master f1ee634626bd cached
45 files
3.1 MB
804.6k tokens
438 symbols
1 requests
Download .txt
Showing preview only (3,218K chars total). Download the full file or copy to clipboard to get everything.
Repository: alexanderperrin/threejs-ballooning
Branch: master
Commit: f1ee634626bd
Files: 45
Total size: 3.1 MB

Directory structure:
gitextract_38dpwdar/

├── .gitignore
├── LICENSE
├── README.md
├── bundle.js
├── lib/
│   ├── Detector.js
│   └── THREE.MeshLine.js
├── package.json
├── public/
│   ├── index.html
│   └── static/
│       ├── app.css
│       └── meshes/
│           ├── balloon.json
│           ├── boat01.json
│           ├── church01.json
│           ├── model.json
│           ├── pier01.json
│           ├── plane.json
│           └── tree.json
├── resources/
│   ├── balloon.fbx
│   ├── blimp.lxo
│   ├── church.c4d
│   ├── dae/
│   │   ├── balloon.dae
│   │   ├── boat01.dae
│   │   ├── church01.dae
│   │   ├── pier01.dae
│   │   ├── plane.dae
│   │   └── tree.dae
│   ├── pier.blend
│   ├── plane.lxo
│   ├── tree.fbx
│   └── tree.lxo
├── src/
│   ├── FBXLoader.js
│   ├── ImprovedNoise.js
│   ├── classes/
│   │   ├── bird.js
│   │   ├── heightmap.js
│   │   ├── mathf.js
│   │   ├── player.js
│   │   ├── random.js
│   │   └── terrain-patch.js
│   ├── index.js
│   └── shaders/
│       ├── landscape_frag.glsl
│       ├── landscape_vert.glsl
│       ├── standard_frag.glsl
│       └── standard_vert.glsl
├── webpack.common.js
├── webpack.dev.js
└── webpack.prod.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
dist


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2019 Alexander Perrin

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.


================================================
FILE: README.md
================================================
# Ballooning with Three.js
This was developed as a study into procedural terrains, buffer geometry optimisation and shadow mappers with Three.js and WebGL.
I had some grand plans for the application, but they were never realised so it's probably more useful to just release it as it is for others to take a look!
There are plenty of issues with it and it's pretty rough having been developed over 2 years ago now, but if it's some use to anyone that's great.

Example at https://alexanderperrin.com.au/triangles/ballooning.

Use the arrow keys or the left and right sides of the screen on touch devices to move the balloon.

## Features
- Procedurally generated infinite terrain & tree placement
- Happy flapping birds
- Shoreline boathouse placement
- Pleasant mountain ballooning
- Statically batched tree rendering
- Runs on desktop and mobile

## Development
Feel free to have a dig around in the code and change things. I've setup a [webpack](https://webpack.js.org/) development environment with hot module replacement that you can use to quickly iterate the application.
- Ensure that you have node and npm installed on your machine. You can follow the official instructions at https://www.npmjs.com/get-npm
- Clone the repository into your desired project folder
- Run `npm install` from within the project folder to install dependencies
- Ensure webpack-cli is either available globally or installed locally (`npm install --save-dev webpack-cli`)
- Run `npm start`. This will spin up a webpack development server running at http://localhost:8080
- Change the code you like and see what happens!

## Building
- Run `npm run build` to build a production ready version of the web app.
- Contents will be processed into /dist, which you can upload to your web server.

## License
MIT

## Warranty
None whatsoever.


================================================
FILE: bundle.js
================================================
/******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};

/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {

/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId])
/******/ 			return installedModules[moduleId].exports;

/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			exports: {},
/******/ 			id: moduleId,
/******/ 			loaded: false
/******/ 		};

/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

/******/ 		// Flag the module as loaded
/******/ 		module.loaded = true;

/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}


/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;

/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;

/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";

/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {

	__webpack_require__(1);
	(function webpackMissingModule() { throw new Error("Cannot find module \"run\""); }());
	(function webpackMissingModule() { throw new Error("Cannot find module \"dev\""); }());


/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {

	/* WEBPACK VAR INJECTION */(function(THREE) {'use strict';

	var _Detector = __webpack_require__(3);

	var _Detector2 = _interopRequireDefault(_Detector);

	var _player = __webpack_require__(5);

	var _player2 = _interopRequireDefault(_player);

	var _terrainPatch = __webpack_require__(7);

	var _terrainPatch2 = _interopRequireDefault(_terrainPatch);

	var _heightmap = __webpack_require__(8);

	var _heightmap2 = _interopRequireDefault(_heightmap);

	var _bird = __webpack_require__(10);

	var _bird2 = _interopRequireDefault(_bird);

	var _mathf = __webpack_require__(6);

	var _mathf2 = _interopRequireDefault(_mathf);

	var _jquery = __webpack_require__(11);

	var _jquery2 = _interopRequireDefault(_jquery);

	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

	function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

	__webpack_require__(12);
	__webpack_require__(13);
	__webpack_require__(14);

	(function () {

	  // Rendering
	  var SHADOW_MAP_WIDTH = 1024;
	  var SHADOW_MAP_HEIGHT = 1024;
	  var SHADOW_CAM_SIZE = 512;
	  var SHADOW_CAM_STEP = 16;

	  // File
	  var IMAGE_PATH = 'static/images/';
	  var MESH_PATH = 'static/meshes/';

	  var meshFiles = ['tree.json', 'balloon.json', 'boat01.json'];
	  var imageFiles = [];

	  var objectLoader = new THREE.ObjectLoader();

	  // Data storage
	  var meshes = {};
	  var textures = {};

	  // Birds
	  var BIRD_COUNT = 40;
	  var BIRD_SPAWN_DISTANCE = -200;
	  var BIRD_RESPAWN_DISTANCE = 512;
	  var BIRD_MAX_RESPAWN_TIME = 10;
	  var birdsVisible = false;
	  var birds = [];

	  // Lights, camera and helpers
	  var renderer = void 0,
	      scene = void 0,
	      cameraControls = void 0,
	      sun = void 0,
	      // Directional light
	  cameraAnchor = void 0,
	      // Camera base rotator
	  gameCamera = void 0,
	      // Game view camera
	  renderCamera = void 0,
	      // Currently rendering camera
	  editorCamera = void 0,
	      // Utility view camera
	  lightAnchor = void 0,
	      // Used for containing sun object and target in more managable unit
	  lightPosIndex = void 0,
	      // Used for tracking movment of light
	  lightShadowOffset = void 0,
	      // Used for offsetting shadow camera matrix
	  clock = void 0,
	      _this = void 0,
	      loadingMessage = void 0,
	      player = void 0;

	  // Debug rays
	  var rays = [];

	  // Terrain
	  var TERRAIN_PATCH_WIDTH = 64;
	  var TERRAIN_PATCH_HEIGHT = 64;
	  var TERRAIN_PATCHES_X = 5;
	  var TERRAIN_PATCHES_Z = 12;
	  var TERRAIN_OFFSET_X = -(TERRAIN_PATCH_WIDTH * TERRAIN_PATCHES_X) * 0.5;
	  var TERRAIN_OFFSET_Z = -128;
	  var TREES_PER_TERRAIN = 50;
	  var WATER_HEIGHT = -15.0;
	  var heightmap = new _heightmap2.default({
	    noiseOffset: {
	      x: -TERRAIN_OFFSET_X,
	      y: -TERRAIN_OFFSET_Z
	    },
	    height: 50,
	    scale: 100
	  });
	  var terrainPatches = [];
	  var waterPlane = void 0;
	  // Used for tracking terrain regeneration requirement
	  var terrainGridIndex = {
	    x: 0,
	    y: 0
	  };

	  // Shaders
	  var standardShader = void 0;

	  // Input
	  var input = {
	    x: 0,
	    y: 0
	  };

	  /**
	   * @summary Window focus detection.
	   * @description Stops the animation clock when window is inactive.
	   */
	  (function () {
	    var hidden = "hidden";

	    // Standards:
	    if (hidden in document) document.addEventListener("visibilitychange", onchange);else if ((hidden = "mozHidden") in document) document.addEventListener("mozvisibilitychange", onchange);else if ((hidden = "webkitHidden") in document) document.addEventListener("webkitvisibilitychange", onchange);else if ((hidden = "msHidden") in document) document.addEventListener("msvisibilitychange", onchange);
	    // IE 9 and lower:
	    else if ("onfocusin" in document) document.onfocusin = document.onfocusout = onchange;
	      // All others:
	      else window.onpageshow = window.onpagehide = window.onfocus = window.onblur = onchange;

	    function onchange(evt) {
	      if (document[hidden]) {
	        if (clock !== undefined) {
	          clock.stop();
	        }
	      } else {
	        if (clock !== undefined) {
	          clock.start();
	        }
	      }
	      var v = "visible",
	          h = "hidden",
	          evtMap = {
	        focus: v,
	        focusin: v,
	        pageshow: v,
	        blur: h,
	        focusout: h,
	        pagehide: h
	      };

	      evt = evt || window.event;
	      if (evt.type in evtMap) document.body.className = evtMap[evt.type];else document.body.className = this[hidden] ? "hidden" : "visible";
	    }

	    // set the initial state (but only if browser supports the Page Visibility API)
	    if (document[hidden] !== undefined) onchange({
	      type: document[hidden] ? "blur" : "focus"
	    });
	  })();

	  /**
	   * Gets the device pixel ratio.
	   * @return float the ratio
	   */
	  var getDevicePixelRatio = function getDevicePixelRatio() {
	    return window.devicePixelRatio || 1;
	  };

	  /**
	   * Adds an event to the object
	   * @param {object}   object   object to add event to
	   * @param {string}   type     event type
	   * @param {Function} callback event handler
	   */
	  var addEvent = function addEvent(object, type, callback) {
	    if (object === null || typeof object === 'undefined') return;
	    if (object.addEventListener) {
	      object.addEventListener(type, callback, false);
	    } else if (object.attachEvent) {
	      object.attachEvent('on' + type, callback);
	    } else {
	      object['on' + type] = callback;
	    }
	  };

	  var updateRenderCamera = function updateRenderCamera() {
	    var width = window.innerWidth;
	    var height = window.innerHeight;
	    renderCamera.aspect = width / height;
	    renderCamera.updateProjectionMatrix();
	  };

	  /**
	   * Resize function
	   * @param  double width
	   * @param  double height
	   */
	  var resize = function resize() {
	    var width = window.innerWidth;
	    var height = window.innerHeight;
	    var devicePixelRatio = getDevicePixelRatio();
	    renderer.setSize(width * devicePixelRatio, height * devicePixelRatio);

	    // Update canvas
	    var canvas = renderer.domElement;
	    canvas.width = width * devicePixelRatio;
	    canvas.height = height * devicePixelRatio;
	    canvas.style.width = width + 'px';
	    canvas.style.height = height + 'px';

	    updateRenderCamera();
	  };

	  /**
	   * Shifts the terrain by given units
	   * @param  {[type]} x terrain units to shift in x
	   * @param  {[type]} y terrain units to shift in y
	   */
	  var shiftTerrain = function shiftTerrain(x, y) {
	    // Shift forward
	    for (var i = 0; i < y; ++i) {
	      for (var j = 0; j < TERRAIN_PATCHES_X; ++j) {
	        var tp = terrainPatches[terrainGridIndex.y % TERRAIN_PATCHES_Z][j];
	        tp.position.z += TERRAIN_PATCH_HEIGHT * TERRAIN_PATCHES_Z;
	        tp.rebuild(scene);
	      }
	    }
	    // Shift right
	    for (var _i = 0; _i < x; ++_i) {
	      for (var _j = 0; _j < TERRAIN_PATCHES_Z; ++_j) {
	        var _tp = terrainPatches[_j][terrainGridIndex.x % TERRAIN_PATCHES_X];
	        _tp.position.x += TERRAIN_PATCH_WIDTH * TERRAIN_PATCHES_X;
	        _tp.rebuild(scene);
	      }
	    }
	    terrainGridIndex.x += x;
	    terrainGridIndex.y += y;
	    waterPlane.position.z += TERRAIN_PATCH_HEIGHT * y;
	  };

	  /**
	   * Terrain grid index to world position transformation
	   * @param  {int} x terrain index x
	   * @param  {int} y terrain index y
	   * @return {vec3}   world position
	   */
	  var terrainGridToWorld = function terrainGridToWorld(x, y) {
	    return {
	      x: x * TERRAIN_PATCH_WIDTH,
	      y: 0,
	      z: y * TERRAIN_PATCH_HEIGHT
	    };
	  };

	  /**
	   * World position to terrain grid index transformation
	   * @param  {vec3} pos world position
	   * @return {vec2}     terrain index
	   */
	  var worldToTerrainGrid = function worldToTerrainGrid(pos) {
	    return {
	      x: Math.round(pos.x / TERRAIN_PATCH_WIDTH),
	      y: Math.round(pos.z / TERRAIN_PATCH_HEIGHT)
	    };
	  };

	  /// Gets a random position on the entire landscape
	  var getRandomPositionOnLandscape = function getRandomPositionOnLandscape() {
	    return {
	      x: getRandomArbitrary(0, TERRAIN_PATCHES_X * TERRAIN_PATCH_WIDTH) + TERRAIN_OFFSET_X,
	      y: 0,
	      z: getRandomArbitrary(0, TERRAIN_PATCHES_Z * TERRAIN_PATCH_HEIGHT) + TERRAIN_OFFSET_Z
	    };
	  };

	  var getLandscapeMidpoint = function getLandscapeMidpoint() {
	    return {
	      x: TERRAIN_PATCHES_X * TERRAIN_PATCH_WIDTH / 2 + TERRAIN_OFFSET_X
	    };
	  };

	  var getLandscapeWidth = function getLandscapeWidth() {
	    return TERRAIN_PATCHES_X * TERRAIN_PATCH_WIDTH;
	  };

	  var getLandscapeDepth = function getLandscapeDepth() {
	    return TERRAIN_PATCHES_Z * TERRAIN_PATCH_HEIGHT;
	  };

	  /// Redraw the view
	  var render = function render() {
	    renderer.render(scene, renderCamera);
	  };

	  /**
	   * Parses a shader from the THREE shader chunk library
	   * @param  {[type]} shaderStr [description]
	   * @return {[type]}           [description]
	   */
	  var getShader = function getShader(shaderStr) {
	    return shaderStr.replace(/#include\s+(\S+)/gi, function (match, p1) {
	      p1 = p1.substr(1, p1.length - 2);
	      var chunk = THREE.ShaderChunk[p1];
	      return chunk ? chunk : "";
	    });
	  };

	  var loadMeshes = function loadMeshes() {

	    loadingMessage.html('geometry');

	    return new Promise(function (resolve) {
	      var numFiles = meshFiles.length;
	      if (numFiles === 0) {
	        resolve();
	      }
	      meshFiles.forEach(function (v) {
	        objectLoader.load(MESH_PATH + v, function (obj) {
	          var name = obj.name;
	          meshes[name] = obj;
	          numFiles--;
	          if (numFiles === 0) {
	            resolve();
	          }
	        });
	      });
	    });
	  };

	  /**
	   * Loads the textures specified in the textures URL array.
	   */
	  var loadTextures = function loadTextures() {

	    loadingMessage.html('images');

	    return new Promise(function (resolve) {
	      var numFiles = imageFiles.length;
	      if (numFiles === 0) {
	        resolve();
	      }
	      imageFiles.forEach(function (v) {
	        var texture = new THREE.Texture();
	        var image = new Image();
	        image.onload = function () {
	          texture.image = image;
	          texture.needsUpdate = true;
	          texture.name = v;
	          textures[v] = texture;
	          numFiles--;
	          if (numFiles === 0) {
	            resolve();
	          }
	        };
	        image.src = IMAGE_PATH + v;
	      });
	    });
	  };

	  /**
	   * Initialises the THREE WebGL renderer and appends to DOM.
	   * @return {[type]} [description]
	   */
	  var initRenderer = function initRenderer() {
	    var _ref;

	    renderer = new THREE.WebGLRenderer({
	      antialias: false
	    });
	    renderer.setClearColor('white', 1);
	    renderer.shadowMap.enabled = true;
	    renderer.shadowMap.autoUpdate = false;
	    renderer.shadowMap.needsUpdate = true;
	    renderer.shadowMap.type = THREE.PCFSoftShadowMap;
	    document.getElementById('canvas-container').appendChild(renderer.domElement);

	    var mat = new THREE.ShaderMaterial((_ref = {
	      lights: true,
	      uniforms: THREE.ShaderLib.phong.uniforms
	    }, _defineProperty(_ref, 'uniforms', THREE.UniformsUtils.merge([THREE.ShaderLib.phong.uniforms, {
	      xFogColor: {
	        type: 'c',
	        value: new THREE.Color(0xFFFFFF)
	      }
	    }])), _defineProperty(_ref, 'shading', THREE.FlatShading), _defineProperty(_ref, 'fog', true), _defineProperty(_ref, 'vertexShader', standardShader.vertexShader), _defineProperty(_ref, 'fragmentShader', standardShader.fragmentShader), _defineProperty(_ref, 'vertexColors', THREE.VertexColors), _ref));

	    // Assign materials
	    Object.keys(meshes).forEach(function (v) {
	      var m = meshes[v];
	      m.material = mat;
	    });
	  };

	  /**
	   * Initialises the base scene objects and helpers.
	   */
	  var initScene = function initScene() {

	    console.log('initialising scene');

	    scene = new THREE.Scene();

	    lightShadowOffset = new THREE.Object3D();

	    // Used for storing sun camera and target
	    lightAnchor = new THREE.Object3D();
	    scene.add(lightAnchor);
	    lightAnchor.add(lightShadowOffset);

	    // Used for transforming light and shadow cameras
	    var lightMatrix = new THREE.Matrix4();
	    var rotation = new THREE.Quaternion();
	    rotation.setFromEuler(new THREE.Euler(THREE.Math.degToRad(35), THREE.Math.degToRad(-135), 0, 'YXZ'));
	    lightMatrix.compose(new THREE.Vector3(0, 128, 0), rotation, new THREE.Vector3(1, 1, 1));

	    // Lights
	    sun = new THREE.DirectionalLight(0xffffff, 1.5);
	    sun.position.set(0, 0, 0);
	    sun.target.position.set(0, 0, 128);
	    scene.add(new THREE.AmbientLight(0xeeeeFF, 0.5));
	    scene.fog = new THREE.Fog(0xdaf0fb, 350, 950);
	    var hemiLight = new THREE.HemisphereLight(0xFFFFFF, 0xFFED00, 0.25);
	    hemiLight.position.set(0, 500, 0);
	    scene.add(hemiLight);

	    // Shadows
	    sun.castShadow = true;
	    sun.shadow.mapSize.width = SHADOW_MAP_WIDTH;
	    sun.shadow.mapSize.height = SHADOW_MAP_HEIGHT;
	    var sCamSize = SHADOW_CAM_SIZE;
	    sun.shadow.camera.right = -sCamSize / 2;
	    sun.shadow.camera.left = sCamSize / 2;
	    sun.shadow.camera.top = sCamSize / 2;
	    sun.shadow.camera.bottom = -sCamSize / 2;
	    sun.shadow.camera.far = 512;
	    sun.shadow.camera.near = -512;
	    sun.shadow.bias = -0.0025;

	    // Shadow camera position texel snapping compensator
	    lightShadowOffset.add(sun);
	    lightShadowOffset.add(sun.target);
	    lightAnchor.applyMatrix(lightMatrix);
	    lightPosIndex = lightAnchor.position.z;
	    lightAnchor.position.z += 400;

	    window.flight.scene = scene;
	  };

	  var initShaders = function initShaders() {
	    standardShader = {
	      vertexShader: getShader(__webpack_require__(15)),
	      fragmentShader: getShader(__webpack_require__(16))
	    };
	  };

	  var initTerrain = function initTerrain() {

	    // Shader uniforms
	    var uniforms = {
	      cliffColor: {
	        type: 'c',
	        value: new THREE.Color(0x555555)
	      },
	      grassColor: {
	        type: 'c',
	        value: new THREE.Color(0x475905)
	      },
	      sandColor: {
	        type: 'c',
	        value: new THREE.Color(0x886633)
	      },
	      steps: {
	        type: 'f',
	        value: 1.0
	      },
	      waterHeight: {
	        type: 'f',
	        value: WATER_HEIGHT + 0.5
	      },
	      xFogColor: {
	        type: 'c',
	        value: new THREE.Color(0xFFFFFF)
	      },
	      threshold: {
	        type: 'f',
	        value: 0.25
	      }
	    };

	    // Materials
	    var landscapeMaterial = new THREE.ShaderMaterial({
	      lights: true,
	      uniforms: THREE.UniformsUtils.merge([THREE.ShaderLib.phong.uniforms, uniforms]),
	      shading: THREE.FlatShading,
	      fog: true,
	      vertexShader: getShader(__webpack_require__(17)),
	      fragmentShader: getShader(__webpack_require__(18))
	    });

	    // Terrain patches
	    for (var i = 0; i < TERRAIN_PATCHES_Z; ++i) {
	      terrainPatches[i] = [];
	      for (var j = 0; j < TERRAIN_PATCHES_X; ++j) {
	        var tp = new _terrainPatch2.default({
	          width: TERRAIN_PATCH_WIDTH,
	          height: TERRAIN_PATCH_HEIGHT,
	          position: new THREE.Vector3(TERRAIN_PATCH_WIDTH * j + TERRAIN_OFFSET_X, 0, TERRAIN_PATCH_HEIGHT * i + TERRAIN_OFFSET_Z),
	          heightmap: heightmap,
	          material: landscapeMaterial
	        });
	        tp.receiveShadow = true;
	        tp.castShadow = true;
	        tp.addScatterObject({
	          mesh: meshes['tree'],
	          count: TREES_PER_TERRAIN,
	          minSize: {
	            x: 0.25,
	            y: 0.4,
	            z: 0.25
	          },
	          maxSize: {
	            x: 0.5,
	            y: 0.5,
	            z: 0.5
	          },
	          lockXZScale: true,
	          minHeight: -10,
	          maxHeight: 100,
	          maxSlope: 0.6
	        });
	        terrainPatches[i][j] = tp;
	        scene.add(terrainPatches[i][j]);
	      }
	    }

	    // River plane
	    var riverMaterial = new THREE.MeshPhongMaterial({
	      color: 0x2f5d63
	    });
	    var riverMesh = new THREE.PlaneGeometry(TERRAIN_PATCHES_X * TERRAIN_PATCH_WIDTH, TERRAIN_PATCHES_Z * TERRAIN_PATCH_HEIGHT * 2, 1, 1);
	    waterPlane = new THREE.Mesh(riverMesh, riverMaterial);
	    waterPlane.position.y = -15;
	    waterPlane.rotation.x = -Math.PI / 2.0;
	    waterPlane.position.z = -TERRAIN_OFFSET_X;
	    scene.add(waterPlane);
	  };

	  var initPlayer = function initPlayer() {
	    var obj = meshes['balloon'];
	    player = new _player2.default();
	    player.position.set(0, 100, 0);
	    player.add(obj);
	    scene.add(player);
	  };

	  var initCameras = function initCameras() {
	    // Game camera
	    gameCamera = new THREE.PerspectiveCamera(15.0, window.innerWidth / window.innerHeight, 100, 10000);
	    cameraAnchor = new THREE.Object3D();
	    cameraAnchor.position.set(TERRAIN_PATCHES_X * TERRAIN_PATCH_WIDTH / 2, 0, TERRAIN_PATCHES_Z * TERRAIN_PATCH_HEIGHT / 2);
	    cameraAnchor.updateMatrix();
	    cameraAnchor.add(gameCamera);
	    gameCamera.position.set(100, 250, -300);
	    gameCamera.lookAt(new THREE.Vector3(0, 100, 0));
	    scene.add(cameraAnchor);

	    // Editor camera
	    editorCamera = gameCamera.clone();
	    cameraControls = new THREE.OrbitControls(editorCamera, renderer.domElement);
	    cameraControls.target.set(0, 0, TERRAIN_PATCHES_Z * TERRAIN_PATCH_HEIGHT / 2);
	    editorCamera.position.set(-250, 350, -250);
	    cameraControls.update();

	    renderCamera = gameCamera;
	  };

	  var respawnBirds = function respawnBirds() {
	    var spawnWidth = getLandscapeWidth() * 0.25;
	    var bunchFactor = _mathf2.default.randRange(0.2, 1);
	    var flockPosition = new THREE.Vector3(_mathf2.default.randRange(-spawnWidth, spawnWidth), _mathf2.default.randRange(64, 128), player.position.z + BIRD_SPAWN_DISTANCE);
	    var birdPos = void 0;
	    for (var i = 0; i < BIRD_COUNT; ++i) {
	      birdPos = flockPosition.clone().add(new THREE.Vector3(_mathf2.default.randRange(-32, 32) * bunchFactor, _mathf2.default.randRange(-16, 16) * bunchFactor, _mathf2.default.randRange(-48, 48) * bunchFactor));
	      birds[i].position.copy(birdPos);
	    }
	    // Loop this function every so often
	    setTimeout(respawnBirds, 30000 + _mathf2.default.randRange(0, 20000));
	  };

	  var initBirds = function initBirds() {
	    for (var i = 0; i < BIRD_COUNT; ++i) {
	      var bird = new _bird2.default();
	      scene.add(bird);
	      birds.push(bird);
	    }
	    respawnBirds();
	  };

	  var init = function init() {

	    window.flight = {};
	    clock = new THREE.Clock(true);
	    window.flight.clock = clock;
	    window.flight.input = 0;
	    window.flight.debug = {};
	    window.flight.debug.drawRay = drawRay;

	    initShaders();
	    initRenderer();
	    initScene();
	    initPlayer();
	    initCameras();
	    initBirds();
	    initTerrain();

	    var a = new THREE.AxisHelper(20);
	    a.position.set(0, 0, 0);
	    scene.add(a);

	    // Events
	    addEvent(window, 'resize', resize);

	    addEvent(window, 'keydown', function (e) {
	      // Inputs
	      if (e.keyCode === 39) {
	        input.x = 1.0;
	      } else if (e.keyCode === 37) {
	        input.x = -1.0;
	      } else if (e.keyCode === 32) {
	        // Camera switching
	        if (renderCamera === editorCamera) {
	          renderCamera = gameCamera;
	        } else {
	          renderCamera = editorCamera;
	        }
	      }
	    });

	    window.addEventListener('touchmove', function (e) {
	      console.log(e);
	      // Prevent scroll behaviour
	      if (!event.target.classList.contains('scrollable')) {
	        event.preventDefault();
	      }
	    });

	    window.addEventListener('mousewheel', function (e) {
	      // Disable mouse wheel scrolling
	      e.preventDefault();
	    });

	    addEvent(window, 'touchstart', function (e) {
	      var mp = window.innerWidth / 2;
	      var p = e.touches[0].clientX;
	      if (p - mp < 0) {
	        // Go left
	        input.x = -1;
	      } else if (p - mp > 0) {
	        // Go right
	        input.x = 1;
	      }
	    });

	    window.addEventListener('touchend', function () {
	      input.x = 0;
	    });

	    addEvent(window, 'keyup', function (e) {
	      // Inputs
	      if (e.keyCode === 39) {
	        input.x = 0;
	      } else if (e.keyCode === 37) {
	        input.x = 0;
	      }
	    });

	    resize();

	    (0, _jquery2.default)('#loader').fadeOut('slow');

	    console.log('initialisation complete');
	  };

	  var drawRay = function drawRay(position, direction, color) {
	    var material = new THREE.LineBasicMaterial({
	      color: color
	    });

	    var geometry = new THREE.Geometry();
	    geometry.vertices.push(new THREE.Vector3(), direction.clone());

	    var line = new THREE.Line(geometry, material);
	    line.position.copy(position);
	    rays.push(line);
	    scene.add(line);
	  };

	  var idle = function idle() {

	    console.log('idle');

	    console.log('dt');
	    console.log(clock);

	    var dt = clock.getDelta();
	    console.log('dt 2');
	    return;
	    window.flight.deltaTime = dt;
	    window.flight.input = input;
	    window.flight.time = clock.getElapsedTime();

	    // Update shadow camera position
	    lightAnchor.position.z = player.position.z + 256;
	    if (Math.round(lightAnchor.position.z) - lightPosIndex > SHADOW_CAM_STEP) {
	      lightPosIndex = Math.round(lightAnchor.position.z);
	      lightAnchor.updateMatrixWorld();
	      // Snap the shadow camera matrix to the nearest texel to prevent shadow swimming
	      var lPos = new THREE.Vector3(0, 0, 0); // Real shadow cam position
	      var lPos2 = new THREE.Vector3(0, 0, 0); // Texel snapped cam position
	      lightAnchor.worldToLocal(lPos);
	      lPos2.set(lPos.x, lPos.y, lPos.z);
	      var tSize = SHADOW_CAM_SIZE / SHADOW_MAP_WIDTH;
	      lPos2.x = Math.round(lPos2.x / tSize) * tSize;
	      lPos2.y = Math.round(lPos2.y / tSize) * tSize;
	      lightShadowOffset.position.set(lPos.x - lPos2.x, lPos.y - lPos2.y, 0);
	      renderer.shadowMap.needsUpdate = true;
	    }

	    console.log('shadow camera moved');

	    if (player) {
	      player.update();
	      player.gridPos = worldToTerrainGrid(player.position);
	      // Check for terrain shift
	      while (player.gridPos.y > terrainGridIndex.y) {
	        shiftTerrain(0, 1);
	      }
	      cameraAnchor.position.set(player.position.x, 0, player.position.z);
	      if (cameraAnchor.position.x > 60) {
	        cameraAnchor.position.x = 60;
	      } else if (cameraAnchor.position.x < -60) {
	        cameraAnchor.position.x = -60;
	      }
	    }

	    console.log('player moved');

	    // Animate birds
	    var avBirdPos = new THREE.Vector3();
	    birds.forEach(function (b) {
	      avBirdPos.add(b.position);
	    });
	    avBirdPos.divideScalar(birds.length);
	    // Basic flocking
	    birds.forEach(function (b) {
	      b.update(dt, avBirdPos, player);
	    });

	    requestAnimationFrame(idle);
	    console.log('rendering');
	    render();

	    // Remove the rays
	    rays.forEach(function (r) {
	      scene.remove(r);
	    });
	  };

	  (0, _jquery2.default)(document).ready(function () {

	    loadingMessage = (0, _jquery2.default)('#loading-message');

	    if (!_Detector2.default.webgl || !_Detector2.default.canvas) {
	      (0, _jquery2.default)('.label').html("My apologies, your device doesn't support WebGL, which is what this thing relies on! Try updating it, or try another one.");
	    } else {
	      loadingMessage.html('code');
	      loadTextures().then(loadMeshes).then(init).then(idle);
	    }
	  });

	  _this = this;
	})();
	/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2)))

