diff --git a/build/vr.dev.js b/build/vr.dev.js
index 25bafd0..adfb2ec 100644
--- a/build/vr.dev.js
+++ b/build/vr.dev.js
@@ -44,7 +44,7 @@
/* 0 */
/***/ function(module, exports, __webpack_require__) {
- eval("(function () {\n\t'use strict';\n\n\t//global-ish declarations\n\tvar VR,\n\t\tNoSleep = __webpack_require__(1).NoSleep;\n\n\tfunction initRequirements() {\n\t\t//load styles\n\t\t__webpack_require__(2);\n\n\t\tVR = __webpack_require__(6);\n\t}\n\n\tfunction initUI() {\n\t\tvar container,\n\t\t\tenableFullscreen,\n\t\t\tdisableFullscreen,\n\t\t\tvrButton,\n\t\t\torientationButton,\n\t\t\telement,\n\n\t\t\tnoSleep = new NoSleep(),\n\n\t\t\tfullScreenElement = document.body,\n\n\t\t\tfullscreenEnabled = document.fullscreenEnabled ||\n\t\t\t\tdocument.webkitFullscreenEnabled ||\n\t\t\t\tdocument.mozFullScreenEnabled ||\n\t\t\t\tdocument.msFullscreenEnabled,\n\n\t\t\trequestFullscreen = fullScreenElement.webkitRequestFullscreen ||\n\t\t\t\tfullScreenElement.mozRequestFullScreen ||\n\t\t\t\tfullScreenElement.msRequestFullscreen;\n\n\t\tfunction svgButton(source, id) {\n\t\t\tvar span = document.createElement('span'),\n\t\t\t\tsvg;\n\n\t\t\tspan.innerHTML = source;\n\t\t\tspan.id = id;\n\n\t\t\tsvg = span.firstChild;\n\t\t\tsvg.setAttribute('width', 18);\n\t\t\tsvg.setAttribute('height', 18);\n\n\t\t\tcontainer.appendChild(span);\n\n\t\t\treturn span;\n\t\t}\n\n\t\tfunction toggleOrientation() {\n\t\t\tif (VR.orientationEnabled()) {\n\t\t\t\tVR.disableOrientation();\n\t\t\t} else {\n\t\t\t\tVR.enableOrientation();\n\t\t\t}\n\t\t}\n\n\t\tfunction deviceChange() {\n\t\t\tif (VR.controlMode()) {\n\t\t\t\tvrButton.classList.remove('unsupported');\n\t\t\t\torientationButton.classList.remove('unsupported');\n\t\t\t}\n\n\t\t\t//todo: enable this\n\t\t\t//info.innerHTML = hmd && hmd.deviceName ? 'HMD: ' + hmd.deviceName : '';\n\t\t\t//info.className = hmd && hmd.deviceId !== 'debug-0' ? 'has-hmd' : '';\n\t\t}\n\n\t\t//set up meta viewport tag for mobile devices\n\t\telement = document.createElement('meta');\n\t\telement.setAttribute('name', 'viewport');\n\t\telement.setAttribute('content', 'width=device-width, initial-scale=1, user-scalable=no');\n\t\tdocument.head.appendChild(element);\n\n\t\tcontainer = document.createElement('div');\n\t\tcontainer.id = 'buttons';\n\t\tdocument.body.appendChild(container);\n\n\t\t//todo: use icons instead of text\n\t\tif (requestFullscreen && fullscreenEnabled) {\n\t\t\tenableFullscreen = svgButton(__webpack_require__(79), 'fs-enable');\n\t\t\tenableFullscreen.setAttribute('title', 'Enable Full Screen');\n\t\t\tenableFullscreen.addEventListener('click', requestFullscreen.bind(fullScreenElement), false);\n\n\t\t\tdisableFullscreen = svgButton(__webpack_require__(80), 'fs-disable');\n\t\t\tdisableFullscreen.setAttribute('title', 'Exit Full Screen');\n\t\t\tdisableFullscreen.addEventListener('click', VR.exitFullscreen, false);\n\t\t}\n\n\t\tVR.on('fullscreenchange', function () {\n\t\t\tif (VR.isFullscreen()) {\n\t\t\t\tdisableFullscreen.style.display = 'inline-block';\n\t\t\t\tenableFullscreen.style.display = 'none';\n\t\t\t} else {\n\t\t\t\tdisableFullscreen.style.display = '';\n\t\t\t\tenableFullscreen.style.display = '';\n\t\t\t}\n\n\t\t\t//disable sleep on mobile devices in VR mode\n\t\t\tif (VR.vrMode()) {\n\t\t\t\tnoSleep.enable();\n\t\t\t} else {\n\t\t\t\tnoSleep.disable();\n\t\t\t}\n\t\t});\n\n\t\tvrButton = svgButton(__webpack_require__(81), 'vr');\n\t\tvrButton.setAttribute('title', 'Toggle Virtual Reality');\n\t\tvrButton.className = 'unsupported';\n\t\tvrButton.addEventListener('click', VR.requestVR, false);\n\n\t\torientationButton = svgButton(__webpack_require__(82), 'orientation');\n\t\torientationButton.setAttribute('title', 'Toggle Orientation');\n\t\torientationButton.className = 'unsupported';\n\t\torientationButton.addEventListener('click', toggleOrientation, false);\n\n\t\t//report on HMD\n\t\tVR.on('devicechange', deviceChange);\n\t\tdeviceChange();\n\n\t\t//keyboard shortcuts for making life a little easier\n\t\twindow.addEventListener('keydown', function (evt) {\n\t\t\tif (evt.keyCode === 'Z'.charCodeAt(0)) {\n\t\t\t\tVR.zeroSensor();\n\t\t\t} else if (evt.keyCode === 'O'.charCodeAt(0)) {\n\t\t\t\tVR.enableOrientation();\n\t\t\t} else if (evt.keyCode === 13) {\n\t\t\t\tVR.requestVR();\n\t\t\t}\n\t\t}, false);\n\n\t\tVR.resize();\n\t}\n\n\tfunction initialize() {\n\t\tinitRequirements();\n\n\t\t//todo: set up button/info elements\n\n\t\tVR.init();\n\n\t\tif (document.body) {\n\t\t\tinitUI();\n\t\t} else {\n\t\t\twindow.addEventListener('load', initUI, false);\n\t\t}\n\n\t\twindow.addEventListener('resize', VR.resize, false);\n\n\t\t/*\n\t\texport global things\n\t\t*/\n\t\twindow.VR = VR;\n\t\twindow.THREE = VR.THREE;\n\t}\n\n\tinitialize();\n\tVR.start();\n}());\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/entry.js\n ** module id = 0\n ** module chunks = 0\n **/\n//# sourceURL=webpack:///./src/entry.js?");
+ eval("(function () {\n\t'use strict';\n\n\t//global-ish declarations\n\tvar VR,\n\t\tNoSleep = __webpack_require__(1).NoSleep;\n\n\tfunction initRequirements() {\n\t\t//load styles\n\t\t__webpack_require__(2);\n\n\t\tVR = __webpack_require__(6);\n\t}\n\n\tfunction initUI() {\n\t\tvar container,\n\t\t\tenableFullscreen,\n\t\t\tdisableFullscreen,\n\t\t\tvrButton,\n\t\t\torientationButton,\n\t\t\telement,\n\n\t\t\tnoSleep = new NoSleep(),\n\n\t\t\tfullScreenElement = document.body,\n\n\t\t\tfullscreenEnabled = document.fullscreenEnabled ||\n\t\t\t\tdocument.webkitFullscreenEnabled ||\n\t\t\t\tdocument.mozFullScreenEnabled ||\n\t\t\t\tdocument.msFullscreenEnabled,\n\n\t\t\trequestFullscreen = fullScreenElement.webkitRequestFullscreen ||\n\t\t\t\tfullScreenElement.mozRequestFullScreen ||\n\t\t\t\tfullScreenElement.msRequestFullscreen;\n\n\t\tfunction svgButton(source, id) {\n\t\t\tvar span = document.createElement('span'),\n\t\t\t\tsvg;\n\n\t\t\tspan.innerHTML = source;\n\t\t\tspan.id = id;\n\n\t\t\tsvg = span.firstChild;\n\t\t\tsvg.setAttribute('width', 18);\n\t\t\tsvg.setAttribute('height', 18);\n\n\t\t\tcontainer.appendChild(span);\n\n\t\t\treturn span;\n\t\t}\n\n\t\tfunction toggleOrientation() {\n\t\t\tif (VR.orientationEnabled()) {\n\t\t\t\tVR.disableOrientation();\n\t\t\t} else {\n\t\t\t\tVR.enableOrientation();\n\t\t\t}\n\t\t}\n\n\t\tfunction deviceChange() {\n\t\t\tif (VR.controlMode()) {\n\t\t\t\tvrButton.classList.remove('unsupported');\n\t\t\t\torientationButton.classList.remove('unsupported');\n\t\t\t}\n\n\t\t\t//todo: enable this\n\t\t\t//info.innerHTML = hmd && hmd.deviceName ? 'HMD: ' + hmd.deviceName : '';\n\t\t\t//info.className = hmd && hmd.deviceId !== 'debug-0' ? 'has-hmd' : '';\n\t\t}\n\n\t\t//set up meta viewport tag for mobile devices\n\t\telement = document.createElement('meta');\n\t\telement.setAttribute('name', 'viewport');\n\t\telement.setAttribute('content', 'width=device-width, initial-scale=1, user-scalable=no');\n\t\tdocument.head.appendChild(element);\n\n\t\tcontainer = document.createElement('div');\n\t\tcontainer.id = 'buttons';\n\t\tdocument.body.appendChild(container);\n\n\t\t//todo: use icons instead of text\n\t\tif (requestFullscreen && fullscreenEnabled) {\n\t\t\tenableFullscreen = svgButton(__webpack_require__(80), 'fs-enable');\n\t\t\tenableFullscreen.setAttribute('title', 'Enable Full Screen');\n\t\t\tenableFullscreen.addEventListener('click', requestFullscreen.bind(fullScreenElement), false);\n\n\t\t\tdisableFullscreen = svgButton(__webpack_require__(81), 'fs-disable');\n\t\t\tdisableFullscreen.setAttribute('title', 'Exit Full Screen');\n\t\t\tdisableFullscreen.addEventListener('click', VR.exitFullscreen, false);\n\t\t}\n\n\t\tVR.on('fullscreenchange', function () {\n\t\t\tif (VR.isFullscreen()) {\n\t\t\t\tdisableFullscreen.style.display = 'inline-block';\n\t\t\t\tenableFullscreen.style.display = 'none';\n\t\t\t} else {\n\t\t\t\tdisableFullscreen.style.display = '';\n\t\t\t\tenableFullscreen.style.display = '';\n\t\t\t}\n\n\t\t\t//disable sleep on mobile devices in VR mode\n\t\t\tif (VR.vrMode()) {\n\t\t\t\tnoSleep.enable();\n\t\t\t} else {\n\t\t\t\tnoSleep.disable();\n\t\t\t}\n\t\t});\n\n\t\tvrButton = svgButton(__webpack_require__(82), 'vr');\n\t\tvrButton.setAttribute('title', 'Toggle Virtual Reality');\n\t\tvrButton.className = 'unsupported';\n\t\tvrButton.addEventListener('click', VR.requestVR, false);\n\n\t\torientationButton = svgButton(__webpack_require__(83), 'orientation');\n\t\torientationButton.setAttribute('title', 'Toggle Orientation');\n\t\torientationButton.className = 'unsupported';\n\t\torientationButton.addEventListener('click', toggleOrientation, false);\n\n\t\t//report on HMD\n\t\tVR.on('devicechange', deviceChange);\n\t\tdeviceChange();\n\n\t\t//keyboard shortcuts for making life a little easier\n\t\twindow.addEventListener('keydown', function (evt) {\n\t\t\tif (evt.keyCode === 'Z'.charCodeAt(0)) {\n\t\t\t\tVR.zeroSensor();\n\t\t\t} else if (evt.keyCode === 'O'.charCodeAt(0)) {\n\t\t\t\tVR.enableOrientation();\n\t\t\t} else if (evt.keyCode === 13) {\n\t\t\t\tVR.requestVR();\n\t\t\t}\n\t\t}, false);\n\n\t\tVR.resize();\n\t}\n\n\tfunction initialize() {\n\t\tinitRequirements();\n\n\t\t//todo: set up button/info elements\n\n\t\tVR.init();\n\n\t\tif (document.body) {\n\t\t\tinitUI();\n\t\t} else {\n\t\t\twindow.addEventListener('load', initUI, false);\n\t\t}\n\n\t\twindow.addEventListener('resize', VR.resize, false);\n\n\t\t/*\n\t\texport global things\n\t\t*/\n\t\twindow.VR = VR;\n\t\twindow.THREE = VR.THREE;\n\t}\n\n\tinitialize();\n\tVR.start();\n}());\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/entry.js\n ** module id = 0\n ** module chunks = 0\n **/\n//# sourceURL=webpack:///./src/entry.js?");
/***/ },
/* 1 */
@@ -80,7 +80,7 @@
/* 6 */
/***/ function(module, exports, __webpack_require__) {
- eval("(function () {\n\t'use strict';\n\n\t//constants\n\tvar NEAR = 0.1,\n\t\tFAR = 1000000,\n\n\t//global-ish declarations\n\t\tTHREE,\n\t\teventEmitter,\n\t\tmaterials = __webpack_require__(7),\n\t\tnop = function () {},\n\t\trequestFullscreen = nop,\n\t\texitFullscreen = (\n\t\t\tdocument.exitFullscreen ||\n\t\t\tdocument.mozCancelFullScreen ||\n\t\t\tdocument.webkitExitFullscreen ||\n\t\t\tdocument.msExitFullscreen ||\n\t\t\tnop\n\t\t).bind(document),\n\n\t//scene assets\n\t\tcamera,\n\t\tscene,\n\t\tbody,\n\t\trenderer,\n\t\taudioListener,\n\t\tvrControls,\n\t\tvrEffect,\n\t\tmouseControls,\n\t\traycaster,\n\t\ttarget,\n\n\t\tbodyWrapper,\n\t\tcameraWrapper,\n\n\t\tfloor,\n\n\t//state\n\t\tgoing = false,\n\t\tvrMode = false,\n\t\torientationEnabled,\n\t\torientationPossible = false,\n\n\t//exported object\n\t\tVR,\n\n\t\tVRObject = __webpack_require__(43),\n\t\tobjectMethods = [\n\t\t\t'box',\n\t\t\t'cylinder',\n\t\t\t'torus',\n\t\t\t'sphere',\n\t\t\t'empty',\n\t\t\t'sound',\n\t\t\t'floor',\n\t\t\t'sky',\n\t\t\t'panorama',\n\t\t\t'image',\n\t\t\t'video',\n\t\t\t'text'\n\t\t],\n\n\t\t//todo: use a weak map or set instead\n\t\tvrObjects = [],\n\t\traycastable = [],\n\n\t\tlastTick = 0,\n\t\tanimationCallbacks = [];\n\n\tfunction isFullscreen() {\n\t\treturn !!(document.fullscreenElement ||\n\t\t\tdocument.mozFullScreenElement ||\n\t\t\tdocument.webkitFullscreenElement ||\n\t\t\tdocument.msFullscreenElement);\n\t}\n\n\tfunction fullScreenError() {\n\t\tvrMode = false;\n\t\tif (vrEffect) {\n\t\t\tvrEffect.exit();\n\t\t}\n\t}\n\n\tfunction pruneObject(object) {\n\t\tvar i = raycastable.indexOf(object);\n\t\tif (i >= 0) {\n\t\t\traycastable.splice(i, 1);\n\t\t}\n\n\t\ti = vrObjects.indexOf(VRObject.findObject(object));\n\t\tif (i >= 0) {\n\t\t\tvrObjects.splice(i, 1);\n\t\t}\n\n\t\tobject.children.forEach(pruneObject);\n\t}\n\n\tfunction raycast() {\n\t\tvar i,\n\t\t\tintersect,\n\t\t\tobject,\n\t\t\tintersects,\n\t\t\tparent,\n\t\t\tprune = [],\n\t\t\tvrObject;\n\n\t\traycaster.ray.origin.setFromMatrixPosition(camera.matrixWorld); // world position\n\t\traycaster.ray.direction.set(0, 0, 0.5).unproject(camera).sub(raycaster.ray.origin).normalize();\n\n\t\tintersects = raycaster.intersectObjects(raycastable, true);\n\t\tfor (i = 0; i < intersects.length; i++) {\n\t\t\tintersect = intersects[i];\n\n\t\t\t// if object has been removed from scene, remove it from raycastable\n\t\t\tparent = intersect.object;\n\t\t\twhile (parent && parent !== scene) {\n\t\t\t\tif (!parent.parent) {\n\t\t\t\t\tprune.push(parent);\n\t\t\t\t}\n\t\t\t\tparent = parent.parent;\n\t\t\t}\n\n\t\t\tif (parent && intersect.object instanceof THREE.Mesh) {\n\t\t\t\tobject = intersect.object;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tprune.forEach(pruneObject);\n\n\t\tif (target !== object) {\n\t\t\tif (target) {\n\t\t\t\tvrObject = VRObject.findObject(target);\n\t\t\t\tvrObject.emit('lookaway');\n\t\t\t\tVR.emit('lookaway', vrObject);\n\t\t\t}\n\t\t\ttarget = object;\n\t\t\tif (target) {\n\t\t\t\tvrObject = VRObject.findObject(target);\n\t\t\t\twhile (!vrObject && target.parent) {\n\t\t\t\t\ttarget = target.parent;\n\t\t\t\t\tvrObject = VRObject.findObject(target);\n\t\t\t\t}\n\t\t\t\tif (vrObject) {\n\t\t\t\t\tvrObject.emit('lookat', intersect);\n\t\t\t\t\tVR.emit('lookat', vrObject, intersect);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction render() {\n\t\tvar now = Date.now() / 1000,\n\t\t\tdelta = Math.min(1, now - lastTick);\n\n\t\tvrControls.update();\n\n\t\tanimationCallbacks.forEach(function (cb) {\n\t\t\tcb(delta, now);\n\t\t});\n\n\t\tscene.updateMatrixWorld();\n\n\t\tvrObjects.forEach(function (object) {\n\t\t\tobject.update(now);\n\t\t});\n\n\t\traycast();\n\n\t\tvrEffect.render(scene, camera);\n\n\t\tlastTick = now;\n\t}\n\n\tfunction renderLoop() {\n\t\tif (going) {\n\t\t\trender();\n\t\t\trequestAnimationFrame(renderLoop);\n\t\t}\n\t}\n\n\tfunction stop() {\n\t\tgoing = false;\n\t}\n\n\tfunction start() {\n\t\tif (!going) {\n\t\t\tgoing = true;\n\t\t\trenderLoop();\n\t\t}\n\t}\n\n\t/*\n\tMute any sounds when this browser tab is in the background or minimized.\n\t*/\n\tfunction visibilityChange() {\n\t\tif (document.hidden || document.mozHidden || document.msHidden || document.webkitHidden) {\n\t\t\taudioListener.volume(0);\n\t\t} else {\n\t\t\taudioListener.volume(1);\n\t\t}\n\t}\n\n\tfunction resize(width, height) {\n\t\twidth = typeof width === 'number' && width || window.innerWidth;\n\t\theight = typeof height === 'number' && height || window.innerHeight;\n\n\t\tcamera.aspect = width / height;\n\t\tcamera.updateProjectionMatrix();\n\t\trenderer.setSize(width, height);\n\t}\n\n\tfunction initShake() {\n\t\tvar lastTime = 0,\n\t\t\tlastX,\n\t\t\tlastY,\n\t\t\tlastZ,\n\t\t\tthreshold = 15;\n\n\t\twindow.addEventListener('devicemotion', function (evt) {\n\t\t\tvar current = evt.accelerationIncludingGravity,\n\t\t\t\ttime,\n\t\t\t\tdiff,\n\t\t\t\tdeltaX = 0,\n\t\t\t\tdeltaY = 0,\n\t\t\t\tdeltaZ = 0,\n\t\t\t\tdist;\n\n\t\t\tif (lastX !== undefined) {\n\t\t\t\tdeltaX = Math.abs(lastX - current.x);\n\t\t\t\tdeltaY = Math.abs(lastY - current.y);\n\t\t\t\tdeltaZ = Math.abs(lastZ - current.z);\n\n\t\t\t\t// if (deltaX > threshold &&\n\t\t\t\t// \t\t(deltaY > threshold || deltaZ > threshold)\n\t\t\t\t// \t) {\n\t\t\t\tdist = Math.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ);\n\t\t\t\tif (dist > threshold) {\n\n\t\t\t\t\ttime = Date.now();\n\t\t\t\t\tdiff = time - lastTime;\n\t\t\t\t\tif (diff > 1000) {\n\t\t\t\t\t\tif (navigator.vibrate) {\n\t\t\t\t\t\t\tnavigator.vibrate(100);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tlastTime = Date.now();\n\n\t\t\t\t\t\tVR.emit('shake');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlastX = current.x;\n\t\t\tlastY = current.y;\n\t\t\tlastZ = current.z;\n\n\t\t\torientationPossible = true;\n\t\t}, false);\n\t}\n\n\tfunction initScene() {\n\t\tfunction attachCanvas() {\n\t\t\tdocument.body.insertBefore(renderer.domElement, document.body.firstChild || null);\n\t\t\tresize();\n\t\t}\n\n\t\tif (renderer) {\n\t\t\treturn;\n\t\t}\n\n\t\t//create renderer and place in document\n\t\trenderer = new THREE.WebGLRenderer({ antialias: true });\n\t\trenderer.domElement.addEventListener('webglcontextlost', function contextLost(event) {\n\t\t\tconsole.log('lost context', event);\n\t\t});\n\t\t// renderer.shadowMapEnabled = true;\n\t\t// renderer.shadowMapSoft = true;\n\n\t\t//need a scene to put all our objects in\n\t\tscene = new THREE.Scene();\n\n\t\tbodyWrapper = new VRObject(scene, __webpack_require__(59), null, {\n\t\t\tname: 'body'\n\t\t}).moveTo(0, 1.5, 4);\n\t\tbody = bodyWrapper.object;\n\n\t\tcameraWrapper = new VRObject(body, function (parent) {\n\t\t\t//need a camera with which to look at stuff\n\t\t\tcamera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, NEAR, FAR);\n\t\t\tparent.add(camera);\n\n\t\t\treturn camera;\n\t\t})\n\t\t// set camera position so that OrbitControls works properly.\n\t\t\t.moveTo(0, 0.0001, 0.0001);\n\n\t\taudioListener = new THREE.AudioListener();\n\t\taudioListener.name = 'audio-listener';\n\t\tcamera.add(audioListener);\n\n\t\t//VRControls point the camera wherever we're looking\n\t\tvrControls = new THREE.VRControls(camera);\n\t\tvrControls.freeze = !orientationEnabled;\n\n\t\t//render left and right eye\n\t\tvrEffect = new THREE.VRStereoEffect(renderer);\n\t\tvrEffect.near = NEAR;\n\t\tvrEffect.far = FAR;\n\t\tvrEffect.addEventListener('fullscreenchange', function (evt) {\n\t\t\tvar screen;\n\t\t\tif (isFullscreen()) {\n\t\t\t\tif (vrMode) {\n\t\t\t\t\t//no mouse control\n\t\t\t\t\tmouseControls.enabled = false;\n\n\t\t\t\t\tvrControls.freeze = false;\n\t\t\t\t\tvrControls.reset();\n\n\t\t\t\t\tscreen = window.screen;\n\t\t\t\t\tif (screen.lockOrientation) {\n\t\t\t\t\t\tscreen.lockOrientation('landscape-primary');\n\t\t\t\t\t} else if (screen.mozLockOrientation) {\n\t\t\t\t\t\tscreen.mozLockOrientation('landscape-primary');\n\t\t\t\t\t} else if (screen.orientation && screen.orientation.lock) {\n\t\t\t\t\t\tscreen.orientation.lock('landscape-primary');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tVR.exitVR();\n\t\t\t}\n\n\t\t\tcamera.position.set(0, 0.0001, 0.0001);\n\t\t\tcamera.rotation.set(0, 0, 0);\n\n\t\t\tVR.emit('fullscreenchange', evt);\n\t\t});\n\n\t\t//report on HMD\n\t\tvrControls.addEventListener('devicechange', function () {\n\t\t\torientationPossible = true;\n\t\t\tif (orientationEnabled === undefined) {\n\t\t\t\torientationEnabled = vrControls.mode() === 'deviceorientation';\n\t\t\t}\n\n\t\t\tvrControls.freeze = !orientationEnabled && !vrMode;\n\n\t\t\tVR.emit('devicechange', vrControls.mode(), vrEffect.hmd());\n\t\t});\n\n\t\t//mouse control in case got no orientation device\n\t\tmouseControls = new THREE.OrbitControls(camera);\n\t\tmouseControls.target0.set(0, 0.0001, 0.000);\n\t\tmouseControls.target.copy(mouseControls.target0);\n\t\tmouseControls.update();\n\n\t\t//todo: remove any default lights once other lights are added\n\t\tvar dLight = new THREE.DirectionalLight(0xffffff, 0.8);\n\t\tdLight.name = 'directional-light';\n\t\tdLight.position.set(20, 100, 100);\n\n\t\tdLight.castShadow = true;\n\t\tdLight.shadowCameraVisible = true;\n\n\t\tdLight.shadowMapWidth = 2048;\n\t\tdLight.shadowMapHeight = 2048;\n\n\t\tdLight.shadowCameraLeft = -10;\n\t\tdLight.shadowCameraRight = 10;\n\t\tdLight.shadowCameraTop = 10;\n\t\tdLight.shadowCameraBottom = -10;\n\n\t\tdLight.shadowCameraFar = 150;\n\t\tdLight.shadowCameraNear = 100;\n\t\tdLight.shadowDarkness = 1;\n\n\t\tscene.add(dLight);\n\n\t\tscene.add(new THREE.AmbientLight(0x444444));\n\n\t\tif (VR) {\n\t\t\tVR.camera = cameraWrapper;\n\t\t\tVR.body = bodyWrapper;\n\t\t\tVR.scene = scene;\n\t\t\tVR.canvas = renderer.domElement;\n\t\t\tVR.renderer = renderer;\n\t\t\tVR.zeroSensor = vrControls.zeroSensor;\n\t\t}\n\n\t\traycaster = new THREE.Raycaster();\n\n\t\tif (document.body) {\n\t\t\tattachCanvas();\n\t\t} else {\n\t\t\twindow.addEventListener('load', attachCanvas, false);\n\t\t}\n\n\t\tVR.canvas.addEventListener('mozfullscreenerror', fullScreenError, false);\n\t\tVR.canvas.addEventListener('webkitfullscreenerror', fullScreenError, false);\n\t\tVR.canvas.addEventListener('fullscreenerror', fullScreenError, false);\n\t}\n\n\tfunction initRequirements() {\n\t\t//load external requirements\n\t\tTHREE = __webpack_require__(8);\n\t\t__webpack_require__(60);\n\t\t__webpack_require__(61);\n\n\t\t//if (typeof __DEV__ !== 'undefined' && __DEV__) {\n\t\t\t__webpack_require__(62);\n\t\t//}\n\n\t\tTHREE.ImageUtils.crossOrigin = '';\n\n\t\teventEmitter = __webpack_require__(44);\n\n\t\t//my VR stuff. todo: move these to a separate repo or two for easy packaging\n\t\t__webpack_require__(63);\n\t\t__webpack_require__(64);\n\t}\n\n\tfunction initialize() {\n\t\t//todo: set up button/info elements\n\n\t\tinitScene();\n\n\t\tinitShake();\n\n\t\tresize();\n\n\t\tdocument.addEventListener('visibilitychange', visibilityChange);\n\t\tdocument.addEventListener('mozvisibilitychange', visibilityChange);\n\t\tdocument.addEventListener('msvisibilitychange', visibilityChange);\n\t\tdocument.addEventListener('webkitvisibilitychange', visibilityChange);\n\t}\n\n\tinitRequirements();\n\n\tmodule.exports = VR = {\n\t\tinit: initialize,\n\t\trender: render,\n\t\tstart: start,\n\t\tstop: stop,\n\t\tresize: resize,\n\n\t\tTHREE: THREE,\n\n\t\tmaterials: materials,\n\n\t\tanimate: function (callback) {\n\t\t\tvar i;\n\t\t\tif (typeof callback === 'function') {\n\t\t\t\ti = animationCallbacks.indexOf(callback);\n\t\t\t\tif (i < 0) {\n\t\t\t\t\tanimationCallbacks.push(callback);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tend: function (callback) {\n\t\t\tvar i;\n\n\t\t\tif (!callback) {\n\t\t\t\tanimationCallbacks.length = 0;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (typeof callback === 'function') {\n\t\t\t\ti = animationCallbacks.indexOf(callback);\n\t\t\t\tif (i >= 0) {\n\t\t\t\t\tanimationCallbacks.splice(i, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\trequestVR: function () {\n\t\t\t//todo: check if it's possible\n\t\t\tif (vrMode || !vrEffect) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvrMode = true;\n\n\t\t\t//full screen and render two eyes\n\t\t\t//always full screen\n\t\t\tvrEffect.requestFullScreen();\n\t\t},\n\n\t\texitVR: function () {\n\t\t\tvrMode = false;\n\t\t\tif (isFullscreen()) {\n\t\t\t\texitFullscreen();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tmouseControls.enabled = true;\n\t\t\tvrControls.freeze = !orientationEnabled;\n\t\t\tcamera.rotation.set(0, 0, 0);\n\t\t},\n\n\t\tvrMode: function () {\n\t\t\treturn vrMode && isFullscreen();\n\t\t},\n\n\t\torientationEnabled: function () {\n\t\t\treturn !!orientationEnabled;\n\t\t},\n\t\tenableOrientation: function () {\n\t\t\torientationEnabled = true;\n\t\t\tif (!vrMode) {\n\t\t\t\tvrControls.freeze = false;\n\t\t\t}\n\t\t},\n\t\tdisableOrientation: function () {\n\t\t\torientationEnabled = false;\n\t\t\tcamera.rotation.set(0, 0, 0);\n\t\t\tvrControls.freeze = !vrMode;\n\t\t},\n\n\t\tisFullscreen: isFullscreen,\n\t\trequestFullscreen: requestFullscreen,\n\t\texitFullscreen: function () {\n\t\t\tif (isFullscreen()) {\n\t\t\t\texitFullscreen();\n\t\t\t}\n\t\t},\n\n\t\tcontrolMode: function () {\n\t\t\treturn vrControls && vrControls.mode();\n\t\t},\n\n\t\tzeroSensor: nop,\n\n\t\tvibrate: navigator.vibrate ? navigator.vibrate.bind(navigator) : nop,\n\n\t\t// Utility\n\t\ttimes: function (n, callback) {\n\t\t\tvar i;\n\n\t\t\tfor (i = 0; i < n; i++) {\n\t\t\t\tcallback(i);\n\t\t\t}\n\t\t},\n\n\t\tcamera: cameraWrapper,\n\t\tbody: bodyWrapper,\n\t\tscene: scene,\n\t\trenderer: renderer || null,\n\t\tcanvas: renderer && renderer.domElement || null\n\t};\n\n\tobjectMethods.forEach(function (method) {\n\t\tvar creator = __webpack_require__(65)(\"./\" + method),\n\t\t\tkey;\n\n\t\tVR[method] = function (options) {\n\t\t\tvar obj = new VRObject(scene, creator, body, options);\n\t\t\tvrObjects.push(obj);\n\t\t\tif (obj.raycastable) {\n\t\t\t\traycastable.push(obj.object);\n\t\t\t}\n\t\t\treturn obj;\n\t\t};\n\n\t\tVRObject.prototype[method] = function (options) {\n\t\t\tvar obj = new VRObject(this.object, creator, body, options);\n\t\t\tvrObjects.push(obj);\n\t\t\tif (obj.raycastable) {\n\t\t\t\traycastable.push(obj.object);\n\t\t\t}\n\t\t\treturn obj;\n\t\t};\n\n\t\tfor (key in creator) {\n\t\t\tif (creator.hasOwnProperty(key) && typeof creator[key] === 'function') {\n\t\t\t\tVR[method][key] = creator[key];\n\t\t\t\tVRObject.prototype[method][key] = creator[key];\n\t\t\t}\n\t\t}\n\t});\n\n\teventEmitter(VR);\n\n\tObject.defineProperty(VR, 'target', {\n\t\tget: function () {\n\t\t\treturn target;\n\t\t}\n\t});\n}());\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/vr.js\n ** module id = 6\n ** module chunks = 0\n **/\n//# sourceURL=webpack:///./src/vr.js?");
+ eval("(function () {\n\t'use strict';\n\n\t//constants\n\tvar NEAR = 0.1,\n\t\tFAR = 1000000,\n\n\t//global-ish declarations\n\t\tTHREE,\n\t\teventEmitter,\n\t\tmaterials = __webpack_require__(7),\n\t\tnop = function () {},\n\t\trequestFullscreen = nop,\n\t\texitFullscreen = (\n\t\t\tdocument.exitFullscreen ||\n\t\t\tdocument.mozCancelFullScreen ||\n\t\t\tdocument.webkitExitFullscreen ||\n\t\t\tdocument.msExitFullscreen ||\n\t\t\tnop\n\t\t).bind(document),\n\n\t//scene assets\n\t\tcamera,\n\t\tscene,\n\t\tbody,\n\t\trenderer,\n\t\taudioListener,\n\t\tvrControls,\n\t\tvrEffect,\n\t\tmouseControls,\n\t\traycaster,\n\t\ttarget,\n\n\t\tbodyWrapper,\n\t\tcameraWrapper,\n\n\t\tfloor,\n\n\t//state\n\t\tgoing = false,\n\t\tvrMode = false,\n\t\torientationEnabled,\n\t\torientationPossible = false,\n\n\t//exported object\n\t\tVR,\n\n\t\tVRObject = __webpack_require__(43),\n\t\tobjectMethods = [\n\t\t\t'box',\n\t\t\t'cylinder',\n\t\t\t'torus',\n\t\t\t'sphere',\n\t\t\t'empty',\n\t\t\t'sound',\n\t\t\t'floor',\n\t\t\t'sky',\n\t\t\t'panorama',\n\t\t\t'image',\n\t\t\t'video',\n\t\t\t'text',\n\t\t\t'grid'\n\t\t],\n\n\t\t//todo: use a weak map or set instead\n\t\tvrObjects = [],\n\t\traycastable = [],\n\n\t\tlastTick = 0,\n\t\tanimationCallbacks = [];\n\n\tfunction isFullscreen() {\n\t\treturn !!(document.fullscreenElement ||\n\t\t\tdocument.mozFullScreenElement ||\n\t\t\tdocument.webkitFullscreenElement ||\n\t\t\tdocument.msFullscreenElement);\n\t}\n\n\tfunction fullScreenError() {\n\t\tvrMode = false;\n\t\tif (vrEffect) {\n\t\t\tvrEffect.exit();\n\t\t}\n\t}\n\n\tfunction pruneObject(object) {\n\t\tvar i = raycastable.indexOf(object);\n\t\tif (i >= 0) {\n\t\t\traycastable.splice(i, 1);\n\t\t}\n\n\t\ti = vrObjects.indexOf(VRObject.findObject(object));\n\t\tif (i >= 0) {\n\t\t\tvrObjects.splice(i, 1);\n\t\t}\n\n\t\tobject.children.forEach(pruneObject);\n\t}\n\n\tfunction raycast() {\n\t\tvar i,\n\t\t\tintersect,\n\t\t\tobject,\n\t\t\tintersects,\n\t\t\tparent,\n\t\t\tprune = [],\n\t\t\tvrObject;\n\n\t\traycaster.ray.origin.setFromMatrixPosition(camera.matrixWorld); // world position\n\t\traycaster.ray.direction.set(0, 0, 0.5).unproject(camera).sub(raycaster.ray.origin).normalize();\n\n\t\tintersects = raycaster.intersectObjects(raycastable, true);\n\t\tfor (i = 0; i < intersects.length; i++) {\n\t\t\tintersect = intersects[i];\n\n\t\t\t// if object has been removed from scene, remove it from raycastable\n\t\t\tparent = intersect.object;\n\t\t\twhile (parent && parent !== scene) {\n\t\t\t\tif (!parent.parent) {\n\t\t\t\t\tprune.push(parent);\n\t\t\t\t}\n\t\t\t\tparent = parent.parent;\n\t\t\t}\n\n\t\t\tif (parent && intersect.object instanceof THREE.Mesh) {\n\t\t\t\tobject = intersect.object;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tprune.forEach(pruneObject);\n\n\t\tif (target !== object) {\n\t\t\tif (target) {\n\t\t\t\tvrObject = VRObject.findObject(target);\n\t\t\t\tvrObject.emit('lookaway');\n\t\t\t\tVR.emit('lookaway', vrObject);\n\t\t\t}\n\t\t\ttarget = object;\n\t\t\tif (target) {\n\t\t\t\tvrObject = VRObject.findObject(target);\n\t\t\t\twhile (!vrObject && target.parent) {\n\t\t\t\t\ttarget = target.parent;\n\t\t\t\t\tvrObject = VRObject.findObject(target);\n\t\t\t\t}\n\t\t\t\tif (vrObject) {\n\t\t\t\t\tvrObject.emit('lookat', intersect);\n\t\t\t\t\tVR.emit('lookat', vrObject, intersect);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction render() {\n\t\tvar now = Date.now() / 1000,\n\t\t\tdelta = Math.min(1, now - lastTick);\n\n\t\tvrControls.update();\n\n\t\tanimationCallbacks.forEach(function (cb) {\n\t\t\tcb(delta, now);\n\t\t});\n\n\t\tscene.updateMatrixWorld();\n\n\t\tvrObjects.forEach(function (object) {\n\t\t\tobject.update(now);\n\t\t});\n\n\t\traycast();\n\n\t\tvrEffect.render(scene, camera);\n\n\t\tlastTick = now;\n\t}\n\n\tfunction renderLoop() {\n\t\tif (going) {\n\t\t\trender();\n\t\t\trequestAnimationFrame(renderLoop);\n\t\t}\n\t}\n\n\tfunction stop() {\n\t\tgoing = false;\n\t}\n\n\tfunction start() {\n\t\tif (!going) {\n\t\t\tgoing = true;\n\t\t\trenderLoop();\n\t\t}\n\t}\n\n\t/*\n\tMute any sounds when this browser tab is in the background or minimized.\n\t*/\n\tfunction visibilityChange() {\n\t\tif (document.hidden || document.mozHidden || document.msHidden || document.webkitHidden) {\n\t\t\taudioListener.volume(0);\n\t\t} else {\n\t\t\taudioListener.volume(1);\n\t\t}\n\t}\n\n\tfunction resize(width, height) {\n\t\twidth = typeof width === 'number' && width || window.innerWidth;\n\t\theight = typeof height === 'number' && height || window.innerHeight;\n\n\t\tcamera.aspect = width / height;\n\t\tcamera.updateProjectionMatrix();\n\t\trenderer.setSize(width, height);\n\t}\n\n\tfunction initShake() {\n\t\tvar lastTime = 0,\n\t\t\tlastX,\n\t\t\tlastY,\n\t\t\tlastZ,\n\t\t\tthreshold = 15;\n\n\t\twindow.addEventListener('devicemotion', function (evt) {\n\t\t\tvar current = evt.accelerationIncludingGravity,\n\t\t\t\ttime,\n\t\t\t\tdiff,\n\t\t\t\tdeltaX = 0,\n\t\t\t\tdeltaY = 0,\n\t\t\t\tdeltaZ = 0,\n\t\t\t\tdist;\n\n\t\t\tif (lastX !== undefined) {\n\t\t\t\tdeltaX = Math.abs(lastX - current.x);\n\t\t\t\tdeltaY = Math.abs(lastY - current.y);\n\t\t\t\tdeltaZ = Math.abs(lastZ - current.z);\n\n\t\t\t\t// if (deltaX > threshold &&\n\t\t\t\t// \t\t(deltaY > threshold || deltaZ > threshold)\n\t\t\t\t// \t) {\n\t\t\t\tdist = Math.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ);\n\t\t\t\tif (dist > threshold) {\n\n\t\t\t\t\ttime = Date.now();\n\t\t\t\t\tdiff = time - lastTime;\n\t\t\t\t\tif (diff > 1000) {\n\t\t\t\t\t\tif (navigator.vibrate) {\n\t\t\t\t\t\t\tnavigator.vibrate(100);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tlastTime = Date.now();\n\n\t\t\t\t\t\tVR.emit('shake');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlastX = current.x;\n\t\t\tlastY = current.y;\n\t\t\tlastZ = current.z;\n\n\t\t\torientationPossible = true;\n\t\t}, false);\n\t}\n\n\tfunction initScene() {\n\t\tfunction attachCanvas() {\n\t\t\tdocument.body.insertBefore(renderer.domElement, document.body.firstChild || null);\n\t\t\tresize();\n\t\t}\n\n\t\tif (renderer) {\n\t\t\treturn;\n\t\t}\n\n\t\t//create renderer and place in document\n\t\trenderer = new THREE.WebGLRenderer({ antialias: true });\n\t\trenderer.domElement.addEventListener('webglcontextlost', function contextLost(event) {\n\t\t\tconsole.log('lost context', event);\n\t\t});\n\t\t// renderer.shadowMapEnabled = true;\n\t\t// renderer.shadowMapSoft = true;\n\n\t\t//need a scene to put all our objects in\n\t\tscene = new THREE.Scene();\n\n\t\tbodyWrapper = new VRObject(scene, __webpack_require__(59), null, {\n\t\t\tname: 'body'\n\t\t}).moveTo(0, 1.5, 4);\n\t\tbody = bodyWrapper.object;\n\n\t\tcameraWrapper = new VRObject(body, function (parent) {\n\t\t\t//need a camera with which to look at stuff\n\t\t\tcamera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, NEAR, FAR);\n\t\t\tparent.add(camera);\n\n\t\t\treturn camera;\n\t\t})\n\t\t// set camera position so that OrbitControls works properly.\n\t\t\t.moveTo(0, 0.0001, 0.0001);\n\n\t\taudioListener = new THREE.AudioListener();\n\t\taudioListener.name = 'audio-listener';\n\t\tcamera.add(audioListener);\n\n\t\t//VRControls point the camera wherever we're looking\n\t\tvrControls = new THREE.VRControls(camera);\n\t\tvrControls.freeze = !orientationEnabled;\n\n\t\t//render left and right eye\n\t\tvrEffect = new THREE.VRStereoEffect(renderer);\n\t\tvrEffect.near = NEAR;\n\t\tvrEffect.far = FAR;\n\t\tvrEffect.addEventListener('fullscreenchange', function (evt) {\n\t\t\tvar screen;\n\t\t\tif (isFullscreen()) {\n\t\t\t\tif (vrMode) {\n\t\t\t\t\t//no mouse control\n\t\t\t\t\tmouseControls.enabled = false;\n\n\t\t\t\t\tvrControls.freeze = false;\n\t\t\t\t\tvrControls.reset();\n\n\t\t\t\t\tscreen = window.screen;\n\t\t\t\t\tif (screen.lockOrientation) {\n\t\t\t\t\t\tscreen.lockOrientation('landscape-primary');\n\t\t\t\t\t} else if (screen.mozLockOrientation) {\n\t\t\t\t\t\tscreen.mozLockOrientation('landscape-primary');\n\t\t\t\t\t} else if (screen.orientation && screen.orientation.lock) {\n\t\t\t\t\t\tscreen.orientation.lock('landscape-primary');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tVR.exitVR();\n\t\t\t}\n\n\t\t\tcamera.position.set(0, 0.0001, 0.0001);\n\t\t\tcamera.rotation.set(0, 0, 0);\n\n\t\t\tVR.emit('fullscreenchange', evt);\n\t\t});\n\n\t\t//report on HMD\n\t\tvrControls.addEventListener('devicechange', function () {\n\t\t\torientationPossible = true;\n\t\t\tif (orientationEnabled === undefined) {\n\t\t\t\torientationEnabled = vrControls.mode() === 'deviceorientation';\n\t\t\t}\n\n\t\t\tvrControls.freeze = !orientationEnabled && !vrMode;\n\n\t\t\tVR.emit('devicechange', vrControls.mode(), vrEffect.hmd());\n\t\t});\n\n\t\t//mouse control in case got no orientation device\n\t\tmouseControls = new THREE.OrbitControls(camera);\n\t\tmouseControls.target0.set(0, 0.0001, 0.000);\n\t\tmouseControls.target.copy(mouseControls.target0);\n\t\tmouseControls.update();\n\n\t\t//todo: remove any default lights once other lights are added\n\t\tvar dLight = new THREE.DirectionalLight(0xffffff, 0.8);\n\t\tdLight.name = 'directional-light';\n\t\tdLight.position.set(20, 100, 100);\n\n\t\tdLight.castShadow = true;\n\t\tdLight.shadowCameraVisible = true;\n\n\t\tdLight.shadowMapWidth = 2048;\n\t\tdLight.shadowMapHeight = 2048;\n\n\t\tdLight.shadowCameraLeft = -10;\n\t\tdLight.shadowCameraRight = 10;\n\t\tdLight.shadowCameraTop = 10;\n\t\tdLight.shadowCameraBottom = -10;\n\n\t\tdLight.shadowCameraFar = 150;\n\t\tdLight.shadowCameraNear = 100;\n\t\tdLight.shadowDarkness = 1;\n\n\t\tscene.add(dLight);\n\n\t\tscene.add(new THREE.AmbientLight(0x444444));\n\n\t\tif (VR) {\n\t\t\tVR.camera = cameraWrapper;\n\t\t\tVR.body = bodyWrapper;\n\t\t\tVR.scene = scene;\n\t\t\tVR.canvas = renderer.domElement;\n\t\t\tVR.renderer = renderer;\n\t\t\tVR.zeroSensor = vrControls.zeroSensor;\n\t\t}\n\n\t\traycaster = new THREE.Raycaster();\n\n\t\tif (document.body) {\n\t\t\tattachCanvas();\n\t\t} else {\n\t\t\twindow.addEventListener('load', attachCanvas, false);\n\t\t}\n\n\t\tVR.canvas.addEventListener('mozfullscreenerror', fullScreenError, false);\n\t\tVR.canvas.addEventListener('webkitfullscreenerror', fullScreenError, false);\n\t\tVR.canvas.addEventListener('fullscreenerror', fullScreenError, false);\n\t}\n\n\tfunction initRequirements() {\n\t\t//load external requirements\n\t\tTHREE = __webpack_require__(8);\n\t\t__webpack_require__(60);\n\t\t__webpack_require__(61);\n\n\t\t//if (typeof __DEV__ !== 'undefined' && __DEV__) {\n\t\t\t__webpack_require__(62);\n\t\t//}\n\n\t\tTHREE.ImageUtils.crossOrigin = '';\n\n\t\teventEmitter = __webpack_require__(44);\n\n\t\t//my VR stuff. todo: move these to a separate repo or two for easy packaging\n\t\t__webpack_require__(63);\n\t\t__webpack_require__(64);\n\t}\n\n\tfunction initialize() {\n\t\t//todo: set up button/info elements\n\n\t\tinitScene();\n\n\t\tinitShake();\n\n\t\tresize();\n\n\t\tdocument.addEventListener('visibilitychange', visibilityChange);\n\t\tdocument.addEventListener('mozvisibilitychange', visibilityChange);\n\t\tdocument.addEventListener('msvisibilitychange', visibilityChange);\n\t\tdocument.addEventListener('webkitvisibilitychange', visibilityChange);\n\t}\n\n\tinitRequirements();\n\n\tmodule.exports = VR = {\n\t\tinit: initialize,\n\t\trender: render,\n\t\tstart: start,\n\t\tstop: stop,\n\t\tresize: resize,\n\n\t\tTHREE: THREE,\n\n\t\tmaterials: materials,\n\n\t\tanimate: function (callback) {\n\t\t\tvar i;\n\t\t\tif (typeof callback === 'function') {\n\t\t\t\ti = animationCallbacks.indexOf(callback);\n\t\t\t\tif (i < 0) {\n\t\t\t\t\tanimationCallbacks.push(callback);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tend: function (callback) {\n\t\t\tvar i;\n\n\t\t\tif (!callback) {\n\t\t\t\tanimationCallbacks.length = 0;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (typeof callback === 'function') {\n\t\t\t\ti = animationCallbacks.indexOf(callback);\n\t\t\t\tif (i >= 0) {\n\t\t\t\t\tanimationCallbacks.splice(i, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\trequestVR: function () {\n\t\t\t//todo: check if it's possible\n\t\t\tif (vrMode || !vrEffect) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvrMode = true;\n\n\t\t\t//full screen and render two eyes\n\t\t\t//always full screen\n\t\t\tvrEffect.requestFullScreen();\n\t\t},\n\n\t\texitVR: function () {\n\t\t\tvrMode = false;\n\t\t\tif (isFullscreen()) {\n\t\t\t\texitFullscreen();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tmouseControls.enabled = true;\n\t\t\tvrControls.freeze = !orientationEnabled;\n\t\t\tcamera.rotation.set(0, 0, 0);\n\t\t},\n\n\t\tvrMode: function () {\n\t\t\treturn vrMode && isFullscreen();\n\t\t},\n\n\t\torientationEnabled: function () {\n\t\t\treturn !!orientationEnabled;\n\t\t},\n\t\tenableOrientation: function () {\n\t\t\torientationEnabled = true;\n\t\t\tif (!vrMode) {\n\t\t\t\tvrControls.freeze = false;\n\t\t\t}\n\t\t},\n\t\tdisableOrientation: function () {\n\t\t\torientationEnabled = false;\n\t\t\tcamera.rotation.set(0, 0, 0);\n\t\t\tvrControls.freeze = !vrMode;\n\t\t},\n\n\t\tisFullscreen: isFullscreen,\n\t\trequestFullscreen: requestFullscreen,\n\t\texitFullscreen: function () {\n\t\t\tif (isFullscreen()) {\n\t\t\t\texitFullscreen();\n\t\t\t}\n\t\t},\n\n\t\tcontrolMode: function () {\n\t\t\treturn vrControls && vrControls.mode();\n\t\t},\n\n\t\tzeroSensor: nop,\n\n\t\tvibrate: navigator.vibrate ? navigator.vibrate.bind(navigator) : nop,\n\n\t\t// Utility\n\t\ttimes: function (n, callback) {\n\t\t\tvar i;\n\n\t\t\tfor (i = 0; i < n; i++) {\n\t\t\t\tcallback(i);\n\t\t\t}\n\t\t},\n\n\t\tcamera: cameraWrapper,\n\t\tbody: bodyWrapper,\n\t\tscene: scene,\n\t\trenderer: renderer || null,\n\t\tcanvas: renderer && renderer.domElement || null\n\t};\n\n\tobjectMethods.forEach(function (method) {\n\t\tvar creator = __webpack_require__(65)(\"./\" + method),\n\t\t\tkey;\n\n\t\tVR[method] = function (options) {\n\t\t\tvar obj = new VRObject(scene, creator, body, options);\n\t\t\tvrObjects.push(obj);\n\t\t\tif (obj.raycastable) {\n\t\t\t\traycastable.push(obj.object);\n\t\t\t}\n\t\t\treturn obj;\n\t\t};\n\n\t\tVRObject.prototype[method] = function (options) {\n\t\t\tvar obj = new VRObject(this.object, creator, body, options);\n\t\t\tvrObjects.push(obj);\n\t\t\tif (obj.raycastable) {\n\t\t\t\traycastable.push(obj.object);\n\t\t\t}\n\t\t\treturn obj;\n\t\t};\n\n\t\tfor (key in creator) {\n\t\t\tif (creator.hasOwnProperty(key) && typeof creator[key] === 'function') {\n\t\t\t\tVR[method][key] = creator[key];\n\t\t\t\tVRObject.prototype[method][key] = creator[key];\n\t\t\t}\n\t\t}\n\t});\n\n\teventEmitter(VR);\n\n\tObject.defineProperty(VR, 'target', {\n\t\tget: function () {\n\t\t\treturn target;\n\t\t}\n\t});\n}());\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/vr.js\n ** module id = 6\n ** module chunks = 0\n **/\n//# sourceURL=webpack:///./src/vr.js?");
/***/ },
/* 7 */
@@ -92,7 +92,7 @@
/* 8 */
/***/ function(module, exports, __webpack_require__) {
- eval("var self = self || {};// File:src/Three.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n */\r\n\r\nvar THREE = { REVISION: '71' };\r\n\r\n// browserify support\r\n\r\nif ( true ) {\r\n\r\n\tmodule.exports = THREE;\r\n\r\n}\r\n\r\n// polyfills\r\n\r\nif ( Math.sign === undefined ) {\r\n\r\n\t// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign\r\n\r\n\tMath.sign = function ( x ) {\r\n\r\n\t\treturn ( x < 0 ) ? - 1 : ( x > 0 ) ? 1 : +x;\r\n\r\n\t};\r\n\r\n}\r\n\r\n\r\n// set the default log handlers\r\nTHREE.log = function() { console.log.apply( console, arguments ); }\r\nTHREE.warn = function() { console.warn.apply( console, arguments ); }\r\nTHREE.error = function() { console.error.apply( console, arguments ); }\r\n\r\n\r\n// https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent.button\r\n\r\nTHREE.MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2 };\r\n\r\n// GL STATE CONSTANTS\r\n\r\nTHREE.CullFaceNone = 0;\r\nTHREE.CullFaceBack = 1;\r\nTHREE.CullFaceFront = 2;\r\nTHREE.CullFaceFrontBack = 3;\r\n\r\nTHREE.FrontFaceDirectionCW = 0;\r\nTHREE.FrontFaceDirectionCCW = 1;\r\n\r\n// SHADOWING TYPES\r\n\r\nTHREE.BasicShadowMap = 0;\r\nTHREE.PCFShadowMap = 1;\r\nTHREE.PCFSoftShadowMap = 2;\r\n\r\n// MATERIAL CONSTANTS\r\n\r\n// side\r\n\r\nTHREE.FrontSide = 0;\r\nTHREE.BackSide = 1;\r\nTHREE.DoubleSide = 2;\r\n\r\n// shading\r\n\r\nTHREE.NoShading = 0;\r\nTHREE.FlatShading = 1;\r\nTHREE.SmoothShading = 2;\r\n\r\n// colors\r\n\r\nTHREE.NoColors = 0;\r\nTHREE.FaceColors = 1;\r\nTHREE.VertexColors = 2;\r\n\r\n// blending modes\r\n\r\nTHREE.NoBlending = 0;\r\nTHREE.NormalBlending = 1;\r\nTHREE.AdditiveBlending = 2;\r\nTHREE.SubtractiveBlending = 3;\r\nTHREE.MultiplyBlending = 4;\r\nTHREE.CustomBlending = 5;\r\n\r\n// custom blending equations\r\n// (numbers start from 100 not to clash with other\r\n// mappings to OpenGL constants defined in Texture.js)\r\n\r\nTHREE.AddEquation = 100;\r\nTHREE.SubtractEquation = 101;\r\nTHREE.ReverseSubtractEquation = 102;\r\nTHREE.MinEquation = 103;\r\nTHREE.MaxEquation = 104;\r\n\r\n// custom blending destination factors\r\n\r\nTHREE.ZeroFactor = 200;\r\nTHREE.OneFactor = 201;\r\nTHREE.SrcColorFactor = 202;\r\nTHREE.OneMinusSrcColorFactor = 203;\r\nTHREE.SrcAlphaFactor = 204;\r\nTHREE.OneMinusSrcAlphaFactor = 205;\r\nTHREE.DstAlphaFactor = 206;\r\nTHREE.OneMinusDstAlphaFactor = 207;\r\n\r\n// custom blending source factors\r\n\r\n//THREE.ZeroFactor = 200;\r\n//THREE.OneFactor = 201;\r\n//THREE.SrcAlphaFactor = 204;\r\n//THREE.OneMinusSrcAlphaFactor = 205;\r\n//THREE.DstAlphaFactor = 206;\r\n//THREE.OneMinusDstAlphaFactor = 207;\r\nTHREE.DstColorFactor = 208;\r\nTHREE.OneMinusDstColorFactor = 209;\r\nTHREE.SrcAlphaSaturateFactor = 210;\r\n\r\n\r\n// TEXTURE CONSTANTS\r\n\r\nTHREE.MultiplyOperation = 0;\r\nTHREE.MixOperation = 1;\r\nTHREE.AddOperation = 2;\r\n\r\n// Mapping modes\r\n\r\nTHREE.UVMapping = 300;\r\n\r\nTHREE.CubeReflectionMapping = 301;\r\nTHREE.CubeRefractionMapping = 302;\r\n\r\nTHREE.EquirectangularReflectionMapping = 303;\r\nTHREE.EquirectangularRefractionMapping = 304;\r\n\r\nTHREE.SphericalReflectionMapping = 305;\r\n\r\n// Wrapping modes\r\n\r\nTHREE.RepeatWrapping = 1000;\r\nTHREE.ClampToEdgeWrapping = 1001;\r\nTHREE.MirroredRepeatWrapping = 1002;\r\n\r\n// Filters\r\n\r\nTHREE.NearestFilter = 1003;\r\nTHREE.NearestMipMapNearestFilter = 1004;\r\nTHREE.NearestMipMapLinearFilter = 1005;\r\nTHREE.LinearFilter = 1006;\r\nTHREE.LinearMipMapNearestFilter = 1007;\r\nTHREE.LinearMipMapLinearFilter = 1008;\r\n\r\n// Data types\r\n\r\nTHREE.UnsignedByteType = 1009;\r\nTHREE.ByteType = 1010;\r\nTHREE.ShortType = 1011;\r\nTHREE.UnsignedShortType = 1012;\r\nTHREE.IntType = 1013;\r\nTHREE.UnsignedIntType = 1014;\r\nTHREE.FloatType = 1015;\r\nTHREE.HalfFloatType = 1025;\r\n\r\n// Pixel types\r\n\r\n//THREE.UnsignedByteType = 1009;\r\nTHREE.UnsignedShort4444Type = 1016;\r\nTHREE.UnsignedShort5551Type = 1017;\r\nTHREE.UnsignedShort565Type = 1018;\r\n\r\n// Pixel formats\r\n\r\nTHREE.AlphaFormat = 1019;\r\nTHREE.RGBFormat = 1020;\r\nTHREE.RGBAFormat = 1021;\r\nTHREE.LuminanceFormat = 1022;\r\nTHREE.LuminanceAlphaFormat = 1023;\r\n// THREE.RGBEFormat handled as THREE.RGBAFormat in shaders\r\nTHREE.RGBEFormat = THREE.RGBAFormat; //1024;\r\n\r\n// DDS / ST3C Compressed texture formats\r\n\r\nTHREE.RGB_S3TC_DXT1_Format = 2001;\r\nTHREE.RGBA_S3TC_DXT1_Format = 2002;\r\nTHREE.RGBA_S3TC_DXT3_Format = 2003;\r\nTHREE.RGBA_S3TC_DXT5_Format = 2004;\r\n\r\n\r\n// PVRTC compressed texture formats\r\n\r\nTHREE.RGB_PVRTC_4BPPV1_Format = 2100;\r\nTHREE.RGB_PVRTC_2BPPV1_Format = 2101;\r\nTHREE.RGBA_PVRTC_4BPPV1_Format = 2102;\r\nTHREE.RGBA_PVRTC_2BPPV1_Format = 2103;\r\n\r\n\r\n// DEPRECATED\r\n\r\nTHREE.Projector = function () {\r\n\r\n\tTHREE.error( 'THREE.Projector has been moved to /examples/js/renderers/Projector.js.' );\r\n\r\n\tthis.projectVector = function ( vector, camera ) {\r\n\r\n\t\tTHREE.warn( 'THREE.Projector: .projectVector() is now vector.project().' );\r\n\t\tvector.project( camera );\r\n\r\n\t};\r\n\r\n\tthis.unprojectVector = function ( vector, camera ) {\r\n\r\n\t\tTHREE.warn( 'THREE.Projector: .unprojectVector() is now vector.unproject().' );\r\n\t\tvector.unproject( camera );\r\n\r\n\t};\r\n\r\n\tthis.pickingRay = function ( vector, camera ) {\r\n\r\n\t\tTHREE.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' );\r\n\r\n\t};\r\n\r\n};\r\n\r\nTHREE.CanvasRenderer = function () {\r\n\r\n\tTHREE.error( 'THREE.CanvasRenderer has been moved to /examples/js/renderers/CanvasRenderer.js' );\r\n\r\n\tthis.domElement = document.createElement( 'canvas' );\r\n\tthis.clear = function () {};\r\n\tthis.render = function () {};\r\n\tthis.setClearColor = function () {};\r\n\tthis.setSize = function () {};\r\n\r\n};\r\n\r\n// File:src/math/Color.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n */\r\n\r\nTHREE.Color = function ( color ) {\r\n\r\n\tif ( arguments.length === 3 ) {\r\n\r\n\t\treturn this.setRGB( arguments[ 0 ], arguments[ 1 ], arguments[ 2 ] );\r\n\r\n\t}\r\n\r\n\treturn this.set( color )\r\n\r\n};\r\n\r\nTHREE.Color.prototype = {\r\n\r\n\tconstructor: THREE.Color,\r\n\r\n\tr: 1, g: 1, b: 1,\r\n\r\n\tset: function ( value ) {\r\n\r\n\t\tif ( value instanceof THREE.Color ) {\r\n\r\n\t\t\tthis.copy( value );\r\n\r\n\t\t} else if ( typeof value === 'number' ) {\r\n\r\n\t\t\tthis.setHex( value );\r\n\r\n\t\t} else if ( typeof value === 'string' ) {\r\n\r\n\t\t\tthis.setStyle( value );\r\n\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetHex: function ( hex ) {\r\n\r\n\t\thex = Math.floor( hex );\r\n\r\n\t\tthis.r = ( hex >> 16 & 255 ) / 255;\r\n\t\tthis.g = ( hex >> 8 & 255 ) / 255;\r\n\t\tthis.b = ( hex & 255 ) / 255;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetRGB: function ( r, g, b ) {\r\n\r\n\t\tthis.r = r;\r\n\t\tthis.g = g;\r\n\t\tthis.b = b;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetHSL: function ( h, s, l ) {\r\n\r\n\t\t// h,s,l ranges are in 0.0 - 1.0\r\n\r\n\t\tif ( s === 0 ) {\r\n\r\n\t\t\tthis.r = this.g = this.b = l;\r\n\r\n\t\t} else {\r\n\r\n\t\t\tvar hue2rgb = function ( p, q, t ) {\r\n\r\n\t\t\t\tif ( t < 0 ) t += 1;\r\n\t\t\t\tif ( t > 1 ) t -= 1;\r\n\t\t\t\tif ( t < 1 / 6 ) return p + ( q - p ) * 6 * t;\r\n\t\t\t\tif ( t < 1 / 2 ) return q;\r\n\t\t\t\tif ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t );\r\n\t\t\t\treturn p;\r\n\r\n\t\t\t};\r\n\r\n\t\t\tvar p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s );\r\n\t\t\tvar q = ( 2 * l ) - p;\r\n\r\n\t\t\tthis.r = hue2rgb( q, p, h + 1 / 3 );\r\n\t\t\tthis.g = hue2rgb( q, p, h );\r\n\t\t\tthis.b = hue2rgb( q, p, h - 1 / 3 );\r\n\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetStyle: function ( style ) {\r\n\r\n\t\t// rgb(255,0,0)\r\n\r\n\t\tif ( /^rgb\\((\\d+), ?(\\d+), ?(\\d+)\\)$/i.test( style ) ) {\r\n\r\n\t\t\tvar color = /^rgb\\((\\d+), ?(\\d+), ?(\\d+)\\)$/i.exec( style );\r\n\r\n\t\t\tthis.r = Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255;\r\n\t\t\tthis.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255;\r\n\t\t\tthis.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255;\r\n\r\n\t\t\treturn this;\r\n\r\n\t\t}\r\n\r\n\t\t// rgb(100%,0%,0%)\r\n\r\n\t\tif ( /^rgb\\((\\d+)\\%, ?(\\d+)\\%, ?(\\d+)\\%\\)$/i.test( style ) ) {\r\n\r\n\t\t\tvar color = /^rgb\\((\\d+)\\%, ?(\\d+)\\%, ?(\\d+)\\%\\)$/i.exec( style );\r\n\r\n\t\t\tthis.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100;\r\n\t\t\tthis.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100;\r\n\t\t\tthis.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100;\r\n\r\n\t\t\treturn this;\r\n\r\n\t\t}\r\n\r\n\t\t// #ff0000\r\n\r\n\t\tif ( /^\\#([0-9a-f]{6})$/i.test( style ) ) {\r\n\r\n\t\t\tvar color = /^\\#([0-9a-f]{6})$/i.exec( style );\r\n\r\n\t\t\tthis.setHex( parseInt( color[ 1 ], 16 ) );\r\n\r\n\t\t\treturn this;\r\n\r\n\t\t}\r\n\r\n\t\t// #f00\r\n\r\n\t\tif ( /^\\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.test( style ) ) {\r\n\r\n\t\t\tvar color = /^\\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec( style );\r\n\r\n\t\t\tthis.setHex( parseInt( color[ 1 ] + color[ 1 ] + color[ 2 ] + color[ 2 ] + color[ 3 ] + color[ 3 ], 16 ) );\r\n\r\n\t\t\treturn this;\r\n\r\n\t\t}\r\n\r\n\t\t// red\r\n\r\n\t\tif ( /^(\\w+)$/i.test( style ) ) {\r\n\r\n\t\t\tthis.setHex( THREE.ColorKeywords[ style ] );\r\n\r\n\t\t\treturn this;\r\n\r\n\t\t}\r\n\r\n\r\n\t},\r\n\r\n\tcopy: function ( color ) {\r\n\r\n\t\tthis.r = color.r;\r\n\t\tthis.g = color.g;\r\n\t\tthis.b = color.b;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tcopyGammaToLinear: function ( color, gammaFactor ) {\r\n\r\n\t\tif ( gammaFactor === undefined ) gammaFactor = 2.0;\r\n\r\n\t\tthis.r = Math.pow( color.r, gammaFactor );\r\n\t\tthis.g = Math.pow( color.g, gammaFactor );\r\n\t\tthis.b = Math.pow( color.b, gammaFactor );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tcopyLinearToGamma: function ( color, gammaFactor ) {\r\n\r\n\t\tif ( gammaFactor === undefined ) gammaFactor = 2.0;\r\n\r\n\t\tvar safeInverse = ( gammaFactor > 0 ) ? ( 1.0 / gammaFactor ) : 1.0;\r\n\r\n\t\tthis.r = Math.pow( color.r, safeInverse );\r\n\t\tthis.g = Math.pow( color.g, safeInverse );\r\n\t\tthis.b = Math.pow( color.b, safeInverse );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tconvertGammaToLinear: function () {\r\n\r\n\t\tvar r = this.r, g = this.g, b = this.b;\r\n\r\n\t\tthis.r = r * r;\r\n\t\tthis.g = g * g;\r\n\t\tthis.b = b * b;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tconvertLinearToGamma: function () {\r\n\r\n\t\tthis.r = Math.sqrt( this.r );\r\n\t\tthis.g = Math.sqrt( this.g );\r\n\t\tthis.b = Math.sqrt( this.b );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tgetHex: function () {\r\n\r\n\t\treturn ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0;\r\n\r\n\t},\r\n\r\n\tgetHexString: function () {\r\n\r\n\t\treturn ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 );\r\n\r\n\t},\r\n\r\n\tgetHSL: function ( optionalTarget ) {\r\n\r\n\t\t// h,s,l ranges are in 0.0 - 1.0\r\n\r\n\t\tvar hsl = optionalTarget || { h: 0, s: 0, l: 0 };\r\n\r\n\t\tvar r = this.r, g = this.g, b = this.b;\r\n\r\n\t\tvar max = Math.max( r, g, b );\r\n\t\tvar min = Math.min( r, g, b );\r\n\r\n\t\tvar hue, saturation;\r\n\t\tvar lightness = ( min + max ) / 2.0;\r\n\r\n\t\tif ( min === max ) {\r\n\r\n\t\t\thue = 0;\r\n\t\t\tsaturation = 0;\r\n\r\n\t\t} else {\r\n\r\n\t\t\tvar delta = max - min;\r\n\r\n\t\t\tsaturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min );\r\n\r\n\t\t\tswitch ( max ) {\r\n\r\n\t\t\t\tcase r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break;\r\n\t\t\t\tcase g: hue = ( b - r ) / delta + 2; break;\r\n\t\t\t\tcase b: hue = ( r - g ) / delta + 4; break;\r\n\r\n\t\t\t}\r\n\r\n\t\t\thue /= 6;\r\n\r\n\t\t}\r\n\r\n\t\thsl.h = hue;\r\n\t\thsl.s = saturation;\r\n\t\thsl.l = lightness;\r\n\r\n\t\treturn hsl;\r\n\r\n\t},\r\n\r\n\tgetStyle: function () {\r\n\r\n\t\treturn 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')';\r\n\r\n\t},\r\n\r\n\toffsetHSL: function ( h, s, l ) {\r\n\r\n\t\tvar hsl = this.getHSL();\r\n\r\n\t\thsl.h += h; hsl.s += s; hsl.l += l;\r\n\r\n\t\tthis.setHSL( hsl.h, hsl.s, hsl.l );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tadd: function ( color ) {\r\n\r\n\t\tthis.r += color.r;\r\n\t\tthis.g += color.g;\r\n\t\tthis.b += color.b;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\taddColors: function ( color1, color2 ) {\r\n\r\n\t\tthis.r = color1.r + color2.r;\r\n\t\tthis.g = color1.g + color2.g;\r\n\t\tthis.b = color1.b + color2.b;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\taddScalar: function ( s ) {\r\n\r\n\t\tthis.r += s;\r\n\t\tthis.g += s;\r\n\t\tthis.b += s;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tmultiply: function ( color ) {\r\n\r\n\t\tthis.r *= color.r;\r\n\t\tthis.g *= color.g;\r\n\t\tthis.b *= color.b;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tmultiplyScalar: function ( s ) {\r\n\r\n\t\tthis.r *= s;\r\n\t\tthis.g *= s;\r\n\t\tthis.b *= s;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tlerp: function ( color, alpha ) {\r\n\r\n\t\tthis.r += ( color.r - this.r ) * alpha;\r\n\t\tthis.g += ( color.g - this.g ) * alpha;\r\n\t\tthis.b += ( color.b - this.b ) * alpha;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tequals: function ( c ) {\r\n\r\n\t\treturn ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b );\r\n\r\n\t},\r\n\r\n\tfromArray: function ( array ) {\r\n\r\n\t\tthis.r = array[ 0 ];\r\n\t\tthis.g = array[ 1 ];\r\n\t\tthis.b = array[ 2 ];\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\ttoArray: function ( array, offset ) {\r\n\r\n\t\tif ( array === undefined ) array = [];\r\n\t\tif ( offset === undefined ) offset = 0;\r\n\r\n\t\tarray[ offset ] = this.r;\r\n\t\tarray[ offset + 1 ] = this.g;\r\n\t\tarray[ offset + 2 ] = this.b;\r\n\r\n\t\treturn array;\r\n\t},\r\n\r\n\tclone: function () {\r\n\r\n\t\treturn new THREE.Color().setRGB( this.r, this.g, this.b );\r\n\r\n\t}\r\n\r\n};\r\n\r\nTHREE.ColorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF,\r\n'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2,\r\n'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50,\r\n'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B,\r\n'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B,\r\n'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F,\r\n'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3,\r\n'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222,\r\n'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700,\r\n'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4,\r\n'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00,\r\n'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3,\r\n'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA,\r\n'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32,\r\n'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3,\r\n'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC,\r\n'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD,\r\n'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6,\r\n'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9,\r\n'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F,\r\n'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE,\r\n'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA,\r\n'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0,\r\n'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 };\r\n\r\n// File:src/math/Quaternion.js\r\n\r\n/**\r\n * @author mikael emtinger / http://gomo.se/\r\n * @author alteredq / http://alteredqualia.com/\r\n * @author WestLangley / http://github.com/WestLangley\r\n * @author bhouston / http://exocortex.com\r\n */\r\n\r\nTHREE.Quaternion = function ( x, y, z, w ) {\r\n\r\n\tthis._x = x || 0;\r\n\tthis._y = y || 0;\r\n\tthis._z = z || 0;\r\n\tthis._w = ( w !== undefined ) ? w : 1;\r\n\r\n};\r\n\r\nTHREE.Quaternion.prototype = {\r\n\r\n\tconstructor: THREE.Quaternion,\r\n\r\n\t_x: 0,_y: 0, _z: 0, _w: 0,\r\n\r\n\tget x () {\r\n\r\n\t\treturn this._x;\r\n\r\n\t},\r\n\r\n\tset x ( value ) {\r\n\r\n\t\tthis._x = value;\r\n\t\tthis.onChangeCallback();\r\n\r\n\t},\r\n\r\n\tget y () {\r\n\r\n\t\treturn this._y;\r\n\r\n\t},\r\n\r\n\tset y ( value ) {\r\n\r\n\t\tthis._y = value;\r\n\t\tthis.onChangeCallback();\r\n\r\n\t},\r\n\r\n\tget z () {\r\n\r\n\t\treturn this._z;\r\n\r\n\t},\r\n\r\n\tset z ( value ) {\r\n\r\n\t\tthis._z = value;\r\n\t\tthis.onChangeCallback();\r\n\r\n\t},\r\n\r\n\tget w () {\r\n\r\n\t\treturn this._w;\r\n\r\n\t},\r\n\r\n\tset w ( value ) {\r\n\r\n\t\tthis._w = value;\r\n\t\tthis.onChangeCallback();\r\n\r\n\t},\r\n\r\n\tset: function ( x, y, z, w ) {\r\n\r\n\t\tthis._x = x;\r\n\t\tthis._y = y;\r\n\t\tthis._z = z;\r\n\t\tthis._w = w;\r\n\r\n\t\tthis.onChangeCallback();\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tcopy: function ( quaternion ) {\r\n\r\n\t\tthis._x = quaternion.x;\r\n\t\tthis._y = quaternion.y;\r\n\t\tthis._z = quaternion.z;\r\n\t\tthis._w = quaternion.w;\r\n\r\n\t\tthis.onChangeCallback();\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetFromEuler: function ( euler, update ) {\r\n\r\n\t\tif ( euler instanceof THREE.Euler === false ) {\r\n\r\n\t\t\tthrow new Error( 'THREE.Quaternion: .setFromEuler() now expects a Euler rotation rather than a Vector3 and order.' );\r\n\t\t}\r\n\r\n\t\t// http://www.mathworks.com/matlabcentral/fileexchange/\r\n\t\t// \t20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/\r\n\t\t//\tcontent/SpinCalc.m\r\n\r\n\t\tvar c1 = Math.cos( euler._x / 2 );\r\n\t\tvar c2 = Math.cos( euler._y / 2 );\r\n\t\tvar c3 = Math.cos( euler._z / 2 );\r\n\t\tvar s1 = Math.sin( euler._x / 2 );\r\n\t\tvar s2 = Math.sin( euler._y / 2 );\r\n\t\tvar s3 = Math.sin( euler._z / 2 );\r\n\r\n\t\tif ( euler.order === 'XYZ' ) {\r\n\r\n\t\t\tthis._x = s1 * c2 * c3 + c1 * s2 * s3;\r\n\t\t\tthis._y = c1 * s2 * c3 - s1 * c2 * s3;\r\n\t\t\tthis._z = c1 * c2 * s3 + s1 * s2 * c3;\r\n\t\t\tthis._w = c1 * c2 * c3 - s1 * s2 * s3;\r\n\r\n\t\t} else if ( euler.order === 'YXZ' ) {\r\n\r\n\t\t\tthis._x = s1 * c2 * c3 + c1 * s2 * s3;\r\n\t\t\tthis._y = c1 * s2 * c3 - s1 * c2 * s3;\r\n\t\t\tthis._z = c1 * c2 * s3 - s1 * s2 * c3;\r\n\t\t\tthis._w = c1 * c2 * c3 + s1 * s2 * s3;\r\n\r\n\t\t} else if ( euler.order === 'ZXY' ) {\r\n\r\n\t\t\tthis._x = s1 * c2 * c3 - c1 * s2 * s3;\r\n\t\t\tthis._y = c1 * s2 * c3 + s1 * c2 * s3;\r\n\t\t\tthis._z = c1 * c2 * s3 + s1 * s2 * c3;\r\n\t\t\tthis._w = c1 * c2 * c3 - s1 * s2 * s3;\r\n\r\n\t\t} else if ( euler.order === 'ZYX' ) {\r\n\r\n\t\t\tthis._x = s1 * c2 * c3 - c1 * s2 * s3;\r\n\t\t\tthis._y = c1 * s2 * c3 + s1 * c2 * s3;\r\n\t\t\tthis._z = c1 * c2 * s3 - s1 * s2 * c3;\r\n\t\t\tthis._w = c1 * c2 * c3 + s1 * s2 * s3;\r\n\r\n\t\t} else if ( euler.order === 'YZX' ) {\r\n\r\n\t\t\tthis._x = s1 * c2 * c3 + c1 * s2 * s3;\r\n\t\t\tthis._y = c1 * s2 * c3 + s1 * c2 * s3;\r\n\t\t\tthis._z = c1 * c2 * s3 - s1 * s2 * c3;\r\n\t\t\tthis._w = c1 * c2 * c3 - s1 * s2 * s3;\r\n\r\n\t\t} else if ( euler.order === 'XZY' ) {\r\n\r\n\t\t\tthis._x = s1 * c2 * c3 - c1 * s2 * s3;\r\n\t\t\tthis._y = c1 * s2 * c3 - s1 * c2 * s3;\r\n\t\t\tthis._z = c1 * c2 * s3 + s1 * s2 * c3;\r\n\t\t\tthis._w = c1 * c2 * c3 + s1 * s2 * s3;\r\n\r\n\t\t}\r\n\r\n\t\tif ( update !== false ) this.onChangeCallback();\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetFromAxisAngle: function ( axis, angle ) {\r\n\r\n\t\t// http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm\r\n\r\n\t\t// assumes axis is normalized\r\n\r\n\t\tvar halfAngle = angle / 2, s = Math.sin( halfAngle );\r\n\r\n\t\tthis._x = axis.x * s;\r\n\t\tthis._y = axis.y * s;\r\n\t\tthis._z = axis.z * s;\r\n\t\tthis._w = Math.cos( halfAngle );\r\n\r\n\t\tthis.onChangeCallback();\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetFromRotationMatrix: function ( m ) {\r\n\r\n\t\t// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm\r\n\r\n\t\t// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)\r\n\r\n\t\tvar te = m.elements,\r\n\r\n\t\t\tm11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],\r\n\t\t\tm21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],\r\n\t\t\tm31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ],\r\n\r\n\t\t\ttrace = m11 + m22 + m33,\r\n\t\t\ts;\r\n\r\n\t\tif ( trace > 0 ) {\r\n\r\n\t\t\ts = 0.5 / Math.sqrt( trace + 1.0 );\r\n\r\n\t\t\tthis._w = 0.25 / s;\r\n\t\t\tthis._x = ( m32 - m23 ) * s;\r\n\t\t\tthis._y = ( m13 - m31 ) * s;\r\n\t\t\tthis._z = ( m21 - m12 ) * s;\r\n\r\n\t\t} else if ( m11 > m22 && m11 > m33 ) {\r\n\r\n\t\t\ts = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 );\r\n\r\n\t\t\tthis._w = ( m32 - m23 ) / s;\r\n\t\t\tthis._x = 0.25 * s;\r\n\t\t\tthis._y = ( m12 + m21 ) / s;\r\n\t\t\tthis._z = ( m13 + m31 ) / s;\r\n\r\n\t\t} else if ( m22 > m33 ) {\r\n\r\n\t\t\ts = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 );\r\n\r\n\t\t\tthis._w = ( m13 - m31 ) / s;\r\n\t\t\tthis._x = ( m12 + m21 ) / s;\r\n\t\t\tthis._y = 0.25 * s;\r\n\t\t\tthis._z = ( m23 + m32 ) / s;\r\n\r\n\t\t} else {\r\n\r\n\t\t\ts = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 );\r\n\r\n\t\t\tthis._w = ( m21 - m12 ) / s;\r\n\t\t\tthis._x = ( m13 + m31 ) / s;\r\n\t\t\tthis._y = ( m23 + m32 ) / s;\r\n\t\t\tthis._z = 0.25 * s;\r\n\r\n\t\t}\r\n\r\n\t\tthis.onChangeCallback();\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetFromUnitVectors: function () {\r\n\r\n\t\t// http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final\r\n\r\n\t\t// assumes direction vectors vFrom and vTo are normalized\r\n\r\n\t\tvar v1, r;\r\n\r\n\t\tvar EPS = 0.000001;\r\n\r\n\t\treturn function ( vFrom, vTo ) {\r\n\r\n\t\t\tif ( v1 === undefined ) v1 = new THREE.Vector3();\r\n\r\n\t\t\tr = vFrom.dot( vTo ) + 1;\r\n\r\n\t\t\tif ( r < EPS ) {\r\n\r\n\t\t\t\tr = 0;\r\n\r\n\t\t\t\tif ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) {\r\n\r\n\t\t\t\t\tv1.set( - vFrom.y, vFrom.x, 0 );\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\tv1.set( 0, - vFrom.z, vFrom.y );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tv1.crossVectors( vFrom, vTo );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tthis._x = v1.x;\r\n\t\t\tthis._y = v1.y;\r\n\t\t\tthis._z = v1.z;\r\n\t\t\tthis._w = r;\r\n\r\n\t\t\tthis.normalize();\r\n\r\n\t\t\treturn this;\r\n\r\n\t\t}\r\n\r\n\t}(),\r\n\r\n\tinverse: function () {\r\n\r\n\t\tthis.conjugate().normalize();\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tconjugate: function () {\r\n\r\n\t\tthis._x *= - 1;\r\n\t\tthis._y *= - 1;\r\n\t\tthis._z *= - 1;\r\n\r\n\t\tthis.onChangeCallback();\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tdot: function ( v ) {\r\n\r\n\t\treturn this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w;\r\n\r\n\t},\r\n\r\n\tlengthSq: function () {\r\n\r\n\t\treturn this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w;\r\n\r\n\t},\r\n\r\n\tlength: function () {\r\n\r\n\t\treturn Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w );\r\n\r\n\t},\r\n\r\n\tnormalize: function () {\r\n\r\n\t\tvar l = this.length();\r\n\r\n\t\tif ( l === 0 ) {\r\n\r\n\t\t\tthis._x = 0;\r\n\t\t\tthis._y = 0;\r\n\t\t\tthis._z = 0;\r\n\t\t\tthis._w = 1;\r\n\r\n\t\t} else {\r\n\r\n\t\t\tl = 1 / l;\r\n\r\n\t\t\tthis._x = this._x * l;\r\n\t\t\tthis._y = this._y * l;\r\n\t\t\tthis._z = this._z * l;\r\n\t\t\tthis._w = this._w * l;\r\n\r\n\t\t}\r\n\r\n\t\tthis.onChangeCallback();\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tmultiply: function ( q, p ) {\r\n\r\n\t\tif ( p !== undefined ) {\r\n\r\n\t\t\tTHREE.warn( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' );\r\n\t\t\treturn this.multiplyQuaternions( q, p );\r\n\r\n\t\t}\r\n\r\n\t\treturn this.multiplyQuaternions( this, q );\r\n\r\n\t},\r\n\r\n\tmultiplyQuaternions: function ( a, b ) {\r\n\r\n\t\t// from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm\r\n\r\n\t\tvar qax = a._x, qay = a._y, qaz = a._z, qaw = a._w;\r\n\t\tvar qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w;\r\n\r\n\t\tthis._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;\r\n\t\tthis._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;\r\n\t\tthis._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;\r\n\t\tthis._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;\r\n\r\n\t\tthis.onChangeCallback();\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tmultiplyVector3: function ( vector ) {\r\n\r\n\t\tTHREE.warn( 'THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' );\r\n\t\treturn vector.applyQuaternion( this );\r\n\r\n\t},\r\n\r\n\tslerp: function ( qb, t ) {\r\n\r\n\t\tif ( t === 0 ) return this;\r\n\t\tif ( t === 1 ) return this.copy( qb );\r\n\r\n\t\tvar x = this._x, y = this._y, z = this._z, w = this._w;\r\n\r\n\t\t// http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/\r\n\r\n\t\tvar cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z;\r\n\r\n\t\tif ( cosHalfTheta < 0 ) {\r\n\r\n\t\t\tthis._w = - qb._w;\r\n\t\t\tthis._x = - qb._x;\r\n\t\t\tthis._y = - qb._y;\r\n\t\t\tthis._z = - qb._z;\r\n\r\n\t\t\tcosHalfTheta = - cosHalfTheta;\r\n\r\n\t\t} else {\r\n\r\n\t\t\tthis.copy( qb );\r\n\r\n\t\t}\r\n\r\n\t\tif ( cosHalfTheta >= 1.0 ) {\r\n\r\n\t\t\tthis._w = w;\r\n\t\t\tthis._x = x;\r\n\t\t\tthis._y = y;\r\n\t\t\tthis._z = z;\r\n\r\n\t\t\treturn this;\r\n\r\n\t\t}\r\n\r\n\t\tvar halfTheta = Math.acos( cosHalfTheta );\r\n\t\tvar sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta );\r\n\r\n\t\tif ( Math.abs( sinHalfTheta ) < 0.001 ) {\r\n\r\n\t\t\tthis._w = 0.5 * ( w + this._w );\r\n\t\t\tthis._x = 0.5 * ( x + this._x );\r\n\t\t\tthis._y = 0.5 * ( y + this._y );\r\n\t\t\tthis._z = 0.5 * ( z + this._z );\r\n\r\n\t\t\treturn this;\r\n\r\n\t\t}\r\n\r\n\t\tvar ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta,\r\n\t\tratioB = Math.sin( t * halfTheta ) / sinHalfTheta;\r\n\r\n\t\tthis._w = ( w * ratioA + this._w * ratioB );\r\n\t\tthis._x = ( x * ratioA + this._x * ratioB );\r\n\t\tthis._y = ( y * ratioA + this._y * ratioB );\r\n\t\tthis._z = ( z * ratioA + this._z * ratioB );\r\n\r\n\t\tthis.onChangeCallback();\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tequals: function ( quaternion ) {\r\n\r\n\t\treturn ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w );\r\n\r\n\t},\r\n\r\n\tfromArray: function ( array, offset ) {\r\n\r\n\t\tif ( offset === undefined ) offset = 0;\r\n\r\n\t\tthis._x = array[ offset ];\r\n\t\tthis._y = array[ offset + 1 ];\r\n\t\tthis._z = array[ offset + 2 ];\r\n\t\tthis._w = array[ offset + 3 ];\r\n\r\n\t\tthis.onChangeCallback();\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\ttoArray: function ( array, offset ) {\r\n\r\n\t\tif ( array === undefined ) array = [];\r\n\t\tif ( offset === undefined ) offset = 0;\r\n\r\n\t\tarray[ offset ] = this._x;\r\n\t\tarray[ offset + 1 ] = this._y;\r\n\t\tarray[ offset + 2 ] = this._z;\r\n\t\tarray[ offset + 3 ] = this._w;\r\n\r\n\t\treturn array;\r\n\r\n\t},\r\n\r\n\tonChange: function ( callback ) {\r\n\r\n\t\tthis.onChangeCallback = callback;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tonChangeCallback: function () {},\r\n\r\n\tclone: function () {\r\n\r\n\t\treturn new THREE.Quaternion( this._x, this._y, this._z, this._w );\r\n\r\n\t}\r\n\r\n};\r\n\r\nTHREE.Quaternion.slerp = function ( qa, qb, qm, t ) {\r\n\r\n\treturn qm.copy( qa ).slerp( qb, t );\r\n\r\n}\r\n\r\n// File:src/math/Vector2.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n * @author philogb / http://blog.thejit.org/\r\n * @author egraether / http://egraether.com/\r\n * @author zz85 / http://www.lab4games.net/zz85/blog\r\n */\r\n\r\nTHREE.Vector2 = function ( x, y ) {\r\n\r\n\tthis.x = x || 0;\r\n\tthis.y = y || 0;\r\n\r\n};\r\n\r\nTHREE.Vector2.prototype = {\r\n\r\n\tconstructor: THREE.Vector2,\r\n\r\n\tset: function ( x, y ) {\r\n\r\n\t\tthis.x = x;\r\n\t\tthis.y = y;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetX: function ( x ) {\r\n\r\n\t\tthis.x = x;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetY: function ( y ) {\r\n\r\n\t\tthis.y = y;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetComponent: function ( index, value ) {\r\n\r\n\t\tswitch ( index ) {\r\n\r\n\t\t\tcase 0: this.x = value; break;\r\n\t\t\tcase 1: this.y = value; break;\r\n\t\t\tdefault: throw new Error( 'index is out of range: ' + index );\r\n\r\n\t\t}\r\n\r\n\t},\r\n\r\n\tgetComponent: function ( index ) {\r\n\r\n\t\tswitch ( index ) {\r\n\r\n\t\t\tcase 0: return this.x;\r\n\t\t\tcase 1: return this.y;\r\n\t\t\tdefault: throw new Error( 'index is out of range: ' + index );\r\n\r\n\t\t}\r\n\r\n\t},\r\n\r\n\tcopy: function ( v ) {\r\n\r\n\t\tthis.x = v.x;\r\n\t\tthis.y = v.y;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tadd: function ( v, w ) {\r\n\r\n\t\tif ( w !== undefined ) {\r\n\r\n\t\t\tTHREE.warn( 'THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );\r\n\t\t\treturn this.addVectors( v, w );\r\n\r\n\t\t}\r\n\r\n\t\tthis.x += v.x;\r\n\t\tthis.y += v.y;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\taddScalar: function ( s ) {\r\n\r\n\t\tthis.x += s;\r\n\t\tthis.y += s;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\taddVectors: function ( a, b ) {\r\n\r\n\t\tthis.x = a.x + b.x;\r\n\t\tthis.y = a.y + b.y;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsub: function ( v, w ) {\r\n\r\n\t\tif ( w !== undefined ) {\r\n\r\n\t\t\tTHREE.warn( 'THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );\r\n\t\t\treturn this.subVectors( v, w );\r\n\r\n\t\t}\r\n\r\n\t\tthis.x -= v.x;\r\n\t\tthis.y -= v.y;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsubScalar: function ( s ) {\r\n\r\n\t\tthis.x -= s;\r\n\t\tthis.y -= s;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsubVectors: function ( a, b ) {\r\n\r\n\t\tthis.x = a.x - b.x;\r\n\t\tthis.y = a.y - b.y;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tmultiply: function ( v ) {\r\n\r\n\t\tthis.x *= v.x;\r\n\t\tthis.y *= v.y;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tmultiplyScalar: function ( s ) {\r\n\r\n\t\tthis.x *= s;\r\n\t\tthis.y *= s;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tdivide: function ( v ) {\r\n\r\n\t\tthis.x /= v.x;\r\n\t\tthis.y /= v.y;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tdivideScalar: function ( scalar ) {\r\n\r\n\t\tif ( scalar !== 0 ) {\r\n\r\n\t\t\tvar invScalar = 1 / scalar;\r\n\r\n\t\t\tthis.x *= invScalar;\r\n\t\t\tthis.y *= invScalar;\r\n\r\n\t\t} else {\r\n\r\n\t\t\tthis.x = 0;\r\n\t\t\tthis.y = 0;\r\n\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tmin: function ( v ) {\r\n\r\n\t\tif ( this.x > v.x ) {\r\n\r\n\t\t\tthis.x = v.x;\r\n\r\n\t\t}\r\n\r\n\t\tif ( this.y > v.y ) {\r\n\r\n\t\t\tthis.y = v.y;\r\n\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tmax: function ( v ) {\r\n\r\n\t\tif ( this.x < v.x ) {\r\n\r\n\t\t\tthis.x = v.x;\r\n\r\n\t\t}\r\n\r\n\t\tif ( this.y < v.y ) {\r\n\r\n\t\t\tthis.y = v.y;\r\n\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tclamp: function ( min, max ) {\r\n\r\n\t\t// This function assumes min < max, if this assumption isn't true it will not operate correctly\r\n\r\n\t\tif ( this.x < min.x ) {\r\n\r\n\t\t\tthis.x = min.x;\r\n\r\n\t\t} else if ( this.x > max.x ) {\r\n\r\n\t\t\tthis.x = max.x;\r\n\r\n\t\t}\r\n\r\n\t\tif ( this.y < min.y ) {\r\n\r\n\t\t\tthis.y = min.y;\r\n\r\n\t\t} else if ( this.y > max.y ) {\r\n\r\n\t\t\tthis.y = max.y;\r\n\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\tclampScalar: ( function () {\r\n\r\n\t\tvar min, max;\r\n\r\n\t\treturn function ( minVal, maxVal ) {\r\n\r\n\t\t\tif ( min === undefined ) {\r\n\r\n\t\t\t\tmin = new THREE.Vector2();\r\n\t\t\t\tmax = new THREE.Vector2();\r\n\r\n\t\t\t}\r\n\r\n\t\t\tmin.set( minVal, minVal );\r\n\t\t\tmax.set( maxVal, maxVal );\r\n\r\n\t\t\treturn this.clamp( min, max );\r\n\r\n\t\t};\r\n\r\n\t} )(),\r\n\r\n\tfloor: function () {\r\n\r\n\t\tthis.x = Math.floor( this.x );\r\n\t\tthis.y = Math.floor( this.y );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tceil: function () {\r\n\r\n\t\tthis.x = Math.ceil( this.x );\r\n\t\tthis.y = Math.ceil( this.y );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tround: function () {\r\n\r\n\t\tthis.x = Math.round( this.x );\r\n\t\tthis.y = Math.round( this.y );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\troundToZero: function () {\r\n\r\n\t\tthis.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );\r\n\t\tthis.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tnegate: function () {\r\n\r\n\t\tthis.x = - this.x;\r\n\t\tthis.y = - this.y;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tdot: function ( v ) {\r\n\r\n\t\treturn this.x * v.x + this.y * v.y;\r\n\r\n\t},\r\n\r\n\tlengthSq: function () {\r\n\r\n\t\treturn this.x * this.x + this.y * this.y;\r\n\r\n\t},\r\n\r\n\tlength: function () {\r\n\r\n\t\treturn Math.sqrt( this.x * this.x + this.y * this.y );\r\n\r\n\t},\r\n\r\n\tnormalize: function () {\r\n\r\n\t\treturn this.divideScalar( this.length() );\r\n\r\n\t},\r\n\r\n\tdistanceTo: function ( v ) {\r\n\r\n\t\treturn Math.sqrt( this.distanceToSquared( v ) );\r\n\r\n\t},\r\n\r\n\tdistanceToSquared: function ( v ) {\r\n\r\n\t\tvar dx = this.x - v.x, dy = this.y - v.y;\r\n\t\treturn dx * dx + dy * dy;\r\n\r\n\t},\r\n\r\n\tsetLength: function ( l ) {\r\n\r\n\t\tvar oldLength = this.length();\r\n\r\n\t\tif ( oldLength !== 0 && l !== oldLength ) {\r\n\r\n\t\t\tthis.multiplyScalar( l / oldLength );\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tlerp: function ( v, alpha ) {\r\n\r\n\t\tthis.x += ( v.x - this.x ) * alpha;\r\n\t\tthis.y += ( v.y - this.y ) * alpha;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tlerpVectors: function ( v1, v2, alpha ) {\r\n\r\n\t\tthis.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tequals: function ( v ) {\r\n\r\n\t\treturn ( ( v.x === this.x ) && ( v.y === this.y ) );\r\n\r\n\t},\r\n\r\n\tfromArray: function ( array, offset ) {\r\n\r\n\t\tif ( offset === undefined ) offset = 0;\r\n\r\n\t\tthis.x = array[ offset ];\r\n\t\tthis.y = array[ offset + 1 ];\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\ttoArray: function ( array, offset ) {\r\n\r\n\t\tif ( array === undefined ) array = [];\r\n\t\tif ( offset === undefined ) offset = 0;\r\n\r\n\t\tarray[ offset ] = this.x;\r\n\t\tarray[ offset + 1 ] = this.y;\r\n\r\n\t\treturn array;\r\n\r\n\t},\r\n\r\n\tfromAttribute: function ( attribute, index, offset ) {\r\n\r\n\t\tif ( offset === undefined ) offset = 0;\r\n\r\n\t\tindex = index * attribute.itemSize + offset;\r\n\r\n\t\tthis.x = attribute.array[ index ];\r\n\t\tthis.y = attribute.array[ index + 1 ];\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tclone: function () {\r\n\r\n\t\treturn new THREE.Vector2( this.x, this.y );\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/math/Vector3.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n * @author *kile / http://kile.stravaganza.org/\r\n * @author philogb / http://blog.thejit.org/\r\n * @author mikael emtinger / http://gomo.se/\r\n * @author egraether / http://egraether.com/\r\n * @author WestLangley / http://github.com/WestLangley\r\n */\r\n\r\nTHREE.Vector3 = function ( x, y, z ) {\r\n\r\n\tthis.x = x || 0;\r\n\tthis.y = y || 0;\r\n\tthis.z = z || 0;\r\n\r\n};\r\n\r\nTHREE.Vector3.prototype = {\r\n\r\n\tconstructor: THREE.Vector3,\r\n\r\n\tset: function ( x, y, z ) {\r\n\r\n\t\tthis.x = x;\r\n\t\tthis.y = y;\r\n\t\tthis.z = z;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetX: function ( x ) {\r\n\r\n\t\tthis.x = x;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetY: function ( y ) {\r\n\r\n\t\tthis.y = y;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetZ: function ( z ) {\r\n\r\n\t\tthis.z = z;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetComponent: function ( index, value ) {\r\n\r\n\t\tswitch ( index ) {\r\n\r\n\t\t\tcase 0: this.x = value; break;\r\n\t\t\tcase 1: this.y = value; break;\r\n\t\t\tcase 2: this.z = value; break;\r\n\t\t\tdefault: throw new Error( 'index is out of range: ' + index );\r\n\r\n\t\t}\r\n\r\n\t},\r\n\r\n\tgetComponent: function ( index ) {\r\n\r\n\t\tswitch ( index ) {\r\n\r\n\t\t\tcase 0: return this.x;\r\n\t\t\tcase 1: return this.y;\r\n\t\t\tcase 2: return this.z;\r\n\t\t\tdefault: throw new Error( 'index is out of range: ' + index );\r\n\r\n\t\t}\r\n\r\n\t},\r\n\r\n\tcopy: function ( v ) {\r\n\r\n\t\tthis.x = v.x;\r\n\t\tthis.y = v.y;\r\n\t\tthis.z = v.z;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tadd: function ( v, w ) {\r\n\r\n\t\tif ( w !== undefined ) {\r\n\r\n\t\t\tTHREE.warn( 'THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );\r\n\t\t\treturn this.addVectors( v, w );\r\n\r\n\t\t}\r\n\r\n\t\tthis.x += v.x;\r\n\t\tthis.y += v.y;\r\n\t\tthis.z += v.z;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\taddScalar: function ( s ) {\r\n\r\n\t\tthis.x += s;\r\n\t\tthis.y += s;\r\n\t\tthis.z += s;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\taddVectors: function ( a, b ) {\r\n\r\n\t\tthis.x = a.x + b.x;\r\n\t\tthis.y = a.y + b.y;\r\n\t\tthis.z = a.z + b.z;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsub: function ( v, w ) {\r\n\r\n\t\tif ( w !== undefined ) {\r\n\r\n\t\t\tTHREE.warn( 'THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );\r\n\t\t\treturn this.subVectors( v, w );\r\n\r\n\t\t}\r\n\r\n\t\tthis.x -= v.x;\r\n\t\tthis.y -= v.y;\r\n\t\tthis.z -= v.z;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\t\r\n\tsubScalar: function ( s ) {\r\n\r\n\t\tthis.x -= s;\r\n\t\tthis.y -= s;\r\n\t\tthis.z -= s;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsubVectors: function ( a, b ) {\r\n\r\n\t\tthis.x = a.x - b.x;\r\n\t\tthis.y = a.y - b.y;\r\n\t\tthis.z = a.z - b.z;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tmultiply: function ( v, w ) {\r\n\r\n\t\tif ( w !== undefined ) {\r\n\r\n\t\t\tTHREE.warn( 'THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' );\r\n\t\t\treturn this.multiplyVectors( v, w );\r\n\r\n\t\t}\r\n\r\n\t\tthis.x *= v.x;\r\n\t\tthis.y *= v.y;\r\n\t\tthis.z *= v.z;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tmultiplyScalar: function ( scalar ) {\r\n\r\n\t\tthis.x *= scalar;\r\n\t\tthis.y *= scalar;\r\n\t\tthis.z *= scalar;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tmultiplyVectors: function ( a, b ) {\r\n\r\n\t\tthis.x = a.x * b.x;\r\n\t\tthis.y = a.y * b.y;\r\n\t\tthis.z = a.z * b.z;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tapplyEuler: function () {\r\n\r\n\t\tvar quaternion;\r\n\r\n\t\treturn function ( euler ) {\r\n\r\n\t\t\tif ( euler instanceof THREE.Euler === false ) {\r\n\r\n\t\t\t\tTHREE.error( 'THREE.Vector3: .applyEuler() now expects a Euler rotation rather than a Vector3 and order.' );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( quaternion === undefined ) quaternion = new THREE.Quaternion();\r\n\r\n\t\t\tthis.applyQuaternion( quaternion.setFromEuler( euler ) );\r\n\r\n\t\t\treturn this;\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\tapplyAxisAngle: function () {\r\n\r\n\t\tvar quaternion;\r\n\r\n\t\treturn function ( axis, angle ) {\r\n\r\n\t\t\tif ( quaternion === undefined ) quaternion = new THREE.Quaternion();\r\n\r\n\t\t\tthis.applyQuaternion( quaternion.setFromAxisAngle( axis, angle ) );\r\n\r\n\t\t\treturn this;\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\tapplyMatrix3: function ( m ) {\r\n\r\n\t\tvar x = this.x;\r\n\t\tvar y = this.y;\r\n\t\tvar z = this.z;\r\n\r\n\t\tvar e = m.elements;\r\n\r\n\t\tthis.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z;\r\n\t\tthis.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z;\r\n\t\tthis.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tapplyMatrix4: function ( m ) {\r\n\r\n\t\t// input: THREE.Matrix4 affine matrix\r\n\r\n\t\tvar x = this.x, y = this.y, z = this.z;\r\n\r\n\t\tvar e = m.elements;\r\n\r\n\t\tthis.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ];\r\n\t\tthis.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ];\r\n\t\tthis.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ];\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tapplyProjection: function ( m ) {\r\n\r\n\t\t// input: THREE.Matrix4 projection matrix\r\n\r\n\t\tvar x = this.x, y = this.y, z = this.z;\r\n\r\n\t\tvar e = m.elements;\r\n\t\tvar d = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] ); // perspective divide\r\n\r\n\t\tthis.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] ) * d;\r\n\t\tthis.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] ) * d;\r\n\t\tthis.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * d;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tapplyQuaternion: function ( q ) {\r\n\r\n\t\tvar x = this.x;\r\n\t\tvar y = this.y;\r\n\t\tvar z = this.z;\r\n\r\n\t\tvar qx = q.x;\r\n\t\tvar qy = q.y;\r\n\t\tvar qz = q.z;\r\n\t\tvar qw = q.w;\r\n\r\n\t\t// calculate quat * vector\r\n\r\n\t\tvar ix = qw * x + qy * z - qz * y;\r\n\t\tvar iy = qw * y + qz * x - qx * z;\r\n\t\tvar iz = qw * z + qx * y - qy * x;\r\n\t\tvar iw = - qx * x - qy * y - qz * z;\r\n\r\n\t\t// calculate result * inverse quat\r\n\r\n\t\tthis.x = ix * qw + iw * - qx + iy * - qz - iz * - qy;\r\n\t\tthis.y = iy * qw + iw * - qy + iz * - qx - ix * - qz;\r\n\t\tthis.z = iz * qw + iw * - qz + ix * - qy - iy * - qx;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tproject: function () {\r\n\r\n\t\tvar matrix;\r\n\r\n\t\treturn function ( camera ) {\r\n\r\n\t\t\tif ( matrix === undefined ) matrix = new THREE.Matrix4();\r\n\r\n\t\t\tmatrix.multiplyMatrices( camera.projectionMatrix, matrix.getInverse( camera.matrixWorld ) );\r\n\t\t\treturn this.applyProjection( matrix );\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\tunproject: function () {\r\n\r\n\t\tvar matrix;\r\n\r\n\t\treturn function ( camera ) {\r\n\r\n\t\t\tif ( matrix === undefined ) matrix = new THREE.Matrix4();\r\n\r\n\t\t\tmatrix.multiplyMatrices( camera.matrixWorld, matrix.getInverse( camera.projectionMatrix ) );\r\n\t\t\treturn this.applyProjection( matrix );\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\ttransformDirection: function ( m ) {\r\n\r\n\t\t// input: THREE.Matrix4 affine matrix\r\n\t\t// vector interpreted as a direction\r\n\r\n\t\tvar x = this.x, y = this.y, z = this.z;\r\n\r\n\t\tvar e = m.elements;\r\n\r\n\t\tthis.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z;\r\n\t\tthis.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z;\r\n\t\tthis.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z;\r\n\r\n\t\tthis.normalize();\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tdivide: function ( v ) {\r\n\r\n\t\tthis.x /= v.x;\r\n\t\tthis.y /= v.y;\r\n\t\tthis.z /= v.z;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tdivideScalar: function ( scalar ) {\r\n\r\n\t\tif ( scalar !== 0 ) {\r\n\r\n\t\t\tvar invScalar = 1 / scalar;\r\n\r\n\t\t\tthis.x *= invScalar;\r\n\t\t\tthis.y *= invScalar;\r\n\t\t\tthis.z *= invScalar;\r\n\r\n\t\t} else {\r\n\r\n\t\t\tthis.x = 0;\r\n\t\t\tthis.y = 0;\r\n\t\t\tthis.z = 0;\r\n\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tmin: function ( v ) {\r\n\r\n\t\tif ( this.x > v.x ) {\r\n\r\n\t\t\tthis.x = v.x;\r\n\r\n\t\t}\r\n\r\n\t\tif ( this.y > v.y ) {\r\n\r\n\t\t\tthis.y = v.y;\r\n\r\n\t\t}\r\n\r\n\t\tif ( this.z > v.z ) {\r\n\r\n\t\t\tthis.z = v.z;\r\n\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tmax: function ( v ) {\r\n\r\n\t\tif ( this.x < v.x ) {\r\n\r\n\t\t\tthis.x = v.x;\r\n\r\n\t\t}\r\n\r\n\t\tif ( this.y < v.y ) {\r\n\r\n\t\t\tthis.y = v.y;\r\n\r\n\t\t}\r\n\r\n\t\tif ( this.z < v.z ) {\r\n\r\n\t\t\tthis.z = v.z;\r\n\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tclamp: function ( min, max ) {\r\n\r\n\t\t// This function assumes min < max, if this assumption isn't true it will not operate correctly\r\n\r\n\t\tif ( this.x < min.x ) {\r\n\r\n\t\t\tthis.x = min.x;\r\n\r\n\t\t} else if ( this.x > max.x ) {\r\n\r\n\t\t\tthis.x = max.x;\r\n\r\n\t\t}\r\n\r\n\t\tif ( this.y < min.y ) {\r\n\r\n\t\t\tthis.y = min.y;\r\n\r\n\t\t} else if ( this.y > max.y ) {\r\n\r\n\t\t\tthis.y = max.y;\r\n\r\n\t\t}\r\n\r\n\t\tif ( this.z < min.z ) {\r\n\r\n\t\t\tthis.z = min.z;\r\n\r\n\t\t} else if ( this.z > max.z ) {\r\n\r\n\t\t\tthis.z = max.z;\r\n\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tclampScalar: ( function () {\r\n\r\n\t\tvar min, max;\r\n\r\n\t\treturn function ( minVal, maxVal ) {\r\n\r\n\t\t\tif ( min === undefined ) {\r\n\r\n\t\t\t\tmin = new THREE.Vector3();\r\n\t\t\t\tmax = new THREE.Vector3();\r\n\r\n\t\t\t}\r\n\r\n\t\t\tmin.set( minVal, minVal, minVal );\r\n\t\t\tmax.set( maxVal, maxVal, maxVal );\r\n\r\n\t\t\treturn this.clamp( min, max );\r\n\r\n\t\t};\r\n\r\n\t} )(),\r\n\r\n\tfloor: function () {\r\n\r\n\t\tthis.x = Math.floor( this.x );\r\n\t\tthis.y = Math.floor( this.y );\r\n\t\tthis.z = Math.floor( this.z );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tceil: function () {\r\n\r\n\t\tthis.x = Math.ceil( this.x );\r\n\t\tthis.y = Math.ceil( this.y );\r\n\t\tthis.z = Math.ceil( this.z );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tround: function () {\r\n\r\n\t\tthis.x = Math.round( this.x );\r\n\t\tthis.y = Math.round( this.y );\r\n\t\tthis.z = Math.round( this.z );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\troundToZero: function () {\r\n\r\n\t\tthis.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );\r\n\t\tthis.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );\r\n\t\tthis.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tnegate: function () {\r\n\r\n\t\tthis.x = - this.x;\r\n\t\tthis.y = - this.y;\r\n\t\tthis.z = - this.z;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tdot: function ( v ) {\r\n\r\n\t\treturn this.x * v.x + this.y * v.y + this.z * v.z;\r\n\r\n\t},\r\n\r\n\tlengthSq: function () {\r\n\r\n\t\treturn this.x * this.x + this.y * this.y + this.z * this.z;\r\n\r\n\t},\r\n\r\n\tlength: function () {\r\n\r\n\t\treturn Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );\r\n\r\n\t},\r\n\r\n\tlengthManhattan: function () {\r\n\r\n\t\treturn Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z );\r\n\r\n\t},\r\n\r\n\tnormalize: function () {\r\n\r\n\t\treturn this.divideScalar( this.length() );\r\n\r\n\t},\r\n\r\n\tsetLength: function ( l ) {\r\n\r\n\t\tvar oldLength = this.length();\r\n\r\n\t\tif ( oldLength !== 0 && l !== oldLength ) {\r\n\r\n\t\t\tthis.multiplyScalar( l / oldLength );\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tlerp: function ( v, alpha ) {\r\n\r\n\t\tthis.x += ( v.x - this.x ) * alpha;\r\n\t\tthis.y += ( v.y - this.y ) * alpha;\r\n\t\tthis.z += ( v.z - this.z ) * alpha;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tlerpVectors: function ( v1, v2, alpha ) {\r\n\r\n\t\tthis.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tcross: function ( v, w ) {\r\n\r\n\t\tif ( w !== undefined ) {\r\n\r\n\t\t\tTHREE.warn( 'THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' );\r\n\t\t\treturn this.crossVectors( v, w );\r\n\r\n\t\t}\r\n\r\n\t\tvar x = this.x, y = this.y, z = this.z;\r\n\r\n\t\tthis.x = y * v.z - z * v.y;\r\n\t\tthis.y = z * v.x - x * v.z;\r\n\t\tthis.z = x * v.y - y * v.x;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tcrossVectors: function ( a, b ) {\r\n\r\n\t\tvar ax = a.x, ay = a.y, az = a.z;\r\n\t\tvar bx = b.x, by = b.y, bz = b.z;\r\n\r\n\t\tthis.x = ay * bz - az * by;\r\n\t\tthis.y = az * bx - ax * bz;\r\n\t\tthis.z = ax * by - ay * bx;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tprojectOnVector: function () {\r\n\r\n\t\tvar v1, dot;\r\n\r\n\t\treturn function ( vector ) {\r\n\r\n\t\t\tif ( v1 === undefined ) v1 = new THREE.Vector3();\r\n\r\n\t\t\tv1.copy( vector ).normalize();\r\n\r\n\t\t\tdot = this.dot( v1 );\r\n\r\n\t\t\treturn this.copy( v1 ).multiplyScalar( dot );\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\tprojectOnPlane: function () {\r\n\r\n\t\tvar v1;\r\n\r\n\t\treturn function ( planeNormal ) {\r\n\r\n\t\t\tif ( v1 === undefined ) v1 = new THREE.Vector3();\r\n\r\n\t\t\tv1.copy( this ).projectOnVector( planeNormal );\r\n\r\n\t\t\treturn this.sub( v1 );\r\n\r\n\t\t}\r\n\r\n\t}(),\r\n\r\n\treflect: function () {\r\n\r\n\t\t// reflect incident vector off plane orthogonal to normal\r\n\t\t// normal is assumed to have unit length\r\n\r\n\t\tvar v1;\r\n\r\n\t\treturn function ( normal ) {\r\n\r\n\t\t\tif ( v1 === undefined ) v1 = new THREE.Vector3();\r\n\r\n\t\t\treturn this.sub( v1.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) );\r\n\r\n\t\t}\r\n\r\n\t}(),\r\n\r\n\tangleTo: function ( v ) {\r\n\r\n\t\tvar theta = this.dot( v ) / ( this.length() * v.length() );\r\n\r\n\t\t// clamp, to handle numerical problems\r\n\r\n\t\treturn Math.acos( THREE.Math.clamp( theta, - 1, 1 ) );\r\n\r\n\t},\r\n\r\n\tdistanceTo: function ( v ) {\r\n\r\n\t\treturn Math.sqrt( this.distanceToSquared( v ) );\r\n\r\n\t},\r\n\r\n\tdistanceToSquared: function ( v ) {\r\n\r\n\t\tvar dx = this.x - v.x;\r\n\t\tvar dy = this.y - v.y;\r\n\t\tvar dz = this.z - v.z;\r\n\r\n\t\treturn dx * dx + dy * dy + dz * dz;\r\n\r\n\t},\r\n\r\n\tsetEulerFromRotationMatrix: function ( m, order ) {\r\n\r\n\t\tTHREE.error( 'THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.' );\r\n\r\n\t},\r\n\r\n\tsetEulerFromQuaternion: function ( q, order ) {\r\n\r\n\t\tTHREE.error( 'THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.' );\r\n\r\n\t},\r\n\r\n\tgetPositionFromMatrix: function ( m ) {\r\n\r\n\t\tTHREE.warn( 'THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().' );\r\n\r\n\t\treturn this.setFromMatrixPosition( m );\r\n\r\n\t},\r\n\r\n\tgetScaleFromMatrix: function ( m ) {\r\n\r\n\t\tTHREE.warn( 'THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().' );\r\n\r\n\t\treturn this.setFromMatrixScale( m );\r\n\t},\r\n\r\n\tgetColumnFromMatrix: function ( index, matrix ) {\r\n\r\n\t\tTHREE.warn( 'THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().' );\r\n\r\n\t\treturn this.setFromMatrixColumn( index, matrix );\r\n\r\n\t},\r\n\r\n\tsetFromMatrixPosition: function ( m ) {\r\n\r\n\t\tthis.x = m.elements[ 12 ];\r\n\t\tthis.y = m.elements[ 13 ];\r\n\t\tthis.z = m.elements[ 14 ];\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetFromMatrixScale: function ( m ) {\r\n\r\n\t\tvar sx = this.set( m.elements[ 0 ], m.elements[ 1 ], m.elements[ 2 ] ).length();\r\n\t\tvar sy = this.set( m.elements[ 4 ], m.elements[ 5 ], m.elements[ 6 ] ).length();\r\n\t\tvar sz = this.set( m.elements[ 8 ], m.elements[ 9 ], m.elements[ 10 ] ).length();\r\n\r\n\t\tthis.x = sx;\r\n\t\tthis.y = sy;\r\n\t\tthis.z = sz;\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\tsetFromMatrixColumn: function ( index, matrix ) {\r\n\t\t\r\n\t\tvar offset = index * 4;\r\n\r\n\t\tvar me = matrix.elements;\r\n\r\n\t\tthis.x = me[ offset ];\r\n\t\tthis.y = me[ offset + 1 ];\r\n\t\tthis.z = me[ offset + 2 ];\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tequals: function ( v ) {\r\n\r\n\t\treturn ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) );\r\n\r\n\t},\r\n\r\n\tfromArray: function ( array, offset ) {\r\n\r\n\t\tif ( offset === undefined ) offset = 0;\r\n\r\n\t\tthis.x = array[ offset ];\r\n\t\tthis.y = array[ offset + 1 ];\r\n\t\tthis.z = array[ offset + 2 ];\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\ttoArray: function ( array, offset ) {\r\n\r\n\t\tif ( array === undefined ) array = [];\r\n\t\tif ( offset === undefined ) offset = 0;\r\n\r\n\t\tarray[ offset ] = this.x;\r\n\t\tarray[ offset + 1 ] = this.y;\r\n\t\tarray[ offset + 2 ] = this.z;\r\n\r\n\t\treturn array;\r\n\r\n\t},\r\n\r\n\tfromAttribute: function ( attribute, index, offset ) {\r\n\r\n\t\tif ( offset === undefined ) offset = 0;\r\n\r\n\t\tindex = index * attribute.itemSize + offset;\r\n\r\n\t\tthis.x = attribute.array[ index ];\r\n\t\tthis.y = attribute.array[ index + 1 ];\r\n\t\tthis.z = attribute.array[ index + 2 ];\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tclone: function () {\r\n\r\n\t\treturn new THREE.Vector3( this.x, this.y, this.z );\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/math/Vector4.js\r\n\r\n/**\r\n * @author supereggbert / http://www.paulbrunt.co.uk/\r\n * @author philogb / http://blog.thejit.org/\r\n * @author mikael emtinger / http://gomo.se/\r\n * @author egraether / http://egraether.com/\r\n * @author WestLangley / http://github.com/WestLangley\r\n */\r\n\r\nTHREE.Vector4 = function ( x, y, z, w ) {\r\n\r\n\tthis.x = x || 0;\r\n\tthis.y = y || 0;\r\n\tthis.z = z || 0;\r\n\tthis.w = ( w !== undefined ) ? w : 1;\r\n\r\n};\r\n\r\nTHREE.Vector4.prototype = {\r\n\r\n\tconstructor: THREE.Vector4,\r\n\r\n\tset: function ( x, y, z, w ) {\r\n\r\n\t\tthis.x = x;\r\n\t\tthis.y = y;\r\n\t\tthis.z = z;\r\n\t\tthis.w = w;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetX: function ( x ) {\r\n\r\n\t\tthis.x = x;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetY: function ( y ) {\r\n\r\n\t\tthis.y = y;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetZ: function ( z ) {\r\n\r\n\t\tthis.z = z;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetW: function ( w ) {\r\n\r\n\t\tthis.w = w;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetComponent: function ( index, value ) {\r\n\r\n\t\tswitch ( index ) {\r\n\r\n\t\t\tcase 0: this.x = value; break;\r\n\t\t\tcase 1: this.y = value; break;\r\n\t\t\tcase 2: this.z = value; break;\r\n\t\t\tcase 3: this.w = value; break;\r\n\t\t\tdefault: throw new Error( 'index is out of range: ' + index );\r\n\r\n\t\t}\r\n\r\n\t},\r\n\r\n\tgetComponent: function ( index ) {\r\n\r\n\t\tswitch ( index ) {\r\n\r\n\t\t\tcase 0: return this.x;\r\n\t\t\tcase 1: return this.y;\r\n\t\t\tcase 2: return this.z;\r\n\t\t\tcase 3: return this.w;\r\n\t\t\tdefault: throw new Error( 'index is out of range: ' + index );\r\n\r\n\t\t}\r\n\r\n\t},\r\n\r\n\tcopy: function ( v ) {\r\n\r\n\t\tthis.x = v.x;\r\n\t\tthis.y = v.y;\r\n\t\tthis.z = v.z;\r\n\t\tthis.w = ( v.w !== undefined ) ? v.w : 1;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tadd: function ( v, w ) {\r\n\r\n\t\tif ( w !== undefined ) {\r\n\r\n\t\t\tTHREE.warn( 'THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );\r\n\t\t\treturn this.addVectors( v, w );\r\n\r\n\t\t}\r\n\r\n\t\tthis.x += v.x;\r\n\t\tthis.y += v.y;\r\n\t\tthis.z += v.z;\r\n\t\tthis.w += v.w;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\taddScalar: function ( s ) {\r\n\r\n\t\tthis.x += s;\r\n\t\tthis.y += s;\r\n\t\tthis.z += s;\r\n\t\tthis.w += s;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\taddVectors: function ( a, b ) {\r\n\r\n\t\tthis.x = a.x + b.x;\r\n\t\tthis.y = a.y + b.y;\r\n\t\tthis.z = a.z + b.z;\r\n\t\tthis.w = a.w + b.w;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsub: function ( v, w ) {\r\n\r\n\t\tif ( w !== undefined ) {\r\n\r\n\t\t\tTHREE.warn( 'THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );\r\n\t\t\treturn this.subVectors( v, w );\r\n\r\n\t\t}\r\n\r\n\t\tthis.x -= v.x;\r\n\t\tthis.y -= v.y;\r\n\t\tthis.z -= v.z;\r\n\t\tthis.w -= v.w;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsubScalar: function ( s ) {\r\n\r\n\t\tthis.x -= s;\r\n\t\tthis.y -= s;\r\n\t\tthis.z -= s;\r\n\t\tthis.w -= s;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsubVectors: function ( a, b ) {\r\n\r\n\t\tthis.x = a.x - b.x;\r\n\t\tthis.y = a.y - b.y;\r\n\t\tthis.z = a.z - b.z;\r\n\t\tthis.w = a.w - b.w;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tmultiplyScalar: function ( scalar ) {\r\n\r\n\t\tthis.x *= scalar;\r\n\t\tthis.y *= scalar;\r\n\t\tthis.z *= scalar;\r\n\t\tthis.w *= scalar;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tapplyMatrix4: function ( m ) {\r\n\r\n\t\tvar x = this.x;\r\n\t\tvar y = this.y;\r\n\t\tvar z = this.z;\r\n\t\tvar w = this.w;\r\n\r\n\t\tvar e = m.elements;\r\n\r\n\t\tthis.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w;\r\n\t\tthis.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w;\r\n\t\tthis.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w;\r\n\t\tthis.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tdivideScalar: function ( scalar ) {\r\n\r\n\t\tif ( scalar !== 0 ) {\r\n\r\n\t\t\tvar invScalar = 1 / scalar;\r\n\r\n\t\t\tthis.x *= invScalar;\r\n\t\t\tthis.y *= invScalar;\r\n\t\t\tthis.z *= invScalar;\r\n\t\t\tthis.w *= invScalar;\r\n\r\n\t\t} else {\r\n\r\n\t\t\tthis.x = 0;\r\n\t\t\tthis.y = 0;\r\n\t\t\tthis.z = 0;\r\n\t\t\tthis.w = 1;\r\n\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetAxisAngleFromQuaternion: function ( q ) {\r\n\r\n\t\t// http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm\r\n\r\n\t\t// q is assumed to be normalized\r\n\r\n\t\tthis.w = 2 * Math.acos( q.w );\r\n\r\n\t\tvar s = Math.sqrt( 1 - q.w * q.w );\r\n\r\n\t\tif ( s < 0.0001 ) {\r\n\r\n\t\t\t this.x = 1;\r\n\t\t\t this.y = 0;\r\n\t\t\t this.z = 0;\r\n\r\n\t\t} else {\r\n\r\n\t\t\t this.x = q.x / s;\r\n\t\t\t this.y = q.y / s;\r\n\t\t\t this.z = q.z / s;\r\n\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetAxisAngleFromRotationMatrix: function ( m ) {\r\n\r\n\t\t// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm\r\n\r\n\t\t// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)\r\n\r\n\t\tvar angle, x, y, z,\t\t// variables for result\r\n\t\t\tepsilon = 0.01,\t\t// margin to allow for rounding errors\r\n\t\t\tepsilon2 = 0.1,\t\t// margin to distinguish between 0 and 180 degrees\r\n\r\n\t\t\tte = m.elements,\r\n\r\n\t\t\tm11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],\r\n\t\t\tm21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],\r\n\t\t\tm31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];\r\n\r\n\t\tif ( ( Math.abs( m12 - m21 ) < epsilon )\r\n\t\t && ( Math.abs( m13 - m31 ) < epsilon )\r\n\t\t && ( Math.abs( m23 - m32 ) < epsilon ) ) {\r\n\r\n\t\t\t// singularity found\r\n\t\t\t// first check for identity matrix which must have +1 for all terms\r\n\t\t\t// in leading diagonal and zero in other terms\r\n\r\n\t\t\tif ( ( Math.abs( m12 + m21 ) < epsilon2 )\r\n\t\t\t && ( Math.abs( m13 + m31 ) < epsilon2 )\r\n\t\t\t && ( Math.abs( m23 + m32 ) < epsilon2 )\r\n\t\t\t && ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) {\r\n\r\n\t\t\t\t// this singularity is identity matrix so angle = 0\r\n\r\n\t\t\t\tthis.set( 1, 0, 0, 0 );\r\n\r\n\t\t\t\treturn this; // zero angle, arbitrary axis\r\n\r\n\t\t\t}\r\n\r\n\t\t\t// otherwise this singularity is angle = 180\r\n\r\n\t\t\tangle = Math.PI;\r\n\r\n\t\t\tvar xx = ( m11 + 1 ) / 2;\r\n\t\t\tvar yy = ( m22 + 1 ) / 2;\r\n\t\t\tvar zz = ( m33 + 1 ) / 2;\r\n\t\t\tvar xy = ( m12 + m21 ) / 4;\r\n\t\t\tvar xz = ( m13 + m31 ) / 4;\r\n\t\t\tvar yz = ( m23 + m32 ) / 4;\r\n\r\n\t\t\tif ( ( xx > yy ) && ( xx > zz ) ) { // m11 is the largest diagonal term\r\n\r\n\t\t\t\tif ( xx < epsilon ) {\r\n\r\n\t\t\t\t\tx = 0;\r\n\t\t\t\t\ty = 0.707106781;\r\n\t\t\t\t\tz = 0.707106781;\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\tx = Math.sqrt( xx );\r\n\t\t\t\t\ty = xy / x;\r\n\t\t\t\t\tz = xz / x;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t} else if ( yy > zz ) { // m22 is the largest diagonal term\r\n\r\n\t\t\t\tif ( yy < epsilon ) {\r\n\r\n\t\t\t\t\tx = 0.707106781;\r\n\t\t\t\t\ty = 0;\r\n\t\t\t\t\tz = 0.707106781;\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\ty = Math.sqrt( yy );\r\n\t\t\t\t\tx = xy / y;\r\n\t\t\t\t\tz = yz / y;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t} else { // m33 is the largest diagonal term so base result on this\r\n\r\n\t\t\t\tif ( zz < epsilon ) {\r\n\r\n\t\t\t\t\tx = 0.707106781;\r\n\t\t\t\t\ty = 0.707106781;\r\n\t\t\t\t\tz = 0;\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\tz = Math.sqrt( zz );\r\n\t\t\t\t\tx = xz / z;\r\n\t\t\t\t\ty = yz / z;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\tthis.set( x, y, z, angle );\r\n\r\n\t\t\treturn this; // return 180 deg rotation\r\n\r\n\t\t}\r\n\r\n\t\t// as we have reached here there are no singularities so we can handle normally\r\n\r\n\t\tvar s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 )\r\n\t\t\t\t\t\t + ( m13 - m31 ) * ( m13 - m31 )\r\n\t\t\t\t\t\t + ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize\r\n\r\n\t\tif ( Math.abs( s ) < 0.001 ) s = 1;\r\n\r\n\t\t// prevent divide by zero, should not happen if matrix is orthogonal and should be\r\n\t\t// caught by singularity test above, but I've left it in just in case\r\n\r\n\t\tthis.x = ( m32 - m23 ) / s;\r\n\t\tthis.y = ( m13 - m31 ) / s;\r\n\t\tthis.z = ( m21 - m12 ) / s;\r\n\t\tthis.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tmin: function ( v ) {\r\n\r\n\t\tif ( this.x > v.x ) {\r\n\r\n\t\t\tthis.x = v.x;\r\n\r\n\t\t}\r\n\r\n\t\tif ( this.y > v.y ) {\r\n\r\n\t\t\tthis.y = v.y;\r\n\r\n\t\t}\r\n\r\n\t\tif ( this.z > v.z ) {\r\n\r\n\t\t\tthis.z = v.z;\r\n\r\n\t\t}\r\n\r\n\t\tif ( this.w > v.w ) {\r\n\r\n\t\t\tthis.w = v.w;\r\n\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tmax: function ( v ) {\r\n\r\n\t\tif ( this.x < v.x ) {\r\n\r\n\t\t\tthis.x = v.x;\r\n\r\n\t\t}\r\n\r\n\t\tif ( this.y < v.y ) {\r\n\r\n\t\t\tthis.y = v.y;\r\n\r\n\t\t}\r\n\r\n\t\tif ( this.z < v.z ) {\r\n\r\n\t\t\tthis.z = v.z;\r\n\r\n\t\t}\r\n\r\n\t\tif ( this.w < v.w ) {\r\n\r\n\t\t\tthis.w = v.w;\r\n\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tclamp: function ( min, max ) {\r\n\r\n\t\t// This function assumes min < max, if this assumption isn't true it will not operate correctly\r\n\r\n\t\tif ( this.x < min.x ) {\r\n\r\n\t\t\tthis.x = min.x;\r\n\r\n\t\t} else if ( this.x > max.x ) {\r\n\r\n\t\t\tthis.x = max.x;\r\n\r\n\t\t}\r\n\r\n\t\tif ( this.y < min.y ) {\r\n\r\n\t\t\tthis.y = min.y;\r\n\r\n\t\t} else if ( this.y > max.y ) {\r\n\r\n\t\t\tthis.y = max.y;\r\n\r\n\t\t}\r\n\r\n\t\tif ( this.z < min.z ) {\r\n\r\n\t\t\tthis.z = min.z;\r\n\r\n\t\t} else if ( this.z > max.z ) {\r\n\r\n\t\t\tthis.z = max.z;\r\n\r\n\t\t}\r\n\r\n\t\tif ( this.w < min.w ) {\r\n\r\n\t\t\tthis.w = min.w;\r\n\r\n\t\t} else if ( this.w > max.w ) {\r\n\r\n\t\t\tthis.w = max.w;\r\n\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tclampScalar: ( function () {\r\n\r\n\t\tvar min, max;\r\n\r\n\t\treturn function ( minVal, maxVal ) {\r\n\r\n\t\t\tif ( min === undefined ) {\r\n\r\n\t\t\t\tmin = new THREE.Vector4();\r\n\t\t\t\tmax = new THREE.Vector4();\r\n\r\n\t\t\t}\r\n\r\n\t\t\tmin.set( minVal, minVal, minVal, minVal );\r\n\t\t\tmax.set( maxVal, maxVal, maxVal, maxVal );\r\n\r\n\t\t\treturn this.clamp( min, max );\r\n\r\n\t\t};\r\n\r\n\t} )(),\r\n\r\n floor: function () {\r\n\r\n\t\tthis.x = Math.floor( this.x );\r\n\t\tthis.y = Math.floor( this.y );\r\n\t\tthis.z = Math.floor( this.z );\r\n\t\tthis.w = Math.floor( this.w );\r\n\r\n\t\treturn this;\r\n\r\n },\r\n\r\n ceil: function () {\r\n\r\n\t\tthis.x = Math.ceil( this.x );\r\n\t\tthis.y = Math.ceil( this.y );\r\n\t\tthis.z = Math.ceil( this.z );\r\n\t\tthis.w = Math.ceil( this.w );\r\n\r\n\t\treturn this;\r\n\r\n },\r\n\r\n round: function () {\r\n\r\n\t\tthis.x = Math.round( this.x );\r\n\t\tthis.y = Math.round( this.y );\r\n\t\tthis.z = Math.round( this.z );\r\n\t\tthis.w = Math.round( this.w );\r\n\r\n\t\treturn this;\r\n\r\n },\r\n\r\n roundToZero: function () {\r\n\r\n\t\tthis.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );\r\n\t\tthis.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );\r\n\t\tthis.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );\r\n\t\tthis.w = ( this.w < 0 ) ? Math.ceil( this.w ) : Math.floor( this.w );\r\n\r\n\t\treturn this;\r\n\r\n },\r\n\r\n\tnegate: function () {\r\n\r\n\t\tthis.x = - this.x;\r\n\t\tthis.y = - this.y;\r\n\t\tthis.z = - this.z;\r\n\t\tthis.w = - this.w;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tdot: function ( v ) {\r\n\r\n\t\treturn this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w;\r\n\r\n\t},\r\n\r\n\tlengthSq: function () {\r\n\r\n\t\treturn this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w;\r\n\r\n\t},\r\n\r\n\tlength: function () {\r\n\r\n\t\treturn Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w );\r\n\r\n\t},\r\n\r\n\tlengthManhattan: function () {\r\n\r\n\t\treturn Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w );\r\n\r\n\t},\r\n\r\n\tnormalize: function () {\r\n\r\n\t\treturn this.divideScalar( this.length() );\r\n\r\n\t},\r\n\r\n\tsetLength: function ( l ) {\r\n\r\n\t\tvar oldLength = this.length();\r\n\r\n\t\tif ( oldLength !== 0 && l !== oldLength ) {\r\n\r\n\t\t\tthis.multiplyScalar( l / oldLength );\r\n\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tlerp: function ( v, alpha ) {\r\n\r\n\t\tthis.x += ( v.x - this.x ) * alpha;\r\n\t\tthis.y += ( v.y - this.y ) * alpha;\r\n\t\tthis.z += ( v.z - this.z ) * alpha;\r\n\t\tthis.w += ( v.w - this.w ) * alpha;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tlerpVectors: function ( v1, v2, alpha ) {\r\n\r\n\t\tthis.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tequals: function ( v ) {\r\n\r\n\t\treturn ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) );\r\n\r\n\t},\r\n\r\n\tfromArray: function ( array, offset ) {\r\n\r\n\t\tif ( offset === undefined ) offset = 0;\r\n\r\n\t\tthis.x = array[ offset ];\r\n\t\tthis.y = array[ offset + 1 ];\r\n\t\tthis.z = array[ offset + 2 ];\r\n\t\tthis.w = array[ offset + 3 ];\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\ttoArray: function ( array, offset ) {\r\n\r\n\t\tif ( array === undefined ) array = [];\r\n\t\tif ( offset === undefined ) offset = 0;\r\n\r\n\t\tarray[ offset ] = this.x;\r\n\t\tarray[ offset + 1 ] = this.y;\r\n\t\tarray[ offset + 2 ] = this.z;\r\n\t\tarray[ offset + 3 ] = this.w;\r\n\r\n\t\treturn array;\r\n\r\n\t},\r\n\r\n\tfromAttribute: function ( attribute, index, offset ) {\r\n\r\n\t\tif ( offset === undefined ) offset = 0;\r\n\r\n\t\tindex = index * attribute.itemSize + offset;\r\n\r\n\t\tthis.x = attribute.array[ index ];\r\n\t\tthis.y = attribute.array[ index + 1 ];\r\n\t\tthis.z = attribute.array[ index + 2 ];\r\n\t\tthis.w = attribute.array[ index + 3 ];\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tclone: function () {\r\n\r\n\t\treturn new THREE.Vector4( this.x, this.y, this.z, this.w );\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/math/Euler.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n * @author WestLangley / http://github.com/WestLangley\r\n * @author bhouston / http://exocortex.com\r\n */\r\n\r\nTHREE.Euler = function ( x, y, z, order ) {\r\n\r\n\tthis._x = x || 0;\r\n\tthis._y = y || 0;\r\n\tthis._z = z || 0;\r\n\tthis._order = order || THREE.Euler.DefaultOrder;\r\n\r\n};\r\n\r\nTHREE.Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ];\r\n\r\nTHREE.Euler.DefaultOrder = 'XYZ';\r\n\r\nTHREE.Euler.prototype = {\r\n\r\n\tconstructor: THREE.Euler,\r\n\r\n\t_x: 0, _y: 0, _z: 0, _order: THREE.Euler.DefaultOrder,\r\n\r\n\tget x () {\r\n\r\n\t\treturn this._x;\r\n\r\n\t},\r\n\r\n\tset x ( value ) {\r\n\r\n\t\tthis._x = value;\r\n\t\tthis.onChangeCallback();\r\n\r\n\t},\r\n\r\n\tget y () {\r\n\r\n\t\treturn this._y;\r\n\r\n\t},\r\n\r\n\tset y ( value ) {\r\n\r\n\t\tthis._y = value;\r\n\t\tthis.onChangeCallback();\r\n\r\n\t},\r\n\r\n\tget z () {\r\n\r\n\t\treturn this._z;\r\n\r\n\t},\r\n\r\n\tset z ( value ) {\r\n\r\n\t\tthis._z = value;\r\n\t\tthis.onChangeCallback();\r\n\r\n\t},\r\n\r\n\tget order () {\r\n\r\n\t\treturn this._order;\r\n\r\n\t},\r\n\r\n\tset order ( value ) {\r\n\r\n\t\tthis._order = value;\r\n\t\tthis.onChangeCallback();\r\n\r\n\t},\r\n\r\n\tset: function ( x, y, z, order ) {\r\n\r\n\t\tthis._x = x;\r\n\t\tthis._y = y;\r\n\t\tthis._z = z;\r\n\t\tthis._order = order || this._order;\r\n\r\n\t\tthis.onChangeCallback();\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tcopy: function ( euler ) {\r\n\r\n\t\tthis._x = euler._x;\r\n\t\tthis._y = euler._y;\r\n\t\tthis._z = euler._z;\r\n\t\tthis._order = euler._order;\r\n\r\n\t\tthis.onChangeCallback();\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetFromRotationMatrix: function ( m, order, update ) {\r\n\r\n\t\tvar clamp = THREE.Math.clamp;\r\n\r\n\t\t// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)\r\n\r\n\t\tvar te = m.elements;\r\n\t\tvar m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ];\r\n\t\tvar m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ];\r\n\t\tvar m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];\r\n\r\n\t\torder = order || this._order;\r\n\r\n\t\tif ( order === 'XYZ' ) {\r\n\r\n\t\t\tthis._y = Math.asin( clamp( m13, - 1, 1 ) );\r\n\r\n\t\t\tif ( Math.abs( m13 ) < 0.99999 ) {\r\n\r\n\t\t\t\tthis._x = Math.atan2( - m23, m33 );\r\n\t\t\t\tthis._z = Math.atan2( - m12, m11 );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tthis._x = Math.atan2( m32, m22 );\r\n\t\t\t\tthis._z = 0;\r\n\r\n\t\t\t}\r\n\r\n\t\t} else if ( order === 'YXZ' ) {\r\n\r\n\t\t\tthis._x = Math.asin( - clamp( m23, - 1, 1 ) );\r\n\r\n\t\t\tif ( Math.abs( m23 ) < 0.99999 ) {\r\n\r\n\t\t\t\tthis._y = Math.atan2( m13, m33 );\r\n\t\t\t\tthis._z = Math.atan2( m21, m22 );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tthis._y = Math.atan2( - m31, m11 );\r\n\t\t\t\tthis._z = 0;\r\n\r\n\t\t\t}\r\n\r\n\t\t} else if ( order === 'ZXY' ) {\r\n\r\n\t\t\tthis._x = Math.asin( clamp( m32, - 1, 1 ) );\r\n\r\n\t\t\tif ( Math.abs( m32 ) < 0.99999 ) {\r\n\r\n\t\t\t\tthis._y = Math.atan2( - m31, m33 );\r\n\t\t\t\tthis._z = Math.atan2( - m12, m22 );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tthis._y = 0;\r\n\t\t\t\tthis._z = Math.atan2( m21, m11 );\r\n\r\n\t\t\t}\r\n\r\n\t\t} else if ( order === 'ZYX' ) {\r\n\r\n\t\t\tthis._y = Math.asin( - clamp( m31, - 1, 1 ) );\r\n\r\n\t\t\tif ( Math.abs( m31 ) < 0.99999 ) {\r\n\r\n\t\t\t\tthis._x = Math.atan2( m32, m33 );\r\n\t\t\t\tthis._z = Math.atan2( m21, m11 );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tthis._x = 0;\r\n\t\t\t\tthis._z = Math.atan2( - m12, m22 );\r\n\r\n\t\t\t}\r\n\r\n\t\t} else if ( order === 'YZX' ) {\r\n\r\n\t\t\tthis._z = Math.asin( clamp( m21, - 1, 1 ) );\r\n\r\n\t\t\tif ( Math.abs( m21 ) < 0.99999 ) {\r\n\r\n\t\t\t\tthis._x = Math.atan2( - m23, m22 );\r\n\t\t\t\tthis._y = Math.atan2( - m31, m11 );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tthis._x = 0;\r\n\t\t\t\tthis._y = Math.atan2( m13, m33 );\r\n\r\n\t\t\t}\r\n\r\n\t\t} else if ( order === 'XZY' ) {\r\n\r\n\t\t\tthis._z = Math.asin( - clamp( m12, - 1, 1 ) );\r\n\r\n\t\t\tif ( Math.abs( m12 ) < 0.99999 ) {\r\n\r\n\t\t\t\tthis._x = Math.atan2( m32, m22 );\r\n\t\t\t\tthis._y = Math.atan2( m13, m11 );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tthis._x = Math.atan2( - m23, m33 );\r\n\t\t\t\tthis._y = 0;\r\n\r\n\t\t\t}\r\n\r\n\t\t} else {\r\n\r\n\t\t\tTHREE.warn( 'THREE.Euler: .setFromRotationMatrix() given unsupported order: ' + order )\r\n\r\n\t\t}\r\n\r\n\t\tthis._order = order;\r\n\r\n\t\tif ( update !== false ) this.onChangeCallback();\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetFromQuaternion: function () {\r\n\r\n\t\tvar matrix;\r\n\r\n\t\treturn function ( q, order, update ) {\r\n\r\n\t\t\tif ( matrix === undefined ) matrix = new THREE.Matrix4();\r\n\t\t\tmatrix.makeRotationFromQuaternion( q );\r\n\t\t\tthis.setFromRotationMatrix( matrix, order, update );\r\n\r\n\t\t\treturn this;\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\tsetFromVector3: function ( v, order ) {\r\n\r\n\t\treturn this.set( v.x, v.y, v.z, order || this._order );\r\n\r\n\t},\r\n\r\n\treorder: function () {\r\n\r\n\t\t// WARNING: this discards revolution information -bhouston\r\n\r\n\t\tvar q = new THREE.Quaternion();\r\n\r\n\t\treturn function ( newOrder ) {\r\n\r\n\t\t\tq.setFromEuler( this );\r\n\t\t\tthis.setFromQuaternion( q, newOrder );\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\tequals: function ( euler ) {\r\n\r\n\t\treturn ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order );\r\n\r\n\t},\r\n\r\n\tfromArray: function ( array ) {\r\n\r\n\t\tthis._x = array[ 0 ];\r\n\t\tthis._y = array[ 1 ];\r\n\t\tthis._z = array[ 2 ];\r\n\t\tif ( array[ 3 ] !== undefined ) this._order = array[ 3 ];\r\n\r\n\t\tthis.onChangeCallback();\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\ttoArray: function ( array, offset ) {\r\n\r\n\t\tif ( array === undefined ) array = [];\r\n\t\tif ( offset === undefined ) offset = 0;\r\n\r\n\t\tarray[ offset ] = this._x;\r\n\t\tarray[ offset + 1 ] = this._y;\r\n\t\tarray[ offset + 2 ] = this._z;\r\n\t\tarray[ offset + 3 ] = this._order;\r\n\r\n\t\treturn array;\r\n\t},\r\n\r\n\ttoVector3: function ( optionalResult ) {\r\n\r\n\t\tif ( optionalResult ) {\r\n\r\n\t\t\treturn optionalResult.set( this._x, this._y, this._z );\r\n\r\n\t\t} else {\r\n\r\n\t\t\treturn new THREE.Vector3( this._x, this._y, this._z );\r\n\r\n\t\t}\r\n\r\n\t},\r\n\r\n\tonChange: function ( callback ) {\r\n\r\n\t\tthis.onChangeCallback = callback;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tonChangeCallback: function () {},\r\n\r\n\tclone: function () {\r\n\r\n\t\treturn new THREE.Euler( this._x, this._y, this._z, this._order );\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/math/Line3.js\r\n\r\n/**\r\n * @author bhouston / http://exocortex.com\r\n */\r\n\r\nTHREE.Line3 = function ( start, end ) {\r\n\r\n\tthis.start = ( start !== undefined ) ? start : new THREE.Vector3();\r\n\tthis.end = ( end !== undefined ) ? end : new THREE.Vector3();\r\n\r\n};\r\n\r\nTHREE.Line3.prototype = {\r\n\r\n\tconstructor: THREE.Line3,\r\n\r\n\tset: function ( start, end ) {\r\n\r\n\t\tthis.start.copy( start );\r\n\t\tthis.end.copy( end );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tcopy: function ( line ) {\r\n\r\n\t\tthis.start.copy( line.start );\r\n\t\tthis.end.copy( line.end );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tcenter: function ( optionalTarget ) {\r\n\r\n\t\tvar result = optionalTarget || new THREE.Vector3();\r\n\t\treturn result.addVectors( this.start, this.end ).multiplyScalar( 0.5 );\r\n\r\n\t},\r\n\r\n\tdelta: function ( optionalTarget ) {\r\n\r\n\t\tvar result = optionalTarget || new THREE.Vector3();\r\n\t\treturn result.subVectors( this.end, this.start );\r\n\r\n\t},\r\n\r\n\tdistanceSq: function () {\r\n\r\n\t\treturn this.start.distanceToSquared( this.end );\r\n\r\n\t},\r\n\r\n\tdistance: function () {\r\n\r\n\t\treturn this.start.distanceTo( this.end );\r\n\r\n\t},\r\n\r\n\tat: function ( t, optionalTarget ) {\r\n\r\n\t\tvar result = optionalTarget || new THREE.Vector3();\r\n\r\n\t\treturn this.delta( result ).multiplyScalar( t ).add( this.start );\r\n\r\n\t},\r\n\r\n\tclosestPointToPointParameter: function () {\r\n\r\n\t\tvar startP = new THREE.Vector3();\r\n\t\tvar startEnd = new THREE.Vector3();\r\n\r\n\t\treturn function ( point, clampToLine ) {\r\n\r\n\t\t\tstartP.subVectors( point, this.start );\r\n\t\t\tstartEnd.subVectors( this.end, this.start );\r\n\r\n\t\t\tvar startEnd2 = startEnd.dot( startEnd );\r\n\t\t\tvar startEnd_startP = startEnd.dot( startP );\r\n\r\n\t\t\tvar t = startEnd_startP / startEnd2;\r\n\r\n\t\t\tif ( clampToLine ) {\r\n\r\n\t\t\t\tt = THREE.Math.clamp( t, 0, 1 );\r\n\r\n\t\t\t}\r\n\r\n\t\t\treturn t;\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\tclosestPointToPoint: function ( point, clampToLine, optionalTarget ) {\r\n\r\n\t\tvar t = this.closestPointToPointParameter( point, clampToLine );\r\n\r\n\t\tvar result = optionalTarget || new THREE.Vector3();\r\n\r\n\t\treturn this.delta( result ).multiplyScalar( t ).add( this.start );\r\n\r\n\t},\r\n\r\n\tapplyMatrix4: function ( matrix ) {\r\n\r\n\t\tthis.start.applyMatrix4( matrix );\r\n\t\tthis.end.applyMatrix4( matrix );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tequals: function ( line ) {\r\n\r\n\t\treturn line.start.equals( this.start ) && line.end.equals( this.end );\r\n\r\n\t},\r\n\r\n\tclone: function () {\r\n\r\n\t\treturn new THREE.Line3().copy( this );\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/math/Box2.js\r\n\r\n/**\r\n * @author bhouston / http://exocortex.com\r\n */\r\n\r\nTHREE.Box2 = function ( min, max ) {\r\n\r\n\tthis.min = ( min !== undefined ) ? min : new THREE.Vector2( Infinity, Infinity );\r\n\tthis.max = ( max !== undefined ) ? max : new THREE.Vector2( - Infinity, - Infinity );\r\n\r\n};\r\n\r\nTHREE.Box2.prototype = {\r\n\r\n\tconstructor: THREE.Box2,\r\n\r\n\tset: function ( min, max ) {\r\n\r\n\t\tthis.min.copy( min );\r\n\t\tthis.max.copy( max );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetFromPoints: function ( points ) {\r\n\r\n\t\tthis.makeEmpty();\r\n\r\n\t\tfor ( var i = 0, il = points.length; i < il; i ++ ) {\r\n\r\n\t\t\tthis.expandByPoint( points[ i ] )\r\n\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetFromCenterAndSize: function () {\r\n\r\n\t\tvar v1 = new THREE.Vector2();\r\n\r\n\t\treturn function ( center, size ) {\r\n\r\n\t\t\tvar halfSize = v1.copy( size ).multiplyScalar( 0.5 );\r\n\t\t\tthis.min.copy( center ).sub( halfSize );\r\n\t\t\tthis.max.copy( center ).add( halfSize );\r\n\r\n\t\t\treturn this;\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\tcopy: function ( box ) {\r\n\r\n\t\tthis.min.copy( box.min );\r\n\t\tthis.max.copy( box.max );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tmakeEmpty: function () {\r\n\r\n\t\tthis.min.x = this.min.y = Infinity;\r\n\t\tthis.max.x = this.max.y = - Infinity;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tempty: function () {\r\n\r\n\t\t// this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes\r\n\r\n\t\treturn ( this.max.x < this.min.x ) || ( this.max.y < this.min.y );\r\n\r\n\t},\r\n\r\n\tcenter: function ( optionalTarget ) {\r\n\r\n\t\tvar result = optionalTarget || new THREE.Vector2();\r\n\t\treturn result.addVectors( this.min, this.max ).multiplyScalar( 0.5 );\r\n\r\n\t},\r\n\r\n\tsize: function ( optionalTarget ) {\r\n\r\n\t\tvar result = optionalTarget || new THREE.Vector2();\r\n\t\treturn result.subVectors( this.max, this.min );\r\n\r\n\t},\r\n\r\n\texpandByPoint: function ( point ) {\r\n\r\n\t\tthis.min.min( point );\r\n\t\tthis.max.max( point );\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\texpandByVector: function ( vector ) {\r\n\r\n\t\tthis.min.sub( vector );\r\n\t\tthis.max.add( vector );\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\texpandByScalar: function ( scalar ) {\r\n\r\n\t\tthis.min.addScalar( - scalar );\r\n\t\tthis.max.addScalar( scalar );\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\tcontainsPoint: function ( point ) {\r\n\r\n\t\tif ( point.x < this.min.x || point.x > this.max.x ||\r\n\t\t point.y < this.min.y || point.y > this.max.y ) {\r\n\r\n\t\t\treturn false;\r\n\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\r\n\t},\r\n\r\n\tcontainsBox: function ( box ) {\r\n\r\n\t\tif ( ( this.min.x <= box.min.x ) && ( box.max.x <= this.max.x ) &&\r\n\t\t ( this.min.y <= box.min.y ) && ( box.max.y <= this.max.y ) ) {\r\n\r\n\t\t\treturn true;\r\n\r\n\t\t}\r\n\r\n\t\treturn false;\r\n\r\n\t},\r\n\r\n\tgetParameter: function ( point, optionalTarget ) {\r\n\r\n\t\t// This can potentially have a divide by zero if the box\r\n\t\t// has a size dimension of 0.\r\n\r\n\t\tvar result = optionalTarget || new THREE.Vector2();\r\n\r\n\t\treturn result.set(\r\n\t\t\t( point.x - this.min.x ) / ( this.max.x - this.min.x ),\r\n\t\t\t( point.y - this.min.y ) / ( this.max.y - this.min.y )\r\n\t\t);\r\n\r\n\t},\r\n\r\n\tisIntersectionBox: function ( box ) {\r\n\r\n\t\t// using 6 splitting planes to rule out intersections.\r\n\r\n\t\tif ( box.max.x < this.min.x || box.min.x > this.max.x ||\r\n\t\t box.max.y < this.min.y || box.min.y > this.max.y ) {\r\n\r\n\t\t\treturn false;\r\n\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\r\n\t},\r\n\r\n\tclampPoint: function ( point, optionalTarget ) {\r\n\r\n\t\tvar result = optionalTarget || new THREE.Vector2();\r\n\t\treturn result.copy( point ).clamp( this.min, this.max );\r\n\r\n\t},\r\n\r\n\tdistanceToPoint: function () {\r\n\r\n\t\tvar v1 = new THREE.Vector2();\r\n\r\n\t\treturn function ( point ) {\r\n\r\n\t\t\tvar clampedPoint = v1.copy( point ).clamp( this.min, this.max );\r\n\t\t\treturn clampedPoint.sub( point ).length();\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\tintersect: function ( box ) {\r\n\r\n\t\tthis.min.max( box.min );\r\n\t\tthis.max.min( box.max );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tunion: function ( box ) {\r\n\r\n\t\tthis.min.min( box.min );\r\n\t\tthis.max.max( box.max );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\ttranslate: function ( offset ) {\r\n\r\n\t\tthis.min.add( offset );\r\n\t\tthis.max.add( offset );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tequals: function ( box ) {\r\n\r\n\t\treturn box.min.equals( this.min ) && box.max.equals( this.max );\r\n\r\n\t},\r\n\r\n\tclone: function () {\r\n\r\n\t\treturn new THREE.Box2().copy( this );\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/math/Box3.js\r\n\r\n/**\r\n * @author bhouston / http://exocortex.com\r\n * @author WestLangley / http://github.com/WestLangley\r\n */\r\n\r\nTHREE.Box3 = function ( min, max ) {\r\n\r\n\tthis.min = ( min !== undefined ) ? min : new THREE.Vector3( Infinity, Infinity, Infinity );\r\n\tthis.max = ( max !== undefined ) ? max : new THREE.Vector3( - Infinity, - Infinity, - Infinity );\r\n\r\n};\r\n\r\nTHREE.Box3.prototype = {\r\n\r\n\tconstructor: THREE.Box3,\r\n\r\n\tset: function ( min, max ) {\r\n\r\n\t\tthis.min.copy( min );\r\n\t\tthis.max.copy( max );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetFromPoints: function ( points ) {\r\n\r\n\t\tthis.makeEmpty();\r\n\r\n\t\tfor ( var i = 0, il = points.length; i < il; i ++ ) {\r\n\r\n\t\t\tthis.expandByPoint( points[ i ] )\r\n\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetFromCenterAndSize: function () {\r\n\r\n\t\tvar v1 = new THREE.Vector3();\r\n\r\n\t\treturn function ( center, size ) {\r\n\r\n\t\t\tvar halfSize = v1.copy( size ).multiplyScalar( 0.5 );\r\n\r\n\t\t\tthis.min.copy( center ).sub( halfSize );\r\n\t\t\tthis.max.copy( center ).add( halfSize );\r\n\r\n\t\t\treturn this;\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\tsetFromObject: function () {\r\n\r\n\t\t// Computes the world-axis-aligned bounding box of an object (including its children),\r\n\t\t// accounting for both the object's, and childrens', world transforms\r\n\r\n\t\tvar v1 = new THREE.Vector3();\r\n\r\n\t\treturn function ( object ) {\r\n\r\n\t\t\tvar scope = this;\r\n\r\n\t\t\tobject.updateMatrixWorld( true );\r\n\r\n\t\t\tthis.makeEmpty();\r\n\r\n\t\t\tobject.traverse( function ( node ) {\r\n\r\n\t\t\t\tvar geometry = node.geometry;\r\n\r\n\t\t\t\tif ( geometry !== undefined ) {\r\n\r\n\t\t\t\t\tif ( geometry instanceof THREE.Geometry ) {\r\n\r\n\t\t\t\t\t\tvar vertices = geometry.vertices;\r\n\r\n\t\t\t\t\t\tfor ( var i = 0, il = vertices.length; i < il; i ++ ) {\r\n\r\n\t\t\t\t\t\t\tv1.copy( vertices[ i ] );\r\n\r\n\t\t\t\t\t\t\tv1.applyMatrix4( node.matrixWorld );\r\n\r\n\t\t\t\t\t\t\tscope.expandByPoint( v1 );\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t} else if ( geometry instanceof THREE.BufferGeometry && geometry.attributes[ 'position' ] !== undefined ) {\r\n\r\n\t\t\t\t\t\tvar positions = geometry.attributes[ 'position' ].array;\r\n\r\n\t\t\t\t\t\tfor ( var i = 0, il = positions.length; i < il; i += 3 ) {\r\n\r\n\t\t\t\t\t\t\tv1.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );\r\n\r\n\t\t\t\t\t\t\tv1.applyMatrix4( node.matrixWorld );\r\n\r\n\t\t\t\t\t\t\tscope.expandByPoint( v1 );\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t} );\r\n\r\n\t\t\treturn this;\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\tcopy: function ( box ) {\r\n\r\n\t\tthis.min.copy( box.min );\r\n\t\tthis.max.copy( box.max );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tmakeEmpty: function () {\r\n\r\n\t\tthis.min.x = this.min.y = this.min.z = Infinity;\r\n\t\tthis.max.x = this.max.y = this.max.z = - Infinity;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tempty: function () {\r\n\r\n\t\t// this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes\r\n\r\n\t\treturn ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z );\r\n\r\n\t},\r\n\r\n\tcenter: function ( optionalTarget ) {\r\n\r\n\t\tvar result = optionalTarget || new THREE.Vector3();\r\n\t\treturn result.addVectors( this.min, this.max ).multiplyScalar( 0.5 );\r\n\r\n\t},\r\n\r\n\tsize: function ( optionalTarget ) {\r\n\r\n\t\tvar result = optionalTarget || new THREE.Vector3();\r\n\t\treturn result.subVectors( this.max, this.min );\r\n\r\n\t},\r\n\r\n\texpandByPoint: function ( point ) {\r\n\r\n\t\tthis.min.min( point );\r\n\t\tthis.max.max( point );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\texpandByVector: function ( vector ) {\r\n\r\n\t\tthis.min.sub( vector );\r\n\t\tthis.max.add( vector );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\texpandByScalar: function ( scalar ) {\r\n\r\n\t\tthis.min.addScalar( - scalar );\r\n\t\tthis.max.addScalar( scalar );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tcontainsPoint: function ( point ) {\r\n\r\n\t\tif ( point.x < this.min.x || point.x > this.max.x ||\r\n\t\t point.y < this.min.y || point.y > this.max.y ||\r\n\t\t point.z < this.min.z || point.z > this.max.z ) {\r\n\r\n\t\t\treturn false;\r\n\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\r\n\t},\r\n\r\n\tcontainsBox: function ( box ) {\r\n\r\n\t\tif ( ( this.min.x <= box.min.x ) && ( box.max.x <= this.max.x ) &&\r\n\t\t\t ( this.min.y <= box.min.y ) && ( box.max.y <= this.max.y ) &&\r\n\t\t\t ( this.min.z <= box.min.z ) && ( box.max.z <= this.max.z ) ) {\r\n\r\n\t\t\treturn true;\r\n\r\n\t\t}\r\n\r\n\t\treturn false;\r\n\r\n\t},\r\n\r\n\tgetParameter: function ( point, optionalTarget ) {\r\n\r\n\t\t// This can potentially have a divide by zero if the box\r\n\t\t// has a size dimension of 0.\r\n\r\n\t\tvar result = optionalTarget || new THREE.Vector3();\r\n\r\n\t\treturn result.set(\r\n\t\t\t( point.x - this.min.x ) / ( this.max.x - this.min.x ),\r\n\t\t\t( point.y - this.min.y ) / ( this.max.y - this.min.y ),\r\n\t\t\t( point.z - this.min.z ) / ( this.max.z - this.min.z )\r\n\t\t);\r\n\r\n\t},\r\n\r\n\tisIntersectionBox: function ( box ) {\r\n\r\n\t\t// using 6 splitting planes to rule out intersections.\r\n\r\n\t\tif ( box.max.x < this.min.x || box.min.x > this.max.x ||\r\n\t\t box.max.y < this.min.y || box.min.y > this.max.y ||\r\n\t\t box.max.z < this.min.z || box.min.z > this.max.z ) {\r\n\r\n\t\t\treturn false;\r\n\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\r\n\t},\r\n\r\n\tclampPoint: function ( point, optionalTarget ) {\r\n\r\n\t\tvar result = optionalTarget || new THREE.Vector3();\r\n\t\treturn result.copy( point ).clamp( this.min, this.max );\r\n\r\n\t},\r\n\r\n\tdistanceToPoint: function () {\r\n\r\n\t\tvar v1 = new THREE.Vector3();\r\n\r\n\t\treturn function ( point ) {\r\n\r\n\t\t\tvar clampedPoint = v1.copy( point ).clamp( this.min, this.max );\r\n\t\t\treturn clampedPoint.sub( point ).length();\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\tgetBoundingSphere: function () {\r\n\r\n\t\tvar v1 = new THREE.Vector3();\r\n\r\n\t\treturn function ( optionalTarget ) {\r\n\r\n\t\t\tvar result = optionalTarget || new THREE.Sphere();\r\n\r\n\t\t\tresult.center = this.center();\r\n\t\t\tresult.radius = this.size( v1 ).length() * 0.5;\r\n\r\n\t\t\treturn result;\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\tintersect: function ( box ) {\r\n\r\n\t\tthis.min.max( box.min );\r\n\t\tthis.max.min( box.max );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tunion: function ( box ) {\r\n\r\n\t\tthis.min.min( box.min );\r\n\t\tthis.max.max( box.max );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tapplyMatrix4: function () {\r\n\r\n\t\tvar points = [\r\n\t\t\tnew THREE.Vector3(),\r\n\t\t\tnew THREE.Vector3(),\r\n\t\t\tnew THREE.Vector3(),\r\n\t\t\tnew THREE.Vector3(),\r\n\t\t\tnew THREE.Vector3(),\r\n\t\t\tnew THREE.Vector3(),\r\n\t\t\tnew THREE.Vector3(),\r\n\t\t\tnew THREE.Vector3()\r\n\t\t];\r\n\r\n\t\treturn function ( matrix ) {\r\n\r\n\t\t\t// NOTE: I am using a binary pattern to specify all 2^3 combinations below\r\n\t\t\tpoints[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000\r\n\t\t\tpoints[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001\r\n\t\t\tpoints[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010\r\n\t\t\tpoints[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011\r\n\t\t\tpoints[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100\r\n\t\t\tpoints[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101\r\n\t\t\tpoints[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110\r\n\t\t\tpoints[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111\r\n\r\n\t\t\tthis.makeEmpty();\r\n\t\t\tthis.setFromPoints( points );\r\n\r\n\t\t\treturn this;\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\ttranslate: function ( offset ) {\r\n\r\n\t\tthis.min.add( offset );\r\n\t\tthis.max.add( offset );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tequals: function ( box ) {\r\n\r\n\t\treturn box.min.equals( this.min ) && box.max.equals( this.max );\r\n\r\n\t},\r\n\r\n\tclone: function () {\r\n\r\n\t\treturn new THREE.Box3().copy( this );\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/math/Matrix3.js\r\n\r\n/**\r\n * @author alteredq / http://alteredqualia.com/\r\n * @author WestLangley / http://github.com/WestLangley\r\n * @author bhouston / http://exocortex.com\r\n */\r\n\r\nTHREE.Matrix3 = function () {\r\n\r\n\tthis.elements = new Float32Array( [\r\n\r\n\t\t1, 0, 0,\r\n\t\t0, 1, 0,\r\n\t\t0, 0, 1\r\n\r\n\t] );\r\n\r\n\tif ( arguments.length > 0 ) {\r\n\r\n\t\tTHREE.error( 'THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.' );\r\n\r\n\t}\r\n\r\n};\r\n\r\nTHREE.Matrix3.prototype = {\r\n\r\n\tconstructor: THREE.Matrix3,\r\n\r\n\tset: function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {\r\n\r\n\t\tvar te = this.elements;\r\n\r\n\t\tte[ 0 ] = n11; te[ 3 ] = n12; te[ 6 ] = n13;\r\n\t\tte[ 1 ] = n21; te[ 4 ] = n22; te[ 7 ] = n23;\r\n\t\tte[ 2 ] = n31; te[ 5 ] = n32; te[ 8 ] = n33;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tidentity: function () {\r\n\r\n\t\tthis.set(\r\n\r\n\t\t\t1, 0, 0,\r\n\t\t\t0, 1, 0,\r\n\t\t\t0, 0, 1\r\n\r\n\t\t);\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tcopy: function ( m ) {\r\n\r\n\t\tvar me = m.elements;\r\n\r\n\t\tthis.set(\r\n\r\n\t\t\tme[ 0 ], me[ 3 ], me[ 6 ],\r\n\t\t\tme[ 1 ], me[ 4 ], me[ 7 ],\r\n\t\t\tme[ 2 ], me[ 5 ], me[ 8 ]\r\n\r\n\t\t);\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tmultiplyVector3: function ( vector ) {\r\n\r\n\t\tTHREE.warn( 'THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' );\r\n\t\treturn vector.applyMatrix3( this );\r\n\r\n\t},\r\n\r\n\tmultiplyVector3Array: function ( a ) {\r\n\r\n\t\tTHREE.warn( 'THREE.Matrix3: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.' );\r\n\t\treturn this.applyToVector3Array( a );\r\n\r\n\t},\r\n\r\n\tapplyToVector3Array: function () {\r\n\r\n\t\tvar v1 = new THREE.Vector3();\r\n\r\n\t\treturn function ( array, offset, length ) {\r\n\r\n\t\t\tif ( offset === undefined ) offset = 0;\r\n\t\t\tif ( length === undefined ) length = array.length;\r\n\r\n\t\t\tfor ( var i = 0, j = offset; i < length; i += 3, j += 3 ) {\r\n\r\n\t\t\t\tv1.x = array[ j ];\r\n\t\t\t\tv1.y = array[ j + 1 ];\r\n\t\t\t\tv1.z = array[ j + 2 ];\r\n\r\n\t\t\t\tv1.applyMatrix3( this );\r\n\r\n\t\t\t\tarray[ j ] = v1.x;\r\n\t\t\t\tarray[ j + 1 ] = v1.y;\r\n\t\t\t\tarray[ j + 2 ] = v1.z;\r\n\r\n\t\t\t}\r\n\r\n\t\t\treturn array;\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\tmultiplyScalar: function ( s ) {\r\n\r\n\t\tvar te = this.elements;\r\n\r\n\t\tte[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s;\r\n\t\tte[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s;\r\n\t\tte[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tdeterminant: function () {\r\n\r\n\t\tvar te = this.elements;\r\n\r\n\t\tvar a = te[ 0 ], b = te[ 1 ], c = te[ 2 ],\r\n\t\t\td = te[ 3 ], e = te[ 4 ], f = te[ 5 ],\r\n\t\t\tg = te[ 6 ], h = te[ 7 ], i = te[ 8 ];\r\n\r\n\t\treturn a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g;\r\n\r\n\t},\r\n\r\n\tgetInverse: function ( matrix, throwOnInvertible ) {\r\n\r\n\t\t// input: THREE.Matrix4\r\n\t\t// ( based on http://code.google.com/p/webgl-mjs/ )\r\n\r\n\t\tvar me = matrix.elements;\r\n\t\tvar te = this.elements;\r\n\r\n\t\tte[ 0 ] = me[ 10 ] * me[ 5 ] - me[ 6 ] * me[ 9 ];\r\n\t\tte[ 1 ] = - me[ 10 ] * me[ 1 ] + me[ 2 ] * me[ 9 ];\r\n\t\tte[ 2 ] = me[ 6 ] * me[ 1 ] - me[ 2 ] * me[ 5 ];\r\n\t\tte[ 3 ] = - me[ 10 ] * me[ 4 ] + me[ 6 ] * me[ 8 ];\r\n\t\tte[ 4 ] = me[ 10 ] * me[ 0 ] - me[ 2 ] * me[ 8 ];\r\n\t\tte[ 5 ] = - me[ 6 ] * me[ 0 ] + me[ 2 ] * me[ 4 ];\r\n\t\tte[ 6 ] = me[ 9 ] * me[ 4 ] - me[ 5 ] * me[ 8 ];\r\n\t\tte[ 7 ] = - me[ 9 ] * me[ 0 ] + me[ 1 ] * me[ 8 ];\r\n\t\tte[ 8 ] = me[ 5 ] * me[ 0 ] - me[ 1 ] * me[ 4 ];\r\n\r\n\t\tvar det = me[ 0 ] * te[ 0 ] + me[ 1 ] * te[ 3 ] + me[ 2 ] * te[ 6 ];\r\n\r\n\t\t// no inverse\r\n\r\n\t\tif ( det === 0 ) {\r\n\r\n\t\t\tvar msg = \"Matrix3.getInverse(): can't invert matrix, determinant is 0\";\r\n\r\n\t\t\tif ( throwOnInvertible || false ) {\r\n\r\n\t\t\t\tthrow new Error( msg );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tTHREE.warn( msg );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tthis.identity();\r\n\r\n\t\t\treturn this;\r\n\r\n\t\t}\r\n\r\n\t\tthis.multiplyScalar( 1.0 / det );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\ttranspose: function () {\r\n\r\n\t\tvar tmp, m = this.elements;\r\n\r\n\t\ttmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp;\r\n\t\ttmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp;\r\n\t\ttmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tflattenToArrayOffset: function ( array, offset ) {\r\n\r\n\t\tvar te = this.elements;\r\n\r\n\t\tarray[ offset ] = te[ 0 ];\r\n\t\tarray[ offset + 1 ] = te[ 1 ];\r\n\t\tarray[ offset + 2 ] = te[ 2 ];\r\n\r\n\t\tarray[ offset + 3 ] = te[ 3 ];\r\n\t\tarray[ offset + 4 ] = te[ 4 ];\r\n\t\tarray[ offset + 5 ] = te[ 5 ];\r\n\r\n\t\tarray[ offset + 6 ] = te[ 6 ];\r\n\t\tarray[ offset + 7 ] = te[ 7 ];\r\n\t\tarray[ offset + 8 ] = te[ 8 ];\r\n\r\n\t\treturn array;\r\n\r\n\t},\r\n\r\n\tgetNormalMatrix: function ( m ) {\r\n\r\n\t\t// input: THREE.Matrix4\r\n\r\n\t\tthis.getInverse( m ).transpose();\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\ttransposeIntoArray: function ( r ) {\r\n\r\n\t\tvar m = this.elements;\r\n\r\n\t\tr[ 0 ] = m[ 0 ];\r\n\t\tr[ 1 ] = m[ 3 ];\r\n\t\tr[ 2 ] = m[ 6 ];\r\n\t\tr[ 3 ] = m[ 1 ];\r\n\t\tr[ 4 ] = m[ 4 ];\r\n\t\tr[ 5 ] = m[ 7 ];\r\n\t\tr[ 6 ] = m[ 2 ];\r\n\t\tr[ 7 ] = m[ 5 ];\r\n\t\tr[ 8 ] = m[ 8 ];\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tfromArray: function ( array ) {\r\n\r\n\t\tthis.elements.set( array );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\ttoArray: function () {\r\n\r\n\t\tvar te = this.elements;\r\n\r\n\t\treturn [\r\n\t\t\tte[ 0 ], te[ 1 ], te[ 2 ],\r\n\t\t\tte[ 3 ], te[ 4 ], te[ 5 ],\r\n\t\t\tte[ 6 ], te[ 7 ], te[ 8 ]\r\n\t\t];\r\n\r\n\t},\r\n\r\n\tclone: function () {\r\n\r\n\t\treturn new THREE.Matrix3().fromArray( this.elements );\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/math/Matrix4.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n * @author supereggbert / http://www.paulbrunt.co.uk/\r\n * @author philogb / http://blog.thejit.org/\r\n * @author jordi_ros / http://plattsoft.com\r\n * @author D1plo1d / http://github.com/D1plo1d\r\n * @author alteredq / http://alteredqualia.com/\r\n * @author mikael emtinger / http://gomo.se/\r\n * @author timknip / http://www.floorplanner.com/\r\n * @author bhouston / http://exocortex.com\r\n * @author WestLangley / http://github.com/WestLangley\r\n */\r\n\r\nTHREE.Matrix4 = function () {\r\n\r\n\tthis.elements = new Float32Array( [\r\n\r\n\t\t1, 0, 0, 0,\r\n\t\t0, 1, 0, 0,\r\n\t\t0, 0, 1, 0,\r\n\t\t0, 0, 0, 1\r\n\r\n\t] );\r\n\r\n\tif ( arguments.length > 0 ) {\r\n\r\n\t\tTHREE.error( 'THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.' );\r\n\r\n\t}\r\n\r\n};\r\n\r\nTHREE.Matrix4.prototype = {\r\n\r\n\tconstructor: THREE.Matrix4,\r\n\r\n\tset: function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {\r\n\r\n\t\tvar te = this.elements;\r\n\r\n\t\tte[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14;\r\n\t\tte[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24;\r\n\t\tte[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34;\r\n\t\tte[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tidentity: function () {\r\n\r\n\t\tthis.set(\r\n\r\n\t\t\t1, 0, 0, 0,\r\n\t\t\t0, 1, 0, 0,\r\n\t\t\t0, 0, 1, 0,\r\n\t\t\t0, 0, 0, 1\r\n\r\n\t\t);\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tcopy: function ( m ) {\r\n\r\n\t\tthis.elements.set( m.elements );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\textractPosition: function ( m ) {\r\n\r\n\t\tTHREE.warn( 'THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().' );\r\n\t\treturn this.copyPosition( m );\r\n\r\n\t},\r\n\r\n\tcopyPosition: function ( m ) {\r\n\r\n\t\tvar te = this.elements;\r\n\t\tvar me = m.elements;\r\n\r\n\t\tte[ 12 ] = me[ 12 ];\r\n\t\tte[ 13 ] = me[ 13 ];\r\n\t\tte[ 14 ] = me[ 14 ];\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\textractBasis: function ( xAxis, yAxis, zAxis ) {\r\n \r\n\t\tvar te = this.elements;\r\n \r\n\t\txAxis.set( te[ 0 ], te[ 1 ], te[ 2 ] );\r\n\t\tyAxis.set( te[ 4 ], te[ 5 ], te[ 6 ] );\r\n\t\tzAxis.set( te[ 8 ], te[ 9 ], te[ 10 ] );\r\n \r\n\t\treturn this;\r\n \t\t\r\n\t},\r\n \r\n\tmakeBasis: function ( xAxis, yAxis, zAxis ) {\r\n\r\n\t\tthis.set(\r\n\t\t\txAxis.x, yAxis.x, zAxis.x, 0,\r\n\t\t\txAxis.y, yAxis.y, zAxis.y, 0,\r\n\t\t\txAxis.z, yAxis.z, zAxis.z, 0,\r\n\t\t\t0, 0, 0, 1\r\n\t\t);\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\textractRotation: function () {\r\n\r\n\t\tvar v1 = new THREE.Vector3();\r\n\r\n\t\treturn function ( m ) {\r\n\r\n\t\t\tvar te = this.elements;\r\n\t\t\tvar me = m.elements;\r\n\r\n\t\t\tvar scaleX = 1 / v1.set( me[ 0 ], me[ 1 ], me[ 2 ] ).length();\r\n\t\t\tvar scaleY = 1 / v1.set( me[ 4 ], me[ 5 ], me[ 6 ] ).length();\r\n\t\t\tvar scaleZ = 1 / v1.set( me[ 8 ], me[ 9 ], me[ 10 ] ).length();\r\n\r\n\t\t\tte[ 0 ] = me[ 0 ] * scaleX;\r\n\t\t\tte[ 1 ] = me[ 1 ] * scaleX;\r\n\t\t\tte[ 2 ] = me[ 2 ] * scaleX;\r\n\r\n\t\t\tte[ 4 ] = me[ 4 ] * scaleY;\r\n\t\t\tte[ 5 ] = me[ 5 ] * scaleY;\r\n\t\t\tte[ 6 ] = me[ 6 ] * scaleY;\r\n\r\n\t\t\tte[ 8 ] = me[ 8 ] * scaleZ;\r\n\t\t\tte[ 9 ] = me[ 9 ] * scaleZ;\r\n\t\t\tte[ 10 ] = me[ 10 ] * scaleZ;\r\n\r\n\t\t\treturn this;\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\tmakeRotationFromEuler: function ( euler ) {\r\n\r\n\t\tif ( euler instanceof THREE.Euler === false ) {\r\n\r\n\t\t\tTHREE.error( 'THREE.Matrix: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.' );\r\n\r\n\t\t}\r\n\r\n\t\tvar te = this.elements;\r\n\r\n\t\tvar x = euler.x, y = euler.y, z = euler.z;\r\n\t\tvar a = Math.cos( x ), b = Math.sin( x );\r\n\t\tvar c = Math.cos( y ), d = Math.sin( y );\r\n\t\tvar e = Math.cos( z ), f = Math.sin( z );\r\n\r\n\t\tif ( euler.order === 'XYZ' ) {\r\n\r\n\t\t\tvar ae = a * e, af = a * f, be = b * e, bf = b * f;\r\n\r\n\t\t\tte[ 0 ] = c * e;\r\n\t\t\tte[ 4 ] = - c * f;\r\n\t\t\tte[ 8 ] = d;\r\n\r\n\t\t\tte[ 1 ] = af + be * d;\r\n\t\t\tte[ 5 ] = ae - bf * d;\r\n\t\t\tte[ 9 ] = - b * c;\r\n\r\n\t\t\tte[ 2 ] = bf - ae * d;\r\n\t\t\tte[ 6 ] = be + af * d;\r\n\t\t\tte[ 10 ] = a * c;\r\n\r\n\t\t} else if ( euler.order === 'YXZ' ) {\r\n\r\n\t\t\tvar ce = c * e, cf = c * f, de = d * e, df = d * f;\r\n\r\n\t\t\tte[ 0 ] = ce + df * b;\r\n\t\t\tte[ 4 ] = de * b - cf;\r\n\t\t\tte[ 8 ] = a * d;\r\n\r\n\t\t\tte[ 1 ] = a * f;\r\n\t\t\tte[ 5 ] = a * e;\r\n\t\t\tte[ 9 ] = - b;\r\n\r\n\t\t\tte[ 2 ] = cf * b - de;\r\n\t\t\tte[ 6 ] = df + ce * b;\r\n\t\t\tte[ 10 ] = a * c;\r\n\r\n\t\t} else if ( euler.order === 'ZXY' ) {\r\n\r\n\t\t\tvar ce = c * e, cf = c * f, de = d * e, df = d * f;\r\n\r\n\t\t\tte[ 0 ] = ce - df * b;\r\n\t\t\tte[ 4 ] = - a * f;\r\n\t\t\tte[ 8 ] = de + cf * b;\r\n\r\n\t\t\tte[ 1 ] = cf + de * b;\r\n\t\t\tte[ 5 ] = a * e;\r\n\t\t\tte[ 9 ] = df - ce * b;\r\n\r\n\t\t\tte[ 2 ] = - a * d;\r\n\t\t\tte[ 6 ] = b;\r\n\t\t\tte[ 10 ] = a * c;\r\n\r\n\t\t} else if ( euler.order === 'ZYX' ) {\r\n\r\n\t\t\tvar ae = a * e, af = a * f, be = b * e, bf = b * f;\r\n\r\n\t\t\tte[ 0 ] = c * e;\r\n\t\t\tte[ 4 ] = be * d - af;\r\n\t\t\tte[ 8 ] = ae * d + bf;\r\n\r\n\t\t\tte[ 1 ] = c * f;\r\n\t\t\tte[ 5 ] = bf * d + ae;\r\n\t\t\tte[ 9 ] = af * d - be;\r\n\r\n\t\t\tte[ 2 ] = - d;\r\n\t\t\tte[ 6 ] = b * c;\r\n\t\t\tte[ 10 ] = a * c;\r\n\r\n\t\t} else if ( euler.order === 'YZX' ) {\r\n\r\n\t\t\tvar ac = a * c, ad = a * d, bc = b * c, bd = b * d;\r\n\r\n\t\t\tte[ 0 ] = c * e;\r\n\t\t\tte[ 4 ] = bd - ac * f;\r\n\t\t\tte[ 8 ] = bc * f + ad;\r\n\r\n\t\t\tte[ 1 ] = f;\r\n\t\t\tte[ 5 ] = a * e;\r\n\t\t\tte[ 9 ] = - b * e;\r\n\r\n\t\t\tte[ 2 ] = - d * e;\r\n\t\t\tte[ 6 ] = ad * f + bc;\r\n\t\t\tte[ 10 ] = ac - bd * f;\r\n\r\n\t\t} else if ( euler.order === 'XZY' ) {\r\n\r\n\t\t\tvar ac = a * c, ad = a * d, bc = b * c, bd = b * d;\r\n\r\n\t\t\tte[ 0 ] = c * e;\r\n\t\t\tte[ 4 ] = - f;\r\n\t\t\tte[ 8 ] = d * e;\r\n\r\n\t\t\tte[ 1 ] = ac * f + bd;\r\n\t\t\tte[ 5 ] = a * e;\r\n\t\t\tte[ 9 ] = ad * f - bc;\r\n\r\n\t\t\tte[ 2 ] = bc * f - ad;\r\n\t\t\tte[ 6 ] = b * e;\r\n\t\t\tte[ 10 ] = bd * f + ac;\r\n\r\n\t\t}\r\n\r\n\t\t// last column\r\n\t\tte[ 3 ] = 0;\r\n\t\tte[ 7 ] = 0;\r\n\t\tte[ 11 ] = 0;\r\n\r\n\t\t// bottom row\r\n\t\tte[ 12 ] = 0;\r\n\t\tte[ 13 ] = 0;\r\n\t\tte[ 14 ] = 0;\r\n\t\tte[ 15 ] = 1;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetRotationFromQuaternion: function ( q ) {\r\n\r\n\t\tTHREE.warn( 'THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().' );\r\n\r\n\t\treturn this.makeRotationFromQuaternion( q );\r\n\r\n\t},\r\n\r\n\tmakeRotationFromQuaternion: function ( q ) {\r\n\r\n\t\tvar te = this.elements;\r\n\r\n\t\tvar x = q.x, y = q.y, z = q.z, w = q.w;\r\n\t\tvar x2 = x + x, y2 = y + y, z2 = z + z;\r\n\t\tvar xx = x * x2, xy = x * y2, xz = x * z2;\r\n\t\tvar yy = y * y2, yz = y * z2, zz = z * z2;\r\n\t\tvar wx = w * x2, wy = w * y2, wz = w * z2;\r\n\r\n\t\tte[ 0 ] = 1 - ( yy + zz );\r\n\t\tte[ 4 ] = xy - wz;\r\n\t\tte[ 8 ] = xz + wy;\r\n\r\n\t\tte[ 1 ] = xy + wz;\r\n\t\tte[ 5 ] = 1 - ( xx + zz );\r\n\t\tte[ 9 ] = yz - wx;\r\n\r\n\t\tte[ 2 ] = xz - wy;\r\n\t\tte[ 6 ] = yz + wx;\r\n\t\tte[ 10 ] = 1 - ( xx + yy );\r\n\r\n\t\t// last column\r\n\t\tte[ 3 ] = 0;\r\n\t\tte[ 7 ] = 0;\r\n\t\tte[ 11 ] = 0;\r\n\r\n\t\t// bottom row\r\n\t\tte[ 12 ] = 0;\r\n\t\tte[ 13 ] = 0;\r\n\t\tte[ 14 ] = 0;\r\n\t\tte[ 15 ] = 1;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tlookAt: function () {\r\n\r\n\t\tvar x = new THREE.Vector3();\r\n\t\tvar y = new THREE.Vector3();\r\n\t\tvar z = new THREE.Vector3();\r\n\r\n\t\treturn function ( eye, target, up ) {\r\n\r\n\t\t\tvar te = this.elements;\r\n\r\n\t\t\tz.subVectors( eye, target ).normalize();\r\n\r\n\t\t\tif ( z.length() === 0 ) {\r\n\r\n\t\t\t\tz.z = 1;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tx.crossVectors( up, z ).normalize();\r\n\r\n\t\t\tif ( x.length() === 0 ) {\r\n\r\n\t\t\t\tz.x += 0.0001;\r\n\t\t\t\tx.crossVectors( up, z ).normalize();\r\n\r\n\t\t\t}\r\n\r\n\t\t\ty.crossVectors( z, x );\r\n\r\n\r\n\t\t\tte[ 0 ] = x.x; te[ 4 ] = y.x; te[ 8 ] = z.x;\r\n\t\t\tte[ 1 ] = x.y; te[ 5 ] = y.y; te[ 9 ] = z.y;\r\n\t\t\tte[ 2 ] = x.z; te[ 6 ] = y.z; te[ 10 ] = z.z;\r\n\r\n\t\t\treturn this;\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\tmultiply: function ( m, n ) {\r\n\r\n\t\tif ( n !== undefined ) {\r\n\r\n\t\t\tTHREE.warn( 'THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' );\r\n\t\t\treturn this.multiplyMatrices( m, n );\r\n\r\n\t\t}\r\n\r\n\t\treturn this.multiplyMatrices( this, m );\r\n\r\n\t},\r\n\r\n\tmultiplyMatrices: function ( a, b ) {\r\n\r\n\t\tvar ae = a.elements;\r\n\t\tvar be = b.elements;\r\n\t\tvar te = this.elements;\r\n\r\n\t\tvar a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ];\r\n\t\tvar a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ];\r\n\t\tvar a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ];\r\n\t\tvar a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ];\r\n\r\n\t\tvar b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ];\r\n\t\tvar b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ];\r\n\t\tvar b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ];\r\n\t\tvar b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ];\r\n\r\n\t\tte[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;\r\n\t\tte[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;\r\n\t\tte[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;\r\n\t\tte[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;\r\n\r\n\t\tte[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;\r\n\t\tte[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;\r\n\t\tte[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;\r\n\t\tte[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;\r\n\r\n\t\tte[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;\r\n\t\tte[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;\r\n\t\tte[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;\r\n\t\tte[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;\r\n\r\n\t\tte[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;\r\n\t\tte[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;\r\n\t\tte[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;\r\n\t\tte[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tmultiplyToArray: function ( a, b, r ) {\r\n\r\n\t\tvar te = this.elements;\r\n\r\n\t\tthis.multiplyMatrices( a, b );\r\n\r\n\t\tr[ 0 ] = te[ 0 ]; r[ 1 ] = te[ 1 ]; r[ 2 ] = te[ 2 ]; r[ 3 ] = te[ 3 ];\r\n\t\tr[ 4 ] = te[ 4 ]; r[ 5 ] = te[ 5 ]; r[ 6 ] = te[ 6 ]; r[ 7 ] = te[ 7 ];\r\n\t\tr[ 8 ] = te[ 8 ]; r[ 9 ] = te[ 9 ]; r[ 10 ] = te[ 10 ]; r[ 11 ] = te[ 11 ];\r\n\t\tr[ 12 ] = te[ 12 ]; r[ 13 ] = te[ 13 ]; r[ 14 ] = te[ 14 ]; r[ 15 ] = te[ 15 ];\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tmultiplyScalar: function ( s ) {\r\n\r\n\t\tvar te = this.elements;\r\n\r\n\t\tte[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s;\r\n\t\tte[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s;\r\n\t\tte[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s;\r\n\t\tte[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tmultiplyVector3: function ( vector ) {\r\n\r\n\t\tTHREE.warn( 'THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) or vector.applyProjection( matrix ) instead.' );\r\n\t\treturn vector.applyProjection( this );\r\n\r\n\t},\r\n\r\n\tmultiplyVector4: function ( vector ) {\r\n\r\n\t\tTHREE.warn( 'THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' );\r\n\t\treturn vector.applyMatrix4( this );\r\n\r\n\t},\r\n\r\n\tmultiplyVector3Array: function ( a ) {\r\n\r\n\t\tTHREE.warn( 'THREE.Matrix4: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.' );\r\n\t\treturn this.applyToVector3Array( a );\r\n\r\n\t},\r\n\r\n\tapplyToVector3Array: function () {\r\n\r\n\t\tvar v1 = new THREE.Vector3();\r\n\r\n\t\treturn function ( array, offset, length ) {\r\n\r\n\t\t\tif ( offset === undefined ) offset = 0;\r\n\t\t\tif ( length === undefined ) length = array.length;\r\n\r\n\t\t\tfor ( var i = 0, j = offset; i < length; i += 3, j += 3 ) {\r\n\r\n\t\t\t\tv1.x = array[ j ];\r\n\t\t\t\tv1.y = array[ j + 1 ];\r\n\t\t\t\tv1.z = array[ j + 2 ];\r\n\r\n\t\t\t\tv1.applyMatrix4( this );\r\n\r\n\t\t\t\tarray[ j ] = v1.x;\r\n\t\t\t\tarray[ j + 1 ] = v1.y;\r\n\t\t\t\tarray[ j + 2 ] = v1.z;\r\n\r\n\t\t\t}\r\n\r\n\t\t\treturn array;\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\trotateAxis: function ( v ) {\r\n\r\n\t\tTHREE.warn( 'THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' );\r\n\r\n\t\tv.transformDirection( this );\r\n\r\n\t},\r\n\r\n\tcrossVector: function ( vector ) {\r\n\r\n\t\tTHREE.warn( 'THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' );\r\n\t\treturn vector.applyMatrix4( this );\r\n\r\n\t},\r\n\r\n\tdeterminant: function () {\r\n\r\n\t\tvar te = this.elements;\r\n\r\n\t\tvar n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ];\r\n\t\tvar n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ];\r\n\t\tvar n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ];\r\n\t\tvar n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ];\r\n\r\n\t\t//TODO: make this more efficient\r\n\t\t//( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm )\r\n\r\n\t\treturn (\r\n\t\t\tn41 * (\r\n\t\t\t\t+ n14 * n23 * n32\r\n\t\t\t\t - n13 * n24 * n32\r\n\t\t\t\t - n14 * n22 * n33\r\n\t\t\t\t + n12 * n24 * n33\r\n\t\t\t\t + n13 * n22 * n34\r\n\t\t\t\t - n12 * n23 * n34\r\n\t\t\t) +\r\n\t\t\tn42 * (\r\n\t\t\t\t+ n11 * n23 * n34\r\n\t\t\t\t - n11 * n24 * n33\r\n\t\t\t\t + n14 * n21 * n33\r\n\t\t\t\t - n13 * n21 * n34\r\n\t\t\t\t + n13 * n24 * n31\r\n\t\t\t\t - n14 * n23 * n31\r\n\t\t\t) +\r\n\t\t\tn43 * (\r\n\t\t\t\t+ n11 * n24 * n32\r\n\t\t\t\t - n11 * n22 * n34\r\n\t\t\t\t - n14 * n21 * n32\r\n\t\t\t\t + n12 * n21 * n34\r\n\t\t\t\t + n14 * n22 * n31\r\n\t\t\t\t - n12 * n24 * n31\r\n\t\t\t) +\r\n\t\t\tn44 * (\r\n\t\t\t\t- n13 * n22 * n31\r\n\t\t\t\t - n11 * n23 * n32\r\n\t\t\t\t + n11 * n22 * n33\r\n\t\t\t\t + n13 * n21 * n32\r\n\t\t\t\t - n12 * n21 * n33\r\n\t\t\t\t + n12 * n23 * n31\r\n\t\t\t)\r\n\r\n\t\t);\r\n\r\n\t},\r\n\r\n\ttranspose: function () {\r\n\r\n\t\tvar te = this.elements;\r\n\t\tvar tmp;\r\n\r\n\t\ttmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp;\r\n\t\ttmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp;\r\n\t\ttmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp;\r\n\r\n\t\ttmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp;\r\n\t\ttmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp;\r\n\t\ttmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tflattenToArrayOffset: function ( array, offset ) {\r\n\r\n\t\tvar te = this.elements;\r\n\r\n\t\tarray[ offset ] = te[ 0 ];\r\n\t\tarray[ offset + 1 ] = te[ 1 ];\r\n\t\tarray[ offset + 2 ] = te[ 2 ];\r\n\t\tarray[ offset + 3 ] = te[ 3 ];\r\n\r\n\t\tarray[ offset + 4 ] = te[ 4 ];\r\n\t\tarray[ offset + 5 ] = te[ 5 ];\r\n\t\tarray[ offset + 6 ] = te[ 6 ];\r\n\t\tarray[ offset + 7 ] = te[ 7 ];\r\n\r\n\t\tarray[ offset + 8 ] = te[ 8 ];\r\n\t\tarray[ offset + 9 ] = te[ 9 ];\r\n\t\tarray[ offset + 10 ] = te[ 10 ];\r\n\t\tarray[ offset + 11 ] = te[ 11 ];\r\n\r\n\t\tarray[ offset + 12 ] = te[ 12 ];\r\n\t\tarray[ offset + 13 ] = te[ 13 ];\r\n\t\tarray[ offset + 14 ] = te[ 14 ];\r\n\t\tarray[ offset + 15 ] = te[ 15 ];\r\n\r\n\t\treturn array;\r\n\r\n\t},\r\n\r\n\tgetPosition: function () {\r\n\r\n\t\tvar v1 = new THREE.Vector3();\r\n\r\n\t\treturn function () {\r\n\r\n\t\t\tTHREE.warn( 'THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' );\r\n\r\n\t\t\tvar te = this.elements;\r\n\t\t\treturn v1.set( te[ 12 ], te[ 13 ], te[ 14 ] );\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\tsetPosition: function ( v ) {\r\n\r\n\t\tvar te = this.elements;\r\n\r\n\t\tte[ 12 ] = v.x;\r\n\t\tte[ 13 ] = v.y;\r\n\t\tte[ 14 ] = v.z;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tgetInverse: function ( m, throwOnInvertible ) {\r\n\r\n\t\t// based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm\r\n\t\tvar te = this.elements;\r\n\t\tvar me = m.elements;\r\n\r\n\t\tvar n11 = me[ 0 ], n12 = me[ 4 ], n13 = me[ 8 ], n14 = me[ 12 ];\r\n\t\tvar n21 = me[ 1 ], n22 = me[ 5 ], n23 = me[ 9 ], n24 = me[ 13 ];\r\n\t\tvar n31 = me[ 2 ], n32 = me[ 6 ], n33 = me[ 10 ], n34 = me[ 14 ];\r\n\t\tvar n41 = me[ 3 ], n42 = me[ 7 ], n43 = me[ 11 ], n44 = me[ 15 ];\r\n\r\n\t\tte[ 0 ] = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44;\r\n\t\tte[ 4 ] = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44;\r\n\t\tte[ 8 ] = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44;\r\n\t\tte[ 12 ] = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34;\r\n\t\tte[ 1 ] = n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44;\r\n\t\tte[ 5 ] = n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44;\r\n\t\tte[ 9 ] = n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44;\r\n\t\tte[ 13 ] = n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34;\r\n\t\tte[ 2 ] = n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44;\r\n\t\tte[ 6 ] = n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44;\r\n\t\tte[ 10 ] = n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44;\r\n\t\tte[ 14 ] = n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34;\r\n\t\tte[ 3 ] = n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43;\r\n\t\tte[ 7 ] = n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43;\r\n\t\tte[ 11 ] = n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43;\r\n\t\tte[ 15 ] = n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33;\r\n\r\n\t\tvar det = n11 * te[ 0 ] + n21 * te[ 4 ] + n31 * te[ 8 ] + n41 * te[ 12 ];\r\n\r\n\t\tif ( det == 0 ) {\r\n\r\n\t\t\tvar msg = \"THREE.Matrix4.getInverse(): can't invert matrix, determinant is 0\";\r\n\r\n\t\t\tif ( throwOnInvertible || false ) {\r\n\r\n\t\t\t\tthrow new Error( msg );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tTHREE.warn( msg );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tthis.identity();\r\n\r\n\t\t\treturn this;\r\n\t\t}\r\n\r\n\t\tthis.multiplyScalar( 1 / det );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\ttranslate: function ( v ) {\r\n\r\n\t\tTHREE.error( 'THREE.Matrix4: .translate() has been removed.' );\r\n\r\n\t},\r\n\r\n\trotateX: function ( angle ) {\r\n\r\n\t\tTHREE.error( 'THREE.Matrix4: .rotateX() has been removed.' );\r\n\r\n\t},\r\n\r\n\trotateY: function ( angle ) {\r\n\r\n\t\tTHREE.error( 'THREE.Matrix4: .rotateY() has been removed.' );\r\n\r\n\t},\r\n\r\n\trotateZ: function ( angle ) {\r\n\r\n\t\tTHREE.error( 'THREE.Matrix4: .rotateZ() has been removed.' );\r\n\r\n\t},\r\n\r\n\trotateByAxis: function ( axis, angle ) {\r\n\r\n\t\tTHREE.error( 'THREE.Matrix4: .rotateByAxis() has been removed.' );\r\n\r\n\t},\r\n\r\n\tscale: function ( v ) {\r\n\r\n\t\tvar te = this.elements;\r\n\t\tvar x = v.x, y = v.y, z = v.z;\r\n\r\n\t\tte[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z;\r\n\t\tte[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z;\r\n\t\tte[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z;\r\n\t\tte[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tgetMaxScaleOnAxis: function () {\r\n\r\n\t\tvar te = this.elements;\r\n\r\n\t\tvar scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ];\r\n\t\tvar scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ];\r\n\t\tvar scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ];\r\n\r\n\t\treturn Math.sqrt( Math.max( scaleXSq, Math.max( scaleYSq, scaleZSq ) ) );\r\n\r\n\t},\r\n\r\n\tmakeTranslation: function ( x, y, z ) {\r\n\r\n\t\tthis.set(\r\n\r\n\t\t\t1, 0, 0, x,\r\n\t\t\t0, 1, 0, y,\r\n\t\t\t0, 0, 1, z,\r\n\t\t\t0, 0, 0, 1\r\n\r\n\t\t);\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tmakeRotationX: function ( theta ) {\r\n\r\n\t\tvar c = Math.cos( theta ), s = Math.sin( theta );\r\n\r\n\t\tthis.set(\r\n\r\n\t\t\t1, 0, 0, 0,\r\n\t\t\t0, c, - s, 0,\r\n\t\t\t0, s, c, 0,\r\n\t\t\t0, 0, 0, 1\r\n\r\n\t\t);\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tmakeRotationY: function ( theta ) {\r\n\r\n\t\tvar c = Math.cos( theta ), s = Math.sin( theta );\r\n\r\n\t\tthis.set(\r\n\r\n\t\t\t c, 0, s, 0,\r\n\t\t\t 0, 1, 0, 0,\r\n\t\t\t- s, 0, c, 0,\r\n\t\t\t 0, 0, 0, 1\r\n\r\n\t\t);\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tmakeRotationZ: function ( theta ) {\r\n\r\n\t\tvar c = Math.cos( theta ), s = Math.sin( theta );\r\n\r\n\t\tthis.set(\r\n\r\n\t\t\tc, - s, 0, 0,\r\n\t\t\ts, c, 0, 0,\r\n\t\t\t0, 0, 1, 0,\r\n\t\t\t0, 0, 0, 1\r\n\r\n\t\t);\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tmakeRotationAxis: function ( axis, angle ) {\r\n\r\n\t\t// Based on http://www.gamedev.net/reference/articles/article1199.asp\r\n\r\n\t\tvar c = Math.cos( angle );\r\n\t\tvar s = Math.sin( angle );\r\n\t\tvar t = 1 - c;\r\n\t\tvar x = axis.x, y = axis.y, z = axis.z;\r\n\t\tvar tx = t * x, ty = t * y;\r\n\r\n\t\tthis.set(\r\n\r\n\t\t\ttx * x + c, tx * y - s * z, tx * z + s * y, 0,\r\n\t\t\ttx * y + s * z, ty * y + c, ty * z - s * x, 0,\r\n\t\t\ttx * z - s * y, ty * z + s * x, t * z * z + c, 0,\r\n\t\t\t0, 0, 0, 1\r\n\r\n\t\t);\r\n\r\n\t\t return this;\r\n\r\n\t},\r\n\r\n\tmakeScale: function ( x, y, z ) {\r\n\r\n\t\tthis.set(\r\n\r\n\t\t\tx, 0, 0, 0,\r\n\t\t\t0, y, 0, 0,\r\n\t\t\t0, 0, z, 0,\r\n\t\t\t0, 0, 0, 1\r\n\r\n\t\t);\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tcompose: function ( position, quaternion, scale ) {\r\n\r\n\t\tthis.makeRotationFromQuaternion( quaternion );\r\n\t\tthis.scale( scale );\r\n\t\tthis.setPosition( position );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tdecompose: function () {\r\n\r\n\t\tvar vector = new THREE.Vector3();\r\n\t\tvar matrix = new THREE.Matrix4();\r\n\r\n\t\treturn function ( position, quaternion, scale ) {\r\n\r\n\t\t\tvar te = this.elements;\r\n\r\n\t\t\tvar sx = vector.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length();\r\n\t\t\tvar sy = vector.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length();\r\n\t\t\tvar sz = vector.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length();\r\n\r\n\t\t\t// if determine is negative, we need to invert one scale\r\n\t\t\tvar det = this.determinant();\r\n\t\t\tif ( det < 0 ) {\r\n\t\t\t\tsx = - sx;\r\n\t\t\t}\r\n\r\n\t\t\tposition.x = te[ 12 ];\r\n\t\t\tposition.y = te[ 13 ];\r\n\t\t\tposition.z = te[ 14 ];\r\n\r\n\t\t\t// scale the rotation part\r\n\r\n\t\t\tmatrix.elements.set( this.elements ); // at this point matrix is incomplete so we can't use .copy()\r\n\r\n\t\t\tvar invSX = 1 / sx;\r\n\t\t\tvar invSY = 1 / sy;\r\n\t\t\tvar invSZ = 1 / sz;\r\n\r\n\t\t\tmatrix.elements[ 0 ] *= invSX;\r\n\t\t\tmatrix.elements[ 1 ] *= invSX;\r\n\t\t\tmatrix.elements[ 2 ] *= invSX;\r\n\r\n\t\t\tmatrix.elements[ 4 ] *= invSY;\r\n\t\t\tmatrix.elements[ 5 ] *= invSY;\r\n\t\t\tmatrix.elements[ 6 ] *= invSY;\r\n\r\n\t\t\tmatrix.elements[ 8 ] *= invSZ;\r\n\t\t\tmatrix.elements[ 9 ] *= invSZ;\r\n\t\t\tmatrix.elements[ 10 ] *= invSZ;\r\n\r\n\t\t\tquaternion.setFromRotationMatrix( matrix );\r\n\r\n\t\t\tscale.x = sx;\r\n\t\t\tscale.y = sy;\r\n\t\t\tscale.z = sz;\r\n\r\n\t\t\treturn this;\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\tmakeFrustum: function ( left, right, bottom, top, near, far ) {\r\n\r\n\t\tvar te = this.elements;\r\n\t\tvar x = 2 * near / ( right - left );\r\n\t\tvar y = 2 * near / ( top - bottom );\r\n\r\n\t\tvar a = ( right + left ) / ( right - left );\r\n\t\tvar b = ( top + bottom ) / ( top - bottom );\r\n\t\tvar c = - ( far + near ) / ( far - near );\r\n\t\tvar d = - 2 * far * near / ( far - near );\r\n\r\n\t\tte[ 0 ] = x;\tte[ 4 ] = 0;\tte[ 8 ] = a;\tte[ 12 ] = 0;\r\n\t\tte[ 1 ] = 0;\tte[ 5 ] = y;\tte[ 9 ] = b;\tte[ 13 ] = 0;\r\n\t\tte[ 2 ] = 0;\tte[ 6 ] = 0;\tte[ 10 ] = c;\tte[ 14 ] = d;\r\n\t\tte[ 3 ] = 0;\tte[ 7 ] = 0;\tte[ 11 ] = - 1;\tte[ 15 ] = 0;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tmakePerspective: function ( fov, aspect, near, far ) {\r\n\r\n\t\tvar ymax = near * Math.tan( THREE.Math.degToRad( fov * 0.5 ) );\r\n\t\tvar ymin = - ymax;\r\n\t\tvar xmin = ymin * aspect;\r\n\t\tvar xmax = ymax * aspect;\r\n\r\n\t\treturn this.makeFrustum( xmin, xmax, ymin, ymax, near, far );\r\n\r\n\t},\r\n\r\n\tmakeOrthographic: function ( left, right, top, bottom, near, far ) {\r\n\r\n\t\tvar te = this.elements;\r\n\t\tvar w = right - left;\r\n\t\tvar h = top - bottom;\r\n\t\tvar p = far - near;\r\n\r\n\t\tvar x = ( right + left ) / w;\r\n\t\tvar y = ( top + bottom ) / h;\r\n\t\tvar z = ( far + near ) / p;\r\n\r\n\t\tte[ 0 ] = 2 / w;\tte[ 4 ] = 0;\tte[ 8 ] = 0;\tte[ 12 ] = - x;\r\n\t\tte[ 1 ] = 0;\tte[ 5 ] = 2 / h;\tte[ 9 ] = 0;\tte[ 13 ] = - y;\r\n\t\tte[ 2 ] = 0;\tte[ 6 ] = 0;\tte[ 10 ] = - 2 / p;\tte[ 14 ] = - z;\r\n\t\tte[ 3 ] = 0;\tte[ 7 ] = 0;\tte[ 11 ] = 0;\tte[ 15 ] = 1;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tfromArray: function ( array ) {\r\n\r\n\t\tthis.elements.set( array );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\ttoArray: function () {\r\n\r\n\t\tvar te = this.elements;\r\n\r\n\t\treturn [\r\n\t\t\tte[ 0 ], te[ 1 ], te[ 2 ], te[ 3 ],\r\n\t\t\tte[ 4 ], te[ 5 ], te[ 6 ], te[ 7 ],\r\n\t\t\tte[ 8 ], te[ 9 ], te[ 10 ], te[ 11 ],\r\n\t\t\tte[ 12 ], te[ 13 ], te[ 14 ], te[ 15 ]\r\n\t\t];\r\n\r\n\t},\r\n\r\n\tclone: function () {\r\n\r\n\t\treturn new THREE.Matrix4().fromArray( this.elements );\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/math/Ray.js\r\n\r\n/**\r\n * @author bhouston / http://exocortex.com\r\n */\r\n\r\nTHREE.Ray = function ( origin, direction ) {\r\n\r\n\tthis.origin = ( origin !== undefined ) ? origin : new THREE.Vector3();\r\n\tthis.direction = ( direction !== undefined ) ? direction : new THREE.Vector3();\r\n\r\n};\r\n\r\nTHREE.Ray.prototype = {\r\n\r\n\tconstructor: THREE.Ray,\r\n\r\n\tset: function ( origin, direction ) {\r\n\r\n\t\tthis.origin.copy( origin );\r\n\t\tthis.direction.copy( direction );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tcopy: function ( ray ) {\r\n\r\n\t\tthis.origin.copy( ray.origin );\r\n\t\tthis.direction.copy( ray.direction );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tat: function ( t, optionalTarget ) {\r\n\r\n\t\tvar result = optionalTarget || new THREE.Vector3();\r\n\r\n\t\treturn result.copy( this.direction ).multiplyScalar( t ).add( this.origin );\r\n\r\n\t},\r\n\r\n\trecast: function () {\r\n\r\n\t\tvar v1 = new THREE.Vector3();\r\n\r\n\t\treturn function ( t ) {\r\n\r\n\t\t\tthis.origin.copy( this.at( t, v1 ) );\r\n\r\n\t\t\treturn this;\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\tclosestPointToPoint: function ( point, optionalTarget ) {\r\n\r\n\t\tvar result = optionalTarget || new THREE.Vector3();\r\n\t\tresult.subVectors( point, this.origin );\r\n\t\tvar directionDistance = result.dot( this.direction );\r\n\r\n\t\tif ( directionDistance < 0 ) {\r\n\r\n\t\t\treturn result.copy( this.origin );\r\n\r\n\t\t}\r\n\r\n\t\treturn result.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );\r\n\r\n\t},\r\n\r\n\tdistanceToPoint: function () {\r\n\r\n\t\tvar v1 = new THREE.Vector3();\r\n\r\n\t\treturn function ( point ) {\r\n\r\n\t\t\tvar directionDistance = v1.subVectors( point, this.origin ).dot( this.direction );\r\n\r\n\t\t\t// point behind the ray\r\n\r\n\t\t\tif ( directionDistance < 0 ) {\r\n\r\n\t\t\t\treturn this.origin.distanceTo( point );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tv1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );\r\n\r\n\t\t\treturn v1.distanceTo( point );\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\tdistanceSqToSegment: function () {\r\n\r\n\t\tvar segCenter = new THREE.Vector3();\r\n\t\tvar segDir = new THREE.Vector3();\r\n\t\tvar diff = new THREE.Vector3();\r\n\r\n\t\treturn function ( v0, v1, optionalPointOnRay, optionalPointOnSegment ) {\r\n\r\n\t\t\t// from http://www.geometrictools.com/LibMathematics/Distance/Wm5DistRay3Segment3.cpp\r\n\t\t\t// It returns the min distance between the ray and the segment\r\n\t\t\t// defined by v0 and v1\r\n\t\t\t// It can also set two optional targets :\r\n\t\t\t// - The closest point on the ray\r\n\t\t\t// - The closest point on the segment\r\n\r\n\t\t\tsegCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 );\r\n\t\t\tsegDir.copy( v1 ).sub( v0 ).normalize();\r\n\t\t\tdiff.copy( this.origin ).sub( segCenter );\r\n\r\n\t\t\tvar segExtent = v0.distanceTo( v1 ) * 0.5;\r\n\t\t\tvar a01 = - this.direction.dot( segDir );\r\n\t\t\tvar b0 = diff.dot( this.direction );\r\n\t\t\tvar b1 = - diff.dot( segDir );\r\n\t\t\tvar c = diff.lengthSq();\r\n\t\t\tvar det = Math.abs( 1 - a01 * a01 );\r\n\t\t\tvar s0, s1, sqrDist, extDet;\r\n\r\n\t\t\tif ( det > 0 ) {\r\n\r\n\t\t\t\t// The ray and segment are not parallel.\r\n\r\n\t\t\t\ts0 = a01 * b1 - b0;\r\n\t\t\t\ts1 = a01 * b0 - b1;\r\n\t\t\t\textDet = segExtent * det;\r\n\r\n\t\t\t\tif ( s0 >= 0 ) {\r\n\r\n\t\t\t\t\tif ( s1 >= - extDet ) {\r\n\r\n\t\t\t\t\t\tif ( s1 <= extDet ) {\r\n\r\n\t\t\t\t\t\t\t// region 0\r\n\t\t\t\t\t\t\t// Minimum at interior points of ray and segment.\r\n\r\n\t\t\t\t\t\t\tvar invDet = 1 / det;\r\n\t\t\t\t\t\t\ts0 *= invDet;\r\n\t\t\t\t\t\t\ts1 *= invDet;\r\n\t\t\t\t\t\t\tsqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c;\r\n\r\n\t\t\t\t\t\t} else {\r\n\r\n\t\t\t\t\t\t\t// region 1\r\n\r\n\t\t\t\t\t\t\ts1 = segExtent;\r\n\t\t\t\t\t\t\ts0 = Math.max( 0, - ( a01 * s1 + b0 ) );\r\n\t\t\t\t\t\t\tsqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t} else {\r\n\r\n\t\t\t\t\t\t// region 5\r\n\r\n\t\t\t\t\t\ts1 = - segExtent;\r\n\t\t\t\t\t\ts0 = Math.max( 0, - ( a01 * s1 + b0 ) );\r\n\t\t\t\t\t\tsqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\tif ( s1 <= - extDet ) {\r\n\r\n\t\t\t\t\t\t// region 4\r\n\r\n\t\t\t\t\t\ts0 = Math.max( 0, - ( - a01 * segExtent + b0 ) );\r\n\t\t\t\t\t\ts1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );\r\n\t\t\t\t\t\tsqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;\r\n\r\n\t\t\t\t\t} else if ( s1 <= extDet ) {\r\n\r\n\t\t\t\t\t\t// region 3\r\n\r\n\t\t\t\t\t\ts0 = 0;\r\n\t\t\t\t\t\ts1 = Math.min( Math.max( - segExtent, - b1 ), segExtent );\r\n\t\t\t\t\t\tsqrDist = s1 * ( s1 + 2 * b1 ) + c;\r\n\r\n\t\t\t\t\t} else {\r\n\r\n\t\t\t\t\t\t// region 2\r\n\r\n\t\t\t\t\t\ts0 = Math.max( 0, - ( a01 * segExtent + b0 ) );\r\n\t\t\t\t\t\ts1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );\r\n\t\t\t\t\t\tsqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\t// Ray and segment are parallel.\r\n\r\n\t\t\t\ts1 = ( a01 > 0 ) ? - segExtent : segExtent;\r\n\t\t\t\ts0 = Math.max( 0, - ( a01 * s1 + b0 ) );\r\n\t\t\t\tsqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( optionalPointOnRay ) {\r\n\r\n\t\t\t\toptionalPointOnRay.copy( this.direction ).multiplyScalar( s0 ).add( this.origin );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( optionalPointOnSegment ) {\r\n\r\n\t\t\t\toptionalPointOnSegment.copy( segDir ).multiplyScalar( s1 ).add( segCenter );\r\n\r\n\t\t\t}\r\n\r\n\t\t\treturn sqrDist;\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\r\n\tisIntersectionSphere: function ( sphere ) {\r\n\r\n\t\treturn this.distanceToPoint( sphere.center ) <= sphere.radius;\r\n\r\n\t},\r\n\r\n\tintersectSphere: function () {\r\n\r\n\t\t// from http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-sphere-intersection/\r\n\r\n\t\tvar v1 = new THREE.Vector3();\r\n\r\n\t\treturn function ( sphere, optionalTarget ) {\r\n\r\n\t\t\tv1.subVectors( sphere.center, this.origin );\r\n\r\n\t\t\tvar tca = v1.dot( this.direction );\r\n\r\n\t\t\tvar d2 = v1.dot( v1 ) - tca * tca;\r\n\r\n\t\t\tvar radius2 = sphere.radius * sphere.radius;\r\n\r\n\t\t\tif ( d2 > radius2 ) return null;\r\n\r\n\t\t\tvar thc = Math.sqrt( radius2 - d2 );\r\n\r\n\t\t\t// t0 = first intersect point - entrance on front of sphere\r\n\t\t\tvar t0 = tca - thc;\r\n\r\n\t\t\t// t1 = second intersect point - exit point on back of sphere\r\n\t\t\tvar t1 = tca + thc;\r\n\r\n\t\t\t// test to see if both t0 and t1 are behind the ray - if so, return null\r\n\t\t\tif ( t0 < 0 && t1 < 0 ) return null;\r\n\r\n\t\t\t// test to see if t0 is behind the ray:\r\n\t\t\t// if it is, the ray is inside the sphere, so return the second exit point scaled by t1,\r\n\t\t\t// in order to always return an intersect point that is in front of the ray.\r\n\t\t\tif ( t0 < 0 ) return this.at( t1, optionalTarget );\r\n\r\n\t\t\t// else t0 is in front of the ray, so return the first collision point scaled by t0 \r\n\t\t\treturn this.at( t0, optionalTarget );\r\n\r\n\t\t}\r\n\r\n\t}(),\r\n\r\n\tisIntersectionPlane: function ( plane ) {\r\n\r\n\t\t// check if the ray lies on the plane first\r\n\r\n\t\tvar distToPoint = plane.distanceToPoint( this.origin );\r\n\r\n\t\tif ( distToPoint === 0 ) {\r\n\r\n\t\t\treturn true;\r\n\r\n\t\t}\r\n\r\n\t\tvar denominator = plane.normal.dot( this.direction );\r\n\r\n\t\tif ( denominator * distToPoint < 0 ) {\r\n\r\n\t\t\treturn true;\r\n\r\n\t\t}\r\n\r\n\t\t// ray origin is behind the plane (and is pointing behind it)\r\n\r\n\t\treturn false;\r\n\r\n\t},\r\n\r\n\tdistanceToPlane: function ( plane ) {\r\n\r\n\t\tvar denominator = plane.normal.dot( this.direction );\r\n\t\tif ( denominator == 0 ) {\r\n\r\n\t\t\t// line is coplanar, return origin\r\n\t\t\tif ( plane.distanceToPoint( this.origin ) == 0 ) {\r\n\r\n\t\t\t\treturn 0;\r\n\r\n\t\t\t}\r\n\r\n\t\t\t// Null is preferable to undefined since undefined means.... it is undefined\r\n\r\n\t\t\treturn null;\r\n\r\n\t\t}\r\n\r\n\t\tvar t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator;\r\n\r\n\t\t// Return if the ray never intersects the plane\r\n\r\n\t\treturn t >= 0 ? t : null;\r\n\r\n\t},\r\n\r\n\tintersectPlane: function ( plane, optionalTarget ) {\r\n\r\n\t\tvar t = this.distanceToPlane( plane );\r\n\r\n\t\tif ( t === null ) {\r\n\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\treturn this.at( t, optionalTarget );\r\n\r\n\t},\r\n\r\n\tisIntersectionBox: function () {\r\n\r\n\t\tvar v = new THREE.Vector3();\r\n\r\n\t\treturn function ( box ) {\r\n\r\n\t\t\treturn this.intersectBox( box, v ) !== null;\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\tintersectBox: function ( box, optionalTarget ) {\r\n\r\n\t\t// http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-box-intersection/\r\n\r\n\t\tvar tmin,tmax,tymin,tymax,tzmin,tzmax;\r\n\r\n\t\tvar invdirx = 1 / this.direction.x,\r\n\t\t\tinvdiry = 1 / this.direction.y,\r\n\t\t\tinvdirz = 1 / this.direction.z;\r\n\r\n\t\tvar origin = this.origin;\r\n\r\n\t\tif ( invdirx >= 0 ) {\r\n\r\n\t\t\ttmin = ( box.min.x - origin.x ) * invdirx;\r\n\t\t\ttmax = ( box.max.x - origin.x ) * invdirx;\r\n\r\n\t\t} else {\r\n\r\n\t\t\ttmin = ( box.max.x - origin.x ) * invdirx;\r\n\t\t\ttmax = ( box.min.x - origin.x ) * invdirx;\r\n\t\t}\r\n\r\n\t\tif ( invdiry >= 0 ) {\r\n\r\n\t\t\ttymin = ( box.min.y - origin.y ) * invdiry;\r\n\t\t\ttymax = ( box.max.y - origin.y ) * invdiry;\r\n\r\n\t\t} else {\r\n\r\n\t\t\ttymin = ( box.max.y - origin.y ) * invdiry;\r\n\t\t\ttymax = ( box.min.y - origin.y ) * invdiry;\r\n\t\t}\r\n\r\n\t\tif ( ( tmin > tymax ) || ( tymin > tmax ) ) return null;\r\n\r\n\t\t// These lines also handle the case where tmin or tmax is NaN\r\n\t\t// (result of 0 * Infinity). x !== x returns true if x is NaN\r\n\r\n\t\tif ( tymin > tmin || tmin !== tmin ) tmin = tymin;\r\n\r\n\t\tif ( tymax < tmax || tmax !== tmax ) tmax = tymax;\r\n\r\n\t\tif ( invdirz >= 0 ) {\r\n\r\n\t\t\ttzmin = ( box.min.z - origin.z ) * invdirz;\r\n\t\t\ttzmax = ( box.max.z - origin.z ) * invdirz;\r\n\r\n\t\t} else {\r\n\r\n\t\t\ttzmin = ( box.max.z - origin.z ) * invdirz;\r\n\t\t\ttzmax = ( box.min.z - origin.z ) * invdirz;\r\n\t\t}\r\n\r\n\t\tif ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null;\r\n\r\n\t\tif ( tzmin > tmin || tmin !== tmin ) tmin = tzmin;\r\n\r\n\t\tif ( tzmax < tmax || tmax !== tmax ) tmax = tzmax;\r\n\r\n\t\t//return point closest to the ray (positive side)\r\n\r\n\t\tif ( tmax < 0 ) return null;\r\n\r\n\t\treturn this.at( tmin >= 0 ? tmin : tmax, optionalTarget );\r\n\r\n\t},\r\n\r\n\tintersectTriangle: function () {\r\n\r\n\t\t// Compute the offset origin, edges, and normal.\r\n\t\tvar diff = new THREE.Vector3();\r\n\t\tvar edge1 = new THREE.Vector3();\r\n\t\tvar edge2 = new THREE.Vector3();\r\n\t\tvar normal = new THREE.Vector3();\r\n\r\n\t\treturn function ( a, b, c, backfaceCulling, optionalTarget ) {\r\n\r\n\t\t\t// from http://www.geometrictools.com/LibMathematics/Intersection/Wm5IntrRay3Triangle3.cpp\r\n\r\n\t\t\tedge1.subVectors( b, a );\r\n\t\t\tedge2.subVectors( c, a );\r\n\t\t\tnormal.crossVectors( edge1, edge2 );\r\n\r\n\t\t\t// Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,\r\n\t\t\t// E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by\r\n\t\t\t// |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))\r\n\t\t\t// |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))\r\n\t\t\t// |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)\r\n\t\t\tvar DdN = this.direction.dot( normal );\r\n\t\t\tvar sign;\r\n\r\n\t\t\tif ( DdN > 0 ) {\r\n\r\n\t\t\t\tif ( backfaceCulling ) return null;\r\n\t\t\t\tsign = 1;\r\n\r\n\t\t\t} else if ( DdN < 0 ) {\r\n\r\n\t\t\t\tsign = - 1;\r\n\t\t\t\tDdN = - DdN;\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\treturn null;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tdiff.subVectors( this.origin, a );\r\n\t\t\tvar DdQxE2 = sign * this.direction.dot( edge2.crossVectors( diff, edge2 ) );\r\n\r\n\t\t\t// b1 < 0, no intersection\r\n\t\t\tif ( DdQxE2 < 0 ) {\r\n\r\n\t\t\t\treturn null;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tvar DdE1xQ = sign * this.direction.dot( edge1.cross( diff ) );\r\n\r\n\t\t\t// b2 < 0, no intersection\r\n\t\t\tif ( DdE1xQ < 0 ) {\r\n\r\n\t\t\t\treturn null;\r\n\r\n\t\t\t}\r\n\r\n\t\t\t// b1+b2 > 1, no intersection\r\n\t\t\tif ( DdQxE2 + DdE1xQ > DdN ) {\r\n\r\n\t\t\t\treturn null;\r\n\r\n\t\t\t}\r\n\r\n\t\t\t// Line intersects triangle, check if ray does.\r\n\t\t\tvar QdN = - sign * diff.dot( normal );\r\n\r\n\t\t\t// t < 0, no intersection\r\n\t\t\tif ( QdN < 0 ) {\r\n\r\n\t\t\t\treturn null;\r\n\r\n\t\t\t}\r\n\r\n\t\t\t// Ray intersects triangle.\r\n\t\t\treturn this.at( QdN / DdN, optionalTarget );\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\tapplyMatrix4: function ( matrix4 ) {\r\n\r\n\t\tthis.direction.add( this.origin ).applyMatrix4( matrix4 );\r\n\t\tthis.origin.applyMatrix4( matrix4 );\r\n\t\tthis.direction.sub( this.origin );\r\n\t\tthis.direction.normalize();\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\tequals: function ( ray ) {\r\n\r\n\t\treturn ray.origin.equals( this.origin ) && ray.direction.equals( this.direction );\r\n\r\n\t},\r\n\r\n\tclone: function () {\r\n\r\n\t\treturn new THREE.Ray().copy( this );\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/math/Sphere.js\r\n\r\n/**\r\n * @author bhouston / http://exocortex.com\r\n * @author mrdoob / http://mrdoob.com/\r\n */\r\n\r\nTHREE.Sphere = function ( center, radius ) {\r\n\r\n\tthis.center = ( center !== undefined ) ? center : new THREE.Vector3();\r\n\tthis.radius = ( radius !== undefined ) ? radius : 0;\r\n\r\n};\r\n\r\nTHREE.Sphere.prototype = {\r\n\r\n\tconstructor: THREE.Sphere,\r\n\r\n\tset: function ( center, radius ) {\r\n\r\n\t\tthis.center.copy( center );\r\n\t\tthis.radius = radius;\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\tsetFromPoints: function () {\r\n\r\n\t\tvar box = new THREE.Box3();\r\n\r\n\t\treturn function ( points, optionalCenter ) {\r\n\r\n\t\t\tvar center = this.center;\r\n\r\n\t\t\tif ( optionalCenter !== undefined ) {\r\n\r\n\t\t\t\tcenter.copy( optionalCenter );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tbox.setFromPoints( points ).center( center );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tvar maxRadiusSq = 0;\r\n\r\n\t\t\tfor ( var i = 0, il = points.length; i < il; i ++ ) {\r\n\r\n\t\t\t\tmaxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tthis.radius = Math.sqrt( maxRadiusSq );\r\n\r\n\t\t\treturn this;\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\tcopy: function ( sphere ) {\r\n\r\n\t\tthis.center.copy( sphere.center );\r\n\t\tthis.radius = sphere.radius;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tempty: function () {\r\n\r\n\t\treturn ( this.radius <= 0 );\r\n\r\n\t},\r\n\r\n\tcontainsPoint: function ( point ) {\r\n\r\n\t\treturn ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) );\r\n\r\n\t},\r\n\r\n\tdistanceToPoint: function ( point ) {\r\n\r\n\t\treturn ( point.distanceTo( this.center ) - this.radius );\r\n\r\n\t},\r\n\r\n\tintersectsSphere: function ( sphere ) {\r\n\r\n\t\tvar radiusSum = this.radius + sphere.radius;\r\n\r\n\t\treturn sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum );\r\n\r\n\t},\r\n\r\n\tclampPoint: function ( point, optionalTarget ) {\r\n\r\n\t\tvar deltaLengthSq = this.center.distanceToSquared( point );\r\n\r\n\t\tvar result = optionalTarget || new THREE.Vector3();\r\n\t\tresult.copy( point );\r\n\r\n\t\tif ( deltaLengthSq > ( this.radius * this.radius ) ) {\r\n\r\n\t\t\tresult.sub( this.center ).normalize();\r\n\t\t\tresult.multiplyScalar( this.radius ).add( this.center );\r\n\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\r\n\t},\r\n\r\n\tgetBoundingBox: function ( optionalTarget ) {\r\n\r\n\t\tvar box = optionalTarget || new THREE.Box3();\r\n\r\n\t\tbox.set( this.center, this.center );\r\n\t\tbox.expandByScalar( this.radius );\r\n\r\n\t\treturn box;\r\n\r\n\t},\r\n\r\n\tapplyMatrix4: function ( matrix ) {\r\n\r\n\t\tthis.center.applyMatrix4( matrix );\r\n\t\tthis.radius = this.radius * matrix.getMaxScaleOnAxis();\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\ttranslate: function ( offset ) {\r\n\r\n\t\tthis.center.add( offset );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tequals: function ( sphere ) {\r\n\r\n\t\treturn sphere.center.equals( this.center ) && ( sphere.radius === this.radius );\r\n\r\n\t},\r\n\r\n\tclone: function () {\r\n\r\n\t\treturn new THREE.Sphere().copy( this );\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/math/Frustum.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n * @author alteredq / http://alteredqualia.com/\r\n * @author bhouston / http://exocortex.com\r\n */\r\n\r\nTHREE.Frustum = function ( p0, p1, p2, p3, p4, p5 ) {\r\n\r\n\tthis.planes = [\r\n\r\n\t\t( p0 !== undefined ) ? p0 : new THREE.Plane(),\r\n\t\t( p1 !== undefined ) ? p1 : new THREE.Plane(),\r\n\t\t( p2 !== undefined ) ? p2 : new THREE.Plane(),\r\n\t\t( p3 !== undefined ) ? p3 : new THREE.Plane(),\r\n\t\t( p4 !== undefined ) ? p4 : new THREE.Plane(),\r\n\t\t( p5 !== undefined ) ? p5 : new THREE.Plane()\r\n\r\n\t];\r\n\r\n};\r\n\r\nTHREE.Frustum.prototype = {\r\n\r\n\tconstructor: THREE.Frustum,\r\n\r\n\tset: function ( p0, p1, p2, p3, p4, p5 ) {\r\n\r\n\t\tvar planes = this.planes;\r\n\r\n\t\tplanes[ 0 ].copy( p0 );\r\n\t\tplanes[ 1 ].copy( p1 );\r\n\t\tplanes[ 2 ].copy( p2 );\r\n\t\tplanes[ 3 ].copy( p3 );\r\n\t\tplanes[ 4 ].copy( p4 );\r\n\t\tplanes[ 5 ].copy( p5 );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tcopy: function ( frustum ) {\r\n\r\n\t\tvar planes = this.planes;\r\n\r\n\t\tfor ( var i = 0; i < 6; i ++ ) {\r\n\r\n\t\t\tplanes[ i ].copy( frustum.planes[ i ] );\r\n\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetFromMatrix: function ( m ) {\r\n\r\n\t\tvar planes = this.planes;\r\n\t\tvar me = m.elements;\r\n\t\tvar me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ];\r\n\t\tvar me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ];\r\n\t\tvar me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ];\r\n\t\tvar me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ];\r\n\r\n\t\tplanes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize();\r\n\t\tplanes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize();\r\n\t\tplanes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize();\r\n\t\tplanes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize();\r\n\t\tplanes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize();\r\n\t\tplanes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize();\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tintersectsObject: function () {\r\n\r\n\t\tvar sphere = new THREE.Sphere();\r\n\r\n\t\treturn function ( object ) {\r\n\r\n\t\t\tvar geometry = object.geometry;\r\n\r\n\t\t\tif ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();\r\n\r\n\t\t\tsphere.copy( geometry.boundingSphere );\r\n\t\t\tsphere.applyMatrix4( object.matrixWorld );\r\n\r\n\t\t\treturn this.intersectsSphere( sphere );\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\tintersectsSphere: function ( sphere ) {\r\n\r\n\t\tvar planes = this.planes;\r\n\t\tvar center = sphere.center;\r\n\t\tvar negRadius = - sphere.radius;\r\n\r\n\t\tfor ( var i = 0; i < 6; i ++ ) {\r\n\r\n\t\t\tvar distance = planes[ i ].distanceToPoint( center );\r\n\r\n\t\t\tif ( distance < negRadius ) {\r\n\r\n\t\t\t\treturn false;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\r\n\t},\r\n\r\n\tintersectsBox: function () {\r\n\r\n\t\tvar p1 = new THREE.Vector3(),\r\n\t\t\tp2 = new THREE.Vector3();\r\n\r\n\t\treturn function ( box ) {\r\n\r\n\t\t\tvar planes = this.planes;\r\n\r\n\t\t\tfor ( var i = 0; i < 6 ; i ++ ) {\r\n\r\n\t\t\t\tvar plane = planes[ i ];\r\n\r\n\t\t\t\tp1.x = plane.normal.x > 0 ? box.min.x : box.max.x;\r\n\t\t\t\tp2.x = plane.normal.x > 0 ? box.max.x : box.min.x;\r\n\t\t\t\tp1.y = plane.normal.y > 0 ? box.min.y : box.max.y;\r\n\t\t\t\tp2.y = plane.normal.y > 0 ? box.max.y : box.min.y;\r\n\t\t\t\tp1.z = plane.normal.z > 0 ? box.min.z : box.max.z;\r\n\t\t\t\tp2.z = plane.normal.z > 0 ? box.max.z : box.min.z;\r\n\r\n\t\t\t\tvar d1 = plane.distanceToPoint( p1 );\r\n\t\t\t\tvar d2 = plane.distanceToPoint( p2 );\r\n\r\n\t\t\t\t// if both outside plane, no intersection\r\n\r\n\t\t\t\tif ( d1 < 0 && d2 < 0 ) {\r\n\r\n\t\t\t\t\treturn false;\r\n\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn true;\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\r\n\tcontainsPoint: function ( point ) {\r\n\r\n\t\tvar planes = this.planes;\r\n\r\n\t\tfor ( var i = 0; i < 6; i ++ ) {\r\n\r\n\t\t\tif ( planes[ i ].distanceToPoint( point ) < 0 ) {\r\n\r\n\t\t\t\treturn false;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\r\n\t},\r\n\r\n\tclone: function () {\r\n\r\n\t\treturn new THREE.Frustum().copy( this );\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/math/Plane.js\r\n\r\n/**\r\n * @author bhouston / http://exocortex.com\r\n */\r\n\r\nTHREE.Plane = function ( normal, constant ) {\r\n\r\n\tthis.normal = ( normal !== undefined ) ? normal : new THREE.Vector3( 1, 0, 0 );\r\n\tthis.constant = ( constant !== undefined ) ? constant : 0;\r\n\r\n};\r\n\r\nTHREE.Plane.prototype = {\r\n\r\n\tconstructor: THREE.Plane,\r\n\r\n\tset: function ( normal, constant ) {\r\n\r\n\t\tthis.normal.copy( normal );\r\n\t\tthis.constant = constant;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetComponents: function ( x, y, z, w ) {\r\n\r\n\t\tthis.normal.set( x, y, z );\r\n\t\tthis.constant = w;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetFromNormalAndCoplanarPoint: function ( normal, point ) {\r\n\r\n\t\tthis.normal.copy( normal );\r\n\t\tthis.constant = - point.dot( this.normal );\t// must be this.normal, not normal, as this.normal is normalized\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetFromCoplanarPoints: function () {\r\n\r\n\t\tvar v1 = new THREE.Vector3();\r\n\t\tvar v2 = new THREE.Vector3();\r\n\r\n\t\treturn function ( a, b, c ) {\r\n\r\n\t\t\tvar normal = v1.subVectors( c, b ).cross( v2.subVectors( a, b ) ).normalize();\r\n\r\n\t\t\t// Q: should an error be thrown if normal is zero (e.g. degenerate plane)?\r\n\r\n\t\t\tthis.setFromNormalAndCoplanarPoint( normal, a );\r\n\r\n\t\t\treturn this;\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\r\n\tcopy: function ( plane ) {\r\n\r\n\t\tthis.normal.copy( plane.normal );\r\n\t\tthis.constant = plane.constant;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tnormalize: function () {\r\n\r\n\t\t// Note: will lead to a divide by zero if the plane is invalid.\r\n\r\n\t\tvar inverseNormalLength = 1.0 / this.normal.length();\r\n\t\tthis.normal.multiplyScalar( inverseNormalLength );\r\n\t\tthis.constant *= inverseNormalLength;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tnegate: function () {\r\n\r\n\t\tthis.constant *= - 1;\r\n\t\tthis.normal.negate();\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tdistanceToPoint: function ( point ) {\r\n\r\n\t\treturn this.normal.dot( point ) + this.constant;\r\n\r\n\t},\r\n\r\n\tdistanceToSphere: function ( sphere ) {\r\n\r\n\t\treturn this.distanceToPoint( sphere.center ) - sphere.radius;\r\n\r\n\t},\r\n\r\n\tprojectPoint: function ( point, optionalTarget ) {\r\n\r\n\t\treturn this.orthoPoint( point, optionalTarget ).sub( point ).negate();\r\n\r\n\t},\r\n\r\n\torthoPoint: function ( point, optionalTarget ) {\r\n\r\n\t\tvar perpendicularMagnitude = this.distanceToPoint( point );\r\n\r\n\t\tvar result = optionalTarget || new THREE.Vector3();\r\n\t\treturn result.copy( this.normal ).multiplyScalar( perpendicularMagnitude );\r\n\r\n\t},\r\n\r\n\tisIntersectionLine: function ( line ) {\r\n\r\n\t\t// Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it.\r\n\r\n\t\tvar startSign = this.distanceToPoint( line.start );\r\n\t\tvar endSign = this.distanceToPoint( line.end );\r\n\r\n\t\treturn ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 );\r\n\r\n\t},\r\n\r\n\tintersectLine: function () {\r\n\r\n\t\tvar v1 = new THREE.Vector3();\r\n\r\n\t\treturn function ( line, optionalTarget ) {\r\n\r\n\t\t\tvar result = optionalTarget || new THREE.Vector3();\r\n\r\n\t\t\tvar direction = line.delta( v1 );\r\n\r\n\t\t\tvar denominator = this.normal.dot( direction );\r\n\r\n\t\t\tif ( denominator == 0 ) {\r\n\r\n\t\t\t\t// line is coplanar, return origin\r\n\t\t\t\tif ( this.distanceToPoint( line.start ) == 0 ) {\r\n\r\n\t\t\t\t\treturn result.copy( line.start );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Unsure if this is the correct method to handle this case.\r\n\t\t\t\treturn undefined;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tvar t = - ( line.start.dot( this.normal ) + this.constant ) / denominator;\r\n\r\n\t\t\tif ( t < 0 || t > 1 ) {\r\n\r\n\t\t\t\treturn undefined;\r\n\r\n\t\t\t}\r\n\r\n\t\t\treturn result.copy( direction ).multiplyScalar( t ).add( line.start );\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\r\n\tcoplanarPoint: function ( optionalTarget ) {\r\n\r\n\t\tvar result = optionalTarget || new THREE.Vector3();\r\n\t\treturn result.copy( this.normal ).multiplyScalar( - this.constant );\r\n\r\n\t},\r\n\r\n\tapplyMatrix4: function () {\r\n\r\n\t\tvar v1 = new THREE.Vector3();\r\n\t\tvar v2 = new THREE.Vector3();\r\n\t\tvar m1 = new THREE.Matrix3();\r\n\r\n\t\treturn function ( matrix, optionalNormalMatrix ) {\r\n\r\n\t\t\t// compute new normal based on theory here:\r\n\t\t\t// http://www.songho.ca/opengl/gl_normaltransform.html\r\n\t\t\tvar normalMatrix = optionalNormalMatrix || m1.getNormalMatrix( matrix );\r\n\t\t\tvar newNormal = v1.copy( this.normal ).applyMatrix3( normalMatrix );\r\n\r\n\t\t\tvar newCoplanarPoint = this.coplanarPoint( v2 );\r\n\t\t\tnewCoplanarPoint.applyMatrix4( matrix );\r\n\r\n\t\t\tthis.setFromNormalAndCoplanarPoint( newNormal, newCoplanarPoint );\r\n\r\n\t\t\treturn this;\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\ttranslate: function ( offset ) {\r\n\r\n\t\tthis.constant = this.constant - offset.dot( this.normal );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tequals: function ( plane ) {\r\n\r\n\t\treturn plane.normal.equals( this.normal ) && ( plane.constant == this.constant );\r\n\r\n\t},\r\n\r\n\tclone: function () {\r\n\r\n\t\treturn new THREE.Plane().copy( this );\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/math/Math.js\r\n\r\n/**\r\n * @author alteredq / http://alteredqualia.com/\r\n * @author mrdoob / http://mrdoob.com/\r\n */\r\n\r\nTHREE.Math = {\r\n\r\n\tgenerateUUID: function () {\r\n\r\n\t\t// http://www.broofa.com/Tools/Math.uuid.htm\r\n\r\n\t\tvar chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split( '' );\r\n\t\tvar uuid = new Array( 36 );\r\n\t\tvar rnd = 0, r;\r\n\r\n\t\treturn function () {\r\n\r\n\t\t\tfor ( var i = 0; i < 36; i ++ ) {\r\n\r\n\t\t\t\tif ( i == 8 || i == 13 || i == 18 || i == 23 ) {\r\n\r\n\t\t\t\t\tuuid[ i ] = '-';\r\n\r\n\t\t\t\t} else if ( i == 14 ) {\r\n\r\n\t\t\t\t\tuuid[ i ] = '4';\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\tif ( rnd <= 0x02 ) rnd = 0x2000000 + ( Math.random() * 0x1000000 ) | 0;\r\n\t\t\t\t\tr = rnd & 0xf;\r\n\t\t\t\t\trnd = rnd >> 4;\r\n\t\t\t\t\tuuid[ i ] = chars[ ( i == 19 ) ? ( r & 0x3 ) | 0x8 : r ];\r\n\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn uuid.join( '' );\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\t// Clamp value to range \r\n\r\n\tclamp: function ( x, a, b ) {\r\n\r\n\t\treturn ( x < a ) ? a : ( ( x > b ) ? b : x );\r\n\r\n\t},\r\n\r\n\t// Clamp value to range to range \r\n\r\n\tmapLinear: function ( x, a1, a2, b1, b2 ) {\r\n\r\n\t\treturn b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );\r\n\r\n\t},\r\n\r\n\t// http://en.wikipedia.org/wiki/Smoothstep\r\n\r\n\tsmoothstep: function ( x, min, max ) {\r\n\r\n\t\tif ( x <= min ) return 0;\r\n\t\tif ( x >= max ) return 1;\r\n\r\n\t\tx = ( x - min ) / ( max - min );\r\n\r\n\t\treturn x * x * ( 3 - 2 * x );\r\n\r\n\t},\r\n\r\n\tsmootherstep: function ( x, min, max ) {\r\n\r\n\t\tif ( x <= min ) return 0;\r\n\t\tif ( x >= max ) return 1;\r\n\r\n\t\tx = ( x - min ) / ( max - min );\r\n\r\n\t\treturn x * x * x * ( x * ( x * 6 - 15 ) + 10 );\r\n\r\n\t},\r\n\r\n\t// Random float from <0, 1> with 16 bits of randomness\r\n\t// (standard Math.random() creates repetitive patterns when applied over larger space)\r\n\r\n\trandom16: function () {\r\n\r\n\t\treturn ( 65280 * Math.random() + 255 * Math.random() ) / 65535;\r\n\r\n\t},\r\n\r\n\t// Random integer from interval\r\n\r\n\trandInt: function ( low, high ) {\r\n\r\n\t\treturn Math.floor( this.randFloat( low, high ) );\r\n\r\n\t},\r\n\r\n\t// Random float from interval\r\n\r\n\trandFloat: function ( low, high ) {\r\n\r\n\t\treturn low + Math.random() * ( high - low );\r\n\r\n\t},\r\n\r\n\t// Random float from <-range/2, range/2> interval\r\n\r\n\trandFloatSpread: function ( range ) {\r\n\r\n\t\treturn range * ( 0.5 - Math.random() );\r\n\r\n\t},\r\n\r\n\tdegToRad: function () {\r\n\r\n\t\tvar degreeToRadiansFactor = Math.PI / 180;\r\n\r\n\t\treturn function ( degrees ) {\r\n\r\n\t\t\treturn degrees * degreeToRadiansFactor;\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\tradToDeg: function () {\r\n\r\n\t\tvar radianToDegreesFactor = 180 / Math.PI;\r\n\r\n\t\treturn function ( radians ) {\r\n\r\n\t\t\treturn radians * radianToDegreesFactor;\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\tisPowerOfTwo: function ( value ) {\r\n\r\n\t\treturn ( value & ( value - 1 ) ) === 0 && value !== 0;\r\n\r\n\t},\r\n\r\n\tnextPowerOfTwo: function ( value ) {\r\n\r\n\t\tvalue --;\r\n\t\tvalue |= value >> 1;\r\n\t\tvalue |= value >> 2;\r\n\t\tvalue |= value >> 4;\r\n\t\tvalue |= value >> 8;\r\n\t\tvalue |= value >> 16;\r\n\t\tvalue ++;\r\n\r\n\t\treturn value;\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/math/Spline.js\r\n\r\n/**\r\n * Spline from Tween.js, slightly optimized (and trashed)\r\n * http://sole.github.com/tween.js/examples/05_spline.html\r\n *\r\n * @author mrdoob / http://mrdoob.com/\r\n * @author alteredq / http://alteredqualia.com/\r\n */\r\n\r\nTHREE.Spline = function ( points ) {\r\n\r\n\tthis.points = points;\r\n\r\n\tvar c = [], v3 = { x: 0, y: 0, z: 0 },\r\n\tpoint, intPoint, weight, w2, w3,\r\n\tpa, pb, pc, pd;\r\n\r\n\tthis.initFromArray = function ( a ) {\r\n\r\n\t\tthis.points = [];\r\n\r\n\t\tfor ( var i = 0; i < a.length; i ++ ) {\r\n\r\n\t\t\tthis.points[ i ] = { x: a[ i ][ 0 ], y: a[ i ][ 1 ], z: a[ i ][ 2 ] };\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n\tthis.getPoint = function ( k ) {\r\n\r\n\t\tpoint = ( this.points.length - 1 ) * k;\r\n\t\tintPoint = Math.floor( point );\r\n\t\tweight = point - intPoint;\r\n\r\n\t\tc[ 0 ] = intPoint === 0 ? intPoint : intPoint - 1;\r\n\t\tc[ 1 ] = intPoint;\r\n\t\tc[ 2 ] = intPoint > this.points.length - 2 ? this.points.length - 1 : intPoint + 1;\r\n\t\tc[ 3 ] = intPoint > this.points.length - 3 ? this.points.length - 1 : intPoint + 2;\r\n\r\n\t\tpa = this.points[ c[ 0 ] ];\r\n\t\tpb = this.points[ c[ 1 ] ];\r\n\t\tpc = this.points[ c[ 2 ] ];\r\n\t\tpd = this.points[ c[ 3 ] ];\r\n\r\n\t\tw2 = weight * weight;\r\n\t\tw3 = weight * w2;\r\n\r\n\t\tv3.x = interpolate( pa.x, pb.x, pc.x, pd.x, weight, w2, w3 );\r\n\t\tv3.y = interpolate( pa.y, pb.y, pc.y, pd.y, weight, w2, w3 );\r\n\t\tv3.z = interpolate( pa.z, pb.z, pc.z, pd.z, weight, w2, w3 );\r\n\r\n\t\treturn v3;\r\n\r\n\t};\r\n\r\n\tthis.getControlPointsArray = function () {\r\n\r\n\t\tvar i, p, l = this.points.length,\r\n\t\t\tcoords = [];\r\n\r\n\t\tfor ( i = 0; i < l; i ++ ) {\r\n\r\n\t\t\tp = this.points[ i ];\r\n\t\t\tcoords[ i ] = [ p.x, p.y, p.z ];\r\n\r\n\t\t}\r\n\r\n\t\treturn coords;\r\n\r\n\t};\r\n\r\n\t// approximate length by summing linear segments\r\n\r\n\tthis.getLength = function ( nSubDivisions ) {\r\n\r\n\t\tvar i, index, nSamples, position,\r\n\t\t\tpoint = 0, intPoint = 0, oldIntPoint = 0,\r\n\t\t\toldPosition = new THREE.Vector3(),\r\n\t\t\ttmpVec = new THREE.Vector3(),\r\n\t\t\tchunkLengths = [],\r\n\t\t\ttotalLength = 0;\r\n\r\n\t\t// first point has 0 length\r\n\r\n\t\tchunkLengths[ 0 ] = 0;\r\n\r\n\t\tif ( ! nSubDivisions ) nSubDivisions = 100;\r\n\r\n\t\tnSamples = this.points.length * nSubDivisions;\r\n\r\n\t\toldPosition.copy( this.points[ 0 ] );\r\n\r\n\t\tfor ( i = 1; i < nSamples; i ++ ) {\r\n\r\n\t\t\tindex = i / nSamples;\r\n\r\n\t\t\tposition = this.getPoint( index );\r\n\t\t\ttmpVec.copy( position );\r\n\r\n\t\t\ttotalLength += tmpVec.distanceTo( oldPosition );\r\n\r\n\t\t\toldPosition.copy( position );\r\n\r\n\t\t\tpoint = ( this.points.length - 1 ) * index;\r\n\t\t\tintPoint = Math.floor( point );\r\n\r\n\t\t\tif ( intPoint != oldIntPoint ) {\r\n\r\n\t\t\t\tchunkLengths[ intPoint ] = totalLength;\r\n\t\t\t\toldIntPoint = intPoint;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\t// last point ends with total length\r\n\r\n\t\tchunkLengths[ chunkLengths.length ] = totalLength;\r\n\r\n\t\treturn { chunks: chunkLengths, total: totalLength };\r\n\r\n\t};\r\n\r\n\tthis.reparametrizeByArcLength = function ( samplingCoef ) {\r\n\r\n\t\tvar i, j,\r\n\t\t\tindex, indexCurrent, indexNext,\r\n\t\t\trealDistance,\r\n\t\t\tsampling, position,\r\n\t\t\tnewpoints = [],\r\n\t\t\ttmpVec = new THREE.Vector3(),\r\n\t\t\tsl = this.getLength();\r\n\r\n\t\tnewpoints.push( tmpVec.copy( this.points[ 0 ] ).clone() );\r\n\r\n\t\tfor ( i = 1; i < this.points.length; i ++ ) {\r\n\r\n\t\t\t//tmpVec.copy( this.points[ i - 1 ] );\r\n\t\t\t//linearDistance = tmpVec.distanceTo( this.points[ i ] );\r\n\r\n\t\t\trealDistance = sl.chunks[ i ] - sl.chunks[ i - 1 ];\r\n\r\n\t\t\tsampling = Math.ceil( samplingCoef * realDistance / sl.total );\r\n\r\n\t\t\tindexCurrent = ( i - 1 ) / ( this.points.length - 1 );\r\n\t\t\tindexNext = i / ( this.points.length - 1 );\r\n\r\n\t\t\tfor ( j = 1; j < sampling - 1; j ++ ) {\r\n\r\n\t\t\t\tindex = indexCurrent + j * ( 1 / sampling ) * ( indexNext - indexCurrent );\r\n\r\n\t\t\t\tposition = this.getPoint( index );\r\n\t\t\t\tnewpoints.push( tmpVec.copy( position ).clone() );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tnewpoints.push( tmpVec.copy( this.points[ i ] ).clone() );\r\n\r\n\t\t}\r\n\r\n\t\tthis.points = newpoints;\r\n\r\n\t};\r\n\r\n\t// Catmull-Rom\r\n\r\n\tfunction interpolate( p0, p1, p2, p3, t, t2, t3 ) {\r\n\r\n\t\tvar v0 = ( p2 - p0 ) * 0.5,\r\n\t\t\tv1 = ( p3 - p1 ) * 0.5;\r\n\r\n\t\treturn ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1;\r\n\r\n\t};\r\n\r\n};\r\n\r\n// File:src/math/Triangle.js\r\n\r\n/**\r\n * @author bhouston / http://exocortex.com\r\n * @author mrdoob / http://mrdoob.com/\r\n */\r\n\r\nTHREE.Triangle = function ( a, b, c ) {\r\n\r\n\tthis.a = ( a !== undefined ) ? a : new THREE.Vector3();\r\n\tthis.b = ( b !== undefined ) ? b : new THREE.Vector3();\r\n\tthis.c = ( c !== undefined ) ? c : new THREE.Vector3();\r\n\r\n};\r\n\r\nTHREE.Triangle.normal = function () {\r\n\r\n\tvar v0 = new THREE.Vector3();\r\n\r\n\treturn function ( a, b, c, optionalTarget ) {\r\n\r\n\t\tvar result = optionalTarget || new THREE.Vector3();\r\n\r\n\t\tresult.subVectors( c, b );\r\n\t\tv0.subVectors( a, b );\r\n\t\tresult.cross( v0 );\r\n\r\n\t\tvar resultLengthSq = result.lengthSq();\r\n\t\tif ( resultLengthSq > 0 ) {\r\n\r\n\t\t\treturn result.multiplyScalar( 1 / Math.sqrt( resultLengthSq ) );\r\n\r\n\t\t}\r\n\r\n\t\treturn result.set( 0, 0, 0 );\r\n\r\n\t};\r\n\r\n}();\r\n\r\n// static/instance method to calculate barycoordinates\r\n// based on: http://www.blackpawn.com/texts/pointinpoly/default.html\r\nTHREE.Triangle.barycoordFromPoint = function () {\r\n\r\n\tvar v0 = new THREE.Vector3();\r\n\tvar v1 = new THREE.Vector3();\r\n\tvar v2 = new THREE.Vector3();\r\n\r\n\treturn function ( point, a, b, c, optionalTarget ) {\r\n\r\n\t\tv0.subVectors( c, a );\r\n\t\tv1.subVectors( b, a );\r\n\t\tv2.subVectors( point, a );\r\n\r\n\t\tvar dot00 = v0.dot( v0 );\r\n\t\tvar dot01 = v0.dot( v1 );\r\n\t\tvar dot02 = v0.dot( v2 );\r\n\t\tvar dot11 = v1.dot( v1 );\r\n\t\tvar dot12 = v1.dot( v2 );\r\n\r\n\t\tvar denom = ( dot00 * dot11 - dot01 * dot01 );\r\n\r\n\t\tvar result = optionalTarget || new THREE.Vector3();\r\n\r\n\t\t// colinear or singular triangle\r\n\t\tif ( denom == 0 ) {\r\n\t\t\t// arbitrary location outside of triangle?\r\n\t\t\t// not sure if this is the best idea, maybe should be returning undefined\r\n\t\t\treturn result.set( - 2, - 1, - 1 );\r\n\t\t}\r\n\r\n\t\tvar invDenom = 1 / denom;\r\n\t\tvar u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;\r\n\t\tvar v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;\r\n\r\n\t\t// barycoordinates must always sum to 1\r\n\t\treturn result.set( 1 - u - v, v, u );\r\n\r\n\t};\r\n\r\n}();\r\n\r\nTHREE.Triangle.containsPoint = function () {\r\n\r\n\tvar v1 = new THREE.Vector3();\r\n\r\n\treturn function ( point, a, b, c ) {\r\n\r\n\t\tvar result = THREE.Triangle.barycoordFromPoint( point, a, b, c, v1 );\r\n\r\n\t\treturn ( result.x >= 0 ) && ( result.y >= 0 ) && ( ( result.x + result.y ) <= 1 );\r\n\r\n\t};\r\n\r\n}();\r\n\r\nTHREE.Triangle.prototype = {\r\n\r\n\tconstructor: THREE.Triangle,\r\n\r\n\tset: function ( a, b, c ) {\r\n\r\n\t\tthis.a.copy( a );\r\n\t\tthis.b.copy( b );\r\n\t\tthis.c.copy( c );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetFromPointsAndIndices: function ( points, i0, i1, i2 ) {\r\n\r\n\t\tthis.a.copy( points[ i0 ] );\r\n\t\tthis.b.copy( points[ i1 ] );\r\n\t\tthis.c.copy( points[ i2 ] );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tcopy: function ( triangle ) {\r\n\r\n\t\tthis.a.copy( triangle.a );\r\n\t\tthis.b.copy( triangle.b );\r\n\t\tthis.c.copy( triangle.c );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tarea: function () {\r\n\r\n\t\tvar v0 = new THREE.Vector3();\r\n\t\tvar v1 = new THREE.Vector3();\r\n\r\n\t\treturn function () {\r\n\r\n\t\t\tv0.subVectors( this.c, this.b );\r\n\t\t\tv1.subVectors( this.a, this.b );\r\n\r\n\t\t\treturn v0.cross( v1 ).length() * 0.5;\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\tmidpoint: function ( optionalTarget ) {\r\n\r\n\t\tvar result = optionalTarget || new THREE.Vector3();\r\n\t\treturn result.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 );\r\n\r\n\t},\r\n\r\n\tnormal: function ( optionalTarget ) {\r\n\r\n\t\treturn THREE.Triangle.normal( this.a, this.b, this.c, optionalTarget );\r\n\r\n\t},\r\n\r\n\tplane: function ( optionalTarget ) {\r\n\r\n\t\tvar result = optionalTarget || new THREE.Plane();\r\n\r\n\t\treturn result.setFromCoplanarPoints( this.a, this.b, this.c );\r\n\r\n\t},\r\n\r\n\tbarycoordFromPoint: function ( point, optionalTarget ) {\r\n\r\n\t\treturn THREE.Triangle.barycoordFromPoint( point, this.a, this.b, this.c, optionalTarget );\r\n\r\n\t},\r\n\r\n\tcontainsPoint: function ( point ) {\r\n\r\n\t\treturn THREE.Triangle.containsPoint( point, this.a, this.b, this.c );\r\n\r\n\t},\r\n\r\n\tequals: function ( triangle ) {\r\n\r\n\t\treturn triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c );\r\n\r\n\t},\r\n\r\n\tclone: function () {\r\n\r\n\t\treturn new THREE.Triangle().copy( this );\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/core/Clock.js\r\n\r\n/**\r\n * @author alteredq / http://alteredqualia.com/\r\n */\r\n\r\nTHREE.Clock = function ( autoStart ) {\r\n\r\n\tthis.autoStart = ( autoStart !== undefined ) ? autoStart : true;\r\n\r\n\tthis.startTime = 0;\r\n\tthis.oldTime = 0;\r\n\tthis.elapsedTime = 0;\r\n\r\n\tthis.running = false;\r\n\r\n};\r\n\r\nTHREE.Clock.prototype = {\r\n\r\n\tconstructor: THREE.Clock,\r\n\r\n\tstart: function () {\r\n\r\n\t\tthis.startTime = self.performance !== undefined && self.performance.now !== undefined\r\n\t\t\t\t\t ? self.performance.now()\r\n\t\t\t\t\t : Date.now();\r\n\r\n\t\tthis.oldTime = this.startTime;\r\n\t\tthis.running = true;\r\n\t},\r\n\r\n\tstop: function () {\r\n\r\n\t\tthis.getElapsedTime();\r\n\t\tthis.running = false;\r\n\r\n\t},\r\n\r\n\tgetElapsedTime: function () {\r\n\r\n\t\tthis.getDelta();\r\n\t\treturn this.elapsedTime;\r\n\r\n\t},\r\n\r\n\tgetDelta: function () {\r\n\r\n\t\tvar diff = 0;\r\n\r\n\t\tif ( this.autoStart && ! this.running ) {\r\n\r\n\t\t\tthis.start();\r\n\r\n\t\t}\r\n\r\n\t\tif ( this.running ) {\r\n\r\n\t\t\tvar newTime = self.performance !== undefined && self.performance.now !== undefined\r\n\t\t\t\t\t ? self.performance.now()\r\n\t\t\t\t\t : Date.now();\r\n\r\n\t\t\tdiff = 0.001 * ( newTime - this.oldTime );\r\n\t\t\tthis.oldTime = newTime;\r\n\r\n\t\t\tthis.elapsedTime += diff;\r\n\r\n\t\t}\r\n\r\n\t\treturn diff;\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/core/EventDispatcher.js\r\n\r\n/**\r\n * https://github.com/mrdoob/eventdispatcher.js/\r\n */\r\n\r\nTHREE.EventDispatcher = function () {}\r\n\r\nTHREE.EventDispatcher.prototype = {\r\n\r\n\tconstructor: THREE.EventDispatcher,\r\n\r\n\tapply: function ( object ) {\r\n\r\n\t\tobject.addEventListener = THREE.EventDispatcher.prototype.addEventListener;\r\n\t\tobject.hasEventListener = THREE.EventDispatcher.prototype.hasEventListener;\r\n\t\tobject.removeEventListener = THREE.EventDispatcher.prototype.removeEventListener;\r\n\t\tobject.dispatchEvent = THREE.EventDispatcher.prototype.dispatchEvent;\r\n\r\n\t},\r\n\r\n\taddEventListener: function ( type, listener ) {\r\n\r\n\t\tif ( this._listeners === undefined ) this._listeners = {};\r\n\r\n\t\tvar listeners = this._listeners;\r\n\r\n\t\tif ( listeners[ type ] === undefined ) {\r\n\r\n\t\t\tlisteners[ type ] = [];\r\n\r\n\t\t}\r\n\r\n\t\tif ( listeners[ type ].indexOf( listener ) === - 1 ) {\r\n\r\n\t\t\tlisteners[ type ].push( listener );\r\n\r\n\t\t}\r\n\r\n\t},\r\n\r\n\thasEventListener: function ( type, listener ) {\r\n\r\n\t\tif ( this._listeners === undefined ) return false;\r\n\r\n\t\tvar listeners = this._listeners;\r\n\r\n\t\tif ( listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1 ) {\r\n\r\n\t\t\treturn true;\r\n\r\n\t\t}\r\n\r\n\t\treturn false;\r\n\r\n\t},\r\n\r\n\tremoveEventListener: function ( type, listener ) {\r\n\r\n\t\tif ( this._listeners === undefined ) return;\r\n\r\n\t\tvar listeners = this._listeners;\r\n\t\tvar listenerArray = listeners[ type ];\r\n\r\n\t\tif ( listenerArray !== undefined ) {\r\n\r\n\t\t\tvar index = listenerArray.indexOf( listener );\r\n\r\n\t\t\tif ( index !== - 1 ) {\r\n\r\n\t\t\t\tlistenerArray.splice( index, 1 );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t},\r\n\r\n\tdispatchEvent: function ( event ) {\r\n\r\n\t\tif ( this._listeners === undefined ) return;\r\n\r\n\t\tvar listeners = this._listeners;\r\n\t\tvar listenerArray = listeners[ event.type ];\r\n\r\n\t\tif ( listenerArray !== undefined ) {\r\n\r\n\t\t\tevent.target = this;\r\n\r\n\t\t\tvar array = [];\r\n\t\t\tvar length = listenerArray.length;\r\n\r\n\t\t\tfor ( var i = 0; i < length; i ++ ) {\r\n\r\n\t\t\t\tarray[ i ] = listenerArray[ i ];\r\n\r\n\t\t\t}\r\n\r\n\t\t\tfor ( var i = 0; i < length; i ++ ) {\r\n\r\n\t\t\t\tarray[ i ].call( this, event );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/core/Raycaster.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n * @author bhouston / http://exocortex.com/\r\n * @author stephomi / http://stephaneginier.com/\r\n */\r\n\r\n( function ( THREE ) {\r\n\r\n\tTHREE.Raycaster = function ( origin, direction, near, far ) {\r\n\r\n\t\tthis.ray = new THREE.Ray( origin, direction );\r\n\t\t// direction is assumed to be normalized (for accurate distance calculations)\r\n\r\n\t\tthis.near = near || 0;\r\n\t\tthis.far = far || Infinity;\r\n\r\n\t\tthis.params = {\r\n\t\t\tSprite: {},\r\n\t\t\tMesh: {},\r\n\t\t\tPointCloud: { threshold: 1 },\r\n\t\t\tLOD: {},\r\n\t\t\tLine: {}\r\n\t\t};\r\n\r\n\t};\r\n\r\n\tvar descSort = function ( a, b ) {\r\n\r\n\t\treturn a.distance - b.distance;\r\n\r\n\t};\r\n\r\n\tvar intersectObject = function ( object, raycaster, intersects, recursive ) {\r\n\r\n\t\tobject.raycast( raycaster, intersects );\r\n\r\n\t\tif ( recursive === true ) {\r\n\r\n\t\t\tvar children = object.children;\r\n\r\n\t\t\tfor ( var i = 0, l = children.length; i < l; i ++ ) {\r\n\r\n\t\t\t\tintersectObject( children[ i ], raycaster, intersects, true );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n\t//\r\n\r\n\tTHREE.Raycaster.prototype = {\r\n\r\n\t\tconstructor: THREE.Raycaster,\r\n\r\n\t\tprecision: 0.0001,\r\n\t\tlinePrecision: 1,\r\n\r\n\t\tset: function ( origin, direction ) {\r\n\r\n\t\t\t// direction is assumed to be normalized (for accurate distance calculations)\r\n\r\n\t\t\tthis.ray.set( origin, direction );\r\n\r\n\t\t},\r\n\r\n\t\tsetFromCamera: function ( coords, camera ) {\r\n\r\n\t\t\t// camera is assumed _not_ to be a child of a transformed object\r\n\r\n\t\t\tif ( camera instanceof THREE.PerspectiveCamera ) {\r\n\r\n\t\t\t\tthis.ray.origin.copy( camera.position );\r\n\t\t\t\tthis.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( camera.position ).normalize();\r\n\r\n\t\t\t} else if ( camera instanceof THREE.OrthographicCamera ) {\r\n\r\n\t\t\t\tthis.ray.origin.set( coords.x, coords.y, - 1 ).unproject( camera );\r\n\t\t\t\tthis.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tTHREE.error( 'THREE.Raycaster: Unsupported camera type.' );\r\n\r\n\t\t\t}\r\n\r\n\t\t},\r\n\r\n\t\tintersectObject: function ( object, recursive ) {\r\n\r\n\t\t\tvar intersects = [];\r\n\r\n\t\t\tintersectObject( object, this, intersects, recursive );\r\n\r\n\t\t\tintersects.sort( descSort );\r\n\r\n\t\t\treturn intersects;\r\n\r\n\t\t},\r\n\r\n\t\tintersectObjects: function ( objects, recursive ) {\r\n\r\n\t\t\tvar intersects = [];\r\n\r\n\t\t\tif ( objects instanceof Array === false ) {\r\n\r\n\t\t\t\tTHREE.warn( 'THREE.Raycaster.intersectObjects: objects is not an Array.' );\r\n\t\t\t\treturn intersects;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tfor ( var i = 0, l = objects.length; i < l; i ++ ) {\r\n\r\n\t\t\t\tintersectObject( objects[ i ], this, intersects, recursive );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tintersects.sort( descSort );\r\n\r\n\t\t\treturn intersects;\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n}( THREE ) );\r\n\r\n// File:src/core/Object3D.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n * @author mikael emtinger / http://gomo.se/\r\n * @author alteredq / http://alteredqualia.com/\r\n * @author WestLangley / http://github.com/WestLangley\r\n */\r\n\r\nTHREE.Object3D = function () {\r\n\r\n\tObject.defineProperty( this, 'id', { value: THREE.Object3DIdCount ++ } );\r\n\r\n\tthis.uuid = THREE.Math.generateUUID();\r\n\r\n\tthis.name = '';\r\n\tthis.type = 'Object3D';\r\n\r\n\tthis.parent = undefined;\r\n\tthis.children = [];\r\n\r\n\tthis.up = THREE.Object3D.DefaultUp.clone();\r\n\r\n\tvar position = new THREE.Vector3();\r\n\tvar rotation = new THREE.Euler();\r\n\tvar quaternion = new THREE.Quaternion();\r\n\tvar scale = new THREE.Vector3( 1, 1, 1 );\r\n\r\n\tvar onRotationChange = function () {\r\n\t\tquaternion.setFromEuler( rotation, false );\r\n\t};\r\n\r\n\tvar onQuaternionChange = function () {\r\n\t\trotation.setFromQuaternion( quaternion, undefined, false );\r\n\t};\r\n\r\n\trotation.onChange( onRotationChange );\r\n\tquaternion.onChange( onQuaternionChange );\r\n\r\n\tObject.defineProperties( this, {\r\n\t\tposition: {\r\n\t\t\tenumerable: true,\r\n\t\t\tvalue: position\r\n\t\t},\r\n\t\trotation: {\r\n\t\t\tenumerable: true,\r\n\t\t\tvalue: rotation\r\n\t\t},\r\n\t\tquaternion: {\r\n\t\t\tenumerable: true,\r\n\t\t\tvalue: quaternion\r\n\t\t},\r\n\t\tscale: {\r\n\t\t\tenumerable: true,\r\n\t\t\tvalue: scale\r\n\t\t}\r\n\t} );\r\n\r\n\tthis.rotationAutoUpdate = true;\r\n\r\n\tthis.matrix = new THREE.Matrix4();\r\n\tthis.matrixWorld = new THREE.Matrix4();\r\n\r\n\tthis.matrixAutoUpdate = true;\r\n\tthis.matrixWorldNeedsUpdate = false;\r\n\r\n\tthis.visible = true;\r\n\r\n\tthis.castShadow = false;\r\n\tthis.receiveShadow = false;\r\n\r\n\tthis.frustumCulled = true;\r\n\tthis.renderOrder = 0;\r\n\r\n\tthis.userData = {};\r\n\r\n};\r\n\r\nTHREE.Object3D.DefaultUp = new THREE.Vector3( 0, 1, 0 );\r\n\r\nTHREE.Object3D.prototype = {\r\n\r\n\tconstructor: THREE.Object3D,\r\n\r\n\tget eulerOrder () {\r\n\r\n\t\tTHREE.warn( 'THREE.Object3D: .eulerOrder has been moved to .rotation.order.' );\r\n\r\n\t\treturn this.rotation.order;\r\n\r\n\t},\r\n\r\n\tset eulerOrder ( value ) {\r\n\r\n\t\tTHREE.warn( 'THREE.Object3D: .eulerOrder has been moved to .rotation.order.' );\r\n\r\n\t\tthis.rotation.order = value;\r\n\r\n\t},\r\n\r\n\tget useQuaternion () {\r\n\r\n\t\tTHREE.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' );\r\n\r\n\t},\r\n\r\n\tset useQuaternion ( value ) {\r\n\r\n\t\tTHREE.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' );\r\n\r\n\t},\r\n\r\n\tapplyMatrix: function ( matrix ) {\r\n\r\n\t\tthis.matrix.multiplyMatrices( matrix, this.matrix );\r\n\r\n\t\tthis.matrix.decompose( this.position, this.quaternion, this.scale );\r\n\r\n\t},\r\n\r\n\tsetRotationFromAxisAngle: function ( axis, angle ) {\r\n\r\n\t\t// assumes axis is normalized\r\n\r\n\t\tthis.quaternion.setFromAxisAngle( axis, angle );\r\n\r\n\t},\r\n\r\n\tsetRotationFromEuler: function ( euler ) {\r\n\r\n\t\tthis.quaternion.setFromEuler( euler, true );\r\n\r\n\t},\r\n\r\n\tsetRotationFromMatrix: function ( m ) {\r\n\r\n\t\t// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)\r\n\r\n\t\tthis.quaternion.setFromRotationMatrix( m );\r\n\r\n\t},\r\n\r\n\tsetRotationFromQuaternion: function ( q ) {\r\n\r\n\t\t// assumes q is normalized\r\n\r\n\t\tthis.quaternion.copy( q );\r\n\r\n\t},\r\n\r\n\trotateOnAxis: function () {\r\n\r\n\t\t// rotate object on axis in object space\r\n\t\t// axis is assumed to be normalized\r\n\r\n\t\tvar q1 = new THREE.Quaternion();\r\n\r\n\t\treturn function ( axis, angle ) {\r\n\r\n\t\t\tq1.setFromAxisAngle( axis, angle );\r\n\r\n\t\t\tthis.quaternion.multiply( q1 );\r\n\r\n\t\t\treturn this;\r\n\r\n\t\t}\r\n\r\n\t}(),\r\n\r\n\trotateX: function () {\r\n\r\n\t\tvar v1 = new THREE.Vector3( 1, 0, 0 );\r\n\r\n\t\treturn function ( angle ) {\r\n\r\n\t\t\treturn this.rotateOnAxis( v1, angle );\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\trotateY: function () {\r\n\r\n\t\tvar v1 = new THREE.Vector3( 0, 1, 0 );\r\n\r\n\t\treturn function ( angle ) {\r\n\r\n\t\t\treturn this.rotateOnAxis( v1, angle );\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\trotateZ: function () {\r\n\r\n\t\tvar v1 = new THREE.Vector3( 0, 0, 1 );\r\n\r\n\t\treturn function ( angle ) {\r\n\r\n\t\t\treturn this.rotateOnAxis( v1, angle );\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\ttranslateOnAxis: function () {\r\n\r\n\t\t// translate object by distance along axis in object space\r\n\t\t// axis is assumed to be normalized\r\n\r\n\t\tvar v1 = new THREE.Vector3();\r\n\r\n\t\treturn function ( axis, distance ) {\r\n\r\n\t\t\tv1.copy( axis ).applyQuaternion( this.quaternion );\r\n\r\n\t\t\tthis.position.add( v1.multiplyScalar( distance ) );\r\n\r\n\t\t\treturn this;\r\n\r\n\t\t}\r\n\r\n\t}(),\r\n\r\n\ttranslate: function ( distance, axis ) {\r\n\r\n\t\tTHREE.warn( 'THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.' );\r\n\t\treturn this.translateOnAxis( axis, distance );\r\n\r\n\t},\r\n\r\n\ttranslateX: function () {\r\n\r\n\t\tvar v1 = new THREE.Vector3( 1, 0, 0 );\r\n\r\n\t\treturn function ( distance ) {\r\n\r\n\t\t\treturn this.translateOnAxis( v1, distance );\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\ttranslateY: function () {\r\n\r\n\t\tvar v1 = new THREE.Vector3( 0, 1, 0 );\r\n\r\n\t\treturn function ( distance ) {\r\n\r\n\t\t\treturn this.translateOnAxis( v1, distance );\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\ttranslateZ: function () {\r\n\r\n\t\tvar v1 = new THREE.Vector3( 0, 0, 1 );\r\n\r\n\t\treturn function ( distance ) {\r\n\r\n\t\t\treturn this.translateOnAxis( v1, distance );\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\tlocalToWorld: function ( vector ) {\r\n\r\n\t\treturn vector.applyMatrix4( this.matrixWorld );\r\n\r\n\t},\r\n\r\n\tworldToLocal: function () {\r\n\r\n\t\tvar m1 = new THREE.Matrix4();\r\n\r\n\t\treturn function ( vector ) {\r\n\r\n\t\t\treturn vector.applyMatrix4( m1.getInverse( this.matrixWorld ) );\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\tlookAt: function () {\r\n\r\n\t\t// This routine does not support objects with rotated and/or translated parent(s)\r\n\r\n\t\tvar m1 = new THREE.Matrix4();\r\n\r\n\t\treturn function ( vector ) {\r\n\r\n\t\t\tm1.lookAt( vector, this.position, this.up );\r\n\r\n\t\t\tthis.quaternion.setFromRotationMatrix( m1 );\r\n\r\n\t\t};\r\n\r\n\t}(),\r\n\r\n\tadd: function ( object ) {\r\n\r\n\t\tif ( arguments.length > 1 ) {\r\n\r\n\t\t\tfor ( var i = 0; i < arguments.length; i ++ ) {\r\n\r\n\t\t\t\tthis.add( arguments[ i ] );\r\n\r\n\t\t\t}\r\n\r\n\t\t\treturn this;\r\n\r\n\t\t};\r\n\r\n\t\tif ( object === this ) {\r\n\r\n\t\t\tTHREE.error( \"THREE.Object3D.add: object can't be added as a child of itself.\", object );\r\n\t\t\treturn this;\r\n\r\n\t\t}\r\n\r\n\t\tif ( object instanceof THREE.Object3D ) {\r\n\r\n\t\t\tif ( object.parent !== undefined ) {\r\n\r\n\t\t\t\tobject.parent.remove( object );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tobject.parent = this;\r\n\t\t\tobject.dispatchEvent( { type: 'added' } );\r\n\r\n\t\t\tthis.children.push( object );\r\n\r\n\t\t} else {\r\n\r\n\t\t\tTHREE.error( \"THREE.Object3D.add: object not an instance of THREE.Object3D.\", object );\r\n\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tremove: function ( object ) {\r\n\r\n\t\tif ( arguments.length > 1 ) {\r\n\r\n\t\t\tfor ( var i = 0; i < arguments.length; i ++ ) {\r\n\r\n\t\t\t\tthis.remove( arguments[ i ] );\r\n\r\n\t\t\t}\r\n\r\n\t\t};\r\n\r\n\t\tvar index = this.children.indexOf( object );\r\n\r\n\t\tif ( index !== - 1 ) {\r\n\r\n\t\t\tobject.parent = undefined;\r\n\r\n\t\t\tobject.dispatchEvent( { type: 'removed' } );\r\n\r\n\t\t\tthis.children.splice( index, 1 );\r\n\r\n\t\t}\r\n\r\n\t},\r\n\r\n\tgetChildByName: function ( name ) {\r\n\r\n\t\tTHREE.warn( 'THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().' );\r\n\t\treturn this.getObjectByName( name );\r\n\r\n\t},\r\n\r\n\tgetObjectById: function ( id ) {\r\n\r\n\t\treturn this.getObjectByProperty( 'id', id );\r\n\r\n\t},\r\n\r\n\tgetObjectByName: function ( name ) {\r\n\r\n\t\treturn this.getObjectByProperty( 'name', name );\r\n\r\n\t},\r\n\r\n\tgetObjectByProperty: function ( name, value ) {\r\n\r\n\t\tif ( this[ name ] === value ) return this;\r\n\r\n\t\tfor ( var i = 0, l = this.children.length; i < l; i ++ ) {\r\n\r\n\t\t\tvar child = this.children[ i ];\r\n\t\t\tvar object = child.getObjectByProperty( name, value );\r\n\r\n\t\t\tif ( object !== undefined ) {\r\n\r\n\t\t\t\treturn object;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\treturn undefined;\r\n\r\n\t},\r\n\r\n\tgetWorldPosition: function ( optionalTarget ) {\r\n\r\n\t\tvar result = optionalTarget || new THREE.Vector3();\r\n\r\n\t\tthis.updateMatrixWorld( true );\r\n\r\n\t\treturn result.setFromMatrixPosition( this.matrixWorld );\r\n\r\n\t},\r\n\r\n\tgetWorldQuaternion: function () {\r\n\r\n\t\tvar position = new THREE.Vector3();\r\n\t\tvar scale = new THREE.Vector3();\r\n\r\n\t\treturn function ( optionalTarget ) {\r\n\r\n\t\t\tvar result = optionalTarget || new THREE.Quaternion();\r\n\r\n\t\t\tthis.updateMatrixWorld( true );\r\n\r\n\t\t\tthis.matrixWorld.decompose( position, result, scale );\r\n\r\n\t\t\treturn result;\r\n\r\n\t\t}\r\n\r\n\t}(),\r\n\r\n\tgetWorldRotation: function () {\r\n\r\n\t\tvar quaternion = new THREE.Quaternion();\r\n\r\n\t\treturn function ( optionalTarget ) {\r\n\r\n\t\t\tvar result = optionalTarget || new THREE.Euler();\r\n\r\n\t\t\tthis.getWorldQuaternion( quaternion );\r\n\r\n\t\t\treturn result.setFromQuaternion( quaternion, this.rotation.order, false );\r\n\r\n\t\t}\r\n\r\n\t}(),\r\n\r\n\tgetWorldScale: function () {\r\n\r\n\t\tvar position = new THREE.Vector3();\r\n\t\tvar quaternion = new THREE.Quaternion();\r\n\r\n\t\treturn function ( optionalTarget ) {\r\n\r\n\t\t\tvar result = optionalTarget || new THREE.Vector3();\r\n\r\n\t\t\tthis.updateMatrixWorld( true );\r\n\r\n\t\t\tthis.matrixWorld.decompose( position, quaternion, result );\r\n\r\n\t\t\treturn result;\r\n\r\n\t\t}\r\n\r\n\t}(),\r\n\r\n\tgetWorldDirection: function () {\r\n\r\n\t\tvar quaternion = new THREE.Quaternion();\r\n\r\n\t\treturn function ( optionalTarget ) {\r\n\r\n\t\t\tvar result = optionalTarget || new THREE.Vector3();\r\n\r\n\t\t\tthis.getWorldQuaternion( quaternion );\r\n\r\n\t\t\treturn result.set( 0, 0, 1 ).applyQuaternion( quaternion );\r\n\r\n\t\t}\r\n\r\n\t}(),\r\n\r\n\traycast: function () {},\r\n\r\n\ttraverse: function ( callback ) {\r\n\r\n\t\tcallback( this );\r\n\r\n\t\tfor ( var i = 0, l = this.children.length; i < l; i ++ ) {\r\n\r\n\t\t\tthis.children[ i ].traverse( callback );\r\n\r\n\t\t}\r\n\r\n\t},\r\n\r\n\ttraverseVisible: function ( callback ) {\r\n\r\n\t\tif ( this.visible === false ) return;\r\n\r\n\t\tcallback( this );\r\n\r\n\t\tfor ( var i = 0, l = this.children.length; i < l; i ++ ) {\r\n\r\n\t\t\tthis.children[ i ].traverseVisible( callback );\r\n\r\n\t\t}\r\n\r\n\t},\r\n\r\n\ttraverseAncestors: function ( callback ) {\r\n\r\n\t\tif ( this.parent ) {\r\n\r\n\t\t\tcallback( this.parent );\r\n\r\n\t\t\tthis.parent.traverseAncestors( callback );\r\n\r\n\t\t}\r\n\r\n\t},\r\n\r\n\tupdateMatrix: function () {\r\n\r\n\t\tthis.matrix.compose( this.position, this.quaternion, this.scale );\r\n\r\n\t\tthis.matrixWorldNeedsUpdate = true;\r\n\r\n\t},\r\n\r\n\tupdateMatrixWorld: function ( force ) {\r\n\r\n\t\tif ( this.matrixAutoUpdate === true ) this.updateMatrix();\r\n\r\n\t\tif ( this.matrixWorldNeedsUpdate === true || force === true ) {\r\n\r\n\t\t\tif ( this.parent === undefined ) {\r\n\r\n\t\t\t\tthis.matrixWorld.copy( this.matrix );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tthis.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tthis.matrixWorldNeedsUpdate = false;\r\n\r\n\t\t\tforce = true;\r\n\r\n\t\t}\r\n\r\n\t\t// update children\r\n\r\n\t\tfor ( var i = 0, l = this.children.length; i < l; i ++ ) {\r\n\r\n\t\t\tthis.children[ i ].updateMatrixWorld( force );\r\n\r\n\t\t}\r\n\r\n\t},\r\n\r\n\ttoJSON: function () {\r\n\r\n\t\tvar output = {\r\n\t\t\tmetadata: {\r\n\t\t\t\tversion: 4.3,\r\n\t\t\t\ttype: 'Object',\r\n\t\t\t\tgenerator: 'ObjectExporter'\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\t//\r\n\r\n\t\tvar geometries = {};\r\n\r\n\t\tvar parseGeometry = function ( geometry ) {\r\n\r\n\t\t\tif ( output.geometries === undefined ) {\r\n\r\n\t\t\t\toutput.geometries = [];\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( geometries[ geometry.uuid ] === undefined ) {\r\n\r\n\t\t\t\tvar json = geometry.toJSON();\r\n\r\n\t\t\t\tdelete json.metadata;\r\n\r\n\t\t\t\tgeometries[ geometry.uuid ] = json;\r\n\r\n\t\t\t\toutput.geometries.push( json );\r\n\r\n\t\t\t}\r\n\r\n\t\t\treturn geometry.uuid;\r\n\r\n\t\t};\r\n\r\n\t\t//\r\n\r\n\t\tvar materials = {};\r\n\r\n\t\tvar parseMaterial = function ( material ) {\r\n\r\n\t\t\tif ( output.materials === undefined ) {\r\n\r\n\t\t\t\toutput.materials = [];\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( materials[ material.uuid ] === undefined ) {\r\n\r\n\t\t\t\tvar json = material.toJSON();\r\n\r\n\t\t\t\tdelete json.metadata;\r\n\r\n\t\t\t\tmaterials[ material.uuid ] = json;\r\n\r\n\t\t\t\toutput.materials.push( json );\r\n\r\n\t\t\t}\r\n\r\n\t\t\treturn material.uuid;\r\n\r\n\t\t};\r\n\r\n\t\t//\r\n\r\n\t\tvar parseObject = function ( object ) {\r\n\r\n\t\t\tvar data = {};\r\n\r\n\t\t\tdata.uuid = object.uuid;\r\n\t\t\tdata.type = object.type;\r\n\r\n\t\t\tif ( object.name !== '' ) data.name = object.name;\r\n\t\t\tif ( JSON.stringify( object.userData ) !== '{}' ) data.userData = object.userData;\r\n\t\t\tif ( object.visible !== true ) data.visible = object.visible;\r\n\r\n\t\t\tif ( object instanceof THREE.PerspectiveCamera ) {\r\n\r\n\t\t\t\tdata.fov = object.fov;\r\n\t\t\t\tdata.aspect = object.aspect;\r\n\t\t\t\tdata.near = object.near;\r\n\t\t\t\tdata.far = object.far;\r\n\r\n\t\t\t} else if ( object instanceof THREE.OrthographicCamera ) {\r\n\r\n\t\t\t\tdata.left = object.left;\r\n\t\t\t\tdata.right = object.right;\r\n\t\t\t\tdata.top = object.top;\r\n\t\t\t\tdata.bottom = object.bottom;\r\n\t\t\t\tdata.near = object.near;\r\n\t\t\t\tdata.far = object.far;\r\n\r\n\t\t\t} else if ( object instanceof THREE.AmbientLight ) {\r\n\r\n\t\t\t\tdata.color = object.color.getHex();\r\n\r\n\t\t\t} else if ( object instanceof THREE.DirectionalLight ) {\r\n\r\n\t\t\t\tdata.color = object.color.getHex();\r\n\t\t\t\tdata.intensity = object.intensity;\r\n\r\n\t\t\t} else if ( object instanceof THREE.PointLight ) {\r\n\r\n\t\t\t\tdata.color = object.color.getHex();\r\n\t\t\t\tdata.intensity = object.intensity;\r\n\t\t\t\tdata.distance = object.distance;\r\n\t\t\t\tdata.decay = object.decay;\r\n\r\n\t\t\t} else if ( object instanceof THREE.SpotLight ) {\r\n\r\n\t\t\t\tdata.color = object.color.getHex();\r\n\t\t\t\tdata.intensity = object.intensity;\r\n\t\t\t\tdata.distance = object.distance;\r\n\t\t\t\tdata.angle = object.angle;\r\n\t\t\t\tdata.exponent = object.exponent;\r\n\t\t\t\tdata.decay = object.decay;\r\n\r\n\t\t\t} else if ( object instanceof THREE.HemisphereLight ) {\r\n\r\n\t\t\t\tdata.color = object.color.getHex();\r\n\t\t\t\tdata.groundColor = object.groundColor.getHex();\r\n\r\n\t\t\t} else if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.PointCloud ) {\r\n\r\n\t\t\t\tdata.geometry = parseGeometry( object.geometry );\r\n\t\t\t\tdata.material = parseMaterial( object.material );\r\n\r\n\t\t\t\tif ( object instanceof THREE.Line ) data.mode = object.mode;\r\n\r\n\t\t\t} else if ( object instanceof THREE.Sprite ) {\r\n\r\n\t\t\t\tdata.material = parseMaterial( object.material );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tdata.matrix = object.matrix.toArray();\r\n\r\n\t\t\tif ( object.children.length > 0 ) {\r\n\r\n\t\t\t\tdata.children = [];\r\n\r\n\t\t\t\tfor ( var i = 0; i < object.children.length; i ++ ) {\r\n\r\n\t\t\t\t\tdata.children.push( parseObject( object.children[ i ] ) );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\treturn data;\r\n\r\n\t\t}\r\n\r\n\t\toutput.object = parseObject( this );\r\n\r\n\t\treturn output;\r\n\r\n\t},\r\n\r\n\tclone: function ( object, recursive ) {\r\n\r\n\t\tif ( object === undefined ) object = new THREE.Object3D();\r\n\t\tif ( recursive === undefined ) recursive = true;\r\n\r\n\t\tobject.name = this.name;\r\n\r\n\t\tobject.up.copy( this.up );\r\n\r\n\t\tobject.position.copy( this.position );\r\n\t\tobject.quaternion.copy( this.quaternion );\r\n\t\tobject.scale.copy( this.scale );\r\n\r\n\t\tobject.rotationAutoUpdate = this.rotationAutoUpdate;\r\n\r\n\t\tobject.matrix.copy( this.matrix );\r\n\t\tobject.matrixWorld.copy( this.matrixWorld );\r\n\r\n\t\tobject.matrixAutoUpdate = this.matrixAutoUpdate;\r\n\t\tobject.matrixWorldNeedsUpdate = this.matrixWorldNeedsUpdate;\r\n\r\n\t\tobject.visible = this.visible;\r\n\r\n\t\tobject.castShadow = this.castShadow;\r\n\t\tobject.receiveShadow = this.receiveShadow;\r\n\r\n\t\tobject.frustumCulled = this.frustumCulled;\r\n\r\n\t\tobject.userData = JSON.parse( JSON.stringify( this.userData ) );\r\n\r\n\t\tif ( recursive === true ) {\r\n\r\n\t\t\tfor ( var i = 0; i < this.children.length; i ++ ) {\r\n\r\n\t\t\t\tvar child = this.children[ i ];\r\n\t\t\t\tobject.add( child.clone() );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\treturn object;\r\n\r\n\t}\r\n\r\n};\r\n\r\nTHREE.EventDispatcher.prototype.apply( THREE.Object3D.prototype );\r\n\r\nTHREE.Object3DIdCount = 0;\r\n\r\n// File:src/core/Face3.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n * @author alteredq / http://alteredqualia.com/\r\n */\r\n\r\nTHREE.Face3 = function ( a, b, c, normal, color, materialIndex ) {\r\n\r\n\tthis.a = a;\r\n\tthis.b = b;\r\n\tthis.c = c;\r\n\r\n\tthis.normal = normal instanceof THREE.Vector3 ? normal : new THREE.Vector3();\r\n\tthis.vertexNormals = normal instanceof Array ? normal : [];\r\n\r\n\tthis.color = color instanceof THREE.Color ? color : new THREE.Color();\r\n\tthis.vertexColors = color instanceof Array ? color : [];\r\n\r\n\tthis.vertexTangents = [];\r\n\r\n\tthis.materialIndex = materialIndex !== undefined ? materialIndex : 0;\r\n\r\n};\r\n\r\nTHREE.Face3.prototype = {\r\n\r\n\tconstructor: THREE.Face3,\r\n\r\n\tclone: function () {\r\n\r\n\t\tvar face = new THREE.Face3( this.a, this.b, this.c );\r\n\r\n\t\tface.normal.copy( this.normal );\r\n\t\tface.color.copy( this.color );\r\n\r\n\t\tface.materialIndex = this.materialIndex;\r\n\r\n\t\tfor ( var i = 0, il = this.vertexNormals.length; i < il; i ++ ) {\r\n\r\n\t\t\tface.vertexNormals[ i ] = this.vertexNormals[ i ].clone();\r\n\r\n\t\t}\r\n\r\n\t\tfor ( var i = 0, il = this.vertexColors.length; i < il; i ++ ) {\r\n\r\n\t\t\tface.vertexColors[ i ] = this.vertexColors[ i ].clone();\r\n\r\n\t\t}\r\n\r\n\t\tfor ( var i = 0, il = this.vertexTangents.length; i < il; i ++ ) {\r\n\r\n\t\t\tface.vertexTangents[ i ] = this.vertexTangents[ i ].clone();\r\n\r\n\t\t}\r\n\r\n\t\treturn face;\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/core/Face4.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n */\r\n\r\nTHREE.Face4 = function ( a, b, c, d, normal, color, materialIndex ) {\r\n\r\n\tTHREE.warn( 'THREE.Face4 has been removed. A THREE.Face3 will be created instead.' )\r\n\treturn new THREE.Face3( a, b, c, normal, color, materialIndex );\r\n\r\n};\r\n\r\n// File:src/core/BufferAttribute.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n */\r\n\r\nTHREE.BufferAttribute = function ( array, itemSize ) {\r\n\r\n\tthis.array = array;\r\n\tthis.itemSize = itemSize;\r\n\r\n\tthis.needsUpdate = false;\r\n\r\n};\r\n\r\nTHREE.BufferAttribute.prototype = {\r\n\r\n\tconstructor: THREE.BufferAttribute,\r\n\r\n\tget length () {\r\n\r\n\t\treturn this.array.length;\r\n\r\n\t},\r\n\r\n\tcopyAt: function ( index1, attribute, index2 ) {\r\n\r\n\t\tindex1 *= this.itemSize;\r\n\t\tindex2 *= attribute.itemSize;\r\n\r\n\t\tfor ( var i = 0, l = this.itemSize; i < l; i ++ ) {\r\n\r\n\t\t\tthis.array[ index1 + i ] = attribute.array[ index2 + i ];\r\n\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tset: function ( value, offset ) {\r\n\r\n\t\tif ( offset === undefined ) offset = 0;\r\n\r\n\t\tthis.array.set( value, offset );\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetX: function ( index, x ) {\r\n\r\n\t\tthis.array[ index * this.itemSize ] = x;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetY: function ( index, y ) {\r\n\r\n\t\tthis.array[ index * this.itemSize + 1 ] = y;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetZ: function ( index, z ) {\r\n\r\n\t\tthis.array[ index * this.itemSize + 2 ] = z;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetXY: function ( index, x, y ) {\r\n\r\n\t\tindex *= this.itemSize;\r\n\r\n\t\tthis.array[ index ] = x;\r\n\t\tthis.array[ index + 1 ] = y;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetXYZ: function ( index, x, y, z ) {\r\n\r\n\t\tindex *= this.itemSize;\r\n\r\n\t\tthis.array[ index ] = x;\r\n\t\tthis.array[ index + 1 ] = y;\r\n\t\tthis.array[ index + 2 ] = z;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tsetXYZW: function ( index, x, y, z, w ) {\r\n\r\n\t\tindex *= this.itemSize;\r\n\r\n\t\tthis.array[ index ] = x;\r\n\t\tthis.array[ index + 1 ] = y;\r\n\t\tthis.array[ index + 2 ] = z;\r\n\t\tthis.array[ index + 3 ] = w;\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tclone: function () {\r\n\r\n\t\treturn new THREE.BufferAttribute( new this.array.constructor( this.array ), this.itemSize );\r\n\r\n\t}\r\n\r\n};\r\n\r\n//\r\n\r\nTHREE.Int8Attribute = function ( data, itemSize ) {\r\n\r\n\tTHREE.warn( 'THREE.Int8Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );\r\n\treturn new THREE.BufferAttribute( data, itemSize );\r\n\r\n};\r\n\r\nTHREE.Uint8Attribute = function ( data, itemSize ) {\r\n\r\n\tTHREE.warn( 'THREE.Uint8Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );\r\n\treturn new THREE.BufferAttribute( data, itemSize );\r\n\r\n};\r\n\r\nTHREE.Uint8ClampedAttribute = function ( data, itemSize ) {\r\n\r\n\tTHREE.warn( 'THREE.Uint8ClampedAttribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );\r\n\treturn new THREE.BufferAttribute( data, itemSize );\r\n\r\n\r\n};\r\n\r\nTHREE.Int16Attribute = function ( data, itemSize ) {\r\n\r\n\tTHREE.warn( 'THREE.Int16Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );\r\n\treturn new THREE.BufferAttribute( data, itemSize );\r\n\r\n};\r\n\r\nTHREE.Uint16Attribute = function ( data, itemSize ) {\r\n\r\n\tTHREE.warn( 'THREE.Uint16Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );\r\n\treturn new THREE.BufferAttribute( data, itemSize );\r\n\r\n};\r\n\r\nTHREE.Int32Attribute = function ( data, itemSize ) {\r\n\r\n\tTHREE.warn( 'THREE.Int32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );\r\n\treturn new THREE.BufferAttribute( data, itemSize );\r\n\r\n};\r\n\r\nTHREE.Uint32Attribute = function ( data, itemSize ) {\r\n\r\n\tTHREE.warn( 'THREE.Uint32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );\r\n\treturn new THREE.BufferAttribute( data, itemSize );\r\n\r\n};\r\n\r\nTHREE.Float32Attribute = function ( data, itemSize ) {\r\n\r\n\tTHREE.warn( 'THREE.Float32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );\r\n\treturn new THREE.BufferAttribute( data, itemSize );\r\n\r\n};\r\n\r\nTHREE.Float64Attribute = function ( data, itemSize ) {\r\n\r\n\tTHREE.warn( 'THREE.Float64Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );\r\n\treturn new THREE.BufferAttribute( data, itemSize );\r\n\r\n};\r\n\r\n// File:src/core/DynamicBufferAttribute.js\r\n\r\n/**\r\n * @author benaadams / https://twitter.com/ben_a_adams\r\n * @author mrdoob / http://mrdoob.com/\r\n */\r\n\r\nTHREE.DynamicBufferAttribute = function ( array, itemSize ) {\r\n\r\n\tTHREE.BufferAttribute.call( this, array, itemSize );\r\n\r\n\tthis.updateRange = { offset: 0, count: -1 };\r\n\r\n};\r\n\r\nTHREE.DynamicBufferAttribute.prototype = Object.create( THREE.BufferAttribute.prototype );\r\nTHREE.DynamicBufferAttribute.prototype.constructor = THREE.DynamicBufferAttribute;\r\n\r\nTHREE.DynamicBufferAttribute.prototype.clone = function () {\r\n\r\n\treturn new THREE.DynamicBufferAttribute( new this.array.constructor( this.array ), this.itemSize );\r\n\r\n};\r\n\r\n// File:src/core/BufferGeometry.js\r\n\r\n/**\r\n * @author alteredq / http://alteredqualia.com/\r\n * @author mrdoob / http://mrdoob.com/\r\n */\r\n\r\nTHREE.BufferGeometry = function () {\r\n\r\n\tObject.defineProperty( this, 'id', { value: THREE.GeometryIdCount ++ } );\r\n\r\n\tthis.uuid = THREE.Math.generateUUID();\r\n\r\n\tthis.name = '';\r\n\tthis.type = 'BufferGeometry';\r\n\r\n\tthis.attributes = {};\r\n\tthis.attributesKeys = [];\r\n\r\n\tthis.drawcalls = [];\r\n\tthis.offsets = this.drawcalls; // backwards compatibility\r\n\r\n\tthis.boundingBox = null;\r\n\tthis.boundingSphere = null;\r\n\r\n};\r\n\r\nTHREE.BufferGeometry.prototype = {\r\n\r\n\tconstructor: THREE.BufferGeometry,\r\n\r\n\taddAttribute: function ( name, attribute ) {\r\n\r\n\t\tif ( attribute instanceof THREE.BufferAttribute === false ) {\r\n\r\n\t\t\tTHREE.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' );\r\n\r\n\t\t\tthis.attributes[ name ] = { array: arguments[ 1 ], itemSize: arguments[ 2 ] };\r\n\r\n\t\t\treturn;\r\n\r\n\t\t}\r\n\r\n\t\tthis.attributes[ name ] = attribute;\r\n\t\tthis.attributesKeys = Object.keys( this.attributes );\r\n\r\n\t},\r\n\r\n\tgetAttribute: function ( name ) {\r\n\r\n\t\treturn this.attributes[ name ];\r\n\r\n\t},\r\n\r\n\taddDrawCall: function ( start, count, indexOffset ) {\r\n\r\n\t\tthis.drawcalls.push( {\r\n\r\n\t\t\tstart: start,\r\n\t\t\tcount: count,\r\n\t\t\tindex: indexOffset !== undefined ? indexOffset : 0\r\n\r\n\t\t} );\r\n\r\n\t},\r\n\r\n\tapplyMatrix: function ( matrix ) {\r\n\r\n\t\tvar position = this.attributes.position;\r\n\r\n\t\tif ( position !== undefined ) {\r\n\r\n\t\t\tmatrix.applyToVector3Array( position.array );\r\n\t\t\tposition.needsUpdate = true;\r\n\r\n\t\t}\r\n\r\n\t\tvar normal = this.attributes.normal;\r\n\r\n\t\tif ( normal !== undefined ) {\r\n\r\n\t\t\tvar normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix );\r\n\r\n\t\t\tnormalMatrix.applyToVector3Array( normal.array );\r\n\t\t\tnormal.needsUpdate = true;\r\n\r\n\t\t}\r\n\r\n\t\tif ( this.boundingBox !== null ) {\r\n\r\n\t\t\tthis.computeBoundingBox();\r\n\r\n\t\t}\r\n\r\n\t\tif ( this.boundingSphere !== null ) {\r\n\r\n\t\t\tthis.computeBoundingSphere();\r\n\r\n\t\t}\r\n\r\n\t},\r\n\r\n\tcenter: function () {\r\n\r\n\t\tthis.computeBoundingBox();\r\n\r\n\t\tvar offset = this.boundingBox.center().negate();\r\n\r\n\t\tthis.applyMatrix( new THREE.Matrix4().setPosition( offset ) );\r\n\r\n\t\treturn offset;\r\n\r\n\t},\r\n\r\n\tfromGeometry: function ( geometry, settings ) {\r\n\r\n\t\tsettings = settings || { 'vertexColors': THREE.NoColors };\r\n\r\n\t\tvar vertices = geometry.vertices;\r\n\t\tvar faces = geometry.faces;\r\n\t\tvar faceVertexUvs = geometry.faceVertexUvs;\r\n\t\tvar vertexColors = settings.vertexColors;\r\n\t\tvar hasFaceVertexUv = faceVertexUvs[ 0 ].length > 0;\r\n\t\tvar hasFaceVertexNormals = faces[ 0 ].vertexNormals.length == 3;\r\n\r\n\t\tvar positions = new Float32Array( faces.length * 3 * 3 );\r\n\t\tthis.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );\r\n\r\n\t\tvar normals = new Float32Array( faces.length * 3 * 3 );\r\n\t\tthis.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) );\r\n\r\n\t\tif ( vertexColors !== THREE.NoColors ) {\r\n\r\n\t\t\tvar colors = new Float32Array( faces.length * 3 * 3 );\r\n\t\t\tthis.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) );\r\n\r\n\t\t}\r\n\r\n\t\tif ( hasFaceVertexUv === true ) {\r\n\r\n\t\t\tvar uvs = new Float32Array( faces.length * 3 * 2 );\r\n\t\t\tthis.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) );\r\n\r\n\t\t}\r\n\r\n\t\tfor ( var i = 0, i2 = 0, i3 = 0; i < faces.length; i ++, i2 += 6, i3 += 9 ) {\r\n\r\n\t\t\tvar face = faces[ i ];\r\n\r\n\t\t\tvar a = vertices[ face.a ];\r\n\t\t\tvar b = vertices[ face.b ];\r\n\t\t\tvar c = vertices[ face.c ];\r\n\r\n\t\t\tpositions[ i3 ] = a.x;\r\n\t\t\tpositions[ i3 + 1 ] = a.y;\r\n\t\t\tpositions[ i3 + 2 ] = a.z;\r\n\r\n\t\t\tpositions[ i3 + 3 ] = b.x;\r\n\t\t\tpositions[ i3 + 4 ] = b.y;\r\n\t\t\tpositions[ i3 + 5 ] = b.z;\r\n\r\n\t\t\tpositions[ i3 + 6 ] = c.x;\r\n\t\t\tpositions[ i3 + 7 ] = c.y;\r\n\t\t\tpositions[ i3 + 8 ] = c.z;\r\n\r\n\t\t\tif ( hasFaceVertexNormals === true ) {\r\n\r\n\t\t\t\tvar na = face.vertexNormals[ 0 ];\r\n\t\t\t\tvar nb = face.vertexNormals[ 1 ];\r\n\t\t\t\tvar nc = face.vertexNormals[ 2 ];\r\n\r\n\t\t\t\tnormals[ i3 ] = na.x;\r\n\t\t\t\tnormals[ i3 + 1 ] = na.y;\r\n\t\t\t\tnormals[ i3 + 2 ] = na.z;\r\n\r\n\t\t\t\tnormals[ i3 + 3 ] = nb.x;\r\n\t\t\t\tnormals[ i3 + 4 ] = nb.y;\r\n\t\t\t\tnormals[ i3 + 5 ] = nb.z;\r\n\r\n\t\t\t\tnormals[ i3 + 6 ] = nc.x;\r\n\t\t\t\tnormals[ i3 + 7 ] = nc.y;\r\n\t\t\t\tnormals[ i3 + 8 ] = nc.z;\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tvar n = face.normal;\r\n\r\n\t\t\t\tnormals[ i3 ] = n.x;\r\n\t\t\t\tnormals[ i3 + 1 ] = n.y;\r\n\t\t\t\tnormals[ i3 + 2 ] = n.z;\r\n\r\n\t\t\t\tnormals[ i3 + 3 ] = n.x;\r\n\t\t\t\tnormals[ i3 + 4 ] = n.y;\r\n\t\t\t\tnormals[ i3 + 5 ] = n.z;\r\n\r\n\t\t\t\tnormals[ i3 + 6 ] = n.x;\r\n\t\t\t\tnormals[ i3 + 7 ] = n.y;\r\n\t\t\t\tnormals[ i3 + 8 ] = n.z;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( vertexColors === THREE.FaceColors ) {\r\n\r\n\t\t\t\tvar fc = face.color;\r\n\r\n\t\t\t\tcolors[ i3 ] = fc.r;\r\n\t\t\t\tcolors[ i3 + 1 ] = fc.g;\r\n\t\t\t\tcolors[ i3 + 2 ] = fc.b;\r\n\r\n\t\t\t\tcolors[ i3 + 3 ] = fc.r;\r\n\t\t\t\tcolors[ i3 + 4 ] = fc.g;\r\n\t\t\t\tcolors[ i3 + 5 ] = fc.b;\r\n\r\n\t\t\t\tcolors[ i3 + 6 ] = fc.r;\r\n\t\t\t\tcolors[ i3 + 7 ] = fc.g;\r\n\t\t\t\tcolors[ i3 + 8 ] = fc.b;\r\n\r\n\t\t\t} else if ( vertexColors === THREE.VertexColors ) {\r\n\r\n\t\t\t\tvar vca = face.vertexColors[ 0 ];\r\n\t\t\t\tvar vcb = face.vertexColors[ 1 ];\r\n\t\t\t\tvar vcc = face.vertexColors[ 2 ];\r\n\r\n\t\t\t\tcolors[ i3 ] = vca.r;\r\n\t\t\t\tcolors[ i3 + 1 ] = vca.g;\r\n\t\t\t\tcolors[ i3 + 2 ] = vca.b;\r\n\r\n\t\t\t\tcolors[ i3 + 3 ] = vcb.r;\r\n\t\t\t\tcolors[ i3 + 4 ] = vcb.g;\r\n\t\t\t\tcolors[ i3 + 5 ] = vcb.b;\r\n\r\n\t\t\t\tcolors[ i3 + 6 ] = vcc.r;\r\n\t\t\t\tcolors[ i3 + 7 ] = vcc.g;\r\n\t\t\t\tcolors[ i3 + 8 ] = vcc.b;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( hasFaceVertexUv === true ) {\r\n\r\n\t\t\t\tvar uva = faceVertexUvs[ 0 ][ i ][ 0 ];\r\n\t\t\t\tvar uvb = faceVertexUvs[ 0 ][ i ][ 1 ];\r\n\t\t\t\tvar uvc = faceVertexUvs[ 0 ][ i ][ 2 ];\r\n\r\n\t\t\t\tuvs[ i2 ] = uva.x;\r\n\t\t\t\tuvs[ i2 + 1 ] = uva.y;\r\n\r\n\t\t\t\tuvs[ i2 + 2 ] = uvb.x;\r\n\t\t\t\tuvs[ i2 + 3 ] = uvb.y;\r\n\r\n\t\t\t\tuvs[ i2 + 4 ] = uvc.x;\r\n\t\t\t\tuvs[ i2 + 5 ] = uvc.y;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tthis.computeBoundingSphere()\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tcomputeBoundingBox: function () {\r\n\r\n\t\tvar vector = new THREE.Vector3();\r\n\r\n\t\treturn function () {\r\n\r\n\t\t\tif ( this.boundingBox === null ) {\r\n\r\n\t\t\t\tthis.boundingBox = new THREE.Box3();\r\n\r\n\t\t\t}\r\n\r\n\t\t\tvar positions = this.attributes.position.array;\r\n\r\n\t\t\tif ( positions ) {\r\n\r\n\t\t\t\tvar bb = this.boundingBox;\r\n\t\t\t\tbb.makeEmpty();\r\n\r\n\t\t\t\tfor ( var i = 0, il = positions.length; i < il; i += 3 ) {\r\n\r\n\t\t\t\t\tvector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );\r\n\t\t\t\t\tbb.expandByPoint( vector );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( positions === undefined || positions.length === 0 ) {\r\n\r\n\t\t\t\tthis.boundingBox.min.set( 0, 0, 0 );\r\n\t\t\t\tthis.boundingBox.max.set( 0, 0, 0 );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) {\r\n\r\n\t\t\t\tTHREE.error( 'THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The \"position\" attribute is likely to have NaN values.' );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t}(),\r\n\r\n\tcomputeBoundingSphere: function () {\r\n\r\n\t\tvar box = new THREE.Box3();\r\n\t\tvar vector = new THREE.Vector3();\r\n\r\n\t\treturn function () {\r\n\r\n\t\t\tif ( this.boundingSphere === null ) {\r\n\r\n\t\t\t\tthis.boundingSphere = new THREE.Sphere();\r\n\r\n\t\t\t}\r\n\r\n\t\t\tvar positions = this.attributes.position.array;\r\n\r\n\t\t\tif ( positions ) {\r\n\r\n\t\t\t\tbox.makeEmpty();\r\n\r\n\t\t\t\tvar center = this.boundingSphere.center;\r\n\r\n\t\t\t\tfor ( var i = 0, il = positions.length; i < il; i += 3 ) {\r\n\r\n\t\t\t\t\tvector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );\r\n\t\t\t\t\tbox.expandByPoint( vector );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tbox.center( center );\r\n\r\n\t\t\t\t// hoping to find a boundingSphere with a radius smaller than the\r\n\t\t\t\t// boundingSphere of the boundingBox: sqrt(3) smaller in the best case\r\n\r\n\t\t\t\tvar maxRadiusSq = 0;\r\n\r\n\t\t\t\tfor ( var i = 0, il = positions.length; i < il; i += 3 ) {\r\n\r\n\t\t\t\t\tvector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );\r\n\t\t\t\t\tmaxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tthis.boundingSphere.radius = Math.sqrt( maxRadiusSq );\r\n\r\n\t\t\t\tif ( isNaN( this.boundingSphere.radius ) ) {\r\n\r\n\t\t\t\t\tTHREE.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The \"position\" attribute is likely to have NaN values.' );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t}(),\r\n\r\n\tcomputeFaceNormals: function () {\r\n\r\n\t\t// backwards compatibility\r\n\r\n\t},\r\n\r\n\tcomputeVertexNormals: function () {\r\n\r\n\t\tvar attributes = this.attributes;\r\n\r\n\t\tif ( attributes.position ) {\r\n\r\n\t\t\tvar positions = attributes.position.array;\r\n\r\n\t\t\tif ( attributes.normal === undefined ) {\r\n\r\n\t\t\t\tthis.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( positions.length ), 3 ) );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\t// reset existing normals to zero\r\n\r\n\t\t\t\tvar normals = attributes.normal.array;\r\n\r\n\t\t\t\tfor ( var i = 0, il = normals.length; i < il; i ++ ) {\r\n\r\n\t\t\t\t\tnormals[ i ] = 0;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\tvar normals = attributes.normal.array;\r\n\r\n\t\t\tvar vA, vB, vC,\r\n\r\n\t\t\tpA = new THREE.Vector3(),\r\n\t\t\tpB = new THREE.Vector3(),\r\n\t\t\tpC = new THREE.Vector3(),\r\n\r\n\t\t\tcb = new THREE.Vector3(),\r\n\t\t\tab = new THREE.Vector3();\r\n\r\n\t\t\t// indexed elements\r\n\r\n\t\t\tif ( attributes.index ) {\r\n\r\n\t\t\t\tvar indices = attributes.index.array;\r\n\r\n\t\t\t\tvar offsets = ( this.offsets.length > 0 ? this.offsets : [ { start: 0, count: indices.length, index: 0 } ] );\r\n\r\n\t\t\t\tfor ( var j = 0, jl = offsets.length; j < jl; ++ j ) {\r\n\r\n\t\t\t\t\tvar start = offsets[ j ].start;\r\n\t\t\t\t\tvar count = offsets[ j ].count;\r\n\t\t\t\t\tvar index = offsets[ j ].index;\r\n\r\n\t\t\t\t\tfor ( var i = start, il = start + count; i < il; i += 3 ) {\r\n\r\n\t\t\t\t\t\tvA = ( index + indices[ i ] ) * 3;\r\n\t\t\t\t\t\tvB = ( index + indices[ i + 1 ] ) * 3;\r\n\t\t\t\t\t\tvC = ( index + indices[ i + 2 ] ) * 3;\r\n\r\n\t\t\t\t\t\tpA.fromArray( positions, vA );\r\n\t\t\t\t\t\tpB.fromArray( positions, vB );\r\n\t\t\t\t\t\tpC.fromArray( positions, vC );\r\n\r\n\t\t\t\t\t\tcb.subVectors( pC, pB );\r\n\t\t\t\t\t\tab.subVectors( pA, pB );\r\n\t\t\t\t\t\tcb.cross( ab );\r\n\r\n\t\t\t\t\t\tnormals[ vA ] += cb.x;\r\n\t\t\t\t\t\tnormals[ vA + 1 ] += cb.y;\r\n\t\t\t\t\t\tnormals[ vA + 2 ] += cb.z;\r\n\r\n\t\t\t\t\t\tnormals[ vB ] += cb.x;\r\n\t\t\t\t\t\tnormals[ vB + 1 ] += cb.y;\r\n\t\t\t\t\t\tnormals[ vB + 2 ] += cb.z;\r\n\r\n\t\t\t\t\t\tnormals[ vC ] += cb.x;\r\n\t\t\t\t\t\tnormals[ vC + 1 ] += cb.y;\r\n\t\t\t\t\t\tnormals[ vC + 2 ] += cb.z;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\t// non-indexed elements (unconnected triangle soup)\r\n\r\n\t\t\t\tfor ( var i = 0, il = positions.length; i < il; i += 9 ) {\r\n\r\n\t\t\t\t\tpA.fromArray( positions, i );\r\n\t\t\t\t\tpB.fromArray( positions, i + 3 );\r\n\t\t\t\t\tpC.fromArray( positions, i + 6 );\r\n\r\n\t\t\t\t\tcb.subVectors( pC, pB );\r\n\t\t\t\t\tab.subVectors( pA, pB );\r\n\t\t\t\t\tcb.cross( ab );\r\n\r\n\t\t\t\t\tnormals[ i ] = cb.x;\r\n\t\t\t\t\tnormals[ i + 1 ] = cb.y;\r\n\t\t\t\t\tnormals[ i + 2 ] = cb.z;\r\n\r\n\t\t\t\t\tnormals[ i + 3 ] = cb.x;\r\n\t\t\t\t\tnormals[ i + 4 ] = cb.y;\r\n\t\t\t\t\tnormals[ i + 5 ] = cb.z;\r\n\r\n\t\t\t\t\tnormals[ i + 6 ] = cb.x;\r\n\t\t\t\t\tnormals[ i + 7 ] = cb.y;\r\n\t\t\t\t\tnormals[ i + 8 ] = cb.z;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\tthis.normalizeNormals();\r\n\r\n\t\t\tattributes.normal.needsUpdate = true;\r\n\r\n\t\t}\r\n\r\n\t},\r\n\r\n\tcomputeTangents: function () {\r\n\r\n\t\t// based on http://www.terathon.com/code/tangent.html\r\n\t\t// (per vertex tangents)\r\n\r\n\t\tif ( this.attributes.index === undefined ||\r\n\t\t\t this.attributes.position === undefined ||\r\n\t\t\t this.attributes.normal === undefined ||\r\n\t\t\t this.attributes.uv === undefined ) {\r\n\r\n\t\t\tTHREE.warn( 'THREE.BufferGeometry: Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()' );\r\n\t\t\treturn;\r\n\r\n\t\t}\r\n\r\n\t\tvar indices = this.attributes.index.array;\r\n\t\tvar positions = this.attributes.position.array;\r\n\t\tvar normals = this.attributes.normal.array;\r\n\t\tvar uvs = this.attributes.uv.array;\r\n\r\n\t\tvar nVertices = positions.length / 3;\r\n\r\n\t\tif ( this.attributes.tangent === undefined ) {\r\n\r\n\t\t\tthis.addAttribute( 'tangent', new THREE.BufferAttribute( new Float32Array( 4 * nVertices ), 4 ) );\r\n\r\n\t\t}\r\n\r\n\t\tvar tangents = this.attributes.tangent.array;\r\n\r\n\t\tvar tan1 = [], tan2 = [];\r\n\r\n\t\tfor ( var k = 0; k < nVertices; k ++ ) {\r\n\r\n\t\t\ttan1[ k ] = new THREE.Vector3();\r\n\t\t\ttan2[ k ] = new THREE.Vector3();\r\n\r\n\t\t}\r\n\r\n\t\tvar vA = new THREE.Vector3(),\r\n\t\t\tvB = new THREE.Vector3(),\r\n\t\t\tvC = new THREE.Vector3(),\r\n\r\n\t\t\tuvA = new THREE.Vector2(),\r\n\t\t\tuvB = new THREE.Vector2(),\r\n\t\t\tuvC = new THREE.Vector2(),\r\n\r\n\t\t\tx1, x2, y1, y2, z1, z2,\r\n\t\t\ts1, s2, t1, t2, r;\r\n\r\n\t\tvar sdir = new THREE.Vector3(), tdir = new THREE.Vector3();\r\n\r\n\t\tfunction handleTriangle( a, b, c ) {\r\n\r\n\t\t\tvA.fromArray( positions, a * 3 );\r\n\t\t\tvB.fromArray( positions, b * 3 );\r\n\t\t\tvC.fromArray( positions, c * 3 );\r\n\r\n\t\t\tuvA.fromArray( uvs, a * 2 );\r\n\t\t\tuvB.fromArray( uvs, b * 2 );\r\n\t\t\tuvC.fromArray( uvs, c * 2 );\r\n\r\n\t\t\tx1 = vB.x - vA.x;\r\n\t\t\tx2 = vC.x - vA.x;\r\n\r\n\t\t\ty1 = vB.y - vA.y;\r\n\t\t\ty2 = vC.y - vA.y;\r\n\r\n\t\t\tz1 = vB.z - vA.z;\r\n\t\t\tz2 = vC.z - vA.z;\r\n\r\n\t\t\ts1 = uvB.x - uvA.x;\r\n\t\t\ts2 = uvC.x - uvA.x;\r\n\r\n\t\t\tt1 = uvB.y - uvA.y;\r\n\t\t\tt2 = uvC.y - uvA.y;\r\n\r\n\t\t\tr = 1.0 / ( s1 * t2 - s2 * t1 );\r\n\r\n\t\t\tsdir.set(\r\n\t\t\t\t( t2 * x1 - t1 * x2 ) * r,\r\n\t\t\t\t( t2 * y1 - t1 * y2 ) * r,\r\n\t\t\t\t( t2 * z1 - t1 * z2 ) * r\r\n\t\t\t);\r\n\r\n\t\t\ttdir.set(\r\n\t\t\t\t( s1 * x2 - s2 * x1 ) * r,\r\n\t\t\t\t( s1 * y2 - s2 * y1 ) * r,\r\n\t\t\t\t( s1 * z2 - s2 * z1 ) * r\r\n\t\t\t);\r\n\r\n\t\t\ttan1[ a ].add( sdir );\r\n\t\t\ttan1[ b ].add( sdir );\r\n\t\t\ttan1[ c ].add( sdir );\r\n\r\n\t\t\ttan2[ a ].add( tdir );\r\n\t\t\ttan2[ b ].add( tdir );\r\n\t\t\ttan2[ c ].add( tdir );\r\n\r\n\t\t}\r\n\r\n\t\tvar i, il;\r\n\t\tvar j, jl;\r\n\t\tvar iA, iB, iC;\r\n\r\n\t\tif ( this.drawcalls.length === 0 ) {\r\n\r\n\t\t\tthis.addDrawCall( 0, indices.length, 0 );\r\n\r\n\t\t}\r\n\r\n\t\tvar drawcalls = this.drawcalls;\r\n\r\n\t\tfor ( j = 0, jl = drawcalls.length; j < jl; ++ j ) {\r\n\r\n\t\t\tvar start = drawcalls[ j ].start;\r\n\t\t\tvar count = drawcalls[ j ].count;\r\n\t\t\tvar index = drawcalls[ j ].index;\r\n\r\n\t\t\tfor ( i = start, il = start + count; i < il; i += 3 ) {\r\n\r\n\t\t\t\tiA = index + indices[ i ];\r\n\t\t\t\tiB = index + indices[ i + 1 ];\r\n\t\t\t\tiC = index + indices[ i + 2 ];\r\n\r\n\t\t\t\thandleTriangle( iA, iB, iC );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tvar tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3();\r\n\t\tvar n = new THREE.Vector3(), n2 = new THREE.Vector3();\r\n\t\tvar w, t, test;\r\n\r\n\t\tfunction handleVertex( v ) {\r\n\r\n\t\t\tn.fromArray( normals, v * 3 );\r\n\t\t\tn2.copy( n );\r\n\r\n\t\t\tt = tan1[ v ];\r\n\r\n\t\t\t// Gram-Schmidt orthogonalize\r\n\r\n\t\t\ttmp.copy( t );\r\n\t\t\ttmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize();\r\n\r\n\t\t\t// Calculate handedness\r\n\r\n\t\t\ttmp2.crossVectors( n2, t );\r\n\t\t\ttest = tmp2.dot( tan2[ v ] );\r\n\t\t\tw = ( test < 0.0 ) ? - 1.0 : 1.0;\r\n\r\n\t\t\ttangents[ v * 4 ] = tmp.x;\r\n\t\t\ttangents[ v * 4 + 1 ] = tmp.y;\r\n\t\t\ttangents[ v * 4 + 2 ] = tmp.z;\r\n\t\t\ttangents[ v * 4 + 3 ] = w;\r\n\r\n\t\t}\r\n\r\n\t\tfor ( j = 0, jl = drawcalls.length; j < jl; ++ j ) {\r\n\r\n\t\t\tvar start = drawcalls[ j ].start;\r\n\t\t\tvar count = drawcalls[ j ].count;\r\n\t\t\tvar index = drawcalls[ j ].index;\r\n\r\n\t\t\tfor ( i = start, il = start + count; i < il; i += 3 ) {\r\n\r\n\t\t\t\tiA = index + indices[ i ];\r\n\t\t\t\tiB = index + indices[ i + 1 ];\r\n\t\t\t\tiC = index + indices[ i + 2 ];\r\n\r\n\t\t\t\thandleVertex( iA );\r\n\t\t\t\thandleVertex( iB );\r\n\t\t\t\thandleVertex( iC );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t},\r\n\r\n\t/*\r\n\tCompute the draw offset for large models by chunking the index buffer into chunks of 65k addressable vertices.\r\n\tThis method will effectively rewrite the index buffer and remap all attributes to match the new indices.\r\n\tWARNING: This method will also expand the vertex count to prevent sprawled triangles across draw offsets.\r\n\tsize - Defaults to 65535, but allows for larger or smaller chunks.\r\n\t*/\r\n\tcomputeOffsets: function ( size ) {\r\n\r\n\t\tif ( size === undefined ) size = 65535; // WebGL limits type of index buffer values to 16-bit.\r\n\r\n\t\tvar indices = this.attributes.index.array;\r\n\t\tvar vertices = this.attributes.position.array;\r\n\r\n\t\tvar facesCount = ( indices.length / 3 );\r\n\r\n\t\t/*\r\n\t\tconsole.log(\"Computing buffers in offsets of \"+size+\" -> indices:\"+indices.length+\" vertices:\"+vertices.length);\r\n\t\tconsole.log(\"Faces to process: \"+(indices.length/3));\r\n\t\tconsole.log(\"Reordering \"+verticesCount+\" vertices.\");\r\n\t\t*/\r\n\r\n\t\tvar sortedIndices = new Uint16Array( indices.length ); //16-bit buffers\r\n\t\tvar indexPtr = 0;\r\n\t\tvar vertexPtr = 0;\r\n\r\n\t\tvar offsets = [ { start:0, count:0, index:0 } ];\r\n\t\tvar offset = offsets[ 0 ];\r\n\r\n\t\tvar duplicatedVertices = 0;\r\n\t\tvar newVerticeMaps = 0;\r\n\t\tvar faceVertices = new Int32Array( 6 );\r\n\t\tvar vertexMap = new Int32Array( vertices.length );\r\n\t\tvar revVertexMap = new Int32Array( vertices.length );\r\n\t\tfor ( var j = 0; j < vertices.length; j ++ ) { vertexMap[ j ] = - 1; revVertexMap[ j ] = - 1; }\r\n\r\n\t\t/*\r\n\t\t\tTraverse every face and reorder vertices in the proper offsets of 65k.\r\n\t\t\tWe can have more than 65k entries in the index buffer per offset, but only reference 65k values.\r\n\t\t*/\r\n\t\tfor ( var findex = 0; findex < facesCount; findex ++ ) {\r\n\t\t\tnewVerticeMaps = 0;\r\n\r\n\t\t\tfor ( var vo = 0; vo < 3; vo ++ ) {\r\n\t\t\t\tvar vid = indices[ findex * 3 + vo ];\r\n\t\t\t\tif ( vertexMap[ vid ] == - 1 ) {\r\n\t\t\t\t\t//Unmapped vertice\r\n\t\t\t\t\tfaceVertices[ vo * 2 ] = vid;\r\n\t\t\t\t\tfaceVertices[ vo * 2 + 1 ] = - 1;\r\n\t\t\t\t\tnewVerticeMaps ++;\r\n\t\t\t\t} else if ( vertexMap[ vid ] < offset.index ) {\r\n\t\t\t\t\t//Reused vertices from previous block (duplicate)\r\n\t\t\t\t\tfaceVertices[ vo * 2 ] = vid;\r\n\t\t\t\t\tfaceVertices[ vo * 2 + 1 ] = - 1;\r\n\t\t\t\t\tduplicatedVertices ++;\r\n\t\t\t\t} else {\r\n\t\t\t\t\t//Reused vertice in the current block\r\n\t\t\t\t\tfaceVertices[ vo * 2 ] = vid;\r\n\t\t\t\t\tfaceVertices[ vo * 2 + 1 ] = vertexMap[ vid ];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tvar faceMax = vertexPtr + newVerticeMaps;\r\n\t\t\tif ( faceMax > ( offset.index + size ) ) {\r\n\t\t\t\tvar new_offset = { start:indexPtr, count:0, index:vertexPtr };\r\n\t\t\t\toffsets.push( new_offset );\r\n\t\t\t\toffset = new_offset;\r\n\r\n\t\t\t\t//Re-evaluate reused vertices in light of new offset.\r\n\t\t\t\tfor ( var v = 0; v < 6; v += 2 ) {\r\n\t\t\t\t\tvar new_vid = faceVertices[ v + 1 ];\r\n\t\t\t\t\tif ( new_vid > - 1 && new_vid < offset.index )\r\n\t\t\t\t\t\tfaceVertices[ v + 1 ] = - 1;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t//Reindex the face.\r\n\t\t\tfor ( var v = 0; v < 6; v += 2 ) {\r\n\t\t\t\tvar vid = faceVertices[ v ];\r\n\t\t\t\tvar new_vid = faceVertices[ v + 1 ];\r\n\r\n\t\t\t\tif ( new_vid === - 1 )\r\n\t\t\t\t\tnew_vid = vertexPtr ++;\r\n\r\n\t\t\t\tvertexMap[ vid ] = new_vid;\r\n\t\t\t\trevVertexMap[ new_vid ] = vid;\r\n\t\t\t\tsortedIndices[ indexPtr ++ ] = new_vid - offset.index; //XXX overflows at 16bit\r\n\t\t\t\toffset.count ++;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t/* Move all attribute values to map to the new computed indices , also expand the vertice stack to match our new vertexPtr. */\r\n\t\tthis.reorderBuffers( sortedIndices, revVertexMap, vertexPtr );\r\n\t\tthis.offsets = offsets; // TODO: Deprecate\r\n\t\tthis.drawcalls = offsets;\r\n\r\n\t\t/*\r\n\t\tvar orderTime = Date.now();\r\n\t\tconsole.log(\"Reorder time: \"+(orderTime-s)+\"ms\");\r\n\t\tconsole.log(\"Duplicated \"+duplicatedVertices+\" vertices.\");\r\n\t\tconsole.log(\"Compute Buffers time: \"+(Date.now()-s)+\"ms\");\r\n\t\tconsole.log(\"Draw offsets: \"+offsets.length);\r\n\t\t*/\r\n\r\n\t\treturn offsets;\r\n\r\n\t},\r\n\r\n\tmerge: function ( geometry, offset ) {\r\n\r\n\t\tif ( geometry instanceof THREE.BufferGeometry === false ) {\r\n\r\n\t\t\tTHREE.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry );\r\n\t\t\treturn;\r\n\r\n\t\t}\r\n\r\n\t\tif ( offset === undefined ) offset = 0;\r\n\r\n\t\tvar attributes = this.attributes;\r\n\r\n\t\tfor ( var key in attributes ) {\r\n\r\n\t\t\tif ( geometry.attributes[ key ] === undefined ) continue;\r\n\r\n\t\t\tvar attribute1 = attributes[ key ];\r\n\t\t\tvar attributeArray1 = attribute1.array;\r\n\r\n\t\t\tvar attribute2 = geometry.attributes[ key ];\r\n\t\t\tvar attributeArray2 = attribute2.array;\r\n\r\n\t\t\tvar attributeSize = attribute2.itemSize;\r\n\r\n\t\t\tfor ( var i = 0, j = attributeSize * offset; i < attributeArray2.length; i ++, j ++ ) {\r\n\r\n\t\t\t\tattributeArray1[ j ] = attributeArray2[ i ];\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tnormalizeNormals: function () {\r\n\r\n\t\tvar normals = this.attributes.normal.array;\r\n\r\n\t\tvar x, y, z, n;\r\n\r\n\t\tfor ( var i = 0, il = normals.length; i < il; i += 3 ) {\r\n\r\n\t\t\tx = normals[ i ];\r\n\t\t\ty = normals[ i + 1 ];\r\n\t\t\tz = normals[ i + 2 ];\r\n\r\n\t\t\tn = 1.0 / Math.sqrt( x * x + y * y + z * z );\r\n\r\n\t\t\tnormals[ i ] *= n;\r\n\t\t\tnormals[ i + 1 ] *= n;\r\n\t\t\tnormals[ i + 2 ] *= n;\r\n\r\n\t\t}\r\n\r\n\t},\r\n\r\n\t/*\r\n\t\treoderBuffers:\r\n\t\tReorder attributes based on a new indexBuffer and indexMap.\r\n\t\tindexBuffer - Uint16Array of the new ordered indices.\r\n\t\tindexMap - Int32Array where the position is the new vertex ID and the value the old vertex ID for each vertex.\r\n\t\tvertexCount - Amount of total vertices considered in this reordering (in case you want to grow the vertice stack).\r\n\t*/\r\n\treorderBuffers: function ( indexBuffer, indexMap, vertexCount ) {\r\n\r\n\t\t/* Create a copy of all attributes for reordering. */\r\n\t\tvar sortedAttributes = {};\r\n\t\tfor ( var attr in this.attributes ) {\r\n\t\t\tif ( attr == 'index' )\r\n\t\t\t\tcontinue;\r\n\t\t\tvar sourceArray = this.attributes[ attr ].array;\r\n\t\t\tsortedAttributes[ attr ] = new sourceArray.constructor( this.attributes[ attr ].itemSize * vertexCount );\r\n\t\t}\r\n\r\n\t\t/* Move attribute positions based on the new index map */\r\n\t\tfor ( var new_vid = 0; new_vid < vertexCount; new_vid ++ ) {\r\n\t\t\tvar vid = indexMap[ new_vid ];\r\n\t\t\tfor ( var attr in this.attributes ) {\r\n\t\t\t\tif ( attr == 'index' )\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\tvar attrArray = this.attributes[ attr ].array;\r\n\t\t\t\tvar attrSize = this.attributes[ attr ].itemSize;\r\n\t\t\t\tvar sortedAttr = sortedAttributes[ attr ];\r\n\t\t\t\tfor ( var k = 0; k < attrSize; k ++ )\r\n\t\t\t\t\tsortedAttr[ new_vid * attrSize + k ] = attrArray[ vid * attrSize + k ];\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t/* Carry the new sorted buffers locally */\r\n\t\tthis.attributes[ 'index' ].array = indexBuffer;\r\n\t\tfor ( var attr in this.attributes ) {\r\n\t\t\tif ( attr == 'index' )\r\n\t\t\t\tcontinue;\r\n\t\t\tthis.attributes[ attr ].array = sortedAttributes[ attr ];\r\n\t\t\tthis.attributes[ attr ].numItems = this.attributes[ attr ].itemSize * vertexCount;\r\n\t\t}\r\n\t},\r\n\r\n\ttoJSON: function () {\r\n\r\n\t\tvar output = {\r\n\t\t\tmetadata: {\r\n\t\t\t\tversion: 4.0,\r\n\t\t\t\ttype: 'BufferGeometry',\r\n\t\t\t\tgenerator: 'BufferGeometryExporter'\r\n\t\t\t},\r\n\t\t\tuuid: this.uuid,\r\n\t\t\ttype: this.type,\r\n\t\t\tdata: {\r\n\t\t\t\tattributes: {}\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tvar attributes = this.attributes;\r\n\t\tvar offsets = this.offsets;\r\n\t\tvar boundingSphere = this.boundingSphere;\r\n\r\n\t\tfor ( var key in attributes ) {\r\n\r\n\t\t\tvar attribute = attributes[ key ];\r\n\r\n\t\t\tvar array = Array.prototype.slice.call( attribute.array );\r\n\r\n\t\t\toutput.data.attributes[ key ] = {\r\n\t\t\t\titemSize: attribute.itemSize,\r\n\t\t\t\ttype: attribute.array.constructor.name,\r\n\t\t\t\tarray: array\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tif ( offsets.length > 0 ) {\r\n\r\n\t\t\toutput.data.offsets = JSON.parse( JSON.stringify( offsets ) );\r\n\r\n\t\t}\r\n\r\n\t\tif ( boundingSphere !== null ) {\r\n\r\n\t\t\toutput.data.boundingSphere = {\r\n\t\t\t\tcenter: boundingSphere.center.toArray(),\r\n\t\t\t\tradius: boundingSphere.radius\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\treturn output;\r\n\r\n\t},\r\n\r\n\tclone: function () {\r\n\r\n\t\tvar geometry = new THREE.BufferGeometry();\r\n\r\n\t\tfor ( var attr in this.attributes ) {\r\n\r\n\t\t\tvar sourceAttr = this.attributes[ attr ];\r\n\t\t\tgeometry.addAttribute( attr, sourceAttr.clone() );\r\n\r\n\t\t}\r\n\r\n\t\tfor ( var i = 0, il = this.offsets.length; i < il; i ++ ) {\r\n\r\n\t\t\tvar offset = this.offsets[ i ];\r\n\r\n\t\t\tgeometry.offsets.push( {\r\n\r\n\t\t\t\tstart: offset.start,\r\n\t\t\t\tindex: offset.index,\r\n\t\t\t\tcount: offset.count\r\n\r\n\t\t\t} );\r\n\r\n\t\t}\r\n\r\n\t\treturn geometry;\r\n\r\n\t},\r\n\r\n\tdispose: function () {\r\n\r\n\t\tthis.dispatchEvent( { type: 'dispose' } );\r\n\r\n\t}\r\n\r\n};\r\n\r\nTHREE.EventDispatcher.prototype.apply( THREE.BufferGeometry.prototype );\r\n\r\n// File:src/core/Geometry.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n * @author kile / http://kile.stravaganza.org/\r\n * @author alteredq / http://alteredqualia.com/\r\n * @author mikael emtinger / http://gomo.se/\r\n * @author zz85 / http://www.lab4games.net/zz85/blog\r\n * @author bhouston / http://exocortex.com\r\n */\r\n\r\nTHREE.Geometry = function () {\r\n\r\n\tObject.defineProperty( this, 'id', { value: THREE.GeometryIdCount ++ } );\r\n\r\n\tthis.uuid = THREE.Math.generateUUID();\r\n\r\n\tthis.name = '';\r\n\tthis.type = 'Geometry';\r\n\r\n\tthis.vertices = [];\r\n\tthis.colors = []; // one-to-one vertex colors, used in Points and Line\r\n\r\n\tthis.faces = [];\r\n\r\n\tthis.faceVertexUvs = [ [] ];\r\n\r\n\tthis.morphTargets = [];\r\n\tthis.morphColors = [];\r\n\tthis.morphNormals = [];\r\n\r\n\tthis.skinWeights = [];\r\n\tthis.skinIndices = [];\r\n\r\n\tthis.lineDistances = [];\r\n\r\n\tthis.boundingBox = null;\r\n\tthis.boundingSphere = null;\r\n\r\n\tthis.hasTangents = false;\r\n\r\n\tthis.dynamic = true; // the intermediate typed arrays will be deleted when set to false\r\n\r\n\t// update flags\r\n\r\n\tthis.verticesNeedUpdate = false;\r\n\tthis.elementsNeedUpdate = false;\r\n\tthis.uvsNeedUpdate = false;\r\n\tthis.normalsNeedUpdate = false;\r\n\tthis.tangentsNeedUpdate = false;\r\n\tthis.colorsNeedUpdate = false;\r\n\tthis.lineDistancesNeedUpdate = false;\r\n\r\n\tthis.groupsNeedUpdate = false;\r\n\r\n};\r\n\r\nTHREE.Geometry.prototype = {\r\n\r\n\tconstructor: THREE.Geometry,\r\n\r\n\tapplyMatrix: function ( matrix ) {\r\n\r\n\t\tvar normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix );\r\n\r\n\t\tfor ( var i = 0, il = this.vertices.length; i < il; i ++ ) {\r\n\r\n\t\t\tvar vertex = this.vertices[ i ];\r\n\t\t\tvertex.applyMatrix4( matrix );\r\n\r\n\t\t}\r\n\r\n\t\tfor ( var i = 0, il = this.faces.length; i < il; i ++ ) {\r\n\r\n\t\t\tvar face = this.faces[ i ];\r\n\t\t\tface.normal.applyMatrix3( normalMatrix ).normalize();\r\n\r\n\t\t\tfor ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) {\r\n\r\n\t\t\t\tface.vertexNormals[ j ].applyMatrix3( normalMatrix ).normalize();\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tif ( this.boundingBox !== null ) {\r\n\r\n\t\t\tthis.computeBoundingBox();\r\n\r\n\t\t}\r\n\r\n\t\tif ( this.boundingSphere !== null ) {\r\n\r\n\t\t\tthis.computeBoundingSphere();\r\n\r\n\t\t}\r\n\r\n\t\tthis.verticesNeedUpdate = true;\r\n\t\tthis.normalsNeedUpdate = true;\r\n\r\n\t},\r\n\r\n\tfromBufferGeometry: function ( geometry ) {\r\n\r\n\t\tvar scope = this;\r\n\r\n\t\tvar attributes = geometry.attributes;\r\n\r\n\t\tvar vertices = attributes.position.array;\r\n\t\tvar indices = attributes.index !== undefined ? attributes.index.array : undefined;\r\n\t\tvar normals = attributes.normal !== undefined ? attributes.normal.array : undefined;\r\n\t\tvar colors = attributes.color !== undefined ? attributes.color.array : undefined;\r\n\t\tvar uvs = attributes.uv !== undefined ? attributes.uv.array : undefined;\r\n\r\n\t\tvar tempNormals = [];\r\n\t\tvar tempUVs = [];\r\n\r\n\t\tfor ( var i = 0, j = 0; i < vertices.length; i += 3, j += 2 ) {\r\n\r\n\t\t\tscope.vertices.push( new THREE.Vector3( vertices[ i ], vertices[ i + 1 ], vertices[ i + 2 ] ) );\r\n\r\n\t\t\tif ( normals !== undefined ) {\r\n\r\n\t\t\t\ttempNormals.push( new THREE.Vector3( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] ) );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( colors !== undefined ) {\r\n\r\n\t\t\t\tscope.colors.push( new THREE.Color( colors[ i ], colors[ i + 1 ], colors[ i + 2 ] ) );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( uvs !== undefined ) {\r\n\r\n\t\t\t\ttempUVs.push( new THREE.Vector2( uvs[ j ], uvs[ j + 1 ] ) );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tvar addFace = function ( a, b, c ) {\r\n\r\n\t\t\tvar vertexNormals = normals !== undefined ? [ tempNormals[ a ].clone(), tempNormals[ b ].clone(), tempNormals[ c ].clone() ] : [];\r\n\t\t\tvar vertexColors = colors !== undefined ? [ scope.colors[ a ].clone(), scope.colors[ b ].clone(), scope.colors[ c ].clone() ] : [];\r\n\r\n\t\t\tscope.faces.push( new THREE.Face3( a, b, c, vertexNormals, vertexColors ) );\r\n\r\n\t\t\tif ( uvs !== undefined ) {\r\n\r\n\t\t\t\tscope.faceVertexUvs[ 0 ].push( [ tempUVs[ a ].clone(), tempUVs[ b ].clone(), tempUVs[ c ].clone() ] );\r\n\r\n\t\t\t}\r\n\r\n\t\t};\r\n\r\n\t\tif ( indices !== undefined ) {\r\n\r\n\t\t\tvar drawcalls = geometry.drawcalls;\r\n\r\n\t\t\tif ( drawcalls.length > 0 ) {\r\n\r\n\t\t\t\tfor ( var i = 0; i < drawcalls.length; i ++ ) {\r\n\r\n\t\t\t\t\tvar drawcall = drawcalls[ i ];\r\n\r\n\t\t\t\t\tvar start = drawcall.start;\r\n\t\t\t\t\tvar count = drawcall.count;\r\n\t\t\t\t\tvar index = drawcall.index;\r\n\r\n\t\t\t\t\tfor ( var j = start, jl = start + count; j < jl; j += 3 ) {\r\n\r\n\t\t\t\t\t\taddFace( index + indices[ j ], index + indices[ j + 1 ], index + indices[ j + 2 ] );\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tfor ( var i = 0; i < indices.length; i += 3 ) {\r\n\r\n\t\t\t\t\taddFace( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t} else {\r\n\r\n\t\t\tfor ( var i = 0; i < vertices.length / 3; i += 3 ) {\r\n\r\n\t\t\t\taddFace( i, i + 1, i + 2 );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tthis.computeFaceNormals();\r\n\r\n\t\tif ( geometry.boundingBox !== null ) {\r\n\r\n\t\t\tthis.boundingBox = geometry.boundingBox.clone();\r\n\r\n\t\t}\r\n\r\n\t\tif ( geometry.boundingSphere !== null ) {\r\n\r\n\t\t\tthis.boundingSphere = geometry.boundingSphere.clone();\r\n\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\r\n\t},\r\n\r\n\tcenter: function () {\r\n\r\n\t\tthis.computeBoundingBox();\r\n\r\n\t\tvar offset = this.boundingBox.center().negate();\r\n\r\n\t\tthis.applyMatrix( new THREE.Matrix4().setPosition( offset ) );\r\n\r\n\t\treturn offset;\r\n\r\n\t},\r\n\r\n\tcomputeFaceNormals: function () {\r\n\r\n\t\tvar cb = new THREE.Vector3(), ab = new THREE.Vector3();\r\n\r\n\t\tfor ( var f = 0, fl = this.faces.length; f < fl; f ++ ) {\r\n\r\n\t\t\tvar face = this.faces[ f ];\r\n\r\n\t\t\tvar vA = this.vertices[ face.a ];\r\n\t\t\tvar vB = this.vertices[ face.b ];\r\n\t\t\tvar vC = this.vertices[ face.c ];\r\n\r\n\t\t\tcb.subVectors( vC, vB );\r\n\t\t\tab.subVectors( vA, vB );\r\n\t\t\tcb.cross( ab );\r\n\r\n\t\t\tcb.normalize();\r\n\r\n\t\t\tface.normal.copy( cb );\r\n\r\n\t\t}\r\n\r\n\t},\r\n\r\n\tcomputeVertexNormals: function ( areaWeighted ) {\r\n\r\n\t\tvar v, vl, f, fl, face, vertices;\r\n\r\n\t\tvertices = new Array( this.vertices.length );\r\n\r\n\t\tfor ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {\r\n\r\n\t\t\tvertices[ v ] = new THREE.Vector3();\r\n\r\n\t\t}\r\n\r\n\t\tif ( areaWeighted ) {\r\n\r\n\t\t\t// vertex normals weighted by triangle areas\r\n\t\t\t// http://www.iquilezles.org/www/articles/normals/normals.htm\r\n\r\n\t\t\tvar vA, vB, vC;\r\n\t\t\tvar cb = new THREE.Vector3(), ab = new THREE.Vector3();\r\n\r\n\t\t\tfor ( f = 0, fl = this.faces.length; f < fl; f ++ ) {\r\n\r\n\t\t\t\tface = this.faces[ f ];\r\n\r\n\t\t\t\tvA = this.vertices[ face.a ];\r\n\t\t\t\tvB = this.vertices[ face.b ];\r\n\t\t\t\tvC = this.vertices[ face.c ];\r\n\r\n\t\t\t\tcb.subVectors( vC, vB );\r\n\t\t\t\tab.subVectors( vA, vB );\r\n\t\t\t\tcb.cross( ab );\r\n\r\n\t\t\t\tvertices[ face.a ].add( cb );\r\n\t\t\t\tvertices[ face.b ].add( cb );\r\n\t\t\t\tvertices[ face.c ].add( cb );\r\n\r\n\t\t\t}\r\n\r\n\t\t} else {\r\n\r\n\t\t\tfor ( f = 0, fl = this.faces.length; f < fl; f ++ ) {\r\n\r\n\t\t\t\tface = this.faces[ f ];\r\n\r\n\t\t\t\tvertices[ face.a ].add( face.normal );\r\n\t\t\t\tvertices[ face.b ].add( face.normal );\r\n\t\t\t\tvertices[ face.c ].add( face.normal );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tfor ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {\r\n\r\n\t\t\tvertices[ v ].normalize();\r\n\r\n\t\t}\r\n\r\n\t\tfor ( f = 0, fl = this.faces.length; f < fl; f ++ ) {\r\n\r\n\t\t\tface = this.faces[ f ];\r\n\r\n\t\t\tface.vertexNormals[ 0 ] = vertices[ face.a ].clone();\r\n\t\t\tface.vertexNormals[ 1 ] = vertices[ face.b ].clone();\r\n\t\t\tface.vertexNormals[ 2 ] = vertices[ face.c ].clone();\r\n\r\n\t\t}\r\n\r\n\t},\r\n\r\n\tcomputeMorphNormals: function () {\r\n\r\n\t\tvar i, il, f, fl, face;\r\n\r\n\t\t// save original normals\r\n\t\t// - create temp variables on first access\r\n\t\t// otherwise just copy (for faster repeated calls)\r\n\r\n\t\tfor ( f = 0, fl = this.faces.length; f < fl; f ++ ) {\r\n\r\n\t\t\tface = this.faces[ f ];\r\n\r\n\t\t\tif ( ! face.__originalFaceNormal ) {\r\n\r\n\t\t\t\tface.__originalFaceNormal = face.normal.clone();\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tface.__originalFaceNormal.copy( face.normal );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( ! face.__originalVertexNormals ) face.__originalVertexNormals = [];\r\n\r\n\t\t\tfor ( i = 0, il = face.vertexNormals.length; i < il; i ++ ) {\r\n\r\n\t\t\t\tif ( ! face.__originalVertexNormals[ i ] ) {\r\n\r\n\t\t\t\t\tface.__originalVertexNormals[ i ] = face.vertexNormals[ i ].clone();\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\tface.__originalVertexNormals[ i ].copy( face.vertexNormals[ i ] );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\t// use temp geometry to compute face and vertex normals for each morph\r\n\r\n\t\tvar tmpGeo = new THREE.Geometry();\r\n\t\ttmpGeo.faces = this.faces;\r\n\r\n\t\tfor ( i = 0, il = this.morphTargets.length; i < il; i ++ ) {\r\n\r\n\t\t\t// create on first access\r\n\r\n\t\t\tif ( ! this.morphNormals[ i ] ) {\r\n\r\n\t\t\t\tthis.morphNormals[ i ] = {};\r\n\t\t\t\tthis.morphNormals[ i ].faceNormals = [];\r\n\t\t\t\tthis.morphNormals[ i ].vertexNormals = [];\r\n\r\n\t\t\t\tvar dstNormalsFace = this.morphNormals[ i ].faceNormals;\r\n\t\t\t\tvar dstNormalsVertex = this.morphNormals[ i ].vertexNormals;\r\n\r\n\t\t\t\tvar faceNormal, vertexNormals;\r\n\r\n\t\t\t\tfor ( f = 0, fl = this.faces.length; f < fl; f ++ ) {\r\n\r\n\t\t\t\t\tfaceNormal = new THREE.Vector3();\r\n\t\t\t\t\tvertexNormals = { a: new THREE.Vector3(), b: new THREE.Vector3(), c: new THREE.Vector3() };\r\n\r\n\t\t\t\t\tdstNormalsFace.push( faceNormal );\r\n\t\t\t\t\tdstNormalsVertex.push( vertexNormals );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\tvar morphNormals = this.morphNormals[ i ];\r\n\r\n\t\t\t// set vertices to morph target\r\n\r\n\t\t\ttmpGeo.vertices = this.morphTargets[ i ].vertices;\r\n\r\n\t\t\t// compute morph normals\r\n\r\n\t\t\ttmpGeo.computeFaceNormals();\r\n\t\t\ttmpGeo.computeVertexNormals();\r\n\r\n\t\t\t// store morph normals\r\n\r\n\t\t\tvar faceNormal, vertexNormals;\r\n\r\n\t\t\tfor ( f = 0, fl = this.faces.length; f < fl; f ++ ) {\r\n\r\n\t\t\t\tface = this.faces[ f ];\r\n\r\n\t\t\t\tfaceNormal = morphNormals.faceNormals[ f ];\r\n\t\t\t\tvertexNormals = morphNormals.vertexNormals[ f ];\r\n\r\n\t\t\t\tfaceNormal.copy( face.normal );\r\n\r\n\t\t\t\tvertexNormals.a.copy( face.vertexNormals[ 0 ] );\r\n\t\t\t\tvertexNormals.b.copy( face.vertexNormals[ 1 ] );\r\n\t\t\t\tvertexNormals.c.copy( face.vertexNormals[ 2 ] );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\t// restore original normals\r\n\r\n\t\tfor ( f = 0, fl = this.faces.length; f < fl; f ++ ) {\r\n\r\n\t\t\tface = this.faces[ f ];\r\n\r\n\t\t\tface.normal = face.__originalFaceNormal;\r\n\t\t\tface.vertexNormals = face.__originalVertexNormals;\r\n\r\n\t\t}\r\n\r\n\t},\r\n\r\n\tcomputeTangents: function () {\r\n\r\n\t\t// based on http://www.terathon.com/code/tangent.html\r\n\t\t// tangents go to vertices\r\n\r\n\t\tvar f, fl, v, vl, i, vertexIndex,\r\n\t\t\tface, uv, vA, vB, vC, uvA, uvB, uvC,\r\n\t\t\tx1, x2, y1, y2, z1, z2,\r\n\t\t\ts1, s2, t1, t2, r, t, test,\r\n\t\t\ttan1 = [], tan2 = [],\r\n\t\t\tsdir = new THREE.Vector3(), tdir = new THREE.Vector3(),\r\n\t\t\ttmp = new THREE.Vector3(), tmp2 = new THREE.Vector3(),\r\n\t\t\tn = new THREE.Vector3(), w;\r\n\r\n\t\tfor ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {\r\n\r\n\t\t\ttan1[ v ] = new THREE.Vector3();\r\n\t\t\ttan2[ v ] = new THREE.Vector3();\r\n\r\n\t\t}\r\n\r\n\t\tfunction handleTriangle( context, a, b, c, ua, ub, uc ) {\r\n\r\n\t\t\tvA = context.vertices[ a ];\r\n\t\t\tvB = context.vertices[ b ];\r\n\t\t\tvC = context.vertices[ c ];\r\n\r\n\t\t\tuvA = uv[ ua ];\r\n\t\t\tuvB = uv[ ub ];\r\n\t\t\tuvC = uv[ uc ];\r\n\r\n\t\t\tx1 = vB.x - vA.x;\r\n\t\t\tx2 = vC.x - vA.x;\r\n\t\t\ty1 = vB.y - vA.y;\r\n\t\t\ty2 = vC.y - vA.y;\r\n\t\t\tz1 = vB.z - vA.z;\r\n\t\t\tz2 = vC.z - vA.z;\r\n\r\n\t\t\ts1 = uvB.x - uvA.x;\r\n\t\t\ts2 = uvC.x - uvA.x;\r\n\t\t\tt1 = uvB.y - uvA.y;\r\n\t\t\tt2 = uvC.y - uvA.y;\r\n\r\n\t\t\tr = 1.0 / ( s1 * t2 - s2 * t1 );\r\n\t\t\tsdir.set( ( t2 * x1 - t1 * x2 ) * r,\r\n\t\t\t\t\t ( t2 * y1 - t1 * y2 ) * r,\r\n\t\t\t\t\t ( t2 * z1 - t1 * z2 ) * r );\r\n\t\t\ttdir.set( ( s1 * x2 - s2 * x1 ) * r,\r\n\t\t\t\t\t ( s1 * y2 - s2 * y1 ) * r,\r\n\t\t\t\t\t ( s1 * z2 - s2 * z1 ) * r );\r\n\r\n\t\t\ttan1[ a ].add( sdir );\r\n\t\t\ttan1[ b ].add( sdir );\r\n\t\t\ttan1[ c ].add( sdir );\r\n\r\n\t\t\ttan2[ a ].add( tdir );\r\n\t\t\ttan2[ b ].add( tdir );\r\n\t\t\ttan2[ c ].add( tdir );\r\n\r\n\t\t}\r\n\r\n\t\tfor ( f = 0, fl = this.faces.length; f < fl; f ++ ) {\r\n\r\n\t\t\tface = this.faces[ f ];\r\n\t\t\tuv = this.faceVertexUvs[ 0 ][ f ]; // use UV layer 0 for tangents\r\n\r\n\t\t\thandleTriangle( this, face.a, face.b, face.c, 0, 1, 2 );\r\n\r\n\t\t}\r\n\r\n\t\tvar faceIndex = [ 'a', 'b', 'c', 'd' ];\r\n\r\n\t\tfor ( f = 0, fl = this.faces.length; f < fl; f ++ ) {\r\n\r\n\t\t\tface = this.faces[ f ];\r\n\r\n\t\t\tfor ( i = 0; i < Math.min( face.vertexNormals.length, 3 ); i ++ ) {\r\n\r\n\t\t\t\tn.copy( face.vertexNormals[ i ] );\r\n\r\n\t\t\t\tvertexIndex = face[ faceIndex[ i ] ];\r\n\r\n\t\t\t\tt = tan1[ vertexIndex ];\r\n\r\n\t\t\t\t// Gram-Schmidt orthogonalize\r\n\r\n\t\t\t\ttmp.copy( t );\r\n\t\t\t\ttmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize();\r\n\r\n\t\t\t\t// Calculate handedness\r\n\r\n\t\t\t\ttmp2.crossVectors( face.vertexNormals[ i ], t );\r\n\t\t\t\ttest = tmp2.dot( tan2[ vertexIndex ] );\r\n\t\t\t\tw = ( test < 0.0 ) ? - 1.0 : 1.0;\r\n\r\n\t\t\t\tface.vertexTangents[ i ] = new THREE.Vector4( tmp.x, tmp.y, tmp.z, w );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tthis.hasTangents = true;\r\n\r\n\t},\r\n\r\n\tcomputeLineDistances: function () {\r\n\r\n\t\tvar d = 0;\r\n\t\tvar vertices = this.vertices;\r\n\r\n\t\tfor ( var i = 0, il = vertices.length; i < il; i ++ ) {\r\n\r\n\t\t\tif ( i > 0 ) {\r\n\r\n\t\t\t\td += vertices[ i ].distanceTo( vertices[ i - 1 ] );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tthis.lineDistances[ i ] = d;\r\n\r\n\t\t}\r\n\r\n\t},\r\n\r\n\tcomputeBoundingBox: function () {\r\n\r\n\t\tif ( this.boundingBox === null ) {\r\n\r\n\t\t\tthis.boundingBox = new THREE.Box3();\r\n\r\n\t\t}\r\n\r\n\t\tthis.boundingBox.setFromPoints( this.vertices );\r\n\r\n\t},\r\n\r\n\tcomputeBoundingSphere: function () {\r\n\r\n\t\tif ( this.boundingSphere === null ) {\r\n\r\n\t\t\tthis.boundingSphere = new THREE.Sphere();\r\n\r\n\t\t}\r\n\r\n\t\tthis.boundingSphere.setFromPoints( this.vertices );\r\n\r\n\t},\r\n\r\n\tmerge: function ( geometry, matrix, materialIndexOffset ) {\r\n\r\n\t\tif ( geometry instanceof THREE.Geometry === false ) {\r\n\r\n\t\t\tTHREE.error( 'THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.', geometry );\r\n\t\t\treturn;\r\n\r\n\t\t}\r\n\r\n\t\tvar normalMatrix,\r\n\t\tvertexOffset = this.vertices.length,\r\n\t\tvertices1 = this.vertices,\r\n\t\tvertices2 = geometry.vertices,\r\n\t\tfaces1 = this.faces,\r\n\t\tfaces2 = geometry.faces,\r\n\t\tuvs1 = this.faceVertexUvs[ 0 ],\r\n\t\tuvs2 = geometry.faceVertexUvs[ 0 ];\r\n\r\n\t\tif ( materialIndexOffset === undefined ) materialIndexOffset = 0;\r\n\r\n\t\tif ( matrix !== undefined ) {\r\n\r\n\t\t\tnormalMatrix = new THREE.Matrix3().getNormalMatrix( matrix );\r\n\r\n\t\t}\r\n\r\n\t\t// vertices\r\n\r\n\t\tfor ( var i = 0, il = vertices2.length; i < il; i ++ ) {\r\n\r\n\t\t\tvar vertex = vertices2[ i ];\r\n\r\n\t\t\tvar vertexCopy = vertex.clone();\r\n\r\n\t\t\tif ( matrix !== undefined ) vertexCopy.applyMatrix4( matrix );\r\n\r\n\t\t\tvertices1.push( vertexCopy );\r\n\r\n\t\t}\r\n\r\n\t\t// faces\r\n\r\n\t\tfor ( i = 0, il = faces2.length; i < il; i ++ ) {\r\n\r\n\t\t\tvar face = faces2[ i ], faceCopy, normal, color,\r\n\t\t\tfaceVertexNormals = face.vertexNormals,\r\n\t\t\tfaceVertexColors = face.vertexColors;\r\n\r\n\t\t\tfaceCopy = new THREE.Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset );\r\n\t\t\tfaceCopy.normal.copy( face.normal );\r\n\r\n\t\t\tif ( normalMatrix !== undefined ) {\r\n\r\n\t\t\t\tfaceCopy.normal.applyMatrix3( normalMatrix ).normalize();\r\n\r\n\t\t\t}\r\n\r\n\t\t\tfor ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) {\r\n\r\n\t\t\t\tnormal = faceVertexNormals[ j ].clone();\r\n\r\n\t\t\t\tif ( normalMatrix !== undefined ) {\r\n\r\n\t\t\t\t\tnormal.applyMatrix3( normalMatrix ).normalize();\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tfaceCopy.vertexNormals.push( normal );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tfaceCopy.color.copy( face.color );\r\n\r\n\t\t\tfor ( var j = 0, jl = faceVertexColors.length; j < jl; j ++ ) {\r\n\r\n\t\t\t\tcolor = faceVertexColors[ j ];\r\n\t\t\t\tfaceCopy.vertexColors.push( color.clone() );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tfaceCopy.materialIndex = face.materialIndex + materialIndexOffset;\r\n\r\n\t\t\tfaces1.push( faceCopy );\r\n\r\n\t\t}\r\n\r\n\t\t// uvs\r\n\r\n\t\tfor ( i = 0, il = uvs2.length; i < il; i ++ ) {\r\n\r\n\t\t\tvar uv = uvs2[ i ], uvCopy = [];\r\n\r\n\t\t\tif ( uv === undefined ) {\r\n\r\n\t\t\t\tcontinue;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tfor ( var j = 0, jl = uv.length; j < jl; j ++ ) {\r\n\r\n\t\t\t\tuvCopy.push( uv[ j ].clone() );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tuvs1.push( uvCopy );\r\n\r\n\t\t}\r\n\r\n\t},\r\n\r\n\tmergeMesh: function ( mesh ) {\r\n\r\n\t\tif ( mesh instanceof THREE.Mesh === false ) {\r\n\r\n\t\t\tTHREE.error( 'THREE.Geometry.mergeMesh(): mesh not an instance of THREE.Mesh.', mesh );\r\n\t\t\treturn;\r\n\r\n\t\t}\r\n\r\n\t\tmesh.matrixAutoUpdate && mesh.updateMatrix();\r\n\r\n\t\tthis.merge( mesh.geometry, mesh.matrix );\r\n\r\n\t},\r\n\r\n\t/*\r\n\t * Checks for duplicate vertices with hashmap.\r\n\t * Duplicated vertices are removed\r\n\t * and faces' vertices are updated.\r\n\t */\r\n\r\n\tmergeVertices: function () {\r\n\r\n\t\tvar verticesMap = {}; // Hashmap for looking up vertice by position coordinates (and making sure they are unique)\r\n\t\tvar unique = [], changes = [];\r\n\r\n\t\tvar v, key;\r\n\t\tvar precisionPoints = 4; // number of decimal points, eg. 4 for epsilon of 0.0001\r\n\t\tvar precision = Math.pow( 10, precisionPoints );\r\n\t\tvar i, il, face;\r\n\t\tvar indices, j, jl;\r\n\r\n\t\tfor ( i = 0, il = this.vertices.length; i < il; i ++ ) {\r\n\r\n\t\t\tv = this.vertices[ i ];\r\n\t\t\tkey = Math.round( v.x * precision ) + '_' + Math.round( v.y * precision ) + '_' + Math.round( v.z * precision );\r\n\r\n\t\t\tif ( verticesMap[ key ] === undefined ) {\r\n\r\n\t\t\t\tverticesMap[ key ] = i;\r\n\t\t\t\tunique.push( this.vertices[ i ] );\r\n\t\t\t\tchanges[ i ] = unique.length - 1;\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\t//console.log('Duplicate vertex found. ', i, ' could be using ', verticesMap[key]);\r\n\t\t\t\tchanges[ i ] = changes[ verticesMap[ key ] ];\r\n\r\n\t\t\t}\r\n\r\n\t\t};\r\n\r\n\r\n\t\t// if faces are completely degenerate after merging vertices, we\r\n\t\t// have to remove them from the geometry.\r\n\t\tvar faceIndicesToRemove = [];\r\n\r\n\t\tfor ( i = 0, il = this.faces.length; i < il; i ++ ) {\r\n\r\n\t\t\tface = this.faces[ i ];\r\n\r\n\t\t\tface.a = changes[ face.a ];\r\n\t\t\tface.b = changes[ face.b ];\r\n\t\t\tface.c = changes[ face.c ];\r\n\r\n\t\t\tindices = [ face.a, face.b, face.c ];\r\n\r\n\t\t\tvar dupIndex = - 1;\r\n\r\n\t\t\t// if any duplicate vertices are found in a Face3\r\n\t\t\t// we have to remove the face as nothing can be saved\r\n\t\t\tfor ( var n = 0; n < 3; n ++ ) {\r\n\t\t\t\tif ( indices[ n ] == indices[ ( n + 1 ) % 3 ] ) {\r\n\r\n\t\t\t\t\tdupIndex = n;\r\n\t\t\t\t\tfaceIndicesToRemove.push( i );\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tfor ( i = faceIndicesToRemove.length - 1; i >= 0; i -- ) {\r\n\t\t\tvar idx = faceIndicesToRemove[ i ];\r\n\r\n\t\t\tthis.faces.splice( idx, 1 );\r\n\r\n\t\t\tfor ( j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) {\r\n\r\n\t\t\t\tthis.faceVertexUvs[ j ].splice( idx, 1 );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\t// Use unique set of vertices\r\n\r\n\t\tvar diff = this.vertices.length - unique.length;\r\n\t\tthis.vertices = unique;\r\n\t\treturn diff;\r\n\r\n\t},\r\n\r\n\ttoJSON: function () {\r\n\r\n\t\tvar output = {\r\n\t\t\tmetadata: {\r\n\t\t\t\tversion: 4.0,\r\n\t\t\t\ttype: 'BufferGeometry',\r\n\t\t\t\tgenerator: 'BufferGeometryExporter'\r\n\t\t\t},\r\n\t\t\tuuid: this.uuid,\r\n\t\t\ttype: this.type\r\n\t\t};\r\n\r\n\t\tif ( this.name !== \"\" ) output.name = this.name;\r\n\r\n\t\tif ( this.parameters !== undefined ) {\r\n\r\n\t\t\tvar parameters = this.parameters;\r\n\r\n\t\t\tfor ( var key in parameters ) {\r\n\r\n\t\t\t\tif ( parameters[ key ] !== undefined ) output[ key ] = parameters[ key ];\r\n\r\n\t\t\t}\r\n\r\n\t\t\treturn output;\r\n\r\n\t\t}\r\n\r\n\t\tvar vertices = [];\r\n\r\n\t\tfor ( var i = 0; i < this.vertices.length; i ++ ) {\r\n\r\n\t\t\tvar vertex = this.vertices[ i ];\r\n\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\r\n\r\n\t\t}\r\n\r\n\t\tvar faces = [];\r\n\t\tvar normals = [];\r\n\t\tvar normalsHash = {};\r\n\t\tvar colors = [];\r\n\t\tvar colorsHash = {};\r\n\t\tvar uvs = [];\r\n\t\tvar uvsHash = {};\r\n\r\n\t\tfor ( var i = 0; i < this.faces.length; i ++ ) {\r\n\r\n\t\t\tvar face = this.faces[ i ];\r\n\r\n\t\t\tvar hasMaterial = false; // face.materialIndex !== undefined;\r\n\t\t\tvar hasFaceUv = false; // deprecated\r\n\t\t\tvar hasFaceVertexUv = this.faceVertexUvs[ 0 ][ i ] !== undefined;\r\n\t\t\tvar hasFaceNormal = face.normal.length() > 0;\r\n\t\t\tvar hasFaceVertexNormal = face.vertexNormals.length > 0;\r\n\t\t\tvar hasFaceColor = face.color.r !== 1 || face.color.g !== 1 || face.color.b !== 1;\r\n\t\t\tvar hasFaceVertexColor = face.vertexColors.length > 0;\r\n\r\n\t\t\tvar faceType = 0;\r\n\r\n\t\t\tfaceType = setBit( faceType, 0, 0 );\r\n\t\t\tfaceType = setBit( faceType, 1, hasMaterial );\r\n\t\t\tfaceType = setBit( faceType, 2, hasFaceUv );\r\n\t\t\tfaceType = setBit( faceType, 3, hasFaceVertexUv );\r\n\t\t\tfaceType = setBit( faceType, 4, hasFaceNormal );\r\n\t\t\tfaceType = setBit( faceType, 5, hasFaceVertexNormal );\r\n\t\t\tfaceType = setBit( faceType, 6, hasFaceColor );\r\n\t\t\tfaceType = setBit( faceType, 7, hasFaceVertexColor );\r\n\r\n\t\t\tfaces.push( faceType );\r\n\t\t\tfaces.push( face.a, face.b, face.c );\r\n\r\n\r\n\t\t\t/*\r\n\t\t\tif ( hasMaterial ) {\r\n\r\n\t\t\t\tfaces.push( face.materialIndex );\r\n\r\n\t\t\t}\r\n\t\t\t*/\r\n\r\n\t\t\tif ( hasFaceVertexUv ) {\r\n\r\n\t\t\t\tvar faceVertexUvs = this.faceVertexUvs[ 0 ][ i ];\r\n\r\n\t\t\t\tfaces.push(\r\n\t\t\t\t\tgetUvIndex( faceVertexUvs[ 0 ] ),\r\n\t\t\t\t\tgetUvIndex( faceVertexUvs[ 1 ] ),\r\n\t\t\t\t\tgetUvIndex( faceVertexUvs[ 2 ] )\r\n\t\t\t\t);\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( hasFaceNormal ) {\r\n\r\n\t\t\t\tfaces.push( getNormalIndex( face.normal ) );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( hasFaceVertexNormal ) {\r\n\r\n\t\t\t\tvar vertexNormals = face.vertexNormals;\r\n\r\n\t\t\t\tfaces.push(\r\n\t\t\t\t\tgetNormalIndex( vertexNormals[ 0 ] ),\r\n\t\t\t\t\tgetNormalIndex( vertexNormals[ 1 ] ),\r\n\t\t\t\t\tgetNormalIndex( vertexNormals[ 2 ] )\r\n\t\t\t\t);\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( hasFaceColor ) {\r\n\r\n\t\t\t\tfaces.push( getColorIndex( face.color ) );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( hasFaceVertexColor ) {\r\n\r\n\t\t\t\tvar vertexColors = face.vertexColors;\r\n\r\n\t\t\t\tfaces.push(\r\n\t\t\t\t\tgetColorIndex( vertexColors[ 0 ] ),\r\n\t\t\t\t\tgetColorIndex( vertexColors[ 1 ] ),\r\n\t\t\t\t\tgetColorIndex( vertexColors[ 2 ] )\r\n\t\t\t\t);\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tfunction setBit( value, position, enabled ) {\r\n\r\n\t\t\treturn enabled ? value | ( 1 << position ) : value & ( ~ ( 1 << position) );\r\n\r\n\t\t}\r\n\r\n\t\tfunction getNormalIndex( normal ) {\r\n\r\n\t\t\tvar hash = normal.x.toString() + normal.y.toString() + normal.z.toString();\r\n\r\n\t\t\tif ( normalsHash[ hash ] !== undefined ) {\r\n\r\n\t\t\t\treturn normalsHash[ hash ];\r\n\r\n\t\t\t}\r\n\r\n\t\t\tnormalsHash[ hash ] = normals.length / 3;\r\n\t\t\tnormals.push( normal.x, normal.y, normal.z );\r\n\r\n\t\t\treturn normalsHash[ hash ];\r\n\r\n\t\t}\r\n\r\n\t\tfunction getColorIndex( color ) {\r\n\r\n\t\t\tvar hash = color.r.toString() + color.g.toString() + color.b.toString();\r\n\r\n\t\t\tif ( colorsHash[ hash ] !== undefined ) {\r\n\r\n\t\t\t\treturn colorsHash[ hash ];\r\n\r\n\t\t\t}\r\n\r\n\t\t\tcolorsHash[ hash ] = colors.length;\r\n\t\t\tcolors.push( color.getHex() );\r\n\r\n\t\t\treturn colorsHash[ hash ];\r\n\r\n\t\t}\r\n\r\n\t\tfunction getUvIndex( uv ) {\r\n\r\n\t\t\tvar hash = uv.x.toString() + uv.y.toString();\r\n\r\n\t\t\tif ( uvsHash[ hash ] !== undefined ) {\r\n\r\n\t\t\t\treturn uvsHash[ hash ];\r\n\r\n\t\t\t}\r\n\r\n\t\t\tuvsHash[ hash ] = uvs.length / 2;\r\n\t\t\tuvs.push( uv.x, uv.y );\r\n\r\n\t\t\treturn uvsHash[ hash ];\r\n\r\n\t\t}\r\n\r\n\t\toutput.data = {};\r\n\r\n\t\toutput.data.vertices = vertices;\r\n\t\toutput.data.normals = normals;\r\n\t\tif ( colors.length > 0 ) output.data.colors = colors;\r\n\t\tif ( uvs.length > 0 ) output.data.uvs = [ uvs ]; // temporal backward compatibility\r\n\t\toutput.data.faces = faces;\r\n\r\n\t\t//\r\n\r\n\t\treturn output;\r\n\r\n\t},\r\n\r\n\tclone: function () {\r\n\r\n\t\tvar geometry = new THREE.Geometry();\r\n\r\n\t\tvar vertices = this.vertices;\r\n\r\n\t\tfor ( var i = 0, il = vertices.length; i < il; i ++ ) {\r\n\r\n\t\t\tgeometry.vertices.push( vertices[ i ].clone() );\r\n\r\n\t\t}\r\n\r\n\t\tvar faces = this.faces;\r\n\r\n\t\tfor ( var i = 0, il = faces.length; i < il; i ++ ) {\r\n\r\n\t\t\tgeometry.faces.push( faces[ i ].clone() );\r\n\r\n\t\t}\r\n\r\n\t\tfor ( var i = 0, il = this.faceVertexUvs.length; i < il; i ++ ) {\r\n\r\n\t\t\tvar faceVertexUvs = this.faceVertexUvs[ i ];\r\n\r\n\t\t\tif ( geometry.faceVertexUvs[ i ] === undefined ) {\r\n\r\n\t\t\t\tgeometry.faceVertexUvs[ i ] = [];\r\n\r\n\t\t\t}\r\n\r\n\t\t\tfor ( var j = 0, jl = faceVertexUvs.length; j < jl; j ++ ) {\r\n\r\n\t\t\t\tvar uvs = faceVertexUvs[ j ], uvsCopy = [];\r\n\r\n\t\t\t\tfor ( var k = 0, kl = uvs.length; k < kl; k ++ ) {\r\n\r\n\t\t\t\t\tvar uv = uvs[ k ];\r\n\r\n\t\t\t\t\tuvsCopy.push( uv.clone() );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tgeometry.faceVertexUvs[ i ].push( uvsCopy );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\treturn geometry;\r\n\r\n\t},\r\n\r\n\tdispose: function () {\r\n\r\n\t\tthis.dispatchEvent( { type: 'dispose' } );\r\n\r\n\t}\r\n\r\n};\r\n\r\nTHREE.EventDispatcher.prototype.apply( THREE.Geometry.prototype );\r\n\r\nTHREE.GeometryIdCount = 0;\r\n\r\n// File:src/cameras/Camera.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n * @author mikael emtinger / http://gomo.se/\r\n * @author WestLangley / http://github.com/WestLangley\r\n*/\r\n\r\nTHREE.Camera = function () {\r\n\r\n\tTHREE.Object3D.call( this );\r\n\r\n\tthis.type = 'Camera';\r\n\r\n\tthis.matrixWorldInverse = new THREE.Matrix4();\r\n\tthis.projectionMatrix = new THREE.Matrix4();\r\n\r\n};\r\n\r\nTHREE.Camera.prototype = Object.create( THREE.Object3D.prototype );\r\nTHREE.Camera.prototype.constructor = THREE.Camera;\r\n\r\nTHREE.Camera.prototype.getWorldDirection = function () {\r\n\r\n\tvar quaternion = new THREE.Quaternion();\r\n\r\n\treturn function ( optionalTarget ) {\r\n\r\n\t\tvar result = optionalTarget || new THREE.Vector3();\r\n\r\n\t\tthis.getWorldQuaternion( quaternion );\r\n\r\n\t\treturn result.set( 0, 0, - 1 ).applyQuaternion( quaternion );\r\n\r\n\t}\r\n\r\n}();\r\n\r\nTHREE.Camera.prototype.lookAt = function () {\r\n\r\n\t// This routine does not support cameras with rotated and/or translated parent(s)\r\n\r\n\tvar m1 = new THREE.Matrix4();\r\n\r\n\treturn function ( vector ) {\r\n\r\n\t\tm1.lookAt( this.position, vector, this.up );\r\n\r\n\t\tthis.quaternion.setFromRotationMatrix( m1 );\r\n\r\n\t};\r\n\r\n}();\r\n\r\nTHREE.Camera.prototype.clone = function ( camera ) {\r\n\r\n\tif ( camera === undefined ) camera = new THREE.Camera();\r\n\r\n\tTHREE.Object3D.prototype.clone.call( this, camera );\r\n\r\n\tcamera.matrixWorldInverse.copy( this.matrixWorldInverse );\r\n\tcamera.projectionMatrix.copy( this.projectionMatrix );\r\n\r\n\treturn camera;\r\n};\r\n\r\n// File:src/cameras/CubeCamera.js\r\n\r\n/**\r\n * Camera for rendering cube maps\r\n *\t- renders scene into axis-aligned cube\r\n *\r\n * @author alteredq / http://alteredqualia.com/\r\n */\r\n\r\nTHREE.CubeCamera = function ( near, far, cubeResolution ) {\r\n\r\n\tTHREE.Object3D.call( this );\r\n\r\n\tthis.type = 'CubeCamera';\r\n\r\n\tvar fov = 90, aspect = 1;\r\n\r\n\tvar cameraPX = new THREE.PerspectiveCamera( fov, aspect, near, far );\r\n\tcameraPX.up.set( 0, - 1, 0 );\r\n\tcameraPX.lookAt( new THREE.Vector3( 1, 0, 0 ) );\r\n\tthis.add( cameraPX );\r\n\r\n\tvar cameraNX = new THREE.PerspectiveCamera( fov, aspect, near, far );\r\n\tcameraNX.up.set( 0, - 1, 0 );\r\n\tcameraNX.lookAt( new THREE.Vector3( - 1, 0, 0 ) );\r\n\tthis.add( cameraNX );\r\n\r\n\tvar cameraPY = new THREE.PerspectiveCamera( fov, aspect, near, far );\r\n\tcameraPY.up.set( 0, 0, 1 );\r\n\tcameraPY.lookAt( new THREE.Vector3( 0, 1, 0 ) );\r\n\tthis.add( cameraPY );\r\n\r\n\tvar cameraNY = new THREE.PerspectiveCamera( fov, aspect, near, far );\r\n\tcameraNY.up.set( 0, 0, - 1 );\r\n\tcameraNY.lookAt( new THREE.Vector3( 0, - 1, 0 ) );\r\n\tthis.add( cameraNY );\r\n\r\n\tvar cameraPZ = new THREE.PerspectiveCamera( fov, aspect, near, far );\r\n\tcameraPZ.up.set( 0, - 1, 0 );\r\n\tcameraPZ.lookAt( new THREE.Vector3( 0, 0, 1 ) );\r\n\tthis.add( cameraPZ );\r\n\r\n\tvar cameraNZ = new THREE.PerspectiveCamera( fov, aspect, near, far );\r\n\tcameraNZ.up.set( 0, - 1, 0 );\r\n\tcameraNZ.lookAt( new THREE.Vector3( 0, 0, - 1 ) );\r\n\tthis.add( cameraNZ );\r\n\r\n\tthis.renderTarget = new THREE.WebGLRenderTargetCube( cubeResolution, cubeResolution, { format: THREE.RGBFormat, magFilter: THREE.LinearFilter, minFilter: THREE.LinearFilter } );\r\n\r\n\tthis.updateCubeMap = function ( renderer, scene ) {\r\n\r\n\t\tvar renderTarget = this.renderTarget;\r\n\t\tvar generateMipmaps = renderTarget.generateMipmaps;\r\n\r\n\t\trenderTarget.generateMipmaps = false;\r\n\r\n\t\trenderTarget.activeCubeFace = 0;\r\n\t\trenderer.render( scene, cameraPX, renderTarget );\r\n\r\n\t\trenderTarget.activeCubeFace = 1;\r\n\t\trenderer.render( scene, cameraNX, renderTarget );\r\n\r\n\t\trenderTarget.activeCubeFace = 2;\r\n\t\trenderer.render( scene, cameraPY, renderTarget );\r\n\r\n\t\trenderTarget.activeCubeFace = 3;\r\n\t\trenderer.render( scene, cameraNY, renderTarget );\r\n\r\n\t\trenderTarget.activeCubeFace = 4;\r\n\t\trenderer.render( scene, cameraPZ, renderTarget );\r\n\r\n\t\trenderTarget.generateMipmaps = generateMipmaps;\r\n\r\n\t\trenderTarget.activeCubeFace = 5;\r\n\t\trenderer.render( scene, cameraNZ, renderTarget );\r\n\r\n\t};\r\n\r\n};\r\n\r\nTHREE.CubeCamera.prototype = Object.create( THREE.Object3D.prototype );\r\nTHREE.CubeCamera.prototype.constructor = THREE.CubeCamera;\r\n\r\n// File:src/cameras/OrthographicCamera.js\r\n\r\n/**\r\n * @author alteredq / http://alteredqualia.com/\r\n */\r\n\r\nTHREE.OrthographicCamera = function ( left, right, top, bottom, near, far ) {\r\n\r\n\tTHREE.Camera.call( this );\r\n\r\n\tthis.type = 'OrthographicCamera';\r\n\r\n\tthis.zoom = 1;\r\n\r\n\tthis.left = left;\r\n\tthis.right = right;\r\n\tthis.top = top;\r\n\tthis.bottom = bottom;\r\n\r\n\tthis.near = ( near !== undefined ) ? near : 0.1;\r\n\tthis.far = ( far !== undefined ) ? far : 2000;\r\n\r\n\tthis.updateProjectionMatrix();\r\n\r\n};\r\n\r\nTHREE.OrthographicCamera.prototype = Object.create( THREE.Camera.prototype );\r\nTHREE.OrthographicCamera.prototype.constructor = THREE.OrthographicCamera;\r\n\r\nTHREE.OrthographicCamera.prototype.updateProjectionMatrix = function () {\r\n\r\n\tvar dx = ( this.right - this.left ) / ( 2 * this.zoom );\r\n\tvar dy = ( this.top - this.bottom ) / ( 2 * this.zoom );\r\n\tvar cx = ( this.right + this.left ) / 2;\r\n\tvar cy = ( this.top + this.bottom ) / 2;\r\n\r\n\tthis.projectionMatrix.makeOrthographic( cx - dx, cx + dx, cy + dy, cy - dy, this.near, this.far );\r\n\r\n};\r\n\r\nTHREE.OrthographicCamera.prototype.clone = function () {\r\n\r\n\tvar camera = new THREE.OrthographicCamera();\r\n\r\n\tTHREE.Camera.prototype.clone.call( this, camera );\r\n\r\n\tcamera.zoom = this.zoom;\r\n\r\n\tcamera.left = this.left;\r\n\tcamera.right = this.right;\r\n\tcamera.top = this.top;\r\n\tcamera.bottom = this.bottom;\r\n\r\n\tcamera.near = this.near;\r\n\tcamera.far = this.far;\r\n\r\n\tcamera.projectionMatrix.copy( this.projectionMatrix );\r\n\r\n\treturn camera;\r\n};\r\n\r\n// File:src/cameras/PerspectiveCamera.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n * @author greggman / http://games.greggman.com/\r\n * @author zz85 / http://www.lab4games.net/zz85/blog\r\n */\r\n\r\nTHREE.PerspectiveCamera = function ( fov, aspect, near, far ) {\r\n\r\n\tTHREE.Camera.call( this );\r\n\r\n\tthis.type = 'PerspectiveCamera';\r\n\r\n\tthis.zoom = 1;\r\n\r\n\tthis.fov = fov !== undefined ? fov : 50;\r\n\tthis.aspect = aspect !== undefined ? aspect : 1;\r\n\tthis.near = near !== undefined ? near : 0.1;\r\n\tthis.far = far !== undefined ? far : 2000;\r\n\r\n\tthis.updateProjectionMatrix();\r\n\r\n};\r\n\r\nTHREE.PerspectiveCamera.prototype = Object.create( THREE.Camera.prototype );\r\nTHREE.PerspectiveCamera.prototype.constructor = THREE.PerspectiveCamera;\r\n\r\n\r\n/**\r\n * Uses Focal Length (in mm) to estimate and set FOV\r\n * 35mm (fullframe) camera is used if frame size is not specified;\r\n * Formula based on http://www.bobatkins.com/photography/technical/field_of_view.html\r\n */\r\n\r\nTHREE.PerspectiveCamera.prototype.setLens = function ( focalLength, frameHeight ) {\r\n\r\n\tif ( frameHeight === undefined ) frameHeight = 24;\r\n\r\n\tthis.fov = 2 * THREE.Math.radToDeg( Math.atan( frameHeight / ( focalLength * 2 ) ) );\r\n\tthis.updateProjectionMatrix();\r\n\r\n}\r\n\r\n\r\n/**\r\n * Sets an offset in a larger frustum. This is useful for multi-window or\r\n * multi-monitor/multi-machine setups.\r\n *\r\n * For example, if you have 3x2 monitors and each monitor is 1920x1080 and\r\n * the monitors are in grid like this\r\n *\r\n * +---+---+---+\r\n * | A | B | C |\r\n * +---+---+---+\r\n * | D | E | F |\r\n * +---+---+---+\r\n *\r\n * then for each monitor you would call it like this\r\n *\r\n * var w = 1920;\r\n * var h = 1080;\r\n * var fullWidth = w * 3;\r\n * var fullHeight = h * 2;\r\n *\r\n * --A--\r\n * camera.setOffset( fullWidth, fullHeight, w * 0, h * 0, w, h );\r\n * --B--\r\n * camera.setOffset( fullWidth, fullHeight, w * 1, h * 0, w, h );\r\n * --C--\r\n * camera.setOffset( fullWidth, fullHeight, w * 2, h * 0, w, h );\r\n * --D--\r\n * camera.setOffset( fullWidth, fullHeight, w * 0, h * 1, w, h );\r\n * --E--\r\n * camera.setOffset( fullWidth, fullHeight, w * 1, h * 1, w, h );\r\n * --F--\r\n * camera.setOffset( fullWidth, fullHeight, w * 2, h * 1, w, h );\r\n *\r\n * Note there is no reason monitors have to be the same size or in a grid.\r\n */\r\n\r\nTHREE.PerspectiveCamera.prototype.setViewOffset = function ( fullWidth, fullHeight, x, y, width, height ) {\r\n\r\n\tthis.fullWidth = fullWidth;\r\n\tthis.fullHeight = fullHeight;\r\n\tthis.x = x;\r\n\tthis.y = y;\r\n\tthis.width = width;\r\n\tthis.height = height;\r\n\r\n\tthis.updateProjectionMatrix();\r\n\r\n};\r\n\r\n\r\nTHREE.PerspectiveCamera.prototype.updateProjectionMatrix = function () {\r\n\r\n\tvar fov = THREE.Math.radToDeg( 2 * Math.atan( Math.tan( THREE.Math.degToRad( this.fov ) * 0.5 ) / this.zoom ) );\r\n\r\n\tif ( this.fullWidth ) {\r\n\r\n\t\tvar aspect = this.fullWidth / this.fullHeight;\r\n\t\tvar top = Math.tan( THREE.Math.degToRad( fov * 0.5 ) ) * this.near;\r\n\t\tvar bottom = - top;\r\n\t\tvar left = aspect * bottom;\r\n\t\tvar right = aspect * top;\r\n\t\tvar width = Math.abs( right - left );\r\n\t\tvar height = Math.abs( top - bottom );\r\n\r\n\t\tthis.projectionMatrix.makeFrustum(\r\n\t\t\tleft + this.x * width / this.fullWidth,\r\n\t\t\tleft + ( this.x + this.width ) * width / this.fullWidth,\r\n\t\t\ttop - ( this.y + this.height ) * height / this.fullHeight,\r\n\t\t\ttop - this.y * height / this.fullHeight,\r\n\t\t\tthis.near,\r\n\t\t\tthis.far\r\n\t\t);\r\n\r\n\t} else {\r\n\r\n\t\tthis.projectionMatrix.makePerspective( fov, this.aspect, this.near, this.far );\r\n\r\n\t}\r\n\r\n};\r\n\r\nTHREE.PerspectiveCamera.prototype.clone = function () {\r\n\r\n\tvar camera = new THREE.PerspectiveCamera();\r\n\r\n\tTHREE.Camera.prototype.clone.call( this, camera );\r\n\r\n\tcamera.zoom = this.zoom;\r\n\r\n\tcamera.fov = this.fov;\r\n\tcamera.aspect = this.aspect;\r\n\tcamera.near = this.near;\r\n\tcamera.far = this.far;\r\n\r\n\tcamera.projectionMatrix.copy( this.projectionMatrix );\r\n\r\n\treturn camera;\r\n\r\n};\r\n\r\n// File:src/lights/Light.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n * @author alteredq / http://alteredqualia.com/\r\n */\r\n\r\nTHREE.Light = function ( color ) {\r\n\r\n\tTHREE.Object3D.call( this );\r\n\r\n\tthis.type = 'Light';\r\n\t\r\n\tthis.color = new THREE.Color( color );\r\n\r\n};\r\n\r\nTHREE.Light.prototype = Object.create( THREE.Object3D.prototype );\r\nTHREE.Light.prototype.constructor = THREE.Light;\r\n\r\nTHREE.Light.prototype.clone = function ( light ) {\r\n\r\n\tif ( light === undefined ) light = new THREE.Light();\r\n\r\n\tTHREE.Object3D.prototype.clone.call( this, light );\r\n\r\n\tlight.color.copy( this.color );\r\n\r\n\treturn light;\r\n\r\n};\r\n\r\n// File:src/lights/AmbientLight.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n */\r\n\r\nTHREE.AmbientLight = function ( color ) {\r\n\r\n\tTHREE.Light.call( this, color );\r\n\r\n\tthis.type = 'AmbientLight';\r\n\r\n};\r\n\r\nTHREE.AmbientLight.prototype = Object.create( THREE.Light.prototype );\r\nTHREE.AmbientLight.prototype.constructor = THREE.AmbientLight;\r\n\r\nTHREE.AmbientLight.prototype.clone = function () {\r\n\r\n\tvar light = new THREE.AmbientLight();\r\n\r\n\tTHREE.Light.prototype.clone.call( this, light );\r\n\r\n\treturn light;\r\n\r\n};\r\n\r\n// File:src/lights/AreaLight.js\r\n\r\n/**\r\n * @author MPanknin / http://www.redplant.de/\r\n * @author alteredq / http://alteredqualia.com/\r\n */\r\n\r\nTHREE.AreaLight = function ( color, intensity ) {\r\n\r\n\tTHREE.Light.call( this, color );\r\n\r\n\tthis.type = 'AreaLight';\r\n\r\n\tthis.normal = new THREE.Vector3( 0, - 1, 0 );\r\n\tthis.right = new THREE.Vector3( 1, 0, 0 );\r\n\r\n\tthis.intensity = ( intensity !== undefined ) ? intensity : 1;\r\n\r\n\tthis.width = 1.0;\r\n\tthis.height = 1.0;\r\n\r\n\tthis.constantAttenuation = 1.5;\r\n\tthis.linearAttenuation = 0.5;\r\n\tthis.quadraticAttenuation = 0.1;\r\n\r\n};\r\n\r\nTHREE.AreaLight.prototype = Object.create( THREE.Light.prototype );\r\nTHREE.AreaLight.prototype.constructor = THREE.AreaLight;\r\n\r\n\r\n// File:src/lights/DirectionalLight.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n * @author alteredq / http://alteredqualia.com/\r\n */\r\n\r\nTHREE.DirectionalLight = function ( color, intensity ) {\r\n\r\n\tTHREE.Light.call( this, color );\r\n\r\n\tthis.type = 'DirectionalLight';\r\n\r\n\tthis.position.set( 0, 1, 0 );\r\n\tthis.target = new THREE.Object3D();\r\n\r\n\tthis.intensity = ( intensity !== undefined ) ? intensity : 1;\r\n\r\n\tthis.castShadow = false;\r\n\tthis.onlyShadow = false;\r\n\r\n\t//\r\n\r\n\tthis.shadowCameraNear = 50;\r\n\tthis.shadowCameraFar = 5000;\r\n\r\n\tthis.shadowCameraLeft = - 500;\r\n\tthis.shadowCameraRight = 500;\r\n\tthis.shadowCameraTop = 500;\r\n\tthis.shadowCameraBottom = - 500;\r\n\r\n\tthis.shadowCameraVisible = false;\r\n\r\n\tthis.shadowBias = 0;\r\n\tthis.shadowDarkness = 0.5;\r\n\r\n\tthis.shadowMapWidth = 512;\r\n\tthis.shadowMapHeight = 512;\r\n\r\n\t//\r\n\r\n\tthis.shadowCascade = false;\r\n\r\n\tthis.shadowCascadeOffset = new THREE.Vector3( 0, 0, - 1000 );\r\n\tthis.shadowCascadeCount = 2;\r\n\r\n\tthis.shadowCascadeBias = [ 0, 0, 0 ];\r\n\tthis.shadowCascadeWidth = [ 512, 512, 512 ];\r\n\tthis.shadowCascadeHeight = [ 512, 512, 512 ];\r\n\r\n\tthis.shadowCascadeNearZ = [ - 1.000, 0.990, 0.998 ];\r\n\tthis.shadowCascadeFarZ = [ 0.990, 0.998, 1.000 ];\r\n\r\n\tthis.shadowCascadeArray = [];\r\n\r\n\t//\r\n\r\n\tthis.shadowMap = null;\r\n\tthis.shadowMapSize = null;\r\n\tthis.shadowCamera = null;\r\n\tthis.shadowMatrix = null;\r\n\r\n};\r\n\r\nTHREE.DirectionalLight.prototype = Object.create( THREE.Light.prototype );\r\nTHREE.DirectionalLight.prototype.constructor = THREE.DirectionalLight;\r\n\r\nTHREE.DirectionalLight.prototype.clone = function () {\r\n\r\n\tvar light = new THREE.DirectionalLight();\r\n\r\n\tTHREE.Light.prototype.clone.call( this, light );\r\n\r\n\tlight.target = this.target.clone();\r\n\r\n\tlight.intensity = this.intensity;\r\n\r\n\tlight.castShadow = this.castShadow;\r\n\tlight.onlyShadow = this.onlyShadow;\r\n\r\n\t//\r\n\r\n\tlight.shadowCameraNear = this.shadowCameraNear;\r\n\tlight.shadowCameraFar = this.shadowCameraFar;\r\n\r\n\tlight.shadowCameraLeft = this.shadowCameraLeft;\r\n\tlight.shadowCameraRight = this.shadowCameraRight;\r\n\tlight.shadowCameraTop = this.shadowCameraTop;\r\n\tlight.shadowCameraBottom = this.shadowCameraBottom;\r\n\r\n\tlight.shadowCameraVisible = this.shadowCameraVisible;\r\n\r\n\tlight.shadowBias = this.shadowBias;\r\n\tlight.shadowDarkness = this.shadowDarkness;\r\n\r\n\tlight.shadowMapWidth = this.shadowMapWidth;\r\n\tlight.shadowMapHeight = this.shadowMapHeight;\r\n\r\n\t//\r\n\r\n\tlight.shadowCascade = this.shadowCascade;\r\n\r\n\tlight.shadowCascadeOffset.copy( this.shadowCascadeOffset );\r\n\tlight.shadowCascadeCount = this.shadowCascadeCount;\r\n\r\n\tlight.shadowCascadeBias = this.shadowCascadeBias.slice( 0 );\r\n\tlight.shadowCascadeWidth = this.shadowCascadeWidth.slice( 0 );\r\n\tlight.shadowCascadeHeight = this.shadowCascadeHeight.slice( 0 );\r\n\r\n\tlight.shadowCascadeNearZ = this.shadowCascadeNearZ.slice( 0 );\r\n\tlight.shadowCascadeFarZ = this.shadowCascadeFarZ.slice( 0 );\r\n\r\n\treturn light;\r\n\r\n};\r\n\r\n// File:src/lights/HemisphereLight.js\r\n\r\n/**\r\n * @author alteredq / http://alteredqualia.com/\r\n */\r\n\r\nTHREE.HemisphereLight = function ( skyColor, groundColor, intensity ) {\r\n\r\n\tTHREE.Light.call( this, skyColor );\r\n\r\n\tthis.type = 'HemisphereLight';\r\n\r\n\tthis.position.set( 0, 100, 0 );\r\n\r\n\tthis.groundColor = new THREE.Color( groundColor );\r\n\tthis.intensity = ( intensity !== undefined ) ? intensity : 1;\r\n\r\n};\r\n\r\nTHREE.HemisphereLight.prototype = Object.create( THREE.Light.prototype );\r\nTHREE.HemisphereLight.prototype.constructor = THREE.HemisphereLight;\r\n\r\nTHREE.HemisphereLight.prototype.clone = function () {\r\n\r\n\tvar light = new THREE.HemisphereLight();\r\n\r\n\tTHREE.Light.prototype.clone.call( this, light );\r\n\r\n\tlight.groundColor.copy( this.groundColor );\r\n\tlight.intensity = this.intensity;\r\n\r\n\treturn light;\r\n\r\n};\r\n\r\n// File:src/lights/PointLight.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n */\r\n\r\nTHREE.PointLight = function ( color, intensity, distance, decay ) {\r\n\r\n\tTHREE.Light.call( this, color );\r\n\r\n\tthis.type = 'PointLight';\r\n\r\n\tthis.intensity = ( intensity !== undefined ) ? intensity : 1;\r\n\tthis.distance = ( distance !== undefined ) ? distance : 0;\r\n\tthis.decay = ( decay !== undefined ) ? decay : 1;\t// for physically correct lights, should be 2.\r\n\r\n};\r\n\r\nTHREE.PointLight.prototype = Object.create( THREE.Light.prototype );\r\nTHREE.PointLight.prototype.constructor = THREE.PointLight;\r\n\r\nTHREE.PointLight.prototype.clone = function () {\r\n\r\n\tvar light = new THREE.PointLight();\r\n\r\n\tTHREE.Light.prototype.clone.call( this, light );\r\n\r\n\tlight.intensity = this.intensity;\r\n\tlight.distance = this.distance;\r\n\tlight.decay = this.decay;\r\n\r\n\treturn light;\r\n\r\n};\r\n\r\n// File:src/lights/SpotLight.js\r\n\r\n/**\r\n * @author alteredq / http://alteredqualia.com/\r\n */\r\n\r\nTHREE.SpotLight = function ( color, intensity, distance, angle, exponent, decay ) {\r\n\r\n\tTHREE.Light.call( this, color );\r\n\r\n\tthis.type = 'SpotLight';\r\n\r\n\tthis.position.set( 0, 1, 0 );\r\n\tthis.target = new THREE.Object3D();\r\n\r\n\tthis.intensity = ( intensity !== undefined ) ? intensity : 1;\r\n\tthis.distance = ( distance !== undefined ) ? distance : 0;\r\n\tthis.angle = ( angle !== undefined ) ? angle : Math.PI / 3;\r\n\tthis.exponent = ( exponent !== undefined ) ? exponent : 10;\r\n\tthis.decay = ( decay !== undefined ) ? decay : 1;\t// for physically correct lights, should be 2.\r\n\r\n\tthis.castShadow = false;\r\n\tthis.onlyShadow = false;\r\n\r\n\t//\r\n\r\n\tthis.shadowCameraNear = 50;\r\n\tthis.shadowCameraFar = 5000;\r\n\tthis.shadowCameraFov = 50;\r\n\r\n\tthis.shadowCameraVisible = false;\r\n\r\n\tthis.shadowBias = 0;\r\n\tthis.shadowDarkness = 0.5;\r\n\r\n\tthis.shadowMapWidth = 512;\r\n\tthis.shadowMapHeight = 512;\r\n\r\n\t//\r\n\r\n\tthis.shadowMap = null;\r\n\tthis.shadowMapSize = null;\r\n\tthis.shadowCamera = null;\r\n\tthis.shadowMatrix = null;\r\n\r\n};\r\n\r\nTHREE.SpotLight.prototype = Object.create( THREE.Light.prototype );\r\nTHREE.SpotLight.prototype.constructor = THREE.SpotLight;\r\n\r\nTHREE.SpotLight.prototype.clone = function () {\r\n\r\n\tvar light = new THREE.SpotLight();\r\n\r\n\tTHREE.Light.prototype.clone.call( this, light );\r\n\r\n\tlight.target = this.target.clone();\r\n\r\n\tlight.intensity = this.intensity;\r\n\tlight.distance = this.distance;\r\n\tlight.angle = this.angle;\r\n\tlight.exponent = this.exponent;\r\n\tlight.decay = this.decay;\r\n\r\n\tlight.castShadow = this.castShadow;\r\n\tlight.onlyShadow = this.onlyShadow;\r\n\r\n\t//\r\n\r\n\tlight.shadowCameraNear = this.shadowCameraNear;\r\n\tlight.shadowCameraFar = this.shadowCameraFar;\r\n\tlight.shadowCameraFov = this.shadowCameraFov;\r\n\r\n\tlight.shadowCameraVisible = this.shadowCameraVisible;\r\n\r\n\tlight.shadowBias = this.shadowBias;\r\n\tlight.shadowDarkness = this.shadowDarkness;\r\n\r\n\tlight.shadowMapWidth = this.shadowMapWidth;\r\n\tlight.shadowMapHeight = this.shadowMapHeight;\r\n\r\n\treturn light;\r\n\r\n};\r\n\r\n// File:src/loaders/Cache.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n */\r\n\r\nTHREE.Cache = {\r\n\r\n\tfiles: {},\r\n\r\n\tadd: function ( key, file ) {\r\n\r\n\t\t// console.log( 'THREE.Cache', 'Adding key:', key );\r\n\r\n\t\tthis.files[ key ] = file;\r\n\r\n\t},\r\n\r\n\tget: function ( key ) {\r\n\r\n\t\t// console.log( 'THREE.Cache', 'Checking key:', key );\r\n\r\n\t\treturn this.files[ key ];\r\n\r\n\t},\r\n\r\n\tremove: function ( key ) {\r\n\r\n\t\tdelete this.files[ key ];\r\n\r\n\t},\r\n\r\n\tclear: function () {\r\n\r\n\t\tthis.files = {}\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/loaders/Loader.js\r\n\r\n/**\r\n * @author alteredq / http://alteredqualia.com/\r\n */\r\n\r\nTHREE.Loader = function ( showStatus ) {\r\n\r\n\tthis.showStatus = showStatus;\r\n\tthis.statusDomElement = showStatus ? THREE.Loader.prototype.addStatusElement() : null;\r\n\r\n\tthis.imageLoader = new THREE.ImageLoader();\r\n\r\n\tthis.onLoadStart = function () {};\r\n\tthis.onLoadProgress = function () {};\r\n\tthis.onLoadComplete = function () {};\r\n\r\n};\r\n\r\nTHREE.Loader.prototype = {\r\n\r\n\tconstructor: THREE.Loader,\r\n\r\n\tcrossOrigin: undefined,\r\n\r\n\taddStatusElement: function () {\r\n\r\n\t\tvar e = document.createElement( 'div' );\r\n\r\n\t\te.style.position = 'absolute';\r\n\t\te.style.right = '0px';\r\n\t\te.style.top = '0px';\r\n\t\te.style.fontSize = '0.8em';\r\n\t\te.style.textAlign = 'left';\r\n\t\te.style.background = 'rgba(0,0,0,0.25)';\r\n\t\te.style.color = '#fff';\r\n\t\te.style.width = '120px';\r\n\t\te.style.padding = '0.5em 0.5em 0.5em 0.5em';\r\n\t\te.style.zIndex = 1000;\r\n\r\n\t\te.innerHTML = 'Loading ...';\r\n\r\n\t\treturn e;\r\n\r\n\t},\r\n\r\n\tupdateProgress: function ( progress ) {\r\n\r\n\t\tvar message = 'Loaded ';\r\n\r\n\t\tif ( progress.total ) {\r\n\r\n\t\t\tmessage += ( 100 * progress.loaded / progress.total ).toFixed( 0 ) + '%';\r\n\r\n\r\n\t\t} else {\r\n\r\n\t\t\tmessage += ( progress.loaded / 1024 ).toFixed( 2 ) + ' KB';\r\n\r\n\t\t}\r\n\r\n\t\tthis.statusDomElement.innerHTML = message;\r\n\r\n\t},\r\n\r\n\textractUrlBase: function ( url ) {\r\n\r\n\t\tvar parts = url.split( '/' );\r\n\r\n\t\tif ( parts.length === 1 ) return './';\r\n\r\n\t\tparts.pop();\r\n\r\n\t\treturn parts.join( '/' ) + '/';\r\n\r\n\t},\r\n\r\n\tinitMaterials: function ( materials, texturePath ) {\r\n\r\n\t\tvar array = [];\r\n\r\n\t\tfor ( var i = 0; i < materials.length; ++ i ) {\r\n\r\n\t\t\tarray[ i ] = this.createMaterial( materials[ i ], texturePath );\r\n\r\n\t\t}\r\n\r\n\t\treturn array;\r\n\r\n\t},\r\n\r\n\tneedsTangents: function ( materials ) {\r\n\r\n\t\tfor ( var i = 0, il = materials.length; i < il; i ++ ) {\r\n\r\n\t\t\tvar m = materials[ i ];\r\n\r\n\t\t\tif ( m instanceof THREE.ShaderMaterial ) return true;\r\n\r\n\t\t}\r\n\r\n\t\treturn false;\r\n\r\n\t},\r\n\r\n\tcreateMaterial: function ( m, texturePath ) {\r\n\r\n\t\tvar scope = this;\r\n\r\n\t\tfunction nearest_pow2( n ) {\r\n\r\n\t\t\tvar l = Math.log( n ) / Math.LN2;\r\n\t\t\treturn Math.pow( 2, Math.round( l ) );\r\n\r\n\t\t}\r\n\r\n\t\tfunction create_texture( where, name, sourceFile, repeat, offset, wrap, anisotropy ) {\r\n\r\n\t\t\tvar fullPath = texturePath + sourceFile;\r\n\r\n\t\t\tvar texture;\r\n\r\n\t\t\tvar loader = THREE.Loader.Handlers.get( fullPath );\r\n\r\n\t\t\tif ( loader !== null ) {\r\n\r\n\t\t\t\ttexture = loader.load( fullPath );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\ttexture = new THREE.Texture();\r\n\r\n\t\t\t\tloader = scope.imageLoader;\r\n\t\t\t\tloader.crossOrigin = scope.crossOrigin;\r\n\t\t\t\tloader.load( fullPath, function ( image ) {\r\n\r\n\t\t\t\t\tif ( THREE.Math.isPowerOfTwo( image.width ) === false ||\r\n\t\t\t\t\t\t THREE.Math.isPowerOfTwo( image.height ) === false ) {\r\n\r\n\t\t\t\t\t\tvar width = nearest_pow2( image.width );\r\n\t\t\t\t\t\tvar height = nearest_pow2( image.height );\r\n\r\n\t\t\t\t\t\tvar canvas = document.createElement( 'canvas' );\r\n\t\t\t\t\t\tcanvas.width = width;\r\n\t\t\t\t\t\tcanvas.height = height;\r\n\r\n\t\t\t\t\t\tvar context = canvas.getContext( '2d' );\r\n\t\t\t\t\t\tcontext.drawImage( image, 0, 0, width, height );\r\n\r\n\t\t\t\t\t\ttexture.image = canvas;\r\n\r\n\t\t\t\t\t} else {\r\n\r\n\t\t\t\t\t\ttexture.image = image;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\ttexture.needsUpdate = true;\r\n\r\n\t\t\t\t} );\r\n\r\n\t\t\t}\r\n\r\n\t\t\ttexture.sourceFile = sourceFile;\r\n\r\n\t\t\tif ( repeat ) {\r\n\r\n\t\t\t\ttexture.repeat.set( repeat[ 0 ], repeat[ 1 ] );\r\n\r\n\t\t\t\tif ( repeat[ 0 ] !== 1 ) texture.wrapS = THREE.RepeatWrapping;\r\n\t\t\t\tif ( repeat[ 1 ] !== 1 ) texture.wrapT = THREE.RepeatWrapping;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( offset ) {\r\n\r\n\t\t\t\ttexture.offset.set( offset[ 0 ], offset[ 1 ] );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( wrap ) {\r\n\r\n\t\t\t\tvar wrapMap = {\r\n\t\t\t\t\t'repeat': THREE.RepeatWrapping,\r\n\t\t\t\t\t'mirror': THREE.MirroredRepeatWrapping\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif ( wrapMap[ wrap[ 0 ] ] !== undefined ) texture.wrapS = wrapMap[ wrap[ 0 ] ];\r\n\t\t\t\tif ( wrapMap[ wrap[ 1 ] ] !== undefined ) texture.wrapT = wrapMap[ wrap[ 1 ] ];\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( anisotropy ) {\r\n\r\n\t\t\t\ttexture.anisotropy = anisotropy;\r\n\r\n\t\t\t}\r\n\r\n\t\t\twhere[ name ] = texture;\r\n\r\n\t\t}\r\n\r\n\t\tfunction rgb2hex( rgb ) {\r\n\r\n\t\t\treturn ( rgb[ 0 ] * 255 << 16 ) + ( rgb[ 1 ] * 255 << 8 ) + rgb[ 2 ] * 255;\r\n\r\n\t\t}\r\n\r\n\t\t// defaults\r\n\r\n\t\tvar mtype = 'MeshLambertMaterial';\r\n\t\tvar mpars = { color: 0xeeeeee, opacity: 1.0, map: null, lightMap: null, normalMap: null, bumpMap: null, wireframe: false };\r\n\r\n\t\t// parameters from model file\r\n\r\n\t\tif ( m.shading ) {\r\n\r\n\t\t\tvar shading = m.shading.toLowerCase();\r\n\r\n\t\t\tif ( shading === 'phong' ) mtype = 'MeshPhongMaterial';\r\n\t\t\telse if ( shading === 'basic' ) mtype = 'MeshBasicMaterial';\r\n\r\n\t\t}\r\n\r\n\t\tif ( m.blending !== undefined && THREE[ m.blending ] !== undefined ) {\r\n\r\n\t\t\tmpars.blending = THREE[ m.blending ];\r\n\r\n\t\t}\r\n\r\n\t\tif ( m.transparent !== undefined ) {\r\n\r\n\t\t\tmpars.transparent = m.transparent;\r\n\r\n\t\t}\r\n\r\n\t\tif ( m.opacity !== undefined && m.opacity < 1.0 ) {\r\n\r\n\t\t\tmpars.transparent = true;\r\n\r\n\t\t}\r\n\r\n\t\tif ( m.depthTest !== undefined ) {\r\n\r\n\t\t\tmpars.depthTest = m.depthTest;\r\n\r\n\t\t}\r\n\r\n\t\tif ( m.depthWrite !== undefined ) {\r\n\r\n\t\t\tmpars.depthWrite = m.depthWrite;\r\n\r\n\t\t}\r\n\r\n\t\tif ( m.visible !== undefined ) {\r\n\r\n\t\t\tmpars.visible = m.visible;\r\n\r\n\t\t}\r\n\r\n\t\tif ( m.flipSided !== undefined ) {\r\n\r\n\t\t\tmpars.side = THREE.BackSide;\r\n\r\n\t\t}\r\n\r\n\t\tif ( m.doubleSided !== undefined ) {\r\n\r\n\t\t\tmpars.side = THREE.DoubleSide;\r\n\r\n\t\t}\r\n\r\n\t\tif ( m.wireframe !== undefined ) {\r\n\r\n\t\t\tmpars.wireframe = m.wireframe;\r\n\r\n\t\t}\r\n\r\n\t\tif ( m.vertexColors !== undefined ) {\r\n\r\n\t\t\tif ( m.vertexColors === 'face' ) {\r\n\r\n\t\t\t\tmpars.vertexColors = THREE.FaceColors;\r\n\r\n\t\t\t} else if ( m.vertexColors ) {\r\n\r\n\t\t\t\tmpars.vertexColors = THREE.VertexColors;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\t// colors\r\n\r\n\t\tif ( m.colorDiffuse ) {\r\n\r\n\t\t\tmpars.color = rgb2hex( m.colorDiffuse );\r\n\r\n\t\t} else if ( m.DbgColor ) {\r\n\r\n\t\t\tmpars.color = m.DbgColor;\r\n\r\n\t\t}\r\n\r\n\t\tif ( m.colorSpecular ) {\r\n\r\n\t\t\tmpars.specular = rgb2hex( m.colorSpecular );\r\n\r\n\t\t}\r\n\r\n\t\tif ( m.colorEmissive ) {\r\n\r\n\t\t\tmpars.emissive = rgb2hex( m.colorEmissive );\r\n\r\n\t\t}\r\n\r\n\t\t// modifiers\r\n\r\n\t\tif ( m.transparency !== undefined ) {\r\n\r\n\t\t\tconsole.warn( 'THREE.Loader: transparency has been renamed to opacity' );\r\n\t\t\tm.opacity = m.transparency;\r\n\r\n\t\t}\r\n\r\n\t\tif ( m.opacity !== undefined ) {\r\n\r\n\t\t\tmpars.opacity = m.opacity;\r\n\r\n\t\t}\r\n\r\n\t\tif ( m.specularCoef ) {\r\n\r\n\t\t\tmpars.shininess = m.specularCoef;\r\n\r\n\t\t}\r\n\r\n\t\t// textures\r\n\r\n\t\tif ( m.mapDiffuse && texturePath ) {\r\n\r\n\t\t\tcreate_texture( mpars, 'map', m.mapDiffuse, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy );\r\n\r\n\t\t}\r\n\r\n\t\tif ( m.mapLight && texturePath ) {\r\n\r\n\t\t\tcreate_texture( mpars, 'lightMap', m.mapLight, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy );\r\n\r\n\t\t}\r\n\r\n\t\tif ( m.mapBump && texturePath ) {\r\n\r\n\t\t\tcreate_texture( mpars, 'bumpMap', m.mapBump, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy );\r\n\r\n\t\t}\r\n\r\n\t\tif ( m.mapNormal && texturePath ) {\r\n\r\n\t\t\tcreate_texture( mpars, 'normalMap', m.mapNormal, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy );\r\n\r\n\t\t}\r\n\r\n\t\tif ( m.mapSpecular && texturePath ) {\r\n\r\n\t\t\tcreate_texture( mpars, 'specularMap', m.mapSpecular, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy );\r\n\r\n\t\t}\r\n\r\n\t\tif ( m.mapAlpha && texturePath ) {\r\n\r\n\t\t\tcreate_texture( mpars, 'alphaMap', m.mapAlpha, m.mapAlphaRepeat, m.mapAlphaOffset, m.mapAlphaWrap, m.mapAlphaAnisotropy );\r\n\r\n\t\t}\r\n\r\n\t\t//\r\n\r\n\t\tif ( m.mapBumpScale ) {\r\n\r\n\t\t\tmpars.bumpScale = m.mapBumpScale;\r\n\r\n\t\t}\r\n\r\n\t\tif ( m.mapNormalFactor ) {\r\n\r\n\t\t\tmpars.normalScale = new THREE.Vector2( m.mapNormalFactor, m.mapNormalFactor );\r\n\r\n\t\t}\r\n\r\n\t\tvar material = new THREE[ mtype ]( mpars );\r\n\r\n\t\tif ( m.DbgName !== undefined ) material.name = m.DbgName;\r\n\r\n\t\treturn material;\r\n\r\n\t}\r\n\r\n};\r\n\r\nTHREE.Loader.Handlers = {\r\n\r\n\thandlers: [],\r\n\r\n\tadd: function ( regex, loader ) {\r\n\r\n\t\tthis.handlers.push( regex, loader );\r\n\r\n\t},\r\n\r\n\tget: function ( file ) {\r\n\r\n\t\tfor ( var i = 0, l = this.handlers.length; i < l; i += 2 ) {\r\n\r\n\t\t\tvar regex = this.handlers[ i ];\r\n\t\t\tvar loader = this.handlers[ i + 1 ];\r\n\r\n\t\t\tif ( regex.test( file ) ) {\r\n\r\n\t\t\t\treturn loader;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/loaders/XHRLoader.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n */\r\n\r\nTHREE.XHRLoader = function ( manager ) {\r\n\r\n\tthis.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;\r\n\r\n};\r\n\r\nTHREE.XHRLoader.prototype = {\r\n\r\n\tconstructor: THREE.XHRLoader,\r\n\r\n\tload: function ( url, onLoad, onProgress, onError ) {\r\n\r\n\t\tvar scope = this;\r\n\r\n\t\tvar cached = THREE.Cache.get( url );\r\n\r\n\t\tif ( cached !== undefined ) {\r\n\r\n\t\t\tif ( onLoad ) onLoad( cached );\r\n\t\t\treturn;\r\n\r\n\t\t}\r\n\r\n\t\tvar request = new XMLHttpRequest();\r\n\t\trequest.open( 'GET', url, true );\r\n\r\n\t\trequest.addEventListener( 'load', function ( event ) {\r\n\r\n\t\t\tTHREE.Cache.add( url, this.response );\r\n\r\n\t\t\tif ( onLoad ) onLoad( this.response );\r\n\r\n\t\t\tscope.manager.itemEnd( url );\r\n\r\n\t\t}, false );\r\n\r\n\t\tif ( onProgress !== undefined ) {\r\n\r\n\t\t\trequest.addEventListener( 'progress', function ( event ) {\r\n\r\n\t\t\t\tonProgress( event );\r\n\r\n\t\t\t}, false );\r\n\r\n\t\t}\r\n\r\n\t\tif ( onError !== undefined ) {\r\n\r\n\t\t\trequest.addEventListener( 'error', function ( event ) {\r\n\r\n\t\t\t\tonError( event );\r\n\r\n\t\t\t}, false );\r\n\r\n\t\t}\r\n\r\n\t\tif ( this.crossOrigin !== undefined ) request.crossOrigin = this.crossOrigin;\r\n\t\tif ( this.responseType !== undefined ) request.responseType = this.responseType;\r\n\r\n\t\trequest.send( null );\r\n\r\n\t\tscope.manager.itemStart( url );\r\n\r\n\t},\r\n\r\n\tsetResponseType: function ( value ) {\r\n\r\n\t\tthis.responseType = value;\r\n\r\n\t},\r\n\r\n\tsetCrossOrigin: function ( value ) {\r\n\r\n\t\tthis.crossOrigin = value;\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/loaders/ImageLoader.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n */\r\n\r\nTHREE.ImageLoader = function ( manager ) {\r\n\r\n\tthis.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;\r\n\r\n};\r\n\r\nTHREE.ImageLoader.prototype = {\r\n\r\n\tconstructor: THREE.ImageLoader,\r\n\r\n\tload: function ( url, onLoad, onProgress, onError ) {\r\n\r\n\t\tvar scope = this;\r\n\r\n\t\tvar cached = THREE.Cache.get( url );\r\n\r\n\t\tif ( cached !== undefined ) {\r\n\r\n\t\t\tonLoad( cached );\r\n\t\t\treturn;\r\n\r\n\t\t}\r\n\r\n\t\tvar image = document.createElement( 'img' );\r\n\r\n\t\timage.addEventListener( 'load', function ( event ) {\r\n\r\n\t\t\tTHREE.Cache.add( url, this );\r\n\r\n\t\t\tif ( onLoad ) onLoad( this );\r\n\t\t\t\r\n\t\t\tscope.manager.itemEnd( url );\r\n\r\n\t\t}, false );\r\n\r\n\t\tif ( onProgress !== undefined ) {\r\n\r\n\t\t\timage.addEventListener( 'progress', function ( event ) {\r\n\r\n\t\t\t\tonProgress( event );\r\n\r\n\t\t\t}, false );\r\n\r\n\t\t}\r\n\r\n\t\tif ( onError !== undefined ) {\r\n\r\n\t\t\timage.addEventListener( 'error', function ( event ) {\r\n\r\n\t\t\t\tonError( event );\r\n\r\n\t\t\t}, false );\r\n\r\n\t\t}\r\n\r\n\t\tif ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin;\r\n\r\n\t\timage.src = url;\r\n\r\n\t\tscope.manager.itemStart( url );\r\n\r\n\t\treturn image;\r\n\r\n\t},\r\n\r\n\tsetCrossOrigin: function ( value ) {\r\n\r\n\t\tthis.crossOrigin = value;\r\n\r\n\t}\r\n\r\n}\r\n\r\n// File:src/loaders/JSONLoader.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n * @author alteredq / http://alteredqualia.com/\r\n */\r\n\r\nTHREE.JSONLoader = function ( showStatus ) {\r\n\r\n\tTHREE.Loader.call( this, showStatus );\r\n\r\n\tthis.withCredentials = false;\r\n\r\n};\r\n\r\nTHREE.JSONLoader.prototype = Object.create( THREE.Loader.prototype );\r\nTHREE.JSONLoader.prototype.constructor = THREE.JSONLoader;\r\n\r\nTHREE.JSONLoader.prototype.load = function ( url, callback, texturePath ) {\r\n\r\n\t// todo: unify load API to for easier SceneLoader use\r\n\r\n\ttexturePath = texturePath && ( typeof texturePath === 'string' ) ? texturePath : this.extractUrlBase( url );\r\n\r\n\tthis.onLoadStart();\r\n\tthis.loadAjaxJSON( this, url, callback, texturePath );\r\n\r\n};\r\n\r\nTHREE.JSONLoader.prototype.loadAjaxJSON = function ( context, url, callback, texturePath, callbackProgress ) {\r\n\r\n\tvar xhr = new XMLHttpRequest();\r\n\r\n\tvar length = 0;\r\n\r\n\txhr.onreadystatechange = function () {\r\n\r\n\t\tif ( xhr.readyState === xhr.DONE ) {\r\n\r\n\t\t\tif ( xhr.status === 200 || xhr.status === 0 ) {\r\n\r\n\t\t\t\tif ( xhr.responseText ) {\r\n\r\n\t\t\t\t\tvar json = JSON.parse( xhr.responseText );\r\n\t\t\t\t\tvar metadata = json.metadata;\r\n\r\n\t\t\t\t\tif ( metadata !== undefined ) {\r\n\r\n\t\t\t\t\t\tif ( metadata.type === 'object' ) {\r\n\r\n\t\t\t\t\t\t\tTHREE.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.ObjectLoader instead.' );\r\n\t\t\t\t\t\t\treturn;\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tif ( metadata.type === 'scene' ) {\r\n\r\n\t\t\t\t\t\t\tTHREE.error( 'THREE.JSONLoader: ' + url + ' seems to be a Scene. Use THREE.SceneLoader instead.' );\r\n\t\t\t\t\t\t\treturn;\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tvar result = context.parse( json, texturePath );\r\n\t\t\t\t\tcallback( result.geometry, result.materials );\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\tTHREE.error( 'THREE.JSONLoader: ' + url + ' seems to be unreachable or the file is empty.' );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// in context of more complex asset initialization\r\n\t\t\t\t// do not block on single failed file\r\n\t\t\t\t// maybe should go even one more level up\r\n\r\n\t\t\t\tcontext.onLoadComplete();\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tTHREE.error( 'THREE.JSONLoader: Couldn\\'t load ' + url + ' (' + xhr.status + ')' );\r\n\r\n\t\t\t}\r\n\r\n\t\t} else if ( xhr.readyState === xhr.LOADING ) {\r\n\r\n\t\t\tif ( callbackProgress ) {\r\n\r\n\t\t\t\tif ( length === 0 ) {\r\n\r\n\t\t\t\t\tlength = xhr.getResponseHeader( 'Content-Length' );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tcallbackProgress( { total: length, loaded: xhr.responseText.length } );\r\n\r\n\t\t\t}\r\n\r\n\t\t} else if ( xhr.readyState === xhr.HEADERS_RECEIVED ) {\r\n\r\n\t\t\tif ( callbackProgress !== undefined ) {\r\n\r\n\t\t\t\tlength = xhr.getResponseHeader( 'Content-Length' );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n\txhr.open( 'GET', url, true );\r\n\txhr.withCredentials = this.withCredentials;\r\n\txhr.send( null );\r\n\r\n};\r\n\r\nTHREE.JSONLoader.prototype.parse = function ( json, texturePath ) {\r\n\r\n\tvar geometry = new THREE.Geometry(),\r\n\tscale = ( json.scale !== undefined ) ? 1.0 / json.scale : 1.0;\r\n\r\n\tparseModel( scale );\r\n\r\n\tparseSkin();\r\n\tparseMorphing( scale );\r\n\r\n\tgeometry.computeFaceNormals();\r\n\tgeometry.computeBoundingSphere();\r\n\r\n\tfunction parseModel( scale ) {\r\n\r\n\t\tfunction isBitSet( value, position ) {\r\n\r\n\t\t\treturn value & ( 1 << position );\r\n\r\n\t\t}\r\n\r\n\t\tvar i, j, fi,\r\n\r\n\t\toffset, zLength,\r\n\r\n\t\tcolorIndex, normalIndex, uvIndex, materialIndex,\r\n\r\n\t\ttype,\r\n\t\tisQuad,\r\n\t\thasMaterial,\r\n\t\thasFaceVertexUv,\r\n\t\thasFaceNormal, hasFaceVertexNormal,\r\n\t\thasFaceColor, hasFaceVertexColor,\r\n\r\n\t\tvertex, face, faceA, faceB, hex, normal,\r\n\r\n\t\tuvLayer, uv, u, v,\r\n\r\n\t\tfaces = json.faces,\r\n\t\tvertices = json.vertices,\r\n\t\tnormals = json.normals,\r\n\t\tcolors = json.colors,\r\n\r\n\t\tnUvLayers = 0;\r\n\r\n\t\tif ( json.uvs !== undefined ) {\r\n\r\n\t\t\t// disregard empty arrays\r\n\r\n\t\t\tfor ( i = 0; i < json.uvs.length; i ++ ) {\r\n\r\n\t\t\t\tif ( json.uvs[ i ].length ) nUvLayers ++;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tfor ( i = 0; i < nUvLayers; i ++ ) {\r\n\r\n\t\t\t\tgeometry.faceVertexUvs[ i ] = [];\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\toffset = 0;\r\n\t\tzLength = vertices.length;\r\n\r\n\t\twhile ( offset < zLength ) {\r\n\r\n\t\t\tvertex = new THREE.Vector3();\r\n\r\n\t\t\tvertex.x = vertices[ offset ++ ] * scale;\r\n\t\t\tvertex.y = vertices[ offset ++ ] * scale;\r\n\t\t\tvertex.z = vertices[ offset ++ ] * scale;\r\n\r\n\t\t\tgeometry.vertices.push( vertex );\r\n\r\n\t\t}\r\n\r\n\t\toffset = 0;\r\n\t\tzLength = faces.length;\r\n\r\n\t\twhile ( offset < zLength ) {\r\n\r\n\t\t\ttype = faces[ offset ++ ];\r\n\r\n\r\n\t\t\tisQuad = isBitSet( type, 0 );\r\n\t\t\thasMaterial = isBitSet( type, 1 );\r\n\t\t\thasFaceVertexUv = isBitSet( type, 3 );\r\n\t\t\thasFaceNormal = isBitSet( type, 4 );\r\n\t\t\thasFaceVertexNormal = isBitSet( type, 5 );\r\n\t\t\thasFaceColor\t = isBitSet( type, 6 );\r\n\t\t\thasFaceVertexColor = isBitSet( type, 7 );\r\n\r\n\t\t\t// console.log(\"type\", type, \"bits\", isQuad, hasMaterial, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor);\r\n\r\n\t\t\tif ( isQuad ) {\r\n\r\n\t\t\t\tfaceA = new THREE.Face3();\r\n\t\t\t\tfaceA.a = faces[ offset ];\r\n\t\t\t\tfaceA.b = faces[ offset + 1 ];\r\n\t\t\t\tfaceA.c = faces[ offset + 3 ];\r\n\r\n\t\t\t\tfaceB = new THREE.Face3();\r\n\t\t\t\tfaceB.a = faces[ offset + 1 ];\r\n\t\t\t\tfaceB.b = faces[ offset + 2 ];\r\n\t\t\t\tfaceB.c = faces[ offset + 3 ];\r\n\r\n\t\t\t\toffset += 4;\r\n\r\n\t\t\t\tif ( hasMaterial ) {\r\n\r\n\t\t\t\t\tmaterialIndex = faces[ offset ++ ];\r\n\t\t\t\t\tfaceA.materialIndex = materialIndex;\r\n\t\t\t\t\tfaceB.materialIndex = materialIndex;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// to get face <=> uv index correspondence\r\n\r\n\t\t\t\tfi = geometry.faces.length;\r\n\r\n\t\t\t\tif ( hasFaceVertexUv ) {\r\n\r\n\t\t\t\t\tfor ( i = 0; i < nUvLayers; i ++ ) {\r\n\r\n\t\t\t\t\t\tuvLayer = json.uvs[ i ];\r\n\r\n\t\t\t\t\t\tgeometry.faceVertexUvs[ i ][ fi ] = [];\r\n\t\t\t\t\t\tgeometry.faceVertexUvs[ i ][ fi + 1 ] = []\r\n\r\n\t\t\t\t\t\tfor ( j = 0; j < 4; j ++ ) {\r\n\r\n\t\t\t\t\t\t\tuvIndex = faces[ offset ++ ];\r\n\r\n\t\t\t\t\t\t\tu = uvLayer[ uvIndex * 2 ];\r\n\t\t\t\t\t\t\tv = uvLayer[ uvIndex * 2 + 1 ];\r\n\r\n\t\t\t\t\t\t\tuv = new THREE.Vector2( u, v );\r\n\r\n\t\t\t\t\t\t\tif ( j !== 2 ) geometry.faceVertexUvs[ i ][ fi ].push( uv );\r\n\t\t\t\t\t\t\tif ( j !== 0 ) geometry.faceVertexUvs[ i ][ fi + 1 ].push( uv );\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif ( hasFaceNormal ) {\r\n\r\n\t\t\t\t\tnormalIndex = faces[ offset ++ ] * 3;\r\n\r\n\t\t\t\t\tfaceA.normal.set(\r\n\t\t\t\t\t\tnormals[ normalIndex ++ ],\r\n\t\t\t\t\t\tnormals[ normalIndex ++ ],\r\n\t\t\t\t\t\tnormals[ normalIndex ]\r\n\t\t\t\t\t);\r\n\r\n\t\t\t\t\tfaceB.normal.copy( faceA.normal );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif ( hasFaceVertexNormal ) {\r\n\r\n\t\t\t\t\tfor ( i = 0; i < 4; i ++ ) {\r\n\r\n\t\t\t\t\t\tnormalIndex = faces[ offset ++ ] * 3;\r\n\r\n\t\t\t\t\t\tnormal = new THREE.Vector3(\r\n\t\t\t\t\t\t\tnormals[ normalIndex ++ ],\r\n\t\t\t\t\t\t\tnormals[ normalIndex ++ ],\r\n\t\t\t\t\t\t\tnormals[ normalIndex ]\r\n\t\t\t\t\t\t);\r\n\r\n\r\n\t\t\t\t\t\tif ( i !== 2 ) faceA.vertexNormals.push( normal );\r\n\t\t\t\t\t\tif ( i !== 0 ) faceB.vertexNormals.push( normal );\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\r\n\t\t\t\tif ( hasFaceColor ) {\r\n\r\n\t\t\t\t\tcolorIndex = faces[ offset ++ ];\r\n\t\t\t\t\thex = colors[ colorIndex ];\r\n\r\n\t\t\t\t\tfaceA.color.setHex( hex );\r\n\t\t\t\t\tfaceB.color.setHex( hex );\r\n\r\n\t\t\t\t}\r\n\r\n\r\n\t\t\t\tif ( hasFaceVertexColor ) {\r\n\r\n\t\t\t\t\tfor ( i = 0; i < 4; i ++ ) {\r\n\r\n\t\t\t\t\t\tcolorIndex = faces[ offset ++ ];\r\n\t\t\t\t\t\thex = colors[ colorIndex ];\r\n\r\n\t\t\t\t\t\tif ( i !== 2 ) faceA.vertexColors.push( new THREE.Color( hex ) );\r\n\t\t\t\t\t\tif ( i !== 0 ) faceB.vertexColors.push( new THREE.Color( hex ) );\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tgeometry.faces.push( faceA );\r\n\t\t\t\tgeometry.faces.push( faceB );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tface = new THREE.Face3();\r\n\t\t\t\tface.a = faces[ offset ++ ];\r\n\t\t\t\tface.b = faces[ offset ++ ];\r\n\t\t\t\tface.c = faces[ offset ++ ];\r\n\r\n\t\t\t\tif ( hasMaterial ) {\r\n\r\n\t\t\t\t\tmaterialIndex = faces[ offset ++ ];\r\n\t\t\t\t\tface.materialIndex = materialIndex;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// to get face <=> uv index correspondence\r\n\r\n\t\t\t\tfi = geometry.faces.length;\r\n\r\n\t\t\t\tif ( hasFaceVertexUv ) {\r\n\r\n\t\t\t\t\tfor ( i = 0; i < nUvLayers; i ++ ) {\r\n\r\n\t\t\t\t\t\tuvLayer = json.uvs[ i ];\r\n\r\n\t\t\t\t\t\tgeometry.faceVertexUvs[ i ][ fi ] = [];\r\n\r\n\t\t\t\t\t\tfor ( j = 0; j < 3; j ++ ) {\r\n\r\n\t\t\t\t\t\t\tuvIndex = faces[ offset ++ ];\r\n\r\n\t\t\t\t\t\t\tu = uvLayer[ uvIndex * 2 ];\r\n\t\t\t\t\t\t\tv = uvLayer[ uvIndex * 2 + 1 ];\r\n\r\n\t\t\t\t\t\t\tuv = new THREE.Vector2( u, v );\r\n\r\n\t\t\t\t\t\t\tgeometry.faceVertexUvs[ i ][ fi ].push( uv );\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif ( hasFaceNormal ) {\r\n\r\n\t\t\t\t\tnormalIndex = faces[ offset ++ ] * 3;\r\n\r\n\t\t\t\t\tface.normal.set(\r\n\t\t\t\t\t\tnormals[ normalIndex ++ ],\r\n\t\t\t\t\t\tnormals[ normalIndex ++ ],\r\n\t\t\t\t\t\tnormals[ normalIndex ]\r\n\t\t\t\t\t);\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif ( hasFaceVertexNormal ) {\r\n\r\n\t\t\t\t\tfor ( i = 0; i < 3; i ++ ) {\r\n\r\n\t\t\t\t\t\tnormalIndex = faces[ offset ++ ] * 3;\r\n\r\n\t\t\t\t\t\tnormal = new THREE.Vector3(\r\n\t\t\t\t\t\t\tnormals[ normalIndex ++ ],\r\n\t\t\t\t\t\t\tnormals[ normalIndex ++ ],\r\n\t\t\t\t\t\t\tnormals[ normalIndex ]\r\n\t\t\t\t\t\t);\r\n\r\n\t\t\t\t\t\tface.vertexNormals.push( normal );\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\r\n\t\t\t\tif ( hasFaceColor ) {\r\n\r\n\t\t\t\t\tcolorIndex = faces[ offset ++ ];\r\n\t\t\t\t\tface.color.setHex( colors[ colorIndex ] );\r\n\r\n\t\t\t\t}\r\n\r\n\r\n\t\t\t\tif ( hasFaceVertexColor ) {\r\n\r\n\t\t\t\t\tfor ( i = 0; i < 3; i ++ ) {\r\n\r\n\t\t\t\t\t\tcolorIndex = faces[ offset ++ ];\r\n\t\t\t\t\t\tface.vertexColors.push( new THREE.Color( colors[ colorIndex ] ) );\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tgeometry.faces.push( face );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n\tfunction parseSkin() {\r\n\t\tvar influencesPerVertex = ( json.influencesPerVertex !== undefined ) ? json.influencesPerVertex : 2;\r\n\r\n\t\tif ( json.skinWeights ) {\r\n\r\n\t\t\tfor ( var i = 0, l = json.skinWeights.length; i < l; i += influencesPerVertex ) {\r\n\r\n\t\t\t\tvar x = json.skinWeights[ i ];\r\n\t\t\t\tvar y = ( influencesPerVertex > 1 ) ? json.skinWeights[ i + 1 ] : 0;\r\n\t\t\t\tvar z = ( influencesPerVertex > 2 ) ? json.skinWeights[ i + 2 ] : 0;\r\n\t\t\t\tvar w = ( influencesPerVertex > 3 ) ? json.skinWeights[ i + 3 ] : 0;\r\n\r\n\t\t\t\tgeometry.skinWeights.push( new THREE.Vector4( x, y, z, w ) );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tif ( json.skinIndices ) {\r\n\r\n\t\t\tfor ( var i = 0, l = json.skinIndices.length; i < l; i += influencesPerVertex ) {\r\n\r\n\t\t\t\tvar a = json.skinIndices[ i ];\r\n\t\t\t\tvar b = ( influencesPerVertex > 1 ) ? json.skinIndices[ i + 1 ] : 0;\r\n\t\t\t\tvar c = ( influencesPerVertex > 2 ) ? json.skinIndices[ i + 2 ] : 0;\r\n\t\t\t\tvar d = ( influencesPerVertex > 3 ) ? json.skinIndices[ i + 3 ] : 0;\r\n\r\n\t\t\t\tgeometry.skinIndices.push( new THREE.Vector4( a, b, c, d ) );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tgeometry.bones = json.bones;\r\n\r\n\t\tif ( geometry.bones && geometry.bones.length > 0 && ( geometry.skinWeights.length !== geometry.skinIndices.length || geometry.skinIndices.length !== geometry.vertices.length ) ) {\r\n\r\n\t\t\tTHREE.warn( 'THREE.JSONLoader: When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' +\r\n\t\t\t\t\tgeometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.' );\r\n\r\n\t\t}\r\n\r\n\r\n\t\t// could change this to json.animations[0] or remove completely\r\n\r\n\t\tgeometry.animation = json.animation;\r\n\t\tgeometry.animations = json.animations;\r\n\r\n\t};\r\n\r\n\tfunction parseMorphing( scale ) {\r\n\r\n\t\tif ( json.morphTargets !== undefined ) {\r\n\r\n\t\t\tvar i, l, v, vl, dstVertices, srcVertices;\r\n\r\n\t\t\tfor ( i = 0, l = json.morphTargets.length; i < l; i ++ ) {\r\n\r\n\t\t\t\tgeometry.morphTargets[ i ] = {};\r\n\t\t\t\tgeometry.morphTargets[ i ].name = json.morphTargets[ i ].name;\r\n\t\t\t\tgeometry.morphTargets[ i ].vertices = [];\r\n\r\n\t\t\t\tdstVertices = geometry.morphTargets[ i ].vertices;\r\n\t\t\t\tsrcVertices = json.morphTargets [ i ].vertices;\r\n\r\n\t\t\t\tfor ( v = 0, vl = srcVertices.length; v < vl; v += 3 ) {\r\n\r\n\t\t\t\t\tvar vertex = new THREE.Vector3();\r\n\t\t\t\t\tvertex.x = srcVertices[ v ] * scale;\r\n\t\t\t\t\tvertex.y = srcVertices[ v + 1 ] * scale;\r\n\t\t\t\t\tvertex.z = srcVertices[ v + 2 ] * scale;\r\n\r\n\t\t\t\t\tdstVertices.push( vertex );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tif ( json.morphColors !== undefined ) {\r\n\r\n\t\t\tvar i, l, c, cl, dstColors, srcColors, color;\r\n\r\n\t\t\tfor ( i = 0, l = json.morphColors.length; i < l; i ++ ) {\r\n\r\n\t\t\t\tgeometry.morphColors[ i ] = {};\r\n\t\t\t\tgeometry.morphColors[ i ].name = json.morphColors[ i ].name;\r\n\t\t\t\tgeometry.morphColors[ i ].colors = [];\r\n\r\n\t\t\t\tdstColors = geometry.morphColors[ i ].colors;\r\n\t\t\t\tsrcColors = json.morphColors [ i ].colors;\r\n\r\n\t\t\t\tfor ( c = 0, cl = srcColors.length; c < cl; c += 3 ) {\r\n\r\n\t\t\t\t\tcolor = new THREE.Color( 0xffaa00 );\r\n\t\t\t\t\tcolor.setRGB( srcColors[ c ], srcColors[ c + 1 ], srcColors[ c + 2 ] );\r\n\t\t\t\t\tdstColors.push( color );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n\tif ( json.materials === undefined || json.materials.length === 0 ) {\r\n\r\n\t\treturn { geometry: geometry };\r\n\r\n\t} else {\r\n\r\n\t\tvar materials = this.initMaterials( json.materials, texturePath );\r\n\r\n\t\tif ( this.needsTangents( materials ) ) {\r\n\r\n\t\t\tgeometry.computeTangents();\r\n\r\n\t\t}\r\n\r\n\t\treturn { geometry: geometry, materials: materials };\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/loaders/LoadingManager.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n */\r\n\r\nTHREE.LoadingManager = function ( onLoad, onProgress, onError ) {\r\n\r\n\tvar scope = this;\r\n\r\n\tvar loaded = 0, total = 0;\r\n\r\n\tthis.onLoad = onLoad;\r\n\tthis.onProgress = onProgress;\r\n\tthis.onError = onError;\r\n\r\n\tthis.itemStart = function ( url ) {\r\n\r\n\t\ttotal ++;\r\n\r\n\t};\r\n\r\n\tthis.itemEnd = function ( url ) {\r\n\r\n\t\tloaded ++;\r\n\r\n\t\tif ( scope.onProgress !== undefined ) {\r\n\r\n\t\t\tscope.onProgress( url, loaded, total );\r\n\r\n\t\t}\r\n\r\n\t\tif ( loaded === total && scope.onLoad !== undefined ) {\r\n\r\n\t\t\tscope.onLoad();\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n};\r\n\r\nTHREE.DefaultLoadingManager = new THREE.LoadingManager();\r\n\r\n// File:src/loaders/BufferGeometryLoader.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n */\r\n\r\nTHREE.BufferGeometryLoader = function ( manager ) {\r\n\r\n\tthis.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;\r\n\r\n};\r\n\r\nTHREE.BufferGeometryLoader.prototype = {\r\n\r\n\tconstructor: THREE.BufferGeometryLoader,\r\n\r\n\tload: function ( url, onLoad, onProgress, onError ) {\r\n\r\n\t\tvar scope = this;\r\n\r\n\t\tvar loader = new THREE.XHRLoader( scope.manager );\r\n\t\tloader.setCrossOrigin( this.crossOrigin );\r\n\t\tloader.load( url, function ( text ) {\r\n\r\n\t\t\tonLoad( scope.parse( JSON.parse( text ) ) );\r\n\r\n\t\t}, onProgress, onError );\r\n\r\n\t},\r\n\r\n\tsetCrossOrigin: function ( value ) {\r\n\r\n\t\tthis.crossOrigin = value;\r\n\r\n\t},\r\n\r\n\tparse: function ( json ) {\r\n\r\n\t\tvar geometry = new THREE.BufferGeometry();\r\n\r\n\t\tvar attributes = json.data.attributes;\r\n\r\n\t\tfor ( var key in attributes ) {\r\n\r\n\t\t\tvar attribute = attributes[ key ];\r\n\t\t\tvar typedArray = new self[ attribute.type ]( attribute.array );\r\n\r\n\t\t\tgeometry.addAttribute( key, new THREE.BufferAttribute( typedArray, attribute.itemSize ) );\r\n\r\n\t\t}\r\n\r\n\t\tvar offsets = json.data.offsets;\r\n\r\n\t\tif ( offsets !== undefined ) {\r\n\r\n\t\t\tgeometry.offsets = JSON.parse( JSON.stringify( offsets ) );\r\n\r\n\t\t}\r\n\r\n\t\tvar boundingSphere = json.data.boundingSphere;\r\n\r\n\t\tif ( boundingSphere !== undefined ) {\r\n\r\n\t\t\tvar center = new THREE.Vector3();\r\n\r\n\t\t\tif ( boundingSphere.center !== undefined ) {\r\n\r\n\t\t\t\tcenter.fromArray( boundingSphere.center );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tgeometry.boundingSphere = new THREE.Sphere( center, boundingSphere.radius );\r\n\r\n\t\t}\r\n\r\n\t\treturn geometry;\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/loaders/MaterialLoader.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n */\r\n\r\nTHREE.MaterialLoader = function ( manager ) {\r\n\r\n\tthis.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;\r\n\r\n};\r\n\r\nTHREE.MaterialLoader.prototype = {\r\n\r\n\tconstructor: THREE.MaterialLoader,\r\n\r\n\tload: function ( url, onLoad, onProgress, onError ) {\r\n\r\n\t\tvar scope = this;\r\n\r\n\t\tvar loader = new THREE.XHRLoader( scope.manager );\r\n\t\tloader.setCrossOrigin( this.crossOrigin );\r\n\t\tloader.load( url, function ( text ) {\r\n\r\n\t\t\tonLoad( scope.parse( JSON.parse( text ) ) );\r\n\r\n\t\t}, onProgress, onError );\r\n\r\n\t},\r\n\r\n\tsetCrossOrigin: function ( value ) {\r\n\r\n\t\tthis.crossOrigin = value;\r\n\r\n\t},\r\n\r\n\tparse: function ( json ) {\r\n\r\n\t\tvar material = new THREE[ json.type ];\r\n\r\n\t\tif ( json.color !== undefined ) material.color.setHex( json.color );\r\n\t\tif ( json.emissive !== undefined ) material.emissive.setHex( json.emissive );\r\n\t\tif ( json.specular !== undefined ) material.specular.setHex( json.specular );\r\n\t\tif ( json.shininess !== undefined ) material.shininess = json.shininess;\r\n\t\tif ( json.uniforms !== undefined ) material.uniforms = json.uniforms;\r\n\t\tif ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader;\r\n\t\tif ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader;\r\n\t\tif ( json.vertexColors !== undefined ) material.vertexColors = json.vertexColors;\r\n\t\tif ( json.shading !== undefined ) material.shading = json.shading;\r\n\t\tif ( json.blending !== undefined ) material.blending = json.blending;\r\n\t\tif ( json.side !== undefined ) material.side = json.side;\r\n\t\tif ( json.opacity !== undefined ) material.opacity = json.opacity;\r\n\t\tif ( json.transparent !== undefined ) material.transparent = json.transparent;\r\n\t\tif ( json.wireframe !== undefined ) material.wireframe = json.wireframe;\r\n\r\n\t\t// for PointCloudMaterial\r\n\t\tif ( json.size !== undefined ) material.size = json.size;\r\n\t\tif ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation;\r\n\r\n\t\tif ( json.materials !== undefined ) {\r\n\r\n\t\t\tfor ( var i = 0, l = json.materials.length; i < l; i ++ ) {\r\n\r\n\t\t\t\tmaterial.materials.push( this.parse( json.materials[ i ] ) );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\treturn material;\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/loaders/ObjectLoader.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n */\r\n\r\nTHREE.ObjectLoader = function ( manager ) {\r\n\r\n\tthis.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;\r\n\tthis.texturePath = '';\r\n\r\n};\r\n\r\nTHREE.ObjectLoader.prototype = {\r\n\r\n\tconstructor: THREE.ObjectLoader,\r\n\r\n\tload: function ( url, onLoad, onProgress, onError ) {\r\n\r\n\t\tif ( this.texturePath === '' ) {\r\n\r\n\t\t\tthis.texturePath = url.substring( 0, url.lastIndexOf( '/' ) + 1 );\r\n\r\n\t\t}\r\n\r\n\t\tvar scope = this;\r\n\r\n\t\tvar loader = new THREE.XHRLoader( scope.manager );\r\n\t\tloader.setCrossOrigin( this.crossOrigin );\r\n\t\tloader.load( url, function ( text ) {\r\n\r\n\t\t\tscope.parse( JSON.parse( text ), onLoad );\r\n\r\n\t\t}, onProgress, onError );\r\n\r\n\t},\r\n\r\n\tsetTexturePath: function ( value ) {\r\n\r\n\t\tthis.texturePath = value;\r\n\r\n\t},\r\n\r\n\tsetCrossOrigin: function ( value ) {\r\n\r\n\t\tthis.crossOrigin = value;\r\n\r\n\t},\r\n\r\n\tparse: function ( json, onLoad ) {\r\n\r\n\t\tvar geometries = this.parseGeometries( json.geometries );\r\n\r\n\t\tvar images = this.parseImages( json.images, function () {\r\n\r\n\t\t\tif ( onLoad !== undefined ) onLoad( object );\r\n\r\n\t\t} );\r\n\t\tvar textures = this.parseTextures( json.textures, images );\r\n\t\tvar materials = this.parseMaterials( json.materials, textures );\r\n\t\tvar object = this.parseObject( json.object, geometries, materials );\r\n\r\n\t\tif ( json.images === undefined || json.images.length === 0 ) {\r\n\r\n\t\t\tif ( onLoad !== undefined ) onLoad( object );\r\n\r\n\t\t}\r\n\r\n\t\treturn object;\r\n\r\n\t},\r\n\r\n\tparseGeometries: function ( json ) {\r\n\r\n\t\tvar geometries = {};\r\n\r\n\t\tif ( json !== undefined ) {\r\n\r\n\t\t\tvar geometryLoader = new THREE.JSONLoader();\r\n\t\t\tvar bufferGeometryLoader = new THREE.BufferGeometryLoader();\r\n\r\n\t\t\tfor ( var i = 0, l = json.length; i < l; i ++ ) {\r\n\r\n\t\t\t\tvar geometry;\r\n\t\t\t\tvar data = json[ i ];\r\n\r\n\t\t\t\tswitch ( data.type ) {\r\n\r\n\t\t\t\t\tcase 'PlaneGeometry':\r\n\t\t\t\t\tcase 'PlaneBufferGeometry':\r\n\r\n\t\t\t\t\t\tgeometry = new THREE[ data.type ](\r\n\t\t\t\t\t\t\tdata.width,\r\n\t\t\t\t\t\t\tdata.height,\r\n\t\t\t\t\t\t\tdata.widthSegments,\r\n\t\t\t\t\t\t\tdata.heightSegments\r\n\t\t\t\t\t\t);\r\n\r\n\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\tcase 'BoxGeometry':\r\n\t\t\t\t\tcase 'CubeGeometry': // backwards compatible\r\n\r\n\t\t\t\t\t\tgeometry = new THREE.BoxGeometry(\r\n\t\t\t\t\t\t\tdata.width,\r\n\t\t\t\t\t\t\tdata.height,\r\n\t\t\t\t\t\t\tdata.depth,\r\n\t\t\t\t\t\t\tdata.widthSegments,\r\n\t\t\t\t\t\t\tdata.heightSegments,\r\n\t\t\t\t\t\t\tdata.depthSegments\r\n\t\t\t\t\t\t);\r\n\r\n\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\tcase 'CircleGeometry':\r\n\r\n\t\t\t\t\t\tgeometry = new THREE.CircleGeometry(\r\n\t\t\t\t\t\t\tdata.radius,\r\n\t\t\t\t\t\t\tdata.segments\r\n\t\t\t\t\t\t);\r\n\r\n\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\tcase 'CylinderGeometry':\r\n\r\n\t\t\t\t\t\tgeometry = new THREE.CylinderGeometry(\r\n\t\t\t\t\t\t\tdata.radiusTop,\r\n\t\t\t\t\t\t\tdata.radiusBottom,\r\n\t\t\t\t\t\t\tdata.height,\r\n\t\t\t\t\t\t\tdata.radialSegments,\r\n\t\t\t\t\t\t\tdata.heightSegments,\r\n\t\t\t\t\t\t\tdata.openEnded\r\n\t\t\t\t\t\t);\r\n\r\n\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\tcase 'SphereGeometry':\r\n\r\n\t\t\t\t\t\tgeometry = new THREE.SphereGeometry(\r\n\t\t\t\t\t\t\tdata.radius,\r\n\t\t\t\t\t\t\tdata.widthSegments,\r\n\t\t\t\t\t\t\tdata.heightSegments,\r\n\t\t\t\t\t\t\tdata.phiStart,\r\n\t\t\t\t\t\t\tdata.phiLength,\r\n\t\t\t\t\t\t\tdata.thetaStart,\r\n\t\t\t\t\t\t\tdata.thetaLength\r\n\t\t\t\t\t\t);\r\n\r\n\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\tcase 'IcosahedronGeometry':\r\n\r\n\t\t\t\t\t\tgeometry = new THREE.IcosahedronGeometry(\r\n\t\t\t\t\t\t\tdata.radius,\r\n\t\t\t\t\t\t\tdata.detail\r\n\t\t\t\t\t\t);\r\n\r\n\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\tcase 'TorusGeometry':\r\n\r\n\t\t\t\t\t\tgeometry = new THREE.TorusGeometry(\r\n\t\t\t\t\t\t\tdata.radius,\r\n\t\t\t\t\t\t\tdata.tube,\r\n\t\t\t\t\t\t\tdata.radialSegments,\r\n\t\t\t\t\t\t\tdata.tubularSegments,\r\n\t\t\t\t\t\t\tdata.arc\r\n\t\t\t\t\t\t);\r\n\r\n\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\tcase 'TorusKnotGeometry':\r\n\r\n\t\t\t\t\t\tgeometry = new THREE.TorusKnotGeometry(\r\n\t\t\t\t\t\t\tdata.radius,\r\n\t\t\t\t\t\t\tdata.tube,\r\n\t\t\t\t\t\t\tdata.radialSegments,\r\n\t\t\t\t\t\t\tdata.tubularSegments,\r\n\t\t\t\t\t\t\tdata.p,\r\n\t\t\t\t\t\t\tdata.q,\r\n\t\t\t\t\t\t\tdata.heightScale\r\n\t\t\t\t\t\t);\r\n\r\n\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\tcase 'BufferGeometry':\r\n\r\n\t\t\t\t\t\tgeometry = bufferGeometryLoader.parse( data );\r\n\r\n\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\tcase 'Geometry':\r\n\r\n\t\t\t\t\t\tgeometry = geometryLoader.parse( data.data ).geometry;\r\n\r\n\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tgeometry.uuid = data.uuid;\r\n\r\n\t\t\t\tif ( data.name !== undefined ) geometry.name = data.name;\r\n\r\n\t\t\t\tgeometries[ data.uuid ] = geometry;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\treturn geometries;\r\n\r\n\t},\r\n\r\n\tparseMaterials: function ( json, textures ) {\r\n\r\n\t\tvar materials = {};\r\n\r\n\t\tif ( json !== undefined ) {\r\n\r\n\t\t\tvar getTexture = function ( name ) {\r\n\r\n\t\t\t\tif ( textures[ name ] === undefined ) {\r\n\r\n\t\t\t\t\tTHREE.warn( 'THREE.ObjectLoader: Undefined texture', name );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn textures[ name ];\r\n\r\n\t\t\t};\r\n\r\n\t\t\tvar loader = new THREE.MaterialLoader();\r\n\r\n\t\t\tfor ( var i = 0, l = json.length; i < l; i ++ ) {\r\n\r\n\t\t\t\tvar data = json[ i ];\r\n\t\t\t\tvar material = loader.parse( data );\r\n\r\n\t\t\t\tmaterial.uuid = data.uuid;\r\n\r\n\t\t\t\tif ( data.name !== undefined ) material.name = data.name;\r\n\r\n\t\t\t\tif ( data.map !== undefined ) {\r\n\r\n\t\t\t\t\tmaterial.map = getTexture( data.map );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif ( data.bumpMap !== undefined ) {\r\n\r\n\t\t\t\t\tmaterial.bumpMap = getTexture( data.bumpMap );\r\n\t\t\t\t\tif ( data.bumpScale ) {\r\n\t\t\t\t\t\tmaterial.bumpScale = new THREE.Vector2( data.bumpScale, data.bumpScale );\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif ( data.alphaMap !== undefined ) {\r\n\r\n\t\t\t\t\tmaterial.alphaMap = getTexture( data.alphaMap );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif ( data.envMap !== undefined ) {\r\n\r\n\t\t\t\t\tmaterial.envMap = getTexture( data.envMap );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif ( data.normalMap !== undefined ) {\r\n\r\n\t\t\t\t\tmaterial.normalMap = getTexture( data.normalMap );\r\n\t\t\t\t\tif ( data.normalScale ) {\r\n\t\t\t\t\t\tmaterial.normalScale = new THREE.Vector2( data.normalScale, data.normalScale );\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif ( data.lightMap !== undefined ) {\r\n\r\n\t\t\t\t\tmaterial.lightMap = getTexture( data.lightMap );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif ( data.specularMap !== undefined ) {\r\n\r\n\t\t\t\t\tmaterial.specularMap = getTexture( data.specularMap );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tmaterials[ data.uuid ] = material;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\treturn materials;\r\n\r\n\t},\r\n\r\n\tparseImages: function ( json, onLoad ) {\r\n\r\n\t\tvar scope = this;\r\n\t\tvar images = {};\r\n\r\n\t\tif ( json !== undefined && json.length > 0 ) {\r\n\r\n\t\t\tvar manager = new THREE.LoadingManager( onLoad );\r\n\r\n\t\t\tvar loader = new THREE.ImageLoader( manager );\r\n\t\t\tloader.setCrossOrigin( this.crossOrigin );\r\n\r\n\t\t\tvar loadImage = function ( url ) {\r\n\r\n\t\t\t\tscope.manager.itemStart( url );\r\n\r\n\t\t\t\treturn loader.load( url, function () {\r\n\r\n\t\t\t\t\tscope.manager.itemEnd( url );\r\n\r\n\t\t\t\t} );\r\n\r\n\t\t\t};\r\n\r\n\t\t\tfor ( var i = 0, l = json.length; i < l; i ++ ) {\r\n\r\n\t\t\t\tvar image = json[ i ];\r\n\t\t\t\tvar path = /^(\\/\\/)|([a-z]+:(\\/\\/)?)/i.test( image.url ) ? image.url : scope.texturePath + image.url;\r\n\r\n\t\t\t\timages[ image.uuid ] = loadImage( path );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\treturn images;\r\n\r\n\t},\r\n\r\n\tparseTextures: function ( json, images ) {\r\n\r\n\t\tvar textures = {};\r\n\r\n\t\tif ( json !== undefined ) {\r\n\r\n\t\t\tfor ( var i = 0, l = json.length; i < l; i ++ ) {\r\n\r\n\t\t\t\tvar data = json[ i ];\r\n\r\n\t\t\t\tif ( data.image === undefined ) {\r\n\r\n\t\t\t\t\tTHREE.warn( 'THREE.ObjectLoader: No \"image\" speficied for', data.uuid );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif ( images[ data.image ] === undefined ) {\r\n\r\n\t\t\t\t\tTHREE.warn( 'THREE.ObjectLoader: Undefined image', data.image );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvar texture = new THREE.Texture( images[ data.image ] );\r\n\t\t\t\ttexture.needsUpdate = true;\r\n\r\n\t\t\t\ttexture.uuid = data.uuid;\r\n\r\n\t\t\t\tif ( data.name !== undefined ) texture.name = data.name;\r\n\t\t\t\tif ( data.repeat !== undefined ) texture.repeat = new THREE.Vector2( data.repeat[ 0 ], data.repeat[ 1 ] );\r\n\t\t\t\tif ( data.minFilter !== undefined ) texture.minFilter = THREE[ data.minFilter ];\r\n\t\t\t\tif ( data.magFilter !== undefined ) texture.magFilter = THREE[ data.magFilter ];\r\n\t\t\t\tif ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy;\r\n\t\t\t\tif ( data.wrap instanceof Array ) {\r\n\r\n\t\t\t\t\ttexture.wrapS = THREE[ data.wrap[ 0 ] ];\r\n\t\t\t\t\ttexture.wrapT = THREE[ data.wrap[ 1 ] ];\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\ttextures[ data.uuid ] = texture;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\treturn textures;\r\n\r\n\t},\r\n\r\n\tparseObject: function () {\r\n\r\n\t\tvar matrix = new THREE.Matrix4();\r\n\r\n\t\treturn function ( data, geometries, materials ) {\r\n\r\n\t\t\tvar object;\r\n\r\n\t\t\tvar getGeometry = function ( name ) {\r\n\r\n\t\t\t\tif ( geometries[ name ] === undefined ) {\r\n\r\n\t\t\t\t\tTHREE.warn( 'THREE.ObjectLoader: Undefined geometry', name );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn geometries[ name ];\r\n\r\n\t\t\t};\r\n\r\n\t\t\tvar getMaterial = function ( name ) {\r\n\r\n\t\t\t\tif ( materials[ name ] === undefined ) {\r\n\r\n\t\t\t\t\tTHREE.warn( 'THREE.ObjectLoader: Undefined material', name );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn materials[ name ];\r\n\r\n\t\t\t};\r\n\r\n\t\t\tswitch ( data.type ) {\r\n\r\n\t\t\t\tcase 'Scene':\r\n\r\n\t\t\t\t\tobject = new THREE.Scene();\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 'PerspectiveCamera':\r\n\r\n\t\t\t\t\tobject = new THREE.PerspectiveCamera( data.fov, data.aspect, data.near, data.far );\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 'OrthographicCamera':\r\n\r\n\t\t\t\t\tobject = new THREE.OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far );\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 'AmbientLight':\r\n\r\n\t\t\t\t\tobject = new THREE.AmbientLight( data.color );\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 'DirectionalLight':\r\n\r\n\t\t\t\t\tobject = new THREE.DirectionalLight( data.color, data.intensity );\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 'PointLight':\r\n\r\n\t\t\t\t\tobject = new THREE.PointLight( data.color, data.intensity, data.distance, data.decay );\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 'SpotLight':\r\n\r\n\t\t\t\t\tobject = new THREE.SpotLight( data.color, data.intensity, data.distance, data.angle, data.exponent, data.decay );\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 'HemisphereLight':\r\n\r\n\t\t\t\t\tobject = new THREE.HemisphereLight( data.color, data.groundColor, data.intensity );\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 'Mesh':\r\n\r\n\t\t\t\t\tobject = new THREE.Mesh( getGeometry( data.geometry ), getMaterial( data.material ) );\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 'Line':\r\n\r\n\t\t\t\t\tobject = new THREE.Line( getGeometry( data.geometry ), getMaterial( data.material ), data.mode );\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 'PointCloud':\r\n\r\n\t\t\t\t\tobject = new THREE.PointCloud( getGeometry( data.geometry ), getMaterial( data.material ) );\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 'Sprite':\r\n\r\n\t\t\t\t\tobject = new THREE.Sprite( getMaterial( data.material ) );\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 'Group':\r\n\r\n\t\t\t\t\tobject = new THREE.Group();\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tdefault:\r\n\r\n\t\t\t\t\tobject = new THREE.Object3D();\r\n\r\n\t\t\t}\r\n\r\n\t\t\tobject.uuid = data.uuid;\r\n\r\n\t\t\tif ( data.name !== undefined ) object.name = data.name;\r\n\t\t\tif ( data.matrix !== undefined ) {\r\n\r\n\t\t\t\tmatrix.fromArray( data.matrix );\r\n\t\t\t\tmatrix.decompose( object.position, object.quaternion, object.scale );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tif ( data.position !== undefined ) object.position.fromArray( data.position );\r\n\t\t\t\tif ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation );\r\n\t\t\t\tif ( data.scale !== undefined ) object.scale.fromArray( data.scale );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( data.visible !== undefined ) object.visible = data.visible;\r\n\t\t\tif ( data.userData !== undefined ) object.userData = data.userData;\r\n\r\n\t\t\tif ( data.children !== undefined ) {\r\n\r\n\t\t\t\tfor ( var child in data.children ) {\r\n\r\n\t\t\t\t\tobject.add( this.parseObject( data.children[ child ], geometries, materials ) );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\treturn object;\r\n\r\n\t\t}\r\n\r\n\t}()\r\n\r\n};\r\n\r\n// File:src/loaders/TextureLoader.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n */\r\n\r\nTHREE.TextureLoader = function ( manager ) {\r\n\r\n\tthis.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;\r\n\r\n};\r\n\r\nTHREE.TextureLoader.prototype = {\r\n\r\n\tconstructor: THREE.TextureLoader,\r\n\r\n\tload: function ( url, onLoad, onProgress, onError ) {\r\n\r\n\t\tvar scope = this;\r\n\r\n\t\tvar loader = new THREE.ImageLoader( scope.manager );\r\n\t\tloader.setCrossOrigin( this.crossOrigin );\r\n\t\tloader.load( url, function ( image ) {\r\n\r\n\t\t\tvar texture = new THREE.Texture( image );\r\n\t\t\ttexture.needsUpdate = true;\r\n\r\n\t\t\tif ( onLoad !== undefined ) {\r\n\r\n\t\t\t\tonLoad( texture );\r\n\r\n\t\t\t}\r\n\r\n\t\t}, onProgress, onError );\r\n\r\n\t},\r\n\r\n\tsetCrossOrigin: function ( value ) {\r\n\r\n\t\tthis.crossOrigin = value;\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/loaders/BinaryTextureLoader.js\r\n\r\n/**\r\n * @author Nikos M. / https://github.com/foo123/\r\n *\r\n * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...)\r\n */\r\n\r\nTHREE.DataTextureLoader = THREE.BinaryTextureLoader = function () {\r\n\r\n\t// override in sub classes\r\n\tthis._parser = null;\r\n\r\n};\r\n\r\nTHREE.BinaryTextureLoader.prototype = {\r\n\r\n\tconstructor: THREE.BinaryTextureLoader,\r\n\r\n\tload: function ( url, onLoad, onProgress, onError ) {\r\n\r\n\t\tvar scope = this;\r\n\r\n\t\tvar texture = new THREE.DataTexture( );\r\n\r\n\t\tvar loader = new THREE.XHRLoader();\r\n\t\tloader.setResponseType( 'arraybuffer' );\r\n\r\n\t\tloader.load( url, function ( buffer ) {\r\n\r\n\t\t\tvar texData = scope._parser( buffer );\r\n\r\n\t\t\tif ( !texData ) return;\r\n\r\n\t\t\tif ( undefined !== texData.image ) {\r\n\r\n\t\t\t\ttexture.image = texData.image;\r\n\r\n\t\t\t} else if ( undefined !== texData.data ) {\r\n\r\n\t\t\t\ttexture.image.width = texData.width;\r\n\t\t\t\ttexture.image.height = texData.height;\r\n\t\t\t\ttexture.image.data = texData.data;\r\n\r\n\t\t\t}\r\n\r\n\t\t\ttexture.wrapS = undefined !== texData.wrapS ? texData.wrapS : THREE.ClampToEdgeWrapping;\r\n\t\t\ttexture.wrapT = undefined !== texData.wrapT ? texData.wrapT : THREE.ClampToEdgeWrapping;\r\n\r\n\t\t\ttexture.magFilter = undefined !== texData.magFilter ? texData.magFilter : THREE.LinearFilter;\r\n\t\t\ttexture.minFilter = undefined !== texData.minFilter ? texData.minFilter : THREE.LinearMipMapLinearFilter;\r\n\r\n\t\t\ttexture.anisotropy = undefined !== texData.anisotropy ? texData.anisotropy : 1;\r\n\r\n\t\t\tif ( undefined !== texData.format ) {\r\n\r\n\t\t\t\ttexture.format = texData.format;\r\n\r\n\t\t\t}\r\n\t\t\tif ( undefined !== texData.type ) {\r\n\r\n\t\t\t\ttexture.type = texData.type;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( undefined !== texData.mipmaps ) {\r\n\r\n\t\t\t\ttexture.mipmaps = texData.mipmaps;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( 1 === texData.mipmapCount ) {\r\n\r\n\t\t\t\ttexture.minFilter = THREE.LinearFilter;\r\n\r\n\t\t\t}\r\n\r\n\t\t\ttexture.needsUpdate = true;\r\n\r\n\t\t\tif ( onLoad ) onLoad( texture, texData );\r\n\r\n\t\t}, onProgress, onError );\r\n\r\n\r\n\t\treturn texture;\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/loaders/CompressedTextureLoader.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n *\r\n * Abstract Base class to block based textures loader (dds, pvr, ...)\r\n */\r\n\r\nTHREE.CompressedTextureLoader = function () {\r\n\r\n\t// override in sub classes\r\n\tthis._parser = null;\r\n\r\n};\r\n\r\n\r\nTHREE.CompressedTextureLoader.prototype = {\r\n\r\n\tconstructor: THREE.CompressedTextureLoader,\r\n\r\n\tload: function ( url, onLoad, onError ) {\r\n\r\n\t\tvar scope = this;\r\n\r\n\t\tvar images = [];\r\n\r\n\t\tvar texture = new THREE.CompressedTexture();\r\n\t\ttexture.image = images;\r\n\r\n\t\tvar loader = new THREE.XHRLoader();\r\n\t\tloader.setResponseType( 'arraybuffer' );\r\n\r\n\t\tif ( url instanceof Array ) {\r\n\r\n\t\t\tvar loaded = 0;\r\n\r\n\t\t\tvar loadTexture = function ( i ) {\r\n\r\n\t\t\t\tloader.load( url[ i ], function ( buffer ) {\r\n\r\n\t\t\t\t\tvar texDatas = scope._parser( buffer, true );\r\n\r\n\t\t\t\t\timages[ i ] = {\r\n\t\t\t\t\t\twidth: texDatas.width,\r\n\t\t\t\t\t\theight: texDatas.height,\r\n\t\t\t\t\t\tformat: texDatas.format,\r\n\t\t\t\t\t\tmipmaps: texDatas.mipmaps\r\n\t\t\t\t\t};\r\n\r\n\t\t\t\t\tloaded += 1;\r\n\r\n\t\t\t\t\tif ( loaded === 6 ) {\r\n\r\n\t\t\t\t\t\tif (texDatas.mipmapCount == 1)\r\n \t\t\t\t\t\t\ttexture.minFilter = THREE.LinearFilter;\r\n\r\n\t\t\t\t\t\ttexture.format = texDatas.format;\r\n\t\t\t\t\t\ttexture.needsUpdate = true;\r\n\r\n\t\t\t\t\t\tif ( onLoad ) onLoad( texture );\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t} );\r\n\r\n\t\t\t};\r\n\r\n\t\t\tfor ( var i = 0, il = url.length; i < il; ++ i ) {\r\n\r\n\t\t\t\tloadTexture( i );\r\n\r\n\t\t\t}\r\n\r\n\t\t} else {\r\n\r\n\t\t\t// compressed cubemap texture stored in a single DDS file\r\n\r\n\t\t\tloader.load( url, function ( buffer ) {\r\n\r\n\t\t\t\tvar texDatas = scope._parser( buffer, true );\r\n\r\n\t\t\t\tif ( texDatas.isCubemap ) {\r\n\r\n\t\t\t\t\tvar faces = texDatas.mipmaps.length / texDatas.mipmapCount;\r\n\r\n\t\t\t\t\tfor ( var f = 0; f < faces; f ++ ) {\r\n\r\n\t\t\t\t\t\timages[ f ] = { mipmaps : [] };\r\n\r\n\t\t\t\t\t\tfor ( var i = 0; i < texDatas.mipmapCount; i ++ ) {\r\n\r\n\t\t\t\t\t\t\timages[ f ].mipmaps.push( texDatas.mipmaps[ f * texDatas.mipmapCount + i ] );\r\n\t\t\t\t\t\t\timages[ f ].format = texDatas.format;\r\n\t\t\t\t\t\t\timages[ f ].width = texDatas.width;\r\n\t\t\t\t\t\t\timages[ f ].height = texDatas.height;\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\ttexture.image.width = texDatas.width;\r\n\t\t\t\t\ttexture.image.height = texDatas.height;\r\n\t\t\t\t\ttexture.mipmaps = texDatas.mipmaps;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif ( texDatas.mipmapCount === 1 ) {\r\n\r\n\t\t\t\t\ttexture.minFilter = THREE.LinearFilter;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\ttexture.format = texDatas.format;\r\n\t\t\t\ttexture.needsUpdate = true;\r\n\r\n\t\t\t\tif ( onLoad ) onLoad( texture );\r\n\r\n\t\t\t} );\r\n\r\n\t\t}\r\n\r\n\t\treturn texture;\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/materials/Material.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n * @author alteredq / http://alteredqualia.com/\r\n */\r\n\r\nTHREE.Material = function () {\r\n\r\n\tObject.defineProperty( this, 'id', { value: THREE.MaterialIdCount ++ } );\r\n\r\n\tthis.uuid = THREE.Math.generateUUID();\r\n\r\n\tthis.name = '';\r\n\tthis.type = 'Material';\r\n\r\n\tthis.side = THREE.FrontSide;\r\n\r\n\tthis.opacity = 1;\r\n\tthis.transparent = false;\r\n\r\n\tthis.blending = THREE.NormalBlending;\r\n\r\n\tthis.blendSrc = THREE.SrcAlphaFactor;\r\n\tthis.blendDst = THREE.OneMinusSrcAlphaFactor;\r\n\tthis.blendEquation = THREE.AddEquation;\r\n\tthis.blendSrcAlpha = null;\r\n\tthis.blendDstAlpha = null;\r\n\tthis.blendEquationAlpha = null;\r\n\r\n\tthis.depthTest = true;\r\n\tthis.depthWrite = true;\r\n\r\n\tthis.colorWrite = true;\r\n\r\n\tthis.polygonOffset = false;\r\n\tthis.polygonOffsetFactor = 0;\r\n\tthis.polygonOffsetUnits = 0;\r\n\r\n\tthis.alphaTest = 0;\r\n\r\n\tthis.overdraw = 0; // Overdrawn pixels (typically between 0 and 1) for fixing antialiasing gaps in CanvasRenderer\r\n\r\n\tthis.visible = true;\r\n\r\n\tthis._needsUpdate = true;\r\n\r\n};\r\n\r\nTHREE.Material.prototype = {\r\n\r\n\tconstructor: THREE.Material,\r\n\r\n\tget needsUpdate () {\r\n\r\n\t\treturn this._needsUpdate;\r\n\r\n\t},\r\n\r\n\tset needsUpdate ( value ) {\r\n\r\n\t\tif ( value === true ) this.update();\r\n\r\n\t\tthis._needsUpdate = value;\r\n\r\n\t},\r\n\r\n\tsetValues: function ( values ) {\r\n\r\n\t\tif ( values === undefined ) return;\r\n\r\n\t\tfor ( var key in values ) {\r\n\r\n\t\t\tvar newValue = values[ key ];\r\n\r\n\t\t\tif ( newValue === undefined ) {\r\n\r\n\t\t\t\tTHREE.warn( \"THREE.Material: '\" + key + \"' parameter is undefined.\" );\r\n\t\t\t\tcontinue;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( key in this ) {\r\n\r\n\t\t\t\tvar currentValue = this[ key ];\r\n\r\n\t\t\t\tif ( currentValue instanceof THREE.Color ) {\r\n\r\n\t\t\t\t\tcurrentValue.set( newValue );\r\n\r\n\t\t\t\t} else if ( currentValue instanceof THREE.Vector3 && newValue instanceof THREE.Vector3 ) {\r\n\r\n\t\t\t\t\tcurrentValue.copy( newValue );\r\n\r\n\t\t\t\t} else if ( key == 'overdraw' ) {\r\n\r\n\t\t\t\t\t// ensure overdraw is backwards-compatable with legacy boolean type\r\n\t\t\t\t\tthis[ key ] = Number( newValue );\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\tthis[ key ] = newValue;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t},\r\n\r\n\ttoJSON: function () {\r\n\r\n\t\tvar output = {\r\n\t\t\tmetadata: {\r\n\t\t\t\tversion: 4.2,\r\n\t\t\t\ttype: 'material',\r\n\t\t\t\tgenerator: 'MaterialExporter'\r\n\t\t\t},\r\n\t\t\tuuid: this.uuid,\r\n\t\t\ttype: this.type\r\n\t\t};\r\n\r\n\t\tif ( this.name !== \"\" ) output.name = this.name;\r\n\r\n\t\tif ( this instanceof THREE.MeshBasicMaterial ) {\r\n\r\n\t\t\toutput.color = this.color.getHex();\r\n\t\t\tif ( this.vertexColors !== THREE.NoColors ) output.vertexColors = this.vertexColors;\r\n\t\t\tif ( this.blending !== THREE.NormalBlending ) output.blending = this.blending;\r\n\t\t\tif ( this.side !== THREE.FrontSide ) output.side = this.side;\r\n\r\n\t\t} else if ( this instanceof THREE.MeshLambertMaterial ) {\r\n\r\n\t\t\toutput.color = this.color.getHex();\r\n\t\t\toutput.emissive = this.emissive.getHex();\r\n\t\t\tif ( this.vertexColors !== THREE.NoColors ) output.vertexColors = this.vertexColors;\r\n\t\t\tif ( this.shading !== THREE.SmoothShading ) output.shading = this.shading;\r\n\t\t\tif ( this.blending !== THREE.NormalBlending ) output.blending = this.blending;\r\n\t\t\tif ( this.side !== THREE.FrontSide ) output.side = this.side;\r\n\r\n\t\t} else if ( this instanceof THREE.MeshPhongMaterial ) {\r\n\r\n\t\t\toutput.color = this.color.getHex();\r\n\t\t\toutput.emissive = this.emissive.getHex();\r\n\t\t\toutput.specular = this.specular.getHex();\r\n\t\t\toutput.shininess = this.shininess;\r\n\t\t\tif ( this.vertexColors !== THREE.NoColors ) output.vertexColors = this.vertexColors;\r\n\t\t\tif ( this.shading !== THREE.SmoothShading ) output.shading = this.shading;\r\n\t\t\tif ( this.blending !== THREE.NormalBlending ) output.blending = this.blending;\r\n\t\t\tif ( this.side !== THREE.FrontSide ) output.side = this.side;\r\n\r\n\t\t} else if ( this instanceof THREE.MeshNormalMaterial ) {\r\n\r\n\t\t\tif ( this.blending !== THREE.NormalBlending ) output.blending = this.blending;\r\n\t\t\tif ( this.side !== THREE.FrontSide ) output.side = this.side;\r\n\r\n\t\t} else if ( this instanceof THREE.MeshDepthMaterial ) {\r\n\r\n\t\t\tif ( this.blending !== THREE.NormalBlending ) output.blending = this.blending;\r\n\t\t\tif ( this.side !== THREE.FrontSide ) output.side = this.side;\r\n\r\n\t\t} else if ( this instanceof THREE.PointCloudMaterial ) {\r\n\r\n\t\t\toutput.size = this.size;\r\n\t\t\toutput.sizeAttenuation = this.sizeAttenuation;\r\n\t\t\toutput.color = this.color.getHex();\r\n\r\n\t\t\tif ( this.vertexColors !== THREE.NoColors ) output.vertexColors = this.vertexColors;\r\n\t\t\tif ( this.blending !== THREE.NormalBlending ) output.blending = this.blending;\r\n\r\n\t\t} else if ( this instanceof THREE.ShaderMaterial ) {\r\n\r\n\t\t\toutput.uniforms = this.uniforms;\r\n\t\t\toutput.vertexShader = this.vertexShader;\r\n\t\t\toutput.fragmentShader = this.fragmentShader;\r\n\r\n\t\t} else if ( this instanceof THREE.SpriteMaterial ) {\r\n\r\n\t\t\toutput.color = this.color.getHex();\r\n\r\n\t\t}\r\n\r\n\t\tif ( this.opacity < 1 ) output.opacity = this.opacity;\r\n\t\tif ( this.transparent !== false ) output.transparent = this.transparent;\r\n\t\tif ( this.wireframe !== false ) output.wireframe = this.wireframe;\r\n\r\n\t\treturn output;\r\n\r\n\t},\r\n\r\n\tclone: function ( material ) {\r\n\r\n\t\tif ( material === undefined ) material = new THREE.Material();\r\n\r\n\t\tmaterial.name = this.name;\r\n\r\n\t\tmaterial.side = this.side;\r\n\r\n\t\tmaterial.opacity = this.opacity;\r\n\t\tmaterial.transparent = this.transparent;\r\n\r\n\t\tmaterial.blending = this.blending;\r\n\r\n\t\tmaterial.blendSrc = this.blendSrc;\r\n\t\tmaterial.blendDst = this.blendDst;\r\n\t\tmaterial.blendEquation = this.blendEquation;\r\n\t\tmaterial.blendSrcAlpha = this.blendSrcAlpha;\r\n\t\tmaterial.blendDstAlpha = this.blendDstAlpha;\r\n\t\tmaterial.blendEquationAlpha = this.blendEquationAlpha;\r\n\r\n\t\tmaterial.depthTest = this.depthTest;\r\n\t\tmaterial.depthWrite = this.depthWrite;\r\n\r\n\t\tmaterial.polygonOffset = this.polygonOffset;\r\n\t\tmaterial.polygonOffsetFactor = this.polygonOffsetFactor;\r\n\t\tmaterial.polygonOffsetUnits = this.polygonOffsetUnits;\r\n\r\n\t\tmaterial.alphaTest = this.alphaTest;\r\n\r\n\t\tmaterial.overdraw = this.overdraw;\r\n\r\n\t\tmaterial.visible = this.visible;\r\n\r\n\t\treturn material;\r\n\r\n\t},\r\n\r\n\tupdate: function () {\r\n\r\n\t\tthis.dispatchEvent( { type: 'update' } );\r\n\r\n\t},\r\n\r\n\tdispose: function () {\r\n\r\n\t\tthis.dispatchEvent( { type: 'dispose' } );\r\n\r\n\t}\r\n\r\n};\r\n\r\nTHREE.EventDispatcher.prototype.apply( THREE.Material.prototype );\r\n\r\nTHREE.MaterialIdCount = 0;\r\n\r\n// File:src/materials/LineBasicMaterial.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n * @author alteredq / http://alteredqualia.com/\r\n *\r\n * parameters = {\r\n * color: ,\r\n * opacity: ,\r\n *\r\n * blending: THREE.NormalBlending,\r\n * depthTest: ,\r\n * depthWrite: ,\r\n *\r\n * linewidth: ,\r\n * linecap: \"round\",\r\n * linejoin: \"round\",\r\n *\r\n * vertexColors: \r\n *\r\n * fog: \r\n * }\r\n */\r\n\r\nTHREE.LineBasicMaterial = function ( parameters ) {\r\n\r\n\tTHREE.Material.call( this );\r\n\r\n\tthis.type = 'LineBasicMaterial';\r\n\r\n\tthis.color = new THREE.Color( 0xffffff );\r\n\r\n\tthis.linewidth = 1;\r\n\tthis.linecap = 'round';\r\n\tthis.linejoin = 'round';\r\n\r\n\tthis.vertexColors = THREE.NoColors;\r\n\r\n\tthis.fog = true;\r\n\r\n\tthis.setValues( parameters );\r\n\r\n};\r\n\r\nTHREE.LineBasicMaterial.prototype = Object.create( THREE.Material.prototype );\r\nTHREE.LineBasicMaterial.prototype.constructor = THREE.LineBasicMaterial;\r\n\r\nTHREE.LineBasicMaterial.prototype.clone = function () {\r\n\r\n\tvar material = new THREE.LineBasicMaterial();\r\n\r\n\tTHREE.Material.prototype.clone.call( this, material );\r\n\r\n\tmaterial.color.copy( this.color );\r\n\r\n\tmaterial.linewidth = this.linewidth;\r\n\tmaterial.linecap = this.linecap;\r\n\tmaterial.linejoin = this.linejoin;\r\n\r\n\tmaterial.vertexColors = this.vertexColors;\r\n\r\n\tmaterial.fog = this.fog;\r\n\r\n\treturn material;\r\n\r\n};\r\n\r\n// File:src/materials/LineDashedMaterial.js\r\n\r\n/**\r\n * @author alteredq / http://alteredqualia.com/\r\n *\r\n * parameters = {\r\n * color: ,\r\n * opacity: ,\r\n *\r\n * blending: THREE.NormalBlending,\r\n * depthTest: ,\r\n * depthWrite: ,\r\n *\r\n * linewidth: ,\r\n *\r\n * scale: ,\r\n * dashSize: ,\r\n * gapSize: ,\r\n *\r\n * vertexColors: \r\n *\r\n * fog: \r\n * }\r\n */\r\n\r\nTHREE.LineDashedMaterial = function ( parameters ) {\r\n\r\n\tTHREE.Material.call( this );\r\n\r\n\tthis.type = 'LineDashedMaterial';\r\n\r\n\tthis.color = new THREE.Color( 0xffffff );\r\n\r\n\tthis.linewidth = 1;\r\n\r\n\tthis.scale = 1;\r\n\tthis.dashSize = 3;\r\n\tthis.gapSize = 1;\r\n\r\n\tthis.vertexColors = false;\r\n\r\n\tthis.fog = true;\r\n\r\n\tthis.setValues( parameters );\r\n\r\n};\r\n\r\nTHREE.LineDashedMaterial.prototype = Object.create( THREE.Material.prototype );\r\nTHREE.LineDashedMaterial.prototype.constructor = THREE.LineDashedMaterial;\r\n\r\nTHREE.LineDashedMaterial.prototype.clone = function () {\r\n\r\n\tvar material = new THREE.LineDashedMaterial();\r\n\r\n\tTHREE.Material.prototype.clone.call( this, material );\r\n\r\n\tmaterial.color.copy( this.color );\r\n\r\n\tmaterial.linewidth = this.linewidth;\r\n\r\n\tmaterial.scale = this.scale;\r\n\tmaterial.dashSize = this.dashSize;\r\n\tmaterial.gapSize = this.gapSize;\r\n\r\n\tmaterial.vertexColors = this.vertexColors;\r\n\r\n\tmaterial.fog = this.fog;\r\n\r\n\treturn material;\r\n\r\n};\r\n\r\n// File:src/materials/MeshBasicMaterial.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n * @author alteredq / http://alteredqualia.com/\r\n *\r\n * parameters = {\r\n * color: ,\r\n * opacity: ,\r\n * map: new THREE.Texture( ),\r\n *\r\n * lightMap: new THREE.Texture( ),\r\n *\r\n * specularMap: new THREE.Texture( ),\r\n *\r\n * alphaMap: new THREE.Texture( ),\r\n *\r\n * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ),\r\n * combine: THREE.Multiply,\r\n * reflectivity: ,\r\n * refractionRatio: ,\r\n *\r\n * shading: THREE.SmoothShading,\r\n * blending: THREE.NormalBlending,\r\n * depthTest: ,\r\n * depthWrite: ,\r\n *\r\n * wireframe: ,\r\n * wireframeLinewidth: ,\r\n *\r\n * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors,\r\n *\r\n * skinning: ,\r\n * morphTargets: ,\r\n *\r\n * fog: \r\n * }\r\n */\r\n\r\nTHREE.MeshBasicMaterial = function ( parameters ) {\r\n\r\n\tTHREE.Material.call( this );\r\n\r\n\tthis.type = 'MeshBasicMaterial';\r\n\r\n\tthis.color = new THREE.Color( 0xffffff ); // emissive\r\n\r\n\tthis.map = null;\r\n\r\n\tthis.lightMap = null;\r\n\r\n\tthis.specularMap = null;\r\n\r\n\tthis.alphaMap = null;\r\n\r\n\tthis.envMap = null;\r\n\tthis.combine = THREE.MultiplyOperation;\r\n\tthis.reflectivity = 1;\r\n\tthis.refractionRatio = 0.98;\r\n\r\n\tthis.fog = true;\r\n\r\n\tthis.shading = THREE.SmoothShading;\r\n\r\n\tthis.wireframe = false;\r\n\tthis.wireframeLinewidth = 1;\r\n\tthis.wireframeLinecap = 'round';\r\n\tthis.wireframeLinejoin = 'round';\r\n\r\n\tthis.vertexColors = THREE.NoColors;\r\n\r\n\tthis.skinning = false;\r\n\tthis.morphTargets = false;\r\n\r\n\tthis.setValues( parameters );\r\n\r\n};\r\n\r\nTHREE.MeshBasicMaterial.prototype = Object.create( THREE.Material.prototype );\r\nTHREE.MeshBasicMaterial.prototype.constructor = THREE.MeshBasicMaterial;\r\n\r\nTHREE.MeshBasicMaterial.prototype.clone = function () {\r\n\r\n\tvar material = new THREE.MeshBasicMaterial();\r\n\r\n\tTHREE.Material.prototype.clone.call( this, material );\r\n\r\n\tmaterial.color.copy( this.color );\r\n\r\n\tmaterial.map = this.map;\r\n\r\n\tmaterial.lightMap = this.lightMap;\r\n\r\n\tmaterial.specularMap = this.specularMap;\r\n\r\n\tmaterial.alphaMap = this.alphaMap;\r\n\r\n\tmaterial.envMap = this.envMap;\r\n\tmaterial.combine = this.combine;\r\n\tmaterial.reflectivity = this.reflectivity;\r\n\tmaterial.refractionRatio = this.refractionRatio;\r\n\r\n\tmaterial.fog = this.fog;\r\n\r\n\tmaterial.shading = this.shading;\r\n\r\n\tmaterial.wireframe = this.wireframe;\r\n\tmaterial.wireframeLinewidth = this.wireframeLinewidth;\r\n\tmaterial.wireframeLinecap = this.wireframeLinecap;\r\n\tmaterial.wireframeLinejoin = this.wireframeLinejoin;\r\n\r\n\tmaterial.vertexColors = this.vertexColors;\r\n\r\n\tmaterial.skinning = this.skinning;\r\n\tmaterial.morphTargets = this.morphTargets;\r\n\r\n\treturn material;\r\n\r\n};\r\n\r\n// File:src/materials/MeshLambertMaterial.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n * @author alteredq / http://alteredqualia.com/\r\n *\r\n * parameters = {\r\n * color: ,\r\n * emissive: ,\r\n * opacity: ,\r\n *\r\n * map: new THREE.Texture( ),\r\n *\r\n * lightMap: new THREE.Texture( ),\r\n *\r\n * specularMap: new THREE.Texture( ),\r\n *\r\n * alphaMap: new THREE.Texture( ),\r\n *\r\n * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ),\r\n * combine: THREE.Multiply,\r\n * reflectivity: ,\r\n * refractionRatio: ,\r\n *\r\n * shading: THREE.SmoothShading,\r\n * blending: THREE.NormalBlending,\r\n * depthTest: ,\r\n * depthWrite: ,\r\n *\r\n * wireframe: ,\r\n * wireframeLinewidth: ,\r\n *\r\n * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors,\r\n *\r\n * skinning: ,\r\n * morphTargets: ,\r\n * morphNormals: ,\r\n *\r\n *\tfog: \r\n * }\r\n */\r\n\r\nTHREE.MeshLambertMaterial = function ( parameters ) {\r\n\r\n\tTHREE.Material.call( this );\r\n\r\n\tthis.type = 'MeshLambertMaterial';\r\n\r\n\tthis.color = new THREE.Color( 0xffffff ); // diffuse\r\n\tthis.emissive = new THREE.Color( 0x000000 );\r\n\r\n\tthis.wrapAround = false;\r\n\tthis.wrapRGB = new THREE.Vector3( 1, 1, 1 );\r\n\r\n\tthis.map = null;\r\n\r\n\tthis.lightMap = null;\r\n\r\n\tthis.specularMap = null;\r\n\r\n\tthis.alphaMap = null;\r\n\r\n\tthis.envMap = null;\r\n\tthis.combine = THREE.MultiplyOperation;\r\n\tthis.reflectivity = 1;\r\n\tthis.refractionRatio = 0.98;\r\n\r\n\tthis.fog = true;\r\n\r\n\tthis.shading = THREE.SmoothShading;\r\n\r\n\tthis.wireframe = false;\r\n\tthis.wireframeLinewidth = 1;\r\n\tthis.wireframeLinecap = 'round';\r\n\tthis.wireframeLinejoin = 'round';\r\n\r\n\tthis.vertexColors = THREE.NoColors;\r\n\r\n\tthis.skinning = false;\r\n\tthis.morphTargets = false;\r\n\tthis.morphNormals = false;\r\n\r\n\tthis.setValues( parameters );\r\n\r\n};\r\n\r\nTHREE.MeshLambertMaterial.prototype = Object.create( THREE.Material.prototype );\r\nTHREE.MeshLambertMaterial.prototype.constructor = THREE.MeshLambertMaterial;\r\n\r\nTHREE.MeshLambertMaterial.prototype.clone = function () {\r\n\r\n\tvar material = new THREE.MeshLambertMaterial();\r\n\r\n\tTHREE.Material.prototype.clone.call( this, material );\r\n\r\n\tmaterial.color.copy( this.color );\r\n\tmaterial.emissive.copy( this.emissive );\r\n\r\n\tmaterial.wrapAround = this.wrapAround;\r\n\tmaterial.wrapRGB.copy( this.wrapRGB );\r\n\r\n\tmaterial.map = this.map;\r\n\r\n\tmaterial.lightMap = this.lightMap;\r\n\r\n\tmaterial.specularMap = this.specularMap;\r\n\r\n\tmaterial.alphaMap = this.alphaMap;\r\n\r\n\tmaterial.envMap = this.envMap;\r\n\tmaterial.combine = this.combine;\r\n\tmaterial.reflectivity = this.reflectivity;\r\n\tmaterial.refractionRatio = this.refractionRatio;\r\n\r\n\tmaterial.fog = this.fog;\r\n\r\n\tmaterial.shading = this.shading;\r\n\r\n\tmaterial.wireframe = this.wireframe;\r\n\tmaterial.wireframeLinewidth = this.wireframeLinewidth;\r\n\tmaterial.wireframeLinecap = this.wireframeLinecap;\r\n\tmaterial.wireframeLinejoin = this.wireframeLinejoin;\r\n\r\n\tmaterial.vertexColors = this.vertexColors;\r\n\r\n\tmaterial.skinning = this.skinning;\r\n\tmaterial.morphTargets = this.morphTargets;\r\n\tmaterial.morphNormals = this.morphNormals;\r\n\r\n\treturn material;\r\n\r\n};\r\n\r\n// File:src/materials/MeshPhongMaterial.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n * @author alteredq / http://alteredqualia.com/\r\n *\r\n * parameters = {\r\n * color: ,\r\n * emissive: ,\r\n * specular: ,\r\n * shininess: ,\r\n * opacity: ,\r\n *\r\n * map: new THREE.Texture( ),\r\n *\r\n * lightMap: new THREE.Texture( ),\r\n *\r\n * bumpMap: new THREE.Texture( ),\r\n * bumpScale: ,\r\n *\r\n * normalMap: new THREE.Texture( ),\r\n * normalScale: ,\r\n *\r\n * specularMap: new THREE.Texture( ),\r\n *\r\n * alphaMap: new THREE.Texture( ),\r\n *\r\n * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ),\r\n * combine: THREE.Multiply,\r\n * reflectivity: ,\r\n * refractionRatio: ,\r\n *\r\n * shading: THREE.SmoothShading,\r\n * blending: THREE.NormalBlending,\r\n * depthTest: ,\r\n * depthWrite: ,\r\n *\r\n * wireframe: ,\r\n * wireframeLinewidth: ,\r\n *\r\n * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors,\r\n *\r\n * skinning: ,\r\n * morphTargets: ,\r\n * morphNormals: ,\r\n *\r\n *\tfog: \r\n * }\r\n */\r\n\r\nTHREE.MeshPhongMaterial = function ( parameters ) {\r\n\r\n\tTHREE.Material.call( this );\r\n\r\n\tthis.type = 'MeshPhongMaterial';\r\n\r\n\tthis.color = new THREE.Color( 0xffffff ); // diffuse\r\n\tthis.emissive = new THREE.Color( 0x000000 );\r\n\tthis.specular = new THREE.Color( 0x111111 );\r\n\tthis.shininess = 30;\r\n\r\n\tthis.metal = false;\r\n\r\n\tthis.wrapAround = false;\r\n\tthis.wrapRGB = new THREE.Vector3( 1, 1, 1 );\r\n\r\n\tthis.map = null;\r\n\r\n\tthis.lightMap = null;\r\n\r\n\tthis.bumpMap = null;\r\n\tthis.bumpScale = 1;\r\n\r\n\tthis.normalMap = null;\r\n\tthis.normalScale = new THREE.Vector2( 1, 1 );\r\n\r\n\tthis.specularMap = null;\r\n\r\n\tthis.alphaMap = null;\r\n\r\n\tthis.envMap = null;\r\n\tthis.combine = THREE.MultiplyOperation;\r\n\tthis.reflectivity = 1;\r\n\tthis.refractionRatio = 0.98;\r\n\r\n\tthis.fog = true;\r\n\r\n\tthis.shading = THREE.SmoothShading;\r\n\r\n\tthis.wireframe = false;\r\n\tthis.wireframeLinewidth = 1;\r\n\tthis.wireframeLinecap = 'round';\r\n\tthis.wireframeLinejoin = 'round';\r\n\r\n\tthis.vertexColors = THREE.NoColors;\r\n\r\n\tthis.skinning = false;\r\n\tthis.morphTargets = false;\r\n\tthis.morphNormals = false;\r\n\r\n\tthis.setValues( parameters );\r\n\r\n};\r\n\r\nTHREE.MeshPhongMaterial.prototype = Object.create( THREE.Material.prototype );\r\nTHREE.MeshPhongMaterial.prototype.constructor = THREE.MeshPhongMaterial;\r\n\r\nTHREE.MeshPhongMaterial.prototype.clone = function () {\r\n\r\n\tvar material = new THREE.MeshPhongMaterial();\r\n\r\n\tTHREE.Material.prototype.clone.call( this, material );\r\n\r\n\tmaterial.color.copy( this.color );\r\n\tmaterial.emissive.copy( this.emissive );\r\n\tmaterial.specular.copy( this.specular );\r\n\tmaterial.shininess = this.shininess;\r\n\r\n\tmaterial.metal = this.metal;\r\n\r\n\tmaterial.wrapAround = this.wrapAround;\r\n\tmaterial.wrapRGB.copy( this.wrapRGB );\r\n\r\n\tmaterial.map = this.map;\r\n\r\n\tmaterial.lightMap = this.lightMap;\r\n\r\n\tmaterial.bumpMap = this.bumpMap;\r\n\tmaterial.bumpScale = this.bumpScale;\r\n\r\n\tmaterial.normalMap = this.normalMap;\r\n\tmaterial.normalScale.copy( this.normalScale );\r\n\r\n\tmaterial.specularMap = this.specularMap;\r\n\r\n\tmaterial.alphaMap = this.alphaMap;\r\n\r\n\tmaterial.envMap = this.envMap;\r\n\tmaterial.combine = this.combine;\r\n\tmaterial.reflectivity = this.reflectivity;\r\n\tmaterial.refractionRatio = this.refractionRatio;\r\n\r\n\tmaterial.fog = this.fog;\r\n\r\n\tmaterial.shading = this.shading;\r\n\r\n\tmaterial.wireframe = this.wireframe;\r\n\tmaterial.wireframeLinewidth = this.wireframeLinewidth;\r\n\tmaterial.wireframeLinecap = this.wireframeLinecap;\r\n\tmaterial.wireframeLinejoin = this.wireframeLinejoin;\r\n\r\n\tmaterial.vertexColors = this.vertexColors;\r\n\r\n\tmaterial.skinning = this.skinning;\r\n\tmaterial.morphTargets = this.morphTargets;\r\n\tmaterial.morphNormals = this.morphNormals;\r\n\r\n\treturn material;\r\n\r\n};\r\n\r\n// File:src/materials/MeshDepthMaterial.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n * @author alteredq / http://alteredqualia.com/\r\n *\r\n * parameters = {\r\n * opacity: ,\r\n *\r\n * blending: THREE.NormalBlending,\r\n * depthTest: ,\r\n * depthWrite: ,\r\n *\r\n * wireframe: ,\r\n * wireframeLinewidth: \r\n * }\r\n */\r\n\r\nTHREE.MeshDepthMaterial = function ( parameters ) {\r\n\r\n\tTHREE.Material.call( this );\r\n\r\n\tthis.type = 'MeshDepthMaterial';\r\n\r\n\tthis.morphTargets = false;\r\n\tthis.wireframe = false;\r\n\tthis.wireframeLinewidth = 1;\r\n\r\n\tthis.setValues( parameters );\r\n\r\n};\r\n\r\nTHREE.MeshDepthMaterial.prototype = Object.create( THREE.Material.prototype );\r\nTHREE.MeshDepthMaterial.prototype.constructor = THREE.MeshDepthMaterial;\r\n\r\nTHREE.MeshDepthMaterial.prototype.clone = function () {\r\n\r\n\tvar material = new THREE.MeshDepthMaterial();\r\n\r\n\tTHREE.Material.prototype.clone.call( this, material );\r\n\r\n\tmaterial.wireframe = this.wireframe;\r\n\tmaterial.wireframeLinewidth = this.wireframeLinewidth;\r\n\r\n\treturn material;\r\n\r\n};\r\n\r\n// File:src/materials/MeshNormalMaterial.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n *\r\n * parameters = {\r\n * opacity: ,\r\n *\r\n * shading: THREE.FlatShading,\r\n * blending: THREE.NormalBlending,\r\n * depthTest: ,\r\n * depthWrite: ,\r\n *\r\n * wireframe: ,\r\n * wireframeLinewidth: \r\n * }\r\n */\r\n\r\nTHREE.MeshNormalMaterial = function ( parameters ) {\r\n\r\n\tTHREE.Material.call( this, parameters );\r\n\r\n\tthis.type = 'MeshNormalMaterial';\r\n\r\n\tthis.wireframe = false;\r\n\tthis.wireframeLinewidth = 1;\r\n\r\n\tthis.morphTargets = false;\r\n\r\n\tthis.setValues( parameters );\r\n\r\n};\r\n\r\nTHREE.MeshNormalMaterial.prototype = Object.create( THREE.Material.prototype );\r\nTHREE.MeshNormalMaterial.prototype.constructor = THREE.MeshNormalMaterial;\r\n\r\nTHREE.MeshNormalMaterial.prototype.clone = function () {\r\n\r\n\tvar material = new THREE.MeshNormalMaterial();\r\n\r\n\tTHREE.Material.prototype.clone.call( this, material );\r\n\r\n\tmaterial.wireframe = this.wireframe;\r\n\tmaterial.wireframeLinewidth = this.wireframeLinewidth;\r\n\r\n\treturn material;\r\n\r\n};\r\n\r\n// File:src/materials/MeshFaceMaterial.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n */\r\n\r\nTHREE.MeshFaceMaterial = function ( materials ) {\r\n\r\n\tthis.uuid = THREE.Math.generateUUID();\r\n\r\n\tthis.type = 'MeshFaceMaterial';\r\n\t\r\n\tthis.materials = materials instanceof Array ? materials : [];\r\n\r\n};\r\n\r\nTHREE.MeshFaceMaterial.prototype = {\r\n\r\n\tconstructor: THREE.MeshFaceMaterial,\r\n\r\n\ttoJSON: function () {\r\n\r\n\t\tvar output = {\r\n\t\t\tmetadata: {\r\n\t\t\t\tversion: 4.2,\r\n\t\t\t\ttype: 'material',\r\n\t\t\t\tgenerator: 'MaterialExporter'\r\n\t\t\t},\r\n\t\t\tuuid: this.uuid,\r\n\t\t\ttype: this.type,\r\n\t\t\tmaterials: []\r\n\t\t};\r\n\r\n\t\tfor ( var i = 0, l = this.materials.length; i < l; i ++ ) {\r\n\r\n\t\t\toutput.materials.push( this.materials[ i ].toJSON() );\r\n\r\n\t\t}\r\n\r\n\t\treturn output;\r\n\r\n\t},\r\n\r\n\tclone: function () {\r\n\r\n\t\tvar material = new THREE.MeshFaceMaterial();\r\n\r\n\t\tfor ( var i = 0; i < this.materials.length; i ++ ) {\r\n\r\n\t\t\tmaterial.materials.push( this.materials[ i ].clone() );\r\n\r\n\t\t}\r\n\r\n\t\treturn material;\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/materials/PointCloudMaterial.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n * @author alteredq / http://alteredqualia.com/\r\n *\r\n * parameters = {\r\n * color: ,\r\n * opacity: ,\r\n * map: new THREE.Texture( ),\r\n *\r\n * size: ,\r\n * sizeAttenuation: ,\r\n *\r\n * blending: THREE.NormalBlending,\r\n * depthTest: ,\r\n * depthWrite: ,\r\n *\r\n * vertexColors: ,\r\n *\r\n * fog: \r\n * }\r\n */\r\n\r\nTHREE.PointCloudMaterial = function ( parameters ) {\r\n\r\n\tTHREE.Material.call( this );\r\n\r\n\tthis.type = 'PointCloudMaterial';\r\n\r\n\tthis.color = new THREE.Color( 0xffffff );\r\n\r\n\tthis.map = null;\r\n\r\n\tthis.size = 1;\r\n\tthis.sizeAttenuation = true;\r\n\r\n\tthis.vertexColors = THREE.NoColors;\r\n\r\n\tthis.fog = true;\r\n\r\n\tthis.setValues( parameters );\r\n\r\n};\r\n\r\nTHREE.PointCloudMaterial.prototype = Object.create( THREE.Material.prototype );\r\nTHREE.PointCloudMaterial.prototype.constructor = THREE.PointCloudMaterial;\r\n\r\nTHREE.PointCloudMaterial.prototype.clone = function () {\r\n\r\n\tvar material = new THREE.PointCloudMaterial();\r\n\r\n\tTHREE.Material.prototype.clone.call( this, material );\r\n\r\n\tmaterial.color.copy( this.color );\r\n\r\n\tmaterial.map = this.map;\r\n\r\n\tmaterial.size = this.size;\r\n\tmaterial.sizeAttenuation = this.sizeAttenuation;\r\n\r\n\tmaterial.vertexColors = this.vertexColors;\r\n\r\n\tmaterial.fog = this.fog;\r\n\r\n\treturn material;\r\n\r\n};\r\n\r\n// backwards compatibility\r\n\r\nTHREE.ParticleBasicMaterial = function ( parameters ) {\r\n\r\n\tTHREE.warn( 'THREE.ParticleBasicMaterial has been renamed to THREE.PointCloudMaterial.' );\r\n\treturn new THREE.PointCloudMaterial( parameters );\r\n\r\n};\r\n\r\nTHREE.ParticleSystemMaterial = function ( parameters ) {\r\n\r\n\tTHREE.warn( 'THREE.ParticleSystemMaterial has been renamed to THREE.PointCloudMaterial.' );\r\n\treturn new THREE.PointCloudMaterial( parameters );\r\n\r\n};\r\n\r\n// File:src/materials/ShaderMaterial.js\r\n\r\n/**\r\n * @author alteredq / http://alteredqualia.com/\r\n *\r\n * parameters = {\r\n * defines: { \"label\" : \"value\" },\r\n * uniforms: { \"parameter1\": { type: \"f\", value: 1.0 }, \"parameter2\": { type: \"i\" value2: 2 } },\r\n *\r\n * fragmentShader: ,\r\n * vertexShader: ,\r\n *\r\n * shading: THREE.SmoothShading,\r\n * blending: THREE.NormalBlending,\r\n * depthTest: ,\r\n * depthWrite: ,\r\n *\r\n * wireframe: ,\r\n * wireframeLinewidth: ,\r\n *\r\n * lights: ,\r\n *\r\n * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors,\r\n *\r\n * skinning: ,\r\n * morphTargets: ,\r\n * morphNormals: ,\r\n *\r\n *\tfog: \r\n * }\r\n */\r\n\r\nTHREE.ShaderMaterial = function ( parameters ) {\r\n\r\n\tTHREE.Material.call( this );\r\n\r\n\tthis.type = 'ShaderMaterial';\r\n\r\n\tthis.defines = {};\r\n\tthis.uniforms = {};\r\n\tthis.attributes = null;\r\n\r\n\tthis.vertexShader = 'void main() {\\n\\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\\n}';\r\n\tthis.fragmentShader = 'void main() {\\n\\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\\n}';\r\n\r\n\tthis.shading = THREE.SmoothShading;\r\n\r\n\tthis.linewidth = 1;\r\n\r\n\tthis.wireframe = false;\r\n\tthis.wireframeLinewidth = 1;\r\n\r\n\tthis.fog = false; // set to use scene fog\r\n\r\n\tthis.lights = false; // set to use scene lights\r\n\r\n\tthis.vertexColors = THREE.NoColors; // set to use \"color\" attribute stream\r\n\r\n\tthis.skinning = false; // set to use skinning attribute streams\r\n\r\n\tthis.morphTargets = false; // set to use morph targets\r\n\tthis.morphNormals = false; // set to use morph normals\r\n\r\n\t// When rendered geometry doesn't include these attributes but the material does,\r\n\t// use these default values in WebGL. This avoids errors when buffer data is missing.\r\n\tthis.defaultAttributeValues = {\r\n\t\t'color': [ 1, 1, 1 ],\r\n\t\t'uv': [ 0, 0 ],\r\n\t\t'uv2': [ 0, 0 ]\r\n\t};\r\n\r\n\tthis.index0AttributeName = undefined;\r\n\r\n\tthis.setValues( parameters );\r\n\r\n};\r\n\r\nTHREE.ShaderMaterial.prototype = Object.create( THREE.Material.prototype );\r\nTHREE.ShaderMaterial.prototype.constructor = THREE.ShaderMaterial;\r\n\r\nTHREE.ShaderMaterial.prototype.clone = function () {\r\n\r\n\tvar material = new THREE.ShaderMaterial();\r\n\r\n\tTHREE.Material.prototype.clone.call( this, material );\r\n\r\n\tmaterial.fragmentShader = this.fragmentShader;\r\n\tmaterial.vertexShader = this.vertexShader;\r\n\r\n\tmaterial.uniforms = THREE.UniformsUtils.clone( this.uniforms );\r\n\r\n\tmaterial.attributes = this.attributes;\r\n\tmaterial.defines = this.defines;\r\n\r\n\tmaterial.shading = this.shading;\r\n\r\n\tmaterial.wireframe = this.wireframe;\r\n\tmaterial.wireframeLinewidth = this.wireframeLinewidth;\r\n\r\n\tmaterial.fog = this.fog;\r\n\r\n\tmaterial.lights = this.lights;\r\n\r\n\tmaterial.vertexColors = this.vertexColors;\r\n\r\n\tmaterial.skinning = this.skinning;\r\n\r\n\tmaterial.morphTargets = this.morphTargets;\r\n\tmaterial.morphNormals = this.morphNormals;\r\n\r\n\treturn material;\r\n\r\n};\r\n\r\n// File:src/materials/RawShaderMaterial.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n */\r\n\r\nTHREE.RawShaderMaterial = function ( parameters ) {\r\n\r\n\tTHREE.ShaderMaterial.call( this, parameters );\r\n\r\n\tthis.type = 'RawShaderMaterial';\r\n\r\n};\r\n\r\nTHREE.RawShaderMaterial.prototype = Object.create( THREE.ShaderMaterial.prototype );\r\nTHREE.RawShaderMaterial.prototype.constructor = THREE.RawShaderMaterial;\r\n\r\nTHREE.RawShaderMaterial.prototype.clone = function () {\r\n\r\n\tvar material = new THREE.RawShaderMaterial();\r\n\r\n\tTHREE.ShaderMaterial.prototype.clone.call( this, material );\r\n\r\n\treturn material;\r\n\r\n};\r\n\r\n// File:src/materials/SpriteMaterial.js\r\n\r\n/**\r\n * @author alteredq / http://alteredqualia.com/\r\n *\r\n * parameters = {\r\n * color: ,\r\n * opacity: ,\r\n * map: new THREE.Texture( ),\r\n *\r\n * blending: THREE.NormalBlending,\r\n * depthTest: ,\r\n * depthWrite: ,\r\n *\r\n *\tuvOffset: new THREE.Vector2(),\r\n *\tuvScale: new THREE.Vector2(),\r\n *\r\n * fog: \r\n * }\r\n */\r\n\r\nTHREE.SpriteMaterial = function ( parameters ) {\r\n\r\n\tTHREE.Material.call( this );\r\n\r\n\tthis.type = 'SpriteMaterial';\r\n\r\n\tthis.color = new THREE.Color( 0xffffff );\r\n\tthis.map = null;\r\n\r\n\tthis.rotation = 0;\r\n\r\n\tthis.fog = false;\r\n\r\n\t// set parameters\r\n\r\n\tthis.setValues( parameters );\r\n\r\n};\r\n\r\nTHREE.SpriteMaterial.prototype = Object.create( THREE.Material.prototype );\r\nTHREE.SpriteMaterial.prototype.constructor = THREE.SpriteMaterial;\r\n\r\nTHREE.SpriteMaterial.prototype.clone = function () {\r\n\r\n\tvar material = new THREE.SpriteMaterial();\r\n\r\n\tTHREE.Material.prototype.clone.call( this, material );\r\n\r\n\tmaterial.color.copy( this.color );\r\n\tmaterial.map = this.map;\r\n\r\n\tmaterial.rotation = this.rotation;\r\n\r\n\tmaterial.fog = this.fog;\r\n\r\n\treturn material;\r\n\r\n};\r\n\r\n// File:src/textures/Texture.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n * @author alteredq / http://alteredqualia.com/\r\n * @author szimek / https://github.com/szimek/\r\n */\r\n\r\nTHREE.Texture = function ( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {\r\n\r\n\tObject.defineProperty( this, 'id', { value: THREE.TextureIdCount ++ } );\r\n\r\n\tthis.uuid = THREE.Math.generateUUID();\r\n\r\n\tthis.name = '';\r\n\tthis.sourceFile = '';\r\n\r\n\tthis.image = image !== undefined ? image : THREE.Texture.DEFAULT_IMAGE;\r\n\tthis.mipmaps = [];\r\n\r\n\tthis.mapping = mapping !== undefined ? mapping : THREE.Texture.DEFAULT_MAPPING;\r\n\r\n\tthis.wrapS = wrapS !== undefined ? wrapS : THREE.ClampToEdgeWrapping;\r\n\tthis.wrapT = wrapT !== undefined ? wrapT : THREE.ClampToEdgeWrapping;\r\n\r\n\tthis.magFilter = magFilter !== undefined ? magFilter : THREE.LinearFilter;\r\n\tthis.minFilter = minFilter !== undefined ? minFilter : THREE.LinearMipMapLinearFilter;\r\n\r\n\tthis.anisotropy = anisotropy !== undefined ? anisotropy : 1;\r\n\r\n\tthis.format = format !== undefined ? format : THREE.RGBAFormat;\r\n\tthis.type = type !== undefined ? type : THREE.UnsignedByteType;\r\n\r\n\tthis.offset = new THREE.Vector2( 0, 0 );\r\n\tthis.repeat = new THREE.Vector2( 1, 1 );\r\n\r\n\tthis.generateMipmaps = true;\r\n\tthis.premultiplyAlpha = false;\r\n\tthis.flipY = true;\r\n\tthis.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml)\r\n\r\n\tthis._needsUpdate = false;\r\n\tthis.onUpdate = null;\r\n\r\n};\r\n\r\nTHREE.Texture.DEFAULT_IMAGE = undefined;\r\nTHREE.Texture.DEFAULT_MAPPING = THREE.UVMapping;\r\n\r\nTHREE.Texture.prototype = {\r\n\r\n\tconstructor: THREE.Texture,\r\n\r\n\tget needsUpdate () {\r\n\r\n\t\treturn this._needsUpdate;\r\n\r\n\t},\r\n\r\n\tset needsUpdate ( value ) {\r\n\r\n\t\tif ( value === true ) this.update();\r\n\r\n\t\tthis._needsUpdate = value;\r\n\r\n\t},\r\n\r\n\tclone: function ( texture ) {\r\n\r\n\t\tif ( texture === undefined ) texture = new THREE.Texture();\r\n\r\n\t\ttexture.image = this.image;\r\n\t\ttexture.mipmaps = this.mipmaps.slice( 0 );\r\n\r\n\t\ttexture.mapping = this.mapping;\r\n\r\n\t\ttexture.wrapS = this.wrapS;\r\n\t\ttexture.wrapT = this.wrapT;\r\n\r\n\t\ttexture.magFilter = this.magFilter;\r\n\t\ttexture.minFilter = this.minFilter;\r\n\r\n\t\ttexture.anisotropy = this.anisotropy;\r\n\r\n\t\ttexture.format = this.format;\r\n\t\ttexture.type = this.type;\r\n\r\n\t\ttexture.offset.copy( this.offset );\r\n\t\ttexture.repeat.copy( this.repeat );\r\n\r\n\t\ttexture.generateMipmaps = this.generateMipmaps;\r\n\t\ttexture.premultiplyAlpha = this.premultiplyAlpha;\r\n\t\ttexture.flipY = this.flipY;\r\n\t\ttexture.unpackAlignment = this.unpackAlignment;\r\n\r\n\t\treturn texture;\r\n\r\n\t},\r\n\r\n\tupdate: function () {\r\n\r\n\t\tthis.dispatchEvent( { type: 'update' } );\r\n\r\n\t},\r\n\r\n\tdispose: function () {\r\n\r\n\t\tthis.dispatchEvent( { type: 'dispose' } );\r\n\r\n\t}\r\n\r\n};\r\n\r\nTHREE.EventDispatcher.prototype.apply( THREE.Texture.prototype );\r\n\r\nTHREE.TextureIdCount = 0;\r\n\r\n// File:src/textures/CubeTexture.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n */\r\n\r\nTHREE.CubeTexture = function ( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {\r\n\r\n\tmapping = mapping !== undefined ? mapping : THREE.CubeReflectionMapping;\r\n\t\r\n\tTHREE.Texture.call( this, images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );\r\n\r\n\tthis.images = images;\r\n\r\n};\r\n\r\nTHREE.CubeTexture.prototype = Object.create( THREE.Texture.prototype );\r\nTHREE.CubeTexture.prototype.constructor = THREE.CubeTexture;\r\n\r\nTHREE.CubeTexture.clone = function ( texture ) {\r\n\r\n\tif ( texture === undefined ) texture = new THREE.CubeTexture();\r\n\r\n\tTHREE.Texture.prototype.clone.call( this, texture );\r\n\r\n\ttexture.images = this.images;\r\n\r\n\treturn texture;\r\n\r\n};\r\n\r\n// File:src/textures/CompressedTexture.js\r\n\r\n/**\r\n * @author alteredq / http://alteredqualia.com/\r\n */\r\n\r\nTHREE.CompressedTexture = function ( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy ) {\r\n\r\n\tTHREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );\r\n\r\n\tthis.image = { width: width, height: height };\r\n\tthis.mipmaps = mipmaps;\r\n\r\n\t// no flipping for cube textures\r\n\t// (also flipping doesn't work for compressed textures )\r\n\r\n\tthis.flipY = false;\r\n\r\n\t// can't generate mipmaps for compressed textures\r\n\t// mips must be embedded in DDS files\r\n\r\n\tthis.generateMipmaps = false;\r\n\r\n};\r\n\r\nTHREE.CompressedTexture.prototype = Object.create( THREE.Texture.prototype );\r\nTHREE.CompressedTexture.prototype.constructor = THREE.CompressedTexture;\r\n\r\nTHREE.CompressedTexture.prototype.clone = function () {\r\n\r\n\tvar texture = new THREE.CompressedTexture();\r\n\r\n\tTHREE.Texture.prototype.clone.call( this, texture );\r\n\r\n\treturn texture;\r\n\r\n};\r\n\r\n// File:src/textures/DataTexture.js\r\n\r\n/**\r\n * @author alteredq / http://alteredqualia.com/\r\n */\r\n\r\nTHREE.DataTexture = function ( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy ) {\r\n\r\n\tTHREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );\r\n\r\n\tthis.image = { data: data, width: width, height: height };\r\n\r\n};\r\n\r\nTHREE.DataTexture.prototype = Object.create( THREE.Texture.prototype );\r\nTHREE.DataTexture.prototype.constructor = THREE.DataTexture;\r\n\r\nTHREE.DataTexture.prototype.clone = function () {\r\n\r\n\tvar texture = new THREE.DataTexture();\r\n\r\n\tTHREE.Texture.prototype.clone.call( this, texture );\r\n\r\n\treturn texture;\r\n\r\n};\r\n\r\n// File:src/textures/VideoTexture.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n */\r\n\r\nTHREE.VideoTexture = function ( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {\r\n\r\n\tTHREE.Texture.call( this, video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );\r\n\r\n\tthis.generateMipmaps = false;\r\n\r\n\tvar scope = this;\r\n\r\n\tvar update = function () {\r\n\r\n\t\trequestAnimationFrame( update );\r\n\r\n\t\tif ( video.readyState === video.HAVE_ENOUGH_DATA ) {\r\n\r\n\t\t\tscope.needsUpdate = true;\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n\tupdate();\r\n\r\n};\r\n\r\nTHREE.VideoTexture.prototype = Object.create( THREE.Texture.prototype );\r\nTHREE.VideoTexture.prototype.constructor = THREE.VideoTexture;\r\n\r\n// File:src/objects/Group.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n */\r\n\r\nTHREE.Group = function () {\r\n\r\n\tTHREE.Object3D.call( this );\r\n\r\n\tthis.type = 'Group';\r\n\r\n};\r\n\r\nTHREE.Group.prototype = Object.create( THREE.Object3D.prototype );\r\nTHREE.Group.prototype.constructor = THREE.Group;\r\n\r\n// File:src/objects/PointCloud.js\r\n\r\n/**\r\n * @author alteredq / http://alteredqualia.com/\r\n */\r\n\r\nTHREE.PointCloud = function ( geometry, material ) {\r\n\r\n\tTHREE.Object3D.call( this );\r\n\r\n\tthis.type = 'PointCloud';\r\n\r\n\tthis.geometry = geometry !== undefined ? geometry : new THREE.Geometry();\r\n\tthis.material = material !== undefined ? material : new THREE.PointCloudMaterial( { color: Math.random() * 0xffffff } );\r\n\r\n};\r\n\r\nTHREE.PointCloud.prototype = Object.create( THREE.Object3D.prototype );\r\nTHREE.PointCloud.prototype.constructor = THREE.PointCloud;\r\n\r\nTHREE.PointCloud.prototype.raycast = ( function () {\r\n\r\n\tvar inverseMatrix = new THREE.Matrix4();\r\n\tvar ray = new THREE.Ray();\r\n\r\n\treturn function ( raycaster, intersects ) {\r\n\r\n\t\tvar object = this;\r\n\t\tvar geometry = object.geometry;\r\n\t\tvar threshold = raycaster.params.PointCloud.threshold;\r\n\r\n\t\tinverseMatrix.getInverse( this.matrixWorld );\r\n\t\tray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );\r\n\r\n\t\tif ( geometry.boundingBox !== null ) {\r\n\r\n\t\t\tif ( ray.isIntersectionBox( geometry.boundingBox ) === false ) {\r\n\r\n\t\t\t\treturn;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tvar localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );\r\n\t\tvar position = new THREE.Vector3();\r\n\r\n\t\tvar testPoint = function ( point, index ) {\r\n\r\n\t\t\tvar rayPointDistance = ray.distanceToPoint( point );\r\n\r\n\t\t\tif ( rayPointDistance < localThreshold ) {\r\n\r\n\t\t\t\tvar intersectPoint = ray.closestPointToPoint( point );\r\n\t\t\t\tintersectPoint.applyMatrix4( object.matrixWorld );\r\n\r\n\t\t\t\tvar distance = raycaster.ray.origin.distanceTo( intersectPoint );\r\n\r\n\t\t\t\tintersects.push( {\r\n\r\n\t\t\t\t\tdistance: distance,\r\n\t\t\t\t\tdistanceToRay: rayPointDistance,\r\n\t\t\t\t\tpoint: intersectPoint.clone(),\r\n\t\t\t\t\tindex: index,\r\n\t\t\t\t\tface: null,\r\n\t\t\t\t\tobject: object\r\n\r\n\t\t\t\t} );\r\n\r\n\t\t\t}\r\n\r\n\t\t};\r\n\r\n\t\tif ( geometry instanceof THREE.BufferGeometry ) {\r\n\r\n\t\t\tvar attributes = geometry.attributes;\r\n\t\t\tvar positions = attributes.position.array;\r\n\r\n\t\t\tif ( attributes.index !== undefined ) {\r\n\r\n\t\t\t\tvar indices = attributes.index.array;\r\n\t\t\t\tvar offsets = geometry.offsets;\r\n\r\n\t\t\t\tif ( offsets.length === 0 ) {\r\n\r\n\t\t\t\t\tvar offset = {\r\n\t\t\t\t\t\tstart: 0,\r\n\t\t\t\t\t\tcount: indices.length,\r\n\t\t\t\t\t\tindex: 0\r\n\t\t\t\t\t};\r\n\r\n\t\t\t\t\toffsets = [ offset ];\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tfor ( var oi = 0, ol = offsets.length; oi < ol; ++ oi ) {\r\n\r\n\t\t\t\t\tvar start = offsets[ oi ].start;\r\n\t\t\t\t\tvar count = offsets[ oi ].count;\r\n\t\t\t\t\tvar index = offsets[ oi ].index;\r\n\r\n\t\t\t\t\tfor ( var i = start, il = start + count; i < il; i ++ ) {\r\n\r\n\t\t\t\t\t\tvar a = index + indices[ i ];\r\n\r\n\t\t\t\t\t\tposition.fromArray( positions, a * 3 );\r\n\r\n\t\t\t\t\t\ttestPoint( position, a );\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tvar pointCount = positions.length / 3;\r\n\r\n\t\t\t\tfor ( var i = 0; i < pointCount; i ++ ) {\r\n\r\n\t\t\t\t\tposition.set(\r\n\t\t\t\t\t\tpositions[ 3 * i ],\r\n\t\t\t\t\t\tpositions[ 3 * i + 1 ],\r\n\t\t\t\t\t\tpositions[ 3 * i + 2 ]\r\n\t\t\t\t\t);\r\n\r\n\t\t\t\t\ttestPoint( position, i );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t} else {\r\n\r\n\t\t\tvar vertices = this.geometry.vertices;\r\n\r\n\t\t\tfor ( var i = 0; i < vertices.length; i ++ ) {\r\n\r\n\t\t\t\ttestPoint( vertices[ i ], i );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n}() );\r\n\r\nTHREE.PointCloud.prototype.clone = function ( object ) {\r\n\r\n\tif ( object === undefined ) object = new THREE.PointCloud( this.geometry, this.material );\r\n\r\n\tTHREE.Object3D.prototype.clone.call( this, object );\r\n\r\n\treturn object;\r\n\r\n};\r\n\r\n// Backwards compatibility\r\n\r\nTHREE.ParticleSystem = function ( geometry, material ) {\r\n\r\n\tTHREE.warn( 'THREE.ParticleSystem has been renamed to THREE.PointCloud.' );\r\n\treturn new THREE.PointCloud( geometry, material );\r\n\r\n};\r\n\r\n// File:src/objects/Line.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n */\r\n\r\nTHREE.Line = function ( geometry, material, mode ) {\r\n\r\n\tTHREE.Object3D.call( this );\r\n\r\n\tthis.type = 'Line';\r\n\r\n\tthis.geometry = geometry !== undefined ? geometry : new THREE.Geometry();\r\n\tthis.material = material !== undefined ? material : new THREE.LineBasicMaterial( { color: Math.random() * 0xffffff } );\r\n\r\n\tthis.mode = mode !== undefined ? mode : THREE.LineStrip;\r\n\r\n};\r\n\r\nTHREE.LineStrip = 0;\r\nTHREE.LinePieces = 1;\r\n\r\nTHREE.Line.prototype = Object.create( THREE.Object3D.prototype );\r\nTHREE.Line.prototype.constructor = THREE.Line;\r\n\r\nTHREE.Line.prototype.raycast = ( function () {\r\n\r\n\tvar inverseMatrix = new THREE.Matrix4();\r\n\tvar ray = new THREE.Ray();\r\n\tvar sphere = new THREE.Sphere();\r\n\r\n\treturn function ( raycaster, intersects ) {\r\n\r\n\t\tvar precision = raycaster.linePrecision;\r\n\t\tvar precisionSq = precision * precision;\r\n\r\n\t\tvar geometry = this.geometry;\r\n\r\n\t\tif ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();\r\n\r\n\t\t// Checking boundingSphere distance to ray\r\n\r\n\t\tsphere.copy( geometry.boundingSphere );\r\n\t\tsphere.applyMatrix4( this.matrixWorld );\r\n\r\n\t\tif ( raycaster.ray.isIntersectionSphere( sphere ) === false ) {\r\n\r\n\t\t\treturn;\r\n\r\n\t\t}\r\n\r\n\t\tinverseMatrix.getInverse( this.matrixWorld );\r\n\t\tray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );\r\n\r\n\t\tvar vStart = new THREE.Vector3();\r\n\t\tvar vEnd = new THREE.Vector3();\r\n\t\tvar interSegment = new THREE.Vector3();\r\n\t\tvar interRay = new THREE.Vector3();\r\n\t\tvar step = this.mode === THREE.LineStrip ? 1 : 2;\r\n\r\n\t\tif ( geometry instanceof THREE.BufferGeometry ) {\r\n\r\n\t\t\tvar attributes = geometry.attributes;\r\n\r\n\t\t\tif ( attributes.index !== undefined ) {\r\n\r\n\t\t\t\tvar indices = attributes.index.array;\r\n\t\t\t\tvar positions = attributes.position.array;\r\n\t\t\t\tvar offsets = geometry.offsets;\r\n\r\n\t\t\t\tif ( offsets.length === 0 ) {\r\n\r\n\t\t\t\t\toffsets = [ { start: 0, count: indices.length, index: 0 } ];\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tfor ( var oi = 0; oi < offsets.length; oi ++) {\r\n\r\n\t\t\t\t\tvar start = offsets[ oi ].start;\r\n\t\t\t\t\tvar count = offsets[ oi ].count;\r\n\t\t\t\t\tvar index = offsets[ oi ].index;\r\n\r\n\t\t\t\t\tfor ( var i = start; i < start + count - 1; i += step ) {\r\n\r\n\t\t\t\t\t\tvar a = index + indices[ i ];\r\n\t\t\t\t\t\tvar b = index + indices[ i + 1 ];\r\n\r\n\t\t\t\t\t\tvStart.fromArray( positions, a * 3 );\r\n\t\t\t\t\t\tvEnd.fromArray( positions, b * 3 );\r\n\r\n\t\t\t\t\t\tvar distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment );\r\n\r\n\t\t\t\t\t\tif ( distSq > precisionSq ) continue;\r\n\r\n\t\t\t\t\t\tvar distance = ray.origin.distanceTo( interRay );\r\n\r\n\t\t\t\t\t\tif ( distance < raycaster.near || distance > raycaster.far ) continue;\r\n\r\n\t\t\t\t\t\tintersects.push( {\r\n\r\n\t\t\t\t\t\t\tdistance: distance,\r\n\t\t\t\t\t\t\t// What do we want? intersection point on the ray or on the segment??\r\n\t\t\t\t\t\t\t// point: raycaster.ray.at( distance ),\r\n\t\t\t\t\t\t\tpoint: interSegment.clone().applyMatrix4( this.matrixWorld ),\r\n\t\t\t\t\t\t\tindex: i,\r\n\t\t\t\t\t\t\toffsetIndex: oi,\r\n\t\t\t\t\t\t\tface: null,\r\n\t\t\t\t\t\t\tfaceIndex: null,\r\n\t\t\t\t\t\t\tobject: this\r\n\r\n\t\t\t\t\t\t} );\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tvar positions = attributes.position.array;\r\n\r\n\t\t\t\tfor ( var i = 0; i < positions.length / 3 - 1; i += step ) {\r\n\r\n\t\t\t\t\tvStart.fromArray( positions, 3 * i );\r\n\t\t\t\t\tvEnd.fromArray( positions, 3 * i + 3 );\r\n\r\n\t\t\t\t\tvar distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment );\r\n\r\n\t\t\t\t\tif ( distSq > precisionSq ) continue;\r\n\r\n\t\t\t\t\tvar distance = ray.origin.distanceTo( interRay );\r\n\r\n\t\t\t\t\tif ( distance < raycaster.near || distance > raycaster.far ) continue;\r\n\r\n\t\t\t\t\tintersects.push( {\r\n\r\n\t\t\t\t\t\tdistance: distance,\r\n\t\t\t\t\t\t// What do we want? intersection point on the ray or on the segment??\r\n\t\t\t\t\t\t// point: raycaster.ray.at( distance ),\r\n\t\t\t\t\t\tpoint: interSegment.clone().applyMatrix4( this.matrixWorld ),\r\n\t\t\t\t\t\tindex: i,\r\n\t\t\t\t\t\tface: null,\r\n\t\t\t\t\t\tfaceIndex: null,\r\n\t\t\t\t\t\tobject: this\r\n\r\n\t\t\t\t\t} );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t} else if ( geometry instanceof THREE.Geometry ) {\r\n\r\n\t\t\tvar vertices = geometry.vertices;\r\n\t\t\tvar nbVertices = vertices.length;\r\n\r\n\t\t\tfor ( var i = 0; i < nbVertices - 1; i += step ) {\r\n\r\n\t\t\t\tvar distSq = ray.distanceSqToSegment( vertices[ i ], vertices[ i + 1 ], interRay, interSegment );\r\n\r\n\t\t\t\tif ( distSq > precisionSq ) continue;\r\n\r\n\t\t\t\tvar distance = ray.origin.distanceTo( interRay );\r\n\r\n\t\t\t\tif ( distance < raycaster.near || distance > raycaster.far ) continue;\r\n\r\n\t\t\t\tintersects.push( {\r\n\r\n\t\t\t\t\tdistance: distance,\r\n\t\t\t\t\t// What do we want? intersection point on the ray or on the segment??\r\n\t\t\t\t\t// point: raycaster.ray.at( distance ),\r\n\t\t\t\t\tpoint: interSegment.clone().applyMatrix4( this.matrixWorld ),\r\n\t\t\t\t\tindex: i,\r\n\t\t\t\t\tface: null,\r\n\t\t\t\t\tfaceIndex: null,\r\n\t\t\t\t\tobject: this\r\n\r\n\t\t\t\t} );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n}() );\r\n\r\nTHREE.Line.prototype.clone = function ( object ) {\r\n\r\n\tif ( object === undefined ) object = new THREE.Line( this.geometry, this.material, this.mode );\r\n\r\n\tTHREE.Object3D.prototype.clone.call( this, object );\r\n\r\n\treturn object;\r\n\r\n};\r\n\r\n// File:src/objects/Mesh.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n * @author alteredq / http://alteredqualia.com/\r\n * @author mikael emtinger / http://gomo.se/\r\n * @author jonobr1 / http://jonobr1.com/\r\n */\r\n\r\nTHREE.Mesh = function ( geometry, material ) {\r\n\r\n\tTHREE.Object3D.call( this );\r\n\r\n\tthis.type = 'Mesh';\r\n\t\r\n\tthis.geometry = geometry !== undefined ? geometry : new THREE.Geometry();\r\n\tthis.material = material !== undefined ? material : new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff } );\r\n\r\n\tthis.updateMorphTargets();\r\n\r\n};\r\n\r\nTHREE.Mesh.prototype = Object.create( THREE.Object3D.prototype );\r\nTHREE.Mesh.prototype.constructor = THREE.Mesh;\r\n\r\nTHREE.Mesh.prototype.updateMorphTargets = function () {\r\n\r\n\tif ( this.geometry.morphTargets !== undefined && this.geometry.morphTargets.length > 0 ) {\r\n\r\n\t\tthis.morphTargetBase = - 1;\r\n\t\tthis.morphTargetForcedOrder = [];\r\n\t\tthis.morphTargetInfluences = [];\r\n\t\tthis.morphTargetDictionary = {};\r\n\r\n\t\tfor ( var m = 0, ml = this.geometry.morphTargets.length; m < ml; m ++ ) {\r\n\r\n\t\t\tthis.morphTargetInfluences.push( 0 );\r\n\t\t\tthis.morphTargetDictionary[ this.geometry.morphTargets[ m ].name ] = m;\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n};\r\n\r\nTHREE.Mesh.prototype.getMorphTargetIndexByName = function ( name ) {\r\n\r\n\tif ( this.morphTargetDictionary[ name ] !== undefined ) {\r\n\r\n\t\treturn this.morphTargetDictionary[ name ];\r\n\r\n\t}\r\n\r\n\tTHREE.warn( 'THREE.Mesh.getMorphTargetIndexByName: morph target ' + name + ' does not exist. Returning 0.' );\r\n\r\n\treturn 0;\r\n\r\n};\r\n\r\n\r\nTHREE.Mesh.prototype.raycast = ( function () {\r\n\r\n\tvar inverseMatrix = new THREE.Matrix4();\r\n\tvar ray = new THREE.Ray();\r\n\tvar sphere = new THREE.Sphere();\r\n\r\n\tvar vA = new THREE.Vector3();\r\n\tvar vB = new THREE.Vector3();\r\n\tvar vC = new THREE.Vector3();\r\n\r\n\treturn function ( raycaster, intersects ) {\r\n\r\n\t\tvar geometry = this.geometry;\r\n\r\n\t\t// Checking boundingSphere distance to ray\r\n\r\n\t\tif ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();\r\n\r\n\t\tsphere.copy( geometry.boundingSphere );\r\n\t\tsphere.applyMatrix4( this.matrixWorld );\r\n\r\n\t\tif ( raycaster.ray.isIntersectionSphere( sphere ) === false ) {\r\n\r\n\t\t\treturn;\r\n\r\n\t\t}\r\n\r\n\t\t// Check boundingBox before continuing\r\n\r\n\t\tinverseMatrix.getInverse( this.matrixWorld );\r\n\t\tray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );\r\n\r\n\t\tif ( geometry.boundingBox !== null ) {\r\n\r\n\t\t\tif ( ray.isIntersectionBox( geometry.boundingBox ) === false ) {\r\n\r\n\t\t\t\treturn;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tif ( geometry instanceof THREE.BufferGeometry ) {\r\n\r\n\t\t\tvar material = this.material;\r\n\r\n\t\t\tif ( material === undefined ) return;\r\n\r\n\t\t\tvar attributes = geometry.attributes;\r\n\r\n\t\t\tvar a, b, c;\r\n\t\t\tvar precision = raycaster.precision;\r\n\r\n\t\t\tif ( attributes.index !== undefined ) {\r\n\r\n\t\t\t\tvar indices = attributes.index.array;\r\n\t\t\t\tvar positions = attributes.position.array;\r\n\t\t\t\tvar offsets = geometry.offsets;\r\n\r\n\t\t\t\tif ( offsets.length === 0 ) {\r\n\r\n\t\t\t\t\toffsets = [ { start: 0, count: indices.length, index: 0 } ];\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tfor ( var oi = 0, ol = offsets.length; oi < ol; ++ oi ) {\r\n\r\n\t\t\t\t\tvar start = offsets[ oi ].start;\r\n\t\t\t\t\tvar count = offsets[ oi ].count;\r\n\t\t\t\t\tvar index = offsets[ oi ].index;\r\n\r\n\t\t\t\t\tfor ( var i = start, il = start + count; i < il; i += 3 ) {\r\n\r\n\t\t\t\t\t\ta = index + indices[ i ];\r\n\t\t\t\t\t\tb = index + indices[ i + 1 ];\r\n\t\t\t\t\t\tc = index + indices[ i + 2 ];\r\n\r\n\t\t\t\t\t\tvA.fromArray( positions, a * 3 );\r\n\t\t\t\t\t\tvB.fromArray( positions, b * 3 );\r\n\t\t\t\t\t\tvC.fromArray( positions, c * 3 );\r\n\r\n\t\t\t\t\t\tif ( material.side === THREE.BackSide ) {\r\n\r\n\t\t\t\t\t\t\tvar intersectionPoint = ray.intersectTriangle( vC, vB, vA, true );\r\n\r\n\t\t\t\t\t\t} else {\r\n\r\n\t\t\t\t\t\t\tvar intersectionPoint = ray.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide );\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tif ( intersectionPoint === null ) continue;\r\n\r\n\t\t\t\t\t\tintersectionPoint.applyMatrix4( this.matrixWorld );\r\n\r\n\t\t\t\t\t\tvar distance = raycaster.ray.origin.distanceTo( intersectionPoint );\r\n\r\n\t\t\t\t\t\tif ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue;\r\n\r\n\t\t\t\t\t\tintersects.push( {\r\n\r\n\t\t\t\t\t\t\tdistance: distance,\r\n\t\t\t\t\t\t\tpoint: intersectionPoint,\r\n\t\t\t\t\t\t\tface: new THREE.Face3( a, b, c, THREE.Triangle.normal( vA, vB, vC ) ),\r\n\t\t\t\t\t\t\tfaceIndex: null,\r\n\t\t\t\t\t\t\tobject: this\r\n\r\n\t\t\t\t\t\t} );\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tvar positions = attributes.position.array;\r\n\r\n\t\t\t\tfor ( var i = 0, j = 0, il = positions.length; i < il; i += 3, j += 9 ) {\r\n\r\n\t\t\t\t\ta = i;\r\n\t\t\t\t\tb = i + 1;\r\n\t\t\t\t\tc = i + 2;\r\n\r\n\t\t\t\t\tvA.fromArray( positions, j );\r\n\t\t\t\t\tvB.fromArray( positions, j + 3 );\r\n\t\t\t\t\tvC.fromArray( positions, j + 6 );\r\n\r\n\t\t\t\t\tif ( material.side === THREE.BackSide ) {\r\n\r\n\t\t\t\t\t\tvar intersectionPoint = ray.intersectTriangle( vC, vB, vA, true );\r\n\r\n\t\t\t\t\t} else {\r\n\r\n\t\t\t\t\t\tvar intersectionPoint = ray.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide );\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif ( intersectionPoint === null ) continue;\r\n\r\n\t\t\t\t\tintersectionPoint.applyMatrix4( this.matrixWorld );\r\n\r\n\t\t\t\t\tvar distance = raycaster.ray.origin.distanceTo( intersectionPoint );\r\n\r\n\t\t\t\t\tif ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue;\r\n\r\n\t\t\t\t\tintersects.push( {\r\n\r\n\t\t\t\t\t\tdistance: distance,\r\n\t\t\t\t\t\tpoint: intersectionPoint,\r\n\t\t\t\t\t\tface: new THREE.Face3( a, b, c, THREE.Triangle.normal( vA, vB, vC ) ),\r\n\t\t\t\t\t\tfaceIndex: null,\r\n\t\t\t\t\t\tobject: this\r\n\r\n\t\t\t\t\t} );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t} else if ( geometry instanceof THREE.Geometry ) {\r\n\r\n\t\t\tvar isFaceMaterial = this.material instanceof THREE.MeshFaceMaterial;\r\n\t\t\tvar objectMaterials = isFaceMaterial === true ? this.material.materials : null;\r\n\r\n\t\t\tvar a, b, c;\r\n\t\t\tvar precision = raycaster.precision;\r\n\r\n\t\t\tvar vertices = geometry.vertices;\r\n\r\n\t\t\tfor ( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) {\r\n\r\n\t\t\t\tvar face = geometry.faces[ f ];\r\n\r\n\t\t\t\tvar material = isFaceMaterial === true ? objectMaterials[ face.materialIndex ] : this.material;\r\n\r\n\t\t\t\tif ( material === undefined ) continue;\r\n\r\n\t\t\t\ta = vertices[ face.a ];\r\n\t\t\t\tb = vertices[ face.b ];\r\n\t\t\t\tc = vertices[ face.c ];\r\n\r\n\t\t\t\tif ( material.morphTargets === true ) {\r\n\r\n\t\t\t\t\tvar morphTargets = geometry.morphTargets;\r\n\t\t\t\t\tvar morphInfluences = this.morphTargetInfluences;\r\n\r\n\t\t\t\t\tvA.set( 0, 0, 0 );\r\n\t\t\t\t\tvB.set( 0, 0, 0 );\r\n\t\t\t\t\tvC.set( 0, 0, 0 );\r\n\r\n\t\t\t\t\tfor ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) {\r\n\r\n\t\t\t\t\t\tvar influence = morphInfluences[ t ];\r\n\r\n\t\t\t\t\t\tif ( influence === 0 ) continue;\r\n\r\n\t\t\t\t\t\tvar targets = morphTargets[ t ].vertices;\r\n\r\n\t\t\t\t\t\tvA.x += ( targets[ face.a ].x - a.x ) * influence;\r\n\t\t\t\t\t\tvA.y += ( targets[ face.a ].y - a.y ) * influence;\r\n\t\t\t\t\t\tvA.z += ( targets[ face.a ].z - a.z ) * influence;\r\n\r\n\t\t\t\t\t\tvB.x += ( targets[ face.b ].x - b.x ) * influence;\r\n\t\t\t\t\t\tvB.y += ( targets[ face.b ].y - b.y ) * influence;\r\n\t\t\t\t\t\tvB.z += ( targets[ face.b ].z - b.z ) * influence;\r\n\r\n\t\t\t\t\t\tvC.x += ( targets[ face.c ].x - c.x ) * influence;\r\n\t\t\t\t\t\tvC.y += ( targets[ face.c ].y - c.y ) * influence;\r\n\t\t\t\t\t\tvC.z += ( targets[ face.c ].z - c.z ) * influence;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tvA.add( a );\r\n\t\t\t\t\tvB.add( b );\r\n\t\t\t\t\tvC.add( c );\r\n\r\n\t\t\t\t\ta = vA;\r\n\t\t\t\t\tb = vB;\r\n\t\t\t\t\tc = vC;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif ( material.side === THREE.BackSide ) {\r\n\r\n\t\t\t\t\tvar intersectionPoint = ray.intersectTriangle( c, b, a, true );\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\tvar intersectionPoint = ray.intersectTriangle( a, b, c, material.side !== THREE.DoubleSide );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif ( intersectionPoint === null ) continue;\r\n\r\n\t\t\t\tintersectionPoint.applyMatrix4( this.matrixWorld );\r\n\r\n\t\t\t\tvar distance = raycaster.ray.origin.distanceTo( intersectionPoint );\r\n\r\n\t\t\t\tif ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue;\r\n\r\n\t\t\t\tintersects.push( {\r\n\r\n\t\t\t\t\tdistance: distance,\r\n\t\t\t\t\tpoint: intersectionPoint,\r\n\t\t\t\t\tface: face,\r\n\t\t\t\t\tfaceIndex: f,\r\n\t\t\t\t\tobject: this\r\n\r\n\t\t\t\t} );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n}() );\r\n\r\nTHREE.Mesh.prototype.clone = function ( object, recursive ) {\r\n\r\n\tif ( object === undefined ) object = new THREE.Mesh( this.geometry, this.material );\r\n\r\n\tTHREE.Object3D.prototype.clone.call( this, object, recursive );\r\n\r\n\treturn object;\r\n\r\n};\r\n\r\n// File:src/objects/Bone.js\r\n\r\n/**\r\n * @author mikael emtinger / http://gomo.se/\r\n * @author alteredq / http://alteredqualia.com/\r\n * @author ikerr / http://verold.com\r\n */\r\n\r\nTHREE.Bone = function ( skin ) {\r\n\r\n\tTHREE.Object3D.call( this );\r\n\r\n\tthis.type = 'Bone';\r\n\r\n\tthis.skin = skin;\r\n\r\n};\r\n\r\nTHREE.Bone.prototype = Object.create( THREE.Object3D.prototype );\r\nTHREE.Bone.prototype.constructor = THREE.Bone;\r\n\r\n// File:src/objects/Skeleton.js\r\n\r\n/**\r\n * @author mikael emtinger / http://gomo.se/\r\n * @author alteredq / http://alteredqualia.com/\r\n * @author michael guerrero / http://realitymeltdown.com\r\n * @author ikerr / http://verold.com\r\n */\r\n\r\nTHREE.Skeleton = function ( bones, boneInverses, useVertexTexture ) {\r\n\r\n\tthis.useVertexTexture = useVertexTexture !== undefined ? useVertexTexture : true;\r\n\r\n\tthis.identityMatrix = new THREE.Matrix4();\r\n\r\n\t// copy the bone array\r\n\r\n\tbones = bones || [];\r\n\r\n\tthis.bones = bones.slice( 0 );\r\n\r\n\t// create a bone texture or an array of floats\r\n\r\n\tif ( this.useVertexTexture ) {\r\n\r\n\t\t// layout (1 matrix = 4 pixels)\r\n\t\t// RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)\r\n\t\t// with 8x8 pixel texture max 16 bones (8 * 8 / 4)\r\n\t\t// 16x16 pixel texture max 64 bones (16 * 16 / 4)\r\n\t\t// 32x32 pixel texture max 256 bones (32 * 32 / 4)\r\n\t\t// 64x64 pixel texture max 1024 bones (64 * 64 / 4)\r\n\r\n\t\tvar size;\r\n\r\n\t\tif ( this.bones.length > 256 )\r\n\t\t\tsize = 64;\r\n\t\telse if ( this.bones.length > 64 )\r\n\t\t\tsize = 32;\r\n\t\telse if ( this.bones.length > 16 )\r\n\t\t\tsize = 16;\r\n\t\telse\r\n\t\t\tsize = 8;\r\n\r\n\t\tthis.boneTextureWidth = size;\r\n\t\tthis.boneTextureHeight = size;\r\n\r\n\t\tthis.boneMatrices = new Float32Array( this.boneTextureWidth * this.boneTextureHeight * 4 ); // 4 floats per RGBA pixel\r\n\t\tthis.boneTexture = new THREE.DataTexture( this.boneMatrices, this.boneTextureWidth, this.boneTextureHeight, THREE.RGBAFormat, THREE.FloatType );\r\n\t\tthis.boneTexture.minFilter = THREE.NearestFilter;\r\n\t\tthis.boneTexture.magFilter = THREE.NearestFilter;\r\n\t\tthis.boneTexture.generateMipmaps = false;\r\n\t\tthis.boneTexture.flipY = false;\r\n\r\n\t} else {\r\n\r\n\t\tthis.boneMatrices = new Float32Array( 16 * this.bones.length );\r\n\r\n\t}\r\n\r\n\t// use the supplied bone inverses or calculate the inverses\r\n\r\n\tif ( boneInverses === undefined ) {\r\n\r\n\t\tthis.calculateInverses();\r\n\r\n\t} else {\r\n\r\n\t\tif ( this.bones.length === boneInverses.length ) {\r\n\r\n\t\t\tthis.boneInverses = boneInverses.slice( 0 );\r\n\r\n\t\t} else {\r\n\r\n\t\t\tTHREE.warn( 'THREE.Skeleton bonInverses is the wrong length.' );\r\n\r\n\t\t\tthis.boneInverses = [];\r\n\r\n\t\t\tfor ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {\r\n\r\n\t\t\t\tthis.boneInverses.push( new THREE.Matrix4() );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n};\r\n\r\nTHREE.Skeleton.prototype.calculateInverses = function () {\r\n\r\n\tthis.boneInverses = [];\r\n\r\n\tfor ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {\r\n\r\n\t\tvar inverse = new THREE.Matrix4();\r\n\r\n\t\tif ( this.bones[ b ] ) {\r\n\r\n\t\t\tinverse.getInverse( this.bones[ b ].matrixWorld );\r\n\r\n\t\t}\r\n\r\n\t\tthis.boneInverses.push( inverse );\r\n\r\n\t}\r\n\r\n};\r\n\r\nTHREE.Skeleton.prototype.pose = function () {\r\n\r\n\tvar bone;\r\n\r\n\t// recover the bind-time world matrices\r\n\r\n\tfor ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {\r\n\r\n\t\tbone = this.bones[ b ];\r\n\r\n\t\tif ( bone ) {\r\n\r\n\t\t\tbone.matrixWorld.getInverse( this.boneInverses[ b ] );\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t// compute the local matrices, positions, rotations and scales\r\n\r\n\tfor ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {\r\n\r\n\t\tbone = this.bones[ b ];\r\n\r\n\t\tif ( bone ) {\r\n\r\n\t\t\tif ( bone.parent ) {\r\n\r\n\t\t\t\tbone.matrix.getInverse( bone.parent.matrixWorld );\r\n\t\t\t\tbone.matrix.multiply( bone.matrixWorld );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tbone.matrix.copy( bone.matrixWorld );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tbone.matrix.decompose( bone.position, bone.quaternion, bone.scale );\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n};\r\n\r\nTHREE.Skeleton.prototype.update = ( function () {\r\n\r\n\tvar offsetMatrix = new THREE.Matrix4();\r\n\t\r\n\treturn function () {\r\n\r\n\t\t// flatten bone matrices to array\r\n\r\n\t\tfor ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {\r\n\r\n\t\t\t// compute the offset between the current and the original transform\r\n\r\n\t\t\tvar matrix = this.bones[ b ] ? this.bones[ b ].matrixWorld : this.identityMatrix;\r\n\r\n\t\t\toffsetMatrix.multiplyMatrices( matrix, this.boneInverses[ b ] );\r\n\t\t\toffsetMatrix.flattenToArrayOffset( this.boneMatrices, b * 16 );\r\n\r\n\t\t}\r\n\r\n\t\tif ( this.useVertexTexture ) {\r\n\r\n\t\t\tthis.boneTexture.needsUpdate = true;\r\n\r\n\t\t}\r\n\t\t\r\n\t};\r\n\r\n} )();\r\n\r\n\r\n// File:src/objects/SkinnedMesh.js\r\n\r\n/**\r\n * @author mikael emtinger / http://gomo.se/\r\n * @author alteredq / http://alteredqualia.com/\r\n * @author ikerr / http://verold.com\r\n */\r\n\r\nTHREE.SkinnedMesh = function ( geometry, material, useVertexTexture ) {\r\n\r\n\tTHREE.Mesh.call( this, geometry, material );\r\n\r\n\tthis.type = 'SkinnedMesh';\r\n\r\n\tthis.bindMode = \"attached\";\r\n\tthis.bindMatrix = new THREE.Matrix4();\r\n\tthis.bindMatrixInverse = new THREE.Matrix4();\r\n\r\n\t// init bones\r\n\r\n\t// TODO: remove bone creation as there is no reason (other than\r\n\t// convenience) for THREE.SkinnedMesh to do this.\r\n\r\n\tvar bones = [];\r\n\r\n\tif ( this.geometry && this.geometry.bones !== undefined ) {\r\n\r\n\t\tvar bone, gbone, p, q, s;\r\n\r\n\t\tfor ( var b = 0, bl = this.geometry.bones.length; b < bl; ++ b ) {\r\n\r\n\t\t\tgbone = this.geometry.bones[ b ];\r\n\r\n\t\t\tp = gbone.pos;\r\n\t\t\tq = gbone.rotq;\r\n\t\t\ts = gbone.scl;\r\n\r\n\t\t\tbone = new THREE.Bone( this );\r\n\t\t\tbones.push( bone );\r\n\r\n\t\t\tbone.name = gbone.name;\r\n\t\t\tbone.position.set( p[ 0 ], p[ 1 ], p[ 2 ] );\r\n\t\t\tbone.quaternion.set( q[ 0 ], q[ 1 ], q[ 2 ], q[ 3 ] );\r\n\r\n\t\t\tif ( s !== undefined ) {\r\n\r\n\t\t\t\tbone.scale.set( s[ 0 ], s[ 1 ], s[ 2 ] );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tbone.scale.set( 1, 1, 1 );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tfor ( var b = 0, bl = this.geometry.bones.length; b < bl; ++ b ) {\r\n\r\n\t\t\tgbone = this.geometry.bones[ b ];\r\n\r\n\t\t\tif ( gbone.parent !== - 1 ) {\r\n\r\n\t\t\t\tbones[ gbone.parent ].add( bones[ b ] );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tthis.add( bones[ b ] );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tthis.normalizeSkinWeights();\r\n\r\n\tthis.updateMatrixWorld( true );\r\n\tthis.bind( new THREE.Skeleton( bones, undefined, useVertexTexture ) );\r\n\r\n};\r\n\r\n\r\nTHREE.SkinnedMesh.prototype = Object.create( THREE.Mesh.prototype );\r\nTHREE.SkinnedMesh.prototype.constructor = THREE.SkinnedMesh;\r\n\r\nTHREE.SkinnedMesh.prototype.bind = function( skeleton, bindMatrix ) {\r\n\r\n\tthis.skeleton = skeleton;\r\n\r\n\tif ( bindMatrix === undefined ) {\r\n\r\n\t\tthis.updateMatrixWorld( true );\r\n\r\n\t\tbindMatrix = this.matrixWorld;\r\n\r\n\t}\r\n\r\n\tthis.bindMatrix.copy( bindMatrix );\r\n\tthis.bindMatrixInverse.getInverse( bindMatrix );\r\n\r\n};\r\n\r\nTHREE.SkinnedMesh.prototype.pose = function () {\r\n\r\n\tthis.skeleton.pose();\r\n\r\n};\r\n\r\nTHREE.SkinnedMesh.prototype.normalizeSkinWeights = function () {\r\n\r\n\tif ( this.geometry instanceof THREE.Geometry ) {\r\n\r\n\t\tfor ( var i = 0; i < this.geometry.skinIndices.length; i ++ ) {\r\n\r\n\t\t\tvar sw = this.geometry.skinWeights[ i ];\r\n\r\n\t\t\tvar scale = 1.0 / sw.lengthManhattan();\r\n\r\n\t\t\tif ( scale !== Infinity ) {\r\n\r\n\t\t\t\tsw.multiplyScalar( scale );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tsw.set( 1 ); // this will be normalized by the shader anyway\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t} else {\r\n\r\n\t\t// skinning weights assumed to be normalized for THREE.BufferGeometry\r\n\r\n\t}\r\n\r\n};\r\n\r\nTHREE.SkinnedMesh.prototype.updateMatrixWorld = function( force ) {\r\n\r\n\tTHREE.Mesh.prototype.updateMatrixWorld.call( this, true );\r\n\r\n\tif ( this.bindMode === \"attached\" ) {\r\n\r\n\t\tthis.bindMatrixInverse.getInverse( this.matrixWorld );\r\n\r\n\t} else if ( this.bindMode === \"detached\" ) {\r\n\r\n\t\tthis.bindMatrixInverse.getInverse( this.bindMatrix );\r\n\r\n\t} else {\r\n\r\n\t\tTHREE.warn( 'THREE.SkinnedMesh unreckognized bindMode: ' + this.bindMode );\r\n\r\n\t}\r\n\r\n};\r\n\r\nTHREE.SkinnedMesh.prototype.clone = function( object ) {\r\n\r\n\tif ( object === undefined ) {\r\n\r\n\t\tobject = new THREE.SkinnedMesh( this.geometry, this.material, this.useVertexTexture );\r\n\r\n\t}\r\n\r\n\tTHREE.Mesh.prototype.clone.call( this, object );\r\n\r\n\treturn object;\r\n\r\n};\r\n\r\n\r\n// File:src/objects/MorphAnimMesh.js\r\n\r\n/**\r\n * @author alteredq / http://alteredqualia.com/\r\n */\r\n\r\nTHREE.MorphAnimMesh = function ( geometry, material ) {\r\n\r\n\tTHREE.Mesh.call( this, geometry, material );\r\n\r\n\tthis.type = 'MorphAnimMesh';\r\n\r\n\t// API\r\n\r\n\tthis.duration = 1000; // milliseconds\r\n\tthis.mirroredLoop = false;\r\n\tthis.time = 0;\r\n\r\n\t// internals\r\n\r\n\tthis.lastKeyframe = 0;\r\n\tthis.currentKeyframe = 0;\r\n\r\n\tthis.direction = 1;\r\n\tthis.directionBackwards = false;\r\n\r\n\tthis.setFrameRange( 0, this.geometry.morphTargets.length - 1 );\r\n\r\n};\r\n\r\nTHREE.MorphAnimMesh.prototype = Object.create( THREE.Mesh.prototype );\r\nTHREE.MorphAnimMesh.prototype.constructor = THREE.MorphAnimMesh;\r\n\r\nTHREE.MorphAnimMesh.prototype.setFrameRange = function ( start, end ) {\r\n\r\n\tthis.startKeyframe = start;\r\n\tthis.endKeyframe = end;\r\n\r\n\tthis.length = this.endKeyframe - this.startKeyframe + 1;\r\n\r\n};\r\n\r\nTHREE.MorphAnimMesh.prototype.setDirectionForward = function () {\r\n\r\n\tthis.direction = 1;\r\n\tthis.directionBackwards = false;\r\n\r\n};\r\n\r\nTHREE.MorphAnimMesh.prototype.setDirectionBackward = function () {\r\n\r\n\tthis.direction = - 1;\r\n\tthis.directionBackwards = true;\r\n\r\n};\r\n\r\nTHREE.MorphAnimMesh.prototype.parseAnimations = function () {\r\n\r\n\tvar geometry = this.geometry;\r\n\r\n\tif ( ! geometry.animations ) geometry.animations = {};\r\n\r\n\tvar firstAnimation, animations = geometry.animations;\r\n\r\n\tvar pattern = /([a-z]+)_?(\\d+)/;\r\n\r\n\tfor ( var i = 0, il = geometry.morphTargets.length; i < il; i ++ ) {\r\n\r\n\t\tvar morph = geometry.morphTargets[ i ];\r\n\t\tvar parts = morph.name.match( pattern );\r\n\r\n\t\tif ( parts && parts.length > 1 ) {\r\n\r\n\t\t\tvar label = parts[ 1 ];\r\n\r\n\t\t\tif ( ! animations[ label ] ) animations[ label ] = { start: Infinity, end: - Infinity };\r\n\r\n\t\t\tvar animation = animations[ label ];\r\n\r\n\t\t\tif ( i < animation.start ) animation.start = i;\r\n\t\t\tif ( i > animation.end ) animation.end = i;\r\n\r\n\t\t\tif ( ! firstAnimation ) firstAnimation = label;\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tgeometry.firstAnimation = firstAnimation;\r\n\r\n};\r\n\r\nTHREE.MorphAnimMesh.prototype.setAnimationLabel = function ( label, start, end ) {\r\n\r\n\tif ( ! this.geometry.animations ) this.geometry.animations = {};\r\n\r\n\tthis.geometry.animations[ label ] = { start: start, end: end };\r\n\r\n};\r\n\r\nTHREE.MorphAnimMesh.prototype.playAnimation = function ( label, fps ) {\r\n\r\n\tvar animation = this.geometry.animations[ label ];\r\n\r\n\tif ( animation ) {\r\n\r\n\t\tthis.setFrameRange( animation.start, animation.end );\r\n\t\tthis.duration = 1000 * ( ( animation.end - animation.start ) / fps );\r\n\t\tthis.time = 0;\r\n\r\n\t} else {\r\n\r\n\t\tTHREE.warn( 'THREE.MorphAnimMesh: animation[' + label + '] undefined in .playAnimation()' );\r\n\r\n\t}\r\n\r\n};\r\n\r\nTHREE.MorphAnimMesh.prototype.updateAnimation = function ( delta ) {\r\n\r\n\tvar frameTime = this.duration / this.length;\r\n\r\n\tthis.time += this.direction * delta;\r\n\r\n\tif ( this.mirroredLoop ) {\r\n\r\n\t\tif ( this.time > this.duration || this.time < 0 ) {\r\n\r\n\t\t\tthis.direction *= - 1;\r\n\r\n\t\t\tif ( this.time > this.duration ) {\r\n\r\n\t\t\t\tthis.time = this.duration;\r\n\t\t\t\tthis.directionBackwards = true;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( this.time < 0 ) {\r\n\r\n\t\t\t\tthis.time = 0;\r\n\t\t\t\tthis.directionBackwards = false;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t} else {\r\n\r\n\t\tthis.time = this.time % this.duration;\r\n\r\n\t\tif ( this.time < 0 ) this.time += this.duration;\r\n\r\n\t}\r\n\r\n\tvar keyframe = this.startKeyframe + THREE.Math.clamp( Math.floor( this.time / frameTime ), 0, this.length - 1 );\r\n\r\n\tif ( keyframe !== this.currentKeyframe ) {\r\n\r\n\t\tthis.morphTargetInfluences[ this.lastKeyframe ] = 0;\r\n\t\tthis.morphTargetInfluences[ this.currentKeyframe ] = 1;\r\n\r\n\t\tthis.morphTargetInfluences[ keyframe ] = 0;\r\n\r\n\t\tthis.lastKeyframe = this.currentKeyframe;\r\n\t\tthis.currentKeyframe = keyframe;\r\n\r\n\t}\r\n\r\n\tvar mix = ( this.time % frameTime ) / frameTime;\r\n\r\n\tif ( this.directionBackwards ) {\r\n\r\n\t\tmix = 1 - mix;\r\n\r\n\t}\r\n\r\n\tthis.morphTargetInfluences[ this.currentKeyframe ] = mix;\r\n\tthis.morphTargetInfluences[ this.lastKeyframe ] = 1 - mix;\r\n\r\n};\r\n\r\nTHREE.MorphAnimMesh.prototype.interpolateTargets = function ( a, b, t ) {\r\n\r\n\tvar influences = this.morphTargetInfluences;\r\n\r\n\tfor ( var i = 0, l = influences.length; i < l; i ++ ) {\r\n\r\n\t\tinfluences[ i ] = 0;\r\n\r\n\t}\r\n\r\n\tif ( a > -1 ) influences[ a ] = 1 - t;\r\n\tif ( b > -1 ) influences[ b ] = t;\r\n\r\n};\r\n\r\nTHREE.MorphAnimMesh.prototype.clone = function ( object ) {\r\n\r\n\tif ( object === undefined ) object = new THREE.MorphAnimMesh( this.geometry, this.material );\r\n\r\n\tobject.duration = this.duration;\r\n\tobject.mirroredLoop = this.mirroredLoop;\r\n\tobject.time = this.time;\r\n\r\n\tobject.lastKeyframe = this.lastKeyframe;\r\n\tobject.currentKeyframe = this.currentKeyframe;\r\n\r\n\tobject.direction = this.direction;\r\n\tobject.directionBackwards = this.directionBackwards;\r\n\r\n\tTHREE.Mesh.prototype.clone.call( this, object );\r\n\r\n\treturn object;\r\n\r\n};\r\n\r\n// File:src/objects/LOD.js\r\n\r\n/**\r\n * @author mikael emtinger / http://gomo.se/\r\n * @author alteredq / http://alteredqualia.com/\r\n * @author mrdoob / http://mrdoob.com/\r\n */\r\n\r\nTHREE.LOD = function () {\r\n\r\n\tTHREE.Object3D.call( this );\r\n\r\n\tthis.objects = [];\r\n\r\n};\r\n\r\n\r\nTHREE.LOD.prototype = Object.create( THREE.Object3D.prototype );\r\nTHREE.LOD.prototype.constructor = THREE.LOD;\r\n\r\nTHREE.LOD.prototype.addLevel = function ( object, distance ) {\r\n\r\n\tif ( distance === undefined ) distance = 0;\r\n\r\n\tdistance = Math.abs( distance );\r\n\r\n\tfor ( var l = 0; l < this.objects.length; l ++ ) {\r\n\r\n\t\tif ( distance < this.objects[ l ].distance ) {\r\n\r\n\t\t\tbreak;\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tthis.objects.splice( l, 0, { distance: distance, object: object } );\r\n\tthis.add( object );\r\n\r\n};\r\n\r\nTHREE.LOD.prototype.getObjectForDistance = function ( distance ) {\r\n\r\n\tfor ( var i = 1, l = this.objects.length; i < l; i ++ ) {\r\n\r\n\t\tif ( distance < this.objects[ i ].distance ) {\r\n\r\n\t\t\tbreak;\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\treturn this.objects[ i - 1 ].object;\r\n\r\n};\r\n\r\nTHREE.LOD.prototype.raycast = ( function () {\r\n\r\n\tvar matrixPosition = new THREE.Vector3();\r\n\r\n\treturn function ( raycaster, intersects ) {\r\n\r\n\t\tmatrixPosition.setFromMatrixPosition( this.matrixWorld );\r\n\r\n\t\tvar distance = raycaster.ray.origin.distanceTo( matrixPosition );\r\n\r\n\t\tthis.getObjectForDistance( distance ).raycast( raycaster, intersects );\r\n\r\n\t};\r\n\r\n}() );\r\n\r\nTHREE.LOD.prototype.update = function () {\r\n\r\n\tvar v1 = new THREE.Vector3();\r\n\tvar v2 = new THREE.Vector3();\r\n\r\n\treturn function ( camera ) {\r\n\r\n\t\tif ( this.objects.length > 1 ) {\r\n\r\n\t\t\tv1.setFromMatrixPosition( camera.matrixWorld );\r\n\t\t\tv2.setFromMatrixPosition( this.matrixWorld );\r\n\r\n\t\t\tvar distance = v1.distanceTo( v2 );\r\n\r\n\t\t\tthis.objects[ 0 ].object.visible = true;\r\n\r\n\t\t\tfor ( var i = 1, l = this.objects.length; i < l; i ++ ) {\r\n\r\n\t\t\t\tif ( distance >= this.objects[ i ].distance ) {\r\n\r\n\t\t\t\t\tthis.objects[ i - 1 ].object.visible = false;\r\n\t\t\t\t\tthis.objects[ i ].object.visible = true;\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\tfor ( ; i < l; i ++ ) {\r\n\r\n\t\t\t\tthis.objects[ i ].object.visible = false;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n}();\r\n\r\nTHREE.LOD.prototype.clone = function ( object ) {\r\n\r\n\tif ( object === undefined ) object = new THREE.LOD();\r\n\r\n\tTHREE.Object3D.prototype.clone.call( this, object );\r\n\r\n\tfor ( var i = 0, l = this.objects.length; i < l; i ++ ) {\r\n\t\tvar x = this.objects[ i ].object.clone();\r\n\t\tx.visible = i === 0;\r\n\t\tobject.addLevel( x, this.objects[ i ].distance );\r\n\t}\r\n\r\n\treturn object;\r\n\r\n};\r\n\r\n// File:src/objects/Sprite.js\r\n\r\n/**\r\n * @author mikael emtinger / http://gomo.se/\r\n * @author alteredq / http://alteredqualia.com/\r\n */\r\n\r\nTHREE.Sprite = ( function () {\r\n\r\n\tvar indices = new Uint16Array( [ 0, 1, 2, 0, 2, 3 ] );\r\n\tvar vertices = new Float32Array( [ - 0.5, - 0.5, 0, 0.5, - 0.5, 0, 0.5, 0.5, 0, - 0.5, 0.5, 0 ] );\r\n\tvar uvs = new Float32Array( [ 0, 0, 1, 0, 1, 1, 0, 1 ] );\r\n\r\n\tvar geometry = new THREE.BufferGeometry();\r\n\tgeometry.addAttribute( 'index', new THREE.BufferAttribute( indices, 1 ) );\r\n\tgeometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );\r\n\tgeometry.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) );\r\n\r\n\treturn function ( material ) {\r\n\r\n\t\tTHREE.Object3D.call( this );\r\n\r\n\t\tthis.type = 'Sprite';\r\n\r\n\t\tthis.geometry = geometry;\r\n\t\tthis.material = ( material !== undefined ) ? material : new THREE.SpriteMaterial();\r\n\r\n\t};\r\n\r\n} )();\r\n\r\nTHREE.Sprite.prototype = Object.create( THREE.Object3D.prototype );\r\nTHREE.Sprite.prototype.constructor = THREE.Sprite;\r\n\r\nTHREE.Sprite.prototype.raycast = ( function () {\r\n\r\n\tvar matrixPosition = new THREE.Vector3();\r\n\r\n\treturn function ( raycaster, intersects ) {\r\n\r\n\t\tmatrixPosition.setFromMatrixPosition( this.matrixWorld );\r\n\r\n\t\tvar distance = raycaster.ray.distanceToPoint( matrixPosition );\r\n\r\n\t\tif ( distance > this.scale.x ) {\r\n\r\n\t\t\treturn;\r\n\r\n\t\t}\r\n\r\n\t\tintersects.push( {\r\n\r\n\t\t\tdistance: distance,\r\n\t\t\tpoint: this.position,\r\n\t\t\tface: null,\r\n\t\t\tobject: this\r\n\r\n\t\t} );\r\n\r\n\t};\r\n\r\n}() );\r\n\r\nTHREE.Sprite.prototype.clone = function ( object ) {\r\n\r\n\tif ( object === undefined ) object = new THREE.Sprite( this.material );\r\n\r\n\tTHREE.Object3D.prototype.clone.call( this, object );\r\n\r\n\treturn object;\r\n\r\n};\r\n\r\n// Backwards compatibility\r\n\r\nTHREE.Particle = THREE.Sprite;\r\n\r\n// File:src/objects/LensFlare.js\r\n\r\n/**\r\n * @author mikael emtinger / http://gomo.se/\r\n * @author alteredq / http://alteredqualia.com/\r\n */\r\n\r\nTHREE.LensFlare = function ( texture, size, distance, blending, color ) {\r\n\r\n\tTHREE.Object3D.call( this );\r\n\r\n\tthis.lensFlares = [];\r\n\r\n\tthis.positionScreen = new THREE.Vector3();\r\n\tthis.customUpdateCallback = undefined;\r\n\r\n\tif ( texture !== undefined ) {\r\n\r\n\t\tthis.add( texture, size, distance, blending, color );\r\n\r\n\t}\r\n\r\n};\r\n\r\nTHREE.LensFlare.prototype = Object.create( THREE.Object3D.prototype );\r\nTHREE.LensFlare.prototype.constructor = THREE.LensFlare;\r\n\r\n\r\n/*\r\n * Add: adds another flare\r\n */\r\n\r\nTHREE.LensFlare.prototype.add = function ( texture, size, distance, blending, color, opacity ) {\r\n\r\n\tif ( size === undefined ) size = - 1;\r\n\tif ( distance === undefined ) distance = 0;\r\n\tif ( opacity === undefined ) opacity = 1;\r\n\tif ( color === undefined ) color = new THREE.Color( 0xffffff );\r\n\tif ( blending === undefined ) blending = THREE.NormalBlending;\r\n\r\n\tdistance = Math.min( distance, Math.max( 0, distance ) );\r\n\r\n\tthis.lensFlares.push( {\r\n\t\ttexture: texture, \t\t\t// THREE.Texture\r\n\t\tsize: size, \t\t\t\t// size in pixels (-1 = use texture.width)\r\n\t\tdistance: distance, \t\t// distance (0-1) from light source (0=at light source)\r\n\t\tx: 0, y: 0, z: 0,\t\t\t// screen position (-1 => 1) z = 0 is ontop z = 1 is back\r\n\t\tscale: 1, \t\t\t\t\t// scale\r\n\t\trotation: 1, \t\t\t\t// rotation\r\n\t\topacity: opacity,\t\t\t// opacity\r\n\t\tcolor: color,\t\t\t\t// color\r\n\t\tblending: blending\t\t\t// blending\r\n\t} );\r\n\r\n};\r\n\r\n/*\r\n * Update lens flares update positions on all flares based on the screen position\r\n * Set myLensFlare.customUpdateCallback to alter the flares in your project specific way.\r\n */\r\n\r\nTHREE.LensFlare.prototype.updateLensFlares = function () {\r\n\r\n\tvar f, fl = this.lensFlares.length;\r\n\tvar flare;\r\n\tvar vecX = - this.positionScreen.x * 2;\r\n\tvar vecY = - this.positionScreen.y * 2;\r\n\r\n\tfor ( f = 0; f < fl; f ++ ) {\r\n\r\n\t\tflare = this.lensFlares[ f ];\r\n\r\n\t\tflare.x = this.positionScreen.x + vecX * flare.distance;\r\n\t\tflare.y = this.positionScreen.y + vecY * flare.distance;\r\n\r\n\t\tflare.wantedRotation = flare.x * Math.PI * 0.25;\r\n\t\tflare.rotation += ( flare.wantedRotation - flare.rotation ) * 0.25;\r\n\r\n\t}\r\n\r\n};\r\n\r\n\r\n// File:src/scenes/Scene.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n */\r\n\r\nTHREE.Scene = function () {\r\n\r\n\tTHREE.Object3D.call( this );\r\n\r\n\tthis.type = 'Scene';\r\n\r\n\tthis.fog = null;\r\n\tthis.overrideMaterial = null;\r\n\r\n\tthis.autoUpdate = true; // checked by the renderer\r\n\r\n};\r\n\r\nTHREE.Scene.prototype = Object.create( THREE.Object3D.prototype );\r\nTHREE.Scene.prototype.constructor = THREE.Scene;\r\n\r\nTHREE.Scene.prototype.clone = function ( object ) {\r\n\r\n\tif ( object === undefined ) object = new THREE.Scene();\r\n\r\n\tTHREE.Object3D.prototype.clone.call( this, object );\r\n\r\n\tif ( this.fog !== null ) object.fog = this.fog.clone();\r\n\tif ( this.overrideMaterial !== null ) object.overrideMaterial = this.overrideMaterial.clone();\r\n\r\n\tobject.autoUpdate = this.autoUpdate;\r\n\tobject.matrixAutoUpdate = this.matrixAutoUpdate;\r\n\r\n\treturn object;\r\n\r\n};\r\n\r\n// File:src/scenes/Fog.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n * @author alteredq / http://alteredqualia.com/\r\n */\r\n\r\nTHREE.Fog = function ( color, near, far ) {\r\n\r\n\tthis.name = '';\r\n\r\n\tthis.color = new THREE.Color( color );\r\n\r\n\tthis.near = ( near !== undefined ) ? near : 1;\r\n\tthis.far = ( far !== undefined ) ? far : 1000;\r\n\r\n};\r\n\r\nTHREE.Fog.prototype.clone = function () {\r\n\r\n\treturn new THREE.Fog( this.color.getHex(), this.near, this.far );\r\n\r\n};\r\n\r\n// File:src/scenes/FogExp2.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n * @author alteredq / http://alteredqualia.com/\r\n */\r\n\r\nTHREE.FogExp2 = function ( color, density ) {\r\n\r\n\tthis.name = '';\r\n\r\n\tthis.color = new THREE.Color( color );\r\n\tthis.density = ( density !== undefined ) ? density : 0.00025;\r\n\r\n};\r\n\r\nTHREE.FogExp2.prototype.clone = function () {\r\n\r\n\treturn new THREE.FogExp2( this.color.getHex(), this.density );\r\n\r\n};\r\n\r\n// File:src/renderers/shaders/ShaderChunk.js\r\n\r\nTHREE.ShaderChunk = {};\r\n\r\n// File:src/renderers/shaders/ShaderChunk/common.glsl\r\n\r\nTHREE.ShaderChunk[ 'common'] = \"#define PI 3.14159\\n#define PI2 6.28318\\n#define RECIPROCAL_PI2 0.15915494\\n#define LOG2 1.442695\\n#define EPSILON 1e-6\\n\\nfloat square( in float a ) { return a*a; }\\nvec2 square( in vec2 a ) { return vec2( a.x*a.x, a.y*a.y ); }\\nvec3 square( in vec3 a ) { return vec3( a.x*a.x, a.y*a.y, a.z*a.z ); }\\nvec4 square( in vec4 a ) { return vec4( a.x*a.x, a.y*a.y, a.z*a.z, a.w*a.w ); }\\nfloat saturate( in float a ) { return clamp( a, 0.0, 1.0 ); }\\nvec2 saturate( in vec2 a ) { return clamp( a, 0.0, 1.0 ); }\\nvec3 saturate( in vec3 a ) { return clamp( a, 0.0, 1.0 ); }\\nvec4 saturate( in vec4 a ) { return clamp( a, 0.0, 1.0 ); }\\nfloat average( in float a ) { return a; }\\nfloat average( in vec2 a ) { return ( a.x + a.y) * 0.5; }\\nfloat average( in vec3 a ) { return ( a.x + a.y + a.z) / 3.0; }\\nfloat average( in vec4 a ) { return ( a.x + a.y + a.z + a.w) * 0.25; }\\nfloat whiteCompliment( in float a ) { return saturate( 1.0 - a ); }\\nvec2 whiteCompliment( in vec2 a ) { return saturate( vec2(1.0) - a ); }\\nvec3 whiteCompliment( in vec3 a ) { return saturate( vec3(1.0) - a ); }\\nvec4 whiteCompliment( in vec4 a ) { return saturate( vec4(1.0) - a ); }\\nvec3 transformDirection( in vec3 normal, in mat4 matrix ) {\\n\treturn normalize( ( matrix * vec4( normal, 0.0 ) ).xyz );\\n}\\n// http://en.wikibooks.org/wiki/GLSL_Programming/Applying_Matrix_Transformations\\nvec3 inverseTransformDirection( in vec3 normal, in mat4 matrix ) {\\n\treturn normalize( ( vec4( normal, 0.0 ) * matrix ).xyz );\\n}\\nvec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal) {\\n\tfloat distance = dot( planeNormal, point-pointOnPlane );\\n\treturn point - distance * planeNormal;\\n}\\nfloat sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\\n\treturn sign( dot( point - pointOnPlane, planeNormal ) );\\n}\\nvec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {\\n\treturn pointOnLine + lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) );\\n}\\nfloat calcLightAttenuation( float lightDistance, float cutoffDistance, float decayExponent ) {\\n\tif ( decayExponent > 0.0 ) {\\n\t return pow( saturate( 1.0 - lightDistance / cutoffDistance ), decayExponent );\\n\t}\\n\treturn 1.0;\\n}\\n\\nvec3 inputToLinear( in vec3 a ) {\\n#ifdef GAMMA_INPUT\\n\treturn pow( a, vec3( float( GAMMA_FACTOR ) ) );\\n#else\\n\treturn a;\\n#endif\\n}\\nvec3 linearToOutput( in vec3 a ) {\\n#ifdef GAMMA_OUTPUT\\n\treturn pow( a, vec3( 1.0 / float( GAMMA_FACTOR ) ) );\\n#else\\n\treturn a;\\n#endif\\n}\\n\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/alphatest_fragment.glsl\r\n\r\nTHREE.ShaderChunk[ 'alphatest_fragment'] = \"#ifdef ALPHATEST\\n\\n\tif ( diffuseColor.a < ALPHATEST ) discard;\\n\\n#endif\\n\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/lights_lambert_vertex.glsl\r\n\r\nTHREE.ShaderChunk[ 'lights_lambert_vertex'] = \"vLightFront = vec3( 0.0 );\\n\\n#ifdef DOUBLE_SIDED\\n\\n\tvLightBack = vec3( 0.0 );\\n\\n#endif\\n\\ntransformedNormal = normalize( transformedNormal );\\n\\n#if MAX_DIR_LIGHTS > 0\\n\\nfor( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {\\n\\n\tvec3 dirVector = transformDirection( directionalLightDirection[ i ], viewMatrix );\\n\\n\tfloat dotProduct = dot( transformedNormal, dirVector );\\n\tvec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );\\n\\n\t#ifdef DOUBLE_SIDED\\n\\n\t\tvec3 directionalLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\\n\\n\t\t#ifdef WRAP_AROUND\\n\\n\t\t\tvec3 directionalLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\\n\\n\t\t#endif\\n\\n\t#endif\\n\\n\t#ifdef WRAP_AROUND\\n\\n\t\tvec3 directionalLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\\n\t\tdirectionalLightWeighting = mix( directionalLightWeighting, directionalLightWeightingHalf, wrapRGB );\\n\\n\t\t#ifdef DOUBLE_SIDED\\n\\n\t\t\tdirectionalLightWeightingBack = mix( directionalLightWeightingBack, directionalLightWeightingHalfBack, wrapRGB );\\n\\n\t\t#endif\\n\\n\t#endif\\n\\n\tvLightFront += directionalLightColor[ i ] * directionalLightWeighting;\\n\\n\t#ifdef DOUBLE_SIDED\\n\\n\t\tvLightBack += directionalLightColor[ i ] * directionalLightWeightingBack;\\n\\n\t#endif\\n\\n}\\n\\n#endif\\n\\n#if MAX_POINT_LIGHTS > 0\\n\\n\tfor( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\\n\\n\t\tvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\\n\t\tvec3 lVector = lPosition.xyz - mvPosition.xyz;\\n\\n\t\tfloat attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecay[ i ] );\\n\\n\t\tlVector = normalize( lVector );\\n\t\tfloat dotProduct = dot( transformedNormal, lVector );\\n\\n\t\tvec3 pointLightWeighting = vec3( max( dotProduct, 0.0 ) );\\n\\n\t\t#ifdef DOUBLE_SIDED\\n\\n\t\t\tvec3 pointLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\\n\\n\t\t\t#ifdef WRAP_AROUND\\n\\n\t\t\t\tvec3 pointLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\\n\\n\t\t\t#endif\\n\\n\t\t#endif\\n\\n\t\t#ifdef WRAP_AROUND\\n\\n\t\t\tvec3 pointLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\\n\t\t\tpointLightWeighting = mix( pointLightWeighting, pointLightWeightingHalf, wrapRGB );\\n\\n\t\t\t#ifdef DOUBLE_SIDED\\n\\n\t\t\t\tpointLightWeightingBack = mix( pointLightWeightingBack, pointLightWeightingHalfBack, wrapRGB );\\n\\n\t\t\t#endif\\n\\n\t\t#endif\\n\\n\t\tvLightFront += pointLightColor[ i ] * pointLightWeighting * attenuation;\\n\\n\t\t#ifdef DOUBLE_SIDED\\n\\n\t\t\tvLightBack += pointLightColor[ i ] * pointLightWeightingBack * attenuation;\\n\\n\t\t#endif\\n\\n\t}\\n\\n#endif\\n\\n#if MAX_SPOT_LIGHTS > 0\\n\\n\tfor( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\\n\\n\t\tvec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\\n\t\tvec3 lVector = lPosition.xyz - mvPosition.xyz;\\n\\n\t\tfloat spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - worldPosition.xyz ) );\\n\\n\t\tif ( spotEffect > spotLightAngleCos[ i ] ) {\\n\\n\t\t\tspotEffect = max( pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] ), 0.0 );\\n\\n\t\t\tfloat attenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecay[ i ] );\\n\\n\t\t\tlVector = normalize( lVector );\\n\\n\t\t\tfloat dotProduct = dot( transformedNormal, lVector );\\n\t\t\tvec3 spotLightWeighting = vec3( max( dotProduct, 0.0 ) );\\n\\n\t\t\t#ifdef DOUBLE_SIDED\\n\\n\t\t\t\tvec3 spotLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\\n\\n\t\t\t\t#ifdef WRAP_AROUND\\n\\n\t\t\t\t\tvec3 spotLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\\n\\n\t\t\t\t#endif\\n\\n\t\t\t#endif\\n\\n\t\t\t#ifdef WRAP_AROUND\\n\\n\t\t\t\tvec3 spotLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\\n\t\t\t\tspotLightWeighting = mix( spotLightWeighting, spotLightWeightingHalf, wrapRGB );\\n\\n\t\t\t\t#ifdef DOUBLE_SIDED\\n\\n\t\t\t\t\tspotLightWeightingBack = mix( spotLightWeightingBack, spotLightWeightingHalfBack, wrapRGB );\\n\\n\t\t\t\t#endif\\n\\n\t\t\t#endif\\n\\n\t\t\tvLightFront += spotLightColor[ i ] * spotLightWeighting * attenuation * spotEffect;\\n\\n\t\t\t#ifdef DOUBLE_SIDED\\n\\n\t\t\t\tvLightBack += spotLightColor[ i ] * spotLightWeightingBack * attenuation * spotEffect;\\n\\n\t\t\t#endif\\n\\n\t\t}\\n\\n\t}\\n\\n#endif\\n\\n#if MAX_HEMI_LIGHTS > 0\\n\\n\tfor( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\\n\\n\t\tvec3 lVector = transformDirection( hemisphereLightDirection[ i ], viewMatrix );\\n\\n\t\tfloat dotProduct = dot( transformedNormal, lVector );\\n\\n\t\tfloat hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\\n\t\tfloat hemiDiffuseWeightBack = -0.5 * dotProduct + 0.5;\\n\\n\t\tvLightFront += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\\n\\n\t\t#ifdef DOUBLE_SIDED\\n\\n\t\t\tvLightBack += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeightBack );\\n\\n\t\t#endif\\n\\n\t}\\n\\n#endif\\n\\nvLightFront += ambientLightColor;\\n\\n#ifdef DOUBLE_SIDED\\n\\n\tvLightBack += ambientLightColor;\\n\\n#endif\\n\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/map_particle_pars_fragment.glsl\r\n\r\nTHREE.ShaderChunk[ 'map_particle_pars_fragment'] = \"#ifdef USE_MAP\\n\\n\tuniform vec4 offsetRepeat;\\n\tuniform sampler2D map;\\n\\n#endif\\n\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/default_vertex.glsl\r\n\r\nTHREE.ShaderChunk[ 'default_vertex'] = \"#ifdef USE_SKINNING\\n\\n\tvec4 mvPosition = modelViewMatrix * skinned;\\n\\n#elif defined( USE_MORPHTARGETS )\\n\\n\tvec4 mvPosition = modelViewMatrix * vec4( morphed, 1.0 );\\n\\n#else\\n\\n\tvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\\n\\n#endif\\n\\ngl_Position = projectionMatrix * mvPosition;\\n\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/map_pars_fragment.glsl\r\n\r\nTHREE.ShaderChunk[ 'map_pars_fragment'] = \"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP )\\n\\n\tvarying vec2 vUv;\\n\\n#endif\\n\\n#ifdef USE_MAP\\n\\n\tuniform sampler2D map;\\n\\n#endif\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/skinnormal_vertex.glsl\r\n\r\nTHREE.ShaderChunk[ 'skinnormal_vertex'] = \"#ifdef USE_SKINNING\\n\\n\tmat4 skinMatrix = mat4( 0.0 );\\n\tskinMatrix += skinWeight.x * boneMatX;\\n\tskinMatrix += skinWeight.y * boneMatY;\\n\tskinMatrix += skinWeight.z * boneMatZ;\\n\tskinMatrix += skinWeight.w * boneMatW;\\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\\n\\n\t#ifdef USE_MORPHNORMALS\\n\\n\tvec4 skinnedNormal = skinMatrix * vec4( morphedNormal, 0.0 );\\n\\n\t#else\\n\\n\tvec4 skinnedNormal = skinMatrix * vec4( normal, 0.0 );\\n\\n\t#endif\\n\\n#endif\\n\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/logdepthbuf_pars_vertex.glsl\r\n\r\nTHREE.ShaderChunk[ 'logdepthbuf_pars_vertex'] = \"#ifdef USE_LOGDEPTHBUF\\n\\n\t#ifdef USE_LOGDEPTHBUF_EXT\\n\\n\t\tvarying float vFragDepth;\\n\\n\t#endif\\n\\n\tuniform float logDepthBufFC;\\n\\n#endif\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/lightmap_pars_vertex.glsl\r\n\r\nTHREE.ShaderChunk[ 'lightmap_pars_vertex'] = \"#ifdef USE_LIGHTMAP\\n\\n\tvarying vec2 vUv2;\\n\\n#endif\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/lights_phong_fragment.glsl\r\n\r\nTHREE.ShaderChunk[ 'lights_phong_fragment'] = \"#ifndef FLAT_SHADED\\n\\n\tvec3 normal = normalize( vNormal );\\n\\n\t#ifdef DOUBLE_SIDED\\n\\n\t\tnormal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );\\n\\n\t#endif\\n\\n#else\\n\\n\tvec3 fdx = dFdx( vViewPosition );\\n\tvec3 fdy = dFdy( vViewPosition );\\n\tvec3 normal = normalize( cross( fdx, fdy ) );\\n\\n#endif\\n\\nvec3 viewPosition = normalize( vViewPosition );\\n\\n#ifdef USE_NORMALMAP\\n\\n\tnormal = perturbNormal2Arb( -vViewPosition, normal );\\n\\n#elif defined( USE_BUMPMAP )\\n\\n\tnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\\n\\n#endif\\n\\nvec3 totalDiffuseLight = vec3( 0.0 );\\nvec3 totalSpecularLight = vec3( 0.0 );\\n\\n#if MAX_POINT_LIGHTS > 0\\n\\n\tfor ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\\n\\n\t\tvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\\n\t\tvec3 lVector = lPosition.xyz + vViewPosition.xyz;\\n\\n\t\tfloat attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecay[ i ] );\\n\\n\t\tlVector = normalize( lVector );\\n\\n\t\t// diffuse\\n\\n\t\tfloat dotProduct = dot( normal, lVector );\\n\\n\t\t#ifdef WRAP_AROUND\\n\\n\t\t\tfloat pointDiffuseWeightFull = max( dotProduct, 0.0 );\\n\t\t\tfloat pointDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\\n\\n\t\t\tvec3 pointDiffuseWeight = mix( vec3( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );\\n\\n\t\t#else\\n\\n\t\t\tfloat pointDiffuseWeight = max( dotProduct, 0.0 );\\n\\n\t\t#endif\\n\\n\t\ttotalDiffuseLight += pointLightColor[ i ] * pointDiffuseWeight * attenuation;\\n\\n\t\t\t\t// specular\\n\\n\t\tvec3 pointHalfVector = normalize( lVector + viewPosition );\\n\t\tfloat pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );\\n\t\tfloat pointSpecularWeight = specularStrength * max( pow( pointDotNormalHalf, shininess ), 0.0 );\\n\\n\t\tfloat specularNormalization = ( shininess + 2.0 ) / 8.0;\\n\\n\t\tvec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, pointHalfVector ), 0.0 ), 5.0 );\\n\t\ttotalSpecularLight += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * attenuation * specularNormalization;\\n\\n\t}\\n\\n#endif\\n\\n#if MAX_SPOT_LIGHTS > 0\\n\\n\tfor ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\\n\\n\t\tvec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\\n\t\tvec3 lVector = lPosition.xyz + vViewPosition.xyz;\\n\\n\t\tfloat attenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecay[ i ] );\\n\\n\t\tlVector = normalize( lVector );\\n\\n\t\tfloat spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );\\n\\n\t\tif ( spotEffect > spotLightAngleCos[ i ] ) {\\n\\n\t\t\tspotEffect = max( pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] ), 0.0 );\\n\\n\t\t\t// diffuse\\n\\n\t\t\tfloat dotProduct = dot( normal, lVector );\\n\\n\t\t\t#ifdef WRAP_AROUND\\n\\n\t\t\t\tfloat spotDiffuseWeightFull = max( dotProduct, 0.0 );\\n\t\t\t\tfloat spotDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\\n\\n\t\t\t\tvec3 spotDiffuseWeight = mix( vec3( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );\\n\\n\t\t\t#else\\n\\n\t\t\t\tfloat spotDiffuseWeight = max( dotProduct, 0.0 );\\n\\n\t\t\t#endif\\n\\n\t\t\ttotalDiffuseLight += spotLightColor[ i ] * spotDiffuseWeight * attenuation * spotEffect;\\n\\n\t\t\t// specular\\n\\n\t\t\tvec3 spotHalfVector = normalize( lVector + viewPosition );\\n\t\t\tfloat spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );\\n\t\t\tfloat spotSpecularWeight = specularStrength * max( pow( spotDotNormalHalf, shininess ), 0.0 );\\n\\n\t\t\tfloat specularNormalization = ( shininess + 2.0 ) / 8.0;\\n\\n\t\t\tvec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, spotHalfVector ), 0.0 ), 5.0 );\\n\t\t\ttotalSpecularLight += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * attenuation * specularNormalization * spotEffect;\\n\\n\t\t}\\n\\n\t}\\n\\n#endif\\n\\n#if MAX_DIR_LIGHTS > 0\\n\\n\tfor( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {\\n\\n\t\tvec3 dirVector = transformDirection( directionalLightDirection[ i ], viewMatrix );\\n\\n\t\t// diffuse\\n\\n\t\tfloat dotProduct = dot( normal, dirVector );\\n\\n\t\t#ifdef WRAP_AROUND\\n\\n\t\t\tfloat dirDiffuseWeightFull = max( dotProduct, 0.0 );\\n\t\t\tfloat dirDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\\n\\n\t\t\tvec3 dirDiffuseWeight = mix( vec3( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), wrapRGB );\\n\\n\t\t#else\\n\\n\t\t\tfloat dirDiffuseWeight = max( dotProduct, 0.0 );\\n\\n\t\t#endif\\n\\n\t\ttotalDiffuseLight += directionalLightColor[ i ] * dirDiffuseWeight;\\n\\n\t\t// specular\\n\\n\t\tvec3 dirHalfVector = normalize( dirVector + viewPosition );\\n\t\tfloat dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );\\n\t\tfloat dirSpecularWeight = specularStrength * max( pow( dirDotNormalHalf, shininess ), 0.0 );\\n\\n\t\t/*\\n\t\t// fresnel term from skin shader\\n\t\tconst float F0 = 0.128;\\n\\n\t\tfloat base = 1.0 - dot( viewPosition, dirHalfVector );\\n\t\tfloat exponential = pow( base, 5.0 );\\n\\n\t\tfloat fresnel = exponential + F0 * ( 1.0 - exponential );\\n\t\t*/\\n\\n\t\t/*\\n\t\t// fresnel term from fresnel shader\\n\t\tconst float mFresnelBias = 0.08;\\n\t\tconst float mFresnelScale = 0.3;\\n\t\tconst float mFresnelPower = 5.0;\\n\\n\t\tfloat fresnel = mFresnelBias + mFresnelScale * pow( 1.0 + dot( normalize( -viewPosition ), normal ), mFresnelPower );\\n\t\t*/\\n\\n\t\tfloat specularNormalization = ( shininess + 2.0 ) / 8.0;\\n\\n\t\t// \t\tdirSpecular += specular * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization * fresnel;\\n\\n\t\tvec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( dirVector, dirHalfVector ), 0.0 ), 5.0 );\\n\t\ttotalSpecularLight += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;\\n\\n\\n\t}\\n\\n#endif\\n\\n#if MAX_HEMI_LIGHTS > 0\\n\\n\tfor( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\\n\\n\t\tvec3 lVector = transformDirection( hemisphereLightDirection[ i ], viewMatrix );\\n\\n\t\t// diffuse\\n\\n\t\tfloat dotProduct = dot( normal, lVector );\\n\t\tfloat hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\\n\\n\t\tvec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\\n\\n\t\ttotalDiffuseLight += hemiColor;\\n\\n\t\t// specular (sky light)\\n\\n\t\tvec3 hemiHalfVectorSky = normalize( lVector + viewPosition );\\n\t\tfloat hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;\\n\t\tfloat hemiSpecularWeightSky = specularStrength * max( pow( max( hemiDotNormalHalfSky, 0.0 ), shininess ), 0.0 );\\n\\n\t\t// specular (ground light)\\n\\n\t\tvec3 lVectorGround = -lVector;\\n\\n\t\tvec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );\\n\t\tfloat hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;\\n\t\tfloat hemiSpecularWeightGround = specularStrength * max( pow( max( hemiDotNormalHalfGround, 0.0 ), shininess ), 0.0 );\\n\\n\t\tfloat dotProductGround = dot( normal, lVectorGround );\\n\\n\t\tfloat specularNormalization = ( shininess + 2.0 ) / 8.0;\\n\\n\t\tvec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, hemiHalfVectorSky ), 0.0 ), 5.0 );\\n\t\tvec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 0.0 ), 5.0 );\\n\t\ttotalSpecularLight += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );\\n\\n\t}\\n\\n#endif\\n\\n#ifdef METAL\\n\\n\toutgoingLight += diffuseColor.rgb * ( totalDiffuseLight + ambientLightColor ) * specular + totalSpecularLight + emissive;\\n\\n#else\\n\\n\toutgoingLight += diffuseColor.rgb * ( totalDiffuseLight + ambientLightColor ) + totalSpecularLight + emissive;\\n\\n#endif\\n\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/fog_pars_fragment.glsl\r\n\r\nTHREE.ShaderChunk[ 'fog_pars_fragment'] = \"#ifdef USE_FOG\\n\\n\tuniform vec3 fogColor;\\n\\n\t#ifdef FOG_EXP2\\n\\n\t\tuniform float fogDensity;\\n\\n\t#else\\n\\n\t\tuniform float fogNear;\\n\t\tuniform float fogFar;\\n\t#endif\\n\\n#endif\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/morphnormal_vertex.glsl\r\n\r\nTHREE.ShaderChunk[ 'morphnormal_vertex'] = \"#ifdef USE_MORPHNORMALS\\n\\n\tvec3 morphedNormal = vec3( 0.0 );\\n\\n\tmorphedNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];\\n\tmorphedNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];\\n\tmorphedNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];\\n\tmorphedNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];\\n\\n\tmorphedNormal += normal;\\n\\n#endif\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/envmap_pars_fragment.glsl\r\n\r\nTHREE.ShaderChunk[ 'envmap_pars_fragment'] = \"#ifdef USE_ENVMAP\\n\\n\tuniform float reflectivity;\\n\t#ifdef ENVMAP_TYPE_CUBE\\n\t\tuniform samplerCube envMap;\\n\t#else\\n\t\tuniform sampler2D envMap;\\n\t#endif\\n\tuniform float flipEnvMap;\\n\\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\\n\\n\t\tuniform float refractionRatio;\\n\\n\t#else\\n\\n\t\tvarying vec3 vReflect;\\n\\n\t#endif\\n\\n#endif\\n\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/logdepthbuf_fragment.glsl\r\n\r\nTHREE.ShaderChunk[ 'logdepthbuf_fragment'] = \"#if defined(USE_LOGDEPTHBUF) && defined(USE_LOGDEPTHBUF_EXT)\\n\\n\tgl_FragDepthEXT = log2(vFragDepth) * logDepthBufFC * 0.5;\\n\\n#endif\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl\r\n\r\nTHREE.ShaderChunk[ 'normalmap_pars_fragment'] = \"#ifdef USE_NORMALMAP\\n\\n\tuniform sampler2D normalMap;\\n\tuniform vec2 normalScale;\\n\\n\t// Per-Pixel Tangent Space Normal Mapping\\n\t// http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html\\n\\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {\\n\\n\t\tvec3 q0 = dFdx( eye_pos.xyz );\\n\t\tvec3 q1 = dFdy( eye_pos.xyz );\\n\t\tvec2 st0 = dFdx( vUv.st );\\n\t\tvec2 st1 = dFdy( vUv.st );\\n\\n\t\tvec3 S = normalize( q0 * st1.t - q1 * st0.t );\\n\t\tvec3 T = normalize( -q0 * st1.s + q1 * st0.s );\\n\t\tvec3 N = normalize( surf_norm );\\n\\n\t\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\\n\t\tmapN.xy = normalScale * mapN.xy;\\n\t\tmat3 tsn = mat3( S, T, N );\\n\t\treturn normalize( tsn * mapN );\\n\\n\t}\\n\\n#endif\\n\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/lights_phong_pars_vertex.glsl\r\n\r\nTHREE.ShaderChunk[ 'lights_phong_pars_vertex'] = \"#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )\\n\\n\tvarying vec3 vWorldPosition;\\n\\n#endif\\n\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/lightmap_pars_fragment.glsl\r\n\r\nTHREE.ShaderChunk[ 'lightmap_pars_fragment'] = \"#ifdef USE_LIGHTMAP\\n\\n\tvarying vec2 vUv2;\\n\tuniform sampler2D lightMap;\\n\\n#endif\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/shadowmap_vertex.glsl\r\n\r\nTHREE.ShaderChunk[ 'shadowmap_vertex'] = \"#ifdef USE_SHADOWMAP\\n\\n\tfor( int i = 0; i < MAX_SHADOWS; i ++ ) {\\n\\n\t\tvShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;\\n\\n\t}\\n\\n#endif\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/lights_phong_vertex.glsl\r\n\r\nTHREE.ShaderChunk[ 'lights_phong_vertex'] = \"#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )\\n\\n\tvWorldPosition = worldPosition.xyz;\\n\\n#endif\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/map_fragment.glsl\r\n\r\nTHREE.ShaderChunk[ 'map_fragment'] = \"#ifdef USE_MAP\\n\\n\tvec4 texelColor = texture2D( map, vUv );\\n\\n\ttexelColor.xyz = inputToLinear( texelColor.xyz );\\n\\n\tdiffuseColor *= texelColor;\\n\\n#endif\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/lightmap_vertex.glsl\r\n\r\nTHREE.ShaderChunk[ 'lightmap_vertex'] = \"#ifdef USE_LIGHTMAP\\n\\n\tvUv2 = uv2;\\n\\n#endif\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/map_particle_fragment.glsl\r\n\r\nTHREE.ShaderChunk[ 'map_particle_fragment'] = \"#ifdef USE_MAP\\n\\n\tdiffuseColor *= texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) * offsetRepeat.zw + offsetRepeat.xy );\\n\\n#endif\\n\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/color_pars_fragment.glsl\r\n\r\nTHREE.ShaderChunk[ 'color_pars_fragment'] = \"#ifdef USE_COLOR\\n\\n\tvarying vec3 vColor;\\n\\n#endif\\n\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/color_vertex.glsl\r\n\r\nTHREE.ShaderChunk[ 'color_vertex'] = \"#ifdef USE_COLOR\\n\\n\tvColor.xyz = inputToLinear( color.xyz );\\n\\n#endif\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/skinning_vertex.glsl\r\n\r\nTHREE.ShaderChunk[ 'skinning_vertex'] = \"#ifdef USE_SKINNING\\n\\n\t#ifdef USE_MORPHTARGETS\\n\\n\tvec4 skinVertex = bindMatrix * vec4( morphed, 1.0 );\\n\\n\t#else\\n\\n\tvec4 skinVertex = bindMatrix * vec4( position, 1.0 );\\n\\n\t#endif\\n\\n\tvec4 skinned = vec4( 0.0 );\\n\tskinned += boneMatX * skinVertex * skinWeight.x;\\n\tskinned += boneMatY * skinVertex * skinWeight.y;\\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\\n\tskinned += boneMatW * skinVertex * skinWeight.w;\\n\tskinned = bindMatrixInverse * skinned;\\n\\n#endif\\n\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/envmap_pars_vertex.glsl\r\n\r\nTHREE.ShaderChunk[ 'envmap_pars_vertex'] = \"#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP ) && ! defined( PHONG )\\n\\n\tvarying vec3 vReflect;\\n\\n\tuniform float refractionRatio;\\n\\n#endif\\n\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/linear_to_gamma_fragment.glsl\r\n\r\nTHREE.ShaderChunk[ 'linear_to_gamma_fragment'] = \"\\n\toutgoingLight = linearToOutput( outgoingLight );\\n\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/color_pars_vertex.glsl\r\n\r\nTHREE.ShaderChunk[ 'color_pars_vertex'] = \"#ifdef USE_COLOR\\n\\n\tvarying vec3 vColor;\\n\\n#endif\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/lights_lambert_pars_vertex.glsl\r\n\r\nTHREE.ShaderChunk[ 'lights_lambert_pars_vertex'] = \"uniform vec3 ambientLightColor;\\n\\n#if MAX_DIR_LIGHTS > 0\\n\\n\tuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\\n\tuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\\n\\n#endif\\n\\n#if MAX_HEMI_LIGHTS > 0\\n\\n\tuniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\\n\tuniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\\n\tuniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\\n\\n#endif\\n\\n#if MAX_POINT_LIGHTS > 0\\n\\n\tuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\\n\tuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\\n\tuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\\n\tuniform float pointLightDecay[ MAX_POINT_LIGHTS ];\\n\\n#endif\\n\\n#if MAX_SPOT_LIGHTS > 0\\n\\n\tuniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\\n\tuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\\n\tuniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\\n\tuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\\n\tuniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\\n\tuniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\\n\tuniform float spotLightDecay[ MAX_SPOT_LIGHTS ];\\n\\n#endif\\n\\n#ifdef WRAP_AROUND\\n\\n\tuniform vec3 wrapRGB;\\n\\n#endif\\n\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/map_pars_vertex.glsl\r\n\r\nTHREE.ShaderChunk[ 'map_pars_vertex'] = \"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP )\\n\\n\tvarying vec2 vUv;\\n\tuniform vec4 offsetRepeat;\\n\\n#endif\\n\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/envmap_fragment.glsl\r\n\r\nTHREE.ShaderChunk[ 'envmap_fragment'] = \"#ifdef USE_ENVMAP\\n\\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\\n\\n\t\tvec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\\n\\n\t\t// Transforming Normal Vectors with the Inverse Transformation\\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\\n\\n\t\t#ifdef ENVMAP_MODE_REFLECTION\\n\\n\t\t\tvec3 reflectVec = reflect( cameraToVertex, worldNormal );\\n\\n\t\t#else\\n\\n\t\t\tvec3 reflectVec = refract( cameraToVertex, worldNormal, refractionRatio );\\n\\n\t\t#endif\\n\\n\t#else\\n\\n\t\tvec3 reflectVec = vReflect;\\n\\n\t#endif\\n\\n\t#ifdef DOUBLE_SIDED\\n\t\tfloat flipNormal = ( -1.0 + 2.0 * float( gl_FrontFacing ) );\\n\t#else\\n\t\tfloat flipNormal = 1.0;\\n\t#endif\\n\\n\t#ifdef ENVMAP_TYPE_CUBE\\n\t\tvec4 envColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\\n\\n\t#elif defined( ENVMAP_TYPE_EQUIREC )\\n\t\tvec2 sampleUV;\\n\t\tsampleUV.y = saturate( flipNormal * reflectVec.y * 0.5 + 0.5 );\\n\t\tsampleUV.x = atan( flipNormal * reflectVec.z, flipNormal * reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\\n\t\tvec4 envColor = texture2D( envMap, sampleUV );\\n\\n\t#elif defined( ENVMAP_TYPE_SPHERE )\\n\t\tvec3 reflectView = flipNormal * normalize((viewMatrix * vec4( reflectVec, 0.0 )).xyz + vec3(0.0,0.0,1.0));\\n\t\tvec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );\\n\t#endif\\n\\n\tenvColor.xyz = inputToLinear( envColor.xyz );\\n\\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\\n\\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\\n\\n\t#elif defined( ENVMAP_BLENDING_MIX )\\n\\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\\n\\n\t#elif defined( ENVMAP_BLENDING_ADD )\\n\\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\\n\\n\t#endif\\n\\n#endif\\n\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/specularmap_pars_fragment.glsl\r\n\r\nTHREE.ShaderChunk[ 'specularmap_pars_fragment'] = \"#ifdef USE_SPECULARMAP\\n\\n\tuniform sampler2D specularMap;\\n\\n#endif\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/logdepthbuf_vertex.glsl\r\n\r\nTHREE.ShaderChunk[ 'logdepthbuf_vertex'] = \"#ifdef USE_LOGDEPTHBUF\\n\\n\tgl_Position.z = log2(max( EPSILON, gl_Position.w + 1.0 )) * logDepthBufFC;\\n\\n\t#ifdef USE_LOGDEPTHBUF_EXT\\n\\n\t\tvFragDepth = 1.0 + gl_Position.w;\\n\\n#else\\n\\n\t\tgl_Position.z = (gl_Position.z - 1.0) * gl_Position.w;\\n\\n\t#endif\\n\\n#endif\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/morphtarget_pars_vertex.glsl\r\n\r\nTHREE.ShaderChunk[ 'morphtarget_pars_vertex'] = \"#ifdef USE_MORPHTARGETS\\n\\n\t#ifndef USE_MORPHNORMALS\\n\\n\tuniform float morphTargetInfluences[ 8 ];\\n\\n\t#else\\n\\n\tuniform float morphTargetInfluences[ 4 ];\\n\\n\t#endif\\n\\n#endif\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/specularmap_fragment.glsl\r\n\r\nTHREE.ShaderChunk[ 'specularmap_fragment'] = \"float specularStrength;\\n\\n#ifdef USE_SPECULARMAP\\n\\n\tvec4 texelSpecular = texture2D( specularMap, vUv );\\n\tspecularStrength = texelSpecular.r;\\n\\n#else\\n\\n\tspecularStrength = 1.0;\\n\\n#endif\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/fog_fragment.glsl\r\n\r\nTHREE.ShaderChunk[ 'fog_fragment'] = \"#ifdef USE_FOG\\n\\n\t#ifdef USE_LOGDEPTHBUF_EXT\\n\\n\t\tfloat depth = gl_FragDepthEXT / gl_FragCoord.w;\\n\\n\t#else\\n\\n\t\tfloat depth = gl_FragCoord.z / gl_FragCoord.w;\\n\\n\t#endif\\n\\n\t#ifdef FOG_EXP2\\n\\n\t\tfloat fogFactor = exp2( - square( fogDensity ) * square( depth ) * LOG2 );\\n\t\tfogFactor = whiteCompliment( fogFactor );\\n\\n\t#else\\n\\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, depth );\\n\\n\t#endif\\n\t\\n\toutgoingLight = mix( outgoingLight, fogColor, fogFactor );\\n\\n#endif\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/bumpmap_pars_fragment.glsl\r\n\r\nTHREE.ShaderChunk[ 'bumpmap_pars_fragment'] = \"#ifdef USE_BUMPMAP\\n\\n\tuniform sampler2D bumpMap;\\n\tuniform float bumpScale;\\n\\n\t// Derivative maps - bump mapping unparametrized surfaces by Morten Mikkelsen\\n\t// http://mmikkelsen3d.blogspot.sk/2011/07/derivative-maps.html\\n\\n\t// Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2)\\n\\n\tvec2 dHdxy_fwd() {\\n\\n\t\tvec2 dSTdx = dFdx( vUv );\\n\t\tvec2 dSTdy = dFdy( vUv );\\n\\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\\n\\n\t\treturn vec2( dBx, dBy );\\n\\n\t}\\n\\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\\n\\n\t\tvec3 vSigmaX = dFdx( surf_pos );\\n\t\tvec3 vSigmaY = dFdy( surf_pos );\\n\t\tvec3 vN = surf_norm;\t\t// normalized\\n\\n\t\tvec3 R1 = cross( vSigmaY, vN );\\n\t\tvec3 R2 = cross( vN, vSigmaX );\\n\\n\t\tfloat fDet = dot( vSigmaX, R1 );\\n\\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\\n\\n\t}\\n\\n#endif\\n\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl\r\n\r\nTHREE.ShaderChunk[ 'defaultnormal_vertex'] = \"#ifdef USE_SKINNING\\n\\n\tvec3 objectNormal = skinnedNormal.xyz;\\n\\n#elif defined( USE_MORPHNORMALS )\\n\\n\tvec3 objectNormal = morphedNormal;\\n\\n#else\\n\\n\tvec3 objectNormal = normal;\\n\\n#endif\\n\\n#ifdef FLIP_SIDED\\n\\n\tobjectNormal = -objectNormal;\\n\\n#endif\\n\\nvec3 transformedNormal = normalMatrix * objectNormal;\\n\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/lights_phong_pars_fragment.glsl\r\n\r\nTHREE.ShaderChunk[ 'lights_phong_pars_fragment'] = \"uniform vec3 ambientLightColor;\\n\\n#if MAX_DIR_LIGHTS > 0\\n\\n\tuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\\n\tuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\\n\\n#endif\\n\\n#if MAX_HEMI_LIGHTS > 0\\n\\n\tuniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\\n\tuniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\\n\tuniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\\n\\n#endif\\n\\n#if MAX_POINT_LIGHTS > 0\\n\\n\tuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\\n\\n\tuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\\n\tuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\\n\tuniform float pointLightDecay[ MAX_POINT_LIGHTS ];\\n\\n#endif\\n\\n#if MAX_SPOT_LIGHTS > 0\\n\\n\tuniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\\n\tuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\\n\tuniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\\n\tuniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\\n\tuniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\\n\tuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\\n\tuniform float spotLightDecay[ MAX_SPOT_LIGHTS ];\\n\\n#endif\\n\\n#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )\\n\\n\tvarying vec3 vWorldPosition;\\n\\n#endif\\n\\n#ifdef WRAP_AROUND\\n\\n\tuniform vec3 wrapRGB;\\n\\n#endif\\n\\nvarying vec3 vViewPosition;\\n\\n#ifndef FLAT_SHADED\\n\\n\tvarying vec3 vNormal;\\n\\n#endif\\n\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/skinbase_vertex.glsl\r\n\r\nTHREE.ShaderChunk[ 'skinbase_vertex'] = \"#ifdef USE_SKINNING\\n\\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\\n\\n#endif\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/map_vertex.glsl\r\n\r\nTHREE.ShaderChunk[ 'map_vertex'] = \"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP )\\n\\n\tvUv = uv * offsetRepeat.zw + offsetRepeat.xy;\\n\\n#endif\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/lightmap_fragment.glsl\r\n\r\nTHREE.ShaderChunk[ 'lightmap_fragment'] = \"#ifdef USE_LIGHTMAP\\n\\n\toutgoingLight *= diffuseColor.xyz * texture2D( lightMap, vUv2 ).xyz;\\n\\n#endif\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/shadowmap_pars_vertex.glsl\r\n\r\nTHREE.ShaderChunk[ 'shadowmap_pars_vertex'] = \"#ifdef USE_SHADOWMAP\\n\\n\tvarying vec4 vShadowCoord[ MAX_SHADOWS ];\\n\tuniform mat4 shadowMatrix[ MAX_SHADOWS ];\\n\\n#endif\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/color_fragment.glsl\r\n\r\nTHREE.ShaderChunk[ 'color_fragment'] = \"#ifdef USE_COLOR\\n\\n\tdiffuseColor.rgb *= vColor;\\n\\n#endif\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/morphtarget_vertex.glsl\r\n\r\nTHREE.ShaderChunk[ 'morphtarget_vertex'] = \"#ifdef USE_MORPHTARGETS\\n\\n\tvec3 morphed = vec3( 0.0 );\\n\tmorphed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\\n\tmorphed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\\n\tmorphed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\\n\tmorphed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\\n\\n\t#ifndef USE_MORPHNORMALS\\n\\n\tmorphed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\\n\tmorphed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\\n\tmorphed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\\n\tmorphed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\\n\\n\t#endif\\n\\n\tmorphed += position;\\n\\n#endif\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/envmap_vertex.glsl\r\n\r\nTHREE.ShaderChunk[ 'envmap_vertex'] = \"#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP ) && ! defined( PHONG )\\n\\n\tvec3 worldNormal = transformDirection( objectNormal, modelMatrix );\\n\\n\tvec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );\\n\\n\t#ifdef ENVMAP_MODE_REFLECTION\\n\\n\t\tvReflect = reflect( cameraToVertex, worldNormal );\\n\\n\t#else\\n\\n\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\\n\\n\t#endif\\n\\n#endif\\n\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/shadowmap_fragment.glsl\r\n\r\nTHREE.ShaderChunk[ 'shadowmap_fragment'] = \"#ifdef USE_SHADOWMAP\\n\\n\t#ifdef SHADOWMAP_DEBUG\\n\\n\t\tvec3 frustumColors[3];\\n\t\tfrustumColors[0] = vec3( 1.0, 0.5, 0.0 );\\n\t\tfrustumColors[1] = vec3( 0.0, 1.0, 0.8 );\\n\t\tfrustumColors[2] = vec3( 0.0, 0.5, 1.0 );\\n\\n\t#endif\\n\\n\t#ifdef SHADOWMAP_CASCADE\\n\\n\t\tint inFrustumCount = 0;\\n\\n\t#endif\\n\\n\tfloat fDepth;\\n\tvec3 shadowColor = vec3( 1.0 );\\n\\n\tfor( int i = 0; i < MAX_SHADOWS; i ++ ) {\\n\\n\t\tvec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;\\n\\n\t\t\t\t// if ( something && something ) breaks ATI OpenGL shader compiler\\n\t\t\t\t// if ( all( something, something ) ) using this instead\\n\\n\t\tbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\\n\t\tbool inFrustum = all( inFrustumVec );\\n\\n\t\t\t\t// don't shadow pixels outside of light frustum\\n\t\t\t\t// use just first frustum (for cascades)\\n\t\t\t\t// don't shadow pixels behind far plane of light frustum\\n\\n\t\t#ifdef SHADOWMAP_CASCADE\\n\\n\t\t\tinFrustumCount += int( inFrustum );\\n\t\t\tbvec3 frustumTestVec = bvec3( inFrustum, inFrustumCount == 1, shadowCoord.z <= 1.0 );\\n\\n\t\t#else\\n\\n\t\t\tbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\\n\\n\t\t#endif\\n\\n\t\tbool frustumTest = all( frustumTestVec );\\n\\n\t\tif ( frustumTest ) {\\n\\n\t\t\tshadowCoord.z += shadowBias[ i ];\\n\\n\t\t\t#if defined( SHADOWMAP_TYPE_PCF )\\n\\n\t\t\t\t\t\t// Percentage-close filtering\\n\t\t\t\t\t\t// (9 pixel kernel)\\n\t\t\t\t\t\t// http://fabiensanglard.net/shadowmappingPCF/\\n\\n\t\t\t\tfloat shadow = 0.0;\\n\\n\t\t/*\\n\t\t\t\t\t\t// nested loops breaks shader compiler / validator on some ATI cards when using OpenGL\\n\t\t\t\t\t\t// must enroll loop manually\\n\\n\t\t\t\tfor ( float y = -1.25; y <= 1.25; y += 1.25 )\\n\t\t\t\t\tfor ( float x = -1.25; x <= 1.25; x += 1.25 ) {\\n\\n\t\t\t\t\t\tvec4 rgbaDepth = texture2D( shadowMap[ i ], vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy );\\n\\n\t\t\t\t\t\t\t\t// doesn't seem to produce any noticeable visual difference compared to simple texture2D lookup\\n\t\t\t\t\t\t\t\t//vec4 rgbaDepth = texture2DProj( shadowMap[ i ], vec4( vShadowCoord[ i ].w * ( vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy ), 0.05, vShadowCoord[ i ].w ) );\\n\\n\t\t\t\t\t\tfloat fDepth = unpackDepth( rgbaDepth );\\n\\n\t\t\t\t\t\tif ( fDepth < shadowCoord.z )\\n\t\t\t\t\t\t\tshadow += 1.0;\\n\\n\t\t\t\t}\\n\\n\t\t\t\tshadow /= 9.0;\\n\\n\t\t*/\\n\\n\t\t\t\tconst float shadowDelta = 1.0 / 9.0;\\n\\n\t\t\t\tfloat xPixelOffset = 1.0 / shadowMapSize[ i ].x;\\n\t\t\t\tfloat yPixelOffset = 1.0 / shadowMapSize[ i ].y;\\n\\n\t\t\t\tfloat dx0 = -1.25 * xPixelOffset;\\n\t\t\t\tfloat dy0 = -1.25 * yPixelOffset;\\n\t\t\t\tfloat dx1 = 1.25 * xPixelOffset;\\n\t\t\t\tfloat dy1 = 1.25 * yPixelOffset;\\n\\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );\\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\\n\\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );\\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\\n\\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );\\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\\n\\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );\\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\\n\\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );\\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\\n\\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );\\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\\n\\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );\\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\\n\\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );\\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\\n\\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );\\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\\n\\n\t\t\t\tshadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );\\n\\n\t\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\\n\\n\t\t\t\t\t\t// Percentage-close filtering\\n\t\t\t\t\t\t// (9 pixel kernel)\\n\t\t\t\t\t\t// http://fabiensanglard.net/shadowmappingPCF/\\n\\n\t\t\t\tfloat shadow = 0.0;\\n\\n\t\t\t\tfloat xPixelOffset = 1.0 / shadowMapSize[ i ].x;\\n\t\t\t\tfloat yPixelOffset = 1.0 / shadowMapSize[ i ].y;\\n\\n\t\t\t\tfloat dx0 = -1.0 * xPixelOffset;\\n\t\t\t\tfloat dy0 = -1.0 * yPixelOffset;\\n\t\t\t\tfloat dx1 = 1.0 * xPixelOffset;\\n\t\t\t\tfloat dy1 = 1.0 * yPixelOffset;\\n\\n\t\t\t\tmat3 shadowKernel;\\n\t\t\t\tmat3 depthKernel;\\n\\n\t\t\t\tdepthKernel[0][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );\\n\t\t\t\tdepthKernel[0][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );\\n\t\t\t\tdepthKernel[0][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );\\n\t\t\t\tdepthKernel[1][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );\\n\t\t\t\tdepthKernel[1][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );\\n\t\t\t\tdepthKernel[1][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );\\n\t\t\t\tdepthKernel[2][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );\\n\t\t\t\tdepthKernel[2][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );\\n\t\t\t\tdepthKernel[2][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );\\n\\n\t\t\t\tvec3 shadowZ = vec3( shadowCoord.z );\\n\t\t\t\tshadowKernel[0] = vec3(lessThan(depthKernel[0], shadowZ ));\\n\t\t\t\tshadowKernel[0] *= vec3(0.25);\\n\\n\t\t\t\tshadowKernel[1] = vec3(lessThan(depthKernel[1], shadowZ ));\\n\t\t\t\tshadowKernel[1] *= vec3(0.25);\\n\\n\t\t\t\tshadowKernel[2] = vec3(lessThan(depthKernel[2], shadowZ ));\\n\t\t\t\tshadowKernel[2] *= vec3(0.25);\\n\\n\t\t\t\tvec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[i].xy );\\n\\n\t\t\t\tshadowKernel[0] = mix( shadowKernel[1], shadowKernel[0], fractionalCoord.x );\\n\t\t\t\tshadowKernel[1] = mix( shadowKernel[2], shadowKernel[1], fractionalCoord.x );\\n\\n\t\t\t\tvec4 shadowValues;\\n\t\t\t\tshadowValues.x = mix( shadowKernel[0][1], shadowKernel[0][0], fractionalCoord.y );\\n\t\t\t\tshadowValues.y = mix( shadowKernel[0][2], shadowKernel[0][1], fractionalCoord.y );\\n\t\t\t\tshadowValues.z = mix( shadowKernel[1][1], shadowKernel[1][0], fractionalCoord.y );\\n\t\t\t\tshadowValues.w = mix( shadowKernel[1][2], shadowKernel[1][1], fractionalCoord.y );\\n\\n\t\t\t\tshadow = dot( shadowValues, vec4( 1.0 ) );\\n\\n\t\t\t\tshadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );\\n\\n\t\t\t#else\\n\\n\t\t\t\tvec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );\\n\t\t\t\tfloat fDepth = unpackDepth( rgbaDepth );\\n\\n\t\t\t\tif ( fDepth < shadowCoord.z )\\n\\n\t\t// spot with multiple shadows is darker\\n\\n\t\t\t\t\tshadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] );\\n\\n\t\t// spot with multiple shadows has the same color as single shadow spot\\n\\n\t\t// \t\t\t\t\tshadowColor = min( shadowColor, vec3( shadowDarkness[ i ] ) );\\n\\n\t\t\t#endif\\n\\n\t\t}\\n\\n\\n\t\t#ifdef SHADOWMAP_DEBUG\\n\\n\t\t\t#ifdef SHADOWMAP_CASCADE\\n\\n\t\t\t\tif ( inFrustum && inFrustumCount == 1 ) outgoingLight *= frustumColors[ i ];\\n\\n\t\t\t#else\\n\\n\t\t\t\tif ( inFrustum ) outgoingLight *= frustumColors[ i ];\\n\\n\t\t\t#endif\\n\\n\t\t#endif\\n\\n\t}\\n\\n\t// NOTE: I am unsure if this is correct in linear space. -bhouston, Dec 29, 2014\\n\tshadowColor = inputToLinear( shadowColor );\\n\\n\toutgoingLight = outgoingLight * shadowColor;\\n\\n#endif\\n\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/worldpos_vertex.glsl\r\n\r\nTHREE.ShaderChunk[ 'worldpos_vertex'] = \"#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )\\n\\n\t#ifdef USE_SKINNING\\n\\n\t\tvec4 worldPosition = modelMatrix * skinned;\\n\\n\t#elif defined( USE_MORPHTARGETS )\\n\\n\t\tvec4 worldPosition = modelMatrix * vec4( morphed, 1.0 );\\n\\n\t#else\\n\\n\t\tvec4 worldPosition = modelMatrix * vec4( position, 1.0 );\\n\\n\t#endif\\n\\n#endif\\n\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl\r\n\r\nTHREE.ShaderChunk[ 'shadowmap_pars_fragment'] = \"#ifdef USE_SHADOWMAP\\n\\n\tuniform sampler2D shadowMap[ MAX_SHADOWS ];\\n\tuniform vec2 shadowMapSize[ MAX_SHADOWS ];\\n\\n\tuniform float shadowDarkness[ MAX_SHADOWS ];\\n\tuniform float shadowBias[ MAX_SHADOWS ];\\n\\n\tvarying vec4 vShadowCoord[ MAX_SHADOWS ];\\n\\n\tfloat unpackDepth( const in vec4 rgba_depth ) {\\n\\n\t\tconst vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );\\n\t\tfloat depth = dot( rgba_depth, bit_shift );\\n\t\treturn depth;\\n\\n\t}\\n\\n#endif\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/skinning_pars_vertex.glsl\r\n\r\nTHREE.ShaderChunk[ 'skinning_pars_vertex'] = \"#ifdef USE_SKINNING\\n\\n\tuniform mat4 bindMatrix;\\n\tuniform mat4 bindMatrixInverse;\\n\\n\t#ifdef BONE_TEXTURE\\n\\n\t\tuniform sampler2D boneTexture;\\n\t\tuniform int boneTextureWidth;\\n\t\tuniform int boneTextureHeight;\\n\\n\t\tmat4 getBoneMatrix( const in float i ) {\\n\\n\t\t\tfloat j = i * 4.0;\\n\t\t\tfloat x = mod( j, float( boneTextureWidth ) );\\n\t\t\tfloat y = floor( j / float( boneTextureWidth ) );\\n\\n\t\t\tfloat dx = 1.0 / float( boneTextureWidth );\\n\t\t\tfloat dy = 1.0 / float( boneTextureHeight );\\n\\n\t\t\ty = dy * ( y + 0.5 );\\n\\n\t\t\tvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\\n\t\t\tvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\\n\t\t\tvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\\n\t\t\tvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\\n\\n\t\t\tmat4 bone = mat4( v1, v2, v3, v4 );\\n\\n\t\t\treturn bone;\\n\\n\t\t}\\n\\n\t#else\\n\\n\t\tuniform mat4 boneGlobalMatrices[ MAX_BONES ];\\n\\n\t\tmat4 getBoneMatrix( const in float i ) {\\n\\n\t\t\tmat4 bone = boneGlobalMatrices[ int(i) ];\\n\t\t\treturn bone;\\n\\n\t\t}\\n\\n\t#endif\\n\\n#endif\\n\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/logdepthbuf_pars_fragment.glsl\r\n\r\nTHREE.ShaderChunk[ 'logdepthbuf_pars_fragment'] = \"#ifdef USE_LOGDEPTHBUF\\n\\n\tuniform float logDepthBufFC;\\n\\n\t#ifdef USE_LOGDEPTHBUF_EXT\\n\\n\t\t#extension GL_EXT_frag_depth : enable\\n\t\tvarying float vFragDepth;\\n\\n\t#endif\\n\\n#endif\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/alphamap_fragment.glsl\r\n\r\nTHREE.ShaderChunk[ 'alphamap_fragment'] = \"#ifdef USE_ALPHAMAP\\n\\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\\n\\n#endif\\n\";\r\n\r\n// File:src/renderers/shaders/ShaderChunk/alphamap_pars_fragment.glsl\r\n\r\nTHREE.ShaderChunk[ 'alphamap_pars_fragment'] = \"#ifdef USE_ALPHAMAP\\n\\n\tuniform sampler2D alphaMap;\\n\\n#endif\\n\";\r\n\r\n// File:src/renderers/shaders/UniformsUtils.js\r\n\r\n/**\r\n * Uniform Utilities\r\n */\r\n\r\nTHREE.UniformsUtils = {\r\n\r\n\tmerge: function ( uniforms ) {\r\n\r\n\t\tvar merged = {};\r\n\r\n\t\tfor ( var u = 0; u < uniforms.length; u ++ ) {\r\n\r\n\t\t\tvar tmp = this.clone( uniforms[ u ] );\r\n\r\n\t\t\tfor ( var p in tmp ) {\r\n\r\n\t\t\t\tmerged[ p ] = tmp[ p ];\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\treturn merged;\r\n\r\n\t},\r\n\r\n\tclone: function ( uniforms_src ) {\r\n\r\n\t\tvar uniforms_dst = {};\r\n\r\n\t\tfor ( var u in uniforms_src ) {\r\n\r\n\t\t\tuniforms_dst[ u ] = {};\r\n\r\n\t\t\tfor ( var p in uniforms_src[ u ] ) {\r\n\r\n\t\t\t\tvar parameter_src = uniforms_src[ u ][ p ];\r\n\r\n\t\t\t\tif ( parameter_src instanceof THREE.Color ||\r\n\t\t\t\t\t parameter_src instanceof THREE.Vector2 ||\r\n\t\t\t\t\t parameter_src instanceof THREE.Vector3 ||\r\n\t\t\t\t\t parameter_src instanceof THREE.Vector4 ||\r\n\t\t\t\t\t parameter_src instanceof THREE.Matrix4 ||\r\n\t\t\t\t\t parameter_src instanceof THREE.Texture ) {\r\n\r\n\t\t\t\t\tuniforms_dst[ u ][ p ] = parameter_src.clone();\r\n\r\n\t\t\t\t} else if ( parameter_src instanceof Array ) {\r\n\r\n\t\t\t\t\tuniforms_dst[ u ][ p ] = parameter_src.slice();\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\tuniforms_dst[ u ][ p ] = parameter_src;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\treturn uniforms_dst;\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/renderers/shaders/UniformsLib.js\r\n\r\n/**\r\n * Uniforms library for shared webgl shaders\r\n */\r\n\r\nTHREE.UniformsLib = {\r\n\r\n\tcommon: {\r\n\r\n\t\t\"diffuse\" : { type: \"c\", value: new THREE.Color( 0xeeeeee ) },\r\n\t\t\"opacity\" : { type: \"f\", value: 1.0 },\r\n\r\n\t\t\"map\" : { type: \"t\", value: null },\r\n\t\t\"offsetRepeat\" : { type: \"v4\", value: new THREE.Vector4( 0, 0, 1, 1 ) },\r\n\r\n\t\t\"lightMap\" : { type: \"t\", value: null },\r\n\t\t\"specularMap\" : { type: \"t\", value: null },\r\n\t\t\"alphaMap\" : { type: \"t\", value: null },\r\n\r\n\t\t\"envMap\" : { type: \"t\", value: null },\r\n\t\t\"flipEnvMap\" : { type: \"f\", value: - 1 },\r\n\t\t\"reflectivity\" : { type: \"f\", value: 1.0 },\r\n\t\t\"refractionRatio\" : { type: \"f\", value: 0.98 },\r\n\r\n\t\t\"morphTargetInfluences\" : { type: \"f\", value: 0 }\r\n\r\n\t},\r\n\r\n\tbump: {\r\n\r\n\t\t\"bumpMap\" : { type: \"t\", value: null },\r\n\t\t\"bumpScale\" : { type: \"f\", value: 1 }\r\n\r\n\t},\r\n\r\n\tnormalmap: {\r\n\r\n\t\t\"normalMap\" : { type: \"t\", value: null },\r\n\t\t\"normalScale\" : { type: \"v2\", value: new THREE.Vector2( 1, 1 ) }\r\n\t},\r\n\r\n\tfog : {\r\n\r\n\t\t\"fogDensity\" : { type: \"f\", value: 0.00025 },\r\n\t\t\"fogNear\" : { type: \"f\", value: 1 },\r\n\t\t\"fogFar\" : { type: \"f\", value: 2000 },\r\n\t\t\"fogColor\" : { type: \"c\", value: new THREE.Color( 0xffffff ) }\r\n\r\n\t},\r\n\r\n\tlights: {\r\n\r\n\t\t\"ambientLightColor\" : { type: \"fv\", value: [] },\r\n\r\n\t\t\"directionalLightDirection\" : { type: \"fv\", value: [] },\r\n\t\t\"directionalLightColor\" : { type: \"fv\", value: [] },\r\n\r\n\t\t\"hemisphereLightDirection\" : { type: \"fv\", value: [] },\r\n\t\t\"hemisphereLightSkyColor\" : { type: \"fv\", value: [] },\r\n\t\t\"hemisphereLightGroundColor\" : { type: \"fv\", value: [] },\r\n\r\n\t\t\"pointLightColor\" : { type: \"fv\", value: [] },\r\n\t\t\"pointLightPosition\" : { type: \"fv\", value: [] },\r\n\t\t\"pointLightDistance\" : { type: \"fv1\", value: [] },\r\n\t\t\"pointLightDecay\" : { type: \"fv1\", value: [] },\r\n\r\n\t\t\"spotLightColor\" : { type: \"fv\", value: [] },\r\n\t\t\"spotLightPosition\" : { type: \"fv\", value: [] },\r\n\t\t\"spotLightDirection\" : { type: \"fv\", value: [] },\r\n\t\t\"spotLightDistance\" : { type: \"fv1\", value: [] },\r\n\t\t\"spotLightAngleCos\" : { type: \"fv1\", value: [] },\r\n\t\t\"spotLightExponent\" : { type: \"fv1\", value: [] },\r\n\t\t\"spotLightDecay\" : { type: \"fv1\", value: [] }\r\n\r\n\t},\r\n\r\n\tparticle: {\r\n\r\n\t\t\"psColor\" : { type: \"c\", value: new THREE.Color( 0xeeeeee ) },\r\n\t\t\"opacity\" : { type: \"f\", value: 1.0 },\r\n\t\t\"size\" : { type: \"f\", value: 1.0 },\r\n\t\t\"scale\" : { type: \"f\", value: 1.0 },\r\n\t\t\"map\" : { type: \"t\", value: null },\r\n\t\t\"offsetRepeat\" : { type: \"v4\", value: new THREE.Vector4( 0, 0, 1, 1 ) },\r\n\r\n\t\t\"fogDensity\" : { type: \"f\", value: 0.00025 },\r\n\t\t\"fogNear\" : { type: \"f\", value: 1 },\r\n\t\t\"fogFar\" : { type: \"f\", value: 2000 },\r\n\t\t\"fogColor\" : { type: \"c\", value: new THREE.Color( 0xffffff ) }\r\n\r\n\t},\r\n\r\n\tshadowmap: {\r\n\r\n\t\t\"shadowMap\": { type: \"tv\", value: [] },\r\n\t\t\"shadowMapSize\": { type: \"v2v\", value: [] },\r\n\r\n\t\t\"shadowBias\" : { type: \"fv1\", value: [] },\r\n\t\t\"shadowDarkness\": { type: \"fv1\", value: [] },\r\n\r\n\t\t\"shadowMatrix\" : { type: \"m4v\", value: [] }\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/renderers/shaders/ShaderLib.js\r\n\r\n/**\r\n * Webgl Shader Library for three.js\r\n *\r\n * @author alteredq / http://alteredqualia.com/\r\n * @author mrdoob / http://mrdoob.com/\r\n * @author mikael emtinger / http://gomo.se/\r\n */\r\n\r\n\r\nTHREE.ShaderLib = {\r\n\r\n\t'basic': {\r\n\r\n\t\tuniforms: THREE.UniformsUtils.merge( [\r\n\r\n\t\t\tTHREE.UniformsLib[ \"common\" ],\r\n\t\t\tTHREE.UniformsLib[ \"fog\" ],\r\n\t\t\tTHREE.UniformsLib[ \"shadowmap\" ]\r\n\r\n\t\t] ),\r\n\r\n\t\tvertexShader: [\r\n\r\n\t\t\tTHREE.ShaderChunk[ \"common\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"map_pars_vertex\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"lightmap_pars_vertex\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"envmap_pars_vertex\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"color_pars_vertex\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"morphtarget_pars_vertex\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"skinning_pars_vertex\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"shadowmap_pars_vertex\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_pars_vertex\" ],\r\n\r\n\t\t\t\"void main() {\",\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"map_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"lightmap_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"color_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"skinbase_vertex\" ],\r\n\r\n\t\t\t\"\t#ifdef USE_ENVMAP\",\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"morphnormal_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"skinnormal_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"defaultnormal_vertex\" ],\r\n\r\n\t\t\t\"\t#endif\",\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"morphtarget_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"skinning_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"default_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_vertex\" ],\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"worldpos_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"envmap_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"shadowmap_vertex\" ],\r\n\r\n\t\t\t\"}\"\r\n\r\n\t\t].join(\"\\n\"),\r\n\r\n\t\tfragmentShader: [\r\n\r\n\t\t\t\"uniform vec3 diffuse;\",\r\n\t\t\t\"uniform float opacity;\",\r\n\r\n\t\t\tTHREE.ShaderChunk[ \"common\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"color_pars_fragment\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"map_pars_fragment\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"alphamap_pars_fragment\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"lightmap_pars_fragment\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"envmap_pars_fragment\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"fog_pars_fragment\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"shadowmap_pars_fragment\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"specularmap_pars_fragment\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_pars_fragment\" ],\r\n\r\n\t\t\t\"void main() {\",\r\n\r\n\t\t\t\"\tvec3 outgoingLight = vec3( 0.0 );\",\t// outgoing light does not have an alpha, the surface does\r\n\t\t\t\"\tvec4 diffuseColor = vec4( diffuse, opacity );\",\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_fragment\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"map_fragment\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"color_fragment\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"alphamap_fragment\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"alphatest_fragment\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"specularmap_fragment\" ],\r\n\r\n\t\t\t\"\toutgoingLight = diffuseColor.rgb;\", // simple shader\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"lightmap_fragment\" ],\t\t// TODO: Light map on an otherwise unlit surface doesn't make sense.\r\n\t\t\t\tTHREE.ShaderChunk[ \"envmap_fragment\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"shadowmap_fragment\" ],\t\t// TODO: Shadows on an otherwise unlit surface doesn't make sense.\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"linear_to_gamma_fragment\" ],\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"fog_fragment\" ],\r\n\r\n\t\t\t\"\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\",\t// TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects\r\n\r\n\t\t\t\"}\"\r\n\r\n\t\t].join(\"\\n\")\r\n\r\n\t},\r\n\r\n\t'lambert': {\r\n\r\n\t\tuniforms: THREE.UniformsUtils.merge( [\r\n\r\n\t\t\tTHREE.UniformsLib[ \"common\" ],\r\n\t\t\tTHREE.UniformsLib[ \"fog\" ],\r\n\t\t\tTHREE.UniformsLib[ \"lights\" ],\r\n\t\t\tTHREE.UniformsLib[ \"shadowmap\" ],\r\n\r\n\t\t\t{\r\n\t\t\t\t\"emissive\" : { type: \"c\", value: new THREE.Color( 0x000000 ) },\r\n\t\t\t\t\"wrapRGB\" : { type: \"v3\", value: new THREE.Vector3( 1, 1, 1 ) }\r\n\t\t\t}\r\n\r\n\t\t] ),\r\n\r\n\t\tvertexShader: [\r\n\r\n\t\t\t\"#define LAMBERT\",\r\n\r\n\t\t\t\"varying vec3 vLightFront;\",\r\n\r\n\t\t\t\"#ifdef DOUBLE_SIDED\",\r\n\r\n\t\t\t\"\tvarying vec3 vLightBack;\",\r\n\r\n\t\t\t\"#endif\",\r\n\r\n\t\t\tTHREE.ShaderChunk[ \"common\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"map_pars_vertex\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"lightmap_pars_vertex\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"envmap_pars_vertex\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"lights_lambert_pars_vertex\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"color_pars_vertex\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"morphtarget_pars_vertex\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"skinning_pars_vertex\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"shadowmap_pars_vertex\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_pars_vertex\" ],\r\n\r\n\t\t\t\"void main() {\",\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"map_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"lightmap_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"color_vertex\" ],\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"morphnormal_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"skinbase_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"skinnormal_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"defaultnormal_vertex\" ],\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"morphtarget_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"skinning_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"default_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_vertex\" ],\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"worldpos_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"envmap_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"lights_lambert_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"shadowmap_vertex\" ],\r\n\r\n\t\t\t\"}\"\r\n\r\n\t\t].join(\"\\n\"),\r\n\r\n\t\tfragmentShader: [\r\n\r\n\t\t\t\"uniform vec3 diffuse;\",\r\n\t\t\t\"uniform vec3 emissive;\",\r\n\t\t\t\"uniform float opacity;\",\r\n\r\n\t\t\t\"varying vec3 vLightFront;\",\r\n\r\n\t\t\t\"#ifdef DOUBLE_SIDED\",\r\n\r\n\t\t\t\"\tvarying vec3 vLightBack;\",\r\n\r\n\t\t\t\"#endif\",\r\n\r\n\t\t\tTHREE.ShaderChunk[ \"common\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"color_pars_fragment\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"map_pars_fragment\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"alphamap_pars_fragment\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"lightmap_pars_fragment\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"envmap_pars_fragment\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"fog_pars_fragment\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"shadowmap_pars_fragment\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"specularmap_pars_fragment\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_pars_fragment\" ],\r\n\r\n\t\t\t\"void main() {\",\r\n\r\n\t\t\t\"\tvec3 outgoingLight = vec3( 0.0 );\",\t// outgoing light does not have an alpha, the surface does\r\n\t\t\t\"\tvec4 diffuseColor = vec4( diffuse, opacity );\",\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_fragment\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"map_fragment\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"color_fragment\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"alphamap_fragment\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"alphatest_fragment\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"specularmap_fragment\" ],\r\n\r\n\t\t\t\"\t#ifdef DOUBLE_SIDED\",\r\n\r\n\t\t\t\t\t//\"float isFront = float( gl_FrontFacing );\",\r\n\t\t\t\t\t//\"gl_FragColor.xyz *= isFront * vLightFront + ( 1.0 - isFront ) * vLightBack;\",\r\n\r\n\t\t\t\"\t\tif ( gl_FrontFacing )\",\r\n\t\t\t\"\t\t\toutgoingLight += diffuseColor.rgb * vLightFront + emissive;\",\r\n\t\t\t\"\t\telse\",\r\n\t\t\t\"\t\t\toutgoingLight += diffuseColor.rgb * vLightBack + emissive;\",\r\n\r\n\t\t\t\"\t#else\",\r\n\r\n\t\t\t\"\t\toutgoingLight += diffuseColor.rgb * vLightFront + emissive;\",\r\n\r\n\t\t\t\"\t#endif\",\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"lightmap_fragment\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"envmap_fragment\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"shadowmap_fragment\" ],\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"linear_to_gamma_fragment\" ],\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"fog_fragment\" ],\r\n\r\n\t\t\t\"\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\",\t// TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects\r\n\r\n\t\t\t\"}\"\r\n\r\n\t\t].join(\"\\n\")\r\n\r\n\t},\r\n\r\n\t'phong': {\r\n\r\n\t\tuniforms: THREE.UniformsUtils.merge( [\r\n\r\n\t\t\tTHREE.UniformsLib[ \"common\" ],\r\n\t\t\tTHREE.UniformsLib[ \"bump\" ],\r\n\t\t\tTHREE.UniformsLib[ \"normalmap\" ],\r\n\t\t\tTHREE.UniformsLib[ \"fog\" ],\r\n\t\t\tTHREE.UniformsLib[ \"lights\" ],\r\n\t\t\tTHREE.UniformsLib[ \"shadowmap\" ],\r\n\r\n\t\t\t{\r\n\t\t\t\t\"emissive\" : { type: \"c\", value: new THREE.Color( 0x000000 ) },\r\n\t\t\t\t\"specular\" : { type: \"c\", value: new THREE.Color( 0x111111 ) },\r\n\t\t\t\t\"shininess\": { type: \"f\", value: 30 },\r\n\t\t\t\t\"wrapRGB\" : { type: \"v3\", value: new THREE.Vector3( 1, 1, 1 ) }\r\n\t\t\t}\r\n\r\n\t\t] ),\r\n\r\n\t\tvertexShader: [\r\n\r\n\t\t\t\"#define PHONG\",\r\n\r\n\t\t\t\"varying vec3 vViewPosition;\",\r\n\r\n\t\t\t\"#ifndef FLAT_SHADED\",\r\n\r\n\t\t\t\"\tvarying vec3 vNormal;\",\r\n\r\n\t\t\t\"#endif\",\r\n\r\n\t\t\tTHREE.ShaderChunk[ \"common\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"map_pars_vertex\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"lightmap_pars_vertex\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"envmap_pars_vertex\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"lights_phong_pars_vertex\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"color_pars_vertex\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"morphtarget_pars_vertex\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"skinning_pars_vertex\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"shadowmap_pars_vertex\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_pars_vertex\" ],\r\n\r\n\t\t\t\"void main() {\",\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"map_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"lightmap_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"color_vertex\" ],\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"morphnormal_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"skinbase_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"skinnormal_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"defaultnormal_vertex\" ],\r\n\r\n\t\t\t\"#ifndef FLAT_SHADED\", // Normal computed with derivatives when FLAT_SHADED\r\n\r\n\t\t\t\"\tvNormal = normalize( transformedNormal );\",\r\n\r\n\t\t\t\"#endif\",\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"morphtarget_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"skinning_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"default_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_vertex\" ],\r\n\r\n\t\t\t\"\tvViewPosition = -mvPosition.xyz;\",\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"worldpos_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"envmap_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"lights_phong_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"shadowmap_vertex\" ],\r\n\r\n\t\t\t\"}\"\r\n\r\n\t\t].join(\"\\n\"),\r\n\r\n\t\tfragmentShader: [\r\n\r\n\t\t\t\"#define PHONG\",\r\n\r\n\t\t\t\"uniform vec3 diffuse;\",\r\n\t\t\t\"uniform vec3 emissive;\",\r\n\t\t\t\"uniform vec3 specular;\",\r\n\t\t\t\"uniform float shininess;\",\r\n\t\t\t\"uniform float opacity;\",\r\n\r\n\t\t\tTHREE.ShaderChunk[ \"common\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"color_pars_fragment\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"map_pars_fragment\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"alphamap_pars_fragment\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"lightmap_pars_fragment\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"envmap_pars_fragment\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"fog_pars_fragment\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"lights_phong_pars_fragment\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"shadowmap_pars_fragment\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"bumpmap_pars_fragment\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"normalmap_pars_fragment\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"specularmap_pars_fragment\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_pars_fragment\" ],\r\n\r\n\t\t\t\"void main() {\",\r\n\r\n\t\t\t\"\tvec3 outgoingLight = vec3( 0.0 );\",\t// outgoing light does not have an alpha, the surface does\r\n\t\t\t\"\tvec4 diffuseColor = vec4( diffuse, opacity );\",\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_fragment\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"map_fragment\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"color_fragment\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"alphamap_fragment\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"alphatest_fragment\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"specularmap_fragment\" ],\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"lights_phong_fragment\" ],\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"lightmap_fragment\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"envmap_fragment\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"shadowmap_fragment\" ],\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"linear_to_gamma_fragment\" ],\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"fog_fragment\" ],\r\n\r\n\t\t\t\"\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\",\t// TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects\r\n\r\n\t\t\t\"}\"\r\n\r\n\t\t].join(\"\\n\")\r\n\r\n\t},\r\n\r\n\t'particle_basic': {\r\n\r\n\t\tuniforms: THREE.UniformsUtils.merge( [\r\n\r\n\t\t\tTHREE.UniformsLib[ \"particle\" ],\r\n\t\t\tTHREE.UniformsLib[ \"shadowmap\" ]\r\n\r\n\t\t] ),\r\n\r\n\t\tvertexShader: [\r\n\r\n\t\t\t\"uniform float size;\",\r\n\t\t\t\"uniform float scale;\",\r\n\r\n\t\t\tTHREE.ShaderChunk[ \"common\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"color_pars_vertex\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"shadowmap_pars_vertex\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_pars_vertex\" ],\r\n\r\n\t\t\t\"void main() {\",\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"color_vertex\" ],\r\n\r\n\t\t\t\"\tvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\",\r\n\r\n\t\t\t\"\t#ifdef USE_SIZEATTENUATION\",\r\n\t\t\t\"\t\tgl_PointSize = size * ( scale / length( mvPosition.xyz ) );\",\r\n\t\t\t\"\t#else\",\r\n\t\t\t\"\t\tgl_PointSize = size;\",\r\n\t\t\t\"\t#endif\",\r\n\r\n\t\t\t\"\tgl_Position = projectionMatrix * mvPosition;\",\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"worldpos_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"shadowmap_vertex\" ],\r\n\r\n\t\t\t\"}\"\r\n\r\n\t\t].join(\"\\n\"),\r\n\r\n\t\tfragmentShader: [\r\n\r\n\t\t\t\"uniform vec3 psColor;\",\r\n\t\t\t\"uniform float opacity;\",\r\n\r\n\t\t\tTHREE.ShaderChunk[ \"common\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"color_pars_fragment\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"map_particle_pars_fragment\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"fog_pars_fragment\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"shadowmap_pars_fragment\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_pars_fragment\" ],\r\n\r\n\t\t\t\"void main() {\",\r\n\r\n\t\t\t\"\tvec3 outgoingLight = vec3( 0.0 );\",\t// outgoing light does not have an alpha, the surface does\r\n\t\t\t\"\tvec4 diffuseColor = vec4( psColor, opacity );\",\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_fragment\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"map_particle_fragment\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"color_fragment\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"alphatest_fragment\" ],\r\n\r\n\t\t\t\"\toutgoingLight = diffuseColor.rgb;\", // simple shader\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"shadowmap_fragment\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"fog_fragment\" ],\r\n\r\n\t\t\t\"\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\",\t// TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects\r\n\r\n\t\t\t\"}\"\r\n\r\n\t\t].join(\"\\n\")\r\n\r\n\t},\r\n\r\n\t'dashed': {\r\n\r\n\t\tuniforms: THREE.UniformsUtils.merge( [\r\n\r\n\t\t\tTHREE.UniformsLib[ \"common\" ],\r\n\t\t\tTHREE.UniformsLib[ \"fog\" ],\r\n\r\n\t\t\t{\r\n\t\t\t\t\"scale\" : { type: \"f\", value: 1 },\r\n\t\t\t\t\"dashSize\" : { type: \"f\", value: 1 },\r\n\t\t\t\t\"totalSize\": { type: \"f\", value: 2 }\r\n\t\t\t}\r\n\r\n\t\t] ),\r\n\r\n\t\tvertexShader: [\r\n\r\n\t\t\t\"uniform float scale;\",\r\n\t\t\t\"attribute float lineDistance;\",\r\n\r\n\t\t\t\"varying float vLineDistance;\",\r\n\r\n\t\t\tTHREE.ShaderChunk[ \"common\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"color_pars_vertex\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_pars_vertex\" ],\r\n\r\n\t\t\t\"void main() {\",\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"color_vertex\" ],\r\n\r\n\t\t\t\"\tvLineDistance = scale * lineDistance;\",\r\n\r\n\t\t\t\"\tvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\",\r\n\t\t\t\"\tgl_Position = projectionMatrix * mvPosition;\",\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_vertex\" ],\r\n\r\n\t\t\t\"}\"\r\n\r\n\t\t].join(\"\\n\"),\r\n\r\n\t\tfragmentShader: [\r\n\r\n\t\t\t\"uniform vec3 diffuse;\",\r\n\t\t\t\"uniform float opacity;\",\r\n\r\n\t\t\t\"uniform float dashSize;\",\r\n\t\t\t\"uniform float totalSize;\",\r\n\r\n\t\t\t\"varying float vLineDistance;\",\r\n\r\n\t\t\tTHREE.ShaderChunk[ \"common\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"color_pars_fragment\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"fog_pars_fragment\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_pars_fragment\" ],\r\n\r\n\t\t\t\"void main() {\",\r\n\r\n\t\t\t\"\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\",\r\n\r\n\t\t\t\"\t\tdiscard;\",\r\n\r\n\t\t\t\"\t}\",\r\n\r\n\t\t\t\"\tvec3 outgoingLight = vec3( 0.0 );\",\t// outgoing light does not have an alpha, the surface does\r\n\t\t\t\"\tvec4 diffuseColor = vec4( diffuse, opacity );\",\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_fragment\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"color_fragment\" ],\r\n\r\n\t\t\t\"\toutgoingLight = diffuseColor.rgb;\", // simple shader\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"fog_fragment\" ],\r\n\r\n\t\t\t\"\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\",\t// TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects\r\n\r\n\t\t\t\"}\"\r\n\r\n\t\t].join(\"\\n\")\r\n\r\n\t},\r\n\r\n\t'depth': {\r\n\r\n\t\tuniforms: {\r\n\r\n\t\t\t\"mNear\": { type: \"f\", value: 1.0 },\r\n\t\t\t\"mFar\" : { type: \"f\", value: 2000.0 },\r\n\t\t\t\"opacity\" : { type: \"f\", value: 1.0 }\r\n\r\n\t\t},\r\n\r\n\t\tvertexShader: [\r\n\r\n\t\t\tTHREE.ShaderChunk[ \"common\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"morphtarget_pars_vertex\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_pars_vertex\" ],\r\n\r\n\t\t\t\"void main() {\",\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"morphtarget_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"default_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_vertex\" ],\r\n\r\n\t\t\t\"}\"\r\n\r\n\t\t].join(\"\\n\"),\r\n\r\n\t\tfragmentShader: [\r\n\r\n\t\t\t\"uniform float mNear;\",\r\n\t\t\t\"uniform float mFar;\",\r\n\t\t\t\"uniform float opacity;\",\r\n\r\n\t\t\tTHREE.ShaderChunk[ \"common\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_pars_fragment\" ],\r\n\r\n\t\t\t\"void main() {\",\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_fragment\" ],\r\n\r\n\t\t\t\"\t#ifdef USE_LOGDEPTHBUF_EXT\",\r\n\r\n\t\t\t\"\t\tfloat depth = gl_FragDepthEXT / gl_FragCoord.w;\",\r\n\r\n\t\t\t\"\t#else\",\r\n\r\n\t\t\t\"\t\tfloat depth = gl_FragCoord.z / gl_FragCoord.w;\",\r\n\r\n\t\t\t\"\t#endif\",\r\n\r\n\t\t\t\"\tfloat color = 1.0 - smoothstep( mNear, mFar, depth );\",\r\n\t\t\t\"\tgl_FragColor = vec4( vec3( color ), opacity );\", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects\r\n\r\n\t\t\t\"}\"\r\n\r\n\t\t].join(\"\\n\")\r\n\r\n\t},\r\n\r\n\t'normal': {\r\n\r\n\t\tuniforms: {\r\n\r\n\t\t\t\"opacity\" : { type: \"f\", value: 1.0 }\r\n\r\n\t\t},\r\n\r\n\t\tvertexShader: [\r\n\r\n\t\t\t\"varying vec3 vNormal;\",\r\n\r\n\t\t\tTHREE.ShaderChunk[ \"common\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"morphtarget_pars_vertex\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_pars_vertex\" ],\r\n\r\n\t\t\t\"void main() {\",\r\n\r\n\t\t\t\"\tvNormal = normalize( normalMatrix * normal );\",\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"morphtarget_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"default_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_vertex\" ],\r\n\r\n\t\t\t\"}\"\r\n\r\n\t\t].join(\"\\n\"),\r\n\r\n\t\tfragmentShader: [\r\n\r\n\t\t\t\"uniform float opacity;\",\r\n\t\t\t\"varying vec3 vNormal;\",\r\n\r\n\t\t\tTHREE.ShaderChunk[ \"common\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_pars_fragment\" ],\r\n\r\n\t\t\t\"void main() {\",\r\n\r\n\t\t\t\"\tgl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, opacity );\",\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_fragment\" ],\r\n\r\n\t\t\t\"}\"\r\n\r\n\t\t].join(\"\\n\")\r\n\r\n\t},\r\n\r\n\t/* -------------------------------------------------------------------------\r\n\t//\tCube map shader\r\n\t ------------------------------------------------------------------------- */\r\n\r\n\t'cube': {\r\n\r\n\t\tuniforms: { \"tCube\": { type: \"t\", value: null },\r\n\t\t\t\t\t\"tFlip\": { type: \"f\", value: - 1 } },\r\n\r\n\t\tvertexShader: [\r\n\r\n\t\t\t\"varying vec3 vWorldPosition;\",\r\n\r\n\t\t\tTHREE.ShaderChunk[ \"common\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_pars_vertex\" ],\r\n\r\n\t\t\t\"void main() {\",\r\n\r\n\t\t\t\"\tvWorldPosition = transformDirection( position, modelMatrix );\",\r\n\r\n\t\t\t\"\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\",\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_vertex\" ],\r\n\r\n\t\t\t\"}\"\r\n\r\n\t\t].join(\"\\n\"),\r\n\r\n\t\tfragmentShader: [\r\n\r\n\t\t\t\"uniform samplerCube tCube;\",\r\n\t\t\t\"uniform float tFlip;\",\r\n\r\n\t\t\t\"varying vec3 vWorldPosition;\",\r\n\r\n\t\t\tTHREE.ShaderChunk[ \"common\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_pars_fragment\" ],\r\n\r\n\t\t\t\"void main() {\",\r\n\r\n\t\t\t\"\tgl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );\",\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_fragment\" ],\r\n\r\n\t\t\t\"}\"\r\n\r\n\t\t].join(\"\\n\")\r\n\r\n\t},\r\n\r\n\t/* -------------------------------------------------------------------------\r\n\t//\tCube map shader\r\n\t ------------------------------------------------------------------------- */\r\n\r\n\t'equirect': {\r\n\r\n\t\tuniforms: { \"tEquirect\": { type: \"t\", value: null },\r\n\t\t\t\t\t\"tFlip\": { type: \"f\", value: - 1 } },\r\n\r\n\t\tvertexShader: [\r\n\r\n\t\t\t\"varying vec3 vWorldPosition;\",\r\n\r\n\t\t\tTHREE.ShaderChunk[ \"common\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_pars_vertex\" ],\r\n\r\n\t\t\t\"void main() {\",\r\n\r\n\t\t\t\"\tvWorldPosition = transformDirection( position, modelMatrix );\",\r\n\r\n\t\t\t\"\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\",\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_vertex\" ],\r\n\r\n\t\t\t\"}\"\r\n\r\n\t\t].join(\"\\n\"),\r\n\r\n\t\tfragmentShader: [\r\n\r\n\t\t\t\"uniform sampler2D tEquirect;\",\r\n\t\t\t\"uniform float tFlip;\",\r\n\r\n\t\t\t\"varying vec3 vWorldPosition;\",\r\n\r\n\t\t\tTHREE.ShaderChunk[ \"common\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_pars_fragment\" ],\r\n\r\n\t\t\t\"void main() {\",\r\n\r\n\t\t\t\t// \"\tgl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );\",\r\n\t\t\t\t\"vec3 direction = normalize( vWorldPosition );\",\r\n\t\t\t\t\"vec2 sampleUV;\",\r\n\t\t\t\t\"sampleUV.y = saturate( tFlip * direction.y * -0.5 + 0.5 );\",\r\n\t\t\t\t\"sampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;\",\r\n\t\t\t\t\"gl_FragColor = texture2D( tEquirect, sampleUV );\",\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_fragment\" ],\r\n\r\n\t\t\t\"}\"\r\n\r\n\t\t].join(\"\\n\")\r\n\r\n\t},\r\n\r\n\t/* Depth encoding into RGBA texture\r\n\t *\r\n\t * based on SpiderGL shadow map example\r\n\t * http://spidergl.org/example.php?id=6\r\n\t *\r\n\t * originally from\r\n\t * http://www.gamedev.net/topic/442138-packing-a-float-into-a-a8r8g8b8-texture-shader/page__whichpage__1%25EF%25BF%25BD\r\n\t *\r\n\t * see also\r\n\t * http://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/\r\n\t */\r\n\r\n\t'depthRGBA': {\r\n\r\n\t\tuniforms: {},\r\n\r\n\t\tvertexShader: [\r\n\r\n\t\t\tTHREE.ShaderChunk[ \"common\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"morphtarget_pars_vertex\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"skinning_pars_vertex\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_pars_vertex\" ],\r\n\r\n\t\t\t\"void main() {\",\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"skinbase_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"morphtarget_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"skinning_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"default_vertex\" ],\r\n\t\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_vertex\" ],\r\n\r\n\t\t\t\"}\"\r\n\r\n\t\t].join(\"\\n\"),\r\n\r\n\t\tfragmentShader: [\r\n\r\n\t\t\tTHREE.ShaderChunk[ \"common\" ],\r\n\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_pars_fragment\" ],\r\n\r\n\t\t\t\"vec4 pack_depth( const in float depth ) {\",\r\n\r\n\t\t\t\"\tconst vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );\",\r\n\t\t\t\"\tconst vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );\",\r\n\t\t\t\"\tvec4 res = mod( depth * bit_shift * vec4( 255 ), vec4( 256 ) ) / vec4( 255 );\", // \"\tvec4 res = fract( depth * bit_shift );\",\r\n\t\t\t\"\tres -= res.xxyz * bit_mask;\",\r\n\t\t\t\"\treturn res;\",\r\n\r\n\t\t\t\"}\",\r\n\r\n\t\t\t\"void main() {\",\r\n\r\n\t\t\t\tTHREE.ShaderChunk[ \"logdepthbuf_fragment\" ],\r\n\r\n\t\t\t\"\t#ifdef USE_LOGDEPTHBUF_EXT\",\r\n\r\n\t\t\t\"\t\tgl_FragData[ 0 ] = pack_depth( gl_FragDepthEXT );\",\r\n\r\n\t\t\t\"\t#else\",\r\n\r\n\t\t\t\"\t\tgl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );\",\r\n\r\n\t\t\t\"\t#endif\",\r\n\r\n\t\t\t\t//\"gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z / gl_FragCoord.w );\",\r\n\t\t\t\t//\"float z = ( ( gl_FragCoord.z / gl_FragCoord.w ) - 3.0 ) / ( 4000.0 - 3.0 );\",\r\n\t\t\t\t//\"gl_FragData[ 0 ] = pack_depth( z );\",\r\n\t\t\t\t//\"gl_FragData[ 0 ] = vec4( z, z, z, 1.0 );\",\r\n\r\n\t\t\t\"}\"\r\n\r\n\t\t].join(\"\\n\")\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/renderers/WebGLRenderer.js\r\n\r\n/**\r\n * @author supereggbert / http://www.paulbrunt.co.uk/\r\n * @author mrdoob / http://mrdoob.com/\r\n * @author alteredq / http://alteredqualia.com/\r\n * @author szimek / https://github.com/szimek/\r\n */\r\n\r\nTHREE.WebGLRenderer = function ( parameters ) {\r\n\r\n\tconsole.log( 'THREE.WebGLRenderer', THREE.REVISION );\r\n\r\n\tparameters = parameters || {};\r\n\r\n\tvar _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElement( 'canvas' ),\r\n\t_context = parameters.context !== undefined ? parameters.context : null,\r\n\r\n\tpixelRatio = 1,\r\n\r\n\t_precision = parameters.precision !== undefined ? parameters.precision : 'highp',\r\n\r\n\t_alpha = parameters.alpha !== undefined ? parameters.alpha : false,\r\n\t_depth = parameters.depth !== undefined ? parameters.depth : true,\r\n\t_stencil = parameters.stencil !== undefined ? parameters.stencil : true,\r\n\t_antialias = parameters.antialias !== undefined ? parameters.antialias : false,\r\n\t_premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true,\r\n\t_preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false,\r\n\t_logarithmicDepthBuffer = parameters.logarithmicDepthBuffer !== undefined ? parameters.logarithmicDepthBuffer : false,\r\n\r\n\t_clearColor = new THREE.Color( 0x000000 ),\r\n\t_clearAlpha = 0;\r\n\r\n\tvar lights = [];\r\n\r\n\tvar _webglObjects = {};\r\n\tvar _webglObjectsImmediate = [];\r\n\r\n\tvar opaqueObjects = [];\r\n\tvar transparentObjects = [];\r\n\r\n\tvar sprites = [];\r\n\tvar lensFlares = [];\r\n\r\n\t// public properties\r\n\r\n\tthis.domElement = _canvas;\r\n\tthis.context = null;\r\n\r\n\t// clearing\r\n\r\n\tthis.autoClear = true;\r\n\tthis.autoClearColor = true;\r\n\tthis.autoClearDepth = true;\r\n\tthis.autoClearStencil = true;\r\n\r\n\t// scene graph\r\n\r\n\tthis.sortObjects = true;\r\n\r\n\t// physically based shading\r\n\r\n\tthis.gammaFactor = 2.0;\t// for backwards compatibility\r\n\tthis.gammaInput = false;\r\n\tthis.gammaOutput = false;\r\n\r\n\t// shadow map\r\n\r\n\tthis.shadowMapEnabled = false;\r\n\tthis.shadowMapType = THREE.PCFShadowMap;\r\n\tthis.shadowMapCullFace = THREE.CullFaceFront;\r\n\tthis.shadowMapDebug = false;\r\n\tthis.shadowMapCascade = false;\r\n\r\n\t// morphs\r\n\r\n\tthis.maxMorphTargets = 8;\r\n\tthis.maxMorphNormals = 4;\r\n\r\n\t// flags\r\n\r\n\tthis.autoScaleCubemaps = true;\r\n\r\n\t// info\r\n\r\n\tthis.info = {\r\n\r\n\t\tmemory: {\r\n\r\n\t\t\tprograms: 0,\r\n\t\t\tgeometries: 0,\r\n\t\t\ttextures: 0\r\n\r\n\t\t},\r\n\r\n\t\trender: {\r\n\r\n\t\t\tcalls: 0,\r\n\t\t\tvertices: 0,\r\n\t\t\tfaces: 0,\r\n\t\t\tpoints: 0\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n\t// internal properties\r\n\r\n\tvar _this = this,\r\n\r\n\t_programs = [],\r\n\r\n\t// internal state cache\r\n\r\n\t_currentProgram = null,\r\n\t_currentFramebuffer = null,\r\n\t_currentMaterialId = - 1,\r\n\t_currentGeometryProgram = '',\r\n\t_currentCamera = null,\r\n\r\n\t_usedTextureUnits = 0,\r\n\r\n\t_viewportX = 0,\r\n\t_viewportY = 0,\r\n\t_viewportWidth = _canvas.width,\r\n\t_viewportHeight = _canvas.height,\r\n\t_currentWidth = 0,\r\n\t_currentHeight = 0,\r\n\r\n\t// frustum\r\n\r\n\t_frustum = new THREE.Frustum(),\r\n\r\n\t // camera matrices cache\r\n\r\n\t_projScreenMatrix = new THREE.Matrix4(),\r\n\r\n\t_vector3 = new THREE.Vector3(),\r\n\r\n\t// light arrays cache\r\n\r\n\t_direction = new THREE.Vector3(),\r\n\r\n\t_lightsNeedUpdate = true,\r\n\r\n\t_lights = {\r\n\r\n\t\tambient: [ 0, 0, 0 ],\r\n\t\tdirectional: { length: 0, colors:[], positions: [] },\r\n\t\tpoint: { length: 0, colors: [], positions: [], distances: [], decays: [] },\r\n\t\tspot: { length: 0, colors: [], positions: [], distances: [], directions: [], anglesCos: [], exponents: [], decays: [] },\r\n\t\themi: { length: 0, skyColors: [], groundColors: [], positions: [] }\r\n\r\n\t};\r\n\r\n\t// initialize\r\n\r\n\tvar _gl;\r\n\r\n\ttry {\r\n\r\n\t\tvar attributes = {\r\n\t\t\talpha: _alpha,\r\n\t\t\tdepth: _depth,\r\n\t\t\tstencil: _stencil,\r\n\t\t\tantialias: _antialias,\r\n\t\t\tpremultipliedAlpha: _premultipliedAlpha,\r\n\t\t\tpreserveDrawingBuffer: _preserveDrawingBuffer\r\n\t\t};\r\n\r\n\t\t_gl = _context || _canvas.getContext( 'webgl', attributes ) || _canvas.getContext( 'experimental-webgl', attributes );\r\n\r\n\t\tif ( _gl === null ) {\r\n\r\n\t\t\tif ( _canvas.getContext( 'webgl') !== null ) {\r\n\r\n\t\t\t\tthrow 'Error creating WebGL context with your selected attributes.';\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tthrow 'Error creating WebGL context.';\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\t_canvas.addEventListener( 'webglcontextlost', function ( event ) {\r\n\r\n\t\t\tevent.preventDefault();\r\n\r\n\t\t\tresetGLState();\r\n\t\t\tsetDefaultGLState();\r\n\r\n\t\t\t_webglObjects = {};\r\n\r\n\t\t}, false);\r\n\r\n\t} catch ( error ) {\r\n\r\n\t\tTHREE.error( 'THREE.WebGLRenderer: ' + error );\r\n\r\n\t}\r\n\r\n\tvar state = new THREE.WebGLState( _gl, paramThreeToGL );\r\n\r\n\tif ( _gl.getShaderPrecisionFormat === undefined ) {\r\n\r\n\t\t_gl.getShaderPrecisionFormat = function () {\r\n\r\n\t\t\treturn {\r\n\t\t\t\t'rangeMin': 1,\r\n\t\t\t\t'rangeMax': 1,\r\n\t\t\t\t'precision': 1\r\n\t\t\t};\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tvar extensions = new THREE.WebGLExtensions( _gl );\r\n\r\n\textensions.get( 'OES_texture_float' );\r\n\textensions.get( 'OES_texture_float_linear' );\r\n\textensions.get( 'OES_texture_half_float' );\r\n\textensions.get( 'OES_texture_half_float_linear' );\r\n\textensions.get( 'OES_standard_derivatives' );\r\n\r\n\tif ( _logarithmicDepthBuffer ) {\r\n\r\n\t\textensions.get( 'EXT_frag_depth' );\r\n\r\n\t}\r\n\r\n\t//\r\n\r\n\tvar glClearColor = function ( r, g, b, a ) {\r\n\r\n\t\tif ( _premultipliedAlpha === true ) {\r\n\r\n\t\t\tr *= a; g *= a; b *= a;\r\n\r\n\t\t}\r\n\r\n\t\t_gl.clearColor( r, g, b, a );\r\n\r\n\t};\r\n\r\n\tvar setDefaultGLState = function () {\r\n\r\n\t\t_gl.clearColor( 0, 0, 0, 1 );\r\n\t\t_gl.clearDepth( 1 );\r\n\t\t_gl.clearStencil( 0 );\r\n\r\n\t\t_gl.enable( _gl.DEPTH_TEST );\r\n\t\t_gl.depthFunc( _gl.LEQUAL );\r\n\r\n\t\t_gl.frontFace( _gl.CCW );\r\n\t\t_gl.cullFace( _gl.BACK );\r\n\t\t_gl.enable( _gl.CULL_FACE );\r\n\r\n\t\t_gl.enable( _gl.BLEND );\r\n\t\t_gl.blendEquation( _gl.FUNC_ADD );\r\n\t\t_gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA );\r\n\r\n\t\t_gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight );\r\n\r\n\t\tglClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );\r\n\r\n\t};\r\n\r\n\tvar resetGLState = function () {\r\n\r\n\t\t_currentProgram = null;\r\n\t\t_currentCamera = null;\r\n\r\n\t\t_currentGeometryProgram = '';\r\n\t\t_currentMaterialId = - 1;\r\n\r\n\t\t_lightsNeedUpdate = true;\r\n\r\n\t\tstate.reset();\r\n\r\n\t};\r\n\r\n\tsetDefaultGLState();\r\n\r\n\tthis.context = _gl;\r\n\tthis.state = state;\r\n\r\n\t// GPU capabilities\r\n\r\n\tvar _maxTextures = _gl.getParameter( _gl.MAX_TEXTURE_IMAGE_UNITS );\r\n\tvar _maxVertexTextures = _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS );\r\n\tvar _maxTextureSize = _gl.getParameter( _gl.MAX_TEXTURE_SIZE );\r\n\tvar _maxCubemapSize = _gl.getParameter( _gl.MAX_CUBE_MAP_TEXTURE_SIZE );\r\n\r\n\tvar _supportsVertexTextures = _maxVertexTextures > 0;\r\n\tvar _supportsBoneTextures = _supportsVertexTextures && extensions.get( 'OES_texture_float' );\r\n\r\n\t//\r\n\r\n\tvar _vertexShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.HIGH_FLOAT );\r\n\tvar _vertexShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.MEDIUM_FLOAT );\r\n\r\n\tvar _fragmentShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.HIGH_FLOAT );\r\n\tvar _fragmentShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.MEDIUM_FLOAT );\r\n\r\n\tvar getCompressedTextureFormats = ( function () {\r\n\r\n\t\tvar array;\r\n\r\n\t\treturn function () {\r\n\r\n\t\t\tif ( array !== undefined ) {\r\n\r\n\t\t\t\treturn array;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tarray = [];\r\n\r\n\t\t\tif ( extensions.get( 'WEBGL_compressed_texture_pvrtc' ) || extensions.get( 'WEBGL_compressed_texture_s3tc' ) ) {\r\n\r\n\t\t\t\tvar formats = _gl.getParameter( _gl.COMPRESSED_TEXTURE_FORMATS );\r\n\r\n\t\t\t\tfor ( var i = 0; i < formats.length; i ++ ) {\r\n\r\n\t\t\t\t\tarray.push( formats[ i ] );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\treturn array;\r\n\r\n\t\t};\r\n\r\n\t} )();\r\n\r\n\t// clamp precision to maximum available\r\n\r\n\tvar highpAvailable = _vertexShaderPrecisionHighpFloat.precision > 0 && _fragmentShaderPrecisionHighpFloat.precision > 0;\r\n\tvar mediumpAvailable = _vertexShaderPrecisionMediumpFloat.precision > 0 && _fragmentShaderPrecisionMediumpFloat.precision > 0;\r\n\r\n\tif ( _precision === 'highp' && ! highpAvailable ) {\r\n\r\n\t\tif ( mediumpAvailable ) {\r\n\r\n\t\t\t_precision = 'mediump';\r\n\t\t\tTHREE.warn( 'THREE.WebGLRenderer: highp not supported, using mediump.' );\r\n\r\n\t\t} else {\r\n\r\n\t\t\t_precision = 'lowp';\r\n\t\t\tTHREE.warn( 'THREE.WebGLRenderer: highp and mediump not supported, using lowp.' );\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tif ( _precision === 'mediump' && ! mediumpAvailable ) {\r\n\r\n\t\t_precision = 'lowp';\r\n\t\tTHREE.warn( 'THREE.WebGLRenderer: mediump not supported, using lowp.' );\r\n\r\n\t}\r\n\r\n\t// Plugins\r\n\r\n\tvar shadowMapPlugin = new THREE.ShadowMapPlugin( this, lights, _webglObjects, _webglObjectsImmediate );\r\n\r\n\tvar spritePlugin = new THREE.SpritePlugin( this, sprites );\r\n\tvar lensFlarePlugin = new THREE.LensFlarePlugin( this, lensFlares );\r\n\r\n\t// API\r\n\r\n\tthis.getContext = function () {\r\n\r\n\t\treturn _gl;\r\n\r\n\t};\r\n\r\n\tthis.forceContextLoss = function () {\r\n\r\n\t\textensions.get( 'WEBGL_lose_context' ).loseContext();\r\n\r\n\t};\r\n\r\n\tthis.supportsVertexTextures = function () {\r\n\r\n\t\treturn _supportsVertexTextures;\r\n\r\n\t};\r\n\r\n\tthis.supportsFloatTextures = function () {\r\n\r\n\t\treturn extensions.get( 'OES_texture_float' );\r\n\r\n\t};\r\n\r\n\tthis.supportsHalfFloatTextures = function () {\r\n\r\n\t\treturn extensions.get( 'OES_texture_half_float' );\r\n\r\n\t};\r\n\r\n\tthis.supportsStandardDerivatives = function () {\r\n\r\n\t\treturn extensions.get( 'OES_standard_derivatives' );\r\n\r\n\t};\r\n\r\n\tthis.supportsCompressedTextureS3TC = function () {\r\n\r\n\t\treturn extensions.get( 'WEBGL_compressed_texture_s3tc' );\r\n\r\n\t};\r\n\r\n\tthis.supportsCompressedTexturePVRTC = function () {\r\n\r\n\t\treturn extensions.get( 'WEBGL_compressed_texture_pvrtc' );\r\n\r\n\t};\r\n\r\n\tthis.supportsBlendMinMax = function () {\r\n\r\n\t\treturn extensions.get( 'EXT_blend_minmax' );\r\n\r\n\t};\r\n\r\n\tthis.getMaxAnisotropy = ( function () {\r\n\r\n\t\tvar value;\r\n\r\n\t\treturn function () {\r\n\r\n\t\t\tif ( value !== undefined ) {\r\n\r\n\t\t\t\treturn value;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tvar extension = extensions.get( 'EXT_texture_filter_anisotropic' );\r\n\r\n\t\t\tvalue = extension !== null ? _gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT ) : 0;\r\n\r\n\t\t\treturn value;\r\n\r\n\t\t}\r\n\r\n\t} )();\r\n\r\n\tthis.getPrecision = function () {\r\n\r\n\t\treturn _precision;\r\n\r\n\t};\r\n\r\n\tthis.getPixelRatio = function () {\r\n\r\n\t\treturn pixelRatio;\r\n\r\n\t};\r\n\r\n\tthis.setPixelRatio = function ( value ) {\r\n\r\n\t\tpixelRatio = value;\r\n\r\n\t};\r\n\r\n\tthis.setSize = function ( width, height, updateStyle ) {\r\n\r\n\t\t_canvas.width = width * pixelRatio;\r\n\t\t_canvas.height = height * pixelRatio;\r\n\r\n\t\tif ( updateStyle !== false ) {\r\n\r\n\t\t\t_canvas.style.width = width + 'px';\r\n\t\t\t_canvas.style.height = height + 'px';\r\n\r\n\t\t}\r\n\r\n\t\tthis.setViewport( 0, 0, width, height );\r\n\r\n\t};\r\n\r\n\tthis.setViewport = function ( x, y, width, height ) {\r\n\r\n\t\t_viewportX = x * pixelRatio;\r\n\t\t_viewportY = y * pixelRatio;\r\n\r\n\t\t_viewportWidth = width * pixelRatio;\r\n\t\t_viewportHeight = height * pixelRatio;\r\n\r\n\t\t_gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight );\r\n\r\n\t};\r\n\r\n\tthis.setScissor = function ( x, y, width, height ) {\r\n\r\n\t\t_gl.scissor(\r\n\t\t\tx * pixelRatio,\r\n\t\t\ty * pixelRatio,\r\n\t\t\twidth * pixelRatio,\r\n\t\t\theight * pixelRatio\r\n\t\t);\r\n\r\n\t};\r\n\r\n\tthis.enableScissorTest = function ( enable ) {\r\n\r\n\t\tenable ? _gl.enable( _gl.SCISSOR_TEST ) : _gl.disable( _gl.SCISSOR_TEST );\r\n\r\n\t};\r\n\r\n\t// Clearing\r\n\r\n\tthis.getClearColor = function () {\r\n\r\n\t\treturn _clearColor;\r\n\r\n\t};\r\n\r\n\tthis.setClearColor = function ( color, alpha ) {\r\n\r\n\t\t_clearColor.set( color );\r\n\r\n\t\t_clearAlpha = alpha !== undefined ? alpha : 1;\r\n\r\n\t\tglClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );\r\n\r\n\t};\r\n\r\n\tthis.getClearAlpha = function () {\r\n\r\n\t\treturn _clearAlpha;\r\n\r\n\t};\r\n\r\n\tthis.setClearAlpha = function ( alpha ) {\r\n\r\n\t\t_clearAlpha = alpha;\r\n\r\n\t\tglClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );\r\n\r\n\t};\r\n\r\n\tthis.clear = function ( color, depth, stencil ) {\r\n\r\n\t\tvar bits = 0;\r\n\r\n\t\tif ( color === undefined || color ) bits |= _gl.COLOR_BUFFER_BIT;\r\n\t\tif ( depth === undefined || depth ) bits |= _gl.DEPTH_BUFFER_BIT;\r\n\t\tif ( stencil === undefined || stencil ) bits |= _gl.STENCIL_BUFFER_BIT;\r\n\r\n\t\t_gl.clear( bits );\r\n\r\n\t};\r\n\r\n\tthis.clearColor = function () {\r\n\r\n\t\t_gl.clear( _gl.COLOR_BUFFER_BIT );\r\n\r\n\t};\r\n\r\n\tthis.clearDepth = function () {\r\n\r\n\t\t_gl.clear( _gl.DEPTH_BUFFER_BIT );\r\n\r\n\t};\r\n\r\n\tthis.clearStencil = function () {\r\n\r\n\t\t_gl.clear( _gl.STENCIL_BUFFER_BIT );\r\n\r\n\t};\r\n\r\n\tthis.clearTarget = function ( renderTarget, color, depth, stencil ) {\r\n\r\n\t\tthis.setRenderTarget( renderTarget );\r\n\t\tthis.clear( color, depth, stencil );\r\n\r\n\t};\r\n\r\n\t// Reset\r\n\r\n\tthis.resetGLState = resetGLState;\r\n\r\n\t// Buffer allocation\r\n\r\n\tfunction createParticleBuffers ( geometry ) {\r\n\r\n\t\tgeometry.__webglVertexBuffer = _gl.createBuffer();\r\n\t\tgeometry.__webglColorBuffer = _gl.createBuffer();\r\n\r\n\t\t_this.info.memory.geometries ++;\r\n\r\n\t};\r\n\r\n\tfunction createLineBuffers ( geometry ) {\r\n\r\n\t\tgeometry.__webglVertexBuffer = _gl.createBuffer();\r\n\t\tgeometry.__webglColorBuffer = _gl.createBuffer();\r\n\t\tgeometry.__webglLineDistanceBuffer = _gl.createBuffer();\r\n\r\n\t\t_this.info.memory.geometries ++;\r\n\r\n\t};\r\n\r\n\tfunction createMeshBuffers ( geometryGroup ) {\r\n\r\n\t\tgeometryGroup.__webglVertexBuffer = _gl.createBuffer();\r\n\t\tgeometryGroup.__webglNormalBuffer = _gl.createBuffer();\r\n\t\tgeometryGroup.__webglTangentBuffer = _gl.createBuffer();\r\n\t\tgeometryGroup.__webglColorBuffer = _gl.createBuffer();\r\n\t\tgeometryGroup.__webglUVBuffer = _gl.createBuffer();\r\n\t\tgeometryGroup.__webglUV2Buffer = _gl.createBuffer();\r\n\r\n\t\tgeometryGroup.__webglSkinIndicesBuffer = _gl.createBuffer();\r\n\t\tgeometryGroup.__webglSkinWeightsBuffer = _gl.createBuffer();\r\n\r\n\t\tgeometryGroup.__webglFaceBuffer = _gl.createBuffer();\r\n\t\tgeometryGroup.__webglLineBuffer = _gl.createBuffer();\r\n\r\n\t\tvar numMorphTargets = geometryGroup.numMorphTargets;\r\n\r\n\t\tif ( numMorphTargets ) {\r\n\r\n\t\t\tgeometryGroup.__webglMorphTargetsBuffers = [];\r\n\r\n\t\t\tfor ( var m = 0, ml = numMorphTargets; m < ml; m ++ ) {\r\n\r\n\t\t\t\tgeometryGroup.__webglMorphTargetsBuffers.push( _gl.createBuffer() );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tvar numMorphNormals = geometryGroup.numMorphNormals;\r\n\r\n\t\tif ( numMorphNormals ) {\r\n\r\n\t\t\tgeometryGroup.__webglMorphNormalsBuffers = [];\r\n\r\n\t\t\tfor ( var m = 0, ml = numMorphNormals; m < ml; m ++ ) {\r\n\r\n\t\t\t\tgeometryGroup.__webglMorphNormalsBuffers.push( _gl.createBuffer() );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\t_this.info.memory.geometries ++;\r\n\r\n\t};\r\n\r\n\t// Events\r\n\r\n\tvar onObjectRemoved = function ( event ) {\r\n\r\n\t\tvar object = event.target;\r\n\r\n\t\tobject.traverse( function ( child ) {\r\n\r\n\t\t\tchild.removeEventListener( 'remove', onObjectRemoved );\r\n\r\n\t\t\tremoveObject( child );\r\n\r\n\t\t} );\r\n\r\n\t};\r\n\r\n\tvar onGeometryDispose = function ( event ) {\r\n\r\n\t\tvar geometry = event.target;\r\n\r\n\t\tgeometry.removeEventListener( 'dispose', onGeometryDispose );\r\n\r\n\t\tdeallocateGeometry( geometry );\r\n\r\n\t};\r\n\r\n\tvar onTextureDispose = function ( event ) {\r\n\r\n\t\tvar texture = event.target;\r\n\r\n\t\ttexture.removeEventListener( 'dispose', onTextureDispose );\r\n\r\n\t\tdeallocateTexture( texture );\r\n\r\n\t\t_this.info.memory.textures --;\r\n\r\n\r\n\t};\r\n\r\n\tvar onRenderTargetDispose = function ( event ) {\r\n\r\n\t\tvar renderTarget = event.target;\r\n\r\n\t\trenderTarget.removeEventListener( 'dispose', onRenderTargetDispose );\r\n\r\n\t\tdeallocateRenderTarget( renderTarget );\r\n\r\n\t\t_this.info.memory.textures --;\r\n\r\n\t};\r\n\r\n\tvar onMaterialDispose = function ( event ) {\r\n\r\n\t\tvar material = event.target;\r\n\r\n\t\tmaterial.removeEventListener( 'dispose', onMaterialDispose );\r\n\r\n\t\tdeallocateMaterial( material );\r\n\r\n\t};\r\n\r\n\t// Buffer deallocation\r\n\r\n\tvar deleteBuffers = function ( geometry ) {\r\n\r\n\t\tvar buffers = [\r\n\t\t\t'__webglVertexBuffer',\r\n\t\t\t'__webglNormalBuffer',\r\n\t\t\t'__webglTangentBuffer',\r\n\t\t\t'__webglColorBuffer',\r\n\t\t\t'__webglUVBuffer',\r\n\t\t\t'__webglUV2Buffer',\r\n\r\n\t\t\t'__webglSkinIndicesBuffer',\r\n\t\t\t'__webglSkinWeightsBuffer',\r\n\r\n\t\t\t'__webglFaceBuffer',\r\n\t\t\t'__webglLineBuffer',\r\n\r\n\t\t\t'__webglLineDistanceBuffer'\r\n\t\t];\r\n\r\n\t\tfor ( var i = 0, l = buffers.length; i < l; i ++ ) {\r\n\r\n\t\t\tvar name = buffers[ i ];\r\n\r\n\t\t\tif ( geometry[ name ] !== undefined ) {\r\n\r\n\t\t\t\t_gl.deleteBuffer( geometry[ name ] );\r\n\r\n\t\t\t\tdelete geometry[ name ];\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\t// custom attributes\r\n\r\n\t\tif ( geometry.__webglCustomAttributesList !== undefined ) {\r\n\r\n\t\t\tfor ( var name in geometry.__webglCustomAttributesList ) {\r\n\r\n\t\t\t\t_gl.deleteBuffer( geometry.__webglCustomAttributesList[ name ].buffer );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tdelete geometry.__webglCustomAttributesList;\r\n\r\n\t\t}\r\n\r\n\t\t_this.info.memory.geometries --;\r\n\r\n\t};\r\n\r\n\tvar deallocateGeometry = function ( geometry ) {\r\n\r\n\t\tdelete geometry.__webglInit;\r\n\r\n\t\tif ( geometry instanceof THREE.BufferGeometry ) {\r\n\r\n\t\t\tfor ( var name in geometry.attributes ) {\r\n\r\n\t\t\t\tvar attribute = geometry.attributes[ name ];\r\n\r\n\t\t\t\tif ( attribute.buffer !== undefined ) {\r\n\r\n\t\t\t\t\t_gl.deleteBuffer( attribute.buffer );\r\n\r\n\t\t\t\t\tdelete attribute.buffer;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\t_this.info.memory.geometries --;\r\n\r\n\t\t} else {\r\n\r\n\t\t\tvar geometryGroupsList = geometryGroups[ geometry.id ];\r\n\r\n\t\t\tif ( geometryGroupsList !== undefined ) {\r\n\r\n\t\t\t\tfor ( var i = 0, l = geometryGroupsList.length; i < l; i ++ ) {\r\n\r\n\t\t\t\t\tvar geometryGroup = geometryGroupsList[ i ];\r\n\r\n\t\t\t\t\tif ( geometryGroup.numMorphTargets !== undefined ) {\r\n\r\n\t\t\t\t\t\tfor ( var m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) {\r\n\r\n\t\t\t\t\t\t\t_gl.deleteBuffer( geometryGroup.__webglMorphTargetsBuffers[ m ] );\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tdelete geometryGroup.__webglMorphTargetsBuffers;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif ( geometryGroup.numMorphNormals !== undefined ) {\r\n\r\n\t\t\t\t\t\tfor ( var m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) {\r\n\r\n\t\t\t\t\t\t\t_gl.deleteBuffer( geometryGroup.__webglMorphNormalsBuffers[ m ] );\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tdelete geometryGroup.__webglMorphNormalsBuffers;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tdeleteBuffers( geometryGroup );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tdelete geometryGroups[ geometry.id ];\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tdeleteBuffers( geometry );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\t// TOFIX: Workaround for deleted geometry being currently bound\r\n\r\n\t\t_currentGeometryProgram = '';\r\n\r\n\t};\r\n\r\n\tvar deallocateTexture = function ( texture ) {\r\n\r\n\t\tif ( texture.image && texture.image.__webglTextureCube ) {\r\n\r\n\t\t\t// cube texture\r\n\r\n\t\t\t_gl.deleteTexture( texture.image.__webglTextureCube );\r\n\r\n\t\t\tdelete texture.image.__webglTextureCube;\r\n\r\n\t\t} else {\r\n\r\n\t\t\t// 2D texture\r\n\r\n\t\t\tif ( texture.__webglInit === undefined ) return;\r\n\r\n\t\t\t_gl.deleteTexture( texture.__webglTexture );\r\n\r\n\t\t\tdelete texture.__webglTexture;\r\n\t\t\tdelete texture.__webglInit;\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n\tvar deallocateRenderTarget = function ( renderTarget ) {\r\n\r\n\t\tif ( ! renderTarget || renderTarget.__webglTexture === undefined ) return;\r\n\r\n\t\t_gl.deleteTexture( renderTarget.__webglTexture );\r\n\r\n\t\tdelete renderTarget.__webglTexture;\r\n\r\n\t\tif ( renderTarget instanceof THREE.WebGLRenderTargetCube ) {\r\n\r\n\t\t\tfor ( var i = 0; i < 6; i ++ ) {\r\n\r\n\t\t\t\t_gl.deleteFramebuffer( renderTarget.__webglFramebuffer[ i ] );\r\n\t\t\t\t_gl.deleteRenderbuffer( renderTarget.__webglRenderbuffer[ i ] );\r\n\r\n\t\t\t}\r\n\r\n\t\t} else {\r\n\r\n\t\t\t_gl.deleteFramebuffer( renderTarget.__webglFramebuffer );\r\n\t\t\t_gl.deleteRenderbuffer( renderTarget.__webglRenderbuffer );\r\n\r\n\t\t}\r\n\r\n\t\tdelete renderTarget.__webglFramebuffer;\r\n\t\tdelete renderTarget.__webglRenderbuffer;\r\n\r\n\t};\r\n\r\n\tvar deallocateMaterial = function ( material ) {\r\n\r\n\t\tvar program = material.program.program;\r\n\r\n\t\tif ( program === undefined ) return;\r\n\r\n\t\tmaterial.program = undefined;\r\n\r\n\t\t// only deallocate GL program if this was the last use of shared program\r\n\t\t// assumed there is only single copy of any program in the _programs list\r\n\t\t// (that's how it's constructed)\r\n\r\n\t\tvar i, il, programInfo;\r\n\t\tvar deleteProgram = false;\r\n\r\n\t\tfor ( i = 0, il = _programs.length; i < il; i ++ ) {\r\n\r\n\t\t\tprogramInfo = _programs[ i ];\r\n\r\n\t\t\tif ( programInfo.program === program ) {\r\n\r\n\t\t\t\tprogramInfo.usedTimes --;\r\n\r\n\t\t\t\tif ( programInfo.usedTimes === 0 ) {\r\n\r\n\t\t\t\t\tdeleteProgram = true;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tbreak;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tif ( deleteProgram === true ) {\r\n\r\n\t\t\t// avoid using array.splice, this is costlier than creating new array from scratch\r\n\r\n\t\t\tvar newPrograms = [];\r\n\r\n\t\t\tfor ( i = 0, il = _programs.length; i < il; i ++ ) {\r\n\r\n\t\t\t\tprogramInfo = _programs[ i ];\r\n\r\n\t\t\t\tif ( programInfo.program !== program ) {\r\n\r\n\t\t\t\t\tnewPrograms.push( programInfo );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\t_programs = newPrograms;\r\n\r\n\t\t\t_gl.deleteProgram( program );\r\n\r\n\t\t\t_this.info.memory.programs --;\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n\t// Buffer initialization\r\n\r\n\tfunction initCustomAttributes ( object ) {\r\n\r\n\t\tvar geometry = object.geometry;\r\n\t\tvar material = object.material;\r\n\r\n\t\tvar nvertices = geometry.vertices.length;\r\n\r\n\t\tif ( material.attributes ) {\r\n\r\n\t\t\tif ( geometry.__webglCustomAttributesList === undefined ) {\r\n\r\n\t\t\t\tgeometry.__webglCustomAttributesList = [];\r\n\r\n\t\t\t}\r\n\r\n\t\t\tfor ( var name in material.attributes ) {\r\n\r\n\t\t\t\tvar attribute = material.attributes[ name ];\r\n\r\n\t\t\t\tif ( ! attribute.__webglInitialized || attribute.createUniqueBuffers ) {\r\n\r\n\t\t\t\t\tattribute.__webglInitialized = true;\r\n\r\n\t\t\t\t\tvar size = 1; // \"f\" and \"i\"\r\n\r\n\t\t\t\t\tif ( attribute.type === 'v2' ) size = 2;\r\n\t\t\t\t\telse if ( attribute.type === 'v3' ) size = 3;\r\n\t\t\t\t\telse if ( attribute.type === 'v4' ) size = 4;\r\n\t\t\t\t\telse if ( attribute.type === 'c' ) size = 3;\r\n\r\n\t\t\t\t\tattribute.size = size;\r\n\r\n\t\t\t\t\tattribute.array = new Float32Array( nvertices * size );\r\n\r\n\t\t\t\t\tattribute.buffer = _gl.createBuffer();\r\n\t\t\t\t\tattribute.buffer.belongsToAttribute = name;\r\n\r\n\t\t\t\t\tattribute.needsUpdate = true;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tgeometry.__webglCustomAttributesList.push( attribute );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n\tfunction initParticleBuffers ( geometry, object ) {\r\n\r\n\t\tvar nvertices = geometry.vertices.length;\r\n\r\n\t\tgeometry.__vertexArray = new Float32Array( nvertices * 3 );\r\n\t\tgeometry.__colorArray = new Float32Array( nvertices * 3 );\r\n\r\n\t\tgeometry.__webglParticleCount = nvertices;\r\n\r\n\t\tinitCustomAttributes( object );\r\n\r\n\t};\r\n\r\n\tfunction initLineBuffers ( geometry, object ) {\r\n\r\n\t\tvar nvertices = geometry.vertices.length;\r\n\r\n\t\tgeometry.__vertexArray = new Float32Array( nvertices * 3 );\r\n\t\tgeometry.__colorArray = new Float32Array( nvertices * 3 );\r\n\t\tgeometry.__lineDistanceArray = new Float32Array( nvertices * 1 );\r\n\r\n\t\tgeometry.__webglLineCount = nvertices;\r\n\r\n\t\tinitCustomAttributes( object );\r\n\r\n\t};\r\n\r\n\tfunction initMeshBuffers ( geometryGroup, object ) {\r\n\r\n\t\tvar geometry = object.geometry,\r\n\t\t\tfaces3 = geometryGroup.faces3,\r\n\r\n\t\t\tnvertices = faces3.length * 3,\r\n\t\t\tntris = faces3.length * 1,\r\n\t\t\tnlines = faces3.length * 3,\r\n\r\n\t\t\tmaterial = getBufferMaterial( object, geometryGroup );\r\n\r\n\t\tgeometryGroup.__vertexArray = new Float32Array( nvertices * 3 );\r\n\t\tgeometryGroup.__normalArray = new Float32Array( nvertices * 3 );\r\n\t\tgeometryGroup.__colorArray = new Float32Array( nvertices * 3 );\r\n\t\tgeometryGroup.__uvArray = new Float32Array( nvertices * 2 );\r\n\r\n\t\tif ( geometry.faceVertexUvs.length > 1 ) {\r\n\r\n\t\t\tgeometryGroup.__uv2Array = new Float32Array( nvertices * 2 );\r\n\r\n\t\t}\r\n\r\n\t\tif ( geometry.hasTangents ) {\r\n\r\n\t\t\tgeometryGroup.__tangentArray = new Float32Array( nvertices * 4 );\r\n\r\n\t\t}\r\n\r\n\t\tif ( object.geometry.skinWeights.length && object.geometry.skinIndices.length ) {\r\n\r\n\t\t\tgeometryGroup.__skinIndexArray = new Float32Array( nvertices * 4 );\r\n\t\t\tgeometryGroup.__skinWeightArray = new Float32Array( nvertices * 4 );\r\n\r\n\t\t}\r\n\r\n\t\tvar UintArray = extensions.get( 'OES_element_index_uint' ) !== null && ntris > 21845 ? Uint32Array : Uint16Array; // 65535 / 3\r\n\r\n\t\tgeometryGroup.__typeArray = UintArray;\r\n\t\tgeometryGroup.__faceArray = new UintArray( ntris * 3 );\r\n\t\tgeometryGroup.__lineArray = new UintArray( nlines * 2 );\r\n\r\n\t\tvar numMorphTargets = geometryGroup.numMorphTargets;\r\n\r\n\t\tif ( numMorphTargets ) {\r\n\r\n\t\t\tgeometryGroup.__morphTargetsArrays = [];\r\n\r\n\t\t\tfor ( var m = 0, ml = numMorphTargets; m < ml; m ++ ) {\r\n\r\n\t\t\t\tgeometryGroup.__morphTargetsArrays.push( new Float32Array( nvertices * 3 ) );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tvar numMorphNormals = geometryGroup.numMorphNormals;\r\n\r\n\t\tif ( numMorphNormals ) {\r\n\r\n\t\t\tgeometryGroup.__morphNormalsArrays = [];\r\n\r\n\t\t\tfor ( var m = 0, ml = numMorphNormals; m < ml; m ++ ) {\r\n\r\n\t\t\t\tgeometryGroup.__morphNormalsArrays.push( new Float32Array( nvertices * 3 ) );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tgeometryGroup.__webglFaceCount = ntris * 3;\r\n\t\tgeometryGroup.__webglLineCount = nlines * 2;\r\n\r\n\r\n\t\t// custom attributes\r\n\r\n\t\tif ( material.attributes ) {\r\n\r\n\t\t\tif ( geometryGroup.__webglCustomAttributesList === undefined ) {\r\n\r\n\t\t\t\tgeometryGroup.__webglCustomAttributesList = [];\r\n\r\n\t\t\t}\r\n\r\n\t\t\tfor ( var name in material.attributes ) {\r\n\r\n\t\t\t\t// Do a shallow copy of the attribute object so different geometryGroup chunks use different\r\n\t\t\t\t// attribute buffers which are correctly indexed in the setMeshBuffers function\r\n\r\n\t\t\t\tvar originalAttribute = material.attributes[ name ];\r\n\r\n\t\t\t\tvar attribute = {};\r\n\r\n\t\t\t\tfor ( var property in originalAttribute ) {\r\n\r\n\t\t\t\t\tattribute[ property ] = originalAttribute[ property ];\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif ( ! attribute.__webglInitialized || attribute.createUniqueBuffers ) {\r\n\r\n\t\t\t\t\tattribute.__webglInitialized = true;\r\n\r\n\t\t\t\t\tvar size = 1; // \"f\" and \"i\"\r\n\r\n\t\t\t\t\tif ( attribute.type === 'v2' ) size = 2;\r\n\t\t\t\t\telse if ( attribute.type === 'v3' ) size = 3;\r\n\t\t\t\t\telse if ( attribute.type === 'v4' ) size = 4;\r\n\t\t\t\t\telse if ( attribute.type === 'c' ) size = 3;\r\n\r\n\t\t\t\t\tattribute.size = size;\r\n\r\n\t\t\t\t\tattribute.array = new Float32Array( nvertices * size );\r\n\r\n\t\t\t\t\tattribute.buffer = _gl.createBuffer();\r\n\t\t\t\t\tattribute.buffer.belongsToAttribute = name;\r\n\r\n\t\t\t\t\toriginalAttribute.needsUpdate = true;\r\n\t\t\t\t\tattribute.__original = originalAttribute;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tgeometryGroup.__webglCustomAttributesList.push( attribute );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tgeometryGroup.__inittedArrays = true;\r\n\r\n\t};\r\n\r\n\tfunction getBufferMaterial( object, geometryGroup ) {\r\n\r\n\t\treturn object.material instanceof THREE.MeshFaceMaterial\r\n\t\t\t ? object.material.materials[ geometryGroup.materialIndex ]\r\n\t\t\t : object.material;\r\n\r\n\t}\r\n\r\n\tfunction materialNeedsFaceNormals ( material ) {\r\n\r\n\t\treturn material instanceof THREE.MeshPhongMaterial === false && material.shading === THREE.FlatShading;\r\n\r\n\t}\r\n\r\n\t// Buffer setting\r\n\r\n\tfunction setParticleBuffers ( geometry, hint, object ) {\r\n\r\n\t\tvar v, c, vertex, offset, color,\r\n\r\n\t\tvertices = geometry.vertices,\r\n\t\tvl = vertices.length,\r\n\r\n\t\tcolors = geometry.colors,\r\n\t\tcl = colors.length,\r\n\r\n\t\tvertexArray = geometry.__vertexArray,\r\n\t\tcolorArray = geometry.__colorArray,\r\n\r\n\t\tdirtyVertices = geometry.verticesNeedUpdate,\r\n\t\tdirtyColors = geometry.colorsNeedUpdate,\r\n\r\n\t\tcustomAttributes = geometry.__webglCustomAttributesList,\r\n\t\ti, il,\r\n\t\tca, cal, value,\r\n\t\tcustomAttribute;\r\n\r\n\t\tif ( dirtyVertices ) {\r\n\r\n\t\t\tfor ( v = 0; v < vl; v ++ ) {\r\n\r\n\t\t\t\tvertex = vertices[ v ];\r\n\r\n\t\t\t\toffset = v * 3;\r\n\r\n\t\t\t\tvertexArray[ offset ] = vertex.x;\r\n\t\t\t\tvertexArray[ offset + 1 ] = vertex.y;\r\n\t\t\t\tvertexArray[ offset + 2 ] = vertex.z;\r\n\r\n\t\t\t}\r\n\r\n\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer );\r\n\t\t\t_gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint );\r\n\r\n\t\t}\r\n\r\n\t\tif ( dirtyColors ) {\r\n\r\n\t\t\tfor ( c = 0; c < cl; c ++ ) {\r\n\r\n\t\t\t\tcolor = colors[ c ];\r\n\r\n\t\t\t\toffset = c * 3;\r\n\r\n\t\t\t\tcolorArray[ offset ] = color.r;\r\n\t\t\t\tcolorArray[ offset + 1 ] = color.g;\r\n\t\t\t\tcolorArray[ offset + 2 ] = color.b;\r\n\r\n\t\t\t}\r\n\r\n\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer );\r\n\t\t\t_gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint );\r\n\r\n\t\t}\r\n\r\n\t\tif ( customAttributes ) {\r\n\r\n\t\t\tfor ( i = 0, il = customAttributes.length; i < il; i ++ ) {\r\n\r\n\t\t\t\tcustomAttribute = customAttributes[ i ];\r\n\r\n\t\t\t\tif ( customAttribute.needsUpdate && ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) ) {\r\n\r\n\t\t\t\t\tcal = customAttribute.value.length;\r\n\r\n\t\t\t\t\toffset = 0;\r\n\r\n\t\t\t\t\tif ( customAttribute.size === 1 ) {\r\n\r\n\t\t\t\t\t\tfor ( ca = 0; ca < cal; ca ++ ) {\r\n\r\n\t\t\t\t\t\t\tcustomAttribute.array[ ca ] = customAttribute.value[ ca ];\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t} else if ( customAttribute.size === 2 ) {\r\n\r\n\t\t\t\t\t\tfor ( ca = 0; ca < cal; ca ++ ) {\r\n\r\n\t\t\t\t\t\t\tvalue = customAttribute.value[ ca ];\r\n\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset ] = value.x;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset + 1 ] = value.y;\r\n\r\n\t\t\t\t\t\t\toffset += 2;\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t} else if ( customAttribute.size === 3 ) {\r\n\r\n\t\t\t\t\t\tif ( customAttribute.type === 'c' ) {\r\n\r\n\t\t\t\t\t\t\tfor ( ca = 0; ca < cal; ca ++ ) {\r\n\r\n\t\t\t\t\t\t\t\tvalue = customAttribute.value[ ca ];\r\n\r\n\t\t\t\t\t\t\t\tcustomAttribute.array[ offset ] = value.r;\r\n\t\t\t\t\t\t\t\tcustomAttribute.array[ offset + 1 ] = value.g;\r\n\t\t\t\t\t\t\t\tcustomAttribute.array[ offset + 2 ] = value.b;\r\n\r\n\t\t\t\t\t\t\t\toffset += 3;\r\n\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t} else {\r\n\r\n\t\t\t\t\t\t\tfor ( ca = 0; ca < cal; ca ++ ) {\r\n\r\n\t\t\t\t\t\t\t\tvalue = customAttribute.value[ ca ];\r\n\r\n\t\t\t\t\t\t\t\tcustomAttribute.array[ offset ] = value.x;\r\n\t\t\t\t\t\t\t\tcustomAttribute.array[ offset + 1 ] = value.y;\r\n\t\t\t\t\t\t\t\tcustomAttribute.array[ offset + 2 ] = value.z;\r\n\r\n\t\t\t\t\t\t\t\toffset += 3;\r\n\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t} else if ( customAttribute.size === 4 ) {\r\n\r\n\t\t\t\t\t\tfor ( ca = 0; ca < cal; ca ++ ) {\r\n\r\n\t\t\t\t\t\t\tvalue = customAttribute.value[ ca ];\r\n\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset ] = value.x;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset + 1 ] = value.y;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset + 2 ] = value.z;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset + 3 ] = value.w;\r\n\r\n\t\t\t\t\t\t\toffset += 4;\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer );\r\n\t\t\t\t_gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint );\r\n\r\n\t\t\t\tcustomAttribute.needsUpdate = false;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tfunction setLineBuffers ( geometry, hint ) {\r\n\r\n\t\tvar v, c, d, vertex, offset, color,\r\n\r\n\t\tvertices = geometry.vertices,\r\n\t\tcolors = geometry.colors,\r\n\t\tlineDistances = geometry.lineDistances,\r\n\r\n\t\tvl = vertices.length,\r\n\t\tcl = colors.length,\r\n\t\tdl = lineDistances.length,\r\n\r\n\t\tvertexArray = geometry.__vertexArray,\r\n\t\tcolorArray = geometry.__colorArray,\r\n\t\tlineDistanceArray = geometry.__lineDistanceArray,\r\n\r\n\t\tdirtyVertices = geometry.verticesNeedUpdate,\r\n\t\tdirtyColors = geometry.colorsNeedUpdate,\r\n\t\tdirtyLineDistances = geometry.lineDistancesNeedUpdate,\r\n\r\n\t\tcustomAttributes = geometry.__webglCustomAttributesList,\r\n\r\n\t\ti, il,\r\n\t\tca, cal, value,\r\n\t\tcustomAttribute;\r\n\r\n\t\tif ( dirtyVertices ) {\r\n\r\n\t\t\tfor ( v = 0; v < vl; v ++ ) {\r\n\r\n\t\t\t\tvertex = vertices[ v ];\r\n\r\n\t\t\t\toffset = v * 3;\r\n\r\n\t\t\t\tvertexArray[ offset ] = vertex.x;\r\n\t\t\t\tvertexArray[ offset + 1 ] = vertex.y;\r\n\t\t\t\tvertexArray[ offset + 2 ] = vertex.z;\r\n\r\n\t\t\t}\r\n\r\n\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer );\r\n\t\t\t_gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint );\r\n\r\n\t\t}\r\n\r\n\t\tif ( dirtyColors ) {\r\n\r\n\t\t\tfor ( c = 0; c < cl; c ++ ) {\r\n\r\n\t\t\t\tcolor = colors[ c ];\r\n\r\n\t\t\t\toffset = c * 3;\r\n\r\n\t\t\t\tcolorArray[ offset ] = color.r;\r\n\t\t\t\tcolorArray[ offset + 1 ] = color.g;\r\n\t\t\t\tcolorArray[ offset + 2 ] = color.b;\r\n\r\n\t\t\t}\r\n\r\n\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer );\r\n\t\t\t_gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint );\r\n\r\n\t\t}\r\n\r\n\t\tif ( dirtyLineDistances ) {\r\n\r\n\t\t\tfor ( d = 0; d < dl; d ++ ) {\r\n\r\n\t\t\t\tlineDistanceArray[ d ] = lineDistances[ d ];\r\n\r\n\t\t\t}\r\n\r\n\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglLineDistanceBuffer );\r\n\t\t\t_gl.bufferData( _gl.ARRAY_BUFFER, lineDistanceArray, hint );\r\n\r\n\t\t}\r\n\r\n\t\tif ( customAttributes ) {\r\n\r\n\t\t\tfor ( i = 0, il = customAttributes.length; i < il; i ++ ) {\r\n\r\n\t\t\t\tcustomAttribute = customAttributes[ i ];\r\n\r\n\t\t\t\tif ( customAttribute.needsUpdate && ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) ) {\r\n\r\n\t\t\t\t\toffset = 0;\r\n\r\n\t\t\t\t\tcal = customAttribute.value.length;\r\n\r\n\t\t\t\t\tif ( customAttribute.size === 1 ) {\r\n\r\n\t\t\t\t\t\tfor ( ca = 0; ca < cal; ca ++ ) {\r\n\r\n\t\t\t\t\t\t\tcustomAttribute.array[ ca ] = customAttribute.value[ ca ];\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t} else if ( customAttribute.size === 2 ) {\r\n\r\n\t\t\t\t\t\tfor ( ca = 0; ca < cal; ca ++ ) {\r\n\r\n\t\t\t\t\t\t\tvalue = customAttribute.value[ ca ];\r\n\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset ] = value.x;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset + 1 ] = value.y;\r\n\r\n\t\t\t\t\t\t\toffset += 2;\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t} else if ( customAttribute.size === 3 ) {\r\n\r\n\t\t\t\t\t\tif ( customAttribute.type === 'c' ) {\r\n\r\n\t\t\t\t\t\t\tfor ( ca = 0; ca < cal; ca ++ ) {\r\n\r\n\t\t\t\t\t\t\t\tvalue = customAttribute.value[ ca ];\r\n\r\n\t\t\t\t\t\t\t\tcustomAttribute.array[ offset ] = value.r;\r\n\t\t\t\t\t\t\t\tcustomAttribute.array[ offset + 1 ] = value.g;\r\n\t\t\t\t\t\t\t\tcustomAttribute.array[ offset + 2 ] = value.b;\r\n\r\n\t\t\t\t\t\t\t\toffset += 3;\r\n\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t} else {\r\n\r\n\t\t\t\t\t\t\tfor ( ca = 0; ca < cal; ca ++ ) {\r\n\r\n\t\t\t\t\t\t\t\tvalue = customAttribute.value[ ca ];\r\n\r\n\t\t\t\t\t\t\t\tcustomAttribute.array[ offset ] = value.x;\r\n\t\t\t\t\t\t\t\tcustomAttribute.array[ offset + 1 ] = value.y;\r\n\t\t\t\t\t\t\t\tcustomAttribute.array[ offset + 2 ] = value.z;\r\n\r\n\t\t\t\t\t\t\t\toffset += 3;\r\n\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t} else if ( customAttribute.size === 4 ) {\r\n\r\n\t\t\t\t\t\tfor ( ca = 0; ca < cal; ca ++ ) {\r\n\r\n\t\t\t\t\t\t\tvalue = customAttribute.value[ ca ];\r\n\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset ] = value.x;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset + 1 ] = value.y;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset + 2 ] = value.z;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset + 3 ] = value.w;\r\n\r\n\t\t\t\t\t\t\toffset += 4;\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer );\r\n\t\t\t\t\t_gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint );\r\n\r\n\t\t\t\t\tcustomAttribute.needsUpdate = false;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tfunction setMeshBuffers( geometryGroup, object, hint, dispose, material ) {\r\n\r\n\t\tif ( ! geometryGroup.__inittedArrays ) {\r\n\r\n\t\t\treturn;\r\n\r\n\t\t}\r\n\r\n\t\tvar needsFaceNormals = materialNeedsFaceNormals( material );\r\n\r\n\t\tvar f, fl, fi, face,\r\n\t\tvertexNormals, faceNormal,\r\n\t\tvertexColors, faceColor,\r\n\t\tvertexTangents,\r\n\t\tuv, uv2, v1, v2, v3, t1, t2, t3, n1, n2, n3,\r\n\t\tc1, c2, c3,\r\n\t\tsw1, sw2, sw3,\r\n\t\tsi1, si2, si3,\r\n\t\ti, il,\r\n\t\tvn, uvi, uv2i,\r\n\t\tvk, vkl, vka,\r\n\t\tnka, chf, faceVertexNormals,\r\n\r\n\t\tvertexIndex = 0,\r\n\r\n\t\toffset = 0,\r\n\t\toffset_uv = 0,\r\n\t\toffset_uv2 = 0,\r\n\t\toffset_face = 0,\r\n\t\toffset_normal = 0,\r\n\t\toffset_tangent = 0,\r\n\t\toffset_line = 0,\r\n\t\toffset_color = 0,\r\n\t\toffset_skin = 0,\r\n\t\toffset_morphTarget = 0,\r\n\t\toffset_custom = 0,\r\n\r\n\t\tvalue,\r\n\r\n\t\tvertexArray = geometryGroup.__vertexArray,\r\n\t\tuvArray = geometryGroup.__uvArray,\r\n\t\tuv2Array = geometryGroup.__uv2Array,\r\n\t\tnormalArray = geometryGroup.__normalArray,\r\n\t\ttangentArray = geometryGroup.__tangentArray,\r\n\t\tcolorArray = geometryGroup.__colorArray,\r\n\r\n\t\tskinIndexArray = geometryGroup.__skinIndexArray,\r\n\t\tskinWeightArray = geometryGroup.__skinWeightArray,\r\n\r\n\t\tmorphTargetsArrays = geometryGroup.__morphTargetsArrays,\r\n\t\tmorphNormalsArrays = geometryGroup.__morphNormalsArrays,\r\n\r\n\t\tcustomAttributes = geometryGroup.__webglCustomAttributesList,\r\n\t\tcustomAttribute,\r\n\r\n\t\tfaceArray = geometryGroup.__faceArray,\r\n\t\tlineArray = geometryGroup.__lineArray,\r\n\r\n\t\tgeometry = object.geometry, // this is shared for all chunks\r\n\r\n\t\tdirtyVertices = geometry.verticesNeedUpdate,\r\n\t\tdirtyElements = geometry.elementsNeedUpdate,\r\n\t\tdirtyUvs = geometry.uvsNeedUpdate,\r\n\t\tdirtyNormals = geometry.normalsNeedUpdate,\r\n\t\tdirtyTangents = geometry.tangentsNeedUpdate,\r\n\t\tdirtyColors = geometry.colorsNeedUpdate,\r\n\t\tdirtyMorphTargets = geometry.morphTargetsNeedUpdate,\r\n\r\n\t\tvertices = geometry.vertices,\r\n\t\tchunk_faces3 = geometryGroup.faces3,\r\n\t\tobj_faces = geometry.faces,\r\n\r\n\t\tobj_uvs = geometry.faceVertexUvs[ 0 ],\r\n\t\tobj_uvs2 = geometry.faceVertexUvs[ 1 ],\r\n\r\n\t\tobj_skinIndices = geometry.skinIndices,\r\n\t\tobj_skinWeights = geometry.skinWeights,\r\n\r\n\t\tmorphTargets = geometry.morphTargets,\r\n\t\tmorphNormals = geometry.morphNormals;\r\n\r\n\t\tif ( dirtyVertices ) {\r\n\r\n\t\t\tfor ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {\r\n\r\n\t\t\t\tface = obj_faces[ chunk_faces3[ f ] ];\r\n\r\n\t\t\t\tv1 = vertices[ face.a ];\r\n\t\t\t\tv2 = vertices[ face.b ];\r\n\t\t\t\tv3 = vertices[ face.c ];\r\n\r\n\t\t\t\tvertexArray[ offset ] = v1.x;\r\n\t\t\t\tvertexArray[ offset + 1 ] = v1.y;\r\n\t\t\t\tvertexArray[ offset + 2 ] = v1.z;\r\n\r\n\t\t\t\tvertexArray[ offset + 3 ] = v2.x;\r\n\t\t\t\tvertexArray[ offset + 4 ] = v2.y;\r\n\t\t\t\tvertexArray[ offset + 5 ] = v2.z;\r\n\r\n\t\t\t\tvertexArray[ offset + 6 ] = v3.x;\r\n\t\t\t\tvertexArray[ offset + 7 ] = v3.y;\r\n\t\t\t\tvertexArray[ offset + 8 ] = v3.z;\r\n\r\n\t\t\t\toffset += 9;\r\n\r\n\t\t\t}\r\n\r\n\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer );\r\n\t\t\t_gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint );\r\n\r\n\t\t}\r\n\r\n\t\tif ( dirtyMorphTargets ) {\r\n\r\n\t\t\tfor ( vk = 0, vkl = morphTargets.length; vk < vkl; vk ++ ) {\r\n\r\n\t\t\t\toffset_morphTarget = 0;\r\n\r\n\t\t\t\tfor ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {\r\n\r\n\t\t\t\t\tchf = chunk_faces3[ f ];\r\n\t\t\t\t\tface = obj_faces[ chf ];\r\n\r\n\t\t\t\t\t// morph positions\r\n\r\n\t\t\t\t\tv1 = morphTargets[ vk ].vertices[ face.a ];\r\n\t\t\t\t\tv2 = morphTargets[ vk ].vertices[ face.b ];\r\n\t\t\t\t\tv3 = morphTargets[ vk ].vertices[ face.c ];\r\n\r\n\t\t\t\t\tvka = morphTargetsArrays[ vk ];\r\n\r\n\t\t\t\t\tvka[ offset_morphTarget ] = v1.x;\r\n\t\t\t\t\tvka[ offset_morphTarget + 1 ] = v1.y;\r\n\t\t\t\t\tvka[ offset_morphTarget + 2 ] = v1.z;\r\n\r\n\t\t\t\t\tvka[ offset_morphTarget + 3 ] = v2.x;\r\n\t\t\t\t\tvka[ offset_morphTarget + 4 ] = v2.y;\r\n\t\t\t\t\tvka[ offset_morphTarget + 5 ] = v2.z;\r\n\r\n\t\t\t\t\tvka[ offset_morphTarget + 6 ] = v3.x;\r\n\t\t\t\t\tvka[ offset_morphTarget + 7 ] = v3.y;\r\n\t\t\t\t\tvka[ offset_morphTarget + 8 ] = v3.z;\r\n\r\n\t\t\t\t\t// morph normals\r\n\r\n\t\t\t\t\tif ( material.morphNormals ) {\r\n\r\n\t\t\t\t\t\tif ( needsFaceNormals ) {\r\n\r\n\t\t\t\t\t\t\tn1 = morphNormals[ vk ].faceNormals[ chf ];\r\n\t\t\t\t\t\t\tn2 = n1;\r\n\t\t\t\t\t\t\tn3 = n1;\r\n\r\n\t\t\t\t\t\t} else {\r\n\r\n\t\t\t\t\t\t\tfaceVertexNormals = morphNormals[ vk ].vertexNormals[ chf ];\r\n\r\n\t\t\t\t\t\t\tn1 = faceVertexNormals.a;\r\n\t\t\t\t\t\t\tn2 = faceVertexNormals.b;\r\n\t\t\t\t\t\t\tn3 = faceVertexNormals.c;\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tnka = morphNormalsArrays[ vk ];\r\n\r\n\t\t\t\t\t\tnka[ offset_morphTarget ] = n1.x;\r\n\t\t\t\t\t\tnka[ offset_morphTarget + 1 ] = n1.y;\r\n\t\t\t\t\t\tnka[ offset_morphTarget + 2 ] = n1.z;\r\n\r\n\t\t\t\t\t\tnka[ offset_morphTarget + 3 ] = n2.x;\r\n\t\t\t\t\t\tnka[ offset_morphTarget + 4 ] = n2.y;\r\n\t\t\t\t\t\tnka[ offset_morphTarget + 5 ] = n2.z;\r\n\r\n\t\t\t\t\t\tnka[ offset_morphTarget + 6 ] = n3.x;\r\n\t\t\t\t\t\tnka[ offset_morphTarget + 7 ] = n3.y;\r\n\t\t\t\t\t\tnka[ offset_morphTarget + 8 ] = n3.z;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t//\r\n\r\n\t\t\t\t\toffset_morphTarget += 9;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ vk ] );\r\n\t\t\t\t_gl.bufferData( _gl.ARRAY_BUFFER, morphTargetsArrays[ vk ], hint );\r\n\r\n\t\t\t\tif ( material.morphNormals ) {\r\n\r\n\t\t\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ vk ] );\r\n\t\t\t\t\t_gl.bufferData( _gl.ARRAY_BUFFER, morphNormalsArrays[ vk ], hint );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tif ( obj_skinWeights.length ) {\r\n\r\n\t\t\tfor ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {\r\n\r\n\t\t\t\tface = obj_faces[ chunk_faces3[ f ] ];\r\n\r\n\t\t\t\t// weights\r\n\r\n\t\t\t\tsw1 = obj_skinWeights[ face.a ];\r\n\t\t\t\tsw2 = obj_skinWeights[ face.b ];\r\n\t\t\t\tsw3 = obj_skinWeights[ face.c ];\r\n\r\n\t\t\t\tskinWeightArray[ offset_skin ] = sw1.x;\r\n\t\t\t\tskinWeightArray[ offset_skin + 1 ] = sw1.y;\r\n\t\t\t\tskinWeightArray[ offset_skin + 2 ] = sw1.z;\r\n\t\t\t\tskinWeightArray[ offset_skin + 3 ] = sw1.w;\r\n\r\n\t\t\t\tskinWeightArray[ offset_skin + 4 ] = sw2.x;\r\n\t\t\t\tskinWeightArray[ offset_skin + 5 ] = sw2.y;\r\n\t\t\t\tskinWeightArray[ offset_skin + 6 ] = sw2.z;\r\n\t\t\t\tskinWeightArray[ offset_skin + 7 ] = sw2.w;\r\n\r\n\t\t\t\tskinWeightArray[ offset_skin + 8 ] = sw3.x;\r\n\t\t\t\tskinWeightArray[ offset_skin + 9 ] = sw3.y;\r\n\t\t\t\tskinWeightArray[ offset_skin + 10 ] = sw3.z;\r\n\t\t\t\tskinWeightArray[ offset_skin + 11 ] = sw3.w;\r\n\r\n\t\t\t\t// indices\r\n\r\n\t\t\t\tsi1 = obj_skinIndices[ face.a ];\r\n\t\t\t\tsi2 = obj_skinIndices[ face.b ];\r\n\t\t\t\tsi3 = obj_skinIndices[ face.c ];\r\n\r\n\t\t\t\tskinIndexArray[ offset_skin ] = si1.x;\r\n\t\t\t\tskinIndexArray[ offset_skin + 1 ] = si1.y;\r\n\t\t\t\tskinIndexArray[ offset_skin + 2 ] = si1.z;\r\n\t\t\t\tskinIndexArray[ offset_skin + 3 ] = si1.w;\r\n\r\n\t\t\t\tskinIndexArray[ offset_skin + 4 ] = si2.x;\r\n\t\t\t\tskinIndexArray[ offset_skin + 5 ] = si2.y;\r\n\t\t\t\tskinIndexArray[ offset_skin + 6 ] = si2.z;\r\n\t\t\t\tskinIndexArray[ offset_skin + 7 ] = si2.w;\r\n\r\n\t\t\t\tskinIndexArray[ offset_skin + 8 ] = si3.x;\r\n\t\t\t\tskinIndexArray[ offset_skin + 9 ] = si3.y;\r\n\t\t\t\tskinIndexArray[ offset_skin + 10 ] = si3.z;\r\n\t\t\t\tskinIndexArray[ offset_skin + 11 ] = si3.w;\r\n\r\n\t\t\t\toffset_skin += 12;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( offset_skin > 0 ) {\r\n\r\n\t\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer );\r\n\t\t\t\t_gl.bufferData( _gl.ARRAY_BUFFER, skinIndexArray, hint );\r\n\r\n\t\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer );\r\n\t\t\t\t_gl.bufferData( _gl.ARRAY_BUFFER, skinWeightArray, hint );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tif ( dirtyColors ) {\r\n\r\n\t\t\tfor ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {\r\n\r\n\t\t\t\tface = obj_faces[ chunk_faces3[ f ] ];\r\n\r\n\t\t\t\tvertexColors = face.vertexColors;\r\n\t\t\t\tfaceColor = face.color;\r\n\r\n\t\t\t\tif ( vertexColors.length === 3 && material.vertexColors === THREE.VertexColors ) {\r\n\r\n\t\t\t\t\tc1 = vertexColors[ 0 ];\r\n\t\t\t\t\tc2 = vertexColors[ 1 ];\r\n\t\t\t\t\tc3 = vertexColors[ 2 ];\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\tc1 = faceColor;\r\n\t\t\t\t\tc2 = faceColor;\r\n\t\t\t\t\tc3 = faceColor;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tcolorArray[ offset_color ] = c1.r;\r\n\t\t\t\tcolorArray[ offset_color + 1 ] = c1.g;\r\n\t\t\t\tcolorArray[ offset_color + 2 ] = c1.b;\r\n\r\n\t\t\t\tcolorArray[ offset_color + 3 ] = c2.r;\r\n\t\t\t\tcolorArray[ offset_color + 4 ] = c2.g;\r\n\t\t\t\tcolorArray[ offset_color + 5 ] = c2.b;\r\n\r\n\t\t\t\tcolorArray[ offset_color + 6 ] = c3.r;\r\n\t\t\t\tcolorArray[ offset_color + 7 ] = c3.g;\r\n\t\t\t\tcolorArray[ offset_color + 8 ] = c3.b;\r\n\r\n\t\t\t\toffset_color += 9;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( offset_color > 0 ) {\r\n\r\n\t\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer );\r\n\t\t\t\t_gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tif ( dirtyTangents && geometry.hasTangents ) {\r\n\r\n\t\t\tfor ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {\r\n\r\n\t\t\t\tface = obj_faces[ chunk_faces3[ f ] ];\r\n\r\n\t\t\t\tvertexTangents = face.vertexTangents;\r\n\r\n\t\t\t\tt1 = vertexTangents[ 0 ];\r\n\t\t\t\tt2 = vertexTangents[ 1 ];\r\n\t\t\t\tt3 = vertexTangents[ 2 ];\r\n\r\n\t\t\t\ttangentArray[ offset_tangent ] = t1.x;\r\n\t\t\t\ttangentArray[ offset_tangent + 1 ] = t1.y;\r\n\t\t\t\ttangentArray[ offset_tangent + 2 ] = t1.z;\r\n\t\t\t\ttangentArray[ offset_tangent + 3 ] = t1.w;\r\n\r\n\t\t\t\ttangentArray[ offset_tangent + 4 ] = t2.x;\r\n\t\t\t\ttangentArray[ offset_tangent + 5 ] = t2.y;\r\n\t\t\t\ttangentArray[ offset_tangent + 6 ] = t2.z;\r\n\t\t\t\ttangentArray[ offset_tangent + 7 ] = t2.w;\r\n\r\n\t\t\t\ttangentArray[ offset_tangent + 8 ] = t3.x;\r\n\t\t\t\ttangentArray[ offset_tangent + 9 ] = t3.y;\r\n\t\t\t\ttangentArray[ offset_tangent + 10 ] = t3.z;\r\n\t\t\t\ttangentArray[ offset_tangent + 11 ] = t3.w;\r\n\r\n\t\t\t\toffset_tangent += 12;\r\n\r\n\t\t\t}\r\n\r\n\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer );\r\n\t\t\t_gl.bufferData( _gl.ARRAY_BUFFER, tangentArray, hint );\r\n\r\n\t\t}\r\n\r\n\t\tif ( dirtyNormals ) {\r\n\r\n\t\t\tfor ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {\r\n\r\n\t\t\t\tface = obj_faces[ chunk_faces3[ f ] ];\r\n\r\n\t\t\t\tvertexNormals = face.vertexNormals;\r\n\t\t\t\tfaceNormal = face.normal;\r\n\r\n\t\t\t\tif ( vertexNormals.length === 3 && needsFaceNormals === false ) {\r\n\r\n\t\t\t\t\tfor ( i = 0; i < 3; i ++ ) {\r\n\r\n\t\t\t\t\t\tvn = vertexNormals[ i ];\r\n\r\n\t\t\t\t\t\tnormalArray[ offset_normal ] = vn.x;\r\n\t\t\t\t\t\tnormalArray[ offset_normal + 1 ] = vn.y;\r\n\t\t\t\t\t\tnormalArray[ offset_normal + 2 ] = vn.z;\r\n\r\n\t\t\t\t\t\toffset_normal += 3;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\tfor ( i = 0; i < 3; i ++ ) {\r\n\r\n\t\t\t\t\t\tnormalArray[ offset_normal ] = faceNormal.x;\r\n\t\t\t\t\t\tnormalArray[ offset_normal + 1 ] = faceNormal.y;\r\n\t\t\t\t\t\tnormalArray[ offset_normal + 2 ] = faceNormal.z;\r\n\r\n\t\t\t\t\t\toffset_normal += 3;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer );\r\n\t\t\t_gl.bufferData( _gl.ARRAY_BUFFER, normalArray, hint );\r\n\r\n\t\t}\r\n\r\n\t\tif ( dirtyUvs && obj_uvs ) {\r\n\r\n\t\t\tfor ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {\r\n\r\n\t\t\t\tfi = chunk_faces3[ f ];\r\n\r\n\t\t\t\tuv = obj_uvs[ fi ];\r\n\r\n\t\t\t\tif ( uv === undefined ) continue;\r\n\r\n\t\t\t\tfor ( i = 0; i < 3; i ++ ) {\r\n\r\n\t\t\t\t\tuvi = uv[ i ];\r\n\r\n\t\t\t\t\tuvArray[ offset_uv ] = uvi.x;\r\n\t\t\t\t\tuvArray[ offset_uv + 1 ] = uvi.y;\r\n\r\n\t\t\t\t\toffset_uv += 2;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( offset_uv > 0 ) {\r\n\r\n\t\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer );\r\n\t\t\t\t_gl.bufferData( _gl.ARRAY_BUFFER, uvArray, hint );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tif ( dirtyUvs && obj_uvs2 ) {\r\n\r\n\t\t\tfor ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {\r\n\r\n\t\t\t\tfi = chunk_faces3[ f ];\r\n\r\n\t\t\t\tuv2 = obj_uvs2[ fi ];\r\n\r\n\t\t\t\tif ( uv2 === undefined ) continue;\r\n\r\n\t\t\t\tfor ( i = 0; i < 3; i ++ ) {\r\n\r\n\t\t\t\t\tuv2i = uv2[ i ];\r\n\r\n\t\t\t\t\tuv2Array[ offset_uv2 ] = uv2i.x;\r\n\t\t\t\t\tuv2Array[ offset_uv2 + 1 ] = uv2i.y;\r\n\r\n\t\t\t\t\toffset_uv2 += 2;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( offset_uv2 > 0 ) {\r\n\r\n\t\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer );\r\n\t\t\t\t_gl.bufferData( _gl.ARRAY_BUFFER, uv2Array, hint );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tif ( dirtyElements ) {\r\n\r\n\t\t\tfor ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {\r\n\r\n\t\t\t\tfaceArray[ offset_face ] = vertexIndex;\r\n\t\t\t\tfaceArray[ offset_face + 1 ] = vertexIndex + 1;\r\n\t\t\t\tfaceArray[ offset_face + 2 ] = vertexIndex + 2;\r\n\r\n\t\t\t\toffset_face += 3;\r\n\r\n\t\t\t\tlineArray[ offset_line ] = vertexIndex;\r\n\t\t\t\tlineArray[ offset_line + 1 ] = vertexIndex + 1;\r\n\r\n\t\t\t\tlineArray[ offset_line + 2 ] = vertexIndex;\r\n\t\t\t\tlineArray[ offset_line + 3 ] = vertexIndex + 2;\r\n\r\n\t\t\t\tlineArray[ offset_line + 4 ] = vertexIndex + 1;\r\n\t\t\t\tlineArray[ offset_line + 5 ] = vertexIndex + 2;\r\n\r\n\t\t\t\toffset_line += 6;\r\n\r\n\t\t\t\tvertexIndex += 3;\r\n\r\n\t\t\t}\r\n\r\n\t\t\t_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer );\r\n\t\t\t_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, faceArray, hint );\r\n\r\n\t\t\t_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer );\r\n\t\t\t_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, lineArray, hint );\r\n\r\n\t\t}\r\n\r\n\t\tif ( customAttributes ) {\r\n\r\n\t\t\tfor ( i = 0, il = customAttributes.length; i < il; i ++ ) {\r\n\r\n\t\t\t\tcustomAttribute = customAttributes[ i ];\r\n\r\n\t\t\t\tif ( ! customAttribute.__original.needsUpdate ) continue;\r\n\r\n\t\t\t\toffset_custom = 0;\r\n\r\n\t\t\t\tif ( customAttribute.size === 1 ) {\r\n\r\n\t\t\t\t\tif ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) {\r\n\r\n\t\t\t\t\t\tfor ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {\r\n\r\n\t\t\t\t\t\t\tface = obj_faces[ chunk_faces3[ f ] ];\r\n\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom ] = customAttribute.value[ face.a ];\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 1 ] = customAttribute.value[ face.b ];\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 2 ] = customAttribute.value[ face.c ];\r\n\r\n\t\t\t\t\t\t\toffset_custom += 3;\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t} else if ( customAttribute.boundTo === 'faces' ) {\r\n\r\n\t\t\t\t\t\tfor ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {\r\n\r\n\t\t\t\t\t\t\tvalue = customAttribute.value[ chunk_faces3[ f ] ];\r\n\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom ] = value;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 1 ] = value;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 2 ] = value;\r\n\r\n\t\t\t\t\t\t\toffset_custom += 3;\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t} else if ( customAttribute.size === 2 ) {\r\n\r\n\t\t\t\t\tif ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) {\r\n\r\n\t\t\t\t\t\tfor ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {\r\n\r\n\t\t\t\t\t\t\tface = obj_faces[ chunk_faces3[ f ] ];\r\n\r\n\t\t\t\t\t\t\tv1 = customAttribute.value[ face.a ];\r\n\t\t\t\t\t\t\tv2 = customAttribute.value[ face.b ];\r\n\t\t\t\t\t\t\tv3 = customAttribute.value[ face.c ];\r\n\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom ] = v1.x;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 1 ] = v1.y;\r\n\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 2 ] = v2.x;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 3 ] = v2.y;\r\n\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 4 ] = v3.x;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 5 ] = v3.y;\r\n\r\n\t\t\t\t\t\t\toffset_custom += 6;\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t} else if ( customAttribute.boundTo === 'faces' ) {\r\n\r\n\t\t\t\t\t\tfor ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {\r\n\r\n\t\t\t\t\t\t\tvalue = customAttribute.value[ chunk_faces3[ f ] ];\r\n\r\n\t\t\t\t\t\t\tv1 = value;\r\n\t\t\t\t\t\t\tv2 = value;\r\n\t\t\t\t\t\t\tv3 = value;\r\n\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom ] = v1.x;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 1 ] = v1.y;\r\n\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 2 ] = v2.x;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 3 ] = v2.y;\r\n\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 4 ] = v3.x;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 5 ] = v3.y;\r\n\r\n\t\t\t\t\t\t\toffset_custom += 6;\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t} else if ( customAttribute.size === 3 ) {\r\n\r\n\t\t\t\t\tvar pp;\r\n\r\n\t\t\t\t\tif ( customAttribute.type === 'c' ) {\r\n\r\n\t\t\t\t\t\tpp = [ 'r', 'g', 'b' ];\r\n\r\n\t\t\t\t\t} else {\r\n\r\n\t\t\t\t\t\tpp = [ 'x', 'y', 'z' ];\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) {\r\n\r\n\t\t\t\t\t\tfor ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {\r\n\r\n\t\t\t\t\t\t\tface = obj_faces[ chunk_faces3[ f ] ];\r\n\r\n\t\t\t\t\t\t\tv1 = customAttribute.value[ face.a ];\r\n\t\t\t\t\t\t\tv2 = customAttribute.value[ face.b ];\r\n\t\t\t\t\t\t\tv3 = customAttribute.value[ face.c ];\r\n\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ];\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ];\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ];\r\n\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ];\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ];\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ];\r\n\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ];\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ];\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ];\r\n\r\n\t\t\t\t\t\t\toffset_custom += 9;\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t} else if ( customAttribute.boundTo === 'faces' ) {\r\n\r\n\t\t\t\t\t\tfor ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {\r\n\r\n\t\t\t\t\t\t\tvalue = customAttribute.value[ chunk_faces3[ f ] ];\r\n\r\n\t\t\t\t\t\t\tv1 = value;\r\n\t\t\t\t\t\t\tv2 = value;\r\n\t\t\t\t\t\t\tv3 = value;\r\n\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ];\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ];\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ];\r\n\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ];\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ];\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ];\r\n\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ];\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ];\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ];\r\n\r\n\t\t\t\t\t\t\toffset_custom += 9;\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t} else if ( customAttribute.boundTo === 'faceVertices' ) {\r\n\r\n\t\t\t\t\t\tfor ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {\r\n\r\n\t\t\t\t\t\t\tvalue = customAttribute.value[ chunk_faces3[ f ] ];\r\n\r\n\t\t\t\t\t\t\tv1 = value[ 0 ];\r\n\t\t\t\t\t\t\tv2 = value[ 1 ];\r\n\t\t\t\t\t\t\tv3 = value[ 2 ];\r\n\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ];\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ];\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ];\r\n\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ];\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ];\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ];\r\n\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ];\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ];\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ];\r\n\r\n\t\t\t\t\t\t\toffset_custom += 9;\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t} else if ( customAttribute.size === 4 ) {\r\n\r\n\t\t\t\t\tif ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) {\r\n\r\n\t\t\t\t\t\tfor ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {\r\n\r\n\t\t\t\t\t\t\tface = obj_faces[ chunk_faces3[ f ] ];\r\n\r\n\t\t\t\t\t\t\tv1 = customAttribute.value[ face.a ];\r\n\t\t\t\t\t\t\tv2 = customAttribute.value[ face.b ];\r\n\t\t\t\t\t\t\tv3 = customAttribute.value[ face.c ];\r\n\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom ] = v1.x;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 1 ] = v1.y;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 2 ] = v1.z;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 3 ] = v1.w;\r\n\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 4 ] = v2.x;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 5 ] = v2.y;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 6 ] = v2.z;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 7 ] = v2.w;\r\n\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 8 ] = v3.x;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 9 ] = v3.y;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 10 ] = v3.z;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 11 ] = v3.w;\r\n\r\n\t\t\t\t\t\t\toffset_custom += 12;\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t} else if ( customAttribute.boundTo === 'faces' ) {\r\n\r\n\t\t\t\t\t\tfor ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {\r\n\r\n\t\t\t\t\t\t\tvalue = customAttribute.value[ chunk_faces3[ f ] ];\r\n\r\n\t\t\t\t\t\t\tv1 = value;\r\n\t\t\t\t\t\t\tv2 = value;\r\n\t\t\t\t\t\t\tv3 = value;\r\n\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom ] = v1.x;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 1 ] = v1.y;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 2 ] = v1.z;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 3 ] = v1.w;\r\n\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 4 ] = v2.x;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 5 ] = v2.y;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 6 ] = v2.z;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 7 ] = v2.w;\r\n\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 8 ] = v3.x;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 9 ] = v3.y;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 10 ] = v3.z;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 11 ] = v3.w;\r\n\r\n\t\t\t\t\t\t\toffset_custom += 12;\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t} else if ( customAttribute.boundTo === 'faceVertices' ) {\r\n\r\n\t\t\t\t\t\tfor ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {\r\n\r\n\t\t\t\t\t\t\tvalue = customAttribute.value[ chunk_faces3[ f ] ];\r\n\r\n\t\t\t\t\t\t\tv1 = value[ 0 ];\r\n\t\t\t\t\t\t\tv2 = value[ 1 ];\r\n\t\t\t\t\t\t\tv3 = value[ 2 ];\r\n\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom ] = v1.x;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 1 ] = v1.y;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 2 ] = v1.z;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 3 ] = v1.w;\r\n\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 4 ] = v2.x;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 5 ] = v2.y;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 6 ] = v2.z;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 7 ] = v2.w;\r\n\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 8 ] = v3.x;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 9 ] = v3.y;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 10 ] = v3.z;\r\n\t\t\t\t\t\t\tcustomAttribute.array[ offset_custom + 11 ] = v3.w;\r\n\r\n\t\t\t\t\t\t\toffset_custom += 12;\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer );\r\n\t\t\t\t_gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tif ( dispose ) {\r\n\r\n\t\t\tdelete geometryGroup.__inittedArrays;\r\n\t\t\tdelete geometryGroup.__colorArray;\r\n\t\t\tdelete geometryGroup.__normalArray;\r\n\t\t\tdelete geometryGroup.__tangentArray;\r\n\t\t\tdelete geometryGroup.__uvArray;\r\n\t\t\tdelete geometryGroup.__uv2Array;\r\n\t\t\tdelete geometryGroup.__faceArray;\r\n\t\t\tdelete geometryGroup.__vertexArray;\r\n\t\t\tdelete geometryGroup.__lineArray;\r\n\t\t\tdelete geometryGroup.__skinIndexArray;\r\n\t\t\tdelete geometryGroup.__skinWeightArray;\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n\t// Buffer rendering\r\n\r\n\tthis.renderBufferImmediate = function ( object, program, material ) {\r\n\r\n\t\tstate.initAttributes();\r\n\r\n\t\tif ( object.hasPositions && ! object.__webglVertexBuffer ) object.__webglVertexBuffer = _gl.createBuffer();\r\n\t\tif ( object.hasNormals && ! object.__webglNormalBuffer ) object.__webglNormalBuffer = _gl.createBuffer();\r\n\t\tif ( object.hasUvs && ! object.__webglUvBuffer ) object.__webglUvBuffer = _gl.createBuffer();\r\n\t\tif ( object.hasColors && ! object.__webglColorBuffer ) object.__webglColorBuffer = _gl.createBuffer();\r\n\r\n\t\tif ( object.hasPositions ) {\r\n\r\n\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglVertexBuffer );\r\n\t\t\t_gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW );\r\n\r\n\t\t\tstate.enableAttribute( program.attributes.position );\r\n\r\n\t\t\t_gl.vertexAttribPointer( program.attributes.position, 3, _gl.FLOAT, false, 0, 0 );\r\n\r\n\t\t}\r\n\r\n\t\tif ( object.hasNormals ) {\r\n\r\n\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglNormalBuffer );\r\n\r\n\t\t\tif ( material instanceof THREE.MeshPhongMaterial === false &&\r\n\t\t\t\t material.shading === THREE.FlatShading ) {\r\n\r\n\t\t\t\tvar nx, ny, nz,\r\n\t\t\t\t\tnax, nbx, ncx, nay, nby, ncy, naz, nbz, ncz,\r\n\t\t\t\t\tnormalArray,\r\n\t\t\t\t\ti, il = object.count * 3;\r\n\r\n\t\t\t\tfor ( i = 0; i < il; i += 9 ) {\r\n\r\n\t\t\t\t\tnormalArray = object.normalArray;\r\n\r\n\t\t\t\t\tnax = normalArray[ i ];\r\n\t\t\t\t\tnay = normalArray[ i + 1 ];\r\n\t\t\t\t\tnaz = normalArray[ i + 2 ];\r\n\r\n\t\t\t\t\tnbx = normalArray[ i + 3 ];\r\n\t\t\t\t\tnby = normalArray[ i + 4 ];\r\n\t\t\t\t\tnbz = normalArray[ i + 5 ];\r\n\r\n\t\t\t\t\tncx = normalArray[ i + 6 ];\r\n\t\t\t\t\tncy = normalArray[ i + 7 ];\r\n\t\t\t\t\tncz = normalArray[ i + 8 ];\r\n\r\n\t\t\t\t\tnx = ( nax + nbx + ncx ) / 3;\r\n\t\t\t\t\tny = ( nay + nby + ncy ) / 3;\r\n\t\t\t\t\tnz = ( naz + nbz + ncz ) / 3;\r\n\r\n\t\t\t\t\tnormalArray[ i ] = nx;\r\n\t\t\t\t\tnormalArray[ i + 1 ] = ny;\r\n\t\t\t\t\tnormalArray[ i + 2 ] = nz;\r\n\r\n\t\t\t\t\tnormalArray[ i + 3 ] = nx;\r\n\t\t\t\t\tnormalArray[ i + 4 ] = ny;\r\n\t\t\t\t\tnormalArray[ i + 5 ] = nz;\r\n\r\n\t\t\t\t\tnormalArray[ i + 6 ] = nx;\r\n\t\t\t\t\tnormalArray[ i + 7 ] = ny;\r\n\t\t\t\t\tnormalArray[ i + 8 ] = nz;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\t_gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW );\r\n\r\n\t\t\tstate.enableAttribute( program.attributes.normal );\r\n\r\n\t\t\t_gl.vertexAttribPointer( program.attributes.normal, 3, _gl.FLOAT, false, 0, 0 );\r\n\r\n\t\t}\r\n\r\n\t\tif ( object.hasUvs && material.map ) {\r\n\r\n\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglUvBuffer );\r\n\t\t\t_gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW );\r\n\r\n\t\t\tstate.enableAttribute( program.attributes.uv );\r\n\r\n\t\t\t_gl.vertexAttribPointer( program.attributes.uv, 2, _gl.FLOAT, false, 0, 0 );\r\n\r\n\t\t}\r\n\r\n\t\tif ( object.hasColors && material.vertexColors !== THREE.NoColors ) {\r\n\r\n\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglColorBuffer );\r\n\t\t\t_gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW );\r\n\r\n\t\t\tstate.enableAttribute( program.attributes.color );\r\n\r\n\t\t\t_gl.vertexAttribPointer( program.attributes.color, 3, _gl.FLOAT, false, 0, 0 );\r\n\r\n\t\t}\r\n\r\n\t\tstate.disableUnusedAttributes();\r\n\r\n\t\t_gl.drawArrays( _gl.TRIANGLES, 0, object.count );\r\n\r\n\t\tobject.count = 0;\r\n\r\n\t};\r\n\r\n\tfunction setupVertexAttributes( material, program, geometry, startIndex ) {\r\n\r\n\t\tvar geometryAttributes = geometry.attributes;\r\n\r\n\t\tvar programAttributes = program.attributes;\r\n\t\tvar programAttributesKeys = program.attributesKeys;\r\n\r\n\t\tfor ( var i = 0, l = programAttributesKeys.length; i < l; i ++ ) {\r\n\r\n\t\t\tvar key = programAttributesKeys[ i ];\r\n\t\t\tvar programAttribute = programAttributes[ key ];\r\n\r\n\t\t\tif ( programAttribute >= 0 ) {\r\n\r\n\t\t\t\tvar geometryAttribute = geometryAttributes[ key ];\r\n\r\n\t\t\t\tif ( geometryAttribute !== undefined ) {\r\n\r\n\t\t\t\t\tvar size = geometryAttribute.itemSize;\r\n\r\n\t\t\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryAttribute.buffer );\r\n\r\n\t\t\t\t\tstate.enableAttribute( programAttribute );\r\n\r\n\t\t\t\t\t_gl.vertexAttribPointer( programAttribute, size, _gl.FLOAT, false, 0, startIndex * size * 4 ); // 4 bytes per Float32\r\n\r\n\t\t\t\t} else if ( material.defaultAttributeValues !== undefined ) {\r\n\r\n\t\t\t\t\tif ( material.defaultAttributeValues[ key ].length === 2 ) {\r\n\r\n\t\t\t\t\t\t_gl.vertexAttrib2fv( programAttribute, material.defaultAttributeValues[ key ] );\r\n\r\n\t\t\t\t\t} else if ( material.defaultAttributeValues[ key ].length === 3 ) {\r\n\r\n\t\t\t\t\t\t_gl.vertexAttrib3fv( programAttribute, material.defaultAttributeValues[ key ] );\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tstate.disableUnusedAttributes();\r\n\r\n\t}\r\n\r\n\tthis.renderBufferDirect = function ( camera, lights, fog, material, geometry, object ) {\r\n\r\n\t\tif ( material.visible === false ) return;\r\n\r\n\t\tupdateObject( object );\r\n\r\n\t\tvar program = setProgram( camera, lights, fog, material, object );\r\n\r\n\t\tvar updateBuffers = false,\r\n\t\t\twireframeBit = material.wireframe ? 1 : 0,\r\n\t\t\tgeometryProgram = 'direct_' + geometry.id + '_' + program.id + '_' + wireframeBit;\r\n\r\n\t\tif ( geometryProgram !== _currentGeometryProgram ) {\r\n\r\n\t\t\t_currentGeometryProgram = geometryProgram;\r\n\t\t\tupdateBuffers = true;\r\n\r\n\t\t}\r\n\r\n\t\tif ( updateBuffers ) {\r\n\r\n\t\t\tstate.initAttributes();\r\n\r\n\t\t}\r\n\r\n\t\t// render mesh\r\n\r\n\t\tif ( object instanceof THREE.Mesh ) {\r\n\r\n\t\t\tvar mode = material.wireframe === true ? _gl.LINES : _gl.TRIANGLES;\r\n\r\n\t\t\tvar index = geometry.attributes.index;\r\n\r\n\t\t\tif ( index ) {\r\n\r\n\t\t\t\t// indexed triangles\r\n\r\n\t\t\t\tvar type, size;\r\n\r\n\t\t\t\tif ( index.array instanceof Uint32Array && extensions.get( 'OES_element_index_uint' ) ) {\r\n\r\n\t\t\t\t\ttype = _gl.UNSIGNED_INT;\r\n\t\t\t\t\tsize = 4;\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\ttype = _gl.UNSIGNED_SHORT;\r\n\t\t\t\t\tsize = 2;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvar offsets = geometry.offsets;\r\n\r\n\t\t\t\tif ( offsets.length === 0 ) {\r\n\r\n\t\t\t\t\tif ( updateBuffers ) {\r\n\r\n\t\t\t\t\t\tsetupVertexAttributes( material, program, geometry, 0 );\r\n\t\t\t\t\t\t_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t_gl.drawElements( mode, index.array.length, type, 0 );\r\n\r\n\t\t\t\t\t_this.info.render.calls ++;\r\n\t\t\t\t\t_this.info.render.vertices += index.array.length; // not really true, here vertices can be shared\r\n\t\t\t\t\t_this.info.render.faces += index.array.length / 3;\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\t// if there is more than 1 chunk\r\n\t\t\t\t\t// must set attribute pointers to use new offsets for each chunk\r\n\t\t\t\t\t// even if geometry and materials didn't change\r\n\r\n\t\t\t\t\tupdateBuffers = true;\r\n\r\n\t\t\t\t\tfor ( var i = 0, il = offsets.length; i < il; i ++ ) {\r\n\r\n\t\t\t\t\t\tvar startIndex = offsets[ i ].index;\r\n\r\n\t\t\t\t\t\tif ( updateBuffers ) {\r\n\r\n\t\t\t\t\t\t\tsetupVertexAttributes( material, program, geometry, startIndex );\r\n\t\t\t\t\t\t\t_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t// render indexed triangles\r\n\r\n\t\t\t\t\t\t_gl.drawElements( mode, offsets[ i ].count, type, offsets[ i ].start * size );\r\n\r\n\t\t\t\t\t\t_this.info.render.calls ++;\r\n\t\t\t\t\t\t_this.info.render.vertices += offsets[ i ].count; // not really true, here vertices can be shared\r\n\t\t\t\t\t\t_this.info.render.faces += offsets[ i ].count / 3;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\t// non-indexed triangles\r\n\r\n\t\t\t\tif ( updateBuffers ) {\r\n\r\n\t\t\t\t\tsetupVertexAttributes( material, program, geometry, 0 );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvar position = geometry.attributes[ 'position' ];\r\n\r\n\t\t\t\t// render non-indexed triangles\r\n\r\n\t\t\t\t_gl.drawArrays( mode, 0, position.array.length / position.itemSize );\r\n\r\n\t\t\t\t_this.info.render.calls ++;\r\n\t\t\t\t_this.info.render.vertices += position.array.length / position.itemSize;\r\n\t\t\t\t_this.info.render.faces += position.array.length / ( 3 * position.itemSize );\r\n\r\n\t\t\t}\r\n\r\n\t\t} else if ( object instanceof THREE.PointCloud ) {\r\n\r\n\t\t\t// render particles\r\n\r\n\t\t\tvar mode = _gl.POINTS;\r\n\r\n\t\t\tvar index = geometry.attributes.index;\r\n\r\n\t\t\tif ( index ) {\r\n\r\n\t\t\t\t// indexed points\r\n\r\n\t\t\t\tvar type, size;\r\n\r\n\t\t\t\tif ( index.array instanceof Uint32Array && extensions.get( 'OES_element_index_uint' ) ) {\r\n\r\n\t\t\t\t\ttype = _gl.UNSIGNED_INT;\r\n\t\t\t\t\tsize = 4;\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\ttype = _gl.UNSIGNED_SHORT;\r\n\t\t\t\t\tsize = 2;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvar offsets = geometry.offsets;\r\n\r\n\t\t\t\tif ( offsets.length === 0 ) {\r\n\r\n\t\t\t\t\tif ( updateBuffers ) {\r\n\r\n\t\t\t\t\t\tsetupVertexAttributes( material, program, geometry, 0 );\r\n\t\t\t\t\t\t_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t_gl.drawElements( mode, index.array.length, type, 0);\r\n\r\n\t\t\t\t\t_this.info.render.calls ++;\r\n\t\t\t\t\t_this.info.render.points += index.array.length;\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\t// if there is more than 1 chunk\r\n\t\t\t\t\t// must set attribute pointers to use new offsets for each chunk\r\n\t\t\t\t\t// even if geometry and materials didn't change\r\n\r\n\t\t\t\t\tif ( offsets.length > 1 ) updateBuffers = true;\r\n\r\n\t\t\t\t\tfor ( var i = 0, il = offsets.length; i < il; i ++ ) {\r\n\r\n\t\t\t\t\t\tvar startIndex = offsets[ i ].index;\r\n\r\n\t\t\t\t\t\tif ( updateBuffers ) {\r\n\r\n\t\t\t\t\t\t\tsetupVertexAttributes( material, program, geometry, startIndex );\r\n\t\t\t\t\t\t\t_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t// render indexed points\r\n\r\n\t\t\t\t\t\t_gl.drawElements( mode, offsets[ i ].count, type, offsets[ i ].start * size );\r\n\r\n\t\t\t\t\t\t_this.info.render.calls ++;\r\n\t\t\t\t\t\t_this.info.render.points += offsets[ i ].count;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\t// non-indexed points\r\n\r\n\t\t\t\tif ( updateBuffers ) {\r\n\r\n\t\t\t\t\tsetupVertexAttributes( material, program, geometry, 0 );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvar position = geometry.attributes.position;\r\n\t\t\t\tvar offsets = geometry.offsets;\r\n\r\n\t\t\t\tif ( offsets.length === 0 ) {\r\n\r\n\t\t\t\t\t_gl.drawArrays( mode, 0, position.array.length / 3 );\r\n\r\n\t\t\t\t\t_this.info.render.calls ++;\r\n\t\t\t\t\t_this.info.render.points += position.array.length / 3;\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\tfor ( var i = 0, il = offsets.length; i < il; i ++ ) {\r\n\r\n\t\t\t\t\t\t_gl.drawArrays( mode, offsets[ i ].index, offsets[ i ].count );\r\n\r\n\t\t\t\t\t\t_this.info.render.calls ++;\r\n\t\t\t\t\t\t_this.info.render.points += offsets[ i ].count;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t} else if ( object instanceof THREE.Line ) {\r\n\r\n\t\t\tvar mode = ( object.mode === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES;\r\n\r\n\t\t\tstate.setLineWidth( material.linewidth * pixelRatio );\r\n\r\n\t\t\tvar index = geometry.attributes.index;\r\n\r\n\t\t\tif ( index ) {\r\n\r\n\t\t\t\t// indexed lines\r\n\r\n\t\t\t\tvar type, size;\r\n\r\n\t\t\t\tif ( index.array instanceof Uint32Array ) {\r\n\r\n\t\t\t\t\ttype = _gl.UNSIGNED_INT;\r\n\t\t\t\t\tsize = 4;\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\ttype = _gl.UNSIGNED_SHORT;\r\n\t\t\t\t\tsize = 2;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvar offsets = geometry.offsets;\r\n\r\n\t\t\t\tif ( offsets.length === 0 ) {\r\n\r\n\t\t\t\t\tif ( updateBuffers ) {\r\n\r\n\t\t\t\t\t\tsetupVertexAttributes( material, program, geometry, 0 );\r\n\t\t\t\t\t\t_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t_gl.drawElements( mode, index.array.length, type, 0 ); // 2 bytes per Uint16Array\r\n\r\n\t\t\t\t\t_this.info.render.calls ++;\r\n\t\t\t\t\t_this.info.render.vertices += index.array.length; // not really true, here vertices can be shared\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\t// if there is more than 1 chunk\r\n\t\t\t\t\t// must set attribute pointers to use new offsets for each chunk\r\n\t\t\t\t\t// even if geometry and materials didn't change\r\n\r\n\t\t\t\t\tif ( offsets.length > 1 ) updateBuffers = true;\r\n\r\n\t\t\t\t\tfor ( var i = 0, il = offsets.length; i < il; i ++ ) {\r\n\r\n\t\t\t\t\t\tvar startIndex = offsets[ i ].index;\r\n\r\n\t\t\t\t\t\tif ( updateBuffers ) {\r\n\r\n\t\t\t\t\t\t\tsetupVertexAttributes( material, program, geometry, startIndex );\r\n\t\t\t\t\t\t\t_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t// render indexed lines\r\n\r\n\t\t\t\t\t\t_gl.drawElements( mode, offsets[ i ].count, type, offsets[ i ].start * size ); // 2 bytes per Uint16Array\r\n\r\n\t\t\t\t\t\t_this.info.render.calls ++;\r\n\t\t\t\t\t\t_this.info.render.vertices += offsets[ i ].count; // not really true, here vertices can be shared\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\t// non-indexed lines\r\n\r\n\t\t\t\tif ( updateBuffers ) {\r\n\r\n\t\t\t\t\tsetupVertexAttributes( material, program, geometry, 0 );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvar position = geometry.attributes.position;\r\n\t\t\t\tvar offsets = geometry.offsets;\r\n\r\n\t\t\t\tif ( offsets.length === 0 ) {\r\n\r\n\t\t\t\t\t_gl.drawArrays( mode, 0, position.array.length / 3 );\r\n\r\n\t\t\t\t\t_this.info.render.calls ++;\r\n\t\t\t\t\t_this.info.render.vertices += position.array.length / 3;\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\tfor ( var i = 0, il = offsets.length; i < il; i ++ ) {\r\n\r\n\t\t\t\t\t\t_gl.drawArrays( mode, offsets[ i ].index, offsets[ i ].count );\r\n\r\n\t\t\t\t\t\t_this.info.render.calls ++;\r\n\t\t\t\t\t\t_this.info.render.vertices += offsets[ i ].count;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n\tthis.renderBuffer = function ( camera, lights, fog, material, geometryGroup, object ) {\r\n\r\n\t\tif ( material.visible === false ) return;\r\n\r\n\t\tupdateObject( object );\r\n\r\n\t\tvar program = setProgram( camera, lights, fog, material, object );\r\n\r\n\t\tvar attributes = program.attributes;\r\n\r\n\t\tvar updateBuffers = false,\r\n\t\t\twireframeBit = material.wireframe ? 1 : 0,\r\n\t\t\tgeometryProgram = geometryGroup.id + '_' + program.id + '_' + wireframeBit;\r\n\r\n\t\tif ( geometryProgram !== _currentGeometryProgram ) {\r\n\r\n\t\t\t_currentGeometryProgram = geometryProgram;\r\n\t\t\tupdateBuffers = true;\r\n\r\n\t\t}\r\n\r\n\t\tif ( updateBuffers ) {\r\n\r\n\t\t\tstate.initAttributes();\r\n\r\n\t\t}\r\n\r\n\t\t// vertices\r\n\r\n\t\tif ( ! material.morphTargets && attributes.position >= 0 ) {\r\n\r\n\t\t\tif ( updateBuffers ) {\r\n\r\n\t\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer );\r\n\r\n\t\t\t\tstate.enableAttribute( attributes.position );\r\n\r\n\t\t\t\t_gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );\r\n\r\n\t\t\t}\r\n\r\n\t\t} else {\r\n\r\n\t\t\tif ( object.morphTargetBase ) {\r\n\r\n\t\t\t\tsetupMorphTargets( material, geometryGroup, object );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\r\n\t\tif ( updateBuffers ) {\r\n\r\n\t\t\t// custom attributes\r\n\r\n\t\t\t// Use the per-geometryGroup custom attribute arrays which are setup in initMeshBuffers\r\n\r\n\t\t\tif ( geometryGroup.__webglCustomAttributesList ) {\r\n\r\n\t\t\t\tfor ( var i = 0, il = geometryGroup.__webglCustomAttributesList.length; i < il; i ++ ) {\r\n\r\n\t\t\t\t\tvar attribute = geometryGroup.__webglCustomAttributesList[ i ];\r\n\r\n\t\t\t\t\tif ( attributes[ attribute.buffer.belongsToAttribute ] >= 0 ) {\r\n\r\n\t\t\t\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, attribute.buffer );\r\n\r\n\t\t\t\t\t\tstate.enableAttribute( attributes[ attribute.buffer.belongsToAttribute ] );\r\n\r\n\t\t\t\t\t\t_gl.vertexAttribPointer( attributes[ attribute.buffer.belongsToAttribute ], attribute.size, _gl.FLOAT, false, 0, 0 );\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\r\n\t\t\t// colors\r\n\r\n\t\t\tif ( attributes.color >= 0 ) {\r\n\r\n\t\t\t\tif ( object.geometry.colors.length > 0 || object.geometry.faces.length > 0 ) {\r\n\r\n\t\t\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer );\r\n\r\n\t\t\t\t\tstate.enableAttribute( attributes.color );\r\n\r\n\t\t\t\t\t_gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 );\r\n\r\n\t\t\t\t} else if ( material.defaultAttributeValues !== undefined ) {\r\n\r\n\r\n\t\t\t\t\t_gl.vertexAttrib3fv( attributes.color, material.defaultAttributeValues.color );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\t// normals\r\n\r\n\t\t\tif ( attributes.normal >= 0 ) {\r\n\r\n\t\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer );\r\n\r\n\t\t\t\tstate.enableAttribute( attributes.normal );\r\n\r\n\t\t\t\t_gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 );\r\n\r\n\t\t\t}\r\n\r\n\t\t\t// tangents\r\n\r\n\t\t\tif ( attributes.tangent >= 0 ) {\r\n\r\n\t\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer );\r\n\r\n\t\t\t\tstate.enableAttribute( attributes.tangent );\r\n\r\n\t\t\t\t_gl.vertexAttribPointer( attributes.tangent, 4, _gl.FLOAT, false, 0, 0 );\r\n\r\n\t\t\t}\r\n\r\n\t\t\t// uvs\r\n\r\n\t\t\tif ( attributes.uv >= 0 ) {\r\n\r\n\t\t\t\tif ( object.geometry.faceVertexUvs[ 0 ] ) {\r\n\r\n\t\t\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer );\r\n\r\n\t\t\t\t\tstate.enableAttribute( attributes.uv );\r\n\r\n\t\t\t\t\t_gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 );\r\n\r\n\t\t\t\t} else if ( material.defaultAttributeValues !== undefined ) {\r\n\r\n\r\n\t\t\t\t\t_gl.vertexAttrib2fv( attributes.uv, material.defaultAttributeValues.uv );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( attributes.uv2 >= 0 ) {\r\n\r\n\t\t\t\tif ( object.geometry.faceVertexUvs[ 1 ] ) {\r\n\r\n\t\t\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer );\r\n\r\n\t\t\t\t\tstate.enableAttribute( attributes.uv2 );\r\n\r\n\t\t\t\t\t_gl.vertexAttribPointer( attributes.uv2, 2, _gl.FLOAT, false, 0, 0 );\r\n\r\n\t\t\t\t} else if ( material.defaultAttributeValues !== undefined ) {\r\n\r\n\r\n\t\t\t\t\t_gl.vertexAttrib2fv( attributes.uv2, material.defaultAttributeValues.uv2 );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( material.skinning &&\r\n\t\t\t\t attributes.skinIndex >= 0 && attributes.skinWeight >= 0 ) {\r\n\r\n\t\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer );\r\n\r\n\t\t\t\tstate.enableAttribute( attributes.skinIndex );\r\n\r\n\t\t\t\t_gl.vertexAttribPointer( attributes.skinIndex, 4, _gl.FLOAT, false, 0, 0 );\r\n\r\n\t\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer );\r\n\r\n\t\t\t\tstate.enableAttribute( attributes.skinWeight );\r\n\r\n\t\t\t\t_gl.vertexAttribPointer( attributes.skinWeight, 4, _gl.FLOAT, false, 0, 0 );\r\n\r\n\t\t\t}\r\n\r\n\t\t\t// line distances\r\n\r\n\t\t\tif ( attributes.lineDistance >= 0 ) {\r\n\r\n\t\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglLineDistanceBuffer );\r\n\r\n\t\t\t\tstate.enableAttribute( attributes.lineDistance );\r\n\r\n\t\t\t\t_gl.vertexAttribPointer( attributes.lineDistance, 1, _gl.FLOAT, false, 0, 0 );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tstate.disableUnusedAttributes();\r\n\r\n\t\t// render mesh\r\n\r\n\t\tif ( object instanceof THREE.Mesh ) {\r\n\r\n\t\t\tvar type = geometryGroup.__typeArray === Uint32Array ? _gl.UNSIGNED_INT : _gl.UNSIGNED_SHORT;\r\n\r\n\t\t\t// wireframe\r\n\r\n\t\t\tif ( material.wireframe ) {\r\n\r\n\t\t\t\tstate.setLineWidth( material.wireframeLinewidth * pixelRatio );\r\n\r\n\t\t\t\tif ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer );\r\n\t\t\t\t_gl.drawElements( _gl.LINES, geometryGroup.__webglLineCount, type, 0 );\r\n\r\n\t\t\t// triangles\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tif ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer );\r\n\t\t\t\t_gl.drawElements( _gl.TRIANGLES, geometryGroup.__webglFaceCount, type, 0 );\r\n\r\n\t\t\t}\r\n\r\n\t\t\t_this.info.render.calls ++;\r\n\t\t\t_this.info.render.vertices += geometryGroup.__webglFaceCount;\r\n\t\t\t_this.info.render.faces += geometryGroup.__webglFaceCount / 3;\r\n\r\n\t\t// render lines\r\n\r\n\t\t} else if ( object instanceof THREE.Line ) {\r\n\r\n\t\t\tvar mode = ( object.mode === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES;\r\n\r\n\t\t\tstate.setLineWidth( material.linewidth * pixelRatio );\r\n\r\n\t\t\t_gl.drawArrays( mode, 0, geometryGroup.__webglLineCount );\r\n\r\n\t\t\t_this.info.render.calls ++;\r\n\r\n\t\t// render particles\r\n\r\n\t\t} else if ( object instanceof THREE.PointCloud ) {\r\n\r\n\t\t\t_gl.drawArrays( _gl.POINTS, 0, geometryGroup.__webglParticleCount );\r\n\r\n\t\t\t_this.info.render.calls ++;\r\n\t\t\t_this.info.render.points += geometryGroup.__webglParticleCount;\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n\tfunction setupMorphTargets ( material, geometryGroup, object ) {\r\n\r\n\t\t// set base\r\n\r\n\t\tvar attributes = material.program.attributes;\r\n\r\n\t\tif ( object.morphTargetBase !== - 1 && attributes.position >= 0 ) {\r\n\r\n\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ object.morphTargetBase ] );\r\n\r\n\t\t\tstate.enableAttribute( attributes.position );\r\n\r\n\t\t\t_gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );\r\n\r\n\t\t} else if ( attributes.position >= 0 ) {\r\n\r\n\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer );\r\n\r\n\t\t\tstate.enableAttribute( attributes.position );\r\n\r\n\t\t\t_gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );\r\n\r\n\t\t}\r\n\r\n\t\tif ( object.morphTargetForcedOrder.length ) {\r\n\r\n\t\t\t// set forced order\r\n\r\n\t\t\tvar m = 0;\r\n\t\t\tvar order = object.morphTargetForcedOrder;\r\n\t\t\tvar influences = object.morphTargetInfluences;\r\n\r\n\t\t\tvar attribute;\r\n\r\n\t\t\twhile ( m < material.numSupportedMorphTargets && m < order.length ) {\r\n\r\n\t\t\t\tattribute = attributes[ 'morphTarget' + m ];\r\n\r\n\t\t\t\tif ( attribute >= 0 ) {\r\n\r\n\t\t\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ order[ m ] ] );\r\n\r\n\t\t\t\t\tstate.enableAttribute( attribute );\r\n\r\n\t\t\t\t\t_gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tattribute = attributes[ 'morphNormal' + m ];\r\n\r\n\t\t\t\tif ( attribute >= 0 && material.morphNormals ) {\r\n\r\n\t\t\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ order[ m ] ] );\r\n\r\n\t\t\t\t\tstate.enableAttribute( attribute );\r\n\r\n\t\t\t\t\t_gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tobject.__webglMorphTargetInfluences[ m ] = influences[ order[ m ] ];\r\n\r\n\t\t\t\tm ++;\r\n\r\n\t\t\t}\r\n\r\n\t\t} else {\r\n\r\n\t\t\t// find the most influencing\r\n\r\n\t\t\tvar activeInfluenceIndices = [];\r\n\t\t\tvar influences = object.morphTargetInfluences;\r\n\t\t\tvar morphTargets = object.geometry.morphTargets;\r\n\r\n\t\t\tif ( influences.length > morphTargets.length ) {\r\n\r\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: Influences array is bigger than morphTargets array.' );\r\n\t\t\t\tinfluences.length = morphTargets.length;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tfor ( var i = 0, il = influences.length; i < il; i ++ ) {\r\n\r\n\t\t\t\tvar influence = influences[ i ];\r\n\r\n\t\t\t\tactiveInfluenceIndices.push( [ influence, i ] );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( activeInfluenceIndices.length > material.numSupportedMorphTargets ) {\r\n\r\n\t\t\t\tactiveInfluenceIndices.sort( numericalSort );\r\n\t\t\t\tactiveInfluenceIndices.length = material.numSupportedMorphTargets;\r\n\r\n\t\t\t} else if ( activeInfluenceIndices.length > material.numSupportedMorphNormals ) {\r\n\r\n\t\t\t\tactiveInfluenceIndices.sort( numericalSort );\r\n\r\n\t\t\t} else if ( activeInfluenceIndices.length === 0 ) {\r\n\r\n\t\t\t\tactiveInfluenceIndices.push( [ 0, 0 ] );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tvar attribute;\r\n\r\n\t\t\tfor ( var m = 0, ml = material.numSupportedMorphTargets; m < ml; m ++ ) {\r\n\r\n\t\t\t\tif ( activeInfluenceIndices[ m ] ) {\r\n\r\n\t\t\t\t\tvar influenceIndex = activeInfluenceIndices[ m ][ 1 ];\r\n\r\n\t\t\t\t\tattribute = attributes[ 'morphTarget' + m ];\r\n\r\n\t\t\t\t\tif ( attribute >= 0 ) {\r\n\r\n\t\t\t\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ influenceIndex ] );\r\n\r\n\t\t\t\t\t\tstate.enableAttribute( attribute );\r\n\r\n\t\t\t\t\t\t_gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 );\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tattribute = attributes[ 'morphNormal' + m ];\r\n\r\n\t\t\t\t\tif ( attribute >= 0 && material.morphNormals ) {\r\n\r\n\t\t\t\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ influenceIndex ] );\r\n\r\n\t\t\t\t\t\tstate.enableAttribute( attribute );\r\n\r\n\t\t\t\t\t\t_gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 );\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tobject.__webglMorphTargetInfluences[ m ] = influences[ influenceIndex ];\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\t/*\r\n\t\t\t\t\t_gl.vertexAttribPointer( attributes[ \"morphTarget\" + m ], 3, _gl.FLOAT, false, 0, 0 );\r\n\r\n\t\t\t\t\tif ( material.morphNormals ) {\r\n\r\n\t\t\t\t\t\t_gl.vertexAttribPointer( attributes[ \"morphNormal\" + m ], 3, _gl.FLOAT, false, 0, 0 );\r\n\r\n\t\t\t\t\t}\r\n\t\t\t\t\t*/\r\n\r\n\t\t\t\t\tobject.__webglMorphTargetInfluences[ m ] = 0;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\t// load updated influences uniform\r\n\r\n\t\tif ( material.program.uniforms.morphTargetInfluences !== null ) {\r\n\r\n\t\t\t_gl.uniform1fv( material.program.uniforms.morphTargetInfluences, object.__webglMorphTargetInfluences );\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t// Sorting\r\n\r\n\tfunction painterSortStable ( a, b ) {\r\n\r\n\t\tif ( a.object.renderOrder !== b.object.renderOrder ) {\r\n\r\n\t\t\treturn a.object.renderOrder - b.object.renderOrder;\r\n\r\n\t\t} else if ( a.material.id !== b.material.id ) {\r\n\r\n\t\t\treturn a.material.id - b.material.id;\r\n\r\n\t\t} else if ( a.z !== b.z ) {\r\n\r\n\t\t\treturn a.z - b.z;\r\n\r\n\t\t} else {\r\n\r\n\t\t\treturn a.id - b.id;\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tfunction reversePainterSortStable ( a, b ) {\r\n\r\n\t\tif ( a.object.renderOrder !== b.object.renderOrder ) {\r\n\r\n\t\t\treturn a.object.renderOrder - b.object.renderOrder;\r\n\r\n\t\t} if ( a.z !== b.z ) {\r\n\r\n\t\t\treturn b.z - a.z;\r\n\r\n\t\t} else {\r\n\r\n\t\t\treturn a.id - b.id;\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tfunction numericalSort ( a, b ) {\r\n\r\n\t\treturn b[ 0 ] - a[ 0 ];\r\n\r\n\t}\r\n\r\n\t// Rendering\r\n\r\n\tthis.render = function ( scene, camera, renderTarget, forceClear ) {\r\n\r\n\t\tif ( camera instanceof THREE.Camera === false ) {\r\n\r\n\t\t\tTHREE.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' );\r\n\t\t\treturn;\r\n\r\n\t\t}\r\n\r\n\t\tvar fog = scene.fog;\r\n\r\n\t\t// reset caching for this frame\r\n\r\n\t\t_currentGeometryProgram = '';\r\n\t\t_currentMaterialId = - 1;\r\n\t\t_currentCamera = null;\r\n\t\t_lightsNeedUpdate = true;\r\n\r\n\t\t// update scene graph\r\n\r\n\t\tif ( scene.autoUpdate === true ) scene.updateMatrixWorld();\r\n\r\n\t\t// update camera matrices and frustum\r\n\r\n\t\tif ( camera.parent === undefined ) camera.updateMatrixWorld();\r\n\r\n\t\t// update Skeleton objects\r\n\r\n\t\tscene.traverse( function ( object ) {\r\n\r\n\t\t\tif ( object instanceof THREE.SkinnedMesh ) {\r\n\r\n\t\t\t\tobject.skeleton.update();\r\n\r\n\t\t\t}\r\n\r\n\t\t} );\r\n\r\n\t\tcamera.matrixWorldInverse.getInverse( camera.matrixWorld );\r\n\r\n\t\t_projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );\r\n\t\t_frustum.setFromMatrix( _projScreenMatrix );\r\n\r\n\t\tlights.length = 0;\r\n\t\topaqueObjects.length = 0;\r\n\t\ttransparentObjects.length = 0;\r\n\r\n\t\tsprites.length = 0;\r\n\t\tlensFlares.length = 0;\r\n\r\n\t\tprojectObject( scene );\r\n\r\n\t\tif ( _this.sortObjects === true ) {\r\n\r\n\t\t\topaqueObjects.sort( painterSortStable );\r\n\t\t\ttransparentObjects.sort( reversePainterSortStable );\r\n\r\n\t\t}\r\n\r\n\t\t// custom render plugins (pre pass)\r\n\r\n\t\tshadowMapPlugin.render( scene, camera );\r\n\r\n\t\t//\r\n\r\n\t\t_this.info.render.calls = 0;\r\n\t\t_this.info.render.vertices = 0;\r\n\t\t_this.info.render.faces = 0;\r\n\t\t_this.info.render.points = 0;\r\n\r\n\t\tthis.setRenderTarget( renderTarget );\r\n\r\n\t\tif ( this.autoClear || forceClear ) {\r\n\r\n\t\t\tthis.clear( this.autoClearColor, this.autoClearDepth, this.autoClearStencil );\r\n\r\n\t\t}\r\n\r\n\t\t// set matrices for immediate objects\r\n\r\n\t\tfor ( var i = 0, il = _webglObjectsImmediate.length; i < il; i ++ ) {\r\n\r\n\t\t\tvar webglObject = _webglObjectsImmediate[ i ];\r\n\t\t\tvar object = webglObject.object;\r\n\r\n\t\t\tif ( object.visible ) {\r\n\r\n\t\t\t\tsetupMatrices( object, camera );\r\n\r\n\t\t\t\tunrollImmediateBufferMaterial( webglObject );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tif ( scene.overrideMaterial ) {\r\n\r\n\t\t\tvar overrideMaterial = scene.overrideMaterial;\r\n\r\n\t\t\tsetMaterial( overrideMaterial );\r\n\r\n\t\t\trenderObjects( opaqueObjects, camera, lights, fog, overrideMaterial );\r\n\t\t\trenderObjects( transparentObjects, camera, lights, fog, overrideMaterial );\r\n\t\t\trenderObjectsImmediate( _webglObjectsImmediate, '', camera, lights, fog, overrideMaterial );\r\n\r\n\t\t} else {\r\n\r\n\t\t\t// opaque pass (front-to-back order)\r\n\r\n\t\t\tstate.setBlending( THREE.NoBlending );\r\n\r\n\t\t\trenderObjects( opaqueObjects, camera, lights, fog, null );\r\n\t\t\trenderObjectsImmediate( _webglObjectsImmediate, 'opaque', camera, lights, fog, null );\r\n\r\n\t\t\t// transparent pass (back-to-front order)\r\n\r\n\t\t\trenderObjects( transparentObjects, camera, lights, fog, null );\r\n\t\t\trenderObjectsImmediate( _webglObjectsImmediate, 'transparent', camera, lights, fog, null );\r\n\r\n\t\t}\r\n\r\n\t\t// custom render plugins (post pass)\r\n\r\n\t\tspritePlugin.render( scene, camera );\r\n\t\tlensFlarePlugin.render( scene, camera, _currentWidth, _currentHeight );\r\n\r\n\t\t// Generate mipmap if we're using any kind of mipmap filtering\r\n\r\n\t\tif ( renderTarget && renderTarget.generateMipmaps && renderTarget.minFilter !== THREE.NearestFilter && renderTarget.minFilter !== THREE.LinearFilter ) {\r\n\r\n\t\t\tupdateRenderTargetMipmap( renderTarget );\r\n\r\n\t\t}\r\n\r\n\t\t// Ensure depth buffer writing is enabled so it can be cleared on next render\r\n\r\n\t\tstate.setDepthTest( true );\r\n\t\tstate.setDepthWrite( true );\r\n\t\tstate.setColorWrite( true );\r\n\r\n\t\t// _gl.finish();\r\n\r\n\t};\r\n\r\n\tfunction projectObject( object ) {\r\n\r\n\t\tif ( object.visible === false ) return;\r\n\r\n\t\tif ( object instanceof THREE.Scene || object instanceof THREE.Group ) {\r\n\r\n\t\t\t// skip\r\n\r\n\t\t} else {\r\n\r\n\t\t\tinitObject( object );\r\n\r\n\t\t\tif ( object instanceof THREE.Light ) {\r\n\r\n\t\t\t\tlights.push( object );\r\n\r\n\t\t\t} else if ( object instanceof THREE.Sprite ) {\r\n\r\n\t\t\t\tsprites.push( object );\r\n\r\n\t\t\t} else if ( object instanceof THREE.LensFlare ) {\r\n\r\n\t\t\t\tlensFlares.push( object );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tvar webglObjects = _webglObjects[ object.id ];\r\n\r\n\t\t\t\tif ( webglObjects && ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) ) {\r\n\r\n\t\t\t\t\tfor ( var i = 0, l = webglObjects.length; i < l; i ++ ) {\r\n\r\n\t\t\t\t\t\tvar webglObject = webglObjects[ i ];\r\n\r\n\t\t\t\t\t\tunrollBufferMaterial( webglObject );\r\n\r\n\t\t\t\t\t\twebglObject.render = true;\r\n\r\n\t\t\t\t\t\tif ( _this.sortObjects === true ) {\r\n\r\n\t\t\t\t\t\t\t_vector3.setFromMatrixPosition( object.matrixWorld );\r\n\t\t\t\t\t\t\t_vector3.applyProjection( _projScreenMatrix );\r\n\r\n\t\t\t\t\t\t\twebglObject.z = _vector3.z;\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tfor ( var i = 0, l = object.children.length; i < l; i ++ ) {\r\n\r\n\t\t\tprojectObject( object.children[ i ] );\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tfunction renderObjects( renderList, camera, lights, fog, overrideMaterial ) {\r\n\r\n\t\tvar material;\r\n\r\n\t\tfor ( var i = 0, l = renderList.length; i < l; i ++ ) {\r\n\r\n\t\t\tvar webglObject = renderList[ i ];\r\n\r\n\t\t\tvar object = webglObject.object;\r\n\t\t\tvar buffer = webglObject.buffer;\r\n\r\n\t\t\tsetupMatrices( object, camera );\r\n\r\n\t\t\tif ( overrideMaterial ) {\r\n\r\n\t\t\t\tmaterial = overrideMaterial;\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tmaterial = webglObject.material;\r\n\r\n\t\t\t\tif ( ! material ) continue;\r\n\r\n\t\t\t\tsetMaterial( material );\r\n\r\n\t\t\t}\r\n\r\n\t\t\t_this.setMaterialFaces( material );\r\n\r\n\t\t\tif ( buffer instanceof THREE.BufferGeometry ) {\r\n\r\n\t\t\t\t_this.renderBufferDirect( camera, lights, fog, material, buffer, object );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\t_this.renderBuffer( camera, lights, fog, material, buffer, object );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tfunction renderObjectsImmediate ( renderList, materialType, camera, lights, fog, overrideMaterial ) {\r\n\r\n\t\tvar material;\r\n\r\n\t\tfor ( var i = 0, l = renderList.length; i < l; i ++ ) {\r\n\r\n\t\t\tvar webglObject = renderList[ i ];\r\n\t\t\tvar object = webglObject.object;\r\n\r\n\t\t\tif ( object.visible ) {\r\n\r\n\t\t\t\tif ( overrideMaterial ) {\r\n\r\n\t\t\t\t\tmaterial = overrideMaterial;\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\tmaterial = webglObject[ materialType ];\r\n\r\n\t\t\t\t\tif ( ! material ) continue;\r\n\r\n\t\t\t\t\tsetMaterial( material );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\t_this.renderImmediateObject( camera, lights, fog, material, object );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tthis.renderImmediateObject = function ( camera, lights, fog, material, object ) {\r\n\r\n\t\tvar program = setProgram( camera, lights, fog, material, object );\r\n\r\n\t\t_currentGeometryProgram = '';\r\n\r\n\t\t_this.setMaterialFaces( material );\r\n\r\n\t\tif ( object.immediateRenderCallback ) {\r\n\r\n\t\t\tobject.immediateRenderCallback( program, _gl, _frustum );\r\n\r\n\t\t} else {\r\n\r\n\t\t\tobject.render( function ( object ) { _this.renderBufferImmediate( object, program, material ); } );\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n\tfunction unrollImmediateBufferMaterial ( globject ) {\r\n\r\n\t\tvar object = globject.object,\r\n\t\t\tmaterial = object.material;\r\n\r\n\t\tif ( material.transparent ) {\r\n\r\n\t\t\tglobject.transparent = material;\r\n\t\t\tglobject.opaque = null;\r\n\r\n\t\t} else {\r\n\r\n\t\t\tglobject.opaque = material;\r\n\t\t\tglobject.transparent = null;\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tfunction unrollBufferMaterial ( globject ) {\r\n\r\n\t\tvar object = globject.object;\r\n\t\tvar buffer = globject.buffer;\r\n\r\n\t\tvar geometry = object.geometry;\r\n\t\tvar material = object.material;\r\n\r\n\t\tif ( material instanceof THREE.MeshFaceMaterial ) {\r\n\r\n\t\t\tvar materialIndex = geometry instanceof THREE.BufferGeometry ? 0 : buffer.materialIndex;\r\n\r\n\t\t\tmaterial = material.materials[ materialIndex ];\r\n\r\n\t\t\tglobject.material = material;\r\n\r\n\t\t\tif ( material.transparent ) {\r\n\r\n\t\t\t\ttransparentObjects.push( globject );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\topaqueObjects.push( globject );\r\n\r\n\t\t\t}\r\n\r\n\t\t} else if ( material ) {\r\n\r\n\t\t\tglobject.material = material;\r\n\r\n\t\t\tif ( material.transparent ) {\r\n\r\n\t\t\t\ttransparentObjects.push( globject );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\topaqueObjects.push( globject );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tfunction initObject( object ) {\r\n\r\n\t\tif ( object.__webglInit === undefined ) {\r\n\r\n\t\t\tobject.__webglInit = true;\r\n\t\t\tobject._modelViewMatrix = new THREE.Matrix4();\r\n\t\t\tobject._normalMatrix = new THREE.Matrix3();\r\n\r\n\t\t\tobject.addEventListener( 'removed', onObjectRemoved );\r\n\r\n\t\t}\r\n\r\n\t\tvar geometry = object.geometry;\r\n\r\n\t\tif ( geometry === undefined ) {\r\n\r\n\t\t\t// ImmediateRenderObject\r\n\r\n\t\t} else if ( geometry.__webglInit === undefined ) {\r\n\r\n\t\t\tgeometry.__webglInit = true;\r\n\t\t\tgeometry.addEventListener( 'dispose', onGeometryDispose );\r\n\r\n\t\t\tif ( geometry instanceof THREE.BufferGeometry ) {\r\n\r\n\t\t\t\t_this.info.memory.geometries ++;\r\n\r\n\t\t\t} else if ( object instanceof THREE.Mesh ) {\r\n\r\n\t\t\t\tinitGeometryGroups( object, geometry );\r\n\r\n\t\t\t} else if ( object instanceof THREE.Line ) {\r\n\r\n\t\t\t\tif ( geometry.__webglVertexBuffer === undefined ) {\r\n\r\n\t\t\t\t\tcreateLineBuffers( geometry );\r\n\t\t\t\t\tinitLineBuffers( geometry, object );\r\n\r\n\t\t\t\t\tgeometry.verticesNeedUpdate = true;\r\n\t\t\t\t\tgeometry.colorsNeedUpdate = true;\r\n\t\t\t\t\tgeometry.lineDistancesNeedUpdate = true;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t} else if ( object instanceof THREE.PointCloud ) {\r\n\r\n\t\t\t\tif ( geometry.__webglVertexBuffer === undefined ) {\r\n\r\n\t\t\t\t\tcreateParticleBuffers( geometry );\r\n\t\t\t\t\tinitParticleBuffers( geometry, object );\r\n\r\n\t\t\t\t\tgeometry.verticesNeedUpdate = true;\r\n\t\t\t\t\tgeometry.colorsNeedUpdate = true;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tif ( object.__webglActive === undefined) {\r\n\r\n\t\t\tobject.__webglActive = true;\r\n\r\n\t\t\tif ( object instanceof THREE.Mesh ) {\r\n\r\n\t\t\t\tif ( geometry instanceof THREE.BufferGeometry ) {\r\n\r\n\t\t\t\t\taddBuffer( _webglObjects, geometry, object );\r\n\r\n\t\t\t\t} else if ( geometry instanceof THREE.Geometry ) {\r\n\r\n\t\t\t\t\tvar geometryGroupsList = geometryGroups[ geometry.id ];\r\n\r\n\t\t\t\t\tfor ( var i = 0,l = geometryGroupsList.length; i < l; i ++ ) {\r\n\r\n\t\t\t\t\t\taddBuffer( _webglObjects, geometryGroupsList[ i ], object );\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t} else if ( object instanceof THREE.Line || object instanceof THREE.PointCloud ) {\r\n\r\n\t\t\t\taddBuffer( _webglObjects, geometry, object );\r\n\r\n\t\t\t} else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) {\r\n\r\n\t\t\t\taddBufferImmediate( _webglObjectsImmediate, object );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t// Geometry splitting\r\n\r\n\tvar geometryGroups = {};\r\n\tvar geometryGroupCounter = 0;\r\n\r\n\tfunction makeGroups( geometry, usesFaceMaterial ) {\r\n\r\n\t\tvar maxVerticesInGroup = extensions.get( 'OES_element_index_uint' ) ? 4294967296 : 65535;\r\n\r\n\t\tvar groupHash, hash_map = {};\r\n\r\n\t\tvar numMorphTargets = geometry.morphTargets.length;\r\n\t\tvar numMorphNormals = geometry.morphNormals.length;\r\n\r\n\t\tvar group;\r\n\t\tvar groups = {};\r\n\t\tvar groupsList = [];\r\n\r\n\t\tfor ( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) {\r\n\r\n\t\t\tvar face = geometry.faces[ f ];\r\n\t\t\tvar materialIndex = usesFaceMaterial ? face.materialIndex : 0;\r\n\r\n\t\t\tif ( ! ( materialIndex in hash_map ) ) {\r\n\r\n\t\t\t\thash_map[ materialIndex ] = { hash: materialIndex, counter: 0 };\r\n\r\n\t\t\t}\r\n\r\n\t\t\tgroupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter;\r\n\r\n\t\t\tif ( ! ( groupHash in groups ) ) {\r\n\r\n\t\t\t\tgroup = {\r\n\t\t\t\t\tid: geometryGroupCounter ++,\r\n\t\t\t\t\tfaces3: [],\r\n\t\t\t\t\tmaterialIndex: materialIndex,\r\n\t\t\t\t\tvertices: 0,\r\n\t\t\t\t\tnumMorphTargets: numMorphTargets,\r\n\t\t\t\t\tnumMorphNormals: numMorphNormals\r\n\t\t\t\t};\r\n\r\n\t\t\t\tgroups[ groupHash ] = group;\r\n\t\t\t\tgroupsList.push( group );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( groups[ groupHash ].vertices + 3 > maxVerticesInGroup ) {\r\n\r\n\t\t\t\thash_map[ materialIndex ].counter += 1;\r\n\t\t\t\tgroupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter;\r\n\r\n\t\t\t\tif ( ! ( groupHash in groups ) ) {\r\n\r\n\t\t\t\t\tgroup = {\r\n\t\t\t\t\t\tid: geometryGroupCounter ++,\r\n\t\t\t\t\t\tfaces3: [],\r\n\t\t\t\t\t\tmaterialIndex: materialIndex,\r\n\t\t\t\t\t\tvertices: 0,\r\n\t\t\t\t\t\tnumMorphTargets: numMorphTargets,\r\n\t\t\t\t\t\tnumMorphNormals: numMorphNormals\r\n\t\t\t\t\t};\r\n\r\n\t\t\t\t\tgroups[ groupHash ] = group;\r\n\t\t\t\t\tgroupsList.push( group );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\tgroups[ groupHash ].faces3.push( f );\r\n\t\t\tgroups[ groupHash ].vertices += 3;\r\n\r\n\t\t}\r\n\r\n\t\treturn groupsList;\r\n\r\n\t}\r\n\r\n\tfunction initGeometryGroups( object, geometry ) {\r\n\r\n\t\tvar material = object.material, addBuffers = false;\r\n\r\n\t\tif ( geometryGroups[ geometry.id ] === undefined || geometry.groupsNeedUpdate === true ) {\r\n\r\n\t\t\tdelete _webglObjects[ object.id ];\r\n\r\n\t\t\tgeometryGroups[ geometry.id ] = makeGroups( geometry, material instanceof THREE.MeshFaceMaterial );\r\n\r\n\t\t\tgeometry.groupsNeedUpdate = false;\r\n\r\n\t\t}\r\n\r\n\t\tvar geometryGroupsList = geometryGroups[ geometry.id ];\r\n\r\n\t\t// create separate VBOs per geometry chunk\r\n\r\n\t\tfor ( var i = 0, il = geometryGroupsList.length; i < il; i ++ ) {\r\n\r\n\t\t\tvar geometryGroup = geometryGroupsList[ i ];\r\n\r\n\t\t\t// initialise VBO on the first access\r\n\r\n\t\t\tif ( geometryGroup.__webglVertexBuffer === undefined ) {\r\n\r\n\t\t\t\tcreateMeshBuffers( geometryGroup );\r\n\t\t\t\tinitMeshBuffers( geometryGroup, object );\r\n\r\n\t\t\t\tgeometry.verticesNeedUpdate = true;\r\n\t\t\t\tgeometry.morphTargetsNeedUpdate = true;\r\n\t\t\t\tgeometry.elementsNeedUpdate = true;\r\n\t\t\t\tgeometry.uvsNeedUpdate = true;\r\n\t\t\t\tgeometry.normalsNeedUpdate = true;\r\n\t\t\t\tgeometry.tangentsNeedUpdate = true;\r\n\t\t\t\tgeometry.colorsNeedUpdate = true;\r\n\r\n\t\t\t\taddBuffers = true;\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\taddBuffers = false;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( addBuffers || object.__webglActive === undefined ) {\r\n\r\n\t\t\t\taddBuffer( _webglObjects, geometryGroup, object );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tobject.__webglActive = true;\r\n\r\n\t}\r\n\r\n\tfunction addBuffer( objlist, buffer, object ) {\r\n\r\n\t\tvar id = object.id;\r\n\t\tobjlist[id] = objlist[id] || [];\r\n\t\tobjlist[id].push(\r\n\t\t\t{\r\n\t\t\t\tid: id,\r\n\t\t\t\tbuffer: buffer,\r\n\t\t\t\tobject: object,\r\n\t\t\t\tmaterial: null,\r\n\t\t\t\tz: 0\r\n\t\t\t}\r\n\t\t);\r\n\r\n\t};\r\n\r\n\tfunction addBufferImmediate( objlist, object ) {\r\n\r\n\t\tobjlist.push(\r\n\t\t\t{\r\n\t\t\t\tid: null,\r\n\t\t\t\tobject: object,\r\n\t\t\t\topaque: null,\r\n\t\t\t\ttransparent: null,\r\n\t\t\t\tz: 0\r\n\t\t\t}\r\n\t\t);\r\n\r\n\t};\r\n\r\n\t// Objects updates\r\n\r\n\tfunction updateObject( object ) {\r\n\r\n\t\tvar geometry = object.geometry;\r\n\r\n\t\tif ( geometry instanceof THREE.BufferGeometry ) {\r\n\r\n\t\t\tvar attributes = geometry.attributes;\r\n\t\t\tvar attributesKeys = geometry.attributesKeys;\r\n\r\n\t\t\tfor ( var i = 0, l = attributesKeys.length; i < l; i ++ ) {\r\n\r\n\t\t\t\tvar key = attributesKeys[ i ];\r\n\t\t\t\tvar attribute = attributes[ key ];\r\n\t\t\t\tvar bufferType = ( key === 'index' ) ? _gl.ELEMENT_ARRAY_BUFFER : _gl.ARRAY_BUFFER;\r\n\r\n\t\t\t\tif ( attribute.buffer === undefined ) {\r\n\r\n\t\t\t\t\tattribute.buffer = _gl.createBuffer();\r\n\t\t\t\t\t_gl.bindBuffer( bufferType, attribute.buffer );\r\n\t\t\t\t\t_gl.bufferData( bufferType, attribute.array, ( attribute instanceof THREE.DynamicBufferAttribute ) ? _gl.DYNAMIC_DRAW : _gl.STATIC_DRAW );\r\n\r\n\t\t\t\t\tattribute.needsUpdate = false;\r\n\r\n\t\t\t\t} else if ( attribute.needsUpdate === true ) {\r\n\r\n\t\t\t\t\t_gl.bindBuffer( bufferType, attribute.buffer );\r\n\r\n\t\t\t\t\tif ( attribute.updateRange === undefined || attribute.updateRange.count === -1 ) { // Not using update ranges\r\n\r\n\t\t\t\t\t\t_gl.bufferSubData( bufferType, 0, attribute.array );\r\n\r\n\t\t\t\t\t} else if ( attribute.updateRange.count === 0 ) {\r\n\r\n\t\t\t\t\t\tconsole.error( 'THREE.WebGLRenderer.updateObject: using updateRange for THREE.DynamicBufferAttribute and marked as needsUpdate but count is 0, ensure you are using set methods or updating manually.' );\r\n\r\n\t\t\t\t\t} else {\r\n\r\n\t\t\t\t\t\t_gl.bufferSubData( bufferType, attribute.updateRange.offset * attribute.array.BYTES_PER_ELEMENT,\r\n\t\t\t\t\t\t\t\t\t\t attribute.array.subarray( attribute.updateRange.offset, attribute.updateRange.offset + attribute.updateRange.count ) );\r\n\r\n\t\t\t\t\t\tattribute.updateRange.count = 0; // reset range\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tattribute.needsUpdate = false;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t} else if ( object instanceof THREE.Mesh ) {\r\n\r\n\t\t\t// check all geometry groups\r\n\r\n\t\t\tif ( geometry.groupsNeedUpdate === true ) {\r\n\r\n\t\t\t\tinitGeometryGroups( object, geometry );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tvar geometryGroupsList = geometryGroups[ geometry.id ];\r\n\r\n\t\t\tfor ( var i = 0, il = geometryGroupsList.length; i < il; i ++ ) {\r\n\r\n\t\t\t\tvar geometryGroup = geometryGroupsList[ i ];\r\n\t\t\t\tvar material = getBufferMaterial( object, geometryGroup );\r\n\r\n\t\t\t\tvar customAttributesDirty = material.attributes && areCustomAttributesDirty( material );\r\n\r\n\t\t\t\tif ( geometry.verticesNeedUpdate || geometry.morphTargetsNeedUpdate || geometry.elementsNeedUpdate ||\r\n\t\t\t\t\t geometry.uvsNeedUpdate || geometry.normalsNeedUpdate ||\r\n\t\t\t\t\t geometry.colorsNeedUpdate || geometry.tangentsNeedUpdate || customAttributesDirty ) {\r\n\r\n\t\t\t\t\tsetMeshBuffers( geometryGroup, object, _gl.DYNAMIC_DRAW, ! geometry.dynamic, material );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\tgeometry.verticesNeedUpdate = false;\r\n\t\t\tgeometry.morphTargetsNeedUpdate = false;\r\n\t\t\tgeometry.elementsNeedUpdate = false;\r\n\t\t\tgeometry.uvsNeedUpdate = false;\r\n\t\t\tgeometry.normalsNeedUpdate = false;\r\n\t\t\tgeometry.colorsNeedUpdate = false;\r\n\t\t\tgeometry.tangentsNeedUpdate = false;\r\n\r\n\t\t\tmaterial.attributes && clearCustomAttributes( material );\r\n\r\n\t\t} else if ( object instanceof THREE.Line ) {\r\n\r\n\t\t\tvar material = getBufferMaterial( object, geometry );\r\n\t\t\tvar customAttributesDirty = material.attributes && areCustomAttributesDirty( material );\r\n\r\n\t\t\tif ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || geometry.lineDistancesNeedUpdate || customAttributesDirty ) {\r\n\r\n\t\t\t\tsetLineBuffers( geometry, _gl.DYNAMIC_DRAW );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tgeometry.verticesNeedUpdate = false;\r\n\t\t\tgeometry.colorsNeedUpdate = false;\r\n\t\t\tgeometry.lineDistancesNeedUpdate = false;\r\n\r\n\t\t\tmaterial.attributes && clearCustomAttributes( material );\r\n\r\n\t\t} else if ( object instanceof THREE.PointCloud ) {\r\n\r\n\t\t\tvar material = getBufferMaterial( object, geometry );\r\n\t\t\tvar customAttributesDirty = material.attributes && areCustomAttributesDirty( material );\r\n\r\n\t\t\tif ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || customAttributesDirty ) {\r\n\r\n\t\t\t\tsetParticleBuffers( geometry, _gl.DYNAMIC_DRAW, object );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tgeometry.verticesNeedUpdate = false;\r\n\t\t\tgeometry.colorsNeedUpdate = false;\r\n\r\n\t\t\tmaterial.attributes && clearCustomAttributes( material );\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t// Objects updates - custom attributes check\r\n\r\n\tfunction areCustomAttributesDirty( material ) {\r\n\r\n\t\tfor ( var name in material.attributes ) {\r\n\r\n\t\t\tif ( material.attributes[ name ].needsUpdate ) return true;\r\n\r\n\t\t}\r\n\r\n\t\treturn false;\r\n\r\n\t}\r\n\r\n\tfunction clearCustomAttributes( material ) {\r\n\r\n\t\tfor ( var name in material.attributes ) {\r\n\r\n\t\t\tmaterial.attributes[ name ].needsUpdate = false;\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t// Objects removal\r\n\r\n\tfunction removeObject( object ) {\r\n\r\n\t\tif ( object instanceof THREE.Mesh ||\r\n\t\t\t object instanceof THREE.PointCloud ||\r\n\t\t\t object instanceof THREE.Line ) {\r\n\r\n\t\t\tdelete _webglObjects[ object.id ];\r\n\r\n\t\t} else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) {\r\n\r\n\t\t\tremoveInstances( _webglObjectsImmediate, object );\r\n\r\n\t\t}\r\n\r\n\t\tdelete object.__webglInit;\r\n\t\tdelete object._modelViewMatrix;\r\n\t\tdelete object._normalMatrix;\r\n\r\n\t\tdelete object.__webglActive;\r\n\r\n\t}\r\n\r\n\tfunction removeInstances( objlist, object ) {\r\n\r\n\t\tfor ( var o = objlist.length - 1; o >= 0; o -- ) {\r\n\r\n\t\t\tif ( objlist[ o ].object === object ) {\r\n\r\n\t\t\t\tobjlist.splice( o, 1 );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t// Materials\r\n\r\n\tvar shaderIDs = {\r\n\t\tMeshDepthMaterial: 'depth',\r\n\t\tMeshNormalMaterial: 'normal',\r\n\t\tMeshBasicMaterial: 'basic',\r\n\t\tMeshLambertMaterial: 'lambert',\r\n\t\tMeshPhongMaterial: 'phong',\r\n\t\tLineBasicMaterial: 'basic',\r\n\t\tLineDashedMaterial: 'dashed',\r\n\t\tPointCloudMaterial: 'particle_basic'\r\n\t};\r\n\r\n\tfunction initMaterial( material, lights, fog, object ) {\r\n\r\n\t\tmaterial.addEventListener( 'dispose', onMaterialDispose );\r\n\r\n\t\tvar shaderID = shaderIDs[ material.type ];\r\n\r\n\t\tif ( shaderID ) {\r\n\r\n\t\t\tvar shader = THREE.ShaderLib[ shaderID ];\r\n\r\n\t\t\tmaterial.__webglShader = {\r\n\t\t\t\tuniforms: THREE.UniformsUtils.clone( shader.uniforms ),\r\n\t\t\t\tvertexShader: shader.vertexShader,\r\n\t\t\t\tfragmentShader: shader.fragmentShader\r\n\t\t\t}\r\n\r\n\t\t} else {\r\n\r\n\t\t\tmaterial.__webglShader = {\r\n\t\t\t\tuniforms: material.uniforms,\r\n\t\t\t\tvertexShader: material.vertexShader,\r\n\t\t\t\tfragmentShader: material.fragmentShader\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\t// heuristics to create shader parameters according to lights in the scene\r\n\t\t// (not to blow over maxLights budget)\r\n\r\n\t\tvar maxLightCount = allocateLights( lights );\r\n\t\tvar maxShadows = allocateShadows( lights );\r\n\t\tvar maxBones = allocateBones( object );\r\n\r\n\t\tvar parameters = {\r\n\r\n\t\t\tprecision: _precision,\r\n\t\t\tsupportsVertexTextures: _supportsVertexTextures,\r\n\r\n\t\t\tmap: !! material.map,\r\n\t\t\tenvMap: !! material.envMap,\r\n\t\t\tenvMapMode: material.envMap && material.envMap.mapping,\r\n\t\t\tlightMap: !! material.lightMap,\r\n\t\t\tbumpMap: !! material.bumpMap,\r\n\t\t\tnormalMap: !! material.normalMap,\r\n\t\t\tspecularMap: !! material.specularMap,\r\n\t\t\talphaMap: !! material.alphaMap,\r\n\r\n\t\t\tcombine: material.combine,\r\n\r\n\t\t\tvertexColors: material.vertexColors,\r\n\r\n\t\t\tfog: fog,\r\n\t\t\tuseFog: material.fog,\r\n\t\t\tfogExp: fog instanceof THREE.FogExp2,\r\n\r\n\t\t\tflatShading: material.shading === THREE.FlatShading,\r\n\r\n\t\t\tsizeAttenuation: material.sizeAttenuation,\r\n\t\t\tlogarithmicDepthBuffer: _logarithmicDepthBuffer,\r\n\r\n\t\t\tskinning: material.skinning,\r\n\t\t\tmaxBones: maxBones,\r\n\t\t\tuseVertexTexture: _supportsBoneTextures && object && object.skeleton && object.skeleton.useVertexTexture,\r\n\r\n\t\t\tmorphTargets: material.morphTargets,\r\n\t\t\tmorphNormals: material.morphNormals,\r\n\t\t\tmaxMorphTargets: _this.maxMorphTargets,\r\n\t\t\tmaxMorphNormals: _this.maxMorphNormals,\r\n\r\n\t\t\tmaxDirLights: maxLightCount.directional,\r\n\t\t\tmaxPointLights: maxLightCount.point,\r\n\t\t\tmaxSpotLights: maxLightCount.spot,\r\n\t\t\tmaxHemiLights: maxLightCount.hemi,\r\n\r\n\t\t\tmaxShadows: maxShadows,\r\n\t\t\tshadowMapEnabled: _this.shadowMapEnabled && object.receiveShadow && maxShadows > 0,\r\n\t\t\tshadowMapType: _this.shadowMapType,\r\n\t\t\tshadowMapDebug: _this.shadowMapDebug,\r\n\t\t\tshadowMapCascade: _this.shadowMapCascade,\r\n\r\n\t\t\talphaTest: material.alphaTest,\r\n\t\t\tmetal: material.metal,\r\n\t\t\twrapAround: material.wrapAround,\r\n\t\t\tdoubleSided: material.side === THREE.DoubleSide,\r\n\t\t\tflipSided: material.side === THREE.BackSide\r\n\r\n\t\t};\r\n\r\n\t\t// Generate code\r\n\r\n\t\tvar chunks = [];\r\n\r\n\t\tif ( shaderID ) {\r\n\r\n\t\t\tchunks.push( shaderID );\r\n\r\n\t\t} else {\r\n\r\n\t\t\tchunks.push( material.fragmentShader );\r\n\t\t\tchunks.push( material.vertexShader );\r\n\r\n\t\t}\r\n\r\n\t\tif ( material.defines !== undefined ) {\r\n\r\n\t\t\tfor ( var name in material.defines ) {\r\n\r\n\t\t\t\tchunks.push( name );\r\n\t\t\t\tchunks.push( material.defines[ name ] );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tfor ( var name in parameters ) {\r\n\r\n\t\t\tchunks.push( name );\r\n\t\t\tchunks.push( parameters[ name ] );\r\n\r\n\t\t}\r\n\r\n\t\tvar code = chunks.join();\r\n\r\n\t\tvar program;\r\n\r\n\t\t// Check if code has been already compiled\r\n\r\n\t\tfor ( var p = 0, pl = _programs.length; p < pl; p ++ ) {\r\n\r\n\t\t\tvar programInfo = _programs[ p ];\r\n\r\n\t\t\tif ( programInfo.code === code ) {\r\n\r\n\t\t\t\tprogram = programInfo;\r\n\t\t\t\tprogram.usedTimes ++;\r\n\r\n\t\t\t\tbreak;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tif ( program === undefined ) {\r\n\r\n\t\t\tprogram = new THREE.WebGLProgram( _this, code, material, parameters );\r\n\t\t\t_programs.push( program );\r\n\r\n\t\t\t_this.info.memory.programs = _programs.length;\r\n\r\n\t\t}\r\n\r\n\t\tmaterial.program = program;\r\n\r\n\t\tvar attributes = program.attributes;\r\n\r\n\t\tif ( material.morphTargets ) {\r\n\r\n\t\t\tmaterial.numSupportedMorphTargets = 0;\r\n\r\n\t\t\tvar id, base = 'morphTarget';\r\n\r\n\t\t\tfor ( var i = 0; i < _this.maxMorphTargets; i ++ ) {\r\n\r\n\t\t\t\tid = base + i;\r\n\r\n\t\t\t\tif ( attributes[ id ] >= 0 ) {\r\n\r\n\t\t\t\t\tmaterial.numSupportedMorphTargets ++;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tif ( material.morphNormals ) {\r\n\r\n\t\t\tmaterial.numSupportedMorphNormals = 0;\r\n\r\n\t\t\tvar id, base = 'morphNormal';\r\n\r\n\t\t\tfor ( i = 0; i < _this.maxMorphNormals; i ++ ) {\r\n\r\n\t\t\t\tid = base + i;\r\n\r\n\t\t\t\tif ( attributes[ id ] >= 0 ) {\r\n\r\n\t\t\t\t\tmaterial.numSupportedMorphNormals ++;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tmaterial.uniformsList = [];\r\n\r\n\t\tfor ( var u in material.__webglShader.uniforms ) {\r\n\r\n\t\t\tvar location = material.program.uniforms[ u ];\r\n\r\n\t\t\tif ( location ) {\r\n\t\t\t\tmaterial.uniformsList.push( [ material.__webglShader.uniforms[ u ], location ] );\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tfunction setMaterial( material ) {\r\n\r\n\t\tif ( material.transparent === true ) {\r\n\r\n\t\t\tstate.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha );\r\n\r\n\t\t} else {\r\n\r\n\t\t\tstate.setBlending( THREE.NoBlending );\r\n\r\n\t\t}\r\n\r\n\t\tstate.setDepthTest( material.depthTest );\r\n\t\tstate.setDepthWrite( material.depthWrite );\r\n\t\tstate.setColorWrite( material.colorWrite );\r\n\t\tstate.setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );\r\n\r\n\t}\r\n\r\n\tfunction setProgram( camera, lights, fog, material, object ) {\r\n\r\n\t\t_usedTextureUnits = 0;\r\n\r\n\t\tif ( material.needsUpdate ) {\r\n\r\n\t\t\tif ( material.program ) deallocateMaterial( material );\r\n\r\n\t\t\tinitMaterial( material, lights, fog, object );\r\n\t\t\tmaterial.needsUpdate = false;\r\n\r\n\t\t}\r\n\r\n\t\tif ( material.morphTargets ) {\r\n\r\n\t\t\tif ( ! object.__webglMorphTargetInfluences ) {\r\n\r\n\t\t\t\tobject.__webglMorphTargetInfluences = new Float32Array( _this.maxMorphTargets );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tvar refreshProgram = false;\r\n\t\tvar refreshMaterial = false;\r\n\t\tvar refreshLights = false;\r\n\r\n\t\tvar program = material.program,\r\n\t\t\tp_uniforms = program.uniforms,\r\n\t\t\tm_uniforms = material.__webglShader.uniforms;\r\n\r\n\t\tif ( program.id !== _currentProgram ) {\r\n\r\n\t\t\t_gl.useProgram( program.program );\r\n\t\t\t_currentProgram = program.id;\r\n\r\n\t\t\trefreshProgram = true;\r\n\t\t\trefreshMaterial = true;\r\n\t\t\trefreshLights = true;\r\n\r\n\t\t}\r\n\r\n\t\tif ( material.id !== _currentMaterialId ) {\r\n\r\n\t\t\tif ( _currentMaterialId === -1 ) refreshLights = true;\r\n\t\t\t_currentMaterialId = material.id;\r\n\r\n\t\t\trefreshMaterial = true;\r\n\r\n\t\t}\r\n\r\n\t\tif ( refreshProgram || camera !== _currentCamera ) {\r\n\r\n\t\t\t_gl.uniformMatrix4fv( p_uniforms.projectionMatrix, false, camera.projectionMatrix.elements );\r\n\r\n\t\t\tif ( _logarithmicDepthBuffer ) {\r\n\r\n\t\t\t\t_gl.uniform1f( p_uniforms.logDepthBufFC, 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) );\r\n\r\n\t\t\t}\r\n\r\n\r\n\t\t\tif ( camera !== _currentCamera ) _currentCamera = camera;\r\n\r\n\t\t\t// load material specific uniforms\r\n\t\t\t// (shader material also gets them for the sake of genericity)\r\n\r\n\t\t\tif ( material instanceof THREE.ShaderMaterial ||\r\n\t\t\t\t material instanceof THREE.MeshPhongMaterial ||\r\n\t\t\t\t material.envMap ) {\r\n\r\n\t\t\t\tif ( p_uniforms.cameraPosition !== null ) {\r\n\r\n\t\t\t\t\t_vector3.setFromMatrixPosition( camera.matrixWorld );\r\n\t\t\t\t\t_gl.uniform3f( p_uniforms.cameraPosition, _vector3.x, _vector3.y, _vector3.z );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( material instanceof THREE.MeshPhongMaterial ||\r\n\t\t\t\t material instanceof THREE.MeshLambertMaterial ||\r\n\t\t\t\t material instanceof THREE.MeshBasicMaterial ||\r\n\t\t\t\t material instanceof THREE.ShaderMaterial ||\r\n\t\t\t\t material.skinning ) {\r\n\r\n\t\t\t\tif ( p_uniforms.viewMatrix !== null ) {\r\n\r\n\t\t\t\t\t_gl.uniformMatrix4fv( p_uniforms.viewMatrix, false, camera.matrixWorldInverse.elements );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\t// skinning uniforms must be set even if material didn't change\r\n\t\t// auto-setting of texture unit for bone texture must go before other textures\r\n\t\t// not sure why, but otherwise weird things happen\r\n\r\n\t\tif ( material.skinning ) {\r\n\r\n\t\t\tif ( object.bindMatrix && p_uniforms.bindMatrix !== null ) {\r\n\r\n\t\t\t\t_gl.uniformMatrix4fv( p_uniforms.bindMatrix, false, object.bindMatrix.elements );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( object.bindMatrixInverse && p_uniforms.bindMatrixInverse !== null ) {\r\n\r\n\t\t\t\t_gl.uniformMatrix4fv( p_uniforms.bindMatrixInverse, false, object.bindMatrixInverse.elements );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( _supportsBoneTextures && object.skeleton && object.skeleton.useVertexTexture ) {\r\n\r\n\t\t\t\tif ( p_uniforms.boneTexture !== null ) {\r\n\r\n\t\t\t\t\tvar textureUnit = getTextureUnit();\r\n\r\n\t\t\t\t\t_gl.uniform1i( p_uniforms.boneTexture, textureUnit );\r\n\t\t\t\t\t_this.setTexture( object.skeleton.boneTexture, textureUnit );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif ( p_uniforms.boneTextureWidth !== null ) {\r\n\r\n\t\t\t\t\t_gl.uniform1i( p_uniforms.boneTextureWidth, object.skeleton.boneTextureWidth );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif ( p_uniforms.boneTextureHeight !== null ) {\r\n\r\n\t\t\t\t\t_gl.uniform1i( p_uniforms.boneTextureHeight, object.skeleton.boneTextureHeight );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t} else if ( object.skeleton && object.skeleton.boneMatrices ) {\r\n\r\n\t\t\t\tif ( p_uniforms.boneGlobalMatrices !== null ) {\r\n\r\n\t\t\t\t\t_gl.uniformMatrix4fv( p_uniforms.boneGlobalMatrices, false, object.skeleton.boneMatrices );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tif ( refreshMaterial ) {\r\n\r\n\t\t\t// refresh uniforms common to several materials\r\n\r\n\t\t\tif ( fog && material.fog ) {\r\n\r\n\t\t\t\trefreshUniformsFog( m_uniforms, fog );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( material instanceof THREE.MeshPhongMaterial ||\r\n\t\t\t\t material instanceof THREE.MeshLambertMaterial ||\r\n\t\t\t\t material.lights ) {\r\n\r\n\t\t\t\tif ( _lightsNeedUpdate ) {\r\n\r\n\t\t\t\t\trefreshLights = true;\r\n\t\t\t\t\tsetupLights( lights );\r\n\t\t\t\t\t_lightsNeedUpdate = false;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif ( refreshLights ) {\r\n\t\t\t\t\trefreshUniformsLights( m_uniforms, _lights );\r\n\t\t\t\t\tmarkUniformsLightsNeedsUpdate( m_uniforms, true );\r\n\t\t\t\t} else {\r\n\t\t\t\t\tmarkUniformsLightsNeedsUpdate( m_uniforms, false );\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( material instanceof THREE.MeshBasicMaterial ||\r\n\t\t\t\t material instanceof THREE.MeshLambertMaterial ||\r\n\t\t\t\t material instanceof THREE.MeshPhongMaterial ) {\r\n\r\n\t\t\t\trefreshUniformsCommon( m_uniforms, material );\r\n\r\n\t\t\t}\r\n\r\n\t\t\t// refresh single material specific uniforms\r\n\r\n\t\t\tif ( material instanceof THREE.LineBasicMaterial ) {\r\n\r\n\t\t\t\trefreshUniformsLine( m_uniforms, material );\r\n\r\n\t\t\t} else if ( material instanceof THREE.LineDashedMaterial ) {\r\n\r\n\t\t\t\trefreshUniformsLine( m_uniforms, material );\r\n\t\t\t\trefreshUniformsDash( m_uniforms, material );\r\n\r\n\t\t\t} else if ( material instanceof THREE.PointCloudMaterial ) {\r\n\r\n\t\t\t\trefreshUniformsParticle( m_uniforms, material );\r\n\r\n\t\t\t} else if ( material instanceof THREE.MeshPhongMaterial ) {\r\n\r\n\t\t\t\trefreshUniformsPhong( m_uniforms, material );\r\n\r\n\t\t\t} else if ( material instanceof THREE.MeshLambertMaterial ) {\r\n\r\n\t\t\t\trefreshUniformsLambert( m_uniforms, material );\r\n\r\n\t\t\t} else if ( material instanceof THREE.MeshDepthMaterial ) {\r\n\r\n\t\t\t\tm_uniforms.mNear.value = camera.near;\r\n\t\t\t\tm_uniforms.mFar.value = camera.far;\r\n\t\t\t\tm_uniforms.opacity.value = material.opacity;\r\n\r\n\t\t\t} else if ( material instanceof THREE.MeshNormalMaterial ) {\r\n\r\n\t\t\t\tm_uniforms.opacity.value = material.opacity;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( object.receiveShadow && ! material._shadowPass ) {\r\n\r\n\t\t\t\trefreshUniformsShadow( m_uniforms, lights );\r\n\r\n\t\t\t}\r\n\r\n\t\t\t// load common uniforms\r\n\r\n\t\t\tloadUniformsGeneric( material.uniformsList );\r\n\r\n\t\t}\r\n\r\n\t\tloadUniformsMatrices( p_uniforms, object );\r\n\r\n\t\tif ( p_uniforms.modelMatrix !== null ) {\r\n\r\n\t\t\t_gl.uniformMatrix4fv( p_uniforms.modelMatrix, false, object.matrixWorld.elements );\r\n\r\n\t\t}\r\n\r\n\t\treturn program;\r\n\r\n\t}\r\n\r\n\t// Uniforms (refresh uniforms objects)\r\n\r\n\tfunction refreshUniformsCommon ( uniforms, material ) {\r\n\r\n\t\tuniforms.opacity.value = material.opacity;\r\n\r\n\t\tuniforms.diffuse.value = material.color;\r\n\r\n\t\tuniforms.map.value = material.map;\r\n\t\tuniforms.lightMap.value = material.lightMap;\r\n\t\tuniforms.specularMap.value = material.specularMap;\r\n\t\tuniforms.alphaMap.value = material.alphaMap;\r\n\r\n\t\tif ( material.bumpMap ) {\r\n\r\n\t\t\tuniforms.bumpMap.value = material.bumpMap;\r\n\t\t\tuniforms.bumpScale.value = material.bumpScale;\r\n\r\n\t\t}\r\n\r\n\t\tif ( material.normalMap ) {\r\n\r\n\t\t\tuniforms.normalMap.value = material.normalMap;\r\n\t\t\tuniforms.normalScale.value.copy( material.normalScale );\r\n\r\n\t\t}\r\n\r\n\t\t// uv repeat and offset setting priorities\r\n\t\t// 1. color map\r\n\t\t// 2. specular map\r\n\t\t// 3. normal map\r\n\t\t// 4. bump map\r\n\t\t// 5. alpha map\r\n\r\n\t\tvar uvScaleMap;\r\n\r\n\t\tif ( material.map ) {\r\n\r\n\t\t\tuvScaleMap = material.map;\r\n\r\n\t\t} else if ( material.specularMap ) {\r\n\r\n\t\t\tuvScaleMap = material.specularMap;\r\n\r\n\t\t} else if ( material.normalMap ) {\r\n\r\n\t\t\tuvScaleMap = material.normalMap;\r\n\r\n\t\t} else if ( material.bumpMap ) {\r\n\r\n\t\t\tuvScaleMap = material.bumpMap;\r\n\r\n\t\t} else if ( material.alphaMap ) {\r\n\r\n\t\t\tuvScaleMap = material.alphaMap;\r\n\r\n\t\t}\r\n\r\n\t\tif ( uvScaleMap !== undefined ) {\r\n\r\n\t\t\tvar offset = uvScaleMap.offset;\r\n\t\t\tvar repeat = uvScaleMap.repeat;\r\n\r\n\t\t\tuniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y );\r\n\r\n\t\t}\r\n\r\n\t\tuniforms.envMap.value = material.envMap;\r\n\t\tuniforms.flipEnvMap.value = ( material.envMap instanceof THREE.WebGLRenderTargetCube ) ? 1 : - 1;\r\n\r\n\t\tuniforms.reflectivity.value = material.reflectivity;\r\n\t\tuniforms.refractionRatio.value = material.refractionRatio;\r\n\r\n\t}\r\n\r\n\tfunction refreshUniformsLine ( uniforms, material ) {\r\n\r\n\t\tuniforms.diffuse.value = material.color;\r\n\t\tuniforms.opacity.value = material.opacity;\r\n\r\n\t}\r\n\r\n\tfunction refreshUniformsDash ( uniforms, material ) {\r\n\r\n\t\tuniforms.dashSize.value = material.dashSize;\r\n\t\tuniforms.totalSize.value = material.dashSize + material.gapSize;\r\n\t\tuniforms.scale.value = material.scale;\r\n\r\n\t}\r\n\r\n\tfunction refreshUniformsParticle ( uniforms, material ) {\r\n\r\n\t\tuniforms.psColor.value = material.color;\r\n\t\tuniforms.opacity.value = material.opacity;\r\n\t\tuniforms.size.value = material.size;\r\n\t\tuniforms.scale.value = _canvas.height / 2.0; // TODO: Cache this.\r\n\r\n\t\tuniforms.map.value = material.map;\r\n\r\n\t\tif ( material.map !== null ) {\r\n\r\n\t\t\tvar offset = material.map.offset;\r\n\t\t\tvar repeat = material.map.repeat;\r\n\r\n\t\t\tuniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y );\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tfunction refreshUniformsFog ( uniforms, fog ) {\r\n\r\n\t\tuniforms.fogColor.value = fog.color;\r\n\r\n\t\tif ( fog instanceof THREE.Fog ) {\r\n\r\n\t\t\tuniforms.fogNear.value = fog.near;\r\n\t\t\tuniforms.fogFar.value = fog.far;\r\n\r\n\t\t} else if ( fog instanceof THREE.FogExp2 ) {\r\n\r\n\t\t\tuniforms.fogDensity.value = fog.density;\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tfunction refreshUniformsPhong ( uniforms, material ) {\r\n\r\n\t\tuniforms.shininess.value = material.shininess;\r\n\r\n\t\tuniforms.emissive.value = material.emissive;\r\n\t\tuniforms.specular.value = material.specular;\r\n\r\n\t\tif ( material.wrapAround ) {\r\n\r\n\t\t\tuniforms.wrapRGB.value.copy( material.wrapRGB );\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tfunction refreshUniformsLambert ( uniforms, material ) {\r\n\r\n\t\tuniforms.emissive.value = material.emissive;\r\n\r\n\t\tif ( material.wrapAround ) {\r\n\r\n\t\t\tuniforms.wrapRGB.value.copy( material.wrapRGB );\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tfunction refreshUniformsLights ( uniforms, lights ) {\r\n\r\n\t\tuniforms.ambientLightColor.value = lights.ambient;\r\n\r\n\t\tuniforms.directionalLightColor.value = lights.directional.colors;\r\n\t\tuniforms.directionalLightDirection.value = lights.directional.positions;\r\n\r\n\t\tuniforms.pointLightColor.value = lights.point.colors;\r\n\t\tuniforms.pointLightPosition.value = lights.point.positions;\r\n\t\tuniforms.pointLightDistance.value = lights.point.distances;\r\n\t\tuniforms.pointLightDecay.value = lights.point.decays;\r\n\r\n\t\tuniforms.spotLightColor.value = lights.spot.colors;\r\n\t\tuniforms.spotLightPosition.value = lights.spot.positions;\r\n\t\tuniforms.spotLightDistance.value = lights.spot.distances;\r\n\t\tuniforms.spotLightDirection.value = lights.spot.directions;\r\n\t\tuniforms.spotLightAngleCos.value = lights.spot.anglesCos;\r\n\t\tuniforms.spotLightExponent.value = lights.spot.exponents;\r\n\t\tuniforms.spotLightDecay.value = lights.spot.decays;\r\n\r\n\t\tuniforms.hemisphereLightSkyColor.value = lights.hemi.skyColors;\r\n\t\tuniforms.hemisphereLightGroundColor.value = lights.hemi.groundColors;\r\n\t\tuniforms.hemisphereLightDirection.value = lights.hemi.positions;\r\n\r\n\t}\r\n\r\n\t// If uniforms are marked as clean, they don't need to be loaded to the GPU.\r\n\r\n\tfunction markUniformsLightsNeedsUpdate ( uniforms, value ) {\r\n\r\n\t\tuniforms.ambientLightColor.needsUpdate = value;\r\n\r\n\t\tuniforms.directionalLightColor.needsUpdate = value;\r\n\t\tuniforms.directionalLightDirection.needsUpdate = value;\r\n\r\n\t\tuniforms.pointLightColor.needsUpdate = value;\r\n\t\tuniforms.pointLightPosition.needsUpdate = value;\r\n\t\tuniforms.pointLightDistance.needsUpdate = value;\r\n\t\tuniforms.pointLightDecay.needsUpdate = value;\r\n\r\n\t\tuniforms.spotLightColor.needsUpdate = value;\r\n\t\tuniforms.spotLightPosition.needsUpdate = value;\r\n\t\tuniforms.spotLightDistance.needsUpdate = value;\r\n\t\tuniforms.spotLightDirection.needsUpdate = value;\r\n\t\tuniforms.spotLightAngleCos.needsUpdate = value;\r\n\t\tuniforms.spotLightExponent.needsUpdate = value;\r\n\t\tuniforms.spotLightDecay.needsUpdate = value;\r\n\r\n\t\tuniforms.hemisphereLightSkyColor.needsUpdate = value;\r\n\t\tuniforms.hemisphereLightGroundColor.needsUpdate = value;\r\n\t\tuniforms.hemisphereLightDirection.needsUpdate = value;\r\n\r\n\t}\r\n\r\n\tfunction refreshUniformsShadow ( uniforms, lights ) {\r\n\r\n\t\tif ( uniforms.shadowMatrix ) {\r\n\r\n\t\t\tvar j = 0;\r\n\r\n\t\t\tfor ( var i = 0, il = lights.length; i < il; i ++ ) {\r\n\r\n\t\t\t\tvar light = lights[ i ];\r\n\r\n\t\t\t\tif ( ! light.castShadow ) continue;\r\n\r\n\t\t\t\tif ( light instanceof THREE.SpotLight || ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) ) {\r\n\r\n\t\t\t\t\tuniforms.shadowMap.value[ j ] = light.shadowMap;\r\n\t\t\t\t\tuniforms.shadowMapSize.value[ j ] = light.shadowMapSize;\r\n\r\n\t\t\t\t\tuniforms.shadowMatrix.value[ j ] = light.shadowMatrix;\r\n\r\n\t\t\t\t\tuniforms.shadowDarkness.value[ j ] = light.shadowDarkness;\r\n\t\t\t\t\tuniforms.shadowBias.value[ j ] = light.shadowBias;\r\n\r\n\t\t\t\t\tj ++;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t// Uniforms (load to GPU)\r\n\r\n\tfunction loadUniformsMatrices ( uniforms, object ) {\r\n\r\n\t\t_gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, object._modelViewMatrix.elements );\r\n\r\n\t\tif ( uniforms.normalMatrix ) {\r\n\r\n\t\t\t_gl.uniformMatrix3fv( uniforms.normalMatrix, false, object._normalMatrix.elements );\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tfunction getTextureUnit() {\r\n\r\n\t\tvar textureUnit = _usedTextureUnits;\r\n\r\n\t\tif ( textureUnit >= _maxTextures ) {\r\n\r\n\t\t\tTHREE.warn( 'WebGLRenderer: trying to use ' + textureUnit + ' texture units while this GPU supports only ' + _maxTextures );\r\n\r\n\t\t}\r\n\r\n\t\t_usedTextureUnits += 1;\r\n\r\n\t\treturn textureUnit;\r\n\r\n\t}\r\n\r\n\tfunction loadUniformsGeneric ( uniforms ) {\r\n\r\n\t\tvar texture, textureUnit, offset;\r\n\r\n\t\tfor ( var j = 0, jl = uniforms.length; j < jl; j ++ ) {\r\n\r\n\t\t\tvar uniform = uniforms[ j ][ 0 ];\r\n\r\n\t\t\t// needsUpdate property is not added to all uniforms.\r\n\t\t\tif ( uniform.needsUpdate === false ) continue;\r\n\r\n\t\t\tvar type = uniform.type;\r\n\t\t\tvar value = uniform.value;\r\n\t\t\tvar location = uniforms[ j ][ 1 ];\r\n\r\n\t\t\tswitch ( type ) {\r\n\r\n\t\t\t\tcase '1i':\r\n\t\t\t\t\t_gl.uniform1i( location, value );\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase '1f':\r\n\t\t\t\t\t_gl.uniform1f( location, value );\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase '2f':\r\n\t\t\t\t\t_gl.uniform2f( location, value[ 0 ], value[ 1 ] );\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase '3f':\r\n\t\t\t\t\t_gl.uniform3f( location, value[ 0 ], value[ 1 ], value[ 2 ] );\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase '4f':\r\n\t\t\t\t\t_gl.uniform4f( location, value[ 0 ], value[ 1 ], value[ 2 ], value[ 3 ] );\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase '1iv':\r\n\t\t\t\t\t_gl.uniform1iv( location, value );\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase '3iv':\r\n\t\t\t\t\t_gl.uniform3iv( location, value );\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase '1fv':\r\n\t\t\t\t\t_gl.uniform1fv( location, value );\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase '2fv':\r\n\t\t\t\t\t_gl.uniform2fv( location, value );\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase '3fv':\r\n\t\t\t\t\t_gl.uniform3fv( location, value );\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase '4fv':\r\n\t\t\t\t\t_gl.uniform4fv( location, value );\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 'Matrix3fv':\r\n\t\t\t\t\t_gl.uniformMatrix3fv( location, false, value );\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 'Matrix4fv':\r\n\t\t\t\t\t_gl.uniformMatrix4fv( location, false, value );\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t//\r\n\r\n\t\t\t\tcase 'i':\r\n\r\n\t\t\t\t\t// single integer\r\n\t\t\t\t\t_gl.uniform1i( location, value );\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 'f':\r\n\r\n\t\t\t\t\t// single float\r\n\t\t\t\t\t_gl.uniform1f( location, value );\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 'v2':\r\n\r\n\t\t\t\t\t// single THREE.Vector2\r\n\t\t\t\t\t_gl.uniform2f( location, value.x, value.y );\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 'v3':\r\n\r\n\t\t\t\t\t// single THREE.Vector3\r\n\t\t\t\t\t_gl.uniform3f( location, value.x, value.y, value.z );\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 'v4':\r\n\r\n\t\t\t\t\t// single THREE.Vector4\r\n\t\t\t\t\t_gl.uniform4f( location, value.x, value.y, value.z, value.w );\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 'c':\r\n\r\n\t\t\t\t\t// single THREE.Color\r\n\t\t\t\t\t_gl.uniform3f( location, value.r, value.g, value.b );\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 'iv1':\r\n\r\n\t\t\t\t\t// flat array of integers (JS or typed array)\r\n\t\t\t\t\t_gl.uniform1iv( location, value );\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 'iv':\r\n\r\n\t\t\t\t\t// flat array of integers with 3 x N size (JS or typed array)\r\n\t\t\t\t\t_gl.uniform3iv( location, value );\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 'fv1':\r\n\r\n\t\t\t\t\t// flat array of floats (JS or typed array)\r\n\t\t\t\t\t_gl.uniform1fv( location, value );\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 'fv':\r\n\r\n\t\t\t\t\t// flat array of floats with 3 x N size (JS or typed array)\r\n\t\t\t\t\t_gl.uniform3fv( location, value );\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 'v2v':\r\n\r\n\t\t\t\t\t// array of THREE.Vector2\r\n\r\n\t\t\t\t\tif ( uniform._array === undefined ) {\r\n\r\n\t\t\t\t\t\tuniform._array = new Float32Array( 2 * value.length );\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tfor ( var i = 0, il = value.length; i < il; i ++ ) {\r\n\r\n\t\t\t\t\t\toffset = i * 2;\r\n\r\n\t\t\t\t\t\tuniform._array[ offset ] = value[ i ].x;\r\n\t\t\t\t\t\tuniform._array[ offset + 1 ] = value[ i ].y;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t_gl.uniform2fv( location, uniform._array );\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 'v3v':\r\n\r\n\t\t\t\t\t// array of THREE.Vector3\r\n\r\n\t\t\t\t\tif ( uniform._array === undefined ) {\r\n\r\n\t\t\t\t\t\tuniform._array = new Float32Array( 3 * value.length );\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tfor ( var i = 0, il = value.length; i < il; i ++ ) {\r\n\r\n\t\t\t\t\t\toffset = i * 3;\r\n\r\n\t\t\t\t\t\tuniform._array[ offset ] = value[ i ].x;\r\n\t\t\t\t\t\tuniform._array[ offset + 1 ] = value[ i ].y;\r\n\t\t\t\t\t\tuniform._array[ offset + 2 ] = value[ i ].z;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t_gl.uniform3fv( location, uniform._array );\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 'v4v':\r\n\r\n\t\t\t\t\t// array of THREE.Vector4\r\n\r\n\t\t\t\t\tif ( uniform._array === undefined ) {\r\n\r\n\t\t\t\t\t\tuniform._array = new Float32Array( 4 * value.length );\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tfor ( var i = 0, il = value.length; i < il; i ++ ) {\r\n\r\n\t\t\t\t\t\toffset = i * 4;\r\n\r\n\t\t\t\t\t\tuniform._array[ offset ] = value[ i ].x;\r\n\t\t\t\t\t\tuniform._array[ offset + 1 ] = value[ i ].y;\r\n\t\t\t\t\t\tuniform._array[ offset + 2 ] = value[ i ].z;\r\n\t\t\t\t\t\tuniform._array[ offset + 3 ] = value[ i ].w;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t_gl.uniform4fv( location, uniform._array );\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 'm3':\r\n\r\n\t\t\t\t\t// single THREE.Matrix3\r\n\t\t\t\t\t_gl.uniformMatrix3fv( location, false, value.elements );\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 'm3v':\r\n\r\n\t\t\t\t\t// array of THREE.Matrix3\r\n\r\n\t\t\t\t\tif ( uniform._array === undefined ) {\r\n\r\n\t\t\t\t\t\tuniform._array = new Float32Array( 9 * value.length );\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tfor ( var i = 0, il = value.length; i < il; i ++ ) {\r\n\r\n\t\t\t\t\t\tvalue[ i ].flattenToArrayOffset( uniform._array, i * 9 );\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t_gl.uniformMatrix3fv( location, false, uniform._array );\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 'm4':\r\n\r\n\t\t\t\t\t// single THREE.Matrix4\r\n\t\t\t\t\t_gl.uniformMatrix4fv( location, false, value.elements );\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 'm4v':\r\n\r\n\t\t\t\t\t// array of THREE.Matrix4\r\n\r\n\t\t\t\t\tif ( uniform._array === undefined ) {\r\n\r\n\t\t\t\t\t\tuniform._array = new Float32Array( 16 * value.length );\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tfor ( var i = 0, il = value.length; i < il; i ++ ) {\r\n\r\n\t\t\t\t\t\tvalue[ i ].flattenToArrayOffset( uniform._array, i * 16 );\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t_gl.uniformMatrix4fv( location, false, uniform._array );\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 't':\r\n\r\n\t\t\t\t\t// single THREE.Texture (2d or cube)\r\n\r\n\t\t\t\t\ttexture = value;\r\n\t\t\t\t\ttextureUnit = getTextureUnit();\r\n\r\n\t\t\t\t\t_gl.uniform1i( location, textureUnit );\r\n\r\n\t\t\t\t\tif ( ! texture ) continue;\r\n\r\n\t\t\t\t\tif ( texture instanceof THREE.CubeTexture ||\r\n\t\t\t\t\t ( texture.image instanceof Array && texture.image.length === 6 ) ) { // CompressedTexture can have Array in image :/\r\n\r\n\t\t\t\t\t\tsetCubeTexture( texture, textureUnit );\r\n\r\n\t\t\t\t\t} else if ( texture instanceof THREE.WebGLRenderTargetCube ) {\r\n\r\n\t\t\t\t\t\tsetCubeTextureDynamic( texture, textureUnit );\r\n\r\n\t\t\t\t\t} else {\r\n\r\n\t\t\t\t\t\t_this.setTexture( texture, textureUnit );\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 'tv':\r\n\r\n\t\t\t\t\t// array of THREE.Texture (2d)\r\n\r\n\t\t\t\t\tif ( uniform._array === undefined ) {\r\n\r\n\t\t\t\t\t\tuniform._array = [];\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tfor ( var i = 0, il = uniform.value.length; i < il; i ++ ) {\r\n\r\n\t\t\t\t\t\tuniform._array[ i ] = getTextureUnit();\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t_gl.uniform1iv( location, uniform._array );\r\n\r\n\t\t\t\t\tfor ( var i = 0, il = uniform.value.length; i < il; i ++ ) {\r\n\r\n\t\t\t\t\t\ttexture = uniform.value[ i ];\r\n\t\t\t\t\t\ttextureUnit = uniform._array[ i ];\r\n\r\n\t\t\t\t\t\tif ( ! texture ) continue;\r\n\r\n\t\t\t\t\t\t_this.setTexture( texture, textureUnit );\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tdefault:\r\n\r\n\t\t\t\t\tTHREE.warn( 'THREE.WebGLRenderer: Unknown uniform type: ' + type );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tfunction setupMatrices ( object, camera ) {\r\n\r\n\t\tobject._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );\r\n\t\tobject._normalMatrix.getNormalMatrix( object._modelViewMatrix );\r\n\r\n\t}\r\n\r\n\tfunction setColorLinear( array, offset, color, intensity ) {\r\n\r\n\t\tarray[ offset ] = color.r * intensity;\r\n\t\tarray[ offset + 1 ] = color.g * intensity;\r\n\t\tarray[ offset + 2 ] = color.b * intensity;\r\n\r\n\t}\r\n\r\n\tfunction setupLights ( lights ) {\r\n\r\n\t\tvar l, ll, light,\r\n\t\tr = 0, g = 0, b = 0,\r\n\t\tcolor, skyColor, groundColor,\r\n\t\tintensity,\r\n\t\tdistance,\r\n\r\n\t\tzlights = _lights,\r\n\r\n\t\tdirColors = zlights.directional.colors,\r\n\t\tdirPositions = zlights.directional.positions,\r\n\r\n\t\tpointColors = zlights.point.colors,\r\n\t\tpointPositions = zlights.point.positions,\r\n\t\tpointDistances = zlights.point.distances,\r\n\t\tpointDecays = zlights.point.decays,\r\n\r\n\t\tspotColors = zlights.spot.colors,\r\n\t\tspotPositions = zlights.spot.positions,\r\n\t\tspotDistances = zlights.spot.distances,\r\n\t\tspotDirections = zlights.spot.directions,\r\n\t\tspotAnglesCos = zlights.spot.anglesCos,\r\n\t\tspotExponents = zlights.spot.exponents,\r\n\t\tspotDecays = zlights.spot.decays,\r\n\r\n\t\themiSkyColors = zlights.hemi.skyColors,\r\n\t\themiGroundColors = zlights.hemi.groundColors,\r\n\t\themiPositions = zlights.hemi.positions,\r\n\r\n\t\tdirLength = 0,\r\n\t\tpointLength = 0,\r\n\t\tspotLength = 0,\r\n\t\themiLength = 0,\r\n\r\n\t\tdirCount = 0,\r\n\t\tpointCount = 0,\r\n\t\tspotCount = 0,\r\n\t\themiCount = 0,\r\n\r\n\t\tdirOffset = 0,\r\n\t\tpointOffset = 0,\r\n\t\tspotOffset = 0,\r\n\t\themiOffset = 0;\r\n\r\n\t\tfor ( l = 0, ll = lights.length; l < ll; l ++ ) {\r\n\r\n\t\t\tlight = lights[ l ];\r\n\r\n\t\t\tif ( light.onlyShadow ) continue;\r\n\r\n\t\t\tcolor = light.color;\r\n\t\t\tintensity = light.intensity;\r\n\t\t\tdistance = light.distance;\r\n\r\n\t\t\tif ( light instanceof THREE.AmbientLight ) {\r\n\r\n\t\t\t\tif ( ! light.visible ) continue;\r\n\r\n\t\t\t\tr += color.r;\r\n\t\t\t\tg += color.g;\r\n\t\t\t\tb += color.b;\r\n\r\n\t\t\t} else if ( light instanceof THREE.DirectionalLight ) {\r\n\r\n\t\t\t\tdirCount += 1;\r\n\r\n\t\t\t\tif ( ! light.visible ) continue;\r\n\r\n\t\t\t\t_direction.setFromMatrixPosition( light.matrixWorld );\r\n\t\t\t\t_vector3.setFromMatrixPosition( light.target.matrixWorld );\r\n\t\t\t\t_direction.sub( _vector3 );\r\n\t\t\t\t_direction.normalize();\r\n\r\n\t\t\t\tdirOffset = dirLength * 3;\r\n\r\n\t\t\t\tdirPositions[ dirOffset ] = _direction.x;\r\n\t\t\t\tdirPositions[ dirOffset + 1 ] = _direction.y;\r\n\t\t\t\tdirPositions[ dirOffset + 2 ] = _direction.z;\r\n\r\n\t\t\t\tsetColorLinear( dirColors, dirOffset, color, intensity );\r\n\r\n\t\t\t\tdirLength += 1;\r\n\r\n\t\t\t} else if ( light instanceof THREE.PointLight ) {\r\n\r\n\t\t\t\tpointCount += 1;\r\n\r\n\t\t\t\tif ( ! light.visible ) continue;\r\n\r\n\t\t\t\tpointOffset = pointLength * 3;\r\n\r\n\t\t\t\tsetColorLinear( pointColors, pointOffset, color, intensity );\r\n\r\n\t\t\t\t_vector3.setFromMatrixPosition( light.matrixWorld );\r\n\r\n\t\t\t\tpointPositions[ pointOffset ] = _vector3.x;\r\n\t\t\t\tpointPositions[ pointOffset + 1 ] = _vector3.y;\r\n\t\t\t\tpointPositions[ pointOffset + 2 ] = _vector3.z;\r\n\r\n\t\t\t\t// distance is 0 if decay is 0, because there is no attenuation at all.\r\n\t\t\t\tpointDistances[ pointLength ] = distance;\r\n\t\t\t\tpointDecays[ pointLength ] = ( light.distance === 0 ) ? 0.0 : light.decay;\r\n\r\n\t\t\t\tpointLength += 1;\r\n\r\n\t\t\t} else if ( light instanceof THREE.SpotLight ) {\r\n\r\n\t\t\t\tspotCount += 1;\r\n\r\n\t\t\t\tif ( ! light.visible ) continue;\r\n\r\n\t\t\t\tspotOffset = spotLength * 3;\r\n\r\n\t\t\t\tsetColorLinear( spotColors, spotOffset, color, intensity );\r\n\r\n\t\t\t\t_direction.setFromMatrixPosition( light.matrixWorld );\r\n\r\n\t\t\t\tspotPositions[ spotOffset ] = _direction.x;\r\n\t\t\t\tspotPositions[ spotOffset + 1 ] = _direction.y;\r\n\t\t\t\tspotPositions[ spotOffset + 2 ] = _direction.z;\r\n\r\n\t\t\t\tspotDistances[ spotLength ] = distance;\r\n\r\n\t\t\t\t_vector3.setFromMatrixPosition( light.target.matrixWorld );\r\n\t\t\t\t_direction.sub( _vector3 );\r\n\t\t\t\t_direction.normalize();\r\n\r\n\t\t\t\tspotDirections[ spotOffset ] = _direction.x;\r\n\t\t\t\tspotDirections[ spotOffset + 1 ] = _direction.y;\r\n\t\t\t\tspotDirections[ spotOffset + 2 ] = _direction.z;\r\n\r\n\t\t\t\tspotAnglesCos[ spotLength ] = Math.cos( light.angle );\r\n\t\t\t\tspotExponents[ spotLength ] = light.exponent;\r\n\t\t\t\tspotDecays[ spotLength ] = ( light.distance === 0 ) ? 0.0 : light.decay;\r\n\r\n\t\t\t\tspotLength += 1;\r\n\r\n\t\t\t} else if ( light instanceof THREE.HemisphereLight ) {\r\n\r\n\t\t\t\themiCount += 1;\r\n\r\n\t\t\t\tif ( ! light.visible ) continue;\r\n\r\n\t\t\t\t_direction.setFromMatrixPosition( light.matrixWorld );\r\n\t\t\t\t_direction.normalize();\r\n\r\n\t\t\t\themiOffset = hemiLength * 3;\r\n\r\n\t\t\t\themiPositions[ hemiOffset ] = _direction.x;\r\n\t\t\t\themiPositions[ hemiOffset + 1 ] = _direction.y;\r\n\t\t\t\themiPositions[ hemiOffset + 2 ] = _direction.z;\r\n\r\n\t\t\t\tskyColor = light.color;\r\n\t\t\t\tgroundColor = light.groundColor;\r\n\r\n\t\t\t\tsetColorLinear( hemiSkyColors, hemiOffset, skyColor, intensity );\r\n\t\t\t\tsetColorLinear( hemiGroundColors, hemiOffset, groundColor, intensity );\r\n\r\n\t\t\t\themiLength += 1;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\t// null eventual remains from removed lights\r\n\t\t// (this is to avoid if in shader)\r\n\r\n\t\tfor ( l = dirLength * 3, ll = Math.max( dirColors.length, dirCount * 3 ); l < ll; l ++ ) dirColors[ l ] = 0.0;\r\n\t\tfor ( l = pointLength * 3, ll = Math.max( pointColors.length, pointCount * 3 ); l < ll; l ++ ) pointColors[ l ] = 0.0;\r\n\t\tfor ( l = spotLength * 3, ll = Math.max( spotColors.length, spotCount * 3 ); l < ll; l ++ ) spotColors[ l ] = 0.0;\r\n\t\tfor ( l = hemiLength * 3, ll = Math.max( hemiSkyColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiSkyColors[ l ] = 0.0;\r\n\t\tfor ( l = hemiLength * 3, ll = Math.max( hemiGroundColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiGroundColors[ l ] = 0.0;\r\n\r\n\t\tzlights.directional.length = dirLength;\r\n\t\tzlights.point.length = pointLength;\r\n\t\tzlights.spot.length = spotLength;\r\n\t\tzlights.hemi.length = hemiLength;\r\n\r\n\t\tzlights.ambient[ 0 ] = r;\r\n\t\tzlights.ambient[ 1 ] = g;\r\n\t\tzlights.ambient[ 2 ] = b;\r\n\r\n\t}\r\n\r\n\t// GL state setting\r\n\r\n\tthis.setFaceCulling = function ( cullFace, frontFaceDirection ) {\r\n\r\n\t\tif ( cullFace === THREE.CullFaceNone ) {\r\n\r\n\t\t\t_gl.disable( _gl.CULL_FACE );\r\n\r\n\t\t} else {\r\n\r\n\t\t\tif ( frontFaceDirection === THREE.FrontFaceDirectionCW ) {\r\n\r\n\t\t\t\t_gl.frontFace( _gl.CW );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\t_gl.frontFace( _gl.CCW );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( cullFace === THREE.CullFaceBack ) {\r\n\r\n\t\t\t\t_gl.cullFace( _gl.BACK );\r\n\r\n\t\t\t} else if ( cullFace === THREE.CullFaceFront ) {\r\n\r\n\t\t\t\t_gl.cullFace( _gl.FRONT );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\t_gl.cullFace( _gl.FRONT_AND_BACK );\r\n\r\n\t\t\t}\r\n\r\n\t\t\t_gl.enable( _gl.CULL_FACE );\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n\tthis.setMaterialFaces = function ( material ) {\r\n\r\n\t\tstate.setDoubleSided( material.side === THREE.DoubleSide );\r\n\t\tstate.setFlipSided( material.side === THREE.BackSide );\r\n\r\n\t};\r\n\r\n\t// Textures\r\n\r\n\tfunction setTextureParameters ( textureType, texture, isImagePowerOfTwo ) {\r\n\r\n\t\tvar extension;\r\n\r\n\t\tif ( isImagePowerOfTwo ) {\r\n\r\n\t\t\t_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, paramThreeToGL( texture.wrapS ) );\r\n\t\t\t_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, paramThreeToGL( texture.wrapT ) );\r\n\r\n\t\t\t_gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, paramThreeToGL( texture.magFilter ) );\r\n\t\t\t_gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, paramThreeToGL( texture.minFilter ) );\r\n\r\n\t\t} else {\r\n\r\n\t\t\t_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );\r\n\t\t\t_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );\r\n\r\n\t\t\tif ( texture.wrapS !== THREE.ClampToEdgeWrapping || texture.wrapT !== THREE.ClampToEdgeWrapping ) {\r\n\r\n\t\t\t\tTHREE.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping. ( ' + texture.sourceFile + ' )' );\r\n\r\n\t\t\t}\r\n\r\n\t\t\t_gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) );\r\n\t\t\t_gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) );\r\n\r\n\t\t\tif ( texture.minFilter !== THREE.NearestFilter && texture.minFilter !== THREE.LinearFilter ) {\r\n\r\n\t\t\t\tTHREE.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter. ( ' + texture.sourceFile + ' )' );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\textension = extensions.get( 'EXT_texture_filter_anisotropic' );\r\n\r\n\t\tif ( extension && texture.type !== THREE.FloatType && texture.type !== THREE.HalfFloatType ) {\r\n\r\n\t\t\tif ( texture.anisotropy > 1 || texture.__currentAnisotropy ) {\r\n\r\n\t\t\t\t_gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, _this.getMaxAnisotropy() ) );\r\n\t\t\t\ttexture.__currentAnisotropy = texture.anisotropy;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tthis.uploadTexture = function ( texture ) {\r\n\r\n\t\tif ( texture.__webglInit === undefined ) {\r\n\r\n\t\t\ttexture.__webglInit = true;\r\n\r\n\t\t\ttexture.addEventListener( 'dispose', onTextureDispose );\r\n\r\n\t\t\ttexture.__webglTexture = _gl.createTexture();\r\n\r\n\t\t\t_this.info.memory.textures ++;\r\n\r\n\t\t}\r\n\r\n\t\t_gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );\r\n\r\n\t\t_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );\r\n\t\t_gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );\r\n\t\t_gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );\r\n\r\n\t\ttexture.image = clampToMaxSize( texture.image, _maxTextureSize );\r\n\r\n\t\tvar image = texture.image,\r\n\t\tisImagePowerOfTwo = THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.isPowerOfTwo( image.height ),\r\n\t\tglFormat = paramThreeToGL( texture.format ),\r\n\t\tglType = paramThreeToGL( texture.type );\r\n\r\n\t\tsetTextureParameters( _gl.TEXTURE_2D, texture, isImagePowerOfTwo );\r\n\r\n\t\tvar mipmap, mipmaps = texture.mipmaps;\r\n\r\n\t\tif ( texture instanceof THREE.DataTexture ) {\r\n\r\n\t\t\t// use manually created mipmaps if available\r\n\t\t\t// if there are no manual mipmaps\r\n\t\t\t// set 0 level mipmap and then use GL to generate other mipmap levels\r\n\r\n\t\t\tif ( mipmaps.length > 0 && isImagePowerOfTwo ) {\r\n\r\n\t\t\t\tfor ( var i = 0, il = mipmaps.length; i < il; i ++ ) {\r\n\r\n\t\t\t\t\tmipmap = mipmaps[ i ];\r\n\t\t\t\t\t_gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\ttexture.generateMipmaps = false;\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\t_gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data );\r\n\r\n\t\t\t}\r\n\r\n\t\t} else if ( texture instanceof THREE.CompressedTexture ) {\r\n\r\n\t\t\tfor ( var i = 0, il = mipmaps.length; i < il; i ++ ) {\r\n\r\n\t\t\t\tmipmap = mipmaps[ i ];\r\n\r\n\t\t\t\tif ( texture.format !== THREE.RGBAFormat && texture.format !== THREE.RGBFormat ) {\r\n\r\n\t\t\t\t\tif ( getCompressedTextureFormats().indexOf( glFormat ) > -1 ) {\r\n\r\n\t\t\t\t\t\t_gl.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );\r\n\r\n\t\t\t\t\t} else {\r\n\r\n\t\t\t\t\t\tTHREE.warn( \"THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()\" );\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\t_gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t} else { // regular Texture (image, video, canvas)\r\n\r\n\t\t\t// use manually created mipmaps if available\r\n\t\t\t// if there are no manual mipmaps\r\n\t\t\t// set 0 level mipmap and then use GL to generate other mipmap levels\r\n\r\n\t\t\tif ( mipmaps.length > 0 && isImagePowerOfTwo ) {\r\n\r\n\t\t\t\tfor ( var i = 0, il = mipmaps.length; i < il; i ++ ) {\r\n\r\n\t\t\t\t\tmipmap = mipmaps[ i ];\r\n\t\t\t\t\t_gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\ttexture.generateMipmaps = false;\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\t_gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, texture.image );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tif ( texture.generateMipmaps && isImagePowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D );\r\n\r\n\t\ttexture.needsUpdate = false;\r\n\r\n\t\tif ( texture.onUpdate ) texture.onUpdate();\r\n\r\n\t};\r\n\r\n\tthis.setTexture = function ( texture, slot ) {\r\n\r\n\t\t_gl.activeTexture( _gl.TEXTURE0 + slot );\r\n\r\n\t\tif ( texture.needsUpdate ) {\r\n\r\n\t\t\t_this.uploadTexture( texture );\r\n\r\n\t\t} else {\r\n\r\n\t\t\t_gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n\tfunction clampToMaxSize ( image, maxSize ) {\r\n\r\n\t\tif ( image.width > maxSize || image.height > maxSize ) {\r\n\r\n\t\t\t// Warning: Scaling through the canvas will only work with images that use\r\n\t\t\t// premultiplied alpha.\r\n\r\n\t\t\tvar scale = maxSize / Math.max( image.width, image.height );\r\n\r\n\t\t\tvar canvas = document.createElement( 'canvas' );\r\n\t\t\tcanvas.width = Math.floor( image.width * scale );\r\n\t\t\tcanvas.height = Math.floor( image.height * scale );\r\n\r\n\t\t\tvar context = canvas.getContext( '2d' );\r\n\t\t\tcontext.drawImage( image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height );\r\n\r\n\t\t\tTHREE.warn( 'THREE.WebGLRenderer: image is too big (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height, image );\r\n\r\n\t\t\treturn canvas;\r\n\r\n\t\t}\r\n\r\n\t\treturn image;\r\n\r\n\t}\r\n\r\n\tfunction setCubeTexture ( texture, slot ) {\r\n\r\n\t\tif ( texture.image.length === 6 ) {\r\n\r\n\t\t\tif ( texture.needsUpdate ) {\r\n\r\n\t\t\t\tif ( ! texture.image.__webglTextureCube ) {\r\n\r\n\t\t\t\t\ttexture.addEventListener( 'dispose', onTextureDispose );\r\n\r\n\t\t\t\t\ttexture.image.__webglTextureCube = _gl.createTexture();\r\n\r\n\t\t\t\t\t_this.info.memory.textures ++;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\t_gl.activeTexture( _gl.TEXTURE0 + slot );\r\n\t\t\t\t_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube );\r\n\r\n\t\t\t\t_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );\r\n\r\n\t\t\t\tvar isCompressed = texture instanceof THREE.CompressedTexture;\r\n\t\t\t\tvar isDataTexture = texture.image[ 0 ] instanceof THREE.DataTexture;\r\n\r\n\t\t\t\tvar cubeImage = [];\r\n\r\n\t\t\t\tfor ( var i = 0; i < 6; i ++ ) {\r\n\r\n\t\t\t\t\tif ( _this.autoScaleCubemaps && ! isCompressed && ! isDataTexture ) {\r\n\r\n\t\t\t\t\t\tcubeImage[ i ] = clampToMaxSize( texture.image[ i ], _maxCubemapSize );\r\n\r\n\t\t\t\t\t} else {\r\n\r\n\t\t\t\t\t\tcubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ];\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvar image = cubeImage[ 0 ],\r\n\t\t\t\tisImagePowerOfTwo = THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.isPowerOfTwo( image.height ),\r\n\t\t\t\tglFormat = paramThreeToGL( texture.format ),\r\n\t\t\t\tglType = paramThreeToGL( texture.type );\r\n\r\n\t\t\t\tsetTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, isImagePowerOfTwo );\r\n\r\n\t\t\t\tfor ( var i = 0; i < 6; i ++ ) {\r\n\r\n\t\t\t\t\tif ( ! isCompressed ) {\r\n\r\n\t\t\t\t\t\tif ( isDataTexture ) {\r\n\r\n\t\t\t\t\t\t\t_gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data );\r\n\r\n\t\t\t\t\t\t} else {\r\n\r\n\t\t\t\t\t\t\t_gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] );\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t} else {\r\n\r\n\t\t\t\t\t\tvar mipmap, mipmaps = cubeImage[ i ].mipmaps;\r\n\r\n\t\t\t\t\t\tfor ( var j = 0, jl = mipmaps.length; j < jl; j ++ ) {\r\n\r\n\t\t\t\t\t\t\tmipmap = mipmaps[ j ];\r\n\r\n\t\t\t\t\t\t\tif ( texture.format !== THREE.RGBAFormat && texture.format !== THREE.RGBFormat ) {\r\n\r\n\t\t\t\t\t\t\t\tif ( getCompressedTextureFormats().indexOf( glFormat ) > -1 ) {\r\n\r\n\t\t\t\t\t\t\t\t\t_gl.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );\r\n\r\n\t\t\t\t\t\t\t\t} else {\r\n\r\n\t\t\t\t\t\t\t\t\tTHREE.warn( \"THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setCubeTexture()\" );\r\n\r\n\t\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t} else {\r\n\r\n\t\t\t\t\t\t\t\t_gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );\r\n\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif ( texture.generateMipmaps && isImagePowerOfTwo ) {\r\n\r\n\t\t\t\t\t_gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\ttexture.needsUpdate = false;\r\n\r\n\t\t\t\tif ( texture.onUpdate ) texture.onUpdate();\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\t_gl.activeTexture( _gl.TEXTURE0 + slot );\r\n\t\t\t\t_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tfunction setCubeTextureDynamic ( texture, slot ) {\r\n\r\n\t\t_gl.activeTexture( _gl.TEXTURE0 + slot );\r\n\t\t_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.__webglTexture );\r\n\r\n\t}\r\n\r\n\t// Render targets\r\n\r\n\tfunction setupFrameBuffer ( framebuffer, renderTarget, textureTarget ) {\r\n\r\n\t\t_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );\r\n\t\t_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureTarget, renderTarget.__webglTexture, 0 );\r\n\r\n\t}\r\n\r\n\tfunction setupRenderBuffer ( renderbuffer, renderTarget ) {\r\n\r\n\t\t_gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer );\r\n\r\n\t\tif ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {\r\n\r\n\t\t\t_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height );\r\n\t\t\t_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );\r\n\r\n\t\t/* For some reason this is not working. Defaulting to RGBA4.\r\n\t\t} else if ( ! renderTarget.depthBuffer && renderTarget.stencilBuffer ) {\r\n\r\n\t\t\t_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.STENCIL_INDEX8, renderTarget.width, renderTarget.height );\r\n\t\t\t_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );\r\n\t\t*/\r\n\t\t} else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {\r\n\r\n\t\t\t_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height );\r\n\t\t\t_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );\r\n\r\n\t\t} else {\r\n\r\n\t\t\t_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height );\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tthis.setRenderTarget = function ( renderTarget ) {\r\n\r\n\t\tvar isCube = ( renderTarget instanceof THREE.WebGLRenderTargetCube );\r\n\r\n\t\tif ( renderTarget && renderTarget.__webglFramebuffer === undefined ) {\r\n\r\n\t\t\tif ( renderTarget.depthBuffer === undefined ) renderTarget.depthBuffer = true;\r\n\t\t\tif ( renderTarget.stencilBuffer === undefined ) renderTarget.stencilBuffer = true;\r\n\r\n\t\t\trenderTarget.addEventListener( 'dispose', onRenderTargetDispose );\r\n\r\n\t\t\trenderTarget.__webglTexture = _gl.createTexture();\r\n\r\n\t\t\t_this.info.memory.textures ++;\r\n\r\n\t\t\t// Setup texture, create render and frame buffers\r\n\r\n\t\t\tvar isTargetPowerOfTwo = THREE.Math.isPowerOfTwo( renderTarget.width ) && THREE.Math.isPowerOfTwo( renderTarget.height ),\r\n\t\t\t\tglFormat = paramThreeToGL( renderTarget.format ),\r\n\t\t\t\tglType = paramThreeToGL( renderTarget.type );\r\n\r\n\t\t\tif ( isCube ) {\r\n\r\n\t\t\t\trenderTarget.__webglFramebuffer = [];\r\n\t\t\t\trenderTarget.__webglRenderbuffer = [];\r\n\r\n\t\t\t\t_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture );\r\n\t\t\t\tsetTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget, isTargetPowerOfTwo );\r\n\r\n\t\t\t\tfor ( var i = 0; i < 6; i ++ ) {\r\n\r\n\t\t\t\t\trenderTarget.__webglFramebuffer[ i ] = _gl.createFramebuffer();\r\n\t\t\t\t\trenderTarget.__webglRenderbuffer[ i ] = _gl.createRenderbuffer();\r\n\r\n\t\t\t\t\t_gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );\r\n\r\n\t\t\t\t\tsetupFrameBuffer( renderTarget.__webglFramebuffer[ i ], renderTarget, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i );\r\n\t\t\t\t\tsetupRenderBuffer( renderTarget.__webglRenderbuffer[ i ], renderTarget );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\trenderTarget.__webglFramebuffer = _gl.createFramebuffer();\r\n\r\n\t\t\t\tif ( renderTarget.shareDepthFrom ) {\r\n\r\n\t\t\t\t\trenderTarget.__webglRenderbuffer = renderTarget.shareDepthFrom.__webglRenderbuffer;\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\trenderTarget.__webglRenderbuffer = _gl.createRenderbuffer();\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\t_gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture );\r\n\t\t\t\tsetTextureParameters( _gl.TEXTURE_2D, renderTarget, isTargetPowerOfTwo );\r\n\r\n\t\t\t\t_gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );\r\n\r\n\t\t\t\tsetupFrameBuffer( renderTarget.__webglFramebuffer, renderTarget, _gl.TEXTURE_2D );\r\n\r\n\t\t\t\tif ( renderTarget.shareDepthFrom ) {\r\n\r\n\t\t\t\t\tif ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {\r\n\r\n\t\t\t\t\t\t_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer );\r\n\r\n\t\t\t\t\t} else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {\r\n\r\n\t\t\t\t\t\t_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer );\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\tsetupRenderBuffer( renderTarget.__webglRenderbuffer, renderTarget );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D );\r\n\r\n\t\t\t}\r\n\r\n\t\t\t// Release everything\r\n\r\n\t\t\tif ( isCube ) {\r\n\r\n\t\t\t\t_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\t_gl.bindTexture( _gl.TEXTURE_2D, null );\r\n\r\n\t\t\t}\r\n\r\n\t\t\t_gl.bindRenderbuffer( _gl.RENDERBUFFER, null );\r\n\t\t\t_gl.bindFramebuffer( _gl.FRAMEBUFFER, null );\r\n\r\n\t\t}\r\n\r\n\t\tvar framebuffer, width, height, vx, vy;\r\n\r\n\t\tif ( renderTarget ) {\r\n\r\n\t\t\tif ( isCube ) {\r\n\r\n\t\t\t\tframebuffer = renderTarget.__webglFramebuffer[ renderTarget.activeCubeFace ];\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tframebuffer = renderTarget.__webglFramebuffer;\r\n\r\n\t\t\t}\r\n\r\n\t\t\twidth = renderTarget.width;\r\n\t\t\theight = renderTarget.height;\r\n\r\n\t\t\tvx = 0;\r\n\t\t\tvy = 0;\r\n\r\n\t\t} else {\r\n\r\n\t\t\tframebuffer = null;\r\n\r\n\t\t\twidth = _viewportWidth;\r\n\t\t\theight = _viewportHeight;\r\n\r\n\t\t\tvx = _viewportX;\r\n\t\t\tvy = _viewportY;\r\n\r\n\t\t}\r\n\r\n\t\tif ( framebuffer !== _currentFramebuffer ) {\r\n\r\n\t\t\t_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );\r\n\t\t\t_gl.viewport( vx, vy, width, height );\r\n\r\n\t\t\t_currentFramebuffer = framebuffer;\r\n\r\n\t\t}\r\n\r\n\t\t_currentWidth = width;\r\n\t\t_currentHeight = height;\r\n\r\n\t};\r\n\r\n\tthis.readRenderTargetPixels = function( renderTarget, x, y, width, height, buffer ) {\r\n\r\n\t\tif ( ! ( renderTarget instanceof THREE.WebGLRenderTarget ) ) {\r\n\r\n\t\t\tconsole.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' );\r\n\t\t\treturn;\r\n\r\n\t\t}\r\n\r\n\t\tif ( renderTarget.__webglFramebuffer ) {\r\n\r\n\t\t\tif ( renderTarget.format !== THREE.RGBAFormat ) {\r\n\r\n\t\t\t\tconsole.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA format. readPixels can read only RGBA format.' );\r\n\t\t\t\treturn;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tvar restore = false;\r\n\r\n\t\t\tif ( renderTarget.__webglFramebuffer !== _currentFramebuffer ) {\r\n\r\n\t\t\t\t_gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTarget.__webglFramebuffer );\r\n\r\n\t\t\t\trestore = true;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( _gl.checkFramebufferStatus( _gl.FRAMEBUFFER ) === _gl.FRAMEBUFFER_COMPLETE ) {\r\n\r\n\t\t\t\t_gl.readPixels( x, y, width, height, _gl.RGBA, _gl.UNSIGNED_BYTE, buffer );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tconsole.error( 'THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( restore ) {\r\n\r\n\t\t\t\t_gl.bindFramebuffer( _gl.FRAMEBUFFER, _currentFramebuffer );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n\tfunction updateRenderTargetMipmap ( renderTarget ) {\r\n\r\n\t\tif ( renderTarget instanceof THREE.WebGLRenderTargetCube ) {\r\n\r\n\t\t\t_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture );\r\n\t\t\t_gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );\r\n\t\t\t_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null );\r\n\r\n\t\t} else {\r\n\r\n\t\t\t_gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture );\r\n\t\t\t_gl.generateMipmap( _gl.TEXTURE_2D );\r\n\t\t\t_gl.bindTexture( _gl.TEXTURE_2D, null );\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t// Fallback filters for non-power-of-2 textures\r\n\r\n\tfunction filterFallback ( f ) {\r\n\r\n\t\tif ( f === THREE.NearestFilter || f === THREE.NearestMipMapNearestFilter || f === THREE.NearestMipMapLinearFilter ) {\r\n\r\n\t\t\treturn _gl.NEAREST;\r\n\r\n\t\t}\r\n\r\n\t\treturn _gl.LINEAR;\r\n\r\n\t}\r\n\r\n\t// Map three.js constants to WebGL constants\r\n\r\n\tfunction paramThreeToGL ( p ) {\r\n\r\n\t\tvar extension;\r\n\r\n\t\tif ( p === THREE.RepeatWrapping ) return _gl.REPEAT;\r\n\t\tif ( p === THREE.ClampToEdgeWrapping ) return _gl.CLAMP_TO_EDGE;\r\n\t\tif ( p === THREE.MirroredRepeatWrapping ) return _gl.MIRRORED_REPEAT;\r\n\r\n\t\tif ( p === THREE.NearestFilter ) return _gl.NEAREST;\r\n\t\tif ( p === THREE.NearestMipMapNearestFilter ) return _gl.NEAREST_MIPMAP_NEAREST;\r\n\t\tif ( p === THREE.NearestMipMapLinearFilter ) return _gl.NEAREST_MIPMAP_LINEAR;\r\n\r\n\t\tif ( p === THREE.LinearFilter ) return _gl.LINEAR;\r\n\t\tif ( p === THREE.LinearMipMapNearestFilter ) return _gl.LINEAR_MIPMAP_NEAREST;\r\n\t\tif ( p === THREE.LinearMipMapLinearFilter ) return _gl.LINEAR_MIPMAP_LINEAR;\r\n\r\n\t\tif ( p === THREE.UnsignedByteType ) return _gl.UNSIGNED_BYTE;\r\n\t\tif ( p === THREE.UnsignedShort4444Type ) return _gl.UNSIGNED_SHORT_4_4_4_4;\r\n\t\tif ( p === THREE.UnsignedShort5551Type ) return _gl.UNSIGNED_SHORT_5_5_5_1;\r\n\t\tif ( p === THREE.UnsignedShort565Type ) return _gl.UNSIGNED_SHORT_5_6_5;\r\n\r\n\t\tif ( p === THREE.ByteType ) return _gl.BYTE;\r\n\t\tif ( p === THREE.ShortType ) return _gl.SHORT;\r\n\t\tif ( p === THREE.UnsignedShortType ) return _gl.UNSIGNED_SHORT;\r\n\t\tif ( p === THREE.IntType ) return _gl.INT;\r\n\t\tif ( p === THREE.UnsignedIntType ) return _gl.UNSIGNED_INT;\r\n\t\tif ( p === THREE.FloatType ) return _gl.FLOAT;\r\n\r\n\t\textension = extensions.get( 'OES_texture_half_float' );\r\n\r\n\t\tif ( extension !== null ) {\r\n\r\n\t\t\tif ( p === THREE.HalfFloatType ) return extension.HALF_FLOAT_OES;\r\n\r\n\t\t}\r\n\r\n\t\tif ( p === THREE.AlphaFormat ) return _gl.ALPHA;\r\n\t\tif ( p === THREE.RGBFormat ) return _gl.RGB;\r\n\t\tif ( p === THREE.RGBAFormat ) return _gl.RGBA;\r\n\t\tif ( p === THREE.LuminanceFormat ) return _gl.LUMINANCE;\r\n\t\tif ( p === THREE.LuminanceAlphaFormat ) return _gl.LUMINANCE_ALPHA;\r\n\r\n\t\tif ( p === THREE.AddEquation ) return _gl.FUNC_ADD;\r\n\t\tif ( p === THREE.SubtractEquation ) return _gl.FUNC_SUBTRACT;\r\n\t\tif ( p === THREE.ReverseSubtractEquation ) return _gl.FUNC_REVERSE_SUBTRACT;\r\n\r\n\t\tif ( p === THREE.ZeroFactor ) return _gl.ZERO;\r\n\t\tif ( p === THREE.OneFactor ) return _gl.ONE;\r\n\t\tif ( p === THREE.SrcColorFactor ) return _gl.SRC_COLOR;\r\n\t\tif ( p === THREE.OneMinusSrcColorFactor ) return _gl.ONE_MINUS_SRC_COLOR;\r\n\t\tif ( p === THREE.SrcAlphaFactor ) return _gl.SRC_ALPHA;\r\n\t\tif ( p === THREE.OneMinusSrcAlphaFactor ) return _gl.ONE_MINUS_SRC_ALPHA;\r\n\t\tif ( p === THREE.DstAlphaFactor ) return _gl.DST_ALPHA;\r\n\t\tif ( p === THREE.OneMinusDstAlphaFactor ) return _gl.ONE_MINUS_DST_ALPHA;\r\n\r\n\t\tif ( p === THREE.DstColorFactor ) return _gl.DST_COLOR;\r\n\t\tif ( p === THREE.OneMinusDstColorFactor ) return _gl.ONE_MINUS_DST_COLOR;\r\n\t\tif ( p === THREE.SrcAlphaSaturateFactor ) return _gl.SRC_ALPHA_SATURATE;\r\n\r\n\t\textension = extensions.get( 'WEBGL_compressed_texture_s3tc' );\r\n\r\n\t\tif ( extension !== null ) {\r\n\r\n\t\t\tif ( p === THREE.RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT;\r\n\t\t\tif ( p === THREE.RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT;\r\n\t\t\tif ( p === THREE.RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT;\r\n\t\t\tif ( p === THREE.RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT;\r\n\r\n\t\t}\r\n\r\n\t\textension = extensions.get( 'WEBGL_compressed_texture_pvrtc' );\r\n\r\n\t\tif ( extension !== null ) {\r\n\r\n\t\t\tif ( p === THREE.RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;\r\n\t\t\tif ( p === THREE.RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;\r\n\t\t\tif ( p === THREE.RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;\r\n\t\t\tif ( p === THREE.RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;\r\n\r\n\t\t}\r\n\r\n\t\textension = extensions.get( 'EXT_blend_minmax' );\r\n\r\n\t\tif ( extension !== null ) {\r\n\r\n\t\t\tif ( p === THREE.MinEquation ) return extension.MIN_EXT;\r\n\t\t\tif ( p === THREE.MaxEquation ) return extension.MAX_EXT;\r\n\r\n\t\t}\r\n\r\n\t\treturn 0;\r\n\r\n\t}\r\n\r\n\t// Allocations\r\n\r\n\tfunction allocateBones ( object ) {\r\n\r\n\t\tif ( _supportsBoneTextures && object && object.skeleton && object.skeleton.useVertexTexture ) {\r\n\r\n\t\t\treturn 1024;\r\n\r\n\t\t} else {\r\n\r\n\t\t\t// default for when object is not specified\r\n\t\t\t// ( for example when prebuilding shader\r\n\t\t\t// to be used with multiple objects )\r\n\t\t\t//\r\n\t\t\t// - leave some extra space for other uniforms\r\n\t\t\t// - limit here is ANGLE's 254 max uniform vectors\r\n\t\t\t// (up to 54 should be safe)\r\n\r\n\t\t\tvar nVertexUniforms = _gl.getParameter( _gl.MAX_VERTEX_UNIFORM_VECTORS );\r\n\t\t\tvar nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 );\r\n\r\n\t\t\tvar maxBones = nVertexMatrices;\r\n\r\n\t\t\tif ( object !== undefined && object instanceof THREE.SkinnedMesh ) {\r\n\r\n\t\t\t\tmaxBones = Math.min( object.skeleton.bones.length, maxBones );\r\n\r\n\t\t\t\tif ( maxBones < object.skeleton.bones.length ) {\r\n\r\n\t\t\t\t\tTHREE.warn( 'WebGLRenderer: too many bones - ' + object.skeleton.bones.length + ', this GPU supports just ' + maxBones + ' (try OpenGL instead of ANGLE)' );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\treturn maxBones;\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tfunction allocateLights( lights ) {\r\n\r\n\t\tvar dirLights = 0;\r\n\t\tvar pointLights = 0;\r\n\t\tvar spotLights = 0;\r\n\t\tvar hemiLights = 0;\r\n\r\n\t\tfor ( var l = 0, ll = lights.length; l < ll; l ++ ) {\r\n\r\n\t\t\tvar light = lights[ l ];\r\n\r\n\t\t\tif ( light.onlyShadow || light.visible === false ) continue;\r\n\r\n\t\t\tif ( light instanceof THREE.DirectionalLight ) dirLights ++;\r\n\t\t\tif ( light instanceof THREE.PointLight ) pointLights ++;\r\n\t\t\tif ( light instanceof THREE.SpotLight ) spotLights ++;\r\n\t\t\tif ( light instanceof THREE.HemisphereLight ) hemiLights ++;\r\n\r\n\t\t}\r\n\r\n\t\treturn { 'directional': dirLights, 'point': pointLights, 'spot': spotLights, 'hemi': hemiLights };\r\n\r\n\t}\r\n\r\n\tfunction allocateShadows( lights ) {\r\n\r\n\t\tvar maxShadows = 0;\r\n\r\n\t\tfor ( var l = 0, ll = lights.length; l < ll; l ++ ) {\r\n\r\n\t\t\tvar light = lights[ l ];\r\n\r\n\t\t\tif ( ! light.castShadow ) continue;\r\n\r\n\t\t\tif ( light instanceof THREE.SpotLight ) maxShadows ++;\r\n\t\t\tif ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) maxShadows ++;\r\n\r\n\t\t}\r\n\r\n\t\treturn maxShadows;\r\n\r\n\t}\r\n\r\n\t// DEPRECATED\r\n\r\n\tthis.initMaterial = function () {\r\n\r\n\t\tTHREE.warn( 'THREE.WebGLRenderer: .initMaterial() has been removed.' );\r\n\r\n\t};\r\n\r\n\tthis.addPrePlugin = function () {\r\n\r\n\t\tTHREE.warn( 'THREE.WebGLRenderer: .addPrePlugin() has been removed.' );\r\n\r\n\t};\r\n\r\n\tthis.addPostPlugin = function () {\r\n\r\n\t\tTHREE.warn( 'THREE.WebGLRenderer: .addPostPlugin() has been removed.' );\r\n\r\n\t};\r\n\r\n\tthis.updateShadowMap = function () {\r\n\r\n\t\tTHREE.warn( 'THREE.WebGLRenderer: .updateShadowMap() has been removed.' );\r\n\r\n\t};\r\n\r\n};\r\n\r\n// File:src/renderers/WebGLRenderTarget.js\r\n\r\n/**\r\n * @author szimek / https://github.com/szimek/\r\n * @author alteredq / http://alteredqualia.com/\r\n */\r\n\r\nTHREE.WebGLRenderTarget = function ( width, height, options ) {\r\n\r\n\tthis.width = width;\r\n\tthis.height = height;\r\n\r\n\toptions = options || {};\r\n\r\n\tthis.wrapS = options.wrapS !== undefined ? options.wrapS : THREE.ClampToEdgeWrapping;\r\n\tthis.wrapT = options.wrapT !== undefined ? options.wrapT : THREE.ClampToEdgeWrapping;\r\n\r\n\tthis.magFilter = options.magFilter !== undefined ? options.magFilter : THREE.LinearFilter;\r\n\tthis.minFilter = options.minFilter !== undefined ? options.minFilter : THREE.LinearMipMapLinearFilter;\r\n\r\n\tthis.anisotropy = options.anisotropy !== undefined ? options.anisotropy : 1;\r\n\r\n\tthis.offset = new THREE.Vector2( 0, 0 );\r\n\tthis.repeat = new THREE.Vector2( 1, 1 );\r\n\r\n\tthis.format = options.format !== undefined ? options.format : THREE.RGBAFormat;\r\n\tthis.type = options.type !== undefined ? options.type : THREE.UnsignedByteType;\r\n\r\n\tthis.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true;\r\n\tthis.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : true;\r\n\r\n\tthis.generateMipmaps = true;\r\n\r\n\tthis.shareDepthFrom = options.shareDepthFrom !== undefined ? options.shareDepthFrom : null;\r\n\r\n};\r\n\r\nTHREE.WebGLRenderTarget.prototype = {\r\n\r\n\tconstructor: THREE.WebGLRenderTarget,\r\n\r\n\tsetSize: function ( width, height ) {\r\n\r\n\t\tthis.width = width;\r\n\t\tthis.height = height;\r\n\r\n\t},\r\n\r\n\tclone: function () {\r\n\r\n\t\tvar tmp = new THREE.WebGLRenderTarget( this.width, this.height );\r\n\r\n\t\ttmp.wrapS = this.wrapS;\r\n\t\ttmp.wrapT = this.wrapT;\r\n\r\n\t\ttmp.magFilter = this.magFilter;\r\n\t\ttmp.minFilter = this.minFilter;\r\n\r\n\t\ttmp.anisotropy = this.anisotropy;\r\n\r\n\t\ttmp.offset.copy( this.offset );\r\n\t\ttmp.repeat.copy( this.repeat );\r\n\r\n\t\ttmp.format = this.format;\r\n\t\ttmp.type = this.type;\r\n\r\n\t\ttmp.depthBuffer = this.depthBuffer;\r\n\t\ttmp.stencilBuffer = this.stencilBuffer;\r\n\r\n\t\ttmp.generateMipmaps = this.generateMipmaps;\r\n\r\n\t\ttmp.shareDepthFrom = this.shareDepthFrom;\r\n\r\n\t\treturn tmp;\r\n\r\n\t},\r\n\r\n\tdispose: function () {\r\n\r\n\t\tthis.dispatchEvent( { type: 'dispose' } );\r\n\r\n\t}\r\n\r\n};\r\n\r\nTHREE.EventDispatcher.prototype.apply( THREE.WebGLRenderTarget.prototype );\r\n\r\n// File:src/renderers/WebGLRenderTargetCube.js\r\n\r\n/**\r\n * @author alteredq / http://alteredqualia.com\r\n */\r\n\r\nTHREE.WebGLRenderTargetCube = function ( width, height, options ) {\r\n\r\n\tTHREE.WebGLRenderTarget.call( this, width, height, options );\r\n\r\n\tthis.activeCubeFace = 0; // PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5\r\n\r\n};\r\n\r\nTHREE.WebGLRenderTargetCube.prototype = Object.create( THREE.WebGLRenderTarget.prototype );\r\nTHREE.WebGLRenderTargetCube.prototype.constructor = THREE.WebGLRenderTargetCube;\r\n\r\n// File:src/renderers/webgl/WebGLExtensions.js\r\n\r\n/**\r\n* @author mrdoob / http://mrdoob.com/\r\n*/\r\n\r\nTHREE.WebGLExtensions = function ( gl ) {\r\n\r\n\tvar extensions = {};\r\n\r\n\tthis.get = function ( name ) {\r\n\r\n\t\tif ( extensions[ name ] !== undefined ) {\r\n\r\n\t\t\treturn extensions[ name ];\r\n\r\n\t\t}\r\n\r\n\t\tvar extension;\r\n\r\n\t\tswitch ( name ) {\r\n\r\n\t\t\tcase 'EXT_texture_filter_anisotropic':\r\n\t\t\t\textension = gl.getExtension( 'EXT_texture_filter_anisotropic' ) || gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' );\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tcase 'WEBGL_compressed_texture_s3tc':\r\n\t\t\t\textension = gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' );\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tcase 'WEBGL_compressed_texture_pvrtc':\r\n\t\t\t\textension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' );\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tdefault:\r\n\t\t\t\textension = gl.getExtension( name );\r\n\r\n\t\t}\r\n\r\n\t\tif ( extension === null ) {\r\n\r\n\t\t\tTHREE.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' );\r\n\r\n\t\t}\r\n\r\n\t\textensions[ name ] = extension;\r\n\r\n\t\treturn extension;\r\n\r\n\t};\r\n\r\n};\r\n\r\n// File:src/renderers/webgl/WebGLProgram.js\r\n\r\nTHREE.WebGLProgram = ( function () {\r\n\r\n\tvar programIdCount = 0;\r\n\r\n\tvar generateDefines = function ( defines ) {\r\n\r\n\t\tvar value, chunk, chunks = [];\r\n\r\n\t\tfor ( var d in defines ) {\r\n\r\n\t\t\tvalue = defines[ d ];\r\n\t\t\tif ( value === false ) continue;\r\n\r\n\t\t\tchunk = '#define ' + d + ' ' + value;\r\n\t\t\tchunks.push( chunk );\r\n\r\n\t\t}\r\n\r\n\t\treturn chunks.join( '\\n' );\r\n\r\n\t};\r\n\r\n\tvar cacheUniformLocations = function ( gl, program, identifiers ) {\r\n\r\n\t\tvar uniforms = {};\r\n\r\n\t\tfor ( var i = 0, l = identifiers.length; i < l; i ++ ) {\r\n\r\n\t\t\tvar id = identifiers[ i ];\r\n\t\t\tuniforms[ id ] = gl.getUniformLocation( program, id );\r\n\r\n\t\t}\r\n\r\n\t\treturn uniforms;\r\n\r\n\t};\r\n\r\n\tvar cacheAttributeLocations = function ( gl, program, identifiers ) {\r\n\r\n\t\tvar attributes = {};\r\n\r\n\t\tfor ( var i = 0, l = identifiers.length; i < l; i ++ ) {\r\n\r\n\t\t\tvar id = identifiers[ i ];\r\n\t\t\tattributes[ id ] = gl.getAttribLocation( program, id );\r\n\r\n\t\t}\r\n\r\n\t\treturn attributes;\r\n\r\n\t};\r\n\r\n\treturn function ( renderer, code, material, parameters ) {\r\n\r\n\t\tvar _this = renderer;\r\n\t\tvar _gl = _this.context;\r\n\r\n\t\tvar defines = material.defines;\r\n\t\tvar uniforms = material.__webglShader.uniforms;\r\n\t\tvar attributes = material.attributes;\r\n\r\n\t\tvar vertexShader = material.__webglShader.vertexShader;\r\n\t\tvar fragmentShader = material.__webglShader.fragmentShader;\r\n\r\n\t\tvar index0AttributeName = material.index0AttributeName;\r\n\r\n\t\tif ( index0AttributeName === undefined && parameters.morphTargets === true ) {\r\n\r\n\t\t\t// programs with morphTargets displace position out of attribute 0\r\n\r\n\t\t\tindex0AttributeName = 'position';\r\n\r\n\t\t}\r\n\r\n\t\tvar shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC';\r\n\r\n\t\tif ( parameters.shadowMapType === THREE.PCFShadowMap ) {\r\n\r\n\t\t\tshadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF';\r\n\r\n\t\t} else if ( parameters.shadowMapType === THREE.PCFSoftShadowMap ) {\r\n\r\n\t\t\tshadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT';\r\n\r\n\t\t}\r\n\r\n\t\tvar envMapTypeDefine = 'ENVMAP_TYPE_CUBE';\r\n\t\tvar envMapModeDefine = 'ENVMAP_MODE_REFLECTION';\r\n\t\tvar envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';\r\n\r\n\t\tif ( parameters.envMap ) {\r\n\r\n\t\t\tswitch ( material.envMap.mapping ) {\r\n\r\n\t\t\t\tcase THREE.CubeReflectionMapping:\r\n\t\t\t\tcase THREE.CubeRefractionMapping:\r\n\t\t\t\t\tenvMapTypeDefine = 'ENVMAP_TYPE_CUBE';\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase THREE.EquirectangularReflectionMapping:\r\n\t\t\t\tcase THREE.EquirectangularRefractionMapping:\r\n\t\t\t\t\tenvMapTypeDefine = 'ENVMAP_TYPE_EQUIREC';\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase THREE.SphericalReflectionMapping:\r\n\t\t\t\t\tenvMapTypeDefine = 'ENVMAP_TYPE_SPHERE';\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tswitch ( material.envMap.mapping ) {\r\n\r\n\t\t\t\tcase THREE.CubeRefractionMapping:\r\n\t\t\t\tcase THREE.EquirectangularRefractionMapping:\r\n\t\t\t\t\tenvMapModeDefine = 'ENVMAP_MODE_REFRACTION';\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tswitch ( material.combine ) {\r\n\r\n\t\t\t\tcase THREE.MultiplyOperation:\r\n\t\t\t\t\tenvMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase THREE.MixOperation:\r\n\t\t\t\t\tenvMapBlendingDefine = 'ENVMAP_BLENDING_MIX';\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase THREE.AddOperation:\r\n\t\t\t\t\tenvMapBlendingDefine = 'ENVMAP_BLENDING_ADD';\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tvar gammaFactorDefine = ( renderer.gammaFactor > 0 ) ? renderer.gammaFactor : 1.0;\r\n\r\n\t\t// console.log( 'building new program ' );\r\n\r\n\t\t//\r\n\r\n\t\tvar customDefines = generateDefines( defines );\r\n\r\n\t\t//\r\n\r\n\t\tvar program = _gl.createProgram();\r\n\r\n\t\tvar prefix_vertex, prefix_fragment;\r\n\r\n\t\tif ( material instanceof THREE.RawShaderMaterial ) {\r\n\r\n\t\t\tprefix_vertex = '';\r\n\t\t\tprefix_fragment = '';\r\n\r\n\t\t} else {\r\n\r\n\t\t\tprefix_vertex = [\r\n\r\n\t\t\t\t'precision ' + parameters.precision + ' float;',\r\n\t\t\t\t'precision ' + parameters.precision + ' int;',\r\n\r\n\t\t\t\tcustomDefines,\r\n\r\n\t\t\t\tparameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '',\r\n\r\n\t\t\t\t_this.gammaInput ? '#define GAMMA_INPUT' : '',\r\n\t\t\t\t_this.gammaOutput ? '#define GAMMA_OUTPUT' : '',\r\n\t\t\t\t'#define GAMMA_FACTOR ' + gammaFactorDefine,\r\n\r\n\t\t\t\t'#define MAX_DIR_LIGHTS ' + parameters.maxDirLights,\r\n\t\t\t\t'#define MAX_POINT_LIGHTS ' + parameters.maxPointLights,\r\n\t\t\t\t'#define MAX_SPOT_LIGHTS ' + parameters.maxSpotLights,\r\n\t\t\t\t'#define MAX_HEMI_LIGHTS ' + parameters.maxHemiLights,\r\n\r\n\t\t\t\t'#define MAX_SHADOWS ' + parameters.maxShadows,\r\n\r\n\t\t\t\t'#define MAX_BONES ' + parameters.maxBones,\r\n\r\n\t\t\t\tparameters.map ? '#define USE_MAP' : '',\r\n\t\t\t\tparameters.envMap ? '#define USE_ENVMAP' : '',\r\n\t\t\t\tparameters.envMap ? '#define ' + envMapModeDefine : '',\r\n\t\t\t\tparameters.lightMap ? '#define USE_LIGHTMAP' : '',\r\n\t\t\t\tparameters.bumpMap ? '#define USE_BUMPMAP' : '',\r\n\t\t\t\tparameters.normalMap ? '#define USE_NORMALMAP' : '',\r\n\t\t\t\tparameters.specularMap ? '#define USE_SPECULARMAP' : '',\r\n\t\t\t\tparameters.alphaMap ? '#define USE_ALPHAMAP' : '',\r\n\t\t\t\tparameters.vertexColors ? '#define USE_COLOR' : '',\r\n\r\n\t\t\t\tparameters.flatShading ? '#define FLAT_SHADED': '',\r\n\r\n\t\t\t\tparameters.skinning ? '#define USE_SKINNING' : '',\r\n\t\t\t\tparameters.useVertexTexture ? '#define BONE_TEXTURE' : '',\r\n\r\n\t\t\t\tparameters.morphTargets ? '#define USE_MORPHTARGETS' : '',\r\n\t\t\t\tparameters.morphNormals ? '#define USE_MORPHNORMALS' : '',\r\n\t\t\t\tparameters.wrapAround ? '#define WRAP_AROUND' : '',\r\n\t\t\t\tparameters.doubleSided ? '#define DOUBLE_SIDED' : '',\r\n\t\t\t\tparameters.flipSided ? '#define FLIP_SIDED' : '',\r\n\r\n\t\t\t\tparameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',\r\n\t\t\t\tparameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',\r\n\t\t\t\tparameters.shadowMapDebug ? '#define SHADOWMAP_DEBUG' : '',\r\n\t\t\t\tparameters.shadowMapCascade ? '#define SHADOWMAP_CASCADE' : '',\r\n\r\n\t\t\t\tparameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '',\r\n\r\n\t\t\t\tparameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',\r\n\t\t\t\t//_this._glExtensionFragDepth ? '#define USE_LOGDEPTHBUF_EXT' : '',\r\n\r\n\r\n\t\t\t\t'uniform mat4 modelMatrix;',\r\n\t\t\t\t'uniform mat4 modelViewMatrix;',\r\n\t\t\t\t'uniform mat4 projectionMatrix;',\r\n\t\t\t\t'uniform mat4 viewMatrix;',\r\n\t\t\t\t'uniform mat3 normalMatrix;',\r\n\t\t\t\t'uniform vec3 cameraPosition;',\r\n\r\n\t\t\t\t'attribute vec3 position;',\r\n\t\t\t\t'attribute vec3 normal;',\r\n\t\t\t\t'attribute vec2 uv;',\r\n\t\t\t\t'attribute vec2 uv2;',\r\n\r\n\t\t\t\t'#ifdef USE_COLOR',\r\n\r\n\t\t\t\t'\tattribute vec3 color;',\r\n\r\n\t\t\t\t'#endif',\r\n\r\n\t\t\t\t'#ifdef USE_MORPHTARGETS',\r\n\r\n\t\t\t\t'\tattribute vec3 morphTarget0;',\r\n\t\t\t\t'\tattribute vec3 morphTarget1;',\r\n\t\t\t\t'\tattribute vec3 morphTarget2;',\r\n\t\t\t\t'\tattribute vec3 morphTarget3;',\r\n\r\n\t\t\t\t'\t#ifdef USE_MORPHNORMALS',\r\n\r\n\t\t\t\t'\t\tattribute vec3 morphNormal0;',\r\n\t\t\t\t'\t\tattribute vec3 morphNormal1;',\r\n\t\t\t\t'\t\tattribute vec3 morphNormal2;',\r\n\t\t\t\t'\t\tattribute vec3 morphNormal3;',\r\n\r\n\t\t\t\t'\t#else',\r\n\r\n\t\t\t\t'\t\tattribute vec3 morphTarget4;',\r\n\t\t\t\t'\t\tattribute vec3 morphTarget5;',\r\n\t\t\t\t'\t\tattribute vec3 morphTarget6;',\r\n\t\t\t\t'\t\tattribute vec3 morphTarget7;',\r\n\r\n\t\t\t\t'\t#endif',\r\n\r\n\t\t\t\t'#endif',\r\n\r\n\t\t\t\t'#ifdef USE_SKINNING',\r\n\r\n\t\t\t\t'\tattribute vec4 skinIndex;',\r\n\t\t\t\t'\tattribute vec4 skinWeight;',\r\n\r\n\t\t\t\t'#endif',\r\n\r\n\t\t\t\t''\r\n\r\n\t\t\t].join( '\\n' );\r\n\r\n\t\t\tprefix_fragment = [\r\n\r\n\t\t\t\t'precision ' + parameters.precision + ' float;',\r\n\t\t\t\t'precision ' + parameters.precision + ' int;',\r\n\r\n\t\t\t\t( parameters.bumpMap || parameters.normalMap || parameters.flatShading ) ? '#extension GL_OES_standard_derivatives : enable' : '',\r\n\r\n\t\t\t\tcustomDefines,\r\n\r\n\t\t\t\t'#define MAX_DIR_LIGHTS ' + parameters.maxDirLights,\r\n\t\t\t\t'#define MAX_POINT_LIGHTS ' + parameters.maxPointLights,\r\n\t\t\t\t'#define MAX_SPOT_LIGHTS ' + parameters.maxSpotLights,\r\n\t\t\t\t'#define MAX_HEMI_LIGHTS ' + parameters.maxHemiLights,\r\n\r\n\t\t\t\t'#define MAX_SHADOWS ' + parameters.maxShadows,\r\n\r\n\t\t\t\tparameters.alphaTest ? '#define ALPHATEST ' + parameters.alphaTest : '',\r\n\r\n\t\t\t\t_this.gammaInput ? '#define GAMMA_INPUT' : '',\r\n\t\t\t\t_this.gammaOutput ? '#define GAMMA_OUTPUT' : '',\r\n\t\t\t\t'#define GAMMA_FACTOR ' + gammaFactorDefine,\r\n\r\n\t\t\t\t( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '',\r\n\t\t\t\t( parameters.useFog && parameters.fogExp ) ? '#define FOG_EXP2' : '',\r\n\r\n\t\t\t\tparameters.map ? '#define USE_MAP' : '',\r\n\t\t\t\tparameters.envMap ? '#define USE_ENVMAP' : '',\r\n\t\t\t\tparameters.envMap ? '#define ' + envMapTypeDefine : '',\r\n\t\t\t\tparameters.envMap ? '#define ' + envMapModeDefine : '',\r\n\t\t\t\tparameters.envMap ? '#define ' + envMapBlendingDefine : '',\r\n\t\t\t\tparameters.lightMap ? '#define USE_LIGHTMAP' : '',\r\n\t\t\t\tparameters.bumpMap ? '#define USE_BUMPMAP' : '',\r\n\t\t\t\tparameters.normalMap ? '#define USE_NORMALMAP' : '',\r\n\t\t\t\tparameters.specularMap ? '#define USE_SPECULARMAP' : '',\r\n\t\t\t\tparameters.alphaMap ? '#define USE_ALPHAMAP' : '',\r\n\t\t\t\tparameters.vertexColors ? '#define USE_COLOR' : '',\r\n\r\n\t\t\t\tparameters.flatShading ? '#define FLAT_SHADED': '',\r\n\r\n\t\t\t\tparameters.metal ? '#define METAL' : '',\r\n\t\t\t\tparameters.wrapAround ? '#define WRAP_AROUND' : '',\r\n\t\t\t\tparameters.doubleSided ? '#define DOUBLE_SIDED' : '',\r\n\t\t\t\tparameters.flipSided ? '#define FLIP_SIDED' : '',\r\n\r\n\t\t\t\tparameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',\r\n\t\t\t\tparameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',\r\n\t\t\t\tparameters.shadowMapDebug ? '#define SHADOWMAP_DEBUG' : '',\r\n\t\t\t\tparameters.shadowMapCascade ? '#define SHADOWMAP_CASCADE' : '',\r\n\r\n\t\t\t\tparameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',\r\n\t\t\t\t//_this._glExtensionFragDepth ? '#define USE_LOGDEPTHBUF_EXT' : '',\r\n\r\n\t\t\t\t'uniform mat4 viewMatrix;',\r\n\t\t\t\t'uniform vec3 cameraPosition;',\r\n\t\t\t\t''\r\n\r\n\t\t\t].join( '\\n' );\r\n\r\n\t\t}\r\n\r\n\t\tvar glVertexShader = new THREE.WebGLShader( _gl, _gl.VERTEX_SHADER, prefix_vertex + vertexShader );\r\n\t\tvar glFragmentShader = new THREE.WebGLShader( _gl, _gl.FRAGMENT_SHADER, prefix_fragment + fragmentShader );\r\n\r\n\t\t_gl.attachShader( program, glVertexShader );\r\n\t\t_gl.attachShader( program, glFragmentShader );\r\n\r\n\t\tif ( index0AttributeName !== undefined ) {\r\n\r\n\t\t\t// Force a particular attribute to index 0.\r\n\t\t\t// because potentially expensive emulation is done by browser if attribute 0 is disabled.\r\n\t\t\t// And, color, for example is often automatically bound to index 0 so disabling it\r\n\r\n\t\t\t_gl.bindAttribLocation( program, 0, index0AttributeName );\r\n\r\n\t\t}\r\n\r\n\t\t_gl.linkProgram( program );\r\n\r\n\t\tvar programLogInfo = _gl.getProgramInfoLog( program );\r\n\r\n\t\tif ( _gl.getProgramParameter( program, _gl.LINK_STATUS ) === false ) {\r\n\r\n\t\t\tTHREE.error( 'THREE.WebGLProgram: shader error: ' + _gl.getError(), 'gl.VALIDATE_STATUS', _gl.getProgramParameter( program, _gl.VALIDATE_STATUS ), 'gl.getPRogramInfoLog', programLogInfo );\r\n\r\n\t\t}\r\n\r\n\t\tif ( programLogInfo !== '' ) {\r\n\r\n\t\t\tTHREE.warn( 'THREE.WebGLProgram: gl.getProgramInfoLog()' + programLogInfo );\r\n\t\t\t// THREE.warn( _gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glVertexShader ) );\r\n\t\t\t// THREE.warn( _gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glFragmentShader ) );\r\n\r\n\t\t}\r\n\r\n\t\t// clean up\r\n\r\n\t\t_gl.deleteShader( glVertexShader );\r\n\t\t_gl.deleteShader( glFragmentShader );\r\n\r\n\t\t// cache uniform locations\r\n\r\n\t\tvar identifiers = [\r\n\r\n\t\t\t'viewMatrix',\r\n\t\t\t'modelViewMatrix',\r\n\t\t\t'projectionMatrix',\r\n\t\t\t'normalMatrix',\r\n\t\t\t'modelMatrix',\r\n\t\t\t'cameraPosition',\r\n\t\t\t'morphTargetInfluences',\r\n\t\t\t'bindMatrix',\r\n\t\t\t'bindMatrixInverse'\r\n\r\n\t\t];\r\n\r\n\t\tif ( parameters.useVertexTexture ) {\r\n\r\n\t\t\tidentifiers.push( 'boneTexture' );\r\n\t\t\tidentifiers.push( 'boneTextureWidth' );\r\n\t\t\tidentifiers.push( 'boneTextureHeight' );\r\n\r\n\t\t} else {\r\n\r\n\t\t\tidentifiers.push( 'boneGlobalMatrices' );\r\n\r\n\t\t}\r\n\r\n\t\tif ( parameters.logarithmicDepthBuffer ) {\r\n\r\n\t\t\tidentifiers.push('logDepthBufFC');\r\n\r\n\t\t}\r\n\r\n\r\n\t\tfor ( var u in uniforms ) {\r\n\r\n\t\t\tidentifiers.push( u );\r\n\r\n\t\t}\r\n\r\n\t\tthis.uniforms = cacheUniformLocations( _gl, program, identifiers );\r\n\r\n\t\t// cache attributes locations\r\n\r\n\t\tidentifiers = [\r\n\r\n\t\t\t'position',\r\n\t\t\t'normal',\r\n\t\t\t'uv',\r\n\t\t\t'uv2',\r\n\t\t\t'tangent',\r\n\t\t\t'color',\r\n\t\t\t'skinIndex',\r\n\t\t\t'skinWeight',\r\n\t\t\t'lineDistance'\r\n\r\n\t\t];\r\n\r\n\t\tfor ( var i = 0; i < parameters.maxMorphTargets; i ++ ) {\r\n\r\n\t\t\tidentifiers.push( 'morphTarget' + i );\r\n\r\n\t\t}\r\n\r\n\t\tfor ( var i = 0; i < parameters.maxMorphNormals; i ++ ) {\r\n\r\n\t\t\tidentifiers.push( 'morphNormal' + i );\r\n\r\n\t\t}\r\n\r\n\t\tfor ( var a in attributes ) {\r\n\r\n\t\t\tidentifiers.push( a );\r\n\r\n\t\t}\r\n\r\n\t\tthis.attributes = cacheAttributeLocations( _gl, program, identifiers );\r\n\t\tthis.attributesKeys = Object.keys( this.attributes );\r\n\r\n\t\t//\r\n\r\n\t\tthis.id = programIdCount ++;\r\n\t\tthis.code = code;\r\n\t\tthis.usedTimes = 1;\r\n\t\tthis.program = program;\r\n\t\tthis.vertexShader = glVertexShader;\r\n\t\tthis.fragmentShader = glFragmentShader;\r\n\r\n\t\treturn this;\r\n\r\n\t};\r\n\r\n} )();\r\n\r\n// File:src/renderers/webgl/WebGLShader.js\r\n\r\nTHREE.WebGLShader = ( function () {\r\n\r\n\tvar addLineNumbers = function ( string ) {\r\n\r\n\t\tvar lines = string.split( '\\n' );\r\n\r\n\t\tfor ( var i = 0; i < lines.length; i ++ ) {\r\n\r\n\t\t\tlines[ i ] = ( i + 1 ) + ': ' + lines[ i ];\r\n\r\n\t\t}\r\n\r\n\t\treturn lines.join( '\\n' );\r\n\r\n\t};\r\n\r\n\treturn function ( gl, type, string ) {\r\n\r\n\t\tvar shader = gl.createShader( type ); \r\n\r\n\t\tgl.shaderSource( shader, string );\r\n\t\tgl.compileShader( shader );\r\n\r\n\t\tif ( gl.getShaderParameter( shader, gl.COMPILE_STATUS ) === false ) {\r\n\r\n\t\t\tTHREE.error( 'THREE.WebGLShader: Shader couldn\\'t compile.' );\r\n\r\n\t\t}\r\n\r\n\t\tif ( gl.getShaderInfoLog( shader ) !== '' ) {\r\n\r\n\t\t\tTHREE.warn( 'THREE.WebGLShader: gl.getShaderInfoLog()', gl.getShaderInfoLog( shader ), addLineNumbers( string ) );\r\n\r\n\t\t}\r\n\r\n\t\t// --enable-privileged-webgl-extension\r\n\t\t// console.log( type, gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) );\r\n\r\n\t\treturn shader;\r\n\r\n\t};\r\n\r\n} )();\r\n\r\n// File:src/renderers/webgl/WebGLState.js\r\n\r\n/**\r\n* @author mrdoob / http://mrdoob.com/\r\n*/\r\n\r\nTHREE.WebGLState = function ( gl, paramThreeToGL ) {\r\n\r\n\tvar newAttributes = new Uint8Array( 16 );\r\n\tvar enabledAttributes = new Uint8Array( 16 );\r\n\r\n\tvar currentBlending = null;\r\n\tvar currentBlendEquation = null;\r\n\tvar currentBlendSrc = null;\r\n\tvar currentBlendDst = null;\r\n\tvar currentBlendEquationAlpha = null;\r\n\tvar currentBlendSrcAlpha = null;\r\n\tvar currentBlendDstAlpha = null;\r\n\r\n\tvar currentDepthTest = null;\r\n\tvar currentDepthWrite = null;\r\n\r\n\tvar currentColorWrite = null;\r\n\r\n\tvar currentDoubleSided = null;\r\n\tvar currentFlipSided = null;\r\n\r\n\tvar currentLineWidth = null;\r\n\r\n\tvar currentPolygonOffset = null;\r\n\tvar currentPolygonOffsetFactor = null;\r\n\tvar currentPolygonOffsetUnits = null;\r\n\r\n\tthis.initAttributes = function () {\r\n\r\n\t\tfor ( var i = 0, l = newAttributes.length; i < l; i ++ ) {\r\n\r\n\t\t\tnewAttributes[ i ] = 0;\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n\tthis.enableAttribute = function ( attribute ) {\r\n\r\n\t\tnewAttributes[ attribute ] = 1;\r\n\r\n\t\tif ( enabledAttributes[ attribute ] === 0 ) {\r\n\r\n\t\t\tgl.enableVertexAttribArray( attribute );\r\n\t\t\tenabledAttributes[ attribute ] = 1;\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n\tthis.disableUnusedAttributes = function () {\r\n\r\n\t\tfor ( var i = 0, l = enabledAttributes.length; i < l; i ++ ) {\r\n\r\n\t\t\tif ( enabledAttributes[ i ] !== newAttributes[ i ] ) {\r\n\r\n\t\t\t\tgl.disableVertexAttribArray( i );\r\n\t\t\t\tenabledAttributes[ i ] = 0;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n\tthis.setBlending = function ( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha ) {\r\n\r\n\t\tif ( blending !== currentBlending ) {\r\n\r\n\t\t\tif ( blending === THREE.NoBlending ) {\r\n\r\n\t\t\t\tgl.disable( gl.BLEND );\r\n\r\n\t\t\t} else if ( blending === THREE.AdditiveBlending ) {\r\n\r\n\t\t\t\tgl.enable( gl.BLEND );\r\n\t\t\t\tgl.blendEquation( gl.FUNC_ADD );\r\n\t\t\t\tgl.blendFunc( gl.SRC_ALPHA, gl.ONE );\r\n\r\n\t\t\t} else if ( blending === THREE.SubtractiveBlending ) {\r\n\r\n\t\t\t\t// TODO: Find blendFuncSeparate() combination\r\n\t\t\t\tgl.enable( gl.BLEND );\r\n\t\t\t\tgl.blendEquation( gl.FUNC_ADD );\r\n\t\t\t\tgl.blendFunc( gl.ZERO, gl.ONE_MINUS_SRC_COLOR );\r\n\r\n\t\t\t} else if ( blending === THREE.MultiplyBlending ) {\r\n\r\n\t\t\t\t// TODO: Find blendFuncSeparate() combination\r\n\t\t\t\tgl.enable( gl.BLEND );\r\n\t\t\t\tgl.blendEquation( gl.FUNC_ADD );\r\n\t\t\t\tgl.blendFunc( gl.ZERO, gl.SRC_COLOR );\r\n\r\n\t\t\t} else if ( blending === THREE.CustomBlending ) {\r\n\r\n\t\t\t\tgl.enable( gl.BLEND );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tgl.enable( gl.BLEND );\r\n\t\t\t\tgl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );\r\n\t\t\t\tgl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tcurrentBlending = blending;\r\n\r\n\t\t}\r\n\r\n\t\tif ( blending === THREE.CustomBlending ) {\r\n\r\n\t\t\tblendEquationAlpha = blendEquationAlpha || blendEquation;\r\n\t\t\tblendSrcAlpha = blendSrcAlpha || blendSrc;\r\n\t\t\tblendDstAlpha = blendDstAlpha || blendDst;\r\n\r\n\t\t\tif ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) {\r\n\r\n\t\t\t\tgl.blendEquationSeparate( paramThreeToGL( blendEquation ), paramThreeToGL( blendEquationAlpha ) );\r\n\r\n\t\t\t\tcurrentBlendEquation = blendEquation;\r\n\t\t\t\tcurrentBlendEquationAlpha = blendEquationAlpha;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) {\r\n\r\n\t\t\t\tgl.blendFuncSeparate( paramThreeToGL( blendSrc ), paramThreeToGL( blendDst ), paramThreeToGL( blendSrcAlpha ), paramThreeToGL( blendDstAlpha ) );\r\n\r\n\t\t\t\tcurrentBlendSrc = blendSrc;\r\n\t\t\t\tcurrentBlendDst = blendDst;\r\n\t\t\t\tcurrentBlendSrcAlpha = blendSrcAlpha;\r\n\t\t\t\tcurrentBlendDstAlpha = blendDstAlpha;\r\n\r\n\t\t\t}\r\n\r\n\t\t} else {\r\n\r\n\t\t\tcurrentBlendEquation = null;\r\n\t\t\tcurrentBlendSrc = null;\r\n\t\t\tcurrentBlendDst = null;\r\n\t\t\tcurrentBlendEquationAlpha = null;\r\n\t\t\tcurrentBlendSrcAlpha = null;\r\n\t\t\tcurrentBlendDstAlpha = null;\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n\tthis.setDepthTest = function ( depthTest ) {\r\n\r\n\t\tif ( currentDepthTest !== depthTest ) {\r\n\r\n\t\t\tif ( depthTest ) {\r\n\r\n\t\t\t\tgl.enable( gl.DEPTH_TEST );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tgl.disable( gl.DEPTH_TEST );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tcurrentDepthTest = depthTest;\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n\tthis.setDepthWrite = function ( depthWrite ) {\r\n\r\n\t\tif ( currentDepthWrite !== depthWrite ) {\r\n\r\n\t\t\tgl.depthMask( depthWrite );\r\n\t\t\tcurrentDepthWrite = depthWrite;\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n\tthis.setColorWrite = function ( colorWrite ) {\r\n\r\n\t\tif ( currentColorWrite !== colorWrite ) {\r\n\r\n\t\t\tgl.colorMask( colorWrite, colorWrite, colorWrite, colorWrite );\r\n\t\t\tcurrentColorWrite = colorWrite;\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n\tthis.setDoubleSided = function ( doubleSided ) {\r\n\r\n\t\tif ( currentDoubleSided !== doubleSided ) {\r\n\r\n\t\t\tif ( doubleSided ) {\r\n\r\n\t\t\t\tgl.disable( gl.CULL_FACE );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tgl.enable( gl.CULL_FACE );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tcurrentDoubleSided = doubleSided;\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n\tthis.setFlipSided = function ( flipSided ) {\r\n\r\n\t\tif ( currentFlipSided !== flipSided ) {\r\n\r\n\t\t\tif ( flipSided ) {\r\n\r\n\t\t\t\tgl.frontFace( gl.CW );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tgl.frontFace( gl.CCW );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tcurrentFlipSided = flipSided;\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n\tthis.setLineWidth = function ( width ) {\r\n\r\n\t\tif ( width !== currentLineWidth ) {\r\n\r\n\t\t\tgl.lineWidth( width );\r\n\r\n\t\t\tcurrentLineWidth = width;\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n\tthis.setPolygonOffset = function ( polygonoffset, factor, units ) {\r\n\r\n\t\tif ( currentPolygonOffset !== polygonoffset ) {\r\n\r\n\t\t\tif ( polygonoffset ) {\r\n\r\n\t\t\t\tgl.enable( gl.POLYGON_OFFSET_FILL );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tgl.disable( gl.POLYGON_OFFSET_FILL );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tcurrentPolygonOffset = polygonoffset;\r\n\r\n\t\t}\r\n\r\n\t\tif ( polygonoffset && ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) ) {\r\n\r\n\t\t\tgl.polygonOffset( factor, units );\r\n\r\n\t\t\tcurrentPolygonOffsetFactor = factor;\r\n\t\t\tcurrentPolygonOffsetUnits = units;\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n\tthis.reset = function () {\r\n\r\n\t\tfor ( var i = 0; i < enabledAttributes.length; i ++ ) {\r\n\r\n\t\t\tenabledAttributes[ i ] = 0;\r\n\r\n\t\t}\r\n\r\n\t\tcurrentBlending = null;\r\n\t\tcurrentDepthTest = null;\r\n\t\tcurrentDepthWrite = null;\r\n\t\tcurrentColorWrite = null;\r\n\t\tcurrentDoubleSided = null;\r\n\t\tcurrentFlipSided = null;\r\n\r\n\t};\r\n\r\n};\r\n\r\n// File:src/renderers/webgl/plugins/LensFlarePlugin.js\r\n\r\n/**\r\n * @author mikael emtinger / http://gomo.se/\r\n * @author alteredq / http://alteredqualia.com/\r\n */\r\n\r\nTHREE.LensFlarePlugin = function ( renderer, flares ) {\r\n\r\n\tvar gl = renderer.context;\r\n\r\n\tvar vertexBuffer, elementBuffer;\r\n\tvar program, attributes, uniforms;\r\n\tvar hasVertexTexture;\r\n\r\n\tvar tempTexture, occlusionTexture;\r\n\r\n\tvar init = function () {\r\n\r\n\t\tvar vertices = new Float32Array( [\r\n\t\t\t-1, -1, 0, 0,\r\n\t\t\t 1, -1, 1, 0,\r\n\t\t\t 1, 1, 1, 1,\r\n\t\t\t-1, 1, 0, 1\r\n\t\t] );\r\n\r\n\t\tvar faces = new Uint16Array( [\r\n\t\t\t0, 1, 2,\r\n\t\t\t0, 2, 3\r\n\t\t] );\r\n\r\n\t\t// buffers\r\n\r\n\t\tvertexBuffer = gl.createBuffer();\r\n\t\telementBuffer = gl.createBuffer();\r\n\r\n\t\tgl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );\r\n\t\tgl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW );\r\n\r\n\t\tgl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );\r\n\t\tgl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW );\r\n\r\n\t\t// textures\r\n\r\n\t\ttempTexture = gl.createTexture();\r\n\t\tocclusionTexture = gl.createTexture();\r\n\r\n\t\tgl.bindTexture( gl.TEXTURE_2D, tempTexture );\r\n\t\tgl.texImage2D( gl.TEXTURE_2D, 0, gl.RGB, 16, 16, 0, gl.RGB, gl.UNSIGNED_BYTE, null );\r\n\t\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE );\r\n\t\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE );\r\n\t\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST );\r\n\t\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST );\r\n\r\n\t\tgl.bindTexture( gl.TEXTURE_2D, occlusionTexture );\r\n\t\tgl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, 16, 16, 0, gl.RGBA, gl.UNSIGNED_BYTE, null );\r\n\t\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE );\r\n\t\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE );\r\n\t\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST );\r\n\t\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST );\r\n\r\n\t\thasVertexTexture = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ) > 0;\r\n\r\n\t\tvar shader;\r\n\r\n\t\tif ( hasVertexTexture ) {\r\n\r\n\t\t\tshader = {\r\n\r\n\t\t\t\tvertexShader: [\r\n\r\n\t\t\t\t\t\"uniform lowp int renderType;\",\r\n\r\n\t\t\t\t\t\"uniform vec3 screenPosition;\",\r\n\t\t\t\t\t\"uniform vec2 scale;\",\r\n\t\t\t\t\t\"uniform float rotation;\",\r\n\r\n\t\t\t\t\t\"uniform sampler2D occlusionMap;\",\r\n\r\n\t\t\t\t\t\"attribute vec2 position;\",\r\n\t\t\t\t\t\"attribute vec2 uv;\",\r\n\r\n\t\t\t\t\t\"varying vec2 vUV;\",\r\n\t\t\t\t\t\"varying float vVisibility;\",\r\n\r\n\t\t\t\t\t\"void main() {\",\r\n\r\n\t\t\t\t\t\t\"vUV = uv;\",\r\n\r\n\t\t\t\t\t\t\"vec2 pos = position;\",\r\n\r\n\t\t\t\t\t\t\"if( renderType == 2 ) {\",\r\n\r\n\t\t\t\t\t\t\t\"vec4 visibility = texture2D( occlusionMap, vec2( 0.1, 0.1 ) );\",\r\n\t\t\t\t\t\t\t\"visibility += texture2D( occlusionMap, vec2( 0.5, 0.1 ) );\",\r\n\t\t\t\t\t\t\t\"visibility += texture2D( occlusionMap, vec2( 0.9, 0.1 ) );\",\r\n\t\t\t\t\t\t\t\"visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) );\",\r\n\t\t\t\t\t\t\t\"visibility += texture2D( occlusionMap, vec2( 0.9, 0.9 ) );\",\r\n\t\t\t\t\t\t\t\"visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) );\",\r\n\t\t\t\t\t\t\t\"visibility += texture2D( occlusionMap, vec2( 0.1, 0.9 ) );\",\r\n\t\t\t\t\t\t\t\"visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) );\",\r\n\t\t\t\t\t\t\t\"visibility += texture2D( occlusionMap, vec2( 0.5, 0.5 ) );\",\r\n\r\n\t\t\t\t\t\t\t\"vVisibility = visibility.r / 9.0;\",\r\n\t\t\t\t\t\t\t\"vVisibility *= 1.0 - visibility.g / 9.0;\",\r\n\t\t\t\t\t\t\t\"vVisibility *= visibility.b / 9.0;\",\r\n\t\t\t\t\t\t\t\"vVisibility *= 1.0 - visibility.a / 9.0;\",\r\n\r\n\t\t\t\t\t\t\t\"pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;\",\r\n\t\t\t\t\t\t\t\"pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;\",\r\n\r\n\t\t\t\t\t\t\"}\",\r\n\r\n\t\t\t\t\t\t\"gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );\",\r\n\r\n\t\t\t\t\t\"}\"\r\n\r\n\t\t\t\t].join( \"\\n\" ),\r\n\r\n\t\t\t\tfragmentShader: [\r\n\r\n\t\t\t\t\t\"uniform lowp int renderType;\",\r\n\r\n\t\t\t\t\t\"uniform sampler2D map;\",\r\n\t\t\t\t\t\"uniform float opacity;\",\r\n\t\t\t\t\t\"uniform vec3 color;\",\r\n\r\n\t\t\t\t\t\"varying vec2 vUV;\",\r\n\t\t\t\t\t\"varying float vVisibility;\",\r\n\r\n\t\t\t\t\t\"void main() {\",\r\n\r\n\t\t\t\t\t\t// pink square\r\n\r\n\t\t\t\t\t\t\"if( renderType == 0 ) {\",\r\n\r\n\t\t\t\t\t\t\t\"gl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );\",\r\n\r\n\t\t\t\t\t\t// restore\r\n\r\n\t\t\t\t\t\t\"} else if( renderType == 1 ) {\",\r\n\r\n\t\t\t\t\t\t\t\"gl_FragColor = texture2D( map, vUV );\",\r\n\r\n\t\t\t\t\t\t// flare\r\n\r\n\t\t\t\t\t\t\"} else {\",\r\n\r\n\t\t\t\t\t\t\t\"vec4 texture = texture2D( map, vUV );\",\r\n\t\t\t\t\t\t\t\"texture.a *= opacity * vVisibility;\",\r\n\t\t\t\t\t\t\t\"gl_FragColor = texture;\",\r\n\t\t\t\t\t\t\t\"gl_FragColor.rgb *= color;\",\r\n\r\n\t\t\t\t\t\t\"}\",\r\n\r\n\t\t\t\t\t\"}\"\r\n\r\n\t\t\t\t].join( \"\\n\" )\r\n\r\n\t\t\t};\r\n\r\n\t\t} else {\r\n\r\n\t\t\tshader = {\r\n\r\n\t\t\t\tvertexShader: [\r\n\r\n\t\t\t\t\t\"uniform lowp int renderType;\",\r\n\r\n\t\t\t\t\t\"uniform vec3 screenPosition;\",\r\n\t\t\t\t\t\"uniform vec2 scale;\",\r\n\t\t\t\t\t\"uniform float rotation;\",\r\n\r\n\t\t\t\t\t\"attribute vec2 position;\",\r\n\t\t\t\t\t\"attribute vec2 uv;\",\r\n\r\n\t\t\t\t\t\"varying vec2 vUV;\",\r\n\r\n\t\t\t\t\t\"void main() {\",\r\n\r\n\t\t\t\t\t\t\"vUV = uv;\",\r\n\r\n\t\t\t\t\t\t\"vec2 pos = position;\",\r\n\r\n\t\t\t\t\t\t\"if( renderType == 2 ) {\",\r\n\r\n\t\t\t\t\t\t\t\"pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;\",\r\n\t\t\t\t\t\t\t\"pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;\",\r\n\r\n\t\t\t\t\t\t\"}\",\r\n\r\n\t\t\t\t\t\t\"gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );\",\r\n\r\n\t\t\t\t\t\"}\"\r\n\r\n\t\t\t\t].join( \"\\n\" ),\r\n\r\n\t\t\t\tfragmentShader: [\r\n\r\n\t\t\t\t\t\"precision mediump float;\",\r\n\r\n\t\t\t\t\t\"uniform lowp int renderType;\",\r\n\r\n\t\t\t\t\t\"uniform sampler2D map;\",\r\n\t\t\t\t\t\"uniform sampler2D occlusionMap;\",\r\n\t\t\t\t\t\"uniform float opacity;\",\r\n\t\t\t\t\t\"uniform vec3 color;\",\r\n\r\n\t\t\t\t\t\"varying vec2 vUV;\",\r\n\r\n\t\t\t\t\t\"void main() {\",\r\n\r\n\t\t\t\t\t\t// pink square\r\n\r\n\t\t\t\t\t\t\"if( renderType == 0 ) {\",\r\n\r\n\t\t\t\t\t\t\t\"gl_FragColor = vec4( texture2D( map, vUV ).rgb, 0.0 );\",\r\n\r\n\t\t\t\t\t\t// restore\r\n\r\n\t\t\t\t\t\t\"} else if( renderType == 1 ) {\",\r\n\r\n\t\t\t\t\t\t\t\"gl_FragColor = texture2D( map, vUV );\",\r\n\r\n\t\t\t\t\t\t// flare\r\n\r\n\t\t\t\t\t\t\"} else {\",\r\n\r\n\t\t\t\t\t\t\t\"float visibility = texture2D( occlusionMap, vec2( 0.5, 0.1 ) ).a;\",\r\n\t\t\t\t\t\t\t\"visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) ).a;\",\r\n\t\t\t\t\t\t\t\"visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) ).a;\",\r\n\t\t\t\t\t\t\t\"visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) ).a;\",\r\n\t\t\t\t\t\t\t\"visibility = ( 1.0 - visibility / 4.0 );\",\r\n\r\n\t\t\t\t\t\t\t\"vec4 texture = texture2D( map, vUV );\",\r\n\t\t\t\t\t\t\t\"texture.a *= opacity * visibility;\",\r\n\t\t\t\t\t\t\t\"gl_FragColor = texture;\",\r\n\t\t\t\t\t\t\t\"gl_FragColor.rgb *= color;\",\r\n\r\n\t\t\t\t\t\t\"}\",\r\n\r\n\t\t\t\t\t\"}\"\r\n\r\n\t\t\t\t].join( \"\\n\" )\r\n\r\n\t\t\t};\r\n\r\n\t\t}\r\n\r\n\t\tprogram = createProgram( shader );\r\n\r\n\t\tattributes = {\r\n\t\t\tvertex: gl.getAttribLocation ( program, \"position\" ),\r\n\t\t\tuv: gl.getAttribLocation ( program, \"uv\" )\r\n\t\t}\r\n\r\n\t\tuniforms = {\r\n\t\t\trenderType: gl.getUniformLocation( program, \"renderType\" ),\r\n\t\t\tmap: gl.getUniformLocation( program, \"map\" ),\r\n\t\t\tocclusionMap: gl.getUniformLocation( program, \"occlusionMap\" ),\r\n\t\t\topacity: gl.getUniformLocation( program, \"opacity\" ),\r\n\t\t\tcolor: gl.getUniformLocation( program, \"color\" ),\r\n\t\t\tscale: gl.getUniformLocation( program, \"scale\" ),\r\n\t\t\trotation: gl.getUniformLocation( program, \"rotation\" ),\r\n\t\t\tscreenPosition: gl.getUniformLocation( program, \"screenPosition\" )\r\n\t\t};\r\n\r\n\t};\r\n\r\n\t/*\r\n\t * Render lens flares\r\n\t * Method: renders 16x16 0xff00ff-colored points scattered over the light source area,\r\n\t * reads these back and calculates occlusion.\r\n\t */\r\n\r\n\tthis.render = function ( scene, camera, viewportWidth, viewportHeight ) {\r\n\r\n\t\tif ( flares.length === 0 ) return;\r\n\r\n\t\tvar tempPosition = new THREE.Vector3();\r\n\r\n\t\tvar invAspect = viewportHeight / viewportWidth,\r\n\t\t\thalfViewportWidth = viewportWidth * 0.5,\r\n\t\t\thalfViewportHeight = viewportHeight * 0.5;\r\n\r\n\t\tvar size = 16 / viewportHeight,\r\n\t\t\tscale = new THREE.Vector2( size * invAspect, size );\r\n\r\n\t\tvar screenPosition = new THREE.Vector3( 1, 1, 0 ),\r\n\t\t\tscreenPositionPixels = new THREE.Vector2( 1, 1 );\r\n\r\n\t\tif ( program === undefined ) {\r\n\r\n\t\t\tinit();\r\n\r\n\t\t}\r\n\r\n\t\tgl.useProgram( program );\r\n\r\n\t\tgl.enableVertexAttribArray( attributes.vertex );\r\n\t\tgl.enableVertexAttribArray( attributes.uv );\r\n\r\n\t\t// loop through all lens flares to update their occlusion and positions\r\n\t\t// setup gl and common used attribs/unforms\r\n\r\n\t\tgl.uniform1i( uniforms.occlusionMap, 0 );\r\n\t\tgl.uniform1i( uniforms.map, 1 );\r\n\r\n\t\tgl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );\r\n\t\tgl.vertexAttribPointer( attributes.vertex, 2, gl.FLOAT, false, 2 * 8, 0 );\r\n\t\tgl.vertexAttribPointer( attributes.uv, 2, gl.FLOAT, false, 2 * 8, 8 );\r\n\r\n\t\tgl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );\r\n\r\n\t\tgl.disable( gl.CULL_FACE );\r\n\t\tgl.depthMask( false );\r\n\r\n\t\tfor ( var i = 0, l = flares.length; i < l; i ++ ) {\r\n\r\n\t\t\tsize = 16 / viewportHeight;\r\n\t\t\tscale.set( size * invAspect, size );\r\n\r\n\t\t\t// calc object screen position\r\n\r\n\t\t\tvar flare = flares[ i ];\r\n\r\n\t\t\ttempPosition.set( flare.matrixWorld.elements[12], flare.matrixWorld.elements[13], flare.matrixWorld.elements[14] );\r\n\r\n\t\t\ttempPosition.applyMatrix4( camera.matrixWorldInverse );\r\n\t\t\ttempPosition.applyProjection( camera.projectionMatrix );\r\n\r\n\t\t\t// setup arrays for gl programs\r\n\r\n\t\t\tscreenPosition.copy( tempPosition )\r\n\r\n\t\t\tscreenPositionPixels.x = screenPosition.x * halfViewportWidth + halfViewportWidth;\r\n\t\t\tscreenPositionPixels.y = screenPosition.y * halfViewportHeight + halfViewportHeight;\r\n\r\n\t\t\t// screen cull\r\n\r\n\t\t\tif ( hasVertexTexture || (\r\n\t\t\t\tscreenPositionPixels.x > 0 &&\r\n\t\t\t\tscreenPositionPixels.x < viewportWidth &&\r\n\t\t\t\tscreenPositionPixels.y > 0 &&\r\n\t\t\t\tscreenPositionPixels.y < viewportHeight ) ) {\r\n\r\n\t\t\t\t// save current RGB to temp texture\r\n\r\n\t\t\t\tgl.activeTexture( gl.TEXTURE1 );\r\n\t\t\t\tgl.bindTexture( gl.TEXTURE_2D, tempTexture );\r\n\t\t\t\tgl.copyTexImage2D( gl.TEXTURE_2D, 0, gl.RGB, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0 );\r\n\r\n\r\n\t\t\t\t// render pink quad\r\n\r\n\t\t\t\tgl.uniform1i( uniforms.renderType, 0 );\r\n\t\t\t\tgl.uniform2f( uniforms.scale, scale.x, scale.y );\r\n\t\t\t\tgl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z );\r\n\r\n\t\t\t\tgl.disable( gl.BLEND );\r\n\t\t\t\tgl.enable( gl.DEPTH_TEST );\r\n\r\n\t\t\t\tgl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );\r\n\r\n\r\n\t\t\t\t// copy result to occlusionMap\r\n\r\n\t\t\t\tgl.activeTexture( gl.TEXTURE0 );\r\n\t\t\t\tgl.bindTexture( gl.TEXTURE_2D, occlusionTexture );\r\n\t\t\t\tgl.copyTexImage2D( gl.TEXTURE_2D, 0, gl.RGBA, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0 );\r\n\r\n\r\n\t\t\t\t// restore graphics\r\n\r\n\t\t\t\tgl.uniform1i( uniforms.renderType, 1 );\r\n\t\t\t\tgl.disable( gl.DEPTH_TEST );\r\n\r\n\t\t\t\tgl.activeTexture( gl.TEXTURE1 );\r\n\t\t\t\tgl.bindTexture( gl.TEXTURE_2D, tempTexture );\r\n\t\t\t\tgl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );\r\n\r\n\r\n\t\t\t\t// update object positions\r\n\r\n\t\t\t\tflare.positionScreen.copy( screenPosition )\r\n\r\n\t\t\t\tif ( flare.customUpdateCallback ) {\r\n\r\n\t\t\t\t\tflare.customUpdateCallback( flare );\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\tflare.updateLensFlares();\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// render flares\r\n\r\n\t\t\t\tgl.uniform1i( uniforms.renderType, 2 );\r\n\t\t\t\tgl.enable( gl.BLEND );\r\n\r\n\t\t\t\tfor ( var j = 0, jl = flare.lensFlares.length; j < jl; j ++ ) {\r\n\r\n\t\t\t\t\tvar sprite = flare.lensFlares[ j ];\r\n\r\n\t\t\t\t\tif ( sprite.opacity > 0.001 && sprite.scale > 0.001 ) {\r\n\r\n\t\t\t\t\t\tscreenPosition.x = sprite.x;\r\n\t\t\t\t\t\tscreenPosition.y = sprite.y;\r\n\t\t\t\t\t\tscreenPosition.z = sprite.z;\r\n\r\n\t\t\t\t\t\tsize = sprite.size * sprite.scale / viewportHeight;\r\n\r\n\t\t\t\t\t\tscale.x = size * invAspect;\r\n\t\t\t\t\t\tscale.y = size;\r\n\r\n\t\t\t\t\t\tgl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z );\r\n\t\t\t\t\t\tgl.uniform2f( uniforms.scale, scale.x, scale.y );\r\n\t\t\t\t\t\tgl.uniform1f( uniforms.rotation, sprite.rotation );\r\n\r\n\t\t\t\t\t\tgl.uniform1f( uniforms.opacity, sprite.opacity );\r\n\t\t\t\t\t\tgl.uniform3f( uniforms.color, sprite.color.r, sprite.color.g, sprite.color.b );\r\n\r\n\t\t\t\t\t\trenderer.state.setBlending( sprite.blending, sprite.blendEquation, sprite.blendSrc, sprite.blendDst );\r\n\t\t\t\t\t\trenderer.setTexture( sprite.texture, 1 );\r\n\r\n\t\t\t\t\t\tgl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\t// restore gl\r\n\r\n\t\tgl.enable( gl.CULL_FACE );\r\n\t\tgl.enable( gl.DEPTH_TEST );\r\n\t\tgl.depthMask( true );\r\n\r\n\t\trenderer.resetGLState();\r\n\r\n\t};\r\n\r\n\tfunction createProgram ( shader ) {\r\n\r\n\t\tvar program = gl.createProgram();\r\n\r\n\t\tvar fragmentShader = gl.createShader( gl.FRAGMENT_SHADER );\r\n\t\tvar vertexShader = gl.createShader( gl.VERTEX_SHADER );\r\n\r\n\t\tvar prefix = \"precision \" + renderer.getPrecision() + \" float;\\n\";\r\n\r\n\t\tgl.shaderSource( fragmentShader, prefix + shader.fragmentShader );\r\n\t\tgl.shaderSource( vertexShader, prefix + shader.vertexShader );\r\n\r\n\t\tgl.compileShader( fragmentShader );\r\n\t\tgl.compileShader( vertexShader );\r\n\r\n\t\tgl.attachShader( program, fragmentShader );\r\n\t\tgl.attachShader( program, vertexShader );\r\n\r\n\t\tgl.linkProgram( program );\r\n\r\n\t\treturn program;\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/renderers/webgl/plugins/ShadowMapPlugin.js\r\n\r\n/**\r\n * @author alteredq / http://alteredqualia.com/\r\n */\r\n\r\nTHREE.ShadowMapPlugin = function ( _renderer, _lights, _webglObjects, _webglObjectsImmediate ) {\r\n\r\n\tvar _gl = _renderer.context;\r\n\r\n\tvar _depthMaterial, _depthMaterialMorph, _depthMaterialSkin, _depthMaterialMorphSkin,\r\n\r\n\t_frustum = new THREE.Frustum(),\r\n\t_projScreenMatrix = new THREE.Matrix4(),\r\n\r\n\t_min = new THREE.Vector3(),\r\n\t_max = new THREE.Vector3(),\r\n\r\n\t_matrixPosition = new THREE.Vector3(),\r\n\r\n\t_renderList = [];\r\n\r\n\t// init\r\n\r\n\tvar depthShader = THREE.ShaderLib[ \"depthRGBA\" ];\r\n\tvar depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms );\r\n\r\n\t_depthMaterial = new THREE.ShaderMaterial( {\r\n\t\tuniforms: depthUniforms,\r\n\t\tvertexShader: depthShader.vertexShader,\r\n\t\tfragmentShader: depthShader.fragmentShader\r\n\t } );\r\n\r\n\t_depthMaterialMorph = new THREE.ShaderMaterial( {\r\n\t\tuniforms: depthUniforms,\r\n\t\tvertexShader: depthShader.vertexShader,\r\n\t\tfragmentShader: depthShader.fragmentShader,\r\n\t\tmorphTargets: true\r\n\t} );\r\n\r\n\t_depthMaterialSkin = new THREE.ShaderMaterial( {\r\n\t\tuniforms: depthUniforms,\r\n\t\tvertexShader: depthShader.vertexShader,\r\n\t\tfragmentShader: depthShader.fragmentShader,\r\n\t\tskinning: true\r\n\t} );\r\n\r\n\t_depthMaterialMorphSkin = new THREE.ShaderMaterial( {\r\n\t\tuniforms: depthUniforms,\r\n\t\tvertexShader: depthShader.vertexShader,\r\n\t\tfragmentShader: depthShader.fragmentShader,\r\n\t\tmorphTargets: true,\r\n\t\tskinning: true\r\n\t} );\r\n\r\n\t_depthMaterial._shadowPass = true;\r\n\t_depthMaterialMorph._shadowPass = true;\r\n\t_depthMaterialSkin._shadowPass = true;\r\n\t_depthMaterialMorphSkin._shadowPass = true;\r\n\r\n\tthis.render = function ( scene, camera ) {\r\n\r\n\t\tif ( _renderer.shadowMapEnabled === false ) return;\r\n\r\n\t\tvar i, il, j, jl, n,\r\n\r\n\t\tshadowMap, shadowMatrix, shadowCamera,\r\n\t\tbuffer, material,\r\n\t\twebglObject, object, light,\r\n\r\n\t\tlights = [],\r\n\t\tk = 0,\r\n\r\n\t\tfog = null;\r\n\r\n\t\t// set GL state for depth map\r\n\r\n\t\t_gl.clearColor( 1, 1, 1, 1 );\r\n\t\t_gl.disable( _gl.BLEND );\r\n\r\n\t\t_gl.enable( _gl.CULL_FACE );\r\n\t\t_gl.frontFace( _gl.CCW );\r\n\r\n\t\tif ( _renderer.shadowMapCullFace === THREE.CullFaceFront ) {\r\n\r\n\t\t\t_gl.cullFace( _gl.FRONT );\r\n\r\n\t\t} else {\r\n\r\n\t\t\t_gl.cullFace( _gl.BACK );\r\n\r\n\t\t}\r\n\r\n\t\t_renderer.state.setDepthTest( true );\r\n\r\n\t\t// preprocess lights\r\n\t\t// \t- skip lights that are not casting shadows\r\n\t\t//\t- create virtual lights for cascaded shadow maps\r\n\r\n\t\tfor ( i = 0, il = _lights.length; i < il; i ++ ) {\r\n\r\n\t\t\tlight = _lights[ i ];\r\n\r\n\t\t\tif ( ! light.castShadow ) continue;\r\n\r\n\t\t\tif ( ( light instanceof THREE.DirectionalLight ) && light.shadowCascade ) {\r\n\r\n\t\t\t\tfor ( n = 0; n < light.shadowCascadeCount; n ++ ) {\r\n\r\n\t\t\t\t\tvar virtualLight;\r\n\r\n\t\t\t\t\tif ( ! light.shadowCascadeArray[ n ] ) {\r\n\r\n\t\t\t\t\t\tvirtualLight = createVirtualLight( light, n );\r\n\t\t\t\t\t\tvirtualLight.originalCamera = camera;\r\n\r\n\t\t\t\t\t\tvar gyro = new THREE.Gyroscope();\r\n\t\t\t\t\t\tgyro.position.copy( light.shadowCascadeOffset );\r\n\r\n\t\t\t\t\t\tgyro.add( virtualLight );\r\n\t\t\t\t\t\tgyro.add( virtualLight.target );\r\n\r\n\t\t\t\t\t\tcamera.add( gyro );\r\n\r\n\t\t\t\t\t\tlight.shadowCascadeArray[ n ] = virtualLight;\r\n\r\n\t\t\t\t\t\t//console.log( \"Created virtualLight\", virtualLight );\r\n\r\n\t\t\t\t\t} else {\r\n\r\n\t\t\t\t\t\tvirtualLight = light.shadowCascadeArray[ n ];\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tupdateVirtualLight( light, n );\r\n\r\n\t\t\t\t\tlights[ k ] = virtualLight;\r\n\t\t\t\t\tk ++;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tlights[ k ] = light;\r\n\t\t\t\tk ++;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\t// render depth map\r\n\r\n\t\tfor ( i = 0, il = lights.length; i < il; i ++ ) {\r\n\r\n\t\t\tlight = lights[ i ];\r\n\r\n\t\t\tif ( ! light.shadowMap ) {\r\n\r\n\t\t\t\tvar shadowFilter = THREE.LinearFilter;\r\n\r\n\t\t\t\tif ( _renderer.shadowMapType === THREE.PCFSoftShadowMap ) {\r\n\r\n\t\t\t\t\tshadowFilter = THREE.NearestFilter;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvar pars = { minFilter: shadowFilter, magFilter: shadowFilter, format: THREE.RGBAFormat };\r\n\r\n\t\t\t\tlight.shadowMap = new THREE.WebGLRenderTarget( light.shadowMapWidth, light.shadowMapHeight, pars );\r\n\t\t\t\tlight.shadowMapSize = new THREE.Vector2( light.shadowMapWidth, light.shadowMapHeight );\r\n\r\n\t\t\t\tlight.shadowMatrix = new THREE.Matrix4();\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( ! light.shadowCamera ) {\r\n\r\n\t\t\t\tif ( light instanceof THREE.SpotLight ) {\r\n\r\n\t\t\t\t\tlight.shadowCamera = new THREE.PerspectiveCamera( light.shadowCameraFov, light.shadowMapWidth / light.shadowMapHeight, light.shadowCameraNear, light.shadowCameraFar );\r\n\r\n\t\t\t\t} else if ( light instanceof THREE.DirectionalLight ) {\r\n\r\n\t\t\t\t\tlight.shadowCamera = new THREE.OrthographicCamera( light.shadowCameraLeft, light.shadowCameraRight, light.shadowCameraTop, light.shadowCameraBottom, light.shadowCameraNear, light.shadowCameraFar );\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\tTHREE.error( \"THREE.ShadowMapPlugin: Unsupported light type for shadow\", light );\r\n\t\t\t\t\tcontinue;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tscene.add( light.shadowCamera );\r\n\r\n\t\t\t\tif ( scene.autoUpdate === true ) scene.updateMatrixWorld();\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( light.shadowCameraVisible && ! light.cameraHelper ) {\r\n\r\n\t\t\t\tlight.cameraHelper = new THREE.CameraHelper( light.shadowCamera );\r\n\t\t\t\tscene.add( light.cameraHelper );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( light.isVirtual && virtualLight.originalCamera == camera ) {\r\n\r\n\t\t\t\tupdateShadowCamera( camera, light );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tshadowMap = light.shadowMap;\r\n\t\t\tshadowMatrix = light.shadowMatrix;\r\n\t\t\tshadowCamera = light.shadowCamera;\r\n\r\n\t\t\t//\r\n\r\n\t\t\tshadowCamera.position.setFromMatrixPosition( light.matrixWorld );\r\n\t\t\t_matrixPosition.setFromMatrixPosition( light.target.matrixWorld );\r\n\t\t\tshadowCamera.lookAt( _matrixPosition );\r\n\t\t\tshadowCamera.updateMatrixWorld();\r\n\r\n\t\t\tshadowCamera.matrixWorldInverse.getInverse( shadowCamera.matrixWorld );\r\n\r\n\t\t\t//\r\n\r\n\t\t\tif ( light.cameraHelper ) light.cameraHelper.visible = light.shadowCameraVisible;\r\n\t\t\tif ( light.shadowCameraVisible ) light.cameraHelper.update();\r\n\r\n\t\t\t// compute shadow matrix\r\n\r\n\t\t\tshadowMatrix.set(\r\n\t\t\t\t0.5, 0.0, 0.0, 0.5,\r\n\t\t\t\t0.0, 0.5, 0.0, 0.5,\r\n\t\t\t\t0.0, 0.0, 0.5, 0.5,\r\n\t\t\t\t0.0, 0.0, 0.0, 1.0\r\n\t\t\t);\r\n\r\n\t\t\tshadowMatrix.multiply( shadowCamera.projectionMatrix );\r\n\t\t\tshadowMatrix.multiply( shadowCamera.matrixWorldInverse );\r\n\r\n\t\t\t// update camera matrices and frustum\r\n\r\n\t\t\t_projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse );\r\n\t\t\t_frustum.setFromMatrix( _projScreenMatrix );\r\n\r\n\t\t\t// render shadow map\r\n\r\n\t\t\t_renderer.setRenderTarget( shadowMap );\r\n\t\t\t_renderer.clear();\r\n\r\n\t\t\t// set object matrices & frustum culling\r\n\r\n\t\t\t_renderList.length = 0;\r\n\r\n\t\t\tprojectObject( scene, scene, shadowCamera );\r\n\r\n\r\n\t\t\t// render regular objects\r\n\r\n\t\t\tvar objectMaterial, useMorphing, useSkinning;\r\n\r\n\t\t\tfor ( j = 0, jl = _renderList.length; j < jl; j ++ ) {\r\n\r\n\t\t\t\twebglObject = _renderList[ j ];\r\n\r\n\t\t\t\tobject = webglObject.object;\r\n\t\t\t\tbuffer = webglObject.buffer;\r\n\r\n\t\t\t\t// culling is overriden globally for all objects\r\n\t\t\t\t// while rendering depth map\r\n\r\n\t\t\t\t// need to deal with MeshFaceMaterial somehow\r\n\t\t\t\t// in that case just use the first of material.materials for now\r\n\t\t\t\t// (proper solution would require to break objects by materials\r\n\t\t\t\t// similarly to regular rendering and then set corresponding\r\n\t\t\t\t// depth materials per each chunk instead of just once per object)\r\n\r\n\t\t\t\tobjectMaterial = getObjectMaterial( object );\r\n\r\n\t\t\t\tuseMorphing = object.geometry.morphTargets !== undefined && object.geometry.morphTargets.length > 0 && objectMaterial.morphTargets;\r\n\t\t\t\tuseSkinning = object instanceof THREE.SkinnedMesh && objectMaterial.skinning;\r\n\r\n\t\t\t\tif ( object.customDepthMaterial ) {\r\n\r\n\t\t\t\t\tmaterial = object.customDepthMaterial;\r\n\r\n\t\t\t\t} else if ( useSkinning ) {\r\n\r\n\t\t\t\t\tmaterial = useMorphing ? _depthMaterialMorphSkin : _depthMaterialSkin;\r\n\r\n\t\t\t\t} else if ( useMorphing ) {\r\n\r\n\t\t\t\t\tmaterial = _depthMaterialMorph;\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\tmaterial = _depthMaterial;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\t_renderer.setMaterialFaces( objectMaterial );\r\n\r\n\t\t\t\tif ( buffer instanceof THREE.BufferGeometry ) {\r\n\r\n\t\t\t\t\t_renderer.renderBufferDirect( shadowCamera, _lights, fog, material, buffer, object );\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\t_renderer.renderBuffer( shadowCamera, _lights, fog, material, buffer, object );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\t// set matrices and render immediate objects\r\n\r\n\t\t\tfor ( j = 0, jl = _webglObjectsImmediate.length; j < jl; j ++ ) {\r\n\r\n\t\t\t\twebglObject = _webglObjectsImmediate[ j ];\r\n\t\t\t\tobject = webglObject.object;\r\n\r\n\t\t\t\tif ( object.visible && object.castShadow ) {\r\n\r\n\t\t\t\t\tobject._modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );\r\n\r\n\t\t\t\t\t_renderer.renderImmediateObject( shadowCamera, _lights, fog, _depthMaterial, object );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\t// restore GL state\r\n\r\n\t\tvar clearColor = _renderer.getClearColor(),\r\n\t\tclearAlpha = _renderer.getClearAlpha();\r\n\r\n\t\t_gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearAlpha );\r\n\t\t_gl.enable( _gl.BLEND );\r\n\r\n\t\tif ( _renderer.shadowMapCullFace === THREE.CullFaceFront ) {\r\n\r\n\t\t\t_gl.cullFace( _gl.BACK );\r\n\r\n\t\t}\r\n\r\n\t\t_renderer.resetGLState();\r\n\r\n\t};\r\n\r\n\tfunction projectObject( scene, object, shadowCamera ) {\r\n\r\n\t\tif ( object.visible ) {\r\n\r\n\t\t\tvar webglObjects = _webglObjects[ object.id ];\r\n\r\n\t\t\tif ( webglObjects && object.castShadow && (object.frustumCulled === false || _frustum.intersectsObject( object ) === true) ) {\r\n\r\n\t\t\t\tfor ( var i = 0, l = webglObjects.length; i < l; i ++ ) {\r\n\r\n\t\t\t\t\tvar webglObject = webglObjects[ i ];\r\n\r\n\t\t\t\t\tobject._modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );\r\n\t\t\t\t\t_renderList.push( webglObject );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\tfor ( var i = 0, l = object.children.length; i < l; i ++ ) {\r\n\r\n\t\t\t\tprojectObject( scene, object.children[ i ], shadowCamera );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tfunction createVirtualLight( light, cascade ) {\r\n\r\n\t\tvar virtualLight = new THREE.DirectionalLight();\r\n\r\n\t\tvirtualLight.isVirtual = true;\r\n\r\n\t\tvirtualLight.onlyShadow = true;\r\n\t\tvirtualLight.castShadow = true;\r\n\r\n\t\tvirtualLight.shadowCameraNear = light.shadowCameraNear;\r\n\t\tvirtualLight.shadowCameraFar = light.shadowCameraFar;\r\n\r\n\t\tvirtualLight.shadowCameraLeft = light.shadowCameraLeft;\r\n\t\tvirtualLight.shadowCameraRight = light.shadowCameraRight;\r\n\t\tvirtualLight.shadowCameraBottom = light.shadowCameraBottom;\r\n\t\tvirtualLight.shadowCameraTop = light.shadowCameraTop;\r\n\r\n\t\tvirtualLight.shadowCameraVisible = light.shadowCameraVisible;\r\n\r\n\t\tvirtualLight.shadowDarkness = light.shadowDarkness;\r\n\r\n\t\tvirtualLight.shadowBias = light.shadowCascadeBias[ cascade ];\r\n\t\tvirtualLight.shadowMapWidth = light.shadowCascadeWidth[ cascade ];\r\n\t\tvirtualLight.shadowMapHeight = light.shadowCascadeHeight[ cascade ];\r\n\r\n\t\tvirtualLight.pointsWorld = [];\r\n\t\tvirtualLight.pointsFrustum = [];\r\n\r\n\t\tvar pointsWorld = virtualLight.pointsWorld,\r\n\t\t\tpointsFrustum = virtualLight.pointsFrustum;\r\n\r\n\t\tfor ( var i = 0; i < 8; i ++ ) {\r\n\r\n\t\t\tpointsWorld[ i ] = new THREE.Vector3();\r\n\t\t\tpointsFrustum[ i ] = new THREE.Vector3();\r\n\r\n\t\t}\r\n\r\n\t\tvar nearZ = light.shadowCascadeNearZ[ cascade ];\r\n\t\tvar farZ = light.shadowCascadeFarZ[ cascade ];\r\n\r\n\t\tpointsFrustum[ 0 ].set( - 1, - 1, nearZ );\r\n\t\tpointsFrustum[ 1 ].set( 1, - 1, nearZ );\r\n\t\tpointsFrustum[ 2 ].set( - 1, 1, nearZ );\r\n\t\tpointsFrustum[ 3 ].set( 1, 1, nearZ );\r\n\r\n\t\tpointsFrustum[ 4 ].set( - 1, - 1, farZ );\r\n\t\tpointsFrustum[ 5 ].set( 1, - 1, farZ );\r\n\t\tpointsFrustum[ 6 ].set( - 1, 1, farZ );\r\n\t\tpointsFrustum[ 7 ].set( 1, 1, farZ );\r\n\r\n\t\treturn virtualLight;\r\n\r\n\t}\r\n\r\n\t// Synchronize virtual light with the original light\r\n\r\n\tfunction updateVirtualLight( light, cascade ) {\r\n\r\n\t\tvar virtualLight = light.shadowCascadeArray[ cascade ];\r\n\r\n\t\tvirtualLight.position.copy( light.position );\r\n\t\tvirtualLight.target.position.copy( light.target.position );\r\n\t\tvirtualLight.lookAt( virtualLight.target );\r\n\r\n\t\tvirtualLight.shadowCameraVisible = light.shadowCameraVisible;\r\n\t\tvirtualLight.shadowDarkness = light.shadowDarkness;\r\n\r\n\t\tvirtualLight.shadowBias = light.shadowCascadeBias[ cascade ];\r\n\r\n\t\tvar nearZ = light.shadowCascadeNearZ[ cascade ];\r\n\t\tvar farZ = light.shadowCascadeFarZ[ cascade ];\r\n\r\n\t\tvar pointsFrustum = virtualLight.pointsFrustum;\r\n\r\n\t\tpointsFrustum[ 0 ].z = nearZ;\r\n\t\tpointsFrustum[ 1 ].z = nearZ;\r\n\t\tpointsFrustum[ 2 ].z = nearZ;\r\n\t\tpointsFrustum[ 3 ].z = nearZ;\r\n\r\n\t\tpointsFrustum[ 4 ].z = farZ;\r\n\t\tpointsFrustum[ 5 ].z = farZ;\r\n\t\tpointsFrustum[ 6 ].z = farZ;\r\n\t\tpointsFrustum[ 7 ].z = farZ;\r\n\r\n\t}\r\n\r\n\t// Fit shadow camera's ortho frustum to camera frustum\r\n\r\n\tfunction updateShadowCamera( camera, light ) {\r\n\r\n\t\tvar shadowCamera = light.shadowCamera,\r\n\t\t\tpointsFrustum = light.pointsFrustum,\r\n\t\t\tpointsWorld = light.pointsWorld;\r\n\r\n\t\t_min.set( Infinity, Infinity, Infinity );\r\n\t\t_max.set( - Infinity, - Infinity, - Infinity );\r\n\r\n\t\tfor ( var i = 0; i < 8; i ++ ) {\r\n\r\n\t\t\tvar p = pointsWorld[ i ];\r\n\r\n\t\t\tp.copy( pointsFrustum[ i ] );\r\n\t\t\tp.unproject( camera );\r\n\r\n\t\t\tp.applyMatrix4( shadowCamera.matrixWorldInverse );\r\n\r\n\t\t\tif ( p.x < _min.x ) _min.x = p.x;\r\n\t\t\tif ( p.x > _max.x ) _max.x = p.x;\r\n\r\n\t\t\tif ( p.y < _min.y ) _min.y = p.y;\r\n\t\t\tif ( p.y > _max.y ) _max.y = p.y;\r\n\r\n\t\t\tif ( p.z < _min.z ) _min.z = p.z;\r\n\t\t\tif ( p.z > _max.z ) _max.z = p.z;\r\n\r\n\t\t}\r\n\r\n\t\tshadowCamera.left = _min.x;\r\n\t\tshadowCamera.right = _max.x;\r\n\t\tshadowCamera.top = _max.y;\r\n\t\tshadowCamera.bottom = _min.y;\r\n\r\n\t\t// can't really fit near/far\r\n\t\t//shadowCamera.near = _min.z;\r\n\t\t//shadowCamera.far = _max.z;\r\n\r\n\t\tshadowCamera.updateProjectionMatrix();\r\n\r\n\t}\r\n\r\n\t// For the moment just ignore objects that have multiple materials with different animation methods\r\n\t// Only the first material will be taken into account for deciding which depth material to use for shadow maps\r\n\r\n\tfunction getObjectMaterial( object ) {\r\n\r\n\t\treturn object.material instanceof THREE.MeshFaceMaterial\r\n\t\t\t? object.material.materials[ 0 ]\r\n\t\t\t: object.material;\r\n\r\n\t};\r\n\r\n};\r\n\r\n// File:src/renderers/webgl/plugins/SpritePlugin.js\r\n\r\n/**\r\n * @author mikael emtinger / http://gomo.se/\r\n * @author alteredq / http://alteredqualia.com/\r\n */\r\n\r\nTHREE.SpritePlugin = function ( renderer, sprites ) {\r\n\r\n\tvar gl = renderer.context;\r\n\r\n\tvar vertexBuffer, elementBuffer;\r\n\tvar program, attributes, uniforms;\r\n\r\n\tvar texture;\r\n\r\n\t// decompose matrixWorld\r\n\r\n\tvar spritePosition = new THREE.Vector3();\r\n\tvar spriteRotation = new THREE.Quaternion();\r\n\tvar spriteScale = new THREE.Vector3();\r\n\r\n\tvar init = function () {\r\n\r\n\t\tvar vertices = new Float32Array( [\r\n\t\t\t- 0.5, - 0.5, 0, 0,\r\n\t\t\t 0.5, - 0.5, 1, 0,\r\n\t\t\t 0.5, 0.5, 1, 1,\r\n\t\t\t- 0.5, 0.5, 0, 1\r\n\t\t] );\r\n\r\n\t\tvar faces = new Uint16Array( [\r\n\t\t\t0, 1, 2,\r\n\t\t\t0, 2, 3\r\n\t\t] );\r\n\r\n\t\tvertexBuffer = gl.createBuffer();\r\n\t\telementBuffer = gl.createBuffer();\r\n\r\n\t\tgl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );\r\n\t\tgl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW );\r\n\r\n\t\tgl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );\r\n\t\tgl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW );\r\n\r\n\t\tprogram = createProgram();\r\n\r\n\t\tattributes = {\r\n\t\t\tposition:\t\t\tgl.getAttribLocation ( program, 'position' ),\r\n\t\t\tuv:\t\t\t\t\tgl.getAttribLocation ( program, 'uv' )\r\n\t\t};\r\n\r\n\t\tuniforms = {\r\n\t\t\tuvOffset:\t\t\tgl.getUniformLocation( program, 'uvOffset' ),\r\n\t\t\tuvScale:\t\t\tgl.getUniformLocation( program, 'uvScale' ),\r\n\r\n\t\t\trotation:\t\t\tgl.getUniformLocation( program, 'rotation' ),\r\n\t\t\tscale:\t\t\t\tgl.getUniformLocation( program, 'scale' ),\r\n\r\n\t\t\tcolor:\t\t\t\tgl.getUniformLocation( program, 'color' ),\r\n\t\t\tmap:\t\t\t\tgl.getUniformLocation( program, 'map' ),\r\n\t\t\topacity:\t\t\tgl.getUniformLocation( program, 'opacity' ),\r\n\r\n\t\t\tmodelViewMatrix: \tgl.getUniformLocation( program, 'modelViewMatrix' ),\r\n\t\t\tprojectionMatrix:\tgl.getUniformLocation( program, 'projectionMatrix' ),\r\n\r\n\t\t\tfogType:\t\t\tgl.getUniformLocation( program, 'fogType' ),\r\n\t\t\tfogDensity:\t\t\tgl.getUniformLocation( program, 'fogDensity' ),\r\n\t\t\tfogNear:\t\t\tgl.getUniformLocation( program, 'fogNear' ),\r\n\t\t\tfogFar:\t\t\t\tgl.getUniformLocation( program, 'fogFar' ),\r\n\t\t\tfogColor:\t\t\tgl.getUniformLocation( program, 'fogColor' ),\r\n\r\n\t\t\talphaTest:\t\t\tgl.getUniformLocation( program, 'alphaTest' )\r\n\t\t};\r\n\r\n\t\tvar canvas = document.createElement( 'canvas' );\r\n\t\tcanvas.width = 8;\r\n\t\tcanvas.height = 8;\r\n\r\n\t\tvar context = canvas.getContext( '2d' );\r\n\t\tcontext.fillStyle = 'white';\r\n\t\tcontext.fillRect( 0, 0, 8, 8 );\r\n\r\n\t\ttexture = new THREE.Texture( canvas );\r\n\t\ttexture.needsUpdate = true;\r\n\r\n\t};\r\n\r\n\tthis.render = function ( scene, camera ) {\r\n\r\n\t\tif ( sprites.length === 0 ) return;\r\n\r\n\t\t// setup gl\r\n\r\n\t\tif ( program === undefined ) {\r\n\r\n\t\t\tinit();\r\n\r\n\t\t}\r\n\r\n\t\tgl.useProgram( program );\r\n\r\n\t\tgl.enableVertexAttribArray( attributes.position );\r\n\t\tgl.enableVertexAttribArray( attributes.uv );\r\n\r\n\t\tgl.disable( gl.CULL_FACE );\r\n\t\tgl.enable( gl.BLEND );\r\n\r\n\t\tgl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );\r\n\t\tgl.vertexAttribPointer( attributes.position, 2, gl.FLOAT, false, 2 * 8, 0 );\r\n\t\tgl.vertexAttribPointer( attributes.uv, 2, gl.FLOAT, false, 2 * 8, 8 );\r\n\r\n\t\tgl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );\r\n\r\n\t\tgl.uniformMatrix4fv( uniforms.projectionMatrix, false, camera.projectionMatrix.elements );\r\n\r\n\t\tgl.activeTexture( gl.TEXTURE0 );\r\n\t\tgl.uniform1i( uniforms.map, 0 );\r\n\r\n\t\tvar oldFogType = 0;\r\n\t\tvar sceneFogType = 0;\r\n\t\tvar fog = scene.fog;\r\n\r\n\t\tif ( fog ) {\r\n\r\n\t\t\tgl.uniform3f( uniforms.fogColor, fog.color.r, fog.color.g, fog.color.b );\r\n\r\n\t\t\tif ( fog instanceof THREE.Fog ) {\r\n\r\n\t\t\t\tgl.uniform1f( uniforms.fogNear, fog.near );\r\n\t\t\t\tgl.uniform1f( uniforms.fogFar, fog.far );\r\n\r\n\t\t\t\tgl.uniform1i( uniforms.fogType, 1 );\r\n\t\t\t\toldFogType = 1;\r\n\t\t\t\tsceneFogType = 1;\r\n\r\n\t\t\t} else if ( fog instanceof THREE.FogExp2 ) {\r\n\r\n\t\t\t\tgl.uniform1f( uniforms.fogDensity, fog.density );\r\n\r\n\t\t\t\tgl.uniform1i( uniforms.fogType, 2 );\r\n\t\t\t\toldFogType = 2;\r\n\t\t\t\tsceneFogType = 2;\r\n\r\n\t\t\t}\r\n\r\n\t\t} else {\r\n\r\n\t\t\tgl.uniform1i( uniforms.fogType, 0 );\r\n\t\t\toldFogType = 0;\r\n\t\t\tsceneFogType = 0;\r\n\r\n\t\t}\r\n\r\n\r\n\t\t// update positions and sort\r\n\r\n\t\tfor ( var i = 0, l = sprites.length; i < l; i ++ ) {\r\n\r\n\t\t\tvar sprite = sprites[ i ];\r\n\r\n\t\t\tsprite._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, sprite.matrixWorld );\r\n\t\t\tsprite.z = - sprite._modelViewMatrix.elements[ 14 ];\r\n\r\n\t\t}\r\n\r\n\t\tsprites.sort( painterSortStable );\r\n\r\n\t\t// render all sprites\r\n\r\n\t\tvar scale = [];\r\n\r\n\t\tfor ( var i = 0, l = sprites.length; i < l; i ++ ) {\r\n\r\n\t\t\tvar sprite = sprites[ i ];\r\n\t\t\tvar material = sprite.material;\r\n\r\n\t\t\tgl.uniform1f( uniforms.alphaTest, material.alphaTest );\r\n\t\t\tgl.uniformMatrix4fv( uniforms.modelViewMatrix, false, sprite._modelViewMatrix.elements );\r\n\r\n\t\t\tsprite.matrixWorld.decompose( spritePosition, spriteRotation, spriteScale );\r\n\r\n\t\t\tscale[ 0 ] = spriteScale.x;\r\n\t\t\tscale[ 1 ] = spriteScale.y;\r\n\r\n\t\t\tvar fogType = 0;\r\n\r\n\t\t\tif ( scene.fog && material.fog ) {\r\n\r\n\t\t\t\tfogType = sceneFogType;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( oldFogType !== fogType ) {\r\n\r\n\t\t\t\tgl.uniform1i( uniforms.fogType, fogType );\r\n\t\t\t\toldFogType = fogType;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( material.map !== null ) {\r\n\r\n\t\t\t\tgl.uniform2f( uniforms.uvOffset, material.map.offset.x, material.map.offset.y );\r\n\t\t\t\tgl.uniform2f( uniforms.uvScale, material.map.repeat.x, material.map.repeat.y );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tgl.uniform2f( uniforms.uvOffset, 0, 0 );\r\n\t\t\t\tgl.uniform2f( uniforms.uvScale, 1, 1 );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tgl.uniform1f( uniforms.opacity, material.opacity );\r\n\t\t\tgl.uniform3f( uniforms.color, material.color.r, material.color.g, material.color.b );\r\n\r\n\t\t\tgl.uniform1f( uniforms.rotation, material.rotation );\r\n\t\t\tgl.uniform2fv( uniforms.scale, scale );\r\n\r\n\t\t\trenderer.state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst );\r\n\t\t\trenderer.state.setDepthTest( material.depthTest );\r\n\t\t\trenderer.state.setDepthWrite( material.depthWrite );\r\n\r\n\t\t\tif ( material.map && material.map.image && material.map.image.width ) {\r\n\r\n\t\t\t\trenderer.setTexture( material.map, 0 );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\trenderer.setTexture( texture, 0 );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tgl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );\r\n\r\n\t\t}\r\n\r\n\t\t// restore gl\r\n\r\n\t\tgl.enable( gl.CULL_FACE );\r\n\r\n\t\trenderer.resetGLState();\r\n\r\n\t};\r\n\r\n\tfunction createProgram () {\r\n\r\n\t\tvar program = gl.createProgram();\r\n\r\n\t\tvar vertexShader = gl.createShader( gl.VERTEX_SHADER );\r\n\t\tvar fragmentShader = gl.createShader( gl.FRAGMENT_SHADER );\r\n\r\n\t\tgl.shaderSource( vertexShader, [\r\n\r\n\t\t\t'precision ' + renderer.getPrecision() + ' float;',\r\n\r\n\t\t\t'uniform mat4 modelViewMatrix;',\r\n\t\t\t'uniform mat4 projectionMatrix;',\r\n\t\t\t'uniform float rotation;',\r\n\t\t\t'uniform vec2 scale;',\r\n\t\t\t'uniform vec2 uvOffset;',\r\n\t\t\t'uniform vec2 uvScale;',\r\n\r\n\t\t\t'attribute vec2 position;',\r\n\t\t\t'attribute vec2 uv;',\r\n\r\n\t\t\t'varying vec2 vUV;',\r\n\r\n\t\t\t'void main() {',\r\n\r\n\t\t\t\t'vUV = uvOffset + uv * uvScale;',\r\n\r\n\t\t\t\t'vec2 alignedPosition = position * scale;',\r\n\r\n\t\t\t\t'vec2 rotatedPosition;',\r\n\t\t\t\t'rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;',\r\n\t\t\t\t'rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;',\r\n\r\n\t\t\t\t'vec4 finalPosition;',\r\n\r\n\t\t\t\t'finalPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );',\r\n\t\t\t\t'finalPosition.xy += rotatedPosition;',\r\n\t\t\t\t'finalPosition = projectionMatrix * finalPosition;',\r\n\r\n\t\t\t\t'gl_Position = finalPosition;',\r\n\r\n\t\t\t'}'\r\n\r\n\t\t].join( '\\n' ) );\r\n\r\n\t\tgl.shaderSource( fragmentShader, [\r\n\r\n\t\t\t'precision ' + renderer.getPrecision() + ' float;',\r\n\r\n\t\t\t'uniform vec3 color;',\r\n\t\t\t'uniform sampler2D map;',\r\n\t\t\t'uniform float opacity;',\r\n\r\n\t\t\t'uniform int fogType;',\r\n\t\t\t'uniform vec3 fogColor;',\r\n\t\t\t'uniform float fogDensity;',\r\n\t\t\t'uniform float fogNear;',\r\n\t\t\t'uniform float fogFar;',\r\n\t\t\t'uniform float alphaTest;',\r\n\r\n\t\t\t'varying vec2 vUV;',\r\n\r\n\t\t\t'void main() {',\r\n\r\n\t\t\t\t'vec4 texture = texture2D( map, vUV );',\r\n\r\n\t\t\t\t'if ( texture.a < alphaTest ) discard;',\r\n\r\n\t\t\t\t'gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );',\r\n\r\n\t\t\t\t'if ( fogType > 0 ) {',\r\n\r\n\t\t\t\t\t'float depth = gl_FragCoord.z / gl_FragCoord.w;',\r\n\t\t\t\t\t'float fogFactor = 0.0;',\r\n\r\n\t\t\t\t\t'if ( fogType == 1 ) {',\r\n\r\n\t\t\t\t\t\t'fogFactor = smoothstep( fogNear, fogFar, depth );',\r\n\r\n\t\t\t\t\t'} else {',\r\n\r\n\t\t\t\t\t\t'const float LOG2 = 1.442695;',\r\n\t\t\t\t\t\t'float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );',\r\n\t\t\t\t\t\t'fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );',\r\n\r\n\t\t\t\t\t'}',\r\n\r\n\t\t\t\t\t'gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );',\r\n\r\n\t\t\t\t'}',\r\n\r\n\t\t\t'}'\r\n\r\n\t\t].join( '\\n' ) );\r\n\r\n\t\tgl.compileShader( vertexShader );\r\n\t\tgl.compileShader( fragmentShader );\r\n\r\n\t\tgl.attachShader( program, vertexShader );\r\n\t\tgl.attachShader( program, fragmentShader );\r\n\r\n\t\tgl.linkProgram( program );\r\n\r\n\t\treturn program;\r\n\r\n\t};\r\n\r\n\tfunction painterSortStable ( a, b ) {\r\n\r\n\t\tif ( a.z !== b.z ) {\r\n\r\n\t\t\treturn b.z - a.z;\r\n\r\n\t\t} else {\r\n\r\n\t\t\treturn b.id - a.id;\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n};\r\n\r\n// File:src/extras/GeometryUtils.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n */\r\n\r\nTHREE.GeometryUtils = {\r\n\r\n\tmerge: function ( geometry1, geometry2, materialIndexOffset ) {\r\n\r\n\t\tTHREE.warn( 'THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.' );\r\n\r\n\t\tvar matrix;\r\n\r\n\t\tif ( geometry2 instanceof THREE.Mesh ) {\r\n\r\n\t\t\tgeometry2.matrixAutoUpdate && geometry2.updateMatrix();\r\n\r\n\t\t\tmatrix = geometry2.matrix;\r\n\t\t\tgeometry2 = geometry2.geometry;\r\n\r\n\t\t}\r\n\r\n\t\tgeometry1.merge( geometry2, matrix, materialIndexOffset );\r\n\r\n\t},\r\n\r\n\tcenter: function ( geometry ) {\r\n\r\n\t\tTHREE.warn( 'THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.' );\r\n\t\treturn geometry.center();\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/extras/ImageUtils.js\r\n\r\n/**\r\n * @author alteredq / http://alteredqualia.com/\r\n * @author mrdoob / http://mrdoob.com/\r\n * @author Daosheng Mu / https://github.com/DaoshengMu/\r\n */\r\n\r\nTHREE.ImageUtils = {\r\n\r\n\tcrossOrigin: undefined,\r\n\r\n\tloadTexture: function ( url, mapping, onLoad, onError ) {\r\n\r\n\t\tvar loader = new THREE.ImageLoader();\r\n\t\tloader.crossOrigin = this.crossOrigin;\r\n\r\n\t\tvar texture = new THREE.Texture( undefined, mapping );\r\n\r\n\t\tloader.load( url, function ( image ) {\r\n\r\n\t\t\ttexture.image = image;\r\n\t\t\ttexture.needsUpdate = true;\r\n\r\n\t\t\tif ( onLoad ) onLoad( texture );\r\n\r\n\t\t}, undefined, function ( event ) {\r\n\r\n\t\t\tif ( onError ) onError( event );\r\n\r\n\t\t} );\r\n\r\n\t\ttexture.sourceFile = url;\r\n\r\n\t\treturn texture;\r\n\r\n\t},\r\n\r\n\tloadTextureCube: function ( array, mapping, onLoad, onError ) {\r\n\r\n\t\tvar images = [];\r\n\r\n\t\tvar loader = new THREE.ImageLoader();\r\n\t\tloader.crossOrigin = this.crossOrigin;\r\n\r\n\t\tvar texture = new THREE.CubeTexture( images, mapping );\r\n\r\n\t\t// no flipping needed for cube textures\r\n\r\n\t\ttexture.flipY = false;\r\n\r\n\t\tvar loaded = 0;\r\n\r\n\t\tvar loadTexture = function ( i ) {\r\n\r\n\t\t\tloader.load( array[ i ], function ( image ) {\r\n\r\n\t\t\t\ttexture.images[ i ] = image;\r\n\r\n\t\t\t\tloaded += 1;\r\n\r\n\t\t\t\tif ( loaded === 6 ) {\r\n\r\n\t\t\t\t\ttexture.needsUpdate = true;\r\n\r\n\t\t\t\t\tif ( onLoad ) onLoad( texture );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}, undefined, onError );\r\n\r\n\t\t}\r\n\r\n\t\tfor ( var i = 0, il = array.length; i < il; ++ i ) {\r\n\r\n\t\t\tloadTexture( i );\r\n\r\n\t\t}\r\n\r\n\t\treturn texture;\r\n\r\n\t},\r\n\r\n\tloadCompressedTexture: function () {\r\n\r\n\t\tTHREE.error( 'THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.' )\r\n\r\n\t},\r\n\r\n\tloadCompressedTextureCube: function () {\r\n\r\n\t\tTHREE.error( 'THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.' )\r\n\r\n\t},\r\n\r\n\tgetNormalMap: function ( image, depth ) {\r\n\r\n\t\t// Adapted from http://www.paulbrunt.co.uk/lab/heightnormal/\r\n\r\n\t\tvar cross = function ( a, b ) {\r\n\r\n\t\t\treturn [ a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ], a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ], a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ] ];\r\n\r\n\t\t}\r\n\r\n\t\tvar subtract = function ( a, b ) {\r\n\r\n\t\t\treturn [ a[ 0 ] - b[ 0 ], a[ 1 ] - b[ 1 ], a[ 2 ] - b[ 2 ] ];\r\n\r\n\t\t}\r\n\r\n\t\tvar normalize = function ( a ) {\r\n\r\n\t\t\tvar l = Math.sqrt( a[ 0 ] * a[ 0 ] + a[ 1 ] * a[ 1 ] + a[ 2 ] * a[ 2 ] );\r\n\t\t\treturn [ a[ 0 ] / l, a[ 1 ] / l, a[ 2 ] / l ];\r\n\r\n\t\t}\r\n\r\n\t\tdepth = depth | 1;\r\n\r\n\t\tvar width = image.width;\r\n\t\tvar height = image.height;\r\n\r\n\t\tvar canvas = document.createElement( 'canvas' );\r\n\t\tcanvas.width = width;\r\n\t\tcanvas.height = height;\r\n\r\n\t\tvar context = canvas.getContext( '2d' );\r\n\t\tcontext.drawImage( image, 0, 0 );\r\n\r\n\t\tvar data = context.getImageData( 0, 0, width, height ).data;\r\n\t\tvar imageData = context.createImageData( width, height );\r\n\t\tvar output = imageData.data;\r\n\r\n\t\tfor ( var x = 0; x < width; x ++ ) {\r\n\r\n\t\t\tfor ( var y = 0; y < height; y ++ ) {\r\n\r\n\t\t\t\tvar ly = y - 1 < 0 ? 0 : y - 1;\r\n\t\t\t\tvar uy = y + 1 > height - 1 ? height - 1 : y + 1;\r\n\t\t\t\tvar lx = x - 1 < 0 ? 0 : x - 1;\r\n\t\t\t\tvar ux = x + 1 > width - 1 ? width - 1 : x + 1;\r\n\r\n\t\t\t\tvar points = [];\r\n\t\t\t\tvar origin = [ 0, 0, data[ ( y * width + x ) * 4 ] / 255 * depth ];\r\n\t\t\t\tpoints.push( [ - 1, 0, data[ ( y * width + lx ) * 4 ] / 255 * depth ] );\r\n\t\t\t\tpoints.push( [ - 1, - 1, data[ ( ly * width + lx ) * 4 ] / 255 * depth ] );\r\n\t\t\t\tpoints.push( [ 0, - 1, data[ ( ly * width + x ) * 4 ] / 255 * depth ] );\r\n\t\t\t\tpoints.push( [ 1, - 1, data[ ( ly * width + ux ) * 4 ] / 255 * depth ] );\r\n\t\t\t\tpoints.push( [ 1, 0, data[ ( y * width + ux ) * 4 ] / 255 * depth ] );\r\n\t\t\t\tpoints.push( [ 1, 1, data[ ( uy * width + ux ) * 4 ] / 255 * depth ] );\r\n\t\t\t\tpoints.push( [ 0, 1, data[ ( uy * width + x ) * 4 ] / 255 * depth ] );\r\n\t\t\t\tpoints.push( [ - 1, 1, data[ ( uy * width + lx ) * 4 ] / 255 * depth ] );\r\n\r\n\t\t\t\tvar normals = [];\r\n\t\t\t\tvar num_points = points.length;\r\n\r\n\t\t\t\tfor ( var i = 0; i < num_points; i ++ ) {\r\n\r\n\t\t\t\t\tvar v1 = points[ i ];\r\n\t\t\t\t\tvar v2 = points[ ( i + 1 ) % num_points ];\r\n\t\t\t\t\tv1 = subtract( v1, origin );\r\n\t\t\t\t\tv2 = subtract( v2, origin );\r\n\t\t\t\t\tnormals.push( normalize( cross( v1, v2 ) ) );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvar normal = [ 0, 0, 0 ];\r\n\r\n\t\t\t\tfor ( var i = 0; i < normals.length; i ++ ) {\r\n\r\n\t\t\t\t\tnormal[ 0 ] += normals[ i ][ 0 ];\r\n\t\t\t\t\tnormal[ 1 ] += normals[ i ][ 1 ];\r\n\t\t\t\t\tnormal[ 2 ] += normals[ i ][ 2 ];\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tnormal[ 0 ] /= normals.length;\r\n\t\t\t\tnormal[ 1 ] /= normals.length;\r\n\t\t\t\tnormal[ 2 ] /= normals.length;\r\n\r\n\t\t\t\tvar idx = ( y * width + x ) * 4;\r\n\r\n\t\t\t\toutput[ idx ] = ( ( normal[ 0 ] + 1.0 ) / 2.0 * 255 ) | 0;\r\n\t\t\t\toutput[ idx + 1 ] = ( ( normal[ 1 ] + 1.0 ) / 2.0 * 255 ) | 0;\r\n\t\t\t\toutput[ idx + 2 ] = ( normal[ 2 ] * 255 ) | 0;\r\n\t\t\t\toutput[ idx + 3 ] = 255;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tcontext.putImageData( imageData, 0, 0 );\r\n\r\n\t\treturn canvas;\r\n\r\n\t},\r\n\r\n\tgenerateDataTexture: function ( width, height, color ) {\r\n\r\n\t\tvar size = width * height;\r\n\t\tvar data = new Uint8Array( 3 * size );\r\n\r\n\t\tvar r = Math.floor( color.r * 255 );\r\n\t\tvar g = Math.floor( color.g * 255 );\r\n\t\tvar b = Math.floor( color.b * 255 );\r\n\r\n\t\tfor ( var i = 0; i < size; i ++ ) {\r\n\r\n\t\t\tdata[ i * 3 ] \t = r;\r\n\t\t\tdata[ i * 3 + 1 ] = g;\r\n\t\t\tdata[ i * 3 + 2 ] = b;\r\n\r\n\t\t}\r\n\r\n\t\tvar texture = new THREE.DataTexture( data, width, height, THREE.RGBFormat );\r\n\t\ttexture.needsUpdate = true;\r\n\r\n\t\treturn texture;\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/extras/SceneUtils.js\r\n\r\n/**\r\n * @author alteredq / http://alteredqualia.com/\r\n */\r\n\r\nTHREE.SceneUtils = {\r\n\r\n\tcreateMultiMaterialObject: function ( geometry, materials ) {\r\n\r\n\t\tvar group = new THREE.Object3D();\r\n\r\n\t\tfor ( var i = 0, l = materials.length; i < l; i ++ ) {\r\n\r\n\t\t\tgroup.add( new THREE.Mesh( geometry, materials[ i ] ) );\r\n\r\n\t\t}\r\n\r\n\t\treturn group;\r\n\r\n\t},\r\n\r\n\tdetach: function ( child, parent, scene ) {\r\n\r\n\t\tchild.applyMatrix( parent.matrixWorld );\r\n\t\tparent.remove( child );\r\n\t\tscene.add( child );\r\n\r\n\t},\r\n\r\n\tattach: function ( child, scene, parent ) {\r\n\r\n\t\tvar matrixWorldInverse = new THREE.Matrix4();\r\n\t\tmatrixWorldInverse.getInverse( parent.matrixWorld );\r\n\t\tchild.applyMatrix( matrixWorldInverse );\r\n\r\n\t\tscene.remove( child );\r\n\t\tparent.add( child );\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/extras/FontUtils.js\r\n\r\n/**\r\n * @author zz85 / http://www.lab4games.net/zz85/blog\r\n * @author alteredq / http://alteredqualia.com/\r\n *\r\n * For Text operations in three.js (See TextGeometry)\r\n *\r\n * It uses techniques used in:\r\n *\r\n * \ttypeface.js and canvastext\r\n * \t\tFor converting fonts and rendering with javascript\r\n *\t\thttp://typeface.neocracy.org\r\n *\r\n *\tTriangulation ported from AS3\r\n *\t\tSimple Polygon Triangulation\r\n *\t\thttp://actionsnippet.com/?p=1462\r\n *\r\n * \tA Method to triangulate shapes with holes\r\n *\t\thttp://www.sakri.net/blog/2009/06/12/an-approach-to-triangulating-polygons-with-holes/\r\n *\r\n */\r\n\r\nTHREE.FontUtils = {\r\n\r\n\tfaces: {},\r\n\r\n\t// Just for now. face[weight][style]\r\n\r\n\tface: 'helvetiker',\r\n\tweight: 'normal',\r\n\tstyle: 'normal',\r\n\tsize: 150,\r\n\tdivisions: 10,\r\n\r\n\tgetFace: function () {\r\n\r\n\t\ttry {\r\n\r\n\t\t\treturn this.faces[ this.face ][ this.weight ][ this.style ];\r\n\r\n\t\t} catch (e) {\r\n\r\n\t\t\tthrow \"The font \" + this.face + \" with \" + this.weight + \" weight and \" + this.style + \" style is missing.\"\r\n\r\n\t\t};\r\n\r\n\t},\r\n\r\n\tloadFace: function ( data ) {\r\n\r\n\t\tvar family = data.familyName.toLowerCase();\r\n\r\n\t\tvar ThreeFont = this;\r\n\r\n\t\tThreeFont.faces[ family ] = ThreeFont.faces[ family ] || {};\r\n\r\n\t\tThreeFont.faces[ family ][ data.cssFontWeight ] = ThreeFont.faces[ family ][ data.cssFontWeight ] || {};\r\n\t\tThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data;\r\n\r\n\t\tThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data;\r\n\r\n\t\treturn data;\r\n\r\n\t},\r\n\r\n\tdrawText: function ( text ) {\r\n\r\n\t\t// RenderText\r\n\r\n\t\tvar i,\r\n\t\t\tface = this.getFace(),\r\n\t\t\tscale = this.size / face.resolution,\r\n\t\t\toffset = 0,\r\n\t\t\tchars = String( text ).split( '' ),\r\n\t\t\tlength = chars.length;\r\n\r\n\t\tvar fontPaths = [];\r\n\r\n\t\tfor ( i = 0; i < length; i ++ ) {\r\n\r\n\t\t\tvar path = new THREE.Path();\r\n\r\n\t\t\tvar ret = this.extractGlyphPoints( chars[ i ], face, scale, offset, path );\r\n\t\t\toffset += ret.offset;\r\n\r\n\t\t\tfontPaths.push( ret.path );\r\n\r\n\t\t}\r\n\r\n\t\t// get the width\r\n\r\n\t\tvar width = offset / 2;\r\n\t\t//\r\n\t\t// for ( p = 0; p < allPts.length; p++ ) {\r\n\t\t//\r\n\t\t// \tallPts[ p ].x -= width;\r\n\t\t//\r\n\t\t// }\r\n\r\n\t\t//var extract = this.extractPoints( allPts, characterPts );\r\n\t\t//extract.contour = allPts;\r\n\r\n\t\t//extract.paths = fontPaths;\r\n\t\t//extract.offset = width;\r\n\r\n\t\treturn { paths: fontPaths, offset: width };\r\n\r\n\t},\r\n\r\n\r\n\r\n\r\n\textractGlyphPoints: function ( c, face, scale, offset, path ) {\r\n\r\n\t\tvar pts = [];\r\n\r\n\t\tvar i, i2, divisions,\r\n\t\t\toutline, action, length,\r\n\t\t\tscaleX, scaleY,\r\n\t\t\tx, y, cpx, cpy, cpx0, cpy0, cpx1, cpy1, cpx2, cpy2,\r\n\t\t\tlaste,\r\n\t\t\tglyph = face.glyphs[ c ] || face.glyphs[ '?' ];\r\n\r\n\t\tif ( ! glyph ) return;\r\n\r\n\t\tif ( glyph.o ) {\r\n\r\n\t\t\toutline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) );\r\n\t\t\tlength = outline.length;\r\n\r\n\t\t\tscaleX = scale;\r\n\t\t\tscaleY = scale;\r\n\r\n\t\t\tfor ( i = 0; i < length; ) {\r\n\r\n\t\t\t\taction = outline[ i ++ ];\r\n\r\n\t\t\t\t//console.log( action );\r\n\r\n\t\t\t\tswitch ( action ) {\r\n\r\n\t\t\t\tcase 'm':\r\n\r\n\t\t\t\t\t// Move To\r\n\r\n\t\t\t\t\tx = outline[ i ++ ] * scaleX + offset;\r\n\t\t\t\t\ty = outline[ i ++ ] * scaleY;\r\n\r\n\t\t\t\t\tpath.moveTo( x, y );\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 'l':\r\n\r\n\t\t\t\t\t// Line To\r\n\r\n\t\t\t\t\tx = outline[ i ++ ] * scaleX + offset;\r\n\t\t\t\t\ty = outline[ i ++ ] * scaleY;\r\n\t\t\t\t\tpath.lineTo( x, y );\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 'q':\r\n\r\n\t\t\t\t\t// QuadraticCurveTo\r\n\r\n\t\t\t\t\tcpx = outline[ i ++ ] * scaleX + offset;\r\n\t\t\t\t\tcpy = outline[ i ++ ] * scaleY;\r\n\t\t\t\t\tcpx1 = outline[ i ++ ] * scaleX + offset;\r\n\t\t\t\t\tcpy1 = outline[ i ++ ] * scaleY;\r\n\r\n\t\t\t\t\tpath.quadraticCurveTo( cpx1, cpy1, cpx, cpy );\r\n\r\n\t\t\t\t\tlaste = pts[ pts.length - 1 ];\r\n\r\n\t\t\t\t\tif ( laste ) {\r\n\r\n\t\t\t\t\t\tcpx0 = laste.x;\r\n\t\t\t\t\t\tcpy0 = laste.y;\r\n\r\n\t\t\t\t\t\tfor ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) {\r\n\r\n\t\t\t\t\t\t\tvar t = i2 / divisions;\r\n\t\t\t\t\t\t\tTHREE.Shape.Utils.b2( t, cpx0, cpx1, cpx );\r\n\t\t\t\t\t\t\tTHREE.Shape.Utils.b2( t, cpy0, cpy1, cpy );\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase 'b':\r\n\r\n\t\t\t\t\t// Cubic Bezier Curve\r\n\r\n\t\t\t\t\tcpx = outline[ i ++ ] * scaleX + offset;\r\n\t\t\t\t\tcpy = outline[ i ++ ] * scaleY;\r\n\t\t\t\t\tcpx1 = outline[ i ++ ] * scaleX + offset;\r\n\t\t\t\t\tcpy1 = outline[ i ++ ] * scaleY;\r\n\t\t\t\t\tcpx2 = outline[ i ++ ] * scaleX + offset;\r\n\t\t\t\t\tcpy2 = outline[ i ++ ] * scaleY;\r\n\r\n\t\t\t\t\tpath.bezierCurveTo( cpx1, cpy1, cpx2, cpy2, cpx, cpy );\r\n\r\n\t\t\t\t\tlaste = pts[ pts.length - 1 ];\r\n\r\n\t\t\t\t\tif ( laste ) {\r\n\r\n\t\t\t\t\t\tcpx0 = laste.x;\r\n\t\t\t\t\t\tcpy0 = laste.y;\r\n\r\n\t\t\t\t\t\tfor ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) {\r\n\r\n\t\t\t\t\t\t\tvar t = i2 / divisions;\r\n\t\t\t\t\t\t\tTHREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx );\r\n\t\t\t\t\t\t\tTHREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy );\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\t\t}\r\n\r\n\r\n\r\n\t\treturn { offset: glyph.ha * scale, path:path };\r\n\t}\r\n\r\n};\r\n\r\n\r\nTHREE.FontUtils.generateShapes = function ( text, parameters ) {\r\n\r\n\t// Parameters \r\n\r\n\tparameters = parameters || {};\r\n\r\n\tvar size = parameters.size !== undefined ? parameters.size : 100;\r\n\tvar curveSegments = parameters.curveSegments !== undefined ? parameters.curveSegments : 4;\r\n\r\n\tvar font = parameters.font !== undefined ? parameters.font : 'helvetiker';\r\n\tvar weight = parameters.weight !== undefined ? parameters.weight : 'normal';\r\n\tvar style = parameters.style !== undefined ? parameters.style : 'normal';\r\n\r\n\tTHREE.FontUtils.size = size;\r\n\tTHREE.FontUtils.divisions = curveSegments;\r\n\r\n\tTHREE.FontUtils.face = font;\r\n\tTHREE.FontUtils.weight = weight;\r\n\tTHREE.FontUtils.style = style;\r\n\r\n\t// Get a Font data json object\r\n\r\n\tvar data = THREE.FontUtils.drawText( text );\r\n\r\n\tvar paths = data.paths;\r\n\tvar shapes = [];\r\n\r\n\tfor ( var p = 0, pl = paths.length; p < pl; p ++ ) {\r\n\r\n\t\tArray.prototype.push.apply( shapes, paths[ p ].toShapes() );\r\n\r\n\t}\r\n\r\n\treturn shapes;\r\n\r\n};\r\n\r\n\r\n/**\r\n * This code is a quick port of code written in C++ which was submitted to\r\n * flipcode.com by John W. Ratcliff // July 22, 2000\r\n * See original code and more information here:\r\n * http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml\r\n *\r\n * ported to actionscript by Zevan Rosser\r\n * www.actionsnippet.com\r\n *\r\n * ported to javascript by Joshua Koo\r\n * http://www.lab4games.net/zz85/blog\r\n *\r\n */\r\n\r\n\r\n( function ( namespace ) {\r\n\r\n\tvar EPSILON = 0.0000000001;\r\n\r\n\t// takes in an contour array and returns\r\n\r\n\tvar process = function ( contour, indices ) {\r\n\r\n\t\tvar n = contour.length;\r\n\r\n\t\tif ( n < 3 ) return null;\r\n\r\n\t\tvar result = [],\r\n\t\t\tverts = [],\r\n\t\t\tvertIndices = [];\r\n\r\n\t\t/* we want a counter-clockwise polygon in verts */\r\n\r\n\t\tvar u, v, w;\r\n\r\n\t\tif ( area( contour ) > 0.0 ) {\r\n\r\n\t\t\tfor ( v = 0; v < n; v ++ ) verts[ v ] = v;\r\n\r\n\t\t} else {\r\n\r\n\t\t\tfor ( v = 0; v < n; v ++ ) verts[ v ] = ( n - 1 ) - v;\r\n\r\n\t\t}\r\n\r\n\t\tvar nv = n;\r\n\r\n\t\t/* remove nv - 2 vertices, creating 1 triangle every time */\r\n\r\n\t\tvar count = 2 * nv; /* error detection */\r\n\r\n\t\tfor ( v = nv - 1; nv > 2; ) {\r\n\r\n\t\t\t/* if we loop, it is probably a non-simple polygon */\r\n\r\n\t\t\tif ( ( count -- ) <= 0 ) {\r\n\r\n\t\t\t\t//** Triangulate: ERROR - probable bad polygon!\r\n\r\n\t\t\t\t//throw ( \"Warning, unable to triangulate polygon!\" );\r\n\t\t\t\t//return null;\r\n\t\t\t\t// Sometimes warning is fine, especially polygons are triangulated in reverse.\r\n\t\t\t\tTHREE.warn( 'THREE.FontUtils: Warning, unable to triangulate polygon! in Triangulate.process()' );\r\n\r\n\t\t\t\tif ( indices ) return vertIndices;\r\n\t\t\t\treturn result;\r\n\r\n\t\t\t}\r\n\r\n\t\t\t/* three consecutive vertices in current polygon, */\r\n\r\n\t\t\tu = v; \t \tif ( nv <= u ) u = 0; /* previous */\r\n\t\t\tv = u + 1; if ( nv <= v ) v = 0; /* new v */\r\n\t\t\tw = v + 1; if ( nv <= w ) w = 0; /* next */\r\n\r\n\t\t\tif ( snip( contour, u, v, w, nv, verts ) ) {\r\n\r\n\t\t\t\tvar a, b, c, s, t;\r\n\r\n\t\t\t\t/* true names of the vertices */\r\n\r\n\t\t\t\ta = verts[ u ];\r\n\t\t\t\tb = verts[ v ];\r\n\t\t\t\tc = verts[ w ];\r\n\r\n\t\t\t\t/* output Triangle */\r\n\r\n\t\t\t\tresult.push( [ contour[ a ],\r\n\t\t\t\t\tcontour[ b ],\r\n\t\t\t\t\tcontour[ c ] ] );\r\n\r\n\r\n\t\t\t\tvertIndices.push( [ verts[ u ], verts[ v ], verts[ w ] ] );\r\n\r\n\t\t\t\t/* remove v from the remaining polygon */\r\n\r\n\t\t\t\tfor ( s = v, t = v + 1; t < nv; s ++, t ++ ) {\r\n\r\n\t\t\t\t\tverts[ s ] = verts[ t ];\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tnv --;\r\n\r\n\t\t\t\t/* reset error detection counter */\r\n\r\n\t\t\t\tcount = 2 * nv;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tif ( indices ) return vertIndices;\r\n\t\treturn result;\r\n\r\n\t};\r\n\r\n\t// calculate area of the contour polygon\r\n\r\n\tvar area = function ( contour ) {\r\n\r\n\t\tvar n = contour.length;\r\n\t\tvar a = 0.0;\r\n\r\n\t\tfor ( var p = n - 1, q = 0; q < n; p = q ++ ) {\r\n\r\n\t\t\ta += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y;\r\n\r\n\t\t}\r\n\r\n\t\treturn a * 0.5;\r\n\r\n\t};\r\n\r\n\tvar snip = function ( contour, u, v, w, n, verts ) {\r\n\r\n\t\tvar p;\r\n\t\tvar ax, ay, bx, by;\r\n\t\tvar cx, cy, px, py;\r\n\r\n\t\tax = contour[ verts[ u ] ].x;\r\n\t\tay = contour[ verts[ u ] ].y;\r\n\r\n\t\tbx = contour[ verts[ v ] ].x;\r\n\t\tby = contour[ verts[ v ] ].y;\r\n\r\n\t\tcx = contour[ verts[ w ] ].x;\r\n\t\tcy = contour[ verts[ w ] ].y;\r\n\r\n\t\tif ( EPSILON > ( ( ( bx - ax ) * ( cy - ay ) ) - ( ( by - ay ) * ( cx - ax ) ) ) ) return false;\r\n\r\n\t\tvar aX, aY, bX, bY, cX, cY;\r\n\t\tvar apx, apy, bpx, bpy, cpx, cpy;\r\n\t\tvar cCROSSap, bCROSScp, aCROSSbp;\r\n\r\n\t\taX = cx - bx; aY = cy - by;\r\n\t\tbX = ax - cx; bY = ay - cy;\r\n\t\tcX = bx - ax; cY = by - ay;\r\n\r\n\t\tfor ( p = 0; p < n; p ++ ) {\r\n\r\n\t\t\tpx = contour[ verts[ p ] ].x\r\n\t\t\tpy = contour[ verts[ p ] ].y\r\n\r\n\t\t\tif ( ( ( px === ax ) && ( py === ay ) ) ||\r\n\t\t\t\t ( ( px === bx ) && ( py === by ) ) ||\r\n\t\t\t\t ( ( px === cx ) && ( py === cy ) ) )\tcontinue;\r\n\r\n\t\t\tapx = px - ax; apy = py - ay;\r\n\t\t\tbpx = px - bx; bpy = py - by;\r\n\t\t\tcpx = px - cx; cpy = py - cy;\r\n\r\n\t\t\t// see if p is inside triangle abc\r\n\r\n\t\t\taCROSSbp = aX * bpy - aY * bpx;\r\n\t\t\tcCROSSap = cX * apy - cY * apx;\r\n\t\t\tbCROSScp = bX * cpy - bY * cpx;\r\n\r\n\t\t\tif ( ( aCROSSbp >= - EPSILON ) && ( bCROSScp >= - EPSILON ) && ( cCROSSap >= - EPSILON ) ) return false;\r\n\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\r\n\t};\r\n\r\n\r\n\tnamespace.Triangulate = process;\r\n\tnamespace.Triangulate.area = area;\r\n\r\n\treturn namespace;\r\n\r\n} )( THREE.FontUtils );\r\n\r\n// To use the typeface.js face files, hook up the API\r\nself._typeface_js = { faces: THREE.FontUtils.faces, loadFace: THREE.FontUtils.loadFace };\r\nTHREE.typeface_js = self._typeface_js;\r\n\r\n// File:src/extras/audio/Audio.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n */\r\n\r\nTHREE.Audio = function ( listener ) {\r\n\r\n\tTHREE.Object3D.call( this );\r\n\r\n\tthis.type = 'Audio';\r\n\r\n\tthis.context = listener.context;\r\n\tthis.source = this.context.createBufferSource();\r\n\tthis.source.onended = this.onEnded.bind(this);\r\n\r\n\tthis.gain = this.context.createGain();\r\n\tthis.gain.connect( this.context.destination );\r\n\r\n\tthis.panner = this.context.createPanner();\r\n\tthis.panner.connect( this.gain );\r\n\r\n\tthis.autoplay = false;\r\n\r\n\tthis.startTime = 0;\r\n\tthis.isPlaying = false;\r\n\r\n};\r\n\r\nTHREE.Audio.prototype = Object.create( THREE.Object3D.prototype );\r\nTHREE.Audio.prototype.constructor = THREE.Audio;\r\n\r\nTHREE.Audio.prototype.load = function ( file ) {\r\n\r\n\tvar scope = this;\r\n\r\n\tvar request = new XMLHttpRequest();\r\n\trequest.open( 'GET', file, true );\r\n\trequest.responseType = 'arraybuffer';\r\n\trequest.onload = function ( e ) {\r\n\r\n\t\tscope.context.decodeAudioData( this.response, function ( buffer ) {\r\n\r\n\t\t\tscope.source.buffer = buffer;\r\n\r\n\t\t\tif( scope.autoplay ) scope.play();\r\n\r\n\t\t} );\r\n\r\n\t};\r\n\trequest.send();\r\n\r\n\treturn this;\r\n\r\n};\r\n\r\nTHREE.Audio.prototype.play = function () {\r\n\r\n\tif ( this.isPlaying === true ) {\r\n\r\n\t\tTHREE.warn( 'THREE.Audio: Audio is already playing.' );\r\n\t\treturn;\r\n\r\n\t}\r\n\r\n\tvar source = this.context.createBufferSource();\r\n\r\n\tsource.buffer = this.source.buffer;\r\n\tsource.loop = this.source.loop;\r\n\tsource.onended = this.source.onended;\r\n\tsource.connect( this.panner );\r\n\tsource.start( 0, this.startTime );\r\n\r\n\tthis.isPlaying = true;\r\n\r\n\tthis.source = source;\r\n\r\n};\r\n\r\nTHREE.Audio.prototype.pause = function () {\r\n\r\n\tthis.source.stop();\r\n\tthis.startTime = this.context.currentTime;\r\n\r\n};\r\n\r\nTHREE.Audio.prototype.stop = function () {\r\n\r\n\tthis.source.stop();\r\n\tthis.startTime = 0;\r\n\r\n};\r\n\r\nTHREE.Audio.prototype.onEnded = function() {\r\n\r\n\tthis.isPlaying = false;\r\n\r\n};\r\n\r\nTHREE.Audio.prototype.setLoop = function ( value ) {\r\n\r\n\tthis.source.loop = value;\r\n\r\n};\r\n\r\nTHREE.Audio.prototype.setRefDistance = function ( value ) {\r\n\r\n\tthis.panner.refDistance = value;\r\n\r\n};\r\n\r\nTHREE.Audio.prototype.setRolloffFactor = function ( value ) {\r\n\r\n\tthis.panner.rolloffFactor = value;\r\n\r\n};\r\n\r\nTHREE.Audio.prototype.setVolume = function ( value ) {\r\n\r\n\tthis.gain.gain.value = value;\r\n\r\n};\r\n\r\nTHREE.Audio.prototype.updateMatrixWorld = ( function () {\r\n\r\n\tvar position = new THREE.Vector3();\r\n\r\n\treturn function ( force ) {\r\n\r\n\t\tTHREE.Object3D.prototype.updateMatrixWorld.call( this, force );\r\n\r\n\t\tposition.setFromMatrixPosition( this.matrixWorld );\r\n\r\n\t\tthis.panner.setPosition( position.x, position.y, position.z );\r\n\r\n\t};\r\n\r\n} )();\r\n\r\n// File:src/extras/audio/AudioListener.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n */\r\n\r\nTHREE.AudioListener = function () {\r\n\r\n\tTHREE.Object3D.call( this );\r\n\r\n\tthis.type = 'AudioListener';\r\n\r\n\tthis.context = new ( window.AudioContext || window.webkitAudioContext )();\r\n\r\n};\r\n\r\nTHREE.AudioListener.prototype = Object.create( THREE.Object3D.prototype );\r\nTHREE.AudioListener.prototype.constructor = THREE.AudioListener;\r\n\r\nTHREE.AudioListener.prototype.updateMatrixWorld = ( function () {\r\n\r\n\tvar position = new THREE.Vector3();\r\n\tvar quaternion = new THREE.Quaternion();\r\n\tvar scale = new THREE.Vector3();\r\n\r\n\tvar orientation = new THREE.Vector3();\r\n\tvar velocity = new THREE.Vector3();\r\n\r\n\tvar positionPrev = new THREE.Vector3();\r\n\r\n\treturn function ( force ) {\r\n\r\n\t\tTHREE.Object3D.prototype.updateMatrixWorld.call( this, force );\r\n\r\n\t\tvar listener = this.context.listener;\r\n\t\tvar up = this.up;\r\n\r\n\t\tthis.matrixWorld.decompose( position, quaternion, scale );\r\n\r\n\t\torientation.set( 0, 0, -1 ).applyQuaternion( quaternion );\r\n\t\tvelocity.subVectors( position, positionPrev );\r\n\r\n\t\tlistener.setPosition( position.x, position.y, position.z );\r\n\t\tlistener.setOrientation( orientation.x, orientation.y, orientation.z, up.x, up.y, up.z );\r\n\t\tlistener.setVelocity( velocity.x, velocity.y, velocity.z );\r\n\r\n\t\tpositionPrev.copy( position );\r\n\r\n\t};\r\n\r\n} )();\r\n\r\n// File:src/extras/core/Curve.js\r\n\r\n/**\r\n * @author zz85 / http://www.lab4games.net/zz85/blog\r\n * Extensible curve object\r\n *\r\n * Some common of Curve methods\r\n * .getPoint(t), getTangent(t)\r\n * .getPointAt(u), getTagentAt(u)\r\n * .getPoints(), .getSpacedPoints()\r\n * .getLength()\r\n * .updateArcLengths()\r\n *\r\n * This following classes subclasses THREE.Curve:\r\n *\r\n * -- 2d classes --\r\n * THREE.LineCurve\r\n * THREE.QuadraticBezierCurve\r\n * THREE.CubicBezierCurve\r\n * THREE.SplineCurve\r\n * THREE.ArcCurve\r\n * THREE.EllipseCurve\r\n *\r\n * -- 3d classes --\r\n * THREE.LineCurve3\r\n * THREE.QuadraticBezierCurve3\r\n * THREE.CubicBezierCurve3\r\n * THREE.SplineCurve3\r\n * THREE.ClosedSplineCurve3\r\n *\r\n * A series of curves can be represented as a THREE.CurvePath\r\n *\r\n **/\r\n\r\n/**************************************************************\r\n *\tAbstract Curve base class\r\n **************************************************************/\r\n\r\nTHREE.Curve = function () {\r\n\r\n};\r\n\r\n// Virtual base class method to overwrite and implement in subclasses\r\n//\t- t [0 .. 1]\r\n\r\nTHREE.Curve.prototype.getPoint = function ( t ) {\r\n\r\n\tTHREE.warn( \"THREE.Curve: Warning, getPoint() not implemented!\" );\r\n\treturn null;\r\n\r\n};\r\n\r\n// Get point at relative position in curve according to arc length\r\n// - u [0 .. 1]\r\n\r\nTHREE.Curve.prototype.getPointAt = function ( u ) {\r\n\r\n\tvar t = this.getUtoTmapping( u );\r\n\treturn this.getPoint( t );\r\n\r\n};\r\n\r\n// Get sequence of points using getPoint( t )\r\n\r\nTHREE.Curve.prototype.getPoints = function ( divisions ) {\r\n\r\n\tif ( ! divisions ) divisions = 5;\r\n\r\n\tvar d, pts = [];\r\n\r\n\tfor ( d = 0; d <= divisions; d ++ ) {\r\n\r\n\t\tpts.push( this.getPoint( d / divisions ) );\r\n\r\n\t}\r\n\r\n\treturn pts;\r\n\r\n};\r\n\r\n// Get sequence of points using getPointAt( u )\r\n\r\nTHREE.Curve.prototype.getSpacedPoints = function ( divisions ) {\r\n\r\n\tif ( ! divisions ) divisions = 5;\r\n\r\n\tvar d, pts = [];\r\n\r\n\tfor ( d = 0; d <= divisions; d ++ ) {\r\n\r\n\t\tpts.push( this.getPointAt( d / divisions ) );\r\n\r\n\t}\r\n\r\n\treturn pts;\r\n\r\n};\r\n\r\n// Get total curve arc length\r\n\r\nTHREE.Curve.prototype.getLength = function () {\r\n\r\n\tvar lengths = this.getLengths();\r\n\treturn lengths[ lengths.length - 1 ];\r\n\r\n};\r\n\r\n// Get list of cumulative segment lengths\r\n\r\nTHREE.Curve.prototype.getLengths = function ( divisions ) {\r\n\r\n\tif ( ! divisions ) divisions = (this.__arcLengthDivisions) ? (this.__arcLengthDivisions) : 200;\r\n\r\n\tif ( this.cacheArcLengths\r\n\t\t&& ( this.cacheArcLengths.length == divisions + 1 )\r\n\t\t&& ! this.needsUpdate) {\r\n\r\n\t\t//console.log( \"cached\", this.cacheArcLengths );\r\n\t\treturn this.cacheArcLengths;\r\n\r\n\t}\r\n\r\n\tthis.needsUpdate = false;\r\n\r\n\tvar cache = [];\r\n\tvar current, last = this.getPoint( 0 );\r\n\tvar p, sum = 0;\r\n\r\n\tcache.push( 0 );\r\n\r\n\tfor ( p = 1; p <= divisions; p ++ ) {\r\n\r\n\t\tcurrent = this.getPoint ( p / divisions );\r\n\t\tsum += current.distanceTo( last );\r\n\t\tcache.push( sum );\r\n\t\tlast = current;\r\n\r\n\t}\r\n\r\n\tthis.cacheArcLengths = cache;\r\n\r\n\treturn cache; // { sums: cache, sum:sum }; Sum is in the last element.\r\n\r\n};\r\n\r\n\r\nTHREE.Curve.prototype.updateArcLengths = function() {\r\n\tthis.needsUpdate = true;\r\n\tthis.getLengths();\r\n};\r\n\r\n// Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equi distance\r\n\r\nTHREE.Curve.prototype.getUtoTmapping = function ( u, distance ) {\r\n\r\n\tvar arcLengths = this.getLengths();\r\n\r\n\tvar i = 0, il = arcLengths.length;\r\n\r\n\tvar targetArcLength; // The targeted u distance value to get\r\n\r\n\tif ( distance ) {\r\n\r\n\t\ttargetArcLength = distance;\r\n\r\n\t} else {\r\n\r\n\t\ttargetArcLength = u * arcLengths[ il - 1 ];\r\n\r\n\t}\r\n\r\n\t//var time = Date.now();\r\n\r\n\t// binary search for the index with largest value smaller than target u distance\r\n\r\n\tvar low = 0, high = il - 1, comparison;\r\n\r\n\twhile ( low <= high ) {\r\n\r\n\t\ti = Math.floor( low + ( high - low ) / 2 ); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats\r\n\r\n\t\tcomparison = arcLengths[ i ] - targetArcLength;\r\n\r\n\t\tif ( comparison < 0 ) {\r\n\r\n\t\t\tlow = i + 1;\r\n\r\n\t\t} else if ( comparison > 0 ) {\r\n\r\n\t\t\thigh = i - 1;\r\n\r\n\t\t} else {\r\n\r\n\t\t\thigh = i;\r\n\t\t\tbreak;\r\n\r\n\t\t\t// DONE\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\ti = high;\r\n\r\n\t//console.log('b' , i, low, high, Date.now()- time);\r\n\r\n\tif ( arcLengths[ i ] == targetArcLength ) {\r\n\r\n\t\tvar t = i / ( il - 1 );\r\n\t\treturn t;\r\n\r\n\t}\r\n\r\n\t// we could get finer grain at lengths, or use simple interpolatation between two points\r\n\r\n\tvar lengthBefore = arcLengths[ i ];\r\n\tvar lengthAfter = arcLengths[ i + 1 ];\r\n\r\n\tvar segmentLength = lengthAfter - lengthBefore;\r\n\r\n // determine where we are between the 'before' and 'after' points\r\n\r\n\tvar segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength;\r\n\r\n // add that fractional amount to t\r\n\r\n\tvar t = ( i + segmentFraction ) / ( il - 1 );\r\n\r\n\treturn t;\r\n\r\n};\r\n\r\n// Returns a unit vector tangent at t\r\n// In case any sub curve does not implement its tangent derivation,\r\n// 2 points a small delta apart will be used to find its gradient\r\n// which seems to give a reasonable approximation\r\n\r\nTHREE.Curve.prototype.getTangent = function( t ) {\r\n\r\n\tvar delta = 0.0001;\r\n\tvar t1 = t - delta;\r\n\tvar t2 = t + delta;\r\n\r\n\t// Capping in case of danger\r\n\r\n\tif ( t1 < 0 ) t1 = 0;\r\n\tif ( t2 > 1 ) t2 = 1;\r\n\r\n\tvar pt1 = this.getPoint( t1 );\r\n\tvar pt2 = this.getPoint( t2 );\r\n\r\n\tvar vec = pt2.clone().sub(pt1);\r\n\treturn vec.normalize();\r\n\r\n};\r\n\r\n\r\nTHREE.Curve.prototype.getTangentAt = function ( u ) {\r\n\r\n\tvar t = this.getUtoTmapping( u );\r\n\treturn this.getTangent( t );\r\n\r\n};\r\n\r\n\r\n\r\n\r\n\r\n/**************************************************************\r\n *\tUtils\r\n **************************************************************/\r\n\r\nTHREE.Curve.Utils = {\r\n\r\n\ttangentQuadraticBezier: function ( t, p0, p1, p2 ) {\r\n\r\n\t\treturn 2 * ( 1 - t ) * ( p1 - p0 ) + 2 * t * ( p2 - p1 );\r\n\r\n\t},\r\n\r\n\t// Puay Bing, thanks for helping with this derivative!\r\n\r\n\ttangentCubicBezier: function (t, p0, p1, p2, p3 ) {\r\n\r\n\t\treturn - 3 * p0 * (1 - t) * (1 - t) +\r\n\t\t\t3 * p1 * (1 - t) * (1 - t) - 6 * t * p1 * (1 - t) +\r\n\t\t\t6 * t * p2 * (1 - t) - 3 * t * t * p2 +\r\n\t\t\t3 * t * t * p3;\r\n\r\n\t},\r\n\r\n\ttangentSpline: function ( t, p0, p1, p2, p3 ) {\r\n\r\n\t\t// To check if my formulas are correct\r\n\r\n\t\tvar h00 = 6 * t * t - 6 * t; \t// derived from 2t^3 ā 3t^2 + 1\r\n\t\tvar h10 = 3 * t * t - 4 * t + 1; // t^3 ā 2t^2 + t\r\n\t\tvar h01 = - 6 * t * t + 6 * t; \t// ā 2t3 + 3t2\r\n\t\tvar h11 = 3 * t * t - 2 * t;\t// t3 ā t2\r\n\r\n\t\treturn h00 + h10 + h01 + h11;\r\n\r\n\t},\r\n\r\n\t// Catmull-Rom\r\n\r\n\tinterpolate: function( p0, p1, p2, p3, t ) {\r\n\r\n\t\tvar v0 = ( p2 - p0 ) * 0.5;\r\n\t\tvar v1 = ( p3 - p1 ) * 0.5;\r\n\t\tvar t2 = t * t;\r\n\t\tvar t3 = t * t2;\r\n\t\treturn ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1;\r\n\r\n\t}\r\n\r\n};\r\n\r\n\r\n// TODO: Transformation for Curves?\r\n\r\n/**************************************************************\r\n *\t3D Curves\r\n **************************************************************/\r\n\r\n// A Factory method for creating new curve subclasses\r\n\r\nTHREE.Curve.create = function ( constructor, getPointFunc ) {\r\n\r\n\tconstructor.prototype = Object.create( THREE.Curve.prototype );\r\n\tconstructor.prototype.constructor = constructor;\r\n\tconstructor.prototype.getPoint = getPointFunc;\r\n\r\n\treturn constructor;\r\n\r\n};\r\n\r\n// File:src/extras/core/CurvePath.js\r\n\r\n/**\r\n * @author zz85 / http://www.lab4games.net/zz85/blog\r\n *\r\n **/\r\n\r\n/**************************************************************\r\n *\tCurved Path - a curve path is simply a array of connected\r\n * curves, but retains the api of a curve\r\n **************************************************************/\r\n\r\nTHREE.CurvePath = function () {\r\n\r\n\tthis.curves = [];\r\n\tthis.bends = [];\r\n\t\r\n\tthis.autoClose = false; // Automatically closes the path\r\n};\r\n\r\nTHREE.CurvePath.prototype = Object.create( THREE.Curve.prototype );\r\nTHREE.CurvePath.prototype.constructor = THREE.CurvePath;\r\n\r\nTHREE.CurvePath.prototype.add = function ( curve ) {\r\n\r\n\tthis.curves.push( curve );\r\n\r\n};\r\n\r\nTHREE.CurvePath.prototype.checkConnection = function() {\r\n\t// TODO\r\n\t// If the ending of curve is not connected to the starting\r\n\t// or the next curve, then, this is not a real path\r\n};\r\n\r\nTHREE.CurvePath.prototype.closePath = function() {\r\n\t// TODO Test\r\n\t// and verify for vector3 (needs to implement equals)\r\n\t// Add a line curve if start and end of lines are not connected\r\n\tvar startPoint = this.curves[0].getPoint(0);\r\n\tvar endPoint = this.curves[this.curves.length - 1].getPoint(1);\r\n\t\r\n\tif (! startPoint.equals(endPoint)) {\r\n\t\tthis.curves.push( new THREE.LineCurve(endPoint, startPoint) );\r\n\t}\r\n\t\r\n};\r\n\r\n// To get accurate point with reference to\r\n// entire path distance at time t,\r\n// following has to be done:\r\n\r\n// 1. Length of each sub path have to be known\r\n// 2. Locate and identify type of curve\r\n// 3. Get t for the curve\r\n// 4. Return curve.getPointAt(t')\r\n\r\nTHREE.CurvePath.prototype.getPoint = function( t ) {\r\n\r\n\tvar d = t * this.getLength();\r\n\tvar curveLengths = this.getCurveLengths();\r\n\tvar i = 0, diff, curve;\r\n\r\n\t// To think about boundaries points.\r\n\r\n\twhile ( i < curveLengths.length ) {\r\n\r\n\t\tif ( curveLengths[ i ] >= d ) {\r\n\r\n\t\t\tdiff = curveLengths[ i ] - d;\r\n\t\t\tcurve = this.curves[ i ];\r\n\r\n\t\t\tvar u = 1 - diff / curve.getLength();\r\n\r\n\t\t\treturn curve.getPointAt( u );\r\n\r\n\t\t}\r\n\r\n\t\ti ++;\r\n\r\n\t}\r\n\r\n\treturn null;\r\n\r\n\t// loop where sum != 0, sum > d , sum+1 maxX ) maxX = p.x;\r\n\t\telse if ( p.x < minX ) minX = p.x;\r\n\r\n\t\tif ( p.y > maxY ) maxY = p.y;\r\n\t\telse if ( p.y < minY ) minY = p.y;\r\n\r\n\t\tif ( v3 ) {\r\n\r\n\t\t\tif ( p.z > maxZ ) maxZ = p.z;\r\n\t\t\telse if ( p.z < minZ ) minZ = p.z;\r\n\r\n\t\t}\r\n\r\n\t\tsum.add( p );\r\n\r\n\t}\r\n\r\n\tvar ret = {\r\n\r\n\t\tminX: minX,\r\n\t\tminY: minY,\r\n\t\tmaxX: maxX,\r\n\t\tmaxY: maxY\r\n\r\n\t};\r\n\r\n\tif ( v3 ) {\r\n\r\n\t\tret.maxZ = maxZ;\r\n\t\tret.minZ = minZ;\r\n\r\n\t}\r\n\r\n\treturn ret;\r\n\r\n};\r\n\r\n/**************************************************************\r\n *\tCreate Geometries Helpers\r\n **************************************************************/\r\n\r\n/// Generate geometry from path points (for Line or Points objects)\r\n\r\nTHREE.CurvePath.prototype.createPointsGeometry = function( divisions ) {\r\n\r\n\tvar pts = this.getPoints( divisions, true );\r\n\treturn this.createGeometry( pts );\r\n\r\n};\r\n\r\n// Generate geometry from equidistance sampling along the path\r\n\r\nTHREE.CurvePath.prototype.createSpacedPointsGeometry = function( divisions ) {\r\n\r\n\tvar pts = this.getSpacedPoints( divisions, true );\r\n\treturn this.createGeometry( pts );\r\n\r\n};\r\n\r\nTHREE.CurvePath.prototype.createGeometry = function( points ) {\r\n\r\n\tvar geometry = new THREE.Geometry();\r\n\r\n\tfor ( var i = 0; i < points.length; i ++ ) {\r\n\r\n\t\tgeometry.vertices.push( new THREE.Vector3( points[ i ].x, points[ i ].y, points[ i ].z || 0) );\r\n\r\n\t}\r\n\r\n\treturn geometry;\r\n\r\n};\r\n\r\n\r\n/**************************************************************\r\n *\tBend / Wrap Helper Methods\r\n **************************************************************/\r\n\r\n// Wrap path / Bend modifiers?\r\n\r\nTHREE.CurvePath.prototype.addWrapPath = function ( bendpath ) {\r\n\r\n\tthis.bends.push( bendpath );\r\n\r\n};\r\n\r\nTHREE.CurvePath.prototype.getTransformedPoints = function( segments, bends ) {\r\n\r\n\tvar oldPts = this.getPoints( segments ); // getPoints getSpacedPoints\r\n\tvar i, il;\r\n\r\n\tif ( ! bends ) {\r\n\r\n\t\tbends = this.bends;\r\n\r\n\t}\r\n\r\n\tfor ( i = 0, il = bends.length; i < il; i ++ ) {\r\n\r\n\t\toldPts = this.getWrapPoints( oldPts, bends[ i ] );\r\n\r\n\t}\r\n\r\n\treturn oldPts;\r\n\r\n};\r\n\r\nTHREE.CurvePath.prototype.getTransformedSpacedPoints = function( segments, bends ) {\r\n\r\n\tvar oldPts = this.getSpacedPoints( segments );\r\n\r\n\tvar i, il;\r\n\r\n\tif ( ! bends ) {\r\n\r\n\t\tbends = this.bends;\r\n\r\n\t}\r\n\r\n\tfor ( i = 0, il = bends.length; i < il; i ++ ) {\r\n\r\n\t\toldPts = this.getWrapPoints( oldPts, bends[ i ] );\r\n\r\n\t}\r\n\r\n\treturn oldPts;\r\n\r\n};\r\n\r\n// This returns getPoints() bend/wrapped around the contour of a path.\r\n// Read http://www.planetclegg.com/projects/WarpingTextToSplines.html\r\n\r\nTHREE.CurvePath.prototype.getWrapPoints = function ( oldPts, path ) {\r\n\r\n\tvar bounds = this.getBoundingBox();\r\n\r\n\tvar i, il, p, oldX, oldY, xNorm;\r\n\r\n\tfor ( i = 0, il = oldPts.length; i < il; i ++ ) {\r\n\r\n\t\tp = oldPts[ i ];\r\n\r\n\t\toldX = p.x;\r\n\t\toldY = p.y;\r\n\r\n\t\txNorm = oldX / bounds.maxX;\r\n\r\n\t\t// If using actual distance, for length > path, requires line extrusions\r\n\t\t//xNorm = path.getUtoTmapping(xNorm, oldX); // 3 styles. 1) wrap stretched. 2) wrap stretch by arc length 3) warp by actual distance\r\n\r\n\t\txNorm = path.getUtoTmapping( xNorm, oldX );\r\n\r\n\t\t// check for out of bounds?\r\n\r\n\t\tvar pathPt = path.getPoint( xNorm );\r\n\t\tvar normal = path.getTangent( xNorm );\r\n\t\tnormal.set( - normal.y, normal.x ).multiplyScalar( oldY );\r\n\r\n\t\tp.x = pathPt.x + normal.x;\r\n\t\tp.y = pathPt.y + normal.y;\r\n\r\n\t}\r\n\r\n\treturn oldPts;\r\n\r\n};\r\n\r\n\r\n// File:src/extras/core/Gyroscope.js\r\n\r\n/**\r\n * @author alteredq / http://alteredqualia.com/\r\n */\r\n\r\nTHREE.Gyroscope = function () {\r\n\r\n\tTHREE.Object3D.call( this );\r\n\r\n};\r\n\r\nTHREE.Gyroscope.prototype = Object.create( THREE.Object3D.prototype );\r\nTHREE.Gyroscope.prototype.constructor = THREE.Gyroscope;\r\n\r\nTHREE.Gyroscope.prototype.updateMatrixWorld = ( function () {\r\n\r\n\tvar translationObject = new THREE.Vector3();\r\n\tvar quaternionObject = new THREE.Quaternion();\r\n\tvar scaleObject = new THREE.Vector3();\r\n\r\n\tvar translationWorld = new THREE.Vector3();\r\n\tvar quaternionWorld = new THREE.Quaternion();\r\n\tvar scaleWorld = new THREE.Vector3();\r\n\r\n\treturn function ( force ) {\r\n\r\n\t\tthis.matrixAutoUpdate && this.updateMatrix();\r\n\r\n\t\t// update matrixWorld\r\n\r\n\t\tif ( this.matrixWorldNeedsUpdate || force ) {\r\n\r\n\t\t\tif ( this.parent ) {\r\n\r\n\t\t\t\tthis.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );\r\n\r\n\t\t\t\tthis.matrixWorld.decompose( translationWorld, quaternionWorld, scaleWorld );\r\n\t\t\t\tthis.matrix.decompose( translationObject, quaternionObject, scaleObject );\r\n\r\n\t\t\t\tthis.matrixWorld.compose( translationWorld, quaternionObject, scaleWorld );\r\n\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tthis.matrixWorld.copy( this.matrix );\r\n\r\n\t\t\t}\r\n\r\n\r\n\t\t\tthis.matrixWorldNeedsUpdate = false;\r\n\r\n\t\t\tforce = true;\r\n\r\n\t\t}\r\n\r\n\t\t// update children\r\n\r\n\t\tfor ( var i = 0, l = this.children.length; i < l; i ++ ) {\r\n\r\n\t\t\tthis.children[ i ].updateMatrixWorld( force );\r\n\r\n\t\t}\r\n\r\n\t};\r\n\t\r\n}() );\r\n\r\n// File:src/extras/core/Path.js\r\n\r\n/**\r\n * @author zz85 / http://www.lab4games.net/zz85/blog\r\n * Creates free form 2d path using series of points, lines or curves.\r\n *\r\n **/\r\n\r\nTHREE.Path = function ( points ) {\r\n\r\n\tTHREE.CurvePath.call(this);\r\n\r\n\tthis.actions = [];\r\n\r\n\tif ( points ) {\r\n\r\n\t\tthis.fromPoints( points );\r\n\r\n\t}\r\n\r\n};\r\n\r\nTHREE.Path.prototype = Object.create( THREE.CurvePath.prototype );\r\nTHREE.Path.prototype.constructor = THREE.Path;\r\n\r\nTHREE.PathActions = {\r\n\r\n\tMOVE_TO: 'moveTo',\r\n\tLINE_TO: 'lineTo',\r\n\tQUADRATIC_CURVE_TO: 'quadraticCurveTo', // Bezier quadratic curve\r\n\tBEZIER_CURVE_TO: 'bezierCurveTo', \t\t// Bezier cubic curve\r\n\tCSPLINE_THRU: 'splineThru',\t\t\t\t// Catmull-rom spline\r\n\tARC: 'arc',\t\t\t\t\t\t\t\t// Circle\r\n\tELLIPSE: 'ellipse'\r\n};\r\n\r\n// TODO Clean up PATH API\r\n\r\n// Create path using straight lines to connect all points\r\n// - vectors: array of Vector2\r\n\r\nTHREE.Path.prototype.fromPoints = function ( vectors ) {\r\n\r\n\tthis.moveTo( vectors[ 0 ].x, vectors[ 0 ].y );\r\n\r\n\tfor ( var v = 1, vlen = vectors.length; v < vlen; v ++ ) {\r\n\r\n\t\tthis.lineTo( vectors[ v ].x, vectors[ v ].y );\r\n\r\n\t};\r\n\r\n};\r\n\r\n// startPath() endPath()?\r\n\r\nTHREE.Path.prototype.moveTo = function ( x, y ) {\r\n\r\n\tvar args = Array.prototype.slice.call( arguments );\r\n\tthis.actions.push( { action: THREE.PathActions.MOVE_TO, args: args } );\r\n\r\n};\r\n\r\nTHREE.Path.prototype.lineTo = function ( x, y ) {\r\n\r\n\tvar args = Array.prototype.slice.call( arguments );\r\n\r\n\tvar lastargs = this.actions[ this.actions.length - 1 ].args;\r\n\r\n\tvar x0 = lastargs[ lastargs.length - 2 ];\r\n\tvar y0 = lastargs[ lastargs.length - 1 ];\r\n\r\n\tvar curve = new THREE.LineCurve( new THREE.Vector2( x0, y0 ), new THREE.Vector2( x, y ) );\r\n\tthis.curves.push( curve );\r\n\r\n\tthis.actions.push( { action: THREE.PathActions.LINE_TO, args: args } );\r\n\r\n};\r\n\r\nTHREE.Path.prototype.quadraticCurveTo = function( aCPx, aCPy, aX, aY ) {\r\n\r\n\tvar args = Array.prototype.slice.call( arguments );\r\n\r\n\tvar lastargs = this.actions[ this.actions.length - 1 ].args;\r\n\r\n\tvar x0 = lastargs[ lastargs.length - 2 ];\r\n\tvar y0 = lastargs[ lastargs.length - 1 ];\r\n\r\n\tvar curve = new THREE.QuadraticBezierCurve( new THREE.Vector2( x0, y0 ),\r\n\t\t\t\t\t\t\t\t\t\t\t\tnew THREE.Vector2( aCPx, aCPy ),\r\n\t\t\t\t\t\t\t\t\t\t\t\tnew THREE.Vector2( aX, aY ) );\r\n\tthis.curves.push( curve );\r\n\r\n\tthis.actions.push( { action: THREE.PathActions.QUADRATIC_CURVE_TO, args: args } );\r\n\r\n};\r\n\r\nTHREE.Path.prototype.bezierCurveTo = function( aCP1x, aCP1y,\r\n\t\t\t\t\t\t\t\t\t\t\t aCP2x, aCP2y,\r\n\t\t\t\t\t\t\t\t\t\t\t aX, aY ) {\r\n\r\n\tvar args = Array.prototype.slice.call( arguments );\r\n\r\n\tvar lastargs = this.actions[ this.actions.length - 1 ].args;\r\n\r\n\tvar x0 = lastargs[ lastargs.length - 2 ];\r\n\tvar y0 = lastargs[ lastargs.length - 1 ];\r\n\r\n\tvar curve = new THREE.CubicBezierCurve( new THREE.Vector2( x0, y0 ),\r\n\t\t\t\t\t\t\t\t\t\t\tnew THREE.Vector2( aCP1x, aCP1y ),\r\n\t\t\t\t\t\t\t\t\t\t\tnew THREE.Vector2( aCP2x, aCP2y ),\r\n\t\t\t\t\t\t\t\t\t\t\tnew THREE.Vector2( aX, aY ) );\r\n\tthis.curves.push( curve );\r\n\r\n\tthis.actions.push( { action: THREE.PathActions.BEZIER_CURVE_TO, args: args } );\r\n\r\n};\r\n\r\nTHREE.Path.prototype.splineThru = function( pts /*Array of Vector*/ ) {\r\n\r\n\tvar args = Array.prototype.slice.call( arguments );\r\n\tvar lastargs = this.actions[ this.actions.length - 1 ].args;\r\n\r\n\tvar x0 = lastargs[ lastargs.length - 2 ];\r\n\tvar y0 = lastargs[ lastargs.length - 1 ];\r\n//---\r\n\tvar npts = [ new THREE.Vector2( x0, y0 ) ];\r\n\tArray.prototype.push.apply( npts, pts );\r\n\r\n\tvar curve = new THREE.SplineCurve( npts );\r\n\tthis.curves.push( curve );\r\n\r\n\tthis.actions.push( { action: THREE.PathActions.CSPLINE_THRU, args: args } );\r\n\r\n};\r\n\r\n// FUTURE: Change the API or follow canvas API?\r\n\r\nTHREE.Path.prototype.arc = function ( aX, aY, aRadius,\r\n\t\t\t\t\t\t\t\t\t aStartAngle, aEndAngle, aClockwise ) {\r\n\r\n\tvar lastargs = this.actions[ this.actions.length - 1].args;\r\n\tvar x0 = lastargs[ lastargs.length - 2 ];\r\n\tvar y0 = lastargs[ lastargs.length - 1 ];\r\n\r\n\tthis.absarc(aX + x0, aY + y0, aRadius,\r\n\t\taStartAngle, aEndAngle, aClockwise );\r\n\r\n };\r\n\r\n THREE.Path.prototype.absarc = function ( aX, aY, aRadius,\r\n\t\t\t\t\t\t\t\t\t aStartAngle, aEndAngle, aClockwise ) {\r\n\tthis.absellipse(aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise);\r\n };\r\n\r\nTHREE.Path.prototype.ellipse = function ( aX, aY, xRadius, yRadius,\r\n\t\t\t\t\t\t\t\t\t aStartAngle, aEndAngle, aClockwise ) {\r\n\r\n\tvar lastargs = this.actions[ this.actions.length - 1].args;\r\n\tvar x0 = lastargs[ lastargs.length - 2 ];\r\n\tvar y0 = lastargs[ lastargs.length - 1 ];\r\n\r\n\tthis.absellipse(aX + x0, aY + y0, xRadius, yRadius,\r\n\t\taStartAngle, aEndAngle, aClockwise );\r\n\r\n };\r\n\r\n\r\nTHREE.Path.prototype.absellipse = function ( aX, aY, xRadius, yRadius,\r\n\t\t\t\t\t\t\t\t\t aStartAngle, aEndAngle, aClockwise ) {\r\n\r\n\tvar args = Array.prototype.slice.call( arguments );\r\n\tvar curve = new THREE.EllipseCurve( aX, aY, xRadius, yRadius,\r\n\t\t\t\t\t\t\t\t\taStartAngle, aEndAngle, aClockwise );\r\n\tthis.curves.push( curve );\r\n\r\n\tvar lastPoint = curve.getPoint(1);\r\n\targs.push(lastPoint.x);\r\n\targs.push(lastPoint.y);\r\n\r\n\tthis.actions.push( { action: THREE.PathActions.ELLIPSE, args: args } );\r\n\r\n };\r\n\r\nTHREE.Path.prototype.getSpacedPoints = function ( divisions, closedPath ) {\r\n\r\n\tif ( ! divisions ) divisions = 40;\r\n\r\n\tvar points = [];\r\n\r\n\tfor ( var i = 0; i < divisions; i ++ ) {\r\n\r\n\t\tpoints.push( this.getPoint( i / divisions ) );\r\n\r\n\t\t//if( !this.getPoint( i / divisions ) ) throw \"DIE\";\r\n\r\n\t}\r\n\r\n\t// if ( closedPath ) {\r\n\t//\r\n\t// \tpoints.push( points[ 0 ] );\r\n\t//\r\n\t// }\r\n\r\n\treturn points;\r\n\r\n};\r\n\r\n/* Return an array of vectors based on contour of the path */\r\n\r\nTHREE.Path.prototype.getPoints = function( divisions, closedPath ) {\r\n\r\n\tif (this.useSpacedPoints) {\r\n\t\tconsole.log('tata');\r\n\t\treturn this.getSpacedPoints( divisions, closedPath );\r\n\t}\r\n\r\n\tdivisions = divisions || 12;\r\n\r\n\tvar points = [];\r\n\r\n\tvar i, il, item, action, args;\r\n\tvar cpx, cpy, cpx2, cpy2, cpx1, cpy1, cpx0, cpy0,\r\n\t\tlaste, j,\r\n\t\tt, tx, ty;\r\n\r\n\tfor ( i = 0, il = this.actions.length; i < il; i ++ ) {\r\n\r\n\t\titem = this.actions[ i ];\r\n\r\n\t\taction = item.action;\r\n\t\targs = item.args;\r\n\r\n\t\tswitch ( action ) {\r\n\r\n\t\tcase THREE.PathActions.MOVE_TO:\r\n\r\n\t\t\tpoints.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) );\r\n\r\n\t\t\tbreak;\r\n\r\n\t\tcase THREE.PathActions.LINE_TO:\r\n\r\n\t\t\tpoints.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) );\r\n\r\n\t\t\tbreak;\r\n\r\n\t\tcase THREE.PathActions.QUADRATIC_CURVE_TO:\r\n\r\n\t\t\tcpx = args[ 2 ];\r\n\t\t\tcpy = args[ 3 ];\r\n\r\n\t\t\tcpx1 = args[ 0 ];\r\n\t\t\tcpy1 = args[ 1 ];\r\n\r\n\t\t\tif ( points.length > 0 ) {\r\n\r\n\t\t\t\tlaste = points[ points.length - 1 ];\r\n\r\n\t\t\t\tcpx0 = laste.x;\r\n\t\t\t\tcpy0 = laste.y;\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tlaste = this.actions[ i - 1 ].args;\r\n\r\n\t\t\t\tcpx0 = laste[ laste.length - 2 ];\r\n\t\t\t\tcpy0 = laste[ laste.length - 1 ];\r\n\r\n\t\t\t}\r\n\r\n\t\t\tfor ( j = 1; j <= divisions; j ++ ) {\r\n\r\n\t\t\t\tt = j / divisions;\r\n\r\n\t\t\t\ttx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx );\r\n\t\t\t\tty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy );\r\n\r\n\t\t\t\tpoints.push( new THREE.Vector2( tx, ty ) );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tbreak;\r\n\r\n\t\tcase THREE.PathActions.BEZIER_CURVE_TO:\r\n\r\n\t\t\tcpx = args[ 4 ];\r\n\t\t\tcpy = args[ 5 ];\r\n\r\n\t\t\tcpx1 = args[ 0 ];\r\n\t\t\tcpy1 = args[ 1 ];\r\n\r\n\t\t\tcpx2 = args[ 2 ];\r\n\t\t\tcpy2 = args[ 3 ];\r\n\r\n\t\t\tif ( points.length > 0 ) {\r\n\r\n\t\t\t\tlaste = points[ points.length - 1 ];\r\n\r\n\t\t\t\tcpx0 = laste.x;\r\n\t\t\t\tcpy0 = laste.y;\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tlaste = this.actions[ i - 1 ].args;\r\n\r\n\t\t\t\tcpx0 = laste[ laste.length - 2 ];\r\n\t\t\t\tcpy0 = laste[ laste.length - 1 ];\r\n\r\n\t\t\t}\r\n\r\n\r\n\t\t\tfor ( j = 1; j <= divisions; j ++ ) {\r\n\r\n\t\t\t\tt = j / divisions;\r\n\r\n\t\t\t\ttx = THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx );\r\n\t\t\t\tty = THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy );\r\n\r\n\t\t\t\tpoints.push( new THREE.Vector2( tx, ty ) );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tbreak;\r\n\r\n\t\tcase THREE.PathActions.CSPLINE_THRU:\r\n\r\n\t\t\tlaste = this.actions[ i - 1 ].args;\r\n\r\n\t\t\tvar last = new THREE.Vector2( laste[ laste.length - 2 ], laste[ laste.length - 1 ] );\r\n\t\t\tvar spts = [ last ];\r\n\r\n\t\t\tvar n = divisions * args[ 0 ].length;\r\n\r\n\t\t\tspts = spts.concat( args[ 0 ] );\r\n\r\n\t\t\tvar spline = new THREE.SplineCurve( spts );\r\n\r\n\t\t\tfor ( j = 1; j <= n; j ++ ) {\r\n\r\n\t\t\t\tpoints.push( spline.getPointAt( j / n ) ) ;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tbreak;\r\n\r\n\t\tcase THREE.PathActions.ARC:\r\n\r\n\t\t\tvar aX = args[ 0 ], aY = args[ 1 ],\r\n\t\t\t\taRadius = args[ 2 ],\r\n\t\t\t\taStartAngle = args[ 3 ], aEndAngle = args[ 4 ],\r\n\t\t\t\taClockwise = !! args[ 5 ];\r\n\r\n\t\t\tvar deltaAngle = aEndAngle - aStartAngle;\r\n\t\t\tvar angle;\r\n\t\t\tvar tdivisions = divisions * 2;\r\n\r\n\t\t\tfor ( j = 1; j <= tdivisions; j ++ ) {\r\n\r\n\t\t\t\tt = j / tdivisions;\r\n\r\n\t\t\t\tif ( ! aClockwise ) {\r\n\r\n\t\t\t\t\tt = 1 - t;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tangle = aStartAngle + t * deltaAngle;\r\n\r\n\t\t\t\ttx = aX + aRadius * Math.cos( angle );\r\n\t\t\t\tty = aY + aRadius * Math.sin( angle );\r\n\r\n\t\t\t\t//console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty);\r\n\r\n\t\t\t\tpoints.push( new THREE.Vector2( tx, ty ) );\r\n\r\n\t\t\t}\r\n\r\n\t\t\t//console.log(points);\r\n\r\n\t\t\tbreak;\r\n\t\t \r\n\t\tcase THREE.PathActions.ELLIPSE:\r\n\r\n\t\t\tvar aX = args[ 0 ], aY = args[ 1 ],\r\n\t\t\t\txRadius = args[ 2 ],\r\n\t\t\t\tyRadius = args[ 3 ],\r\n\t\t\t\taStartAngle = args[ 4 ], aEndAngle = args[ 5 ],\r\n\t\t\t\taClockwise = !! args[ 6 ];\r\n\r\n\r\n\t\t\tvar deltaAngle = aEndAngle - aStartAngle;\r\n\t\t\tvar angle;\r\n\t\t\tvar tdivisions = divisions * 2;\r\n\r\n\t\t\tfor ( j = 1; j <= tdivisions; j ++ ) {\r\n\r\n\t\t\t\tt = j / tdivisions;\r\n\r\n\t\t\t\tif ( ! aClockwise ) {\r\n\r\n\t\t\t\t\tt = 1 - t;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tangle = aStartAngle + t * deltaAngle;\r\n\r\n\t\t\t\ttx = aX + xRadius * Math.cos( angle );\r\n\t\t\t\tty = aY + yRadius * Math.sin( angle );\r\n\r\n\t\t\t\t//console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty);\r\n\r\n\t\t\t\tpoints.push( new THREE.Vector2( tx, ty ) );\r\n\r\n\t\t\t}\r\n\r\n\t\t\t//console.log(points);\r\n\r\n\t\t\tbreak;\r\n\r\n\t\t} // end switch\r\n\r\n\t}\r\n\r\n\r\n\r\n\t// Normalize to remove the closing point by default.\r\n\tvar lastPoint = points[ points.length - 1];\r\n\tvar EPSILON = 0.0000000001;\r\n\tif ( Math.abs(lastPoint.x - points[ 0 ].x) < EPSILON &&\r\n\t\t\t Math.abs(lastPoint.y - points[ 0 ].y) < EPSILON)\r\n\t\tpoints.splice( points.length - 1, 1);\r\n\tif ( closedPath ) {\r\n\r\n\t\tpoints.push( points[ 0 ] );\r\n\r\n\t}\r\n\r\n\treturn points;\r\n\r\n};\r\n\r\n//\r\n// Breaks path into shapes\r\n//\r\n//\tAssumptions (if parameter isCCW==true the opposite holds):\r\n//\t- solid shapes are defined clockwise (CW)\r\n//\t- holes are defined counterclockwise (CCW)\r\n//\r\n//\tIf parameter noHoles==true:\r\n// - all subPaths are regarded as solid shapes\r\n// - definition order CW/CCW has no relevance\r\n//\r\n\r\nTHREE.Path.prototype.toShapes = function( isCCW, noHoles ) {\r\n\r\n\tfunction extractSubpaths( inActions ) {\r\n\r\n\t\tvar i, il, item, action, args;\r\n\r\n\t\tvar subPaths = [], lastPath = new THREE.Path();\r\n\r\n\t\tfor ( i = 0, il = inActions.length; i < il; i ++ ) {\r\n\r\n\t\t\titem = inActions[ i ];\r\n\r\n\t\t\targs = item.args;\r\n\t\t\taction = item.action;\r\n\r\n\t\t\tif ( action == THREE.PathActions.MOVE_TO ) {\r\n\r\n\t\t\t\tif ( lastPath.actions.length != 0 ) {\r\n\r\n\t\t\t\t\tsubPaths.push( lastPath );\r\n\t\t\t\t\tlastPath = new THREE.Path();\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\tlastPath[ action ].apply( lastPath, args );\r\n\r\n\t\t}\r\n\r\n\t\tif ( lastPath.actions.length != 0 ) {\r\n\r\n\t\t\tsubPaths.push( lastPath );\r\n\r\n\t\t}\r\n\r\n\t\t// console.log(subPaths);\r\n\r\n\t\treturn\tsubPaths;\r\n\t}\r\n\r\n\tfunction toShapesNoHoles( inSubpaths ) {\r\n\r\n\t\tvar shapes = [];\r\n\r\n\t\tfor ( var i = 0, il = inSubpaths.length; i < il; i ++ ) {\r\n\r\n\t\t\tvar tmpPath = inSubpaths[ i ];\r\n\r\n\t\t\tvar tmpShape = new THREE.Shape();\r\n\t\t\ttmpShape.actions = tmpPath.actions;\r\n\t\t\ttmpShape.curves = tmpPath.curves;\r\n\r\n\t\t\tshapes.push( tmpShape );\r\n\t\t}\r\n\r\n\t\t//console.log(\"shape\", shapes);\r\n\r\n\t\treturn shapes;\r\n\t};\r\n\r\n\tfunction isPointInsidePolygon( inPt, inPolygon ) {\r\n\t\tvar EPSILON = 0.0000000001;\r\n\r\n\t\tvar polyLen = inPolygon.length;\r\n\r\n\t\t// inPt on polygon contour => immediate success or\r\n\t\t// toggling of inside/outside at every single! intersection point of an edge\r\n\t\t// with the horizontal line through inPt, left of inPt\r\n\t\t// not counting lowerY endpoints of edges and whole edges on that line\r\n\t\tvar inside = false;\r\n\t\tfor ( var p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) {\r\n\t\t\tvar edgeLowPt = inPolygon[ p ];\r\n\t\t\tvar edgeHighPt = inPolygon[ q ];\r\n\r\n\t\t\tvar edgeDx = edgeHighPt.x - edgeLowPt.x;\r\n\t\t\tvar edgeDy = edgeHighPt.y - edgeLowPt.y;\r\n\r\n\t\t\tif ( Math.abs(edgeDy) > EPSILON ) {\t\t\t// not parallel\r\n\t\t\t\tif ( edgeDy < 0 ) {\r\n\t\t\t\t\tedgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx;\r\n\t\t\t\t\tedgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy;\r\n\t\t\t\t}\r\n\t\t\t\tif ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) \t\tcontinue;\r\n\r\n\t\t\t\tif ( inPt.y == edgeLowPt.y ) {\r\n\t\t\t\t\tif ( inPt.x == edgeLowPt.x )\t\treturn\ttrue;\t\t// inPt is on contour ?\r\n\t\t\t\t\t// continue;\t\t\t\t// no intersection or edgeLowPt => doesn't count !!!\r\n\t\t\t\t} else {\r\n\t\t\t\t\tvar perpEdge = edgeDy * (inPt.x - edgeLowPt.x) - edgeDx * (inPt.y - edgeLowPt.y);\r\n\t\t\t\t\tif ( perpEdge == 0 )\t\t\t\treturn\ttrue;\t\t// inPt is on contour ?\r\n\t\t\t\t\tif ( perpEdge < 0 ) \t\t\t\tcontinue;\r\n\t\t\t\t\tinside = ! inside;\t\t// true intersection left of inPt\r\n\t\t\t\t}\r\n\t\t\t} else {\t\t// parallel or colinear\r\n\t\t\t\tif ( inPt.y != edgeLowPt.y ) \t\tcontinue;\t\t\t// parallel\r\n\t\t\t\t// egde lies on the same horizontal line as inPt\r\n\t\t\t\tif ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) ||\r\n\t\t\t\t\t ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) )\t\treturn\ttrue;\t// inPt: Point on contour !\r\n\t\t\t\t// continue;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn\tinside;\r\n\t}\r\n\r\n\r\n\tvar subPaths = extractSubpaths( this.actions );\r\n\tif ( subPaths.length == 0 ) return [];\r\n\r\n\tif ( noHoles === true )\treturn\ttoShapesNoHoles( subPaths );\r\n\r\n\r\n\tvar solid, tmpPath, tmpShape, shapes = [];\r\n\r\n\tif ( subPaths.length == 1) {\r\n\r\n\t\ttmpPath = subPaths[0];\r\n\t\ttmpShape = new THREE.Shape();\r\n\t\ttmpShape.actions = tmpPath.actions;\r\n\t\ttmpShape.curves = tmpPath.curves;\r\n\t\tshapes.push( tmpShape );\r\n\t\treturn shapes;\r\n\r\n\t}\r\n\r\n\tvar holesFirst = ! THREE.Shape.Utils.isClockWise( subPaths[ 0 ].getPoints() );\r\n\tholesFirst = isCCW ? ! holesFirst : holesFirst;\r\n\r\n\t// console.log(\"Holes first\", holesFirst);\r\n\t\r\n\tvar betterShapeHoles = [];\r\n\tvar newShapes = [];\r\n\tvar newShapeHoles = [];\r\n\tvar mainIdx = 0;\r\n\tvar tmpPoints;\r\n\r\n\tnewShapes[mainIdx] = undefined;\r\n\tnewShapeHoles[mainIdx] = [];\r\n\r\n\tvar i, il;\r\n\r\n\tfor ( i = 0, il = subPaths.length; i < il; i ++ ) {\r\n\r\n\t\ttmpPath = subPaths[ i ];\r\n\t\ttmpPoints = tmpPath.getPoints();\r\n\t\tsolid = THREE.Shape.Utils.isClockWise( tmpPoints );\r\n\t\tsolid = isCCW ? ! solid : solid;\r\n\r\n\t\tif ( solid ) {\r\n\r\n\t\t\tif ( (! holesFirst ) && ( newShapes[mainIdx] ) )\tmainIdx ++;\r\n\r\n\t\t\tnewShapes[mainIdx] = { s: new THREE.Shape(), p: tmpPoints };\r\n\t\t\tnewShapes[mainIdx].s.actions = tmpPath.actions;\r\n\t\t\tnewShapes[mainIdx].s.curves = tmpPath.curves;\r\n\t\t\t\r\n\t\t\tif ( holesFirst )\tmainIdx ++;\r\n\t\t\tnewShapeHoles[mainIdx] = [];\r\n\r\n\t\t\t//console.log('cw', i);\r\n\r\n\t\t} else {\r\n\r\n\t\t\tnewShapeHoles[mainIdx].push( { h: tmpPath, p: tmpPoints[0] } );\r\n\r\n\t\t\t//console.log('ccw', i);\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t// only Holes? -> probably all Shapes with wrong orientation\r\n\tif ( ! newShapes[0] )\treturn\ttoShapesNoHoles( subPaths );\r\n\r\n\r\n\tif ( newShapes.length > 1 ) {\r\n\t\tvar ambigious = false;\r\n\t\tvar toChange = [];\r\n\r\n\t\tfor (var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {\r\n\t\t\tbetterShapeHoles[sIdx] = [];\r\n\t\t}\r\n\t\tfor (var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {\r\n\t\t\tvar sho = newShapeHoles[sIdx];\r\n\t\t\tfor (var hIdx = 0; hIdx < sho.length; hIdx ++ ) {\r\n\t\t\t\tvar ho = sho[hIdx];\r\n\t\t\t\tvar hole_unassigned = true;\r\n\t\t\t\tfor (var s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) {\r\n\t\t\t\t\tif ( isPointInsidePolygon( ho.p, newShapes[s2Idx].p ) ) {\r\n\t\t\t\t\t\tif ( sIdx != s2Idx )\t\ttoChange.push( { froms: sIdx, tos: s2Idx, hole: hIdx } );\r\n\t\t\t\t\t\tif ( hole_unassigned ) {\r\n\t\t\t\t\t\t\thole_unassigned = false;\r\n\t\t\t\t\t\t\tbetterShapeHoles[s2Idx].push( ho );\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tambigious = true;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tif ( hole_unassigned ) { betterShapeHoles[sIdx].push( ho ); }\r\n\t\t\t}\r\n\t\t}\r\n\t\t// console.log(\"ambigious: \", ambigious);\r\n\t\tif ( toChange.length > 0 ) {\r\n\t\t\t// console.log(\"to change: \", toChange);\r\n\t\t\tif (! ambigious)\tnewShapeHoles = betterShapeHoles;\r\n\t\t}\r\n\t}\r\n\r\n\tvar tmpHoles, j, jl;\r\n\tfor ( i = 0, il = newShapes.length; i < il; i ++ ) {\r\n\t\ttmpShape = newShapes[i].s;\r\n\t\tshapes.push( tmpShape );\r\n\t\ttmpHoles = newShapeHoles[i];\r\n\t\tfor ( j = 0, jl = tmpHoles.length; j < jl; j ++ ) {\r\n\t\t\ttmpShape.holes.push( tmpHoles[j].h );\r\n\t\t}\r\n\t}\r\n\r\n\t//console.log(\"shape\", shapes);\r\n\r\n\treturn shapes;\r\n\r\n};\r\n\r\n// File:src/extras/core/Shape.js\r\n\r\n/**\r\n * @author zz85 / http://www.lab4games.net/zz85/blog\r\n * Defines a 2d shape plane using paths.\r\n **/\r\n\r\n// STEP 1 Create a path.\r\n// STEP 2 Turn path into shape.\r\n// STEP 3 ExtrudeGeometry takes in Shape/Shapes\r\n// STEP 3a - Extract points from each shape, turn to vertices\r\n// STEP 3b - Triangulate each shape, add faces.\r\n\r\nTHREE.Shape = function () {\r\n\r\n\tTHREE.Path.apply( this, arguments );\r\n\tthis.holes = [];\r\n\r\n};\r\n\r\nTHREE.Shape.prototype = Object.create( THREE.Path.prototype );\r\nTHREE.Shape.prototype.constructor = THREE.Shape;\r\n\r\n// Convenience method to return ExtrudeGeometry\r\n\r\nTHREE.Shape.prototype.extrude = function ( options ) {\r\n\r\n\tvar extruded = new THREE.ExtrudeGeometry( this, options );\r\n\treturn extruded;\r\n\r\n};\r\n\r\n// Convenience method to return ShapeGeometry\r\n\r\nTHREE.Shape.prototype.makeGeometry = function ( options ) {\r\n\r\n\tvar geometry = new THREE.ShapeGeometry( this, options );\r\n\treturn geometry;\r\n\r\n};\r\n\r\n// Get points of holes\r\n\r\nTHREE.Shape.prototype.getPointsHoles = function ( divisions ) {\r\n\r\n\tvar i, il = this.holes.length, holesPts = [];\r\n\r\n\tfor ( i = 0; i < il; i ++ ) {\r\n\r\n\t\tholesPts[ i ] = this.holes[ i ].getTransformedPoints( divisions, this.bends );\r\n\r\n\t}\r\n\r\n\treturn holesPts;\r\n\r\n};\r\n\r\n// Get points of holes (spaced by regular distance)\r\n\r\nTHREE.Shape.prototype.getSpacedPointsHoles = function ( divisions ) {\r\n\r\n\tvar i, il = this.holes.length, holesPts = [];\r\n\r\n\tfor ( i = 0; i < il; i ++ ) {\r\n\r\n\t\tholesPts[ i ] = this.holes[ i ].getTransformedSpacedPoints( divisions, this.bends );\r\n\r\n\t}\r\n\r\n\treturn holesPts;\r\n\r\n};\r\n\r\n\r\n// Get points of shape and holes (keypoints based on segments parameter)\r\n\r\nTHREE.Shape.prototype.extractAllPoints = function ( divisions ) {\r\n\r\n\treturn {\r\n\r\n\t\tshape: this.getTransformedPoints( divisions ),\r\n\t\tholes: this.getPointsHoles( divisions )\r\n\r\n\t};\r\n\r\n};\r\n\r\nTHREE.Shape.prototype.extractPoints = function ( divisions ) {\r\n\r\n\tif (this.useSpacedPoints) {\r\n\t\treturn this.extractAllSpacedPoints(divisions);\r\n\t}\r\n\r\n\treturn this.extractAllPoints(divisions);\r\n\r\n};\r\n\r\n//\r\n// THREE.Shape.prototype.extractAllPointsWithBend = function ( divisions, bend ) {\r\n//\r\n// \treturn {\r\n//\r\n// \t\tshape: this.transform( bend, divisions ),\r\n// \t\tholes: this.getPointsHoles( divisions, bend )\r\n//\r\n// \t};\r\n//\r\n// };\r\n\r\n// Get points of shape and holes (spaced by regular distance)\r\n\r\nTHREE.Shape.prototype.extractAllSpacedPoints = function ( divisions ) {\r\n\r\n\treturn {\r\n\r\n\t\tshape: this.getTransformedSpacedPoints( divisions ),\r\n\t\tholes: this.getSpacedPointsHoles( divisions )\r\n\r\n\t};\r\n\r\n};\r\n\r\n/**************************************************************\r\n *\tUtils\r\n **************************************************************/\r\n\r\nTHREE.Shape.Utils = {\r\n\r\n\ttriangulateShape: function ( contour, holes ) {\r\n\r\n\t\tfunction point_in_segment_2D_colin( inSegPt1, inSegPt2, inOtherPt ) {\r\n\t\t\t// inOtherPt needs to be colinear to the inSegment\r\n\t\t\tif ( inSegPt1.x != inSegPt2.x ) {\r\n\t\t\t\tif ( inSegPt1.x < inSegPt2.x ) {\r\n\t\t\t\t\treturn\t( ( inSegPt1.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt2.x ) );\r\n\t\t\t\t} else {\r\n\t\t\t\t\treturn\t( ( inSegPt2.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt1.x ) );\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tif ( inSegPt1.y < inSegPt2.y ) {\r\n\t\t\t\t\treturn\t( ( inSegPt1.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt2.y ) );\r\n\t\t\t\t} else {\r\n\t\t\t\t\treturn\t( ( inSegPt2.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt1.y ) );\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tfunction intersect_segments_2D( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1, inSeg2Pt2, inExcludeAdjacentSegs ) {\r\n\t\t\tvar EPSILON = 0.0000000001;\r\n\r\n\t\t\tvar seg1dx = inSeg1Pt2.x - inSeg1Pt1.x, seg1dy = inSeg1Pt2.y - inSeg1Pt1.y;\r\n\t\t\tvar seg2dx = inSeg2Pt2.x - inSeg2Pt1.x, seg2dy = inSeg2Pt2.y - inSeg2Pt1.y;\r\n\r\n\t\t\tvar seg1seg2dx = inSeg1Pt1.x - inSeg2Pt1.x;\r\n\t\t\tvar seg1seg2dy = inSeg1Pt1.y - inSeg2Pt1.y;\r\n\r\n\t\t\tvar limit\t\t= seg1dy * seg2dx - seg1dx * seg2dy;\r\n\t\t\tvar perpSeg1\t= seg1dy * seg1seg2dx - seg1dx * seg1seg2dy;\r\n\r\n\t\t\tif ( Math.abs(limit) > EPSILON ) {\t\t\t// not parallel\r\n\r\n\t\t\t\tvar perpSeg2;\r\n\t\t\t\tif ( limit > 0 ) {\r\n\t\t\t\t\tif ( ( perpSeg1 < 0 ) || ( perpSeg1 > limit ) ) \t\treturn [];\r\n\t\t\t\t\tperpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy;\r\n\t\t\t\t\tif ( ( perpSeg2 < 0 ) || ( perpSeg2 > limit ) ) \t\treturn [];\r\n\t\t\t\t} else {\r\n\t\t\t\t\tif ( ( perpSeg1 > 0 ) || ( perpSeg1 < limit ) ) \t\treturn [];\r\n\t\t\t\t\tperpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy;\r\n\t\t\t\t\tif ( ( perpSeg2 > 0 ) || ( perpSeg2 < limit ) ) \t\treturn [];\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// i.e. to reduce rounding errors\r\n\t\t\t\t// intersection at endpoint of segment#1?\r\n\t\t\t\tif ( perpSeg2 == 0 ) {\r\n\t\t\t\t\tif ( ( inExcludeAdjacentSegs ) &&\r\n\t\t\t\t\t\t ( ( perpSeg1 == 0 ) || ( perpSeg1 == limit ) ) )\t\treturn [];\r\n\t\t\t\t\treturn [ inSeg1Pt1 ];\r\n\t\t\t\t}\r\n\t\t\t\tif ( perpSeg2 == limit ) {\r\n\t\t\t\t\tif ( ( inExcludeAdjacentSegs ) &&\r\n\t\t\t\t\t\t ( ( perpSeg1 == 0 ) || ( perpSeg1 == limit ) ) )\t\treturn [];\r\n\t\t\t\t\treturn [ inSeg1Pt2 ];\r\n\t\t\t\t}\r\n\t\t\t\t// intersection at endpoint of segment#2?\r\n\t\t\t\tif ( perpSeg1 == 0 )\t\treturn [ inSeg2Pt1 ];\r\n\t\t\t\tif ( perpSeg1 == limit )\treturn [ inSeg2Pt2 ];\r\n\r\n\t\t\t\t// return real intersection point\r\n\t\t\t\tvar factorSeg1 = perpSeg2 / limit;\r\n\t\t\t\treturn\t[ { x: inSeg1Pt1.x + factorSeg1 * seg1dx,\r\n\t\t\t\t\t\t\ty: inSeg1Pt1.y + factorSeg1 * seg1dy } ];\r\n\r\n\t\t\t} else {\t\t// parallel or colinear\r\n\t\t\t\tif ( ( perpSeg1 != 0 ) ||\r\n\t\t\t\t\t ( seg2dy * seg1seg2dx != seg2dx * seg1seg2dy ) ) \t\t\treturn [];\r\n\r\n\t\t\t\t// they are collinear or degenerate\r\n\t\t\t\tvar seg1Pt = ( (seg1dx == 0) && (seg1dy == 0) );\t// segment1 ist just a point?\r\n\t\t\t\tvar seg2Pt = ( (seg2dx == 0) && (seg2dy == 0) );\t// segment2 ist just a point?\r\n\t\t\t\t// both segments are points\r\n\t\t\t\tif ( seg1Pt && seg2Pt ) {\r\n\t\t\t\t\tif ( (inSeg1Pt1.x != inSeg2Pt1.x) ||\r\n\t\t\t\t\t\t (inSeg1Pt1.y != inSeg2Pt1.y) )\t\treturn []; \t// they are distinct points\r\n\t\t\t\t\treturn [ inSeg1Pt1 ]; \t\t\t\t\t// they are the same point\r\n\t\t\t\t}\r\n\t\t\t\t// segment#1 is a single point\r\n\t\t\t\tif ( seg1Pt ) {\r\n\t\t\t\t\tif (! point_in_segment_2D_colin( inSeg2Pt1, inSeg2Pt2, inSeg1Pt1 ) )\t\treturn [];\t\t// but not in segment#2\r\n\t\t\t\t\treturn [ inSeg1Pt1 ];\r\n\t\t\t\t}\r\n\t\t\t\t// segment#2 is a single point\r\n\t\t\t\tif ( seg2Pt ) {\r\n\t\t\t\t\tif (! point_in_segment_2D_colin( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1 ) )\t\treturn [];\t\t// but not in segment#1\r\n\t\t\t\t\treturn [ inSeg2Pt1 ];\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// they are collinear segments, which might overlap\r\n\t\t\t\tvar seg1min, seg1max, seg1minVal, seg1maxVal;\r\n\t\t\t\tvar seg2min, seg2max, seg2minVal, seg2maxVal;\r\n\t\t\t\tif (seg1dx != 0) {\t\t// the segments are NOT on a vertical line\r\n\t\t\t\t\tif ( inSeg1Pt1.x < inSeg1Pt2.x ) {\r\n\t\t\t\t\t\tseg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.x;\r\n\t\t\t\t\t\tseg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.x;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tseg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.x;\r\n\t\t\t\t\t\tseg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.x;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif ( inSeg2Pt1.x < inSeg2Pt2.x ) {\r\n\t\t\t\t\t\tseg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.x;\r\n\t\t\t\t\t\tseg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.x;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tseg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.x;\r\n\t\t\t\t\t\tseg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.x;\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\t\t\t\t// the segments are on a vertical line\r\n\t\t\t\t\tif ( inSeg1Pt1.y < inSeg1Pt2.y ) {\r\n\t\t\t\t\t\tseg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.y;\r\n\t\t\t\t\t\tseg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.y;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tseg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.y;\r\n\t\t\t\t\t\tseg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.y;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif ( inSeg2Pt1.y < inSeg2Pt2.y ) {\r\n\t\t\t\t\t\tseg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.y;\r\n\t\t\t\t\t\tseg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.y;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tseg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.y;\r\n\t\t\t\t\t\tseg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.y;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tif ( seg1minVal <= seg2minVal ) {\r\n\t\t\t\t\tif ( seg1maxVal < seg2minVal )\treturn [];\r\n\t\t\t\t\tif ( seg1maxVal == seg2minVal )\t{\r\n\t\t\t\t\t\tif ( inExcludeAdjacentSegs )\t\treturn [];\r\n\t\t\t\t\t\treturn [ seg2min ];\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif ( seg1maxVal <= seg2maxVal )\treturn [ seg2min, seg1max ];\r\n\t\t\t\t\treturn\t[ seg2min, seg2max ];\r\n\t\t\t\t} else {\r\n\t\t\t\t\tif ( seg1minVal > seg2maxVal )\treturn [];\r\n\t\t\t\t\tif ( seg1minVal == seg2maxVal )\t{\r\n\t\t\t\t\t\tif ( inExcludeAdjacentSegs )\t\treturn [];\r\n\t\t\t\t\t\treturn [ seg1min ];\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif ( seg1maxVal <= seg2maxVal )\treturn [ seg1min, seg1max ];\r\n\t\t\t\t\treturn\t[ seg1min, seg2max ];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tfunction isPointInsideAngle( inVertex, inLegFromPt, inLegToPt, inOtherPt ) {\r\n\t\t\t// The order of legs is important\r\n\r\n\t\t\tvar EPSILON = 0.0000000001;\r\n\r\n\t\t\t// translation of all points, so that Vertex is at (0,0)\r\n\t\t\tvar legFromPtX\t= inLegFromPt.x - inVertex.x, legFromPtY\t= inLegFromPt.y - inVertex.y;\r\n\t\t\tvar legToPtX\t= inLegToPt.x\t- inVertex.x, legToPtY\t\t= inLegToPt.y\t- inVertex.y;\r\n\t\t\tvar otherPtX\t= inOtherPt.x\t- inVertex.x, otherPtY\t\t= inOtherPt.y\t- inVertex.y;\r\n\r\n\t\t\t// main angle >0: < 180 deg.; 0: 180 deg.; <0: > 180 deg.\r\n\t\t\tvar from2toAngle\t= legFromPtX * legToPtY - legFromPtY * legToPtX;\r\n\t\t\tvar from2otherAngle\t= legFromPtX * otherPtY - legFromPtY * otherPtX;\r\n\r\n\t\t\tif ( Math.abs(from2toAngle) > EPSILON ) {\t\t\t// angle != 180 deg.\r\n\r\n\t\t\t\tvar other2toAngle\t\t= otherPtX * legToPtY - otherPtY * legToPtX;\r\n\t\t\t\t// console.log( \"from2to: \" + from2toAngle + \", from2other: \" + from2otherAngle + \", other2to: \" + other2toAngle );\r\n\r\n\t\t\t\tif ( from2toAngle > 0 ) {\t\t\t\t// main angle < 180 deg.\r\n\t\t\t\t\treturn\t( ( from2otherAngle >= 0 ) && ( other2toAngle >= 0 ) );\r\n\t\t\t\t} else {\t\t\t\t\t\t\t\t// main angle > 180 deg.\r\n\t\t\t\t\treturn\t( ( from2otherAngle >= 0 ) || ( other2toAngle >= 0 ) );\r\n\t\t\t\t}\r\n\t\t\t} else {\t\t\t\t\t\t\t\t\t\t// angle == 180 deg.\r\n\t\t\t\t// console.log( \"from2to: 180 deg., from2other: \" + from2otherAngle );\r\n\t\t\t\treturn\t( from2otherAngle > 0 );\r\n\t\t\t}\r\n\t\t}\r\n\r\n\r\n\t\tfunction removeHoles( contour, holes ) {\r\n\r\n\t\t\tvar shape = contour.concat(); // work on this shape\r\n\t\t\tvar hole;\r\n\r\n\t\t\tfunction isCutLineInsideAngles( inShapeIdx, inHoleIdx ) {\r\n\t\t\t\t// Check if hole point lies within angle around shape point\r\n\t\t\t\tvar lastShapeIdx = shape.length - 1;\r\n\r\n\t\t\t\tvar prevShapeIdx = inShapeIdx - 1;\r\n\t\t\t\tif ( prevShapeIdx < 0 )\t\t\tprevShapeIdx = lastShapeIdx;\r\n\r\n\t\t\t\tvar nextShapeIdx = inShapeIdx + 1;\r\n\t\t\t\tif ( nextShapeIdx > lastShapeIdx )\tnextShapeIdx = 0;\r\n\r\n\t\t\t\tvar insideAngle = isPointInsideAngle( shape[inShapeIdx], shape[ prevShapeIdx ], shape[ nextShapeIdx ], hole[inHoleIdx] );\r\n\t\t\t\tif (! insideAngle ) {\r\n\t\t\t\t\t// console.log( \"Vertex (Shape): \" + inShapeIdx + \", Point: \" + hole[inHoleIdx].x + \"/\" + hole[inHoleIdx].y );\r\n\t\t\t\t\treturn\tfalse;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Check if shape point lies within angle around hole point\r\n\t\t\t\tvar lastHoleIdx = hole.length - 1;\r\n\r\n\t\t\t\tvar prevHoleIdx = inHoleIdx - 1;\r\n\t\t\t\tif ( prevHoleIdx < 0 )\t\t\tprevHoleIdx = lastHoleIdx;\r\n\r\n\t\t\t\tvar nextHoleIdx = inHoleIdx + 1;\r\n\t\t\t\tif ( nextHoleIdx > lastHoleIdx )\tnextHoleIdx = 0;\r\n\r\n\t\t\t\tinsideAngle = isPointInsideAngle( hole[inHoleIdx], hole[ prevHoleIdx ], hole[ nextHoleIdx ], shape[inShapeIdx] );\r\n\t\t\t\tif (! insideAngle ) {\r\n\t\t\t\t\t// console.log( \"Vertex (Hole): \" + inHoleIdx + \", Point: \" + shape[inShapeIdx].x + \"/\" + shape[inShapeIdx].y );\r\n\t\t\t\t\treturn\tfalse;\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn\ttrue;\r\n\t\t\t}\r\n\r\n\t\t\tfunction intersectsShapeEdge( inShapePt, inHolePt ) {\r\n\t\t\t\t// checks for intersections with shape edges\r\n\t\t\t\tvar sIdx, nextIdx, intersection;\r\n\t\t\t\tfor ( sIdx = 0; sIdx < shape.length; sIdx ++ ) {\r\n\t\t\t\t\tnextIdx = sIdx + 1; nextIdx %= shape.length;\r\n\t\t\t\t\tintersection = intersect_segments_2D( inShapePt, inHolePt, shape[sIdx], shape[nextIdx], true );\r\n\t\t\t\t\tif ( intersection.length > 0 )\t\treturn\ttrue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn\tfalse;\r\n\t\t\t}\r\n\r\n\t\t\tvar indepHoles = [];\r\n\r\n\t\t\tfunction intersectsHoleEdge( inShapePt, inHolePt ) {\r\n\t\t\t\t// checks for intersections with hole edges\r\n\t\t\t\tvar ihIdx, chkHole,\r\n\t\t\t\t\thIdx, nextIdx, intersection;\r\n\t\t\t\tfor ( ihIdx = 0; ihIdx < indepHoles.length; ihIdx ++ ) {\r\n\t\t\t\t\tchkHole = holes[indepHoles[ihIdx]];\r\n\t\t\t\t\tfor ( hIdx = 0; hIdx < chkHole.length; hIdx ++ ) {\r\n\t\t\t\t\t\tnextIdx = hIdx + 1; nextIdx %= chkHole.length;\r\n\t\t\t\t\t\tintersection = intersect_segments_2D( inShapePt, inHolePt, chkHole[hIdx], chkHole[nextIdx], true );\r\n\t\t\t\t\t\tif ( intersection.length > 0 )\t\treturn\ttrue;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\treturn\tfalse;\r\n\t\t\t}\r\n\r\n\t\t\tvar holeIndex, shapeIndex,\r\n\t\t\t\tshapePt, holePt,\r\n\t\t\t\tholeIdx, cutKey, failedCuts = [],\r\n\t\t\t\ttmpShape1, tmpShape2,\r\n\t\t\t\ttmpHole1, tmpHole2;\r\n\r\n\t\t\tfor ( var h = 0, hl = holes.length; h < hl; h ++ ) {\r\n\r\n\t\t\t\tindepHoles.push( h );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tvar minShapeIndex = 0;\r\n\t\t\tvar counter = indepHoles.length * 2;\r\n\t\t\twhile ( indepHoles.length > 0 ) {\r\n\t\t\t\tcounter --;\r\n\t\t\t\tif ( counter < 0 ) {\r\n\t\t\t\t\tconsole.log( \"Infinite Loop! Holes left:\" + indepHoles.length + \", Probably Hole outside Shape!\" );\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// search for shape-vertex and hole-vertex,\r\n\t\t\t\t// which can be connected without intersections\r\n\t\t\t\tfor ( shapeIndex = minShapeIndex; shapeIndex < shape.length; shapeIndex ++ ) {\r\n\r\n\t\t\t\t\tshapePt = shape[ shapeIndex ];\r\n\t\t\t\t\tholeIndex\t= - 1;\r\n\r\n\t\t\t\t\t// search for hole which can be reached without intersections\r\n\t\t\t\t\tfor ( var h = 0; h < indepHoles.length; h ++ ) {\r\n\t\t\t\t\t\tholeIdx = indepHoles[h];\r\n\r\n\t\t\t\t\t\t// prevent multiple checks\r\n\t\t\t\t\t\tcutKey = shapePt.x + \":\" + shapePt.y + \":\" + holeIdx;\r\n\t\t\t\t\t\tif ( failedCuts[cutKey] !== undefined )\t\t\tcontinue;\r\n\r\n\t\t\t\t\t\thole = holes[holeIdx];\r\n\t\t\t\t\t\tfor ( var h2 = 0; h2 < hole.length; h2 ++ ) {\r\n\t\t\t\t\t\t\tholePt = hole[ h2 ];\r\n\t\t\t\t\t\t\tif (! isCutLineInsideAngles( shapeIndex, h2 ) )\t\tcontinue;\r\n\t\t\t\t\t\t\tif ( intersectsShapeEdge( shapePt, holePt ) )\t\tcontinue;\r\n\t\t\t\t\t\t\tif ( intersectsHoleEdge( shapePt, holePt ) )\t\tcontinue;\r\n\r\n\t\t\t\t\t\t\tholeIndex = h2;\r\n\t\t\t\t\t\t\tindepHoles.splice(h, 1);\r\n\r\n\t\t\t\t\t\t\ttmpShape1 = shape.slice( 0, shapeIndex + 1 );\r\n\t\t\t\t\t\t\ttmpShape2 = shape.slice( shapeIndex );\r\n\t\t\t\t\t\t\ttmpHole1 = hole.slice( holeIndex );\r\n\t\t\t\t\t\t\ttmpHole2 = hole.slice( 0, holeIndex + 1 );\r\n\r\n\t\t\t\t\t\t\tshape = tmpShape1.concat( tmpHole1 ).concat( tmpHole2 ).concat( tmpShape2 );\r\n\r\n\t\t\t\t\t\t\tminShapeIndex = shapeIndex;\r\n\r\n\t\t\t\t\t\t\t// Debug only, to show the selected cuts\r\n\t\t\t\t\t\t\t// glob_CutLines.push( [ shapePt, holePt ] );\r\n\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif ( holeIndex >= 0 )\tbreak;\t\t// hole-vertex found\r\n\r\n\t\t\t\t\t\tfailedCuts[cutKey] = true;\t\t\t// remember failure\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif ( holeIndex >= 0 )\tbreak;\t\t// hole-vertex found\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn shape; \t\t\t/* shape with no holes */\r\n\t\t}\r\n\r\n\r\n\t\tvar i, il, f, face,\r\n\t\t\tkey, index,\r\n\t\t\tallPointsMap = {};\r\n\r\n\t\t// To maintain reference to old shape, one must match coordinates, or offset the indices from original arrays. It's probably easier to do the first.\r\n\r\n\t\tvar allpoints = contour.concat();\r\n\r\n\t\tfor ( var h = 0, hl = holes.length; h < hl; h ++ ) {\r\n\r\n\t\t\tArray.prototype.push.apply( allpoints, holes[h] );\r\n\r\n\t\t}\r\n\r\n\t\t//console.log( \"allpoints\",allpoints, allpoints.length );\r\n\r\n\t\t// prepare all points map\r\n\r\n\t\tfor ( i = 0, il = allpoints.length; i < il; i ++ ) {\r\n\r\n\t\t\tkey = allpoints[ i ].x + \":\" + allpoints[ i ].y;\r\n\r\n\t\t\tif ( allPointsMap[ key ] !== undefined ) {\r\n\r\n\t\t\t\tTHREE.warn( \"THREE.Shape: Duplicate point\", key );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tallPointsMap[ key ] = i;\r\n\r\n\t\t}\r\n\r\n\t\t// remove holes by cutting paths to holes and adding them to the shape\r\n\t\tvar shapeWithoutHoles = removeHoles( contour, holes );\r\n\r\n\t\tvar triangles = THREE.FontUtils.Triangulate( shapeWithoutHoles, false ); // True returns indices for points of spooled shape\r\n\t\t//console.log( \"triangles\",triangles, triangles.length );\r\n\r\n\t\t// check all face vertices against all points map\r\n\r\n\t\tfor ( i = 0, il = triangles.length; i < il; i ++ ) {\r\n\r\n\t\t\tface = triangles[ i ];\r\n\r\n\t\t\tfor ( f = 0; f < 3; f ++ ) {\r\n\r\n\t\t\t\tkey = face[ f ].x + \":\" + face[ f ].y;\r\n\r\n\t\t\t\tindex = allPointsMap[ key ];\r\n\r\n\t\t\t\tif ( index !== undefined ) {\r\n\r\n\t\t\t\t\tface[ f ] = index;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\treturn triangles.concat();\r\n\r\n\t},\r\n\r\n\tisClockWise: function ( pts ) {\r\n\r\n\t\treturn THREE.FontUtils.Triangulate.area( pts ) < 0;\r\n\r\n\t},\r\n\r\n\t// Bezier Curves formulas obtained from\r\n\t// http://en.wikipedia.org/wiki/B%C3%A9zier_curve\r\n\r\n\t// Quad Bezier Functions\r\n\r\n\tb2p0: function ( t, p ) {\r\n\r\n\t\tvar k = 1 - t;\r\n\t\treturn k * k * p;\r\n\r\n\t},\r\n\r\n\tb2p1: function ( t, p ) {\r\n\r\n\t\treturn 2 * ( 1 - t ) * t * p;\r\n\r\n\t},\r\n\r\n\tb2p2: function ( t, p ) {\r\n\r\n\t\treturn t * t * p;\r\n\r\n\t},\r\n\r\n\tb2: function ( t, p0, p1, p2 ) {\r\n\r\n\t\treturn this.b2p0( t, p0 ) + this.b2p1( t, p1 ) + this.b2p2( t, p2 );\r\n\r\n\t},\r\n\r\n\t// Cubic Bezier Functions\r\n\r\n\tb3p0: function ( t, p ) {\r\n\r\n\t\tvar k = 1 - t;\r\n\t\treturn k * k * k * p;\r\n\r\n\t},\r\n\r\n\tb3p1: function ( t, p ) {\r\n\r\n\t\tvar k = 1 - t;\r\n\t\treturn 3 * k * k * t * p;\r\n\r\n\t},\r\n\r\n\tb3p2: function ( t, p ) {\r\n\r\n\t\tvar k = 1 - t;\r\n\t\treturn 3 * k * t * t * p;\r\n\r\n\t},\r\n\r\n\tb3p3: function ( t, p ) {\r\n\r\n\t\treturn t * t * t * p;\r\n\r\n\t},\r\n\r\n\tb3: function ( t, p0, p1, p2, p3 ) {\r\n\r\n\t\treturn this.b3p0( t, p0 ) + this.b3p1( t, p1 ) + this.b3p2( t, p2 ) + this.b3p3( t, p3 );\r\n\r\n\t}\r\n\r\n};\r\n\r\n\r\n// File:src/extras/curves/LineCurve.js\r\n\r\n/**************************************************************\r\n *\tLine\r\n **************************************************************/\r\n\r\nTHREE.LineCurve = function ( v1, v2 ) {\r\n\r\n\tthis.v1 = v1;\r\n\tthis.v2 = v2;\r\n\r\n};\r\n\r\nTHREE.LineCurve.prototype = Object.create( THREE.Curve.prototype );\r\nTHREE.LineCurve.prototype.constructor = THREE.LineCurve;\r\n\r\nTHREE.LineCurve.prototype.getPoint = function ( t ) {\r\n\r\n\tvar point = this.v2.clone().sub(this.v1);\r\n\tpoint.multiplyScalar( t ).add( this.v1 );\r\n\r\n\treturn point;\r\n\r\n};\r\n\r\n// Line curve is linear, so we can overwrite default getPointAt\r\n\r\nTHREE.LineCurve.prototype.getPointAt = function ( u ) {\r\n\r\n\treturn this.getPoint( u );\r\n\r\n};\r\n\r\nTHREE.LineCurve.prototype.getTangent = function( t ) {\r\n\r\n\tvar tangent = this.v2.clone().sub(this.v1);\r\n\r\n\treturn tangent.normalize();\r\n\r\n};\r\n\r\n// File:src/extras/curves/QuadraticBezierCurve.js\r\n\r\n/**************************************************************\r\n *\tQuadratic Bezier curve\r\n **************************************************************/\r\n\r\n\r\nTHREE.QuadraticBezierCurve = function ( v0, v1, v2 ) {\r\n\r\n\tthis.v0 = v0;\r\n\tthis.v1 = v1;\r\n\tthis.v2 = v2;\r\n\r\n};\r\n\r\nTHREE.QuadraticBezierCurve.prototype = Object.create( THREE.Curve.prototype );\r\nTHREE.QuadraticBezierCurve.prototype.constructor = THREE.QuadraticBezierCurve;\r\n\r\n\r\nTHREE.QuadraticBezierCurve.prototype.getPoint = function ( t ) {\r\n\r\n\tvar vector = new THREE.Vector2();\r\n\r\n\tvector.x = THREE.Shape.Utils.b2( t, this.v0.x, this.v1.x, this.v2.x );\r\n\tvector.y = THREE.Shape.Utils.b2( t, this.v0.y, this.v1.y, this.v2.y );\r\n\r\n\treturn vector;\r\n\r\n};\r\n\r\n\r\nTHREE.QuadraticBezierCurve.prototype.getTangent = function( t ) {\r\n\r\n\tvar vector = new THREE.Vector2();\r\n\r\n\tvector.x = THREE.Curve.Utils.tangentQuadraticBezier( t, this.v0.x, this.v1.x, this.v2.x );\r\n\tvector.y = THREE.Curve.Utils.tangentQuadraticBezier( t, this.v0.y, this.v1.y, this.v2.y );\r\n\r\n\t// returns unit vector\r\n\r\n\treturn vector.normalize();\r\n\r\n};\r\n\r\n// File:src/extras/curves/CubicBezierCurve.js\r\n\r\n/**************************************************************\r\n *\tCubic Bezier curve\r\n **************************************************************/\r\n\r\nTHREE.CubicBezierCurve = function ( v0, v1, v2, v3 ) {\r\n\r\n\tthis.v0 = v0;\r\n\tthis.v1 = v1;\r\n\tthis.v2 = v2;\r\n\tthis.v3 = v3;\r\n\r\n};\r\n\r\nTHREE.CubicBezierCurve.prototype = Object.create( THREE.Curve.prototype );\r\nTHREE.CubicBezierCurve.prototype.constructor = THREE.CubicBezierCurve;\r\n\r\nTHREE.CubicBezierCurve.prototype.getPoint = function ( t ) {\r\n\r\n\tvar tx, ty;\r\n\r\n\ttx = THREE.Shape.Utils.b3( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x );\r\n\tty = THREE.Shape.Utils.b3( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y );\r\n\r\n\treturn new THREE.Vector2( tx, ty );\r\n\r\n};\r\n\r\nTHREE.CubicBezierCurve.prototype.getTangent = function( t ) {\r\n\r\n\tvar tx, ty;\r\n\r\n\ttx = THREE.Curve.Utils.tangentCubicBezier( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x );\r\n\tty = THREE.Curve.Utils.tangentCubicBezier( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y );\r\n\r\n\tvar tangent = new THREE.Vector2( tx, ty );\r\n\ttangent.normalize();\r\n\r\n\treturn tangent;\r\n\r\n};\r\n\r\n// File:src/extras/curves/SplineCurve.js\r\n\r\n/**************************************************************\r\n *\tSpline curve\r\n **************************************************************/\r\n\r\nTHREE.SplineCurve = function ( points /* array of Vector2 */ ) {\r\n\r\n\tthis.points = ( points == undefined ) ? [] : points;\r\n\r\n};\r\n\r\nTHREE.SplineCurve.prototype = Object.create( THREE.Curve.prototype );\r\nTHREE.SplineCurve.prototype.constructor = THREE.SplineCurve;\r\n\r\nTHREE.SplineCurve.prototype.getPoint = function ( t ) {\r\n\r\n\tvar points = this.points;\r\n\tvar point = ( points.length - 1 ) * t;\r\n\r\n\tvar intPoint = Math.floor( point );\r\n\tvar weight = point - intPoint;\r\n\r\n\tvar point0 = points[ intPoint == 0 ? intPoint : intPoint - 1 ]\r\n\tvar point1 = points[ intPoint ]\r\n\tvar point2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ]\r\n\tvar point3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ]\r\n\r\n\tvar vector = new THREE.Vector2();\r\n\r\n\tvector.x = THREE.Curve.Utils.interpolate( point0.x, point1.x, point2.x, point3.x, weight );\r\n\tvector.y = THREE.Curve.Utils.interpolate( point0.y, point1.y, point2.y, point3.y, weight );\r\n\r\n\treturn vector;\r\n\r\n};\r\n\r\n// File:src/extras/curves/EllipseCurve.js\r\n\r\n/**************************************************************\r\n *\tEllipse curve\r\n **************************************************************/\r\n\r\nTHREE.EllipseCurve = function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise ) {\r\n\r\n\tthis.aX = aX;\r\n\tthis.aY = aY;\r\n\r\n\tthis.xRadius = xRadius;\r\n\tthis.yRadius = yRadius;\r\n\r\n\tthis.aStartAngle = aStartAngle;\r\n\tthis.aEndAngle = aEndAngle;\r\n\r\n\tthis.aClockwise = aClockwise;\r\n\r\n};\r\n\r\nTHREE.EllipseCurve.prototype = Object.create( THREE.Curve.prototype );\r\nTHREE.EllipseCurve.prototype.constructor = THREE.EllipseCurve;\r\n\r\nTHREE.EllipseCurve.prototype.getPoint = function ( t ) {\r\n\r\n\tvar deltaAngle = this.aEndAngle - this.aStartAngle;\r\n\r\n\tif ( deltaAngle < 0 ) deltaAngle += Math.PI * 2;\r\n\tif ( deltaAngle > Math.PI * 2 ) deltaAngle -= Math.PI * 2;\r\n\r\n\tvar angle;\r\n\r\n\tif ( this.aClockwise === true ) {\r\n\r\n\t\tangle = this.aEndAngle + ( 1 - t ) * ( Math.PI * 2 - deltaAngle );\r\n\r\n\t} else {\r\n\r\n\t\tangle = this.aStartAngle + t * deltaAngle;\r\n\r\n\t}\r\n\t\r\n\tvar vector = new THREE.Vector2();\r\n\r\n\tvector.x = this.aX + this.xRadius * Math.cos( angle );\r\n\tvector.y = this.aY + this.yRadius * Math.sin( angle );\r\n\r\n\treturn vector;\r\n\r\n};\r\n\r\n// File:src/extras/curves/ArcCurve.js\r\n\r\n/**************************************************************\r\n *\tArc curve\r\n **************************************************************/\r\n\r\nTHREE.ArcCurve = function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {\r\n\r\n\tTHREE.EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );\r\n};\r\n\r\nTHREE.ArcCurve.prototype = Object.create( THREE.EllipseCurve.prototype );\r\nTHREE.ArcCurve.prototype.constructor = THREE.ArcCurve;\r\n\r\n// File:src/extras/curves/LineCurve3.js\r\n\r\n/**************************************************************\r\n *\tLine3D\r\n **************************************************************/\r\n\r\nTHREE.LineCurve3 = THREE.Curve.create(\r\n\r\n\tfunction ( v1, v2 ) {\r\n\r\n\t\tthis.v1 = v1;\r\n\t\tthis.v2 = v2;\r\n\r\n\t},\r\n\r\n\tfunction ( t ) {\r\n\r\n\t\tvar vector = new THREE.Vector3();\r\n\r\n\t\tvector.subVectors( this.v2, this.v1 ); // diff\r\n\t\tvector.multiplyScalar( t );\r\n\t\tvector.add( this.v1 );\r\n\r\n\t\treturn vector;\r\n\r\n\t}\r\n\r\n);\r\n\r\n// File:src/extras/curves/QuadraticBezierCurve3.js\r\n\r\n/**************************************************************\r\n *\tQuadratic Bezier 3D curve\r\n **************************************************************/\r\n\r\nTHREE.QuadraticBezierCurve3 = THREE.Curve.create(\r\n\r\n\tfunction ( v0, v1, v2 ) {\r\n\r\n\t\tthis.v0 = v0;\r\n\t\tthis.v1 = v1;\r\n\t\tthis.v2 = v2;\r\n\r\n\t},\r\n\r\n\tfunction ( t ) {\r\n\r\n\t\tvar vector = new THREE.Vector3();\r\n\r\n\t\tvector.x = THREE.Shape.Utils.b2( t, this.v0.x, this.v1.x, this.v2.x );\r\n\t\tvector.y = THREE.Shape.Utils.b2( t, this.v0.y, this.v1.y, this.v2.y );\r\n\t\tvector.z = THREE.Shape.Utils.b2( t, this.v0.z, this.v1.z, this.v2.z );\r\n\r\n\t\treturn vector;\r\n\r\n\t}\r\n\r\n);\r\n\r\n// File:src/extras/curves/CubicBezierCurve3.js\r\n\r\n/**************************************************************\r\n *\tCubic Bezier 3D curve\r\n **************************************************************/\r\n\r\nTHREE.CubicBezierCurve3 = THREE.Curve.create(\r\n\r\n\tfunction ( v0, v1, v2, v3 ) {\r\n\r\n\t\tthis.v0 = v0;\r\n\t\tthis.v1 = v1;\r\n\t\tthis.v2 = v2;\r\n\t\tthis.v3 = v3;\r\n\r\n\t},\r\n\r\n\tfunction ( t ) {\r\n\r\n\t\tvar vector = new THREE.Vector3();\r\n\r\n\t\tvector.x = THREE.Shape.Utils.b3( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x );\r\n\t\tvector.y = THREE.Shape.Utils.b3( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y );\r\n\t\tvector.z = THREE.Shape.Utils.b3( t, this.v0.z, this.v1.z, this.v2.z, this.v3.z );\r\n\r\n\t\treturn vector;\r\n\r\n\t}\r\n\r\n);\r\n\r\n// File:src/extras/curves/SplineCurve3.js\r\n\r\n/**************************************************************\r\n *\tSpline 3D curve\r\n **************************************************************/\r\n\r\n\r\nTHREE.SplineCurve3 = THREE.Curve.create(\r\n\r\n\tfunction ( points /* array of Vector3 */) {\r\n\r\n\t\tthis.points = ( points == undefined ) ? [] : points;\r\n\r\n\t},\r\n\r\n\tfunction ( t ) {\r\n\r\n\t\tvar points = this.points;\r\n\t\tvar point = ( points.length - 1 ) * t;\r\n\r\n\t\tvar intPoint = Math.floor( point );\r\n\t\tvar weight = point - intPoint;\r\n\r\n\t\tvar point0 = points[ intPoint == 0 ? intPoint : intPoint - 1 ];\r\n\t\tvar point1 = points[ intPoint ];\r\n\t\tvar point2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ];\r\n\t\tvar point3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ];\r\n\r\n\t\tvar vector = new THREE.Vector3();\r\n\r\n\t\tvector.x = THREE.Curve.Utils.interpolate( point0.x, point1.x, point2.x, point3.x, weight );\r\n\t\tvector.y = THREE.Curve.Utils.interpolate( point0.y, point1.y, point2.y, point3.y, weight );\r\n\t\tvector.z = THREE.Curve.Utils.interpolate( point0.z, point1.z, point2.z, point3.z, weight );\r\n\r\n\t\treturn vector;\r\n\r\n\t}\r\n\r\n);\r\n\r\n// File:src/extras/curves/ClosedSplineCurve3.js\r\n\r\n/**************************************************************\r\n *\tClosed Spline 3D curve\r\n **************************************************************/\r\n\r\n\r\nTHREE.ClosedSplineCurve3 = THREE.Curve.create(\r\n\r\n\tfunction ( points /* array of Vector3 */) {\r\n\r\n\t\tthis.points = ( points == undefined ) ? [] : points;\r\n\r\n\t},\r\n\r\n\tfunction ( t ) {\r\n\r\n\t\tvar points = this.points;\r\n\t\tvar point = ( points.length - 0 ) * t; // This needs to be from 0-length +1\r\n\r\n\t\tvar intPoint = Math.floor( point );\r\n\t\tvar weight = point - intPoint;\r\n\r\n\t\tintPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / points.length ) + 1 ) * points.length;\r\n\r\n\t\tvar point0 = points[ ( intPoint - 1 ) % points.length ];\r\n\t\tvar point1 = points[ ( intPoint ) % points.length ];\r\n\t\tvar point2 = points[ ( intPoint + 1 ) % points.length ];\r\n\t\tvar point3 = points[ ( intPoint + 2 ) % points.length ];\r\n\r\n\t\tvar vector = new THREE.Vector3();\r\n\r\n\t\tvector.x = THREE.Curve.Utils.interpolate( point0.x, point1.x, point2.x, point3.x, weight );\r\n\t\tvector.y = THREE.Curve.Utils.interpolate( point0.y, point1.y, point2.y, point3.y, weight );\r\n\t\tvector.z = THREE.Curve.Utils.interpolate( point0.z, point1.z, point2.z, point3.z, weight );\r\n\r\n\t\treturn vector;\r\n\r\n\t}\r\n\r\n);\r\n\r\n// File:src/extras/animation/AnimationHandler.js\r\n\r\n/**\r\n * @author mikael emtinger / http://gomo.se/\r\n */\r\n\r\nTHREE.AnimationHandler = {\r\n\r\n\tLINEAR: 0,\r\n\tCATMULLROM: 1,\r\n\tCATMULLROM_FORWARD: 2,\r\n\r\n\t//\r\n\r\n\tadd: function () { THREE.warn( 'THREE.AnimationHandler.add() has been deprecated.' ); },\r\n\tget: function () { THREE.warn( 'THREE.AnimationHandler.get() has been deprecated.' ); },\r\n\tremove: function () { THREE.warn( 'THREE.AnimationHandler.remove() has been deprecated.' ); },\r\n\r\n\t//\r\n\r\n\tanimations: [],\r\n\r\n\tinit: function ( data ) {\r\n\r\n\t\tif ( data.initialized === true ) return data;\r\n\r\n\t\t// loop through all keys\r\n\r\n\t\tfor ( var h = 0; h < data.hierarchy.length; h ++ ) {\r\n\r\n\t\t\tfor ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) {\r\n\r\n\t\t\t\t// remove minus times\r\n\r\n\t\t\t\tif ( data.hierarchy[ h ].keys[ k ].time < 0 ) {\r\n\r\n\t\t\t\t\t data.hierarchy[ h ].keys[ k ].time = 0;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// create quaternions\r\n\r\n\t\t\t\tif ( data.hierarchy[ h ].keys[ k ].rot !== undefined &&\r\n\t\t\t\t ! ( data.hierarchy[ h ].keys[ k ].rot instanceof THREE.Quaternion ) ) {\r\n\r\n\t\t\t\t\tvar quat = data.hierarchy[ h ].keys[ k ].rot;\r\n\t\t\t\t\tdata.hierarchy[ h ].keys[ k ].rot = new THREE.Quaternion().fromArray( quat );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\t// prepare morph target keys\r\n\r\n\t\t\tif ( data.hierarchy[ h ].keys.length && data.hierarchy[ h ].keys[ 0 ].morphTargets !== undefined ) {\r\n\r\n\t\t\t\t// get all used\r\n\r\n\t\t\t\tvar usedMorphTargets = {};\r\n\r\n\t\t\t\tfor ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) {\r\n\r\n\t\t\t\t\tfor ( var m = 0; m < data.hierarchy[ h ].keys[ k ].morphTargets.length; m ++ ) {\r\n\r\n\t\t\t\t\t\tvar morphTargetName = data.hierarchy[ h ].keys[ k ].morphTargets[ m ];\r\n\t\t\t\t\t\tusedMorphTargets[ morphTargetName ] = - 1;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tdata.hierarchy[ h ].usedMorphTargets = usedMorphTargets;\r\n\r\n\r\n\t\t\t\t// set all used on all frames\r\n\r\n\t\t\t\tfor ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) {\r\n\r\n\t\t\t\t\tvar influences = {};\r\n\r\n\t\t\t\t\tfor ( var morphTargetName in usedMorphTargets ) {\r\n\r\n\t\t\t\t\t\tfor ( var m = 0; m < data.hierarchy[ h ].keys[ k ].morphTargets.length; m ++ ) {\r\n\r\n\t\t\t\t\t\t\tif ( data.hierarchy[ h ].keys[ k ].morphTargets[ m ] === morphTargetName ) {\r\n\r\n\t\t\t\t\t\t\t\tinfluences[ morphTargetName ] = data.hierarchy[ h ].keys[ k ].morphTargetsInfluences[ m ];\r\n\t\t\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tif ( m === data.hierarchy[ h ].keys[ k ].morphTargets.length ) {\r\n\r\n\t\t\t\t\t\t\tinfluences[ morphTargetName ] = 0;\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tdata.hierarchy[ h ].keys[ k ].morphTargetsInfluences = influences;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\r\n\t\t\t// remove all keys that are on the same time\r\n\r\n\t\t\tfor ( var k = 1; k < data.hierarchy[ h ].keys.length; k ++ ) {\r\n\r\n\t\t\t\tif ( data.hierarchy[ h ].keys[ k ].time === data.hierarchy[ h ].keys[ k - 1 ].time ) {\r\n\r\n\t\t\t\t\tdata.hierarchy[ h ].keys.splice( k, 1 );\r\n\t\t\t\t\tk --;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\r\n\t\t\t// set index\r\n\r\n\t\t\tfor ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) {\r\n\r\n\t\t\t\tdata.hierarchy[ h ].keys[ k ].index = k;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tdata.initialized = true;\r\n\r\n\t\treturn data;\r\n\r\n\t},\r\n\r\n\tparse: function ( root ) {\r\n\r\n\t\tvar parseRecurseHierarchy = function ( root, hierarchy ) {\r\n\r\n\t\t\thierarchy.push( root );\r\n\r\n\t\t\tfor ( var c = 0; c < root.children.length; c ++ )\r\n\t\t\t\tparseRecurseHierarchy( root.children[ c ], hierarchy );\r\n\r\n\t\t};\r\n\r\n\t\t// setup hierarchy\r\n\r\n\t\tvar hierarchy = [];\r\n\r\n\t\tif ( root instanceof THREE.SkinnedMesh ) {\r\n\r\n\t\t\tfor ( var b = 0; b < root.skeleton.bones.length; b ++ ) {\r\n\r\n\t\t\t\thierarchy.push( root.skeleton.bones[ b ] );\r\n\r\n\t\t\t}\r\n\r\n\t\t} else {\r\n\r\n\t\t\tparseRecurseHierarchy( root, hierarchy );\r\n\r\n\t\t}\r\n\r\n\t\treturn hierarchy;\r\n\r\n\t},\r\n\r\n\tplay: function ( animation ) {\r\n\r\n\t\tif ( this.animations.indexOf( animation ) === - 1 ) {\r\n\r\n\t\t\tthis.animations.push( animation );\r\n\r\n\t\t}\r\n\r\n\t},\r\n\r\n\tstop: function ( animation ) {\r\n\r\n\t\tvar index = this.animations.indexOf( animation );\r\n\r\n\t\tif ( index !== - 1 ) {\r\n\r\n\t\t\tthis.animations.splice( index, 1 );\r\n\r\n\t\t}\r\n\r\n\t},\r\n\r\n\tupdate: function ( deltaTimeMS ) {\r\n\r\n\t\tfor ( var i = 0; i < this.animations.length; i ++ ) {\r\n\r\n\t\t\tthis.animations[ i ].resetBlendWeights( );\r\n\r\n\t\t}\r\n\r\n\t\tfor ( var i = 0; i < this.animations.length; i ++ ) {\r\n\r\n\t\t\tthis.animations[ i ].update( deltaTimeMS );\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/extras/animation/Animation.js\r\n\r\n/**\r\n * @author mikael emtinger / http://gomo.se/\r\n * @author mrdoob / http://mrdoob.com/\r\n * @author alteredq / http://alteredqualia.com/\r\n */\r\n\r\nTHREE.Animation = function ( root, data ) {\r\n\r\n\tthis.root = root;\r\n\tthis.data = THREE.AnimationHandler.init( data );\r\n\tthis.hierarchy = THREE.AnimationHandler.parse( root );\r\n\r\n\tthis.currentTime = 0;\r\n\tthis.timeScale = 1;\r\n\r\n\tthis.isPlaying = false;\r\n\tthis.loop = true;\r\n\tthis.weight = 0;\r\n\r\n\tthis.interpolationType = THREE.AnimationHandler.LINEAR;\r\n\r\n};\r\n\r\nTHREE.Animation.prototype = {\r\n\r\n\tconstructor: THREE.Animation,\r\n\r\n\tkeyTypes: [ \"pos\", \"rot\", \"scl\" ],\r\n\r\n\tplay: function ( startTime, weight ) {\r\n\r\n\t\tthis.currentTime = startTime !== undefined ? startTime : 0;\r\n\t\tthis.weight = weight !== undefined ? weight : 1;\r\n\r\n\t\tthis.isPlaying = true;\r\n\r\n\t\tthis.reset();\r\n\r\n\t\tTHREE.AnimationHandler.play( this );\r\n\r\n\t},\r\n\r\n\tstop: function() {\r\n\r\n\t\tthis.isPlaying = false;\r\n\r\n\t\tTHREE.AnimationHandler.stop( this );\r\n\r\n\t},\r\n\r\n\treset: function () {\r\n\r\n\t\tfor ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) {\r\n\r\n\t\t\tvar object = this.hierarchy[ h ];\r\n\r\n\t\t\tif ( object.animationCache === undefined ) {\r\n\r\n\t\t\t\tobject.animationCache = {\r\n\t\t\t\t\tanimations: {},\r\n\t\t\t\t\tblending: {\r\n\t\t\t\t\t\tpositionWeight: 0.0,\r\n\t\t\t\t\t\tquaternionWeight: 0.0,\r\n\t\t\t\t\t\tscaleWeight: 0.0\r\n\t\t\t\t\t}\r\n\t\t\t\t};\r\n\t\t\t}\r\n\r\n\t\t\tvar name = this.data.name;\r\n\t\t\tvar animations = object.animationCache.animations;\r\n\t\t\tvar animationCache = animations[ name ];\r\n\r\n\t\t\tif ( animationCache === undefined ) {\r\n\r\n\t\t\t\tanimationCache = {\r\n\t\t\t\t\tprevKey: { pos: 0, rot: 0, scl: 0 },\r\n\t\t\t\t\tnextKey: { pos: 0, rot: 0, scl: 0 },\r\n\t\t\t\t\toriginalMatrix: object.matrix\r\n\t\t\t\t};\r\n\r\n\t\t\t\tanimations[ name ] = animationCache;\r\n\r\n\t\t\t}\r\n\r\n\t\t\t// Get keys to match our current time\r\n\r\n\t\t\tfor ( var t = 0; t < 3; t ++ ) {\r\n\r\n\t\t\t\tvar type = this.keyTypes[ t ];\r\n\r\n\t\t\t\tvar prevKey = this.data.hierarchy[ h ].keys[ 0 ];\r\n\t\t\t\tvar nextKey = this.getNextKeyWith( type, h, 1 );\r\n\r\n\t\t\t\twhile ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) {\r\n\r\n\t\t\t\t\tprevKey = nextKey;\r\n\t\t\t\t\tnextKey = this.getNextKeyWith( type, h, nextKey.index + 1 );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tanimationCache.prevKey[ type ] = prevKey;\r\n\t\t\t\tanimationCache.nextKey[ type ] = nextKey;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t},\r\n\r\n\tresetBlendWeights: function () {\r\n\r\n\t\tfor ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) {\r\n\r\n\t\t\tvar object = this.hierarchy[ h ];\r\n\t\t\tvar animationCache = object.animationCache;\r\n\r\n\t\t\tif ( animationCache !== undefined ) {\r\n\r\n\t\t\t\tvar blending = animationCache.blending;\r\n\r\n\t\t\t\tblending.positionWeight = 0.0;\r\n\t\t\t\tblending.quaternionWeight = 0.0;\r\n\t\t\t\tblending.scaleWeight = 0.0;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t},\r\n\r\n\tupdate: ( function() {\r\n\r\n\t\tvar points = [];\r\n\t\tvar target = new THREE.Vector3();\r\n\t\tvar newVector = new THREE.Vector3();\r\n\t\tvar newQuat = new THREE.Quaternion();\r\n\r\n\t\t// Catmull-Rom spline\r\n\r\n\t\tvar interpolateCatmullRom = function ( points, scale ) {\r\n\r\n\t\t\tvar c = [], v3 = [],\r\n\t\t\tpoint, intPoint, weight, w2, w3,\r\n\t\t\tpa, pb, pc, pd;\r\n\r\n\t\t\tpoint = ( points.length - 1 ) * scale;\r\n\t\t\tintPoint = Math.floor( point );\r\n\t\t\tweight = point - intPoint;\r\n\r\n\t\t\tc[ 0 ] = intPoint === 0 ? intPoint : intPoint - 1;\r\n\t\t\tc[ 1 ] = intPoint;\r\n\t\t\tc[ 2 ] = intPoint > points.length - 2 ? intPoint : intPoint + 1;\r\n\t\t\tc[ 3 ] = intPoint > points.length - 3 ? intPoint : intPoint + 2;\r\n\r\n\t\t\tpa = points[ c[ 0 ] ];\r\n\t\t\tpb = points[ c[ 1 ] ];\r\n\t\t\tpc = points[ c[ 2 ] ];\r\n\t\t\tpd = points[ c[ 3 ] ];\r\n\r\n\t\t\tw2 = weight * weight;\r\n\t\t\tw3 = weight * w2;\r\n\r\n\t\t\tv3[ 0 ] = interpolate( pa[ 0 ], pb[ 0 ], pc[ 0 ], pd[ 0 ], weight, w2, w3 );\r\n\t\t\tv3[ 1 ] = interpolate( pa[ 1 ], pb[ 1 ], pc[ 1 ], pd[ 1 ], weight, w2, w3 );\r\n\t\t\tv3[ 2 ] = interpolate( pa[ 2 ], pb[ 2 ], pc[ 2 ], pd[ 2 ], weight, w2, w3 );\r\n\r\n\t\t\treturn v3;\r\n\r\n\t\t};\r\n\r\n\t\tvar interpolate = function ( p0, p1, p2, p3, t, t2, t3 ) {\r\n\r\n\t\t\tvar v0 = ( p2 - p0 ) * 0.5,\r\n\t\t\t\tv1 = ( p3 - p1 ) * 0.5;\r\n\r\n\t\t\treturn ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1;\r\n\r\n\t\t};\r\n\r\n\t\treturn function ( delta ) {\r\n\r\n\t\t\tif ( this.isPlaying === false ) return;\r\n\r\n\t\t\tthis.currentTime += delta * this.timeScale;\r\n\r\n\t\t\tif ( this.weight === 0 )\r\n\t\t\t\treturn;\r\n\r\n\t\t\t//\r\n\r\n\t\t\tvar duration = this.data.length;\r\n\r\n\t\t\tif ( this.currentTime > duration || this.currentTime < 0 ) {\r\n\r\n\t\t\t\tif ( this.loop ) {\r\n\r\n\t\t\t\t\tthis.currentTime %= duration;\r\n\r\n\t\t\t\t\tif ( this.currentTime < 0 )\r\n\t\t\t\t\t\tthis.currentTime += duration;\r\n\r\n\t\t\t\t\tthis.reset();\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\tthis.stop();\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\tfor ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) {\r\n\r\n\t\t\t\tvar object = this.hierarchy[ h ];\r\n\t\t\t\tvar animationCache = object.animationCache.animations[this.data.name];\r\n\t\t\t\tvar blending = object.animationCache.blending;\r\n\r\n\t\t\t\t// loop through pos/rot/scl\r\n\r\n\t\t\t\tfor ( var t = 0; t < 3; t ++ ) {\r\n\r\n\t\t\t\t\t// get keys\r\n\r\n\t\t\t\t\tvar type = this.keyTypes[ t ];\r\n\t\t\t\t\tvar prevKey = animationCache.prevKey[ type ];\r\n\t\t\t\t\tvar nextKey = animationCache.nextKey[ type ];\r\n\r\n\t\t\t\t\tif ( ( this.timeScale > 0 && nextKey.time <= this.currentTime ) ||\r\n\t\t\t\t\t\t( this.timeScale < 0 && prevKey.time >= this.currentTime ) ) {\r\n\r\n\t\t\t\t\t\tprevKey = this.data.hierarchy[ h ].keys[ 0 ];\r\n\t\t\t\t\t\tnextKey = this.getNextKeyWith( type, h, 1 );\r\n\r\n\t\t\t\t\t\twhile ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) {\r\n\r\n\t\t\t\t\t\t\tprevKey = nextKey;\r\n\t\t\t\t\t\t\tnextKey = this.getNextKeyWith( type, h, nextKey.index + 1 );\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tanimationCache.prevKey[ type ] = prevKey;\r\n\t\t\t\t\t\tanimationCache.nextKey[ type ] = nextKey;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tvar scale = ( this.currentTime - prevKey.time ) / ( nextKey.time - prevKey.time );\r\n\r\n\t\t\t\t\tvar prevXYZ = prevKey[ type ];\r\n\t\t\t\t\tvar nextXYZ = nextKey[ type ];\r\n\r\n\t\t\t\t\tif ( scale < 0 ) scale = 0;\r\n\t\t\t\t\tif ( scale > 1 ) scale = 1;\r\n\r\n\t\t\t\t\t// interpolate\r\n\r\n\t\t\t\t\tif ( type === \"pos\" ) {\r\n\r\n\t\t\t\t\t\tif ( this.interpolationType === THREE.AnimationHandler.LINEAR ) {\r\n\r\n\t\t\t\t\t\t\tnewVector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale;\r\n\t\t\t\t\t\t\tnewVector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale;\r\n\t\t\t\t\t\t\tnewVector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale;\r\n\r\n\t\t\t\t\t\t\t// blend\r\n\t\t\t\t\t\t\tvar proportionalWeight = this.weight / ( this.weight + blending.positionWeight );\r\n\t\t\t\t\t\t\tobject.position.lerp( newVector, proportionalWeight );\r\n\t\t\t\t\t\t\tblending.positionWeight += this.weight;\r\n\r\n\t\t\t\t\t\t} else if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM ||\r\n\t\t\t\t\t\t\t\t\tthis.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {\r\n\r\n\t\t\t\t\t\t\tpoints[ 0 ] = this.getPrevKeyWith( \"pos\", h, prevKey.index - 1 )[ \"pos\" ];\r\n\t\t\t\t\t\t\tpoints[ 1 ] = prevXYZ;\r\n\t\t\t\t\t\t\tpoints[ 2 ] = nextXYZ;\r\n\t\t\t\t\t\t\tpoints[ 3 ] = this.getNextKeyWith( \"pos\", h, nextKey.index + 1 )[ \"pos\" ];\r\n\r\n\t\t\t\t\t\t\tscale = scale * 0.33 + 0.33;\r\n\r\n\t\t\t\t\t\t\tvar currentPoint = interpolateCatmullRom( points, scale );\r\n\t\t\t\t\t\t\tvar proportionalWeight = this.weight / ( this.weight + blending.positionWeight );\r\n\t\t\t\t\t\t\tblending.positionWeight += this.weight;\r\n\r\n\t\t\t\t\t\t\t// blend\r\n\r\n\t\t\t\t\t\t\tvar vector = object.position;\r\n\r\n\t\t\t\t\t\t\tvector.x = vector.x + ( currentPoint[ 0 ] - vector.x ) * proportionalWeight;\r\n\t\t\t\t\t\t\tvector.y = vector.y + ( currentPoint[ 1 ] - vector.y ) * proportionalWeight;\r\n\t\t\t\t\t\t\tvector.z = vector.z + ( currentPoint[ 2 ] - vector.z ) * proportionalWeight;\r\n\r\n\t\t\t\t\t\t\tif ( this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {\r\n\r\n\t\t\t\t\t\t\t\tvar forwardPoint = interpolateCatmullRom( points, scale * 1.01 );\r\n\r\n\t\t\t\t\t\t\t\ttarget.set( forwardPoint[ 0 ], forwardPoint[ 1 ], forwardPoint[ 2 ] );\r\n\t\t\t\t\t\t\t\ttarget.sub( vector );\r\n\t\t\t\t\t\t\t\ttarget.y = 0;\r\n\t\t\t\t\t\t\t\ttarget.normalize();\r\n\r\n\t\t\t\t\t\t\t\tvar angle = Math.atan2( target.x, target.z );\r\n\t\t\t\t\t\t\t\tobject.rotation.set( 0, angle, 0 );\r\n\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t} else if ( type === \"rot\" ) {\r\n\r\n\t\t\t\t\t\tTHREE.Quaternion.slerp( prevXYZ, nextXYZ, newQuat, scale );\r\n\r\n\t\t\t\t\t\t// Avoid paying the cost of an additional slerp if we don't have to\r\n\t\t\t\t\t\tif ( blending.quaternionWeight === 0 ) {\r\n\r\n\t\t\t\t\t\t\tobject.quaternion.copy(newQuat);\r\n\t\t\t\t\t\t\tblending.quaternionWeight = this.weight;\r\n\r\n\t\t\t\t\t\t} else {\r\n\r\n\t\t\t\t\t\t\tvar proportionalWeight = this.weight / ( this.weight + blending.quaternionWeight );\r\n\t\t\t\t\t\t\tTHREE.Quaternion.slerp( object.quaternion, newQuat, object.quaternion, proportionalWeight );\r\n\t\t\t\t\t\t\tblending.quaternionWeight += this.weight;\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t} else if ( type === \"scl\" ) {\r\n\r\n\t\t\t\t\t\tnewVector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale;\r\n\t\t\t\t\t\tnewVector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale;\r\n\t\t\t\t\t\tnewVector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale;\r\n\r\n\t\t\t\t\t\tvar proportionalWeight = this.weight / ( this.weight + blending.scaleWeight );\r\n\t\t\t\t\t\tobject.scale.lerp( newVector, proportionalWeight );\r\n\t\t\t\t\t\tblending.scaleWeight += this.weight;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\treturn true;\r\n\r\n\t\t};\r\n\r\n\t} )(),\r\n\r\n\tgetNextKeyWith: function ( type, h, key ) {\r\n\r\n\t\tvar keys = this.data.hierarchy[ h ].keys;\r\n\r\n\t\tif ( this.interpolationType === THREE.AnimationHandler.CATMULLROM ||\r\n\t\t\t this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {\r\n\r\n\t\t\tkey = key < keys.length - 1 ? key : keys.length - 1;\r\n\r\n\t\t} else {\r\n\r\n\t\t\tkey = key % keys.length;\r\n\r\n\t\t}\r\n\r\n\t\tfor ( ; key < keys.length; key ++ ) {\r\n\r\n\t\t\tif ( keys[ key ][ type ] !== undefined ) {\r\n\r\n\t\t\t\treturn keys[ key ];\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\treturn this.data.hierarchy[ h ].keys[ 0 ];\r\n\r\n\t},\r\n\r\n\tgetPrevKeyWith: function ( type, h, key ) {\r\n\r\n\t\tvar keys = this.data.hierarchy[ h ].keys;\r\n\r\n\t\tif ( this.interpolationType === THREE.AnimationHandler.CATMULLROM ||\r\n\t\t\tthis.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {\r\n\r\n\t\t\tkey = key > 0 ? key : 0;\r\n\r\n\t\t} else {\r\n\r\n\t\t\tkey = key >= 0 ? key : key + keys.length;\r\n\r\n\t\t}\r\n\r\n\r\n\t\tfor ( ; key >= 0; key -- ) {\r\n\r\n\t\t\tif ( keys[ key ][ type ] !== undefined ) {\r\n\r\n\t\t\t\treturn keys[ key ];\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\treturn this.data.hierarchy[ h ].keys[ keys.length - 1 ];\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/extras/animation/KeyFrameAnimation.js\r\n\r\n/**\r\n * @author mikael emtinger / http://gomo.se/\r\n * @author mrdoob / http://mrdoob.com/\r\n * @author alteredq / http://alteredqualia.com/\r\n * @author khang duong\r\n * @author erik kitson\r\n */\r\n\r\nTHREE.KeyFrameAnimation = function ( data ) {\r\n\r\n\tthis.root = data.node;\r\n\tthis.data = THREE.AnimationHandler.init( data );\r\n\tthis.hierarchy = THREE.AnimationHandler.parse( this.root );\r\n\tthis.currentTime = 0;\r\n\tthis.timeScale = 0.001;\r\n\tthis.isPlaying = false;\r\n\tthis.isPaused = true;\r\n\tthis.loop = true;\r\n\r\n\t// initialize to first keyframes\r\n\r\n\tfor ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) {\r\n\r\n\t\tvar keys = this.data.hierarchy[h].keys,\r\n\t\t\tsids = this.data.hierarchy[h].sids,\r\n\t\t\tobj = this.hierarchy[h];\r\n\r\n\t\tif ( keys.length && sids ) {\r\n\r\n\t\t\tfor ( var s = 0; s < sids.length; s ++ ) {\r\n\r\n\t\t\t\tvar sid = sids[ s ],\r\n\t\t\t\t\tnext = this.getNextKeyWith( sid, h, 0 );\r\n\r\n\t\t\t\tif ( next ) {\r\n\r\n\t\t\t\t\tnext.apply( sid );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\tobj.matrixAutoUpdate = false;\r\n\t\t\tthis.data.hierarchy[h].node.updateMatrix();\r\n\t\t\tobj.matrixWorldNeedsUpdate = true;\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n};\r\n\r\nTHREE.KeyFrameAnimation.prototype = {\r\n\r\n\tconstructor: THREE.KeyFrameAnimation,\r\n\r\n\tplay: function ( startTime ) {\r\n\r\n\t\tthis.currentTime = startTime !== undefined ? startTime : 0;\r\n\r\n\t\tif ( this.isPlaying === false ) {\r\n\r\n\t\t\tthis.isPlaying = true;\r\n\r\n\t\t\t// reset key cache\r\n\r\n\t\t\tvar h, hl = this.hierarchy.length,\r\n\t\t\t\tobject,\r\n\t\t\t\tnode;\r\n\r\n\t\t\tfor ( h = 0; h < hl; h ++ ) {\r\n\r\n\t\t\t\tobject = this.hierarchy[ h ];\r\n\t\t\t\tnode = this.data.hierarchy[ h ];\r\n\r\n\t\t\t\tif ( node.animationCache === undefined ) {\r\n\r\n\t\t\t\t\tnode.animationCache = {};\r\n\t\t\t\t\tnode.animationCache.prevKey = null;\r\n\t\t\t\t\tnode.animationCache.nextKey = null;\r\n\t\t\t\t\tnode.animationCache.originalMatrix = object.matrix;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvar keys = this.data.hierarchy[h].keys;\r\n\r\n\t\t\t\tif (keys.length) {\r\n\r\n\t\t\t\t\tnode.animationCache.prevKey = keys[ 0 ];\r\n\t\t\t\t\tnode.animationCache.nextKey = keys[ 1 ];\r\n\r\n\t\t\t\t\tthis.startTime = Math.min( keys[0].time, this.startTime );\r\n\t\t\t\t\tthis.endTime = Math.max( keys[keys.length - 1].time, this.endTime );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\tthis.update( 0 );\r\n\r\n\t\t}\r\n\r\n\t\tthis.isPaused = false;\r\n\r\n\t\tTHREE.AnimationHandler.play( this );\r\n\r\n\t},\r\n\r\n\tstop: function () {\r\n\r\n\t\tthis.isPlaying = false;\r\n\t\tthis.isPaused = false;\r\n\r\n\t\tTHREE.AnimationHandler.stop( this );\r\n\r\n\t\t// reset JIT matrix and remove cache\r\n\r\n\t\tfor ( var h = 0; h < this.data.hierarchy.length; h ++ ) {\r\n\r\n\t\t\tvar obj = this.hierarchy[ h ];\r\n\t\t\tvar node = this.data.hierarchy[ h ];\r\n\r\n\t\t\tif ( node.animationCache !== undefined ) {\r\n\r\n\t\t\t\tvar original = node.animationCache.originalMatrix;\r\n\r\n\t\t\t\toriginal.copy( obj.matrix );\r\n\t\t\t\tobj.matrix = original;\r\n\r\n\t\t\t\tdelete node.animationCache;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t},\r\n\r\n\tupdate: function ( delta ) {\r\n\r\n\t\tif ( this.isPlaying === false ) return;\r\n\r\n\t\tthis.currentTime += delta * this.timeScale;\r\n\r\n\t\t//\r\n\r\n\t\tvar duration = this.data.length;\r\n\r\n\t\tif ( this.loop === true && this.currentTime > duration ) {\r\n\r\n\t\t\tthis.currentTime %= duration;\r\n\r\n\t\t}\r\n\r\n\t\tthis.currentTime = Math.min( this.currentTime, duration );\r\n\r\n\t\tfor ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) {\r\n\r\n\t\t\tvar object = this.hierarchy[ h ];\r\n\t\t\tvar node = this.data.hierarchy[ h ];\r\n\r\n\t\t\tvar keys = node.keys,\r\n\t\t\t\tanimationCache = node.animationCache;\r\n\r\n\r\n\t\t\tif ( keys.length ) {\r\n\r\n\t\t\t\tvar prevKey = animationCache.prevKey;\r\n\t\t\t\tvar nextKey = animationCache.nextKey;\r\n\r\n\t\t\t\tif ( nextKey.time <= this.currentTime ) {\r\n\r\n\t\t\t\t\twhile ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) {\r\n\r\n\t\t\t\t\t\tprevKey = nextKey;\r\n\t\t\t\t\t\tnextKey = keys[ prevKey.index + 1 ];\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tanimationCache.prevKey = prevKey;\r\n\t\t\t\t\tanimationCache.nextKey = nextKey;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif ( nextKey.time >= this.currentTime ) {\r\n\r\n\t\t\t\t\tprevKey.interpolate( nextKey, this.currentTime );\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\tprevKey.interpolate( nextKey, nextKey.time );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tthis.data.hierarchy[ h ].node.updateMatrix();\r\n\t\t\t\tobject.matrixWorldNeedsUpdate = true;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t},\r\n\r\n\tgetNextKeyWith: function ( sid, h, key ) {\r\n\r\n\t\tvar keys = this.data.hierarchy[ h ].keys;\r\n\t\tkey = key % keys.length;\r\n\r\n\t\tfor ( ; key < keys.length; key ++ ) {\r\n\r\n\t\t\tif ( keys[ key ].hasTarget( sid ) ) {\r\n\r\n\t\t\t\treturn keys[ key ];\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\treturn keys[ 0 ];\r\n\r\n\t},\r\n\r\n\tgetPrevKeyWith: function ( sid, h, key ) {\r\n\r\n\t\tvar keys = this.data.hierarchy[ h ].keys;\r\n\t\tkey = key >= 0 ? key : key + keys.length;\r\n\r\n\t\tfor ( ; key >= 0; key -- ) {\r\n\r\n\t\t\tif ( keys[ key ].hasTarget( sid ) ) {\r\n\r\n\t\t\t\treturn keys[ key ];\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\treturn keys[ keys.length - 1 ];\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/extras/animation/MorphAnimation.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com\r\n * @author willy-vvu / http://willy-vvu.github.io\r\n */\r\n\r\nTHREE.MorphAnimation = function ( mesh ) {\r\n\r\n\tthis.mesh = mesh;\r\n\tthis.frames = mesh.morphTargetInfluences.length;\r\n\tthis.currentTime = 0;\r\n\tthis.duration = 1000;\r\n\tthis.loop = true;\r\n\tthis.lastFrame = 0;\r\n\tthis.currentFrame = 0;\r\n\r\n\tthis.isPlaying = false;\r\n\r\n};\r\n\r\nTHREE.MorphAnimation.prototype = {\r\n\r\n\tconstructor: THREE.MorphAnimation,\r\n\r\n\tplay: function () {\r\n\r\n\t\tthis.isPlaying = true;\r\n\r\n\t},\r\n\r\n\tpause: function () {\r\n\r\n\t\tthis.isPlaying = false;\r\n\r\n\t},\r\n\r\n\tupdate: function ( delta ) {\r\n\r\n\t\tif ( this.isPlaying === false ) return;\r\n\r\n\t\tthis.currentTime += delta;\r\n\r\n\t\tif ( this.loop === true && this.currentTime > this.duration ) {\r\n\r\n\t\t\tthis.currentTime %= this.duration;\r\n\r\n\t\t}\r\n\r\n\t\tthis.currentTime = Math.min( this.currentTime, this.duration );\r\n\r\n\t\tvar interpolation = this.duration / this.frames;\r\n\t\tvar frame = Math.floor( this.currentTime / interpolation );\r\n\r\n\t\tvar influences = this.mesh.morphTargetInfluences;\r\n\r\n\t\tif ( frame != this.currentFrame ) {\r\n\r\n\t\t\tinfluences[ this.lastFrame ] = 0;\r\n\t\t\tinfluences[ this.currentFrame ] = 1;\r\n\t\t\tinfluences[ frame ] = 0;\r\n\r\n\t\t\tthis.lastFrame = this.currentFrame;\r\n\t\t\tthis.currentFrame = frame;\r\n\r\n\t\t}\r\n\r\n\t\tinfluences[ frame ] = ( this.currentTime % interpolation ) / interpolation;\r\n\t\tinfluences[ this.lastFrame ] = 1 - influences[ frame ];\r\n\r\n\t}\r\n\r\n};\r\n\r\n// File:src/extras/geometries/BoxGeometry.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Cube.as\r\n */\r\n\r\nTHREE.BoxGeometry = function ( width, height, depth, widthSegments, heightSegments, depthSegments ) {\r\n\r\n\tTHREE.Geometry.call( this );\r\n\r\n\tthis.type = 'BoxGeometry';\r\n\r\n\tthis.parameters = {\r\n\t\twidth: width,\r\n\t\theight: height,\r\n\t\tdepth: depth,\r\n\t\twidthSegments: widthSegments,\r\n\t\theightSegments: heightSegments,\r\n\t\tdepthSegments: depthSegments\r\n\t};\r\n\r\n\tthis.widthSegments = widthSegments || 1;\r\n\tthis.heightSegments = heightSegments || 1;\r\n\tthis.depthSegments = depthSegments || 1;\r\n\r\n\tvar scope = this;\r\n\r\n\tvar width_half = width / 2;\r\n\tvar height_half = height / 2;\r\n\tvar depth_half = depth / 2;\r\n\r\n\tbuildPlane( 'z', 'y', - 1, - 1, depth, height, width_half, 0 ); // px\r\n\tbuildPlane( 'z', 'y', 1, - 1, depth, height, - width_half, 1 ); // nx\r\n\tbuildPlane( 'x', 'z', 1, 1, width, depth, height_half, 2 ); // py\r\n\tbuildPlane( 'x', 'z', 1, - 1, width, depth, - height_half, 3 ); // ny\r\n\tbuildPlane( 'x', 'y', 1, - 1, width, height, depth_half, 4 ); // pz\r\n\tbuildPlane( 'x', 'y', - 1, - 1, width, height, - depth_half, 5 ); // nz\r\n\r\n\tfunction buildPlane( u, v, udir, vdir, width, height, depth, materialIndex ) {\r\n\r\n\t\tvar w, ix, iy,\r\n\t\tgridX = scope.widthSegments,\r\n\t\tgridY = scope.heightSegments,\r\n\t\twidth_half = width / 2,\r\n\t\theight_half = height / 2,\r\n\t\toffset = scope.vertices.length;\r\n\r\n\t\tif ( ( u === 'x' && v === 'y' ) || ( u === 'y' && v === 'x' ) ) {\r\n\r\n\t\t\tw = 'z';\r\n\r\n\t\t} else if ( ( u === 'x' && v === 'z' ) || ( u === 'z' && v === 'x' ) ) {\r\n\r\n\t\t\tw = 'y';\r\n\t\t\tgridY = scope.depthSegments;\r\n\r\n\t\t} else if ( ( u === 'z' && v === 'y' ) || ( u === 'y' && v === 'z' ) ) {\r\n\r\n\t\t\tw = 'x';\r\n\t\t\tgridX = scope.depthSegments;\r\n\r\n\t\t}\r\n\r\n\t\tvar gridX1 = gridX + 1,\r\n\t\tgridY1 = gridY + 1,\r\n\t\tsegment_width = width / gridX,\r\n\t\tsegment_height = height / gridY,\r\n\t\tnormal = new THREE.Vector3();\r\n\r\n\t\tnormal[ w ] = depth > 0 ? 1 : - 1;\r\n\r\n\t\tfor ( iy = 0; iy < gridY1; iy ++ ) {\r\n\r\n\t\t\tfor ( ix = 0; ix < gridX1; ix ++ ) {\r\n\r\n\t\t\t\tvar vector = new THREE.Vector3();\r\n\t\t\t\tvector[ u ] = ( ix * segment_width - width_half ) * udir;\r\n\t\t\t\tvector[ v ] = ( iy * segment_height - height_half ) * vdir;\r\n\t\t\t\tvector[ w ] = depth;\r\n\r\n\t\t\t\tscope.vertices.push( vector );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tfor ( iy = 0; iy < gridY; iy ++ ) {\r\n\r\n\t\t\tfor ( ix = 0; ix < gridX; ix ++ ) {\r\n\r\n\t\t\t\tvar a = ix + gridX1 * iy;\r\n\t\t\t\tvar b = ix + gridX1 * ( iy + 1 );\r\n\t\t\t\tvar c = ( ix + 1 ) + gridX1 * ( iy + 1 );\r\n\t\t\t\tvar d = ( ix + 1 ) + gridX1 * iy;\r\n\r\n\t\t\t\tvar uva = new THREE.Vector2( ix / gridX, 1 - iy / gridY );\r\n\t\t\t\tvar uvb = new THREE.Vector2( ix / gridX, 1 - ( iy + 1 ) / gridY );\r\n\t\t\t\tvar uvc = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - ( iy + 1 ) / gridY );\r\n\t\t\t\tvar uvd = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - iy / gridY );\r\n\r\n\t\t\t\tvar face = new THREE.Face3( a + offset, b + offset, d + offset );\r\n\t\t\t\tface.normal.copy( normal );\r\n\t\t\t\tface.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() );\r\n\t\t\t\tface.materialIndex = materialIndex;\r\n\r\n\t\t\t\tscope.faces.push( face );\r\n\t\t\t\tscope.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] );\r\n\r\n\t\t\t\tface = new THREE.Face3( b + offset, c + offset, d + offset );\r\n\t\t\t\tface.normal.copy( normal );\r\n\t\t\t\tface.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() );\r\n\t\t\t\tface.materialIndex = materialIndex;\r\n\r\n\t\t\t\tscope.faces.push( face );\r\n\t\t\t\tscope.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tthis.mergeVertices();\r\n\r\n};\r\n\r\nTHREE.BoxGeometry.prototype = Object.create( THREE.Geometry.prototype );\r\nTHREE.BoxGeometry.prototype.constructor = THREE.BoxGeometry;\r\n\r\n// File:src/extras/geometries/CircleGeometry.js\r\n\r\n/**\r\n * @author hughes\r\n */\r\n\r\nTHREE.CircleGeometry = function ( radius, segments, thetaStart, thetaLength ) {\r\n\r\n\tTHREE.Geometry.call( this );\r\n\r\n\tthis.type = 'CircleGeometry';\r\n\r\n\tthis.parameters = {\r\n\t\tradius: radius,\r\n\t\tsegments: segments,\r\n\t\tthetaStart: thetaStart,\r\n\t\tthetaLength: thetaLength\r\n\t};\r\n\r\n\tradius = radius || 50;\r\n\tsegments = segments !== undefined ? Math.max( 3, segments ) : 8;\r\n\r\n\tthetaStart = thetaStart !== undefined ? thetaStart : 0;\r\n\tthetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;\r\n\r\n\tvar i, uvs = [],\r\n\tcenter = new THREE.Vector3(), centerUV = new THREE.Vector2( 0.5, 0.5 );\r\n\r\n\tthis.vertices.push(center);\r\n\tuvs.push( centerUV );\r\n\r\n\tfor ( i = 0; i <= segments; i ++ ) {\r\n\r\n\t\tvar vertex = new THREE.Vector3();\r\n\t\tvar segment = thetaStart + i / segments * thetaLength;\r\n\r\n\t\tvertex.x = radius * Math.cos( segment );\r\n\t\tvertex.y = radius * Math.sin( segment );\r\n\r\n\t\tthis.vertices.push( vertex );\r\n\t\tuvs.push( new THREE.Vector2( ( vertex.x / radius + 1 ) / 2, ( vertex.y / radius + 1 ) / 2 ) );\r\n\r\n\t}\r\n\r\n\tvar n = new THREE.Vector3( 0, 0, 1 );\r\n\r\n\tfor ( i = 1; i <= segments; i ++ ) {\r\n\r\n\t\tthis.faces.push( new THREE.Face3( i, i + 1, 0, [ n.clone(), n.clone(), n.clone() ] ) );\r\n\t\tthis.faceVertexUvs[ 0 ].push( [ uvs[ i ].clone(), uvs[ i + 1 ].clone(), centerUV.clone() ] );\r\n\r\n\t}\r\n\r\n\tthis.computeFaceNormals();\r\n\r\n\tthis.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius );\r\n\r\n};\r\n\r\nTHREE.CircleGeometry.prototype = Object.create( THREE.Geometry.prototype );\r\nTHREE.CircleGeometry.prototype.constructor = THREE.CircleGeometry;\r\n\r\n// File:src/extras/geometries/CubeGeometry.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n */\r\n\r\n\r\nTHREE.CubeGeometry = function ( width, height, depth, widthSegments, heightSegments, depthSegments ) {\r\n\r\n\tTHREE.warn( 'THREE.CubeGeometry has been renamed to THREE.BoxGeometry.' );\r\n\treturn new THREE.BoxGeometry( width, height, depth, widthSegments, heightSegments, depthSegments );\r\n\r\n };\r\n\r\n// File:src/extras/geometries/CylinderGeometry.js\r\n\r\n/**\r\n * @author mrdoob / http://mrdoob.com/\r\n */\r\n\r\nTHREE.CylinderGeometry = function ( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {\r\n\r\n\tTHREE.Geometry.call( this );\r\n\r\n\tthis.type = 'CylinderGeometry';\r\n\r\n\tthis.parameters = {\r\n\t\tradiusTop: radiusTop,\r\n\t\tradiusBottom: radiusBottom,\r\n\t\theight: height,\r\n\t\tradialSegments: radialSegments,\r\n\t\theightSegments: heightSegments,\r\n\t\topenEnded: openEnded,\r\n\t\tthetaStart: thetaStart,\r\n\t\tthetaLength: thetaLength\r\n\t};\r\n\r\n\tradiusTop = radiusTop !== undefined ? radiusTop : 20;\r\n\tradiusBottom = radiusBottom !== undefined ? radiusBottom : 20;\r\n\theight = height !== undefined ? height : 100;\r\n\r\n\tradialSegments = radialSegments || 8;\r\n\theightSegments = heightSegments || 1;\r\n\r\n\topenEnded = openEnded !== undefined ? openEnded : false;\r\n\tthetaStart = thetaStart !== undefined ? thetaStart : 0;\r\n\tthetaLength = thetaLength !== undefined ? thetaLength : 2 * Math.PI;\r\n\r\n\tvar heightHalf = height / 2;\r\n\r\n\tvar x, y, vertices = [], uvs = [];\r\n\r\n\tfor ( y = 0; y <= heightSegments; y ++ ) {\r\n\r\n\t\tvar verticesRow = [];\r\n\t\tvar uvsRow = [];\r\n\r\n\t\tvar v = y / heightSegments;\r\n\t\tvar radius = v * ( radiusBottom - radiusTop ) + radiusTop;\r\n\r\n\t\tfor ( x = 0; x <= radialSegments; x ++ ) {\r\n\r\n\t\t\tvar u = x / radialSegments;\r\n\r\n\t\t\tvar vertex = new THREE.Vector3();\r\n\t\t\tvertex.x = radius * Math.sin( u * thetaLength + thetaStart );\r\n\t\t\tvertex.y = - v * height + heightHalf;\r\n\t\t\tvertex.z = radius * Math.cos( u * thetaLength + thetaStart );\r\n\r\n\t\t\tthis.vertices.push( vertex );\r\n\r\n\t\t\tverticesRow.push( this.vertices.length - 1 );\r\n\t\t\tuvsRow.push( new THREE.Vector2( u, 1 - v ) );\r\n\r\n\t\t}\r\n\r\n\t\tvertices.push( verticesRow );\r\n\t\tuvs.push( uvsRow );\r\n\r\n\t}\r\n\r\n\tvar tanTheta = ( radiusBottom - radiusTop ) / height;\r\n\tvar na, nb;\r\n\r\n\tfor ( x = 0; x < radialSegments; x ++ ) {\r\n\r\n\t\tif ( radiusTop !== 0 ) {\r\n\r\n\t\t\tna = this.vertices[ vertices[ 0 ][ x ] ].clone();\r\n\t\t\tnb = this.vertices[ vertices[ 0 ][ x + 1 ] ].clone();\r\n\r\n\t\t} else {\r\n\r\n\t\t\tna = this.vertices[ vertices[ 1 ][ x ] ].clone();\r\n\t\t\tnb = this.vertices[ vertices[ 1 ][ x + 1 ] ].clone();\r\n\r\n\t\t}\r\n\r\n\t\tna.setY( Math.sqrt( na.x * na.x + na.z * na.z ) * tanTheta ).normalize();\r\n\t\tnb.setY( Math.sqrt( nb.x * nb.x + nb.z * nb.z ) * tanTheta ).normalize();\r\n\r\n\t\tfor ( y = 0; y < heightSegments; y ++ ) {\r\n\r\n\t\t\tvar v1 = vertices[ y ][ x ];\r\n\t\t\tvar v2 = vertices[ y + 1 ][ x ];\r\n\t\t\tvar v3 = vertices[ y + 1 ][ x + 1 ];\r\n\t\t\tvar v4 = vertices[ y ][ x + 1 ];\r\n\r\n\t\t\tvar n1 = na.clone();\r\n\t\t\tvar n2 = na.clone();\r\n\t\t\tvar n3 = nb.clone();\r\n\t\t\tvar n4 = nb.clone();\r\n\r\n\t\t\tvar uv1 = uvs[ y ][ x ].clone();\r\n\t\t\tvar uv2 = uvs[ y + 1 ][ x ].clone();\r\n\t\t\tvar uv3 = uvs[ y + 1 ][ x + 1 ].clone();\r\n\t\t\tvar uv4 = uvs[ y ][ x + 1 ].clone();\r\n\r\n\t\t\tthis.faces.push( new THREE.Face3( v1, v2, v4, [ n1, n2, n4 ] ) );\r\n\t\t\tthis.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv4 ] );\r\n\r\n\t\t\tthis.faces.push( new THREE.Face3( v2, v3, v4, [ n2.clone(), n3, n4.clone() ] ) );\r\n\t\t\tthis.faceVertexUvs[ 0 ].push( [ uv2.clone(), uv3, uv4.clone() ] );\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t// top cap\r\n\r\n\tif ( openEnded === false && radiusTop > 0 ) {\r\n\r\n\t\tthis.vertices.push( new THREE.Vector3( 0, heightHalf, 0 ) );\r\n\r\n\t\tfor ( x = 0; x < radialSegments; x ++ ) {\r\n\r\n\t\t\tvar v1 = vertices[ 0 ][ x ];\r\n\t\t\tvar v2 = vertices[ 0 ][ x + 1 ];\r\n\t\t\tvar v3 = this.vertices.length - 1;\r\n\r\n\t\t\tvar n1 = new THREE.Vector3( 0, 1, 0 );\r\n\t\t\tvar n2 = new THREE.Vector3( 0, 1, 0 );\r\n\t\t\tvar n3 = new THREE.Vector3( 0, 1, 0 );\r\n\r\n\t\t\tvar uv1 = uvs[ 0 ][ x ].clone();\r\n\t\t\tvar uv2 = uvs[ 0 ][ x + 1 ].clone();\r\n\t\t\tvar uv3 = new THREE.Vector2( uv2.x, 0 );\r\n\r\n\t\t\tthis.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) );\r\n\t\t\tthis.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] );\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t// bottom cap\r\n\r\n\tif ( openEnded === false && radiusBottom > 0 ) {\r\n\r\n\t\tthis.vertices.push( new THREE.Vector3( 0, - heightHalf, 0 ) );\r\n\r\n\t\tfor ( x = 0; x < radialSegments; x ++ ) {\r\n\r\n\t\t\tvar v1 = vertices[ heightSegments ][ x + 1 ];\r\n\t\t\tvar v2 = vertices[ heightSegments ][ x ];\r\n\t\t\tvar v3 = this.vertices.length - 1;\r\n\r\n\t\t\tvar n1 = new THREE.Vector3( 0, - 1, 0 );\r\n\t\t\tvar n2 = new THREE.Vector3( 0, - 1, 0 );\r\n\t\t\tvar n3 = new THREE.Vector3( 0, - 1, 0 );\r\n\r\n\t\t\tvar uv1 = uvs[ heightSegments ][ x + 1 ].clone();\r\n\t\t\tvar uv2 = uvs[ heightSegments ][ x ].clone();\r\n\t\t\tvar uv3 = new THREE.Vector2( uv2.x, 1 );\r\n\r\n\t\t\tthis.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) );\r\n\t\t\tthis.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] );\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tthis.computeFaceNormals();\r\n\r\n};\r\n\r\nTHREE.CylinderGeometry.prototype = Object.create( THREE.Geometry.prototype );\r\nTHREE.CylinderGeometry.prototype.constructor = THREE.CylinderGeometry;\r\n\r\n// File:src/extras/geometries/ExtrudeGeometry.js\r\n\r\n/**\r\n * @author zz85 / http://www.lab4games.net/zz85/blog\r\n *\r\n * Creates extruded geometry from a path shape.\r\n *\r\n * parameters = {\r\n *\r\n * curveSegments: , // number of points on the curves\r\n * steps: , // number of points for z-side extrusions / used for subdividing segements of extrude spline too\r\n * amount: , // Depth to extrude the shape\r\n *\r\n * bevelEnabled: , // turn on bevel\r\n * bevelThickness: , // how deep into the original shape bevel goes\r\n * bevelSize: , // how far from shape outline is bevel\r\n * bevelSegments: , // number of bevel layers\r\n *\r\n * extrudePath: // 3d spline path to extrude shape along. (creates Frames if .frames aren't defined)\r\n * frames: // containing arrays of tangents, normals, binormals\r\n *\r\n * material: // material index for front and back faces\r\n * extrudeMaterial: // material index for extrusion and beveled faces\r\n * uvGenerator: