diff --git a/.travis.yml b/.travis.yml
index c04c7a5a..aee686da 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,5 +1,5 @@
language: node_js
node_js:
- - "0.10"
+ - "12"
before_install: npm install -g grunt-cli
script: grunt test
\ No newline at end of file
diff --git a/bower.json b/bower.json
index 870d5d20..51ecdd1c 100644
--- a/bower.json
+++ b/bower.json
@@ -1,9 +1,9 @@
{
"name": "leapjs",
- "version": "0.6.4",
+ "version": "1.0.0",
"homepage": "https://github.com/leapmotion/leapjs",
"description": "JavaScript client for the Leap Motion Controller",
- "main": "leap-0.6.4.js",
+ "main": "leap-1.0.0.js",
"keywords": [
"leap",
"leapmotion"
diff --git a/examples/css-visualizer.html b/examples/css-visualizer.html
index bbd26610..d635a156 100644
--- a/examples/css-visualizer.html
+++ b/examples/css-visualizer.html
@@ -1,7 +1,7 @@
DOM Visualizer - Leap
-
+
+
+
-
+
+
diff --git a/examples/loop.html b/examples/loop.html
index c603e947..13492334 100644
--- a/examples/loop.html
+++ b/examples/loop.html
@@ -3,7 +3,7 @@
Loop - Leap
-
+
+
+
diff --git a/examples/plugins.html b/examples/plugins.html
index 0e19490d..24556f5d 100644
--- a/examples/plugins.html
+++ b/examples/plugins.html
@@ -1,7 +1,7 @@
Plugins - Leap
-
+
+
+
diff --git a/examples/threejs-bones.html b/examples/threejs-bones.html
index 1fc9bfea..7c966342 100644
--- a/examples/threejs-bones.html
+++ b/examples/threejs-bones.html
@@ -1,7 +1,7 @@
Bone Hands - Leap
-
+
diff --git a/integration_test/protocol_versions.js b/integration_test/protocol_versions.js
index f44f2aa8..b54365be 100644
--- a/integration_test/protocol_versions.js
+++ b/integration_test/protocol_versions.js
@@ -14,7 +14,10 @@ downgradeProtocol = function(){
var expected = ['/v6.json', '/v5.json', '/v4.json', '/v3.json', '/v2.json', '/v1.json'];
var wss = new WebSocketServer({port: 9494})
- wss.on('connection', function(ws) {
+ // https://github.com/websockets/ws/issues/1114
+ // https://github.com/websockets/ws/pull/1099
+ wss.on('connection', function(ws, req) {
+ ws.upgradeReq = req
if (passed) return;
console.log("connected to socket with "+ws.upgradeReq.url)
if (expected.length == 0) {
@@ -41,7 +44,8 @@ saveGoodProtocol = function(){
var wss = new WebSocketServer({port: 9495})
var origUrl;
- wss.on('connection', function(ws) {
+ wss.on('connection', function(ws, req) {
+ ws.upgradeReq = req
console.log("connected to socket with "+ws.upgradeReq.url)
ws.send('{"version": 4}');
@@ -80,7 +84,8 @@ disconnectAfterConnect = function () {
var wss = new WebSocketServer({port: 9496})
- wss.on('connection', function (ws) {
+ wss.on('connection', function (ws, req) {
+ ws.upgradeReq = req
timesConnected++;
console.log("connected to socket with "+ws.upgradeReq.url)
diff --git a/leap-0.6.4.js b/leap-0.6.4.js
deleted file mode 100644
index 575679f9..00000000
--- a/leap-0.6.4.js
+++ /dev/null
@@ -1,9420 +0,0 @@
-/*!
- * LeapJS v0.6.4
- * http://github.com/leapmotion/leapjs/
- *
- * Copyright 2013 LeapMotion, Inc. and other contributors
- * Released under the Apache-2.0 license
- * http://github.com/leapmotion/leapjs/blob/master/LICENSE.txt
- */
-;(function(e,t,n){function i(n,s){if(!t[n]){if(!e[n]){var o=typeof require=="function"&&require;if(!s&&o)return o(n,!0);if(r)return r(n,!0);throw new Error("Cannot find module '"+n+"'")}var u=t[n]={exports:{}};e[n][0].call(u.exports,function(t){var r=e[n][1][t];return i(r?r:t)},u,u.exports)}return t[n].exports}var r=typeof require=="function"&&require;for(var s=0;s= this.size) return undefined;
- if (i >= this._buf.length) return undefined;
- return this._buf[(this.pos - i - 1) % this.size];
-}
-
-CircularBuffer.prototype.push = function(o) {
- this._buf[this.pos % this.size] = o;
- return this.pos++;
-}
-
-},{}],3:[function(require,module,exports){
-var chooseProtocol = require('../protocol').chooseProtocol
- , EventEmitter = require('events').EventEmitter
- , _ = require('underscore');
-
-var BaseConnection = module.exports = function(opts) {
- this.opts = _.defaults(opts || {}, {
- host : '127.0.0.1',
- enableGestures: false,
- scheme: this.getScheme(),
- port: this.getPort(),
- background: false,
- optimizeHMD: false,
- requestProtocolVersion: BaseConnection.defaultProtocolVersion
- });
- this.host = this.opts.host;
- this.port = this.opts.port;
- this.scheme = this.opts.scheme;
- this.protocolVersionVerified = false;
- this.background = null;
- this.optimizeHMD = null;
- this.on('ready', function() {
- this.enableGestures(this.opts.enableGestures);
- this.setBackground(this.opts.background);
- this.setOptimizeHMD(this.opts.optimizeHMD);
-
- if (this.opts.optimizeHMD){
- console.log("Optimized for head mounted display usage.");
- }else {
- console.log("Optimized for desktop usage.");
- }
-
- });
-};
-
-// The latest available:
-BaseConnection.defaultProtocolVersion = 6;
-
-BaseConnection.prototype.getUrl = function() {
- return this.scheme + "//" + this.host + ":" + this.port + "/v" + this.opts.requestProtocolVersion + ".json";
-}
-
-
-BaseConnection.prototype.getScheme = function(){
- return 'ws:'
-}
-
-BaseConnection.prototype.getPort = function(){
- return 6437
-}
-
-
-BaseConnection.prototype.setBackground = function(state) {
- this.opts.background = state;
- if (this.protocol && this.protocol.sendBackground && this.background !== this.opts.background) {
- this.background = this.opts.background;
- this.protocol.sendBackground(this, this.opts.background);
- }
-}
-
-BaseConnection.prototype.setOptimizeHMD = function(state) {
- this.opts.optimizeHMD = state;
- if (this.protocol && this.protocol.sendOptimizeHMD && this.optimizeHMD !== this.opts.optimizeHMD) {
- this.optimizeHMD = this.opts.optimizeHMD;
- this.protocol.sendOptimizeHMD(this, this.opts.optimizeHMD);
- }
-}
-
-BaseConnection.prototype.handleOpen = function() {
- if (!this.connected) {
- this.connected = true;
- this.emit('connect');
- }
-}
-
-BaseConnection.prototype.enableGestures = function(enabled) {
- this.gesturesEnabled = enabled ? true : false;
- this.send(this.protocol.encode({"enableGestures": this.gesturesEnabled}));
-}
-
-BaseConnection.prototype.handleClose = function(code, reason) {
- if (!this.connected) return;
- this.disconnect();
-
- // 1001 - an active connection is closed
- // 1006 - cannot connect
- if (code === 1001 && this.opts.requestProtocolVersion > 1) {
- if (this.protocolVersionVerified) {
- this.protocolVersionVerified = false;
- }else{
- this.opts.requestProtocolVersion--;
- }
- }
- this.startReconnection();
-}
-
-BaseConnection.prototype.startReconnection = function() {
- var connection = this;
- if(!this.reconnectionTimer){
- (this.reconnectionTimer = setInterval(function() { connection.reconnect() }, 500));
- }
-}
-
-BaseConnection.prototype.stopReconnection = function() {
- this.reconnectionTimer = clearInterval(this.reconnectionTimer);
-}
-
-// By default, disconnect will prevent auto-reconnection.
-// Pass in true to allow the reconnection loop not be interrupted continue
-BaseConnection.prototype.disconnect = function(allowReconnect) {
- if (!allowReconnect) this.stopReconnection();
- if (!this.socket) return;
- this.socket.close();
- delete this.socket;
- delete this.protocol;
- delete this.background; // This is not persisted when reconnecting to the web socket server
- delete this.optimizeHMD;
- delete this.focusedState;
- if (this.connected) {
- this.connected = false;
- this.emit('disconnect');
- }
- return true;
-}
-
-BaseConnection.prototype.reconnect = function() {
- if (this.connected) {
- this.stopReconnection();
- } else {
- this.disconnect(true);
- this.connect();
- }
-}
-
-BaseConnection.prototype.handleData = function(data) {
- var message = JSON.parse(data);
-
- var messageEvent;
- if (this.protocol === undefined) {
- messageEvent = this.protocol = chooseProtocol(message);
- this.protocolVersionVerified = true;
- this.emit('ready');
- } else {
- messageEvent = this.protocol(message);
- }
- this.emit(messageEvent.type, messageEvent);
-}
-
-BaseConnection.prototype.connect = function() {
- if (this.socket) return;
- this.socket = this.setupSocket();
- return true;
-}
-
-BaseConnection.prototype.send = function(data) {
- this.socket.send(data);
-}
-
-BaseConnection.prototype.reportFocus = function(state) {
- if (!this.connected || this.focusedState === state) return;
- this.focusedState = state;
- this.emit(this.focusedState ? 'focus' : 'blur');
- if (this.protocol && this.protocol.sendFocused) {
- this.protocol.sendFocused(this, this.focusedState);
- }
-}
-
-_.extend(BaseConnection.prototype, EventEmitter.prototype);
-},{"../protocol":15,"events":21,"underscore":24}],4:[function(require,module,exports){
-var BaseConnection = module.exports = require('./base')
- , _ = require('underscore');
-
-
-var BrowserConnection = module.exports = function(opts) {
- BaseConnection.call(this, opts);
- var connection = this;
- this.on('ready', function() { connection.startFocusLoop(); })
- this.on('disconnect', function() { connection.stopFocusLoop(); })
-}
-
-_.extend(BrowserConnection.prototype, BaseConnection.prototype);
-
-BrowserConnection.__proto__ = BaseConnection;
-
-BrowserConnection.prototype.useSecure = function(){
- return location.protocol === 'https:'
-}
-
-BrowserConnection.prototype.getScheme = function(){
- return this.useSecure() ? 'wss:' : 'ws:'
-}
-
-BrowserConnection.prototype.getPort = function(){
- return this.useSecure() ? 6436 : 6437
-}
-
-BrowserConnection.prototype.setupSocket = function() {
- var connection = this;
- var socket = new WebSocket(this.getUrl());
- socket.onopen = function() { connection.handleOpen(); };
- socket.onclose = function(data) { connection.handleClose(data['code'], data['reason']); };
- socket.onmessage = function(message) { connection.handleData(message.data) };
- socket.onerror = function(error) {
-
- // attempt to degrade to ws: after one failed attempt for older Leap Service installations.
- if (connection.useSecure() && connection.scheme === 'wss:'){
- connection.scheme = 'ws:';
- connection.port = 6437;
- connection.disconnect();
- connection.connect();
- }
-
- };
- return socket;
-}
-
-BrowserConnection.prototype.startFocusLoop = function() {
- if (this.focusDetectorTimer) return;
- var connection = this;
- var propertyName = null;
- if (typeof document.hidden !== "undefined") {
- propertyName = "hidden";
- } else if (typeof document.mozHidden !== "undefined") {
- propertyName = "mozHidden";
- } else if (typeof document.msHidden !== "undefined") {
- propertyName = "msHidden";
- } else if (typeof document.webkitHidden !== "undefined") {
- propertyName = "webkitHidden";
- } else {
- propertyName = undefined;
- }
-
- if (connection.windowVisible === undefined) {
- connection.windowVisible = propertyName === undefined ? true : document[propertyName] === false;
- }
-
- var focusListener = window.addEventListener('focus', function(e) {
- connection.windowVisible = true;
- updateFocusState();
- });
-
- var blurListener = window.addEventListener('blur', function(e) {
- connection.windowVisible = false;
- updateFocusState();
- });
-
- this.on('disconnect', function() {
- window.removeEventListener('focus', focusListener);
- window.removeEventListener('blur', blurListener);
- });
-
- var updateFocusState = function() {
- var isVisible = propertyName === undefined ? true : document[propertyName] === false;
- connection.reportFocus(isVisible && connection.windowVisible);
- }
-
- // save 100ms when resuming focus
- updateFocusState();
-
- this.focusDetectorTimer = setInterval(updateFocusState, 100);
-}
-
-BrowserConnection.prototype.stopFocusLoop = function() {
- if (!this.focusDetectorTimer) return;
- clearTimeout(this.focusDetectorTimer);
- delete this.focusDetectorTimer;
-}
-
-},{"./base":3,"underscore":24}],5:[function(require,module,exports){
-var process=require("__browserify_process");var Frame = require('./frame')
- , Hand = require('./hand')
- , Pointable = require('./pointable')
- , Finger = require('./finger')
- , CircularBuffer = require("./circular_buffer")
- , Pipeline = require("./pipeline")
- , EventEmitter = require('events').EventEmitter
- , gestureListener = require('./gesture').gestureListener
- , Dialog = require('./dialog')
- , _ = require('underscore');
-
-/**
- * Constructs a Controller object.
- *
- * When creating a Controller object, you may optionally pass in options
- * to set the host , set the port, enable gestures, or select the frame event type.
- *
- * ```javascript
- * var controller = new Leap.Controller({
- * host: '127.0.0.1',
- * port: 6437,
- * enableGestures: true,
- * frameEventName: 'animationFrame'
- * });
- * ```
- *
- * @class Controller
- * @memberof Leap
- * @classdesc
- * The Controller class is your main interface to the Leap Motion Controller.
- *
- * Create an instance of this Controller class to access frames of tracking data
- * and configuration information. Frame data can be polled at any time using the
- * [Controller.frame]{@link Leap.Controller#frame}() function. Call frame() or frame(0) to get the most recent
- * frame. Set the history parameter to a positive integer to access previous frames.
- * A controller stores up to 60 frames in its frame history.
- *
- * Polling is an appropriate strategy for applications which already have an
- * intrinsic update loop, such as a game.
- *
- * loopWhileDisconnected defaults to true, and maintains a 60FPS frame rate even when Leap Motion is not streaming
- * data at that rate (such as no hands in frame). This is important for VR/WebGL apps which rely on rendering for
- * regular visual updates, including from other input devices. Flipping this to false should be considered an
- * optimization for very specific use-cases.
- *
- *
- */
-
-
-var Controller = module.exports = function(opts) {
- var inNode = (typeof(process) !== 'undefined' && process.versions && process.versions.node),
- controller = this;
-
- opts = _.defaults(opts || {}, {
- inNode: inNode
- });
-
- this.inNode = opts.inNode;
-
- opts = _.defaults(opts || {}, {
- frameEventName: this.useAnimationLoop() ? 'animationFrame' : 'deviceFrame',
- suppressAnimationLoop: !this.useAnimationLoop(),
- loopWhileDisconnected: true,
- useAllPlugins: false,
- checkVersion: true
- });
-
- this.animationFrameRequested = false;
- this.onAnimationFrame = function(timestamp) {
- if (controller.lastConnectionFrame.valid){
- controller.emit('animationFrame', controller.lastConnectionFrame);
- }
- controller.emit('frameEnd', timestamp);
- if (
- controller.loopWhileDisconnected &&
- ( ( controller.connection.focusedState !== false ) // loop while undefined, pre-ready.
- || controller.connection.opts.background) ){
- window.requestAnimationFrame(controller.onAnimationFrame);
- }else{
- controller.animationFrameRequested = false;
- }
- };
- this.suppressAnimationLoop = opts.suppressAnimationLoop;
- this.loopWhileDisconnected = opts.loopWhileDisconnected;
- this.frameEventName = opts.frameEventName;
- this.useAllPlugins = opts.useAllPlugins;
- this.history = new CircularBuffer(200);
- this.lastFrame = Frame.Invalid;
- this.lastValidFrame = Frame.Invalid;
- this.lastConnectionFrame = Frame.Invalid;
- this.accumulatedGestures = [];
- this.checkVersion = opts.checkVersion;
- if (opts.connectionType === undefined) {
- this.connectionType = (this.inBrowser() ? require('./connection/browser') : require('./connection/node'));
- } else {
- this.connectionType = opts.connectionType;
- }
- this.connection = new this.connectionType(opts);
- this.streamingCount = 0;
- this.devices = {};
- this.plugins = {};
- this._pluginPipelineSteps = {};
- this._pluginExtendedMethods = {};
- if (opts.useAllPlugins) this.useRegisteredPlugins();
- this.setupFrameEvents(opts);
- this.setupConnectionEvents();
-
- this.startAnimationLoop(); // immediately when started
-}
-
-Controller.prototype.gesture = function(type, cb) {
- var creator = gestureListener(this, type);
- if (cb !== undefined) {
- creator.stop(cb);
- }
- return creator;
-}
-
-/*
- * @returns the controller
- */
-Controller.prototype.setBackground = function(state) {
- this.connection.setBackground(state);
- return this;
-}
-
-Controller.prototype.setOptimizeHMD = function(state) {
- this.connection.setOptimizeHMD(state);
- return this;
-}
-
-Controller.prototype.inBrowser = function() {
- return !this.inNode;
-}
-
-Controller.prototype.useAnimationLoop = function() {
- return this.inBrowser() && !this.inBackgroundPage();
-}
-
-Controller.prototype.inBackgroundPage = function(){
- // http://developer.chrome.com/extensions/extension#method-getBackgroundPage
- return (typeof(chrome) !== "undefined") &&
- chrome.extension &&
- chrome.extension.getBackgroundPage &&
- (chrome.extension.getBackgroundPage() === window)
-}
-
-/*
- * @returns the controller
- */
-Controller.prototype.connect = function() {
- this.connection.connect();
- return this;
-}
-
-Controller.prototype.streaming = function() {
- return this.streamingCount > 0;
-}
-
-Controller.prototype.connected = function() {
- return !!this.connection.connected;
-}
-
-Controller.prototype.startAnimationLoop = function(){
- if (!this.suppressAnimationLoop && !this.animationFrameRequested) {
- this.animationFrameRequested = true;
- window.requestAnimationFrame(this.onAnimationFrame);
- }
-}
-
-/*
- * @returns the controller
- */
-Controller.prototype.disconnect = function() {
- this.connection.disconnect();
- return this;
-}
-
-/**
- * Returns a frame of tracking data from the Leap.
- *
- * Use the optional history parameter to specify which frame to retrieve.
- * Call frame() or frame(0) to access the most recent frame; call frame(1) to
- * access the previous frame, and so on. If you use a history value greater
- * than the number of stored frames, then the controller returns an invalid frame.
- *
- * @method frame
- * @memberof Leap.Controller.prototype
- * @param {number} history The age of the frame to return, counting backwards from
- * the most recent frame (0) into the past and up to the maximum age (59).
- * @returns {Leap.Frame} The specified frame; or, if no history
- * parameter is specified, the newest frame. If a frame is not available at
- * the specified history position, an invalid Frame is returned.
- **/
-Controller.prototype.frame = function(num) {
- return this.history.get(num) || Frame.Invalid;
-}
-
-Controller.prototype.loop = function(callback) {
- if (callback) {
- if (typeof callback === 'function'){
- this.on(this.frameEventName, callback);
- }else{
- // callback is actually of the form: {eventName: callback}
- this.setupFrameEvents(callback);
- }
- }
-
- return this.connect();
-}
-
-Controller.prototype.addStep = function(step) {
- if (!this.pipeline) this.pipeline = new Pipeline(this);
- this.pipeline.addStep(step);
-}
-
-// this is run on every deviceFrame
-Controller.prototype.processFrame = function(frame) {
- if (frame.gestures) {
- this.accumulatedGestures = this.accumulatedGestures.concat(frame.gestures);
- }
- // lastConnectionFrame is used by the animation loop
- this.lastConnectionFrame = frame;
- this.startAnimationLoop(); // Only has effect if loopWhileDisconnected: false
- this.emit('deviceFrame', frame);
-}
-
-// on a this.deviceEventName (usually 'animationFrame' in browsers), this emits a 'frame'
-Controller.prototype.processFinishedFrame = function(frame) {
- this.lastFrame = frame;
- if (frame.valid) {
- this.lastValidFrame = frame;
- }
- frame.controller = this;
- frame.historyIdx = this.history.push(frame);
- if (frame.gestures) {
- frame.gestures = this.accumulatedGestures;
- this.accumulatedGestures = [];
- for (var gestureIdx = 0; gestureIdx != frame.gestures.length; gestureIdx++) {
- this.emit("gesture", frame.gestures[gestureIdx], frame);
- }
- }
- if (this.pipeline) {
- frame = this.pipeline.run(frame);
- if (!frame) frame = Frame.Invalid;
- }
- this.emit('frame', frame);
- this.emitHandEvents(frame);
-}
-
-/**
- * The controller will emit 'hand' events for every hand on each frame. The hand in question will be passed
- * to the event callback.
- *
- * @param frame
- */
-Controller.prototype.emitHandEvents = function(frame){
- for (var i = 0; i < frame.hands.length; i++){
- this.emit('hand', frame.hands[i]);
- }
-}
-
-Controller.prototype.setupFrameEvents = function(opts){
- if (opts.frame){
- this.on('frame', opts.frame);
- }
- if (opts.hand){
- this.on('hand', opts.hand);
- }
-}
-
-/**
- Controller events. The old 'deviceConnected' and 'deviceDisconnected' have been depricated -
- use 'deviceStreaming' and 'deviceStopped' instead, except in the case of an unexpected disconnect.
-
- There are 4 pairs of device events recently added/changed:
- -deviceAttached/deviceRemoved - called when a device's physical connection to the computer changes
- -deviceStreaming/deviceStopped - called when a device is paused or resumed.
- -streamingStarted/streamingStopped - called when there is/is no longer at least 1 streaming device.
- Always comes after deviceStreaming.
-
- The first of all of the above event pairs is triggered as appropriate upon connection. All of
- these events receives an argument with the most recent info about the device that triggered it.
- These events will always be fired in the order they are listed here, with reverse ordering for the
- matching shutdown call. (ie, deviceStreaming always comes after deviceAttached, and deviceStopped
- will come before deviceRemoved).
-
- -deviceConnected/deviceDisconnected - These are considered deprecated and will be removed in
- the next revision. In contrast to the other events and in keeping with it's original behavior,
- it will only be fired when a device begins streaming AFTER a connection has been established.
- It is not paired, and receives no device info. Nearly identical functionality to
- streamingStarted/Stopped if you need to port.
-*/
-Controller.prototype.setupConnectionEvents = function() {
- var controller = this;
- this.connection.on('frame', function(frame) {
- controller.processFrame(frame);
- });
- // either deviceFrame or animationFrame:
- this.on(this.frameEventName, function(frame) {
- controller.processFinishedFrame(frame);
- });
-
-
- // here we backfill the 0.5.0 deviceEvents as best possible
- // backfill begin streaming events
- var backfillStreamingStartedEventsHandler = function(){
- if (controller.connection.opts.requestProtocolVersion < 5 && controller.streamingCount == 0){
- controller.streamingCount = 1;
- var info = {
- attached: true,
- streaming: true,
- type: 'unknown',
- id: "Lx00000000000"
- };
- controller.devices[info.id] = info;
-
- controller.emit('deviceAttached', info);
- controller.emit('deviceStreaming', info);
- controller.emit('streamingStarted', info);
- controller.connection.removeListener('frame', backfillStreamingStartedEventsHandler)
- }
- }
-
- var backfillStreamingStoppedEvents = function(){
- if (controller.streamingCount > 0) {
- for (var deviceId in controller.devices){
- controller.emit('deviceStopped', controller.devices[deviceId]);
- controller.emit('deviceRemoved', controller.devices[deviceId]);
- }
- // only emit streamingStopped once, with the last device
- controller.emit('streamingStopped', controller.devices[deviceId]);
-
- controller.streamingCount = 0;
-
- for (var deviceId in controller.devices){
- delete controller.devices[deviceId];
- }
- }
- }
- // Delegate connection events
- this.connection.on('focus', function() {
-
- if ( controller.loopWhileDisconnected ){
-
- controller.startAnimationLoop();
-
- }
-
- controller.emit('focus');
-
- });
- this.connection.on('blur', function() { controller.emit('blur') });
- this.connection.on('protocol', function(protocol) {
-
- protocol.on('beforeFrameCreated', function(frameData){
- controller.emit('beforeFrameCreated', frameData)
- });
-
- protocol.on('afterFrameCreated', function(frame, frameData){
- controller.emit('afterFrameCreated', frame, frameData)
- });
-
- controller.emit('protocol', protocol);
- });
-
- this.connection.on('ready', function() {
-
- if (controller.checkVersion && !controller.inNode){
- // show dialog only to web users
- controller.checkOutOfDate();
- }
-
- controller.emit('ready');
- });
-
- this.connection.on('connect', function() {
- controller.emit('connect');
- controller.connection.removeListener('frame', backfillStreamingStartedEventsHandler)
- controller.connection.on('frame', backfillStreamingStartedEventsHandler);
- });
-
- this.connection.on('disconnect', function() {
- controller.emit('disconnect');
- backfillStreamingStoppedEvents();
- });
-
- // this does not fire when the controller is manually disconnected
- // or for Leap Service v1.2.0+
- this.connection.on('deviceConnect', function(evt) {
- if (evt.state){
- controller.emit('deviceConnected');
- controller.connection.removeListener('frame', backfillStreamingStartedEventsHandler)
- controller.connection.on('frame', backfillStreamingStartedEventsHandler);
- }else{
- controller.emit('deviceDisconnected');
- backfillStreamingStoppedEvents();
- }
- });
-
- // Does not fire for Leap Service pre v1.2.0
- this.connection.on('deviceEvent', function(evt) {
- var info = evt.state,
- oldInfo = controller.devices[info.id];
-
- //Grab a list of changed properties in the device info
- var changed = {};
- for(var property in info) {
- //If a property i doesn't exist the cache, or has changed...
- if( !oldInfo || !oldInfo.hasOwnProperty(property) || oldInfo[property] != info[property] ) {
- changed[property] = true;
- }
- }
-
- //Update the device list
- controller.devices[info.id] = info;
-
- //Fire events based on change list
- if(changed.attached) {
- controller.emit(info.attached ? 'deviceAttached' : 'deviceRemoved', info);
- }
-
- if(!changed.streaming) return;
-
- if(info.streaming) {
- controller.streamingCount++;
- controller.emit('deviceStreaming', info);
- if( controller.streamingCount == 1 ) {
- controller.emit('streamingStarted', info);
- }
- //if attached & streaming both change to true at the same time, that device was streaming
- //already when we connected.
- if(!changed.attached) {
- controller.emit('deviceConnected');
- }
- }
- //Since when devices are attached all fields have changed, don't send events for streaming being false.
- else if(!(changed.attached && info.attached)) {
- controller.streamingCount--;
- controller.emit('deviceStopped', info);
- if(controller.streamingCount == 0){
- controller.emit('streamingStopped', info);
- }
- controller.emit('deviceDisconnected');
- }
-
- });
-
-
- this.on('newListener', function(event, listener) {
- if( event == 'deviceConnected' || event == 'deviceDisconnected' ) {
- console.warn(event + " events are depricated. Consider using 'streamingStarted/streamingStopped' or 'deviceStreaming/deviceStopped' instead");
- }
- });
-
-};
-
-
-
-
-// Checks if the protocol version is the latest, if if not, shows the dialog.
-Controller.prototype.checkOutOfDate = function(){
- console.assert(this.connection && this.connection.protocol);
-
- var serviceVersion = this.connection.protocol.serviceVersion;
- var protocolVersion = this.connection.protocol.version;
- var defaultProtocolVersion = this.connectionType.defaultProtocolVersion;
-
- if (defaultProtocolVersion > protocolVersion){
-
- console.warn("Your Protocol Version is v" + protocolVersion +
- ", this app was designed for v" + defaultProtocolVersion);
-
- Dialog.warnOutOfDate({
- sV: serviceVersion,
- pV: protocolVersion
- });
- return true
- }else{
- return false
- }
-
-};
-
-
-
-Controller._pluginFactories = {};
-
-/*
- * Registers a plugin, making is accessible to controller.use later on.
- *
- * @member plugin
- * @memberof Leap.Controller.prototype
- * @param {String} name The name of the plugin (usually camelCase).
- * @param {function} factory A factory method which will return an instance of a plugin.
- * The factory receives an optional hash of options, passed in via controller.use.
- *
- * Valid keys for the object include frame, hand, finger, tool, and pointable. The value
- * of each key can be either a function or an object. If given a function, that function
- * will be called once for every instance of the object, with that instance injected as an
- * argument. This allows decoration of objects with additional data:
- *
- * ```javascript
- * Leap.Controller.plugin('testPlugin', function(options){
- * return {
- * frame: function(frame){
- * frame.foo = 'bar';
- * }
- * }
- * });
- * ```
- *
- * When hand is used, the callback is called for every hand in `frame.hands`. Note that
- * hand objects are recreated with every new frame, so that data saved on the hand will not
- * persist.
- *
- * ```javascript
- * Leap.Controller.plugin('testPlugin', function(){
- * return {
- * hand: function(hand){
- * console.log('testPlugin running on hand ' + hand.id);
- * }
- * }
- * });
- * ```
- *
- * A factory can return an object to add custom functionality to Frames, Hands, or Pointables.
- * The methods are added directly to the object's prototype. Finger and Tool cannot be used here, Pointable
- * must be used instead.
- * This is encouraged for calculations which may not be necessary on every frame.
- * Memoization is also encouraged, for cases where the method may be called many times per frame by the application.
- *
- * ```javascript
- * // This plugin allows hand.usefulData() to be called later.
- * Leap.Controller.plugin('testPlugin', function(){
- * return {
- * hand: {
- * usefulData: function(){
- * console.log('usefulData on hand', this.id);
- * // memoize the results on to the hand, preventing repeat work:
- * this.x || this.x = someExpensiveCalculation();
- * return this.x;
- * }
- * }
- * }
- * });
- *
- * Note that the factory pattern allows encapsulation for every plugin instance.
- *
- * ```javascript
- * Leap.Controller.plugin('testPlugin', function(options){
- * options || options = {}
- * options.center || options.center = [0,0,0]
- *
- * privatePrintingMethod = function(){
- * console.log('privatePrintingMethod - options', options);
- * }
- *
- * return {
- * pointable: {
- * publicPrintingMethod: function(){
- * privatePrintingMethod();
- * }
- * }
- * }
- * });
- *
- */
-Controller.plugin = function(pluginName, factory) {
- if (this._pluginFactories[pluginName]) {
- console.warn("Plugin \"" + pluginName + "\" already registered");
- }
- return this._pluginFactories[pluginName] = factory;
-};
-
-/*
- * Returns a list of registered plugins.
- * @returns {Array} Plugin Factories.
- */
-Controller.plugins = function() {
- return _.keys(this._pluginFactories);
-};
-
-
-
-var setPluginCallbacks = function(pluginName, type, callback){
-
- if ( ['beforeFrameCreated', 'afterFrameCreated'].indexOf(type) != -1 ){
-
- // todo - not able to "unuse" a plugin currently
- this.on(type, callback);
-
- }else {
-
- if (!this.pipeline) this.pipeline = new Pipeline(this);
-
- if (!this._pluginPipelineSteps[pluginName]) this._pluginPipelineSteps[pluginName] = [];
-
- this._pluginPipelineSteps[pluginName].push(
-
- this.pipeline.addWrappedStep(type, callback)
-
- );
-
- }
-
-};
-
-var setPluginMethods = function(pluginName, type, hash){
- var klass;
-
- if (!this._pluginExtendedMethods[pluginName]) this._pluginExtendedMethods[pluginName] = [];
-
- switch (type) {
- case 'frame':
- klass = Frame;
- break;
- case 'hand':
- klass = Hand;
- break;
- case 'pointable':
- klass = Pointable;
- _.extend(Finger.prototype, hash);
- _.extend(Finger.Invalid, hash);
- break;
- case 'finger':
- klass = Finger;
- break;
- default:
- throw pluginName + ' specifies invalid object type "' + type + '" for prototypical extension'
- }
-
- _.extend(klass.prototype, hash);
- _.extend(klass.Invalid, hash);
- this._pluginExtendedMethods[pluginName].push([klass, hash])
-
-}
-
-
-
-/*
- * Begin using a registered plugin. The plugin's functionality will be added to all frames
- * returned by the controller (and/or added to the objects within the frame).
- * - The order of plugin execution inside the loop will match the order in which use is called by the application.
- * - The plugin be run for both deviceFrames and animationFrames.
- *
- * If called a second time, the options will be merged with those of the already instantiated plugin.
- *
- * @method use
- * @memberOf Leap.Controller.prototype
- * @param pluginName
- * @param {Hash} Options to be passed to the plugin's factory.
- * @returns the controller
- */
-Controller.prototype.use = function(pluginName, options) {
- var functionOrHash, pluginFactory, key, pluginInstance;
-
- pluginFactory = (typeof pluginName == 'function') ? pluginName : Controller._pluginFactories[pluginName];
-
- if (!pluginFactory) {
- throw 'Leap Plugin ' + pluginName + ' not found.';
- }
-
- options || (options = {});
-
- if (this.plugins[pluginName]){
- _.extend(this.plugins[pluginName], options);
- return this;
- }
-
- this.plugins[pluginName] = options;
-
- pluginInstance = pluginFactory.call(this, options);
-
- for (key in pluginInstance) {
-
- functionOrHash = pluginInstance[key];
-
- if (typeof functionOrHash === 'function') {
-
- setPluginCallbacks.call(this, pluginName, key, functionOrHash);
-
- } else {
-
- setPluginMethods.call(this, pluginName, key, functionOrHash);
-
- }
-
- }
-
- return this;
-};
-
-
-
-
-/*
- * Stop using a used plugin. This will remove any of the plugin's pipeline methods (those called on every frame)
- * and remove any methods which extend frame-object prototypes.
- *
- * @method stopUsing
- * @memberOf Leap.Controller.prototype
- * @param pluginName
- * @returns the controller
- */
-Controller.prototype.stopUsing = function (pluginName) {
- var steps = this._pluginPipelineSteps[pluginName],
- extMethodHashes = this._pluginExtendedMethods[pluginName],
- i = 0, klass, extMethodHash;
-
- if (!this.plugins[pluginName]) return;
-
- if (steps) {
- for (i = 0; i < steps.length; i++) {
- this.pipeline.removeStep(steps[i]);
- }
- }
-
- if (extMethodHashes){
- for (i = 0; i < extMethodHashes.length; i++){
- klass = extMethodHashes[i][0];
- extMethodHash = extMethodHashes[i][1];
- for (var methodName in extMethodHash) {
- delete klass.prototype[methodName];
- delete klass.Invalid[methodName];
- }
- }
- }
-
- delete this.plugins[pluginName];
-
- return this;
-}
-
-Controller.prototype.useRegisteredPlugins = function(){
- for (var plugin in Controller._pluginFactories){
- this.use(plugin);
- }
-}
-
-
-_.extend(Controller.prototype, EventEmitter.prototype);
-
-},{"./circular_buffer":2,"./connection/browser":4,"./connection/node":20,"./dialog":6,"./finger":7,"./frame":8,"./gesture":9,"./hand":10,"./pipeline":13,"./pointable":14,"__browserify_process":22,"events":21,"underscore":24}],6:[function(require,module,exports){
-var process=require("__browserify_process");var Dialog = module.exports = function(message, options){
- this.options = (options || {});
- this.message = message;
-
- this.createElement();
-};
-
-Dialog.prototype.createElement = function(){
- this.element = document.createElement('div');
- this.element.className = "leapjs-dialog";
- this.element.style.position = "fixed";
- this.element.style.top = '8px';
- this.element.style.left = 0;
- this.element.style.right = 0;
- this.element.style.textAlign = 'center';
- this.element.style.zIndex = 1000;
-
- var dialog = document.createElement('div');
- this.element.appendChild(dialog);
- dialog.style.className = "leapjs-dialog";
- dialog.style.display = "inline-block";
- dialog.style.margin = "auto";
- dialog.style.padding = "8px";
- dialog.style.color = "#222";
- dialog.style.background = "#eee";
- dialog.style.borderRadius = "4px";
- dialog.style.border = "1px solid #999";
- dialog.style.textAlign = "left";
- dialog.style.cursor = "pointer";
- dialog.style.whiteSpace = "nowrap";
- dialog.style.transition = "box-shadow 1s linear";
- dialog.innerHTML = this.message;
-
-
- if (this.options.onclick){
- dialog.addEventListener('click', this.options.onclick);
- }
-
- if (this.options.onmouseover){
- dialog.addEventListener('mouseover', this.options.onmouseover);
- }
-
- if (this.options.onmouseout){
- dialog.addEventListener('mouseout', this.options.onmouseout);
- }
-
- if (this.options.onmousemove){
- dialog.addEventListener('mousemove', this.options.onmousemove);
- }
-};
-
-Dialog.prototype.show = function(){
- document.body.appendChild(this.element);
- return this;
-};
-
-Dialog.prototype.hide = function(){
- document.body.removeChild(this.element);
- return this;
-};
-
-
-
-
-// Shows a DOM dialog box with links to developer.leapmotion.com to upgrade
-// This will work whether or not the Leap is plugged in,
-// As long as it is called after a call to .connect() and the 'ready' event has fired.
-Dialog.warnOutOfDate = function(params){
- params || (params = {});
-
- var url = "http://developer.leapmotion.com?";
-
- params.returnTo = window.location.href;
-
- for (var key in params){
- url += key + '=' + encodeURIComponent(params[key]) + '&';
- }
-
- var dialog,
- onclick = function(event){
-
- if (event.target.id != 'leapjs-decline-upgrade'){
-
- var popup = window.open(url,
- '_blank',
- 'height=800,width=1000,location=1,menubar=1,resizable=1,status=1,toolbar=1,scrollbars=1'
- );
-
- if (window.focus) {popup.focus()}
-
- }
-
- dialog.hide();
-
- return true;
- },
-
-
- message = "This site requires Leap Motion Tracking V2." +
- "" +
- "";
-
- dialog = new Dialog(message, {
- onclick: onclick,
- onmousemove: function(e){
- if (e.target == document.getElementById('leapjs-decline-upgrade')){
- document.getElementById('leapjs-decline-upgrade').style.color = '#000';
- document.getElementById('leapjs-decline-upgrade').style.boxShadow = '0px 0px 2px #5daa00';
-
- document.getElementById('leapjs-accept-upgrade').style.color = '#444';
- document.getElementById('leapjs-accept-upgrade').style.boxShadow = 'none';
- }else{
- document.getElementById('leapjs-accept-upgrade').style.color = '#000';
- document.getElementById('leapjs-accept-upgrade').style.boxShadow = '0px 0px 2px #5daa00';
-
- document.getElementById('leapjs-decline-upgrade').style.color = '#444';
- document.getElementById('leapjs-decline-upgrade').style.boxShadow = 'none';
- }
- },
- onmouseout: function(){
- document.getElementById('leapjs-decline-upgrade').style.color = '#444';
- document.getElementById('leapjs-decline-upgrade').style.boxShadow = 'none';
- document.getElementById('leapjs-accept-upgrade').style.color = '#444';
- document.getElementById('leapjs-accept-upgrade').style.boxShadow = 'none';
- }
- }
- );
-
- return dialog.show();
-};
-
-
-// Tracks whether we've warned for lack of bones API. This will be shown only for early private-beta members.
-Dialog.hasWarnedBones = false;
-
-Dialog.warnBones = function(){
- if (this.hasWarnedBones) return;
- this.hasWarnedBones = true;
-
- console.warn("Your Leap Service is out of date");
-
- if ( !(typeof(process) !== 'undefined' && process.versions && process.versions.node) ){
- this.warnOutOfDate({reason: 'bones'});
- }
-
-}
-},{"__browserify_process":22}],7:[function(require,module,exports){
-var Pointable = require('./pointable'),
- Bone = require('./bone')
- , Dialog = require('./dialog')
- , _ = require('underscore');
-
-/**
-* Constructs a Finger object.
-*
-* An uninitialized finger is considered invalid.
-* Get valid Finger objects from a Frame or a Hand object.
-*
-* @class Finger
-* @memberof Leap
-* @classdesc
-* The Finger class reports the physical characteristics of a finger.
-*
-* Both fingers and tools are classified as Pointable objects. Use the
-* Pointable.tool property to determine whether a Pointable object represents a
-* tool or finger. The Leap classifies a detected entity as a tool when it is
-* thinner, straighter, and longer than a typical finger.
-*
-* Note that Finger objects can be invalid, which means that they do not
-* contain valid tracking data and do not correspond to a physical entity.
-* Invalid Finger objects can be the result of asking for a Finger object
-* using an ID from an earlier frame when no Finger objects with that ID
-* exist in the current frame. A Finger object created from the Finger
-* constructor is also invalid. Test for validity with the Pointable.valid
-* property.
-*/
-var Finger = module.exports = function(data) {
- Pointable.call(this, data); // use pointable as super-constructor
-
- /**
- * The position of the distal interphalangeal joint of the finger.
- * This joint is closest to the tip.
- *
- * The distal interphalangeal joint is located between the most extreme segment
- * of the finger (the distal phalanx) and the middle segment (the medial
- * phalanx).
- *
- * @member dipPosition
- * @type {number[]}
- * @memberof Leap.Finger.prototype
- */
- this.dipPosition = data.dipPosition;
-
- /**
- * The position of the proximal interphalangeal joint of the finger. This joint is the middle
- * joint of a finger.
- *
- * The proximal interphalangeal joint is located between the two finger segments
- * closest to the hand (the proximal and the medial phalanges). On a thumb,
- * which lacks an medial phalanx, this joint index identifies the knuckle joint
- * between the proximal phalanx and the metacarpal bone.
- *
- * @member pipPosition
- * @type {number[]}
- * @memberof Leap.Finger.prototype
- */
- this.pipPosition = data.pipPosition;
-
- /**
- * The position of the metacarpopophalangeal joint, or knuckle, of the finger.
- *
- * The metacarpopophalangeal joint is located at the base of a finger between
- * the metacarpal bone and the first phalanx. The common name for this joint is
- * the knuckle.
- *
- * On a thumb, which has one less phalanx than a finger, this joint index
- * identifies the thumb joint near the base of the hand, between the carpal
- * and metacarpal bones.
- *
- * @member mcpPosition
- * @type {number[]}
- * @memberof Leap.Finger.prototype
- */
- this.mcpPosition = data.mcpPosition;
-
- /**
- * The position of the Carpometacarpal joint
- *
- * This is at the distal end of the wrist, and has no common name.
- *
- */
- this.carpPosition = data.carpPosition;
-
- /**
- * Whether or not this finger is in an extended posture.
- *
- * A finger is considered extended if it is extended straight from the hand as if
- * pointing. A finger is not extended when it is bent down and curled towards the
- * palm.
- * @member extended
- * @type {Boolean}
- * @memberof Leap.Finger.prototype
- */
- this.extended = data.extended;
-
- /**
- * An integer code for the name of this finger.
- *
- * * 0 -- thumb
- * * 1 -- index finger
- * * 2 -- middle finger
- * * 3 -- ring finger
- * * 4 -- pinky
- *
- * @member type
- * @type {number}
- * @memberof Leap.Finger.prototype
- */
- this.type = data.type;
-
- this.finger = true;
-
- /**
- * The joint positions of this finger as an array in the order base to tip.
- *
- * @member positions
- * @type {array[]}
- * @memberof Leap.Finger.prototype
- */
- this.positions = [this.carpPosition, this.mcpPosition, this.pipPosition, this.dipPosition, this.tipPosition];
-
- if (data.bases){
- this.addBones(data);
- } else {
- Dialog.warnBones();
- }
-
-};
-
-_.extend(Finger.prototype, Pointable.prototype);
-
-
-Finger.prototype.addBones = function(data){
- /**
- * Four bones per finger, from wrist outwards:
- * metacarpal, proximal, medial, and distal.
- *
- * See http://en.wikipedia.org/wiki/Interphalangeal_articulations_of_hand
- */
- this.metacarpal = new Bone(this, {
- type: 0,
- width: this.width,
- prevJoint: this.carpPosition,
- nextJoint: this.mcpPosition,
- basis: data.bases[0]
- });
-
- this.proximal = new Bone(this, {
- type: 1,
- width: this.width,
- prevJoint: this.mcpPosition,
- nextJoint: this.pipPosition,
- basis: data.bases[1]
- });
-
- this.medial = new Bone(this, {
- type: 2,
- width: this.width,
- prevJoint: this.pipPosition,
- nextJoint: this.dipPosition,
- basis: data.bases[2]
- });
-
- /**
- * Note that the `distal.nextJoint` position is slightly different from the `finger.tipPosition`.
- * The former is at the very end of the bone, where the latter is the center of a sphere positioned at
- * the tip of the finger. The btipPosition "bone tip position" is a few mm closer to the wrist than
- * the tipPosition.
- * @type {Bone}
- */
- this.distal = new Bone(this, {
- type: 3,
- width: this.width,
- prevJoint: this.dipPosition,
- nextJoint: data.btipPosition,
- basis: data.bases[3]
- });
-
- this.bones = [this.metacarpal, this.proximal, this.medial, this.distal];
-};
-
-Finger.prototype.toString = function() {
- return "Finger [ id:" + this.id + " " + this.length + "mmx | width:" + this.width + "mm | direction:" + this.direction + ' ]';
-};
-
-Finger.Invalid = { valid: false };
-
-},{"./bone":1,"./dialog":6,"./pointable":14,"underscore":24}],8:[function(require,module,exports){
-var Hand = require("./hand")
- , Pointable = require("./pointable")
- , createGesture = require("./gesture").createGesture
- , glMatrix = require("gl-matrix")
- , mat3 = glMatrix.mat3
- , vec3 = glMatrix.vec3
- , InteractionBox = require("./interaction_box")
- , Finger = require('./finger')
- , _ = require("underscore");
-
-/**
- * Constructs a Frame object.
- *
- * Frame instances created with this constructor are invalid.
- * Get valid Frame objects by calling the
- * [Controller.frame]{@link Leap.Controller#frame}() function.
- *
- * @class Frame
- * @memberof Leap
- * @classdesc
- * The Frame class represents a set of hand and finger tracking data detected
- * in a single frame.
- *
- * The Leap detects hands, fingers and tools within the tracking area, reporting
- * their positions, orientations and motions in frames at the Leap frame rate.
- *
- * Access Frame objects using the [Controller.frame]{@link Leap.Controller#frame}() function.
- */
-var Frame = module.exports = function(data) {
- /**
- * Reports whether this Frame instance is valid.
- *
- * A valid Frame is one generated by the Controller object that contains
- * tracking data for all detected entities. An invalid Frame contains no
- * actual tracking data, but you can call its functions without risk of a
- * undefined object exception. The invalid Frame mechanism makes it more
- * convenient to track individual data across the frame history. For example,
- * you can invoke:
- *
- * ```javascript
- * var finger = controller.frame(n).finger(fingerID);
- * ```
- *
- * for an arbitrary Frame history value, "n", without first checking whether
- * frame(n) returned a null object. (You should still check that the
- * returned Finger instance is valid.)
- *
- * @member valid
- * @memberof Leap.Frame.prototype
- * @type {Boolean}
- */
- this.valid = true;
- /**
- * A unique ID for this Frame. Consecutive frames processed by the Leap
- * have consecutive increasing values.
- * @member id
- * @memberof Leap.Frame.prototype
- * @type {String}
- */
- this.id = data.id;
- /**
- * The frame capture time in microseconds elapsed since the Leap started.
- * @member timestamp
- * @memberof Leap.Frame.prototype
- * @type {number}
- */
- this.timestamp = data.timestamp;
- /**
- * The list of Hand objects detected in this frame, given in arbitrary order.
- * The list can be empty if no hands are detected.
- *
- * @member hands[]
- * @memberof Leap.Frame.prototype
- * @type {Leap.Hand}
- */
- this.hands = [];
- this.handsMap = {};
- /**
- * The list of Pointable objects (fingers and tools) detected in this frame,
- * given in arbitrary order. The list can be empty if no fingers or tools are
- * detected.
- *
- * @member pointables[]
- * @memberof Leap.Frame.prototype
- * @type {Leap.Pointable}
- */
- this.pointables = [];
- /**
- * The list of Tool objects detected in this frame, given in arbitrary order.
- * The list can be empty if no tools are detected.
- *
- * @member tools[]
- * @memberof Leap.Frame.prototype
- * @type {Leap.Pointable}
- */
- this.tools = [];
- /**
- * The list of Finger objects detected in this frame, given in arbitrary order.
- * The list can be empty if no fingers are detected.
- * @member fingers[]
- * @memberof Leap.Frame.prototype
- * @type {Leap.Pointable}
- */
- this.fingers = [];
-
- /**
- * The InteractionBox associated with the current frame.
- *
- * @member interactionBox
- * @memberof Leap.Frame.prototype
- * @type {Leap.InteractionBox}
- */
- if (data.interactionBox) {
- this.interactionBox = new InteractionBox(data.interactionBox);
- }
- this.gestures = [];
- this.pointablesMap = {};
- this._translation = data.t;
- this._rotation = _.flatten(data.r);
- this._scaleFactor = data.s;
- this.data = data;
- this.type = 'frame'; // used by event emitting
- this.currentFrameRate = data.currentFrameRate;
-
- if (data.gestures) {
- /**
- * The list of Gesture objects detected in this frame, given in arbitrary order.
- * The list can be empty if no gestures are detected.
- *
- * Circle and swipe gestures are updated every frame. Tap gestures
- * only appear in the list for a single frame.
- * @member gestures[]
- * @memberof Leap.Frame.prototype
- * @type {Leap.Gesture}
- */
- for (var gestureIdx = 0, gestureCount = data.gestures.length; gestureIdx != gestureCount; gestureIdx++) {
- this.gestures.push(createGesture(data.gestures[gestureIdx]));
- }
- }
- this.postprocessData(data);
-};
-
-Frame.prototype.postprocessData = function(data){
- if (!data) {
- data = this.data;
- }
-
- for (var handIdx = 0, handCount = data.hands.length; handIdx != handCount; handIdx++) {
- var hand = new Hand(data.hands[handIdx]);
- hand.frame = this;
- this.hands.push(hand);
- this.handsMap[hand.id] = hand;
- }
-
- data.pointables = _.sortBy(data.pointables, function(pointable) { return pointable.id });
-
- for (var pointableIdx = 0, pointableCount = data.pointables.length; pointableIdx != pointableCount; pointableIdx++) {
- var pointableData = data.pointables[pointableIdx];
- var pointable = pointableData.dipPosition ? new Finger(pointableData) : new Pointable(pointableData);
- pointable.frame = this;
- this.addPointable(pointable);
- }
-};
-
-/**
- * Adds data from a pointable element into the pointablesMap;
- * also adds the pointable to the frame.handsMap hand to which it belongs,
- * and to the hand's tools or hand's fingers map.
- *
- * @param pointable {Object} a Pointable
- */
-Frame.prototype.addPointable = function (pointable) {
- this.pointables.push(pointable);
- this.pointablesMap[pointable.id] = pointable;
- (pointable.tool ? this.tools : this.fingers).push(pointable);
- if (pointable.handId !== undefined && this.handsMap.hasOwnProperty(pointable.handId)) {
- var hand = this.handsMap[pointable.handId];
- hand.pointables.push(pointable);
- (pointable.tool ? hand.tools : hand.fingers).push(pointable);
- switch (pointable.type){
- case 0:
- hand.thumb = pointable;
- break;
- case 1:
- hand.indexFinger = pointable;
- break;
- case 2:
- hand.middleFinger = pointable;
- break;
- case 3:
- hand.ringFinger = pointable;
- break;
- case 4:
- hand.pinky = pointable;
- break;
- }
- }
-};
-
-/**
- * The tool with the specified ID in this frame.
- *
- * Use the Frame tool() function to retrieve a tool from
- * this frame using an ID value obtained from a previous frame.
- * This function always returns a Pointable object, but if no tool
- * with the specified ID is present, an invalid Pointable object is returned.
- *
- * Note that ID values persist across frames, but only until tracking of a
- * particular object is lost. If tracking of a tool is lost and subsequently
- * regained, the new Pointable object representing that tool may have a
- * different ID than that representing the tool in an earlier frame.
- *
- * @method tool
- * @memberof Leap.Frame.prototype
- * @param {String} id The ID value of a Tool object from a previous frame.
- * @returns {Leap.Pointable} The tool with the
- * matching ID if one exists in this frame; otherwise, an invalid Pointable object
- * is returned.
- */
-Frame.prototype.tool = function(id) {
- var pointable = this.pointable(id);
- return pointable.tool ? pointable : Pointable.Invalid;
-};
-
-/**
- * The Pointable object with the specified ID in this frame.
- *
- * Use the Frame pointable() function to retrieve the Pointable object from
- * this frame using an ID value obtained from a previous frame.
- * This function always returns a Pointable object, but if no finger or tool
- * with the specified ID is present, an invalid Pointable object is returned.
- *
- * Note that ID values persist across frames, but only until tracking of a
- * particular object is lost. If tracking of a finger or tool is lost and subsequently
- * regained, the new Pointable object representing that finger or tool may have
- * a different ID than that representing the finger or tool in an earlier frame.
- *
- * @method pointable
- * @memberof Leap.Frame.prototype
- * @param {String} id The ID value of a Pointable object from a previous frame.
- * @returns {Leap.Pointable} The Pointable object with
- * the matching ID if one exists in this frame;
- * otherwise, an invalid Pointable object is returned.
- */
-Frame.prototype.pointable = function(id) {
- return this.pointablesMap[id] || Pointable.Invalid;
-};
-
-/**
- * The finger with the specified ID in this frame.
- *
- * Use the Frame finger() function to retrieve the finger from
- * this frame using an ID value obtained from a previous frame.
- * This function always returns a Finger object, but if no finger
- * with the specified ID is present, an invalid Pointable object is returned.
- *
- * Note that ID values persist across frames, but only until tracking of a
- * particular object is lost. If tracking of a finger is lost and subsequently
- * regained, the new Pointable object representing that physical finger may have
- * a different ID than that representing the finger in an earlier frame.
- *
- * @method finger
- * @memberof Leap.Frame.prototype
- * @param {String} id The ID value of a finger from a previous frame.
- * @returns {Leap.Pointable} The finger with the
- * matching ID if one exists in this frame; otherwise, an invalid Pointable
- * object is returned.
- */
-Frame.prototype.finger = function(id) {
- var pointable = this.pointable(id);
- return !pointable.tool ? pointable : Pointable.Invalid;
-};
-
-/**
- * The Hand object with the specified ID in this frame.
- *
- * Use the Frame hand() function to retrieve the Hand object from
- * this frame using an ID value obtained from a previous frame.
- * This function always returns a Hand object, but if no hand
- * with the specified ID is present, an invalid Hand object is returned.
- *
- * Note that ID values persist across frames, but only until tracking of a
- * particular object is lost. If tracking of a hand is lost and subsequently
- * regained, the new Hand object representing that physical hand may have
- * a different ID than that representing the physical hand in an earlier frame.
- *
- * @method hand
- * @memberof Leap.Frame.prototype
- * @param {String} id The ID value of a Hand object from a previous frame.
- * @returns {Leap.Hand} The Hand object with the matching
- * ID if one exists in this frame; otherwise, an invalid Hand object is returned.
- */
-Frame.prototype.hand = function(id) {
- return this.handsMap[id] || Hand.Invalid;
-};
-
-/**
- * The angle of rotation around the rotation axis derived from the overall
- * rotational motion between the current frame and the specified frame.
- *
- * The returned angle is expressed in radians measured clockwise around
- * the rotation axis (using the right-hand rule) between the start and end frames.
- * The value is always between 0 and pi radians (0 and 180 degrees).
- *
- * The Leap derives frame rotation from the relative change in position and
- * orientation of all objects detected in the field of view.
- *
- * If either this frame or sinceFrame is an invalid Frame object, then the
- * angle of rotation is zero.
- *
- * @method rotationAngle
- * @memberof Leap.Frame.prototype
- * @param {Leap.Frame} sinceFrame The starting frame for computing the relative rotation.
- * @param {number[]} [axis] The axis to measure rotation around.
- * @returns {number} A positive value containing the heuristically determined
- * rotational change between the current frame and that specified in the sinceFrame parameter.
- */
-Frame.prototype.rotationAngle = function(sinceFrame, axis) {
- if (!this.valid || !sinceFrame.valid) return 0.0;
-
- var rot = this.rotationMatrix(sinceFrame);
- var cs = (rot[0] + rot[4] + rot[8] - 1.0)*0.5;
- var angle = Math.acos(cs);
- angle = isNaN(angle) ? 0.0 : angle;
-
- if (axis !== undefined) {
- var rotAxis = this.rotationAxis(sinceFrame);
- angle *= vec3.dot(rotAxis, vec3.normalize(vec3.create(), axis));
- }
-
- return angle;
-};
-
-/**
- * The axis of rotation derived from the overall rotational motion between
- * the current frame and the specified frame.
- *
- * The returned direction vector is normalized.
- *
- * The Leap derives frame rotation from the relative change in position and
- * orientation of all objects detected in the field of view.
- *
- * If either this frame or sinceFrame is an invalid Frame object, or if no
- * rotation is detected between the two frames, a zero vector is returned.
- *
- * @method rotationAxis
- * @memberof Leap.Frame.prototype
- * @param {Leap.Frame} sinceFrame The starting frame for computing the relative rotation.
- * @returns {number[]} A normalized direction vector representing the axis of the heuristically determined
- * rotational change between the current frame and that specified in the sinceFrame parameter.
- */
-Frame.prototype.rotationAxis = function(sinceFrame) {
- if (!this.valid || !sinceFrame.valid) return vec3.create();
- return vec3.normalize(vec3.create(), [
- this._rotation[7] - sinceFrame._rotation[5],
- this._rotation[2] - sinceFrame._rotation[6],
- this._rotation[3] - sinceFrame._rotation[1]
- ]);
-}
-
-/**
- * The transform matrix expressing the rotation derived from the overall
- * rotational motion between the current frame and the specified frame.
- *
- * The Leap derives frame rotation from the relative change in position and
- * orientation of all objects detected in the field of view.
- *
- * If either this frame or sinceFrame is an invalid Frame object, then
- * this method returns an identity matrix.
- *
- * @method rotationMatrix
- * @memberof Leap.Frame.prototype
- * @param {Leap.Frame} sinceFrame The starting frame for computing the relative rotation.
- * @returns {number[]} A transformation matrix containing the heuristically determined
- * rotational change between the current frame and that specified in the sinceFrame parameter.
- */
-Frame.prototype.rotationMatrix = function(sinceFrame) {
- if (!this.valid || !sinceFrame.valid) return mat3.create();
- var transpose = mat3.transpose(mat3.create(), this._rotation)
- return mat3.multiply(mat3.create(), sinceFrame._rotation, transpose);
-}
-
-/**
- * The scale factor derived from the overall motion between the current frame and the specified frame.
- *
- * The scale factor is always positive. A value of 1.0 indicates no scaling took place.
- * Values between 0.0 and 1.0 indicate contraction and values greater than 1.0 indicate expansion.
- *
- * The Leap derives scaling from the relative inward or outward motion of all
- * objects detected in the field of view (independent of translation and rotation).
- *
- * If either this frame or sinceFrame is an invalid Frame object, then this method returns 1.0.
- *
- * @method scaleFactor
- * @memberof Leap.Frame.prototype
- * @param {Leap.Frame} sinceFrame The starting frame for computing the relative scaling.
- * @returns {number} A positive value representing the heuristically determined
- * scaling change ratio between the current frame and that specified in the sinceFrame parameter.
- */
-Frame.prototype.scaleFactor = function(sinceFrame) {
- if (!this.valid || !sinceFrame.valid) return 1.0;
- return Math.exp(this._scaleFactor - sinceFrame._scaleFactor);
-}
-
-/**
- * The change of position derived from the overall linear motion between the
- * current frame and the specified frame.
- *
- * The returned translation vector provides the magnitude and direction of the
- * movement in millimeters.
- *
- * The Leap derives frame translation from the linear motion of all objects
- * detected in the field of view.
- *
- * If either this frame or sinceFrame is an invalid Frame object, then this
- * method returns a zero vector.
- *
- * @method translation
- * @memberof Leap.Frame.prototype
- * @param {Leap.Frame} sinceFrame The starting frame for computing the relative translation.
- * @returns {number[]} A vector representing the heuristically determined change in
- * position of all objects between the current frame and that specified in the sinceFrame parameter.
- */
-Frame.prototype.translation = function(sinceFrame) {
- if (!this.valid || !sinceFrame.valid) return vec3.create();
- return vec3.subtract(vec3.create(), this._translation, sinceFrame._translation);
-}
-
-/**
- * A string containing a brief, human readable description of the Frame object.
- *
- * @method toString
- * @memberof Leap.Frame.prototype
- * @returns {String} A brief description of this frame.
- */
-Frame.prototype.toString = function() {
- var str = "Frame [ id:"+this.id+" | timestamp:"+this.timestamp+" | Hand count:("+this.hands.length+") | Pointable count:("+this.pointables.length+")";
- if (this.gestures) str += " | Gesture count:("+this.gestures.length+")";
- str += " ]";
- return str;
-}
-
-/**
- * Returns a JSON-formatted string containing the hands, pointables and gestures
- * in this frame.
- *
- * @method dump
- * @memberof Leap.Frame.prototype
- * @returns {String} A JSON-formatted string.
- */
-Frame.prototype.dump = function() {
- var out = '';
- out += "Frame Info: ";
- out += this.toString();
- out += "
Raw JSON: ";
- out += JSON.stringify(this.data);
- return out;
-}
-
-/**
- * An invalid Frame object.
- *
- * You can use this invalid Frame in comparisons testing
- * whether a given Frame instance is valid or invalid. (You can also check the
- * [Frame.valid]{@link Leap.Frame#valid} property.)
- *
- * @static
- * @type {Leap.Frame}
- * @name Invalid
- * @memberof Leap.Frame
- */
-Frame.Invalid = {
- valid: false,
- hands: [],
- fingers: [],
- tools: [],
- gestures: [],
- pointables: [],
- pointable: function() { return Pointable.Invalid },
- finger: function() { return Pointable.Invalid },
- hand: function() { return Hand.Invalid },
- toString: function() { return "invalid frame" },
- dump: function() { return this.toString() },
- rotationAngle: function() { return 0.0; },
- rotationMatrix: function() { return mat3.create(); },
- rotationAxis: function() { return vec3.create(); },
- scaleFactor: function() { return 1.0; },
- translation: function() { return vec3.create(); }
-};
-
-},{"./finger":7,"./gesture":9,"./hand":10,"./interaction_box":12,"./pointable":14,"gl-matrix":23,"underscore":24}],9:[function(require,module,exports){
-var glMatrix = require("gl-matrix")
- , vec3 = glMatrix.vec3
- , EventEmitter = require('events').EventEmitter
- , _ = require('underscore');
-
-/**
- * Constructs a new Gesture object.
- *
- * An uninitialized Gesture object is considered invalid. Get valid instances
- * of the Gesture class, which will be one of the Gesture subclasses, from a
- * Frame object.
- *
- * @class Gesture
- * @abstract
- * @memberof Leap
- * @classdesc
- * The Gesture class represents a recognized movement by the user.
- *
- * The Leap watches the activity within its field of view for certain movement
- * patterns typical of a user gesture or command. For example, a movement from side to
- * side with the hand can indicate a swipe gesture, while a finger poking forward
- * can indicate a screen tap gesture.
- *
- * When the Leap recognizes a gesture, it assigns an ID and adds a
- * Gesture object to the frame gesture list. For continuous gestures, which
- * occur over many frames, the Leap updates the gesture by adding
- * a Gesture object having the same ID and updated properties in each
- * subsequent frame.
- *
- * **Important:** Recognition for each type of gesture must be enabled;
- * otherwise **no gestures are recognized or reported**.
- *
- * Subclasses of Gesture define the properties for the specific movement patterns
- * recognized by the Leap.
- *
- * The Gesture subclasses for include:
- *
- * * CircleGesture -- A circular movement by a finger.
- * * SwipeGesture -- A straight line movement by the hand with fingers extended.
- * * ScreenTapGesture -- A forward tapping movement by a finger.
- * * KeyTapGesture -- A downward tapping movement by a finger.
- *
- * Circle and swipe gestures are continuous and these objects can have a
- * state of start, update, and stop.
- *
- * The screen tap gesture is a discrete gesture. The Leap only creates a single
- * ScreenTapGesture object appears for each tap and it always has a stop state.
- *
- * Get valid Gesture instances from a Frame object. You can get a list of gestures
- * from the Frame gestures array. You can also use the Frame gesture() method
- * to find a gesture in the current frame using an ID value obtained in a
- * previous frame.
- *
- * Gesture objects can be invalid. For example, when you get a gesture by ID
- * using Frame.gesture(), and there is no gesture with that ID in the current
- * frame, then gesture() returns an Invalid Gesture object (rather than a null
- * value). Always check object validity in situations where a gesture might be
- * invalid.
- */
-var createGesture = exports.createGesture = function(data) {
- var gesture;
- switch (data.type) {
- case 'circle':
- gesture = new CircleGesture(data);
- break;
- case 'swipe':
- gesture = new SwipeGesture(data);
- break;
- case 'screenTap':
- gesture = new ScreenTapGesture(data);
- break;
- case 'keyTap':
- gesture = new KeyTapGesture(data);
- break;
- default:
- throw "unknown gesture type";
- }
-
- /**
- * The gesture ID.
- *
- * All Gesture objects belonging to the same recognized movement share the
- * same ID value. Use the ID value with the Frame::gesture() method to
- * find updates related to this Gesture object in subsequent frames.
- *
- * @member id
- * @memberof Leap.Gesture.prototype
- * @type {number}
- */
- gesture.id = data.id;
- /**
- * The list of hands associated with this Gesture, if any.
- *
- * If no hands are related to this gesture, the list is empty.
- *
- * @member handIds
- * @memberof Leap.Gesture.prototype
- * @type {Array}
- */
- gesture.handIds = data.handIds.slice();
- /**
- * The list of fingers and tools associated with this Gesture, if any.
- *
- * If no Pointable objects are related to this gesture, the list is empty.
- *
- * @member pointableIds
- * @memberof Leap.Gesture.prototype
- * @type {Array}
- */
- gesture.pointableIds = data.pointableIds.slice();
- /**
- * The elapsed duration of the recognized movement up to the
- * frame containing this Gesture object, in microseconds.
- *
- * The duration reported for the first Gesture in the sequence (with the
- * start state) will typically be a small positive number since
- * the movement must progress far enough for the Leap to recognize it as
- * an intentional gesture.
- *
- * @member duration
- * @memberof Leap.Gesture.prototype
- * @type {number}
- */
- gesture.duration = data.duration;
- /**
- * The gesture ID.
- *
- * Recognized movements occur over time and have a beginning, a middle,
- * and an end. The 'state()' attribute reports where in that sequence this
- * Gesture object falls.
- *
- * Possible values for the state field are:
- *
- * * start
- * * update
- * * stop
- *
- * @member state
- * @memberof Leap.Gesture.prototype
- * @type {String}
- */
- gesture.state = data.state;
- /**
- * The gesture type.
- *
- * Possible values for the type field are:
- *
- * * circle
- * * swipe
- * * screenTap
- * * keyTap
- *
- * @member type
- * @memberof Leap.Gesture.prototype
- * @type {String}
- */
- gesture.type = data.type;
- return gesture;
-}
-
-/*
- * Returns a builder object, which uses method chaining for gesture callback binding.
- */
-var gestureListener = exports.gestureListener = function(controller, type) {
- var handlers = {};
- var gestureMap = {};
-
- controller.on('gesture', function(gesture, frame) {
- if (gesture.type == type) {
- if (gesture.state == "start" || gesture.state == "stop") {
- if (gestureMap[gesture.id] === undefined) {
- var gestureTracker = new Gesture(gesture, frame);
- gestureMap[gesture.id] = gestureTracker;
- _.each(handlers, function(cb, name) {
- gestureTracker.on(name, cb);
- });
- }
- }
- gestureMap[gesture.id].update(gesture, frame);
- if (gesture.state == "stop") {
- delete gestureMap[gesture.id];
- }
- }
- });
- var builder = {
- start: function(cb) {
- handlers['start'] = cb;
- return builder;
- },
- stop: function(cb) {
- handlers['stop'] = cb;
- return builder;
- },
- complete: function(cb) {
- handlers['stop'] = cb;
- return builder;
- },
- update: function(cb) {
- handlers['update'] = cb;
- return builder;
- }
- }
- return builder;
-}
-
-var Gesture = exports.Gesture = function(gesture, frame) {
- this.gestures = [gesture];
- this.frames = [frame];
-}
-
-Gesture.prototype.update = function(gesture, frame) {
- this.lastGesture = gesture;
- this.lastFrame = frame;
- this.gestures.push(gesture);
- this.frames.push(frame);
- this.emit(gesture.state, this);
-}
-
-Gesture.prototype.translation = function() {
- return vec3.subtract(vec3.create(), this.lastGesture.startPosition, this.lastGesture.position);
-}
-
-_.extend(Gesture.prototype, EventEmitter.prototype);
-
-/**
- * Constructs a new CircleGesture object.
- *
- * An uninitialized CircleGesture object is considered invalid. Get valid instances
- * of the CircleGesture class from a Frame object.
- *
- * @class CircleGesture
- * @memberof Leap
- * @augments Leap.Gesture
- * @classdesc
- * The CircleGesture classes represents a circular finger movement.
- *
- * A circle movement is recognized when the tip of a finger draws a circle
- * within the Leap field of view.
- *
- * ![CircleGesture](images/Leap_Gesture_Circle.png)
- *
- * Circle gestures are continuous. The CircleGesture objects for the gesture have
- * three possible states:
- *
- * * start -- The circle gesture has just started. The movement has
- * progressed far enough for the recognizer to classify it as a circle.
- * * update -- The circle gesture is continuing.
- * * stop -- The circle gesture is finished.
- */
-var CircleGesture = function(data) {
- /**
- * The center point of the circle within the Leap frame of reference.
- *
- * @member center
- * @memberof Leap.CircleGesture.prototype
- * @type {number[]}
- */
- this.center = data.center;
- /**
- * The normal vector for the circle being traced.
- *
- * If you draw the circle clockwise, the normal vector points in the same
- * general direction as the pointable object drawing the circle. If you draw
- * the circle counterclockwise, the normal points back toward the
- * pointable. If the angle between the normal and the pointable object
- * drawing the circle is less than 90 degrees, then the circle is clockwise.
- *
- * ```javascript
- * var clockwiseness;
- * if (circle.pointable.direction.angleTo(circle.normal) <= PI/4) {
- * clockwiseness = "clockwise";
- * }
- * else
- * {
- * clockwiseness = "counterclockwise";
- * }
- * ```
- *
- * @member normal
- * @memberof Leap.CircleGesture.prototype
- * @type {number[]}
- */
- this.normal = data.normal;
- /**
- * The number of times the finger tip has traversed the circle.
- *
- * Progress is reported as a positive number of the number. For example,
- * a progress value of .5 indicates that the finger has gone halfway
- * around, while a value of 3 indicates that the finger has gone around
- * the the circle three times.
- *
- * Progress starts where the circle gesture began. Since the circle
- * must be partially formed before the Leap can recognize it, progress
- * will be greater than zero when a circle gesture first appears in the
- * frame.
- *
- * @member progress
- * @memberof Leap.CircleGesture.prototype
- * @type {number}
- */
- this.progress = data.progress;
- /**
- * The radius of the circle in mm.
- *
- * @member radius
- * @memberof Leap.CircleGesture.prototype
- * @type {number}
- */
- this.radius = data.radius;
-}
-
-CircleGesture.prototype.toString = function() {
- return "CircleGesture ["+JSON.stringify(this)+"]";
-}
-
-/**
- * Constructs a new SwipeGesture object.
- *
- * An uninitialized SwipeGesture object is considered invalid. Get valid instances
- * of the SwipeGesture class from a Frame object.
- *
- * @class SwipeGesture
- * @memberof Leap
- * @augments Leap.Gesture
- * @classdesc
- * The SwipeGesture class represents a swiping motion of a finger or tool.
- *
- * ![SwipeGesture](images/Leap_Gesture_Swipe.png)
- *
- * Swipe gestures are continuous.
- */
-var SwipeGesture = function(data) {
- /**
- * The starting position within the Leap frame of
- * reference, in mm.
- *
- * @member startPosition
- * @memberof Leap.SwipeGesture.prototype
- * @type {number[]}
- */
- this.startPosition = data.startPosition;
- /**
- * The current swipe position within the Leap frame of
- * reference, in mm.
- *
- * @member position
- * @memberof Leap.SwipeGesture.prototype
- * @type {number[]}
- */
- this.position = data.position;
- /**
- * The unit direction vector parallel to the swipe motion.
- *
- * You can compare the components of the vector to classify the swipe as
- * appropriate for your application. For example, if you are using swipes
- * for two dimensional scrolling, you can compare the x and y values to
- * determine if the swipe is primarily horizontal or vertical.
- *
- * @member direction
- * @memberof Leap.SwipeGesture.prototype
- * @type {number[]}
- */
- this.direction = data.direction;
- /**
- * The speed of the finger performing the swipe gesture in
- * millimeters per second.
- *
- * @member speed
- * @memberof Leap.SwipeGesture.prototype
- * @type {number}
- */
- this.speed = data.speed;
-}
-
-SwipeGesture.prototype.toString = function() {
- return "SwipeGesture ["+JSON.stringify(this)+"]";
-}
-
-/**
- * Constructs a new ScreenTapGesture object.
- *
- * An uninitialized ScreenTapGesture object is considered invalid. Get valid instances
- * of the ScreenTapGesture class from a Frame object.
- *
- * @class ScreenTapGesture
- * @memberof Leap
- * @augments Leap.Gesture
- * @classdesc
- * The ScreenTapGesture class represents a tapping gesture by a finger or tool.
- *
- * A screen tap gesture is recognized when the tip of a finger pokes forward
- * and then springs back to approximately the original postion, as if
- * tapping a vertical screen. The tapping finger must pause briefly before beginning the tap.
- *
- * ![ScreenTap](images/Leap_Gesture_Tap2.png)
- *
- * ScreenTap gestures are discrete. The ScreenTapGesture object representing a tap always
- * has the state, STATE_STOP. Only one ScreenTapGesture object is created for each
- * screen tap gesture recognized.
- */
-var ScreenTapGesture = function(data) {
- /**
- * The position where the screen tap is registered.
- *
- * @member position
- * @memberof Leap.ScreenTapGesture.prototype
- * @type {number[]}
- */
- this.position = data.position;
- /**
- * The direction of finger tip motion.
- *
- * @member direction
- * @memberof Leap.ScreenTapGesture.prototype
- * @type {number[]}
- */
- this.direction = data.direction;
- /**
- * The progess value is always 1.0 for a screen tap gesture.
- *
- * @member progress
- * @memberof Leap.ScreenTapGesture.prototype
- * @type {number}
- */
- this.progress = data.progress;
-}
-
-ScreenTapGesture.prototype.toString = function() {
- return "ScreenTapGesture ["+JSON.stringify(this)+"]";
-}
-
-/**
- * Constructs a new KeyTapGesture object.
- *
- * An uninitialized KeyTapGesture object is considered invalid. Get valid instances
- * of the KeyTapGesture class from a Frame object.
- *
- * @class KeyTapGesture
- * @memberof Leap
- * @augments Leap.Gesture
- * @classdesc
- * The KeyTapGesture class represents a tapping gesture by a finger or tool.
- *
- * A key tap gesture is recognized when the tip of a finger rotates down toward the
- * palm and then springs back to approximately the original postion, as if
- * tapping. The tapping finger must pause briefly before beginning the tap.
- *
- * ![KeyTap](images/Leap_Gesture_Tap.png)
- *
- * Key tap gestures are discrete. The KeyTapGesture object representing a tap always
- * has the state, STATE_STOP. Only one KeyTapGesture object is created for each
- * key tap gesture recognized.
- */
-var KeyTapGesture = function(data) {
- /**
- * The position where the key tap is registered.
- *
- * @member position
- * @memberof Leap.KeyTapGesture.prototype
- * @type {number[]}
- */
- this.position = data.position;
- /**
- * The direction of finger tip motion.
- *
- * @member direction
- * @memberof Leap.KeyTapGesture.prototype
- * @type {number[]}
- */
- this.direction = data.direction;
- /**
- * The progess value is always 1.0 for a key tap gesture.
- *
- * @member progress
- * @memberof Leap.KeyTapGesture.prototype
- * @type {number}
- */
- this.progress = data.progress;
-}
-
-KeyTapGesture.prototype.toString = function() {
- return "KeyTapGesture ["+JSON.stringify(this)+"]";
-}
-
-},{"events":21,"gl-matrix":23,"underscore":24}],10:[function(require,module,exports){
-var Pointable = require("./pointable")
- , Bone = require('./bone')
- , glMatrix = require("gl-matrix")
- , mat3 = glMatrix.mat3
- , vec3 = glMatrix.vec3
- , _ = require("underscore");
-
-/**
- * Constructs a Hand object.
- *
- * An uninitialized hand is considered invalid.
- * Get valid Hand objects from a Frame object.
- * @class Hand
- * @memberof Leap
- * @classdesc
- * The Hand class reports the physical characteristics of a detected hand.
- *
- * Hand tracking data includes a palm position and velocity; vectors for
- * the palm normal and direction to the fingers; properties of a sphere fit
- * to the hand; and lists of the attached fingers and tools.
- *
- * Note that Hand objects can be invalid, which means that they do not contain
- * valid tracking data and do not correspond to a physical entity. Invalid Hand
- * objects can be the result of asking for a Hand object using an ID from an
- * earlier frame when no Hand objects with that ID exist in the current frame.
- * A Hand object created from the Hand constructor is also invalid.
- * Test for validity with the [Hand.valid]{@link Leap.Hand#valid} property.
- */
-var Hand = module.exports = function(data) {
- /**
- * A unique ID assigned to this Hand object, whose value remains the same
- * across consecutive frames while the tracked hand remains visible. If
- * tracking is lost (for example, when a hand is occluded by another hand
- * or when it is withdrawn from or reaches the edge of the Leap field of view),
- * the Leap may assign a new ID when it detects the hand in a future frame.
- *
- * Use the ID value with the {@link Frame.hand}() function to find this
- * Hand object in future frames.
- *
- * @member id
- * @memberof Leap.Hand.prototype
- * @type {String}
- */
- this.id = data.id;
- /**
- * The center position of the palm in millimeters from the Leap origin.
- * @member palmPosition
- * @memberof Leap.Hand.prototype
- * @type {number[]}
- */
- this.palmPosition = data.palmPosition;
- /**
- * The direction from the palm position toward the fingers.
- *
- * The direction is expressed as a unit vector pointing in the same
- * direction as the directed line from the palm position to the fingers.
- *
- * @member direction
- * @memberof Leap.Hand.prototype
- * @type {number[]}
- */
- this.direction = data.direction;
- /**
- * The rate of change of the palm position in millimeters/second.
- *
- * @member palmVeclocity
- * @memberof Leap.Hand.prototype
- * @type {number[]}
- */
- this.palmVelocity = data.palmVelocity;
- /**
- * The normal vector to the palm. If your hand is flat, this vector will
- * point downward, or "out" of the front surface of your palm.
- *
- * ![Palm Vectors](images/Leap_Palm_Vectors.png)
- *
- * The direction is expressed as a unit vector pointing in the same
- * direction as the palm normal (that is, a vector orthogonal to the palm).
- * @member palmNormal
- * @memberof Leap.Hand.prototype
- * @type {number[]}
- */
- this.palmNormal = data.palmNormal;
- /**
- * The center of a sphere fit to the curvature of this hand.
- *
- * This sphere is placed roughly as if the hand were holding a ball.
- *
- * ![Hand Ball](images/Leap_Hand_Ball.png)
- * @member sphereCenter
- * @memberof Leap.Hand.prototype
- * @type {number[]}
- */
- this.sphereCenter = data.sphereCenter;
- /**
- * The radius of a sphere fit to the curvature of this hand, in millimeters.
- *
- * This sphere is placed roughly as if the hand were holding a ball. Thus the
- * size of the sphere decreases as the fingers are curled into a fist.
- *
- * @member sphereRadius
- * @memberof Leap.Hand.prototype
- * @type {number}
- */
- this.sphereRadius = data.sphereRadius;
- /**
- * Reports whether this is a valid Hand object.
- *
- * @member valid
- * @memberof Leap.Hand.prototype
- * @type {boolean}
- */
- this.valid = true;
- /**
- * The list of Pointable objects (fingers and tools) detected in this frame
- * that are associated with this hand, given in arbitrary order. The list
- * can be empty if no fingers or tools associated with this hand are detected.
- *
- * Use the {@link Pointable} tool property to determine
- * whether or not an item in the list represents a tool or finger.
- * You can also get only the tools using the Hand.tools[] list or
- * only the fingers using the Hand.fingers[] list.
- *
- * @member pointables[]
- * @memberof Leap.Hand.prototype
- * @type {Leap.Pointable[]}
- */
- this.pointables = [];
- /**
- * The list of fingers detected in this frame that are attached to
- * this hand, given in arbitrary order.
- *
- * The list can be empty if no fingers attached to this hand are detected.
- *
- * @member fingers[]
- * @memberof Leap.Hand.prototype
- * @type {Leap.Pointable[]}
- */
- this.fingers = [];
-
- if (data.armBasis){
- this.arm = new Bone(this, {
- type: 4,
- width: data.armWidth,
- prevJoint: data.elbow,
- nextJoint: data.wrist,
- basis: data.armBasis
- });
- }else{
- this.arm = null;
- }
-
- /**
- * The list of tools detected in this frame that are held by this
- * hand, given in arbitrary order.
- *
- * The list can be empty if no tools held by this hand are detected.
- *
- * @member tools[]
- * @memberof Leap.Hand.prototype
- * @type {Leap.Pointable[]}
- */
- this.tools = [];
- this._translation = data.t;
- this._rotation = _.flatten(data.r);
- this._scaleFactor = data.s;
-
- /**
- * Time the hand has been visible in seconds.
- *
- * @member timeVisible
- * @memberof Leap.Hand.prototype
- * @type {number}
- */
- this.timeVisible = data.timeVisible;
-
- /**
- * The palm position with stabalization
- * @member stabilizedPalmPosition
- * @memberof Leap.Hand.prototype
- * @type {number[]}
- */
- this.stabilizedPalmPosition = data.stabilizedPalmPosition;
-
- /**
- * Reports whether this is a left or a right hand.
- *
- * @member type
- * @type {String}
- * @memberof Leap.Hand.prototype
- */
- this.type = data.type;
- this.grabStrength = data.grabStrength;
- this.pinchStrength = data.pinchStrength;
- this.confidence = data.confidence;
-}
-
-/**
- * The finger with the specified ID attached to this hand.
- *
- * Use this function to retrieve a Pointable object representing a finger
- * attached to this hand using an ID value obtained from a previous frame.
- * This function always returns a Pointable object, but if no finger
- * with the specified ID is present, an invalid Pointable object is returned.
- *
- * Note that the ID values assigned to fingers persist across frames, but only
- * until tracking of a particular finger is lost. If tracking of a finger is
- * lost and subsequently regained, the new Finger object representing that
- * finger may have a different ID than that representing the finger in an
- * earlier frame.
- *
- * @method finger
- * @memberof Leap.Hand.prototype
- * @param {String} id The ID value of a finger from a previous frame.
- * @returns {Leap.Pointable} The Finger object with
- * the matching ID if one exists for this hand in this frame; otherwise, an
- * invalid Finger object is returned.
- */
-Hand.prototype.finger = function(id) {
- var finger = this.frame.finger(id);
- return (finger && (finger.handId == this.id)) ? finger : Pointable.Invalid;
-}
-
-/**
- * The angle of rotation around the rotation axis derived from the change in
- * orientation of this hand, and any associated fingers and tools, between the
- * current frame and the specified frame.
- *
- * The returned angle is expressed in radians measured clockwise around the
- * rotation axis (using the right-hand rule) between the start and end frames.
- * The value is always between 0 and pi radians (0 and 180 degrees).
- *
- * If a corresponding Hand object is not found in sinceFrame, or if either
- * this frame or sinceFrame are invalid Frame objects, then the angle of rotation is zero.
- *
- * @method rotationAngle
- * @memberof Leap.Hand.prototype
- * @param {Leap.Frame} sinceFrame The starting frame for computing the relative rotation.
- * @param {numnber[]} [axis] The axis to measure rotation around.
- * @returns {number} A positive value representing the heuristically determined
- * rotational change of the hand between the current frame and that specified in
- * the sinceFrame parameter.
- */
-Hand.prototype.rotationAngle = function(sinceFrame, axis) {
- if (!this.valid || !sinceFrame.valid) return 0.0;
- var sinceHand = sinceFrame.hand(this.id);
- if(!sinceHand.valid) return 0.0;
- var rot = this.rotationMatrix(sinceFrame);
- var cs = (rot[0] + rot[4] + rot[8] - 1.0)*0.5
- var angle = Math.acos(cs);
- angle = isNaN(angle) ? 0.0 : angle;
- if (axis !== undefined) {
- var rotAxis = this.rotationAxis(sinceFrame);
- angle *= vec3.dot(rotAxis, vec3.normalize(vec3.create(), axis));
- }
- return angle;
-}
-
-/**
- * The axis of rotation derived from the change in orientation of this hand, and
- * any associated fingers and tools, between the current frame and the specified frame.
- *
- * The returned direction vector is normalized.
- *
- * If a corresponding Hand object is not found in sinceFrame, or if either
- * this frame or sinceFrame are invalid Frame objects, then this method returns a zero vector.
- *
- * @method rotationAxis
- * @memberof Leap.Hand.prototype
- * @param {Leap.Frame} sinceFrame The starting frame for computing the relative rotation.
- * @returns {number[]} A normalized direction Vector representing the axis of the heuristically determined
- * rotational change of the hand between the current frame and that specified in the sinceFrame parameter.
- */
-Hand.prototype.rotationAxis = function(sinceFrame) {
- if (!this.valid || !sinceFrame.valid) return vec3.create();
- var sinceHand = sinceFrame.hand(this.id);
- if (!sinceHand.valid) return vec3.create();
- return vec3.normalize(vec3.create(), [
- this._rotation[7] - sinceHand._rotation[5],
- this._rotation[2] - sinceHand._rotation[6],
- this._rotation[3] - sinceHand._rotation[1]
- ]);
-}
-
-/**
- * The transform matrix expressing the rotation derived from the change in
- * orientation of this hand, and any associated fingers and tools, between
- * the current frame and the specified frame.
- *
- * If a corresponding Hand object is not found in sinceFrame, or if either
- * this frame or sinceFrame are invalid Frame objects, then this method returns
- * an identity matrix.
- *
- * @method rotationMatrix
- * @memberof Leap.Hand.prototype
- * @param {Leap.Frame} sinceFrame The starting frame for computing the relative rotation.
- * @returns {number[]} A transformation Matrix containing the heuristically determined
- * rotational change of the hand between the current frame and that specified in the sinceFrame parameter.
- */
-Hand.prototype.rotationMatrix = function(sinceFrame) {
- if (!this.valid || !sinceFrame.valid) return mat3.create();
- var sinceHand = sinceFrame.hand(this.id);
- if(!sinceHand.valid) return mat3.create();
- var transpose = mat3.transpose(mat3.create(), this._rotation);
- var m = mat3.multiply(mat3.create(), sinceHand._rotation, transpose);
- return m;
-}
-
-/**
- * The scale factor derived from the hand's motion between the current frame and the specified frame.
- *
- * The scale factor is always positive. A value of 1.0 indicates no scaling took place.
- * Values between 0.0 and 1.0 indicate contraction and values greater than 1.0 indicate expansion.
- *
- * The Leap derives scaling from the relative inward or outward motion of a hand
- * and its associated fingers and tools (independent of translation and rotation).
- *
- * If a corresponding Hand object is not found in sinceFrame, or if either this frame or sinceFrame
- * are invalid Frame objects, then this method returns 1.0.
- *
- * @method scaleFactor
- * @memberof Leap.Hand.prototype
- * @param {Leap.Frame} sinceFrame The starting frame for computing the relative scaling.
- * @returns {number} A positive value representing the heuristically determined
- * scaling change ratio of the hand between the current frame and that specified in the sinceFrame parameter.
- */
-Hand.prototype.scaleFactor = function(sinceFrame) {
- if (!this.valid || !sinceFrame.valid) return 1.0;
- var sinceHand = sinceFrame.hand(this.id);
- if(!sinceHand.valid) return 1.0;
-
- return Math.exp(this._scaleFactor - sinceHand._scaleFactor);
-}
-
-/**
- * The change of position of this hand between the current frame and the specified frame
- *
- * The returned translation vector provides the magnitude and direction of the
- * movement in millimeters.
- *
- * If a corresponding Hand object is not found in sinceFrame, or if either this frame or
- * sinceFrame are invalid Frame objects, then this method returns a zero vector.
- *
- * @method translation
- * @memberof Leap.Hand.prototype
- * @param {Leap.Frame} sinceFrame The starting frame for computing the relative translation.
- * @returns {number[]} A Vector representing the heuristically determined change in hand
- * position between the current frame and that specified in the sinceFrame parameter.
- */
-Hand.prototype.translation = function(sinceFrame) {
- if (!this.valid || !sinceFrame.valid) return vec3.create();
- var sinceHand = sinceFrame.hand(this.id);
- if(!sinceHand.valid) return vec3.create();
- return [
- this._translation[0] - sinceHand._translation[0],
- this._translation[1] - sinceHand._translation[1],
- this._translation[2] - sinceHand._translation[2]
- ];
-}
-
-/**
- * A string containing a brief, human readable description of the Hand object.
- * @method toString
- * @memberof Leap.Hand.prototype
- * @returns {String} A description of the Hand as a string.
- */
-Hand.prototype.toString = function() {
- return "Hand (" + this.type + ") [ id: "+ this.id + " | palm velocity:"+this.palmVelocity+" | sphere center:"+this.sphereCenter+" ] ";
-}
-
-/**
- * The pitch angle in radians.
- *
- * Pitch is the angle between the negative z-axis and the projection of
- * the vector onto the y-z plane. In other words, pitch represents rotation
- * around the x-axis.
- * If the vector points upward, the returned angle is between 0 and pi radians
- * (180 degrees); if it points downward, the angle is between 0 and -pi radians.
- *
- * @method pitch
- * @memberof Leap.Hand.prototype
- * @returns {number} The angle of this vector above or below the horizon (x-z plane).
- *
- */
-Hand.prototype.pitch = function() {
- return Math.atan2(this.direction[1], -this.direction[2]);
-}
-
-/**
- * The yaw angle in radians.
- *
- * Yaw is the angle between the negative z-axis and the projection of
- * the vector onto the x-z plane. In other words, yaw represents rotation
- * around the y-axis. If the vector points to the right of the negative z-axis,
- * then the returned angle is between 0 and pi radians (180 degrees);
- * if it points to the left, the angle is between 0 and -pi radians.
- *
- * @method yaw
- * @memberof Leap.Hand.prototype
- * @returns {number} The angle of this vector to the right or left of the y-axis.
- *
- */
-Hand.prototype.yaw = function() {
- return Math.atan2(this.direction[0], -this.direction[2]);
-}
-
-/**
- * The roll angle in radians.
- *
- * Roll is the angle between the y-axis and the projection of
- * the vector onto the x-y plane. In other words, roll represents rotation
- * around the z-axis. If the vector points to the left of the y-axis,
- * then the returned angle is between 0 and pi radians (180 degrees);
- * if it points to the right, the angle is between 0 and -pi radians.
- *
- * @method roll
- * @memberof Leap.Hand.prototype
- * @returns {number} The angle of this vector to the right or left of the y-axis.
- *
- */
-Hand.prototype.roll = function() {
- return Math.atan2(this.palmNormal[0], -this.palmNormal[1]);
-}
-
-/**
- * An invalid Hand object.
- *
- * You can use an invalid Hand object in comparisons testing
- * whether a given Hand instance is valid or invalid. (You can also use the
- * Hand valid property.)
- *
- * @static
- * @type {Leap.Hand}
- * @name Invalid
- * @memberof Leap.Hand
- */
-Hand.Invalid = {
- valid: false,
- fingers: [],
- tools: [],
- pointables: [],
- left: false,
- pointable: function() { return Pointable.Invalid },
- finger: function() { return Pointable.Invalid },
- toString: function() { return "invalid frame" },
- dump: function() { return this.toString(); },
- rotationAngle: function() { return 0.0; },
- rotationMatrix: function() { return mat3.create(); },
- rotationAxis: function() { return vec3.create(); },
- scaleFactor: function() { return 1.0; },
- translation: function() { return vec3.create(); }
-};
-
-},{"./bone":1,"./pointable":14,"gl-matrix":23,"underscore":24}],11:[function(require,module,exports){
-/**
- * Leap is the global namespace of the Leap API.
- * @namespace Leap
- */
-module.exports = {
- Controller: require("./controller"),
- Frame: require("./frame"),
- Gesture: require("./gesture"),
- Hand: require("./hand"),
- Pointable: require("./pointable"),
- Finger: require("./finger"),
- InteractionBox: require("./interaction_box"),
- CircularBuffer: require("./circular_buffer"),
- UI: require("./ui"),
- JSONProtocol: require("./protocol").JSONProtocol,
- glMatrix: require("gl-matrix"),
- mat3: require("gl-matrix").mat3,
- vec3: require("gl-matrix").vec3,
- loopController: undefined,
- version: require('./version.js'),
-
- /**
- * Expose utility libraries for convenience
- * Use carefully - they may be subject to upgrade or removal in different versions of LeapJS.
- *
- */
- _: require('underscore'),
- EventEmitter: require('events').EventEmitter,
-
- /**
- * The Leap.loop() function passes a frame of Leap data to your
- * callback function and then calls window.requestAnimationFrame() after
- * executing your callback function.
- *
- * Leap.loop() sets up the Leap controller and WebSocket connection for you.
- * You do not need to create your own controller when using this method.
- *
- * Your callback function is called on an interval determined by the client
- * browser. Typically, this is on an interval of 60 frames/second. The most
- * recent frame of Leap data is passed to your callback function. If the Leap
- * is producing frames at a slower rate than the browser frame rate, the same
- * frame of Leap data can be passed to your function in successive animation
- * updates.
- *
- * As an alternative, you can create your own Controller object and use a
- * {@link Controller#onFrame onFrame} callback to process the data at
- * the frame rate of the Leap device. See {@link Controller} for an
- * example.
- *
- * @method Leap.loop
- * @param {function} callback A function called when the browser is ready to
- * draw to the screen. The most recent {@link Frame} object is passed to
- * your callback function.
- *
- * ```javascript
- * Leap.loop( function( frame ) {
- * // ... your code here
- * })
- * ```
- */
- loop: function(opts, callback) {
- if (opts && callback === undefined && ( ({}).toString.call(opts) === '[object Function]' ) ) {
- callback = opts;
- opts = {};
- }
-
- if (this.loopController) {
- if (opts){
- this.loopController.setupFrameEvents(opts);
- }
- }else{
- this.loopController = new this.Controller(opts);
- }
-
- this.loopController.loop(callback);
- return this.loopController;
- },
-
- /*
- * Convenience method for Leap.Controller.plugin
- */
- plugin: function(name, options){
- this.Controller.plugin(name, options)
- }
-}
-
-},{"./circular_buffer":2,"./controller":5,"./finger":7,"./frame":8,"./gesture":9,"./hand":10,"./interaction_box":12,"./pointable":14,"./protocol":15,"./ui":16,"./version.js":19,"events":21,"gl-matrix":23,"underscore":24}],12:[function(require,module,exports){
-var glMatrix = require("gl-matrix")
- , vec3 = glMatrix.vec3;
-
-/**
- * Constructs a InteractionBox object.
- *
- * @class InteractionBox
- * @memberof Leap
- * @classdesc
- * The InteractionBox class represents a box-shaped region completely within
- * the field of view of the Leap Motion controller.
- *
- * The interaction box is an axis-aligned rectangular prism and provides
- * normalized coordinates for hands, fingers, and tools within this box.
- * The InteractionBox class can make it easier to map positions in the
- * Leap Motion coordinate system to 2D or 3D coordinate systems used
- * for application drawing.
- *
- * ![Interaction Box](images/Leap_InteractionBox.png)
- *
- * The InteractionBox region is defined by a center and dimensions along the x, y, and z axes.
- */
-var InteractionBox = module.exports = function(data) {
- /**
- * Indicates whether this is a valid InteractionBox object.
- *
- * @member valid
- * @type {Boolean}
- * @memberof Leap.InteractionBox.prototype
- */
- this.valid = true;
- /**
- * The center of the InteractionBox in device coordinates (millimeters).
- * This point is equidistant from all sides of the box.
- *
- * @member center
- * @type {number[]}
- * @memberof Leap.InteractionBox.prototype
- */
- this.center = data.center;
-
- this.size = data.size;
- /**
- * The width of the InteractionBox in millimeters, measured along the x-axis.
- *
- * @member width
- * @type {number}
- * @memberof Leap.InteractionBox.prototype
- */
- this.width = data.size[0];
- /**
- * The height of the InteractionBox in millimeters, measured along the y-axis.
- *
- * @member height
- * @type {number}
- * @memberof Leap.InteractionBox.prototype
- */
- this.height = data.size[1];
- /**
- * The depth of the InteractionBox in millimeters, measured along the z-axis.
- *
- * @member depth
- * @type {number}
- * @memberof Leap.InteractionBox.prototype
- */
- this.depth = data.size[2];
-}
-
-/**
- * Converts a position defined by normalized InteractionBox coordinates
- * into device coordinates in millimeters.
- *
- * This function performs the inverse of normalizePoint().
- *
- * @method denormalizePoint
- * @memberof Leap.InteractionBox.prototype
- * @param {number[]} normalizedPosition The input position in InteractionBox coordinates.
- * @returns {number[]} The corresponding denormalized position in device coordinates.
- */
-InteractionBox.prototype.denormalizePoint = function(normalizedPosition) {
- return vec3.fromValues(
- (normalizedPosition[0] - 0.5) * this.size[0] + this.center[0],
- (normalizedPosition[1] - 0.5) * this.size[1] + this.center[1],
- (normalizedPosition[2] - 0.5) * this.size[2] + this.center[2]
- );
-}
-
-/**
- * Normalizes the coordinates of a point using the interaction box.
- *
- * Coordinates from the Leap Motion frame of reference (millimeters) are
- * converted to a range of [0..1] such that the minimum value of the
- * InteractionBox maps to 0 and the maximum value of the InteractionBox maps to 1.
- *
- * @method normalizePoint
- * @memberof Leap.InteractionBox.prototype
- * @param {number[]} position The input position in device coordinates.
- * @param {Boolean} clamp Whether or not to limit the output value to the range [0,1]
- * when the input position is outside the InteractionBox. Defaults to true.
- * @returns {number[]} The normalized position.
- */
-InteractionBox.prototype.normalizePoint = function(position, clamp) {
- var vec = vec3.fromValues(
- ((position[0] - this.center[0]) / this.size[0]) + 0.5,
- ((position[1] - this.center[1]) / this.size[1]) + 0.5,
- ((position[2] - this.center[2]) / this.size[2]) + 0.5
- );
-
- if (clamp) {
- vec[0] = Math.min(Math.max(vec[0], 0), 1);
- vec[1] = Math.min(Math.max(vec[1], 0), 1);
- vec[2] = Math.min(Math.max(vec[2], 0), 1);
- }
- return vec;
-}
-
-/**
- * Writes a brief, human readable description of the InteractionBox object.
- *
- * @method toString
- * @memberof Leap.InteractionBox.prototype
- * @returns {String} A description of the InteractionBox object as a string.
- */
-InteractionBox.prototype.toString = function() {
- return "InteractionBox [ width:" + this.width + " | height:" + this.height + " | depth:" + this.depth + " ]";
-}
-
-/**
- * An invalid InteractionBox object.
- *
- * You can use this InteractionBox instance in comparisons testing
- * whether a given InteractionBox instance is valid or invalid. (You can also use the
- * InteractionBox.valid property.)
- *
- * @static
- * @type {Leap.InteractionBox}
- * @name Invalid
- * @memberof Leap.InteractionBox
- */
-InteractionBox.Invalid = { valid: false };
-
-},{"gl-matrix":23}],13:[function(require,module,exports){
-var Pipeline = module.exports = function (controller) {
- this.steps = [];
- this.controller = controller;
-}
-
-Pipeline.prototype.addStep = function (step) {
- this.steps.push(step);
-}
-
-Pipeline.prototype.run = function (frame) {
- var stepsLength = this.steps.length;
- for (var i = 0; i != stepsLength; i++) {
- if (!frame) break;
- frame = this.steps[i](frame);
- }
- return frame;
-}
-
-Pipeline.prototype.removeStep = function(step){
- var index = this.steps.indexOf(step);
- if (index === -1) throw "Step not found in pipeline";
- this.steps.splice(index, 1);
-}
-
-/*
- * Wraps a plugin callback method in method which can be run inside the pipeline.
- * This wrapper method loops the callback over objects within the frame as is appropriate,
- * calling the callback for each in turn.
- *
- * @method createStepFunction
- * @memberOf Leap.Controller.prototype
- * @param {Controller} The controller on which the callback is called.
- * @param {String} type What frame object the callback is run for and receives.
- * Can be one of 'frame', 'finger', 'hand', 'pointable', 'tool'
- * @param {function} callback The method which will be run inside the pipeline loop. Receives one argument, such as a hand.
- * @private
- */
-Pipeline.prototype.addWrappedStep = function (type, callback) {
- var controller = this.controller,
- step = function (frame) {
- var dependencies, i, len;
- dependencies = (type == 'frame') ? [frame] : (frame[type + 's'] || []);
-
- for (i = 0, len = dependencies.length; i < len; i++) {
- callback.call(controller, dependencies[i]);
- }
-
- return frame;
- };
-
- this.addStep(step);
- return step;
-};
-},{}],14:[function(require,module,exports){
-var glMatrix = require("gl-matrix")
- , vec3 = glMatrix.vec3;
-
-/**
- * Constructs a Pointable object.
- *
- * An uninitialized pointable is considered invalid.
- * Get valid Pointable objects from a Frame or a Hand object.
- *
- * @class Pointable
- * @memberof Leap
- * @classdesc
- * The Pointable class reports the physical characteristics of a detected
- * finger or tool.
- *
- * Both fingers and tools are classified as Pointable objects. Use the
- * Pointable.tool property to determine whether a Pointable object represents a
- * tool or finger. The Leap classifies a detected entity as a tool when it is
- * thinner, straighter, and longer than a typical finger.
- *
- * Note that Pointable objects can be invalid, which means that they do not
- * contain valid tracking data and do not correspond to a physical entity.
- * Invalid Pointable objects can be the result of asking for a Pointable object
- * using an ID from an earlier frame when no Pointable objects with that ID
- * exist in the current frame. A Pointable object created from the Pointable
- * constructor is also invalid. Test for validity with the Pointable.valid
- * property.
- */
-var Pointable = module.exports = function(data) {
- /**
- * Indicates whether this is a valid Pointable object.
- *
- * @member valid
- * @type {Boolean}
- * @memberof Leap.Pointable.prototype
- */
- this.valid = true;
- /**
- * A unique ID assigned to this Pointable object, whose value remains the
- * same across consecutive frames while the tracked finger or tool remains
- * visible. If tracking is lost (for example, when a finger is occluded by
- * another finger or when it is withdrawn from the Leap field of view), the
- * Leap may assign a new ID when it detects the entity in a future frame.
- *
- * Use the ID value with the pointable() functions defined for the
- * {@link Frame} and {@link Frame.Hand} classes to find this
- * Pointable object in future frames.
- *
- * @member id
- * @type {String}
- * @memberof Leap.Pointable.prototype
- */
- this.id = data.id;
- this.handId = data.handId;
- /**
- * The estimated length of the finger or tool in millimeters.
- *
- * The reported length is the visible length of the finger or tool from the
- * hand to tip. If the length isn't known, then a value of 0 is returned.
- *
- * @member length
- * @type {number}
- * @memberof Leap.Pointable.prototype
- */
- this.length = data.length;
- /**
- * Whether or not the Pointable is believed to be a tool.
- * Tools are generally longer, thinner, and straighter than fingers.
- *
- * If tool is false, then this Pointable must be a finger.
- *
- * @member tool
- * @type {Boolean}
- * @memberof Leap.Pointable.prototype
- */
- this.tool = data.tool;
- /**
- * The estimated width of the tool in millimeters.
- *
- * The reported width is the average width of the visible portion of the
- * tool from the hand to the tip. If the width isn't known,
- * then a value of 0 is returned.
- *
- * Pointable objects representing fingers do not have a width property.
- *
- * @member width
- * @type {number}
- * @memberof Leap.Pointable.prototype
- */
- this.width = data.width;
- /**
- * The direction in which this finger or tool is pointing.
- *
- * The direction is expressed as a unit vector pointing in the same
- * direction as the tip.
- *
- * ![Finger](images/Leap_Finger_Model.png)
- * @member direction
- * @type {number[]}
- * @memberof Leap.Pointable.prototype
- */
- this.direction = data.direction;
- /**
- * The tip position in millimeters from the Leap origin.
- * Stabilized
- *
- * @member stabilizedTipPosition
- * @type {number[]}
- * @memberof Leap.Pointable.prototype
- */
- this.stabilizedTipPosition = data.stabilizedTipPosition;
- /**
- * The tip position in millimeters from the Leap origin.
- *
- * @member tipPosition
- * @type {number[]}
- * @memberof Leap.Pointable.prototype
- */
- this.tipPosition = data.tipPosition;
- /**
- * The rate of change of the tip position in millimeters/second.
- *
- * @member tipVelocity
- * @type {number[]}
- * @memberof Leap.Pointable.prototype
- */
- this.tipVelocity = data.tipVelocity;
- /**
- * The current touch zone of this Pointable object.
- *
- * The Leap Motion software computes the touch zone based on a floating touch
- * plane that adapts to the user's finger movement and hand posture. The Leap
- * Motion software interprets purposeful movements toward this plane as potential touch
- * points. When a Pointable moves close to the adaptive touch plane, it enters the
- * "hovering" zone. When a Pointable reaches or passes through the plane, it enters
- * the "touching" zone.
- *
- * The possible states include:
- *
- * * "none" -- The Pointable is outside the hovering zone.
- * * "hovering" -- The Pointable is close to, but not touching the touch plane.
- * * "touching" -- The Pointable has penetrated the touch plane.
- *
- * The touchDistance value provides a normalized indication of the distance to
- * the touch plane when the Pointable is in the hovering or touching zones.
- *
- * @member touchZone
- * @type {String}
- * @memberof Leap.Pointable.prototype
- */
- this.touchZone = data.touchZone;
- /**
- * A value proportional to the distance between this Pointable object and the
- * adaptive touch plane.
- *
- * ![Touch Distance](images/Leap_Touch_Plane.png)
- *
- * The touch distance is a value in the range [-1, 1]. The value 1.0 indicates the
- * Pointable is at the far edge of the hovering zone. The value 0 indicates the
- * Pointable is just entering the touching zone. A value of -1.0 indicates the
- * Pointable is firmly within the touching zone. Values in between are
- * proportional to the distance from the plane. Thus, the touchDistance of 0.5
- * indicates that the Pointable is halfway into the hovering zone.
- *
- * You can use the touchDistance value to modulate visual feedback given to the
- * user as their fingers close in on a touch target, such as a button.
- *
- * @member touchDistance
- * @type {number}
- * @memberof Leap.Pointable.prototype
- */
- this.touchDistance = data.touchDistance;
-
- /**
- * How long the pointable has been visible in seconds.
- *
- * @member timeVisible
- * @type {number}
- * @memberof Leap.Pointable.prototype
- */
- this.timeVisible = data.timeVisible;
-}
-
-/**
- * A string containing a brief, human readable description of the Pointable
- * object.
- *
- * @method toString
- * @memberof Leap.Pointable.prototype
- * @returns {String} A description of the Pointable object as a string.
- */
-Pointable.prototype.toString = function() {
- return "Pointable [ id:" + this.id + " " + this.length + "mmx | width:" + this.width + "mm | direction:" + this.direction + ' ]';
-}
-
-/**
- * Returns the hand which the pointable is attached to.
- */
-Pointable.prototype.hand = function(){
- return this.frame.hand(this.handId);
-}
-
-/**
- * An invalid Pointable object.
- *
- * You can use this Pointable instance in comparisons testing
- * whether a given Pointable instance is valid or invalid. (You can also use the
- * Pointable.valid property.)
-
- * @static
- * @type {Leap.Pointable}
- * @name Invalid
- * @memberof Leap.Pointable
- */
-Pointable.Invalid = { valid: false };
-
-},{"gl-matrix":23}],15:[function(require,module,exports){
-var Frame = require('./frame')
- , Hand = require('./hand')
- , Pointable = require('./pointable')
- , Finger = require('./finger')
- , _ = require('underscore')
- , EventEmitter = require('events').EventEmitter;
-
-var Event = function(data) {
- this.type = data.type;
- this.state = data.state;
-};
-
-exports.chooseProtocol = function(header) {
- var protocol;
- switch(header.version) {
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- protocol = JSONProtocol(header);
- protocol.sendBackground = function(connection, state) {
- connection.send(protocol.encode({background: state}));
- }
- protocol.sendFocused = function(connection, state) {
- connection.send(protocol.encode({focused: state}));
- }
- protocol.sendOptimizeHMD = function(connection, state) {
- connection.send(protocol.encode({optimizeHMD: state}));
- }
- break;
- default:
- throw "unrecognized version";
- }
- return protocol;
-}
-
-var JSONProtocol = exports.JSONProtocol = function(header) {
-
- var protocol = function(frameData) {
-
- if (frameData.event) {
-
- return new Event(frameData.event);
-
- } else {
-
- protocol.emit('beforeFrameCreated', frameData);
-
- var frame = new Frame(frameData);
-
- protocol.emit('afterFrameCreated', frame, frameData);
-
- return frame;
-
- }
-
- };
-
- protocol.encode = function(message) {
- return JSON.stringify(message);
- };
- protocol.version = header.version;
- protocol.serviceVersion = header.serviceVersion;
- protocol.versionLong = 'Version ' + header.version;
- protocol.type = 'protocol';
-
- _.extend(protocol, EventEmitter.prototype);
-
- return protocol;
-};
-
-
-
-},{"./finger":7,"./frame":8,"./hand":10,"./pointable":14,"events":21,"underscore":24}],16:[function(require,module,exports){
-exports.UI = {
- Region: require("./ui/region"),
- Cursor: require("./ui/cursor")
-};
-},{"./ui/cursor":17,"./ui/region":18}],17:[function(require,module,exports){
-var Cursor = module.exports = function() {
- return function(frame) {
- var pointable = frame.pointables.sort(function(a, b) { return a.z - b.z })[0]
- if (pointable && pointable.valid) {
- frame.cursorPosition = pointable.tipPosition
- }
- return frame
- }
-}
-
-},{}],18:[function(require,module,exports){
-var EventEmitter = require('events').EventEmitter
- , _ = require('underscore')
-
-var Region = module.exports = function(start, end) {
- this.start = new Vector(start)
- this.end = new Vector(end)
- this.enteredFrame = null
-}
-
-Region.prototype.hasPointables = function(frame) {
- for (var i = 0; i != frame.pointables.length; i++) {
- var position = frame.pointables[i].tipPosition
- if (position.x >= this.start.x && position.x <= this.end.x && position.y >= this.start.y && position.y <= this.end.y && position.z >= this.start.z && position.z <= this.end.z) {
- return true
- }
- }
- return false
-}
-
-Region.prototype.listener = function(opts) {
- var region = this
- if (opts && opts.nearThreshold) this.setupNearRegion(opts.nearThreshold)
- return function(frame) {
- return region.updatePosition(frame)
- }
-}
-
-Region.prototype.clipper = function() {
- var region = this
- return function(frame) {
- region.updatePosition(frame)
- return region.enteredFrame ? frame : null
- }
-}
-
-Region.prototype.setupNearRegion = function(distance) {
- var nearRegion = this.nearRegion = new Region(
- [this.start.x - distance, this.start.y - distance, this.start.z - distance],
- [this.end.x + distance, this.end.y + distance, this.end.z + distance]
- )
- var region = this
- nearRegion.on("enter", function(frame) {
- region.emit("near", frame)
- })
- nearRegion.on("exit", function(frame) {
- region.emit("far", frame)
- })
- region.on('exit', function(frame) {
- region.emit("near", frame)
- })
-}
-
-Region.prototype.updatePosition = function(frame) {
- if (this.nearRegion) this.nearRegion.updatePosition(frame)
- if (this.hasPointables(frame) && this.enteredFrame == null) {
- this.enteredFrame = frame
- this.emit("enter", this.enteredFrame)
- } else if (!this.hasPointables(frame) && this.enteredFrame != null) {
- this.enteredFrame = null
- this.emit("exit", this.enteredFrame)
- }
- return frame
-}
-
-Region.prototype.normalize = function(position) {
- return new Vector([
- (position.x - this.start.x) / (this.end.x - this.start.x),
- (position.y - this.start.y) / (this.end.y - this.start.y),
- (position.z - this.start.z) / (this.end.z - this.start.z)
- ])
-}
-
-Region.prototype.mapToXY = function(position, width, height) {
- var normalized = this.normalize(position)
- var x = normalized.x, y = normalized.y
- if (x > 1) x = 1
- else if (x < -1) x = -1
- if (y > 1) y = 1
- else if (y < -1) y = -1
- return [
- (x + 1) / 2 * width,
- (1 - y) / 2 * height,
- normalized.z
- ]
-}
-
-_.extend(Region.prototype, EventEmitter.prototype)
-},{"events":21,"underscore":24}],19:[function(require,module,exports){
-// This file is automatically updated from package.json by grunt.
-module.exports = {
- full: '0.6.4',
- major: 0,
- minor: 6,
- dot: 4
-}
-},{}],20:[function(require,module,exports){
-
-},{}],21:[function(require,module,exports){
-var process=require("__browserify_process");if (!process.EventEmitter) process.EventEmitter = function () {};
-
-var EventEmitter = exports.EventEmitter = process.EventEmitter;
-var isArray = typeof Array.isArray === 'function'
- ? Array.isArray
- : function (xs) {
- return Object.prototype.toString.call(xs) === '[object Array]'
- }
-;
-function indexOf (xs, x) {
- if (xs.indexOf) return xs.indexOf(x);
- for (var i = 0; i < xs.length; i++) {
- if (x === xs[i]) return i;
- }
- return -1;
-}
-
-// By default EventEmitters will print a warning if more than
-// 10 listeners are added to it. This is a useful default which
-// helps finding memory leaks.
-//
-// Obviously not all Emitters should be limited to 10. This function allows
-// that to be increased. Set to zero for unlimited.
-var defaultMaxListeners = 10;
-EventEmitter.prototype.setMaxListeners = function(n) {
- if (!this._events) this._events = {};
- this._events.maxListeners = n;
-};
-
-
-EventEmitter.prototype.emit = function(type) {
- // If there is no 'error' event listener then throw.
- if (type === 'error') {
- if (!this._events || !this._events.error ||
- (isArray(this._events.error) && !this._events.error.length))
- {
- if (arguments[1] instanceof Error) {
- throw arguments[1]; // Unhandled 'error' event
- } else {
- throw new Error("Uncaught, unspecified 'error' event.");
- }
- return false;
- }
- }
-
- if (!this._events) return false;
- var handler = this._events[type];
- if (!handler) return false;
-
- if (typeof handler == 'function') {
- switch (arguments.length) {
- // fast cases
- case 1:
- handler.call(this);
- break;
- case 2:
- handler.call(this, arguments[1]);
- break;
- case 3:
- handler.call(this, arguments[1], arguments[2]);
- break;
- // slower
- default:
- var args = Array.prototype.slice.call(arguments, 1);
- handler.apply(this, args);
- }
- return true;
-
- } else if (isArray(handler)) {
- var args = Array.prototype.slice.call(arguments, 1);
-
- var listeners = handler.slice();
- for (var i = 0, l = listeners.length; i < l; i++) {
- listeners[i].apply(this, args);
- }
- return true;
-
- } else {
- return false;
- }
-};
-
-// EventEmitter is defined in src/node_events.cc
-// EventEmitter.prototype.emit() is also defined there.
-EventEmitter.prototype.addListener = function(type, listener) {
- if ('function' !== typeof listener) {
- throw new Error('addListener only takes instances of Function');
- }
-
- if (!this._events) this._events = {};
-
- // To avoid recursion in the case that type == "newListeners"! Before
- // adding it to the listeners, first emit "newListeners".
- this.emit('newListener', type, listener);
-
- if (!this._events[type]) {
- // Optimize the case of one listener. Don't need the extra array object.
- this._events[type] = listener;
- } else if (isArray(this._events[type])) {
-
- // Check for listener leak
- if (!this._events[type].warned) {
- var m;
- if (this._events.maxListeners !== undefined) {
- m = this._events.maxListeners;
- } else {
- m = defaultMaxListeners;
- }
-
- if (m && m > 0 && this._events[type].length > m) {
- this._events[type].warned = true;
- console.error('(node) warning: possible EventEmitter memory ' +
- 'leak detected. %d listeners added. ' +
- 'Use emitter.setMaxListeners() to increase limit.',
- this._events[type].length);
- console.trace();
- }
- }
-
- // If we've already got an array, just append.
- this._events[type].push(listener);
- } else {
- // Adding the second element, need to change to array.
- this._events[type] = [this._events[type], listener];
- }
-
- return this;
-};
-
-EventEmitter.prototype.on = EventEmitter.prototype.addListener;
-
-EventEmitter.prototype.once = function(type, listener) {
- var self = this;
- self.on(type, function g() {
- self.removeListener(type, g);
- listener.apply(this, arguments);
- });
-
- return this;
-};
-
-EventEmitter.prototype.removeListener = function(type, listener) {
- if ('function' !== typeof listener) {
- throw new Error('removeListener only takes instances of Function');
- }
-
- // does not use listeners(), so no side effect of creating _events[type]
- if (!this._events || !this._events[type]) return this;
-
- var list = this._events[type];
-
- if (isArray(list)) {
- var i = indexOf(list, listener);
- if (i < 0) return this;
- list.splice(i, 1);
- if (list.length == 0)
- delete this._events[type];
- } else if (this._events[type] === listener) {
- delete this._events[type];
- }
-
- return this;
-};
-
-EventEmitter.prototype.removeAllListeners = function(type) {
- if (arguments.length === 0) {
- this._events = {};
- return this;
- }
-
- // does not use listeners(), so no side effect of creating _events[type]
- if (type && this._events && this._events[type]) this._events[type] = null;
- return this;
-};
-
-EventEmitter.prototype.listeners = function(type) {
- if (!this._events) this._events = {};
- if (!this._events[type]) this._events[type] = [];
- if (!isArray(this._events[type])) {
- this._events[type] = [this._events[type]];
- }
- return this._events[type];
-};
-
-EventEmitter.listenerCount = function(emitter, type) {
- var ret;
- if (!emitter._events || !emitter._events[type])
- ret = 0;
- else if (typeof emitter._events[type] === 'function')
- ret = 1;
- else
- ret = emitter._events[type].length;
- return ret;
-};
-
-},{"__browserify_process":22}],22:[function(require,module,exports){
-// shim for using process in browser
-
-var process = module.exports = {};
-
-process.nextTick = (function () {
- var canSetImmediate = typeof window !== 'undefined'
- && window.setImmediate;
- var canPost = typeof window !== 'undefined'
- && window.postMessage && window.addEventListener
- ;
-
- if (canSetImmediate) {
- return function (f) { return window.setImmediate(f) };
- }
-
- if (canPost) {
- var queue = [];
- window.addEventListener('message', function (ev) {
- var source = ev.source;
- if ((source === window || source === null) && ev.data === 'process-tick') {
- ev.stopPropagation();
- if (queue.length > 0) {
- var fn = queue.shift();
- fn();
- }
- }
- }, true);
-
- return function nextTick(fn) {
- queue.push(fn);
- window.postMessage('process-tick', '*');
- };
- }
-
- return function nextTick(fn) {
- setTimeout(fn, 0);
- };
-})();
-
-process.title = 'browser';
-process.browser = true;
-process.env = {};
-process.argv = [];
-
-process.binding = function (name) {
- throw new Error('process.binding is not supported');
-}
-
-// TODO(shtylman)
-process.cwd = function () { return '/' };
-process.chdir = function (dir) {
- throw new Error('process.chdir is not supported');
-};
-
-},{}],23:[function(require,module,exports){
-/**
- * @fileoverview gl-matrix - High performance matrix and vector operations
- * @author Brandon Jones
- * @author Colin MacKenzie IV
- * @version 2.2.1
- */
-
-/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
-
-
-(function(_global) {
- "use strict";
-
- var shim = {};
- if (typeof(exports) === 'undefined') {
- if(typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
- shim.exports = {};
- define(function() {
- return shim.exports;
- });
- } else {
- // gl-matrix lives in a browser, define its namespaces in global
- shim.exports = typeof(window) !== 'undefined' ? window : _global;
- }
- }
- else {
- // gl-matrix lives in commonjs, define its namespaces in exports
- shim.exports = exports;
- }
-
- (function(exports) {
- /* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
-
-
-if(!GLMAT_EPSILON) {
- var GLMAT_EPSILON = 0.000001;
-}
-
-if(!GLMAT_ARRAY_TYPE) {
- var GLMAT_ARRAY_TYPE = (typeof Float32Array !== 'undefined') ? Float32Array : Array;
-}
-
-if(!GLMAT_RANDOM) {
- var GLMAT_RANDOM = Math.random;
-}
-
-/**
- * @class Common utilities
- * @name glMatrix
- */
-var glMatrix = {};
-
-/**
- * Sets the type of array used when creating new vectors and matricies
- *
- * @param {Type} type Array type, such as Float32Array or Array
- */
-glMatrix.setMatrixArrayType = function(type) {
- GLMAT_ARRAY_TYPE = type;
-}
-
-if(typeof(exports) !== 'undefined') {
- exports.glMatrix = glMatrix;
-}
-
-var degree = Math.PI / 180;
-
-/**
-* Convert Degree To Radian
-*
-* @param {Number} Angle in Degrees
-*/
-glMatrix.toRadian = function(a){
- return a * degree;
-}
-;
-/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
-
-/**
- * @class 2 Dimensional Vector
- * @name vec2
- */
-
-var vec2 = {};
-
-/**
- * Creates a new, empty vec2
- *
- * @returns {vec2} a new 2D vector
- */
-vec2.create = function() {
- var out = new GLMAT_ARRAY_TYPE(2);
- out[0] = 0;
- out[1] = 0;
- return out;
-};
-
-/**
- * Creates a new vec2 initialized with values from an existing vector
- *
- * @param {vec2} a vector to clone
- * @returns {vec2} a new 2D vector
- */
-vec2.clone = function(a) {
- var out = new GLMAT_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
- */
-vec2.fromValues = function(x, y) {
- var out = new GLMAT_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 {vec2} a the source vector
- * @returns {vec2} out
- */
-vec2.copy = function(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
- */
-vec2.set = function(out, x, y) {
- out[0] = x;
- out[1] = y;
- return out;
-};
-
-/**
- * Adds two vec2's
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {vec2} out
- */
-vec2.add = function(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 {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {vec2} out
- */
-vec2.subtract = function(out, a, b) {
- out[0] = a[0] - b[0];
- out[1] = a[1] - b[1];
- return out;
-};
-
-/**
- * Alias for {@link vec2.subtract}
- * @function
- */
-vec2.sub = vec2.subtract;
-
-/**
- * Multiplies two vec2's
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {vec2} out
- */
-vec2.multiply = function(out, a, b) {
- out[0] = a[0] * b[0];
- out[1] = a[1] * b[1];
- return out;
-};
-
-/**
- * Alias for {@link vec2.multiply}
- * @function
- */
-vec2.mul = vec2.multiply;
-
-/**
- * Divides two vec2's
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {vec2} out
- */
-vec2.divide = function(out, a, b) {
- out[0] = a[0] / b[0];
- out[1] = a[1] / b[1];
- return out;
-};
-
-/**
- * Alias for {@link vec2.divide}
- * @function
- */
-vec2.div = vec2.divide;
-
-/**
- * Returns the minimum of two vec2's
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {vec2} out
- */
-vec2.min = function(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 {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {vec2} out
- */
-vec2.max = function(out, a, b) {
- out[0] = Math.max(a[0], b[0]);
- out[1] = Math.max(a[1], b[1]);
- return out;
-};
-
-/**
- * Scales a vec2 by a scalar number
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the vector to scale
- * @param {Number} b amount to scale the vector by
- * @returns {vec2} out
- */
-vec2.scale = function(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 {vec2} a the first operand
- * @param {vec2} b the second operand
- * @param {Number} scale the amount to scale b by before adding
- * @returns {vec2} out
- */
-vec2.scaleAndAdd = function(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 {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {Number} distance between a and b
- */
-vec2.distance = function(a, b) {
- var x = b[0] - a[0],
- y = b[1] - a[1];
- return Math.sqrt(x*x + y*y);
-};
-
-/**
- * Alias for {@link vec2.distance}
- * @function
- */
-vec2.dist = vec2.distance;
-
-/**
- * Calculates the squared euclidian distance between two vec2's
- *
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {Number} squared distance between a and b
- */
-vec2.squaredDistance = function(a, b) {
- var x = b[0] - a[0],
- y = b[1] - a[1];
- return x*x + y*y;
-};
-
-/**
- * Alias for {@link vec2.squaredDistance}
- * @function
- */
-vec2.sqrDist = vec2.squaredDistance;
-
-/**
- * Calculates the length of a vec2
- *
- * @param {vec2} a vector to calculate length of
- * @returns {Number} length of a
- */
-vec2.length = function (a) {
- var x = a[0],
- y = a[1];
- return Math.sqrt(x*x + y*y);
-};
-
-/**
- * Alias for {@link vec2.length}
- * @function
- */
-vec2.len = vec2.length;
-
-/**
- * Calculates the squared length of a vec2
- *
- * @param {vec2} a vector to calculate squared length of
- * @returns {Number} squared length of a
- */
-vec2.squaredLength = function (a) {
- var x = a[0],
- y = a[1];
- return x*x + y*y;
-};
-
-/**
- * Alias for {@link vec2.squaredLength}
- * @function
- */
-vec2.sqrLen = vec2.squaredLength;
-
-/**
- * Negates the components of a vec2
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a vector to negate
- * @returns {vec2} out
- */
-vec2.negate = function(out, a) {
- out[0] = -a[0];
- out[1] = -a[1];
- return out;
-};
-
-/**
- * Normalize a vec2
- *
- * @param {vec2} out the receiving vector
- * @param {vec2} a vector to normalize
- * @returns {vec2} out
- */
-vec2.normalize = function(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 {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {Number} dot product of a and b
- */
-vec2.dot = function (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 {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {vec3} out
- */
-vec2.cross = function(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 {vec2} a the first operand
- * @param {vec2} b the second operand
- * @param {Number} t interpolation amount between the two inputs
- * @returns {vec2} out
- */
-vec2.lerp = function (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
- */
-vec2.random = function (out, scale) {
- scale = scale || 1.0;
- var r = GLMAT_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 {vec2} a the vector to transform
- * @param {mat2} m matrix to transform with
- * @returns {vec2} out
- */
-vec2.transformMat2 = function(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 {vec2} a the vector to transform
- * @param {mat2d} m matrix to transform with
- * @returns {vec2} out
- */
-vec2.transformMat2d = function(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 {vec2} a the vector to transform
- * @param {mat3} m matrix to transform with
- * @returns {vec2} out
- */
-vec2.transformMat3 = function(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 {vec2} a the vector to transform
- * @param {mat4} m matrix to transform with
- * @returns {vec2} out
- */
-vec2.transformMat4 = function(out, a, m) {
- var x = a[0],
- 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;
-};
-
-/**
- * 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
- */
-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;
- };
-})();
-
-/**
- * Returns a string representation of a vector
- *
- * @param {vec2} vec vector to represent as a string
- * @returns {String} string representation of the vector
- */
-vec2.str = function (a) {
- return 'vec2(' + a[0] + ', ' + a[1] + ')';
-};
-
-if(typeof(exports) !== 'undefined') {
- exports.vec2 = vec2;
-}
-;
-/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
-
-/**
- * @class 3 Dimensional Vector
- * @name vec3
- */
-
-var vec3 = {};
-
-/**
- * Creates a new, empty vec3
- *
- * @returns {vec3} a new 3D vector
- */
-vec3.create = function() {
- var out = new GLMAT_ARRAY_TYPE(3);
- out[0] = 0;
- out[1] = 0;
- out[2] = 0;
- return out;
-};
-
-/**
- * Creates a new vec3 initialized with values from an existing vector
- *
- * @param {vec3} a vector to clone
- * @returns {vec3} a new 3D vector
- */
-vec3.clone = function(a) {
- var out = new GLMAT_ARRAY_TYPE(3);
- out[0] = a[0];
- out[1] = a[1];
- out[2] = a[2];
- return out;
-};
-
-/**
- * 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
- */
-vec3.fromValues = function(x, y, z) {
- var out = new GLMAT_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 {vec3} a the source vector
- * @returns {vec3} out
- */
-vec3.copy = function(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
- */
-vec3.set = function(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 {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {vec3} out
- */
-vec3.add = function(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 {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {vec3} out
- */
-vec3.subtract = function(out, a, b) {
- out[0] = a[0] - b[0];
- out[1] = a[1] - b[1];
- out[2] = a[2] - b[2];
- return out;
-};
-
-/**
- * Alias for {@link vec3.subtract}
- * @function
- */
-vec3.sub = vec3.subtract;
-
-/**
- * Multiplies two vec3's
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {vec3} out
- */
-vec3.multiply = function(out, a, b) {
- out[0] = a[0] * b[0];
- out[1] = a[1] * b[1];
- out[2] = a[2] * b[2];
- return out;
-};
-
-/**
- * Alias for {@link vec3.multiply}
- * @function
- */
-vec3.mul = vec3.multiply;
-
-/**
- * Divides two vec3's
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {vec3} out
- */
-vec3.divide = function(out, a, b) {
- out[0] = a[0] / b[0];
- out[1] = a[1] / b[1];
- out[2] = a[2] / b[2];
- return out;
-};
-
-/**
- * Alias for {@link vec3.divide}
- * @function
- */
-vec3.div = vec3.divide;
-
-/**
- * Returns the minimum of two vec3's
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {vec3} out
- */
-vec3.min = function(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 {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {vec3} out
- */
-vec3.max = function(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;
-};
-
-/**
- * Scales a vec3 by a scalar number
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the vector to scale
- * @param {Number} b amount to scale the vector by
- * @returns {vec3} out
- */
-vec3.scale = function(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 {vec3} a the first operand
- * @param {vec3} b the second operand
- * @param {Number} scale the amount to scale b by before adding
- * @returns {vec3} out
- */
-vec3.scaleAndAdd = function(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 {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {Number} distance between a and b
- */
-vec3.distance = function(a, b) {
- var x = b[0] - a[0],
- y = b[1] - a[1],
- z = b[2] - a[2];
- return Math.sqrt(x*x + y*y + z*z);
-};
-
-/**
- * Alias for {@link vec3.distance}
- * @function
- */
-vec3.dist = vec3.distance;
-
-/**
- * Calculates the squared euclidian distance between two vec3's
- *
- * @param {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {Number} squared distance between a and b
- */
-vec3.squaredDistance = function(a, b) {
- var x = b[0] - a[0],
- y = b[1] - a[1],
- z = b[2] - a[2];
- return x*x + y*y + z*z;
-};
-
-/**
- * Alias for {@link vec3.squaredDistance}
- * @function
- */
-vec3.sqrDist = vec3.squaredDistance;
-
-/**
- * Calculates the length of a vec3
- *
- * @param {vec3} a vector to calculate length of
- * @returns {Number} length of a
- */
-vec3.length = function (a) {
- var x = a[0],
- y = a[1],
- z = a[2];
- return Math.sqrt(x*x + y*y + z*z);
-};
-
-/**
- * Alias for {@link vec3.length}
- * @function
- */
-vec3.len = vec3.length;
-
-/**
- * Calculates the squared length of a vec3
- *
- * @param {vec3} a vector to calculate squared length of
- * @returns {Number} squared length of a
- */
-vec3.squaredLength = function (a) {
- var x = a[0],
- y = a[1],
- z = a[2];
- return x*x + y*y + z*z;
-};
-
-/**
- * Alias for {@link vec3.squaredLength}
- * @function
- */
-vec3.sqrLen = vec3.squaredLength;
-
-/**
- * Negates the components of a vec3
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a vector to negate
- * @returns {vec3} out
- */
-vec3.negate = function(out, a) {
- out[0] = -a[0];
- out[1] = -a[1];
- out[2] = -a[2];
- return out;
-};
-
-/**
- * Normalize a vec3
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a vector to normalize
- * @returns {vec3} out
- */
-vec3.normalize = function(out, a) {
- var x = a[0],
- y = a[1],
- 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 {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {Number} dot product of a and b
- */
-vec3.dot = function (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 {vec3} a the first operand
- * @param {vec3} b the second operand
- * @returns {vec3} out
- */
-vec3.cross = function(out, a, b) {
- var ax = a[0], ay = a[1], az = a[2],
- 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 {vec3} a the first operand
- * @param {vec3} b the second operand
- * @param {Number} t interpolation amount between the two inputs
- * @returns {vec3} out
- */
-vec3.lerp = function (out, a, b, t) {
- var ax = a[0],
- ay = a[1],
- 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;
-};
-
-/**
- * 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
- */
-vec3.random = function (out, scale) {
- scale = scale || 1.0;
-
- var r = GLMAT_RANDOM() * 2.0 * Math.PI;
- var z = (GLMAT_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 {vec3} a the vector to transform
- * @param {mat4} m matrix to transform with
- * @returns {vec3} out
- */
-vec3.transformMat4 = function(out, a, m) {
- var x = a[0], y = a[1], z = a[2];
- out[0] = m[0] * x + m[4] * y + m[8] * z + m[12];
- out[1] = m[1] * x + m[5] * y + m[9] * z + m[13];
- out[2] = m[2] * x + m[6] * y + m[10] * z + m[14];
- return out;
-};
-
-/**
- * Transforms the vec3 with a mat3.
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the vector to transform
- * @param {mat4} m the 3x3 matrix to transform with
- * @returns {vec3} out
- */
-vec3.transformMat3 = function(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
- *
- * @param {vec3} out the receiving vector
- * @param {vec3} a the vector to transform
- * @param {quat} q quaternion to transform with
- * @returns {vec3} out
- */
-vec3.transformQuat = function(out, a, q) {
- // benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations
-
- var x = a[0], y = a[1], z = a[2],
- qx = q[0], qy = q[1], qz = q[2], qw = q[3],
-
- // calculate quat * vec
- ix = qw * x + qy * z - qz * y,
- iy = qw * y + qz * x - qx * z,
- iz = qw * z + qx * y - qy * x,
- 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;
- return out;
-};
-
-/*
-* Rotate a 3D vector around the x-axis
-* @param {vec3} out The receiving vec3
-* @param {vec3} a The vec3 point to rotate
-* @param {vec3} b The origin of the rotation
-* @param {Number} c The angle of rotation
-* @returns {vec3} out
-*/
-vec3.rotateX = function(out, a, b, c){
- 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(c) - p[2]*Math.sin(c);
- r[2] = p[1]*Math.sin(c) + p[2]*Math.cos(c);
-
- //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 {vec3} a The vec3 point to rotate
-* @param {vec3} b The origin of the rotation
-* @param {Number} c The angle of rotation
-* @returns {vec3} out
-*/
-vec3.rotateY = function(out, a, b, c){
- 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(c) + p[0]*Math.cos(c);
- r[1] = p[1];
- r[2] = p[2]*Math.cos(c) - p[0]*Math.sin(c);
-
- //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 {vec3} a The vec3 point to rotate
-* @param {vec3} b The origin of the rotation
-* @param {Number} c The angle of rotation
-* @returns {vec3} out
-*/
-vec3.rotateZ = function(out, a, b, c){
- 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(c) - p[1]*Math.sin(c);
- r[1] = p[0]*Math.sin(c) + p[1]*Math.cos(c);
- 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;
-};
-
-/**
- * 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
- */
-vec3.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;
- };
-})();
-
-/**
- * Returns a string representation of a vector
- *
- * @param {vec3} vec vector to represent as a string
- * @returns {String} string representation of the vector
- */
-vec3.str = function (a) {
- return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')';
-};
-
-if(typeof(exports) !== 'undefined') {
- exports.vec3 = vec3;
-}
-;
-/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
-
-/**
- * @class 4 Dimensional Vector
- * @name vec4
- */
-
-var vec4 = {};
-
-/**
- * Creates a new, empty vec4
- *
- * @returns {vec4} a new 4D vector
- */
-vec4.create = function() {
- var out = new GLMAT_ARRAY_TYPE(4);
- 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 {vec4} a vector to clone
- * @returns {vec4} a new 4D vector
- */
-vec4.clone = function(a) {
- var out = new GLMAT_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
- */
-vec4.fromValues = function(x, y, z, w) {
- var out = new GLMAT_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 {vec4} a the source vector
- * @returns {vec4} out
- */
-vec4.copy = function(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
- */
-vec4.set = function(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 {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {vec4} out
- */
-vec4.add = function(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 {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {vec4} out
- */
-vec4.subtract = function(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;
-};
-
-/**
- * Alias for {@link vec4.subtract}
- * @function
- */
-vec4.sub = vec4.subtract;
-
-/**
- * Multiplies two vec4's
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {vec4} out
- */
-vec4.multiply = function(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;
-};
-
-/**
- * Alias for {@link vec4.multiply}
- * @function
- */
-vec4.mul = vec4.multiply;
-
-/**
- * Divides two vec4's
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {vec4} out
- */
-vec4.divide = function(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;
-};
-
-/**
- * Alias for {@link vec4.divide}
- * @function
- */
-vec4.div = vec4.divide;
-
-/**
- * Returns the minimum of two vec4's
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {vec4} out
- */
-vec4.min = function(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 {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {vec4} out
- */
-vec4.max = function(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;
-};
-
-/**
- * Scales a vec4 by a scalar number
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the vector to scale
- * @param {Number} b amount to scale the vector by
- * @returns {vec4} out
- */
-vec4.scale = function(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 {vec4} a the first operand
- * @param {vec4} b the second operand
- * @param {Number} scale the amount to scale b by before adding
- * @returns {vec4} out
- */
-vec4.scaleAndAdd = function(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 {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {Number} distance between a and b
- */
-vec4.distance = function(a, b) {
- var x = b[0] - a[0],
- y = b[1] - a[1],
- z = b[2] - a[2],
- w = b[3] - a[3];
- return Math.sqrt(x*x + y*y + z*z + w*w);
-};
-
-/**
- * Alias for {@link vec4.distance}
- * @function
- */
-vec4.dist = vec4.distance;
-
-/**
- * Calculates the squared euclidian distance between two vec4's
- *
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {Number} squared distance between a and b
- */
-vec4.squaredDistance = function(a, b) {
- var x = b[0] - a[0],
- y = b[1] - a[1],
- z = b[2] - a[2],
- w = b[3] - a[3];
- return x*x + y*y + z*z + w*w;
-};
-
-/**
- * Alias for {@link vec4.squaredDistance}
- * @function
- */
-vec4.sqrDist = vec4.squaredDistance;
-
-/**
- * Calculates the length of a vec4
- *
- * @param {vec4} a vector to calculate length of
- * @returns {Number} length of a
- */
-vec4.length = function (a) {
- var x = a[0],
- y = a[1],
- z = a[2],
- w = a[3];
- return Math.sqrt(x*x + y*y + z*z + w*w);
-};
-
-/**
- * Alias for {@link vec4.length}
- * @function
- */
-vec4.len = vec4.length;
-
-/**
- * Calculates the squared length of a vec4
- *
- * @param {vec4} a vector to calculate squared length of
- * @returns {Number} squared length of a
- */
-vec4.squaredLength = function (a) {
- var x = a[0],
- y = a[1],
- z = a[2],
- w = a[3];
- return x*x + y*y + z*z + w*w;
-};
-
-/**
- * Alias for {@link vec4.squaredLength}
- * @function
- */
-vec4.sqrLen = vec4.squaredLength;
-
-/**
- * Negates the components of a vec4
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a vector to negate
- * @returns {vec4} out
- */
-vec4.negate = function(out, a) {
- out[0] = -a[0];
- out[1] = -a[1];
- out[2] = -a[2];
- out[3] = -a[3];
- return out;
-};
-
-/**
- * Normalize a vec4
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a vector to normalize
- * @returns {vec4} out
- */
-vec4.normalize = function(out, a) {
- var x = a[0],
- y = a[1],
- z = a[2],
- w = a[3];
- var len = x*x + y*y + z*z + w*w;
- if (len > 0) {
- len = 1 / Math.sqrt(len);
- out[0] = a[0] * len;
- out[1] = a[1] * len;
- out[2] = a[2] * len;
- out[3] = a[3] * len;
- }
- return out;
-};
-
-/**
- * Calculates the dot product of two vec4's
- *
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @returns {Number} dot product of a and b
- */
-vec4.dot = function (a, b) {
- return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
-};
-
-/**
- * Performs a linear interpolation between two vec4's
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the first operand
- * @param {vec4} b the second operand
- * @param {Number} t interpolation amount between the two inputs
- * @returns {vec4} out
- */
-vec4.lerp = function (out, a, b, t) {
- var ax = a[0],
- ay = a[1],
- az = a[2],
- 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
- */
-vec4.random = function (out, scale) {
- scale = scale || 1.0;
-
- //TODO: This is a pretty awful way of doing this. Find something better.
- out[0] = GLMAT_RANDOM();
- out[1] = GLMAT_RANDOM();
- out[2] = GLMAT_RANDOM();
- out[3] = GLMAT_RANDOM();
- vec4.normalize(out, out);
- vec4.scale(out, out, scale);
- return out;
-};
-
-/**
- * Transforms the vec4 with a mat4.
- *
- * @param {vec4} out the receiving vector
- * @param {vec4} a the vector to transform
- * @param {mat4} m matrix to transform with
- * @returns {vec4} out
- */
-vec4.transformMat4 = function(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 {vec4} a the vector to transform
- * @param {quat} q quaternion to transform with
- * @returns {vec4} out
- */
-vec4.transformQuat = function(out, a, q) {
- var x = a[0], y = a[1], z = a[2],
- qx = q[0], qy = q[1], qz = q[2], qw = q[3],
-
- // calculate quat * vec
- ix = qw * x + qy * z - qz * y,
- iy = qw * y + qz * x - qx * z,
- iz = qw * z + qx * y - qy * x,
- 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;
- return out;
-};
-
-/**
- * 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 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
- */
-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;
- };
-})();
-
-/**
- * Returns a string representation of a vector
- *
- * @param {vec4} vec vector to represent as a string
- * @returns {String} string representation of the vector
- */
-vec4.str = function (a) {
- return 'vec4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
-};
-
-if(typeof(exports) !== 'undefined') {
- exports.vec4 = vec4;
-}
-;
-/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
-
-/**
- * @class 2x2 Matrix
- * @name mat2
- */
-
-var mat2 = {};
-
-/**
- * Creates a new identity mat2
- *
- * @returns {mat2} a new 2x2 matrix
- */
-mat2.create = function() {
- var out = new GLMAT_ARRAY_TYPE(4);
- out[0] = 1;
- out[1] = 0;
- out[2] = 0;
- out[3] = 1;
- return out;
-};
-
-/**
- * Creates a new mat2 initialized with values from an existing matrix
- *
- * @param {mat2} a matrix to clone
- * @returns {mat2} a new 2x2 matrix
- */
-mat2.clone = function(a) {
- var out = new GLMAT_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 {mat2} a the source matrix
- * @returns {mat2} out
- */
-mat2.copy = function(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
- */
-mat2.identity = function(out) {
- out[0] = 1;
- out[1] = 0;
- out[2] = 0;
- out[3] = 1;
- return out;
-};
-
-/**
- * Transpose the values of a mat2
- *
- * @param {mat2} out the receiving matrix
- * @param {mat2} a the source matrix
- * @returns {mat2} out
- */
-mat2.transpose = function(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 {mat2} a the source matrix
- * @returns {mat2} out
- */
-mat2.invert = function(out, a) {
- var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
-
- // Calculate the determinant
- 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 {mat2} a the source matrix
- * @returns {mat2} out
- */
-mat2.adjoint = function(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 {mat2} a the source matrix
- * @returns {Number} determinant of a
- */
-mat2.determinant = function (a) {
- return a[0] * a[3] - a[2] * a[1];
-};
-
-/**
- * Multiplies two mat2's
- *
- * @param {mat2} out the receiving matrix
- * @param {mat2} a the first operand
- * @param {mat2} b the second operand
- * @returns {mat2} out
- */
-mat2.multiply = function (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;
-};
-
-/**
- * Alias for {@link mat2.multiply}
- * @function
- */
-mat2.mul = mat2.multiply;
-
-/**
- * Rotates a mat2 by the given angle
- *
- * @param {mat2} out the receiving matrix
- * @param {mat2} a the matrix to rotate
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat2} out
- */
-mat2.rotate = function (out, a, rad) {
- var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
- s = Math.sin(rad),
- 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 {mat2} a the matrix to rotate
- * @param {vec2} v the vec2 to scale the matrix by
- * @returns {mat2} out
- **/
-mat2.scale = function(out, a, v) {
- var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
- v0 = v[0], v1 = v[1];
- out[0] = a0 * v0;
- out[1] = a1 * v0;
- out[2] = a2 * v1;
- out[3] = a3 * v1;
- return out;
-};
-
-/**
- * Returns a string representation of a mat2
- *
- * @param {mat2} mat matrix to represent as a string
- * @returns {String} string representation of the matrix
- */
-mat2.str = function (a) {
- return 'mat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
-};
-
-/**
- * Returns Frobenius norm of a mat2
- *
- * @param {mat2} a the matrix to calculate Frobenius norm of
- * @returns {Number} Frobenius norm
- */
-mat2.frob = function (a) {
- return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2)))
-};
-
-/**
- * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix
- * @param {mat2} L the lower triangular matrix
- * @param {mat2} D the diagonal matrix
- * @param {mat2} U the upper triangular matrix
- * @param {mat2} a the input matrix to factorize
- */
-
-mat2.LDU = function (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];
-};
-
-if(typeof(exports) !== 'undefined') {
- exports.mat2 = mat2;
-}
-;
-/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
-
-/**
- * @class 2x3 Matrix
- * @name mat2d
- *
- * @description
- * A mat2d contains six elements defined as:
- *
- * [a, c, tx,
- * b, d, ty]
- *
- * This is a short form for the 3x3 matrix:
- *
- * [a, c, tx,
- * b, d, ty,
- * 0, 0, 1]
- *
- * The last row is ignored so the array is shorter and operations are faster.
- */
-
-var mat2d = {};
-
-/**
- * Creates a new identity mat2d
- *
- * @returns {mat2d} a new 2x3 matrix
- */
-mat2d.create = function() {
- var out = new GLMAT_ARRAY_TYPE(6);
- out[0] = 1;
- out[1] = 0;
- out[2] = 0;
- out[3] = 1;
- out[4] = 0;
- out[5] = 0;
- return out;
-};
-
-/**
- * Creates a new mat2d initialized with values from an existing matrix
- *
- * @param {mat2d} a matrix to clone
- * @returns {mat2d} a new 2x3 matrix
- */
-mat2d.clone = function(a) {
- var out = new GLMAT_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 {mat2d} a the source matrix
- * @returns {mat2d} out
- */
-mat2d.copy = function(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
- */
-mat2d.identity = function(out) {
- out[0] = 1;
- out[1] = 0;
- out[2] = 0;
- out[3] = 1;
- out[4] = 0;
- out[5] = 0;
- return out;
-};
-
-/**
- * Inverts a mat2d
- *
- * @param {mat2d} out the receiving matrix
- * @param {mat2d} a the source matrix
- * @returns {mat2d} out
- */
-mat2d.invert = function(out, a) {
- var aa = a[0], ab = a[1], ac = a[2], ad = a[3],
- 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 {mat2d} a the source matrix
- * @returns {Number} determinant of a
- */
-mat2d.determinant = function (a) {
- return a[0] * a[3] - a[1] * a[2];
-};
-
-/**
- * Multiplies two mat2d's
- *
- * @param {mat2d} out the receiving matrix
- * @param {mat2d} a the first operand
- * @param {mat2d} b the second operand
- * @returns {mat2d} out
- */
-mat2d.multiply = function (out, a, b) {
- var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5],
- 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;
-};
-
-/**
- * Alias for {@link mat2d.multiply}
- * @function
- */
-mat2d.mul = mat2d.multiply;
-
-
-/**
- * Rotates a mat2d by the given angle
- *
- * @param {mat2d} out the receiving matrix
- * @param {mat2d} a the matrix to rotate
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat2d} out
- */
-mat2d.rotate = function (out, a, rad) {
- var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5],
- s = Math.sin(rad),
- 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 {mat2d} a the matrix to translate
- * @param {vec2} v the vec2 to scale the matrix by
- * @returns {mat2d} out
- **/
-mat2d.scale = function(out, a, v) {
- var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5],
- 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 {mat2d} a the matrix to translate
- * @param {vec2} v the vec2 to translate the matrix by
- * @returns {mat2d} out
- **/
-mat2d.translate = function(out, a, v) {
- var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5],
- 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;
-};
-
-/**
- * Returns a string representation of a mat2d
- *
- * @param {mat2d} a matrix to represent as a string
- * @returns {String} string representation of the matrix
- */
-mat2d.str = function (a) {
- return 'mat2d(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' +
- a[3] + ', ' + a[4] + ', ' + a[5] + ')';
-};
-
-/**
- * Returns Frobenius norm of a mat2d
- *
- * @param {mat2d} a the matrix to calculate Frobenius norm of
- * @returns {Number} Frobenius norm
- */
-mat2d.frob = function (a) {
- return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + 1))
-};
-
-if(typeof(exports) !== 'undefined') {
- exports.mat2d = mat2d;
-}
-;
-/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
-
-/**
- * @class 3x3 Matrix
- * @name mat3
- */
-
-var mat3 = {};
-
-/**
- * Creates a new identity mat3
- *
- * @returns {mat3} a new 3x3 matrix
- */
-mat3.create = function() {
- var out = new GLMAT_ARRAY_TYPE(9);
- 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;
-};
-
-/**
- * Copies the upper-left 3x3 values into the given mat3.
- *
- * @param {mat3} out the receiving 3x3 matrix
- * @param {mat4} a the source 4x4 matrix
- * @returns {mat3} out
- */
-mat3.fromMat4 = function(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 {mat3} a matrix to clone
- * @returns {mat3} a new 3x3 matrix
- */
-mat3.clone = function(a) {
- var out = new GLMAT_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 {mat3} a the source matrix
- * @returns {mat3} out
- */
-mat3.copy = function(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;
-};
-
-/**
- * Set a mat3 to the identity matrix
- *
- * @param {mat3} out the receiving matrix
- * @returns {mat3} out
- */
-mat3.identity = function(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 {mat3} a the source matrix
- * @returns {mat3} out
- */
-mat3.transpose = function(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 {mat3} a the source matrix
- * @returns {mat3} out
- */
-mat3.invert = function(out, a) {
- 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],
-
- b01 = a22 * a11 - a12 * a21,
- b11 = -a22 * a10 + a12 * a20,
- b21 = a21 * a10 - a11 * a20,
-
- // Calculate the determinant
- 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 {mat3} a the source matrix
- * @returns {mat3} out
- */
-mat3.adjoint = function(out, a) {
- 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];
-
- 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 {mat3} a the source matrix
- * @returns {Number} determinant of a
- */
-mat3.determinant = function (a) {
- 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];
-
- 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 {mat3} a the first operand
- * @param {mat3} b the second operand
- * @returns {mat3} out
- */
-mat3.multiply = function (out, a, b) {
- 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],
-
- b00 = b[0], b01 = b[1], b02 = b[2],
- b10 = b[3], b11 = b[4], b12 = b[5],
- 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;
-};
-
-/**
- * Alias for {@link mat3.multiply}
- * @function
- */
-mat3.mul = mat3.multiply;
-
-/**
- * Translate a mat3 by the given vector
- *
- * @param {mat3} out the receiving matrix
- * @param {mat3} a the matrix to translate
- * @param {vec2} v vector to translate by
- * @returns {mat3} out
- */
-mat3.translate = function(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 {mat3} a the matrix to rotate
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat3} out
- */
-mat3.rotate = function (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 {mat3} a the matrix to rotate
- * @param {vec2} v the vec2 to scale the matrix by
- * @returns {mat3} out
- **/
-mat3.scale = function(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;
-};
-
-/**
- * Copies the values from a mat2d into a mat3
- *
- * @param {mat3} out the receiving matrix
- * @param {mat2d} a the matrix to copy
- * @returns {mat3} out
- **/
-mat3.fromMat2d = function(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 {quat} q Quaternion to create matrix from
-*
-* @returns {mat3} out
-*/
-mat3.fromQuat = function (out, q) {
- var x = q[0], y = q[1], z = q[2], w = q[3],
- x2 = x + x,
- y2 = y + y,
- z2 = z + z,
-
- xx = x * x2,
- yx = y * x2,
- yy = y * y2,
- zx = z * x2,
- zy = z * y2,
- zz = z * z2,
- wx = w * x2,
- wy = w * y2,
- 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 {mat4} a Mat4 to derive the normal matrix from
-*
-* @returns {mat3} out
-*/
-mat3.normalFromMat4 = function (out, a) {
- var 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],
- a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
-
- b00 = a00 * a11 - a01 * a10,
- b01 = a00 * a12 - a02 * a10,
- b02 = a00 * a13 - a03 * a10,
- b03 = a01 * a12 - a02 * a11,
- b04 = a01 * a13 - a03 * a11,
- b05 = a02 * a13 - a03 * a12,
- b06 = a20 * a31 - a21 * a30,
- b07 = a20 * a32 - a22 * a30,
- b08 = a20 * a33 - a23 * a30,
- b09 = a21 * a32 - a22 * a31,
- b10 = a21 * a33 - a23 * a31,
- b11 = a22 * a33 - a23 * a32,
-
- // Calculate the determinant
- 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;
-};
-
-/**
- * Returns a string representation of a mat3
- *
- * @param {mat3} mat matrix to represent as a string
- * @returns {String} string representation of the matrix
- */
-mat3.str = function (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 {mat3} a the matrix to calculate Frobenius norm of
- * @returns {Number} Frobenius norm
- */
-mat3.frob = function (a) {
- return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2)))
-};
-
-
-if(typeof(exports) !== 'undefined') {
- exports.mat3 = mat3;
-}
-;
-/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
-
-/**
- * @class 4x4 Matrix
- * @name mat4
- */
-
-var mat4 = {};
-
-/**
- * Creates a new identity mat4
- *
- * @returns {mat4} a new 4x4 matrix
- */
-mat4.create = function() {
- var out = new GLMAT_ARRAY_TYPE(16);
- 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;
-};
-
-/**
- * Creates a new mat4 initialized with values from an existing matrix
- *
- * @param {mat4} a matrix to clone
- * @returns {mat4} a new 4x4 matrix
- */
-mat4.clone = function(a) {
- var out = new GLMAT_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 {mat4} a the source matrix
- * @returns {mat4} out
- */
-mat4.copy = function(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;
-};
-
-/**
- * Set a mat4 to the identity matrix
- *
- * @param {mat4} out the receiving matrix
- * @returns {mat4} out
- */
-mat4.identity = function(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 {mat4} a the source matrix
- * @returns {mat4} out
- */
-mat4.transpose = function(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],
- a12 = a[6], a13 = a[7],
- 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 {mat4} a the source matrix
- * @returns {mat4} out
- */
-mat4.invert = function(out, a) {
- var 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],
- a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
-
- b00 = a00 * a11 - a01 * a10,
- b01 = a00 * a12 - a02 * a10,
- b02 = a00 * a13 - a03 * a10,
- b03 = a01 * a12 - a02 * a11,
- b04 = a01 * a13 - a03 * a11,
- b05 = a02 * a13 - a03 * a12,
- b06 = a20 * a31 - a21 * a30,
- b07 = a20 * a32 - a22 * a30,
- b08 = a20 * a33 - a23 * a30,
- b09 = a21 * a32 - a22 * a31,
- b10 = a21 * a33 - a23 * a31,
- b11 = a22 * a33 - a23 * a32,
-
- // Calculate the determinant
- 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 {mat4} a the source matrix
- * @returns {mat4} out
- */
-mat4.adjoint = function(out, a) {
- var 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],
- 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 {mat4} a the source matrix
- * @returns {Number} determinant of a
- */
-mat4.determinant = function (a) {
- var 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],
- a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
-
- b00 = a00 * a11 - a01 * a10,
- b01 = a00 * a12 - a02 * a10,
- b02 = a00 * a13 - a03 * a10,
- b03 = a01 * a12 - a02 * a11,
- b04 = a01 * a13 - a03 * a11,
- b05 = a02 * a13 - a03 * a12,
- b06 = a20 * a31 - a21 * a30,
- b07 = a20 * a32 - a22 * a30,
- b08 = a20 * a33 - a23 * a30,
- b09 = a21 * a32 - a22 * a31,
- b10 = a21 * a33 - a23 * a31,
- b11 = a22 * a33 - a23 * a32;
-
- // Calculate the determinant
- return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
-};
-
-/**
- * Multiplies two mat4's
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the first operand
- * @param {mat4} b the second operand
- * @returns {mat4} out
- */
-mat4.multiply = function (out, a, b) {
- var 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],
- 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;
-};
-
-/**
- * Alias for {@link mat4.multiply}
- * @function
- */
-mat4.mul = mat4.multiply;
-
-/**
- * Translate a mat4 by the given vector
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the matrix to translate
- * @param {vec3} v vector to translate by
- * @returns {mat4} out
- */
-mat4.translate = function (out, a, v) {
- var x = v[0], y = v[1], z = v[2],
- a00, a01, a02, a03,
- a10, a11, a12, a13,
- 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
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the matrix to scale
- * @param {vec3} v the vec3 to scale the matrix by
- * @returns {mat4} out
- **/
-mat4.scale = function(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
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the matrix to rotate
- * @param {Number} rad the angle to rotate the matrix by
- * @param {vec3} axis the axis to rotate around
- * @returns {mat4} out
- */
-mat4.rotate = function (out, a, rad, axis) {
- var x = axis[0], y = axis[1], z = axis[2],
- len = Math.sqrt(x * x + y * y + z * z),
- s, c, t,
- a00, a01, a02, a03,
- a10, a11, a12, a13,
- a20, a21, a22, a23,
- b00, b01, b02,
- b10, b11, b12,
- b20, b21, b22;
-
- if (Math.abs(len) < GLMAT_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 {mat4} a the matrix to rotate
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat4} out
- */
-mat4.rotateX = function (out, a, rad) {
- var s = Math.sin(rad),
- c = Math.cos(rad),
- a10 = a[4],
- a11 = a[5],
- a12 = a[6],
- a13 = a[7],
- a20 = a[8],
- a21 = a[9],
- a22 = a[10],
- 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 {mat4} a the matrix to rotate
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat4} out
- */
-mat4.rotateY = function (out, a, rad) {
- var s = Math.sin(rad),
- c = Math.cos(rad),
- a00 = a[0],
- a01 = a[1],
- a02 = a[2],
- a03 = a[3],
- a20 = a[8],
- a21 = a[9],
- a22 = a[10],
- 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 {mat4} a the matrix to rotate
- * @param {Number} rad the angle to rotate the matrix by
- * @returns {mat4} out
- */
-mat4.rotateZ = function (out, a, rad) {
- var s = Math.sin(rad),
- c = Math.cos(rad),
- a00 = a[0],
- a01 = a[1],
- a02 = a[2],
- a03 = a[3],
- a10 = a[4],
- a11 = a[5],
- a12 = a[6],
- 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 quaternion rotation and vector translation
- * This is equivalent to (but much faster than):
- *
- * mat4.identity(dest);
- * mat4.translate(dest, vec);
- * var quatMat = mat4.create();
- * quat4.toMat4(quat, quatMat);
- * mat4.multiply(dest, quatMat);
- *
- * @param {mat4} out mat4 receiving operation result
- * @param {quat4} q Rotation quaternion
- * @param {vec3} v Translation vector
- * @returns {mat4} out
- */
-mat4.fromRotationTranslation = function (out, q, v) {
- // Quaternion math
- var x = q[0], y = q[1], z = q[2], w = q[3],
- x2 = x + x,
- y2 = y + y,
- z2 = z + z,
-
- xx = x * x2,
- xy = x * y2,
- xz = x * z2,
- yy = y * y2,
- yz = y * z2,
- zz = z * z2,
- wx = w * x2,
- wy = w * y2,
- 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;
-};
-
-mat4.fromQuat = function (out, q) {
- var x = q[0], y = q[1], z = q[2], w = q[3],
- x2 = x + x,
- y2 = y + y,
- z2 = z + z,
-
- xx = x * x2,
- yx = y * x2,
- yy = y * y2,
- zx = z * x2,
- zy = z * y2,
- zz = z * z2,
- wx = w * x2,
- wy = w * y2,
- 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
- */
-mat4.frustum = function (out, left, right, bottom, top, near, far) {
- var rl = 1 / (right - left),
- tb = 1 / (top - bottom),
- 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
- *
- * @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
- * @returns {mat4} out
- */
-mat4.perspective = function (out, fovy, aspect, near, far) {
- var f = 1.0 / Math.tan(fovy / 2),
- nf = 1 / (near - far);
- 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[10] = (far + near) * nf;
- out[11] = -1;
- out[12] = 0;
- out[13] = 0;
- out[14] = (2 * far * near) * nf;
- out[15] = 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
- */
-mat4.ortho = function (out, left, right, bottom, top, near, far) {
- var lr = 1 / (left - right),
- bt = 1 / (bottom - top),
- 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
- *
- * @param {mat4} out mat4 frustum matrix will be written into
- * @param {vec3} eye Position of the viewer
- * @param {vec3} center Point the viewer is looking at
- * @param {vec3} up vec3 pointing up
- * @returns {mat4} out
- */
-mat4.lookAt = function (out, eye, center, up) {
- var x0, x1, x2, y0, y1, y2, z0, z1, z2, len,
- eyex = eye[0],
- eyey = eye[1],
- eyez = eye[2],
- upx = up[0],
- upy = up[1],
- upz = up[2],
- centerx = center[0],
- centery = center[1],
- centerz = center[2];
-
- if (Math.abs(eyex - centerx) < GLMAT_EPSILON &&
- Math.abs(eyey - centery) < GLMAT_EPSILON &&
- Math.abs(eyez - centerz) < GLMAT_EPSILON) {
- return mat4.identity(out);
- }
-
- z0 = eyex - centerx;
- z1 = eyey - centery;
- z2 = eyez - centerz;
-
- len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
- z0 *= len;
- z1 *= len;
- z2 *= len;
-
- x0 = upy * z2 - upz * z1;
- x1 = upz * z0 - upx * z2;
- x2 = upx * z1 - upy * z0;
- len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * 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.sqrt(y0 * y0 + y1 * y1 + y2 * 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;
-};
-
-/**
- * Returns a string representation of a mat4
- *
- * @param {mat4} mat matrix to represent as a string
- * @returns {String} string representation of the matrix
- */
-mat4.str = function (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 {mat4} a the matrix to calculate Frobenius norm of
- * @returns {Number} Frobenius norm
- */
-mat4.frob = function (a) {
- return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2) + Math.pow(a[9], 2) + Math.pow(a[10], 2) + Math.pow(a[11], 2) + Math.pow(a[12], 2) + Math.pow(a[13], 2) + Math.pow(a[14], 2) + Math.pow(a[15], 2) ))
-};
-
-
-if(typeof(exports) !== 'undefined') {
- exports.mat4 = mat4;
-}
-;
-/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
-
-/**
- * @class Quaternion
- * @name quat
- */
-
-var quat = {};
-
-/**
- * Creates a new identity quat
- *
- * @returns {quat} a new quaternion
- */
-quat.create = function() {
- var out = new GLMAT_ARRAY_TYPE(4);
- out[0] = 0;
- out[1] = 0;
- out[2] = 0;
- out[3] = 1;
- return out;
-};
-
-/**
- * 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 {vec3} a the initial vector
- * @param {vec3} b the destination vector
- * @returns {quat} out
- */
-quat.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) {
- vec3.cross(tmpvec3, xUnitVec3, a);
- if (vec3.length(tmpvec3) < 0.000001)
- vec3.cross(tmpvec3, yUnitVec3, a);
- vec3.normalize(tmpvec3, tmpvec3);
- quat.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 {
- vec3.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);
- }
- };
-})();
-
-/**
- * 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 {vec3} view the vector representing the viewing direction
- * @param {vec3} right the vector representing the local "right" direction
- * @param {vec3} up the vector representing the local "up" direction
- * @returns {quat} out
- */
-quat.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, quat.fromMat3(out, matr));
- };
-})();
-
-/**
- * Creates a new quat initialized with values from an existing quaternion
- *
- * @param {quat} a quaternion to clone
- * @returns {quat} a new quaternion
- * @function
- */
-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
- */
-quat.fromValues = vec4.fromValues;
-
-/**
- * Copy the values from one quat to another
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a the source quaternion
- * @returns {quat} out
- * @function
- */
-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
- */
-quat.set = vec4.set;
-
-/**
- * Set a quat to the identity quaternion
- *
- * @param {quat} out the receiving quaternion
- * @returns {quat} out
- */
-quat.identity = function(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 {vec3} axis the axis around which to rotate
- * @param {Number} rad the angle in radians
- * @returns {quat} out
- **/
-quat.setAxisAngle = function(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;
-};
-
-/**
- * Adds two quat's
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a the first operand
- * @param {quat} b the second operand
- * @returns {quat} out
- * @function
- */
-quat.add = vec4.add;
-
-/**
- * Multiplies two quat's
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a the first operand
- * @param {quat} b the second operand
- * @returns {quat} out
- */
-quat.multiply = function(out, a, b) {
- var ax = a[0], ay = a[1], az = a[2], aw = a[3],
- 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;
-};
-
-/**
- * Alias for {@link quat.multiply}
- * @function
- */
-quat.mul = quat.multiply;
-
-/**
- * Scales a quat by a scalar number
- *
- * @param {quat} out the receiving vector
- * @param {quat} a the vector to scale
- * @param {Number} b amount to scale the vector by
- * @returns {quat} out
- * @function
- */
-quat.scale = vec4.scale;
-
-/**
- * Rotates a quaternion by the given angle about the X axis
- *
- * @param {quat} out quat receiving operation result
- * @param {quat} a quat to rotate
- * @param {number} rad angle (in radians) to rotate
- * @returns {quat} out
- */
-quat.rotateX = function (out, a, rad) {
- rad *= 0.5;
-
- var ax = a[0], ay = a[1], az = a[2], aw = a[3],
- 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 {quat} a quat to rotate
- * @param {number} rad angle (in radians) to rotate
- * @returns {quat} out
- */
-quat.rotateY = function (out, a, rad) {
- rad *= 0.5;
-
- var ax = a[0], ay = a[1], az = a[2], aw = a[3],
- 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 {quat} a quat to rotate
- * @param {number} rad angle (in radians) to rotate
- * @returns {quat} out
- */
-quat.rotateZ = function (out, a, rad) {
- rad *= 0.5;
-
- var ax = a[0], ay = a[1], az = a[2], aw = a[3],
- 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 {quat} a quat to calculate W component of
- * @returns {quat} out
- */
-quat.calculateW = function (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;
-};
-
-/**
- * Calculates the dot product of two quat's
- *
- * @param {quat} a the first operand
- * @param {quat} b the second operand
- * @returns {Number} dot product of a and b
- * @function
- */
-quat.dot = vec4.dot;
-
-/**
- * Performs a linear interpolation between two quat's
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a the first operand
- * @param {quat} b the second operand
- * @param {Number} t interpolation amount between the two inputs
- * @returns {quat} out
- * @function
- */
-quat.lerp = vec4.lerp;
-
-/**
- * Performs a spherical linear interpolation between two quat
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a the first operand
- * @param {quat} b the second operand
- * @param {Number} t interpolation amount between the two inputs
- * @returns {quat} out
- */
-quat.slerp = function (out, a, b, t) {
- // benchmarks:
- // http://jsperf.com/quaternion-slerp-implementations
-
- var ax = a[0], ay = a[1], az = a[2], aw = a[3],
- 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) > 0.000001 ) {
- // 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;
-};
-
-/**
- * Calculates the inverse of a quat
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a quat to calculate inverse of
- * @returns {quat} out
- */
-quat.invert = function(out, a) {
- var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
- dot = a0*a0 + a1*a1 + a2*a2 + a3*a3,
- 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 {quat} a quat to calculate conjugate of
- * @returns {quat} out
- */
-quat.conjugate = function (out, a) {
- out[0] = -a[0];
- out[1] = -a[1];
- out[2] = -a[2];
- out[3] = a[3];
- return out;
-};
-
-/**
- * Calculates the length of a quat
- *
- * @param {quat} a vector to calculate length of
- * @returns {Number} length of a
- * @function
- */
-quat.length = vec4.length;
-
-/**
- * Alias for {@link quat.length}
- * @function
- */
-quat.len = quat.length;
-
-/**
- * Calculates the squared length of a quat
- *
- * @param {quat} a vector to calculate squared length of
- * @returns {Number} squared length of a
- * @function
- */
-quat.squaredLength = vec4.squaredLength;
-
-/**
- * Alias for {@link quat.squaredLength}
- * @function
- */
-quat.sqrLen = quat.squaredLength;
-
-/**
- * Normalize a quat
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a quaternion to normalize
- * @returns {quat} out
- * @function
- */
-quat.normalize = vec4.normalize;
-
-/**
- * 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 {mat3} m rotation matrix
- * @returns {quat} out
- * @function
- */
-quat.fromMat3 = function(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[7]-m[5])*fRoot;
- out[1] = (m[2]-m[6])*fRoot;
- out[2] = (m[3]-m[1])*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[k*3+j] - m[j*3+k]) * 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;
-};
-
-/**
- * Returns a string representation of a quatenion
- *
- * @param {quat} vec vector to represent as a string
- * @returns {String} string representation of the vector
- */
-quat.str = function (a) {
- return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
-};
-
-if(typeof(exports) !== 'undefined') {
- exports.quat = quat;
-}
-;
-
-
-
-
-
-
-
-
-
-
-
-
-
- })(shim.exports);
-})(this);
-
-},{}],24:[function(require,module,exports){
-// Underscore.js 1.4.4
-// http://underscorejs.org
-// (c) 2009-2013 Jeremy Ashkenas, DocumentCloud Inc.
-// Underscore may be freely distributed under the MIT license.
-
-(function() {
-
- // Baseline setup
- // --------------
-
- // Establish the root object, `window` in the browser, or `global` on the server.
- var root = this;
-
- // Save the previous value of the `_` variable.
- var previousUnderscore = root._;
-
- // Establish the object that gets returned to break out of a loop iteration.
- var breaker = {};
-
- // Save bytes in the minified (but not gzipped) version:
- var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
-
- // Create quick reference variables for speed access to core prototypes.
- var push = ArrayProto.push,
- slice = ArrayProto.slice,
- concat = ArrayProto.concat,
- toString = ObjProto.toString,
- hasOwnProperty = ObjProto.hasOwnProperty;
-
- // All **ECMAScript 5** native function implementations that we hope to use
- // are declared here.
- var
- nativeForEach = ArrayProto.forEach,
- nativeMap = ArrayProto.map,
- nativeReduce = ArrayProto.reduce,
- nativeReduceRight = ArrayProto.reduceRight,
- nativeFilter = ArrayProto.filter,
- nativeEvery = ArrayProto.every,
- nativeSome = ArrayProto.some,
- nativeIndexOf = ArrayProto.indexOf,
- nativeLastIndexOf = ArrayProto.lastIndexOf,
- nativeIsArray = Array.isArray,
- nativeKeys = Object.keys,
- nativeBind = FuncProto.bind;
-
- // Create a safe reference to the Underscore object for use below.
- var _ = function(obj) {
- if (obj instanceof _) return obj;
- if (!(this instanceof _)) return new _(obj);
- this._wrapped = obj;
- };
-
- // Export the Underscore object for **Node.js**, with
- // backwards-compatibility for the old `require()` API. If we're in
- // the browser, add `_` as a global object via a string identifier,
- // for Closure Compiler "advanced" mode.
- if (typeof exports !== 'undefined') {
- if (typeof module !== 'undefined' && module.exports) {
- exports = module.exports = _;
- }
- exports._ = _;
- } else {
- root._ = _;
- }
-
- // Current version.
- _.VERSION = '1.4.4';
-
- // Collection Functions
- // --------------------
-
- // The cornerstone, an `each` implementation, aka `forEach`.
- // Handles objects with the built-in `forEach`, arrays, and raw objects.
- // Delegates to **ECMAScript 5**'s native `forEach` if available.
- var each = _.each = _.forEach = function(obj, iterator, context) {
- if (obj == null) return;
- if (nativeForEach && obj.forEach === nativeForEach) {
- obj.forEach(iterator, context);
- } else if (obj.length === +obj.length) {
- for (var i = 0, l = obj.length; i < l; i++) {
- if (iterator.call(context, obj[i], i, obj) === breaker) return;
- }
- } else {
- for (var key in obj) {
- if (_.has(obj, key)) {
- if (iterator.call(context, obj[key], key, obj) === breaker) return;
- }
- }
- }
- };
-
- // Return the results of applying the iterator to each element.
- // Delegates to **ECMAScript 5**'s native `map` if available.
- _.map = _.collect = function(obj, iterator, context) {
- var results = [];
- if (obj == null) return results;
- if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
- each(obj, function(value, index, list) {
- results[results.length] = iterator.call(context, value, index, list);
- });
- return results;
- };
-
- var reduceError = 'Reduce of empty array with no initial value';
-
- // **Reduce** builds up a single result from a list of values, aka `inject`,
- // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
- _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
- var initial = arguments.length > 2;
- if (obj == null) obj = [];
- if (nativeReduce && obj.reduce === nativeReduce) {
- if (context) iterator = _.bind(iterator, context);
- return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
- }
- each(obj, function(value, index, list) {
- if (!initial) {
- memo = value;
- initial = true;
- } else {
- memo = iterator.call(context, memo, value, index, list);
- }
- });
- if (!initial) throw new TypeError(reduceError);
- return memo;
- };
-
- // The right-associative version of reduce, also known as `foldr`.
- // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
- _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
- var initial = arguments.length > 2;
- if (obj == null) obj = [];
- if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
- if (context) iterator = _.bind(iterator, context);
- return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
- }
- var length = obj.length;
- if (length !== +length) {
- var keys = _.keys(obj);
- length = keys.length;
- }
- each(obj, function(value, index, list) {
- index = keys ? keys[--length] : --length;
- if (!initial) {
- memo = obj[index];
- initial = true;
- } else {
- memo = iterator.call(context, memo, obj[index], index, list);
- }
- });
- if (!initial) throw new TypeError(reduceError);
- return memo;
- };
-
- // Return the first value which passes a truth test. Aliased as `detect`.
- _.find = _.detect = function(obj, iterator, context) {
- var result;
- any(obj, function(value, index, list) {
- if (iterator.call(context, value, index, list)) {
- result = value;
- return true;
- }
- });
- return result;
- };
-
- // Return all the elements that pass a truth test.
- // Delegates to **ECMAScript 5**'s native `filter` if available.
- // Aliased as `select`.
- _.filter = _.select = function(obj, iterator, context) {
- var results = [];
- if (obj == null) return results;
- if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
- each(obj, function(value, index, list) {
- if (iterator.call(context, value, index, list)) results[results.length] = value;
- });
- return results;
- };
-
- // Return all the elements for which a truth test fails.
- _.reject = function(obj, iterator, context) {
- return _.filter(obj, function(value, index, list) {
- return !iterator.call(context, value, index, list);
- }, context);
- };
-
- // Determine whether all of the elements match a truth test.
- // Delegates to **ECMAScript 5**'s native `every` if available.
- // Aliased as `all`.
- _.every = _.all = function(obj, iterator, context) {
- iterator || (iterator = _.identity);
- var result = true;
- if (obj == null) return result;
- if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
- each(obj, function(value, index, list) {
- if (!(result = result && iterator.call(context, value, index, list))) return breaker;
- });
- return !!result;
- };
-
- // Determine if at least one element in the object matches a truth test.
- // Delegates to **ECMAScript 5**'s native `some` if available.
- // Aliased as `any`.
- var any = _.some = _.any = function(obj, iterator, context) {
- iterator || (iterator = _.identity);
- var result = false;
- if (obj == null) return result;
- if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
- each(obj, function(value, index, list) {
- if (result || (result = iterator.call(context, value, index, list))) return breaker;
- });
- return !!result;
- };
-
- // Determine if the array or object contains a given value (using `===`).
- // Aliased as `include`.
- _.contains = _.include = function(obj, target) {
- if (obj == null) return false;
- if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
- return any(obj, function(value) {
- return value === target;
- });
- };
-
- // Invoke a method (with arguments) on every item in a collection.
- _.invoke = function(obj, method) {
- var args = slice.call(arguments, 2);
- var isFunc = _.isFunction(method);
- return _.map(obj, function(value) {
- return (isFunc ? method : value[method]).apply(value, args);
- });
- };
-
- // Convenience version of a common use case of `map`: fetching a property.
- _.pluck = function(obj, key) {
- return _.map(obj, function(value){ return value[key]; });
- };
-
- // Convenience version of a common use case of `filter`: selecting only objects
- // containing specific `key:value` pairs.
- _.where = function(obj, attrs, first) {
- if (_.isEmpty(attrs)) return first ? null : [];
- return _[first ? 'find' : 'filter'](obj, function(value) {
- for (var key in attrs) {
- if (attrs[key] !== value[key]) return false;
- }
- return true;
- });
- };
-
- // Convenience version of a common use case of `find`: getting the first object
- // containing specific `key:value` pairs.
- _.findWhere = function(obj, attrs) {
- return _.where(obj, attrs, true);
- };
-
- // Return the maximum element or (element-based computation).
- // Can't optimize arrays of integers longer than 65,535 elements.
- // See: https://bugs.webkit.org/show_bug.cgi?id=80797
- _.max = function(obj, iterator, context) {
- if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
- return Math.max.apply(Math, obj);
- }
- if (!iterator && _.isEmpty(obj)) return -Infinity;
- var result = {computed : -Infinity, value: -Infinity};
- each(obj, function(value, index, list) {
- var computed = iterator ? iterator.call(context, value, index, list) : value;
- computed >= result.computed && (result = {value : value, computed : computed});
- });
- return result.value;
- };
-
- // Return the minimum element (or element-based computation).
- _.min = function(obj, iterator, context) {
- if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
- return Math.min.apply(Math, obj);
- }
- if (!iterator && _.isEmpty(obj)) return Infinity;
- var result = {computed : Infinity, value: Infinity};
- each(obj, function(value, index, list) {
- var computed = iterator ? iterator.call(context, value, index, list) : value;
- computed < result.computed && (result = {value : value, computed : computed});
- });
- return result.value;
- };
-
- // Shuffle an array.
- _.shuffle = function(obj) {
- var rand;
- var index = 0;
- var shuffled = [];
- each(obj, function(value) {
- rand = _.random(index++);
- shuffled[index - 1] = shuffled[rand];
- shuffled[rand] = value;
- });
- return shuffled;
- };
-
- // An internal function to generate lookup iterators.
- var lookupIterator = function(value) {
- return _.isFunction(value) ? value : function(obj){ return obj[value]; };
- };
-
- // Sort the object's values by a criterion produced by an iterator.
- _.sortBy = function(obj, value, context) {
- var iterator = lookupIterator(value);
- return _.pluck(_.map(obj, function(value, index, list) {
- return {
- value : value,
- index : index,
- criteria : iterator.call(context, value, index, list)
- };
- }).sort(function(left, right) {
- var a = left.criteria;
- var b = right.criteria;
- if (a !== b) {
- if (a > b || a === void 0) return 1;
- if (a < b || b === void 0) return -1;
- }
- return left.index < right.index ? -1 : 1;
- }), 'value');
- };
-
- // An internal function used for aggregate "group by" operations.
- var group = function(obj, value, context, behavior) {
- var result = {};
- var iterator = lookupIterator(value || _.identity);
- each(obj, function(value, index) {
- var key = iterator.call(context, value, index, obj);
- behavior(result, key, value);
- });
- return result;
- };
-
- // Groups the object's values by a criterion. Pass either a string attribute
- // to group by, or a function that returns the criterion.
- _.groupBy = function(obj, value, context) {
- return group(obj, value, context, function(result, key, value) {
- (_.has(result, key) ? result[key] : (result[key] = [])).push(value);
- });
- };
-
- // Counts instances of an object that group by a certain criterion. Pass
- // either a string attribute to count by, or a function that returns the
- // criterion.
- _.countBy = function(obj, value, context) {
- return group(obj, value, context, function(result, key) {
- if (!_.has(result, key)) result[key] = 0;
- result[key]++;
- });
- };
-
- // Use a comparator function to figure out the smallest index at which
- // an object should be inserted so as to maintain order. Uses binary search.
- _.sortedIndex = function(array, obj, iterator, context) {
- iterator = iterator == null ? _.identity : lookupIterator(iterator);
- var value = iterator.call(context, obj);
- var low = 0, high = array.length;
- while (low < high) {
- var mid = (low + high) >>> 1;
- iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;
- }
- return low;
- };
-
- // Safely convert anything iterable into a real, live array.
- _.toArray = function(obj) {
- if (!obj) return [];
- if (_.isArray(obj)) return slice.call(obj);
- if (obj.length === +obj.length) return _.map(obj, _.identity);
- return _.values(obj);
- };
-
- // Return the number of elements in an object.
- _.size = function(obj) {
- if (obj == null) return 0;
- return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;
- };
-
- // Array Functions
- // ---------------
-
- // Get the first element of an array. Passing **n** will return the first N
- // values in the array. Aliased as `head` and `take`. The **guard** check
- // allows it to work with `_.map`.
- _.first = _.head = _.take = function(array, n, guard) {
- if (array == null) return void 0;
- return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
- };
-
- // Returns everything but the last entry of the array. Especially useful on
- // the arguments object. Passing **n** will return all the values in
- // the array, excluding the last N. The **guard** check allows it to work with
- // `_.map`.
- _.initial = function(array, n, guard) {
- return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
- };
-
- // Get the last element of an array. Passing **n** will return the last N
- // values in the array. The **guard** check allows it to work with `_.map`.
- _.last = function(array, n, guard) {
- if (array == null) return void 0;
- if ((n != null) && !guard) {
- return slice.call(array, Math.max(array.length - n, 0));
- } else {
- return array[array.length - 1];
- }
- };
-
- // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
- // Especially useful on the arguments object. Passing an **n** will return
- // the rest N values in the array. The **guard**
- // check allows it to work with `_.map`.
- _.rest = _.tail = _.drop = function(array, n, guard) {
- return slice.call(array, (n == null) || guard ? 1 : n);
- };
-
- // Trim out all falsy values from an array.
- _.compact = function(array) {
- return _.filter(array, _.identity);
- };
-
- // Internal implementation of a recursive `flatten` function.
- var flatten = function(input, shallow, output) {
- each(input, function(value) {
- if (_.isArray(value)) {
- shallow ? push.apply(output, value) : flatten(value, shallow, output);
- } else {
- output.push(value);
- }
- });
- return output;
- };
-
- // Return a completely flattened version of an array.
- _.flatten = function(array, shallow) {
- return flatten(array, shallow, []);
- };
-
- // Return a version of the array that does not contain the specified value(s).
- _.without = function(array) {
- return _.difference(array, slice.call(arguments, 1));
- };
-
- // Produce a duplicate-free version of the array. If the array has already
- // been sorted, you have the option of using a faster algorithm.
- // Aliased as `unique`.
- _.uniq = _.unique = function(array, isSorted, iterator, context) {
- if (_.isFunction(isSorted)) {
- context = iterator;
- iterator = isSorted;
- isSorted = false;
- }
- var initial = iterator ? _.map(array, iterator, context) : array;
- var results = [];
- var seen = [];
- each(initial, function(value, index) {
- if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {
- seen.push(value);
- results.push(array[index]);
- }
- });
- return results;
- };
-
- // Produce an array that contains the union: each distinct element from all of
- // the passed-in arrays.
- _.union = function() {
- return _.uniq(concat.apply(ArrayProto, arguments));
- };
-
- // Produce an array that contains every item shared between all the
- // passed-in arrays.
- _.intersection = function(array) {
- var rest = slice.call(arguments, 1);
- return _.filter(_.uniq(array), function(item) {
- return _.every(rest, function(other) {
- return _.indexOf(other, item) >= 0;
- });
- });
- };
-
- // Take the difference between one array and a number of other arrays.
- // Only the elements present in just the first array will remain.
- _.difference = function(array) {
- var rest = concat.apply(ArrayProto, slice.call(arguments, 1));
- return _.filter(array, function(value){ return !_.contains(rest, value); });
- };
-
- // Zip together multiple lists into a single array -- elements that share
- // an index go together.
- _.zip = function() {
- var args = slice.call(arguments);
- var length = _.max(_.pluck(args, 'length'));
- var results = new Array(length);
- for (var i = 0; i < length; i++) {
- results[i] = _.pluck(args, "" + i);
- }
- return results;
- };
-
- // Converts lists into objects. Pass either a single array of `[key, value]`
- // pairs, or two parallel arrays of the same length -- one of keys, and one of
- // the corresponding values.
- _.object = function(list, values) {
- if (list == null) return {};
- var result = {};
- for (var i = 0, l = list.length; i < l; i++) {
- if (values) {
- result[list[i]] = values[i];
- } else {
- result[list[i][0]] = list[i][1];
- }
- }
- return result;
- };
-
- // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
- // we need this function. Return the position of the first occurrence of an
- // item in an array, or -1 if the item is not included in the array.
- // Delegates to **ECMAScript 5**'s native `indexOf` if available.
- // If the array is large and already in sort order, pass `true`
- // for **isSorted** to use binary search.
- _.indexOf = function(array, item, isSorted) {
- if (array == null) return -1;
- var i = 0, l = array.length;
- if (isSorted) {
- if (typeof isSorted == 'number') {
- i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted);
- } else {
- i = _.sortedIndex(array, item);
- return array[i] === item ? i : -1;
- }
- }
- if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
- for (; i < l; i++) if (array[i] === item) return i;
- return -1;
- };
-
- // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
- _.lastIndexOf = function(array, item, from) {
- if (array == null) return -1;
- var hasIndex = from != null;
- if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {
- return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);
- }
- var i = (hasIndex ? from : array.length);
- while (i--) if (array[i] === item) return i;
- return -1;
- };
-
- // Generate an integer Array containing an arithmetic progression. A port of
- // the native Python `range()` function. See
- // [the Python documentation](http://docs.python.org/library/functions.html#range).
- _.range = function(start, stop, step) {
- if (arguments.length <= 1) {
- stop = start || 0;
- start = 0;
- }
- step = arguments[2] || 1;
-
- var len = Math.max(Math.ceil((stop - start) / step), 0);
- var idx = 0;
- var range = new Array(len);
-
- while(idx < len) {
- range[idx++] = start;
- start += step;
- }
-
- return range;
- };
-
- // Function (ahem) Functions
- // ------------------
-
- // Create a function bound to a given object (assigning `this`, and arguments,
- // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
- // available.
- _.bind = function(func, context) {
- if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
- var args = slice.call(arguments, 2);
- return function() {
- return func.apply(context, args.concat(slice.call(arguments)));
- };
- };
-
- // Partially apply a function by creating a version that has had some of its
- // arguments pre-filled, without changing its dynamic `this` context.
- _.partial = function(func) {
- var args = slice.call(arguments, 1);
- return function() {
- return func.apply(this, args.concat(slice.call(arguments)));
- };
- };
-
- // Bind all of an object's methods to that object. Useful for ensuring that
- // all callbacks defined on an object belong to it.
- _.bindAll = function(obj) {
- var funcs = slice.call(arguments, 1);
- if (funcs.length === 0) funcs = _.functions(obj);
- each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
- return obj;
- };
-
- // Memoize an expensive function by storing its results.
- _.memoize = function(func, hasher) {
- var memo = {};
- hasher || (hasher = _.identity);
- return function() {
- var key = hasher.apply(this, arguments);
- return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
- };
- };
-
- // Delays a function for the given number of milliseconds, and then calls
- // it with the arguments supplied.
- _.delay = function(func, wait) {
- var args = slice.call(arguments, 2);
- return setTimeout(function(){ return func.apply(null, args); }, wait);
- };
-
- // Defers a function, scheduling it to run after the current call stack has
- // cleared.
- _.defer = function(func) {
- return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
- };
-
- // Returns a function, that, when invoked, will only be triggered at most once
- // during a given window of time.
- _.throttle = function(func, wait) {
- var context, args, timeout, result;
- var previous = 0;
- var later = function() {
- previous = new Date;
- timeout = null;
- result = func.apply(context, args);
- };
- return function() {
- var now = new Date;
- var remaining = wait - (now - previous);
- context = this;
- args = arguments;
- if (remaining <= 0) {
- clearTimeout(timeout);
- timeout = null;
- previous = now;
- result = func.apply(context, args);
- } else if (!timeout) {
- timeout = setTimeout(later, remaining);
- }
- return result;
- };
- };
-
- // Returns a function, that, as long as it continues to be invoked, will not
- // be triggered. The function will be called after it stops being called for
- // N milliseconds. If `immediate` is passed, trigger the function on the
- // leading edge, instead of the trailing.
- _.debounce = function(func, wait, immediate) {
- var timeout, result;
- return function() {
- var context = this, args = arguments;
- var later = function() {
- timeout = null;
- if (!immediate) result = func.apply(context, args);
- };
- var callNow = immediate && !timeout;
- clearTimeout(timeout);
- timeout = setTimeout(later, wait);
- if (callNow) result = func.apply(context, args);
- return result;
- };
- };
-
- // Returns a function that will be executed at most one time, no matter how
- // often you call it. Useful for lazy initialization.
- _.once = function(func) {
- var ran = false, memo;
- return function() {
- if (ran) return memo;
- ran = true;
- memo = func.apply(this, arguments);
- func = null;
- return memo;
- };
- };
-
- // Returns the first function passed as an argument to the second,
- // allowing you to adjust arguments, run code before and after, and
- // conditionally execute the original function.
- _.wrap = function(func, wrapper) {
- return function() {
- var args = [func];
- push.apply(args, arguments);
- return wrapper.apply(this, args);
- };
- };
-
- // Returns a function that is the composition of a list of functions, each
- // consuming the return value of the function that follows.
- _.compose = function() {
- var funcs = arguments;
- return function() {
- var args = arguments;
- for (var i = funcs.length - 1; i >= 0; i--) {
- args = [funcs[i].apply(this, args)];
- }
- return args[0];
- };
- };
-
- // Returns a function that will only be executed after being called N times.
- _.after = function(times, func) {
- if (times <= 0) return func();
- return function() {
- if (--times < 1) {
- return func.apply(this, arguments);
- }
- };
- };
-
- // Object Functions
- // ----------------
-
- // Retrieve the names of an object's properties.
- // Delegates to **ECMAScript 5**'s native `Object.keys`
- _.keys = nativeKeys || function(obj) {
- if (obj !== Object(obj)) throw new TypeError('Invalid object');
- var keys = [];
- for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key;
- return keys;
- };
-
- // Retrieve the values of an object's properties.
- _.values = function(obj) {
- var values = [];
- for (var key in obj) if (_.has(obj, key)) values.push(obj[key]);
- return values;
- };
-
- // Convert an object into a list of `[key, value]` pairs.
- _.pairs = function(obj) {
- var pairs = [];
- for (var key in obj) if (_.has(obj, key)) pairs.push([key, obj[key]]);
- return pairs;
- };
-
- // Invert the keys and values of an object. The values must be serializable.
- _.invert = function(obj) {
- var result = {};
- for (var key in obj) if (_.has(obj, key)) result[obj[key]] = key;
- return result;
- };
-
- // Return a sorted list of the function names available on the object.
- // Aliased as `methods`
- _.functions = _.methods = function(obj) {
- var names = [];
- for (var key in obj) {
- if (_.isFunction(obj[key])) names.push(key);
- }
- return names.sort();
- };
-
- // Extend a given object with all the properties in passed-in object(s).
- _.extend = function(obj) {
- each(slice.call(arguments, 1), function(source) {
- if (source) {
- for (var prop in source) {
- obj[prop] = source[prop];
- }
- }
- });
- return obj;
- };
-
- // Return a copy of the object only containing the whitelisted properties.
- _.pick = function(obj) {
- var copy = {};
- var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
- each(keys, function(key) {
- if (key in obj) copy[key] = obj[key];
- });
- return copy;
- };
-
- // Return a copy of the object without the blacklisted properties.
- _.omit = function(obj) {
- var copy = {};
- var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
- for (var key in obj) {
- if (!_.contains(keys, key)) copy[key] = obj[key];
- }
- return copy;
- };
-
- // Fill in a given object with default properties.
- _.defaults = function(obj) {
- each(slice.call(arguments, 1), function(source) {
- if (source) {
- for (var prop in source) {
- if (obj[prop] == null) obj[prop] = source[prop];
- }
- }
- });
- return obj;
- };
-
- // Create a (shallow-cloned) duplicate of an object.
- _.clone = function(obj) {
- if (!_.isObject(obj)) return obj;
- return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
- };
-
- // Invokes interceptor with the obj, and then returns obj.
- // The primary purpose of this method is to "tap into" a method chain, in
- // order to perform operations on intermediate results within the chain.
- _.tap = function(obj, interceptor) {
- interceptor(obj);
- return obj;
- };
-
- // Internal recursive comparison function for `isEqual`.
- var eq = function(a, b, aStack, bStack) {
- // Identical objects are equal. `0 === -0`, but they aren't identical.
- // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal.
- if (a === b) return a !== 0 || 1 / a == 1 / b;
- // A strict comparison is necessary because `null == undefined`.
- if (a == null || b == null) return a === b;
- // Unwrap any wrapped objects.
- if (a instanceof _) a = a._wrapped;
- if (b instanceof _) b = b._wrapped;
- // Compare `[[Class]]` names.
- var className = toString.call(a);
- if (className != toString.call(b)) return false;
- switch (className) {
- // Strings, numbers, dates, and booleans are compared by value.
- case '[object String]':
- // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
- // equivalent to `new String("5")`.
- return a == String(b);
- case '[object Number]':
- // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
- // other numeric values.
- return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
- case '[object Date]':
- case '[object Boolean]':
- // Coerce dates and booleans to numeric primitive values. Dates are compared by their
- // millisecond representations. Note that invalid dates with millisecond representations
- // of `NaN` are not equivalent.
- return +a == +b;
- // RegExps are compared by their source patterns and flags.
- case '[object RegExp]':
- return a.source == b.source &&
- a.global == b.global &&
- a.multiline == b.multiline &&
- a.ignoreCase == b.ignoreCase;
- }
- if (typeof a != 'object' || typeof b != 'object') return false;
- // Assume equality for cyclic structures. The algorithm for detecting cyclic
- // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
- var length = aStack.length;
- while (length--) {
- // Linear search. Performance is inversely proportional to the number of
- // unique nested structures.
- if (aStack[length] == a) return bStack[length] == b;
- }
- // Add the first object to the stack of traversed objects.
- aStack.push(a);
- bStack.push(b);
- var size = 0, result = true;
- // Recursively compare objects and arrays.
- if (className == '[object Array]') {
- // Compare array lengths to determine if a deep comparison is necessary.
- size = a.length;
- result = size == b.length;
- if (result) {
- // Deep compare the contents, ignoring non-numeric properties.
- while (size--) {
- if (!(result = eq(a[size], b[size], aStack, bStack))) break;
- }
- }
- } else {
- // Objects with different constructors are not equivalent, but `Object`s
- // from different frames are.
- var aCtor = a.constructor, bCtor = b.constructor;
- if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
- _.isFunction(bCtor) && (bCtor instanceof bCtor))) {
- return false;
- }
- // Deep compare objects.
- for (var key in a) {
- if (_.has(a, key)) {
- // Count the expected number of properties.
- size++;
- // Deep compare each member.
- if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
- }
- }
- // Ensure that both objects contain the same number of properties.
- if (result) {
- for (key in b) {
- if (_.has(b, key) && !(size--)) break;
- }
- result = !size;
- }
- }
- // Remove the first object from the stack of traversed objects.
- aStack.pop();
- bStack.pop();
- return result;
- };
-
- // Perform a deep comparison to check if two objects are equal.
- _.isEqual = function(a, b) {
- return eq(a, b, [], []);
- };
-
- // Is a given array, string, or object empty?
- // An "empty" object has no enumerable own-properties.
- _.isEmpty = function(obj) {
- if (obj == null) return true;
- if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
- for (var key in obj) if (_.has(obj, key)) return false;
- return true;
- };
-
- // Is a given value a DOM element?
- _.isElement = function(obj) {
- return !!(obj && obj.nodeType === 1);
- };
-
- // Is a given value an array?
- // Delegates to ECMA5's native Array.isArray
- _.isArray = nativeIsArray || function(obj) {
- return toString.call(obj) == '[object Array]';
- };
-
- // Is a given variable an object?
- _.isObject = function(obj) {
- return obj === Object(obj);
- };
-
- // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
- each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
- _['is' + name] = function(obj) {
- return toString.call(obj) == '[object ' + name + ']';
- };
- });
-
- // Define a fallback version of the method in browsers (ahem, IE), where
- // there isn't any inspectable "Arguments" type.
- if (!_.isArguments(arguments)) {
- _.isArguments = function(obj) {
- return !!(obj && _.has(obj, 'callee'));
- };
- }
-
- // Optimize `isFunction` if appropriate.
- if (typeof (/./) !== 'function') {
- _.isFunction = function(obj) {
- return typeof obj === 'function';
- };
- }
-
- // Is a given object a finite number?
- _.isFinite = function(obj) {
- return isFinite(obj) && !isNaN(parseFloat(obj));
- };
-
- // Is the given value `NaN`? (NaN is the only number which does not equal itself).
- _.isNaN = function(obj) {
- return _.isNumber(obj) && obj != +obj;
- };
-
- // Is a given value a boolean?
- _.isBoolean = function(obj) {
- return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
- };
-
- // Is a given value equal to null?
- _.isNull = function(obj) {
- return obj === null;
- };
-
- // Is a given variable undefined?
- _.isUndefined = function(obj) {
- return obj === void 0;
- };
-
- // Shortcut function for checking if an object has a given property directly
- // on itself (in other words, not on a prototype).
- _.has = function(obj, key) {
- return hasOwnProperty.call(obj, key);
- };
-
- // Utility Functions
- // -----------------
-
- // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
- // previous owner. Returns a reference to the Underscore object.
- _.noConflict = function() {
- root._ = previousUnderscore;
- return this;
- };
-
- // Keep the identity function around for default iterators.
- _.identity = function(value) {
- return value;
- };
-
- // Run a function **n** times.
- _.times = function(n, iterator, context) {
- var accum = Array(n);
- for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);
- return accum;
- };
-
- // Return a random integer between min and max (inclusive).
- _.random = function(min, max) {
- if (max == null) {
- max = min;
- min = 0;
- }
- return min + Math.floor(Math.random() * (max - min + 1));
- };
-
- // List of HTML entities for escaping.
- var entityMap = {
- escape: {
- '&': '&',
- '<': '<',
- '>': '>',
- '"': '"',
- "'": ''',
- '/': '/'
- }
- };
- entityMap.unescape = _.invert(entityMap.escape);
-
- // Regexes containing the keys and values listed immediately above.
- var entityRegexes = {
- escape: new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),
- unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')
- };
-
- // Functions for escaping and unescaping strings to/from HTML interpolation.
- _.each(['escape', 'unescape'], function(method) {
- _[method] = function(string) {
- if (string == null) return '';
- return ('' + string).replace(entityRegexes[method], function(match) {
- return entityMap[method][match];
- });
- };
- });
-
- // If the value of the named property is a function then invoke it;
- // otherwise, return it.
- _.result = function(object, property) {
- if (object == null) return null;
- var value = object[property];
- return _.isFunction(value) ? value.call(object) : value;
- };
-
- // Add your own custom functions to the Underscore object.
- _.mixin = function(obj) {
- each(_.functions(obj), function(name){
- var func = _[name] = obj[name];
- _.prototype[name] = function() {
- var args = [this._wrapped];
- push.apply(args, arguments);
- return result.call(this, func.apply(_, args));
- };
- });
- };
-
- // Generate a unique integer id (unique within the entire client session).
- // Useful for temporary DOM ids.
- var idCounter = 0;
- _.uniqueId = function(prefix) {
- var id = ++idCounter + '';
- return prefix ? prefix + id : id;
- };
-
- // By default, Underscore uses ERB-style template delimiters, change the
- // following template settings to use alternative delimiters.
- _.templateSettings = {
- evaluate : /<%([\s\S]+?)%>/g,
- interpolate : /<%=([\s\S]+?)%>/g,
- escape : /<%-([\s\S]+?)%>/g
- };
-
- // When customizing `templateSettings`, if you don't want to define an
- // interpolation, evaluation or escaping regex, we need one that is
- // guaranteed not to match.
- var noMatch = /(.)^/;
-
- // Certain characters need to be escaped so that they can be put into a
- // string literal.
- var escapes = {
- "'": "'",
- '\\': '\\',
- '\r': 'r',
- '\n': 'n',
- '\t': 't',
- '\u2028': 'u2028',
- '\u2029': 'u2029'
- };
-
- var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
-
- // JavaScript micro-templating, similar to John Resig's implementation.
- // Underscore templating handles arbitrary delimiters, preserves whitespace,
- // and correctly escapes quotes within interpolated code.
- _.template = function(text, data, settings) {
- var render;
- settings = _.defaults({}, settings, _.templateSettings);
-
- // Combine delimiters into one regular expression via alternation.
- var matcher = new RegExp([
- (settings.escape || noMatch).source,
- (settings.interpolate || noMatch).source,
- (settings.evaluate || noMatch).source
- ].join('|') + '|$', 'g');
-
- // Compile the template source, escaping string literals appropriately.
- var index = 0;
- var source = "__p+='";
- text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
- source += text.slice(index, offset)
- .replace(escaper, function(match) { return '\\' + escapes[match]; });
-
- if (escape) {
- source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
- }
- if (interpolate) {
- source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
- }
- if (evaluate) {
- source += "';\n" + evaluate + "\n__p+='";
- }
- index = offset + match.length;
- return match;
- });
- source += "';\n";
-
- // If a variable is not specified, place data values in local scope.
- if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
-
- source = "var __t,__p='',__j=Array.prototype.join," +
- "print=function(){__p+=__j.call(arguments,'');};\n" +
- source + "return __p;\n";
-
- try {
- render = new Function(settings.variable || 'obj', '_', source);
- } catch (e) {
- e.source = source;
- throw e;
- }
-
- if (data) return render(data, _);
- var template = function(data) {
- return render.call(this, data, _);
- };
-
- // Provide the compiled function source as a convenience for precompilation.
- template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
-
- return template;
- };
-
- // Add a "chain" function, which will delegate to the wrapper.
- _.chain = function(obj) {
- return _(obj).chain();
- };
-
- // OOP
- // ---------------
- // If Underscore is called as a function, it returns a wrapped object that
- // can be used OO-style. This wrapper holds altered versions of all the
- // underscore functions. Wrapped objects may be chained.
-
- // Helper function to continue chaining intermediate results.
- var result = function(obj) {
- return this._chain ? _(obj).chain() : obj;
- };
-
- // Add all of the Underscore functions to the wrapper object.
- _.mixin(_);
-
- // Add all mutator Array functions to the wrapper.
- each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
- var method = ArrayProto[name];
- _.prototype[name] = function() {
- var obj = this._wrapped;
- method.apply(obj, arguments);
- if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];
- return result.call(this, obj);
- };
- });
-
- // Add all accessor Array functions to the wrapper.
- each(['concat', 'join', 'slice'], function(name) {
- var method = ArrayProto[name];
- _.prototype[name] = function() {
- return result.call(this, method.apply(this._wrapped, arguments));
- };
- });
-
- _.extend(_.prototype, {
-
- // Start chaining a wrapped Underscore object.
- chain: function() {
- this._chain = true;
- return this;
- },
-
- // Extracts the result from a wrapped and chained object.
- value: function() {
- return this._wrapped;
- }
-
- });
-
-}).call(this);
-
-},{}],25:[function(require,module,exports){
-if (typeof(window) !== 'undefined' && typeof(window.requestAnimationFrame) !== 'function') {
- window.requestAnimationFrame = (
- window.webkitRequestAnimationFrame ||
- window.mozRequestAnimationFrame ||
- window.oRequestAnimationFrame ||
- window.msRequestAnimationFrame ||
- function(callback) { setTimeout(callback, 1000 / 60); }
- );
-}
-
-Leap = require("../lib/index");
-
-},{"../lib/index":11}]},{},[25])
-;
\ No newline at end of file
diff --git a/leap-0.6.4.min.js b/leap-0.6.4.min.js
deleted file mode 100644
index 5b7b593e..00000000
--- a/leap-0.6.4.min.js
+++ /dev/null
@@ -1,11 +0,0 @@
-/*!
- * LeapJS v0.6.4
- * http://github.com/leapmotion/leapjs/
- *
- * Copyright 2013 LeapMotion, Inc. and other contributors
- * Released under the Apache-2.0 license
- * http://github.com/leapmotion/leapjs/blob/master/LICENSE.txt
- */
-!function(a,b,c){function d(c,f){if(!b[c]){if(!a[c]){var g="function"==typeof require&&require;if(!f&&g)return g(c,!0);if(e)return e(c,!0);throw new Error("Cannot find module '"+c+"'")}var h=b[c]={exports:{}};a[c][0].call(h.exports,function(b){var e=a[c][1][b];return d(e?e:b)},h,h.exports)}return b[c].exports}for(var e="function"==typeof require&&require,f=0;f=this.size?void 0:a>=this._buf.length?void 0:this._buf[(this.pos-a-1)%this.size]},c.prototype.push=function(a){return this._buf[this.pos%this.size]=a,this.pos++}},{}],3:[function(a,b){var c=a("../protocol").chooseProtocol,d=a("events").EventEmitter,e=a("underscore"),f=b.exports=function(a){this.opts=e.defaults(a||{},{host:"127.0.0.1",enableGestures:!1,scheme:this.getScheme(),port:this.getPort(),background:!1,optimizeHMD:!1,requestProtocolVersion:f.defaultProtocolVersion}),this.host=this.opts.host,this.port=this.opts.port,this.scheme=this.opts.scheme,this.protocolVersionVerified=!1,this.background=null,this.optimizeHMD=null,this.on("ready",function(){this.enableGestures(this.opts.enableGestures),this.setBackground(this.opts.background),this.setOptimizeHMD(this.opts.optimizeHMD),console.log(this.opts.optimizeHMD?"Optimized for head mounted display usage.":"Optimized for desktop usage.")})};f.defaultProtocolVersion=6,f.prototype.getUrl=function(){return this.scheme+"//"+this.host+":"+this.port+"/v"+this.opts.requestProtocolVersion+".json"},f.prototype.getScheme=function(){return"ws:"},f.prototype.getPort=function(){return 6437},f.prototype.setBackground=function(a){this.opts.background=a,this.protocol&&this.protocol.sendBackground&&this.background!==this.opts.background&&(this.background=this.opts.background,this.protocol.sendBackground(this,this.opts.background))},f.prototype.setOptimizeHMD=function(a){this.opts.optimizeHMD=a,this.protocol&&this.protocol.sendOptimizeHMD&&this.optimizeHMD!==this.opts.optimizeHMD&&(this.optimizeHMD=this.opts.optimizeHMD,this.protocol.sendOptimizeHMD(this,this.opts.optimizeHMD))},f.prototype.handleOpen=function(){this.connected||(this.connected=!0,this.emit("connect"))},f.prototype.enableGestures=function(a){this.gesturesEnabled=a?!0:!1,this.send(this.protocol.encode({enableGestures:this.gesturesEnabled}))},f.prototype.handleClose=function(a){this.connected&&(this.disconnect(),1001===a&&this.opts.requestProtocolVersion>1&&(this.protocolVersionVerified?this.protocolVersionVerified=!1:this.opts.requestProtocolVersion--),this.startReconnection())},f.prototype.startReconnection=function(){var a=this;this.reconnectionTimer||(this.reconnectionTimer=setInterval(function(){a.reconnect()},500))},f.prototype.stopReconnection=function(){this.reconnectionTimer=clearInterval(this.reconnectionTimer)},f.prototype.disconnect=function(a){return a||this.stopReconnection(),this.socket?(this.socket.close(),delete this.socket,delete this.protocol,delete this.background,delete this.optimizeHMD,delete this.focusedState,this.connected&&(this.connected=!1,this.emit("disconnect")),!0):void 0},f.prototype.reconnect=function(){this.connected?this.stopReconnection():(this.disconnect(!0),this.connect())},f.prototype.handleData=function(a){var b,d=JSON.parse(a);void 0===this.protocol?(b=this.protocol=c(d),this.protocolVersionVerified=!0,this.emit("ready")):b=this.protocol(d),this.emit(b.type,b)},f.prototype.connect=function(){return this.socket?void 0:(this.socket=this.setupSocket(),!0)},f.prototype.send=function(a){this.socket.send(a)},f.prototype.reportFocus=function(a){this.connected&&this.focusedState!==a&&(this.focusedState=a,this.emit(this.focusedState?"focus":"blur"),this.protocol&&this.protocol.sendFocused&&this.protocol.sendFocused(this,this.focusedState))},e.extend(f.prototype,d.prototype)},{"../protocol":15,events:21,underscore:24}],4:[function(a,b){var c=b.exports=a("./base"),d=a("underscore"),e=b.exports=function(a){c.call(this,a);var b=this;this.on("ready",function(){b.startFocusLoop()}),this.on("disconnect",function(){b.stopFocusLoop()})};d.extend(e.prototype,c.prototype),e.__proto__=c,e.prototype.useSecure=function(){return"https:"===location.protocol},e.prototype.getScheme=function(){return this.useSecure()?"wss:":"ws:"},e.prototype.getPort=function(){return this.useSecure()?6436:6437},e.prototype.setupSocket=function(){var a=this,b=new WebSocket(this.getUrl());return b.onopen=function(){a.handleOpen()},b.onclose=function(b){a.handleClose(b.code,b.reason)},b.onmessage=function(b){a.handleData(b.data)},b.onerror=function(){a.useSecure()&&"wss:"===a.scheme&&(a.scheme="ws:",a.port=6437,a.disconnect(),a.connect())},b},e.prototype.startFocusLoop=function(){if(!this.focusDetectorTimer){var a=this,b=null;b="undefined"!=typeof document.hidden?"hidden":"undefined"!=typeof document.mozHidden?"mozHidden":"undefined"!=typeof document.msHidden?"msHidden":"undefined"!=typeof document.webkitHidden?"webkitHidden":void 0,void 0===a.windowVisible&&(a.windowVisible=void 0===b?!0:document[b]===!1);var c=window.addEventListener("focus",function(){a.windowVisible=!0,e()}),d=window.addEventListener("blur",function(){a.windowVisible=!1,e()});this.on("disconnect",function(){window.removeEventListener("focus",c),window.removeEventListener("blur",d)});var e=function(){var c=void 0===b?!0:document[b]===!1;a.reportFocus(c&&a.windowVisible)};e(),this.focusDetectorTimer=setInterval(e,100)}},e.prototype.stopFocusLoop=function(){this.focusDetectorTimer&&(clearTimeout(this.focusDetectorTimer),delete this.focusDetectorTimer)}},{"./base":3,underscore:24}],5:[function(a,b){var c=a("__browserify_process"),d=a("./frame"),e=a("./hand"),f=a("./pointable"),g=a("./finger"),h=a("./circular_buffer"),i=a("./pipeline"),j=a("events").EventEmitter,k=a("./gesture").gestureListener,l=a("./dialog"),m=a("underscore"),n=b.exports=function(b){var e="undefined"!=typeof c&&c.versions&&c.versions.node,f=this;b=m.defaults(b||{},{inNode:e}),this.inNode=b.inNode,b=m.defaults(b||{},{frameEventName:this.useAnimationLoop()?"animationFrame":"deviceFrame",suppressAnimationLoop:!this.useAnimationLoop(),loopWhileDisconnected:!0,useAllPlugins:!1,checkVersion:!0}),this.animationFrameRequested=!1,this.onAnimationFrame=function(a){f.lastConnectionFrame.valid&&f.emit("animationFrame",f.lastConnectionFrame),f.emit("frameEnd",a),f.loopWhileDisconnected&&(f.connection.focusedState!==!1||f.connection.opts.background)?window.requestAnimationFrame(f.onAnimationFrame):f.animationFrameRequested=!1},this.suppressAnimationLoop=b.suppressAnimationLoop,this.loopWhileDisconnected=b.loopWhileDisconnected,this.frameEventName=b.frameEventName,this.useAllPlugins=b.useAllPlugins,this.history=new h(200),this.lastFrame=d.Invalid,this.lastValidFrame=d.Invalid,this.lastConnectionFrame=d.Invalid,this.accumulatedGestures=[],this.checkVersion=b.checkVersion,this.connectionType=void 0===b.connectionType?a(this.inBrowser()?"./connection/browser":"./connection/node"):b.connectionType,this.connection=new this.connectionType(b),this.streamingCount=0,this.devices={},this.plugins={},this._pluginPipelineSteps={},this._pluginExtendedMethods={},b.useAllPlugins&&this.useRegisteredPlugins(),this.setupFrameEvents(b),this.setupConnectionEvents(),this.startAnimationLoop()};n.prototype.gesture=function(a,b){var c=k(this,a);return void 0!==b&&c.stop(b),c},n.prototype.setBackground=function(a){return this.connection.setBackground(a),this},n.prototype.setOptimizeHMD=function(a){return this.connection.setOptimizeHMD(a),this},n.prototype.inBrowser=function(){return!this.inNode},n.prototype.useAnimationLoop=function(){return this.inBrowser()&&!this.inBackgroundPage()},n.prototype.inBackgroundPage=function(){return"undefined"!=typeof chrome&&chrome.extension&&chrome.extension.getBackgroundPage&&chrome.extension.getBackgroundPage()===window},n.prototype.connect=function(){return this.connection.connect(),this},n.prototype.streaming=function(){return this.streamingCount>0},n.prototype.connected=function(){return!!this.connection.connected},n.prototype.startAnimationLoop=function(){this.suppressAnimationLoop||this.animationFrameRequested||(this.animationFrameRequested=!0,window.requestAnimationFrame(this.onAnimationFrame))},n.prototype.disconnect=function(){return this.connection.disconnect(),this},n.prototype.frame=function(a){return this.history.get(a)||d.Invalid},n.prototype.loop=function(a){return a&&("function"==typeof a?this.on(this.frameEventName,a):this.setupFrameEvents(a)),this.connect()},n.prototype.addStep=function(a){this.pipeline||(this.pipeline=new i(this)),this.pipeline.addStep(a)},n.prototype.processFrame=function(a){a.gestures&&(this.accumulatedGestures=this.accumulatedGestures.concat(a.gestures)),this.lastConnectionFrame=a,this.startAnimationLoop(),this.emit("deviceFrame",a)},n.prototype.processFinishedFrame=function(a){if(this.lastFrame=a,a.valid&&(this.lastValidFrame=a),a.controller=this,a.historyIdx=this.history.push(a),a.gestures){a.gestures=this.accumulatedGestures,this.accumulatedGestures=[];for(var b=0;b!=a.gestures.length;b++)this.emit("gesture",a.gestures[b],a)}this.pipeline&&(a=this.pipeline.run(a),a||(a=d.Invalid)),this.emit("frame",a),this.emitHandEvents(a)},n.prototype.emitHandEvents=function(a){for(var b=0;b0){for(var b in a.devices)a.emit("deviceStopped",a.devices[b]),a.emit("deviceRemoved",a.devices[b]);a.emit("streamingStopped",a.devices[b]),a.streamingCount=0;for(var b in a.devices)delete a.devices[b]}};this.connection.on("focus",function(){a.loopWhileDisconnected&&a.startAnimationLoop(),a.emit("focus")}),this.connection.on("blur",function(){a.emit("blur")}),this.connection.on("protocol",function(b){b.on("beforeFrameCreated",function(b){a.emit("beforeFrameCreated",b)}),b.on("afterFrameCreated",function(b,c){a.emit("afterFrameCreated",b,c)}),a.emit("protocol",b)}),this.connection.on("ready",function(){a.checkVersion&&!a.inNode&&a.checkOutOfDate(),a.emit("ready")}),this.connection.on("connect",function(){a.emit("connect"),a.connection.removeListener("frame",b),a.connection.on("frame",b)}),this.connection.on("disconnect",function(){a.emit("disconnect"),c()}),this.connection.on("deviceConnect",function(d){d.state?(a.emit("deviceConnected"),a.connection.removeListener("frame",b),a.connection.on("frame",b)):(a.emit("deviceDisconnected"),c())}),this.connection.on("deviceEvent",function(b){var c=b.state,d=a.devices[c.id],e={};for(var f in c)d&&d.hasOwnProperty(f)&&d[f]==c[f]||(e[f]=!0);a.devices[c.id]=c,e.attached&&a.emit(c.attached?"deviceAttached":"deviceRemoved",c),e.streaming&&(c.streaming?(a.streamingCount++,a.emit("deviceStreaming",c),1==a.streamingCount&&a.emit("streamingStarted",c),e.attached||a.emit("deviceConnected")):e.attached&&c.attached||(a.streamingCount--,a.emit("deviceStopped",c),0==a.streamingCount&&a.emit("streamingStopped",c),a.emit("deviceDisconnected")))}),this.on("newListener",function(a){("deviceConnected"==a||"deviceDisconnected"==a)&&console.warn(a+" events are depricated. Consider using 'streamingStarted/streamingStopped' or 'deviceStreaming/deviceStopped' instead")})},n.prototype.checkOutOfDate=function(){console.assert(this.connection&&this.connection.protocol);var a=this.connection.protocol.serviceVersion,b=this.connection.protocol.version,c=this.connectionType.defaultProtocolVersion;return c>b?(console.warn("Your Protocol Version is v"+b+", this app was designed for v"+c),l.warnOutOfDate({sV:a,pV:b}),!0):!1},n._pluginFactories={},n.plugin=function(a,b){return this._pluginFactories[a]&&console.warn('Plugin "'+a+'" already registered'),this._pluginFactories[a]=b},n.plugins=function(){return m.keys(this._pluginFactories)};var o=function(a,b,c){-1!=["beforeFrameCreated","afterFrameCreated"].indexOf(b)?this.on(b,c):(this.pipeline||(this.pipeline=new i(this)),this._pluginPipelineSteps[a]||(this._pluginPipelineSteps[a]=[]),this._pluginPipelineSteps[a].push(this.pipeline.addWrappedStep(b,c)))},p=function(a,b,c){var h;switch(this._pluginExtendedMethods[a]||(this._pluginExtendedMethods[a]=[]),b){case"frame":h=d;break;case"hand":h=e;break;case"pointable":h=f,m.extend(g.prototype,c),m.extend(g.Invalid,c);break;case"finger":h=g;break;default:throw a+' specifies invalid object type "'+b+'" for prototypical extension'}m.extend(h.prototype,c),m.extend(h.Invalid,c),this._pluginExtendedMethods[a].push([h,c])};n.prototype.use=function(a,b){var c,d,e,f;if(d="function"==typeof a?a:n._pluginFactories[a],!d)throw"Leap Plugin "+a+" not found.";if(b||(b={}),this.plugins[a])return m.extend(this.plugins[a],b),this;this.plugins[a]=b,f=d.call(this,b);for(e in f)c=f[e],"function"==typeof c?o.call(this,a,e,c):p.call(this,a,e,c);return this},n.prototype.stopUsing=function(a){var b,c,d=this._pluginPipelineSteps[a],e=this._pluginExtendedMethods[a],f=0;if(this.plugins[a]){if(d)for(f=0;fUpgrade";return e=new d(g,{onclick:f,onmousemove:function(a){a.target==document.getElementById("leapjs-decline-upgrade")?(document.getElementById("leapjs-decline-upgrade").style.color="#000",document.getElementById("leapjs-decline-upgrade").style.boxShadow="0px 0px 2px #5daa00",document.getElementById("leapjs-accept-upgrade").style.color="#444",document.getElementById("leapjs-accept-upgrade").style.boxShadow="none"):(document.getElementById("leapjs-accept-upgrade").style.color="#000",document.getElementById("leapjs-accept-upgrade").style.boxShadow="0px 0px 2px #5daa00",document.getElementById("leapjs-decline-upgrade").style.color="#444",document.getElementById("leapjs-decline-upgrade").style.boxShadow="none")},onmouseout:function(){document.getElementById("leapjs-decline-upgrade").style.color="#444",document.getElementById("leapjs-decline-upgrade").style.boxShadow="none",document.getElementById("leapjs-accept-upgrade").style.color="#444",document.getElementById("leapjs-accept-upgrade").style.boxShadow="none"}}),e.show()},d.hasWarnedBones=!1,d.warnBones=function(){this.hasWarnedBones||(this.hasWarnedBones=!0,console.warn("Your Leap Service is out of date"),"undefined"!=typeof c&&c.versions&&c.versions.node||this.warnOutOfDate({reason:"bones"}))}},{__browserify_process:22}],7:[function(a,b){var c=a("./pointable"),d=a("./bone"),e=a("./dialog"),f=a("underscore"),g=b.exports=function(a){c.call(this,a),this.dipPosition=a.dipPosition,this.pipPosition=a.pipPosition,this.mcpPosition=a.mcpPosition,this.carpPosition=a.carpPosition,this.extended=a.extended,this.type=a.type,this.finger=!0,this.positions=[this.carpPosition,this.mcpPosition,this.pipPosition,this.dipPosition,this.tipPosition],a.bases?this.addBones(a):e.warnBones()};f.extend(g.prototype,c.prototype),g.prototype.addBones=function(a){this.metacarpal=new d(this,{type:0,width:this.width,prevJoint:this.carpPosition,nextJoint:this.mcpPosition,basis:a.bases[0]}),this.proximal=new d(this,{type:1,width:this.width,prevJoint:this.mcpPosition,nextJoint:this.pipPosition,basis:a.bases[1]}),this.medial=new d(this,{type:2,width:this.width,prevJoint:this.pipPosition,nextJoint:this.dipPosition,basis:a.bases[2]}),this.distal=new d(this,{type:3,width:this.width,prevJoint:this.dipPosition,nextJoint:a.btipPosition,basis:a.bases[3]}),this.bones=[this.metacarpal,this.proximal,this.medial,this.distal]},g.prototype.toString=function(){return"Finger [ id:"+this.id+" "+this.length+"mmx | width:"+this.width+"mm | direction:"+this.direction+" ]"},g.Invalid={valid:!1}},{"./bone":1,"./dialog":6,"./pointable":14,underscore:24}],8:[function(a,b){var c=a("./hand"),d=a("./pointable"),e=a("./gesture").createGesture,f=a("gl-matrix"),g=f.mat3,h=f.vec3,i=a("./interaction_box"),j=a("./finger"),k=a("underscore"),l=b.exports=function(a){if(this.valid=!0,this.id=a.id,this.timestamp=a.timestamp,this.hands=[],this.handsMap={},this.pointables=[],this.tools=[],this.fingers=[],a.interactionBox&&(this.interactionBox=new i(a.interactionBox)),this.gestures=[],this.pointablesMap={},this._translation=a.t,this._rotation=k.flatten(a.r),this._scaleFactor=a.s,this.data=a,this.type="frame",this.currentFrameRate=a.currentFrameRate,a.gestures)for(var b=0,c=a.gestures.length;b!=c;b++)this.gestures.push(e(a.gestures[b]));this.postprocessData(a)};l.prototype.postprocessData=function(a){a||(a=this.data);for(var b=0,e=a.hands.length;b!=e;b++){var f=new c(a.hands[b]);f.frame=this,this.hands.push(f),this.handsMap[f.id]=f}a.pointables=k.sortBy(a.pointables,function(a){return a.id});for(var g=0,h=a.pointables.length;g!=h;g++){var i=a.pointables[g],l=i.dipPosition?new j(i):new d(i);l.frame=this,this.addPointable(l)}},l.prototype.addPointable=function(a){if(this.pointables.push(a),this.pointablesMap[a.id]=a,(a.tool?this.tools:this.fingers).push(a),void 0!==a.handId&&this.handsMap.hasOwnProperty(a.handId)){var b=this.handsMap[a.handId];switch(b.pointables.push(a),(a.tool?b.tools:b.fingers).push(a),a.type){case 0:b.thumb=a;break;case 1:b.indexFinger=a;break;case 2:b.middleFinger=a;break;case 3:b.ringFinger=a;break;case 4:b.pinky=a}}},l.prototype.tool=function(a){var b=this.pointable(a);return b.tool?b:d.Invalid},l.prototype.pointable=function(a){return this.pointablesMap[a]||d.Invalid},l.prototype.finger=function(a){var b=this.pointable(a);return b.tool?d.Invalid:b},l.prototype.hand=function(a){return this.handsMap[a]||c.Invalid},l.prototype.rotationAngle=function(a,b){if(!this.valid||!a.valid)return 0;var c=this.rotationMatrix(a),d=.5*(c[0]+c[4]+c[8]-1),e=Math.acos(d);if(e=isNaN(e)?0:e,void 0!==b){var f=this.rotationAxis(a);e*=h.dot(f,h.normalize(h.create(),b))}return e},l.prototype.rotationAxis=function(a){return this.valid&&a.valid?h.normalize(h.create(),[this._rotation[7]-a._rotation[5],this._rotation[2]-a._rotation[6],this._rotation[3]-a._rotation[1]]):h.create()},l.prototype.rotationMatrix=function(a){if(!this.valid||!a.valid)return g.create();var b=g.transpose(g.create(),this._rotation);return g.multiply(g.create(),a._rotation,b)},l.prototype.scaleFactor=function(a){return this.valid&&a.valid?Math.exp(this._scaleFactor-a._scaleFactor):1},l.prototype.translation=function(a){return this.valid&&a.valid?h.subtract(h.create(),this._translation,a._translation):h.create()},l.prototype.toString=function(){var a="Frame [ id:"+this.id+" | timestamp:"+this.timestamp+" | Hand count:("+this.hands.length+") | Pointable count:("+this.pointables.length+")";return this.gestures&&(a+=" | Gesture count:("+this.gestures.length+")"),a+=" ]"},l.prototype.dump=function(){var a="";a+="Frame Info: ",a+=this.toString(),a+="
Raw JSON: ",a+=JSON.stringify(this.data)},l.Invalid={valid:!1,hands:[],fingers:[],tools:[],gestures:[],pointables:[],pointable:function(){return d.Invalid},finger:function(){return d.Invalid},hand:function(){return c.Invalid},toString:function(){return"invalid frame"},dump:function(){return this.toString()},rotationAngle:function(){return 0},rotationMatrix:function(){return g.create()},rotationAxis:function(){return h.create()},scaleFactor:function(){return 1},translation:function(){return h.create()}}},{"./finger":7,"./gesture":9,"./hand":10,"./interaction_box":12,"./pointable":14,"gl-matrix":23,underscore:24}],9:[function(a,b,c){var d=a("gl-matrix"),e=d.vec3,f=a("events").EventEmitter,g=a("underscore"),h=(c.createGesture=function(a){var b;switch(a.type){case"circle":b=new i(a);break;case"swipe":b=new j(a);break;case"screenTap":b=new k(a);break;case"keyTap":b=new l(a);break;default:throw"unknown gesture type"}return b.id=a.id,b.handIds=a.handIds.slice(),b.pointableIds=a.pointableIds.slice(),b.duration=a.duration,b.state=a.state,b.type=a.type,b},c.gestureListener=function(a,b){var c={},d={};a.on("gesture",function(a,e){if(a.type==b){if(("start"==a.state||"stop"==a.state)&&void 0===d[a.id]){var f=new h(a,e);d[a.id]=f,g.each(c,function(a,b){f.on(b,a)})}d[a.id].update(a,e),"stop"==a.state&&delete d[a.id]}});var e={start:function(a){return c.start=a,e},stop:function(a){return c.stop=a,e},complete:function(a){return c.stop=a,e},update:function(a){return c.update=a,e}};return e},c.Gesture=function(a,b){this.gestures=[a],this.frames=[b]});h.prototype.update=function(a,b){this.lastGesture=a,this.lastFrame=b,this.gestures.push(a),this.frames.push(b),this.emit(a.state,this)},h.prototype.translation=function(){return e.subtract(e.create(),this.lastGesture.startPosition,this.lastGesture.position)},g.extend(h.prototype,f.prototype);var i=function(a){this.center=a.center,this.normal=a.normal,this.progress=a.progress,this.radius=a.radius};i.prototype.toString=function(){return"CircleGesture ["+JSON.stringify(this)+"]"};var j=function(a){this.startPosition=a.startPosition,this.position=a.position,this.direction=a.direction,this.speed=a.speed};j.prototype.toString=function(){return"SwipeGesture ["+JSON.stringify(this)+"]"};var k=function(a){this.position=a.position,this.direction=a.direction,this.progress=a.progress};k.prototype.toString=function(){return"ScreenTapGesture ["+JSON.stringify(this)+"]"};var l=function(a){this.position=a.position,this.direction=a.direction,this.progress=a.progress};l.prototype.toString=function(){return"KeyTapGesture ["+JSON.stringify(this)+"]"}},{events:21,"gl-matrix":23,underscore:24}],10:[function(a,b){var c=a("./pointable"),d=a("./bone"),e=a("gl-matrix"),f=e.mat3,g=e.vec3,h=a("underscore"),i=b.exports=function(a){this.id=a.id,this.palmPosition=a.palmPosition,this.direction=a.direction,this.palmVelocity=a.palmVelocity,this.palmNormal=a.palmNormal,this.sphereCenter=a.sphereCenter,this.sphereRadius=a.sphereRadius,this.valid=!0,this.pointables=[],this.fingers=[],this.arm=a.armBasis?new d(this,{type:4,width:a.armWidth,prevJoint:a.elbow,nextJoint:a.wrist,basis:a.armBasis}):null,this.tools=[],this._translation=a.t,this._rotation=h.flatten(a.r),this._scaleFactor=a.s,this.timeVisible=a.timeVisible,this.stabilizedPalmPosition=a.stabilizedPalmPosition,this.type=a.type,this.grabStrength=a.grabStrength,this.pinchStrength=a.pinchStrength,this.confidence=a.confidence};i.prototype.finger=function(a){var b=this.frame.finger(a);return b&&b.handId==this.id?b:c.Invalid},i.prototype.rotationAngle=function(a,b){if(!this.valid||!a.valid)return 0;var c=a.hand(this.id);if(!c.valid)return 0;var d=this.rotationMatrix(a),e=.5*(d[0]+d[4]+d[8]-1),f=Math.acos(e);if(f=isNaN(f)?0:f,void 0!==b){var h=this.rotationAxis(a);f*=g.dot(h,g.normalize(g.create(),b))}return f},i.prototype.rotationAxis=function(a){if(!this.valid||!a.valid)return g.create();var b=a.hand(this.id);return b.valid?g.normalize(g.create(),[this._rotation[7]-b._rotation[5],this._rotation[2]-b._rotation[6],this._rotation[3]-b._rotation[1]]):g.create()},i.prototype.rotationMatrix=function(a){if(!this.valid||!a.valid)return f.create();var b=a.hand(this.id);if(!b.valid)return f.create();var c=f.transpose(f.create(),this._rotation),d=f.multiply(f.create(),b._rotation,c);return d},i.prototype.scaleFactor=function(a){if(!this.valid||!a.valid)return 1;var b=a.hand(this.id);return b.valid?Math.exp(this._scaleFactor-b._scaleFactor):1},i.prototype.translation=function(a){if(!this.valid||!a.valid)return g.create();var b=a.hand(this.id);return b.valid?[this._translation[0]-b._translation[0],this._translation[1]-b._translation[1],this._translation[2]-b._translation[2]]:g.create()},i.prototype.toString=function(){return"Hand ("+this.type+") [ id: "+this.id+" | palm velocity:"+this.palmVelocity+" | sphere center:"+this.sphereCenter+" ] "},i.prototype.pitch=function(){return Math.atan2(this.direction[1],-this.direction[2])},i.prototype.yaw=function(){return Math.atan2(this.direction[0],-this.direction[2])},i.prototype.roll=function(){return Math.atan2(this.palmNormal[0],-this.palmNormal[1])},i.Invalid={valid:!1,fingers:[],tools:[],pointables:[],left:!1,pointable:function(){return c.Invalid},finger:function(){return c.Invalid},toString:function(){return"invalid frame"},dump:function(){return this.toString()},rotationAngle:function(){return 0},rotationMatrix:function(){return f.create()},rotationAxis:function(){return g.create()},scaleFactor:function(){return 1},translation:function(){return g.create()}}},{"./bone":1,"./pointable":14,"gl-matrix":23,underscore:24}],11:[function(a,b){b.exports={Controller:a("./controller"),Frame:a("./frame"),Gesture:a("./gesture"),Hand:a("./hand"),Pointable:a("./pointable"),Finger:a("./finger"),InteractionBox:a("./interaction_box"),CircularBuffer:a("./circular_buffer"),UI:a("./ui"),JSONProtocol:a("./protocol").JSONProtocol,glMatrix:a("gl-matrix"),mat3:a("gl-matrix").mat3,vec3:a("gl-matrix").vec3,loopController:void 0,version:a("./version.js"),_:a("underscore"),EventEmitter:a("events").EventEmitter,loop:function(a,b){return a&&void 0===b&&"[object Function]"==={}.toString.call(a)&&(b=a,a={}),this.loopController?a&&this.loopController.setupFrameEvents(a):this.loopController=new this.Controller(a),this.loopController.loop(b),this.loopController},plugin:function(a,b){this.Controller.plugin(a,b)}}},{"./circular_buffer":2,"./controller":5,"./finger":7,"./frame":8,"./gesture":9,"./hand":10,"./interaction_box":12,"./pointable":14,"./protocol":15,"./ui":16,"./version.js":19,events:21,"gl-matrix":23,underscore:24}],12:[function(a,b){var c=a("gl-matrix"),d=c.vec3,e=b.exports=function(a){this.valid=!0,this.center=a.center,this.size=a.size,this.width=a.size[0],this.height=a.size[1],this.depth=a.size[2]};e.prototype.denormalizePoint=function(a){return d.fromValues((a[0]-.5)*this.size[0]+this.center[0],(a[1]-.5)*this.size[1]+this.center[1],(a[2]-.5)*this.size[2]+this.center[2])},e.prototype.normalizePoint=function(a,b){var c=d.fromValues((a[0]-this.center[0])/this.size[0]+.5,(a[1]-this.center[1])/this.size[1]+.5,(a[2]-this.center[2])/this.size[2]+.5);return b&&(c[0]=Math.min(Math.max(c[0],0),1),c[1]=Math.min(Math.max(c[1],0),1),c[2]=Math.min(Math.max(c[2],0),1)),c},e.prototype.toString=function(){return"InteractionBox [ width:"+this.width+" | height:"+this.height+" | depth:"+this.depth+" ]"},e.Invalid={valid:!1}},{"gl-matrix":23}],13:[function(a,b){var c=b.exports=function(a){this.steps=[],this.controller=a};c.prototype.addStep=function(a){this.steps.push(a)},c.prototype.run=function(a){for(var b=this.steps.length,c=0;c!=b&&a;c++)a=this.steps[c](a);return a},c.prototype.removeStep=function(a){var b=this.steps.indexOf(a);if(-1===b)throw"Step not found in pipeline";this.steps.splice(b,1)},c.prototype.addWrappedStep=function(a,b){var c=this.controller,d=function(d){var e,f,g;for(e="frame"==a?[d]:d[a+"s"]||[],f=0,g=e.length;g>f;f++)b.call(c,e[f]);return d};return this.addStep(d),d}},{}],14:[function(a,b){var c=a("gl-matrix"),d=(c.vec3,b.exports=function(a){this.valid=!0,this.id=a.id,this.handId=a.handId,this.length=a.length,this.tool=a.tool,this.width=a.width,this.direction=a.direction,this.stabilizedTipPosition=a.stabilizedTipPosition,this.tipPosition=a.tipPosition,this.tipVelocity=a.tipVelocity,this.touchZone=a.touchZone,this.touchDistance=a.touchDistance,this.timeVisible=a.timeVisible});d.prototype.toString=function(){return"Pointable [ id:"+this.id+" "+this.length+"mmx | width:"+this.width+"mm | direction:"+this.direction+" ]"},d.prototype.hand=function(){return this.frame.hand(this.handId)
-},d.Invalid={valid:!1}},{"gl-matrix":23}],15:[function(a,b,c){var d=a("./frame"),e=(a("./hand"),a("./pointable"),a("./finger"),a("underscore")),f=a("events").EventEmitter,g=function(a){this.type=a.type,this.state=a.state};c.chooseProtocol=function(a){var b;switch(a.version){case 1:case 2:case 3:case 4:case 5:case 6:b=h(a),b.sendBackground=function(a,c){a.send(b.encode({background:c}))},b.sendFocused=function(a,c){a.send(b.encode({focused:c}))},b.sendOptimizeHMD=function(a,c){a.send(b.encode({optimizeHMD:c}))};break;default:throw"unrecognized version"}return b};var h=c.JSONProtocol=function(a){var b=function(a){if(a.event)return new g(a.event);b.emit("beforeFrameCreated",a);var c=new d(a);return b.emit("afterFrameCreated",c,a),c};return b.encode=function(a){return JSON.stringify(a)},b.version=a.version,b.serviceVersion=a.serviceVersion,b.versionLong="Version "+a.version,b.type="protocol",e.extend(b,f.prototype),b}},{"./finger":7,"./frame":8,"./hand":10,"./pointable":14,events:21,underscore:24}],16:[function(a,b,c){c.UI={Region:a("./ui/region"),Cursor:a("./ui/cursor")}},{"./ui/cursor":17,"./ui/region":18}],17:[function(a,b){b.exports=function(){return function(a){var b=a.pointables.sort(function(a,b){return a.z-b.z})[0];return b&&b.valid&&(a.cursorPosition=b.tipPosition),a}}},{}],18:[function(a,b){var c=a("events").EventEmitter,d=a("underscore"),e=b.exports=function(a,b){this.start=new Vector(a),this.end=new Vector(b),this.enteredFrame=null};e.prototype.hasPointables=function(a){for(var b=0;b!=a.pointables.length;b++){var c=a.pointables[b].tipPosition;if(c.x>=this.start.x&&c.x<=this.end.x&&c.y>=this.start.y&&c.y<=this.end.y&&c.z>=this.start.z&&c.z<=this.end.z)return!0}return!1},e.prototype.listener=function(a){var b=this;return a&&a.nearThreshold&&this.setupNearRegion(a.nearThreshold),function(a){return b.updatePosition(a)}},e.prototype.clipper=function(){var a=this;return function(b){return a.updatePosition(b),a.enteredFrame?b:null}},e.prototype.setupNearRegion=function(a){var b=this.nearRegion=new e([this.start.x-a,this.start.y-a,this.start.z-a],[this.end.x+a,this.end.y+a,this.end.z+a]),c=this;b.on("enter",function(a){c.emit("near",a)}),b.on("exit",function(a){c.emit("far",a)}),c.on("exit",function(a){c.emit("near",a)})},e.prototype.updatePosition=function(a){return this.nearRegion&&this.nearRegion.updatePosition(a),this.hasPointables(a)&&null==this.enteredFrame?(this.enteredFrame=a,this.emit("enter",this.enteredFrame)):this.hasPointables(a)||null==this.enteredFrame||(this.enteredFrame=null,this.emit("exit",this.enteredFrame)),a},e.prototype.normalize=function(a){return new Vector([(a.x-this.start.x)/(this.end.x-this.start.x),(a.y-this.start.y)/(this.end.y-this.start.y),(a.z-this.start.z)/(this.end.z-this.start.z)])},e.prototype.mapToXY=function(a,b,c){var d=this.normalize(a),e=d.x,f=d.y;return e>1?e=1:-1>e&&(e=-1),f>1?f=1:-1>f&&(f=-1),[(e+1)/2*b,(1-f)/2*c,d.z]},d.extend(e.prototype,c.prototype)},{events:21,underscore:24}],19:[function(a,b){b.exports={full:"0.6.4",major:0,minor:6,dot:4}},{}],20:[function(){},{}],21:[function(a,b,c){function d(a,b){if(a.indexOf)return a.indexOf(b);for(var c=0;ce;e++)d[e].apply(this,c);return!0}return!1},f.prototype.addListener=function(a,b){if("function"!=typeof b)throw new Error("addListener only takes instances of Function");if(this._events||(this._events={}),this.emit("newListener",a,b),this._events[a])if(g(this._events[a])){if(!this._events[a].warned){var c;c=void 0!==this._events.maxListeners?this._events.maxListeners:h,c&&c>0&&this._events[a].length>c&&(this._events[a].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[a].length),console.trace())}this._events[a].push(b)}else this._events[a]=[this._events[a],b];else this._events[a]=b;return this},f.prototype.on=f.prototype.addListener,f.prototype.once=function(a,b){var c=this;return c.on(a,function d(){c.removeListener(a,d),b.apply(this,arguments)}),this},f.prototype.removeListener=function(a,b){if("function"!=typeof b)throw new Error("removeListener only takes instances of Function");if(!this._events||!this._events[a])return this;var c=this._events[a];if(g(c)){var e=d(c,b);if(0>e)return this;c.splice(e,1),0==c.length&&delete this._events[a]}else this._events[a]===b&&delete this._events[a];return this},f.prototype.removeAllListeners=function(a){return 0===arguments.length?(this._events={},this):(a&&this._events&&this._events[a]&&(this._events[a]=null),this)},f.prototype.listeners=function(a){return this._events||(this._events={}),this._events[a]||(this._events[a]=[]),g(this._events[a])||(this._events[a]=[this._events[a]]),this._events[a]},f.listenerCount=function(a,b){var c;return c=a._events&&a._events[b]?"function"==typeof a._events[b]?1:a._events[b].length:0}},{__browserify_process:22}],22:[function(a,b){var c=b.exports={};c.nextTick=function(){var a="undefined"!=typeof window&&window.setImmediate,b="undefined"!=typeof window&&window.postMessage&&window.addEventListener;if(a)return function(a){return window.setImmediate(a)};if(b){var c=[];return window.addEventListener("message",function(a){var b=a.source;if((b===window||null===b)&&"process-tick"===a.data&&(a.stopPropagation(),c.length>0)){var d=c.shift();d()}},!0),function(a){c.push(a),window.postMessage("process-tick","*")}}return function(a){setTimeout(a,0)}}(),c.title="browser",c.browser=!0,c.env={},c.argv=[],c.binding=function(){throw new Error("process.binding is not supported")},c.cwd=function(){return"/"},c.chdir=function(){throw new Error("process.chdir is not supported")}},{}],23:[function(a,b,c){!function(a){"use strict";var b={};"undefined"==typeof c?"function"==typeof define&&"object"==typeof define.amd&&define.amd?(b.exports={},define(function(){return b.exports})):b.exports="undefined"!=typeof window?window:a:b.exports=c,function(a){if(!b)var b=1e-6;if(!c)var c="undefined"!=typeof Float32Array?Float32Array:Array;if(!d)var d=Math.random;var e={};e.setMatrixArrayType=function(a){c=a},"undefined"!=typeof a&&(a.glMatrix=e);var f=Math.PI/180;e.toRadian=function(a){return a*f};var g={};g.create=function(){var a=new c(2);return a[0]=0,a[1]=0,a},g.clone=function(a){var b=new c(2);return b[0]=a[0],b[1]=a[1],b},g.fromValues=function(a,b){var d=new c(2);return d[0]=a,d[1]=b,d},g.copy=function(a,b){return a[0]=b[0],a[1]=b[1],a},g.set=function(a,b,c){return a[0]=b,a[1]=c,a},g.add=function(a,b,c){return a[0]=b[0]+c[0],a[1]=b[1]+c[1],a},g.subtract=function(a,b,c){return a[0]=b[0]-c[0],a[1]=b[1]-c[1],a},g.sub=g.subtract,g.multiply=function(a,b,c){return a[0]=b[0]*c[0],a[1]=b[1]*c[1],a},g.mul=g.multiply,g.divide=function(a,b,c){return a[0]=b[0]/c[0],a[1]=b[1]/c[1],a},g.div=g.divide,g.min=function(a,b,c){return a[0]=Math.min(b[0],c[0]),a[1]=Math.min(b[1],c[1]),a},g.max=function(a,b,c){return a[0]=Math.max(b[0],c[0]),a[1]=Math.max(b[1],c[1]),a},g.scale=function(a,b,c){return a[0]=b[0]*c,a[1]=b[1]*c,a},g.scaleAndAdd=function(a,b,c,d){return a[0]=b[0]+c[0]*d,a[1]=b[1]+c[1]*d,a},g.distance=function(a,b){var c=b[0]-a[0],d=b[1]-a[1];return Math.sqrt(c*c+d*d)},g.dist=g.distance,g.squaredDistance=function(a,b){var c=b[0]-a[0],d=b[1]-a[1];return c*c+d*d},g.sqrDist=g.squaredDistance,g.length=function(a){var b=a[0],c=a[1];return Math.sqrt(b*b+c*c)},g.len=g.length,g.squaredLength=function(a){var b=a[0],c=a[1];return b*b+c*c},g.sqrLen=g.squaredLength,g.negate=function(a,b){return a[0]=-b[0],a[1]=-b[1],a},g.normalize=function(a,b){var c=b[0],d=b[1],e=c*c+d*d;return e>0&&(e=1/Math.sqrt(e),a[0]=b[0]*e,a[1]=b[1]*e),a},g.dot=function(a,b){return a[0]*b[0]+a[1]*b[1]},g.cross=function(a,b,c){var d=b[0]*c[1]-b[1]*c[0];return a[0]=a[1]=0,a[2]=d,a},g.lerp=function(a,b,c,d){var e=b[0],f=b[1];return a[0]=e+d*(c[0]-e),a[1]=f+d*(c[1]-f),a},g.random=function(a,b){b=b||1;var c=2*d()*Math.PI;return a[0]=Math.cos(c)*b,a[1]=Math.sin(c)*b,a},g.transformMat2=function(a,b,c){var d=b[0],e=b[1];return a[0]=c[0]*d+c[2]*e,a[1]=c[1]*d+c[3]*e,a},g.transformMat2d=function(a,b,c){var d=b[0],e=b[1];return a[0]=c[0]*d+c[2]*e+c[4],a[1]=c[1]*d+c[3]*e+c[5],a},g.transformMat3=function(a,b,c){var d=b[0],e=b[1];return a[0]=c[0]*d+c[3]*e+c[6],a[1]=c[1]*d+c[4]*e+c[7],a},g.transformMat4=function(a,b,c){var d=b[0],e=b[1];return a[0]=c[0]*d+c[4]*e+c[12],a[1]=c[1]*d+c[5]*e+c[13],a},g.forEach=function(){var a=g.create();return function(b,c,d,e,f,g){var h,i;for(c||(c=2),d||(d=0),i=e?Math.min(e*c+d,b.length):b.length,h=d;i>h;h+=c)a[0]=b[h],a[1]=b[h+1],f(a,a,g),b[h]=a[0],b[h+1]=a[1];return b}}(),g.str=function(a){return"vec2("+a[0]+", "+a[1]+")"},"undefined"!=typeof a&&(a.vec2=g);var h={};h.create=function(){var a=new c(3);return a[0]=0,a[1]=0,a[2]=0,a},h.clone=function(a){var b=new c(3);return b[0]=a[0],b[1]=a[1],b[2]=a[2],b},h.fromValues=function(a,b,d){var e=new c(3);return e[0]=a,e[1]=b,e[2]=d,e},h.copy=function(a,b){return a[0]=b[0],a[1]=b[1],a[2]=b[2],a},h.set=function(a,b,c,d){return a[0]=b,a[1]=c,a[2]=d,a},h.add=function(a,b,c){return a[0]=b[0]+c[0],a[1]=b[1]+c[1],a[2]=b[2]+c[2],a},h.subtract=function(a,b,c){return a[0]=b[0]-c[0],a[1]=b[1]-c[1],a[2]=b[2]-c[2],a},h.sub=h.subtract,h.multiply=function(a,b,c){return a[0]=b[0]*c[0],a[1]=b[1]*c[1],a[2]=b[2]*c[2],a},h.mul=h.multiply,h.divide=function(a,b,c){return a[0]=b[0]/c[0],a[1]=b[1]/c[1],a[2]=b[2]/c[2],a},h.div=h.divide,h.min=function(a,b,c){return a[0]=Math.min(b[0],c[0]),a[1]=Math.min(b[1],c[1]),a[2]=Math.min(b[2],c[2]),a},h.max=function(a,b,c){return a[0]=Math.max(b[0],c[0]),a[1]=Math.max(b[1],c[1]),a[2]=Math.max(b[2],c[2]),a},h.scale=function(a,b,c){return a[0]=b[0]*c,a[1]=b[1]*c,a[2]=b[2]*c,a},h.scaleAndAdd=function(a,b,c,d){return a[0]=b[0]+c[0]*d,a[1]=b[1]+c[1]*d,a[2]=b[2]+c[2]*d,a},h.distance=function(a,b){var c=b[0]-a[0],d=b[1]-a[1],e=b[2]-a[2];return Math.sqrt(c*c+d*d+e*e)},h.dist=h.distance,h.squaredDistance=function(a,b){var c=b[0]-a[0],d=b[1]-a[1],e=b[2]-a[2];return c*c+d*d+e*e},h.sqrDist=h.squaredDistance,h.length=function(a){var b=a[0],c=a[1],d=a[2];return Math.sqrt(b*b+c*c+d*d)},h.len=h.length,h.squaredLength=function(a){var b=a[0],c=a[1],d=a[2];return b*b+c*c+d*d},h.sqrLen=h.squaredLength,h.negate=function(a,b){return a[0]=-b[0],a[1]=-b[1],a[2]=-b[2],a},h.normalize=function(a,b){var c=b[0],d=b[1],e=b[2],f=c*c+d*d+e*e;return f>0&&(f=1/Math.sqrt(f),a[0]=b[0]*f,a[1]=b[1]*f,a[2]=b[2]*f),a},h.dot=function(a,b){return a[0]*b[0]+a[1]*b[1]+a[2]*b[2]},h.cross=function(a,b,c){var d=b[0],e=b[1],f=b[2],g=c[0],h=c[1],i=c[2];return a[0]=e*i-f*h,a[1]=f*g-d*i,a[2]=d*h-e*g,a},h.lerp=function(a,b,c,d){var e=b[0],f=b[1],g=b[2];return a[0]=e+d*(c[0]-e),a[1]=f+d*(c[1]-f),a[2]=g+d*(c[2]-g),a},h.random=function(a,b){b=b||1;var c=2*d()*Math.PI,e=2*d()-1,f=Math.sqrt(1-e*e)*b;return a[0]=Math.cos(c)*f,a[1]=Math.sin(c)*f,a[2]=e*b,a},h.transformMat4=function(a,b,c){var d=b[0],e=b[1],f=b[2];return a[0]=c[0]*d+c[4]*e+c[8]*f+c[12],a[1]=c[1]*d+c[5]*e+c[9]*f+c[13],a[2]=c[2]*d+c[6]*e+c[10]*f+c[14],a},h.transformMat3=function(a,b,c){var d=b[0],e=b[1],f=b[2];return a[0]=d*c[0]+e*c[3]+f*c[6],a[1]=d*c[1]+e*c[4]+f*c[7],a[2]=d*c[2]+e*c[5]+f*c[8],a},h.transformQuat=function(a,b,c){var d=b[0],e=b[1],f=b[2],g=c[0],h=c[1],i=c[2],j=c[3],k=j*d+h*f-i*e,l=j*e+i*d-g*f,m=j*f+g*e-h*d,n=-g*d-h*e-i*f;return a[0]=k*j+n*-g+l*-i-m*-h,a[1]=l*j+n*-h+m*-g-k*-i,a[2]=m*j+n*-i+k*-h-l*-g,a},h.rotateX=function(a,b,c,d){var e=[],f=[];return e[0]=b[0]-c[0],e[1]=b[1]-c[1],e[2]=b[2]-c[2],f[0]=e[0],f[1]=e[1]*Math.cos(d)-e[2]*Math.sin(d),f[2]=e[1]*Math.sin(d)+e[2]*Math.cos(d),a[0]=f[0]+c[0],a[1]=f[1]+c[1],a[2]=f[2]+c[2],a},h.rotateY=function(a,b,c,d){var e=[],f=[];return e[0]=b[0]-c[0],e[1]=b[1]-c[1],e[2]=b[2]-c[2],f[0]=e[2]*Math.sin(d)+e[0]*Math.cos(d),f[1]=e[1],f[2]=e[2]*Math.cos(d)-e[0]*Math.sin(d),a[0]=f[0]+c[0],a[1]=f[1]+c[1],a[2]=f[2]+c[2],a},h.rotateZ=function(a,b,c,d){var e=[],f=[];return e[0]=b[0]-c[0],e[1]=b[1]-c[1],e[2]=b[2]-c[2],f[0]=e[0]*Math.cos(d)-e[1]*Math.sin(d),f[1]=e[0]*Math.sin(d)+e[1]*Math.cos(d),f[2]=e[2],a[0]=f[0]+c[0],a[1]=f[1]+c[1],a[2]=f[2]+c[2],a},h.forEach=function(){var a=h.create();return function(b,c,d,e,f,g){var h,i;for(c||(c=3),d||(d=0),i=e?Math.min(e*c+d,b.length):b.length,h=d;i>h;h+=c)a[0]=b[h],a[1]=b[h+1],a[2]=b[h+2],f(a,a,g),b[h]=a[0],b[h+1]=a[1],b[h+2]=a[2];return b}}(),h.str=function(a){return"vec3("+a[0]+", "+a[1]+", "+a[2]+")"},"undefined"!=typeof a&&(a.vec3=h);var i={};i.create=function(){var a=new c(4);return a[0]=0,a[1]=0,a[2]=0,a[3]=0,a},i.clone=function(a){var b=new c(4);return b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=a[3],b},i.fromValues=function(a,b,d,e){var f=new c(4);return f[0]=a,f[1]=b,f[2]=d,f[3]=e,f},i.copy=function(a,b){return a[0]=b[0],a[1]=b[1],a[2]=b[2],a[3]=b[3],a},i.set=function(a,b,c,d,e){return a[0]=b,a[1]=c,a[2]=d,a[3]=e,a},i.add=function(a,b,c){return a[0]=b[0]+c[0],a[1]=b[1]+c[1],a[2]=b[2]+c[2],a[3]=b[3]+c[3],a},i.subtract=function(a,b,c){return a[0]=b[0]-c[0],a[1]=b[1]-c[1],a[2]=b[2]-c[2],a[3]=b[3]-c[3],a},i.sub=i.subtract,i.multiply=function(a,b,c){return a[0]=b[0]*c[0],a[1]=b[1]*c[1],a[2]=b[2]*c[2],a[3]=b[3]*c[3],a},i.mul=i.multiply,i.divide=function(a,b,c){return a[0]=b[0]/c[0],a[1]=b[1]/c[1],a[2]=b[2]/c[2],a[3]=b[3]/c[3],a},i.div=i.divide,i.min=function(a,b,c){return a[0]=Math.min(b[0],c[0]),a[1]=Math.min(b[1],c[1]),a[2]=Math.min(b[2],c[2]),a[3]=Math.min(b[3],c[3]),a},i.max=function(a,b,c){return a[0]=Math.max(b[0],c[0]),a[1]=Math.max(b[1],c[1]),a[2]=Math.max(b[2],c[2]),a[3]=Math.max(b[3],c[3]),a},i.scale=function(a,b,c){return a[0]=b[0]*c,a[1]=b[1]*c,a[2]=b[2]*c,a[3]=b[3]*c,a},i.scaleAndAdd=function(a,b,c,d){return a[0]=b[0]+c[0]*d,a[1]=b[1]+c[1]*d,a[2]=b[2]+c[2]*d,a[3]=b[3]+c[3]*d,a},i.distance=function(a,b){var c=b[0]-a[0],d=b[1]-a[1],e=b[2]-a[2],f=b[3]-a[3];return Math.sqrt(c*c+d*d+e*e+f*f)},i.dist=i.distance,i.squaredDistance=function(a,b){var c=b[0]-a[0],d=b[1]-a[1],e=b[2]-a[2],f=b[3]-a[3];return c*c+d*d+e*e+f*f},i.sqrDist=i.squaredDistance,i.length=function(a){var b=a[0],c=a[1],d=a[2],e=a[3];return Math.sqrt(b*b+c*c+d*d+e*e)},i.len=i.length,i.squaredLength=function(a){var b=a[0],c=a[1],d=a[2],e=a[3];return b*b+c*c+d*d+e*e},i.sqrLen=i.squaredLength,i.negate=function(a,b){return a[0]=-b[0],a[1]=-b[1],a[2]=-b[2],a[3]=-b[3],a},i.normalize=function(a,b){var c=b[0],d=b[1],e=b[2],f=b[3],g=c*c+d*d+e*e+f*f;return g>0&&(g=1/Math.sqrt(g),a[0]=b[0]*g,a[1]=b[1]*g,a[2]=b[2]*g,a[3]=b[3]*g),a},i.dot=function(a,b){return a[0]*b[0]+a[1]*b[1]+a[2]*b[2]+a[3]*b[3]},i.lerp=function(a,b,c,d){var e=b[0],f=b[1],g=b[2],h=b[3];return a[0]=e+d*(c[0]-e),a[1]=f+d*(c[1]-f),a[2]=g+d*(c[2]-g),a[3]=h+d*(c[3]-h),a},i.random=function(a,b){return b=b||1,a[0]=d(),a[1]=d(),a[2]=d(),a[3]=d(),i.normalize(a,a),i.scale(a,a,b),a},i.transformMat4=function(a,b,c){var d=b[0],e=b[1],f=b[2],g=b[3];return a[0]=c[0]*d+c[4]*e+c[8]*f+c[12]*g,a[1]=c[1]*d+c[5]*e+c[9]*f+c[13]*g,a[2]=c[2]*d+c[6]*e+c[10]*f+c[14]*g,a[3]=c[3]*d+c[7]*e+c[11]*f+c[15]*g,a},i.transformQuat=function(a,b,c){var d=b[0],e=b[1],f=b[2],g=c[0],h=c[1],i=c[2],j=c[3],k=j*d+h*f-i*e,l=j*e+i*d-g*f,m=j*f+g*e-h*d,n=-g*d-h*e-i*f;return a[0]=k*j+n*-g+l*-i-m*-h,a[1]=l*j+n*-h+m*-g-k*-i,a[2]=m*j+n*-i+k*-h-l*-g,a},i.forEach=function(){var a=i.create();return function(b,c,d,e,f,g){var h,i;for(c||(c=4),d||(d=0),i=e?Math.min(e*c+d,b.length):b.length,h=d;i>h;h+=c)a[0]=b[h],a[1]=b[h+1],a[2]=b[h+2],a[3]=b[h+3],f(a,a,g),b[h]=a[0],b[h+1]=a[1],b[h+2]=a[2],b[h+3]=a[3];return b}}(),i.str=function(a){return"vec4("+a[0]+", "+a[1]+", "+a[2]+", "+a[3]+")"},"undefined"!=typeof a&&(a.vec4=i);var j={};j.create=function(){var a=new c(4);return a[0]=1,a[1]=0,a[2]=0,a[3]=1,a},j.clone=function(a){var b=new c(4);return b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=a[3],b},j.copy=function(a,b){return a[0]=b[0],a[1]=b[1],a[2]=b[2],a[3]=b[3],a},j.identity=function(a){return a[0]=1,a[1]=0,a[2]=0,a[3]=1,a},j.transpose=function(a,b){if(a===b){var c=b[1];a[1]=b[2],a[2]=c}else a[0]=b[0],a[1]=b[2],a[2]=b[1],a[3]=b[3];return a},j.invert=function(a,b){var c=b[0],d=b[1],e=b[2],f=b[3],g=c*f-e*d;return g?(g=1/g,a[0]=f*g,a[1]=-d*g,a[2]=-e*g,a[3]=c*g,a):null},j.adjoint=function(a,b){var c=b[0];return a[0]=b[3],a[1]=-b[1],a[2]=-b[2],a[3]=c,a},j.determinant=function(a){return a[0]*a[3]-a[2]*a[1]},j.multiply=function(a,b,c){var d=b[0],e=b[1],f=b[2],g=b[3],h=c[0],i=c[1],j=c[2],k=c[3];return a[0]=d*h+f*i,a[1]=e*h+g*i,a[2]=d*j+f*k,a[3]=e*j+g*k,a},j.mul=j.multiply,j.rotate=function(a,b,c){var d=b[0],e=b[1],f=b[2],g=b[3],h=Math.sin(c),i=Math.cos(c);return a[0]=d*i+f*h,a[1]=e*i+g*h,a[2]=d*-h+f*i,a[3]=e*-h+g*i,a},j.scale=function(a,b,c){var d=b[0],e=b[1],f=b[2],g=b[3],h=c[0],i=c[1];return a[0]=d*h,a[1]=e*h,a[2]=f*i,a[3]=g*i,a},j.str=function(a){return"mat2("+a[0]+", "+a[1]+", "+a[2]+", "+a[3]+")"},j.frob=function(a){return Math.sqrt(Math.pow(a[0],2)+Math.pow(a[1],2)+Math.pow(a[2],2)+Math.pow(a[3],2))},j.LDU=function(a,b,c,d){return a[2]=d[2]/d[0],c[0]=d[0],c[1]=d[1],c[3]=d[3]-a[2]*c[1],[a,b,c]},"undefined"!=typeof a&&(a.mat2=j);var k={};k.create=function(){var a=new c(6);return a[0]=1,a[1]=0,a[2]=0,a[3]=1,a[4]=0,a[5]=0,a},k.clone=function(a){var b=new c(6);return b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=a[3],b[4]=a[4],b[5]=a[5],b},k.copy=function(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},k.identity=function(a){return a[0]=1,a[1]=0,a[2]=0,a[3]=1,a[4]=0,a[5]=0,a},k.invert=function(a,b){var c=b[0],d=b[1],e=b[2],f=b[3],g=b[4],h=b[5],i=c*f-d*e;return i?(i=1/i,a[0]=f*i,a[1]=-d*i,a[2]=-e*i,a[3]=c*i,a[4]=(e*h-f*g)*i,a[5]=(d*g-c*h)*i,a):null},k.determinant=function(a){return a[0]*a[3]-a[1]*a[2]},k.multiply=function(a,b,c){var d=b[0],e=b[1],f=b[2],g=b[3],h=b[4],i=b[5],j=c[0],k=c[1],l=c[2],m=c[3],n=c[4],o=c[5];return a[0]=d*j+f*k,a[1]=e*j+g*k,a[2]=d*l+f*m,a[3]=e*l+g*m,a[4]=d*n+f*o+h,a[5]=e*n+g*o+i,a},k.mul=k.multiply,k.rotate=function(a,b,c){var d=b[0],e=b[1],f=b[2],g=b[3],h=b[4],i=b[5],j=Math.sin(c),k=Math.cos(c);return a[0]=d*k+f*j,a[1]=e*k+g*j,a[2]=d*-j+f*k,a[3]=e*-j+g*k,a[4]=h,a[5]=i,a},k.scale=function(a,b,c){var d=b[0],e=b[1],f=b[2],g=b[3],h=b[4],i=b[5],j=c[0],k=c[1];return a[0]=d*j,a[1]=e*j,a[2]=f*k,a[3]=g*k,a[4]=h,a[5]=i,a},k.translate=function(a,b,c){var d=b[0],e=b[1],f=b[2],g=b[3],h=b[4],i=b[5],j=c[0],k=c[1];return a[0]=d,a[1]=e,a[2]=f,a[3]=g,a[4]=d*j+f*k+h,a[5]=e*j+g*k+i,a},k.str=function(a){return"mat2d("+a[0]+", "+a[1]+", "+a[2]+", "+a[3]+", "+a[4]+", "+a[5]+")"},k.frob=function(a){return Math.sqrt(Math.pow(a[0],2)+Math.pow(a[1],2)+Math.pow(a[2],2)+Math.pow(a[3],2)+Math.pow(a[4],2)+Math.pow(a[5],2)+1)},"undefined"!=typeof a&&(a.mat2d=k);var l={};l.create=function(){var a=new c(9);return a[0]=1,a[1]=0,a[2]=0,a[3]=0,a[4]=1,a[5]=0,a[6]=0,a[7]=0,a[8]=1,a},l.fromMat4=function(a,b){return a[0]=b[0],a[1]=b[1],a[2]=b[2],a[3]=b[4],a[4]=b[5],a[5]=b[6],a[6]=b[8],a[7]=b[9],a[8]=b[10],a},l.clone=function(a){var b=new c(9);return b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=a[3],b[4]=a[4],b[5]=a[5],b[6]=a[6],b[7]=a[7],b[8]=a[8],b},l.copy=function(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},l.identity=function(a){return a[0]=1,a[1]=0,a[2]=0,a[3]=0,a[4]=1,a[5]=0,a[6]=0,a[7]=0,a[8]=1,a},l.transpose=function(a,b){if(a===b){var c=b[1],d=b[2],e=b[5];a[1]=b[3],a[2]=b[6],a[3]=c,a[5]=b[7],a[6]=d,a[7]=e}else a[0]=b[0],a[1]=b[3],a[2]=b[6],a[3]=b[1],a[4]=b[4],a[5]=b[7],a[6]=b[2],a[7]=b[5],a[8]=b[8];return a},l.invert=function(a,b){var c=b[0],d=b[1],e=b[2],f=b[3],g=b[4],h=b[5],i=b[6],j=b[7],k=b[8],l=k*g-h*j,m=-k*f+h*i,n=j*f-g*i,o=c*l+d*m+e*n;return o?(o=1/o,a[0]=l*o,a[1]=(-k*d+e*j)*o,a[2]=(h*d-e*g)*o,a[3]=m*o,a[4]=(k*c-e*i)*o,a[5]=(-h*c+e*f)*o,a[6]=n*o,a[7]=(-j*c+d*i)*o,a[8]=(g*c-d*f)*o,a):null},l.adjoint=function(a,b){var c=b[0],d=b[1],e=b[2],f=b[3],g=b[4],h=b[5],i=b[6],j=b[7],k=b[8];return a[0]=g*k-h*j,a[1]=e*j-d*k,a[2]=d*h-e*g,a[3]=h*i-f*k,a[4]=c*k-e*i,a[5]=e*f-c*h,a[6]=f*j-g*i,a[7]=d*i-c*j,a[8]=c*g-d*f,a},l.determinant=function(a){var b=a[0],c=a[1],d=a[2],e=a[3],f=a[4],g=a[5],h=a[6],i=a[7],j=a[8];return b*(j*f-g*i)+c*(-j*e+g*h)+d*(i*e-f*h)},l.multiply=function(a,b,c){var d=b[0],e=b[1],f=b[2],g=b[3],h=b[4],i=b[5],j=b[6],k=b[7],l=b[8],m=c[0],n=c[1],o=c[2],p=c[3],q=c[4],r=c[5],s=c[6],t=c[7],u=c[8];return a[0]=m*d+n*g+o*j,a[1]=m*e+n*h+o*k,a[2]=m*f+n*i+o*l,a[3]=p*d+q*g+r*j,a[4]=p*e+q*h+r*k,a[5]=p*f+q*i+r*l,a[6]=s*d+t*g+u*j,a[7]=s*e+t*h+u*k,a[8]=s*f+t*i+u*l,a},l.mul=l.multiply,l.translate=function(a,b,c){var d=b[0],e=b[1],f=b[2],g=b[3],h=b[4],i=b[5],j=b[6],k=b[7],l=b[8],m=c[0],n=c[1];return a[0]=d,a[1]=e,a[2]=f,a[3]=g,a[4]=h,a[5]=i,a[6]=m*d+n*g+j,a[7]=m*e+n*h+k,a[8]=m*f+n*i+l,a},l.rotate=function(a,b,c){var d=b[0],e=b[1],f=b[2],g=b[3],h=b[4],i=b[5],j=b[6],k=b[7],l=b[8],m=Math.sin(c),n=Math.cos(c);return a[0]=n*d+m*g,a[1]=n*e+m*h,a[2]=n*f+m*i,a[3]=n*g-m*d,a[4]=n*h-m*e,a[5]=n*i-m*f,a[6]=j,a[7]=k,a[8]=l,a},l.scale=function(a,b,c){var d=c[0],e=c[1];return a[0]=d*b[0],a[1]=d*b[1],a[2]=d*b[2],a[3]=e*b[3],a[4]=e*b[4],a[5]=e*b[5],a[6]=b[6],a[7]=b[7],a[8]=b[8],a},l.fromMat2d=function(a,b){return a[0]=b[0],a[1]=b[1],a[2]=0,a[3]=b[2],a[4]=b[3],a[5]=0,a[6]=b[4],a[7]=b[5],a[8]=1,a},l.fromQuat=function(a,b){var c=b[0],d=b[1],e=b[2],f=b[3],g=c+c,h=d+d,i=e+e,j=c*g,k=d*g,l=d*h,m=e*g,n=e*h,o=e*i,p=f*g,q=f*h,r=f*i;return a[0]=1-l-o,a[3]=k-r,a[6]=m+q,a[1]=k+r,a[4]=1-j-o,a[7]=n-p,a[2]=m-q,a[5]=n+p,a[8]=1-j-l,a},l.normalFromMat4=function(a,b){var c=b[0],d=b[1],e=b[2],f=b[3],g=b[4],h=b[5],i=b[6],j=b[7],k=b[8],l=b[9],m=b[10],n=b[11],o=b[12],p=b[13],q=b[14],r=b[15],s=c*h-d*g,t=c*i-e*g,u=c*j-f*g,v=d*i-e*h,w=d*j-f*h,x=e*j-f*i,y=k*p-l*o,z=k*q-m*o,A=k*r-n*o,B=l*q-m*p,C=l*r-n*p,D=m*r-n*q,E=s*D-t*C+u*B+v*A-w*z+x*y;return E?(E=1/E,a[0]=(h*D-i*C+j*B)*E,a[1]=(i*A-g*D-j*z)*E,a[2]=(g*C-h*A+j*y)*E,a[3]=(e*C-d*D-f*B)*E,a[4]=(c*D-e*A+f*z)*E,a[5]=(d*A-c*C-f*y)*E,a[6]=(p*x-q*w+r*v)*E,a[7]=(q*u-o*x-r*t)*E,a[8]=(o*w-p*u+r*s)*E,a):null},l.str=function(a){return"mat3("+a[0]+", "+a[1]+", "+a[2]+", "+a[3]+", "+a[4]+", "+a[5]+", "+a[6]+", "+a[7]+", "+a[8]+")"},l.frob=function(a){return Math.sqrt(Math.pow(a[0],2)+Math.pow(a[1],2)+Math.pow(a[2],2)+Math.pow(a[3],2)+Math.pow(a[4],2)+Math.pow(a[5],2)+Math.pow(a[6],2)+Math.pow(a[7],2)+Math.pow(a[8],2))},"undefined"!=typeof a&&(a.mat3=l);var m={};m.create=function(){var a=new c(16);return a[0]=1,a[1]=0,a[2]=0,a[3]=0,a[4]=0,a[5]=1,a[6]=0,a[7]=0,a[8]=0,a[9]=0,a[10]=1,a[11]=0,a[12]=0,a[13]=0,a[14]=0,a[15]=1,a},m.clone=function(a){var b=new c(16);return b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=a[3],b[4]=a[4],b[5]=a[5],b[6]=a[6],b[7]=a[7],b[8]=a[8],b[9]=a[9],b[10]=a[10],b[11]=a[11],b[12]=a[12],b[13]=a[13],b[14]=a[14],b[15]=a[15],b},m.copy=function(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],a},m.identity=function(a){return a[0]=1,a[1]=0,a[2]=0,a[3]=0,a[4]=0,a[5]=1,a[6]=0,a[7]=0,a[8]=0,a[9]=0,a[10]=1,a[11]=0,a[12]=0,a[13]=0,a[14]=0,a[15]=1,a},m.transpose=function(a,b){if(a===b){var c=b[1],d=b[2],e=b[3],f=b[6],g=b[7],h=b[11];a[1]=b[4],a[2]=b[8],a[3]=b[12],a[4]=c,a[6]=b[9],a[7]=b[13],a[8]=d,a[9]=f,a[11]=b[14],a[12]=e,a[13]=g,a[14]=h}else a[0]=b[0],a[1]=b[4],a[2]=b[8],a[3]=b[12],a[4]=b[1],a[5]=b[5],a[6]=b[9],a[7]=b[13],a[8]=b[2],a[9]=b[6],a[10]=b[10],a[11]=b[14],a[12]=b[3],a[13]=b[7],a[14]=b[11],a[15]=b[15];return a},m.invert=function(a,b){var c=b[0],d=b[1],e=b[2],f=b[3],g=b[4],h=b[5],i=b[6],j=b[7],k=b[8],l=b[9],m=b[10],n=b[11],o=b[12],p=b[13],q=b[14],r=b[15],s=c*h-d*g,t=c*i-e*g,u=c*j-f*g,v=d*i-e*h,w=d*j-f*h,x=e*j-f*i,y=k*p-l*o,z=k*q-m*o,A=k*r-n*o,B=l*q-m*p,C=l*r-n*p,D=m*r-n*q,E=s*D-t*C+u*B+v*A-w*z+x*y;return E?(E=1/E,a[0]=(h*D-i*C+j*B)*E,a[1]=(e*C-d*D-f*B)*E,a[2]=(p*x-q*w+r*v)*E,a[3]=(m*w-l*x-n*v)*E,a[4]=(i*A-g*D-j*z)*E,a[5]=(c*D-e*A+f*z)*E,a[6]=(q*u-o*x-r*t)*E,a[7]=(k*x-m*u+n*t)*E,a[8]=(g*C-h*A+j*y)*E,a[9]=(d*A-c*C-f*y)*E,a[10]=(o*w-p*u+r*s)*E,a[11]=(l*u-k*w-n*s)*E,a[12]=(h*z-g*B-i*y)*E,a[13]=(c*B-d*z+e*y)*E,a[14]=(p*t-o*v-q*s)*E,a[15]=(k*v-l*t+m*s)*E,a):null},m.adjoint=function(a,b){var c=b[0],d=b[1],e=b[2],f=b[3],g=b[4],h=b[5],i=b[6],j=b[7],k=b[8],l=b[9],m=b[10],n=b[11],o=b[12],p=b[13],q=b[14],r=b[15];return a[0]=h*(m*r-n*q)-l*(i*r-j*q)+p*(i*n-j*m),a[1]=-(d*(m*r-n*q)-l*(e*r-f*q)+p*(e*n-f*m)),a[2]=d*(i*r-j*q)-h*(e*r-f*q)+p*(e*j-f*i),a[3]=-(d*(i*n-j*m)-h*(e*n-f*m)+l*(e*j-f*i)),a[4]=-(g*(m*r-n*q)-k*(i*r-j*q)+o*(i*n-j*m)),a[5]=c*(m*r-n*q)-k*(e*r-f*q)+o*(e*n-f*m),a[6]=-(c*(i*r-j*q)-g*(e*r-f*q)+o*(e*j-f*i)),a[7]=c*(i*n-j*m)-g*(e*n-f*m)+k*(e*j-f*i),a[8]=g*(l*r-n*p)-k*(h*r-j*p)+o*(h*n-j*l),a[9]=-(c*(l*r-n*p)-k*(d*r-f*p)+o*(d*n-f*l)),a[10]=c*(h*r-j*p)-g*(d*r-f*p)+o*(d*j-f*h),a[11]=-(c*(h*n-j*l)-g*(d*n-f*l)+k*(d*j-f*h)),a[12]=-(g*(l*q-m*p)-k*(h*q-i*p)+o*(h*m-i*l)),a[13]=c*(l*q-m*p)-k*(d*q-e*p)+o*(d*m-e*l),a[14]=-(c*(h*q-i*p)-g*(d*q-e*p)+o*(d*i-e*h)),a[15]=c*(h*m-i*l)-g*(d*m-e*l)+k*(d*i-e*h),a},m.determinant=function(a){var b=a[0],c=a[1],d=a[2],e=a[3],f=a[4],g=a[5],h=a[6],i=a[7],j=a[8],k=a[9],l=a[10],m=a[11],n=a[12],o=a[13],p=a[14],q=a[15],r=b*g-c*f,s=b*h-d*f,t=b*i-e*f,u=c*h-d*g,v=c*i-e*g,w=d*i-e*h,x=j*o-k*n,y=j*p-l*n,z=j*q-m*n,A=k*p-l*o,B=k*q-m*o,C=l*q-m*p;return r*C-s*B+t*A+u*z-v*y+w*x},m.multiply=function(a,b,c){var d=b[0],e=b[1],f=b[2],g=b[3],h=b[4],i=b[5],j=b[6],k=b[7],l=b[8],m=b[9],n=b[10],o=b[11],p=b[12],q=b[13],r=b[14],s=b[15],t=c[0],u=c[1],v=c[2],w=c[3];return a[0]=t*d+u*h+v*l+w*p,a[1]=t*e+u*i+v*m+w*q,a[2]=t*f+u*j+v*n+w*r,a[3]=t*g+u*k+v*o+w*s,t=c[4],u=c[5],v=c[6],w=c[7],a[4]=t*d+u*h+v*l+w*p,a[5]=t*e+u*i+v*m+w*q,a[6]=t*f+u*j+v*n+w*r,a[7]=t*g+u*k+v*o+w*s,t=c[8],u=c[9],v=c[10],w=c[11],a[8]=t*d+u*h+v*l+w*p,a[9]=t*e+u*i+v*m+w*q,a[10]=t*f+u*j+v*n+w*r,a[11]=t*g+u*k+v*o+w*s,t=c[12],u=c[13],v=c[14],w=c[15],a[12]=t*d+u*h+v*l+w*p,a[13]=t*e+u*i+v*m+w*q,a[14]=t*f+u*j+v*n+w*r,a[15]=t*g+u*k+v*o+w*s,a},m.mul=m.multiply,m.translate=function(a,b,c){var d,e,f,g,h,i,j,k,l,m,n,o,p=c[0],q=c[1],r=c[2];return b===a?(a[12]=b[0]*p+b[4]*q+b[8]*r+b[12],a[13]=b[1]*p+b[5]*q+b[9]*r+b[13],a[14]=b[2]*p+b[6]*q+b[10]*r+b[14],a[15]=b[3]*p+b[7]*q+b[11]*r+b[15]):(d=b[0],e=b[1],f=b[2],g=b[3],h=b[4],i=b[5],j=b[6],k=b[7],l=b[8],m=b[9],n=b[10],o=b[11],a[0]=d,a[1]=e,a[2]=f,a[3]=g,a[4]=h,a[5]=i,a[6]=j,a[7]=k,a[8]=l,a[9]=m,a[10]=n,a[11]=o,a[12]=d*p+h*q+l*r+b[12],a[13]=e*p+i*q+m*r+b[13],a[14]=f*p+j*q+n*r+b[14],a[15]=g*p+k*q+o*r+b[15]),a},m.scale=function(a,b,c){var d=c[0],e=c[1],f=c[2];return a[0]=b[0]*d,a[1]=b[1]*d,a[2]=b[2]*d,a[3]=b[3]*d,a[4]=b[4]*e,a[5]=b[5]*e,a[6]=b[6]*e,a[7]=b[7]*e,a[8]=b[8]*f,a[9]=b[9]*f,a[10]=b[10]*f,a[11]=b[11]*f,a[12]=b[12],a[13]=b[13],a[14]=b[14],a[15]=b[15],a},m.rotate=function(a,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D=e[0],E=e[1],F=e[2],G=Math.sqrt(D*D+E*E+F*F);return Math.abs(G)g?(h.cross(a,b,e),h.length(a)<1e-6&&h.cross(a,c,e),h.normalize(a,a),n.setAxisAngle(d,a,Math.PI),d):g>.999999?(d[0]=0,d[1]=0,d[2]=0,d[3]=1,d):(h.cross(a,e,f),d[0]=a[0],d[1]=a[1],d[2]=a[2],d[3]=1+g,n.normalize(d,d))}}(),n.setAxes=function(){var a=l.create();return function(b,c,d,e){return a[0]=d[0],a[3]=d[1],a[6]=d[2],a[1]=e[0],a[4]=e[1],a[7]=e[2],a[2]=-c[0],a[5]=-c[1],a[8]=-c[2],n.normalize(b,n.fromMat3(b,a))
-}}(),n.clone=i.clone,n.fromValues=i.fromValues,n.copy=i.copy,n.set=i.set,n.identity=function(a){return a[0]=0,a[1]=0,a[2]=0,a[3]=1,a},n.setAxisAngle=function(a,b,c){c=.5*c;var d=Math.sin(c);return a[0]=d*b[0],a[1]=d*b[1],a[2]=d*b[2],a[3]=Math.cos(c),a},n.add=i.add,n.multiply=function(a,b,c){var d=b[0],e=b[1],f=b[2],g=b[3],h=c[0],i=c[1],j=c[2],k=c[3];return a[0]=d*k+g*h+e*j-f*i,a[1]=e*k+g*i+f*h-d*j,a[2]=f*k+g*j+d*i-e*h,a[3]=g*k-d*h-e*i-f*j,a},n.mul=n.multiply,n.scale=i.scale,n.rotateX=function(a,b,c){c*=.5;var d=b[0],e=b[1],f=b[2],g=b[3],h=Math.sin(c),i=Math.cos(c);return a[0]=d*i+g*h,a[1]=e*i+f*h,a[2]=f*i-e*h,a[3]=g*i-d*h,a},n.rotateY=function(a,b,c){c*=.5;var d=b[0],e=b[1],f=b[2],g=b[3],h=Math.sin(c),i=Math.cos(c);return a[0]=d*i-f*h,a[1]=e*i+g*h,a[2]=f*i+d*h,a[3]=g*i-e*h,a},n.rotateZ=function(a,b,c){c*=.5;var d=b[0],e=b[1],f=b[2],g=b[3],h=Math.sin(c),i=Math.cos(c);return a[0]=d*i+e*h,a[1]=e*i-d*h,a[2]=f*i+g*h,a[3]=g*i-f*h,a},n.calculateW=function(a,b){var c=b[0],d=b[1],e=b[2];return a[0]=c,a[1]=d,a[2]=e,a[3]=-Math.sqrt(Math.abs(1-c*c-d*d-e*e)),a},n.dot=i.dot,n.lerp=i.lerp,n.slerp=function(a,b,c,d){var e,f,g,h,i,j=b[0],k=b[1],l=b[2],m=b[3],n=c[0],o=c[1],p=c[2],q=c[3];return f=j*n+k*o+l*p+m*q,0>f&&(f=-f,n=-n,o=-o,p=-p,q=-q),1-f>1e-6?(e=Math.acos(f),g=Math.sin(e),h=Math.sin((1-d)*e)/g,i=Math.sin(d*e)/g):(h=1-d,i=d),a[0]=h*j+i*n,a[1]=h*k+i*o,a[2]=h*l+i*p,a[3]=h*m+i*q,a},n.invert=function(a,b){var c=b[0],d=b[1],e=b[2],f=b[3],g=c*c+d*d+e*e+f*f,h=g?1/g:0;return a[0]=-c*h,a[1]=-d*h,a[2]=-e*h,a[3]=f*h,a},n.conjugate=function(a,b){return a[0]=-b[0],a[1]=-b[1],a[2]=-b[2],a[3]=b[3],a},n.length=i.length,n.len=n.length,n.squaredLength=i.squaredLength,n.sqrLen=n.squaredLength,n.normalize=i.normalize,n.fromMat3=function(a,b){var c,d=b[0]+b[4]+b[8];if(d>0)c=Math.sqrt(d+1),a[3]=.5*c,c=.5/c,a[0]=(b[7]-b[5])*c,a[1]=(b[2]-b[6])*c,a[2]=(b[3]-b[1])*c;else{var e=0;b[4]>b[0]&&(e=1),b[8]>b[3*e+e]&&(e=2);var f=(e+1)%3,g=(e+2)%3;c=Math.sqrt(b[3*e+e]-b[3*f+f]-b[3*g+g]+1),a[e]=.5*c,c=.5/c,a[3]=(b[3*g+f]-b[3*f+g])*c,a[f]=(b[3*f+e]+b[3*e+f])*c,a[g]=(b[3*g+e]+b[3*e+g])*c}return a},n.str=function(a){return"quat("+a[0]+", "+a[1]+", "+a[2]+", "+a[3]+")"},"undefined"!=typeof a&&(a.quat=n)}(b.exports)}(this)},{}],24:[function(a,b,c){(function(){var a=this,d=a._,e={},f=Array.prototype,g=Object.prototype,h=Function.prototype,i=f.push,j=f.slice,k=f.concat,l=g.toString,m=g.hasOwnProperty,n=f.forEach,o=f.map,p=f.reduce,q=f.reduceRight,r=f.filter,s=f.every,t=f.some,u=f.indexOf,v=f.lastIndexOf,w=Array.isArray,x=Object.keys,y=h.bind,z=function(a){return a instanceof z?a:this instanceof z?void(this._wrapped=a):new z(a)};"undefined"!=typeof c?("undefined"!=typeof b&&b.exports&&(c=b.exports=z),c._=z):a._=z,z.VERSION="1.4.4";var A=z.each=z.forEach=function(a,b,c){if(null!=a)if(n&&a.forEach===n)a.forEach(b,c);else if(a.length===+a.length){for(var d=0,f=a.length;f>d;d++)if(b.call(c,a[d],d,a)===e)return}else for(var g in a)if(z.has(a,g)&&b.call(c,a[g],g,a)===e)return};z.map=z.collect=function(a,b,c){var d=[];return null==a?d:o&&a.map===o?a.map(b,c):(A(a,function(a,e,f){d[d.length]=b.call(c,a,e,f)}),d)};var B="Reduce of empty array with no initial value";z.reduce=z.foldl=z.inject=function(a,b,c,d){var e=arguments.length>2;if(null==a&&(a=[]),p&&a.reduce===p)return d&&(b=z.bind(b,d)),e?a.reduce(b,c):a.reduce(b);if(A(a,function(a,f,g){e?c=b.call(d,c,a,f,g):(c=a,e=!0)}),!e)throw new TypeError(B);return c},z.reduceRight=z.foldr=function(a,b,c,d){var e=arguments.length>2;if(null==a&&(a=[]),q&&a.reduceRight===q)return d&&(b=z.bind(b,d)),e?a.reduceRight(b,c):a.reduceRight(b);var f=a.length;if(f!==+f){var g=z.keys(a);f=g.length}if(A(a,function(h,i,j){i=g?g[--f]:--f,e?c=b.call(d,c,a[i],i,j):(c=a[i],e=!0)}),!e)throw new TypeError(B);return c},z.find=z.detect=function(a,b,c){var d;return C(a,function(a,e,f){return b.call(c,a,e,f)?(d=a,!0):void 0}),d},z.filter=z.select=function(a,b,c){var d=[];return null==a?d:r&&a.filter===r?a.filter(b,c):(A(a,function(a,e,f){b.call(c,a,e,f)&&(d[d.length]=a)}),d)},z.reject=function(a,b,c){return z.filter(a,function(a,d,e){return!b.call(c,a,d,e)},c)},z.every=z.all=function(a,b,c){b||(b=z.identity);var d=!0;return null==a?d:s&&a.every===s?a.every(b,c):(A(a,function(a,f,g){return(d=d&&b.call(c,a,f,g))?void 0:e}),!!d)};var C=z.some=z.any=function(a,b,c){b||(b=z.identity);var d=!1;return null==a?d:t&&a.some===t?a.some(b,c):(A(a,function(a,f,g){return d||(d=b.call(c,a,f,g))?e:void 0}),!!d)};z.contains=z.include=function(a,b){return null==a?!1:u&&a.indexOf===u?-1!=a.indexOf(b):C(a,function(a){return a===b})},z.invoke=function(a,b){var c=j.call(arguments,2),d=z.isFunction(b);return z.map(a,function(a){return(d?b:a[b]).apply(a,c)})},z.pluck=function(a,b){return z.map(a,function(a){return a[b]})},z.where=function(a,b,c){return z.isEmpty(b)?c?null:[]:z[c?"find":"filter"](a,function(a){for(var c in b)if(b[c]!==a[c])return!1;return!0})},z.findWhere=function(a,b){return z.where(a,b,!0)},z.max=function(a,b,c){if(!b&&z.isArray(a)&&a[0]===+a[0]&&a.length<65535)return Math.max.apply(Math,a);if(!b&&z.isEmpty(a))return-1/0;var d={computed:-1/0,value:-1/0};return A(a,function(a,e,f){var g=b?b.call(c,a,e,f):a;g>=d.computed&&(d={value:a,computed:g})}),d.value},z.min=function(a,b,c){if(!b&&z.isArray(a)&&a[0]===+a[0]&&a.length<65535)return Math.min.apply(Math,a);if(!b&&z.isEmpty(a))return 1/0;var d={computed:1/0,value:1/0};return A(a,function(a,e,f){var g=b?b.call(c,a,e,f):a;gd||void 0===c)return 1;if(d>c||void 0===d)return-1}return a.indexf;){var h=f+g>>>1;c.call(d,a[h])=0})})},z.difference=function(a){var b=k.apply(f,j.call(arguments,1));return z.filter(a,function(a){return!z.contains(b,a)})},z.zip=function(){for(var a=j.call(arguments),b=z.max(z.pluck(a,"length")),c=new Array(b),d=0;b>d;d++)c[d]=z.pluck(a,""+d);return c},z.object=function(a,b){if(null==a)return{};for(var c={},d=0,e=a.length;e>d;d++)b?c[a[d]]=b[d]:c[a[d][0]]=a[d][1];return c},z.indexOf=function(a,b,c){if(null==a)return-1;var d=0,e=a.length;if(c){if("number"!=typeof c)return d=z.sortedIndex(a,b),a[d]===b?d:-1;d=0>c?Math.max(0,e+c):c}if(u&&a.indexOf===u)return a.indexOf(b,c);for(;e>d;d++)if(a[d]===b)return d;return-1},z.lastIndexOf=function(a,b,c){if(null==a)return-1;var d=null!=c;if(v&&a.lastIndexOf===v)return d?a.lastIndexOf(b,c):a.lastIndexOf(b);for(var e=d?c:a.length;e--;)if(a[e]===b)return e;return-1},z.range=function(a,b,c){arguments.length<=1&&(b=a||0,a=0),c=arguments[2]||1;for(var d=Math.max(Math.ceil((b-a)/c),0),e=0,f=new Array(d);d>e;)f[e++]=a,a+=c;return f},z.bind=function(a,b){if(a.bind===y&&y)return y.apply(a,j.call(arguments,1));var c=j.call(arguments,2);return function(){return a.apply(b,c.concat(j.call(arguments)))}},z.partial=function(a){var b=j.call(arguments,1);return function(){return a.apply(this,b.concat(j.call(arguments)))}},z.bindAll=function(a){var b=j.call(arguments,1);return 0===b.length&&(b=z.functions(a)),A(b,function(b){a[b]=z.bind(a[b],a)}),a},z.memoize=function(a,b){var c={};return b||(b=z.identity),function(){var d=b.apply(this,arguments);return z.has(c,d)?c[d]:c[d]=a.apply(this,arguments)}},z.delay=function(a,b){var c=j.call(arguments,2);return setTimeout(function(){return a.apply(null,c)},b)},z.defer=function(a){return z.delay.apply(z,[a,1].concat(j.call(arguments,1)))},z.throttle=function(a,b){var c,d,e,f,g=0,h=function(){g=new Date,e=null,f=a.apply(c,d)};return function(){var i=new Date,j=b-(i-g);return c=this,d=arguments,0>=j?(clearTimeout(e),e=null,g=i,f=a.apply(c,d)):e||(e=setTimeout(h,j)),f}},z.debounce=function(a,b,c){var d,e;return function(){var f=this,g=arguments,h=function(){d=null,c||(e=a.apply(f,g))},i=c&&!d;return clearTimeout(d),d=setTimeout(h,b),i&&(e=a.apply(f,g)),e}},z.once=function(a){var b,c=!1;return function(){return c?b:(c=!0,b=a.apply(this,arguments),a=null,b)}},z.wrap=function(a,b){return function(){var c=[a];return i.apply(c,arguments),b.apply(this,c)}},z.compose=function(){var a=arguments;return function(){for(var b=arguments,c=a.length-1;c>=0;c--)b=[a[c].apply(this,b)];return b[0]}},z.after=function(a,b){return 0>=a?b():function(){return--a<1?b.apply(this,arguments):void 0}},z.keys=x||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var b=[];for(var c in a)z.has(a,c)&&(b[b.length]=c);return b},z.values=function(a){var b=[];for(var c in a)z.has(a,c)&&b.push(a[c]);return b},z.pairs=function(a){var b=[];for(var c in a)z.has(a,c)&&b.push([c,a[c]]);return b},z.invert=function(a){var b={};for(var c in a)z.has(a,c)&&(b[a[c]]=c);return b},z.functions=z.methods=function(a){var b=[];for(var c in a)z.isFunction(a[c])&&b.push(c);return b.sort()},z.extend=function(a){return A(j.call(arguments,1),function(b){if(b)for(var c in b)a[c]=b[c]}),a},z.pick=function(a){var b={},c=k.apply(f,j.call(arguments,1));return A(c,function(c){c in a&&(b[c]=a[c])}),b},z.omit=function(a){var b={},c=k.apply(f,j.call(arguments,1));for(var d in a)z.contains(c,d)||(b[d]=a[d]);return b},z.defaults=function(a){return A(j.call(arguments,1),function(b){if(b)for(var c in b)null==a[c]&&(a[c]=b[c])}),a},z.clone=function(a){return z.isObject(a)?z.isArray(a)?a.slice():z.extend({},a):a},z.tap=function(a,b){return b(a),a};var G=function(a,b,c,d){if(a===b)return 0!==a||1/a==1/b;if(null==a||null==b)return a===b;a instanceof z&&(a=a._wrapped),b instanceof z&&(b=b._wrapped);var e=l.call(a);if(e!=l.call(b))return!1;switch(e){case"[object String]":return a==String(b);case"[object Number]":return a!=+a?b!=+b:0==a?1/a==1/b:a==+b;case"[object Date]":case"[object Boolean]":return+a==+b;case"[object RegExp]":return a.source==b.source&&a.global==b.global&&a.multiline==b.multiline&&a.ignoreCase==b.ignoreCase}if("object"!=typeof a||"object"!=typeof b)return!1;for(var f=c.length;f--;)if(c[f]==a)return d[f]==b;c.push(a),d.push(b);var g=0,h=!0;if("[object Array]"==e){if(g=a.length,h=g==b.length)for(;g--&&(h=G(a[g],b[g],c,d)););}else{var i=a.constructor,j=b.constructor;if(i!==j&&!(z.isFunction(i)&&i instanceof i&&z.isFunction(j)&&j instanceof j))return!1;for(var k in a)if(z.has(a,k)&&(g++,!(h=z.has(b,k)&&G(a[k],b[k],c,d))))break;if(h){for(k in b)if(z.has(b,k)&&!g--)break;h=!g}}return c.pop(),d.pop(),h};z.isEqual=function(a,b){return G(a,b,[],[])},z.isEmpty=function(a){if(null==a)return!0;if(z.isArray(a)||z.isString(a))return 0===a.length;for(var b in a)if(z.has(a,b))return!1;return!0},z.isElement=function(a){return!(!a||1!==a.nodeType)},z.isArray=w||function(a){return"[object Array]"==l.call(a)},z.isObject=function(a){return a===Object(a)},A(["Arguments","Function","String","Number","Date","RegExp"],function(a){z["is"+a]=function(b){return l.call(b)=="[object "+a+"]"}}),z.isArguments(arguments)||(z.isArguments=function(a){return!(!a||!z.has(a,"callee"))}),"function"!=typeof/./&&(z.isFunction=function(a){return"function"==typeof a}),z.isFinite=function(a){return isFinite(a)&&!isNaN(parseFloat(a))},z.isNaN=function(a){return z.isNumber(a)&&a!=+a},z.isBoolean=function(a){return a===!0||a===!1||"[object Boolean]"==l.call(a)},z.isNull=function(a){return null===a},z.isUndefined=function(a){return void 0===a},z.has=function(a,b){return m.call(a,b)},z.noConflict=function(){return a._=d,this},z.identity=function(a){return a},z.times=function(a,b,c){for(var d=Array(a),e=0;a>e;e++)d[e]=b.call(c,e);return d},z.random=function(a,b){return null==b&&(b=a,a=0),a+Math.floor(Math.random()*(b-a+1))};var H={escape:{"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"}};H.unescape=z.invert(H.escape);var I={escape:new RegExp("["+z.keys(H.escape).join("")+"]","g"),unescape:new RegExp("("+z.keys(H.unescape).join("|")+")","g")};z.each(["escape","unescape"],function(a){z[a]=function(b){return null==b?"":(""+b).replace(I[a],function(b){return H[a][b]})}}),z.result=function(a,b){if(null==a)return null;var c=a[b];return z.isFunction(c)?c.call(a):c},z.mixin=function(a){A(z.functions(a),function(b){var c=z[b]=a[b];z.prototype[b]=function(){var a=[this._wrapped];return i.apply(a,arguments),N.call(this,c.apply(z,a))}})};var J=0;z.uniqueId=function(a){var b=++J+"";return a?a+b:b},z.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var K=/(.)^/,L={"'":"'","\\":"\\","\r":"r","\n":"n"," ":"t","\u2028":"u2028","\u2029":"u2029"},M=/\\|'|\r|\n|\t|\u2028|\u2029/g;z.template=function(a,b,c){var d;c=z.defaults({},c,z.templateSettings);var e=new RegExp([(c.escape||K).source,(c.interpolate||K).source,(c.evaluate||K).source].join("|")+"|$","g"),f=0,g="__p+='";a.replace(e,function(b,c,d,e,h){return g+=a.slice(f,h).replace(M,function(a){return"\\"+L[a]}),c&&(g+="'+\n((__t=("+c+"))==null?'':_.escape(__t))+\n'"),d&&(g+="'+\n((__t=("+d+"))==null?'':__t)+\n'"),e&&(g+="';\n"+e+"\n__p+='"),f=h+b.length,b}),g+="';\n",c.variable||(g="with(obj||{}){\n"+g+"}\n"),g="var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\n"+g+"return __p;\n";try{d=new Function(c.variable||"obj","_",g)}catch(h){throw h.source=g,h}if(b)return d(b,z);var i=function(a){return d.call(this,a,z)};return i.source="function("+(c.variable||"obj")+"){\n"+g+"}",i},z.chain=function(a){return z(a).chain()};var N=function(a){return this._chain?z(a).chain():a};z.mixin(z),A(["pop","push","reverse","shift","sort","splice","unshift"],function(a){var b=f[a];z.prototype[a]=function(){var c=this._wrapped;return b.apply(c,arguments),"shift"!=a&&"splice"!=a||0!==c.length||delete c[0],N.call(this,c)}}),A(["concat","join","slice"],function(a){var b=f[a];z.prototype[a]=function(){return N.call(this,b.apply(this._wrapped,arguments))}}),z.extend(z.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}).call(this)},{}],25:[function(a){"undefined"!=typeof window&&"function"!=typeof window.requestAnimationFrame&&(window.requestAnimationFrame=window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(a){setTimeout(a,1e3/60)}),Leap=a("../lib/index")},{"../lib/index":11}]},{},[25]);
\ No newline at end of file
diff --git a/leap-1.0.0.js b/leap-1.0.0.js
new file mode 100644
index 00000000..126cc1ed
--- /dev/null
+++ b/leap-1.0.0.js
@@ -0,0 +1,14138 @@
+/*!
+ * LeapJS v1.0.0
+ * http://github.com/leapmotion/leapjs/
+ *
+ * Copyright 2013 LeapMotion, Inc. and other contributors
+ * Released under the Apache-2.0 license
+ * http://github.com/leapmotion/leapjs/blob/master/LICENSE
+ */
+(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= this.size) return undefined;
+ if (i >= this._buf.length) return undefined;
+ return this._buf[(this.pos - i - 1) % this.size];
+}
+
+CircularBuffer.prototype.push = function(o) {
+ this._buf[this.pos % this.size] = o;
+ return this.pos++;
+}
+
+},{}],3:[function(require,module,exports){
+var chooseProtocol = require('../protocol').chooseProtocol
+ , EventEmitter = require('events').EventEmitter
+ , _ = require('underscore');
+
+var BaseConnection = module.exports = function(opts) {
+ this.opts = _.defaults(opts || {}, {
+ host : '127.0.0.1',
+ enableGestures: false,
+ scheme: this.getScheme(),
+ port: this.getPort(),
+ background: false,
+ optimizeHMD: false,
+ requestProtocolVersion: BaseConnection.defaultProtocolVersion
+ });
+ this.host = this.opts.host;
+ this.port = this.opts.port;
+ this.scheme = this.opts.scheme;
+ this.protocolVersionVerified = false;
+ this.background = null;
+ this.optimizeHMD = null;
+ this.on('ready', function() {
+ this.enableGestures(this.opts.enableGestures);
+ this.setBackground(this.opts.background);
+ this.setOptimizeHMD(this.opts.optimizeHMD);
+
+ if (this.opts.optimizeHMD){
+ console.log("Optimized for head mounted display usage.");
+ }else {
+ console.log("Optimized for desktop usage.");
+ }
+
+ });
+};
+
+// The latest available:
+BaseConnection.defaultProtocolVersion = 6;
+
+BaseConnection.prototype.getUrl = function() {
+ return this.scheme + "//" + this.host + ":" + this.port + "/v" + this.opts.requestProtocolVersion + ".json";
+}
+
+
+BaseConnection.prototype.getScheme = function(){
+ return 'ws:'
+}
+
+BaseConnection.prototype.getPort = function(){
+ return 6437
+}
+
+
+BaseConnection.prototype.setBackground = function(state) {
+ this.opts.background = state;
+ if (this.protocol && this.protocol.sendBackground && this.background !== this.opts.background) {
+ this.background = this.opts.background;
+ this.protocol.sendBackground(this, this.opts.background);
+ }
+}
+
+BaseConnection.prototype.setOptimizeHMD = function(state) {
+ this.opts.optimizeHMD = state;
+ if (this.protocol && this.protocol.sendOptimizeHMD && this.optimizeHMD !== this.opts.optimizeHMD) {
+ this.optimizeHMD = this.opts.optimizeHMD;
+ this.protocol.sendOptimizeHMD(this, this.opts.optimizeHMD);
+ }
+}
+
+BaseConnection.prototype.handleOpen = function() {
+ if (!this.connected) {
+ this.connected = true;
+ this.emit('connect');
+ }
+}
+
+BaseConnection.prototype.enableGestures = function(enabled) {
+ this.gesturesEnabled = enabled ? true : false;
+ this.send(this.protocol.encode({"enableGestures": this.gesturesEnabled}));
+}
+
+BaseConnection.prototype.handleClose = function(code, reason) {
+ if (!this.connected) return;
+ this.disconnect();
+
+ // 1001 - an active connection is closed
+ // 1006 - cannot connect
+ if (code === 1001 && this.opts.requestProtocolVersion > 1) {
+ if (this.protocolVersionVerified) {
+ this.protocolVersionVerified = false;
+ }else{
+ this.opts.requestProtocolVersion--;
+ }
+ }
+ this.startReconnection();
+}
+
+BaseConnection.prototype.startReconnection = function() {
+ var connection = this;
+ if(!this.reconnectionTimer){
+ (this.reconnectionTimer = setInterval(function() { connection.reconnect() }, 500));
+ }
+}
+
+BaseConnection.prototype.stopReconnection = function() {
+ this.reconnectionTimer = clearInterval(this.reconnectionTimer);
+}
+
+// By default, disconnect will prevent auto-reconnection.
+// Pass in true to allow the reconnection loop not be interrupted continue
+BaseConnection.prototype.disconnect = function(allowReconnect) {
+ if (!allowReconnect) this.stopReconnection();
+ if (!this.socket) return;
+ this.socket.close();
+ delete this.socket;
+ delete this.protocol;
+ delete this.background; // This is not persisted when reconnecting to the web socket server
+ delete this.optimizeHMD;
+ delete this.focusedState;
+ if (this.connected) {
+ this.connected = false;
+ this.emit('disconnect');
+ }
+ return true;
+}
+
+BaseConnection.prototype.reconnect = function() {
+ if (this.connected) {
+ this.stopReconnection();
+ } else {
+ this.disconnect(true);
+ this.connect();
+ }
+}
+
+BaseConnection.prototype.handleData = function(data) {
+ var message = JSON.parse(data);
+
+ var messageEvent;
+ if (this.protocol === undefined) {
+ messageEvent = this.protocol = chooseProtocol(message);
+ this.protocolVersionVerified = true;
+ this.emit('ready');
+ } else {
+ messageEvent = this.protocol(message);
+ }
+ this.emit(messageEvent.type, messageEvent);
+}
+
+BaseConnection.prototype.connect = function() {
+ if (this.socket) return;
+ this.socket = this.setupSocket();
+ return true;
+}
+
+BaseConnection.prototype.send = function(data) {
+ this.socket.send(data);
+}
+
+BaseConnection.prototype.reportFocus = function(state) {
+ if (!this.connected || this.focusedState === state) return;
+ this.focusedState = state;
+ this.emit(this.focusedState ? 'focus' : 'blur');
+ if (this.protocol && this.protocol.sendFocused) {
+ this.protocol.sendFocused(this, this.focusedState);
+ }
+}
+
+_.extend(BaseConnection.prototype, EventEmitter.prototype);
+},{"../protocol":16,"events":21,"underscore":34}],4:[function(require,module,exports){
+var BaseConnection = module.exports = require('./base')
+ , _ = require('underscore');
+
+
+var BrowserConnection = module.exports = function(opts) {
+ BaseConnection.call(this, opts);
+ var connection = this;
+ this.on('ready', function() { connection.startFocusLoop(); })
+ this.on('disconnect', function() { connection.stopFocusLoop(); })
+}
+
+_.extend(BrowserConnection.prototype, BaseConnection.prototype);
+
+BrowserConnection.__proto__ = BaseConnection;
+
+BrowserConnection.prototype.useSecure = function(){
+ return location.protocol === 'https:'
+}
+
+BrowserConnection.prototype.getScheme = function(){
+ return this.useSecure() ? 'wss:' : 'ws:'
+}
+
+BrowserConnection.prototype.getPort = function(){
+ return this.useSecure() ? 6436 : 6437
+}
+
+BrowserConnection.prototype.setupSocket = function() {
+ var connection = this;
+ var socket = new WebSocket(this.getUrl());
+ socket.onopen = function() { connection.handleOpen(); };
+ socket.onclose = function(data) { connection.handleClose(data['code'], data['reason']); };
+ socket.onmessage = function(message) { connection.handleData(message.data) };
+ socket.onerror = function(error) {
+
+ // attempt to degrade to ws: after one failed attempt for older Leap Service installations.
+ if (!connection.useSecure() && connection.scheme === 'wss:'){
+ connection.scheme = 'ws:';
+ connection.port = 6437;
+ connection.disconnect();
+ connection.connect();
+ }
+
+ };
+ return socket;
+}
+
+BrowserConnection.prototype.startFocusLoop = function() {
+ if (this.focusDetectorTimer) return;
+ var connection = this;
+ var propertyName = null;
+ if (typeof document.hidden !== "undefined") {
+ propertyName = "hidden";
+ } else if (typeof document.mozHidden !== "undefined") {
+ propertyName = "mozHidden";
+ } else if (typeof document.msHidden !== "undefined") {
+ propertyName = "msHidden";
+ } else if (typeof document.webkitHidden !== "undefined") {
+ propertyName = "webkitHidden";
+ } else {
+ propertyName = undefined;
+ }
+
+ if (connection.windowVisible === undefined) {
+ connection.windowVisible = propertyName === undefined ? true : document[propertyName] === false;
+ }
+
+ var focusListener = window.addEventListener('focus', function(e) {
+ connection.windowVisible = true;
+ updateFocusState();
+ });
+
+ var blurListener = window.addEventListener('blur', function(e) {
+ connection.windowVisible = false;
+ updateFocusState();
+ });
+
+ this.on('disconnect', function() {
+ window.removeEventListener('focus', focusListener);
+ window.removeEventListener('blur', blurListener);
+ });
+
+ var updateFocusState = function() {
+ var isVisible = propertyName === undefined ? true : document[propertyName] === false;
+ connection.reportFocus(isVisible && connection.windowVisible);
+ }
+
+ // save 100ms when resuming focus
+ updateFocusState();
+
+ this.focusDetectorTimer = setInterval(updateFocusState, 100);
+}
+
+BrowserConnection.prototype.stopFocusLoop = function() {
+ if (!this.focusDetectorTimer) return;
+ clearTimeout(this.focusDetectorTimer);
+ delete this.focusDetectorTimer;
+}
+
+},{"./base":3,"underscore":34}],5:[function(require,module,exports){
+var WebSocket = require('ws')
+ , BaseConnection = require('./base')
+ , _ = require('underscore');
+
+var NodeConnection = module.exports = function(opts) {
+ BaseConnection.call(this, opts);
+ var connection = this;
+ this.on('ready', function() { connection.reportFocus(true); });
+}
+
+_.extend(NodeConnection.prototype, BaseConnection.prototype);
+
+NodeConnection.__proto__ = BaseConnection;
+
+NodeConnection.prototype.setupSocket = function() {
+ var connection = this;
+ var socket = new WebSocket(this.getUrl());
+ socket.on('open', function() { connection.handleOpen(); });
+ socket.on('message', function(m) { connection.handleData(m); });
+ socket.on('close', function(code, reason) { connection.handleClose(code, reason); });
+ socket.on('error', function() { connection.startReconnection(); });
+ return socket;
+}
+
+},{"./base":3,"underscore":34,"ws":35}],6:[function(require,module,exports){
+(function (process){
+var Frame = require('./frame')
+ , Hand = require('./hand')
+ , Pointable = require('./pointable')
+ , Finger = require('./finger')
+ , CircularBuffer = require("./circular_buffer")
+ , Pipeline = require("./pipeline")
+ , EventEmitter = require('events').EventEmitter
+ , gestureListener = require('./gesture').gestureListener
+ , Dialog = require('./dialog')
+ , _ = require('underscore');
+
+/**
+ * Constructs a Controller object.
+ *
+ * When creating a Controller object, you may optionally pass in options
+ * to set the host , set the port, enable gestures, or select the frame event type.
+ *
+ * ```javascript
+ * var controller = new Leap.Controller({
+ * host: '127.0.0.1',
+ * port: 6437,
+ * enableGestures: true,
+ * frameEventName: 'animationFrame'
+ * });
+ * ```
+ *
+ * @class Controller
+ * @memberof Leap
+ * @classdesc
+ * The Controller class is your main interface to the Leap Motion Controller.
+ *
+ * Create an instance of this Controller class to access frames of tracking data
+ * and configuration information. Frame data can be polled at any time using the
+ * [Controller.frame]{@link Leap.Controller#frame}() function. Call frame() or frame(0) to get the most recent
+ * frame. Set the history parameter to a positive integer to access previous frames.
+ * A controller stores up to 60 frames in its frame history.
+ *
+ * Polling is an appropriate strategy for applications which already have an
+ * intrinsic update loop, such as a game.
+ *
+ * loopWhileDisconnected defaults to true, and maintains a 60FPS frame rate even when Leap Motion is not streaming
+ * data at that rate (such as no hands in frame). This is important for VR/WebGL apps which rely on rendering for
+ * regular visual updates, including from other input devices. Flipping this to false should be considered an
+ * optimization for very specific use-cases.
+ *
+ *
+ */
+
+
+var Controller = module.exports = function(opts) {
+ var inNode = (typeof(process) !== 'undefined' && process.versions && process.versions.node),
+ controller = this;
+
+ opts = _.defaults(opts || {}, {
+ inNode: inNode
+ });
+
+ this.inNode = opts.inNode;
+
+ opts = _.defaults(opts || {}, {
+ frameEventName: this.useAnimationLoop() ? 'animationFrame' : 'deviceFrame',
+ suppressAnimationLoop: !this.useAnimationLoop(),
+ loopWhileDisconnected: true,
+ useAllPlugins: false,
+ checkVersion: true
+ });
+
+ this.animationFrameRequested = false;
+ this.onAnimationFrame = function(timestamp) {
+ if (controller.lastConnectionFrame.valid){
+ controller.emit('animationFrame', controller.lastConnectionFrame);
+ }
+ controller.emit('frameEnd', timestamp);
+ if (
+ controller.loopWhileDisconnected &&
+ ( ( controller.connection.focusedState !== false ) // loop while undefined, pre-ready.
+ || controller.connection.opts.background) ){
+ window.requestAnimationFrame(controller.onAnimationFrame);
+ }else{
+ controller.animationFrameRequested = false;
+ }
+ };
+ this.suppressAnimationLoop = opts.suppressAnimationLoop;
+ this.loopWhileDisconnected = opts.loopWhileDisconnected;
+ this.frameEventName = opts.frameEventName;
+ this.useAllPlugins = opts.useAllPlugins;
+ this.history = new CircularBuffer(200);
+ this.lastFrame = Frame.Invalid;
+ this.lastValidFrame = Frame.Invalid;
+ this.lastConnectionFrame = Frame.Invalid;
+ this.accumulatedGestures = [];
+ this.checkVersion = opts.checkVersion;
+ if (opts.connectionType === undefined) {
+ this.connectionType = (this.inBrowser() ? require('./connection/browser') : require('./connection/node'));
+ } else {
+ this.connectionType = opts.connectionType;
+ }
+ this.connection = new this.connectionType(opts);
+ this.streamingCount = 0;
+ this.devices = {};
+ this.plugins = {};
+ this._pluginPipelineSteps = {};
+ this._pluginExtendedMethods = {};
+ if (opts.useAllPlugins) this.useRegisteredPlugins();
+ this.setupFrameEvents(opts);
+ this.setupConnectionEvents();
+
+ this.startAnimationLoop(); // immediately when started
+}
+
+Controller.prototype.gesture = function(type, cb) {
+ var creator = gestureListener(this, type);
+ if (cb !== undefined) {
+ creator.stop(cb);
+ }
+ return creator;
+}
+
+/*
+ * @returns the controller
+ */
+Controller.prototype.setBackground = function(state) {
+ this.connection.setBackground(state);
+ return this;
+}
+
+Controller.prototype.setOptimizeHMD = function(state) {
+ this.connection.setOptimizeHMD(state);
+ return this;
+}
+
+Controller.prototype.inBrowser = function() {
+ return !this.inNode;
+}
+
+Controller.prototype.useAnimationLoop = function() {
+ return this.inBrowser() && !this.inBackgroundPage();
+}
+
+Controller.prototype.inBackgroundPage = function(){
+ // http://developer.chrome.com/extensions/extension#method-getBackgroundPage
+ return (typeof(chrome) !== "undefined") &&
+ chrome.extension &&
+ chrome.extension.getBackgroundPage &&
+ (chrome.extension.getBackgroundPage() === window)
+}
+
+/*
+ * @returns the controller
+ */
+Controller.prototype.connect = function() {
+ this.connection.connect();
+ return this;
+}
+
+Controller.prototype.streaming = function() {
+ return this.streamingCount > 0;
+}
+
+Controller.prototype.connected = function() {
+ return !!this.connection.connected;
+}
+
+Controller.prototype.startAnimationLoop = function(){
+ if (!this.suppressAnimationLoop && !this.animationFrameRequested) {
+ this.animationFrameRequested = true;
+ window.requestAnimationFrame(this.onAnimationFrame);
+ }
+}
+
+/*
+ * @returns the controller
+ */
+Controller.prototype.disconnect = function() {
+ this.connection.disconnect();
+ return this;
+}
+
+/**
+ * Returns a frame of tracking data from the Leap.
+ *
+ * Use the optional history parameter to specify which frame to retrieve.
+ * Call frame() or frame(0) to access the most recent frame; call frame(1) to
+ * access the previous frame, and so on. If you use a history value greater
+ * than the number of stored frames, then the controller returns an invalid frame.
+ *
+ * @method frame
+ * @memberof Leap.Controller.prototype
+ * @param {number} history The age of the frame to return, counting backwards from
+ * the most recent frame (0) into the past and up to the maximum age (59).
+ * @returns {Leap.Frame} The specified frame; or, if no history
+ * parameter is specified, the newest frame. If a frame is not available at
+ * the specified history position, an invalid Frame is returned.
+ **/
+Controller.prototype.frame = function(num) {
+ return this.history.get(num) || Frame.Invalid;
+}
+
+Controller.prototype.loop = function(callback) {
+ if (callback) {
+ if (typeof callback === 'function'){
+ this.on(this.frameEventName, callback);
+ }else{
+ // callback is actually of the form: {eventName: callback}
+ this.setupFrameEvents(callback);
+ }
+ }
+
+ return this.connect();
+}
+
+Controller.prototype.addStep = function(step) {
+ if (!this.pipeline) this.pipeline = new Pipeline(this);
+ this.pipeline.addStep(step);
+}
+
+// this is run on every deviceFrame
+Controller.prototype.processFrame = function(frame) {
+ if (frame.gestures) {
+ this.accumulatedGestures = this.accumulatedGestures.concat(frame.gestures);
+ }
+ // lastConnectionFrame is used by the animation loop
+ this.lastConnectionFrame = frame;
+ this.startAnimationLoop(); // Only has effect if loopWhileDisconnected: false
+ this.emit('deviceFrame', frame);
+}
+
+// on a this.deviceEventName (usually 'animationFrame' in browsers), this emits a 'frame'
+Controller.prototype.processFinishedFrame = function(frame) {
+ this.lastFrame = frame;
+ if (frame.valid) {
+ this.lastValidFrame = frame;
+ }
+ frame.controller = this;
+ frame.historyIdx = this.history.push(frame);
+ if (frame.gestures) {
+ frame.gestures = this.accumulatedGestures;
+ this.accumulatedGestures = [];
+ for (var gestureIdx = 0; gestureIdx != frame.gestures.length; gestureIdx++) {
+ this.emit("gesture", frame.gestures[gestureIdx], frame);
+ }
+ }
+ if (this.pipeline) {
+ frame = this.pipeline.run(frame);
+ if (!frame) frame = Frame.Invalid;
+ }
+ this.emit('frame', frame);
+ this.emitHandEvents(frame);
+}
+
+/**
+ * The controller will emit 'hand' events for every hand on each frame. The hand in question will be passed
+ * to the event callback.
+ *
+ * @param frame
+ */
+Controller.prototype.emitHandEvents = function(frame){
+ for (var i = 0; i < frame.hands.length; i++){
+ this.emit('hand', frame.hands[i]);
+ }
+}
+
+Controller.prototype.setupFrameEvents = function(opts){
+ if (opts.frame){
+ this.on('frame', opts.frame);
+ }
+ if (opts.hand){
+ this.on('hand', opts.hand);
+ }
+}
+
+/**
+ Controller events. The old 'deviceConnected' and 'deviceDisconnected' have been depricated -
+ use 'deviceStreaming' and 'deviceStopped' instead, except in the case of an unexpected disconnect.
+
+ There are 4 pairs of device events recently added/changed:
+ -deviceAttached/deviceRemoved - called when a device's physical connection to the computer changes
+ -deviceStreaming/deviceStopped - called when a device is paused or resumed.
+ -streamingStarted/streamingStopped - called when there is/is no longer at least 1 streaming device.
+ Always comes after deviceStreaming.
+
+ The first of all of the above event pairs is triggered as appropriate upon connection. All of
+ these events receives an argument with the most recent info about the device that triggered it.
+ These events will always be fired in the order they are listed here, with reverse ordering for the
+ matching shutdown call. (ie, deviceStreaming always comes after deviceAttached, and deviceStopped
+ will come before deviceRemoved).
+
+ -deviceConnected/deviceDisconnected - These are considered deprecated and will be removed in
+ the next revision. In contrast to the other events and in keeping with it's original behavior,
+ it will only be fired when a device begins streaming AFTER a connection has been established.
+ It is not paired, and receives no device info. Nearly identical functionality to
+ streamingStarted/Stopped if you need to port.
+*/
+Controller.prototype.setupConnectionEvents = function() {
+ var controller = this;
+ this.connection.on('frame', function(frame) {
+ controller.processFrame(frame);
+ });
+ // either deviceFrame or animationFrame:
+ this.on(this.frameEventName, function(frame) {
+ controller.processFinishedFrame(frame);
+ });
+
+
+ // here we backfill the 0.5.0 deviceEvents as best possible
+ // backfill begin streaming events
+ var backfillStreamingStartedEventsHandler = function(){
+ if (controller.connection.opts.requestProtocolVersion < 5 && controller.streamingCount == 0){
+ controller.streamingCount = 1;
+ var info = {
+ attached: true,
+ streaming: true,
+ type: 'unknown',
+ id: "Lx00000000000"
+ };
+ controller.devices[info.id] = info;
+
+ controller.emit('deviceAttached', info);
+ controller.emit('deviceStreaming', info);
+ controller.emit('streamingStarted', info);
+ controller.connection.removeListener('frame', backfillStreamingStartedEventsHandler)
+ }
+ }
+
+ var backfillStreamingStoppedEvents = function(){
+ if (controller.streamingCount > 0) {
+ for (var deviceId in controller.devices){
+ controller.emit('deviceStopped', controller.devices[deviceId]);
+ controller.emit('deviceRemoved', controller.devices[deviceId]);
+ }
+ // only emit streamingStopped once, with the last device
+ controller.emit('streamingStopped', controller.devices[deviceId]);
+
+ controller.streamingCount = 0;
+
+ for (var deviceId in controller.devices){
+ delete controller.devices[deviceId];
+ }
+ }
+ }
+ // Delegate connection events
+ this.connection.on('focus', function() {
+
+ if ( controller.loopWhileDisconnected ){
+
+ controller.startAnimationLoop();
+
+ }
+
+ controller.emit('focus');
+
+ });
+ this.connection.on('blur', function() { controller.emit('blur') });
+ this.connection.on('protocol', function(protocol) {
+
+ protocol.on('beforeFrameCreated', function(frameData){
+ controller.emit('beforeFrameCreated', frameData)
+ });
+
+ protocol.on('afterFrameCreated', function(frame, frameData){
+ controller.emit('afterFrameCreated', frame, frameData)
+ });
+
+ controller.emit('protocol', protocol);
+ });
+
+ this.connection.on('ready', function() {
+
+ if (controller.checkVersion && !controller.inNode){
+ // show dialog only to web users
+ controller.checkOutOfDate();
+ }
+
+ controller.emit('ready');
+ });
+
+ this.connection.on('connect', function() {
+ controller.emit('connect');
+ controller.connection.removeListener('frame', backfillStreamingStartedEventsHandler)
+ controller.connection.on('frame', backfillStreamingStartedEventsHandler);
+ });
+
+ this.connection.on('disconnect', function() {
+ controller.emit('disconnect');
+ backfillStreamingStoppedEvents();
+ });
+
+ // this does not fire when the controller is manually disconnected
+ // or for Leap Service v1.2.0+
+ this.connection.on('deviceConnect', function(evt) {
+ if (evt.state){
+ controller.emit('deviceConnected');
+ controller.connection.removeListener('frame', backfillStreamingStartedEventsHandler)
+ controller.connection.on('frame', backfillStreamingStartedEventsHandler);
+ }else{
+ controller.emit('deviceDisconnected');
+ backfillStreamingStoppedEvents();
+ }
+ });
+
+ // Does not fire for Leap Service pre v1.2.0
+ this.connection.on('deviceEvent', function(evt) {
+ var info = evt.state,
+ oldInfo = controller.devices[info.id];
+
+ //Grab a list of changed properties in the device info
+ var changed = {};
+ for(var property in info) {
+ //If a property i doesn't exist the cache, or has changed...
+ if( !oldInfo || !oldInfo.hasOwnProperty(property) || oldInfo[property] != info[property] ) {
+ changed[property] = true;
+ }
+ }
+
+ //Update the device list
+ controller.devices[info.id] = info;
+
+ //Fire events based on change list
+ if(changed.attached) {
+ controller.emit(info.attached ? 'deviceAttached' : 'deviceRemoved', info);
+ }
+
+ if(!changed.streaming) return;
+
+ if(info.streaming) {
+ controller.streamingCount++;
+ controller.emit('deviceStreaming', info);
+ if( controller.streamingCount == 1 ) {
+ controller.emit('streamingStarted', info);
+ }
+ //if attached & streaming both change to true at the same time, that device was streaming
+ //already when we connected.
+ if(!changed.attached) {
+ controller.emit('deviceConnected');
+ }
+ }
+ //Since when devices are attached all fields have changed, don't send events for streaming being false.
+ else if(!(changed.attached && info.attached)) {
+ controller.streamingCount--;
+ controller.emit('deviceStopped', info);
+ if(controller.streamingCount == 0){
+ controller.emit('streamingStopped', info);
+ }
+ controller.emit('deviceDisconnected');
+ }
+
+ });
+
+
+ this.on('newListener', function(event, listener) {
+ if( event == 'deviceConnected' || event == 'deviceDisconnected' ) {
+ console.warn(event + " events are depricated. Consider using 'streamingStarted/streamingStopped' or 'deviceStreaming/deviceStopped' instead");
+ }
+ });
+
+};
+
+
+
+
+// Checks if the protocol version is the latest, if if not, shows the dialog.
+Controller.prototype.checkOutOfDate = function(){
+ console.assert(this.connection && this.connection.protocol);
+
+ var serviceVersion = this.connection.protocol.serviceVersion;
+ var protocolVersion = this.connection.protocol.version;
+ var defaultProtocolVersion = this.connectionType.defaultProtocolVersion;
+
+ if (defaultProtocolVersion > protocolVersion){
+
+ console.warn("Your Protocol Version is v" + protocolVersion +
+ ", this app was designed for v" + defaultProtocolVersion);
+
+ Dialog.warnOutOfDate({
+ sV: serviceVersion,
+ pV: protocolVersion
+ });
+ return true
+ }else{
+ return false
+ }
+
+};
+
+
+
+Controller._pluginFactories = {};
+
+/*
+ * Registers a plugin, making is accessible to controller.use later on.
+ *
+ * @member plugin
+ * @memberof Leap.Controller.prototype
+ * @param {String} name The name of the plugin (usually camelCase).
+ * @param {function} factory A factory method which will return an instance of a plugin.
+ * The factory receives an optional hash of options, passed in via controller.use.
+ *
+ * Valid keys for the object include frame, hand, finger, tool, and pointable. The value
+ * of each key can be either a function or an object. If given a function, that function
+ * will be called once for every instance of the object, with that instance injected as an
+ * argument. This allows decoration of objects with additional data:
+ *
+ * ```javascript
+ * Leap.Controller.plugin('testPlugin', function(options){
+ * return {
+ * frame: function(frame){
+ * frame.foo = 'bar';
+ * }
+ * }
+ * });
+ * ```
+ *
+ * When hand is used, the callback is called for every hand in `frame.hands`. Note that
+ * hand objects are recreated with every new frame, so that data saved on the hand will not
+ * persist.
+ *
+ * ```javascript
+ * Leap.Controller.plugin('testPlugin', function(){
+ * return {
+ * hand: function(hand){
+ * console.log('testPlugin running on hand ' + hand.id);
+ * }
+ * }
+ * });
+ * ```
+ *
+ * A factory can return an object to add custom functionality to Frames, Hands, or Pointables.
+ * The methods are added directly to the object's prototype. Finger and Tool cannot be used here, Pointable
+ * must be used instead.
+ * This is encouraged for calculations which may not be necessary on every frame.
+ * Memoization is also encouraged, for cases where the method may be called many times per frame by the application.
+ *
+ * ```javascript
+ * // This plugin allows hand.usefulData() to be called later.
+ * Leap.Controller.plugin('testPlugin', function(){
+ * return {
+ * hand: {
+ * usefulData: function(){
+ * console.log('usefulData on hand', this.id);
+ * // memoize the results on to the hand, preventing repeat work:
+ * this.x || this.x = someExpensiveCalculation();
+ * return this.x;
+ * }
+ * }
+ * }
+ * });
+ *
+ * Note that the factory pattern allows encapsulation for every plugin instance.
+ *
+ * ```javascript
+ * Leap.Controller.plugin('testPlugin', function(options){
+ * options || options = {}
+ * options.center || options.center = [0,0,0]
+ *
+ * privatePrintingMethod = function(){
+ * console.log('privatePrintingMethod - options', options);
+ * }
+ *
+ * return {
+ * pointable: {
+ * publicPrintingMethod: function(){
+ * privatePrintingMethod();
+ * }
+ * }
+ * }
+ * });
+ *
+ */
+Controller.plugin = function(pluginName, factory) {
+ if (this._pluginFactories[pluginName]) {
+ console.warn("Plugin \"" + pluginName + "\" already registered");
+ }
+ return this._pluginFactories[pluginName] = factory;
+};
+
+/*
+ * Returns a list of registered plugins.
+ * @returns {Array} Plugin Factories.
+ */
+Controller.plugins = function() {
+ return _.keys(this._pluginFactories);
+};
+
+
+
+var setPluginCallbacks = function(pluginName, type, callback){
+
+ if ( ['beforeFrameCreated', 'afterFrameCreated'].indexOf(type) != -1 ){
+
+ // todo - not able to "unuse" a plugin currently
+ this.on(type, callback);
+
+ }else {
+
+ if (!this.pipeline) this.pipeline = new Pipeline(this);
+
+ if (!this._pluginPipelineSteps[pluginName]) this._pluginPipelineSteps[pluginName] = [];
+
+ this._pluginPipelineSteps[pluginName].push(
+
+ this.pipeline.addWrappedStep(type, callback)
+
+ );
+
+ }
+
+};
+
+var setPluginMethods = function(pluginName, type, hash){
+ var klass;
+
+ if (!this._pluginExtendedMethods[pluginName]) this._pluginExtendedMethods[pluginName] = [];
+
+ switch (type) {
+ case 'frame':
+ klass = Frame;
+ break;
+ case 'hand':
+ klass = Hand;
+ break;
+ case 'pointable':
+ klass = Pointable;
+ _.extend(Finger.prototype, hash);
+ _.extend(Finger.Invalid, hash);
+ break;
+ case 'finger':
+ klass = Finger;
+ break;
+ default:
+ throw pluginName + ' specifies invalid object type "' + type + '" for prototypical extension'
+ }
+
+ _.extend(klass.prototype, hash);
+ _.extend(klass.Invalid, hash);
+ this._pluginExtendedMethods[pluginName].push([klass, hash])
+
+}
+
+
+
+/*
+ * Begin using a registered plugin. The plugin's functionality will be added to all frames
+ * returned by the controller (and/or added to the objects within the frame).
+ * - The order of plugin execution inside the loop will match the order in which use is called by the application.
+ * - The plugin be run for both deviceFrames and animationFrames.
+ *
+ * If called a second time, the options will be merged with those of the already instantiated plugin.
+ *
+ * @method use
+ * @memberOf Leap.Controller.prototype
+ * @param pluginName
+ * @param {Hash} Options to be passed to the plugin's factory.
+ * @returns the controller
+ */
+Controller.prototype.use = function(pluginName, options) {
+ var functionOrHash, pluginFactory, key, pluginInstance;
+
+ pluginFactory = (typeof pluginName == 'function') ? pluginName : Controller._pluginFactories[pluginName];
+
+ if (!pluginFactory) {
+ throw 'Leap Plugin ' + pluginName + ' not found.';
+ }
+
+ options || (options = {});
+
+ if (this.plugins[pluginName]){
+ _.extend(this.plugins[pluginName], options);
+ return this;
+ }
+
+ this.plugins[pluginName] = options;
+
+ pluginInstance = pluginFactory.call(this, options);
+
+ for (key in pluginInstance) {
+
+ functionOrHash = pluginInstance[key];
+
+ if (typeof functionOrHash === 'function') {
+
+ setPluginCallbacks.call(this, pluginName, key, functionOrHash);
+
+ } else {
+
+ setPluginMethods.call(this, pluginName, key, functionOrHash);
+
+ }
+
+ }
+
+ return this;
+};
+
+
+
+
+/*
+ * Stop using a used plugin. This will remove any of the plugin's pipeline methods (those called on every frame)
+ * and remove any methods which extend frame-object prototypes.
+ *
+ * @method stopUsing
+ * @memberOf Leap.Controller.prototype
+ * @param pluginName
+ * @returns the controller
+ */
+Controller.prototype.stopUsing = function (pluginName) {
+ var steps = this._pluginPipelineSteps[pluginName],
+ extMethodHashes = this._pluginExtendedMethods[pluginName],
+ i = 0, klass, extMethodHash;
+
+ if (!this.plugins[pluginName]) return;
+
+ if (steps) {
+ for (i = 0; i < steps.length; i++) {
+ this.pipeline.removeStep(steps[i]);
+ }
+ }
+
+ if (extMethodHashes){
+ for (i = 0; i < extMethodHashes.length; i++){
+ klass = extMethodHashes[i][0];
+ extMethodHash = extMethodHashes[i][1];
+ for (var methodName in extMethodHash) {
+ delete klass.prototype[methodName];
+ delete klass.Invalid[methodName];
+ }
+ }
+ }
+
+ delete this.plugins[pluginName];
+
+ return this;
+}
+
+Controller.prototype.useRegisteredPlugins = function(){
+ for (var plugin in Controller._pluginFactories){
+ this.use(plugin);
+ }
+}
+
+
+_.extend(Controller.prototype, EventEmitter.prototype);
+
+}).call(this,require('_process'))
+},{"./circular_buffer":2,"./connection/browser":4,"./connection/node":5,"./dialog":7,"./finger":8,"./frame":9,"./gesture":10,"./hand":11,"./pipeline":14,"./pointable":15,"_process":33,"events":21,"underscore":34}],7:[function(require,module,exports){
+(function (process){
+var Dialog = module.exports = function(message, options){
+ this.options = (options || {});
+ this.message = message;
+
+ this.createElement();
+};
+
+Dialog.prototype.createElement = function(){
+ this.element = document.createElement('div');
+ this.element.className = "leapjs-dialog";
+ this.element.style.position = "fixed";
+ this.element.style.top = '8px';
+ this.element.style.left = 0;
+ this.element.style.right = 0;
+ this.element.style.textAlign = 'center';
+ this.element.style.zIndex = 1000;
+
+ var dialog = document.createElement('div');
+ this.element.appendChild(dialog);
+ dialog.style.className = "leapjs-dialog";
+ dialog.style.display = "inline-block";
+ dialog.style.margin = "auto";
+ dialog.style.padding = "8px";
+ dialog.style.color = "#222";
+ dialog.style.background = "#eee";
+ dialog.style.borderRadius = "4px";
+ dialog.style.border = "1px solid #999";
+ dialog.style.textAlign = "left";
+ dialog.style.cursor = "pointer";
+ dialog.style.whiteSpace = "nowrap";
+ dialog.style.transition = "box-shadow 1s linear";
+ dialog.innerHTML = this.message;
+
+
+ if (this.options.onclick){
+ dialog.addEventListener('click', this.options.onclick);
+ }
+
+ if (this.options.onmouseover){
+ dialog.addEventListener('mouseover', this.options.onmouseover);
+ }
+
+ if (this.options.onmouseout){
+ dialog.addEventListener('mouseout', this.options.onmouseout);
+ }
+
+ if (this.options.onmousemove){
+ dialog.addEventListener('mousemove', this.options.onmousemove);
+ }
+};
+
+Dialog.prototype.show = function(){
+ document.body.appendChild(this.element);
+ return this;
+};
+
+Dialog.prototype.hide = function(){
+ document.body.removeChild(this.element);
+ return this;
+};
+
+
+
+
+// Shows a DOM dialog box with links to developer.leapmotion.com to upgrade
+// This will work whether or not the Leap is plugged in,
+// As long as it is called after a call to .connect() and the 'ready' event has fired.
+Dialog.warnOutOfDate = function(params){
+ params || (params = {});
+
+ var url = "http://developer.leapmotion.com?";
+
+ params.returnTo = window.location.href;
+
+ for (var key in params){
+ url += key + '=' + encodeURIComponent(params[key]) + '&';
+ }
+
+ var dialog,
+ onclick = function(event){
+
+ if (event.target.id != 'leapjs-decline-upgrade'){
+
+ var popup = window.open(url,
+ '_blank',
+ 'height=800,width=1000,location=1,menubar=1,resizable=1,status=1,toolbar=1,scrollbars=1'
+ );
+
+ if (window.focus) {popup.focus()}
+
+ }
+
+ dialog.hide();
+
+ return true;
+ },
+
+
+ message = "This site requires Leap Motion Tracking V2." +
+ "" +
+ "";
+
+ dialog = new Dialog(message, {
+ onclick: onclick,
+ onmousemove: function(e){
+ if (e.target == document.getElementById('leapjs-decline-upgrade')){
+ document.getElementById('leapjs-decline-upgrade').style.color = '#000';
+ document.getElementById('leapjs-decline-upgrade').style.boxShadow = '0px 0px 2px #5daa00';
+
+ document.getElementById('leapjs-accept-upgrade').style.color = '#444';
+ document.getElementById('leapjs-accept-upgrade').style.boxShadow = 'none';
+ }else{
+ document.getElementById('leapjs-accept-upgrade').style.color = '#000';
+ document.getElementById('leapjs-accept-upgrade').style.boxShadow = '0px 0px 2px #5daa00';
+
+ document.getElementById('leapjs-decline-upgrade').style.color = '#444';
+ document.getElementById('leapjs-decline-upgrade').style.boxShadow = 'none';
+ }
+ },
+ onmouseout: function(){
+ document.getElementById('leapjs-decline-upgrade').style.color = '#444';
+ document.getElementById('leapjs-decline-upgrade').style.boxShadow = 'none';
+ document.getElementById('leapjs-accept-upgrade').style.color = '#444';
+ document.getElementById('leapjs-accept-upgrade').style.boxShadow = 'none';
+ }
+ }
+ );
+
+ return dialog.show();
+};
+
+
+// Tracks whether we've warned for lack of bones API. This will be shown only for early private-beta members.
+Dialog.hasWarnedBones = false;
+
+Dialog.warnBones = function(){
+ if (this.hasWarnedBones) return;
+ this.hasWarnedBones = true;
+
+ console.warn("Your Leap Service is out of date");
+
+ if ( !(typeof(process) !== 'undefined' && process.versions && process.versions.node) ){
+ this.warnOutOfDate({reason: 'bones'});
+ }
+
+}
+}).call(this,require('_process'))
+},{"_process":33}],8:[function(require,module,exports){
+var Pointable = require('./pointable'),
+ Bone = require('./bone')
+ , Dialog = require('./dialog')
+ , _ = require('underscore');
+
+/**
+* Constructs a Finger object.
+*
+* An uninitialized finger is considered invalid.
+* Get valid Finger objects from a Frame or a Hand object.
+*
+* @class Finger
+* @memberof Leap
+* @classdesc
+* The Finger class reports the physical characteristics of a finger.
+*
+* Both fingers and tools are classified as Pointable objects. Use the
+* Pointable.tool property to determine whether a Pointable object represents a
+* tool or finger. The Leap classifies a detected entity as a tool when it is
+* thinner, straighter, and longer than a typical finger.
+*
+* Note that Finger objects can be invalid, which means that they do not
+* contain valid tracking data and do not correspond to a physical entity.
+* Invalid Finger objects can be the result of asking for a Finger object
+* using an ID from an earlier frame when no Finger objects with that ID
+* exist in the current frame. A Finger object created from the Finger
+* constructor is also invalid. Test for validity with the Pointable.valid
+* property.
+*/
+var Finger = module.exports = function(data) {
+ Pointable.call(this, data); // use pointable as super-constructor
+
+ /**
+ * The position of the distal interphalangeal joint of the finger.
+ * This joint is closest to the tip.
+ *
+ * The distal interphalangeal joint is located between the most extreme segment
+ * of the finger (the distal phalanx) and the middle segment (the medial
+ * phalanx).
+ *
+ * @member dipPosition
+ * @type {number[]}
+ * @memberof Leap.Finger.prototype
+ */
+ this.dipPosition = data.dipPosition;
+
+ /**
+ * The position of the proximal interphalangeal joint of the finger. This joint is the middle
+ * joint of a finger.
+ *
+ * The proximal interphalangeal joint is located between the two finger segments
+ * closest to the hand (the proximal and the medial phalanges). On a thumb,
+ * which lacks an medial phalanx, this joint index identifies the knuckle joint
+ * between the proximal phalanx and the metacarpal bone.
+ *
+ * @member pipPosition
+ * @type {number[]}
+ * @memberof Leap.Finger.prototype
+ */
+ this.pipPosition = data.pipPosition;
+
+ /**
+ * The position of the metacarpopophalangeal joint, or knuckle, of the finger.
+ *
+ * The metacarpopophalangeal joint is located at the base of a finger between
+ * the metacarpal bone and the first phalanx. The common name for this joint is
+ * the knuckle.
+ *
+ * On a thumb, which has one less phalanx than a finger, this joint index
+ * identifies the thumb joint near the base of the hand, between the carpal
+ * and metacarpal bones.
+ *
+ * @member mcpPosition
+ * @type {number[]}
+ * @memberof Leap.Finger.prototype
+ */
+ this.mcpPosition = data.mcpPosition;
+
+ /**
+ * The position of the Carpometacarpal joint
+ *
+ * This is at the distal end of the wrist, and has no common name.
+ *
+ */
+ this.carpPosition = data.carpPosition;
+
+ /**
+ * Whether or not this finger is in an extended posture.
+ *
+ * A finger is considered extended if it is extended straight from the hand as if
+ * pointing. A finger is not extended when it is bent down and curled towards the
+ * palm.
+ * @member extended
+ * @type {Boolean}
+ * @memberof Leap.Finger.prototype
+ */
+ this.extended = data.extended;
+
+ /**
+ * An integer code for the name of this finger.
+ *
+ * * 0 -- thumb
+ * * 1 -- index finger
+ * * 2 -- middle finger
+ * * 3 -- ring finger
+ * * 4 -- pinky
+ *
+ * @member type
+ * @type {number}
+ * @memberof Leap.Finger.prototype
+ */
+ this.type = data.type;
+
+ this.finger = true;
+
+ /**
+ * The joint positions of this finger as an array in the order base to tip.
+ *
+ * @member positions
+ * @type {array[]}
+ * @memberof Leap.Finger.prototype
+ */
+ this.positions = [this.carpPosition, this.mcpPosition, this.pipPosition, this.dipPosition, this.tipPosition];
+
+ if (data.bases){
+ this.addBones(data);
+ } else {
+ Dialog.warnBones();
+ }
+
+};
+
+_.extend(Finger.prototype, Pointable.prototype);
+
+
+Finger.prototype.addBones = function(data){
+ /**
+ * Four bones per finger, from wrist outwards:
+ * metacarpal, proximal, medial, and distal.
+ *
+ * See http://en.wikipedia.org/wiki/Interphalangeal_articulations_of_hand
+ */
+ this.metacarpal = new Bone(this, {
+ type: 0,
+ width: this.width,
+ prevJoint: this.carpPosition,
+ nextJoint: this.mcpPosition,
+ basis: data.bases[0]
+ });
+
+ this.proximal = new Bone(this, {
+ type: 1,
+ width: this.width,
+ prevJoint: this.mcpPosition,
+ nextJoint: this.pipPosition,
+ basis: data.bases[1]
+ });
+
+ this.medial = new Bone(this, {
+ type: 2,
+ width: this.width,
+ prevJoint: this.pipPosition,
+ nextJoint: this.dipPosition,
+ basis: data.bases[2]
+ });
+
+ /**
+ * Note that the `distal.nextJoint` position is slightly different from the `finger.tipPosition`.
+ * The former is at the very end of the bone, where the latter is the center of a sphere positioned at
+ * the tip of the finger. The btipPosition "bone tip position" is a few mm closer to the wrist than
+ * the tipPosition.
+ * @type {Bone}
+ */
+ this.distal = new Bone(this, {
+ type: 3,
+ width: this.width,
+ prevJoint: this.dipPosition,
+ nextJoint: data.btipPosition,
+ basis: data.bases[3]
+ });
+
+ this.bones = [this.metacarpal, this.proximal, this.medial, this.distal];
+};
+
+Finger.prototype.toString = function() {
+ return "Finger [ id:" + this.id + " " + this.length + "mmx | width:" + this.width + "mm | direction:" + this.direction + ' ]';
+};
+
+Finger.Invalid = { valid: false };
+
+},{"./bone":1,"./dialog":7,"./pointable":15,"underscore":34}],9:[function(require,module,exports){
+var Hand = require("./hand")
+ , Pointable = require("./pointable")
+ , createGesture = require("./gesture").createGesture
+ , glMatrix = require("gl-matrix")
+ , mat3 = glMatrix.mat3
+ , vec3 = glMatrix.vec3
+ , InteractionBox = require("./interaction_box")
+ , Finger = require('./finger')
+ , _ = require("underscore");
+
+/**
+ * Constructs a Frame object.
+ *
+ * Frame instances created with this constructor are invalid.
+ * Get valid Frame objects by calling the
+ * [Controller.frame]{@link Leap.Controller#frame}() function.
+ *
+ * @class Frame
+ * @memberof Leap
+ * @classdesc
+ * The Frame class represents a set of hand and finger tracking data detected
+ * in a single frame.
+ *
+ * The Leap detects hands, fingers and tools within the tracking area, reporting
+ * their positions, orientations and motions in frames at the Leap frame rate.
+ *
+ * Access Frame objects using the [Controller.frame]{@link Leap.Controller#frame}() function.
+ */
+var Frame = module.exports = function(data) {
+ /**
+ * Reports whether this Frame instance is valid.
+ *
+ * A valid Frame is one generated by the Controller object that contains
+ * tracking data for all detected entities. An invalid Frame contains no
+ * actual tracking data, but you can call its functions without risk of a
+ * undefined object exception. The invalid Frame mechanism makes it more
+ * convenient to track individual data across the frame history. For example,
+ * you can invoke:
+ *
+ * ```javascript
+ * var finger = controller.frame(n).finger(fingerID);
+ * ```
+ *
+ * for an arbitrary Frame history value, "n", without first checking whether
+ * frame(n) returned a null object. (You should still check that the
+ * returned Finger instance is valid.)
+ *
+ * @member valid
+ * @memberof Leap.Frame.prototype
+ * @type {Boolean}
+ */
+ this.valid = true;
+ /**
+ * A unique ID for this Frame. Consecutive frames processed by the Leap
+ * have consecutive increasing values.
+ * @member id
+ * @memberof Leap.Frame.prototype
+ * @type {String}
+ */
+ this.id = data.id;
+ /**
+ * The frame capture time in microseconds elapsed since the Leap started.
+ * @member timestamp
+ * @memberof Leap.Frame.prototype
+ * @type {number}
+ */
+ this.timestamp = data.timestamp;
+ /**
+ * The list of Hand objects detected in this frame, given in arbitrary order.
+ * The list can be empty if no hands are detected.
+ *
+ * @member hands[]
+ * @memberof Leap.Frame.prototype
+ * @type {Leap.Hand}
+ */
+ this.hands = [];
+ this.handsMap = {};
+ /**
+ * The list of Pointable objects (fingers and tools) detected in this frame,
+ * given in arbitrary order. The list can be empty if no fingers or tools are
+ * detected.
+ *
+ * @member pointables[]
+ * @memberof Leap.Frame.prototype
+ * @type {Leap.Pointable}
+ */
+ this.pointables = [];
+ /**
+ * The list of Tool objects detected in this frame, given in arbitrary order.
+ * The list can be empty if no tools are detected.
+ *
+ * @member tools[]
+ * @memberof Leap.Frame.prototype
+ * @type {Leap.Pointable}
+ */
+ this.tools = [];
+ /**
+ * The list of Finger objects detected in this frame, given in arbitrary order.
+ * The list can be empty if no fingers are detected.
+ * @member fingers[]
+ * @memberof Leap.Frame.prototype
+ * @type {Leap.Pointable}
+ */
+ this.fingers = [];
+
+ /**
+ * The InteractionBox associated with the current frame.
+ *
+ * @member interactionBox
+ * @memberof Leap.Frame.prototype
+ * @type {Leap.InteractionBox}
+ */
+ if (data.interactionBox) {
+ this.interactionBox = new InteractionBox(data.interactionBox);
+ }
+ this.gestures = [];
+ this.pointablesMap = {};
+ this._translation = data.t;
+ this._rotation = _.flatten(data.r);
+ this._scaleFactor = data.s;
+ this.data = data;
+ this.type = 'frame'; // used by event emitting
+ this.currentFrameRate = data.currentFrameRate;
+
+ if (data.gestures) {
+ /**
+ * The list of Gesture objects detected in this frame, given in arbitrary order.
+ * The list can be empty if no gestures are detected.
+ *
+ * Circle and swipe gestures are updated every frame. Tap gestures
+ * only appear in the list for a single frame.
+ * @member gestures[]
+ * @memberof Leap.Frame.prototype
+ * @type {Leap.Gesture}
+ */
+ for (var gestureIdx = 0, gestureCount = data.gestures.length; gestureIdx != gestureCount; gestureIdx++) {
+ this.gestures.push(createGesture(data.gestures[gestureIdx]));
+ }
+ }
+ this.postprocessData(data);
+};
+
+Frame.prototype.postprocessData = function(data){
+ if (!data) {
+ data = this.data;
+ }
+
+ for (var handIdx = 0, handCount = data.hands.length; handIdx != handCount; handIdx++) {
+ var hand = new Hand(data.hands[handIdx]);
+ hand.frame = this;
+ this.hands.push(hand);
+ this.handsMap[hand.id] = hand;
+ }
+
+ data.pointables = _.sortBy(data.pointables, function(pointable) { return pointable.id });
+
+ for (var pointableIdx = 0, pointableCount = data.pointables.length; pointableIdx != pointableCount; pointableIdx++) {
+ var pointableData = data.pointables[pointableIdx];
+ var pointable = pointableData.dipPosition ? new Finger(pointableData) : new Pointable(pointableData);
+ pointable.frame = this;
+ this.addPointable(pointable);
+ }
+};
+
+/**
+ * Adds data from a pointable element into the pointablesMap;
+ * also adds the pointable to the frame.handsMap hand to which it belongs,
+ * and to the hand's tools or hand's fingers map.
+ *
+ * @param pointable {Object} a Pointable
+ */
+Frame.prototype.addPointable = function (pointable) {
+ this.pointables.push(pointable);
+ this.pointablesMap[pointable.id] = pointable;
+ (pointable.tool ? this.tools : this.fingers).push(pointable);
+ if (pointable.handId !== undefined && this.handsMap.hasOwnProperty(pointable.handId)) {
+ var hand = this.handsMap[pointable.handId];
+ hand.pointables.push(pointable);
+ (pointable.tool ? hand.tools : hand.fingers).push(pointable);
+ switch (pointable.type){
+ case 0:
+ hand.thumb = pointable;
+ break;
+ case 1:
+ hand.indexFinger = pointable;
+ break;
+ case 2:
+ hand.middleFinger = pointable;
+ break;
+ case 3:
+ hand.ringFinger = pointable;
+ break;
+ case 4:
+ hand.pinky = pointable;
+ break;
+ }
+ }
+};
+
+/**
+ * The tool with the specified ID in this frame.
+ *
+ * Use the Frame tool() function to retrieve a tool from
+ * this frame using an ID value obtained from a previous frame.
+ * This function always returns a Pointable object, but if no tool
+ * with the specified ID is present, an invalid Pointable object is returned.
+ *
+ * Note that ID values persist across frames, but only until tracking of a
+ * particular object is lost. If tracking of a tool is lost and subsequently
+ * regained, the new Pointable object representing that tool may have a
+ * different ID than that representing the tool in an earlier frame.
+ *
+ * @method tool
+ * @memberof Leap.Frame.prototype
+ * @param {String} id The ID value of a Tool object from a previous frame.
+ * @returns {Leap.Pointable} The tool with the
+ * matching ID if one exists in this frame; otherwise, an invalid Pointable object
+ * is returned.
+ */
+Frame.prototype.tool = function(id) {
+ var pointable = this.pointable(id);
+ return pointable.tool ? pointable : Pointable.Invalid;
+};
+
+/**
+ * The Pointable object with the specified ID in this frame.
+ *
+ * Use the Frame pointable() function to retrieve the Pointable object from
+ * this frame using an ID value obtained from a previous frame.
+ * This function always returns a Pointable object, but if no finger or tool
+ * with the specified ID is present, an invalid Pointable object is returned.
+ *
+ * Note that ID values persist across frames, but only until tracking of a
+ * particular object is lost. If tracking of a finger or tool is lost and subsequently
+ * regained, the new Pointable object representing that finger or tool may have
+ * a different ID than that representing the finger or tool in an earlier frame.
+ *
+ * @method pointable
+ * @memberof Leap.Frame.prototype
+ * @param {String} id The ID value of a Pointable object from a previous frame.
+ * @returns {Leap.Pointable} The Pointable object with
+ * the matching ID if one exists in this frame;
+ * otherwise, an invalid Pointable object is returned.
+ */
+Frame.prototype.pointable = function(id) {
+ return this.pointablesMap[id] || Pointable.Invalid;
+};
+
+/**
+ * The finger with the specified ID in this frame.
+ *
+ * Use the Frame finger() function to retrieve the finger from
+ * this frame using an ID value obtained from a previous frame.
+ * This function always returns a Finger object, but if no finger
+ * with the specified ID is present, an invalid Pointable object is returned.
+ *
+ * Note that ID values persist across frames, but only until tracking of a
+ * particular object is lost. If tracking of a finger is lost and subsequently
+ * regained, the new Pointable object representing that physical finger may have
+ * a different ID than that representing the finger in an earlier frame.
+ *
+ * @method finger
+ * @memberof Leap.Frame.prototype
+ * @param {String} id The ID value of a finger from a previous frame.
+ * @returns {Leap.Pointable} The finger with the
+ * matching ID if one exists in this frame; otherwise, an invalid Pointable
+ * object is returned.
+ */
+Frame.prototype.finger = function(id) {
+ var pointable = this.pointable(id);
+ return !pointable.tool ? pointable : Pointable.Invalid;
+};
+
+/**
+ * The Hand object with the specified ID in this frame.
+ *
+ * Use the Frame hand() function to retrieve the Hand object from
+ * this frame using an ID value obtained from a previous frame.
+ * This function always returns a Hand object, but if no hand
+ * with the specified ID is present, an invalid Hand object is returned.
+ *
+ * Note that ID values persist across frames, but only until tracking of a
+ * particular object is lost. If tracking of a hand is lost and subsequently
+ * regained, the new Hand object representing that physical hand may have
+ * a different ID than that representing the physical hand in an earlier frame.
+ *
+ * @method hand
+ * @memberof Leap.Frame.prototype
+ * @param {String} id The ID value of a Hand object from a previous frame.
+ * @returns {Leap.Hand} The Hand object with the matching
+ * ID if one exists in this frame; otherwise, an invalid Hand object is returned.
+ */
+Frame.prototype.hand = function(id) {
+ return this.handsMap[id] || Hand.Invalid;
+};
+
+/**
+ * The angle of rotation around the rotation axis derived from the overall
+ * rotational motion between the current frame and the specified frame.
+ *
+ * The returned angle is expressed in radians measured clockwise around
+ * the rotation axis (using the right-hand rule) between the start and end frames.
+ * The value is always between 0 and pi radians (0 and 180 degrees).
+ *
+ * The Leap derives frame rotation from the relative change in position and
+ * orientation of all objects detected in the field of view.
+ *
+ * If either this frame or sinceFrame is an invalid Frame object, then the
+ * angle of rotation is zero.
+ *
+ * @method rotationAngle
+ * @memberof Leap.Frame.prototype
+ * @param {Leap.Frame} sinceFrame The starting frame for computing the relative rotation.
+ * @param {number[]} [axis] The axis to measure rotation around.
+ * @returns {number} A positive value containing the heuristically determined
+ * rotational change between the current frame and that specified in the sinceFrame parameter.
+ */
+Frame.prototype.rotationAngle = function(sinceFrame, axis) {
+ if (!this.valid || !sinceFrame.valid) return 0.0;
+
+ var rot = this.rotationMatrix(sinceFrame);
+ var cs = (rot[0] + rot[4] + rot[8] - 1.0)*0.5;
+ var angle = Math.acos(cs);
+ angle = isNaN(angle) ? 0.0 : angle;
+
+ if (axis !== undefined) {
+ var rotAxis = this.rotationAxis(sinceFrame);
+ angle *= vec3.dot(rotAxis, vec3.normalize(vec3.create(), axis));
+ }
+
+ return angle;
+};
+
+/**
+ * The axis of rotation derived from the overall rotational motion between
+ * the current frame and the specified frame.
+ *
+ * The returned direction vector is normalized.
+ *
+ * The Leap derives frame rotation from the relative change in position and
+ * orientation of all objects detected in the field of view.
+ *
+ * If either this frame or sinceFrame is an invalid Frame object, or if no
+ * rotation is detected between the two frames, a zero vector is returned.
+ *
+ * @method rotationAxis
+ * @memberof Leap.Frame.prototype
+ * @param {Leap.Frame} sinceFrame The starting frame for computing the relative rotation.
+ * @returns {number[]} A normalized direction vector representing the axis of the heuristically determined
+ * rotational change between the current frame and that specified in the sinceFrame parameter.
+ */
+Frame.prototype.rotationAxis = function(sinceFrame) {
+ if (!this.valid || !sinceFrame.valid) return vec3.create();
+ return vec3.normalize(vec3.create(), [
+ this._rotation[7] - sinceFrame._rotation[5],
+ this._rotation[2] - sinceFrame._rotation[6],
+ this._rotation[3] - sinceFrame._rotation[1]
+ ]);
+}
+
+/**
+ * The transform matrix expressing the rotation derived from the overall
+ * rotational motion between the current frame and the specified frame.
+ *
+ * The Leap derives frame rotation from the relative change in position and
+ * orientation of all objects detected in the field of view.
+ *
+ * If either this frame or sinceFrame is an invalid Frame object, then
+ * this method returns an identity matrix.
+ *
+ * @method rotationMatrix
+ * @memberof Leap.Frame.prototype
+ * @param {Leap.Frame} sinceFrame The starting frame for computing the relative rotation.
+ * @returns {number[]} A transformation matrix containing the heuristically determined
+ * rotational change between the current frame and that specified in the sinceFrame parameter.
+ */
+Frame.prototype.rotationMatrix = function(sinceFrame) {
+ if (!this.valid || !sinceFrame.valid) return mat3.create();
+ var transpose = mat3.transpose(mat3.create(), this._rotation)
+ return mat3.multiply(mat3.create(), sinceFrame._rotation, transpose);
+}
+
+/**
+ * The scale factor derived from the overall motion between the current frame and the specified frame.
+ *
+ * The scale factor is always positive. A value of 1.0 indicates no scaling took place.
+ * Values between 0.0 and 1.0 indicate contraction and values greater than 1.0 indicate expansion.
+ *
+ * The Leap derives scaling from the relative inward or outward motion of all
+ * objects detected in the field of view (independent of translation and rotation).
+ *
+ * If either this frame or sinceFrame is an invalid Frame object, then this method returns 1.0.
+ *
+ * @method scaleFactor
+ * @memberof Leap.Frame.prototype
+ * @param {Leap.Frame} sinceFrame The starting frame for computing the relative scaling.
+ * @returns {number} A positive value representing the heuristically determined
+ * scaling change ratio between the current frame and that specified in the sinceFrame parameter.
+ */
+Frame.prototype.scaleFactor = function(sinceFrame) {
+ if (!this.valid || !sinceFrame.valid) return 1.0;
+ return Math.exp(this._scaleFactor - sinceFrame._scaleFactor);
+}
+
+/**
+ * The change of position derived from the overall linear motion between the
+ * current frame and the specified frame.
+ *
+ * The returned translation vector provides the magnitude and direction of the
+ * movement in millimeters.
+ *
+ * The Leap derives frame translation from the linear motion of all objects
+ * detected in the field of view.
+ *
+ * If either this frame or sinceFrame is an invalid Frame object, then this
+ * method returns a zero vector.
+ *
+ * @method translation
+ * @memberof Leap.Frame.prototype
+ * @param {Leap.Frame} sinceFrame The starting frame for computing the relative translation.
+ * @returns {number[]} A vector representing the heuristically determined change in
+ * position of all objects between the current frame and that specified in the sinceFrame parameter.
+ */
+Frame.prototype.translation = function(sinceFrame) {
+ if (!this.valid || !sinceFrame.valid) return vec3.create();
+ return vec3.subtract(vec3.create(), this._translation, sinceFrame._translation);
+}
+
+/**
+ * A string containing a brief, human readable description of the Frame object.
+ *
+ * @method toString
+ * @memberof Leap.Frame.prototype
+ * @returns {String} A brief description of this frame.
+ */
+Frame.prototype.toString = function() {
+ var str = "Frame [ id:"+this.id+" | timestamp:"+this.timestamp+" | Hand count:("+this.hands.length+") | Pointable count:("+this.pointables.length+")";
+ if (this.gestures) str += " | Gesture count:("+this.gestures.length+")";
+ str += " ]";
+ return str;
+}
+
+/**
+ * Returns a JSON-formatted string containing the hands, pointables and gestures
+ * in this frame.
+ *
+ * @method dump
+ * @memberof Leap.Frame.prototype
+ * @returns {String} A JSON-formatted string.
+ */
+Frame.prototype.dump = function() {
+ var out = '';
+ out += "Frame Info: ";
+ out += this.toString();
+ out += "
Raw JSON: ";
+ out += JSON.stringify(this.data);
+ return out;
+}
+
+/**
+ * An invalid Frame object.
+ *
+ * You can use this invalid Frame in comparisons testing
+ * whether a given Frame instance is valid or invalid. (You can also check the
+ * [Frame.valid]{@link Leap.Frame#valid} property.)
+ *
+ * @static
+ * @type {Leap.Frame}
+ * @name Invalid
+ * @memberof Leap.Frame
+ */
+Frame.Invalid = {
+ valid: false,
+ hands: [],
+ fingers: [],
+ tools: [],
+ gestures: [],
+ pointables: [],
+ pointable: function() { return Pointable.Invalid },
+ finger: function() { return Pointable.Invalid },
+ hand: function() { return Hand.Invalid },
+ toString: function() { return "invalid frame" },
+ dump: function() { return this.toString() },
+ rotationAngle: function() { return 0.0; },
+ rotationMatrix: function() { return mat3.create(); },
+ rotationAxis: function() { return vec3.create(); },
+ scaleFactor: function() { return 1.0; },
+ translation: function() { return vec3.create(); }
+};
+
+},{"./finger":8,"./gesture":10,"./hand":11,"./interaction_box":13,"./pointable":15,"gl-matrix":23,"underscore":34}],10:[function(require,module,exports){
+var glMatrix = require("gl-matrix")
+ , vec3 = glMatrix.vec3
+ , EventEmitter = require('events').EventEmitter
+ , _ = require('underscore');
+
+/**
+ * Constructs a new Gesture object.
+ *
+ * An uninitialized Gesture object is considered invalid. Get valid instances
+ * of the Gesture class, which will be one of the Gesture subclasses, from a
+ * Frame object.
+ *
+ * @class Gesture
+ * @abstract
+ * @memberof Leap
+ * @classdesc
+ * The Gesture class represents a recognized movement by the user.
+ *
+ * The Leap watches the activity within its field of view for certain movement
+ * patterns typical of a user gesture or command. For example, a movement from side to
+ * side with the hand can indicate a swipe gesture, while a finger poking forward
+ * can indicate a screen tap gesture.
+ *
+ * When the Leap recognizes a gesture, it assigns an ID and adds a
+ * Gesture object to the frame gesture list. For continuous gestures, which
+ * occur over many frames, the Leap updates the gesture by adding
+ * a Gesture object having the same ID and updated properties in each
+ * subsequent frame.
+ *
+ * **Important:** Recognition for each type of gesture must be enabled;
+ * otherwise **no gestures are recognized or reported**.
+ *
+ * Subclasses of Gesture define the properties for the specific movement patterns
+ * recognized by the Leap.
+ *
+ * The Gesture subclasses for include:
+ *
+ * * CircleGesture -- A circular movement by a finger.
+ * * SwipeGesture -- A straight line movement by the hand with fingers extended.
+ * * ScreenTapGesture -- A forward tapping movement by a finger.
+ * * KeyTapGesture -- A downward tapping movement by a finger.
+ *
+ * Circle and swipe gestures are continuous and these objects can have a
+ * state of start, update, and stop.
+ *
+ * The screen tap gesture is a discrete gesture. The Leap only creates a single
+ * ScreenTapGesture object appears for each tap and it always has a stop state.
+ *
+ * Get valid Gesture instances from a Frame object. You can get a list of gestures
+ * from the Frame gestures array. You can also use the Frame gesture() method
+ * to find a gesture in the current frame using an ID value obtained in a
+ * previous frame.
+ *
+ * Gesture objects can be invalid. For example, when you get a gesture by ID
+ * using Frame.gesture(), and there is no gesture with that ID in the current
+ * frame, then gesture() returns an Invalid Gesture object (rather than a null
+ * value). Always check object validity in situations where a gesture might be
+ * invalid.
+ */
+var createGesture = exports.createGesture = function(data) {
+ var gesture;
+ switch (data.type) {
+ case 'circle':
+ gesture = new CircleGesture(data);
+ break;
+ case 'swipe':
+ gesture = new SwipeGesture(data);
+ break;
+ case 'screenTap':
+ gesture = new ScreenTapGesture(data);
+ break;
+ case 'keyTap':
+ gesture = new KeyTapGesture(data);
+ break;
+ default:
+ throw "unknown gesture type";
+ }
+
+ /**
+ * The gesture ID.
+ *
+ * All Gesture objects belonging to the same recognized movement share the
+ * same ID value. Use the ID value with the Frame::gesture() method to
+ * find updates related to this Gesture object in subsequent frames.
+ *
+ * @member id
+ * @memberof Leap.Gesture.prototype
+ * @type {number}
+ */
+ gesture.id = data.id;
+ /**
+ * The list of hands associated with this Gesture, if any.
+ *
+ * If no hands are related to this gesture, the list is empty.
+ *
+ * @member handIds
+ * @memberof Leap.Gesture.prototype
+ * @type {Array}
+ */
+ gesture.handIds = data.handIds.slice();
+ /**
+ * The list of fingers and tools associated with this Gesture, if any.
+ *
+ * If no Pointable objects are related to this gesture, the list is empty.
+ *
+ * @member pointableIds
+ * @memberof Leap.Gesture.prototype
+ * @type {Array}
+ */
+ gesture.pointableIds = data.pointableIds.slice();
+ /**
+ * The elapsed duration of the recognized movement up to the
+ * frame containing this Gesture object, in microseconds.
+ *
+ * The duration reported for the first Gesture in the sequence (with the
+ * start state) will typically be a small positive number since
+ * the movement must progress far enough for the Leap to recognize it as
+ * an intentional gesture.
+ *
+ * @member duration
+ * @memberof Leap.Gesture.prototype
+ * @type {number}
+ */
+ gesture.duration = data.duration;
+ /**
+ * The gesture ID.
+ *
+ * Recognized movements occur over time and have a beginning, a middle,
+ * and an end. The 'state()' attribute reports where in that sequence this
+ * Gesture object falls.
+ *
+ * Possible values for the state field are:
+ *
+ * * start
+ * * update
+ * * stop
+ *
+ * @member state
+ * @memberof Leap.Gesture.prototype
+ * @type {String}
+ */
+ gesture.state = data.state;
+ /**
+ * The gesture type.
+ *
+ * Possible values for the type field are:
+ *
+ * * circle
+ * * swipe
+ * * screenTap
+ * * keyTap
+ *
+ * @member type
+ * @memberof Leap.Gesture.prototype
+ * @type {String}
+ */
+ gesture.type = data.type;
+ return gesture;
+}
+
+/*
+ * Returns a builder object, which uses method chaining for gesture callback binding.
+ */
+var gestureListener = exports.gestureListener = function(controller, type) {
+ var handlers = {};
+ var gestureMap = {};
+
+ controller.on('gesture', function(gesture, frame) {
+ if (gesture.type == type) {
+ if (gesture.state == "start" || gesture.state == "stop") {
+ if (gestureMap[gesture.id] === undefined) {
+ var gestureTracker = new Gesture(gesture, frame);
+ gestureMap[gesture.id] = gestureTracker;
+ _.each(handlers, function(cb, name) {
+ gestureTracker.on(name, cb);
+ });
+ }
+ }
+ gestureMap[gesture.id].update(gesture, frame);
+ if (gesture.state == "stop") {
+ delete gestureMap[gesture.id];
+ }
+ }
+ });
+ var builder = {
+ start: function(cb) {
+ handlers['start'] = cb;
+ return builder;
+ },
+ stop: function(cb) {
+ handlers['stop'] = cb;
+ return builder;
+ },
+ complete: function(cb) {
+ handlers['stop'] = cb;
+ return builder;
+ },
+ update: function(cb) {
+ handlers['update'] = cb;
+ return builder;
+ }
+ }
+ return builder;
+}
+
+var Gesture = exports.Gesture = function(gesture, frame) {
+ this.gestures = [gesture];
+ this.frames = [frame];
+}
+
+Gesture.prototype.update = function(gesture, frame) {
+ this.lastGesture = gesture;
+ this.lastFrame = frame;
+ this.gestures.push(gesture);
+ this.frames.push(frame);
+ this.emit(gesture.state, this);
+}
+
+Gesture.prototype.translation = function() {
+ return vec3.subtract(vec3.create(), this.lastGesture.startPosition, this.lastGesture.position);
+}
+
+_.extend(Gesture.prototype, EventEmitter.prototype);
+
+/**
+ * Constructs a new CircleGesture object.
+ *
+ * An uninitialized CircleGesture object is considered invalid. Get valid instances
+ * of the CircleGesture class from a Frame object.
+ *
+ * @class CircleGesture
+ * @memberof Leap
+ * @augments Leap.Gesture
+ * @classdesc
+ * The CircleGesture classes represents a circular finger movement.
+ *
+ * A circle movement is recognized when the tip of a finger draws a circle
+ * within the Leap field of view.
+ *
+ * ![CircleGesture](images/Leap_Gesture_Circle.png)
+ *
+ * Circle gestures are continuous. The CircleGesture objects for the gesture have
+ * three possible states:
+ *
+ * * start -- The circle gesture has just started. The movement has
+ * progressed far enough for the recognizer to classify it as a circle.
+ * * update -- The circle gesture is continuing.
+ * * stop -- The circle gesture is finished.
+ */
+var CircleGesture = function(data) {
+ /**
+ * The center point of the circle within the Leap frame of reference.
+ *
+ * @member center
+ * @memberof Leap.CircleGesture.prototype
+ * @type {number[]}
+ */
+ this.center = data.center;
+ /**
+ * The normal vector for the circle being traced.
+ *
+ * If you draw the circle clockwise, the normal vector points in the same
+ * general direction as the pointable object drawing the circle. If you draw
+ * the circle counterclockwise, the normal points back toward the
+ * pointable. If the angle between the normal and the pointable object
+ * drawing the circle is less than 90 degrees, then the circle is clockwise.
+ *
+ * ```javascript
+ * var clockwiseness;
+ * if (circle.pointable.direction.angleTo(circle.normal) <= PI/4) {
+ * clockwiseness = "clockwise";
+ * }
+ * else
+ * {
+ * clockwiseness = "counterclockwise";
+ * }
+ * ```
+ *
+ * @member normal
+ * @memberof Leap.CircleGesture.prototype
+ * @type {number[]}
+ */
+ this.normal = data.normal;
+ /**
+ * The number of times the finger tip has traversed the circle.
+ *
+ * Progress is reported as a positive number of the number. For example,
+ * a progress value of .5 indicates that the finger has gone halfway
+ * around, while a value of 3 indicates that the finger has gone around
+ * the the circle three times.
+ *
+ * Progress starts where the circle gesture began. Since the circle
+ * must be partially formed before the Leap can recognize it, progress
+ * will be greater than zero when a circle gesture first appears in the
+ * frame.
+ *
+ * @member progress
+ * @memberof Leap.CircleGesture.prototype
+ * @type {number}
+ */
+ this.progress = data.progress;
+ /**
+ * The radius of the circle in mm.
+ *
+ * @member radius
+ * @memberof Leap.CircleGesture.prototype
+ * @type {number}
+ */
+ this.radius = data.radius;
+}
+
+CircleGesture.prototype.toString = function() {
+ return "CircleGesture ["+JSON.stringify(this)+"]";
+}
+
+/**
+ * Constructs a new SwipeGesture object.
+ *
+ * An uninitialized SwipeGesture object is considered invalid. Get valid instances
+ * of the SwipeGesture class from a Frame object.
+ *
+ * @class SwipeGesture
+ * @memberof Leap
+ * @augments Leap.Gesture
+ * @classdesc
+ * The SwipeGesture class represents a swiping motion of a finger or tool.
+ *
+ * ![SwipeGesture](images/Leap_Gesture_Swipe.png)
+ *
+ * Swipe gestures are continuous.
+ */
+var SwipeGesture = function(data) {
+ /**
+ * The starting position within the Leap frame of
+ * reference, in mm.
+ *
+ * @member startPosition
+ * @memberof Leap.SwipeGesture.prototype
+ * @type {number[]}
+ */
+ this.startPosition = data.startPosition;
+ /**
+ * The current swipe position within the Leap frame of
+ * reference, in mm.
+ *
+ * @member position
+ * @memberof Leap.SwipeGesture.prototype
+ * @type {number[]}
+ */
+ this.position = data.position;
+ /**
+ * The unit direction vector parallel to the swipe motion.
+ *
+ * You can compare the components of the vector to classify the swipe as
+ * appropriate for your application. For example, if you are using swipes
+ * for two dimensional scrolling, you can compare the x and y values to
+ * determine if the swipe is primarily horizontal or vertical.
+ *
+ * @member direction
+ * @memberof Leap.SwipeGesture.prototype
+ * @type {number[]}
+ */
+ this.direction = data.direction;
+ /**
+ * The speed of the finger performing the swipe gesture in
+ * millimeters per second.
+ *
+ * @member speed
+ * @memberof Leap.SwipeGesture.prototype
+ * @type {number}
+ */
+ this.speed = data.speed;
+}
+
+SwipeGesture.prototype.toString = function() {
+ return "SwipeGesture ["+JSON.stringify(this)+"]";
+}
+
+/**
+ * Constructs a new ScreenTapGesture object.
+ *
+ * An uninitialized ScreenTapGesture object is considered invalid. Get valid instances
+ * of the ScreenTapGesture class from a Frame object.
+ *
+ * @class ScreenTapGesture
+ * @memberof Leap
+ * @augments Leap.Gesture
+ * @classdesc
+ * The ScreenTapGesture class represents a tapping gesture by a finger or tool.
+ *
+ * A screen tap gesture is recognized when the tip of a finger pokes forward
+ * and then springs back to approximately the original postion, as if
+ * tapping a vertical screen. The tapping finger must pause briefly before beginning the tap.
+ *
+ * ![ScreenTap](images/Leap_Gesture_Tap2.png)
+ *
+ * ScreenTap gestures are discrete. The ScreenTapGesture object representing a tap always
+ * has the state, STATE_STOP. Only one ScreenTapGesture object is created for each
+ * screen tap gesture recognized.
+ */
+var ScreenTapGesture = function(data) {
+ /**
+ * The position where the screen tap is registered.
+ *
+ * @member position
+ * @memberof Leap.ScreenTapGesture.prototype
+ * @type {number[]}
+ */
+ this.position = data.position;
+ /**
+ * The direction of finger tip motion.
+ *
+ * @member direction
+ * @memberof Leap.ScreenTapGesture.prototype
+ * @type {number[]}
+ */
+ this.direction = data.direction;
+ /**
+ * The progess value is always 1.0 for a screen tap gesture.
+ *
+ * @member progress
+ * @memberof Leap.ScreenTapGesture.prototype
+ * @type {number}
+ */
+ this.progress = data.progress;
+}
+
+ScreenTapGesture.prototype.toString = function() {
+ return "ScreenTapGesture ["+JSON.stringify(this)+"]";
+}
+
+/**
+ * Constructs a new KeyTapGesture object.
+ *
+ * An uninitialized KeyTapGesture object is considered invalid. Get valid instances
+ * of the KeyTapGesture class from a Frame object.
+ *
+ * @class KeyTapGesture
+ * @memberof Leap
+ * @augments Leap.Gesture
+ * @classdesc
+ * The KeyTapGesture class represents a tapping gesture by a finger or tool.
+ *
+ * A key tap gesture is recognized when the tip of a finger rotates down toward the
+ * palm and then springs back to approximately the original postion, as if
+ * tapping. The tapping finger must pause briefly before beginning the tap.
+ *
+ * ![KeyTap](images/Leap_Gesture_Tap.png)
+ *
+ * Key tap gestures are discrete. The KeyTapGesture object representing a tap always
+ * has the state, STATE_STOP. Only one KeyTapGesture object is created for each
+ * key tap gesture recognized.
+ */
+var KeyTapGesture = function(data) {
+ /**
+ * The position where the key tap is registered.
+ *
+ * @member position
+ * @memberof Leap.KeyTapGesture.prototype
+ * @type {number[]}
+ */
+ this.position = data.position;
+ /**
+ * The direction of finger tip motion.
+ *
+ * @member direction
+ * @memberof Leap.KeyTapGesture.prototype
+ * @type {number[]}
+ */
+ this.direction = data.direction;
+ /**
+ * The progess value is always 1.0 for a key tap gesture.
+ *
+ * @member progress
+ * @memberof Leap.KeyTapGesture.prototype
+ * @type {number}
+ */
+ this.progress = data.progress;
+}
+
+KeyTapGesture.prototype.toString = function() {
+ return "KeyTapGesture ["+JSON.stringify(this)+"]";
+}
+
+},{"events":21,"gl-matrix":23,"underscore":34}],11:[function(require,module,exports){
+var Pointable = require("./pointable")
+ , Bone = require('./bone')
+ , glMatrix = require("gl-matrix")
+ , mat3 = glMatrix.mat3
+ , vec3 = glMatrix.vec3
+ , _ = require("underscore");
+
+/**
+ * Constructs a Hand object.
+ *
+ * An uninitialized hand is considered invalid.
+ * Get valid Hand objects from a Frame object.
+ * @class Hand
+ * @memberof Leap
+ * @classdesc
+ * The Hand class reports the physical characteristics of a detected hand.
+ *
+ * Hand tracking data includes a palm position and velocity; vectors for
+ * the palm normal and direction to the fingers; properties of a sphere fit
+ * to the hand; and lists of the attached fingers and tools.
+ *
+ * Note that Hand objects can be invalid, which means that they do not contain
+ * valid tracking data and do not correspond to a physical entity. Invalid Hand
+ * objects can be the result of asking for a Hand object using an ID from an
+ * earlier frame when no Hand objects with that ID exist in the current frame.
+ * A Hand object created from the Hand constructor is also invalid.
+ * Test for validity with the [Hand.valid]{@link Leap.Hand#valid} property.
+ */
+var Hand = module.exports = function(data) {
+ /**
+ * A unique ID assigned to this Hand object, whose value remains the same
+ * across consecutive frames while the tracked hand remains visible. If
+ * tracking is lost (for example, when a hand is occluded by another hand
+ * or when it is withdrawn from or reaches the edge of the Leap field of view),
+ * the Leap may assign a new ID when it detects the hand in a future frame.
+ *
+ * Use the ID value with the {@link Frame.hand}() function to find this
+ * Hand object in future frames.
+ *
+ * @member id
+ * @memberof Leap.Hand.prototype
+ * @type {String}
+ */
+ this.id = data.id;
+ /**
+ * The center position of the palm in millimeters from the Leap origin.
+ * @member palmPosition
+ * @memberof Leap.Hand.prototype
+ * @type {number[]}
+ */
+ this.palmPosition = data.palmPosition;
+ /**
+ * The direction from the palm position toward the fingers.
+ *
+ * The direction is expressed as a unit vector pointing in the same
+ * direction as the directed line from the palm position to the fingers.
+ *
+ * @member direction
+ * @memberof Leap.Hand.prototype
+ * @type {number[]}
+ */
+ this.direction = data.direction;
+ /**
+ * The rate of change of the palm position in millimeters/second.
+ *
+ * @member palmVeclocity
+ * @memberof Leap.Hand.prototype
+ * @type {number[]}
+ */
+ this.palmVelocity = data.palmVelocity;
+ /**
+ * The normal vector to the palm. If your hand is flat, this vector will
+ * point downward, or "out" of the front surface of your palm.
+ *
+ * ![Palm Vectors](images/Leap_Palm_Vectors.png)
+ *
+ * The direction is expressed as a unit vector pointing in the same
+ * direction as the palm normal (that is, a vector orthogonal to the palm).
+ * @member palmNormal
+ * @memberof Leap.Hand.prototype
+ * @type {number[]}
+ */
+ this.palmNormal = data.palmNormal;
+ /**
+ * The center of a sphere fit to the curvature of this hand.
+ *
+ * This sphere is placed roughly as if the hand were holding a ball.
+ *
+ * ![Hand Ball](images/Leap_Hand_Ball.png)
+ * @member sphereCenter
+ * @memberof Leap.Hand.prototype
+ * @type {number[]}
+ */
+ this.sphereCenter = data.sphereCenter;
+ /**
+ * The radius of a sphere fit to the curvature of this hand, in millimeters.
+ *
+ * This sphere is placed roughly as if the hand were holding a ball. Thus the
+ * size of the sphere decreases as the fingers are curled into a fist.
+ *
+ * @member sphereRadius
+ * @memberof Leap.Hand.prototype
+ * @type {number}
+ */
+ this.sphereRadius = data.sphereRadius;
+ /**
+ * Reports whether this is a valid Hand object.
+ *
+ * @member valid
+ * @memberof Leap.Hand.prototype
+ * @type {boolean}
+ */
+ this.valid = true;
+ /**
+ * The list of Pointable objects (fingers and tools) detected in this frame
+ * that are associated with this hand, given in arbitrary order. The list
+ * can be empty if no fingers or tools associated with this hand are detected.
+ *
+ * Use the {@link Pointable} tool property to determine
+ * whether or not an item in the list represents a tool or finger.
+ * You can also get only the tools using the Hand.tools[] list or
+ * only the fingers using the Hand.fingers[] list.
+ *
+ * @member pointables[]
+ * @memberof Leap.Hand.prototype
+ * @type {Leap.Pointable[]}
+ */
+ this.pointables = [];
+ /**
+ * The list of fingers detected in this frame that are attached to
+ * this hand, given in arbitrary order.
+ *
+ * The list can be empty if no fingers attached to this hand are detected.
+ *
+ * @member fingers[]
+ * @memberof Leap.Hand.prototype
+ * @type {Leap.Pointable[]}
+ */
+ this.fingers = [];
+
+ if (data.armBasis){
+ this.arm = new Bone(this, {
+ type: 4,
+ width: data.armWidth,
+ prevJoint: data.elbow,
+ nextJoint: data.wrist,
+ basis: data.armBasis
+ });
+ }else{
+ this.arm = null;
+ }
+
+ /**
+ * The list of tools detected in this frame that are held by this
+ * hand, given in arbitrary order.
+ *
+ * The list can be empty if no tools held by this hand are detected.
+ *
+ * @member tools[]
+ * @memberof Leap.Hand.prototype
+ * @type {Leap.Pointable[]}
+ */
+ this.tools = [];
+ this._translation = data.t;
+ this._rotation = _.flatten(data.r);
+ this._scaleFactor = data.s;
+
+ /**
+ * Time the hand has been visible in seconds.
+ *
+ * @member timeVisible
+ * @memberof Leap.Hand.prototype
+ * @type {number}
+ */
+ this.timeVisible = data.timeVisible;
+
+ /**
+ * The palm position with stabalization
+ * @member stabilizedPalmPosition
+ * @memberof Leap.Hand.prototype
+ * @type {number[]}
+ */
+ this.stabilizedPalmPosition = data.stabilizedPalmPosition;
+
+ /**
+ * Reports whether this is a left or a right hand.
+ *
+ * @member type
+ * @type {String}
+ * @memberof Leap.Hand.prototype
+ */
+ this.type = data.type;
+ this.grabStrength = data.grabStrength;
+ this.pinchStrength = data.pinchStrength;
+ this.confidence = data.confidence;
+}
+
+/**
+ * The finger with the specified ID attached to this hand.
+ *
+ * Use this function to retrieve a Pointable object representing a finger
+ * attached to this hand using an ID value obtained from a previous frame.
+ * This function always returns a Pointable object, but if no finger
+ * with the specified ID is present, an invalid Pointable object is returned.
+ *
+ * Note that the ID values assigned to fingers persist across frames, but only
+ * until tracking of a particular finger is lost. If tracking of a finger is
+ * lost and subsequently regained, the new Finger object representing that
+ * finger may have a different ID than that representing the finger in an
+ * earlier frame.
+ *
+ * @method finger
+ * @memberof Leap.Hand.prototype
+ * @param {String} id The ID value of a finger from a previous frame.
+ * @returns {Leap.Pointable} The Finger object with
+ * the matching ID if one exists for this hand in this frame; otherwise, an
+ * invalid Finger object is returned.
+ */
+Hand.prototype.finger = function(id) {
+ var finger = this.frame.finger(id);
+ return (finger && (finger.handId == this.id)) ? finger : Pointable.Invalid;
+}
+
+/**
+ * The angle of rotation around the rotation axis derived from the change in
+ * orientation of this hand, and any associated fingers and tools, between the
+ * current frame and the specified frame.
+ *
+ * The returned angle is expressed in radians measured clockwise around the
+ * rotation axis (using the right-hand rule) between the start and end frames.
+ * The value is always between 0 and pi radians (0 and 180 degrees).
+ *
+ * If a corresponding Hand object is not found in sinceFrame, or if either
+ * this frame or sinceFrame are invalid Frame objects, then the angle of rotation is zero.
+ *
+ * @method rotationAngle
+ * @memberof Leap.Hand.prototype
+ * @param {Leap.Frame} sinceFrame The starting frame for computing the relative rotation.
+ * @param {numnber[]} [axis] The axis to measure rotation around.
+ * @returns {number} A positive value representing the heuristically determined
+ * rotational change of the hand between the current frame and that specified in
+ * the sinceFrame parameter.
+ */
+Hand.prototype.rotationAngle = function(sinceFrame, axis) {
+ if (!this.valid || !sinceFrame.valid) return 0.0;
+ var sinceHand = sinceFrame.hand(this.id);
+ if(!sinceHand.valid) return 0.0;
+ var rot = this.rotationMatrix(sinceFrame);
+ var cs = (rot[0] + rot[4] + rot[8] - 1.0)*0.5
+ var angle = Math.acos(cs);
+ angle = isNaN(angle) ? 0.0 : angle;
+ if (axis !== undefined) {
+ var rotAxis = this.rotationAxis(sinceFrame);
+ angle *= vec3.dot(rotAxis, vec3.normalize(vec3.create(), axis));
+ }
+ return angle;
+}
+
+/**
+ * The axis of rotation derived from the change in orientation of this hand, and
+ * any associated fingers and tools, between the current frame and the specified frame.
+ *
+ * The returned direction vector is normalized.
+ *
+ * If a corresponding Hand object is not found in sinceFrame, or if either
+ * this frame or sinceFrame are invalid Frame objects, then this method returns a zero vector.
+ *
+ * @method rotationAxis
+ * @memberof Leap.Hand.prototype
+ * @param {Leap.Frame} sinceFrame The starting frame for computing the relative rotation.
+ * @returns {number[]} A normalized direction Vector representing the axis of the heuristically determined
+ * rotational change of the hand between the current frame and that specified in the sinceFrame parameter.
+ */
+Hand.prototype.rotationAxis = function(sinceFrame) {
+ if (!this.valid || !sinceFrame.valid) return vec3.create();
+ var sinceHand = sinceFrame.hand(this.id);
+ if (!sinceHand.valid) return vec3.create();
+ return vec3.normalize(vec3.create(), [
+ this._rotation[7] - sinceHand._rotation[5],
+ this._rotation[2] - sinceHand._rotation[6],
+ this._rotation[3] - sinceHand._rotation[1]
+ ]);
+}
+
+/**
+ * The transform matrix expressing the rotation derived from the change in
+ * orientation of this hand, and any associated fingers and tools, between
+ * the current frame and the specified frame.
+ *
+ * If a corresponding Hand object is not found in sinceFrame, or if either
+ * this frame or sinceFrame are invalid Frame objects, then this method returns
+ * an identity matrix.
+ *
+ * @method rotationMatrix
+ * @memberof Leap.Hand.prototype
+ * @param {Leap.Frame} sinceFrame The starting frame for computing the relative rotation.
+ * @returns {number[]} A transformation Matrix containing the heuristically determined
+ * rotational change of the hand between the current frame and that specified in the sinceFrame parameter.
+ */
+Hand.prototype.rotationMatrix = function(sinceFrame) {
+ if (!this.valid || !sinceFrame.valid) return mat3.create();
+ var sinceHand = sinceFrame.hand(this.id);
+ if(!sinceHand.valid) return mat3.create();
+ var transpose = mat3.transpose(mat3.create(), this._rotation);
+ var m = mat3.multiply(mat3.create(), sinceHand._rotation, transpose);
+ return m;
+}
+
+/**
+ * The scale factor derived from the hand's motion between the current frame and the specified frame.
+ *
+ * The scale factor is always positive. A value of 1.0 indicates no scaling took place.
+ * Values between 0.0 and 1.0 indicate contraction and values greater than 1.0 indicate expansion.
+ *
+ * The Leap derives scaling from the relative inward or outward motion of a hand
+ * and its associated fingers and tools (independent of translation and rotation).
+ *
+ * If a corresponding Hand object is not found in sinceFrame, or if either this frame or sinceFrame
+ * are invalid Frame objects, then this method returns 1.0.
+ *
+ * @method scaleFactor
+ * @memberof Leap.Hand.prototype
+ * @param {Leap.Frame} sinceFrame The starting frame for computing the relative scaling.
+ * @returns {number} A positive value representing the heuristically determined
+ * scaling change ratio of the hand between the current frame and that specified in the sinceFrame parameter.
+ */
+Hand.prototype.scaleFactor = function(sinceFrame) {
+ if (!this.valid || !sinceFrame.valid) return 1.0;
+ var sinceHand = sinceFrame.hand(this.id);
+ if(!sinceHand.valid) return 1.0;
+
+ return Math.exp(this._scaleFactor - sinceHand._scaleFactor);
+}
+
+/**
+ * The change of position of this hand between the current frame and the specified frame
+ *
+ * The returned translation vector provides the magnitude and direction of the
+ * movement in millimeters.
+ *
+ * If a corresponding Hand object is not found in sinceFrame, or if either this frame or
+ * sinceFrame are invalid Frame objects, then this method returns a zero vector.
+ *
+ * @method translation
+ * @memberof Leap.Hand.prototype
+ * @param {Leap.Frame} sinceFrame The starting frame for computing the relative translation.
+ * @returns {number[]} A Vector representing the heuristically determined change in hand
+ * position between the current frame and that specified in the sinceFrame parameter.
+ */
+Hand.prototype.translation = function(sinceFrame) {
+ if (!this.valid || !sinceFrame.valid) return vec3.create();
+ var sinceHand = sinceFrame.hand(this.id);
+ if(!sinceHand.valid) return vec3.create();
+ return [
+ this._translation[0] - sinceHand._translation[0],
+ this._translation[1] - sinceHand._translation[1],
+ this._translation[2] - sinceHand._translation[2]
+ ];
+}
+
+/**
+ * A string containing a brief, human readable description of the Hand object.
+ * @method toString
+ * @memberof Leap.Hand.prototype
+ * @returns {String} A description of the Hand as a string.
+ */
+Hand.prototype.toString = function() {
+ return "Hand (" + this.type + ") [ id: "+ this.id + " | palm velocity:"+this.palmVelocity+" | sphere center:"+this.sphereCenter+" ] ";
+}
+
+/**
+ * The pitch angle in radians.
+ *
+ * Pitch is the angle between the negative z-axis and the projection of
+ * the vector onto the y-z plane. In other words, pitch represents rotation
+ * around the x-axis.
+ * If the vector points upward, the returned angle is between 0 and pi radians
+ * (180 degrees); if it points downward, the angle is between 0 and -pi radians.
+ *
+ * @method pitch
+ * @memberof Leap.Hand.prototype
+ * @returns {number} The angle of this vector above or below the horizon (x-z plane).
+ *
+ */
+Hand.prototype.pitch = function() {
+ return Math.atan2(this.direction[1], -this.direction[2]);
+}
+
+/**
+ * The yaw angle in radians.
+ *
+ * Yaw is the angle between the negative z-axis and the projection of
+ * the vector onto the x-z plane. In other words, yaw represents rotation
+ * around the y-axis. If the vector points to the right of the negative z-axis,
+ * then the returned angle is between 0 and pi radians (180 degrees);
+ * if it points to the left, the angle is between 0 and -pi radians.
+ *
+ * @method yaw
+ * @memberof Leap.Hand.prototype
+ * @returns {number} The angle of this vector to the right or left of the y-axis.
+ *
+ */
+Hand.prototype.yaw = function() {
+ return Math.atan2(this.direction[0], -this.direction[2]);
+}
+
+/**
+ * The roll angle in radians.
+ *
+ * Roll is the angle between the y-axis and the projection of
+ * the vector onto the x-y plane. In other words, roll represents rotation
+ * around the z-axis. If the vector points to the left of the y-axis,
+ * then the returned angle is between 0 and pi radians (180 degrees);
+ * if it points to the right, the angle is between 0 and -pi radians.
+ *
+ * @method roll
+ * @memberof Leap.Hand.prototype
+ * @returns {number} The angle of this vector to the right or left of the y-axis.
+ *
+ */
+Hand.prototype.roll = function() {
+ return Math.atan2(this.palmNormal[0], -this.palmNormal[1]);
+}
+
+/**
+ * An invalid Hand object.
+ *
+ * You can use an invalid Hand object in comparisons testing
+ * whether a given Hand instance is valid or invalid. (You can also use the
+ * Hand valid property.)
+ *
+ * @static
+ * @type {Leap.Hand}
+ * @name Invalid
+ * @memberof Leap.Hand
+ */
+Hand.Invalid = {
+ valid: false,
+ fingers: [],
+ tools: [],
+ pointables: [],
+ left: false,
+ pointable: function() { return Pointable.Invalid },
+ finger: function() { return Pointable.Invalid },
+ toString: function() { return "invalid frame" },
+ dump: function() { return this.toString(); },
+ rotationAngle: function() { return 0.0; },
+ rotationMatrix: function() { return mat3.create(); },
+ rotationAxis: function() { return vec3.create(); },
+ scaleFactor: function() { return 1.0; },
+ translation: function() { return vec3.create(); }
+};
+
+},{"./bone":1,"./pointable":15,"gl-matrix":23,"underscore":34}],12:[function(require,module,exports){
+/**
+ * Leap is the global namespace of the Leap API.
+ * @namespace Leap
+ */
+module.exports = {
+ Controller: require("./controller"),
+ Frame: require("./frame"),
+ Gesture: require("./gesture"),
+ Hand: require("./hand"),
+ Pointable: require("./pointable"),
+ Finger: require("./finger"),
+ InteractionBox: require("./interaction_box"),
+ CircularBuffer: require("./circular_buffer"),
+ UI: require("./ui"),
+ JSONProtocol: require("./protocol").JSONProtocol,
+ glMatrix: require("gl-matrix"),
+ mat3: require("gl-matrix").mat3,
+ vec3: require("gl-matrix").vec3,
+ loopController: undefined,
+ version: require('./version.js'),
+
+ /**
+ * Expose utility libraries for convenience
+ * Use carefully - they may be subject to upgrade or removal in different versions of LeapJS.
+ *
+ */
+ _: require('underscore'),
+ EventEmitter: require('events').EventEmitter,
+
+ /**
+ * The Leap.loop() function passes a frame of Leap data to your
+ * callback function and then calls window.requestAnimationFrame() after
+ * executing your callback function.
+ *
+ * Leap.loop() sets up the Leap controller and WebSocket connection for you.
+ * You do not need to create your own controller when using this method.
+ *
+ * Your callback function is called on an interval determined by the client
+ * browser. Typically, this is on an interval of 60 frames/second. The most
+ * recent frame of Leap data is passed to your callback function. If the Leap
+ * is producing frames at a slower rate than the browser frame rate, the same
+ * frame of Leap data can be passed to your function in successive animation
+ * updates.
+ *
+ * As an alternative, you can create your own Controller object and use a
+ * {@link Controller#onFrame onFrame} callback to process the data at
+ * the frame rate of the Leap device. See {@link Controller} for an
+ * example.
+ *
+ * @method Leap.loop
+ * @param {function} callback A function called when the browser is ready to
+ * draw to the screen. The most recent {@link Frame} object is passed to
+ * your callback function.
+ *
+ * ```javascript
+ * Leap.loop( function( frame ) {
+ * // ... your code here
+ * })
+ * ```
+ */
+ loop: function(opts, callback) {
+ if (opts && callback === undefined && ( ({}).toString.call(opts) === '[object Function]' ) ) {
+ callback = opts;
+ opts = {};
+ }
+
+ if (this.loopController) {
+ if (opts){
+ this.loopController.setupFrameEvents(opts);
+ }
+ }else{
+ this.loopController = new this.Controller(opts);
+ }
+
+ this.loopController.loop(callback);
+ return this.loopController;
+ },
+
+ /*
+ * Convenience method for Leap.Controller.plugin
+ */
+ plugin: function(name, options){
+ this.Controller.plugin(name, options)
+ }
+}
+
+},{"./circular_buffer":2,"./controller":6,"./finger":8,"./frame":9,"./gesture":10,"./hand":11,"./interaction_box":13,"./pointable":15,"./protocol":16,"./ui":17,"./version.js":20,"events":21,"gl-matrix":23,"underscore":34}],13:[function(require,module,exports){
+var glMatrix = require("gl-matrix")
+ , vec3 = glMatrix.vec3;
+
+/**
+ * Constructs a InteractionBox object.
+ *
+ * @class InteractionBox
+ * @memberof Leap
+ * @classdesc
+ * The InteractionBox class represents a box-shaped region completely within
+ * the field of view of the Leap Motion controller.
+ *
+ * The interaction box is an axis-aligned rectangular prism and provides
+ * normalized coordinates for hands, fingers, and tools within this box.
+ * The InteractionBox class can make it easier to map positions in the
+ * Leap Motion coordinate system to 2D or 3D coordinate systems used
+ * for application drawing.
+ *
+ * ![Interaction Box](images/Leap_InteractionBox.png)
+ *
+ * The InteractionBox region is defined by a center and dimensions along the x, y, and z axes.
+ */
+var InteractionBox = module.exports = function(data) {
+ /**
+ * Indicates whether this is a valid InteractionBox object.
+ *
+ * @member valid
+ * @type {Boolean}
+ * @memberof Leap.InteractionBox.prototype
+ */
+ this.valid = true;
+ /**
+ * The center of the InteractionBox in device coordinates (millimeters).
+ * This point is equidistant from all sides of the box.
+ *
+ * @member center
+ * @type {number[]}
+ * @memberof Leap.InteractionBox.prototype
+ */
+ this.center = data.center;
+
+ this.size = data.size;
+ /**
+ * The width of the InteractionBox in millimeters, measured along the x-axis.
+ *
+ * @member width
+ * @type {number}
+ * @memberof Leap.InteractionBox.prototype
+ */
+ this.width = data.size[0];
+ /**
+ * The height of the InteractionBox in millimeters, measured along the y-axis.
+ *
+ * @member height
+ * @type {number}
+ * @memberof Leap.InteractionBox.prototype
+ */
+ this.height = data.size[1];
+ /**
+ * The depth of the InteractionBox in millimeters, measured along the z-axis.
+ *
+ * @member depth
+ * @type {number}
+ * @memberof Leap.InteractionBox.prototype
+ */
+ this.depth = data.size[2];
+}
+
+/**
+ * Converts a position defined by normalized InteractionBox coordinates
+ * into device coordinates in millimeters.
+ *
+ * This function performs the inverse of normalizePoint().
+ *
+ * @method denormalizePoint
+ * @memberof Leap.InteractionBox.prototype
+ * @param {number[]} normalizedPosition The input position in InteractionBox coordinates.
+ * @returns {number[]} The corresponding denormalized position in device coordinates.
+ */
+InteractionBox.prototype.denormalizePoint = function(normalizedPosition) {
+ return vec3.fromValues(
+ (normalizedPosition[0] - 0.5) * this.size[0] + this.center[0],
+ (normalizedPosition[1] - 0.5) * this.size[1] + this.center[1],
+ (normalizedPosition[2] - 0.5) * this.size[2] + this.center[2]
+ );
+}
+
+/**
+ * Normalizes the coordinates of a point using the interaction box.
+ *
+ * Coordinates from the Leap Motion frame of reference (millimeters) are
+ * converted to a range of [0..1] such that the minimum value of the
+ * InteractionBox maps to 0 and the maximum value of the InteractionBox maps to 1.
+ *
+ * @method normalizePoint
+ * @memberof Leap.InteractionBox.prototype
+ * @param {number[]} position The input position in device coordinates.
+ * @param {Boolean} clamp Whether or not to limit the output value to the range [0,1]
+ * when the input position is outside the InteractionBox. Defaults to true.
+ * @returns {number[]} The normalized position.
+ */
+InteractionBox.prototype.normalizePoint = function(position, clamp) {
+ var vec = vec3.fromValues(
+ ((position[0] - this.center[0]) / this.size[0]) + 0.5,
+ ((position[1] - this.center[1]) / this.size[1]) + 0.5,
+ ((position[2] - this.center[2]) / this.size[2]) + 0.5
+ );
+
+ if (clamp) {
+ vec[0] = Math.min(Math.max(vec[0], 0), 1);
+ vec[1] = Math.min(Math.max(vec[1], 0), 1);
+ vec[2] = Math.min(Math.max(vec[2], 0), 1);
+ }
+ return vec;
+}
+
+/**
+ * Writes a brief, human readable description of the InteractionBox object.
+ *
+ * @method toString
+ * @memberof Leap.InteractionBox.prototype
+ * @returns {String} A description of the InteractionBox object as a string.
+ */
+InteractionBox.prototype.toString = function() {
+ return "InteractionBox [ width:" + this.width + " | height:" + this.height + " | depth:" + this.depth + " ]";
+}
+
+/**
+ * An invalid InteractionBox object.
+ *
+ * You can use this InteractionBox instance in comparisons testing
+ * whether a given InteractionBox instance is valid or invalid. (You can also use the
+ * InteractionBox.valid property.)
+ *
+ * @static
+ * @type {Leap.InteractionBox}
+ * @name Invalid
+ * @memberof Leap.InteractionBox
+ */
+InteractionBox.Invalid = { valid: false };
+
+},{"gl-matrix":23}],14:[function(require,module,exports){
+var Pipeline = module.exports = function (controller) {
+ this.steps = [];
+ this.controller = controller;
+}
+
+Pipeline.prototype.addStep = function (step) {
+ this.steps.push(step);
+}
+
+Pipeline.prototype.run = function (frame) {
+ var stepsLength = this.steps.length;
+ for (var i = 0; i != stepsLength; i++) {
+ if (!frame) break;
+ frame = this.steps[i](frame);
+ }
+ return frame;
+}
+
+Pipeline.prototype.removeStep = function(step){
+ var index = this.steps.indexOf(step);
+ if (index === -1) throw "Step not found in pipeline";
+ this.steps.splice(index, 1);
+}
+
+/*
+ * Wraps a plugin callback method in method which can be run inside the pipeline.
+ * This wrapper method loops the callback over objects within the frame as is appropriate,
+ * calling the callback for each in turn.
+ *
+ * @method createStepFunction
+ * @memberOf Leap.Controller.prototype
+ * @param {Controller} The controller on which the callback is called.
+ * @param {String} type What frame object the callback is run for and receives.
+ * Can be one of 'frame', 'finger', 'hand', 'pointable', 'tool'
+ * @param {function} callback The method which will be run inside the pipeline loop. Receives one argument, such as a hand.
+ * @private
+ */
+Pipeline.prototype.addWrappedStep = function (type, callback) {
+ var controller = this.controller,
+ step = function (frame) {
+ var dependencies, i, len;
+ dependencies = (type == 'frame') ? [frame] : (frame[type + 's'] || []);
+
+ for (i = 0, len = dependencies.length; i < len; i++) {
+ callback.call(controller, dependencies[i]);
+ }
+
+ return frame;
+ };
+
+ this.addStep(step);
+ return step;
+};
+},{}],15:[function(require,module,exports){
+var glMatrix = require("gl-matrix")
+ , vec3 = glMatrix.vec3;
+
+/**
+ * Constructs a Pointable object.
+ *
+ * An uninitialized pointable is considered invalid.
+ * Get valid Pointable objects from a Frame or a Hand object.
+ *
+ * @class Pointable
+ * @memberof Leap
+ * @classdesc
+ * The Pointable class reports the physical characteristics of a detected
+ * finger or tool.
+ *
+ * Both fingers and tools are classified as Pointable objects. Use the
+ * Pointable.tool property to determine whether a Pointable object represents a
+ * tool or finger. The Leap classifies a detected entity as a tool when it is
+ * thinner, straighter, and longer than a typical finger.
+ *
+ * Note that Pointable objects can be invalid, which means that they do not
+ * contain valid tracking data and do not correspond to a physical entity.
+ * Invalid Pointable objects can be the result of asking for a Pointable object
+ * using an ID from an earlier frame when no Pointable objects with that ID
+ * exist in the current frame. A Pointable object created from the Pointable
+ * constructor is also invalid. Test for validity with the Pointable.valid
+ * property.
+ */
+var Pointable = module.exports = function(data) {
+ /**
+ * Indicates whether this is a valid Pointable object.
+ *
+ * @member valid
+ * @type {Boolean}
+ * @memberof Leap.Pointable.prototype
+ */
+ this.valid = true;
+ /**
+ * A unique ID assigned to this Pointable object, whose value remains the
+ * same across consecutive frames while the tracked finger or tool remains
+ * visible. If tracking is lost (for example, when a finger is occluded by
+ * another finger or when it is withdrawn from the Leap field of view), the
+ * Leap may assign a new ID when it detects the entity in a future frame.
+ *
+ * Use the ID value with the pointable() functions defined for the
+ * {@link Frame} and {@link Frame.Hand} classes to find this
+ * Pointable object in future frames.
+ *
+ * @member id
+ * @type {String}
+ * @memberof Leap.Pointable.prototype
+ */
+ this.id = data.id;
+ this.handId = data.handId;
+ /**
+ * The estimated length of the finger or tool in millimeters.
+ *
+ * The reported length is the visible length of the finger or tool from the
+ * hand to tip. If the length isn't known, then a value of 0 is returned.
+ *
+ * @member length
+ * @type {number}
+ * @memberof Leap.Pointable.prototype
+ */
+ this.length = data.length;
+ /**
+ * Whether or not the Pointable is believed to be a tool.
+ * Tools are generally longer, thinner, and straighter than fingers.
+ *
+ * If tool is false, then this Pointable must be a finger.
+ *
+ * @member tool
+ * @type {Boolean}
+ * @memberof Leap.Pointable.prototype
+ */
+ this.tool = data.tool;
+ /**
+ * The estimated width of the tool in millimeters.
+ *
+ * The reported width is the average width of the visible portion of the
+ * tool from the hand to the tip. If the width isn't known,
+ * then a value of 0 is returned.
+ *
+ * Pointable objects representing fingers do not have a width property.
+ *
+ * @member width
+ * @type {number}
+ * @memberof Leap.Pointable.prototype
+ */
+ this.width = data.width;
+ /**
+ * The direction in which this finger or tool is pointing.
+ *
+ * The direction is expressed as a unit vector pointing in the same
+ * direction as the tip.
+ *
+ * ![Finger](images/Leap_Finger_Model.png)
+ * @member direction
+ * @type {number[]}
+ * @memberof Leap.Pointable.prototype
+ */
+ this.direction = data.direction;
+ /**
+ * The tip position in millimeters from the Leap origin.
+ * Stabilized
+ *
+ * @member stabilizedTipPosition
+ * @type {number[]}
+ * @memberof Leap.Pointable.prototype
+ */
+ this.stabilizedTipPosition = data.stabilizedTipPosition;
+ /**
+ * The tip position in millimeters from the Leap origin.
+ *
+ * @member tipPosition
+ * @type {number[]}
+ * @memberof Leap.Pointable.prototype
+ */
+ this.tipPosition = data.tipPosition;
+ /**
+ * The rate of change of the tip position in millimeters/second.
+ *
+ * @member tipVelocity
+ * @type {number[]}
+ * @memberof Leap.Pointable.prototype
+ */
+ this.tipVelocity = data.tipVelocity;
+ /**
+ * The current touch zone of this Pointable object.
+ *
+ * The Leap Motion software computes the touch zone based on a floating touch
+ * plane that adapts to the user's finger movement and hand posture. The Leap
+ * Motion software interprets purposeful movements toward this plane as potential touch
+ * points. When a Pointable moves close to the adaptive touch plane, it enters the
+ * "hovering" zone. When a Pointable reaches or passes through the plane, it enters
+ * the "touching" zone.
+ *
+ * The possible states include:
+ *
+ * * "none" -- The Pointable is outside the hovering zone.
+ * * "hovering" -- The Pointable is close to, but not touching the touch plane.
+ * * "touching" -- The Pointable has penetrated the touch plane.
+ *
+ * The touchDistance value provides a normalized indication of the distance to
+ * the touch plane when the Pointable is in the hovering or touching zones.
+ *
+ * @member touchZone
+ * @type {String}
+ * @memberof Leap.Pointable.prototype
+ */
+ this.touchZone = data.touchZone;
+ /**
+ * A value proportional to the distance between this Pointable object and the
+ * adaptive touch plane.
+ *
+ * ![Touch Distance](images/Leap_Touch_Plane.png)
+ *
+ * The touch distance is a value in the range [-1, 1]. The value 1.0 indicates the
+ * Pointable is at the far edge of the hovering zone. The value 0 indicates the
+ * Pointable is just entering the touching zone. A value of -1.0 indicates the
+ * Pointable is firmly within the touching zone. Values in between are
+ * proportional to the distance from the plane. Thus, the touchDistance of 0.5
+ * indicates that the Pointable is halfway into the hovering zone.
+ *
+ * You can use the touchDistance value to modulate visual feedback given to the
+ * user as their fingers close in on a touch target, such as a button.
+ *
+ * @member touchDistance
+ * @type {number}
+ * @memberof Leap.Pointable.prototype
+ */
+ this.touchDistance = data.touchDistance;
+
+ /**
+ * How long the pointable has been visible in seconds.
+ *
+ * @member timeVisible
+ * @type {number}
+ * @memberof Leap.Pointable.prototype
+ */
+ this.timeVisible = data.timeVisible;
+}
+
+/**
+ * A string containing a brief, human readable description of the Pointable
+ * object.
+ *
+ * @method toString
+ * @memberof Leap.Pointable.prototype
+ * @returns {String} A description of the Pointable object as a string.
+ */
+Pointable.prototype.toString = function() {
+ return "Pointable [ id:" + this.id + " " + this.length + "mmx | width:" + this.width + "mm | direction:" + this.direction + ' ]';
+}
+
+/**
+ * Returns the hand which the pointable is attached to.
+ */
+Pointable.prototype.hand = function(){
+ return this.frame.hand(this.handId);
+}
+
+/**
+ * An invalid Pointable object.
+ *
+ * You can use this Pointable instance in comparisons testing
+ * whether a given Pointable instance is valid or invalid. (You can also use the
+ * Pointable.valid property.)
+
+ * @static
+ * @type {Leap.Pointable}
+ * @name Invalid
+ * @memberof Leap.Pointable
+ */
+Pointable.Invalid = { valid: false };
+
+},{"gl-matrix":23}],16:[function(require,module,exports){
+var Frame = require('./frame')
+ , Hand = require('./hand')
+ , Pointable = require('./pointable')
+ , Finger = require('./finger')
+ , _ = require('underscore')
+ , EventEmitter = require('events').EventEmitter;
+
+var Event = function(data) {
+ this.type = data.type;
+ this.state = data.state;
+};
+
+exports.chooseProtocol = function(header) {
+ var protocol;
+ switch(header.version) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ protocol = JSONProtocol(header);
+ protocol.sendBackground = function(connection, state) {
+ connection.send(protocol.encode({background: state}));
+ }
+ protocol.sendFocused = function(connection, state) {
+ connection.send(protocol.encode({focused: state}));
+ }
+ protocol.sendOptimizeHMD = function(connection, state) {
+ connection.send(protocol.encode({optimizeHMD: state}));
+ }
+ break;
+ default:
+ throw "unrecognized version";
+ }
+ return protocol;
+}
+
+var JSONProtocol = exports.JSONProtocol = function(header) {
+
+ var protocol = function(frameData) {
+
+ if (frameData.event) {
+
+ return new Event(frameData.event);
+
+ } else {
+
+ protocol.emit('beforeFrameCreated', frameData);
+
+ var frame = new Frame(frameData);
+
+ protocol.emit('afterFrameCreated', frame, frameData);
+
+ return frame;
+
+ }
+
+ };
+
+ protocol.encode = function(message) {
+ return JSON.stringify(message);
+ };
+ protocol.version = header.version;
+ protocol.serviceVersion = header.serviceVersion;
+ protocol.versionLong = 'Version ' + header.version;
+ protocol.type = 'protocol';
+
+ _.extend(protocol, EventEmitter.prototype);
+
+ return protocol;
+};
+
+
+
+},{"./finger":8,"./frame":9,"./hand":11,"./pointable":15,"events":21,"underscore":34}],17:[function(require,module,exports){
+exports.UI = {
+ Region: require("./ui/region"),
+ Cursor: require("./ui/cursor")
+};
+},{"./ui/cursor":18,"./ui/region":19}],18:[function(require,module,exports){
+var Cursor = module.exports = function() {
+ return function(frame) {
+ var pointable = frame.pointables.sort(function(a, b) { return a.z - b.z })[0]
+ if (pointable && pointable.valid) {
+ frame.cursorPosition = pointable.tipPosition
+ }
+ return frame
+ }
+}
+
+},{}],19:[function(require,module,exports){
+var EventEmitter = require('events').EventEmitter
+ , _ = require('underscore')
+
+var Region = module.exports = function(start, end) {
+ this.start = new Vector(start)
+ this.end = new Vector(end)
+ this.enteredFrame = null
+}
+
+Region.prototype.hasPointables = function(frame) {
+ for (var i = 0; i != frame.pointables.length; i++) {
+ var position = frame.pointables[i].tipPosition
+ if (position.x >= this.start.x && position.x <= this.end.x && position.y >= this.start.y && position.y <= this.end.y && position.z >= this.start.z && position.z <= this.end.z) {
+ return true
+ }
+ }
+ return false
+}
+
+Region.prototype.listener = function(opts) {
+ var region = this
+ if (opts && opts.nearThreshold) this.setupNearRegion(opts.nearThreshold)
+ return function(frame) {
+ return region.updatePosition(frame)
+ }
+}
+
+Region.prototype.clipper = function() {
+ var region = this
+ return function(frame) {
+ region.updatePosition(frame)
+ return region.enteredFrame ? frame : null
+ }
+}
+
+Region.prototype.setupNearRegion = function(distance) {
+ var nearRegion = this.nearRegion = new Region(
+ [this.start.x - distance, this.start.y - distance, this.start.z - distance],
+ [this.end.x + distance, this.end.y + distance, this.end.z + distance]
+ )
+ var region = this
+ nearRegion.on("enter", function(frame) {
+ region.emit("near", frame)
+ })
+ nearRegion.on("exit", function(frame) {
+ region.emit("far", frame)
+ })
+ region.on('exit', function(frame) {
+ region.emit("near", frame)
+ })
+}
+
+Region.prototype.updatePosition = function(frame) {
+ if (this.nearRegion) this.nearRegion.updatePosition(frame)
+ if (this.hasPointables(frame) && this.enteredFrame == null) {
+ this.enteredFrame = frame
+ this.emit("enter", this.enteredFrame)
+ } else if (!this.hasPointables(frame) && this.enteredFrame != null) {
+ this.enteredFrame = null
+ this.emit("exit", this.enteredFrame)
+ }
+ return frame
+}
+
+Region.prototype.normalize = function(position) {
+ return new Vector([
+ (position.x - this.start.x) / (this.end.x - this.start.x),
+ (position.y - this.start.y) / (this.end.y - this.start.y),
+ (position.z - this.start.z) / (this.end.z - this.start.z)
+ ])
+}
+
+Region.prototype.mapToXY = function(position, width, height) {
+ var normalized = this.normalize(position)
+ var x = normalized.x, y = normalized.y
+ if (x > 1) x = 1
+ else if (x < -1) x = -1
+ if (y > 1) y = 1
+ else if (y < -1) y = -1
+ return [
+ (x + 1) / 2 * width,
+ (1 - y) / 2 * height,
+ normalized.z
+ ]
+}
+
+_.extend(Region.prototype, EventEmitter.prototype)
+},{"events":21,"underscore":34}],20:[function(require,module,exports){
+// This file is automatically updated from package.json by grunt.
+module.exports = {
+ full: '1.0.0',
+ major: 1,
+ minor: 0,
+ dot: 0
+}
+},{}],21:[function(require,module,exports){
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+var objectCreate = Object.create || objectCreatePolyfill
+var objectKeys = Object.keys || objectKeysPolyfill
+var bind = Function.prototype.bind || functionBindPolyfill
+
+function EventEmitter() {
+ if (!this._events || !Object.prototype.hasOwnProperty.call(this, '_events')) {
+ this._events = objectCreate(null);
+ this._eventsCount = 0;
+ }
+
+ this._maxListeners = this._maxListeners || undefined;
+}
+module.exports = EventEmitter;
+
+// Backwards-compat with node 0.10.x
+EventEmitter.EventEmitter = EventEmitter;
+
+EventEmitter.prototype._events = undefined;
+EventEmitter.prototype._maxListeners = undefined;
+
+// By default EventEmitters will print a warning if more than 10 listeners are
+// added to it. This is a useful default which helps finding memory leaks.
+var defaultMaxListeners = 10;
+
+var hasDefineProperty;
+try {
+ var o = {};
+ if (Object.defineProperty) Object.defineProperty(o, 'x', { value: 0 });
+ hasDefineProperty = o.x === 0;
+} catch (err) { hasDefineProperty = false }
+if (hasDefineProperty) {
+ Object.defineProperty(EventEmitter, 'defaultMaxListeners', {
+ enumerable: true,
+ get: function() {
+ return defaultMaxListeners;
+ },
+ set: function(arg) {
+ // check whether the input is a positive number (whose value is zero or
+ // greater and not a NaN).
+ if (typeof arg !== 'number' || arg < 0 || arg !== arg)
+ throw new TypeError('"defaultMaxListeners" must be a positive number');
+ defaultMaxListeners = arg;
+ }
+ });
+} else {
+ EventEmitter.defaultMaxListeners = defaultMaxListeners;
+}
+
+// Obviously not all Emitters should be limited to 10. This function allows
+// that to be increased. Set to zero for unlimited.
+EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {
+ if (typeof n !== 'number' || n < 0 || isNaN(n))
+ throw new TypeError('"n" argument must be a positive number');
+ this._maxListeners = n;
+ return this;
+};
+
+function $getMaxListeners(that) {
+ if (that._maxListeners === undefined)
+ return EventEmitter.defaultMaxListeners;
+ return that._maxListeners;
+}
+
+EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
+ return $getMaxListeners(this);
+};
+
+// These standalone emit* functions are used to optimize calling of event
+// handlers for fast cases because emit() itself often has a variable number of
+// arguments and can be deoptimized because of that. These functions always have
+// the same number of arguments and thus do not get deoptimized, so the code
+// inside them can execute faster.
+function emitNone(handler, isFn, self) {
+ if (isFn)
+ handler.call(self);
+ else {
+ var len = handler.length;
+ var listeners = arrayClone(handler, len);
+ for (var i = 0; i < len; ++i)
+ listeners[i].call(self);
+ }
+}
+function emitOne(handler, isFn, self, arg1) {
+ if (isFn)
+ handler.call(self, arg1);
+ else {
+ var len = handler.length;
+ var listeners = arrayClone(handler, len);
+ for (var i = 0; i < len; ++i)
+ listeners[i].call(self, arg1);
+ }
+}
+function emitTwo(handler, isFn, self, arg1, arg2) {
+ if (isFn)
+ handler.call(self, arg1, arg2);
+ else {
+ var len = handler.length;
+ var listeners = arrayClone(handler, len);
+ for (var i = 0; i < len; ++i)
+ listeners[i].call(self, arg1, arg2);
+ }
+}
+function emitThree(handler, isFn, self, arg1, arg2, arg3) {
+ if (isFn)
+ handler.call(self, arg1, arg2, arg3);
+ else {
+ var len = handler.length;
+ var listeners = arrayClone(handler, len);
+ for (var i = 0; i < len; ++i)
+ listeners[i].call(self, arg1, arg2, arg3);
+ }
+}
+
+function emitMany(handler, isFn, self, args) {
+ if (isFn)
+ handler.apply(self, args);
+ else {
+ var len = handler.length;
+ var listeners = arrayClone(handler, len);
+ for (var i = 0; i < len; ++i)
+ listeners[i].apply(self, args);
+ }
+}
+
+EventEmitter.prototype.emit = function emit(type) {
+ var er, handler, len, args, i, events;
+ var doError = (type === 'error');
+
+ events = this._events;
+ if (events)
+ doError = (doError && events.error == null);
+ else if (!doError)
+ return false;
+
+ // If there is no 'error' event listener then throw.
+ if (doError) {
+ if (arguments.length > 1)
+ er = arguments[1];
+ if (er instanceof Error) {
+ throw er; // Unhandled 'error' event
+ } else {
+ // At least give some kind of context to the user
+ var err = new Error('Unhandled "error" event. (' + er + ')');
+ err.context = er;
+ throw err;
+ }
+ return false;
+ }
+
+ handler = events[type];
+
+ if (!handler)
+ return false;
+
+ var isFn = typeof handler === 'function';
+ len = arguments.length;
+ switch (len) {
+ // fast cases
+ case 1:
+ emitNone(handler, isFn, this);
+ break;
+ case 2:
+ emitOne(handler, isFn, this, arguments[1]);
+ break;
+ case 3:
+ emitTwo(handler, isFn, this, arguments[1], arguments[2]);
+ break;
+ case 4:
+ emitThree(handler, isFn, this, arguments[1], arguments[2], arguments[3]);
+ break;
+ // slower
+ default:
+ args = new Array(len - 1);
+ for (i = 1; i < len; i++)
+ args[i - 1] = arguments[i];
+ emitMany(handler, isFn, this, args);
+ }
+
+ return true;
+};
+
+function _addListener(target, type, listener, prepend) {
+ var m;
+ var events;
+ var existing;
+
+ if (typeof listener !== 'function')
+ throw new TypeError('"listener" argument must be a function');
+
+ events = target._events;
+ if (!events) {
+ events = target._events = objectCreate(null);
+ target._eventsCount = 0;
+ } else {
+ // To avoid recursion in the case that type === "newListener"! Before
+ // adding it to the listeners, first emit "newListener".
+ if (events.newListener) {
+ target.emit('newListener', type,
+ listener.listener ? listener.listener : listener);
+
+ // Re-assign `events` because a newListener handler could have caused the
+ // this._events to be assigned to a new object
+ events = target._events;
+ }
+ existing = events[type];
+ }
+
+ if (!existing) {
+ // Optimize the case of one listener. Don't need the extra array object.
+ existing = events[type] = listener;
+ ++target._eventsCount;
+ } else {
+ if (typeof existing === 'function') {
+ // Adding the second element, need to change to array.
+ existing = events[type] =
+ prepend ? [listener, existing] : [existing, listener];
+ } else {
+ // If we've already got an array, just append.
+ if (prepend) {
+ existing.unshift(listener);
+ } else {
+ existing.push(listener);
+ }
+ }
+
+ // Check for listener leak
+ if (!existing.warned) {
+ m = $getMaxListeners(target);
+ if (m && m > 0 && existing.length > m) {
+ existing.warned = true;
+ var w = new Error('Possible EventEmitter memory leak detected. ' +
+ existing.length + ' "' + String(type) + '" listeners ' +
+ 'added. Use emitter.setMaxListeners() to ' +
+ 'increase limit.');
+ w.name = 'MaxListenersExceededWarning';
+ w.emitter = target;
+ w.type = type;
+ w.count = existing.length;
+ if (typeof console === 'object' && console.warn) {
+ console.warn('%s: %s', w.name, w.message);
+ }
+ }
+ }
+ }
+
+ return target;
+}
+
+EventEmitter.prototype.addListener = function addListener(type, listener) {
+ return _addListener(this, type, listener, false);
+};
+
+EventEmitter.prototype.on = EventEmitter.prototype.addListener;
+
+EventEmitter.prototype.prependListener =
+ function prependListener(type, listener) {
+ return _addListener(this, type, listener, true);
+ };
+
+function onceWrapper() {
+ if (!this.fired) {
+ this.target.removeListener(this.type, this.wrapFn);
+ this.fired = true;
+ switch (arguments.length) {
+ case 0:
+ return this.listener.call(this.target);
+ case 1:
+ return this.listener.call(this.target, arguments[0]);
+ case 2:
+ return this.listener.call(this.target, arguments[0], arguments[1]);
+ case 3:
+ return this.listener.call(this.target, arguments[0], arguments[1],
+ arguments[2]);
+ default:
+ var args = new Array(arguments.length);
+ for (var i = 0; i < args.length; ++i)
+ args[i] = arguments[i];
+ this.listener.apply(this.target, args);
+ }
+ }
+}
+
+function _onceWrap(target, type, listener) {
+ var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener };
+ var wrapped = bind.call(onceWrapper, state);
+ wrapped.listener = listener;
+ state.wrapFn = wrapped;
+ return wrapped;
+}
+
+EventEmitter.prototype.once = function once(type, listener) {
+ if (typeof listener !== 'function')
+ throw new TypeError('"listener" argument must be a function');
+ this.on(type, _onceWrap(this, type, listener));
+ return this;
+};
+
+EventEmitter.prototype.prependOnceListener =
+ function prependOnceListener(type, listener) {
+ if (typeof listener !== 'function')
+ throw new TypeError('"listener" argument must be a function');
+ this.prependListener(type, _onceWrap(this, type, listener));
+ return this;
+ };
+
+// Emits a 'removeListener' event if and only if the listener was removed.
+EventEmitter.prototype.removeListener =
+ function removeListener(type, listener) {
+ var list, events, position, i, originalListener;
+
+ if (typeof listener !== 'function')
+ throw new TypeError('"listener" argument must be a function');
+
+ events = this._events;
+ if (!events)
+ return this;
+
+ list = events[type];
+ if (!list)
+ return this;
+
+ if (list === listener || list.listener === listener) {
+ if (--this._eventsCount === 0)
+ this._events = objectCreate(null);
+ else {
+ delete events[type];
+ if (events.removeListener)
+ this.emit('removeListener', type, list.listener || listener);
+ }
+ } else if (typeof list !== 'function') {
+ position = -1;
+
+ for (i = list.length - 1; i >= 0; i--) {
+ if (list[i] === listener || list[i].listener === listener) {
+ originalListener = list[i].listener;
+ position = i;
+ break;
+ }
+ }
+
+ if (position < 0)
+ return this;
+
+ if (position === 0)
+ list.shift();
+ else
+ spliceOne(list, position);
+
+ if (list.length === 1)
+ events[type] = list[0];
+
+ if (events.removeListener)
+ this.emit('removeListener', type, originalListener || listener);
+ }
+
+ return this;
+ };
+
+EventEmitter.prototype.removeAllListeners =
+ function removeAllListeners(type) {
+ var listeners, events, i;
+
+ events = this._events;
+ if (!events)
+ return this;
+
+ // not listening for removeListener, no need to emit
+ if (!events.removeListener) {
+ if (arguments.length === 0) {
+ this._events = objectCreate(null);
+ this._eventsCount = 0;
+ } else if (events[type]) {
+ if (--this._eventsCount === 0)
+ this._events = objectCreate(null);
+ else
+ delete events[type];
+ }
+ return this;
+ }
+
+ // emit removeListener for all listeners on all events
+ if (arguments.length === 0) {
+ var keys = objectKeys(events);
+ var key;
+ for (i = 0; i < keys.length; ++i) {
+ key = keys[i];
+ if (key === 'removeListener') continue;
+ this.removeAllListeners(key);
+ }
+ this.removeAllListeners('removeListener');
+ this._events = objectCreate(null);
+ this._eventsCount = 0;
+ return this;
+ }
+
+ listeners = events[type];
+
+ if (typeof listeners === 'function') {
+ this.removeListener(type, listeners);
+ } else if (listeners) {
+ // LIFO order
+ for (i = listeners.length - 1; i >= 0; i--) {
+ this.removeListener(type, listeners[i]);
+ }
+ }
+
+ return this;
+ };
+
+function _listeners(target, type, unwrap) {
+ var events = target._events;
+
+ if (!events)
+ return [];
+
+ var evlistener = events[type];
+ if (!evlistener)
+ return [];
+
+ if (typeof evlistener === 'function')
+ return unwrap ? [evlistener.listener || evlistener] : [evlistener];
+
+ return unwrap ? unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);
+}
+
+EventEmitter.prototype.listeners = function listeners(type) {
+ return _listeners(this, type, true);
+};
+
+EventEmitter.prototype.rawListeners = function rawListeners(type) {
+ return _listeners(this, type, false);
+};
+
+EventEmitter.listenerCount = function(emitter, type) {
+ if (typeof emitter.listenerCount === 'function') {
+ return emitter.listenerCount(type);
+ } else {
+ return listenerCount.call(emitter, type);
+ }
+};
+
+EventEmitter.prototype.listenerCount = listenerCount;
+function listenerCount(type) {
+ var events = this._events;
+
+ if (events) {
+ var evlistener = events[type];
+
+ if (typeof evlistener === 'function') {
+ return 1;
+ } else if (evlistener) {
+ return evlistener.length;
+ }
+ }
+
+ return 0;
+}
+
+EventEmitter.prototype.eventNames = function eventNames() {
+ return this._eventsCount > 0 ? Reflect.ownKeys(this._events) : [];
+};
+
+// About 1.5x faster than the two-arg version of Array#splice().
+function spliceOne(list, index) {
+ for (var i = index, k = i + 1, n = list.length; k < n; i += 1, k += 1)
+ list[i] = list[k];
+ list.pop();
+}
+
+function arrayClone(arr, n) {
+ var copy = new Array(n);
+ for (var i = 0; i < n; ++i)
+ copy[i] = arr[i];
+ return copy;
+}
+
+function unwrapListeners(arr) {
+ var ret = new Array(arr.length);
+ for (var i = 0; i < ret.length; ++i) {
+ ret[i] = arr[i].listener || arr[i];
+ }
+ return ret;
+}
+
+function objectCreatePolyfill(proto) {
+ var F = function() {};
+ F.prototype = proto;
+ return new F;
+}
+function objectKeysPolyfill(obj) {
+ var keys = [];
+ for (var k in obj) if (Object.prototype.hasOwnProperty.call(obj, k)) {
+ keys.push(k);
+ }
+ return k;
+}
+function functionBindPolyfill(context) {
+ var fn = this;
+ return function () {
+ return fn.apply(context, arguments);
+ };
+}
+
+},{}],22:[function(require,module,exports){
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.setMatrixArrayType = setMatrixArrayType;
+exports.toRadian = toRadian;
+exports.equals = equals;
+exports.RANDOM = exports.ARRAY_TYPE = exports.EPSILON = void 0;
+
+/**
+ * Common utilities
+ * @module glMatrix
+ */
+// Configuration Constants
+var EPSILON = 0.000001;
+exports.EPSILON = EPSILON;
+var ARRAY_TYPE = typeof Float32Array !== 'undefined' ? Float32Array : Array;
+exports.ARRAY_TYPE = ARRAY_TYPE;
+var RANDOM = Math.random;
+/**
+ * Sets the type of array used when creating new vectors and matrices
+ *
+ * @param {Type} type Array type, such as Float32Array or Array
+ */
+
+exports.RANDOM = RANDOM;
+
+function setMatrixArrayType(type) {
+ exports.ARRAY_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);
+};
+},{}],23:[function(require,module,exports){
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.vec4 = exports.vec3 = exports.vec2 = exports.quat2 = exports.quat = exports.mat4 = exports.mat3 = exports.mat2d = exports.mat2 = exports.glMatrix = void 0;
+
+var glMatrix = _interopRequireWildcard(require("./common.js"));
+
+exports.glMatrix = glMatrix;
+
+var mat2 = _interopRequireWildcard(require("./mat2.js"));
+
+exports.mat2 = mat2;
+
+var mat2d = _interopRequireWildcard(require("./mat2d.js"));
+
+exports.mat2d = mat2d;
+
+var mat3 = _interopRequireWildcard(require("./mat3.js"));
+
+exports.mat3 = mat3;
+
+var mat4 = _interopRequireWildcard(require("./mat4.js"));
+
+exports.mat4 = mat4;
+
+var quat = _interopRequireWildcard(require("./quat.js"));
+
+exports.quat = quat;
+
+var quat2 = _interopRequireWildcard(require("./quat2.js"));
+
+exports.quat2 = quat2;
+
+var vec2 = _interopRequireWildcard(require("./vec2.js"));
+
+exports.vec2 = vec2;
+
+var vec3 = _interopRequireWildcard(require("./vec3.js"));
+
+exports.vec3 = vec3;
+
+var vec4 = _interopRequireWildcard(require("./vec4.js"));
+
+exports.vec4 = vec4;
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj["default"] = obj; return newObj; } }
+},{"./common.js":22,"./mat2.js":24,"./mat2d.js":25,"./mat3.js":26,"./mat4.js":27,"./quat.js":28,"./quat2.js":29,"./vec2.js":30,"./vec3.js":31,"./vec4.js":32}],24:[function(require,module,exports){
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.create = create;
+exports.clone = clone;
+exports.copy = copy;
+exports.identity = identity;
+exports.fromValues = fromValues;
+exports.set = set;
+exports.transpose = transpose;
+exports.invert = invert;
+exports.adjoint = adjoint;
+exports.determinant = determinant;
+exports.multiply = multiply;
+exports.rotate = rotate;
+exports.scale = scale;
+exports.fromRotation = fromRotation;
+exports.fromScaling = fromScaling;
+exports.str = str;
+exports.frob = frob;
+exports.LDU = LDU;
+exports.add = add;
+exports.subtract = subtract;
+exports.exactEquals = exactEquals;
+exports.equals = equals;
+exports.multiplyScalar = multiplyScalar;
+exports.multiplyScalarAndAdd = multiplyScalarAndAdd;
+exports.sub = exports.mul = void 0;
+
+var glMatrix = _interopRequireWildcard(require("./common.js"));
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj["default"] = obj; return newObj; } }
+
+/**
+ * 2x2 Matrix
+ * @module mat2
+ */
+
+/**
+ * Creates a new identity mat2
+ *
+ * @returns {mat2} a new 2x2 matrix
+ */
+function create() {
+ var out = new glMatrix.ARRAY_TYPE(4);
+
+ if (glMatrix.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 {mat2} a matrix to clone
+ * @returns {mat2} a new 2x2 matrix
+ */
+
+
+function clone(a) {
+ var out = new glMatrix.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 {mat2} 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 glMatrix.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 {mat2} 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 {mat2} 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 {mat2} 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 {mat2} 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 {mat2} a the first operand
+ * @param {mat2} 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 {mat2} 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 {mat2} a the matrix to rotate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat2} out
+ **/
+
+
+function scale(out, a, v) {
+ var a0 = a[0],
+ a1 = a[1],
+ a2 = a[2],
+ a3 = a[3];
+ var v0 = v[0],
+ v1 = v[1];
+ out[0] = a0 * v0;
+ out[1] = a1 * v0;
+ out[2] = a2 * v1;
+ out[3] = a3 * v1;
+ return out;
+}
+/**
+ * Creates a matrix from a given angle
+ * This is equivalent to (but much faster than):
+ *
+ * mat2.identity(dest);
+ * mat2.rotate(dest, dest, rad);
+ *
+ * @param {mat2} out mat2 receiving operation result
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat2} out
+ */
+
+
+function fromRotation(out, rad) {
+ var s = Math.sin(rad);
+ var c = Math.cos(rad);
+ out[0] = c;
+ out[1] = s;
+ out[2] = -s;
+ out[3] = c;
+ return out;
+}
+/**
+ * Creates a matrix from a vector scaling
+ * This is equivalent to (but much faster than):
+ *
+ * mat2.identity(dest);
+ * mat2.scale(dest, dest, vec);
+ *
+ * @param {mat2} out mat2 receiving operation result
+ * @param {vec2} 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 {mat2} 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 {mat2} 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 {mat2} L the lower triangular matrix
+ * @param {mat2} D the diagonal matrix
+ * @param {mat2} U the upper triangular matrix
+ * @param {mat2} 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 {mat2} a the first operand
+ * @param {mat2} 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 {mat2} a the first operand
+ * @param {mat2} 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 {mat2} a The first matrix.
+ * @param {mat2} 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 {mat2} a The first matrix.
+ * @param {mat2} b The second matrix.
+ * @returns {Boolean} True if the matrices are equal, false otherwise.
+ */
+
+
+function 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) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= glMatrix.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 {mat2} 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 {mat2} a the first operand
+ * @param {mat2} 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
+ */
+
+exports.mul = mul;
+var sub = subtract;
+exports.sub = sub;
+},{"./common.js":22}],25:[function(require,module,exports){
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.create = create;
+exports.clone = clone;
+exports.copy = copy;
+exports.identity = identity;
+exports.fromValues = fromValues;
+exports.set = set;
+exports.invert = invert;
+exports.determinant = determinant;
+exports.multiply = multiply;
+exports.rotate = rotate;
+exports.scale = scale;
+exports.translate = translate;
+exports.fromRotation = fromRotation;
+exports.fromScaling = fromScaling;
+exports.fromTranslation = fromTranslation;
+exports.str = str;
+exports.frob = frob;
+exports.add = add;
+exports.subtract = subtract;
+exports.multiplyScalar = multiplyScalar;
+exports.multiplyScalarAndAdd = multiplyScalarAndAdd;
+exports.exactEquals = exactEquals;
+exports.equals = equals;
+exports.sub = exports.mul = void 0;
+
+var glMatrix = _interopRequireWildcard(require("./common.js"));
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj["default"] = obj; return newObj; } }
+
+/**
+ * 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 create() {
+ var out = new glMatrix.ARRAY_TYPE(6);
+
+ if (glMatrix.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 {mat2d} a matrix to clone
+ * @returns {mat2d} a new 2x3 matrix
+ */
+
+
+function clone(a) {
+ var out = new glMatrix.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 {mat2d} a the source matrix
+ * @returns {mat2d} out
+ */
+
+
+function 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 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 fromValues(a, b, c, d, tx, ty) {
+ var out = new glMatrix.ARRAY_TYPE(6);
+ out[0] = a;
+ out[1] = b;
+ out[2] = c;
+ out[3] = d;
+ out[4] = tx;
+ out[5] = ty;
+ return out;
+}
+/**
+ * Set the components of a mat2d to the given values
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {Number} a Component A (index 0)
+ * @param {Number} b Component B (index 1)
+ * @param {Number} c Component C (index 2)
+ * @param {Number} d Component D (index 3)
+ * @param {Number} tx Component TX (index 4)
+ * @param {Number} ty Component TY (index 5)
+ * @returns {mat2d} out
+ */
+
+
+function set(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 {mat2d} a the source matrix
+ * @returns {mat2d} out
+ */
+
+
+function 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 {mat2d} a the source matrix
+ * @returns {Number} determinant of a
+ */
+
+
+function determinant(a) {
+ return a[0] * a[3] - a[1] * a[2];
+}
+/**
+ * Multiplies two mat2d's
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the first operand
+ * @param {mat2d} b the second operand
+ * @returns {mat2d} out
+ */
+
+
+function 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 {mat2d} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat2d} out
+ */
+
+
+function 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 {mat2d} a the matrix to translate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat2d} out
+ **/
+
+
+function 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 {mat2d} a the matrix to translate
+ * @param {vec2} v the vec2 to translate the matrix by
+ * @returns {mat2d} out
+ **/
+
+
+function translate(out, a, v) {
+ var a0 = a[0],
+ a1 = a[1],
+ a2 = a[2],
+ a3 = a[3],
+ a4 = a[4],
+ a5 = a[5];
+ var v0 = v[0],
+ v1 = v[1];
+ out[0] = a0;
+ out[1] = a1;
+ out[2] = a2;
+ out[3] = a3;
+ out[4] = a0 * v0 + a2 * v1 + a4;
+ out[5] = a1 * v0 + a3 * v1 + a5;
+ return out;
+}
+/**
+ * Creates a matrix from a given angle
+ * This is equivalent to (but much faster than):
+ *
+ * mat2d.identity(dest);
+ * mat2d.rotate(dest, dest, rad);
+ *
+ * @param {mat2d} out mat2d receiving operation result
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat2d} out
+ */
+
+
+function fromRotation(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 {vec2} v Scaling vector
+ * @returns {mat2d} out
+ */
+
+
+function 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 {vec2} 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 {mat2d} a matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+
+
+function str(a) {
+ return 'mat2d(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + a[4] + ', ' + a[5] + ')';
+}
+/**
+ * Returns Frobenius norm of a mat2d
+ *
+ * @param {mat2d} 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], a[4], a[5], 1);
+}
+/**
+ * Adds two mat2d's
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the first operand
+ * @param {mat2d} b the second operand
+ * @returns {mat2d} 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];
+ 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 {mat2d} a the first operand
+ * @param {mat2d} b the second operand
+ * @returns {mat2d} 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];
+ 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 {mat2d} a the matrix to scale
+ * @param {Number} b amount to scale the matrix's elements by
+ * @returns {mat2d} 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;
+ 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 {mat2d} a the first operand
+ * @param {mat2d} b the second operand
+ * @param {Number} scale the amount to scale b's elements by before adding
+ * @returns {mat2d} 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;
+ 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 {mat2d} a The first matrix.
+ * @param {mat2d} 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] && a[4] === b[4] && a[5] === b[5];
+}
+/**
+ * Returns whether or not the matrices have approximately the same elements in the same position.
+ *
+ * @param {mat2d} a The first matrix.
+ * @param {mat2d} b The second matrix.
+ * @returns {Boolean} True if the matrices are equal, false otherwise.
+ */
+
+
+function 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) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5));
+}
+/**
+ * Alias for {@link mat2d.multiply}
+ * @function
+ */
+
+
+var mul = multiply;
+/**
+ * Alias for {@link mat2d.subtract}
+ * @function
+ */
+
+exports.mul = mul;
+var sub = subtract;
+exports.sub = sub;
+},{"./common.js":22}],26:[function(require,module,exports){
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.create = create;
+exports.fromMat4 = fromMat4;
+exports.clone = clone;
+exports.copy = copy;
+exports.fromValues = fromValues;
+exports.set = set;
+exports.identity = identity;
+exports.transpose = transpose;
+exports.invert = invert;
+exports.adjoint = adjoint;
+exports.determinant = determinant;
+exports.multiply = multiply;
+exports.translate = translate;
+exports.rotate = rotate;
+exports.scale = scale;
+exports.fromTranslation = fromTranslation;
+exports.fromRotation = fromRotation;
+exports.fromScaling = fromScaling;
+exports.fromMat2d = fromMat2d;
+exports.fromQuat = fromQuat;
+exports.normalFromMat4 = normalFromMat4;
+exports.projection = projection;
+exports.str = str;
+exports.frob = frob;
+exports.add = add;
+exports.subtract = subtract;
+exports.multiplyScalar = multiplyScalar;
+exports.multiplyScalarAndAdd = multiplyScalarAndAdd;
+exports.exactEquals = exactEquals;
+exports.equals = equals;
+exports.sub = exports.mul = void 0;
+
+var glMatrix = _interopRequireWildcard(require("./common.js"));
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj["default"] = obj; return newObj; } }
+
+/**
+ * 3x3 Matrix
+ * @module mat3
+ */
+
+/**
+ * Creates a new identity mat3
+ *
+ * @returns {mat3} a new 3x3 matrix
+ */
+function create() {
+ var out = new glMatrix.ARRAY_TYPE(9);
+
+ if (glMatrix.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 {mat4} 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 {mat3} a matrix to clone
+ * @returns {mat3} a new 3x3 matrix
+ */
+
+
+function clone(a) {
+ var out = new glMatrix.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 {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+
+
+function 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 fromValues(m00, m01, m02, m10, m11, m12, m20, m21, m22) {
+ var out = new glMatrix.ARRAY_TYPE(9);
+ out[0] = m00;
+ out[1] = m01;
+ out[2] = m02;
+ out[3] = m10;
+ out[4] = m11;
+ out[5] = m12;
+ out[6] = m20;
+ out[7] = m21;
+ out[8] = m22;
+ return out;
+}
+/**
+ * Set the components of a mat3 to the given values
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {Number} m00 Component in column 0, row 0 position (index 0)
+ * @param {Number} m01 Component in column 0, row 1 position (index 1)
+ * @param {Number} m02 Component in column 0, row 2 position (index 2)
+ * @param {Number} m10 Component in column 1, row 0 position (index 3)
+ * @param {Number} m11 Component in column 1, row 1 position (index 4)
+ * @param {Number} m12 Component in column 1, row 2 position (index 5)
+ * @param {Number} m20 Component in column 2, row 0 position (index 6)
+ * @param {Number} m21 Component in column 2, row 1 position (index 7)
+ * @param {Number} m22 Component in column 2, row 2 position (index 8)
+ * @returns {mat3} out
+ */
+
+
+function set(out, m00, m01, m02, m10, m11, m12, m20, m21, m22) {
+ out[0] = m00;
+ out[1] = m01;
+ out[2] = m02;
+ out[3] = m10;
+ out[4] = m11;
+ out[5] = m12;
+ out[6] = m20;
+ out[7] = m21;
+ out[8] = m22;
+ return out;
+}
+/**
+ * Set a mat3 to the identity matrix
+ *
+ * @param {mat3} out the receiving matrix
+ * @returns {mat3} out
+ */
+
+
+function identity(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 {mat3} a the source matrix
+ * @returns {mat3} 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 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 {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+
+
+function 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 {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+
+
+function 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 {mat3} a the source matrix
+ * @returns {Number} determinant of a
+ */
+
+
+function 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 {mat3} a the first operand
+ * @param {mat3} b the second operand
+ * @returns {mat3} out
+ */
+
+
+function 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 {mat3} a the matrix to translate
+ * @param {vec2} v vector to translate by
+ * @returns {mat3} out
+ */
+
+
+function 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 {mat3} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat3} out
+ */
+
+
+function 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 {mat3} a the matrix to rotate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat3} out
+ **/
+
+function 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 {vec2} v Translation vector
+ * @returns {mat3} out
+ */
+
+
+function 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 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 {vec2} v Scaling vector
+ * @returns {mat3} out
+ */
+
+
+function 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 {mat2d} 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 {quat} 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 {mat4} 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 {mat3} a matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+
+
+function 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 {mat3} 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], a[4], a[5], a[6], a[7], a[8]);
+}
+/**
+ * Adds two mat3's
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the first operand
+ * @param {mat3} b the second operand
+ * @returns {mat3} 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];
+ 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 {mat3} a the first operand
+ * @param {mat3} b the second operand
+ * @returns {mat3} 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];
+ 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 {mat3} a the matrix to scale
+ * @param {Number} b amount to scale the matrix's elements by
+ * @returns {mat3} 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;
+ 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 {mat3} a the first operand
+ * @param {mat3} b the second operand
+ * @param {Number} scale the amount to scale b's elements by before adding
+ * @returns {mat3} 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;
+ 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 {mat3} a The first matrix.
+ * @param {mat3} 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] && 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 {mat3} a The first matrix.
+ * @param {mat3} b The second matrix.
+ * @returns {Boolean} True if the matrices are equal, false otherwise.
+ */
+
+
+function 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) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8));
+}
+/**
+ * Alias for {@link mat3.multiply}
+ * @function
+ */
+
+
+var mul = multiply;
+/**
+ * Alias for {@link mat3.subtract}
+ * @function
+ */
+
+exports.mul = mul;
+var sub = subtract;
+exports.sub = sub;
+},{"./common.js":22}],27:[function(require,module,exports){
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.create = create;
+exports.clone = clone;
+exports.copy = copy;
+exports.fromValues = fromValues;
+exports.set = set;
+exports.identity = identity;
+exports.transpose = transpose;
+exports.invert = invert;
+exports.adjoint = adjoint;
+exports.determinant = determinant;
+exports.multiply = multiply;
+exports.translate = translate;
+exports.scale = scale;
+exports.rotate = rotate;
+exports.rotateX = rotateX;
+exports.rotateY = rotateY;
+exports.rotateZ = rotateZ;
+exports.fromTranslation = fromTranslation;
+exports.fromScaling = fromScaling;
+exports.fromRotation = fromRotation;
+exports.fromXRotation = fromXRotation;
+exports.fromYRotation = fromYRotation;
+exports.fromZRotation = fromZRotation;
+exports.fromRotationTranslation = fromRotationTranslation;
+exports.fromQuat2 = fromQuat2;
+exports.getTranslation = getTranslation;
+exports.getScaling = getScaling;
+exports.getRotation = getRotation;
+exports.fromRotationTranslationScale = fromRotationTranslationScale;
+exports.fromRotationTranslationScaleOrigin = fromRotationTranslationScaleOrigin;
+exports.fromQuat = fromQuat;
+exports.frustum = frustum;
+exports.perspective = perspective;
+exports.perspectiveFromFieldOfView = perspectiveFromFieldOfView;
+exports.ortho = ortho;
+exports.lookAt = lookAt;
+exports.targetTo = targetTo;
+exports.str = str;
+exports.frob = frob;
+exports.add = add;
+exports.subtract = subtract;
+exports.multiplyScalar = multiplyScalar;
+exports.multiplyScalarAndAdd = multiplyScalarAndAdd;
+exports.exactEquals = exactEquals;
+exports.equals = equals;
+exports.sub = exports.mul = void 0;
+
+var glMatrix = _interopRequireWildcard(require("./common.js"));
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj["default"] = obj; return newObj; } }
+
+/**
+ * 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 create() {
+ var out = new glMatrix.ARRAY_TYPE(16);
+
+ if (glMatrix.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 {mat4} a matrix to clone
+ * @returns {mat4} a new 4x4 matrix
+ */
+
+
+function clone(a) {
+ var out = new glMatrix.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 {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+
+
+function 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 fromValues(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
+ var out = new glMatrix.ARRAY_TYPE(16);
+ out[0] = m00;
+ out[1] = m01;
+ out[2] = m02;
+ out[3] = m03;
+ out[4] = m10;
+ out[5] = m11;
+ out[6] = m12;
+ out[7] = m13;
+ out[8] = m20;
+ out[9] = m21;
+ out[10] = m22;
+ out[11] = m23;
+ out[12] = m30;
+ out[13] = m31;
+ out[14] = m32;
+ out[15] = m33;
+ return out;
+}
+/**
+ * Set the components of a mat4 to the given values
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {Number} m00 Component in column 0, row 0 position (index 0)
+ * @param {Number} m01 Component in column 0, row 1 position (index 1)
+ * @param {Number} m02 Component in column 0, row 2 position (index 2)
+ * @param {Number} m03 Component in column 0, row 3 position (index 3)
+ * @param {Number} m10 Component in column 1, row 0 position (index 4)
+ * @param {Number} m11 Component in column 1, row 1 position (index 5)
+ * @param {Number} m12 Component in column 1, row 2 position (index 6)
+ * @param {Number} m13 Component in column 1, row 3 position (index 7)
+ * @param {Number} m20 Component in column 2, row 0 position (index 8)
+ * @param {Number} m21 Component in column 2, row 1 position (index 9)
+ * @param {Number} m22 Component in column 2, row 2 position (index 10)
+ * @param {Number} m23 Component in column 2, row 3 position (index 11)
+ * @param {Number} m30 Component in column 3, row 0 position (index 12)
+ * @param {Number} m31 Component in column 3, row 1 position (index 13)
+ * @param {Number} m32 Component in column 3, row 2 position (index 14)
+ * @param {Number} m33 Component in column 3, row 3 position (index 15)
+ * @returns {mat4} out
+ */
+
+
+function set(out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
+ out[0] = m00;
+ out[1] = m01;
+ out[2] = m02;
+ out[3] = m03;
+ out[4] = m10;
+ out[5] = m11;
+ out[6] = m12;
+ out[7] = m13;
+ out[8] = m20;
+ out[9] = m21;
+ out[10] = m22;
+ out[11] = m23;
+ out[12] = m30;
+ out[13] = m31;
+ out[14] = m32;
+ out[15] = m33;
+ return out;
+}
+/**
+ * Set a mat4 to the identity matrix
+ *
+ * @param {mat4} out the receiving matrix
+ * @returns {mat4} out
+ */
+
+
+function identity(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 {mat4} a the source matrix
+ * @returns {mat4} 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 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 {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+
+
+function 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 {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+
+
+function 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 {mat4} a the source matrix
+ * @returns {Number} determinant of a
+ */
+
+
+function 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 {mat4} a the first operand
+ * @param {mat4} b the second operand
+ * @returns {mat4} out
+ */
+
+
+function 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 {mat4} a the matrix to translate
+ * @param {vec3} v vector to translate by
+ * @returns {mat4} out
+ */
+
+
+function 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 {mat4} a the matrix to scale
+ * @param {vec3} v the vec3 to scale the matrix by
+ * @returns {mat4} out
+ **/
+
+
+function 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 {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @param {vec3} axis the axis to rotate around
+ * @returns {mat4} out
+ */
+
+
+function 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 < glMatrix.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 {mat4} 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 {mat4} 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 {mat4} 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 {vec3} v Translation vector
+ * @returns {mat4} out
+ */
+
+
+function 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 {vec3} v Scaling vector
+ * @returns {mat4} out
+ */
+
+
+function 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 {vec3} axis the axis to rotate around
+ * @returns {mat4} out
+ */
+
+
+function 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 < glMatrix.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 {vec3} 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 {quat2} a Dual Quaternion
+ * @returns {mat4} mat4 receiving operation result
+ */
+
+
+function fromQuat2(out, a) {
+ var translation = new glMatrix.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 {mat4} 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 {mat4} 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 {mat4} mat Matrix to be decomposed (input)
+ * @return {quat} out
+ */
+
+
+function getRotation(out, mat) {
+ var scaling = new glMatrix.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 {vec3} v Translation vector
+ * @param {vec3} 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 {vec3} v Translation vector
+ * @param {vec3} s Scaling vector
+ * @param {vec3} 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 {quat} q Quaternion to create matrix from
+ *
+ * @returns {mat4} 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[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 {vec3} eye Position of the viewer
+ * @param {vec3} center Point the viewer is looking at
+ * @param {vec3} 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) < glMatrix.EPSILON && Math.abs(eyey - centery) < glMatrix.EPSILON && Math.abs(eyez - centerz) < glMatrix.EPSILON) {
+ return 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 {vec3} eye Position of the viewer
+ * @param {vec3} center Point the viewer is looking at
+ * @param {vec3} 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 {mat4} a matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+
+function 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 {mat4} a the matrix to calculate Frobenius norm of
+ * @returns {Number} Frobenius norm
+ */
+
+
+function frob(a) {
+ return Math.hypot(a[0], a[1], 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 {mat4} a the first operand
+ * @param {mat4} b the second operand
+ * @returns {mat4} 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];
+ 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 {mat4} a the first operand
+ * @param {mat4} b the second operand
+ * @returns {mat4} 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];
+ 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 {mat4} a the matrix to scale
+ * @param {Number} b amount to scale the matrix's elements by
+ * @returns {mat4} 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;
+ 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 {mat4} a the first operand
+ * @param {mat4} b the second operand
+ * @param {Number} scale the amount to scale b's elements by before adding
+ * @returns {mat4} 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;
+ 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 {mat4} a The first matrix.
+ * @param {mat4} 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] && 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 {mat4} a The first matrix.
+ * @param {mat4} b The second matrix.
+ * @returns {Boolean} True if the matrices are equal, false otherwise.
+ */
+
+
+function 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) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8)) && Math.abs(a9 - b9) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a9), Math.abs(b9)) && Math.abs(a10 - b10) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a10), Math.abs(b10)) && Math.abs(a11 - b11) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a11), Math.abs(b11)) && Math.abs(a12 - b12) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a12), Math.abs(b12)) && Math.abs(a13 - b13) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a13), Math.abs(b13)) && Math.abs(a14 - b14) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a14), Math.abs(b14)) && Math.abs(a15 - b15) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a15), Math.abs(b15));
+}
+/**
+ * Alias for {@link mat4.multiply}
+ * @function
+ */
+
+
+var mul = multiply;
+/**
+ * Alias for {@link mat4.subtract}
+ * @function
+ */
+
+exports.mul = mul;
+var sub = subtract;
+exports.sub = sub;
+},{"./common.js":22}],28:[function(require,module,exports){
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.create = create;
+exports.identity = identity;
+exports.setAxisAngle = setAxisAngle;
+exports.getAxisAngle = getAxisAngle;
+exports.getAngle = getAngle;
+exports.multiply = multiply;
+exports.rotateX = rotateX;
+exports.rotateY = rotateY;
+exports.rotateZ = rotateZ;
+exports.calculateW = calculateW;
+exports.exp = exp;
+exports.ln = ln;
+exports.pow = pow;
+exports.slerp = slerp;
+exports.random = random;
+exports.invert = invert;
+exports.conjugate = conjugate;
+exports.fromMat3 = fromMat3;
+exports.fromEuler = fromEuler;
+exports.str = str;
+exports.setAxes = exports.sqlerp = exports.rotationTo = exports.equals = exports.exactEquals = exports.normalize = exports.sqrLen = exports.squaredLength = exports.len = exports.length = exports.lerp = exports.dot = exports.scale = exports.mul = exports.add = exports.set = exports.copy = exports.fromValues = exports.clone = void 0;
+
+var glMatrix = _interopRequireWildcard(require("./common.js"));
+
+var mat3 = _interopRequireWildcard(require("./mat3.js"));
+
+var vec3 = _interopRequireWildcard(require("./vec3.js"));
+
+var vec4 = _interopRequireWildcard(require("./vec4.js"));
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj["default"] = obj; return newObj; } }
+
+/**
+ * Quaternion
+ * @module quat
+ */
+
+/**
+ * Creates a new identity quat
+ *
+ * @returns {quat} a new quaternion
+ */
+function create() {
+ var out = new glMatrix.ARRAY_TYPE(4);
+
+ if (glMatrix.ARRAY_TYPE != Float32Array) {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ }
+
+ out[3] = 1;
+ return out;
+}
+/**
+ * Set a quat to the identity quaternion
+ *
+ * @param {quat} out the receiving quaternion
+ * @returns {quat} out
+ */
+
+
+function identity(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 {vec3} 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 {quat} 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 > glMatrix.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 {quat} a Origin unit quaternion
+ * @param {quat} b Destination unit quaternion
+ * @return {Number} Angle, in radians, between the two quaternions
+ */
+
+
+function getAngle(a, b) {
+ var dotproduct = dot(a, b);
+ return Math.acos(2 * dotproduct * dotproduct - 1);
+}
+/**
+ * Multiplies two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {quat} out
+ */
+
+
+function 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 {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+
+
+function 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 {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+
+
+function 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 {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+
+
+function 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 {quat} 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 {quat} 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 {quat} 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 {quat} a quat to calculate the exponential of
+ * @param {Number} b amount to scale the quaternion by
+ * @returns {quat} out
+ */
+
+
+function pow(out, a, b) {
+ ln(out, a);
+ scale(out, out, b);
+ exp(out, out);
+ return out;
+}
+/**
+ * Performs a spherical linear interpolation between two quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} 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 > glMatrix.EPSILON) {
+ // standard case (slerp)
+ omega = Math.acos(cosom);
+ sinom = Math.sin(omega);
+ scale0 = Math.sin((1.0 - t) * omega) / sinom;
+ scale1 = Math.sin(t * omega) / sinom;
+ } else {
+ // "from" and "to" quaternions are very close
+ // ... so we can do a linear interpolation
+ scale0 = 1.0 - t;
+ scale1 = t;
+ } // calculate final values
+
+
+ out[0] = scale0 * ax + scale1 * bx;
+ out[1] = scale0 * ay + scale1 * by;
+ out[2] = scale0 * az + scale1 * bz;
+ out[3] = scale0 * aw + scale1 * bw;
+ return out;
+}
+/**
+ * Generates a random unit quaternion
+ *
+ * @param {quat} out the receiving quaternion
+ * @returns {quat} out
+ */
+
+
+function random(out) {
+ // Implementation of http://planning.cs.uiuc.edu/node198.html
+ // TODO: Calling random 3 times is probably not the fastest solution
+ var u1 = glMatrix.RANDOM();
+ var u2 = glMatrix.RANDOM();
+ var u3 = glMatrix.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 {quat} a quat to calculate inverse of
+ * @returns {quat} out
+ */
+
+
+function 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 {quat} 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 {mat3} 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 {quat} a vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+
+
+function str(a) {
+ return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+}
+/**
+ * Creates a new quat initialized with values from an existing quaternion
+ *
+ * @param {quat} a quaternion to clone
+ * @returns {quat} a new quaternion
+ * @function
+ */
+
+
+var 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
+ */
+
+exports.clone = clone;
+var fromValues = vec4.fromValues;
+/**
+ * Copy the values from one quat to another
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the source quaternion
+ * @returns {quat} out
+ * @function
+ */
+
+exports.fromValues = fromValues;
+var 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
+ */
+
+exports.copy = copy;
+var set = vec4.set;
+/**
+ * Adds two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {quat} out
+ * @function
+ */
+
+exports.set = set;
+var add = vec4.add;
+/**
+ * Alias for {@link quat.multiply}
+ * @function
+ */
+
+exports.add = add;
+var mul = multiply;
+/**
+ * Scales a quat by a scalar number
+ *
+ * @param {quat} out the receiving vector
+ * @param {quat} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {quat} out
+ * @function
+ */
+
+exports.mul = mul;
+var scale = vec4.scale;
+/**
+ * Calculates the dot product of two quat's
+ *
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {Number} dot product of a and b
+ * @function
+ */
+
+exports.scale = scale;
+var dot = vec4.dot;
+/**
+ * Performs a linear interpolation between two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+ * @returns {quat} out
+ * @function
+ */
+
+exports.dot = dot;
+var lerp = vec4.lerp;
+/**
+ * Calculates the length of a quat
+ *
+ * @param {quat} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+
+exports.lerp = lerp;
+var length = vec4.length;
+/**
+ * Alias for {@link quat.length}
+ * @function
+ */
+
+exports.length = length;
+var len = length;
+/**
+ * Calculates the squared length of a quat
+ *
+ * @param {quat} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ * @function
+ */
+
+exports.len = len;
+var squaredLength = vec4.squaredLength;
+/**
+ * Alias for {@link quat.squaredLength}
+ * @function
+ */
+
+exports.squaredLength = squaredLength;
+var sqrLen = squaredLength;
+/**
+ * Normalize a quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quaternion to normalize
+ * @returns {quat} out
+ * @function
+ */
+
+exports.sqrLen = sqrLen;
+var normalize = vec4.normalize;
+/**
+ * Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===)
+ *
+ * @param {quat} a The first quaternion.
+ * @param {quat} b The second quaternion.
+ * @returns {Boolean} True if the vectors are equal, false otherwise.
+ */
+
+exports.normalize = normalize;
+var exactEquals = vec4.exactEquals;
+/**
+ * Returns whether or not the quaternions have approximately the same elements in the same position.
+ *
+ * @param {quat} a The first vector.
+ * @param {quat} b The second vector.
+ * @returns {Boolean} True if the vectors are equal, false otherwise.
+ */
+
+exports.exactEquals = exactEquals;
+var 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 {vec3} a the initial vector
+ * @param {vec3} b the destination vector
+ * @returns {quat} out
+ */
+
+exports.equals = equals;
+
+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) {
+ vec3.cross(tmpvec3, xUnitVec3, a);
+ if (vec3.len(tmpvec3) < 0.000001) vec3.cross(tmpvec3, yUnitVec3, a);
+ vec3.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 {
+ vec3.cross(tmpvec3, a, b);
+ out[0] = tmpvec3[0];
+ out[1] = tmpvec3[1];
+ out[2] = tmpvec3[2];
+ out[3] = 1 + dot;
+ return normalize(out, out);
+ }
+ };
+}();
+/**
+ * Performs a spherical linear interpolation with two control points
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @param {quat} c the third operand
+ * @param {quat} d the fourth operand
+ * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+ * @returns {quat} out
+ */
+
+
+exports.rotationTo = rotationTo;
+
+var sqlerp = function () {
+ var temp1 = create();
+ var temp2 = 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 {vec3} view the vector representing the viewing direction
+ * @param {vec3} right the vector representing the local "right" direction
+ * @param {vec3} up the vector representing the local "up" direction
+ * @returns {quat} out
+ */
+
+
+exports.sqlerp = sqlerp;
+
+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 normalize(out, fromMat3(out, matr));
+ };
+}();
+
+exports.setAxes = setAxes;
+},{"./common.js":22,"./mat3.js":26,"./vec3.js":31,"./vec4.js":32}],29:[function(require,module,exports){
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.create = create;
+exports.clone = clone;
+exports.fromValues = fromValues;
+exports.fromRotationTranslationValues = fromRotationTranslationValues;
+exports.fromRotationTranslation = fromRotationTranslation;
+exports.fromTranslation = fromTranslation;
+exports.fromRotation = fromRotation;
+exports.fromMat4 = fromMat4;
+exports.copy = copy;
+exports.identity = identity;
+exports.set = set;
+exports.getDual = getDual;
+exports.setDual = setDual;
+exports.getTranslation = getTranslation;
+exports.translate = translate;
+exports.rotateX = rotateX;
+exports.rotateY = rotateY;
+exports.rotateZ = rotateZ;
+exports.rotateByQuatAppend = rotateByQuatAppend;
+exports.rotateByQuatPrepend = rotateByQuatPrepend;
+exports.rotateAroundAxis = rotateAroundAxis;
+exports.add = add;
+exports.multiply = multiply;
+exports.scale = scale;
+exports.lerp = lerp;
+exports.invert = invert;
+exports.conjugate = conjugate;
+exports.normalize = normalize;
+exports.str = str;
+exports.exactEquals = exactEquals;
+exports.equals = equals;
+exports.sqrLen = exports.squaredLength = exports.len = exports.length = exports.dot = exports.mul = exports.setReal = exports.getReal = void 0;
+
+var glMatrix = _interopRequireWildcard(require("./common.js"));
+
+var quat = _interopRequireWildcard(require("./quat.js"));
+
+var mat4 = _interopRequireWildcard(require("./mat4.js"));
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj["default"] = obj; return newObj; } }
+
+/**
+ * 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 create() {
+ var dq = new glMatrix.ARRAY_TYPE(8);
+
+ if (glMatrix.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 {quat2} a dual quaternion to clone
+ * @returns {quat2} new dual quaternion
+ * @function
+ */
+
+
+function clone(a) {
+ var dq = new glMatrix.ARRAY_TYPE(8);
+ dq[0] = a[0];
+ dq[1] = a[1];
+ dq[2] = a[2];
+ dq[3] = a[3];
+ dq[4] = a[4];
+ dq[5] = a[5];
+ dq[6] = a[6];
+ dq[7] = a[7];
+ return dq;
+}
+/**
+ * Creates a new dual quat initialized with the given values
+ *
+ * @param {Number} x1 X component
+ * @param {Number} y1 Y component
+ * @param {Number} z1 Z component
+ * @param {Number} w1 W component
+ * @param {Number} x2 X component
+ * @param {Number} y2 Y component
+ * @param {Number} z2 Z component
+ * @param {Number} w2 W component
+ * @returns {quat2} new dual quaternion
+ * @function
+ */
+
+
+function fromValues(x1, y1, z1, w1, x2, y2, z2, w2) {
+ var dq = new glMatrix.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 glMatrix.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 {quat2} dual quaternion receiving operation result
+ * @param {quat} q a normalized quaternion
+ * @param {vec3} t tranlation vector
+ * @returns {quat2} dual quaternion receiving operation result
+ * @function
+ */
+
+
+function 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 {quat2} dual quaternion receiving operation result
+ * @param {vec3} t translation vector
+ * @returns {quat2} dual quaternion receiving operation result
+ * @function
+ */
+
+
+function 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 {quat2} dual quaternion receiving operation result
+ * @param {quat} q the quaternion
+ * @returns {quat2} dual quaternion receiving operation result
+ * @function
+ */
+
+
+function 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 {mat4} a the matrix
+ * @returns {quat2} dual quat receiving operation result
+ * @function
+ */
+
+
+function fromMat4(out, a) {
+ //TODO Optimize this
+ var outer = quat.create();
+ mat4.getRotation(outer, a);
+ var t = new glMatrix.ARRAY_TYPE(3);
+ mat4.getTranslation(t, a);
+ fromRotationTranslation(out, outer, t);
+ return out;
+}
+/**
+ * Copy the values from one dual quat to another
+ *
+ * @param {quat2} out the receiving dual quaternion
+ * @param {quat2} a the source dual quaternion
+ * @returns {quat2} out
+ * @function
+ */
+
+
+function 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 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 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 {quat2} 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 {quat2} a Dual Quaternion
+ * @return {quat} dual part
+ */
+
+exports.getReal = getReal;
+
+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 {quat} 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 {quat} q a quaternion representing the dual part
+ * @returns {quat2} out
+ * @function
+ */
+
+exports.setReal = setReal;
+
+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 {quat2} a Dual Quaternion to be decomposed
+ * @return {vec3} translation
+ */
+
+
+function 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 {quat2} a the dual quaternion to translate
+ * @param {vec3} v vector to translate by
+ * @returns {quat2} out
+ */
+
+
+function 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 {quat2} a the dual quaternion to rotate
+ * @param {number} rad how far should the rotation be
+ * @returns {quat2} out
+ */
+
+
+function 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 {quat2} a the dual quaternion to rotate
+ * @param {number} rad how far should the rotation be
+ * @returns {quat2} out
+ */
+
+
+function 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 {quat2} a the dual quaternion to rotate
+ * @param {number} rad how far should the rotation be
+ * @returns {quat2} out
+ */
+
+
+function 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 {quat2} a the dual quaternion to rotate
+ * @param {quat} 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 {quat} q quaternion to rotate by
+ * @param {quat2} 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 {quat2} a the dual quaternion to rotate
+ * @param {vec3} 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) < glMatrix.EPSILON) {
+ return 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 {quat2} a the first operand
+ * @param {quat2} b the second operand
+ * @returns {quat2} out
+ * @function
+ */
+
+
+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];
+ 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 {quat2} a the first operand
+ * @param {quat2} b the second operand
+ * @returns {quat2} out
+ */
+
+
+function 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 mul = multiply;
+/**
+ * Scales a dual quat by a scalar number
+ *
+ * @param {quat2} out the receiving dual quat
+ * @param {quat2} a the dual quat to scale
+ * @param {Number} b amount to scale the dual quat by
+ * @returns {quat2} out
+ * @function
+ */
+
+exports.mul = mul;
+
+function 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 {quat2} a the first operand
+ * @param {quat2} b the second operand
+ * @returns {Number} dot product of a and b
+ * @function
+ */
+
+
+var 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 {quat2} a the first operand
+ * @param {quat2} b the second operand
+ * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+ * @returns {quat2} out
+ */
+
+exports.dot = dot;
+
+function lerp(out, a, b, t) {
+ var mt = 1 - t;
+ if (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 {quat2} a dual quat to calculate inverse of
+ * @returns {quat2} out
+ */
+
+
+function invert(out, a) {
+ var sqlen = 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 {quat2} a quat to calculate conjugate of
+ * @returns {quat2} out
+ */
+
+
+function 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 {quat2} a dual quat to calculate length of
+ * @returns {Number} length of a
+ * @function
+ */
+
+
+var length = quat.length;
+/**
+ * Alias for {@link quat2.length}
+ * @function
+ */
+
+exports.length = length;
+var len = length;
+/**
+ * Calculates the squared length of a dual quat
+ *
+ * @param {quat2} a dual quat to calculate squared length of
+ * @returns {Number} squared length of a
+ * @function
+ */
+
+exports.len = len;
+var squaredLength = quat.squaredLength;
+/**
+ * Alias for {@link quat2.squaredLength}
+ * @function
+ */
+
+exports.squaredLength = squaredLength;
+var sqrLen = squaredLength;
+/**
+ * Normalize a dual quat
+ *
+ * @param {quat2} out the receiving dual quaternion
+ * @param {quat2} a dual quaternion to normalize
+ * @returns {quat2} out
+ * @function
+ */
+
+exports.sqrLen = sqrLen;
+
+function normalize(out, a) {
+ var magnitude = 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 {quat2} a dual quaternion to represent as a string
+ * @returns {String} string representation of the dual quat
+ */
+
+
+function 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 {quat2} a the first dual quaternion.
+ * @param {quat2} b the second dual quaternion.
+ * @returns {Boolean} true if the dual quaternions 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] && 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 {quat2} a the first dual quat.
+ * @param {quat2} b the second dual quat.
+ * @returns {Boolean} true if the dual quats are equal, false otherwise.
+ */
+
+
+function 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) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7));
+}
+},{"./common.js":22,"./mat4.js":27,"./quat.js":28}],30:[function(require,module,exports){
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.create = create;
+exports.clone = clone;
+exports.fromValues = fromValues;
+exports.copy = copy;
+exports.set = set;
+exports.add = add;
+exports.subtract = subtract;
+exports.multiply = multiply;
+exports.divide = divide;
+exports.ceil = ceil;
+exports.floor = floor;
+exports.min = min;
+exports.max = max;
+exports.round = round;
+exports.scale = scale;
+exports.scaleAndAdd = scaleAndAdd;
+exports.distance = distance;
+exports.squaredDistance = squaredDistance;
+exports.length = length;
+exports.squaredLength = squaredLength;
+exports.negate = negate;
+exports.inverse = inverse;
+exports.normalize = normalize;
+exports.dot = dot;
+exports.cross = cross;
+exports.lerp = lerp;
+exports.random = random;
+exports.transformMat2 = transformMat2;
+exports.transformMat2d = transformMat2d;
+exports.transformMat3 = transformMat3;
+exports.transformMat4 = transformMat4;
+exports.rotate = rotate;
+exports.angle = angle;
+exports.zero = zero;
+exports.str = str;
+exports.exactEquals = exactEquals;
+exports.equals = equals;
+exports.forEach = exports.sqrLen = exports.sqrDist = exports.dist = exports.div = exports.mul = exports.sub = exports.len = void 0;
+
+var glMatrix = _interopRequireWildcard(require("./common.js"));
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj["default"] = obj; return newObj; } }
+
+/**
+ * 2 Dimensional Vector
+ * @module vec2
+ */
+
+/**
+ * Creates a new, empty vec2
+ *
+ * @returns {vec2} a new 2D vector
+ */
+function create() {
+ var out = new glMatrix.ARRAY_TYPE(2);
+
+ if (glMatrix.ARRAY_TYPE != Float32Array) {
+ out[0] = 0;
+ out[1] = 0;
+ }
+
+ return out;
+}
+/**
+ * Creates a new vec2 initialized with values from an existing vector
+ *
+ * @param {vec2} a vector to clone
+ * @returns {vec2} a new 2D vector
+ */
+
+
+function clone(a) {
+ var out = new glMatrix.ARRAY_TYPE(2);
+ out[0] = a[0];
+ out[1] = a[1];
+ return out;
+}
+/**
+ * Creates a new vec2 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @returns {vec2} a new 2D vector
+ */
+
+
+function fromValues(x, y) {
+ var out = new glMatrix.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 {vec2} a the source vector
+ * @returns {vec2} out
+ */
+
+
+function 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 set(out, x, y) {
+ out[0] = x;
+ out[1] = y;
+ return out;
+}
+/**
+ * Adds two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+
+
+function 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 {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+
+
+function 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 {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+
+
+function 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 {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+
+
+function 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 {vec2} a vector to ceil
+ * @returns {vec2} out
+ */
+
+
+function 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 {vec2} a vector to floor
+ * @returns {vec2} out
+ */
+
+
+function 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 {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+
+
+function 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 {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+
+
+function 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 {vec2} a vector to round
+ * @returns {vec2} out
+ */
+
+
+function 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 {vec2} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec2} out
+ */
+
+
+function 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 {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec2} out
+ */
+
+
+function 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 {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} distance between a and b
+ */
+
+
+function 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 {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} squared distance between a and b
+ */
+
+
+function 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 {vec2} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+
+
+function length(a) {
+ var x = a[0],
+ y = a[1];
+ return Math.hypot(x, y);
+}
+/**
+ * Calculates the squared length of a vec2
+ *
+ * @param {vec2} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+
+
+function 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 {vec2} a vector to negate
+ * @returns {vec2} out
+ */
+
+
+function 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 {vec2} a vector to invert
+ * @returns {vec2} out
+ */
+
+
+function 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 {vec2} a vector to normalize
+ * @returns {vec2} out
+ */
+
+
+function 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 {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+
+
+function dot(a, b) {
+ return a[0] * b[0] + a[1] * b[1];
+}
+/**
+ * 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 {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec3} out
+ */
+
+
+function 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 {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+ * @returns {vec2} out
+ */
+
+
+function 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 random(out, scale) {
+ scale = scale || 1.0;
+ var r = glMatrix.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 {vec2} a the vector to transform
+ * @param {mat2} 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 {vec2} a the vector to transform
+ * @param {mat2d} 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 {vec2} a the vector to transform
+ * @param {mat3} m matrix to transform with
+ * @returns {vec2} out
+ */
+
+
+function 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 {vec2} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec2} out
+ */
+
+
+function 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 {vec2} a The vec2 point to rotate
+ * @param {vec2} b The origin of the rotation
+ * @param {Number} c The angle of rotation
+ * @returns {vec2} out
+ */
+
+
+function rotate(out, a, b, c) {
+ //Translate point to the origin
+ var p0 = a[0] - b[0],
+ p1 = a[1] - b[1],
+ sinC = Math.sin(c),
+ cosC = Math.cos(c); //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 {vec2} a The first operand
+ * @param {vec2} b The second operand
+ * @returns {Number} The angle in radians
+ */
+
+
+function angle(a, b) {
+ var x1 = a[0],
+ y1 = a[1],
+ x2 = b[0],
+ y2 = b[1];
+ var len1 = x1 * x1 + y1 * y1;
+
+ if (len1 > 0) {
+ //TODO: evaluate use of glm_invsqrt here?
+ len1 = 1 / Math.sqrt(len1);
+ }
+
+ var len2 = x2 * x2 + y2 * y2;
+
+ if (len2 > 0) {
+ //TODO: evaluate use of glm_invsqrt here?
+ len2 = 1 / Math.sqrt(len2);
+ }
+
+ var cosine = (x1 * x2 + y1 * y2) * len1 * len2;
+
+ if (cosine > 1.0) {
+ return 0;
+ } else if (cosine < -1.0) {
+ return Math.PI;
+ } else {
+ return Math.acos(cosine);
+ }
+}
+/**
+ * Set the components of a vec2 to zero
+ *
+ * @param {vec2} out the receiving vector
+ * @returns {vec2} out
+ */
+
+
+function zero(out) {
+ out[0] = 0.0;
+ out[1] = 0.0;
+ return out;
+}
+/**
+ * Returns a string representation of a vector
+ *
+ * @param {vec2} a vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+
+
+function 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 {vec2} a The first vector.
+ * @param {vec2} b The second vector.
+ * @returns {Boolean} True if the vectors are equal, false otherwise.
+ */
+
+
+function 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 {vec2} a The first vector.
+ * @param {vec2} b The second vector.
+ * @returns {Boolean} True if the vectors are equal, false otherwise.
+ */
+
+
+function equals(a, b) {
+ var a0 = a[0],
+ a1 = a[1];
+ var b0 = b[0],
+ b1 = b[1];
+ return Math.abs(a0 - b0) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1));
+}
+/**
+ * Alias for {@link vec2.length}
+ * @function
+ */
+
+
+var len = length;
+/**
+ * Alias for {@link vec2.subtract}
+ * @function
+ */
+
+exports.len = len;
+var sub = subtract;
+/**
+ * Alias for {@link vec2.multiply}
+ * @function
+ */
+
+exports.sub = sub;
+var mul = multiply;
+/**
+ * Alias for {@link vec2.divide}
+ * @function
+ */
+
+exports.mul = mul;
+var div = divide;
+/**
+ * Alias for {@link vec2.distance}
+ * @function
+ */
+
+exports.div = div;
+var dist = distance;
+/**
+ * Alias for {@link vec2.squaredDistance}
+ * @function
+ */
+
+exports.dist = dist;
+var sqrDist = squaredDistance;
+/**
+ * Alias for {@link vec2.squaredLength}
+ * @function
+ */
+
+exports.sqrDist = sqrDist;
+var sqrLen = 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
+ */
+
+exports.sqrLen = sqrLen;
+
+var forEach = function () {
+ var vec = 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;
+ };
+}();
+
+exports.forEach = forEach;
+},{"./common.js":22}],31:[function(require,module,exports){
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.create = create;
+exports.clone = clone;
+exports.length = length;
+exports.fromValues = fromValues;
+exports.copy = copy;
+exports.set = set;
+exports.add = add;
+exports.subtract = subtract;
+exports.multiply = multiply;
+exports.divide = divide;
+exports.ceil = ceil;
+exports.floor = floor;
+exports.min = min;
+exports.max = max;
+exports.round = round;
+exports.scale = scale;
+exports.scaleAndAdd = scaleAndAdd;
+exports.distance = distance;
+exports.squaredDistance = squaredDistance;
+exports.squaredLength = squaredLength;
+exports.negate = negate;
+exports.inverse = inverse;
+exports.normalize = normalize;
+exports.dot = dot;
+exports.cross = cross;
+exports.lerp = lerp;
+exports.hermite = hermite;
+exports.bezier = bezier;
+exports.random = random;
+exports.transformMat4 = transformMat4;
+exports.transformMat3 = transformMat3;
+exports.transformQuat = transformQuat;
+exports.rotateX = rotateX;
+exports.rotateY = rotateY;
+exports.rotateZ = rotateZ;
+exports.angle = angle;
+exports.zero = zero;
+exports.str = str;
+exports.exactEquals = exactEquals;
+exports.equals = equals;
+exports.forEach = exports.sqrLen = exports.len = exports.sqrDist = exports.dist = exports.div = exports.mul = exports.sub = void 0;
+
+var glMatrix = _interopRequireWildcard(require("./common.js"));
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj["default"] = obj; return newObj; } }
+
+/**
+ * 3 Dimensional Vector
+ * @module vec3
+ */
+
+/**
+ * Creates a new, empty vec3
+ *
+ * @returns {vec3} a new 3D vector
+ */
+function create() {
+ var out = new glMatrix.ARRAY_TYPE(3);
+
+ if (glMatrix.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 {vec3} a vector to clone
+ * @returns {vec3} a new 3D vector
+ */
+
+
+function clone(a) {
+ var out = new glMatrix.ARRAY_TYPE(3);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ return out;
+}
+/**
+ * Calculates the length of a vec3
+ *
+ * @param {vec3} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+
+
+function length(a) {
+ var x = a[0];
+ var y = a[1];
+ var z = a[2];
+ return Math.hypot(x, y, z);
+}
+/**
+ * Creates a new vec3 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @returns {vec3} a new 3D vector
+ */
+
+
+function fromValues(x, y, z) {
+ var out = new glMatrix.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 {vec3} a the source vector
+ * @returns {vec3} out
+ */
+
+
+function 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 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 {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+
+
+function 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 {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+
+
+function 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 {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+
+
+function 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 {vec3} a the first operand
+ * @param {vec3} 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 {vec3} 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 {vec3} 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 {vec3} a the first operand
+ * @param {vec3} 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 {vec3} a the first operand
+ * @param {vec3} 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 {vec3} 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 {vec3} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec3} out
+ */
+
+
+function 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 {vec3} a the first operand
+ * @param {vec3} 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 {vec3} a the first operand
+ * @param {vec3} 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 {vec3} a the first operand
+ * @param {vec3} 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 {vec3} 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 {vec3} 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 {vec3} 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 {vec3} 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 {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+
+
+function dot(a, b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+}
+/**
+ * Computes the cross product of two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} 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 {vec3} a the first operand
+ * @param {vec3} 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 {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @param {vec3} c the third operand
+ * @param {vec3} 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 {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @param {vec3} c the third operand
+ * @param {vec3} 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 = glMatrix.RANDOM() * 2.0 * Math.PI;
+ var z = glMatrix.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 {vec3} a the vector to transform
+ * @param {mat4} 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 {vec3} a the vector to transform
+ * @param {mat3} 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 {vec3} a the vector to transform
+ * @param {quat} 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 {vec3} a The vec3 point to rotate
+ * @param {vec3} b The origin of the rotation
+ * @param {Number} c The angle of rotation
+ * @returns {vec3} out
+ */
+
+
+function rotateX(out, a, b, c) {
+ 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(c) - p[2] * Math.sin(c);
+ r[2] = p[1] * Math.sin(c) + p[2] * Math.cos(c); //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 {vec3} a The vec3 point to rotate
+ * @param {vec3} b The origin of the rotation
+ * @param {Number} c The angle of rotation
+ * @returns {vec3} out
+ */
+
+
+function rotateY(out, a, b, c) {
+ 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(c) + p[0] * Math.cos(c);
+ r[1] = p[1];
+ r[2] = p[2] * Math.cos(c) - p[0] * Math.sin(c); //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 {vec3} a The vec3 point to rotate
+ * @param {vec3} b The origin of the rotation
+ * @param {Number} c The angle of rotation
+ * @returns {vec3} out
+ */
+
+
+function rotateZ(out, a, b, c) {
+ 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(c) - p[1] * Math.sin(c);
+ r[1] = p[0] * Math.sin(c) + p[1] * Math.cos(c);
+ 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 {vec3} a The first operand
+ * @param {vec3} b The second operand
+ * @returns {Number} The angle in radians
+ */
+
+
+function angle(a, b) {
+ var tempA = fromValues(a[0], a[1], a[2]);
+ var tempB = fromValues(b[0], b[1], b[2]);
+ normalize(tempA, tempA);
+ normalize(tempB, tempB);
+ var cosine = dot(tempA, tempB);
+
+ if (cosine > 1.0) {
+ return 0;
+ } else if (cosine < -1.0) {
+ return Math.PI;
+ } else {
+ return Math.acos(cosine);
+ }
+}
+/**
+ * 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 {vec3} a vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+
+
+function 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 {vec3} a The first vector.
+ * @param {vec3} b The second vector.
+ * @returns {Boolean} True if the vectors are equal, false otherwise.
+ */
+
+
+function 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 {vec3} a The first vector.
+ * @param {vec3} b The second vector.
+ * @returns {Boolean} True if the vectors are equal, false otherwise.
+ */
+
+
+function 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) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2));
+}
+/**
+ * Alias for {@link vec3.subtract}
+ * @function
+ */
+
+
+var sub = subtract;
+/**
+ * Alias for {@link vec3.multiply}
+ * @function
+ */
+
+exports.sub = sub;
+var mul = multiply;
+/**
+ * Alias for {@link vec3.divide}
+ * @function
+ */
+
+exports.mul = mul;
+var div = divide;
+/**
+ * Alias for {@link vec3.distance}
+ * @function
+ */
+
+exports.div = div;
+var dist = distance;
+/**
+ * Alias for {@link vec3.squaredDistance}
+ * @function
+ */
+
+exports.dist = dist;
+var sqrDist = squaredDistance;
+/**
+ * Alias for {@link vec3.length}
+ * @function
+ */
+
+exports.sqrDist = sqrDist;
+var len = length;
+/**
+ * Alias for {@link vec3.squaredLength}
+ * @function
+ */
+
+exports.len = len;
+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
+ */
+
+exports.sqrLen = sqrLen;
+
+var forEach = function () {
+ var vec = 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;
+ };
+}();
+
+exports.forEach = forEach;
+},{"./common.js":22}],32:[function(require,module,exports){
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.create = create;
+exports.clone = clone;
+exports.fromValues = fromValues;
+exports.copy = copy;
+exports.set = set;
+exports.add = add;
+exports.subtract = subtract;
+exports.multiply = multiply;
+exports.divide = divide;
+exports.ceil = ceil;
+exports.floor = floor;
+exports.min = min;
+exports.max = max;
+exports.round = round;
+exports.scale = scale;
+exports.scaleAndAdd = scaleAndAdd;
+exports.distance = distance;
+exports.squaredDistance = squaredDistance;
+exports.length = length;
+exports.squaredLength = squaredLength;
+exports.negate = negate;
+exports.inverse = inverse;
+exports.normalize = normalize;
+exports.dot = dot;
+exports.cross = cross;
+exports.lerp = lerp;
+exports.random = random;
+exports.transformMat4 = transformMat4;
+exports.transformQuat = transformQuat;
+exports.zero = zero;
+exports.str = str;
+exports.exactEquals = exactEquals;
+exports.equals = equals;
+exports.forEach = exports.sqrLen = exports.len = exports.sqrDist = exports.dist = exports.div = exports.mul = exports.sub = void 0;
+
+var glMatrix = _interopRequireWildcard(require("./common.js"));
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj["default"] = obj; return newObj; } }
+
+/**
+ * 4 Dimensional Vector
+ * @module vec4
+ */
+
+/**
+ * Creates a new, empty vec4
+ *
+ * @returns {vec4} a new 4D vector
+ */
+function create() {
+ var out = new glMatrix.ARRAY_TYPE(4);
+
+ if (glMatrix.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 {vec4} a vector to clone
+ * @returns {vec4} a new 4D vector
+ */
+
+
+function clone(a) {
+ var out = new glMatrix.ARRAY_TYPE(4);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+}
+/**
+ * Creates a new vec4 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {vec4} a new 4D vector
+ */
+
+
+function fromValues(x, y, z, w) {
+ var out = new glMatrix.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 {vec4} a the source vector
+ * @returns {vec4} out
+ */
+
+
+function 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 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 {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} 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 vector b from vector a
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} 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;
+}
+/**
+ * Multiplies two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+
+
+function 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 {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+
+
+function 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 {vec4} a vector to ceil
+ * @returns {vec4} out
+ */
+
+
+function 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 {vec4} a vector to floor
+ * @returns {vec4} out
+ */
+
+
+function 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 {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} 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]);
+ out[3] = Math.min(a[3], b[3]);
+ return out;
+}
+/**
+ * Returns the maximum of two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} 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]);
+ out[3] = Math.max(a[3], b[3]);
+ return out;
+}
+/**
+ * Math.round the components of a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to round
+ * @returns {vec4} out
+ */
+
+
+function 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 {vec4} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec4} out
+ */
+
+
+function 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 {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec4} 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;
+ out[3] = a[3] + b[3] * scale;
+ return out;
+}
+/**
+ * Calculates the euclidian distance between two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} 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];
+ var w = b[3] - a[3];
+ return Math.hypot(x, y, z, w);
+}
+/**
+ * Calculates the squared euclidian distance between two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} 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];
+ var w = b[3] - a[3];
+ return x * x + y * y + z * z + w * w;
+}
+/**
+ * Calculates the length of a vec4
+ *
+ * @param {vec4} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+
+
+function length(a) {
+ var x = a[0];
+ var y = a[1];
+ var z = a[2];
+ var w = a[3];
+ return Math.hypot(x, y, z, w);
+}
+/**
+ * Calculates the squared length of a vec4
+ *
+ * @param {vec4} 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];
+ 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 {vec4} a vector to negate
+ * @returns {vec4} out
+ */
+
+
+function 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 {vec4} a vector to invert
+ * @returns {vec4} out
+ */
+
+
+function 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 {vec4} a vector to normalize
+ * @returns {vec4} out
+ */
+
+
+function 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 {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+
+
+function dot(a, b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
+}
+/**
+ * Returns the cross-product of three vectors in a 4-dimensional space
+ *
+ * @param {vec4} result the receiving vector
+ * @param {vec4} U the first vector
+ * @param {vec4} V the second vector
+ * @param {vec4} W the third vector
+ * @returns {vec4} result
+ */
+
+
+function 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 {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+ * @returns {vec4} out
+ */
+
+function 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 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 = glMatrix.RANDOM() * 2 - 1;
+ v2 = glMatrix.RANDOM() * 2 - 1;
+ s1 = v1 * v1 + v2 * v2;
+ } while (s1 >= 1);
+
+ do {
+ v3 = glMatrix.RANDOM() * 2 - 1;
+ v4 = glMatrix.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 {vec4} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec4} out
+ */
+
+
+function 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 {vec4} a the vector to transform
+ * @param {quat} q quaternion to transform with
+ * @returns {vec4} out
+ */
+
+
+function 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 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 {vec4} a vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+
+
+function 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 {vec4} a The first vector.
+ * @param {vec4} b The second vector.
+ * @returns {Boolean} True if the vectors 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 vectors have approximately the same elements in the same position.
+ *
+ * @param {vec4} a The first vector.
+ * @param {vec4} b The second vector.
+ * @returns {Boolean} True if the vectors are equal, false otherwise.
+ */
+
+
+function 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) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3));
+}
+/**
+ * Alias for {@link vec4.subtract}
+ * @function
+ */
+
+
+var sub = subtract;
+/**
+ * Alias for {@link vec4.multiply}
+ * @function
+ */
+
+exports.sub = sub;
+var mul = multiply;
+/**
+ * Alias for {@link vec4.divide}
+ * @function
+ */
+
+exports.mul = mul;
+var div = divide;
+/**
+ * Alias for {@link vec4.distance}
+ * @function
+ */
+
+exports.div = div;
+var dist = distance;
+/**
+ * Alias for {@link vec4.squaredDistance}
+ * @function
+ */
+
+exports.dist = dist;
+var sqrDist = squaredDistance;
+/**
+ * Alias for {@link vec4.length}
+ * @function
+ */
+
+exports.sqrDist = sqrDist;
+var len = length;
+/**
+ * Alias for {@link vec4.squaredLength}
+ * @function
+ */
+
+exports.len = len;
+var sqrLen = 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
+ */
+
+exports.sqrLen = sqrLen;
+
+var forEach = function () {
+ var vec = 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;
+ };
+}();
+
+exports.forEach = forEach;
+},{"./common.js":22}],33:[function(require,module,exports){
+// shim for using process in browser
+var process = module.exports = {};
+
+// cached from whatever global is present so that test runners that stub it
+// don't break things. But we need to wrap it in a try catch in case it is
+// wrapped in strict mode code which doesn't define any globals. It's inside a
+// function because try/catches deoptimize in certain engines.
+
+var cachedSetTimeout;
+var cachedClearTimeout;
+
+function defaultSetTimout() {
+ throw new Error('setTimeout has not been defined');
+}
+function defaultClearTimeout () {
+ throw new Error('clearTimeout has not been defined');
+}
+(function () {
+ try {
+ if (typeof setTimeout === 'function') {
+ cachedSetTimeout = setTimeout;
+ } else {
+ cachedSetTimeout = defaultSetTimout;
+ }
+ } catch (e) {
+ cachedSetTimeout = defaultSetTimout;
+ }
+ try {
+ if (typeof clearTimeout === 'function') {
+ cachedClearTimeout = clearTimeout;
+ } else {
+ cachedClearTimeout = defaultClearTimeout;
+ }
+ } catch (e) {
+ cachedClearTimeout = defaultClearTimeout;
+ }
+} ())
+function runTimeout(fun) {
+ if (cachedSetTimeout === setTimeout) {
+ //normal enviroments in sane situations
+ return setTimeout(fun, 0);
+ }
+ // if setTimeout wasn't available but was latter defined
+ if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
+ cachedSetTimeout = setTimeout;
+ return setTimeout(fun, 0);
+ }
+ try {
+ // when when somebody has screwed with setTimeout but no I.E. maddness
+ return cachedSetTimeout(fun, 0);
+ } catch(e){
+ try {
+ // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
+ return cachedSetTimeout.call(null, fun, 0);
+ } catch(e){
+ // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
+ return cachedSetTimeout.call(this, fun, 0);
+ }
+ }
+
+
+}
+function runClearTimeout(marker) {
+ if (cachedClearTimeout === clearTimeout) {
+ //normal enviroments in sane situations
+ return clearTimeout(marker);
+ }
+ // if clearTimeout wasn't available but was latter defined
+ if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
+ cachedClearTimeout = clearTimeout;
+ return clearTimeout(marker);
+ }
+ try {
+ // when when somebody has screwed with setTimeout but no I.E. maddness
+ return cachedClearTimeout(marker);
+ } catch (e){
+ try {
+ // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
+ return cachedClearTimeout.call(null, marker);
+ } catch (e){
+ // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
+ // Some versions of I.E. have different rules for clearTimeout vs setTimeout
+ return cachedClearTimeout.call(this, marker);
+ }
+ }
+
+
+
+}
+var queue = [];
+var draining = false;
+var currentQueue;
+var queueIndex = -1;
+
+function cleanUpNextTick() {
+ if (!draining || !currentQueue) {
+ return;
+ }
+ draining = false;
+ if (currentQueue.length) {
+ queue = currentQueue.concat(queue);
+ } else {
+ queueIndex = -1;
+ }
+ if (queue.length) {
+ drainQueue();
+ }
+}
+
+function drainQueue() {
+ if (draining) {
+ return;
+ }
+ var timeout = runTimeout(cleanUpNextTick);
+ draining = true;
+
+ var len = queue.length;
+ while(len) {
+ currentQueue = queue;
+ queue = [];
+ while (++queueIndex < len) {
+ if (currentQueue) {
+ currentQueue[queueIndex].run();
+ }
+ }
+ queueIndex = -1;
+ len = queue.length;
+ }
+ currentQueue = null;
+ draining = false;
+ runClearTimeout(timeout);
+}
+
+process.nextTick = function (fun) {
+ var args = new Array(arguments.length - 1);
+ if (arguments.length > 1) {
+ for (var i = 1; i < arguments.length; i++) {
+ args[i - 1] = arguments[i];
+ }
+ }
+ queue.push(new Item(fun, args));
+ if (queue.length === 1 && !draining) {
+ runTimeout(drainQueue);
+ }
+};
+
+// v8 likes predictible objects
+function Item(fun, array) {
+ this.fun = fun;
+ this.array = array;
+}
+Item.prototype.run = function () {
+ this.fun.apply(null, this.array);
+};
+process.title = 'browser';
+process.browser = true;
+process.env = {};
+process.argv = [];
+process.version = ''; // empty string to avoid regexp issues
+process.versions = {};
+
+function noop() {}
+
+process.on = noop;
+process.addListener = noop;
+process.once = noop;
+process.off = noop;
+process.removeListener = noop;
+process.removeAllListeners = noop;
+process.emit = noop;
+process.prependListener = noop;
+process.prependOnceListener = noop;
+
+process.listeners = function (name) { return [] }
+
+process.binding = function (name) {
+ throw new Error('process.binding is not supported');
+};
+
+process.cwd = function () { return '/' };
+process.chdir = function (dir) {
+ throw new Error('process.chdir is not supported');
+};
+process.umask = function() { return 0; };
+
+},{}],34:[function(require,module,exports){
+(function (global){
+// Underscore.js 1.9.1
+// http://underscorejs.org
+// (c) 2009-2018 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+// Underscore may be freely distributed under the MIT license.
+
+(function() {
+
+ // Baseline setup
+ // --------------
+
+ // Establish the root object, `window` (`self`) in the browser, `global`
+ // on the server, or `this` in some virtual machines. We use `self`
+ // instead of `window` for `WebWorker` support.
+ var root = typeof self == 'object' && self.self === self && self ||
+ typeof global == 'object' && global.global === global && global ||
+ this ||
+ {};
+
+ // Save the previous value of the `_` variable.
+ var previousUnderscore = root._;
+
+ // Save bytes in the minified (but not gzipped) version:
+ var ArrayProto = Array.prototype, ObjProto = Object.prototype;
+ var SymbolProto = typeof Symbol !== 'undefined' ? Symbol.prototype : null;
+
+ // Create quick reference variables for speed access to core prototypes.
+ var push = ArrayProto.push,
+ slice = ArrayProto.slice,
+ toString = ObjProto.toString,
+ hasOwnProperty = ObjProto.hasOwnProperty;
+
+ // All **ECMAScript 5** native function implementations that we hope to use
+ // are declared here.
+ var nativeIsArray = Array.isArray,
+ nativeKeys = Object.keys,
+ nativeCreate = Object.create;
+
+ // Naked function reference for surrogate-prototype-swapping.
+ var Ctor = function(){};
+
+ // Create a safe reference to the Underscore object for use below.
+ var _ = function(obj) {
+ if (obj instanceof _) return obj;
+ if (!(this instanceof _)) return new _(obj);
+ this._wrapped = obj;
+ };
+
+ // Export the Underscore object for **Node.js**, with
+ // backwards-compatibility for their old module API. If we're in
+ // the browser, add `_` as a global object.
+ // (`nodeType` is checked to ensure that `module`
+ // and `exports` are not HTML elements.)
+ if (typeof exports != 'undefined' && !exports.nodeType) {
+ if (typeof module != 'undefined' && !module.nodeType && module.exports) {
+ exports = module.exports = _;
+ }
+ exports._ = _;
+ } else {
+ root._ = _;
+ }
+
+ // Current version.
+ _.VERSION = '1.9.1';
+
+ // Internal function that returns an efficient (for current engines) version
+ // of the passed-in callback, to be repeatedly applied in other Underscore
+ // functions.
+ var optimizeCb = function(func, context, argCount) {
+ if (context === void 0) return func;
+ switch (argCount == null ? 3 : argCount) {
+ case 1: return function(value) {
+ return func.call(context, value);
+ };
+ // The 2-argument case is omitted because we’re not using it.
+ case 3: return function(value, index, collection) {
+ return func.call(context, value, index, collection);
+ };
+ case 4: return function(accumulator, value, index, collection) {
+ return func.call(context, accumulator, value, index, collection);
+ };
+ }
+ return function() {
+ return func.apply(context, arguments);
+ };
+ };
+
+ var builtinIteratee;
+
+ // An internal function to generate callbacks that can be applied to each
+ // element in a collection, returning the desired result — either `identity`,
+ // an arbitrary callback, a property matcher, or a property accessor.
+ var cb = function(value, context, argCount) {
+ if (_.iteratee !== builtinIteratee) return _.iteratee(value, context);
+ if (value == null) return _.identity;
+ if (_.isFunction(value)) return optimizeCb(value, context, argCount);
+ if (_.isObject(value) && !_.isArray(value)) return _.matcher(value);
+ return _.property(value);
+ };
+
+ // External wrapper for our callback generator. Users may customize
+ // `_.iteratee` if they want additional predicate/iteratee shorthand styles.
+ // This abstraction hides the internal-only argCount argument.
+ _.iteratee = builtinIteratee = function(value, context) {
+ return cb(value, context, Infinity);
+ };
+
+ // Some functions take a variable number of arguments, or a few expected
+ // arguments at the beginning and then a variable number of values to operate
+ // on. This helper accumulates all remaining arguments past the function’s
+ // argument length (or an explicit `startIndex`), into an array that becomes
+ // the last argument. Similar to ES6’s "rest parameter".
+ var restArguments = function(func, startIndex) {
+ startIndex = startIndex == null ? func.length - 1 : +startIndex;
+ return function() {
+ var length = Math.max(arguments.length - startIndex, 0),
+ rest = Array(length),
+ index = 0;
+ for (; index < length; index++) {
+ rest[index] = arguments[index + startIndex];
+ }
+ switch (startIndex) {
+ case 0: return func.call(this, rest);
+ case 1: return func.call(this, arguments[0], rest);
+ case 2: return func.call(this, arguments[0], arguments[1], rest);
+ }
+ var args = Array(startIndex + 1);
+ for (index = 0; index < startIndex; index++) {
+ args[index] = arguments[index];
+ }
+ args[startIndex] = rest;
+ return func.apply(this, args);
+ };
+ };
+
+ // An internal function for creating a new object that inherits from another.
+ var baseCreate = function(prototype) {
+ if (!_.isObject(prototype)) return {};
+ if (nativeCreate) return nativeCreate(prototype);
+ Ctor.prototype = prototype;
+ var result = new Ctor;
+ Ctor.prototype = null;
+ return result;
+ };
+
+ var shallowProperty = function(key) {
+ return function(obj) {
+ return obj == null ? void 0 : obj[key];
+ };
+ };
+
+ var has = function(obj, path) {
+ return obj != null && hasOwnProperty.call(obj, path);
+ }
+
+ var deepGet = function(obj, path) {
+ var length = path.length;
+ for (var i = 0; i < length; i++) {
+ if (obj == null) return void 0;
+ obj = obj[path[i]];
+ }
+ return length ? obj : void 0;
+ };
+
+ // Helper for collection methods to determine whether a collection
+ // should be iterated as an array or as an object.
+ // Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength
+ // Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094
+ var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
+ var getLength = shallowProperty('length');
+ var isArrayLike = function(collection) {
+ var length = getLength(collection);
+ return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
+ };
+
+ // Collection Functions
+ // --------------------
+
+ // The cornerstone, an `each` implementation, aka `forEach`.
+ // Handles raw objects in addition to array-likes. Treats all
+ // sparse array-likes as if they were dense.
+ _.each = _.forEach = function(obj, iteratee, context) {
+ iteratee = optimizeCb(iteratee, context);
+ var i, length;
+ if (isArrayLike(obj)) {
+ for (i = 0, length = obj.length; i < length; i++) {
+ iteratee(obj[i], i, obj);
+ }
+ } else {
+ var keys = _.keys(obj);
+ for (i = 0, length = keys.length; i < length; i++) {
+ iteratee(obj[keys[i]], keys[i], obj);
+ }
+ }
+ return obj;
+ };
+
+ // Return the results of applying the iteratee to each element.
+ _.map = _.collect = function(obj, iteratee, context) {
+ iteratee = cb(iteratee, context);
+ var keys = !isArrayLike(obj) && _.keys(obj),
+ length = (keys || obj).length,
+ results = Array(length);
+ for (var index = 0; index < length; index++) {
+ var currentKey = keys ? keys[index] : index;
+ results[index] = iteratee(obj[currentKey], currentKey, obj);
+ }
+ return results;
+ };
+
+ // Create a reducing function iterating left or right.
+ var createReduce = function(dir) {
+ // Wrap code that reassigns argument variables in a separate function than
+ // the one that accesses `arguments.length` to avoid a perf hit. (#1991)
+ var reducer = function(obj, iteratee, memo, initial) {
+ var keys = !isArrayLike(obj) && _.keys(obj),
+ length = (keys || obj).length,
+ index = dir > 0 ? 0 : length - 1;
+ if (!initial) {
+ memo = obj[keys ? keys[index] : index];
+ index += dir;
+ }
+ for (; index >= 0 && index < length; index += dir) {
+ var currentKey = keys ? keys[index] : index;
+ memo = iteratee(memo, obj[currentKey], currentKey, obj);
+ }
+ return memo;
+ };
+
+ return function(obj, iteratee, memo, context) {
+ var initial = arguments.length >= 3;
+ return reducer(obj, optimizeCb(iteratee, context, 4), memo, initial);
+ };
+ };
+
+ // **Reduce** builds up a single result from a list of values, aka `inject`,
+ // or `foldl`.
+ _.reduce = _.foldl = _.inject = createReduce(1);
+
+ // The right-associative version of reduce, also known as `foldr`.
+ _.reduceRight = _.foldr = createReduce(-1);
+
+ // Return the first value which passes a truth test. Aliased as `detect`.
+ _.find = _.detect = function(obj, predicate, context) {
+ var keyFinder = isArrayLike(obj) ? _.findIndex : _.findKey;
+ var key = keyFinder(obj, predicate, context);
+ if (key !== void 0 && key !== -1) return obj[key];
+ };
+
+ // Return all the elements that pass a truth test.
+ // Aliased as `select`.
+ _.filter = _.select = function(obj, predicate, context) {
+ var results = [];
+ predicate = cb(predicate, context);
+ _.each(obj, function(value, index, list) {
+ if (predicate(value, index, list)) results.push(value);
+ });
+ return results;
+ };
+
+ // Return all the elements for which a truth test fails.
+ _.reject = function(obj, predicate, context) {
+ return _.filter(obj, _.negate(cb(predicate)), context);
+ };
+
+ // Determine whether all of the elements match a truth test.
+ // Aliased as `all`.
+ _.every = _.all = function(obj, predicate, context) {
+ predicate = cb(predicate, context);
+ var keys = !isArrayLike(obj) && _.keys(obj),
+ length = (keys || obj).length;
+ for (var index = 0; index < length; index++) {
+ var currentKey = keys ? keys[index] : index;
+ if (!predicate(obj[currentKey], currentKey, obj)) return false;
+ }
+ return true;
+ };
+
+ // Determine if at least one element in the object matches a truth test.
+ // Aliased as `any`.
+ _.some = _.any = function(obj, predicate, context) {
+ predicate = cb(predicate, context);
+ var keys = !isArrayLike(obj) && _.keys(obj),
+ length = (keys || obj).length;
+ for (var index = 0; index < length; index++) {
+ var currentKey = keys ? keys[index] : index;
+ if (predicate(obj[currentKey], currentKey, obj)) return true;
+ }
+ return false;
+ };
+
+ // Determine if the array or object contains a given item (using `===`).
+ // Aliased as `includes` and `include`.
+ _.contains = _.includes = _.include = function(obj, item, fromIndex, guard) {
+ if (!isArrayLike(obj)) obj = _.values(obj);
+ if (typeof fromIndex != 'number' || guard) fromIndex = 0;
+ return _.indexOf(obj, item, fromIndex) >= 0;
+ };
+
+ // Invoke a method (with arguments) on every item in a collection.
+ _.invoke = restArguments(function(obj, path, args) {
+ var contextPath, func;
+ if (_.isFunction(path)) {
+ func = path;
+ } else if (_.isArray(path)) {
+ contextPath = path.slice(0, -1);
+ path = path[path.length - 1];
+ }
+ return _.map(obj, function(context) {
+ var method = func;
+ if (!method) {
+ if (contextPath && contextPath.length) {
+ context = deepGet(context, contextPath);
+ }
+ if (context == null) return void 0;
+ method = context[path];
+ }
+ return method == null ? method : method.apply(context, args);
+ });
+ });
+
+ // Convenience version of a common use case of `map`: fetching a property.
+ _.pluck = function(obj, key) {
+ return _.map(obj, _.property(key));
+ };
+
+ // Convenience version of a common use case of `filter`: selecting only objects
+ // containing specific `key:value` pairs.
+ _.where = function(obj, attrs) {
+ return _.filter(obj, _.matcher(attrs));
+ };
+
+ // Convenience version of a common use case of `find`: getting the first object
+ // containing specific `key:value` pairs.
+ _.findWhere = function(obj, attrs) {
+ return _.find(obj, _.matcher(attrs));
+ };
+
+ // Return the maximum element (or element-based computation).
+ _.max = function(obj, iteratee, context) {
+ var result = -Infinity, lastComputed = -Infinity,
+ value, computed;
+ if (iteratee == null || typeof iteratee == 'number' && typeof obj[0] != 'object' && obj != null) {
+ obj = isArrayLike(obj) ? obj : _.values(obj);
+ for (var i = 0, length = obj.length; i < length; i++) {
+ value = obj[i];
+ if (value != null && value > result) {
+ result = value;
+ }
+ }
+ } else {
+ iteratee = cb(iteratee, context);
+ _.each(obj, function(v, index, list) {
+ computed = iteratee(v, index, list);
+ if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
+ result = v;
+ lastComputed = computed;
+ }
+ });
+ }
+ return result;
+ };
+
+ // Return the minimum element (or element-based computation).
+ _.min = function(obj, iteratee, context) {
+ var result = Infinity, lastComputed = Infinity,
+ value, computed;
+ if (iteratee == null || typeof iteratee == 'number' && typeof obj[0] != 'object' && obj != null) {
+ obj = isArrayLike(obj) ? obj : _.values(obj);
+ for (var i = 0, length = obj.length; i < length; i++) {
+ value = obj[i];
+ if (value != null && value < result) {
+ result = value;
+ }
+ }
+ } else {
+ iteratee = cb(iteratee, context);
+ _.each(obj, function(v, index, list) {
+ computed = iteratee(v, index, list);
+ if (computed < lastComputed || computed === Infinity && result === Infinity) {
+ result = v;
+ lastComputed = computed;
+ }
+ });
+ }
+ return result;
+ };
+
+ // Shuffle a collection.
+ _.shuffle = function(obj) {
+ return _.sample(obj, Infinity);
+ };
+
+ // Sample **n** random values from a collection using the modern version of the
+ // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
+ // If **n** is not specified, returns a single random element.
+ // The internal `guard` argument allows it to work with `map`.
+ _.sample = function(obj, n, guard) {
+ if (n == null || guard) {
+ if (!isArrayLike(obj)) obj = _.values(obj);
+ return obj[_.random(obj.length - 1)];
+ }
+ var sample = isArrayLike(obj) ? _.clone(obj) : _.values(obj);
+ var length = getLength(sample);
+ n = Math.max(Math.min(n, length), 0);
+ var last = length - 1;
+ for (var index = 0; index < n; index++) {
+ var rand = _.random(index, last);
+ var temp = sample[index];
+ sample[index] = sample[rand];
+ sample[rand] = temp;
+ }
+ return sample.slice(0, n);
+ };
+
+ // Sort the object's values by a criterion produced by an iteratee.
+ _.sortBy = function(obj, iteratee, context) {
+ var index = 0;
+ iteratee = cb(iteratee, context);
+ return _.pluck(_.map(obj, function(value, key, list) {
+ return {
+ value: value,
+ index: index++,
+ criteria: iteratee(value, key, list)
+ };
+ }).sort(function(left, right) {
+ var a = left.criteria;
+ var b = right.criteria;
+ if (a !== b) {
+ if (a > b || a === void 0) return 1;
+ if (a < b || b === void 0) return -1;
+ }
+ return left.index - right.index;
+ }), 'value');
+ };
+
+ // An internal function used for aggregate "group by" operations.
+ var group = function(behavior, partition) {
+ return function(obj, iteratee, context) {
+ var result = partition ? [[], []] : {};
+ iteratee = cb(iteratee, context);
+ _.each(obj, function(value, index) {
+ var key = iteratee(value, index, obj);
+ behavior(result, value, key);
+ });
+ return result;
+ };
+ };
+
+ // Groups the object's values by a criterion. Pass either a string attribute
+ // to group by, or a function that returns the criterion.
+ _.groupBy = group(function(result, value, key) {
+ if (has(result, key)) result[key].push(value); else result[key] = [value];
+ });
+
+ // Indexes the object's values by a criterion, similar to `groupBy`, but for
+ // when you know that your index values will be unique.
+ _.indexBy = group(function(result, value, key) {
+ result[key] = value;
+ });
+
+ // Counts instances of an object that group by a certain criterion. Pass
+ // either a string attribute to count by, or a function that returns the
+ // criterion.
+ _.countBy = group(function(result, value, key) {
+ if (has(result, key)) result[key]++; else result[key] = 1;
+ });
+
+ var reStrSymbol = /[^\ud800-\udfff]|[\ud800-\udbff][\udc00-\udfff]|[\ud800-\udfff]/g;
+ // Safely create a real, live array from anything iterable.
+ _.toArray = function(obj) {
+ if (!obj) return [];
+ if (_.isArray(obj)) return slice.call(obj);
+ if (_.isString(obj)) {
+ // Keep surrogate pair characters together
+ return obj.match(reStrSymbol);
+ }
+ if (isArrayLike(obj)) return _.map(obj, _.identity);
+ return _.values(obj);
+ };
+
+ // Return the number of elements in an object.
+ _.size = function(obj) {
+ if (obj == null) return 0;
+ return isArrayLike(obj) ? obj.length : _.keys(obj).length;
+ };
+
+ // Split a collection into two arrays: one whose elements all satisfy the given
+ // predicate, and one whose elements all do not satisfy the predicate.
+ _.partition = group(function(result, value, pass) {
+ result[pass ? 0 : 1].push(value);
+ }, true);
+
+ // Array Functions
+ // ---------------
+
+ // Get the first element of an array. Passing **n** will return the first N
+ // values in the array. Aliased as `head` and `take`. The **guard** check
+ // allows it to work with `_.map`.
+ _.first = _.head = _.take = function(array, n, guard) {
+ if (array == null || array.length < 1) return n == null ? void 0 : [];
+ if (n == null || guard) return array[0];
+ return _.initial(array, array.length - n);
+ };
+
+ // Returns everything but the last entry of the array. Especially useful on
+ // the arguments object. Passing **n** will return all the values in
+ // the array, excluding the last N.
+ _.initial = function(array, n, guard) {
+ return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
+ };
+
+ // Get the last element of an array. Passing **n** will return the last N
+ // values in the array.
+ _.last = function(array, n, guard) {
+ if (array == null || array.length < 1) return n == null ? void 0 : [];
+ if (n == null || guard) return array[array.length - 1];
+ return _.rest(array, Math.max(0, array.length - n));
+ };
+
+ // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
+ // Especially useful on the arguments object. Passing an **n** will return
+ // the rest N values in the array.
+ _.rest = _.tail = _.drop = function(array, n, guard) {
+ return slice.call(array, n == null || guard ? 1 : n);
+ };
+
+ // Trim out all falsy values from an array.
+ _.compact = function(array) {
+ return _.filter(array, Boolean);
+ };
+
+ // Internal implementation of a recursive `flatten` function.
+ var flatten = function(input, shallow, strict, output) {
+ output = output || [];
+ var idx = output.length;
+ for (var i = 0, length = getLength(input); i < length; i++) {
+ var value = input[i];
+ if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
+ // Flatten current level of array or arguments object.
+ if (shallow) {
+ var j = 0, len = value.length;
+ while (j < len) output[idx++] = value[j++];
+ } else {
+ flatten(value, shallow, strict, output);
+ idx = output.length;
+ }
+ } else if (!strict) {
+ output[idx++] = value;
+ }
+ }
+ return output;
+ };
+
+ // Flatten out an array, either recursively (by default), or just one level.
+ _.flatten = function(array, shallow) {
+ return flatten(array, shallow, false);
+ };
+
+ // Return a version of the array that does not contain the specified value(s).
+ _.without = restArguments(function(array, otherArrays) {
+ return _.difference(array, otherArrays);
+ });
+
+ // Produce a duplicate-free version of the array. If the array has already
+ // been sorted, you have the option of using a faster algorithm.
+ // The faster algorithm will not work with an iteratee if the iteratee
+ // is not a one-to-one function, so providing an iteratee will disable
+ // the faster algorithm.
+ // Aliased as `unique`.
+ _.uniq = _.unique = function(array, isSorted, iteratee, context) {
+ if (!_.isBoolean(isSorted)) {
+ context = iteratee;
+ iteratee = isSorted;
+ isSorted = false;
+ }
+ if (iteratee != null) iteratee = cb(iteratee, context);
+ var result = [];
+ var seen = [];
+ for (var i = 0, length = getLength(array); i < length; i++) {
+ var value = array[i],
+ computed = iteratee ? iteratee(value, i, array) : value;
+ if (isSorted && !iteratee) {
+ if (!i || seen !== computed) result.push(value);
+ seen = computed;
+ } else if (iteratee) {
+ if (!_.contains(seen, computed)) {
+ seen.push(computed);
+ result.push(value);
+ }
+ } else if (!_.contains(result, value)) {
+ result.push(value);
+ }
+ }
+ return result;
+ };
+
+ // Produce an array that contains the union: each distinct element from all of
+ // the passed-in arrays.
+ _.union = restArguments(function(arrays) {
+ return _.uniq(flatten(arrays, true, true));
+ });
+
+ // Produce an array that contains every item shared between all the
+ // passed-in arrays.
+ _.intersection = function(array) {
+ var result = [];
+ var argsLength = arguments.length;
+ for (var i = 0, length = getLength(array); i < length; i++) {
+ var item = array[i];
+ if (_.contains(result, item)) continue;
+ var j;
+ for (j = 1; j < argsLength; j++) {
+ if (!_.contains(arguments[j], item)) break;
+ }
+ if (j === argsLength) result.push(item);
+ }
+ return result;
+ };
+
+ // Take the difference between one array and a number of other arrays.
+ // Only the elements present in just the first array will remain.
+ _.difference = restArguments(function(array, rest) {
+ rest = flatten(rest, true, true);
+ return _.filter(array, function(value){
+ return !_.contains(rest, value);
+ });
+ });
+
+ // Complement of _.zip. Unzip accepts an array of arrays and groups
+ // each array's elements on shared indices.
+ _.unzip = function(array) {
+ var length = array && _.max(array, getLength).length || 0;
+ var result = Array(length);
+
+ for (var index = 0; index < length; index++) {
+ result[index] = _.pluck(array, index);
+ }
+ return result;
+ };
+
+ // Zip together multiple lists into a single array -- elements that share
+ // an index go together.
+ _.zip = restArguments(_.unzip);
+
+ // Converts lists into objects. Pass either a single array of `[key, value]`
+ // pairs, or two parallel arrays of the same length -- one of keys, and one of
+ // the corresponding values. Passing by pairs is the reverse of _.pairs.
+ _.object = function(list, values) {
+ var result = {};
+ for (var i = 0, length = getLength(list); i < length; i++) {
+ if (values) {
+ result[list[i]] = values[i];
+ } else {
+ result[list[i][0]] = list[i][1];
+ }
+ }
+ return result;
+ };
+
+ // Generator function to create the findIndex and findLastIndex functions.
+ var createPredicateIndexFinder = function(dir) {
+ return function(array, predicate, context) {
+ predicate = cb(predicate, context);
+ var length = getLength(array);
+ var index = dir > 0 ? 0 : length - 1;
+ for (; index >= 0 && index < length; index += dir) {
+ if (predicate(array[index], index, array)) return index;
+ }
+ return -1;
+ };
+ };
+
+ // Returns the first index on an array-like that passes a predicate test.
+ _.findIndex = createPredicateIndexFinder(1);
+ _.findLastIndex = createPredicateIndexFinder(-1);
+
+ // Use a comparator function to figure out the smallest index at which
+ // an object should be inserted so as to maintain order. Uses binary search.
+ _.sortedIndex = function(array, obj, iteratee, context) {
+ iteratee = cb(iteratee, context, 1);
+ var value = iteratee(obj);
+ var low = 0, high = getLength(array);
+ while (low < high) {
+ var mid = Math.floor((low + high) / 2);
+ if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;
+ }
+ return low;
+ };
+
+ // Generator function to create the indexOf and lastIndexOf functions.
+ var createIndexFinder = function(dir, predicateFind, sortedIndex) {
+ return function(array, item, idx) {
+ var i = 0, length = getLength(array);
+ if (typeof idx == 'number') {
+ if (dir > 0) {
+ i = idx >= 0 ? idx : Math.max(idx + length, i);
+ } else {
+ length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1;
+ }
+ } else if (sortedIndex && idx && length) {
+ idx = sortedIndex(array, item);
+ return array[idx] === item ? idx : -1;
+ }
+ if (item !== item) {
+ idx = predicateFind(slice.call(array, i, length), _.isNaN);
+ return idx >= 0 ? idx + i : -1;
+ }
+ for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) {
+ if (array[idx] === item) return idx;
+ }
+ return -1;
+ };
+ };
+
+ // Return the position of the first occurrence of an item in an array,
+ // or -1 if the item is not included in the array.
+ // If the array is large and already in sort order, pass `true`
+ // for **isSorted** to use binary search.
+ _.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex);
+ _.lastIndexOf = createIndexFinder(-1, _.findLastIndex);
+
+ // Generate an integer Array containing an arithmetic progression. A port of
+ // the native Python `range()` function. See
+ // [the Python documentation](http://docs.python.org/library/functions.html#range).
+ _.range = function(start, stop, step) {
+ if (stop == null) {
+ stop = start || 0;
+ start = 0;
+ }
+ if (!step) {
+ step = stop < start ? -1 : 1;
+ }
+
+ var length = Math.max(Math.ceil((stop - start) / step), 0);
+ var range = Array(length);
+
+ for (var idx = 0; idx < length; idx++, start += step) {
+ range[idx] = start;
+ }
+
+ return range;
+ };
+
+ // Chunk a single array into multiple arrays, each containing `count` or fewer
+ // items.
+ _.chunk = function(array, count) {
+ if (count == null || count < 1) return [];
+ var result = [];
+ var i = 0, length = array.length;
+ while (i < length) {
+ result.push(slice.call(array, i, i += count));
+ }
+ return result;
+ };
+
+ // Function (ahem) Functions
+ // ------------------
+
+ // Determines whether to execute a function as a constructor
+ // or a normal function with the provided arguments.
+ var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) {
+ if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args);
+ var self = baseCreate(sourceFunc.prototype);
+ var result = sourceFunc.apply(self, args);
+ if (_.isObject(result)) return result;
+ return self;
+ };
+
+ // Create a function bound to a given object (assigning `this`, and arguments,
+ // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
+ // available.
+ _.bind = restArguments(function(func, context, args) {
+ if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function');
+ var bound = restArguments(function(callArgs) {
+ return executeBound(func, bound, context, this, args.concat(callArgs));
+ });
+ return bound;
+ });
+
+ // Partially apply a function by creating a version that has had some of its
+ // arguments pre-filled, without changing its dynamic `this` context. _ acts
+ // as a placeholder by default, allowing any combination of arguments to be
+ // pre-filled. Set `_.partial.placeholder` for a custom placeholder argument.
+ _.partial = restArguments(function(func, boundArgs) {
+ var placeholder = _.partial.placeholder;
+ var bound = function() {
+ var position = 0, length = boundArgs.length;
+ var args = Array(length);
+ for (var i = 0; i < length; i++) {
+ args[i] = boundArgs[i] === placeholder ? arguments[position++] : boundArgs[i];
+ }
+ while (position < arguments.length) args.push(arguments[position++]);
+ return executeBound(func, bound, this, this, args);
+ };
+ return bound;
+ });
+
+ _.partial.placeholder = _;
+
+ // Bind a number of an object's methods to that object. Remaining arguments
+ // are the method names to be bound. Useful for ensuring that all callbacks
+ // defined on an object belong to it.
+ _.bindAll = restArguments(function(obj, keys) {
+ keys = flatten(keys, false, false);
+ var index = keys.length;
+ if (index < 1) throw new Error('bindAll must be passed function names');
+ while (index--) {
+ var key = keys[index];
+ obj[key] = _.bind(obj[key], obj);
+ }
+ });
+
+ // Memoize an expensive function by storing its results.
+ _.memoize = function(func, hasher) {
+ var memoize = function(key) {
+ var cache = memoize.cache;
+ var address = '' + (hasher ? hasher.apply(this, arguments) : key);
+ if (!has(cache, address)) cache[address] = func.apply(this, arguments);
+ return cache[address];
+ };
+ memoize.cache = {};
+ return memoize;
+ };
+
+ // Delays a function for the given number of milliseconds, and then calls
+ // it with the arguments supplied.
+ _.delay = restArguments(function(func, wait, args) {
+ return setTimeout(function() {
+ return func.apply(null, args);
+ }, wait);
+ });
+
+ // Defers a function, scheduling it to run after the current call stack has
+ // cleared.
+ _.defer = _.partial(_.delay, _, 1);
+
+ // Returns a function, that, when invoked, will only be triggered at most once
+ // during a given window of time. Normally, the throttled function will run
+ // as much as it can, without ever going more than once per `wait` duration;
+ // but if you'd like to disable the execution on the leading edge, pass
+ // `{leading: false}`. To disable execution on the trailing edge, ditto.
+ _.throttle = function(func, wait, options) {
+ var timeout, context, args, result;
+ var previous = 0;
+ if (!options) options = {};
+
+ var later = function() {
+ previous = options.leading === false ? 0 : _.now();
+ timeout = null;
+ result = func.apply(context, args);
+ if (!timeout) context = args = null;
+ };
+
+ var throttled = function() {
+ var now = _.now();
+ if (!previous && options.leading === false) previous = now;
+ var remaining = wait - (now - previous);
+ context = this;
+ args = arguments;
+ if (remaining <= 0 || remaining > wait) {
+ if (timeout) {
+ clearTimeout(timeout);
+ timeout = null;
+ }
+ previous = now;
+ result = func.apply(context, args);
+ if (!timeout) context = args = null;
+ } else if (!timeout && options.trailing !== false) {
+ timeout = setTimeout(later, remaining);
+ }
+ return result;
+ };
+
+ throttled.cancel = function() {
+ clearTimeout(timeout);
+ previous = 0;
+ timeout = context = args = null;
+ };
+
+ return throttled;
+ };
+
+ // Returns a function, that, as long as it continues to be invoked, will not
+ // be triggered. The function will be called after it stops being called for
+ // N milliseconds. If `immediate` is passed, trigger the function on the
+ // leading edge, instead of the trailing.
+ _.debounce = function(func, wait, immediate) {
+ var timeout, result;
+
+ var later = function(context, args) {
+ timeout = null;
+ if (args) result = func.apply(context, args);
+ };
+
+ var debounced = restArguments(function(args) {
+ if (timeout) clearTimeout(timeout);
+ if (immediate) {
+ var callNow = !timeout;
+ timeout = setTimeout(later, wait);
+ if (callNow) result = func.apply(this, args);
+ } else {
+ timeout = _.delay(later, wait, this, args);
+ }
+
+ return result;
+ });
+
+ debounced.cancel = function() {
+ clearTimeout(timeout);
+ timeout = null;
+ };
+
+ return debounced;
+ };
+
+ // Returns the first function passed as an argument to the second,
+ // allowing you to adjust arguments, run code before and after, and
+ // conditionally execute the original function.
+ _.wrap = function(func, wrapper) {
+ return _.partial(wrapper, func);
+ };
+
+ // Returns a negated version of the passed-in predicate.
+ _.negate = function(predicate) {
+ return function() {
+ return !predicate.apply(this, arguments);
+ };
+ };
+
+ // Returns a function that is the composition of a list of functions, each
+ // consuming the return value of the function that follows.
+ _.compose = function() {
+ var args = arguments;
+ var start = args.length - 1;
+ return function() {
+ var i = start;
+ var result = args[start].apply(this, arguments);
+ while (i--) result = args[i].call(this, result);
+ return result;
+ };
+ };
+
+ // Returns a function that will only be executed on and after the Nth call.
+ _.after = function(times, func) {
+ return function() {
+ if (--times < 1) {
+ return func.apply(this, arguments);
+ }
+ };
+ };
+
+ // Returns a function that will only be executed up to (but not including) the Nth call.
+ _.before = function(times, func) {
+ var memo;
+ return function() {
+ if (--times > 0) {
+ memo = func.apply(this, arguments);
+ }
+ if (times <= 1) func = null;
+ return memo;
+ };
+ };
+
+ // Returns a function that will be executed at most one time, no matter how
+ // often you call it. Useful for lazy initialization.
+ _.once = _.partial(_.before, 2);
+
+ _.restArguments = restArguments;
+
+ // Object Functions
+ // ----------------
+
+ // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed.
+ var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString');
+ var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString',
+ 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'];
+
+ var collectNonEnumProps = function(obj, keys) {
+ var nonEnumIdx = nonEnumerableProps.length;
+ var constructor = obj.constructor;
+ var proto = _.isFunction(constructor) && constructor.prototype || ObjProto;
+
+ // Constructor is a special case.
+ var prop = 'constructor';
+ if (has(obj, prop) && !_.contains(keys, prop)) keys.push(prop);
+
+ while (nonEnumIdx--) {
+ prop = nonEnumerableProps[nonEnumIdx];
+ if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) {
+ keys.push(prop);
+ }
+ }
+ };
+
+ // Retrieve the names of an object's own properties.
+ // Delegates to **ECMAScript 5**'s native `Object.keys`.
+ _.keys = function(obj) {
+ if (!_.isObject(obj)) return [];
+ if (nativeKeys) return nativeKeys(obj);
+ var keys = [];
+ for (var key in obj) if (has(obj, key)) keys.push(key);
+ // Ahem, IE < 9.
+ if (hasEnumBug) collectNonEnumProps(obj, keys);
+ return keys;
+ };
+
+ // Retrieve all the property names of an object.
+ _.allKeys = function(obj) {
+ if (!_.isObject(obj)) return [];
+ var keys = [];
+ for (var key in obj) keys.push(key);
+ // Ahem, IE < 9.
+ if (hasEnumBug) collectNonEnumProps(obj, keys);
+ return keys;
+ };
+
+ // Retrieve the values of an object's properties.
+ _.values = function(obj) {
+ var keys = _.keys(obj);
+ var length = keys.length;
+ var values = Array(length);
+ for (var i = 0; i < length; i++) {
+ values[i] = obj[keys[i]];
+ }
+ return values;
+ };
+
+ // Returns the results of applying the iteratee to each element of the object.
+ // In contrast to _.map it returns an object.
+ _.mapObject = function(obj, iteratee, context) {
+ iteratee = cb(iteratee, context);
+ var keys = _.keys(obj),
+ length = keys.length,
+ results = {};
+ for (var index = 0; index < length; index++) {
+ var currentKey = keys[index];
+ results[currentKey] = iteratee(obj[currentKey], currentKey, obj);
+ }
+ return results;
+ };
+
+ // Convert an object into a list of `[key, value]` pairs.
+ // The opposite of _.object.
+ _.pairs = function(obj) {
+ var keys = _.keys(obj);
+ var length = keys.length;
+ var pairs = Array(length);
+ for (var i = 0; i < length; i++) {
+ pairs[i] = [keys[i], obj[keys[i]]];
+ }
+ return pairs;
+ };
+
+ // Invert the keys and values of an object. The values must be serializable.
+ _.invert = function(obj) {
+ var result = {};
+ var keys = _.keys(obj);
+ for (var i = 0, length = keys.length; i < length; i++) {
+ result[obj[keys[i]]] = keys[i];
+ }
+ return result;
+ };
+
+ // Return a sorted list of the function names available on the object.
+ // Aliased as `methods`.
+ _.functions = _.methods = function(obj) {
+ var names = [];
+ for (var key in obj) {
+ if (_.isFunction(obj[key])) names.push(key);
+ }
+ return names.sort();
+ };
+
+ // An internal function for creating assigner functions.
+ var createAssigner = function(keysFunc, defaults) {
+ return function(obj) {
+ var length = arguments.length;
+ if (defaults) obj = Object(obj);
+ if (length < 2 || obj == null) return obj;
+ for (var index = 1; index < length; index++) {
+ var source = arguments[index],
+ keys = keysFunc(source),
+ l = keys.length;
+ for (var i = 0; i < l; i++) {
+ var key = keys[i];
+ if (!defaults || obj[key] === void 0) obj[key] = source[key];
+ }
+ }
+ return obj;
+ };
+ };
+
+ // Extend a given object with all the properties in passed-in object(s).
+ _.extend = createAssigner(_.allKeys);
+
+ // Assigns a given object with all the own properties in the passed-in object(s).
+ // (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
+ _.extendOwn = _.assign = createAssigner(_.keys);
+
+ // Returns the first key on an object that passes a predicate test.
+ _.findKey = function(obj, predicate, context) {
+ predicate = cb(predicate, context);
+ var keys = _.keys(obj), key;
+ for (var i = 0, length = keys.length; i < length; i++) {
+ key = keys[i];
+ if (predicate(obj[key], key, obj)) return key;
+ }
+ };
+
+ // Internal pick helper function to determine if `obj` has key `key`.
+ var keyInObj = function(value, key, obj) {
+ return key in obj;
+ };
+
+ // Return a copy of the object only containing the whitelisted properties.
+ _.pick = restArguments(function(obj, keys) {
+ var result = {}, iteratee = keys[0];
+ if (obj == null) return result;
+ if (_.isFunction(iteratee)) {
+ if (keys.length > 1) iteratee = optimizeCb(iteratee, keys[1]);
+ keys = _.allKeys(obj);
+ } else {
+ iteratee = keyInObj;
+ keys = flatten(keys, false, false);
+ obj = Object(obj);
+ }
+ for (var i = 0, length = keys.length; i < length; i++) {
+ var key = keys[i];
+ var value = obj[key];
+ if (iteratee(value, key, obj)) result[key] = value;
+ }
+ return result;
+ });
+
+ // Return a copy of the object without the blacklisted properties.
+ _.omit = restArguments(function(obj, keys) {
+ var iteratee = keys[0], context;
+ if (_.isFunction(iteratee)) {
+ iteratee = _.negate(iteratee);
+ if (keys.length > 1) context = keys[1];
+ } else {
+ keys = _.map(flatten(keys, false, false), String);
+ iteratee = function(value, key) {
+ return !_.contains(keys, key);
+ };
+ }
+ return _.pick(obj, iteratee, context);
+ });
+
+ // Fill in a given object with default properties.
+ _.defaults = createAssigner(_.allKeys, true);
+
+ // Creates an object that inherits from the given prototype object.
+ // If additional properties are provided then they will be added to the
+ // created object.
+ _.create = function(prototype, props) {
+ var result = baseCreate(prototype);
+ if (props) _.extendOwn(result, props);
+ return result;
+ };
+
+ // Create a (shallow-cloned) duplicate of an object.
+ _.clone = function(obj) {
+ if (!_.isObject(obj)) return obj;
+ return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
+ };
+
+ // Invokes interceptor with the obj, and then returns obj.
+ // The primary purpose of this method is to "tap into" a method chain, in
+ // order to perform operations on intermediate results within the chain.
+ _.tap = function(obj, interceptor) {
+ interceptor(obj);
+ return obj;
+ };
+
+ // Returns whether an object has a given set of `key:value` pairs.
+ _.isMatch = function(object, attrs) {
+ var keys = _.keys(attrs), length = keys.length;
+ if (object == null) return !length;
+ var obj = Object(object);
+ for (var i = 0; i < length; i++) {
+ var key = keys[i];
+ if (attrs[key] !== obj[key] || !(key in obj)) return false;
+ }
+ return true;
+ };
+
+
+ // Internal recursive comparison function for `isEqual`.
+ var eq, deepEq;
+ eq = function(a, b, aStack, bStack) {
+ // Identical objects are equal. `0 === -0`, but they aren't identical.
+ // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
+ if (a === b) return a !== 0 || 1 / a === 1 / b;
+ // `null` or `undefined` only equal to itself (strict comparison).
+ if (a == null || b == null) return false;
+ // `NaN`s are equivalent, but non-reflexive.
+ if (a !== a) return b !== b;
+ // Exhaust primitive checks
+ var type = typeof a;
+ if (type !== 'function' && type !== 'object' && typeof b != 'object') return false;
+ return deepEq(a, b, aStack, bStack);
+ };
+
+ // Internal recursive comparison function for `isEqual`.
+ deepEq = function(a, b, aStack, bStack) {
+ // Unwrap any wrapped objects.
+ if (a instanceof _) a = a._wrapped;
+ if (b instanceof _) b = b._wrapped;
+ // Compare `[[Class]]` names.
+ var className = toString.call(a);
+ if (className !== toString.call(b)) return false;
+ switch (className) {
+ // Strings, numbers, regular expressions, dates, and booleans are compared by value.
+ case '[object RegExp]':
+ // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
+ case '[object String]':
+ // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
+ // equivalent to `new String("5")`.
+ return '' + a === '' + b;
+ case '[object Number]':
+ // `NaN`s are equivalent, but non-reflexive.
+ // Object(NaN) is equivalent to NaN.
+ if (+a !== +a) return +b !== +b;
+ // An `egal` comparison is performed for other numeric values.
+ return +a === 0 ? 1 / +a === 1 / b : +a === +b;
+ case '[object Date]':
+ case '[object Boolean]':
+ // Coerce dates and booleans to numeric primitive values. Dates are compared by their
+ // millisecond representations. Note that invalid dates with millisecond representations
+ // of `NaN` are not equivalent.
+ return +a === +b;
+ case '[object Symbol]':
+ return SymbolProto.valueOf.call(a) === SymbolProto.valueOf.call(b);
+ }
+
+ var areArrays = className === '[object Array]';
+ if (!areArrays) {
+ if (typeof a != 'object' || typeof b != 'object') return false;
+
+ // Objects with different constructors are not equivalent, but `Object`s or `Array`s
+ // from different frames are.
+ var aCtor = a.constructor, bCtor = b.constructor;
+ if (aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor &&
+ _.isFunction(bCtor) && bCtor instanceof bCtor)
+ && ('constructor' in a && 'constructor' in b)) {
+ return false;
+ }
+ }
+ // Assume equality for cyclic structures. The algorithm for detecting cyclic
+ // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
+
+ // Initializing stack of traversed objects.
+ // It's done here since we only need them for objects and arrays comparison.
+ aStack = aStack || [];
+ bStack = bStack || [];
+ var length = aStack.length;
+ while (length--) {
+ // Linear search. Performance is inversely proportional to the number of
+ // unique nested structures.
+ if (aStack[length] === a) return bStack[length] === b;
+ }
+
+ // Add the first object to the stack of traversed objects.
+ aStack.push(a);
+ bStack.push(b);
+
+ // Recursively compare objects and arrays.
+ if (areArrays) {
+ // Compare array lengths to determine if a deep comparison is necessary.
+ length = a.length;
+ if (length !== b.length) return false;
+ // Deep compare the contents, ignoring non-numeric properties.
+ while (length--) {
+ if (!eq(a[length], b[length], aStack, bStack)) return false;
+ }
+ } else {
+ // Deep compare objects.
+ var keys = _.keys(a), key;
+ length = keys.length;
+ // Ensure that both objects contain the same number of properties before comparing deep equality.
+ if (_.keys(b).length !== length) return false;
+ while (length--) {
+ // Deep compare each member
+ key = keys[length];
+ if (!(has(b, key) && eq(a[key], b[key], aStack, bStack))) return false;
+ }
+ }
+ // Remove the first object from the stack of traversed objects.
+ aStack.pop();
+ bStack.pop();
+ return true;
+ };
+
+ // Perform a deep comparison to check if two objects are equal.
+ _.isEqual = function(a, b) {
+ return eq(a, b);
+ };
+
+ // Is a given array, string, or object empty?
+ // An "empty" object has no enumerable own-properties.
+ _.isEmpty = function(obj) {
+ if (obj == null) return true;
+ if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0;
+ return _.keys(obj).length === 0;
+ };
+
+ // Is a given value a DOM element?
+ _.isElement = function(obj) {
+ return !!(obj && obj.nodeType === 1);
+ };
+
+ // Is a given value an array?
+ // Delegates to ECMA5's native Array.isArray
+ _.isArray = nativeIsArray || function(obj) {
+ return toString.call(obj) === '[object Array]';
+ };
+
+ // Is a given variable an object?
+ _.isObject = function(obj) {
+ var type = typeof obj;
+ return type === 'function' || type === 'object' && !!obj;
+ };
+
+ // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError, isMap, isWeakMap, isSet, isWeakSet.
+ _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error', 'Symbol', 'Map', 'WeakMap', 'Set', 'WeakSet'], function(name) {
+ _['is' + name] = function(obj) {
+ return toString.call(obj) === '[object ' + name + ']';
+ };
+ });
+
+ // Define a fallback version of the method in browsers (ahem, IE < 9), where
+ // there isn't any inspectable "Arguments" type.
+ if (!_.isArguments(arguments)) {
+ _.isArguments = function(obj) {
+ return has(obj, 'callee');
+ };
+ }
+
+ // Optimize `isFunction` if appropriate. Work around some typeof bugs in old v8,
+ // IE 11 (#1621), Safari 8 (#1929), and PhantomJS (#2236).
+ var nodelist = root.document && root.document.childNodes;
+ if (typeof /./ != 'function' && typeof Int8Array != 'object' && typeof nodelist != 'function') {
+ _.isFunction = function(obj) {
+ return typeof obj == 'function' || false;
+ };
+ }
+
+ // Is a given object a finite number?
+ _.isFinite = function(obj) {
+ return !_.isSymbol(obj) && isFinite(obj) && !isNaN(parseFloat(obj));
+ };
+
+ // Is the given value `NaN`?
+ _.isNaN = function(obj) {
+ return _.isNumber(obj) && isNaN(obj);
+ };
+
+ // Is a given value a boolean?
+ _.isBoolean = function(obj) {
+ return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
+ };
+
+ // Is a given value equal to null?
+ _.isNull = function(obj) {
+ return obj === null;
+ };
+
+ // Is a given variable undefined?
+ _.isUndefined = function(obj) {
+ return obj === void 0;
+ };
+
+ // Shortcut function for checking if an object has a given property directly
+ // on itself (in other words, not on a prototype).
+ _.has = function(obj, path) {
+ if (!_.isArray(path)) {
+ return has(obj, path);
+ }
+ var length = path.length;
+ for (var i = 0; i < length; i++) {
+ var key = path[i];
+ if (obj == null || !hasOwnProperty.call(obj, key)) {
+ return false;
+ }
+ obj = obj[key];
+ }
+ return !!length;
+ };
+
+ // Utility Functions
+ // -----------------
+
+ // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
+ // previous owner. Returns a reference to the Underscore object.
+ _.noConflict = function() {
+ root._ = previousUnderscore;
+ return this;
+ };
+
+ // Keep the identity function around for default iteratees.
+ _.identity = function(value) {
+ return value;
+ };
+
+ // Predicate-generating functions. Often useful outside of Underscore.
+ _.constant = function(value) {
+ return function() {
+ return value;
+ };
+ };
+
+ _.noop = function(){};
+
+ // Creates a function that, when passed an object, will traverse that object’s
+ // properties down the given `path`, specified as an array of keys or indexes.
+ _.property = function(path) {
+ if (!_.isArray(path)) {
+ return shallowProperty(path);
+ }
+ return function(obj) {
+ return deepGet(obj, path);
+ };
+ };
+
+ // Generates a function for a given object that returns a given property.
+ _.propertyOf = function(obj) {
+ if (obj == null) {
+ return function(){};
+ }
+ return function(path) {
+ return !_.isArray(path) ? obj[path] : deepGet(obj, path);
+ };
+ };
+
+ // Returns a predicate for checking whether an object has a given set of
+ // `key:value` pairs.
+ _.matcher = _.matches = function(attrs) {
+ attrs = _.extendOwn({}, attrs);
+ return function(obj) {
+ return _.isMatch(obj, attrs);
+ };
+ };
+
+ // Run a function **n** times.
+ _.times = function(n, iteratee, context) {
+ var accum = Array(Math.max(0, n));
+ iteratee = optimizeCb(iteratee, context, 1);
+ for (var i = 0; i < n; i++) accum[i] = iteratee(i);
+ return accum;
+ };
+
+ // Return a random integer between min and max (inclusive).
+ _.random = function(min, max) {
+ if (max == null) {
+ max = min;
+ min = 0;
+ }
+ return min + Math.floor(Math.random() * (max - min + 1));
+ };
+
+ // A (possibly faster) way to get the current timestamp as an integer.
+ _.now = Date.now || function() {
+ return new Date().getTime();
+ };
+
+ // List of HTML entities for escaping.
+ var escapeMap = {
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"',
+ "'": ''',
+ '`': '`'
+ };
+ var unescapeMap = _.invert(escapeMap);
+
+ // Functions for escaping and unescaping strings to/from HTML interpolation.
+ var createEscaper = function(map) {
+ var escaper = function(match) {
+ return map[match];
+ };
+ // Regexes for identifying a key that needs to be escaped.
+ var source = '(?:' + _.keys(map).join('|') + ')';
+ var testRegexp = RegExp(source);
+ var replaceRegexp = RegExp(source, 'g');
+ return function(string) {
+ string = string == null ? '' : '' + string;
+ return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
+ };
+ };
+ _.escape = createEscaper(escapeMap);
+ _.unescape = createEscaper(unescapeMap);
+
+ // Traverses the children of `obj` along `path`. If a child is a function, it
+ // is invoked with its parent as context. Returns the value of the final
+ // child, or `fallback` if any child is undefined.
+ _.result = function(obj, path, fallback) {
+ if (!_.isArray(path)) path = [path];
+ var length = path.length;
+ if (!length) {
+ return _.isFunction(fallback) ? fallback.call(obj) : fallback;
+ }
+ for (var i = 0; i < length; i++) {
+ var prop = obj == null ? void 0 : obj[path[i]];
+ if (prop === void 0) {
+ prop = fallback;
+ i = length; // Ensure we don't continue iterating.
+ }
+ obj = _.isFunction(prop) ? prop.call(obj) : prop;
+ }
+ return obj;
+ };
+
+ // Generate a unique integer id (unique within the entire client session).
+ // Useful for temporary DOM ids.
+ var idCounter = 0;
+ _.uniqueId = function(prefix) {
+ var id = ++idCounter + '';
+ return prefix ? prefix + id : id;
+ };
+
+ // By default, Underscore uses ERB-style template delimiters, change the
+ // following template settings to use alternative delimiters.
+ _.templateSettings = {
+ evaluate: /<%([\s\S]+?)%>/g,
+ interpolate: /<%=([\s\S]+?)%>/g,
+ escape: /<%-([\s\S]+?)%>/g
+ };
+
+ // When customizing `templateSettings`, if you don't want to define an
+ // interpolation, evaluation or escaping regex, we need one that is
+ // guaranteed not to match.
+ var noMatch = /(.)^/;
+
+ // Certain characters need to be escaped so that they can be put into a
+ // string literal.
+ var escapes = {
+ "'": "'",
+ '\\': '\\',
+ '\r': 'r',
+ '\n': 'n',
+ '\u2028': 'u2028',
+ '\u2029': 'u2029'
+ };
+
+ var escapeRegExp = /\\|'|\r|\n|\u2028|\u2029/g;
+
+ var escapeChar = function(match) {
+ return '\\' + escapes[match];
+ };
+
+ // JavaScript micro-templating, similar to John Resig's implementation.
+ // Underscore templating handles arbitrary delimiters, preserves whitespace,
+ // and correctly escapes quotes within interpolated code.
+ // NB: `oldSettings` only exists for backwards compatibility.
+ _.template = function(text, settings, oldSettings) {
+ if (!settings && oldSettings) settings = oldSettings;
+ settings = _.defaults({}, settings, _.templateSettings);
+
+ // Combine delimiters into one regular expression via alternation.
+ var matcher = RegExp([
+ (settings.escape || noMatch).source,
+ (settings.interpolate || noMatch).source,
+ (settings.evaluate || noMatch).source
+ ].join('|') + '|$', 'g');
+
+ // Compile the template source, escaping string literals appropriately.
+ var index = 0;
+ var source = "__p+='";
+ text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
+ source += text.slice(index, offset).replace(escapeRegExp, escapeChar);
+ index = offset + match.length;
+
+ if (escape) {
+ source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
+ } else if (interpolate) {
+ source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
+ } else if (evaluate) {
+ source += "';\n" + evaluate + "\n__p+='";
+ }
+
+ // Adobe VMs need the match returned to produce the correct offset.
+ return match;
+ });
+ source += "';\n";
+
+ // If a variable is not specified, place data values in local scope.
+ if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
+
+ source = "var __t,__p='',__j=Array.prototype.join," +
+ "print=function(){__p+=__j.call(arguments,'');};\n" +
+ source + 'return __p;\n';
+
+ var render;
+ try {
+ render = new Function(settings.variable || 'obj', '_', source);
+ } catch (e) {
+ e.source = source;
+ throw e;
+ }
+
+ var template = function(data) {
+ return render.call(this, data, _);
+ };
+
+ // Provide the compiled source as a convenience for precompilation.
+ var argument = settings.variable || 'obj';
+ template.source = 'function(' + argument + '){\n' + source + '}';
+
+ return template;
+ };
+
+ // Add a "chain" function. Start chaining a wrapped Underscore object.
+ _.chain = function(obj) {
+ var instance = _(obj);
+ instance._chain = true;
+ return instance;
+ };
+
+ // OOP
+ // ---------------
+ // If Underscore is called as a function, it returns a wrapped object that
+ // can be used OO-style. This wrapper holds altered versions of all the
+ // underscore functions. Wrapped objects may be chained.
+
+ // Helper function to continue chaining intermediate results.
+ var chainResult = function(instance, obj) {
+ return instance._chain ? _(obj).chain() : obj;
+ };
+
+ // Add your own custom functions to the Underscore object.
+ _.mixin = function(obj) {
+ _.each(_.functions(obj), function(name) {
+ var func = _[name] = obj[name];
+ _.prototype[name] = function() {
+ var args = [this._wrapped];
+ push.apply(args, arguments);
+ return chainResult(this, func.apply(_, args));
+ };
+ });
+ return _;
+ };
+
+ // Add all of the Underscore functions to the wrapper object.
+ _.mixin(_);
+
+ // Add all mutator Array functions to the wrapper.
+ _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
+ var method = ArrayProto[name];
+ _.prototype[name] = function() {
+ var obj = this._wrapped;
+ method.apply(obj, arguments);
+ if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0];
+ return chainResult(this, obj);
+ };
+ });
+
+ // Add all accessor Array functions to the wrapper.
+ _.each(['concat', 'join', 'slice'], function(name) {
+ var method = ArrayProto[name];
+ _.prototype[name] = function() {
+ return chainResult(this, method.apply(this._wrapped, arguments));
+ };
+ });
+
+ // Extracts the result from a wrapped and chained object.
+ _.prototype.value = function() {
+ return this._wrapped;
+ };
+
+ // Provide unwrapping proxy for some methods used in engine operations
+ // such as arithmetic and JSON stringification.
+ _.prototype.valueOf = _.prototype.toJSON = _.prototype.value;
+
+ _.prototype.toString = function() {
+ return String(this._wrapped);
+ };
+
+ // AMD registration happens at the end for compatibility with AMD loaders
+ // that may not enforce next-turn semantics on modules. Even though general
+ // practice for AMD registration is to be anonymous, underscore registers
+ // as a named module because, like jQuery, it is a base library that is
+ // popular enough to be bundled in a third party lib, but not be part of
+ // an AMD load request. Those cases could generate an error when an
+ // anonymous define() is called outside of a loader request.
+ if (typeof define == 'function' && define.amd) {
+ define('underscore', [], function() {
+ return _;
+ });
+ }
+}());
+
+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+},{}],35:[function(require,module,exports){
+'use strict';
+
+module.exports = function() {
+ throw new Error(
+ 'ws does not work in the browser. Browser clients must use the native ' +
+ 'WebSocket object'
+ );
+};
+
+},{}],36:[function(require,module,exports){
+if (typeof(window) !== 'undefined' && typeof(window.requestAnimationFrame) !== 'function') {
+ window.requestAnimationFrame = (
+ window.webkitRequestAnimationFrame ||
+ window.mozRequestAnimationFrame ||
+ window.oRequestAnimationFrame ||
+ window.msRequestAnimationFrame ||
+ function(callback) { setTimeout(callback, 1000 / 60); }
+ );
+}
+
+Leap = require("../lib/index");
+
+},{"../lib/index":12}]},{},[36]);
diff --git a/leap-1.0.0.min.js b/leap-1.0.0.min.js
new file mode 100644
index 00000000..517b5988
--- /dev/null
+++ b/leap-1.0.0.min.js
@@ -0,0 +1,9 @@
+/*!
+ * LeapJS v1.0.0
+ * http://github.com/leapmotion/leapjs/
+ *
+ * Copyright 2013 LeapMotion, Inc. and other contributors
+ * Released under the Apache-2.0 license
+ * http://github.com/leapmotion/leapjs/blob/master/LICENSE
+ */
+!function o(a,s,u){function c(e,t){if(!s[e]){if(!a[e]){var n="function"==typeof require&&require;if(!t&&n)return n(e,!0);if(h)return h(e,!0);var r=new Error("Cannot find module '"+e+"'");throw r.code="MODULE_NOT_FOUND",r}var i=s[e]={exports:{}};a[e][0].call(i.exports,function(t){return c(a[e][1][t]||t)},i,i.exports,o,a,s,u)}return s[e].exports}for(var h="function"==typeof require&&require,t=0;t=this.size||t>=this._buf.length))return this._buf[(this.pos-t-1)%this.size]},r.prototype.push=function(t){return this._buf[this.pos%this.size]=t,this.pos++}},{}],3:[function(t,e,n){var r=t("../protocol").chooseProtocol,i=t("events").EventEmitter,o=t("underscore"),a=e.exports=function(t){this.opts=o.defaults(t||{},{host:"127.0.0.1",enableGestures:!1,scheme:this.getScheme(),port:this.getPort(),background:!1,optimizeHMD:!1,requestProtocolVersion:a.defaultProtocolVersion}),this.host=this.opts.host,this.port=this.opts.port,this.scheme=this.opts.scheme,this.protocolVersionVerified=!1,this.background=null,this.optimizeHMD=null,this.on("ready",function(){this.enableGestures(this.opts.enableGestures),this.setBackground(this.opts.background),this.setOptimizeHMD(this.opts.optimizeHMD),this.opts.optimizeHMD?console.log("Optimized for head mounted display usage."):console.log("Optimized for desktop usage.")})};a.defaultProtocolVersion=6,a.prototype.getUrl=function(){return this.scheme+"//"+this.host+":"+this.port+"/v"+this.opts.requestProtocolVersion+".json"},a.prototype.getScheme=function(){return"ws:"},a.prototype.getPort=function(){return 6437},a.prototype.setBackground=function(t){this.opts.background=t,this.protocol&&this.protocol.sendBackground&&this.background!==this.opts.background&&(this.background=this.opts.background,this.protocol.sendBackground(this,this.opts.background))},a.prototype.setOptimizeHMD=function(t){this.opts.optimizeHMD=t,this.protocol&&this.protocol.sendOptimizeHMD&&this.optimizeHMD!==this.opts.optimizeHMD&&(this.optimizeHMD=this.opts.optimizeHMD,this.protocol.sendOptimizeHMD(this,this.opts.optimizeHMD))},a.prototype.handleOpen=function(){this.connected||(this.connected=!0,this.emit("connect"))},a.prototype.enableGestures=function(t){this.gesturesEnabled=!!t,this.send(this.protocol.encode({enableGestures:this.gesturesEnabled}))},a.prototype.handleClose=function(t,e){this.connected&&(this.disconnect(),1001===t&&1Upgrade",{onclick:function(t){if("leapjs-decline-upgrade"!=t.target.id){var e=window.open(n,"_blank","height=800,width=1000,location=1,menubar=1,resizable=1,status=1,toolbar=1,scrollbars=1");window.focus&&e.focus()}return r.hide(),!0},onmousemove:function(t){t.target==document.getElementById("leapjs-decline-upgrade")?(document.getElementById("leapjs-decline-upgrade").style.color="#000",document.getElementById("leapjs-decline-upgrade").style.boxShadow="0px 0px 2px #5daa00",document.getElementById("leapjs-accept-upgrade").style.color="#444",document.getElementById("leapjs-accept-upgrade").style.boxShadow="none"):(document.getElementById("leapjs-accept-upgrade").style.color="#000",document.getElementById("leapjs-accept-upgrade").style.boxShadow="0px 0px 2px #5daa00",document.getElementById("leapjs-decline-upgrade").style.color="#444",document.getElementById("leapjs-decline-upgrade").style.boxShadow="none")},onmouseout:function(){document.getElementById("leapjs-decline-upgrade").style.color="#444",document.getElementById("leapjs-decline-upgrade").style.boxShadow="none",document.getElementById("leapjs-accept-upgrade").style.color="#444",document.getElementById("leapjs-accept-upgrade").style.boxShadow="none"}})).show()},i.hasWarnedBones=!1,i.warnBones=function(){this.hasWarnedBones||(this.hasWarnedBones=!0,console.warn("Your Leap Service is out of date"),void 0!==t&&t.versions&&t.versions.node||this.warnOutOfDate({reason:"bones"}))}}).call(this,t("_process"))},{_process:33}],8:[function(t,e,n){var r=t("./pointable"),i=t("./bone"),o=t("./dialog"),a=t("underscore"),s=e.exports=function(t){r.call(this,t),this.dipPosition=t.dipPosition,this.pipPosition=t.pipPosition,this.mcpPosition=t.mcpPosition,this.carpPosition=t.carpPosition,this.extended=t.extended,this.type=t.type,this.finger=!0,this.positions=[this.carpPosition,this.mcpPosition,this.pipPosition,this.dipPosition,this.tipPosition],t.bases?this.addBones(t):o.warnBones()};a.extend(s.prototype,r.prototype),s.prototype.addBones=function(t){this.metacarpal=new i(this,{type:0,width:this.width,prevJoint:this.carpPosition,nextJoint:this.mcpPosition,basis:t.bases[0]}),this.proximal=new i(this,{type:1,width:this.width,prevJoint:this.mcpPosition,nextJoint:this.pipPosition,basis:t.bases[1]}),this.medial=new i(this,{type:2,width:this.width,prevJoint:this.pipPosition,nextJoint:this.dipPosition,basis:t.bases[2]}),this.distal=new i(this,{type:3,width:this.width,prevJoint:this.dipPosition,nextJoint:t.btipPosition,basis:t.bases[3]}),this.bones=[this.metacarpal,this.proximal,this.medial,this.distal]},s.prototype.toString=function(){return"Finger [ id:"+this.id+" "+this.length+"mmx | width:"+this.width+"mm | direction:"+this.direction+" ]"},s.Invalid={valid:!1}},{"./bone":1,"./dialog":7,"./pointable":15,underscore:34}],9:[function(t,e,n){var u=t("./hand"),c=t("./pointable"),r=t("./gesture").createGesture,i=t("gl-matrix"),o=i.mat3,a=i.vec3,s=t("./interaction_box"),h=t("./finger"),l=t("underscore"),f=e.exports=function(t){if(this.valid=!0,this.id=t.id,this.timestamp=t.timestamp,this.hands=[],this.handsMap={},this.pointables=[],this.tools=[],this.fingers=[],t.interactionBox&&(this.interactionBox=new s(t.interactionBox)),this.gestures=[],this.pointablesMap={},this._translation=t.t,this._rotation=l.flatten(t.r),this._scaleFactor=t.s,this.data=t,this.type="frame",this.currentFrameRate=t.currentFrameRate,t.gestures)for(var e=0,n=t.gestures.length;e!=n;e++)this.gestures.push(r(t.gestures[e]));this.postprocessData(t)};f.prototype.postprocessData=function(t){for(var e=0,n=(t=t||this.data).hands.length;e!=n;e++){var r=new u(t.hands[e]);(r.frame=this).hands.push(r),this.handsMap[r.id]=r}t.pointables=l.sortBy(t.pointables,function(t){return t.id});for(var i=0,o=t.pointables.length;i!=o;i++){var a=t.pointables[i],s=a.dipPosition?new h(a):new c(a);(s.frame=this).addPointable(s)}},f.prototype.addPointable=function(t){if(this.pointables.push(t),((this.pointablesMap[t.id]=t).tool?this.tools:this.fingers).push(t),void 0!==t.handId&&this.handsMap.hasOwnProperty(t.handId)){var e=this.handsMap[t.handId];switch(e.pointables.push(t),(t.tool?e.tools:e.fingers).push(t),t.type){case 0:e.thumb=t;break;case 1:e.indexFinger=t;break;case 2:e.middleFinger=t;break;case 3:e.ringFinger=t;break;case 4:e.pinky=t}}},f.prototype.tool=function(t){var e=this.pointable(t);return e.tool?e:c.Invalid},f.prototype.pointable=function(t){return this.pointablesMap[t]||c.Invalid},f.prototype.finger=function(t){var e=this.pointable(t);return e.tool?c.Invalid:e},f.prototype.hand=function(t){return this.handsMap[t]||u.Invalid},f.prototype.rotationAngle=function(t,e){if(!this.valid||!t.valid)return 0;var n=this.rotationMatrix(t),r=.5*(n[0]+n[4]+n[8]-1),i=Math.acos(r);if(i=isNaN(i)?0:i,void 0!==e){var o=this.rotationAxis(t);i*=a.dot(o,a.normalize(a.create(),e))}return i},f.prototype.rotationAxis=function(t){return this.valid&&t.valid?a.normalize(a.create(),[this._rotation[7]-t._rotation[5],this._rotation[2]-t._rotation[6],this._rotation[3]-t._rotation[1]]):a.create()},f.prototype.rotationMatrix=function(t){if(!this.valid||!t.valid)return o.create();var e=o.transpose(o.create(),this._rotation);return o.multiply(o.create(),t._rotation,e)},f.prototype.scaleFactor=function(t){return this.valid&&t.valid?Math.exp(this._scaleFactor-t._scaleFactor):1},f.prototype.translation=function(t){return this.valid&&t.valid?a.subtract(a.create(),this._translation,t._translation):a.create()},f.prototype.toString=function(){var t="Frame [ id:"+this.id+" | timestamp:"+this.timestamp+" | Hand count:("+this.hands.length+") | Pointable count:("+this.pointables.length+")";return this.gestures&&(t+=" | Gesture count:("+this.gestures.length+")"),t+=" ]"},f.prototype.dump=function(){var t="";t+="Frame Info: ",t+=this.toString(),t+="