/***/ },
/* 2 */
/***/ function(module, exports, __webpack_require__) {

	var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;// File:src/Three.js

	/**
	 * @author mrdoob / http://mrdoob.com/
	 */

	var THREE = { REVISION: '78' };

	//

	if ( true ) {

		!(__WEBPACK_AMD_DEFINE_FACTORY__ = (THREE), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, __webpack_require__, exports, module)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));

	} else if ( 'undefined' !== typeof exports && 'undefined' !== typeof module ) {

		module.exports = THREE;

	}

	// Polyfills

	if ( Number.EPSILON === undefined ) {

		Number.EPSILON = Math.pow( 2, - 52 );

	}

	//

	if ( Math.sign === undefined ) {

		// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign

		Math.sign = function ( x ) {

			return ( x < 0 ) ? - 1 : ( x > 0 ) ? 1 : + x;

		};

	}

	if ( Function.prototype.name === undefined ) {

		// Missing in IE9-11.
		// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name

		Object.defineProperty( Function.prototype, 'name', {

			get: function () {

				return this.toString().match( /^\s*function\s*(\S*)\s*\(/ )[ 1 ];

			}

		} );

	}

	if ( Object.assign === undefined ) {

		// Missing in IE.
		// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

		( function () {

			Object.assign = function ( target ) {

				'use strict';

				if ( target === undefined || target === null ) {

					throw new TypeError( 'Cannot convert undefined or null to object' );

				}

				var output = Object( target );

				for ( var index = 1; index < arguments.length; index ++ ) {

					var source = arguments[ index ];

					if ( source !== undefined && source !== null ) {

						for ( var nextKey in source ) {

							if ( Object.prototype.hasOwnProperty.call( source, nextKey ) ) {

								output[ nextKey ] = source[ nextKey ];

							}

						}

					}

				}

				return output;

			};

		} )();

	}

	//

	Object.assign( THREE, {

		// https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent.button

		MOUSE: { LEFT: 0, MIDDLE: 1, RIGHT: 2 },

		// GL STATE CONSTANTS

		CullFaceNone: 0,
		CullFaceBack: 1,
		CullFaceFront: 2,
		CullFaceFrontBack: 3,

		FrontFaceDirectionCW: 0,
		FrontFaceDirectionCCW: 1,

		// SHADOWING TYPES

		BasicShadowMap: 0,
		PCFShadowMap: 1,
		PCFSoftShadowMap: 2,

		// MATERIAL CONSTANTS

		// side

		FrontSide: 0,
		BackSide: 1,
		DoubleSide: 2,

		// shading

		FlatShading: 1,
		SmoothShading: 2,

		// colors

		NoColors: 0,
		FaceColors: 1,
		VertexColors: 2,

		// blending modes

		NoBlending: 0,
		NormalBlending: 1,
		AdditiveBlending: 2,
		SubtractiveBlending: 3,
		MultiplyBlending: 4,
		CustomBlending: 5,

		// custom blending equations
		// (numbers start from 100 not to clash with other
		// mappings to OpenGL constants defined in Texture.js)

		AddEquation: 100,
		SubtractEquation: 101,
		ReverseSubtractEquation: 102,
		MinEquation: 103,
		MaxEquation: 104,

		// custom blending destination factors

		ZeroFactor: 200,
		OneFactor: 201,
		SrcColorFactor: 202,
		OneMinusSrcColorFactor: 203,
		SrcAlphaFactor: 204,
		OneMinusSrcAlphaFactor: 205,
		DstAlphaFactor: 206,
		OneMinusDstAlphaFactor: 207,

		// custom blending source factors

		//ZeroFactor: 200,
		//OneFactor: 201,
		//SrcAlphaFactor: 204,
		//OneMinusSrcAlphaFactor: 205,
		//DstAlphaFactor: 206,
		//OneMinusDstAlphaFactor: 207,
		DstColorFactor: 208,
		OneMinusDstColorFactor: 209,
		SrcAlphaSaturateFactor: 210,

		// depth modes

		NeverDepth: 0,
		AlwaysDepth: 1,
		LessDepth: 2,
		LessEqualDepth: 3,
		EqualDepth: 4,
		GreaterEqualDepth: 5,
		GreaterDepth: 6,
		NotEqualDepth: 7,


		// TEXTURE CONSTANTS

		MultiplyOperation: 0,
		MixOperation: 1,
		AddOperation: 2,

		// Tone Mapping modes

		NoToneMapping: 0, // do not do any tone mapping, not even exposure (required for special purpose passes.)
		LinearToneMapping: 1, // only apply exposure.
		ReinhardToneMapping: 2,
		Uncharted2ToneMapping: 3, // John Hable
		CineonToneMapping: 4, // optimized filmic operator by Jim Hejl and Richard Burgess-Dawson

		// Mapping modes

		UVMapping: 300,

		CubeReflectionMapping: 301,
		CubeRefractionMapping: 302,

		EquirectangularReflectionMapping: 303,
		EquirectangularRefractionMapping: 304,

		SphericalReflectionMapping: 305,
		CubeUVReflectionMapping: 306,
		CubeUVRefractionMapping: 307,

		// Wrapping modes

		RepeatWrapping: 1000,
		ClampToEdgeWrapping: 1001,
		MirroredRepeatWrapping: 1002,

		// Filters

		NearestFilter: 1003,
		NearestMipMapNearestFilter: 1004,
		NearestMipMapLinearFilter: 1005,
		LinearFilter: 1006,
		LinearMipMapNearestFilter: 1007,
		LinearMipMapLinearFilter: 1008,

		// Data types

		UnsignedByteType: 1009,
		ByteType: 1010,
		ShortType: 1011,
		UnsignedShortType: 1012,
		IntType: 1013,
		UnsignedIntType: 1014,
		FloatType: 1015,
		HalfFloatType: 1025,

		// Pixel types

		//UnsignedByteType: 1009,
		UnsignedShort4444Type: 1016,
		UnsignedShort5551Type: 1017,
		UnsignedShort565Type: 1018,

		// Pixel formats

		AlphaFormat: 1019,
		RGBFormat: 1020,
		RGBAFormat: 1021,
		LuminanceFormat: 1022,
		LuminanceAlphaFormat: 1023,
		// THREE.RGBEFormat handled as THREE.RGBAFormat in shaders
		RGBEFormat: THREE.RGBAFormat, //1024;
		DepthFormat: 1026,

		// DDS / ST3C Compressed texture formats

		RGB_S3TC_DXT1_Format: 2001,
		RGBA_S3TC_DXT1_Format: 2002,
		RGBA_S3TC_DXT3_Format: 2003,
		RGBA_S3TC_DXT5_Format: 2004,

		// PVRTC compressed texture formats

		RGB_PVRTC_4BPPV1_Format: 2100,
		RGB_PVRTC_2BPPV1_Format: 2101,
		RGBA_PVRTC_4BPPV1_Format: 2102,
		RGBA_PVRTC_2BPPV1_Format: 2103,

		// ETC compressed texture formats

		RGB_ETC1_Format: 2151,

		// Loop styles for AnimationAction

		LoopOnce: 2200,
		LoopRepeat: 2201,
		LoopPingPong: 2202,

		// Interpolation

		InterpolateDiscrete: 2300,
		InterpolateLinear: 2301,
		InterpolateSmooth: 2302,

		// Interpolant ending modes

		ZeroCurvatureEnding: 2400,
		ZeroSlopeEnding: 2401,
		WrapAroundEnding: 2402,

		// Triangle Draw modes

		TrianglesDrawMode: 0,
		TriangleStripDrawMode: 1,
		TriangleFanDrawMode: 2,

		// Texture Encodings

		LinearEncoding: 3000, // No encoding at all.
		sRGBEncoding: 3001,
		GammaEncoding: 3007, // uses GAMMA_FACTOR, for backwards compatibility with WebGLRenderer.gammaInput/gammaOutput

		// The following Texture Encodings are for RGB-only (no alpha) HDR light emission sources.
		// These encodings should not specified as output encodings except in rare situations.
		RGBEEncoding: 3002, // AKA Radiance.
		LogLuvEncoding: 3003,
		RGBM7Encoding: 3004,
		RGBM16Encoding: 3005,
		RGBDEncoding: 3006, // MaxRange is 256.

		// Depth packing strategies

		BasicDepthPacking: 3200, // for writing to float textures for high precision or for visualizing results in RGB buffers
		RGBADepthPacking: 3201 // for packing into RGBA buffers.

	} );

	// File:src/math/Color.js

	/**
	 * @author mrdoob / http://mrdoob.com/
	 */

	THREE.Color = function ( r, g, b ) {

		if ( g === undefined && b === undefined ) {

			// r is THREE.Color, hex or string
			return this.set( r );

		}

		return this.setRGB( r, g, b );

	};

	THREE.Color.prototype = {

		constructor: THREE.Color,

		r: 1, g: 1, b: 1,

		set: function ( value ) {

			if ( value instanceof THREE.Color ) {

				this.copy( value );

			} else if ( typeof value === 'number' ) {

				this.setHex( value );

			} else if ( typeof value === 'string' ) {

				this.setStyle( value );

			}

			return this;

		},

		setScalar: function ( scalar ) {

			this.r = scalar;
			this.g = scalar;
			this.b = scalar;

		},

		setHex: function ( hex ) {

			hex = Math.floor( hex );

			this.r = ( hex >> 16 & 255 ) / 255;
			this.g = ( hex >> 8 & 255 ) / 255;
			this.b = ( hex & 255 ) / 255;

			return this;

		},

		setRGB: function ( r, g, b ) {

			this.r = r;
			this.g = g;
			this.b = b;

			return this;

		},

		setHSL: function () {

			function hue2rgb( p, q, t ) {

				if ( t < 0 ) t += 1;
				if ( t > 1 ) t -= 1;
				if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t;
				if ( t < 1 / 2 ) return q;
				if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t );
				return p;

			}

			return function setHSL( h, s, l ) {

				// h,s,l ranges are in 0.0 - 1.0
				h = THREE.Math.euclideanModulo( h, 1 );
				s = THREE.Math.clamp( s, 0, 1 );
				l = THREE.Math.clamp( l, 0, 1 );

				if ( s === 0 ) {

					this.r = this.g = this.b = l;

				} else {

					var p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s );
					var q = ( 2 * l ) - p;

					this.r = hue2rgb( q, p, h + 1 / 3 );
					this.g = hue2rgb( q, p, h );
					this.b = hue2rgb( q, p, h - 1 / 3 );

				}

				return this;

			};

		}(),

		setStyle: function ( style ) {

			function handleAlpha( string ) {

				if ( string === undefined ) return;

				if ( parseFloat( string ) < 1 ) {

					console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' );

				}

			}


			var m;

			if ( m = /^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec( style ) ) {

				// rgb / hsl

				var color;
				var name = m[ 1 ];
				var components = m[ 2 ];

				switch ( name ) {

					case 'rgb':
					case 'rgba':

						if ( color = /^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) {

							// rgb(255,0,0) rgba(255,0,0,0.5)
							this.r = Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255;
							this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255;
							this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255;

							handleAlpha( color[ 5 ] );

							return this;

						}

						if ( color = /^(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) {

							// rgb(100%,0%,0%) rgba(100%,0%,0%,0.5)
							this.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100;
							this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100;
							this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100;

							handleAlpha( color[ 5 ] );

							return this;

						}

						break;

					case 'hsl':
					case 'hsla':

						if ( color = /^([0-9]*\.?[0-9]+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) {

							// hsl(120,50%,50%) hsla(120,50%,50%,0.5)
							var h = parseFloat( color[ 1 ] ) / 360;
							var s = parseInt( color[ 2 ], 10 ) / 100;
							var l = parseInt( color[ 3 ], 10 ) / 100;

							handleAlpha( color[ 5 ] );

							return this.setHSL( h, s, l );

						}

						break;

				}

			} else if ( m = /^\#([A-Fa-f0-9]+)$/.exec( style ) ) {

				// hex color

				var hex = m[ 1 ];
				var size = hex.length;

				if ( size === 3 ) {

					// #ff0
					this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 0 ), 16 ) / 255;
					this.g = parseInt( hex.charAt( 1 ) + hex.charAt( 1 ), 16 ) / 255;
					this.b = parseInt( hex.charAt( 2 ) + hex.charAt( 2 ), 16 ) / 255;

					return this;

				} else if ( size === 6 ) {

					// #ff0000
					this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 1 ), 16 ) / 255;
					this.g = parseInt( hex.charAt( 2 ) + hex.charAt( 3 ), 16 ) / 255;
					this.b = parseInt( hex.charAt( 4 ) + hex.charAt( 5 ), 16 ) / 255;

					return this;

				}

			}

			if ( style && style.length > 0 ) {

				// color keywords
				var hex = THREE.ColorKeywords[ style ];

				if ( hex !== undefined ) {

					// red
					this.setHex( hex );

				} else {

					// unknown color
					console.warn( 'THREE.Color: Unknown color ' + style );

				}

			}

			return this;

		},

		clone: function () {

			return new this.constructor( this.r, this.g, this.b );

		},

		copy: function ( color ) {

			this.r = color.r;
			this.g = color.g;
			this.b = color.b;

			return this;

		},

		copyGammaToLinear: function ( color, gammaFactor ) {

			if ( gammaFactor === undefined ) gammaFactor = 2.0;

			this.r = Math.pow( color.r, gammaFactor );
			this.g = Math.pow( color.g, gammaFactor );
			this.b = Math.pow( color.b, gammaFactor );

			return this;

		},

		copyLinearToGamma: function ( color, gammaFactor ) {

			if ( gammaFactor === undefined ) gammaFactor = 2.0;

			var safeInverse = ( gammaFactor > 0 ) ? ( 1.0 / gammaFactor ) : 1.0;

			this.r = Math.pow( color.r, safeInverse );
			this.g = Math.pow( color.g, safeInverse );
			this.b = Math.pow( color.b, safeInverse );

			return this;

		},

		convertGammaToLinear: function () {

			var r = this.r, g = this.g, b = this.b;

			this.r = r * r;
			this.g = g * g;
			this.b = b * b;

			return this;

		},

		convertLinearToGamma: function () {

			this.r = Math.sqrt( this.r );
			this.g = Math.sqrt( this.g );
			this.b = Math.sqrt( this.b );

			return this;

		},

		getHex: function () {

			return ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0;

		},

		getHexString: function () {

			return ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 );

		},

		getHSL: function ( optionalTarget ) {

			// h,s,l ranges are in 0.0 - 1.0

			var hsl = optionalTarget || { h: 0, s: 0, l: 0 };

			var r = this.r, g = this.g, b = this.b;

			var max = Math.max( r, g, b );
			var min = Math.min( r, g, b );

			var hue, saturation;
			var lightness = ( min + max ) / 2.0;

			if ( min === max ) {

				hue = 0;
				saturation = 0;

			} else {

				var delta = max - min;

				saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min );

				switch ( max ) {

					case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break;
					case g: hue = ( b - r ) / delta + 2; break;
					case b: hue = ( r - g ) / delta + 4; break;

				}

				hue /= 6;

			}

			hsl.h = hue;
			hsl.s = saturation;
			hsl.l = lightness;

			return hsl;

		},

		getStyle: function () {

			return 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')';

		},

		offsetHSL: function ( h, s, l ) {

			var hsl = this.getHSL();

			hsl.h += h; hsl.s += s; hsl.l += l;

			this.setHSL( hsl.h, hsl.s, hsl.l );

			return this;

		},

		add: function ( color ) {

			this.r += color.r;
			this.g += color.g;
			this.b += color.b;

			return this;

		},

		addColors: function ( color1, color2 ) {

			this.r = color1.r + color2.r;
			this.g = color1.g + color2.g;
			this.b = color1.b + color2.b;

			return this;

		},

		addScalar: function ( s ) {

			this.r += s;
			this.g += s;
			this.b += s;

			return this;

		},

		multiply: function ( color ) {

			this.r *= color.r;
			this.g *= color.g;
			this.b *= color.b;

			return this;

		},

		multiplyScalar: function ( s ) {

			this.r *= s;
			this.g *= s;
			this.b *= s;

			return this;

		},

		lerp: function ( color, alpha ) {

			this.r += ( color.r - this.r ) * alpha;
			this.g += ( color.g - this.g ) * alpha;
			this.b += ( color.b - this.b ) * alpha;

			return this;

		},

		equals: function ( c ) {

			return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b );

		},

		fromArray: function ( array, offset ) {

			if ( offset === undefined ) offset = 0;

			this.r = array[ offset ];
			this.g = array[ offset + 1 ];
			this.b = array[ offset + 2 ];

			return this;

		},

		toArray: function ( array, offset ) {

			if ( array === undefined ) array = [];
			if ( offset === undefined ) offset = 0;

			array[ offset ] = this.r;
			array[ offset + 1 ] = this.g;
			array[ offset + 2 ] = this.b;

			return array;

		}

	};

	THREE.ColorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF,
	'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2,
	'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50,
	'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B,
	'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B,
	'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F,
	'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3,
	'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222,
	'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700,
	'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4,
	'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00,
	'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3,
	'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA,
	'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32,
	'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3,
	'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC,
	'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD,
	'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6,
	'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9,
	'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F,
	'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE,
	'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA,
	'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0,
	'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 };

	// File:src/math/Quaternion.js

	/**
	 * @author mikael emtinger / http://gomo.se/
	 * @author alteredq / http://alteredqualia.com/
	 * @author WestLangley / http://github.com/WestLangley
	 * @author bhouston / http://clara.io
	 */

	THREE.Quaternion = function ( x, y, z, w ) {

		this._x = x || 0;
		this._y = y || 0;
		this._z = z || 0;
		this._w = ( w !== undefined ) ? w : 1;

	};

	THREE.Quaternion.prototype = {

		constructor: THREE.Quaternion,

		get x () {

			return this._x;

		},

		set x ( value ) {

			this._x = value;
			this.onChangeCallback();

		},

		get y () {

			return this._y;

		},

		set y ( value ) {

			this._y = value;
			this.onChangeCallback();

		},

		get z () {

			return this._z;

		},

		set z ( value ) {

			this._z = value;
			this.onChangeCallback();

		},

		get w () {

			return this._w;

		},

		set w ( value ) {

			this._w = value;
			this.onChangeCallback();

		},

		set: function ( x, y, z, w ) {

			this._x = x;
			this._y = y;
			this._z = z;
			this._w = w;

			this.onChangeCallback();

			return this;

		},

		clone: function () {

			return new this.constructor( this._x, this._y, this._z, this._w );

		},

		copy: function ( quaternion ) {

			this._x = quaternion.x;
			this._y = quaternion.y;
			this._z = quaternion.z;
			this._w = quaternion.w;

			this.onChangeCallback();

			return this;

		},

		setFromEuler: function ( euler, update ) {

			if ( euler instanceof THREE.Euler === false ) {

				throw new Error( 'THREE.Quaternion: .setFromEuler() now expects a Euler rotation rather than a Vector3 and order.' );

			}

			// http://www.mathworks.com/matlabcentral/fileexchange/
			// 	20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
			//	content/SpinCalc.m

			var c1 = Math.cos( euler._x / 2 );
			var c2 = Math.cos( euler._y / 2 );
			var c3 = Math.cos( euler._z / 2 );
			var s1 = Math.sin( euler._x / 2 );
			var s2 = Math.sin( euler._y / 2 );
			var s3 = Math.sin( euler._z / 2 );

			var order = euler.order;

			if ( order === 'XYZ' ) {

				this._x = s1 * c2 * c3 + c1 * s2 * s3;
				this._y = c1 * s2 * c3 - s1 * c2 * s3;
				this._z = c1 * c2 * s3 + s1 * s2 * c3;
				this._w = c1 * c2 * c3 - s1 * s2 * s3;

			} else if ( order === 'YXZ' ) {

				this._x = s1 * c2 * c3 + c1 * s2 * s3;
				this._y = c1 * s2 * c3 - s1 * c2 * s3;
				this._z = c1 * c2 * s3 - s1 * s2 * c3;
				this._w = c1 * c2 * c3 + s1 * s2 * s3;

			} else if ( order === 'ZXY' ) {

				this._x = s1 * c2 * c3 - c1 * s2 * s3;
				this._y = c1 * s2 * c3 + s1 * c2 * s3;
				this._z = c1 * c2 * s3 + s1 * s2 * c3;
				this._w = c1 * c2 * c3 - s1 * s2 * s3;

			} else if ( order === 'ZYX' ) {

				this._x = s1 * c2 * c3 - c1 * s2 * s3;
				this._y = c1 * s2 * c3 + s1 * c2 * s3;
				this._z = c1 * c2 * s3 - s1 * s2 * c3;
				this._w = c1 * c2 * c3 + s1 * s2 * s3;

			} else if ( order === 'YZX' ) {

				this._x = s1 * c2 * c3 + c1 * s2 * s3;
				this._y = c1 * s2 * c3 + s1 * c2 * s3;
				this._z = c1 * c2 * s3 - s1 * s2 * c3;
				this._w = c1 * c2 * c3 - s1 * s2 * s3;

			} else if ( order === 'XZY' ) {

				this._x = s1 * c2 * c3 - c1 * s2 * s3;
				this._y = c1 * s2 * c3 - s1 * c2 * s3;
				this._z = c1 * c2 * s3 + s1 * s2 * c3;
				this._w = c1 * c2 * c3 + s1 * s2 * s3;

			}

			if ( update !== false ) this.onChangeCallback();

			return this;

		},

		setFromAxisAngle: function ( axis, angle ) {

			// http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm

			// assumes axis is normalized

			var halfAngle = angle / 2, s = Math.sin( halfAngle );

			this._x = axis.x * s;
			this._y = axis.y * s;
			this._z = axis.z * s;
			this._w = Math.cos( halfAngle );

			this.onChangeCallback();

			return this;

		},

		setFromRotationMatrix: function ( m ) {

			// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm

			// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)

			var te = m.elements,

				m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
				m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
				m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ],

				trace = m11 + m22 + m33,
				s;

			if ( trace > 0 ) {

				s = 0.5 / Math.sqrt( trace + 1.0 );

				this._w = 0.25 / s;
				this._x = ( m32 - m23 ) * s;
				this._y = ( m13 - m31 ) * s;
				this._z = ( m21 - m12 ) * s;

			} else if ( m11 > m22 && m11 > m33 ) {

				s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 );

				this._w = ( m32 - m23 ) / s;
				this._x = 0.25 * s;
				this._y = ( m12 + m21 ) / s;
				this._z = ( m13 + m31 ) / s;

			} else if ( m22 > m33 ) {

				s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 );

				this._w = ( m13 - m31 ) / s;
				this._x = ( m12 + m21 ) / s;
				this._y = 0.25 * s;
				this._z = ( m23 + m32 ) / s;

			} else {

				s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 );

				this._w = ( m21 - m12 ) / s;
				this._x = ( m13 + m31 ) / s;
				this._y = ( m23 + m32 ) / s;
				this._z = 0.25 * s;

			}

			this.onChangeCallback();

			return this;

		},

		setFromUnitVectors: function () {

			// http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final

			// assumes direction vectors vFrom and vTo are normalized

			var v1, r;

			var EPS = 0.000001;

			return function setFromUnitVectors( vFrom, vTo ) {

				if ( v1 === undefined ) v1 = new THREE.Vector3();

				r = vFrom.dot( vTo ) + 1;

				if ( r < EPS ) {

					r = 0;

					if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) {

						v1.set( - vFrom.y, vFrom.x, 0 );

					} else {

						v1.set( 0, - vFrom.z, vFrom.y );

					}

				} else {

					v1.crossVectors( vFrom, vTo );

				}

				this._x = v1.x;
				this._y = v1.y;
				this._z = v1.z;
				this._w = r;

				return this.normalize();

			};

		}(),

		inverse: function () {

			return this.conjugate().normalize();

		},

		conjugate: function () {

			this._x *= - 1;
			this._y *= - 1;
			this._z *= - 1;

			this.onChangeCallback();

			return this;

		},

		dot: function ( v ) {

			return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w;

		},

		lengthSq: function () {

			return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w;

		},

		length: function () {

			return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w );

		},

		normalize: function () {

			var l = this.length();

			if ( l === 0 ) {

				this._x = 0;
				this._y = 0;
				this._z = 0;
				this._w = 1;

			} else {

				l = 1 / l;

				this._x = this._x * l;
				this._y = this._y * l;
				this._z = this._z * l;
				this._w = this._w * l;

			}

			this.onChangeCallback();

			return this;

		},

		multiply: function ( q, p ) {

			if ( p !== undefined ) {

				console.warn( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' );
				return this.multiplyQuaternions( q, p );

			}

			return this.multiplyQuaternions( this, q );

		},

		premultiply: function ( q ) {

			return this.multiplyQuaternions( q, this );

		},

		multiplyQuaternions: function ( a, b ) {

			// from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm

			var qax = a._x, qay = a._y, qaz = a._z, qaw = a._w;
			var qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w;

			this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
			this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
			this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
			this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;

			this.onChangeCallback();

			return this;

		},

		slerp: function ( qb, t ) {

			if ( t === 0 ) return this;
			if ( t === 1 ) return this.copy( qb );

			var x = this._x, y = this._y, z = this._z, w = this._w;

			// http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/

			var cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z;

			if ( cosHalfTheta < 0 ) {

				this._w = - qb._w;
				this._x = - qb._x;
				this._y = - qb._y;
				this._z = - qb._z;

				cosHalfTheta = - cosHalfTheta;

			} else {

				this.copy( qb );

			}

			if ( cosHalfTheta >= 1.0 ) {

				this._w = w;
				this._x = x;
				this._y = y;
				this._z = z;

				return this;

			}

			var sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta );

			if ( Math.abs( sinHalfTheta ) < 0.001 ) {

				this._w = 0.5 * ( w + this._w );
				this._x = 0.5 * ( x + this._x );
				this._y = 0.5 * ( y + this._y );
				this._z = 0.5 * ( z + this._z );

				return this;

			}

			var halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta );
			var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta,
			ratioB = Math.sin( t * halfTheta ) / sinHalfTheta;

			this._w = ( w * ratioA + this._w * ratioB );
			this._x = ( x * ratioA + this._x * ratioB );
			this._y = ( y * ratioA + this._y * ratioB );
			this._z = ( z * ratioA + this._z * ratioB );

			this.onChangeCallback();

			return this;

		},

		equals: function ( quaternion ) {

			return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w );

		},

		fromArray: function ( array, offset ) {

			if ( offset === undefined ) offset = 0;

			this._x = array[ offset ];
			this._y = array[ offset + 1 ];
			this._z = array[ offset + 2 ];
			this._w = array[ offset + 3 ];

			this.onChangeCallback();

			return this;

		},

		toArray: function ( array, offset ) {

			if ( array === undefined ) array = [];
			if ( offset === undefined ) offset = 0;

			array[ offset ] = this._x;
			array[ offset + 1 ] = this._y;
			array[ offset + 2 ] = this._z;
			array[ offset + 3 ] = this._w;

			return array;

		},

		onChange: function ( callback ) {

			this.onChangeCallback = callback;

			return this;

		},

		onChangeCallback: function () {}

	};

	Object.assign( THREE.Quaternion, {

		slerp: function( qa, qb, qm, t ) {

			return qm.copy( qa ).slerp( qb, t );

		},

		slerpFlat: function(
				dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) {

			// fuzz-free, array-based Quaternion SLERP operation

			var x0 = src0[ srcOffset0 + 0 ],
				y0 = src0[ srcOffset0 + 1 ],
				z0 = src0[ srcOffset0 + 2 ],
				w0 = src0[ srcOffset0 + 3 ],

				x1 = src1[ srcOffset1 + 0 ],
				y1 = src1[ srcOffset1 + 1 ],
				z1 = src1[ srcOffset1 + 2 ],
				w1 = src1[ srcOffset1 + 3 ];

			if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) {

				var s = 1 - t,

					cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1,

					dir = ( cos >= 0 ? 1 : - 1 ),
					sqrSin = 1 - cos * cos;

				// Skip the Slerp for tiny steps to avoid numeric problems:
				if ( sqrSin > Number.EPSILON ) {

					var sin = Math.sqrt( sqrSin ),
						len = Math.atan2( sin, cos * dir );

					s = Math.sin( s * len ) / sin;
					t = Math.sin( t * len ) / sin;

				}

				var tDir = t * dir;

				x0 = x0 * s + x1 * tDir;
				y0 = y0 * s + y1 * tDir;
				z0 = z0 * s + z1 * tDir;
				w0 = w0 * s + w1 * tDir;

				// Normalize in case we just did a lerp:
				if ( s === 1 - t ) {

					var f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 );

					x0 *= f;
					y0 *= f;
					z0 *= f;
					w0 *= f;

				}

			}

			dst[ dstOffset ] = x0;
			dst[ dstOffset + 1 ] = y0;
			dst[ dstOffset + 2 ] = z0;
			dst[ dstOffset + 3 ] = w0;

		}

	} );

	// File:src/math/Vector2.js

	/**
	 * @author mrdoob / http://mrdoob.com/
	 * @author philogb / http://blog.thejit.org/
	 * @author egraether / http://egraether.com/
	 * @author zz85 / http://www.lab4games.net/zz85/blog
	 */

	THREE.Vector2 = function ( x, y ) {

		this.x = x || 0;
		this.y = y || 0;

	};

	THREE.Vector2.prototype = {

		constructor: THREE.Vector2,

		get width() {

			return this.x;

		},

		set width( value ) {

			this.x = value;

		},

		get height() {

			return this.y;

		},

		set height( value ) {

			this.y = value;

		},

		//

		set: function ( x, y ) {

			this.x = x;
			this.y = y;

			return this;

		},

		setScalar: function ( scalar ) {

			this.x = scalar;
			this.y = scalar;

			return this;

		},

		setX: function ( x ) {

			this.x = x;

			return this;

		},

		setY: function ( y ) {

			this.y = y;

			return this;

		},

		setComponent: function ( index, value ) {

			switch ( index ) {

				case 0: this.x = value; break;
				case 1: this.y = value; break;
				default: throw new Error( 'index is out of range: ' + index );

			}

		},

		getComponent: function ( index ) {

			switch ( index ) {

				case 0: return this.x;
				case 1: return this.y;
				default: throw new Error( 'index is out of range: ' + index );

			}

		},

		clone: function () {

			return new this.constructor( this.x, this.y );

		},

		copy: function ( v ) {

			this.x = v.x;
			this.y = v.y;

			return this;

		},

		add: function ( v, w ) {

			if ( w !== undefined ) {

				console.warn( 'THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
				return this.addVectors( v, w );

			}

			this.x += v.x;
			this.y += v.y;

			return this;

		},

		addScalar: function ( s ) {

			this.x += s;
			this.y += s;

			return this;

		},

		addVectors: function ( a, b ) {

			this.x = a.x + b.x;
			this.y = a.y + b.y;

			return this;

		},

		addScaledVector: function ( v, s ) {

			this.x += v.x * s;
			this.y += v.y * s;

			return this;

		},

		sub: function ( v, w ) {

			if ( w !== undefined ) {

				console.warn( 'THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
				return this.subVectors( v, w );

			}

			this.x -= v.x;
			this.y -= v.y;

			return this;

		},

		subScalar: function ( s ) {

			this.x -= s;
			this.y -= s;

			return this;

		},

		subVectors: function ( a, b ) {

			this.x = a.x - b.x;
			this.y = a.y - b.y;

			return this;

		},

		multiply: function ( v ) {

			this.x *= v.x;
			this.y *= v.y;

			return this;

		},

		multiplyScalar: function ( scalar ) {

			if ( isFinite( scalar ) ) {

				this.x *= scalar;
				this.y *= scalar;

			} else {

				this.x = 0;
				this.y = 0;

			}

			return this;

		},

		divide: function ( v ) {

			this.x /= v.x;
			this.y /= v.y;

			return this;

		},

		divideScalar: function ( scalar ) {

			return this.multiplyScalar( 1 / scalar );

		},

		min: function ( v ) {

			this.x = Math.min( this.x, v.x );
			this.y = Math.min( this.y, v.y );

			return this;

		},

		max: function ( v ) {

			this.x = Math.max( this.x, v.x );
			this.y = Math.max( this.y, v.y );

			return this;

		},

		clamp: function ( min, max ) {

			// This function assumes min < max, if this assumption isn't true it will not operate correctly

			this.x = Math.max( min.x, Math.min( max.x, this.x ) );
			this.y = Math.max( min.y, Math.min( max.y, this.y ) );

			return this;

		},

		clampScalar: function () {

			var min, max;

			return function clampScalar( minVal, maxVal ) {

				if ( min === undefined ) {

					min = new THREE.Vector2();
					max = new THREE.Vector2();

				}

				min.set( minVal, minVal );
				max.set( maxVal, maxVal );

				return this.clamp( min, max );

			};

		}(),

		clampLength: function ( min, max ) {

			var length = this.length();

			return this.multiplyScalar( Math.max( min, Math.min( max, length ) ) / length );

		},

		floor: function () {

			this.x = Math.floor( this.x );
			this.y = Math.floor( this.y );

			return this;

		},

		ceil: function () {

			this.x = Math.ceil( this.x );
			this.y = Math.ceil( this.y );

			return this;

		},

		round: function () {

			this.x = Math.round( this.x );
			this.y = Math.round( this.y );

			return this;

		},

		roundToZero: function () {

			this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
			this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );

			return this;

		},

		negate: function () {

			this.x = - this.x;
			this.y = - this.y;

			return this;

		},

		dot: function ( v ) {

			return this.x * v.x + this.y * v.y;

		},

		lengthSq: function () {

			return this.x * this.x + this.y * this.y;

		},

		length: function () {

			return Math.sqrt( this.x * this.x + this.y * this.y );

		},

		lengthManhattan: function() {

			return Math.abs( this.x ) + Math.abs( this.y );

		},

		normalize: function () {

			return this.divideScalar( this.length() );

		},

		angle: function () {

			// computes the angle in radians with respect to the positive x-axis

			var angle = Math.atan2( this.y, this.x );

			if ( angle < 0 ) angle += 2 * Math.PI;

			return angle;

		},

		distanceTo: function ( v ) {

			return Math.sqrt( this.distanceToSquared( v ) );

		},

		distanceToSquared: function ( v ) {

			var dx = this.x - v.x, dy = this.y - v.y;
			return dx * dx + dy * dy;

		},

		setLength: function ( length ) {

			return this.multiplyScalar( length / this.length() );

		},

		lerp: function ( v, alpha ) {

			this.x += ( v.x - this.x ) * alpha;
			this.y += ( v.y - this.y ) * alpha;

			return this;

		},

		lerpVectors: function ( v1, v2, alpha ) {

			return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );

		},

		equals: function ( v ) {

			return ( ( v.x === this.x ) && ( v.y === this.y ) );

		},

		fromArray: function ( array, offset ) {

			if ( offset === undefined ) offset = 0;

			this.x = array[ offset ];
			this.y = array[ offset + 1 ];

			return this;

		},

		toArray: function ( array, offset ) {

			if ( array === undefined ) array = [];
			if ( offset === undefined ) offset = 0;

			array[ offset ] = this.x;
			array[ offset + 1 ] = this.y;

			return array;

		},

		fromAttribute: function ( attribute, index, offset ) {

			if ( offset === undefined ) offset = 0;

			index = index * attribute.itemSize + offset;

			this.x = attribute.array[ index ];
			this.y = attribute.array[ index + 1 ];

			return this;

		},

		rotateAround: function ( center, angle ) {

			var c = Math.cos( angle ), s = Math.sin( angle );

			var x = this.x - center.x;
			var y = this.y - center.y;

			this.x = x * c - y * s + center.x;
			this.y = x * s + y * c + center.y;

			return this;

		}

	};

	// File:src/math/Vector3.js

	/**
	 * @author mrdoob / http://mrdoob.com/
	 * @author *kile / http://kile.stravaganza.org/
	 * @author philogb / http://blog.thejit.org/
	 * @author mikael emtinger / http://gomo.se/
	 * @author egraether / http://egraether.com/
	 * @author WestLangley / http://github.com/WestLangley
	 */

	THREE.Vector3 = function ( x, y, z ) {

		this.x = x || 0;
		this.y = y || 0;
		this.z = z || 0;

	};

	THREE.Vector3.prototype = {

		constructor: THREE.Vector3,

		set: function ( x, y, z ) {

			this.x = x;
			this.y = y;
			this.z = z;

			return this;

		},

		setScalar: function ( scalar ) {

			this.x = scalar;
			this.y = scalar;
			this.z = scalar;

			return this;

		},

		setX: function ( x ) {

			this.x = x;

			return this;

		},

		setY: function ( y ) {

			this.y = y;

			return this;

		},

		setZ: function ( z ) {

			this.z = z;

			return this;

		},

		setComponent: function ( index, value ) {

			switch ( index ) {

				case 0: this.x = value; break;
				case 1: this.y = value; break;
				case 2: this.z = value; break;
				default: throw new Error( 'index is out of range: ' + index );

			}

		},

		getComponent: function ( index ) {

			switch ( index ) {

				case 0: return this.x;
				case 1: return this.y;
				case 2: return this.z;
				default: throw new Error( 'index is out of range: ' + index );

			}

		},

		clone: function () {

			return new this.constructor( this.x, this.y, this.z );

		},

		copy: function ( v ) {

			this.x = v.x;
			this.y = v.y;
			this.z = v.z;

			return this;

		},

		add: function ( v, w ) {

			if ( w !== undefined ) {

				console.warn( 'THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
				return this.addVectors( v, w );

			}

			this.x += v.x;
			this.y += v.y;
			this.z += v.z;

			return this;

		},

		addScalar: function ( s ) {

			this.x += s;
			this.y += s;
			this.z += s;

			return this;

		},

		addVectors: function ( a, b ) {

			this.x = a.x + b.x;
			this.y = a.y + b.y;
			this.z = a.z + b.z;

			return this;

		},

		addScaledVector: function ( v, s ) {

			this.x += v.x * s;
			this.y += v.y * s;
			this.z += v.z * s;

			return this;

		},

		sub: function ( v, w ) {

			if ( w !== undefined ) {

				console.warn( 'THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
				return this.subVectors( v, w );

			}

			this.x -= v.x;
			this.y -= v.y;
			this.z -= v.z;

			return this;

		},

		subScalar: function ( s ) {

			this.x -= s;
			this.y -= s;
			this.z -= s;

			return this;

		},

		subVectors: function ( a, b ) {

			this.x = a.x - b.x;
			this.y = a.y - b.y;
			this.z = a.z - b.z;

			return this;

		},

		multiply: function ( v, w ) {

			if ( w !== undefined ) {

				console.warn( 'THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' );
				return this.multiplyVectors( v, w );

			}

			this.x *= v.x;
			this.y *= v.y;
			this.z *= v.z;

			return this;

		},

		multiplyScalar: function ( scalar ) {

			if ( isFinite( scalar ) ) {

				this.x *= scalar;
				this.y *= scalar;
				this.z *= scalar;

			} else {

				this.x = 0;
				this.y = 0;
				this.z = 0;

			}

			return this;

		},

		multiplyVectors: function ( a, b ) {

			this.x = a.x * b.x;
			this.y = a.y * b.y;
			this.z = a.z * b.z;

			return this;

		},

		applyEuler: function () {

			var quaternion;

			return function applyEuler( euler ) {

				if ( euler instanceof THREE.Euler === false ) {

					console.error( 'THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order.' );

				}

				if ( quaternion === undefined ) quaternion = new THREE.Quaternion();

				return this.applyQuaternion( quaternion.setFromEuler( euler ) );

			};

		}(),

		applyAxisAngle: function () {

			var quaternion;

			return function applyAxisAngle( axis, angle ) {

				if ( quaternion === undefined ) quaternion = new THREE.Quaternion();

				return this.applyQuaternion( quaternion.setFromAxisAngle( axis, angle ) );

			};

		}(),

		applyMatrix3: function ( m ) {

			var x = this.x, y = this.y, z = this.z;
			var e = m.elements;

			this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z;
			this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z;
			this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z;

			return this;

		},

		applyMatrix4: function ( m ) {

			// input: THREE.Matrix4 affine matrix

			var x = this.x, y = this.y, z = this.z;
			var e = m.elements;

			this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ]  * z + e[ 12 ];
			this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ]  * z + e[ 13 ];
			this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ];

			return this;

		},

		applyProjection: function ( m ) {

			// input: THREE.Matrix4 projection matrix

			var x = this.x, y = this.y, z = this.z;
			var e = m.elements;
			var d = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] ); // perspective divide

			this.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ]  * z + e[ 12 ] ) * d;
			this.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ]  * z + e[ 13 ] ) * d;
			this.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * d;

			return this;

		},

		applyQuaternion: function ( q ) {

			var x = this.x, y = this.y, z = this.z;
			var qx = q.x, qy = q.y, qz = q.z, qw = q.w;

			// calculate quat * vector

			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

			this.x = ix * qw + iw * - qx + iy * - qz - iz * - qy;
			this.y = iy * qw + iw * - qy + iz * - qx - ix * - qz;
			this.z = iz * qw + iw * - qz + ix * - qy - iy * - qx;

			return this;

		},

		project: function () {

			var matrix;

			return function project( camera ) {

				if ( matrix === undefined ) matrix = new THREE.Matrix4();

				matrix.multiplyMatrices( camera.projectionMatrix, matrix.getInverse( camera.matrixWorld ) );
				return this.applyProjection( matrix );

			};

		}(),

		unproject: function () {

			var matrix;

			return function unproject( camera ) {

				if ( matrix === undefined ) matrix = new THREE.Matrix4();

				matrix.multiplyMatrices( camera.matrixWorld, matrix.getInverse( camera.projectionMatrix ) );
				return this.applyProjection( matrix );

			};

		}(),

		transformDirection: function ( m ) {

			// input: THREE.Matrix4 affine matrix
			// vector interpreted as a direction

			var x = this.x, y = this.y, z = this.z;
			var e = m.elements;

			this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ]  * z;
			this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ]  * z;
			this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z;

			return this.normalize();

		},

		divide: function ( v ) {

			this.x /= v.x;
			this.y /= v.y;
			this.z /= v.z;

			return this;

		},

		divideScalar: function ( scalar ) {

			return this.multiplyScalar( 1 / scalar );

		},

		min: function ( v ) {

			this.x = Math.min( this.x, v.x );
			this.y = Math.min( this.y, v.y );
			this.z = Math.min( this.z, v.z );

			return this;

		},

		max: function ( v ) {

			this.x = Math.max( this.x, v.x );
			this.y = Math.max( this.y, v.y );
			this.z = Math.max( this.z, v.z );

			return this;

		},

		clamp: function ( min, max ) {

			// This function assumes min < max, if this assumption isn't true it will not operate correctly

			this.x = Math.max( min.x, Math.min( max.x, this.x ) );
			this.y = Math.max( min.y, Math.min( max.y, this.y ) );
			this.z = Math.max( min.z, Math.min( max.z, this.z ) );

			return this;

		},

		clampScalar: function () {

			var min, max;

			return function clampScalar( minVal, maxVal ) {

				if ( min === undefined ) {

					min = new THREE.Vector3();
					max = new THREE.Vector3();

				}

				min.set( minVal, minVal, minVal );
				max.set( maxVal, maxVal, maxVal );

				return this.clamp( min, max );

			};

		}(),

		clampLength: function ( min, max ) {

			var length = this.length();

			return this.multiplyScalar( Math.max( min, Math.min( max, length ) ) / length );

		},

		floor: function () {

			this.x = Math.floor( this.x );
			this.y = Math.floor( this.y );
			this.z = Math.floor( this.z );

			return this;

		},

		ceil: function () {

			this.x = Math.ceil( this.x );
			this.y = Math.ceil( this.y );
			this.z = Math.ceil( this.z );

			return this;

		},

		round: function () {

			this.x = Math.round( this.x );
			this.y = Math.round( this.y );
			this.z = Math.round( this.z );

			return this;

		},

		roundToZero: function () {

			this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
			this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
			this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );

			return this;

		},

		negate: function () {

			this.x = - this.x;
			this.y = - this.y;
			this.z = - this.z;

			return this;

		},

		dot: function ( v ) {

			return this.x * v.x + this.y * v.y + this.z * v.z;

		},

		lengthSq: function () {

			return this.x * this.x + this.y * this.y + this.z * this.z;

		},

		length: function () {

			return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );

		},

		lengthManhattan: function () {

			return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z );

		},

		normalize: function () {

			return this.divideScalar( this.length() );

		},

		setLength: function ( length ) {

			return this.multiplyScalar( length / this.length() );

		},

		lerp: function ( v, alpha ) {

			this.x += ( v.x - this.x ) * alpha;
			this.y += ( v.y - this.y ) * alpha;
			this.z += ( v.z - this.z ) * alpha;

			return this;

		},

		lerpVectors: function ( v1, v2, alpha ) {

			return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );

		},

		cross: function ( v, w ) {

			if ( w !== undefined ) {

				console.warn( 'THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' );
				return this.crossVectors( v, w );

			}

			var x = this.x, y = this.y, z = this.z;

			this.x = y * v.z - z * v.y;
			this.y = z * v.x - x * v.z;
			this.z = x * v.y - y * v.x;

			return this;

		},

		crossVectors: function ( a, b ) {

			var ax = a.x, ay = a.y, az = a.z;
			var bx = b.x, by = b.y, bz = b.z;

			this.x = ay * bz - az * by;
			this.y = az * bx - ax * bz;
			this.z = ax * by - ay * bx;

			return this;

		},

		projectOnVector: function ( vector ) {

			var scalar = vector.dot( this ) / vector.lengthSq();
		
			return this.copy( vector ).multiplyScalar( scalar );
		
		},

		projectOnPlane: function () {

			var v1;

			return function projectOnPlane( planeNormal ) {

				if ( v1 === undefined ) v1 = new THREE.Vector3();

				v1.copy( this ).projectOnVector( planeNormal );

				return this.sub( v1 );

			};

		}(),

		reflect: function () {

			// reflect incident vector off plane orthogonal to normal
			// normal is assumed to have unit length

			var v1;

			return function reflect( normal ) {

				if ( v1 === undefined ) v1 = new THREE.Vector3();

				return this.sub( v1.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) );

			};

		}(),

		angleTo: function ( v ) {

			var theta = this.dot( v ) / ( Math.sqrt( this.lengthSq() * v.lengthSq() ) );

			// clamp, to handle numerical problems

			return Math.acos( THREE.Math.clamp( theta, - 1, 1 ) );

		},

		distanceTo: function ( v ) {

			return Math.sqrt( this.distanceToSquared( v ) );

		},

		distanceToSquared: function ( v ) {

			var dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z;

			return dx * dx + dy * dy + dz * dz;

		},

		setFromSpherical: function( s ) {

			var sinPhiRadius = Math.sin( s.phi ) * s.radius;

			this.x = sinPhiRadius * Math.sin( s.theta );
			this.y = Math.cos( s.phi ) * s.radius;
			this.z = sinPhiRadius * Math.cos( s.theta );

			return this;

		},

		setFromMatrixPosition: function ( m ) {

			return this.setFromMatrixColumn( m, 3 );

		},

		setFromMatrixScale: function ( m ) {

			var sx = this.setFromMatrixColumn( m, 0 ).length();
			var sy = this.setFromMatrixColumn( m, 1 ).length();
			var sz = this.setFromMatrixColumn( m, 2 ).length();

			this.x = sx;
			this.y = sy;
			this.z = sz;

			return this;

		},

		setFromMatrixColumn: function ( m, index ) {

			if ( typeof m === 'number' ) {

				console.warn( 'THREE.Vector3: setFromMatrixColumn now expects ( matrix, index ).' );
				var temp = m
				m = index;
				index = temp;

			}

			return this.fromArray( m.elements, index * 4 );

		},

		equals: function ( v ) {

			return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) );

		},

		fromArray: function ( array, offset ) {

			if ( offset === undefined ) offset = 0;

			this.x = array[ offset ];
			this.y = array[ offset + 1 ];
			this.z = array[ offset + 2 ];

			return this;

		},

		toArray: function ( array, offset ) {

			if ( array === undefined ) array = [];
			if ( offset === undefined ) offset = 0;

			array[ offset ] = this.x;
			array[ offset + 1 ] = this.y;
			array[ offset + 2 ] = this.z;

			return array;

		},

		fromAttribute: function ( attribute, index, offset ) {

			if ( offset === undefined ) offset = 0;

			index = index * attribute.itemSize + offset;

			this.x = attribute.array[ index ];
			this.y = attribute.array[ index + 1 ];
			this.z = attribute.array[ index + 2 ];

			return this;

		}

	};

	// File:src/math/Vector4.js

	/**
	 * @author supereggbert / http://www.paulbrunt.co.uk/
	 * @author philogb / http://blog.thejit.org/
	 * @author mikael emtinger / http://gomo.se/
	 * @author egraether / http://egraether.com/
	 * @author WestLangley / http://github.com/WestLangley
	 */

	THREE.Vector4 = function ( x, y, z, w ) {

		this.x = x || 0;
		this.y = y || 0;
		this.z = z || 0;
		this.w = ( w !== undefined ) ? w : 1;

	};

	THREE.Vector4.prototype = {

		constructor: THREE.Vector4,

		set: function ( x, y, z, w ) {

			this.x = x;
			this.y = y;
			this.z = z;
			this.w = w;

			return this;

		},

		setScalar: function ( scalar ) {

			this.x = scalar;
			this.y = scalar;
			this.z = scalar;
			this.w = scalar;

			return this;

		},

		setX: function ( x ) {

			this.x = x;

			return this;

		},

		setY: function ( y ) {

			this.y = y;

			return this;

		},

		setZ: function ( z ) {

			this.z = z;

			return this;

		},

		setW: function ( w ) {

			this.w = w;

			return this;

		},

		setComponent: function ( index, value ) {

			switch ( index ) {

				case 0: this.x = value; break;
				case 1: this.y = value; break;
				case 2: this.z = value; break;
				case 3: this.w = value; break;
				default: throw new Error( 'index is out of range: ' + index );

			}

		},

		getComponent: function ( index ) {

			switch ( index ) {

				case 0: return this.x;
				case 1: return this.y;
				case 2: return this.z;
				case 3: return this.w;
				default: throw new Error( 'index is out of range: ' + index );

			}

		},

		clone: function () {

			return new this.constructor( this.x, this.y, this.z, this.w );

		},

		copy: function ( v ) {

			this.x = v.x;
			this.y = v.y;
			this.z = v.z;
			this.w = ( v.w !== undefined ) ? v.w : 1;

			return this;

		},

		add: function ( v, w ) {

			if ( w !== undefined ) {

				console.warn( 'THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
				return this.addVectors( v, w );

			}

			this.x += v.x;
			this.y += v.y;
			this.z += v.z;
			this.w += v.w;

			return this;

		},

		addScalar: function ( s ) {

			this.x += s;
			this.y += s;
			this.z += s;
			this.w += s;

			return this;

		},

		addVectors: function ( a, b ) {

			this.x = a.x + b.x;
			this.y = a.y + b.y;
			this.z = a.z + b.z;
			this.w = a.w + b.w;

			return this;

		},

		addScaledVector: function ( v, s ) {

			this.x += v.x * s;
			this.y += v.y * s;
			this.z += v.z * s;
			this.w += v.w * s;

			return this;

		},

		sub: function ( v, w ) {

			if ( w !== undefined ) {

				console.warn( 'THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
				return this.subVectors( v, w );

			}

			this.x -= v.x;
			this.y -= v.y;
			this.z -= v.z;
			this.w -= v.w;

			return this;

		},

		subScalar: function ( s ) {

			this.x -= s;
			this.y -= s;
			this.z -= s;
			this.w -= s;

			return this;

		},

		subVectors: function ( a, b ) {

			this.x = a.x - b.x;
			this.y = a.y - b.y;
			this.z = a.z - b.z;
			this.w = a.w - b.w;

			return this;

		},

		multiplyScalar: function ( scalar ) {

			if ( isFinite( scalar ) ) {

				this.x *= scalar;
				this.y *= scalar;
				this.z *= scalar;
				this.w *= scalar;

			} else {

				this.x = 0;
				this.y = 0;
				this.z = 0;
				this.w = 0;

			}

			return this;

		},

		applyMatrix4: function ( m ) {

			var x = this.x, y = this.y, z = this.z, w = this.w;
			var e = m.elements;

			this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w;
			this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w;
			this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w;
			this.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w;

			return this;

		},

		divideScalar: function ( scalar ) {

			return this.multiplyScalar( 1 / scalar );

		},

		setAxisAngleFromQuaternion: function ( q ) {

			// http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm

			// q is assumed to be normalized

			this.w = 2 * Math.acos( q.w );

			var s = Math.sqrt( 1 - q.w * q.w );

			if ( s < 0.0001 ) {

				 this.x = 1;
				 this.y = 0;
				 this.z = 0;

			} else {

				 this.x = q.x / s;
				 this.y = q.y / s;
				 this.z = q.z / s;

			}

			return this;

		},

		setAxisAngleFromRotationMatrix: function ( m ) {

			// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm

			// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)

			var angle, x, y, z,		// variables for result
				epsilon = 0.01,		// margin to allow for rounding errors
				epsilon2 = 0.1,		// margin to distinguish between 0 and 180 degrees

				te = m.elements,

				m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
				m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
				m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];

			if ( ( Math.abs( m12 - m21 ) < epsilon ) &&
			     ( Math.abs( m13 - m31 ) < epsilon ) &&
			     ( Math.abs( m23 - m32 ) < epsilon ) ) {

				// singularity found
				// first check for identity matrix which must have +1 for all terms
				// in leading diagonal and zero in other terms

				if ( ( Math.abs( m12 + m21 ) < epsilon2 ) &&
				     ( Math.abs( m13 + m31 ) < epsilon2 ) &&
				     ( Math.abs( m23 + m32 ) < epsilon2 ) &&
				     ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) {

					// this singularity is identity matrix so angle = 0

					this.set( 1, 0, 0, 0 );

					return this; // zero angle, arbitrary axis

				}

				// otherwise this singularity is angle = 180

				angle = Math.PI;

				var xx = ( m11 + 1 ) / 2;
				var yy = ( m22 + 1 ) / 2;
				var zz = ( m33 + 1 ) / 2;
				var xy = ( m12 + m21 ) / 4;
				var xz = ( m13 + m31 ) / 4;
				var yz = ( m23 + m32 ) / 4;

				if ( ( xx > yy ) && ( xx > zz ) ) {

					// m11 is the largest diagonal term

					if ( xx < epsilon ) {

						x = 0;
						y = 0.707106781;
						z = 0.707106781;

					} else {

						x = Math.sqrt( xx );
						y = xy / x;
						z = xz / x;

					}

				} else if ( yy > zz ) {

					// m22 is the largest diagonal term

					if ( yy < epsilon ) {

						x = 0.707106781;
						y = 0;
						z = 0.707106781;

					} else {

						y = Math.sqrt( yy );
						x = xy / y;
						z = yz / y;

					}

				} else {

					// m33 is the largest diagonal term so base result on this

					if ( zz < epsilon ) {

						x = 0.707106781;
						y = 0.707106781;
						z = 0;

					} else {

						z = Math.sqrt( zz );
						x = xz / z;
						y = yz / z;

					}

				}

				this.set( x, y, z, angle );

				return this; // return 180 deg rotation

			}

			// as we have reached here there are no singularities so we can handle normally

			var s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) +
			                   ( m13 - m31 ) * ( m13 - m31 ) +
			                   ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize

			if ( Math.abs( s ) < 0.001 ) s = 1;

			// prevent divide by zero, should not happen if matrix is orthogonal and should be
			// caught by singularity test above, but I've left it in just in case

			this.x = ( m32 - m23 ) / s;
			this.y = ( m13 - m31 ) / s;
			this.z = ( m21 - m12 ) / s;
			this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 );

			return this;

		},

		min: function ( v ) {

			this.x = Math.min( this.x, v.x );
			this.y = Math.min( this.y, v.y );
			this.z = Math.min( this.z, v.z );
			this.w = Math.min( this.w, v.w );

			return this;

		},

		max: function ( v ) {

			this.x = Math.max( this.x, v.x );
			this.y = Math.max( this.y, v.y );
			this.z = Math.max( this.z, v.z );
			this.w = Math.max( this.w, v.w );

			return this;

		},

		clamp: function ( min, max ) {

			// This function assumes min < max, if this assumption isn't true it will not operate correctly

			this.x = Math.max( min.x, Math.min( max.x, this.x ) );
			this.y = Math.max( min.y, Math.min( max.y, this.y ) );
			this.z = Math.max( min.z, Math.min( max.z, this.z ) );
			this.w = Math.max( min.w, Math.min( max.w, this.w ) );

			return this;

		},

		clampScalar: function () {

			var min, max;

			return function clampScalar( minVal, maxVal ) {

				if ( min === undefined ) {

					min = new THREE.Vector4();
					max = new THREE.Vector4();

				}

				min.set( minVal, minVal, minVal, minVal );
				max.set( maxVal, maxVal, maxVal, maxVal );

				return this.clamp( min, max );

			};

		}(),

		floor: function () {

			this.x = Math.floor( this.x );
			this.y = Math.floor( this.y );
			this.z = Math.floor( this.z );
			this.w = Math.floor( this.w );

			return this;

		},

		ceil: function () {

			this.x = Math.ceil( this.x );
			this.y = Math.ceil( this.y );
			this.z = Math.ceil( this.z );
			this.w = Math.ceil( this.w );

			return this;

		},

		round: function () {

			this.x = Math.round( this.x );
			this.y = Math.round( this.y );
			this.z = Math.round( this.z );
			this.w = Math.round( this.w );

			return this;

		},

		roundToZero: function () {

			this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
			this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
			this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );
			this.w = ( this.w < 0 ) ? Math.ceil( this.w ) : Math.floor( this.w );

			return this;

		},

		negate: function () {

			this.x = - this.x;
			this.y = - this.y;
			this.z = - this.z;
			this.w = - this.w;

			return this;

		},

		dot: function ( v ) {

			return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w;

		},

		lengthSq: function () {

			return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w;

		},

		length: function () {

			return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w );

		},

		lengthManhattan: function () {

			return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w );

		},

		normalize: function () {

			return this.divideScalar( this.length() );

		},

		setLength: function ( length ) {

			return this.multiplyScalar( length / this.length() );

		},

		lerp: function ( v, alpha ) {

			this.x += ( v.x - this.x ) * alpha;
			this.y += ( v.y - this.y ) * alpha;
			this.z += ( v.z - this.z ) * alpha;
			this.w += ( v.w - this.w ) * alpha;

			return this;

		},

		lerpVectors: function ( v1, v2, alpha ) {

			return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );

		},

		equals: function ( v ) {

			return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) );

		},

		fromArray: function ( array, offset ) {

			if ( offset === undefined ) offset = 0;

			this.x = array[ offset ];
			this.y = array[ offset + 1 ];
			this.z = array[ offset + 2 ];
			this.w = array[ offset + 3 ];

			return this;

		},

		toArray: function ( array, offset ) {

			if ( array === undefined ) array = [];
			if ( offset === undefined ) offset = 0;

			array[ offset ] = this.x;
			array[ offset + 1 ] = this.y;
			array[ offset + 2 ] = this.z;
			array[ offset + 3 ] = this.w;

			return array;

		},

		fromAttribute: function ( attribute, index, offset ) {

			if ( offset === undefined ) offset = 0;

			index = index * attribute.itemSize + offset;

			this.x = attribute.array[ index ];
			this.y = attribute.array[ index + 1 ];
			this.z = attribute.array[ index + 2 ];
			this.w = attribute.array[ index + 3 ];

			return this;

		}

	};

	// File:src/math/Euler.js

	/**
	 * @author mrdoob / http://mrdoob.com/
	 * @author WestLangley / http://github.com/WestLangley
	 * @author bhouston / http://clara.io
	 */

	THREE.Euler = function ( x, y, z, order ) {

		this._x = x || 0;
		this._y = y || 0;
		this._z = z || 0;
		this._order = order || THREE.Euler.DefaultOrder;

	};

	THREE.Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ];

	THREE.Euler.DefaultOrder = 'XYZ';

	THREE.Euler.prototype = {

		constructor: THREE.Euler,

		get x () {

			return this._x;

		},

		set x ( value ) {

			this._x = value;
			this.onChangeCallback();

		},

		get y () {

			return this._y;

		},

		set y ( value ) {

			this._y = value;
			this.onChangeCallback();

		},

		get z () {

			return this._z;

		},

		set z ( value ) {

			this._z = value;
			this.onChangeCallback();

		},

		get order () {

			return this._order;

		},

		set order ( value ) {

			this._order = value;
			this.onChangeCallback();

		},

		set: function ( x, y, z, order ) {

			this._x = x;
			this._y = y;
			this._z = z;
			this._order = order || this._order;

			this.onChangeCallback();

			return this;

		},

		clone: function () {

			return new this.constructor( this._x, this._y, this._z, this._order );

		},

		copy: function ( euler ) {

			this._x = euler._x;
			this._y = euler._y;
			this._z = euler._z;
			this._order = euler._order;

			this.onChangeCallback();

			return this;

		},

		setFromRotationMatrix: function ( m, order, update ) {

			var clamp = THREE.Math.clamp;

			// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)

			var te = m.elements;
			var m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ];
			var m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ];
			var m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];

			order = order || this._order;

			if ( order === 'XYZ' ) {

				this._y = Math.asin( clamp( m13, - 1, 1 ) );

				if ( Math.abs( m13 ) < 0.99999 ) {

					this._x = Math.atan2( - m23, m33 );
					this._z = Math.atan2( - m12, m11 );

				} else {

					this._x = Math.atan2( m32, m22 );
					this._z = 0;

				}

			} else if ( order === 'YXZ' ) {

				this._x = Math.asin( - clamp( m23, - 1, 1 ) );

				if ( Math.abs( m23 ) < 0.99999 ) {

					this._y = Math.atan2( m13, m33 );
					this._z = Math.atan2( m21, m22 );

				} else {

					this._y = Math.atan2( - m31, m11 );
					this._z = 0;

				}

			} else if ( order === 'ZXY' ) {

				this._x = Math.asin( clamp( m32, - 1, 1 ) );

				if ( Math.abs( m32 ) < 0.99999 ) {

					this._y = Math.atan2( - m31, m33 );
					this._z = Math.atan2( - m12, m22 );

				} else {

					this._y = 0;
					this._z = Math.atan2( m21, m11 );

				}

			} else if ( order === 'ZYX' ) {

				this._y = Math.asin( - clamp( m31, - 1, 1 ) );

				if ( Math.abs( m31 ) < 0.99999 ) {

					this._x = Math.atan2( m32, m33 );
					this._z = Math.atan2( m21, m11 );

				} else {

					this._x = 0;
					this._z = Math.atan2( - m12, m22 );

				}

			} else if ( order === 'YZX' ) {

				this._z = Math.asin( clamp( m21, - 1, 1 ) );

				if ( Math.abs( m21 ) < 0.99999 ) {

					this._x = Math.atan2( - m23, m22 );
					this._y = Math.atan2( - m31, m11 );

				} else {

					this._x = 0;
					this._y = Math.atan2( m13, m33 );

				}

			} else if ( order === 'XZY' ) {

				this._z = Math.asin( - clamp( m12, - 1, 1 ) );

				if ( Math.abs( m12 ) < 0.99999 ) {

					this._x = Math.atan2( m32, m22 );
					this._y = Math.atan2( m13, m11 );

				} else {

					this._x = Math.atan2( - m23, m33 );
					this._y = 0;

				}

			} else {

				console.warn( 'THREE.Euler: .setFromRotationMatrix() given unsupported order: ' + order );

			}

			this._order = order;

			if ( update !== false ) this.onChangeCallback();

			return this;

		},

		setFromQuaternion: function () {

			var matrix;

			return function setFromQuaternion( q, order, update ) {

				if ( matrix === undefined ) matrix = new THREE.Matrix4();

				matrix.makeRotationFromQuaternion( q );

				return this.setFromRotationMatrix( matrix, order, update );

			};

		}(),

		setFromVector3: function ( v, order ) {

			return this.set( v.x, v.y, v.z, order || this._order );

		},

		reorder: function () {

			// WARNING: this discards revolution information -bhouston

			var q = new THREE.Quaternion();

			return function reorder( newOrder ) {

				q.setFromEuler( this );
				
				return this.setFromQuaternion( q, newOrder );

			};

		}(),

		equals: function ( euler ) {

			return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order );

		},

		fromArray: function ( array ) {

			this._x = array[ 0 ];
			this._y = array[ 1 ];
			this._z = array[ 2 ];
			if ( array[ 3 ] !== undefined ) this._order = array[ 3 ];

			this.onChangeCallback();

			return this;

		},

		toArray: function ( array, offset ) {

			if ( array === undefined ) array = [];
			if ( offset === undefined ) offset = 0;

			array[ offset ] = this._x;
			array[ offset + 1 ] = this._y;
			array[ offset + 2 ] = this._z;
			array[ offset + 3 ] = this._order;

			return array;

		},

		toVector3: function ( optionalResult ) {

			if ( optionalResult ) {

				return optionalResult.set( this._x, this._y, this._z );

			} else {

				return new THREE.Vector3( this._x, this._y, this._z );

			}

		},

		onChange: function ( callback ) {

			this.onChangeCallback = callback;

			return this;

		},

		onChangeCallback: function () {}

	};

	// File:src/math/Line3.js

	/**
	 * @author bhouston / http://clara.io
	 */

	THREE.Line3 = function ( start, end ) {

		this.start = ( start !== undefined ) ? start : new THREE.Vector3();
		this.end = ( end !== undefined ) ? end : new THREE.Vector3();

	};

	THREE.Line3.prototype = {

		constructor: THREE.Line3,

		set: function ( start, end ) {

			this.start.copy( start );
			this.end.copy( end );

			return this;

		},

		clone: function () {

			return new this.constructor().copy( this );

		},

		copy: function ( line ) {

			this.start.copy( line.start );
			this.end.copy( line.end );

			return this;

		},

		center: function ( optionalTarget ) {

			var result = optionalTarget || new THREE.Vector3();
			return result.addVectors( this.start, this.end ).multiplyScalar( 0.5 );

		},

		delta: function ( optionalTarget ) {

			var result = optionalTarget || new THREE.Vector3();
			return result.subVectors( this.end, this.start );

		},

		distanceSq: function () {

			return this.start.distanceToSquared( this.end );

		},

		distance: function () {

			return this.start.distanceTo( this.end );

		},

		at: function ( t, optionalTarget ) {

			var result = optionalTarget || new THREE.Vector3();

			return this.delta( result ).multiplyScalar( t ).add( this.start );

		},

		closestPointToPointParameter: function () {

			var startP = new THREE.Vector3();
			var startEnd = new THREE.Vector3();

			return function closestPointToPointParameter( point, clampToLine ) {

				startP.subVectors( point, this.start );
				startEnd.subVectors( this.end, this.start );

				var startEnd2 = startEnd.dot( startEnd );
				var startEnd_startP = startEnd.dot( startP );

				var t = startEnd_startP / startEnd2;

				if ( clampToLine ) {

					t = THREE.Math.clamp( t, 0, 1 );

				}

				return t;

			};

		}(),

		closestPointToPoint: function ( point, clampToLine, optionalTarget ) {

			var t = this.closestPointToPointParameter( point, clampToLine );

			var result = optionalTarget || new THREE.Vector3();

			return this.delta( result ).multiplyScalar( t ).add( this.start );

		},

		applyMatrix4: function ( matrix ) {

			this.start.applyMatrix4( matrix );
			this.end.applyMatrix4( matrix );

			return this;

		},

		equals: function ( line ) {

			return line.start.equals( this.start ) && line.end.equals( this.end );

		}

	};

	// File:src/math/Box2.js

	/**
	 * @author bhouston / http://clara.io
	 */

	THREE.Box2 = function ( min, max ) {

		this.min = ( min !== undefined ) ? min : new THREE.Vector2( + Infinity, + Infinity );
		this.max = ( max !== undefined ) ? max : new THREE.Vector2( - Infinity, - Infinity );

	};

	THREE.Box2.prototype = {

		constructor: THREE.Box2,

		set: function ( min, max ) {

			this.min.copy( min );
			this.max.copy( max );

			return this;

		},

		setFromPoints: function ( points ) {

			this.makeEmpty();

			for ( var i = 0, il = points.length; i < il; i ++ ) {

				this.expandByPoint( points[ i ] );

			}

			return this;

		},

		setFromCenterAndSize: function () {

			var v1 = new THREE.Vector2();

			return function setFromCenterAndSize( center, size ) {

				var halfSize = v1.copy( size ).multiplyScalar( 0.5 );
				this.min.copy( center ).sub( halfSize );
				this.max.copy( center ).add( halfSize );

				return this;

			};

		}(),

		clone: function () {

			return new this.constructor().copy( this );

		},

		copy: function ( box ) {

			this.min.copy( box.min );
			this.max.copy( box.max );

			return this;

		},

		makeEmpty: function () {

			this.min.x = this.min.y = + Infinity;
			this.max.x = this.max.y = - Infinity;

			return this;

		},

		isEmpty: function () {

			// this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes

			return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y );

		},

		center: function ( optionalTarget ) {

			var result = optionalTarget || new THREE.Vector2();
			return result.addVectors( this.min, this.max ).multiplyScalar( 0.5 );

		},

		size: function ( optionalTarget ) {

			var result = optionalTarget || new THREE.Vector2();
			return result.subVectors( this.max, this.min );

		},

		expandByPoint: function ( point ) {

			this.min.min( point );
			this.max.max( point );

			return this;

		},

		expandByVector: function ( vector ) {

			this.min.sub( vector );
			this.max.add( vector );

			return this;

		},

		expandByScalar: function ( scalar ) {

			this.min.addScalar( - scalar );
			this.max.addScalar( scalar );

			return this;

		},

		containsPoint: function ( point ) {

			if ( point.x < this.min.x || point.x > this.max.x ||
			     point.y < this.min.y || point.y > this.max.y ) {

				return false;

			}

			return true;

		},

		containsBox: function ( box ) {

			if ( ( this.min.x <= box.min.x ) && ( box.max.x <= this.max.x ) &&
			     ( this.min.y <= box.min.y ) && ( box.max.y <= this.max.y ) ) {

				return true;

			}

			return false;

		},

		getParameter: function ( point, optionalTarget ) {

			// This can potentially have a divide by zero if the box
			// has a size dimension of 0.

			var result = optionalTarget || new THREE.Vector2();

			return result.set(
				( point.x - this.min.x ) / ( this.max.x - this.min.x ),
				( point.y - this.min.y ) / ( this.max.y - this.min.y )
			);

		},

		intersectsBox: function ( box ) {

			// using 6 splitting planes to rule out intersections.

			if ( box.max.x < this.min.x || box.min.x > this.max.x ||
			     box.max.y < this.min.y || box.min.y > this.max.y ) {

				return false;

			}

			return true;

		},

		clampPoint: function ( point, optionalTarget ) {

			var result = optionalTarget || new THREE.Vector2();
			return result.copy( point ).clamp( this.min, this.max );

		},

		distanceToPoint: function () {

			var v1 = new THREE.Vector2();

			return function distanceToPoint( point ) {

				var clampedPoint = v1.copy( point ).clamp( this.min, this.max );
				return clampedPoint.sub( point ).length();

			};

		}(),

		intersect: function ( box ) {

			this.min.max( box.min );
			this.max.min( box.max );

			return this;

		},

		union: function ( box ) {

			this.min.min( box.min );
			this.max.max( box.max );

			return this;

		},

		translate: function ( offset ) {

			this.min.add( offset );
			this.max.add( offset );

			return this;

		},

		equals: function ( box ) {

			return box.min.equals( this.min ) && box.max.equals( this.max );

		}

	};

	// File:src/math/Box3.js

	/**
	 * @author bhouston / http://clara.io
	 * @author WestLangley / http://github.com/WestLangley
	 */

	THREE.Box3 = function ( min, max ) {

		this.min = ( min !== undefined ) ? min : new THREE.Vector3( + Infinity, + Infinity, + Infinity );
		this.max = ( max !== undefined ) ? max : new THREE.Vector3( - Infinity, - Infinity, - Infinity );

	};

	THREE.Box3.prototype = {

		constructor: THREE.Box3,

		set: function ( min, max ) {

			this.min.copy( min );
			this.max.copy( max );

			return this;

		},

		setFromArray: function ( array ) {

			var minX = + Infinity;
			var minY = + Infinity;
			var minZ = + Infinity;

			var maxX = - Infinity;
			var maxY = - Infinity;
			var maxZ = - Infinity;

			for ( var i = 0, l = array.length; i < l; i += 3 ) {

				var x = array[ i ];
				var y = array[ i + 1 ];
				var z = array[ i + 2 ];

				if ( x < minX ) minX = x;
				if ( y < minY ) minY = y;
				if ( z < minZ ) minZ = z;

				if ( x > maxX ) maxX = x;
				if ( y > maxY ) maxY = y;
				if ( z > maxZ ) maxZ = z;

			}

			this.min.set( minX, minY, minZ );
			this.max.set( maxX, maxY, maxZ );

		},

		setFromPoints: function ( points ) {

			this.makeEmpty();

			for ( var i = 0, il = points.length; i < il; i ++ ) {

				this.expandByPoint( points[ i ] );

			}

			return this;

		},

		setFromCenterAndSize: function () {

			var v1 = new THREE.Vector3();

			return function setFromCenterAndSize( center, size ) {

				var halfSize = v1.copy( size ).multiplyScalar( 0.5 );

				this.min.copy( center ).sub( halfSize );
				this.max.copy( center ).add( halfSize );

				return this;

			};

		}(),

		setFromObject: function () {

			// Computes the world-axis-aligned bounding box of an object (including its children),
			// accounting for both the object's, and children's, world transforms

			var v1 = new THREE.Vector3();

			return function setFromObject( object ) {

				var scope = this;

				object.updateMatrixWorld( true );

				this.makeEmpty();

				object.traverse( function ( node ) {

					var geometry = node.geometry;

					if ( geometry !== undefined ) {

						if ( geometry instanceof THREE.Geometry ) {

							var vertices = geometry.vertices;

							for ( var i = 0, il = vertices.length; i < il; i ++ ) {

								v1.copy( vertices[ i ] );
								v1.applyMatrix4( node.matrixWorld );

								scope.expandByPoint( v1 );

							}

						} else if ( geometry instanceof THREE.BufferGeometry && geometry.attributes[ 'position' ] !== undefined ) {

							var positions = geometry.attributes[ 'position' ].array;

							for ( var i = 0, il = positions.length; i < il; i += 3 ) {

								v1.fromArray( positions, i );
								v1.applyMatrix4( node.matrixWorld );

								scope.expandByPoint( v1 );

							}

						}

					}

				} );

				return this;

			};

		}(),

		clone: function () {

			return new this.constructor().copy( this );

		},

		copy: function ( box ) {

			this.min.copy( box.min );
			this.max.copy( box.max );

			return this;

		},

		makeEmpty: function () {

			this.min.x = this.min.y = this.min.z = + Infinity;
			this.max.x = this.max.y = this.max.z = - Infinity;

			return this;

		},

		isEmpty: function () {

			// this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes

			return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z );

		},

		center: function ( optionalTarget ) {

			var result = optionalTarget || new THREE.Vector3();
			return result.addVectors( this.min, this.max ).multiplyScalar( 0.5 );

		},

		size: function ( optionalTarget ) {

			var result = optionalTarget || new THREE.Vector3();
			return result.subVectors( this.max, this.min );

		},

		expandByPoint: function ( point ) {

			this.min.min( point );
			this.max.max( point );

			return this;

		},

		expandByVector: function ( vector ) {

			this.min.sub( vector );
			this.max.add( vector );

			return this;

		},

		expandByScalar: function ( scalar ) {

			this.min.addScalar( - scalar );
			this.max.addScalar( scalar );

			return this;

		},

		containsPoint: function ( point ) {

			if ( point.x < this.min.x || point.x > this.max.x ||
					 point.y < this.min.y || point.y > this.max.y ||
					 point.z < this.min.z || point.z > this.max.z ) {

				return false;

			}

			return true;

		},

		containsBox: function ( box ) {

			if ( ( this.min.x <= box.min.x ) && ( box.max.x <= this.max.x ) &&
				 ( this.min.y <= box.min.y ) && ( box.max.y <= this.max.y ) &&
				 ( this.min.z <= box.min.z ) && ( box.max.z <= this.max.z ) ) {

				return true;

			}

			return false;

		},

		getParameter: function ( point, optionalTarget ) {

			// This can potentially have a divide by zero if the box
			// has a size dimension of 0.

			var result = optionalTarget || new THREE.Vector3();

			return result.set(
				( point.x - this.min.x ) / ( this.max.x - this.min.x ),
				( point.y - this.min.y ) / ( this.max.y - this.min.y ),
				( point.z - this.min.z ) / ( this.max.z - this.min.z )
			);

		},

		intersectsBox: function ( box ) {

			// using 6 splitting planes to rule out intersections.

			if ( box.max.x < this.min.x || box.min.x > this.max.x ||
					 box.max.y < this.min.y || box.min.y > this.max.y ||
					 box.max.z < this.min.z || box.min.z > this.max.z ) {

				return false;

			}

			return true;

		},

		intersectsSphere: ( function () {

			var closestPoint;

			return function intersectsSphere( sphere ) {

				if ( closestPoint === undefined ) closestPoint = new THREE.Vector3();

				// Find the point on the AABB closest to the sphere center.
				this.clampPoint( sphere.center, closestPoint );

				// If that point is inside the sphere, the AABB and sphere intersect.
				return closestPoint.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius );

			};

		} )(),

		intersectsPlane: function ( plane ) {

			// We compute the minimum and maximum dot product values. If those values
			// are on the same side (back or front) of the plane, then there is no intersection.

			var min, max;

			if ( plane.normal.x > 0 ) {

				min = plane.normal.x * this.min.x;
				max = plane.normal.x * this.max.x;

			} else {

				min = plane.normal.x * this.max.x;
				max = plane.normal.x * this.min.x;

			}

			if ( plane.normal.y > 0 ) {

				min += plane.normal.y * this.min.y;
				max += plane.normal.y * this.max.y;

			} else {

				min += plane.normal.y * this.max.y;
				max += plane.normal.y * this.min.y;

			}

			if ( plane.normal.z > 0 ) {

				min += plane.normal.z * this.min.z;
				max += plane.normal.z * this.max.z;

			} else {

				min += plane.normal.z * this.max.z;
				max += plane.normal.z * this.min.z;

			}

			return ( min <= plane.constant && max >= plane.constant );

		},

		clampPoint: function ( point, optionalTarget ) {

			var result = optionalTarget || new THREE.Vector3();
			return result.copy( point ).clamp( this.min, this.max );

		},

		distanceToPoint: function () {

			var v1 = new THREE.Vector3();

			return function distanceToPoint( point ) {

				var clampedPoint = v1.copy( point ).clamp( this.min, this.max );
				return clampedPoint.sub( point ).length();

			};

		}(),

		getBoundingSphere: function () {

			var v1 = new THREE.Vector3();

			return function getBoundingSphere( optionalTarget ) {

				var result = optionalTarget || new THREE.Sphere();

				result.center = this.center();
				result.radius = this.size( v1 ).length() * 0.5;

				return result;

			};

		}(),

		intersect: function ( box ) {

			this.min.max( box.min );
			this.max.min( box.max );

			// ensure that if there is no overlap, the result is fully empty, not slightly empty with non-inf/+inf values that will cause subsequence intersects to erroneously return valid values.
			if( this.isEmpty() ) this.makeEmpty();

			return this;

		},

		union: function ( box ) {

			this.min.min( box.min );
			this.max.max( box.max );

			return this;

		},

		applyMatrix4: function () {

			var points = [
				new THREE.Vector3(),
				new THREE.Vector3(),
				new THREE.Vector3(),
				new THREE.Vector3(),
				new THREE.Vector3(),
				new THREE.Vector3(),
				new THREE.Vector3(),
				new THREE.Vector3()
			];

			return function applyMatrix4( matrix ) {

				// transform of empty box is an empty box.
				if( this.isEmpty() ) return this;

				// NOTE: I am using a binary pattern to specify all 2^3 combinations below
				points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000
				points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001
				points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010
				points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011
				points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100
				points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101
				points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110
				points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix );	// 111

				this.setFromPoints( points );

				return this;

			};

		}(),

		translate: function ( offset ) {

			this.min.add( offset );
			this.max.add( offset );

			return this;

		},

		equals: function ( box ) {

			return box.min.equals( this.min ) && box.max.equals( this.max );

		}

	};

	// File:src/math/Matrix3.js

	/**
	 * @author alteredq / http://alteredqualia.com/
	 * @author WestLangley / http://github.com/WestLangley
	 * @author bhouston / http://clara.io
	 * @author tschw
	 */

	THREE.Matrix3 = function () {

		this.elements = new Float32Array( [

			1, 0, 0,
			0, 1, 0,
			0, 0, 1

		] );

		if ( arguments.length > 0 ) {

			console.error( 'THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.' );

		}

	};

	THREE.Matrix3.prototype = {

		constructor: THREE.Matrix3,

		set: function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {

			var te = this.elements;

			te[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31;
			te[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32;
			te[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33;

			return this;

		},

		identity: function () {

			this.set(

				1, 0, 0,
				0, 1, 0,
				0, 0, 1

			);

			return this;

		},

		clone: function () {

			return new this.constructor().fromArray( this.elements );

		},

		copy: function ( m ) {

			var me = m.elements;

			this.set(

				me[ 0 ], me[ 3 ], me[ 6 ],
				me[ 1 ], me[ 4 ], me[ 7 ],
				me[ 2 ], me[ 5 ], me[ 8 ]

			);

			return this;

		},

		setFromMatrix4: function( m ) {

			var me = m.elements;

			this.set(

				me[ 0 ], me[ 4 ], me[  8 ],
				me[ 1 ], me[ 5 ], me[  9 ],
				me[ 2 ], me[ 6 ], me[ 10 ]

			);

			return this;

		},

		applyToVector3Array: function () {

			var v1;

			return function applyToVector3Array( array, offset, length ) {

				if ( v1 === undefined ) v1 = new THREE.Vector3();
				if ( offset === undefined ) offset = 0;
				if ( length === undefined ) length = array.length;

				for ( var i = 0, j = offset; i < length; i += 3, j += 3 ) {

					v1.fromArray( array, j );
					v1.applyMatrix3( this );
					v1.toArray( array, j );

				}

				return array;

			};

		}(),

		applyToBuffer: function () {

			var v1;

			return function applyToBuffer( buffer, offset, length ) {

				if ( v1 === undefined ) v1 = new THREE.Vector3();
				if ( offset === undefined ) offset = 0;
				if ( length === undefined ) length = buffer.length / buffer.itemSize;

				for ( var i = 0, j = offset; i < length; i ++, j ++ ) {

					v1.x = buffer.getX( j );
					v1.y = buffer.getY( j );
					v1.z = buffer.getZ( j );

					v1.applyMatrix3( this );

					buffer.setXYZ( v1.x, v1.y, v1.z );

				}

				return buffer;

			};

		}(),

		multiplyScalar: function ( s ) {

			var te = this.elements;

			te[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s;
			te[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s;
			te[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s;

			return this;

		},

		determinant: function () {

			var te = this.elements;

			var a = te[ 0 ], b = te[ 1 ], c = te[ 2 ],
				d = te[ 3 ], e = te[ 4 ], f = te[ 5 ],
				g = te[ 6 ], h = te[ 7 ], i = te[ 8 ];

			return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g;

		},

		getInverse: function ( matrix, throwOnDegenerate ) {

			if ( matrix instanceof THREE.Matrix4 ) {

				console.error( "THREE.Matrix3.getInverse no longer takes a Matrix4 argument." );

			}

			var me = matrix.elements,
				te = this.elements,

				n11 = me[ 0 ], n21 = me[ 1 ], n31 = me[ 2 ],
				n12 = me[ 3 ], n22 = me[ 4 ], n32 = me[ 5 ],
				n13 = me[ 6 ], n23 = me[ 7 ], n33 = me[ 8 ],

				t11 = n33 * n22 - n32 * n23,
				t12 = n32 * n13 - n33 * n12,
				t13 = n23 * n12 - n22 * n13,

				det = n11 * t11 + n21 * t12 + n31 * t13;

			if ( det === 0 ) {

				var msg = "THREE.Matrix3.getInverse(): can't invert matrix, determinant is 0";

				if ( throwOnDegenerate || false ) {

					throw new Error( msg );

				} else {

					console.warn( msg );

				}

				return this.identity();
			}
			
			var detInv = 1 / det;

			te[ 0 ] = t11 * detInv;
			te[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv;
			te[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv;

			te[ 3 ] = t12 * detInv;
			te[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv;
			te[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv;

			te[ 6 ] = t13 * detInv;
			te[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv;
			te[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv;

			return this;

		},

		transpose: function () {

			var tmp, m = this.elements;

			tmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp;
			tmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp;
			tmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp;

			return this;

		},

		flattenToArrayOffset: function ( array, offset ) {

			console.warn( "THREE.Matrix3: .flattenToArrayOffset is deprecated " +
					"- just use .toArray instead." );

			return this.toArray( array, offset );

		},

		getNormalMatrix: function ( matrix4 ) {

			return this.setFromMatrix4( matrix4 ).getInverse( this ).transpose();

		},

		transposeIntoArray: function ( r ) {

			var m = this.elements;

			r[ 0 ] = m[ 0 ];
			r[ 1 ] = m[ 3 ];
			r[ 2 ] = m[ 6 ];
			r[ 3 ] = m[ 1 ];
			r[ 4 ] = m[ 4 ];
			r[ 5 ] = m[ 7 ];
			r[ 6 ] = m[ 2 ];
			r[ 7 ] = m[ 5 ];
			r[ 8 ] = m[ 8 ];

			return this;

		},

		fromArray: function ( array ) {

			this.elements.set( array );

			return this;

		},

		toArray: function ( array, offset ) {

			if ( array === undefined ) array = [];
			if ( offset === undefined ) offset = 0;

			var te = this.elements;

			array[ offset ] = te[ 0 ];
			array[ offset + 1 ] = te[ 1 ];
			array[ offset + 2 ] = te[ 2 ];

			array[ offset + 3 ] = te[ 3 ];
			array[ offset + 4 ] = te[ 4 ];
			array[ offset + 5 ] = te[ 5 ];

			array[ offset + 6 ] = te[ 6 ];
			array[ offset + 7 ] = te[ 7 ];
			array[ offset + 8 ]  = te[ 8 ];

			return array;

		}

	};

	// File:src/math/Matrix4.js

	/**
	 * @author mrdoob / http://mrdoob.com/
	 * @author supereggbert / http://www.paulbrunt.co.uk/
	 * @author philogb / http://blog.thejit.org/
	 * @author jordi_ros / http://plattsoft.com
	 * @author D1plo1d / http://github.com/D1plo1d
	 * @author alteredq / http://alteredqualia.com/
	 * @author mikael emtinger / http://gomo.se/
	 * @author timknip / http://www.floorplanner.com/
	 * @author bhouston / http://clara.io
	 * @author WestLangley / http://github.com/WestLangley
	 */

	THREE.Matrix4 = function () {

		this.elements = new Float32Array( [

			1, 0, 0, 0,
			0, 1, 0, 0,
			0, 0, 1, 0,
			0, 0, 0, 1

		] );

		if ( arguments.length > 0 ) {

			console.error( 'THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.' );

		}

	};

	THREE.Matrix4.prototype = {

		constructor: THREE.Matrix4,

		set: function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {

			var te = this.elements;

			te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14;
			te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24;
			te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34;
			te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44;

			return this;

		},

		identity: function () {

			this.set(

				1, 0, 0, 0,
				0, 1, 0, 0,
				0, 0, 1, 0,
				0, 0, 0, 1

			);

			return this;

		},

		clone: function () {

			return new THREE.Matrix4().fromArray( this.elements );

		},

		copy: function ( m ) {

			this.elements.set( m.elements );

			return this;

		},

		copyPosition: function ( m ) {

			var te = this.elements;
			var me = m.elements;

			te[ 12 ] = me[ 12 ];
			te[ 13 ] = me[ 13 ];
			te[ 14 ] = me[ 14 ];

			return this;

		},

		extractBasis: function ( xAxis, yAxis, zAxis ) {

			xAxis.setFromMatrixColumn( this, 0 );
			yAxis.setFromMatrixColumn( this, 1 );
			zAxis.setFromMatrixColumn( this, 2 );

			return this;

		},

		makeBasis: function ( xAxis, yAxis, zAxis ) {

			this.set(
				xAxis.x, yAxis.x, zAxis.x, 0,
				xAxis.y, yAxis.y, zAxis.y, 0,
				xAxis.z, yAxis.z, zAxis.z, 0,
				0,       0,       0,       1
			);

			return this;

		},

		extractRotation: function () {

			var v1;

			return function extractRotation( m ) {

				if ( v1 === undefined ) v1 = new THREE.Vector3();

				var te = this.elements;
				var me = m.elements;

				var scaleX = 1 / v1.setFromMatrixColumn( m, 0 ).length();
				var scaleY = 1 / v1.setFromMatrixColumn( m, 1 ).length();
				var scaleZ = 1 / v1.setFromMatrixColumn( m, 2 ).length();

				te[ 0 ] = me[ 0 ] * scaleX;
				te[ 1 ] = me[ 1 ] * scaleX;
				te[ 2 ] = me[ 2 ] * scaleX;

				te[ 4 ] = me[ 4 ] * scaleY;
				te[ 5 ] = me[ 5 ] * scaleY;
				te[ 6 ] = me[ 6 ] * scaleY;

				te[ 8 ] = me[ 8 ] * scaleZ;
				te[ 9 ] = me[ 9 ] * scaleZ;
				te[ 10 ] = me[ 10 ] * scaleZ;

				return this;

			};

		}(),

		makeRotationFromEuler: function ( euler ) {

			if ( euler instanceof THREE.Euler === false ) {

				console.error( 'THREE.Matrix: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.' );

			}

			var te = this.elements;

			var x = euler.x, y = euler.y, z = euler.z;
			var a = Math.cos( x ), b = Math.sin( x );
			var c = Math.cos( y ), d = Math.sin( y );
			var e = Math.cos( z ), f = Math.sin( z );

			if ( euler.order === 'XYZ' ) {

				var ae = a * e, af = a * f, be = b * e, bf = b * f;

				te[ 0 ] = c * e;
				te[ 4 ] = - c * f;
				te[ 8 ] = d;

				te[ 1 ] = af + be * d;
				te[ 5 ] = ae - bf * d;
				te[ 9 ] = - b * c;

				te[ 2 ] = bf - ae * d;
				te[ 6 ] = be + af * d;
				te[ 10 ] = a * c;

			} else if ( euler.order === 'YXZ' ) {

				var ce = c * e, cf = c * f, de = d * e, df = d * f;

				te[ 0 ] = ce + df * b;
				te[ 4 ] = de * b - cf;
				te[ 8 ] = a * d;

				te[ 1 ] = a * f;
				te[ 5 ] = a * e;
				te[ 9 ] = - b;

				te[ 2 ] = cf * b - de;
				te[ 6 ] = df + ce * b;
				te[ 10 ] = a * c;

			} else if ( euler.order === 'ZXY' ) {

				var ce = c * e, cf = c * f, de = d * e, df = d * f;

				te[ 0 ] = ce - df * b;
				te[ 4 ] = - a * f;
				te[ 8 ] = de + cf * b;

				te[ 1 ] = cf + de * b;
				te[ 5 ] = a * e;
				te[ 9 ] = df - ce * b;

				te[ 2 ] = - a * d;
				te[ 6 ] = b;
				te[ 10 ] = a * c;

			} else if ( euler.order === 'ZYX' ) {

				var ae = a * e, af = a * f, be = b * e, bf = b * f;

				te[ 0 ] = c * e;
				te[ 4 ] = be * d - af;
				te[ 8 ] = ae * d + bf;

				te[ 1 ] = c * f;
				te[ 5 ] = bf * d + ae;
				te[ 9 ] = af * d - be;

				te[ 2 ] = - d;
				te[ 6 ] = b * c;
				te[ 10 ] = a * c;

			} else if ( euler.order === 'YZX' ) {

				var ac = a * c, ad = a * d, bc = b * c, bd = b * d;

				te[ 0 ] = c * e;
				te[ 4 ] = bd - ac * f;
				te[ 8 ] = bc * f + ad;

				te[ 1 ] = f;
				te[ 5 ] = a * e;
				te[ 9 ] = - b * e;

				te[ 2 ] = - d * e;
				te[ 6 ] = ad * f + bc;
				te[ 10 ] = ac - bd * f;

			} else if ( euler.order === 'XZY' ) {

				var ac = a * c, ad = a * d, bc = b * c, bd = b * d;

				te[ 0 ] = c * e;
				te[ 4 ] = - f;
				te[ 8 ] = d * e;

				te[ 1 ] = ac * f + bd;
				te[ 5 ] = a * e;
				te[ 9 ] = ad * f - bc;

				te[ 2 ] = bc * f - ad;
				te[ 6 ] = b * e;
				te[ 10 ] = bd * f + ac;

			}

			// last column
			te[ 3 ] = 0;
			te[ 7 ] = 0;
			te[ 11 ] = 0;

			// bottom row
			te[ 12 ] = 0;
			te[ 13 ] = 0;
			te[ 14 ] = 0;
			te[ 15 ] = 1;

			return this;

		},

		makeRotationFromQuaternion: function ( q ) {

			var te = this.elements;

			var x = q.x, y = q.y, z = q.z, w = q.w;
			var x2 = x + x, y2 = y + y, z2 = z + z;
			var xx = x * x2, xy = x * y2, xz = x * z2;
			var yy = y * y2, yz = y * z2, zz = z * z2;
			var wx = w * x2, wy = w * y2, wz = w * z2;

			te[ 0 ] = 1 - ( yy + zz );
			te[ 4 ] = xy - wz;
			te[ 8 ] = xz + wy;

			te[ 1 ] = xy + wz;
			te[ 5 ] = 1 - ( xx + zz );
			te[ 9 ] = yz - wx;

			te[ 2 ] = xz - wy;
			te[ 6 ] = yz + wx;
			te[ 10 ] = 1 - ( xx + yy );

			// last column
			te[ 3 ] = 0;
			te[ 7 ] = 0;
			te[ 11 ] = 0;

			// bottom row
			te[ 12 ] = 0;
			te[ 13 ] = 0;
			te[ 14 ] = 0;
			te[ 15 ] = 1;

			return this;

		},

		lookAt: function () {

			var x, y, z;

			return function lookAt( eye, target, up ) {

				if ( x === undefined ) {

					x = new THREE.Vector3();
					y = new THREE.Vector3();
					z = new THREE.Vector3();

				}

				var te = this.elements;

				z.subVectors( eye, target ).normalize();

				if ( z.lengthSq() === 0 ) {

					z.z = 1;

				}

				x.crossVectors( up, z ).normalize();

				if ( x.lengthSq() === 0 ) {

					z.z += 0.0001;
					x.crossVectors( up, z ).normalize();

				}

				y.crossVectors( z, x );


				te[ 0 ] = x.x; te[ 4 ] = y.x; te[ 8 ] = z.x;
				te[ 1 ] = x.y; te[ 5 ] = y.y; te[ 9 ] = z.y;
				te[ 2 ] = x.z; te[ 6 ] = y.z; te[ 10 ] = z.z;

				return this;

			};

		}(),

		multiply: function ( m, n ) {

			if ( n !== undefined ) {

				console.warn( 'THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' );
				return this.multiplyMatrices( m, n );

			}

			return this.multiplyMatrices( this, m );

		},

		premultiply: function ( m ) {

			return this.multiplyMatrices( m, this );

		},

		multiplyMatrices: function ( a, b ) {

			var ae = a.elements;
			var be = b.elements;
			var te = this.elements;

			var a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ];
			var a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ];
			var a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ];
			var a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ];

			var b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ];
			var b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ];
			var b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ];
			var b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ];

			te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;
			te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;
			te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;
			te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;

			te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;
			te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;
			te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;
			te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;

			te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;
			te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;
			te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;
			te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;

			te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;
			te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;
			te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;
			te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;

			return this;

		},

		multiplyToArray: function ( a, b, r ) {

			var te = this.elements;

			this.multiplyMatrices( a, b );

			r[ 0 ] = te[ 0 ]; r[ 1 ] = te[ 1 ]; r[ 2 ] = te[ 2 ]; r[ 3 ] = te[ 3 ];
			r[ 4 ] = te[ 4 ]; r[ 5 ] = te[ 5 ]; r[ 6 ] = te[ 6 ]; r[ 7 ] = te[ 7 ];
			r[ 8 ]  = te[ 8 ]; r[ 9 ]  = te[ 9 ]; r[ 10 ] = te[ 10 ]; r[ 11 ] = te[ 11 ];
			r[ 12 ] = te[ 12 ]; r[ 13 ] = te[ 13 ]; r[ 14 ] = te[ 14 ]; r[ 15 ] = te[ 15 ];

			return this;

		},

		multiplyScalar: function ( s ) {

			var te = this.elements;

			te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s;
			te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s;
			te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s;
			te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s;

			return this;

		},

		applyToVector3Array: function () {

			var v1;

			return function applyToVector3Array( array, offset, length ) {

				if ( v1 === undefined ) v1 = new THREE.Vector3();
				if ( offset === undefined ) offset = 0;
				if ( length === undefined ) length = array.length;

				for ( var i = 0, j = offset; i < length; i += 3, j += 3 ) {

					v1.fromArray( array, j );
					v1.applyMatrix4( this );
					v1.toArray( array, j );

				}

				return array;

			};

		}(),

		applyToBuffer: function () {

			var v1;

			return function applyToBuffer( buffer, offset, length ) {

				if ( v1 === undefined ) v1 = new THREE.Vector3();
				if ( offset === undefined ) offset = 0;
				if ( length === undefined ) length = buffer.length / buffer.itemSize;

				for ( var i = 0, j = offset; i < length; i ++, j ++ ) {

					v1.x = buffer.getX( j );
					v1.y = buffer.getY( j );
					v1.z = buffer.getZ( j );

					v1.applyMatrix4( this );

					buffer.setXYZ( v1.x, v1.y, v1.z );

				}

				return buffer;

			};

		}(),

		determinant: function () {

			var te = this.elements;

			var n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ];
			var n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ];
			var n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ];
			var n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ];

			//TODO: make this more efficient
			//( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm )

			return (
				n41 * (
					+ n14 * n23 * n32
					 - n13 * n24 * n32
					 - n14 * n22 * n33
					 + n12 * n24 * n33
					 + n13 * n22 * n34
					 - n12 * n23 * n34
				) +
				n42 * (
					+ n11 * n23 * n34
					 - n11 * n24 * n33
					 + n14 * n21 * n33
					 - n13 * n21 * n34
					 + n13 * n24 * n31
					 - n14 * n23 * n31
				) +
				n43 * (
					+ n11 * n24 * n32
					 - n11 * n22 * n34
					 - n14 * n21 * n32
					 + n12 * n21 * n34
					 + n14 * n22 * n31
					 - n12 * n24 * n31
				) +
				n44 * (
					- n13 * n22 * n31
					 - n11 * n23 * n32
					 + n11 * n22 * n33
					 + n13 * n21 * n32
					 - n12 * n21 * n33
					 + n12 * n23 * n31
				)

			);

		},

		transpose: function () {

			var te = this.elements;
			var tmp;

			tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp;
			tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp;
			tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp;

			tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp;
			tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp;
			tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp;

			return this;

		},

		flattenToArrayOffset: function ( array, offset ) {

			console.warn( "THREE.Matrix3: .flattenToArrayOffset is deprecated " +
					"- just use .toArray instead." );

			return this.toArray( array, offset );

		},

		getPosition: function () {

			var v1;

			return function getPosition() {

				if ( v1 === undefined ) v1 = new THREE.Vector3();
				console.warn( 'THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' );

				return v1.setFromMatrixColumn( this, 3 );

			};

		}(),

		setPosition: function ( v ) {

			var te = this.elements;

			te[ 12 ] = v.x;
			te[ 13 ] = v.y;
			te[ 14 ] = v.z;

			return this;

		},

		getInverse: function ( m, throwOnDegenerate ) {

			// based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm
			var te = this.elements,
				me = m.elements,

				n11 = me[ 0 ], n21 = me[ 1 ], n31 = me[ 2 ], n41 = me[ 3 ],
				n12 = me[ 4 ], n22 = me[ 5 ], n32 = me[ 6 ], n42 = me[ 7 ],
				n13 = me[ 8 ], n23 = me[ 9 ], n33 = me[ 10 ], n43 = me[ 11 ],
				n14 = me[ 12 ], n24 = me[ 13 ], n34 = me[ 14 ], n44 = me[ 15 ],

				t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44,
				t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44,
				t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44,
				t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34;

			var det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14;

			if ( det === 0 ) {

				var msg = "THREE.Matrix4.getInverse(): can't invert matrix, determinant is 0";

				if ( throwOnDegenerate || false ) {

					throw new Error( msg );

				} else {

					console.warn( msg );

				}

				return this.identity();

			}
			
			var detInv = 1 / det;

			te[ 0 ] = t11 * detInv;
			te[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv;
			te[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv;
			te[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv;

			te[ 4 ] = t12 * detInv;
			te[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv;
			te[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv;
			te[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv;

			te[ 8 ] = t13 * detInv;
			te[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv;
			te[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv;
			te[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv;

			te[ 12 ] = t14 * detInv;
			te[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv;
			te[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv;
			te[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv;

			return this;

		},

		scale: function ( v ) {

			var te = this.elements;
			var x = v.x, y = v.y, z = v.z;

			te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z;
			te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z;
			te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z;
			te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z;

			return this;

		},

		getMaxScaleOnAxis: function () {

			var te = this.elements;

			var scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ];
			var scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ];
			var scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ];

			return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) );

		},

		makeTranslation: function ( x, y, z ) {

			this.set(

				1, 0, 0, x,
				0, 1, 0, y,
				0, 0, 1, z,
				0, 0, 0, 1

			);

			return this;

		},

		makeRotationX: function ( theta ) {

			var c = Math.cos( theta ), s = Math.sin( theta );

			this.set(

				1, 0,  0, 0,
				0, c, - s, 0,
				0, s,  c, 0,
				0, 0,  0, 1

			);

			return this;

		},

		makeRotationY: function ( theta ) {

			var c = Math.cos( theta ), s = Math.sin( theta );

			this.set(

				 c, 0, s, 0,
				 0, 1, 0, 0,
				- s, 0, c, 0,
				 0, 0, 0, 1

			);

			return this;

		},

		makeRotationZ: function ( theta ) {

			var c = Math.cos( theta ), s = Math.sin( theta );

			this.set(

				c, - s, 0, 0,
				s,  c, 0, 0,
				0,  0, 1, 0,
				0,  0, 0, 1

			);

			return this;

		},

		makeRotationAxis: function ( axis, angle ) {

			// Based on http://www.gamedev.net/reference/articles/article1199.asp

			var c = Math.cos( angle );
			var s = Math.sin( angle );
			var t = 1 - c;
			var x = axis.x, y = axis.y, z = axis.z;
			var tx = t * x, ty = t * y;

			this.set(

				tx * x + c, tx * y - s * z, tx * z + s * y, 0,
				tx * y + s * z, ty * y + c, ty * z - s * x, 0,
				tx * z - s * y, ty * z + s * x, t * z * z + c, 0,
				0, 0, 0, 1

			);

			 return this;

		},

		makeScale: function ( x, y, z ) {

			this.set(

				x, 0, 0, 0,
				0, y, 0, 0,
				0, 0, z, 0,
				0, 0, 0, 1

			);

			return this;

		},

		compose: function ( position, quaternion, scale ) {

			this.makeRotationFromQuaternion( quaternion );
			this.scale( scale );
			this.setPosition( position );

			return this;

		},

		decompose: function () {

			var vector, matrix;

			return function decompose( position, quaternion, scale ) {

				if ( vector === undefined ) {

					vector = new THREE.Vector3();
					matrix = new THREE.Matrix4();

				}

				var te = this.elements;

				var sx = vector.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length();
				var sy = vector.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length();
				var sz = vector.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length();

				// if determine is negative, we need to invert one scale
				var det = this.determinant();
				if ( det < 0 ) {

					sx = - sx;

				}

				position.x = te[ 12 ];
				position.y = te[ 13 ];
				position.z = te[ 14 ];

				// scale the rotation part

				matrix.elements.set( this.elements ); // at this point matrix is incomplete so we can't use .copy()

				var invSX = 1 / sx;
				var invSY = 1 / sy;
				var invSZ = 1 / sz;

				matrix.elements[ 0 ] *= invSX;
				matrix.elements[ 1 ] *= invSX;
				matrix.elements[ 2 ] *= invSX;

				matrix.elements[ 4 ] *= invSY;
				matrix.elements[ 5 ] *= invSY;
				matrix.elements[ 6 ] *= invSY;

				matrix.elements[ 8 ] *= invSZ;
				matrix.elements[ 9 ] *= invSZ;
				matrix.elements[ 10 ] *= invSZ;

				quaternion.setFromRotationMatrix( matrix );

				scale.x = sx;
				scale.y = sy;
				scale.z = sz;

				return this;

			};

		}(),

		makeFrustum: function ( left, right, bottom, top, near, far ) {

			var te = this.elements;
			var x = 2 * near / ( right - left );
			var y = 2 * near / ( top - bottom );

			var a = ( right + left ) / ( right - left );
			var b = ( top + bottom ) / ( top - bottom );
			var c = - ( far + near ) / ( far - near );
			var d = - 2 * far * near / ( far - near );

			te[ 0 ] = x;	te[ 4 ] = 0;	te[ 8 ] = a;	te[ 12 ] = 0;
			te[ 1 ] = 0;	te[ 5 ] = y;	te[ 9 ] = b;	te[ 13 ] = 0;
			te[ 2 ] = 0;	te[ 6 ] = 0;	te[ 10 ] = c;	te[ 14 ] = d;
			te[ 3 ] = 0;	te[ 7 ] = 0;	te[ 11 ] = - 1;	te[ 15 ] = 0;

			return this;

		},

		makePerspective: function ( fov, aspect, near, far ) {

			var ymax = near * Math.tan( THREE.Math.DEG2RAD * fov * 0.5 );
			var ymin = - ymax;
			var xmin = ymin * aspect;
			var xmax = ymax * aspect;

			return this.makeFrustum( xmin, xmax, ymin, ymax, near, far );

		},

		makeOrthographic: function ( left, right, top, bottom, near, far ) {

			var te = this.elements;
			var w = 1.0 / ( right - left );
			var h = 1.0 / ( top - bottom );
			var p = 1.0 / ( far - near );

			var x = ( right + left ) * w;
			var y = ( top + bottom ) * h;
			var z = ( far + near ) * p;

			te[ 0 ] = 2 * w;	te[ 4 ] = 0;	te[ 8 ] = 0;	te[ 12 ] = - x;
			te[ 1 ] = 0;	te[ 5 ] = 2 * h;	te[ 9 ] = 0;	te[ 13 ] = - y;
			te[ 2 ] = 0;	te[ 6 ] = 0;	te[ 10 ] = - 2 * p;	te[ 14 ] = - z;
			te[ 3 ] = 0;	te[ 7 ] = 0;	te[ 11 ] = 0;	te[ 15 ] = 1;

			return this;

		},

		equals: function ( matrix ) {

			var te = this.elements;
			var me = matrix.elements;

			for ( var i = 0; i < 16; i ++ ) {

				if ( te[ i ] !== me[ i ] ) return false;

			}

			return true;

		},

		fromArray: function ( array ) {

			this.elements.set( array );

			return this;

		},

		toArray: function ( array, offset ) {

			if ( array === undefined ) array = [];
			if ( offset === undefined ) offset = 0;

			var te = this.elements;

			array[ offset ] = te[ 0 ];
			array[ offset + 1 ] = te[ 1 ];
			array[ offset + 2 ] = te[ 2 ];
			array[ offset + 3 ] = te[ 3 ];

			array[ offset + 4 ] = te[ 4 ];
			array[ offset + 5 ] = te[ 5 ];
			array[ offset + 6 ] = te[ 6 ];
			array[ offset + 7 ] = te[ 7 ];

			array[ offset + 8 ]  = te[ 8 ];
			array[ offset + 9 ]  = te[ 9 ];
			array[ offset + 10 ] = te[ 10 ];
			array[ offset + 11 ] = te[ 11 ];

			array[ offset + 12 ] = te[ 12 ];
			array[ offset + 13 ] = te[ 13 ];
			array[ offset + 14 ] = te[ 14 ];
			array[ offset + 15 ] = te[ 15 ];

			return array;

		}

	};

	// File:src/math/Ray.js

	/**
	 * @author bhouston / http://clara.io
	 */

	THREE.Ray = function ( origin, direction ) {

		this.origin = ( origin !== undefined ) ? origin : new THREE.Vector3();
		this.direction = ( direction !== undefined ) ? direction : new THREE.Vector3();

	};

	THREE.Ray.prototype = {

		constructor: THREE.Ray,

		set: function ( origin, direction ) {

			this.origin.copy( origin );
			this.direction.copy( direction );

			return this;

		},

		clone: function () {

			return new this.constructor().copy( this );

		},

		copy: function ( ray ) {

			this.origin.copy( ray.origin );
			this.direction.copy( ray.direction );

			return this;

		},

		at: function ( t, optionalTarget ) {

			var result = optionalTarget || new THREE.Vector3();

			return result.copy( this.direction ).multiplyScalar( t ).add( this.origin );

		},

		lookAt: function ( v ) {

			this.direction.copy( v ).sub( this.origin ).normalize();

			return this;

		},

		recast: function () {

			var v1 = new THREE.Vector3();

			return function recast( t ) {

				this.origin.copy( this.at( t, v1 ) );

				return this;

			};

		}(),

		closestPointToPoint: function ( point, optionalTarget ) {

			var result = optionalTarget || new THREE.Vector3();
			result.subVectors( point, this.origin );
			var directionDistance = result.dot( this.direction );

			if ( directionDistance < 0 ) {

				return result.copy( this.origin );

			}

			return result.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );

		},

		distanceToPoint: function ( point ) {

			return Math.sqrt( this.distanceSqToPoint( point ) );

		},

		distanceSqToPoint: function () {

			var v1 = new THREE.Vector3();

			return function distanceSqToPoint( point ) {

				var directionDistance = v1.subVectors( point, this.origin ).dot( this.direction );

				// point behind the ray

				if ( directionDistance < 0 ) {

					return this.origin.distanceToSquared( point );

				}

				v1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );

				return v1.distanceToSquared( point );

			};

		}(),

		distanceSqToSegment: function () {

			var segCenter = new THREE.Vector3();
			var segDir = new THREE.Vector3();
			var diff = new THREE.Vector3();

			return function distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) {

				// from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteDistRaySegment.h
				// It returns the min distance between the ray and the segment
				// defined by v0 and v1
				// It can also set two optional targets :
				// - The closest point on the ray
				// - The closest point on the segment

				segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 );
				segDir.copy( v1 ).sub( v0 ).normalize();
				diff.copy( this.origin ).sub( segCenter );

				var segExtent = v0.distanceTo( v1 ) * 0.5;
				var a01 = - this.direction.dot( segDir );
				var b0 = diff.dot( this.direction );
				var b1 = - diff.dot( segDir );
				var c = diff.lengthSq();
				var det = Math.abs( 1 - a01 * a01 );
				var s0, s1, sqrDist, extDet;

				if ( det > 0 ) {

					// The ray and segment are not parallel.

					s0 = a01 * b1 - b0;
					s1 = a01 * b0 - b1;
					extDet = segExtent * det;

					if ( s0 >= 0 ) {

						if ( s1 >= - extDet ) {

							if ( s1 <= extDet ) {

								// region 0
								// Minimum at interior points of ray and segment.

								var invDet = 1 / det;
								s0 *= invDet;
								s1 *= invDet;
								sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c;

							} else {

								// region 1

								s1 = segExtent;
								s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
								sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;

							}

						} else {

							// region 5

							s1 = - segExtent;
							s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
							sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;

						}

					} else {

						if ( s1 <= - extDet ) {

							// region 4

							s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) );
							s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
							sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;

						} else if ( s1 <= extDet ) {

							// region 3

							s0 = 0;
							s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent );
							sqrDist = s1 * ( s1 + 2 * b1 ) + c;

						} else {

							// region 2

							s0 = Math.max( 0, - ( a01 * segExtent + b0 ) );
							s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
							sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;

						}

					}

				} else {

					// Ray and segment are parallel.

					s1 = ( a01 > 0 ) ? - segExtent : segExtent;
					s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
					sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;

				}

				if ( optionalPointOnRay ) {

					optionalPointOnRay.copy( this.direction ).multiplyScalar( s0 ).add( this.origin );

				}

				if ( optionalPointOnSegment ) {

					optionalPointOnSegment.copy( segDir ).multiplyScalar( s1 ).add( segCenter );

				}

				return sqrDist;

			};

		}(),

		intersectSphere: function () {

			var v1 = new THREE.Vector3();

			return function intersectSphere( sphere, optionalTarget ) {

				v1.subVectors( sphere.center, this.origin );
				var tca = v1.dot( this.direction );
				var d2 = v1.dot( v1 ) - tca * tca;
				var radius2 = sphere.radius * sphere.radius;

				if ( d2 > radius2 ) return null;

				var thc = Math.sqrt( radius2 - d2 );

				// t0 = first intersect point - entrance on front of sphere
				var t0 = tca - thc;

				// t1 = second intersect point - exit point on back of sphere
				var t1 = tca + thc;

				// test to see if both t0 and t1 are behind the ray - if so, return null
				if ( t0 < 0 && t1 < 0 ) return null;

				// test to see if t0 is behind the ray:
				// if it is, the ray is inside the sphere, so return the second exit point scaled by t1,
				// in order to always return an intersect point that is in front of the ray.
				if ( t0 < 0 ) return this.at( t1, optionalTarget );

				// else t0 is in front of the ray, so return the first collision point scaled by t0
				return this.at( t0, optionalTarget );

			};

		}(),

		intersectsSphere: function ( sphere ) {

			return this.distanceToPoint( sphere.center ) <= sphere.radius;

		},

		distanceToPlane: function ( plane ) {

			var denominator = plane.normal.dot( this.direction );

			if ( denominator === 0 ) {

				// line is coplanar, return origin
				if ( plane.distanceToPoint( this.origin ) === 0 ) {

					return 0;

				}

				// Null is preferable to undefined since undefined means.... it is undefined

				return null;

			}

			var t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator;

			// Return if the ray never intersects the plane

			return t >= 0 ? t :  null;

		},

		intersectPlane: function ( plane, optionalTarget ) {

			var t = this.distanceToPlane( plane );

			if ( t === null ) {

				return null;

			}

			return this.at( t, optionalTarget );

		},



		intersectsPlane: function ( plane ) {

			// check if the ray lies on the plane first

			var distToPoint = plane.distanceToPoint( this.origin );

			if ( distToPoint === 0 ) {

				return true;

			}

			var denominator = plane.normal.dot( this.direction );

			if ( denominator * distToPoint < 0 ) {

				return true;

			}

			// ray origin is behind the plane (and is pointing behind it)

			return false;

		},

		intersectBox: function ( box, optionalTarget ) {

			var tmin, tmax, tymin, tymax, tzmin, tzmax;

			var invdirx = 1 / this.direction.x,
				invdiry = 1 / this.direction.y,
				invdirz = 1 / this.direction.z;

			var origin = this.origin;

			if ( invdirx >= 0 ) {

				tmin = ( box.min.x - origin.x ) * invdirx;
				tmax = ( box.max.x - origin.x ) * invdirx;

			} else {

				tmin = ( box.max.x - origin.x ) * invdirx;
				tmax = ( box.min.x - origin.x ) * invdirx;

			}

			if ( invdiry >= 0 ) {

				tymin = ( box.min.y - origin.y ) * invdiry;
				tymax = ( box.max.y - origin.y ) * invdiry;

			} else {

				tymin = ( box.max.y - origin.y ) * invdiry;
				tymax = ( box.min.y - origin.y ) * invdiry;

			}

			if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null;

			// These lines also handle the case where tmin or tmax is NaN
			// (result of 0 * Infinity). x !== x returns true if x is NaN

			if ( tymin > tmin || tmin !== tmin ) tmin = tymin;

			if ( tymax < tmax || tmax !== tmax ) tmax = tymax;

			if ( invdirz >= 0 ) {

				tzmin = ( box.min.z - origin.z ) * invdirz;
				tzmax = ( box.max.z - origin.z ) * invdirz;

			} else {

				tzmin = ( box.max.z - origin.z ) * invdirz;
				tzmax = ( box.min.z - origin.z ) * invdirz;

			}

			if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null;

			if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin;

			if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax;

			//return point closest to the ray (positive side)

			if ( tmax < 0 ) return null;

			return this.at( tmin >= 0 ? tmin : tmax, optionalTarget );

		},

		intersectsBox: ( function () {

			var v = new THREE.Vector3();

			return function intersectsBox( box ) {

				return this.intersectBox( box, v ) !== null;

			};

		} )(),

		intersectTriangle: function () {

			// Compute the offset origin, edges, and normal.
			var diff = new THREE.Vector3();
			var edge1 = new THREE.Vector3();
			var edge2 = new THREE.Vector3();
			var normal = new THREE.Vector3();

			return function intersectTriangle( a, b, c, backfaceCulling, optionalTarget ) {

				// from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h

				edge1.subVectors( b, a );
				edge2.subVectors( c, a );
				normal.crossVectors( edge1, edge2 );

				// Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,
				// E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by
				//   |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))
				//   |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))
				//   |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)
				var DdN = this.direction.dot( normal );
				var sign;

				if ( DdN > 0 ) {

					if ( backfaceCulling ) return null;
					sign = 1;

				} else if ( DdN < 0 ) {

					sign = - 1;
					DdN = - DdN;

				} else {

					return null;

				}

				diff.subVectors( this.origin, a );
				var DdQxE2 = sign * this.direction.dot( edge2.crossVectors( diff, edge2 ) );

				// b1 < 0, no intersection
				if ( DdQxE2 < 0 ) {

					return null;

				}

				var DdE1xQ = sign * this.direction.dot( edge1.cross( diff ) );

				// b2 < 0, no intersection
				if ( DdE1xQ < 0 ) {

					return null;

				}

				// b1+b2 > 1, no intersection
				if ( DdQxE2 + DdE1xQ > DdN ) {

					return null;

				}

				// Line intersects triangle, check if ray does.
				var QdN = - sign * diff.dot( normal );

				// t < 0, no intersection
				if ( QdN < 0 ) {

					return null;

				}

				// Ray intersects triangle.
				return this.at( QdN / DdN, optionalTarget );

			};

		}(),

		applyMatrix4: function ( matrix4 ) {

			this.direction.add( this.origin ).applyMatrix4( matrix4 );
			this.origin.applyMatrix4( matrix4 );
			this.direction.sub( this.origin );
			this.direction.normalize();

			return this;

		},

		equals: function ( ray ) {

			return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction );

		}

	};

	// File:src/math/Sphere.js

	/**
	 * @author bhouston / http://clara.io
	 * @author mrdoob / http://mrdoob.com/
	 */

	THREE.Sphere = function ( center, radius ) {

		this.center = ( center !== undefined ) ? center : new THREE.Vector3();
		this.radius = ( radius !== undefined ) ? radius : 0;

	};

	THREE.Sphere.prototype = {

		constructor: THREE.Sphere,

		set: function ( center, radius ) {

			this.center.copy( center );
			this.radius = radius;

			return this;

		},

		setFromPoints: function () {

			var box = new THREE.Box3();

			return function setFromPoints( points, optionalCenter ) {

				var center = this.center;

				if ( optionalCenter !== undefined ) {

					center.copy( optionalCenter );

				} else {

					box.setFromPoints( points ).center( center );

				}

				var maxRadiusSq = 0;

				for ( var i = 0, il = points.length; i < il; i ++ ) {

					maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) );

				}

				this.radius = Math.sqrt( maxRadiusSq );

				return this;

			};

		}(),

		clone: function () {

			return new this.constructor().copy( this );

		},

		copy: function ( sphere ) {

			this.center.copy( sphere.center );
			this.radius = sphere.radius;

			return this;

		},

		empty: function () {

			return ( this.radius <= 0 );

		},

		containsPoint: function ( point ) {

			return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) );

		},

		distanceToPoint: function ( point ) {

			return ( point.distanceTo( this.center ) - this.radius );

		},

		intersectsSphere: function ( sphere ) {

			var radiusSum = this.radius + sphere.radius;

			return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum );

		},

		intersectsBox: function ( box ) {

			return box.intersectsSphere( this );

		},

		intersectsPlane: function ( plane ) {

			// We use the following equation to compute the signed distance from
			// the center of the sphere to the plane.
			//
			// distance = q * n - d
			//
			// If this distance is greater than the radius of the sphere,
			// then there is no intersection.

			return Math.abs( this.center.dot( plane.normal ) - plane.constant ) <= this.radius;

		},

		clampPoint: function ( point, optionalTarget ) {

			var deltaLengthSq = this.center.distanceToSquared( point );

			var result = optionalTarget || new THREE.Vector3();

			result.copy( point );

			if ( deltaLengthSq > ( this.radius * this.radius ) ) {

				result.sub( this.center ).normalize();
				result.multiplyScalar( this.radius ).add( this.center );

			}

			return result;

		},

		getBoundingBox: function ( optionalTarget ) {

			var box = optionalTarget || new THREE.Box3();

			box.set( this.center, this.center );
			box.expandByScalar( this.radius );

			return box;

		},

		applyMatrix4: function ( matrix ) {

			this.center.applyMatrix4( matrix );
			this.radius = this.radius * matrix.getMaxScaleOnAxis();

			return this;

		},

		translate: function ( offset ) {

			this.center.add( offset );

			return this;

		},

		equals: function ( sphere ) {

			return sphere.center.equals( this.center ) && ( sphere.radius === this.radius );

		}

	};

	// File:src/math/Frustum.js

	/**
	 * @author mrdoob / http://mrdoob.com/
	 * @author alteredq / http://alteredqualia.com/
	 * @author bhouston / http://clara.io
	 */

	THREE.Frustum = function ( p0, p1, p2, p3, p4, p5 ) {

		this.planes = [

			( p0 !== undefined ) ? p0 : new THREE.Plane(),
			( p1 !== undefined ) ? p1 : new THREE.Plane(),
			( p2 !== undefined ) ? p2 : new THREE.Plane(),
			( p3 !== undefined ) ? p3 : new THREE.Plane(),
			( p4 !== undefined ) ? p4 : new THREE.Plane(),
			( p5 !== undefined ) ? p5 : new THREE.Plane()

		];

	};

	THREE.Frustum.prototype = {

		constructor: THREE.Frustum,

		set: function ( p0, p1, p2, p3, p4, p5 ) {

			var planes = this.planes;

			planes[ 0 ].copy( p0 );
			planes[ 1 ].copy( p1 );
			planes[ 2 ].copy( p2 );
			planes[ 3 ].copy( p3 );
			planes[ 4 ].copy( p4 );
			planes[ 5 ].copy( p5 );

			return this;

		},

		clone: function () {

			return new this.constructor().copy( this );

		},

		copy: function ( frustum ) {

			var planes = this.planes;

			for ( var i = 0; i < 6; i ++ ) {

				planes[ i ].copy( frustum.planes[ i ] );

			}

			return this;

		},

		setFromMatrix: function ( m ) {

			var planes = this.planes;
			var me = m.elements;
			var me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ];
			var me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ];
			var me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ];
			var me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ];

			planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize();
			planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize();
			planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize();
			planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize();
			planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize();
			planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize();

			return this;

		},

		intersectsObject: function () {

			var sphere = new THREE.Sphere();

			return function intersectsObject( object ) {

				var geometry = object.geometry;

				if ( geometry.boundingSphere === null )
					geometry.computeBoundingSphere();

				sphere.copy( geometry.boundingSphere )
					.applyMatrix4( object.matrixWorld );

				return this.intersectsSphere( sphere );

			};

		}(),

		intersectsSprite: function () {

			var sphere = new THREE.Sphere();

			return function intersectsSprite( sprite ) {

				sphere.center.set( 0, 0, 0 );
				sphere.radius = 0.7071067811865476;
				sphere.applyMatrix4( sprite.matrixWorld );

				return this.intersectsSphere( sphere );

			};

		}(),

		intersectsSphere: function ( sphere ) {

			var planes = this.planes;
			var center = sphere.center;
			var negRadius = - sphere.radius;

			for ( var i = 0; i < 6; i ++ ) {

				var distance = planes[ i ].distanceToPoint( center );

				if ( distance < negRadius ) {

					return false;

				}

			}

			return true;

		},

		intersectsBox: function () {

			var p1 = new THREE.Vector3(),
				p2 = new THREE.Vector3();

			return function intersectsBox( box ) {

				var planes = this.planes;

				for ( var i = 0; i < 6 ; i ++ ) {

					var plane = planes[ i ];

					p1.x = plane.normal.x > 0 ? box.min.x : box.max.x;
					p2.x = plane.normal.x > 0 ? box.max.x : box.min.x;
					p1.y = plane.normal.y > 0 ? box.min.y : box.max.y;
					p2.y = plane.normal.y > 0 ? box.max.y : box.min.y;
					p1.z = plane.normal.z > 0 ? box.min.z : box.max.z;
					p2.z = plane.normal.z > 0 ? box.max.z : box.min.z;

					var d1 = plane.distanceToPoint( p1 );
					var d2 = plane.distanceToPoint( p2 );

					// if both outside plane, no intersection

					if ( d1 < 0 && d2 < 0 ) {

						return false;

					}

				}

				return true;

			};

		}(),


		containsPoint: function ( point ) {

			var planes = this.planes;

			for ( var i = 0; i < 6; i ++ ) {

				if ( planes[ i ].distanceToPoint( point ) < 0 ) {

					return false;

				}

			}

			return true;

		}

	};

	// File:src/math/Plane.js

	/**
	 * @author bhouston / http://clara.io
	 */

	THREE.Plane = function ( normal, constant ) {

		this.normal = ( normal !== undefined ) ? normal : new THREE.Vector3( 1, 0, 0 );
		this.constant = ( constant !== undefined ) ? constant : 0;

	};

	THREE.Plane.prototype = {

		constructor: THREE.Plane,

		set: function ( normal, constant ) {

			this.normal.copy( normal );
			this.constant = constant;

			return this;

		},

		setComponents: function ( x, y, z, w ) {

			this.normal.set( x, y, z );
			this.constant = w;

			return this;

		},

		setFromNormalAndCoplanarPoint: function ( normal, point ) {

			this.normal.copy( normal );
			this.constant = - point.dot( this.normal );	// must be this.normal, not normal, as this.normal is normalized

			return this;

		},

		setFromCoplanarPoints: function () {

			var v1 = new THREE.Vector3();
			var v2 = new THREE.Vector3();

			return function setFromCoplanarPoints( a, b, c ) {

				var normal = v1.subVectors( c, b ).cross( v2.subVectors( a, b ) ).normalize();

				// Q: should an error be thrown if normal is zero (e.g. degenerate plane)?

				this.setFromNormalAndCoplanarPoint( normal, a );

				return this;

			};

		}(),

		clone: function () {

			return new this.constructor().copy( this );

		},

		copy: function ( plane ) {

			this.normal.copy( plane.normal );
			this.constant = plane.constant;

			return this;

		},

		normalize: function () {

			// Note: will lead to a divide by zero if the plane is invalid.

			var inverseNormalLength = 1.0 / this.normal.length();
			this.normal.multiplyScalar( inverseNormalLength );
			this.constant *= inverseNormalLength;

			return this;

		},

		negate: function () {

			this.constant *= - 1;
			this.normal.negate();

			return this;

		},

		distanceToPoint: function ( point ) {

			return this.normal.dot( point ) + this.constant;

		},

		distanceToSphere: function ( sphere ) {

			return this.distanceToPoint( sphere.center ) - sphere.radius;

		},

		projectPoint: function ( point, optionalTarget ) {

			return this.orthoPoint( point, optionalTarget ).sub( point ).negate();

		},

		orthoPoint: function ( point, optionalTarget ) {

			var perpendicularMagnitude = this.distanceToPoint( point );

			var result = optionalTarget || new THREE.Vector3();
			return result.copy( this.normal ).multiplyScalar( perpendicularMagnitude );

		},

		intersectLine: function () {

			var v1 = new THREE.Vector3();

			return function intersectLine( line, optionalTarget ) {

				var result = optionalTarget || new THREE.Vector3();

				var direction = line.delta( v1 );

				var denominator = this.normal.dot( direction );

				if ( denominator === 0 ) {

					// line is coplanar, return origin
					if ( this.distanceToPoint( line.start ) === 0 ) {

						return result.copy( line.start );

					}

					// Unsure if this is the correct method to handle this case.
					return undefined;

				}

				var t = - ( line.start.dot( this.normal ) + this.constant ) / denominator;

				if ( t < 0 || t > 1 ) {

					return undefined;

				}

				return result.copy( direction ).multiplyScalar( t ).add( line.start );

			};

		}(),

		intersectsLine: function ( line ) {

			// Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it.

			var startSign = this.distanceToPoint( line.start );
			var endSign = this.distanceToPoint( line.end );

			return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 );

		},

		intersectsBox: function ( box ) {

			return box.intersectsPlane( this );

		},

		intersectsSphere: function ( sphere ) {

			return sphere.intersectsPlane( this );

		},

		coplanarPoint: function ( optionalTarget ) {

			var result = optionalTarget || new THREE.Vector3();
			return result.copy( this.normal ).multiplyScalar( - this.constant );

		},

		applyMatrix4: function () {

			var v1 = new THREE.Vector3();
			var m1 = new THREE.Matrix3();

			return function applyMatrix4( matrix, optionalNormalMatrix ) {

				var referencePoint = this.coplanarPoint( v1 ).applyMatrix4( matrix );

				// transform normal based on theory here:
				// http://www.songho.ca/opengl/gl_normaltransform.html
				var normalMatrix = optionalNormalMatrix || m1.getNormalMatrix( matrix );
				var normal = this.normal.applyMatrix3( normalMatrix ).normalize();

				// recalculate constant (like in setFromNormalAndCoplanarPoint)
				this.constant = - referencePoint.dot( normal );

				return this;

			};

		}(),

		translate: function ( offset ) {

			this.constant = this.constant - offset.dot( this.normal );

			return this;

		},

		equals: function ( plane ) {

			return plane.normal.equals( this.normal ) && ( plane.constant === this.constant );

		}

	};

	// File:src/math/Spherical.js

	/**
	 * @author bhouston / http://clara.io
	 * @author WestLangley / http://github.com/WestLangley
	 *
	 * Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system
	 *
	 * The poles (phi) are at the positive and negative y axis.
	 * The equator starts at positive z.
	 */

	THREE.Spherical = function ( radius, phi, theta ) {

		this.radius = ( radius !== undefined ) ? radius : 1.0;
		this.phi = ( phi !== undefined ) ? phi : 0; // up / down towards top and bottom pole
		this.theta = ( theta !== undefined ) ? theta : 0; // around the equator of the sphere

		return this;

	};

	THREE.Spherical.prototype = {

		constructor: THREE.Spherical,

		set: function ( radius, phi, theta ) {

			this.radius = radius;
			this.phi = phi;
			this.theta = theta;

			return this;

		},

		clone: function () {

			return new this.constructor().copy( this );

		},

		copy: function ( other ) {

			this.radius.copy( other.radius );
			this.phi.copy( other.phi );
			this.theta.copy( other.theta );

			return this;

		},

		// restrict phi to be betwee EPS and PI-EPS
		makeSafe: function() {

			var EPS = 0.000001;
			this.phi = Math.max( EPS, Math.min( Math.PI - EPS, this.phi ) );

			return this;

		},

		setFromVector3: function( vec3 ) {

			this.radius = vec3.length();

			if ( this.radius === 0 ) {

				this.theta = 0;
				this.phi = 0;

			} else {

				this.theta = Math.atan2( vec3.x, vec3.z ); // equator angle around y-up axis
				this.phi = Math.acos( THREE.Math.clamp( vec3.y / this.radius, - 1, 1 ) ); // polar angle

			}

			return this;

		},

	};

	// File:src/math/Math.js

	/**
	 * @author alteredq / http://alteredqualia.com/
	 * @author mrdoob / http://mrdoob.com/
	 */

	THREE.Math = {

		DEG2RAD: Math.PI / 180,
		RAD2DEG: 180 / Math.PI,

		generateUUID: function () {

			// http://www.broofa.com/Tools/Math.uuid.htm

			var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split( '' );
			var uuid = new Array( 36 );
			var rnd = 0, r;

			return function generateUUID() {

				for ( var i = 0; i < 36; i ++ ) {

					if ( i === 8 || i === 13 || i === 18 || i === 23 ) {

						uuid[ i ] = '-';

					} else if ( i === 14 ) {

						uuid[ i ] = '4';

					} else {

						if ( rnd <= 0x02 ) rnd = 0x2000000 + ( Math.random() * 0x1000000 ) | 0;
						r = rnd & 0xf;
						rnd = rnd >> 4;
						uuid[ i ] = chars[ ( i === 19 ) ? ( r & 0x3 ) | 0x8 : r ];

					}

				}

				return uuid.join( '' );

			};

		}(),

		clamp: function ( value, min, max ) {

			return Math.max( min, Math.min( max, value ) );

		},

		// compute euclidian modulo of m % n
		// https://en.wikipedia.org/wiki/Modulo_operation

		euclideanModulo: function ( n, m ) {

			return ( ( n % m ) + m ) % m;

		},

		// Linear mapping from range <a1, a2> to range <b1, b2>

		mapLinear: function ( x, a1, a2, b1, b2 ) {

			return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );

		},

		// http://en.wikipedia.org/wiki/Smoothstep

		smoothstep: function ( x, min, max ) {

			if ( x <= min ) return 0;
			if ( x >= max ) return 1;

			x = ( x - min ) / ( max - min );

			return x * x * ( 3 - 2 * x );

		},

		smootherstep: function ( x, min, max ) {

			if ( x <= min ) return 0;
			if ( x >= max ) return 1;

			x = ( x - min ) / ( max - min );

			return x * x * x * ( x * ( x * 6 - 15 ) + 10 );

		},

		random16: function () {

			console.warn( 'THREE.Math.random16() has been deprecated. Use Math.random() instead.' );
			return Math.random();

		},

		// Random integer from <low, high> interval

		randInt: function ( low, high ) {

			return low + Math.floor( Math.random() * ( high - low + 1 ) );

		},

		// Random float from <low, high> interval

		randFloat: function ( low, high ) {

			return low + Math.random() * ( high - low );

		},

		// Random float from <-range/2, range/2> interval

		randFloatSpread: function ( range ) {

			return range * ( 0.5 - Math.random() );

		},

		degToRad: function ( degrees ) {

			return degrees * THREE.Math.DEG2RAD;

		},

		radToDeg: function ( radians ) {

			return radians * THREE.Math.RAD2DEG;

		},

		isPowerOfTwo: function ( value ) {

			return ( value & ( value - 1 ) ) === 0 && value !== 0;

		},

		nearestPowerOfTwo: function ( value ) {

			return Math.pow( 2, Math.round( Math.log( value ) / Math.LN2 ) );

		},

		nextPowerOfTwo: function ( value ) {

			value --;
			value |= value >> 1;
			value |= value >> 2;
			value |= value >> 4;
			value |= value >> 8;
			value |= value >> 16;
			value ++;

			return value;

		}

	};

	// File:src/math/Spline.js

	/**
	 * Spline from Tween.js, slightly optimized (and trashed)
	 * http://sole.github.com/tween.js/examples/05_spline.html
	 *
	 * @author mrdoob / http://mrdoob.com/
	 * @author alteredq / http://alteredqualia.com/
	 */

	THREE.Spline = function ( points ) {

		this.points = points;

		var c = [], v3 = { x: 0, y: 0, z: 0 },
		point, intPoint, weight, w2, w3,
		pa, pb, pc, pd;

		this.initFromArray = function ( a ) {

			this.points = [];

			for ( var i = 0; i < a.length; i ++ ) {

				this.points[ i ] = { x: a[ i ][ 0 ], y: a[ i ][ 1 ], z: a[ i ][ 2 ] };

			}

		};

		this.getPoint = function ( k ) {

			point = ( this.points.length - 1 ) * k;
			intPoint = Math.floor( point );
			weight = point - intPoint;

			c[ 0 ] = intPoint === 0 ? intPoint : intPoint - 1;
			c[ 1 ] = intPoint;
			c[ 2 ] = intPoint  > this.points.length - 2 ? this.points.length - 1 : intPoint + 1;
			c[ 3 ] = intPoint  > this.points.length - 3 ? this.points.length - 1 : intPoint + 2;

			pa = this.points[ c[ 0 ] ];
			pb = this.points[ c[ 1 ] ];
			pc = this.points[ c[ 2 ] ];
			pd = this.points[ c[ 3 ] ];

			w2 = weight * weight;
			w3 = weight * w2;

			v3.x = interpolate( pa.x, pb.x, pc.x, pd.x, weight, w2, w3 );
			v3.y = interpolate( pa.y, pb.y, pc.y, pd.y, weight, w2, w3 );
			v3.z = interpolate( pa.z, pb.z, pc.z, pd.z, weight, w2, w3 );

			return v3;

		};

		this.getControlPointsArray = function () {

			var i, p, l = this.points.length,
				coords = [];

			for ( i = 0; i < l; i ++ ) {

				p = this.points[ i ];
				coords[ i ] = [ p.x, p.y, p.z ];

			}

			return coords;

		};

		// approximate length by summing linear segments

		this.getLength = function ( nSubDivisions ) {

			var i, index, nSamples, position,
				point = 0, intPoint = 0, oldIntPoint = 0,
				oldPosition = new THREE.Vector3(),
				tmpVec = new THREE.Vector3(),
				chunkLengths = [],
				totalLength = 0;

			// first point has 0 length

			chunkLengths[ 0 ] = 0;

			if ( ! nSubDivisions ) nSubDivisions = 100;

			nSamples = this.points.length * nSubDivisions;

			oldPosition.copy( this.points[ 0 ] );

			for ( i = 1; i < nSamples; i ++ ) {

				index = i / nSamples;

				position = this.getPoint( index );
				tmpVec.copy( position );

				totalLength += tmpVec.distanceTo( oldPosition );

				oldPosition.copy( position );

				point = ( this.points.length - 1 ) * index;
				intPoint = Math.floor( point );

				if ( intPoint !== oldIntPoint ) {

					chunkLengths[ intPoint ] = totalLength;
					oldIntPoint = intPoint;

				}

			}

			// last point ends with total length

			chunkLengths[ chunkLengths.length ] = totalLength;

			return { chunks: chunkLengths, total: totalLength };

		};

		this.reparametrizeByArcLength = function ( samplingCoef ) {

			var i, j,
				index, indexCurrent, indexNext,
				realDistance,
				sampling, position,
				newpoints = [],
				tmpVec = new THREE.Vector3(),
				sl = this.getLength();

			newpoints.push( tmpVec.copy( this.points[ 0 ] ).clone() );

			for ( i = 1; i < this.points.length; i ++ ) {

				//tmpVec.copy( this.points[ i - 1 ] );
				//linearDistance = tmpVec.distanceTo( this.points[ i ] );

				realDistance = sl.chunks[ i ] - sl.chunks[ i - 1 ];

				sampling = Math.ceil( samplingCoef * realDistance / sl.total );

				indexCurrent = ( i - 1 ) / ( this.points.length - 1 );
				indexNext = i / ( this.points.length - 1 );

				for ( j = 1; j < sampling - 1; j ++ ) {

					index = indexCurrent + j * ( 1 / sampling ) * ( indexNext - indexCurrent );

					position = this.getPoint( index );
					newpoints.push( tmpVec.copy( position ).clone() );

				}

				newpoints.push( tmpVec.copy( this.points[ i ] ).clone() );

			}

			this.points = newpoints;

		};

		// Catmull-Rom

		function interpolate( p0, p1, p2, p3, t, t2, t3 ) {

			var v0 = ( p2 - p0 ) * 0.5,
				v1 = ( p3 - p1 ) * 0.5;

			return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1;

		}

	};

	// File:src/math/Triangle.js

	/**
	 * @author bhouston / http://clara.io
	 * @author mrdoob / http://mrdoob.com/
	 */

	THREE.Triangle = function ( a, b, c ) {

		this.a = ( a !== undefined ) ? a : new THREE.Vector3();
		this.b = ( b !== undefined ) ? b : new THREE.Vector3();
		this.c = ( c !== undefined ) ? c : new THREE.Vector3();

	};

	THREE.Triangle.normal = function () {

		var v0 = new THREE.Vector3();

		return function normal( a, b, c, optionalTarget ) {

			var result = optionalTarget || new THREE.Vector3();

			result.subVectors( c, b );
			v0.subVectors( a, b );
			result.cross( v0 );

			var resultLengthSq = result.lengthSq();
			if ( resultLengthSq > 0 ) {

				return result.multiplyScalar( 1 / Math.sqrt( resultLengthSq ) );

			}

			return result.set( 0, 0, 0 );

		};

	}();

	// static/instance method to calculate barycentric coordinates
	// based on: http://www.blackpawn.com/texts/pointinpoly/default.html
	THREE.Triangle.barycoordFromPoint = function () {

		var v0 = new THREE.Vector3();
		var v1 = new THREE.Vector3();
		var v2 = new THREE.Vector3();

		return function barycoordFromPoint( point, a, b, c, optionalTarget ) {

			v0.subVectors( c, a );
			v1.subVectors( b, a );
			v2.subVectors( point, a );

			var dot00 = v0.dot( v0 );
			var dot01 = v0.dot( v1 );
			var dot02 = v0.dot( v2 );
			var dot11 = v1.dot( v1 );
			var dot12 = v1.dot( v2 );

			var denom = ( dot00 * dot11 - dot01 * dot01 );

			var result = optionalTarget || new THREE.Vector3();

			// collinear or singular triangle
			if ( denom === 0 ) {

				// arbitrary location outside of triangle?
				// not sure if this is the best idea, maybe should be returning undefined
				return result.set( - 2, - 1, - 1 );

			}

			var invDenom = 1 / denom;
			var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
			var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;

			// barycentric coordinates must always sum to 1
			return result.set( 1 - u - v, v, u );

		};

	}();

	THREE.Triangle.containsPoint = function () {

		var v1 = new THREE.Vector3();

		return function containsPoint( point, a, b, c ) {

			var result = THREE.Triangle.barycoordFromPoint( point, a, b, c, v1 );

			return ( result.x >= 0 ) && ( result.y >= 0 ) && ( ( result.x + result.y ) <= 1 );

		};

	}();

	THREE.Triangle.prototype = {

		constructor: THREE.Triangle,

		set: function ( a, b, c ) {

			this.a.copy( a );
			this.b.copy( b );
			this.c.copy( c );

			return this;

		},

		setFromPointsAndIndices: function ( points, i0, i1, i2 ) {

			this.a.copy( points[ i0 ] );
			this.b.copy( points[ i1 ] );
			this.c.copy( points[ i2 ] );

			return this;

		},

		clone: function () {

			return new this.constructor().copy( this );

		},

		copy: function ( triangle ) {

			this.a.copy( triangle.a );
			this.b.copy( triangle.b );
			this.c.copy( triangle.c );

			return this;

		},

		area: function () {

			var v0 = new THREE.Vector3();
			var v1 = new THREE.Vector3();

			return function area() {

				v0.subVectors( this.c, this.b );
				v1.subVectors( this.a, this.b );

				return v0.cross( v1 ).length() * 0.5;

			};

		}(),

		midpoint: function ( optionalTarget ) {

			var result = optionalTarget || new THREE.Vector3();
			return result.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 );

		},

		normal: function ( optionalTarget ) {

			return THREE.Triangle.normal( this.a, this.b, this.c, optionalTarget );

		},

		plane: function ( optionalTarget ) {

			var result = optionalTarget || new THREE.Plane();

			return result.setFromCoplanarPoints( this.a, this.b, this.c );

		},

		barycoordFromPoint: function ( point, optionalTarget ) {

			return THREE.Triangle.barycoordFromPoint( point, this.a, this.b, this.c, optionalTarget );

		},

		containsPoint: function ( point ) {

			return THREE.Triangle.containsPoint( point, this.a, this.b, this.c );

		},

		closestPointToPoint: function () {

			var plane, edgeList, projectedPoint, closestPoint;

			return function closestPointToPoint( point, optionalTarget ) {

				if ( plane === undefined ) {

					plane = new THREE.Plane();
					edgeList = [ new THREE.Line3(), new THREE.Line3(), new THREE.Line3() ];
					projectedPoint = new THREE.Vector3();
					closestPoint = new THREE.Vector3();

				}

				var result = optionalTarget || new THREE.Vector3();
				var minDistance = Infinity;

				// project the point onto the plane of the triangle

				plane.setFromCoplanarPoints( this.a, this.b, this.c );
				plane.projectPoint( point, projectedPoint );

				// check if the projection lies within the triangle

				if( this.containsPoint( projectedPoint ) === true ) {

					// if so, this is the closest point

					result.copy( projectedPoint );

				} else {

					// if not, the point falls outside the triangle. the result is the closest point to the triangle's edges or vertices

					edgeList[ 0 ].set( this.a, this.b );
					edgeList[ 1 ].set( this.b, this.c );
					edgeList[ 2 ].set( this.c, this.a );

					for( var i = 0; i < edgeList.length; i ++ ) {

						edgeList[ i ].closestPointToPoint( projectedPoint, true, closestPoint );

						var distance = projectedPoint.distanceToSquared( closestPoint );

						if( distance < minDistance ) {

							minDistance = distance;

							result.copy( closestPoint );

						}

					}

				}

				return result;

			};

		}(),

		equals: function ( triangle ) {

			return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c );

		}

	};

	// File:src/math/Interpolant.js

	/**
	 * Abstract base class of interpolants over parametric samples.
	 *
	 * The parameter domain is one dimensional, typically the time or a path
	 * along a curve defined by the data.
	 *
	 * The sample values can have any dimensionality and derived classes may
	 * apply special interpretations to the data.
	 *
	 * This class provides the interval seek in a Template Method, deferring
	 * the actual interpolation to derived classes.
	 *
	 * Time complexity is O(1) for linear access crossing at most two points
	 * and O(log N) for random access, where N is the number of positions.
	 *
	 * References:
	 *
	 * 		http://www.oodesign.com/template-method-pattern.html
	 *
	 * @author tschw
	 */

	THREE.Interpolant = function(
			parameterPositions, sampleValues, sampleSize, resultBuffer ) {

		this.parameterPositions = parameterPositions;
		this._cachedIndex = 0;

		this.resultBuffer = resultBuffer !== undefined ?
				resultBuffer : new sampleValues.constructor( sampleSize );
		this.sampleValues = sampleValues;
		this.valueSize = sampleSize;

	};

	THREE.Interpolant.prototype = {

		constructor: THREE.Interpolant,

		evaluate: function( t ) {

			var pp = this.parameterPositions,
				i1 = this._cachedIndex,

				t1 = pp[   i1   ],
				t0 = pp[ i1 - 1 ];

			validate_interval: {

				seek: {

					var right;

					linear_scan: {
	//- See http://jsperf.com/comparison-to-undefined/3
	//- slower code:
	//-
	//- 				if ( t >= t1 || t1 === undefined ) {
						forward_scan: if ( ! ( t < t1 ) ) {

							for ( var giveUpAt = i1 + 2; ;) {

								if ( t1 === undefined ) {

									if ( t < t0 ) break forward_scan;

									// after end

									i1 = pp.length;
									this._cachedIndex = i1;
									return this.afterEnd_( i1 - 1, t, t0 );

								}

								if ( i1 === giveUpAt ) break; // this loop

								t0 = t1;
								t1 = pp[ ++ i1 ];

								if ( t < t1 ) {

									// we have arrived at the sought interval
									break seek;

								}

							}

							// prepare binary search on the right side of the index
							right = pp.length;
							break linear_scan;

						}

	//- slower code:
	//-					if ( t < t0 || t0 === undefined ) {
						if ( ! ( t >= t0 ) ) {

							// looping?

							var t1global = pp[ 1 ];

							if ( t < t1global ) {

								i1 = 2; // + 1, using the scan for the details
								t0 = t1global;

							}

							// linear reverse scan

							for ( var giveUpAt = i1 - 2; ;) {

								if ( t0 === undefined ) {

									// before start

									this._cachedIndex = 0;
									return this.beforeStart_( 0, t, t1 );

								}

								if ( i1 === giveUpAt ) break; // this loop

								t1 = t0;
								t0 = pp[ -- i1 - 1 ];

								if ( t >= t0 ) {

									// we have arrived at the sought interval
									break seek;

								}

							}

							// prepare binary search on the left side of the index
							right = i1;
							i1 = 0;
							break linear_scan;

						}

						// the interval is valid

						break validate_interval;

					} // linear scan

					// binary search

					while ( i1 < right ) {

						var mid = ( i1 + right ) >>> 1;

						if ( t < pp[ mid ] ) {

							right = mid;

						} else {

							i1 = mid + 1;

						}

					}

					t1 = pp[   i1   ];
					t0 = pp[ i1 - 1 ];

					// check boundary cases, again

					if ( t0 === undefined ) {

						this._cachedIndex = 0;
						return this.beforeStart_( 0, t, t1 );

					}

					if ( t1 === undefined ) {

						i1 = pp.length;
						this._cachedIndex = i1;
						return this.afterEnd_( i1 - 1, t0, t );

					}

				} // seek

				this._cachedIndex = i1;

				this.intervalChanged_( i1, t0, t1 );

			} // validate_interval

			return this.interpolate_( i1, t0, t, t1 );

		},

		settings: null, // optional, subclass-specific settings structure
		// Note: The indirection allows central control of many interpolants.

		// --- Protected interface

		DefaultSettings_: {},

		getSettings_: function() {

			return this.settings || this.DefaultSettings_;

		},

		copySampleValue_: function( index ) {

			// copies a sample value to the result buffer

			var result = this.resultBuffer,
				values = this.sampleValues,
				stride = this.valueSize,
				offset = index * stride;

			for ( var i = 0; i !== stride; ++ i ) {

				result[ i ] = values[ offset + i ];

			}

			return result;

		},

		// Template methods for derived classes:

		interpolate_: function( i1, t0, t, t1 ) {

			throw new Error( "call to abstract method" );
			// implementations shall return this.resultBuffer

		},

		intervalChanged_: function( i1, t0, t1 ) {

			// empty

		}

	};

	Object.assign( THREE.Interpolant.prototype, {

		beforeStart_: //( 0, t, t0 ), returns this.resultBuffer
			THREE.Interpolant.prototype.copySampleValue_,

		afterEnd_: //( N-1, tN-1, t ), returns this.resultBuffer
			THREE.Interpolant.prototype.copySampleValue_

	} );

	// File:src/math/interpolants/CubicInterpolant.js

	/**
	 * Fast and simple cubic spline interpolant.
	 *
	 * It was derived from a Hermitian construction setting the first derivative
	 * at each sample position to the linear slope between neighboring positions
	 * over their parameter interval.
	 *
	 * @author tschw
	 */

	THREE.CubicInterpolant = function(
			parameterPositions, sampleValues, sampleSize, resultBuffer ) {

		THREE.Interpolant.call(
				this, parameterPositions, sampleValues, sampleSize, resultBuffer );

		this._weightPrev = -0;
		this._offsetPrev = -0;
		this._weightNext = -0;
		this._offsetNext = -0;

	};

	THREE.CubicInterpolant.prototype =
			Object.assign( Object.create( THREE.Interpolant.prototype ), {

		constructor: THREE.CubicInterpolant,

		DefaultSettings_: {

			endingStart: 	THREE.ZeroCurvatureEnding,
			endingEnd:		THREE.ZeroCurvatureEnding

		},

		intervalChanged_: function( i1, t0, t1 ) {

			var pp = this.parameterPositions,
				iPrev = i1 - 2,
				iNext = i1 + 1,

				tPrev = pp[ iPrev ],
				tNext = pp[ iNext ];

			if ( tPrev === undefined ) {

				switch ( this.getSettings_().endingStart ) {

					case THREE.ZeroSlopeEnding:

						// f'(t0) = 0
						iPrev = i1;
						tPrev = 2 * t0 - t1;

						break;

					case THREE.WrapAroundEnding:

						// use the other end of the curve
						iPrev = pp.length - 2;
						tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ];

						break;

					default: // ZeroCurvatureEnding

						// f''(t0) = 0 a.k.a. Natural Spline
						iPrev = i1;
						tPrev = t1;

				}

			}

			if ( tNext === undefined ) {

				switch ( this.getSettings_().endingEnd ) {

					case THREE.ZeroSlopeEnding:

						// f'(tN) = 0
						iNext = i1;
						tNext = 2 * t1 - t0;

						break;

					case THREE.WrapAroundEnding:

						// use the other end of the curve
						iNext = 1;
						tNext = t1 + pp[ 1 ] - pp[ 0 ];

						break;

					default: // ZeroCurvatureEnding

						// f''(tN) = 0, a.k.a. Natural Spline
						iNext = i1 - 1;
						tNext = t0;

				}

			}

			var halfDt = ( t1 - t0 ) * 0.5,
				stride = this.valueSize;

			this._weightPrev = halfDt / ( t0 - tPrev );
			this._weightNext = halfDt / ( tNext - t1 );
			this._offsetPrev = iPrev * stride;
			this._offsetNext = iNext * stride;

		},

		interpolate_: function( i1, t0, t, t1 ) {

			var result = this.resultBuffer,
				values = this.sampleValues,
				stride = this.valueSize,

				o1 = i1 * stride,		o0 = o1 - stride,
				oP = this._offsetPrev, 	oN = this._offsetNext,
				wP = this._weightPrev,	wN = this._weightNext,

				p = ( t - t0 ) / ( t1 - t0 ),
				pp = p * p,
				ppp = pp * p;

			// evaluate polynomials

			var sP =     - wP   * ppp   +         2 * wP    * pp    -          wP   * p;
			var s0 = ( 1 + wP ) * ppp   + (-1.5 - 2 * wP )  * pp    + ( -0.5 + wP ) * p     + 1;
			var s1 = (-1 - wN ) * ppp   + ( 1.5 +   wN   )  * pp    +    0.5        * p;
			var sN =       wN   * ppp   -           wN      * pp;

			// combine data linearly

			for ( var i = 0; i !== stride; ++ i ) {

				result[ i ] =
						sP * values[ oP + i ] +
						s0 * values[ o0 + i ] +
						s1 * values[ o1 + i ] +
						sN * values[ oN + i ];

			}

			return result;

		}

	} );

	// File:src/math/interpolants/DiscreteInterpolant.js

	/**
	 *
	 * Interpolant that evaluates to the sample value at the position preceeding
	 * the parameter.
	 *
	 * @author tschw
	 */

	THREE.DiscreteInterpolant = function(
			parameterPositions, sampleValues, sampleSize, resultBuffer ) {

		THREE.Interpolant.call(
				this, parameterPositions, sampleValues, sampleSize, resultBuffer );

	};

	THREE.DiscreteInterpolant.prototype =
			Object.assign( Object.create( THREE.Interpolant.prototype ), {

		constructor: THREE.DiscreteInterpolant,

		interpolate_: function( i1, t0, t, t1 ) {

			return this.copySampleValue_( i1 - 1 );

		}

	} );

	// File:src/math/interpolants/LinearInterpolant.js

	/**
	 * @author tschw
	 */

	THREE.LinearInterpolant = function(
			parameterPositions, sampleValues, sampleSize, resultBuffer ) {

		THREE.Interpolant.call(
				this, parameterPositions, sampleValues, sampleSize, resultBuffer );

	};

	THREE.LinearInterpolant.prototype =
			Object.assign( Object.create( THREE.Interpolant.prototype ), {

		constructor: THREE.LinearInterpolant,

		interpolate_: function( i1, t0, t, t1 ) {

			var result = this.resultBuffer,
				values = this.sampleValues,
				stride = this.valueSize,

				offset1 = i1 * stride,
				offset0 = offset1 - stride,

				weight1 = ( t - t0 ) / ( t1 - t0 ),
				weight0 = 1 - weight1;

			for ( var i = 0; i !== stride; ++ i ) {

				result[ i ] =
						values[ offset0 + i ] * weight0 +
						values[ offset1 + i ] * weight1;

			}

			return result;

		}

	} );

	// File:src/math/interpolants/QuaternionLinearInterpolant.js

	/**
	 * Spherical linear unit quaternion interpolant.
	 *
	 * @author tschw
	 */

	THREE.QuaternionLinearInterpolant = function(
			parameterPositions, sampleValues, sampleSize, resultBuffer ) {

		THREE.Interpolant.call(
				this, parameterPositions, sampleValues, sampleSize, resultBuffer );

	};

	THREE.QuaternionLinearInterpolant.prototype =
			Object.assign( Object.create( THREE.Interpolant.prototype ), {

		constructor: THREE.QuaternionLinearInterpolant,

		interpolate_: function( i1, t0, t, t1 ) {

			var result = this.resultBuffer,
				values = this.sampleValues,
				stride = this.valueSize,

				offset = i1 * stride,

				alpha = ( t - t0 ) / ( t1 - t0 );

			for ( var end = offset + stride; offset !== end; offset += 4 ) {

				THREE.Quaternion.slerpFlat( result, 0,
						values, offset - stride, values, offset, alpha );

			}

			return result;

		}

	} );

	// File:src/core/Clock.js

	/**
	 * @author alteredq / http://alteredqualia.com/
	 */

	THREE.Clock = function ( autoStart ) {

		this.autoStart = ( autoStart !== undefined ) ? autoStart : true;

		this.startTime = 0;
		this.oldTime = 0;
		this.elapsedTime = 0;

		this.running = false;

	};

	THREE.Clock.prototype = {

		constructor: THREE.Clock,

		start: function () {

			this.startTime = ( performance || Date ).now();

			this.oldTime = this.startTime;
			this.running = true;

		},

		stop: function () {

			this.getElapsedTime();
			this.running = false;

		},

		getElapsedTime: function () {

			this.getDelta();
			return this.elapsedTime;

		},

		getDelta: function () {

			var diff = 0;

			if ( this.autoStart && ! this.running ) {

				this.start();

			}

			if ( this.running ) {

				var newTime = ( performance || Date ).now();

				diff = ( newTime - this.oldTime ) / 1000;
				this.oldTime = newTime;

				this.elapsedTime += diff;

			}

			return diff;

		}

	};

	// File:src/core/EventDispatcher.js

	/**
	 * https://github.com/mrdoob/eventdispatcher.js/
	 */

	THREE.EventDispatcher = function () {};

	Object.assign( THREE.EventDispatcher.prototype, {

		addEventListener: function ( type, listener ) {

			if ( this._listeners === undefined ) this._listeners = {};

			var listeners = this._listeners;

			if ( listeners[ type ] === undefined ) {

				listeners[ type ] = [];

			}

			if ( listeners[ type ].indexOf( listener ) === - 1 ) {

				listeners[ type ].push( listener );

			}

		},

		hasEventListener: function ( type, listener ) {

			if ( this._listeners === undefined ) return false;

			var listeners = this._listeners;

			if ( listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1 ) {

				return true;

			}

			return false;

		},

		removeEventListener: function ( type, listener ) {

			if ( this._listeners === undefined ) return;

			var listeners = this._listeners;
			var listenerArray = listeners[ type ];

			if ( listenerArray !== undefined ) {

				var index = listenerArray.indexOf( listener );

				if ( index !== - 1 ) {

					listenerArray.splice( index, 1 );

				}

			}

		},

		dispatchEvent: function ( event ) {

			if ( this._listeners === undefined ) return;

			var listeners = this._listeners;
			var listenerArray = listeners[ event.type ];

			if ( listenerArray !== undefined ) {

				event.target = this;

				var array = [], i = 0;
				var length = listenerArray.length;

				for ( i = 0; i < length; i ++ ) {

					array[ i ] = listenerArray[ i ];

				}

				for ( i = 0; i < length; i ++ ) {

					array[ i ].call( this, event );

				}

			}

		}

	} );

	// File:src/core/Layers.js

	/**
	 * @author mrdoob / http://mrdoob.com/
	 */

	THREE.Layers = function () {

		this.mask = 1;

	};

	THREE.Layers.prototype = {

		constructor: THREE.Layers,

		set: function ( channel ) {

			this.mask = 1 << channel;

		},

		enable: function ( channel ) {

			this.mask |= 1 << channel;

		},

		toggle: function ( channel ) {

			this.mask ^= 1 << channel;

		},

		disable: function ( channel ) {

			this.mask &= ~ ( 1 << channel );

		},

		test: function ( layers ) {

			return ( this.mask & layers.mask ) !== 0;

		}

	};

	// File:src/core/Raycaster.js

	/**
	 * @author mrdoob / http://mrdoob.com/
	 * @author bhouston / http://clara.io/
	 * @author stephomi / http://stephaneginier.com/
	 */

	( function ( THREE ) {

		THREE.Raycaster = function ( origin, direction, near, far ) {

			this.ray = new THREE.Ray( origin, direction );
			// direction is assumed to be normalized (for accurate distance calculations)

			this.near = near || 0;
			this.far = far || Infinity;

			this.params = {
				Mesh: {},
				Line: {},
				LOD: {},
				Points: { threshold: 1 },
				Sprite: {}
			};

			Object.defineProperties( this.params, {
				PointCloud: {
					get: function () {
						console.warn( 'THREE.Raycaster: params.PointCloud has been renamed to params.Points.' );
						return this.Points;
					}
				}
			} );

		};

		function ascSort( a, b ) {

			return a.distance - b.distance;

		}

		function intersectObject( object, raycaster, intersects, recursive ) {

			if ( object.visible === false ) return;

			object.raycast( raycaster, intersects );

			if ( recursive === true ) {

				var children = object.children;

				for ( var i = 0, l = children.length; i < l; i ++ ) {

					intersectObject( children[ i ], raycaster, intersects, true );

				}

			}

		}

		//

		THREE.Raycaster.prototype = {

			constructor: THREE.Raycaster,

			linePrecision: 1,

			set: function ( origin, direction ) {

				// direction is assumed to be normalized (for accurate distance calculations)

				this.ray.set( origin, direction );

			},

			setFromCamera: function ( coords, camera ) {

				if ( camera instanceof THREE.PerspectiveCamera ) {

					this.ray.origin.setFromMatrixPosition( camera.matrixWorld );
					this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize();

				} else if ( camera instanceof THREE.OrthographicCamera ) {

					this.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera
					this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld );

				} else {

					console.error( 'THREE.Raycaster: Unsupported camera type.' );

				}

			},

			intersectObject: function ( object, recursive ) {

				var intersects = [];

				intersectObject( object, this, intersects, recursive );

				intersects.sort( ascSort );

				return intersects;

			},

			intersectObjects: function ( objects, recursive ) {

				var intersects = [];

				if ( Array.isArray( objects ) === false ) {

					console.warn( 'THREE.Raycaster.intersectObjects: objects is not an Array.' );
					return intersects;

				}

				for ( var i = 0, l = objects.length; i < l; i ++ ) {

					intersectObject( objects[ i ], this, intersects, recursive );

				}

				intersects.sort( ascSort );

				return intersects;

			}

		};

	}( THREE ) );

	// File:src/core/Object3D.js

	/**
	 * @author mrdoob / http://mrdoob.com/
	 * @author mikael emtinger / http://gomo.se/
	 * @author alteredq / http://alteredqualia.com/
	 * @author WestLangley / http://github.com/WestLangley
	 * @author elephantatwork / www.elephantatwork.ch
	 */

	THREE.Object3D = function () {

		Object.defineProperty( this, 'id', { value: THREE.Object3DIdCount ++ } );

		this.uuid = THREE.Math.generateUUID();

		this.name = '';
		this.type = 'Object3D';

		this.parent = null;
		this.children = [];

		this.up = THREE.Object3D.DefaultUp.clone();

		var position = new THREE.Vector3();
		var rotation = new THREE.Euler();
		var quaternion = new THREE.Quaternion();
		var scale = new THREE.Vector3( 1, 1, 1 );

		function onRotationChange() {

			quaternion.setFromEuler( rotation, false );

		}

		function onQuaternionChange() {

			rotation.setFromQuaternion( quaternion, undefined, false );

		}

		rotation.onChange( onRotationChange );
		quaternion.onChange( onQuaternionChange );

		Object.defineProperties( this, {
			position: {
				enumerable: true,
				value: position
			},
			rotation: {
				enumerable: true,
				value: rotation
			},
			quaternion: {
				enumerable: true,
				value: quaternion
			},
			scale: {
				enumerable: true,
				value: scale
			},
			modelViewMatrix: {
				value: new THREE.Matrix4()
			},
			normalMatrix: {
				value: new THREE.Matrix3()
			}
		} );

		this.matrix = new THREE.Matrix4();
		this.matrixWorld = new THREE.Matrix4();

		this.matrixAutoUpdate = THREE.Object3D.DefaultMatrixAutoUpdate;
		this.matrixWorldNeedsUpdate = false;

		this.layers = new THREE.Layers();
		this.visible = true;

		this.castShadow = false;
		this.receiveShadow = false;

		this.frustumCulled = true;
		this.renderOrder = 0;

		this.userData = {};

	};

	THREE.Object3D.DefaultUp = new THREE.Vector3( 0, 1, 0 );
	THREE.Object3D.DefaultMatrixAutoUpdate = true;

	Object.assign( THREE.Object3D.prototype, THREE.EventDispatcher.prototype, {

		applyMatrix: function ( matrix ) {

			this.matrix.multiplyMatrices( matrix, this.matrix );

			this.matrix.decompose( this.position, this.quaternion, this.scale );

		},

		setRotationFromAxisAngle: function ( axis, angle ) {

			// assumes axis is normalized

			this.quaternion.setFromAxisAngle( axis, angle );

		},

		setRotationFromEuler: function ( euler ) {

			this.quaternion.setFromEuler( euler, true );

		},

		setRotationFromMatrix: function ( m ) {

			// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)

			this.quaternion.setFromRotationMatrix( m );

		},

		setRotationFromQuaternion: function ( q ) {

			// assumes q is normalized

			this.quaternion.copy( q );

		},

		rotateOnAxis: function () {

			// rotate object on axis in object space
			// axis is assumed to be normalized

			var q1 = new THREE.Quaternion();

			return function rotateOnAxis( axis, angle ) {

				q1.setFromAxisAngle( axis, angle );

				this.quaternion.multiply( q1 );

				return this;

			};

		}(),

		rotateX: function () {

			var v1 = new THREE.Vector3( 1, 0, 0 );

			return function rotateX( angle ) {

				return this.rotateOnAxis( v1, angle );

			};

		}(),

		rotateY: function () {

			var v1 = new THREE.Vector3( 0, 1, 0 );

			return function rotateY( angle ) {

				return this.rotateOnAxis( v1, angle );

			};

		}(),

		rotateZ: function () {

			var v1 = new THREE.Vector3( 0, 0, 1 );

			return function rotateZ( angle ) {

				return this.rotateOnAxis( v1, angle );

			};

		}(),

		translateOnAxis: function () {

			// translate object by distance along axis in object space
			// axis is assumed to be normalized

			var v1 = new THREE.Vector3();

			return function translateOnAxis( axis, distance ) {

				v1.copy( axis ).applyQuaternion( this.quaternion );

				this.position.add( v1.multiplyScalar( distance ) );

				return this;

			};

		}(),

		translateX: function () {

			var v1 = new THREE.Vector3( 1, 0, 0 );

			return function translateX( distance ) {

				return this.translateOnAxis( v1, distance );

			};

		}(),

		translateY: function () {

			var v1 = new THREE.Vector3( 0, 1, 0 );

			return function translateY( distance ) {

				return this.translateOnAxis( v1, distance );

			};

		}(),

		translateZ: function () {

			var v1 = new THREE.Vector3( 0, 0, 1 );

			return function translateZ( distance ) {

				return this.translateOnAxis( v1, distance );

			};

		}(),

		localToWorld: function ( vector ) {

			return vector.applyMatrix4( this.matrixWorld );

		},

		worldToLocal: function () {

			var m1 = new THREE.Matrix4();

			return function worldToLocal( vector ) {

				return vector.applyMatrix4( m1.getInverse( this.matrixWorld ) );

			};

		}(),

		lookAt: function () {

			// This routine does not support objects with rotated and/or translated parent(s)

			var m1 = new THREE.Matrix4();

			return function lookAt( vector ) {

				m1.lookAt( vector, this.position, this.up );

				this.quaternion.setFromRotationMatrix( m1 );

			};

		}(),

		add: function ( object ) {

			if ( arguments.length > 1 ) {

				for ( var i = 0; i < arguments.length; i ++ ) {

					this.add( arguments[ i ] );

				}

				return this;

			}

			if ( object === this ) {

				console.error( "THREE.Object3D.add: object can't be added as a child of itself.", object );
				return this;

			}

			if ( object instanceof THREE.Object3D ) {

				if ( object.parent !== null ) {

					object.parent.remove( object );

				}

				object.parent = this;
				object.dispatchEvent( { type: 'added' } );

				this.children.push( object );

			} else {

				console.error( "THREE.Object3D.add: object not an instance of THREE.Object3D.", object );

		
Download .txt
gitextract_38dpwdar/

├── .gitignore
├── LICENSE
├── README.md
├── bundle.js
├── lib/
│   ├── Detector.js
│   └── THREE.MeshLine.js
├── package.json
├── public/
│   ├── index.html
│   └── static/
│       ├── app.css
│       └── meshes/
│           ├── balloon.json
│           ├── boat01.json
│           ├── church01.json
│           ├── model.json
│           ├── pier01.json
│           ├── plane.json
│           └── tree.json
├── resources/
│   ├── balloon.fbx
│   ├── blimp.lxo
│   ├── church.c4d
│   ├── dae/
│   │   ├── balloon.dae
│   │   ├── boat01.dae
│   │   ├── church01.dae
│   │   ├── pier01.dae
│   │   ├── plane.dae
│   │   └── tree.dae
│   ├── pier.blend
│   ├── plane.lxo
│   ├── tree.fbx
│   └── tree.lxo
├── src/
│   ├── FBXLoader.js
│   ├── ImprovedNoise.js
│   ├── classes/
│   │   ├── bird.js
│   │   ├── heightmap.js
│   │   ├── mathf.js
│   │   ├── player.js
│   │   ├── random.js
│   │   └── terrain-patch.js
│   ├── index.js
│   └── shaders/
│       ├── landscape_frag.glsl
│       ├── landscape_vert.glsl
│       ├── standard_frag.glsl
│       └── standard_vert.glsl
├── webpack.common.js
├── webpack.dev.js
└── webpack.prod.js
Download .txt
SYMBOL INDEX (438 symbols across 11 files)

FILE: bundle.js
  function __webpack_require__ (line 6) | function __webpack_require__(moduleId) {
  function _interopRequireDefault (line 86) | function _interopRequireDefault(obj) { return obj && obj.__esModule ? ob...
  function _defineProperty (line 88) | function _defineProperty(obj, key, value) { if (key in obj) { Object.def...
  function onchange (line 199) | function onchange(evt) {
  function hue2rgb (line 1273) | function hue2rgb( p, q, t ) {
  function handleAlpha (line 1314) | function handleAlpha( string ) {
  method x (line 1721) | get x () {
  method x (line 1727) | set x ( value ) {
  method y (line 1734) | get y () {
  method y (line 1740) | set y ( value ) {
  method z (line 1747) | get z () {
  method z (line 1753) | set z ( value ) {
  method w (line 1760) | get w () {
  method w (line 1766) | set w ( value ) {
  method width (line 2307) | get width() {
  method width (line 2313) | set width( value ) {
  method height (line 2319) | get height() {
  method height (line 2325) | set height( value ) {
  method x (line 4173) | get x () {
  method x (line 4179) | set x ( value ) {
  method y (line 4186) | get y () {
  method y (line 4192) | set y ( value ) {
  method z (line 4199) | get z () {
  method z (line 4205) | set z ( value ) {
  method order (line 4212) | get order () {
  method order (line 4218) | set order ( value ) {
  function interpolate (line 8149) | function interpolate( p0, p1, p2, p3, t, t2, t3 ) {
  function ascSort (line 9209) | function ascSort( a, b ) {
  function intersectObject (line 9215) | function intersectObject( object, raycaster, intersects, recursive ) {
  function onRotationChange (line 9339) | function onRotationChange() {
  function onQuaternionChange (line 9345) | function onQuaternionChange() {
  function extractFromCache (line 9958) | function extractFromCache ( cache ) {
  method count (line 10114) | get count() {
  method needsUpdate (line 10120) | set needsUpdate( value ) {
  method length (line 10513) | get length () {
  method count (line 10519) | get count () {
  method needsUpdate (line 10525) | set needsUpdate( value ) {
  method length (line 10630) | get length() {
  method count (line 10637) | get count() {
  function addFace (line 10997) | function addFace( a, b, c, materialIndex ) {
  function materialIndexSort (line 11626) | function materialIndexSort( a, b ) {
  function setBit (line 11782) | function setBit( value, position, enabled ) {
  function getNormalIndex (line 11788) | function getNormalIndex( normal ) {
  function getColorIndex (line 11805) | function getColorIndex( color ) {
  function getUvIndex (line 11822) | function getUvIndex( uv ) {
  method total (line 14827) | get total() { return scope._actions.length; }
  method inUse (line 14828) | get inUse() { return scope._nActiveActions; }
  method total (line 14831) | get total() { return scope._bindings.length; }
  method inUse (line 14832) | get inUse() { return scope._nActiveBindings; }
  method total (line 14835) | get total() { return scope._controlInterpolants.length; }
  method inUse (line 14836) | get inUse() { return scope._nActiveControlInterpolants; }
  method total (line 15187) | get total() { return scope._objects.length; }
  method inUse (line 15188) | get inUse() { return this.total - scope.nCachedObjects_;  }
  method bindingsPerObject (line 15191) | get bindingsPerObject() { return scope._bindings.length; }
  function compareTime (line 15547) | function compareTime( i, j ) {
  function loadTexture (line 18888) | function loadTexture( path, repeat, offset, wrap, anisotropy ) {
  function parseModel (line 19480) | function parseModel( scale ) {
  function parseSkin (line 19780) | function parseSkin() {
  function parseMorphing (line 19825) | function parseMorphing( scale ) {
  function parseAnimations (line 19870) | function parseAnimations() {
  function loadImage (line 20581) | function loadImage( url ) {
  function parseConstant (line 20617) | function parseConstant( value ) {
  function getGeometry (line 20684) | function getGeometry( name ) {
  function getMaterial (line 20696) | function getMaterial( name ) {
  function loadTexture (line 20957) | function loadTexture( i ) {
  function loadTexture (line 21125) | function loadTexture( i ) {
  method needsUpdate (line 21293) | get needsUpdate() {
  method needsUpdate (line 21299) | set needsUpdate( value ) {
  function extractFromCache (line 21441) | function extractFromCache ( cache ) {
  method needsUpdate (line 22806) | set needsUpdate( value ) {
  function getDataURL (line 22857) | function getDataURL( image ) {
  function update (line 23171) | function update() {
  function testPoint (line 23262) | function testPoint( point, index ) {
  function uvIntersection (line 23651) | function uvIntersection( point, p1, p2, p3, uv1, uv2, uv3 ) {
  function checkIntersection (line 23665) | function checkIntersection( object, raycaster, ray, pA, pB, pC, point ) {
  function checkBufferGeometryIntersection (line 23697) | function checkBufferGeometryIntersection( object, raycaster, ray, positi...
  function getTargetPixelRatio (line 25894) | function getTargetPixelRatio() {
  function glClearColor (line 25900) | function glClearColor( r, g, b, a ) {
  function setDefaultGLState (line 25912) | function setDefaultGLState() {
  function resetGLState (line 25923) | function resetGLState() {
  function onContextLost (line 26135) | function onContextLost( event ) {
  function onMaterialDispose (line 26146) | function onMaterialDispose( event ) {
  function deallocateMaterial (line 26158) | function deallocateMaterial( material ) {
  function releaseMaterialProgramReference (line 26167) | function releaseMaterialProgramReference( material ) {
  function setupVertexAttributes (line 26475) | function setupVertexAttributes( material, program, geometry, startIndex ) {
  function absNumericalSort (line 26640) | function absNumericalSort( a, b ) {
  function painterSortStable (line 26646) | function painterSortStable ( a, b ) {
  function reversePainterSortStable (line 26668) | function reversePainterSortStable ( a, b ) {
  function pushRenderItem (line 26853) | function pushRenderItem( object, geometry, material, z, group ) {
  function isObjectViewable (line 26904) | function isObjectViewable( object ) {
  function isSpriteViewable (line 26918) | function isSpriteViewable( sprite ) {
  function isSphereViewable (line 26928) | function isSphereViewable( sphere ) {
  function projectObject (line 26953) | function projectObject( object, camera ) {
  function renderObjects (line 27051) | function renderObjects( renderList, camera, fog, overrideMaterial ) {
  function initMaterial (line 27089) | function initMaterial( material, fog, object ) {
  function setMaterial (line 27234) | function setMaterial( material ) {
  function setProgram (line 27261) | function setProgram( camera, fog, material, object ) {
  function refreshUniformsCommon (line 27543) | function refreshUniformsCommon ( uniforms, material ) {
  function refreshUniformsLine (line 27643) | function refreshUniformsLine ( uniforms, material ) {
  function refreshUniformsDash (line 27650) | function refreshUniformsDash ( uniforms, material ) {
  function refreshUniformsPoints (line 27658) | function refreshUniformsPoints ( uniforms, material ) {
  function refreshUniformsFog (line 27678) | function refreshUniformsFog ( uniforms, fog ) {
  function refreshUniformsLambert (line 27695) | function refreshUniformsLambert ( uniforms, material ) {
  function refreshUniformsPhong (line 27712) | function refreshUniformsPhong ( uniforms, material ) {
  function refreshUniformsStandard (line 27754) | function refreshUniformsStandard ( uniforms, material ) {
  function refreshUniformsPhysical (line 27815) | function refreshUniformsPhysical ( uniforms, material ) {
  function markUniformsLightsNeedsUpdate (line 27826) | function markUniformsLightsNeedsUpdate ( uniforms, value ) {
  function setupShadows (line 27839) | function setupShadows ( lights ) {
  function setupLights (line 27859) | function setupLights ( lights, camera ) {
  function allocTextureUnit (line 28025) | function allocTextureUnit() {
  function paramThreeToGL (line 28277) | function paramThreeToGL ( p ) {
  function setMode (line 28496) | function setMode( value ) {
  function render (line 28502) | function render( start, count ) {
  function renderInstances (line 28512) | function renderInstances( geometry ) {
  function resetGlobalState (line 28647) | function resetGlobalState() {
  function projectPlanes (line 28660) | function projectPlanes( planes, camera, dstOffset, skipTransform ) {
  function setMode (line 28718) | function setMode( value ) {
  function setIndex (line 28726) | function setIndex( index ) {
  function render (line 28742) | function render( start, count ) {
  function renderInstances (line 28752) | function renderInstances( geometry, start, count ) {
  function getMaxAnisotropy (line 28844) | function getMaxAnisotropy() {
  function getMaxPrecision (line 28864) | function getMaxPrecision( precision ) {
  function get (line 28941) | function get( object ) {
  function onGeometryDispose (line 28979) | function onGeometryDispose( event ) {
  function getAttributeBuffer (line 29024) | function getAttributeBuffer( attribute ) {
  function deleteAttribute (line 29036) | function deleteAttribute( attribute ) {
  function deleteAttributes (line 29049) | function deleteAttributes( attributes ) {
  function removeAttributeBuffer (line 29059) | function removeAttributeBuffer( attribute ) {
  function update (line 29172) | function update( object ) {
  function updateAttribute (line 29219) | function updateAttribute( attribute, bufferType ) {
  function createBuffer (line 29237) | function createBuffer( attributeProperties, data, bufferType ) {
  function updateBuffer (line 29250) | function updateBuffer( attributeProperties, data, bufferType ) {
  function getAttributeBuffer (line 29277) | function getAttributeBuffer( attribute ) {
  function getWireframeAttribute (line 29289) | function getWireframeAttribute( geometry ) {
  function checkEdge (line 29353) | function checkEdge( edges, a, b ) {
  function getEncodingComponents (line 29394) | function getEncodingComponents( encoding ) {
  function getTexelDecodingFunction (line 29419) | function getTexelDecodingFunction( functionName, encoding ) {
  function getTexelEncodingFunction (line 29426) | function getTexelEncodingFunction( functionName, encoding ) {
  function getToneMappingFunction (line 29433) | function getToneMappingFunction( functionName, toneMapping ) {
  function generateExtensions (line 29464) | function generateExtensions( extensions, parameters, rendererExtensions ) {
  function generateDefines (line 29479) | function generateDefines( defines ) {
  function fetchAttributeLocations (line 29497) | function fetchAttributeLocations( gl, program, identifiers ) {
  function filterEmptyLine (line 29518) | function filterEmptyLine( string ) {
  function replaceLightNums (line 29524) | function replaceLightNums( string, parameters ) {
  function parseIncludes (line 29534) | function parseIncludes( string ) {
  function unrollLoops (line 29556) | function unrollLoops( string ) {
  function allocateBones (line 30078) | function allocateBones ( object ) {
  function getTextureEncodingFromMap (line 30116) | function getTextureEncodingFromMap( map, gammaOverrideLinear ) {
  function addLineNumbers (line 30376) | function addLineNumbers( string ) {
  function getDepthMaterial (line 30716) | function getDepthMaterial( object, material, isPointLight, lightPosition...
  function projectObject (line 30819) | function projectObject( object, camera, shadowCamera ) {
  function createTexture (line 30904) | function createTexture( type, target, count ) {
  function clampToMaxSize (line 31787) | function clampToMaxSize ( image, maxSize ) {
  function isPowerOfTwo (line 31813) | function isPowerOfTwo( image ) {
  function makePowerOfTwo (line 31819) | function makePowerOfTwo( image ) {
  function textureNeedsPowerOfTwo (line 31840) | function textureNeedsPowerOfTwo( texture ) {
  function filterFallback (line 31851) | function filterFallback ( f ) {
  function onTextureDispose (line 31865) | function onTextureDispose( event ) {
  function onRenderTargetDispose (line 31878) | function onRenderTargetDispose( event ) {
  function deallocateTexture (line 31892) | function deallocateTexture( texture ) {
  function deallocateRenderTarget (line 31917) | function deallocateRenderTarget( renderTarget ) {
  function setTexture2D (line 31961) | function setTexture2D( texture, slot ) {
  function setTextureCube (line 31991) | function setTextureCube ( texture, slot ) {
  function setTextureCubeDynamic (line 32107) | function setTextureCubeDynamic ( texture, slot ) {
  function setTextureParameters (line 32114) | function setTextureParameters ( textureType, texture, isPowerOfTwoImage ) {
  function uploadTexture (line 32166) | function uploadTexture( textureProperties, texture, slot ) {
  function setupFrameBufferTexture (line 32310) | function setupFrameBufferTexture ( framebuffer, renderTarget, attachment...
  function setupRenderBufferStorage (line 32322) | function setupRenderBufferStorage ( renderbuffer, renderTarget ) {
  function setupDepthTexture (line 32348) | function setupDepthTexture ( framebuffer, renderTarget ) {
  function setupDepthRenderbuffer (line 32378) | function setupDepthRenderbuffer( renderTarget ) {
  function setupRenderTarget (line 32419) | function setupRenderTarget( renderTarget ) {
  function updateRenderTargetMipmap (line 32488) | function updateRenderTargetMipmap( renderTarget ) {
  function init (line 33137) | function init() {
  function createProgram (line 33479) | function createProgram ( shader ) {
  function init (line 33528) | function init() {
  function createProgram (line 33752) | function createProgram () {
  function painterSortStable (line 33859) | function painterSortStable ( a, b ) {
  function snip (line 34785) | function snip( contour, u, v, w, n, verts ) {
  function point_in_segment_2D_colin (line 34939) | function point_in_segment_2D_colin( inSegPt1, inSegPt2, inOtherPt ) {
  function intersect_segments_2D (line 34970) | function intersect_segments_2D( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1, inSeg2P...
  function isPointInsideAngle (line 35143) | function isPointInsideAngle( inVertex, inLegFromPt, inLegToPt, inOtherPt...
  function removeHoles (line 35186) | function removeHoles( contour, holes ) {
  function b2p0 (line 35429) | function b2p0( t, p ) {
  function b2p1 (line 35436) | function b2p1( t, p ) {
  function b2p2 (line 35442) | function b2p2( t, p ) {
  function b3p0 (line 35460) | function b3p0( t, p ) {
  function b3p1 (line 35467) | function b3p1( t, p ) {
  function b3p2 (line 35474) | function b3p2( t, p ) {
  function b3p3 (line 35481) | function b3p3( t, p ) {
  function createPaths (line 35977) | function createPaths( text ) {
  function createPath (line 35998) | function createPath( c, scale, offset ) {
  function extractSubpaths (line 36573) | function extractSubpaths( inActions ) {
  function toShapesNoHoles (line 36611) | function toShapesNoHoles( inSubpaths ) {
  function isPointInsidePolygon (line 36633) | function isPointInsidePolygon( inPt, inPolygon ) {
  function CubicPoly (line 37321) | function CubicPoly() {
  function calculateVertexCount (line 37589) | function calculateVertexCount ( w, h, d ) {
  function calculateIndexCount (line 37602) | function calculateIndexCount ( w, h, d ) {
  function buildPlane (line 37615) | function buildPlane ( u, v, w, udir, vdir, width, height, depth, gridX, ...
  function calculateVertexCount (line 37906) | function calculateVertexCount() {
  function calculateIndexCount (line 37920) | function calculateIndexCount() {
  function generateTorso (line 37934) | function generateTorso() {
  function generateCap (line 38034) | function generateCap( top ) {
  function sortFunction (line 38257) | function sortFunction( a, b ) {
  function scalePt2 (line 38515) | function scalePt2 ( pt, vec, size ) {
  function getBevelVec (line 38531) | function getBevelVec( inPt, inPrev, inNext ) {
  function buildLidFaces (line 38851) | function buildLidFaces() {
  function buildSideFaces (line 38905) | function buildSideFaces() {
  function sidewalls (line 38923) | function sidewalls( contour, layeroffset ) {
  function v (line 38957) | function v( x, y, z ) {
  function f3 (line 38963) | function f3( a, b, c ) {
  function f4 (line 38977) | function f4( a, b, c, d, wallContour, stepIndex, stepsLength, contourInd...
  function calculatePositionOnCurve (line 40147) | function calculatePositionOnCurve( u, p, q, radius, position ) {
  function vert (line 40262) | function vert( x, y, z ) {
  function initialNormal3 (line 40414) | function initialNormal3() {
  function prepare (line 40605) | function prepare( vector ) {
  function make (line 40623) | function make( v1, v2, v3 ) {
  function subdivide (line 40643) | function subdivide( face, detail ) {
  function azimuth (line 40712) | function azimuth( vector ) {
  function inclination (line 40721) | function inclination( vector ) {
  function correctUV (line 40730) | function correctUV( uv, vector, azimuth ) {
  function sortFunction (line 41002) | function sortFunction( a, b ) {
  function addLine (line 41513) | function addLine( a, b, hex ) {
  function addPoint (line 41520) | function addPoint( id, hex ) {
  function setPoint (line 41559) | function setPoint( point, x, y, z ) {
  function defineProperties (line 42833) | function defineProperties(target, props) { for (var i = 0; i < props.len...
  function _interopRequireDefault (line 42839) | function _interopRequireDefault(obj) { return obj && obj.__esModule ? ob...
  function _classCallCheck (line 42841) | function _classCallCheck(instance, Constructor) { if (!(instance instanc...
  function _possibleConstructorReturn (line 42843) | function _possibleConstructorReturn(self, call) { if (!self) { throw new...
  function _inherits (line 42845) | function _inherits(subClass, superClass) { if (typeof superClass !== "fu...
  function Player (line 42857) | function Player() {
  function defineProperties (line 42962) | function defineProperties(target, props) { for (var i = 0; i < props.len...
  function _classCallCheck (line 42964) | function _classCallCheck(instance, Constructor) { if (!(instance instanc...
  function Mathf (line 42967) | function Mathf() {
  function defineProperties (line 43024) | function defineProperties(target, props) { for (var i = 0; i < props.len...
  function _interopRequireDefault (line 43030) | function _interopRequireDefault(obj) { return obj && obj.__esModule ? ob...
  function _classCallCheck (line 43032) | function _classCallCheck(instance, Constructor) { if (!(instance instanc...
  function _possibleConstructorReturn (line 43034) | function _possibleConstructorReturn(self, call) { if (!self) { throw new...
  function _inherits (line 43036) | function _inherits(subClass, superClass) { if (typeof superClass !== "fu...
  function TerrainPatch (line 43045) | function TerrainPatch(opts) {
  function defineProperties (line 43360) | function defineProperties(target, props) { for (var i = 0; i < props.len...
  function _interopRequireDefault (line 43366) | function _interopRequireDefault(obj) { return obj && obj.__esModule ? ob...
  function _classCallCheck (line 43368) | function _classCallCheck(instance, Constructor) { if (!(instance instanc...
  function Heightmap (line 43378) | function Heightmap(opts) {
  function fade (line 43458) | function fade(t) {
  function lerp (line 43463) | function lerp(t, a, b) {
  function grad (line 43468) | function grad(hash, x, y, z) {
  function defineProperties (line 43524) | function defineProperties(target, props) { for (var i = 0; i < props.len...
  function _interopRequireDefault (line 43530) | function _interopRequireDefault(obj) { return obj && obj.__esModule ? ob...
  function _classCallCheck (line 43532) | function _classCallCheck(instance, Constructor) { if (!(instance instanc...
  function _possibleConstructorReturn (line 43534) | function _possibleConstructorReturn(self, call) { if (!self) { throw new...
  function _inherits (line 43536) | function _inherits(subClass, superClass) { if (typeof superClass !== "fu...
  function Bird (line 43546) | function Bird() {
  function DOMEval (line 43688) | function DOMEval( code, doc ) {
  function isArrayLike (line 44139) | function isArrayLike( obj ) {
  function Sizzle (line 44371) | function Sizzle( selector, context, results, seed ) {
  function createCache (line 44510) | function createCache() {
  function markFunction (line 44528) | function markFunction( fn ) {
  function assert (line 44537) | function assert( fn ) {
  function addHandle (line 44559) | function addHandle( attrs, handler ) {
  function siblingCheck (line 44574) | function siblingCheck( a, b ) {
  function createInputPseudo (line 44600) | function createInputPseudo( type ) {
  function createButtonPseudo (line 44611) | function createButtonPseudo( type ) {
  function createDisabledPseudo (line 44622) | function createDisabledPseudo( disabled ) {
  function createPositionalPseudo (line 44650) | function createPositionalPseudo( fn ) {
  function testContext (line 44673) | function testContext( context ) {
  function setFilters (line 45729) | function setFilters() {}
  function toSelector (line 45800) | function toSelector( tokens ) {
  function addCombinator (line 45810) | function addCombinator( matcher, combinator, base ) {
  function elementMatcher (line 45872) | function elementMatcher( matchers ) {
  function multipleContexts (line 45886) | function multipleContexts( selector, contexts, results ) {
  function condense (line 45895) | function condense( unmatched, map, filter, context, xml ) {
  function setMatcher (line 45916) | function setMatcher( preFilter, selector, matcher, postFilter, postFinde...
  function matcherFromTokens (line 46009) | function matcherFromTokens( tokens ) {
  function matcherFromGroupMatchers (line 46067) | function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
  function winnow (line 46409) | function winnow( elements, qualifier, not ) {
  function sibling (line 46705) | function sibling( cur, dir ) {
  function createOptions (line 46781) | function createOptions( options ) {
  function Identity (line 47006) | function Identity( v ) {
  function Thrower (line 47009) | function Thrower( ex ) {
  function adoptValue (line 47013) | function adoptValue( value, resolve, reject ) {
  function resolve (line 47105) | function resolve( depth, deferred, handler, special ) {
  function completed (line 47471) | function completed() {
  function Data (line 47570) | function Data() {
  function dataAttr (line 47739) | function dataAttr( elem, key, data ) {
  function adjustCSS (line 48059) | function adjustCSS( elem, prop, valueParts, tween ) {
  function getDefaultDisplay (line 48124) | function getDefaultDisplay( elem ) {
  function showHide (line 48147) | function showHide( elements, show ) {
  function getAll (line 48248) | function getAll( context, tag ) {
  function setGlobalEval (line 48265) | function setGlobalEval( elems, refElements ) {
  function buildFragment (line 48281) | function buildFragment( elems, context, scripts, selection, ignored ) {
  function returnTrue (line 48404) | function returnTrue() {
  function returnFalse (line 48408) | function returnFalse() {
  function safeActiveElement (line 48414) | function safeActiveElement() {
  function on (line 48420) | function on( elem, types, selector, data, fn, one ) {
  function manipulationTarget (line 49129) | function manipulationTarget( elem, content ) {
  function disableScript (line 49140) | function disableScript( elem ) {
  function restoreScript (line 49144) | function restoreScript( elem ) {
  function cloneCopyEvent (line 49156) | function cloneCopyEvent( src, dest ) {
  function fixInput (line 49191) | function fixInput( src, dest ) {
  function domManip (line 49204) | function domManip( collection, args, callback, ignored ) {
  function remove (line 49294) | function remove( elem, selector, keepData ) {
  function computeStyleTests (line 49587) | function computeStyleTests() {
  function curCSS (line 49661) | function curCSS( elem, name, computed ) {
  function addGetHookIf (line 49708) | function addGetHookIf( conditionFn, hookFn ) {
  function vendorPropName (line 49744) | function vendorPropName( name ) {
  function setPositiveNumber (line 49763) | function setPositiveNumber( elem, value, subtract ) {
  function augmentWidthOrHeight (line 49775) | function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
  function getWidthOrHeight (line 49819) | function getWidthOrHeight( elem, name, extra ) {
  function Tween (line 50127) | function Tween( elem, options, prop, end, easing ) {
  function raf (line 50250) | function raf() {
  function createFxNow (line 50258) | function createFxNow() {
  function genFx (line 50266) | function genFx( type, includeWidth ) {
  function createTween (line 50286) | function createTween( value, prop, animation ) {
  function defaultPrefilter (line 50300) | function defaultPrefilter( elem, props, opts ) {
  function propFilter (line 50471) | function propFilter( props, specialEasing ) {
  function Animation (line 50508) | function Animation( elem, properties, options ) {
  function getClass (line 51199) | function getClass( elem ) {
  function buildParams (line 51824) | function buildParams( prefix, obj, traditional, add ) {
  function addToPrefiltersOrTransports (line 51970) | function addToPrefiltersOrTransports( structure ) {
  function inspectPrefiltersOrTransports (line 52004) | function inspectPrefiltersOrTransports( structure, options, originalOpti...
  function ajaxExtend (line 52033) | function ajaxExtend( target, src ) {
  function ajaxHandleResponses (line 52053) | function ajaxHandleResponses( s, jqXHR, responses ) {
  function ajaxConvert (line 52111) | function ajaxConvert( s, response, jqXHR, isSuccess ) {
  function done (line 52624) | function done( status, nativeStatusText, responses, headers ) {
  function getWindow (line 53349) | function getWindow( elem ) {
  function loadImage (line 54010) | function loadImage( url ) {
  function parseConstant (line 54046) | function parseConstant( value ) {
  function getGeometry (line 54113) | function getGeometry( name ) {
  function getMaterial (line 54125) | function getMaterial( name ) {
  function getAutoRotationAngle (line 54581) | function getAutoRotationAngle() {
  function getZoomScale (line 54587) | function getZoomScale() {
  function rotateLeft (line 54593) | function rotateLeft( angle ) {
  function rotateUp (line 54599) | function rotateUp( angle ) {
  function dollyIn (line 54676) | function dollyIn( dollyScale ) {
  function dollyOut (line 54697) | function dollyOut( dollyScale ) {
  function handleMouseDownRotate (line 54722) | function handleMouseDownRotate( event ) {
  function handleMouseDownDolly (line 54730) | function handleMouseDownDolly( event ) {
  function handleMouseDownPan (line 54738) | function handleMouseDownPan( event ) {
  function handleMouseMoveRotate (line 54746) | function handleMouseMoveRotate( event ) {
  function handleMouseMoveDolly (line 54767) | function handleMouseMoveDolly( event ) {
  function handleMouseMovePan (line 54791) | function handleMouseMovePan( event ) {
  function handleMouseUp (line 54807) | function handleMouseUp( event ) {
  function handleMouseWheel (line 54813) | function handleMouseWheel( event ) {
  function handleKeyDown (line 54847) | function handleKeyDown( event ) {
  function handleTouchStartRotate (line 54877) | function handleTouchStartRotate( event ) {
  function handleTouchStartDolly (line 54885) | function handleTouchStartDolly( event ) {
  function handleTouchStartPan (line 54898) | function handleTouchStartPan( event ) {
  function handleTouchMoveRotate (line 54906) | function handleTouchMoveRotate( event ) {
  function handleTouchMoveDolly (line 54927) | function handleTouchMoveDolly( event ) {
  function handleTouchMovePan (line 54956) | function handleTouchMovePan( event ) {
  function handleTouchEnd (line 54972) | function handleTouchEnd( event ) {
  function onMouseDown (line 54982) | function onMouseDown( event ) {
  function onMouseMove (line 55026) | function onMouseMove( event ) {
  function onMouseUp (line 55054) | function onMouseUp( event ) {
  function onMouseWheel (line 55070) | function onMouseWheel( event ) {
  function onKeyDown (line 55084) | function onKeyDown( event ) {
  function onTouchStart (line 55092) | function onTouchStart( event ) {
  function onTouchMove (line 55142) | function onTouchMove( event ) {
  function onTouchEnd (line 55186) | function onTouchEnd( event ) {
  function onContextMenu (line 55198) | function onContextMenu( event ) {
  function memcpy (line 55528) | function memcpy(src, srcOffset, dst, dstOffset, length) {
  function check (line 55592) | function check(v, d) {

FILE: lib/THREE.MeshLine.js
  function memcpy (line 175) | function memcpy( src, srcOffset, dst, dstOffset, length ) {
  function check (line 352) | function check( v, d ) {

FILE: src/FBXLoader.js
  function FBXNodes (line 558) | function FBXNodes() {}
  function FBXParser (line 698) | function FBXParser() {}
  function FBXAnalyzer (line 1093) | function FBXAnalyzer() {}
  function Weights (line 1103) | function Weights() {
  function Bones (line 1234) | function Bones() {
  function Geometry (line 1523) | function Geometry() {
  function UV (line 1741) | function UV() {
  function Normal (line 1966) | function Normal() {
  function AnimationCurve (line 2164) | function AnimationCurve() {
  function AnimationNode (line 2209) | function AnimationNode() {
  function Animation (line 2291) | function Animation() {
  function Textures (line 2389) | function Textures() {
  function Texture (line 2441) | function Texture() {
  function loadTextureImage (line 2498) | function loadTextureImage( texture, url ) {
  function parse_Data_ByPolygonVertex_IndexToDirect (line 2540) | function parse_Data_ByPolygonVertex_IndexToDirect( node, indices, itemSi...
  function mapByPolygonVertexToByVertex (line 2615) | function mapByPolygonVertexToByVertex( data, indices, stride ) {

FILE: src/ImprovedNoise.js
  function fade (line 22) | function fade( t ) {
  function lerp (line 28) | function lerp( t, a, b ) {
  function grad (line 34) | function grad( hash, x, y, z ) {

FILE: src/classes/bird.js
  constant FLIGHT_SPEED (line 21) | const FLIGHT_SPEED = 30;
  constant FLOCK_DIST (line 22) | const FLOCK_DIST = 16;
  constant PLAYER_SEP_DIST (line 23) | const PLAYER_SEP_DIST = 80;
  constant SEPARATION_FORCE (line 24) | const SEPARATION_FORCE = 100;
  class Bird (line 26) | class Bird extends THREE.Mesh {
    method constructor (line 27) | constructor() {
    method update (line 49) | update(dt, center, player) {

FILE: src/classes/heightmap.js
  constant VALLEY_01_SCALE (line 23) | const VALLEY_01_SCALE = 0.025;
  constant VALLEY_02_SCALE (line 24) | const VALLEY_02_SCALE = 0.01;
  constant VALLEY_01_MULT (line 25) | const VALLEY_01_MULT = 1.0;
  constant VALLEY_02_MULT (line 26) | const VALLEY_02_MULT = 0.5;
  constant HEIGHT_MULT (line 27) | const HEIGHT_MULT = 10.0;
  constant RIVER_WIDTH (line 28) | const RIVER_WIDTH = 100.0;
  class Heightmap (line 30) | class Heightmap {
    method constructor (line 32) | constructor( opts ) {
    method lerp (line 40) | lerp( from, to, t ) {
    method clamp (line 44) | clamp( val, min, max ) {
    method getHeight (line 49) | getHeight( x, y ) {
    method perlinNoise (line 66) | perlinNoise( x, y, frequency ) {
    method step (line 74) | step( height, steps ) {

FILE: src/classes/mathf.js
  class Mathf (line 27) | class Mathf {
    method clamp (line 28) | static clamp( num, min, max ) {
    method getCount (line 32) | static getCount() {
    method lerp (line 36) | static lerp( from, to, t ) {
    method inverseLerp (line 40) | static inverseLerp( from, to, t ) {
    method randRange (line 51) | static randRange( min, max ) {
    method randRange2 (line 55) | static randRange2( min, max ) {
    method moveTowards (line 59) | static moveTowards( current, target, maxDelta ) {

FILE: src/classes/player.js
  constant FLIGHT_SPEED (line 23) | const FLIGHT_SPEED = 12;
  constant BANK_SPEED (line 24) | const BANK_SPEED = 0.5;
  constant SPIN_SPEED (line 25) | const SPIN_SPEED = 1;
  constant SIDEWAYS_SPEED (line 26) | const SIDEWAYS_SPEED = 5;
  constant FLAG_ADJUST_SPEED (line 27) | const FLAG_ADJUST_SPEED = 55;
  constant SCARF_SEG_DIST (line 28) | const SCARF_SEG_DIST = 0.3;
  class Player (line 30) | class Player extends THREE.Object3D {
    method constructor (line 31) | constructor() {
    method initScarf (line 47) | initScarf() {
    method update (line 70) | update() {

FILE: src/classes/random.js
  class Random (line 23) | class Random {
    method constructor (line 24) | constructor( seed ) {
    method range (line 29) | range( min, max ) {

FILE: src/classes/terrain-patch.js
  constant SEGS_X (line 23) | const SEGS_X = 8;
  constant SEGS_Y (line 24) | const SEGS_Y = 8;
  constant VERTS_X (line 25) | const VERTS_X = SEGS_X + 1;
  class TerrainPatch (line 27) | class TerrainPatch extends THREE.Mesh {
    method constructor (line 28) | constructor(opts) {
    method rebuild (line 67) | rebuild(scene) {
    method getNiceHeightmapData (line 103) | getNiceHeightmapData() {
    method addScatterObject (line 127) | addScatterObject(opts) {
    method createScatterGeometry (line 142) | createScatterGeometry(opts) {
    method getPosition (line 258) | getPosition(coord) {
    method containsWorldPosition (line 290) | containsWorldPosition(coord) {
    method getNormal (line 307) | getNormal(coord) {
    method createGeometry (line 349) | createGeometry() {

FILE: src/index.js
  function onchange (line 178) | function onchange(evt) {
Condensed preview — 45 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (3,414K chars).
[
  {
    "path": ".gitignore",
    "chars": 5,
    "preview": "dist\n"
  },
  {
    "path": "LICENSE",
    "chars": 1073,
    "preview": "MIT License\n\nCopyright (c) 2019 Alexander Perrin\n\nPermission is hereby granted, free of charge, to any person obtaining "
  },
  {
    "path": "README.md",
    "chars": 1819,
    "preview": "# Ballooning with Three.js\nThis was developed as a study into procedural terrains, buffer geometry optimisation and shad"
  },
  {
    "path": "bundle.js",
    "chars": 1387475,
    "preview": "/******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n\n/*"
  },
  {
    "path": "lib/Detector.js",
    "chars": 2076,
    "preview": "/**\n * @author alteredq / http://alteredqualia.com/\n * @author mr.doob / http://mrdoob.com/\n */\n\nvar Detector = {\n\n\tcanv"
  },
  {
    "path": "lib/THREE.MeshLine.js",
    "chars": 13198,
    "preview": "( function () {\n\n  THREE.MeshLine = function () {\n\n    this.positions = [];\n\n    this.previous = [];\n    this.next = [];"
  },
  {
    "path": "package.json",
    "chars": 1237,
    "preview": "{\n  \"name\": \"threejs-ballooning\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Experiment using Three.js\",\n  \"main\": \"index.j"
  },
  {
    "path": "public/index.html",
    "chars": 600,
    "preview": "<!DOCTYPE html>\n<html>\n  <head>\n    <title>Three.js Ballooning - Alexander Perrin</title>\n    <meta charset=\"utf-8\" />\n "
  },
  {
    "path": "public/static/app.css",
    "chars": 1435,
    "preview": "@-moz-keyframes spin {\n    100% {\n        -moz-transform: rotate(360deg);\n    }\n}\n\n@-webkit-keyframes spin {\n    100% {\n"
  },
  {
    "path": "public/static/meshes/balloon.json",
    "chars": 738618,
    "preview": "{\n\t\"metadata\": {\n\t\t\"version\": 4.4,\n\t\t\"type\": \"Object\",\n\t\t\"generator\": \"Object3D.toJSON\"\n\t},\n\t\"geometries\": [\n\t\t{\n\t\t\t\"uui"
  },
  {
    "path": "public/static/meshes/boat01.json",
    "chars": 86852,
    "preview": "{\n\t\"metadata\": {\n\t\t\"version\": 4.4,\n\t\t\"type\": \"Object\",\n\t\t\"generator\": \"Object3D.toJSON\"\n\t},\n\t\"geometries\": [\n\t\t{\n\t\t\t\"uui"
  },
  {
    "path": "public/static/meshes/church01.json",
    "chars": 21687,
    "preview": "{\n\t\"metadata\": {\n\t\t\"version\": 4.4,\n\t\t\"type\": \"Object\",\n\t\t\"generator\": \"Object3D.toJSON\"\n\t},\n\t\"geometries\": [\n\t\t{\n\t\t\t\"uui"
  },
  {
    "path": "public/static/meshes/model.json",
    "chars": 21999,
    "preview": "{\n\t\"metadata\": {\n\t\t\"version\": 4.4,\n\t\t\"type\": \"Object\",\n\t\t\"generator\": \"Object3D.toJSON\"\n\t},\n\t\"geometries\": [\n\t\t{\n\t\t\t\"uui"
  },
  {
    "path": "public/static/meshes/pier01.json",
    "chars": 41023,
    "preview": "{\n\t\"metadata\": {\n\t\t\"version\": 4.4,\n\t\t\"type\": \"Object\",\n\t\t\"generator\": \"Object3D.toJSON\"\n\t},\n\t\"geometries\": [\n\t\t{\n\t\t\t\"uui"
  },
  {
    "path": "public/static/meshes/plane.json",
    "chars": 172352,
    "preview": "{\n\t\"metadata\": {\n\t\t\"version\": 4.4,\n\t\t\"type\": \"Object\",\n\t\t\"generator\": \"Object3D.toJSON\"\n\t},\n\t\"geometries\": [\n\t\t{\n\t\t\t\"uui"
  },
  {
    "path": "public/static/meshes/tree.json",
    "chars": 89515,
    "preview": "{\n\t\"metadata\": {\n\t\t\"version\": 4.4,\n\t\t\"type\": \"Object\",\n\t\t\"generator\": \"Object3D.toJSON\"\n\t},\n\t\"geometries\": [\n\t\t{\n\t\t\t\"uui"
  },
  {
    "path": "resources/balloon.fbx",
    "chars": 187201,
    "preview": "; FBX 7.4.0 project file\n; Copyright (C) 1997-2010 Autodesk Inc. and/or its licensors.\n; All rights reserved.\n; --------"
  },
  {
    "path": "resources/dae/balloon.dae",
    "chars": 153167,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<COLLADA xmlns=\"http://www.collada.org/2005/11/COLLADASchema\" version=\"1.4.1\">\n "
  },
  {
    "path": "resources/dae/boat01.dae",
    "chars": 35083,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<COLLADA xmlns=\"http://www.collada.org/2005/11/COLLADASchema\" version=\"1.4.1\">\n  "
  },
  {
    "path": "resources/dae/church01.dae",
    "chars": 13584,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<COLLADA xmlns=\"http://www.collada.org/2005/11/COLLADASchema\" version=\"1.4.1\">\n  "
  },
  {
    "path": "resources/dae/pier01.dae",
    "chars": 17140,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<COLLADA xmlns=\"http://www.collada.org/2005/11/COLLADASchema\" version=\"1.4.1\">\n  "
  },
  {
    "path": "resources/dae/plane.dae",
    "chars": 61003,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<COLLADA xmlns=\"http://www.collada.org/2005/11/COLLADASchema\" version=\"1.4.1\">\n "
  },
  {
    "path": "resources/dae/tree.dae",
    "chars": 32959,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<COLLADA xmlns=\"http://www.collada.org/2005/11/COLLADASchema\" version=\"1.4.1\">\n "
  },
  {
    "path": "src/FBXLoader.js",
    "chars": 62703,
    "preview": "/**\n * @author yamahigashi https://github.com/yamahigashi\n *\n * This loader loads FBX file in *ASCII and version 7 forma"
  },
  {
    "path": "src/ImprovedNoise.js",
    "chars": 2793,
    "preview": "// http://mrl.nyu.edu/~perlin/noise/\n\nvar ImprovedNoise = function () {\n\n  var p = [ 151, 160, 137, 91, 90, 15, 131, 13,"
  },
  {
    "path": "src/classes/bird.js",
    "chars": 3267,
    "preview": "// Copyright (c) 2019 Alexander Perrin contact@alexperrin.com\n\n// Permission is hereby granted, free of charge, to any p"
  },
  {
    "path": "src/classes/heightmap.js",
    "chars": 2893,
    "preview": "// Copyright (c) 2019 Alexander Perrin contact@alexperrin.com\n\n// Permission is hereby granted, free of charge, to any p"
  },
  {
    "path": "src/classes/mathf.js",
    "chars": 2104,
    "preview": "// Copyright (c) 2019 Alexander Perrin contact@alexperrin.com\n\n// Permission is hereby granted, free of charge, to any p"
  },
  {
    "path": "src/classes/player.js",
    "chars": 4271,
    "preview": "// Copyright (c) 2019 Alexander Perrin contact@alexperrin.com\n\n// Permission is hereby granted, free of charge, to any p"
  },
  {
    "path": "src/classes/random.js",
    "chars": 1390,
    "preview": "// Copyright (c) 2019 Alexander Perrin contact@alexperrin.com\n\n// Permission is hereby granted, free of charge, to any p"
  },
  {
    "path": "src/classes/terrain-patch.js",
    "chars": 12815,
    "preview": "// Copyright (c) 2019 Alexander Perrin contact@alexperrin.com\n\n// Permission is hereby granted, free of charge, to any p"
  },
  {
    "path": "src/index.js",
    "chars": 30149,
    "preview": "// Copyright (c) 2019 Alexander Perrin contact@alexperrin.com\n\n// Permission is hereby granted, free of charge, to any p"
  },
  {
    "path": "src/shaders/landscape_frag.glsl",
    "chars": 2464,
    "preview": "#define PHONG\n\nuniform vec3 cliffColor;\nuniform vec3 grassColor;\nuniform vec3 sandColor;\nuniform vec3 emissive;\nuniform "
  },
  {
    "path": "src/shaders/landscape_vert.glsl",
    "chars": 931,
    "preview": "#define PHONG\n\nvarying vec3 vViewPosition;\nvarying vec3 vWorldNormal;\nvarying vec3 vWorldPos;\n\n#ifndef FLAT_SHADED\n\n\tvar"
  },
  {
    "path": "src/shaders/standard_frag.glsl",
    "chars": 1988,
    "preview": "#define PHONG\n\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform floa"
  },
  {
    "path": "src/shaders/standard_vert.glsl",
    "chars": 1199,
    "preview": "#define PHONG\n\nvarying vec3 vViewPosition;\nvarying vec3 vWorldPos;\n\n#ifndef FLAT_SHADED\n\n\tvarying vec3 vNormal;\n\n#endif\n"
  },
  {
    "path": "webpack.common.js",
    "chars": 806,
    "preview": "const path = require(\"path\");\nconst HtmlWebpackPlugin = require(\"html-webpack-plugin\");\nconst CleanWebpackPlugin = requi"
  },
  {
    "path": "webpack.dev.js",
    "chars": 244,
    "preview": "const merge = require(\"webpack-merge\");\nconst common = require(\"./webpack.common.js\");\n\nmodule.exports = merge(common, {"
  },
  {
    "path": "webpack.prod.js",
    "chars": 381,
    "preview": "const merge = require(\"webpack-merge\");\nconst common = require(\"./webpack.common.js\");\nconst MinifyPlugin = require(\"bab"
  }
]

// ... and 6 more files (download for full content)

About this extraction

This page contains the full source code of the alexanderperrin/threejs-ballooning GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 45 files (3.1 MB), approximately 804.6k tokens, and a symbol index with 438 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!