diff --git a/ALVARIZA-BILLAR/img.jpg b/ALVARIZA-BILLAR/img.jpg deleted file mode 100644 index d642e136257de4fb317a18f7c422126216665b16..0000000000000000000000000000000000000000 Binary files a/ALVARIZA-BILLAR/img.jpg and /dev/null differ diff --git a/ALVARIZA-BILLAR/index.html b/ALVARIZA-BILLAR/index.html deleted file mode 100644 index 76e27dc119783f47da855d49712c43bab0798e9a..0000000000000000000000000000000000000000 --- a/ALVARIZA-BILLAR/index.html +++ /dev/null @@ -1 +0,0 @@ -Le travail n'a pas encore commencé!!! \ No newline at end of file diff --git a/ALVARIZA-BILLAR_DESERT_KANY/Hopper-Gas.png b/ALVARIZA-BILLAR_DESERT_KANY/Hopper-Gas.png new file mode 100644 index 0000000000000000000000000000000000000000..a6299857e51d075f1af3e2ffb7207f577d5eeb50 Binary files /dev/null and b/ALVARIZA-BILLAR_DESERT_KANY/Hopper-Gas.png differ diff --git a/ALVARIZA-BILLAR_DESERT_KANY/checklistProjet.md b/ALVARIZA-BILLAR_DESERT_KANY/checklistProjet.md new file mode 100644 index 0000000000000000000000000000000000000000..9e90e5bc378d681035ffdc095f6996ad75bedfaf --- /dev/null +++ b/ALVARIZA-BILLAR_DESERT_KANY/checklistProjet.md @@ -0,0 +1,20 @@ +- [ ] Esthetisme +- [ ] Mise en page de la page web +- [ ] Paragraphe(s) d'explications techniques +- [ ] Légèreté du dossier (<2Mo) +- [ ] Géométrie +- [ ] Couleur +- [ ] Transparence +- [ ] Eclairage +- [ ] Ombres portées +- [ ] Position de la caméra +- [ ] Brouillard +- [ ] Effet miroir +- [ ] Texture classique +- [ ] Texture avec transparence +- [ ] Sprites +- [ ] Environment map +- [ ] Skybox +- [ ] Animations +- [ ] normal maps +- [ ] Interaction par GUI \ No newline at end of file diff --git a/ALVARIZA-BILLAR_DESERT_KANY/credits.md b/ALVARIZA-BILLAR_DESERT_KANY/credits.md new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/ALVARIZA-BILLAR_DESERT_KANY/index.html b/ALVARIZA-BILLAR_DESERT_KANY/index.html new file mode 100644 index 0000000000000000000000000000000000000000..993035b56f18e6334d0f2aad8faed83ead8dad22 --- /dev/null +++ b/ALVARIZA-BILLAR_DESERT_KANY/index.html @@ -0,0 +1,43 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="UTF-8"> + <title>projet</title> + <style> + body { + margin: 0; + } + + canvas { + width: 100%; + height: 100% + } + + .centre { + text-align: center; + } + </style> +</head> +<body> +<!-- API importe du site de Three.js --> +<script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims +.js"></script> +<script type="importmap"> + { + "imports": { + "three": "https://threejs.org/build/three.module.js", + "three/addons/": "https://threejs.org/examples/jsm/" + } + } +</script> +<!-- JQuery pour afficher les erreurs --> +<script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.min.js +"></script> +<!-- Un titre centre --> +<h1 class="centre"> projet</h1> +<div id="webGL" class="centre"></div> +<!-- Mon script avec un chemin relatif --> +<script type="module" src="projet.js"></script> +<p class="centre"> projet </p> +</body> +</html> \ No newline at end of file diff --git a/ALVARIZA-BILLAR_DESERT_KANY/projet.js b/ALVARIZA-BILLAR_DESERT_KANY/projet.js new file mode 100644 index 0000000000000000000000000000000000000000..d0e25baee3fb05acd4eeeee6fffa5afbc61cb8e2 --- /dev/null +++ b/ALVARIZA-BILLAR_DESERT_KANY/projet.js @@ -0,0 +1,152 @@ +"use strict"; // good practice - see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode +//////////////////////////////////////////////////////////////////////////////// +// Add a grassy plain underneath the drinking bird +//////////////////////////////////////////////////////////////////////////////// +/*global THREE, $ */ +import * as THREE from 'three'; + +import {OBJLoader} from 'three/addons/loaders/OBJLoader.js'; +import {OrbitControls} from 'three/addons/controls/OrbitControls.js'; +import {dat} from './lib/dat.gui.min.js'; +import {Coordinates} from './lib/Coordinates.js'; +import { MTLLoader } from 'three/addons/loaders/MTLLoader.js'; + +window.scene = new THREE.Scene(); + +var camera, renderer; +var cameraControls; +var bevelRadius = 1.9; +var clock = new THREE.Clock(); +var cylinder,sphere,cube; + +function fillScene() { + scene = new THREE.Scene(); + + + // LIGHTS + scene.add( new THREE.AmbientLight( 0x222222 ) ); + var light = new THREE.DirectionalLight( 0xFFFFFF, 0.9); + light.position.set( 200, 500, 500 ); + scene.add( light ); + light = new THREE.DirectionalLight( 0xFFFFFF, 100000 ); + light.position.set( -200, -100, -400 ); + scene.add( light ); + + // GROUND + // Student: texture is located at URL textures/grass512x512.jpg + var texture = new THREE.TextureLoader(); + // var grassGround = texture.load('textures/grass512x512.jpg'); + var grassTexture = texture.load('textures/road.png'); + + + grassTexture.wrapS = THREE.RepeatWrapping; + grassTexture.wrapT = THREE.RepeatWrapping; + grassTexture.repeat.set(10, 10); + + + var solidGround = new THREE.Mesh( + new THREE.PlaneGeometry( 100000, 100000, 1000, 1000 ), + // new THREE.MeshLambertMaterial( { map : grassGround } ) ); + new THREE.MeshLambertMaterial( { map : grassTexture } ) ); + solidGround.rotation.x = - Math.PI / 2; + + scene.add( solidGround ); + + scene.background = new THREE.CubeTextureLoader() + .setPath( 'textures/skybox/' ) + .load( ['px.jpg', 'nx.jpg', + 'py.jpg', 'ny.jpg', + 'pz.jpg', 'nz.jpg' ]); + + + new MTLLoader() + .load( 'tree_bonus.mtl', function ( materials ) { + + materials.preload(); + //materials.color.sethex(0x08000); + + new OBJLoader() + .setMaterials( materials ) + .load( 'tree_bonus.obj', function ( object ) { + + // object.position.y = - 0.95; + + object.scale.setScalar( 400); + + + scene.add( object ); + + }); + }); + + } + + + + + + + +function init() { + var canvasWidth = 846; + var canvasHeight = 494; + // For grading the window is fixed in size; here's general code: + //var canvasWidth = window.innerWidth; + //var canvasHeight = window.innerHeight; + var canvasRatio = canvasWidth / canvasHeight; + + // RENDERER + renderer = new THREE.WebGLRenderer( { antialias: true } ); + renderer.gammaInput = true; + renderer.gammaOutput = true; + renderer.setSize(canvasWidth, canvasHeight); + renderer.setClearColor( 0xAAAAAA, 1.0 ); + + var container = document.getElementById( 'webGL'); + container.appendChild( renderer.domElement ); + + // CAMERA + camera = new THREE.PerspectiveCamera( 35, canvasRatio, 1, 800000); + camera.position.set( -1230, 920, -670 ); + + // CONTROLS + cameraControls = new OrbitControls(camera, renderer.domElement); + cameraControls.target.set(0,270,0); + +} + +function addToDOM() { + var container = document.getElementById( 'webGL'); + var canvas = container.getElementsByTagName('canvas'); + if (canvas.length>0) { + container.removeChild(canvas[0]); + } + container.appendChild( renderer.domElement ); + + +} + +function animate() { + window.requestAnimationFrame(animate); + render(); +} + +function render() { + var delta = clock.getDelta(); + cameraControls.update(delta); + + // Anime water texture + + + renderer.render(scene, camera); +} + +try { + init(); + fillScene(); + addToDOM(); + animate(); +} catch(e) { + var errorReport = "Your program encountered an unrecoverable error, can not draw on canvas. Error was:<br/><br/>"; + $('#webGL').append(errorReport+e); +} diff --git a/ALVARIZA-BILLAR_DESERT_KANY/source.txt b/ALVARIZA-BILLAR_DESERT_KANY/source.txt new file mode 100644 index 0000000000000000000000000000000000000000..7703df76b1a3ea84cd4790d5f163d1ed03607b1c --- /dev/null +++ b/ALVARIZA-BILLAR_DESERT_KANY/source.txt @@ -0,0 +1 @@ +Arbre poly : https://www.turbosquid.com/3d-models/3d-low-poly-trees-1431822 \ No newline at end of file diff --git a/ALVARIZA-BILLAR_DESERT_KANY/textures/skybox/nx.jpg b/ALVARIZA-BILLAR_DESERT_KANY/textures/skybox/nx.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1cae307a60b90353ccc2b1ff95b7edcb4506f383 Binary files /dev/null and b/ALVARIZA-BILLAR_DESERT_KANY/textures/skybox/nx.jpg differ diff --git a/ALVARIZA-BILLAR_DESERT_KANY/textures/skybox/ny.jpg b/ALVARIZA-BILLAR_DESERT_KANY/textures/skybox/ny.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fa7a975d349aa8a45fd1f891e8a11ab2da36effa Binary files /dev/null and b/ALVARIZA-BILLAR_DESERT_KANY/textures/skybox/ny.jpg differ diff --git a/ALVARIZA-BILLAR_DESERT_KANY/textures/skybox/nz.jpg b/ALVARIZA-BILLAR_DESERT_KANY/textures/skybox/nz.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1e9c54ef26c720d1247750bfa9adb120bf14a5ae Binary files /dev/null and b/ALVARIZA-BILLAR_DESERT_KANY/textures/skybox/nz.jpg differ diff --git a/ALVARIZA-BILLAR_DESERT_KANY/textures/skybox/px.jpg b/ALVARIZA-BILLAR_DESERT_KANY/textures/skybox/px.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0ad2eeaf0498edb2d5758c4a29356d1709a0ec00 Binary files /dev/null and b/ALVARIZA-BILLAR_DESERT_KANY/textures/skybox/px.jpg differ diff --git a/ALVARIZA-BILLAR_DESERT_KANY/textures/skybox/py.jpg b/ALVARIZA-BILLAR_DESERT_KANY/textures/skybox/py.jpg new file mode 100644 index 0000000000000000000000000000000000000000..de7e5ccada20846d5f100f4d92c2b8f3f7db4c32 Binary files /dev/null and b/ALVARIZA-BILLAR_DESERT_KANY/textures/skybox/py.jpg differ diff --git a/ALVARIZA-BILLAR_DESERT_KANY/textures/skybox/pz.jpg b/ALVARIZA-BILLAR_DESERT_KANY/textures/skybox/pz.jpg new file mode 100644 index 0000000000000000000000000000000000000000..836cdb4a32c31dec3052184044753d51eac474e7 Binary files /dev/null and b/ALVARIZA-BILLAR_DESERT_KANY/textures/skybox/pz.jpg differ diff --git a/ALVARIZA-BILLAR_DESERT_KANY/tree_bonus.mtl b/ALVARIZA-BILLAR_DESERT_KANY/tree_bonus.mtl new file mode 100644 index 0000000000000000000000000000000000000000..d6b610871d533637e5206b4e807bd849a326b3fa --- /dev/null +++ b/ALVARIZA-BILLAR_DESERT_KANY/tree_bonus.mtl @@ -0,0 +1,12 @@ +# Blender 4.3.2 MTL File: 'tree_bonus.blend' +# www.blender.org + +newmtl tre__fin_ +Ns 250.000000 +Ka 1.000000 1.000000 1.000000 +Kd 0.800000 0.800000 0.800000 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.000000 +d 1.000000 +illum 2 diff --git a/ALVARIZA-BILLAR_DESERT_KANY/tree_bonus.obj b/ALVARIZA-BILLAR_DESERT_KANY/tree_bonus.obj new file mode 100644 index 0000000000000000000000000000000000000000..daa6ffa054c231934056e284581f4841131b481e --- /dev/null +++ b/ALVARIZA-BILLAR_DESERT_KANY/tree_bonus.obj @@ -0,0 +1,3125 @@ +# Blender 4.3.2 +# www.blender.org +mtllib tree_bonus.mtl +o Cube.001 +v -0.184628 0.887715 -0.142606 +v -0.184628 0.407852 -0.199763 +v -0.091490 0.407852 -0.292902 +v -0.091490 0.887715 -0.235745 +v -0.184628 0.407852 -0.016644 +v -0.184628 0.887715 0.040514 +v -0.091490 0.887715 0.133652 +v -0.091490 0.407852 0.076495 +v -0.091490 -0.072012 0.167589 +v -0.184628 -0.072012 0.074451 +v -0.181469 1.374361 0.056960 +v -0.089069 1.377173 0.147464 +v -0.184628 -0.072012 -0.108669 +v -0.091490 -0.072012 -0.201807 +v -0.085715 1.390468 -0.208170 +v -0.180561 1.376311 -0.122903 +v 0.184768 -0.072012 0.074451 +v 0.091630 -0.072012 0.167589 +v 0.091225 1.370001 0.150491 +v 0.179247 1.382082 0.055349 +v 0.091630 -0.072012 -0.201807 +v 0.184768 -0.072012 -0.108669 +v 0.181478 1.376222 -0.122921 +v 0.090018 1.377213 -0.213794 +v 0.184768 0.887715 -0.142606 +v 0.184768 0.407852 -0.199763 +v 0.091630 0.407852 -0.292902 +v 0.091630 0.887715 -0.235745 +v 0.091630 0.887715 0.133652 +v 0.091630 0.407852 0.076495 +v 0.184768 0.407852 -0.016644 +v 0.184768 0.887715 0.040514 +v 1.000334 1.249479 0.725286 +v 1.489783 1.168326 0.532616 +v 1.090233 1.345061 0.267450 +v 1.620326 1.189442 0.109973 +v 1.363551 1.185014 -0.181964 +v 1.140853 1.260555 -0.357799 +v 1.242872 1.021799 -0.938080 +v 0.961951 1.435121 -0.795751 +v 0.828053 1.248039 -0.996475 +v 0.869179 1.083090 -1.375773 +v 0.421529 1.066760 -1.278008 +v 0.017847 1.143497 -1.546426 +v -0.056604 1.357828 -1.106290 +v -0.237929 1.091828 -1.540811 +v -0.560771 1.195332 -1.194773 +v -0.901573 1.147901 -1.242765 +v -1.026832 1.407036 -0.918715 +v -1.258866 1.290041 -0.753656 +v -1.488569 1.329354 -0.606810 +v -1.444121 1.352419 -0.198338 +v -1.490717 1.412974 0.130613 +v -0.846432 1.449470 0.231783 +v -1.511177 1.213909 0.532888 +v -1.002623 1.144909 0.822208 +v -1.058705 1.203207 1.313120 +v -0.550832 1.202106 1.090185 +v -0.366259 1.221923 1.439682 +v -0.077559 1.121296 1.348193 +v 0.149063 1.157053 1.492365 +v 0.479448 1.096652 1.326158 +v 0.709616 1.380724 1.187933 +v 1.009209 1.317704 1.127450 +v 0.159529 1.214230 0.052743 +v 0.208767 1.221148 0.048571 +v 0.209388 1.183059 0.011336 +v 0.245529 1.189826 -0.017121 +v 0.187919 1.217132 -0.049206 +v 0.207252 1.217011 -0.083038 +v 0.186671 1.197084 -0.108303 +v 0.216102 1.173973 -0.171416 +v 0.144506 1.205032 -0.149360 +v 0.129784 1.226517 -0.183146 +v 0.100682 1.177423 -0.197835 +v 0.065190 1.230704 -0.181344 +v 0.036215 1.194727 -0.190087 +v -0.011303 1.168440 -0.242881 +v -0.020389 1.198170 -0.169903 +v -0.058813 1.207968 -0.169151 +v -0.077979 1.239179 -0.140101 +v -0.085388 1.194373 -0.108711 +v -0.106699 1.235381 -0.082360 +v -0.079171 1.224699 -0.047839 +v -0.130290 1.229267 -0.016700 +v -0.101462 1.188090 0.011006 +v -0.113384 1.224397 0.053335 +v -0.072630 1.186763 0.066771 +v -0.052383 1.238821 0.091599 +v -0.014482 1.212766 0.088697 +v 0.001077 1.235279 0.130862 +v 0.037660 1.206070 0.109714 +v 0.067730 1.239140 0.132071 +v 0.099171 1.186646 0.118511 +v 0.142874 1.209649 0.134963 +v 0.191606 1.168738 0.133266 +v 0.351442 2.101283 0.225039 +v 0.513364 2.101282 0.222649 +v 0.425499 2.101283 0.085676 +v 0.530881 2.101282 0.016950 +v 0.440587 2.101283 -0.071419 +v 0.497271 2.101283 -0.171085 +v 0.394409 2.101283 -0.222330 +v 0.424616 2.101282 -0.349526 +v 0.293995 2.101283 -0.344082 +v 0.282951 2.101282 -0.492090 +v 0.154633 2.101283 -0.418139 +v 0.082796 2.101283 -0.498762 +v -0.002462 2.101283 -0.433227 +v -0.107677 2.101282 -0.505478 +v -0.153373 2.101283 -0.387049 +v -0.270910 2.101283 -0.404711 +v -0.398669 2.101282 -0.386207 +v -0.319017 2.101283 -0.220601 +v -0.482808 2.101282 -0.186662 +v -0.364463 2.101283 -0.069468 +v -0.537992 2.101282 0.027995 +v -0.348613 2.101283 0.087552 +v -0.469090 2.101282 0.242163 +v -0.273881 2.101283 0.226554 +v -0.311245 2.101282 0.396765 +v -0.151644 2.101283 0.326377 +v -0.127069 2.101282 0.516568 +v -0.000511 2.101283 0.371823 +v 0.094331 2.101282 0.534565 +v 0.156509 2.101283 0.355973 +v 0.296176 2.101282 0.451045 +v 0.358891 2.101282 0.359125 +v 0.173543 2.738163 0.087892 +v 0.245686 2.738162 0.086828 +v 0.206539 2.738163 0.025800 +v 0.253491 2.738162 -0.004820 +v 0.213261 2.738163 -0.044192 +v 0.238516 2.738163 -0.088597 +v 0.192687 2.738163 -0.111429 +v 0.206146 2.738162 -0.168100 +v 0.147949 2.738163 -0.165674 +v 0.143028 2.738162 -0.231618 +v 0.085857 2.738163 -0.198670 +v 0.053851 2.738163 -0.234590 +v 0.015865 2.738163 -0.205392 +v -0.031013 2.738162 -0.237583 +v -0.051372 2.738163 -0.184818 +v -0.103740 2.738163 -0.192687 +v -0.160661 2.738162 -0.184443 +v -0.125173 2.738163 -0.110658 +v -0.198149 2.738162 -0.095537 +v -0.145421 2.738163 -0.043322 +v -0.222736 2.738162 0.000101 +v -0.138360 2.738163 0.026636 +v -0.192037 2.738162 0.095522 +v -0.105064 2.738163 0.088568 +v -0.121711 2.738162 0.164403 +v -0.050602 2.738163 0.133043 +v -0.039653 2.738162 0.217780 +v 0.016734 2.738163 0.153291 +v 0.058990 2.738162 0.225799 +v 0.086693 2.738163 0.146229 +v 0.148920 2.738162 0.188587 +v 0.176862 2.738162 0.147633 +v 0.304747 2.200102 -1.053526 +v 0.143020 2.129410 -1.579393 +v -0.093184 2.283362 -0.970835 +v -0.486705 2.147804 -1.332986 +v -0.546393 2.143947 -1.038229 +v -0.612218 2.209750 -0.799987 +v -0.997472 2.001772 -0.788786 +v -0.903267 2.361813 -0.508244 +v -1.019107 2.198848 -0.332866 +v -1.448016 2.055162 -0.216598 +v -1.107603 2.040937 0.088692 +v -1.327178 2.107783 0.383042 +v -0.808037 2.294484 0.414427 +v -1.189088 2.062774 0.960701 +v -0.708537 2.152935 0.849070 +v -0.660816 2.111619 1.234069 +v -0.329296 2.337348 1.129822 +v -0.118313 2.036631 1.260256 +v 0.192639 2.269680 1.435510 +v 0.390122 2.025670 1.221138 +v 0.751697 2.342520 1.198618 +v 0.533237 2.374311 0.595867 +v 1.351744 1.998647 0.875628 +v 1.060024 2.109012 0.521544 +v 1.473068 2.159795 0.400518 +v 1.122327 2.158836 0.068234 +v 1.548746 2.176098 -0.196033 +v 1.169362 2.088443 -0.398949 +v 1.458098 2.119590 -0.824700 +v 0.963273 2.066976 -0.838627 +v 0.774463 2.314428 -0.976640 +v 0.650135 2.259532 -1.455071 +v 0.049261 2.169397 -0.151099 +v 0.029257 2.175422 -0.189214 +v -0.000842 2.142244 -0.177118 +v -0.035910 2.148139 -0.196505 +v -0.042180 2.171925 -0.139406 +v -0.075878 2.171820 -0.143482 +v -0.089197 2.154461 -0.118416 +v -0.149816 2.134330 -0.120695 +v -0.107893 2.161385 -0.070681 +v -0.130036 2.180100 -0.047436 +v -0.131984 2.137335 -0.019106 +v -0.106741 2.183747 0.003807 +v -0.103959 2.152408 0.030024 +v -0.130266 2.129510 0.086025 +v -0.068611 2.155407 0.068634 +v -0.055011 2.163942 0.099225 +v -0.025208 2.191129 0.104784 +v 0.002496 2.152100 0.100115 +v 0.030857 2.187821 0.108309 +v 0.049257 2.178516 0.074535 +v 0.091544 2.182496 0.105037 +v 0.104034 2.146627 0.072525 +v 0.142045 2.178254 0.067779 +v 0.139047 2.145471 0.030519 +v 0.152128 2.190818 0.005868 +v 0.136979 2.168122 -0.023575 +v 0.165565 2.187732 -0.050326 +v 0.136214 2.162289 -0.072541 +v 0.143990 2.191096 -0.104241 +v 0.122471 2.145368 -0.124893 +v 0.120895 2.165407 -0.165540 +v 0.103050 2.129769 -0.204085 +v 0.122657 2.942098 -0.363432 +v 0.065971 2.942098 -0.492606 +v -0.014263 2.942098 -0.375744 +v -0.105077 2.942098 -0.437092 +v -0.145473 2.942098 -0.334720 +v -0.244652 2.942098 -0.346512 +v -0.250996 2.942098 -0.246608 +v -0.363319 2.942098 -0.227833 +v -0.314767 2.942098 -0.124820 +v -0.429844 2.942098 -0.065893 +v -0.327079 2.942098 0.012101 +v -0.367500 2.942098 0.097036 +v -0.286055 2.942098 0.143310 +v -0.308466 2.942098 0.252209 +v -0.197942 2.942098 0.248833 +v -0.172365 2.942098 0.349159 +v -0.114298 2.942098 0.445457 +v -0.008301 2.942098 0.325503 +v 0.074343 2.942098 0.445506 +v 0.128391 2.942098 0.310865 +v 0.265322 2.942098 0.417199 +v 0.249076 2.942098 0.245032 +v 0.413938 2.942098 0.289449 +v 0.335382 2.942098 0.138026 +v 0.484654 2.942098 0.110448 +v 0.374168 2.942098 0.006138 +v 0.518529 2.942098 -0.077919 +v 0.359530 2.942098 -0.130554 +v 0.458091 2.942098 -0.261733 +v 0.293697 2.942098 -0.251239 +v 0.322775 2.942098 -0.395512 +v 0.227774 2.942098 -0.414765 +v 0.072736 3.496877 -0.174238 +v 0.047480 3.496877 -0.231790 +v 0.011733 3.496877 -0.179724 +v -0.028729 3.496877 -0.207057 +v -0.046727 3.496877 -0.161446 +v -0.090915 3.496877 -0.166700 +v -0.093742 3.496877 -0.122188 +v -0.143786 3.496877 -0.113823 +v -0.122154 3.496877 -0.067927 +v -0.173426 3.496877 -0.041672 +v -0.127639 3.496877 -0.006923 +v -0.145649 3.496877 0.030919 +v -0.109362 3.496877 0.051536 +v -0.119347 3.496877 0.100055 +v -0.070104 3.496877 0.098551 +v -0.058708 3.496877 0.143250 +v -0.032837 3.496877 0.186155 +v 0.014389 3.496877 0.132711 +v 0.051210 3.496877 0.186177 +v 0.075291 3.496877 0.126189 +v 0.136299 3.496877 0.173565 +v 0.129061 3.496877 0.096858 +v 0.202514 3.496877 0.116647 +v 0.167514 3.496877 0.049182 +v 0.234021 3.496877 0.036895 +v 0.184795 3.496877 -0.009580 +v 0.249114 3.496877 -0.047030 +v 0.178273 3.496877 -0.070482 +v 0.222186 3.496877 -0.128927 +v 0.148942 3.496877 -0.124252 +v 0.161897 3.496877 -0.188531 +v 0.119570 3.496877 -0.197109 +v 0.009751 3.163760 -0.835077 +v -0.221547 3.109890 -1.184759 +v -0.263391 3.227208 -0.689067 +v -0.652222 3.123907 -1.007617 +v -0.609215 3.120967 -0.640898 +v -0.606116 3.171113 -0.452571 +v -1.160570 3.012624 -0.507188 +v -0.756172 3.286990 -0.176706 +v -0.803155 3.162804 -0.023584 +v -1.222887 3.053310 0.221253 +v -0.777217 3.042470 0.303637 +v -0.874459 3.093408 0.566040 +v -0.488176 3.235683 0.477369 +v -0.649306 3.059110 0.958668 +v -0.321984 3.127817 0.773737 +v -0.204321 3.096332 1.044944 +v 0.015635 3.268347 0.897453 +v 0.197924 3.039188 0.947450 +v 0.544846 3.216781 1.287242 +v 0.561223 3.030836 0.809537 +v 0.993711 3.272289 0.809698 +v 0.531417 3.296516 0.321641 +v 1.361378 3.010242 0.537970 +v 0.900563 3.094346 0.154045 +v 1.176512 3.133044 -0.023239 +v 0.848650 3.132313 -0.190758 +v 1.103581 3.145468 -0.475640 +v 0.782592 3.078671 -0.542420 +v 0.902145 3.102407 -0.915758 +v 0.537392 3.062312 -0.819552 +v 0.369683 3.250881 -0.879857 +v 0.232544 3.209048 -1.306692 +v 0.016992 3.140361 -0.120398 +v -0.005827 3.144953 -0.143962 +v -0.025232 3.119670 -0.128648 +v -0.055037 3.124162 -0.135281 +v -0.047345 3.142287 -0.092190 +v -0.072857 3.142208 -0.087925 +v -0.077206 3.128979 -0.066735 +v -0.122012 3.113639 -0.055368 +v -0.080611 3.134255 -0.027817 +v -0.091801 3.148518 -0.006062 +v -0.087134 3.115928 0.015068 +v -0.063753 3.151296 0.026392 +v -0.056083 3.127415 0.044960 +v -0.063275 3.109966 0.091558 +v -0.021939 3.129701 0.065588 +v -0.005419 3.136204 0.085029 +v 0.017564 3.156922 0.082685 +v 0.036814 3.127180 0.073315 +v 0.059310 3.154401 0.073208 +v 0.065501 3.147310 0.044560 +v 0.102974 3.150343 0.057769 +v 0.105115 3.123010 0.031314 +v 0.131884 3.147110 0.019671 +v 0.121681 3.122129 -0.006924 +v 0.125945 3.156685 -0.027759 +v 0.108539 3.139390 -0.046027 +v 0.123686 3.154334 -0.071730 +v 0.097452 3.134944 -0.081660 +v 0.096322 3.156897 -0.106507 +v 0.076149 3.122051 -0.116980 +v 0.066258 3.137321 -0.146357 +v 0.044925 3.110164 -0.170700 +v 0.024999 3.729192 -0.291412 +v -0.044216 3.729192 -0.373661 +v -0.077748 3.729192 -0.270974 +v -0.157331 3.729192 -0.296300 +v -0.164854 3.729192 -0.212772 +v -0.239897 3.729192 -0.200070 +v -0.223055 3.729192 -0.125667 +v -0.301136 3.729192 -0.087792 +v -0.243493 3.729192 -0.022919 +v -0.314955 3.729192 0.044903 +v -0.223055 3.729192 0.079828 +v -0.234346 3.729192 0.150614 +v -0.164854 3.729192 0.166933 +v -0.157825 3.729192 0.251366 +v -0.077748 3.729192 0.225135 +v -0.037479 3.729192 0.292982 +v 0.025677 3.729192 0.350900 +v 0.077380 3.729192 0.240414 +v 0.163600 3.729192 0.310378 +v 0.174166 3.729192 0.200324 +v 0.297136 3.729192 0.248622 +v 0.248243 3.729192 0.126247 +v 0.378320 3.729192 0.123274 +v 0.288333 3.729192 0.029461 +v 0.391534 3.729192 -0.022795 +v 0.288333 3.729192 -0.075300 +v 0.375801 3.729192 -0.167790 +v 0.248242 3.729192 -0.172086 +v 0.292094 3.729192 -0.289179 +v 0.174165 3.729192 -0.246163 +v 0.164405 3.729192 -0.357890 +v 0.090812 3.729192 -0.351540 +v 0.029180 4.281134 -0.142362 +v -0.001658 4.281134 -0.179007 +v -0.016599 4.281134 -0.133256 +v -0.052056 4.281134 -0.144540 +v -0.055407 4.281134 -0.107325 +v -0.088842 4.281134 -0.101665 +v -0.081339 4.281134 -0.068516 +v -0.116127 4.281134 -0.051641 +v -0.090445 4.281134 -0.022738 +v -0.122284 4.281134 0.007480 +v -0.081339 4.281134 0.023041 +v -0.086369 4.281134 0.054578 +v -0.055407 4.281134 0.061850 +v -0.052276 4.281134 0.099468 +v -0.016599 4.281134 0.087781 +v 0.001343 4.281134 0.118010 +v 0.029482 4.281134 0.143814 +v 0.052517 4.281134 0.094588 +v 0.090932 4.281134 0.125760 +v 0.095640 4.281134 0.076726 +v 0.150428 4.281134 0.098245 +v 0.128644 4.281134 0.043722 +v 0.186598 4.281134 0.042397 +v 0.146506 4.281134 0.000600 +v 0.192486 4.281134 -0.022682 +v 0.146506 4.281134 -0.046075 +v 0.185476 4.281134 -0.087284 +v 0.128644 4.281134 -0.089197 +v 0.148182 4.281134 -0.141367 +v 0.095639 4.281134 -0.122202 +v 0.091291 4.281134 -0.171981 +v 0.058502 4.281134 -0.169152 +v -0.294140 4.117845 -0.506281 +v -0.568787 4.063974 -0.629022 +v -0.403355 4.181292 -0.312740 +v -0.761418 4.077991 -0.356000 +v -0.594238 4.075052 -0.150476 +v -0.519882 4.125197 -0.037622 +v -0.876666 3.966709 0.142691 +v -0.504583 4.241075 0.187186 +v -0.474104 4.116889 0.297994 +v -0.634055 4.007395 0.607799 +v -0.332463 3.996554 0.486168 +v -0.290361 4.047493 0.682498 +v -0.090564 4.189767 0.480135 +v -0.002908 4.013195 0.833611 +v 0.124138 4.081902 0.595648 +v 0.299768 4.050417 0.714600 +v 0.376205 4.222432 0.540631 +v 0.505836 3.993273 0.500752 +v 0.846696 4.170866 0.573006 +v 0.672764 3.984921 0.277417 +v 0.934730 4.226373 0.111067 +v 0.466943 4.250600 -0.006570 +v 1.052802 3.964327 -0.194985 +v 0.625987 4.048430 -0.250131 +v 0.724865 4.087129 -0.463692 +v 0.461849 4.086398 -0.438956 +v 0.506589 4.099553 -0.709586 +v 0.286505 4.032756 -0.626490 +v 0.215220 4.056492 -0.898586 +v 0.031361 4.016397 -0.699947 +v -0.093408 4.204966 -0.671922 +v -0.340728 4.163133 -0.877623 +v -0.014704 4.094446 -0.076276 +v -0.037591 4.099038 -0.081764 +v -0.043448 4.073755 -0.065022 +v -0.064051 4.078247 -0.057568 +v -0.042808 4.096373 -0.034433 +v -0.056616 4.096292 -0.022031 +v -0.051095 4.083064 -0.007526 +v -0.073854 4.067724 0.016602 +v -0.038179 4.088340 0.017352 +v -0.036583 4.102602 0.034833 +v -0.025625 4.070014 0.045833 +v -0.007108 4.105381 0.043692 +v 0.004684 4.081500 0.051985 +v 0.018262 4.064050 0.082971 +v 0.033299 4.083786 0.051336 +v 0.050785 4.090289 0.056750 +v 0.063801 4.111007 0.046486 +v 0.071852 4.081265 0.033403 +v 0.085434 4.108486 0.024680 +v 0.078158 4.101395 0.004950 +v 0.105934 4.104428 -0.001474 +v 0.097049 4.077095 -0.018318 +v 0.108779 4.101195 -0.035671 +v 0.092365 4.076213 -0.047850 +v 0.086929 4.110770 -0.062108 +v 0.069358 4.093475 -0.066472 +v 0.068638 4.108418 -0.087866 +v 0.048930 4.089029 -0.083783 +v 0.038682 4.110982 -0.098395 +v 0.022436 4.076135 -0.096973 +v 0.005140 4.091406 -0.110957 +v -0.017148 4.064249 -0.117488 +v -0.075671 4.683277 -0.182919 +v -0.149240 4.683277 -0.206089 +v -0.130027 4.683277 -0.130999 +v -0.187967 4.683277 -0.115708 +v -0.160376 4.683277 -0.062230 +v -0.200931 4.683277 -0.025657 +v -0.162098 4.683277 0.012918 +v -0.194805 4.683277 0.065904 +v -0.134931 4.683277 0.083005 +v -0.152104 4.683277 0.151579 +v -0.083011 4.683277 0.137361 +v -0.062606 4.683277 0.184572 +v -0.014242 4.683277 0.167710 +v 0.022509 4.683277 0.216135 +v 0.060906 4.683277 0.169432 +v 0.111404 4.683277 0.195020 +v 0.171939 4.683277 0.205788 +v 0.160728 4.683277 0.118982 +v 0.239867 4.683277 0.128167 +v 0.203910 4.683277 0.057455 +v 0.296965 4.683277 0.039377 +v 0.220260 4.683277 -0.015913 +v 0.297887 4.683277 -0.067775 +v 0.207288 4.683277 -0.089954 +v 0.249673 4.683277 -0.161316 +v 0.166970 4.683277 -0.153394 +v 0.184342 4.683277 -0.243067 +v 0.105443 4.683277 -0.196576 +v 0.086934 4.683277 -0.284362 +v 0.032075 4.683277 -0.212926 +v -0.016835 4.683277 -0.276828 +v -0.058958 4.683277 -0.244660 +v -0.015776 4.956873 -0.094267 +v -0.048554 4.956873 -0.104590 +v -0.039994 4.956873 -0.071135 +v -0.065809 4.956873 -0.064322 +v -0.053516 4.956873 -0.040496 +v -0.071585 4.956873 -0.024201 +v -0.054283 4.956873 -0.007014 +v -0.068855 4.956873 0.016594 +v -0.042179 4.956873 0.024213 +v -0.049830 4.956873 0.054765 +v -0.019047 4.956873 0.048430 +v -0.009955 4.956873 0.069465 +v 0.011593 4.956873 0.061952 +v 0.027967 4.956873 0.083528 +v 0.045074 4.956873 0.062720 +v 0.067573 4.956873 0.074120 +v 0.094544 4.956873 0.078918 +v 0.089549 4.956873 0.040242 +v 0.124809 4.956873 0.044334 +v 0.108788 4.956873 0.012829 +v 0.150249 4.956873 0.004775 +v 0.116073 4.956873 -0.019859 +v 0.150659 4.956873 -0.042966 +v 0.110294 4.956873 -0.052847 +v 0.129178 4.956873 -0.084642 +v 0.092330 4.956873 -0.081113 +v 0.100070 4.956873 -0.121066 +v 0.064917 4.956873 -0.100352 +v 0.056671 4.956873 -0.139464 +v 0.032229 4.956873 -0.107636 +v 0.010437 4.956873 -0.136108 +v -0.008330 4.956873 -0.121775 +v -0.116967 5.267776 0.055175 +v 0.022079 5.267790 -0.168849 +v 0.012554 4.737098 -0.320187 +v -0.117119 5.267788 -0.202906 +v 0.299708 4.737098 -0.357372 +v 0.151283 5.267789 -0.059731 +v 0.282345 4.737098 -0.093806 +v 0.159196 5.267789 -0.185407 +v 0.342385 4.737098 0.149305 +v 0.168416 4.737098 0.362652 +v -0.081144 4.737098 0.211197 +v 0.180455 5.267790 0.056890 +v -0.341358 4.737098 0.180706 +v 0.097097 5.267790 0.159789 +v -0.257237 4.737098 -0.093806 +v -0.285819 4.737098 -0.401822 +v 0.032314 5.831081 -0.022686 +v -0.095566 5.267783 -0.056916 +v -0.018662 5.267784 0.077901 +vn -0.0089 -0.0315 0.9995 +vn 0.9999 0.0088 0.0060 +vn -1.0000 -0.0000 -0.0000 +vn -0.0138 0.0499 -0.9987 +vn -0.7032 -0.0180 0.7108 +vn -0.7008 -0.1330 -0.7008 +vn 0.7008 -0.1330 -0.7008 +vn 0.7008 0.1330 0.7008 +vn -1.0000 0.0075 -0.0025 +vn 0.7211 -0.0181 0.6926 +vn 0.7046 -0.0839 0.7046 +vn 0.7057 0.0337 -0.7077 +vn 0.7046 0.0839 -0.7046 +vn -0.6894 0.0413 -0.7232 +vn -0.7046 0.0839 -0.7046 +vn -0.7008 0.1330 0.7008 +vn -0.7046 -0.0839 0.7046 +vn -0.0000 -0.1865 -0.9825 +vn -0.0000 0.1183 -0.9930 +vn 1.0000 -0.0000 -0.0000 +vn -0.0000 0.1865 0.9825 +vn -0.0000 -0.1183 0.9930 +vn 0.8817 -0.4490 -0.1448 +vn -0.4013 -0.9092 -0.1111 +vn -0.2435 -0.9632 0.1134 +vn -0.0847 -0.9865 0.1403 +vn 0.2932 -0.9543 -0.0575 +vn 0.1034 -0.9939 -0.0384 +vn 0.2636 -0.6967 -0.6672 +vn -0.3022 -0.9532 -0.0096 +vn -0.4873 -0.7617 0.4270 +vn -0.0352 -0.8297 0.5571 +vn 0.6691 -0.6980 -0.2553 +vn 0.2033 -0.8628 -0.4628 +vn -0.0129 -0.9982 -0.0580 +vn -0.2240 -0.9283 0.2966 +vn -0.1661 -0.9643 0.2065 +vn -0.0515 -0.9546 -0.2934 +vn 0.0695 -0.9967 0.0410 +vn -0.0908 -0.9950 0.0426 +vn 0.1660 -0.8986 0.4062 +vn -0.1125 -0.9827 0.1472 +vn -0.6037 -0.2344 -0.7620 +vn -0.0989 -0.8689 0.4850 +vn 0.4394 -0.8632 0.2484 +vn -0.3273 -0.3799 -0.8652 +vn 0.4028 -0.8563 0.3232 +vn -0.0818 -0.9772 -0.1957 +vn 0.1652 -0.9687 0.1854 +vn 0.2615 -0.9400 0.2193 +vn -0.3061 -0.9511 0.0427 +vn -0.0814 -0.9937 -0.0772 +vn -0.8287 -0.5588 0.0323 +vn 0.1301 -0.9907 0.0406 +vn 0.5848 0.5338 -0.6108 +vn 0.5058 0.5729 0.6450 +vn -0.5029 0.6684 -0.5480 +vn 0.2966 0.6054 0.7386 +vn -0.5992 0.5710 0.5611 +vn 0.0416 0.6491 -0.7596 +vn 0.6574 0.4664 -0.5918 +vn 0.5632 0.6337 0.5302 +vn -0.1909 0.7098 -0.6780 +vn 0.3965 0.5394 0.7429 +vn -0.3565 0.5759 0.7357 +vn -0.6739 0.7371 -0.0498 +vn 0.5691 0.6315 -0.5267 +vn 0.3549 0.7747 0.5233 +vn -0.2394 0.6996 -0.6732 +vn 0.7038 0.6683 -0.2409 +vn 0.8147 0.5716 -0.0975 +vn -0.6084 0.7785 0.1542 +vn 0.7031 0.6649 -0.2523 +vn -0.5304 0.7571 -0.3813 +vn 0.8323 0.4958 0.2478 +vn -0.1913 0.3742 0.9074 +vn 0.1157 0.6343 -0.7644 +vn -0.5459 0.3283 -0.7709 +vn 0.7951 0.5903 -0.1393 +vn -0.2391 0.5976 0.7653 +vn -0.2506 0.5641 -0.7868 +vn -0.8327 0.5288 -0.1643 +vn 0.5289 0.6143 -0.5856 +vn 0.3460 0.5134 0.7853 +vn -0.7391 0.5039 -0.4470 +vn -0.7848 0.5509 0.2839 +vn -0.9554 0.2078 -0.2097 +vn 0.7132 0.2960 -0.6354 +vn 0.3946 0.2090 0.8948 +vn -0.5835 0.2884 -0.7592 +vn -0.9732 0.1926 0.1257 +vn 0.5453 0.2684 -0.7941 +vn 0.7374 0.2013 0.6448 +vn -0.9021 0.2550 -0.3481 +vn 0.0144 0.2143 0.9767 +vn -0.8478 0.1925 0.4941 +vn 0.1427 0.2787 -0.9497 +vn 0.8187 0.2321 -0.5252 +vn 0.9239 0.2072 0.3217 +vn -0.1346 0.3446 -0.9291 +vn 0.5278 0.2576 0.8094 +vn -0.5506 0.2060 0.8089 +vn -0.8838 0.1956 0.4251 +vn 0.6735 0.2698 -0.6882 +vn 0.7607 0.3898 0.5190 +vn -0.1977 0.2249 -0.9541 +vn 0.8350 0.2778 0.4749 +vn 0.9647 0.2579 -0.0536 +vn -0.6882 0.2082 0.6950 +vn 0.4275 0.2848 -0.8580 +vn -0.4798 0.2001 -0.8543 +vn 0.9398 0.2588 0.2232 +vn -0.2947 0.1869 0.9371 +vn -0.0402 0.2610 -0.9645 +vn -0.7732 0.1976 -0.6025 +vn 0.9676 0.2421 -0.0722 +vn 0.0782 0.1912 0.9784 +vn -0.4850 0.2376 -0.8416 +vn -0.4487 -0.6730 -0.5880 +vn 0.0427 -0.9217 0.3855 +vn 0.2542 -0.9414 0.2216 +vn 0.2179 -0.9751 0.0416 +vn -0.1624 -0.9593 -0.2310 +vn -0.0627 -0.9956 -0.0693 +vn -0.4934 -0.8687 -0.0427 +vn 0.1552 -0.9310 0.3305 +vn 0.6007 -0.7468 0.2855 +vn 0.4325 -0.8822 -0.1861 +vn -0.4950 -0.6980 -0.5175 +vn -0.7839 -0.6040 -0.1439 +vn -0.0649 -0.9969 0.0443 +vn 0.3395 -0.9379 0.0709 +vn 0.6277 -0.7782 -0.0209 +vn -0.2504 -0.9546 0.1614 +vn -0.0608 -0.9935 -0.0967 +vn -0.6941 -0.7097 0.1207 +vn 0.4253 -0.8155 -0.3925 +vn 0.6027 -0.7520 -0.2669 +vn -0.4723 -0.5299 0.7044 +vn 0.5470 -0.8192 -0.1721 +vn 0.0583 -0.8632 -0.5014 +vn -0.4569 -0.6686 0.5867 +vn 0.1174 -0.8977 -0.4246 +vn 0.0350 -0.9749 -0.2197 +vn 0.0996 -0.9591 -0.2649 +vn 0.1006 -0.9400 -0.3261 +vn 0.1630 -0.8934 0.4187 +vn -0.0395 -0.9937 0.1049 +vn 0.1853 -0.8222 0.5382 +vn -0.0120 -0.9895 -0.1442 +vn -0.7905 0.5353 -0.2975 +vn 0.2939 0.5245 -0.7991 +vn 0.0697 0.5790 0.8123 +vn 0.8029 0.5017 -0.3219 +vn 0.6981 0.4991 0.5134 +vn -0.7625 0.6247 0.1683 +vn -0.7521 0.4964 -0.4334 +vn -0.0383 0.5345 -0.8443 +vn -0.4269 0.7544 0.4986 +vn 0.4456 0.5684 -0.6916 +vn 0.8164 0.5759 0.0428 +vn 0.5199 0.5701 0.6361 +vn -0.7897 0.5823 -0.1934 +vn 0.5483 0.7699 -0.3266 +vn -0.6826 0.5637 0.4650 +vn -0.4953 0.6683 -0.5551 +vn -0.6625 0.4480 -0.6003 +vn 0.8303 0.4979 0.2503 +vn -0.5083 0.6646 -0.5477 +vn -0.4649 0.5473 0.6960 +vn -0.2436 0.6128 -0.7518 +vn 0.9024 0.3442 -0.2592 +vn -0.7493 0.6343 0.1902 +vn -0.1187 0.4521 0.8840 +vn -0.3844 0.5666 -0.7289 +vn 0.7603 0.4626 -0.4559 +vn -0.5476 0.5238 0.6526 +vn 0.1719 0.5288 0.8311 +vn -0.6484 0.5375 -0.5392 +vn 0.5894 0.5134 -0.6237 +vn -0.2768 0.5681 0.7750 +vn 0.4452 0.4838 0.7535 +vn 0.1777 0.2078 0.9619 +vn -0.8625 0.2960 -0.4105 +vn 0.6713 0.2090 -0.7111 +vn -0.4730 0.2884 0.8325 +vn 0.4938 0.1926 0.8480 +vn -0.9435 0.2684 -0.1942 +vn 0.3078 0.2013 -0.9299 +vn 0.0295 0.2550 0.9665 +vn 0.8944 0.2143 -0.3925 +vn 0.7845 0.1925 0.5895 +vn -0.9306 0.2787 0.2373 +vn -0.8019 0.2321 -0.5506 +vn -0.0623 0.2072 -0.9763 +vn -0.8039 0.3446 0.4847 +vn 0.5409 0.2576 -0.8007 +vn 0.9593 0.2060 0.1933 +vn 0.7349 0.1956 0.6494 +vn -0.8957 0.2698 -0.3534 +vn 0.1829 0.3898 -0.9026 +vn -0.8025 0.2249 0.5527 +vn 0.1134 0.2778 -0.9539 +vn -0.4240 0.2579 -0.8682 +vn 0.9077 0.2082 0.3644 +vn -0.9567 0.2848 -0.0608 +vn -0.6009 0.2001 0.7739 +vn -0.1592 0.2588 -0.9527 +vn 0.9780 0.1869 -0.0923 +vn -0.8732 0.2610 0.4116 +vn -0.2550 0.1976 0.9465 +vn -0.4422 0.2421 -0.8636 +vn 0.8713 0.1912 -0.4520 +vn -0.5872 0.2376 0.7737 +vn -0.5964 -0.6730 -0.4375 +vn 0.1497 -0.9217 0.3578 +vn 0.3064 -0.9414 0.1408 +vn 0.2208 -0.9751 -0.0216 +vn -0.2210 -0.9593 -0.1758 +vn -0.0797 -0.9956 -0.0488 +vn -0.4854 -0.8687 0.0983 +vn 0.2421 -0.9310 0.2733 +vn 0.6568 -0.7468 0.1044 +vn 0.4481 -0.8333 -0.3237 +vn -0.6209 -0.6980 -0.3568 +vn -0.7926 -0.6040 0.0831 +vn -0.0316 -0.9987 0.0409 +vn 0.3983 -0.9173 0.0004 +vn 0.6081 -0.7688 -0.1977 +vn -0.1947 -0.9546 0.2255 +vn -0.0963 -0.9925 -0.0750 +vn -0.5812 -0.7687 0.2671 +vn 0.2838 -0.8302 -0.4797 +vn 0.4332 -0.8111 -0.3930 +vn -0.2635 -0.6150 0.7432 +vn 0.5302 -0.7057 -0.4699 +vn -0.0855 -0.8632 -0.4975 +vn -0.3514 -0.5666 0.7453 +vn -0.0102 -0.9364 -0.3509 +vn -0.0541 -0.9952 -0.0812 +vn -0.0110 -0.9383 -0.3457 +vn 0.0044 -0.9400 -0.3413 +vn 0.2745 -0.8934 0.3557 +vn -0.0083 -0.9937 0.1118 +vn 0.3297 -0.8222 0.4641 +vn -0.0522 -0.9895 -0.1349 +vn -0.8424 0.5353 -0.0624 +vn 0.0565 0.5245 -0.8495 +vn 0.2961 0.5790 0.7596 +vn 0.6795 0.5017 -0.5353 +vn 0.8146 0.4991 0.2956 +vn -0.6840 0.6247 0.3766 +vn -0.8439 0.4964 -0.2036 +vn -0.2749 0.5345 -0.7992 +vn -0.2689 0.7544 0.5988 +vn 0.4415 0.4932 -0.7496 +vn 0.7953 0.5759 -0.1893 +vn 0.6782 0.5701 0.4636 +vn -0.8190 0.5698 0.0683 +vn 0.5749 0.7342 -0.3612 +vn -0.7017 0.4642 0.5405 +vn -0.6318 0.6683 -0.3928 +vn -0.7993 0.4526 -0.3953 +vn 0.8933 0.4387 -0.0978 +vn -0.2041 0.5953 -0.7771 +vn -0.2983 0.5266 0.7961 +vn -0.6379 0.7701 -0.0084 +vn 0.7378 0.2972 -0.6061 +vn -0.6652 0.6343 0.3939 +vn -0.0877 0.3894 0.9169 +vn -0.5344 0.5394 -0.6507 +vn 0.6164 0.4767 -0.6268 +vn -0.1815 0.4514 0.8737 +vn 0.3994 0.5288 0.7489 +vn -0.7742 0.5375 -0.3343 +vn 0.3894 0.5134 -0.7647 +vn -0.0469 0.5681 0.8216 +vn 0.6397 0.4838 0.5973 +vn 0.4459 0.1606 0.8806 +vn -0.9608 0.2309 -0.1533 +vn 0.4475 0.1616 -0.8796 +vn -0.2228 0.2248 0.9486 +vn 0.7185 0.1486 0.6795 +vn -0.9746 0.2087 0.0811 +vn 0.0332 0.1555 -0.9873 +vn 0.3051 0.1980 0.9315 +vn 0.7545 0.1658 -0.6350 +vn 0.9261 0.1486 0.3468 +vn -0.8394 0.2170 0.4982 +vn -0.9351 0.1798 -0.3054 +vn -0.3383 0.1601 -0.9273 +vn -0.6506 0.2707 0.7095 +vn 0.2971 0.2000 -0.9337 +vn 0.9835 0.1592 -0.0859 +vn 0.8953 0.1510 0.4190 +vn -0.9738 0.2099 -0.0877 +vn -0.0818 0.3084 -0.9477 +vn -0.6205 0.1741 0.7647 +vn -0.1629 0.2162 -0.9627 +vn -0.6608 0.2003 -0.7233 +vn 0.9825 0.1609 0.0943 +vn -0.9510 0.2219 0.2153 +vn -0.3612 0.1545 0.9196 +vn -0.4275 0.2010 -0.8814 +vn 0.9189 0.1442 -0.3671 +vn -0.7320 0.2028 0.6504 +vn 0.0226 0.1526 0.9880 +vn -0.6762 0.1877 -0.7124 +vn 0.7138 0.1476 -0.6847 +vn -0.3492 0.1842 0.9188 +vn -0.8355 -0.5467 -0.0559 +vn 0.4151 -0.8626 0.2891 +vn 0.4426 -0.8947 -0.0603 +vn 0.2381 -0.9532 -0.1861 +vn -0.3775 -0.9252 -0.0401 +vn -0.1297 -0.9916 0.0022 +vn -0.4484 -0.7829 0.4312 +vn 0.4610 -0.8775 0.1324 +vn 0.7147 -0.6274 -0.3093 +vn 0.2512 -0.7343 -0.6306 +vn -0.8187 -0.5731 0.0365 +vn -0.6883 -0.4777 0.5459 +vn -0.0065 -0.9974 0.0716 +vn 0.4372 -0.8556 -0.2773 +vn 0.4821 -0.6532 -0.5838 +vn -0.0580 -0.9170 0.3946 +vn -0.1682 -0.9856 -0.0161 +vn -0.4111 -0.6530 0.6360 +vn -0.0218 -0.7302 -0.6829 +vn 0.1876 -0.7054 -0.6836 +vn 0.1950 -0.4884 0.8506 +vn 0.2244 -0.5815 -0.7820 +vn -0.4243 -0.7752 -0.4681 +vn 0.1123 -0.4424 0.8897 +vn -0.2596 -0.8863 -0.3835 +vn -0.1238 -0.9908 -0.0549 +vn -0.2573 -0.8895 -0.3777 +vn -0.2372 -0.8923 -0.3842 +vn 0.5397 -0.8188 0.1955 +vn 0.0734 -0.9879 0.1369 +vn 0.6430 -0.7196 0.2621 +vn -0.1607 -0.9799 -0.1185 +vn -0.8022 0.4139 0.4302 +vn -0.4383 0.4043 -0.8028 +vn 0.7184 0.4540 0.5271 +vn 0.3056 0.3842 -0.8712 +vn 0.9023 0.3820 -0.1999 +vn -0.4168 0.4978 0.7605 +vn -0.8754 0.3796 0.2992 +vn -0.7119 0.4132 -0.5679 +vn 0.1107 0.6362 0.7635 +vn -0.0313 0.3768 -0.9258 +vn 0.6220 0.4511 -0.6401 +vn 0.8947 0.4457 0.0300 +vn -0.7131 0.4454 0.5413 +vn 0.3392 0.6130 -0.7136 +vn -0.3194 0.3520 0.8798 +vn -0.8405 0.5418 0.0083 +vn -0.9343 0.3422 0.1002 +vn 0.7367 0.3306 -0.5899 +vn -0.6474 0.4694 -0.6005 +vn 0.1883 0.4061 0.8942 +vn -0.6433 0.6547 0.3970 +vn 0.3042 0.2180 -0.9273 +vn -0.3904 0.5073 0.7683 +vn 0.4341 0.2902 0.8528 +vn -0.8633 0.4176 -0.2833 +vn 0.1951 0.3626 -0.9113 +vn 0.3322 0.3412 0.8793 +vn 0.7946 0.4082 0.4494 +vn -0.8980 0.4159 0.1435 +vn -0.0872 0.3945 -0.9148 +vn 0.4367 0.4439 0.7825 +vn 0.9137 0.3687 0.1710 +vn 0.8369 0.2293 0.4971 +vn -0.8681 0.3249 0.3752 +vn -0.0928 0.2306 -0.9686 +vn 0.3123 0.3167 0.8956 +vn 0.9593 0.2126 0.1858 +vn -0.7611 0.2951 0.5776 +vn -0.4950 0.2221 -0.8400 +vn 0.7414 0.2806 0.6096 +vn 0.2919 0.2364 -0.9268 +vn 0.9561 0.2125 -0.2016 +vn -0.4303 0.3063 0.8491 +vn -0.9366 0.2558 0.2396 +vn -0.7721 0.2286 -0.5929 +vn -0.1622 0.3770 0.9119 +vn -0.2447 0.2834 -0.9272 +vn 0.7733 0.2273 -0.5919 +vn 0.9684 0.2159 -0.1251 +vn -0.8487 0.2967 0.4379 +vn -0.5494 0.4248 -0.7195 +vn -0.1117 0.2479 0.9623 +vn -0.6377 0.3053 -0.7072 +vn -0.9256 0.2838 -0.2506 +vn 0.8675 0.2297 -0.4411 +vn -0.6694 0.3129 0.6738 +vn 0.1860 0.2208 0.9574 +vn -0.8157 0.2848 -0.5035 +vn 0.5721 0.2064 -0.7938 +vn -0.2631 0.2871 0.9211 +vn 0.5421 0.2182 0.8115 +vn -0.9349 0.2666 -0.2341 +vn 0.2324 0.2112 -0.9494 +vn 0.1945 0.2618 0.9453 +vn -0.2211 0.1908 0.9564 +vn -0.1208 0.2756 -0.9537 +vn -0.9563 0.2282 -0.1826 +vn 0.9697 0.2359 0.0630 +vn -0.9670 0.2109 0.1428 +vn 0.9406 0.2468 -0.2333 +vn -0.1160 0.2514 -0.9609 +vn 0.7330 0.3270 0.5964 +vn 0.2307 0.2405 -0.9428 +vn -0.5207 0.2538 0.8151 +vn 0.9774 0.2024 0.0615 +vn -0.1414 0.2704 0.9523 +vn 0.9473 0.2157 -0.2370 +vn -0.9164 0.3124 -0.2501 +vn 0.7456 0.2814 0.6040 +vn -0.9559 0.2741 0.1056 +vn -0.5665 0.1943 0.8008 +vn 0.2464 0.2662 -0.9319 +vn -0.0000 -1.0000 -0.0000 +vt 0.417604 0.024257 +vt 0.396350 0.024257 +vt 0.396350 0.045511 +vt 0.417604 0.045511 +vt 0.394348 0.024257 +vt 0.373094 0.024257 +vt 0.373094 0.045511 +vt 0.394348 0.045511 +vt 0.417604 0.001001 +vt 0.396350 0.001001 +vt 0.396350 0.022255 +vt 0.417604 0.022255 +vt 0.394348 0.001001 +vt 0.373094 0.001001 +vt 0.373094 0.022255 +vt 0.394348 0.022255 +vt 0.464115 0.024257 +vt 0.442861 0.024257 +vt 0.442861 0.045511 +vt 0.464115 0.045511 +vt 0.440859 0.024257 +vt 0.419606 0.024257 +vt 0.419606 0.045511 +vt 0.440859 0.045511 +vt 0.464115 0.001001 +vt 0.442861 0.001001 +vt 0.442861 0.022255 +vt 0.464115 0.022255 +vt 0.440859 0.001001 +vt 0.419606 0.001001 +vt 0.419606 0.022255 +vt 0.440859 0.022255 +vt 0.417604 0.070768 +vt 0.396350 0.070768 +vt 0.396350 0.092022 +vt 0.417604 0.092022 +vt 0.394348 0.070768 +vt 0.373094 0.070768 +vt 0.373094 0.092022 +vt 0.394348 0.092022 +vt 0.417604 0.047513 +vt 0.396350 0.047513 +vt 0.396350 0.068766 +vt 0.417604 0.068766 +vt 0.394348 0.047513 +vt 0.373094 0.047513 +vt 0.373094 0.068766 +vt 0.394348 0.068766 +vt 0.464115 0.070768 +vt 0.442861 0.070768 +vt 0.442861 0.092022 +vt 0.464115 0.092022 +vt 0.440859 0.070768 +vt 0.419606 0.070768 +vt 0.419606 0.092022 +vt 0.440859 0.092022 +vt 0.464115 0.047513 +vt 0.442861 0.047513 +vt 0.442861 0.068766 +vt 0.464115 0.068766 +vt 0.440859 0.047513 +vt 0.419606 0.047513 +vt 0.419606 0.068766 +vt 0.440859 0.068766 +vt 0.324580 0.303327 +vt 0.303327 0.303327 +vt 0.303327 0.324580 +vt 0.324580 0.324580 +vt 0.301325 0.303327 +vt 0.280071 0.303327 +vt 0.280071 0.324580 +vt 0.301325 0.324580 +vt 0.324580 0.280071 +vt 0.303327 0.280071 +vt 0.303327 0.301325 +vt 0.324580 0.301325 +vt 0.301325 0.280071 +vt 0.280071 0.280071 +vt 0.280071 0.301325 +vt 0.301325 0.301325 +vt 0.371092 0.303327 +vt 0.349838 0.303327 +vt 0.349838 0.324580 +vt 0.371092 0.324580 +vt 0.347836 0.303327 +vt 0.326582 0.303327 +vt 0.326582 0.324580 +vt 0.347836 0.324580 +vt 0.371092 0.280071 +vt 0.349838 0.280071 +vt 0.349838 0.301325 +vt 0.371092 0.301325 +vt 0.347836 0.280071 +vt 0.326582 0.280071 +vt 0.326582 0.301325 +vt 0.347836 0.301325 +vt 0.882720 0.373094 +vt 0.838210 0.373094 +vt 0.838210 0.464115 +vt 0.882720 0.464115 +vt 0.278069 0.859464 +vt 0.278069 0.838210 +vt 0.187048 0.838210 +vt 0.187048 0.859464 +vt 0.789697 0.373094 +vt 0.745187 0.373094 +vt 0.745187 0.464115 +vt 0.789697 0.464115 +vt 0.371092 0.696673 +vt 0.371092 0.652164 +vt 0.280071 0.652164 +vt 0.280071 0.696673 +vt 0.929232 0.559141 +vt 0.907978 0.559141 +vt 0.907978 0.650162 +vt 0.929232 0.650162 +vt 0.371092 0.929232 +vt 0.371092 0.907978 +vt 0.280071 0.907978 +vt 0.280071 0.929232 +vt 0.696673 0.001001 +vt 0.652164 0.001001 +vt 0.652164 0.092022 +vt 0.696673 0.092022 +vt 0.464115 0.929232 +vt 0.464115 0.907978 +vt 0.373094 0.907978 +vt 0.373094 0.929232 +vt 0.859464 0.838210 +vt 0.838210 0.838210 +vt 0.838210 0.929232 +vt 0.859464 0.929232 +vt 0.278069 0.650162 +vt 0.278069 0.605652 +vt 0.187048 0.605652 +vt 0.187048 0.650162 +vt 0.952487 0.001001 +vt 0.931234 0.001001 +vt 0.931234 0.092022 +vt 0.952487 0.092022 +vt 0.278069 0.998999 +vt 0.278069 0.977745 +vt 0.187048 0.977745 +vt 0.187048 0.998999 +vt 0.603650 0.094024 +vt 0.559141 0.094024 +vt 0.559141 0.185046 +vt 0.603650 0.185046 +vt 0.557139 0.998999 +vt 0.557139 0.977745 +vt 0.466117 0.977745 +vt 0.466117 0.998999 +vt 0.998999 0.001001 +vt 0.977745 0.001001 +vt 0.977745 0.092022 +vt 0.998999 0.092022 +vt 0.464115 0.998999 +vt 0.464115 0.977745 +vt 0.373094 0.977745 +vt 0.373094 0.998999 +vt 0.417604 0.187048 +vt 0.373094 0.187048 +vt 0.373094 0.278069 +vt 0.417604 0.278069 +vt 0.185046 0.417604 +vt 0.185046 0.373094 +vt 0.094024 0.373094 +vt 0.094024 0.417604 +vt 0.417604 0.094024 +vt 0.373094 0.094024 +vt 0.373094 0.185046 +vt 0.417604 0.185046 +vt 0.371092 0.998999 +vt 0.371092 0.977745 +vt 0.280071 0.977745 +vt 0.280071 0.998999 +vt 0.975743 0.838210 +vt 0.954489 0.838210 +vt 0.954489 0.929232 +vt 0.975743 0.929232 +vt 0.278069 0.417604 +vt 0.278069 0.373094 +vt 0.187048 0.373094 +vt 0.187048 0.417604 +vt 0.975743 0.466117 +vt 0.954489 0.466117 +vt 0.954489 0.557139 +vt 0.975743 0.557139 +vt 0.371092 0.417604 +vt 0.371092 0.373094 +vt 0.280071 0.373094 +vt 0.280071 0.417604 +vt 0.975743 0.373094 +vt 0.954489 0.373094 +vt 0.954489 0.464115 +vt 0.975743 0.464115 +vt 0.185046 0.464115 +vt 0.185046 0.419606 +vt 0.094024 0.419606 +vt 0.094024 0.464115 +vt 0.464115 0.187048 +vt 0.419606 0.187048 +vt 0.419606 0.278069 +vt 0.464115 0.278069 +vt 0.278069 0.464115 +vt 0.278069 0.419606 +vt 0.187048 0.419606 +vt 0.187048 0.464115 +vt 0.464115 0.280071 +vt 0.419606 0.280071 +vt 0.419606 0.371092 +vt 0.464115 0.371092 +vt 0.371092 0.464115 +vt 0.371092 0.419606 +vt 0.280071 0.419606 +vt 0.280071 0.464115 +vt 0.417604 0.373094 +vt 0.373094 0.373094 +vt 0.373094 0.464115 +vt 0.417604 0.464115 +vt 0.743185 0.975743 +vt 0.743185 0.954489 +vt 0.652164 0.954489 +vt 0.652164 0.975743 +vt 0.464115 0.373094 +vt 0.419606 0.373094 +vt 0.419606 0.464115 +vt 0.464115 0.464115 +vt 0.185046 0.510627 +vt 0.185046 0.466117 +vt 0.094024 0.466117 +vt 0.094024 0.510627 +vt 0.510627 0.001001 +vt 0.466117 0.001001 +vt 0.466117 0.092022 +vt 0.510627 0.092022 +vt 0.278069 0.510627 +vt 0.278069 0.466117 +vt 0.187048 0.466117 +vt 0.187048 0.510627 +vt 0.510627 0.094024 +vt 0.466117 0.094024 +vt 0.466117 0.185046 +vt 0.510627 0.185046 +vt 0.371092 0.510627 +vt 0.371092 0.466117 +vt 0.280071 0.466117 +vt 0.280071 0.510627 +vt 0.510627 0.187048 +vt 0.466117 0.187048 +vt 0.466117 0.278069 +vt 0.510627 0.278069 +vt 0.464115 0.510627 +vt 0.464115 0.466117 +vt 0.373094 0.466117 +vt 0.373094 0.510627 +vt 0.510627 0.280071 +vt 0.466117 0.280071 +vt 0.466117 0.371092 +vt 0.510627 0.371092 +vt 0.092022 0.557139 +vt 0.092022 0.512629 +vt 0.001001 0.512629 +vt 0.001001 0.557139 +vt 0.510627 0.373094 +vt 0.466117 0.373094 +vt 0.466117 0.464115 +vt 0.510627 0.464115 +vt 0.185046 0.557139 +vt 0.185046 0.512629 +vt 0.094024 0.512629 +vt 0.094024 0.557139 +vt 0.557139 0.001001 +vt 0.512629 0.001001 +vt 0.512629 0.092022 +vt 0.557139 0.092022 +vt 0.650162 0.975743 +vt 0.650162 0.954489 +vt 0.559141 0.954489 +vt 0.559141 0.975743 +vt 0.975743 0.280071 +vt 0.954489 0.280071 +vt 0.954489 0.371092 +vt 0.975743 0.371092 +vt 0.278069 0.952487 +vt 0.278069 0.931234 +vt 0.187048 0.931234 +vt 0.187048 0.952487 +vt 0.557139 0.373094 +vt 0.512629 0.373094 +vt 0.512629 0.464115 +vt 0.557139 0.464115 +vt 0.278069 0.557139 +vt 0.278069 0.512629 +vt 0.187048 0.512629 +vt 0.187048 0.557139 +vt 0.510627 0.466117 +vt 0.466117 0.466117 +vt 0.466117 0.557139 +vt 0.510627 0.557139 +vt 0.371092 0.557139 +vt 0.371092 0.512629 +vt 0.280071 0.512629 +vt 0.280071 0.557139 +vt 0.557139 0.466117 +vt 0.512629 0.466117 +vt 0.512629 0.557139 +vt 0.557139 0.557139 +vt 0.464115 0.557139 +vt 0.464115 0.512629 +vt 0.373094 0.512629 +vt 0.373094 0.557139 +vt 0.952487 0.094024 +vt 0.931234 0.094024 +vt 0.931234 0.185046 +vt 0.952487 0.185046 +vt 0.371092 0.094024 +vt 0.280071 0.094024 +vt 0.280071 0.185046 +vt 0.371092 0.185046 +vt 0.092022 0.603650 +vt 0.092022 0.559141 +vt 0.001001 0.559141 +vt 0.001001 0.603650 +vt 0.603650 0.187048 +vt 0.559141 0.187048 +vt 0.559141 0.278069 +vt 0.603650 0.278069 +vt 0.185046 0.603650 +vt 0.185046 0.559141 +vt 0.094024 0.559141 +vt 0.094024 0.603650 +vt 0.603650 0.280071 +vt 0.559141 0.280071 +vt 0.559141 0.371092 +vt 0.603650 0.371092 +vt 0.278069 0.603650 +vt 0.278069 0.559141 +vt 0.187048 0.559141 +vt 0.187048 0.603650 +vt 0.603650 0.373094 +vt 0.559141 0.373094 +vt 0.559141 0.464115 +vt 0.603650 0.464115 +vt 0.371092 0.603650 +vt 0.371092 0.559141 +vt 0.280071 0.559141 +vt 0.280071 0.603650 +vt 0.603650 0.466117 +vt 0.559141 0.466117 +vt 0.559141 0.557139 +vt 0.603650 0.557139 +vt 0.324580 0.233559 +vt 0.303327 0.233559 +vt 0.303327 0.278069 +vt 0.324580 0.278069 +vt 0.068766 0.001001 +vt 0.059141 0.001001 +vt 0.059141 0.045511 +vt 0.068766 0.045511 +vt 0.301325 0.233559 +vt 0.280071 0.233559 +vt 0.280071 0.278069 +vt 0.301325 0.278069 +vt 0.057139 0.001001 +vt 0.047513 0.001001 +vt 0.047513 0.045511 +vt 0.057139 0.045511 +vt 0.371092 0.233559 +vt 0.349838 0.233559 +vt 0.349838 0.278069 +vt 0.371092 0.278069 +vt 0.092022 0.001001 +vt 0.082396 0.001001 +vt 0.082396 0.045511 +vt 0.092022 0.045511 +vt 0.347836 0.233559 +vt 0.326582 0.233559 +vt 0.326582 0.278069 +vt 0.347836 0.278069 +vt 0.080394 0.001001 +vt 0.070768 0.001001 +vt 0.070768 0.045511 +vt 0.080394 0.045511 +vt 0.231557 0.280071 +vt 0.210303 0.280071 +vt 0.210303 0.324580 +vt 0.231557 0.324580 +vt 0.208301 0.280071 +vt 0.187048 0.280071 +vt 0.187048 0.324580 +vt 0.208301 0.324580 +vt 0.022255 0.001001 +vt 0.012629 0.001001 +vt 0.012629 0.045511 +vt 0.022255 0.045511 +vt 0.278069 0.280071 +vt 0.256815 0.280071 +vt 0.256815 0.324580 +vt 0.278069 0.324580 +vt 0.254813 0.280071 +vt 0.233559 0.280071 +vt 0.233559 0.324580 +vt 0.254813 0.324580 +vt 0.010627 0.001001 +vt 0.001001 0.001001 +vt 0.001001 0.045511 +vt 0.010627 0.045511 +vt 0.045511 0.001001 +vt 0.035885 0.001001 +vt 0.035885 0.045511 +vt 0.045511 0.045511 +vt 0.231557 0.326582 +vt 0.210303 0.326582 +vt 0.210303 0.371092 +vt 0.231557 0.371092 +vt 0.208301 0.326582 +vt 0.187048 0.326582 +vt 0.187048 0.371092 +vt 0.208301 0.371092 +vt 0.033883 0.001001 +vt 0.024257 0.001001 +vt 0.024257 0.045511 +vt 0.033883 0.045511 +vt 0.068766 0.140536 +vt 0.059141 0.140536 +vt 0.059141 0.185046 +vt 0.068766 0.185046 +vt 0.278069 0.326582 +vt 0.256815 0.326582 +vt 0.256815 0.371092 +vt 0.278069 0.371092 +vt 0.057139 0.140536 +vt 0.047513 0.140536 +vt 0.047513 0.185046 +vt 0.057139 0.185046 +vt 0.092022 0.140536 +vt 0.082396 0.140536 +vt 0.082396 0.185046 +vt 0.092022 0.185046 +vt 0.254813 0.326582 +vt 0.233559 0.326582 +vt 0.233559 0.371092 +vt 0.254813 0.371092 +vt 0.080394 0.140536 +vt 0.070768 0.140536 +vt 0.070768 0.185046 +vt 0.080394 0.185046 +vt 0.138534 0.280071 +vt 0.117280 0.280071 +vt 0.117280 0.324580 +vt 0.138534 0.324580 +vt 0.022255 0.140536 +vt 0.012629 0.140536 +vt 0.012629 0.185046 +vt 0.022255 0.185046 +vt 0.115278 0.280071 +vt 0.094024 0.280071 +vt 0.094024 0.324580 +vt 0.115278 0.324580 +vt 0.010627 0.140536 +vt 0.001001 0.140536 +vt 0.001001 0.185046 +vt 0.010627 0.185046 +vt 0.185046 0.280071 +vt 0.163792 0.280071 +vt 0.163792 0.324580 +vt 0.185046 0.324580 +vt 0.045511 0.140536 +vt 0.035885 0.140536 +vt 0.035885 0.185046 +vt 0.045511 0.185046 +vt 0.161790 0.280071 +vt 0.140536 0.280071 +vt 0.140536 0.324580 +vt 0.161790 0.324580 +vt 0.033883 0.140536 +vt 0.024257 0.140536 +vt 0.024257 0.185046 +vt 0.033883 0.185046 +vt 0.464115 0.603650 +vt 0.464115 0.559141 +vt 0.373094 0.559141 +vt 0.373094 0.603650 +vt 0.650162 0.001001 +vt 0.605652 0.001001 +vt 0.605652 0.092022 +vt 0.650162 0.092022 +vt 0.557139 0.603650 +vt 0.557139 0.559141 +vt 0.466117 0.559141 +vt 0.466117 0.603650 +vt 0.650162 0.094024 +vt 0.605652 0.094024 +vt 0.605652 0.185046 +vt 0.650162 0.185046 +vt 0.092022 0.650162 +vt 0.092022 0.605652 +vt 0.001001 0.605652 +vt 0.001001 0.650162 +vt 0.929232 0.838210 +vt 0.907978 0.838210 +vt 0.907978 0.929232 +vt 0.929232 0.929232 +vt 0.185046 0.650162 +vt 0.185046 0.605652 +vt 0.094024 0.605652 +vt 0.094024 0.650162 +vt 0.650162 0.280071 +vt 0.605652 0.280071 +vt 0.605652 0.371092 +vt 0.650162 0.371092 +vt 0.743185 0.905976 +vt 0.743185 0.884722 +vt 0.652164 0.884722 +vt 0.652164 0.905976 +vt 0.650162 0.373094 +vt 0.605652 0.373094 +vt 0.605652 0.464115 +vt 0.650162 0.464115 +vt 0.650162 0.905976 +vt 0.650162 0.884722 +vt 0.559141 0.884722 +vt 0.559141 0.905976 +vt 0.929232 0.094024 +vt 0.907978 0.094024 +vt 0.907978 0.185046 +vt 0.929232 0.185046 +vt 0.464115 0.905976 +vt 0.464115 0.884722 +vt 0.373094 0.884722 +vt 0.373094 0.905976 +vt 0.603650 0.559141 +vt 0.559141 0.559141 +vt 0.559141 0.650162 +vt 0.603650 0.650162 +vt 0.371092 0.905976 +vt 0.371092 0.884722 +vt 0.280071 0.884722 +vt 0.280071 0.905976 +vt 0.905976 0.745187 +vt 0.884722 0.745187 +vt 0.884722 0.836208 +vt 0.905976 0.836208 +vt 0.092022 0.696673 +vt 0.092022 0.652164 +vt 0.001001 0.652164 +vt 0.001001 0.696673 +vt 0.905976 0.652164 +vt 0.884722 0.652164 +vt 0.884722 0.743185 +vt 0.905976 0.743185 +vt 0.278069 0.905976 +vt 0.278069 0.884722 +vt 0.187048 0.884722 +vt 0.187048 0.905976 +vt 0.905976 0.466117 +vt 0.884722 0.466117 +vt 0.884722 0.557139 +vt 0.905976 0.557139 +vt 0.185046 0.905976 +vt 0.185046 0.884722 +vt 0.094024 0.884722 +vt 0.094024 0.905976 +vt 0.696673 0.187048 +vt 0.652164 0.187048 +vt 0.652164 0.278069 +vt 0.696673 0.278069 +vt 0.092022 0.905976 +vt 0.092022 0.884722 +vt 0.001001 0.884722 +vt 0.001001 0.905976 +vt 0.185046 0.094024 +vt 0.094024 0.094024 +vt 0.094024 0.185046 +vt 0.185046 0.185046 +vt 0.696673 0.373094 +vt 0.652164 0.373094 +vt 0.652164 0.464115 +vt 0.696673 0.464115 +vt 0.464115 0.696673 +vt 0.464115 0.652164 +vt 0.373094 0.652164 +vt 0.373094 0.696673 +vt 0.696673 0.466117 +vt 0.652164 0.466117 +vt 0.652164 0.557139 +vt 0.696673 0.557139 +vt 0.557139 0.696673 +vt 0.557139 0.652164 +vt 0.466117 0.652164 +vt 0.466117 0.696673 +vt 0.905976 0.373094 +vt 0.884722 0.373094 +vt 0.884722 0.464115 +vt 0.905976 0.464115 +vt 0.092022 0.743185 +vt 0.092022 0.698675 +vt 0.001001 0.698675 +vt 0.001001 0.743185 +vt 0.696673 0.559141 +vt 0.652164 0.559141 +vt 0.652164 0.650162 +vt 0.696673 0.650162 +vt 0.185046 0.743185 +vt 0.185046 0.698675 +vt 0.094024 0.698675 +vt 0.094024 0.743185 +vt 0.743185 0.001001 +vt 0.698675 0.001001 +vt 0.698675 0.092022 +vt 0.743185 0.092022 +vt 0.278069 0.743185 +vt 0.278069 0.698675 +vt 0.187048 0.698675 +vt 0.187048 0.743185 +vt 0.743185 0.094024 +vt 0.698675 0.094024 +vt 0.698675 0.185046 +vt 0.743185 0.185046 +vt 0.371092 0.743185 +vt 0.371092 0.698675 +vt 0.280071 0.698675 +vt 0.280071 0.743185 +vt 0.743185 0.187048 +vt 0.698675 0.187048 +vt 0.698675 0.278069 +vt 0.743185 0.278069 +vt 0.464115 0.743185 +vt 0.464115 0.698675 +vt 0.373094 0.698675 +vt 0.373094 0.743185 +vt 0.743185 0.280071 +vt 0.698675 0.280071 +vt 0.698675 0.371092 +vt 0.743185 0.371092 +vt 0.557139 0.743185 +vt 0.557139 0.698675 +vt 0.466117 0.698675 +vt 0.466117 0.743185 +vt 0.743185 0.373094 +vt 0.698675 0.373094 +vt 0.698675 0.464115 +vt 0.743185 0.464115 +vt 0.650162 0.743185 +vt 0.650162 0.698675 +vt 0.559141 0.698675 +vt 0.559141 0.743185 +vt 0.905976 0.280071 +vt 0.884722 0.280071 +vt 0.884722 0.371092 +vt 0.905976 0.371092 +vt 0.743185 0.882720 +vt 0.743185 0.861466 +vt 0.652164 0.861466 +vt 0.652164 0.882720 +vt 0.905976 0.187048 +vt 0.884722 0.187048 +vt 0.884722 0.278069 +vt 0.905976 0.278069 +vt 0.743185 0.743185 +vt 0.743185 0.698675 +vt 0.652164 0.698675 +vt 0.652164 0.743185 +vt 0.789697 0.001001 +vt 0.745187 0.001001 +vt 0.745187 0.092022 +vt 0.789697 0.092022 +vt 0.650162 0.882720 +vt 0.650162 0.861466 +vt 0.559141 0.861466 +vt 0.559141 0.882720 +vt 0.789697 0.187048 +vt 0.745187 0.187048 +vt 0.745187 0.278069 +vt 0.789697 0.278069 +vt 0.092022 0.789697 +vt 0.092022 0.745187 +vt 0.001001 0.745187 +vt 0.001001 0.789697 +vt 0.789697 0.280071 +vt 0.745187 0.280071 +vt 0.745187 0.371092 +vt 0.789697 0.371092 +vt 0.185046 0.789697 +vt 0.185046 0.745187 +vt 0.094024 0.745187 +vt 0.094024 0.789697 +vt 0.905976 0.001001 +vt 0.884722 0.001001 +vt 0.884722 0.092022 +vt 0.905976 0.092022 +vt 0.371092 0.789697 +vt 0.371092 0.745187 +vt 0.280071 0.745187 +vt 0.280071 0.789697 +vt 0.882720 0.652164 +vt 0.861466 0.652164 +vt 0.861466 0.743185 +vt 0.882720 0.743185 +vt 0.185046 0.001001 +vt 0.094024 0.001001 +vt 0.094024 0.092022 +vt 0.185046 0.092022 +vt 0.557139 0.789697 +vt 0.557139 0.745187 +vt 0.466117 0.745187 +vt 0.466117 0.789697 +vt 0.789697 0.466117 +vt 0.745187 0.466117 +vt 0.745187 0.557139 +vt 0.789697 0.557139 +vt 0.650162 0.789697 +vt 0.650162 0.745187 +vt 0.559141 0.745187 +vt 0.559141 0.789697 +vt 0.789697 0.559141 +vt 0.745187 0.559141 +vt 0.745187 0.650162 +vt 0.789697 0.650162 +vt 0.743185 0.789697 +vt 0.743185 0.745187 +vt 0.652164 0.745187 +vt 0.652164 0.789697 +vt 0.789697 0.652164 +vt 0.745187 0.652164 +vt 0.745187 0.743185 +vt 0.789697 0.743185 +vt 0.092022 0.836208 +vt 0.092022 0.791699 +vt 0.001001 0.791699 +vt 0.001001 0.836208 +vt 0.836208 0.001001 +vt 0.791699 0.001001 +vt 0.791699 0.092022 +vt 0.836208 0.092022 +vt 0.068766 0.094024 +vt 0.059141 0.094024 +vt 0.059141 0.138534 +vt 0.068766 0.138534 +vt 0.057139 0.094024 +vt 0.047513 0.094024 +vt 0.047513 0.138534 +vt 0.057139 0.138534 +vt 0.092022 0.094024 +vt 0.082396 0.094024 +vt 0.082396 0.138534 +vt 0.092022 0.138534 +vt 0.080394 0.094024 +vt 0.070768 0.094024 +vt 0.070768 0.138534 +vt 0.080394 0.138534 +vt 0.138534 0.326582 +vt 0.117280 0.326582 +vt 0.117280 0.371092 +vt 0.138534 0.371092 +vt 0.022255 0.094024 +vt 0.012629 0.094024 +vt 0.012629 0.138534 +vt 0.022255 0.138534 +vt 0.115278 0.326582 +vt 0.094024 0.326582 +vt 0.094024 0.371092 +vt 0.115278 0.371092 +vt 0.010627 0.094024 +vt 0.001001 0.094024 +vt 0.001001 0.138534 +vt 0.010627 0.138534 +vt 0.045511 0.094024 +vt 0.035885 0.094024 +vt 0.035885 0.138534 +vt 0.045511 0.138534 +vt 0.185046 0.326582 +vt 0.163792 0.326582 +vt 0.163792 0.371092 +vt 0.185046 0.371092 +vt 0.033883 0.094024 +vt 0.024257 0.094024 +vt 0.024257 0.138534 +vt 0.033883 0.138534 +vt 0.068766 0.233559 +vt 0.059141 0.233559 +vt 0.059141 0.278069 +vt 0.068766 0.278069 +vt 0.161790 0.326582 +vt 0.140536 0.326582 +vt 0.140536 0.371092 +vt 0.161790 0.371092 +vt 0.057139 0.233559 +vt 0.047513 0.233559 +vt 0.047513 0.278069 +vt 0.057139 0.278069 +vt 0.092022 0.233559 +vt 0.082396 0.233559 +vt 0.082396 0.278069 +vt 0.092022 0.278069 +vt 0.080394 0.233559 +vt 0.070768 0.233559 +vt 0.070768 0.278069 +vt 0.080394 0.278069 +vt 0.324580 0.001001 +vt 0.303327 0.001001 +vt 0.303327 0.045511 +vt 0.324580 0.045511 +vt 0.022255 0.233559 +vt 0.012629 0.233559 +vt 0.012629 0.278069 +vt 0.022255 0.278069 +vt 0.010627 0.233559 +vt 0.001001 0.233559 +vt 0.001001 0.278069 +vt 0.010627 0.278069 +vt 0.045511 0.233559 +vt 0.035885 0.233559 +vt 0.035885 0.278069 +vt 0.045511 0.278069 +vt 0.033883 0.233559 +vt 0.024257 0.233559 +vt 0.024257 0.278069 +vt 0.033883 0.278069 +vt 0.068766 0.187048 +vt 0.059141 0.187048 +vt 0.059141 0.231557 +vt 0.068766 0.231557 +vt 0.057139 0.187048 +vt 0.047513 0.187048 +vt 0.047513 0.231557 +vt 0.057139 0.231557 +vt 0.092022 0.187048 +vt 0.082396 0.187048 +vt 0.082396 0.231557 +vt 0.092022 0.231557 +vt 0.301325 0.001001 +vt 0.280071 0.001001 +vt 0.280071 0.045511 +vt 0.301325 0.045511 +vt 0.080394 0.187048 +vt 0.070768 0.187048 +vt 0.070768 0.231557 +vt 0.080394 0.231557 +vt 0.371092 0.001001 +vt 0.349838 0.001001 +vt 0.349838 0.045511 +vt 0.371092 0.045511 +vt 0.022255 0.187048 +vt 0.012629 0.187048 +vt 0.012629 0.231557 +vt 0.022255 0.231557 +vt 0.347836 0.001001 +vt 0.326582 0.001001 +vt 0.326582 0.045511 +vt 0.347836 0.045511 +vt 0.010627 0.187048 +vt 0.001001 0.187048 +vt 0.001001 0.231557 +vt 0.010627 0.231557 +vt 0.324580 0.047513 +vt 0.303327 0.047513 +vt 0.303327 0.092022 +vt 0.324580 0.092022 +vt 0.045511 0.187048 +vt 0.035885 0.187048 +vt 0.035885 0.231557 +vt 0.045511 0.231557 +vt 0.185046 0.836208 +vt 0.185046 0.791699 +vt 0.094024 0.791699 +vt 0.094024 0.836208 +vt 0.882720 0.559141 +vt 0.861466 0.559141 +vt 0.861466 0.650162 +vt 0.882720 0.650162 +vt 0.371092 0.882720 +vt 0.371092 0.861466 +vt 0.280071 0.861466 +vt 0.280071 0.882720 +vt 0.836208 0.280071 +vt 0.791699 0.280071 +vt 0.791699 0.371092 +vt 0.836208 0.371092 +vt 0.278069 0.882720 +vt 0.278069 0.861466 +vt 0.187048 0.861466 +vt 0.187048 0.882720 +vt 0.882720 0.466117 +vt 0.861466 0.466117 +vt 0.861466 0.557139 +vt 0.882720 0.557139 +vt 0.371092 0.836208 +vt 0.371092 0.791699 +vt 0.280071 0.791699 +vt 0.280071 0.836208 +vt 0.859464 0.745187 +vt 0.838210 0.745187 +vt 0.838210 0.836208 +vt 0.859464 0.836208 +vt 0.836208 0.859464 +vt 0.836208 0.838210 +vt 0.745187 0.838210 +vt 0.745187 0.859464 +vt 0.836208 0.559141 +vt 0.791699 0.559141 +vt 0.791699 0.650162 +vt 0.836208 0.650162 +vt 0.464115 0.859464 +vt 0.464115 0.838210 +vt 0.373094 0.838210 +vt 0.373094 0.859464 +vt 0.859464 0.466117 +vt 0.838210 0.466117 +vt 0.838210 0.557139 +vt 0.859464 0.557139 +vt 0.371092 0.859464 +vt 0.371092 0.838210 +vt 0.280071 0.838210 +vt 0.280071 0.859464 +vt 0.836208 0.745187 +vt 0.791699 0.745187 +vt 0.791699 0.836208 +vt 0.836208 0.836208 +vt 0.650162 0.836208 +vt 0.650162 0.791699 +vt 0.559141 0.791699 +vt 0.559141 0.836208 +vt 0.987371 0.280071 +vt 0.977745 0.280071 +vt 0.977745 0.371092 +vt 0.987371 0.371092 +vt 0.743185 0.836208 +vt 0.743185 0.791699 +vt 0.652164 0.791699 +vt 0.652164 0.836208 +vt 0.882720 0.094024 +vt 0.838210 0.094024 +vt 0.838210 0.185046 +vt 0.882720 0.185046 +vt 0.092022 0.882720 +vt 0.092022 0.838210 +vt 0.001001 0.838210 +vt 0.001001 0.882720 +vt 0.882720 0.187048 +vt 0.838210 0.187048 +vt 0.838210 0.278069 +vt 0.882720 0.278069 +vt 0.185046 0.882720 +vt 0.185046 0.838210 +vt 0.094024 0.838210 +vt 0.094024 0.882720 +vt 0.882720 0.280071 +vt 0.838210 0.280071 +vt 0.838210 0.371092 +vt 0.882720 0.371092 +vt 0.929232 0.987371 +vt 0.929232 0.977745 +vt 0.838210 0.977745 +vt 0.838210 0.987371 +vt 0.092022 0.280071 +vt 0.001001 0.280071 +vt 0.001001 0.371092 +vt 0.092022 0.371092 +vt 0.789697 0.745187 +vt 0.745187 0.745187 +vt 0.745187 0.836208 +vt 0.789697 0.836208 +vt 0.557139 0.836208 +vt 0.557139 0.791699 +vt 0.466117 0.791699 +vt 0.466117 0.836208 +vt 0.836208 0.652164 +vt 0.791699 0.652164 +vt 0.791699 0.743185 +vt 0.836208 0.743185 +vt 0.557139 0.859464 +vt 0.557139 0.838210 +vt 0.466117 0.838210 +vt 0.466117 0.859464 +vt 0.859464 0.559141 +vt 0.838210 0.559141 +vt 0.838210 0.650162 +vt 0.859464 0.650162 +vt 0.650162 0.859464 +vt 0.650162 0.838210 +vt 0.559141 0.838210 +vt 0.559141 0.859464 +vt 0.859464 0.652164 +vt 0.838210 0.652164 +vt 0.838210 0.743185 +vt 0.859464 0.743185 +vt 0.743185 0.859464 +vt 0.743185 0.838210 +vt 0.652164 0.838210 +vt 0.652164 0.859464 +vt 0.836208 0.466117 +vt 0.791699 0.466117 +vt 0.791699 0.557139 +vt 0.836208 0.557139 +vt 0.464115 0.836208 +vt 0.464115 0.791699 +vt 0.373094 0.791699 +vt 0.373094 0.836208 +vt 0.836208 0.373094 +vt 0.791699 0.373094 +vt 0.791699 0.464115 +vt 0.836208 0.464115 +vt 0.278069 0.836208 +vt 0.278069 0.791699 +vt 0.187048 0.791699 +vt 0.187048 0.836208 +vt 0.836208 0.187048 +vt 0.791699 0.187048 +vt 0.791699 0.278069 +vt 0.836208 0.278069 +vt 0.464115 0.882720 +vt 0.464115 0.861466 +vt 0.373094 0.861466 +vt 0.373094 0.882720 +vt 0.836208 0.094024 +vt 0.791699 0.094024 +vt 0.791699 0.185046 +vt 0.836208 0.185046 +vt 0.464115 0.789697 +vt 0.464115 0.745187 +vt 0.373094 0.745187 +vt 0.373094 0.789697 +vt 0.882720 0.745187 +vt 0.861466 0.745187 +vt 0.861466 0.836208 +vt 0.882720 0.836208 +vt 0.278069 0.789697 +vt 0.278069 0.745187 +vt 0.187048 0.745187 +vt 0.187048 0.789697 +vt 0.905976 0.094024 +vt 0.884722 0.094024 +vt 0.884722 0.185046 +vt 0.905976 0.185046 +vt 0.557139 0.882720 +vt 0.557139 0.861466 +vt 0.466117 0.861466 +vt 0.466117 0.882720 +vt 0.789697 0.094024 +vt 0.745187 0.094024 +vt 0.745187 0.185046 +vt 0.789697 0.185046 +vt 0.743185 0.696673 +vt 0.743185 0.652164 +vt 0.652164 0.652164 +vt 0.652164 0.696673 +vt 0.743185 0.559141 +vt 0.698675 0.559141 +vt 0.698675 0.650162 +vt 0.743185 0.650162 +vt 0.836208 0.882720 +vt 0.836208 0.861466 +vt 0.745187 0.861466 +vt 0.745187 0.882720 +vt 0.743185 0.466117 +vt 0.698675 0.466117 +vt 0.698675 0.557139 +vt 0.743185 0.557139 +vt 0.650162 0.696673 +vt 0.650162 0.652164 +vt 0.559141 0.652164 +vt 0.559141 0.696673 +vt 0.696673 0.280071 +vt 0.652164 0.280071 +vt 0.652164 0.371092 +vt 0.696673 0.371092 +vt 0.278069 0.696673 +vt 0.278069 0.652164 +vt 0.187048 0.652164 +vt 0.187048 0.696673 +vt 0.696673 0.094024 +vt 0.652164 0.094024 +vt 0.652164 0.185046 +vt 0.696673 0.185046 +vt 0.185046 0.696673 +vt 0.185046 0.652164 +vt 0.094024 0.652164 +vt 0.094024 0.696673 +vt 0.905976 0.559141 +vt 0.884722 0.559141 +vt 0.884722 0.650162 +vt 0.905976 0.650162 +vt 0.278069 0.094024 +vt 0.187048 0.094024 +vt 0.187048 0.185046 +vt 0.278069 0.185046 +vt 0.557139 0.650162 +vt 0.557139 0.605652 +vt 0.466117 0.605652 +vt 0.466117 0.650162 +vt 0.650162 0.559141 +vt 0.605652 0.559141 +vt 0.605652 0.650162 +vt 0.650162 0.650162 +vt 0.464115 0.650162 +vt 0.464115 0.605652 +vt 0.373094 0.605652 +vt 0.373094 0.650162 +vt 0.929232 0.001001 +vt 0.907978 0.001001 +vt 0.907978 0.092022 +vt 0.929232 0.092022 +vt 0.557139 0.905976 +vt 0.557139 0.884722 +vt 0.466117 0.884722 +vt 0.466117 0.905976 +vt 0.650162 0.466117 +vt 0.605652 0.466117 +vt 0.605652 0.557139 +vt 0.650162 0.557139 +vt 0.371092 0.650162 +vt 0.371092 0.605652 +vt 0.280071 0.605652 +vt 0.280071 0.650162 +vt 0.882720 0.001001 +vt 0.838210 0.001001 +vt 0.838210 0.092022 +vt 0.882720 0.092022 +vt 0.033883 0.187048 +vt 0.024257 0.187048 +vt 0.024257 0.231557 +vt 0.033883 0.231557 +vt 0.254813 0.047513 +vt 0.245187 0.047513 +vt 0.245187 0.092022 +vt 0.254813 0.092022 +vt 0.243185 0.047513 +vt 0.233559 0.047513 +vt 0.233559 0.092022 +vt 0.243185 0.092022 +vt 0.278069 0.047513 +vt 0.268443 0.047513 +vt 0.268443 0.092022 +vt 0.278069 0.092022 +vt 0.266441 0.047513 +vt 0.256815 0.047513 +vt 0.256815 0.092022 +vt 0.266441 0.092022 +vt 0.208301 0.047513 +vt 0.198675 0.047513 +vt 0.198675 0.092022 +vt 0.208301 0.092022 +vt 0.196673 0.047513 +vt 0.187048 0.047513 +vt 0.187048 0.092022 +vt 0.196673 0.092022 +vt 0.231557 0.047513 +vt 0.221931 0.047513 +vt 0.221931 0.092022 +vt 0.231557 0.092022 +vt 0.219929 0.047513 +vt 0.210303 0.047513 +vt 0.210303 0.092022 +vt 0.219929 0.092022 +vt 0.254813 0.001001 +vt 0.245187 0.001001 +vt 0.245187 0.045511 +vt 0.254813 0.045511 +vt 0.243185 0.001001 +vt 0.233559 0.001001 +vt 0.233559 0.045511 +vt 0.243185 0.045511 +vt 0.278069 0.001001 +vt 0.268443 0.001001 +vt 0.268443 0.045511 +vt 0.278069 0.045511 +vt 0.266441 0.001001 +vt 0.256815 0.001001 +vt 0.256815 0.045511 +vt 0.266441 0.045511 +vt 0.208301 0.001001 +vt 0.198675 0.001001 +vt 0.198675 0.045511 +vt 0.208301 0.045511 +vt 0.196673 0.001001 +vt 0.187048 0.001001 +vt 0.187048 0.045511 +vt 0.196673 0.045511 +vt 0.231557 0.001001 +vt 0.221931 0.001001 +vt 0.221931 0.045511 +vt 0.231557 0.045511 +vt 0.219929 0.001001 +vt 0.210303 0.001001 +vt 0.210303 0.045511 +vt 0.219929 0.045511 +vt 0.161790 0.233559 +vt 0.152164 0.233559 +vt 0.152164 0.278069 +vt 0.161790 0.278069 +vt 0.150162 0.233559 +vt 0.140536 0.233559 +vt 0.140536 0.278069 +vt 0.150162 0.278069 +vt 0.185046 0.233559 +vt 0.175420 0.233559 +vt 0.175420 0.278069 +vt 0.185046 0.278069 +vt 0.173418 0.233559 +vt 0.163792 0.233559 +vt 0.163792 0.278069 +vt 0.173418 0.278069 +vt 0.115278 0.233559 +vt 0.105652 0.233559 +vt 0.105652 0.278069 +vt 0.115278 0.278069 +vt 0.103650 0.233559 +vt 0.094024 0.233559 +vt 0.094024 0.278069 +vt 0.103650 0.278069 +vt 0.138534 0.233559 +vt 0.128908 0.233559 +vt 0.128908 0.278069 +vt 0.138534 0.278069 +vt 0.126906 0.233559 +vt 0.117280 0.233559 +vt 0.117280 0.278069 +vt 0.126906 0.278069 +vt 0.161790 0.187048 +vt 0.152164 0.187048 +vt 0.152164 0.231557 +vt 0.161790 0.231557 +vt 0.150162 0.187048 +vt 0.140536 0.187048 +vt 0.140536 0.231557 +vt 0.150162 0.231557 +vt 0.185046 0.187048 +vt 0.175420 0.187048 +vt 0.175420 0.231557 +vt 0.185046 0.231557 +vt 0.173418 0.187048 +vt 0.163792 0.187048 +vt 0.163792 0.231557 +vt 0.173418 0.231557 +vt 0.115278 0.187048 +vt 0.105652 0.187048 +vt 0.105652 0.231557 +vt 0.115278 0.231557 +vt 0.103650 0.187048 +vt 0.094024 0.187048 +vt 0.094024 0.231557 +vt 0.103650 0.231557 +vt 0.138534 0.187048 +vt 0.128908 0.187048 +vt 0.128908 0.231557 +vt 0.138534 0.231557 +vt 0.836208 0.905976 +vt 0.836208 0.884722 +vt 0.745187 0.884722 +vt 0.745187 0.905976 +vt 0.929232 0.187048 +vt 0.907978 0.187048 +vt 0.907978 0.278069 +vt 0.929232 0.278069 +vt 0.092022 0.929232 +vt 0.092022 0.907978 +vt 0.001001 0.907978 +vt 0.001001 0.929232 +vt 0.929232 0.280071 +vt 0.907978 0.280071 +vt 0.907978 0.371092 +vt 0.929232 0.371092 +vt 0.185046 0.929232 +vt 0.185046 0.907978 +vt 0.094024 0.907978 +vt 0.094024 0.929232 +vt 0.929232 0.373094 +vt 0.907978 0.373094 +vt 0.907978 0.464115 +vt 0.929232 0.464115 +vt 0.278069 0.929232 +vt 0.278069 0.907978 +vt 0.187048 0.907978 +vt 0.187048 0.929232 +vt 0.929232 0.466117 +vt 0.907978 0.466117 +vt 0.907978 0.557139 +vt 0.929232 0.557139 +vt 0.836208 0.987371 +vt 0.836208 0.977745 +vt 0.745187 0.977745 +vt 0.745187 0.987371 +vt 0.929232 0.652164 +vt 0.907978 0.652164 +vt 0.907978 0.743185 +vt 0.929232 0.743185 +vt 0.743185 0.987371 +vt 0.743185 0.977745 +vt 0.652164 0.977745 +vt 0.652164 0.987371 +vt 0.987371 0.187048 +vt 0.977745 0.187048 +vt 0.977745 0.278069 +vt 0.987371 0.278069 +vt 0.557139 0.929232 +vt 0.557139 0.907978 +vt 0.466117 0.907978 +vt 0.466117 0.929232 +vt 0.929232 0.745187 +vt 0.907978 0.745187 +vt 0.907978 0.836208 +vt 0.929232 0.836208 +vt 0.650162 0.929232 +vt 0.650162 0.907978 +vt 0.559141 0.907978 +vt 0.559141 0.929232 +vt 0.987371 0.094024 +vt 0.977745 0.094024 +vt 0.977745 0.185046 +vt 0.987371 0.185046 +vt 0.743185 0.929232 +vt 0.743185 0.907978 +vt 0.652164 0.907978 +vt 0.652164 0.929232 +vt 0.882720 0.838210 +vt 0.861466 0.838210 +vt 0.861466 0.929232 +vt 0.882720 0.929232 +vt 0.836208 0.929232 +vt 0.836208 0.907978 +vt 0.745187 0.907978 +vt 0.745187 0.929232 +vt 0.905976 0.838210 +vt 0.884722 0.838210 +vt 0.884722 0.929232 +vt 0.905976 0.929232 +vt 0.092022 0.952487 +vt 0.092022 0.931234 +vt 0.001001 0.931234 +vt 0.001001 0.952487 +vt 0.650162 0.187048 +vt 0.605652 0.187048 +vt 0.605652 0.278069 +vt 0.650162 0.278069 +vt 0.650162 0.987371 +vt 0.650162 0.977745 +vt 0.559141 0.977745 +vt 0.559141 0.987371 +vt 0.603650 0.001001 +vt 0.559141 0.001001 +vt 0.559141 0.092022 +vt 0.603650 0.092022 +vt 0.185046 0.952487 +vt 0.185046 0.931234 +vt 0.094024 0.931234 +vt 0.094024 0.952487 +vt 0.557139 0.280071 +vt 0.512629 0.280071 +vt 0.512629 0.371092 +vt 0.557139 0.371092 +vt 0.371092 0.952487 +vt 0.371092 0.931234 +vt 0.280071 0.931234 +vt 0.280071 0.952487 +vt 0.952487 0.187048 +vt 0.931234 0.187048 +vt 0.931234 0.278069 +vt 0.952487 0.278069 +vt 0.464115 0.952487 +vt 0.464115 0.931234 +vt 0.373094 0.931234 +vt 0.373094 0.952487 +vt 0.952487 0.280071 +vt 0.931234 0.280071 +vt 0.931234 0.371092 +vt 0.952487 0.371092 +vt 0.557139 0.952487 +vt 0.557139 0.931234 +vt 0.466117 0.931234 +vt 0.466117 0.952487 +vt 0.952487 0.373094 +vt 0.931234 0.373094 +vt 0.931234 0.464115 +vt 0.952487 0.464115 +vt 0.650162 0.952487 +vt 0.650162 0.931234 +vt 0.559141 0.931234 +vt 0.559141 0.952487 +vt 0.952487 0.466117 +vt 0.931234 0.466117 +vt 0.931234 0.557139 +vt 0.952487 0.557139 +vt 0.743185 0.952487 +vt 0.743185 0.931234 +vt 0.652164 0.931234 +vt 0.652164 0.952487 +vt 0.952487 0.559141 +vt 0.931234 0.559141 +vt 0.931234 0.650162 +vt 0.952487 0.650162 +vt 0.836208 0.952487 +vt 0.836208 0.931234 +vt 0.745187 0.931234 +vt 0.745187 0.952487 +vt 0.952487 0.652164 +vt 0.931234 0.652164 +vt 0.931234 0.743185 +vt 0.952487 0.743185 +vt 0.929232 0.952487 +vt 0.929232 0.931234 +vt 0.838210 0.931234 +vt 0.838210 0.952487 +vt 0.952487 0.745187 +vt 0.931234 0.745187 +vt 0.931234 0.836208 +vt 0.952487 0.836208 +vt 0.092022 0.975743 +vt 0.092022 0.954489 +vt 0.001001 0.954489 +vt 0.001001 0.975743 +vt 0.952487 0.838210 +vt 0.931234 0.838210 +vt 0.931234 0.929232 +vt 0.952487 0.929232 +vt 0.185046 0.975743 +vt 0.185046 0.954489 +vt 0.094024 0.954489 +vt 0.094024 0.975743 +vt 0.975743 0.001001 +vt 0.954489 0.001001 +vt 0.954489 0.092022 +vt 0.975743 0.092022 +vt 0.278069 0.975743 +vt 0.278069 0.954489 +vt 0.187048 0.954489 +vt 0.187048 0.975743 +vt 0.975743 0.094024 +vt 0.954489 0.094024 +vt 0.954489 0.185046 +vt 0.975743 0.185046 +vt 0.371092 0.975743 +vt 0.371092 0.954489 +vt 0.280071 0.954489 +vt 0.280071 0.975743 +vt 0.126906 0.187048 +vt 0.117280 0.187048 +vt 0.117280 0.231557 +vt 0.126906 0.231557 +vt 0.975743 0.187048 +vt 0.954489 0.187048 +vt 0.954489 0.278069 +vt 0.975743 0.278069 +vt 0.464115 0.975743 +vt 0.464115 0.954489 +vt 0.373094 0.954489 +vt 0.373094 0.975743 +vt 0.557139 0.187048 +vt 0.512629 0.187048 +vt 0.512629 0.278069 +vt 0.557139 0.278069 +vt 0.557139 0.975743 +vt 0.557139 0.954489 +vt 0.466117 0.954489 +vt 0.466117 0.975743 +vt 0.557139 0.094024 +vt 0.512629 0.094024 +vt 0.512629 0.185046 +vt 0.557139 0.185046 +vt 0.092022 0.510627 +vt 0.092022 0.466117 +vt 0.001001 0.466117 +vt 0.001001 0.510627 +vt 0.975743 0.952487 +vt 0.975743 0.942861 +vt 0.931234 0.942861 +vt 0.931234 0.952487 +vt 0.464115 0.094024 +vt 0.419606 0.094024 +vt 0.419606 0.185046 +vt 0.464115 0.185046 +vt 0.836208 0.975743 +vt 0.836208 0.954489 +vt 0.745187 0.954489 +vt 0.745187 0.975743 +vt 0.417604 0.280071 +vt 0.373094 0.280071 +vt 0.373094 0.371092 +vt 0.417604 0.371092 +vt 0.929232 0.975743 +vt 0.929232 0.954489 +vt 0.838210 0.954489 +vt 0.838210 0.975743 +vt 0.975743 0.559141 +vt 0.954489 0.559141 +vt 0.954489 0.650162 +vt 0.975743 0.650162 +vt 0.092022 0.998999 +vt 0.092022 0.977745 +vt 0.001001 0.977745 +vt 0.001001 0.998999 +vt 0.975743 0.652164 +vt 0.954489 0.652164 +vt 0.954489 0.743185 +vt 0.975743 0.743185 +vt 0.185046 0.998999 +vt 0.185046 0.977745 +vt 0.094024 0.977745 +vt 0.094024 0.998999 +vt 0.975743 0.745187 +vt 0.954489 0.745187 +vt 0.954489 0.836208 +vt 0.975743 0.836208 +vt 0.347836 0.187048 +vt 0.338210 0.187048 +vt 0.338210 0.208301 +vt 0.347836 0.208301 +vt 0.336208 0.187048 +vt 0.326582 0.187048 +vt 0.326582 0.208301 +vt 0.336208 0.208301 +vt 0.371092 0.187048 +vt 0.361466 0.187048 +vt 0.361466 0.208301 +vt 0.371092 0.208301 +vt 0.359464 0.187048 +vt 0.349838 0.187048 +vt 0.349838 0.208301 +vt 0.359464 0.208301 +vt 0.347836 0.210303 +vt 0.338210 0.210303 +vt 0.338210 0.231557 +vt 0.347836 0.231557 +vt 0.336208 0.210303 +vt 0.326582 0.210303 +vt 0.326582 0.231557 +vt 0.336208 0.231557 +vt 0.371092 0.210303 +vt 0.361466 0.210303 +vt 0.361466 0.231557 +vt 0.371092 0.231557 +vt 0.359464 0.210303 +vt 0.349838 0.210303 +vt 0.349838 0.231557 +vt 0.359464 0.231557 +vt 0.301325 0.187048 +vt 0.291699 0.187048 +vt 0.291699 0.208301 +vt 0.301325 0.208301 +vt 0.289697 0.187048 +vt 0.280071 0.187048 +vt 0.280071 0.208301 +vt 0.289697 0.208301 +vt 0.324580 0.187048 +vt 0.314954 0.187048 +vt 0.314954 0.208301 +vt 0.324580 0.208301 +vt 0.312952 0.187048 +vt 0.303327 0.187048 +vt 0.303327 0.208301 +vt 0.312952 0.208301 +vt 0.301325 0.210303 +vt 0.291699 0.210303 +vt 0.291699 0.231557 +vt 0.301325 0.231557 +vt 0.289697 0.210303 +vt 0.280071 0.210303 +vt 0.280071 0.231557 +vt 0.289697 0.231557 +vt 0.324580 0.210303 +vt 0.314954 0.210303 +vt 0.314954 0.231557 +vt 0.324580 0.231557 +vt 0.312952 0.210303 +vt 0.303327 0.210303 +vt 0.303327 0.231557 +vt 0.312952 0.231557 +vt 0.347836 0.326582 +vt 0.338210 0.326582 +vt 0.338210 0.347836 +vt 0.347836 0.347836 +vt 0.336208 0.326582 +vt 0.326582 0.326582 +vt 0.326582 0.347836 +vt 0.336208 0.347836 +vt 0.371092 0.326582 +vt 0.361466 0.326582 +vt 0.361466 0.347836 +vt 0.371092 0.347836 +vt 0.359464 0.326582 +vt 0.349838 0.326582 +vt 0.349838 0.347836 +vt 0.359464 0.347836 +vt 0.347836 0.349838 +vt 0.338210 0.349838 +vt 0.338210 0.371092 +vt 0.347836 0.371092 +vt 0.336208 0.349838 +vt 0.326582 0.349838 +vt 0.326582 0.371092 +vt 0.336208 0.371092 +vt 0.371092 0.349838 +vt 0.361466 0.349838 +vt 0.361466 0.371092 +vt 0.371092 0.371092 +vt 0.359464 0.349838 +vt 0.349838 0.349838 +vt 0.349838 0.371092 +vt 0.359464 0.371092 +vt 0.301325 0.326582 +vt 0.291699 0.326582 +vt 0.291699 0.347836 +vt 0.301325 0.347836 +vt 0.289697 0.326582 +vt 0.280071 0.326582 +vt 0.280071 0.347836 +vt 0.289697 0.347836 +vt 0.324580 0.326582 +vt 0.314954 0.326582 +vt 0.314954 0.347836 +vt 0.324580 0.347836 +vt 0.312952 0.326582 +vt 0.303327 0.326582 +vt 0.303327 0.347836 +vt 0.312952 0.347836 +vt 0.301325 0.349838 +vt 0.291699 0.349838 +vt 0.291699 0.371092 +vt 0.301325 0.371092 +vt 0.289697 0.349838 +vt 0.280071 0.349838 +vt 0.280071 0.371092 +vt 0.289697 0.371092 +vt 0.324580 0.349838 +vt 0.314954 0.349838 +vt 0.314954 0.371092 +vt 0.324580 0.371092 +vt 0.312952 0.349838 +vt 0.303327 0.349838 +vt 0.303327 0.371092 +vt 0.312952 0.371092 +vt 0.931234 0.939858 +vt 0.931234 0.931234 +vt 0.974742 0.931234 +vt 0.301325 0.092022 +vt 0.301325 0.047513 +vt 0.280071 0.047513 +vt 0.280071 0.092022 +vt 0.278069 0.278069 +vt 0.257816 0.278069 +vt 0.278069 0.234560 +vt 0.371092 0.092022 +vt 0.371092 0.047513 +vt 0.349838 0.047513 +vt 0.349838 0.092022 +vt 0.234560 0.278069 +vt 0.254813 0.278069 +vt 0.254813 0.234560 +vt 0.347836 0.092022 +vt 0.347836 0.047513 +vt 0.326582 0.047513 +vt 0.326582 0.092022 +vt 0.211304 0.278069 +vt 0.231557 0.278069 +vt 0.231557 0.234560 +vt 0.231557 0.231557 +vt 0.231557 0.187048 +vt 0.210303 0.187048 +vt 0.210303 0.231557 +vt 0.233559 0.233559 +vt 0.253812 0.233559 +vt 0.233559 0.277068 +vt 0.208301 0.231557 +vt 0.208301 0.187048 +vt 0.187048 0.187048 +vt 0.187048 0.231557 +vt 0.208301 0.278069 +vt 0.188049 0.278069 +vt 0.208301 0.234560 +vt 0.278069 0.231557 +vt 0.278069 0.187048 +vt 0.256815 0.187048 +vt 0.256815 0.231557 +vt 0.277068 0.233559 +vt 0.256815 0.233559 +vt 0.256815 0.277068 +vt 0.254813 0.231557 +vt 0.254813 0.187048 +vt 0.233559 0.187048 +vt 0.233559 0.231557 +vt 0.207300 0.233559 +vt 0.187048 0.233559 +vt 0.187048 0.277068 +vt 0.092022 0.047513 +vt 0.047513 0.047513 +vt 0.047513 0.092022 +vt 0.092022 0.092022 +vt 0.210303 0.233559 +vt 0.230556 0.233559 +vt 0.210303 0.277068 +vt 0.045511 0.047513 +vt 0.001001 0.047513 +vt 0.001001 0.092022 +vt 0.045511 0.092022 +vt 0.051087 0.456093 +vt 0.013166 0.464115 +vt 0.012128 0.431160 +vt 0.001001 0.401664 +vt 0.021542 0.373094 +vt 0.056841 0.388956 +vt 0.092022 0.389663 +vt 0.084274 0.424768 +vt 0.092022 0.462702 +s 0 +usemtl tre__fin_ +f 29/1/1 19/2/1 12/3/1 7/4/1 +f 25/5/2 23/6/2 20/7/2 32/8/2 +f 10/9/3 5/10/3 2/11/3 13/12/3 +f 4/13/4 15/14/4 24/15/4 28/16/4 +f 7/17/5 12/18/5 11/19/5 6/20/5 +f 3/21/6 14/22/6 13/23/6 2/24/6 +f 26/25/7 22/26/7 21/27/7 27/28/7 +f 30/29/8 18/30/8 17/31/8 31/32/8 +f 6/33/9 11/34/9 16/35/9 1/36/9 +f 5/37/3 6/38/3 1/39/3 2/40/3 +f 19/41/10 29/42/10 32/43/10 20/44/10 +f 29/45/11 30/46/11 31/47/11 32/48/11 +f 23/49/12 25/50/12 28/51/12 24/52/12 +f 25/53/13 26/54/13 27/55/13 28/56/13 +f 15/57/14 4/58/14 1/59/14 16/60/14 +f 4/61/15 3/62/15 2/63/15 1/64/15 +f 9/65/16 8/66/16 5/67/16 10/68/16 +f 8/69/17 7/70/17 6/71/17 5/72/17 +f 14/73/18 3/74/18 27/75/18 21/76/18 +f 3/77/19 4/78/19 28/79/19 27/80/19 +f 22/81/20 26/82/20 31/83/20 17/84/20 +f 26/85/20 25/86/20 32/87/20 31/88/20 +f 18/89/21 30/90/21 8/91/21 9/92/21 +f 30/93/22 29/94/22 7/95/22 8/96/22 +f 46/97/23 45/98/23 77/99/23 78/100/23 +f 60/101/24 59/102/24 91/103/24 92/104/24 +f 47/105/25 46/106/25 78/107/25 79/108/25 +f 34/109/26 33/110/26 65/111/26 66/112/26 +f 61/113/27 60/114/27 92/115/27 93/116/27 +f 48/117/28 47/118/28 79/119/28 80/120/28 +f 35/121/29 34/122/29 66/123/29 67/124/29 +f 62/125/30 61/126/30 93/127/30 94/128/30 +f 49/129/31 48/130/31 80/131/31 81/132/31 +f 36/133/32 35/134/32 67/135/32 68/136/32 +f 63/137/33 62/138/33 94/139/33 95/140/33 +f 50/141/34 49/142/34 81/143/34 82/144/34 +f 37/145/35 36/146/35 68/147/35 69/148/35 +f 64/149/36 63/150/36 95/151/36 96/152/36 +f 51/153/37 50/154/37 82/155/37 83/156/37 +f 38/157/38 37/158/38 69/159/38 70/160/38 +f 33/161/39 64/162/39 96/163/39 65/164/39 +f 52/165/40 51/166/40 83/167/40 84/168/40 +f 39/169/41 38/170/41 70/171/41 71/172/41 +f 53/173/42 52/174/42 84/175/42 85/176/42 +f 40/177/43 39/178/43 71/179/43 72/180/43 +f 54/181/44 53/182/44 85/183/44 86/184/44 +f 41/185/45 40/186/45 72/187/45 73/188/45 +f 55/189/46 54/190/46 86/191/46 87/192/46 +f 42/193/47 41/194/47 73/195/47 74/196/47 +f 56/197/48 55/198/48 87/199/48 88/200/48 +f 43/201/49 42/202/49 74/203/49 75/204/49 +f 57/205/50 56/206/50 88/207/50 89/208/50 +f 44/209/51 43/210/51 75/211/51 76/212/51 +f 58/213/52 57/214/52 89/215/52 90/216/52 +f 45/217/53 44/218/53 76/219/53 77/220/53 +f 59/221/54 58/222/54 90/223/54 91/224/54 +f 45/225/55 46/226/55 110/227/55 109/228/55 +f 59/229/56 60/230/56 124/231/56 123/232/56 +f 46/233/57 47/234/57 111/235/57 110/236/57 +f 33/237/58 34/238/58 98/239/58 97/240/58 +f 60/241/59 61/242/59 125/243/59 124/244/59 +f 47/245/60 48/246/60 112/247/60 111/248/60 +f 34/249/61 35/250/61 99/251/61 98/252/61 +f 61/253/62 62/254/62 126/255/62 125/256/62 +f 48/257/63 49/258/63 113/259/63 112/260/63 +f 35/261/64 36/262/64 100/263/64 99/264/64 +f 62/265/65 63/266/65 127/267/65 126/268/65 +f 49/269/66 50/270/66 114/271/66 113/272/66 +f 36/273/67 37/274/67 101/275/67 100/276/67 +f 63/277/68 64/278/68 128/279/68 127/280/68 +f 50/281/69 51/282/69 115/283/69 114/284/69 +f 37/285/70 38/286/70 102/287/70 101/288/70 +f 64/289/71 33/290/71 97/291/71 128/292/71 +f 51/293/72 52/294/72 116/295/72 115/296/72 +f 38/297/73 39/298/73 103/299/73 102/300/73 +f 52/301/74 53/302/74 117/303/74 116/304/74 +f 39/305/75 40/306/75 104/307/75 103/308/75 +f 53/309/76 54/310/76 118/311/76 117/312/76 +f 40/313/77 41/314/77 105/315/77 104/316/77 +f 54/317/78 55/318/78 119/319/78 118/320/78 +f 41/321/79 42/322/79 106/323/79 105/324/79 +f 55/325/80 56/326/80 120/327/80 119/328/80 +f 42/329/81 43/330/81 107/331/81 106/332/81 +f 56/333/82 57/334/82 121/335/82 120/336/82 +f 43/337/83 44/338/83 108/339/83 107/340/83 +f 57/341/84 58/342/84 122/343/84 121/344/84 +f 44/345/85 45/346/85 109/347/85 108/348/85 +f 58/349/86 59/350/86 123/351/86 122/352/86 +f 120/353/87 121/354/87 153/355/87 152/356/87 +f 107/357/88 108/358/88 140/359/88 139/360/88 +f 121/361/89 122/362/89 154/363/89 153/364/89 +f 108/365/90 109/366/90 141/367/90 140/368/90 +f 122/369/91 123/370/91 155/371/91 154/372/91 +f 109/373/92 110/374/92 142/375/92 141/376/92 +f 123/377/93 124/378/93 156/379/93 155/380/93 +f 110/381/94 111/382/94 143/383/94 142/384/94 +f 97/385/95 98/386/95 130/387/95 129/388/95 +f 124/389/96 125/390/96 157/391/96 156/392/96 +f 111/393/97 112/394/97 144/395/97 143/396/97 +f 98/397/98 99/398/98 131/399/98 130/400/98 +f 125/401/99 126/402/99 158/403/99 157/404/99 +f 112/405/100 113/406/100 145/407/100 144/408/100 +f 99/409/101 100/410/101 132/411/101 131/412/101 +f 126/413/102 127/414/102 159/415/102 158/416/102 +f 113/417/103 114/418/103 146/419/103 145/420/103 +f 100/421/104 101/422/104 133/423/104 132/424/104 +f 127/425/105 128/426/105 160/427/105 159/428/105 +f 114/429/106 115/430/106 147/431/106 146/432/106 +f 101/433/107 102/434/107 134/435/107 133/436/107 +f 128/437/108 97/438/108 129/439/108 160/440/108 +f 115/441/109 116/442/109 148/443/109 147/444/109 +f 102/445/110 103/446/110 135/447/110 134/448/110 +f 116/449/111 117/450/111 149/451/111 148/452/111 +f 103/453/112 104/454/112 136/455/112 135/456/112 +f 117/457/113 118/458/113 150/459/113 149/460/113 +f 104/461/114 105/462/114 137/463/114 136/464/114 +f 118/465/115 119/466/115 151/467/115 150/468/115 +f 105/469/116 106/470/116 138/471/116 137/472/116 +f 119/473/117 120/474/117 152/475/117 151/476/117 +f 106/477/118 107/478/118 139/479/118 138/480/118 +f 174/481/119 173/482/119 205/483/119 206/484/119 +f 188/485/120 187/486/120 219/487/120 220/488/120 +f 175/489/121 174/490/121 206/491/121 207/492/121 +f 162/493/122 161/494/122 193/495/122 194/496/122 +f 189/497/123 188/498/123 220/499/123 221/500/123 +f 176/501/124 175/502/124 207/503/124 208/504/124 +f 163/505/125 162/506/125 194/507/125 195/508/125 +f 190/509/126 189/510/126 221/511/126 222/512/126 +f 177/513/127 176/514/127 208/515/127 209/516/127 +f 164/517/128 163/518/128 195/519/128 196/520/128 +f 191/521/129 190/522/129 222/523/129 223/524/129 +f 178/525/130 177/526/130 209/527/130 210/528/130 +f 165/529/131 164/530/131 196/531/131 197/532/131 +f 192/533/132 191/534/132 223/535/132 224/536/132 +f 179/537/133 178/538/133 210/539/133 211/540/133 +f 166/541/134 165/542/134 197/543/134 198/544/134 +f 161/545/135 192/546/135 224/547/135 193/548/135 +f 180/549/136 179/550/136 211/551/136 212/552/136 +f 167/553/137 166/554/137 198/555/137 199/556/137 +f 181/557/138 180/558/138 212/559/138 213/560/138 +f 168/561/139 167/562/139 199/563/139 200/564/139 +f 182/565/140 181/566/140 213/567/140 214/568/140 +f 169/569/141 168/570/141 200/571/141 201/572/141 +f 183/573/142 182/574/142 214/575/142 215/576/142 +f 170/577/143 169/578/143 201/579/143 202/580/143 +f 184/581/144 183/582/144 215/583/144 216/584/144 +f 171/585/145 170/586/145 202/587/145 203/588/145 +f 185/589/146 184/590/146 216/591/146 217/592/146 +f 172/593/147 171/594/147 203/595/147 204/596/147 +f 186/597/148 185/598/148 217/599/148 218/600/148 +f 173/601/149 172/602/149 204/603/149 205/604/149 +f 187/605/150 186/606/150 218/607/150 219/608/150 +f 173/609/151 174/610/151 238/611/151 237/612/151 +f 187/613/152 188/614/152 252/615/152 251/616/152 +f 174/617/153 175/618/153 239/619/153 238/620/153 +f 161/621/154 162/622/154 226/623/154 225/624/154 +f 188/625/155 189/626/155 253/627/155 252/628/155 +f 175/629/156 176/630/156 240/631/156 239/632/156 +f 162/633/157 163/634/157 227/635/157 226/636/157 +f 189/637/158 190/638/158 254/639/158 253/640/158 +f 176/641/159 177/642/159 241/643/159 240/644/159 +f 163/645/160 164/646/160 228/647/160 227/648/160 +f 190/649/161 191/650/161 255/651/161 254/652/161 +f 177/653/162 178/654/162 242/655/162 241/656/162 +f 164/657/163 165/658/163 229/659/163 228/660/163 +f 191/661/164 192/662/164 256/663/164 255/664/164 +f 178/665/165 179/666/165 243/667/165 242/668/165 +f 165/669/166 166/670/166 230/671/166 229/672/166 +f 192/673/167 161/674/167 225/675/167 256/676/167 +f 179/677/168 180/678/168 244/679/168 243/680/168 +f 166/681/169 167/682/169 231/683/169 230/684/169 +f 180/685/170 181/686/170 245/687/170 244/688/170 +f 167/689/171 168/690/171 232/691/171 231/692/171 +f 181/693/172 182/694/172 246/695/172 245/696/172 +f 168/697/173 169/698/173 233/699/173 232/700/173 +f 182/701/174 183/702/174 247/703/174 246/704/174 +f 169/705/175 170/706/175 234/707/175 233/708/175 +f 183/709/176 184/710/176 248/711/176 247/712/176 +f 170/713/177 171/714/177 235/715/177 234/716/177 +f 184/717/178 185/718/178 249/719/178 248/720/178 +f 171/721/179 172/722/179 236/723/179 235/724/179 +f 185/725/180 186/726/180 250/727/180 249/728/180 +f 172/729/181 173/730/181 237/731/181 236/732/181 +f 186/733/182 187/734/182 251/735/182 250/736/182 +f 248/737/183 249/738/183 281/739/183 280/740/183 +f 235/741/184 236/742/184 268/743/184 267/744/184 +f 249/745/185 250/746/185 282/747/185 281/748/185 +f 236/749/186 237/750/186 269/751/186 268/752/186 +f 250/753/187 251/754/187 283/755/187 282/756/187 +f 237/757/188 238/758/188 270/759/188 269/760/188 +f 251/761/189 252/762/189 284/763/189 283/764/189 +f 238/765/190 239/766/190 271/767/190 270/768/190 +f 225/769/191 226/770/191 258/771/191 257/772/191 +f 252/773/192 253/774/192 285/775/192 284/776/192 +f 239/777/193 240/778/193 272/779/193 271/780/193 +f 226/781/194 227/782/194 259/783/194 258/784/194 +f 253/785/195 254/786/195 286/787/195 285/788/195 +f 240/789/196 241/790/196 273/791/196 272/792/196 +f 227/793/197 228/794/197 260/795/197 259/796/197 +f 254/797/198 255/798/198 287/799/198 286/800/198 +f 241/801/199 242/802/199 274/803/199 273/804/199 +f 228/805/200 229/806/200 261/807/200 260/808/200 +f 255/809/201 256/810/201 288/811/201 287/812/201 +f 242/813/202 243/814/202 275/815/202 274/816/202 +f 229/817/203 230/818/203 262/819/203 261/820/203 +f 256/821/204 225/822/204 257/823/204 288/824/204 +f 243/825/205 244/826/205 276/827/205 275/828/205 +f 230/829/206 231/830/206 263/831/206 262/832/206 +f 244/833/207 245/834/207 277/835/207 276/836/207 +f 231/837/208 232/838/208 264/839/208 263/840/208 +f 245/841/209 246/842/209 278/843/209 277/844/209 +f 232/845/210 233/846/210 265/847/210 264/848/210 +f 246/849/211 247/850/211 279/851/211 278/852/211 +f 233/853/212 234/854/212 266/855/212 265/856/212 +f 247/857/213 248/858/213 280/859/213 279/860/213 +f 234/861/214 235/862/214 267/863/214 266/864/214 +f 302/865/215 301/866/215 333/867/215 334/868/215 +f 316/869/216 315/870/216 347/871/216 348/872/216 +f 303/873/217 302/874/217 334/875/217 335/876/217 +f 290/877/218 289/878/218 321/879/218 322/880/218 +f 317/881/219 316/882/219 348/883/219 349/884/219 +f 304/885/220 303/886/220 335/887/220 336/888/220 +f 291/889/221 290/890/221 322/891/221 323/892/221 +f 318/893/222 317/894/222 349/895/222 350/896/222 +f 305/897/223 304/898/223 336/899/223 337/900/223 +f 292/901/224 291/902/224 323/903/224 324/904/224 +f 319/905/225 318/906/225 350/907/225 351/908/225 +f 306/909/226 305/910/226 337/911/226 338/912/226 +f 293/913/227 292/914/227 324/915/227 325/916/227 +f 320/917/228 319/918/228 351/919/228 352/920/228 +f 307/921/229 306/922/229 338/923/229 339/924/229 +f 294/925/230 293/926/230 325/927/230 326/928/230 +f 289/929/231 320/930/231 352/931/231 321/932/231 +f 308/933/232 307/934/232 339/935/232 340/936/232 +f 295/937/233 294/938/233 326/939/233 327/940/233 +f 309/941/234 308/942/234 340/943/234 341/944/234 +f 296/945/235 295/946/235 327/947/235 328/948/235 +f 310/949/236 309/950/236 341/951/236 342/952/236 +f 297/953/237 296/954/237 328/955/237 329/956/237 +f 311/957/238 310/958/238 342/959/238 343/960/238 +f 298/961/239 297/962/239 329/963/239 330/964/239 +f 312/965/240 311/966/240 343/967/240 344/968/240 +f 299/969/241 298/970/241 330/971/241 331/972/241 +f 313/973/242 312/974/242 344/975/242 345/976/242 +f 300/977/243 299/978/243 331/979/243 332/980/243 +f 314/981/244 313/982/244 345/983/244 346/984/244 +f 301/985/245 300/986/245 332/987/245 333/988/245 +f 315/989/246 314/990/246 346/991/246 347/992/246 +f 301/993/247 302/994/247 366/995/247 365/996/247 +f 315/997/248 316/998/248 380/999/248 379/1000/248 +f 302/1001/249 303/1002/249 367/1003/249 366/1004/249 +f 289/1005/250 290/1006/250 354/1007/250 353/1008/250 +f 316/1009/251 317/1010/251 381/1011/251 380/1012/251 +f 303/1013/252 304/1014/252 368/1015/252 367/1016/252 +f 290/1017/253 291/1018/253 355/1019/253 354/1020/253 +f 317/1021/254 318/1022/254 382/1023/254 381/1024/254 +f 304/1025/255 305/1026/255 369/1027/255 368/1028/255 +f 291/1029/256 292/1030/256 356/1031/256 355/1032/256 +f 318/1033/257 319/1034/257 383/1035/257 382/1036/257 +f 305/1037/258 306/1038/258 370/1039/258 369/1040/258 +f 292/1041/259 293/1042/259 357/1043/259 356/1044/259 +f 319/1045/260 320/1046/260 384/1047/260 383/1048/260 +f 306/1049/261 307/1050/261 371/1051/261 370/1052/261 +f 293/1053/262 294/1054/262 358/1055/262 357/1056/262 +f 320/1057/263 289/1058/263 353/1059/263 384/1060/263 +f 307/1061/264 308/1062/264 372/1063/264 371/1064/264 +f 294/1065/265 295/1066/265 359/1067/265 358/1068/265 +f 308/1069/266 309/1070/266 373/1071/266 372/1072/266 +f 295/1073/267 296/1074/267 360/1075/267 359/1076/267 +f 309/1077/268 310/1078/268 374/1079/268 373/1080/268 +f 296/1081/269 297/1082/269 361/1083/269 360/1084/269 +f 310/1085/270 311/1086/270 375/1087/270 374/1088/270 +f 297/1089/271 298/1090/271 362/1091/271 361/1092/271 +f 311/1093/272 312/1094/272 376/1095/272 375/1096/272 +f 298/1097/273 299/1098/273 363/1099/273 362/1100/273 +f 312/1101/274 313/1102/274 377/1103/274 376/1104/274 +f 299/1105/275 300/1106/275 364/1107/275 363/1108/275 +f 313/1109/276 314/1110/276 378/1111/276 377/1112/276 +f 300/1113/277 301/1114/277 365/1115/277 364/1116/277 +f 314/1117/278 315/1118/278 379/1119/278 378/1120/278 +f 376/1121/279 377/1122/279 409/1123/279 408/1124/279 +f 363/1125/280 364/1126/280 396/1127/280 395/1128/280 +f 377/1129/281 378/1130/281 410/1131/281 409/1132/281 +f 364/1133/282 365/1134/282 397/1135/282 396/1136/282 +f 378/1137/283 379/1138/283 411/1139/283 410/1140/283 +f 365/1141/284 366/1142/284 398/1143/284 397/1144/284 +f 379/1145/285 380/1146/285 412/1147/285 411/1148/285 +f 366/1149/286 367/1150/286 399/1151/286 398/1152/286 +f 353/1153/287 354/1154/287 386/1155/287 385/1156/287 +f 380/1157/288 381/1158/288 413/1159/288 412/1160/288 +f 367/1161/289 368/1162/289 400/1163/289 399/1164/289 +f 354/1165/290 355/1166/290 387/1167/290 386/1168/290 +f 381/1169/291 382/1170/291 414/1171/291 413/1172/291 +f 368/1173/292 369/1174/292 401/1175/292 400/1176/292 +f 355/1177/293 356/1178/293 388/1179/293 387/1180/293 +f 382/1181/294 383/1182/294 415/1183/294 414/1184/294 +f 369/1185/295 370/1186/295 402/1187/295 401/1188/295 +f 356/1189/296 357/1190/296 389/1191/296 388/1192/296 +f 383/1193/297 384/1194/297 416/1195/297 415/1196/297 +f 370/1197/298 371/1198/298 403/1199/298 402/1200/298 +f 357/1201/299 358/1202/299 390/1203/299 389/1204/299 +f 384/1205/300 353/1206/300 385/1207/300 416/1208/300 +f 371/1209/301 372/1210/301 404/1211/301 403/1212/301 +f 358/1213/302 359/1214/302 391/1215/302 390/1216/302 +f 372/1217/303 373/1218/303 405/1219/303 404/1220/303 +f 359/1221/304 360/1222/304 392/1223/304 391/1224/304 +f 373/1225/305 374/1226/305 406/1227/305 405/1228/305 +f 360/1229/306 361/1230/306 393/1231/306 392/1232/306 +f 374/1233/307 375/1234/307 407/1235/307 406/1236/307 +f 361/1237/308 362/1238/308 394/1239/308 393/1240/308 +f 375/1241/309 376/1242/309 408/1243/309 407/1244/309 +f 362/1245/310 363/1246/310 395/1247/310 394/1248/310 +f 430/1249/311 429/1250/311 461/1251/311 462/1252/311 +f 444/1253/312 443/1254/312 475/1255/312 476/1256/312 +f 431/1257/313 430/1258/313 462/1259/313 463/1260/313 +f 418/1261/314 417/1262/314 449/1263/314 450/1264/314 +f 445/1265/315 444/1266/315 476/1267/315 477/1268/315 +f 432/1269/316 431/1270/316 463/1271/316 464/1272/316 +f 419/1273/317 418/1274/317 450/1275/317 451/1276/317 +f 446/1277/318 445/1278/318 477/1279/318 478/1280/318 +f 433/1281/319 432/1282/319 464/1283/319 465/1284/319 +f 420/1285/320 419/1286/320 451/1287/320 452/1288/320 +f 447/1289/321 446/1290/321 478/1291/321 479/1292/321 +f 434/1293/322 433/1294/322 465/1295/322 466/1296/322 +f 421/1297/323 420/1298/323 452/1299/323 453/1300/323 +f 448/1301/324 447/1302/324 479/1303/324 480/1304/324 +f 435/1305/325 434/1306/325 466/1307/325 467/1308/325 +f 422/1309/326 421/1310/326 453/1311/326 454/1312/326 +f 417/1313/327 448/1314/327 480/1315/327 449/1316/327 +f 436/1317/328 435/1318/328 467/1319/328 468/1320/328 +f 423/1321/329 422/1322/329 454/1323/329 455/1324/329 +f 437/1325/330 436/1326/330 468/1327/330 469/1328/330 +f 424/1329/331 423/1330/331 455/1331/331 456/1332/331 +f 438/1333/332 437/1334/332 469/1335/332 470/1336/332 +f 425/1337/333 424/1338/333 456/1339/333 457/1340/333 +f 439/1341/334 438/1342/334 470/1343/334 471/1344/334 +f 426/1345/335 425/1346/335 457/1347/335 458/1348/335 +f 440/1349/336 439/1350/336 471/1351/336 472/1352/336 +f 427/1353/337 426/1354/337 458/1355/337 459/1356/337 +f 441/1357/338 440/1358/338 472/1359/338 473/1360/338 +f 428/1361/339 427/1362/339 459/1363/339 460/1364/339 +f 442/1365/340 441/1366/340 473/1367/340 474/1368/340 +f 429/1369/341 428/1370/341 460/1371/341 461/1372/341 +f 443/1373/342 442/1374/342 474/1375/342 475/1376/342 +f 429/1377/343 430/1378/343 494/1379/343 493/1380/343 +f 443/1381/344 444/1382/344 508/1383/344 507/1384/344 +f 430/1385/345 431/1386/345 495/1387/345 494/1388/345 +f 417/1389/346 418/1390/346 482/1391/346 481/1392/346 +f 444/1393/347 445/1394/347 509/1395/347 508/1396/347 +f 431/1397/348 432/1398/348 496/1399/348 495/1400/348 +f 418/1401/349 419/1402/349 483/1403/349 482/1404/349 +f 445/1405/350 446/1406/350 510/1407/350 509/1408/350 +f 432/1409/351 433/1410/351 497/1411/351 496/1412/351 +f 419/1413/352 420/1414/352 484/1415/352 483/1416/352 +f 446/1417/353 447/1418/353 511/1419/353 510/1420/353 +f 433/1421/354 434/1422/354 498/1423/354 497/1424/354 +f 420/1425/355 421/1426/355 485/1427/355 484/1428/355 +f 447/1429/356 448/1430/356 512/1431/356 511/1432/356 +f 434/1433/357 435/1434/357 499/1435/357 498/1436/357 +f 421/1437/358 422/1438/358 486/1439/358 485/1440/358 +f 448/1441/359 417/1442/359 481/1443/359 512/1444/359 +f 435/1445/360 436/1446/360 500/1447/360 499/1448/360 +f 422/1449/361 423/1450/361 487/1451/361 486/1452/361 +f 436/1453/362 437/1454/362 501/1455/362 500/1456/362 +f 423/1457/363 424/1458/363 488/1459/363 487/1460/363 +f 437/1461/364 438/1462/364 502/1463/364 501/1464/364 +f 424/1465/365 425/1466/365 489/1467/365 488/1468/365 +f 438/1469/366 439/1470/366 503/1471/366 502/1472/366 +f 425/1473/367 426/1474/367 490/1475/367 489/1476/367 +f 439/1477/368 440/1478/368 504/1479/368 503/1480/368 +f 426/1481/369 427/1482/369 491/1483/369 490/1484/369 +f 440/1485/370 441/1486/370 505/1487/370 504/1488/370 +f 427/1489/371 428/1490/371 492/1491/371 491/1492/371 +f 441/1493/372 442/1494/372 506/1495/372 505/1496/372 +f 428/1497/373 429/1498/373 493/1499/373 492/1500/373 +f 442/1501/374 443/1502/374 507/1503/374 506/1504/374 +f 504/1505/375 505/1506/375 537/1507/375 536/1508/375 +f 491/1509/376 492/1510/376 524/1511/376 523/1512/376 +f 505/1513/377 506/1514/377 538/1515/377 537/1516/377 +f 492/1517/378 493/1518/378 525/1519/378 524/1520/378 +f 506/1521/379 507/1522/379 539/1523/379 538/1524/379 +f 493/1525/380 494/1526/380 526/1527/380 525/1528/380 +f 507/1529/381 508/1530/381 540/1531/381 539/1532/381 +f 494/1533/382 495/1534/382 527/1535/382 526/1536/382 +f 481/1537/383 482/1538/383 514/1539/383 513/1540/383 +f 508/1541/384 509/1542/384 541/1543/384 540/1544/384 +f 495/1545/385 496/1546/385 528/1547/385 527/1548/385 +f 482/1549/386 483/1550/386 515/1551/386 514/1552/386 +f 509/1553/387 510/1554/387 542/1555/387 541/1556/387 +f 496/1557/388 497/1558/388 529/1559/388 528/1560/388 +f 483/1561/389 484/1562/389 516/1563/389 515/1564/389 +f 510/1565/390 511/1566/390 543/1567/390 542/1568/390 +f 497/1569/391 498/1570/391 530/1571/391 529/1572/391 +f 484/1573/392 485/1574/392 517/1575/392 516/1576/392 +f 511/1577/393 512/1578/393 544/1579/393 543/1580/393 +f 498/1581/394 499/1582/394 531/1583/394 530/1584/394 +f 485/1585/395 486/1586/395 518/1587/395 517/1588/395 +f 512/1589/396 481/1590/396 513/1591/396 544/1592/396 +f 499/1593/397 500/1594/397 532/1595/397 531/1596/397 +f 486/1597/398 487/1598/398 519/1599/398 518/1600/398 +f 500/1601/399 501/1602/399 533/1603/399 532/1604/399 +f 487/1605/400 488/1606/400 520/1607/400 519/1608/400 +f 501/1609/401 502/1610/401 534/1611/401 533/1612/401 +f 488/1613/402 489/1614/402 521/1615/402 520/1616/402 +f 502/1617/403 503/1618/403 535/1619/403 534/1620/403 +f 489/1621/404 490/1622/404 522/1623/404 521/1624/404 +f 503/1625/405 504/1626/405 536/1627/405 535/1628/405 +f 490/1629/406 491/1630/406 523/1631/406 522/1632/406 +f 545/1633/407 563/1634/407 561/1635/407 +f 547/1636/408 546/1637/408 552/1638/408 549/1639/408 +f 562/1640/409 545/1641/409 561/1642/409 +f 549/1643/410 552/1644/410 550/1645/410 551/1646/410 +f 548/1647/411 562/1648/411 561/1649/411 +f 551/1650/412 550/1651/412 556/1652/412 553/1653/412 +f 552/1654/413 546/1655/413 561/1656/413 +f 553/1657/414 556/1658/414 558/1659/414 554/1660/414 +f 546/1661/415 548/1662/415 561/1663/415 +f 554/1664/416 558/1665/416 563/1666/416 555/1667/416 +f 550/1668/417 552/1669/417 561/1670/417 +f 555/1671/418 563/1672/418 545/1673/418 557/1674/418 +f 556/1675/419 550/1676/419 561/1677/419 +f 557/1678/420 545/1679/420 562/1680/420 559/1681/420 +f 558/1682/421 556/1683/421 561/1684/421 +f 559/1685/422 562/1686/422 548/1687/422 560/1688/422 +f 563/1689/423 558/1690/423 561/1691/423 +f 560/1692/424 548/1693/424 546/1694/424 547/1695/424 +f 547/1696/425 549/1697/425 551/1698/425 553/1699/425 554/1700/425 555/1701/425 557/1702/425 559/1703/425 560/1704/425 diff --git a/ALVARIZA-BILLAR_DESERT_KANY/tree_lowpoly/Arbre.png b/ALVARIZA-BILLAR_DESERT_KANY/tree_lowpoly/Arbre.png new file mode 100644 index 0000000000000000000000000000000000000000..22e80b662bea7cbf1cd273ed8e2e7d8935281746 Binary files /dev/null and b/ALVARIZA-BILLAR_DESERT_KANY/tree_lowpoly/Arbre.png differ diff --git a/COGNET/lib/Coordinates.js b/COGNET/lib/Coordinates.js new file mode 100644 index 0000000000000000000000000000000000000000..bd23f0cb17418554b0a854f18deb370c56021445 --- /dev/null +++ b/COGNET/lib/Coordinates.js @@ -0,0 +1,150 @@ +"use strict"; // good practice - see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode +/*global THREE, scene*/ +import * as THREE from 'three'; +export var Coordinates = { + drawGrid:function(params) { + params = params || {}; + var size = params.size !== undefined ? params.size:100; + var scale = params.scale !== undefined ? params.scale:0.1; + var orientation = params.orientation !== undefined ? params.orientation:"x"; + var grid = new THREE.Mesh( + new THREE.PlaneGeometry(size, size, size * scale, size * scale), + new THREE.MeshBasicMaterial({ color: 0x555555, wireframe: true }) + ); + // Yes, these are poorly labeled! It would be a mess to fix. + // What's really going on here: + // "x" means "rotate 90 degrees around x", etc. + // So "x" really means "show a grid with a normal of Y" + // "y" means "show a grid with a normal of X" + // "z" means (logically enough) "show a grid with a normal of Z" + if (orientation === "x") { + grid.rotation.x = - Math.PI / 2; + } else if (orientation === "y") { + grid.rotation.y = - Math.PI / 2; + } else if (orientation === "z") { + grid.rotation.z = - Math.PI / 2; + } + + scene.add(grid); + }, + drawGround:function(params) { + params = params || {}; + var size = params.size !== undefined ? params.size:100; + var color = params.color !== undefined ? params.color:0xFFFFFF; + var ground = new THREE.Mesh( + new THREE.PlaneGeometry(size, size), + // When we use a ground plane we use directional lights, so illuminating + // just the corners is sufficient. + // Use MeshPhongMaterial if you want to capture per-pixel lighting: + // new THREE.MeshPhongMaterial({ color: color, specular: 0x000000, + new THREE.MeshLambertMaterial({ color: color, + // polygonOffset moves the plane back from the eye a bit, so that the lines on top of + // the grid do not have z-fighting with the grid: + // Factor == 1 moves it back relative to the slope (more on-edge means move back farther) + // Units == 4 is a fixed amount to move back, and 4 is usually a good value + polygonOffset: true, polygonOffsetFactor: 1.0, polygonOffsetUnits: 4.0 + })); + ground.rotation.x = - Math.PI / 2; + scene.add(ground); + }, + drawAxes:function(params) { + // x = red, y = green, z = blue (RGB = xyz) + params = params || {}; + var axisRadius = params.axisRadius !== undefined ? params.axisRadius:0.04; + var axisLength = params.axisLength !== undefined ? params.axisLength:11; + var axisTess = params.axisTess !== undefined ? params.axisTess:48; + var axisOrientation = params.axisOrientation !== undefined ? params.axisOrientation:"x"; + + var axisMaterial = new THREE.MeshLambertMaterial({ color: 0x000000, side: THREE.DoubleSide }); + var axis = new THREE.Mesh( + new THREE.CylinderGeometry(axisRadius, axisRadius, axisLength, axisTess, 1, true), + axisMaterial + ); + if (axisOrientation === "x") { + axis.rotation.z = - Math.PI / 2; + axis.position.x = axisLength/2-1; + } else if (axisOrientation === "y") { + axis.position.y = axisLength/2-1; + } + + scene.add( axis ); + + var arrow = new THREE.Mesh( + new THREE.CylinderGeometry(0, 4*axisRadius, 8*axisRadius, axisTess, 1, true), + axisMaterial + ); + if (axisOrientation === "x") { + arrow.rotation.z = - Math.PI / 2; + arrow.position.x = axisLength - 1 + axisRadius*4/2; + } else if (axisOrientation === "y") { + arrow.position.y = axisLength - 1 + axisRadius*4/2; + } + + scene.add( arrow ); + + }, + drawAllAxes:function(params) { + params = params || {}; + var axisRadius = params.axisRadius !== undefined ? params.axisRadius:0.04; + var axisLength = params.axisLength !== undefined ? params.axisLength:11; + var axisTess = params.axisTess !== undefined ? params.axisTess:48; + + var axisXMaterial = new THREE.MeshLambertMaterial({ color: 0xFF0000 }); + var axisYMaterial = new THREE.MeshLambertMaterial({ color: 0x00FF00 }); + var axisZMaterial = new THREE.MeshLambertMaterial({ color: 0x0000FF }); + axisXMaterial.side = THREE.DoubleSide; + axisYMaterial.side = THREE.DoubleSide; + axisZMaterial.side = THREE.DoubleSide; + var axisX = new THREE.Mesh( + new THREE.CylinderGeometry(axisRadius, axisRadius, axisLength, axisTess, 1, true), + axisXMaterial + ); + var axisY = new THREE.Mesh( + new THREE.CylinderGeometry(axisRadius, axisRadius, axisLength, axisTess, 1, true), + axisYMaterial + ); + var axisZ = new THREE.Mesh( + new THREE.CylinderGeometry(axisRadius, axisRadius, axisLength, axisTess, 1, true), + axisZMaterial + ); + axisX.rotation.z = - Math.PI / 2; + axisX.position.x = axisLength/2-1; + + axisY.position.y = axisLength/2-1; + + axisZ.rotation.y = - Math.PI / 2; + axisZ.rotation.z = - Math.PI / 2; + axisZ.position.z = axisLength/2-1; + + scene.add( axisX ); + scene.add( axisY ); + scene.add( axisZ ); + + var arrowX = new THREE.Mesh( + new THREE.CylinderGeometry(0, 4*axisRadius, 4*axisRadius, axisTess, 1, true), + axisXMaterial + ); + var arrowY = new THREE.Mesh( + new THREE.CylinderGeometry(0, 4*axisRadius, 4*axisRadius, axisTess, 1, true), + axisYMaterial + ); + var arrowZ = new THREE.Mesh( + new THREE.CylinderGeometry(0, 4*axisRadius, 4*axisRadius, axisTess, 1, true), + axisZMaterial + ); + arrowX.rotation.z = - Math.PI / 2; + arrowX.position.x = axisLength - 1 + axisRadius*4/2; + + arrowY.position.y = axisLength - 1 + axisRadius*4/2; + + arrowZ.rotation.z = - Math.PI / 2; + arrowZ.rotation.y = - Math.PI / 2; + arrowZ.position.z = axisLength - 1 + axisRadius*4/2; + + scene.add( arrowX ); + scene.add( arrowY ); + scene.add( arrowZ ); + + } + +}; \ No newline at end of file diff --git a/COGNET/lib/Detector.js b/COGNET/lib/Detector.js new file mode 100644 index 0000000000000000000000000000000000000000..9f59fcc895067a1ca2b4cb0c65ef5e6c9f8be4ee --- /dev/null +++ b/COGNET/lib/Detector.js @@ -0,0 +1,40 @@ +// TODO: This should be replaced with the checking code from http://get.webgl.org +// they have better supprot messages for different browsers +var Detector={ + canvas:!!window.CanvasRenderingContext2D, + webgl:(function(){ + try{ + return!!window.WebGLRenderingContext&&!!document.createElement('canvas').getContext('experimental-webgl'); + } + catch(e){ + return false; + } + })(), + workers:!!window.Worker, + fileapi:window.File&&window.FileReader&&window.FileList&&window.Blob, + getWebGLErrorMessage:function(){ + var element=document.createElement('div'); + element.id='webgl-error-message'; + element.style.fontFamily='monospace';element.style.fontSize='13px'; + element.style.fontWeight='normal'; + element.style.textAlign='center'; + element.style.background='#fff'; + element.style.color='#000'; + element.style.padding='1.5em'; + element.style.width='400px'; + element.style.margin='5em auto 0'; + if(!this.webgl){ + element.innerHTML=window.WebGLRenderingContext?['Your graphics card does not seem to support <a href="http://khronos.org/webgl/wiki/Getting_a_WebGL_Implementation" style="color:#000">WebGL</a>.<br />','Find out how to get it <a href="http://get.webgl.org/" style="color:#000">here</a>.'].join('\n'):['Your browser does not seem to support <a href="http://khronos.org/webgl/wiki/Getting_a_WebGL_Implementation" style="color:#000">WebGL</a>.<br/>','Find out how to get it <a href="http://get.webgl.org/" style="color:#000">here</a>.'].join('\n'); + } + return element; + }, + addGetWebGLMessage:function(parameters){ + var parent,id,element; + parameters=parameters||{}; + parent=parameters.parent!==undefined?parameters.parent:document.body; + id=parameters.id!==undefined?parameters.id:'unsupported'; + element=Detector.getWebGLErrorMessage(); + element.id=id; + document.body.insertBefore(element, document.body.childNodes[0]); + } +}; \ No newline at end of file diff --git a/COGNET/lib/OrbitAndPanControls.js b/COGNET/lib/OrbitAndPanControls.js new file mode 100644 index 0000000000000000000000000000000000000000..5c7ed23cbcdf6161c708346d8b6b570b08e6e701 --- /dev/null +++ b/COGNET/lib/OrbitAndPanControls.js @@ -0,0 +1,532 @@ +"use strict"; // good practice - see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode +/** + * @author qiao / https://github.com/qiao + * @author mrdoob / http://mrdoob.com + * @author alteredq / http://alteredqualia.com/ + * @author WestLangley / http://github.com/WestLangley + * @author erich666 / http://erichaines.com + */ +/*global THREE, console */ + +THREE.OrbitAndPanControls = function ( object, domElement ) { + + THREE.EventDispatcher.call( this ); + + this.enabled = true; + + this.object = object; + this.domElement = ( domElement !== undefined ) ? domElement : document; + + // API + + this.enabled = true; + + this.target = new THREE.Vector3(); + // center is old, deprecated; use "target" instead + this.center = this.target; + + // This option actually enables dollying in and out + this.noZoom = false; + this.zoomSpeed = 1.0; + + this.noRotate = false; + this.rotateSpeed = 1.0; + + this.noPan = false; + + this.autoRotate = false; + this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60 + + this.minPolarAngle = 0; // radians + this.maxPolarAngle = Math.PI; // radians + + this.minDistance = 0; + this.maxDistance = Infinity; + + this.noKeys = false; + this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 }; + + // internals + + var scope = this; + + var EPS = 0.000001; + + var rotateStart = new THREE.Vector2(); + var rotateEnd = new THREE.Vector2(); + var rotateDelta = new THREE.Vector2(); + + var panStart = new THREE.Vector2(); + var panEnd = new THREE.Vector2(); + var panDelta = new THREE.Vector2(); + + var dollyStart = new THREE.Vector2(); + var dollyEnd = new THREE.Vector2(); + var dollyDelta = new THREE.Vector2(); + + var phiDelta = 0; + var thetaDelta = 0; + var scale = 1; + var pan = new THREE.Vector3(); + + var lastPosition = new THREE.Vector3(); + + var STATE = { NONE : -1, ROTATE : 0, DOLLY : 1, PAN : 2, TOUCH_ROTATE : 3, TOUCH_DOLLY : 4, TOUCH_PAN : 5 }; + var state = STATE.NONE; + + // events + + var changeEvent = { type: 'change' }; + + + this.rotateLeft = function ( angle ) { + + if ( angle === undefined ) { + + angle = getAutoRotationAngle(); + + } + + thetaDelta -= angle; + + }; + + this.rotateUp = function ( angle ) { + + if ( angle === undefined ) { + + angle = getAutoRotationAngle(); + + } + + phiDelta -= angle; + + }; + + // pass in distance in world space to move left + this.panLeft = function ( distance ) { + + var panOffset = new THREE.Vector3(); + var te = this.object.matrix.elements; + // get X column of matrix + panOffset.set( te[0], te[1], te[2] ); + panOffset.multiplyScalar(-distance); + + pan.add( panOffset ); + + }; + + // pass in distance in world space to move up + this.panUp = function ( distance ) { + + var panOffset = new THREE.Vector3(); + var te = this.object.matrix.elements; + // get Y column of matrix + panOffset.set( te[4], te[5], te[6] ); + panOffset.multiplyScalar(distance); + + pan.add( panOffset ); + }; + + // main entry point; pass in Vector2 of change desired in pixel space, + // right and down are positive + this.pan = function ( delta ) { + + if ( scope.object.fov !== undefined ) + { + // perspective + var position = scope.object.position; + var offset = position.clone().sub( scope.target ); + var targetDistance = offset.length(); + + // half of the fov is center to top of screen + targetDistance *= Math.tan( (scope.object.fov/2) * Math.PI / 180.0 ); + // we actually don't use screenWidth, since perspective camera is fixed to screen height + scope.panLeft( 2 * delta.x * targetDistance / scope.domElement.height ); + scope.panUp( 2 * delta.y * targetDistance / scope.domElement.height ); + } + else if ( scope.object.top !== undefined ) + { + // orthographic + scope.panLeft( delta.x * (scope.object.right - scope.object.left) / scope.domElement.width ); + scope.panUp( delta.y * (scope.object.top - scope.object.bottom) / scope.domElement.height ); + } + else + { + // camera neither orthographic or perspective - warn user + console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' ); + } + }; + + this.dollyIn = function ( dollyScale ) { + + if ( dollyScale === undefined ) { + + dollyScale = getZoomScale(); + + } + + scale /= dollyScale; + + }; + + this.dollyOut = function ( dollyScale ) { + + if ( dollyScale === undefined ) { + + dollyScale = getZoomScale(); + + } + + scale *= dollyScale; + + }; + + this.update = function () { + + var position = this.object.position; + var offset = position.clone().sub( this.target ); + + // angle from z-axis around y-axis + + var theta = Math.atan2( offset.x, offset.z ); + + // angle from y-axis + + var phi = Math.atan2( Math.sqrt( offset.x * offset.x + offset.z * offset.z ), offset.y ); + + if ( this.autoRotate ) { + + this.rotateLeft( getAutoRotationAngle() ); + + } + + theta += thetaDelta; + phi += phiDelta; + + // restrict phi to be between desired limits + phi = Math.max( this.minPolarAngle, Math.min( this.maxPolarAngle, phi ) ); + + // restrict phi to be betwee EPS and PI-EPS + phi = Math.max( EPS, Math.min( Math.PI - EPS, phi ) ); + + var radius = offset.length() * scale; + + // restrict radius to be between desired limits + radius = Math.max( this.minDistance, Math.min( this.maxDistance, radius ) ); + + // move target to panned location + this.target.add( pan ); + + offset.x = radius * Math.sin( phi ) * Math.sin( theta ); + offset.y = radius * Math.cos( phi ); + offset.z = radius * Math.sin( phi ) * Math.cos( theta ); + + position.copy( this.target ).add( offset ); + + this.object.lookAt( this.target ); + + thetaDelta = 0; + phiDelta = 0; + scale = 1; + pan.set(0,0,0); + + if ( lastPosition.distanceTo( this.object.position ) > 0 ) { + + this.dispatchEvent( changeEvent ); + + lastPosition.copy( this.object.position ); + + } + + }; + + + function getAutoRotationAngle() { + + return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed; + + } + + function getZoomScale() { + + return Math.pow( 0.95, scope.zoomSpeed ); + + } + + function onMouseDown( event ) { + + if ( scope.enabled === false ) { return; } + event.preventDefault(); + + if ( event.button === 0 ) { + if ( scope.noRotate === true ) { return; } + + state = STATE.ROTATE; + + rotateStart.set( event.clientX, event.clientY ); + + } else if ( event.button === 1 ) { + if ( scope.noZoom === true ) { return; } + + state = STATE.DOLLY; + + dollyStart.set( event.clientX, event.clientY ); + + } else if ( event.button === 2 ) { + if ( scope.noPan === true ) { return; } + + state = STATE.PAN; + + panStart.set( event.clientX, event.clientY ); + + } + + document.addEventListener( 'mousemove', onMouseMove, false ); + document.addEventListener( 'mouseup', onMouseUp, false ); + + } + + function onMouseMove( event ) { + + if ( scope.enabled === false ) { return; } + + event.preventDefault(); + + if ( state === STATE.ROTATE ) { + if ( scope.noRotate === true ) { return; } + + rotateEnd.set( event.clientX, event.clientY ); + rotateDelta.subVectors( rotateEnd, rotateStart ); + + // rotating across whole screen goes 360 degrees around + scope.rotateLeft( 2 * Math.PI * rotateDelta.x / scope.domElement.width * scope.rotateSpeed ); + // rotating up and down along whole screen attempts to go 360, but limited to 180 + scope.rotateUp( 2 * Math.PI * rotateDelta.y / scope.domElement.height * scope.rotateSpeed ); + + rotateStart.copy( rotateEnd ); + + } else if ( state === STATE.DOLLY ) { + if ( scope.noZoom === true ) { return; } + + dollyEnd.set( event.clientX, event.clientY ); + dollyDelta.subVectors( dollyEnd, dollyStart ); + + if ( dollyDelta.y > 0 ) { + + scope.dollyIn(); + + } else { + + scope.dollyOut(); + + } + + dollyStart.copy( dollyEnd ); + + } else if ( state === STATE.PAN ) { + if ( scope.noPan === true ) { return; } + + panEnd.set( event.clientX, event.clientY ); + panDelta.subVectors( panEnd, panStart ); + + scope.pan( panDelta ); + + panStart.copy( panEnd ); + + } + + } + + function onMouseUp( /* event */ ) { + + if ( scope.enabled === false ) { return; } + + document.removeEventListener( 'mousemove', onMouseMove, false ); + document.removeEventListener( 'mouseup', onMouseUp, false ); + + state = STATE.NONE; + + } + + function onMouseWheel( event ) { + // this is needed when the program is inside an iframe + // to prevent scrolling the whole page + event.preventDefault(); + if ( scope.enabled === false ) { return; } + if ( scope.noZoom === true ) { return; } + + var delta = 0; + + if ( event.wheelDelta ) { // WebKit / Opera / Explorer 9 + + delta = event.wheelDelta; + + } else if ( event.detail ) { // Firefox + + delta = - event.detail; + + } + + if ( delta > 0 ) { + + scope.dollyOut(); + + } else { + + scope.dollyIn(); + + } + + } + + function onKeyDown( event ) { + + if ( scope.enabled === false ) { return; } + if ( scope.noKeys === true ) { return; } + if ( scope.noPan === true ) { return; } + + // pan a pixel - I guess for precise positioning? + switch ( event.keyCode ) { + + case scope.keys.UP: + scope.pan( new THREE.Vector2( 0, 1 ) ); + break; + case scope.keys.BOTTOM: + scope.pan( new THREE.Vector2( 0, -1 ) ); + break; + case scope.keys.LEFT: + scope.pan( new THREE.Vector2( 1, 0 ) ); + break; + case scope.keys.RIGHT: + scope.pan( new THREE.Vector2( -1, 0 ) ); + break; + } + + } + + function touchstart( event ) { + + if ( scope.enabled === false ) { return; } + + switch ( event.touches.length ) { + + case 1: // one-fingered touch: rotate + if ( scope.noRotate === true ) { return; } + + state = STATE.TOUCH_ROTATE; + + rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + break; + + case 2: // two-fingered touch: dolly + if ( scope.noZoom === true ) { return; } + + state = STATE.TOUCH_DOLLY; + + var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; + var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; + var distance = Math.sqrt( dx * dx + dy * dy ); + dollyStart.set( 0, distance ); + break; + + case 3: // three-fingered touch: pan + if ( scope.noPan === true ) { return; } + + state = STATE.TOUCH_PAN; + + panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + break; + + default: + state = STATE.NONE; + + } + } + + function touchmove( event ) { + + if ( scope.enabled === false ) { return; } + + event.preventDefault(); + event.stopPropagation(); + + switch ( event.touches.length ) { + + case 1: // one-fingered touch: rotate + if ( scope.noRotate === true ) { return; } + if ( state !== STATE.TOUCH_ROTATE ) { return; } + + rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + rotateDelta.subVectors( rotateEnd, rotateStart ); + + // rotating across whole screen goes 360 degrees around + scope.rotateLeft( 2 * Math.PI * rotateDelta.x / scope.domElement.width * scope.rotateSpeed ); + // rotating up and down along whole screen attempts to go 360, but limited to 180 + scope.rotateUp( 2 * Math.PI * rotateDelta.y / scope.domElement.height * scope.rotateSpeed ); + + rotateStart.copy( rotateEnd ); + break; + + case 2: // two-fingered touch: dolly + if ( scope.noZoom === true ) { return; } + if ( state !== STATE.TOUCH_DOLLY ) { return; } + + var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; + var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; + var distance = Math.sqrt( dx * dx + dy * dy ); + + dollyEnd.set( 0, distance ); + dollyDelta.subVectors( dollyEnd, dollyStart ); + + if ( dollyDelta.y > 0 ) { + + scope.dollyOut(); + + } else { + + scope.dollyIn(); + + } + + dollyStart.copy( dollyEnd ); + break; + + case 3: // three-fingered touch: pan + if ( scope.noPan === true ) { return; } + if ( state !== STATE.TOUCH_PAN ) { return; } + + panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + panDelta.subVectors( panEnd, panStart ); + + scope.pan( panDelta ); + + panStart.copy( panEnd ); + break; + + default: + state = STATE.NONE; + + } + + } + + function touchend( /* event */ ) { + + if ( scope.enabled === false ) { return; } + + state = STATE.NONE; + } + + this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false ); + this.domElement.addEventListener( 'mousedown', onMouseDown, false ); + this.domElement.addEventListener( 'mousewheel', onMouseWheel, false ); + this.domElement.addEventListener( 'DOMMouseScroll', onMouseWheel, false ); // firefox + + this.domElement.addEventListener( 'keydown', onKeyDown, false ); + + this.domElement.addEventListener( 'touchstart', touchstart, false ); + this.domElement.addEventListener( 'touchend', touchend, false ); + this.domElement.addEventListener( 'touchmove', touchmove, false ); + +}; diff --git a/COGNET/lib/OrbitAndPanControls.new.js b/COGNET/lib/OrbitAndPanControls.new.js new file mode 100644 index 0000000000000000000000000000000000000000..bb8c6b2e5b825363a40c863bb4e2a272f34e4052 --- /dev/null +++ b/COGNET/lib/OrbitAndPanControls.new.js @@ -0,0 +1,530 @@ +"use strict"; // good practice - see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode +/** + * @author qiao / https://github.com/qiao + * @author mrdoob / http://mrdoob.com + * @author alteredq / http://alteredqualia.com/ + * @author WestLangley / http://github.com/WestLangley + * @author erich666 / http://erichaines.com + */ +/*global THREE, console */ + +THREE.OrbitAndPanControls = function ( object, domElement ) { + + this.object = object; + this.domElement = ( domElement !== undefined ) ? domElement : document; + + // API + + this.enabled = true; + + this.target = new THREE.Vector3(); + // center is old, deprecated; use "target" instead + this.center = this.target; + + // This option actually enables dollying in and out + this.noZoom = false; + this.zoomSpeed = 1.0; + + this.noRotate = false; + this.rotateSpeed = 1.0; + + this.noPan = false; + + this.autoRotate = false; + this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60 + + this.minPolarAngle = 0; // radians + this.maxPolarAngle = Math.PI; // radians + + this.minDistance = 0; + this.maxDistance = Infinity; + + this.noKeys = false; + this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 }; + + // internals + + var scope = this; + + var EPS = 0.000001; + + var rotateStart = new THREE.Vector2(); + var rotateEnd = new THREE.Vector2(); + var rotateDelta = new THREE.Vector2(); + + var panStart = new THREE.Vector2(); + var panEnd = new THREE.Vector2(); + var panDelta = new THREE.Vector2(); + + var dollyStart = new THREE.Vector2(); + var dollyEnd = new THREE.Vector2(); + var dollyDelta = new THREE.Vector2(); + + var phiDelta = 0; + var thetaDelta = 0; + var scale = 1; + var pan = new THREE.Vector3(); + + var lastPosition = new THREE.Vector3(); + + var STATE = { NONE : -1, ROTATE : 0, DOLLY : 1, PAN : 2, TOUCH_ROTATE : 3, TOUCH_DOLLY : 4, TOUCH_PAN : 5 }; + var state = STATE.NONE; + + // events + + var changeEvent = { type: 'change' }; + + + this.rotateLeft = function ( angle ) { + + if ( angle === undefined ) { + + angle = getAutoRotationAngle(); + + } + + thetaDelta -= angle; + + }; + + this.rotateUp = function ( angle ) { + + if ( angle === undefined ) { + + angle = getAutoRotationAngle(); + + } + + phiDelta -= angle; + + }; + + // pass in distance in world space to move left + this.panLeft = function ( distance ) { + + var panOffset = new THREE.Vector3(); + var te = this.object.matrix.elements; + // get X column of matrix + panOffset.set( te[0], te[1], te[2] ); + panOffset.multiplyScalar(-distance); + + pan.add( panOffset ); + + }; + + // pass in distance in world space to move up + this.panUp = function ( distance ) { + + var panOffset = new THREE.Vector3(); + var te = this.object.matrix.elements; + // get Y column of matrix + panOffset.set( te[4], te[5], te[6] ); + panOffset.multiplyScalar(distance); + + pan.add( panOffset ); + }; + + // main entry point; pass in Vector2 of change desired in pixel space, + // right and down are positive + this.pan = function ( delta ) { + + if ( scope.object.fov !== undefined ) + { + // perspective + var position = scope.object.position; + var offset = position.clone().sub( scope.target ); + var targetDistance = offset.length(); + + // half of the fov is center to top of screen + targetDistance *= Math.tan( (scope.object.fov/2) * Math.PI / 180.0 ); + // we actually don't use screenWidth, since perspective camera is fixed to screen height + scope.panLeft( 2 * delta.x * targetDistance / scope.domElement.height ); + scope.panUp( 2 * delta.y * targetDistance / scope.domElement.height ); + } + else if ( scope.object.top !== undefined ) + { + // orthographic + scope.panLeft( delta.x * (scope.object.right - scope.object.left) / scope.domElement.width ); + scope.panUp( delta.y * (scope.object.top - scope.object.bottom) / scope.domElement.height ); + } + else + { + // camera neither orthographic or perspective - warn user + console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' ); + } + }; + + this.dollyIn = function ( dollyScale ) { + + if ( dollyScale === undefined ) { + + dollyScale = getZoomScale(); + + } + + scale /= dollyScale; + + }; + + this.dollyOut = function ( dollyScale ) { + + if ( dollyScale === undefined ) { + + dollyScale = getZoomScale(); + + } + + scale *= dollyScale; + + }; + + this.update = function () { + + var position = this.object.position; + var offset = position.clone().sub( this.target ); + + // angle from z-axis around y-axis + + var theta = Math.atan2( offset.x, offset.z ); + + // angle from y-axis + + var phi = Math.atan2( Math.sqrt( offset.x * offset.x + offset.z * offset.z ), offset.y ); + + if ( this.autoRotate ) { + + this.rotateLeft( getAutoRotationAngle() ); + + } + + theta += thetaDelta; + phi += phiDelta; + + // restrict phi to be between desired limits + phi = Math.max( this.minPolarAngle, Math.min( this.maxPolarAngle, phi ) ); + + // restrict phi to be betwee EPS and PI-EPS + phi = Math.max( EPS, Math.min( Math.PI - EPS, phi ) ); + + var radius = offset.length() * scale; + + // restrict radius to be between desired limits + radius = Math.max( this.minDistance, Math.min( this.maxDistance, radius ) ); + + // move target to panned location + this.target.add( pan ); + + offset.x = radius * Math.sin( phi ) * Math.sin( theta ); + offset.y = radius * Math.cos( phi ); + offset.z = radius * Math.sin( phi ) * Math.cos( theta ); + + position.copy( this.target ).add( offset ); + + this.object.lookAt( this.target ); + + thetaDelta = 0; + phiDelta = 0; + scale = 1; + pan.set(0,0,0); + + if ( lastPosition.distanceTo( this.object.position ) > 0 ) { + + this.dispatchEvent( changeEvent ); + + lastPosition.copy( this.object.position ); + + } + + }; + + + function getAutoRotationAngle() { + + return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed; + + } + + function getZoomScale() { + + return Math.pow( 0.95, scope.zoomSpeed ); + + } + + function onMouseDown( event ) { + + if ( scope.enabled === false ) { return; } + event.preventDefault(); + + if ( event.button === 0 ) { + if ( scope.noRotate === true ) { return; } + + state = STATE.ROTATE; + + rotateStart.set( event.clientX, event.clientY ); + + } else if ( event.button === 1 ) { + if ( scope.noZoom === true ) { return; } + + state = STATE.DOLLY; + + dollyStart.set( event.clientX, event.clientY ); + + } else if ( event.button === 2 ) { + if ( scope.noPan === true ) { return; } + + state = STATE.PAN; + + panStart.set( event.clientX, event.clientY ); + + } + + document.addEventListener( 'mousemove', onMouseMove, false ); + document.addEventListener( 'mouseup', onMouseUp, false ); + + } + + function onMouseMove( event ) { + + if ( scope.enabled === false ) { return; } + + event.preventDefault(); + + if ( state === STATE.ROTATE ) { + if ( scope.noRotate === true ) { return; } + + rotateEnd.set( event.clientX, event.clientY ); + rotateDelta.subVectors( rotateEnd, rotateStart ); + + // rotating across whole screen goes 360 degrees around + scope.rotateLeft( 2 * Math.PI * rotateDelta.x / scope.domElement.width * scope.rotateSpeed ); + // rotating up and down along whole screen attempts to go 360, but limited to 180 + scope.rotateUp( 2 * Math.PI * rotateDelta.y / scope.domElement.height * scope.rotateSpeed ); + + rotateStart.copy( rotateEnd ); + + } else if ( state === STATE.DOLLY ) { + if ( scope.noZoom === true ) { return; } + + dollyEnd.set( event.clientX, event.clientY ); + dollyDelta.subVectors( dollyEnd, dollyStart ); + + if ( dollyDelta.y > 0 ) { + + scope.dollyIn(); + + } else { + + scope.dollyOut(); + + } + + dollyStart.copy( dollyEnd ); + + } else if ( state === STATE.PAN ) { + if ( scope.noPan === true ) { return; } + + panEnd.set( event.clientX, event.clientY ); + panDelta.subVectors( panEnd, panStart ); + + scope.pan( panDelta ); + + panStart.copy( panEnd ); + + } + + } + + function onMouseUp( /* event */ ) { + + if ( scope.enabled === false ) { return; } + + document.removeEventListener( 'mousemove', onMouseMove, false ); + document.removeEventListener( 'mouseup', onMouseUp, false ); + + state = STATE.NONE; + + } + + function onMouseWheel( event ) { + // this is needed when the program is inside an iframe + // to prevent scrolling the whole page + event.preventDefault(); + if ( scope.enabled === false ) { return; } + if ( scope.noZoom === true ) { return; } + + var delta = 0; + + if ( event.wheelDelta ) { // WebKit / Opera / Explorer 9 + + delta = event.wheelDelta; + + } else if ( event.detail ) { // Firefox + + delta = - event.detail; + + } + + if ( delta > 0 ) { + + scope.dollyOut(); + + } else { + + scope.dollyIn(); + + } + + } + + function onKeyDown( event ) { + + if ( scope.enabled === false ) { return; } + if ( scope.noKeys === true ) { return; } + if ( scope.noPan === true ) { return; } + + // pan a pixel - I guess for precise positioning? + switch ( event.keyCode ) { + + case scope.keys.UP: + scope.pan( new THREE.Vector2( 0, 1 ) ); + break; + case scope.keys.BOTTOM: + scope.pan( new THREE.Vector2( 0, -1 ) ); + break; + case scope.keys.LEFT: + scope.pan( new THREE.Vector2( 1, 0 ) ); + break; + case scope.keys.RIGHT: + scope.pan( new THREE.Vector2( -1, 0 ) ); + break; + } + + } + + function touchstart( event ) { + + if ( scope.enabled === false ) { return; } + + switch ( event.touches.length ) { + + case 1: // one-fingered touch: rotate + if ( scope.noRotate === true ) { return; } + + state = STATE.TOUCH_ROTATE; + + rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + break; + + case 2: // two-fingered touch: dolly + if ( scope.noZoom === true ) { return; } + + state = STATE.TOUCH_DOLLY; + + var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; + var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; + var distance = Math.sqrt( dx * dx + dy * dy ); + dollyStart.set( 0, distance ); + break; + + case 3: // three-fingered touch: pan + if ( scope.noPan === true ) { return; } + + state = STATE.TOUCH_PAN; + + panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + break; + + default: + state = STATE.NONE; + + } + } + + function touchmove( event ) { + + if ( scope.enabled === false ) { return; } + + event.preventDefault(); + event.stopPropagation(); + + switch ( event.touches.length ) { + + case 1: // one-fingered touch: rotate + if ( scope.noRotate === true ) { return; } + if ( state !== STATE.TOUCH_ROTATE ) { return; } + + rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + rotateDelta.subVectors( rotateEnd, rotateStart ); + + // rotating across whole screen goes 360 degrees around + scope.rotateLeft( 2 * Math.PI * rotateDelta.x / scope.domElement.width * scope.rotateSpeed ); + // rotating up and down along whole screen attempts to go 360, but limited to 180 + scope.rotateUp( 2 * Math.PI * rotateDelta.y / scope.domElement.height * scope.rotateSpeed ); + + rotateStart.copy( rotateEnd ); + break; + + case 2: // two-fingered touch: dolly + if ( scope.noZoom === true ) { return; } + if ( state !== STATE.TOUCH_DOLLY ) { return; } + + var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; + var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; + var distance = Math.sqrt( dx * dx + dy * dy ); + + dollyEnd.set( 0, distance ); + dollyDelta.subVectors( dollyEnd, dollyStart ); + + if ( dollyDelta.y > 0 ) { + + scope.dollyOut(); + + } else { + + scope.dollyIn(); + + } + + dollyStart.copy( dollyEnd ); + break; + + case 3: // three-fingered touch: pan + if ( scope.noPan === true ) { return; } + if ( state !== STATE.TOUCH_PAN ) { return; } + + panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + panDelta.subVectors( panEnd, panStart ); + + scope.pan( panDelta ); + + panStart.copy( panEnd ); + break; + + default: + state = STATE.NONE; + + } + + } + + function touchend( /* event */ ) { + + if ( scope.enabled === false ) { return; } + + state = STATE.NONE; + } + + this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false ); + this.domElement.addEventListener( 'mousedown', onMouseDown, false ); + this.domElement.addEventListener( 'mousewheel', onMouseWheel, false ); + this.domElement.addEventListener( 'DOMMouseScroll', onMouseWheel, false ); // firefox + + this.domElement.addEventListener( 'keydown', onKeyDown, false ); + + this.domElement.addEventListener( 'touchstart', touchstart, false ); + this.domElement.addEventListener( 'touchend', touchend, false ); + this.domElement.addEventListener( 'touchmove', touchmove, false ); + +}; + +THREE.OrbitAndPanControls.prototype = Object.create( THREE.EventDispatcher.prototype ); diff --git a/COGNET/lib/TrackballControls.js b/COGNET/lib/TrackballControls.js new file mode 100644 index 0000000000000000000000000000000000000000..0935ce04a601a7b3e17e6efd60bcf01481fa9818 --- /dev/null +++ b/COGNET/lib/TrackballControls.js @@ -0,0 +1,537 @@ +/** + * @author Eberhard Graether / http://egraether.com/ + */ + +THREE.TrackballControls = function ( object, domElement ) { + + THREE.EventDispatcher.call( this ); + + var _this = this; + var STATE = { NONE: -1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM: 4, TOUCH_PAN: 5 }; + + this.object = object; + this.domElement = ( domElement !== undefined ) ? domElement : document; + + // API + + this.enabled = true; + + this.screen = { width: 0, height: 0, offsetLeft: 0, offsetTop: 0 }; + this.radius = ( this.screen.width + this.screen.height ) / 4; + + this.rotateSpeed = 1.0; + this.zoomSpeed = 1.2; + this.panSpeed = 0.3; + + this.noRotate = false; + this.noZoom = false; + this.noPan = false; + + this.staticMoving = false; + this.dynamicDampingFactor = 0.2; + + this.minDistance = 0; + this.maxDistance = Infinity; + + this.keys = [ 65 /*A*/, 83 /*S*/, 68 /*D*/ ]; + + // internals + + this.target = new THREE.Vector3(); + + var lastPosition = new THREE.Vector3(); + + var _state = STATE.NONE, + _prevState = STATE.NONE, + + _eye = new THREE.Vector3(), + + _rotateStart = new THREE.Vector3(), + _rotateEnd = new THREE.Vector3(), + + _zoomStart = new THREE.Vector2(), + _zoomEnd = new THREE.Vector2(), + + _touchZoomDistanceStart = 0, + _touchZoomDistanceEnd = 0, + + _panStart = new THREE.Vector2(), + _panEnd = new THREE.Vector2(); + + // for reset + + this.target0 = this.target.clone(); + this.position0 = this.object.position.clone(); + this.up0 = this.object.up.clone(); + + // events + + var changeEvent = { type: 'change' }; + + + // methods + + this.handleResize = function () { + + this.screen.width = window.innerWidth; + this.screen.height = window.innerHeight; + + this.screen.offsetLeft = 0; + this.screen.offsetTop = 0; + + this.radius = ( this.screen.width + this.screen.height ) / 4; + + }; + + this.handleEvent = function ( event ) { + + if ( typeof this[ event.type ] == 'function' ) { + + this[ event.type ]( event ); + + } + + }; + + this.getMouseOnScreen = function ( clientX, clientY ) { + + return new THREE.Vector2( + ( clientX - _this.screen.offsetLeft ) / _this.radius * 0.5, + ( clientY - _this.screen.offsetTop ) / _this.radius * 0.5 + ); + + }; + + this.getMouseProjectionOnBall = function ( clientX, clientY ) { + + var mouseOnBall = new THREE.Vector3( + ( clientX - _this.screen.width * 0.5 - _this.screen.offsetLeft ) / _this.radius, + ( _this.screen.height * 0.5 + _this.screen.offsetTop - clientY ) / _this.radius, + 0.0 + ); + + var length = mouseOnBall.length(); + + if ( length > 1.0 ) { + + mouseOnBall.normalize(); + + } else { + + mouseOnBall.z = Math.sqrt( 1.0 - length * length ); + + } + + _eye.copy( _this.object.position ).sub( _this.target ); + + var projection = _this.object.up.clone().setLength( mouseOnBall.y ); + projection.add( _this.object.up.clone().cross( _eye ).setLength( mouseOnBall.x ) ); + projection.add( _eye.setLength( mouseOnBall.z ) ); + + return projection; + + }; + + this.rotateCamera = function () { + + var angle = Math.acos( _rotateStart.dot( _rotateEnd ) / _rotateStart.length() / _rotateEnd.length() ); + + if ( angle ) { + + var axis = ( new THREE.Vector3() ).crossVectors( _rotateStart, _rotateEnd ).normalize(), + quaternion = new THREE.Quaternion(); + + angle *= _this.rotateSpeed; + + quaternion.setFromAxisAngle( axis, -angle ); + + _eye.applyQuaternion( quaternion ); + _this.object.up.applyQuaternion( quaternion ); + + _rotateEnd.applyQuaternion( quaternion ); + + if ( _this.staticMoving ) { + + _rotateStart.copy( _rotateEnd ); + + } else { + + quaternion.setFromAxisAngle( axis, angle * ( _this.dynamicDampingFactor - 1.0 ) ); + _rotateStart.applyQuaternion( quaternion ); + + } + + } + + }; + + this.zoomCamera = function () { + + if ( _state === STATE.TOUCH_ZOOM ) { + + var factor = _touchZoomDistanceStart / _touchZoomDistanceEnd; + _touchZoomDistanceStart = _touchZoomDistanceEnd; + _eye.multiplyScalar( factor ); + + } else { + + var factor = 1.0 + ( _zoomEnd.y - _zoomStart.y ) * _this.zoomSpeed; + + if ( factor !== 1.0 && factor > 0.0 ) { + + _eye.multiplyScalar( factor ); + + if ( _this.staticMoving ) { + + _zoomStart.copy( _zoomEnd ); + + } else { + + _zoomStart.y += ( _zoomEnd.y - _zoomStart.y ) * this.dynamicDampingFactor; + + } + + } + + } + + }; + + this.panCamera = function () { + + var mouseChange = _panEnd.clone().sub( _panStart ); + + if ( mouseChange.lengthSq() ) { + + mouseChange.multiplyScalar( _eye.length() * _this.panSpeed ); + + var pan = _eye.clone().cross( _this.object.up ).setLength( mouseChange.x ); + pan.add( _this.object.up.clone().setLength( mouseChange.y ) ); + + _this.object.position.add( pan ); + _this.target.add( pan ); + + if ( _this.staticMoving ) { + + _panStart = _panEnd; + + } else { + + _panStart.add( mouseChange.subVectors( _panEnd, _panStart ).multiplyScalar( _this.dynamicDampingFactor ) ); + + } + + } + + }; + + this.checkDistances = function () { + + if ( !_this.noZoom || !_this.noPan ) { + + if ( _this.object.position.lengthSq() > _this.maxDistance * _this.maxDistance ) { + + _this.object.position.setLength( _this.maxDistance ); + + } + + if ( _eye.lengthSq() < _this.minDistance * _this.minDistance ) { + + _this.object.position.addVectors( _this.target, _eye.setLength( _this.minDistance ) ); + + } + + } + + }; + + this.update = function () { + + _eye.subVectors( _this.object.position, _this.target ); + + if ( !_this.noRotate ) { + + _this.rotateCamera(); + + } + + if ( !_this.noZoom ) { + + _this.zoomCamera(); + + } + + if ( !_this.noPan ) { + + _this.panCamera(); + + } + + _this.object.position.addVectors( _this.target, _eye ); + + _this.checkDistances(); + + _this.object.lookAt( _this.target ); + + if ( lastPosition.distanceToSquared( _this.object.position ) > 0 ) { + + _this.dispatchEvent( changeEvent ); + + lastPosition.copy( _this.object.position ); + + } + + }; + + this.reset = function () { + + _state = STATE.NONE; + _prevState = STATE.NONE; + + _this.target.copy( _this.target0 ); + _this.object.position.copy( _this.position0 ); + _this.object.up.copy( _this.up0 ); + + _eye.subVectors( _this.object.position, _this.target ); + + _this.object.lookAt( _this.target ); + + _this.dispatchEvent( changeEvent ); + + lastPosition.copy( _this.object.position ); + + }; + + // listeners + + function keydown( event ) { + + if ( _this.enabled === false ) return; + + window.removeEventListener( 'keydown', keydown ); + + _prevState = _state; + + if ( _state !== STATE.NONE ) { + + return; + + } else if ( event.keyCode === _this.keys[ STATE.ROTATE ] && !_this.noRotate ) { + + _state = STATE.ROTATE; + + } else if ( event.keyCode === _this.keys[ STATE.ZOOM ] && !_this.noZoom ) { + + _state = STATE.ZOOM; + + } else if ( event.keyCode === _this.keys[ STATE.PAN ] && !_this.noPan ) { + + _state = STATE.PAN; + + } + + } + + function keyup( event ) { + + if ( _this.enabled === false ) return; + + _state = _prevState; + + window.addEventListener( 'keydown', keydown, false ); + + } + + function mousedown( event ) { + + if ( _this.enabled === false ) return; + + event.preventDefault(); + event.stopPropagation(); + + if ( _state === STATE.NONE ) { + + _state = event.button; + + } + + if ( _state === STATE.ROTATE && !_this.noRotate ) { + + _rotateStart = _rotateEnd = _this.getMouseProjectionOnBall( event.clientX, event.clientY ); + + } else if ( _state === STATE.ZOOM && !_this.noZoom ) { + + _zoomStart = _zoomEnd = _this.getMouseOnScreen( event.clientX, event.clientY ); + + } else if ( _state === STATE.PAN && !_this.noPan ) { + + _panStart = _panEnd = _this.getMouseOnScreen( event.clientX, event.clientY ); + + } + + document.addEventListener( 'mousemove', mousemove, false ); + document.addEventListener( 'mouseup', mouseup, false ); + + } + + function mousemove( event ) { + + if ( _this.enabled === false ) return; + + event.preventDefault(); + event.stopPropagation(); + + if ( _state === STATE.ROTATE && !_this.noRotate ) { + + _rotateEnd = _this.getMouseProjectionOnBall( event.clientX, event.clientY ); + + } else if ( _state === STATE.ZOOM && !_this.noZoom ) { + + _zoomEnd = _this.getMouseOnScreen( event.clientX, event.clientY ); + + } else if ( _state === STATE.PAN && !_this.noPan ) { + + _panEnd = _this.getMouseOnScreen( event.clientX, event.clientY ); + + } + + } + + function mouseup( event ) { + + if ( _this.enabled === false ) return; + + event.preventDefault(); + event.stopPropagation(); + + _state = STATE.NONE; + + document.removeEventListener( 'mousemove', mousemove ); + document.removeEventListener( 'mouseup', mouseup ); + + } + + function mousewheel( event ) { + + if ( _this.enabled === false ) return; + + event.preventDefault(); + event.stopPropagation(); + + var delta = 0; + + if ( event.wheelDelta ) { // WebKit / Opera / Explorer 9 + + delta = event.wheelDelta / 40; + + } else if ( event.detail ) { // Firefox + + delta = - event.detail / 3; + + } + + _zoomStart.y += ( 1 / delta ) * 0.05; + + } + + function touchstart( event ) { + + if ( _this.enabled === false ) return; + + switch ( event.touches.length ) { + + case 1: + _state = STATE.TOUCH_ROTATE; + _rotateStart = _rotateEnd = _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + break; + + case 2: + _state = STATE.TOUCH_ZOOM; + var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; + var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; + _touchZoomDistanceEnd = _touchZoomDistanceStart = Math.sqrt( dx * dx + dy * dy ); + break; + + case 3: + _state = STATE.TOUCH_PAN; + _panStart = _panEnd = _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + break; + + default: + _state = STATE.NONE; + + } + + } + + function touchmove( event ) { + + if ( _this.enabled === false ) return; + + event.preventDefault(); + event.stopPropagation(); + + switch ( event.touches.length ) { + + case 1: + _rotateEnd = _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + break; + + case 2: + var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; + var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; + _touchZoomDistanceEnd = Math.sqrt( dx * dx + dy * dy ) + break; + + case 3: + _panEnd = _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + break; + + default: + _state = STATE.NONE; + + } + + } + + function touchend( event ) { + + if ( _this.enabled === false ) return; + + switch ( event.touches.length ) { + + case 1: + _rotateStart = _rotateEnd = _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + break; + + case 2: + _touchZoomDistanceStart = _touchZoomDistanceEnd = 0; + break; + + case 3: + _panStart = _panEnd = _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + break; + + } + + _state = STATE.NONE; + + } + + this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false ); + + this.domElement.addEventListener( 'mousedown', mousedown, false ); + + this.domElement.addEventListener( 'mousewheel', mousewheel, false ); + this.domElement.addEventListener( 'DOMMouseScroll', mousewheel, false ); // firefox + + this.domElement.addEventListener( 'touchstart', touchstart, false ); + this.domElement.addEventListener( 'touchend', touchend, false ); + this.domElement.addEventListener( 'touchmove', touchmove, false ); + + window.addEventListener( 'keydown', keydown, false ); + window.addEventListener( 'keyup', keyup, false ); + + this.handleResize(); + +}; diff --git a/COGNET/lib/dat.gui.min.js b/COGNET/lib/dat.gui.min.js new file mode 100644 index 0000000000000000000000000000000000000000..4d7aac9e753deba83dd914fb21d1f627645f51ad --- /dev/null +++ b/COGNET/lib/dat.gui.min.js @@ -0,0 +1,94 @@ +/** + * dat-gui JavaScript Controller Library + * http://code.google.com/p/dat-gui + * + * Copyright 2011 Data Arts Team, Google Creative Lab + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ +export var dat=dat||{};dat.gui=dat.gui||{};dat.utils=dat.utils||{};dat.controllers=dat.controllers||{};dat.dom=dat.dom||{};dat.color=dat.color||{};dat.utils.css=function(){return{load:function(e,a){var a=a||document,c=a.createElement("link");c.type="text/css";c.rel="stylesheet";c.href=e;a.getElementsByTagName("head")[0].appendChild(c)},inject:function(e,a){var a=a||document,c=document.createElement("style");c.type="text/css";c.innerHTML=e;a.getElementsByTagName("head")[0].appendChild(c)}}}(); +dat.utils.common=function(){var e=Array.prototype.forEach,a=Array.prototype.slice;return{BREAK:{},extend:function(c){this.each(a.call(arguments,1),function(a){for(var f in a)this.isUndefined(a[f])||(c[f]=a[f])},this);return c},defaults:function(c){this.each(a.call(arguments,1),function(a){for(var f in a)this.isUndefined(c[f])&&(c[f]=a[f])},this);return c},compose:function(){var c=a.call(arguments);return function(){for(var d=a.call(arguments),f=c.length-1;f>=0;f--)d=[c[f].apply(this,d)];return d[0]}}, + each:function(a,d,f){if(e&&a.forEach===e)a.forEach(d,f);else if(a.length===a.length+0)for(var b=0,n=a.length;b<n;b++){if(b in a&&d.call(f,a[b],b)===this.BREAK)break}else for(b in a)if(d.call(f,a[b],b)===this.BREAK)break},defer:function(a){setTimeout(a,0)},toArray:function(c){return c.toArray?c.toArray():a.call(c)},isUndefined:function(a){return a===void 0},isNull:function(a){return a===null},isNaN:function(a){return a!==a},isArray:Array.isArray||function(a){return a.constructor===Array},isObject:function(a){return a=== + Object(a)},isNumber:function(a){return a===a+0},isString:function(a){return a===a+""},isBoolean:function(a){return a===false||a===true},isFunction:function(a){return Object.prototype.toString.call(a)==="[object Function]"}}}(); +dat.controllers.Controller=function(e){var a=function(a,d){this.initialValue=a[d];this.domElement=document.createElement("div");this.object=a;this.property=d;this.__onFinishChange=this.__onChange=void 0};e.extend(a.prototype,{onChange:function(a){this.__onChange=a;return this},onFinishChange:function(a){this.__onFinishChange=a;return this},setValue:function(a){this.object[this.property]=a;this.__onChange&&this.__onChange.call(this,a);this.updateDisplay();return this},getValue:function(){return this.object[this.property]}, + updateDisplay:function(){return this},isModified:function(){return this.initialValue!==this.getValue()}});return a}(dat.utils.common); +dat.dom.dom=function(e){function a(b){if(b==="0"||e.isUndefined(b))return 0;b=b.match(d);return!e.isNull(b)?parseFloat(b[1]):0}var c={};e.each({HTMLEvents:["change"],MouseEvents:["click","mousemove","mousedown","mouseup","mouseover"],KeyboardEvents:["keydown"]},function(b,a){e.each(b,function(b){c[b]=a})});var d=/(\d+(\.\d+)?)px/,f={makeSelectable:function(b,a){if(!(b===void 0||b.style===void 0))b.onselectstart=a?function(){return false}:function(){},b.style.MozUserSelect=a?"auto":"none",b.style.KhtmlUserSelect= + a?"auto":"none",b.unselectable=a?"on":"off"},makeFullscreen:function(b,a,d){e.isUndefined(a)&&(a=true);e.isUndefined(d)&&(d=true);b.style.position="absolute";if(a)b.style.left=0,b.style.right=0;if(d)b.style.top=0,b.style.bottom=0},fakeEvent:function(b,a,d,f){var d=d||{},m=c[a];if(!m)throw Error("Event type "+a+" not supported.");var l=document.createEvent(m);switch(m){case "MouseEvents":l.initMouseEvent(a,d.bubbles||false,d.cancelable||true,window,d.clickCount||1,0,0,d.x||d.clientX||0,d.y||d.clientY|| + 0,false,false,false,false,0,null);break;case "KeyboardEvents":m=l.initKeyboardEvent||l.initKeyEvent;e.defaults(d,{cancelable:true,ctrlKey:false,altKey:false,shiftKey:false,metaKey:false,keyCode:void 0,charCode:void 0});m(a,d.bubbles||false,d.cancelable,window,d.ctrlKey,d.altKey,d.shiftKey,d.metaKey,d.keyCode,d.charCode);break;default:l.initEvent(a,d.bubbles||false,d.cancelable||true)}e.defaults(l,f);b.dispatchEvent(l)},bind:function(b,a,d,c){b.addEventListener?b.addEventListener(a,d,c||false):b.attachEvent&& + b.attachEvent("on"+a,d);return f},unbind:function(b,a,d,c){b.removeEventListener?b.removeEventListener(a,d,c||false):b.detachEvent&&b.detachEvent("on"+a,d);return f},addClass:function(b,a){if(b.className===void 0)b.className=a;else if(b.className!==a){var d=b.className.split(/ +/);if(d.indexOf(a)==-1)d.push(a),b.className=d.join(" ").replace(/^\s+/,"").replace(/\s+$/,"")}return f},removeClass:function(b,a){if(a){if(b.className!==void 0)if(b.className===a)b.removeAttribute("class");else{var d=b.className.split(/ +/), + c=d.indexOf(a);if(c!=-1)d.splice(c,1),b.className=d.join(" ")}}else b.className=void 0;return f},hasClass:function(a,d){return RegExp("(?:^|\\s+)"+d+"(?:\\s+|$)").test(a.className)||false},getWidth:function(b){b=getComputedStyle(b);return a(b["border-left-width"])+a(b["border-right-width"])+a(b["padding-left"])+a(b["padding-right"])+a(b.width)},getHeight:function(b){b=getComputedStyle(b);return a(b["border-top-width"])+a(b["border-bottom-width"])+a(b["padding-top"])+a(b["padding-bottom"])+a(b.height)}, + getOffset:function(a){var d={left:0,top:0};if(a.offsetParent){do d.left+=a.offsetLeft,d.top+=a.offsetTop;while(a=a.offsetParent)}return d},isActive:function(a){return a===document.activeElement&&(a.type||a.href)}};return f}(dat.utils.common); +dat.controllers.OptionController=function(e,a,c){var d=function(f,b,e){d.superclass.call(this,f,b);var h=this;this.__select=document.createElement("select");if(c.isArray(e)){var j={};c.each(e,function(a){j[a]=a});e=j}c.each(e,function(a,b){var d=document.createElement("option");d.innerHTML=b;d.setAttribute("value",a);h.__select.appendChild(d)});this.updateDisplay();a.bind(this.__select,"change",function(){h.setValue(this.options[this.selectedIndex].value)});this.domElement.appendChild(this.__select)}; + d.superclass=e;c.extend(d.prototype,e.prototype,{setValue:function(a){a=d.superclass.prototype.setValue.call(this,a);this.__onFinishChange&&this.__onFinishChange.call(this,this.getValue());return a},updateDisplay:function(){this.__select.value=this.getValue();return d.superclass.prototype.updateDisplay.call(this)}});return d}(dat.controllers.Controller,dat.dom.dom,dat.utils.common); +dat.controllers.NumberController=function(e,a){var c=function(d,f,b){c.superclass.call(this,d,f);b=b||{};this.__min=b.min;this.__max=b.max;this.__step=b.step;d=this.__impliedStep=a.isUndefined(this.__step)?this.initialValue==0?1:Math.pow(10,Math.floor(Math.log(this.initialValue)/Math.LN10))/10:this.__step;d=d.toString();this.__precision=d.indexOf(".")>-1?d.length-d.indexOf(".")-1:0};c.superclass=e;a.extend(c.prototype,e.prototype,{setValue:function(a){if(this.__min!==void 0&&a<this.__min)a=this.__min; + else if(this.__max!==void 0&&a>this.__max)a=this.__max;this.__step!==void 0&&a%this.__step!=0&&(a=Math.round(a/this.__step)*this.__step);return c.superclass.prototype.setValue.call(this,a)},min:function(a){this.__min=a;return this},max:function(a){this.__max=a;return this},step:function(a){this.__step=a;return this}});return c}(dat.controllers.Controller,dat.utils.common); +dat.controllers.NumberControllerBox=function(e,a,c){var d=function(f,b,e){function h(){var a=parseFloat(l.__input.value);c.isNaN(a)||l.setValue(a)}function j(a){var b=o-a.clientY;l.setValue(l.getValue()+b*l.__impliedStep);o=a.clientY}function m(){a.unbind(window,"mousemove",j);a.unbind(window,"mouseup",m)}this.__truncationSuspended=false;d.superclass.call(this,f,b,e);var l=this,o;this.__input=document.createElement("input");this.__input.setAttribute("type","text");a.bind(this.__input,"change",h); + a.bind(this.__input,"blur",function(){h();l.__onFinishChange&&l.__onFinishChange.call(l,l.getValue())});a.bind(this.__input,"mousedown",function(b){a.bind(window,"mousemove",j);a.bind(window,"mouseup",m);o=b.clientY});a.bind(this.__input,"keydown",function(a){if(a.keyCode===13)l.__truncationSuspended=true,this.blur(),l.__truncationSuspended=false});this.updateDisplay();this.domElement.appendChild(this.__input)};d.superclass=e;c.extend(d.prototype,e.prototype,{updateDisplay:function(){var a=this.__input, + b;if(this.__truncationSuspended)b=this.getValue();else{b=this.getValue();var c=Math.pow(10,this.__precision);b=Math.round(b*c)/c}a.value=b;return d.superclass.prototype.updateDisplay.call(this)}});return d}(dat.controllers.NumberController,dat.dom.dom,dat.utils.common); +dat.controllers.NumberControllerSlider=function(e,a,c,d,f){var b=function(d,c,f,e,l){function o(b){b.preventDefault();var d=a.getOffset(g.__background),c=a.getWidth(g.__background);g.setValue(g.__min+(g.__max-g.__min)*((b.clientX-d.left)/(d.left+c-d.left)));return false}function y(){a.unbind(window,"mousemove",o);a.unbind(window,"mouseup",y);g.__onFinishChange&&g.__onFinishChange.call(g,g.getValue())}b.superclass.call(this,d,c,{min:f,max:e,step:l});var g=this;this.__background=document.createElement("div"); + this.__foreground=document.createElement("div");a.bind(this.__background,"mousedown",function(b){a.bind(window,"mousemove",o);a.bind(window,"mouseup",y);o(b)});a.addClass(this.__background,"slider");a.addClass(this.__foreground,"slider-fg");this.updateDisplay();this.__background.appendChild(this.__foreground);this.domElement.appendChild(this.__background)};b.superclass=e;b.useDefaultStyles=function(){c.inject(f)};d.extend(b.prototype,e.prototype,{updateDisplay:function(){this.__foreground.style.width= + (this.getValue()-this.__min)/(this.__max-this.__min)*100+"%";return b.superclass.prototype.updateDisplay.call(this)}});return b}(dat.controllers.NumberController,dat.dom.dom,dat.utils.css,dat.utils.common,".slider {\n box-shadow: inset 0 2px 4px rgba(0,0,0,0.15);\n height: 1em;\n border-radius: 1em;\n background-color: #eee;\n padding: 0 0.5em;\n overflow: hidden;\n}\n\n.slider-fg {\n padding: 1px 0 2px 0;\n background-color: #aaa;\n height: 1em;\n margin-left: -0.5em;\n padding-right: 0.5em;\n border-radius: 1em 0 0 1em;\n}\n\n.slider-fg:after {\n display: inline-block;\n border-radius: 1em;\n background-color: #fff;\n border: 1px solid #aaa;\n content: '';\n float: right;\n margin-right: -1em;\n margin-top: -1px;\n height: 0.9em;\n width: 0.9em;\n}"); +dat.controllers.FunctionController=function(e,a,c){var d=function(c,b,e){d.superclass.call(this,c,b);var h=this;this.__button=document.createElement("div");this.__button.innerHTML=e===void 0?"Fire":e;a.bind(this.__button,"click",function(a){a.preventDefault();h.fire();return false});a.addClass(this.__button,"button");this.domElement.appendChild(this.__button)};d.superclass=e;c.extend(d.prototype,e.prototype,{fire:function(){this.__onChange&&this.__onChange.call(this);this.__onFinishChange&&this.__onFinishChange.call(this, + this.getValue());this.getValue().call(this.object)}});return d}(dat.controllers.Controller,dat.dom.dom,dat.utils.common); +dat.controllers.BooleanController=function(e,a,c){var d=function(c,b){d.superclass.call(this,c,b);var e=this;this.__prev=this.getValue();this.__checkbox=document.createElement("input");this.__checkbox.setAttribute("type","checkbox");a.bind(this.__checkbox,"change",function(){e.setValue(!e.__prev)},false);this.domElement.appendChild(this.__checkbox);this.updateDisplay()};d.superclass=e;c.extend(d.prototype,e.prototype,{setValue:function(a){a=d.superclass.prototype.setValue.call(this,a);this.__onFinishChange&& + this.__onFinishChange.call(this,this.getValue());this.__prev=this.getValue();return a},updateDisplay:function(){this.getValue()===true?(this.__checkbox.setAttribute("checked","checked"),this.__checkbox.checked=true):this.__checkbox.checked=false;return d.superclass.prototype.updateDisplay.call(this)}});return d}(dat.controllers.Controller,dat.dom.dom,dat.utils.common); +dat.color.toString=function(e){return function(a){if(a.a==1||e.isUndefined(a.a)){for(a=a.hex.toString(16);a.length<6;)a="0"+a;return"#"+a}else return"rgba("+Math.round(a.r)+","+Math.round(a.g)+","+Math.round(a.b)+","+a.a+")"}}(dat.utils.common); +dat.color.interpret=function(e,a){var c,d,f=[{litmus:a.isString,conversions:{THREE_CHAR_HEX:{read:function(a){a=a.match(/^#([A-F0-9])([A-F0-9])([A-F0-9])$/i);return a===null?false:{space:"HEX",hex:parseInt("0x"+a[1].toString()+a[1].toString()+a[2].toString()+a[2].toString()+a[3].toString()+a[3].toString())}},write:e},SIX_CHAR_HEX:{read:function(a){a=a.match(/^#([A-F0-9]{6})$/i);return a===null?false:{space:"HEX",hex:parseInt("0x"+a[1].toString())}},write:e},CSS_RGB:{read:function(a){a=a.match(/^rgb\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\)/); + return a===null?false:{space:"RGB",r:parseFloat(a[1]),g:parseFloat(a[2]),b:parseFloat(a[3])}},write:e},CSS_RGBA:{read:function(a){a=a.match(/^rgba\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\,\s*(.+)\s*\)/);return a===null?false:{space:"RGB",r:parseFloat(a[1]),g:parseFloat(a[2]),b:parseFloat(a[3]),a:parseFloat(a[4])}},write:e}}},{litmus:a.isNumber,conversions:{HEX:{read:function(a){return{space:"HEX",hex:a,conversionName:"HEX"}},write:function(a){return a.hex}}}},{litmus:a.isArray,conversions:{RGB_ARRAY:{read:function(a){return a.length!= + 3?false:{space:"RGB",r:a[0],g:a[1],b:a[2]}},write:function(a){return[a.r,a.g,a.b]}},RGBA_ARRAY:{read:function(a){return a.length!=4?false:{space:"RGB",r:a[0],g:a[1],b:a[2],a:a[3]}},write:function(a){return[a.r,a.g,a.b,a.a]}}}},{litmus:a.isObject,conversions:{RGBA_OBJ:{read:function(b){return a.isNumber(b.r)&&a.isNumber(b.g)&&a.isNumber(b.b)&&a.isNumber(b.a)?{space:"RGB",r:b.r,g:b.g,b:b.b,a:b.a}:false},write:function(a){return{r:a.r,g:a.g,b:a.b,a:a.a}}},RGB_OBJ:{read:function(b){return a.isNumber(b.r)&& + a.isNumber(b.g)&&a.isNumber(b.b)?{space:"RGB",r:b.r,g:b.g,b:b.b}:false},write:function(a){return{r:a.r,g:a.g,b:a.b}}},HSVA_OBJ:{read:function(b){return a.isNumber(b.h)&&a.isNumber(b.s)&&a.isNumber(b.v)&&a.isNumber(b.a)?{space:"HSV",h:b.h,s:b.s,v:b.v,a:b.a}:false},write:function(a){return{h:a.h,s:a.s,v:a.v,a:a.a}}},HSV_OBJ:{read:function(b){return a.isNumber(b.h)&&a.isNumber(b.s)&&a.isNumber(b.v)?{space:"HSV",h:b.h,s:b.s,v:b.v}:false},write:function(a){return{h:a.h,s:a.s,v:a.v}}}}}];return function(){d= + false;var b=arguments.length>1?a.toArray(arguments):arguments[0];a.each(f,function(e){if(e.litmus(b))return a.each(e.conversions,function(e,f){c=e.read(b);if(d===false&&c!==false)return d=c,c.conversionName=f,c.conversion=e,a.BREAK}),a.BREAK});return d}}(dat.color.toString,dat.utils.common); +dat.GUI=dat.gui.GUI=function(e,a,c,d,f,b,n,h,j,m,l,o,y,g,i){function q(a,b,r,c){if(b[r]===void 0)throw Error("Object "+b+' has no property "'+r+'"');c.color?b=new l(b,r):(b=[b,r].concat(c.factoryArgs),b=d.apply(a,b));if(c.before instanceof f)c.before=c.before.__li;t(a,b);g.addClass(b.domElement,"c");r=document.createElement("span");g.addClass(r,"property-name");r.innerHTML=b.property;var e=document.createElement("div");e.appendChild(r);e.appendChild(b.domElement);c=s(a,e,c.before);g.addClass(c,k.CLASS_CONTROLLER_ROW); + g.addClass(c,typeof b.getValue());p(a,c,b);a.__controllers.push(b);return b}function s(a,b,d){var c=document.createElement("li");b&&c.appendChild(b);d?a.__ul.insertBefore(c,params.before):a.__ul.appendChild(c);a.onResize();return c}function p(a,d,c){c.__li=d;c.__gui=a;i.extend(c,{options:function(b){if(arguments.length>1)return c.remove(),q(a,c.object,c.property,{before:c.__li.nextElementSibling,factoryArgs:[i.toArray(arguments)]});if(i.isArray(b)||i.isObject(b))return c.remove(),q(a,c.object,c.property, + {before:c.__li.nextElementSibling,factoryArgs:[b]})},name:function(a){c.__li.firstElementChild.firstElementChild.innerHTML=a;return c},listen:function(){c.__gui.listen(c);return c},remove:function(){c.__gui.remove(c);return c}});if(c instanceof j){var e=new h(c.object,c.property,{min:c.__min,max:c.__max,step:c.__step});i.each(["updateDisplay","onChange","onFinishChange"],function(a){var b=c[a],H=e[a];c[a]=e[a]=function(){var a=Array.prototype.slice.call(arguments);b.apply(c,a);return H.apply(e,a)}}); + g.addClass(d,"has-slider");c.domElement.insertBefore(e.domElement,c.domElement.firstElementChild)}else if(c instanceof h){var f=function(b){return i.isNumber(c.__min)&&i.isNumber(c.__max)?(c.remove(),q(a,c.object,c.property,{before:c.__li.nextElementSibling,factoryArgs:[c.__min,c.__max,c.__step]})):b};c.min=i.compose(f,c.min);c.max=i.compose(f,c.max)}else if(c instanceof b)g.bind(d,"click",function(){g.fakeEvent(c.__checkbox,"click")}),g.bind(c.__checkbox,"click",function(a){a.stopPropagation()}); +else if(c instanceof n)g.bind(d,"click",function(){g.fakeEvent(c.__button,"click")}),g.bind(d,"mouseover",function(){g.addClass(c.__button,"hover")}),g.bind(d,"mouseout",function(){g.removeClass(c.__button,"hover")});else if(c instanceof l)g.addClass(d,"color"),c.updateDisplay=i.compose(function(a){d.style.borderLeftColor=c.__color.toString();return a},c.updateDisplay),c.updateDisplay();c.setValue=i.compose(function(b){a.getRoot().__preset_select&&c.isModified()&&B(a.getRoot(),true);return b},c.setValue)} + function t(a,b){var c=a.getRoot(),d=c.__rememberedObjects.indexOf(b.object);if(d!=-1){var e=c.__rememberedObjectIndecesToControllers[d];e===void 0&&(e={},c.__rememberedObjectIndecesToControllers[d]=e);e[b.property]=b;if(c.load&&c.load.remembered){c=c.load.remembered;if(c[a.preset])c=c[a.preset];else if(c[w])c=c[w];else return;if(c[d]&&c[d][b.property]!==void 0)d=c[d][b.property],b.initialValue=d,b.setValue(d)}}}function I(a){var b=a.__save_row=document.createElement("li");g.addClass(a.domElement, + "has-save");a.__ul.insertBefore(b,a.__ul.firstChild);g.addClass(b,"save-row");var c=document.createElement("span");c.innerHTML=" ";g.addClass(c,"button gears");var d=document.createElement("span");d.innerHTML="Save";g.addClass(d,"button");g.addClass(d,"save");var e=document.createElement("span");e.innerHTML="New";g.addClass(e,"button");g.addClass(e,"save-as");var f=document.createElement("span");f.innerHTML="Revert";g.addClass(f,"button");g.addClass(f,"revert");var m=a.__preset_select=document.createElement("select"); + a.load&&a.load.remembered?i.each(a.load.remembered,function(b,c){C(a,c,c==a.preset)}):C(a,w,false);g.bind(m,"change",function(){for(var b=0;b<a.__preset_select.length;b++)a.__preset_select[b].innerHTML=a.__preset_select[b].value;a.preset=this.value});b.appendChild(m);b.appendChild(c);b.appendChild(d);b.appendChild(e);b.appendChild(f);if(u){var b=document.getElementById("dg-save-locally"),l=document.getElementById("dg-local-explain");b.style.display="block";b=document.getElementById("dg-local-storage"); + localStorage.getItem(document.location.href+".isLocal")==="true"&&b.setAttribute("checked","checked");var o=function(){l.style.display=a.useLocalStorage?"block":"none"};o();g.bind(b,"change",function(){a.useLocalStorage=!a.useLocalStorage;o()})}var h=document.getElementById("dg-new-constructor");g.bind(h,"keydown",function(a){a.metaKey&&(a.which===67||a.keyCode==67)&&x.hide()});g.bind(c,"click",function(){h.innerHTML=JSON.stringify(a.getSaveObject(),void 0,2);x.show();h.focus();h.select()});g.bind(d, + "click",function(){a.save()});g.bind(e,"click",function(){var b=prompt("Enter a new preset name.");b&&a.saveAs(b)});g.bind(f,"click",function(){a.revert()})}function J(a){function b(f){f.preventDefault();e=f.clientX;g.addClass(a.__closeButton,k.CLASS_DRAG);g.bind(window,"mousemove",c);g.bind(window,"mouseup",d);return false}function c(b){b.preventDefault();a.width+=e-b.clientX;a.onResize();e=b.clientX;return false}function d(){g.removeClass(a.__closeButton,k.CLASS_DRAG);g.unbind(window,"mousemove", + c);g.unbind(window,"mouseup",d)}a.__resize_handle=document.createElement("div");i.extend(a.__resize_handle.style,{width:"6px",marginLeft:"-3px",height:"200px",cursor:"ew-resize",position:"absolute"});var e;g.bind(a.__resize_handle,"mousedown",b);g.bind(a.__closeButton,"mousedown",b);a.domElement.insertBefore(a.__resize_handle,a.domElement.firstElementChild)}function D(a,b){a.domElement.style.width=b+"px";if(a.__save_row&&a.autoPlace)a.__save_row.style.width=b+"px";if(a.__closeButton)a.__closeButton.style.width= + b+"px"}function z(a,b){var c={};i.each(a.__rememberedObjects,function(d,e){var f={};i.each(a.__rememberedObjectIndecesToControllers[e],function(a,c){f[c]=b?a.initialValue:a.getValue()});c[e]=f});return c}function C(a,b,c){var d=document.createElement("option");d.innerHTML=b;d.value=b;a.__preset_select.appendChild(d);if(c)a.__preset_select.selectedIndex=a.__preset_select.length-1}function B(a,b){var c=a.__preset_select[a.__preset_select.selectedIndex];c.innerHTML=b?c.value+"*":c.value}function E(a){a.length!= + 0&&o(function(){E(a)});i.each(a,function(a){a.updateDisplay()})}e.inject(c);var w="Default",u;try{u="localStorage"in window&&window.localStorage!==null}catch(K){u=false}var x,F=true,v,A=false,G=[],k=function(a){function b(){localStorage.setItem(document.location.href+".gui",JSON.stringify(d.getSaveObject()))}function c(){var a=d.getRoot();a.width+=1;i.defer(function(){a.width-=1})}var d=this;this.domElement=document.createElement("div");this.__ul=document.createElement("ul");this.domElement.appendChild(this.__ul); + g.addClass(this.domElement,"dg");this.__folders={};this.__controllers=[];this.__rememberedObjects=[];this.__rememberedObjectIndecesToControllers=[];this.__listening=[];a=a||{};a=i.defaults(a,{autoPlace:true,width:k.DEFAULT_WIDTH});a=i.defaults(a,{resizable:a.autoPlace,hideable:a.autoPlace});if(i.isUndefined(a.load))a.load={preset:w};else if(a.preset)a.load.preset=a.preset;i.isUndefined(a.parent)&&a.hideable&&G.push(this);a.resizable=i.isUndefined(a.parent)&&a.resizable;if(a.autoPlace&&i.isUndefined(a.scrollable))a.scrollable= + true;var e=u&&localStorage.getItem(document.location.href+".isLocal")==="true";Object.defineProperties(this,{parent:{get:function(){return a.parent}},scrollable:{get:function(){return a.scrollable}},autoPlace:{get:function(){return a.autoPlace}},preset:{get:function(){return d.parent?d.getRoot().preset:a.load.preset},set:function(b){d.parent?d.getRoot().preset=b:a.load.preset=b;for(b=0;b<this.__preset_select.length;b++)if(this.__preset_select[b].value==this.preset)this.__preset_select.selectedIndex= + b;d.revert()}},width:{get:function(){return a.width},set:function(b){a.width=b;D(d,b)}},name:{get:function(){return a.name},set:function(b){a.name=b;if(m)m.innerHTML=a.name}},closed:{get:function(){return a.closed},set:function(b){a.closed=b;a.closed?g.addClass(d.__ul,k.CLASS_CLOSED):g.removeClass(d.__ul,k.CLASS_CLOSED);this.onResize();if(d.__closeButton)d.__closeButton.innerHTML=b?k.TEXT_OPEN:k.TEXT_CLOSED}},load:{get:function(){return a.load}},useLocalStorage:{get:function(){return e},set:function(a){u&& + ((e=a)?g.bind(window,"unload",b):g.unbind(window,"unload",b),localStorage.setItem(document.location.href+".isLocal",a))}}});if(i.isUndefined(a.parent)){a.closed=false;g.addClass(this.domElement,k.CLASS_MAIN);g.makeSelectable(this.domElement,false);if(u&&e){d.useLocalStorage=true;var f=localStorage.getItem(document.location.href+".gui");if(f)a.load=JSON.parse(f)}this.__closeButton=document.createElement("div");this.__closeButton.innerHTML=k.TEXT_CLOSED;g.addClass(this.__closeButton,k.CLASS_CLOSE_BUTTON); + this.domElement.appendChild(this.__closeButton);g.bind(this.__closeButton,"click",function(){d.closed=!d.closed})}else{if(a.closed===void 0)a.closed=true;var m=document.createTextNode(a.name);g.addClass(m,"controller-name");f=s(d,m);g.addClass(this.__ul,k.CLASS_CLOSED);g.addClass(f,"title");g.bind(f,"click",function(a){a.preventDefault();d.closed=!d.closed;return false});if(!a.closed)this.closed=false}a.autoPlace&&(i.isUndefined(a.parent)&&(F&&(v=document.createElement("div"),g.addClass(v,"dg"),g.addClass(v, + k.CLASS_AUTO_PLACE_CONTAINER),document.body.appendChild(v),F=false),v.appendChild(this.domElement),g.addClass(this.domElement,k.CLASS_AUTO_PLACE)),this.parent||D(d,a.width));g.bind(window,"resize",function(){d.onResize()});g.bind(this.__ul,"webkitTransitionEnd",function(){d.onResize()});g.bind(this.__ul,"transitionend",function(){d.onResize()});g.bind(this.__ul,"oTransitionEnd",function(){d.onResize()});this.onResize();a.resizable&&J(this);d.getRoot();a.parent||c()};k.toggleHide=function(){A=!A;i.each(G, + function(a){a.domElement.style.zIndex=A?-999:999;a.domElement.style.opacity=A?0:1})};k.CLASS_AUTO_PLACE="a";k.CLASS_AUTO_PLACE_CONTAINER="ac";k.CLASS_MAIN="main";k.CLASS_CONTROLLER_ROW="cr";k.CLASS_TOO_TALL="taller-than-window";k.CLASS_CLOSED="closed";k.CLASS_CLOSE_BUTTON="close-button";k.CLASS_DRAG="drag";k.DEFAULT_WIDTH=245;k.TEXT_CLOSED="Close Controls";k.TEXT_OPEN="Open Controls";g.bind(window,"keydown",function(a){document.activeElement.type!=="text"&&(a.which===72||a.keyCode==72)&&k.toggleHide()}, + false);i.extend(k.prototype,{add:function(a,b){return q(this,a,b,{factoryArgs:Array.prototype.slice.call(arguments,2)})},addColor:function(a,b){return q(this,a,b,{color:true})},remove:function(a){this.__ul.removeChild(a.__li);this.__controllers.slice(this.__controllers.indexOf(a),1);var b=this;i.defer(function(){b.onResize()})},destroy:function(){this.autoPlace&&v.removeChild(this.domElement)},addFolder:function(a){if(this.__folders[a]!==void 0)throw Error('You already have a folder in this GUI by the name "'+ + a+'"');var b={name:a,parent:this};b.autoPlace=this.autoPlace;if(this.load&&this.load.folders&&this.load.folders[a])b.closed=this.load.folders[a].closed,b.load=this.load.folders[a];b=new k(b);this.__folders[a]=b;a=s(this,b.domElement);g.addClass(a,"folder");return b},open:function(){this.closed=false},close:function(){this.closed=true},onResize:function(){var a=this.getRoot();if(a.scrollable){var b=g.getOffset(a.__ul).top,c=0;i.each(a.__ul.childNodes,function(b){a.autoPlace&&b===a.__save_row||(c+= + g.getHeight(b))});window.innerHeight-b-20<c?(g.addClass(a.domElement,k.CLASS_TOO_TALL),a.__ul.style.height=window.innerHeight-b-20+"px"):(g.removeClass(a.domElement,k.CLASS_TOO_TALL),a.__ul.style.height="auto")}a.__resize_handle&&i.defer(function(){a.__resize_handle.style.height=a.__ul.offsetHeight+"px"});if(a.__closeButton)a.__closeButton.style.width=a.width+"px"},remember:function(){if(i.isUndefined(x))x=new y,x.domElement.innerHTML=a;if(this.parent)throw Error("You can only call remember on a top level GUI."); + var b=this;i.each(Array.prototype.slice.call(arguments),function(a){b.__rememberedObjects.length==0&&I(b);b.__rememberedObjects.indexOf(a)==-1&&b.__rememberedObjects.push(a)});this.autoPlace&&D(this,this.width)},getRoot:function(){for(var a=this;a.parent;)a=a.parent;return a},getSaveObject:function(){var a=this.load;a.closed=this.closed;if(this.__rememberedObjects.length>0){a.preset=this.preset;if(!a.remembered)a.remembered={};a.remembered[this.preset]=z(this)}a.folders={};i.each(this.__folders,function(b, + c){a.folders[c]=b.getSaveObject()});return a},save:function(){if(!this.load.remembered)this.load.remembered={};this.load.remembered[this.preset]=z(this);B(this,false)},saveAs:function(a){if(!this.load.remembered)this.load.remembered={},this.load.remembered[w]=z(this,true);this.load.remembered[a]=z(this);this.preset=a;C(this,a,true)},revert:function(a){i.each(this.__controllers,function(b){this.getRoot().load.remembered?t(a||this.getRoot(),b):b.setValue(b.initialValue)},this);i.each(this.__folders, + function(a){a.revert(a)});a||B(this.getRoot(),false)},listen:function(a){var b=this.__listening.length==0;this.__listening.push(a);b&&E(this.__listening)}});return k}(dat.utils.css,'<div id="dg-save" class="dg dialogue">\n\n Here\'s the new load parameter for your <code>GUI</code>\'s constructor:\n\n <textarea id="dg-new-constructor"></textarea>\n\n <div id="dg-save-locally">\n\n <input id="dg-local-storage" type="checkbox"/> Automatically save\n values to <code>localStorage</code> on exit.\n\n <div id="dg-local-explain">The values saved to <code>localStorage</code> will\n override those passed to <code>dat.GUI</code>\'s constructor. This makes it\n easier to work incrementally, but <code>localStorage</code> is fragile,\n and your friends may not see the same values you do.\n \n </div>\n \n </div>\n\n</div>', + ".dg ul{list-style:none;margin:0;padding:0;width:100%;clear:both}.dg.ac{position:fixed;top:0;left:0;right:0;height:0;z-index:0}.dg:not(.ac) .main{overflow:hidden}.dg.main{-webkit-transition:opacity 0.1s linear;-o-transition:opacity 0.1s linear;-moz-transition:opacity 0.1s linear;transition:opacity 0.1s linear}.dg.main.taller-than-window{overflow-y:auto}.dg.main.taller-than-window .close-button{opacity:1;margin-top:-1px;border-top:1px solid #2c2c2c}.dg.main ul.closed .close-button{opacity:1 !important}.dg.main:hover .close-button,.dg.main .close-button.drag{opacity:1}.dg.main .close-button{-webkit-transition:opacity 0.1s linear;-o-transition:opacity 0.1s linear;-moz-transition:opacity 0.1s linear;transition:opacity 0.1s linear;border:0;position:absolute;line-height:19px;height:20px;cursor:pointer;text-align:center;background-color:#000}.dg.main .close-button:hover{background-color:#111}.dg.a{float:right;margin-right:15px;overflow-x:hidden}.dg.a.has-save ul{margin-top:27px}.dg.a.has-save ul.closed{margin-top:0}.dg.a .save-row{position:fixed;top:0;z-index:1002}.dg li{-webkit-transition:height 0.1s ease-out;-o-transition:height 0.1s ease-out;-moz-transition:height 0.1s ease-out;transition:height 0.1s ease-out}.dg li:not(.folder){cursor:auto;height:27px;line-height:27px;overflow:hidden;padding:0 4px 0 5px}.dg li.folder{padding:0;border-left:4px solid rgba(0,0,0,0)}.dg li.title{cursor:pointer;margin-left:-4px}.dg .closed li:not(.title),.dg .closed ul li,.dg .closed ul li > *{height:0;overflow:hidden;border:0}.dg .cr{clear:both;padding-left:3px;height:27px}.dg .property-name{cursor:default;float:left;clear:left;width:40%;overflow:hidden;text-overflow:ellipsis}.dg .c{float:left;width:60%}.dg .c input[type=text]{border:0;margin-top:4px;padding:3px;width:100%;float:right}.dg .has-slider input[type=text]{width:30%;margin-left:0}.dg .slider{float:left;width:66%;margin-left:-5px;margin-right:0;height:19px;margin-top:4px}.dg .slider-fg{height:100%}.dg .c input[type=checkbox]{margin-top:9px}.dg .c select{margin-top:5px}.dg .cr.function,.dg .cr.function .property-name,.dg .cr.function *,.dg .cr.boolean,.dg .cr.boolean *{cursor:pointer}.dg .selector{display:none;position:absolute;margin-left:-9px;margin-top:23px;z-index:10}.dg .c:hover .selector,.dg .selector.drag{display:block}.dg li.save-row{padding:0}.dg li.save-row .button{display:inline-block;padding:0px 6px}.dg.dialogue{background-color:#222;width:460px;padding:15px;font-size:13px;line-height:15px}#dg-new-constructor{padding:10px;color:#222;font-family:Monaco, monospace;font-size:10px;border:0;resize:none;box-shadow:inset 1px 1px 1px #888;word-wrap:break-word;margin:12px 0;display:block;width:440px;overflow-y:scroll;height:100px;position:relative}#dg-local-explain{display:none;font-size:11px;line-height:17px;border-radius:3px;background-color:#333;padding:8px;margin-top:10px}#dg-local-explain code{font-size:10px}#dat-gui-save-locally{display:none}.dg{color:#eee;font:11px 'Lucida Grande', sans-serif;text-shadow:0 -1px 0 #111}.dg.main::-webkit-scrollbar{width:5px;background:#1a1a1a}.dg.main::-webkit-scrollbar-corner{height:0;display:none}.dg.main::-webkit-scrollbar-thumb{border-radius:5px;background:#676767}.dg li:not(.folder){background:#1a1a1a;border-bottom:1px solid #2c2c2c}.dg li.save-row{line-height:25px;background:#dad5cb;border:0}.dg li.save-row select{margin-left:5px;width:108px}.dg li.save-row .button{margin-left:5px;margin-top:1px;border-radius:2px;font-size:9px;line-height:7px;padding:4px 4px 5px 4px;background:#c5bdad;color:#fff;text-shadow:0 1px 0 #b0a58f;box-shadow:0 -1px 0 #b0a58f;cursor:pointer}.dg li.save-row .button.gears{background:#c5bdad url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAANCAYAAAB/9ZQ7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQJJREFUeNpiYKAU/P//PwGIC/ApCABiBSAW+I8AClAcgKxQ4T9hoMAEUrxx2QSGN6+egDX+/vWT4e7N82AMYoPAx/evwWoYoSYbACX2s7KxCxzcsezDh3evFoDEBYTEEqycggWAzA9AuUSQQgeYPa9fPv6/YWm/Acx5IPb7ty/fw+QZblw67vDs8R0YHyQhgObx+yAJkBqmG5dPPDh1aPOGR/eugW0G4vlIoTIfyFcA+QekhhHJhPdQxbiAIguMBTQZrPD7108M6roWYDFQiIAAv6Aow/1bFwXgis+f2LUAynwoIaNcz8XNx3Dl7MEJUDGQpx9gtQ8YCueB+D26OECAAQDadt7e46D42QAAAABJRU5ErkJggg==) 2px 1px no-repeat;height:7px;width:8px}.dg li.save-row .button:hover{background-color:#bab19e;box-shadow:0 -1px 0 #b0a58f}.dg li.folder{border-bottom:0}.dg li.title{padding-left:16px;background:#000 url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 6px 10px no-repeat;cursor:pointer;border-bottom:1px solid rgba(255,255,255,0.2)}.dg .closed li.title{background-image:url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlGIWqMCbWAEAOw==)}.dg .cr.boolean{border-left:3px solid #806787}.dg .cr.function{border-left:3px solid #e61d5f}.dg .cr.number{border-left:3px solid #2fa1d6}.dg .cr.number input[type=text]{color:#2fa1d6}.dg .cr.string{border-left:3px solid #1ed36f}.dg .cr.string input[type=text]{color:#1ed36f}.dg .cr.function:hover,.dg .cr.boolean:hover{background:#111}.dg .c input[type=text]{background:#303030;outline:none}.dg .c input[type=text]:hover{background:#3c3c3c}.dg .c input[type=text]:focus{background:#494949;color:#fff}.dg .c .slider{background:#303030;cursor:ew-resize}.dg .c .slider-fg{background:#2fa1d6}.dg .c .slider:hover{background:#3c3c3c}.dg .c .slider:hover .slider-fg{background:#44abda}\n", + dat.controllers.factory=function(e,a,c,d,f,b,n){return function(h,j,m,l){var o=h[j];if(n.isArray(m)||n.isObject(m))return new e(h,j,m);if(n.isNumber(o))return n.isNumber(m)&&n.isNumber(l)?new c(h,j,m,l):new a(h,j,{min:m,max:l});if(n.isString(o))return new d(h,j);if(n.isFunction(o))return new f(h,j,"");if(n.isBoolean(o))return new b(h,j)}}(dat.controllers.OptionController,dat.controllers.NumberControllerBox,dat.controllers.NumberControllerSlider,dat.controllers.StringController=function(e,a,c){var d= + function(c,b){function e(){h.setValue(h.__input.value)}d.superclass.call(this,c,b);var h=this;this.__input=document.createElement("input");this.__input.setAttribute("type","text");a.bind(this.__input,"keyup",e);a.bind(this.__input,"change",e);a.bind(this.__input,"blur",function(){h.__onFinishChange&&h.__onFinishChange.call(h,h.getValue())});a.bind(this.__input,"keydown",function(a){a.keyCode===13&&this.blur()});this.updateDisplay();this.domElement.appendChild(this.__input)};d.superclass=e;c.extend(d.prototype, + e.prototype,{updateDisplay:function(){if(!a.isActive(this.__input))this.__input.value=this.getValue();return d.superclass.prototype.updateDisplay.call(this)}});return d}(dat.controllers.Controller,dat.dom.dom,dat.utils.common),dat.controllers.FunctionController,dat.controllers.BooleanController,dat.utils.common),dat.controllers.Controller,dat.controllers.BooleanController,dat.controllers.FunctionController,dat.controllers.NumberControllerBox,dat.controllers.NumberControllerSlider,dat.controllers.OptionController, + dat.controllers.ColorController=function(e,a,c,d,f){function b(a,b,c,d){a.style.background="";f.each(j,function(e){a.style.cssText+="background: "+e+"linear-gradient("+b+", "+c+" 0%, "+d+" 100%); "})}function n(a){a.style.background="";a.style.cssText+="background: -moz-linear-gradient(top, #ff0000 0%, #ff00ff 17%, #0000ff 34%, #00ffff 50%, #00ff00 67%, #ffff00 84%, #ff0000 100%);";a.style.cssText+="background: -webkit-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);"; + a.style.cssText+="background: -o-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);";a.style.cssText+="background: -ms-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);";a.style.cssText+="background: linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);"}var h=function(e,l){function o(b){q(b);a.bind(window,"mousemove",q);a.bind(window, + "mouseup",j)}function j(){a.unbind(window,"mousemove",q);a.unbind(window,"mouseup",j)}function g(){var a=d(this.value);a!==false?(p.__color.__state=a,p.setValue(p.__color.toOriginal())):this.value=p.__color.toString()}function i(){a.unbind(window,"mousemove",s);a.unbind(window,"mouseup",i)}function q(b){b.preventDefault();var c=a.getWidth(p.__saturation_field),d=a.getOffset(p.__saturation_field),e=(b.clientX-d.left+document.body.scrollLeft)/c,b=1-(b.clientY-d.top+document.body.scrollTop)/c;b>1?b= + 1:b<0&&(b=0);e>1?e=1:e<0&&(e=0);p.__color.v=b;p.__color.s=e;p.setValue(p.__color.toOriginal());return false}function s(b){b.preventDefault();var c=a.getHeight(p.__hue_field),d=a.getOffset(p.__hue_field),b=1-(b.clientY-d.top+document.body.scrollTop)/c;b>1?b=1:b<0&&(b=0);p.__color.h=b*360;p.setValue(p.__color.toOriginal());return false}h.superclass.call(this,e,l);this.__color=new c(this.getValue());this.__temp=new c(0);var p=this;this.domElement=document.createElement("div");a.makeSelectable(this.domElement, + false);this.__selector=document.createElement("div");this.__selector.className="selector";this.__saturation_field=document.createElement("div");this.__saturation_field.className="saturation-field";this.__field_knob=document.createElement("div");this.__field_knob.className="field-knob";this.__field_knob_border="2px solid ";this.__hue_knob=document.createElement("div");this.__hue_knob.className="hue-knob";this.__hue_field=document.createElement("div");this.__hue_field.className="hue-field";this.__input= + document.createElement("input");this.__input.type="text";this.__input_textShadow="0 1px 1px ";a.bind(this.__input,"keydown",function(a){a.keyCode===13&&g.call(this)});a.bind(this.__input,"blur",g);a.bind(this.__selector,"mousedown",function(){a.addClass(this,"drag").bind(window,"mouseup",function(){a.removeClass(p.__selector,"drag")})});var t=document.createElement("div");f.extend(this.__selector.style,{width:"122px",height:"102px",padding:"3px",backgroundColor:"#222",boxShadow:"0px 1px 3px rgba(0,0,0,0.3)"}); + f.extend(this.__field_knob.style,{position:"absolute",width:"12px",height:"12px",border:this.__field_knob_border+(this.__color.v<0.5?"#fff":"#000"),boxShadow:"0px 1px 3px rgba(0,0,0,0.5)",borderRadius:"12px",zIndex:1});f.extend(this.__hue_knob.style,{position:"absolute",width:"15px",height:"2px",borderRight:"4px solid #fff",zIndex:1});f.extend(this.__saturation_field.style,{width:"100px",height:"100px",border:"1px solid #555",marginRight:"3px",display:"inline-block",cursor:"pointer"});f.extend(t.style, + {width:"100%",height:"100%",background:"none"});b(t,"top","rgba(0,0,0,0)","#000");f.extend(this.__hue_field.style,{width:"15px",height:"100px",display:"inline-block",border:"1px solid #555",cursor:"ns-resize"});n(this.__hue_field);f.extend(this.__input.style,{outline:"none",textAlign:"center",color:"#fff",border:0,fontWeight:"bold",textShadow:this.__input_textShadow+"rgba(0,0,0,0.7)"});a.bind(this.__saturation_field,"mousedown",o);a.bind(this.__field_knob,"mousedown",o);a.bind(this.__hue_field,"mousedown", + function(b){s(b);a.bind(window,"mousemove",s);a.bind(window,"mouseup",i)});this.__saturation_field.appendChild(t);this.__selector.appendChild(this.__field_knob);this.__selector.appendChild(this.__saturation_field);this.__selector.appendChild(this.__hue_field);this.__hue_field.appendChild(this.__hue_knob);this.domElement.appendChild(this.__input);this.domElement.appendChild(this.__selector);this.updateDisplay()};h.superclass=e;f.extend(h.prototype,e.prototype,{updateDisplay:function(){var a=d(this.getValue()); + if(a!==false){var e=false;f.each(c.COMPONENTS,function(b){if(!f.isUndefined(a[b])&&!f.isUndefined(this.__color.__state[b])&&a[b]!==this.__color.__state[b])return e=true,{}},this);e&&f.extend(this.__color.__state,a)}f.extend(this.__temp.__state,this.__color.__state);this.__temp.a=1;var h=this.__color.v<0.5||this.__color.s>0.5?255:0,j=255-h;f.extend(this.__field_knob.style,{marginLeft:100*this.__color.s-7+"px",marginTop:100*(1-this.__color.v)-7+"px",backgroundColor:this.__temp.toString(),border:this.__field_knob_border+ + "rgb("+h+","+h+","+h+")"});this.__hue_knob.style.marginTop=(1-this.__color.h/360)*100+"px";this.__temp.s=1;this.__temp.v=1;b(this.__saturation_field,"left","#fff",this.__temp.toString());f.extend(this.__input.style,{backgroundColor:this.__input.value=this.__color.toString(),color:"rgb("+h+","+h+","+h+")",textShadow:this.__input_textShadow+"rgba("+j+","+j+","+j+",.7)"})}});var j=["-moz-","-o-","-webkit-","-ms-",""];return h}(dat.controllers.Controller,dat.dom.dom,dat.color.Color=function(e,a,c,d){function f(a, + b,c){Object.defineProperty(a,b,{get:function(){if(this.__state.space==="RGB")return this.__state[b];n(this,b,c);return this.__state[b]},set:function(a){if(this.__state.space!=="RGB")n(this,b,c),this.__state.space="RGB";this.__state[b]=a}})}function b(a,b){Object.defineProperty(a,b,{get:function(){if(this.__state.space==="HSV")return this.__state[b];h(this);return this.__state[b]},set:function(a){if(this.__state.space!=="HSV")h(this),this.__state.space="HSV";this.__state[b]=a}})}function n(b,c,e){if(b.__state.space=== + "HEX")b.__state[c]=a.component_from_hex(b.__state.hex,e);else if(b.__state.space==="HSV")d.extend(b.__state,a.hsv_to_rgb(b.__state.h,b.__state.s,b.__state.v));else throw"Corrupted color state";}function h(b){var c=a.rgb_to_hsv(b.r,b.g,b.b);d.extend(b.__state,{s:c.s,v:c.v});if(d.isNaN(c.h)){if(d.isUndefined(b.__state.h))b.__state.h=0}else b.__state.h=c.h}var j=function(){this.__state=e.apply(this,arguments);if(this.__state===false)throw"Failed to interpret color arguments";this.__state.a=this.__state.a|| + 1};j.COMPONENTS="r,g,b,h,s,v,hex,a".split(",");d.extend(j.prototype,{toString:function(){return c(this)},toOriginal:function(){return this.__state.conversion.write(this)}});f(j.prototype,"r",2);f(j.prototype,"g",1);f(j.prototype,"b",0);b(j.prototype,"h");b(j.prototype,"s");b(j.prototype,"v");Object.defineProperty(j.prototype,"a",{get:function(){return this.__state.a},set:function(a){this.__state.a=a}});Object.defineProperty(j.prototype,"hex",{get:function(){if(!this.__state.space!=="HEX")this.__state.hex= + a.rgb_to_hex(this.r,this.g,this.b);return this.__state.hex},set:function(a){this.__state.space="HEX";this.__state.hex=a}});return j}(dat.color.interpret,dat.color.math=function(){var e;return{hsv_to_rgb:function(a,c,d){var e=a/60-Math.floor(a/60),b=d*(1-c),n=d*(1-e*c),c=d*(1-(1-e)*c),a=[[d,c,b],[n,d,b],[b,d,c],[b,n,d],[c,b,d],[d,b,n]][Math.floor(a/60)%6];return{r:a[0]*255,g:a[1]*255,b:a[2]*255}},rgb_to_hsv:function(a,c,d){var e=Math.min(a,c,d),b=Math.max(a,c,d),e=b-e;if(b==0)return{h:NaN,s:0,v:0}; + a=a==b?(c-d)/e:c==b?2+(d-a)/e:4+(a-c)/e;a/=6;a<0&&(a+=1);return{h:a*360,s:e/b,v:b/255}},rgb_to_hex:function(a,c,d){a=this.hex_with_component(0,2,a);a=this.hex_with_component(a,1,c);return a=this.hex_with_component(a,0,d)},component_from_hex:function(a,c){return a>>c*8&255},hex_with_component:function(a,c,d){return d<<(e=c*8)|a&~(255<<e)}}}(),dat.color.toString,dat.utils.common),dat.color.interpret,dat.utils.common),dat.utils.requestAnimationFrame=function(){return window.webkitRequestAnimationFrame|| + window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(e){window.setTimeout(e,1E3/60)}}(),dat.dom.CenteredDiv=function(e,a){var c=function(){this.backgroundElement=document.createElement("div");a.extend(this.backgroundElement.style,{backgroundColor:"rgba(0,0,0,0.8)",top:0,left:0,display:"none",zIndex:"1000",opacity:0,WebkitTransition:"opacity 0.2s linear"});e.makeFullscreen(this.backgroundElement);this.backgroundElement.style.position="fixed";this.domElement= + document.createElement("div");a.extend(this.domElement.style,{position:"fixed",display:"none",zIndex:"1001",opacity:0,WebkitTransition:"-webkit-transform 0.2s ease-out, opacity 0.2s linear"});document.body.appendChild(this.backgroundElement);document.body.appendChild(this.domElement);var c=this;e.bind(this.backgroundElement,"click",function(){c.hide()})};c.prototype.show=function(){var c=this;this.backgroundElement.style.display="block";this.domElement.style.display="block";this.domElement.style.opacity= + 0;this.domElement.style.webkitTransform="scale(1.1)";this.layout();a.defer(function(){c.backgroundElement.style.opacity=1;c.domElement.style.opacity=1;c.domElement.style.webkitTransform="scale(1)"})};c.prototype.hide=function(){var a=this,c=function(){a.domElement.style.display="none";a.backgroundElement.style.display="none";e.unbind(a.domElement,"webkitTransitionEnd",c);e.unbind(a.domElement,"transitionend",c);e.unbind(a.domElement,"oTransitionEnd",c)};e.bind(this.domElement,"webkitTransitionEnd", + c);e.bind(this.domElement,"transitionend",c);e.bind(this.domElement,"oTransitionEnd",c);this.backgroundElement.style.opacity=0;this.domElement.style.opacity=0;this.domElement.style.webkitTransform="scale(1.1)"};c.prototype.layout=function(){this.domElement.style.left=window.innerWidth/2-e.getWidth(this.domElement)/2+"px";this.domElement.style.top=window.innerHeight/2-e.getHeight(this.domElement)/2+"px"};return c}(dat.dom.dom,dat.utils.common),dat.dom.dom,dat.utils.common); \ No newline at end of file diff --git a/COGNET/lib/jquery-1.8.3.min.js b/COGNET/lib/jquery-1.8.3.min.js new file mode 100644 index 0000000000000000000000000000000000000000..38837795279c5eb281e98ce6017998b993026518 --- /dev/null +++ b/COGNET/lib/jquery-1.8.3.min.js @@ -0,0 +1,2 @@ +/*! jQuery v1.8.3 jquery.com | jquery.org/license */ +(function(e,t){function _(e){var t=M[e]={};return v.each(e.split(y),function(e,n){t[n]=!0}),t}function H(e,n,r){if(r===t&&e.nodeType===1){var i="data-"+n.replace(P,"-$1").toLowerCase();r=e.getAttribute(i);if(typeof r=="string"){try{r=r==="true"?!0:r==="false"?!1:r==="null"?null:+r+""===r?+r:D.test(r)?v.parseJSON(r):r}catch(s){}v.data(e,n,r)}else r=t}return r}function B(e){var t;for(t in e){if(t==="data"&&v.isEmptyObject(e[t]))continue;if(t!=="toJSON")return!1}return!0}function et(){return!1}function tt(){return!0}function ut(e){return!e||!e.parentNode||e.parentNode.nodeType===11}function at(e,t){do e=e[t];while(e&&e.nodeType!==1);return e}function ft(e,t,n){t=t||0;if(v.isFunction(t))return v.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return v.grep(e,function(e,r){return e===t===n});if(typeof t=="string"){var r=v.grep(e,function(e){return e.nodeType===1});if(it.test(t))return v.filter(t,r,!n);t=v.filter(t,r)}return v.grep(e,function(e,r){return v.inArray(e,t)>=0===n})}function lt(e){var t=ct.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function At(e,t){if(t.nodeType!==1||!v.hasData(e))return;var n,r,i,s=v._data(e),o=v._data(t,s),u=s.events;if(u){delete o.handle,o.events={};for(n in u)for(r=0,i=u[n].length;r<i;r++)v.event.add(t,n,u[n][r])}o.data&&(o.data=v.extend({},o.data))}function Ot(e,t){var n;if(t.nodeType!==1)return;t.clearAttributes&&t.clearAttributes(),t.mergeAttributes&&t.mergeAttributes(e),n=t.nodeName.toLowerCase(),n==="object"?(t.parentNode&&(t.outerHTML=e.outerHTML),v.support.html5Clone&&e.innerHTML&&!v.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):n==="input"&&Et.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):n==="option"?t.selected=e.defaultSelected:n==="input"||n==="textarea"?t.defaultValue=e.defaultValue:n==="script"&&t.text!==e.text&&(t.text=e.text),t.removeAttribute(v.expando)}function Mt(e){return typeof e.getElementsByTagName!="undefined"?e.getElementsByTagName("*"):typeof e.querySelectorAll!="undefined"?e.querySelectorAll("*"):[]}function _t(e){Et.test(e.type)&&(e.defaultChecked=e.checked)}function Qt(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=Jt.length;while(i--){t=Jt[i]+n;if(t in e)return t}return r}function Gt(e,t){return e=t||e,v.css(e,"display")==="none"||!v.contains(e.ownerDocument,e)}function Yt(e,t){var n,r,i=[],s=0,o=e.length;for(;s<o;s++){n=e[s];if(!n.style)continue;i[s]=v._data(n,"olddisplay"),t?(!i[s]&&n.style.display==="none"&&(n.style.display=""),n.style.display===""&&Gt(n)&&(i[s]=v._data(n,"olddisplay",nn(n.nodeName)))):(r=Dt(n,"display"),!i[s]&&r!=="none"&&v._data(n,"olddisplay",r))}for(s=0;s<o;s++){n=e[s];if(!n.style)continue;if(!t||n.style.display==="none"||n.style.display==="")n.style.display=t?i[s]||"":"none"}return e}function Zt(e,t,n){var r=Rt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function en(e,t,n,r){var i=n===(r?"border":"content")?4:t==="width"?1:0,s=0;for(;i<4;i+=2)n==="margin"&&(s+=v.css(e,n+$t[i],!0)),r?(n==="content"&&(s-=parseFloat(Dt(e,"padding"+$t[i]))||0),n!=="margin"&&(s-=parseFloat(Dt(e,"border"+$t[i]+"Width"))||0)):(s+=parseFloat(Dt(e,"padding"+$t[i]))||0,n!=="padding"&&(s+=parseFloat(Dt(e,"border"+$t[i]+"Width"))||0));return s}function tn(e,t,n){var r=t==="width"?e.offsetWidth:e.offsetHeight,i=!0,s=v.support.boxSizing&&v.css(e,"boxSizing")==="border-box";if(r<=0||r==null){r=Dt(e,t);if(r<0||r==null)r=e.style[t];if(Ut.test(r))return r;i=s&&(v.support.boxSizingReliable||r===e.style[t]),r=parseFloat(r)||0}return r+en(e,t,n||(s?"border":"content"),i)+"px"}function nn(e){if(Wt[e])return Wt[e];var t=v("<"+e+">").appendTo(i.body),n=t.css("display");t.remove();if(n==="none"||n===""){Pt=i.body.appendChild(Pt||v.extend(i.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!Ht||!Pt.createElement)Ht=(Pt.contentWindow||Pt.contentDocument).document,Ht.write("<!doctype html><html><body>"),Ht.close();t=Ht.body.appendChild(Ht.createElement(e)),n=Dt(t,"display"),i.body.removeChild(Pt)}return Wt[e]=n,n}function fn(e,t,n,r){var i;if(v.isArray(t))v.each(t,function(t,i){n||sn.test(e)?r(e,i):fn(e+"["+(typeof i=="object"?t:"")+"]",i,n,r)});else if(!n&&v.type(t)==="object")for(i in t)fn(e+"["+i+"]",t[i],n,r);else r(e,t)}function Cn(e){return function(t,n){typeof t!="string"&&(n=t,t="*");var r,i,s,o=t.toLowerCase().split(y),u=0,a=o.length;if(v.isFunction(n))for(;u<a;u++)r=o[u],s=/^\+/.test(r),s&&(r=r.substr(1)||"*"),i=e[r]=e[r]||[],i[s?"unshift":"push"](n)}}function kn(e,n,r,i,s,o){s=s||n.dataTypes[0],o=o||{},o[s]=!0;var u,a=e[s],f=0,l=a?a.length:0,c=e===Sn;for(;f<l&&(c||!u);f++)u=a[f](n,r,i),typeof u=="string"&&(!c||o[u]?u=t:(n.dataTypes.unshift(u),u=kn(e,n,r,i,u,o)));return(c||!u)&&!o["*"]&&(u=kn(e,n,r,i,"*",o)),u}function Ln(e,n){var r,i,s=v.ajaxSettings.flatOptions||{};for(r in n)n[r]!==t&&((s[r]?e:i||(i={}))[r]=n[r]);i&&v.extend(!0,e,i)}function An(e,n,r){var i,s,o,u,a=e.contents,f=e.dataTypes,l=e.responseFields;for(s in l)s in r&&(n[l[s]]=r[s]);while(f[0]==="*")f.shift(),i===t&&(i=e.mimeType||n.getResponseHeader("content-type"));if(i)for(s in a)if(a[s]&&a[s].test(i)){f.unshift(s);break}if(f[0]in r)o=f[0];else{for(s in r){if(!f[0]||e.converters[s+" "+f[0]]){o=s;break}u||(u=s)}o=o||u}if(o)return o!==f[0]&&f.unshift(o),r[o]}function On(e,t){var n,r,i,s,o=e.dataTypes.slice(),u=o[0],a={},f=0;e.dataFilter&&(t=e.dataFilter(t,e.dataType));if(o[1])for(n in e.converters)a[n.toLowerCase()]=e.converters[n];for(;i=o[++f];)if(i!=="*"){if(u!=="*"&&u!==i){n=a[u+" "+i]||a["* "+i];if(!n)for(r in a){s=r.split(" ");if(s[1]===i){n=a[u+" "+s[0]]||a["* "+s[0]];if(n){n===!0?n=a[r]:a[r]!==!0&&(i=s[0],o.splice(f--,0,i));break}}}if(n!==!0)if(n&&e["throws"])t=n(t);else try{t=n(t)}catch(l){return{state:"parsererror",error:n?l:"No conversion from "+u+" to "+i}}}u=i}return{state:"success",data:t}}function Fn(){try{return new e.XMLHttpRequest}catch(t){}}function In(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}function $n(){return setTimeout(function(){qn=t},0),qn=v.now()}function Jn(e,t){v.each(t,function(t,n){var r=(Vn[t]||[]).concat(Vn["*"]),i=0,s=r.length;for(;i<s;i++)if(r[i].call(e,t,n))return})}function Kn(e,t,n){var r,i=0,s=0,o=Xn.length,u=v.Deferred().always(function(){delete a.elem}),a=function(){var t=qn||$n(),n=Math.max(0,f.startTime+f.duration-t),r=n/f.duration||0,i=1-r,s=0,o=f.tweens.length;for(;s<o;s++)f.tweens[s].run(i);return u.notifyWith(e,[f,i,n]),i<1&&o?n:(u.resolveWith(e,[f]),!1)},f=u.promise({elem:e,props:v.extend({},t),opts:v.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:qn||$n(),duration:n.duration,tweens:[],createTween:function(t,n,r){var i=v.Tween(e,f.opts,t,n,f.opts.specialEasing[t]||f.opts.easing);return f.tweens.push(i),i},stop:function(t){var n=0,r=t?f.tweens.length:0;for(;n<r;n++)f.tweens[n].run(1);return t?u.resolveWith(e,[f,t]):u.rejectWith(e,[f,t]),this}}),l=f.props;Qn(l,f.opts.specialEasing);for(;i<o;i++){r=Xn[i].call(f,e,l,f.opts);if(r)return r}return Jn(f,l),v.isFunction(f.opts.start)&&f.opts.start.call(e,f),v.fx.timer(v.extend(a,{anim:f,queue:f.opts.queue,elem:e})),f.progress(f.opts.progress).done(f.opts.done,f.opts.complete).fail(f.opts.fail).always(f.opts.always)}function Qn(e,t){var n,r,i,s,o;for(n in e){r=v.camelCase(n),i=t[r],s=e[n],v.isArray(s)&&(i=s[1],s=e[n]=s[0]),n!==r&&(e[r]=s,delete e[n]),o=v.cssHooks[r];if(o&&"expand"in o){s=o.expand(s),delete e[r];for(n in s)n in e||(e[n]=s[n],t[n]=i)}else t[r]=i}}function Gn(e,t,n){var r,i,s,o,u,a,f,l,c,h=this,p=e.style,d={},m=[],g=e.nodeType&&Gt(e);n.queue||(l=v._queueHooks(e,"fx"),l.unqueued==null&&(l.unqueued=0,c=l.empty.fire,l.empty.fire=function(){l.unqueued||c()}),l.unqueued++,h.always(function(){h.always(function(){l.unqueued--,v.queue(e,"fx").length||l.empty.fire()})})),e.nodeType===1&&("height"in t||"width"in t)&&(n.overflow=[p.overflow,p.overflowX,p.overflowY],v.css(e,"display")==="inline"&&v.css(e,"float")==="none"&&(!v.support.inlineBlockNeedsLayout||nn(e.nodeName)==="inline"?p.display="inline-block":p.zoom=1)),n.overflow&&(p.overflow="hidden",v.support.shrinkWrapBlocks||h.done(function(){p.overflow=n.overflow[0],p.overflowX=n.overflow[1],p.overflowY=n.overflow[2]}));for(r in t){s=t[r];if(Un.exec(s)){delete t[r],a=a||s==="toggle";if(s===(g?"hide":"show"))continue;m.push(r)}}o=m.length;if(o){u=v._data(e,"fxshow")||v._data(e,"fxshow",{}),"hidden"in u&&(g=u.hidden),a&&(u.hidden=!g),g?v(e).show():h.done(function(){v(e).hide()}),h.done(function(){var t;v.removeData(e,"fxshow",!0);for(t in d)v.style(e,t,d[t])});for(r=0;r<o;r++)i=m[r],f=h.createTween(i,g?u[i]:0),d[i]=u[i]||v.style(e,i),i in u||(u[i]=f.start,g&&(f.end=f.start,f.start=i==="width"||i==="height"?1:0))}}function Yn(e,t,n,r,i){return new Yn.prototype.init(e,t,n,r,i)}function Zn(e,t){var n,r={height:e},i=0;t=t?1:0;for(;i<4;i+=2-t)n=$t[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}function tr(e){return v.isWindow(e)?e:e.nodeType===9?e.defaultView||e.parentWindow:!1}var n,r,i=e.document,s=e.location,o=e.navigator,u=e.jQuery,a=e.$,f=Array.prototype.push,l=Array.prototype.slice,c=Array.prototype.indexOf,h=Object.prototype.toString,p=Object.prototype.hasOwnProperty,d=String.prototype.trim,v=function(e,t){return new v.fn.init(e,t,n)},m=/[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,g=/\S/,y=/\s+/,b=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,w=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,E=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,S=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,T=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,N=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,C=/^-ms-/,k=/-([\da-z])/gi,L=function(e,t){return(t+"").toUpperCase()},A=function(){i.addEventListener?(i.removeEventListener("DOMContentLoaded",A,!1),v.ready()):i.readyState==="complete"&&(i.detachEvent("onreadystatechange",A),v.ready())},O={};v.fn=v.prototype={constructor:v,init:function(e,n,r){var s,o,u,a;if(!e)return this;if(e.nodeType)return this.context=this[0]=e,this.length=1,this;if(typeof e=="string"){e.charAt(0)==="<"&&e.charAt(e.length-1)===">"&&e.length>=3?s=[null,e,null]:s=w.exec(e);if(s&&(s[1]||!n)){if(s[1])return n=n instanceof v?n[0]:n,a=n&&n.nodeType?n.ownerDocument||n:i,e=v.parseHTML(s[1],a,!0),E.test(s[1])&&v.isPlainObject(n)&&this.attr.call(e,n,!0),v.merge(this,e);o=i.getElementById(s[2]);if(o&&o.parentNode){if(o.id!==s[2])return r.find(e);this.length=1,this[0]=o}return this.context=i,this.selector=e,this}return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e)}return v.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),v.makeArray(e,this))},selector:"",jquery:"1.8.3",length:0,size:function(){return this.length},toArray:function(){return l.call(this)},get:function(e){return e==null?this.toArray():e<0?this[this.length+e]:this[e]},pushStack:function(e,t,n){var r=v.merge(this.constructor(),e);return r.prevObject=this,r.context=this.context,t==="find"?r.selector=this.selector+(this.selector?" ":"")+n:t&&(r.selector=this.selector+"."+t+"("+n+")"),r},each:function(e,t){return v.each(this,e,t)},ready:function(e){return v.ready.promise().done(e),this},eq:function(e){return e=+e,e===-1?this.slice(e):this.slice(e,e+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(l.apply(this,arguments),"slice",l.call(arguments).join(","))},map:function(e){return this.pushStack(v.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:[].sort,splice:[].splice},v.fn.init.prototype=v.fn,v.extend=v.fn.extend=function(){var e,n,r,i,s,o,u=arguments[0]||{},a=1,f=arguments.length,l=!1;typeof u=="boolean"&&(l=u,u=arguments[1]||{},a=2),typeof u!="object"&&!v.isFunction(u)&&(u={}),f===a&&(u=this,--a);for(;a<f;a++)if((e=arguments[a])!=null)for(n in e){r=u[n],i=e[n];if(u===i)continue;l&&i&&(v.isPlainObject(i)||(s=v.isArray(i)))?(s?(s=!1,o=r&&v.isArray(r)?r:[]):o=r&&v.isPlainObject(r)?r:{},u[n]=v.extend(l,o,i)):i!==t&&(u[n]=i)}return u},v.extend({noConflict:function(t){return e.$===v&&(e.$=a),t&&e.jQuery===v&&(e.jQuery=u),v},isReady:!1,readyWait:1,holdReady:function(e){e?v.readyWait++:v.ready(!0)},ready:function(e){if(e===!0?--v.readyWait:v.isReady)return;if(!i.body)return setTimeout(v.ready,1);v.isReady=!0;if(e!==!0&&--v.readyWait>0)return;r.resolveWith(i,[v]),v.fn.trigger&&v(i).trigger("ready").off("ready")},isFunction:function(e){return v.type(e)==="function"},isArray:Array.isArray||function(e){return v.type(e)==="array"},isWindow:function(e){return e!=null&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return e==null?String(e):O[h.call(e)]||"object"},isPlainObject:function(e){if(!e||v.type(e)!=="object"||e.nodeType||v.isWindow(e))return!1;try{if(e.constructor&&!p.call(e,"constructor")&&!p.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||p.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw new Error(e)},parseHTML:function(e,t,n){var r;return!e||typeof e!="string"?null:(typeof t=="boolean"&&(n=t,t=0),t=t||i,(r=E.exec(e))?[t.createElement(r[1])]:(r=v.buildFragment([e],t,n?null:[]),v.merge([],(r.cacheable?v.clone(r.fragment):r.fragment).childNodes)))},parseJSON:function(t){if(!t||typeof t!="string")return null;t=v.trim(t);if(e.JSON&&e.JSON.parse)return e.JSON.parse(t);if(S.test(t.replace(T,"@").replace(N,"]").replace(x,"")))return(new Function("return "+t))();v.error("Invalid JSON: "+t)},parseXML:function(n){var r,i;if(!n||typeof n!="string")return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(s){r=t}return(!r||!r.documentElement||r.getElementsByTagName("parsererror").length)&&v.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&g.test(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(C,"ms-").replace(k,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,n,r){var i,s=0,o=e.length,u=o===t||v.isFunction(e);if(r){if(u){for(i in e)if(n.apply(e[i],r)===!1)break}else for(;s<o;)if(n.apply(e[s++],r)===!1)break}else if(u){for(i in e)if(n.call(e[i],i,e[i])===!1)break}else for(;s<o;)if(n.call(e[s],s,e[s++])===!1)break;return e},trim:d&&!d.call("\ufeff\u00a0")?function(e){return e==null?"":d.call(e)}:function(e){return e==null?"":(e+"").replace(b,"")},makeArray:function(e,t){var n,r=t||[];return e!=null&&(n=v.type(e),e.length==null||n==="string"||n==="function"||n==="regexp"||v.isWindow(e)?f.call(r,e):v.merge(r,e)),r},inArray:function(e,t,n){var r;if(t){if(c)return c.call(t,e,n);r=t.length,n=n?n<0?Math.max(0,r+n):n:0;for(;n<r;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,s=0;if(typeof r=="number")for(;s<r;s++)e[i++]=n[s];else while(n[s]!==t)e[i++]=n[s++];return e.length=i,e},grep:function(e,t,n){var r,i=[],s=0,o=e.length;n=!!n;for(;s<o;s++)r=!!t(e[s],s),n!==r&&i.push(e[s]);return i},map:function(e,n,r){var i,s,o=[],u=0,a=e.length,f=e instanceof v||a!==t&&typeof a=="number"&&(a>0&&e[0]&&e[a-1]||a===0||v.isArray(e));if(f)for(;u<a;u++)i=n(e[u],u,r),i!=null&&(o[o.length]=i);else for(s in e)i=n(e[s],s,r),i!=null&&(o[o.length]=i);return o.concat.apply([],o)},guid:1,proxy:function(e,n){var r,i,s;return typeof n=="string"&&(r=e[n],n=e,e=r),v.isFunction(e)?(i=l.call(arguments,2),s=function(){return e.apply(n,i.concat(l.call(arguments)))},s.guid=e.guid=e.guid||v.guid++,s):t},access:function(e,n,r,i,s,o,u){var a,f=r==null,l=0,c=e.length;if(r&&typeof r=="object"){for(l in r)v.access(e,n,l,r[l],1,o,i);s=1}else if(i!==t){a=u===t&&v.isFunction(i),f&&(a?(a=n,n=function(e,t,n){return a.call(v(e),n)}):(n.call(e,i),n=null));if(n)for(;l<c;l++)n(e[l],r,a?i.call(e[l],l,n(e[l],r)):i,u);s=1}return s?e:f?n.call(e):c?n(e[0],r):o},now:function(){return(new Date).getTime()}}),v.ready.promise=function(t){if(!r){r=v.Deferred();if(i.readyState==="complete")setTimeout(v.ready,1);else if(i.addEventListener)i.addEventListener("DOMContentLoaded",A,!1),e.addEventListener("load",v.ready,!1);else{i.attachEvent("onreadystatechange",A),e.attachEvent("onload",v.ready);var n=!1;try{n=e.frameElement==null&&i.documentElement}catch(s){}n&&n.doScroll&&function o(){if(!v.isReady){try{n.doScroll("left")}catch(e){return setTimeout(o,50)}v.ready()}}()}}return r.promise(t)},v.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(e,t){O["[object "+t+"]"]=t.toLowerCase()}),n=v(i);var M={};v.Callbacks=function(e){e=typeof e=="string"?M[e]||_(e):v.extend({},e);var n,r,i,s,o,u,a=[],f=!e.once&&[],l=function(t){n=e.memory&&t,r=!0,u=s||0,s=0,o=a.length,i=!0;for(;a&&u<o;u++)if(a[u].apply(t[0],t[1])===!1&&e.stopOnFalse){n=!1;break}i=!1,a&&(f?f.length&&l(f.shift()):n?a=[]:c.disable())},c={add:function(){if(a){var t=a.length;(function r(t){v.each(t,function(t,n){var i=v.type(n);i==="function"?(!e.unique||!c.has(n))&&a.push(n):n&&n.length&&i!=="string"&&r(n)})})(arguments),i?o=a.length:n&&(s=t,l(n))}return this},remove:function(){return a&&v.each(arguments,function(e,t){var n;while((n=v.inArray(t,a,n))>-1)a.splice(n,1),i&&(n<=o&&o--,n<=u&&u--)}),this},has:function(e){return v.inArray(e,a)>-1},empty:function(){return a=[],this},disable:function(){return a=f=n=t,this},disabled:function(){return!a},lock:function(){return f=t,n||c.disable(),this},locked:function(){return!f},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],a&&(!r||f)&&(i?f.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},v.extend({Deferred:function(e){var t=[["resolve","done",v.Callbacks("once memory"),"resolved"],["reject","fail",v.Callbacks("once memory"),"rejected"],["notify","progress",v.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return v.Deferred(function(n){v.each(t,function(t,r){var s=r[0],o=e[t];i[r[1]](v.isFunction(o)?function(){var e=o.apply(this,arguments);e&&v.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===i?n:this,[e])}:n[s])}),e=null}).promise()},promise:function(e){return e!=null?v.extend(e,r):r}},i={};return r.pipe=r.then,v.each(t,function(e,s){var o=s[2],u=s[3];r[s[1]]=o.add,u&&o.add(function(){n=u},t[e^1][2].disable,t[2][2].lock),i[s[0]]=o.fire,i[s[0]+"With"]=o.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=l.call(arguments),r=n.length,i=r!==1||e&&v.isFunction(e.promise)?r:0,s=i===1?e:v.Deferred(),o=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?l.call(arguments):r,n===u?s.notifyWith(t,n):--i||s.resolveWith(t,n)}},u,a,f;if(r>1){u=new Array(r),a=new Array(r),f=new Array(r);for(;t<r;t++)n[t]&&v.isFunction(n[t].promise)?n[t].promise().done(o(t,f,n)).fail(s.reject).progress(o(t,a,u)):--i}return i||s.resolveWith(f,n),s.promise()}}),v.support=function(){var t,n,r,s,o,u,a,f,l,c,h,p=i.createElement("div");p.setAttribute("className","t"),p.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",n=p.getElementsByTagName("*"),r=p.getElementsByTagName("a")[0];if(!n||!r||!n.length)return{};s=i.createElement("select"),o=s.appendChild(i.createElement("option")),u=p.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:r.getAttribute("href")==="/a",opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:u.value==="on",optSelected:o.selected,getSetAttribute:p.className!=="t",enctype:!!i.createElement("form").enctype,html5Clone:i.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",boxModel:i.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},u.checked=!0,t.noCloneChecked=u.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!o.disabled;try{delete p.test}catch(d){t.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",h=function(){t.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick"),p.detachEvent("onclick",h)),u=i.createElement("input"),u.value="t",u.setAttribute("type","radio"),t.radioValue=u.value==="t",u.setAttribute("checked","checked"),u.setAttribute("name","t"),p.appendChild(u),a=i.createDocumentFragment(),a.appendChild(p.lastChild),t.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,t.appendChecked=u.checked,a.removeChild(u),a.appendChild(p);if(p.attachEvent)for(l in{submit:!0,change:!0,focusin:!0})f="on"+l,c=f in p,c||(p.setAttribute(f,"return;"),c=typeof p[f]=="function"),t[l+"Bubbles"]=c;return v(function(){var n,r,s,o,u="padding:0;margin:0;border:0;display:block;overflow:hidden;",a=i.getElementsByTagName("body")[0];if(!a)return;n=i.createElement("div"),n.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",a.insertBefore(n,a.firstChild),r=i.createElement("div"),n.appendChild(r),r.innerHTML="<table><tr><td></td><td>t</td></tr></table>",s=r.getElementsByTagName("td"),s[0].style.cssText="padding:0;margin:0;border:0;display:none",c=s[0].offsetHeight===0,s[0].style.display="",s[1].style.display="none",t.reliableHiddenOffsets=c&&s[0].offsetHeight===0,r.innerHTML="",r.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=r.offsetWidth===4,t.doesNotIncludeMarginInBodyOffset=a.offsetTop!==1,e.getComputedStyle&&(t.pixelPosition=(e.getComputedStyle(r,null)||{}).top!=="1%",t.boxSizingReliable=(e.getComputedStyle(r,null)||{width:"4px"}).width==="4px",o=i.createElement("div"),o.style.cssText=r.style.cssText=u,o.style.marginRight=o.style.width="0",r.style.width="1px",r.appendChild(o),t.reliableMarginRight=!parseFloat((e.getComputedStyle(o,null)||{}).marginRight)),typeof r.style.zoom!="undefined"&&(r.innerHTML="",r.style.cssText=u+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=r.offsetWidth===3,r.style.display="block",r.style.overflow="visible",r.innerHTML="<div></div>",r.firstChild.style.width="5px",t.shrinkWrapBlocks=r.offsetWidth!==3,n.style.zoom=1),a.removeChild(n),n=r=s=o=null}),a.removeChild(p),n=r=s=o=u=a=p=null,t}();var D=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;v.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(v.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?v.cache[e[v.expando]]:e[v.expando],!!e&&!B(e)},data:function(e,n,r,i){if(!v.acceptData(e))return;var s,o,u=v.expando,a=typeof n=="string",f=e.nodeType,l=f?v.cache:e,c=f?e[u]:e[u]&&u;if((!c||!l[c]||!i&&!l[c].data)&&a&&r===t)return;c||(f?e[u]=c=v.deletedIds.pop()||v.guid++:c=u),l[c]||(l[c]={},f||(l[c].toJSON=v.noop));if(typeof n=="object"||typeof n=="function")i?l[c]=v.extend(l[c],n):l[c].data=v.extend(l[c].data,n);return s=l[c],i||(s.data||(s.data={}),s=s.data),r!==t&&(s[v.camelCase(n)]=r),a?(o=s[n],o==null&&(o=s[v.camelCase(n)])):o=s,o},removeData:function(e,t,n){if(!v.acceptData(e))return;var r,i,s,o=e.nodeType,u=o?v.cache:e,a=o?e[v.expando]:v.expando;if(!u[a])return;if(t){r=n?u[a]:u[a].data;if(r){v.isArray(t)||(t in r?t=[t]:(t=v.camelCase(t),t in r?t=[t]:t=t.split(" ")));for(i=0,s=t.length;i<s;i++)delete r[t[i]];if(!(n?B:v.isEmptyObject)(r))return}}if(!n){delete u[a].data;if(!B(u[a]))return}o?v.cleanData([e],!0):v.support.deleteExpando||u!=u.window?delete u[a]:u[a]=null},_data:function(e,t,n){return v.data(e,t,n,!0)},acceptData:function(e){var t=e.nodeName&&v.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),v.fn.extend({data:function(e,n){var r,i,s,o,u,a=this[0],f=0,l=null;if(e===t){if(this.length){l=v.data(a);if(a.nodeType===1&&!v._data(a,"parsedAttrs")){s=a.attributes;for(u=s.length;f<u;f++)o=s[f].name,o.indexOf("data-")||(o=v.camelCase(o.substring(5)),H(a,o,l[o]));v._data(a,"parsedAttrs",!0)}}return l}return typeof e=="object"?this.each(function(){v.data(this,e)}):(r=e.split(".",2),r[1]=r[1]?"."+r[1]:"",i=r[1]+"!",v.access(this,function(n){if(n===t)return l=this.triggerHandler("getData"+i,[r[0]]),l===t&&a&&(l=v.data(a,e),l=H(a,e,l)),l===t&&r[1]?this.data(r[0]):l;r[1]=n,this.each(function(){var t=v(this);t.triggerHandler("setData"+i,r),v.data(this,e,n),t.triggerHandler("changeData"+i,r)})},null,n,arguments.length>1,null,!1))},removeData:function(e){return this.each(function(){v.removeData(this,e)})}}),v.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=v._data(e,t),n&&(!r||v.isArray(n)?r=v._data(e,t,v.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=v.queue(e,t),r=n.length,i=n.shift(),s=v._queueHooks(e,t),o=function(){v.dequeue(e,t)};i==="inprogress"&&(i=n.shift(),r--),i&&(t==="fx"&&n.unshift("inprogress"),delete s.stop,i.call(e,o,s)),!r&&s&&s.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return v._data(e,n)||v._data(e,n,{empty:v.Callbacks("once memory").add(function(){v.removeData(e,t+"queue",!0),v.removeData(e,n,!0)})})}}),v.fn.extend({queue:function(e,n){var r=2;return typeof e!="string"&&(n=e,e="fx",r--),arguments.length<r?v.queue(this[0],e):n===t?this:this.each(function(){var t=v.queue(this,e,n);v._queueHooks(this,e),e==="fx"&&t[0]!=="inprogress"&&v.dequeue(this,e)})},dequeue:function(e){return this.each(function(){v.dequeue(this,e)})},delay:function(e,t){return e=v.fx?v.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,s=v.Deferred(),o=this,u=this.length,a=function(){--i||s.resolveWith(o,[o])};typeof e!="string"&&(n=e,e=t),e=e||"fx";while(u--)r=v._data(o[u],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(a));return a(),s.promise(n)}});var j,F,I,q=/[\t\r\n]/g,R=/\r/g,U=/^(?:button|input)$/i,z=/^(?:button|input|object|select|textarea)$/i,W=/^a(?:rea|)$/i,X=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,V=v.support.getSetAttribute;v.fn.extend({attr:function(e,t){return v.access(this,v.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){v.removeAttr(this,e)})},prop:function(e,t){return v.access(this,v.prop,e,t,arguments.length>1)},removeProp:function(e){return e=v.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,s,o,u;if(v.isFunction(e))return this.each(function(t){v(this).addClass(e.call(this,t,this.className))});if(e&&typeof e=="string"){t=e.split(y);for(n=0,r=this.length;n<r;n++){i=this[n];if(i.nodeType===1)if(!i.className&&t.length===1)i.className=e;else{s=" "+i.className+" ";for(o=0,u=t.length;o<u;o++)s.indexOf(" "+t[o]+" ")<0&&(s+=t[o]+" ");i.className=v.trim(s)}}}return this},removeClass:function(e){var n,r,i,s,o,u,a;if(v.isFunction(e))return this.each(function(t){v(this).removeClass(e.call(this,t,this.className))});if(e&&typeof e=="string"||e===t){n=(e||"").split(y);for(u=0,a=this.length;u<a;u++){i=this[u];if(i.nodeType===1&&i.className){r=(" "+i.className+" ").replace(q," ");for(s=0,o=n.length;s<o;s++)while(r.indexOf(" "+n[s]+" ")>=0)r=r.replace(" "+n[s]+" "," ");i.className=e?v.trim(r):""}}}return this},toggleClass:function(e,t){var n=typeof e,r=typeof t=="boolean";return v.isFunction(e)?this.each(function(n){v(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if(n==="string"){var i,s=0,o=v(this),u=t,a=e.split(y);while(i=a[s++])u=r?u:!o.hasClass(i),o[u?"addClass":"removeClass"](i)}else if(n==="undefined"||n==="boolean")this.className&&v._data(this,"__className__",this.className),this.className=this.className||e===!1?"":v._data(this,"__className__")||""})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;n<r;n++)if(this[n].nodeType===1&&(" "+this[n].className+" ").replace(q," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,s=this[0];if(!arguments.length){if(s)return n=v.valHooks[s.type]||v.valHooks[s.nodeName.toLowerCase()],n&&"get"in n&&(r=n.get(s,"value"))!==t?r:(r=s.value,typeof r=="string"?r.replace(R,""):r==null?"":r);return}return i=v.isFunction(e),this.each(function(r){var s,o=v(this);if(this.nodeType!==1)return;i?s=e.call(this,r,o.val()):s=e,s==null?s="":typeof s=="number"?s+="":v.isArray(s)&&(s=v.map(s,function(e){return e==null?"":e+""})),n=v.valHooks[this.type]||v.valHooks[this.nodeName.toLowerCase()];if(!n||!("set"in n)||n.set(this,s,"value")===t)this.value=s})}}),v.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,s=e.type==="select-one"||i<0,o=s?null:[],u=s?i+1:r.length,a=i<0?u:s?i:0;for(;a<u;a++){n=r[a];if((n.selected||a===i)&&(v.support.optDisabled?!n.disabled:n.getAttribute("disabled")===null)&&(!n.parentNode.disabled||!v.nodeName(n.parentNode,"optgroup"))){t=v(n).val();if(s)return t;o.push(t)}}return o},set:function(e,t){var n=v.makeArray(t);return v(e).find("option").each(function(){this.selected=v.inArray(v(this).val(),n)>=0}),n.length||(e.selectedIndex=-1),n}}},attrFn:{},attr:function(e,n,r,i){var s,o,u,a=e.nodeType;if(!e||a===3||a===8||a===2)return;if(i&&v.isFunction(v.fn[n]))return v(e)[n](r);if(typeof e.getAttribute=="undefined")return v.prop(e,n,r);u=a!==1||!v.isXMLDoc(e),u&&(n=n.toLowerCase(),o=v.attrHooks[n]||(X.test(n)?F:j));if(r!==t){if(r===null){v.removeAttr(e,n);return}return o&&"set"in o&&u&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r)}return o&&"get"in o&&u&&(s=o.get(e,n))!==null?s:(s=e.getAttribute(n),s===null?t:s)},removeAttr:function(e,t){var n,r,i,s,o=0;if(t&&e.nodeType===1){r=t.split(y);for(;o<r.length;o++)i=r[o],i&&(n=v.propFix[i]||i,s=X.test(i),s||v.attr(e,i,""),e.removeAttribute(V?i:n),s&&n in e&&(e[n]=!1))}},attrHooks:{type:{set:function(e,t){if(U.test(e.nodeName)&&e.parentNode)v.error("type property can't be changed");else if(!v.support.radioValue&&t==="radio"&&v.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}},value:{get:function(e,t){return j&&v.nodeName(e,"button")?j.get(e,t):t in e?e.value:null},set:function(e,t,n){if(j&&v.nodeName(e,"button"))return j.set(e,t,n);e.value=t}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(e,n,r){var i,s,o,u=e.nodeType;if(!e||u===3||u===8||u===2)return;return o=u!==1||!v.isXMLDoc(e),o&&(n=v.propFix[n]||n,s=v.propHooks[n]),r!==t?s&&"set"in s&&(i=s.set(e,r,n))!==t?i:e[n]=r:s&&"get"in s&&(i=s.get(e,n))!==null?i:e[n]},propHooks:{tabIndex:{get:function(e){var n=e.getAttributeNode("tabindex");return n&&n.specified?parseInt(n.value,10):z.test(e.nodeName)||W.test(e.nodeName)&&e.href?0:t}}}}),F={get:function(e,n){var r,i=v.prop(e,n);return i===!0||typeof i!="boolean"&&(r=e.getAttributeNode(n))&&r.nodeValue!==!1?n.toLowerCase():t},set:function(e,t,n){var r;return t===!1?v.removeAttr(e,n):(r=v.propFix[n]||n,r in e&&(e[r]=!0),e.setAttribute(n,n.toLowerCase())),n}},V||(I={name:!0,id:!0,coords:!0},j=v.valHooks.button={get:function(e,n){var r;return r=e.getAttributeNode(n),r&&(I[n]?r.value!=="":r.specified)?r.value:t},set:function(e,t,n){var r=e.getAttributeNode(n);return r||(r=i.createAttribute(n),e.setAttributeNode(r)),r.value=t+""}},v.each(["width","height"],function(e,t){v.attrHooks[t]=v.extend(v.attrHooks[t],{set:function(e,n){if(n==="")return e.setAttribute(t,"auto"),n}})}),v.attrHooks.contenteditable={get:j.get,set:function(e,t,n){t===""&&(t="false"),j.set(e,t,n)}}),v.support.hrefNormalized||v.each(["href","src","width","height"],function(e,n){v.attrHooks[n]=v.extend(v.attrHooks[n],{get:function(e){var r=e.getAttribute(n,2);return r===null?t:r}})}),v.support.style||(v.attrHooks.style={get:function(e){return e.style.cssText.toLowerCase()||t},set:function(e,t){return e.style.cssText=t+""}}),v.support.optSelected||(v.propHooks.selected=v.extend(v.propHooks.selected,{get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}})),v.support.enctype||(v.propFix.enctype="encoding"),v.support.checkOn||v.each(["radio","checkbox"],function(){v.valHooks[this]={get:function(e){return e.getAttribute("value")===null?"on":e.value}}}),v.each(["radio","checkbox"],function(){v.valHooks[this]=v.extend(v.valHooks[this],{set:function(e,t){if(v.isArray(t))return e.checked=v.inArray(v(e).val(),t)>=0}})});var $=/^(?:textarea|input|select)$/i,J=/^([^\.]*|)(?:\.(.+)|)$/,K=/(?:^|\s)hover(\.\S+|)\b/,Q=/^key/,G=/^(?:mouse|contextmenu)|click/,Y=/^(?:focusinfocus|focusoutblur)$/,Z=function(e){return v.event.special.hover?e:e.replace(K,"mouseenter$1 mouseleave$1")};v.event={add:function(e,n,r,i,s){var o,u,a,f,l,c,h,p,d,m,g;if(e.nodeType===3||e.nodeType===8||!n||!r||!(o=v._data(e)))return;r.handler&&(d=r,r=d.handler,s=d.selector),r.guid||(r.guid=v.guid++),a=o.events,a||(o.events=a={}),u=o.handle,u||(o.handle=u=function(e){return typeof v=="undefined"||!!e&&v.event.triggered===e.type?t:v.event.dispatch.apply(u.elem,arguments)},u.elem=e),n=v.trim(Z(n)).split(" ");for(f=0;f<n.length;f++){l=J.exec(n[f])||[],c=l[1],h=(l[2]||"").split(".").sort(),g=v.event.special[c]||{},c=(s?g.delegateType:g.bindType)||c,g=v.event.special[c]||{},p=v.extend({type:c,origType:l[1],data:i,handler:r,guid:r.guid,selector:s,needsContext:s&&v.expr.match.needsContext.test(s),namespace:h.join(".")},d),m=a[c];if(!m){m=a[c]=[],m.delegateCount=0;if(!g.setup||g.setup.call(e,i,h,u)===!1)e.addEventListener?e.addEventListener(c,u,!1):e.attachEvent&&e.attachEvent("on"+c,u)}g.add&&(g.add.call(e,p),p.handler.guid||(p.handler.guid=r.guid)),s?m.splice(m.delegateCount++,0,p):m.push(p),v.event.global[c]=!0}e=null},global:{},remove:function(e,t,n,r,i){var s,o,u,a,f,l,c,h,p,d,m,g=v.hasData(e)&&v._data(e);if(!g||!(h=g.events))return;t=v.trim(Z(t||"")).split(" ");for(s=0;s<t.length;s++){o=J.exec(t[s])||[],u=a=o[1],f=o[2];if(!u){for(u in h)v.event.remove(e,u+t[s],n,r,!0);continue}p=v.event.special[u]||{},u=(r?p.delegateType:p.bindType)||u,d=h[u]||[],l=d.length,f=f?new RegExp("(^|\\.)"+f.split(".").sort().join("\\.(?:.*\\.|)")+"(\\.|$)"):null;for(c=0;c<d.length;c++)m=d[c],(i||a===m.origType)&&(!n||n.guid===m.guid)&&(!f||f.test(m.namespace))&&(!r||r===m.selector||r==="**"&&m.selector)&&(d.splice(c--,1),m.selector&&d.delegateCount--,p.remove&&p.remove.call(e,m));d.length===0&&l!==d.length&&((!p.teardown||p.teardown.call(e,f,g.handle)===!1)&&v.removeEvent(e,u,g.handle),delete h[u])}v.isEmptyObject(h)&&(delete g.handle,v.removeData(e,"events",!0))},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(n,r,s,o){if(!s||s.nodeType!==3&&s.nodeType!==8){var u,a,f,l,c,h,p,d,m,g,y=n.type||n,b=[];if(Y.test(y+v.event.triggered))return;y.indexOf("!")>=0&&(y=y.slice(0,-1),a=!0),y.indexOf(".")>=0&&(b=y.split("."),y=b.shift(),b.sort());if((!s||v.event.customEvent[y])&&!v.event.global[y])return;n=typeof n=="object"?n[v.expando]?n:new v.Event(y,n):new v.Event(y),n.type=y,n.isTrigger=!0,n.exclusive=a,n.namespace=b.join("."),n.namespace_re=n.namespace?new RegExp("(^|\\.)"+b.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,h=y.indexOf(":")<0?"on"+y:"";if(!s){u=v.cache;for(f in u)u[f].events&&u[f].events[y]&&v.event.trigger(n,r,u[f].handle.elem,!0);return}n.result=t,n.target||(n.target=s),r=r!=null?v.makeArray(r):[],r.unshift(n),p=v.event.special[y]||{};if(p.trigger&&p.trigger.apply(s,r)===!1)return;m=[[s,p.bindType||y]];if(!o&&!p.noBubble&&!v.isWindow(s)){g=p.delegateType||y,l=Y.test(g+y)?s:s.parentNode;for(c=s;l;l=l.parentNode)m.push([l,g]),c=l;c===(s.ownerDocument||i)&&m.push([c.defaultView||c.parentWindow||e,g])}for(f=0;f<m.length&&!n.isPropagationStopped();f++)l=m[f][0],n.type=m[f][1],d=(v._data(l,"events")||{})[n.type]&&v._data(l,"handle"),d&&d.apply(l,r),d=h&&l[h],d&&v.acceptData(l)&&d.apply&&d.apply(l,r)===!1&&n.preventDefault();return n.type=y,!o&&!n.isDefaultPrevented()&&(!p._default||p._default.apply(s.ownerDocument,r)===!1)&&(y!=="click"||!v.nodeName(s,"a"))&&v.acceptData(s)&&h&&s[y]&&(y!=="focus"&&y!=="blur"||n.target.offsetWidth!==0)&&!v.isWindow(s)&&(c=s[h],c&&(s[h]=null),v.event.triggered=y,s[y](),v.event.triggered=t,c&&(s[h]=c)),n.result}return},dispatch:function(n){n=v.event.fix(n||e.event);var r,i,s,o,u,a,f,c,h,p,d=(v._data(this,"events")||{})[n.type]||[],m=d.delegateCount,g=l.call(arguments),y=!n.exclusive&&!n.namespace,b=v.event.special[n.type]||{},w=[];g[0]=n,n.delegateTarget=this;if(b.preDispatch&&b.preDispatch.call(this,n)===!1)return;if(m&&(!n.button||n.type!=="click"))for(s=n.target;s!=this;s=s.parentNode||this)if(s.disabled!==!0||n.type!=="click"){u={},f=[];for(r=0;r<m;r++)c=d[r],h=c.selector,u[h]===t&&(u[h]=c.needsContext?v(h,this).index(s)>=0:v.find(h,this,null,[s]).length),u[h]&&f.push(c);f.length&&w.push({elem:s,matches:f})}d.length>m&&w.push({elem:this,matches:d.slice(m)});for(r=0;r<w.length&&!n.isPropagationStopped();r++){a=w[r],n.currentTarget=a.elem;for(i=0;i<a.matches.length&&!n.isImmediatePropagationStopped();i++){c=a.matches[i];if(y||!n.namespace&&!c.namespace||n.namespace_re&&n.namespace_re.test(c.namespace))n.data=c.data,n.handleObj=c,o=((v.event.special[c.origType]||{}).handle||c.handler).apply(a.elem,g),o!==t&&(n.result=o,o===!1&&(n.preventDefault(),n.stopPropagation()))}}return b.postDispatch&&b.postDispatch.call(this,n),n.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return e.which==null&&(e.which=t.charCode!=null?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,s,o,u=n.button,a=n.fromElement;return e.pageX==null&&n.clientX!=null&&(r=e.target.ownerDocument||i,s=r.documentElement,o=r.body,e.pageX=n.clientX+(s&&s.scrollLeft||o&&o.scrollLeft||0)-(s&&s.clientLeft||o&&o.clientLeft||0),e.pageY=n.clientY+(s&&s.scrollTop||o&&o.scrollTop||0)-(s&&s.clientTop||o&&o.clientTop||0)),!e.relatedTarget&&a&&(e.relatedTarget=a===e.target?n.toElement:a),!e.which&&u!==t&&(e.which=u&1?1:u&2?3:u&4?2:0),e}},fix:function(e){if(e[v.expando])return e;var t,n,r=e,s=v.event.fixHooks[e.type]||{},o=s.props?this.props.concat(s.props):this.props;e=v.Event(r);for(t=o.length;t;)n=o[--t],e[n]=r[n];return e.target||(e.target=r.srcElement||i),e.target.nodeType===3&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,r):e},special:{load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(e,t,n){v.isWindow(this)&&(this.onbeforeunload=n)},teardown:function(e,t){this.onbeforeunload===t&&(this.onbeforeunload=null)}}},simulate:function(e,t,n,r){var i=v.extend(new v.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?v.event.trigger(i,null,t):v.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},v.event.handle=v.event.dispatch,v.removeEvent=i.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]=="undefined"&&(e[r]=null),e.detachEvent(r,n))},v.Event=function(e,t){if(!(this instanceof v.Event))return new v.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?tt:et):this.type=e,t&&v.extend(this,t),this.timeStamp=e&&e.timeStamp||v.now(),this[v.expando]=!0},v.Event.prototype={preventDefault:function(){this.isDefaultPrevented=tt;var e=this.originalEvent;if(!e)return;e.preventDefault?e.preventDefault():e.returnValue=!1},stopPropagation:function(){this.isPropagationStopped=tt;var e=this.originalEvent;if(!e)return;e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=tt,this.stopPropagation()},isDefaultPrevented:et,isPropagationStopped:et,isImmediatePropagationStopped:et},v.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){v.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,s=e.handleObj,o=s.selector;if(!i||i!==r&&!v.contains(r,i))e.type=s.origType,n=s.handler.apply(this,arguments),e.type=t;return n}}}),v.support.submitBubbles||(v.event.special.submit={setup:function(){if(v.nodeName(this,"form"))return!1;v.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=v.nodeName(n,"input")||v.nodeName(n,"button")?n.form:t;r&&!v._data(r,"_submit_attached")&&(v.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),v._data(r,"_submit_attached",!0))})},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&v.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){if(v.nodeName(this,"form"))return!1;v.event.remove(this,"._submit")}}),v.support.changeBubbles||(v.event.special.change={setup:function(){if($.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")v.event.add(this,"propertychange._change",function(e){e.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),v.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),v.event.simulate("change",this,e,!0)});return!1}v.event.add(this,"beforeactivate._change",function(e){var t=e.target;$.test(t.nodeName)&&!v._data(t,"_change_attached")&&(v.event.add(t,"change._change",function(e){this.parentNode&&!e.isSimulated&&!e.isTrigger&&v.event.simulate("change",this.parentNode,e,!0)}),v._data(t,"_change_attached",!0))})},handle:function(e){var t=e.target;if(this!==t||e.isSimulated||e.isTrigger||t.type!=="radio"&&t.type!=="checkbox")return e.handleObj.handler.apply(this,arguments)},teardown:function(){return v.event.remove(this,"._change"),!$.test(this.nodeName)}}),v.support.focusinBubbles||v.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){v.event.simulate(t,e.target,v.event.fix(e),!0)};v.event.special[t]={setup:function(){n++===0&&i.addEventListener(e,r,!0)},teardown:function(){--n===0&&i.removeEventListener(e,r,!0)}}}),v.fn.extend({on:function(e,n,r,i,s){var o,u;if(typeof e=="object"){typeof n!="string"&&(r=r||n,n=t);for(u in e)this.on(u,n,r,e[u],s);return this}r==null&&i==null?(i=n,r=n=t):i==null&&(typeof n=="string"?(i=r,r=t):(i=r,r=n,n=t));if(i===!1)i=et;else if(!i)return this;return s===1&&(o=i,i=function(e){return v().off(e),o.apply(this,arguments)},i.guid=o.guid||(o.guid=v.guid++)),this.each(function(){v.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,s;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,v(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if(typeof e=="object"){for(s in e)this.off(s,n,e[s]);return this}if(n===!1||typeof n=="function")r=n,n=t;return r===!1&&(r=et),this.each(function(){v.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},live:function(e,t,n){return v(this.context).on(e,this.selector,t,n),this},die:function(e,t){return v(this.context).off(e,this.selector||"**",t),this},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return arguments.length===1?this.off(e,"**"):this.off(t,e||"**",n)},trigger:function(e,t){return this.each(function(){v.event.trigger(e,t,this)})},triggerHandler:function(e,t){if(this[0])return v.event.trigger(e,t,this[0],!0)},toggle:function(e){var t=arguments,n=e.guid||v.guid++,r=0,i=function(n){var i=(v._data(this,"lastToggle"+e.guid)||0)%r;return v._data(this,"lastToggle"+e.guid,i+1),n.preventDefault(),t[i].apply(this,arguments)||!1};i.guid=n;while(r<t.length)t[r++].guid=n;return this.click(i)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),v.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){v.fn[t]=function(e,n){return n==null&&(n=e,e=null),arguments.length>0?this.on(t,null,e,n):this.trigger(t)},Q.test(t)&&(v.event.fixHooks[t]=v.event.keyHooks),G.test(t)&&(v.event.fixHooks[t]=v.event.mouseHooks)}),function(e,t){function nt(e,t,n,r){n=n||[],t=t||g;var i,s,a,f,l=t.nodeType;if(!e||typeof e!="string")return n;if(l!==1&&l!==9)return[];a=o(t);if(!a&&!r)if(i=R.exec(e))if(f=i[1]){if(l===9){s=t.getElementById(f);if(!s||!s.parentNode)return n;if(s.id===f)return n.push(s),n}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(f))&&u(t,s)&&s.id===f)return n.push(s),n}else{if(i[2])return S.apply(n,x.call(t.getElementsByTagName(e),0)),n;if((f=i[3])&&Z&&t.getElementsByClassName)return S.apply(n,x.call(t.getElementsByClassName(f),0)),n}return vt(e.replace(j,"$1"),t,n,r,a)}function rt(e){return function(t){var n=t.nodeName.toLowerCase();return n==="input"&&t.type===e}}function it(e){return function(t){var n=t.nodeName.toLowerCase();return(n==="input"||n==="button")&&t.type===e}}function st(e){return N(function(t){return t=+t,N(function(n,r){var i,s=e([],n.length,t),o=s.length;while(o--)n[i=s[o]]&&(n[i]=!(r[i]=n[i]))})})}function ot(e,t,n){if(e===t)return n;var r=e.nextSibling;while(r){if(r===t)return-1;r=r.nextSibling}return 1}function ut(e,t){var n,r,s,o,u,a,f,l=L[d][e+" "];if(l)return t?0:l.slice(0);u=e,a=[],f=i.preFilter;while(u){if(!n||(r=F.exec(u)))r&&(u=u.slice(r[0].length)||u),a.push(s=[]);n=!1;if(r=I.exec(u))s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=r[0].replace(j," ");for(o in i.filter)(r=J[o].exec(u))&&(!f[o]||(r=f[o](r)))&&(s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=o,n.matches=r);if(!n)break}return t?u.length:u?nt.error(e):L(e,a).slice(0)}function at(e,t,r){var i=t.dir,s=r&&t.dir==="parentNode",o=w++;return t.first?function(t,n,r){while(t=t[i])if(s||t.nodeType===1)return e(t,n,r)}:function(t,r,u){if(!u){var a,f=b+" "+o+" ",l=f+n;while(t=t[i])if(s||t.nodeType===1){if((a=t[d])===l)return t.sizset;if(typeof a=="string"&&a.indexOf(f)===0){if(t.sizset)return t}else{t[d]=l;if(e(t,r,u))return t.sizset=!0,t;t.sizset=!1}}}else while(t=t[i])if(s||t.nodeType===1)if(e(t,r,u))return t}}function ft(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function lt(e,t,n,r,i){var s,o=[],u=0,a=e.length,f=t!=null;for(;u<a;u++)if(s=e[u])if(!n||n(s,r,i))o.push(s),f&&t.push(u);return o}function ct(e,t,n,r,i,s){return r&&!r[d]&&(r=ct(r)),i&&!i[d]&&(i=ct(i,s)),N(function(s,o,u,a){var f,l,c,h=[],p=[],d=o.length,v=s||dt(t||"*",u.nodeType?[u]:u,[]),m=e&&(s||!t)?lt(v,h,e,u,a):v,g=n?i||(s?e:d||r)?[]:o:m;n&&n(m,g,u,a);if(r){f=lt(g,p),r(f,[],u,a),l=f.length;while(l--)if(c=f[l])g[p[l]]=!(m[p[l]]=c)}if(s){if(i||e){if(i){f=[],l=g.length;while(l--)(c=g[l])&&f.push(m[l]=c);i(null,g=[],f,a)}l=g.length;while(l--)(c=g[l])&&(f=i?T.call(s,c):h[l])>-1&&(s[f]=!(o[f]=c))}}else g=lt(g===o?g.splice(d,g.length):g),i?i(null,o,g,a):S.apply(o,g)})}function ht(e){var t,n,r,s=e.length,o=i.relative[e[0].type],u=o||i.relative[" "],a=o?1:0,f=at(function(e){return e===t},u,!0),l=at(function(e){return T.call(t,e)>-1},u,!0),h=[function(e,n,r){return!o&&(r||n!==c)||((t=n).nodeType?f(e,n,r):l(e,n,r))}];for(;a<s;a++)if(n=i.relative[e[a].type])h=[at(ft(h),n)];else{n=i.filter[e[a].type].apply(null,e[a].matches);if(n[d]){r=++a;for(;r<s;r++)if(i.relative[e[r].type])break;return ct(a>1&&ft(h),a>1&&e.slice(0,a-1).join("").replace(j,"$1"),n,a<r&&ht(e.slice(a,r)),r<s&&ht(e=e.slice(r)),r<s&&e.join(""))}h.push(n)}return ft(h)}function pt(e,t){var r=t.length>0,s=e.length>0,o=function(u,a,f,l,h){var p,d,v,m=[],y=0,w="0",x=u&&[],T=h!=null,N=c,C=u||s&&i.find.TAG("*",h&&a.parentNode||a),k=b+=N==null?1:Math.E;T&&(c=a!==g&&a,n=o.el);for(;(p=C[w])!=null;w++){if(s&&p){for(d=0;v=e[d];d++)if(v(p,a,f)){l.push(p);break}T&&(b=k,n=++o.el)}r&&((p=!v&&p)&&y--,u&&x.push(p))}y+=w;if(r&&w!==y){for(d=0;v=t[d];d++)v(x,m,a,f);if(u){if(y>0)while(w--)!x[w]&&!m[w]&&(m[w]=E.call(l));m=lt(m)}S.apply(l,m),T&&!u&&m.length>0&&y+t.length>1&&nt.uniqueSort(l)}return T&&(b=k,c=N),x};return o.el=0,r?N(o):o}function dt(e,t,n){var r=0,i=t.length;for(;r<i;r++)nt(e,t[r],n);return n}function vt(e,t,n,r,s){var o,u,f,l,c,h=ut(e),p=h.length;if(!r&&h.length===1){u=h[0]=h[0].slice(0);if(u.length>2&&(f=u[0]).type==="ID"&&t.nodeType===9&&!s&&i.relative[u[1].type]){t=i.find.ID(f.matches[0].replace($,""),t,s)[0];if(!t)return n;e=e.slice(u.shift().length)}for(o=J.POS.test(e)?-1:u.length-1;o>=0;o--){f=u[o];if(i.relative[l=f.type])break;if(c=i.find[l])if(r=c(f.matches[0].replace($,""),z.test(u[0].type)&&t.parentNode||t,s)){u.splice(o,1),e=r.length&&u.join("");if(!e)return S.apply(n,x.call(r,0)),n;break}}}return a(e,h)(r,t,s,n,z.test(e)),n}function mt(){}var n,r,i,s,o,u,a,f,l,c,h=!0,p="undefined",d=("sizcache"+Math.random()).replace(".",""),m=String,g=e.document,y=g.documentElement,b=0,w=0,E=[].pop,S=[].push,x=[].slice,T=[].indexOf||function(e){var t=0,n=this.length;for(;t<n;t++)if(this[t]===e)return t;return-1},N=function(e,t){return e[d]=t==null||t,e},C=function(){var e={},t=[];return N(function(n,r){return t.push(n)>i.cacheLength&&delete e[t.shift()],e[n+" "]=r},e)},k=C(),L=C(),A=C(),O="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",_=M.replace("w","w#"),D="([*^$|!~]?=)",P="\\["+O+"*("+M+")"+O+"*(?:"+D+O+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+_+")|)|)"+O+"*\\]",H=":("+M+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+P+")|[^:]|\\\\.)*|.*))\\)|)",B=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+O+"*((?:-\\d)?\\d*)"+O+"*\\)|)(?=[^-]|$)",j=new RegExp("^"+O+"+|((?:^|[^\\\\])(?:\\\\.)*)"+O+"+$","g"),F=new RegExp("^"+O+"*,"+O+"*"),I=new RegExp("^"+O+"*([\\x20\\t\\r\\n\\f>+~])"+O+"*"),q=new RegExp(H),R=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,U=/^:not/,z=/[\x20\t\r\n\f]*[+~]/,W=/:not\($/,X=/h\d/i,V=/input|select|textarea|button/i,$=/\\(?!\\)/g,J={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),NAME:new RegExp("^\\[name=['\"]?("+M+")['\"]?\\]"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+H),POS:new RegExp(B,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+O+"*(even|odd|(([+-]|)(\\d*)n|)"+O+"*(?:([+-]|)"+O+"*(\\d+)|))"+O+"*\\)|)","i"),needsContext:new RegExp("^"+O+"*[>+~]|"+B,"i")},K=function(e){var t=g.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}},Q=K(function(e){return e.appendChild(g.createComment("")),!e.getElementsByTagName("*").length}),G=K(function(e){return e.innerHTML="<a href='#'></a>",e.firstChild&&typeof e.firstChild.getAttribute!==p&&e.firstChild.getAttribute("href")==="#"}),Y=K(function(e){e.innerHTML="<select></select>";var t=typeof e.lastChild.getAttribute("multiple");return t!=="boolean"&&t!=="string"}),Z=K(function(e){return e.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",!e.getElementsByClassName||!e.getElementsByClassName("e").length?!1:(e.lastChild.className="e",e.getElementsByClassName("e").length===2)}),et=K(function(e){e.id=d+0,e.innerHTML="<a name='"+d+"'></a><div name='"+d+"'></div>",y.insertBefore(e,y.firstChild);var t=g.getElementsByName&&g.getElementsByName(d).length===2+g.getElementsByName(d+0).length;return r=!g.getElementById(d),y.removeChild(e),t});try{x.call(y.childNodes,0)[0].nodeType}catch(tt){x=function(e){var t,n=[];for(;t=this[e];e++)n.push(t);return n}}nt.matches=function(e,t){return nt(e,null,null,t)},nt.matchesSelector=function(e,t){return nt(t,null,null,[e]).length>0},s=nt.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(i===1||i===9||i===11){if(typeof e.textContent=="string")return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=s(e)}else if(i===3||i===4)return e.nodeValue}else for(;t=e[r];r++)n+=s(t);return n},o=nt.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?t.nodeName!=="HTML":!1},u=nt.contains=y.contains?function(e,t){var n=e.nodeType===9?e.documentElement:e,r=t&&t.parentNode;return e===r||!!(r&&r.nodeType===1&&n.contains&&n.contains(r))}:y.compareDocumentPosition?function(e,t){return t&&!!(e.compareDocumentPosition(t)&16)}:function(e,t){while(t=t.parentNode)if(t===e)return!0;return!1},nt.attr=function(e,t){var n,r=o(e);return r||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):r||Y?e.getAttribute(t):(n=e.getAttributeNode(t),n?typeof e[t]=="boolean"?e[t]?t:null:n.specified?n.value:null:null)},i=nt.selectors={cacheLength:50,createPseudo:N,match:J,attrHandle:G?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},find:{ID:r?function(e,t,n){if(typeof t.getElementById!==p&&!n){var r=t.getElementById(e);return r&&r.parentNode?[r]:[]}}:function(e,n,r){if(typeof n.getElementById!==p&&!r){var i=n.getElementById(e);return i?i.id===e||typeof i.getAttributeNode!==p&&i.getAttributeNode("id").value===e?[i]:t:[]}},TAG:Q?function(e,t){if(typeof t.getElementsByTagName!==p)return t.getElementsByTagName(e)}:function(e,t){var n=t.getElementsByTagName(e);if(e==="*"){var r,i=[],s=0;for(;r=n[s];s++)r.nodeType===1&&i.push(r);return i}return n},NAME:et&&function(e,t){if(typeof t.getElementsByName!==p)return t.getElementsByName(name)},CLASS:Z&&function(e,t,n){if(typeof t.getElementsByClassName!==p&&!n)return t.getElementsByClassName(e)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace($,""),e[3]=(e[4]||e[5]||"").replace($,""),e[2]==="~="&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),e[1]==="nth"?(e[2]||nt.error(e[0]),e[3]=+(e[3]?e[4]+(e[5]||1):2*(e[2]==="even"||e[2]==="odd")),e[4]=+(e[6]+e[7]||e[2]==="odd")):e[2]&&nt.error(e[0]),e},PSEUDO:function(e){var t,n;if(J.CHILD.test(e[0]))return null;if(e[3])e[2]=e[3];else if(t=e[4])q.test(t)&&(n=ut(t,!0))&&(n=t.indexOf(")",t.length-n)-t.length)&&(t=t.slice(0,n),e[0]=e[0].slice(0,n)),e[2]=t;return e.slice(0,3)}},filter:{ID:r?function(e){return e=e.replace($,""),function(t){return t.getAttribute("id")===e}}:function(e){return e=e.replace($,""),function(t){var n=typeof t.getAttributeNode!==p&&t.getAttributeNode("id");return n&&n.value===e}},TAG:function(e){return e==="*"?function(){return!0}:(e=e.replace($,"").toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[d][e+" "];return t||(t=new RegExp("(^|"+O+")"+e+"("+O+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==p&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r,i){var s=nt.attr(r,e);return s==null?t==="!=":t?(s+="",t==="="?s===n:t==="!="?s!==n:t==="^="?n&&s.indexOf(n)===0:t==="*="?n&&s.indexOf(n)>-1:t==="$="?n&&s.substr(s.length-n.length)===n:t==="~="?(" "+s+" ").indexOf(n)>-1:t==="|="?s===n||s.substr(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r){return e==="nth"?function(e){var t,i,s=e.parentNode;if(n===1&&r===0)return!0;if(s){i=0;for(t=s.firstChild;t;t=t.nextSibling)if(t.nodeType===1){i++;if(e===t)break}}return i-=r,i===n||i%n===0&&i/n>=0}:function(t){var n=t;switch(e){case"only":case"first":while(n=n.previousSibling)if(n.nodeType===1)return!1;if(e==="first")return!0;n=t;case"last":while(n=n.nextSibling)if(n.nodeType===1)return!1;return!0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||nt.error("unsupported pseudo: "+e);return r[d]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?N(function(e,n){var i,s=r(e,t),o=s.length;while(o--)i=T.call(e,s[o]),e[i]=!(n[i]=s[o])}):function(e){return r(e,0,n)}):r}},pseudos:{not:N(function(e){var t=[],n=[],r=a(e.replace(j,"$1"));return r[d]?N(function(e,t,n,i){var s,o=r(e,null,i,[]),u=e.length;while(u--)if(s=o[u])e[u]=!(t[u]=s)}):function(e,i,s){return t[0]=e,r(t,null,s,n),!n.pop()}}),has:N(function(e){return function(t){return nt(e,t).length>0}}),contains:N(function(e){return function(t){return(t.textContent||t.innerText||s(t)).indexOf(e)>-1}}),enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&!!e.checked||t==="option"&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},parent:function(e){return!i.pseudos.empty(e)},empty:function(e){var t;e=e.firstChild;while(e){if(e.nodeName>"@"||(t=e.nodeType)===3||t===4)return!1;e=e.nextSibling}return!0},header:function(e){return X.test(e.nodeName)},text:function(e){var t,n;return e.nodeName.toLowerCase()==="input"&&(t=e.type)==="text"&&((n=e.getAttribute("type"))==null||n.toLowerCase()===t)},radio:rt("radio"),checkbox:rt("checkbox"),file:rt("file"),password:rt("password"),image:rt("image"),submit:it("submit"),reset:it("reset"),button:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&e.type==="button"||t==="button"},input:function(e){return V.test(e.nodeName)},focus:function(e){var t=e.ownerDocument;return e===t.activeElement&&(!t.hasFocus||t.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},active:function(e){return e===e.ownerDocument.activeElement},first:st(function(){return[0]}),last:st(function(e,t){return[t-1]}),eq:st(function(e,t,n){return[n<0?n+t:n]}),even:st(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:st(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:st(function(e,t,n){for(var r=n<0?n+t:n;--r>=0;)e.push(r);return e}),gt:st(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}},f=y.compareDocumentPosition?function(e,t){return e===t?(l=!0,0):(!e.compareDocumentPosition||!t.compareDocumentPosition?e.compareDocumentPosition:e.compareDocumentPosition(t)&4)?-1:1}:function(e,t){if(e===t)return l=!0,0;if(e.sourceIndex&&t.sourceIndex)return e.sourceIndex-t.sourceIndex;var n,r,i=[],s=[],o=e.parentNode,u=t.parentNode,a=o;if(o===u)return ot(e,t);if(!o)return-1;if(!u)return 1;while(a)i.unshift(a),a=a.parentNode;a=u;while(a)s.unshift(a),a=a.parentNode;n=i.length,r=s.length;for(var f=0;f<n&&f<r;f++)if(i[f]!==s[f])return ot(i[f],s[f]);return f===n?ot(e,s[f],-1):ot(i[f],t,1)},[0,0].sort(f),h=!l,nt.uniqueSort=function(e){var t,n=[],r=1,i=0;l=h,e.sort(f);if(l){for(;t=e[r];r++)t===e[r-1]&&(i=n.push(r));while(i--)e.splice(n[i],1)}return e},nt.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},a=nt.compile=function(e,t){var n,r=[],i=[],s=A[d][e+" "];if(!s){t||(t=ut(e)),n=t.length;while(n--)s=ht(t[n]),s[d]?r.push(s):i.push(s);s=A(e,pt(i,r))}return s},g.querySelectorAll&&function(){var e,t=vt,n=/'|\\/g,r=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,i=[":focus"],s=[":active"],u=y.matchesSelector||y.mozMatchesSelector||y.webkitMatchesSelector||y.oMatchesSelector||y.msMatchesSelector;K(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||i.push("\\["+O+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||i.push(":checked")}),K(function(e){e.innerHTML="<p test=''></p>",e.querySelectorAll("[test^='']").length&&i.push("[*^$]="+O+"*(?:\"\"|'')"),e.innerHTML="<input type='hidden'/>",e.querySelectorAll(":enabled").length||i.push(":enabled",":disabled")}),i=new RegExp(i.join("|")),vt=function(e,r,s,o,u){if(!o&&!u&&!i.test(e)){var a,f,l=!0,c=d,h=r,p=r.nodeType===9&&e;if(r.nodeType===1&&r.nodeName.toLowerCase()!=="object"){a=ut(e),(l=r.getAttribute("id"))?c=l.replace(n,"\\$&"):r.setAttribute("id",c),c="[id='"+c+"'] ",f=a.length;while(f--)a[f]=c+a[f].join("");h=z.test(e)&&r.parentNode||r,p=a.join(",")}if(p)try{return S.apply(s,x.call(h.querySelectorAll(p),0)),s}catch(v){}finally{l||r.removeAttribute("id")}}return t(e,r,s,o,u)},u&&(K(function(t){e=u.call(t,"div");try{u.call(t,"[test!='']:sizzle"),s.push("!=",H)}catch(n){}}),s=new RegExp(s.join("|")),nt.matchesSelector=function(t,n){n=n.replace(r,"='$1']");if(!o(t)&&!s.test(n)&&!i.test(n))try{var a=u.call(t,n);if(a||e||t.document&&t.document.nodeType!==11)return a}catch(f){}return nt(n,null,null,[t]).length>0})}(),i.pseudos.nth=i.pseudos.eq,i.filters=mt.prototype=i.pseudos,i.setFilters=new mt,nt.attr=v.attr,v.find=nt,v.expr=nt.selectors,v.expr[":"]=v.expr.pseudos,v.unique=nt.uniqueSort,v.text=nt.getText,v.isXMLDoc=nt.isXML,v.contains=nt.contains}(e);var nt=/Until$/,rt=/^(?:parents|prev(?:Until|All))/,it=/^.[^:#\[\.,]*$/,st=v.expr.match.needsContext,ot={children:!0,contents:!0,next:!0,prev:!0};v.fn.extend({find:function(e){var t,n,r,i,s,o,u=this;if(typeof e!="string")return v(e).filter(function(){for(t=0,n=u.length;t<n;t++)if(v.contains(u[t],this))return!0});o=this.pushStack("","find",e);for(t=0,n=this.length;t<n;t++){r=o.length,v.find(e,this[t],o);if(t>0)for(i=r;i<o.length;i++)for(s=0;s<r;s++)if(o[s]===o[i]){o.splice(i--,1);break}}return o},has:function(e){var t,n=v(e,this),r=n.length;return this.filter(function(){for(t=0;t<r;t++)if(v.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e,!1),"not",e)},filter:function(e){return this.pushStack(ft(this,e,!0),"filter",e)},is:function(e){return!!e&&(typeof e=="string"?st.test(e)?v(e,this.context).index(this[0])>=0:v.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,s=[],o=st.test(e)||typeof e!="string"?v(e,t||this.context):0;for(;r<i;r++){n=this[r];while(n&&n.ownerDocument&&n!==t&&n.nodeType!==11){if(o?o.index(n)>-1:v.find.matchesSelector(n,e)){s.push(n);break}n=n.parentNode}}return s=s.length>1?v.unique(s):s,this.pushStack(s,"closest",e)},index:function(e){return e?typeof e=="string"?v.inArray(this[0],v(e)):v.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(e,t){var n=typeof e=="string"?v(e,t):v.makeArray(e&&e.nodeType?[e]:e),r=v.merge(this.get(),n);return this.pushStack(ut(n[0])||ut(r[0])?r:v.unique(r))},addBack:function(e){return this.add(e==null?this.prevObject:this.prevObject.filter(e))}}),v.fn.andSelf=v.fn.addBack,v.each({parent:function(e){var t=e.parentNode;return t&&t.nodeType!==11?t:null},parents:function(e){return v.dir(e,"parentNode")},parentsUntil:function(e,t,n){return v.dir(e,"parentNode",n)},next:function(e){return at(e,"nextSibling")},prev:function(e){return at(e,"previousSibling")},nextAll:function(e){return v.dir(e,"nextSibling")},prevAll:function(e){return v.dir(e,"previousSibling")},nextUntil:function(e,t,n){return v.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return v.dir(e,"previousSibling",n)},siblings:function(e){return v.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return v.sibling(e.firstChild)},contents:function(e){return v.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:v.merge([],e.childNodes)}},function(e,t){v.fn[e]=function(n,r){var i=v.map(this,t,n);return nt.test(e)||(r=n),r&&typeof r=="string"&&(i=v.filter(r,i)),i=this.length>1&&!ot[e]?v.unique(i):i,this.length>1&&rt.test(e)&&(i=i.reverse()),this.pushStack(i,e,l.call(arguments).join(","))}}),v.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),t.length===1?v.find.matchesSelector(t[0],e)?[t[0]]:[]:v.find.matches(e,t)},dir:function(e,n,r){var i=[],s=e[n];while(s&&s.nodeType!==9&&(r===t||s.nodeType!==1||!v(s).is(r)))s.nodeType===1&&i.push(s),s=s[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)e.nodeType===1&&e!==t&&n.push(e);return n}});var ct="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",ht=/ jQuery\d+="(?:null|\d+)"/g,pt=/^\s+/,dt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,vt=/<([\w:]+)/,mt=/<tbody/i,gt=/<|&#?\w+;/,yt=/<(?:script|style|link)/i,bt=/<(?:script|object|embed|option|style)/i,wt=new RegExp("<(?:"+ct+")[\\s/>]","i"),Et=/^(?:checkbox|radio)$/,St=/checked\s*(?:[^=]|=\s*.checked.)/i,xt=/\/(java|ecma)script/i,Tt=/^\s*<!(?:\[CDATA\[|\-\-)|[\]\-]{2}>\s*$/g,Nt={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},Ct=lt(i),kt=Ct.appendChild(i.createElement("div"));Nt.optgroup=Nt.option,Nt.tbody=Nt.tfoot=Nt.colgroup=Nt.caption=Nt.thead,Nt.th=Nt.td,v.support.htmlSerialize||(Nt._default=[1,"X<div>","</div>"]),v.fn.extend({text:function(e){return v.access(this,function(e){return e===t?v.text(this):this.empty().append((this[0]&&this[0].ownerDocument||i).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(v.isFunction(e))return this.each(function(t){v(this).wrapAll(e.call(this,t))});if(this[0]){var t=v(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&e.firstChild.nodeType===1)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return v.isFunction(e)?this.each(function(t){v(this).wrapInner(e.call(this,t))}):this.each(function(){var t=v(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=v.isFunction(e);return this.each(function(n){v(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){v.nodeName(this,"body")||v(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(e,this.firstChild)})},before:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(e,this),"before",this.selector)}},after:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this.nextSibling)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(this,e),"after",this.selector)}},remove:function(e,t){var n,r=0;for(;(n=this[r])!=null;r++)if(!e||v.filter(e,[n]).length)!t&&n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),v.cleanData([n])),n.parentNode&&n.parentNode.removeChild(n);return this},empty:function(){var e,t=0;for(;(e=this[t])!=null;t++){e.nodeType===1&&v.cleanData(e.getElementsByTagName("*"));while(e.firstChild)e.removeChild(e.firstChild)}return this},clone:function(e,t){return e=e==null?!1:e,t=t==null?e:t,this.map(function(){return v.clone(this,e,t)})},html:function(e){return v.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return n.nodeType===1?n.innerHTML.replace(ht,""):t;if(typeof e=="string"&&!yt.test(e)&&(v.support.htmlSerialize||!wt.test(e))&&(v.support.leadingWhitespace||!pt.test(e))&&!Nt[(vt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(dt,"<$1></$2>");try{for(;r<i;r++)n=this[r]||{},n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),n.innerHTML=e);n=0}catch(s){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(e){return ut(this[0])?this.length?this.pushStack(v(v.isFunction(e)?e():e),"replaceWith",e):this:v.isFunction(e)?this.each(function(t){var n=v(this),r=n.html();n.replaceWith(e.call(this,t,r))}):(typeof e!="string"&&(e=v(e).detach()),this.each(function(){var t=this.nextSibling,n=this.parentNode;v(this).remove(),t?v(t).before(e):v(n).append(e)}))},detach:function(e){return this.remove(e,!0)},domManip:function(e,n,r){e=[].concat.apply([],e);var i,s,o,u,a=0,f=e[0],l=[],c=this.length;if(!v.support.checkClone&&c>1&&typeof f=="string"&&St.test(f))return this.each(function(){v(this).domManip(e,n,r)});if(v.isFunction(f))return this.each(function(i){var s=v(this);e[0]=f.call(this,i,n?s.html():t),s.domManip(e,n,r)});if(this[0]){i=v.buildFragment(e,this,l),o=i.fragment,s=o.firstChild,o.childNodes.length===1&&(o=s);if(s){n=n&&v.nodeName(s,"tr");for(u=i.cacheable||c-1;a<c;a++)r.call(n&&v.nodeName(this[a],"table")?Lt(this[a],"tbody"):this[a],a===u?o:v.clone(o,!0,!0))}o=s=null,l.length&&v.each(l,function(e,t){t.src?v.ajax?v.ajax({url:t.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):v.error("no ajax"):v.globalEval((t.text||t.textContent||t.innerHTML||"").replace(Tt,"")),t.parentNode&&t.parentNode.removeChild(t)})}return this}}),v.buildFragment=function(e,n,r){var s,o,u,a=e[0];return n=n||i,n=!n.nodeType&&n[0]||n,n=n.ownerDocument||n,e.length===1&&typeof a=="string"&&a.length<512&&n===i&&a.charAt(0)==="<"&&!bt.test(a)&&(v.support.checkClone||!St.test(a))&&(v.support.html5Clone||!wt.test(a))&&(o=!0,s=v.fragments[a],u=s!==t),s||(s=n.createDocumentFragment(),v.clean(e,n,s,r),o&&(v.fragments[a]=u&&s)),{fragment:s,cacheable:o}},v.fragments={},v.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){v.fn[e]=function(n){var r,i=0,s=[],o=v(n),u=o.length,a=this.length===1&&this[0].parentNode;if((a==null||a&&a.nodeType===11&&a.childNodes.length===1)&&u===1)return o[t](this[0]),this;for(;i<u;i++)r=(i>0?this.clone(!0):this).get(),v(o[i])[t](r),s=s.concat(r);return this.pushStack(s,e,o.selector)}}),v.extend({clone:function(e,t,n){var r,i,s,o;v.support.html5Clone||v.isXMLDoc(e)||!wt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(kt.innerHTML=e.outerHTML,kt.removeChild(o=kt.firstChild));if((!v.support.noCloneEvent||!v.support.noCloneChecked)&&(e.nodeType===1||e.nodeType===11)&&!v.isXMLDoc(e)){Ot(e,o),r=Mt(e),i=Mt(o);for(s=0;r[s];++s)i[s]&&Ot(r[s],i[s])}if(t){At(e,o);if(n){r=Mt(e),i=Mt(o);for(s=0;r[s];++s)At(r[s],i[s])}}return r=i=null,o},clean:function(e,t,n,r){var s,o,u,a,f,l,c,h,p,d,m,g,y=t===i&&Ct,b=[];if(!t||typeof t.createDocumentFragment=="undefined")t=i;for(s=0;(u=e[s])!=null;s++){typeof u=="number"&&(u+="");if(!u)continue;if(typeof u=="string")if(!gt.test(u))u=t.createTextNode(u);else{y=y||lt(t),c=t.createElement("div"),y.appendChild(c),u=u.replace(dt,"<$1></$2>"),a=(vt.exec(u)||["",""])[1].toLowerCase(),f=Nt[a]||Nt._default,l=f[0],c.innerHTML=f[1]+u+f[2];while(l--)c=c.lastChild;if(!v.support.tbody){h=mt.test(u),p=a==="table"&&!h?c.firstChild&&c.firstChild.childNodes:f[1]==="<table>"&&!h?c.childNodes:[];for(o=p.length-1;o>=0;--o)v.nodeName(p[o],"tbody")&&!p[o].childNodes.length&&p[o].parentNode.removeChild(p[o])}!v.support.leadingWhitespace&&pt.test(u)&&c.insertBefore(t.createTextNode(pt.exec(u)[0]),c.firstChild),u=c.childNodes,c.parentNode.removeChild(c)}u.nodeType?b.push(u):v.merge(b,u)}c&&(u=c=y=null);if(!v.support.appendChecked)for(s=0;(u=b[s])!=null;s++)v.nodeName(u,"input")?_t(u):typeof u.getElementsByTagName!="undefined"&&v.grep(u.getElementsByTagName("input"),_t);if(n){m=function(e){if(!e.type||xt.test(e.type))return r?r.push(e.parentNode?e.parentNode.removeChild(e):e):n.appendChild(e)};for(s=0;(u=b[s])!=null;s++)if(!v.nodeName(u,"script")||!m(u))n.appendChild(u),typeof u.getElementsByTagName!="undefined"&&(g=v.grep(v.merge([],u.getElementsByTagName("script")),m),b.splice.apply(b,[s+1,0].concat(g)),s+=g.length)}return b},cleanData:function(e,t){var n,r,i,s,o=0,u=v.expando,a=v.cache,f=v.support.deleteExpando,l=v.event.special;for(;(i=e[o])!=null;o++)if(t||v.acceptData(i)){r=i[u],n=r&&a[r];if(n){if(n.events)for(s in n.events)l[s]?v.event.remove(i,s):v.removeEvent(i,s,n.handle);a[r]&&(delete a[r],f?delete i[u]:i.removeAttribute?i.removeAttribute(u):i[u]=null,v.deletedIds.push(r))}}}}),function(){var e,t;v.uaMatch=function(e){e=e.toLowerCase();var t=/(chrome)[ \/]([\w.]+)/.exec(e)||/(webkit)[ \/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||e.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},e=v.uaMatch(o.userAgent),t={},e.browser&&(t[e.browser]=!0,t.version=e.version),t.chrome?t.webkit=!0:t.webkit&&(t.safari=!0),v.browser=t,v.sub=function(){function e(t,n){return new e.fn.init(t,n)}v.extend(!0,e,this),e.superclass=this,e.fn=e.prototype=this(),e.fn.constructor=e,e.sub=this.sub,e.fn.init=function(r,i){return i&&i instanceof v&&!(i instanceof e)&&(i=e(i)),v.fn.init.call(this,r,i,t)},e.fn.init.prototype=e.fn;var t=e(i);return e}}();var Dt,Pt,Ht,Bt=/alpha\([^)]*\)/i,jt=/opacity=([^)]*)/,Ft=/^(top|right|bottom|left)$/,It=/^(none|table(?!-c[ea]).+)/,qt=/^margin/,Rt=new RegExp("^("+m+")(.*)$","i"),Ut=new RegExp("^("+m+")(?!px)[a-z%]+$","i"),zt=new RegExp("^([-+])=("+m+")","i"),Wt={BODY:"block"},Xt={position:"absolute",visibility:"hidden",display:"block"},Vt={letterSpacing:0,fontWeight:400},$t=["Top","Right","Bottom","Left"],Jt=["Webkit","O","Moz","ms"],Kt=v.fn.toggle;v.fn.extend({css:function(e,n){return v.access(this,function(e,n,r){return r!==t?v.style(e,n,r):v.css(e,n)},e,n,arguments.length>1)},show:function(){return Yt(this,!0)},hide:function(){return Yt(this)},toggle:function(e,t){var n=typeof e=="boolean";return v.isFunction(e)&&v.isFunction(t)?Kt.apply(this,arguments):this.each(function(){(n?e:Gt(this))?v(this).show():v(this).hide()})}}),v.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Dt(e,"opacity");return n===""?"1":n}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":v.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(!e||e.nodeType===3||e.nodeType===8||!e.style)return;var s,o,u,a=v.camelCase(n),f=e.style;n=v.cssProps[a]||(v.cssProps[a]=Qt(f,a)),u=v.cssHooks[n]||v.cssHooks[a];if(r===t)return u&&"get"in u&&(s=u.get(e,!1,i))!==t?s:f[n];o=typeof r,o==="string"&&(s=zt.exec(r))&&(r=(s[1]+1)*s[2]+parseFloat(v.css(e,n)),o="number");if(r==null||o==="number"&&isNaN(r))return;o==="number"&&!v.cssNumber[a]&&(r+="px");if(!u||!("set"in u)||(r=u.set(e,r,i))!==t)try{f[n]=r}catch(l){}},css:function(e,n,r,i){var s,o,u,a=v.camelCase(n);return n=v.cssProps[a]||(v.cssProps[a]=Qt(e.style,a)),u=v.cssHooks[n]||v.cssHooks[a],u&&"get"in u&&(s=u.get(e,!0,i)),s===t&&(s=Dt(e,n)),s==="normal"&&n in Vt&&(s=Vt[n]),r||i!==t?(o=parseFloat(s),r||v.isNumeric(o)?o||0:s):s},swap:function(e,t,n){var r,i,s={};for(i in t)s[i]=e.style[i],e.style[i]=t[i];r=n.call(e);for(i in t)e.style[i]=s[i];return r}}),e.getComputedStyle?Dt=function(t,n){var r,i,s,o,u=e.getComputedStyle(t,null),a=t.style;return u&&(r=u.getPropertyValue(n)||u[n],r===""&&!v.contains(t.ownerDocument,t)&&(r=v.style(t,n)),Ut.test(r)&&qt.test(n)&&(i=a.width,s=a.minWidth,o=a.maxWidth,a.minWidth=a.maxWidth=a.width=r,r=u.width,a.width=i,a.minWidth=s,a.maxWidth=o)),r}:i.documentElement.currentStyle&&(Dt=function(e,t){var n,r,i=e.currentStyle&&e.currentStyle[t],s=e.style;return i==null&&s&&s[t]&&(i=s[t]),Ut.test(i)&&!Ft.test(t)&&(n=s.left,r=e.runtimeStyle&&e.runtimeStyle.left,r&&(e.runtimeStyle.left=e.currentStyle.left),s.left=t==="fontSize"?"1em":i,i=s.pixelLeft+"px",s.left=n,r&&(e.runtimeStyle.left=r)),i===""?"auto":i}),v.each(["height","width"],function(e,t){v.cssHooks[t]={get:function(e,n,r){if(n)return e.offsetWidth===0&&It.test(Dt(e,"display"))?v.swap(e,Xt,function(){return tn(e,t,r)}):tn(e,t,r)},set:function(e,n,r){return Zt(e,n,r?en(e,t,r,v.support.boxSizing&&v.css(e,"boxSizing")==="border-box"):0)}}}),v.support.opacity||(v.cssHooks.opacity={get:function(e,t){return jt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=v.isNumeric(t)?"alpha(opacity="+t*100+")":"",s=r&&r.filter||n.filter||"";n.zoom=1;if(t>=1&&v.trim(s.replace(Bt,""))===""&&n.removeAttribute){n.removeAttribute("filter");if(r&&!r.filter)return}n.filter=Bt.test(s)?s.replace(Bt,i):s+" "+i}}),v(function(){v.support.reliableMarginRight||(v.cssHooks.marginRight={get:function(e,t){return v.swap(e,{display:"inline-block"},function(){if(t)return Dt(e,"marginRight")})}}),!v.support.pixelPosition&&v.fn.position&&v.each(["top","left"],function(e,t){v.cssHooks[t]={get:function(e,n){if(n){var r=Dt(e,t);return Ut.test(r)?v(e).position()[t]+"px":r}}}})}),v.expr&&v.expr.filters&&(v.expr.filters.hidden=function(e){return e.offsetWidth===0&&e.offsetHeight===0||!v.support.reliableHiddenOffsets&&(e.style&&e.style.display||Dt(e,"display"))==="none"},v.expr.filters.visible=function(e){return!v.expr.filters.hidden(e)}),v.each({margin:"",padding:"",border:"Width"},function(e,t){v.cssHooks[e+t]={expand:function(n){var r,i=typeof n=="string"?n.split(" "):[n],s={};for(r=0;r<4;r++)s[e+$t[r]+t]=i[r]||i[r-2]||i[0];return s}},qt.test(e)||(v.cssHooks[e+t].set=Zt)});var rn=/%20/g,sn=/\[\]$/,on=/\r?\n/g,un=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,an=/^(?:select|textarea)/i;v.fn.extend({serialize:function(){return v.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?v.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||an.test(this.nodeName)||un.test(this.type))}).map(function(e,t){var n=v(this).val();return n==null?null:v.isArray(n)?v.map(n,function(e,n){return{name:t.name,value:e.replace(on,"\r\n")}}):{name:t.name,value:n.replace(on,"\r\n")}}).get()}}),v.param=function(e,n){var r,i=[],s=function(e,t){t=v.isFunction(t)?t():t==null?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};n===t&&(n=v.ajaxSettings&&v.ajaxSettings.traditional);if(v.isArray(e)||e.jquery&&!v.isPlainObject(e))v.each(e,function(){s(this.name,this.value)});else for(r in e)fn(r,e[r],n,s);return i.join("&").replace(rn,"+")};var ln,cn,hn=/#.*$/,pn=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,dn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,vn=/^(?:GET|HEAD)$/,mn=/^\/\//,gn=/\?/,yn=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bn=/([?&])_=[^&]*/,wn=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,En=v.fn.load,Sn={},xn={},Tn=["*/"]+["*"];try{cn=s.href}catch(Nn){cn=i.createElement("a"),cn.href="",cn=cn.href}ln=wn.exec(cn.toLowerCase())||[],v.fn.load=function(e,n,r){if(typeof e!="string"&&En)return En.apply(this,arguments);if(!this.length)return this;var i,s,o,u=this,a=e.indexOf(" ");return a>=0&&(i=e.slice(a,e.length),e=e.slice(0,a)),v.isFunction(n)?(r=n,n=t):n&&typeof n=="object"&&(s="POST"),v.ajax({url:e,type:s,dataType:"html",data:n,complete:function(e,t){r&&u.each(r,o||[e.responseText,t,e])}}).done(function(e){o=arguments,u.html(i?v("<div>").append(e.replace(yn,"")).find(i):e)}),this},v.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,t){v.fn[t]=function(e){return this.on(t,e)}}),v.each(["get","post"],function(e,n){v[n]=function(e,r,i,s){return v.isFunction(r)&&(s=s||i,i=r,r=t),v.ajax({type:n,url:e,data:r,success:i,dataType:s})}}),v.extend({getScript:function(e,n){return v.get(e,t,n,"script")},getJSON:function(e,t,n){return v.get(e,t,n,"json")},ajaxSetup:function(e,t){return t?Ln(e,v.ajaxSettings):(t=e,e=v.ajaxSettings),Ln(e,t),e},ajaxSettings:{url:cn,isLocal:dn.test(ln[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":Tn},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":v.parseJSON,"text xml":v.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:Cn(Sn),ajaxTransport:Cn(xn),ajax:function(e,n){function T(e,n,s,a){var l,y,b,w,S,T=n;if(E===2)return;E=2,u&&clearTimeout(u),o=t,i=a||"",x.readyState=e>0?4:0,s&&(w=An(c,x,s));if(e>=200&&e<300||e===304)c.ifModified&&(S=x.getResponseHeader("Last-Modified"),S&&(v.lastModified[r]=S),S=x.getResponseHeader("Etag"),S&&(v.etag[r]=S)),e===304?(T="notmodified",l=!0):(l=On(c,w),T=l.state,y=l.data,b=l.error,l=!b);else{b=T;if(!T||e)T="error",e<0&&(e=0)}x.status=e,x.statusText=(n||T)+"",l?d.resolveWith(h,[y,T,x]):d.rejectWith(h,[x,T,b]),x.statusCode(g),g=t,f&&p.trigger("ajax"+(l?"Success":"Error"),[x,c,l?y:b]),m.fireWith(h,[x,T]),f&&(p.trigger("ajaxComplete",[x,c]),--v.active||v.event.trigger("ajaxStop"))}typeof e=="object"&&(n=e,e=t),n=n||{};var r,i,s,o,u,a,f,l,c=v.ajaxSetup({},n),h=c.context||c,p=h!==c&&(h.nodeType||h instanceof v)?v(h):v.event,d=v.Deferred(),m=v.Callbacks("once memory"),g=c.statusCode||{},b={},w={},E=0,S="canceled",x={readyState:0,setRequestHeader:function(e,t){if(!E){var n=e.toLowerCase();e=w[n]=w[n]||e,b[e]=t}return this},getAllResponseHeaders:function(){return E===2?i:null},getResponseHeader:function(e){var n;if(E===2){if(!s){s={};while(n=pn.exec(i))s[n[1].toLowerCase()]=n[2]}n=s[e.toLowerCase()]}return n===t?null:n},overrideMimeType:function(e){return E||(c.mimeType=e),this},abort:function(e){return e=e||S,o&&o.abort(e),T(0,e),this}};d.promise(x),x.success=x.done,x.error=x.fail,x.complete=m.add,x.statusCode=function(e){if(e){var t;if(E<2)for(t in e)g[t]=[g[t],e[t]];else t=e[x.status],x.always(t)}return this},c.url=((e||c.url)+"").replace(hn,"").replace(mn,ln[1]+"//"),c.dataTypes=v.trim(c.dataType||"*").toLowerCase().split(y),c.crossDomain==null&&(a=wn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===ln[1]&&a[2]===ln[2]&&(a[3]||(a[1]==="http:"?80:443))==(ln[3]||(ln[1]==="http:"?80:443)))),c.data&&c.processData&&typeof c.data!="string"&&(c.data=v.param(c.data,c.traditional)),kn(Sn,c,n,x);if(E===2)return x;f=c.global,c.type=c.type.toUpperCase(),c.hasContent=!vn.test(c.type),f&&v.active++===0&&v.event.trigger("ajaxStart");if(!c.hasContent){c.data&&(c.url+=(gn.test(c.url)?"&":"?")+c.data,delete c.data),r=c.url;if(c.cache===!1){var N=v.now(),C=c.url.replace(bn,"$1_="+N);c.url=C+(C===c.url?(gn.test(c.url)?"&":"?")+"_="+N:"")}}(c.data&&c.hasContent&&c.contentType!==!1||n.contentType)&&x.setRequestHeader("Content-Type",c.contentType),c.ifModified&&(r=r||c.url,v.lastModified[r]&&x.setRequestHeader("If-Modified-Since",v.lastModified[r]),v.etag[r]&&x.setRequestHeader("If-None-Match",v.etag[r])),x.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+(c.dataTypes[0]!=="*"?", "+Tn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)x.setRequestHeader(l,c.headers[l]);if(!c.beforeSend||c.beforeSend.call(h,x,c)!==!1&&E!==2){S="abort";for(l in{success:1,error:1,complete:1})x[l](c[l]);o=kn(xn,c,n,x);if(!o)T(-1,"No Transport");else{x.readyState=1,f&&p.trigger("ajaxSend",[x,c]),c.async&&c.timeout>0&&(u=setTimeout(function(){x.abort("timeout")},c.timeout));try{E=1,o.send(b,T)}catch(k){if(!(E<2))throw k;T(-1,k)}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var Mn=[],_n=/\?/,Dn=/(=)\?(?=&|$)|\?\?/,Pn=v.now();v.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Mn.pop()||v.expando+"_"+Pn++;return this[e]=!0,e}}),v.ajaxPrefilter("json jsonp",function(n,r,i){var s,o,u,a=n.data,f=n.url,l=n.jsonp!==!1,c=l&&Dn.test(f),h=l&&!c&&typeof a=="string"&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Dn.test(a);if(n.dataTypes[0]==="jsonp"||c||h)return s=n.jsonpCallback=v.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,o=e[s],c?n.url=f.replace(Dn,"$1"+s):h?n.data=a.replace(Dn,"$1"+s):l&&(n.url+=(_n.test(f)?"&":"?")+n.jsonp+"="+s),n.converters["script json"]=function(){return u||v.error(s+" was not called"),u[0]},n.dataTypes[0]="json",e[s]=function(){u=arguments},i.always(function(){e[s]=o,n[s]&&(n.jsonpCallback=r.jsonpCallback,Mn.push(s)),u&&v.isFunction(o)&&o(u[0]),u=o=t}),"script"}),v.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(e){return v.globalEval(e),e}}}),v.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),v.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=i.head||i.getElementsByTagName("head")[0]||i.documentElement;return{send:function(s,o){n=i.createElement("script"),n.async="async",e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,i){if(i||!n.readyState||/loaded|complete/.test(n.readyState))n.onload=n.onreadystatechange=null,r&&n.parentNode&&r.removeChild(n),n=t,i||o(200,"success")},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(0,1)}}}});var Hn,Bn=e.ActiveXObject?function(){for(var e in Hn)Hn[e](0,1)}:!1,jn=0;v.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&Fn()||In()}:Fn,function(e){v.extend(v.support,{ajax:!!e,cors:!!e&&"withCredentials"in e})}(v.ajaxSettings.xhr()),v.support.ajax&&v.ajaxTransport(function(n){if(!n.crossDomain||v.support.cors){var r;return{send:function(i,s){var o,u,a=n.xhr();n.username?a.open(n.type,n.url,n.async,n.username,n.password):a.open(n.type,n.url,n.async);if(n.xhrFields)for(u in n.xhrFields)a[u]=n.xhrFields[u];n.mimeType&&a.overrideMimeType&&a.overrideMimeType(n.mimeType),!n.crossDomain&&!i["X-Requested-With"]&&(i["X-Requested-With"]="XMLHttpRequest");try{for(u in i)a.setRequestHeader(u,i[u])}catch(f){}a.send(n.hasContent&&n.data||null),r=function(e,i){var u,f,l,c,h;try{if(r&&(i||a.readyState===4)){r=t,o&&(a.onreadystatechange=v.noop,Bn&&delete Hn[o]);if(i)a.readyState!==4&&a.abort();else{u=a.status,l=a.getAllResponseHeaders(),c={},h=a.responseXML,h&&h.documentElement&&(c.xml=h);try{c.text=a.responseText}catch(p){}try{f=a.statusText}catch(p){f=""}!u&&n.isLocal&&!n.crossDomain?u=c.text?200:404:u===1223&&(u=204)}}}catch(d){i||s(-1,d)}c&&s(u,f,c,l)},n.async?a.readyState===4?setTimeout(r,0):(o=++jn,Bn&&(Hn||(Hn={},v(e).unload(Bn)),Hn[o]=r),a.onreadystatechange=r):r()},abort:function(){r&&r(0,1)}}}});var qn,Rn,Un=/^(?:toggle|show|hide)$/,zn=new RegExp("^(?:([-+])=|)("+m+")([a-z%]*)$","i"),Wn=/queueHooks$/,Xn=[Gn],Vn={"*":[function(e,t){var n,r,i=this.createTween(e,t),s=zn.exec(t),o=i.cur(),u=+o||0,a=1,f=20;if(s){n=+s[2],r=s[3]||(v.cssNumber[e]?"":"px");if(r!=="px"&&u){u=v.css(i.elem,e,!0)||n||1;do a=a||".5",u/=a,v.style(i.elem,e,u+r);while(a!==(a=i.cur()/o)&&a!==1&&--f)}i.unit=r,i.start=u,i.end=s[1]?u+(s[1]+1)*n:n}return i}]};v.Animation=v.extend(Kn,{tweener:function(e,t){v.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;r<i;r++)n=e[r],Vn[n]=Vn[n]||[],Vn[n].unshift(t)},prefilter:function(e,t){t?Xn.unshift(e):Xn.push(e)}}),v.Tween=Yn,Yn.prototype={constructor:Yn,init:function(e,t,n,r,i,s){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=s||(v.cssNumber[n]?"":"px")},cur:function(){var e=Yn.propHooks[this.prop];return e&&e.get?e.get(this):Yn.propHooks._default.get(this)},run:function(e){var t,n=Yn.propHooks[this.prop];return this.options.duration?this.pos=t=v.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):Yn.propHooks._default.set(this),this}},Yn.prototype.init.prototype=Yn.prototype,Yn.propHooks={_default:{get:function(e){var t;return e.elem[e.prop]==null||!!e.elem.style&&e.elem.style[e.prop]!=null?(t=v.css(e.elem,e.prop,!1,""),!t||t==="auto"?0:t):e.elem[e.prop]},set:function(e){v.fx.step[e.prop]?v.fx.step[e.prop](e):e.elem.style&&(e.elem.style[v.cssProps[e.prop]]!=null||v.cssHooks[e.prop])?v.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},Yn.propHooks.scrollTop=Yn.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},v.each(["toggle","show","hide"],function(e,t){var n=v.fn[t];v.fn[t]=function(r,i,s){return r==null||typeof r=="boolean"||!e&&v.isFunction(r)&&v.isFunction(i)?n.apply(this,arguments):this.animate(Zn(t,!0),r,i,s)}}),v.fn.extend({fadeTo:function(e,t,n,r){return this.filter(Gt).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=v.isEmptyObject(e),s=v.speed(t,n,r),o=function(){var t=Kn(this,v.extend({},e),s);i&&t.stop(!0)};return i||s.queue===!1?this.each(o):this.queue(s.queue,o)},stop:function(e,n,r){var i=function(e){var t=e.stop;delete e.stop,t(r)};return typeof e!="string"&&(r=n,n=e,e=t),n&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,n=e!=null&&e+"queueHooks",s=v.timers,o=v._data(this);if(n)o[n]&&o[n].stop&&i(o[n]);else for(n in o)o[n]&&o[n].stop&&Wn.test(n)&&i(o[n]);for(n=s.length;n--;)s[n].elem===this&&(e==null||s[n].queue===e)&&(s[n].anim.stop(r),t=!1,s.splice(n,1));(t||!r)&&v.dequeue(this,e)})}}),v.each({slideDown:Zn("show"),slideUp:Zn("hide"),slideToggle:Zn("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){v.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),v.speed=function(e,t,n){var r=e&&typeof e=="object"?v.extend({},e):{complete:n||!n&&t||v.isFunction(e)&&e,duration:e,easing:n&&t||t&&!v.isFunction(t)&&t};r.duration=v.fx.off?0:typeof r.duration=="number"?r.duration:r.duration in v.fx.speeds?v.fx.speeds[r.duration]:v.fx.speeds._default;if(r.queue==null||r.queue===!0)r.queue="fx";return r.old=r.complete,r.complete=function(){v.isFunction(r.old)&&r.old.call(this),r.queue&&v.dequeue(this,r.queue)},r},v.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},v.timers=[],v.fx=Yn.prototype.init,v.fx.tick=function(){var e,n=v.timers,r=0;qn=v.now();for(;r<n.length;r++)e=n[r],!e()&&n[r]===e&&n.splice(r--,1);n.length||v.fx.stop(),qn=t},v.fx.timer=function(e){e()&&v.timers.push(e)&&!Rn&&(Rn=setInterval(v.fx.tick,v.fx.interval))},v.fx.interval=13,v.fx.stop=function(){clearInterval(Rn),Rn=null},v.fx.speeds={slow:600,fast:200,_default:400},v.fx.step={},v.expr&&v.expr.filters&&(v.expr.filters.animated=function(e){return v.grep(v.timers,function(t){return e===t.elem}).length});var er=/^(?:body|html)$/i;v.fn.offset=function(e){if(arguments.length)return e===t?this:this.each(function(t){v.offset.setOffset(this,e,t)});var n,r,i,s,o,u,a,f={top:0,left:0},l=this[0],c=l&&l.ownerDocument;if(!c)return;return(r=c.body)===l?v.offset.bodyOffset(l):(n=c.documentElement,v.contains(n,l)?(typeof l.getBoundingClientRect!="undefined"&&(f=l.getBoundingClientRect()),i=tr(c),s=n.clientTop||r.clientTop||0,o=n.clientLeft||r.clientLeft||0,u=i.pageYOffset||n.scrollTop,a=i.pageXOffset||n.scrollLeft,{top:f.top+u-s,left:f.left+a-o}):f)},v.offset={bodyOffset:function(e){var t=e.offsetTop,n=e.offsetLeft;return v.support.doesNotIncludeMarginInBodyOffset&&(t+=parseFloat(v.css(e,"marginTop"))||0,n+=parseFloat(v.css(e,"marginLeft"))||0),{top:t,left:n}},setOffset:function(e,t,n){var r=v.css(e,"position");r==="static"&&(e.style.position="relative");var i=v(e),s=i.offset(),o=v.css(e,"top"),u=v.css(e,"left"),a=(r==="absolute"||r==="fixed")&&v.inArray("auto",[o,u])>-1,f={},l={},c,h;a?(l=i.position(),c=l.top,h=l.left):(c=parseFloat(o)||0,h=parseFloat(u)||0),v.isFunction(t)&&(t=t.call(e,n,s)),t.top!=null&&(f.top=t.top-s.top+c),t.left!=null&&(f.left=t.left-s.left+h),"using"in t?t.using.call(e,f):i.css(f)}},v.fn.extend({position:function(){if(!this[0])return;var e=this[0],t=this.offsetParent(),n=this.offset(),r=er.test(t[0].nodeName)?{top:0,left:0}:t.offset();return n.top-=parseFloat(v.css(e,"marginTop"))||0,n.left-=parseFloat(v.css(e,"marginLeft"))||0,r.top+=parseFloat(v.css(t[0],"borderTopWidth"))||0,r.left+=parseFloat(v.css(t[0],"borderLeftWidth"))||0,{top:n.top-r.top,left:n.left-r.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||i.body;while(e&&!er.test(e.nodeName)&&v.css(e,"position")==="static")e=e.offsetParent;return e||i.body})}}),v.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);v.fn[e]=function(i){return v.access(this,function(e,i,s){var o=tr(e);if(s===t)return o?n in o?o[n]:o.document.documentElement[i]:e[i];o?o.scrollTo(r?v(o).scrollLeft():s,r?s:v(o).scrollTop()):e[i]=s},e,i,arguments.length,null)}}),v.each({Height:"height",Width:"width"},function(e,n){v.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){v.fn[i]=function(i,s){var o=arguments.length&&(r||typeof i!="boolean"),u=r||(i===!0||s===!0?"margin":"border");return v.access(this,function(n,r,i){var s;return v.isWindow(n)?n.document.documentElement["client"+e]:n.nodeType===9?(s=n.documentElement,Math.max(n.body["scroll"+e],s["scroll"+e],n.body["offset"+e],s["offset"+e],s["client"+e])):i===t?v.css(n,r,i,u):v.style(n,r,i,u)},n,o?i:t,o,null)}})}),e.jQuery=e.$=v,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return v})})(window); \ No newline at end of file diff --git a/COGNET/lib/sprintf.js b/COGNET/lib/sprintf.js new file mode 100644 index 0000000000000000000000000000000000000000..019324e5d299899d9636ba9656c27ef1925b93f9 --- /dev/null +++ b/COGNET/lib/sprintf.js @@ -0,0 +1,134 @@ +/*! sprintf.js | Copyright (c) 2007-2013 Alexandru Marasteanu <hello at alexei dot ro> | 3 clause BSD license */ + +(function(ctx) { + var sprintf = function() { + if (!sprintf.cache.hasOwnProperty(arguments[0])) { + sprintf.cache[arguments[0]] = sprintf.parse(arguments[0]); + } + return sprintf.format.call(null, sprintf.cache[arguments[0]], arguments); + }; + + sprintf.format = function(parse_tree, argv) { + var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length; + for (i = 0; i < tree_length; i++) { + node_type = get_type(parse_tree[i]); + if (node_type === 'string') { + output.push(parse_tree[i]); + } + else if (node_type === 'array') { + match = parse_tree[i]; // convenience purposes only + if (match[2]) { // keyword argument + arg = argv[cursor]; + for (k = 0; k < match[2].length; k++) { + if (!arg.hasOwnProperty(match[2][k])) { + throw(sprintf('[sprintf] property "%s" does not exist', match[2][k])); + } + arg = arg[match[2][k]]; + } + } + else if (match[1]) { // positional argument (explicit) + arg = argv[match[1]]; + } + else { // positional argument (implicit) + arg = argv[cursor++]; + } + + if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) { + throw(sprintf('[sprintf] expecting number but found %s', get_type(arg))); + } + switch (match[8]) { + case 'b': arg = arg.toString(2); break; + case 'c': arg = String.fromCharCode(arg); break; + case 'd': arg = parseInt(arg, 10); break; + case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break; + case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break; + case 'o': arg = arg.toString(8); break; + case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break; + case 'u': arg = arg >>> 0; break; + case 'x': arg = arg.toString(16); break; + case 'X': arg = arg.toString(16).toUpperCase(); break; + } + arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg); + pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' '; + pad_length = match[6] - String(arg).length; + pad = match[6] ? str_repeat(pad_character, pad_length) : ''; + output.push(match[5] ? arg + pad : pad + arg); + } + } + return output.join(''); + }; + + sprintf.cache = {}; + + sprintf.parse = function(fmt) { + var _fmt = fmt, match = [], parse_tree = [], arg_names = 0; + while (_fmt) { + if ((match = /^[^\x25]+/.exec(_fmt)) !== null) { + parse_tree.push(match[0]); + } + else if ((match = /^\x25{2}/.exec(_fmt)) !== null) { + parse_tree.push('%'); + } + else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) { + if (match[2]) { + arg_names |= 1; + var field_list = [], replacement_field = match[2], field_match = []; + if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) { + field_list.push(field_match[1]); + while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') { + if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) { + field_list.push(field_match[1]); + } + else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) { + field_list.push(field_match[1]); + } + else { + throw('[sprintf] huh?'); + } + } + } + else { + throw('[sprintf] huh?'); + } + match[2] = field_list; + } + else { + arg_names |= 2; + } + if (arg_names === 3) { + throw('[sprintf] mixing positional and named placeholders is not (yet) supported'); + } + parse_tree.push(match); + } + else { + throw('[sprintf] huh?'); + } + _fmt = _fmt.substring(match[0].length); + } + return parse_tree; + }; + + var vsprintf = function(fmt, argv, _argv) { + _argv = argv.slice(0); + _argv.splice(0, 0, fmt); + return sprintf.apply(null, _argv); + }; + + /** + * helpers + */ + function get_type(variable) { + return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase(); + } + + function str_repeat(input, multiplier) { + for (var output = []; multiplier > 0; output[--multiplier] = input) {/* do nothing */} + return output.join(''); + } + + /** + * export to either browser or node.js + */ + ctx.sprintf = sprintf; + ctx.vsprintf = vsprintf; +})(typeof exports != "undefined" ? exports : window); \ No newline at end of file diff --git a/COGNET/lib/stats.min.js b/COGNET/lib/stats.min.js new file mode 100644 index 0000000000000000000000000000000000000000..bddd408a3d4e6a57679ccfd6f7cb7db8e673f883 --- /dev/null +++ b/COGNET/lib/stats.min.js @@ -0,0 +1,6 @@ +// stats.js - http://github.com/mrdoob/stats.js +export var Stats=function(){var l=Date.now(),m=l,g=0,n=Infinity,o=0,h=0,p=Infinity,q=0,r=0,s=0,f=document.createElement("div");f.id="stats";f.addEventListener("mousedown",function(b){b.preventDefault();t(++s%2)},!1);f.style.cssText="width:80px;opacity:0.9;cursor:pointer";var a=document.createElement("div");a.id="fps";a.style.cssText="padding:0 0 3px 3px;text-align:left;background-color:#002";f.appendChild(a);var i=document.createElement("div");i.id="fpsText";i.style.cssText="color:#0ff;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px"; +i.innerHTML="FPS";a.appendChild(i);var c=document.createElement("div");c.id="fpsGraph";c.style.cssText="position:relative;width:74px;height:30px;background-color:#0ff";for(a.appendChild(c);74>c.children.length;){var j=document.createElement("span");j.style.cssText="width:1px;height:30px;float:left;background-color:#113";c.appendChild(j)}var d=document.createElement("div");d.id="ms";d.style.cssText="padding:0 0 3px 3px;text-align:left;background-color:#020;display:none";f.appendChild(d);var k=document.createElement("div"); +k.id="msText";k.style.cssText="color:#0f0;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px";k.innerHTML="MS";d.appendChild(k);var e=document.createElement("div");e.id="msGraph";e.style.cssText="position:relative;width:74px;height:30px;background-color:#0f0";for(d.appendChild(e);74>e.children.length;)j=document.createElement("span"),j.style.cssText="width:1px;height:30px;float:left;background-color:#131",e.appendChild(j);var t=function(b){s=b;switch(s){case 0:a.style.display= +"block";d.style.display="none";break;case 1:a.style.display="none",d.style.display="block"}};return{REVISION:11,domElement:f,setMode:t,begin:function(){l=Date.now()},end:function(){var b=Date.now();g=b-l;n=Math.min(n,g);o=Math.max(o,g);k.textContent=g+" MS ("+n+"-"+o+")";var a=Math.min(30,30-30*(g/200));e.appendChild(e.firstChild).style.height=a+"px";r++;b>m+1E3&&(h=Math.round(1E3*r/(b-m)),p=Math.min(p,h),q=Math.max(q,h),i.textContent=h+" FPS ("+p+"-"+q+")",a=Math.min(30,30-30*(h/100)),c.appendChild(c.firstChild).style.height= +a+"px",m=b,r=0);return b},update:function(){l=this.end()}}}; diff --git a/COGNET/lib/three.js b/COGNET/lib/three.js new file mode 100644 index 0000000000000000000000000000000000000000..2d01d65b3115898c1d2f9510b8718acc9db884e6 --- /dev/null +++ b/COGNET/lib/three.js @@ -0,0 +1,35996 @@ +/** + * @author mrdoob / http://mrdoob.com/ + * @author Larry Battle / http://bateru.com/news + */ + +var THREE = THREE || { REVISION: '56' }; + +self.console = self.console || { + + info: function () {}, + log: function () {}, + debug: function () {}, + warn: function () {}, + error: function () {} + +}; + +self.Int32Array = self.Int32Array || Array; +self.Float32Array = self.Float32Array || Array; + +String.prototype.trim = String.prototype.trim || function () { + + return this.replace( /^\s+|\s+$/g, '' ); + +}; + +// based on https://github.com/documentcloud/underscore/blob/bf657be243a075b5e72acc8a83e6f12a564d8f55/underscore.js#L767 +THREE.extend = function ( obj, source ) { + + // ECMAScript5 compatibility based on: http://www.nczonline.net/blog/2012/12/11/are-your-mixins-ecmascript-5-compatible/ + if ( Object.keys ) { + + var keys = Object.keys( source ); + + for (var i = 0, il = keys.length; i < il; i++) { + + var prop = keys[i]; + Object.defineProperty( obj, prop, Object.getOwnPropertyDescriptor( source, prop ) ); + + } + + } else { + + var safeHasOwnProperty = {}.hasOwnProperty; + + for ( var prop in source ) { + + if ( safeHasOwnProperty.call( source, prop ) ) { + + obj[prop] = source[prop]; + + } + + } + + } + + return obj; + +}; + +// http://paulirish.com/2011/requestanimationframe-for-smart-animating/ +// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating + +// requestAnimationFrame polyfill by Erik M�ller +// fixes from Paul Irish and Tino Zijdel + +( function () { + + var lastTime = 0; + var vendors = [ 'ms', 'moz', 'webkit', 'o' ]; + + for ( var x = 0; x < vendors.length && !window.requestAnimationFrame; ++ x ) { + + window.requestAnimationFrame = window[ vendors[ x ] + 'RequestAnimationFrame' ]; + window.cancelAnimationFrame = window[ vendors[ x ] + 'CancelAnimationFrame' ] || window[ vendors[ x ] + 'CancelRequestAnimationFrame' ]; + + } + + if ( window.requestAnimationFrame === undefined ) { + + window.requestAnimationFrame = function ( callback ) { + + var currTime = Date.now(), timeToCall = Math.max( 0, 16 - ( currTime - lastTime ) ); + var id = window.setTimeout( function() { callback( currTime + timeToCall ); }, timeToCall ); + lastTime = currTime + timeToCall; + return id; + + }; + + } + + window.cancelAnimationFrame = window.cancelAnimationFrame || function ( id ) { window.clearTimeout( id ) }; + +}() ); + +// GL STATE CONSTANTS + +THREE.CullFaceNone = 0; +THREE.CullFaceBack = 1; +THREE.CullFaceFront = 2; +THREE.CullFaceFrontBack = 3; + +THREE.FrontFaceDirectionCW = 0; +THREE.FrontFaceDirectionCCW = 1; + +// SHADOWING TYPES + +THREE.BasicShadowMap = 0; +THREE.PCFShadowMap = 1; +THREE.PCFSoftShadowMap = 2; + +// MATERIAL CONSTANTS + +// side + +THREE.FrontSide = 0; +THREE.BackSide = 1; +THREE.DoubleSide = 2; + +// shading + +THREE.NoShading = 0; +THREE.FlatShading = 1; +THREE.SmoothShading = 2; + +// colors + +THREE.NoColors = 0; +THREE.FaceColors = 1; +THREE.VertexColors = 2; + +// blending modes + +THREE.NoBlending = 0; +THREE.NormalBlending = 1; +THREE.AdditiveBlending = 2; +THREE.SubtractiveBlending = 3; +THREE.MultiplyBlending = 4; +THREE.CustomBlending = 5; + +// custom blending equations +// (numbers start from 100 not to clash with other +// mappings to OpenGL constants defined in Texture.js) + +THREE.AddEquation = 100; +THREE.SubtractEquation = 101; +THREE.ReverseSubtractEquation = 102; + +// custom blending destination factors + +THREE.ZeroFactor = 200; +THREE.OneFactor = 201; +THREE.SrcColorFactor = 202; +THREE.OneMinusSrcColorFactor = 203; +THREE.SrcAlphaFactor = 204; +THREE.OneMinusSrcAlphaFactor = 205; +THREE.DstAlphaFactor = 206; +THREE.OneMinusDstAlphaFactor = 207; + +// custom blending source factors + +//THREE.ZeroFactor = 200; +//THREE.OneFactor = 201; +//THREE.SrcAlphaFactor = 204; +//THREE.OneMinusSrcAlphaFactor = 205; +//THREE.DstAlphaFactor = 206; +//THREE.OneMinusDstAlphaFactor = 207; +THREE.DstColorFactor = 208; +THREE.OneMinusDstColorFactor = 209; +THREE.SrcAlphaSaturateFactor = 210; + + +// TEXTURE CONSTANTS + +THREE.MultiplyOperation = 0; +THREE.MixOperation = 1; +THREE.AddOperation = 2; + +// Mapping modes + +THREE.UVMapping = function () {}; + +THREE.CubeReflectionMapping = function () {}; +THREE.CubeRefractionMapping = function () {}; + +THREE.SphericalReflectionMapping = function () {}; +THREE.SphericalRefractionMapping = function () {}; + +// Wrapping modes + +THREE.RepeatWrapping = 1000; +THREE.ClampToEdgeWrapping = 1001; +THREE.MirroredRepeatWrapping = 1002; + +// Filters + +THREE.NearestFilter = 1003; +THREE.NearestMipMapNearestFilter = 1004; +THREE.NearestMipMapLinearFilter = 1005; +THREE.LinearFilter = 1006; +THREE.LinearMipMapNearestFilter = 1007; +THREE.LinearMipMapLinearFilter = 1008; + +// Data types + +THREE.UnsignedByteType = 1009; +THREE.ByteType = 1010; +THREE.ShortType = 1011; +THREE.UnsignedShortType = 1012; +THREE.IntType = 1013; +THREE.UnsignedIntType = 1014; +THREE.FloatType = 1015; + +// Pixel types + +//THREE.UnsignedByteType = 1009; +THREE.UnsignedShort4444Type = 1016; +THREE.UnsignedShort5551Type = 1017; +THREE.UnsignedShort565Type = 1018; + +// Pixel formats + +THREE.AlphaFormat = 1019; +THREE.RGBFormat = 1020; +THREE.RGBAFormat = 1021; +THREE.LuminanceFormat = 1022; +THREE.LuminanceAlphaFormat = 1023; + +// Compressed texture formats + +THREE.RGB_S3TC_DXT1_Format = 2001; +THREE.RGBA_S3TC_DXT1_Format = 2002; +THREE.RGBA_S3TC_DXT3_Format = 2003; +THREE.RGBA_S3TC_DXT5_Format = 2004; + +/* +// Potential future PVRTC compressed texture formats +THREE.RGB_PVRTC_4BPPV1_Format = 2100; +THREE.RGB_PVRTC_2BPPV1_Format = 2101; +THREE.RGBA_PVRTC_4BPPV1_Format = 2102; +THREE.RGBA_PVRTC_2BPPV1_Format = 2103; +*/ +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.Color = function ( value ) { + + if ( value !== undefined ) this.set( value ); + + return this; + +}; + +THREE.extend( THREE.Color.prototype, { + + r: 1, g: 1, b: 1, + + set: function ( value ) { + + switch ( typeof value ) { + + case "number": + this.setHex( value ); + break; + + case "string": + this.setStyle( value ); + break; + + } + + }, + + setHex: function ( hex ) { + + hex = Math.floor( hex ); + + this.r = ( hex >> 16 & 255 ) / 255; + this.g = ( hex >> 8 & 255 ) / 255; + this.b = ( hex & 255 ) / 255; + + return this; + + }, + + setRGB: function ( r, g, b ) { + + this.r = r; + this.g = g; + this.b = b; + + return this; + + }, + + setHSV: function ( h, s, v ) { + + console.log( 'DEPRECATED: Color\'s .setHSV() will be removed. Use .setHSL( h, s, l ) instead.' ); + return this.setHSL(h,s*v/((h=(2-s)*v)<1?h:2-h),h/2); // https://gist.github.com/xpansive/1337890 + + }, + + setHSL: function ( h, s, l ) { + + // h,s,l ranges are in 0.0 - 1.0 + + if ( s === 0 ) { + + this.r = this.g = this.b = l; + + } else { + + var hue2rgb = function ( p, q, t ) { + + if ( t < 0 ) t += 1; + if ( t > 1 ) t -= 1; + if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t; + if ( t < 1 / 2 ) return q; + if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t ); + return p; + + }; + + var p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s ); + var q = ( 2 * l ) - p; + + this.r = hue2rgb( q, p, h + 1 / 3 ); + this.g = hue2rgb( q, p, h ); + this.b = hue2rgb( q, p, h - 1 / 3 ); + + } + + return this; + + }, + + setStyle: function ( style ) { + + // rgb(255,0,0) + + if ( /^rgb\((\d+),(\d+),(\d+)\)$/i.test( style ) ) { + + var color = /^rgb\((\d+),(\d+),(\d+)\)$/i.exec( style ); + + this.r = Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255; + this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255; + this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255; + + return this; + + } + + // rgb(100%,0%,0%) + + if ( /^rgb\((\d+)\%,(\d+)\%,(\d+)\%\)$/i.test( style ) ) { + + var color = /^rgb\((\d+)\%,(\d+)\%,(\d+)\%\)$/i.exec( style ); + + this.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100; + this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100; + this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100; + + return this; + + } + + // #ff0000 + + if ( /^\#([0-9a-f]{6})$/i.test( style ) ) { + + var color = /^\#([0-9a-f]{6})$/i.exec( style ); + + this.setHex( parseInt( color[ 1 ], 16 ) ); + + return this; + + } + + // #f00 + + if ( /^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.test( style ) ) { + + var color = /^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec( style ); + + this.setHex( parseInt( color[ 1 ] + color[ 1 ] + color[ 2 ] + color[ 2 ] + color[ 3 ] + color[ 3 ], 16 ) ); + + return this; + + } + + // red + + if ( /^(\w+)$/i.test( style ) ) { + + this.setHex( THREE.ColorKeywords[ style ] ); + + return this; + + } + + + }, + + copy: function ( color ) { + + this.r = color.r; + this.g = color.g; + this.b = color.b; + + return this; + + }, + + copyGammaToLinear: function ( color ) { + + this.r = color.r * color.r; + this.g = color.g * color.g; + this.b = color.b * color.b; + + return this; + + }, + + copyLinearToGamma: function ( color ) { + + this.r = Math.sqrt( color.r ); + this.g = Math.sqrt( color.g ); + this.b = Math.sqrt( color.b ); + + return this; + + }, + + convertGammaToLinear: function () { + + var r = this.r, g = this.g, b = this.b; + + this.r = r * r; + this.g = g * g; + this.b = b * b; + + return this; + + }, + + convertLinearToGamma: function () { + + this.r = Math.sqrt( this.r ); + this.g = Math.sqrt( this.g ); + this.b = Math.sqrt( this.b ); + + return this; + + }, + + getHex: function () { + + return ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0; + + }, + + getHexString: function () { + + return ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 ); + + }, + + getHSL: function () { + + var hsl = { h: 0, s: 0, l: 0 }; + + return function () { + + // h,s,l ranges are in 0.0 - 1.0 + + var r = this.r, g = this.g, b = this.b; + + var max = Math.max( r, g, b ); + var min = Math.min( r, g, b ); + + var hue, saturation; + var lightness = ( min + max ) / 2.0; + + if ( min === max ) { + + hue = 0; + saturation = 0; + + } else { + + var delta = max - min; + + saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min ); + + switch ( max ) { + + case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break; + case g: hue = ( b - r ) / delta + 2; break; + case b: hue = ( r - g ) / delta + 4; break; + + } + + hue /= 6; + + } + + hsl.h = hue; + hsl.s = saturation; + hsl.l = lightness; + + return hsl; + + }; + + }(), + + getStyle: function () { + + return 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')'; + + }, + + offsetHSL: function ( h, s, l ) { + + var hsl = this.getHSL(); + + hsl.h += h; hsl.s += s; hsl.l += l; + + this.setHSL( hsl.h, hsl.s, hsl.l ); + + return this; + + }, + + add: function ( color ) { + + this.r += color.r; + this.g += color.g; + this.b += color.b; + + return this; + + }, + + addColors: function ( color1, color2 ) { + + this.r = color1.r + color2.r; + this.g = color1.g + color2.g; + this.b = color1.b + color2.b; + + return this; + + }, + + addScalar: function ( s ) { + + this.r += s; + this.g += s; + this.b += s; + + return this; + + }, + + multiply: function ( color ) { + + this.r *= color.r; + this.g *= color.g; + this.b *= color.b; + + return this; + + }, + + multiplyScalar: function ( s ) { + + this.r *= s; + this.g *= s; + this.b *= s; + + return this; + + }, + + lerp: function ( color, alpha ) { + + this.r += ( color.r - this.r ) * alpha; + this.g += ( color.g - this.g ) * alpha; + this.b += ( color.b - this.b ) * alpha; + + return this; + + }, + + clone: function () { + + return new THREE.Color().setRGB( this.r, this.g, this.b ); + + } + +} ); + +THREE.ColorKeywords = { "aliceblue": 0xF0F8FF, "antiquewhite": 0xFAEBD7, "aqua": 0x00FFFF, "aquamarine": 0x7FFFD4, "azure": 0xF0FFFF, +"beige": 0xF5F5DC, "bisque": 0xFFE4C4, "black": 0x000000, "blanchedalmond": 0xFFEBCD, "blue": 0x0000FF, "blueviolet": 0x8A2BE2, +"brown": 0xA52A2A, "burlywood": 0xDEB887, "cadetblue": 0x5F9EA0, "chartreuse": 0x7FFF00, "chocolate": 0xD2691E, "coral": 0xFF7F50, +"cornflowerblue": 0x6495ED, "cornsilk": 0xFFF8DC, "crimson": 0xDC143C, "cyan": 0x00FFFF, "darkblue": 0x00008B, "darkcyan": 0x008B8B, +"darkgoldenrod": 0xB8860B, "darkgray": 0xA9A9A9, "darkgreen": 0x006400, "darkgrey": 0xA9A9A9, "darkkhaki": 0xBDB76B, "darkmagenta": 0x8B008B, +"darkolivegreen": 0x556B2F, "darkorange": 0xFF8C00, "darkorchid": 0x9932CC, "darkred": 0x8B0000, "darksalmon": 0xE9967A, "darkseagreen": 0x8FBC8F, +"darkslateblue": 0x483D8B, "darkslategray": 0x2F4F4F, "darkslategrey": 0x2F4F4F, "darkturquoise": 0x00CED1, "darkviolet": 0x9400D3, +"deeppink": 0xFF1493, "deepskyblue": 0x00BFFF, "dimgray": 0x696969, "dimgrey": 0x696969, "dodgerblue": 0x1E90FF, "firebrick": 0xB22222, +"floralwhite": 0xFFFAF0, "forestgreen": 0x228B22, "fuchsia": 0xFF00FF, "gainsboro": 0xDCDCDC, "ghostwhite": 0xF8F8FF, "gold": 0xFFD700, +"goldenrod": 0xDAA520, "gray": 0x808080, "green": 0x008000, "greenyellow": 0xADFF2F, "grey": 0x808080, "honeydew": 0xF0FFF0, "hotpink": 0xFF69B4, +"indianred": 0xCD5C5C, "indigo": 0x4B0082, "ivory": 0xFFFFF0, "khaki": 0xF0E68C, "lavender": 0xE6E6FA, "lavenderblush": 0xFFF0F5, "lawngreen": 0x7CFC00, +"lemonchiffon": 0xFFFACD, "lightblue": 0xADD8E6, "lightcoral": 0xF08080, "lightcyan": 0xE0FFFF, "lightgoldenrodyellow": 0xFAFAD2, "lightgray": 0xD3D3D3, +"lightgreen": 0x90EE90, "lightgrey": 0xD3D3D3, "lightpink": 0xFFB6C1, "lightsalmon": 0xFFA07A, "lightseagreen": 0x20B2AA, "lightskyblue": 0x87CEFA, +"lightslategray": 0x778899, "lightslategrey": 0x778899, "lightsteelblue": 0xB0C4DE, "lightyellow": 0xFFFFE0, "lime": 0x00FF00, "limegreen": 0x32CD32, +"linen": 0xFAF0E6, "magenta": 0xFF00FF, "maroon": 0x800000, "mediumaquamarine": 0x66CDAA, "mediumblue": 0x0000CD, "mediumorchid": 0xBA55D3, +"mediumpurple": 0x9370DB, "mediumseagreen": 0x3CB371, "mediumslateblue": 0x7B68EE, "mediumspringgreen": 0x00FA9A, "mediumturquoise": 0x48D1CC, +"mediumvioletred": 0xC71585, "midnightblue": 0x191970, "mintcream": 0xF5FFFA, "mistyrose": 0xFFE4E1, "moccasin": 0xFFE4B5, "navajowhite": 0xFFDEAD, +"navy": 0x000080, "oldlace": 0xFDF5E6, "olive": 0x808000, "olivedrab": 0x6B8E23, "orange": 0xFFA500, "orangered": 0xFF4500, "orchid": 0xDA70D6, +"palegoldenrod": 0xEEE8AA, "palegreen": 0x98FB98, "paleturquoise": 0xAFEEEE, "palevioletred": 0xDB7093, "papayawhip": 0xFFEFD5, "peachpuff": 0xFFDAB9, +"peru": 0xCD853F, "pink": 0xFFC0CB, "plum": 0xDDA0DD, "powderblue": 0xB0E0E6, "purple": 0x800080, "red": 0xFF0000, "rosybrown": 0xBC8F8F, +"royalblue": 0x4169E1, "saddlebrown": 0x8B4513, "salmon": 0xFA8072, "sandybrown": 0xF4A460, "seagreen": 0x2E8B57, "seashell": 0xFFF5EE, +"sienna": 0xA0522D, "silver": 0xC0C0C0, "skyblue": 0x87CEEB, "slateblue": 0x6A5ACD, "slategray": 0x708090, "slategrey": 0x708090, "snow": 0xFFFAFA, +"springgreen": 0x00FF7F, "steelblue": 0x4682B4, "tan": 0xD2B48C, "teal": 0x008080, "thistle": 0xD8BFD8, "tomato": 0xFF6347, "turquoise": 0x40E0D0, +"violet": 0xEE82EE, "wheat": 0xF5DEB3, "white": 0xFFFFFF, "whitesmoke": 0xF5F5F5, "yellow": 0xFFFF00, "yellowgreen": 0x9ACD32 }; +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + * @author WestLangley / http://github.com/WestLangley + * @author bhouston / http://exocortex.com + */ + +THREE.Quaternion = function( x, y, z, w ) { + + this.x = x || 0; + this.y = y || 0; + this.z = z || 0; + this.w = ( w !== undefined ) ? w : 1; + +}; + +THREE.extend( THREE.Quaternion.prototype, { + + set: function ( x, y, z, w ) { + + this.x = x; + this.y = y; + this.z = z; + this.w = w; + + return this; + + }, + + copy: function ( q ) { + + this.x = q.x; + this.y = q.y; + this.z = q.z; + this.w = q.w; + + return this; + + }, + + setFromEuler: function ( v, order ) { + + // http://www.mathworks.com/matlabcentral/fileexchange/ + // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ + // content/SpinCalc.m + + var c1 = Math.cos( v.x / 2 ); + var c2 = Math.cos( v.y / 2 ); + var c3 = Math.cos( v.z / 2 ); + var s1 = Math.sin( v.x / 2 ); + var s2 = Math.sin( v.y / 2 ); + var s3 = Math.sin( v.z / 2 ); + + if ( order === undefined || order === 'XYZ' ) { + + this.x = s1 * c2 * c3 + c1 * s2 * s3; + this.y = c1 * s2 * c3 - s1 * c2 * s3; + this.z = c1 * c2 * s3 + s1 * s2 * c3; + this.w = c1 * c2 * c3 - s1 * s2 * s3; + + } else if ( order === 'YXZ' ) { + + this.x = s1 * c2 * c3 + c1 * s2 * s3; + this.y = c1 * s2 * c3 - s1 * c2 * s3; + this.z = c1 * c2 * s3 - s1 * s2 * c3; + this.w = c1 * c2 * c3 + s1 * s2 * s3; + + } else if ( order === 'ZXY' ) { + + this.x = s1 * c2 * c3 - c1 * s2 * s3; + this.y = c1 * s2 * c3 + s1 * c2 * s3; + this.z = c1 * c2 * s3 + s1 * s2 * c3; + this.w = c1 * c2 * c3 - s1 * s2 * s3; + + } else if ( order === 'ZYX' ) { + + this.x = s1 * c2 * c3 - c1 * s2 * s3; + this.y = c1 * s2 * c3 + s1 * c2 * s3; + this.z = c1 * c2 * s3 - s1 * s2 * c3; + this.w = c1 * c2 * c3 + s1 * s2 * s3; + + } else if ( order === 'YZX' ) { + + this.x = s1 * c2 * c3 + c1 * s2 * s3; + this.y = c1 * s2 * c3 + s1 * c2 * s3; + this.z = c1 * c2 * s3 - s1 * s2 * c3; + this.w = c1 * c2 * c3 - s1 * s2 * s3; + + } else if ( order === 'XZY' ) { + + this.x = s1 * c2 * c3 - c1 * s2 * s3; + this.y = c1 * s2 * c3 - s1 * c2 * s3; + this.z = c1 * c2 * s3 + s1 * s2 * c3; + this.w = c1 * c2 * c3 + s1 * s2 * s3; + + } + + return this; + + }, + + setFromAxisAngle: function ( axis, angle ) { + + // from http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm + // axis have to be normalized + + var halfAngle = angle / 2, + s = Math.sin( halfAngle ); + + this.x = axis.x * s; + this.y = axis.y * s; + this.z = axis.z * s; + this.w = Math.cos( halfAngle ); + + return this; + + }, + + setFromRotationMatrix: function ( m ) { + + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm + + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + + var te = m.elements, + + m11 = te[0], m12 = te[4], m13 = te[8], + m21 = te[1], m22 = te[5], m23 = te[9], + m31 = te[2], m32 = te[6], m33 = te[10], + + trace = m11 + m22 + m33, + s; + + if ( trace > 0 ) { + + s = 0.5 / Math.sqrt( trace + 1.0 ); + + this.w = 0.25 / s; + this.x = ( m32 - m23 ) * s; + this.y = ( m13 - m31 ) * s; + this.z = ( m21 - m12 ) * s; + + } else if ( m11 > m22 && m11 > m33 ) { + + s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 ); + + this.w = (m32 - m23 ) / s; + this.x = 0.25 * s; + this.y = (m12 + m21 ) / s; + this.z = (m13 + m31 ) / s; + + } else if ( m22 > m33 ) { + + s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 ); + + this.w = (m13 - m31 ) / s; + this.x = (m12 + m21 ) / s; + this.y = 0.25 * s; + this.z = (m23 + m32 ) / s; + + } else { + + s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 ); + + this.w = ( m21 - m12 ) / s; + this.x = ( m13 + m31 ) / s; + this.y = ( m23 + m32 ) / s; + this.z = 0.25 * s; + + } + + return this; + + }, + + inverse: function () { + + this.conjugate().normalize(); + + return this; + + }, + + conjugate: function () { + + this.x *= -1; + this.y *= -1; + this.z *= -1; + + return this; + + }, + + lengthSq: function () { + + return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; + + }, + + length: function () { + + return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w ); + + }, + + normalize: function () { + + var l = this.length(); + + if ( l === 0 ) { + + this.x = 0; + this.y = 0; + this.z = 0; + this.w = 1; + + } else { + + l = 1 / l; + + this.x = this.x * l; + this.y = this.y * l; + this.z = this.z * l; + this.w = this.w * l; + + } + + return this; + + }, + + multiply: function ( q, p ) { + + if ( p !== undefined ) { + + console.warn( 'DEPRECATED: Quaternion\'s .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' ); + return this.multiplyQuaternions( q, p ); + + } + + return this.multiplyQuaternions( this, q ); + + }, + + multiplyQuaternions: function ( a, b ) { + + // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm + + var qax = a.x, qay = a.y, qaz = a.z, qaw = a.w; + var qbx = b.x, qby = b.y, qbz = b.z, qbw = b.w; + + this.x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; + this.y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; + this.z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; + this.w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; + + return this; + + }, + + multiplyVector3: function ( vector ) { + + console.warn( 'DEPRECATED: Quaternion\'s .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' ); + return vector.applyQuaternion( this ); + + }, + + slerp: function ( qb, t ) { + + var x = this.x, y = this.y, z = this.z, w = this.w; + + // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ + + var cosHalfTheta = w * qb.w + x * qb.x + y * qb.y + z * qb.z; + + if ( cosHalfTheta < 0 ) { + + this.w = -qb.w; + this.x = -qb.x; + this.y = -qb.y; + this.z = -qb.z; + + cosHalfTheta = -cosHalfTheta; + + } else { + + this.copy( qb ); + + } + + if ( cosHalfTheta >= 1.0 ) { + + this.w = w; + this.x = x; + this.y = y; + this.z = z; + + return this; + + } + + var halfTheta = Math.acos( cosHalfTheta ); + var sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta ); + + if ( Math.abs( sinHalfTheta ) < 0.001 ) { + + this.w = 0.5 * ( w + this.w ); + this.x = 0.5 * ( x + this.x ); + this.y = 0.5 * ( y + this.y ); + this.z = 0.5 * ( z + this.z ); + + return this; + + } + + var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta, + ratioB = Math.sin( t * halfTheta ) / sinHalfTheta; + + this.w = ( w * ratioA + this.w * ratioB ); + this.x = ( x * ratioA + this.x * ratioB ); + this.y = ( y * ratioA + this.y * ratioB ); + this.z = ( z * ratioA + this.z * ratioB ); + + return this; + + }, + + equals: function ( v ) { + + return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) ); + + }, + + clone: function () { + + return new THREE.Quaternion( this.x, this.y, this.z, this.w ); + + } + +} ); + +THREE.Quaternion.slerp = function ( qa, qb, qm, t ) { + + return qm.copy( qa ).slerp( qb, t ); + +} +/** + * @author mrdoob / http://mrdoob.com/ + * @author philogb / http://blog.thejit.org/ + * @author egraether / http://egraether.com/ + * @author zz85 / http://www.lab4games.net/zz85/blog + */ + +THREE.Vector2 = function ( x, y ) { + + this.x = x || 0; + this.y = y || 0; + +}; + +THREE.extend( THREE.Vector2.prototype, { + + set: function ( x, y ) { + + this.x = x; + this.y = y; + + return this; + + }, + + setX: function ( x ) { + + this.x = x; + + return this; + + }, + + setY: function ( y ) { + + this.y = y; + + return this; + + }, + + + setComponent: function ( index, value ) { + + switch ( index ) { + + case 0: this.x = value; break; + case 1: this.y = value; break; + default: throw new Error( "index is out of range: " + index ); + + } + + }, + + getComponent: function ( index ) { + + switch ( index ) { + + case 0: return this.x; + case 1: return this.y; + default: throw new Error( "index is out of range: " + index ); + + } + + }, + + copy: function ( v ) { + + this.x = v.x; + this.y = v.y; + + return this; + + }, + + add: function ( v, w ) { + + if ( w !== undefined ) { + + console.warn( 'DEPRECATED: Vector2\'s .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); + return this.addVectors( v, w ); + + } + + this.x += v.x; + this.y += v.y; + + return this; + + }, + + addVectors: function ( a, b ) { + + this.x = a.x + b.x; + this.y = a.y + b.y; + + return this; + + }, + + addScalar: function ( s ) { + + this.x += s; + this.y += s; + + return this; + + }, + + sub: function ( v, w ) { + + if ( w !== undefined ) { + + console.warn( 'DEPRECATED: Vector2\'s .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); + return this.subVectors( v, w ); + + } + + this.x -= v.x; + this.y -= v.y; + + return this; + + }, + + subVectors: function ( a, b ) { + + this.x = a.x - b.x; + this.y = a.y - b.y; + + return this; + + }, + + multiplyScalar: function ( s ) { + + this.x *= s; + this.y *= s; + + return this; + + }, + + divideScalar: function ( s ) { + + if ( s !== 0 ) { + + this.x /= s; + this.y /= s; + + } else { + + this.set( 0, 0 ); + + } + + return this; + + }, + + min: function ( v ) { + + if ( this.x > v.x ) { + + this.x = v.x; + + } + + if ( this.y > v.y ) { + + this.y = v.y; + + } + + return this; + + }, + + max: function ( v ) { + + if ( this.x < v.x ) { + + this.x = v.x; + + } + + if ( this.y < v.y ) { + + this.y = v.y; + + } + + return this; + + }, + + clamp: function ( min, max ) { + + // This function assumes min < max, if this assumption isn't true it will not operate correctly + + if ( this.x < min.x ) { + + this.x = min.x; + + } else if ( this.x > max.x ) { + + this.x = max.x; + + } + + if ( this.y < min.y ) { + + this.y = min.y; + + } else if ( this.y > max.y ) { + + this.y = max.y; + + } + + return this; + + }, + + negate: function() { + + return this.multiplyScalar( - 1 ); + + }, + + dot: function ( v ) { + + return this.x * v.x + this.y * v.y; + + }, + + lengthSq: function () { + + return this.x * this.x + this.y * this.y; + + }, + + length: function () { + + return Math.sqrt( this.x * this.x + this.y * this.y ); + + }, + + normalize: function () { + + return this.divideScalar( this.length() ); + + }, + + distanceTo: function ( v ) { + + return Math.sqrt( this.distanceToSquared( v ) ); + + }, + + distanceToSquared: function ( v ) { + + var dx = this.x - v.x, dy = this.y - v.y; + return dx * dx + dy * dy; + + }, + + setLength: function ( l ) { + + var oldLength = this.length(); + + if ( oldLength !== 0 && l !== oldLength ) { + + this.multiplyScalar( l / oldLength ); + } + + return this; + + }, + + lerp: function ( v, alpha ) { + + this.x += ( v.x - this.x ) * alpha; + this.y += ( v.y - this.y ) * alpha; + + return this; + + }, + + equals: function( v ) { + + return ( ( v.x === this.x ) && ( v.y === this.y ) ); + + }, + + toArray: function () { + + return [ this.x, this.y ]; + + }, + + clone: function () { + + return new THREE.Vector2( this.x, this.y ); + + } + +} ); +/** + * @author mrdoob / http://mrdoob.com/ + * @author *kile / http://kile.stravaganza.org/ + * @author philogb / http://blog.thejit.org/ + * @author mikael emtinger / http://gomo.se/ + * @author egraether / http://egraether.com/ + * @author WestLangley / http://github.com/WestLangley + */ + +THREE.Vector3 = function ( x, y, z ) { + + this.x = x || 0; + this.y = y || 0; + this.z = z || 0; + +}; + +THREE.extend( THREE.Vector3.prototype, { + + set: function ( x, y, z ) { + + this.x = x; + this.y = y; + this.z = z; + + return this; + + }, + + setX: function ( x ) { + + this.x = x; + + return this; + + }, + + setY: function ( y ) { + + this.y = y; + + return this; + + }, + + setZ: function ( z ) { + + this.z = z; + + return this; + + }, + + setComponent: function ( index, value ) { + + switch ( index ) { + + case 0: this.x = value; break; + case 1: this.y = value; break; + case 2: this.z = value; break; + default: throw new Error( "index is out of range: " + index ); + + } + + }, + + getComponent: function ( index ) { + + switch ( index ) { + + case 0: return this.x; + case 1: return this.y; + case 2: return this.z; + default: throw new Error( "index is out of range: " + index ); + + } + + }, + + copy: function ( v ) { + + this.x = v.x; + this.y = v.y; + this.z = v.z; + + return this; + + }, + + add: function ( v, w ) { + + if ( w !== undefined ) { + + console.warn( 'DEPRECATED: Vector3\'s .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); + return this.addVectors( v, w ); + + } + + this.x += v.x; + this.y += v.y; + this.z += v.z; + + return this; + + }, + + addScalar: function ( s ) { + + this.x += s; + this.y += s; + this.z += s; + + return this; + + }, + + addVectors: function ( a, b ) { + + this.x = a.x + b.x; + this.y = a.y + b.y; + this.z = a.z + b.z; + + return this; + + }, + + sub: function ( v, w ) { + + if ( w !== undefined ) { + + console.warn( 'DEPRECATED: Vector3\'s .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); + return this.subVectors( v, w ); + + } + + this.x -= v.x; + this.y -= v.y; + this.z -= v.z; + + return this; + + }, + + subVectors: function ( a, b ) { + + this.x = a.x - b.x; + this.y = a.y - b.y; + this.z = a.z - b.z; + + return this; + + }, + + multiply: function ( v, w ) { + + if ( w !== undefined ) { + + console.warn( 'DEPRECATED: Vector3\'s .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' ); + return this.multiplyVectors( v, w ); + + } + + this.x *= v.x; + this.y *= v.y; + this.z *= v.z; + + return this; + + }, + + multiplyScalar: function ( s ) { + + this.x *= s; + this.y *= s; + this.z *= s; + + return this; + + }, + + multiplyVectors: function ( a, b ) { + + this.x = a.x * b.x; + this.y = a.y * b.y; + this.z = a.z * b.z; + + return this; + + }, + + applyMatrix3: function ( m ) { + + var x = this.x; + var y = this.y; + var z = this.z; + + var e = m.elements; + + this.x = e[0] * x + e[3] * y + e[6] * z; + this.y = e[1] * x + e[4] * y + e[7] * z; + this.z = e[2] * x + e[5] * y + e[8] * z; + + return this; + + }, + + applyMatrix4: function ( m ) { + + // input: THREE.Matrix4 affine matrix + + var x = this.x, y = this.y, z = this.z; + + var e = m.elements; + + this.x = e[0] * x + e[4] * y + e[8] * z + e[12]; + this.y = e[1] * x + e[5] * y + e[9] * z + e[13]; + this.z = e[2] * x + e[6] * y + e[10] * z + e[14]; + + return this; + + }, + + applyProjection: function ( m ) { + + // input: THREE.Matrix4 projection matrix + + var x = this.x, y = this.y, z = this.z; + + var e = m.elements; + var d = 1 / ( e[3] * x + e[7] * y + e[11] * z + e[15] ); // perspective divide + + this.x = ( e[0] * x + e[4] * y + e[8] * z + e[12] ) * d; + this.y = ( e[1] * x + e[5] * y + e[9] * z + e[13] ) * d; + this.z = ( e[2] * x + e[6] * y + e[10] * z + e[14] ) * d; + + return this; + + }, + + applyQuaternion: function ( q ) { + + var x = this.x; + var y = this.y; + var z = this.z; + + var qx = q.x; + var qy = q.y; + var qz = q.z; + var qw = q.w; + + // calculate quat * vector + + var ix = qw * x + qy * z - qz * y; + var iy = qw * y + qz * x - qx * z; + var iz = qw * z + qx * y - qy * x; + var iw = -qx * x - qy * y - qz * z; + + // calculate result * inverse quat + + this.x = ix * qw + iw * -qx + iy * -qz - iz * -qy; + this.y = iy * qw + iw * -qy + iz * -qx - ix * -qz; + this.z = iz * qw + iw * -qz + ix * -qy - iy * -qx; + + return this; + + }, + + applyEuler: function () { + + var q1 = new THREE.Quaternion(); + + return function ( v, eulerOrder ) { + + var quaternion = q1.setFromEuler( v, eulerOrder ); + + this.applyQuaternion( quaternion ); + + return this; + + }; + + }(), + + applyAxisAngle: function () { + + var q1 = new THREE.Quaternion(); + + return function ( axis, angle ) { + + var quaternion = q1.setFromAxisAngle( axis, angle ); + + this.applyQuaternion( quaternion ); + + return this; + + }; + + }(), + + transformDirection: function ( m ) { + + // input: THREE.Matrix4 affine matrix + // vector interpreted as a direction + + var x = this.x, y = this.y, z = this.z; + + var e = m.elements; + + this.x = e[0] * x + e[4] * y + e[8] * z; + this.y = e[1] * x + e[5] * y + e[9] * z; + this.z = e[2] * x + e[6] * y + e[10] * z; + + this.normalize(); + + return this; + + }, + + divide: function ( v ) { + + this.x /= v.x; + this.y /= v.y; + this.z /= v.z; + + return this; + + }, + + divideScalar: function ( s ) { + + if ( s !== 0 ) { + + this.x /= s; + this.y /= s; + this.z /= s; + + } else { + + this.x = 0; + this.y = 0; + this.z = 0; + + } + + return this; + + }, + + min: function ( v ) { + + if ( this.x > v.x ) { + + this.x = v.x; + + } + + if ( this.y > v.y ) { + + this.y = v.y; + + } + + if ( this.z > v.z ) { + + this.z = v.z; + + } + + return this; + + }, + + max: function ( v ) { + + if ( this.x < v.x ) { + + this.x = v.x; + + } + + if ( this.y < v.y ) { + + this.y = v.y; + + } + + if ( this.z < v.z ) { + + this.z = v.z; + + } + + return this; + + }, + + clamp: function ( min, max ) { + + // This function assumes min < max, if this assumption isn't true it will not operate correctly + + if ( this.x < min.x ) { + + this.x = min.x; + + } else if ( this.x > max.x ) { + + this.x = max.x; + + } + + if ( this.y < min.y ) { + + this.y = min.y; + + } else if ( this.y > max.y ) { + + this.y = max.y; + + } + + if ( this.z < min.z ) { + + this.z = min.z; + + } else if ( this.z > max.z ) { + + this.z = max.z; + + } + + return this; + + }, + + negate: function () { + + return this.multiplyScalar( - 1 ); + + }, + + dot: function ( v ) { + + return this.x * v.x + this.y * v.y + this.z * v.z; + + }, + + lengthSq: function () { + + return this.x * this.x + this.y * this.y + this.z * this.z; + + }, + + length: function () { + + return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); + + }, + + lengthManhattan: function () { + + return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ); + + }, + + normalize: function () { + + return this.divideScalar( this.length() ); + + }, + + setLength: function ( l ) { + + var oldLength = this.length(); + + if ( oldLength !== 0 && l !== oldLength ) { + + this.multiplyScalar( l / oldLength ); + } + + return this; + + }, + + lerp: function ( v, alpha ) { + + this.x += ( v.x - this.x ) * alpha; + this.y += ( v.y - this.y ) * alpha; + this.z += ( v.z - this.z ) * alpha; + + return this; + + }, + + cross: function ( v, w ) { + + if ( w !== undefined ) { + + console.warn( 'DEPRECATED: Vector3\'s .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' ); + return this.crossVectors( v, w ); + + } + + var x = this.x, y = this.y, z = this.z; + + this.x = y * v.z - z * v.y; + this.y = z * v.x - x * v.z; + this.z = x * v.y - y * v.x; + + return this; + + }, + + crossVectors: function ( a, b ) { + + this.x = a.y * b.z - a.z * b.y; + this.y = a.z * b.x - a.x * b.z; + this.z = a.x * b.y - a.y * b.x; + + return this; + + }, + + projectOnVector: function () { + + var v1 = new THREE.Vector3(); + + return function( vector ) { + + v1.copy( vector ).normalize(); + var d = this.dot( v1 ); + return this.copy( v1 ).multiplyScalar( d ); + + }; + + }(), + + projectOnPlane: function () { + + var v1 = new THREE.Vector3(); + + return function( planeNormal ) { + + v1.copy( this ).projectOnVector( planeNormal ); + + return this.sub( v1 ); + + } + + }(), + + reflect: function () { + + var v1 = new THREE.Vector3(); + + return function ( vector ) { + + v1.copy( this ).projectOnVector( vector ).multiplyScalar( 2 ); + + return this.subVectors( v1, this ); + + } + + }(), + + angleTo: function ( v ) { + + var theta = this.dot( v ) / ( this.length() * v.length() ); + + // clamp, to handle numerical problems + + return Math.acos( THREE.Math.clamp( theta, -1, 1 ) ); + + }, + + distanceTo: function ( v ) { + + return Math.sqrt( this.distanceToSquared( v ) ); + + }, + + distanceToSquared: function ( v ) { + + var dx = this.x - v.x; + var dy = this.y - v.y; + var dz = this.z - v.z; + + return dx * dx + dy * dy + dz * dz; + + }, + + getPositionFromMatrix: function ( m ) { + + this.x = m.elements[12]; + this.y = m.elements[13]; + this.z = m.elements[14]; + + return this; + + }, + + setEulerFromRotationMatrix: function ( m, order ) { + + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + + // clamp, to handle numerical problems + + function clamp( x ) { + + return Math.min( Math.max( x, -1 ), 1 ); + + } + + var te = m.elements; + var m11 = te[0], m12 = te[4], m13 = te[8]; + var m21 = te[1], m22 = te[5], m23 = te[9]; + var m31 = te[2], m32 = te[6], m33 = te[10]; + + if ( order === undefined || order === 'XYZ' ) { + + this.y = Math.asin( clamp( m13 ) ); + + if ( Math.abs( m13 ) < 0.99999 ) { + + this.x = Math.atan2( - m23, m33 ); + this.z = Math.atan2( - m12, m11 ); + + } else { + + this.x = Math.atan2( m32, m22 ); + this.z = 0; + + } + + } else if ( order === 'YXZ' ) { + + this.x = Math.asin( - clamp( m23 ) ); + + if ( Math.abs( m23 ) < 0.99999 ) { + + this.y = Math.atan2( m13, m33 ); + this.z = Math.atan2( m21, m22 ); + + } else { + + this.y = Math.atan2( - m31, m11 ); + this.z = 0; + + } + + } else if ( order === 'ZXY' ) { + + this.x = Math.asin( clamp( m32 ) ); + + if ( Math.abs( m32 ) < 0.99999 ) { + + this.y = Math.atan2( - m31, m33 ); + this.z = Math.atan2( - m12, m22 ); + + } else { + + this.y = 0; + this.z = Math.atan2( m21, m11 ); + + } + + } else if ( order === 'ZYX' ) { + + this.y = Math.asin( - clamp( m31 ) ); + + if ( Math.abs( m31 ) < 0.99999 ) { + + this.x = Math.atan2( m32, m33 ); + this.z = Math.atan2( m21, m11 ); + + } else { + + this.x = 0; + this.z = Math.atan2( - m12, m22 ); + + } + + } else if ( order === 'YZX' ) { + + this.z = Math.asin( clamp( m21 ) ); + + if ( Math.abs( m21 ) < 0.99999 ) { + + this.x = Math.atan2( - m23, m22 ); + this.y = Math.atan2( - m31, m11 ); + + } else { + + this.x = 0; + this.y = Math.atan2( m13, m33 ); + + } + + } else if ( order === 'XZY' ) { + + this.z = Math.asin( - clamp( m12 ) ); + + if ( Math.abs( m12 ) < 0.99999 ) { + + this.x = Math.atan2( m32, m22 ); + this.y = Math.atan2( m13, m11 ); + + } else { + + this.x = Math.atan2( - m23, m33 ); + this.y = 0; + + } + + } + + return this; + + }, + + setEulerFromQuaternion: function ( q, order ) { + + // q is assumed to be normalized + + // clamp, to handle numerical problems + + function clamp( x ) { + + return Math.min( Math.max( x, -1 ), 1 ); + + } + + // http://www.mathworks.com/matlabcentral/fileexchange/20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/content/SpinCalc.m + + var sqx = q.x * q.x; + var sqy = q.y * q.y; + var sqz = q.z * q.z; + var sqw = q.w * q.w; + + if ( order === undefined || order === 'XYZ' ) { + + this.x = Math.atan2( 2 * ( q.x * q.w - q.y * q.z ), ( sqw - sqx - sqy + sqz ) ); + this.y = Math.asin( clamp( 2 * ( q.x * q.z + q.y * q.w ) ) ); + this.z = Math.atan2( 2 * ( q.z * q.w - q.x * q.y ), ( sqw + sqx - sqy - sqz ) ); + + } else if ( order === 'YXZ' ) { + + this.x = Math.asin( clamp( 2 * ( q.x * q.w - q.y * q.z ) ) ); + this.y = Math.atan2( 2 * ( q.x * q.z + q.y * q.w ), ( sqw - sqx - sqy + sqz ) ); + this.z = Math.atan2( 2 * ( q.x * q.y + q.z * q.w ), ( sqw - sqx + sqy - sqz ) ); + + } else if ( order === 'ZXY' ) { + + this.x = Math.asin( clamp( 2 * ( q.x * q.w + q.y * q.z ) ) ); + this.y = Math.atan2( 2 * ( q.y * q.w - q.z * q.x ), ( sqw - sqx - sqy + sqz ) ); + this.z = Math.atan2( 2 * ( q.z * q.w - q.x * q.y ), ( sqw - sqx + sqy - sqz ) ); + + } else if ( order === 'ZYX' ) { + + this.x = Math.atan2( 2 * ( q.x * q.w + q.z * q.y ), ( sqw - sqx - sqy + sqz ) ); + this.y = Math.asin( clamp( 2 * ( q.y * q.w - q.x * q.z ) ) ); + this.z = Math.atan2( 2 * ( q.x * q.y + q.z * q.w ), ( sqw + sqx - sqy - sqz ) ); + + } else if ( order === 'YZX' ) { + + this.x = Math.atan2( 2 * ( q.x * q.w - q.z * q.y ), ( sqw - sqx + sqy - sqz ) ); + this.y = Math.atan2( 2 * ( q.y * q.w - q.x * q.z ), ( sqw + sqx - sqy - sqz ) ); + this.z = Math.asin( clamp( 2 * ( q.x * q.y + q.z * q.w ) ) ); + + } else if ( order === 'XZY' ) { + + this.x = Math.atan2( 2 * ( q.x * q.w + q.y * q.z ), ( sqw - sqx + sqy - sqz ) ); + this.y = Math.atan2( 2 * ( q.x * q.z + q.y * q.w ), ( sqw + sqx - sqy - sqz ) ); + this.z = Math.asin( clamp( 2 * ( q.z * q.w - q.x * q.y ) ) ); + + } + + return this; + + }, + + getScaleFromMatrix: function ( m ) { + + var sx = this.set( m.elements[0], m.elements[1], m.elements[2] ).length(); + var sy = this.set( m.elements[4], m.elements[5], m.elements[6] ).length(); + var sz = this.set( m.elements[8], m.elements[9], m.elements[10] ).length(); + + this.x = sx; + this.y = sy; + this.z = sz; + + return this; + }, + + equals: function ( v ) { + + return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); + + }, + + toArray: function () { + + return [ this.x, this.y, this.z ]; + + }, + + clone: function () { + + return new THREE.Vector3( this.x, this.y, this.z ); + + } + +} ); +/** + * @author supereggbert / http://www.paulbrunt.co.uk/ + * @author philogb / http://blog.thejit.org/ + * @author mikael emtinger / http://gomo.se/ + * @author egraether / http://egraether.com/ + * @author WestLangley / http://github.com/WestLangley + */ + +THREE.Vector4 = function ( x, y, z, w ) { + + this.x = x || 0; + this.y = y || 0; + this.z = z || 0; + this.w = ( w !== undefined ) ? w : 1; + +}; + +THREE.extend( THREE.Vector4.prototype, { + + set: function ( x, y, z, w ) { + + this.x = x; + this.y = y; + this.z = z; + this.w = w; + + return this; + + }, + + setX: function ( x ) { + + this.x = x; + + return this; + + }, + + setY: function ( y ) { + + this.y = y; + + return this; + + }, + + setZ: function ( z ) { + + this.z = z; + + return this; + + }, + + setW: function ( w ) { + + this.w = w; + + return this; + + }, + + setComponent: function ( index, value ) { + + switch ( index ) { + + case 0: this.x = value; break; + case 1: this.y = value; break; + case 2: this.z = value; break; + case 3: this.w = value; break; + default: throw new Error( "index is out of range: " + index ); + + } + + }, + + getComponent: function ( index ) { + + switch ( index ) { + + case 0: return this.x; + case 1: return this.y; + case 2: return this.z; + case 3: return this.w; + default: throw new Error( "index is out of range: " + index ); + + } + + }, + + copy: function ( v ) { + + this.x = v.x; + this.y = v.y; + this.z = v.z; + this.w = ( v.w !== undefined ) ? v.w : 1; + + return this; + + }, + + add: function ( v, w ) { + + if ( w !== undefined ) { + + console.warn( 'DEPRECATED: Vector4\'s .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); + return this.addVectors( v, w ); + + } + + this.x += v.x; + this.y += v.y; + this.z += v.z; + this.w += v.w; + + return this; + + }, + + addScalar: function ( s ) { + + this.x += s; + this.y += s; + this.z += s; + this.w += s; + + return this; + + }, + + addVectors: function ( a, b ) { + + this.x = a.x + b.x; + this.y = a.y + b.y; + this.z = a.z + b.z; + this.w = a.w + b.w; + + return this; + + }, + + sub: function ( v, w ) { + + if ( w !== undefined ) { + + console.warn( 'DEPRECATED: Vector4\'s .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); + return this.subVectors( v, w ); + + } + + this.x -= v.x; + this.y -= v.y; + this.z -= v.z; + this.w -= v.w; + + return this; + + }, + + subVectors: function ( a, b ) { + + this.x = a.x - b.x; + this.y = a.y - b.y; + this.z = a.z - b.z; + this.w = a.w - b.w; + + return this; + + }, + + multiplyScalar: function ( s ) { + + this.x *= s; + this.y *= s; + this.z *= s; + this.w *= s; + + return this; + + }, + + applyMatrix4: function ( m ) { + + var x = this.x; + var y = this.y; + var z = this.z; + var w = this.w; + + var e = m.elements; + + this.x = e[0] * x + e[4] * y + e[8] * z + e[12] * w; + this.y = e[1] * x + e[5] * y + e[9] * z + e[13] * w; + this.z = e[2] * x + e[6] * y + e[10] * z + e[14] * w; + this.w = e[3] * x + e[7] * y + e[11] * z + e[15] * w; + + return this; + + }, + + divideScalar: function ( s ) { + + if ( s !== 0 ) { + + this.x /= s; + this.y /= s; + this.z /= s; + this.w /= s; + + } else { + + this.x = 0; + this.y = 0; + this.z = 0; + this.w = 1; + + } + + return this; + + }, + + setAxisAngleFromQuaternion: function ( q ) { + + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm + + // q is assumed to be normalized + + this.w = 2 * Math.acos( q.w ); + + var s = Math.sqrt( 1 - q.w * q.w ); + + if ( s < 0.0001 ) { + + this.x = 1; + this.y = 0; + this.z = 0; + + } else { + + this.x = q.x / s; + this.y = q.y / s; + this.z = q.z / s; + + } + + return this; + + }, + + setAxisAngleFromRotationMatrix: function ( m ) { + + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm + + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + + var angle, x, y, z, // variables for result + epsilon = 0.01, // margin to allow for rounding errors + epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees + + te = m.elements, + + m11 = te[0], m12 = te[4], m13 = te[8], + m21 = te[1], m22 = te[5], m23 = te[9], + m31 = te[2], m32 = te[6], m33 = te[10]; + + if ( ( Math.abs( m12 - m21 ) < epsilon ) + && ( Math.abs( m13 - m31 ) < epsilon ) + && ( Math.abs( m23 - m32 ) < epsilon ) ) { + + // singularity found + // first check for identity matrix which must have +1 for all terms + // in leading diagonal and zero in other terms + + if ( ( Math.abs( m12 + m21 ) < epsilon2 ) + && ( Math.abs( m13 + m31 ) < epsilon2 ) + && ( Math.abs( m23 + m32 ) < epsilon2 ) + && ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) { + + // this singularity is identity matrix so angle = 0 + + this.set( 1, 0, 0, 0 ); + + return this; // zero angle, arbitrary axis + + } + + // otherwise this singularity is angle = 180 + + angle = Math.PI; + + var xx = ( m11 + 1 ) / 2; + var yy = ( m22 + 1 ) / 2; + var zz = ( m33 + 1 ) / 2; + var xy = ( m12 + m21 ) / 4; + var xz = ( m13 + m31 ) / 4; + var yz = ( m23 + m32 ) / 4; + + if ( ( xx > yy ) && ( xx > zz ) ) { // m11 is the largest diagonal term + + if ( xx < epsilon ) { + + x = 0; + y = 0.707106781; + z = 0.707106781; + + } else { + + x = Math.sqrt( xx ); + y = xy / x; + z = xz / x; + + } + + } else if ( yy > zz ) { // m22 is the largest diagonal term + + if ( yy < epsilon ) { + + x = 0.707106781; + y = 0; + z = 0.707106781; + + } else { + + y = Math.sqrt( yy ); + x = xy / y; + z = yz / y; + + } + + } else { // m33 is the largest diagonal term so base result on this + + if ( zz < epsilon ) { + + x = 0.707106781; + y = 0.707106781; + z = 0; + + } else { + + z = Math.sqrt( zz ); + x = xz / z; + y = yz / z; + + } + + } + + this.set( x, y, z, angle ); + + return this; // return 180 deg rotation + + } + + // as we have reached here there are no singularities so we can handle normally + + var s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) + + ( m13 - m31 ) * ( m13 - m31 ) + + ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize + + if ( Math.abs( s ) < 0.001 ) s = 1; + + // prevent divide by zero, should not happen if matrix is orthogonal and should be + // caught by singularity test above, but I've left it in just in case + + this.x = ( m32 - m23 ) / s; + this.y = ( m13 - m31 ) / s; + this.z = ( m21 - m12 ) / s; + this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 ); + + return this; + + }, + + min: function ( v ) { + + if ( this.x > v.x ) { + + this.x = v.x; + + } + + if ( this.y > v.y ) { + + this.y = v.y; + + } + + if ( this.z > v.z ) { + + this.z = v.z; + + } + + if ( this.w > v.w ) { + + this.w = v.w; + + } + + return this; + + }, + + max: function ( v ) { + + if ( this.x < v.x ) { + + this.x = v.x; + + } + + if ( this.y < v.y ) { + + this.y = v.y; + + } + + if ( this.z < v.z ) { + + this.z = v.z; + + } + + if ( this.w < v.w ) { + + this.w = v.w; + + } + + return this; + + }, + + clamp: function ( min, max ) { + + // This function assumes min < max, if this assumption isn't true it will not operate correctly + + if ( this.x < min.x ) { + + this.x = min.x; + + } else if ( this.x > max.x ) { + + this.x = max.x; + + } + + if ( this.y < min.y ) { + + this.y = min.y; + + } else if ( this.y > max.y ) { + + this.y = max.y; + + } + + if ( this.z < min.z ) { + + this.z = min.z; + + } else if ( this.z > max.z ) { + + this.z = max.z; + + } + + if ( this.w < min.w ) { + + this.w = min.w; + + } else if ( this.w > max.w ) { + + this.w = max.w; + + } + + return this; + + }, + + negate: function() { + + return this.multiplyScalar( -1 ); + + }, + + dot: function ( v ) { + + return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w; + + }, + + lengthSq: function () { + + return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; + + }, + + length: function () { + + return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w ); + + }, + + lengthManhattan: function () { + + return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w ); + + }, + + normalize: function () { + + return this.divideScalar( this.length() ); + + }, + + setLength: function ( l ) { + + var oldLength = this.length(); + + if ( oldLength !== 0 && l !== oldLength ) { + + this.multiplyScalar( l / oldLength ); + } + + return this; + + }, + + lerp: function ( v, alpha ) { + + this.x += ( v.x - this.x ) * alpha; + this.y += ( v.y - this.y ) * alpha; + this.z += ( v.z - this.z ) * alpha; + this.w += ( v.w - this.w ) * alpha; + + return this; + + }, + + equals: function ( v ) { + + return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) ); + + }, + + toArray: function () { + + return [ this.x, this.y, this.z, this.w ]; + + }, + + clone: function () { + + return new THREE.Vector4( this.x, this.y, this.z, this.w ); + + } + +} ); +/** + * @author bhouston / http://exocortex.com + */ + +THREE.Box2 = function ( min, max ) { + + this.min = ( min !== undefined ) ? min : new THREE.Vector2( Infinity, Infinity ); + this.max = ( max !== undefined ) ? max : new THREE.Vector2( -Infinity, -Infinity ); + +}; + +THREE.extend( THREE.Box2.prototype, { + + set: function ( min, max ) { + + this.min.copy( min ); + this.max.copy( max ); + + return this; + + }, + + setFromPoints: function ( points ) { + + if ( points.length > 0 ) { + + var point = points[ 0 ]; + + this.min.copy( point ); + this.max.copy( point ); + + for ( var i = 1, il = points.length; i < il; i ++ ) { + + point = points[ i ]; + + if ( point.x < this.min.x ) { + + this.min.x = point.x; + + } else if ( point.x > this.max.x ) { + + this.max.x = point.x; + + } + + if ( point.y < this.min.y ) { + + this.min.y = point.y; + + } else if ( point.y > this.max.y ) { + + this.max.y = point.y; + + } + + } + + } else { + + this.makeEmpty(); + + } + + return this; + + }, + + setFromCenterAndSize: function() { + + var v1 = new THREE.Vector2(); + + return function ( center, size ) { + + var halfSize = v1.copy( size ).multiplyScalar( 0.5 ); + this.min.copy( center ).sub( halfSize ); + this.max.copy( center ).add( halfSize ); + + return this; + + }; + + }(), + + copy: function ( box ) { + + this.min.copy( box.min ); + this.max.copy( box.max ); + + return this; + + }, + + makeEmpty: function () { + + this.min.x = this.min.y = Infinity; + this.max.x = this.max.y = -Infinity; + + return this; + + }, + + empty: function () { + + // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes + + return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ); + + }, + + center: function ( optionalTarget ) { + + var result = optionalTarget || new THREE.Vector2(); + return result.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); + + }, + + size: function ( optionalTarget ) { + + var result = optionalTarget || new THREE.Vector2(); + return result.subVectors( this.max, this.min ); + + }, + + expandByPoint: function ( point ) { + + this.min.min( point ); + this.max.max( point ); + + return this; + }, + + expandByVector: function ( vector ) { + + this.min.sub( vector ); + this.max.add( vector ); + + return this; + }, + + expandByScalar: function ( scalar ) { + + this.min.addScalar( -scalar ); + this.max.addScalar( scalar ); + + return this; + }, + + containsPoint: function ( point ) { + + if ( point.x < this.min.x || point.x > this.max.x || + point.y < this.min.y || point.y > this.max.y ) { + + return false; + + } + + return true; + + }, + + containsBox: function ( box ) { + + if ( ( this.min.x <= box.min.x ) && ( box.max.x <= this.max.x ) && + ( this.min.y <= box.min.y ) && ( box.max.y <= this.max.y ) ) { + + return true; + + } + + return false; + + }, + + getParameter: function ( point ) { + + // This can potentially have a divide by zero if the box + // has a size dimension of 0. + + return new THREE.Vector2( + ( point.x - this.min.x ) / ( this.max.x - this.min.x ), + ( point.y - this.min.y ) / ( this.max.y - this.min.y ) + ); + + }, + + isIntersectionBox: function ( box ) { + + // using 6 splitting planes to rule out intersections. + + if ( box.max.x < this.min.x || box.min.x > this.max.x || + box.max.y < this.min.y || box.min.y > this.max.y ) { + + return false; + + } + + return true; + + }, + + clampPoint: function ( point, optionalTarget ) { + + var result = optionalTarget || new THREE.Vector2(); + return result.copy( point ).clamp( this.min, this.max ); + + }, + + distanceToPoint: function() { + + var v1 = new THREE.Vector2(); + + return function ( point ) { + + var clampedPoint = v1.copy( point ).clamp( this.min, this.max ); + return clampedPoint.sub( point ).length(); + + }; + + }(), + + intersect: function ( box ) { + + this.min.max( box.min ); + this.max.min( box.max ); + + return this; + + }, + + union: function ( box ) { + + this.min.min( box.min ); + this.max.max( box.max ); + + return this; + + }, + + translate: function ( offset ) { + + this.min.add( offset ); + this.max.add( offset ); + + return this; + + }, + + equals: function ( box ) { + + return box.min.equals( this.min ) && box.max.equals( this.max ); + + }, + + clone: function () { + + return new THREE.Box2().copy( this ); + + } + +} ); +/** + * @author bhouston / http://exocortex.com + */ + +THREE.Box3 = function ( min, max ) { + + this.min = ( min !== undefined ) ? min : new THREE.Vector3( Infinity, Infinity, Infinity ); + this.max = ( max !== undefined ) ? max : new THREE.Vector3( -Infinity, -Infinity, -Infinity ); + +}; + +THREE.extend( THREE.Box3.prototype, { + + set: function ( min, max ) { + + this.min.copy( min ); + this.max.copy( max ); + + return this; + + }, + + setFromPoints: function ( points ) { + + if ( points.length > 0 ) { + + var point = points[ 0 ]; + + this.min.copy( point ); + this.max.copy( point ); + + for ( var i = 1, il = points.length; i < il; i ++ ) { + + point = points[ i ]; + + if ( point.x < this.min.x ) { + + this.min.x = point.x; + + } else if ( point.x > this.max.x ) { + + this.max.x = point.x; + + } + + if ( point.y < this.min.y ) { + + this.min.y = point.y; + + } else if ( point.y > this.max.y ) { + + this.max.y = point.y; + + } + + if ( point.z < this.min.z ) { + + this.min.z = point.z; + + } else if ( point.z > this.max.z ) { + + this.max.z = point.z; + + } + + } + + } else { + + this.makeEmpty(); + + } + + return this; + + }, + + setFromCenterAndSize: function() { + + var v1 = new THREE.Vector3(); + + return function ( center, size ) { + + var halfSize = v1.copy( size ).multiplyScalar( 0.5 ); + + this.min.copy( center ).sub( halfSize ); + this.max.copy( center ).add( halfSize ); + + return this; + + }; + + }(), + + copy: function ( box ) { + + this.min.copy( box.min ); + this.max.copy( box.max ); + + return this; + + }, + + makeEmpty: function () { + + this.min.x = this.min.y = this.min.z = Infinity; + this.max.x = this.max.y = this.max.z = -Infinity; + + return this; + + }, + + empty: function () { + + // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes + + return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z ); + + }, + + center: function ( optionalTarget ) { + + var result = optionalTarget || new THREE.Vector3(); + return result.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); + + }, + + size: function ( optionalTarget ) { + + var result = optionalTarget || new THREE.Vector3(); + return result.subVectors( this.max, this.min ); + + }, + + expandByPoint: function ( point ) { + + this.min.min( point ); + this.max.max( point ); + + return this; + + }, + + expandByVector: function ( vector ) { + + this.min.sub( vector ); + this.max.add( vector ); + + return this; + + }, + + expandByScalar: function ( scalar ) { + + this.min.addScalar( -scalar ); + this.max.addScalar( scalar ); + + return this; + + }, + + containsPoint: function ( point ) { + + if ( point.x < this.min.x || point.x > this.max.x || + point.y < this.min.y || point.y > this.max.y || + point.z < this.min.z || point.z > this.max.z ) { + + return false; + + } + + return true; + + }, + + containsBox: function ( box ) { + + if ( ( this.min.x <= box.min.x ) && ( box.max.x <= this.max.x ) && + ( this.min.y <= box.min.y ) && ( box.max.y <= this.max.y ) && + ( this.min.z <= box.min.z ) && ( box.max.z <= this.max.z ) ) { + + return true; + + } + + return false; + + }, + + getParameter: function ( point ) { + + // This can potentially have a divide by zero if the box + // has a size dimension of 0. + + return new THREE.Vector3( + ( point.x - this.min.x ) / ( this.max.x - this.min.x ), + ( point.y - this.min.y ) / ( this.max.y - this.min.y ), + ( point.z - this.min.z ) / ( this.max.z - this.min.z ) + ); + + }, + + isIntersectionBox: function ( box ) { + + // using 6 splitting planes to rule out intersections. + + if ( box.max.x < this.min.x || box.min.x > this.max.x || + box.max.y < this.min.y || box.min.y > this.max.y || + box.max.z < this.min.z || box.min.z > this.max.z ) { + + return false; + + } + + return true; + + }, + + clampPoint: function ( point, optionalTarget ) { + + var result = optionalTarget || new THREE.Vector3(); + return result.copy( point ).clamp( this.min, this.max ); + + }, + + distanceToPoint: function() { + + var v1 = new THREE.Vector3(); + + return function ( point ) { + + var clampedPoint = v1.copy( point ).clamp( this.min, this.max ); + return clampedPoint.sub( point ).length(); + + }; + + }(), + + getBoundingSphere: function() { + + var v1 = new THREE.Vector3(); + + return function ( optionalTarget ) { + + var result = optionalTarget || new THREE.Sphere(); + + result.center = this.center(); + result.radius = this.size( v1 ).length() * 0.5; + + return result; + + }; + + }(), + + intersect: function ( box ) { + + this.min.max( box.min ); + this.max.min( box.max ); + + return this; + + }, + + union: function ( box ) { + + this.min.min( box.min ); + this.max.max( box.max ); + + return this; + + }, + + applyMatrix4: function() { + + var points = [ + new THREE.Vector3(), + new THREE.Vector3(), + new THREE.Vector3(), + new THREE.Vector3(), + new THREE.Vector3(), + new THREE.Vector3(), + new THREE.Vector3(), + new THREE.Vector3() + ]; + + return function ( matrix ) { + + // NOTE: I am using a binary pattern to specify all 2^3 combinations below + points[0].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000 + points[1].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001 + points[2].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010 + points[3].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011 + points[4].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100 + points[5].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101 + points[6].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110 + points[7].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111 + + this.makeEmpty(); + this.setFromPoints( points ); + + return this; + + }; + + }(), + + translate: function ( offset ) { + + this.min.add( offset ); + this.max.add( offset ); + + return this; + + }, + + equals: function ( box ) { + + return box.min.equals( this.min ) && box.max.equals( this.max ); + + }, + + clone: function () { + + return new THREE.Box3().copy( this ); + + } + +} ); +/** + * @author alteredq / http://alteredqualia.com/ + * @author WestLangley / http://github.com/WestLangley + * @author bhouston / http://exocortex.com + */ + +THREE.Matrix3 = function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { + + this.elements = new Float32Array(9); + + this.set( + + ( n11 !== undefined ) ? n11 : 1, n12 || 0, n13 || 0, + n21 || 0, ( n22 !== undefined ) ? n22 : 1, n23 || 0, + n31 || 0, n32 || 0, ( n33 !== undefined ) ? n33 : 1 + + ); +}; + +THREE.extend( THREE.Matrix3.prototype, { + + set: function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { + + var te = this.elements; + + te[0] = n11; te[3] = n12; te[6] = n13; + te[1] = n21; te[4] = n22; te[7] = n23; + te[2] = n31; te[5] = n32; te[8] = n33; + + return this; + + }, + + identity: function () { + + this.set( + + 1, 0, 0, + 0, 1, 0, + 0, 0, 1 + + ); + + return this; + + }, + + copy: function ( m ) { + + var me = m.elements; + + this.set( + + me[0], me[3], me[6], + me[1], me[4], me[7], + me[2], me[5], me[8] + + ); + + return this; + + }, + + multiplyVector3: function ( vector ) { + + console.warn( 'DEPRECATED: Matrix3\'s .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' ); + return vector.applyMatrix3( this ); + + }, + + multiplyVector3Array: function() { + + var v1 = new THREE.Vector3(); + + return function ( a ) { + + for ( var i = 0, il = a.length; i < il; i += 3 ) { + + v1.x = a[ i ]; + v1.y = a[ i + 1 ]; + v1.z = a[ i + 2 ]; + + v1.applyMatrix3(this); + + a[ i ] = v1.x; + a[ i + 1 ] = v1.y; + a[ i + 2 ] = v1.z; + + } + + return a; + + }; + + }(), + + multiplyScalar: function ( s ) { + + var te = this.elements; + + te[0] *= s; te[3] *= s; te[6] *= s; + te[1] *= s; te[4] *= s; te[7] *= s; + te[2] *= s; te[5] *= s; te[8] *= s; + + return this; + + }, + + determinant: function () { + + var te = this.elements; + + var a = te[0], b = te[1], c = te[2], + d = te[3], e = te[4], f = te[5], + g = te[6], h = te[7], i = te[8]; + + return a*e*i - a*f*h - b*d*i + b*f*g + c*d*h - c*e*g; + + }, + + getInverse: function ( matrix, throwOnInvertible ) { + + // input: THREE.Matrix4 + // ( based on http://code.google.com/p/webgl-mjs/ ) + + var me = matrix.elements; + var te = this.elements; + + te[ 0 ] = me[10] * me[5] - me[6] * me[9]; + te[ 1 ] = - me[10] * me[1] + me[2] * me[9]; + te[ 2 ] = me[6] * me[1] - me[2] * me[5]; + te[ 3 ] = - me[10] * me[4] + me[6] * me[8]; + te[ 4 ] = me[10] * me[0] - me[2] * me[8]; + te[ 5 ] = - me[6] * me[0] + me[2] * me[4]; + te[ 6 ] = me[9] * me[4] - me[5] * me[8]; + te[ 7 ] = - me[9] * me[0] + me[1] * me[8]; + te[ 8 ] = me[5] * me[0] - me[1] * me[4]; + + var det = me[ 0 ] * te[ 0 ] + me[ 1 ] * te[ 3 ] + me[ 2 ] * te[ 6 ]; + + // no inverse + + if ( det === 0 ) { + + var msg = "Matrix3.getInverse(): can't invert matrix, determinant is 0"; + + if ( throwOnInvertible || false ) { + + throw new Error( msg ); + + } else { + + console.warn( msg ); + + } + + this.identity(); + + return this; + + } + + this.multiplyScalar( 1.0 / det ); + + return this; + + }, + + transpose: function () { + + var tmp, m = this.elements; + + tmp = m[1]; m[1] = m[3]; m[3] = tmp; + tmp = m[2]; m[2] = m[6]; m[6] = tmp; + tmp = m[5]; m[5] = m[7]; m[7] = tmp; + + return this; + + }, + + getNormalMatrix: function ( m ) { + + // input: THREE.Matrix4 + + this.getInverse( m ).transpose(); + + return this; + + }, + + transposeIntoArray: function ( r ) { + + var m = this.elements; + + r[ 0 ] = m[ 0 ]; + r[ 1 ] = m[ 3 ]; + r[ 2 ] = m[ 6 ]; + r[ 3 ] = m[ 1 ]; + r[ 4 ] = m[ 4 ]; + r[ 5 ] = m[ 7 ]; + r[ 6 ] = m[ 2 ]; + r[ 7 ] = m[ 5 ]; + r[ 8 ] = m[ 8 ]; + + return this; + + }, + + clone: function () { + + var te = this.elements; + + return new THREE.Matrix3( + + te[0], te[3], te[6], + te[1], te[4], te[7], + te[2], te[5], te[8] + + ); + + } + +} ); +/** + * @author mrdoob / http://mrdoob.com/ + * @author supereggbert / http://www.paulbrunt.co.uk/ + * @author philogb / http://blog.thejit.org/ + * @author jordi_ros / http://plattsoft.com + * @author D1plo1d / http://github.com/D1plo1d + * @author alteredq / http://alteredqualia.com/ + * @author mikael emtinger / http://gomo.se/ + * @author timknip / http://www.floorplanner.com/ + * @author bhouston / http://exocortex.com + */ + + +THREE.Matrix4 = function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { + + var te = this.elements = new Float32Array( 16 ); + + // TODO: if n11 is undefined, then just set to identity, otherwise copy all other values into matrix + // we should not support semi specification of Matrix4, it is just weird. + + te[0] = ( n11 !== undefined ) ? n11 : 1; te[4] = n12 || 0; te[8] = n13 || 0; te[12] = n14 || 0; + te[1] = n21 || 0; te[5] = ( n22 !== undefined ) ? n22 : 1; te[9] = n23 || 0; te[13] = n24 || 0; + te[2] = n31 || 0; te[6] = n32 || 0; te[10] = ( n33 !== undefined ) ? n33 : 1; te[14] = n34 || 0; + te[3] = n41 || 0; te[7] = n42 || 0; te[11] = n43 || 0; te[15] = ( n44 !== undefined ) ? n44 : 1; + +}; + +THREE.extend( THREE.Matrix4.prototype, { + + set: function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { + + var te = this.elements; + + te[0] = n11; te[4] = n12; te[8] = n13; te[12] = n14; + te[1] = n21; te[5] = n22; te[9] = n23; te[13] = n24; + te[2] = n31; te[6] = n32; te[10] = n33; te[14] = n34; + te[3] = n41; te[7] = n42; te[11] = n43; te[15] = n44; + + return this; + + }, + + identity: function () { + + this.set( + + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 + + ); + + return this; + + }, + + copy: function ( m ) { + + var me = m.elements; + + this.set( + + me[0], me[4], me[8], me[12], + me[1], me[5], me[9], me[13], + me[2], me[6], me[10], me[14], + me[3], me[7], me[11], me[15] + + ); + + return this; + + }, + + setRotationFromEuler: function ( v, order ) { + + var te = this.elements; + + var x = v.x, y = v.y, z = v.z; + var a = Math.cos( x ), b = Math.sin( x ); + var c = Math.cos( y ), d = Math.sin( y ); + var e = Math.cos( z ), f = Math.sin( z ); + + if ( order === undefined || order === 'XYZ' ) { + + var ae = a * e, af = a * f, be = b * e, bf = b * f; + + te[0] = c * e; + te[4] = - c * f; + te[8] = d; + + te[1] = af + be * d; + te[5] = ae - bf * d; + te[9] = - b * c; + + te[2] = bf - ae * d; + te[6] = be + af * d; + te[10] = a * c; + + } else if ( order === 'YXZ' ) { + + var ce = c * e, cf = c * f, de = d * e, df = d * f; + + te[0] = ce + df * b; + te[4] = de * b - cf; + te[8] = a * d; + + te[1] = a * f; + te[5] = a * e; + te[9] = - b; + + te[2] = cf * b - de; + te[6] = df + ce * b; + te[10] = a * c; + + } else if ( order === 'ZXY' ) { + + var ce = c * e, cf = c * f, de = d * e, df = d * f; + + te[0] = ce - df * b; + te[4] = - a * f; + te[8] = de + cf * b; + + te[1] = cf + de * b; + te[5] = a * e; + te[9] = df - ce * b; + + te[2] = - a * d; + te[6] = b; + te[10] = a * c; + + } else if ( order === 'ZYX' ) { + + var ae = a * e, af = a * f, be = b * e, bf = b * f; + + te[0] = c * e; + te[4] = be * d - af; + te[8] = ae * d + bf; + + te[1] = c * f; + te[5] = bf * d + ae; + te[9] = af * d - be; + + te[2] = - d; + te[6] = b * c; + te[10] = a * c; + + } else if ( order === 'YZX' ) { + + var ac = a * c, ad = a * d, bc = b * c, bd = b * d; + + te[0] = c * e; + te[4] = bd - ac * f; + te[8] = bc * f + ad; + + te[1] = f; + te[5] = a * e; + te[9] = - b * e; + + te[2] = - d * e; + te[6] = ad * f + bc; + te[10] = ac - bd * f; + + } else if ( order === 'XZY' ) { + + var ac = a * c, ad = a * d, bc = b * c, bd = b * d; + + te[0] = c * e; + te[4] = - f; + te[8] = d * e; + + te[1] = ac * f + bd; + te[5] = a * e; + te[9] = ad * f - bc; + + te[2] = bc * f - ad; + te[6] = b * e; + te[10] = bd * f + ac; + + } + + return this; + + }, + + setRotationFromQuaternion: function ( q ) { + + var te = this.elements; + + var x = q.x, y = q.y, z = q.z, w = q.w; + var x2 = x + x, y2 = y + y, z2 = z + z; + var xx = x * x2, xy = x * y2, xz = x * z2; + var yy = y * y2, yz = y * z2, zz = z * z2; + var wx = w * x2, wy = w * y2, wz = w * z2; + + te[0] = 1 - ( yy + zz ); + te[4] = xy - wz; + te[8] = xz + wy; + + te[1] = xy + wz; + te[5] = 1 - ( xx + zz ); + te[9] = yz - wx; + + te[2] = xz - wy; + te[6] = yz + wx; + te[10] = 1 - ( xx + yy ); + + return this; + + }, + + lookAt: function() { + + var x = new THREE.Vector3(); + var y = new THREE.Vector3(); + var z = new THREE.Vector3(); + + return function ( eye, target, up ) { + + var te = this.elements; + + z.subVectors( eye, target ).normalize(); + + if ( z.length() === 0 ) { + + z.z = 1; + + } + + x.crossVectors( up, z ).normalize(); + + if ( x.length() === 0 ) { + + z.x += 0.0001; + x.crossVectors( up, z ).normalize(); + + } + + y.crossVectors( z, x ); + + + te[0] = x.x; te[4] = y.x; te[8] = z.x; + te[1] = x.y; te[5] = y.y; te[9] = z.y; + te[2] = x.z; te[6] = y.z; te[10] = z.z; + + return this; + + }; + + }(), + + multiply: function ( m, n ) { + + if ( n !== undefined ) { + + console.warn( 'DEPRECATED: Matrix4\'s .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' ); + return this.multiplyMatrices( m, n ); + + } + + return this.multiplyMatrices( this, m ); + + }, + + multiplyMatrices: function ( a, b ) { + + var ae = a.elements; + var be = b.elements; + var te = this.elements; + + var a11 = ae[0], a12 = ae[4], a13 = ae[8], a14 = ae[12]; + var a21 = ae[1], a22 = ae[5], a23 = ae[9], a24 = ae[13]; + var a31 = ae[2], a32 = ae[6], a33 = ae[10], a34 = ae[14]; + var a41 = ae[3], a42 = ae[7], a43 = ae[11], a44 = ae[15]; + + var b11 = be[0], b12 = be[4], b13 = be[8], b14 = be[12]; + var b21 = be[1], b22 = be[5], b23 = be[9], b24 = be[13]; + var b31 = be[2], b32 = be[6], b33 = be[10], b34 = be[14]; + var b41 = be[3], b42 = be[7], b43 = be[11], b44 = be[15]; + + te[0] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41; + te[4] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42; + te[8] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43; + te[12] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44; + + te[1] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41; + te[5] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42; + te[9] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43; + te[13] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44; + + te[2] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41; + te[6] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42; + te[10] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43; + te[14] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44; + + te[3] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41; + te[7] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42; + te[11] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43; + te[15] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44; + + return this; + + }, + + multiplyToArray: function ( a, b, r ) { + + var te = this.elements; + + this.multiplyMatrices( a, b ); + + r[ 0 ] = te[0]; r[ 1 ] = te[1]; r[ 2 ] = te[2]; r[ 3 ] = te[3]; + r[ 4 ] = te[4]; r[ 5 ] = te[5]; r[ 6 ] = te[6]; r[ 7 ] = te[7]; + r[ 8 ] = te[8]; r[ 9 ] = te[9]; r[ 10 ] = te[10]; r[ 11 ] = te[11]; + r[ 12 ] = te[12]; r[ 13 ] = te[13]; r[ 14 ] = te[14]; r[ 15 ] = te[15]; + + return this; + + }, + + multiplyScalar: function ( s ) { + + var te = this.elements; + + te[0] *= s; te[4] *= s; te[8] *= s; te[12] *= s; + te[1] *= s; te[5] *= s; te[9] *= s; te[13] *= s; + te[2] *= s; te[6] *= s; te[10] *= s; te[14] *= s; + te[3] *= s; te[7] *= s; te[11] *= s; te[15] *= s; + + return this; + + }, + + multiplyVector3: function ( vector ) { + + console.warn( 'DEPRECATED: Matrix4\'s .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) or vector.applyProjection( matrix ) instead.' ); + return vector.applyProjection( this ); + + }, + + multiplyVector4: function ( vector ) { + + console.warn( 'DEPRECATED: Matrix4\'s .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); + return vector.applyMatrix4( this ); + + }, + + multiplyVector3Array: function() { + + var v1 = new THREE.Vector3(); + + return function ( a ) { + + for ( var i = 0, il = a.length; i < il; i += 3 ) { + + v1.x = a[ i ]; + v1.y = a[ i + 1 ]; + v1.z = a[ i + 2 ]; + + v1.applyProjection( this ); + + a[ i ] = v1.x; + a[ i + 1 ] = v1.y; + a[ i + 2 ] = v1.z; + + } + + return a; + + }; + + }(), + + rotateAxis: function ( v ) { + + var te = this.elements; + var vx = v.x, vy = v.y, vz = v.z; + + v.x = vx * te[0] + vy * te[4] + vz * te[8]; + v.y = vx * te[1] + vy * te[5] + vz * te[9]; + v.z = vx * te[2] + vy * te[6] + vz * te[10]; + + v.normalize(); + + return v; + + }, + + crossVector: function ( a ) { + + var te = this.elements; + var v = new THREE.Vector4(); + + v.x = te[0] * a.x + te[4] * a.y + te[8] * a.z + te[12] * a.w; + v.y = te[1] * a.x + te[5] * a.y + te[9] * a.z + te[13] * a.w; + v.z = te[2] * a.x + te[6] * a.y + te[10] * a.z + te[14] * a.w; + + v.w = ( a.w ) ? te[3] * a.x + te[7] * a.y + te[11] * a.z + te[15] * a.w : 1; + + return v; + + }, + + determinant: function () { + + var te = this.elements; + + var n11 = te[0], n12 = te[4], n13 = te[8], n14 = te[12]; + var n21 = te[1], n22 = te[5], n23 = te[9], n24 = te[13]; + var n31 = te[2], n32 = te[6], n33 = te[10], n34 = te[14]; + var n41 = te[3], n42 = te[7], n43 = te[11], n44 = te[15]; + + //TODO: make this more efficient + //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm ) + + return ( + n41 * ( + +n14 * n23 * n32 + -n13 * n24 * n32 + -n14 * n22 * n33 + +n12 * n24 * n33 + +n13 * n22 * n34 + -n12 * n23 * n34 + ) + + n42 * ( + +n11 * n23 * n34 + -n11 * n24 * n33 + +n14 * n21 * n33 + -n13 * n21 * n34 + +n13 * n24 * n31 + -n14 * n23 * n31 + ) + + n43 * ( + +n11 * n24 * n32 + -n11 * n22 * n34 + -n14 * n21 * n32 + +n12 * n21 * n34 + +n14 * n22 * n31 + -n12 * n24 * n31 + ) + + n44 * ( + -n13 * n22 * n31 + -n11 * n23 * n32 + +n11 * n22 * n33 + +n13 * n21 * n32 + -n12 * n21 * n33 + +n12 * n23 * n31 + ) + + ); + + }, + + transpose: function () { + + var te = this.elements; + var tmp; + + tmp = te[1]; te[1] = te[4]; te[4] = tmp; + tmp = te[2]; te[2] = te[8]; te[8] = tmp; + tmp = te[6]; te[6] = te[9]; te[9] = tmp; + + tmp = te[3]; te[3] = te[12]; te[12] = tmp; + tmp = te[7]; te[7] = te[13]; te[13] = tmp; + tmp = te[11]; te[11] = te[14]; te[14] = tmp; + + return this; + + }, + + flattenToArray: function ( flat ) { + + var te = this.elements; + flat[ 0 ] = te[0]; flat[ 1 ] = te[1]; flat[ 2 ] = te[2]; flat[ 3 ] = te[3]; + flat[ 4 ] = te[4]; flat[ 5 ] = te[5]; flat[ 6 ] = te[6]; flat[ 7 ] = te[7]; + flat[ 8 ] = te[8]; flat[ 9 ] = te[9]; flat[ 10 ] = te[10]; flat[ 11 ] = te[11]; + flat[ 12 ] = te[12]; flat[ 13 ] = te[13]; flat[ 14 ] = te[14]; flat[ 15 ] = te[15]; + + return flat; + + }, + + flattenToArrayOffset: function( flat, offset ) { + + var te = this.elements; + flat[ offset ] = te[0]; + flat[ offset + 1 ] = te[1]; + flat[ offset + 2 ] = te[2]; + flat[ offset + 3 ] = te[3]; + + flat[ offset + 4 ] = te[4]; + flat[ offset + 5 ] = te[5]; + flat[ offset + 6 ] = te[6]; + flat[ offset + 7 ] = te[7]; + + flat[ offset + 8 ] = te[8]; + flat[ offset + 9 ] = te[9]; + flat[ offset + 10 ] = te[10]; + flat[ offset + 11 ] = te[11]; + + flat[ offset + 12 ] = te[12]; + flat[ offset + 13 ] = te[13]; + flat[ offset + 14 ] = te[14]; + flat[ offset + 15 ] = te[15]; + + return flat; + + }, + + getPosition: function() { + + var v1 = new THREE.Vector3(); + + return function () { + + console.warn( 'DEPRECATED: Matrix4\'s .getPosition() has been removed. Use Vector3.getPositionFromMatrix( matrix ) instead.' ); + + var te = this.elements; + return v1.set( te[12], te[13], te[14] ); + + }; + + }(), + + setPosition: function ( v ) { + + var te = this.elements; + + te[12] = v.x; + te[13] = v.y; + te[14] = v.z; + + return this; + + }, + + getInverse: function ( m, throwOnInvertible ) { + + // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm + var te = this.elements; + var me = m.elements; + + var n11 = me[0], n12 = me[4], n13 = me[8], n14 = me[12]; + var n21 = me[1], n22 = me[5], n23 = me[9], n24 = me[13]; + var n31 = me[2], n32 = me[6], n33 = me[10], n34 = me[14]; + var n41 = me[3], n42 = me[7], n43 = me[11], n44 = me[15]; + + te[0] = n23*n34*n42 - n24*n33*n42 + n24*n32*n43 - n22*n34*n43 - n23*n32*n44 + n22*n33*n44; + te[4] = n14*n33*n42 - n13*n34*n42 - n14*n32*n43 + n12*n34*n43 + n13*n32*n44 - n12*n33*n44; + te[8] = n13*n24*n42 - n14*n23*n42 + n14*n22*n43 - n12*n24*n43 - n13*n22*n44 + n12*n23*n44; + te[12] = n14*n23*n32 - n13*n24*n32 - n14*n22*n33 + n12*n24*n33 + n13*n22*n34 - n12*n23*n34; + te[1] = n24*n33*n41 - n23*n34*n41 - n24*n31*n43 + n21*n34*n43 + n23*n31*n44 - n21*n33*n44; + te[5] = n13*n34*n41 - n14*n33*n41 + n14*n31*n43 - n11*n34*n43 - n13*n31*n44 + n11*n33*n44; + te[9] = n14*n23*n41 - n13*n24*n41 - n14*n21*n43 + n11*n24*n43 + n13*n21*n44 - n11*n23*n44; + te[13] = n13*n24*n31 - n14*n23*n31 + n14*n21*n33 - n11*n24*n33 - n13*n21*n34 + n11*n23*n34; + te[2] = n22*n34*n41 - n24*n32*n41 + n24*n31*n42 - n21*n34*n42 - n22*n31*n44 + n21*n32*n44; + te[6] = n14*n32*n41 - n12*n34*n41 - n14*n31*n42 + n11*n34*n42 + n12*n31*n44 - n11*n32*n44; + te[10] = n12*n24*n41 - n14*n22*n41 + n14*n21*n42 - n11*n24*n42 - n12*n21*n44 + n11*n22*n44; + te[14] = n14*n22*n31 - n12*n24*n31 - n14*n21*n32 + n11*n24*n32 + n12*n21*n34 - n11*n22*n34; + te[3] = n23*n32*n41 - n22*n33*n41 - n23*n31*n42 + n21*n33*n42 + n22*n31*n43 - n21*n32*n43; + te[7] = n12*n33*n41 - n13*n32*n41 + n13*n31*n42 - n11*n33*n42 - n12*n31*n43 + n11*n32*n43; + te[11] = n13*n22*n41 - n12*n23*n41 - n13*n21*n42 + n11*n23*n42 + n12*n21*n43 - n11*n22*n43; + te[15] = n12*n23*n31 - n13*n22*n31 + n13*n21*n32 - n11*n23*n32 - n12*n21*n33 + n11*n22*n33; + + var det = me[ 0 ] * te[ 0 ] + me[ 1 ] * te[ 4 ] + me[ 2 ] * te[ 8 ] + me[ 3 ] * te[ 12 ]; + + if ( det == 0 ) { + + var msg = "Matrix4.getInverse(): can't invert matrix, determinant is 0"; + + if ( throwOnInvertible || false ) { + + throw new Error( msg ); + + } else { + + console.warn( msg ); + + } + + this.identity(); + + return this; + } + + this.multiplyScalar( 1 / det ); + + return this; + + }, + + compose: function() { + + var mRotation = new THREE.Matrix4(), + mScale = new THREE.Matrix4(); + + return function ( translation, rotation, scale ) { + + var te = this.elements; + + mRotation.identity(); + mRotation.setRotationFromQuaternion( rotation ); + + mScale.makeScale( scale.x, scale.y, scale.z ); + + this.multiplyMatrices( mRotation, mScale ); + + te[12] = translation.x; + te[13] = translation.y; + te[14] = translation.z; + + return this; + + }; + + }(), + + decompose: function() { + + var x = new THREE.Vector3(), + y = new THREE.Vector3(), + z = new THREE.Vector3(), + matrix = new THREE.Matrix4(); + + return function ( translation, rotation, scale ) { + + var te = this.elements; + + // grab the axis vectors + x.set( te[0], te[1], te[2] ); + y.set( te[4], te[5], te[6] ); + z.set( te[8], te[9], te[10] ); + + translation = ( translation instanceof THREE.Vector3 ) ? translation : new THREE.Vector3(); + rotation = ( rotation instanceof THREE.Quaternion ) ? rotation : new THREE.Quaternion(); + scale = ( scale instanceof THREE.Vector3 ) ? scale : new THREE.Vector3(); + + scale.x = x.length(); + scale.y = y.length(); + scale.z = z.length(); + + translation.x = te[12]; + translation.y = te[13]; + translation.z = te[14]; + + // scale the rotation part + + matrix.copy( this ); + + matrix.elements[0] /= scale.x; + matrix.elements[1] /= scale.x; + matrix.elements[2] /= scale.x; + + matrix.elements[4] /= scale.y; + matrix.elements[5] /= scale.y; + matrix.elements[6] /= scale.y; + + matrix.elements[8] /= scale.z; + matrix.elements[9] /= scale.z; + matrix.elements[10] /= scale.z; + + rotation.setFromRotationMatrix( matrix ); + + return [ translation, rotation, scale ]; + + }; + + }(), + + extractPosition: function ( m ) { + + var te = this.elements; + var me = m.elements; + + te[12] = me[12]; + te[13] = me[13]; + te[14] = me[14]; + + return this; + + }, + + extractRotation: function() { + + var v1 = new THREE.Vector3(); + + return function ( m ) { + + var te = this.elements; + var me = m.elements; + + var scaleX = 1 / v1.set( me[0], me[1], me[2] ).length(); + var scaleY = 1 / v1.set( me[4], me[5], me[6] ).length(); + var scaleZ = 1 / v1.set( me[8], me[9], me[10] ).length(); + + te[0] = me[0] * scaleX; + te[1] = me[1] * scaleX; + te[2] = me[2] * scaleX; + + te[4] = me[4] * scaleY; + te[5] = me[5] * scaleY; + te[6] = me[6] * scaleY; + + te[8] = me[8] * scaleZ; + te[9] = me[9] * scaleZ; + te[10] = me[10] * scaleZ; + + return this; + + }; + + }(), + + translate: function ( v ) { + + var te = this.elements; + var x = v.x, y = v.y, z = v.z; + + te[12] = te[0] * x + te[4] * y + te[8] * z + te[12]; + te[13] = te[1] * x + te[5] * y + te[9] * z + te[13]; + te[14] = te[2] * x + te[6] * y + te[10] * z + te[14]; + te[15] = te[3] * x + te[7] * y + te[11] * z + te[15]; + + return this; + + }, + + rotateX: function ( angle ) { + + var te = this.elements; + var m12 = te[4]; + var m22 = te[5]; + var m32 = te[6]; + var m42 = te[7]; + var m13 = te[8]; + var m23 = te[9]; + var m33 = te[10]; + var m43 = te[11]; + var c = Math.cos( angle ); + var s = Math.sin( angle ); + + te[4] = c * m12 + s * m13; + te[5] = c * m22 + s * m23; + te[6] = c * m32 + s * m33; + te[7] = c * m42 + s * m43; + + te[8] = c * m13 - s * m12; + te[9] = c * m23 - s * m22; + te[10] = c * m33 - s * m32; + te[11] = c * m43 - s * m42; + + return this; + + }, + + rotateY: function ( angle ) { + + var te = this.elements; + var m11 = te[0]; + var m21 = te[1]; + var m31 = te[2]; + var m41 = te[3]; + var m13 = te[8]; + var m23 = te[9]; + var m33 = te[10]; + var m43 = te[11]; + var c = Math.cos( angle ); + var s = Math.sin( angle ); + + te[0] = c * m11 - s * m13; + te[1] = c * m21 - s * m23; + te[2] = c * m31 - s * m33; + te[3] = c * m41 - s * m43; + + te[8] = c * m13 + s * m11; + te[9] = c * m23 + s * m21; + te[10] = c * m33 + s * m31; + te[11] = c * m43 + s * m41; + + return this; + + }, + + rotateZ: function ( angle ) { + + var te = this.elements; + var m11 = te[0]; + var m21 = te[1]; + var m31 = te[2]; + var m41 = te[3]; + var m12 = te[4]; + var m22 = te[5]; + var m32 = te[6]; + var m42 = te[7]; + var c = Math.cos( angle ); + var s = Math.sin( angle ); + + te[0] = c * m11 + s * m12; + te[1] = c * m21 + s * m22; + te[2] = c * m31 + s * m32; + te[3] = c * m41 + s * m42; + + te[4] = c * m12 - s * m11; + te[5] = c * m22 - s * m21; + te[6] = c * m32 - s * m31; + te[7] = c * m42 - s * m41; + + return this; + + }, + + rotateByAxis: function ( axis, angle ) { + + var te = this.elements; + + // optimize by checking axis + + if ( axis.x === 1 && axis.y === 0 && axis.z === 0 ) { + + return this.rotateX( angle ); + + } else if ( axis.x === 0 && axis.y === 1 && axis.z === 0 ) { + + return this.rotateY( angle ); + + } else if ( axis.x === 0 && axis.y === 0 && axis.z === 1 ) { + + return this.rotateZ( angle ); + + } + + var x = axis.x, y = axis.y, z = axis.z; + var n = Math.sqrt(x * x + y * y + z * z); + + x /= n; + y /= n; + z /= n; + + var xx = x * x, yy = y * y, zz = z * z; + var c = Math.cos( angle ); + var s = Math.sin( angle ); + var oneMinusCosine = 1 - c; + var xy = x * y * oneMinusCosine; + var xz = x * z * oneMinusCosine; + var yz = y * z * oneMinusCosine; + var xs = x * s; + var ys = y * s; + var zs = z * s; + + var r11 = xx + (1 - xx) * c; + var r21 = xy + zs; + var r31 = xz - ys; + var r12 = xy - zs; + var r22 = yy + (1 - yy) * c; + var r32 = yz + xs; + var r13 = xz + ys; + var r23 = yz - xs; + var r33 = zz + (1 - zz) * c; + + var m11 = te[0], m21 = te[1], m31 = te[2], m41 = te[3]; + var m12 = te[4], m22 = te[5], m32 = te[6], m42 = te[7]; + var m13 = te[8], m23 = te[9], m33 = te[10], m43 = te[11]; + + te[0] = r11 * m11 + r21 * m12 + r31 * m13; + te[1] = r11 * m21 + r21 * m22 + r31 * m23; + te[2] = r11 * m31 + r21 * m32 + r31 * m33; + te[3] = r11 * m41 + r21 * m42 + r31 * m43; + + te[4] = r12 * m11 + r22 * m12 + r32 * m13; + te[5] = r12 * m21 + r22 * m22 + r32 * m23; + te[6] = r12 * m31 + r22 * m32 + r32 * m33; + te[7] = r12 * m41 + r22 * m42 + r32 * m43; + + te[8] = r13 * m11 + r23 * m12 + r33 * m13; + te[9] = r13 * m21 + r23 * m22 + r33 * m23; + te[10] = r13 * m31 + r23 * m32 + r33 * m33; + te[11] = r13 * m41 + r23 * m42 + r33 * m43; + + return this; + + }, + + scale: function ( v ) { + + var te = this.elements; + var x = v.x, y = v.y, z = v.z; + + te[0] *= x; te[4] *= y; te[8] *= z; + te[1] *= x; te[5] *= y; te[9] *= z; + te[2] *= x; te[6] *= y; te[10] *= z; + te[3] *= x; te[7] *= y; te[11] *= z; + + return this; + + }, + + getMaxScaleOnAxis: function () { + + var te = this.elements; + + var scaleXSq = te[0] * te[0] + te[1] * te[1] + te[2] * te[2]; + var scaleYSq = te[4] * te[4] + te[5] * te[5] + te[6] * te[6]; + var scaleZSq = te[8] * te[8] + te[9] * te[9] + te[10] * te[10]; + + return Math.sqrt( Math.max( scaleXSq, Math.max( scaleYSq, scaleZSq ) ) ); + + }, + + makeTranslation: function ( x, y, z ) { + + this.set( + + 1, 0, 0, x, + 0, 1, 0, y, + 0, 0, 1, z, + 0, 0, 0, 1 + + ); + + return this; + + }, + + makeRotationX: function ( theta ) { + + var c = Math.cos( theta ), s = Math.sin( theta ); + + this.set( + + 1, 0, 0, 0, + 0, c, -s, 0, + 0, s, c, 0, + 0, 0, 0, 1 + + ); + + return this; + + }, + + makeRotationY: function ( theta ) { + + var c = Math.cos( theta ), s = Math.sin( theta ); + + this.set( + + c, 0, s, 0, + 0, 1, 0, 0, + -s, 0, c, 0, + 0, 0, 0, 1 + + ); + + return this; + + }, + + makeRotationZ: function ( theta ) { + + var c = Math.cos( theta ), s = Math.sin( theta ); + + this.set( + + c, -s, 0, 0, + s, c, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 + + ); + + return this; + + }, + + makeRotationAxis: function ( axis, angle ) { + + // Based on http://www.gamedev.net/reference/articles/article1199.asp + + var c = Math.cos( angle ); + var s = Math.sin( angle ); + var t = 1 - c; + var x = axis.x, y = axis.y, z = axis.z; + var tx = t * x, ty = t * y; + + this.set( + + tx * x + c, tx * y - s * z, tx * z + s * y, 0, + tx * y + s * z, ty * y + c, ty * z - s * x, 0, + tx * z - s * y, ty * z + s * x, t * z * z + c, 0, + 0, 0, 0, 1 + + ); + + return this; + + }, + + makeScale: function ( x, y, z ) { + + this.set( + + x, 0, 0, 0, + 0, y, 0, 0, + 0, 0, z, 0, + 0, 0, 0, 1 + + ); + + return this; + + }, + + makeFrustum: function ( left, right, bottom, top, near, far ) { + + var te = this.elements; + var x = 2 * near / ( right - left ); + var y = 2 * near / ( top - bottom ); + + var a = ( right + left ) / ( right - left ); + var b = ( top + bottom ) / ( top - bottom ); + var c = - ( far + near ) / ( far - near ); + var d = - 2 * far * near / ( far - near ); + + te[0] = x; te[4] = 0; te[8] = a; te[12] = 0; + te[1] = 0; te[5] = y; te[9] = b; te[13] = 0; + te[2] = 0; te[6] = 0; te[10] = c; te[14] = d; + te[3] = 0; te[7] = 0; te[11] = - 1; te[15] = 0; + + return this; + + }, + + makePerspective: function ( fov, aspect, near, far ) { + + var ymax = near * Math.tan( THREE.Math.degToRad( fov * 0.5 ) ); + var ymin = - ymax; + var xmin = ymin * aspect; + var xmax = ymax * aspect; + + return this.makeFrustum( xmin, xmax, ymin, ymax, near, far ); + + }, + + makeOrthographic: function ( left, right, top, bottom, near, far ) { + + var te = this.elements; + var w = right - left; + var h = top - bottom; + var p = far - near; + + var x = ( right + left ) / w; + var y = ( top + bottom ) / h; + var z = ( far + near ) / p; + + te[0] = 2 / w; te[4] = 0; te[8] = 0; te[12] = -x; + te[1] = 0; te[5] = 2 / h; te[9] = 0; te[13] = -y; + te[2] = 0; te[6] = 0; te[10] = -2/p; te[14] = -z; + te[3] = 0; te[7] = 0; te[11] = 0; te[15] = 1; + + return this; + + }, + + clone: function () { + + var te = this.elements; + + return new THREE.Matrix4( + + te[0], te[4], te[8], te[12], + te[1], te[5], te[9], te[13], + te[2], te[6], te[10], te[14], + te[3], te[7], te[11], te[15] + + ); + + } + +} ); +/** + * @author bhouston / http://exocortex.com + */ + +THREE.Ray = function ( origin, direction ) { + + this.origin = ( origin !== undefined ) ? origin : new THREE.Vector3(); + this.direction = ( direction !== undefined ) ? direction : new THREE.Vector3(); + +}; + +THREE.extend( THREE.Ray.prototype, { + + set: function ( origin, direction ) { + + this.origin.copy( origin ); + this.direction.copy( direction ); + + return this; + + }, + + copy: function ( ray ) { + + this.origin.copy( ray.origin ); + this.direction.copy( ray.direction ); + + return this; + + }, + + at: function( t, optionalTarget ) { + + var result = optionalTarget || new THREE.Vector3(); + + return result.copy( this.direction ).multiplyScalar( t ).add( this.origin ); + + }, + + recast: function() { + + var v1 = new THREE.Vector3(); + + return function ( t ) { + + this.origin.copy( this.at( t, v1 ) ); + + return this; + + }; + + }(), + + closestPointToPoint: function ( point, optionalTarget ) { + + var result = optionalTarget || new THREE.Vector3(); + result.subVectors( point, this.origin ); + var directionDistance = result.dot( this.direction ); + + return result.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); + + }, + + distanceToPoint: function() { + + var v1 = new THREE.Vector3(); + + return function ( point ) { + + var directionDistance = v1.subVectors( point, this.origin ).dot( this.direction ); + v1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); + + return v1.distanceTo( point ); + + }; + + }(), + + isIntersectionSphere: function( sphere ) { + + return ( this.distanceToPoint( sphere.center ) <= sphere.radius ); + + }, + + isIntersectionPlane: function ( plane ) { + + // check if the line and plane are non-perpendicular, if they + // eventually they will intersect. + var denominator = plane.normal.dot( this.direction ); + if ( denominator != 0 ) { + + return true; + + } + + // line is coplanar, return origin + if( plane.distanceToPoint( this.origin ) == 0 ) { + + return true; + + } + + return false; + + }, + + distanceToPlane: function ( plane ) { + + var denominator = plane.normal.dot( this.direction ); + if ( denominator == 0 ) { + + // line is coplanar, return origin + if( plane.distanceToPoint( this.origin ) == 0 ) { + + return 0; + + } + + // Unsure if this is the correct method to handle this case. + return undefined; + + } + + var t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator; + + return t; + + }, + + intersectPlane: function ( plane, optionalTarget ) { + + var t = this.distanceToPlane( plane ); + + if ( t === undefined ) { + + return undefined; + } + + return this.at( t, optionalTarget ); + + }, + + applyMatrix4: function ( matrix4 ) { + + this.direction.add( this.origin ).applyMatrix4( matrix4 ); + this.origin.applyMatrix4( matrix4 ); + this.direction.sub( this.origin ); + + return this; + }, + + equals: function ( ray ) { + + return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction ); + + }, + + clone: function () { + + return new THREE.Ray().copy( this ); + + } + +} ); +/** + * @author bhouston / http://exocortex.com + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.Sphere = function ( center, radius ) { + + this.center = ( center !== undefined ) ? center : new THREE.Vector3(); + this.radius = ( radius !== undefined ) ? radius : 0; + +}; + +THREE.extend( THREE.Sphere.prototype, { + + set: function ( center, radius ) { + + this.center.copy( center ); + this.radius = radius; + + return this; + }, + + setFromCenterAndPoints: function ( center, points ) { + + var maxRadiusSq = 0; + + for ( var i = 0, il = points.length; i < il; i ++ ) { + + var radiusSq = center.distanceToSquared( points[ i ] ); + maxRadiusSq = Math.max( maxRadiusSq, radiusSq ); + + } + + this.center = center; + this.radius = Math.sqrt( maxRadiusSq ); + + return this; + + }, + + copy: function ( sphere ) { + + this.center.copy( sphere.center ); + this.radius = sphere.radius; + + return this; + + }, + + empty: function () { + + return ( this.radius <= 0 ); + + }, + + containsPoint: function ( point ) { + + return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) ); + + }, + + distanceToPoint: function ( point ) { + + return ( point.distanceTo( this.center ) - this.radius ); + + }, + + intersectsSphere: function ( sphere ) { + + var radiusSum = this.radius + sphere.radius; + + return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum ); + + }, + + clampPoint: function ( point, optionalTarget ) { + + var deltaLengthSq = this.center.distanceToSquared( point ); + + var result = optionalTarget || new THREE.Vector3(); + result.copy( point ); + + if ( deltaLengthSq > ( this.radius * this.radius ) ) { + + result.sub( this.center ).normalize(); + result.multiplyScalar( this.radius ).add( this.center ); + + } + + return result; + + }, + + getBoundingBox: function ( optionalTarget ) { + + var box = optionalTarget || new THREE.Box3(); + + box.set( this.center, this.center ); + box.expandByScalar( this.radius ); + + return box; + + }, + + applyMatrix4: function ( matrix ) { + + this.center.applyMatrix4( matrix ); + this.radius = this.radius * matrix.getMaxScaleOnAxis(); + + return this; + + }, + + translate: function ( offset ) { + + this.center.add( offset ); + + return this; + + }, + + equals: function ( sphere ) { + + return sphere.center.equals( this.center ) && ( sphere.radius === this.radius ); + + }, + + clone: function () { + + return new THREE.Sphere().copy( this ); + + } + +} ); +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * @author bhouston / http://exocortex.com + */ + +THREE.Frustum = function ( p0, p1, p2, p3, p4, p5 ) { + + this.planes = [ + + ( p0 !== undefined ) ? p0 : new THREE.Plane(), + ( p1 !== undefined ) ? p1 : new THREE.Plane(), + ( p2 !== undefined ) ? p2 : new THREE.Plane(), + ( p3 !== undefined ) ? p3 : new THREE.Plane(), + ( p4 !== undefined ) ? p4 : new THREE.Plane(), + ( p5 !== undefined ) ? p5 : new THREE.Plane() + + ]; + +}; + +THREE.extend( THREE.Frustum.prototype, { + + set: function ( p0, p1, p2, p3, p4, p5 ) { + + var planes = this.planes; + + planes[0].copy( p0 ); + planes[1].copy( p1 ); + planes[2].copy( p2 ); + planes[3].copy( p3 ); + planes[4].copy( p4 ); + planes[5].copy( p5 ); + + return this; + + }, + + copy: function ( frustum ) { + + var planes = this.planes; + + for( var i = 0; i < 6; i ++ ) { + + planes[i].copy( frustum.planes[i] ); + + } + + return this; + + }, + + setFromMatrix: function ( m ) { + + var planes = this.planes; + var me = m.elements; + var me0 = me[0], me1 = me[1], me2 = me[2], me3 = me[3]; + var me4 = me[4], me5 = me[5], me6 = me[6], me7 = me[7]; + var me8 = me[8], me9 = me[9], me10 = me[10], me11 = me[11]; + var me12 = me[12], me13 = me[13], me14 = me[14], me15 = me[15]; + + planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize(); + planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize(); + planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize(); + planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize(); + planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize(); + planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize(); + + return this; + + }, + + intersectsObject: function () { + + var center = new THREE.Vector3(); + + return function ( object ) { + + // this method is expanded inlined for performance reasons. + + var matrix = object.matrixWorld; + var planes = this.planes; + var negRadius = - object.geometry.boundingSphere.radius * matrix.getMaxScaleOnAxis(); + + center.getPositionFromMatrix( matrix ); + + for ( var i = 0; i < 6; i ++ ) { + + var distance = planes[ i ].distanceToPoint( center ); + + if ( distance < negRadius ) { + + return false; + + } + + } + + return true; + + }; + + }(), + + intersectsSphere: function ( sphere ) { + + var planes = this.planes; + var center = sphere.center; + var negRadius = -sphere.radius; + + for ( var i = 0; i < 6; i ++ ) { + + var distance = planes[ i ].distanceToPoint( center ); + + if ( distance < negRadius ) { + + return false; + + } + + } + + return true; + + }, + + containsPoint: function ( point ) { + + var planes = this.planes; + + for ( var i = 0; i < 6; i ++ ) { + + if ( planes[ i ].distanceToPoint( point ) < 0 ) { + + return false; + + } + + } + + return true; + + }, + + clone: function () { + + return new THREE.Frustum().copy( this ); + + } + +} ); +/** + * @author bhouston / http://exocortex.com + */ + +THREE.Plane = function ( normal, constant ) { + + this.normal = ( normal !== undefined ) ? normal : new THREE.Vector3( 1, 0, 0 ); + this.constant = ( constant !== undefined ) ? constant : 0; + +}; + +THREE.extend( THREE.Plane.prototype, { + + set: function ( normal, constant ) { + + this.normal.copy( normal ); + this.constant = constant; + + return this; + + }, + + setComponents: function ( x, y, z, w ) { + + this.normal.set( x, y, z ); + this.constant = w; + + return this; + + }, + + setFromNormalAndCoplanarPoint: function ( normal, point ) { + + this.normal.copy( normal ); + this.constant = - point.dot( this.normal ); // must be this.normal, not normal, as this.normal is normalized + + return this; + + }, + + setFromCoplanarPoints: function() { + + var v1 = new THREE.Vector3(); + var v2 = new THREE.Vector3(); + + return function ( a, b, c ) { + + var normal = v1.subVectors( c, b ).cross( v2.subVectors( a, b ) ).normalize(); + + // Q: should an error be thrown if normal is zero (e.g. degenerate plane)? + + this.setFromNormalAndCoplanarPoint( normal, a ); + + return this; + + }; + + }(), + + + copy: function ( plane ) { + + this.normal.copy( plane.normal ); + this.constant = plane.constant; + + return this; + + }, + + normalize: function () { + + // Note: will lead to a divide by zero if the plane is invalid. + + var inverseNormalLength = 1.0 / this.normal.length(); + this.normal.multiplyScalar( inverseNormalLength ); + this.constant *= inverseNormalLength; + + return this; + + }, + + negate: function () { + + this.constant *= -1; + this.normal.negate(); + + return this; + + }, + + distanceToPoint: function ( point ) { + + return this.normal.dot( point ) + this.constant; + + }, + + distanceToSphere: function ( sphere ) { + + return this.distanceToPoint( sphere.center ) - sphere.radius; + + }, + + projectPoint: function ( point, optionalTarget ) { + + return this.orthoPoint( point, optionalTarget ).sub( point ).negate(); + + }, + + orthoPoint: function ( point, optionalTarget ) { + + var perpendicularMagnitude = this.distanceToPoint( point ); + + var result = optionalTarget || new THREE.Vector3(); + return result.copy( this.normal ).multiplyScalar( perpendicularMagnitude ); + + }, + + isIntersectionLine: function ( line ) { + + // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it. + + var startSign = this.distanceToPoint( line.start ); + var endSign = this.distanceToPoint( line.end ); + + return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 ); + + }, + + intersectLine: function() { + + var v1 = new THREE.Vector3(); + + return function ( line, optionalTarget ) { + + var result = optionalTarget || new THREE.Vector3(); + + var direction = line.delta( v1 ); + + var denominator = this.normal.dot( direction ); + + if ( denominator == 0 ) { + + // line is coplanar, return origin + if( this.distanceToPoint( line.start ) == 0 ) { + + return result.copy( line.start ); + + } + + // Unsure if this is the correct method to handle this case. + return undefined; + + } + + var t = - ( line.start.dot( this.normal ) + this.constant ) / denominator; + + if( t < 0 || t > 1 ) { + + return undefined; + + } + + return result.copy( direction ).multiplyScalar( t ).add( line.start ); + + }; + + }(), + + + coplanarPoint: function ( optionalTarget ) { + + var result = optionalTarget || new THREE.Vector3(); + return result.copy( this.normal ).multiplyScalar( - this.constant ); + + }, + + applyMatrix4: function() { + + var v1 = new THREE.Vector3(); + var v2 = new THREE.Vector3(); + + return function ( matrix, optionalNormalMatrix ) { + + // compute new normal based on theory here: + // http://www.songho.ca/opengl/gl_normaltransform.html + optionalNormalMatrix = optionalNormalMatrix || new THREE.Matrix3().getInverse( matrix ).transpose(); + var newNormal = v1.copy( this.normal ).applyMatrix3( optionalNormalMatrix ); + + var newCoplanarPoint = this.coplanarPoint( v2 ); + newCoplanarPoint.applyMatrix4( matrix ); + + this.setFromNormalAndCoplanarPoint( newNormal, newCoplanarPoint ); + + return this; + + }; + + }(), + + translate: function ( offset ) { + + this.constant = this.constant - offset.dot( this.normal ); + + return this; + + }, + + equals: function ( plane ) { + + return plane.normal.equals( this.normal ) && ( plane.constant == this.constant ); + + }, + + clone: function () { + + return new THREE.Plane().copy( this ); + + } + +} ); +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Math = { + + // Clamp value to range <a, b> + + clamp: function ( x, a, b ) { + + return ( x < a ) ? a : ( ( x > b ) ? b : x ); + + }, + + // Clamp value to range <a, inf) + + clampBottom: function ( x, a ) { + + return x < a ? a : x; + + }, + + // Linear mapping from range <a1, a2> to range <b1, b2> + + mapLinear: function ( x, a1, a2, b1, b2 ) { + + return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 ); + + }, + + // http://en.wikipedia.org/wiki/Smoothstep + + smoothstep: function ( x, min, max ) { + + if ( x <= min ) return 0; + if ( x >= max ) return 1; + + x = ( x - min )/( max - min ); + + return x*x*(3 - 2*x); + + }, + + smootherstep: function ( x, min, max ) { + + if ( x <= min ) return 0; + if ( x >= max ) return 1; + + x = ( x - min )/( max - min ); + + return x*x*x*(x*(x*6 - 15) + 10); + + }, + + // Random float from <0, 1> with 16 bits of randomness + // (standard Math.random() creates repetitive patterns when applied over larger space) + + random16: function () { + + return ( 65280 * Math.random() + 255 * Math.random() ) / 65535; + + }, + + // Random integer from <low, high> interval + + randInt: function ( low, high ) { + + return low + Math.floor( Math.random() * ( high - low + 1 ) ); + + }, + + // Random float from <low, high> interval + + randFloat: function ( low, high ) { + + return low + Math.random() * ( high - low ); + + }, + + // Random float from <-range/2, range/2> interval + + randFloatSpread: function ( range ) { + + return range * ( 0.5 - Math.random() ); + + }, + + sign: function ( x ) { + + return ( x < 0 ) ? -1 : ( ( x > 0 ) ? 1 : 0 ); + + }, + + degToRad: function() { + + var degreeToRadiansFactor = Math.PI / 180; + + return function ( degrees ) { + + return degrees * degreeToRadiansFactor; + + }; + + }(), + + radToDeg: function() { + + var radianToDegreesFactor = 180 / Math.PI; + + return function ( radians ) { + + return radians * radianToDegreesFactor; + + }; + + }() + +}; +/** + * Spline from Tween.js, slightly optimized (and trashed) + * http://sole.github.com/tween.js/examples/05_spline.html + * + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Spline = function ( points ) { + + this.points = points; + + var c = [], v3 = { x: 0, y: 0, z: 0 }, + point, intPoint, weight, w2, w3, + pa, pb, pc, pd; + + this.initFromArray = function( a ) { + + this.points = []; + + for ( var i = 0; i < a.length; i++ ) { + + this.points[ i ] = { x: a[ i ][ 0 ], y: a[ i ][ 1 ], z: a[ i ][ 2 ] }; + + } + + }; + + this.getPoint = function ( k ) { + + point = ( this.points.length - 1 ) * k; + intPoint = Math.floor( point ); + weight = point - intPoint; + + c[ 0 ] = intPoint === 0 ? intPoint : intPoint - 1; + c[ 1 ] = intPoint; + c[ 2 ] = intPoint > this.points.length - 2 ? this.points.length - 1 : intPoint + 1; + c[ 3 ] = intPoint > this.points.length - 3 ? this.points.length - 1 : intPoint + 2; + + pa = this.points[ c[ 0 ] ]; + pb = this.points[ c[ 1 ] ]; + pc = this.points[ c[ 2 ] ]; + pd = this.points[ c[ 3 ] ]; + + w2 = weight * weight; + w3 = weight * w2; + + v3.x = interpolate( pa.x, pb.x, pc.x, pd.x, weight, w2, w3 ); + v3.y = interpolate( pa.y, pb.y, pc.y, pd.y, weight, w2, w3 ); + v3.z = interpolate( pa.z, pb.z, pc.z, pd.z, weight, w2, w3 ); + + return v3; + + }; + + this.getControlPointsArray = function () { + + var i, p, l = this.points.length, + coords = []; + + for ( i = 0; i < l; i ++ ) { + + p = this.points[ i ]; + coords[ i ] = [ p.x, p.y, p.z ]; + + } + + return coords; + + }; + + // approximate length by summing linear segments + + this.getLength = function ( nSubDivisions ) { + + var i, index, nSamples, position, + point = 0, intPoint = 0, oldIntPoint = 0, + oldPosition = new THREE.Vector3(), + tmpVec = new THREE.Vector3(), + chunkLengths = [], + totalLength = 0; + + // first point has 0 length + + chunkLengths[ 0 ] = 0; + + if ( !nSubDivisions ) nSubDivisions = 100; + + nSamples = this.points.length * nSubDivisions; + + oldPosition.copy( this.points[ 0 ] ); + + for ( i = 1; i < nSamples; i ++ ) { + + index = i / nSamples; + + position = this.getPoint( index ); + tmpVec.copy( position ); + + totalLength += tmpVec.distanceTo( oldPosition ); + + oldPosition.copy( position ); + + point = ( this.points.length - 1 ) * index; + intPoint = Math.floor( point ); + + if ( intPoint != oldIntPoint ) { + + chunkLengths[ intPoint ] = totalLength; + oldIntPoint = intPoint; + + } + + } + + // last point ends with total length + + chunkLengths[ chunkLengths.length ] = totalLength; + + return { chunks: chunkLengths, total: totalLength }; + + }; + + this.reparametrizeByArcLength = function ( samplingCoef ) { + + var i, j, + index, indexCurrent, indexNext, + linearDistance, realDistance, + sampling, position, + newpoints = [], + tmpVec = new THREE.Vector3(), + sl = this.getLength(); + + newpoints.push( tmpVec.copy( this.points[ 0 ] ).clone() ); + + for ( i = 1; i < this.points.length; i++ ) { + + //tmpVec.copy( this.points[ i - 1 ] ); + //linearDistance = tmpVec.distanceTo( this.points[ i ] ); + + realDistance = sl.chunks[ i ] - sl.chunks[ i - 1 ]; + + sampling = Math.ceil( samplingCoef * realDistance / sl.total ); + + indexCurrent = ( i - 1 ) / ( this.points.length - 1 ); + indexNext = i / ( this.points.length - 1 ); + + for ( j = 1; j < sampling - 1; j++ ) { + + index = indexCurrent + j * ( 1 / sampling ) * ( indexNext - indexCurrent ); + + position = this.getPoint( index ); + newpoints.push( tmpVec.copy( position ).clone() ); + + } + + newpoints.push( tmpVec.copy( this.points[ i ] ).clone() ); + + } + + this.points = newpoints; + + }; + + // Catmull-Rom + + function interpolate( p0, p1, p2, p3, t, t2, t3 ) { + + var v0 = ( p2 - p0 ) * 0.5, + v1 = ( p3 - p1 ) * 0.5; + + return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1; + + }; + +}; +/** + * @author bhouston / http://exocortex.com + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.Triangle = function ( a, b, c ) { + + this.a = ( a !== undefined ) ? a : new THREE.Vector3(); + this.b = ( b !== undefined ) ? b : new THREE.Vector3(); + this.c = ( c !== undefined ) ? c : new THREE.Vector3(); + +}; + +THREE.Triangle.normal = function() { + + var v0 = new THREE.Vector3(); + + return function( a, b, c, optionalTarget ) { + + var result = optionalTarget || new THREE.Vector3(); + + result.subVectors( c, b ); + v0.subVectors( a, b ); + result.cross( v0 ); + + var resultLengthSq = result.lengthSq(); + if( resultLengthSq > 0 ) { + + return result.multiplyScalar( 1 / Math.sqrt( resultLengthSq ) ); + + } + + return result.set( 0, 0, 0 ); + + }; + +}(); + +// static/instance method to calculate barycoordinates +// based on: http://www.blackpawn.com/texts/pointinpoly/default.html +THREE.Triangle.barycoordFromPoint = function() { + + var v0 = new THREE.Vector3(), + v1 = new THREE.Vector3(), + v2 = new THREE.Vector3(); + + return function ( point, a, b, c, optionalTarget ) { + + v0.subVectors( c, a ); + v1.subVectors( b, a ); + v2.subVectors( point, a ); + + var dot00 = v0.dot( v0 ); + var dot01 = v0.dot( v1 ); + var dot02 = v0.dot( v2 ); + var dot11 = v1.dot( v1 ); + var dot12 = v1.dot( v2 ); + + var denom = ( dot00 * dot11 - dot01 * dot01 ); + + var result = optionalTarget || new THREE.Vector3(); + + // colinear or singular triangle + if( denom == 0 ) { + // arbitrary location outside of triangle? + // not sure if this is the best idea, maybe should be returning undefined + return result.set( -2, -1, -1 ); + } + + var invDenom = 1 / denom; + var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom; + var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom; + + // barycoordinates must always sum to 1 + return result.set( 1 - u - v, v, u ); + + }; + +}(); + +THREE.Triangle.containsPoint = function() { + + var v1 = new THREE.Vector3(); + + return function ( point, a, b, c ) { + + var result = THREE.Triangle.barycoordFromPoint( point, a, b, c, v1 ); + + return ( result.x >= 0 ) && ( result.y >= 0 ) && ( ( result.x + result.y ) <= 1 ); + + }; + +}(); + +THREE.extend( THREE.Triangle.prototype, { + + constructor: THREE.Triangle, + + set: function ( a, b, c ) { + + this.a.copy( a ); + this.b.copy( b ); + this.c.copy( c ); + + return this; + + }, + + setFromPointsAndIndices: function ( points, i0, i1, i2 ) { + + this.a.copy( points[i0] ); + this.b.copy( points[i1] ); + this.c.copy( points[i2] ); + + return this; + + }, + + copy: function ( triangle ) { + + this.a.copy( triangle.a ); + this.b.copy( triangle.b ); + this.c.copy( triangle.c ); + + return this; + + }, + + area: function() { + + var v0 = new THREE.Vector3(); + var v1 = new THREE.Vector3(); + + return function () { + + v0.subVectors( this.c, this.b ); + v1.subVectors( this.a, this.b ); + + return v0.cross( v1 ).length() * 0.5; + + }; + + }(), + + midpoint: function ( optionalTarget ) { + + var result = optionalTarget || new THREE.Vector3(); + return result.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 ); + + }, + + normal: function ( optionalTarget ) { + + return THREE.Triangle.normal( this.a, this.b, this.c, optionalTarget ); + + }, + + plane: function ( optionalTarget ) { + + var result = optionalTarget || new THREE.Plane(); + + return result.setFromCoplanarPoints( this.a, this.b, this.c ); + + }, + + barycoordFromPoint: function ( point, optionalTarget ) { + + return THREE.Triangle.barycoordFromPoint( point, this.a, this.b, this.c, optionalTarget ); + + }, + + containsPoint: function ( point ) { + + return THREE.Triangle.containsPoint( point, this.a, this.b, this.c ); + + }, + + equals: function ( triangle ) { + + return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c ); + + }, + + clone: function () { + + return new THREE.Triangle().copy( this ); + + } + +} ); +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.Vertex = function ( v ) { + + console.warn( 'THREE.Vertex has been DEPRECATED. Use THREE.Vector3 instead.') + return v; + +}; +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.UV = function ( u, v ) { + + console.warn( 'THREE.UV has been DEPRECATED. Use THREE.Vector2 instead.') + return new THREE.Vector2( u, v ); + +}; +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Clock = function ( autoStart ) { + + this.autoStart = ( autoStart !== undefined ) ? autoStart : true; + + this.startTime = 0; + this.oldTime = 0; + this.elapsedTime = 0; + + this.running = false; + +}; + +THREE.extend( THREE.Clock.prototype, { + + start: function () { + + this.startTime = window.performance !== undefined && window.performance.now !== undefined + ? window.performance.now() + : Date.now(); + + this.oldTime = this.startTime; + this.running = true; + }, + + stop: function () { + + this.getElapsedTime(); + this.running = false; + + }, + + getElapsedTime: function () { + + this.getDelta(); + return this.elapsedTime; + + }, + + getDelta: function () { + + var diff = 0; + + if ( this.autoStart && ! this.running ) { + + this.start(); + + } + + if ( this.running ) { + + var newTime = window.performance !== undefined && window.performance.now !== undefined + ? window.performance.now() + : Date.now(); + + diff = 0.001 * ( newTime - this.oldTime ); + this.oldTime = newTime; + + this.elapsedTime += diff; + + } + + return diff; + + } + +} ); +/** + * https://github.com/mrdoob/eventdispatcher.js/ + */ + +THREE.EventDispatcher = function () { + + var listeners = {}; + + this.addEventListener = function ( type, listener ) { + + if ( listeners[ type ] === undefined ) { + + listeners[ type ] = []; + + } + + if ( listeners[ type ].indexOf( listener ) === - 1 ) { + + listeners[ type ].push( listener ); + + } + + }; + + this.removeEventListener = function ( type, listener ) { + + var index = listeners[ type ].indexOf( listener ); + + if ( index !== - 1 ) { + + listeners[ type ].splice( index, 1 ); + + } + + }; + + this.dispatchEvent = function ( event ) { + + var listenerArray = listeners[ event.type ]; + + if ( listenerArray !== undefined ) { + + event.target = this; + + for ( var i = 0, l = listenerArray.length; i < l; i ++ ) { + + listenerArray[ i ].call( this, event ); + + } + + } + + }; + +}; +/** + * @author mrdoob / http://mrdoob.com/ + * @author bhouston / http://exocortex.com/ + */ + +( function ( THREE ) { + + THREE.Raycaster = function ( origin, direction, near, far ) { + + this.ray = new THREE.Ray( origin, direction ); + + // normalized ray.direction required for accurate distance calculations + if( this.ray.direction.lengthSq() > 0 ) { + + this.ray.direction.normalize(); + + } + + this.near = near || 0; + this.far = far || Infinity; + + }; + + var sphere = new THREE.Sphere(); + var localRay = new THREE.Ray(); + var facePlane = new THREE.Plane(); + var intersectPoint = new THREE.Vector3(); + var matrixPosition = new THREE.Vector3(); + + var inverseMatrix = new THREE.Matrix4(); + + var descSort = function ( a, b ) { + + return a.distance - b.distance; + + }; + + var intersectObject = function ( object, raycaster, intersects ) { + + if ( object instanceof THREE.Particle ) { + + matrixPosition.getPositionFromMatrix( object.matrixWorld ); + var distance = raycaster.ray.distanceToPoint( matrixPosition ); + + if ( distance > object.scale.x ) { + + return intersects; + + } + + intersects.push( { + + distance: distance, + point: object.position, + face: null, + object: object + + } ); + + } else if ( object instanceof THREE.Mesh ) { + + // Checking boundingSphere distance to ray + matrixPosition.getPositionFromMatrix( object.matrixWorld ); + sphere.set( + matrixPosition, + object.geometry.boundingSphere.radius * object.matrixWorld.getMaxScaleOnAxis() ); + + if ( ! raycaster.ray.isIntersectionSphere( sphere ) ) { + + return intersects; + + } + + // Checking faces + + var geometry = object.geometry; + var vertices = geometry.vertices; + + var isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial; + var objectMaterials = isFaceMaterial === true ? object.material.materials : null; + + var side = object.material.side; + + var a, b, c, d; + var precision = raycaster.precision; + + object.matrixRotationWorld.extractRotation( object.matrixWorld ); + + inverseMatrix.getInverse( object.matrixWorld ); + + localRay.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); + + for ( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) { + + var face = geometry.faces[ f ]; + + var material = isFaceMaterial === true ? objectMaterials[ face.materialIndex ] : object.material; + + if ( material === undefined ) continue; + + facePlane.setFromNormalAndCoplanarPoint( face.normal, vertices[face.a] ); + + var planeDistance = localRay.distanceToPlane( facePlane ); + + // bail if raycaster and plane are parallel + if ( Math.abs( planeDistance ) < precision ) continue; + + // if negative distance, then plane is behind raycaster + if ( planeDistance < 0 ) continue; + + // check if we hit the wrong side of a single sided face + side = material.side; + if( side !== THREE.DoubleSide ) { + + var planeSign = localRay.direction.dot( facePlane.normal ); + + if( ! ( side === THREE.FrontSide ? planeSign < 0 : planeSign > 0 ) ) continue; + + } + + // this can be done using the planeDistance from localRay because localRay wasn't normalized, but ray was + if ( planeDistance < raycaster.near || planeDistance > raycaster.far ) continue; + + intersectPoint = localRay.at( planeDistance, intersectPoint ); // passing in intersectPoint avoids a copy + + if ( face instanceof THREE.Face3 ) { + + a = vertices[ face.a ]; + b = vertices[ face.b ]; + c = vertices[ face.c ]; + + if ( ! THREE.Triangle.containsPoint( intersectPoint, a, b, c ) ) continue; + + } else if ( face instanceof THREE.Face4 ) { + + a = vertices[ face.a ]; + b = vertices[ face.b ]; + c = vertices[ face.c ]; + d = vertices[ face.d ]; + + if ( ( ! THREE.Triangle.containsPoint( intersectPoint, a, b, d ) ) && + ( ! THREE.Triangle.containsPoint( intersectPoint, b, c, d ) ) ) continue; + + } else { + + // This is added because if we call out of this if/else group when none of the cases + // match it will add a point to the intersection list erroneously. + throw Error( "face type not supported" ); + + } + + intersects.push( { + + distance: planeDistance, // this works because the original ray was normalized, and the transformed localRay wasn't + point: raycaster.ray.at( planeDistance ), + face: face, + faceIndex: f, + object: object + + } ); + + } + + } + + }; + + var intersectDescendants = function ( object, raycaster, intersects ) { + + var descendants = object.getDescendants(); + + for ( var i = 0, l = descendants.length; i < l; i ++ ) { + + intersectObject( descendants[ i ], raycaster, intersects ); + + } + }; + + // + + THREE.Raycaster.prototype.precision = 0.0001; + + THREE.Raycaster.prototype.set = function ( origin, direction ) { + + this.ray.set( origin, direction ); + + // normalized ray.direction required for accurate distance calculations + if( this.ray.direction.length() > 0 ) { + + this.ray.direction.normalize(); + + } + + }; + + THREE.Raycaster.prototype.intersectObject = function ( object, recursive ) { + + var intersects = []; + + if ( recursive === true ) { + + intersectDescendants( object, this, intersects ); + + } + + intersectObject( object, this, intersects ); + + intersects.sort( descSort ); + + return intersects; + + }; + + THREE.Raycaster.prototype.intersectObjects = function ( objects, recursive ) { + + var intersects = []; + + for ( var i = 0, l = objects.length; i < l; i ++ ) { + + intersectObject( objects[ i ], this, intersects ); + + if ( recursive === true ) { + + intersectDescendants( objects[ i ], this, intersects ); + + } + } + + intersects.sort( descSort ); + + return intersects; + + }; + +}( THREE ) ); +/** + * @author mrdoob / http://mrdoob.com/ + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Object3D = function () { + + this.id = THREE.Object3DIdCount ++; + + this.name = ''; + this.properties = {}; + + this.parent = undefined; + this.children = []; + + this.up = new THREE.Vector3( 0, 1, 0 ); + + this.position = new THREE.Vector3(); + this.rotation = new THREE.Vector3(); + this.eulerOrder = THREE.Object3D.defaultEulerOrder; + this.scale = new THREE.Vector3( 1, 1, 1 ); + + this.renderDepth = null; + + this.rotationAutoUpdate = true; + + this.matrix = new THREE.Matrix4(); + this.matrixWorld = new THREE.Matrix4(); + this.matrixRotationWorld = new THREE.Matrix4(); + + this.matrixAutoUpdate = true; + this.matrixWorldNeedsUpdate = true; + + this.quaternion = new THREE.Quaternion(); + this.useQuaternion = false; + + this.visible = true; + + this.castShadow = false; + this.receiveShadow = false; + + this.frustumCulled = true; + + this._vector = new THREE.Vector3(); + +}; + + +THREE.Object3D.prototype = { + + constructor: THREE.Object3D, + + applyMatrix: function ( matrix ) { + + this.matrix.multiplyMatrices( matrix, this.matrix ); + + this.scale.getScaleFromMatrix( this.matrix ); + + var mat = new THREE.Matrix4().extractRotation( this.matrix ); + this.rotation.setEulerFromRotationMatrix( mat, this.eulerOrder ); + + this.position.getPositionFromMatrix( this.matrix ); + + }, + + translate: function ( distance, axis ) { + + this.matrix.rotateAxis( axis ); + this.position.add( axis.multiplyScalar( distance ) ); + + }, + + translateX: function ( distance ) { + + this.translate( distance, this._vector.set( 1, 0, 0 ) ); + + }, + + translateY: function ( distance ) { + + this.translate( distance, this._vector.set( 0, 1, 0 ) ); + + }, + + translateZ: function ( distance ) { + + this.translate( distance, this._vector.set( 0, 0, 1 ) ); + + }, + + localToWorld: function ( vector ) { + + return vector.applyMatrix4( this.matrixWorld ); + + }, + + worldToLocal: function ( vector ) { + + return vector.applyMatrix4( THREE.Object3D.__m1.getInverse( this.matrixWorld ) ); + + }, + + lookAt: function ( vector ) { + + // TODO: Add hierarchy support. + + this.matrix.lookAt( vector, this.position, this.up ); + + if ( this.rotationAutoUpdate ) { + + if ( this.useQuaternion === false ) { + + this.rotation.setEulerFromRotationMatrix( this.matrix, this.eulerOrder ); + + } else { + + this.quaternion.copy( this.matrix.decompose()[ 1 ] ); + + } + + } + + }, + + add: function ( object ) { + + if ( object === this ) { + + console.warn( 'THREE.Object3D.add: An object can\'t be added as a child of itself.' ); + return; + + } + + if ( object instanceof THREE.Object3D ) { + + if ( object.parent !== undefined ) { + + object.parent.remove( object ); + + } + + object.parent = this; + this.children.push( object ); + + // add to scene + + var scene = this; + + while ( scene.parent !== undefined ) { + + scene = scene.parent; + + } + + if ( scene !== undefined && scene instanceof THREE.Scene ) { + + scene.__addObject( object ); + + } + + } + + }, + + remove: function ( object ) { + + var index = this.children.indexOf( object ); + + if ( index !== - 1 ) { + + object.parent = undefined; + this.children.splice( index, 1 ); + + // remove from scene + + var scene = this; + + while ( scene.parent !== undefined ) { + + scene = scene.parent; + + } + + if ( scene !== undefined && scene instanceof THREE.Scene ) { + + scene.__removeObject( object ); + + } + + } + + }, + + traverse: function ( callback ) { + + callback( this ); + + for ( var i = 0, l = this.children.length; i < l; i ++ ) { + + this.children[ i ].traverse( callback ); + + } + + }, + + getChildByName: function ( name, recursive ) { + + for ( var i = 0, l = this.children.length; i < l; i ++ ) { + + var child = this.children[ i ]; + + if ( child.name === name ) { + + return child; + + } + + if ( recursive === true ) { + + child = child.getChildByName( name, recursive ); + + if ( child !== undefined ) { + + return child; + + } + + } + + } + + return undefined; + + }, + + getDescendants: function ( array ) { + + if ( array === undefined ) array = []; + + Array.prototype.push.apply( array, this.children ); + + for ( var i = 0, l = this.children.length; i < l; i ++ ) { + + this.children[ i ].getDescendants( array ); + + } + + return array; + + }, + + updateMatrix: function () { + + this.matrix.setPosition( this.position ); + + if ( this.useQuaternion === false ) { + + this.matrix.setRotationFromEuler( this.rotation, this.eulerOrder ); + + } else { + + this.matrix.setRotationFromQuaternion( this.quaternion ); + + } + + if ( this.scale.x !== 1 || this.scale.y !== 1 || this.scale.z !== 1 ) { + + this.matrix.scale( this.scale ); + + } + + this.matrixWorldNeedsUpdate = true; + + }, + + updateMatrixWorld: function ( force ) { + + if ( this.matrixAutoUpdate === true ) this.updateMatrix(); + + if ( this.matrixWorldNeedsUpdate === true || force === true ) { + + if ( this.parent === undefined ) { + + this.matrixWorld.copy( this.matrix ); + + } else { + + this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); + + } + + this.matrixWorldNeedsUpdate = false; + + force = true; + + } + + // update children + + for ( var i = 0, l = this.children.length; i < l; i ++ ) { + + this.children[ i ].updateMatrixWorld( force ); + + } + + }, + + clone: function ( object ) { + + if ( object === undefined ) object = new THREE.Object3D(); + + object.name = this.name; + + object.up.copy( this.up ); + + object.position.copy( this.position ); + if ( object.rotation instanceof THREE.Vector3 ) object.rotation.copy( this.rotation ); // because of Sprite madness + object.eulerOrder = this.eulerOrder; + object.scale.copy( this.scale ); + + object.renderDepth = this.renderDepth; + + object.rotationAutoUpdate = this.rotationAutoUpdate; + + object.matrix.copy( this.matrix ); + object.matrixWorld.copy( this.matrixWorld ); + object.matrixRotationWorld.copy( this.matrixRotationWorld ); + + object.matrixAutoUpdate = this.matrixAutoUpdate; + object.matrixWorldNeedsUpdate = this.matrixWorldNeedsUpdate; + + object.quaternion.copy( this.quaternion ); + object.useQuaternion = this.useQuaternion; + + object.visible = this.visible; + + object.castShadow = this.castShadow; + object.receiveShadow = this.receiveShadow; + + object.frustumCulled = this.frustumCulled; + + for ( var i = 0; i < this.children.length; i ++ ) { + + var child = this.children[ i ]; + object.add( child.clone() ); + + } + + return object; + + } + +}; + +THREE.Object3D.__m1 = new THREE.Matrix4(); +THREE.Object3D.defaultEulerOrder = 'XYZ', + +THREE.Object3DIdCount = 0; +/** + * @author mrdoob / http://mrdoob.com/ + * @author supereggbert / http://www.paulbrunt.co.uk/ + * @author julianwa / https://github.com/julianwa + */ + +THREE.Projector = function () { + + var _object, _objectCount, _objectPool = [], _objectPoolLength = 0, + _vertex, _vertexCount, _vertexPool = [], _vertexPoolLength = 0, + _face, _face3Count, _face3Pool = [], _face3PoolLength = 0, + _face4Count, _face4Pool = [], _face4PoolLength = 0, + _line, _lineCount, _linePool = [], _linePoolLength = 0, + _particle, _particleCount, _particlePool = [], _particlePoolLength = 0, + + _renderData = { objects: [], sprites: [], lights: [], elements: [] }, + + _vector3 = new THREE.Vector3(), + _vector4 = new THREE.Vector4(), + + _clipBox = new THREE.Box3( new THREE.Vector3( -1, -1, -1 ), new THREE.Vector3( 1, 1, 1 ) ), + _boundingBox = new THREE.Box3(), + _points3 = new Array( 3 ), + _points4 = new Array( 4 ), + + _viewMatrix = new THREE.Matrix4(), + _viewProjectionMatrix = new THREE.Matrix4(), + + _modelMatrix, + _modelViewProjectionMatrix = new THREE.Matrix4(), + + _normalMatrix = new THREE.Matrix3(), + _normalViewMatrix = new THREE.Matrix3(), + + _centroid = new THREE.Vector3(), + + _frustum = new THREE.Frustum(), + + _clippedVertex1PositionScreen = new THREE.Vector4(), + _clippedVertex2PositionScreen = new THREE.Vector4(); + + this.projectVector = function ( vector, camera ) { + + camera.matrixWorldInverse.getInverse( camera.matrixWorld ); + + _viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); + + return vector.applyProjection( _viewProjectionMatrix ); + + }; + + this.unprojectVector = function ( vector, camera ) { + + camera.projectionMatrixInverse.getInverse( camera.projectionMatrix ); + + _viewProjectionMatrix.multiplyMatrices( camera.matrixWorld, camera.projectionMatrixInverse ); + + return vector.applyProjection( _viewProjectionMatrix ); + + }; + + this.pickingRay = function ( vector, camera ) { + + // set two vectors with opposing z values + vector.z = -1.0; + var end = new THREE.Vector3( vector.x, vector.y, 1.0 ); + + this.unprojectVector( vector, camera ); + this.unprojectVector( end, camera ); + + // find direction from vector to end + end.sub( vector ).normalize(); + + return new THREE.Raycaster( vector, end ); + + }; + + var projectGraph = function ( root, sortObjects ) { + + _objectCount = 0; + + _renderData.objects.length = 0; + _renderData.sprites.length = 0; + _renderData.lights.length = 0; + + var projectObject = function ( parent ) { + + for ( var c = 0, cl = parent.children.length; c < cl; c ++ ) { + + var object = parent.children[ c ]; + + if ( object.visible === false ) continue; + + if ( object instanceof THREE.Light ) { + + _renderData.lights.push( object ); + + } else if ( object instanceof THREE.Mesh || object instanceof THREE.Line ) { + + if ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) { + + _object = getNextObjectInPool(); + _object.object = object; + + if ( object.renderDepth !== null ) { + + _object.z = object.renderDepth; + + } else { + + _vector3.getPositionFromMatrix( object.matrixWorld ); + _vector3.applyProjection( _viewProjectionMatrix ); + _object.z = _vector3.z; + + } + + _renderData.objects.push( _object ); + + } + + } else if ( object instanceof THREE.Sprite || object instanceof THREE.Particle ) { + + _object = getNextObjectInPool(); + _object.object = object; + + // TODO: Find an elegant and performant solution and remove this dupe code. + + if ( object.renderDepth !== null ) { + + _object.z = object.renderDepth; + + } else { + + _vector3.getPositionFromMatrix( object.matrixWorld ); + _vector3.applyProjection( _viewProjectionMatrix ); + _object.z = _vector3.z; + + } + + _renderData.sprites.push( _object ); + + } else { + + _object = getNextObjectInPool(); + _object.object = object; + + if ( object.renderDepth !== null ) { + + _object.z = object.renderDepth; + + } else { + + _vector3.getPositionFromMatrix( object.matrixWorld ); + _vector3.applyProjection( _viewProjectionMatrix ); + _object.z = _vector3.z; + + } + + _renderData.objects.push( _object ); + + } + + projectObject( object ); + + } + + }; + + projectObject( root ); + + if ( sortObjects === true ) _renderData.objects.sort( painterSort ); + + return _renderData; + + }; + + this.projectScene = function ( scene, camera, sortObjects, sortElements ) { + + var visible = false, + o, ol, v, vl, f, fl, n, nl, c, cl, u, ul, object, + geometry, vertices, faces, face, faceVertexNormals, faceVertexUvs, uvs, + v1, v2, v3, v4, isFaceMaterial, objectMaterials; + + _face3Count = 0; + _face4Count = 0; + _lineCount = 0; + _particleCount = 0; + + _renderData.elements.length = 0; + + scene.updateMatrixWorld(); + + if ( camera.parent === undefined ) camera.updateMatrixWorld(); + + _viewMatrix.copy( camera.matrixWorldInverse.getInverse( camera.matrixWorld ) ); + _viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, _viewMatrix ); + + _normalViewMatrix.getInverse( _viewMatrix ); + _normalViewMatrix.transpose(); + + _frustum.setFromMatrix( _viewProjectionMatrix ); + + _renderData = projectGraph( scene, sortObjects ); + + for ( o = 0, ol = _renderData.objects.length; o < ol; o ++ ) { + + object = _renderData.objects[ o ].object; + + _modelMatrix = object.matrixWorld; + + _vertexCount = 0; + + if ( object instanceof THREE.Mesh ) { + + geometry = object.geometry; + + vertices = geometry.vertices; + faces = geometry.faces; + faceVertexUvs = geometry.faceVertexUvs; + + _normalMatrix.getInverse( _modelMatrix ); + _normalMatrix.transpose(); + + isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial; + objectMaterials = isFaceMaterial === true ? object.material : null; + + for ( v = 0, vl = vertices.length; v < vl; v ++ ) { + + _vertex = getNextVertexInPool(); + + _vertex.positionWorld.copy( vertices[ v ] ).applyMatrix4( _modelMatrix ); + _vertex.positionScreen.copy( _vertex.positionWorld ).applyMatrix4( _viewProjectionMatrix ); + + _vertex.positionScreen.x /= _vertex.positionScreen.w; + _vertex.positionScreen.y /= _vertex.positionScreen.w; + _vertex.positionScreen.z /= _vertex.positionScreen.w; + + _vertex.visible = ! ( _vertex.positionScreen.x < -1 || _vertex.positionScreen.x > 1 || + _vertex.positionScreen.y < -1 || _vertex.positionScreen.y > 1 || + _vertex.positionScreen.z < -1 || _vertex.positionScreen.z > 1 ); + + } + + for ( f = 0, fl = faces.length; f < fl; f ++ ) { + + face = faces[ f ]; + + var material = isFaceMaterial === true + ? objectMaterials.materials[ face.materialIndex ] + : object.material; + + if ( material === undefined ) continue; + + var side = material.side; + + if ( face instanceof THREE.Face3 ) { + + v1 = _vertexPool[ face.a ]; + v2 = _vertexPool[ face.b ]; + v3 = _vertexPool[ face.c ]; + + _points3[ 0 ] = v1.positionScreen; + _points3[ 1 ] = v2.positionScreen; + _points3[ 2 ] = v3.positionScreen; + + if ( v1.visible === true || v2.visible === true || v3.visible === true || + _clipBox.isIntersectionBox( _boundingBox.setFromPoints( _points3 ) ) ) { + + visible = ( ( v3.positionScreen.x - v1.positionScreen.x ) * ( v2.positionScreen.y - v1.positionScreen.y ) - + ( v3.positionScreen.y - v1.positionScreen.y ) * ( v2.positionScreen.x - v1.positionScreen.x ) ) < 0; + + if ( side === THREE.DoubleSide || visible === ( side === THREE.FrontSide ) ) { + + _face = getNextFace3InPool(); + + _face.v1.copy( v1 ); + _face.v2.copy( v2 ); + _face.v3.copy( v3 ); + + } else { + + continue; + + } + + } else { + + continue; + + } + + } else if ( face instanceof THREE.Face4 ) { + + v1 = _vertexPool[ face.a ]; + v2 = _vertexPool[ face.b ]; + v3 = _vertexPool[ face.c ]; + v4 = _vertexPool[ face.d ]; + + _points4[ 0 ] = v1.positionScreen; + _points4[ 1 ] = v2.positionScreen; + _points4[ 2 ] = v3.positionScreen; + _points4[ 3 ] = v4.positionScreen; + + if ( v1.visible === true || v2.visible === true || v3.visible === true || v4.visible === true || + _clipBox.isIntersectionBox( _boundingBox.setFromPoints( _points4 ) ) ) { + + visible = ( v4.positionScreen.x - v1.positionScreen.x ) * ( v2.positionScreen.y - v1.positionScreen.y ) - + ( v4.positionScreen.y - v1.positionScreen.y ) * ( v2.positionScreen.x - v1.positionScreen.x ) < 0 || + ( v2.positionScreen.x - v3.positionScreen.x ) * ( v4.positionScreen.y - v3.positionScreen.y ) - + ( v2.positionScreen.y - v3.positionScreen.y ) * ( v4.positionScreen.x - v3.positionScreen.x ) < 0; + + + if ( side === THREE.DoubleSide || visible === ( side === THREE.FrontSide ) ) { + + _face = getNextFace4InPool(); + + _face.v1.copy( v1 ); + _face.v2.copy( v2 ); + _face.v3.copy( v3 ); + _face.v4.copy( v4 ); + + } else { + + continue; + + } + + } else { + + continue; + + } + + } + + _face.normalModel.copy( face.normal ); + + if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) { + + _face.normalModel.negate(); + + } + + _face.normalModel.applyMatrix3( _normalMatrix ).normalize(); + + _face.normalModelView.copy( _face.normalModel ).applyMatrix3( _normalViewMatrix ); + + _face.centroidModel.copy( face.centroid ).applyMatrix4( _modelMatrix ); + + faceVertexNormals = face.vertexNormals; + + for ( n = 0, nl = faceVertexNormals.length; n < nl; n ++ ) { + + var normalModel = _face.vertexNormalsModel[ n ]; + normalModel.copy( faceVertexNormals[ n ] ); + + if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) { + + normalModel.negate(); + + } + + normalModel.applyMatrix3( _normalMatrix ).normalize(); + + var normalModelView = _face.vertexNormalsModelView[ n ]; + normalModelView.copy( normalModel ).applyMatrix3( _normalViewMatrix ); + + } + + _face.vertexNormalsLength = faceVertexNormals.length; + + for ( c = 0, cl = faceVertexUvs.length; c < cl; c ++ ) { + + uvs = faceVertexUvs[ c ][ f ]; + + if ( uvs === undefined ) continue; + + for ( u = 0, ul = uvs.length; u < ul; u ++ ) { + + _face.uvs[ c ][ u ] = uvs[ u ]; + + } + + } + + _face.color = face.color; + _face.material = material; + + _centroid.copy( _face.centroidModel ).applyProjection( _viewProjectionMatrix ); + + _face.z = _centroid.z; + + _renderData.elements.push( _face ); + + } + + } else if ( object instanceof THREE.Line ) { + + _modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix ); + + vertices = object.geometry.vertices; + + v1 = getNextVertexInPool(); + v1.positionScreen.copy( vertices[ 0 ] ).applyMatrix4( _modelViewProjectionMatrix ); + + // Handle LineStrip and LinePieces + var step = object.type === THREE.LinePieces ? 2 : 1; + + for ( v = 1, vl = vertices.length; v < vl; v ++ ) { + + v1 = getNextVertexInPool(); + v1.positionScreen.copy( vertices[ v ] ).applyMatrix4( _modelViewProjectionMatrix ); + + if ( ( v + 1 ) % step > 0 ) continue; + + v2 = _vertexPool[ _vertexCount - 2 ]; + + _clippedVertex1PositionScreen.copy( v1.positionScreen ); + _clippedVertex2PositionScreen.copy( v2.positionScreen ); + + if ( clipLine( _clippedVertex1PositionScreen, _clippedVertex2PositionScreen ) === true ) { + + // Perform the perspective divide + _clippedVertex1PositionScreen.multiplyScalar( 1 / _clippedVertex1PositionScreen.w ); + _clippedVertex2PositionScreen.multiplyScalar( 1 / _clippedVertex2PositionScreen.w ); + + _line = getNextLineInPool(); + _line.v1.positionScreen.copy( _clippedVertex1PositionScreen ); + _line.v2.positionScreen.copy( _clippedVertex2PositionScreen ); + + _line.z = Math.max( _clippedVertex1PositionScreen.z, _clippedVertex2PositionScreen.z ); + + _line.material = object.material; + + _renderData.elements.push( _line ); + + } + + } + + } + + } + + for ( o = 0, ol = _renderData.sprites.length; o < ol; o++ ) { + + object = _renderData.sprites[ o ].object; + + _modelMatrix = object.matrixWorld; + + if ( object instanceof THREE.Particle ) { + + _vector4.set( _modelMatrix.elements[12], _modelMatrix.elements[13], _modelMatrix.elements[14], 1 ); + _vector4.applyMatrix4( _viewProjectionMatrix ); + + _vector4.z /= _vector4.w; + + if ( _vector4.z > 0 && _vector4.z < 1 ) { + + _particle = getNextParticleInPool(); + _particle.object = object; + _particle.x = _vector4.x / _vector4.w; + _particle.y = _vector4.y / _vector4.w; + _particle.z = _vector4.z; + + _particle.rotation = object.rotation.z; + + _particle.scale.x = object.scale.x * Math.abs( _particle.x - ( _vector4.x + camera.projectionMatrix.elements[0] ) / ( _vector4.w + camera.projectionMatrix.elements[12] ) ); + _particle.scale.y = object.scale.y * Math.abs( _particle.y - ( _vector4.y + camera.projectionMatrix.elements[5] ) / ( _vector4.w + camera.projectionMatrix.elements[13] ) ); + + _particle.material = object.material; + + _renderData.elements.push( _particle ); + + } + + } + + } + + if ( sortElements === true ) _renderData.elements.sort( painterSort ); + + return _renderData; + + }; + + // Pools + + function getNextObjectInPool() { + + if ( _objectCount === _objectPoolLength ) { + + var object = new THREE.RenderableObject(); + _objectPool.push( object ); + _objectPoolLength ++; + _objectCount ++; + return object; + + } + + return _objectPool[ _objectCount ++ ]; + + } + + function getNextVertexInPool() { + + if ( _vertexCount === _vertexPoolLength ) { + + var vertex = new THREE.RenderableVertex(); + _vertexPool.push( vertex ); + _vertexPoolLength ++; + _vertexCount ++; + return vertex; + + } + + return _vertexPool[ _vertexCount ++ ]; + + } + + function getNextFace3InPool() { + + if ( _face3Count === _face3PoolLength ) { + + var face = new THREE.RenderableFace3(); + _face3Pool.push( face ); + _face3PoolLength ++; + _face3Count ++; + return face; + + } + + return _face3Pool[ _face3Count ++ ]; + + + } + + function getNextFace4InPool() { + + if ( _face4Count === _face4PoolLength ) { + + var face = new THREE.RenderableFace4(); + _face4Pool.push( face ); + _face4PoolLength ++; + _face4Count ++; + return face; + + } + + return _face4Pool[ _face4Count ++ ]; + + } + + function getNextLineInPool() { + + if ( _lineCount === _linePoolLength ) { + + var line = new THREE.RenderableLine(); + _linePool.push( line ); + _linePoolLength ++; + _lineCount ++ + return line; + + } + + return _linePool[ _lineCount ++ ]; + + } + + function getNextParticleInPool() { + + if ( _particleCount === _particlePoolLength ) { + + var particle = new THREE.RenderableParticle(); + _particlePool.push( particle ); + _particlePoolLength ++; + _particleCount ++ + return particle; + + } + + return _particlePool[ _particleCount ++ ]; + + } + + // + + function painterSort( a, b ) { + + return b.z - a.z; + + } + + function clipLine( s1, s2 ) { + + var alpha1 = 0, alpha2 = 1, + + // Calculate the boundary coordinate of each vertex for the near and far clip planes, + // Z = -1 and Z = +1, respectively. + bc1near = s1.z + s1.w, + bc2near = s2.z + s2.w, + bc1far = - s1.z + s1.w, + bc2far = - s2.z + s2.w; + + if ( bc1near >= 0 && bc2near >= 0 && bc1far >= 0 && bc2far >= 0 ) { + + // Both vertices lie entirely within all clip planes. + return true; + + } else if ( ( bc1near < 0 && bc2near < 0) || (bc1far < 0 && bc2far < 0 ) ) { + + // Both vertices lie entirely outside one of the clip planes. + return false; + + } else { + + // The line segment spans at least one clip plane. + + if ( bc1near < 0 ) { + + // v1 lies outside the near plane, v2 inside + alpha1 = Math.max( alpha1, bc1near / ( bc1near - bc2near ) ); + + } else if ( bc2near < 0 ) { + + // v2 lies outside the near plane, v1 inside + alpha2 = Math.min( alpha2, bc1near / ( bc1near - bc2near ) ); + + } + + if ( bc1far < 0 ) { + + // v1 lies outside the far plane, v2 inside + alpha1 = Math.max( alpha1, bc1far / ( bc1far - bc2far ) ); + + } else if ( bc2far < 0 ) { + + // v2 lies outside the far plane, v2 inside + alpha2 = Math.min( alpha2, bc1far / ( bc1far - bc2far ) ); + + } + + if ( alpha2 < alpha1 ) { + + // The line segment spans two boundaries, but is outside both of them. + // (This can't happen when we're only clipping against just near/far but good + // to leave the check here for future usage if other clip planes are added.) + return false; + + } else { + + // Update the s1 and s2 vertices to match the clipped line segment. + s1.lerp( s2, alpha1 ); + s2.lerp( s1, 1 - alpha2 ); + + return true; + + } + + } + + } + +}; +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Face3 = function ( a, b, c, normal, color, materialIndex ) { + + this.a = a; + this.b = b; + this.c = c; + + this.normal = normal instanceof THREE.Vector3 ? normal : new THREE.Vector3(); + this.vertexNormals = normal instanceof Array ? normal : [ ]; + + this.color = color instanceof THREE.Color ? color : new THREE.Color(); + this.vertexColors = color instanceof Array ? color : []; + + this.vertexTangents = []; + + this.materialIndex = materialIndex !== undefined ? materialIndex : 0; + + this.centroid = new THREE.Vector3(); + +}; + +THREE.Face3.prototype = { + + constructor: THREE.Face3, + + clone: function () { + + var face = new THREE.Face3( this.a, this.b, this.c ); + + face.normal.copy( this.normal ); + face.color.copy( this.color ); + face.centroid.copy( this.centroid ); + + face.materialIndex = this.materialIndex; + + var i, il; + for ( i = 0, il = this.vertexNormals.length; i < il; i ++ ) face.vertexNormals[ i ] = this.vertexNormals[ i ].clone(); + for ( i = 0, il = this.vertexColors.length; i < il; i ++ ) face.vertexColors[ i ] = this.vertexColors[ i ].clone(); + for ( i = 0, il = this.vertexTangents.length; i < il; i ++ ) face.vertexTangents[ i ] = this.vertexTangents[ i ].clone(); + + return face; + + } + +}; +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Face4 = function ( a, b, c, d, normal, color, materialIndex ) { + + this.a = a; + this.b = b; + this.c = c; + this.d = d; + + this.normal = normal instanceof THREE.Vector3 ? normal : new THREE.Vector3(); + this.vertexNormals = normal instanceof Array ? normal : [ ]; + + this.color = color instanceof THREE.Color ? color : new THREE.Color(); + this.vertexColors = color instanceof Array ? color : []; + + this.vertexTangents = []; + + this.materialIndex = materialIndex !== undefined ? materialIndex : 0; + + this.centroid = new THREE.Vector3(); + +}; + +THREE.Face4.prototype = { + + constructor: THREE.Face4, + + clone: function () { + + var face = new THREE.Face4( this.a, this.b, this.c, this.d ); + + face.normal.copy( this.normal ); + face.color.copy( this.color ); + face.centroid.copy( this.centroid ); + + face.materialIndex = this.materialIndex; + + var i, il; + for ( i = 0, il = this.vertexNormals.length; i < il; i ++ ) face.vertexNormals[ i ] = this.vertexNormals[ i ].clone(); + for ( i = 0, il = this.vertexColors.length; i < il; i ++ ) face.vertexColors[ i ] = this.vertexColors[ i ].clone(); + for ( i = 0, il = this.vertexTangents.length; i < il; i ++ ) face.vertexTangents[ i ] = this.vertexTangents[ i ].clone(); + + return face; + + } + +}; +/** + * @author mrdoob / http://mrdoob.com/ + * @author kile / http://kile.stravaganza.org/ + * @author alteredq / http://alteredqualia.com/ + * @author mikael emtinger / http://gomo.se/ + * @author zz85 / http://www.lab4games.net/zz85/blog + * @author bhouston / http://exocortex.com + */ + +THREE.Geometry = function () { + + THREE.EventDispatcher.call( this ); + + this.id = THREE.GeometryIdCount ++; + + this.name = ''; + + this.vertices = []; + this.colors = []; // one-to-one vertex colors, used in ParticleSystem, Line and Ribbon + this.normals = []; // one-to-one vertex normals, used in Ribbon + + this.faces = []; + + this.faceUvs = [[]]; + this.faceVertexUvs = [[]]; + + this.morphTargets = []; + this.morphColors = []; + this.morphNormals = []; + + this.skinWeights = []; + this.skinIndices = []; + + this.lineDistances = []; + + this.boundingBox = null; + this.boundingSphere = null; + + this.hasTangents = false; + + this.dynamic = true; // the intermediate typed arrays will be deleted when set to false + + // update flags + + this.verticesNeedUpdate = false; + this.elementsNeedUpdate = false; + this.uvsNeedUpdate = false; + this.normalsNeedUpdate = false; + this.tangentsNeedUpdate = false; + this.colorsNeedUpdate = false; + this.lineDistancesNeedUpdate = false; + + this.buffersNeedUpdate = false; + +}; + +THREE.Geometry.prototype = { + + constructor: THREE.Geometry, + + applyMatrix: function ( matrix ) { + + var normalMatrix = new THREE.Matrix3().getInverse( matrix ).transpose(); + + for ( var i = 0, il = this.vertices.length; i < il; i ++ ) { + + var vertex = this.vertices[ i ]; + vertex.applyMatrix4( matrix ); + + } + + for ( var i = 0, il = this.faces.length; i < il; i ++ ) { + + var face = this.faces[ i ]; + face.normal.applyMatrix3( normalMatrix ).normalize(); + + for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { + + face.vertexNormals[ j ].applyMatrix3( normalMatrix ).normalize(); + + } + + face.centroid.applyMatrix4( matrix ); + + } + + }, + + computeCentroids: function () { + + var f, fl, face; + + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + + face = this.faces[ f ]; + face.centroid.set( 0, 0, 0 ); + + if ( face instanceof THREE.Face3 ) { + + face.centroid.add( this.vertices[ face.a ] ); + face.centroid.add( this.vertices[ face.b ] ); + face.centroid.add( this.vertices[ face.c ] ); + face.centroid.divideScalar( 3 ); + + } else if ( face instanceof THREE.Face4 ) { + + face.centroid.add( this.vertices[ face.a ] ); + face.centroid.add( this.vertices[ face.b ] ); + face.centroid.add( this.vertices[ face.c ] ); + face.centroid.add( this.vertices[ face.d ] ); + face.centroid.divideScalar( 4 ); + + } + + } + + }, + + computeFaceNormals: function () { + + var cb = new THREE.Vector3(), ab = new THREE.Vector3(); + + for ( var f = 0, fl = this.faces.length; f < fl; f ++ ) { + + var face = this.faces[ f ]; + + var vA = this.vertices[ face.a ]; + var vB = this.vertices[ face.b ]; + var vC = this.vertices[ face.c ]; + + cb.subVectors( vC, vB ); + ab.subVectors( vA, vB ); + cb.cross( ab ); + + cb.normalize(); + + face.normal.copy( cb ); + + } + + }, + + computeVertexNormals: function ( areaWeighted ) { + + var v, vl, f, fl, face, vertices; + + // create internal buffers for reuse when calling this method repeatedly + // (otherwise memory allocation / deallocation every frame is big resource hog) + + if ( this.__tmpVertices === undefined ) { + + this.__tmpVertices = new Array( this.vertices.length ); + vertices = this.__tmpVertices; + + for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { + + vertices[ v ] = new THREE.Vector3(); + + } + + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + + face = this.faces[ f ]; + + if ( face instanceof THREE.Face3 ) { + + face.vertexNormals = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ]; + + } else if ( face instanceof THREE.Face4 ) { + + face.vertexNormals = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ]; + + } + + } + + } else { + + vertices = this.__tmpVertices; + + for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { + + vertices[ v ].set( 0, 0, 0 ); + + } + + } + + if ( areaWeighted ) { + + // vertex normals weighted by triangle areas + // http://www.iquilezles.org/www/articles/normals/normals.htm + + var vA, vB, vC, vD; + var cb = new THREE.Vector3(), ab = new THREE.Vector3(), + db = new THREE.Vector3(), dc = new THREE.Vector3(), bc = new THREE.Vector3(); + + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + + face = this.faces[ f ]; + + if ( face instanceof THREE.Face3 ) { + + vA = this.vertices[ face.a ]; + vB = this.vertices[ face.b ]; + vC = this.vertices[ face.c ]; + + cb.subVectors( vC, vB ); + ab.subVectors( vA, vB ); + cb.cross( ab ); + + vertices[ face.a ].add( cb ); + vertices[ face.b ].add( cb ); + vertices[ face.c ].add( cb ); + + } else if ( face instanceof THREE.Face4 ) { + + vA = this.vertices[ face.a ]; + vB = this.vertices[ face.b ]; + vC = this.vertices[ face.c ]; + vD = this.vertices[ face.d ]; + + // abd + + db.subVectors( vD, vB ); + ab.subVectors( vA, vB ); + db.cross( ab ); + + vertices[ face.a ].add( db ); + vertices[ face.b ].add( db ); + vertices[ face.d ].add( db ); + + // bcd + + dc.subVectors( vD, vC ); + bc.subVectors( vB, vC ); + dc.cross( bc ); + + vertices[ face.b ].add( dc ); + vertices[ face.c ].add( dc ); + vertices[ face.d ].add( dc ); + + } + + } + + } else { + + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + + face = this.faces[ f ]; + + if ( face instanceof THREE.Face3 ) { + + vertices[ face.a ].add( face.normal ); + vertices[ face.b ].add( face.normal ); + vertices[ face.c ].add( face.normal ); + + } else if ( face instanceof THREE.Face4 ) { + + vertices[ face.a ].add( face.normal ); + vertices[ face.b ].add( face.normal ); + vertices[ face.c ].add( face.normal ); + vertices[ face.d ].add( face.normal ); + + } + + } + + } + + for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { + + vertices[ v ].normalize(); + + } + + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + + face = this.faces[ f ]; + + if ( face instanceof THREE.Face3 ) { + + face.vertexNormals[ 0 ].copy( vertices[ face.a ] ); + face.vertexNormals[ 1 ].copy( vertices[ face.b ] ); + face.vertexNormals[ 2 ].copy( vertices[ face.c ] ); + + } else if ( face instanceof THREE.Face4 ) { + + face.vertexNormals[ 0 ].copy( vertices[ face.a ] ); + face.vertexNormals[ 1 ].copy( vertices[ face.b ] ); + face.vertexNormals[ 2 ].copy( vertices[ face.c ] ); + face.vertexNormals[ 3 ].copy( vertices[ face.d ] ); + + } + + } + + }, + + computeMorphNormals: function () { + + var i, il, f, fl, face; + + // save original normals + // - create temp variables on first access + // otherwise just copy (for faster repeated calls) + + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + + face = this.faces[ f ]; + + if ( ! face.__originalFaceNormal ) { + + face.__originalFaceNormal = face.normal.clone(); + + } else { + + face.__originalFaceNormal.copy( face.normal ); + + } + + if ( ! face.__originalVertexNormals ) face.__originalVertexNormals = []; + + for ( i = 0, il = face.vertexNormals.length; i < il; i ++ ) { + + if ( ! face.__originalVertexNormals[ i ] ) { + + face.__originalVertexNormals[ i ] = face.vertexNormals[ i ].clone(); + + } else { + + face.__originalVertexNormals[ i ].copy( face.vertexNormals[ i ] ); + + } + + } + + } + + // use temp geometry to compute face and vertex normals for each morph + + var tmpGeo = new THREE.Geometry(); + tmpGeo.faces = this.faces; + + for ( i = 0, il = this.morphTargets.length; i < il; i ++ ) { + + // create on first access + + if ( ! this.morphNormals[ i ] ) { + + this.morphNormals[ i ] = {}; + this.morphNormals[ i ].faceNormals = []; + this.morphNormals[ i ].vertexNormals = []; + + var dstNormalsFace = this.morphNormals[ i ].faceNormals; + var dstNormalsVertex = this.morphNormals[ i ].vertexNormals; + + var faceNormal, vertexNormals; + + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + + face = this.faces[ f ]; + + faceNormal = new THREE.Vector3(); + + if ( face instanceof THREE.Face3 ) { + + vertexNormals = { a: new THREE.Vector3(), b: new THREE.Vector3(), c: new THREE.Vector3() }; + + } else { + + vertexNormals = { a: new THREE.Vector3(), b: new THREE.Vector3(), c: new THREE.Vector3(), d: new THREE.Vector3() }; + + } + + dstNormalsFace.push( faceNormal ); + dstNormalsVertex.push( vertexNormals ); + + } + + } + + var morphNormals = this.morphNormals[ i ]; + + // set vertices to morph target + + tmpGeo.vertices = this.morphTargets[ i ].vertices; + + // compute morph normals + + tmpGeo.computeFaceNormals(); + tmpGeo.computeVertexNormals(); + + // store morph normals + + var faceNormal, vertexNormals; + + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + + face = this.faces[ f ]; + + faceNormal = morphNormals.faceNormals[ f ]; + vertexNormals = morphNormals.vertexNormals[ f ]; + + faceNormal.copy( face.normal ); + + if ( face instanceof THREE.Face3 ) { + + vertexNormals.a.copy( face.vertexNormals[ 0 ] ); + vertexNormals.b.copy( face.vertexNormals[ 1 ] ); + vertexNormals.c.copy( face.vertexNormals[ 2 ] ); + + } else { + + vertexNormals.a.copy( face.vertexNormals[ 0 ] ); + vertexNormals.b.copy( face.vertexNormals[ 1 ] ); + vertexNormals.c.copy( face.vertexNormals[ 2 ] ); + vertexNormals.d.copy( face.vertexNormals[ 3 ] ); + + } + + } + + } + + // restore original normals + + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + + face = this.faces[ f ]; + + face.normal = face.__originalFaceNormal; + face.vertexNormals = face.__originalVertexNormals; + + } + + }, + + computeTangents: function () { + + // based on http://www.terathon.com/code/tangent.html + // tangents go to vertices + + var f, fl, v, vl, i, il, vertexIndex, + face, uv, vA, vB, vC, uvA, uvB, uvC, + x1, x2, y1, y2, z1, z2, + s1, s2, t1, t2, r, t, test, + tan1 = [], tan2 = [], + sdir = new THREE.Vector3(), tdir = new THREE.Vector3(), + tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3(), + n = new THREE.Vector3(), w; + + for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { + + tan1[ v ] = new THREE.Vector3(); + tan2[ v ] = new THREE.Vector3(); + + } + + function handleTriangle( context, a, b, c, ua, ub, uc ) { + + vA = context.vertices[ a ]; + vB = context.vertices[ b ]; + vC = context.vertices[ c ]; + + uvA = uv[ ua ]; + uvB = uv[ ub ]; + uvC = uv[ uc ]; + + x1 = vB.x - vA.x; + x2 = vC.x - vA.x; + y1 = vB.y - vA.y; + y2 = vC.y - vA.y; + z1 = vB.z - vA.z; + z2 = vC.z - vA.z; + + s1 = uvB.x - uvA.x; + s2 = uvC.x - uvA.x; + t1 = uvB.y - uvA.y; + t2 = uvC.y - uvA.y; + + r = 1.0 / ( s1 * t2 - s2 * t1 ); + sdir.set( ( t2 * x1 - t1 * x2 ) * r, + ( t2 * y1 - t1 * y2 ) * r, + ( t2 * z1 - t1 * z2 ) * r ); + tdir.set( ( s1 * x2 - s2 * x1 ) * r, + ( s1 * y2 - s2 * y1 ) * r, + ( s1 * z2 - s2 * z1 ) * r ); + + tan1[ a ].add( sdir ); + tan1[ b ].add( sdir ); + tan1[ c ].add( sdir ); + + tan2[ a ].add( tdir ); + tan2[ b ].add( tdir ); + tan2[ c ].add( tdir ); + + } + + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + + face = this.faces[ f ]; + uv = this.faceVertexUvs[ 0 ][ f ]; // use UV layer 0 for tangents + + if ( face instanceof THREE.Face3 ) { + + handleTriangle( this, face.a, face.b, face.c, 0, 1, 2 ); + + } else if ( face instanceof THREE.Face4 ) { + + handleTriangle( this, face.a, face.b, face.d, 0, 1, 3 ); + handleTriangle( this, face.b, face.c, face.d, 1, 2, 3 ); + + } + + } + + var faceIndex = [ 'a', 'b', 'c', 'd' ]; + + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + + face = this.faces[ f ]; + + for ( i = 0; i < face.vertexNormals.length; i++ ) { + + n.copy( face.vertexNormals[ i ] ); + + vertexIndex = face[ faceIndex[ i ] ]; + + t = tan1[ vertexIndex ]; + + // Gram-Schmidt orthogonalize + + tmp.copy( t ); + tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize(); + + // Calculate handedness + + tmp2.crossVectors( face.vertexNormals[ i ], t ); + test = tmp2.dot( tan2[ vertexIndex ] ); + w = (test < 0.0) ? -1.0 : 1.0; + + face.vertexTangents[ i ] = new THREE.Vector4( tmp.x, tmp.y, tmp.z, w ); + + } + + } + + this.hasTangents = true; + + }, + + computeLineDistances: function ( ) { + + var d = 0; + var vertices = this.vertices; + + for ( var i = 0, il = vertices.length; i < il; i ++ ) { + + if ( i > 0 ) { + + d += vertices[ i ].distanceTo( vertices[ i - 1 ] ); + + } + + this.lineDistances[ i ] = d; + + } + + }, + + computeBoundingBox: function () { + + if ( this.boundingBox === null ) { + + this.boundingBox = new THREE.Box3(); + + } + + this.boundingBox.setFromPoints( this.vertices ); + + }, + + computeBoundingSphere: function () { + + if ( this.boundingSphere === null ) { + + this.boundingSphere = new THREE.Sphere(); + + } + + this.boundingSphere.setFromCenterAndPoints( this.boundingSphere.center, this.vertices ); + + }, + + /* + * Checks for duplicate vertices with hashmap. + * Duplicated vertices are removed + * and faces' vertices are updated. + */ + + mergeVertices: function () { + + var verticesMap = {}; // Hashmap for looking up vertice by position coordinates (and making sure they are unique) + var unique = [], changes = []; + + var v, key; + var precisionPoints = 4; // number of decimal points, eg. 4 for epsilon of 0.0001 + var precision = Math.pow( 10, precisionPoints ); + var i,il, face; + var indices, k, j, jl, u; + + // reset cache of vertices as it now will be changing. + this.__tmpVertices = undefined; + + for ( i = 0, il = this.vertices.length; i < il; i ++ ) { + + v = this.vertices[ i ]; + key = [ Math.round( v.x * precision ), Math.round( v.y * precision ), Math.round( v.z * precision ) ].join( '_' ); + + if ( verticesMap[ key ] === undefined ) { + + verticesMap[ key ] = i; + unique.push( this.vertices[ i ] ); + changes[ i ] = unique.length - 1; + + } else { + + //console.log('Duplicate vertex found. ', i, ' could be using ', verticesMap[key]); + changes[ i ] = changes[ verticesMap[ key ] ]; + + } + + }; + + + // if faces are completely degenerate after merging vertices, we + // have to remove them from the geometry. + var faceIndicesToRemove = []; + + for( i = 0, il = this.faces.length; i < il; i ++ ) { + + face = this.faces[ i ]; + + if ( face instanceof THREE.Face3 ) { + + face.a = changes[ face.a ]; + face.b = changes[ face.b ]; + face.c = changes[ face.c ]; + + indices = [ face.a, face.b, face.c ]; + + var dupIndex = -1; + + // if any duplicate vertices are found in a Face3 + // we have to remove the face as nothing can be saved + for ( var n = 0; n < 3; n ++ ) { + if ( indices[ n ] == indices[ ( n + 1 ) % 3 ] ) { + + dupIndex = n; + faceIndicesToRemove.push( i ); + break; + + } + } + + } else if ( face instanceof THREE.Face4 ) { + + face.a = changes[ face.a ]; + face.b = changes[ face.b ]; + face.c = changes[ face.c ]; + face.d = changes[ face.d ]; + + // check dups in (a, b, c, d) and convert to -> face3 + + indices = [ face.a, face.b, face.c, face.d ]; + + var dupIndex = -1; + + for ( var n = 0; n < 4; n ++ ) { + + if ( indices[ n ] == indices[ ( n + 1 ) % 4 ] ) { + + // if more than one duplicated vertex is found + // we can't generate any valid Face3's, thus + // we need to remove this face complete. + if ( dupIndex >= 0 ) { + + faceIndicesToRemove.push( i ); + + } + + dupIndex = n; + + } + } + + if ( dupIndex >= 0 ) { + + indices.splice( dupIndex, 1 ); + + var newFace = new THREE.Face3( indices[0], indices[1], indices[2], face.normal, face.color, face.materialIndex ); + + for ( j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) { + + u = this.faceVertexUvs[ j ][ i ]; + + if ( u ) { + u.splice( dupIndex, 1 ); + } + + } + + if( face.vertexNormals && face.vertexNormals.length > 0) { + + newFace.vertexNormals = face.vertexNormals; + newFace.vertexNormals.splice( dupIndex, 1 ); + + } + + if( face.vertexColors && face.vertexColors.length > 0 ) { + + newFace.vertexColors = face.vertexColors; + newFace.vertexColors.splice( dupIndex, 1 ); + } + + this.faces[ i ] = newFace; + } + + } + + } + + for ( i = faceIndicesToRemove.length - 1; i >= 0; i -- ) { + + this.faces.splice( i, 1 ); + + for ( j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) { + + this.faceVertexUvs[ j ].splice( i, 1 ); + + } + + } + + // Use unique set of vertices + + var diff = this.vertices.length - unique.length; + this.vertices = unique; + return diff; + + }, + + clone: function () { + + var geometry = new THREE.Geometry(); + + var vertices = this.vertices; + + for ( var i = 0, il = vertices.length; i < il; i ++ ) { + + geometry.vertices.push( vertices[ i ].clone() ); + + } + + var faces = this.faces; + + for ( var i = 0, il = faces.length; i < il; i ++ ) { + + geometry.faces.push( faces[ i ].clone() ); + + } + + var uvs = this.faceVertexUvs[ 0 ]; + + for ( var i = 0, il = uvs.length; i < il; i ++ ) { + + var uv = uvs[ i ], uvCopy = []; + + for ( var j = 0, jl = uv.length; j < jl; j ++ ) { + + uvCopy.push( new THREE.Vector2( uv[ j ].x, uv[ j ].y ) ); + + } + + geometry.faceVertexUvs[ 0 ].push( uvCopy ); + + } + + return geometry; + + }, + + dispose: function () { + + this.dispatchEvent( { type: 'dispose' } ); + + } + +}; + +THREE.GeometryIdCount = 0; +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.BufferGeometry = function () { + + THREE.EventDispatcher.call( this ); + + this.id = THREE.GeometryIdCount ++; + + // attributes + + this.attributes = {}; + + // attributes typed arrays are kept only if dynamic flag is set + + this.dynamic = false; + + // offsets for chunks when using indexed elements + + this.offsets = []; + + // boundings + + this.boundingBox = null; + this.boundingSphere = null; + + this.hasTangents = false; + + // for compatibility + + this.morphTargets = []; + +}; + +THREE.BufferGeometry.prototype = { + + constructor : THREE.BufferGeometry, + + applyMatrix: function ( matrix ) { + + var positionArray; + var normalArray; + + if ( this.attributes[ "position" ] ) positionArray = this.attributes[ "position" ].array; + if ( this.attributes[ "normal" ] ) normalArray = this.attributes[ "normal" ].array; + + if ( positionArray !== undefined ) { + + matrix.multiplyVector3Array( positionArray ); + this.verticesNeedUpdate = true; + + } + + if ( normalArray !== undefined ) { + + var normalMatrix = new THREE.Matrix3(); + normalMatrix.getInverse( matrix ).transpose(); + + normalMatrix.multiplyVector3Array( normalArray ); + + this.normalizeNormals(); + + this.normalsNeedUpdate = true; + + } + + }, + + computeBoundingBox: function () { + + if ( this.boundingBox === null ) { + + this.boundingBox = new THREE.Box3(); + + } + + var positions = this.attributes[ "position" ].array; + + if ( positions ) { + + var bb = this.boundingBox; + var x, y, z; + + if( positions.length >= 3 ) { + bb.min.x = bb.max.x = positions[ 0 ]; + bb.min.y = bb.max.y = positions[ 1 ]; + bb.min.z = bb.max.z = positions[ 2 ]; + } + + for ( var i = 3, il = positions.length; i < il; i += 3 ) { + + x = positions[ i ]; + y = positions[ i + 1 ]; + z = positions[ i + 2 ]; + + // bounding box + + if ( x < bb.min.x ) { + + bb.min.x = x; + + } else if ( x > bb.max.x ) { + + bb.max.x = x; + + } + + if ( y < bb.min.y ) { + + bb.min.y = y; + + } else if ( y > bb.max.y ) { + + bb.max.y = y; + + } + + if ( z < bb.min.z ) { + + bb.min.z = z; + + } else if ( z > bb.max.z ) { + + bb.max.z = z; + + } + + } + + } + + if ( positions === undefined || positions.length === 0 ) { + + this.boundingBox.min.set( 0, 0, 0 ); + this.boundingBox.max.set( 0, 0, 0 ); + + } + + }, + + computeBoundingSphere: function () { + + if ( this.boundingSphere === null ) { + + this.boundingSphere = new THREE.Sphere(); + + } + + var positions = this.attributes[ "position" ].array; + + if ( positions ) { + + var radiusSq, maxRadiusSq = 0; + var x, y, z; + + for ( var i = 0, il = positions.length; i < il; i += 3 ) { + + x = positions[ i ]; + y = positions[ i + 1 ]; + z = positions[ i + 2 ]; + + radiusSq = x * x + y * y + z * z; + if ( radiusSq > maxRadiusSq ) maxRadiusSq = radiusSq; + + } + + this.boundingSphere.radius = Math.sqrt( maxRadiusSq ); + + } + + }, + + computeVertexNormals: function () { + + if ( this.attributes[ "position" ] ) { + + var i, il; + var j, jl; + + var nVertexElements = this.attributes[ "position" ].array.length; + + if ( this.attributes[ "normal" ] === undefined ) { + + this.attributes[ "normal" ] = { + + itemSize: 3, + array: new Float32Array( nVertexElements ), + numItems: nVertexElements + + }; + + } else { + + // reset existing normals to zero + + for ( i = 0, il = this.attributes[ "normal" ].array.length; i < il; i ++ ) { + + this.attributes[ "normal" ].array[ i ] = 0; + + } + + } + + var positions = this.attributes[ "position" ].array; + var normals = this.attributes[ "normal" ].array; + + var vA, vB, vC, x, y, z, + + pA = new THREE.Vector3(), + pB = new THREE.Vector3(), + pC = new THREE.Vector3(), + + cb = new THREE.Vector3(), + ab = new THREE.Vector3(); + + // indexed elements + + if ( this.attributes[ "index" ] ) { + + var indices = this.attributes[ "index" ].array; + + var offsets = this.offsets; + + for ( j = 0, jl = offsets.length; j < jl; ++ j ) { + + var start = offsets[ j ].start; + var count = offsets[ j ].count; + var index = offsets[ j ].index; + + for ( i = start, il = start + count; i < il; i += 3 ) { + + vA = index + indices[ i ]; + vB = index + indices[ i + 1 ]; + vC = index + indices[ i + 2 ]; + + x = positions[ vA * 3 ]; + y = positions[ vA * 3 + 1 ]; + z = positions[ vA * 3 + 2 ]; + pA.set( x, y, z ); + + x = positions[ vB * 3 ]; + y = positions[ vB * 3 + 1 ]; + z = positions[ vB * 3 + 2 ]; + pB.set( x, y, z ); + + x = positions[ vC * 3 ]; + y = positions[ vC * 3 + 1 ]; + z = positions[ vC * 3 + 2 ]; + pC.set( x, y, z ); + + cb.subVectors( pC, pB ); + ab.subVectors( pA, pB ); + cb.cross( ab ); + + normals[ vA * 3 ] += cb.x; + normals[ vA * 3 + 1 ] += cb.y; + normals[ vA * 3 + 2 ] += cb.z; + + normals[ vB * 3 ] += cb.x; + normals[ vB * 3 + 1 ] += cb.y; + normals[ vB * 3 + 2 ] += cb.z; + + normals[ vC * 3 ] += cb.x; + normals[ vC * 3 + 1 ] += cb.y; + normals[ vC * 3 + 2 ] += cb.z; + + } + + } + + // non-indexed elements (unconnected triangle soup) + + } else { + + for ( i = 0, il = positions.length; i < il; i += 9 ) { + + x = positions[ i ]; + y = positions[ i + 1 ]; + z = positions[ i + 2 ]; + pA.set( x, y, z ); + + x = positions[ i + 3 ]; + y = positions[ i + 4 ]; + z = positions[ i + 5 ]; + pB.set( x, y, z ); + + x = positions[ i + 6 ]; + y = positions[ i + 7 ]; + z = positions[ i + 8 ]; + pC.set( x, y, z ); + + cb.subVectors( pC, pB ); + ab.subVectors( pA, pB ); + cb.cross( ab ); + + normals[ i ] = cb.x; + normals[ i + 1 ] = cb.y; + normals[ i + 2 ] = cb.z; + + normals[ i + 3 ] = cb.x; + normals[ i + 4 ] = cb.y; + normals[ i + 5 ] = cb.z; + + normals[ i + 6 ] = cb.x; + normals[ i + 7 ] = cb.y; + normals[ i + 8 ] = cb.z; + + } + + } + + this.normalizeNormals(); + + this.normalsNeedUpdate = true; + + } + + }, + + normalizeNormals: function () { + + var normals = this.attributes[ "normal" ].array; + + var x, y, z, n; + + for ( var i = 0, il = normals.length; i < il; i += 3 ) { + + x = normals[ i ]; + y = normals[ i + 1 ]; + z = normals[ i + 2 ]; + + n = 1.0 / Math.sqrt( x * x + y * y + z * z ); + + normals[ i ] *= n; + normals[ i + 1 ] *= n; + normals[ i + 2 ] *= n; + + } + + }, + + computeTangents: function () { + + // based on http://www.terathon.com/code/tangent.html + // (per vertex tangents) + + if ( this.attributes[ "index" ] === undefined || + this.attributes[ "position" ] === undefined || + this.attributes[ "normal" ] === undefined || + this.attributes[ "uv" ] === undefined ) { + + console.warn( "Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()" ); + return; + + } + + var indices = this.attributes[ "index" ].array; + var positions = this.attributes[ "position" ].array; + var normals = this.attributes[ "normal" ].array; + var uvs = this.attributes[ "uv" ].array; + + var nVertices = positions.length / 3; + + if ( this.attributes[ "tangent" ] === undefined ) { + + var nTangentElements = 4 * nVertices; + + this.attributes[ "tangent" ] = { + + itemSize: 4, + array: new Float32Array( nTangentElements ), + numItems: nTangentElements + + }; + + } + + var tangents = this.attributes[ "tangent" ].array; + + var tan1 = [], tan2 = []; + + for ( var k = 0; k < nVertices; k ++ ) { + + tan1[ k ] = new THREE.Vector3(); + tan2[ k ] = new THREE.Vector3(); + + } + + var xA, yA, zA, + xB, yB, zB, + xC, yC, zC, + + uA, vA, + uB, vB, + uC, vC, + + x1, x2, y1, y2, z1, z2, + s1, s2, t1, t2, r; + + var sdir = new THREE.Vector3(), tdir = new THREE.Vector3(); + + function handleTriangle( a, b, c ) { + + xA = positions[ a * 3 ]; + yA = positions[ a * 3 + 1 ]; + zA = positions[ a * 3 + 2 ]; + + xB = positions[ b * 3 ]; + yB = positions[ b * 3 + 1 ]; + zB = positions[ b * 3 + 2 ]; + + xC = positions[ c * 3 ]; + yC = positions[ c * 3 + 1 ]; + zC = positions[ c * 3 + 2 ]; + + uA = uvs[ a * 2 ]; + vA = uvs[ a * 2 + 1 ]; + + uB = uvs[ b * 2 ]; + vB = uvs[ b * 2 + 1 ]; + + uC = uvs[ c * 2 ]; + vC = uvs[ c * 2 + 1 ]; + + x1 = xB - xA; + x2 = xC - xA; + + y1 = yB - yA; + y2 = yC - yA; + + z1 = zB - zA; + z2 = zC - zA; + + s1 = uB - uA; + s2 = uC - uA; + + t1 = vB - vA; + t2 = vC - vA; + + r = 1.0 / ( s1 * t2 - s2 * t1 ); + + sdir.set( + ( t2 * x1 - t1 * x2 ) * r, + ( t2 * y1 - t1 * y2 ) * r, + ( t2 * z1 - t1 * z2 ) * r + ); + + tdir.set( + ( s1 * x2 - s2 * x1 ) * r, + ( s1 * y2 - s2 * y1 ) * r, + ( s1 * z2 - s2 * z1 ) * r + ); + + tan1[ a ].add( sdir ); + tan1[ b ].add( sdir ); + tan1[ c ].add( sdir ); + + tan2[ a ].add( tdir ); + tan2[ b ].add( tdir ); + tan2[ c ].add( tdir ); + + } + + var i, il; + var j, jl; + var iA, iB, iC; + + var offsets = this.offsets; + + for ( j = 0, jl = offsets.length; j < jl; ++ j ) { + + var start = offsets[ j ].start; + var count = offsets[ j ].count; + var index = offsets[ j ].index; + + for ( i = start, il = start + count; i < il; i += 3 ) { + + iA = index + indices[ i ]; + iB = index + indices[ i + 1 ]; + iC = index + indices[ i + 2 ]; + + handleTriangle( iA, iB, iC ); + + } + + } + + var tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3(); + var n = new THREE.Vector3(), n2 = new THREE.Vector3(); + var w, t, test; + + function handleVertex( v ) { + + n.x = normals[ v * 3 ]; + n.y = normals[ v * 3 + 1 ]; + n.z = normals[ v * 3 + 2 ]; + + n2.copy( n ); + + t = tan1[ v ]; + + // Gram-Schmidt orthogonalize + + tmp.copy( t ); + tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize(); + + // Calculate handedness + + tmp2.crossVectors( n2, t ); + test = tmp2.dot( tan2[ v ] ); + w = ( test < 0.0 ) ? -1.0 : 1.0; + + tangents[ v * 4 ] = tmp.x; + tangents[ v * 4 + 1 ] = tmp.y; + tangents[ v * 4 + 2 ] = tmp.z; + tangents[ v * 4 + 3 ] = w; + + } + + for ( j = 0, jl = offsets.length; j < jl; ++ j ) { + + var start = offsets[ j ].start; + var count = offsets[ j ].count; + var index = offsets[ j ].index; + + for ( i = start, il = start + count; i < il; i += 3 ) { + + iA = index + indices[ i ]; + iB = index + indices[ i + 1 ]; + iC = index + indices[ i + 2 ]; + + handleVertex( iA ); + handleVertex( iB ); + handleVertex( iC ); + + } + + } + + this.hasTangents = true; + this.tangentsNeedUpdate = true; + + }, + + dispose: function () { + + this.dispatchEvent( { type: 'dispose' } ); + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author mikael emtinger / http://gomo.se/ + */ + +THREE.Camera = function () { + + THREE.Object3D.call( this ); + + this.matrixWorldInverse = new THREE.Matrix4(); + + this.projectionMatrix = new THREE.Matrix4(); + this.projectionMatrixInverse = new THREE.Matrix4(); + +}; + +THREE.Camera.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.Camera.prototype.lookAt = function ( vector ) { + + // TODO: Add hierarchy support. + + this.matrix.lookAt( this.position, vector, this.up ); + + if ( this.rotationAutoUpdate === true ) { + + if ( this.useQuaternion === false ) { + + this.rotation.setEulerFromRotationMatrix( this.matrix, this.eulerOrder ); + + } else { + + this.quaternion.copy( this.matrix.decompose()[ 1 ] ); + + } + + } + +}; +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.OrthographicCamera = function ( left, right, top, bottom, near, far ) { + + THREE.Camera.call( this ); + + this.left = left; + this.right = right; + this.top = top; + this.bottom = bottom; + + this.near = ( near !== undefined ) ? near : 0.1; + this.far = ( far !== undefined ) ? far : 2000; + + this.updateProjectionMatrix(); + +}; + +THREE.OrthographicCamera.prototype = Object.create( THREE.Camera.prototype ); + +THREE.OrthographicCamera.prototype.updateProjectionMatrix = function () { + + this.projectionMatrix.makeOrthographic( this.left, this.right, this.top, this.bottom, this.near, this.far ); + +}; +/** + * @author mrdoob / http://mrdoob.com/ + * @author greggman / http://games.greggman.com/ + * @author zz85 / http://www.lab4games.net/zz85/blog + */ + +THREE.PerspectiveCamera = function ( fov, aspect, near, far ) { + + THREE.Camera.call( this ); + + this.fov = fov !== undefined ? fov : 50; + this.aspect = aspect !== undefined ? aspect : 1; + this.near = near !== undefined ? near : 0.1; + this.far = far !== undefined ? far : 2000; + + this.updateProjectionMatrix(); + +}; + +THREE.PerspectiveCamera.prototype = Object.create( THREE.Camera.prototype ); + + +/** + * Uses Focal Length (in mm) to estimate and set FOV + * 35mm (fullframe) camera is used if frame size is not specified; + * Formula based on http://www.bobatkins.com/photography/technical/field_of_view.html + */ + +THREE.PerspectiveCamera.prototype.setLens = function ( focalLength, frameHeight ) { + + if ( frameHeight === undefined ) frameHeight = 24; + + this.fov = 2 * THREE.Math.radToDeg( Math.atan( frameHeight / ( focalLength * 2 ) ) ); + this.updateProjectionMatrix(); + +} + + +/** + * Sets an offset in a larger frustum. This is useful for multi-window or + * multi-monitor/multi-machine setups. + * + * For example, if you have 3x2 monitors and each monitor is 1920x1080 and + * the monitors are in grid like this + * + * +---+---+---+ + * | A | B | C | + * +---+---+---+ + * | D | E | F | + * +---+---+---+ + * + * then for each monitor you would call it like this + * + * var w = 1920; + * var h = 1080; + * var fullWidth = w * 3; + * var fullHeight = h * 2; + * + * --A-- + * camera.setOffset( fullWidth, fullHeight, w * 0, h * 0, w, h ); + * --B-- + * camera.setOffset( fullWidth, fullHeight, w * 1, h * 0, w, h ); + * --C-- + * camera.setOffset( fullWidth, fullHeight, w * 2, h * 0, w, h ); + * --D-- + * camera.setOffset( fullWidth, fullHeight, w * 0, h * 1, w, h ); + * --E-- + * camera.setOffset( fullWidth, fullHeight, w * 1, h * 1, w, h ); + * --F-- + * camera.setOffset( fullWidth, fullHeight, w * 2, h * 1, w, h ); + * + * Note there is no reason monitors have to be the same size or in a grid. + */ + +THREE.PerspectiveCamera.prototype.setViewOffset = function ( fullWidth, fullHeight, x, y, width, height ) { + + this.fullWidth = fullWidth; + this.fullHeight = fullHeight; + this.x = x; + this.y = y; + this.width = width; + this.height = height; + + this.updateProjectionMatrix(); + +}; + + +THREE.PerspectiveCamera.prototype.updateProjectionMatrix = function () { + + if ( this.fullWidth ) { + + var aspect = this.fullWidth / this.fullHeight; + var top = Math.tan( THREE.Math.degToRad( this.fov * 0.5 ) ) * this.near; + var bottom = -top; + var left = aspect * bottom; + var right = aspect * top; + var width = Math.abs( right - left ); + var height = Math.abs( top - bottom ); + + this.projectionMatrix.makeFrustum( + left + this.x * width / this.fullWidth, + left + ( this.x + this.width ) * width / this.fullWidth, + top - ( this.y + this.height ) * height / this.fullHeight, + top - this.y * height / this.fullHeight, + this.near, + this.far + ); + + } else { + + this.projectionMatrix.makePerspective( this.fov, this.aspect, this.near, this.far ); + + } + +}; +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Light = function ( hex ) { + + THREE.Object3D.call( this ); + + this.color = new THREE.Color( hex ); + +}; + +THREE.Light.prototype = Object.create( THREE.Object3D.prototype ); +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.AmbientLight = function ( hex ) { + + THREE.Light.call( this, hex ); + +}; + +THREE.AmbientLight.prototype = Object.create( THREE.Light.prototype ); +/** + * @author MPanknin / http://www.redplant.de/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.AreaLight = function ( hex, intensity ) { + + THREE.Light.call( this, hex ); + + this.normal = new THREE.Vector3( 0, -1, 0 ); + this.right = new THREE.Vector3( 1, 0, 0 ); + + this.intensity = ( intensity !== undefined ) ? intensity : 1; + + this.width = 1.0; + this.height = 1.0; + + this.constantAttenuation = 1.5; + this.linearAttenuation = 0.5; + this.quadraticAttenuation = 0.1; + +}; + +THREE.AreaLight.prototype = Object.create( THREE.Light.prototype ); + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.DirectionalLight = function ( hex, intensity ) { + + THREE.Light.call( this, hex ); + + this.position = new THREE.Vector3( 0, 1, 0 ); + this.target = new THREE.Object3D(); + + this.intensity = ( intensity !== undefined ) ? intensity : 1; + + this.castShadow = false; + this.onlyShadow = false; + + // + + this.shadowCameraNear = 50; + this.shadowCameraFar = 5000; + + this.shadowCameraLeft = -500; + this.shadowCameraRight = 500; + this.shadowCameraTop = 500; + this.shadowCameraBottom = -500; + + this.shadowCameraVisible = false; + + this.shadowBias = 0; + this.shadowDarkness = 0.5; + + this.shadowMapWidth = 512; + this.shadowMapHeight = 512; + + // + + this.shadowCascade = false; + + this.shadowCascadeOffset = new THREE.Vector3( 0, 0, -1000 ); + this.shadowCascadeCount = 2; + + this.shadowCascadeBias = [ 0, 0, 0 ]; + this.shadowCascadeWidth = [ 512, 512, 512 ]; + this.shadowCascadeHeight = [ 512, 512, 512 ]; + + this.shadowCascadeNearZ = [ -1.000, 0.990, 0.998 ]; + this.shadowCascadeFarZ = [ 0.990, 0.998, 1.000 ]; + + this.shadowCascadeArray = []; + + // + + this.shadowMap = null; + this.shadowMapSize = null; + this.shadowCamera = null; + this.shadowMatrix = null; + +}; + +THREE.DirectionalLight.prototype = Object.create( THREE.Light.prototype ); +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.HemisphereLight = function ( skyColorHex, groundColorHex, intensity ) { + + THREE.Light.call( this, skyColorHex ); + + this.groundColor = new THREE.Color( groundColorHex ); + + this.position = new THREE.Vector3( 0, 100, 0 ); + + this.intensity = ( intensity !== undefined ) ? intensity : 1; + +}; + +THREE.HemisphereLight.prototype = Object.create( THREE.Light.prototype ); +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.PointLight = function ( hex, intensity, distance ) { + + THREE.Light.call( this, hex ); + + this.position = new THREE.Vector3( 0, 0, 0 ); + this.intensity = ( intensity !== undefined ) ? intensity : 1; + this.distance = ( distance !== undefined ) ? distance : 0; + +}; + +THREE.PointLight.prototype = Object.create( THREE.Light.prototype ); +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.SpotLight = function ( hex, intensity, distance, angle, exponent ) { + + THREE.Light.call( this, hex ); + + this.position = new THREE.Vector3( 0, 1, 0 ); + this.target = new THREE.Object3D(); + + this.intensity = ( intensity !== undefined ) ? intensity : 1; + this.distance = ( distance !== undefined ) ? distance : 0; + this.angle = ( angle !== undefined ) ? angle : Math.PI / 2; + this.exponent = ( exponent !== undefined ) ? exponent : 10; + + this.castShadow = false; + this.onlyShadow = false; + + // + + this.shadowCameraNear = 50; + this.shadowCameraFar = 5000; + this.shadowCameraFov = 50; + + this.shadowCameraVisible = false; + + this.shadowBias = 0; + this.shadowDarkness = 0.5; + + this.shadowMapWidth = 512; + this.shadowMapHeight = 512; + + // + + this.shadowMap = null; + this.shadowMapSize = null; + this.shadowCamera = null; + this.shadowMatrix = null; + +}; + +THREE.SpotLight.prototype = Object.create( THREE.Light.prototype ); +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Loader = function ( showStatus ) { + + this.showStatus = showStatus; + this.statusDomElement = showStatus ? THREE.Loader.prototype.addStatusElement() : null; + + this.onLoadStart = function () {}; + this.onLoadProgress = function () {}; + this.onLoadComplete = function () {}; + +}; + +THREE.Loader.prototype = { + + constructor: THREE.Loader, + + crossOrigin: 'anonymous', + + addStatusElement: function () { + + var e = document.createElement( "div" ); + + e.style.position = "absolute"; + e.style.right = "0px"; + e.style.top = "0px"; + e.style.fontSize = "0.8em"; + e.style.textAlign = "left"; + e.style.background = "rgba(0,0,0,0.25)"; + e.style.color = "#fff"; + e.style.width = "120px"; + e.style.padding = "0.5em 0.5em 0.5em 0.5em"; + e.style.zIndex = 1000; + + e.innerHTML = "Loading ..."; + + return e; + + }, + + updateProgress: function ( progress ) { + + var message = "Loaded "; + + if ( progress.total ) { + + message += ( 100 * progress.loaded / progress.total ).toFixed(0) + "%"; + + + } else { + + message += ( progress.loaded / 1000 ).toFixed(2) + " KB"; + + } + + this.statusDomElement.innerHTML = message; + + }, + + extractUrlBase: function ( url ) { + + var parts = url.split( '/' ); + parts.pop(); + return ( parts.length < 1 ? '.' : parts.join( '/' ) ) + '/'; + + }, + + initMaterials: function ( materials, texturePath ) { + + var array = []; + + for ( var i = 0; i < materials.length; ++ i ) { + + array[ i ] = THREE.Loader.prototype.createMaterial( materials[ i ], texturePath ); + + } + + return array; + + }, + + needsTangents: function ( materials ) { + + for( var i = 0, il = materials.length; i < il; i ++ ) { + + var m = materials[ i ]; + + if ( m instanceof THREE.ShaderMaterial ) return true; + + } + + return false; + + }, + + createMaterial: function ( m, texturePath ) { + + var _this = this; + + function is_pow2( n ) { + + var l = Math.log( n ) / Math.LN2; + return Math.floor( l ) == l; + + } + + function nearest_pow2( n ) { + + var l = Math.log( n ) / Math.LN2; + return Math.pow( 2, Math.round( l ) ); + + } + + function load_image( where, url ) { + + var image = new Image(); + + image.onload = function () { + + if ( !is_pow2( this.width ) || !is_pow2( this.height ) ) { + + var width = nearest_pow2( this.width ); + var height = nearest_pow2( this.height ); + + where.image.width = width; + where.image.height = height; + where.image.getContext( '2d' ).drawImage( this, 0, 0, width, height ); + + } else { + + where.image = this; + + } + + where.needsUpdate = true; + + }; + + image.crossOrigin = _this.crossOrigin; + image.src = url; + + } + + function create_texture( where, name, sourceFile, repeat, offset, wrap, anisotropy ) { + + var isCompressed = /\.dds$/i.test( sourceFile ); + var fullPath = texturePath + "/" + sourceFile; + + if ( isCompressed ) { + + var texture = THREE.ImageUtils.loadCompressedTexture( fullPath ); + + where[ name ] = texture; + + } else { + + var texture = document.createElement( 'canvas' ); + + where[ name ] = new THREE.Texture( texture ); + + } + + where[ name ].sourceFile = sourceFile; + + if( repeat ) { + + where[ name ].repeat.set( repeat[ 0 ], repeat[ 1 ] ); + + if ( repeat[ 0 ] !== 1 ) where[ name ].wrapS = THREE.RepeatWrapping; + if ( repeat[ 1 ] !== 1 ) where[ name ].wrapT = THREE.RepeatWrapping; + + } + + if ( offset ) { + + where[ name ].offset.set( offset[ 0 ], offset[ 1 ] ); + + } + + if ( wrap ) { + + var wrapMap = { + "repeat": THREE.RepeatWrapping, + "mirror": THREE.MirroredRepeatWrapping + } + + if ( wrapMap[ wrap[ 0 ] ] !== undefined ) where[ name ].wrapS = wrapMap[ wrap[ 0 ] ]; + if ( wrapMap[ wrap[ 1 ] ] !== undefined ) where[ name ].wrapT = wrapMap[ wrap[ 1 ] ]; + + } + + if ( anisotropy ) { + + where[ name ].anisotropy = anisotropy; + + } + + if ( ! isCompressed ) { + + load_image( where[ name ], fullPath ); + + } + + } + + function rgb2hex( rgb ) { + + return ( rgb[ 0 ] * 255 << 16 ) + ( rgb[ 1 ] * 255 << 8 ) + rgb[ 2 ] * 255; + + } + + // defaults + + var mtype = "MeshLambertMaterial"; + var mpars = { color: 0xeeeeee, opacity: 1.0, map: null, lightMap: null, normalMap: null, bumpMap: null, wireframe: false }; + + // parameters from model file + + if ( m.shading ) { + + var shading = m.shading.toLowerCase(); + + if ( shading === "phong" ) mtype = "MeshPhongMaterial"; + else if ( shading === "basic" ) mtype = "MeshBasicMaterial"; + + } + + if ( m.blending !== undefined && THREE[ m.blending ] !== undefined ) { + + mpars.blending = THREE[ m.blending ]; + + } + + if ( m.transparent !== undefined || m.opacity < 1.0 ) { + + mpars.transparent = m.transparent; + + } + + if ( m.depthTest !== undefined ) { + + mpars.depthTest = m.depthTest; + + } + + if ( m.depthWrite !== undefined ) { + + mpars.depthWrite = m.depthWrite; + + } + + if ( m.visible !== undefined ) { + + mpars.visible = m.visible; + + } + + if ( m.flipSided !== undefined ) { + + mpars.side = THREE.BackSide; + + } + + if ( m.doubleSided !== undefined ) { + + mpars.side = THREE.DoubleSide; + + } + + if ( m.wireframe !== undefined ) { + + mpars.wireframe = m.wireframe; + + } + + if ( m.vertexColors !== undefined ) { + + if ( m.vertexColors === "face" ) { + + mpars.vertexColors = THREE.FaceColors; + + } else if ( m.vertexColors ) { + + mpars.vertexColors = THREE.VertexColors; + + } + + } + + // colors + + if ( m.colorDiffuse ) { + + mpars.color = rgb2hex( m.colorDiffuse ); + + } else if ( m.DbgColor ) { + + mpars.color = m.DbgColor; + + } + + if ( m.colorSpecular ) { + + mpars.specular = rgb2hex( m.colorSpecular ); + + } + + if ( m.colorAmbient ) { + + mpars.ambient = rgb2hex( m.colorAmbient ); + + } + + // modifiers + + if ( m.transparency ) { + + mpars.opacity = m.transparency; + + } + + if ( m.specularCoef ) { + + mpars.shininess = m.specularCoef; + + } + + // textures + + if ( m.mapDiffuse && texturePath ) { + + create_texture( mpars, "map", m.mapDiffuse, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy ); + + } + + if ( m.mapLight && texturePath ) { + + create_texture( mpars, "lightMap", m.mapLight, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy ); + + } + + if ( m.mapBump && texturePath ) { + + create_texture( mpars, "bumpMap", m.mapBump, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy ); + + } + + if ( m.mapNormal && texturePath ) { + + create_texture( mpars, "normalMap", m.mapNormal, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy ); + + } + + if ( m.mapSpecular && texturePath ) { + + create_texture( mpars, "specularMap", m.mapSpecular, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy ); + + } + + // + + if ( m.mapBumpScale ) { + + mpars.bumpScale = m.mapBumpScale; + + } + + // special case for normal mapped material + + if ( m.mapNormal ) { + + var shader = THREE.ShaderLib[ "normalmap" ]; + var uniforms = THREE.UniformsUtils.clone( shader.uniforms ); + + uniforms[ "tNormal" ].value = mpars.normalMap; + + if ( m.mapNormalFactor ) { + + uniforms[ "uNormalScale" ].value.set( m.mapNormalFactor, m.mapNormalFactor ); + + } + + if ( mpars.map ) { + + uniforms[ "tDiffuse" ].value = mpars.map; + uniforms[ "enableDiffuse" ].value = true; + + } + + if ( mpars.specularMap ) { + + uniforms[ "tSpecular" ].value = mpars.specularMap; + uniforms[ "enableSpecular" ].value = true; + + } + + if ( mpars.lightMap ) { + + uniforms[ "tAO" ].value = mpars.lightMap; + uniforms[ "enableAO" ].value = true; + + } + + // for the moment don't handle displacement texture + + uniforms[ "uDiffuseColor" ].value.setHex( mpars.color ); + uniforms[ "uSpecularColor" ].value.setHex( mpars.specular ); + uniforms[ "uAmbientColor" ].value.setHex( mpars.ambient ); + + uniforms[ "uShininess" ].value = mpars.shininess; + + if ( mpars.opacity !== undefined ) { + + uniforms[ "uOpacity" ].value = mpars.opacity; + + } + + var parameters = { fragmentShader: shader.fragmentShader, vertexShader: shader.vertexShader, uniforms: uniforms, lights: true, fog: true }; + var material = new THREE.ShaderMaterial( parameters ); + + if ( mpars.transparent ) { + + material.transparent = true; + + } + + } else { + + var material = new THREE[ mtype ]( mpars ); + + } + + if ( m.DbgName !== undefined ) material.name = m.DbgName; + + return material; + + } + +}; +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.ImageLoader = function () { + + THREE.EventDispatcher.call( this ); + + this.crossOrigin = null; + +}; + +THREE.ImageLoader.prototype = { + + constructor: THREE.ImageLoader, + + load: function ( url, image ) { + + var scope = this; + + if ( image === undefined ) image = new Image(); + + image.addEventListener( 'load', function () { + + scope.dispatchEvent( { type: 'load', content: image } ); + + }, false ); + + image.addEventListener( 'error', function () { + + scope.dispatchEvent( { type: 'error', message: 'Couldn\'t load URL [' + url + ']' } ); + + }, false ); + + if ( scope.crossOrigin ) image.crossOrigin = scope.crossOrigin; + + image.src = url; + + } + +} +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.JSONLoader = function ( showStatus ) { + + THREE.Loader.call( this, showStatus ); + + this.withCredentials = false; + +}; + +THREE.JSONLoader.prototype = Object.create( THREE.Loader.prototype ); + +THREE.JSONLoader.prototype.load = function ( url, callback, texturePath ) { + + var scope = this; + + // todo: unify load API to for easier SceneLoader use + + texturePath = texturePath && ( typeof texturePath === "string" ) ? texturePath : this.extractUrlBase( url ); + + this.onLoadStart(); + this.loadAjaxJSON( this, url, callback, texturePath ); + +}; + +THREE.JSONLoader.prototype.loadAjaxJSON = function ( context, url, callback, texturePath, callbackProgress ) { + + var xhr = new XMLHttpRequest(); + + var length = 0; + + xhr.onreadystatechange = function () { + + if ( xhr.readyState === xhr.DONE ) { + + if ( xhr.status === 200 || xhr.status === 0 ) { + + if ( xhr.responseText ) { + + var json = JSON.parse( xhr.responseText ); + context.createModel( json, callback, texturePath ); + + } else { + + console.warn( "THREE.JSONLoader: [" + url + "] seems to be unreachable or file there is empty" ); + + } + + // in context of more complex asset initialization + // do not block on single failed file + // maybe should go even one more level up + + context.onLoadComplete(); + + } else { + + console.error( "THREE.JSONLoader: Couldn't load [" + url + "] [" + xhr.status + "]" ); + + } + + } else if ( xhr.readyState === xhr.LOADING ) { + + if ( callbackProgress ) { + + if ( length === 0 ) { + + length = xhr.getResponseHeader( "Content-Length" ); + + } + + callbackProgress( { total: length, loaded: xhr.responseText.length } ); + + } + + } else if ( xhr.readyState === xhr.HEADERS_RECEIVED ) { + + length = xhr.getResponseHeader( "Content-Length" ); + + } + + }; + + xhr.open( "GET", url, true ); + xhr.withCredentials = this.withCredentials; + xhr.send( null ); + +}; + +THREE.JSONLoader.prototype.createModel = function ( json, callback, texturePath ) { + + var scope = this, + geometry = new THREE.Geometry(), + scale = ( json.scale !== undefined ) ? 1.0 / json.scale : 1.0; + + parseModel( scale ); + + parseSkin(); + parseMorphing( scale ); + + geometry.computeCentroids(); + geometry.computeFaceNormals(); + + function parseModel( scale ) { + + function isBitSet( value, position ) { + + return value & ( 1 << position ); + + } + + var i, j, fi, + + offset, zLength, nVertices, + + colorIndex, normalIndex, uvIndex, materialIndex, + + type, + isQuad, + hasMaterial, + hasFaceUv, hasFaceVertexUv, + hasFaceNormal, hasFaceVertexNormal, + hasFaceColor, hasFaceVertexColor, + + vertex, face, color, normal, + + uvLayer, uvs, u, v, + + faces = json.faces, + vertices = json.vertices, + normals = json.normals, + colors = json.colors, + + nUvLayers = 0; + + // disregard empty arrays + + for ( i = 0; i < json.uvs.length; i++ ) { + + if ( json.uvs[ i ].length ) nUvLayers ++; + + } + + for ( i = 0; i < nUvLayers; i++ ) { + + geometry.faceUvs[ i ] = []; + geometry.faceVertexUvs[ i ] = []; + + } + + offset = 0; + zLength = vertices.length; + + while ( offset < zLength ) { + + vertex = new THREE.Vector3(); + + vertex.x = vertices[ offset ++ ] * scale; + vertex.y = vertices[ offset ++ ] * scale; + vertex.z = vertices[ offset ++ ] * scale; + + geometry.vertices.push( vertex ); + + } + + offset = 0; + zLength = faces.length; + + while ( offset < zLength ) { + + type = faces[ offset ++ ]; + + + isQuad = isBitSet( type, 0 ); + hasMaterial = isBitSet( type, 1 ); + hasFaceUv = isBitSet( type, 2 ); + hasFaceVertexUv = isBitSet( type, 3 ); + hasFaceNormal = isBitSet( type, 4 ); + hasFaceVertexNormal = isBitSet( type, 5 ); + hasFaceColor = isBitSet( type, 6 ); + hasFaceVertexColor = isBitSet( type, 7 ); + + //console.log("type", type, "bits", isQuad, hasMaterial, hasFaceUv, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor); + + if ( isQuad ) { + + face = new THREE.Face4(); + + face.a = faces[ offset ++ ]; + face.b = faces[ offset ++ ]; + face.c = faces[ offset ++ ]; + face.d = faces[ offset ++ ]; + + nVertices = 4; + + } else { + + face = new THREE.Face3(); + + face.a = faces[ offset ++ ]; + face.b = faces[ offset ++ ]; + face.c = faces[ offset ++ ]; + + nVertices = 3; + + } + + if ( hasMaterial ) { + + materialIndex = faces[ offset ++ ]; + face.materialIndex = materialIndex; + + } + + // to get face <=> uv index correspondence + + fi = geometry.faces.length; + + if ( hasFaceUv ) { + + for ( i = 0; i < nUvLayers; i++ ) { + + uvLayer = json.uvs[ i ]; + + uvIndex = faces[ offset ++ ]; + + u = uvLayer[ uvIndex * 2 ]; + v = uvLayer[ uvIndex * 2 + 1 ]; + + geometry.faceUvs[ i ][ fi ] = new THREE.Vector2( u, v ); + + } + + } + + if ( hasFaceVertexUv ) { + + for ( i = 0; i < nUvLayers; i++ ) { + + uvLayer = json.uvs[ i ]; + + uvs = []; + + for ( j = 0; j < nVertices; j ++ ) { + + uvIndex = faces[ offset ++ ]; + + u = uvLayer[ uvIndex * 2 ]; + v = uvLayer[ uvIndex * 2 + 1 ]; + + uvs[ j ] = new THREE.Vector2( u, v ); + + } + + geometry.faceVertexUvs[ i ][ fi ] = uvs; + + } + + } + + if ( hasFaceNormal ) { + + normalIndex = faces[ offset ++ ] * 3; + + normal = new THREE.Vector3(); + + normal.x = normals[ normalIndex ++ ]; + normal.y = normals[ normalIndex ++ ]; + normal.z = normals[ normalIndex ]; + + face.normal = normal; + + } + + if ( hasFaceVertexNormal ) { + + for ( i = 0; i < nVertices; i++ ) { + + normalIndex = faces[ offset ++ ] * 3; + + normal = new THREE.Vector3(); + + normal.x = normals[ normalIndex ++ ]; + normal.y = normals[ normalIndex ++ ]; + normal.z = normals[ normalIndex ]; + + face.vertexNormals.push( normal ); + + } + + } + + + if ( hasFaceColor ) { + + colorIndex = faces[ offset ++ ]; + + color = new THREE.Color( colors[ colorIndex ] ); + face.color = color; + + } + + + if ( hasFaceVertexColor ) { + + for ( i = 0; i < nVertices; i++ ) { + + colorIndex = faces[ offset ++ ]; + + color = new THREE.Color( colors[ colorIndex ] ); + face.vertexColors.push( color ); + + } + + } + + geometry.faces.push( face ); + + } + + }; + + function parseSkin() { + + var i, l, x, y, z, w, a, b, c, d; + + if ( json.skinWeights ) { + + for ( i = 0, l = json.skinWeights.length; i < l; i += 2 ) { + + x = json.skinWeights[ i ]; + y = json.skinWeights[ i + 1 ]; + z = 0; + w = 0; + + geometry.skinWeights.push( new THREE.Vector4( x, y, z, w ) ); + + } + + } + + if ( json.skinIndices ) { + + for ( i = 0, l = json.skinIndices.length; i < l; i += 2 ) { + + a = json.skinIndices[ i ]; + b = json.skinIndices[ i + 1 ]; + c = 0; + d = 0; + + geometry.skinIndices.push( new THREE.Vector4( a, b, c, d ) ); + + } + + } + + geometry.bones = json.bones; + geometry.animation = json.animation; + + }; + + function parseMorphing( scale ) { + + if ( json.morphTargets !== undefined ) { + + var i, l, v, vl, dstVertices, srcVertices; + + for ( i = 0, l = json.morphTargets.length; i < l; i ++ ) { + + geometry.morphTargets[ i ] = {}; + geometry.morphTargets[ i ].name = json.morphTargets[ i ].name; + geometry.morphTargets[ i ].vertices = []; + + dstVertices = geometry.morphTargets[ i ].vertices; + srcVertices = json.morphTargets [ i ].vertices; + + for( v = 0, vl = srcVertices.length; v < vl; v += 3 ) { + + var vertex = new THREE.Vector3(); + vertex.x = srcVertices[ v ] * scale; + vertex.y = srcVertices[ v + 1 ] * scale; + vertex.z = srcVertices[ v + 2 ] * scale; + + dstVertices.push( vertex ); + + } + + } + + } + + if ( json.morphColors !== undefined ) { + + var i, l, c, cl, dstColors, srcColors, color; + + for ( i = 0, l = json.morphColors.length; i < l; i++ ) { + + geometry.morphColors[ i ] = {}; + geometry.morphColors[ i ].name = json.morphColors[ i ].name; + geometry.morphColors[ i ].colors = []; + + dstColors = geometry.morphColors[ i ].colors; + srcColors = json.morphColors [ i ].colors; + + for ( c = 0, cl = srcColors.length; c < cl; c += 3 ) { + + color = new THREE.Color( 0xffaa00 ); + color.setRGB( srcColors[ c ], srcColors[ c + 1 ], srcColors[ c + 2 ] ); + dstColors.push( color ); + + } + + } + + } + + }; + + var materials = this.initMaterials( json.materials, texturePath ); + + if ( this.needsTangents( materials ) ) geometry.computeTangents(); + + callback( geometry, materials ); + +}; +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.LoadingMonitor = function () { + + THREE.EventDispatcher.call( this ); + + var scope = this; + + var loaded = 0; + var total = 0; + + var onLoad = function ( event ) { + + loaded ++; + + scope.dispatchEvent( { type: 'progress', loaded: loaded, total: total } ); + + if ( loaded === total ) { + + scope.dispatchEvent( { type: 'load' } ); + + } + + }; + + this.add = function ( loader ) { + + total ++; + + loader.addEventListener( 'load', onLoad, false ); + + }; + +}; +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.SceneLoader = function () { + + this.onLoadStart = function () {}; + this.onLoadProgress = function() {}; + this.onLoadComplete = function () {}; + + this.callbackSync = function () {}; + this.callbackProgress = function () {}; + + this.geometryHandlerMap = {}; + this.hierarchyHandlerMap = {}; + + this.addGeometryHandler( "ascii", THREE.JSONLoader ); + +}; + +THREE.SceneLoader.prototype.constructor = THREE.SceneLoader; + +THREE.SceneLoader.prototype.load = function ( url, callbackFinished ) { + + var scope = this; + + var xhr = new XMLHttpRequest(); + + xhr.onreadystatechange = function () { + + if ( xhr.readyState === 4 ) { + + if ( xhr.status === 200 || xhr.status === 0 ) { + + var json = JSON.parse( xhr.responseText ); + scope.parse( json, callbackFinished, url ); + + } else { + + console.error( "THREE.SceneLoader: Couldn't load [" + url + "] [" + xhr.status + "]" ); + + } + + } + + }; + + xhr.open( "GET", url, true ); + xhr.send( null ); + +}; + +THREE.SceneLoader.prototype.addGeometryHandler = function ( typeID, loaderClass ) { + + this.geometryHandlerMap[ typeID ] = { "loaderClass": loaderClass }; + +}; + +THREE.SceneLoader.prototype.addHierarchyHandler = function ( typeID, loaderClass ) { + + this.hierarchyHandlerMap[ typeID ] = { "loaderClass": loaderClass }; + +}; + +THREE.SceneLoader.prototype.parse = function ( json, callbackFinished, url ) { + + var scope = this; + + var urlBase = THREE.Loader.prototype.extractUrlBase( url ); + + var geometry, material, camera, fog, + texture, images, color, + light, hex, intensity, + counter_models, counter_textures, + total_models, total_textures, + result; + + var target_array = []; + + var data = json; + + // async geometry loaders + + for ( var typeID in this.geometryHandlerMap ) { + + var loaderClass = this.geometryHandlerMap[ typeID ][ "loaderClass" ]; + this.geometryHandlerMap[ typeID ][ "loaderObject" ] = new loaderClass(); + + } + + // async hierachy loaders + + for ( var typeID in this.hierarchyHandlerMap ) { + + var loaderClass = this.hierarchyHandlerMap[ typeID ][ "loaderClass" ]; + this.hierarchyHandlerMap[ typeID ][ "loaderObject" ] = new loaderClass(); + + } + + counter_models = 0; + counter_textures = 0; + + result = { + + scene: new THREE.Scene(), + geometries: {}, + face_materials: {}, + materials: {}, + textures: {}, + objects: {}, + cameras: {}, + lights: {}, + fogs: {}, + empties: {}, + groups: {} + + }; + + if ( data.transform ) { + + var position = data.transform.position, + rotation = data.transform.rotation, + scale = data.transform.scale; + + if ( position ) + result.scene.position.set( position[ 0 ], position[ 1 ], position [ 2 ] ); + + if ( rotation ) + result.scene.rotation.set( rotation[ 0 ], rotation[ 1 ], rotation [ 2 ] ); + + if ( scale ) + result.scene.scale.set( scale[ 0 ], scale[ 1 ], scale [ 2 ] ); + + if ( position || rotation || scale ) { + + result.scene.updateMatrix(); + result.scene.updateMatrixWorld(); + + } + + } + + function get_url( source_url, url_type ) { + + if ( url_type == "relativeToHTML" ) { + + return source_url; + + } else { + + return urlBase + "/" + source_url; + + } + + }; + + // toplevel loader function, delegates to handle_children + + function handle_objects() { + + handle_children( result.scene, data.objects ); + + } + + // handle all the children from the loaded json and attach them to given parent + + function handle_children( parent, children ) { + + var mat, dst, pos, rot, scl, quat; + + for ( var objID in children ) { + + // check by id if child has already been handled, + // if not, create new object + + if ( result.objects[ objID ] === undefined ) { + + var objJSON = children[ objID ]; + + var object = null; + + // meshes + + if ( objJSON.type && ( objJSON.type in scope.hierarchyHandlerMap ) ) { + + if ( objJSON.loading === undefined ) { + + var reservedTypes = { "type": 1, "url": 1, "material": 1, + "position": 1, "rotation": 1, "scale" : 1, + "visible": 1, "children": 1, "properties": 1, + "skin": 1, "morph": 1, "mirroredLoop": 1, "duration": 1 }; + + var loaderParameters = {}; + + for ( var parType in objJSON ) { + + if ( ! ( parType in reservedTypes ) ) { + + loaderParameters[ parType ] = objJSON[ parType ]; + + } + + } + + material = result.materials[ objJSON.material ]; + + objJSON.loading = true; + + var loader = scope.hierarchyHandlerMap[ objJSON.type ][ "loaderObject" ]; + + // ColladaLoader + + if ( loader.options ) { + + loader.load( get_url( objJSON.url, data.urlBaseType ), create_callback_hierachy( objID, parent, material, objJSON ) ); + + // UTF8Loader + // OBJLoader + + } else { + + loader.load( get_url( objJSON.url, data.urlBaseType ), create_callback_hierachy( objID, parent, material, objJSON ), loaderParameters ); + + } + + } + + } else if ( objJSON.geometry !== undefined ) { + + geometry = result.geometries[ objJSON.geometry ]; + + // geometry already loaded + + if ( geometry ) { + + var needsTangents = false; + + material = result.materials[ objJSON.material ]; + needsTangents = material instanceof THREE.ShaderMaterial; + + pos = objJSON.position; + rot = objJSON.rotation; + scl = objJSON.scale; + mat = objJSON.matrix; + quat = objJSON.quaternion; + + // use materials from the model file + // if there is no material specified in the object + + if ( ! objJSON.material ) { + + material = new THREE.MeshFaceMaterial( result.face_materials[ objJSON.geometry ] ); + + } + + // use materials from the model file + // if there is just empty face material + // (must create new material as each model has its own face material) + + if ( ( material instanceof THREE.MeshFaceMaterial ) && material.materials.length === 0 ) { + + material = new THREE.MeshFaceMaterial( result.face_materials[ objJSON.geometry ] ); + + } + + if ( material instanceof THREE.MeshFaceMaterial ) { + + for ( var i = 0; i < material.materials.length; i ++ ) { + + needsTangents = needsTangents || ( material.materials[ i ] instanceof THREE.ShaderMaterial ); + + } + + } + + if ( needsTangents ) { + + geometry.computeTangents(); + + } + + if ( objJSON.skin ) { + + object = new THREE.SkinnedMesh( geometry, material ); + + } else if ( objJSON.morph ) { + + object = new THREE.MorphAnimMesh( geometry, material ); + + if ( objJSON.duration !== undefined ) { + + object.duration = objJSON.duration; + + } + + if ( objJSON.time !== undefined ) { + + object.time = objJSON.time; + + } + + if ( objJSON.mirroredLoop !== undefined ) { + + object.mirroredLoop = objJSON.mirroredLoop; + + } + + if ( material.morphNormals ) { + + geometry.computeMorphNormals(); + + } + + } else { + + object = new THREE.Mesh( geometry, material ); + + } + + object.name = objID; + + if ( mat ) { + + object.matrixAutoUpdate = false; + object.matrix.set( + mat[0], mat[1], mat[2], mat[3], + mat[4], mat[5], mat[6], mat[7], + mat[8], mat[9], mat[10], mat[11], + mat[12], mat[13], mat[14], mat[15] + ); + + } else { + + object.position.set( pos[0], pos[1], pos[2] ); + + if ( quat ) { + + object.quaternion.set( quat[0], quat[1], quat[2], quat[3] ); + object.useQuaternion = true; + + } else { + + object.rotation.set( rot[0], rot[1], rot[2] ); + + } + + object.scale.set( scl[0], scl[1], scl[2] ); + + } + + object.visible = objJSON.visible; + object.castShadow = objJSON.castShadow; + object.receiveShadow = objJSON.receiveShadow; + + parent.add( object ); + + result.objects[ objID ] = object; + + } + + // lights + + } else if ( objJSON.type === "DirectionalLight" || objJSON.type === "PointLight" || objJSON.type === "AmbientLight" ) { + + hex = ( objJSON.color !== undefined ) ? objJSON.color : 0xffffff; + intensity = ( objJSON.intensity !== undefined ) ? objJSON.intensity : 1; + + if ( objJSON.type === "DirectionalLight" ) { + + pos = objJSON.direction; + + light = new THREE.DirectionalLight( hex, intensity ); + light.position.set( pos[0], pos[1], pos[2] ); + + if ( objJSON.target ) { + + target_array.push( { "object": light, "targetName" : objJSON.target } ); + + // kill existing default target + // otherwise it gets added to scene when parent gets added + + light.target = null; + + } + + } else if ( objJSON.type === "PointLight" ) { + + pos = objJSON.position; + dst = objJSON.distance; + + light = new THREE.PointLight( hex, intensity, dst ); + light.position.set( pos[0], pos[1], pos[2] ); + + } else if ( objJSON.type === "AmbientLight" ) { + + light = new THREE.AmbientLight( hex ); + + } + + parent.add( light ); + + light.name = objID; + result.lights[ objID ] = light; + result.objects[ objID ] = light; + + // cameras + + } else if ( objJSON.type === "PerspectiveCamera" || objJSON.type === "OrthographicCamera" ) { + + if ( objJSON.type === "PerspectiveCamera" ) { + + camera = new THREE.PerspectiveCamera( objJSON.fov, objJSON.aspect, objJSON.near, objJSON.far ); + + } else if ( objJSON.type === "OrthographicCamera" ) { + + camera = new THREE.OrthographicCamera( objJSON.left, objJSON.right, objJSON.top, objJSON.bottom, objJSON.near, objJSON.far ); + + } + + pos = objJSON.position; + camera.position.set( pos[0], pos[1], pos[2] ); + parent.add( camera ); + + camera.name = objID; + result.cameras[ objID ] = camera; + result.objects[ objID ] = camera; + + // pure Object3D + + } else { + + pos = objJSON.position; + rot = objJSON.rotation; + scl = objJSON.scale; + quat = objJSON.quaternion; + + object = new THREE.Object3D(); + object.name = objID; + object.position.set( pos[0], pos[1], pos[2] ); + + if ( quat ) { + + object.quaternion.set( quat[0], quat[1], quat[2], quat[3] ); + object.useQuaternion = true; + + } else { + + object.rotation.set( rot[0], rot[1], rot[2] ); + + } + + object.scale.set( scl[0], scl[1], scl[2] ); + object.visible = ( objJSON.visible !== undefined ) ? objJSON.visible : false; + + parent.add( object ); + + result.objects[ objID ] = object; + result.empties[ objID ] = object; + + } + + if ( object ) { + + if ( objJSON.properties !== undefined ) { + + for ( var key in objJSON.properties ) { + + var value = objJSON.properties[ key ]; + object.properties[ key ] = value; + + } + + } + + if ( objJSON.groups !== undefined ) { + + for ( var i = 0; i < objJSON.groups.length; i ++ ) { + + var groupID = objJSON.groups[ i ]; + + if ( result.groups[ groupID ] === undefined ) { + + result.groups[ groupID ] = []; + + } + + result.groups[ groupID ].push( objID ); + + } + + } + + if ( objJSON.children !== undefined ) { + + handle_children( object, objJSON.children ); + + } + + } + + } + + } + + }; + + function handle_mesh( geo, mat, id ) { + + result.geometries[ id ] = geo; + result.face_materials[ id ] = mat; + handle_objects(); + + }; + + function handle_hierarchy( node, id, parent, material, obj ) { + + var p = obj.position; + var r = obj.rotation; + var q = obj.quaternion; + var s = obj.scale; + + node.position.set( p[0], p[1], p[2] ); + + if ( q ) { + + node.quaternion.set( q[0], q[1], q[2], q[3] ); + node.useQuaternion = true; + + } else { + + node.rotation.set( r[0], r[1], r[2] ); + + } + + node.scale.set( s[0], s[1], s[2] ); + + // override children materials + // if object material was specified in JSON explicitly + + if ( material ) { + + node.traverse( function ( child ) { + + child.material = material; + + } ); + + } + + // override children visibility + // with root node visibility as specified in JSON + + var visible = ( obj.visible !== undefined ) ? obj.visible : true; + + node.traverse( function ( child ) { + + child.visible = visible; + + } ); + + parent.add( node ); + + node.name = id; + + result.objects[ id ] = node; + handle_objects(); + + }; + + function create_callback_geometry( id ) { + + return function( geo, mat ) { + + handle_mesh( geo, mat, id ); + + counter_models -= 1; + + scope.onLoadComplete(); + + async_callback_gate(); + + } + + }; + + function create_callback_hierachy( id, parent, material, obj ) { + + return function( event ) { + + var result; + + // loaders which use EventDispatcher + + if ( event.content ) { + + result = event.content; + + // ColladaLoader + + } else if ( event.dae ) { + + result = event.scene; + + + // UTF8Loader + + } else { + + result = event; + + } + + handle_hierarchy( result, id, parent, material, obj ); + + counter_models -= 1; + + scope.onLoadComplete(); + + async_callback_gate(); + + } + + }; + + function create_callback_embed( id ) { + + return function( geo, mat ) { + + result.geometries[ id ] = geo; + result.face_materials[ id ] = mat; + + } + + }; + + function async_callback_gate() { + + var progress = { + + totalModels : total_models, + totalTextures : total_textures, + loadedModels : total_models - counter_models, + loadedTextures : total_textures - counter_textures + + }; + + scope.callbackProgress( progress, result ); + + scope.onLoadProgress(); + + if ( counter_models === 0 && counter_textures === 0 ) { + + finalize(); + callbackFinished( result ); + + } + + }; + + function finalize() { + + // take care of targets which could be asynchronously loaded objects + + for ( var i = 0; i < target_array.length; i ++ ) { + + var ta = target_array[ i ]; + + var target = result.objects[ ta.targetName ]; + + if ( target ) { + + ta.object.target = target; + + } else { + + // if there was error and target of specified name doesn't exist in the scene file + // create instead dummy target + // (target must be added to scene explicitly as parent is already added) + + ta.object.target = new THREE.Object3D(); + result.scene.add( ta.object.target ); + + } + + ta.object.target.properties.targetInverse = ta.object; + + } + + }; + + var callbackTexture = function ( count ) { + + counter_textures -= count; + async_callback_gate(); + + scope.onLoadComplete(); + + }; + + // must use this instead of just directly calling callbackTexture + // because of closure in the calling context loop + + var generateTextureCallback = function ( count ) { + + return function() { + + callbackTexture( count ); + + }; + + }; + + // first go synchronous elements + + // fogs + + var fogID, fogJSON; + + for ( fogID in data.fogs ) { + + fogJSON = data.fogs[ fogID ]; + + if ( fogJSON.type === "linear" ) { + + fog = new THREE.Fog( 0x000000, fogJSON.near, fogJSON.far ); + + } else if ( fogJSON.type === "exp2" ) { + + fog = new THREE.FogExp2( 0x000000, fogJSON.density ); + + } + + color = fogJSON.color; + fog.color.setRGB( color[0], color[1], color[2] ); + + result.fogs[ fogID ] = fog; + + } + + // now come potentially asynchronous elements + + // geometries + + // count how many geometries will be loaded asynchronously + + var geoID, geoJSON; + + for ( geoID in data.geometries ) { + + geoJSON = data.geometries[ geoID ]; + + if ( geoJSON.type in this.geometryHandlerMap ) { + + counter_models += 1; + + scope.onLoadStart(); + + } + + } + + // count how many hierarchies will be loaded asynchronously + + var objID, objJSON; + + for ( objID in data.objects ) { + + objJSON = data.objects[ objID ]; + + if ( objJSON.type && ( objJSON.type in this.hierarchyHandlerMap ) ) { + + counter_models += 1; + + scope.onLoadStart(); + + } + + } + + total_models = counter_models; + + for ( geoID in data.geometries ) { + + geoJSON = data.geometries[ geoID ]; + + if ( geoJSON.type === "cube" ) { + + geometry = new THREE.CubeGeometry( geoJSON.width, geoJSON.height, geoJSON.depth, geoJSON.widthSegments, geoJSON.heightSegments, geoJSON.depthSegments ); + result.geometries[ geoID ] = geometry; + + } else if ( geoJSON.type === "plane" ) { + + geometry = new THREE.PlaneGeometry( geoJSON.width, geoJSON.height, geoJSON.widthSegments, geoJSON.heightSegments ); + result.geometries[ geoID ] = geometry; + + } else if ( geoJSON.type === "sphere" ) { + + geometry = new THREE.SphereGeometry( geoJSON.radius, geoJSON.widthSegments, geoJSON.heightSegments ); + result.geometries[ geoID ] = geometry; + + } else if ( geoJSON.type === "cylinder" ) { + + geometry = new THREE.CylinderGeometry( geoJSON.topRad, geoJSON.botRad, geoJSON.height, geoJSON.radSegs, geoJSON.heightSegs ); + result.geometries[ geoID ] = geometry; + + } else if ( geoJSON.type === "torus" ) { + + geometry = new THREE.TorusGeometry( geoJSON.radius, geoJSON.tube, geoJSON.segmentsR, geoJSON.segmentsT ); + result.geometries[ geoID ] = geometry; + + } else if ( geoJSON.type === "icosahedron" ) { + + geometry = new THREE.IcosahedronGeometry( geoJSON.radius, geoJSON.subdivisions ); + result.geometries[ geoID ] = geometry; + + } else if ( geoJSON.type in this.geometryHandlerMap ) { + + var loaderParameters = {}; + + for ( var parType in geoJSON ) { + + if ( parType !== "type" && parType !== "url" ) { + + loaderParameters[ parType ] = geoJSON[ parType ]; + + } + + } + + var loader = this.geometryHandlerMap[ geoJSON.type ][ "loaderObject" ]; + loader.load( get_url( geoJSON.url, data.urlBaseType ), create_callback_geometry( geoID ), loaderParameters ); + + } else if ( geoJSON.type === "embedded" ) { + + var modelJson = data.embeds[ geoJSON.id ], + texture_path = ""; + + // pass metadata along to jsonLoader so it knows the format version + + modelJson.metadata = data.metadata; + + if ( modelJson ) { + + var jsonLoader = this.geometryHandlerMap[ "ascii" ][ "loaderObject" ]; + jsonLoader.createModel( modelJson, create_callback_embed( geoID ), texture_path ); + + } + + } + + } + + // textures + + // count how many textures will be loaded asynchronously + + var textureID, textureJSON; + + for ( textureID in data.textures ) { + + textureJSON = data.textures[ textureID ]; + + if ( textureJSON.url instanceof Array ) { + + counter_textures += textureJSON.url.length; + + for( var n = 0; n < textureJSON.url.length; n ++ ) { + + scope.onLoadStart(); + + } + + } else { + + counter_textures += 1; + + scope.onLoadStart(); + + } + + } + + total_textures = counter_textures; + + for ( textureID in data.textures ) { + + textureJSON = data.textures[ textureID ]; + + if ( textureJSON.mapping !== undefined && THREE[ textureJSON.mapping ] !== undefined ) { + + textureJSON.mapping = new THREE[ textureJSON.mapping ](); + + } + + if ( textureJSON.url instanceof Array ) { + + var count = textureJSON.url.length; + var url_array = []; + + for( var i = 0; i < count; i ++ ) { + + url_array[ i ] = get_url( textureJSON.url[ i ], data.urlBaseType ); + + } + + var isCompressed = /\.dds$/i.test( url_array[ 0 ] ); + + if ( isCompressed ) { + + texture = THREE.ImageUtils.loadCompressedTextureCube( url_array, textureJSON.mapping, generateTextureCallback( count ) ); + + } else { + + texture = THREE.ImageUtils.loadTextureCube( url_array, textureJSON.mapping, generateTextureCallback( count ) ); + + } + + } else { + + var isCompressed = /\.dds$/i.test( textureJSON.url ); + var fullUrl = get_url( textureJSON.url, data.urlBaseType ); + var textureCallback = generateTextureCallback( 1 ); + + if ( isCompressed ) { + + texture = THREE.ImageUtils.loadCompressedTexture( fullUrl, textureJSON.mapping, textureCallback ); + + } else { + + texture = THREE.ImageUtils.loadTexture( fullUrl, textureJSON.mapping, textureCallback ); + + } + + if ( THREE[ textureJSON.minFilter ] !== undefined ) + texture.minFilter = THREE[ textureJSON.minFilter ]; + + if ( THREE[ textureJSON.magFilter ] !== undefined ) + texture.magFilter = THREE[ textureJSON.magFilter ]; + + if ( textureJSON.anisotropy ) texture.anisotropy = textureJSON.anisotropy; + + if ( textureJSON.repeat ) { + + texture.repeat.set( textureJSON.repeat[ 0 ], textureJSON.repeat[ 1 ] ); + + if ( textureJSON.repeat[ 0 ] !== 1 ) texture.wrapS = THREE.RepeatWrapping; + if ( textureJSON.repeat[ 1 ] !== 1 ) texture.wrapT = THREE.RepeatWrapping; + + } + + if ( textureJSON.offset ) { + + texture.offset.set( textureJSON.offset[ 0 ], textureJSON.offset[ 1 ] ); + + } + + // handle wrap after repeat so that default repeat can be overriden + + if ( textureJSON.wrap ) { + + var wrapMap = { + "repeat" : THREE.RepeatWrapping, + "mirror" : THREE.MirroredRepeatWrapping + } + + if ( wrapMap[ textureJSON.wrap[ 0 ] ] !== undefined ) texture.wrapS = wrapMap[ textureJSON.wrap[ 0 ] ]; + if ( wrapMap[ textureJSON.wrap[ 1 ] ] !== undefined ) texture.wrapT = wrapMap[ textureJSON.wrap[ 1 ] ]; + + } + + } + + result.textures[ textureID ] = texture; + + } + + // materials + + var matID, matJSON; + var parID; + + for ( matID in data.materials ) { + + matJSON = data.materials[ matID ]; + + for ( parID in matJSON.parameters ) { + + if ( parID === "envMap" || parID === "map" || parID === "lightMap" || parID === "bumpMap" ) { + + matJSON.parameters[ parID ] = result.textures[ matJSON.parameters[ parID ] ]; + + } else if ( parID === "shading" ) { + + matJSON.parameters[ parID ] = ( matJSON.parameters[ parID ] === "flat" ) ? THREE.FlatShading : THREE.SmoothShading; + + } else if ( parID === "side" ) { + + if ( matJSON.parameters[ parID ] == "double" ) { + + matJSON.parameters[ parID ] = THREE.DoubleSide; + + } else if ( matJSON.parameters[ parID ] == "back" ) { + + matJSON.parameters[ parID ] = THREE.BackSide; + + } else { + + matJSON.parameters[ parID ] = THREE.FrontSide; + + } + + } else if ( parID === "blending" ) { + + matJSON.parameters[ parID ] = matJSON.parameters[ parID ] in THREE ? THREE[ matJSON.parameters[ parID ] ] : THREE.NormalBlending; + + } else if ( parID === "combine" ) { + + matJSON.parameters[ parID ] = matJSON.parameters[ parID ] in THREE ? THREE[ matJSON.parameters[ parID ] ] : THREE.MultiplyOperation; + + } else if ( parID === "vertexColors" ) { + + if ( matJSON.parameters[ parID ] == "face" ) { + + matJSON.parameters[ parID ] = THREE.FaceColors; + + // default to vertex colors if "vertexColors" is anything else face colors or 0 / null / false + + } else if ( matJSON.parameters[ parID ] ) { + + matJSON.parameters[ parID ] = THREE.VertexColors; + + } + + } else if ( parID === "wrapRGB" ) { + + var v3 = matJSON.parameters[ parID ]; + matJSON.parameters[ parID ] = new THREE.Vector3( v3[ 0 ], v3[ 1 ], v3[ 2 ] ); + + } + + } + + if ( matJSON.parameters.opacity !== undefined && matJSON.parameters.opacity < 1.0 ) { + + matJSON.parameters.transparent = true; + + } + + if ( matJSON.parameters.normalMap ) { + + var shader = THREE.ShaderLib[ "normalmap" ]; + var uniforms = THREE.UniformsUtils.clone( shader.uniforms ); + + var diffuse = matJSON.parameters.color; + var specular = matJSON.parameters.specular; + var ambient = matJSON.parameters.ambient; + var shininess = matJSON.parameters.shininess; + + uniforms[ "tNormal" ].value = result.textures[ matJSON.parameters.normalMap ]; + + if ( matJSON.parameters.normalScale ) { + + uniforms[ "uNormalScale" ].value.set( matJSON.parameters.normalScale[ 0 ], matJSON.parameters.normalScale[ 1 ] ); + + } + + if ( matJSON.parameters.map ) { + + uniforms[ "tDiffuse" ].value = matJSON.parameters.map; + uniforms[ "enableDiffuse" ].value = true; + + } + + if ( matJSON.parameters.envMap ) { + + uniforms[ "tCube" ].value = matJSON.parameters.envMap; + uniforms[ "enableReflection" ].value = true; + uniforms[ "uReflectivity" ].value = matJSON.parameters.reflectivity; + + } + + if ( matJSON.parameters.lightMap ) { + + uniforms[ "tAO" ].value = matJSON.parameters.lightMap; + uniforms[ "enableAO" ].value = true; + + } + + if ( matJSON.parameters.specularMap ) { + + uniforms[ "tSpecular" ].value = result.textures[ matJSON.parameters.specularMap ]; + uniforms[ "enableSpecular" ].value = true; + + } + + if ( matJSON.parameters.displacementMap ) { + + uniforms[ "tDisplacement" ].value = result.textures[ matJSON.parameters.displacementMap ]; + uniforms[ "enableDisplacement" ].value = true; + + uniforms[ "uDisplacementBias" ].value = matJSON.parameters.displacementBias; + uniforms[ "uDisplacementScale" ].value = matJSON.parameters.displacementScale; + + } + + uniforms[ "uDiffuseColor" ].value.setHex( diffuse ); + uniforms[ "uSpecularColor" ].value.setHex( specular ); + uniforms[ "uAmbientColor" ].value.setHex( ambient ); + + uniforms[ "uShininess" ].value = shininess; + + if ( matJSON.parameters.opacity ) { + + uniforms[ "uOpacity" ].value = matJSON.parameters.opacity; + + } + + var parameters = { fragmentShader: shader.fragmentShader, vertexShader: shader.vertexShader, uniforms: uniforms, lights: true, fog: true }; + + material = new THREE.ShaderMaterial( parameters ); + + } else { + + material = new THREE[ matJSON.type ]( matJSON.parameters ); + + } + + result.materials[ matID ] = material; + + } + + // second pass through all materials to initialize MeshFaceMaterials + // that could be referring to other materials out of order + + for ( matID in data.materials ) { + + matJSON = data.materials[ matID ]; + + if ( matJSON.parameters.materials ) { + + var materialArray = []; + + for ( var i = 0; i < matJSON.parameters.materials.length; i ++ ) { + + var label = matJSON.parameters.materials[ i ]; + materialArray.push( result.materials[ label ] ); + + } + + result.materials[ matID ].materials = materialArray; + + } + + } + + // objects ( synchronous init of procedural primitives ) + + handle_objects(); + + // defaults + + if ( result.cameras && data.defaults.camera ) { + + result.currentCamera = result.cameras[ data.defaults.camera ]; + + } + + if ( result.fogs && data.defaults.fog ) { + + result.scene.fog = result.fogs[ data.defaults.fog ]; + + } + + // synchronous callback + + scope.callbackSync( result ); + + // just in case there are no async elements + + async_callback_gate(); + +}; +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.TextureLoader = function () { + + THREE.EventDispatcher.call( this ); + + this.crossOrigin = null; + +}; + +THREE.TextureLoader.prototype = { + + constructor: THREE.TextureLoader, + + load: function ( url ) { + + var scope = this; + + var image = new Image(); + + image.addEventListener( 'load', function () { + + var texture = new THREE.Texture( image ); + texture.needsUpdate = true; + + scope.dispatchEvent( { type: 'load', content: texture } ); + + }, false ); + + image.addEventListener( 'error', function () { + + scope.dispatchEvent( { type: 'error', message: 'Couldn\'t load URL [' + url + ']' } ); + + }, false ); + + if ( scope.crossOrigin ) image.crossOrigin = scope.crossOrigin; + + image.src = url; + + } + +} +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Material = function () { + + THREE.EventDispatcher.call( this ); + + this.id = THREE.MaterialIdCount ++; + + this.name = ''; + + this.side = THREE.FrontSide; + + this.opacity = 1; + this.transparent = false; + + this.blending = THREE.NormalBlending; + + this.blendSrc = THREE.SrcAlphaFactor; + this.blendDst = THREE.OneMinusSrcAlphaFactor; + this.blendEquation = THREE.AddEquation; + + this.depthTest = true; + this.depthWrite = true; + + this.polygonOffset = false; + this.polygonOffsetFactor = 0; + this.polygonOffsetUnits = 0; + + this.alphaTest = 0; + + this.overdraw = false; // Boolean for fixing antialiasing gaps in CanvasRenderer + + this.visible = true; + + this.needsUpdate = true; + +}; + +THREE.Material.prototype.setValues = function ( values ) { + + if ( values === undefined ) return; + + for ( var key in values ) { + + var newValue = values[ key ]; + + if ( newValue === undefined ) { + + console.warn( 'THREE.Material: \'' + key + '\' parameter is undefined.' ); + continue; + + } + + if ( key in this ) { + + var currentValue = this[ key ]; + + if ( currentValue instanceof THREE.Color && newValue instanceof THREE.Color ) { + + currentValue.copy( newValue ); + + } else if ( currentValue instanceof THREE.Color ) { + + currentValue.set( newValue ); + + } else if ( currentValue instanceof THREE.Vector3 && newValue instanceof THREE.Vector3 ) { + + currentValue.copy( newValue ); + + } else { + + this[ key ] = newValue; + + } + + } + + } + +}; + +THREE.Material.prototype.clone = function ( material ) { + + if ( material === undefined ) material = new THREE.Material(); + + material.name = this.name; + + material.side = this.side; + + material.opacity = this.opacity; + material.transparent = this.transparent; + + material.blending = this.blending; + + material.blendSrc = this.blendSrc; + material.blendDst = this.blendDst; + material.blendEquation = this.blendEquation; + + material.depthTest = this.depthTest; + material.depthWrite = this.depthWrite; + + material.polygonOffset = this.polygonOffset; + material.polygonOffsetFactor = this.polygonOffsetFactor; + material.polygonOffsetUnits = this.polygonOffsetUnits; + + material.alphaTest = this.alphaTest; + + material.overdraw = this.overdraw; + + material.visible = this.visible; + + return material; + +}; + +THREE.Material.prototype.dispose = function () { + + this.dispatchEvent( { type: 'dispose' } ); + +}; + +THREE.MaterialIdCount = 0; +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: <hex>, + * opacity: <float>, + * + * blending: THREE.NormalBlending, + * depthTest: <bool>, + * depthWrite: <bool>, + * + * linewidth: <float>, + * linecap: "round", + * linejoin: "round", + * + * vertexColors: <bool> + * + * fog: <bool> + * } + */ + +THREE.LineBasicMaterial = function ( parameters ) { + + THREE.Material.call( this ); + + this.color = new THREE.Color( 0xffffff ); + + this.linewidth = 1; + this.linecap = 'round'; + this.linejoin = 'round'; + + this.vertexColors = false; + + this.fog = true; + + this.setValues( parameters ); + +}; + +THREE.LineBasicMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.LineBasicMaterial.prototype.clone = function () { + + var material = new THREE.LineBasicMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.color.copy( this.color ); + + material.linewidth = this.linewidth; + material.linecap = this.linecap; + material.linejoin = this.linejoin; + + material.vertexColors = this.vertexColors; + + material.fog = this.fog; + + return material; + +}; +/** + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: <hex>, + * opacity: <float>, + * + * blending: THREE.NormalBlending, + * depthTest: <bool>, + * depthWrite: <bool>, + * + * linewidth: <float>, + * + * scale: <float>, + * dashSize: <float>, + * gapSize: <float>, + * + * vertexColors: <bool> + * + * fog: <bool> + * } + */ + +THREE.LineDashedMaterial = function ( parameters ) { + + THREE.Material.call( this ); + + this.color = new THREE.Color( 0xffffff ); + + this.linewidth = 1; + + this.scale = 1; + this.dashSize = 3; + this.gapSize = 1; + + this.vertexColors = false; + + this.fog = true; + + this.setValues( parameters ); + +}; + +THREE.LineDashedMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.LineDashedMaterial.prototype.clone = function () { + + var material = new THREE.LineDashedMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.color.copy( this.color ); + + material.linewidth = this.linewidth; + + material.scale = this.scale; + material.dashSize = this.dashSize; + material.gapSize = this.gapSize; + + material.vertexColors = this.vertexColors; + + material.fog = this.fog; + + return material; + +}; +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: <hex>, + * opacity: <float>, + * map: new THREE.Texture( <Image> ), + * + * lightMap: new THREE.Texture( <Image> ), + * + * specularMap: new THREE.Texture( <Image> ), + * + * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), + * combine: THREE.Multiply, + * reflectivity: <float>, + * refractionRatio: <float>, + * + * shading: THREE.SmoothShading, + * blending: THREE.NormalBlending, + * depthTest: <bool>, + * depthWrite: <bool>, + * + * wireframe: <boolean>, + * wireframeLinewidth: <float>, + * + * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, + * + * skinning: <bool>, + * morphTargets: <bool>, + * + * fog: <bool> + * } + */ + +THREE.MeshBasicMaterial = function ( parameters ) { + + THREE.Material.call( this ); + + this.color = new THREE.Color( 0xffffff ); // emissive + + this.map = null; + + this.lightMap = null; + + this.specularMap = null; + + this.envMap = null; + this.combine = THREE.MultiplyOperation; + this.reflectivity = 1; + this.refractionRatio = 0.98; + + this.fog = true; + + this.shading = THREE.SmoothShading; + + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; + + this.vertexColors = THREE.NoColors; + + this.skinning = false; + this.morphTargets = false; + + this.setValues( parameters ); + +}; + +THREE.MeshBasicMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.MeshBasicMaterial.prototype.clone = function () { + + var material = new THREE.MeshBasicMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.color.copy( this.color ); + + material.map = this.map; + + material.lightMap = this.lightMap; + + material.specularMap = this.specularMap; + + material.envMap = this.envMap; + material.combine = this.combine; + material.reflectivity = this.reflectivity; + material.refractionRatio = this.refractionRatio; + + material.fog = this.fog; + + material.shading = this.shading; + + material.wireframe = this.wireframe; + material.wireframeLinewidth = this.wireframeLinewidth; + material.wireframeLinecap = this.wireframeLinecap; + material.wireframeLinejoin = this.wireframeLinejoin; + + material.vertexColors = this.vertexColors; + + material.skinning = this.skinning; + material.morphTargets = this.morphTargets; + + return material; + +}; +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: <hex>, + * ambient: <hex>, + * emissive: <hex>, + * opacity: <float>, + * + * map: new THREE.Texture( <Image> ), + * + * lightMap: new THREE.Texture( <Image> ), + * + * specularMap: new THREE.Texture( <Image> ), + * + * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), + * combine: THREE.Multiply, + * reflectivity: <float>, + * refractionRatio: <float>, + * + * shading: THREE.SmoothShading, + * blending: THREE.NormalBlending, + * depthTest: <bool>, + * depthWrite: <bool>, + * + * wireframe: <boolean>, + * wireframeLinewidth: <float>, + * + * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, + * + * skinning: <bool>, + * morphTargets: <bool>, + * morphNormals: <bool>, + * + * fog: <bool> + * } + */ + +THREE.MeshLambertMaterial = function ( parameters ) { + + THREE.Material.call( this ); + + this.color = new THREE.Color( 0xffffff ); // diffuse + this.ambient = new THREE.Color( 0xffffff ); + this.emissive = new THREE.Color( 0x000000 ); + + this.wrapAround = false; + this.wrapRGB = new THREE.Vector3( 1, 1, 1 ); + + this.map = null; + + this.lightMap = null; + + this.specularMap = null; + + this.envMap = null; + this.combine = THREE.MultiplyOperation; + this.reflectivity = 1; + this.refractionRatio = 0.98; + + this.fog = true; + + this.shading = THREE.SmoothShading; + + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; + + this.vertexColors = THREE.NoColors; + + this.skinning = false; + this.morphTargets = false; + this.morphNormals = false; + + this.setValues( parameters ); + +}; + +THREE.MeshLambertMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.MeshLambertMaterial.prototype.clone = function () { + + var material = new THREE.MeshLambertMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.color.copy( this.color ); + material.ambient.copy( this.ambient ); + material.emissive.copy( this.emissive ); + + material.wrapAround = this.wrapAround; + material.wrapRGB.copy( this.wrapRGB ); + + material.map = this.map; + + material.lightMap = this.lightMap; + + material.specularMap = this.specularMap; + + material.envMap = this.envMap; + material.combine = this.combine; + material.reflectivity = this.reflectivity; + material.refractionRatio = this.refractionRatio; + + material.fog = this.fog; + + material.shading = this.shading; + + material.wireframe = this.wireframe; + material.wireframeLinewidth = this.wireframeLinewidth; + material.wireframeLinecap = this.wireframeLinecap; + material.wireframeLinejoin = this.wireframeLinejoin; + + material.vertexColors = this.vertexColors; + + material.skinning = this.skinning; + material.morphTargets = this.morphTargets; + material.morphNormals = this.morphNormals; + + return material; + +}; +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: <hex>, + * ambient: <hex>, + * emissive: <hex>, + * specular: <hex>, + * shininess: <float>, + * opacity: <float>, + * + * map: new THREE.Texture( <Image> ), + * + * lightMap: new THREE.Texture( <Image> ), + * + * bumpMap: new THREE.Texture( <Image> ), + * bumpScale: <float>, + * + * normalMap: new THREE.Texture( <Image> ), + * normalScale: <Vector2>, + * + * specularMap: new THREE.Texture( <Image> ), + * + * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), + * combine: THREE.Multiply, + * reflectivity: <float>, + * refractionRatio: <float>, + * + * shading: THREE.SmoothShading, + * blending: THREE.NormalBlending, + * depthTest: <bool>, + * depthWrite: <bool>, + * + * wireframe: <boolean>, + * wireframeLinewidth: <float>, + * + * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, + * + * skinning: <bool>, + * morphTargets: <bool>, + * morphNormals: <bool>, + * + * fog: <bool> + * } + */ + +THREE.MeshPhongMaterial = function ( parameters ) { + + THREE.Material.call( this ); + + this.color = new THREE.Color( 0xffffff ); // diffuse + this.ambient = new THREE.Color( 0xffffff ); + this.emissive = new THREE.Color( 0x000000 ); + this.specular = new THREE.Color( 0x111111 ); + this.shininess = 30; + + this.metal = false; + this.perPixel = true; + + this.wrapAround = false; + this.wrapRGB = new THREE.Vector3( 1, 1, 1 ); + + this.map = null; + + this.lightMap = null; + + this.bumpMap = null; + this.bumpScale = 1; + + this.normalMap = null; + this.normalScale = new THREE.Vector2( 1, 1 ); + + this.specularMap = null; + + this.envMap = null; + this.combine = THREE.MultiplyOperation; + this.reflectivity = 1; + this.refractionRatio = 0.98; + + this.fog = true; + + this.shading = THREE.SmoothShading; + + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; + + this.vertexColors = THREE.NoColors; + + this.skinning = false; + this.morphTargets = false; + this.morphNormals = false; + + this.setValues( parameters ); + +}; + +THREE.MeshPhongMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.MeshPhongMaterial.prototype.clone = function () { + + var material = new THREE.MeshPhongMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.color.copy( this.color ); + material.ambient.copy( this.ambient ); + material.emissive.copy( this.emissive ); + material.specular.copy( this.specular ); + material.shininess = this.shininess; + + material.metal = this.metal; + material.perPixel = this.perPixel; + + material.wrapAround = this.wrapAround; + material.wrapRGB.copy( this.wrapRGB ); + + material.map = this.map; + + material.lightMap = this.lightMap; + + material.bumpMap = this.bumpMap; + material.bumpScale = this.bumpScale; + + material.normalMap = this.normalMap; + material.normalScale.copy( this.normalScale ); + + material.specularMap = this.specularMap; + + material.envMap = this.envMap; + material.combine = this.combine; + material.reflectivity = this.reflectivity; + material.refractionRatio = this.refractionRatio; + + material.fog = this.fog; + + material.shading = this.shading; + + material.wireframe = this.wireframe; + material.wireframeLinewidth = this.wireframeLinewidth; + material.wireframeLinecap = this.wireframeLinecap; + material.wireframeLinejoin = this.wireframeLinejoin; + + material.vertexColors = this.vertexColors; + + material.skinning = this.skinning; + material.morphTargets = this.morphTargets; + material.morphNormals = this.morphNormals; + + return material; + +}; +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * opacity: <float>, + * + * blending: THREE.NormalBlending, + * depthTest: <bool>, + * depthWrite: <bool>, + * + * wireframe: <boolean>, + * wireframeLinewidth: <float> + * } + */ + +THREE.MeshDepthMaterial = function ( parameters ) { + + THREE.Material.call( this ); + + this.wireframe = false; + this.wireframeLinewidth = 1; + + this.setValues( parameters ); + +}; + +THREE.MeshDepthMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.MeshDepthMaterial.prototype.clone = function () { + + var material = new THREE.LineBasicMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.wireframe = this.wireframe; + material.wireframeLinewidth = this.wireframeLinewidth; + + return material; + +}; +/** + * @author mrdoob / http://mrdoob.com/ + * + * parameters = { + * opacity: <float>, + * + * shading: THREE.FlatShading, + * blending: THREE.NormalBlending, + * depthTest: <bool>, + * depthWrite: <bool>, + * + * wireframe: <boolean>, + * wireframeLinewidth: <float> + * } + */ + +THREE.MeshNormalMaterial = function ( parameters ) { + + THREE.Material.call( this, parameters ); + + this.shading = THREE.FlatShading; + + this.wireframe = false; + this.wireframeLinewidth = 1; + + this.setValues( parameters ); + +}; + +THREE.MeshNormalMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.MeshNormalMaterial.prototype.clone = function () { + + var material = new THREE.MeshNormalMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.shading = this.shading; + + material.wireframe = this.wireframe; + material.wireframeLinewidth = this.wireframeLinewidth; + + return material; + +}; +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.MeshFaceMaterial = function ( materials ) { + + this.materials = materials instanceof Array ? materials : []; + +}; + +THREE.MeshFaceMaterial.prototype.clone = function () { + + return new THREE.MeshFaceMaterial( this.materials.slice( 0 ) ); + +}; +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: <hex>, + * opacity: <float>, + * map: new THREE.Texture( <Image> ), + * + * size: <float>, + * + * blending: THREE.NormalBlending, + * depthTest: <bool>, + * depthWrite: <bool>, + * + * vertexColors: <bool>, + * + * fog: <bool> + * } + */ + +THREE.ParticleBasicMaterial = function ( parameters ) { + + THREE.Material.call( this ); + + this.color = new THREE.Color( 0xffffff ); + + this.map = null; + + this.size = 1; + this.sizeAttenuation = true; + + this.vertexColors = false; + + this.fog = true; + + this.setValues( parameters ); + +}; + +THREE.ParticleBasicMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.ParticleBasicMaterial.prototype.clone = function () { + + var material = new THREE.ParticleBasicMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.color.copy( this.color ); + + material.map = this.map; + + material.size = this.size; + material.sizeAttenuation = this.sizeAttenuation; + + material.vertexColors = this.vertexColors; + + material.fog = this.fog; + + return material; + +}; +/** + * @author mrdoob / http://mrdoob.com/ + * + * parameters = { + * color: <hex>, + * program: <function>, + * opacity: <float>, + * blending: THREE.NormalBlending + * } + */ + +THREE.ParticleCanvasMaterial = function ( parameters ) { + + THREE.Material.call( this ); + + this.color = new THREE.Color( 0xffffff ); + this.program = function ( context, color ) {}; + + this.setValues( parameters ); + +}; + +THREE.ParticleCanvasMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.ParticleCanvasMaterial.prototype.clone = function () { + + var material = new THREE.ParticleCanvasMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.color.copy( this.color ); + material.program = this.program; + + return material; + +}; +/** + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * fragmentShader: <string>, + * vertexShader: <string>, + * + * uniforms: { "parameter1": { type: "f", value: 1.0 }, "parameter2": { type: "i" value2: 2 } }, + * + * defines: { "label" : "value" }, + * + * shading: THREE.SmoothShading, + * blending: THREE.NormalBlending, + * depthTest: <bool>, + * depthWrite: <bool>, + * + * wireframe: <boolean>, + * wireframeLinewidth: <float>, + * + * lights: <bool>, + * + * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, + * + * skinning: <bool>, + * morphTargets: <bool>, + * morphNormals: <bool>, + * + * fog: <bool> + * } + */ + +THREE.ShaderMaterial = function ( parameters ) { + + THREE.Material.call( this ); + + this.fragmentShader = "void main() {}"; + this.vertexShader = "void main() {}"; + this.uniforms = {}; + this.defines = {}; + this.attributes = null; + + this.shading = THREE.SmoothShading; + + this.wireframe = false; + this.wireframeLinewidth = 1; + + this.fog = false; // set to use scene fog + + this.lights = false; // set to use scene lights + + this.vertexColors = THREE.NoColors; // set to use "color" attribute stream + + this.skinning = false; // set to use skinning attribute streams + + this.morphTargets = false; // set to use morph targets + this.morphNormals = false; // set to use morph normals + + this.setValues( parameters ); + +}; + +THREE.ShaderMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.ShaderMaterial.prototype.clone = function () { + + var material = new THREE.ShaderMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.fragmentShader = this.fragmentShader; + material.vertexShader = this.vertexShader; + + material.uniforms = THREE.UniformsUtils.clone( this.uniforms ); + + material.attributes = this.attributes; + material.defines = this.defines; + + material.shading = this.shading; + + material.wireframe = this.wireframe; + material.wireframeLinewidth = this.wireframeLinewidth; + + material.fog = this.fog; + + material.lights = this.lights; + + material.vertexColors = this.vertexColors; + + material.skinning = this.skinning; + + material.morphTargets = this.morphTargets; + material.morphNormals = this.morphNormals; + + return material; + +}; +/** + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: <hex>, + * opacity: <float>, + * map: new THREE.Texture( <Image> ), + * + * blending: THREE.NormalBlending, + * depthTest: <bool>, + * depthWrite: <bool>, + * + * useScreenCoordinates: <bool>, + * sizeAttenuation: <bool>, + * scaleByViewport: <bool>, + * alignment: THREE.SpriteAlignment.center, + * + * uvOffset: new THREE.Vector2(), + * uvScale: new THREE.Vector2(), + * + * fog: <bool> + * } + */ + +THREE.SpriteMaterial = function ( parameters ) { + + THREE.Material.call( this ); + + // defaults + + this.color = new THREE.Color( 0xffffff ); + this.map = new THREE.Texture(); + + this.useScreenCoordinates = true; + this.depthTest = !this.useScreenCoordinates; + this.sizeAttenuation = !this.useScreenCoordinates; + this.scaleByViewport = !this.sizeAttenuation; + this.alignment = THREE.SpriteAlignment.center.clone(); + + this.fog = false; + + this.uvOffset = new THREE.Vector2( 0, 0 ); + this.uvScale = new THREE.Vector2( 1, 1 ); + + // set parameters + + this.setValues( parameters ); + + // override coupled defaults if not specified explicitly by parameters + + parameters = parameters || {}; + + if ( parameters.depthTest === undefined ) this.depthTest = !this.useScreenCoordinates; + if ( parameters.sizeAttenuation === undefined ) this.sizeAttenuation = !this.useScreenCoordinates; + if ( parameters.scaleByViewport === undefined ) this.scaleByViewport = !this.sizeAttenuation; + +}; + +THREE.SpriteMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.SpriteMaterial.prototype.clone = function () { + + var material = new THREE.SpriteMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.color.copy( this.color ); + material.map = this.map; + + material.useScreenCoordinates = this.useScreenCoordinates; + material.sizeAttenuation = this.sizeAttenuation; + material.scaleByViewport = this.scaleByViewport; + material.alignment.copy( this.alignment ); + + material.uvOffset.copy( this.uvOffset ); + material.uvScale.copy( this.uvScale ); + + material.fog = this.fog; + + return material; + +}; + +// Alignment enums + +THREE.SpriteAlignment = {}; +THREE.SpriteAlignment.topLeft = new THREE.Vector2( 1, -1 ); +THREE.SpriteAlignment.topCenter = new THREE.Vector2( 0, -1 ); +THREE.SpriteAlignment.topRight = new THREE.Vector2( -1, -1 ); +THREE.SpriteAlignment.centerLeft = new THREE.Vector2( 1, 0 ); +THREE.SpriteAlignment.center = new THREE.Vector2( 0, 0 ); +THREE.SpriteAlignment.centerRight = new THREE.Vector2( -1, 0 ); +THREE.SpriteAlignment.bottomLeft = new THREE.Vector2( 1, 1 ); +THREE.SpriteAlignment.bottomCenter = new THREE.Vector2( 0, 1 ); +THREE.SpriteAlignment.bottomRight = new THREE.Vector2( -1, 1 ); +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * @author szimek / https://github.com/szimek/ + */ + +THREE.Texture = function ( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { + + THREE.EventDispatcher.call( this ); + + this.id = THREE.TextureIdCount ++; + + this.name = ''; + + this.image = image; + this.mipmaps = []; + + this.mapping = mapping !== undefined ? mapping : new THREE.UVMapping(); + + this.wrapS = wrapS !== undefined ? wrapS : THREE.ClampToEdgeWrapping; + this.wrapT = wrapT !== undefined ? wrapT : THREE.ClampToEdgeWrapping; + + this.magFilter = magFilter !== undefined ? magFilter : THREE.LinearFilter; + this.minFilter = minFilter !== undefined ? minFilter : THREE.LinearMipMapLinearFilter; + + this.anisotropy = anisotropy !== undefined ? anisotropy : 1; + + this.format = format !== undefined ? format : THREE.RGBAFormat; + this.type = type !== undefined ? type : THREE.UnsignedByteType; + + this.offset = new THREE.Vector2( 0, 0 ); + this.repeat = new THREE.Vector2( 1, 1 ); + + this.generateMipmaps = true; + this.premultiplyAlpha = false; + this.flipY = true; + this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml) + + this.needsUpdate = false; + this.onUpdate = null; + +}; + +THREE.Texture.prototype = { + + constructor: THREE.Texture, + + clone: function ( texture ) { + + if ( texture === undefined ) texture = new THREE.Texture(); + + texture.image = this.image; + texture.mipmaps = this.mipmaps.slice(0); + + texture.mapping = this.mapping; + + texture.wrapS = this.wrapS; + texture.wrapT = this.wrapT; + + texture.magFilter = this.magFilter; + texture.minFilter = this.minFilter; + + texture.anisotropy = this.anisotropy; + + texture.format = this.format; + texture.type = this.type; + + texture.offset.copy( this.offset ); + texture.repeat.copy( this.repeat ); + + texture.generateMipmaps = this.generateMipmaps; + texture.premultiplyAlpha = this.premultiplyAlpha; + texture.flipY = this.flipY; + texture.unpackAlignment = this.unpackAlignment; + + return texture; + + }, + + dispose: function () { + + this.dispatchEvent( { type: 'dispose' } ); + + } + +}; + +THREE.TextureIdCount = 0; +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.CompressedTexture = function ( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy ) { + + THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); + + this.image = { width: width, height: height }; + this.mipmaps = mipmaps; + + this.generateMipmaps = false; // WebGL currently can't generate mipmaps for compressed textures, they must be embedded in DDS file + +}; + +THREE.CompressedTexture.prototype = Object.create( THREE.Texture.prototype ); + +THREE.CompressedTexture.prototype.clone = function () { + + var texture = new THREE.CompressedTexture(); + + THREE.Texture.prototype.clone.call( this, texture ); + + return texture; + +}; +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.DataTexture = function ( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy ) { + + THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); + + this.image = { data: data, width: width, height: height }; + +}; + +THREE.DataTexture.prototype = Object.create( THREE.Texture.prototype ); + +THREE.DataTexture.prototype.clone = function () { + + var texture = new THREE.DataTexture(); + + THREE.Texture.prototype.clone.call( this, texture ); + + return texture; + +}; +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.Particle = function ( material ) { + + THREE.Object3D.call( this ); + + this.material = material; + +}; + +THREE.Particle.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.Particle.prototype.clone = function ( object ) { + + if ( object === undefined ) object = new THREE.Particle( this.material ); + + THREE.Object3D.prototype.clone.call( this, object ); + + return object; + +}; +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.ParticleSystem = function ( geometry, material ) { + + THREE.Object3D.call( this ); + + this.geometry = geometry; + this.material = ( material !== undefined ) ? material : new THREE.ParticleBasicMaterial( { color: Math.random() * 0xffffff } ); + + this.sortParticles = false; + + if ( this.geometry ) { + + // calc bound radius + + if( this.geometry.boundingSphere === null ) { + + this.geometry.computeBoundingSphere(); + + } + + } + + this.frustumCulled = false; + +}; + +THREE.ParticleSystem.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.ParticleSystem.prototype.clone = function ( object ) { + + if ( object === undefined ) object = new THREE.ParticleSystem( this.geometry, this.material ); + object.sortParticles = this.sortParticles; + + THREE.Object3D.prototype.clone.call( this, object ); + + return object; + +}; +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.Line = function ( geometry, material, type ) { + + THREE.Object3D.call( this ); + + this.geometry = geometry; + this.material = ( material !== undefined ) ? material : new THREE.LineBasicMaterial( { color: Math.random() * 0xffffff } ); + this.type = ( type !== undefined ) ? type : THREE.LineStrip; + + if ( this.geometry ) { + + if ( ! this.geometry.boundingSphere ) { + + this.geometry.computeBoundingSphere(); + + } + + } + +}; + +THREE.LineStrip = 0; +THREE.LinePieces = 1; + +THREE.Line.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.Line.prototype.clone = function ( object ) { + + if ( object === undefined ) object = new THREE.Line( this.geometry, this.material, this.type ); + + THREE.Object3D.prototype.clone.call( this, object ); + + return object; + +}; +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * @author mikael emtinger / http://gomo.se/ + * @author jonobr1 / http://jonobr1.com/ + */ + +THREE.Mesh = function ( geometry, material ) { + + THREE.Object3D.call( this ); + + this.geometry = geometry; + this.material = ( material !== undefined ) ? material : new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff, wireframe: true } ); + + if ( this.geometry !== undefined ) { + + if ( this.geometry.boundingSphere === null ) { + + this.geometry.computeBoundingSphere(); + + } + + this.updateMorphTargets(); + + } + +}; + +THREE.Mesh.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.Mesh.prototype.updateMorphTargets = function () { + + if ( this.geometry.morphTargets.length > 0 ) { + + this.morphTargetBase = -1; + this.morphTargetForcedOrder = []; + this.morphTargetInfluences = []; + this.morphTargetDictionary = {}; + + for ( var m = 0, ml = this.geometry.morphTargets.length; m < ml; m ++ ) { + + this.morphTargetInfluences.push( 0 ); + this.morphTargetDictionary[ this.geometry.morphTargets[ m ].name ] = m; + + } + + } + +}; + +THREE.Mesh.prototype.getMorphTargetIndexByName = function ( name ) { + + if ( this.morphTargetDictionary[ name ] !== undefined ) { + + return this.morphTargetDictionary[ name ]; + + } + + console.log( "THREE.Mesh.getMorphTargetIndexByName: morph target " + name + " does not exist. Returning 0." ); + + return 0; + +}; + +THREE.Mesh.prototype.clone = function ( object ) { + + if ( object === undefined ) object = new THREE.Mesh( this.geometry, this.material ); + + THREE.Object3D.prototype.clone.call( this, object ); + + return object; + +}; +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Bone = function( belongsToSkin ) { + + THREE.Object3D.call( this ); + + this.skin = belongsToSkin; + this.skinMatrix = new THREE.Matrix4(); + +}; + +THREE.Bone.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.Bone.prototype.update = function ( parentSkinMatrix, forceUpdate ) { + + // update local + + if ( this.matrixAutoUpdate ) { + + forceUpdate |= this.updateMatrix(); + + } + + // update skin matrix + + if ( forceUpdate || this.matrixWorldNeedsUpdate ) { + + if( parentSkinMatrix ) { + + this.skinMatrix.multiplyMatrices( parentSkinMatrix, this.matrix ); + + } else { + + this.skinMatrix.copy( this.matrix ); + + } + + this.matrixWorldNeedsUpdate = false; + forceUpdate = true; + + } + + // update children + + var child, i, l = this.children.length; + + for ( i = 0; i < l; i ++ ) { + + this.children[ i ].update( this.skinMatrix, forceUpdate ); + + } + +}; + +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.SkinnedMesh = function ( geometry, material, useVertexTexture ) { + + THREE.Mesh.call( this, geometry, material ); + + // + + this.useVertexTexture = useVertexTexture !== undefined ? useVertexTexture : true; + + // init bones + + this.identityMatrix = new THREE.Matrix4(); + + this.bones = []; + this.boneMatrices = []; + + var b, bone, gbone, p, q, s; + + if ( this.geometry && this.geometry.bones !== undefined ) { + + for ( b = 0; b < this.geometry.bones.length; b ++ ) { + + gbone = this.geometry.bones[ b ]; + + p = gbone.pos; + q = gbone.rotq; + s = gbone.scl; + + bone = this.addBone(); + + bone.name = gbone.name; + bone.position.set( p[0], p[1], p[2] ); + bone.quaternion.set( q[0], q[1], q[2], q[3] ); + bone.useQuaternion = true; + + if ( s !== undefined ) { + + bone.scale.set( s[0], s[1], s[2] ); + + } else { + + bone.scale.set( 1, 1, 1 ); + + } + + } + + for ( b = 0; b < this.bones.length; b ++ ) { + + gbone = this.geometry.bones[ b ]; + bone = this.bones[ b ]; + + if ( gbone.parent === -1 ) { + + this.add( bone ); + + } else { + + this.bones[ gbone.parent ].add( bone ); + + } + + } + + // + + var nBones = this.bones.length; + + if ( this.useVertexTexture ) { + + // layout (1 matrix = 4 pixels) + // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4) + // with 8x8 pixel texture max 16 bones (8 * 8 / 4) + // 16x16 pixel texture max 64 bones (16 * 16 / 4) + // 32x32 pixel texture max 256 bones (32 * 32 / 4) + // 64x64 pixel texture max 1024 bones (64 * 64 / 4) + + var size; + + if ( nBones > 256 ) + size = 64; + else if ( nBones > 64 ) + size = 32; + else if ( nBones > 16 ) + size = 16; + else + size = 8; + + this.boneTextureWidth = size; + this.boneTextureHeight = size; + + this.boneMatrices = new Float32Array( this.boneTextureWidth * this.boneTextureHeight * 4 ); // 4 floats per RGBA pixel + this.boneTexture = new THREE.DataTexture( this.boneMatrices, this.boneTextureWidth, this.boneTextureHeight, THREE.RGBAFormat, THREE.FloatType ); + this.boneTexture.minFilter = THREE.NearestFilter; + this.boneTexture.magFilter = THREE.NearestFilter; + this.boneTexture.generateMipmaps = false; + this.boneTexture.flipY = false; + + } else { + + this.boneMatrices = new Float32Array( 16 * nBones ); + + } + + this.pose(); + + } + +}; + +THREE.SkinnedMesh.prototype = Object.create( THREE.Mesh.prototype ); + +THREE.SkinnedMesh.prototype.addBone = function( bone ) { + + if ( bone === undefined ) { + + bone = new THREE.Bone( this ); + + } + + this.bones.push( bone ); + + return bone; + +}; + +THREE.SkinnedMesh.prototype.updateMatrixWorld = function ( force ) { + + this.matrixAutoUpdate && this.updateMatrix(); + + // update matrixWorld + + if ( this.matrixWorldNeedsUpdate || force ) { + + if ( this.parent ) { + + this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); + + } else { + + this.matrixWorld.copy( this.matrix ); + + } + + this.matrixWorldNeedsUpdate = false; + + force = true; + + } + + // update children + + for ( var i = 0, l = this.children.length; i < l; i ++ ) { + + var child = this.children[ i ]; + + if ( child instanceof THREE.Bone ) { + + child.update( this.identityMatrix, false ); + + } else { + + child.updateMatrixWorld( true ); + + } + + } + + // make a snapshot of the bones' rest position + + if ( this.boneInverses == undefined ) { + + this.boneInverses = []; + + for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { + + var inverse = new THREE.Matrix4(); + + inverse.getInverse( this.bones[ b ].skinMatrix ); + + this.boneInverses.push( inverse ); + + } + + } + + // flatten bone matrices to array + + for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { + + // compute the offset between the current and the original transform; + + //TODO: we could get rid of this multiplication step if the skinMatrix + // was already representing the offset; however, this requires some + // major changes to the animation system + + THREE.SkinnedMesh.offsetMatrix.multiplyMatrices( this.bones[ b ].skinMatrix, this.boneInverses[ b ] ); + + THREE.SkinnedMesh.offsetMatrix.flattenToArrayOffset( this.boneMatrices, b * 16 ); + + } + + if ( this.useVertexTexture ) { + + this.boneTexture.needsUpdate = true; + + } + +}; + +THREE.SkinnedMesh.prototype.pose = function () { + + this.updateMatrixWorld( true ); + + for ( var i = 0; i < this.geometry.skinIndices.length; i ++ ) { + + // normalize weights + + var sw = this.geometry.skinWeights[ i ]; + + var scale = 1.0 / sw.lengthManhattan(); + + if ( scale !== Infinity ) { + + sw.multiplyScalar( scale ); + + } else { + + sw.set( 1 ); // this will be normalized by the shader anyway + + } + + } + +}; + +THREE.SkinnedMesh.prototype.clone = function ( object ) { + + if ( object === undefined ) object = new THREE.SkinnedMesh( this.geometry, this.material, this.useVertexTexture ); + + THREE.Mesh.prototype.clone.call( this, object ); + + return object; + +}; + +THREE.SkinnedMesh.offsetMatrix = new THREE.Matrix4(); +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.MorphAnimMesh = function ( geometry, material ) { + + THREE.Mesh.call( this, geometry, material ); + + // API + + this.duration = 1000; // milliseconds + this.mirroredLoop = false; + this.time = 0; + + // internals + + this.lastKeyframe = 0; + this.currentKeyframe = 0; + + this.direction = 1; + this.directionBackwards = false; + + this.setFrameRange( 0, this.geometry.morphTargets.length - 1 ); + +}; + +THREE.MorphAnimMesh.prototype = Object.create( THREE.Mesh.prototype ); + +THREE.MorphAnimMesh.prototype.setFrameRange = function ( start, end ) { + + this.startKeyframe = start; + this.endKeyframe = end; + + this.length = this.endKeyframe - this.startKeyframe + 1; + +}; + +THREE.MorphAnimMesh.prototype.setDirectionForward = function () { + + this.direction = 1; + this.directionBackwards = false; + +}; + +THREE.MorphAnimMesh.prototype.setDirectionBackward = function () { + + this.direction = -1; + this.directionBackwards = true; + +}; + +THREE.MorphAnimMesh.prototype.parseAnimations = function () { + + var geometry = this.geometry; + + if ( ! geometry.animations ) geometry.animations = {}; + + var firstAnimation, animations = geometry.animations; + + var pattern = /([a-z]+)(\d+)/; + + for ( var i = 0, il = geometry.morphTargets.length; i < il; i ++ ) { + + var morph = geometry.morphTargets[ i ]; + var parts = morph.name.match( pattern ); + + if ( parts && parts.length > 1 ) { + + var label = parts[ 1 ]; + var num = parts[ 2 ]; + + if ( ! animations[ label ] ) animations[ label ] = { start: Infinity, end: -Infinity }; + + var animation = animations[ label ]; + + if ( i < animation.start ) animation.start = i; + if ( i > animation.end ) animation.end = i; + + if ( ! firstAnimation ) firstAnimation = label; + + } + + } + + geometry.firstAnimation = firstAnimation; + +}; + +THREE.MorphAnimMesh.prototype.setAnimationLabel = function ( label, start, end ) { + + if ( ! this.geometry.animations ) this.geometry.animations = {}; + + this.geometry.animations[ label ] = { start: start, end: end }; + +}; + +THREE.MorphAnimMesh.prototype.playAnimation = function ( label, fps ) { + + var animation = this.geometry.animations[ label ]; + + if ( animation ) { + + this.setFrameRange( animation.start, animation.end ); + this.duration = 1000 * ( ( animation.end - animation.start ) / fps ); + this.time = 0; + + } else { + + console.warn( "animation[" + label + "] undefined" ); + + } + +}; + +THREE.MorphAnimMesh.prototype.updateAnimation = function ( delta ) { + + var frameTime = this.duration / this.length; + + this.time += this.direction * delta; + + if ( this.mirroredLoop ) { + + if ( this.time > this.duration || this.time < 0 ) { + + this.direction *= -1; + + if ( this.time > this.duration ) { + + this.time = this.duration; + this.directionBackwards = true; + + } + + if ( this.time < 0 ) { + + this.time = 0; + this.directionBackwards = false; + + } + + } + + } else { + + this.time = this.time % this.duration; + + if ( this.time < 0 ) this.time += this.duration; + + } + + var keyframe = this.startKeyframe + THREE.Math.clamp( Math.floor( this.time / frameTime ), 0, this.length - 1 ); + + if ( keyframe !== this.currentKeyframe ) { + + this.morphTargetInfluences[ this.lastKeyframe ] = 0; + this.morphTargetInfluences[ this.currentKeyframe ] = 1; + + this.morphTargetInfluences[ keyframe ] = 0; + + this.lastKeyframe = this.currentKeyframe; + this.currentKeyframe = keyframe; + + } + + var mix = ( this.time % frameTime ) / frameTime; + + if ( this.directionBackwards ) { + + mix = 1 - mix; + + } + + this.morphTargetInfluences[ this.currentKeyframe ] = mix; + this.morphTargetInfluences[ this.lastKeyframe ] = 1 - mix; + +}; + +THREE.MorphAnimMesh.prototype.clone = function ( object ) { + + if ( object === undefined ) object = new THREE.MorphAnimMesh( this.geometry, this.material ); + + object.duration = this.duration; + object.mirroredLoop = this.mirroredLoop; + object.time = this.time; + + object.lastKeyframe = this.lastKeyframe; + object.currentKeyframe = this.currentKeyframe; + + object.direction = this.direction; + object.directionBackwards = this.directionBackwards; + + THREE.Mesh.prototype.clone.call( this, object ); + + return object; + +}; +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Ribbon = function ( geometry, material ) { + + THREE.Object3D.call( this ); + + this.geometry = geometry; + this.material = material; + +}; + +THREE.Ribbon.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.Ribbon.prototype.clone = function ( object ) { + + if ( object === undefined ) object = new THREE.Ribbon( this.geometry, this.material ); + + THREE.Object3D.prototype.clone.call( this, object ); + + return object; + +}; +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.LOD = function () { + + THREE.Object3D.call( this ); + + this.LODs = []; + +}; + + +THREE.LOD.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.LOD.prototype.addLevel = function ( object3D, visibleAtDistance ) { + + if ( visibleAtDistance === undefined ) { + + visibleAtDistance = 0; + + } + + visibleAtDistance = Math.abs( visibleAtDistance ); + + for ( var l = 0; l < this.LODs.length; l ++ ) { + + if ( visibleAtDistance < this.LODs[ l ].visibleAtDistance ) { + + break; + + } + + } + + this.LODs.splice( l, 0, { visibleAtDistance: visibleAtDistance, object3D: object3D } ); + this.add( object3D ); + +}; + +THREE.LOD.prototype.update = function ( camera ) { + + if ( this.LODs.length > 1 ) { + + camera.matrixWorldInverse.getInverse( camera.matrixWorld ); + + var inverse = camera.matrixWorldInverse; + var distance = -( inverse.elements[2] * this.matrixWorld.elements[12] + inverse.elements[6] * this.matrixWorld.elements[13] + inverse.elements[10] * this.matrixWorld.elements[14] + inverse.elements[14] ); + + this.LODs[ 0 ].object3D.visible = true; + + for ( var l = 1; l < this.LODs.length; l ++ ) { + + if( distance >= this.LODs[ l ].visibleAtDistance ) { + + this.LODs[ l - 1 ].object3D.visible = false; + this.LODs[ l ].object3D.visible = true; + + } else { + + break; + + } + + } + + for( ; l < this.LODs.length; l ++ ) { + + this.LODs[ l ].object3D.visible = false; + + } + + } + +}; + +THREE.LOD.prototype.clone = function () { + + // TODO + +}; +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Sprite = function ( material ) { + + THREE.Object3D.call( this ); + + this.material = ( material !== undefined ) ? material : new THREE.SpriteMaterial(); + + this.rotation3d = this.rotation; + this.rotation = 0; + +}; + +THREE.Sprite.prototype = Object.create( THREE.Object3D.prototype ); + +/* + * Custom update matrix + */ + +THREE.Sprite.prototype.updateMatrix = function () { + + this.matrix.setPosition( this.position ); + + this.rotation3d.set( 0, 0, this.rotation ); + this.matrix.setRotationFromEuler( this.rotation3d ); + + if ( this.scale.x !== 1 || this.scale.y !== 1 ) { + + this.matrix.scale( this.scale ); + + } + + this.matrixWorldNeedsUpdate = true; + +}; + +THREE.Sprite.prototype.clone = function ( object ) { + + if ( object === undefined ) object = new THREE.Sprite( this.material ); + + THREE.Object3D.prototype.clone.call( this, object ); + + return object; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.Scene = function () { + + THREE.Object3D.call( this ); + + this.fog = null; + this.overrideMaterial = null; + + this.matrixAutoUpdate = false; + + this.__objects = []; + this.__lights = []; + + this.__objectsAdded = []; + this.__objectsRemoved = []; + +}; + +THREE.Scene.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.Scene.prototype.__addObject = function ( object ) { + + if ( object instanceof THREE.Light ) { + + if ( this.__lights.indexOf( object ) === - 1 ) { + + this.__lights.push( object ); + + } + + if ( object.target && object.target.parent === undefined ) { + + this.add( object.target ); + + } + + } else if ( !( object instanceof THREE.Camera || object instanceof THREE.Bone ) ) { + + if ( this.__objects.indexOf( object ) === - 1 ) { + + this.__objects.push( object ); + this.__objectsAdded.push( object ); + + // check if previously removed + + var i = this.__objectsRemoved.indexOf( object ); + + if ( i !== -1 ) { + + this.__objectsRemoved.splice( i, 1 ); + + } + + } + + } + + for ( var c = 0; c < object.children.length; c ++ ) { + + this.__addObject( object.children[ c ] ); + + } + +}; + +THREE.Scene.prototype.__removeObject = function ( object ) { + + if ( object instanceof THREE.Light ) { + + var i = this.__lights.indexOf( object ); + + if ( i !== -1 ) { + + this.__lights.splice( i, 1 ); + + } + + } else if ( !( object instanceof THREE.Camera ) ) { + + var i = this.__objects.indexOf( object ); + + if( i !== -1 ) { + + this.__objects.splice( i, 1 ); + this.__objectsRemoved.push( object ); + + // check if previously added + + var ai = this.__objectsAdded.indexOf( object ); + + if ( ai !== -1 ) { + + this.__objectsAdded.splice( ai, 1 ); + + } + + } + + } + + for ( var c = 0; c < object.children.length; c ++ ) { + + this.__removeObject( object.children[ c ] ); + + } + +}; +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Fog = function ( hex, near, far ) { + + this.name = ''; + + this.color = new THREE.Color( hex ); + + this.near = ( near !== undefined ) ? near : 1; + this.far = ( far !== undefined ) ? far : 1000; + +}; + +THREE.Fog.prototype.clone = function () { + + return new THREE.Fog( this.color.getHex(), this.near, this.far ); + +}; +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.FogExp2 = function ( hex, density ) { + + this.name = ''; + this.color = new THREE.Color( hex ); + this.density = ( density !== undefined ) ? density : 0.00025; + +}; + +THREE.FogExp2.prototype.clone = function () { + + return new THREE.FogExp2( this.color.getHex(), this.density ); + +}; +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.CanvasRenderer = function ( parameters ) { + + console.log( 'THREE.CanvasRenderer', THREE.REVISION ); + + var smoothstep = THREE.Math.smoothstep; + + parameters = parameters || {}; + + var _this = this, + _renderData, _elements, _lights, + _projector = new THREE.Projector(), + + _canvas = parameters.canvas !== undefined + ? parameters.canvas + : document.createElement( 'canvas' ), + + _canvasWidth, _canvasHeight, _canvasWidthHalf, _canvasHeightHalf, + _context = _canvas.getContext( '2d' ), + + _clearColor = new THREE.Color( 0x000000 ), + _clearOpacity = 0, + + _contextGlobalAlpha = 1, + _contextGlobalCompositeOperation = 0, + _contextStrokeStyle = null, + _contextFillStyle = null, + _contextLineWidth = null, + _contextLineCap = null, + _contextLineJoin = null, + _contextDashSize = null, + _contextGapSize = 0, + + _v1, _v2, _v3, _v4, + _v5 = new THREE.RenderableVertex(), + _v6 = new THREE.RenderableVertex(), + + _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, + _v4x, _v4y, _v5x, _v5y, _v6x, _v6y, + + _color = new THREE.Color(), + _color1 = new THREE.Color(), + _color2 = new THREE.Color(), + _color3 = new THREE.Color(), + _color4 = new THREE.Color(), + + _diffuseColor = new THREE.Color(), + _emissiveColor = new THREE.Color(), + + _lightColor = new THREE.Color(), + + _patterns = {}, _imagedatas = {}, + + _near, _far, + + _image, _uvs, + _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, + + _clipBox = new THREE.Box2(), + _clearBox = new THREE.Box2(), + _elemBox = new THREE.Box2(), + + _enableLighting = false, + _ambientLight = new THREE.Color(), + _directionalLights = new THREE.Color(), + _pointLights = new THREE.Color(), + + _vector3 = new THREE.Vector3(), // Needed for PointLight + + _pixelMap, _pixelMapContext, _pixelMapImage, _pixelMapData, + _gradientMap, _gradientMapContext, _gradientMapQuality = 16; + + _pixelMap = document.createElement( 'canvas' ); + _pixelMap.width = _pixelMap.height = 2; + + _pixelMapContext = _pixelMap.getContext( '2d' ); + _pixelMapContext.fillStyle = 'rgba(0,0,0,1)'; + _pixelMapContext.fillRect( 0, 0, 2, 2 ); + + _pixelMapImage = _pixelMapContext.getImageData( 0, 0, 2, 2 ); + _pixelMapData = _pixelMapImage.data; + + _gradientMap = document.createElement( 'canvas' ); + _gradientMap.width = _gradientMap.height = _gradientMapQuality; + + _gradientMapContext = _gradientMap.getContext( '2d' ); + _gradientMapContext.translate( - _gradientMapQuality / 2, - _gradientMapQuality / 2 ); + _gradientMapContext.scale( _gradientMapQuality, _gradientMapQuality ); + + _gradientMapQuality --; // Fix UVs + + // dash+gap fallbacks for Firefox and everything else + + if ( _context.setLineDash === undefined ) { + + if ( _context.mozDash !== undefined ) { + + _context.setLineDash = function ( values ) { + + _context.mozDash = values[ 0 ] !== null ? values : null; + + } + + } else { + + _context.setLineDash = function () {} + + } + + } + + this.domElement = _canvas; + + this.devicePixelRatio = parameters.devicePixelRatio !== undefined + ? parameters.devicePixelRatio + : window.devicePixelRatio !== undefined + ? window.devicePixelRatio + : 1; + + this.autoClear = true; + this.sortObjects = true; + this.sortElements = true; + + this.info = { + + render: { + + vertices: 0, + faces: 0 + + } + + } + + // WebGLRenderer compatibility + + this.supportsVertexTextures = function () {}; + this.setFaceCulling = function () {}; + + this.setSize = function ( width, height ) { + + _canvasWidth = width * this.devicePixelRatio; + _canvasHeight = height * this.devicePixelRatio; + + _canvasWidthHalf = Math.floor( _canvasWidth / 2 ); + _canvasHeightHalf = Math.floor( _canvasHeight / 2 ); + + _canvas.width = _canvasWidth; + _canvas.height = _canvasHeight; + + _canvas.style.width = width + 'px'; + _canvas.style.height = height + 'px'; + + _clipBox.set( + new THREE.Vector2( - _canvasWidthHalf, - _canvasHeightHalf ), + new THREE.Vector2( _canvasWidthHalf, _canvasHeightHalf ) + ); + + _clearBox.set( + new THREE.Vector2( - _canvasWidthHalf, - _canvasHeightHalf ), + new THREE.Vector2( _canvasWidthHalf, _canvasHeightHalf ) + ); + + _contextGlobalAlpha = 1; + _contextGlobalCompositeOperation = 0; + _contextStrokeStyle = null; + _contextFillStyle = null; + _contextLineWidth = null; + _contextLineCap = null; + _contextLineJoin = null; + + }; + + this.setClearColor = function ( color, opacity ) { + + _clearColor.copy( color ); + _clearOpacity = opacity !== undefined ? opacity : 1; + + _clearBox.set( + new THREE.Vector2( - _canvasWidthHalf, - _canvasHeightHalf ), + new THREE.Vector2( _canvasWidthHalf, _canvasHeightHalf ) + ); + + }; + + this.setClearColorHex = function ( hex, opacity ) { + + _clearColor.setHex( hex ); + _clearOpacity = opacity !== undefined ? opacity : 1; + + _clearBox.set( + new THREE.Vector2( - _canvasWidthHalf, - _canvasHeightHalf ), + new THREE.Vector2( _canvasWidthHalf, _canvasHeightHalf ) + ); + + }; + + this.getMaxAnisotropy = function () { + + return 0; + + }; + + this.clear = function () { + + _context.setTransform( 1, 0, 0, - 1, _canvasWidthHalf, _canvasHeightHalf ); + + if ( _clearBox.empty() === false ) { + + _clearBox.intersect( _clipBox ); + _clearBox.expandByScalar( 2 ); + + if ( _clearOpacity < 1 ) { + + _context.clearRect( + _clearBox.min.x | 0, + _clearBox.min.y | 0, + ( _clearBox.max.x - _clearBox.min.x ) | 0, + ( _clearBox.max.y - _clearBox.min.y ) | 0 + ); + + } + + if ( _clearOpacity > 0 ) { + + setBlending( THREE.NormalBlending ); + setOpacity( 1 ); + + setFillStyle( 'rgba(' + Math.floor( _clearColor.r * 255 ) + ',' + Math.floor( _clearColor.g * 255 ) + ',' + Math.floor( _clearColor.b * 255 ) + ',' + _clearOpacity + ')' ); + + _context.fillRect( + _clearBox.min.x | 0, + _clearBox.min.y | 0, + ( _clearBox.max.x - _clearBox.min.x ) | 0, + ( _clearBox.max.y - _clearBox.min.y ) | 0 + ); + + } + + _clearBox.makeEmpty(); + + } + + + }; + + this.render = function ( scene, camera ) { + + if ( camera instanceof THREE.Camera === false ) { + + console.error( 'THREE.CanvasRenderer.render: camera is not an instance of THREE.Camera.' ); + return; + + } + + if ( this.autoClear === true ) { + + this.clear(); + + } + + _context.setTransform( 1, 0, 0, - 1, _canvasWidthHalf, _canvasHeightHalf ); + + _this.info.render.vertices = 0; + _this.info.render.faces = 0; + + _renderData = _projector.projectScene( scene, camera, this.sortObjects, this.sortElements ); + _elements = _renderData.elements; + _lights = _renderData.lights; + + /* DEBUG + setFillStyle( 'rgba( 0, 255, 255, 0.5 )' ); + _context.fillRect( _clipBox.min.x, _clipBox.min.y, _clipBox.max.x - _clipBox.min.x, _clipBox.max.y - _clipBox.min.y ); + */ + + _enableLighting = _lights.length > 0; + + if ( _enableLighting === true ) { + + calculateLights(); + + } + + for ( var e = 0, el = _elements.length; e < el; e++ ) { + + var element = _elements[ e ]; + + var material = element.material; + + if ( material === undefined || material.visible === false ) continue; + + _elemBox.makeEmpty(); + + if ( element instanceof THREE.RenderableParticle ) { + + _v1 = element; + _v1.x *= _canvasWidthHalf; _v1.y *= _canvasHeightHalf; + + renderParticle( _v1, element, material ); + + } else if ( element instanceof THREE.RenderableLine ) { + + _v1 = element.v1; _v2 = element.v2; + + _v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf; + _v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf; + + _elemBox.setFromPoints( [ _v1.positionScreen, _v2.positionScreen ] ); + + if ( _clipBox.isIntersectionBox( _elemBox ) === true ) { + + renderLine( _v1, _v2, element, material ); + + } + + } else if ( element instanceof THREE.RenderableFace3 ) { + + _v1 = element.v1; _v2 = element.v2; _v3 = element.v3; + + if ( _v1.positionScreen.z < -1 || _v1.positionScreen.z > 1 ) continue; + if ( _v2.positionScreen.z < -1 || _v2.positionScreen.z > 1 ) continue; + if ( _v3.positionScreen.z < -1 || _v3.positionScreen.z > 1 ) continue; + + _v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf; + _v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf; + _v3.positionScreen.x *= _canvasWidthHalf; _v3.positionScreen.y *= _canvasHeightHalf; + + if ( material.overdraw === true ) { + + expand( _v1.positionScreen, _v2.positionScreen ); + expand( _v2.positionScreen, _v3.positionScreen ); + expand( _v3.positionScreen, _v1.positionScreen ); + + } + + _elemBox.setFromPoints( [ _v1.positionScreen, _v2.positionScreen, _v3.positionScreen ] ); + + renderFace3( _v1, _v2, _v3, 0, 1, 2, element, material ); + + } else if ( element instanceof THREE.RenderableFace4 ) { + + _v1 = element.v1; _v2 = element.v2; _v3 = element.v3; _v4 = element.v4; + + if ( _v1.positionScreen.z < -1 || _v1.positionScreen.z > 1 ) continue; + if ( _v2.positionScreen.z < -1 || _v2.positionScreen.z > 1 ) continue; + if ( _v3.positionScreen.z < -1 || _v3.positionScreen.z > 1 ) continue; + if ( _v4.positionScreen.z < -1 || _v4.positionScreen.z > 1 ) continue; + + _v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf; + _v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf; + _v3.positionScreen.x *= _canvasWidthHalf; _v3.positionScreen.y *= _canvasHeightHalf; + _v4.positionScreen.x *= _canvasWidthHalf; _v4.positionScreen.y *= _canvasHeightHalf; + + _v5.positionScreen.copy( _v2.positionScreen ); + _v6.positionScreen.copy( _v4.positionScreen ); + + if ( material.overdraw === true ) { + + expand( _v1.positionScreen, _v2.positionScreen ); + expand( _v2.positionScreen, _v4.positionScreen ); + expand( _v4.positionScreen, _v1.positionScreen ); + + expand( _v3.positionScreen, _v5.positionScreen ); + expand( _v3.positionScreen, _v6.positionScreen ); + + } + + _elemBox.setFromPoints( [ _v1.positionScreen, _v2.positionScreen, _v3.positionScreen, _v4.positionScreen ] ); + + renderFace4( _v1, _v2, _v3, _v4, _v5, _v6, element, material, scene ); + + } + + /* DEBUG + setLineWidth( 1 ); + setStrokeStyle( 'rgba( 0, 255, 0, 0.5 )' ); + _context.strokeRect( _elemBox.min.x, _elemBox.min.y, _elemBox.max.x - _elemBox.min.x, _elemBox.max.y - _elemBox.min.y ); + */ + + _clearBox.union( _elemBox ); + + } + + /* DEBUG + setLineWidth( 1 ); + setStrokeStyle( 'rgba( 255, 0, 0, 0.5 )' ); + _context.strokeRect( _clearBox.min.x, _clearBox.min.y, _clearBox.max.x - _clearBox.min.x, _clearBox.max.y - _clearBox.min.y ); + */ + + _context.setTransform( 1, 0, 0, 1, 0, 0 ); + + // + + function calculateLights() { + + _ambientLight.setRGB( 0, 0, 0 ); + _directionalLights.setRGB( 0, 0, 0 ); + _pointLights.setRGB( 0, 0, 0 ); + + for ( var l = 0, ll = _lights.length; l < ll; l ++ ) { + + var light = _lights[ l ]; + var lightColor = light.color; + + if ( light instanceof THREE.AmbientLight ) { + + _ambientLight.add( lightColor ); + + } else if ( light instanceof THREE.DirectionalLight ) { + + // for particles + + _directionalLights.add( lightColor ); + + } else if ( light instanceof THREE.PointLight ) { + + // for particles + + _pointLights.add( lightColor ); + + } + + } + + } + + function calculateLight( position, normal, color ) { + + for ( var l = 0, ll = _lights.length; l < ll; l ++ ) { + + var light = _lights[ l ]; + + _lightColor.copy( light.color ); + + if ( light instanceof THREE.DirectionalLight ) { + + var lightPosition = _vector3.getPositionFromMatrix( light.matrixWorld ).normalize(); + + var amount = normal.dot( lightPosition ); + + if ( amount <= 0 ) continue; + + amount *= light.intensity; + + color.add( _lightColor.multiplyScalar( amount ) ); + + } else if ( light instanceof THREE.PointLight ) { + + var lightPosition = _vector3.getPositionFromMatrix( light.matrixWorld ); + + var amount = normal.dot( _vector3.subVectors( lightPosition, position ).normalize() ); + + if ( amount <= 0 ) continue; + + amount *= light.distance == 0 ? 1 : 1 - Math.min( position.distanceTo( lightPosition ) / light.distance, 1 ); + + if ( amount == 0 ) continue; + + amount *= light.intensity; + + color.add( _lightColor.multiplyScalar( amount ) ); + + } + + } + + } + + function renderParticle( v1, element, material ) { + + setOpacity( material.opacity ); + setBlending( material.blending ); + + var width, height, scaleX, scaleY, + bitmap, bitmapWidth, bitmapHeight; + + if ( material instanceof THREE.ParticleBasicMaterial ) { + + if ( material.map === null ) { + + scaleX = element.object.scale.x; + scaleY = element.object.scale.y; + + // TODO: Be able to disable this + + scaleX *= element.scale.x * _canvasWidthHalf; + scaleY *= element.scale.y * _canvasHeightHalf; + + _elemBox.min.set( v1.x - scaleX, v1.y - scaleY ); + _elemBox.max.set( v1.x + scaleX, v1.y + scaleY ); + + if ( _clipBox.isIntersectionBox( _elemBox ) === false ) { + + return; + + } + + setFillStyle( material.color.getStyle() ); + + _context.save(); + _context.translate( v1.x, v1.y ); + _context.rotate( - element.rotation ); + _context.scale( scaleX, scaleY ); + _context.fillRect( -1, -1, 2, 2 ); + _context.restore(); + + } else { + + bitmap = material.map.image; + bitmapWidth = bitmap.width >> 1; + bitmapHeight = bitmap.height >> 1; + + scaleX = element.scale.x * _canvasWidthHalf; + scaleY = element.scale.y * _canvasHeightHalf; + + width = scaleX * bitmapWidth; + height = scaleY * bitmapHeight; + + // TODO: Rotations break this... + + _elemBox.min.set( v1.x - width, v1.y - height ); + _elemBox.max.set( v1.x + width, v1.y + height ); + + if ( _clipBox.isIntersectionBox( _elemBox ) === false ) { + + return; + + } + + _context.save(); + _context.translate( v1.x, v1.y ); + _context.rotate( - element.rotation ); + _context.scale( scaleX, - scaleY ); + + _context.translate( - bitmapWidth, - bitmapHeight ); + _context.drawImage( bitmap, 0, 0 ); + _context.restore(); + + } + + /* DEBUG + setStrokeStyle( 'rgb(255,255,0)' ); + _context.beginPath(); + _context.moveTo( v1.x - 10, v1.y ); + _context.lineTo( v1.x + 10, v1.y ); + _context.moveTo( v1.x, v1.y - 10 ); + _context.lineTo( v1.x, v1.y + 10 ); + _context.stroke(); + */ + + } else if ( material instanceof THREE.ParticleCanvasMaterial ) { + + width = element.scale.x * _canvasWidthHalf; + height = element.scale.y * _canvasHeightHalf; + + _elemBox.min.set( v1.x - width, v1.y - height ); + _elemBox.max.set( v1.x + width, v1.y + height ); + + if ( _clipBox.isIntersectionBox( _elemBox ) === false ) { + + return; + + } + + setStrokeStyle( material.color.getStyle() ); + setFillStyle( material.color.getStyle() ); + + _context.save(); + _context.translate( v1.x, v1.y ); + _context.rotate( - element.rotation ); + _context.scale( width, height ); + + material.program( _context ); + + _context.restore(); + + } + + } + + function renderLine( v1, v2, element, material ) { + + setOpacity( material.opacity ); + setBlending( material.blending ); + + _context.beginPath(); + _context.moveTo( v1.positionScreen.x, v1.positionScreen.y ); + _context.lineTo( v2.positionScreen.x, v2.positionScreen.y ); + + if ( material instanceof THREE.LineBasicMaterial ) { + + setLineWidth( material.linewidth ); + setLineCap( material.linecap ); + setLineJoin( material.linejoin ); + setStrokeStyle( material.color.getStyle() ); + setDashAndGap( null, null ); + + _context.stroke(); + _elemBox.expandByScalar( material.linewidth * 2 ); + + } else if ( material instanceof THREE.LineDashedMaterial ) { + + setLineWidth( material.linewidth ); + setLineCap( material.linecap ); + setLineJoin( material.linejoin ); + setStrokeStyle( material.color.getStyle() ); + setDashAndGap( material.dashSize, material.gapSize ); + + _context.stroke(); + _elemBox.expandByScalar( material.linewidth * 2 ); + + } + + } + + function renderFace3( v1, v2, v3, uv1, uv2, uv3, element, material ) { + + _this.info.render.vertices += 3; + _this.info.render.faces ++; + + setOpacity( material.opacity ); + setBlending( material.blending ); + + _v1x = v1.positionScreen.x; _v1y = v1.positionScreen.y; + _v2x = v2.positionScreen.x; _v2y = v2.positionScreen.y; + _v3x = v3.positionScreen.x; _v3y = v3.positionScreen.y; + + drawTriangle( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y ); + + if ( ( material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) && material.map === null ) { + + _diffuseColor.copy( material.color ); + _emissiveColor.copy( material.emissive ); + + if ( material.vertexColors === THREE.FaceColors ) { + + _diffuseColor.multiply( element.color ); + + } + + if ( _enableLighting === true ) { + + if ( material.wireframe === false && material.shading == THREE.SmoothShading && element.vertexNormalsLength == 3 ) { + + _color1.copy( _ambientLight ); + _color2.copy( _ambientLight ); + _color3.copy( _ambientLight ); + + calculateLight( element.v1.positionWorld, element.vertexNormalsModel[ 0 ], _color1 ); + calculateLight( element.v2.positionWorld, element.vertexNormalsModel[ 1 ], _color2 ); + calculateLight( element.v3.positionWorld, element.vertexNormalsModel[ 2 ], _color3 ); + + _color1.multiply( _diffuseColor ).add( _emissiveColor ); + _color2.multiply( _diffuseColor ).add( _emissiveColor ); + _color3.multiply( _diffuseColor ).add( _emissiveColor ); + _color4.addColors( _color2, _color3 ).multiplyScalar( 0.5 ); + + _image = getGradientTexture( _color1, _color2, _color3, _color4 ); + + clipImage( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, 0, 0, 1, 0, 0, 1, _image ); + + } else { + + _color.copy( _ambientLight ); + + calculateLight( element.centroidModel, element.normalModel, _color ); + + _color.multiply( _diffuseColor ).add( _emissiveColor ); + + material.wireframe === true + ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) + : fillPath( _color ); + + } + + } else { + + material.wireframe === true + ? strokePath( material.color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) + : fillPath( material.color ); + + } + + } else if ( material instanceof THREE.MeshBasicMaterial || material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) { + + if ( material.map !== null ) { + + if ( material.map.mapping instanceof THREE.UVMapping ) { + + _uvs = element.uvs[ 0 ]; + patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uvs[ uv1 ].x, _uvs[ uv1 ].y, _uvs[ uv2 ].x, _uvs[ uv2 ].y, _uvs[ uv3 ].x, _uvs[ uv3 ].y, material.map ); + + } + + + } else if ( material.envMap !== null ) { + + if ( material.envMap.mapping instanceof THREE.SphericalReflectionMapping ) { + + _vector3.copy( element.vertexNormalsModelView[ uv1 ] ); + _uv1x = 0.5 * _vector3.x + 0.5; + _uv1y = 0.5 * _vector3.y + 0.5; + + _vector3.copy( element.vertexNormalsModelView[ uv2 ] ); + _uv2x = 0.5 * _vector3.x + 0.5; + _uv2y = 0.5 * _vector3.y + 0.5; + + _vector3.copy( element.vertexNormalsModelView[ uv3 ] ); + _uv3x = 0.5 * _vector3.x + 0.5; + _uv3y = 0.5 * _vector3.y + 0.5; + + patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, material.envMap ); + + }/* else if ( material.envMap.mapping == THREE.SphericalRefractionMapping ) { + + + + }*/ + + + } else { + + _color.copy( material.color ); + + if ( material.vertexColors === THREE.FaceColors ) { + + _color.multiply( element.color ); + + } + + material.wireframe === true + ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) + : fillPath( _color ); + + } + + } else if ( material instanceof THREE.MeshDepthMaterial ) { + + _near = camera.near; + _far = camera.far; + + _color1.r = _color1.g = _color1.b = 1 - smoothstep( v1.positionScreen.z * v1.positionScreen.w, _near, _far ); + _color2.r = _color2.g = _color2.b = 1 - smoothstep( v2.positionScreen.z * v2.positionScreen.w, _near, _far ); + _color3.r = _color3.g = _color3.b = 1 - smoothstep( v3.positionScreen.z * v3.positionScreen.w, _near, _far ); + _color4.addColors( _color2, _color3 ).multiplyScalar( 0.5 ); + + _image = getGradientTexture( _color1, _color2, _color3, _color4 ); + + clipImage( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, 0, 0, 1, 0, 0, 1, _image ); + + } else if ( material instanceof THREE.MeshNormalMaterial ) { + + var normal; + + if ( material.shading == THREE.FlatShading ) { + + normal = element.normalModelView; + + _color.setRGB( normal.x, normal.y, normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 ); + + material.wireframe === true + ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) + : fillPath( _color ); + + } else if ( material.shading == THREE.SmoothShading ) { + + normal = element.vertexNormalsModelView[ uv1 ]; + _color1.setRGB( normal.x, normal.y, normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 ); + + normal = element.vertexNormalsModelView[ uv2 ]; + _color2.setRGB( normal.x, normal.y, normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 ); + + normal = element.vertexNormalsModelView[ uv3 ]; + _color3.setRGB( normal.x, normal.y, normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 ); + + _color4.addColors( _color2, _color3 ).multiplyScalar( 0.5 ); + + _image = getGradientTexture( _color1, _color2, _color3, _color4 ); + + clipImage( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, 0, 0, 1, 0, 0, 1, _image ); + + } + + } + + } + + function renderFace4( v1, v2, v3, v4, v5, v6, element, material ) { + + _this.info.render.vertices += 4; + _this.info.render.faces ++; + + setOpacity( material.opacity ); + setBlending( material.blending ); + + if ( ( material.map !== undefined && material.map !== null ) || ( material.envMap !== undefined && material.envMap !== null ) ) { + + // Let renderFace3() handle this + + renderFace3( v1, v2, v4, 0, 1, 3, element, material ); + renderFace3( v5, v3, v6, 1, 2, 3, element, material ); + + return; + + } + + _v1x = v1.positionScreen.x; _v1y = v1.positionScreen.y; + _v2x = v2.positionScreen.x; _v2y = v2.positionScreen.y; + _v3x = v3.positionScreen.x; _v3y = v3.positionScreen.y; + _v4x = v4.positionScreen.x; _v4y = v4.positionScreen.y; + _v5x = v5.positionScreen.x; _v5y = v5.positionScreen.y; + _v6x = v6.positionScreen.x; _v6y = v6.positionScreen.y; + + if ( material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) { + + _diffuseColor.copy( material.color ); + _emissiveColor.copy( material.emissive ); + + if ( material.vertexColors === THREE.FaceColors ) { + + _diffuseColor.multiply( element.color ); + + } + + if ( _enableLighting === true ) { + + if ( material.wireframe === false && material.shading == THREE.SmoothShading && element.vertexNormalsLength == 4 ) { + + _color1.copy( _ambientLight ); + _color2.copy( _ambientLight ); + _color3.copy( _ambientLight ); + _color4.copy( _ambientLight ); + + calculateLight( element.v1.positionWorld, element.vertexNormalsModel[ 0 ], _color1 ); + calculateLight( element.v2.positionWorld, element.vertexNormalsModel[ 1 ], _color2 ); + calculateLight( element.v4.positionWorld, element.vertexNormalsModel[ 3 ], _color3 ); + calculateLight( element.v3.positionWorld, element.vertexNormalsModel[ 2 ], _color4 ); + + _color1.multiply( _diffuseColor ).add( _emissiveColor ); + _color2.multiply( _diffuseColor ).add( _emissiveColor ); + _color3.multiply( _diffuseColor ).add( _emissiveColor ); + _color4.multiply( _diffuseColor ).add( _emissiveColor ); + + _image = getGradientTexture( _color1, _color2, _color3, _color4 ); + + // TODO: UVs are incorrect, v4->v3? + + drawTriangle( _v1x, _v1y, _v2x, _v2y, _v4x, _v4y ); + clipImage( _v1x, _v1y, _v2x, _v2y, _v4x, _v4y, 0, 0, 1, 0, 0, 1, _image ); + + drawTriangle( _v5x, _v5y, _v3x, _v3y, _v6x, _v6y ); + clipImage( _v5x, _v5y, _v3x, _v3y, _v6x, _v6y, 1, 0, 1, 1, 0, 1, _image ); + + } else { + + _color.copy( _ambientLight ); + + calculateLight( element.centroidModel, element.normalModel, _color ); + + _color.multiply( _diffuseColor ).add( _emissiveColor ); + + drawQuad( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _v4x, _v4y ); + + material.wireframe === true + ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) + : fillPath( _color ); + + } + + } else { + + _color.addColors( _diffuseColor, _emissiveColor ); + + drawQuad( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _v4x, _v4y ); + + material.wireframe === true + ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) + : fillPath( _color ); + + } + + } else if ( material instanceof THREE.MeshBasicMaterial ) { + + _color.copy( material.color ); + + if ( material.vertexColors === THREE.FaceColors ) { + + _color.multiply( element.color ); + + } + + drawQuad( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _v4x, _v4y ); + + material.wireframe === true + ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) + : fillPath( _color ); + + } else if ( material instanceof THREE.MeshNormalMaterial ) { + + var normal; + + if ( material.shading == THREE.FlatShading ) { + + normal = element.normalModelView; + _color.setRGB( normal.x, normal.y, normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 ); + + drawQuad( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _v4x, _v4y ); + + material.wireframe === true + ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) + : fillPath( _color ); + + } else if ( material.shading == THREE.SmoothShading ) { + + normal = element.vertexNormalsModelView[ 0 ]; + _color1.setRGB( normal.x, normal.y, normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 ); + + normal = element.vertexNormalsModelView[ 1 ]; + _color2.setRGB( normal.x, normal.y, normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 ); + + normal = element.vertexNormalsModelView[ 3 ]; + _color3.setRGB( normal.x, normal.y, normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 ); + + normal = element.vertexNormalsModelView[ 2 ]; + _color4.setRGB( normal.x, normal.y, normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 ); + + _image = getGradientTexture( _color1, _color2, _color3, _color4 ); + + drawTriangle( _v1x, _v1y, _v2x, _v2y, _v4x, _v4y ); + clipImage( _v1x, _v1y, _v2x, _v2y, _v4x, _v4y, 0, 0, 1, 0, 0, 1, _image ); + + drawTriangle( _v5x, _v5y, _v3x, _v3y, _v6x, _v6y ); + clipImage( _v5x, _v5y, _v3x, _v3y, _v6x, _v6y, 1, 0, 1, 1, 0, 1, _image ); + + } + + + + } else if ( material instanceof THREE.MeshDepthMaterial ) { + + _near = camera.near; + _far = camera.far; + + _color1.r = _color1.g = _color1.b = 1 - smoothstep( v1.positionScreen.z * v1.positionScreen.w, _near, _far ); + _color2.r = _color2.g = _color2.b = 1 - smoothstep( v2.positionScreen.z * v2.positionScreen.w, _near, _far ); + _color3.r = _color3.g = _color3.b = 1 - smoothstep( v4.positionScreen.z * v4.positionScreen.w, _near, _far ); + _color4.r = _color4.g = _color4.b = 1 - smoothstep( v3.positionScreen.z * v3.positionScreen.w, _near, _far ); + + _image = getGradientTexture( _color1, _color2, _color3, _color4 ); + + // TODO: UVs are incorrect, v4->v3? + + drawTriangle( _v1x, _v1y, _v2x, _v2y, _v4x, _v4y ); + clipImage( _v1x, _v1y, _v2x, _v2y, _v4x, _v4y, 0, 0, 1, 0, 0, 1, _image ); + + drawTriangle( _v5x, _v5y, _v3x, _v3y, _v6x, _v6y ); + clipImage( _v5x, _v5y, _v3x, _v3y, _v6x, _v6y, 1, 0, 1, 1, 0, 1, _image ); + + } + + } + + // + + function drawTriangle( x0, y0, x1, y1, x2, y2 ) { + + _context.beginPath(); + _context.moveTo( x0, y0 ); + _context.lineTo( x1, y1 ); + _context.lineTo( x2, y2 ); + _context.closePath(); + + } + + function drawQuad( x0, y0, x1, y1, x2, y2, x3, y3 ) { + + _context.beginPath(); + _context.moveTo( x0, y0 ); + _context.lineTo( x1, y1 ); + _context.lineTo( x2, y2 ); + _context.lineTo( x3, y3 ); + _context.closePath(); + + } + + function strokePath( color, linewidth, linecap, linejoin ) { + + setLineWidth( linewidth ); + setLineCap( linecap ); + setLineJoin( linejoin ); + setStrokeStyle( color.getStyle() ); + + _context.stroke(); + + _elemBox.expandByScalar( linewidth * 2 ); + + } + + function fillPath( color ) { + + setFillStyle( color.getStyle() ); + _context.fill(); + + } + + function patternPath( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, texture ) { + + if ( texture instanceof THREE.DataTexture || texture.image === undefined || texture.image.width == 0 ) return; + + if ( texture.needsUpdate === true ) { + + var repeatX = texture.wrapS == THREE.RepeatWrapping; + var repeatY = texture.wrapT == THREE.RepeatWrapping; + + _patterns[ texture.id ] = _context.createPattern( + texture.image, repeatX === true && repeatY === true + ? 'repeat' + : repeatX === true && repeatY === false + ? 'repeat-x' + : repeatX === false && repeatY === true + ? 'repeat-y' + : 'no-repeat' + ); + + texture.needsUpdate = false; + + } + + _patterns[ texture.id ] === undefined + ? setFillStyle( 'rgba(0,0,0,1)' ) + : setFillStyle( _patterns[ texture.id ] ); + + // http://extremelysatisfactorytotalitarianism.com/blog/?p=2120 + + var a, b, c, d, e, f, det, idet, + offsetX = texture.offset.x / texture.repeat.x, + offsetY = texture.offset.y / texture.repeat.y, + width = texture.image.width * texture.repeat.x, + height = texture.image.height * texture.repeat.y; + + u0 = ( u0 + offsetX ) * width; + v0 = ( 1.0 - v0 + offsetY ) * height; + + u1 = ( u1 + offsetX ) * width; + v1 = ( 1.0 - v1 + offsetY ) * height; + + u2 = ( u2 + offsetX ) * width; + v2 = ( 1.0 - v2 + offsetY ) * height; + + x1 -= x0; y1 -= y0; + x2 -= x0; y2 -= y0; + + u1 -= u0; v1 -= v0; + u2 -= u0; v2 -= v0; + + det = u1 * v2 - u2 * v1; + + if ( det === 0 ) { + + if ( _imagedatas[ texture.id ] === undefined ) { + + var canvas = document.createElement( 'canvas' ) + canvas.width = texture.image.width; + canvas.height = texture.image.height; + + var context = canvas.getContext( '2d' ); + context.drawImage( texture.image, 0, 0 ); + + _imagedatas[ texture.id ] = context.getImageData( 0, 0, texture.image.width, texture.image.height ).data; + + } + + var data = _imagedatas[ texture.id ]; + var index = ( Math.floor( u0 ) + Math.floor( v0 ) * texture.image.width ) * 4; + + _color.setRGB( data[ index ] / 255, data[ index + 1 ] / 255, data[ index + 2 ] / 255 ); + fillPath( _color ); + + return; + + } + + idet = 1 / det; + + a = ( v2 * x1 - v1 * x2 ) * idet; + b = ( v2 * y1 - v1 * y2 ) * idet; + c = ( u1 * x2 - u2 * x1 ) * idet; + d = ( u1 * y2 - u2 * y1 ) * idet; + + e = x0 - a * u0 - c * v0; + f = y0 - b * u0 - d * v0; + + _context.save(); + _context.transform( a, b, c, d, e, f ); + _context.fill(); + _context.restore(); + + } + + function clipImage( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, image ) { + + // http://extremelysatisfactorytotalitarianism.com/blog/?p=2120 + + var a, b, c, d, e, f, det, idet, + width = image.width - 1, + height = image.height - 1; + + u0 *= width; v0 *= height; + u1 *= width; v1 *= height; + u2 *= width; v2 *= height; + + x1 -= x0; y1 -= y0; + x2 -= x0; y2 -= y0; + + u1 -= u0; v1 -= v0; + u2 -= u0; v2 -= v0; + + det = u1 * v2 - u2 * v1; + + idet = 1 / det; + + a = ( v2 * x1 - v1 * x2 ) * idet; + b = ( v2 * y1 - v1 * y2 ) * idet; + c = ( u1 * x2 - u2 * x1 ) * idet; + d = ( u1 * y2 - u2 * y1 ) * idet; + + e = x0 - a * u0 - c * v0; + f = y0 - b * u0 - d * v0; + + _context.save(); + _context.transform( a, b, c, d, e, f ); + _context.clip(); + _context.drawImage( image, 0, 0 ); + _context.restore(); + + } + + function getGradientTexture( color1, color2, color3, color4 ) { + + // http://mrdoob.com/blog/post/710 + + _pixelMapData[ 0 ] = ( color1.r * 255 ) | 0; + _pixelMapData[ 1 ] = ( color1.g * 255 ) | 0; + _pixelMapData[ 2 ] = ( color1.b * 255 ) | 0; + + _pixelMapData[ 4 ] = ( color2.r * 255 ) | 0; + _pixelMapData[ 5 ] = ( color2.g * 255 ) | 0; + _pixelMapData[ 6 ] = ( color2.b * 255 ) | 0; + + _pixelMapData[ 8 ] = ( color3.r * 255 ) | 0; + _pixelMapData[ 9 ] = ( color3.g * 255 ) | 0; + _pixelMapData[ 10 ] = ( color3.b * 255 ) | 0; + + _pixelMapData[ 12 ] = ( color4.r * 255 ) | 0; + _pixelMapData[ 13 ] = ( color4.g * 255 ) | 0; + _pixelMapData[ 14 ] = ( color4.b * 255 ) | 0; + + _pixelMapContext.putImageData( _pixelMapImage, 0, 0 ); + _gradientMapContext.drawImage( _pixelMap, 0, 0 ); + + return _gradientMap; + + } + + // Hide anti-alias gaps + + function expand( v1, v2 ) { + + var x = v2.x - v1.x, y = v2.y - v1.y, + det = x * x + y * y, idet; + + if ( det === 0 ) return; + + idet = 1 / Math.sqrt( det ); + + x *= idet; y *= idet; + + v2.x += x; v2.y += y; + v1.x -= x; v1.y -= y; + + } + }; + + // Context cached methods. + + function setOpacity( value ) { + + if ( _contextGlobalAlpha !== value ) { + + _context.globalAlpha = value; + _contextGlobalAlpha = value; + + } + + } + + function setBlending( value ) { + + if ( _contextGlobalCompositeOperation !== value ) { + + if ( value === THREE.NormalBlending ) { + + _context.globalCompositeOperation = 'source-over'; + + } else if ( value === THREE.AdditiveBlending ) { + + _context.globalCompositeOperation = 'lighter'; + + } else if ( value === THREE.SubtractiveBlending ) { + + _context.globalCompositeOperation = 'darker'; + + } + + _contextGlobalCompositeOperation = value; + + } + + } + + function setLineWidth( value ) { + + if ( _contextLineWidth !== value ) { + + _context.lineWidth = value; + _contextLineWidth = value; + + } + + } + + function setLineCap( value ) { + + // "butt", "round", "square" + + if ( _contextLineCap !== value ) { + + _context.lineCap = value; + _contextLineCap = value; + + } + + } + + function setLineJoin( value ) { + + // "round", "bevel", "miter" + + if ( _contextLineJoin !== value ) { + + _context.lineJoin = value; + _contextLineJoin = value; + + } + + } + + function setStrokeStyle( value ) { + + if ( _contextStrokeStyle !== value ) { + + _context.strokeStyle = value; + _contextStrokeStyle = value; + + } + + } + + function setFillStyle( value ) { + + if ( _contextFillStyle !== value ) { + + _context.fillStyle = value; + _contextFillStyle = value; + + } + + } + + function setDashAndGap( dashSizeValue, gapSizeValue ) { + + if ( _contextDashSize !== dashSizeValue || _contextGapSize !== gapSizeValue ) { + + _context.setLineDash( [ dashSizeValue, gapSizeValue ] ); + _contextDashSize = dashSizeValue; + _contextGapSize = gapSizeValue; + + } + + } + +}; +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + * @author mikael emtinger / http://gomo.se/ + */ + +THREE.ShaderChunk = { + + // FOG + + fog_pars_fragment: [ + + "#ifdef USE_FOG", + + "uniform vec3 fogColor;", + + "#ifdef FOG_EXP2", + + "uniform float fogDensity;", + + "#else", + + "uniform float fogNear;", + "uniform float fogFar;", + + "#endif", + + "#endif" + + ].join("\n"), + + fog_fragment: [ + + "#ifdef USE_FOG", + + "float depth = gl_FragCoord.z / gl_FragCoord.w;", + + "#ifdef FOG_EXP2", + + "const float LOG2 = 1.442695;", + "float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );", + "fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );", + + "#else", + + "float fogFactor = smoothstep( fogNear, fogFar, depth );", + + "#endif", + + "gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );", + + "#endif" + + ].join("\n"), + + // ENVIRONMENT MAP + + envmap_pars_fragment: [ + + "#ifdef USE_ENVMAP", + + "uniform float reflectivity;", + "uniform samplerCube envMap;", + "uniform float flipEnvMap;", + "uniform int combine;", + + "#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )", + + "uniform bool useRefract;", + "uniform float refractionRatio;", + + "#else", + + "varying vec3 vReflect;", + + "#endif", + + "#endif" + + ].join("\n"), + + envmap_fragment: [ + + "#ifdef USE_ENVMAP", + + "vec3 reflectVec;", + + "#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )", + + "vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );", + + "if ( useRefract ) {", + + "reflectVec = refract( cameraToVertex, normal, refractionRatio );", + + "} else { ", + + "reflectVec = reflect( cameraToVertex, normal );", + + "}", + + "#else", + + "reflectVec = vReflect;", + + "#endif", + + "#ifdef DOUBLE_SIDED", + + "float flipNormal = ( -1.0 + 2.0 * float( gl_FrontFacing ) );", + "vec4 cubeColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );", + + "#else", + + "vec4 cubeColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );", + + "#endif", + + "#ifdef GAMMA_INPUT", + + "cubeColor.xyz *= cubeColor.xyz;", + + "#endif", + + "if ( combine == 1 ) {", + + "gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularStrength * reflectivity );", + + "} else if ( combine == 2 ) {", + + "gl_FragColor.xyz += cubeColor.xyz * specularStrength * reflectivity;", + + "} else {", + + "gl_FragColor.xyz = mix( gl_FragColor.xyz, gl_FragColor.xyz * cubeColor.xyz, specularStrength * reflectivity );", + + "}", + + "#endif" + + ].join("\n"), + + envmap_pars_vertex: [ + + "#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP )", + + "varying vec3 vReflect;", + + "uniform float refractionRatio;", + "uniform bool useRefract;", + + "#endif" + + ].join("\n"), + + worldpos_vertex : [ + + "#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )", + + "#ifdef USE_SKINNING", + + "vec4 worldPosition = modelMatrix * skinned;", + + "#endif", + + "#if defined( USE_MORPHTARGETS ) && ! defined( USE_SKINNING )", + + "vec4 worldPosition = modelMatrix * vec4( morphed, 1.0 );", + + "#endif", + + "#if ! defined( USE_MORPHTARGETS ) && ! defined( USE_SKINNING )", + + "vec4 worldPosition = modelMatrix * vec4( position, 1.0 );", + + "#endif", + + "#endif" + + ].join("\n"), + + envmap_vertex : [ + + "#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP )", + + "vec3 worldNormal = mat3( modelMatrix[ 0 ].xyz, modelMatrix[ 1 ].xyz, modelMatrix[ 2 ].xyz ) * objectNormal;", + "worldNormal = normalize( worldNormal );", + + "vec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );", + + "if ( useRefract ) {", + + "vReflect = refract( cameraToVertex, worldNormal, refractionRatio );", + + "} else {", + + "vReflect = reflect( cameraToVertex, worldNormal );", + + "}", + + "#endif" + + ].join("\n"), + + // COLOR MAP (particles) + + map_particle_pars_fragment: [ + + "#ifdef USE_MAP", + + "uniform sampler2D map;", + + "#endif" + + ].join("\n"), + + + map_particle_fragment: [ + + "#ifdef USE_MAP", + + "gl_FragColor = gl_FragColor * texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) );", + + "#endif" + + ].join("\n"), + + // COLOR MAP (triangles) + + map_pars_vertex: [ + + "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )", + + "varying vec2 vUv;", + "uniform vec4 offsetRepeat;", + + "#endif" + + ].join("\n"), + + map_pars_fragment: [ + + "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )", + + "varying vec2 vUv;", + + "#endif", + + "#ifdef USE_MAP", + + "uniform sampler2D map;", + + "#endif" + + ].join("\n"), + + map_vertex: [ + + "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )", + + "vUv = uv * offsetRepeat.zw + offsetRepeat.xy;", + + "#endif" + + ].join("\n"), + + map_fragment: [ + + "#ifdef USE_MAP", + + "vec4 texelColor = texture2D( map, vUv );", + + "#ifdef GAMMA_INPUT", + + "texelColor.xyz *= texelColor.xyz;", + + "#endif", + + "gl_FragColor = gl_FragColor * texelColor;", + + "#endif" + + ].join("\n"), + + // LIGHT MAP + + lightmap_pars_fragment: [ + + "#ifdef USE_LIGHTMAP", + + "varying vec2 vUv2;", + "uniform sampler2D lightMap;", + + "#endif" + + ].join("\n"), + + lightmap_pars_vertex: [ + + "#ifdef USE_LIGHTMAP", + + "varying vec2 vUv2;", + + "#endif" + + ].join("\n"), + + lightmap_fragment: [ + + "#ifdef USE_LIGHTMAP", + + "gl_FragColor = gl_FragColor * texture2D( lightMap, vUv2 );", + + "#endif" + + ].join("\n"), + + lightmap_vertex: [ + + "#ifdef USE_LIGHTMAP", + + "vUv2 = uv2;", + + "#endif" + + ].join("\n"), + + // BUMP MAP + + bumpmap_pars_fragment: [ + + "#ifdef USE_BUMPMAP", + + "uniform sampler2D bumpMap;", + "uniform float bumpScale;", + + // Derivative maps - bump mapping unparametrized surfaces by Morten Mikkelsen + // http://mmikkelsen3d.blogspot.sk/2011/07/derivative-maps.html + + // Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2) + + "vec2 dHdxy_fwd() {", + + "vec2 dSTdx = dFdx( vUv );", + "vec2 dSTdy = dFdy( vUv );", + + "float Hll = bumpScale * texture2D( bumpMap, vUv ).x;", + "float dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;", + "float dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;", + + "return vec2( dBx, dBy );", + + "}", + + "vec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {", + + "vec3 vSigmaX = dFdx( surf_pos );", + "vec3 vSigmaY = dFdy( surf_pos );", + "vec3 vN = surf_norm;", // normalized + + "vec3 R1 = cross( vSigmaY, vN );", + "vec3 R2 = cross( vN, vSigmaX );", + + "float fDet = dot( vSigmaX, R1 );", + + "vec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );", + "return normalize( abs( fDet ) * surf_norm - vGrad );", + + "}", + + "#endif" + + ].join("\n"), + + // NORMAL MAP + + normalmap_pars_fragment: [ + + "#ifdef USE_NORMALMAP", + + "uniform sampler2D normalMap;", + "uniform vec2 normalScale;", + + // Per-Pixel Tangent Space Normal Mapping + // http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html + + "vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {", + + "vec3 q0 = dFdx( eye_pos.xyz );", + "vec3 q1 = dFdy( eye_pos.xyz );", + "vec2 st0 = dFdx( vUv.st );", + "vec2 st1 = dFdy( vUv.st );", + + "vec3 S = normalize( q0 * st1.t - q1 * st0.t );", + "vec3 T = normalize( -q0 * st1.s + q1 * st0.s );", + "vec3 N = normalize( surf_norm );", + + "vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;", + "mapN.xy = normalScale * mapN.xy;", + "mat3 tsn = mat3( S, T, N );", + "return normalize( tsn * mapN );", + + "}", + + "#endif" + + ].join("\n"), + + // SPECULAR MAP + + specularmap_pars_fragment: [ + + "#ifdef USE_SPECULARMAP", + + "uniform sampler2D specularMap;", + + "#endif" + + ].join("\n"), + + specularmap_fragment: [ + + "float specularStrength;", + + "#ifdef USE_SPECULARMAP", + + "vec4 texelSpecular = texture2D( specularMap, vUv );", + "specularStrength = texelSpecular.r;", + + "#else", + + "specularStrength = 1.0;", + + "#endif" + + ].join("\n"), + + // LIGHTS LAMBERT + + lights_lambert_pars_vertex: [ + + "uniform vec3 ambient;", + "uniform vec3 diffuse;", + "uniform vec3 emissive;", + + "uniform vec3 ambientLightColor;", + + "#if MAX_DIR_LIGHTS > 0", + + "uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];", + "uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];", + + "#endif", + + "#if MAX_HEMI_LIGHTS > 0", + + "uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];", + "uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];", + "uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];", + + "#endif", + + "#if MAX_POINT_LIGHTS > 0", + + "uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];", + "uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];", + "uniform float pointLightDistance[ MAX_POINT_LIGHTS ];", + + "#endif", + + "#if MAX_SPOT_LIGHTS > 0", + + "uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];", + "uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];", + "uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];", + "uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];", + "uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];", + "uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];", + + "#endif", + + "#ifdef WRAP_AROUND", + + "uniform vec3 wrapRGB;", + + "#endif" + + ].join("\n"), + + lights_lambert_vertex: [ + + "vLightFront = vec3( 0.0 );", + + "#ifdef DOUBLE_SIDED", + + "vLightBack = vec3( 0.0 );", + + "#endif", + + "transformedNormal = normalize( transformedNormal );", + + "#if MAX_DIR_LIGHTS > 0", + + "for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {", + + "vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );", + "vec3 dirVector = normalize( lDirection.xyz );", + + "float dotProduct = dot( transformedNormal, dirVector );", + "vec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );", + + "#ifdef DOUBLE_SIDED", + + "vec3 directionalLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );", + + "#ifdef WRAP_AROUND", + + "vec3 directionalLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );", + + "#endif", + + "#endif", + + "#ifdef WRAP_AROUND", + + "vec3 directionalLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );", + "directionalLightWeighting = mix( directionalLightWeighting, directionalLightWeightingHalf, wrapRGB );", + + "#ifdef DOUBLE_SIDED", + + "directionalLightWeightingBack = mix( directionalLightWeightingBack, directionalLightWeightingHalfBack, wrapRGB );", + + "#endif", + + "#endif", + + "vLightFront += directionalLightColor[ i ] * directionalLightWeighting;", + + "#ifdef DOUBLE_SIDED", + + "vLightBack += directionalLightColor[ i ] * directionalLightWeightingBack;", + + "#endif", + + "}", + + "#endif", + + "#if MAX_POINT_LIGHTS > 0", + + "for( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {", + + "vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );", + "vec3 lVector = lPosition.xyz - mvPosition.xyz;", + + "float lDistance = 1.0;", + "if ( pointLightDistance[ i ] > 0.0 )", + "lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );", + + "lVector = normalize( lVector );", + "float dotProduct = dot( transformedNormal, lVector );", + + "vec3 pointLightWeighting = vec3( max( dotProduct, 0.0 ) );", + + "#ifdef DOUBLE_SIDED", + + "vec3 pointLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );", + + "#ifdef WRAP_AROUND", + + "vec3 pointLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );", + + "#endif", + + "#endif", + + "#ifdef WRAP_AROUND", + + "vec3 pointLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );", + "pointLightWeighting = mix( pointLightWeighting, pointLightWeightingHalf, wrapRGB );", + + "#ifdef DOUBLE_SIDED", + + "pointLightWeightingBack = mix( pointLightWeightingBack, pointLightWeightingHalfBack, wrapRGB );", + + "#endif", + + "#endif", + + "vLightFront += pointLightColor[ i ] * pointLightWeighting * lDistance;", + + "#ifdef DOUBLE_SIDED", + + "vLightBack += pointLightColor[ i ] * pointLightWeightingBack * lDistance;", + + "#endif", + + "}", + + "#endif", + + "#if MAX_SPOT_LIGHTS > 0", + + "for( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {", + + "vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );", + "vec3 lVector = lPosition.xyz - mvPosition.xyz;", + + "float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - worldPosition.xyz ) );", + + "if ( spotEffect > spotLightAngleCos[ i ] ) {", + + "spotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );", + + "float lDistance = 1.0;", + "if ( spotLightDistance[ i ] > 0.0 )", + "lDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );", + + "lVector = normalize( lVector );", + + "float dotProduct = dot( transformedNormal, lVector );", + "vec3 spotLightWeighting = vec3( max( dotProduct, 0.0 ) );", + + "#ifdef DOUBLE_SIDED", + + "vec3 spotLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );", + + "#ifdef WRAP_AROUND", + + "vec3 spotLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );", + + "#endif", + + "#endif", + + "#ifdef WRAP_AROUND", + + "vec3 spotLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );", + "spotLightWeighting = mix( spotLightWeighting, spotLightWeightingHalf, wrapRGB );", + + "#ifdef DOUBLE_SIDED", + + "spotLightWeightingBack = mix( spotLightWeightingBack, spotLightWeightingHalfBack, wrapRGB );", + + "#endif", + + "#endif", + + "vLightFront += spotLightColor[ i ] * spotLightWeighting * lDistance * spotEffect;", + + "#ifdef DOUBLE_SIDED", + + "vLightBack += spotLightColor[ i ] * spotLightWeightingBack * lDistance * spotEffect;", + + "#endif", + + "}", + + "}", + + "#endif", + + "#if MAX_HEMI_LIGHTS > 0", + + "for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {", + + "vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );", + "vec3 lVector = normalize( lDirection.xyz );", + + "float dotProduct = dot( transformedNormal, lVector );", + + "float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;", + "float hemiDiffuseWeightBack = -0.5 * dotProduct + 0.5;", + + "vLightFront += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );", + + "#ifdef DOUBLE_SIDED", + + "vLightBack += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeightBack );", + + "#endif", + + "}", + + "#endif", + + "vLightFront = vLightFront * diffuse + ambient * ambientLightColor + emissive;", + + "#ifdef DOUBLE_SIDED", + + "vLightBack = vLightBack * diffuse + ambient * ambientLightColor + emissive;", + + "#endif" + + ].join("\n"), + + // LIGHTS PHONG + + lights_phong_pars_vertex: [ + + "#ifndef PHONG_PER_PIXEL", + + "#if MAX_POINT_LIGHTS > 0", + + "uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];", + "uniform float pointLightDistance[ MAX_POINT_LIGHTS ];", + + "varying vec4 vPointLight[ MAX_POINT_LIGHTS ];", + + "#endif", + + "#if MAX_SPOT_LIGHTS > 0", + + "uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];", + "uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];", + + "varying vec4 vSpotLight[ MAX_SPOT_LIGHTS ];", + + "#endif", + + "#endif", + + "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )", + + "varying vec3 vWorldPosition;", + + "#endif" + + ].join("\n"), + + + lights_phong_vertex: [ + + "#ifndef PHONG_PER_PIXEL", + + "#if MAX_POINT_LIGHTS > 0", + + "for( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {", + + "vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );", + "vec3 lVector = lPosition.xyz - mvPosition.xyz;", + + "float lDistance = 1.0;", + "if ( pointLightDistance[ i ] > 0.0 )", + "lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );", + + "vPointLight[ i ] = vec4( lVector, lDistance );", + + "}", + + "#endif", + + "#if MAX_SPOT_LIGHTS > 0", + + "for( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {", + + "vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );", + "vec3 lVector = lPosition.xyz - mvPosition.xyz;", + + "float lDistance = 1.0;", + "if ( spotLightDistance[ i ] > 0.0 )", + "lDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );", + + "vSpotLight[ i ] = vec4( lVector, lDistance );", + + "}", + + "#endif", + + "#endif", + + "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )", + + "vWorldPosition = worldPosition.xyz;", + + "#endif" + + ].join("\n"), + + lights_phong_pars_fragment: [ + + "uniform vec3 ambientLightColor;", + + "#if MAX_DIR_LIGHTS > 0", + + "uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];", + "uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];", + + "#endif", + + "#if MAX_HEMI_LIGHTS > 0", + + "uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];", + "uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];", + "uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];", + + "#endif", + + "#if MAX_POINT_LIGHTS > 0", + + "uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];", + + "#ifdef PHONG_PER_PIXEL", + + "uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];", + "uniform float pointLightDistance[ MAX_POINT_LIGHTS ];", + + "#else", + + "varying vec4 vPointLight[ MAX_POINT_LIGHTS ];", + + "#endif", + + "#endif", + + "#if MAX_SPOT_LIGHTS > 0", + + "uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];", + "uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];", + "uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];", + "uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];", + "uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];", + + "#ifdef PHONG_PER_PIXEL", + + "uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];", + + "#else", + + "varying vec4 vSpotLight[ MAX_SPOT_LIGHTS ];", + + "#endif", + + "#endif", + + "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )", + + "varying vec3 vWorldPosition;", + + "#endif", + + "#ifdef WRAP_AROUND", + + "uniform vec3 wrapRGB;", + + "#endif", + + "varying vec3 vViewPosition;", + "varying vec3 vNormal;" + + ].join("\n"), + + lights_phong_fragment: [ + + "vec3 normal = normalize( vNormal );", + "vec3 viewPosition = normalize( vViewPosition );", + + "#ifdef DOUBLE_SIDED", + + "normal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );", + + "#endif", + + "#ifdef USE_NORMALMAP", + + "normal = perturbNormal2Arb( -viewPosition, normal );", + + "#elif defined( USE_BUMPMAP )", + + "normal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );", + + "#endif", + + "#if MAX_POINT_LIGHTS > 0", + + "vec3 pointDiffuse = vec3( 0.0 );", + "vec3 pointSpecular = vec3( 0.0 );", + + "for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {", + + "#ifdef PHONG_PER_PIXEL", + + "vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );", + "vec3 lVector = lPosition.xyz + vViewPosition.xyz;", + + "float lDistance = 1.0;", + "if ( pointLightDistance[ i ] > 0.0 )", + "lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );", + + "lVector = normalize( lVector );", + + "#else", + + "vec3 lVector = normalize( vPointLight[ i ].xyz );", + "float lDistance = vPointLight[ i ].w;", + + "#endif", + + // diffuse + + "float dotProduct = dot( normal, lVector );", + + "#ifdef WRAP_AROUND", + + "float pointDiffuseWeightFull = max( dotProduct, 0.0 );", + "float pointDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );", + + "vec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );", + + "#else", + + "float pointDiffuseWeight = max( dotProduct, 0.0 );", + + "#endif", + + "pointDiffuse += diffuse * pointLightColor[ i ] * pointDiffuseWeight * lDistance;", + + // specular + + "vec3 pointHalfVector = normalize( lVector + viewPosition );", + "float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );", + "float pointSpecularWeight = specularStrength * max( pow( pointDotNormalHalf, shininess ), 0.0 );", + + "#ifdef PHYSICALLY_BASED_SHADING", + + // 2.0 => 2.0001 is hack to work around ANGLE bug + + "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", + + "vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, pointHalfVector ), 5.0 );", + "pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance * specularNormalization;", + + "#else", + + "pointSpecular += specular * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance;", + + "#endif", + + "}", + + "#endif", + + "#if MAX_SPOT_LIGHTS > 0", + + "vec3 spotDiffuse = vec3( 0.0 );", + "vec3 spotSpecular = vec3( 0.0 );", + + "for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {", + + "#ifdef PHONG_PER_PIXEL", + + "vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );", + "vec3 lVector = lPosition.xyz + vViewPosition.xyz;", + + "float lDistance = 1.0;", + "if ( spotLightDistance[ i ] > 0.0 )", + "lDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );", + + "lVector = normalize( lVector );", + + "#else", + + "vec3 lVector = normalize( vSpotLight[ i ].xyz );", + "float lDistance = vSpotLight[ i ].w;", + + "#endif", + + "float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );", + + "if ( spotEffect > spotLightAngleCos[ i ] ) {", + + "spotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );", + + // diffuse + + "float dotProduct = dot( normal, lVector );", + + "#ifdef WRAP_AROUND", + + "float spotDiffuseWeightFull = max( dotProduct, 0.0 );", + "float spotDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );", + + "vec3 spotDiffuseWeight = mix( vec3 ( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );", + + "#else", + + "float spotDiffuseWeight = max( dotProduct, 0.0 );", + + "#endif", + + "spotDiffuse += diffuse * spotLightColor[ i ] * spotDiffuseWeight * lDistance * spotEffect;", + + // specular + + "vec3 spotHalfVector = normalize( lVector + viewPosition );", + "float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );", + "float spotSpecularWeight = specularStrength * max( pow( spotDotNormalHalf, shininess ), 0.0 );", + + "#ifdef PHYSICALLY_BASED_SHADING", + + // 2.0 => 2.0001 is hack to work around ANGLE bug + + "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", + + "vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, spotHalfVector ), 5.0 );", + "spotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * lDistance * specularNormalization * spotEffect;", + + "#else", + + "spotSpecular += specular * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * lDistance * spotEffect;", + + "#endif", + + "}", + + "}", + + "#endif", + + "#if MAX_DIR_LIGHTS > 0", + + "vec3 dirDiffuse = vec3( 0.0 );", + "vec3 dirSpecular = vec3( 0.0 );" , + + "for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {", + + "vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );", + "vec3 dirVector = normalize( lDirection.xyz );", + + // diffuse + + "float dotProduct = dot( normal, dirVector );", + + "#ifdef WRAP_AROUND", + + "float dirDiffuseWeightFull = max( dotProduct, 0.0 );", + "float dirDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );", + + "vec3 dirDiffuseWeight = mix( vec3( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), wrapRGB );", + + "#else", + + "float dirDiffuseWeight = max( dotProduct, 0.0 );", + + "#endif", + + "dirDiffuse += diffuse * directionalLightColor[ i ] * dirDiffuseWeight;", + + // specular + + "vec3 dirHalfVector = normalize( dirVector + viewPosition );", + "float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );", + "float dirSpecularWeight = specularStrength * max( pow( dirDotNormalHalf, shininess ), 0.0 );", + + "#ifdef PHYSICALLY_BASED_SHADING", + + /* + // fresnel term from skin shader + "const float F0 = 0.128;", + + "float base = 1.0 - dot( viewPosition, dirHalfVector );", + "float exponential = pow( base, 5.0 );", + + "float fresnel = exponential + F0 * ( 1.0 - exponential );", + */ + + /* + // fresnel term from fresnel shader + "const float mFresnelBias = 0.08;", + "const float mFresnelScale = 0.3;", + "const float mFresnelPower = 5.0;", + + "float fresnel = mFresnelBias + mFresnelScale * pow( 1.0 + dot( normalize( -viewPosition ), normal ), mFresnelPower );", + */ + + // 2.0 => 2.0001 is hack to work around ANGLE bug + + "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", + + //"dirSpecular += specular * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization * fresnel;", + + "vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( dirVector, dirHalfVector ), 5.0 );", + "dirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;", + + "#else", + + "dirSpecular += specular * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight;", + + "#endif", + + "}", + + "#endif", + + "#if MAX_HEMI_LIGHTS > 0", + + "vec3 hemiDiffuse = vec3( 0.0 );", + "vec3 hemiSpecular = vec3( 0.0 );" , + + "for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {", + + "vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );", + "vec3 lVector = normalize( lDirection.xyz );", + + // diffuse + + "float dotProduct = dot( normal, lVector );", + "float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;", + + "vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );", + + "hemiDiffuse += diffuse * hemiColor;", + + // specular (sky light) + + "vec3 hemiHalfVectorSky = normalize( lVector + viewPosition );", + "float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;", + "float hemiSpecularWeightSky = specularStrength * max( pow( hemiDotNormalHalfSky, shininess ), 0.0 );", + + // specular (ground light) + + "vec3 lVectorGround = -lVector;", + + "vec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );", + "float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;", + "float hemiSpecularWeightGround = specularStrength * max( pow( hemiDotNormalHalfGround, shininess ), 0.0 );", + + "#ifdef PHYSICALLY_BASED_SHADING", + + "float dotProductGround = dot( normal, lVectorGround );", + + // 2.0 => 2.0001 is hack to work around ANGLE bug + + "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", + + "vec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, hemiHalfVectorSky ), 5.0 );", + "vec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 5.0 );", + "hemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );", + + "#else", + + "hemiSpecular += specular * hemiColor * ( hemiSpecularWeightSky + hemiSpecularWeightGround ) * hemiDiffuseWeight;", + + "#endif", + + "}", + + "#endif", + + "vec3 totalDiffuse = vec3( 0.0 );", + "vec3 totalSpecular = vec3( 0.0 );", + + "#if MAX_DIR_LIGHTS > 0", + + "totalDiffuse += dirDiffuse;", + "totalSpecular += dirSpecular;", + + "#endif", + + "#if MAX_HEMI_LIGHTS > 0", + + "totalDiffuse += hemiDiffuse;", + "totalSpecular += hemiSpecular;", + + "#endif", + + "#if MAX_POINT_LIGHTS > 0", + + "totalDiffuse += pointDiffuse;", + "totalSpecular += pointSpecular;", + + "#endif", + + "#if MAX_SPOT_LIGHTS > 0", + + "totalDiffuse += spotDiffuse;", + "totalSpecular += spotSpecular;", + + "#endif", + + "#ifdef METAL", + + "gl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient + totalSpecular );", + + "#else", + + "gl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient ) + totalSpecular;", + + "#endif" + + ].join("\n"), + + // VERTEX COLORS + + color_pars_fragment: [ + + "#ifdef USE_COLOR", + + "varying vec3 vColor;", + + "#endif" + + ].join("\n"), + + + color_fragment: [ + + "#ifdef USE_COLOR", + + "gl_FragColor = gl_FragColor * vec4( vColor, opacity );", + + "#endif" + + ].join("\n"), + + color_pars_vertex: [ + + "#ifdef USE_COLOR", + + "varying vec3 vColor;", + + "#endif" + + ].join("\n"), + + + color_vertex: [ + + "#ifdef USE_COLOR", + + "#ifdef GAMMA_INPUT", + + "vColor = color * color;", + + "#else", + + "vColor = color;", + + "#endif", + + "#endif" + + ].join("\n"), + + // SKINNING + + skinning_pars_vertex: [ + + "#ifdef USE_SKINNING", + + "#ifdef BONE_TEXTURE", + + "uniform sampler2D boneTexture;", + + "mat4 getBoneMatrix( const in float i ) {", + + "float j = i * 4.0;", + "float x = mod( j, N_BONE_PIXEL_X );", + "float y = floor( j / N_BONE_PIXEL_X );", + + "const float dx = 1.0 / N_BONE_PIXEL_X;", + "const float dy = 1.0 / N_BONE_PIXEL_Y;", + + "y = dy * ( y + 0.5 );", + + "vec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );", + "vec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );", + "vec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );", + "vec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );", + + "mat4 bone = mat4( v1, v2, v3, v4 );", + + "return bone;", + + "}", + + "#else", + + "uniform mat4 boneGlobalMatrices[ MAX_BONES ];", + + "mat4 getBoneMatrix( const in float i ) {", + + "mat4 bone = boneGlobalMatrices[ int(i) ];", + "return bone;", + + "}", + + "#endif", + + "#endif" + + ].join("\n"), + + skinbase_vertex: [ + + "#ifdef USE_SKINNING", + + "mat4 boneMatX = getBoneMatrix( skinIndex.x );", + "mat4 boneMatY = getBoneMatrix( skinIndex.y );", + + "#endif" + + ].join("\n"), + + skinning_vertex: [ + + "#ifdef USE_SKINNING", + + "#ifdef USE_MORPHTARGETS", + + "vec4 skinVertex = vec4( morphed, 1.0 );", + + "#else", + + "vec4 skinVertex = vec4( position, 1.0 );", + + "#endif", + + "vec4 skinned = boneMatX * skinVertex * skinWeight.x;", + "skinned += boneMatY * skinVertex * skinWeight.y;", + + "#endif" + + ].join("\n"), + + // MORPHING + + morphtarget_pars_vertex: [ + + "#ifdef USE_MORPHTARGETS", + + "#ifndef USE_MORPHNORMALS", + + "uniform float morphTargetInfluences[ 8 ];", + + "#else", + + "uniform float morphTargetInfluences[ 4 ];", + + "#endif", + + "#endif" + + ].join("\n"), + + morphtarget_vertex: [ + + "#ifdef USE_MORPHTARGETS", + + "vec3 morphed = vec3( 0.0 );", + "morphed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];", + "morphed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];", + "morphed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];", + "morphed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];", + + "#ifndef USE_MORPHNORMALS", + + "morphed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];", + "morphed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];", + "morphed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];", + "morphed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];", + + "#endif", + + "morphed += position;", + + "#endif" + + ].join("\n"), + + default_vertex : [ + + "vec4 mvPosition;", + + "#ifdef USE_SKINNING", + + "mvPosition = modelViewMatrix * skinned;", + + "#endif", + + "#if !defined( USE_SKINNING ) && defined( USE_MORPHTARGETS )", + + "mvPosition = modelViewMatrix * vec4( morphed, 1.0 );", + + "#endif", + + "#if !defined( USE_SKINNING ) && ! defined( USE_MORPHTARGETS )", + + "mvPosition = modelViewMatrix * vec4( position, 1.0 );", + + "#endif", + + "gl_Position = projectionMatrix * mvPosition;" + + ].join("\n"), + + morphnormal_vertex: [ + + "#ifdef USE_MORPHNORMALS", + + "vec3 morphedNormal = vec3( 0.0 );", + + "morphedNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];", + "morphedNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];", + "morphedNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];", + "morphedNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];", + + "morphedNormal += normal;", + + "#endif" + + ].join("\n"), + + skinnormal_vertex: [ + + "#ifdef USE_SKINNING", + + "mat4 skinMatrix = skinWeight.x * boneMatX;", + "skinMatrix += skinWeight.y * boneMatY;", + + "#ifdef USE_MORPHNORMALS", + + "vec4 skinnedNormal = skinMatrix * vec4( morphedNormal, 0.0 );", + + "#else", + + "vec4 skinnedNormal = skinMatrix * vec4( normal, 0.0 );", + + "#endif", + + "#endif" + + ].join("\n"), + + defaultnormal_vertex: [ + + "vec3 objectNormal;", + + "#ifdef USE_SKINNING", + + "objectNormal = skinnedNormal.xyz;", + + "#endif", + + "#if !defined( USE_SKINNING ) && defined( USE_MORPHNORMALS )", + + "objectNormal = morphedNormal;", + + "#endif", + + "#if !defined( USE_SKINNING ) && ! defined( USE_MORPHNORMALS )", + + "objectNormal = normal;", + + "#endif", + + "#ifdef FLIP_SIDED", + + "objectNormal = -objectNormal;", + + "#endif", + + "vec3 transformedNormal = normalMatrix * objectNormal;" + + ].join("\n"), + + // SHADOW MAP + + // based on SpiderGL shadow map and Fabien Sanglard's GLSL shadow mapping examples + // http://spidergl.org/example.php?id=6 + // http://fabiensanglard.net/shadowmapping + + shadowmap_pars_fragment: [ + + "#ifdef USE_SHADOWMAP", + + "uniform sampler2D shadowMap[ MAX_SHADOWS ];", + "uniform vec2 shadowMapSize[ MAX_SHADOWS ];", + + "uniform float shadowDarkness[ MAX_SHADOWS ];", + "uniform float shadowBias[ MAX_SHADOWS ];", + + "varying vec4 vShadowCoord[ MAX_SHADOWS ];", + + "float unpackDepth( const in vec4 rgba_depth ) {", + + "const vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );", + "float depth = dot( rgba_depth, bit_shift );", + "return depth;", + + "}", + + "#endif" + + ].join("\n"), + + shadowmap_fragment: [ + + "#ifdef USE_SHADOWMAP", + + "#ifdef SHADOWMAP_DEBUG", + + "vec3 frustumColors[3];", + "frustumColors[0] = vec3( 1.0, 0.5, 0.0 );", + "frustumColors[1] = vec3( 0.0, 1.0, 0.8 );", + "frustumColors[2] = vec3( 0.0, 0.5, 1.0 );", + + "#endif", + + "#ifdef SHADOWMAP_CASCADE", + + "int inFrustumCount = 0;", + + "#endif", + + "float fDepth;", + "vec3 shadowColor = vec3( 1.0 );", + + "for( int i = 0; i < MAX_SHADOWS; i ++ ) {", + + "vec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;", + + // "if ( something && something )" breaks ATI OpenGL shader compiler + // "if ( all( something, something ) )" using this instead + + "bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );", + "bool inFrustum = all( inFrustumVec );", + + // don't shadow pixels outside of light frustum + // use just first frustum (for cascades) + // don't shadow pixels behind far plane of light frustum + + "#ifdef SHADOWMAP_CASCADE", + + "inFrustumCount += int( inFrustum );", + "bvec3 frustumTestVec = bvec3( inFrustum, inFrustumCount == 1, shadowCoord.z <= 1.0 );", + + "#else", + + "bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );", + + "#endif", + + "bool frustumTest = all( frustumTestVec );", + + "if ( frustumTest ) {", + + "shadowCoord.z += shadowBias[ i ];", + + "#if defined( SHADOWMAP_TYPE_PCF )", + + // Percentage-close filtering + // (9 pixel kernel) + // http://fabiensanglard.net/shadowmappingPCF/ + + "float shadow = 0.0;", + + /* + // nested loops breaks shader compiler / validator on some ATI cards when using OpenGL + // must enroll loop manually + + "for ( float y = -1.25; y <= 1.25; y += 1.25 )", + "for ( float x = -1.25; x <= 1.25; x += 1.25 ) {", + + "vec4 rgbaDepth = texture2D( shadowMap[ i ], vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy );", + + // doesn't seem to produce any noticeable visual difference compared to simple "texture2D" lookup + //"vec4 rgbaDepth = texture2DProj( shadowMap[ i ], vec4( vShadowCoord[ i ].w * ( vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy ), 0.05, vShadowCoord[ i ].w ) );", + + "float fDepth = unpackDepth( rgbaDepth );", + + "if ( fDepth < shadowCoord.z )", + "shadow += 1.0;", + + "}", + + "shadow /= 9.0;", + + */ + + "const float shadowDelta = 1.0 / 9.0;", + + "float xPixelOffset = 1.0 / shadowMapSize[ i ].x;", + "float yPixelOffset = 1.0 / shadowMapSize[ i ].y;", + + "float dx0 = -1.25 * xPixelOffset;", + "float dy0 = -1.25 * yPixelOffset;", + "float dx1 = 1.25 * xPixelOffset;", + "float dy1 = 1.25 * yPixelOffset;", + + "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );", + "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + + "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );", + "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + + "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );", + "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + + "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );", + "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + + "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );", + "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + + "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );", + "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + + "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );", + "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + + "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );", + "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + + "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );", + "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + + "shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );", + + "#elif defined( SHADOWMAP_TYPE_PCF_SOFT )", + + // Percentage-close filtering + // (9 pixel kernel) + // http://fabiensanglard.net/shadowmappingPCF/ + + "float shadow = 0.0;", + + "float xPixelOffset = 1.0 / shadowMapSize[ i ].x;", + "float yPixelOffset = 1.0 / shadowMapSize[ i ].y;", + + "float dx0 = -1.0 * xPixelOffset;", + "float dy0 = -1.0 * yPixelOffset;", + "float dx1 = 1.0 * xPixelOffset;", + "float dy1 = 1.0 * yPixelOffset;", + + "mat3 shadowKernel;", + "mat3 depthKernel;", + + "depthKernel[0][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );", + "if ( depthKernel[0][0] < shadowCoord.z ) shadowKernel[0][0] = 0.25;", + "else shadowKernel[0][0] = 0.0;", + + "depthKernel[0][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );", + "if ( depthKernel[0][1] < shadowCoord.z ) shadowKernel[0][1] = 0.25;", + "else shadowKernel[0][1] = 0.0;", + + "depthKernel[0][2] = unpackDepth( texture2D( shadowMap[ i], shadowCoord.xy + vec2( dx0, dy1 ) ) );", + "if ( depthKernel[0][2] < shadowCoord.z ) shadowKernel[0][2] = 0.25;", + "else shadowKernel[0][2] = 0.0;", + + "depthKernel[1][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );", + "if ( depthKernel[1][0] < shadowCoord.z ) shadowKernel[1][0] = 0.25;", + "else shadowKernel[1][0] = 0.0;", + + "depthKernel[1][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );", + "if ( depthKernel[1][1] < shadowCoord.z ) shadowKernel[1][1] = 0.25;", + "else shadowKernel[1][1] = 0.0;", + + "depthKernel[1][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );", + "if ( depthKernel[1][2] < shadowCoord.z ) shadowKernel[1][2] = 0.25;", + "else shadowKernel[1][2] = 0.0;", + + "depthKernel[2][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );", + "if ( depthKernel[2][0] < shadowCoord.z ) shadowKernel[2][0] = 0.25;", + "else shadowKernel[2][0] = 0.0;", + + "depthKernel[2][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );", + "if ( depthKernel[2][1] < shadowCoord.z ) shadowKernel[2][1] = 0.25;", + "else shadowKernel[2][1] = 0.0;", + + "depthKernel[2][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );", + "if ( depthKernel[2][2] < shadowCoord.z ) shadowKernel[2][2] = 0.25;", + "else shadowKernel[2][2] = 0.0;", + + "vec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[i].xy );", + + "shadowKernel[0] = mix( shadowKernel[1], shadowKernel[0], fractionalCoord.x );", + "shadowKernel[1] = mix( shadowKernel[2], shadowKernel[1], fractionalCoord.x );", + + "vec4 shadowValues;", + "shadowValues.x = mix( shadowKernel[0][1], shadowKernel[0][0], fractionalCoord.y );", + "shadowValues.y = mix( shadowKernel[0][2], shadowKernel[0][1], fractionalCoord.y );", + "shadowValues.z = mix( shadowKernel[1][1], shadowKernel[1][0], fractionalCoord.y );", + "shadowValues.w = mix( shadowKernel[1][2], shadowKernel[1][1], fractionalCoord.y );", + + "shadow = dot( shadowValues, vec4( 1.0 ) );", + + "shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );", + + "#else", + + "vec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );", + "float fDepth = unpackDepth( rgbaDepth );", + + "if ( fDepth < shadowCoord.z )", + + // spot with multiple shadows is darker + + "shadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] );", + + // spot with multiple shadows has the same color as single shadow spot + + //"shadowColor = min( shadowColor, vec3( shadowDarkness[ i ] ) );", + + "#endif", + + "}", + + + "#ifdef SHADOWMAP_DEBUG", + + "#ifdef SHADOWMAP_CASCADE", + + "if ( inFrustum && inFrustumCount == 1 ) gl_FragColor.xyz *= frustumColors[ i ];", + + "#else", + + "if ( inFrustum ) gl_FragColor.xyz *= frustumColors[ i ];", + + "#endif", + + "#endif", + + "}", + + "#ifdef GAMMA_OUTPUT", + + "shadowColor *= shadowColor;", + + "#endif", + + "gl_FragColor.xyz = gl_FragColor.xyz * shadowColor;", + + "#endif" + + ].join("\n"), + + shadowmap_pars_vertex: [ + + "#ifdef USE_SHADOWMAP", + + "varying vec4 vShadowCoord[ MAX_SHADOWS ];", + "uniform mat4 shadowMatrix[ MAX_SHADOWS ];", + + "#endif" + + ].join("\n"), + + shadowmap_vertex: [ + + "#ifdef USE_SHADOWMAP", + + "for( int i = 0; i < MAX_SHADOWS; i ++ ) {", + + "vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;", + + "}", + + "#endif" + + ].join("\n"), + + // ALPHATEST + + alphatest_fragment: [ + + "#ifdef ALPHATEST", + + "if ( gl_FragColor.a < ALPHATEST ) discard;", + + "#endif" + + ].join("\n"), + + // LINEAR SPACE + + linear_to_gamma_fragment: [ + + "#ifdef GAMMA_OUTPUT", + + "gl_FragColor.xyz = sqrt( gl_FragColor.xyz );", + + "#endif" + + ].join("\n") + + +}; + +THREE.UniformsUtils = { + + merge: function ( uniforms ) { + + var u, p, tmp, merged = {}; + + for ( u = 0; u < uniforms.length; u ++ ) { + + tmp = this.clone( uniforms[ u ] ); + + for ( p in tmp ) { + + merged[ p ] = tmp[ p ]; + + } + + } + + return merged; + + }, + + clone: function ( uniforms_src ) { + + var u, p, parameter, parameter_src, uniforms_dst = {}; + + for ( u in uniforms_src ) { + + uniforms_dst[ u ] = {}; + + for ( p in uniforms_src[ u ] ) { + + parameter_src = uniforms_src[ u ][ p ]; + + if ( parameter_src instanceof THREE.Color || + parameter_src instanceof THREE.Vector2 || + parameter_src instanceof THREE.Vector3 || + parameter_src instanceof THREE.Vector4 || + parameter_src instanceof THREE.Matrix4 || + parameter_src instanceof THREE.Texture ) { + + uniforms_dst[ u ][ p ] = parameter_src.clone(); + + } else if ( parameter_src instanceof Array ) { + + uniforms_dst[ u ][ p ] = parameter_src.slice(); + + } else { + + uniforms_dst[ u ][ p ] = parameter_src; + + } + + } + + } + + return uniforms_dst; + + } + +}; + +THREE.UniformsLib = { + + common: { + + "diffuse" : { type: "c", value: new THREE.Color( 0xeeeeee ) }, + "opacity" : { type: "f", value: 1.0 }, + + "map" : { type: "t", value: null }, + "offsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, + + "lightMap" : { type: "t", value: null }, + "specularMap" : { type: "t", value: null }, + + "envMap" : { type: "t", value: null }, + "flipEnvMap" : { type: "f", value: -1 }, + "useRefract" : { type: "i", value: 0 }, + "reflectivity" : { type: "f", value: 1.0 }, + "refractionRatio" : { type: "f", value: 0.98 }, + "combine" : { type: "i", value: 0 }, + + "morphTargetInfluences" : { type: "f", value: 0 } + + }, + + bump: { + + "bumpMap" : { type: "t", value: null }, + "bumpScale" : { type: "f", value: 1 } + + }, + + normalmap: { + + "normalMap" : { type: "t", value: null }, + "normalScale" : { type: "v2", value: new THREE.Vector2( 1, 1 ) } + }, + + fog : { + + "fogDensity" : { type: "f", value: 0.00025 }, + "fogNear" : { type: "f", value: 1 }, + "fogFar" : { type: "f", value: 2000 }, + "fogColor" : { type: "c", value: new THREE.Color( 0xffffff ) } + + }, + + lights: { + + "ambientLightColor" : { type: "fv", value: [] }, + + "directionalLightDirection" : { type: "fv", value: [] }, + "directionalLightColor" : { type: "fv", value: [] }, + + "hemisphereLightDirection" : { type: "fv", value: [] }, + "hemisphereLightSkyColor" : { type: "fv", value: [] }, + "hemisphereLightGroundColor" : { type: "fv", value: [] }, + + "pointLightColor" : { type: "fv", value: [] }, + "pointLightPosition" : { type: "fv", value: [] }, + "pointLightDistance" : { type: "fv1", value: [] }, + + "spotLightColor" : { type: "fv", value: [] }, + "spotLightPosition" : { type: "fv", value: [] }, + "spotLightDirection" : { type: "fv", value: [] }, + "spotLightDistance" : { type: "fv1", value: [] }, + "spotLightAngleCos" : { type: "fv1", value: [] }, + "spotLightExponent" : { type: "fv1", value: [] } + + }, + + particle: { + + "psColor" : { type: "c", value: new THREE.Color( 0xeeeeee ) }, + "opacity" : { type: "f", value: 1.0 }, + "size" : { type: "f", value: 1.0 }, + "scale" : { type: "f", value: 1.0 }, + "map" : { type: "t", value: null }, + + "fogDensity" : { type: "f", value: 0.00025 }, + "fogNear" : { type: "f", value: 1 }, + "fogFar" : { type: "f", value: 2000 }, + "fogColor" : { type: "c", value: new THREE.Color( 0xffffff ) } + + }, + + shadowmap: { + + "shadowMap": { type: "tv", value: [] }, + "shadowMapSize": { type: "v2v", value: [] }, + + "shadowBias" : { type: "fv1", value: [] }, + "shadowDarkness": { type: "fv1", value: [] }, + + "shadowMatrix" : { type: "m4v", value: [] } + + } + +}; + +THREE.ShaderLib = { + + 'basic': { + + uniforms: THREE.UniformsUtils.merge( [ + + THREE.UniformsLib[ "common" ], + THREE.UniformsLib[ "fog" ], + THREE.UniformsLib[ "shadowmap" ] + + ] ), + + vertexShader: [ + + THREE.ShaderChunk[ "map_pars_vertex" ], + THREE.ShaderChunk[ "lightmap_pars_vertex" ], + THREE.ShaderChunk[ "envmap_pars_vertex" ], + THREE.ShaderChunk[ "color_pars_vertex" ], + THREE.ShaderChunk[ "morphtarget_pars_vertex" ], + THREE.ShaderChunk[ "skinning_pars_vertex" ], + THREE.ShaderChunk[ "shadowmap_pars_vertex" ], + + "void main() {", + + THREE.ShaderChunk[ "map_vertex" ], + THREE.ShaderChunk[ "lightmap_vertex" ], + THREE.ShaderChunk[ "color_vertex" ], + THREE.ShaderChunk[ "skinbase_vertex" ], + + "#ifdef USE_ENVMAP", + + THREE.ShaderChunk[ "morphnormal_vertex" ], + THREE.ShaderChunk[ "skinnormal_vertex" ], + THREE.ShaderChunk[ "defaultnormal_vertex" ], + + "#endif", + + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "skinning_vertex" ], + THREE.ShaderChunk[ "default_vertex" ], + + THREE.ShaderChunk[ "worldpos_vertex" ], + THREE.ShaderChunk[ "envmap_vertex" ], + THREE.ShaderChunk[ "shadowmap_vertex" ], + + "}" + + ].join("\n"), + + fragmentShader: [ + + "uniform vec3 diffuse;", + "uniform float opacity;", + + THREE.ShaderChunk[ "color_pars_fragment" ], + THREE.ShaderChunk[ "map_pars_fragment" ], + THREE.ShaderChunk[ "lightmap_pars_fragment" ], + THREE.ShaderChunk[ "envmap_pars_fragment" ], + THREE.ShaderChunk[ "fog_pars_fragment" ], + THREE.ShaderChunk[ "shadowmap_pars_fragment" ], + THREE.ShaderChunk[ "specularmap_pars_fragment" ], + + "void main() {", + + "gl_FragColor = vec4( diffuse, opacity );", + + THREE.ShaderChunk[ "map_fragment" ], + THREE.ShaderChunk[ "alphatest_fragment" ], + THREE.ShaderChunk[ "specularmap_fragment" ], + THREE.ShaderChunk[ "lightmap_fragment" ], + THREE.ShaderChunk[ "color_fragment" ], + THREE.ShaderChunk[ "envmap_fragment" ], + THREE.ShaderChunk[ "shadowmap_fragment" ], + + THREE.ShaderChunk[ "linear_to_gamma_fragment" ], + + THREE.ShaderChunk[ "fog_fragment" ], + + "}" + + ].join("\n") + + }, + + 'lambert': { + + uniforms: THREE.UniformsUtils.merge( [ + + THREE.UniformsLib[ "common" ], + THREE.UniformsLib[ "fog" ], + THREE.UniformsLib[ "lights" ], + THREE.UniformsLib[ "shadowmap" ], + + { + "ambient" : { type: "c", value: new THREE.Color( 0xffffff ) }, + "emissive" : { type: "c", value: new THREE.Color( 0x000000 ) }, + "wrapRGB" : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) } + } + + ] ), + + vertexShader: [ + + "#define LAMBERT", + + "varying vec3 vLightFront;", + + "#ifdef DOUBLE_SIDED", + + "varying vec3 vLightBack;", + + "#endif", + + THREE.ShaderChunk[ "map_pars_vertex" ], + THREE.ShaderChunk[ "lightmap_pars_vertex" ], + THREE.ShaderChunk[ "envmap_pars_vertex" ], + THREE.ShaderChunk[ "lights_lambert_pars_vertex" ], + THREE.ShaderChunk[ "color_pars_vertex" ], + THREE.ShaderChunk[ "morphtarget_pars_vertex" ], + THREE.ShaderChunk[ "skinning_pars_vertex" ], + THREE.ShaderChunk[ "shadowmap_pars_vertex" ], + + "void main() {", + + THREE.ShaderChunk[ "map_vertex" ], + THREE.ShaderChunk[ "lightmap_vertex" ], + THREE.ShaderChunk[ "color_vertex" ], + + THREE.ShaderChunk[ "morphnormal_vertex" ], + THREE.ShaderChunk[ "skinbase_vertex" ], + THREE.ShaderChunk[ "skinnormal_vertex" ], + THREE.ShaderChunk[ "defaultnormal_vertex" ], + + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "skinning_vertex" ], + THREE.ShaderChunk[ "default_vertex" ], + + THREE.ShaderChunk[ "worldpos_vertex" ], + THREE.ShaderChunk[ "envmap_vertex" ], + THREE.ShaderChunk[ "lights_lambert_vertex" ], + THREE.ShaderChunk[ "shadowmap_vertex" ], + + "}" + + ].join("\n"), + + fragmentShader: [ + + "uniform float opacity;", + + "varying vec3 vLightFront;", + + "#ifdef DOUBLE_SIDED", + + "varying vec3 vLightBack;", + + "#endif", + + THREE.ShaderChunk[ "color_pars_fragment" ], + THREE.ShaderChunk[ "map_pars_fragment" ], + THREE.ShaderChunk[ "lightmap_pars_fragment" ], + THREE.ShaderChunk[ "envmap_pars_fragment" ], + THREE.ShaderChunk[ "fog_pars_fragment" ], + THREE.ShaderChunk[ "shadowmap_pars_fragment" ], + THREE.ShaderChunk[ "specularmap_pars_fragment" ], + + "void main() {", + + "gl_FragColor = vec4( vec3 ( 1.0 ), opacity );", + + THREE.ShaderChunk[ "map_fragment" ], + THREE.ShaderChunk[ "alphatest_fragment" ], + THREE.ShaderChunk[ "specularmap_fragment" ], + + "#ifdef DOUBLE_SIDED", + + //"float isFront = float( gl_FrontFacing );", + //"gl_FragColor.xyz *= isFront * vLightFront + ( 1.0 - isFront ) * vLightBack;", + + "if ( gl_FrontFacing )", + "gl_FragColor.xyz *= vLightFront;", + "else", + "gl_FragColor.xyz *= vLightBack;", + + "#else", + + "gl_FragColor.xyz *= vLightFront;", + + "#endif", + + THREE.ShaderChunk[ "lightmap_fragment" ], + THREE.ShaderChunk[ "color_fragment" ], + THREE.ShaderChunk[ "envmap_fragment" ], + THREE.ShaderChunk[ "shadowmap_fragment" ], + + THREE.ShaderChunk[ "linear_to_gamma_fragment" ], + + THREE.ShaderChunk[ "fog_fragment" ], + + "}" + + ].join("\n") + + }, + + 'phong': { + + uniforms: THREE.UniformsUtils.merge( [ + + THREE.UniformsLib[ "common" ], + THREE.UniformsLib[ "bump" ], + THREE.UniformsLib[ "normalmap" ], + THREE.UniformsLib[ "fog" ], + THREE.UniformsLib[ "lights" ], + THREE.UniformsLib[ "shadowmap" ], + + { + "ambient" : { type: "c", value: new THREE.Color( 0xffffff ) }, + "emissive" : { type: "c", value: new THREE.Color( 0x000000 ) }, + "specular" : { type: "c", value: new THREE.Color( 0x111111 ) }, + "shininess": { type: "f", value: 30 }, + "wrapRGB" : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) } + } + + ] ), + + vertexShader: [ + + "#define PHONG", + + "varying vec3 vViewPosition;", + "varying vec3 vNormal;", + + THREE.ShaderChunk[ "map_pars_vertex" ], + THREE.ShaderChunk[ "lightmap_pars_vertex" ], + THREE.ShaderChunk[ "envmap_pars_vertex" ], + THREE.ShaderChunk[ "lights_phong_pars_vertex" ], + THREE.ShaderChunk[ "color_pars_vertex" ], + THREE.ShaderChunk[ "morphtarget_pars_vertex" ], + THREE.ShaderChunk[ "skinning_pars_vertex" ], + THREE.ShaderChunk[ "shadowmap_pars_vertex" ], + + "void main() {", + + THREE.ShaderChunk[ "map_vertex" ], + THREE.ShaderChunk[ "lightmap_vertex" ], + THREE.ShaderChunk[ "color_vertex" ], + + THREE.ShaderChunk[ "morphnormal_vertex" ], + THREE.ShaderChunk[ "skinbase_vertex" ], + THREE.ShaderChunk[ "skinnormal_vertex" ], + THREE.ShaderChunk[ "defaultnormal_vertex" ], + + "vNormal = normalize( transformedNormal );", + + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "skinning_vertex" ], + THREE.ShaderChunk[ "default_vertex" ], + + "vViewPosition = -mvPosition.xyz;", + + THREE.ShaderChunk[ "worldpos_vertex" ], + THREE.ShaderChunk[ "envmap_vertex" ], + THREE.ShaderChunk[ "lights_phong_vertex" ], + THREE.ShaderChunk[ "shadowmap_vertex" ], + + "}" + + ].join("\n"), + + fragmentShader: [ + + "uniform vec3 diffuse;", + "uniform float opacity;", + + "uniform vec3 ambient;", + "uniform vec3 emissive;", + "uniform vec3 specular;", + "uniform float shininess;", + + THREE.ShaderChunk[ "color_pars_fragment" ], + THREE.ShaderChunk[ "map_pars_fragment" ], + THREE.ShaderChunk[ "lightmap_pars_fragment" ], + THREE.ShaderChunk[ "envmap_pars_fragment" ], + THREE.ShaderChunk[ "fog_pars_fragment" ], + THREE.ShaderChunk[ "lights_phong_pars_fragment" ], + THREE.ShaderChunk[ "shadowmap_pars_fragment" ], + THREE.ShaderChunk[ "bumpmap_pars_fragment" ], + THREE.ShaderChunk[ "normalmap_pars_fragment" ], + THREE.ShaderChunk[ "specularmap_pars_fragment" ], + + "void main() {", + + "gl_FragColor = vec4( vec3 ( 1.0 ), opacity );", + + THREE.ShaderChunk[ "map_fragment" ], + THREE.ShaderChunk[ "alphatest_fragment" ], + THREE.ShaderChunk[ "specularmap_fragment" ], + + THREE.ShaderChunk[ "lights_phong_fragment" ], + + THREE.ShaderChunk[ "lightmap_fragment" ], + THREE.ShaderChunk[ "color_fragment" ], + THREE.ShaderChunk[ "envmap_fragment" ], + THREE.ShaderChunk[ "shadowmap_fragment" ], + + THREE.ShaderChunk[ "linear_to_gamma_fragment" ], + + THREE.ShaderChunk[ "fog_fragment" ], + + "}" + + ].join("\n") + + }, + + 'particle_basic': { + + uniforms: THREE.UniformsUtils.merge( [ + + THREE.UniformsLib[ "particle" ], + THREE.UniformsLib[ "shadowmap" ] + + ] ), + + vertexShader: [ + + "uniform float size;", + "uniform float scale;", + + THREE.ShaderChunk[ "color_pars_vertex" ], + THREE.ShaderChunk[ "shadowmap_pars_vertex" ], + + "void main() {", + + THREE.ShaderChunk[ "color_vertex" ], + + "vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );", + + "#ifdef USE_SIZEATTENUATION", + "gl_PointSize = size * ( scale / length( mvPosition.xyz ) );", + "#else", + "gl_PointSize = size;", + "#endif", + + "gl_Position = projectionMatrix * mvPosition;", + + THREE.ShaderChunk[ "worldpos_vertex" ], + THREE.ShaderChunk[ "shadowmap_vertex" ], + + "}" + + ].join("\n"), + + fragmentShader: [ + + "uniform vec3 psColor;", + "uniform float opacity;", + + THREE.ShaderChunk[ "color_pars_fragment" ], + THREE.ShaderChunk[ "map_particle_pars_fragment" ], + THREE.ShaderChunk[ "fog_pars_fragment" ], + THREE.ShaderChunk[ "shadowmap_pars_fragment" ], + + "void main() {", + + "gl_FragColor = vec4( psColor, opacity );", + + THREE.ShaderChunk[ "map_particle_fragment" ], + THREE.ShaderChunk[ "alphatest_fragment" ], + THREE.ShaderChunk[ "color_fragment" ], + THREE.ShaderChunk[ "shadowmap_fragment" ], + THREE.ShaderChunk[ "fog_fragment" ], + + "}" + + ].join("\n") + + }, + + 'dashed': { + + uniforms: THREE.UniformsUtils.merge( [ + + THREE.UniformsLib[ "common" ], + THREE.UniformsLib[ "fog" ], + + { + "scale": { type: "f", value: 1 }, + "dashSize": { type: "f", value: 1 }, + "totalSize": { type: "f", value: 2 } + } + + ] ), + + vertexShader: [ + + "uniform float scale;", + "attribute float lineDistance;", + + "varying float vLineDistance;", + + THREE.ShaderChunk[ "color_pars_vertex" ], + + "void main() {", + + THREE.ShaderChunk[ "color_vertex" ], + + "vLineDistance = scale * lineDistance;", + + "vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );", + "gl_Position = projectionMatrix * mvPosition;", + + "}" + + ].join("\n"), + + fragmentShader: [ + + "uniform vec3 diffuse;", + "uniform float opacity;", + + "uniform float dashSize;", + "uniform float totalSize;", + + "varying float vLineDistance;", + + THREE.ShaderChunk[ "color_pars_fragment" ], + THREE.ShaderChunk[ "fog_pars_fragment" ], + + "void main() {", + + "if ( mod( vLineDistance, totalSize ) > dashSize ) {", + + "discard;", + + "}", + + "gl_FragColor = vec4( diffuse, opacity );", + + THREE.ShaderChunk[ "color_fragment" ], + THREE.ShaderChunk[ "fog_fragment" ], + + "}" + + ].join("\n") + + }, + + 'depth': { + + uniforms: { + + "mNear": { type: "f", value: 1.0 }, + "mFar" : { type: "f", value: 2000.0 }, + "opacity" : { type: "f", value: 1.0 } + + }, + + vertexShader: [ + + "void main() {", + + "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", + + "}" + + ].join("\n"), + + fragmentShader: [ + + "uniform float mNear;", + "uniform float mFar;", + "uniform float opacity;", + + "void main() {", + + "float depth = gl_FragCoord.z / gl_FragCoord.w;", + "float color = 1.0 - smoothstep( mNear, mFar, depth );", + "gl_FragColor = vec4( vec3( color ), opacity );", + + "}" + + ].join("\n") + + }, + + 'normal': { + + uniforms: { + + "opacity" : { type: "f", value: 1.0 } + + }, + + vertexShader: [ + + "varying vec3 vNormal;", + + "void main() {", + + "vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );", + "vNormal = normalize( normalMatrix * normal );", + + "gl_Position = projectionMatrix * mvPosition;", + + "}" + + ].join("\n"), + + fragmentShader: [ + + "uniform float opacity;", + "varying vec3 vNormal;", + + "void main() {", + + "gl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, opacity );", + + "}" + + ].join("\n") + + }, + + /* ------------------------------------------------------------------------- + // Normal map shader + // - Blinn-Phong + // - normal + diffuse + specular + AO + displacement + reflection + shadow maps + // - point and directional lights (use with "lights: true" material option) + ------------------------------------------------------------------------- */ + + 'normalmap' : { + + uniforms: THREE.UniformsUtils.merge( [ + + THREE.UniformsLib[ "fog" ], + THREE.UniformsLib[ "lights" ], + THREE.UniformsLib[ "shadowmap" ], + + { + + "enableAO" : { type: "i", value: 0 }, + "enableDiffuse" : { type: "i", value: 0 }, + "enableSpecular" : { type: "i", value: 0 }, + "enableReflection": { type: "i", value: 0 }, + "enableDisplacement": { type: "i", value: 0 }, + + "tDisplacement": { type: "t", value: null }, // must go first as this is vertex texture + "tDiffuse" : { type: "t", value: null }, + "tCube" : { type: "t", value: null }, + "tNormal" : { type: "t", value: null }, + "tSpecular" : { type: "t", value: null }, + "tAO" : { type: "t", value: null }, + + "uNormalScale": { type: "v2", value: new THREE.Vector2( 1, 1 ) }, + + "uDisplacementBias": { type: "f", value: 0.0 }, + "uDisplacementScale": { type: "f", value: 1.0 }, + + "uDiffuseColor": { type: "c", value: new THREE.Color( 0xffffff ) }, + "uSpecularColor": { type: "c", value: new THREE.Color( 0x111111 ) }, + "uAmbientColor": { type: "c", value: new THREE.Color( 0xffffff ) }, + "uShininess": { type: "f", value: 30 }, + "uOpacity": { type: "f", value: 1 }, + + "useRefract": { type: "i", value: 0 }, + "uRefractionRatio": { type: "f", value: 0.98 }, + "uReflectivity": { type: "f", value: 0.5 }, + + "uOffset" : { type: "v2", value: new THREE.Vector2( 0, 0 ) }, + "uRepeat" : { type: "v2", value: new THREE.Vector2( 1, 1 ) }, + + "wrapRGB" : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) } + + } + + ] ), + + fragmentShader: [ + + "uniform vec3 uAmbientColor;", + "uniform vec3 uDiffuseColor;", + "uniform vec3 uSpecularColor;", + "uniform float uShininess;", + "uniform float uOpacity;", + + "uniform bool enableDiffuse;", + "uniform bool enableSpecular;", + "uniform bool enableAO;", + "uniform bool enableReflection;", + + "uniform sampler2D tDiffuse;", + "uniform sampler2D tNormal;", + "uniform sampler2D tSpecular;", + "uniform sampler2D tAO;", + + "uniform samplerCube tCube;", + + "uniform vec2 uNormalScale;", + + "uniform bool useRefract;", + "uniform float uRefractionRatio;", + "uniform float uReflectivity;", + + "varying vec3 vTangent;", + "varying vec3 vBinormal;", + "varying vec3 vNormal;", + "varying vec2 vUv;", + + "uniform vec3 ambientLightColor;", + + "#if MAX_DIR_LIGHTS > 0", + + "uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];", + "uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];", + + "#endif", + + "#if MAX_HEMI_LIGHTS > 0", + + "uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];", + "uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];", + "uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];", + + "#endif", + + "#if MAX_POINT_LIGHTS > 0", + + "uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];", + "uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];", + "uniform float pointLightDistance[ MAX_POINT_LIGHTS ];", + + "#endif", + + "#if MAX_SPOT_LIGHTS > 0", + + "uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];", + "uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];", + "uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];", + "uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];", + "uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];", + "uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];", + + "#endif", + + "#ifdef WRAP_AROUND", + + "uniform vec3 wrapRGB;", + + "#endif", + + "varying vec3 vWorldPosition;", + "varying vec3 vViewPosition;", + + THREE.ShaderChunk[ "shadowmap_pars_fragment" ], + THREE.ShaderChunk[ "fog_pars_fragment" ], + + "void main() {", + + "gl_FragColor = vec4( vec3( 1.0 ), uOpacity );", + + "vec3 specularTex = vec3( 1.0 );", + + "vec3 normalTex = texture2D( tNormal, vUv ).xyz * 2.0 - 1.0;", + "normalTex.xy *= uNormalScale;", + "normalTex = normalize( normalTex );", + + "if( enableDiffuse ) {", + + "#ifdef GAMMA_INPUT", + + "vec4 texelColor = texture2D( tDiffuse, vUv );", + "texelColor.xyz *= texelColor.xyz;", + + "gl_FragColor = gl_FragColor * texelColor;", + + "#else", + + "gl_FragColor = gl_FragColor * texture2D( tDiffuse, vUv );", + + "#endif", + + "}", + + "if( enableAO ) {", + + "#ifdef GAMMA_INPUT", + + "vec4 aoColor = texture2D( tAO, vUv );", + "aoColor.xyz *= aoColor.xyz;", + + "gl_FragColor.xyz = gl_FragColor.xyz * aoColor.xyz;", + + "#else", + + "gl_FragColor.xyz = gl_FragColor.xyz * texture2D( tAO, vUv ).xyz;", + + "#endif", + + "}", + + "if( enableSpecular )", + "specularTex = texture2D( tSpecular, vUv ).xyz;", + + "mat3 tsb = mat3( normalize( vTangent ), normalize( vBinormal ), normalize( vNormal ) );", + "vec3 finalNormal = tsb * normalTex;", + + "#ifdef FLIP_SIDED", + + "finalNormal = -finalNormal;", + + "#endif", + + "vec3 normal = normalize( finalNormal );", + "vec3 viewPosition = normalize( vViewPosition );", + + // point lights + + "#if MAX_POINT_LIGHTS > 0", + + "vec3 pointDiffuse = vec3( 0.0 );", + "vec3 pointSpecular = vec3( 0.0 );", + + "for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {", + + "vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );", + "vec3 pointVector = lPosition.xyz + vViewPosition.xyz;", + + "float pointDistance = 1.0;", + "if ( pointLightDistance[ i ] > 0.0 )", + "pointDistance = 1.0 - min( ( length( pointVector ) / pointLightDistance[ i ] ), 1.0 );", + + "pointVector = normalize( pointVector );", + + // diffuse + + "#ifdef WRAP_AROUND", + + "float pointDiffuseWeightFull = max( dot( normal, pointVector ), 0.0 );", + "float pointDiffuseWeightHalf = max( 0.5 * dot( normal, pointVector ) + 0.5, 0.0 );", + + "vec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );", + + "#else", + + "float pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );", + + "#endif", + + "pointDiffuse += pointDistance * pointLightColor[ i ] * uDiffuseColor * pointDiffuseWeight;", + + // specular + + "vec3 pointHalfVector = normalize( pointVector + viewPosition );", + "float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );", + "float pointSpecularWeight = specularTex.r * max( pow( pointDotNormalHalf, uShininess ), 0.0 );", + + "#ifdef PHYSICALLY_BASED_SHADING", + + // 2.0 => 2.0001 is hack to work around ANGLE bug + + "float specularNormalization = ( uShininess + 2.0001 ) / 8.0;", + + "vec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( pointVector, pointHalfVector ), 5.0 );", + "pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * pointDistance * specularNormalization;", + + "#else", + + "pointSpecular += pointDistance * pointLightColor[ i ] * uSpecularColor * pointSpecularWeight * pointDiffuseWeight;", + + "#endif", + + "}", + + "#endif", + + // spot lights + + "#if MAX_SPOT_LIGHTS > 0", + + "vec3 spotDiffuse = vec3( 0.0 );", + "vec3 spotSpecular = vec3( 0.0 );", + + "for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {", + + "vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );", + "vec3 spotVector = lPosition.xyz + vViewPosition.xyz;", + + "float spotDistance = 1.0;", + "if ( spotLightDistance[ i ] > 0.0 )", + "spotDistance = 1.0 - min( ( length( spotVector ) / spotLightDistance[ i ] ), 1.0 );", + + "spotVector = normalize( spotVector );", + + "float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );", + + "if ( spotEffect > spotLightAngleCos[ i ] ) {", + + "spotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );", + + // diffuse + + "#ifdef WRAP_AROUND", + + "float spotDiffuseWeightFull = max( dot( normal, spotVector ), 0.0 );", + "float spotDiffuseWeightHalf = max( 0.5 * dot( normal, spotVector ) + 0.5, 0.0 );", + + "vec3 spotDiffuseWeight = mix( vec3 ( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );", + + "#else", + + "float spotDiffuseWeight = max( dot( normal, spotVector ), 0.0 );", + + "#endif", + + "spotDiffuse += spotDistance * spotLightColor[ i ] * uDiffuseColor * spotDiffuseWeight * spotEffect;", + + // specular + + "vec3 spotHalfVector = normalize( spotVector + viewPosition );", + "float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );", + "float spotSpecularWeight = specularTex.r * max( pow( spotDotNormalHalf, uShininess ), 0.0 );", + + "#ifdef PHYSICALLY_BASED_SHADING", + + // 2.0 => 2.0001 is hack to work around ANGLE bug + + "float specularNormalization = ( uShininess + 2.0001 ) / 8.0;", + + "vec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( spotVector, spotHalfVector ), 5.0 );", + "spotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * spotDistance * specularNormalization * spotEffect;", + + "#else", + + "spotSpecular += spotDistance * spotLightColor[ i ] * uSpecularColor * spotSpecularWeight * spotDiffuseWeight * spotEffect;", + + "#endif", + + "}", + + "}", + + "#endif", + + // directional lights + + "#if MAX_DIR_LIGHTS > 0", + + "vec3 dirDiffuse = vec3( 0.0 );", + "vec3 dirSpecular = vec3( 0.0 );", + + "for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {", + + "vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );", + "vec3 dirVector = normalize( lDirection.xyz );", + + // diffuse + + "#ifdef WRAP_AROUND", + + "float directionalLightWeightingFull = max( dot( normal, dirVector ), 0.0 );", + "float directionalLightWeightingHalf = max( 0.5 * dot( normal, dirVector ) + 0.5, 0.0 );", + + "vec3 dirDiffuseWeight = mix( vec3( directionalLightWeightingFull ), vec3( directionalLightWeightingHalf ), wrapRGB );", + + "#else", + + "float dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );", + + "#endif", + + "dirDiffuse += directionalLightColor[ i ] * uDiffuseColor * dirDiffuseWeight;", + + // specular + + "vec3 dirHalfVector = normalize( dirVector + viewPosition );", + "float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );", + "float dirSpecularWeight = specularTex.r * max( pow( dirDotNormalHalf, uShininess ), 0.0 );", + + "#ifdef PHYSICALLY_BASED_SHADING", + + // 2.0 => 2.0001 is hack to work around ANGLE bug + + "float specularNormalization = ( uShininess + 2.0001 ) / 8.0;", + + "vec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( dirVector, dirHalfVector ), 5.0 );", + "dirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;", + + "#else", + + "dirSpecular += directionalLightColor[ i ] * uSpecularColor * dirSpecularWeight * dirDiffuseWeight;", + + "#endif", + + "}", + + "#endif", + + // hemisphere lights + + "#if MAX_HEMI_LIGHTS > 0", + + "vec3 hemiDiffuse = vec3( 0.0 );", + "vec3 hemiSpecular = vec3( 0.0 );" , + + "for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {", + + "vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );", + "vec3 lVector = normalize( lDirection.xyz );", + + // diffuse + + "float dotProduct = dot( normal, lVector );", + "float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;", + + "vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );", + + "hemiDiffuse += uDiffuseColor * hemiColor;", + + // specular (sky light) + + + "vec3 hemiHalfVectorSky = normalize( lVector + viewPosition );", + "float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;", + "float hemiSpecularWeightSky = specularTex.r * max( pow( hemiDotNormalHalfSky, uShininess ), 0.0 );", + + // specular (ground light) + + "vec3 lVectorGround = -lVector;", + + "vec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );", + "float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;", + "float hemiSpecularWeightGround = specularTex.r * max( pow( hemiDotNormalHalfGround, uShininess ), 0.0 );", + + "#ifdef PHYSICALLY_BASED_SHADING", + + "float dotProductGround = dot( normal, lVectorGround );", + + // 2.0 => 2.0001 is hack to work around ANGLE bug + + "float specularNormalization = ( uShininess + 2.0001 ) / 8.0;", + + "vec3 schlickSky = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( lVector, hemiHalfVectorSky ), 5.0 );", + "vec3 schlickGround = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 5.0 );", + "hemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );", + + "#else", + + "hemiSpecular += uSpecularColor * hemiColor * ( hemiSpecularWeightSky + hemiSpecularWeightGround ) * hemiDiffuseWeight;", + + "#endif", + + "}", + + "#endif", + + // all lights contribution summation + + "vec3 totalDiffuse = vec3( 0.0 );", + "vec3 totalSpecular = vec3( 0.0 );", + + "#if MAX_DIR_LIGHTS > 0", + + "totalDiffuse += dirDiffuse;", + "totalSpecular += dirSpecular;", + + "#endif", + + "#if MAX_HEMI_LIGHTS > 0", + + "totalDiffuse += hemiDiffuse;", + "totalSpecular += hemiSpecular;", + + "#endif", + + "#if MAX_POINT_LIGHTS > 0", + + "totalDiffuse += pointDiffuse;", + "totalSpecular += pointSpecular;", + + "#endif", + + "#if MAX_SPOT_LIGHTS > 0", + + "totalDiffuse += spotDiffuse;", + "totalSpecular += spotSpecular;", + + "#endif", + + "#ifdef METAL", + + "gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * uAmbientColor + totalSpecular );", + + "#else", + + "gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * uAmbientColor ) + totalSpecular;", + + "#endif", + + "if ( enableReflection ) {", + + "vec3 vReflect;", + "vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );", + + "if ( useRefract ) {", + + "vReflect = refract( cameraToVertex, normal, uRefractionRatio );", + + "} else {", + + "vReflect = reflect( cameraToVertex, normal );", + + "}", + + "vec4 cubeColor = textureCube( tCube, vec3( -vReflect.x, vReflect.yz ) );", + + "#ifdef GAMMA_INPUT", + + "cubeColor.xyz *= cubeColor.xyz;", + + "#endif", + + "gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularTex.r * uReflectivity );", + + "}", + + THREE.ShaderChunk[ "shadowmap_fragment" ], + THREE.ShaderChunk[ "linear_to_gamma_fragment" ], + THREE.ShaderChunk[ "fog_fragment" ], + + "}" + + ].join("\n"), + + vertexShader: [ + + "attribute vec4 tangent;", + + "uniform vec2 uOffset;", + "uniform vec2 uRepeat;", + + "uniform bool enableDisplacement;", + + "#ifdef VERTEX_TEXTURES", + + "uniform sampler2D tDisplacement;", + "uniform float uDisplacementScale;", + "uniform float uDisplacementBias;", + + "#endif", + + "varying vec3 vTangent;", + "varying vec3 vBinormal;", + "varying vec3 vNormal;", + "varying vec2 vUv;", + + "varying vec3 vWorldPosition;", + "varying vec3 vViewPosition;", + + THREE.ShaderChunk[ "skinning_pars_vertex" ], + THREE.ShaderChunk[ "shadowmap_pars_vertex" ], + + "void main() {", + + THREE.ShaderChunk[ "skinbase_vertex" ], + THREE.ShaderChunk[ "skinnormal_vertex" ], + + // normal, tangent and binormal vectors + + "#ifdef USE_SKINNING", + + "vNormal = normalize( normalMatrix * skinnedNormal.xyz );", + + "vec4 skinnedTangent = skinMatrix * vec4( tangent.xyz, 0.0 );", + "vTangent = normalize( normalMatrix * skinnedTangent.xyz );", + + "#else", + + "vNormal = normalize( normalMatrix * normal );", + "vTangent = normalize( normalMatrix * tangent.xyz );", + + "#endif", + + "vBinormal = normalize( cross( vNormal, vTangent ) * tangent.w );", + + "vUv = uv * uRepeat + uOffset;", + + // displacement mapping + + "vec3 displacedPosition;", + + "#ifdef VERTEX_TEXTURES", + + "if ( enableDisplacement ) {", + + "vec3 dv = texture2D( tDisplacement, uv ).xyz;", + "float df = uDisplacementScale * dv.x + uDisplacementBias;", + "displacedPosition = position + normalize( normal ) * df;", + + "} else {", + + "#ifdef USE_SKINNING", + + "vec4 skinVertex = vec4( position, 1.0 );", + + "vec4 skinned = boneMatX * skinVertex * skinWeight.x;", + "skinned += boneMatY * skinVertex * skinWeight.y;", + + "displacedPosition = skinned.xyz;", + + "#else", + + "displacedPosition = position;", + + "#endif", + + "}", + + "#else", + + "#ifdef USE_SKINNING", + + "vec4 skinVertex = vec4( position, 1.0 );", + + "vec4 skinned = boneMatX * skinVertex * skinWeight.x;", + "skinned += boneMatY * skinVertex * skinWeight.y;", + + "displacedPosition = skinned.xyz;", + + "#else", + + "displacedPosition = position;", + + "#endif", + + "#endif", + + // + + "vec4 mvPosition = modelViewMatrix * vec4( displacedPosition, 1.0 );", + "vec4 worldPosition = modelMatrix * vec4( displacedPosition, 1.0 );", + + "gl_Position = projectionMatrix * mvPosition;", + + // + + "vWorldPosition = worldPosition.xyz;", + "vViewPosition = -mvPosition.xyz;", + + // shadows + + "#ifdef USE_SHADOWMAP", + + "for( int i = 0; i < MAX_SHADOWS; i ++ ) {", + + "vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;", + + "}", + + "#endif", + + "}" + + ].join("\n") + + }, + + /* ------------------------------------------------------------------------- + // Cube map shader + ------------------------------------------------------------------------- */ + + 'cube': { + + uniforms: { "tCube": { type: "t", value: null }, + "tFlip": { type: "f", value: -1 } }, + + vertexShader: [ + + "varying vec3 vWorldPosition;", + + "void main() {", + + "vec4 worldPosition = modelMatrix * vec4( position, 1.0 );", + "vWorldPosition = worldPosition.xyz;", + + "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", + + "}" + + ].join("\n"), + + fragmentShader: [ + + "uniform samplerCube tCube;", + "uniform float tFlip;", + + "varying vec3 vWorldPosition;", + + "void main() {", + + "gl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );", + + "}" + + ].join("\n") + + }, + + // Depth encoding into RGBA texture + // based on SpiderGL shadow map example + // http://spidergl.org/example.php?id=6 + // originally from + // http://www.gamedev.net/topic/442138-packing-a-float-into-a-a8r8g8b8-texture-shader/page__whichpage__1%25EF%25BF%25BD + // see also here: + // http://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/ + + 'depthRGBA': { + + uniforms: {}, + + vertexShader: [ + + THREE.ShaderChunk[ "morphtarget_pars_vertex" ], + THREE.ShaderChunk[ "skinning_pars_vertex" ], + + "void main() {", + + THREE.ShaderChunk[ "skinbase_vertex" ], + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "skinning_vertex" ], + THREE.ShaderChunk[ "default_vertex" ], + + "}" + + ].join("\n"), + + fragmentShader: [ + + "vec4 pack_depth( const in float depth ) {", + + "const vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );", + "const vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );", + "vec4 res = fract( depth * bit_shift );", + "res -= res.xxyz * bit_mask;", + "return res;", + + "}", + + "void main() {", + + "gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );", + + //"gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z / gl_FragCoord.w );", + //"float z = ( ( gl_FragCoord.z / gl_FragCoord.w ) - 3.0 ) / ( 4000.0 - 3.0 );", + //"gl_FragData[ 0 ] = pack_depth( z );", + //"gl_FragData[ 0 ] = vec4( z, z, z, 1.0 );", + + "}" + + ].join("\n") + + } + +}; +/** + * @author supereggbert / http://www.paulbrunt.co.uk/ + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * @author szimek / https://github.com/szimek/ + */ + +THREE.WebGLRenderer = function ( parameters ) { + + console.log( 'THREE.WebGLRenderer', THREE.REVISION ); + + parameters = parameters || {}; + + var _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElement( 'canvas' ), + + _precision = parameters.precision !== undefined ? parameters.precision : 'highp', + + _alpha = parameters.alpha !== undefined ? parameters.alpha : true, + _premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true, + _antialias = parameters.antialias !== undefined ? parameters.antialias : false, + _stencil = parameters.stencil !== undefined ? parameters.stencil : true, + _preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false, + + _clearColor = parameters.clearColor !== undefined ? new THREE.Color( parameters.clearColor ) : new THREE.Color( 0x000000 ), + _clearAlpha = parameters.clearAlpha !== undefined ? parameters.clearAlpha : 0; + + // public properties + + this.domElement = _canvas; + this.context = null; + this.devicePixelRatio = parameters.devicePixelRatio !== undefined + ? parameters.devicePixelRatio + : window.devicePixelRatio !== undefined + ? window.devicePixelRatio + : 1; + + // clearing + + this.autoClear = true; + this.autoClearColor = true; + this.autoClearDepth = true; + this.autoClearStencil = true; + + // scene graph + + this.sortObjects = true; + + this.autoUpdateObjects = true; + this.autoUpdateScene = true; + + // physically based shading + + this.gammaInput = false; + this.gammaOutput = false; + this.physicallyBasedShading = false; + + // shadow map + + this.shadowMapEnabled = false; + this.shadowMapAutoUpdate = true; + this.shadowMapType = THREE.PCFShadowMap; + this.shadowMapCullFace = THREE.CullFaceFront; + this.shadowMapDebug = false; + this.shadowMapCascade = false; + + // morphs + + this.maxMorphTargets = 8; + this.maxMorphNormals = 4; + + // flags + + this.autoScaleCubemaps = true; + + // custom render plugins + + this.renderPluginsPre = []; + this.renderPluginsPost = []; + + // info + + this.info = { + + memory: { + + programs: 0, + geometries: 0, + textures: 0 + + }, + + render: { + + calls: 0, + vertices: 0, + faces: 0, + points: 0 + + } + + }; + + // internal properties + + var _this = this, + + _programs = [], + _programs_counter = 0, + + // internal state cache + + _currentProgram = null, + _currentFramebuffer = null, + _currentMaterialId = -1, + _currentGeometryGroupHash = null, + _currentCamera = null, + _geometryGroupCounter = 0, + + _usedTextureUnits = 0, + + // GL state cache + + _oldDoubleSided = -1, + _oldFlipSided = -1, + + _oldBlending = -1, + + _oldBlendEquation = -1, + _oldBlendSrc = -1, + _oldBlendDst = -1, + + _oldDepthTest = -1, + _oldDepthWrite = -1, + + _oldPolygonOffset = null, + _oldPolygonOffsetFactor = null, + _oldPolygonOffsetUnits = null, + + _oldLineWidth = null, + + _viewportX = 0, + _viewportY = 0, + _viewportWidth = 0, + _viewportHeight = 0, + _currentWidth = 0, + _currentHeight = 0, + + _enabledAttributes = {}, + + // frustum + + _frustum = new THREE.Frustum(), + + // camera matrices cache + + _projScreenMatrix = new THREE.Matrix4(), + _projScreenMatrixPS = new THREE.Matrix4(), + + _vector3 = new THREE.Vector3(), + + // light arrays cache + + _direction = new THREE.Vector3(), + + _lightsNeedUpdate = true, + + _lights = { + + ambient: [ 0, 0, 0 ], + directional: { length: 0, colors: new Array(), positions: new Array() }, + point: { length: 0, colors: new Array(), positions: new Array(), distances: new Array() }, + spot: { length: 0, colors: new Array(), positions: new Array(), distances: new Array(), directions: new Array(), anglesCos: new Array(), exponents: new Array() }, + hemi: { length: 0, skyColors: new Array(), groundColors: new Array(), positions: new Array() } + + }; + + // initialize + + var _gl; + + var _glExtensionTextureFloat; + var _glExtensionStandardDerivatives; + var _glExtensionTextureFilterAnisotropic; + var _glExtensionCompressedTextureS3TC; + + initGL(); + + setDefaultGLState(); + + this.context = _gl; + + // GPU capabilities + + var _maxTextures = _gl.getParameter( _gl.MAX_TEXTURE_IMAGE_UNITS ); + var _maxVertexTextures = _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ); + var _maxTextureSize = _gl.getParameter( _gl.MAX_TEXTURE_SIZE ); + var _maxCubemapSize = _gl.getParameter( _gl.MAX_CUBE_MAP_TEXTURE_SIZE ); + + var _maxAnisotropy = _glExtensionTextureFilterAnisotropic ? _gl.getParameter( _glExtensionTextureFilterAnisotropic.MAX_TEXTURE_MAX_ANISOTROPY_EXT ) : 0; + + var _supportsVertexTextures = ( _maxVertexTextures > 0 ); + var _supportsBoneTextures = _supportsVertexTextures && _glExtensionTextureFloat; + + var _compressedTextureFormats = _glExtensionCompressedTextureS3TC ? _gl.getParameter( _gl.COMPRESSED_TEXTURE_FORMATS ) : []; + + // + + var _vertexShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.HIGH_FLOAT ); + var _vertexShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.MEDIUM_FLOAT ); + var _vertexShaderPrecisionLowpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.LOW_FLOAT ); + + var _fragmentShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.HIGH_FLOAT ); + var _fragmentShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.MEDIUM_FLOAT ); + var _fragmentShaderPrecisionLowpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.LOW_FLOAT ); + + var _vertexShaderPrecisionHighpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.HIGH_INT ); + var _vertexShaderPrecisionMediumpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.MEDIUM_INT ); + var _vertexShaderPrecisionLowpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.LOW_INT ); + + var _fragmentShaderPrecisionHighpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.HIGH_INT ); + var _fragmentShaderPrecisionMediumpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.MEDIUM_INT ); + var _fragmentShaderPrecisionLowpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.LOW_INT ); + + // clamp precision to maximum available + + var highpAvailable = _vertexShaderPrecisionHighpFloat.precision > 0 && _fragmentShaderPrecisionHighpFloat.precision > 0; + var mediumpAvailable = _vertexShaderPrecisionMediumpFloat.precision > 0 && _fragmentShaderPrecisionMediumpFloat.precision > 0; + + if ( _precision === "highp" && ! highpAvailable ) { + + if ( mediumpAvailable ) { + + _precision = "mediump"; + console.warn( "WebGLRenderer: highp not supported, using mediump" ); + + } else { + + _precision = "lowp"; + console.warn( "WebGLRenderer: highp and mediump not supported, using lowp" ); + + } + + } + + if ( _precision === "mediump" && ! mediumpAvailable ) { + + _precision = "lowp"; + console.warn( "WebGLRenderer: mediump not supported, using lowp" ); + + } + + // API + + this.getContext = function () { + + return _gl; + + }; + + this.supportsVertexTextures = function () { + + return _supportsVertexTextures; + + }; + + this.supportsFloatTextures = function () { + + return _glExtensionTextureFloat; + + }; + + this.supportsStandardDerivatives = function () { + + return _glExtensionStandardDerivatives; + + }; + + this.supportsCompressedTextureS3TC = function () { + + return _glExtensionCompressedTextureS3TC; + + }; + + this.getMaxAnisotropy = function () { + + return _maxAnisotropy; + + }; + + this.getPrecision = function () { + + return _precision; + + }; + + this.setSize = function ( width, height ) { + + _canvas.width = width * this.devicePixelRatio; + _canvas.height = height * this.devicePixelRatio; + + _canvas.style.width = width + 'px'; + _canvas.style.height = height + 'px'; + + this.setViewport( 0, 0, _canvas.width, _canvas.height ); + + }; + + this.setViewport = function ( x, y, width, height ) { + + _viewportX = x !== undefined ? x : 0; + _viewportY = y !== undefined ? y : 0; + + _viewportWidth = width !== undefined ? width : _canvas.width; + _viewportHeight = height !== undefined ? height : _canvas.height; + + _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight ); + + }; + + this.setScissor = function ( x, y, width, height ) { + + _gl.scissor( x, y, width, height ); + + }; + + this.enableScissorTest = function ( enable ) { + + enable ? _gl.enable( _gl.SCISSOR_TEST ) : _gl.disable( _gl.SCISSOR_TEST ); + + }; + + // Clearing + + this.setClearColorHex = function ( hex, alpha ) { + + _clearColor.setHex( hex ); + _clearAlpha = alpha; + + _gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); + + }; + + this.setClearColor = function ( color, alpha ) { + + _clearColor.copy( color ); + _clearAlpha = alpha; + + _gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); + + }; + + this.getClearColor = function () { + + return _clearColor; + + }; + + this.getClearAlpha = function () { + + return _clearAlpha; + + }; + + this.clear = function ( color, depth, stencil ) { + + var bits = 0; + + if ( color === undefined || color ) bits |= _gl.COLOR_BUFFER_BIT; + if ( depth === undefined || depth ) bits |= _gl.DEPTH_BUFFER_BIT; + if ( stencil === undefined || stencil ) bits |= _gl.STENCIL_BUFFER_BIT; + + _gl.clear( bits ); + + }; + + this.clearTarget = function ( renderTarget, color, depth, stencil ) { + + this.setRenderTarget( renderTarget ); + this.clear( color, depth, stencil ); + + }; + + // Plugins + + this.addPostPlugin = function ( plugin ) { + + plugin.init( this ); + this.renderPluginsPost.push( plugin ); + + }; + + this.addPrePlugin = function ( plugin ) { + + plugin.init( this ); + this.renderPluginsPre.push( plugin ); + + }; + + // Rendering + + this.updateShadowMap = function ( scene, camera ) { + + _currentProgram = null; + _oldBlending = -1; + _oldDepthTest = -1; + _oldDepthWrite = -1; + _currentGeometryGroupHash = -1; + _currentMaterialId = -1; + _lightsNeedUpdate = true; + _oldDoubleSided = -1; + _oldFlipSided = -1; + + this.shadowMapPlugin.update( scene, camera ); + + }; + + // Internal functions + + // Buffer allocation + + function createParticleBuffers ( geometry ) { + + geometry.__webglVertexBuffer = _gl.createBuffer(); + geometry.__webglColorBuffer = _gl.createBuffer(); + + _this.info.memory.geometries ++; + + }; + + function createLineBuffers ( geometry ) { + + geometry.__webglVertexBuffer = _gl.createBuffer(); + geometry.__webglColorBuffer = _gl.createBuffer(); + geometry.__webglLineDistanceBuffer = _gl.createBuffer(); + + _this.info.memory.geometries ++; + + }; + + function createRibbonBuffers ( geometry ) { + + geometry.__webglVertexBuffer = _gl.createBuffer(); + geometry.__webglColorBuffer = _gl.createBuffer(); + geometry.__webglNormalBuffer = _gl.createBuffer(); + + _this.info.memory.geometries ++; + + }; + + function createMeshBuffers ( geometryGroup ) { + + geometryGroup.__webglVertexBuffer = _gl.createBuffer(); + geometryGroup.__webglNormalBuffer = _gl.createBuffer(); + geometryGroup.__webglTangentBuffer = _gl.createBuffer(); + geometryGroup.__webglColorBuffer = _gl.createBuffer(); + geometryGroup.__webglUVBuffer = _gl.createBuffer(); + geometryGroup.__webglUV2Buffer = _gl.createBuffer(); + + geometryGroup.__webglSkinIndicesBuffer = _gl.createBuffer(); + geometryGroup.__webglSkinWeightsBuffer = _gl.createBuffer(); + + geometryGroup.__webglFaceBuffer = _gl.createBuffer(); + geometryGroup.__webglLineBuffer = _gl.createBuffer(); + + var m, ml; + + if ( geometryGroup.numMorphTargets ) { + + geometryGroup.__webglMorphTargetsBuffers = []; + + for ( m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) { + + geometryGroup.__webglMorphTargetsBuffers.push( _gl.createBuffer() ); + + } + + } + + if ( geometryGroup.numMorphNormals ) { + + geometryGroup.__webglMorphNormalsBuffers = []; + + for ( m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) { + + geometryGroup.__webglMorphNormalsBuffers.push( _gl.createBuffer() ); + + } + + } + + _this.info.memory.geometries ++; + + }; + + // Events + + var onGeometryDispose = function ( event ) { + + var geometry = event.target; + + geometry.removeEventListener( 'dispose', onGeometryDispose ); + + deallocateGeometry( geometry ); + + _this.info.memory.geometries --; + + }; + + var onTextureDispose = function ( event ) { + + var texture = event.target; + + texture.removeEventListener( 'dispose', onTextureDispose ); + + deallocateTexture( texture ); + + _this.info.memory.textures --; + + + }; + + var onRenderTargetDispose = function ( event ) { + + var renderTarget = event.target; + + renderTarget.removeEventListener( 'dispose', onRenderTargetDispose ); + + deallocateRenderTarget( renderTarget ); + + _this.info.memory.textures --; + + }; + + var onMaterialDispose = function ( event ) { + + var material = event.target; + + material.removeEventListener( 'dispose', onMaterialDispose ); + + deallocateMaterial( material ); + + }; + + // Buffer deallocation + + var deallocateGeometry = function ( geometry ) { + + geometry.__webglInit = undefined; + + if ( geometry.__webglVertexBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglVertexBuffer ); + if ( geometry.__webglNormalBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglNormalBuffer ); + if ( geometry.__webglTangentBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglTangentBuffer ); + if ( geometry.__webglColorBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglColorBuffer ); + if ( geometry.__webglUVBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglUVBuffer ); + if ( geometry.__webglUV2Buffer !== undefined ) _gl.deleteBuffer( geometry.__webglUV2Buffer ); + + if ( geometry.__webglSkinIndicesBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglSkinIndicesBuffer ); + if ( geometry.__webglSkinWeightsBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglSkinWeightsBuffer ); + + if ( geometry.__webglFaceBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglFaceBuffer ); + if ( geometry.__webglLineBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglLineBuffer ); + + if ( geometry.__webglLineDistanceBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglLineDistanceBuffer ); + + // geometry groups + + if ( geometry.geometryGroups !== undefined ) { + + for ( var g in geometry.geometryGroups ) { + + var geometryGroup = geometry.geometryGroups[ g ]; + + if ( geometryGroup.numMorphTargets !== undefined ) { + + for ( var m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) { + + _gl.deleteBuffer( geometryGroup.__webglMorphTargetsBuffers[ m ] ); + + } + + } + + if ( geometryGroup.numMorphNormals !== undefined ) { + + for ( var m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) { + + _gl.deleteBuffer( geometryGroup.__webglMorphNormalsBuffers[ m ] ); + + } + + } + + deleteCustomAttributesBuffers( geometryGroup ); + + } + + } + + deleteCustomAttributesBuffers( geometry ); + + }; + + var deallocateTexture = function ( texture ) { + + if ( texture.image && texture.image.__webglTextureCube ) { + + // cube texture + + _gl.deleteTexture( texture.image.__webglTextureCube ); + + } else { + + // 2D texture + + if ( ! texture.__webglInit ) return; + + texture.__webglInit = false; + _gl.deleteTexture( texture.__webglTexture ); + + } + + }; + + var deallocateRenderTarget = function ( renderTarget ) { + + if ( !renderTarget || ! renderTarget.__webglTexture ) return; + + _gl.deleteTexture( renderTarget.__webglTexture ); + + if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) { + + for ( var i = 0; i < 6; i ++ ) { + + _gl.deleteFramebuffer( renderTarget.__webglFramebuffer[ i ] ); + _gl.deleteRenderbuffer( renderTarget.__webglRenderbuffer[ i ] ); + + } + + } else { + + _gl.deleteFramebuffer( renderTarget.__webglFramebuffer ); + _gl.deleteRenderbuffer( renderTarget.__webglRenderbuffer ); + + } + + }; + + var deallocateMaterial = function ( material ) { + + var program = material.program; + + if ( program === undefined ) return; + + material.program = undefined; + + // only deallocate GL program if this was the last use of shared program + // assumed there is only single copy of any program in the _programs list + // (that's how it's constructed) + + var i, il, programInfo; + var deleteProgram = false; + + for ( i = 0, il = _programs.length; i < il; i ++ ) { + + programInfo = _programs[ i ]; + + if ( programInfo.program === program ) { + + programInfo.usedTimes --; + + if ( programInfo.usedTimes === 0 ) { + + deleteProgram = true; + + } + + break; + + } + + } + + if ( deleteProgram === true ) { + + // avoid using array.splice, this is costlier than creating new array from scratch + + var newPrograms = []; + + for ( i = 0, il = _programs.length; i < il; i ++ ) { + + programInfo = _programs[ i ]; + + if ( programInfo.program !== program ) { + + newPrograms.push( programInfo ); + + } + + } + + _programs = newPrograms; + + _gl.deleteProgram( program ); + + _this.info.memory.programs --; + + } + + }; + + // + + /* + function deleteParticleBuffers ( geometry ) { + + _gl.deleteBuffer( geometry.__webglVertexBuffer ); + _gl.deleteBuffer( geometry.__webglColorBuffer ); + + deleteCustomAttributesBuffers( geometry ); + + _this.info.memory.geometries --; + + }; + + function deleteLineBuffers ( geometry ) { + + _gl.deleteBuffer( geometry.__webglVertexBuffer ); + _gl.deleteBuffer( geometry.__webglColorBuffer ); + _gl.deleteBuffer( geometry.__webglLineDistanceBuffer ); + + deleteCustomAttributesBuffers( geometry ); + + _this.info.memory.geometries --; + + }; + + function deleteRibbonBuffers ( geometry ) { + + _gl.deleteBuffer( geometry.__webglVertexBuffer ); + _gl.deleteBuffer( geometry.__webglColorBuffer ); + _gl.deleteBuffer( geometry.__webglNormalBuffer ); + + deleteCustomAttributesBuffers( geometry ); + + _this.info.memory.geometries --; + + }; + + function deleteMeshBuffers ( geometryGroup ) { + + _gl.deleteBuffer( geometryGroup.__webglVertexBuffer ); + _gl.deleteBuffer( geometryGroup.__webglNormalBuffer ); + _gl.deleteBuffer( geometryGroup.__webglTangentBuffer ); + _gl.deleteBuffer( geometryGroup.__webglColorBuffer ); + _gl.deleteBuffer( geometryGroup.__webglUVBuffer ); + _gl.deleteBuffer( geometryGroup.__webglUV2Buffer ); + + _gl.deleteBuffer( geometryGroup.__webglSkinIndicesBuffer ); + _gl.deleteBuffer( geometryGroup.__webglSkinWeightsBuffer ); + + _gl.deleteBuffer( geometryGroup.__webglFaceBuffer ); + _gl.deleteBuffer( geometryGroup.__webglLineBuffer ); + + var m, ml; + + if ( geometryGroup.numMorphTargets ) { + + for ( m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) { + + _gl.deleteBuffer( geometryGroup.__webglMorphTargetsBuffers[ m ] ); + + } + + } + + if ( geometryGroup.numMorphNormals ) { + + for ( m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) { + + _gl.deleteBuffer( geometryGroup.__webglMorphNormalsBuffers[ m ] ); + + } + + } + + deleteCustomAttributesBuffers( geometryGroup ); + + _this.info.memory.geometries --; + + }; + */ + + function deleteCustomAttributesBuffers( geometry ) { + + if ( geometry.__webglCustomAttributesList ) { + + for ( var id in geometry.__webglCustomAttributesList ) { + + _gl.deleteBuffer( geometry.__webglCustomAttributesList[ id ].buffer ); + + } + + } + + }; + + // Buffer initialization + + function initCustomAttributes ( geometry, object ) { + + var nvertices = geometry.vertices.length; + + var material = object.material; + + if ( material.attributes ) { + + if ( geometry.__webglCustomAttributesList === undefined ) { + + geometry.__webglCustomAttributesList = []; + + } + + for ( var a in material.attributes ) { + + var attribute = material.attributes[ a ]; + + if ( !attribute.__webglInitialized || attribute.createUniqueBuffers ) { + + attribute.__webglInitialized = true; + + var size = 1; // "f" and "i" + + if ( attribute.type === "v2" ) size = 2; + else if ( attribute.type === "v3" ) size = 3; + else if ( attribute.type === "v4" ) size = 4; + else if ( attribute.type === "c" ) size = 3; + + attribute.size = size; + + attribute.array = new Float32Array( nvertices * size ); + + attribute.buffer = _gl.createBuffer(); + attribute.buffer.belongsToAttribute = a; + + attribute.needsUpdate = true; + + } + + geometry.__webglCustomAttributesList.push( attribute ); + + } + + } + + }; + + function initParticleBuffers ( geometry, object ) { + + var nvertices = geometry.vertices.length; + + geometry.__vertexArray = new Float32Array( nvertices * 3 ); + geometry.__colorArray = new Float32Array( nvertices * 3 ); + + geometry.__sortArray = []; + + geometry.__webglParticleCount = nvertices; + + initCustomAttributes ( geometry, object ); + + }; + + function initLineBuffers ( geometry, object ) { + + var nvertices = geometry.vertices.length; + + geometry.__vertexArray = new Float32Array( nvertices * 3 ); + geometry.__colorArray = new Float32Array( nvertices * 3 ); + geometry.__lineDistanceArray = new Float32Array( nvertices * 1 ); + + geometry.__webglLineCount = nvertices; + + initCustomAttributes ( geometry, object ); + + }; + + function initRibbonBuffers ( geometry, object ) { + + var nvertices = geometry.vertices.length; + + geometry.__vertexArray = new Float32Array( nvertices * 3 ); + geometry.__colorArray = new Float32Array( nvertices * 3 ); + geometry.__normalArray = new Float32Array( nvertices * 3 ); + + geometry.__webglVertexCount = nvertices; + + initCustomAttributes ( geometry, object ); + + }; + + function initMeshBuffers ( geometryGroup, object ) { + + var geometry = object.geometry, + faces3 = geometryGroup.faces3, + faces4 = geometryGroup.faces4, + + nvertices = faces3.length * 3 + faces4.length * 4, + ntris = faces3.length * 1 + faces4.length * 2, + nlines = faces3.length * 3 + faces4.length * 4, + + material = getBufferMaterial( object, geometryGroup ), + + uvType = bufferGuessUVType( material ), + normalType = bufferGuessNormalType( material ), + vertexColorType = bufferGuessVertexColorType( material ); + + //console.log( "uvType", uvType, "normalType", normalType, "vertexColorType", vertexColorType, object, geometryGroup, material ); + + geometryGroup.__vertexArray = new Float32Array( nvertices * 3 ); + + if ( normalType ) { + + geometryGroup.__normalArray = new Float32Array( nvertices * 3 ); + + } + + if ( geometry.hasTangents ) { + + geometryGroup.__tangentArray = new Float32Array( nvertices * 4 ); + + } + + if ( vertexColorType ) { + + geometryGroup.__colorArray = new Float32Array( nvertices * 3 ); + + } + + if ( uvType ) { + + if ( geometry.faceUvs.length > 0 || geometry.faceVertexUvs.length > 0 ) { + + geometryGroup.__uvArray = new Float32Array( nvertices * 2 ); + + } + + if ( geometry.faceUvs.length > 1 || geometry.faceVertexUvs.length > 1 ) { + + geometryGroup.__uv2Array = new Float32Array( nvertices * 2 ); + + } + + } + + if ( object.geometry.skinWeights.length && object.geometry.skinIndices.length ) { + + geometryGroup.__skinIndexArray = new Float32Array( nvertices * 4 ); + geometryGroup.__skinWeightArray = new Float32Array( nvertices * 4 ); + + } + + geometryGroup.__faceArray = new Uint16Array( ntris * 3 ); + geometryGroup.__lineArray = new Uint16Array( nlines * 2 ); + + var m, ml; + + if ( geometryGroup.numMorphTargets ) { + + geometryGroup.__morphTargetsArrays = []; + + for ( m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) { + + geometryGroup.__morphTargetsArrays.push( new Float32Array( nvertices * 3 ) ); + + } + + } + + if ( geometryGroup.numMorphNormals ) { + + geometryGroup.__morphNormalsArrays = []; + + for ( m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) { + + geometryGroup.__morphNormalsArrays.push( new Float32Array( nvertices * 3 ) ); + + } + + } + + geometryGroup.__webglFaceCount = ntris * 3; + geometryGroup.__webglLineCount = nlines * 2; + + + // custom attributes + + if ( material.attributes ) { + + if ( geometryGroup.__webglCustomAttributesList === undefined ) { + + geometryGroup.__webglCustomAttributesList = []; + + } + + for ( var a in material.attributes ) { + + // Do a shallow copy of the attribute object so different geometryGroup chunks use different + // attribute buffers which are correctly indexed in the setMeshBuffers function + + var originalAttribute = material.attributes[ a ]; + + var attribute = {}; + + for ( var property in originalAttribute ) { + + attribute[ property ] = originalAttribute[ property ]; + + } + + if ( !attribute.__webglInitialized || attribute.createUniqueBuffers ) { + + attribute.__webglInitialized = true; + + var size = 1; // "f" and "i" + + if( attribute.type === "v2" ) size = 2; + else if( attribute.type === "v3" ) size = 3; + else if( attribute.type === "v4" ) size = 4; + else if( attribute.type === "c" ) size = 3; + + attribute.size = size; + + attribute.array = new Float32Array( nvertices * size ); + + attribute.buffer = _gl.createBuffer(); + attribute.buffer.belongsToAttribute = a; + + originalAttribute.needsUpdate = true; + attribute.__original = originalAttribute; + + } + + geometryGroup.__webglCustomAttributesList.push( attribute ); + + } + + } + + geometryGroup.__inittedArrays = true; + + }; + + function getBufferMaterial( object, geometryGroup ) { + + return object.material instanceof THREE.MeshFaceMaterial + ? object.material.materials[ geometryGroup.materialIndex ] + : object.material; + + }; + + function materialNeedsSmoothNormals ( material ) { + + return material && material.shading !== undefined && material.shading === THREE.SmoothShading; + + }; + + function bufferGuessNormalType ( material ) { + + // only MeshBasicMaterial and MeshDepthMaterial don't need normals + + if ( ( material instanceof THREE.MeshBasicMaterial && !material.envMap ) || material instanceof THREE.MeshDepthMaterial ) { + + return false; + + } + + if ( materialNeedsSmoothNormals( material ) ) { + + return THREE.SmoothShading; + + } else { + + return THREE.FlatShading; + + } + + }; + + function bufferGuessVertexColorType ( material ) { + + if ( material.vertexColors ) { + + return material.vertexColors; + + } + + return false; + + }; + + function bufferGuessUVType ( material ) { + + // material must use some texture to require uvs + + if ( material.map || material.lightMap || material.bumpMap || material.normalMap || material.specularMap || material instanceof THREE.ShaderMaterial ) { + + return true; + + } + + return false; + + }; + + // + + function initDirectBuffers( geometry ) { + + var a, attribute, type; + + for ( a in geometry.attributes ) { + + if ( a === "index" ) { + + type = _gl.ELEMENT_ARRAY_BUFFER; + + } else { + + type = _gl.ARRAY_BUFFER; + + } + + attribute = geometry.attributes[ a ]; + + attribute.buffer = _gl.createBuffer(); + + _gl.bindBuffer( type, attribute.buffer ); + _gl.bufferData( type, attribute.array, _gl.STATIC_DRAW ); + + } + + }; + + // Buffer setting + + function setParticleBuffers ( geometry, hint, object ) { + + var v, c, vertex, offset, index, color, + + vertices = geometry.vertices, + vl = vertices.length, + + colors = geometry.colors, + cl = colors.length, + + vertexArray = geometry.__vertexArray, + colorArray = geometry.__colorArray, + + sortArray = geometry.__sortArray, + + dirtyVertices = geometry.verticesNeedUpdate, + dirtyElements = geometry.elementsNeedUpdate, + dirtyColors = geometry.colorsNeedUpdate, + + customAttributes = geometry.__webglCustomAttributesList, + i, il, + a, ca, cal, value, + customAttribute; + + if ( object.sortParticles ) { + + _projScreenMatrixPS.copy( _projScreenMatrix ); + _projScreenMatrixPS.multiply( object.matrixWorld ); + + for ( v = 0; v < vl; v ++ ) { + + vertex = vertices[ v ]; + + _vector3.copy( vertex ); + _vector3.applyProjection( _projScreenMatrixPS ); + + sortArray[ v ] = [ _vector3.z, v ]; + + } + + sortArray.sort( numericalSort ); + + for ( v = 0; v < vl; v ++ ) { + + vertex = vertices[ sortArray[v][1] ]; + + offset = v * 3; + + vertexArray[ offset ] = vertex.x; + vertexArray[ offset + 1 ] = vertex.y; + vertexArray[ offset + 2 ] = vertex.z; + + } + + for ( c = 0; c < cl; c ++ ) { + + offset = c * 3; + + color = colors[ sortArray[c][1] ]; + + colorArray[ offset ] = color.r; + colorArray[ offset + 1 ] = color.g; + colorArray[ offset + 2 ] = color.b; + + } + + if ( customAttributes ) { + + for ( i = 0, il = customAttributes.length; i < il; i ++ ) { + + customAttribute = customAttributes[ i ]; + + if ( ! ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) ) continue; + + offset = 0; + + cal = customAttribute.value.length; + + if ( customAttribute.size === 1 ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + index = sortArray[ ca ][ 1 ]; + + customAttribute.array[ ca ] = customAttribute.value[ index ]; + + } + + } else if ( customAttribute.size === 2 ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + index = sortArray[ ca ][ 1 ]; + + value = customAttribute.value[ index ]; + + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; + + offset += 2; + + } + + } else if ( customAttribute.size === 3 ) { + + if ( customAttribute.type === "c" ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + index = sortArray[ ca ][ 1 ]; + + value = customAttribute.value[ index ]; + + customAttribute.array[ offset ] = value.r; + customAttribute.array[ offset + 1 ] = value.g; + customAttribute.array[ offset + 2 ] = value.b; + + offset += 3; + + } + + } else { + + for ( ca = 0; ca < cal; ca ++ ) { + + index = sortArray[ ca ][ 1 ]; + + value = customAttribute.value[ index ]; + + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; + customAttribute.array[ offset + 2 ] = value.z; + + offset += 3; + + } + + } + + } else if ( customAttribute.size === 4 ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + index = sortArray[ ca ][ 1 ]; + + value = customAttribute.value[ index ]; + + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; + customAttribute.array[ offset + 2 ] = value.z; + customAttribute.array[ offset + 3 ] = value.w; + + offset += 4; + + } + + } + + } + + } + + } else { + + if ( dirtyVertices ) { + + for ( v = 0; v < vl; v ++ ) { + + vertex = vertices[ v ]; + + offset = v * 3; + + vertexArray[ offset ] = vertex.x; + vertexArray[ offset + 1 ] = vertex.y; + vertexArray[ offset + 2 ] = vertex.z; + + } + + } + + if ( dirtyColors ) { + + for ( c = 0; c < cl; c ++ ) { + + color = colors[ c ]; + + offset = c * 3; + + colorArray[ offset ] = color.r; + colorArray[ offset + 1 ] = color.g; + colorArray[ offset + 2 ] = color.b; + + } + + } + + if ( customAttributes ) { + + for ( i = 0, il = customAttributes.length; i < il; i ++ ) { + + customAttribute = customAttributes[ i ]; + + if ( customAttribute.needsUpdate && + ( customAttribute.boundTo === undefined || + customAttribute.boundTo === "vertices") ) { + + cal = customAttribute.value.length; + + offset = 0; + + if ( customAttribute.size === 1 ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + customAttribute.array[ ca ] = customAttribute.value[ ca ]; + + } + + } else if ( customAttribute.size === 2 ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + value = customAttribute.value[ ca ]; + + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; + + offset += 2; + + } + + } else if ( customAttribute.size === 3 ) { + + if ( customAttribute.type === "c" ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + value = customAttribute.value[ ca ]; + + customAttribute.array[ offset ] = value.r; + customAttribute.array[ offset + 1 ] = value.g; + customAttribute.array[ offset + 2 ] = value.b; + + offset += 3; + + } + + } else { + + for ( ca = 0; ca < cal; ca ++ ) { + + value = customAttribute.value[ ca ]; + + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; + customAttribute.array[ offset + 2 ] = value.z; + + offset += 3; + + } + + } + + } else if ( customAttribute.size === 4 ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + value = customAttribute.value[ ca ]; + + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; + customAttribute.array[ offset + 2 ] = value.z; + customAttribute.array[ offset + 3 ] = value.w; + + offset += 4; + + } + + } + + } + + } + + } + + } + + if ( dirtyVertices || object.sortParticles ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint ); + + } + + if ( dirtyColors || object.sortParticles ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint ); + + } + + if ( customAttributes ) { + + for ( i = 0, il = customAttributes.length; i < il; i ++ ) { + + customAttribute = customAttributes[ i ]; + + if ( customAttribute.needsUpdate || object.sortParticles ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint ); + + } + + } + + } + + + }; + + function setLineBuffers ( geometry, hint ) { + + var v, c, d, vertex, offset, color, + + vertices = geometry.vertices, + colors = geometry.colors, + lineDistances = geometry.lineDistances, + + vl = vertices.length, + cl = colors.length, + dl = lineDistances.length, + + vertexArray = geometry.__vertexArray, + colorArray = geometry.__colorArray, + lineDistanceArray = geometry.__lineDistanceArray, + + dirtyVertices = geometry.verticesNeedUpdate, + dirtyColors = geometry.colorsNeedUpdate, + dirtyLineDistances = geometry.lineDistancesNeedUpdate, + + customAttributes = geometry.__webglCustomAttributesList, + + i, il, + a, ca, cal, value, + customAttribute; + + if ( dirtyVertices ) { + + for ( v = 0; v < vl; v ++ ) { + + vertex = vertices[ v ]; + + offset = v * 3; + + vertexArray[ offset ] = vertex.x; + vertexArray[ offset + 1 ] = vertex.y; + vertexArray[ offset + 2 ] = vertex.z; + + } + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint ); + + } + + if ( dirtyColors ) { + + for ( c = 0; c < cl; c ++ ) { + + color = colors[ c ]; + + offset = c * 3; + + colorArray[ offset ] = color.r; + colorArray[ offset + 1 ] = color.g; + colorArray[ offset + 2 ] = color.b; + + } + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint ); + + } + + if ( dirtyLineDistances ) { + + for ( d = 0; d < dl; d ++ ) { + + lineDistanceArray[ d ] = lineDistances[ d ]; + + } + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglLineDistanceBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, lineDistanceArray, hint ); + + } + + if ( customAttributes ) { + + for ( i = 0, il = customAttributes.length; i < il; i ++ ) { + + customAttribute = customAttributes[ i ]; + + if ( customAttribute.needsUpdate && + ( customAttribute.boundTo === undefined || + customAttribute.boundTo === "vertices" ) ) { + + offset = 0; + + cal = customAttribute.value.length; + + if ( customAttribute.size === 1 ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + customAttribute.array[ ca ] = customAttribute.value[ ca ]; + + } + + } else if ( customAttribute.size === 2 ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + value = customAttribute.value[ ca ]; + + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; + + offset += 2; + + } + + } else if ( customAttribute.size === 3 ) { + + if ( customAttribute.type === "c" ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + value = customAttribute.value[ ca ]; + + customAttribute.array[ offset ] = value.r; + customAttribute.array[ offset + 1 ] = value.g; + customAttribute.array[ offset + 2 ] = value.b; + + offset += 3; + + } + + } else { + + for ( ca = 0; ca < cal; ca ++ ) { + + value = customAttribute.value[ ca ]; + + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; + customAttribute.array[ offset + 2 ] = value.z; + + offset += 3; + + } + + } + + } else if ( customAttribute.size === 4 ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + value = customAttribute.value[ ca ]; + + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; + customAttribute.array[ offset + 2 ] = value.z; + customAttribute.array[ offset + 3 ] = value.w; + + offset += 4; + + } + + } + + _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint ); + + } + + } + + } + + }; + + function setRibbonBuffers ( geometry, hint ) { + + var v, c, n, vertex, offset, color, normal, + + i, il, ca, cal, customAttribute, value, + + vertices = geometry.vertices, + colors = geometry.colors, + normals = geometry.normals, + + vl = vertices.length, + cl = colors.length, + nl = normals.length, + + vertexArray = geometry.__vertexArray, + colorArray = geometry.__colorArray, + normalArray = geometry.__normalArray, + + dirtyVertices = geometry.verticesNeedUpdate, + dirtyColors = geometry.colorsNeedUpdate, + dirtyNormals = geometry.normalsNeedUpdate, + + customAttributes = geometry.__webglCustomAttributesList; + + if ( dirtyVertices ) { + + for ( v = 0; v < vl; v ++ ) { + + vertex = vertices[ v ]; + + offset = v * 3; + + vertexArray[ offset ] = vertex.x; + vertexArray[ offset + 1 ] = vertex.y; + vertexArray[ offset + 2 ] = vertex.z; + + } + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint ); + + } + + if ( dirtyColors ) { + + for ( c = 0; c < cl; c ++ ) { + + color = colors[ c ]; + + offset = c * 3; + + colorArray[ offset ] = color.r; + colorArray[ offset + 1 ] = color.g; + colorArray[ offset + 2 ] = color.b; + + } + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint ); + + } + + if ( dirtyNormals ) { + + for ( n = 0; n < nl; n ++ ) { + + normal = normals[ n ]; + + offset = n * 3; + + normalArray[ offset ] = normal.x; + normalArray[ offset + 1 ] = normal.y; + normalArray[ offset + 2 ] = normal.z; + + } + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglNormalBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, normalArray, hint ); + + } + + if ( customAttributes ) { + + for ( i = 0, il = customAttributes.length; i < il; i ++ ) { + + customAttribute = customAttributes[ i ]; + + if ( customAttribute.needsUpdate && + ( customAttribute.boundTo === undefined || + customAttribute.boundTo === "vertices" ) ) { + + offset = 0; + + cal = customAttribute.value.length; + + if ( customAttribute.size === 1 ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + customAttribute.array[ ca ] = customAttribute.value[ ca ]; + + } + + } else if ( customAttribute.size === 2 ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + value = customAttribute.value[ ca ]; + + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; + + offset += 2; + + } + + } else if ( customAttribute.size === 3 ) { + + if ( customAttribute.type === "c" ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + value = customAttribute.value[ ca ]; + + customAttribute.array[ offset ] = value.r; + customAttribute.array[ offset + 1 ] = value.g; + customAttribute.array[ offset + 2 ] = value.b; + + offset += 3; + + } + + } else { + + for ( ca = 0; ca < cal; ca ++ ) { + + value = customAttribute.value[ ca ]; + + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; + customAttribute.array[ offset + 2 ] = value.z; + + offset += 3; + + } + + } + + } else if ( customAttribute.size === 4 ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + value = customAttribute.value[ ca ]; + + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; + customAttribute.array[ offset + 2 ] = value.z; + customAttribute.array[ offset + 3 ] = value.w; + + offset += 4; + + } + + } + + _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint ); + + } + + } + + } + + }; + + function setMeshBuffers( geometryGroup, object, hint, dispose, material ) { + + if ( ! geometryGroup.__inittedArrays ) { + + return; + + } + + var normalType = bufferGuessNormalType( material ), + vertexColorType = bufferGuessVertexColorType( material ), + uvType = bufferGuessUVType( material ), + + needsSmoothNormals = ( normalType === THREE.SmoothShading ); + + var f, fl, fi, face, + vertexNormals, faceNormal, normal, + vertexColors, faceColor, + vertexTangents, + uv, uv2, v1, v2, v3, v4, t1, t2, t3, t4, n1, n2, n3, n4, + c1, c2, c3, c4, + sw1, sw2, sw3, sw4, + si1, si2, si3, si4, + sa1, sa2, sa3, sa4, + sb1, sb2, sb3, sb4, + m, ml, i, il, + vn, uvi, uv2i, + vk, vkl, vka, + nka, chf, faceVertexNormals, + a, + + vertexIndex = 0, + + offset = 0, + offset_uv = 0, + offset_uv2 = 0, + offset_face = 0, + offset_normal = 0, + offset_tangent = 0, + offset_line = 0, + offset_color = 0, + offset_skin = 0, + offset_morphTarget = 0, + offset_custom = 0, + offset_customSrc = 0, + + value, + + vertexArray = geometryGroup.__vertexArray, + uvArray = geometryGroup.__uvArray, + uv2Array = geometryGroup.__uv2Array, + normalArray = geometryGroup.__normalArray, + tangentArray = geometryGroup.__tangentArray, + colorArray = geometryGroup.__colorArray, + + skinIndexArray = geometryGroup.__skinIndexArray, + skinWeightArray = geometryGroup.__skinWeightArray, + + morphTargetsArrays = geometryGroup.__morphTargetsArrays, + morphNormalsArrays = geometryGroup.__morphNormalsArrays, + + customAttributes = geometryGroup.__webglCustomAttributesList, + customAttribute, + + faceArray = geometryGroup.__faceArray, + lineArray = geometryGroup.__lineArray, + + geometry = object.geometry, // this is shared for all chunks + + dirtyVertices = geometry.verticesNeedUpdate, + dirtyElements = geometry.elementsNeedUpdate, + dirtyUvs = geometry.uvsNeedUpdate, + dirtyNormals = geometry.normalsNeedUpdate, + dirtyTangents = geometry.tangentsNeedUpdate, + dirtyColors = geometry.colorsNeedUpdate, + dirtyMorphTargets = geometry.morphTargetsNeedUpdate, + + vertices = geometry.vertices, + chunk_faces3 = geometryGroup.faces3, + chunk_faces4 = geometryGroup.faces4, + obj_faces = geometry.faces, + + obj_uvs = geometry.faceVertexUvs[ 0 ], + obj_uvs2 = geometry.faceVertexUvs[ 1 ], + + obj_colors = geometry.colors, + + obj_skinIndices = geometry.skinIndices, + obj_skinWeights = geometry.skinWeights, + + morphTargets = geometry.morphTargets, + morphNormals = geometry.morphNormals; + + if ( dirtyVertices ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces3[ f ] ]; + + v1 = vertices[ face.a ]; + v2 = vertices[ face.b ]; + v3 = vertices[ face.c ]; + + vertexArray[ offset ] = v1.x; + vertexArray[ offset + 1 ] = v1.y; + vertexArray[ offset + 2 ] = v1.z; + + vertexArray[ offset + 3 ] = v2.x; + vertexArray[ offset + 4 ] = v2.y; + vertexArray[ offset + 5 ] = v2.z; + + vertexArray[ offset + 6 ] = v3.x; + vertexArray[ offset + 7 ] = v3.y; + vertexArray[ offset + 8 ] = v3.z; + + offset += 9; + + } + + for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces4[ f ] ]; + + v1 = vertices[ face.a ]; + v2 = vertices[ face.b ]; + v3 = vertices[ face.c ]; + v4 = vertices[ face.d ]; + + vertexArray[ offset ] = v1.x; + vertexArray[ offset + 1 ] = v1.y; + vertexArray[ offset + 2 ] = v1.z; + + vertexArray[ offset + 3 ] = v2.x; + vertexArray[ offset + 4 ] = v2.y; + vertexArray[ offset + 5 ] = v2.z; + + vertexArray[ offset + 6 ] = v3.x; + vertexArray[ offset + 7 ] = v3.y; + vertexArray[ offset + 8 ] = v3.z; + + vertexArray[ offset + 9 ] = v4.x; + vertexArray[ offset + 10 ] = v4.y; + vertexArray[ offset + 11 ] = v4.z; + + offset += 12; + + } + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint ); + + } + + if ( dirtyMorphTargets ) { + + for ( vk = 0, vkl = morphTargets.length; vk < vkl; vk ++ ) { + + offset_morphTarget = 0; + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + chf = chunk_faces3[ f ]; + face = obj_faces[ chf ]; + + // morph positions + + v1 = morphTargets[ vk ].vertices[ face.a ]; + v2 = morphTargets[ vk ].vertices[ face.b ]; + v3 = morphTargets[ vk ].vertices[ face.c ]; + + vka = morphTargetsArrays[ vk ]; + + vka[ offset_morphTarget ] = v1.x; + vka[ offset_morphTarget + 1 ] = v1.y; + vka[ offset_morphTarget + 2 ] = v1.z; + + vka[ offset_morphTarget + 3 ] = v2.x; + vka[ offset_morphTarget + 4 ] = v2.y; + vka[ offset_morphTarget + 5 ] = v2.z; + + vka[ offset_morphTarget + 6 ] = v3.x; + vka[ offset_morphTarget + 7 ] = v3.y; + vka[ offset_morphTarget + 8 ] = v3.z; + + // morph normals + + if ( material.morphNormals ) { + + if ( needsSmoothNormals ) { + + faceVertexNormals = morphNormals[ vk ].vertexNormals[ chf ]; + + n1 = faceVertexNormals.a; + n2 = faceVertexNormals.b; + n3 = faceVertexNormals.c; + + } else { + + n1 = morphNormals[ vk ].faceNormals[ chf ]; + n2 = n1; + n3 = n1; + + } + + nka = morphNormalsArrays[ vk ]; + + nka[ offset_morphTarget ] = n1.x; + nka[ offset_morphTarget + 1 ] = n1.y; + nka[ offset_morphTarget + 2 ] = n1.z; + + nka[ offset_morphTarget + 3 ] = n2.x; + nka[ offset_morphTarget + 4 ] = n2.y; + nka[ offset_morphTarget + 5 ] = n2.z; + + nka[ offset_morphTarget + 6 ] = n3.x; + nka[ offset_morphTarget + 7 ] = n3.y; + nka[ offset_morphTarget + 8 ] = n3.z; + + } + + // + + offset_morphTarget += 9; + + } + + for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) { + + chf = chunk_faces4[ f ]; + face = obj_faces[ chf ]; + + // morph positions + + v1 = morphTargets[ vk ].vertices[ face.a ]; + v2 = morphTargets[ vk ].vertices[ face.b ]; + v3 = morphTargets[ vk ].vertices[ face.c ]; + v4 = morphTargets[ vk ].vertices[ face.d ]; + + vka = morphTargetsArrays[ vk ]; + + vka[ offset_morphTarget ] = v1.x; + vka[ offset_morphTarget + 1 ] = v1.y; + vka[ offset_morphTarget + 2 ] = v1.z; + + vka[ offset_morphTarget + 3 ] = v2.x; + vka[ offset_morphTarget + 4 ] = v2.y; + vka[ offset_morphTarget + 5 ] = v2.z; + + vka[ offset_morphTarget + 6 ] = v3.x; + vka[ offset_morphTarget + 7 ] = v3.y; + vka[ offset_morphTarget + 8 ] = v3.z; + + vka[ offset_morphTarget + 9 ] = v4.x; + vka[ offset_morphTarget + 10 ] = v4.y; + vka[ offset_morphTarget + 11 ] = v4.z; + + // morph normals + + if ( material.morphNormals ) { + + if ( needsSmoothNormals ) { + + faceVertexNormals = morphNormals[ vk ].vertexNormals[ chf ]; + + n1 = faceVertexNormals.a; + n2 = faceVertexNormals.b; + n3 = faceVertexNormals.c; + n4 = faceVertexNormals.d; + + } else { + + n1 = morphNormals[ vk ].faceNormals[ chf ]; + n2 = n1; + n3 = n1; + n4 = n1; + + } + + nka = morphNormalsArrays[ vk ]; + + nka[ offset_morphTarget ] = n1.x; + nka[ offset_morphTarget + 1 ] = n1.y; + nka[ offset_morphTarget + 2 ] = n1.z; + + nka[ offset_morphTarget + 3 ] = n2.x; + nka[ offset_morphTarget + 4 ] = n2.y; + nka[ offset_morphTarget + 5 ] = n2.z; + + nka[ offset_morphTarget + 6 ] = n3.x; + nka[ offset_morphTarget + 7 ] = n3.y; + nka[ offset_morphTarget + 8 ] = n3.z; + + nka[ offset_morphTarget + 9 ] = n4.x; + nka[ offset_morphTarget + 10 ] = n4.y; + nka[ offset_morphTarget + 11 ] = n4.z; + + } + + // + + offset_morphTarget += 12; + + } + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ vk ] ); + _gl.bufferData( _gl.ARRAY_BUFFER, morphTargetsArrays[ vk ], hint ); + + if ( material.morphNormals ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ vk ] ); + _gl.bufferData( _gl.ARRAY_BUFFER, morphNormalsArrays[ vk ], hint ); + + } + + } + + } + + if ( obj_skinWeights.length ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces3[ f ] ]; + + // weights + + sw1 = obj_skinWeights[ face.a ]; + sw2 = obj_skinWeights[ face.b ]; + sw3 = obj_skinWeights[ face.c ]; + + skinWeightArray[ offset_skin ] = sw1.x; + skinWeightArray[ offset_skin + 1 ] = sw1.y; + skinWeightArray[ offset_skin + 2 ] = sw1.z; + skinWeightArray[ offset_skin + 3 ] = sw1.w; + + skinWeightArray[ offset_skin + 4 ] = sw2.x; + skinWeightArray[ offset_skin + 5 ] = sw2.y; + skinWeightArray[ offset_skin + 6 ] = sw2.z; + skinWeightArray[ offset_skin + 7 ] = sw2.w; + + skinWeightArray[ offset_skin + 8 ] = sw3.x; + skinWeightArray[ offset_skin + 9 ] = sw3.y; + skinWeightArray[ offset_skin + 10 ] = sw3.z; + skinWeightArray[ offset_skin + 11 ] = sw3.w; + + // indices + + si1 = obj_skinIndices[ face.a ]; + si2 = obj_skinIndices[ face.b ]; + si3 = obj_skinIndices[ face.c ]; + + skinIndexArray[ offset_skin ] = si1.x; + skinIndexArray[ offset_skin + 1 ] = si1.y; + skinIndexArray[ offset_skin + 2 ] = si1.z; + skinIndexArray[ offset_skin + 3 ] = si1.w; + + skinIndexArray[ offset_skin + 4 ] = si2.x; + skinIndexArray[ offset_skin + 5 ] = si2.y; + skinIndexArray[ offset_skin + 6 ] = si2.z; + skinIndexArray[ offset_skin + 7 ] = si2.w; + + skinIndexArray[ offset_skin + 8 ] = si3.x; + skinIndexArray[ offset_skin + 9 ] = si3.y; + skinIndexArray[ offset_skin + 10 ] = si3.z; + skinIndexArray[ offset_skin + 11 ] = si3.w; + + offset_skin += 12; + + } + + for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces4[ f ] ]; + + // weights + + sw1 = obj_skinWeights[ face.a ]; + sw2 = obj_skinWeights[ face.b ]; + sw3 = obj_skinWeights[ face.c ]; + sw4 = obj_skinWeights[ face.d ]; + + skinWeightArray[ offset_skin ] = sw1.x; + skinWeightArray[ offset_skin + 1 ] = sw1.y; + skinWeightArray[ offset_skin + 2 ] = sw1.z; + skinWeightArray[ offset_skin + 3 ] = sw1.w; + + skinWeightArray[ offset_skin + 4 ] = sw2.x; + skinWeightArray[ offset_skin + 5 ] = sw2.y; + skinWeightArray[ offset_skin + 6 ] = sw2.z; + skinWeightArray[ offset_skin + 7 ] = sw2.w; + + skinWeightArray[ offset_skin + 8 ] = sw3.x; + skinWeightArray[ offset_skin + 9 ] = sw3.y; + skinWeightArray[ offset_skin + 10 ] = sw3.z; + skinWeightArray[ offset_skin + 11 ] = sw3.w; + + skinWeightArray[ offset_skin + 12 ] = sw4.x; + skinWeightArray[ offset_skin + 13 ] = sw4.y; + skinWeightArray[ offset_skin + 14 ] = sw4.z; + skinWeightArray[ offset_skin + 15 ] = sw4.w; + + // indices + + si1 = obj_skinIndices[ face.a ]; + si2 = obj_skinIndices[ face.b ]; + si3 = obj_skinIndices[ face.c ]; + si4 = obj_skinIndices[ face.d ]; + + skinIndexArray[ offset_skin ] = si1.x; + skinIndexArray[ offset_skin + 1 ] = si1.y; + skinIndexArray[ offset_skin + 2 ] = si1.z; + skinIndexArray[ offset_skin + 3 ] = si1.w; + + skinIndexArray[ offset_skin + 4 ] = si2.x; + skinIndexArray[ offset_skin + 5 ] = si2.y; + skinIndexArray[ offset_skin + 6 ] = si2.z; + skinIndexArray[ offset_skin + 7 ] = si2.w; + + skinIndexArray[ offset_skin + 8 ] = si3.x; + skinIndexArray[ offset_skin + 9 ] = si3.y; + skinIndexArray[ offset_skin + 10 ] = si3.z; + skinIndexArray[ offset_skin + 11 ] = si3.w; + + skinIndexArray[ offset_skin + 12 ] = si4.x; + skinIndexArray[ offset_skin + 13 ] = si4.y; + skinIndexArray[ offset_skin + 14 ] = si4.z; + skinIndexArray[ offset_skin + 15 ] = si4.w; + + offset_skin += 16; + + } + + if ( offset_skin > 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, skinIndexArray, hint ); + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, skinWeightArray, hint ); + + } + + } + + if ( dirtyColors && vertexColorType ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces3[ f ] ]; + + vertexColors = face.vertexColors; + faceColor = face.color; + + if ( vertexColors.length === 3 && vertexColorType === THREE.VertexColors ) { + + c1 = vertexColors[ 0 ]; + c2 = vertexColors[ 1 ]; + c3 = vertexColors[ 2 ]; + + } else { + + c1 = faceColor; + c2 = faceColor; + c3 = faceColor; + + } + + colorArray[ offset_color ] = c1.r; + colorArray[ offset_color + 1 ] = c1.g; + colorArray[ offset_color + 2 ] = c1.b; + + colorArray[ offset_color + 3 ] = c2.r; + colorArray[ offset_color + 4 ] = c2.g; + colorArray[ offset_color + 5 ] = c2.b; + + colorArray[ offset_color + 6 ] = c3.r; + colorArray[ offset_color + 7 ] = c3.g; + colorArray[ offset_color + 8 ] = c3.b; + + offset_color += 9; + + } + + for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces4[ f ] ]; + + vertexColors = face.vertexColors; + faceColor = face.color; + + if ( vertexColors.length === 4 && vertexColorType === THREE.VertexColors ) { + + c1 = vertexColors[ 0 ]; + c2 = vertexColors[ 1 ]; + c3 = vertexColors[ 2 ]; + c4 = vertexColors[ 3 ]; + + } else { + + c1 = faceColor; + c2 = faceColor; + c3 = faceColor; + c4 = faceColor; + + } + + colorArray[ offset_color ] = c1.r; + colorArray[ offset_color + 1 ] = c1.g; + colorArray[ offset_color + 2 ] = c1.b; + + colorArray[ offset_color + 3 ] = c2.r; + colorArray[ offset_color + 4 ] = c2.g; + colorArray[ offset_color + 5 ] = c2.b; + + colorArray[ offset_color + 6 ] = c3.r; + colorArray[ offset_color + 7 ] = c3.g; + colorArray[ offset_color + 8 ] = c3.b; + + colorArray[ offset_color + 9 ] = c4.r; + colorArray[ offset_color + 10 ] = c4.g; + colorArray[ offset_color + 11 ] = c4.b; + + offset_color += 12; + + } + + if ( offset_color > 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint ); + + } + + } + + if ( dirtyTangents && geometry.hasTangents ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces3[ f ] ]; + + vertexTangents = face.vertexTangents; + + t1 = vertexTangents[ 0 ]; + t2 = vertexTangents[ 1 ]; + t3 = vertexTangents[ 2 ]; + + tangentArray[ offset_tangent ] = t1.x; + tangentArray[ offset_tangent + 1 ] = t1.y; + tangentArray[ offset_tangent + 2 ] = t1.z; + tangentArray[ offset_tangent + 3 ] = t1.w; + + tangentArray[ offset_tangent + 4 ] = t2.x; + tangentArray[ offset_tangent + 5 ] = t2.y; + tangentArray[ offset_tangent + 6 ] = t2.z; + tangentArray[ offset_tangent + 7 ] = t2.w; + + tangentArray[ offset_tangent + 8 ] = t3.x; + tangentArray[ offset_tangent + 9 ] = t3.y; + tangentArray[ offset_tangent + 10 ] = t3.z; + tangentArray[ offset_tangent + 11 ] = t3.w; + + offset_tangent += 12; + + } + + for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces4[ f ] ]; + + vertexTangents = face.vertexTangents; + + t1 = vertexTangents[ 0 ]; + t2 = vertexTangents[ 1 ]; + t3 = vertexTangents[ 2 ]; + t4 = vertexTangents[ 3 ]; + + tangentArray[ offset_tangent ] = t1.x; + tangentArray[ offset_tangent + 1 ] = t1.y; + tangentArray[ offset_tangent + 2 ] = t1.z; + tangentArray[ offset_tangent + 3 ] = t1.w; + + tangentArray[ offset_tangent + 4 ] = t2.x; + tangentArray[ offset_tangent + 5 ] = t2.y; + tangentArray[ offset_tangent + 6 ] = t2.z; + tangentArray[ offset_tangent + 7 ] = t2.w; + + tangentArray[ offset_tangent + 8 ] = t3.x; + tangentArray[ offset_tangent + 9 ] = t3.y; + tangentArray[ offset_tangent + 10 ] = t3.z; + tangentArray[ offset_tangent + 11 ] = t3.w; + + tangentArray[ offset_tangent + 12 ] = t4.x; + tangentArray[ offset_tangent + 13 ] = t4.y; + tangentArray[ offset_tangent + 14 ] = t4.z; + tangentArray[ offset_tangent + 15 ] = t4.w; + + offset_tangent += 16; + + } + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, tangentArray, hint ); + + } + + if ( dirtyNormals && normalType ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces3[ f ] ]; + + vertexNormals = face.vertexNormals; + faceNormal = face.normal; + + if ( vertexNormals.length === 3 && needsSmoothNormals ) { + + for ( i = 0; i < 3; i ++ ) { + + vn = vertexNormals[ i ]; + + normalArray[ offset_normal ] = vn.x; + normalArray[ offset_normal + 1 ] = vn.y; + normalArray[ offset_normal + 2 ] = vn.z; + + offset_normal += 3; + + } + + } else { + + for ( i = 0; i < 3; i ++ ) { + + normalArray[ offset_normal ] = faceNormal.x; + normalArray[ offset_normal + 1 ] = faceNormal.y; + normalArray[ offset_normal + 2 ] = faceNormal.z; + + offset_normal += 3; + + } + + } + + } + + for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces4[ f ] ]; + + vertexNormals = face.vertexNormals; + faceNormal = face.normal; + + if ( vertexNormals.length === 4 && needsSmoothNormals ) { + + for ( i = 0; i < 4; i ++ ) { + + vn = vertexNormals[ i ]; + + normalArray[ offset_normal ] = vn.x; + normalArray[ offset_normal + 1 ] = vn.y; + normalArray[ offset_normal + 2 ] = vn.z; + + offset_normal += 3; + + } + + } else { + + for ( i = 0; i < 4; i ++ ) { + + normalArray[ offset_normal ] = faceNormal.x; + normalArray[ offset_normal + 1 ] = faceNormal.y; + normalArray[ offset_normal + 2 ] = faceNormal.z; + + offset_normal += 3; + + } + + } + + } + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, normalArray, hint ); + + } + + if ( dirtyUvs && obj_uvs && uvType ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + fi = chunk_faces3[ f ]; + + uv = obj_uvs[ fi ]; + + if ( uv === undefined ) continue; + + for ( i = 0; i < 3; i ++ ) { + + uvi = uv[ i ]; + + uvArray[ offset_uv ] = uvi.x; + uvArray[ offset_uv + 1 ] = uvi.y; + + offset_uv += 2; + + } + + } + + for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) { + + fi = chunk_faces4[ f ]; + + uv = obj_uvs[ fi ]; + + if ( uv === undefined ) continue; + + for ( i = 0; i < 4; i ++ ) { + + uvi = uv[ i ]; + + uvArray[ offset_uv ] = uvi.x; + uvArray[ offset_uv + 1 ] = uvi.y; + + offset_uv += 2; + + } + + } + + if ( offset_uv > 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, uvArray, hint ); + + } + + } + + if ( dirtyUvs && obj_uvs2 && uvType ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + fi = chunk_faces3[ f ]; + + uv2 = obj_uvs2[ fi ]; + + if ( uv2 === undefined ) continue; + + for ( i = 0; i < 3; i ++ ) { + + uv2i = uv2[ i ]; + + uv2Array[ offset_uv2 ] = uv2i.x; + uv2Array[ offset_uv2 + 1 ] = uv2i.y; + + offset_uv2 += 2; + + } + + } + + for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) { + + fi = chunk_faces4[ f ]; + + uv2 = obj_uvs2[ fi ]; + + if ( uv2 === undefined ) continue; + + for ( i = 0; i < 4; i ++ ) { + + uv2i = uv2[ i ]; + + uv2Array[ offset_uv2 ] = uv2i.x; + uv2Array[ offset_uv2 + 1 ] = uv2i.y; + + offset_uv2 += 2; + + } + + } + + if ( offset_uv2 > 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, uv2Array, hint ); + + } + + } + + if ( dirtyElements ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + faceArray[ offset_face ] = vertexIndex; + faceArray[ offset_face + 1 ] = vertexIndex + 1; + faceArray[ offset_face + 2 ] = vertexIndex + 2; + + offset_face += 3; + + lineArray[ offset_line ] = vertexIndex; + lineArray[ offset_line + 1 ] = vertexIndex + 1; + + lineArray[ offset_line + 2 ] = vertexIndex; + lineArray[ offset_line + 3 ] = vertexIndex + 2; + + lineArray[ offset_line + 4 ] = vertexIndex + 1; + lineArray[ offset_line + 5 ] = vertexIndex + 2; + + offset_line += 6; + + vertexIndex += 3; + + } + + for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) { + + faceArray[ offset_face ] = vertexIndex; + faceArray[ offset_face + 1 ] = vertexIndex + 1; + faceArray[ offset_face + 2 ] = vertexIndex + 3; + + faceArray[ offset_face + 3 ] = vertexIndex + 1; + faceArray[ offset_face + 4 ] = vertexIndex + 2; + faceArray[ offset_face + 5 ] = vertexIndex + 3; + + offset_face += 6; + + lineArray[ offset_line ] = vertexIndex; + lineArray[ offset_line + 1 ] = vertexIndex + 1; + + lineArray[ offset_line + 2 ] = vertexIndex; + lineArray[ offset_line + 3 ] = vertexIndex + 3; + + lineArray[ offset_line + 4 ] = vertexIndex + 1; + lineArray[ offset_line + 5 ] = vertexIndex + 2; + + lineArray[ offset_line + 6 ] = vertexIndex + 2; + lineArray[ offset_line + 7 ] = vertexIndex + 3; + + offset_line += 8; + + vertexIndex += 4; + + } + + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer ); + _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, faceArray, hint ); + + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer ); + _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, lineArray, hint ); + + } + + if ( customAttributes ) { + + for ( i = 0, il = customAttributes.length; i < il; i ++ ) { + + customAttribute = customAttributes[ i ]; + + if ( ! customAttribute.__original.needsUpdate ) continue; + + offset_custom = 0; + offset_customSrc = 0; + + if ( customAttribute.size === 1 ) { + + if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces3[ f ] ]; + + customAttribute.array[ offset_custom ] = customAttribute.value[ face.a ]; + customAttribute.array[ offset_custom + 1 ] = customAttribute.value[ face.b ]; + customAttribute.array[ offset_custom + 2 ] = customAttribute.value[ face.c ]; + + offset_custom += 3; + + } + + for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces4[ f ] ]; + + customAttribute.array[ offset_custom ] = customAttribute.value[ face.a ]; + customAttribute.array[ offset_custom + 1 ] = customAttribute.value[ face.b ]; + customAttribute.array[ offset_custom + 2 ] = customAttribute.value[ face.c ]; + customAttribute.array[ offset_custom + 3 ] = customAttribute.value[ face.d ]; + + offset_custom += 4; + + } + + } else if ( customAttribute.boundTo === "faces" ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + value = customAttribute.value[ chunk_faces3[ f ] ]; + + customAttribute.array[ offset_custom ] = value; + customAttribute.array[ offset_custom + 1 ] = value; + customAttribute.array[ offset_custom + 2 ] = value; + + offset_custom += 3; + + } + + for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) { + + value = customAttribute.value[ chunk_faces4[ f ] ]; + + customAttribute.array[ offset_custom ] = value; + customAttribute.array[ offset_custom + 1 ] = value; + customAttribute.array[ offset_custom + 2 ] = value; + customAttribute.array[ offset_custom + 3 ] = value; + + offset_custom += 4; + + } + + } + + } else if ( customAttribute.size === 2 ) { + + if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces3[ f ] ]; + + v1 = customAttribute.value[ face.a ]; + v2 = customAttribute.value[ face.b ]; + v3 = customAttribute.value[ face.c ]; + + customAttribute.array[ offset_custom ] = v1.x; + customAttribute.array[ offset_custom + 1 ] = v1.y; + + customAttribute.array[ offset_custom + 2 ] = v2.x; + customAttribute.array[ offset_custom + 3 ] = v2.y; + + customAttribute.array[ offset_custom + 4 ] = v3.x; + customAttribute.array[ offset_custom + 5 ] = v3.y; + + offset_custom += 6; + + } + + for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces4[ f ] ]; + + v1 = customAttribute.value[ face.a ]; + v2 = customAttribute.value[ face.b ]; + v3 = customAttribute.value[ face.c ]; + v4 = customAttribute.value[ face.d ]; + + customAttribute.array[ offset_custom ] = v1.x; + customAttribute.array[ offset_custom + 1 ] = v1.y; + + customAttribute.array[ offset_custom + 2 ] = v2.x; + customAttribute.array[ offset_custom + 3 ] = v2.y; + + customAttribute.array[ offset_custom + 4 ] = v3.x; + customAttribute.array[ offset_custom + 5 ] = v3.y; + + customAttribute.array[ offset_custom + 6 ] = v4.x; + customAttribute.array[ offset_custom + 7 ] = v4.y; + + offset_custom += 8; + + } + + } else if ( customAttribute.boundTo === "faces" ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + value = customAttribute.value[ chunk_faces3[ f ] ]; + + v1 = value; + v2 = value; + v3 = value; + + customAttribute.array[ offset_custom ] = v1.x; + customAttribute.array[ offset_custom + 1 ] = v1.y; + + customAttribute.array[ offset_custom + 2 ] = v2.x; + customAttribute.array[ offset_custom + 3 ] = v2.y; + + customAttribute.array[ offset_custom + 4 ] = v3.x; + customAttribute.array[ offset_custom + 5 ] = v3.y; + + offset_custom += 6; + + } + + for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) { + + value = customAttribute.value[ chunk_faces4[ f ] ]; + + v1 = value; + v2 = value; + v3 = value; + v4 = value; + + customAttribute.array[ offset_custom ] = v1.x; + customAttribute.array[ offset_custom + 1 ] = v1.y; + + customAttribute.array[ offset_custom + 2 ] = v2.x; + customAttribute.array[ offset_custom + 3 ] = v2.y; + + customAttribute.array[ offset_custom + 4 ] = v3.x; + customAttribute.array[ offset_custom + 5 ] = v3.y; + + customAttribute.array[ offset_custom + 6 ] = v4.x; + customAttribute.array[ offset_custom + 7 ] = v4.y; + + offset_custom += 8; + + } + + } + + } else if ( customAttribute.size === 3 ) { + + var pp; + + if ( customAttribute.type === "c" ) { + + pp = [ "r", "g", "b" ]; + + } else { + + pp = [ "x", "y", "z" ]; + + } + + if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces3[ f ] ]; + + v1 = customAttribute.value[ face.a ]; + v2 = customAttribute.value[ face.b ]; + v3 = customAttribute.value[ face.c ]; + + customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ]; + + customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ]; + + customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ]; + + offset_custom += 9; + + } + + for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces4[ f ] ]; + + v1 = customAttribute.value[ face.a ]; + v2 = customAttribute.value[ face.b ]; + v3 = customAttribute.value[ face.c ]; + v4 = customAttribute.value[ face.d ]; + + customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ]; + + customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ]; + + customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ]; + + customAttribute.array[ offset_custom + 9 ] = v4[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 10 ] = v4[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 11 ] = v4[ pp[ 2 ] ]; + + offset_custom += 12; + + } + + } else if ( customAttribute.boundTo === "faces" ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + value = customAttribute.value[ chunk_faces3[ f ] ]; + + v1 = value; + v2 = value; + v3 = value; + + customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ]; + + customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ]; + + customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ]; + + offset_custom += 9; + + } + + for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) { + + value = customAttribute.value[ chunk_faces4[ f ] ]; + + v1 = value; + v2 = value; + v3 = value; + v4 = value; + + customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ]; + + customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ]; + + customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ]; + + customAttribute.array[ offset_custom + 9 ] = v4[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 10 ] = v4[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 11 ] = v4[ pp[ 2 ] ]; + + offset_custom += 12; + + } + + } else if ( customAttribute.boundTo === "faceVertices" ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + value = customAttribute.value[ chunk_faces3[ f ] ]; + + v1 = value[ 0 ]; + v2 = value[ 1 ]; + v3 = value[ 2 ]; + + customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ]; + + customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ]; + + customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ]; + + offset_custom += 9; + + } + + for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) { + + value = customAttribute.value[ chunk_faces4[ f ] ]; + + v1 = value[ 0 ]; + v2 = value[ 1 ]; + v3 = value[ 2 ]; + v4 = value[ 3 ]; + + customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ]; + + customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ]; + + customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ]; + + customAttribute.array[ offset_custom + 9 ] = v4[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 10 ] = v4[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 11 ] = v4[ pp[ 2 ] ]; + + offset_custom += 12; + + } + + } + + } else if ( customAttribute.size === 4 ) { + + if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces3[ f ] ]; + + v1 = customAttribute.value[ face.a ]; + v2 = customAttribute.value[ face.b ]; + v3 = customAttribute.value[ face.c ]; + + customAttribute.array[ offset_custom ] = v1.x; + customAttribute.array[ offset_custom + 1 ] = v1.y; + customAttribute.array[ offset_custom + 2 ] = v1.z; + customAttribute.array[ offset_custom + 3 ] = v1.w; + + customAttribute.array[ offset_custom + 4 ] = v2.x; + customAttribute.array[ offset_custom + 5 ] = v2.y; + customAttribute.array[ offset_custom + 6 ] = v2.z; + customAttribute.array[ offset_custom + 7 ] = v2.w; + + customAttribute.array[ offset_custom + 8 ] = v3.x; + customAttribute.array[ offset_custom + 9 ] = v3.y; + customAttribute.array[ offset_custom + 10 ] = v3.z; + customAttribute.array[ offset_custom + 11 ] = v3.w; + + offset_custom += 12; + + } + + for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces4[ f ] ]; + + v1 = customAttribute.value[ face.a ]; + v2 = customAttribute.value[ face.b ]; + v3 = customAttribute.value[ face.c ]; + v4 = customAttribute.value[ face.d ]; + + customAttribute.array[ offset_custom ] = v1.x; + customAttribute.array[ offset_custom + 1 ] = v1.y; + customAttribute.array[ offset_custom + 2 ] = v1.z; + customAttribute.array[ offset_custom + 3 ] = v1.w; + + customAttribute.array[ offset_custom + 4 ] = v2.x; + customAttribute.array[ offset_custom + 5 ] = v2.y; + customAttribute.array[ offset_custom + 6 ] = v2.z; + customAttribute.array[ offset_custom + 7 ] = v2.w; + + customAttribute.array[ offset_custom + 8 ] = v3.x; + customAttribute.array[ offset_custom + 9 ] = v3.y; + customAttribute.array[ offset_custom + 10 ] = v3.z; + customAttribute.array[ offset_custom + 11 ] = v3.w; + + customAttribute.array[ offset_custom + 12 ] = v4.x; + customAttribute.array[ offset_custom + 13 ] = v4.y; + customAttribute.array[ offset_custom + 14 ] = v4.z; + customAttribute.array[ offset_custom + 15 ] = v4.w; + + offset_custom += 16; + + } + + } else if ( customAttribute.boundTo === "faces" ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + value = customAttribute.value[ chunk_faces3[ f ] ]; + + v1 = value; + v2 = value; + v3 = value; + + customAttribute.array[ offset_custom ] = v1.x; + customAttribute.array[ offset_custom + 1 ] = v1.y; + customAttribute.array[ offset_custom + 2 ] = v1.z; + customAttribute.array[ offset_custom + 3 ] = v1.w; + + customAttribute.array[ offset_custom + 4 ] = v2.x; + customAttribute.array[ offset_custom + 5 ] = v2.y; + customAttribute.array[ offset_custom + 6 ] = v2.z; + customAttribute.array[ offset_custom + 7 ] = v2.w; + + customAttribute.array[ offset_custom + 8 ] = v3.x; + customAttribute.array[ offset_custom + 9 ] = v3.y; + customAttribute.array[ offset_custom + 10 ] = v3.z; + customAttribute.array[ offset_custom + 11 ] = v3.w; + + offset_custom += 12; + + } + + for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) { + + value = customAttribute.value[ chunk_faces4[ f ] ]; + + v1 = value; + v2 = value; + v3 = value; + v4 = value; + + customAttribute.array[ offset_custom ] = v1.x; + customAttribute.array[ offset_custom + 1 ] = v1.y; + customAttribute.array[ offset_custom + 2 ] = v1.z; + customAttribute.array[ offset_custom + 3 ] = v1.w; + + customAttribute.array[ offset_custom + 4 ] = v2.x; + customAttribute.array[ offset_custom + 5 ] = v2.y; + customAttribute.array[ offset_custom + 6 ] = v2.z; + customAttribute.array[ offset_custom + 7 ] = v2.w; + + customAttribute.array[ offset_custom + 8 ] = v3.x; + customAttribute.array[ offset_custom + 9 ] = v3.y; + customAttribute.array[ offset_custom + 10 ] = v3.z; + customAttribute.array[ offset_custom + 11 ] = v3.w; + + customAttribute.array[ offset_custom + 12 ] = v4.x; + customAttribute.array[ offset_custom + 13 ] = v4.y; + customAttribute.array[ offset_custom + 14 ] = v4.z; + customAttribute.array[ offset_custom + 15 ] = v4.w; + + offset_custom += 16; + + } + + } else if ( customAttribute.boundTo === "faceVertices" ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + value = customAttribute.value[ chunk_faces3[ f ] ]; + + v1 = value[ 0 ]; + v2 = value[ 1 ]; + v3 = value[ 2 ]; + + customAttribute.array[ offset_custom ] = v1.x; + customAttribute.array[ offset_custom + 1 ] = v1.y; + customAttribute.array[ offset_custom + 2 ] = v1.z; + customAttribute.array[ offset_custom + 3 ] = v1.w; + + customAttribute.array[ offset_custom + 4 ] = v2.x; + customAttribute.array[ offset_custom + 5 ] = v2.y; + customAttribute.array[ offset_custom + 6 ] = v2.z; + customAttribute.array[ offset_custom + 7 ] = v2.w; + + customAttribute.array[ offset_custom + 8 ] = v3.x; + customAttribute.array[ offset_custom + 9 ] = v3.y; + customAttribute.array[ offset_custom + 10 ] = v3.z; + customAttribute.array[ offset_custom + 11 ] = v3.w; + + offset_custom += 12; + + } + + for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) { + + value = customAttribute.value[ chunk_faces4[ f ] ]; + + v1 = value[ 0 ]; + v2 = value[ 1 ]; + v3 = value[ 2 ]; + v4 = value[ 3 ]; + + customAttribute.array[ offset_custom ] = v1.x; + customAttribute.array[ offset_custom + 1 ] = v1.y; + customAttribute.array[ offset_custom + 2 ] = v1.z; + customAttribute.array[ offset_custom + 3 ] = v1.w; + + customAttribute.array[ offset_custom + 4 ] = v2.x; + customAttribute.array[ offset_custom + 5 ] = v2.y; + customAttribute.array[ offset_custom + 6 ] = v2.z; + customAttribute.array[ offset_custom + 7 ] = v2.w; + + customAttribute.array[ offset_custom + 8 ] = v3.x; + customAttribute.array[ offset_custom + 9 ] = v3.y; + customAttribute.array[ offset_custom + 10 ] = v3.z; + customAttribute.array[ offset_custom + 11 ] = v3.w; + + customAttribute.array[ offset_custom + 12 ] = v4.x; + customAttribute.array[ offset_custom + 13 ] = v4.y; + customAttribute.array[ offset_custom + 14 ] = v4.z; + customAttribute.array[ offset_custom + 15 ] = v4.w; + + offset_custom += 16; + + } + + } + + } + + _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint ); + + } + + } + + if ( dispose ) { + + delete geometryGroup.__inittedArrays; + delete geometryGroup.__colorArray; + delete geometryGroup.__normalArray; + delete geometryGroup.__tangentArray; + delete geometryGroup.__uvArray; + delete geometryGroup.__uv2Array; + delete geometryGroup.__faceArray; + delete geometryGroup.__vertexArray; + delete geometryGroup.__lineArray; + delete geometryGroup.__skinIndexArray; + delete geometryGroup.__skinWeightArray; + + } + + }; + + function setDirectBuffers ( geometry, hint, dispose ) { + + var attributes = geometry.attributes; + + var index = attributes[ "index" ]; + var position = attributes[ "position" ]; + var normal = attributes[ "normal" ]; + var uv = attributes[ "uv" ]; + var color = attributes[ "color" ]; + var tangent = attributes[ "tangent" ]; + + if ( geometry.elementsNeedUpdate && index !== undefined ) { + + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); + _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, index.array, hint ); + + } + + if ( geometry.verticesNeedUpdate && position !== undefined ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, position.buffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, position.array, hint ); + + } + + if ( geometry.normalsNeedUpdate && normal !== undefined ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, normal.buffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, normal.array, hint ); + + } + + if ( geometry.uvsNeedUpdate && uv !== undefined ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, uv.buffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, uv.array, hint ); + + } + + if ( geometry.colorsNeedUpdate && color !== undefined ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, color.buffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, color.array, hint ); + + } + + if ( geometry.tangentsNeedUpdate && tangent !== undefined ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, tangent.buffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, tangent.array, hint ); + + } + + if ( dispose ) { + + for ( var i in geometry.attributes ) { + + delete geometry.attributes[ i ].array; + + } + + } + + }; + + // Buffer rendering + + this.renderBufferImmediate = function ( object, program, material ) { + + if ( object.hasPositions && ! object.__webglVertexBuffer ) object.__webglVertexBuffer = _gl.createBuffer(); + if ( object.hasNormals && ! object.__webglNormalBuffer ) object.__webglNormalBuffer = _gl.createBuffer(); + if ( object.hasUvs && ! object.__webglUvBuffer ) object.__webglUvBuffer = _gl.createBuffer(); + if ( object.hasColors && ! object.__webglColorBuffer ) object.__webglColorBuffer = _gl.createBuffer(); + + if ( object.hasPositions ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglVertexBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW ); + _gl.enableVertexAttribArray( program.attributes.position ); + _gl.vertexAttribPointer( program.attributes.position, 3, _gl.FLOAT, false, 0, 0 ); + + } + + if ( object.hasNormals ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglNormalBuffer ); + + if ( material.shading === THREE.FlatShading ) { + + var nx, ny, nz, + nax, nbx, ncx, nay, nby, ncy, naz, nbz, ncz, + normalArray, + i, il = object.count * 3; + + for( i = 0; i < il; i += 9 ) { + + normalArray = object.normalArray; + + nax = normalArray[ i ]; + nay = normalArray[ i + 1 ]; + naz = normalArray[ i + 2 ]; + + nbx = normalArray[ i + 3 ]; + nby = normalArray[ i + 4 ]; + nbz = normalArray[ i + 5 ]; + + ncx = normalArray[ i + 6 ]; + ncy = normalArray[ i + 7 ]; + ncz = normalArray[ i + 8 ]; + + nx = ( nax + nbx + ncx ) / 3; + ny = ( nay + nby + ncy ) / 3; + nz = ( naz + nbz + ncz ) / 3; + + normalArray[ i ] = nx; + normalArray[ i + 1 ] = ny; + normalArray[ i + 2 ] = nz; + + normalArray[ i + 3 ] = nx; + normalArray[ i + 4 ] = ny; + normalArray[ i + 5 ] = nz; + + normalArray[ i + 6 ] = nx; + normalArray[ i + 7 ] = ny; + normalArray[ i + 8 ] = nz; + + } + + } + + _gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW ); + _gl.enableVertexAttribArray( program.attributes.normal ); + _gl.vertexAttribPointer( program.attributes.normal, 3, _gl.FLOAT, false, 0, 0 ); + + } + + if ( object.hasUvs && material.map ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglUvBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW ); + _gl.enableVertexAttribArray( program.attributes.uv ); + _gl.vertexAttribPointer( program.attributes.uv, 2, _gl.FLOAT, false, 0, 0 ); + + } + + if ( object.hasColors && material.vertexColors !== THREE.NoColors ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglColorBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW ); + _gl.enableVertexAttribArray( program.attributes.color ); + _gl.vertexAttribPointer( program.attributes.color, 3, _gl.FLOAT, false, 0, 0 ); + + } + + _gl.drawArrays( _gl.TRIANGLES, 0, object.count ); + + object.count = 0; + + }; + + this.renderBufferDirect = function ( camera, lights, fog, material, geometry, object ) { + + if ( material.visible === false ) return; + + var program, attributes, linewidth, primitives, a, attribute; + + program = setProgram( camera, lights, fog, material, object ); + + attributes = program.attributes; + + var updateBuffers = false, + wireframeBit = material.wireframe ? 1 : 0, + geometryHash = ( geometry.id * 0xffffff ) + ( program.id * 2 ) + wireframeBit; + + if ( geometryHash !== _currentGeometryGroupHash ) { + + _currentGeometryGroupHash = geometryHash; + updateBuffers = true; + + } + + if ( updateBuffers ) { + + disableAttributes(); + + } + + // render mesh + + if ( object instanceof THREE.Mesh ) { + + var index = geometry.attributes[ "index" ]; + + // indexed triangles + + if ( index ) { + + var offsets = geometry.offsets; + + // if there is more than 1 chunk + // must set attribute pointers to use new offsets for each chunk + // even if geometry and materials didn't change + + if ( offsets.length > 1 ) updateBuffers = true; + + for ( var i = 0, il = offsets.length; i < il; i ++ ) { + + var startIndex = offsets[ i ].index; + + if ( updateBuffers ) { + + // vertices + + var position = geometry.attributes[ "position" ]; + var positionSize = position.itemSize; + + _gl.bindBuffer( _gl.ARRAY_BUFFER, position.buffer ); + enableAttribute( attributes.position ); + _gl.vertexAttribPointer( attributes.position, positionSize, _gl.FLOAT, false, 0, startIndex * positionSize * 4 ); // 4 bytes per Float32 + + // normals + + var normal = geometry.attributes[ "normal" ]; + + if ( attributes.normal >= 0 && normal ) { + + var normalSize = normal.itemSize; + + _gl.bindBuffer( _gl.ARRAY_BUFFER, normal.buffer ); + enableAttribute( attributes.normal ); + _gl.vertexAttribPointer( attributes.normal, normalSize, _gl.FLOAT, false, 0, startIndex * normalSize * 4 ); + + } + + // uvs + + var uv = geometry.attributes[ "uv" ]; + + if ( attributes.uv >= 0 && uv ) { + + var uvSize = uv.itemSize; + + _gl.bindBuffer( _gl.ARRAY_BUFFER, uv.buffer ); + enableAttribute( attributes.uv ); + _gl.vertexAttribPointer( attributes.uv, uvSize, _gl.FLOAT, false, 0, startIndex * uvSize * 4 ); + + } + + // colors + + var color = geometry.attributes[ "color" ]; + + if ( attributes.color >= 0 && color ) { + + var colorSize = color.itemSize; + + _gl.bindBuffer( _gl.ARRAY_BUFFER, color.buffer ); + enableAttribute( attributes.color ); + _gl.vertexAttribPointer( attributes.color, colorSize, _gl.FLOAT, false, 0, startIndex * colorSize * 4 ); + + } + + // tangents + + var tangent = geometry.attributes[ "tangent" ]; + + if ( attributes.tangent >= 0 && tangent ) { + + var tangentSize = tangent.itemSize; + + _gl.bindBuffer( _gl.ARRAY_BUFFER, tangent.buffer ); + enableAttribute( attributes.tangent ); + _gl.vertexAttribPointer( attributes.tangent, tangentSize, _gl.FLOAT, false, 0, startIndex * tangentSize * 4 ); + + } + + // indices + + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); + + } + + // render indexed triangles + + _gl.drawElements( _gl.TRIANGLES, offsets[ i ].count, _gl.UNSIGNED_SHORT, offsets[ i ].start * 2 ); // 2 bytes per Uint16 + + _this.info.render.calls ++; + _this.info.render.vertices += offsets[ i ].count; // not really true, here vertices can be shared + _this.info.render.faces += offsets[ i ].count / 3; + + } + + // non-indexed triangles + + } else { + + if ( updateBuffers ) { + + // vertices + + var position = geometry.attributes[ "position" ]; + var positionSize = position.itemSize; + + _gl.bindBuffer( _gl.ARRAY_BUFFER, position.buffer ); + enableAttribute( attributes.position ); + _gl.vertexAttribPointer( attributes.position, positionSize, _gl.FLOAT, false, 0, 0 ); + + // normals + + var normal = geometry.attributes[ "normal" ]; + + if ( attributes.normal >= 0 && normal ) { + + var normalSize = normal.itemSize; + + _gl.bindBuffer( _gl.ARRAY_BUFFER, normal.buffer ); + enableAttribute( attributes.normal ); + _gl.vertexAttribPointer( attributes.normal, normalSize, _gl.FLOAT, false, 0, 0 ); + + } + + // uvs + + var uv = geometry.attributes[ "uv" ]; + + if ( attributes.uv >= 0 && uv ) { + + var uvSize = uv.itemSize; + + _gl.bindBuffer( _gl.ARRAY_BUFFER, uv.buffer ); + enableAttribute( attributes.uv ); + _gl.vertexAttribPointer( attributes.uv, uvSize, _gl.FLOAT, false, 0, 0 ); + + } + + // colors + + var color = geometry.attributes[ "color" ]; + + if ( attributes.color >= 0 && color ) { + + var colorSize = color.itemSize; + + _gl.bindBuffer( _gl.ARRAY_BUFFER, color.buffer ); + enableAttribute( attributes.color ); + _gl.vertexAttribPointer( attributes.color, colorSize, _gl.FLOAT, false, 0, 0 ); + + } + + // tangents + + var tangent = geometry.attributes[ "tangent" ]; + + if ( attributes.tangent >= 0 && tangent ) { + + var tangentSize = tangent.itemSize; + + _gl.bindBuffer( _gl.ARRAY_BUFFER, tangent.buffer ); + enableAttribute( attributes.tangent ); + _gl.vertexAttribPointer( attributes.tangent, tangentSize, _gl.FLOAT, false, 0, 0 ); + + } + + } + + // render non-indexed triangles + + _gl.drawArrays( _gl.TRIANGLES, 0, position.numItems / 3 ); + + _this.info.render.calls ++; + _this.info.render.vertices += position.numItems / 3; + _this.info.render.faces += position.numItems / 3 / 3; + + } + + // render particles + + } else if ( object instanceof THREE.ParticleSystem ) { + + if ( updateBuffers ) { + + // vertices + + var position = geometry.attributes[ "position" ]; + var positionSize = position.itemSize; + + _gl.bindBuffer( _gl.ARRAY_BUFFER, position.buffer ); + enableAttribute( attributes.position ); + _gl.vertexAttribPointer( attributes.position, positionSize, _gl.FLOAT, false, 0, 0 ); + + // colors + + var color = geometry.attributes[ "color" ]; + + if ( attributes.color >= 0 && color ) { + + var colorSize = color.itemSize; + + _gl.bindBuffer( _gl.ARRAY_BUFFER, color.buffer ); + enableAttribute( attributes.color ); + _gl.vertexAttribPointer( attributes.color, colorSize, _gl.FLOAT, false, 0, 0 ); + + } + + // render particles + + _gl.drawArrays( _gl.POINTS, 0, position.numItems / 3 ); + + _this.info.render.calls ++; + _this.info.render.points += position.numItems / 3; + + } + + } else if ( object instanceof THREE.Line ) { + + if ( updateBuffers ) { + + // vertices + + var position = geometry.attributes[ "position" ]; + var positionSize = position.itemSize; + + _gl.bindBuffer( _gl.ARRAY_BUFFER, position.buffer ); + enableAttribute( attributes.position ); + _gl.vertexAttribPointer( attributes.position, positionSize, _gl.FLOAT, false, 0, 0 ); + + // colors + + var color = geometry.attributes[ "color" ]; + + if ( attributes.color >= 0 && color ) { + + var colorSize = color.itemSize; + + _gl.bindBuffer( _gl.ARRAY_BUFFER, color.buffer ); + enableAttribute( attributes.color ); + _gl.vertexAttribPointer( attributes.color, colorSize, _gl.FLOAT, false, 0, 0 ); + + } + + // render lines + + setLineWidth( material.linewidth ); + + _gl.drawArrays( _gl.LINE_STRIP, 0, position.numItems / 3 ); + + _this.info.render.calls ++; + _this.info.render.points += position.numItems; + + } + + } + + }; + + this.renderBuffer = function ( camera, lights, fog, material, geometryGroup, object ) { + + if ( material.visible === false ) return; + + var program, attributes, linewidth, primitives, a, attribute, i, il; + + program = setProgram( camera, lights, fog, material, object ); + + attributes = program.attributes; + + var updateBuffers = false, + wireframeBit = material.wireframe ? 1 : 0, + geometryGroupHash = ( geometryGroup.id * 0xffffff ) + ( program.id * 2 ) + wireframeBit; + + if ( geometryGroupHash !== _currentGeometryGroupHash ) { + + _currentGeometryGroupHash = geometryGroupHash; + updateBuffers = true; + + } + + if ( updateBuffers ) { + + disableAttributes(); + + } + + // vertices + + if ( !material.morphTargets && attributes.position >= 0 ) { + + if ( updateBuffers ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer ); + enableAttribute( attributes.position ); + _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); + + } + + } else { + + if ( object.morphTargetBase ) { + + setupMorphTargets( material, geometryGroup, object ); + + } + + } + + + if ( updateBuffers ) { + + // custom attributes + + // Use the per-geometryGroup custom attribute arrays which are setup in initMeshBuffers + + if ( geometryGroup.__webglCustomAttributesList ) { + + for ( i = 0, il = geometryGroup.__webglCustomAttributesList.length; i < il; i ++ ) { + + attribute = geometryGroup.__webglCustomAttributesList[ i ]; + + if ( attributes[ attribute.buffer.belongsToAttribute ] >= 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, attribute.buffer ); + enableAttribute( attributes[ attribute.buffer.belongsToAttribute ] ); + _gl.vertexAttribPointer( attributes[ attribute.buffer.belongsToAttribute ], attribute.size, _gl.FLOAT, false, 0, 0 ); + + } + + } + + } + + + // colors + + if ( attributes.color >= 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer ); + enableAttribute( attributes.color ); + _gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 ); + + } + + // normals + + if ( attributes.normal >= 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer ); + enableAttribute( attributes.normal ); + _gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 ); + + } + + // tangents + + if ( attributes.tangent >= 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer ); + enableAttribute( attributes.tangent ); + _gl.vertexAttribPointer( attributes.tangent, 4, _gl.FLOAT, false, 0, 0 ); + + } + + // uvs + + if ( attributes.uv >= 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer ); + enableAttribute( attributes.uv ); + _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 ); + + } + + if ( attributes.uv2 >= 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer ); + enableAttribute( attributes.uv2 ); + _gl.vertexAttribPointer( attributes.uv2, 2, _gl.FLOAT, false, 0, 0 ); + + } + + if ( material.skinning && + attributes.skinIndex >= 0 && attributes.skinWeight >= 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer ); + enableAttribute( attributes.skinIndex ); + _gl.vertexAttribPointer( attributes.skinIndex, 4, _gl.FLOAT, false, 0, 0 ); + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer ); + enableAttribute( attributes.skinWeight ); + _gl.vertexAttribPointer( attributes.skinWeight, 4, _gl.FLOAT, false, 0, 0 ); + + } + + // line distances + + if ( attributes.lineDistance >= 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglLineDistanceBuffer ); + enableAttribute( attributes.lineDistance ); + _gl.vertexAttribPointer( attributes.lineDistance, 1, _gl.FLOAT, false, 0, 0 ); + + } + + } + + // render mesh + + if ( object instanceof THREE.Mesh ) { + + // wireframe + + if ( material.wireframe ) { + + setLineWidth( material.wireframeLinewidth ); + + if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer ); + _gl.drawElements( _gl.LINES, geometryGroup.__webglLineCount, _gl.UNSIGNED_SHORT, 0 ); + + // triangles + + } else { + + if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer ); + _gl.drawElements( _gl.TRIANGLES, geometryGroup.__webglFaceCount, _gl.UNSIGNED_SHORT, 0 ); + + } + + _this.info.render.calls ++; + _this.info.render.vertices += geometryGroup.__webglFaceCount; + _this.info.render.faces += geometryGroup.__webglFaceCount / 3; + + // render lines + + } else if ( object instanceof THREE.Line ) { + + primitives = ( object.type === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES; + + setLineWidth( material.linewidth ); + + _gl.drawArrays( primitives, 0, geometryGroup.__webglLineCount ); + + _this.info.render.calls ++; + + // render particles + + } else if ( object instanceof THREE.ParticleSystem ) { + + _gl.drawArrays( _gl.POINTS, 0, geometryGroup.__webglParticleCount ); + + _this.info.render.calls ++; + _this.info.render.points += geometryGroup.__webglParticleCount; + + // render ribbon + + } else if ( object instanceof THREE.Ribbon ) { + + _gl.drawArrays( _gl.TRIANGLE_STRIP, 0, geometryGroup.__webglVertexCount ); + + _this.info.render.calls ++; + + } + + }; + + function enableAttribute( attribute ) { + + if ( ! _enabledAttributes[ attribute ] ) { + + _gl.enableVertexAttribArray( attribute ); + _enabledAttributes[ attribute ] = true; + + } + + }; + + function disableAttributes() { + + for ( var attribute in _enabledAttributes ) { + + if ( _enabledAttributes[ attribute ] ) { + + _gl.disableVertexAttribArray( attribute ); + _enabledAttributes[ attribute ] = false; + + } + + } + + }; + + function setupMorphTargets ( material, geometryGroup, object ) { + + // set base + + var attributes = material.program.attributes; + + if ( object.morphTargetBase !== -1 && attributes.position >= 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ object.morphTargetBase ] ); + enableAttribute( attributes.position ); + _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); + + } else if ( attributes.position >= 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer ); + enableAttribute( attributes.position ); + _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); + + } + + if ( object.morphTargetForcedOrder.length ) { + + // set forced order + + var m = 0; + var order = object.morphTargetForcedOrder; + var influences = object.morphTargetInfluences; + + while ( m < material.numSupportedMorphTargets && m < order.length ) { + + if ( attributes[ "morphTarget" + m ] >= 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ order[ m ] ] ); + enableAttribute( attributes[ "morphTarget" + m ] ); + _gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 ); + + } + + if ( attributes[ "morphNormal" + m ] >= 0 && material.morphNormals ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ order[ m ] ] ); + enableAttribute( attributes[ "morphNormal" + m ] ); + _gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 ); + + } + + object.__webglMorphTargetInfluences[ m ] = influences[ order[ m ] ]; + + m ++; + } + + } else { + + // find the most influencing + + var influence, activeInfluenceIndices = []; + var influences = object.morphTargetInfluences; + var i, il = influences.length; + + for ( i = 0; i < il; i ++ ) { + + influence = influences[ i ]; + + if ( influence > 0 ) { + + activeInfluenceIndices.push( [ influence, i ] ); + + } + + } + + if ( activeInfluenceIndices.length > material.numSupportedMorphTargets ) { + + activeInfluenceIndices.sort( numericalSort ); + activeInfluenceIndices.length = material.numSupportedMorphTargets; + + } else if ( activeInfluenceIndices.length > material.numSupportedMorphNormals ) { + + activeInfluenceIndices.sort( numericalSort ); + + } else if ( activeInfluenceIndices.length === 0 ) { + + activeInfluenceIndices.push( [ 0, 0 ] ); + + }; + + var influenceIndex, m = 0; + + while ( m < material.numSupportedMorphTargets ) { + + if ( activeInfluenceIndices[ m ] ) { + + influenceIndex = activeInfluenceIndices[ m ][ 1 ]; + + if ( attributes[ "morphTarget" + m ] >= 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ influenceIndex ] ); + enableAttribute( attributes[ "morphTarget" + m ] ); + _gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 ); + + } + + if ( attributes[ "morphNormal" + m ] >= 0 && material.morphNormals ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ influenceIndex ] ); + enableAttribute( attributes[ "morphNormal" + m ] ); + _gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 ); + + + } + + object.__webglMorphTargetInfluences[ m ] = influences[ influenceIndex ]; + + } else { + + /* + _gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 ); + + if ( material.morphNormals ) { + + _gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 ); + + } + */ + + object.__webglMorphTargetInfluences[ m ] = 0; + + } + + m ++; + + } + + } + + // load updated influences uniform + + if ( material.program.uniforms.morphTargetInfluences !== null ) { + + _gl.uniform1fv( material.program.uniforms.morphTargetInfluences, object.__webglMorphTargetInfluences ); + + } + + }; + + // Sorting + + function painterSortStable ( a, b ) { + + if ( a.z !== b.z ) { + + return b.z - a.z; + + } else { + + return b.id - a.id; + + } + + }; + + function numericalSort ( a, b ) { + + return b[ 0 ] - a[ 0 ]; + + }; + + + // Rendering + + this.render = function ( scene, camera, renderTarget, forceClear ) { + + if ( camera instanceof THREE.Camera === false ) { + + console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); + return; + + } + + var i, il, + + webglObject, object, + renderList, + + lights = scene.__lights, + fog = scene.fog; + + // reset caching for this frame + + _currentMaterialId = -1; + _lightsNeedUpdate = true; + + // update scene graph + + if ( this.autoUpdateScene ) scene.updateMatrixWorld(); + + // update camera matrices and frustum + + if ( camera.parent === undefined ) camera.updateMatrixWorld(); + + camera.matrixWorldInverse.getInverse( camera.matrixWorld ); + + _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); + _frustum.setFromMatrix( _projScreenMatrix ); + + // update WebGL objects + + if ( this.autoUpdateObjects ) this.initWebGLObjects( scene ); + + // custom render plugins (pre pass) + + renderPlugins( this.renderPluginsPre, scene, camera ); + + // + + _this.info.render.calls = 0; + _this.info.render.vertices = 0; + _this.info.render.faces = 0; + _this.info.render.points = 0; + + this.setRenderTarget( renderTarget ); + + if ( this.autoClear || forceClear ) { + + this.clear( this.autoClearColor, this.autoClearDepth, this.autoClearStencil ); + + } + + // set matrices for regular objects (frustum culled) + + renderList = scene.__webglObjects; + + for ( i = 0, il = renderList.length; i < il; i ++ ) { + + webglObject = renderList[ i ]; + object = webglObject.object; + + webglObject.render = false; + + if ( object.visible ) { + + if ( ! ( object instanceof THREE.Mesh || object instanceof THREE.ParticleSystem ) || ! ( object.frustumCulled ) || _frustum.intersectsObject( object ) ) { + + setupMatrices( object, camera ); + + unrollBufferMaterial( webglObject ); + + webglObject.render = true; + + if ( this.sortObjects === true ) { + + if ( object.renderDepth !== null ) { + + webglObject.z = object.renderDepth; + + } else { + + _vector3.getPositionFromMatrix( object.matrixWorld ); + _vector3.applyProjection( _projScreenMatrix ); + + webglObject.z = _vector3.z; + + } + + webglObject.id = object.id; + + } + + } + + } + + } + + if ( this.sortObjects ) { + + renderList.sort( painterSortStable ); + + } + + // set matrices for immediate objects + + renderList = scene.__webglObjectsImmediate; + + for ( i = 0, il = renderList.length; i < il; i ++ ) { + + webglObject = renderList[ i ]; + object = webglObject.object; + + if ( object.visible ) { + + setupMatrices( object, camera ); + + unrollImmediateBufferMaterial( webglObject ); + + } + + } + + if ( scene.overrideMaterial ) { + + var material = scene.overrideMaterial; + + this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); + this.setDepthTest( material.depthTest ); + this.setDepthWrite( material.depthWrite ); + setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); + + renderObjects( scene.__webglObjects, false, "", camera, lights, fog, true, material ); + renderObjectsImmediate( scene.__webglObjectsImmediate, "", camera, lights, fog, false, material ); + + } else { + + var material = null; + + // opaque pass (front-to-back order) + + this.setBlending( THREE.NoBlending ); + + renderObjects( scene.__webglObjects, true, "opaque", camera, lights, fog, false, material ); + renderObjectsImmediate( scene.__webglObjectsImmediate, "opaque", camera, lights, fog, false, material ); + + // transparent pass (back-to-front order) + + renderObjects( scene.__webglObjects, false, "transparent", camera, lights, fog, true, material ); + renderObjectsImmediate( scene.__webglObjectsImmediate, "transparent", camera, lights, fog, true, material ); + + } + + // custom render plugins (post pass) + + renderPlugins( this.renderPluginsPost, scene, camera ); + + + // Generate mipmap if we're using any kind of mipmap filtering + + if ( renderTarget && renderTarget.generateMipmaps && renderTarget.minFilter !== THREE.NearestFilter && renderTarget.minFilter !== THREE.LinearFilter ) { + + updateRenderTargetMipmap( renderTarget ); + + } + + // Ensure depth buffer writing is enabled so it can be cleared on next render + + this.setDepthTest( true ); + this.setDepthWrite( true ); + + // _gl.finish(); + + }; + + function renderPlugins( plugins, scene, camera ) { + + if ( ! plugins.length ) return; + + for ( var i = 0, il = plugins.length; i < il; i ++ ) { + + // reset state for plugin (to start from clean slate) + + _currentProgram = null; + _currentCamera = null; + + _oldBlending = -1; + _oldDepthTest = -1; + _oldDepthWrite = -1; + _oldDoubleSided = -1; + _oldFlipSided = -1; + _currentGeometryGroupHash = -1; + _currentMaterialId = -1; + + _lightsNeedUpdate = true; + + plugins[ i ].render( scene, camera, _currentWidth, _currentHeight ); + + // reset state after plugin (anything could have changed) + + _currentProgram = null; + _currentCamera = null; + + _oldBlending = -1; + _oldDepthTest = -1; + _oldDepthWrite = -1; + _oldDoubleSided = -1; + _oldFlipSided = -1; + _currentGeometryGroupHash = -1; + _currentMaterialId = -1; + + _lightsNeedUpdate = true; + + } + + }; + + function renderObjects ( renderList, reverse, materialType, camera, lights, fog, useBlending, overrideMaterial ) { + + var webglObject, object, buffer, material, start, end, delta; + + if ( reverse ) { + + start = renderList.length - 1; + end = -1; + delta = -1; + + } else { + + start = 0; + end = renderList.length; + delta = 1; + } + + for ( var i = start; i !== end; i += delta ) { + + webglObject = renderList[ i ]; + + if ( webglObject.render ) { + + object = webglObject.object; + buffer = webglObject.buffer; + + if ( overrideMaterial ) { + + material = overrideMaterial; + + } else { + + material = webglObject[ materialType ]; + + if ( ! material ) continue; + + if ( useBlending ) _this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); + + _this.setDepthTest( material.depthTest ); + _this.setDepthWrite( material.depthWrite ); + setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); + + } + + _this.setMaterialFaces( material ); + + if ( buffer instanceof THREE.BufferGeometry ) { + + _this.renderBufferDirect( camera, lights, fog, material, buffer, object ); + + } else { + + _this.renderBuffer( camera, lights, fog, material, buffer, object ); + + } + + } + + } + + }; + + function renderObjectsImmediate ( renderList, materialType, camera, lights, fog, useBlending, overrideMaterial ) { + + var webglObject, object, material, program; + + for ( var i = 0, il = renderList.length; i < il; i ++ ) { + + webglObject = renderList[ i ]; + object = webglObject.object; + + if ( object.visible ) { + + if ( overrideMaterial ) { + + material = overrideMaterial; + + } else { + + material = webglObject[ materialType ]; + + if ( ! material ) continue; + + if ( useBlending ) _this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); + + _this.setDepthTest( material.depthTest ); + _this.setDepthWrite( material.depthWrite ); + setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); + + } + + _this.renderImmediateObject( camera, lights, fog, material, object ); + + } + + } + + }; + + this.renderImmediateObject = function ( camera, lights, fog, material, object ) { + + var program = setProgram( camera, lights, fog, material, object ); + + _currentGeometryGroupHash = -1; + + _this.setMaterialFaces( material ); + + if ( object.immediateRenderCallback ) { + + object.immediateRenderCallback( program, _gl, _frustum ); + + } else { + + object.render( function( object ) { _this.renderBufferImmediate( object, program, material ); } ); + + } + + }; + + function unrollImmediateBufferMaterial ( globject ) { + + var object = globject.object, + material = object.material; + + if ( material.transparent ) { + + globject.transparent = material; + globject.opaque = null; + + } else { + + globject.opaque = material; + globject.transparent = null; + + } + + }; + + function unrollBufferMaterial ( globject ) { + + var object = globject.object, + buffer = globject.buffer, + material, materialIndex, meshMaterial; + + meshMaterial = object.material; + + if ( meshMaterial instanceof THREE.MeshFaceMaterial ) { + + materialIndex = buffer.materialIndex; + + material = meshMaterial.materials[ materialIndex ]; + + if ( material.transparent ) { + + globject.transparent = material; + globject.opaque = null; + + } else { + + globject.opaque = material; + globject.transparent = null; + + } + + } else { + + material = meshMaterial; + + if ( material ) { + + if ( material.transparent ) { + + globject.transparent = material; + globject.opaque = null; + + } else { + + globject.opaque = material; + globject.transparent = null; + + } + + } + + } + + }; + + // Geometry splitting + + function sortFacesByMaterial ( geometry, material ) { + + var f, fl, face, materialIndex, vertices, + groupHash, hash_map = {}; + + var numMorphTargets = geometry.morphTargets.length; + var numMorphNormals = geometry.morphNormals.length; + + var usesFaceMaterial = material instanceof THREE.MeshFaceMaterial; + + geometry.geometryGroups = {}; + + for ( f = 0, fl = geometry.faces.length; f < fl; f ++ ) { + + face = geometry.faces[ f ]; + materialIndex = usesFaceMaterial ? face.materialIndex : 0; + + if ( hash_map[ materialIndex ] === undefined ) { + + hash_map[ materialIndex ] = { 'hash': materialIndex, 'counter': 0 }; + + } + + groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter; + + if ( geometry.geometryGroups[ groupHash ] === undefined ) { + + geometry.geometryGroups[ groupHash ] = { 'faces3': [], 'faces4': [], 'materialIndex': materialIndex, 'vertices': 0, 'numMorphTargets': numMorphTargets, 'numMorphNormals': numMorphNormals }; + + } + + vertices = face instanceof THREE.Face3 ? 3 : 4; + + if ( geometry.geometryGroups[ groupHash ].vertices + vertices > 65535 ) { + + hash_map[ materialIndex ].counter += 1; + groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter; + + if ( geometry.geometryGroups[ groupHash ] === undefined ) { + + geometry.geometryGroups[ groupHash ] = { 'faces3': [], 'faces4': [], 'materialIndex': materialIndex, 'vertices': 0, 'numMorphTargets': numMorphTargets, 'numMorphNormals': numMorphNormals }; + + } + + } + + if ( face instanceof THREE.Face3 ) { + + geometry.geometryGroups[ groupHash ].faces3.push( f ); + + } else { + + geometry.geometryGroups[ groupHash ].faces4.push( f ); + + } + + geometry.geometryGroups[ groupHash ].vertices += vertices; + + } + + geometry.geometryGroupsList = []; + + for ( var g in geometry.geometryGroups ) { + + geometry.geometryGroups[ g ].id = _geometryGroupCounter ++; + + geometry.geometryGroupsList.push( geometry.geometryGroups[ g ] ); + + } + + }; + + // Objects refresh + + this.initWebGLObjects = function ( scene ) { + + if ( !scene.__webglObjects ) { + + scene.__webglObjects = []; + scene.__webglObjectsImmediate = []; + scene.__webglSprites = []; + scene.__webglFlares = []; + + } + + while ( scene.__objectsAdded.length ) { + + addObject( scene.__objectsAdded[ 0 ], scene ); + scene.__objectsAdded.splice( 0, 1 ); + + } + + while ( scene.__objectsRemoved.length ) { + + removeObject( scene.__objectsRemoved[ 0 ], scene ); + scene.__objectsRemoved.splice( 0, 1 ); + + } + + // update must be called after objects adding / removal + + for ( var o = 0, ol = scene.__webglObjects.length; o < ol; o ++ ) { + + updateObject( scene.__webglObjects[ o ].object ); + + } + + }; + + // Objects adding + + function addObject ( object, scene ) { + + var g, geometry, material, geometryGroup; + + if ( ! object.__webglInit ) { + + object.__webglInit = true; + + object._modelViewMatrix = new THREE.Matrix4(); + object._normalMatrix = new THREE.Matrix3(); + + if ( object.geometry !== undefined && object.geometry.__webglInit === undefined ) { + + object.geometry.__webglInit = true; + object.geometry.addEventListener( 'dispose', onGeometryDispose ); + + } + + if ( object instanceof THREE.Mesh ) { + + geometry = object.geometry; + material = object.material; + + if ( geometry instanceof THREE.Geometry ) { + + if ( geometry.geometryGroups === undefined ) { + + sortFacesByMaterial( geometry, material ); + + } + + // create separate VBOs per geometry chunk + + for ( g in geometry.geometryGroups ) { + + geometryGroup = geometry.geometryGroups[ g ]; + + // initialise VBO on the first access + + if ( ! geometryGroup.__webglVertexBuffer ) { + + createMeshBuffers( geometryGroup ); + initMeshBuffers( geometryGroup, object ); + + geometry.verticesNeedUpdate = true; + geometry.morphTargetsNeedUpdate = true; + geometry.elementsNeedUpdate = true; + geometry.uvsNeedUpdate = true; + geometry.normalsNeedUpdate = true; + geometry.tangentsNeedUpdate = true; + geometry.colorsNeedUpdate = true; + + } + + } + + } else if ( geometry instanceof THREE.BufferGeometry ) { + + initDirectBuffers( geometry ); + + } + + } else if ( object instanceof THREE.Ribbon ) { + + geometry = object.geometry; + + if ( ! geometry.__webglVertexBuffer ) { + + createRibbonBuffers( geometry ); + initRibbonBuffers( geometry, object ); + + geometry.verticesNeedUpdate = true; + geometry.colorsNeedUpdate = true; + geometry.normalsNeedUpdate = true; + + } + + } else if ( object instanceof THREE.Line ) { + + geometry = object.geometry; + + if ( ! geometry.__webglVertexBuffer ) { + + if ( geometry instanceof THREE.Geometry ) { + + createLineBuffers( geometry ); + initLineBuffers( geometry, object ); + + geometry.verticesNeedUpdate = true; + geometry.colorsNeedUpdate = true; + geometry.lineDistancesNeedUpdate = true; + + } else if ( geometry instanceof THREE.BufferGeometry ) { + + initDirectBuffers( geometry ); + + } + + } + + } else if ( object instanceof THREE.ParticleSystem ) { + + geometry = object.geometry; + + if ( ! geometry.__webglVertexBuffer ) { + + if ( geometry instanceof THREE.Geometry ) { + + createParticleBuffers( geometry ); + initParticleBuffers( geometry, object ); + + geometry.verticesNeedUpdate = true; + geometry.colorsNeedUpdate = true; + + } else if ( geometry instanceof THREE.BufferGeometry ) { + + initDirectBuffers( geometry ); + + } + + + } + + } + + } + + if ( ! object.__webglActive ) { + + if ( object instanceof THREE.Mesh ) { + + geometry = object.geometry; + + if ( geometry instanceof THREE.BufferGeometry ) { + + addBuffer( scene.__webglObjects, geometry, object ); + + } else if ( geometry instanceof THREE.Geometry ) { + + for ( g in geometry.geometryGroups ) { + + geometryGroup = geometry.geometryGroups[ g ]; + + addBuffer( scene.__webglObjects, geometryGroup, object ); + + } + + } + + } else if ( object instanceof THREE.Ribbon || + object instanceof THREE.Line || + object instanceof THREE.ParticleSystem ) { + + geometry = object.geometry; + addBuffer( scene.__webglObjects, geometry, object ); + + } else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) { + + addBufferImmediate( scene.__webglObjectsImmediate, object ); + + } else if ( object instanceof THREE.Sprite ) { + + scene.__webglSprites.push( object ); + + } else if ( object instanceof THREE.LensFlare ) { + + scene.__webglFlares.push( object ); + + } + + object.__webglActive = true; + + } + + }; + + function addBuffer ( objlist, buffer, object ) { + + objlist.push( + { + buffer: buffer, + object: object, + opaque: null, + transparent: null + } + ); + + }; + + function addBufferImmediate ( objlist, object ) { + + objlist.push( + { + object: object, + opaque: null, + transparent: null + } + ); + + }; + + // Objects updates + + function updateObject ( object ) { + + var geometry = object.geometry, + geometryGroup, customAttributesDirty, material; + + if ( object instanceof THREE.Mesh ) { + + if ( geometry instanceof THREE.BufferGeometry ) { + + if ( geometry.verticesNeedUpdate || geometry.elementsNeedUpdate || + geometry.uvsNeedUpdate || geometry.normalsNeedUpdate || + geometry.colorsNeedUpdate || geometry.tangentsNeedUpdate ) { + + setDirectBuffers( geometry, _gl.DYNAMIC_DRAW, !geometry.dynamic ); + + } + + geometry.verticesNeedUpdate = false; + geometry.elementsNeedUpdate = false; + geometry.uvsNeedUpdate = false; + geometry.normalsNeedUpdate = false; + geometry.colorsNeedUpdate = false; + geometry.tangentsNeedUpdate = false; + + } else { + + // check all geometry groups + + for( var i = 0, il = geometry.geometryGroupsList.length; i < il; i ++ ) { + + geometryGroup = geometry.geometryGroupsList[ i ]; + + material = getBufferMaterial( object, geometryGroup ); + + if ( geometry.buffersNeedUpdate ) { + + initMeshBuffers( geometryGroup, object ); + + } + + customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); + + if ( geometry.verticesNeedUpdate || geometry.morphTargetsNeedUpdate || geometry.elementsNeedUpdate || + geometry.uvsNeedUpdate || geometry.normalsNeedUpdate || + geometry.colorsNeedUpdate || geometry.tangentsNeedUpdate || customAttributesDirty ) { + + setMeshBuffers( geometryGroup, object, _gl.DYNAMIC_DRAW, !geometry.dynamic, material ); + + } + + } + + geometry.verticesNeedUpdate = false; + geometry.morphTargetsNeedUpdate = false; + geometry.elementsNeedUpdate = false; + geometry.uvsNeedUpdate = false; + geometry.normalsNeedUpdate = false; + geometry.colorsNeedUpdate = false; + geometry.tangentsNeedUpdate = false; + + geometry.buffersNeedUpdate = false; + + material.attributes && clearCustomAttributes( material ); + + } + + } else if ( object instanceof THREE.Ribbon ) { + + material = getBufferMaterial( object, geometry ); + + customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); + + if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || geometry.normalsNeedUpdate || customAttributesDirty ) { + + setRibbonBuffers( geometry, _gl.DYNAMIC_DRAW ); + + } + + geometry.verticesNeedUpdate = false; + geometry.colorsNeedUpdate = false; + geometry.normalsNeedUpdate = false; + + material.attributes && clearCustomAttributes( material ); + + } else if ( object instanceof THREE.Line ) { + + if ( geometry instanceof THREE.BufferGeometry ) { + + if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate ) { + + setDirectBuffers( geometry, _gl.DYNAMIC_DRAW, !geometry.dynamic ); + + } + + geometry.verticesNeedUpdate = false; + geometry.colorsNeedUpdate = false; + + } else { + + material = getBufferMaterial( object, geometry ); + + customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); + + if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || geometry.lineDistancesNeedUpdate || customAttributesDirty ) { + + setLineBuffers( geometry, _gl.DYNAMIC_DRAW ); + + } + + geometry.verticesNeedUpdate = false; + geometry.colorsNeedUpdate = false; + geometry.lineDistancesNeedUpdate = false; + + material.attributes && clearCustomAttributes( material ); + + } + + } else if ( object instanceof THREE.ParticleSystem ) { + + if ( geometry instanceof THREE.BufferGeometry ) { + + if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate ) { + + setDirectBuffers( geometry, _gl.DYNAMIC_DRAW, !geometry.dynamic ); + + } + + geometry.verticesNeedUpdate = false; + geometry.colorsNeedUpdate = false; + + } else { + + material = getBufferMaterial( object, geometry ); + + customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); + + if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || object.sortParticles || customAttributesDirty ) { + + setParticleBuffers( geometry, _gl.DYNAMIC_DRAW, object ); + + } + + geometry.verticesNeedUpdate = false; + geometry.colorsNeedUpdate = false; + + material.attributes && clearCustomAttributes( material ); + + } + + } + + }; + + // Objects updates - custom attributes check + + function areCustomAttributesDirty ( material ) { + + for ( var a in material.attributes ) { + + if ( material.attributes[ a ].needsUpdate ) return true; + + } + + return false; + + }; + + function clearCustomAttributes ( material ) { + + for ( var a in material.attributes ) { + + material.attributes[ a ].needsUpdate = false; + + } + + }; + + // Objects removal + + function removeObject ( object, scene ) { + + if ( object instanceof THREE.Mesh || + object instanceof THREE.ParticleSystem || + object instanceof THREE.Ribbon || + object instanceof THREE.Line ) { + + removeInstances( scene.__webglObjects, object ); + + } else if ( object instanceof THREE.Sprite ) { + + removeInstancesDirect( scene.__webglSprites, object ); + + } else if ( object instanceof THREE.LensFlare ) { + + removeInstancesDirect( scene.__webglFlares, object ); + + } else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) { + + removeInstances( scene.__webglObjectsImmediate, object ); + + } + + object.__webglActive = false; + + }; + + function removeInstances ( objlist, object ) { + + for ( var o = objlist.length - 1; o >= 0; o -- ) { + + if ( objlist[ o ].object === object ) { + + objlist.splice( o, 1 ); + + } + + } + + }; + + function removeInstancesDirect ( objlist, object ) { + + for ( var o = objlist.length - 1; o >= 0; o -- ) { + + if ( objlist[ o ] === object ) { + + objlist.splice( o, 1 ); + + } + + } + + }; + + // Materials + + this.initMaterial = function ( material, lights, fog, object ) { + + material.addEventListener( 'dispose', onMaterialDispose ); + + var u, a, identifiers, i, parameters, maxLightCount, maxBones, maxShadows, shaderID; + + if ( material instanceof THREE.MeshDepthMaterial ) { + + shaderID = 'depth'; + + } else if ( material instanceof THREE.MeshNormalMaterial ) { + + shaderID = 'normal'; + + } else if ( material instanceof THREE.MeshBasicMaterial ) { + + shaderID = 'basic'; + + } else if ( material instanceof THREE.MeshLambertMaterial ) { + + shaderID = 'lambert'; + + } else if ( material instanceof THREE.MeshPhongMaterial ) { + + shaderID = 'phong'; + + } else if ( material instanceof THREE.LineBasicMaterial ) { + + shaderID = 'basic'; + + } else if ( material instanceof THREE.LineDashedMaterial ) { + + shaderID = 'dashed'; + + } else if ( material instanceof THREE.ParticleBasicMaterial ) { + + shaderID = 'particle_basic'; + + } + + if ( shaderID ) { + + setMaterialShaders( material, THREE.ShaderLib[ shaderID ] ); + + } + + // heuristics to create shader parameters according to lights in the scene + // (not to blow over maxLights budget) + + maxLightCount = allocateLights( lights ); + + maxShadows = allocateShadows( lights ); + + maxBones = allocateBones( object ); + + parameters = { + + map: !!material.map, + envMap: !!material.envMap, + lightMap: !!material.lightMap, + bumpMap: !!material.bumpMap, + normalMap: !!material.normalMap, + specularMap: !!material.specularMap, + + vertexColors: material.vertexColors, + + fog: fog, + useFog: material.fog, + fogExp: fog instanceof THREE.FogExp2, + + sizeAttenuation: material.sizeAttenuation, + + skinning: material.skinning, + maxBones: maxBones, + useVertexTexture: _supportsBoneTextures && object && object.useVertexTexture, + boneTextureWidth: object && object.boneTextureWidth, + boneTextureHeight: object && object.boneTextureHeight, + + morphTargets: material.morphTargets, + morphNormals: material.morphNormals, + maxMorphTargets: this.maxMorphTargets, + maxMorphNormals: this.maxMorphNormals, + + maxDirLights: maxLightCount.directional, + maxPointLights: maxLightCount.point, + maxSpotLights: maxLightCount.spot, + maxHemiLights: maxLightCount.hemi, + + maxShadows: maxShadows, + shadowMapEnabled: this.shadowMapEnabled && object.receiveShadow, + shadowMapType: this.shadowMapType, + shadowMapDebug: this.shadowMapDebug, + shadowMapCascade: this.shadowMapCascade, + + alphaTest: material.alphaTest, + metal: material.metal, + perPixel: material.perPixel, + wrapAround: material.wrapAround, + doubleSided: material.side === THREE.DoubleSide, + flipSided: material.side === THREE.BackSide + + }; + + material.program = buildProgram( shaderID, material.fragmentShader, material.vertexShader, material.uniforms, material.attributes, material.defines, parameters ); + + var attributes = material.program.attributes; + + if ( material.morphTargets ) { + + material.numSupportedMorphTargets = 0; + + var id, base = "morphTarget"; + + for ( i = 0; i < this.maxMorphTargets; i ++ ) { + + id = base + i; + + if ( attributes[ id ] >= 0 ) { + + material.numSupportedMorphTargets ++; + + } + + } + + } + + if ( material.morphNormals ) { + + material.numSupportedMorphNormals = 0; + + var id, base = "morphNormal"; + + for ( i = 0; i < this.maxMorphNormals; i ++ ) { + + id = base + i; + + if ( attributes[ id ] >= 0 ) { + + material.numSupportedMorphNormals ++; + + } + + } + + } + + material.uniformsList = []; + + for ( u in material.uniforms ) { + + material.uniformsList.push( [ material.uniforms[ u ], u ] ); + + } + + }; + + function setMaterialShaders( material, shaders ) { + + material.uniforms = THREE.UniformsUtils.clone( shaders.uniforms ); + material.vertexShader = shaders.vertexShader; + material.fragmentShader = shaders.fragmentShader; + + }; + + function setProgram( camera, lights, fog, material, object ) { + + _usedTextureUnits = 0; + + if ( material.needsUpdate ) { + + if ( material.program ) deallocateMaterial( material ); + + _this.initMaterial( material, lights, fog, object ); + material.needsUpdate = false; + + } + + if ( material.morphTargets ) { + + if ( ! object.__webglMorphTargetInfluences ) { + + object.__webglMorphTargetInfluences = new Float32Array( _this.maxMorphTargets ); + + } + + } + + var refreshMaterial = false; + + var program = material.program, + p_uniforms = program.uniforms, + m_uniforms = material.uniforms; + + if ( program !== _currentProgram ) { + + _gl.useProgram( program ); + _currentProgram = program; + + refreshMaterial = true; + + } + + if ( material.id !== _currentMaterialId ) { + + _currentMaterialId = material.id; + refreshMaterial = true; + + } + + if ( refreshMaterial || camera !== _currentCamera ) { + + _gl.uniformMatrix4fv( p_uniforms.projectionMatrix, false, camera.projectionMatrix.elements ); + + if ( camera !== _currentCamera ) _currentCamera = camera; + + } + + // skinning uniforms must be set even if material didn't change + // auto-setting of texture unit for bone texture must go before other textures + // not sure why, but otherwise weird things happen + + if ( material.skinning ) { + + if ( _supportsBoneTextures && object.useVertexTexture ) { + + if ( p_uniforms.boneTexture !== null ) { + + var textureUnit = getTextureUnit(); + + _gl.uniform1i( p_uniforms.boneTexture, textureUnit ); + _this.setTexture( object.boneTexture, textureUnit ); + + } + + } else { + + if ( p_uniforms.boneGlobalMatrices !== null ) { + + _gl.uniformMatrix4fv( p_uniforms.boneGlobalMatrices, false, object.boneMatrices ); + + } + + } + + } + + if ( refreshMaterial ) { + + // refresh uniforms common to several materials + + if ( fog && material.fog ) { + + refreshUniformsFog( m_uniforms, fog ); + + } + + if ( material instanceof THREE.MeshPhongMaterial || + material instanceof THREE.MeshLambertMaterial || + material.lights ) { + + if ( _lightsNeedUpdate ) { + + setupLights( program, lights ); + _lightsNeedUpdate = false; + + } + + refreshUniformsLights( m_uniforms, _lights ); + + } + + if ( material instanceof THREE.MeshBasicMaterial || + material instanceof THREE.MeshLambertMaterial || + material instanceof THREE.MeshPhongMaterial ) { + + refreshUniformsCommon( m_uniforms, material ); + + } + + // refresh single material specific uniforms + + if ( material instanceof THREE.LineBasicMaterial ) { + + refreshUniformsLine( m_uniforms, material ); + + } else if ( material instanceof THREE.LineDashedMaterial ) { + + refreshUniformsLine( m_uniforms, material ); + refreshUniformsDash( m_uniforms, material ); + + } else if ( material instanceof THREE.ParticleBasicMaterial ) { + + refreshUniformsParticle( m_uniforms, material ); + + } else if ( material instanceof THREE.MeshPhongMaterial ) { + + refreshUniformsPhong( m_uniforms, material ); + + } else if ( material instanceof THREE.MeshLambertMaterial ) { + + refreshUniformsLambert( m_uniforms, material ); + + } else if ( material instanceof THREE.MeshDepthMaterial ) { + + m_uniforms.mNear.value = camera.near; + m_uniforms.mFar.value = camera.far; + m_uniforms.opacity.value = material.opacity; + + } else if ( material instanceof THREE.MeshNormalMaterial ) { + + m_uniforms.opacity.value = material.opacity; + + } + + if ( object.receiveShadow && ! material._shadowPass ) { + + refreshUniformsShadow( m_uniforms, lights ); + + } + + // load common uniforms + + loadUniformsGeneric( program, material.uniformsList ); + + // load material specific uniforms + // (shader material also gets them for the sake of genericity) + + if ( material instanceof THREE.ShaderMaterial || + material instanceof THREE.MeshPhongMaterial || + material.envMap ) { + + if ( p_uniforms.cameraPosition !== null ) { + + _vector3.getPositionFromMatrix( camera.matrixWorld ); + _gl.uniform3f( p_uniforms.cameraPosition, _vector3.x, _vector3.y, _vector3.z ); + + } + + } + + if ( material instanceof THREE.MeshPhongMaterial || + material instanceof THREE.MeshLambertMaterial || + material instanceof THREE.ShaderMaterial || + material.skinning ) { + + if ( p_uniforms.viewMatrix !== null ) { + + _gl.uniformMatrix4fv( p_uniforms.viewMatrix, false, camera.matrixWorldInverse.elements ); + + } + + } + + } + + loadUniformsMatrices( p_uniforms, object ); + + if ( p_uniforms.modelMatrix !== null ) { + + _gl.uniformMatrix4fv( p_uniforms.modelMatrix, false, object.matrixWorld.elements ); + + } + + return program; + + }; + + // Uniforms (refresh uniforms objects) + + function refreshUniformsCommon ( uniforms, material ) { + + uniforms.opacity.value = material.opacity; + + if ( _this.gammaInput ) { + + uniforms.diffuse.value.copyGammaToLinear( material.color ); + + } else { + + uniforms.diffuse.value = material.color; + + } + + uniforms.map.value = material.map; + uniforms.lightMap.value = material.lightMap; + uniforms.specularMap.value = material.specularMap; + + if ( material.bumpMap ) { + + uniforms.bumpMap.value = material.bumpMap; + uniforms.bumpScale.value = material.bumpScale; + + } + + if ( material.normalMap ) { + + uniforms.normalMap.value = material.normalMap; + uniforms.normalScale.value.copy( material.normalScale ); + + } + + // uv repeat and offset setting priorities + // 1. color map + // 2. specular map + // 3. normal map + // 4. bump map + + var uvScaleMap; + + if ( material.map ) { + + uvScaleMap = material.map; + + } else if ( material.specularMap ) { + + uvScaleMap = material.specularMap; + + } else if ( material.normalMap ) { + + uvScaleMap = material.normalMap; + + } else if ( material.bumpMap ) { + + uvScaleMap = material.bumpMap; + + } + + if ( uvScaleMap !== undefined ) { + + var offset = uvScaleMap.offset; + var repeat = uvScaleMap.repeat; + + uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y ); + + } + + uniforms.envMap.value = material.envMap; + uniforms.flipEnvMap.value = ( material.envMap instanceof THREE.WebGLRenderTargetCube ) ? 1 : -1; + + if ( _this.gammaInput ) { + + //uniforms.reflectivity.value = material.reflectivity * material.reflectivity; + uniforms.reflectivity.value = material.reflectivity; + + } else { + + uniforms.reflectivity.value = material.reflectivity; + + } + + uniforms.refractionRatio.value = material.refractionRatio; + uniforms.combine.value = material.combine; + uniforms.useRefract.value = material.envMap && material.envMap.mapping instanceof THREE.CubeRefractionMapping; + + }; + + function refreshUniformsLine ( uniforms, material ) { + + uniforms.diffuse.value = material.color; + uniforms.opacity.value = material.opacity; + + }; + + function refreshUniformsDash ( uniforms, material ) { + + uniforms.dashSize.value = material.dashSize; + uniforms.totalSize.value = material.dashSize + material.gapSize; + uniforms.scale.value = material.scale; + + }; + + function refreshUniformsParticle ( uniforms, material ) { + + uniforms.psColor.value = material.color; + uniforms.opacity.value = material.opacity; + uniforms.size.value = material.size; + uniforms.scale.value = _canvas.height / 2.0; // TODO: Cache this. + + uniforms.map.value = material.map; + + }; + + function refreshUniformsFog ( uniforms, fog ) { + + uniforms.fogColor.value = fog.color; + + if ( fog instanceof THREE.Fog ) { + + uniforms.fogNear.value = fog.near; + uniforms.fogFar.value = fog.far; + + } else if ( fog instanceof THREE.FogExp2 ) { + + uniforms.fogDensity.value = fog.density; + + } + + }; + + function refreshUniformsPhong ( uniforms, material ) { + + uniforms.shininess.value = material.shininess; + + if ( _this.gammaInput ) { + + uniforms.ambient.value.copyGammaToLinear( material.ambient ); + uniforms.emissive.value.copyGammaToLinear( material.emissive ); + uniforms.specular.value.copyGammaToLinear( material.specular ); + + } else { + + uniforms.ambient.value = material.ambient; + uniforms.emissive.value = material.emissive; + uniforms.specular.value = material.specular; + + } + + if ( material.wrapAround ) { + + uniforms.wrapRGB.value.copy( material.wrapRGB ); + + } + + }; + + function refreshUniformsLambert ( uniforms, material ) { + + if ( _this.gammaInput ) { + + uniforms.ambient.value.copyGammaToLinear( material.ambient ); + uniforms.emissive.value.copyGammaToLinear( material.emissive ); + + } else { + + uniforms.ambient.value = material.ambient; + uniforms.emissive.value = material.emissive; + + } + + if ( material.wrapAround ) { + + uniforms.wrapRGB.value.copy( material.wrapRGB ); + + } + + }; + + function refreshUniformsLights ( uniforms, lights ) { + + uniforms.ambientLightColor.value = lights.ambient; + + uniforms.directionalLightColor.value = lights.directional.colors; + uniforms.directionalLightDirection.value = lights.directional.positions; + + uniforms.pointLightColor.value = lights.point.colors; + uniforms.pointLightPosition.value = lights.point.positions; + uniforms.pointLightDistance.value = lights.point.distances; + + uniforms.spotLightColor.value = lights.spot.colors; + uniforms.spotLightPosition.value = lights.spot.positions; + uniforms.spotLightDistance.value = lights.spot.distances; + uniforms.spotLightDirection.value = lights.spot.directions; + uniforms.spotLightAngleCos.value = lights.spot.anglesCos; + uniforms.spotLightExponent.value = lights.spot.exponents; + + uniforms.hemisphereLightSkyColor.value = lights.hemi.skyColors; + uniforms.hemisphereLightGroundColor.value = lights.hemi.groundColors; + uniforms.hemisphereLightDirection.value = lights.hemi.positions; + + }; + + function refreshUniformsShadow ( uniforms, lights ) { + + if ( uniforms.shadowMatrix ) { + + var j = 0; + + for ( var i = 0, il = lights.length; i < il; i ++ ) { + + var light = lights[ i ]; + + if ( ! light.castShadow ) continue; + + if ( light instanceof THREE.SpotLight || ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) ) { + + uniforms.shadowMap.value[ j ] = light.shadowMap; + uniforms.shadowMapSize.value[ j ] = light.shadowMapSize; + + uniforms.shadowMatrix.value[ j ] = light.shadowMatrix; + + uniforms.shadowDarkness.value[ j ] = light.shadowDarkness; + uniforms.shadowBias.value[ j ] = light.shadowBias; + + j ++; + + } + + } + + } + + }; + + // Uniforms (load to GPU) + + function loadUniformsMatrices ( uniforms, object ) { + + _gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, object._modelViewMatrix.elements ); + + if ( uniforms.normalMatrix ) { + + _gl.uniformMatrix3fv( uniforms.normalMatrix, false, object._normalMatrix.elements ); + + } + + }; + + function getTextureUnit() { + + var textureUnit = _usedTextureUnits; + + if ( textureUnit >= _maxTextures ) { + + console.warn( "WebGLRenderer: trying to use " + textureUnit + " texture units while this GPU supports only " + _maxTextures ); + + } + + _usedTextureUnits += 1; + + return textureUnit; + + }; + + function loadUniformsGeneric ( program, uniforms ) { + + var uniform, value, type, location, texture, textureUnit, i, il, j, jl, offset; + + for ( j = 0, jl = uniforms.length; j < jl; j ++ ) { + + location = program.uniforms[ uniforms[ j ][ 1 ] ]; + if ( !location ) continue; + + uniform = uniforms[ j ][ 0 ]; + + type = uniform.type; + value = uniform.value; + + if ( type === "i" ) { // single integer + + _gl.uniform1i( location, value ); + + } else if ( type === "f" ) { // single float + + _gl.uniform1f( location, value ); + + } else if ( type === "v2" ) { // single THREE.Vector2 + + _gl.uniform2f( location, value.x, value.y ); + + } else if ( type === "v3" ) { // single THREE.Vector3 + + _gl.uniform3f( location, value.x, value.y, value.z ); + + } else if ( type === "v4" ) { // single THREE.Vector4 + + _gl.uniform4f( location, value.x, value.y, value.z, value.w ); + + } else if ( type === "c" ) { // single THREE.Color + + _gl.uniform3f( location, value.r, value.g, value.b ); + + } else if ( type === "iv1" ) { // flat array of integers (JS or typed array) + + _gl.uniform1iv( location, value ); + + } else if ( type === "iv" ) { // flat array of integers with 3 x N size (JS or typed array) + + _gl.uniform3iv( location, value ); + + } else if ( type === "fv1" ) { // flat array of floats (JS or typed array) + + _gl.uniform1fv( location, value ); + + } else if ( type === "fv" ) { // flat array of floats with 3 x N size (JS or typed array) + + _gl.uniform3fv( location, value ); + + } else if ( type === "v2v" ) { // array of THREE.Vector2 + + if ( uniform._array === undefined ) { + + uniform._array = new Float32Array( 2 * value.length ); + + } + + for ( i = 0, il = value.length; i < il; i ++ ) { + + offset = i * 2; + + uniform._array[ offset ] = value[ i ].x; + uniform._array[ offset + 1 ] = value[ i ].y; + + } + + _gl.uniform2fv( location, uniform._array ); + + } else if ( type === "v3v" ) { // array of THREE.Vector3 + + if ( uniform._array === undefined ) { + + uniform._array = new Float32Array( 3 * value.length ); + + } + + for ( i = 0, il = value.length; i < il; i ++ ) { + + offset = i * 3; + + uniform._array[ offset ] = value[ i ].x; + uniform._array[ offset + 1 ] = value[ i ].y; + uniform._array[ offset + 2 ] = value[ i ].z; + + } + + _gl.uniform3fv( location, uniform._array ); + + } else if ( type === "v4v" ) { // array of THREE.Vector4 + + if ( uniform._array === undefined ) { + + uniform._array = new Float32Array( 4 * value.length ); + + } + + for ( i = 0, il = value.length; i < il; i ++ ) { + + offset = i * 4; + + uniform._array[ offset ] = value[ i ].x; + uniform._array[ offset + 1 ] = value[ i ].y; + uniform._array[ offset + 2 ] = value[ i ].z; + uniform._array[ offset + 3 ] = value[ i ].w; + + } + + _gl.uniform4fv( location, uniform._array ); + + } else if ( type === "m4") { // single THREE.Matrix4 + + if ( uniform._array === undefined ) { + + uniform._array = new Float32Array( 16 ); + + } + + value.flattenToArray( uniform._array ); + _gl.uniformMatrix4fv( location, false, uniform._array ); + + } else if ( type === "m4v" ) { // array of THREE.Matrix4 + + if ( uniform._array === undefined ) { + + uniform._array = new Float32Array( 16 * value.length ); + + } + + for ( i = 0, il = value.length; i < il; i ++ ) { + + value[ i ].flattenToArrayOffset( uniform._array, i * 16 ); + + } + + _gl.uniformMatrix4fv( location, false, uniform._array ); + + } else if ( type === "t" ) { // single THREE.Texture (2d or cube) + + texture = value; + textureUnit = getTextureUnit(); + + _gl.uniform1i( location, textureUnit ); + + if ( !texture ) continue; + + if ( texture.image instanceof Array && texture.image.length === 6 ) { + + setCubeTexture( texture, textureUnit ); + + } else if ( texture instanceof THREE.WebGLRenderTargetCube ) { + + setCubeTextureDynamic( texture, textureUnit ); + + } else { + + _this.setTexture( texture, textureUnit ); + + } + + } else if ( type === "tv" ) { // array of THREE.Texture (2d) + + if ( uniform._array === undefined ) { + + uniform._array = []; + + } + + for( i = 0, il = uniform.value.length; i < il; i ++ ) { + + uniform._array[ i ] = getTextureUnit(); + + } + + _gl.uniform1iv( location, uniform._array ); + + for( i = 0, il = uniform.value.length; i < il; i ++ ) { + + texture = uniform.value[ i ]; + textureUnit = uniform._array[ i ]; + + if ( !texture ) continue; + + _this.setTexture( texture, textureUnit ); + + } + + } + + } + + }; + + function setupMatrices ( object, camera ) { + + object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); + + object._normalMatrix.getInverse( object._modelViewMatrix ); + object._normalMatrix.transpose(); + + }; + + // + + function setColorGamma( array, offset, color, intensitySq ) { + + array[ offset ] = color.r * color.r * intensitySq; + array[ offset + 1 ] = color.g * color.g * intensitySq; + array[ offset + 2 ] = color.b * color.b * intensitySq; + + }; + + function setColorLinear( array, offset, color, intensity ) { + + array[ offset ] = color.r * intensity; + array[ offset + 1 ] = color.g * intensity; + array[ offset + 2 ] = color.b * intensity; + + }; + + function setupLights ( program, lights ) { + + var l, ll, light, n, + r = 0, g = 0, b = 0, + color, skyColor, groundColor, + intensity, intensitySq, + position, + distance, + + zlights = _lights, + + dirColors = zlights.directional.colors, + dirPositions = zlights.directional.positions, + + pointColors = zlights.point.colors, + pointPositions = zlights.point.positions, + pointDistances = zlights.point.distances, + + spotColors = zlights.spot.colors, + spotPositions = zlights.spot.positions, + spotDistances = zlights.spot.distances, + spotDirections = zlights.spot.directions, + spotAnglesCos = zlights.spot.anglesCos, + spotExponents = zlights.spot.exponents, + + hemiSkyColors = zlights.hemi.skyColors, + hemiGroundColors = zlights.hemi.groundColors, + hemiPositions = zlights.hemi.positions, + + dirLength = 0, + pointLength = 0, + spotLength = 0, + hemiLength = 0, + + dirCount = 0, + pointCount = 0, + spotCount = 0, + hemiCount = 0, + + dirOffset = 0, + pointOffset = 0, + spotOffset = 0, + hemiOffset = 0; + + for ( l = 0, ll = lights.length; l < ll; l ++ ) { + + light = lights[ l ]; + + if ( light.onlyShadow ) continue; + + color = light.color; + intensity = light.intensity; + distance = light.distance; + + if ( light instanceof THREE.AmbientLight ) { + + if ( ! light.visible ) continue; + + if ( _this.gammaInput ) { + + r += color.r * color.r; + g += color.g * color.g; + b += color.b * color.b; + + } else { + + r += color.r; + g += color.g; + b += color.b; + + } + + } else if ( light instanceof THREE.DirectionalLight ) { + + dirCount += 1; + + if ( ! light.visible ) continue; + + _direction.getPositionFromMatrix( light.matrixWorld ); + _vector3.getPositionFromMatrix( light.target.matrixWorld ); + _direction.sub( _vector3 ); + _direction.normalize(); + + // skip lights with undefined direction + // these create troubles in OpenGL (making pixel black) + + if ( _direction.x === 0 && _direction.y === 0 && _direction.z === 0 ) continue; + + dirOffset = dirLength * 3; + + dirPositions[ dirOffset ] = _direction.x; + dirPositions[ dirOffset + 1 ] = _direction.y; + dirPositions[ dirOffset + 2 ] = _direction.z; + + if ( _this.gammaInput ) { + + setColorGamma( dirColors, dirOffset, color, intensity * intensity ); + + } else { + + setColorLinear( dirColors, dirOffset, color, intensity ); + + } + + dirLength += 1; + + } else if ( light instanceof THREE.PointLight ) { + + pointCount += 1; + + if ( ! light.visible ) continue; + + pointOffset = pointLength * 3; + + if ( _this.gammaInput ) { + + setColorGamma( pointColors, pointOffset, color, intensity * intensity ); + + } else { + + setColorLinear( pointColors, pointOffset, color, intensity ); + + } + + _vector3.getPositionFromMatrix( light.matrixWorld ); + + pointPositions[ pointOffset ] = _vector3.x; + pointPositions[ pointOffset + 1 ] = _vector3.y; + pointPositions[ pointOffset + 2 ] = _vector3.z; + + pointDistances[ pointLength ] = distance; + + pointLength += 1; + + } else if ( light instanceof THREE.SpotLight ) { + + spotCount += 1; + + if ( ! light.visible ) continue; + + spotOffset = spotLength * 3; + + if ( _this.gammaInput ) { + + setColorGamma( spotColors, spotOffset, color, intensity * intensity ); + + } else { + + setColorLinear( spotColors, spotOffset, color, intensity ); + + } + + _vector3.getPositionFromMatrix( light.matrixWorld ); + + spotPositions[ spotOffset ] = _vector3.x; + spotPositions[ spotOffset + 1 ] = _vector3.y; + spotPositions[ spotOffset + 2 ] = _vector3.z; + + spotDistances[ spotLength ] = distance; + + _direction.copy( _vector3 ); + _vector3.getPositionFromMatrix( light.target.matrixWorld ); + _direction.sub( _vector3 ); + _direction.normalize(); + + spotDirections[ spotOffset ] = _direction.x; + spotDirections[ spotOffset + 1 ] = _direction.y; + spotDirections[ spotOffset + 2 ] = _direction.z; + + spotAnglesCos[ spotLength ] = Math.cos( light.angle ); + spotExponents[ spotLength ] = light.exponent; + + spotLength += 1; + + } else if ( light instanceof THREE.HemisphereLight ) { + + hemiCount += 1; + + if ( ! light.visible ) continue; + + _direction.getPositionFromMatrix( light.matrixWorld ); + _direction.normalize(); + + // skip lights with undefined direction + // these create troubles in OpenGL (making pixel black) + + if ( _direction.x === 0 && _direction.y === 0 && _direction.z === 0 ) continue; + + hemiOffset = hemiLength * 3; + + hemiPositions[ hemiOffset ] = _direction.x; + hemiPositions[ hemiOffset + 1 ] = _direction.y; + hemiPositions[ hemiOffset + 2 ] = _direction.z; + + skyColor = light.color; + groundColor = light.groundColor; + + if ( _this.gammaInput ) { + + intensitySq = intensity * intensity; + + setColorGamma( hemiSkyColors, hemiOffset, skyColor, intensitySq ); + setColorGamma( hemiGroundColors, hemiOffset, groundColor, intensitySq ); + + } else { + + setColorLinear( hemiSkyColors, hemiOffset, skyColor, intensity ); + setColorLinear( hemiGroundColors, hemiOffset, groundColor, intensity ); + + } + + hemiLength += 1; + + } + + } + + // null eventual remains from removed lights + // (this is to avoid if in shader) + + for ( l = dirLength * 3, ll = Math.max( dirColors.length, dirCount * 3 ); l < ll; l ++ ) dirColors[ l ] = 0.0; + for ( l = pointLength * 3, ll = Math.max( pointColors.length, pointCount * 3 ); l < ll; l ++ ) pointColors[ l ] = 0.0; + for ( l = spotLength * 3, ll = Math.max( spotColors.length, spotCount * 3 ); l < ll; l ++ ) spotColors[ l ] = 0.0; + for ( l = hemiLength * 3, ll = Math.max( hemiSkyColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiSkyColors[ l ] = 0.0; + for ( l = hemiLength * 3, ll = Math.max( hemiGroundColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiGroundColors[ l ] = 0.0; + + zlights.directional.length = dirLength; + zlights.point.length = pointLength; + zlights.spot.length = spotLength; + zlights.hemi.length = hemiLength; + + zlights.ambient[ 0 ] = r; + zlights.ambient[ 1 ] = g; + zlights.ambient[ 2 ] = b; + + }; + + // GL state setting + + this.setFaceCulling = function ( cullFace, frontFaceDirection ) { + + if ( cullFace === THREE.CullFaceNone ) { + + _gl.disable( _gl.CULL_FACE ); + + } else { + + if ( frontFaceDirection === THREE.FrontFaceDirectionCW ) { + + _gl.frontFace( _gl.CW ); + + } else { + + _gl.frontFace( _gl.CCW ); + + } + + if ( cullFace === THREE.CullFaceBack ) { + + _gl.cullFace( _gl.BACK ); + + } else if ( cullFace === THREE.CullFaceFront ) { + + _gl.cullFace( _gl.FRONT ); + + } else { + + _gl.cullFace( _gl.FRONT_AND_BACK ); + + } + + _gl.enable( _gl.CULL_FACE ); + + } + + }; + + this.setMaterialFaces = function ( material ) { + + var doubleSided = material.side === THREE.DoubleSide; + var flipSided = material.side === THREE.BackSide; + + if ( _oldDoubleSided !== doubleSided ) { + + if ( doubleSided ) { + + _gl.disable( _gl.CULL_FACE ); + + } else { + + _gl.enable( _gl.CULL_FACE ); + + } + + _oldDoubleSided = doubleSided; + + } + + if ( _oldFlipSided !== flipSided ) { + + if ( flipSided ) { + + _gl.frontFace( _gl.CW ); + + } else { + + _gl.frontFace( _gl.CCW ); + + } + + _oldFlipSided = flipSided; + + } + + }; + + this.setDepthTest = function ( depthTest ) { + + if ( _oldDepthTest !== depthTest ) { + + if ( depthTest ) { + + _gl.enable( _gl.DEPTH_TEST ); + + } else { + + _gl.disable( _gl.DEPTH_TEST ); + + } + + _oldDepthTest = depthTest; + + } + + }; + + this.setDepthWrite = function ( depthWrite ) { + + if ( _oldDepthWrite !== depthWrite ) { + + _gl.depthMask( depthWrite ); + _oldDepthWrite = depthWrite; + + } + + }; + + function setLineWidth ( width ) { + + if ( width !== _oldLineWidth ) { + + _gl.lineWidth( width ); + + _oldLineWidth = width; + + } + + }; + + function setPolygonOffset ( polygonoffset, factor, units ) { + + if ( _oldPolygonOffset !== polygonoffset ) { + + if ( polygonoffset ) { + + _gl.enable( _gl.POLYGON_OFFSET_FILL ); + + } else { + + _gl.disable( _gl.POLYGON_OFFSET_FILL ); + + } + + _oldPolygonOffset = polygonoffset; + + } + + if ( polygonoffset && ( _oldPolygonOffsetFactor !== factor || _oldPolygonOffsetUnits !== units ) ) { + + _gl.polygonOffset( factor, units ); + + _oldPolygonOffsetFactor = factor; + _oldPolygonOffsetUnits = units; + + } + + }; + + this.setBlending = function ( blending, blendEquation, blendSrc, blendDst ) { + + if ( blending !== _oldBlending ) { + + if ( blending === THREE.NoBlending ) { + + _gl.disable( _gl.BLEND ); + + } else if ( blending === THREE.AdditiveBlending ) { + + _gl.enable( _gl.BLEND ); + _gl.blendEquation( _gl.FUNC_ADD ); + _gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE ); + + } else if ( blending === THREE.SubtractiveBlending ) { + + // TODO: Find blendFuncSeparate() combination + _gl.enable( _gl.BLEND ); + _gl.blendEquation( _gl.FUNC_ADD ); + _gl.blendFunc( _gl.ZERO, _gl.ONE_MINUS_SRC_COLOR ); + + } else if ( blending === THREE.MultiplyBlending ) { + + // TODO: Find blendFuncSeparate() combination + _gl.enable( _gl.BLEND ); + _gl.blendEquation( _gl.FUNC_ADD ); + _gl.blendFunc( _gl.ZERO, _gl.SRC_COLOR ); + + } else if ( blending === THREE.CustomBlending ) { + + _gl.enable( _gl.BLEND ); + + } else { + + _gl.enable( _gl.BLEND ); + _gl.blendEquationSeparate( _gl.FUNC_ADD, _gl.FUNC_ADD ); + _gl.blendFuncSeparate( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA, _gl.ONE, _gl.ONE_MINUS_SRC_ALPHA ); + + } + + _oldBlending = blending; + + } + + if ( blending === THREE.CustomBlending ) { + + if ( blendEquation !== _oldBlendEquation ) { + + _gl.blendEquation( paramThreeToGL( blendEquation ) ); + + _oldBlendEquation = blendEquation; + + } + + if ( blendSrc !== _oldBlendSrc || blendDst !== _oldBlendDst ) { + + _gl.blendFunc( paramThreeToGL( blendSrc ), paramThreeToGL( blendDst ) ); + + _oldBlendSrc = blendSrc; + _oldBlendDst = blendDst; + + } + + } else { + + _oldBlendEquation = null; + _oldBlendSrc = null; + _oldBlendDst = null; + + } + + }; + + // Defines + + function generateDefines ( defines ) { + + var value, chunk, chunks = []; + + for ( var d in defines ) { + + value = defines[ d ]; + if ( value === false ) continue; + + chunk = "#define " + d + " " + value; + chunks.push( chunk ); + + } + + return chunks.join( "\n" ); + + }; + + // Shaders + + function buildProgram ( shaderID, fragmentShader, vertexShader, uniforms, attributes, defines, parameters ) { + + var p, pl, d, program, code; + var chunks = []; + + // Generate code + + if ( shaderID ) { + + chunks.push( shaderID ); + + } else { + + chunks.push( fragmentShader ); + chunks.push( vertexShader ); + + } + + for ( d in defines ) { + + chunks.push( d ); + chunks.push( defines[ d ] ); + + } + + for ( p in parameters ) { + + chunks.push( p ); + chunks.push( parameters[ p ] ); + + } + + code = chunks.join(); + + // Check if code has been already compiled + + for ( p = 0, pl = _programs.length; p < pl; p ++ ) { + + var programInfo = _programs[ p ]; + + if ( programInfo.code === code ) { + + //console.log( "Code already compiled." /*: \n\n" + code*/ ); + + programInfo.usedTimes ++; + + return programInfo.program; + + } + + } + + var shadowMapTypeDefine = "SHADOWMAP_TYPE_BASIC"; + + if ( parameters.shadowMapType === THREE.PCFShadowMap ) { + + shadowMapTypeDefine = "SHADOWMAP_TYPE_PCF"; + + } else if ( parameters.shadowMapType === THREE.PCFSoftShadowMap ) { + + shadowMapTypeDefine = "SHADOWMAP_TYPE_PCF_SOFT"; + + } + + //console.log( "building new program " ); + + // + + var customDefines = generateDefines( defines ); + + // + + program = _gl.createProgram(); + + var prefix_vertex = [ + + "precision " + _precision + " float;", + + customDefines, + + _supportsVertexTextures ? "#define VERTEX_TEXTURES" : "", + + _this.gammaInput ? "#define GAMMA_INPUT" : "", + _this.gammaOutput ? "#define GAMMA_OUTPUT" : "", + _this.physicallyBasedShading ? "#define PHYSICALLY_BASED_SHADING" : "", + + "#define MAX_DIR_LIGHTS " + parameters.maxDirLights, + "#define MAX_POINT_LIGHTS " + parameters.maxPointLights, + "#define MAX_SPOT_LIGHTS " + parameters.maxSpotLights, + "#define MAX_HEMI_LIGHTS " + parameters.maxHemiLights, + + "#define MAX_SHADOWS " + parameters.maxShadows, + + "#define MAX_BONES " + parameters.maxBones, + + parameters.map ? "#define USE_MAP" : "", + parameters.envMap ? "#define USE_ENVMAP" : "", + parameters.lightMap ? "#define USE_LIGHTMAP" : "", + parameters.bumpMap ? "#define USE_BUMPMAP" : "", + parameters.normalMap ? "#define USE_NORMALMAP" : "", + parameters.specularMap ? "#define USE_SPECULARMAP" : "", + parameters.vertexColors ? "#define USE_COLOR" : "", + + parameters.skinning ? "#define USE_SKINNING" : "", + parameters.useVertexTexture ? "#define BONE_TEXTURE" : "", + parameters.boneTextureWidth ? "#define N_BONE_PIXEL_X " + parameters.boneTextureWidth.toFixed( 1 ) : "", + parameters.boneTextureHeight ? "#define N_BONE_PIXEL_Y " + parameters.boneTextureHeight.toFixed( 1 ) : "", + + parameters.morphTargets ? "#define USE_MORPHTARGETS" : "", + parameters.morphNormals ? "#define USE_MORPHNORMALS" : "", + parameters.perPixel ? "#define PHONG_PER_PIXEL" : "", + parameters.wrapAround ? "#define WRAP_AROUND" : "", + parameters.doubleSided ? "#define DOUBLE_SIDED" : "", + parameters.flipSided ? "#define FLIP_SIDED" : "", + + parameters.shadowMapEnabled ? "#define USE_SHADOWMAP" : "", + parameters.shadowMapEnabled ? "#define " + shadowMapTypeDefine : "", + parameters.shadowMapDebug ? "#define SHADOWMAP_DEBUG" : "", + parameters.shadowMapCascade ? "#define SHADOWMAP_CASCADE" : "", + + parameters.sizeAttenuation ? "#define USE_SIZEATTENUATION" : "", + + "uniform mat4 modelMatrix;", + "uniform mat4 modelViewMatrix;", + "uniform mat4 projectionMatrix;", + "uniform mat4 viewMatrix;", + "uniform mat3 normalMatrix;", + "uniform vec3 cameraPosition;", + + "attribute vec3 position;", + "attribute vec3 normal;", + "attribute vec2 uv;", + "attribute vec2 uv2;", + + "#ifdef USE_COLOR", + + "attribute vec3 color;", + + "#endif", + + "#ifdef USE_MORPHTARGETS", + + "attribute vec3 morphTarget0;", + "attribute vec3 morphTarget1;", + "attribute vec3 morphTarget2;", + "attribute vec3 morphTarget3;", + + "#ifdef USE_MORPHNORMALS", + + "attribute vec3 morphNormal0;", + "attribute vec3 morphNormal1;", + "attribute vec3 morphNormal2;", + "attribute vec3 morphNormal3;", + + "#else", + + "attribute vec3 morphTarget4;", + "attribute vec3 morphTarget5;", + "attribute vec3 morphTarget6;", + "attribute vec3 morphTarget7;", + + "#endif", + + "#endif", + + "#ifdef USE_SKINNING", + + "attribute vec4 skinIndex;", + "attribute vec4 skinWeight;", + + "#endif", + + "" + + ].join("\n"); + + var prefix_fragment = [ + + "precision " + _precision + " float;", + + ( parameters.bumpMap || parameters.normalMap ) ? "#extension GL_OES_standard_derivatives : enable" : "", + + customDefines, + + "#define MAX_DIR_LIGHTS " + parameters.maxDirLights, + "#define MAX_POINT_LIGHTS " + parameters.maxPointLights, + "#define MAX_SPOT_LIGHTS " + parameters.maxSpotLights, + "#define MAX_HEMI_LIGHTS " + parameters.maxHemiLights, + + "#define MAX_SHADOWS " + parameters.maxShadows, + + parameters.alphaTest ? "#define ALPHATEST " + parameters.alphaTest: "", + + _this.gammaInput ? "#define GAMMA_INPUT" : "", + _this.gammaOutput ? "#define GAMMA_OUTPUT" : "", + _this.physicallyBasedShading ? "#define PHYSICALLY_BASED_SHADING" : "", + + ( parameters.useFog && parameters.fog ) ? "#define USE_FOG" : "", + ( parameters.useFog && parameters.fogExp ) ? "#define FOG_EXP2" : "", + + parameters.map ? "#define USE_MAP" : "", + parameters.envMap ? "#define USE_ENVMAP" : "", + parameters.lightMap ? "#define USE_LIGHTMAP" : "", + parameters.bumpMap ? "#define USE_BUMPMAP" : "", + parameters.normalMap ? "#define USE_NORMALMAP" : "", + parameters.specularMap ? "#define USE_SPECULARMAP" : "", + parameters.vertexColors ? "#define USE_COLOR" : "", + + parameters.metal ? "#define METAL" : "", + parameters.perPixel ? "#define PHONG_PER_PIXEL" : "", + parameters.wrapAround ? "#define WRAP_AROUND" : "", + parameters.doubleSided ? "#define DOUBLE_SIDED" : "", + parameters.flipSided ? "#define FLIP_SIDED" : "", + + parameters.shadowMapEnabled ? "#define USE_SHADOWMAP" : "", + parameters.shadowMapEnabled ? "#define " + shadowMapTypeDefine : "", + parameters.shadowMapDebug ? "#define SHADOWMAP_DEBUG" : "", + parameters.shadowMapCascade ? "#define SHADOWMAP_CASCADE" : "", + + "uniform mat4 viewMatrix;", + "uniform vec3 cameraPosition;", + "" + + ].join("\n"); + + var glFragmentShader = getShader( "fragment", prefix_fragment + fragmentShader ); + var glVertexShader = getShader( "vertex", prefix_vertex + vertexShader ); + + _gl.attachShader( program, glVertexShader ); + _gl.attachShader( program, glFragmentShader ); + + _gl.linkProgram( program ); + + if ( !_gl.getProgramParameter( program, _gl.LINK_STATUS ) ) { + + console.error( "Could not initialise shader\n" + "VALIDATE_STATUS: " + _gl.getProgramParameter( program, _gl.VALIDATE_STATUS ) + ", gl error [" + _gl.getError() + "]" ); + + } + + // clean up + + _gl.deleteShader( glFragmentShader ); + _gl.deleteShader( glVertexShader ); + + //console.log( prefix_fragment + fragmentShader ); + //console.log( prefix_vertex + vertexShader ); + + program.uniforms = {}; + program.attributes = {}; + + var identifiers, u, a, i; + + // cache uniform locations + + identifiers = [ + + 'viewMatrix', 'modelViewMatrix', 'projectionMatrix', 'normalMatrix', 'modelMatrix', 'cameraPosition', + 'morphTargetInfluences' + + ]; + + if ( parameters.useVertexTexture ) { + + identifiers.push( 'boneTexture' ); + + } else { + + identifiers.push( 'boneGlobalMatrices' ); + + } + + for ( u in uniforms ) { + + identifiers.push( u ); + + } + + cacheUniformLocations( program, identifiers ); + + // cache attributes locations + + identifiers = [ + + "position", "normal", "uv", "uv2", "tangent", "color", + "skinIndex", "skinWeight", "lineDistance" + + ]; + + for ( i = 0; i < parameters.maxMorphTargets; i ++ ) { + + identifiers.push( "morphTarget" + i ); + + } + + for ( i = 0; i < parameters.maxMorphNormals; i ++ ) { + + identifiers.push( "morphNormal" + i ); + + } + + for ( a in attributes ) { + + identifiers.push( a ); + + } + + cacheAttributeLocations( program, identifiers ); + + program.id = _programs_counter ++; + + _programs.push( { program: program, code: code, usedTimes: 1 } ); + + _this.info.memory.programs = _programs.length; + + return program; + + }; + + // Shader parameters cache + + function cacheUniformLocations ( program, identifiers ) { + + var i, l, id; + + for( i = 0, l = identifiers.length; i < l; i ++ ) { + + id = identifiers[ i ]; + program.uniforms[ id ] = _gl.getUniformLocation( program, id ); + + } + + }; + + function cacheAttributeLocations ( program, identifiers ) { + + var i, l, id; + + for( i = 0, l = identifiers.length; i < l; i ++ ) { + + id = identifiers[ i ]; + program.attributes[ id ] = _gl.getAttribLocation( program, id ); + + } + + }; + + function addLineNumbers ( string ) { + + var chunks = string.split( "\n" ); + + for ( var i = 0, il = chunks.length; i < il; i ++ ) { + + // Chrome reports shader errors on lines + // starting counting from 1 + + chunks[ i ] = ( i + 1 ) + ": " + chunks[ i ]; + + } + + return chunks.join( "\n" ); + + }; + + function getShader ( type, string ) { + + var shader; + + if ( type === "fragment" ) { + + shader = _gl.createShader( _gl.FRAGMENT_SHADER ); + + } else if ( type === "vertex" ) { + + shader = _gl.createShader( _gl.VERTEX_SHADER ); + + } + + _gl.shaderSource( shader, string ); + _gl.compileShader( shader ); + + if ( !_gl.getShaderParameter( shader, _gl.COMPILE_STATUS ) ) { + + console.error( _gl.getShaderInfoLog( shader ) ); + console.error( addLineNumbers( string ) ); + return null; + + } + + return shader; + + }; + + // Textures + + + function isPowerOfTwo ( value ) { + + return ( value & ( value - 1 ) ) === 0; + + }; + + function setTextureParameters ( textureType, texture, isImagePowerOfTwo ) { + + if ( isImagePowerOfTwo ) { + + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, paramThreeToGL( texture.wrapS ) ); + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, paramThreeToGL( texture.wrapT ) ); + + _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, paramThreeToGL( texture.magFilter ) ); + _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, paramThreeToGL( texture.minFilter ) ); + + } else { + + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE ); + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE ); + + _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) ); + _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) ); + + } + + if ( _glExtensionTextureFilterAnisotropic && texture.type !== THREE.FloatType ) { + + if ( texture.anisotropy > 1 || texture.__oldAnisotropy ) { + + _gl.texParameterf( textureType, _glExtensionTextureFilterAnisotropic.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, _maxAnisotropy ) ); + texture.__oldAnisotropy = texture.anisotropy; + + } + + } + + }; + + this.setTexture = function ( texture, slot ) { + + if ( texture.needsUpdate ) { + + if ( ! texture.__webglInit ) { + + texture.__webglInit = true; + + texture.addEventListener( 'dispose', onTextureDispose ); + + texture.__webglTexture = _gl.createTexture(); + + _this.info.memory.textures ++; + + } + + _gl.activeTexture( _gl.TEXTURE0 + slot ); + _gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture ); + + _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); + _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha ); + _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment ); + + var image = texture.image, + isImagePowerOfTwo = isPowerOfTwo( image.width ) && isPowerOfTwo( image.height ), + glFormat = paramThreeToGL( texture.format ), + glType = paramThreeToGL( texture.type ); + + setTextureParameters( _gl.TEXTURE_2D, texture, isImagePowerOfTwo ); + + var mipmap, mipmaps = texture.mipmaps; + + if ( texture instanceof THREE.DataTexture ) { + + // use manually created mipmaps if available + // if there are no manual mipmaps + // set 0 level mipmap and then use GL to generate other mipmap levels + + if ( mipmaps.length > 0 && isImagePowerOfTwo ) { + + for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { + + mipmap = mipmaps[ i ]; + _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); + + } + + texture.generateMipmaps = false; + + } else { + + _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data ); + + } + + } else if ( texture instanceof THREE.CompressedTexture ) { + + // compressed textures can only use manually created mipmaps + // WebGL can't generate mipmaps for DDS textures + + for( var i = 0, il = mipmaps.length; i < il; i ++ ) { + + mipmap = mipmaps[ i ]; + _gl.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); + + } + + } else { // regular Texture (image, video, canvas) + + // use manually created mipmaps if available + // if there are no manual mipmaps + // set 0 level mipmap and then use GL to generate other mipmap levels + + if ( mipmaps.length > 0 && isImagePowerOfTwo ) { + + for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { + + mipmap = mipmaps[ i ]; + _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap ); + + } + + texture.generateMipmaps = false; + + } else { + + _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, texture.image ); + + } + + } + + if ( texture.generateMipmaps && isImagePowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D ); + + texture.needsUpdate = false; + + if ( texture.onUpdate ) texture.onUpdate(); + + } else { + + _gl.activeTexture( _gl.TEXTURE0 + slot ); + _gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture ); + + } + + }; + + function clampToMaxSize ( image, maxSize ) { + + if ( image.width <= maxSize && image.height <= maxSize ) { + + return image; + + } + + // Warning: Scaling through the canvas will only work with images that use + // premultiplied alpha. + + var maxDimension = Math.max( image.width, image.height ); + var newWidth = Math.floor( image.width * maxSize / maxDimension ); + var newHeight = Math.floor( image.height * maxSize / maxDimension ); + + var canvas = document.createElement( 'canvas' ); + canvas.width = newWidth; + canvas.height = newHeight; + + var ctx = canvas.getContext( "2d" ); + ctx.drawImage( image, 0, 0, image.width, image.height, 0, 0, newWidth, newHeight ); + + return canvas; + + } + + function setCubeTexture ( texture, slot ) { + + if ( texture.image.length === 6 ) { + + if ( texture.needsUpdate ) { + + if ( ! texture.image.__webglTextureCube ) { + + texture.image.__webglTextureCube = _gl.createTexture(); + + _this.info.memory.textures ++; + + } + + _gl.activeTexture( _gl.TEXTURE0 + slot ); + _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube ); + + _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); + + var isCompressed = texture instanceof THREE.CompressedTexture; + + var cubeImage = []; + + for ( var i = 0; i < 6; i ++ ) { + + if ( _this.autoScaleCubemaps && ! isCompressed ) { + + cubeImage[ i ] = clampToMaxSize( texture.image[ i ], _maxCubemapSize ); + + } else { + + cubeImage[ i ] = texture.image[ i ]; + + } + + } + + var image = cubeImage[ 0 ], + isImagePowerOfTwo = isPowerOfTwo( image.width ) && isPowerOfTwo( image.height ), + glFormat = paramThreeToGL( texture.format ), + glType = paramThreeToGL( texture.type ); + + setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, isImagePowerOfTwo ); + + for ( var i = 0; i < 6; i ++ ) { + + if ( isCompressed ) { + + var mipmap, mipmaps = cubeImage[ i ].mipmaps; + + for( var j = 0, jl = mipmaps.length; j < jl; j ++ ) { + + mipmap = mipmaps[ j ]; + _gl.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); + + } + + } else { + + _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] ); + + } + + } + + if ( texture.generateMipmaps && isImagePowerOfTwo ) { + + _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); + + } + + texture.needsUpdate = false; + + if ( texture.onUpdate ) texture.onUpdate(); + + } else { + + _gl.activeTexture( _gl.TEXTURE0 + slot ); + _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube ); + + } + + } + + }; + + function setCubeTextureDynamic ( texture, slot ) { + + _gl.activeTexture( _gl.TEXTURE0 + slot ); + _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.__webglTexture ); + + }; + + // Render targets + + function setupFrameBuffer ( framebuffer, renderTarget, textureTarget ) { + + _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); + _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureTarget, renderTarget.__webglTexture, 0 ); + + }; + + function setupRenderBuffer ( renderbuffer, renderTarget ) { + + _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer ); + + if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { + + _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height ); + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); + + /* For some reason this is not working. Defaulting to RGBA4. + } else if( ! renderTarget.depthBuffer && renderTarget.stencilBuffer ) { + + _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.STENCIL_INDEX8, renderTarget.width, renderTarget.height ); + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); + */ + } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { + + _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height ); + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); + + } else { + + _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height ); + + } + + }; + + this.setRenderTarget = function ( renderTarget ) { + + var isCube = ( renderTarget instanceof THREE.WebGLRenderTargetCube ); + + if ( renderTarget && ! renderTarget.__webglFramebuffer ) { + + if ( renderTarget.depthBuffer === undefined ) renderTarget.depthBuffer = true; + if ( renderTarget.stencilBuffer === undefined ) renderTarget.stencilBuffer = true; + + renderTarget.addEventListener( 'dispose', onRenderTargetDispose ); + + renderTarget.__webglTexture = _gl.createTexture(); + + _this.info.memory.textures ++; + + // Setup texture, create render and frame buffers + + var isTargetPowerOfTwo = isPowerOfTwo( renderTarget.width ) && isPowerOfTwo( renderTarget.height ), + glFormat = paramThreeToGL( renderTarget.format ), + glType = paramThreeToGL( renderTarget.type ); + + if ( isCube ) { + + renderTarget.__webglFramebuffer = []; + renderTarget.__webglRenderbuffer = []; + + _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture ); + setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget, isTargetPowerOfTwo ); + + for ( var i = 0; i < 6; i ++ ) { + + renderTarget.__webglFramebuffer[ i ] = _gl.createFramebuffer(); + renderTarget.__webglRenderbuffer[ i ] = _gl.createRenderbuffer(); + + _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); + + setupFrameBuffer( renderTarget.__webglFramebuffer[ i ], renderTarget, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i ); + setupRenderBuffer( renderTarget.__webglRenderbuffer[ i ], renderTarget ); + + } + + if ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); + + } else { + + renderTarget.__webglFramebuffer = _gl.createFramebuffer(); + + if ( renderTarget.shareDepthFrom ) { + + renderTarget.__webglRenderbuffer = renderTarget.shareDepthFrom.__webglRenderbuffer; + + } else { + + renderTarget.__webglRenderbuffer = _gl.createRenderbuffer(); + + } + + _gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture ); + setTextureParameters( _gl.TEXTURE_2D, renderTarget, isTargetPowerOfTwo ); + + _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); + + setupFrameBuffer( renderTarget.__webglFramebuffer, renderTarget, _gl.TEXTURE_2D ); + + if ( renderTarget.shareDepthFrom ) { + + if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { + + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer ); + + } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { + + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer ); + + } + + } else { + + setupRenderBuffer( renderTarget.__webglRenderbuffer, renderTarget ); + + } + + if ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D ); + + } + + // Release everything + + if ( isCube ) { + + _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null ); + + } else { + + _gl.bindTexture( _gl.TEXTURE_2D, null ); + + } + + _gl.bindRenderbuffer( _gl.RENDERBUFFER, null ); + _gl.bindFramebuffer( _gl.FRAMEBUFFER, null ); + + } + + var framebuffer, width, height, vx, vy; + + if ( renderTarget ) { + + if ( isCube ) { + + framebuffer = renderTarget.__webglFramebuffer[ renderTarget.activeCubeFace ]; + + } else { + + framebuffer = renderTarget.__webglFramebuffer; + + } + + width = renderTarget.width; + height = renderTarget.height; + + vx = 0; + vy = 0; + + } else { + + framebuffer = null; + + width = _viewportWidth; + height = _viewportHeight; + + vx = _viewportX; + vy = _viewportY; + + } + + if ( framebuffer !== _currentFramebuffer ) { + + _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); + _gl.viewport( vx, vy, width, height ); + + _currentFramebuffer = framebuffer; + + } + + _currentWidth = width; + _currentHeight = height; + + }; + + function updateRenderTargetMipmap ( renderTarget ) { + + if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) { + + _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture ); + _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); + _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null ); + + } else { + + _gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture ); + _gl.generateMipmap( _gl.TEXTURE_2D ); + _gl.bindTexture( _gl.TEXTURE_2D, null ); + + } + + }; + + // Fallback filters for non-power-of-2 textures + + function filterFallback ( f ) { + + if ( f === THREE.NearestFilter || f === THREE.NearestMipMapNearestFilter || f === THREE.NearestMipMapLinearFilter ) { + + return _gl.NEAREST; + + } + + return _gl.LINEAR; + + }; + + // Map three.js constants to WebGL constants + + function paramThreeToGL ( p ) { + + if ( p === THREE.RepeatWrapping ) return _gl.REPEAT; + if ( p === THREE.ClampToEdgeWrapping ) return _gl.CLAMP_TO_EDGE; + if ( p === THREE.MirroredRepeatWrapping ) return _gl.MIRRORED_REPEAT; + + if ( p === THREE.NearestFilter ) return _gl.NEAREST; + if ( p === THREE.NearestMipMapNearestFilter ) return _gl.NEAREST_MIPMAP_NEAREST; + if ( p === THREE.NearestMipMapLinearFilter ) return _gl.NEAREST_MIPMAP_LINEAR; + + if ( p === THREE.LinearFilter ) return _gl.LINEAR; + if ( p === THREE.LinearMipMapNearestFilter ) return _gl.LINEAR_MIPMAP_NEAREST; + if ( p === THREE.LinearMipMapLinearFilter ) return _gl.LINEAR_MIPMAP_LINEAR; + + if ( p === THREE.UnsignedByteType ) return _gl.UNSIGNED_BYTE; + if ( p === THREE.UnsignedShort4444Type ) return _gl.UNSIGNED_SHORT_4_4_4_4; + if ( p === THREE.UnsignedShort5551Type ) return _gl.UNSIGNED_SHORT_5_5_5_1; + if ( p === THREE.UnsignedShort565Type ) return _gl.UNSIGNED_SHORT_5_6_5; + + if ( p === THREE.ByteType ) return _gl.BYTE; + if ( p === THREE.ShortType ) return _gl.SHORT; + if ( p === THREE.UnsignedShortType ) return _gl.UNSIGNED_SHORT; + if ( p === THREE.IntType ) return _gl.INT; + if ( p === THREE.UnsignedIntType ) return _gl.UNSIGNED_INT; + if ( p === THREE.FloatType ) return _gl.FLOAT; + + if ( p === THREE.AlphaFormat ) return _gl.ALPHA; + if ( p === THREE.RGBFormat ) return _gl.RGB; + if ( p === THREE.RGBAFormat ) return _gl.RGBA; + if ( p === THREE.LuminanceFormat ) return _gl.LUMINANCE; + if ( p === THREE.LuminanceAlphaFormat ) return _gl.LUMINANCE_ALPHA; + + if ( p === THREE.AddEquation ) return _gl.FUNC_ADD; + if ( p === THREE.SubtractEquation ) return _gl.FUNC_SUBTRACT; + if ( p === THREE.ReverseSubtractEquation ) return _gl.FUNC_REVERSE_SUBTRACT; + + if ( p === THREE.ZeroFactor ) return _gl.ZERO; + if ( p === THREE.OneFactor ) return _gl.ONE; + if ( p === THREE.SrcColorFactor ) return _gl.SRC_COLOR; + if ( p === THREE.OneMinusSrcColorFactor ) return _gl.ONE_MINUS_SRC_COLOR; + if ( p === THREE.SrcAlphaFactor ) return _gl.SRC_ALPHA; + if ( p === THREE.OneMinusSrcAlphaFactor ) return _gl.ONE_MINUS_SRC_ALPHA; + if ( p === THREE.DstAlphaFactor ) return _gl.DST_ALPHA; + if ( p === THREE.OneMinusDstAlphaFactor ) return _gl.ONE_MINUS_DST_ALPHA; + + if ( p === THREE.DstColorFactor ) return _gl.DST_COLOR; + if ( p === THREE.OneMinusDstColorFactor ) return _gl.ONE_MINUS_DST_COLOR; + if ( p === THREE.SrcAlphaSaturateFactor ) return _gl.SRC_ALPHA_SATURATE; + + if ( _glExtensionCompressedTextureS3TC !== undefined ) { + + if ( p === THREE.RGB_S3TC_DXT1_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGB_S3TC_DXT1_EXT; + if ( p === THREE.RGBA_S3TC_DXT1_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT1_EXT; + if ( p === THREE.RGBA_S3TC_DXT3_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT3_EXT; + if ( p === THREE.RGBA_S3TC_DXT5_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT5_EXT; + + } + + return 0; + + }; + + // Allocations + + function allocateBones ( object ) { + + if ( _supportsBoneTextures && object && object.useVertexTexture ) { + + return 1024; + + } else { + + // default for when object is not specified + // ( for example when prebuilding shader + // to be used with multiple objects ) + // + // - leave some extra space for other uniforms + // - limit here is ANGLE's 254 max uniform vectors + // (up to 54 should be safe) + + var nVertexUniforms = _gl.getParameter( _gl.MAX_VERTEX_UNIFORM_VECTORS ); + var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 ); + + var maxBones = nVertexMatrices; + + if ( object !== undefined && object instanceof THREE.SkinnedMesh ) { + + maxBones = Math.min( object.bones.length, maxBones ); + + if ( maxBones < object.bones.length ) { + + console.warn( "WebGLRenderer: too many bones - " + object.bones.length + ", this GPU supports just " + maxBones + " (try OpenGL instead of ANGLE)" ); + + } + + } + + return maxBones; + + } + + }; + + function allocateLights ( lights ) { + + var l, ll, light, dirLights, pointLights, spotLights, hemiLights; + + dirLights = pointLights = spotLights = hemiLights = 0; + + for ( l = 0, ll = lights.length; l < ll; l ++ ) { + + light = lights[ l ]; + + if ( light.onlyShadow ) continue; + + if ( light instanceof THREE.DirectionalLight ) dirLights ++; + if ( light instanceof THREE.PointLight ) pointLights ++; + if ( light instanceof THREE.SpotLight ) spotLights ++; + if ( light instanceof THREE.HemisphereLight ) hemiLights ++; + + } + + return { 'directional' : dirLights, 'point' : pointLights, 'spot': spotLights, 'hemi': hemiLights }; + + }; + + function allocateShadows ( lights ) { + + var l, ll, light, maxShadows = 0; + + for ( l = 0, ll = lights.length; l < ll; l++ ) { + + light = lights[ l ]; + + if ( ! light.castShadow ) continue; + + if ( light instanceof THREE.SpotLight ) maxShadows ++; + if ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) maxShadows ++; + + } + + return maxShadows; + + }; + + // Initialization + + function initGL () { + + try { + + if ( ! ( _gl = _canvas.getContext( 'experimental-webgl', { alpha: _alpha, premultipliedAlpha: _premultipliedAlpha, antialias: _antialias, stencil: _stencil, preserveDrawingBuffer: _preserveDrawingBuffer } ) ) ) { + + throw 'Error creating WebGL context.'; + + } + + } catch ( error ) { + + console.error( error ); + + } + + _glExtensionTextureFloat = _gl.getExtension( 'OES_texture_float' ); + _glExtensionStandardDerivatives = _gl.getExtension( 'OES_standard_derivatives' ); + + _glExtensionTextureFilterAnisotropic = _gl.getExtension( 'EXT_texture_filter_anisotropic' ) || + _gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || + _gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' ); + + + _glExtensionCompressedTextureS3TC = _gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || + _gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || + _gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' ); + + if ( ! _glExtensionTextureFloat ) { + + console.log( 'THREE.WebGLRenderer: Float textures not supported.' ); + + } + + if ( ! _glExtensionStandardDerivatives ) { + + console.log( 'THREE.WebGLRenderer: Standard derivatives not supported.' ); + + } + + if ( ! _glExtensionTextureFilterAnisotropic ) { + + console.log( 'THREE.WebGLRenderer: Anisotropic texture filtering not supported.' ); + + } + + if ( ! _glExtensionCompressedTextureS3TC ) { + + console.log( 'THREE.WebGLRenderer: S3TC compressed textures not supported.' ); + + } + + if ( _gl.getShaderPrecisionFormat === undefined ) { + + _gl.getShaderPrecisionFormat = function() { + + return { + "rangeMin" : 1, + "rangeMax" : 1, + "precision" : 1 + }; + + } + } + + }; + + function setDefaultGLState () { + + _gl.clearColor( 0, 0, 0, 1 ); + _gl.clearDepth( 1 ); + _gl.clearStencil( 0 ); + + _gl.enable( _gl.DEPTH_TEST ); + _gl.depthFunc( _gl.LEQUAL ); + + _gl.frontFace( _gl.CCW ); + _gl.cullFace( _gl.BACK ); + _gl.enable( _gl.CULL_FACE ); + + _gl.enable( _gl.BLEND ); + _gl.blendEquation( _gl.FUNC_ADD ); + _gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA ); + + _gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); + + }; + + // default plugins (order is important) + + this.shadowMapPlugin = new THREE.ShadowMapPlugin(); + this.addPrePlugin( this.shadowMapPlugin ); + + this.addPostPlugin( new THREE.SpritePlugin() ); + this.addPostPlugin( new THREE.LensFlarePlugin() ); + +}; +/** + * @author szimek / https://github.com/szimek/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.WebGLRenderTarget = function ( width, height, options ) { + + THREE.EventDispatcher.call( this ); + + this.width = width; + this.height = height; + + options = options || {}; + + this.wrapS = options.wrapS !== undefined ? options.wrapS : THREE.ClampToEdgeWrapping; + this.wrapT = options.wrapT !== undefined ? options.wrapT : THREE.ClampToEdgeWrapping; + + this.magFilter = options.magFilter !== undefined ? options.magFilter : THREE.LinearFilter; + this.minFilter = options.minFilter !== undefined ? options.minFilter : THREE.LinearMipMapLinearFilter; + + this.anisotropy = options.anisotropy !== undefined ? options.anisotropy : 1; + + this.offset = new THREE.Vector2( 0, 0 ); + this.repeat = new THREE.Vector2( 1, 1 ); + + this.format = options.format !== undefined ? options.format : THREE.RGBAFormat; + this.type = options.type !== undefined ? options.type : THREE.UnsignedByteType; + + this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true; + this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : true; + + this.generateMipmaps = true; + + this.shareDepthFrom = null; + +}; + +THREE.WebGLRenderTarget.prototype.clone = function() { + + var tmp = new THREE.WebGLRenderTarget( this.width, this.height ); + + tmp.wrapS = this.wrapS; + tmp.wrapT = this.wrapT; + + tmp.magFilter = this.magFilter; + tmp.minFilter = this.minFilter; + + tmp.anisotropy = this.anisotropy; + + tmp.offset.copy( this.offset ); + tmp.repeat.copy( this.repeat ); + + tmp.format = this.format; + tmp.type = this.type; + + tmp.depthBuffer = this.depthBuffer; + tmp.stencilBuffer = this.stencilBuffer; + + tmp.generateMipmaps = this.generateMipmaps; + + tmp.shareDepthFrom = this.shareDepthFrom; + + return tmp; + +}; + +THREE.WebGLRenderTarget.prototype.dispose = function () { + + this.dispatchEvent( { type: 'dispose' } ); + +}; +/** + * @author alteredq / http://alteredqualia.com + */ + +THREE.WebGLRenderTargetCube = function ( width, height, options ) { + + THREE.WebGLRenderTarget.call( this, width, height, options ); + + this.activeCubeFace = 0; // PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5 + +}; + +THREE.WebGLRenderTargetCube.prototype = Object.create( THREE.WebGLRenderTarget.prototype ); +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.RenderableVertex = function () { + + this.positionWorld = new THREE.Vector3(); + this.positionScreen = new THREE.Vector4(); + + this.visible = true; + +}; + +THREE.RenderableVertex.prototype.copy = function ( vertex ) { + + this.positionWorld.copy( vertex.positionWorld ); + this.positionScreen.copy( vertex.positionScreen ); + +}; +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.RenderableFace3 = function () { + + this.v1 = new THREE.RenderableVertex(); + this.v2 = new THREE.RenderableVertex(); + this.v3 = new THREE.RenderableVertex(); + + this.centroidModel = new THREE.Vector3(); + + this.normalModel = new THREE.Vector3(); + this.normalModelView = new THREE.Vector3(); + + this.vertexNormalsLength = 0; + this.vertexNormalsModel = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ]; + this.vertexNormalsModelView = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ]; + + this.color = null; + this.material = null; + this.uvs = [[]]; + + this.z = null; + +}; +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.RenderableFace4 = function () { + + this.v1 = new THREE.RenderableVertex(); + this.v2 = new THREE.RenderableVertex(); + this.v3 = new THREE.RenderableVertex(); + this.v4 = new THREE.RenderableVertex(); + + this.centroidModel = new THREE.Vector3(); + + this.normalModel = new THREE.Vector3(); + this.normalModelView = new THREE.Vector3(); + + this.vertexNormalsLength = 0; + this.vertexNormalsModel = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ]; + this.vertexNormalsModelView = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ]; + + this.color = null; + this.material = null; + this.uvs = [[]]; + + this.z = null; + +}; +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.RenderableObject = function () { + + this.object = null; + this.z = null; + +}; +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.RenderableParticle = function () { + + this.object = null; + + this.x = null; + this.y = null; + this.z = null; + + this.rotation = null; + this.scale = new THREE.Vector2(); + + this.material = null; + +}; +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.RenderableLine = function () { + + this.z = null; + + this.v1 = new THREE.RenderableVertex(); + this.v2 = new THREE.RenderableVertex(); + + this.material = null; + +}; +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.GeometryUtils = { + + // Merge two geometries or geometry and geometry from object (using object's transform) + + merge: function ( geometry1, object2 /* mesh | geometry */ ) { + + var matrix, normalMatrix, + vertexOffset = geometry1.vertices.length, + uvPosition = geometry1.faceVertexUvs[ 0 ].length, + geometry2 = object2 instanceof THREE.Mesh ? object2.geometry : object2, + vertices1 = geometry1.vertices, + vertices2 = geometry2.vertices, + faces1 = geometry1.faces, + faces2 = geometry2.faces, + uvs1 = geometry1.faceVertexUvs[ 0 ], + uvs2 = geometry2.faceVertexUvs[ 0 ]; + + if ( object2 instanceof THREE.Mesh ) { + + object2.matrixAutoUpdate && object2.updateMatrix(); + + matrix = object2.matrix; + + normalMatrix = new THREE.Matrix3(); + normalMatrix.getInverse( matrix ); + normalMatrix.transpose(); + + } + + // vertices + + for ( var i = 0, il = vertices2.length; i < il; i ++ ) { + + var vertex = vertices2[ i ]; + + var vertexCopy = vertex.clone(); + + if ( matrix ) vertexCopy.applyMatrix4( matrix ); + + vertices1.push( vertexCopy ); + + } + + // faces + + for ( i = 0, il = faces2.length; i < il; i ++ ) { + + var face = faces2[ i ], faceCopy, normal, color, + faceVertexNormals = face.vertexNormals, + faceVertexColors = face.vertexColors; + + if ( face instanceof THREE.Face3 ) { + + faceCopy = new THREE.Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset ); + + } else if ( face instanceof THREE.Face4 ) { + + faceCopy = new THREE.Face4( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset, face.d + vertexOffset ); + + } + + faceCopy.normal.copy( face.normal ); + + if ( normalMatrix ) { + + faceCopy.normal.applyMatrix3( normalMatrix ).normalize(); + + } + + for ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) { + + normal = faceVertexNormals[ j ].clone(); + + if ( normalMatrix ) { + + normal.applyMatrix3( normalMatrix ).normalize(); + + } + + faceCopy.vertexNormals.push( normal ); + + } + + faceCopy.color.copy( face.color ); + + for ( var j = 0, jl = faceVertexColors.length; j < jl; j ++ ) { + + color = faceVertexColors[ j ]; + faceCopy.vertexColors.push( color.clone() ); + + } + + faceCopy.materialIndex = face.materialIndex; + + faceCopy.centroid.copy( face.centroid ); + + if ( matrix ) { + + faceCopy.centroid.applyMatrix4( matrix ); + + } + + faces1.push( faceCopy ); + + } + + // uvs + + for ( i = 0, il = uvs2.length; i < il; i ++ ) { + + var uv = uvs2[ i ], uvCopy = []; + + for ( var j = 0, jl = uv.length; j < jl; j ++ ) { + + uvCopy.push( new THREE.Vector2( uv[ j ].x, uv[ j ].y ) ); + + } + + uvs1.push( uvCopy ); + + } + + }, + + removeMaterials: function ( geometry, materialIndexArray ) { + + var materialIndexMap = {}; + + for ( var i = 0, il = materialIndexArray.length; i < il; i ++ ) { + + materialIndexMap[ materialIndexArray[i] ] = true; + + } + + var face, newFaces = []; + + for ( var i = 0, il = geometry.faces.length; i < il; i ++ ) { + + face = geometry.faces[ i ]; + if ( ! ( face.materialIndex in materialIndexMap ) ) newFaces.push( face ); + + } + + geometry.faces = newFaces; + + }, + + // Get random point in triangle (via barycentric coordinates) + // (uniform distribution) + // http://www.cgafaq.info/wiki/Random_Point_In_Triangle + + randomPointInTriangle: function ( vectorA, vectorB, vectorC ) { + + var a, b, c, + point = new THREE.Vector3(), + tmp = THREE.GeometryUtils.__v1; + + a = THREE.GeometryUtils.random(); + b = THREE.GeometryUtils.random(); + + if ( ( a + b ) > 1 ) { + + a = 1 - a; + b = 1 - b; + + } + + c = 1 - a - b; + + point.copy( vectorA ); + point.multiplyScalar( a ); + + tmp.copy( vectorB ); + tmp.multiplyScalar( b ); + + point.add( tmp ); + + tmp.copy( vectorC ); + tmp.multiplyScalar( c ); + + point.add( tmp ); + + return point; + + }, + + // Get random point in face (triangle / quad) + // (uniform distribution) + + randomPointInFace: function ( face, geometry, useCachedAreas ) { + + var vA, vB, vC, vD; + + if ( face instanceof THREE.Face3 ) { + + vA = geometry.vertices[ face.a ]; + vB = geometry.vertices[ face.b ]; + vC = geometry.vertices[ face.c ]; + + return THREE.GeometryUtils.randomPointInTriangle( vA, vB, vC ); + + } else if ( face instanceof THREE.Face4 ) { + + vA = geometry.vertices[ face.a ]; + vB = geometry.vertices[ face.b ]; + vC = geometry.vertices[ face.c ]; + vD = geometry.vertices[ face.d ]; + + var area1, area2; + + if ( useCachedAreas ) { + + if ( face._area1 && face._area2 ) { + + area1 = face._area1; + area2 = face._area2; + + } else { + + area1 = THREE.GeometryUtils.triangleArea( vA, vB, vD ); + area2 = THREE.GeometryUtils.triangleArea( vB, vC, vD ); + + face._area1 = area1; + face._area2 = area2; + + } + + } else { + + area1 = THREE.GeometryUtils.triangleArea( vA, vB, vD ), + area2 = THREE.GeometryUtils.triangleArea( vB, vC, vD ); + + } + + var r = THREE.GeometryUtils.random() * ( area1 + area2 ); + + if ( r < area1 ) { + + return THREE.GeometryUtils.randomPointInTriangle( vA, vB, vD ); + + } else { + + return THREE.GeometryUtils.randomPointInTriangle( vB, vC, vD ); + + } + + } + + }, + + // Get uniformly distributed random points in mesh + // - create array with cumulative sums of face areas + // - pick random number from 0 to total area + // - find corresponding place in area array by binary search + // - get random point in face + + randomPointsInGeometry: function ( geometry, n ) { + + var face, i, + faces = geometry.faces, + vertices = geometry.vertices, + il = faces.length, + totalArea = 0, + cumulativeAreas = [], + vA, vB, vC, vD; + + // precompute face areas + + for ( i = 0; i < il; i ++ ) { + + face = faces[ i ]; + + if ( face instanceof THREE.Face3 ) { + + vA = vertices[ face.a ]; + vB = vertices[ face.b ]; + vC = vertices[ face.c ]; + + face._area = THREE.GeometryUtils.triangleArea( vA, vB, vC ); + + } else if ( face instanceof THREE.Face4 ) { + + vA = vertices[ face.a ]; + vB = vertices[ face.b ]; + vC = vertices[ face.c ]; + vD = vertices[ face.d ]; + + face._area1 = THREE.GeometryUtils.triangleArea( vA, vB, vD ); + face._area2 = THREE.GeometryUtils.triangleArea( vB, vC, vD ); + + face._area = face._area1 + face._area2; + + } + + totalArea += face._area; + + cumulativeAreas[ i ] = totalArea; + + } + + // binary search cumulative areas array + + function binarySearchIndices( value ) { + + function binarySearch( start, end ) { + + // return closest larger index + // if exact number is not found + + if ( end < start ) + return start; + + var mid = start + Math.floor( ( end - start ) / 2 ); + + if ( cumulativeAreas[ mid ] > value ) { + + return binarySearch( start, mid - 1 ); + + } else if ( cumulativeAreas[ mid ] < value ) { + + return binarySearch( mid + 1, end ); + + } else { + + return mid; + + } + + } + + var result = binarySearch( 0, cumulativeAreas.length - 1 ) + return result; + + } + + // pick random face weighted by face area + + var r, index, + result = []; + + var stats = {}; + + for ( i = 0; i < n; i ++ ) { + + r = THREE.GeometryUtils.random() * totalArea; + + index = binarySearchIndices( r ); + + result[ i ] = THREE.GeometryUtils.randomPointInFace( faces[ index ], geometry, true ); + + if ( ! stats[ index ] ) { + + stats[ index ] = 1; + + } else { + + stats[ index ] += 1; + + } + + } + + return result; + + }, + + // Get triangle area (half of parallelogram) + // http://mathworld.wolfram.com/TriangleArea.html + + triangleArea: function ( vectorA, vectorB, vectorC ) { + + var tmp1 = THREE.GeometryUtils.__v1, + tmp2 = THREE.GeometryUtils.__v2; + + tmp1.subVectors( vectorB, vectorA ); + tmp2.subVectors( vectorC, vectorA ); + tmp1.cross( tmp2 ); + + return 0.5 * tmp1.length(); + + }, + + // Center geometry so that 0,0,0 is in center of bounding box + + center: function ( geometry ) { + + geometry.computeBoundingBox(); + + var bb = geometry.boundingBox; + + var offset = new THREE.Vector3(); + + offset.addVectors( bb.min, bb.max ); + offset.multiplyScalar( -0.5 ); + + geometry.applyMatrix( new THREE.Matrix4().makeTranslation( offset.x, offset.y, offset.z ) ); + geometry.computeBoundingBox(); + + return offset; + + }, + + // Normalize UVs to be from <0,1> + // (for now just the first set of UVs) + + normalizeUVs: function ( geometry ) { + + var uvSet = geometry.faceVertexUvs[ 0 ]; + + for ( var i = 0, il = uvSet.length; i < il; i ++ ) { + + var uvs = uvSet[ i ]; + + for ( var j = 0, jl = uvs.length; j < jl; j ++ ) { + + // texture repeat + + if( uvs[ j ].x !== 1.0 ) uvs[ j ].x = uvs[ j ].x - Math.floor( uvs[ j ].x ); + if( uvs[ j ].y !== 1.0 ) uvs[ j ].y = uvs[ j ].y - Math.floor( uvs[ j ].y ); + + } + + } + + }, + + triangulateQuads: function ( geometry ) { + + var i, il, j, jl; + + var faces = []; + var faceUvs = []; + var faceVertexUvs = []; + + for ( i = 0, il = geometry.faceUvs.length; i < il; i ++ ) { + + faceUvs[ i ] = []; + + } + + for ( i = 0, il = geometry.faceVertexUvs.length; i < il; i ++ ) { + + faceVertexUvs[ i ] = []; + + } + + for ( i = 0, il = geometry.faces.length; i < il; i ++ ) { + + var face = geometry.faces[ i ]; + + if ( face instanceof THREE.Face4 ) { + + var a = face.a; + var b = face.b; + var c = face.c; + var d = face.d; + + var triA = new THREE.Face3(); + var triB = new THREE.Face3(); + + triA.color.copy( face.color ); + triB.color.copy( face.color ); + + triA.materialIndex = face.materialIndex; + triB.materialIndex = face.materialIndex; + + triA.a = a; + triA.b = b; + triA.c = d; + + triB.a = b; + triB.b = c; + triB.c = d; + + if ( face.vertexColors.length === 4 ) { + + triA.vertexColors[ 0 ] = face.vertexColors[ 0 ].clone(); + triA.vertexColors[ 1 ] = face.vertexColors[ 1 ].clone(); + triA.vertexColors[ 2 ] = face.vertexColors[ 3 ].clone(); + + triB.vertexColors[ 0 ] = face.vertexColors[ 1 ].clone(); + triB.vertexColors[ 1 ] = face.vertexColors[ 2 ].clone(); + triB.vertexColors[ 2 ] = face.vertexColors[ 3 ].clone(); + + } + + faces.push( triA, triB ); + + for ( j = 0, jl = geometry.faceVertexUvs.length; j < jl; j ++ ) { + + if ( geometry.faceVertexUvs[ j ].length ) { + + var uvs = geometry.faceVertexUvs[ j ][ i ]; + + var uvA = uvs[ 0 ]; + var uvB = uvs[ 1 ]; + var uvC = uvs[ 2 ]; + var uvD = uvs[ 3 ]; + + var uvsTriA = [ uvA.clone(), uvB.clone(), uvD.clone() ]; + var uvsTriB = [ uvB.clone(), uvC.clone(), uvD.clone() ]; + + faceVertexUvs[ j ].push( uvsTriA, uvsTriB ); + + } + + } + + for ( j = 0, jl = geometry.faceUvs.length; j < jl; j ++ ) { + + if ( geometry.faceUvs[ j ].length ) { + + var faceUv = geometry.faceUvs[ j ][ i ]; + + faceUvs[ j ].push( faceUv, faceUv ); + + } + + } + + } else { + + faces.push( face ); + + for ( j = 0, jl = geometry.faceUvs.length; j < jl; j ++ ) { + + faceUvs[ j ].push( geometry.faceUvs[ j ][ i ] ); + + } + + for ( j = 0, jl = geometry.faceVertexUvs.length; j < jl; j ++ ) { + + faceVertexUvs[ j ].push( geometry.faceVertexUvs[ j ][ i ] ); + + } + + } + + } + + geometry.faces = faces; + geometry.faceUvs = faceUvs; + geometry.faceVertexUvs = faceVertexUvs; + + geometry.computeCentroids(); + geometry.computeFaceNormals(); + geometry.computeVertexNormals(); + + if ( geometry.hasTangents ) geometry.computeTangents(); + + }, + + setMaterialIndex: function ( geometry, index, startFace, endFace ){ + + var faces = geometry.faces; + var start = startFace || 0; + var end = endFace || faces.length - 1; + + for ( var i = start; i <= end; i ++ ) { + + faces[i].materialIndex = index; + + } + + } + +}; + +THREE.GeometryUtils.random = THREE.Math.random16; + +THREE.GeometryUtils.__v1 = new THREE.Vector3(); +THREE.GeometryUtils.__v2 = new THREE.Vector3(); +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.ImageUtils = { + + crossOrigin: 'anonymous', + + loadTexture: function ( url, mapping, onLoad, onError ) { + + var image = new Image(); + var texture = new THREE.Texture( image, mapping ); + + var loader = new THREE.ImageLoader(); + + loader.addEventListener( 'load', function ( event ) { + + texture.image = event.content; + texture.needsUpdate = true; + + if ( onLoad ) onLoad( texture ); + + } ); + + loader.addEventListener( 'error', function ( event ) { + + if ( onError ) onError( event.message ); + + } ); + + loader.crossOrigin = this.crossOrigin; + loader.load( url, image ); + + texture.sourceFile = url; + + return texture; + + }, + + loadCompressedTexture: function ( url, mapping, onLoad, onError ) { + + var texture = new THREE.CompressedTexture(); + texture.mapping = mapping; + + var request = new XMLHttpRequest(); + + request.onload = function () { + + var buffer = request.response; + var dds = THREE.ImageUtils.parseDDS( buffer, true ); + + texture.format = dds.format; + + texture.mipmaps = dds.mipmaps; + texture.image.width = dds.width; + texture.image.height = dds.height; + + // gl.generateMipmap fails for compressed textures + // mipmaps must be embedded in the DDS file + // or texture filters must not use mipmapping + + texture.generateMipmaps = false; + + texture.needsUpdate = true; + + if ( onLoad ) onLoad( texture ); + + } + + request.onerror = onError; + + request.open( 'GET', url, true ); + request.responseType = "arraybuffer"; + request.send( null ); + + return texture; + + }, + + loadTextureCube: function ( array, mapping, onLoad, onError ) { + + var images = []; + images.loadCount = 0; + + var texture = new THREE.Texture(); + texture.image = images; + if ( mapping !== undefined ) texture.mapping = mapping; + + // no flipping needed for cube textures + + texture.flipY = false; + + for ( var i = 0, il = array.length; i < il; ++ i ) { + + var cubeImage = new Image(); + images[ i ] = cubeImage; + + cubeImage.onload = function () { + + images.loadCount += 1; + + if ( images.loadCount === 6 ) { + + texture.needsUpdate = true; + if ( onLoad ) onLoad( texture ); + + } + + }; + + cubeImage.onerror = onError; + + cubeImage.crossOrigin = this.crossOrigin; + cubeImage.src = array[ i ]; + + } + + return texture; + + }, + + loadCompressedTextureCube: function ( array, mapping, onLoad, onError ) { + + var images = []; + images.loadCount = 0; + + var texture = new THREE.CompressedTexture(); + texture.image = images; + if ( mapping !== undefined ) texture.mapping = mapping; + + // no flipping for cube textures + // (also flipping doesn't work for compressed textures ) + + texture.flipY = false; + + // can't generate mipmaps for compressed textures + // mips must be embedded in DDS files + + texture.generateMipmaps = false; + + var generateCubeFaceCallback = function ( rq, img ) { + + return function () { + + var buffer = rq.response; + var dds = THREE.ImageUtils.parseDDS( buffer, true ); + + img.format = dds.format; + + img.mipmaps = dds.mipmaps; + img.width = dds.width; + img.height = dds.height; + + images.loadCount += 1; + + if ( images.loadCount === 6 ) { + + texture.format = dds.format; + texture.needsUpdate = true; + if ( onLoad ) onLoad( texture ); + + } + + } + + } + + // compressed cubemap textures as 6 separate DDS files + + if ( array instanceof Array ) { + + for ( var i = 0, il = array.length; i < il; ++ i ) { + + var cubeImage = {}; + images[ i ] = cubeImage; + + var request = new XMLHttpRequest(); + + request.onload = generateCubeFaceCallback( request, cubeImage ); + request.onerror = onError; + + var url = array[ i ]; + + request.open( 'GET', url, true ); + request.responseType = "arraybuffer"; + request.send( null ); + + } + + // compressed cubemap texture stored in a single DDS file + + } else { + + var url = array; + var request = new XMLHttpRequest(); + + request.onload = function( ) { + + var buffer = request.response; + var dds = THREE.ImageUtils.parseDDS( buffer, true ); + + if ( dds.isCubemap ) { + + var faces = dds.mipmaps.length / dds.mipmapCount; + + for ( var f = 0; f < faces; f ++ ) { + + images[ f ] = { mipmaps : [] }; + + for ( var i = 0; i < dds.mipmapCount; i ++ ) { + + images[ f ].mipmaps.push( dds.mipmaps[ f * dds.mipmapCount + i ] ); + images[ f ].format = dds.format; + images[ f ].width = dds.width; + images[ f ].height = dds.height; + + } + + } + + texture.format = dds.format; + texture.needsUpdate = true; + if ( onLoad ) onLoad( texture ); + + } + + } + + request.onerror = onError; + + request.open( 'GET', url, true ); + request.responseType = "arraybuffer"; + request.send( null ); + + } + + return texture; + + }, + + parseDDS: function ( buffer, loadMipmaps ) { + + var dds = { mipmaps: [], width: 0, height: 0, format: null, mipmapCount: 1 }; + + // Adapted from @toji's DDS utils + // https://github.com/toji/webgl-texture-utils/blob/master/texture-util/dds.js + + // All values and structures referenced from: + // http://msdn.microsoft.com/en-us/library/bb943991.aspx/ + + var DDS_MAGIC = 0x20534444; + + var DDSD_CAPS = 0x1, + DDSD_HEIGHT = 0x2, + DDSD_WIDTH = 0x4, + DDSD_PITCH = 0x8, + DDSD_PIXELFORMAT = 0x1000, + DDSD_MIPMAPCOUNT = 0x20000, + DDSD_LINEARSIZE = 0x80000, + DDSD_DEPTH = 0x800000; + + var DDSCAPS_COMPLEX = 0x8, + DDSCAPS_MIPMAP = 0x400000, + DDSCAPS_TEXTURE = 0x1000; + + var DDSCAPS2_CUBEMAP = 0x200, + DDSCAPS2_CUBEMAP_POSITIVEX = 0x400, + DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800, + DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000, + DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000, + DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000, + DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000, + DDSCAPS2_VOLUME = 0x200000; + + var DDPF_ALPHAPIXELS = 0x1, + DDPF_ALPHA = 0x2, + DDPF_FOURCC = 0x4, + DDPF_RGB = 0x40, + DDPF_YUV = 0x200, + DDPF_LUMINANCE = 0x20000; + + function fourCCToInt32( value ) { + + return value.charCodeAt(0) + + (value.charCodeAt(1) << 8) + + (value.charCodeAt(2) << 16) + + (value.charCodeAt(3) << 24); + + } + + function int32ToFourCC( value ) { + + return String.fromCharCode( + value & 0xff, + (value >> 8) & 0xff, + (value >> 16) & 0xff, + (value >> 24) & 0xff + ); + } + + var FOURCC_DXT1 = fourCCToInt32("DXT1"); + var FOURCC_DXT3 = fourCCToInt32("DXT3"); + var FOURCC_DXT5 = fourCCToInt32("DXT5"); + + var headerLengthInt = 31; // The header length in 32 bit ints + + // Offsets into the header array + + var off_magic = 0; + + var off_size = 1; + var off_flags = 2; + var off_height = 3; + var off_width = 4; + + var off_mipmapCount = 7; + + var off_pfFlags = 20; + var off_pfFourCC = 21; + + var off_caps = 27; + var off_caps2 = 28; + var off_caps3 = 29; + var off_caps4 = 30; + + // Parse header + + var header = new Int32Array( buffer, 0, headerLengthInt ); + + if ( header[ off_magic ] !== DDS_MAGIC ) { + + console.error( "ImageUtils.parseDDS(): Invalid magic number in DDS header" ); + return dds; + + } + + if ( ! header[ off_pfFlags ] & DDPF_FOURCC ) { + + console.error( "ImageUtils.parseDDS(): Unsupported format, must contain a FourCC code" ); + return dds; + + } + + var blockBytes; + + var fourCC = header[ off_pfFourCC ]; + + switch ( fourCC ) { + + case FOURCC_DXT1: + + blockBytes = 8; + dds.format = THREE.RGB_S3TC_DXT1_Format; + break; + + case FOURCC_DXT3: + + blockBytes = 16; + dds.format = THREE.RGBA_S3TC_DXT3_Format; + break; + + case FOURCC_DXT5: + + blockBytes = 16; + dds.format = THREE.RGBA_S3TC_DXT5_Format; + break; + + default: + + console.error( "ImageUtils.parseDDS(): Unsupported FourCC code: ", int32ToFourCC( fourCC ) ); + return dds; + + } + + dds.mipmapCount = 1; + + if ( header[ off_flags ] & DDSD_MIPMAPCOUNT && loadMipmaps !== false ) { + + dds.mipmapCount = Math.max( 1, header[ off_mipmapCount ] ); + + } + + //TODO: Verify that all faces of the cubemap are present with DDSCAPS2_CUBEMAP_POSITIVEX, etc. + + dds.isCubemap = header[ off_caps2 ] & DDSCAPS2_CUBEMAP ? true : false; + + dds.width = header[ off_width ]; + dds.height = header[ off_height ]; + + var dataOffset = header[ off_size ] + 4; + + // Extract mipmaps buffers + + var width = dds.width; + var height = dds.height; + + var faces = dds.isCubemap ? 6 : 1; + + for ( var face = 0; face < faces; face ++ ) { + + for ( var i = 0; i < dds.mipmapCount; i ++ ) { + + var dataLength = Math.max( 4, width ) / 4 * Math.max( 4, height ) / 4 * blockBytes; + var byteArray = new Uint8Array( buffer, dataOffset, dataLength ); + + var mipmap = { "data": byteArray, "width": width, "height": height }; + dds.mipmaps.push( mipmap ); + + dataOffset += dataLength; + + width = Math.max( width * 0.5, 1 ); + height = Math.max( height * 0.5, 1 ); + + } + + width = dds.width; + height = dds.height; + + } + + return dds; + + }, + + getNormalMap: function ( image, depth ) { + + // Adapted from http://www.paulbrunt.co.uk/lab/heightnormal/ + + var cross = function ( a, b ) { + + return [ a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ], a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ], a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ] ]; + + } + + var subtract = function ( a, b ) { + + return [ a[ 0 ] - b[ 0 ], a[ 1 ] - b[ 1 ], a[ 2 ] - b[ 2 ] ]; + + } + + var normalize = function ( a ) { + + var l = Math.sqrt( a[ 0 ] * a[ 0 ] + a[ 1 ] * a[ 1 ] + a[ 2 ] * a[ 2 ] ); + return [ a[ 0 ] / l, a[ 1 ] / l, a[ 2 ] / l ]; + + } + + depth = depth | 1; + + var width = image.width; + var height = image.height; + + var canvas = document.createElement( 'canvas' ); + canvas.width = width; + canvas.height = height; + + var context = canvas.getContext( '2d' ); + context.drawImage( image, 0, 0 ); + + var data = context.getImageData( 0, 0, width, height ).data; + var imageData = context.createImageData( width, height ); + var output = imageData.data; + + for ( var x = 0; x < width; x ++ ) { + + for ( var y = 0; y < height; y ++ ) { + + var ly = y - 1 < 0 ? 0 : y - 1; + var uy = y + 1 > height - 1 ? height - 1 : y + 1; + var lx = x - 1 < 0 ? 0 : x - 1; + var ux = x + 1 > width - 1 ? width - 1 : x + 1; + + var points = []; + var origin = [ 0, 0, data[ ( y * width + x ) * 4 ] / 255 * depth ]; + points.push( [ - 1, 0, data[ ( y * width + lx ) * 4 ] / 255 * depth ] ); + points.push( [ - 1, - 1, data[ ( ly * width + lx ) * 4 ] / 255 * depth ] ); + points.push( [ 0, - 1, data[ ( ly * width + x ) * 4 ] / 255 * depth ] ); + points.push( [ 1, - 1, data[ ( ly * width + ux ) * 4 ] / 255 * depth ] ); + points.push( [ 1, 0, data[ ( y * width + ux ) * 4 ] / 255 * depth ] ); + points.push( [ 1, 1, data[ ( uy * width + ux ) * 4 ] / 255 * depth ] ); + points.push( [ 0, 1, data[ ( uy * width + x ) * 4 ] / 255 * depth ] ); + points.push( [ - 1, 1, data[ ( uy * width + lx ) * 4 ] / 255 * depth ] ); + + var normals = []; + var num_points = points.length; + + for ( var i = 0; i < num_points; i ++ ) { + + var v1 = points[ i ]; + var v2 = points[ ( i + 1 ) % num_points ]; + v1 = subtract( v1, origin ); + v2 = subtract( v2, origin ); + normals.push( normalize( cross( v1, v2 ) ) ); + + } + + var normal = [ 0, 0, 0 ]; + + for ( var i = 0; i < normals.length; i ++ ) { + + normal[ 0 ] += normals[ i ][ 0 ]; + normal[ 1 ] += normals[ i ][ 1 ]; + normal[ 2 ] += normals[ i ][ 2 ]; + + } + + normal[ 0 ] /= normals.length; + normal[ 1 ] /= normals.length; + normal[ 2 ] /= normals.length; + + var idx = ( y * width + x ) * 4; + + output[ idx ] = ( ( normal[ 0 ] + 1.0 ) / 2.0 * 255 ) | 0; + output[ idx + 1 ] = ( ( normal[ 1 ] + 1.0 ) / 2.0 * 255 ) | 0; + output[ idx + 2 ] = ( normal[ 2 ] * 255 ) | 0; + output[ idx + 3 ] = 255; + + } + + } + + context.putImageData( imageData, 0, 0 ); + + return canvas; + + }, + + generateDataTexture: function ( width, height, color ) { + + var size = width * height; + var data = new Uint8Array( 3 * size ); + + var r = Math.floor( color.r * 255 ); + var g = Math.floor( color.g * 255 ); + var b = Math.floor( color.b * 255 ); + + for ( var i = 0; i < size; i ++ ) { + + data[ i * 3 ] = r; + data[ i * 3 + 1 ] = g; + data[ i * 3 + 2 ] = b; + + } + + var texture = new THREE.DataTexture( data, width, height, THREE.RGBFormat ); + texture.needsUpdate = true; + + return texture; + + } + +}; +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.SceneUtils = { + + createMultiMaterialObject: function ( geometry, materials ) { + + var group = new THREE.Object3D(); + + for ( var i = 0, l = materials.length; i < l; i ++ ) { + + group.add( new THREE.Mesh( geometry, materials[ i ] ) ); + + } + + return group; + + }, + + detach : function ( child, parent, scene ) { + + child.applyMatrix( parent.matrixWorld ); + parent.remove( child ); + scene.add( child ); + + }, + + attach: function ( child, scene, parent ) { + + var matrixWorldInverse = new THREE.Matrix4(); + matrixWorldInverse.getInverse( parent.matrixWorld ); + child.applyMatrix( matrixWorldInverse ); + + scene.remove( child ); + parent.add( child ); + + } + +}; +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * @author alteredq / http://alteredqualia.com/ + * + * For Text operations in three.js (See TextGeometry) + * + * It uses techniques used in: + * + * typeface.js and canvastext + * For converting fonts and rendering with javascript + * http://typeface.neocracy.org + * + * Triangulation ported from AS3 + * Simple Polygon Triangulation + * http://actionsnippet.com/?p=1462 + * + * A Method to triangulate shapes with holes + * http://www.sakri.net/blog/2009/06/12/an-approach-to-triangulating-polygons-with-holes/ + * + */ + +THREE.FontUtils = { + + faces : {}, + + // Just for now. face[weight][style] + + face : "helvetiker", + weight: "normal", + style : "normal", + size : 150, + divisions : 10, + + getFace : function() { + + return this.faces[ this.face ][ this.weight ][ this.style ]; + + }, + + loadFace : function( data ) { + + var family = data.familyName.toLowerCase(); + + var ThreeFont = this; + + ThreeFont.faces[ family ] = ThreeFont.faces[ family ] || {}; + + ThreeFont.faces[ family ][ data.cssFontWeight ] = ThreeFont.faces[ family ][ data.cssFontWeight ] || {}; + ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data; + + var face = ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data; + + return data; + + }, + + drawText : function( text ) { + + var characterPts = [], allPts = []; + + // RenderText + + var i, p, + face = this.getFace(), + scale = this.size / face.resolution, + offset = 0, + chars = String( text ).split( '' ), + length = chars.length; + + var fontPaths = []; + + for ( i = 0; i < length; i ++ ) { + + var path = new THREE.Path(); + + var ret = this.extractGlyphPoints( chars[ i ], face, scale, offset, path ); + offset += ret.offset; + + fontPaths.push( ret.path ); + + } + + // get the width + + var width = offset / 2; + // + // for ( p = 0; p < allPts.length; p++ ) { + // + // allPts[ p ].x -= width; + // + // } + + //var extract = this.extractPoints( allPts, characterPts ); + //extract.contour = allPts; + + //extract.paths = fontPaths; + //extract.offset = width; + + return { paths : fontPaths, offset : width }; + + }, + + + + + extractGlyphPoints : function( c, face, scale, offset, path ) { + + var pts = []; + + var i, i2, divisions, + outline, action, length, + scaleX, scaleY, + x, y, cpx, cpy, cpx0, cpy0, cpx1, cpy1, cpx2, cpy2, + laste, + glyph = face.glyphs[ c ] || face.glyphs[ '?' ]; + + if ( !glyph ) return; + + if ( glyph.o ) { + + outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) ); + length = outline.length; + + scaleX = scale; + scaleY = scale; + + for ( i = 0; i < length; ) { + + action = outline[ i ++ ]; + + //console.log( action ); + + switch( action ) { + + case 'm': + + // Move To + + x = outline[ i++ ] * scaleX + offset; + y = outline[ i++ ] * scaleY; + + path.moveTo( x, y ); + break; + + case 'l': + + // Line To + + x = outline[ i++ ] * scaleX + offset; + y = outline[ i++ ] * scaleY; + path.lineTo(x,y); + break; + + case 'q': + + // QuadraticCurveTo + + cpx = outline[ i++ ] * scaleX + offset; + cpy = outline[ i++ ] * scaleY; + cpx1 = outline[ i++ ] * scaleX + offset; + cpy1 = outline[ i++ ] * scaleY; + + path.quadraticCurveTo(cpx1, cpy1, cpx, cpy); + + laste = pts[ pts.length - 1 ]; + + if ( laste ) { + + cpx0 = laste.x; + cpy0 = laste.y; + + for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) { + + var t = i2 / divisions; + var tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx ); + var ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy ); + } + + } + + break; + + case 'b': + + // Cubic Bezier Curve + + cpx = outline[ i++ ] * scaleX + offset; + cpy = outline[ i++ ] * scaleY; + cpx1 = outline[ i++ ] * scaleX + offset; + cpy1 = outline[ i++ ] * -scaleY; + cpx2 = outline[ i++ ] * scaleX + offset; + cpy2 = outline[ i++ ] * -scaleY; + + path.bezierCurveTo( cpx, cpy, cpx1, cpy1, cpx2, cpy2 ); + + laste = pts[ pts.length - 1 ]; + + if ( laste ) { + + cpx0 = laste.x; + cpy0 = laste.y; + + for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) { + + var t = i2 / divisions; + var tx = THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx ); + var ty = THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy ); + + } + + } + + break; + + } + + } + } + + + + return { offset: glyph.ha*scale, path:path}; + } + +}; + + +THREE.FontUtils.generateShapes = function( text, parameters ) { + + // Parameters + + parameters = parameters || {}; + + var size = parameters.size !== undefined ? parameters.size : 100; + var curveSegments = parameters.curveSegments !== undefined ? parameters.curveSegments: 4; + + var font = parameters.font !== undefined ? parameters.font : "helvetiker"; + var weight = parameters.weight !== undefined ? parameters.weight : "normal"; + var style = parameters.style !== undefined ? parameters.style : "normal"; + + THREE.FontUtils.size = size; + THREE.FontUtils.divisions = curveSegments; + + THREE.FontUtils.face = font; + THREE.FontUtils.weight = weight; + THREE.FontUtils.style = style; + + // Get a Font data json object + + var data = THREE.FontUtils.drawText( text ); + + var paths = data.paths; + var shapes = []; + + for ( var p = 0, pl = paths.length; p < pl; p ++ ) { + + Array.prototype.push.apply( shapes, paths[ p ].toShapes() ); + + } + + return shapes; + +}; + + +/** + * This code is a quick port of code written in C++ which was submitted to + * flipcode.com by John W. Ratcliff // July 22, 2000 + * See original code and more information here: + * http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml + * + * ported to actionscript by Zevan Rosser + * www.actionsnippet.com + * + * ported to javascript by Joshua Koo + * http://www.lab4games.net/zz85/blog + * + */ + + +( function( namespace ) { + + var EPSILON = 0.0000000001; + + // takes in an contour array and returns + + var process = function( contour, indices ) { + + var n = contour.length; + + if ( n < 3 ) return null; + + var result = [], + verts = [], + vertIndices = []; + + /* we want a counter-clockwise polygon in verts */ + + var u, v, w; + + if ( area( contour ) > 0.0 ) { + + for ( v = 0; v < n; v++ ) verts[ v ] = v; + + } else { + + for ( v = 0; v < n; v++ ) verts[ v ] = ( n - 1 ) - v; + + } + + var nv = n; + + /* remove nv - 2 vertices, creating 1 triangle every time */ + + var count = 2 * nv; /* error detection */ + + for( v = nv - 1; nv > 2; ) { + + /* if we loop, it is probably a non-simple polygon */ + + if ( ( count-- ) <= 0 ) { + + //** Triangulate: ERROR - probable bad polygon! + + //throw ( "Warning, unable to triangulate polygon!" ); + //return null; + // Sometimes warning is fine, especially polygons are triangulated in reverse. + console.log( "Warning, unable to triangulate polygon!" ); + + if ( indices ) return vertIndices; + return result; + + } + + /* three consecutive vertices in current polygon, <u,v,w> */ + + u = v; if ( nv <= u ) u = 0; /* previous */ + v = u + 1; if ( nv <= v ) v = 0; /* new v */ + w = v + 1; if ( nv <= w ) w = 0; /* next */ + + if ( snip( contour, u, v, w, nv, verts ) ) { + + var a, b, c, s, t; + + /* true names of the vertices */ + + a = verts[ u ]; + b = verts[ v ]; + c = verts[ w ]; + + /* output Triangle */ + + result.push( [ contour[ a ], + contour[ b ], + contour[ c ] ] ); + + + vertIndices.push( [ verts[ u ], verts[ v ], verts[ w ] ] ); + + /* remove v from the remaining polygon */ + + for( s = v, t = v + 1; t < nv; s++, t++ ) { + + verts[ s ] = verts[ t ]; + + } + + nv--; + + /* reset error detection counter */ + + count = 2 * nv; + + } + + } + + if ( indices ) return vertIndices; + return result; + + }; + + // calculate area of the contour polygon + + var area = function ( contour ) { + + var n = contour.length; + var a = 0.0; + + for( var p = n - 1, q = 0; q < n; p = q++ ) { + + a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y; + + } + + return a * 0.5; + + }; + + var snip = function ( contour, u, v, w, n, verts ) { + + var p; + var ax, ay, bx, by; + var cx, cy, px, py; + + ax = contour[ verts[ u ] ].x; + ay = contour[ verts[ u ] ].y; + + bx = contour[ verts[ v ] ].x; + by = contour[ verts[ v ] ].y; + + cx = contour[ verts[ w ] ].x; + cy = contour[ verts[ w ] ].y; + + if ( EPSILON > (((bx-ax)*(cy-ay)) - ((by-ay)*(cx-ax))) ) return false; + + var aX, aY, bX, bY, cX, cY; + var apx, apy, bpx, bpy, cpx, cpy; + var cCROSSap, bCROSScp, aCROSSbp; + + aX = cx - bx; aY = cy - by; + bX = ax - cx; bY = ay - cy; + cX = bx - ax; cY = by - ay; + + for ( p = 0; p < n; p++ ) { + + if( (p === u) || (p === v) || (p === w) ) continue; + + px = contour[ verts[ p ] ].x + py = contour[ verts[ p ] ].y + + apx = px - ax; apy = py - ay; + bpx = px - bx; bpy = py - by; + cpx = px - cx; cpy = py - cy; + + // see if p is inside triangle abc + + aCROSSbp = aX*bpy - aY*bpx; + cCROSSap = cX*apy - cY*apx; + bCROSScp = bX*cpy - bY*cpx; + + if ( (aCROSSbp >= 0.0) && (bCROSScp >= 0.0) && (cCROSSap >= 0.0) ) return false; + + } + + return true; + + }; + + + namespace.Triangulate = process; + namespace.Triangulate.area = area; + + return namespace; + +})(THREE.FontUtils); + +// To use the typeface.js face files, hook up the API +self._typeface_js = { faces: THREE.FontUtils.faces, loadFace: THREE.FontUtils.loadFace };/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * Extensible curve object + * + * Some common of Curve methods + * .getPoint(t), getTangent(t) + * .getPointAt(u), getTagentAt(u) + * .getPoints(), .getSpacedPoints() + * .getLength() + * .updateArcLengths() + * + * This file contains following classes: + * + * -- 2d classes -- + * THREE.Curve + * THREE.LineCurve + * THREE.QuadraticBezierCurve + * THREE.CubicBezierCurve + * THREE.SplineCurve + * THREE.ArcCurve + * THREE.EllipseCurve + * + * -- 3d classes -- + * THREE.LineCurve3 + * THREE.QuadraticBezierCurve3 + * THREE.CubicBezierCurve3 + * THREE.SplineCurve3 + * THREE.ClosedSplineCurve3 + * + * A series of curves can be represented as a THREE.CurvePath + * + **/ + +/************************************************************** + * Abstract Curve base class + **************************************************************/ + +THREE.Curve = function () { + +}; + +// Virtual base class method to overwrite and implement in subclasses +// - t [0 .. 1] + +THREE.Curve.prototype.getPoint = function ( t ) { + + console.log( "Warning, getPoint() not implemented!" ); + return null; + +}; + +// Get point at relative position in curve according to arc length +// - u [0 .. 1] + +THREE.Curve.prototype.getPointAt = function ( u ) { + + var t = this.getUtoTmapping( u ); + return this.getPoint( t ); + +}; + +// Get sequence of points using getPoint( t ) + +THREE.Curve.prototype.getPoints = function ( divisions ) { + + if ( !divisions ) divisions = 5; + + var d, pts = []; + + for ( d = 0; d <= divisions; d ++ ) { + + pts.push( this.getPoint( d / divisions ) ); + + } + + return pts; + +}; + +// Get sequence of points using getPointAt( u ) + +THREE.Curve.prototype.getSpacedPoints = function ( divisions ) { + + if ( !divisions ) divisions = 5; + + var d, pts = []; + + for ( d = 0; d <= divisions; d ++ ) { + + pts.push( this.getPointAt( d / divisions ) ); + + } + + return pts; + +}; + +// Get total curve arc length + +THREE.Curve.prototype.getLength = function () { + + var lengths = this.getLengths(); + return lengths[ lengths.length - 1 ]; + +}; + +// Get list of cumulative segment lengths + +THREE.Curve.prototype.getLengths = function ( divisions ) { + + if ( !divisions ) divisions = (this.__arcLengthDivisions) ? (this.__arcLengthDivisions): 200; + + if ( this.cacheArcLengths + && ( this.cacheArcLengths.length == divisions + 1 ) + && !this.needsUpdate) { + + //console.log( "cached", this.cacheArcLengths ); + return this.cacheArcLengths; + + } + + this.needsUpdate = false; + + var cache = []; + var current, last = this.getPoint( 0 ); + var p, sum = 0; + + cache.push( 0 ); + + for ( p = 1; p <= divisions; p ++ ) { + + current = this.getPoint ( p / divisions ); + sum += current.distanceTo( last ); + cache.push( sum ); + last = current; + + } + + this.cacheArcLengths = cache; + + return cache; // { sums: cache, sum:sum }; Sum is in the last element. + +}; + + +THREE.Curve.prototype.updateArcLengths = function() { + this.needsUpdate = true; + this.getLengths(); +}; + +// Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equi distance + +THREE.Curve.prototype.getUtoTmapping = function ( u, distance ) { + + var arcLengths = this.getLengths(); + + var i = 0, il = arcLengths.length; + + var targetArcLength; // The targeted u distance value to get + + if ( distance ) { + + targetArcLength = distance; + + } else { + + targetArcLength = u * arcLengths[ il - 1 ]; + + } + + //var time = Date.now(); + + // binary search for the index with largest value smaller than target u distance + + var low = 0, high = il - 1, comparison; + + while ( low <= high ) { + + i = 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 + + comparison = arcLengths[ i ] - targetArcLength; + + if ( comparison < 0 ) { + + low = i + 1; + continue; + + } else if ( comparison > 0 ) { + + high = i - 1; + continue; + + } else { + + high = i; + break; + + // DONE + + } + + } + + i = high; + + //console.log('b' , i, low, high, Date.now()- time); + + if ( arcLengths[ i ] == targetArcLength ) { + + var t = i / ( il - 1 ); + return t; + + } + + // we could get finer grain at lengths, or use simple interpolatation between two points + + var lengthBefore = arcLengths[ i ]; + var lengthAfter = arcLengths[ i + 1 ]; + + var segmentLength = lengthAfter - lengthBefore; + + // determine where we are between the 'before' and 'after' points + + var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; + + // add that fractional amount to t + + var t = ( i + segmentFraction ) / ( il -1 ); + + return t; + +}; + +// Returns a unit vector tangent at t +// In case any sub curve does not implement its tangent derivation, +// 2 points a small delta apart will be used to find its gradient +// which seems to give a reasonable approximation + +THREE.Curve.prototype.getTangent = function( t ) { + + var delta = 0.0001; + var t1 = t - delta; + var t2 = t + delta; + + // Capping in case of danger + + if ( t1 < 0 ) t1 = 0; + if ( t2 > 1 ) t2 = 1; + + var pt1 = this.getPoint( t1 ); + var pt2 = this.getPoint( t2 ); + + var vec = pt2.clone().sub(pt1); + return vec.normalize(); + +}; + + +THREE.Curve.prototype.getTangentAt = function ( u ) { + + var t = this.getUtoTmapping( u ); + return this.getTangent( t ); + +}; + +/************************************************************** + * Line + **************************************************************/ + +THREE.LineCurve = function ( v1, v2 ) { + + this.v1 = v1; + this.v2 = v2; + +}; + +THREE.LineCurve.prototype = Object.create( THREE.Curve.prototype ); + +THREE.LineCurve.prototype.getPoint = function ( t ) { + + var point = this.v2.clone().sub(this.v1); + point.multiplyScalar( t ).add( this.v1 ); + + return point; + +}; + +// Line curve is linear, so we can overwrite default getPointAt + +THREE.LineCurve.prototype.getPointAt = function ( u ) { + + return this.getPoint( u ); + +}; + +THREE.LineCurve.prototype.getTangent = function( t ) { + + var tangent = this.v2.clone().sub(this.v1); + + return tangent.normalize(); + +}; + +/************************************************************** + * Quadratic Bezier curve + **************************************************************/ + + +THREE.QuadraticBezierCurve = function ( v0, v1, v2 ) { + + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; + +}; + +THREE.QuadraticBezierCurve.prototype = Object.create( THREE.Curve.prototype ); + + +THREE.QuadraticBezierCurve.prototype.getPoint = function ( t ) { + + var tx, ty; + + tx = THREE.Shape.Utils.b2( t, this.v0.x, this.v1.x, this.v2.x ); + ty = THREE.Shape.Utils.b2( t, this.v0.y, this.v1.y, this.v2.y ); + + return new THREE.Vector2( tx, ty ); + +}; + + +THREE.QuadraticBezierCurve.prototype.getTangent = function( t ) { + + var tx, ty; + + tx = THREE.Curve.Utils.tangentQuadraticBezier( t, this.v0.x, this.v1.x, this.v2.x ); + ty = THREE.Curve.Utils.tangentQuadraticBezier( t, this.v0.y, this.v1.y, this.v2.y ); + + // returns unit vector + + var tangent = new THREE.Vector2( tx, ty ); + tangent.normalize(); + + return tangent; + +}; + + +/************************************************************** + * Cubic Bezier curve + **************************************************************/ + +THREE.CubicBezierCurve = function ( v0, v1, v2, v3 ) { + + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; + this.v3 = v3; + +}; + +THREE.CubicBezierCurve.prototype = Object.create( THREE.Curve.prototype ); + +THREE.CubicBezierCurve.prototype.getPoint = function ( t ) { + + var tx, ty; + + tx = THREE.Shape.Utils.b3( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ); + ty = THREE.Shape.Utils.b3( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y ); + + return new THREE.Vector2( tx, ty ); + +}; + +THREE.CubicBezierCurve.prototype.getTangent = function( t ) { + + var tx, ty; + + tx = THREE.Curve.Utils.tangentCubicBezier( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ); + ty = THREE.Curve.Utils.tangentCubicBezier( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y ); + + var tangent = new THREE.Vector2( tx, ty ); + tangent.normalize(); + + return tangent; + +}; + + +/************************************************************** + * Spline curve + **************************************************************/ + +THREE.SplineCurve = function ( points /* array of Vector2 */ ) { + + this.points = (points == undefined) ? [] : points; + +}; + +THREE.SplineCurve.prototype = Object.create( THREE.Curve.prototype ); + +THREE.SplineCurve.prototype.getPoint = function ( t ) { + + var v = new THREE.Vector2(); + var c = []; + var points = this.points, point, intPoint, weight; + point = ( points.length - 1 ) * t; + + intPoint = Math.floor( point ); + weight = point - intPoint; + + c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1; + c[ 1 ] = intPoint; + c[ 2 ] = intPoint > points.length - 2 ? points.length -1 : intPoint + 1; + c[ 3 ] = intPoint > points.length - 3 ? points.length -1 : intPoint + 2; + + v.x = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].x, points[ c[ 1 ] ].x, points[ c[ 2 ] ].x, points[ c[ 3 ] ].x, weight ); + v.y = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].y, points[ c[ 1 ] ].y, points[ c[ 2 ] ].y, points[ c[ 3 ] ].y, weight ); + + return v; + +}; + +/************************************************************** + * Ellipse curve + **************************************************************/ + +THREE.EllipseCurve = function ( aX, aY, xRadius, yRadius, + aStartAngle, aEndAngle, + aClockwise ) { + + this.aX = aX; + this.aY = aY; + + this.xRadius = xRadius; + this.yRadius = yRadius; + + this.aStartAngle = aStartAngle; + this.aEndAngle = aEndAngle; + + this.aClockwise = aClockwise; + +}; + +THREE.EllipseCurve.prototype = Object.create( THREE.Curve.prototype ); + +THREE.EllipseCurve.prototype.getPoint = function ( t ) { + + var deltaAngle = this.aEndAngle - this.aStartAngle; + + if ( !this.aClockwise ) { + + t = 1 - t; + + } + + var angle = this.aStartAngle + t * deltaAngle; + + var tx = this.aX + this.xRadius * Math.cos( angle ); + var ty = this.aY + this.yRadius * Math.sin( angle ); + + return new THREE.Vector2( tx, ty ); + +}; + +/************************************************************** + * Arc curve + **************************************************************/ + +THREE.ArcCurve = function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { + + THREE.EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); +}; + +THREE.ArcCurve.prototype = Object.create( THREE.EllipseCurve.prototype ); + + +/************************************************************** + * Utils + **************************************************************/ + +THREE.Curve.Utils = { + + tangentQuadraticBezier: function ( t, p0, p1, p2 ) { + + return 2 * ( 1 - t ) * ( p1 - p0 ) + 2 * t * ( p2 - p1 ); + + }, + + // Puay Bing, thanks for helping with this derivative! + + tangentCubicBezier: function (t, p0, p1, p2, p3 ) { + + return -3 * p0 * (1 - t) * (1 - t) + + 3 * p1 * (1 - t) * (1-t) - 6 *t *p1 * (1-t) + + 6 * t * p2 * (1-t) - 3 * t * t * p2 + + 3 * t * t * p3; + }, + + + tangentSpline: function ( t, p0, p1, p2, p3 ) { + + // To check if my formulas are correct + + var h00 = 6 * t * t - 6 * t; // derived from 2t^3 - 3t^2 + 1 + var h10 = 3 * t * t - 4 * t + 1; // t^3 - 2t^2 + t + var h01 = -6 * t * t + 6 * t; // - 2t3 + 3t2 + var h11 = 3 * t * t - 2 * t; // t3 - t2 + + return h00 + h10 + h01 + h11; + + }, + + // Catmull-Rom + + interpolate: function( p0, p1, p2, p3, t ) { + + var v0 = ( p2 - p0 ) * 0.5; + var v1 = ( p3 - p1 ) * 0.5; + var t2 = t * t; + var t3 = t * t2; + return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1; + + } + +}; + + +// TODO: Transformation for Curves? + +/************************************************************** + * 3D Curves + **************************************************************/ + +// A Factory method for creating new curve subclasses + +THREE.Curve.create = function ( constructor, getPointFunc ) { + + constructor.prototype = Object.create( THREE.Curve.prototype ); + constructor.prototype.getPoint = getPointFunc; + + return constructor; + +}; + + +/************************************************************** + * Line3D + **************************************************************/ + +THREE.LineCurve3 = THREE.Curve.create( + + function ( v1, v2 ) { + + this.v1 = v1; + this.v2 = v2; + + }, + + function ( t ) { + + var r = new THREE.Vector3(); + + + r.subVectors( this.v2, this.v1 ); // diff + r.multiplyScalar( t ); + r.add( this.v1 ); + + return r; + + } + +); + + +/************************************************************** + * Quadratic Bezier 3D curve + **************************************************************/ + +THREE.QuadraticBezierCurve3 = THREE.Curve.create( + + function ( v0, v1, v2 ) { + + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; + + }, + + function ( t ) { + + var tx, ty, tz; + + tx = THREE.Shape.Utils.b2( t, this.v0.x, this.v1.x, this.v2.x ); + ty = THREE.Shape.Utils.b2( t, this.v0.y, this.v1.y, this.v2.y ); + tz = THREE.Shape.Utils.b2( t, this.v0.z, this.v1.z, this.v2.z ); + + return new THREE.Vector3( tx, ty, tz ); + + } + +); + + + +/************************************************************** + * Cubic Bezier 3D curve + **************************************************************/ + +THREE.CubicBezierCurve3 = THREE.Curve.create( + + function ( v0, v1, v2, v3 ) { + + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; + this.v3 = v3; + + }, + + function ( t ) { + + var tx, ty, tz; + + tx = THREE.Shape.Utils.b3( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ); + ty = THREE.Shape.Utils.b3( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y ); + tz = THREE.Shape.Utils.b3( t, this.v0.z, this.v1.z, this.v2.z, this.v3.z ); + + return new THREE.Vector3( tx, ty, tz ); + + } + +); + + + +/************************************************************** + * Spline 3D curve + **************************************************************/ + + +THREE.SplineCurve3 = THREE.Curve.create( + + function ( points /* array of Vector3 */) { + + this.points = (points == undefined) ? [] : points; + + }, + + function ( t ) { + + var v = new THREE.Vector3(); + var c = []; + var points = this.points, point, intPoint, weight; + point = ( points.length - 1 ) * t; + + intPoint = Math.floor( point ); + weight = point - intPoint; + + c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1; + c[ 1 ] = intPoint; + c[ 2 ] = intPoint > points.length - 2 ? points.length - 1 : intPoint + 1; + c[ 3 ] = intPoint > points.length - 3 ? points.length - 1 : intPoint + 2; + + var pt0 = points[ c[0] ], + pt1 = points[ c[1] ], + pt2 = points[ c[2] ], + pt3 = points[ c[3] ]; + + v.x = THREE.Curve.Utils.interpolate(pt0.x, pt1.x, pt2.x, pt3.x, weight); + v.y = THREE.Curve.Utils.interpolate(pt0.y, pt1.y, pt2.y, pt3.y, weight); + v.z = THREE.Curve.Utils.interpolate(pt0.z, pt1.z, pt2.z, pt3.z, weight); + + return v; + + } + +); + + +// THREE.SplineCurve3.prototype.getTangent = function(t) { +// var v = new THREE.Vector3(); +// var c = []; +// var points = this.points, point, intPoint, weight; +// point = ( points.length - 1 ) * t; + +// intPoint = Math.floor( point ); +// weight = point - intPoint; + +// c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1; +// c[ 1 ] = intPoint; +// c[ 2 ] = intPoint > points.length - 2 ? points.length - 1 : intPoint + 1; +// c[ 3 ] = intPoint > points.length - 3 ? points.length - 1 : intPoint + 2; + +// var pt0 = points[ c[0] ], +// pt1 = points[ c[1] ], +// pt2 = points[ c[2] ], +// pt3 = points[ c[3] ]; + +// // t = weight; +// v.x = THREE.Curve.Utils.tangentSpline( t, pt0.x, pt1.x, pt2.x, pt3.x ); +// v.y = THREE.Curve.Utils.tangentSpline( t, pt0.y, pt1.y, pt2.y, pt3.y ); +// v.z = THREE.Curve.Utils.tangentSpline( t, pt0.z, pt1.z, pt2.z, pt3.z ); + +// return v; + +// } + +/************************************************************** + * Closed Spline 3D curve + **************************************************************/ + + +THREE.ClosedSplineCurve3 = THREE.Curve.create( + + function ( points /* array of Vector3 */) { + + this.points = (points == undefined) ? [] : points; + + }, + + function ( t ) { + + var v = new THREE.Vector3(); + var c = []; + var points = this.points, point, intPoint, weight; + point = ( points.length - 0 ) * t; + // This needs to be from 0-length +1 + + intPoint = Math.floor( point ); + weight = point - intPoint; + + intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / points.length ) + 1 ) * points.length; + c[ 0 ] = ( intPoint - 1 ) % points.length; + c[ 1 ] = ( intPoint ) % points.length; + c[ 2 ] = ( intPoint + 1 ) % points.length; + c[ 3 ] = ( intPoint + 2 ) % points.length; + + v.x = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].x, points[ c[ 1 ] ].x, points[ c[ 2 ] ].x, points[ c[ 3 ] ].x, weight ); + v.y = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].y, points[ c[ 1 ] ].y, points[ c[ 2 ] ].y, points[ c[ 3 ] ].y, weight ); + v.z = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].z, points[ c[ 1 ] ].z, points[ c[ 2 ] ].z, points[ c[ 3 ] ].z, weight ); + + return v; + + } + +); +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * + **/ + +/************************************************************** + * Curved Path - a curve path is simply a array of connected + * curves, but retains the api of a curve + **************************************************************/ + +THREE.CurvePath = function () { + + this.curves = []; + this.bends = []; + + this.autoClose = false; // Automatically closes the path +}; + +THREE.CurvePath.prototype = Object.create( THREE.Curve.prototype ); + +THREE.CurvePath.prototype.add = function ( curve ) { + + this.curves.push( curve ); + +}; + +THREE.CurvePath.prototype.checkConnection = function() { + // TODO + // If the ending of curve is not connected to the starting + // or the next curve, then, this is not a real path +}; + +THREE.CurvePath.prototype.closePath = function() { + // TODO Test + // and verify for vector3 (needs to implement equals) + // Add a line curve if start and end of lines are not connected + var startPoint = this.curves[0].getPoint(0); + var endPoint = this.curves[this.curves.length-1].getPoint(1); + + if (!startPoint.equals(endPoint)) { + this.curves.push( new THREE.LineCurve(endPoint, startPoint) ); + } + +}; + +// To get accurate point with reference to +// entire path distance at time t, +// following has to be done: + +// 1. Length of each sub path have to be known +// 2. Locate and identify type of curve +// 3. Get t for the curve +// 4. Return curve.getPointAt(t') + +THREE.CurvePath.prototype.getPoint = function( t ) { + + var d = t * this.getLength(); + var curveLengths = this.getCurveLengths(); + var i = 0, diff, curve; + + // To think about boundaries points. + + while ( i < curveLengths.length ) { + + if ( curveLengths[ i ] >= d ) { + + diff = curveLengths[ i ] - d; + curve = this.curves[ i ]; + + var u = 1 - diff / curve.getLength(); + + return curve.getPointAt( u ); + + break; + } + + i ++; + + } + + return null; + + // loop where sum != 0, sum > d , sum+1 <d + +}; + +/* +THREE.CurvePath.prototype.getTangent = function( t ) { +};*/ + + +// We cannot use the default THREE.Curve getPoint() with getLength() because in +// THREE.Curve, getLength() depends on getPoint() but in THREE.CurvePath +// getPoint() depends on getLength + +THREE.CurvePath.prototype.getLength = function() { + + var lens = this.getCurveLengths(); + return lens[ lens.length - 1 ]; + +}; + +// Compute lengths and cache them +// We cannot overwrite getLengths() because UtoT mapping uses it. + +THREE.CurvePath.prototype.getCurveLengths = function() { + + // We use cache values if curves and cache array are same length + + if ( this.cacheLengths && this.cacheLengths.length == this.curves.length ) { + + return this.cacheLengths; + + }; + + // Get length of subsurve + // Push sums into cached array + + var lengths = [], sums = 0; + var i, il = this.curves.length; + + for ( i = 0; i < il; i ++ ) { + + sums += this.curves[ i ].getLength(); + lengths.push( sums ); + + } + + this.cacheLengths = lengths; + + return lengths; + +}; + + + +// Returns min and max coordinates, as well as centroid + +THREE.CurvePath.prototype.getBoundingBox = function () { + + var points = this.getPoints(); + + var maxX, maxY, maxZ; + var minX, minY, minZ; + + maxX = maxY = Number.NEGATIVE_INFINITY; + minX = minY = Number.POSITIVE_INFINITY; + + var p, i, il, sum; + + var v3 = points[0] instanceof THREE.Vector3; + + sum = v3 ? new THREE.Vector3() : new THREE.Vector2(); + + for ( i = 0, il = points.length; i < il; i ++ ) { + + p = points[ i ]; + + if ( p.x > maxX ) maxX = p.x; + else if ( p.x < minX ) minX = p.x; + + if ( p.y > maxY ) maxY = p.y; + else if ( p.y < minY ) minY = p.y; + + if ( v3 ) { + + if ( p.z > maxZ ) maxZ = p.z; + else if ( p.z < minZ ) minZ = p.z; + + } + + sum.add( p ); + + } + + var ret = { + + minX: minX, + minY: minY, + maxX: maxX, + maxY: maxY, + centroid: sum.divideScalar( il ) + + }; + + if ( v3 ) { + + ret.maxZ = maxZ; + ret.minZ = minZ; + + } + + return ret; + +}; + +/************************************************************** + * Create Geometries Helpers + **************************************************************/ + +/// Generate geometry from path points (for Line or ParticleSystem objects) + +THREE.CurvePath.prototype.createPointsGeometry = function( divisions ) { + + var pts = this.getPoints( divisions, true ); + return this.createGeometry( pts ); + +}; + +// Generate geometry from equidistance sampling along the path + +THREE.CurvePath.prototype.createSpacedPointsGeometry = function( divisions ) { + + var pts = this.getSpacedPoints( divisions, true ); + return this.createGeometry( pts ); + +}; + +THREE.CurvePath.prototype.createGeometry = function( points ) { + + var geometry = new THREE.Geometry(); + + for ( var i = 0; i < points.length; i ++ ) { + + geometry.vertices.push( new THREE.Vector3( points[ i ].x, points[ i ].y, points[ i ].z || 0) ); + + } + + return geometry; + +}; + + +/************************************************************** + * Bend / Wrap Helper Methods + **************************************************************/ + +// Wrap path / Bend modifiers? + +THREE.CurvePath.prototype.addWrapPath = function ( bendpath ) { + + this.bends.push( bendpath ); + +}; + +THREE.CurvePath.prototype.getTransformedPoints = function( segments, bends ) { + + var oldPts = this.getPoints( segments ); // getPoints getSpacedPoints + var i, il; + + if ( !bends ) { + + bends = this.bends; + + } + + for ( i = 0, il = bends.length; i < il; i ++ ) { + + oldPts = this.getWrapPoints( oldPts, bends[ i ] ); + + } + + return oldPts; + +}; + +THREE.CurvePath.prototype.getTransformedSpacedPoints = function( segments, bends ) { + + var oldPts = this.getSpacedPoints( segments ); + + var i, il; + + if ( !bends ) { + + bends = this.bends; + + } + + for ( i = 0, il = bends.length; i < il; i ++ ) { + + oldPts = this.getWrapPoints( oldPts, bends[ i ] ); + + } + + return oldPts; + +}; + +// This returns getPoints() bend/wrapped around the contour of a path. +// Read http://www.planetclegg.com/projects/WarpingTextToSplines.html + +THREE.CurvePath.prototype.getWrapPoints = function ( oldPts, path ) { + + var bounds = this.getBoundingBox(); + + var i, il, p, oldX, oldY, xNorm; + + for ( i = 0, il = oldPts.length; i < il; i ++ ) { + + p = oldPts[ i ]; + + oldX = p.x; + oldY = p.y; + + xNorm = oldX / bounds.maxX; + + // If using actual distance, for length > path, requires line extrusions + //xNorm = path.getUtoTmapping(xNorm, oldX); // 3 styles. 1) wrap stretched. 2) wrap stretch by arc length 3) warp by actual distance + + xNorm = path.getUtoTmapping( xNorm, oldX ); + + // check for out of bounds? + + var pathPt = path.getPoint( xNorm ); + var normal = path.getNormalVector( xNorm ).multiplyScalar( oldY ); + + p.x = pathPt.x + normal.x; + p.y = pathPt.y + normal.y; + + } + + return oldPts; + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Gyroscope = function () { + + THREE.Object3D.call( this ); + +}; + +THREE.Gyroscope.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.Gyroscope.prototype.updateMatrixWorld = function ( force ) { + + this.matrixAutoUpdate && this.updateMatrix(); + + // update matrixWorld + + if ( this.matrixWorldNeedsUpdate || force ) { + + if ( this.parent ) { + + this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); + + this.matrixWorld.decompose( this.translationWorld, this.rotationWorld, this.scaleWorld ); + this.matrix.decompose( this.translationObject, this.rotationObject, this.scaleObject ); + + this.matrixWorld.compose( this.translationWorld, this.rotationObject, this.scaleWorld ); + + + } else { + + this.matrixWorld.copy( this.matrix ); + + } + + + this.matrixWorldNeedsUpdate = false; + + force = true; + + } + + // update children + + for ( var i = 0, l = this.children.length; i < l; i ++ ) { + + this.children[ i ].updateMatrixWorld( force ); + + } + +}; + +THREE.Gyroscope.prototype.translationWorld = new THREE.Vector3(); +THREE.Gyroscope.prototype.translationObject = new THREE.Vector3(); +THREE.Gyroscope.prototype.rotationWorld = new THREE.Quaternion(); +THREE.Gyroscope.prototype.rotationObject = new THREE.Quaternion(); +THREE.Gyroscope.prototype.scaleWorld = new THREE.Vector3(); +THREE.Gyroscope.prototype.scaleObject = new THREE.Vector3(); + +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * Creates free form 2d path using series of points, lines or curves. + * + **/ + +THREE.Path = function ( points ) { + + THREE.CurvePath.call(this); + + this.actions = []; + + if ( points ) { + + this.fromPoints( points ); + + } + +}; + +THREE.Path.prototype = Object.create( THREE.CurvePath.prototype ); + +THREE.PathActions = { + + MOVE_TO: 'moveTo', + LINE_TO: 'lineTo', + QUADRATIC_CURVE_TO: 'quadraticCurveTo', // Bezier quadratic curve + BEZIER_CURVE_TO: 'bezierCurveTo', // Bezier cubic curve + CSPLINE_THRU: 'splineThru', // Catmull-rom spline + ARC: 'arc', // Circle + ELLIPSE: 'ellipse' +}; + +// TODO Clean up PATH API + +// Create path using straight lines to connect all points +// - vectors: array of Vector2 + +THREE.Path.prototype.fromPoints = function ( vectors ) { + + this.moveTo( vectors[ 0 ].x, vectors[ 0 ].y ); + + for ( var v = 1, vlen = vectors.length; v < vlen; v ++ ) { + + this.lineTo( vectors[ v ].x, vectors[ v ].y ); + + }; + +}; + +// startPath() endPath()? + +THREE.Path.prototype.moveTo = function ( x, y ) { + + var args = Array.prototype.slice.call( arguments ); + this.actions.push( { action: THREE.PathActions.MOVE_TO, args: args } ); + +}; + +THREE.Path.prototype.lineTo = function ( x, y ) { + + var args = Array.prototype.slice.call( arguments ); + + var lastargs = this.actions[ this.actions.length - 1 ].args; + + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; + + var curve = new THREE.LineCurve( new THREE.Vector2( x0, y0 ), new THREE.Vector2( x, y ) ); + this.curves.push( curve ); + + this.actions.push( { action: THREE.PathActions.LINE_TO, args: args } ); + +}; + +THREE.Path.prototype.quadraticCurveTo = function( aCPx, aCPy, aX, aY ) { + + var args = Array.prototype.slice.call( arguments ); + + var lastargs = this.actions[ this.actions.length - 1 ].args; + + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; + + var curve = new THREE.QuadraticBezierCurve( new THREE.Vector2( x0, y0 ), + new THREE.Vector2( aCPx, aCPy ), + new THREE.Vector2( aX, aY ) ); + this.curves.push( curve ); + + this.actions.push( { action: THREE.PathActions.QUADRATIC_CURVE_TO, args: args } ); + +}; + +THREE.Path.prototype.bezierCurveTo = function( aCP1x, aCP1y, + aCP2x, aCP2y, + aX, aY ) { + + var args = Array.prototype.slice.call( arguments ); + + var lastargs = this.actions[ this.actions.length - 1 ].args; + + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; + + var curve = new THREE.CubicBezierCurve( new THREE.Vector2( x0, y0 ), + new THREE.Vector2( aCP1x, aCP1y ), + new THREE.Vector2( aCP2x, aCP2y ), + new THREE.Vector2( aX, aY ) ); + this.curves.push( curve ); + + this.actions.push( { action: THREE.PathActions.BEZIER_CURVE_TO, args: args } ); + +}; + +THREE.Path.prototype.splineThru = function( pts /*Array of Vector*/ ) { + + var args = Array.prototype.slice.call( arguments ); + var lastargs = this.actions[ this.actions.length - 1 ].args; + + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; +//--- + var npts = [ new THREE.Vector2( x0, y0 ) ]; + Array.prototype.push.apply( npts, pts ); + + var curve = new THREE.SplineCurve( npts ); + this.curves.push( curve ); + + this.actions.push( { action: THREE.PathActions.CSPLINE_THRU, args: args } ); + +}; + +// FUTURE: Change the API or follow canvas API? + +THREE.Path.prototype.arc = function ( aX, aY, aRadius, + aStartAngle, aEndAngle, aClockwise ) { + + var lastargs = this.actions[ this.actions.length - 1].args; + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; + + this.absarc(aX + x0, aY + y0, aRadius, + aStartAngle, aEndAngle, aClockwise ); + + }; + + THREE.Path.prototype.absarc = function ( aX, aY, aRadius, + aStartAngle, aEndAngle, aClockwise ) { + this.absellipse(aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise); + }; + +THREE.Path.prototype.ellipse = function ( aX, aY, xRadius, yRadius, + aStartAngle, aEndAngle, aClockwise ) { + + var lastargs = this.actions[ this.actions.length - 1].args; + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; + + this.absellipse(aX + x0, aY + y0, xRadius, yRadius, + aStartAngle, aEndAngle, aClockwise ); + + }; + + +THREE.Path.prototype.absellipse = function ( aX, aY, xRadius, yRadius, + aStartAngle, aEndAngle, aClockwise ) { + + var args = Array.prototype.slice.call( arguments ); + var curve = new THREE.EllipseCurve( aX, aY, xRadius, yRadius, + aStartAngle, aEndAngle, aClockwise ); + this.curves.push( curve ); + + var lastPoint = curve.getPoint(aClockwise ? 1 : 0); + args.push(lastPoint.x); + args.push(lastPoint.y); + + this.actions.push( { action: THREE.PathActions.ELLIPSE, args: args } ); + + }; + +THREE.Path.prototype.getSpacedPoints = function ( divisions, closedPath ) { + + if ( ! divisions ) divisions = 40; + + var points = []; + + for ( var i = 0; i < divisions; i ++ ) { + + points.push( this.getPoint( i / divisions ) ); + + //if( !this.getPoint( i / divisions ) ) throw "DIE"; + + } + + // if ( closedPath ) { + // + // points.push( points[ 0 ] ); + // + // } + + return points; + +}; + +/* Return an array of vectors based on contour of the path */ + +THREE.Path.prototype.getPoints = function( divisions, closedPath ) { + + if (this.useSpacedPoints) { + console.log('tata'); + return this.getSpacedPoints( divisions, closedPath ); + } + + divisions = divisions || 12; + + var points = []; + + var i, il, item, action, args; + var cpx, cpy, cpx2, cpy2, cpx1, cpy1, cpx0, cpy0, + laste, j, + t, tx, ty; + + for ( i = 0, il = this.actions.length; i < il; i ++ ) { + + item = this.actions[ i ]; + + action = item.action; + args = item.args; + + switch( action ) { + + case THREE.PathActions.MOVE_TO: + + points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) ); + + break; + + case THREE.PathActions.LINE_TO: + + points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) ); + + break; + + case THREE.PathActions.QUADRATIC_CURVE_TO: + + cpx = args[ 2 ]; + cpy = args[ 3 ]; + + cpx1 = args[ 0 ]; + cpy1 = args[ 1 ]; + + if ( points.length > 0 ) { + + laste = points[ points.length - 1 ]; + + cpx0 = laste.x; + cpy0 = laste.y; + + } else { + + laste = this.actions[ i - 1 ].args; + + cpx0 = laste[ laste.length - 2 ]; + cpy0 = laste[ laste.length - 1 ]; + + } + + for ( j = 1; j <= divisions; j ++ ) { + + t = j / divisions; + + tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx ); + ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy ); + + points.push( new THREE.Vector2( tx, ty ) ); + + } + + break; + + case THREE.PathActions.BEZIER_CURVE_TO: + + cpx = args[ 4 ]; + cpy = args[ 5 ]; + + cpx1 = args[ 0 ]; + cpy1 = args[ 1 ]; + + cpx2 = args[ 2 ]; + cpy2 = args[ 3 ]; + + if ( points.length > 0 ) { + + laste = points[ points.length - 1 ]; + + cpx0 = laste.x; + cpy0 = laste.y; + + } else { + + laste = this.actions[ i - 1 ].args; + + cpx0 = laste[ laste.length - 2 ]; + cpy0 = laste[ laste.length - 1 ]; + + } + + + for ( j = 1; j <= divisions; j ++ ) { + + t = j / divisions; + + tx = THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx ); + ty = THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy ); + + points.push( new THREE.Vector2( tx, ty ) ); + + } + + break; + + case THREE.PathActions.CSPLINE_THRU: + + laste = this.actions[ i - 1 ].args; + + var last = new THREE.Vector2( laste[ laste.length - 2 ], laste[ laste.length - 1 ] ); + var spts = [ last ]; + + var n = divisions * args[ 0 ].length; + + spts = spts.concat( args[ 0 ] ); + + var spline = new THREE.SplineCurve( spts ); + + for ( j = 1; j <= n; j ++ ) { + + points.push( spline.getPointAt( j / n ) ) ; + + } + + break; + + case THREE.PathActions.ARC: + + var aX = args[ 0 ], aY = args[ 1 ], + aRadius = args[ 2 ], + aStartAngle = args[ 3 ], aEndAngle = args[ 4 ], + aClockwise = !!args[ 5 ]; + + var deltaAngle = aEndAngle - aStartAngle; + var angle; + var tdivisions = divisions * 2; + + for ( j = 1; j <= tdivisions; j ++ ) { + + t = j / tdivisions; + + if ( ! aClockwise ) { + + t = 1 - t; + + } + + angle = aStartAngle + t * deltaAngle; + + tx = aX + aRadius * Math.cos( angle ); + ty = aY + aRadius * Math.sin( angle ); + + //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty); + + points.push( new THREE.Vector2( tx, ty ) ); + + } + + //console.log(points); + + break; + + case THREE.PathActions.ELLIPSE: + + var aX = args[ 0 ], aY = args[ 1 ], + xRadius = args[ 2 ], + yRadius = args[ 3 ], + aStartAngle = args[ 4 ], aEndAngle = args[ 5 ], + aClockwise = !!args[ 6 ]; + + + var deltaAngle = aEndAngle - aStartAngle; + var angle; + var tdivisions = divisions * 2; + + for ( j = 1; j <= tdivisions; j ++ ) { + + t = j / tdivisions; + + if ( ! aClockwise ) { + + t = 1 - t; + + } + + angle = aStartAngle + t * deltaAngle; + + tx = aX + xRadius * Math.cos( angle ); + ty = aY + yRadius * Math.sin( angle ); + + //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty); + + points.push( new THREE.Vector2( tx, ty ) ); + + } + + //console.log(points); + + break; + + } // end switch + + } + + + + // Normalize to remove the closing point by default. + var lastPoint = points[ points.length - 1]; + var EPSILON = 0.0000000001; + if ( Math.abs(lastPoint.x - points[ 0 ].x) < EPSILON && + Math.abs(lastPoint.y - points[ 0 ].y) < EPSILON) + points.splice( points.length - 1, 1); + if ( closedPath ) { + + points.push( points[ 0 ] ); + + } + + return points; + +}; + +// Breaks path into shapes + +THREE.Path.prototype.toShapes = function() { + + var i, il, item, action, args; + + var subPaths = [], lastPath = new THREE.Path(); + + for ( i = 0, il = this.actions.length; i < il; i ++ ) { + + item = this.actions[ i ]; + + args = item.args; + action = item.action; + + if ( action == THREE.PathActions.MOVE_TO ) { + + if ( lastPath.actions.length != 0 ) { + + subPaths.push( lastPath ); + lastPath = new THREE.Path(); + + } + + } + + lastPath[ action ].apply( lastPath, args ); + + } + + if ( lastPath.actions.length != 0 ) { + + subPaths.push( lastPath ); + + } + + // console.log(subPaths); + + if ( subPaths.length == 0 ) return []; + + var tmpPath, tmpShape, shapes = []; + + var holesFirst = !THREE.Shape.Utils.isClockWise( subPaths[ 0 ].getPoints() ); + // console.log("Holes first", holesFirst); + + if ( subPaths.length == 1) { + tmpPath = subPaths[0]; + tmpShape = new THREE.Shape(); + tmpShape.actions = tmpPath.actions; + tmpShape.curves = tmpPath.curves; + shapes.push( tmpShape ); + return shapes; + }; + + if ( holesFirst ) { + + tmpShape = new THREE.Shape(); + + for ( i = 0, il = subPaths.length; i < il; i ++ ) { + + tmpPath = subPaths[ i ]; + + if ( THREE.Shape.Utils.isClockWise( tmpPath.getPoints() ) ) { + + tmpShape.actions = tmpPath.actions; + tmpShape.curves = tmpPath.curves; + + shapes.push( tmpShape ); + tmpShape = new THREE.Shape(); + + //console.log('cw', i); + + } else { + + tmpShape.holes.push( tmpPath ); + + //console.log('ccw', i); + + } + + } + + } else { + + // Shapes first + + for ( i = 0, il = subPaths.length; i < il; i ++ ) { + + tmpPath = subPaths[ i ]; + + if ( THREE.Shape.Utils.isClockWise( tmpPath.getPoints() ) ) { + + + if ( tmpShape ) shapes.push( tmpShape ); + + tmpShape = new THREE.Shape(); + tmpShape.actions = tmpPath.actions; + tmpShape.curves = tmpPath.curves; + + } else { + + tmpShape.holes.push( tmpPath ); + + } + + } + + shapes.push( tmpShape ); + + } + + //console.log("shape", shapes); + + return shapes; + +}; +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * Defines a 2d shape plane using paths. + **/ + +// STEP 1 Create a path. +// STEP 2 Turn path into shape. +// STEP 3 ExtrudeGeometry takes in Shape/Shapes +// STEP 3a - Extract points from each shape, turn to vertices +// STEP 3b - Triangulate each shape, add faces. + +THREE.Shape = function () { + + THREE.Path.apply( this, arguments ); + this.holes = []; + +}; + +THREE.Shape.prototype = Object.create( THREE.Path.prototype ); + +// Convenience method to return ExtrudeGeometry + +THREE.Shape.prototype.extrude = function ( options ) { + + var extruded = new THREE.ExtrudeGeometry( this, options ); + return extruded; + +}; + +// Convenience method to return ShapeGeometry + +THREE.Shape.prototype.makeGeometry = function ( options ) { + + var geometry = new THREE.ShapeGeometry( this, options ); + return geometry; + +}; + +// Get points of holes + +THREE.Shape.prototype.getPointsHoles = function ( divisions ) { + + var i, il = this.holes.length, holesPts = []; + + for ( i = 0; i < il; i ++ ) { + + holesPts[ i ] = this.holes[ i ].getTransformedPoints( divisions, this.bends ); + + } + + return holesPts; + +}; + +// Get points of holes (spaced by regular distance) + +THREE.Shape.prototype.getSpacedPointsHoles = function ( divisions ) { + + var i, il = this.holes.length, holesPts = []; + + for ( i = 0; i < il; i ++ ) { + + holesPts[ i ] = this.holes[ i ].getTransformedSpacedPoints( divisions, this.bends ); + + } + + return holesPts; + +}; + + +// Get points of shape and holes (keypoints based on segments parameter) + +THREE.Shape.prototype.extractAllPoints = function ( divisions ) { + + return { + + shape: this.getTransformedPoints( divisions ), + holes: this.getPointsHoles( divisions ) + + }; + +}; + +THREE.Shape.prototype.extractPoints = function ( divisions ) { + + if (this.useSpacedPoints) { + return this.extractAllSpacedPoints(divisions); + } + + return this.extractAllPoints(divisions); + +}; + +// +// THREE.Shape.prototype.extractAllPointsWithBend = function ( divisions, bend ) { +// +// return { +// +// shape: this.transform( bend, divisions ), +// holes: this.getPointsHoles( divisions, bend ) +// +// }; +// +// }; + +// Get points of shape and holes (spaced by regular distance) + +THREE.Shape.prototype.extractAllSpacedPoints = function ( divisions ) { + + return { + + shape: this.getTransformedSpacedPoints( divisions ), + holes: this.getSpacedPointsHoles( divisions ) + + }; + +}; + +/************************************************************** + * Utils + **************************************************************/ + +THREE.Shape.Utils = { + + /* + contour - array of vector2 for contour + holes - array of array of vector2 + */ + + removeHoles: function ( contour, holes ) { + + var shape = contour.concat(); // work on this shape + var allpoints = shape.concat(); + + /* For each isolated shape, find the closest points and break to the hole to allow triangulation */ + + + var prevShapeVert, nextShapeVert, + prevHoleVert, nextHoleVert, + holeIndex, shapeIndex, + shapeId, shapeGroup, + h, h2, + hole, shortest, d, + p, pts1, pts2, + tmpShape1, tmpShape2, + tmpHole1, tmpHole2, + verts = []; + + for ( h = 0; h < holes.length; h ++ ) { + + hole = holes[ h ]; + + /* + shapeholes[ h ].concat(); // preserves original + holes.push( hole ); + */ + + Array.prototype.push.apply( allpoints, hole ); + + shortest = Number.POSITIVE_INFINITY; + + + // Find the shortest pair of pts between shape and hole + + // Note: Actually, I'm not sure now if we could optimize this to be faster than O(m*n) + // Using distanceToSquared() intead of distanceTo() should speed a little + // since running square roots operations are reduced. + + for ( h2 = 0; h2 < hole.length; h2 ++ ) { + + pts1 = hole[ h2 ]; + var dist = []; + + for ( p = 0; p < shape.length; p++ ) { + + pts2 = shape[ p ]; + d = pts1.distanceToSquared( pts2 ); + dist.push( d ); + + if ( d < shortest ) { + + shortest = d; + holeIndex = h2; + shapeIndex = p; + + } + + } + + } + + //console.log("shortest", shortest, dist); + + prevShapeVert = ( shapeIndex - 1 ) >= 0 ? shapeIndex - 1 : shape.length - 1; + prevHoleVert = ( holeIndex - 1 ) >= 0 ? holeIndex - 1 : hole.length - 1; + + var areaapts = [ + + hole[ holeIndex ], + shape[ shapeIndex ], + shape[ prevShapeVert ] + + ]; + + var areaa = THREE.FontUtils.Triangulate.area( areaapts ); + + var areabpts = [ + + hole[ holeIndex ], + hole[ prevHoleVert ], + shape[ shapeIndex ] + + ]; + + var areab = THREE.FontUtils.Triangulate.area( areabpts ); + + var shapeOffset = 1; + var holeOffset = -1; + + var oldShapeIndex = shapeIndex, oldHoleIndex = holeIndex; + shapeIndex += shapeOffset; + holeIndex += holeOffset; + + if ( shapeIndex < 0 ) { shapeIndex += shape.length; } + shapeIndex %= shape.length; + + if ( holeIndex < 0 ) { holeIndex += hole.length; } + holeIndex %= hole.length; + + prevShapeVert = ( shapeIndex - 1 ) >= 0 ? shapeIndex - 1 : shape.length - 1; + prevHoleVert = ( holeIndex - 1 ) >= 0 ? holeIndex - 1 : hole.length - 1; + + areaapts = [ + + hole[ holeIndex ], + shape[ shapeIndex ], + shape[ prevShapeVert ] + + ]; + + var areaa2 = THREE.FontUtils.Triangulate.area( areaapts ); + + areabpts = [ + + hole[ holeIndex ], + hole[ prevHoleVert ], + shape[ shapeIndex ] + + ]; + + var areab2 = THREE.FontUtils.Triangulate.area( areabpts ); + //console.log(areaa,areab ,areaa2,areab2, ( areaa + areab ), ( areaa2 + areab2 )); + + if ( ( areaa + areab ) > ( areaa2 + areab2 ) ) { + + // In case areas are not correct. + //console.log("USE THIS"); + + shapeIndex = oldShapeIndex; + holeIndex = oldHoleIndex ; + + if ( shapeIndex < 0 ) { shapeIndex += shape.length; } + shapeIndex %= shape.length; + + if ( holeIndex < 0 ) { holeIndex += hole.length; } + holeIndex %= hole.length; + + prevShapeVert = ( shapeIndex - 1 ) >= 0 ? shapeIndex - 1 : shape.length - 1; + prevHoleVert = ( holeIndex - 1 ) >= 0 ? holeIndex - 1 : hole.length - 1; + + } else { + + //console.log("USE THAT ") + + } + + tmpShape1 = shape.slice( 0, shapeIndex ); + tmpShape2 = shape.slice( shapeIndex ); + tmpHole1 = hole.slice( holeIndex ); + tmpHole2 = hole.slice( 0, holeIndex ); + + // Should check orders here again? + + var trianglea = [ + + hole[ holeIndex ], + shape[ shapeIndex ], + shape[ prevShapeVert ] + + ]; + + var triangleb = [ + + hole[ holeIndex ] , + hole[ prevHoleVert ], + shape[ shapeIndex ] + + ]; + + verts.push( trianglea ); + verts.push( triangleb ); + + shape = tmpShape1.concat( tmpHole1 ).concat( tmpHole2 ).concat( tmpShape2 ); + + } + + return { + + shape:shape, /* shape with no holes */ + isolatedPts: verts, /* isolated faces */ + allpoints: allpoints + + } + + + }, + + triangulateShape: function ( contour, holes ) { + + var shapeWithoutHoles = THREE.Shape.Utils.removeHoles( contour, holes ); + + var shape = shapeWithoutHoles.shape, + allpoints = shapeWithoutHoles.allpoints, + isolatedPts = shapeWithoutHoles.isolatedPts; + + var triangles = THREE.FontUtils.Triangulate( shape, false ); // True returns indices for points of spooled shape + + // 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. + + //console.log( "triangles",triangles, triangles.length ); + //console.log( "allpoints",allpoints, allpoints.length ); + + var i, il, f, face, + key, index, + allPointsMap = {}, + isolatedPointsMap = {}; + + // prepare all points map + + for ( i = 0, il = allpoints.length; i < il; i ++ ) { + + key = allpoints[ i ].x + ":" + allpoints[ i ].y; + + if ( allPointsMap[ key ] !== undefined ) { + + console.log( "Duplicate point", key ); + + } + + allPointsMap[ key ] = i; + + } + + // check all face vertices against all points map + + for ( i = 0, il = triangles.length; i < il; i ++ ) { + + face = triangles[ i ]; + + for ( f = 0; f < 3; f ++ ) { + + key = face[ f ].x + ":" + face[ f ].y; + + index = allPointsMap[ key ]; + + if ( index !== undefined ) { + + face[ f ] = index; + + } + + } + + } + + // check isolated points vertices against all points map + + for ( i = 0, il = isolatedPts.length; i < il; i ++ ) { + + face = isolatedPts[ i ]; + + for ( f = 0; f < 3; f ++ ) { + + key = face[ f ].x + ":" + face[ f ].y; + + index = allPointsMap[ key ]; + + if ( index !== undefined ) { + + face[ f ] = index; + + } + + } + + } + + return triangles.concat( isolatedPts ); + + }, // end triangulate shapes + + /* + triangulate2 : function( pts, holes ) { + + // For use with Poly2Tri.js + + var allpts = pts.concat(); + var shape = []; + for (var p in pts) { + shape.push(new js.poly2tri.Point(pts[p].x, pts[p].y)); + } + + var swctx = new js.poly2tri.SweepContext(shape); + + for (var h in holes) { + var aHole = holes[h]; + var newHole = [] + for (i in aHole) { + newHole.push(new js.poly2tri.Point(aHole[i].x, aHole[i].y)); + allpts.push(aHole[i]); + } + swctx.AddHole(newHole); + } + + var find; + var findIndexForPt = function (pt) { + find = new THREE.Vector2(pt.x, pt.y); + var p; + for (p=0, pl = allpts.length; p<pl; p++) { + if (allpts[p].equals(find)) return p; + } + return -1; + }; + + // triangulate + js.poly2tri.sweep.Triangulate(swctx); + + var triangles = swctx.GetTriangles(); + var tr ; + var facesPts = []; + for (var t in triangles) { + tr = triangles[t]; + facesPts.push([ + findIndexForPt(tr.GetPoint(0)), + findIndexForPt(tr.GetPoint(1)), + findIndexForPt(tr.GetPoint(2)) + ]); + } + + + // console.log(facesPts); + // console.log("triangles", triangles.length, triangles); + + // Returns array of faces with 3 element each + return facesPts; + }, +*/ + + isClockWise: function ( pts ) { + + return THREE.FontUtils.Triangulate.area( pts ) < 0; + + }, + + // Bezier Curves formulas obtained from + // http://en.wikipedia.org/wiki/B%C3%A9zier_curve + + // Quad Bezier Functions + + b2p0: function ( t, p ) { + + var k = 1 - t; + return k * k * p; + + }, + + b2p1: function ( t, p ) { + + return 2 * ( 1 - t ) * t * p; + + }, + + b2p2: function ( t, p ) { + + return t * t * p; + + }, + + b2: function ( t, p0, p1, p2 ) { + + return this.b2p0( t, p0 ) + this.b2p1( t, p1 ) + this.b2p2( t, p2 ); + + }, + + // Cubic Bezier Functions + + b3p0: function ( t, p ) { + + var k = 1 - t; + return k * k * k * p; + + }, + + b3p1: function ( t, p ) { + + var k = 1 - t; + return 3 * k * k * t * p; + + }, + + b3p2: function ( t, p ) { + + var k = 1 - t; + return 3 * k * t * t * p; + + }, + + b3p3: function ( t, p ) { + + return t * t * t * p; + + }, + + b3: function ( t, p0, p1, p2, p3 ) { + + return this.b3p0( t, p0 ) + this.b3p1( t, p1 ) + this.b3p2( t, p2 ) + this.b3p3( t, p3 ); + + } + +}; + +/** + * @author mikael emtinger / http://gomo.se/ + */ + +THREE.AnimationHandler = (function() { + + var playing = []; + var library = {}; + var that = {}; + + + //--- update --- + + that.update = function( deltaTimeMS ) { + + for( var i = 0; i < playing.length; i ++ ) + playing[ i ].update( deltaTimeMS ); + + }; + + + //--- add --- + + that.addToUpdate = function( animation ) { + + if ( playing.indexOf( animation ) === -1 ) + playing.push( animation ); + + }; + + + //--- remove --- + + that.removeFromUpdate = function( animation ) { + + var index = playing.indexOf( animation ); + + if( index !== -1 ) + playing.splice( index, 1 ); + + }; + + + //--- add --- + + that.add = function( data ) { + + if ( library[ data.name ] !== undefined ) + console.log( "THREE.AnimationHandler.add: Warning! " + data.name + " already exists in library. Overwriting." ); + + library[ data.name ] = data; + initData( data ); + + }; + + + //--- get --- + + that.get = function( name ) { + + if ( typeof name === "string" ) { + + if ( library[ name ] ) { + + return library[ name ]; + + } else { + + console.log( "THREE.AnimationHandler.get: Couldn't find animation " + name ); + return null; + + } + + } else { + + // todo: add simple tween library + + } + + }; + + //--- parse --- + + that.parse = function( root ) { + + // setup hierarchy + + var hierarchy = []; + + if ( root instanceof THREE.SkinnedMesh ) { + + for( var b = 0; b < root.bones.length; b++ ) { + + hierarchy.push( root.bones[ b ] ); + + } + + } else { + + parseRecurseHierarchy( root, hierarchy ); + + } + + return hierarchy; + + }; + + var parseRecurseHierarchy = function( root, hierarchy ) { + + hierarchy.push( root ); + + for( var c = 0; c < root.children.length; c++ ) + parseRecurseHierarchy( root.children[ c ], hierarchy ); + + } + + + //--- init data --- + + var initData = function( data ) { + + if( data.initialized === true ) + return; + + + // loop through all keys + + for( var h = 0; h < data.hierarchy.length; h ++ ) { + + for( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { + + // remove minus times + + if( data.hierarchy[ h ].keys[ k ].time < 0 ) + data.hierarchy[ h ].keys[ k ].time = 0; + + + // create quaternions + + if( data.hierarchy[ h ].keys[ k ].rot !== undefined && + !( data.hierarchy[ h ].keys[ k ].rot instanceof THREE.Quaternion ) ) { + + var quat = data.hierarchy[ h ].keys[ k ].rot; + data.hierarchy[ h ].keys[ k ].rot = new THREE.Quaternion( quat[0], quat[1], quat[2], quat[3] ); + + } + + } + + + // prepare morph target keys + + if( data.hierarchy[ h ].keys.length && data.hierarchy[ h ].keys[ 0 ].morphTargets !== undefined ) { + + // get all used + + var usedMorphTargets = {}; + + for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { + + for ( var m = 0; m < data.hierarchy[ h ].keys[ k ].morphTargets.length; m ++ ) { + + var morphTargetName = data.hierarchy[ h ].keys[ k ].morphTargets[ m ]; + usedMorphTargets[ morphTargetName ] = -1; + + } + + } + + data.hierarchy[ h ].usedMorphTargets = usedMorphTargets; + + + // set all used on all frames + + for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { + + var influences = {}; + + for ( var morphTargetName in usedMorphTargets ) { + + for ( var m = 0; m < data.hierarchy[ h ].keys[ k ].morphTargets.length; m ++ ) { + + if ( data.hierarchy[ h ].keys[ k ].morphTargets[ m ] === morphTargetName ) { + + influences[ morphTargetName ] = data.hierarchy[ h ].keys[ k ].morphTargetsInfluences[ m ]; + break; + + } + + } + + if ( m === data.hierarchy[ h ].keys[ k ].morphTargets.length ) { + + influences[ morphTargetName ] = 0; + + } + + } + + data.hierarchy[ h ].keys[ k ].morphTargetsInfluences = influences; + + } + + } + + + // remove all keys that are on the same time + + for ( var k = 1; k < data.hierarchy[ h ].keys.length; k ++ ) { + + if ( data.hierarchy[ h ].keys[ k ].time === data.hierarchy[ h ].keys[ k - 1 ].time ) { + + data.hierarchy[ h ].keys.splice( k, 1 ); + k --; + + } + + } + + + // set index + + for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { + + data.hierarchy[ h ].keys[ k ].index = k; + + } + + } + + + // JIT + + var lengthInFrames = parseInt( data.length * data.fps, 10 ); + + data.JIT = {}; + data.JIT.hierarchy = []; + + for( var h = 0; h < data.hierarchy.length; h ++ ) + data.JIT.hierarchy.push( new Array( lengthInFrames ) ); + + + // done + + data.initialized = true; + + }; + + + // interpolation types + + that.LINEAR = 0; + that.CATMULLROM = 1; + that.CATMULLROM_FORWARD = 2; + + return that; + +}()); +/** + * @author mikael emtinger / http://gomo.se/ + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Animation = function ( root, name, interpolationType ) { + + this.root = root; + this.data = THREE.AnimationHandler.get( name ); + this.hierarchy = THREE.AnimationHandler.parse( root ); + + this.currentTime = 0; + this.timeScale = 1; + + this.isPlaying = false; + this.isPaused = true; + this.loop = true; + + this.interpolationType = interpolationType !== undefined ? interpolationType : THREE.AnimationHandler.LINEAR; + + this.points = []; + this.target = new THREE.Vector3(); + +}; + +THREE.Animation.prototype.play = function ( loop, startTimeMS ) { + + if ( this.isPlaying === false ) { + + this.isPlaying = true; + this.loop = loop !== undefined ? loop : true; + this.currentTime = startTimeMS !== undefined ? startTimeMS : 0; + + // reset key cache + + var h, hl = this.hierarchy.length, + object; + + for ( h = 0; h < hl; h ++ ) { + + object = this.hierarchy[ h ]; + + if ( this.interpolationType !== THREE.AnimationHandler.CATMULLROM_FORWARD ) { + + object.useQuaternion = true; + + } + + object.matrixAutoUpdate = true; + + if ( object.animationCache === undefined ) { + + object.animationCache = {}; + object.animationCache.prevKey = { pos: 0, rot: 0, scl: 0 }; + object.animationCache.nextKey = { pos: 0, rot: 0, scl: 0 }; + object.animationCache.originalMatrix = object instanceof THREE.Bone ? object.skinMatrix : object.matrix; + + } + + var prevKey = object.animationCache.prevKey; + var nextKey = object.animationCache.nextKey; + + prevKey.pos = this.data.hierarchy[ h ].keys[ 0 ]; + prevKey.rot = this.data.hierarchy[ h ].keys[ 0 ]; + prevKey.scl = this.data.hierarchy[ h ].keys[ 0 ]; + + nextKey.pos = this.getNextKeyWith( "pos", h, 1 ); + nextKey.rot = this.getNextKeyWith( "rot", h, 1 ); + nextKey.scl = this.getNextKeyWith( "scl", h, 1 ); + + } + + this.update( 0 ); + + } + + this.isPaused = false; + + THREE.AnimationHandler.addToUpdate( this ); + +}; + + +THREE.Animation.prototype.pause = function() { + + if ( this.isPaused === true ) { + + THREE.AnimationHandler.addToUpdate( this ); + + } else { + + THREE.AnimationHandler.removeFromUpdate( this ); + + } + + this.isPaused = !this.isPaused; + +}; + + +THREE.Animation.prototype.stop = function() { + + this.isPlaying = false; + this.isPaused = false; + THREE.AnimationHandler.removeFromUpdate( this ); + +}; + + +THREE.Animation.prototype.update = function ( deltaTimeMS ) { + + // early out + + if ( this.isPlaying === false ) return; + + + // vars + + var types = [ "pos", "rot", "scl" ]; + var type; + var scale; + var vector; + var prevXYZ, nextXYZ; + var prevKey, nextKey; + var object; + var animationCache; + var frame; + var JIThierarchy = this.data.JIT.hierarchy; + var currentTime, unloopedCurrentTime; + var currentPoint, forwardPoint, angle; + + + this.currentTime += deltaTimeMS * this.timeScale; + + unloopedCurrentTime = this.currentTime; + currentTime = this.currentTime = this.currentTime % this.data.length; + frame = parseInt( Math.min( currentTime * this.data.fps, this.data.length * this.data.fps ), 10 ); + + + for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { + + object = this.hierarchy[ h ]; + animationCache = object.animationCache; + + // loop through pos/rot/scl + + for ( var t = 0; t < 3; t ++ ) { + + // get keys + + type = types[ t ]; + prevKey = animationCache.prevKey[ type ]; + nextKey = animationCache.nextKey[ type ]; + + // switch keys? + + if ( nextKey.time <= unloopedCurrentTime ) { + + // did we loop? + + if ( currentTime < unloopedCurrentTime ) { + + if ( this.loop ) { + + prevKey = this.data.hierarchy[ h ].keys[ 0 ]; + nextKey = this.getNextKeyWith( type, h, 1 ); + + while( nextKey.time < currentTime ) { + + prevKey = nextKey; + nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 ); + + } + + } else { + + this.stop(); + return; + + } + + } else { + + do { + + prevKey = nextKey; + nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 ); + + } while( nextKey.time < currentTime ) + + } + + animationCache.prevKey[ type ] = prevKey; + animationCache.nextKey[ type ] = nextKey; + + } + + + object.matrixAutoUpdate = true; + object.matrixWorldNeedsUpdate = true; + + scale = ( currentTime - prevKey.time ) / ( nextKey.time - prevKey.time ); + prevXYZ = prevKey[ type ]; + nextXYZ = nextKey[ type ]; + + + // check scale error + + if ( scale < 0 || scale > 1 ) { + + console.log( "THREE.Animation.update: Warning! Scale out of bounds:" + scale + " on bone " + h ); + scale = scale < 0 ? 0 : 1; + + } + + // interpolate + + if ( type === "pos" ) { + + vector = object.position; + + if ( this.interpolationType === THREE.AnimationHandler.LINEAR ) { + + vector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale; + vector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale; + vector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale; + + } else if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || + this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { + + this.points[ 0 ] = this.getPrevKeyWith( "pos", h, prevKey.index - 1 )[ "pos" ]; + this.points[ 1 ] = prevXYZ; + this.points[ 2 ] = nextXYZ; + this.points[ 3 ] = this.getNextKeyWith( "pos", h, nextKey.index + 1 )[ "pos" ]; + + scale = scale * 0.33 + 0.33; + + currentPoint = this.interpolateCatmullRom( this.points, scale ); + + vector.x = currentPoint[ 0 ]; + vector.y = currentPoint[ 1 ]; + vector.z = currentPoint[ 2 ]; + + if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { + + forwardPoint = this.interpolateCatmullRom( this.points, scale * 1.01 ); + + this.target.set( forwardPoint[ 0 ], forwardPoint[ 1 ], forwardPoint[ 2 ] ); + this.target.sub( vector ); + this.target.y = 0; + this.target.normalize(); + + angle = Math.atan2( this.target.x, this.target.z ); + object.rotation.set( 0, angle, 0 ); + + } + + } + + } else if ( type === "rot" ) { + + THREE.Quaternion.slerp( prevXYZ, nextXYZ, object.quaternion, scale ); + + } else if ( type === "scl" ) { + + vector = object.scale; + + vector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale; + vector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale; + vector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale; + + } + + } + + } + +}; + +// Catmull-Rom spline + +THREE.Animation.prototype.interpolateCatmullRom = function ( points, scale ) { + + var c = [], v3 = [], + point, intPoint, weight, w2, w3, + pa, pb, pc, pd; + + point = ( points.length - 1 ) * scale; + intPoint = Math.floor( point ); + weight = point - intPoint; + + c[ 0 ] = intPoint === 0 ? intPoint : intPoint - 1; + c[ 1 ] = intPoint; + c[ 2 ] = intPoint > points.length - 2 ? intPoint : intPoint + 1; + c[ 3 ] = intPoint > points.length - 3 ? intPoint : intPoint + 2; + + pa = points[ c[ 0 ] ]; + pb = points[ c[ 1 ] ]; + pc = points[ c[ 2 ] ]; + pd = points[ c[ 3 ] ]; + + w2 = weight * weight; + w3 = weight * w2; + + v3[ 0 ] = this.interpolate( pa[ 0 ], pb[ 0 ], pc[ 0 ], pd[ 0 ], weight, w2, w3 ); + v3[ 1 ] = this.interpolate( pa[ 1 ], pb[ 1 ], pc[ 1 ], pd[ 1 ], weight, w2, w3 ); + v3[ 2 ] = this.interpolate( pa[ 2 ], pb[ 2 ], pc[ 2 ], pd[ 2 ], weight, w2, w3 ); + + return v3; + +}; + +THREE.Animation.prototype.interpolate = function ( p0, p1, p2, p3, t, t2, t3 ) { + + var v0 = ( p2 - p0 ) * 0.5, + v1 = ( p3 - p1 ) * 0.5; + + return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1; + +}; + + + +// Get next key with + +THREE.Animation.prototype.getNextKeyWith = function ( type, h, key ) { + + var keys = this.data.hierarchy[ h ].keys; + + if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || + this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { + + key = key < keys.length - 1 ? key : keys.length - 1; + + } else { + + key = key % keys.length; + + } + + for ( ; key < keys.length; key++ ) { + + if ( keys[ key ][ type ] !== undefined ) { + + return keys[ key ]; + + } + + } + + return this.data.hierarchy[ h ].keys[ 0 ]; + +}; + +// Get previous key with + +THREE.Animation.prototype.getPrevKeyWith = function ( type, h, key ) { + + var keys = this.data.hierarchy[ h ].keys; + + if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || + this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { + + key = key > 0 ? key : 0; + + } else { + + key = key >= 0 ? key : key + keys.length; + + } + + + for ( ; key >= 0; key -- ) { + + if ( keys[ key ][ type ] !== undefined ) { + + return keys[ key ]; + + } + + } + + return this.data.hierarchy[ h ].keys[ keys.length - 1 ]; + +}; +/** + * @author mikael emtinger / http://gomo.se/ + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * @author khang duong + * @author erik kitson + */ + +THREE.KeyFrameAnimation = function( root, data, JITCompile ) { + + this.root = root; + this.data = THREE.AnimationHandler.get( data ); + this.hierarchy = THREE.AnimationHandler.parse( root ); + this.currentTime = 0; + this.timeScale = 0.001; + this.isPlaying = false; + this.isPaused = true; + this.loop = true; + this.JITCompile = JITCompile !== undefined ? JITCompile : true; + + // initialize to first keyframes + + for ( var h = 0, hl = this.hierarchy.length; h < hl; h++ ) { + + var keys = this.data.hierarchy[h].keys, + sids = this.data.hierarchy[h].sids, + obj = this.hierarchy[h]; + + if ( keys.length && sids ) { + + for ( var s = 0; s < sids.length; s++ ) { + + var sid = sids[ s ], + next = this.getNextKeyWith( sid, h, 0 ); + + if ( next ) { + + next.apply( sid ); + + } + + } + + obj.matrixAutoUpdate = false; + this.data.hierarchy[h].node.updateMatrix(); + obj.matrixWorldNeedsUpdate = true; + + } + + } + +}; + +// Play + +THREE.KeyFrameAnimation.prototype.play = function( loop, startTimeMS ) { + + if( !this.isPlaying ) { + + this.isPlaying = true; + this.loop = loop !== undefined ? loop : true; + this.currentTime = startTimeMS !== undefined ? startTimeMS : 0; + this.startTimeMs = startTimeMS; + this.startTime = 10000000; + this.endTime = -this.startTime; + + + // reset key cache + + var h, hl = this.hierarchy.length, + object, + node; + + for ( h = 0; h < hl; h++ ) { + + object = this.hierarchy[ h ]; + node = this.data.hierarchy[ h ]; + object.useQuaternion = true; + + if ( node.animationCache === undefined ) { + + node.animationCache = {}; + node.animationCache.prevKey = null; + node.animationCache.nextKey = null; + node.animationCache.originalMatrix = object instanceof THREE.Bone ? object.skinMatrix : object.matrix; + + } + + var keys = this.data.hierarchy[h].keys; + + if (keys.length) { + + node.animationCache.prevKey = keys[ 0 ]; + node.animationCache.nextKey = keys[ 1 ]; + + this.startTime = Math.min( keys[0].time, this.startTime ); + this.endTime = Math.max( keys[keys.length - 1].time, this.endTime ); + + } + + } + + this.update( 0 ); + + } + + this.isPaused = false; + + THREE.AnimationHandler.addToUpdate( this ); + +}; + + + +// Pause + +THREE.KeyFrameAnimation.prototype.pause = function() { + + if( this.isPaused ) { + + THREE.AnimationHandler.addToUpdate( this ); + + } else { + + THREE.AnimationHandler.removeFromUpdate( this ); + + } + + this.isPaused = !this.isPaused; + +}; + + +// Stop + +THREE.KeyFrameAnimation.prototype.stop = function() { + + this.isPlaying = false; + this.isPaused = false; + THREE.AnimationHandler.removeFromUpdate( this ); + + + // reset JIT matrix and remove cache + + for ( var h = 0; h < this.data.hierarchy.length; h++ ) { + + var obj = this.hierarchy[ h ]; + var node = this.data.hierarchy[ h ]; + + if ( node.animationCache !== undefined ) { + + var original = node.animationCache.originalMatrix; + + if( obj instanceof THREE.Bone ) { + + original.copy( obj.skinMatrix ); + obj.skinMatrix = original; + + } else { + + original.copy( obj.matrix ); + obj.matrix = original; + + } + + delete node.animationCache; + + } + + } + +}; + + +// Update + +THREE.KeyFrameAnimation.prototype.update = function( deltaTimeMS ) { + + // early out + + if( !this.isPlaying ) return; + + + // vars + + var prevKey, nextKey; + var object; + var node; + var frame; + var JIThierarchy = this.data.JIT.hierarchy; + var currentTime, unloopedCurrentTime; + var looped; + + + // update + + this.currentTime += deltaTimeMS * this.timeScale; + + unloopedCurrentTime = this.currentTime; + currentTime = this.currentTime = this.currentTime % this.data.length; + + // if looped around, the current time should be based on the startTime + if ( currentTime < this.startTimeMs ) { + + currentTime = this.currentTime = this.startTimeMs + currentTime; + + } + + frame = parseInt( Math.min( currentTime * this.data.fps, this.data.length * this.data.fps ), 10 ); + looped = currentTime < unloopedCurrentTime; + + if ( looped && !this.loop ) { + + // Set the animation to the last keyframes and stop + for ( var h = 0, hl = this.hierarchy.length; h < hl; h++ ) { + + var keys = this.data.hierarchy[h].keys, + sids = this.data.hierarchy[h].sids, + end = keys.length-1, + obj = this.hierarchy[h]; + + if ( keys.length ) { + + for ( var s = 0; s < sids.length; s++ ) { + + var sid = sids[ s ], + prev = this.getPrevKeyWith( sid, h, end ); + + if ( prev ) { + prev.apply( sid ); + + } + + } + + this.data.hierarchy[h].node.updateMatrix(); + obj.matrixWorldNeedsUpdate = true; + + } + + } + + this.stop(); + return; + + } + + // check pre-infinity + if ( currentTime < this.startTime ) { + + return; + + } + + // update + + for ( var h = 0, hl = this.hierarchy.length; h < hl; h++ ) { + + object = this.hierarchy[ h ]; + node = this.data.hierarchy[ h ]; + + var keys = node.keys, + animationCache = node.animationCache; + + // use JIT? + + if ( this.JITCompile && JIThierarchy[ h ][ frame ] !== undefined ) { + + if( object instanceof THREE.Bone ) { + + object.skinMatrix = JIThierarchy[ h ][ frame ]; + object.matrixWorldNeedsUpdate = false; + + } else { + + object.matrix = JIThierarchy[ h ][ frame ]; + object.matrixWorldNeedsUpdate = true; + + } + + // use interpolation + + } else if ( keys.length ) { + + // make sure so original matrix and not JIT matrix is set + + if ( this.JITCompile && animationCache ) { + + if( object instanceof THREE.Bone ) { + + object.skinMatrix = animationCache.originalMatrix; + + } else { + + object.matrix = animationCache.originalMatrix; + + } + + } + + prevKey = animationCache.prevKey; + nextKey = animationCache.nextKey; + + if ( prevKey && nextKey ) { + + // switch keys? + + if ( nextKey.time <= unloopedCurrentTime ) { + + // did we loop? + + if ( looped && this.loop ) { + + prevKey = keys[ 0 ]; + nextKey = keys[ 1 ]; + + while ( nextKey.time < currentTime ) { + + prevKey = nextKey; + nextKey = keys[ prevKey.index + 1 ]; + + } + + } else if ( !looped ) { + + var lastIndex = keys.length - 1; + + while ( nextKey.time < currentTime && nextKey.index !== lastIndex ) { + + prevKey = nextKey; + nextKey = keys[ prevKey.index + 1 ]; + + } + + } + + animationCache.prevKey = prevKey; + animationCache.nextKey = nextKey; + + } + if(nextKey.time >= currentTime) + prevKey.interpolate( nextKey, currentTime ); + else + prevKey.interpolate( nextKey, nextKey.time); + + } + + this.data.hierarchy[h].node.updateMatrix(); + object.matrixWorldNeedsUpdate = true; + + } + + } + + // update JIT? + + if ( this.JITCompile ) { + + if ( JIThierarchy[ 0 ][ frame ] === undefined ) { + + this.hierarchy[ 0 ].updateMatrixWorld( true ); + + for ( var h = 0; h < this.hierarchy.length; h++ ) { + + if( this.hierarchy[ h ] instanceof THREE.Bone ) { + + JIThierarchy[ h ][ frame ] = this.hierarchy[ h ].skinMatrix.clone(); + + } else { + + JIThierarchy[ h ][ frame ] = this.hierarchy[ h ].matrix.clone(); + + } + + } + + } + + } + +}; + +// Get next key with + +THREE.KeyFrameAnimation.prototype.getNextKeyWith = function( sid, h, key ) { + + var keys = this.data.hierarchy[ h ].keys; + key = key % keys.length; + + for ( ; key < keys.length; key++ ) { + + if ( keys[ key ].hasTarget( sid ) ) { + + return keys[ key ]; + + } + + } + + return keys[ 0 ]; + +}; + +// Get previous key with + +THREE.KeyFrameAnimation.prototype.getPrevKeyWith = function( sid, h, key ) { + + var keys = this.data.hierarchy[ h ].keys; + key = key >= 0 ? key : key + keys.length; + + for ( ; key >= 0; key-- ) { + + if ( keys[ key ].hasTarget( sid ) ) { + + return keys[ key ]; + + } + + } + + return keys[ keys.length - 1 ]; + +}; +/** + * Camera for rendering cube maps + * - renders scene into axis-aligned cube + * + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.CubeCamera = function ( near, far, cubeResolution ) { + + THREE.Object3D.call( this ); + + var fov = 90, aspect = 1; + + var cameraPX = new THREE.PerspectiveCamera( fov, aspect, near, far ); + cameraPX.up.set( 0, -1, 0 ); + cameraPX.lookAt( new THREE.Vector3( 1, 0, 0 ) ); + this.add( cameraPX ); + + var cameraNX = new THREE.PerspectiveCamera( fov, aspect, near, far ); + cameraNX.up.set( 0, -1, 0 ); + cameraNX.lookAt( new THREE.Vector3( -1, 0, 0 ) ); + this.add( cameraNX ); + + var cameraPY = new THREE.PerspectiveCamera( fov, aspect, near, far ); + cameraPY.up.set( 0, 0, 1 ); + cameraPY.lookAt( new THREE.Vector3( 0, 1, 0 ) ); + this.add( cameraPY ); + + var cameraNY = new THREE.PerspectiveCamera( fov, aspect, near, far ); + cameraNY.up.set( 0, 0, -1 ); + cameraNY.lookAt( new THREE.Vector3( 0, -1, 0 ) ); + this.add( cameraNY ); + + var cameraPZ = new THREE.PerspectiveCamera( fov, aspect, near, far ); + cameraPZ.up.set( 0, -1, 0 ); + cameraPZ.lookAt( new THREE.Vector3( 0, 0, 1 ) ); + this.add( cameraPZ ); + + var cameraNZ = new THREE.PerspectiveCamera( fov, aspect, near, far ); + cameraNZ.up.set( 0, -1, 0 ); + cameraNZ.lookAt( new THREE.Vector3( 0, 0, -1 ) ); + this.add( cameraNZ ); + + this.renderTarget = new THREE.WebGLRenderTargetCube( cubeResolution, cubeResolution, { format: THREE.RGBFormat, magFilter: THREE.LinearFilter, minFilter: THREE.LinearFilter } ); + + this.updateCubeMap = function ( renderer, scene ) { + + var renderTarget = this.renderTarget; + var generateMipmaps = renderTarget.generateMipmaps; + + renderTarget.generateMipmaps = false; + + renderTarget.activeCubeFace = 0; + renderer.render( scene, cameraPX, renderTarget ); + + renderTarget.activeCubeFace = 1; + renderer.render( scene, cameraNX, renderTarget ); + + renderTarget.activeCubeFace = 2; + renderer.render( scene, cameraPY, renderTarget ); + + renderTarget.activeCubeFace = 3; + renderer.render( scene, cameraNY, renderTarget ); + + renderTarget.activeCubeFace = 4; + renderer.render( scene, cameraPZ, renderTarget ); + + renderTarget.generateMipmaps = generateMipmaps; + + renderTarget.activeCubeFace = 5; + renderer.render( scene, cameraNZ, renderTarget ); + + }; + +}; + +THREE.CubeCamera.prototype = Object.create( THREE.Object3D.prototype ); +/* + * @author zz85 / http://twitter.com/blurspline / http://www.lab4games.net/zz85/blog + * + * A general perpose camera, for setting FOV, Lens Focal Length, + * and switching between perspective and orthographic views easily. + * Use this only if you do not wish to manage + * both a Orthographic and Perspective Camera + * + */ + + +THREE.CombinedCamera = function ( width, height, fov, near, far, orthoNear, orthoFar ) { + + THREE.Camera.call( this ); + + this.fov = fov; + + this.left = -width / 2; + this.right = width / 2 + this.top = height / 2; + this.bottom = -height / 2; + + // We could also handle the projectionMatrix internally, but just wanted to test nested camera objects + + this.cameraO = new THREE.OrthographicCamera( width / - 2, width / 2, height / 2, height / - 2, orthoNear, orthoFar ); + this.cameraP = new THREE.PerspectiveCamera( fov, width / height, near, far ); + + this.zoom = 1; + + this.toPerspective(); + + var aspect = width/height; + +}; + +THREE.CombinedCamera.prototype = Object.create( THREE.Camera.prototype ); + +THREE.CombinedCamera.prototype.toPerspective = function () { + + // Switches to the Perspective Camera + + this.near = this.cameraP.near; + this.far = this.cameraP.far; + + this.cameraP.fov = this.fov / this.zoom ; + + this.cameraP.updateProjectionMatrix(); + + this.projectionMatrix = this.cameraP.projectionMatrix; + + this.inPerspectiveMode = true; + this.inOrthographicMode = false; + +}; + +THREE.CombinedCamera.prototype.toOrthographic = function () { + + // Switches to the Orthographic camera estimating viewport from Perspective + + var fov = this.fov; + var aspect = this.cameraP.aspect; + var near = this.cameraP.near; + var far = this.cameraP.far; + + // The size that we set is the mid plane of the viewing frustum + + var hyperfocus = ( near + far ) / 2; + + var halfHeight = Math.tan( fov / 2 ) * hyperfocus; + var planeHeight = 2 * halfHeight; + var planeWidth = planeHeight * aspect; + var halfWidth = planeWidth / 2; + + halfHeight /= this.zoom; + halfWidth /= this.zoom; + + this.cameraO.left = -halfWidth; + this.cameraO.right = halfWidth; + this.cameraO.top = halfHeight; + this.cameraO.bottom = -halfHeight; + + // this.cameraO.left = -farHalfWidth; + // this.cameraO.right = farHalfWidth; + // this.cameraO.top = farHalfHeight; + // this.cameraO.bottom = -farHalfHeight; + + // this.cameraO.left = this.left / this.zoom; + // this.cameraO.right = this.right / this.zoom; + // this.cameraO.top = this.top / this.zoom; + // this.cameraO.bottom = this.bottom / this.zoom; + + this.cameraO.updateProjectionMatrix(); + + this.near = this.cameraO.near; + this.far = this.cameraO.far; + this.projectionMatrix = this.cameraO.projectionMatrix; + + this.inPerspectiveMode = false; + this.inOrthographicMode = true; + +}; + + +THREE.CombinedCamera.prototype.setSize = function( width, height ) { + + this.cameraP.aspect = width / height; + this.left = -width / 2; + this.right = width / 2 + this.top = height / 2; + this.bottom = -height / 2; + +}; + + +THREE.CombinedCamera.prototype.setFov = function( fov ) { + + this.fov = fov; + + if ( this.inPerspectiveMode ) { + + this.toPerspective(); + + } else { + + this.toOrthographic(); + + } + +}; + +// For mantaining similar API with PerspectiveCamera + +THREE.CombinedCamera.prototype.updateProjectionMatrix = function() { + + if ( this.inPerspectiveMode ) { + + this.toPerspective(); + + } else { + + this.toPerspective(); + this.toOrthographic(); + + } + +}; + +/* +* Uses Focal Length (in mm) to estimate and set FOV +* 35mm (fullframe) camera is used if frame size is not specified; +* Formula based on http://www.bobatkins.com/photography/technical/field_of_view.html +*/ +THREE.CombinedCamera.prototype.setLens = function ( focalLength, frameHeight ) { + + if ( frameHeight === undefined ) frameHeight = 24; + + var fov = 2 * THREE.Math.radToDeg( Math.atan( frameHeight / ( focalLength * 2 ) ) ); + + this.setFov( fov ); + + return fov; +}; + + +THREE.CombinedCamera.prototype.setZoom = function( zoom ) { + + this.zoom = zoom; + + if ( this.inPerspectiveMode ) { + + this.toPerspective(); + + } else { + + this.toOrthographic(); + + } + +}; + +THREE.CombinedCamera.prototype.toFrontView = function() { + + this.rotation.x = 0; + this.rotation.y = 0; + this.rotation.z = 0; + + // should we be modifing the matrix instead? + + this.rotationAutoUpdate = false; + +}; + +THREE.CombinedCamera.prototype.toBackView = function() { + + this.rotation.x = 0; + this.rotation.y = Math.PI; + this.rotation.z = 0; + this.rotationAutoUpdate = false; + +}; + +THREE.CombinedCamera.prototype.toLeftView = function() { + + this.rotation.x = 0; + this.rotation.y = - Math.PI / 2; + this.rotation.z = 0; + this.rotationAutoUpdate = false; + +}; + +THREE.CombinedCamera.prototype.toRightView = function() { + + this.rotation.x = 0; + this.rotation.y = Math.PI / 2; + this.rotation.z = 0; + this.rotationAutoUpdate = false; + +}; + +THREE.CombinedCamera.prototype.toTopView = function() { + + this.rotation.x = - Math.PI / 2; + this.rotation.y = 0; + this.rotation.z = 0; + this.rotationAutoUpdate = false; + +}; + +THREE.CombinedCamera.prototype.toBottomView = function() { + + this.rotation.x = Math.PI / 2; + this.rotation.y = 0; + this.rotation.z = 0; + this.rotationAutoUpdate = false; + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + * + * - 3d asterisk shape (for line pieces THREE.Line) + */ + +THREE.AsteriskGeometry = function ( innerRadius, outerRadius ) { + + THREE.Geometry.call( this ); + + var sd = innerRadius; + var ed = outerRadius; + + var sd2 = 0.707 * sd; + var ed2 = 0.707 * ed; + + var rays = [ [ sd, 0, 0 ], [ ed, 0, 0 ], [ -sd, 0, 0 ], [ -ed, 0, 0 ], + [ 0, sd, 0 ], [ 0, ed, 0 ], [ 0, -sd, 0 ], [ 0, -ed, 0 ], + [ 0, 0, sd ], [ 0, 0, ed ], [ 0, 0, -sd ], [ 0, 0, -ed ], + [ sd2, sd2, 0 ], [ ed2, ed2, 0 ], [ -sd2, -sd2, 0 ], [ -ed2, -ed2, 0 ], + [ sd2, -sd2, 0 ], [ ed2, -ed2, 0 ], [ -sd2, sd2, 0 ], [ -ed2, ed2, 0 ], + [ sd2, 0, sd2 ], [ ed2, 0, ed2 ], [ -sd2, 0, -sd2 ], [ -ed2, 0, -ed2 ], + [ sd2, 0, -sd2 ], [ ed2, 0, -ed2 ], [ -sd2, 0, sd2 ], [ -ed2, 0, ed2 ], + [ 0, sd2, sd2 ], [ 0, ed2, ed2 ], [ 0, -sd2, -sd2 ], [ 0, -ed2, -ed2 ], + [ 0, sd2, -sd2 ], [ 0, ed2, -ed2 ], [ 0, -sd2, sd2 ], [ 0, -ed2, ed2 ] + ]; + + for ( var i = 0, il = rays.length; i < il; i ++ ) { + + var x = rays[ i ][ 0 ]; + var y = rays[ i ][ 1 ]; + var z = rays[ i ][ 2 ]; + + this.vertices.push( new THREE.Vector3( x, y, z ) ); + + } + +}; + +THREE.AsteriskGeometry.prototype = Object.create( THREE.Geometry.prototype );/** + * @author hughes + */ + +THREE.CircleGeometry = function ( radius, segments, thetaStart, thetaLength ) { + + THREE.Geometry.call( this ); + + radius = radius || 50; + + thetaStart = thetaStart !== undefined ? thetaStart : 0; + thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; + segments = segments !== undefined ? Math.max( 3, segments ) : 8; + + var i, uvs = [], + center = new THREE.Vector3(), centerUV = new THREE.Vector2( 0.5, 0.5 ); + + this.vertices.push(center); + uvs.push( centerUV ); + + for ( i = 0; i <= segments; i ++ ) { + + var vertex = new THREE.Vector3(); + + vertex.x = radius * Math.cos( thetaStart + i / segments * thetaLength ); + vertex.y = radius * Math.sin( thetaStart + i / segments * thetaLength ); + + this.vertices.push( vertex ); + uvs.push( new THREE.Vector2( ( vertex.x / radius + 1 ) / 2, - ( vertex.y / radius + 1 ) / 2 + 1 ) ); + + } + + var n = new THREE.Vector3( 0, 0, -1 ); + + for ( i = 1; i <= segments; i ++ ) { + + var v1 = i; + var v2 = i + 1 ; + var v3 = 0; + + this.faces.push( new THREE.Face3( v1, v2, v3, [ n, n, n ] ) ); + this.faceVertexUvs[ 0 ].push( [ uvs[ i ], uvs[ i + 1 ], centerUV ] ); + + } + + this.computeCentroids(); + this.computeFaceNormals(); + + this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); + +}; + +THREE.CircleGeometry.prototype = Object.create( THREE.Geometry.prototype ); +/** + * @author mrdoob / http://mrdoob.com/ + * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Cube.as + */ + +THREE.CubeGeometry = function ( width, height, depth, widthSegments, heightSegments, depthSegments ) { + + THREE.Geometry.call( this ); + + var scope = this; + + this.width = width; + this.height = height; + this.depth = depth; + + this.widthSegments = widthSegments || 1; + this.heightSegments = heightSegments || 1; + this.depthSegments = depthSegments || 1; + + var width_half = this.width / 2; + var height_half = this.height / 2; + var depth_half = this.depth / 2; + + buildPlane( 'z', 'y', - 1, - 1, this.depth, this.height, width_half, 0 ); // px + buildPlane( 'z', 'y', 1, - 1, this.depth, this.height, - width_half, 1 ); // nx + buildPlane( 'x', 'z', 1, 1, this.width, this.depth, height_half, 2 ); // py + buildPlane( 'x', 'z', 1, - 1, this.width, this.depth, - height_half, 3 ); // ny + buildPlane( 'x', 'y', 1, - 1, this.width, this.height, depth_half, 4 ); // pz + buildPlane( 'x', 'y', - 1, - 1, this.width, this.height, - depth_half, 5 ); // nz + + function buildPlane( u, v, udir, vdir, width, height, depth, materialIndex ) { + + var w, ix, iy, + gridX = scope.widthSegments, + gridY = scope.heightSegments, + width_half = width / 2, + height_half = height / 2, + offset = scope.vertices.length; + + if ( ( u === 'x' && v === 'y' ) || ( u === 'y' && v === 'x' ) ) { + + w = 'z'; + + } else if ( ( u === 'x' && v === 'z' ) || ( u === 'z' && v === 'x' ) ) { + + w = 'y'; + gridY = scope.depthSegments; + + } else if ( ( u === 'z' && v === 'y' ) || ( u === 'y' && v === 'z' ) ) { + + w = 'x'; + gridX = scope.depthSegments; + + } + + var gridX1 = gridX + 1, + gridY1 = gridY + 1, + segment_width = width / gridX, + segment_height = height / gridY, + normal = new THREE.Vector3(); + + normal[ w ] = depth > 0 ? 1 : - 1; + + for ( iy = 0; iy < gridY1; iy ++ ) { + + for ( ix = 0; ix < gridX1; ix ++ ) { + + var vector = new THREE.Vector3(); + vector[ u ] = ( ix * segment_width - width_half ) * udir; + vector[ v ] = ( iy * segment_height - height_half ) * vdir; + vector[ w ] = depth; + + scope.vertices.push( vector ); + + } + + } + + for ( iy = 0; iy < gridY; iy++ ) { + + for ( ix = 0; ix < gridX; ix++ ) { + + var a = ix + gridX1 * iy; + var b = ix + gridX1 * ( iy + 1 ); + var c = ( ix + 1 ) + gridX1 * ( iy + 1 ); + var d = ( ix + 1 ) + gridX1 * iy; + + var face = new THREE.Face4( a + offset, b + offset, c + offset, d + offset ); + face.normal.copy( normal ); + face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone(), normal.clone() ); + face.materialIndex = materialIndex; + + scope.faces.push( face ); + scope.faceVertexUvs[ 0 ].push( [ + new THREE.Vector2( ix / gridX, 1 - iy / gridY ), + new THREE.Vector2( ix / gridX, 1 - ( iy + 1 ) / gridY ), + new THREE.Vector2( ( ix + 1 ) / gridX, 1- ( iy + 1 ) / gridY ), + new THREE.Vector2( ( ix + 1 ) / gridX, 1 - iy / gridY ) + ] ); + + } + + } + + } + + this.computeCentroids(); + this.mergeVertices(); + +}; + +THREE.CubeGeometry.prototype = Object.create( THREE.Geometry.prototype ); +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.CylinderGeometry = function ( radiusTop, radiusBottom, height, radiusSegments, heightSegments, openEnded ) { + + THREE.Geometry.call( this ); + + radiusTop = radiusTop !== undefined ? radiusTop : 20; + radiusBottom = radiusBottom !== undefined ? radiusBottom : 20; + height = height !== undefined ? height : 100; + + var heightHalf = height / 2; + var segmentsX = radiusSegments || 8; + var segmentsY = heightSegments || 1; + + var x, y, vertices = [], uvs = []; + + for ( y = 0; y <= segmentsY; y ++ ) { + + var verticesRow = []; + var uvsRow = []; + + var v = y / segmentsY; + var radius = v * ( radiusBottom - radiusTop ) + radiusTop; + + for ( x = 0; x <= segmentsX; x ++ ) { + + var u = x / segmentsX; + + var vertex = new THREE.Vector3(); + vertex.x = radius * Math.sin( u * Math.PI * 2 ); + vertex.y = - v * height + heightHalf; + vertex.z = radius * Math.cos( u * Math.PI * 2 ); + + this.vertices.push( vertex ); + + verticesRow.push( this.vertices.length - 1 ); + uvsRow.push( new THREE.Vector2( u, 1 - v ) ); + + } + + vertices.push( verticesRow ); + uvs.push( uvsRow ); + + } + + var tanTheta = ( radiusBottom - radiusTop ) / height; + var na, nb; + + for ( x = 0; x < segmentsX; x ++ ) { + + if ( radiusTop !== 0 ) { + + na = this.vertices[ vertices[ 0 ][ x ] ].clone(); + nb = this.vertices[ vertices[ 0 ][ x + 1 ] ].clone(); + + } else { + + na = this.vertices[ vertices[ 1 ][ x ] ].clone(); + nb = this.vertices[ vertices[ 1 ][ x + 1 ] ].clone(); + + } + + na.setY( Math.sqrt( na.x * na.x + na.z * na.z ) * tanTheta ).normalize(); + nb.setY( Math.sqrt( nb.x * nb.x + nb.z * nb.z ) * tanTheta ).normalize(); + + for ( y = 0; y < segmentsY; y ++ ) { + + var v1 = vertices[ y ][ x ]; + var v2 = vertices[ y + 1 ][ x ]; + var v3 = vertices[ y + 1 ][ x + 1 ]; + var v4 = vertices[ y ][ x + 1 ]; + + var n1 = na.clone(); + var n2 = na.clone(); + var n3 = nb.clone(); + var n4 = nb.clone(); + + var uv1 = uvs[ y ][ x ].clone(); + var uv2 = uvs[ y + 1 ][ x ].clone(); + var uv3 = uvs[ y + 1 ][ x + 1 ].clone(); + var uv4 = uvs[ y ][ x + 1 ].clone(); + + this.faces.push( new THREE.Face4( v1, v2, v3, v4, [ n1, n2, n3, n4 ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3, uv4 ] ); + + } + + } + + // top cap + + if ( !openEnded && radiusTop > 0 ) { + + this.vertices.push( new THREE.Vector3( 0, heightHalf, 0 ) ); + + for ( x = 0; x < segmentsX; x ++ ) { + + var v1 = vertices[ 0 ][ x ]; + var v2 = vertices[ 0 ][ x + 1 ]; + var v3 = this.vertices.length - 1; + + var n1 = new THREE.Vector3( 0, 1, 0 ); + var n2 = new THREE.Vector3( 0, 1, 0 ); + var n3 = new THREE.Vector3( 0, 1, 0 ); + + var uv1 = uvs[ 0 ][ x ].clone(); + var uv2 = uvs[ 0 ][ x + 1 ].clone(); + var uv3 = new THREE.Vector2( uv2.u, 0 ); + + this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] ); + + } + + } + + // bottom cap + + if ( !openEnded && radiusBottom > 0 ) { + + this.vertices.push( new THREE.Vector3( 0, - heightHalf, 0 ) ); + + for ( x = 0; x < segmentsX; x ++ ) { + + var v1 = vertices[ y ][ x + 1 ]; + var v2 = vertices[ y ][ x ]; + var v3 = this.vertices.length - 1; + + var n1 = new THREE.Vector3( 0, - 1, 0 ); + var n2 = new THREE.Vector3( 0, - 1, 0 ); + var n3 = new THREE.Vector3( 0, - 1, 0 ); + + var uv1 = uvs[ y ][ x + 1 ].clone(); + var uv2 = uvs[ y ][ x ].clone(); + var uv3 = new THREE.Vector2( uv2.u, 1 ); + + this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] ); + + } + + } + + this.computeCentroids(); + this.computeFaceNormals(); + +} + +THREE.CylinderGeometry.prototype = Object.create( THREE.Geometry.prototype ); +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * + * Creates extruded geometry from a path shape. + * + * parameters = { + * + * size: <float>, // size of the text + * height: <float>, // thickness to extrude text + * curveSegments: <int>, // number of points on the curves + * steps: <int>, // number of points for z-side extrusions / used for subdividing segements of extrude spline too + * amount: <int>, // Amount + * + * bevelEnabled: <bool>, // turn on bevel + * bevelThickness: <float>, // how deep into text bevel goes + * bevelSize: <float>, // how far from text outline is bevel + * bevelSegments: <int>, // number of bevel layers + * + * extrudePath: <THREE.CurvePath> // 3d spline path to extrude shape along. (creates Frames if .frames aren't defined) + * frames: <THREE.TubeGeometry.FrenetFrames> // containing arrays of tangents, normals, binormals + * + * material: <int> // material index for front and back faces + * extrudeMaterial: <int> // material index for extrusion and beveled faces + * uvGenerator: <Object> // object that provides UV generator functions + * + * } + **/ + +THREE.ExtrudeGeometry = function ( shapes, options ) { + + if ( typeof( shapes ) === "undefined" ) { + shapes = []; + return; + } + + THREE.Geometry.call( this ); + + shapes = shapes instanceof Array ? shapes : [ shapes ]; + + this.shapebb = shapes[ shapes.length - 1 ].getBoundingBox(); + + this.addShapeList( shapes, options ); + + this.computeCentroids(); + this.computeFaceNormals(); + + // can't really use automatic vertex normals + // as then front and back sides get smoothed too + // should do separate smoothing just for sides + + //this.computeVertexNormals(); + + //console.log( "took", ( Date.now() - startTime ) ); + +}; + +THREE.ExtrudeGeometry.prototype = Object.create( THREE.Geometry.prototype ); + +THREE.ExtrudeGeometry.prototype.addShapeList = function ( shapes, options ) { + var sl = shapes.length; + + for ( var s = 0; s < sl; s ++ ) { + var shape = shapes[ s ]; + this.addShape( shape, options ); + } +}; + +THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { + + var amount = options.amount !== undefined ? options.amount : 100; + + var bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 6; // 10 + var bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 2; // 8 + var bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3; + + var bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true; // false + + var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; + + var steps = options.steps !== undefined ? options.steps : 1; + + var extrudePath = options.extrudePath; + var extrudePts, extrudeByPath = false; + + var material = options.material; + var extrudeMaterial = options.extrudeMaterial; + + // Use default WorldUVGenerator if no UV generators are specified. + var uvgen = options.UVGenerator !== undefined ? options.UVGenerator : THREE.ExtrudeGeometry.WorldUVGenerator; + + var shapebb = this.shapebb; + //shapebb = shape.getBoundingBox(); + + + + var splineTube, binormal, normal, position2; + if ( extrudePath ) { + + extrudePts = extrudePath.getSpacedPoints( steps ); + + extrudeByPath = true; + bevelEnabled = false; // bevels not supported for path extrusion + + // SETUP TNB variables + + // Reuse TNB from TubeGeomtry for now. + // TODO1 - have a .isClosed in spline? + + splineTube = options.frames !== undefined ? options.frames : new THREE.TubeGeometry.FrenetFrames(extrudePath, steps, false); + + // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length); + + binormal = new THREE.Vector3(); + normal = new THREE.Vector3(); + position2 = new THREE.Vector3(); + + } + + // Safeguards if bevels are not enabled + + if ( ! bevelEnabled ) { + + bevelSegments = 0; + bevelThickness = 0; + bevelSize = 0; + + } + + // Variables initalization + + var ahole, h, hl; // looping of holes + var scope = this; + var bevelPoints = []; + + var shapesOffset = this.vertices.length; + + var shapePoints = shape.extractPoints( curveSegments ); + + var vertices = shapePoints.shape; + var holes = shapePoints.holes; + + var reverse = !THREE.Shape.Utils.isClockWise( vertices ) ; + + if ( reverse ) { + + vertices = vertices.reverse(); + + // Maybe we should also check if holes are in the opposite direction, just to be safe ... + + for ( h = 0, hl = holes.length; h < hl; h ++ ) { + + ahole = holes[ h ]; + + if ( THREE.Shape.Utils.isClockWise( ahole ) ) { + + holes[ h ] = ahole.reverse(); + + } + + } + + reverse = false; // If vertices are in order now, we shouldn't need to worry about them again (hopefully)! + + } + + + var faces = THREE.Shape.Utils.triangulateShape ( vertices, holes ); + + /* Vertices */ + + var contour = vertices; // vertices has all points but contour has only points of circumference + + for ( h = 0, hl = holes.length; h < hl; h ++ ) { + + ahole = holes[ h ]; + + vertices = vertices.concat( ahole ); + + } + + + function scalePt2 ( pt, vec, size ) { + + if ( !vec ) console.log( "die" ); + + return vec.clone().multiplyScalar( size ).add( pt ); + + } + + var b, bs, t, z, + vert, vlen = vertices.length, + face, flen = faces.length, + cont, clen = contour.length; + + + // Find directions for point movement + + var RAD_TO_DEGREES = 180 / Math.PI; + + + function getBevelVec( pt_i, pt_j, pt_k ) { + + // Algorithm 2 + + return getBevelVec2( pt_i, pt_j, pt_k ); + + } + + function getBevelVec1( pt_i, pt_j, pt_k ) { + + var anglea = Math.atan2( pt_j.y - pt_i.y, pt_j.x - pt_i.x ); + var angleb = Math.atan2( pt_k.y - pt_i.y, pt_k.x - pt_i.x ); + + if ( anglea > angleb ) { + + angleb += Math.PI * 2; + + } + + var anglec = ( anglea + angleb ) / 2; + + + //console.log('angle1', anglea * RAD_TO_DEGREES,'angle2', angleb * RAD_TO_DEGREES, 'anglec', anglec *RAD_TO_DEGREES); + + var x = - Math.cos( anglec ); + var y = - Math.sin( anglec ); + + var vec = new THREE.Vector2( x, y ); //.normalize(); + + return vec; + + } + + function getBevelVec2( pt_i, pt_j, pt_k ) { + + var a = THREE.ExtrudeGeometry.__v1, + b = THREE.ExtrudeGeometry.__v2, + v_hat = THREE.ExtrudeGeometry.__v3, + w_hat = THREE.ExtrudeGeometry.__v4, + p = THREE.ExtrudeGeometry.__v5, + q = THREE.ExtrudeGeometry.__v6, + v, w, + v_dot_w_hat, q_sub_p_dot_w_hat, + s, intersection; + + // good reading for line-line intersection + // http://sputsoft.com/blog/2010/03/line-line-intersection.html + + // define a as vector j->i + // define b as vectot k->i + + a.set( pt_i.x - pt_j.x, pt_i.y - pt_j.y ); + b.set( pt_i.x - pt_k.x, pt_i.y - pt_k.y ); + + // get unit vectors + + v = a.normalize(); + w = b.normalize(); + + // normals from pt i + + v_hat.set( -v.y, v.x ); + w_hat.set( w.y, -w.x ); + + // pts from i + + p.copy( pt_i ).add( v_hat ); + q.copy( pt_i ).add( w_hat ); + + if ( p.equals( q ) ) { + + //console.log("Warning: lines are straight"); + return w_hat.clone(); + + } + + // Points from j, k. helps prevents points cross overover most of the time + + p.copy( pt_j ).add( v_hat ); + q.copy( pt_k ).add( w_hat ); + + v_dot_w_hat = v.dot( w_hat ); + q_sub_p_dot_w_hat = q.sub( p ).dot( w_hat ); + + // We should not reach these conditions + + if ( v_dot_w_hat === 0 ) { + + console.log( "Either infinite or no solutions!" ); + + if ( q_sub_p_dot_w_hat === 0 ) { + + console.log( "Its finite solutions." ); + + } else { + + console.log( "Too bad, no solutions." ); + + } + + } + + s = q_sub_p_dot_w_hat / v_dot_w_hat; + + if ( s < 0 ) { + + // in case of emergecy, revert to algorithm 1. + + return getBevelVec1( pt_i, pt_j, pt_k ); + + } + + intersection = v.multiplyScalar( s ).add( p ); + + return intersection.sub( pt_i ).clone(); // Don't normalize!, otherwise sharp corners become ugly + + } + + var contourMovements = []; + + for ( var i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { + + if ( j === il ) j = 0; + if ( k === il ) k = 0; + + // (j)---(i)---(k) + // console.log('i,j,k', i, j , k) + + var pt_i = contour[ i ]; + var pt_j = contour[ j ]; + var pt_k = contour[ k ]; + + contourMovements[ i ]= getBevelVec( contour[ i ], contour[ j ], contour[ k ] ); + + } + + var holesMovements = [], oneHoleMovements, verticesMovements = contourMovements.concat(); + + for ( h = 0, hl = holes.length; h < hl; h ++ ) { + + ahole = holes[ h ]; + + oneHoleMovements = []; + + for ( i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { + + if ( j === il ) j = 0; + if ( k === il ) k = 0; + + // (j)---(i)---(k) + oneHoleMovements[ i ]= getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] ); + + } + + holesMovements.push( oneHoleMovements ); + verticesMovements = verticesMovements.concat( oneHoleMovements ); + + } + + + // Loop bevelSegments, 1 for the front, 1 for the back + + for ( b = 0; b < bevelSegments; b ++ ) { + //for ( b = bevelSegments; b > 0; b -- ) { + + t = b / bevelSegments; + z = bevelThickness * ( 1 - t ); + + //z = bevelThickness * t; + bs = bevelSize * ( Math.sin ( t * Math.PI/2 ) ) ; // curved + //bs = bevelSize * t ; // linear + + // contract shape + + for ( i = 0, il = contour.length; i < il; i ++ ) { + + vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); + //vert = scalePt( contour[ i ], contourCentroid, bs, false ); + v( vert.x, vert.y, - z ); + + } + + // expand holes + + for ( h = 0, hl = holes.length; h < hl; h++ ) { + + ahole = holes[ h ]; + oneHoleMovements = holesMovements[ h ]; + + for ( i = 0, il = ahole.length; i < il; i++ ) { + + vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); + //vert = scalePt( ahole[ i ], holesCentroids[ h ], bs, true ); + + v( vert.x, vert.y, -z ); + + } + + } + + } + + bs = bevelSize; + + // Back facing vertices + + for ( i = 0; i < vlen; i ++ ) { + + vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; + + if ( !extrudeByPath ) { + + v( vert.x, vert.y, 0 ); + + } else { + + // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x ); + + normal.copy( splineTube.normals[0] ).multiplyScalar(vert.x); + binormal.copy( splineTube.binormals[0] ).multiplyScalar(vert.y); + + position2.copy( extrudePts[0] ).add(normal).add(binormal); + + v( position2.x, position2.y, position2.z ); + + } + + } + + // Add stepped vertices... + // Including front facing vertices + + var s; + + for ( s = 1; s <= steps; s ++ ) { + + for ( i = 0; i < vlen; i ++ ) { + + vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; + + if ( !extrudeByPath ) { + + v( vert.x, vert.y, amount / steps * s ); + + } else { + + // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x ); + + normal.copy( splineTube.normals[s] ).multiplyScalar( vert.x ); + binormal.copy( splineTube.binormals[s] ).multiplyScalar( vert.y ); + + position2.copy( extrudePts[s] ).add( normal ).add( binormal ); + + v( position2.x, position2.y, position2.z ); + + } + + } + + } + + + // Add bevel segments planes + + //for ( b = 1; b <= bevelSegments; b ++ ) { + for ( b = bevelSegments - 1; b >= 0; b -- ) { + + t = b / bevelSegments; + z = bevelThickness * ( 1 - t ); + //bs = bevelSize * ( 1-Math.sin ( ( 1 - t ) * Math.PI/2 ) ); + bs = bevelSize * Math.sin ( t * Math.PI/2 ) ; + + // contract shape + + for ( i = 0, il = contour.length; i < il; i ++ ) { + + vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); + v( vert.x, vert.y, amount + z ); + + } + + // expand holes + + for ( h = 0, hl = holes.length; h < hl; h ++ ) { + + ahole = holes[ h ]; + oneHoleMovements = holesMovements[ h ]; + + for ( i = 0, il = ahole.length; i < il; i ++ ) { + + vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); + + if ( !extrudeByPath ) { + + v( vert.x, vert.y, amount + z ); + + } else { + + v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z ); + + } + + } + + } + + } + + /* Faces */ + + // Top and bottom faces + + buildLidFaces(); + + // Sides faces + + buildSideFaces(); + + + ///// Internal functions + + function buildLidFaces() { + + if ( bevelEnabled ) { + + var layer = 0 ; // steps + 1 + var offset = vlen * layer; + + // Bottom faces + + for ( i = 0; i < flen; i ++ ) { + + face = faces[ i ]; + f3( face[ 2 ]+ offset, face[ 1 ]+ offset, face[ 0 ] + offset, true ); + + } + + layer = steps + bevelSegments * 2; + offset = vlen * layer; + + // Top faces + + for ( i = 0; i < flen; i ++ ) { + + face = faces[ i ]; + f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset, false ); + + } + + } else { + + // Bottom faces + + for ( i = 0; i < flen; i++ ) { + + face = faces[ i ]; + f3( face[ 2 ], face[ 1 ], face[ 0 ], true ); + + } + + // Top faces + + for ( i = 0; i < flen; i ++ ) { + + face = faces[ i ]; + f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps, false ); + + } + } + + } + + // Create faces for the z-sides of the shape + + function buildSideFaces() { + + var layeroffset = 0; + sidewalls( contour, layeroffset ); + layeroffset += contour.length; + + for ( h = 0, hl = holes.length; h < hl; h ++ ) { + + ahole = holes[ h ]; + sidewalls( ahole, layeroffset ); + + //, true + layeroffset += ahole.length; + + } + + } + + function sidewalls( contour, layeroffset ) { + + var j, k; + i = contour.length; + + while ( --i >= 0 ) { + + j = i; + k = i - 1; + if ( k < 0 ) k = contour.length - 1; + + //console.log('b', i,j, i-1, k,vertices.length); + + var s = 0, sl = steps + bevelSegments * 2; + + for ( s = 0; s < sl; s ++ ) { + + var slen1 = vlen * s; + var slen2 = vlen * ( s + 1 ); + + var a = layeroffset + j + slen1, + b = layeroffset + k + slen1, + c = layeroffset + k + slen2, + d = layeroffset + j + slen2; + + f4( a, b, c, d, contour, s, sl, j, k ); + + } + } + + } + + + function v( x, y, z ) { + + scope.vertices.push( new THREE.Vector3( x, y, z ) ); + + } + + function f3( a, b, c, isBottom ) { + + a += shapesOffset; + b += shapesOffset; + c += shapesOffset; + + // normal, color, material + scope.faces.push( new THREE.Face3( a, b, c, null, null, material ) ); + + var uvs = isBottom ? uvgen.generateBottomUV( scope, shape, options, a, b, c ) : uvgen.generateTopUV( scope, shape, options, a, b, c ); + + scope.faceVertexUvs[ 0 ].push( uvs ); + + } + + function f4( a, b, c, d, wallContour, stepIndex, stepsLength, contourIndex1, contourIndex2 ) { + + a += shapesOffset; + b += shapesOffset; + c += shapesOffset; + d += shapesOffset; + + scope.faces.push( new THREE.Face4( a, b, c, d, null, null, extrudeMaterial ) ); + + var uvs = uvgen.generateSideWallUV( scope, shape, wallContour, options, a, b, c, d, + stepIndex, stepsLength, contourIndex1, contourIndex2 ); + scope.faceVertexUvs[ 0 ].push( uvs ); + + } + +}; + +THREE.ExtrudeGeometry.WorldUVGenerator = { + + generateTopUV: function( geometry, extrudedShape, extrudeOptions, indexA, indexB, indexC ) { + var ax = geometry.vertices[ indexA ].x, + ay = geometry.vertices[ indexA ].y, + + bx = geometry.vertices[ indexB ].x, + by = geometry.vertices[ indexB ].y, + + cx = geometry.vertices[ indexC ].x, + cy = geometry.vertices[ indexC ].y; + + return [ + new THREE.Vector2( ax, ay ), + new THREE.Vector2( bx, by ), + new THREE.Vector2( cx, cy ) + ]; + + }, + + generateBottomUV: function( geometry, extrudedShape, extrudeOptions, indexA, indexB, indexC ) { + + return this.generateTopUV( geometry, extrudedShape, extrudeOptions, indexA, indexB, indexC ); + + }, + + generateSideWallUV: function( geometry, extrudedShape, wallContour, extrudeOptions, + indexA, indexB, indexC, indexD, stepIndex, stepsLength, + contourIndex1, contourIndex2 ) { + + var ax = geometry.vertices[ indexA ].x, + ay = geometry.vertices[ indexA ].y, + az = geometry.vertices[ indexA ].z, + + bx = geometry.vertices[ indexB ].x, + by = geometry.vertices[ indexB ].y, + bz = geometry.vertices[ indexB ].z, + + cx = geometry.vertices[ indexC ].x, + cy = geometry.vertices[ indexC ].y, + cz = geometry.vertices[ indexC ].z, + + dx = geometry.vertices[ indexD ].x, + dy = geometry.vertices[ indexD ].y, + dz = geometry.vertices[ indexD ].z; + + if ( Math.abs( ay - by ) < 0.01 ) { + return [ + new THREE.Vector2( ax, 1 - az ), + new THREE.Vector2( bx, 1 - bz ), + new THREE.Vector2( cx, 1 - cz ), + new THREE.Vector2( dx, 1 - dz ) + ]; + } else { + return [ + new THREE.Vector2( ay, 1 - az ), + new THREE.Vector2( by, 1 - bz ), + new THREE.Vector2( cy, 1 - cz ), + new THREE.Vector2( dy, 1 - dz ) + ]; + } + } +}; + +THREE.ExtrudeGeometry.__v1 = new THREE.Vector2(); +THREE.ExtrudeGeometry.__v2 = new THREE.Vector2(); +THREE.ExtrudeGeometry.__v3 = new THREE.Vector2(); +THREE.ExtrudeGeometry.__v4 = new THREE.Vector2(); +THREE.ExtrudeGeometry.__v5 = new THREE.Vector2(); +THREE.ExtrudeGeometry.__v6 = new THREE.Vector2(); +/** + * @author jonobr1 / http://jonobr1.com + * + * Creates a one-sided polygonal geometry from a path shape. Similar to + * ExtrudeGeometry. + * + * parameters = { + * + * curveSegments: <int>, // number of points on the curves. NOT USED AT THE MOMENT. + * + * material: <int> // material index for front and back faces + * uvGenerator: <Object> // object that provides UV generator functions + * + * } + **/ + +THREE.ShapeGeometry = function ( shapes, options ) { + + THREE.Geometry.call( this ); + + if ( shapes instanceof Array === false ) shapes = [ shapes ]; + + this.shapebb = shapes[ shapes.length - 1 ].getBoundingBox(); + + this.addShapeList( shapes, options ); + + this.computeCentroids(); + this.computeFaceNormals(); + +}; + +THREE.ShapeGeometry.prototype = Object.create( THREE.Geometry.prototype ); + +/** + * Add an array of shapes to THREE.ShapeGeometry. + */ +THREE.ShapeGeometry.prototype.addShapeList = function ( shapes, options ) { + + for ( var i = 0, l = shapes.length; i < l; i++ ) { + + this.addShape( shapes[ i ], options ); + + } + + return this; + +}; + +/** + * Adds a shape to THREE.ShapeGeometry, based on THREE.ExtrudeGeometry. + */ +THREE.ShapeGeometry.prototype.addShape = function ( shape, options ) { + + if ( options === undefined ) options = {}; + var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; + + var material = options.material; + var uvgen = options.UVGenerator === undefined ? THREE.ExtrudeGeometry.WorldUVGenerator : options.UVGenerator; + + var shapebb = this.shapebb; + + // + + var i, l, hole, s; + + var shapesOffset = this.vertices.length; + var shapePoints = shape.extractPoints( curveSegments ); + + var vertices = shapePoints.shape; + var holes = shapePoints.holes; + + var reverse = !THREE.Shape.Utils.isClockWise( vertices ); + + if ( reverse ) { + + vertices = vertices.reverse(); + + // Maybe we should also check if holes are in the opposite direction, just to be safe... + + for ( i = 0, l = holes.length; i < l; i++ ) { + + hole = holes[ i ]; + + if ( THREE.Shape.Utils.isClockWise( hole ) ) { + + holes[ i ] = hole.reverse(); + + } + + } + + reverse = false; + + } + + var faces = THREE.Shape.Utils.triangulateShape( vertices, holes ); + + // Vertices + + var contour = vertices; + + for ( i = 0, l = holes.length; i < l; i++ ) { + + hole = holes[ i ]; + vertices = vertices.concat( hole ); + + } + + // + + var vert, vlen = vertices.length; + var face, flen = faces.length; + var cont, clen = contour.length; + + for ( i = 0; i < vlen; i++ ) { + + vert = vertices[ i ]; + + this.vertices.push( new THREE.Vector3( vert.x, vert.y, 0 ) ); + + } + + for ( i = 0; i < flen; i++ ) { + + face = faces[ i ]; + + var a = face[ 0 ] + shapesOffset; + var b = face[ 1 ] + shapesOffset; + var c = face[ 2 ] + shapesOffset; + + this.faces.push( new THREE.Face3( a, b, c, null, null, material ) ); + this.faceVertexUvs[ 0 ].push( uvgen.generateBottomUV( this, shape, options, a, b, c ) ); + + } + +}; +/** + * @author astrodud / http://astrodud.isgreat.org/ + * @author zz85 / https://github.com/zz85 + * @author bhouston / http://exocortex.com + */ + +// points - to create a closed torus, one must use a set of points +// like so: [ a, b, c, d, a ], see first is the same as last. +// segments - the number of circumference segments to create +// phiStart - the starting radian +// phiLength - the radian (0 to 2*PI) range of the lathed section +// 2*pi is a closed lathe, less than 2PI is a portion. +THREE.LatheGeometry = function ( points, segments, phiStart, phiLength ) { + + THREE.Geometry.call( this ); + + segments = segments || 12; + phiStart = phiStart || 0; + phiLength = phiLength || 2 * Math.PI; + + var inversePointLength = 1.0 / ( points.length - 1 ); + var inverseSegments = 1.0 / segments; + + for ( var i = 0, il = segments; i <= il; i ++ ) { + + var phi = phiStart + i * inverseSegments * phiLength; + + var c = Math.cos( phi ), + s = Math.sin( phi ); + + for ( var j = 0, jl = points.length; j < jl; j ++ ) { + + var pt = points[ j ]; + + var vertex = new THREE.Vector3(); + + vertex.x = c * pt.x - s * pt.y; + vertex.y = s * pt.x + c * pt.y; + vertex.z = pt.z; + + this.vertices.push( vertex ); + + } + + } + + var np = points.length; + + for ( var i = 0, il = segments; i < il; i ++ ) { + + for ( var j = 0, jl = points.length - 1; j < jl; j ++ ) { + + var base = j + np * i; + var a = base; + var b = base + np; + var c = base + 1 + np; + var d = base + 1; + + this.faces.push( new THREE.Face4( a, b, c, d ) ); + + var u0 = i * inverseSegments; + var v0 = j * inversePointLength; + var u1 = u0 + inverseSegments; + var v1 = v0 + inversePointLength; + + this.faceVertexUvs[ 0 ].push( [ + + new THREE.Vector2( u0, v0 ), + new THREE.Vector2( u1, v0 ), + new THREE.Vector2( u1, v1 ), + new THREE.Vector2( u0, v1 ) + + ] ); + + } + + } + + this.mergeVertices(); + this.computeCentroids(); + this.computeFaceNormals(); + this.computeVertexNormals(); + +}; + +THREE.LatheGeometry.prototype = Object.create( THREE.Geometry.prototype ); +/** + * @author mrdoob / http://mrdoob.com/ + * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as + */ + +THREE.PlaneGeometry = function ( width, height, widthSegments, heightSegments ) { + + THREE.Geometry.call( this ); + + this.width = width; + this.height = height; + + this.widthSegments = widthSegments || 1; + this.heightSegments = heightSegments || 1; + + var ix, iz; + var width_half = width / 2; + var height_half = height / 2; + + var gridX = this.widthSegments; + var gridZ = this.heightSegments; + + var gridX1 = gridX + 1; + var gridZ1 = gridZ + 1; + + var segment_width = this.width / gridX; + var segment_height = this.height / gridZ; + + var normal = new THREE.Vector3( 0, 0, 1 ); + + for ( iz = 0; iz < gridZ1; iz ++ ) { + + for ( ix = 0; ix < gridX1; ix ++ ) { + + var x = ix * segment_width - width_half; + var y = iz * segment_height - height_half; + + this.vertices.push( new THREE.Vector3( x, - y, 0 ) ); + + } + + } + + for ( iz = 0; iz < gridZ; iz ++ ) { + + for ( ix = 0; ix < gridX; ix ++ ) { + + var a = ix + gridX1 * iz; + var b = ix + gridX1 * ( iz + 1 ); + var c = ( ix + 1 ) + gridX1 * ( iz + 1 ); + var d = ( ix + 1 ) + gridX1 * iz; + + var face = new THREE.Face4( a, b, c, d ); + face.normal.copy( normal ); + face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone(), normal.clone() ); + + this.faces.push( face ); + this.faceVertexUvs[ 0 ].push( [ + new THREE.Vector2( ix / gridX, 1 - iz / gridZ ), + new THREE.Vector2( ix / gridX, 1 - ( iz + 1 ) / gridZ ), + new THREE.Vector2( ( ix + 1 ) / gridX, 1 - ( iz + 1 ) / gridZ ), + new THREE.Vector2( ( ix + 1 ) / gridX, 1 - iz / gridZ ) + ] ); + + } + + } + + this.computeCentroids(); + +}; + +THREE.PlaneGeometry.prototype = Object.create( THREE.Geometry.prototype ); +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.SphereGeometry = function ( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { + + THREE.Geometry.call( this ); + + this.radius = radius || 50; + + this.widthSegments = Math.max( 3, Math.floor( widthSegments ) || 8 ); + this.heightSegments = Math.max( 2, Math.floor( heightSegments ) || 6 ); + + phiStart = phiStart !== undefined ? phiStart : 0; + phiLength = phiLength !== undefined ? phiLength : Math.PI * 2; + + thetaStart = thetaStart !== undefined ? thetaStart : 0; + thetaLength = thetaLength !== undefined ? thetaLength : Math.PI; + + var x, y, vertices = [], uvs = []; + + for ( y = 0; y <= this.heightSegments; y ++ ) { + + var verticesRow = []; + var uvsRow = []; + + for ( x = 0; x <= this.widthSegments; x ++ ) { + + var u = x / this.widthSegments; + var v = y / this.heightSegments; + + var vertex = new THREE.Vector3(); + vertex.x = - this.radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); + vertex.y = this.radius * Math.cos( thetaStart + v * thetaLength ); + vertex.z = this.radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); + + this.vertices.push( vertex ); + + verticesRow.push( this.vertices.length - 1 ); + uvsRow.push( new THREE.Vector2( u, 1 - v ) ); + + } + + vertices.push( verticesRow ); + uvs.push( uvsRow ); + + } + + for ( y = 0; y < this.heightSegments; y ++ ) { + + for ( x = 0; x < this.widthSegments; x ++ ) { + + var v1 = vertices[ y ][ x + 1 ]; + var v2 = vertices[ y ][ x ]; + var v3 = vertices[ y + 1 ][ x ]; + var v4 = vertices[ y + 1 ][ x + 1 ]; + + var n1 = this.vertices[ v1 ].clone().normalize(); + var n2 = this.vertices[ v2 ].clone().normalize(); + var n3 = this.vertices[ v3 ].clone().normalize(); + var n4 = this.vertices[ v4 ].clone().normalize(); + + var uv1 = uvs[ y ][ x + 1 ].clone(); + var uv2 = uvs[ y ][ x ].clone(); + var uv3 = uvs[ y + 1 ][ x ].clone(); + var uv4 = uvs[ y + 1 ][ x + 1 ].clone(); + + if ( Math.abs( this.vertices[ v1 ].y ) === this.radius ) { + + this.faces.push( new THREE.Face3( v1, v3, v4, [ n1, n3, n4 ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv1, uv3, uv4 ] ); + + } else if ( Math.abs( this.vertices[ v3 ].y ) === this.radius ) { + + this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] ); + + } else { + + this.faces.push( new THREE.Face4( v1, v2, v3, v4, [ n1, n2, n3, n4 ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3, uv4 ] ); + + } + + } + + } + + this.computeCentroids(); + this.computeFaceNormals(); + + this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); + +}; + +THREE.SphereGeometry.prototype = Object.create( THREE.Geometry.prototype ); +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * @author alteredq / http://alteredqualia.com/ + * + * For creating 3D text geometry in three.js + * + * Text = 3D Text + * + * parameters = { + * size: <float>, // size of the text + * height: <float>, // thickness to extrude text + * curveSegments: <int>, // number of points on the curves + * + * font: <string>, // font name + * weight: <string>, // font weight (normal, bold) + * style: <string>, // font style (normal, italics) + * + * bevelEnabled: <bool>, // turn on bevel + * bevelThickness: <float>, // how deep into text bevel goes + * bevelSize: <float>, // how far from text outline is bevel + * } + * + */ + +/* Usage Examples + + // TextGeometry wrapper + + var text3d = new TextGeometry( text, options ); + + // Complete manner + + var textShapes = THREE.FontUtils.generateShapes( text, options ); + var text3d = new ExtrudeGeometry( textShapes, options ); + +*/ + + +THREE.TextGeometry = function ( text, parameters ) { + + var textShapes = THREE.FontUtils.generateShapes( text, parameters ); + + // translate parameters to ExtrudeGeometry API + + parameters.amount = parameters.height !== undefined ? parameters.height : 50; + + // defaults + + if ( parameters.bevelThickness === undefined ) parameters.bevelThickness = 10; + if ( parameters.bevelSize === undefined ) parameters.bevelSize = 8; + if ( parameters.bevelEnabled === undefined ) parameters.bevelEnabled = false; + + THREE.ExtrudeGeometry.call( this, textShapes, parameters ); + +}; + +THREE.TextGeometry.prototype = Object.create( THREE.ExtrudeGeometry.prototype ); +/** + * @author oosmoxiecode + * @author mrdoob / http://mrdoob.com/ + * based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3DLite/src/away3dlite/primitives/Torus.as?r=2888 + */ + +THREE.TorusGeometry = function ( radius, tube, radialSegments, tubularSegments, arc ) { + + THREE.Geometry.call( this ); + + var scope = this; + + this.radius = radius || 100; + this.tube = tube || 40; + this.radialSegments = radialSegments || 8; + this.tubularSegments = tubularSegments || 6; + this.arc = arc || Math.PI * 2; + + var center = new THREE.Vector3(), uvs = [], normals = []; + + for ( var j = 0; j <= this.radialSegments; j ++ ) { + + for ( var i = 0; i <= this.tubularSegments; i ++ ) { + + var u = i / this.tubularSegments * this.arc; + var v = j / this.radialSegments * Math.PI * 2; + + center.x = this.radius * Math.cos( u ); + center.y = this.radius * Math.sin( u ); + + var vertex = new THREE.Vector3(); + vertex.x = ( this.radius + this.tube * Math.cos( v ) ) * Math.cos( u ); + vertex.y = ( this.radius + this.tube * Math.cos( v ) ) * Math.sin( u ); + vertex.z = this.tube * Math.sin( v ); + + this.vertices.push( vertex ); + + uvs.push( new THREE.Vector2( i / this.tubularSegments, j / this.radialSegments ) ); + normals.push( vertex.clone().sub( center ).normalize() ); + + } + } + + + for ( var j = 1; j <= this.radialSegments; j ++ ) { + + for ( var i = 1; i <= this.tubularSegments; i ++ ) { + + var a = ( this.tubularSegments + 1 ) * j + i - 1; + var b = ( this.tubularSegments + 1 ) * ( j - 1 ) + i - 1; + var c = ( this.tubularSegments + 1 ) * ( j - 1 ) + i; + var d = ( this.tubularSegments + 1 ) * j + i; + + var face = new THREE.Face4( a, b, c, d, [ normals[ a ], normals[ b ], normals[ c ], normals[ d ] ] ); + face.normal.add( normals[ a ] ); + face.normal.add( normals[ b ] ); + face.normal.add( normals[ c ] ); + face.normal.add( normals[ d ] ); + face.normal.normalize(); + + this.faces.push( face ); + + this.faceVertexUvs[ 0 ].push( [ uvs[ a ].clone(), uvs[ b ].clone(), uvs[ c ].clone(), uvs[ d ].clone() ] ); + } + + } + + this.computeCentroids(); + +}; + +THREE.TorusGeometry.prototype = Object.create( THREE.Geometry.prototype ); +/** + * @author oosmoxiecode + * based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3D/src/away3d/primitives/TorusKnot.as?spec=svn2473&r=2473 + */ + +THREE.TorusKnotGeometry = function ( radius, tube, radialSegments, tubularSegments, p, q, heightScale ) { + + THREE.Geometry.call( this ); + + var scope = this; + + this.radius = radius || 100; + this.tube = tube || 40; + this.radialSegments = radialSegments || 64; + this.tubularSegments = tubularSegments || 8; + this.p = p || 2; + this.q = q || 3; + this.heightScale = heightScale || 1; + this.grid = new Array( this.radialSegments ); + + var tang = new THREE.Vector3(); + var n = new THREE.Vector3(); + var bitan = new THREE.Vector3(); + + for ( var i = 0; i < this.radialSegments; ++ i ) { + + this.grid[ i ] = new Array( this.tubularSegments ); + + for ( var j = 0; j < this.tubularSegments; ++ j ) { + + var u = i / this.radialSegments * 2 * this.p * Math.PI; + var v = j / this.tubularSegments * 2 * Math.PI; + var p1 = getPos( u, v, this.q, this.p, this.radius, this.heightScale ); + var p2 = getPos( u + 0.01, v, this.q, this.p, this.radius, this.heightScale ); + var cx, cy; + + tang.subVectors( p2, p1 ); + n.addVectors( p2, p1 ); + + bitan.crossVectors( tang, n ); + n.crossVectors( bitan, tang ); + bitan.normalize(); + n.normalize(); + + cx = - this.tube * Math.cos( v ); // TODO: Hack: Negating it so it faces outside. + cy = this.tube * Math.sin( v ); + + p1.x += cx * n.x + cy * bitan.x; + p1.y += cx * n.y + cy * bitan.y; + p1.z += cx * n.z + cy * bitan.z; + + this.grid[ i ][ j ] = vert( p1.x, p1.y, p1.z ); + + } + + } + + for ( var i = 0; i < this.radialSegments; ++ i ) { + + for ( var j = 0; j < this.tubularSegments; ++ j ) { + + var ip = ( i + 1 ) % this.radialSegments; + var jp = ( j + 1 ) % this.tubularSegments; + + var a = this.grid[ i ][ j ]; + var b = this.grid[ ip ][ j ]; + var c = this.grid[ ip ][ jp ]; + var d = this.grid[ i ][ jp ]; + + var uva = new THREE.Vector2( i / this.radialSegments, j / this.tubularSegments ); + var uvb = new THREE.Vector2( ( i + 1 ) / this.radialSegments, j / this.tubularSegments ); + var uvc = new THREE.Vector2( ( i + 1 ) / this.radialSegments, ( j + 1 ) / this.tubularSegments ); + var uvd = new THREE.Vector2( i / this.radialSegments, ( j + 1 ) / this.tubularSegments ); + + this.faces.push( new THREE.Face4( a, b, c, d ) ); + this.faceVertexUvs[ 0 ].push( [ uva,uvb,uvc, uvd ] ); + + } + } + + this.computeCentroids(); + this.computeFaceNormals(); + this.computeVertexNormals(); + + function vert( x, y, z ) { + + return scope.vertices.push( new THREE.Vector3( x, y, z ) ) - 1; + + } + + function getPos( u, v, in_q, in_p, radius, heightScale ) { + + var cu = Math.cos( u ); + var cv = Math.cos( v ); + var su = Math.sin( u ); + var quOverP = in_q / in_p * u; + var cs = Math.cos( quOverP ); + + var tx = radius * ( 2 + cs ) * 0.5 * cu; + var ty = radius * ( 2 + cs ) * su * 0.5; + var tz = heightScale * radius * Math.sin( quOverP ) * 0.5; + + return new THREE.Vector3( tx, ty, tz ); + + } + +}; + +THREE.TorusKnotGeometry.prototype = Object.create( THREE.Geometry.prototype ); +/** + * @author WestLangley / https://github.com/WestLangley + * @author zz85 / https://github.com/zz85 + * @author miningold / https://github.com/miningold + * + * Modified from the TorusKnotGeometry by @oosmoxiecode + * + * Creates a tube which extrudes along a 3d spline + * + * Uses parallel transport frames as described in + * http://www.cs.indiana.edu/pub/techreports/TR425.pdf + */ + +THREE.TubeGeometry = function( path, segments, radius, radiusSegments, closed, debug ) { + + THREE.Geometry.call( this ); + + this.path = path; + this.segments = segments || 64; + this.radius = radius || 1; + this.radiusSegments = radiusSegments || 8; + this.closed = closed || false; + + if ( debug ) this.debug = new THREE.Object3D(); + + this.grid = []; + + var scope = this, + + tangent, + normal, + binormal, + + numpoints = this.segments + 1, + + x, y, z, + tx, ty, tz, + u, v, + + cx, cy, + pos, pos2 = new THREE.Vector3(), + i, j, + ip, jp, + a, b, c, d, + uva, uvb, uvc, uvd; + + var frames = new THREE.TubeGeometry.FrenetFrames( this.path, this.segments, this.closed ), + tangents = frames.tangents, + normals = frames.normals, + binormals = frames.binormals; + + // proxy internals + this.tangents = tangents; + this.normals = normals; + this.binormals = binormals; + + function vert( x, y, z ) { + + return scope.vertices.push( new THREE.Vector3( x, y, z ) ) - 1; + + } + + + // consruct the grid + + for ( i = 0; i < numpoints; i++ ) { + + this.grid[ i ] = []; + + u = i / ( numpoints - 1 ); + + pos = path.getPointAt( u ); + + tangent = tangents[ i ]; + normal = normals[ i ]; + binormal = binormals[ i ]; + + if ( this.debug ) { + + this.debug.add( new THREE.ArrowHelper(tangent, pos, radius, 0x0000ff ) ); + this.debug.add( new THREE.ArrowHelper(normal, pos, radius, 0xff0000 ) ); + this.debug.add( new THREE.ArrowHelper(binormal, pos, radius, 0x00ff00 ) ); + + } + + for ( j = 0; j < this.radiusSegments; j++ ) { + + v = j / this.radiusSegments * 2 * Math.PI; + + cx = -this.radius * Math.cos( v ); // TODO: Hack: Negating it so it faces outside. + cy = this.radius * Math.sin( v ); + + pos2.copy( pos ); + pos2.x += cx * normal.x + cy * binormal.x; + pos2.y += cx * normal.y + cy * binormal.y; + pos2.z += cx * normal.z + cy * binormal.z; + + this.grid[ i ][ j ] = vert( pos2.x, pos2.y, pos2.z ); + + } + } + + + // construct the mesh + + for ( i = 0; i < this.segments; i++ ) { + + for ( j = 0; j < this.radiusSegments; j++ ) { + + ip = ( this.closed ) ? (i + 1) % this.segments : i + 1; + jp = (j + 1) % this.radiusSegments; + + a = this.grid[ i ][ j ]; // *** NOT NECESSARILY PLANAR ! *** + b = this.grid[ ip ][ j ]; + c = this.grid[ ip ][ jp ]; + d = this.grid[ i ][ jp ]; + + uva = new THREE.Vector2( i / this.segments, j / this.radiusSegments ); + uvb = new THREE.Vector2( ( i + 1 ) / this.segments, j / this.radiusSegments ); + uvc = new THREE.Vector2( ( i + 1 ) / this.segments, ( j + 1 ) / this.radiusSegments ); + uvd = new THREE.Vector2( i / this.segments, ( j + 1 ) / this.radiusSegments ); + + this.faces.push( new THREE.Face4( a, b, c, d ) ); + this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvc, uvd ] ); + + } + } + + this.computeCentroids(); + this.computeFaceNormals(); + this.computeVertexNormals(); + +}; + +THREE.TubeGeometry.prototype = Object.create( THREE.Geometry.prototype ); + + +// For computing of Frenet frames, exposing the tangents, normals and binormals the spline +THREE.TubeGeometry.FrenetFrames = function(path, segments, closed) { + + var tangent = new THREE.Vector3(), + normal = new THREE.Vector3(), + binormal = new THREE.Vector3(), + + tangents = [], + normals = [], + binormals = [], + + vec = new THREE.Vector3(), + mat = new THREE.Matrix4(), + + numpoints = segments + 1, + theta, + epsilon = 0.0001, + smallest, + + tx, ty, tz, + i, u, v; + + + // expose internals + this.tangents = tangents; + this.normals = normals; + this.binormals = binormals; + + // compute the tangent vectors for each segment on the path + + for ( i = 0; i < numpoints; i++ ) { + + u = i / ( numpoints - 1 ); + + tangents[ i ] = path.getTangentAt( u ); + tangents[ i ].normalize(); + + } + + initialNormal3(); + + function initialNormal1(lastBinormal) { + // fixed start binormal. Has dangers of 0 vectors + normals[ 0 ] = new THREE.Vector3(); + binormals[ 0 ] = new THREE.Vector3(); + if (lastBinormal===undefined) lastBinormal = new THREE.Vector3( 0, 0, 1 ); + normals[ 0 ].crossVectors( lastBinormal, tangents[ 0 ] ).normalize(); + binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ).normalize(); + } + + function initialNormal2() { + + // This uses the Frenet-Serret formula for deriving binormal + var t2 = path.getTangentAt( epsilon ); + + normals[ 0 ] = new THREE.Vector3().subVectors( t2, tangents[ 0 ] ).normalize(); + binormals[ 0 ] = new THREE.Vector3().crossVectors( tangents[ 0 ], normals[ 0 ] ); + + normals[ 0 ].crossVectors( binormals[ 0 ], tangents[ 0 ] ).normalize(); // last binormal x tangent + binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ).normalize(); + + } + + function initialNormal3() { + // select an initial normal vector perpenicular to the first tangent vector, + // and in the direction of the smallest tangent xyz component + + normals[ 0 ] = new THREE.Vector3(); + binormals[ 0 ] = new THREE.Vector3(); + smallest = Number.MAX_VALUE; + tx = Math.abs( tangents[ 0 ].x ); + ty = Math.abs( tangents[ 0 ].y ); + tz = Math.abs( tangents[ 0 ].z ); + + if ( tx <= smallest ) { + smallest = tx; + normal.set( 1, 0, 0 ); + } + + if ( ty <= smallest ) { + smallest = ty; + normal.set( 0, 1, 0 ); + } + + if ( tz <= smallest ) { + normal.set( 0, 0, 1 ); + } + + vec.crossVectors( tangents[ 0 ], normal ).normalize(); + + normals[ 0 ].crossVectors( tangents[ 0 ], vec ); + binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ); + } + + + // compute the slowly-varying normal and binormal vectors for each segment on the path + + for ( i = 1; i < numpoints; i++ ) { + + normals[ i ] = normals[ i-1 ].clone(); + + binormals[ i ] = binormals[ i-1 ].clone(); + + vec.crossVectors( tangents[ i-1 ], tangents[ i ] ); + + if ( vec.length() > epsilon ) { + + vec.normalize(); + + theta = Math.acos( tangents[ i-1 ].dot( tangents[ i ] ) ); + + normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) ); + + } + + binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); + + } + + + // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same + + if ( closed ) { + + theta = Math.acos( normals[ 0 ].dot( normals[ numpoints-1 ] ) ); + theta /= ( numpoints - 1 ); + + if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ numpoints-1 ] ) ) > 0 ) { + + theta = -theta; + + } + + for ( i = 1; i < numpoints; i++ ) { + + // twist a little... + normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) ); + binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); + + } + + } +}; +/** + * @author clockworkgeek / https://github.com/clockworkgeek + * @author timothypratley / https://github.com/timothypratley + */ + +THREE.PolyhedronGeometry = function ( vertices, faces, radius, detail ) { + + THREE.Geometry.call( this ); + + radius = radius || 1; + detail = detail || 0; + + var that = this; + + for ( var i = 0, l = vertices.length; i < l; i ++ ) { + + prepare( new THREE.Vector3( vertices[ i ][ 0 ], vertices[ i ][ 1 ], vertices[ i ][ 2 ] ) ); + + } + + var midpoints = [], p = this.vertices; + + for ( var i = 0, l = faces.length; i < l; i ++ ) { + + make( p[ faces[ i ][ 0 ] ], p[ faces[ i ][ 1 ] ], p[ faces[ i ][ 2 ] ], detail ); + + } + + this.mergeVertices(); + + // Apply radius + + for ( var i = 0, l = this.vertices.length; i < l; i ++ ) { + + this.vertices[ i ].multiplyScalar( radius ); + + } + + + // Project vector onto sphere's surface + + function prepare( vector ) { + + var vertex = vector.normalize().clone(); + vertex.index = that.vertices.push( vertex ) - 1; + + // Texture coords are equivalent to map coords, calculate angle and convert to fraction of a circle. + + var u = azimuth( vector ) / 2 / Math.PI + 0.5; + var v = inclination( vector ) / Math.PI + 0.5; + vertex.uv = new THREE.Vector2( u, 1 - v ); + + return vertex; + + } + + + // Approximate a curved face with recursively sub-divided triangles. + + function make( v1, v2, v3, detail ) { + + if ( detail < 1 ) { + + var face = new THREE.Face3( v1.index, v2.index, v3.index, [ v1.clone(), v2.clone(), v3.clone() ] ); + face.centroid.add( v1 ).add( v2 ).add( v3 ).divideScalar( 3 ); + face.normal = face.centroid.clone().normalize(); + that.faces.push( face ); + + var azi = azimuth( face.centroid ); + that.faceVertexUvs[ 0 ].push( [ + correctUV( v1.uv, v1, azi ), + correctUV( v2.uv, v2, azi ), + correctUV( v3.uv, v3, azi ) + ] ); + + } else { + + detail -= 1; + + // split triangle into 4 smaller triangles + + make( v1, midpoint( v1, v2 ), midpoint( v1, v3 ), detail ); // top quadrant + make( midpoint( v1, v2 ), v2, midpoint( v2, v3 ), detail ); // left quadrant + make( midpoint( v1, v3 ), midpoint( v2, v3 ), v3, detail ); // right quadrant + make( midpoint( v1, v2 ), midpoint( v2, v3 ), midpoint( v1, v3 ), detail ); // center quadrant + + } + + } + + function midpoint( v1, v2 ) { + + if ( !midpoints[ v1.index ] ) midpoints[ v1.index ] = []; + if ( !midpoints[ v2.index ] ) midpoints[ v2.index ] = []; + + var mid = midpoints[ v1.index ][ v2.index ]; + + if ( mid === undefined ) { + + // generate mean point and project to surface with prepare() + + midpoints[ v1.index ][ v2.index ] = midpoints[ v2.index ][ v1.index ] = mid = prepare( + new THREE.Vector3().addVectors( v1, v2 ).divideScalar( 2 ) + ); + } + + return mid; + + } + + + // Angle around the Y axis, counter-clockwise when looking from above. + + function azimuth( vector ) { + + return Math.atan2( vector.z, -vector.x ); + + } + + + // Angle above the XZ plane. + + function inclination( vector ) { + + return Math.atan2( -vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) ); + + } + + + // Texture fixing helper. Spheres have some odd behaviours. + + function correctUV( uv, vector, azimuth ) { + + if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) uv = new THREE.Vector2( uv.x - 1, uv.y ); + if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) uv = new THREE.Vector2( azimuth / 2 / Math.PI + 0.5, uv.y ); + return uv; + + } + + this.computeCentroids(); + + this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); + +}; + +THREE.PolyhedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); +/** + * @author timothypratley / https://github.com/timothypratley + */ + +THREE.IcosahedronGeometry = function ( radius, detail ) { + + var t = ( 1 + Math.sqrt( 5 ) ) / 2; + + var vertices = [ + [ -1, t, 0 ], [ 1, t, 0 ], [ -1, -t, 0 ], [ 1, -t, 0 ], + [ 0, -1, t ], [ 0, 1, t ], [ 0, -1, -t ], [ 0, 1, -t ], + [ t, 0, -1 ], [ t, 0, 1 ], [ -t, 0, -1 ], [ -t, 0, 1 ] + ]; + + var faces = [ + [ 0, 11, 5 ], [ 0, 5, 1 ], [ 0, 1, 7 ], [ 0, 7, 10 ], [ 0, 10, 11 ], + [ 1, 5, 9 ], [ 5, 11, 4 ], [ 11, 10, 2 ], [ 10, 7, 6 ], [ 7, 1, 8 ], + [ 3, 9, 4 ], [ 3, 4, 2 ], [ 3, 2, 6 ], [ 3, 6, 8 ], [ 3, 8, 9 ], + [ 4, 9, 5 ], [ 2, 4, 11 ], [ 6, 2, 10 ], [ 8, 6, 7 ], [ 9, 8, 1 ] + ]; + + THREE.PolyhedronGeometry.call( this, vertices, faces, radius, detail ); + +}; + +THREE.IcosahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); +/** + * @author timothypratley / https://github.com/timothypratley + */ + +THREE.OctahedronGeometry = function ( radius, detail ) { + + var vertices = [ + [ 1, 0, 0 ], [ -1, 0, 0 ], [ 0, 1, 0 ], [ 0, -1, 0 ], [ 0, 0, 1 ], [ 0, 0, -1 ] + ]; + + var faces = [ + [ 0, 2, 4 ], [ 0, 4, 3 ], [ 0, 3, 5 ], [ 0, 5, 2 ], [ 1, 2, 5 ], [ 1, 5, 3 ], [ 1, 3, 4 ], [ 1, 4, 2 ] + ]; + + THREE.PolyhedronGeometry.call( this, vertices, faces, radius, detail ); +}; + +THREE.OctahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); +/** + * @author timothypratley / https://github.com/timothypratley + */ + +THREE.TetrahedronGeometry = function ( radius, detail ) { + + var vertices = [ + [ 1, 1, 1 ], [ -1, -1, 1 ], [ -1, 1, -1 ], [ 1, -1, -1 ] + ]; + + var faces = [ + [ 2, 1, 0 ], [ 0, 3, 2 ], [ 1, 3, 0 ], [ 2, 3, 1 ] + ]; + + THREE.PolyhedronGeometry.call( this, vertices, faces, radius, detail ); + +}; + +THREE.TetrahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); +/** + * @author zz85 / https://github.com/zz85 + * Parametric Surfaces Geometry + * based on the brilliant article by @prideout http://prideout.net/blog/?p=44 + * + * new THREE.ParametricGeometry( parametricFunction, uSegments, ySegements, useTris ); + * + */ + +THREE.ParametricGeometry = function ( func, slices, stacks, useTris ) { + + THREE.Geometry.call( this ); + + var verts = this.vertices; + var faces = this.faces; + var uvs = this.faceVertexUvs[ 0 ]; + + useTris = (useTris === undefined) ? false : useTris; + + var i, il, j, p; + var u, v; + + var stackCount = stacks + 1; + var sliceCount = slices + 1; + + for ( i = 0; i <= stacks; i ++ ) { + + v = i / stacks; + + for ( j = 0; j <= slices; j ++ ) { + + u = j / slices; + + p = func( u, v ); + verts.push( p ); + + } + } + + var a, b, c, d; + var uva, uvb, uvc, uvd; + + for ( i = 0; i < stacks; i ++ ) { + + for ( j = 0; j < slices; j ++ ) { + + a = i * sliceCount + j; + b = i * sliceCount + j + 1; + c = (i + 1) * sliceCount + j; + d = (i + 1) * sliceCount + j + 1; + + uva = new THREE.Vector2( j / slices, i / stacks ); + uvb = new THREE.Vector2( ( j + 1 ) / slices, i / stacks ); + uvc = new THREE.Vector2( j / slices, ( i + 1 ) / stacks ); + uvd = new THREE.Vector2( ( j + 1 ) / slices, ( i + 1 ) / stacks ); + + if ( useTris ) { + + faces.push( new THREE.Face3( a, b, c ) ); + faces.push( new THREE.Face3( b, d, c ) ); + + uvs.push( [ uva, uvb, uvc ] ); + uvs.push( [ uvb, uvd, uvc ] ); + + } else { + + faces.push( new THREE.Face4( a, b, d, c ) ); + uvs.push( [ uva, uvb, uvd, uvc ] ); + + } + + } + + } + + // console.log(this); + + // magic bullet + // var diff = this.mergeVertices(); + // console.log('removed ', diff, ' vertices by merging'); + + this.computeCentroids(); + this.computeFaceNormals(); + this.computeVertexNormals(); + +}; + +THREE.ParametricGeometry.prototype = Object.create( THREE.Geometry.prototype ); +/** + * @author qiao / https://github.com/qiao + * @fileoverview This is a convex hull generator using the incremental method. + * The complexity is O(n^2) where n is the number of vertices. + * O(nlogn) algorithms do exist, but they are much more complicated. + * + * Benchmark: + * + * Platform: CPU: P7350 @2.00GHz Engine: V8 + * + * Num Vertices Time(ms) + * + * 10 1 + * 20 3 + * 30 19 + * 40 48 + * 50 107 + */ + +THREE.ConvexGeometry = function( vertices ) { + + THREE.Geometry.call( this ); + + var faces = [ [ 0, 1, 2 ], [ 0, 2, 1 ] ]; + + for ( var i = 3; i < vertices.length; i++ ) { + + addPoint( i ); + + } + + + function addPoint( vertexId ) { + + var vertex = vertices[ vertexId ].clone(); + + var mag = vertex.length(); + vertex.x += mag * randomOffset(); + vertex.y += mag * randomOffset(); + vertex.z += mag * randomOffset(); + + var hole = []; + + for ( var f = 0; f < faces.length; ) { + + var face = faces[ f ]; + + // for each face, if the vertex can see it, + // then we try to add the face's edges into the hole. + if ( visible( face, vertex ) ) { + + for ( var e = 0; e < 3; e++ ) { + + var edge = [ face[ e ], face[ ( e + 1 ) % 3 ] ]; + var boundary = true; + + // remove duplicated edges. + for ( var h = 0; h < hole.length; h++ ) { + + if ( equalEdge( hole[ h ], edge ) ) { + + hole[ h ] = hole[ hole.length - 1 ]; + hole.pop(); + boundary = false; + break; + + } + + } + + if ( boundary ) { + + hole.push( edge ); + + } + + } + + // remove faces[ f ] + faces[ f ] = faces[ faces.length - 1 ]; + faces.pop(); + + } else { // not visible + + f++; + + } + } + + // construct the new faces formed by the edges of the hole and the vertex + for ( var h = 0; h < hole.length; h++ ) { + + faces.push( [ + hole[ h ][ 0 ], + hole[ h ][ 1 ], + vertexId + ] ); + + } + } + + /** + * Whether the face is visible from the vertex + */ + function visible( face, vertex ) { + + var va = vertices[ face[ 0 ] ]; + var vb = vertices[ face[ 1 ] ]; + var vc = vertices[ face[ 2 ] ]; + + var n = normal( va, vb, vc ); + + // distance from face to origin + var dist = n.dot( va ); + + return n.dot( vertex ) >= dist; + + } + + /** + * Face normal + */ + function normal( va, vb, vc ) { + + var cb = new THREE.Vector3(); + var ab = new THREE.Vector3(); + + cb.subVectors( vc, vb ); + ab.subVectors( va, vb ); + cb.cross( ab ); + + cb.normalize(); + + return cb; + + } + + /** + * Detect whether two edges are equal. + * Note that when constructing the convex hull, two same edges can only + * be of the negative direction. + */ + function equalEdge( ea, eb ) { + + return ea[ 0 ] === eb[ 1 ] && ea[ 1 ] === eb[ 0 ]; + + } + + /** + * Create a random offset between -1e-6 and 1e-6. + */ + function randomOffset() { + + return ( Math.random() - 0.5 ) * 2 * 1e-6; + + } + + + /** + * XXX: Not sure if this is the correct approach. Need someone to review. + */ + function vertexUv( vertex ) { + + var mag = vertex.length(); + return new THREE.Vector2( vertex.x / mag, vertex.y / mag ); + + } + + // Push vertices into `this.vertices`, skipping those inside the hull + var id = 0; + var newId = new Array( vertices.length ); // map from old vertex id to new id + + for ( var i = 0; i < faces.length; i++ ) { + + var face = faces[ i ]; + + for ( var j = 0; j < 3; j++ ) { + + if ( newId[ face[ j ] ] === undefined ) { + + newId[ face[ j ] ] = id++; + this.vertices.push( vertices[ face[ j ] ] ); + + } + + face[ j ] = newId[ face[ j ] ]; + + } + + } + + // Convert faces into instances of THREE.Face3 + for ( var i = 0; i < faces.length; i++ ) { + + this.faces.push( new THREE.Face3( + faces[ i ][ 0 ], + faces[ i ][ 1 ], + faces[ i ][ 2 ] + ) ); + + } + + // Compute UVs + for ( var i = 0; i < this.faces.length; i++ ) { + + var face = this.faces[ i ]; + + this.faceVertexUvs[ 0 ].push( [ + vertexUv( this.vertices[ face.a ] ), + vertexUv( this.vertices[ face.b ] ), + vertexUv( this.vertices[ face.c ]) + ] ); + + } + + + this.computeCentroids(); + this.computeFaceNormals(); + this.computeVertexNormals(); + +}; + +THREE.ConvexGeometry.prototype = Object.create( THREE.Geometry.prototype ); +/** + * @author sroucheray / http://sroucheray.org/ + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.AxisHelper = function ( size ) { + + var geometry = new THREE.Geometry(); + + geometry.vertices.push( + new THREE.Vector3(), new THREE.Vector3( size || 1, 0, 0 ), + new THREE.Vector3(), new THREE.Vector3( 0, size || 1, 0 ), + new THREE.Vector3(), new THREE.Vector3( 0, 0, size || 1 ) + ); + + geometry.colors.push( + new THREE.Color( 0xff0000 ), new THREE.Color( 0xffaa00 ), + new THREE.Color( 0x00ff00 ), new THREE.Color( 0xaaff00 ), + new THREE.Color( 0x0000ff ), new THREE.Color( 0x00aaff ) + ); + + var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } ); + + THREE.Line.call( this, geometry, material, THREE.LinePieces ); + +}; + +THREE.AxisHelper.prototype = Object.create( THREE.Line.prototype ); +/** + * @author WestLangley / http://github.com/WestLangley + * @author zz85 / https://github.com/zz85 + * @author bhouston / https://exocortex.com + * + * Creates an arrow for visualizing directions + * + * Parameters: + * dir - Vector3 + * origin - Vector3 + * length - Number + * hex - color in hex value + */ + +THREE.ArrowHelper = function ( dir, origin, length, hex ) { + + THREE.Object3D.call( this ); + + if ( length === undefined ) length = 20; + if ( hex === undefined ) hex = 0xffff00; + + var lineGeometry = new THREE.Geometry(); + lineGeometry.vertices.push( new THREE.Vector3( 0, 0, 0 ) ); + lineGeometry.vertices.push( new THREE.Vector3( 0, 1, 0 ) ); + + this.line = new THREE.Line( lineGeometry, new THREE.LineBasicMaterial( { color: hex } ) ); + this.add( this.line ); + + var coneGeometry = new THREE.CylinderGeometry( 0, 0.05, 0.25, 5, 1 ); + + this.cone = new THREE.Mesh( coneGeometry, new THREE.MeshBasicMaterial( { color: hex } ) ); + this.cone.position.set( 0, 1, 0 ); + this.add( this.cone ); + + if ( origin instanceof THREE.Vector3 ) this.position = origin; + + this.setDirection( dir ); + this.setLength( length ); + +}; + +THREE.ArrowHelper.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.ArrowHelper.prototype.setDirection = function ( dir ) { + + var d = THREE.ArrowHelper.__v1.copy( dir ).normalize(); + + if ( d.y > 0.999 ) { + + this.rotation.set( 0, 0, 0 ); + + } else if ( d.y < - 0.999 ) { + + this.rotation.set( Math.PI, 0, 0 ); + + } else { + + var axis = THREE.ArrowHelper.__v2.set( d.z, 0, - d.x ).normalize(); + var radians = Math.acos( d.y ); + var quaternion = THREE.ArrowHelper.__q1.setFromAxisAngle( axis, radians ); + + this.rotation.setEulerFromQuaternion( quaternion, this.eulerOrder ); + + } + +}; + +THREE.ArrowHelper.prototype.setLength = function ( length ) { + + this.scale.set( length, length, length ); + +}; + +THREE.ArrowHelper.prototype.setColor = function ( hex ) { + + this.line.material.color.setHex( hex ); + this.cone.material.color.setHex( hex ); + +}; + +THREE.ArrowHelper.__v1 = new THREE.Vector3(); +THREE.ArrowHelper.__v2 = new THREE.Vector3(); +THREE.ArrowHelper.__q1 = new THREE.Quaternion(); +/** + * @author alteredq / http://alteredqualia.com/ + * + * - shows frustum, line of sight and up of the camera + * - suitable for fast updates + * - based on frustum visualization in lightgl.js shadowmap example + * http://evanw.github.com/lightgl.js/tests/shadowmap.html + */ + +THREE.CameraHelper = function ( camera ) { + + THREE.Line.call( this ); + + var scope = this; + + this.geometry = new THREE.Geometry(); + this.material = new THREE.LineBasicMaterial( { color: 0xffffff, vertexColors: THREE.FaceColors } ); + this.type = THREE.LinePieces; + + this.matrixWorld = camera.matrixWorld; + this.matrixAutoUpdate = false; + + this.pointMap = {}; + + // colors + + var hexFrustum = 0xffaa00; + var hexCone = 0xff0000; + var hexUp = 0x00aaff; + var hexTarget = 0xffffff; + var hexCross = 0x333333; + + // near + + addLine( "n1", "n2", hexFrustum ); + addLine( "n2", "n4", hexFrustum ); + addLine( "n4", "n3", hexFrustum ); + addLine( "n3", "n1", hexFrustum ); + + // far + + addLine( "f1", "f2", hexFrustum ); + addLine( "f2", "f4", hexFrustum ); + addLine( "f4", "f3", hexFrustum ); + addLine( "f3", "f1", hexFrustum ); + + // sides + + addLine( "n1", "f1", hexFrustum ); + addLine( "n2", "f2", hexFrustum ); + addLine( "n3", "f3", hexFrustum ); + addLine( "n4", "f4", hexFrustum ); + + // cone + + addLine( "p", "n1", hexCone ); + addLine( "p", "n2", hexCone ); + addLine( "p", "n3", hexCone ); + addLine( "p", "n4", hexCone ); + + // up + + addLine( "u1", "u2", hexUp ); + addLine( "u2", "u3", hexUp ); + addLine( "u3", "u1", hexUp ); + + // target + + addLine( "c", "t", hexTarget ); + addLine( "p", "c", hexCross ); + + // cross + + addLine( "cn1", "cn2", hexCross ); + addLine( "cn3", "cn4", hexCross ); + + addLine( "cf1", "cf2", hexCross ); + addLine( "cf3", "cf4", hexCross ); + + this.camera = camera; + + function addLine( a, b, hex ) { + + addPoint( a, hex ); + addPoint( b, hex ); + + } + + function addPoint( id, hex ) { + + scope.geometry.vertices.push( new THREE.Vector3() ); + scope.geometry.colors.push( new THREE.Color( hex ) ); + + if ( scope.pointMap[ id ] === undefined ) scope.pointMap[ id ] = []; + + scope.pointMap[ id ].push( scope.geometry.vertices.length - 1 ); + + } + + this.update( camera ); + +}; + +THREE.CameraHelper.prototype = Object.create( THREE.Line.prototype ); + +THREE.CameraHelper.prototype.update = function () { + + var scope = this; + + var w = 1, h = 1; + + // we need just camera projection matrix + // world matrix must be identity + + THREE.CameraHelper.__c.projectionMatrix.copy( this.camera.projectionMatrix ); + + // center / target + + setPoint( "c", 0, 0, -1 ); + setPoint( "t", 0, 0, 1 ); + + // near + + setPoint( "n1", -w, -h, -1 ); + setPoint( "n2", w, -h, -1 ); + setPoint( "n3", -w, h, -1 ); + setPoint( "n4", w, h, -1 ); + + // far + + setPoint( "f1", -w, -h, 1 ); + setPoint( "f2", w, -h, 1 ); + setPoint( "f3", -w, h, 1 ); + setPoint( "f4", w, h, 1 ); + + // up + + setPoint( "u1", w * 0.7, h * 1.1, -1 ); + setPoint( "u2", -w * 0.7, h * 1.1, -1 ); + setPoint( "u3", 0, h * 2, -1 ); + + // cross + + setPoint( "cf1", -w, 0, 1 ); + setPoint( "cf2", w, 0, 1 ); + setPoint( "cf3", 0, -h, 1 ); + setPoint( "cf4", 0, h, 1 ); + + setPoint( "cn1", -w, 0, -1 ); + setPoint( "cn2", w, 0, -1 ); + setPoint( "cn3", 0, -h, -1 ); + setPoint( "cn4", 0, h, -1 ); + + function setPoint( point, x, y, z ) { + + THREE.CameraHelper.__v.set( x, y, z ); + THREE.CameraHelper.__projector.unprojectVector( THREE.CameraHelper.__v, THREE.CameraHelper.__c ); + + var points = scope.pointMap[ point ]; + + if ( points !== undefined ) { + + for ( var i = 0, il = points.length; i < il; i ++ ) { + + scope.geometry.vertices[ points[ i ] ].copy( THREE.CameraHelper.__v ); + + } + + } + + } + + this.geometry.verticesNeedUpdate = true; + +}; + +THREE.CameraHelper.__projector = new THREE.Projector(); +THREE.CameraHelper.__v = new THREE.Vector3(); +THREE.CameraHelper.__c = new THREE.Camera(); + +/** + * @author alteredq / http://alteredqualia.com/ + * + * - shows directional light color, intensity, position, orientation and target + */ + +THREE.DirectionalLightHelper = function ( light, sphereSize ) { + + THREE.Object3D.call( this ); + + this.light = light; + + // position + + this.position = light.position; + + // direction + + this.direction = new THREE.Vector3(); + this.direction.subVectors( light.target.position, light.position ); + + // color + + var intensity = THREE.Math.clamp( light.intensity, 0, 1 ); + + this.color = light.color.clone(); + this.color.multiplyScalar( intensity ); + + var hexColor = this.color.getHex(); + + // light helper + + var bulbGeometry = new THREE.SphereGeometry( sphereSize, 16, 8 ); + var raysGeometry = new THREE.AsteriskGeometry( sphereSize * 1.25, sphereSize * 2.25 ); + + var bulbMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false } ); + var raysMaterial = new THREE.LineBasicMaterial( { color: hexColor, fog: false } ); + + this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial ); + + this.lightRays = new THREE.Line( raysGeometry, raysMaterial, THREE.LinePieces ); + + this.add( this.lightSphere ); + this.add( this.lightRays ); + + this.lightSphere.properties.isGizmo = true; + this.lightSphere.properties.gizmoSubject = light; + this.lightSphere.properties.gizmoRoot = this; + + // light target helper + + this.targetSphere = null; + + if ( light.target.properties.targetInverse !== undefined ) { + + var targetGeo = new THREE.SphereGeometry( sphereSize, 8, 4 ); + var targetMaterial = new THREE.MeshBasicMaterial( { color: hexColor, wireframe: true, fog: false } ); + + this.targetSphere = new THREE.Mesh( targetGeo, targetMaterial ); + this.targetSphere.position = light.target.position; + + this.targetSphere.properties.isGizmo = true; + this.targetSphere.properties.gizmoSubject = light.target; + this.targetSphere.properties.gizmoRoot = this.targetSphere; + + var lineMaterial = new THREE.LineDashedMaterial( { color: hexColor, dashSize: 4, gapSize: 4, opacity: 0.75, transparent: true, fog: false } ); + var lineGeometry = new THREE.Geometry(); + lineGeometry.vertices.push( this.position.clone() ); + lineGeometry.vertices.push( this.targetSphere.position.clone() ); + lineGeometry.computeLineDistances(); + + this.targetLine = new THREE.Line( lineGeometry, lineMaterial ); + this.targetLine.properties.isGizmo = true; + + } + + // + + this.properties.isGizmo = true; + +} + +THREE.DirectionalLightHelper.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.DirectionalLightHelper.prototype.update = function () { + + // update arrow orientation + // pointing from light to target + + this.direction.subVectors( this.light.target.position, this.light.position ); + + // update arrow, spheres, rays and line colors to light color * light intensity + + var intensity = THREE.Math.clamp( this.light.intensity, 0, 1 ); + + this.color.copy( this.light.color ); + this.color.multiplyScalar( intensity ); + + this.lightSphere.material.color.copy( this.color ); + this.lightRays.material.color.copy( this.color ); + + // Only update targetSphere and targetLine if available + if ( this.targetSphere !== null ) { + + this.targetSphere.material.color.copy( this.color ); + this.targetLine.material.color.copy( this.color ); + + // update target line vertices + + this.targetLine.geometry.vertices[ 0 ].copy( this.light.position ); + this.targetLine.geometry.vertices[ 1 ].copy( this.light.target.position ); + + this.targetLine.geometry.computeLineDistances(); + this.targetLine.geometry.verticesNeedUpdate = true; + + } + +} + +/** + * @author alteredq / http://alteredqualia.com/ + * + * - shows hemisphere light intensity, sky and ground colors and directions + */ + +THREE.HemisphereLightHelper = function ( light, sphereSize, arrowLength, domeSize ) { + + THREE.Object3D.call( this ); + + this.light = light; + + // position + + this.position = light.position; + + // + + var intensity = THREE.Math.clamp( light.intensity, 0, 1 ); + + // sky color + + this.color = light.color.clone(); + this.color.multiplyScalar( intensity ); + + var hexColor = this.color.getHex(); + + // ground color + + this.groundColor = light.groundColor.clone(); + this.groundColor.multiplyScalar( intensity ); + + var hexColorGround = this.groundColor.getHex(); + + // double colored light bulb + + var bulbGeometry = new THREE.SphereGeometry( sphereSize, 16, 8, 0, Math.PI * 2, 0, Math.PI * 0.5 ); + var bulbGroundGeometry = new THREE.SphereGeometry( sphereSize, 16, 8, 0, Math.PI * 2, Math.PI * 0.5, Math.PI ); + + var bulbSkyMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false } ); + var bulbGroundMaterial = new THREE.MeshBasicMaterial( { color: hexColorGround, fog: false } ); + + for ( var i = 0, il = bulbGeometry.faces.length; i < il; i ++ ) { + + bulbGeometry.faces[ i ].materialIndex = 0; + + } + + for ( var i = 0, il = bulbGroundGeometry.faces.length; i < il; i ++ ) { + + bulbGroundGeometry.faces[ i ].materialIndex = 1; + + } + + THREE.GeometryUtils.merge( bulbGeometry, bulbGroundGeometry ); + + this.lightSphere = new THREE.Mesh( bulbGeometry, new THREE.MeshFaceMaterial( [ bulbSkyMaterial, bulbGroundMaterial ] ) ); + + // arrows for sky and ground light directions + + this.lightArrow = new THREE.ArrowHelper( new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( 0, ( sphereSize + arrowLength ) * 1.1, 0 ), arrowLength, hexColor ); + this.lightArrow.rotation.x = Math.PI; + + this.lightArrowGround = new THREE.ArrowHelper( new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( 0, ( sphereSize + arrowLength ) * -1.1, 0 ), arrowLength, hexColorGround ); + + var joint = new THREE.Object3D(); + joint.rotation.x = -Math.PI * 0.5; + + joint.add( this.lightSphere ); + joint.add( this.lightArrow ); + joint.add( this.lightArrowGround ); + + this.add( joint ); + + // + + this.lightSphere.properties.isGizmo = true; + this.lightSphere.properties.gizmoSubject = light; + this.lightSphere.properties.gizmoRoot = this; + + // + + this.properties.isGizmo = true; + + // + + this.target = new THREE.Vector3(); + this.lookAt( this.target ); + +} + +THREE.HemisphereLightHelper.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.HemisphereLightHelper.prototype.update = function () { + + // update sphere sky and ground colors to light color * light intensity + + var intensity = THREE.Math.clamp( this.light.intensity, 0, 1 ); + + this.color.copy( this.light.color ); + this.color.multiplyScalar( intensity ); + + this.groundColor.copy( this.light.groundColor ); + this.groundColor.multiplyScalar( intensity ); + + this.lightSphere.material.materials[ 0 ].color.copy( this.color ); + this.lightSphere.material.materials[ 1 ].color.copy( this.groundColor ); + + this.lightArrow.setColor( this.color.getHex() ); + this.lightArrowGround.setColor( this.groundColor.getHex() ); + + this.lookAt( this.target ); + +} + +/** + * @author alteredq / http://alteredqualia.com/ + * + * - shows point light color, intensity, position and distance + */ + +THREE.PointLightHelper = function ( light, sphereSize ) { + + THREE.Object3D.call( this ); + + this.light = light; + + // position + + this.position = light.position; + + // color + + var intensity = THREE.Math.clamp( light.intensity, 0, 1 ); + + this.color = light.color.clone(); + this.color.multiplyScalar( intensity ); + + var hexColor = this.color.getHex(); + + // light helper + + var bulbGeometry = new THREE.SphereGeometry( sphereSize, 16, 8 ); + var raysGeometry = new THREE.AsteriskGeometry( sphereSize * 1.25, sphereSize * 2.25 ); + var distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 ); + + var bulbMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false } ); + var raysMaterial = new THREE.LineBasicMaterial( { color: hexColor, fog: false } ); + var distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } ); + + this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial ); + this.lightRays = new THREE.Line( raysGeometry, raysMaterial, THREE.LinePieces ); + this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial ); + + var d = light.distance; + + if ( d === 0.0 ) { + + this.lightDistance.visible = false; + + } else { + + this.lightDistance.scale.set( d, d, d ); + + } + + this.add( this.lightSphere ); + this.add( this.lightRays ); + this.add( this.lightDistance ); + + // + + this.lightSphere.properties.isGizmo = true; + this.lightSphere.properties.gizmoSubject = light; + this.lightSphere.properties.gizmoRoot = this; + + // + + this.properties.isGizmo = true; + +} + +THREE.PointLightHelper.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.PointLightHelper.prototype.update = function () { + + // update sphere and rays colors to light color * light intensity + + var intensity = THREE.Math.clamp( this.light.intensity, 0, 1 ); + + this.color.copy( this.light.color ); + this.color.multiplyScalar( intensity ); + + this.lightSphere.material.color.copy( this.color ); + this.lightRays.material.color.copy( this.color ); + this.lightDistance.material.color.copy( this.color ); + + // + + var d = this.light.distance; + + if ( d === 0.0 ) { + + this.lightDistance.visible = false; + + } else { + + this.lightDistance.visible = true; + this.lightDistance.scale.set( d, d, d ); + + } + +} + +/** + * @author alteredq / http://alteredqualia.com/ + * + * - shows spot light color, intensity, position, orientation, light cone and target + */ + +THREE.SpotLightHelper = function ( light, sphereSize ) { + + THREE.Object3D.call( this ); + + this.light = light; + + // position + + this.position = light.position; + + // direction + + this.direction = new THREE.Vector3(); + this.direction.subVectors( light.target.position, light.position ); + + // color + + var intensity = THREE.Math.clamp( light.intensity, 0, 1 ); + + this.color = light.color.clone(); + this.color.multiplyScalar( intensity ); + + var hexColor = this.color.getHex(); + + // light helper + + var bulbGeometry = new THREE.SphereGeometry( sphereSize, 16, 8 ); + var raysGeometry = new THREE.AsteriskGeometry( sphereSize * 1.25, sphereSize * 2.25 ); + var coneGeometry = new THREE.CylinderGeometry( 0.0001, 1, 1, 8, 1, true ); + + var coneMatrix = new THREE.Matrix4(); + coneMatrix.rotateX( -Math.PI/2 ); + coneMatrix.translate( new THREE.Vector3( 0, -0.5, 0 ) ); + coneGeometry.applyMatrix( coneMatrix ); + + var bulbMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false } ); + var raysMaterial = new THREE.LineBasicMaterial( { color: hexColor, fog: false } ); + var coneMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.3, transparent: true } ); + + this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial ); + this.lightCone = new THREE.Mesh( coneGeometry, coneMaterial ); + + var coneLength = light.distance ? light.distance : 10000; + var coneWidth = coneLength * Math.tan( light.angle * 0.5 ) * 2; + this.lightCone.scale.set( coneWidth, coneWidth, coneLength ); + + this.lightRays = new THREE.Line( raysGeometry, raysMaterial, THREE.LinePieces ); + + this.gyroscope = new THREE.Gyroscope(); + + this.gyroscope.add( this.lightSphere ); + this.gyroscope.add( this.lightRays ); + + this.add( this.gyroscope ); + this.add( this.lightCone ); + + this.lookAt( light.target.position ); + + this.lightSphere.properties.isGizmo = true; + this.lightSphere.properties.gizmoSubject = light; + this.lightSphere.properties.gizmoRoot = this; + + // light target helper + + this.targetSphere = null; + + if ( light.target.properties.targetInverse !== undefined ) { + + var targetGeo = new THREE.SphereGeometry( sphereSize, 8, 4 ); + var targetMaterial = new THREE.MeshBasicMaterial( { color: hexColor, wireframe: true, fog: false } ); + + this.targetSphere = new THREE.Mesh( targetGeo, targetMaterial ); + this.targetSphere.position = light.target.position; + + this.targetSphere.properties.isGizmo = true; + this.targetSphere.properties.gizmoSubject = light.target; + this.targetSphere.properties.gizmoRoot = this.targetSphere; + + var lineMaterial = new THREE.LineDashedMaterial( { color: hexColor, dashSize: 4, gapSize: 4, opacity: 0.75, transparent: true, fog: false } ); + var lineGeometry = new THREE.Geometry(); + lineGeometry.vertices.push( this.position.clone() ); + lineGeometry.vertices.push( this.targetSphere.position.clone() ); + lineGeometry.computeLineDistances(); + + this.targetLine = new THREE.Line( lineGeometry, lineMaterial ); + this.targetLine.properties.isGizmo = true; + + } + + // + + this.properties.isGizmo = true; + +} + +THREE.SpotLightHelper.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.SpotLightHelper.prototype.update = function () { + + // update arrow orientation + // pointing from light to target + + this.direction.subVectors( this.light.target.position, this.light.position ); + + // update light cone orientation and size + + this.lookAt( this.light.target.position ); + + var coneLength = this.light.distance ? this.light.distance : 10000; + var coneWidth = coneLength * Math.tan( this.light.angle * 0.5 ) * 2; + this.lightCone.scale.set( coneWidth, coneWidth, coneLength ); + + // update arrow, spheres, rays and line colors to light color * light intensity + + var intensity = THREE.Math.clamp( this.light.intensity, 0, 1 ); + + this.color.copy( this.light.color ); + this.color.multiplyScalar( intensity ); + + this.lightSphere.material.color.copy( this.color ); + this.lightRays.material.color.copy( this.color ); + this.lightCone.material.color.copy( this.color ); + + // Only update targetSphere and targetLine if available + if ( this.targetSphere !== null ) { + + this.targetSphere.material.color.copy( this.color ); + this.targetLine.material.color.copy( this.color ); + + // update target line vertices + + this.targetLine.geometry.vertices[ 0 ].copy( this.light.position ); + this.targetLine.geometry.vertices[ 1 ].copy( this.light.target.position ); + + this.targetLine.geometry.computeLineDistances(); + this.targetLine.geometry.verticesNeedUpdate = true; + + } + +}; +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.ImmediateRenderObject = function () { + + THREE.Object3D.call( this ); + + this.render = function ( renderCallback ) { }; + +}; + +THREE.ImmediateRenderObject.prototype = Object.create( THREE.Object3D.prototype ); +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.LensFlare = function ( texture, size, distance, blending, color ) { + + THREE.Object3D.call( this ); + + this.lensFlares = []; + + this.positionScreen = new THREE.Vector3(); + this.customUpdateCallback = undefined; + + if( texture !== undefined ) { + + this.add( texture, size, distance, blending, color ); + + } + +}; + +THREE.LensFlare.prototype = Object.create( THREE.Object3D.prototype ); + + +/* + * Add: adds another flare + */ + +THREE.LensFlare.prototype.add = function ( texture, size, distance, blending, color, opacity ) { + + if( size === undefined ) size = -1; + if( distance === undefined ) distance = 0; + if( opacity === undefined ) opacity = 1; + if( color === undefined ) color = new THREE.Color( 0xffffff ); + if( blending === undefined ) blending = THREE.NormalBlending; + + distance = Math.min( distance, Math.max( 0, distance ) ); + + this.lensFlares.push( { texture: texture, // THREE.Texture + size: size, // size in pixels (-1 = use texture.width) + distance: distance, // distance (0-1) from light source (0=at light source) + x: 0, y: 0, z: 0, // screen position (-1 => 1) z = 0 is ontop z = 1 is back + scale: 1, // scale + rotation: 1, // rotation + opacity: opacity, // opacity + color: color, // color + blending: blending } ); // blending + +}; + + +/* + * Update lens flares update positions on all flares based on the screen position + * Set myLensFlare.customUpdateCallback to alter the flares in your project specific way. + */ + +THREE.LensFlare.prototype.updateLensFlares = function () { + + var f, fl = this.lensFlares.length; + var flare; + var vecX = -this.positionScreen.x * 2; + var vecY = -this.positionScreen.y * 2; + + for( f = 0; f < fl; f ++ ) { + + flare = this.lensFlares[ f ]; + + flare.x = this.positionScreen.x + vecX * flare.distance; + flare.y = this.positionScreen.y + vecY * flare.distance; + + flare.wantedRotation = flare.x * Math.PI * 0.25; + flare.rotation += ( flare.wantedRotation - flare.rotation ) * 0.25; + + } + +}; + + + + + + + + + + + + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.MorphBlendMesh = function( geometry, material ) { + + THREE.Mesh.call( this, geometry, material ); + + this.animationsMap = {}; + this.animationsList = []; + + // prepare default animation + // (all frames played together in 1 second) + + var numFrames = this.geometry.morphTargets.length; + + var name = "__default"; + + var startFrame = 0; + var endFrame = numFrames - 1; + + var fps = numFrames / 1; + + this.createAnimation( name, startFrame, endFrame, fps ); + this.setAnimationWeight( name, 1 ); + +}; + +THREE.MorphBlendMesh.prototype = Object.create( THREE.Mesh.prototype ); + +THREE.MorphBlendMesh.prototype.createAnimation = function ( name, start, end, fps ) { + + var animation = { + + startFrame: start, + endFrame: end, + + length: end - start + 1, + + fps: fps, + duration: ( end - start ) / fps, + + lastFrame: 0, + currentFrame: 0, + + active: false, + + time: 0, + direction: 1, + weight: 1, + + directionBackwards: false, + mirroredLoop: false + + }; + + this.animationsMap[ name ] = animation; + this.animationsList.push( animation ); + +}; + +THREE.MorphBlendMesh.prototype.autoCreateAnimations = function ( fps ) { + + var pattern = /([a-z]+)(\d+)/; + + var firstAnimation, frameRanges = {}; + + var geometry = this.geometry; + + for ( var i = 0, il = geometry.morphTargets.length; i < il; i ++ ) { + + var morph = geometry.morphTargets[ i ]; + var chunks = morph.name.match( pattern ); + + if ( chunks && chunks.length > 1 ) { + + var name = chunks[ 1 ]; + var num = chunks[ 2 ]; + + if ( ! frameRanges[ name ] ) frameRanges[ name ] = { start: Infinity, end: -Infinity }; + + var range = frameRanges[ name ]; + + if ( i < range.start ) range.start = i; + if ( i > range.end ) range.end = i; + + if ( ! firstAnimation ) firstAnimation = name; + + } + + } + + for ( var name in frameRanges ) { + + var range = frameRanges[ name ]; + this.createAnimation( name, range.start, range.end, fps ); + + } + + this.firstAnimation = firstAnimation; + +}; + +THREE.MorphBlendMesh.prototype.setAnimationDirectionForward = function ( name ) { + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + animation.direction = 1; + animation.directionBackwards = false; + + } + +}; + +THREE.MorphBlendMesh.prototype.setAnimationDirectionBackward = function ( name ) { + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + animation.direction = -1; + animation.directionBackwards = true; + + } + +}; + +THREE.MorphBlendMesh.prototype.setAnimationFPS = function ( name, fps ) { + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + animation.fps = fps; + animation.duration = ( animation.end - animation.start ) / animation.fps; + + } + +}; + +THREE.MorphBlendMesh.prototype.setAnimationDuration = function ( name, duration ) { + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + animation.duration = duration; + animation.fps = ( animation.end - animation.start ) / animation.duration; + + } + +}; + +THREE.MorphBlendMesh.prototype.setAnimationWeight = function ( name, weight ) { + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + animation.weight = weight; + + } + +}; + +THREE.MorphBlendMesh.prototype.setAnimationTime = function ( name, time ) { + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + animation.time = time; + + } + +}; + +THREE.MorphBlendMesh.prototype.getAnimationTime = function ( name ) { + + var time = 0; + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + time = animation.time; + + } + + return time; + +}; + +THREE.MorphBlendMesh.prototype.getAnimationDuration = function ( name ) { + + var duration = -1; + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + duration = animation.duration; + + } + + return duration; + +}; + +THREE.MorphBlendMesh.prototype.playAnimation = function ( name ) { + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + animation.time = 0; + animation.active = true; + + } else { + + console.warn( "animation[" + name + "] undefined" ); + + } + +}; + +THREE.MorphBlendMesh.prototype.stopAnimation = function ( name ) { + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + animation.active = false; + + } + +}; + +THREE.MorphBlendMesh.prototype.update = function ( delta ) { + + for ( var i = 0, il = this.animationsList.length; i < il; i ++ ) { + + var animation = this.animationsList[ i ]; + + if ( ! animation.active ) continue; + + var frameTime = animation.duration / animation.length; + + animation.time += animation.direction * delta; + + if ( animation.mirroredLoop ) { + + if ( animation.time > animation.duration || animation.time < 0 ) { + + animation.direction *= -1; + + if ( animation.time > animation.duration ) { + + animation.time = animation.duration; + animation.directionBackwards = true; + + } + + if ( animation.time < 0 ) { + + animation.time = 0; + animation.directionBackwards = false; + + } + + } + + } else { + + animation.time = animation.time % animation.duration; + + if ( animation.time < 0 ) animation.time += animation.duration; + + } + + var keyframe = animation.startFrame + THREE.Math.clamp( Math.floor( animation.time / frameTime ), 0, animation.length - 1 ); + var weight = animation.weight; + + if ( keyframe !== animation.currentFrame ) { + + this.morphTargetInfluences[ animation.lastFrame ] = 0; + this.morphTargetInfluences[ animation.currentFrame ] = 1 * weight; + + this.morphTargetInfluences[ keyframe ] = 0; + + animation.lastFrame = animation.currentFrame; + animation.currentFrame = keyframe; + + } + + var mix = ( animation.time % frameTime ) / frameTime; + + if ( animation.directionBackwards ) mix = 1 - mix; + + this.morphTargetInfluences[ animation.currentFrame ] = mix * weight; + this.morphTargetInfluences[ animation.lastFrame ] = ( 1 - mix ) * weight; + + } + +}; +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.LensFlarePlugin = function () { + + var _gl, _renderer, _precision, _lensFlare = {}; + + this.init = function ( renderer ) { + + _gl = renderer.context; + _renderer = renderer; + + _precision = renderer.getPrecision(); + + _lensFlare.vertices = new Float32Array( 8 + 8 ); + _lensFlare.faces = new Uint16Array( 6 ); + + var i = 0; + _lensFlare.vertices[ i++ ] = -1; _lensFlare.vertices[ i++ ] = -1; // vertex + _lensFlare.vertices[ i++ ] = 0; _lensFlare.vertices[ i++ ] = 0; // uv... etc. + + _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = -1; + _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = 0; + + _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = 1; + _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = 1; + + _lensFlare.vertices[ i++ ] = -1; _lensFlare.vertices[ i++ ] = 1; + _lensFlare.vertices[ i++ ] = 0; _lensFlare.vertices[ i++ ] = 1; + + i = 0; + _lensFlare.faces[ i++ ] = 0; _lensFlare.faces[ i++ ] = 1; _lensFlare.faces[ i++ ] = 2; + _lensFlare.faces[ i++ ] = 0; _lensFlare.faces[ i++ ] = 2; _lensFlare.faces[ i++ ] = 3; + + // buffers + + _lensFlare.vertexBuffer = _gl.createBuffer(); + _lensFlare.elementBuffer = _gl.createBuffer(); + + _gl.bindBuffer( _gl.ARRAY_BUFFER, _lensFlare.vertexBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, _lensFlare.vertices, _gl.STATIC_DRAW ); + + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.elementBuffer ); + _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.faces, _gl.STATIC_DRAW ); + + // textures + + _lensFlare.tempTexture = _gl.createTexture(); + _lensFlare.occlusionTexture = _gl.createTexture(); + + _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.tempTexture ); + _gl.texImage2D( _gl.TEXTURE_2D, 0, _gl.RGB, 16, 16, 0, _gl.RGB, _gl.UNSIGNED_BYTE, null ); + _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE ); + _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE ); + _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, _gl.NEAREST ); + _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, _gl.NEAREST ); + + _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.occlusionTexture ); + _gl.texImage2D( _gl.TEXTURE_2D, 0, _gl.RGBA, 16, 16, 0, _gl.RGBA, _gl.UNSIGNED_BYTE, null ); + _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE ); + _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE ); + _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, _gl.NEAREST ); + _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, _gl.NEAREST ); + + if ( _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ) <= 0 ) { + + _lensFlare.hasVertexTexture = false; + _lensFlare.program = createProgram( THREE.ShaderFlares[ "lensFlare" ], _precision ); + + } else { + + _lensFlare.hasVertexTexture = true; + _lensFlare.program = createProgram( THREE.ShaderFlares[ "lensFlareVertexTexture" ], _precision ); + + } + + _lensFlare.attributes = {}; + _lensFlare.uniforms = {}; + + _lensFlare.attributes.vertex = _gl.getAttribLocation ( _lensFlare.program, "position" ); + _lensFlare.attributes.uv = _gl.getAttribLocation ( _lensFlare.program, "uv" ); + + _lensFlare.uniforms.renderType = _gl.getUniformLocation( _lensFlare.program, "renderType" ); + _lensFlare.uniforms.map = _gl.getUniformLocation( _lensFlare.program, "map" ); + _lensFlare.uniforms.occlusionMap = _gl.getUniformLocation( _lensFlare.program, "occlusionMap" ); + _lensFlare.uniforms.opacity = _gl.getUniformLocation( _lensFlare.program, "opacity" ); + _lensFlare.uniforms.color = _gl.getUniformLocation( _lensFlare.program, "color" ); + _lensFlare.uniforms.scale = _gl.getUniformLocation( _lensFlare.program, "scale" ); + _lensFlare.uniforms.rotation = _gl.getUniformLocation( _lensFlare.program, "rotation" ); + _lensFlare.uniforms.screenPosition = _gl.getUniformLocation( _lensFlare.program, "screenPosition" ); + + }; + + + /* + * Render lens flares + * Method: renders 16x16 0xff00ff-colored points scattered over the light source area, + * reads these back and calculates occlusion. + * Then _lensFlare.update_lensFlares() is called to re-position and + * update transparency of flares. Then they are rendered. + * + */ + + this.render = function ( scene, camera, viewportWidth, viewportHeight ) { + + var flares = scene.__webglFlares, + nFlares = flares.length; + + if ( ! nFlares ) return; + + var tempPosition = new THREE.Vector3(); + + var invAspect = viewportHeight / viewportWidth, + halfViewportWidth = viewportWidth * 0.5, + halfViewportHeight = viewportHeight * 0.5; + + var size = 16 / viewportHeight, + scale = new THREE.Vector2( size * invAspect, size ); + + var screenPosition = new THREE.Vector3( 1, 1, 0 ), + screenPositionPixels = new THREE.Vector2( 1, 1 ); + + var uniforms = _lensFlare.uniforms, + attributes = _lensFlare.attributes; + + // set _lensFlare program and reset blending + + _gl.useProgram( _lensFlare.program ); + + _gl.enableVertexAttribArray( _lensFlare.attributes.vertex ); + _gl.enableVertexAttribArray( _lensFlare.attributes.uv ); + + // loop through all lens flares to update their occlusion and positions + // setup gl and common used attribs/unforms + + _gl.uniform1i( uniforms.occlusionMap, 0 ); + _gl.uniform1i( uniforms.map, 1 ); + + _gl.bindBuffer( _gl.ARRAY_BUFFER, _lensFlare.vertexBuffer ); + _gl.vertexAttribPointer( attributes.vertex, 2, _gl.FLOAT, false, 2 * 8, 0 ); + _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 2 * 8, 8 ); + + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.elementBuffer ); + + _gl.disable( _gl.CULL_FACE ); + _gl.depthMask( false ); + + var i, j, jl, flare, sprite; + + for ( i = 0; i < nFlares; i ++ ) { + + size = 16 / viewportHeight; + scale.set( size * invAspect, size ); + + // calc object screen position + + flare = flares[ i ]; + + tempPosition.set( flare.matrixWorld.elements[12], flare.matrixWorld.elements[13], flare.matrixWorld.elements[14] ); + + tempPosition.applyMatrix4( camera.matrixWorldInverse ); + tempPosition.applyProjection( camera.projectionMatrix ); + + // setup arrays for gl programs + + screenPosition.copy( tempPosition ) + + screenPositionPixels.x = screenPosition.x * halfViewportWidth + halfViewportWidth; + screenPositionPixels.y = screenPosition.y * halfViewportHeight + halfViewportHeight; + + // screen cull + + if ( _lensFlare.hasVertexTexture || ( + screenPositionPixels.x > 0 && + screenPositionPixels.x < viewportWidth && + screenPositionPixels.y > 0 && + screenPositionPixels.y < viewportHeight ) ) { + + // save current RGB to temp texture + + _gl.activeTexture( _gl.TEXTURE1 ); + _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.tempTexture ); + _gl.copyTexImage2D( _gl.TEXTURE_2D, 0, _gl.RGB, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0 ); + + + // render pink quad + + _gl.uniform1i( uniforms.renderType, 0 ); + _gl.uniform2f( uniforms.scale, scale.x, scale.y ); + _gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z ); + + _gl.disable( _gl.BLEND ); + _gl.enable( _gl.DEPTH_TEST ); + + _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 ); + + + // copy result to occlusionMap + + _gl.activeTexture( _gl.TEXTURE0 ); + _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.occlusionTexture ); + _gl.copyTexImage2D( _gl.TEXTURE_2D, 0, _gl.RGBA, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0 ); + + + // restore graphics + + _gl.uniform1i( uniforms.renderType, 1 ); + _gl.disable( _gl.DEPTH_TEST ); + + _gl.activeTexture( _gl.TEXTURE1 ); + _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.tempTexture ); + _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 ); + + + // update object positions + + flare.positionScreen.copy( screenPosition ) + + if ( flare.customUpdateCallback ) { + + flare.customUpdateCallback( flare ); + + } else { + + flare.updateLensFlares(); + + } + + // render flares + + _gl.uniform1i( uniforms.renderType, 2 ); + _gl.enable( _gl.BLEND ); + + for ( j = 0, jl = flare.lensFlares.length; j < jl; j ++ ) { + + sprite = flare.lensFlares[ j ]; + + if ( sprite.opacity > 0.001 && sprite.scale > 0.001 ) { + + screenPosition.x = sprite.x; + screenPosition.y = sprite.y; + screenPosition.z = sprite.z; + + size = sprite.size * sprite.scale / viewportHeight; + + scale.x = size * invAspect; + scale.y = size; + + _gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z ); + _gl.uniform2f( uniforms.scale, scale.x, scale.y ); + _gl.uniform1f( uniforms.rotation, sprite.rotation ); + + _gl.uniform1f( uniforms.opacity, sprite.opacity ); + _gl.uniform3f( uniforms.color, sprite.color.r, sprite.color.g, sprite.color.b ); + + _renderer.setBlending( sprite.blending, sprite.blendEquation, sprite.blendSrc, sprite.blendDst ); + _renderer.setTexture( sprite.texture, 1 ); + + _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 ); + + } + + } + + } + + } + + // restore gl + + _gl.enable( _gl.CULL_FACE ); + _gl.enable( _gl.DEPTH_TEST ); + _gl.depthMask( true ); + + }; + + function createProgram ( shader, precision ) { + + var program = _gl.createProgram(); + + var fragmentShader = _gl.createShader( _gl.FRAGMENT_SHADER ); + var vertexShader = _gl.createShader( _gl.VERTEX_SHADER ); + + var prefix = "precision " + precision + " float;\n"; + + _gl.shaderSource( fragmentShader, prefix + shader.fragmentShader ); + _gl.shaderSource( vertexShader, prefix + shader.vertexShader ); + + _gl.compileShader( fragmentShader ); + _gl.compileShader( vertexShader ); + + _gl.attachShader( program, fragmentShader ); + _gl.attachShader( program, vertexShader ); + + _gl.linkProgram( program ); + + return program; + + }; + +}; +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.ShadowMapPlugin = function () { + + var _gl, + _renderer, + _depthMaterial, _depthMaterialMorph, _depthMaterialSkin, _depthMaterialMorphSkin, + + _frustum = new THREE.Frustum(), + _projScreenMatrix = new THREE.Matrix4(), + + _min = new THREE.Vector3(), + _max = new THREE.Vector3(), + + _matrixPosition = new THREE.Vector3(); + + this.init = function ( renderer ) { + + _gl = renderer.context; + _renderer = renderer; + + var depthShader = THREE.ShaderLib[ "depthRGBA" ]; + var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms ); + + _depthMaterial = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms } ); + _depthMaterialMorph = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true } ); + _depthMaterialSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, skinning: true } ); + _depthMaterialMorphSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true, skinning: true } ); + + _depthMaterial._shadowPass = true; + _depthMaterialMorph._shadowPass = true; + _depthMaterialSkin._shadowPass = true; + _depthMaterialMorphSkin._shadowPass = true; + + }; + + this.render = function ( scene, camera ) { + + if ( ! ( _renderer.shadowMapEnabled && _renderer.shadowMapAutoUpdate ) ) return; + + this.update( scene, camera ); + + }; + + this.update = function ( scene, camera ) { + + var i, il, j, jl, n, + + shadowMap, shadowMatrix, shadowCamera, + program, buffer, material, + webglObject, object, light, + renderList, + + lights = [], + k = 0, + + fog = null; + + // set GL state for depth map + + _gl.clearColor( 1, 1, 1, 1 ); + _gl.disable( _gl.BLEND ); + + _gl.enable( _gl.CULL_FACE ); + _gl.frontFace( _gl.CCW ); + + if ( _renderer.shadowMapCullFace === THREE.CullFaceFront ) { + + _gl.cullFace( _gl.FRONT ); + + } else { + + _gl.cullFace( _gl.BACK ); + + } + + _renderer.setDepthTest( true ); + + // preprocess lights + // - skip lights that are not casting shadows + // - create virtual lights for cascaded shadow maps + + for ( i = 0, il = scene.__lights.length; i < il; i ++ ) { + + light = scene.__lights[ i ]; + + if ( ! light.castShadow ) continue; + + if ( ( light instanceof THREE.DirectionalLight ) && light.shadowCascade ) { + + for ( n = 0; n < light.shadowCascadeCount; n ++ ) { + + var virtualLight; + + if ( ! light.shadowCascadeArray[ n ] ) { + + virtualLight = createVirtualLight( light, n ); + virtualLight.originalCamera = camera; + + var gyro = new THREE.Gyroscope(); + gyro.position = light.shadowCascadeOffset; + + gyro.add( virtualLight ); + gyro.add( virtualLight.target ); + + camera.add( gyro ); + + light.shadowCascadeArray[ n ] = virtualLight; + + console.log( "Created virtualLight", virtualLight ); + + } else { + + virtualLight = light.shadowCascadeArray[ n ]; + + } + + updateVirtualLight( light, n ); + + lights[ k ] = virtualLight; + k ++; + + } + + } else { + + lights[ k ] = light; + k ++; + + } + + } + + // render depth map + + for ( i = 0, il = lights.length; i < il; i ++ ) { + + light = lights[ i ]; + + if ( ! light.shadowMap ) { + + var shadowFilter = THREE.LinearFilter; + + if ( _renderer.shadowMapType === THREE.PCFSoftShadowMap ) { + + shadowFilter = THREE.NearestFilter; + + } + + var pars = { minFilter: shadowFilter, magFilter: shadowFilter, format: THREE.RGBAFormat }; + + light.shadowMap = new THREE.WebGLRenderTarget( light.shadowMapWidth, light.shadowMapHeight, pars ); + light.shadowMapSize = new THREE.Vector2( light.shadowMapWidth, light.shadowMapHeight ); + + light.shadowMatrix = new THREE.Matrix4(); + + } + + if ( ! light.shadowCamera ) { + + if ( light instanceof THREE.SpotLight ) { + + light.shadowCamera = new THREE.PerspectiveCamera( light.shadowCameraFov, light.shadowMapWidth / light.shadowMapHeight, light.shadowCameraNear, light.shadowCameraFar ); + + } else if ( light instanceof THREE.DirectionalLight ) { + + light.shadowCamera = new THREE.OrthographicCamera( light.shadowCameraLeft, light.shadowCameraRight, light.shadowCameraTop, light.shadowCameraBottom, light.shadowCameraNear, light.shadowCameraFar ); + + } else { + + console.error( "Unsupported light type for shadow" ); + continue; + + } + + scene.add( light.shadowCamera ); + + if ( _renderer.autoUpdateScene ) scene.updateMatrixWorld(); + + } + + if ( light.shadowCameraVisible && ! light.cameraHelper ) { + + light.cameraHelper = new THREE.CameraHelper( light.shadowCamera ); + light.shadowCamera.add( light.cameraHelper ); + + } + + if ( light.isVirtual && virtualLight.originalCamera == camera ) { + + updateShadowCamera( camera, light ); + + } + + shadowMap = light.shadowMap; + shadowMatrix = light.shadowMatrix; + shadowCamera = light.shadowCamera; + + shadowCamera.position.getPositionFromMatrix( light.matrixWorld ); + _matrixPosition.getPositionFromMatrix( light.target.matrixWorld ); + shadowCamera.lookAt( _matrixPosition ); + shadowCamera.updateMatrixWorld(); + + shadowCamera.matrixWorldInverse.getInverse( shadowCamera.matrixWorld ); + + if ( light.cameraHelper ) light.cameraHelper.visible = light.shadowCameraVisible; + if ( light.shadowCameraVisible ) light.cameraHelper.update(); + + // compute shadow matrix + + shadowMatrix.set( 0.5, 0.0, 0.0, 0.5, + 0.0, 0.5, 0.0, 0.5, + 0.0, 0.0, 0.5, 0.5, + 0.0, 0.0, 0.0, 1.0 ); + + shadowMatrix.multiply( shadowCamera.projectionMatrix ); + shadowMatrix.multiply( shadowCamera.matrixWorldInverse ); + + // update camera matrices and frustum + + _projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse ); + _frustum.setFromMatrix( _projScreenMatrix ); + + // render shadow map + + _renderer.setRenderTarget( shadowMap ); + _renderer.clear(); + + // set object matrices & frustum culling + + renderList = scene.__webglObjects; + + for ( j = 0, jl = renderList.length; j < jl; j ++ ) { + + webglObject = renderList[ j ]; + object = webglObject.object; + + webglObject.render = false; + + if ( object.visible && object.castShadow ) { + + if ( ! ( object instanceof THREE.Mesh || object instanceof THREE.ParticleSystem ) || ! ( object.frustumCulled ) || _frustum.intersectsObject( object ) ) { + + object._modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); + + webglObject.render = true; + + } + + } + + } + + // render regular objects + + var objectMaterial, useMorphing, useSkinning; + + for ( j = 0, jl = renderList.length; j < jl; j ++ ) { + + webglObject = renderList[ j ]; + + if ( webglObject.render ) { + + object = webglObject.object; + buffer = webglObject.buffer; + + // culling is overriden globally for all objects + // while rendering depth map + + // need to deal with MeshFaceMaterial somehow + // in that case just use the first of material.materials for now + // (proper solution would require to break objects by materials + // similarly to regular rendering and then set corresponding + // depth materials per each chunk instead of just once per object) + + objectMaterial = getObjectMaterial( object ); + + useMorphing = object.geometry.morphTargets.length > 0 && objectMaterial.morphTargets; + useSkinning = object instanceof THREE.SkinnedMesh && objectMaterial.skinning; + + if ( object.customDepthMaterial ) { + + material = object.customDepthMaterial; + + } else if ( useSkinning ) { + + material = useMorphing ? _depthMaterialMorphSkin : _depthMaterialSkin; + + } else if ( useMorphing ) { + + material = _depthMaterialMorph; + + } else { + + material = _depthMaterial; + + } + + if ( buffer instanceof THREE.BufferGeometry ) { + + _renderer.renderBufferDirect( shadowCamera, scene.__lights, fog, material, buffer, object ); + + } else { + + _renderer.renderBuffer( shadowCamera, scene.__lights, fog, material, buffer, object ); + + } + + } + + } + + // set matrices and render immediate objects + + renderList = scene.__webglObjectsImmediate; + + for ( j = 0, jl = renderList.length; j < jl; j ++ ) { + + webglObject = renderList[ j ]; + object = webglObject.object; + + if ( object.visible && object.castShadow ) { + + object._modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); + + _renderer.renderImmediateObject( shadowCamera, scene.__lights, fog, _depthMaterial, object ); + + } + + } + + } + + // restore GL state + + var clearColor = _renderer.getClearColor(), + clearAlpha = _renderer.getClearAlpha(); + + _gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearAlpha ); + _gl.enable( _gl.BLEND ); + + if ( _renderer.shadowMapCullFace === THREE.CullFaceFront ) { + + _gl.cullFace( _gl.BACK ); + + } + + }; + + function createVirtualLight( light, cascade ) { + + var virtualLight = new THREE.DirectionalLight(); + + virtualLight.isVirtual = true; + + virtualLight.onlyShadow = true; + virtualLight.castShadow = true; + + virtualLight.shadowCameraNear = light.shadowCameraNear; + virtualLight.shadowCameraFar = light.shadowCameraFar; + + virtualLight.shadowCameraLeft = light.shadowCameraLeft; + virtualLight.shadowCameraRight = light.shadowCameraRight; + virtualLight.shadowCameraBottom = light.shadowCameraBottom; + virtualLight.shadowCameraTop = light.shadowCameraTop; + + virtualLight.shadowCameraVisible = light.shadowCameraVisible; + + virtualLight.shadowDarkness = light.shadowDarkness; + + virtualLight.shadowBias = light.shadowCascadeBias[ cascade ]; + virtualLight.shadowMapWidth = light.shadowCascadeWidth[ cascade ]; + virtualLight.shadowMapHeight = light.shadowCascadeHeight[ cascade ]; + + virtualLight.pointsWorld = []; + virtualLight.pointsFrustum = []; + + var pointsWorld = virtualLight.pointsWorld, + pointsFrustum = virtualLight.pointsFrustum; + + for ( var i = 0; i < 8; i ++ ) { + + pointsWorld[ i ] = new THREE.Vector3(); + pointsFrustum[ i ] = new THREE.Vector3(); + + } + + var nearZ = light.shadowCascadeNearZ[ cascade ]; + var farZ = light.shadowCascadeFarZ[ cascade ]; + + pointsFrustum[ 0 ].set( -1, -1, nearZ ); + pointsFrustum[ 1 ].set( 1, -1, nearZ ); + pointsFrustum[ 2 ].set( -1, 1, nearZ ); + pointsFrustum[ 3 ].set( 1, 1, nearZ ); + + pointsFrustum[ 4 ].set( -1, -1, farZ ); + pointsFrustum[ 5 ].set( 1, -1, farZ ); + pointsFrustum[ 6 ].set( -1, 1, farZ ); + pointsFrustum[ 7 ].set( 1, 1, farZ ); + + return virtualLight; + + } + + // Synchronize virtual light with the original light + + function updateVirtualLight( light, cascade ) { + + var virtualLight = light.shadowCascadeArray[ cascade ]; + + virtualLight.position.copy( light.position ); + virtualLight.target.position.copy( light.target.position ); + virtualLight.lookAt( virtualLight.target ); + + virtualLight.shadowCameraVisible = light.shadowCameraVisible; + virtualLight.shadowDarkness = light.shadowDarkness; + + virtualLight.shadowBias = light.shadowCascadeBias[ cascade ]; + + var nearZ = light.shadowCascadeNearZ[ cascade ]; + var farZ = light.shadowCascadeFarZ[ cascade ]; + + var pointsFrustum = virtualLight.pointsFrustum; + + pointsFrustum[ 0 ].z = nearZ; + pointsFrustum[ 1 ].z = nearZ; + pointsFrustum[ 2 ].z = nearZ; + pointsFrustum[ 3 ].z = nearZ; + + pointsFrustum[ 4 ].z = farZ; + pointsFrustum[ 5 ].z = farZ; + pointsFrustum[ 6 ].z = farZ; + pointsFrustum[ 7 ].z = farZ; + + } + + // Fit shadow camera's ortho frustum to camera frustum + + function updateShadowCamera( camera, light ) { + + var shadowCamera = light.shadowCamera, + pointsFrustum = light.pointsFrustum, + pointsWorld = light.pointsWorld; + + _min.set( Infinity, Infinity, Infinity ); + _max.set( -Infinity, -Infinity, -Infinity ); + + for ( var i = 0; i < 8; i ++ ) { + + var p = pointsWorld[ i ]; + + p.copy( pointsFrustum[ i ] ); + THREE.ShadowMapPlugin.__projector.unprojectVector( p, camera ); + + p.applyMatrix4( shadowCamera.matrixWorldInverse ); + + if ( p.x < _min.x ) _min.x = p.x; + if ( p.x > _max.x ) _max.x = p.x; + + if ( p.y < _min.y ) _min.y = p.y; + if ( p.y > _max.y ) _max.y = p.y; + + if ( p.z < _min.z ) _min.z = p.z; + if ( p.z > _max.z ) _max.z = p.z; + + } + + shadowCamera.left = _min.x; + shadowCamera.right = _max.x; + shadowCamera.top = _max.y; + shadowCamera.bottom = _min.y; + + // can't really fit near/far + //shadowCamera.near = _min.z; + //shadowCamera.far = _max.z; + + shadowCamera.updateProjectionMatrix(); + + } + + // For the moment just ignore objects that have multiple materials with different animation methods + // Only the first material will be taken into account for deciding which depth material to use for shadow maps + + function getObjectMaterial( object ) { + + return object.material instanceof THREE.MeshFaceMaterial + ? object.material.materials[ 0 ] + : object.material; + + }; + +}; + +THREE.ShadowMapPlugin.__projector = new THREE.Projector(); +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.SpritePlugin = function () { + + var _gl, _renderer, _precision, _sprite = {}; + + this.init = function ( renderer ) { + + _gl = renderer.context; + _renderer = renderer; + + _precision = renderer.getPrecision(); + + _sprite.vertices = new Float32Array( 8 + 8 ); + _sprite.faces = new Uint16Array( 6 ); + + var i = 0; + + _sprite.vertices[ i++ ] = -1; _sprite.vertices[ i++ ] = -1; // vertex 0 + _sprite.vertices[ i++ ] = 0; _sprite.vertices[ i++ ] = 0; // uv 0 + + _sprite.vertices[ i++ ] = 1; _sprite.vertices[ i++ ] = -1; // vertex 1 + _sprite.vertices[ i++ ] = 1; _sprite.vertices[ i++ ] = 0; // uv 1 + + _sprite.vertices[ i++ ] = 1; _sprite.vertices[ i++ ] = 1; // vertex 2 + _sprite.vertices[ i++ ] = 1; _sprite.vertices[ i++ ] = 1; // uv 2 + + _sprite.vertices[ i++ ] = -1; _sprite.vertices[ i++ ] = 1; // vertex 3 + _sprite.vertices[ i++ ] = 0; _sprite.vertices[ i++ ] = 1; // uv 3 + + i = 0; + + _sprite.faces[ i++ ] = 0; _sprite.faces[ i++ ] = 1; _sprite.faces[ i++ ] = 2; + _sprite.faces[ i++ ] = 0; _sprite.faces[ i++ ] = 2; _sprite.faces[ i++ ] = 3; + + _sprite.vertexBuffer = _gl.createBuffer(); + _sprite.elementBuffer = _gl.createBuffer(); + + _gl.bindBuffer( _gl.ARRAY_BUFFER, _sprite.vertexBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, _sprite.vertices, _gl.STATIC_DRAW ); + + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _sprite.elementBuffer ); + _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, _sprite.faces, _gl.STATIC_DRAW ); + + _sprite.program = createProgram( THREE.ShaderSprite[ "sprite" ], _precision ); + + _sprite.attributes = {}; + _sprite.uniforms = {}; + + _sprite.attributes.position = _gl.getAttribLocation ( _sprite.program, "position" ); + _sprite.attributes.uv = _gl.getAttribLocation ( _sprite.program, "uv" ); + + _sprite.uniforms.uvOffset = _gl.getUniformLocation( _sprite.program, "uvOffset" ); + _sprite.uniforms.uvScale = _gl.getUniformLocation( _sprite.program, "uvScale" ); + + _sprite.uniforms.rotation = _gl.getUniformLocation( _sprite.program, "rotation" ); + _sprite.uniforms.scale = _gl.getUniformLocation( _sprite.program, "scale" ); + _sprite.uniforms.alignment = _gl.getUniformLocation( _sprite.program, "alignment" ); + + _sprite.uniforms.color = _gl.getUniformLocation( _sprite.program, "color" ); + _sprite.uniforms.map = _gl.getUniformLocation( _sprite.program, "map" ); + _sprite.uniforms.opacity = _gl.getUniformLocation( _sprite.program, "opacity" ); + + _sprite.uniforms.useScreenCoordinates = _gl.getUniformLocation( _sprite.program, "useScreenCoordinates" ); + _sprite.uniforms.sizeAttenuation = _gl.getUniformLocation( _sprite.program, "sizeAttenuation" ); + _sprite.uniforms.screenPosition = _gl.getUniformLocation( _sprite.program, "screenPosition" ); + _sprite.uniforms.modelViewMatrix = _gl.getUniformLocation( _sprite.program, "modelViewMatrix" ); + _sprite.uniforms.projectionMatrix = _gl.getUniformLocation( _sprite.program, "projectionMatrix" ); + + _sprite.uniforms.fogType = _gl.getUniformLocation( _sprite.program, "fogType" ); + _sprite.uniforms.fogDensity = _gl.getUniformLocation( _sprite.program, "fogDensity" ); + _sprite.uniforms.fogNear = _gl.getUniformLocation( _sprite.program, "fogNear" ); + _sprite.uniforms.fogFar = _gl.getUniformLocation( _sprite.program, "fogFar" ); + _sprite.uniforms.fogColor = _gl.getUniformLocation( _sprite.program, "fogColor" ); + + _sprite.uniforms.alphaTest = _gl.getUniformLocation( _sprite.program, "alphaTest" ); + + }; + + this.render = function ( scene, camera, viewportWidth, viewportHeight ) { + + var sprites = scene.__webglSprites, + nSprites = sprites.length; + + if ( ! nSprites ) return; + + var attributes = _sprite.attributes, + uniforms = _sprite.uniforms; + + var invAspect = viewportHeight / viewportWidth; + + var halfViewportWidth = viewportWidth * 0.5, + halfViewportHeight = viewportHeight * 0.5; + + // setup gl + + _gl.useProgram( _sprite.program ); + + _gl.enableVertexAttribArray( attributes.position ); + _gl.enableVertexAttribArray( attributes.uv ); + + _gl.disable( _gl.CULL_FACE ); + _gl.enable( _gl.BLEND ); + + _gl.bindBuffer( _gl.ARRAY_BUFFER, _sprite.vertexBuffer ); + _gl.vertexAttribPointer( attributes.position, 2, _gl.FLOAT, false, 2 * 8, 0 ); + _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 2 * 8, 8 ); + + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _sprite.elementBuffer ); + + _gl.uniformMatrix4fv( uniforms.projectionMatrix, false, camera.projectionMatrix.elements ); + + _gl.activeTexture( _gl.TEXTURE0 ); + _gl.uniform1i( uniforms.map, 0 ); + + var oldFogType = 0; + var sceneFogType = 0; + var fog = scene.fog; + + if ( fog ) { + + _gl.uniform3f( uniforms.fogColor, fog.color.r, fog.color.g, fog.color.b ); + + if ( fog instanceof THREE.Fog ) { + + _gl.uniform1f( uniforms.fogNear, fog.near ); + _gl.uniform1f( uniforms.fogFar, fog.far ); + + _gl.uniform1i( uniforms.fogType, 1 ); + oldFogType = 1; + sceneFogType = 1; + + } else if ( fog instanceof THREE.FogExp2 ) { + + _gl.uniform1f( uniforms.fogDensity, fog.density ); + + _gl.uniform1i( uniforms.fogType, 2 ); + oldFogType = 2; + sceneFogType = 2; + + } + + } else { + + _gl.uniform1i( uniforms.fogType, 0 ); + oldFogType = 0; + sceneFogType = 0; + + } + + + // update positions and sort + + var i, sprite, material, screenPosition, size, fogType, scale = []; + + for( i = 0; i < nSprites; i ++ ) { + + sprite = sprites[ i ]; + material = sprite.material; + + if ( ! sprite.visible || material.opacity === 0 ) continue; + + if ( ! material.useScreenCoordinates ) { + + sprite._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, sprite.matrixWorld ); + sprite.z = - sprite._modelViewMatrix.elements[ 14 ]; + + } else { + + sprite.z = - sprite.position.z; + + } + + } + + sprites.sort( painterSortStable ); + + // render all sprites + + for( i = 0; i < nSprites; i ++ ) { + + sprite = sprites[ i ]; + material = sprite.material; + + if ( ! sprite.visible || material.opacity === 0 ) continue; + + if ( material.map && material.map.image && material.map.image.width ) { + + _gl.uniform1f( uniforms.alphaTest, material.alphaTest ); + + if ( material.useScreenCoordinates === true ) { + + _gl.uniform1i( uniforms.useScreenCoordinates, 1 ); + _gl.uniform3f( + uniforms.screenPosition, + ( ( sprite.position.x * _renderer.devicePixelRatio ) - halfViewportWidth ) / halfViewportWidth, + ( halfViewportHeight - ( sprite.position.y * _renderer.devicePixelRatio ) ) / halfViewportHeight, + Math.max( 0, Math.min( 1, sprite.position.z ) ) + ); + + scale[ 0 ] = _renderer.devicePixelRatio; + scale[ 1 ] = _renderer.devicePixelRatio; + + } else { + + _gl.uniform1i( uniforms.useScreenCoordinates, 0 ); + _gl.uniform1i( uniforms.sizeAttenuation, material.sizeAttenuation ? 1 : 0 ); + _gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, sprite._modelViewMatrix.elements ); + + scale[ 0 ] = 1; + scale[ 1 ] = 1; + + } + + if ( scene.fog && material.fog ) { + + fogType = sceneFogType; + + } else { + + fogType = 0; + + } + + if ( oldFogType !== fogType ) { + + _gl.uniform1i( uniforms.fogType, fogType ); + oldFogType = fogType; + + } + + size = 1 / ( material.scaleByViewport ? viewportHeight : 1 ); + + scale[ 0 ] *= size * invAspect * sprite.scale.x + scale[ 1 ] *= size * sprite.scale.y; + + _gl.uniform2f( uniforms.uvScale, material.uvScale.x, material.uvScale.y ); + _gl.uniform2f( uniforms.uvOffset, material.uvOffset.x, material.uvOffset.y ); + _gl.uniform2f( uniforms.alignment, material.alignment.x, material.alignment.y ); + + _gl.uniform1f( uniforms.opacity, material.opacity ); + _gl.uniform3f( uniforms.color, material.color.r, material.color.g, material.color.b ); + + _gl.uniform1f( uniforms.rotation, sprite.rotation ); + _gl.uniform2fv( uniforms.scale, scale ); + + _renderer.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); + _renderer.setDepthTest( material.depthTest ); + _renderer.setDepthWrite( material.depthWrite ); + _renderer.setTexture( material.map, 0 ); + + _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 ); + + } + + } + + // restore gl + + _gl.enable( _gl.CULL_FACE ); + + }; + + function createProgram ( shader, precision ) { + + var program = _gl.createProgram(); + + var fragmentShader = _gl.createShader( _gl.FRAGMENT_SHADER ); + var vertexShader = _gl.createShader( _gl.VERTEX_SHADER ); + + var prefix = "precision " + precision + " float;\n"; + + _gl.shaderSource( fragmentShader, prefix + shader.fragmentShader ); + _gl.shaderSource( vertexShader, prefix + shader.vertexShader ); + + _gl.compileShader( fragmentShader ); + _gl.compileShader( vertexShader ); + + _gl.attachShader( program, fragmentShader ); + _gl.attachShader( program, vertexShader ); + + _gl.linkProgram( program ); + + return program; + + }; + + function painterSortStable ( a, b ) { + + if ( a.z !== b.z ) { + + return b.z - a.z; + + } else { + + return b.id - a.id; + + } + + }; + +}; +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.DepthPassPlugin = function () { + + this.enabled = false; + this.renderTarget = null; + + var _gl, + _renderer, + _depthMaterial, _depthMaterialMorph, _depthMaterialSkin, _depthMaterialMorphSkin, + + _frustum = new THREE.Frustum(), + _projScreenMatrix = new THREE.Matrix4(); + + this.init = function ( renderer ) { + + _gl = renderer.context; + _renderer = renderer; + + var depthShader = THREE.ShaderLib[ "depthRGBA" ]; + var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms ); + + _depthMaterial = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms } ); + _depthMaterialMorph = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true } ); + _depthMaterialSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, skinning: true } ); + _depthMaterialMorphSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true, skinning: true } ); + + _depthMaterial._shadowPass = true; + _depthMaterialMorph._shadowPass = true; + _depthMaterialSkin._shadowPass = true; + _depthMaterialMorphSkin._shadowPass = true; + + }; + + this.render = function ( scene, camera ) { + + if ( ! this.enabled ) return; + + this.update( scene, camera ); + + }; + + this.update = function ( scene, camera ) { + + var i, il, j, jl, n, + + program, buffer, material, + webglObject, object, light, + renderList, + + fog = null; + + // set GL state for depth map + + _gl.clearColor( 1, 1, 1, 1 ); + _gl.disable( _gl.BLEND ); + + _renderer.setDepthTest( true ); + + // update scene + + if ( _renderer.autoUpdateScene ) scene.updateMatrixWorld(); + + // update camera matrices and frustum + + camera.matrixWorldInverse.getInverse( camera.matrixWorld ); + + _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); + _frustum.setFromMatrix( _projScreenMatrix ); + + // render depth map + + _renderer.setRenderTarget( this.renderTarget ); + _renderer.clear(); + + // set object matrices & frustum culling + + renderList = scene.__webglObjects; + + for ( j = 0, jl = renderList.length; j < jl; j ++ ) { + + webglObject = renderList[ j ]; + object = webglObject.object; + + webglObject.render = false; + + if ( object.visible ) { + + if ( ! ( object instanceof THREE.Mesh || object instanceof THREE.ParticleSystem ) || ! ( object.frustumCulled ) || _frustum.intersectsObject( object ) ) { + + object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); + + webglObject.render = true; + + } + + } + + } + + // render regular objects + + var objectMaterial, useMorphing, useSkinning; + + for ( j = 0, jl = renderList.length; j < jl; j ++ ) { + + webglObject = renderList[ j ]; + + if ( webglObject.render ) { + + object = webglObject.object; + buffer = webglObject.buffer; + + // todo: create proper depth material for particles + + if ( object instanceof THREE.ParticleSystem && !object.customDepthMaterial ) continue; + + objectMaterial = getObjectMaterial( object ); + + if ( objectMaterial ) _renderer.setMaterialFaces( object.material ); + + useMorphing = object.geometry.morphTargets.length > 0 && objectMaterial.morphTargets; + useSkinning = object instanceof THREE.SkinnedMesh && objectMaterial.skinning; + + if ( object.customDepthMaterial ) { + + material = object.customDepthMaterial; + + } else if ( useSkinning ) { + + material = useMorphing ? _depthMaterialMorphSkin : _depthMaterialSkin; + + } else if ( useMorphing ) { + + material = _depthMaterialMorph; + + } else { + + material = _depthMaterial; + + } + + if ( buffer instanceof THREE.BufferGeometry ) { + + _renderer.renderBufferDirect( camera, scene.__lights, fog, material, buffer, object ); + + } else { + + _renderer.renderBuffer( camera, scene.__lights, fog, material, buffer, object ); + + } + + } + + } + + // set matrices and render immediate objects + + renderList = scene.__webglObjectsImmediate; + + for ( j = 0, jl = renderList.length; j < jl; j ++ ) { + + webglObject = renderList[ j ]; + object = webglObject.object; + + if ( object.visible ) { + + object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); + + _renderer.renderImmediateObject( camera, scene.__lights, fog, _depthMaterial, object ); + + } + + } + + // restore GL state + + var clearColor = _renderer.getClearColor(), + clearAlpha = _renderer.getClearAlpha(); + + _gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearAlpha ); + _gl.enable( _gl.BLEND ); + + }; + + // For the moment just ignore objects that have multiple materials with different animation methods + // Only the first material will be taken into account for deciding which depth material to use + + function getObjectMaterial( object ) { + + return object.material instanceof THREE.MeshFaceMaterial + ? object.material.materials[ 0 ] + : object.material; + + }; + +}; + +/** + * @author mikael emtinger / http://gomo.se/ + * + */ + +THREE.ShaderFlares = { + + 'lensFlareVertexTexture': { + + vertexShader: [ + + "uniform lowp int renderType;", + + "uniform vec3 screenPosition;", + "uniform vec2 scale;", + "uniform float rotation;", + + "uniform sampler2D occlusionMap;", + + "attribute vec2 position;", + "attribute vec2 uv;", + + "varying vec2 vUV;", + "varying float vVisibility;", + + "void main() {", + + "vUV = uv;", + + "vec2 pos = position;", + + "if( renderType == 2 ) {", + + "vec4 visibility = texture2D( occlusionMap, vec2( 0.1, 0.1 ) ) +", + "texture2D( occlusionMap, vec2( 0.5, 0.1 ) ) +", + "texture2D( occlusionMap, vec2( 0.9, 0.1 ) ) +", + "texture2D( occlusionMap, vec2( 0.9, 0.5 ) ) +", + "texture2D( occlusionMap, vec2( 0.9, 0.9 ) ) +", + "texture2D( occlusionMap, vec2( 0.5, 0.9 ) ) +", + "texture2D( occlusionMap, vec2( 0.1, 0.9 ) ) +", + "texture2D( occlusionMap, vec2( 0.1, 0.5 ) ) +", + "texture2D( occlusionMap, vec2( 0.5, 0.5 ) );", + + "vVisibility = ( visibility.r / 9.0 ) *", + "( 1.0 - visibility.g / 9.0 ) *", + "( visibility.b / 9.0 ) *", + "( 1.0 - visibility.a / 9.0 );", + + "pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;", + "pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;", + + "}", + + "gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );", + + "}" + + ].join( "\n" ), + + fragmentShader: [ + + "uniform lowp int renderType;", + + "uniform sampler2D map;", + "uniform float opacity;", + "uniform vec3 color;", + + "varying vec2 vUV;", + "varying float vVisibility;", + + "void main() {", + + // pink square + + "if( renderType == 0 ) {", + + "gl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );", + + // restore + + "} else if( renderType == 1 ) {", + + "gl_FragColor = texture2D( map, vUV );", + + // flare + + "} else {", + + "vec4 texture = texture2D( map, vUV );", + "texture.a *= opacity * vVisibility;", + "gl_FragColor = texture;", + "gl_FragColor.rgb *= color;", + + "}", + + "}" + ].join( "\n" ) + + }, + + + 'lensFlare': { + + vertexShader: [ + + "uniform lowp int renderType;", + + "uniform vec3 screenPosition;", + "uniform vec2 scale;", + "uniform float rotation;", + + "attribute vec2 position;", + "attribute vec2 uv;", + + "varying vec2 vUV;", + + "void main() {", + + "vUV = uv;", + + "vec2 pos = position;", + + "if( renderType == 2 ) {", + + "pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;", + "pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;", + + "}", + + "gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );", + + "}" + + ].join( "\n" ), + + fragmentShader: [ + + "precision mediump float;", + + "uniform lowp int renderType;", + + "uniform sampler2D map;", + "uniform sampler2D occlusionMap;", + "uniform float opacity;", + "uniform vec3 color;", + + "varying vec2 vUV;", + + "void main() {", + + // pink square + + "if( renderType == 0 ) {", + + "gl_FragColor = vec4( texture2D( map, vUV ).rgb, 0.0 );", + + // restore + + "} else if( renderType == 1 ) {", + + "gl_FragColor = texture2D( map, vUV );", + + // flare + + "} else {", + + "float visibility = texture2D( occlusionMap, vec2( 0.5, 0.1 ) ).a +", + "texture2D( occlusionMap, vec2( 0.9, 0.5 ) ).a +", + "texture2D( occlusionMap, vec2( 0.5, 0.9 ) ).a +", + "texture2D( occlusionMap, vec2( 0.1, 0.5 ) ).a;", + + "visibility = ( 1.0 - visibility / 4.0 );", + + "vec4 texture = texture2D( map, vUV );", + "texture.a *= opacity * visibility;", + "gl_FragColor = texture;", + "gl_FragColor.rgb *= color;", + + "}", + + "}" + + ].join( "\n" ) + + } + +}; +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + * + */ + +THREE.ShaderSprite = { + + 'sprite': { + + vertexShader: [ + + "uniform int useScreenCoordinates;", + "uniform int sizeAttenuation;", + "uniform vec3 screenPosition;", + "uniform mat4 modelViewMatrix;", + "uniform mat4 projectionMatrix;", + "uniform float rotation;", + "uniform vec2 scale;", + "uniform vec2 alignment;", + "uniform vec2 uvOffset;", + "uniform vec2 uvScale;", + + "attribute vec2 position;", + "attribute vec2 uv;", + + "varying vec2 vUV;", + + "void main() {", + + "vUV = uvOffset + uv * uvScale;", + + "vec2 alignedPosition = position + alignment;", + + "vec2 rotatedPosition;", + "rotatedPosition.x = ( cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y ) * scale.x;", + "rotatedPosition.y = ( sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y ) * scale.y;", + + "vec4 finalPosition;", + + "if( useScreenCoordinates != 0 ) {", + + "finalPosition = vec4( screenPosition.xy + rotatedPosition, screenPosition.z, 1.0 );", + + "} else {", + + "finalPosition = projectionMatrix * modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );", + "finalPosition.xy += rotatedPosition * ( sizeAttenuation == 1 ? 1.0 : finalPosition.z );", + + "}", + + "gl_Position = finalPosition;", + + "}" + + ].join( "\n" ), + + fragmentShader: [ + + "uniform vec3 color;", + "uniform sampler2D map;", + "uniform float opacity;", + + "uniform int fogType;", + "uniform vec3 fogColor;", + "uniform float fogDensity;", + "uniform float fogNear;", + "uniform float fogFar;", + "uniform float alphaTest;", + + "varying vec2 vUV;", + + "void main() {", + + "vec4 texture = texture2D( map, vUV );", + + "if ( texture.a < alphaTest ) discard;", + + "gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );", + + "if ( fogType > 0 ) {", + + "float depth = gl_FragCoord.z / gl_FragCoord.w;", + "float fogFactor = 0.0;", + + "if ( fogType == 1 ) {", + + "fogFactor = smoothstep( fogNear, fogFar, depth );", + + "} else {", + + "const float LOG2 = 1.442695;", + "float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );", + "fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );", + + "}", + + "gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );", + + "}", + + "}" + + ].join( "\n" ) + + } + +}; \ No newline at end of file diff --git a/COGNET/lib/three.min.js b/COGNET/lib/three.min.js new file mode 100644 index 0000000000000000000000000000000000000000..c504d196cf6308fb27fed0ccf60620dccd7218f1 --- /dev/null +++ b/COGNET/lib/three.min.js @@ -0,0 +1,706 @@ +// three.js - http://github.com/mrdoob/three.js +'use strict';var THREE=THREE||{REVISION:"56"};self.console=self.console||{info:function(){},log:function(){},debug:function(){},warn:function(){},error:function(){}};self.Int32Array=self.Int32Array||Array;self.Float32Array=self.Float32Array||Array;String.prototype.trim=String.prototype.trim||function(){return this.replace(/^\s+|\s+$/g,"")}; +THREE.extend=function(a,b){if(Object.keys)for(var c=Object.keys(b),d=0,e=c.length;d<e;d++){var f=c[d];Object.defineProperty(a,f,Object.getOwnPropertyDescriptor(b,f))}else for(f in c={}.hasOwnProperty,b)c.call(b,f)&&(a[f]=b[f]);return a}; +(function(){for(var a=0,b=["ms","moz","webkit","o"],c=0;c<b.length&&!window.requestAnimationFrame;++c)window.requestAnimationFrame=window[b[c]+"RequestAnimationFrame"],window.cancelAnimationFrame=window[b[c]+"CancelAnimationFrame"]||window[b[c]+"CancelRequestAnimationFrame"];void 0===window.requestAnimationFrame&&(window.requestAnimationFrame=function(b){var c=Date.now(),f=Math.max(0,16-(c-a)),g=window.setTimeout(function(){b(c+f)},f);a=c+f;return g});window.cancelAnimationFrame=window.cancelAnimationFrame|| +function(a){window.clearTimeout(a)}})();THREE.CullFaceNone=0;THREE.CullFaceBack=1;THREE.CullFaceFront=2;THREE.CullFaceFrontBack=3;THREE.FrontFaceDirectionCW=0;THREE.FrontFaceDirectionCCW=1;THREE.BasicShadowMap=0;THREE.PCFShadowMap=1;THREE.PCFSoftShadowMap=2;THREE.FrontSide=0;THREE.BackSide=1;THREE.DoubleSide=2;THREE.NoShading=0;THREE.FlatShading=1;THREE.SmoothShading=2;THREE.NoColors=0;THREE.FaceColors=1;THREE.VertexColors=2;THREE.NoBlending=0;THREE.NormalBlending=1;THREE.AdditiveBlending=2; +THREE.SubtractiveBlending=3;THREE.MultiplyBlending=4;THREE.CustomBlending=5;THREE.AddEquation=100;THREE.SubtractEquation=101;THREE.ReverseSubtractEquation=102;THREE.ZeroFactor=200;THREE.OneFactor=201;THREE.SrcColorFactor=202;THREE.OneMinusSrcColorFactor=203;THREE.SrcAlphaFactor=204;THREE.OneMinusSrcAlphaFactor=205;THREE.DstAlphaFactor=206;THREE.OneMinusDstAlphaFactor=207;THREE.DstColorFactor=208;THREE.OneMinusDstColorFactor=209;THREE.SrcAlphaSaturateFactor=210;THREE.MultiplyOperation=0; +THREE.MixOperation=1;THREE.AddOperation=2;THREE.UVMapping=function(){};THREE.CubeReflectionMapping=function(){};THREE.CubeRefractionMapping=function(){};THREE.SphericalReflectionMapping=function(){};THREE.SphericalRefractionMapping=function(){};THREE.RepeatWrapping=1E3;THREE.ClampToEdgeWrapping=1001;THREE.MirroredRepeatWrapping=1002;THREE.NearestFilter=1003;THREE.NearestMipMapNearestFilter=1004;THREE.NearestMipMapLinearFilter=1005;THREE.LinearFilter=1006;THREE.LinearMipMapNearestFilter=1007; +THREE.LinearMipMapLinearFilter=1008;THREE.UnsignedByteType=1009;THREE.ByteType=1010;THREE.ShortType=1011;THREE.UnsignedShortType=1012;THREE.IntType=1013;THREE.UnsignedIntType=1014;THREE.FloatType=1015;THREE.UnsignedShort4444Type=1016;THREE.UnsignedShort5551Type=1017;THREE.UnsignedShort565Type=1018;THREE.AlphaFormat=1019;THREE.RGBFormat=1020;THREE.RGBAFormat=1021;THREE.LuminanceFormat=1022;THREE.LuminanceAlphaFormat=1023;THREE.RGB_S3TC_DXT1_Format=2001;THREE.RGBA_S3TC_DXT1_Format=2002; +THREE.RGBA_S3TC_DXT3_Format=2003;THREE.RGBA_S3TC_DXT5_Format=2004;THREE.Color=function(a){void 0!==a&&this.set(a);return this}; +THREE.extend(THREE.Color.prototype,{r:1,g:1,b:1,set:function(a){switch(typeof a){case "number":this.setHex(a);break;case "string":this.setStyle(a)}},setHex:function(a){a=Math.floor(a);this.r=(a>>16&255)/255;this.g=(a>>8&255)/255;this.b=(a&255)/255;return this},setRGB:function(a,b,c){this.r=a;this.g=b;this.b=c;return this},setHSV:function(a,b,c){console.log("DEPRECATED: Color's .setHSV() will be removed. Use .setHSL( h, s, l ) instead.");return this.setHSL(a,b*c/(1>(a=(2-b)*c)?a:2-a),a/2)},setHSL:function(a, +b,c){if(0===b)this.r=this.g=this.b=c;else{var d=function(a,b,c){0>c&&(c+=1);1<c&&(c-=1);return c<1/6?a+6*(b-a)*c:0.5>c?b:c<2/3?a+6*(b-a)*(2/3-c):a},b=0.5>=c?c*(1+b):c+b-c*b,c=2*c-b;this.r=d(c,b,a+1/3);this.g=d(c,b,a);this.b=d(c,b,a-1/3)}return this},setStyle:function(a){if(/^rgb\((\d+),(\d+),(\d+)\)$/i.test(a))return a=/^rgb\((\d+),(\d+),(\d+)\)$/i.exec(a),this.r=Math.min(255,parseInt(a[1],10))/255,this.g=Math.min(255,parseInt(a[2],10))/255,this.b=Math.min(255,parseInt(a[3],10))/255,this;if(/^rgb\((\d+)\%,(\d+)\%,(\d+)\%\)$/i.test(a))return a= +/^rgb\((\d+)\%,(\d+)\%,(\d+)\%\)$/i.exec(a),this.r=Math.min(100,parseInt(a[1],10))/100,this.g=Math.min(100,parseInt(a[2],10))/100,this.b=Math.min(100,parseInt(a[3],10))/100,this;if(/^\#([0-9a-f]{6})$/i.test(a))return a=/^\#([0-9a-f]{6})$/i.exec(a),this.setHex(parseInt(a[1],16)),this;if(/^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.test(a))return a=/^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec(a),this.setHex(parseInt(a[1]+a[1]+a[2]+a[2]+a[3]+a[3],16)),this;if(/^(\w+)$/i.test(a))return this.setHex(THREE.ColorKeywords[a]), +this},copy:function(a){this.r=a.r;this.g=a.g;this.b=a.b;return this},copyGammaToLinear:function(a){this.r=a.r*a.r;this.g=a.g*a.g;this.b=a.b*a.b;return this},copyLinearToGamma:function(a){this.r=Math.sqrt(a.r);this.g=Math.sqrt(a.g);this.b=Math.sqrt(a.b);return this},convertGammaToLinear:function(){var a=this.r,b=this.g,c=this.b;this.r=a*a;this.g=b*b;this.b=c*c;return this},convertLinearToGamma:function(){this.r=Math.sqrt(this.r);this.g=Math.sqrt(this.g);this.b=Math.sqrt(this.b);return this},getHex:function(){return 255* +this.r<<16^255*this.g<<8^255*this.b<<0},getHexString:function(){return("000000"+this.getHex().toString(16)).slice(-6)},getHSL:function(){var a={h:0,s:0,l:0};return function(){var b=this.r,c=this.g,d=this.b,e=Math.max(b,c,d),f=Math.min(b,c,d),g,h=(f+e)/2;if(f===e)f=g=0;else{var i=e-f,f=0.5>=h?i/(e+f):i/(2-e-f);switch(e){case b:g=(c-d)/i+(c<d?6:0);break;case c:g=(d-b)/i+2;break;case d:g=(b-c)/i+4}g/=6}a.h=g;a.s=f;a.l=h;return a}}(),getStyle:function(){return"rgb("+(255*this.r|0)+","+(255*this.g|0)+ +","+(255*this.b|0)+")"},offsetHSL:function(a,b,c){var d=this.getHSL();d.h+=a;d.s+=b;d.l+=c;this.setHSL(d.h,d.s,d.l);return this},add:function(a){this.r+=a.r;this.g+=a.g;this.b+=a.b;return this},addColors:function(a,b){this.r=a.r+b.r;this.g=a.g+b.g;this.b=a.b+b.b;return this},addScalar:function(a){this.r+=a;this.g+=a;this.b+=a;return this},multiply:function(a){this.r*=a.r;this.g*=a.g;this.b*=a.b;return this},multiplyScalar:function(a){this.r*=a;this.g*=a;this.b*=a;return this},lerp:function(a,b){this.r+= +(a.r-this.r)*b;this.g+=(a.g-this.g)*b;this.b+=(a.b-this.b)*b;return this},clone:function(){return(new THREE.Color).setRGB(this.r,this.g,this.b)}}); +THREE.ColorKeywords={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643, +darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055, +grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184, +lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130, +palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888, +tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074};THREE.Quaternion=function(a,b,c,d){this.x=a||0;this.y=b||0;this.z=c||0;this.w=void 0!==d?d:1}; +THREE.extend(THREE.Quaternion.prototype,{set:function(a,b,c,d){this.x=a;this.y=b;this.z=c;this.w=d;return this},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;this.w=a.w;return this},setFromEuler:function(a,b){var c=Math.cos(a.x/2),d=Math.cos(a.y/2),e=Math.cos(a.z/2),f=Math.sin(a.x/2),g=Math.sin(a.y/2),h=Math.sin(a.z/2);void 0===b||"XYZ"===b?(this.x=f*d*e+c*g*h,this.y=c*g*e-f*d*h,this.z=c*d*h+f*g*e,this.w=c*d*e-f*g*h):"YXZ"===b?(this.x=f*d*e+c*g*h,this.y=c*g*e-f*d*h,this.z=c*d*h-f*g*e,this.w=c* +d*e+f*g*h):"ZXY"===b?(this.x=f*d*e-c*g*h,this.y=c*g*e+f*d*h,this.z=c*d*h+f*g*e,this.w=c*d*e-f*g*h):"ZYX"===b?(this.x=f*d*e-c*g*h,this.y=c*g*e+f*d*h,this.z=c*d*h-f*g*e,this.w=c*d*e+f*g*h):"YZX"===b?(this.x=f*d*e+c*g*h,this.y=c*g*e+f*d*h,this.z=c*d*h-f*g*e,this.w=c*d*e-f*g*h):"XZY"===b&&(this.x=f*d*e-c*g*h,this.y=c*g*e-f*d*h,this.z=c*d*h+f*g*e,this.w=c*d*e+f*g*h);return this},setFromAxisAngle:function(a,b){var c=b/2,d=Math.sin(c);this.x=a.x*d;this.y=a.y*d;this.z=a.z*d;this.w=Math.cos(c);return this}, +setFromRotationMatrix:function(a){var b=a.elements,c=b[0],a=b[4],d=b[8],e=b[1],f=b[5],g=b[9],h=b[2],i=b[6],b=b[10],k=c+f+b;0<k?(c=0.5/Math.sqrt(k+1),this.w=0.25/c,this.x=(i-g)*c,this.y=(d-h)*c,this.z=(e-a)*c):c>f&&c>b?(c=2*Math.sqrt(1+c-f-b),this.w=(i-g)/c,this.x=0.25*c,this.y=(a+e)/c,this.z=(d+h)/c):f>b?(c=2*Math.sqrt(1+f-c-b),this.w=(d-h)/c,this.x=(a+e)/c,this.y=0.25*c,this.z=(g+i)/c):(c=2*Math.sqrt(1+b-c-f),this.w=(e-a)/c,this.x=(d+h)/c,this.y=(g+i)/c,this.z=0.25*c);return this},inverse:function(){this.conjugate().normalize(); +return this},conjugate:function(){this.x*=-1;this.y*=-1;this.z*=-1;return this},lengthSq:function(){return this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w)},normalize:function(){var a=this.length();0===a?(this.z=this.y=this.x=0,this.w=1):(a=1/a,this.x*=a,this.y*=a,this.z*=a,this.w*=a);return this},multiply:function(a,b){return void 0!==b?(console.warn("DEPRECATED: Quaternion's .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead."), +this.multiplyQuaternions(a,b)):this.multiplyQuaternions(this,a)},multiplyQuaternions:function(a,b){var c=a.x,d=a.y,e=a.z,f=a.w,g=b.x,h=b.y,i=b.z,k=b.w;this.x=c*k+f*g+d*i-e*h;this.y=d*k+f*h+e*g-c*i;this.z=e*k+f*i+c*h-d*g;this.w=f*k-c*g-d*h-e*i;return this},multiplyVector3:function(a){console.warn("DEPRECATED: Quaternion's .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.");return a.applyQuaternion(this)},slerp:function(a,b){var c=this.x,d=this.y,e=this.z, +f=this.w,g=f*a.w+c*a.x+d*a.y+e*a.z;0>g?(this.w=-a.w,this.x=-a.x,this.y=-a.y,this.z=-a.z,g=-g):this.copy(a);if(1<=g)return this.w=f,this.x=c,this.y=d,this.z=e,this;var h=Math.acos(g),i=Math.sqrt(1-g*g);if(0.001>Math.abs(i))return this.w=0.5*(f+this.w),this.x=0.5*(c+this.x),this.y=0.5*(d+this.y),this.z=0.5*(e+this.z),this;g=Math.sin((1-b)*h)/i;h=Math.sin(b*h)/i;this.w=f*g+this.w*h;this.x=c*g+this.x*h;this.y=d*g+this.y*h;this.z=e*g+this.z*h;return this},equals:function(a){return a.x===this.x&&a.y=== +this.y&&a.z===this.z&&a.w===this.w},clone:function(){return new THREE.Quaternion(this.x,this.y,this.z,this.w)}});THREE.Quaternion.slerp=function(a,b,c,d){return c.copy(a).slerp(b,d)};THREE.Vector2=function(a,b){this.x=a||0;this.y=b||0}; +THREE.extend(THREE.Vector2.prototype,{set:function(a,b){this.x=a;this.y=b;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;default:throw Error("index is out of range: "+a);}},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;default:throw Error("index is out of range: "+a);}},copy:function(a){this.x=a.x;this.y=a.y;return this},add:function(a,b){if(void 0!== +b)return console.warn("DEPRECATED: Vector2's .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;return this},addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;return this},addScalar:function(a){this.x+=a;this.y+=a;return this},sub:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector2's .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b);this.x-=a.x;this.y-=a.y;return this}, +subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;return this},divideScalar:function(a){0!==a?(this.x/=a,this.y/=a):this.set(0,0);return this},min:function(a){this.x>a.x&&(this.x=a.x);this.y>a.y&&(this.y=a.y);return this},max:function(a){this.x<a.x&&(this.x=a.x);this.y<a.y&&(this.y=a.y);return this},clamp:function(a,b){this.x<a.x?this.x=a.x:this.x>b.x&&(this.x=b.x);this.y<a.y?this.y=a.y:this.y>b.y&&(this.y=b.y);return this},negate:function(){return this.multiplyScalar(-1)}, +dot:function(a){return this.x*a.x+this.y*a.y},lengthSq:function(){return this.x*this.x+this.y*this.y},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y)},normalize:function(){return this.divideScalar(this.length())},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){var b=this.x-a.x,a=this.y-a.y;return b*b+a*a},setLength:function(a){var b=this.length();0!==b&&a!==b&&this.multiplyScalar(a/b);return this},lerp:function(a,b){this.x+=(a.x-this.x)* +b;this.y+=(a.y-this.y)*b;return this},equals:function(a){return a.x===this.x&&a.y===this.y},toArray:function(){return[this.x,this.y]},clone:function(){return new THREE.Vector2(this.x,this.y)}});THREE.Vector3=function(a,b,c){this.x=a||0;this.y=b||0;this.z=c||0}; +THREE.extend(THREE.Vector3.prototype,{set:function(a,b,c){this.x=a;this.y=b;this.z=c;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setZ:function(a){this.z=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;case 2:this.z=b;break;default:throw Error("index is out of range: "+a);}},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:throw Error("index is out of range: "+ +a);}},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;return this},add:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector3's .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;this.z+=a.z;return this},addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;return this},addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;this.z=a.z+b.z;return this},sub:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector3's .sub() now only accepts one argument. Use .subVectors( a, b ) instead."), +this.subVectors(a,b);this.x-=a.x;this.y-=a.y;this.z-=a.z;return this},subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;this.z=a.z-b.z;return this},multiply:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector3's .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead."),this.multiplyVectors(a,b);this.x*=a.x;this.y*=a.y;this.z*=a.z;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;this.z*=a;return this},multiplyVectors:function(a,b){this.x=a.x* +b.x;this.y=a.y*b.y;this.z=a.z*b.z;return this},applyMatrix3:function(a){var b=this.x,c=this.y,d=this.z,a=a.elements;this.x=a[0]*b+a[3]*c+a[6]*d;this.y=a[1]*b+a[4]*c+a[7]*d;this.z=a[2]*b+a[5]*c+a[8]*d;return this},applyMatrix4:function(a){var b=this.x,c=this.y,d=this.z,a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d+a[12];this.y=a[1]*b+a[5]*c+a[9]*d+a[13];this.z=a[2]*b+a[6]*c+a[10]*d+a[14];return this},applyProjection:function(a){var b=this.x,c=this.y,d=this.z,a=a.elements,e=1/(a[3]*b+a[7]*c+a[11]*d+a[15]); +this.x=(a[0]*b+a[4]*c+a[8]*d+a[12])*e;this.y=(a[1]*b+a[5]*c+a[9]*d+a[13])*e;this.z=(a[2]*b+a[6]*c+a[10]*d+a[14])*e;return this},applyQuaternion:function(a){var b=this.x,c=this.y,d=this.z,e=a.x,f=a.y,g=a.z,a=a.w,h=a*b+f*d-g*c,i=a*c+g*b-e*d,k=a*d+e*c-f*b,b=-e*b-f*c-g*d;this.x=h*a+b*-e+i*-g-k*-f;this.y=i*a+b*-f+k*-e-h*-g;this.z=k*a+b*-g+h*-f-i*-e;return this},applyEuler:function(){var a=new THREE.Quaternion;return function(b,c){var d=a.setFromEuler(b,c);this.applyQuaternion(d);return this}}(),applyAxisAngle:function(){var a= +new THREE.Quaternion;return function(b,c){var d=a.setFromAxisAngle(b,c);this.applyQuaternion(d);return this}}(),transformDirection:function(a){var b=this.x,c=this.y,d=this.z,a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d;this.y=a[1]*b+a[5]*c+a[9]*d;this.z=a[2]*b+a[6]*c+a[10]*d;this.normalize();return this},divide:function(a){this.x/=a.x;this.y/=a.y;this.z/=a.z;return this},divideScalar:function(a){0!==a?(this.x/=a,this.y/=a,this.z/=a):this.z=this.y=this.x=0;return this},min:function(a){this.x>a.x&&(this.x= +a.x);this.y>a.y&&(this.y=a.y);this.z>a.z&&(this.z=a.z);return this},max:function(a){this.x<a.x&&(this.x=a.x);this.y<a.y&&(this.y=a.y);this.z<a.z&&(this.z=a.z);return this},clamp:function(a,b){this.x<a.x?this.x=a.x:this.x>b.x&&(this.x=b.x);this.y<a.y?this.y=a.y:this.y>b.y&&(this.y=b.y);this.z<a.z?this.z=a.z:this.z>b.z&&(this.z=b.z);return this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.z},lengthSq:function(){return this.x*this.x+this.y* +this.y+this.z*this.z},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)},lengthManhattan:function(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)},normalize:function(){return this.divideScalar(this.length())},setLength:function(a){var b=this.length();0!==b&&a!==b&&this.multiplyScalar(a/b);return this},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;this.z+=(a.z-this.z)*b;return this},cross:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector3's .cross() now only accepts one argument. Use .crossVectors( a, b ) instead."), +this.crossVectors(a,b);var c=this.x,d=this.y,e=this.z;this.x=d*a.z-e*a.y;this.y=e*a.x-c*a.z;this.z=c*a.y-d*a.x;return this},crossVectors:function(a,b){this.x=a.y*b.z-a.z*b.y;this.y=a.z*b.x-a.x*b.z;this.z=a.x*b.y-a.y*b.x;return this},projectOnVector:function(){var a=new THREE.Vector3;return function(b){a.copy(b).normalize();b=this.dot(a);return this.copy(a).multiplyScalar(b)}}(),projectOnPlane:function(){var a=new THREE.Vector3;return function(b){a.copy(this).projectOnVector(b);return this.sub(a)}}(), +reflect:function(){var a=new THREE.Vector3;return function(b){a.copy(this).projectOnVector(b).multiplyScalar(2);return this.subVectors(a,this)}}(),angleTo:function(a){a=this.dot(a)/(this.length()*a.length());return Math.acos(THREE.Math.clamp(a,-1,1))},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){var b=this.x-a.x,c=this.y-a.y,a=this.z-a.z;return b*b+c*c+a*a},getPositionFromMatrix:function(a){this.x=a.elements[12];this.y=a.elements[13];this.z=a.elements[14]; +return this},setEulerFromRotationMatrix:function(a,b){function c(a){return Math.min(Math.max(a,-1),1)}var d=a.elements,e=d[0],f=d[4],g=d[8],h=d[1],i=d[5],k=d[9],l=d[2],m=d[6],d=d[10];void 0===b||"XYZ"===b?(this.y=Math.asin(c(g)),0.99999>Math.abs(g)?(this.x=Math.atan2(-k,d),this.z=Math.atan2(-f,e)):(this.x=Math.atan2(m,i),this.z=0)):"YXZ"===b?(this.x=Math.asin(-c(k)),0.99999>Math.abs(k)?(this.y=Math.atan2(g,d),this.z=Math.atan2(h,i)):(this.y=Math.atan2(-l,e),this.z=0)):"ZXY"===b?(this.x=Math.asin(c(m)), +0.99999>Math.abs(m)?(this.y=Math.atan2(-l,d),this.z=Math.atan2(-f,i)):(this.y=0,this.z=Math.atan2(h,e))):"ZYX"===b?(this.y=Math.asin(-c(l)),0.99999>Math.abs(l)?(this.x=Math.atan2(m,d),this.z=Math.atan2(h,e)):(this.x=0,this.z=Math.atan2(-f,i))):"YZX"===b?(this.z=Math.asin(c(h)),0.99999>Math.abs(h)?(this.x=Math.atan2(-k,i),this.y=Math.atan2(-l,e)):(this.x=0,this.y=Math.atan2(g,d))):"XZY"===b&&(this.z=Math.asin(-c(f)),0.99999>Math.abs(f)?(this.x=Math.atan2(m,i),this.y=Math.atan2(g,e)):(this.x=Math.atan2(-k, +d),this.y=0));return this},setEulerFromQuaternion:function(a,b){function c(a){return Math.min(Math.max(a,-1),1)}var d=a.x*a.x,e=a.y*a.y,f=a.z*a.z,g=a.w*a.w;void 0===b||"XYZ"===b?(this.x=Math.atan2(2*(a.x*a.w-a.y*a.z),g-d-e+f),this.y=Math.asin(c(2*(a.x*a.z+a.y*a.w))),this.z=Math.atan2(2*(a.z*a.w-a.x*a.y),g+d-e-f)):"YXZ"===b?(this.x=Math.asin(c(2*(a.x*a.w-a.y*a.z))),this.y=Math.atan2(2*(a.x*a.z+a.y*a.w),g-d-e+f),this.z=Math.atan2(2*(a.x*a.y+a.z*a.w),g-d+e-f)):"ZXY"===b?(this.x=Math.asin(c(2*(a.x*a.w+ +a.y*a.z))),this.y=Math.atan2(2*(a.y*a.w-a.z*a.x),g-d-e+f),this.z=Math.atan2(2*(a.z*a.w-a.x*a.y),g-d+e-f)):"ZYX"===b?(this.x=Math.atan2(2*(a.x*a.w+a.z*a.y),g-d-e+f),this.y=Math.asin(c(2*(a.y*a.w-a.x*a.z))),this.z=Math.atan2(2*(a.x*a.y+a.z*a.w),g+d-e-f)):"YZX"===b?(this.x=Math.atan2(2*(a.x*a.w-a.z*a.y),g-d+e-f),this.y=Math.atan2(2*(a.y*a.w-a.x*a.z),g+d-e-f),this.z=Math.asin(c(2*(a.x*a.y+a.z*a.w)))):"XZY"===b&&(this.x=Math.atan2(2*(a.x*a.w+a.y*a.z),g-d+e-f),this.y=Math.atan2(2*(a.x*a.z+a.y*a.w),g+d- +e-f),this.z=Math.asin(c(2*(a.z*a.w-a.x*a.y))));return this},getScaleFromMatrix:function(a){var b=this.set(a.elements[0],a.elements[1],a.elements[2]).length(),c=this.set(a.elements[4],a.elements[5],a.elements[6]).length(),a=this.set(a.elements[8],a.elements[9],a.elements[10]).length();this.x=b;this.y=c;this.z=a;return this},equals:function(a){return a.x===this.x&&a.y===this.y&&a.z===this.z},toArray:function(){return[this.x,this.y,this.z]},clone:function(){return new THREE.Vector3(this.x,this.y,this.z)}});THREE.Vector4=function(a,b,c,d){this.x=a||0;this.y=b||0;this.z=c||0;this.w=void 0!==d?d:1}; +THREE.extend(THREE.Vector4.prototype,{set:function(a,b,c,d){this.x=a;this.y=b;this.z=c;this.w=d;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setZ:function(a){this.z=a;return this},setW:function(a){this.w=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;case 2:this.z=b;break;case 3:this.w=b;break;default:throw Error("index is out of range: "+a);}},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y; +case 2:return this.z;case 3:return this.w;default:throw Error("index is out of range: "+a);}},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;this.w=void 0!==a.w?a.w:1;return this},add:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector4's .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;this.z+=a.z;this.w+=a.w;return this},addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;this.w+=a;return this},addVectors:function(a, +b){this.x=a.x+b.x;this.y=a.y+b.y;this.z=a.z+b.z;this.w=a.w+b.w;return this},sub:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector4's .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b);this.x-=a.x;this.y-=a.y;this.z-=a.z;this.w-=a.w;return this},subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;this.z=a.z-b.z;this.w=a.w-b.w;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;this.z*=a;this.w*=a;return this},applyMatrix4:function(a){var b= +this.x,c=this.y,d=this.z,e=this.w,a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d+a[12]*e;this.y=a[1]*b+a[5]*c+a[9]*d+a[13]*e;this.z=a[2]*b+a[6]*c+a[10]*d+a[14]*e;this.w=a[3]*b+a[7]*c+a[11]*d+a[15]*e;return this},divideScalar:function(a){0!==a?(this.x/=a,this.y/=a,this.z/=a,this.w/=a):(this.z=this.y=this.x=0,this.w=1);return this},setAxisAngleFromQuaternion:function(a){this.w=2*Math.acos(a.w);var b=Math.sqrt(1-a.w*a.w);1E-4>b?(this.x=1,this.z=this.y=0):(this.x=a.x/b,this.y=a.y/b,this.z=a.z/b);return this}, +setAxisAngleFromRotationMatrix:function(a){var b,c,d,a=a.elements,e=a[0];d=a[4];var f=a[8],g=a[1],h=a[5],i=a[9];c=a[2];b=a[6];var k=a[10];if(0.01>Math.abs(d-g)&&0.01>Math.abs(f-c)&&0.01>Math.abs(i-b)){if(0.1>Math.abs(d+g)&&0.1>Math.abs(f+c)&&0.1>Math.abs(i+b)&&0.1>Math.abs(e+h+k-3))return this.set(1,0,0,0),this;a=Math.PI;e=(e+1)/2;h=(h+1)/2;k=(k+1)/2;d=(d+g)/4;f=(f+c)/4;i=(i+b)/4;e>h&&e>k?0.01>e?(b=0,d=c=0.707106781):(b=Math.sqrt(e),c=d/b,d=f/b):h>k?0.01>h?(b=0.707106781,c=0,d=0.707106781):(c=Math.sqrt(h), +b=d/c,d=i/c):0.01>k?(c=b=0.707106781,d=0):(d=Math.sqrt(k),b=f/d,c=i/d);this.set(b,c,d,a);return this}a=Math.sqrt((b-i)*(b-i)+(f-c)*(f-c)+(g-d)*(g-d));0.001>Math.abs(a)&&(a=1);this.x=(b-i)/a;this.y=(f-c)/a;this.z=(g-d)/a;this.w=Math.acos((e+h+k-1)/2);return this},min:function(a){this.x>a.x&&(this.x=a.x);this.y>a.y&&(this.y=a.y);this.z>a.z&&(this.z=a.z);this.w>a.w&&(this.w=a.w);return this},max:function(a){this.x<a.x&&(this.x=a.x);this.y<a.y&&(this.y=a.y);this.z<a.z&&(this.z=a.z);this.w<a.w&&(this.w= +a.w);return this},clamp:function(a,b){this.x<a.x?this.x=a.x:this.x>b.x&&(this.x=b.x);this.y<a.y?this.y=a.y:this.y>b.y&&(this.y=b.y);this.z<a.z?this.z=a.z:this.z>b.z&&(this.z=b.z);this.w<a.w?this.w=a.w:this.w>b.w&&(this.w=b.w);return this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.z+this.w*a.w},lengthSq:function(){return this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+ +this.z*this.z+this.w*this.w)},lengthManhattan:function(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)+Math.abs(this.w)},normalize:function(){return this.divideScalar(this.length())},setLength:function(a){var b=this.length();0!==b&&a!==b&&this.multiplyScalar(a/b);return this},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;this.z+=(a.z-this.z)*b;this.w+=(a.w-this.w)*b;return this},equals:function(a){return a.x===this.x&&a.y===this.y&&a.z===this.z&&a.w===this.w},toArray:function(){return[this.x, +this.y,this.z,this.w]},clone:function(){return new THREE.Vector4(this.x,this.y,this.z,this.w)}});THREE.Line3=function(a,b){this.start=void 0!==a?a:new THREE.Vector3;this.end=void 0!==b?b:new THREE.Vector3}; +THREE.extend(THREE.Line3.prototype,{set:function(a,b){this.start.copy(a);this.end.copy(b);return this},copy:function(a){this.start.copy(a.start);this.end.copy(a.end);return this},center:function(a){return(a||new THREE.Vector3).addVectors(this.start,this.end).multiplyScalar(0.5)},delta:function(a){return(a||new THREE.Vector3).subVectors(this.end,this.start)},distanceSq:function(){return this.start.distanceToSquared(this.end)},distance:function(){return this.start.distanceTo(this.end)},at:function(a, +b){var c=b||new THREE.Vector3;return this.delta(c).multiplyScalar(a).add(this.start)},closestPointToPointParameter:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(c,d){a.subVectors(c,this.start);b.subVectors(this.end,this.start);var e=b.dot(b),e=b.dot(a)/e;d&&(e=THREE.Math.clamp(e,0,1));return e}}(),closestPointToPoint:function(a,b,c){a=this.closestPointToPointParameter(a,b);c=c||new THREE.Vector3;return this.delta(c).multiplyScalar(a).add(this.start)},applyMatrix4:function(a){this.start.applyMatrix4(a); +this.end.applyMatrix4(a);return this},equals:function(a){return a.start.equals(this.start)&&a.end.equals(this.end)},clone:function(){return(new THREE.Line3).copy(this)}});THREE.Box2=function(a,b){this.min=void 0!==a?a:new THREE.Vector2(Infinity,Infinity);this.max=void 0!==b?b:new THREE.Vector2(-Infinity,-Infinity)}; +THREE.extend(THREE.Box2.prototype,{set:function(a,b){this.min.copy(a);this.max.copy(b);return this},setFromPoints:function(a){if(0<a.length){var b=a[0];this.min.copy(b);this.max.copy(b);for(var c=1,d=a.length;c<d;c++)b=a[c],b.x<this.min.x?this.min.x=b.x:b.x>this.max.x&&(this.max.x=b.x),b.y<this.min.y?this.min.y=b.y:b.y>this.max.y&&(this.max.y=b.y)}else this.makeEmpty();return this},setFromCenterAndSize:function(){var a=new THREE.Vector2;return function(b,c){var d=a.copy(c).multiplyScalar(0.5);this.min.copy(b).sub(d); +this.max.copy(b).add(d);return this}}(),copy:function(a){this.min.copy(a.min);this.max.copy(a.max);return this},makeEmpty:function(){this.min.x=this.min.y=Infinity;this.max.x=this.max.y=-Infinity;return this},empty:function(){return this.max.x<this.min.x||this.max.y<this.min.y},center:function(a){return(a||new THREE.Vector2).addVectors(this.min,this.max).multiplyScalar(0.5)},size:function(a){return(a||new THREE.Vector2).subVectors(this.max,this.min)},expandByPoint:function(a){this.min.min(a);this.max.max(a); +return this},expandByVector:function(a){this.min.sub(a);this.max.add(a);return this},expandByScalar:function(a){this.min.addScalar(-a);this.max.addScalar(a);return this},containsPoint:function(a){return a.x<this.min.x||a.x>this.max.x||a.y<this.min.y||a.y>this.max.y?!1:!0},containsBox:function(a){return this.min.x<=a.min.x&&a.max.x<=this.max.x&&this.min.y<=a.min.y&&a.max.y<=this.max.y?!0:!1},getParameter:function(a){return new THREE.Vector2((a.x-this.min.x)/(this.max.x-this.min.x),(a.y-this.min.y)/ +(this.max.y-this.min.y))},isIntersectionBox:function(a){return a.max.x<this.min.x||a.min.x>this.max.x||a.max.y<this.min.y||a.min.y>this.max.y?!1:!0},clampPoint:function(a,b){return(b||new THREE.Vector2).copy(a).clamp(this.min,this.max)},distanceToPoint:function(){var a=new THREE.Vector2;return function(b){return a.copy(b).clamp(this.min,this.max).sub(b).length()}}(),intersect:function(a){this.min.max(a.min);this.max.min(a.max);return this},union:function(a){this.min.min(a.min);this.max.max(a.max); +return this},translate:function(a){this.min.add(a);this.max.add(a);return this},equals:function(a){return a.min.equals(this.min)&&a.max.equals(this.max)},clone:function(){return(new THREE.Box2).copy(this)}});THREE.Box3=function(a,b){this.min=void 0!==a?a:new THREE.Vector3(Infinity,Infinity,Infinity);this.max=void 0!==b?b:new THREE.Vector3(-Infinity,-Infinity,-Infinity)}; +THREE.extend(THREE.Box3.prototype,{set:function(a,b){this.min.copy(a);this.max.copy(b);return this},setFromPoints:function(a){if(0<a.length){var b=a[0];this.min.copy(b);this.max.copy(b);for(var c=1,d=a.length;c<d;c++)b=a[c],b.x<this.min.x?this.min.x=b.x:b.x>this.max.x&&(this.max.x=b.x),b.y<this.min.y?this.min.y=b.y:b.y>this.max.y&&(this.max.y=b.y),b.z<this.min.z?this.min.z=b.z:b.z>this.max.z&&(this.max.z=b.z)}else this.makeEmpty();return this},setFromCenterAndSize:function(){var a=new THREE.Vector3; +return function(b,c){var d=a.copy(c).multiplyScalar(0.5);this.min.copy(b).sub(d);this.max.copy(b).add(d);return this}}(),copy:function(a){this.min.copy(a.min);this.max.copy(a.max);return this},makeEmpty:function(){this.min.x=this.min.y=this.min.z=Infinity;this.max.x=this.max.y=this.max.z=-Infinity;return this},empty:function(){return this.max.x<this.min.x||this.max.y<this.min.y||this.max.z<this.min.z},center:function(a){return(a||new THREE.Vector3).addVectors(this.min,this.max).multiplyScalar(0.5)}, +size:function(a){return(a||new THREE.Vector3).subVectors(this.max,this.min)},expandByPoint:function(a){this.min.min(a);this.max.max(a);return this},expandByVector:function(a){this.min.sub(a);this.max.add(a);return this},expandByScalar:function(a){this.min.addScalar(-a);this.max.addScalar(a);return this},containsPoint:function(a){return a.x<this.min.x||a.x>this.max.x||a.y<this.min.y||a.y>this.max.y||a.z<this.min.z||a.z>this.max.z?!1:!0},containsBox:function(a){return this.min.x<=a.min.x&&a.max.x<= +this.max.x&&this.min.y<=a.min.y&&a.max.y<=this.max.y&&this.min.z<=a.min.z&&a.max.z<=this.max.z?!0:!1},getParameter:function(a){return new THREE.Vector3((a.x-this.min.x)/(this.max.x-this.min.x),(a.y-this.min.y)/(this.max.y-this.min.y),(a.z-this.min.z)/(this.max.z-this.min.z))},isIntersectionBox:function(a){return a.max.x<this.min.x||a.min.x>this.max.x||a.max.y<this.min.y||a.min.y>this.max.y||a.max.z<this.min.z||a.min.z>this.max.z?!1:!0},clampPoint:function(a,b){return(b||new THREE.Vector3).copy(a).clamp(this.min, +this.max)},distanceToPoint:function(){var a=new THREE.Vector3;return function(b){return a.copy(b).clamp(this.min,this.max).sub(b).length()}}(),getBoundingSphere:function(){var a=new THREE.Vector3;return function(b){b=b||new THREE.Sphere;b.center=this.center();b.radius=0.5*this.size(a).length();return b}}(),intersect:function(a){this.min.max(a.min);this.max.min(a.max);return this},union:function(a){this.min.min(a.min);this.max.max(a.max);return this},applyMatrix4:function(){var a=[new THREE.Vector3, +new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3];return function(b){a[0].set(this.min.x,this.min.y,this.min.z).applyMatrix4(b);a[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(b);a[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(b);a[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(b);a[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(b);a[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(b);a[6].set(this.max.x, +this.max.y,this.min.z).applyMatrix4(b);a[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(b);this.makeEmpty();this.setFromPoints(a);return this}}(),translate:function(a){this.min.add(a);this.max.add(a);return this},equals:function(a){return a.min.equals(this.min)&&a.max.equals(this.max)},clone:function(){return(new THREE.Box3).copy(this)}});THREE.Matrix3=function(a,b,c,d,e,f,g,h,i){this.elements=new Float32Array(9);this.set(void 0!==a?a:1,b||0,c||0,d||0,void 0!==e?e:1,f||0,g||0,h||0,void 0!==i?i:1)}; +THREE.extend(THREE.Matrix3.prototype,{set:function(a,b,c,d,e,f,g,h,i){var k=this.elements;k[0]=a;k[3]=b;k[6]=c;k[1]=d;k[4]=e;k[7]=f;k[2]=g;k[5]=h;k[8]=i;return this},identity:function(){this.set(1,0,0,0,1,0,0,0,1);return this},copy:function(a){a=a.elements;this.set(a[0],a[3],a[6],a[1],a[4],a[7],a[2],a[5],a[8]);return this},multiplyVector3:function(a){console.warn("DEPRECATED: Matrix3's .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.");return a.applyMatrix3(this)},multiplyVector3Array:function(){var a= +new THREE.Vector3;return function(b){for(var c=0,d=b.length;c<d;c+=3)a.x=b[c],a.y=b[c+1],a.z=b[c+2],a.applyMatrix3(this),b[c]=a.x,b[c+1]=a.y,b[c+2]=a.z;return b}}(),multiplyScalar:function(a){var b=this.elements;b[0]*=a;b[3]*=a;b[6]*=a;b[1]*=a;b[4]*=a;b[7]*=a;b[2]*=a;b[5]*=a;b[8]*=a;return this},determinant:function(){var a=this.elements,b=a[0],c=a[1],d=a[2],e=a[3],f=a[4],g=a[5],h=a[6],i=a[7],a=a[8];return b*f*a-b*g*i-c*e*a+c*g*h+d*e*i-d*f*h},getInverse:function(a,b){var c=a.elements,d=this.elements; +d[0]=c[10]*c[5]-c[6]*c[9];d[1]=-c[10]*c[1]+c[2]*c[9];d[2]=c[6]*c[1]-c[2]*c[5];d[3]=-c[10]*c[4]+c[6]*c[8];d[4]=c[10]*c[0]-c[2]*c[8];d[5]=-c[6]*c[0]+c[2]*c[4];d[6]=c[9]*c[4]-c[5]*c[8];d[7]=-c[9]*c[0]+c[1]*c[8];d[8]=c[5]*c[0]-c[1]*c[4];c=c[0]*d[0]+c[1]*d[3]+c[2]*d[6];if(0===c){if(b)throw Error("Matrix3.getInverse(): can't invert matrix, determinant is 0");console.warn("Matrix3.getInverse(): can't invert matrix, determinant is 0");this.identity();return this}this.multiplyScalar(1/c);return this},transpose:function(){var a, +b=this.elements;a=b[1];b[1]=b[3];b[3]=a;a=b[2];b[2]=b[6];b[6]=a;a=b[5];b[5]=b[7];b[7]=a;return this},getNormalMatrix:function(a){this.getInverse(a).transpose();return this},transposeIntoArray:function(a){var b=this.elements;a[0]=b[0];a[1]=b[3];a[2]=b[6];a[3]=b[1];a[4]=b[4];a[5]=b[7];a[6]=b[2];a[7]=b[5];a[8]=b[8];return this},clone:function(){var a=this.elements;return new THREE.Matrix3(a[0],a[3],a[6],a[1],a[4],a[7],a[2],a[5],a[8])}});THREE.Matrix4=function(a,b,c,d,e,f,g,h,i,k,l,m,n,s,r,p){var q=this.elements=new Float32Array(16);q[0]=void 0!==a?a:1;q[4]=b||0;q[8]=c||0;q[12]=d||0;q[1]=e||0;q[5]=void 0!==f?f:1;q[9]=g||0;q[13]=h||0;q[2]=i||0;q[6]=k||0;q[10]=void 0!==l?l:1;q[14]=m||0;q[3]=n||0;q[7]=s||0;q[11]=r||0;q[15]=void 0!==p?p:1}; +THREE.extend(THREE.Matrix4.prototype,{set:function(a,b,c,d,e,f,g,h,i,k,l,m,n,s,r,p){var q=this.elements;q[0]=a;q[4]=b;q[8]=c;q[12]=d;q[1]=e;q[5]=f;q[9]=g;q[13]=h;q[2]=i;q[6]=k;q[10]=l;q[14]=m;q[3]=n;q[7]=s;q[11]=r;q[15]=p;return this},identity:function(){this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1);return this},copy:function(a){a=a.elements;this.set(a[0],a[4],a[8],a[12],a[1],a[5],a[9],a[13],a[2],a[6],a[10],a[14],a[3],a[7],a[11],a[15]);return this},setRotationFromEuler:function(a,b){var c=this.elements, +d=a.x,e=a.y,f=a.z,g=Math.cos(d),d=Math.sin(d),h=Math.cos(e),e=Math.sin(e),i=Math.cos(f),f=Math.sin(f);if(void 0===b||"XYZ"===b){var k=g*i,l=g*f,m=d*i,n=d*f;c[0]=h*i;c[4]=-h*f;c[8]=e;c[1]=l+m*e;c[5]=k-n*e;c[9]=-d*h;c[2]=n-k*e;c[6]=m+l*e;c[10]=g*h}else"YXZ"===b?(k=h*i,l=h*f,m=e*i,n=e*f,c[0]=k+n*d,c[4]=m*d-l,c[8]=g*e,c[1]=g*f,c[5]=g*i,c[9]=-d,c[2]=l*d-m,c[6]=n+k*d,c[10]=g*h):"ZXY"===b?(k=h*i,l=h*f,m=e*i,n=e*f,c[0]=k-n*d,c[4]=-g*f,c[8]=m+l*d,c[1]=l+m*d,c[5]=g*i,c[9]=n-k*d,c[2]=-g*e,c[6]=d,c[10]=g*h): +"ZYX"===b?(k=g*i,l=g*f,m=d*i,n=d*f,c[0]=h*i,c[4]=m*e-l,c[8]=k*e+n,c[1]=h*f,c[5]=n*e+k,c[9]=l*e-m,c[2]=-e,c[6]=d*h,c[10]=g*h):"YZX"===b?(k=g*h,l=g*e,m=d*h,n=d*e,c[0]=h*i,c[4]=n-k*f,c[8]=m*f+l,c[1]=f,c[5]=g*i,c[9]=-d*i,c[2]=-e*i,c[6]=l*f+m,c[10]=k-n*f):"XZY"===b&&(k=g*h,l=g*e,m=d*h,n=d*e,c[0]=h*i,c[4]=-f,c[8]=e*i,c[1]=k*f+n,c[5]=g*i,c[9]=l*f-m,c[2]=m*f-l,c[6]=d*i,c[10]=n*f+k);return this},setRotationFromQuaternion:function(a){var b=this.elements,c=a.x,d=a.y,e=a.z,f=a.w,g=c+c,h=d+d,i=e+e,a=c*g,k=c*h, +c=c*i,l=d*h,d=d*i,e=e*i,g=f*g,h=f*h,f=f*i;b[0]=1-(l+e);b[4]=k-f;b[8]=c+h;b[1]=k+f;b[5]=1-(a+e);b[9]=d-g;b[2]=c-h;b[6]=d+g;b[10]=1-(a+l);return this},lookAt:function(){var a=new THREE.Vector3,b=new THREE.Vector3,c=new THREE.Vector3;return function(d,e,f){var g=this.elements;c.subVectors(d,e).normalize();0===c.length()&&(c.z=1);a.crossVectors(f,c).normalize();0===a.length()&&(c.x+=1E-4,a.crossVectors(f,c).normalize());b.crossVectors(c,a);g[0]=a.x;g[4]=b.x;g[8]=c.x;g[1]=a.y;g[5]=b.y;g[9]=c.y;g[2]=a.z; +g[6]=b.z;g[10]=c.z;return this}}(),multiply:function(a,b){return void 0!==b?(console.warn("DEPRECATED: Matrix4's .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead."),this.multiplyMatrices(a,b)):this.multiplyMatrices(this,a)},multiplyMatrices:function(a,b){var c=a.elements,d=b.elements,e=this.elements,f=c[0],g=c[4],h=c[8],i=c[12],k=c[1],l=c[5],m=c[9],n=c[13],s=c[2],r=c[6],p=c[10],q=c[14],y=c[3],v=c[7],z=c[11],c=c[15],t=d[0],A=d[4],I=d[8],C=d[12],x=d[1],G=d[5],J=d[9], +E=d[13],H=d[2],B=d[6],W=d[10],F=d[14],K=d[3],L=d[7],U=d[11],d=d[15];e[0]=f*t+g*x+h*H+i*K;e[4]=f*A+g*G+h*B+i*L;e[8]=f*I+g*J+h*W+i*U;e[12]=f*C+g*E+h*F+i*d;e[1]=k*t+l*x+m*H+n*K;e[5]=k*A+l*G+m*B+n*L;e[9]=k*I+l*J+m*W+n*U;e[13]=k*C+l*E+m*F+n*d;e[2]=s*t+r*x+p*H+q*K;e[6]=s*A+r*G+p*B+q*L;e[10]=s*I+r*J+p*W+q*U;e[14]=s*C+r*E+p*F+q*d;e[3]=y*t+v*x+z*H+c*K;e[7]=y*A+v*G+z*B+c*L;e[11]=y*I+v*J+z*W+c*U;e[15]=y*C+v*E+z*F+c*d;return this},multiplyToArray:function(a,b,c){var d=this.elements;this.multiplyMatrices(a,b); +c[0]=d[0];c[1]=d[1];c[2]=d[2];c[3]=d[3];c[4]=d[4];c[5]=d[5];c[6]=d[6];c[7]=d[7];c[8]=d[8];c[9]=d[9];c[10]=d[10];c[11]=d[11];c[12]=d[12];c[13]=d[13];c[14]=d[14];c[15]=d[15];return this},multiplyScalar:function(a){var b=this.elements;b[0]*=a;b[4]*=a;b[8]*=a;b[12]*=a;b[1]*=a;b[5]*=a;b[9]*=a;b[13]*=a;b[2]*=a;b[6]*=a;b[10]*=a;b[14]*=a;b[3]*=a;b[7]*=a;b[11]*=a;b[15]*=a;return this},multiplyVector3:function(a){console.warn("DEPRECATED: Matrix4's .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) or vector.applyProjection( matrix ) instead."); +return a.applyProjection(this)},multiplyVector4:function(a){console.warn("DEPRECATED: Matrix4's .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.");return a.applyMatrix4(this)},multiplyVector3Array:function(){var a=new THREE.Vector3;return function(b){for(var c=0,d=b.length;c<d;c+=3)a.x=b[c],a.y=b[c+1],a.z=b[c+2],a.applyProjection(this),b[c]=a.x,b[c+1]=a.y,b[c+2]=a.z;return b}}(),rotateAxis:function(a){var b=this.elements,c=a.x,d=a.y,e=a.z;a.x=c*b[0]+d*b[4]+e*b[8];a.y= +c*b[1]+d*b[5]+e*b[9];a.z=c*b[2]+d*b[6]+e*b[10];a.normalize();return a},crossVector:function(a){var b=this.elements,c=new THREE.Vector4;c.x=b[0]*a.x+b[4]*a.y+b[8]*a.z+b[12]*a.w;c.y=b[1]*a.x+b[5]*a.y+b[9]*a.z+b[13]*a.w;c.z=b[2]*a.x+b[6]*a.y+b[10]*a.z+b[14]*a.w;c.w=a.w?b[3]*a.x+b[7]*a.y+b[11]*a.z+b[15]*a.w:1;return c},determinant:function(){var a=this.elements,b=a[0],c=a[4],d=a[8],e=a[12],f=a[1],g=a[5],h=a[9],i=a[13],k=a[2],l=a[6],m=a[10],n=a[14];return a[3]*(+e*h*l-d*i*l-e*g*m+c*i*m+d*g*n-c*h*n)+a[7]* +(+b*h*n-b*i*m+e*f*m-d*f*n+d*i*k-e*h*k)+a[11]*(+b*i*l-b*g*n-e*f*l+c*f*n+e*g*k-c*i*k)+a[15]*(-d*g*k-b*h*l+b*g*m+d*f*l-c*f*m+c*h*k)},transpose:function(){var a=this.elements,b;b=a[1];a[1]=a[4];a[4]=b;b=a[2];a[2]=a[8];a[8]=b;b=a[6];a[6]=a[9];a[9]=b;b=a[3];a[3]=a[12];a[12]=b;b=a[7];a[7]=a[13];a[13]=b;b=a[11];a[11]=a[14];a[14]=b;return this},flattenToArray:function(a){var b=this.elements;a[0]=b[0];a[1]=b[1];a[2]=b[2];a[3]=b[3];a[4]=b[4];a[5]=b[5];a[6]=b[6];a[7]=b[7];a[8]=b[8];a[9]=b[9];a[10]=b[10];a[11]= +b[11];a[12]=b[12];a[13]=b[13];a[14]=b[14];a[15]=b[15];return a},flattenToArrayOffset:function(a,b){var c=this.elements;a[b]=c[0];a[b+1]=c[1];a[b+2]=c[2];a[b+3]=c[3];a[b+4]=c[4];a[b+5]=c[5];a[b+6]=c[6];a[b+7]=c[7];a[b+8]=c[8];a[b+9]=c[9];a[b+10]=c[10];a[b+11]=c[11];a[b+12]=c[12];a[b+13]=c[13];a[b+14]=c[14];a[b+15]=c[15];return a},getPosition:function(){var a=new THREE.Vector3;return function(){console.warn("DEPRECATED: Matrix4's .getPosition() has been removed. Use Vector3.getPositionFromMatrix( matrix ) instead."); +var b=this.elements;return a.set(b[12],b[13],b[14])}}(),setPosition:function(a){var b=this.elements;b[12]=a.x;b[13]=a.y;b[14]=a.z;return this},getInverse:function(a,b){var c=this.elements,d=a.elements,e=d[0],f=d[4],g=d[8],h=d[12],i=d[1],k=d[5],l=d[9],m=d[13],n=d[2],s=d[6],r=d[10],p=d[14],q=d[3],y=d[7],v=d[11],z=d[15];c[0]=l*p*y-m*r*y+m*s*v-k*p*v-l*s*z+k*r*z;c[4]=h*r*y-g*p*y-h*s*v+f*p*v+g*s*z-f*r*z;c[8]=g*m*y-h*l*y+h*k*v-f*m*v-g*k*z+f*l*z;c[12]=h*l*s-g*m*s-h*k*r+f*m*r+g*k*p-f*l*p;c[1]=m*r*q-l*p*q- +m*n*v+i*p*v+l*n*z-i*r*z;c[5]=g*p*q-h*r*q+h*n*v-e*p*v-g*n*z+e*r*z;c[9]=h*l*q-g*m*q-h*i*v+e*m*v+g*i*z-e*l*z;c[13]=g*m*n-h*l*n+h*i*r-e*m*r-g*i*p+e*l*p;c[2]=k*p*q-m*s*q+m*n*y-i*p*y-k*n*z+i*s*z;c[6]=h*s*q-f*p*q-h*n*y+e*p*y+f*n*z-e*s*z;c[10]=f*m*q-h*k*q+h*i*y-e*m*y-f*i*z+e*k*z;c[14]=h*k*n-f*m*n-h*i*s+e*m*s+f*i*p-e*k*p;c[3]=l*s*q-k*r*q-l*n*y+i*r*y+k*n*v-i*s*v;c[7]=f*r*q-g*s*q+g*n*y-e*r*y-f*n*v+e*s*v;c[11]=g*k*q-f*l*q-g*i*y+e*l*y+f*i*v-e*k*v;c[15]=f*l*n-g*k*n+g*i*s-e*l*s-f*i*r+e*k*r;c=d[0]*c[0]+d[1]*c[4]+ +d[2]*c[8]+d[3]*c[12];if(0==c){if(b)throw Error("Matrix4.getInverse(): can't invert matrix, determinant is 0");console.warn("Matrix4.getInverse(): can't invert matrix, determinant is 0");this.identity();return this}this.multiplyScalar(1/c);return this},compose:function(){var a=new THREE.Matrix4,b=new THREE.Matrix4;return function(c,d,e){var f=this.elements;a.identity();a.setRotationFromQuaternion(d);b.makeScale(e.x,e.y,e.z);this.multiplyMatrices(a,b);f[12]=c.x;f[13]=c.y;f[14]=c.z;return this}}(),decompose:function(){var a= +new THREE.Vector3,b=new THREE.Vector3,c=new THREE.Vector3,d=new THREE.Matrix4;return function(e,f,g){var h=this.elements;a.set(h[0],h[1],h[2]);b.set(h[4],h[5],h[6]);c.set(h[8],h[9],h[10]);e=e instanceof THREE.Vector3?e:new THREE.Vector3;f=f instanceof THREE.Quaternion?f:new THREE.Quaternion;g=g instanceof THREE.Vector3?g:new THREE.Vector3;g.x=a.length();g.y=b.length();g.z=c.length();e.x=h[12];e.y=h[13];e.z=h[14];d.copy(this);d.elements[0]/=g.x;d.elements[1]/=g.x;d.elements[2]/=g.x;d.elements[4]/= +g.y;d.elements[5]/=g.y;d.elements[6]/=g.y;d.elements[8]/=g.z;d.elements[9]/=g.z;d.elements[10]/=g.z;f.setFromRotationMatrix(d);return[e,f,g]}}(),extractPosition:function(a){var b=this.elements,a=a.elements;b[12]=a[12];b[13]=a[13];b[14]=a[14];return this},extractRotation:function(){var a=new THREE.Vector3;return function(b){var c=this.elements,b=b.elements,d=1/a.set(b[0],b[1],b[2]).length(),e=1/a.set(b[4],b[5],b[6]).length(),f=1/a.set(b[8],b[9],b[10]).length();c[0]=b[0]*d;c[1]=b[1]*d;c[2]=b[2]*d;c[4]= +b[4]*e;c[5]=b[5]*e;c[6]=b[6]*e;c[8]=b[8]*f;c[9]=b[9]*f;c[10]=b[10]*f;return this}}(),translate:function(a){var b=this.elements,c=a.x,d=a.y,a=a.z;b[12]=b[0]*c+b[4]*d+b[8]*a+b[12];b[13]=b[1]*c+b[5]*d+b[9]*a+b[13];b[14]=b[2]*c+b[6]*d+b[10]*a+b[14];b[15]=b[3]*c+b[7]*d+b[11]*a+b[15];return this},rotateX:function(a){var b=this.elements,c=b[4],d=b[5],e=b[6],f=b[7],g=b[8],h=b[9],i=b[10],k=b[11],l=Math.cos(a),a=Math.sin(a);b[4]=l*c+a*g;b[5]=l*d+a*h;b[6]=l*e+a*i;b[7]=l*f+a*k;b[8]=l*g-a*c;b[9]=l*h-a*d;b[10]= +l*i-a*e;b[11]=l*k-a*f;return this},rotateY:function(a){var b=this.elements,c=b[0],d=b[1],e=b[2],f=b[3],g=b[8],h=b[9],i=b[10],k=b[11],l=Math.cos(a),a=Math.sin(a);b[0]=l*c-a*g;b[1]=l*d-a*h;b[2]=l*e-a*i;b[3]=l*f-a*k;b[8]=l*g+a*c;b[9]=l*h+a*d;b[10]=l*i+a*e;b[11]=l*k+a*f;return this},rotateZ:function(a){var b=this.elements,c=b[0],d=b[1],e=b[2],f=b[3],g=b[4],h=b[5],i=b[6],k=b[7],l=Math.cos(a),a=Math.sin(a);b[0]=l*c+a*g;b[1]=l*d+a*h;b[2]=l*e+a*i;b[3]=l*f+a*k;b[4]=l*g-a*c;b[5]=l*h-a*d;b[6]=l*i-a*e;b[7]=l* +k-a*f;return this},rotateByAxis:function(a,b){var c=this.elements;if(1===a.x&&0===a.y&&0===a.z)return this.rotateX(b);if(0===a.x&&1===a.y&&0===a.z)return this.rotateY(b);if(0===a.x&&0===a.y&&1===a.z)return this.rotateZ(b);var d=a.x,e=a.y,f=a.z,g=Math.sqrt(d*d+e*e+f*f),d=d/g,e=e/g,f=f/g,g=d*d,h=e*e,i=f*f,k=Math.cos(b),l=Math.sin(b),m=1-k,n=d*e*m,s=d*f*m,m=e*f*m,d=d*l,r=e*l,l=f*l,f=g+(1-g)*k,g=n+l,e=s-r,n=n-l,h=h+(1-h)*k,l=m+d,s=s+r,m=m-d,i=i+(1-i)*k,k=c[0],d=c[1],r=c[2],p=c[3],q=c[4],y=c[5],v=c[6], +z=c[7],t=c[8],A=c[9],I=c[10],C=c[11];c[0]=f*k+g*q+e*t;c[1]=f*d+g*y+e*A;c[2]=f*r+g*v+e*I;c[3]=f*p+g*z+e*C;c[4]=n*k+h*q+l*t;c[5]=n*d+h*y+l*A;c[6]=n*r+h*v+l*I;c[7]=n*p+h*z+l*C;c[8]=s*k+m*q+i*t;c[9]=s*d+m*y+i*A;c[10]=s*r+m*v+i*I;c[11]=s*p+m*z+i*C;return this},scale:function(a){var b=this.elements,c=a.x,d=a.y,a=a.z;b[0]*=c;b[4]*=d;b[8]*=a;b[1]*=c;b[5]*=d;b[9]*=a;b[2]*=c;b[6]*=d;b[10]*=a;b[3]*=c;b[7]*=d;b[11]*=a;return this},getMaxScaleOnAxis:function(){var a=this.elements;return Math.sqrt(Math.max(a[0]* +a[0]+a[1]*a[1]+a[2]*a[2],Math.max(a[4]*a[4]+a[5]*a[5]+a[6]*a[6],a[8]*a[8]+a[9]*a[9]+a[10]*a[10])))},makeTranslation:function(a,b,c){this.set(1,0,0,a,0,1,0,b,0,0,1,c,0,0,0,1);return this},makeRotationX:function(a){var b=Math.cos(a),a=Math.sin(a);this.set(1,0,0,0,0,b,-a,0,0,a,b,0,0,0,0,1);return this},makeRotationY:function(a){var b=Math.cos(a),a=Math.sin(a);this.set(b,0,a,0,0,1,0,0,-a,0,b,0,0,0,0,1);return this},makeRotationZ:function(a){var b=Math.cos(a),a=Math.sin(a);this.set(b,-a,0,0,a,b,0,0,0, +0,1,0,0,0,0,1);return this},makeRotationAxis:function(a,b){var c=Math.cos(b),d=Math.sin(b),e=1-c,f=a.x,g=a.y,h=a.z,i=e*f,k=e*g;this.set(i*f+c,i*g-d*h,i*h+d*g,0,i*g+d*h,k*g+c,k*h-d*f,0,i*h-d*g,k*h+d*f,e*h*h+c,0,0,0,0,1);return this},makeScale:function(a,b,c){this.set(a,0,0,0,0,b,0,0,0,0,c,0,0,0,0,1);return this},makeFrustum:function(a,b,c,d,e,f){var g=this.elements;g[0]=2*e/(b-a);g[4]=0;g[8]=(b+a)/(b-a);g[12]=0;g[1]=0;g[5]=2*e/(d-c);g[9]=(d+c)/(d-c);g[13]=0;g[2]=0;g[6]=0;g[10]=-(f+e)/(f-e);g[14]=-2* +f*e/(f-e);g[3]=0;g[7]=0;g[11]=-1;g[15]=0;return this},makePerspective:function(a,b,c,d){var a=c*Math.tan(THREE.Math.degToRad(0.5*a)),e=-a;return this.makeFrustum(e*b,a*b,e,a,c,d)},makeOrthographic:function(a,b,c,d,e,f){var g=this.elements,h=b-a,i=c-d,k=f-e;g[0]=2/h;g[4]=0;g[8]=0;g[12]=-((b+a)/h);g[1]=0;g[5]=2/i;g[9]=0;g[13]=-((c+d)/i);g[2]=0;g[6]=0;g[10]=-2/k;g[14]=-((f+e)/k);g[3]=0;g[7]=0;g[11]=0;g[15]=1;return this},clone:function(){var a=this.elements;return new THREE.Matrix4(a[0],a[4],a[8],a[12], +a[1],a[5],a[9],a[13],a[2],a[6],a[10],a[14],a[3],a[7],a[11],a[15])}});THREE.Ray=function(a,b){this.origin=void 0!==a?a:new THREE.Vector3;this.direction=void 0!==b?b:new THREE.Vector3}; +THREE.extend(THREE.Ray.prototype,{set:function(a,b){this.origin.copy(a);this.direction.copy(b);return this},copy:function(a){this.origin.copy(a.origin);this.direction.copy(a.direction);return this},at:function(a,b){return(b||new THREE.Vector3).copy(this.direction).multiplyScalar(a).add(this.origin)},recast:function(){var a=new THREE.Vector3;return function(b){this.origin.copy(this.at(b,a));return this}}(),closestPointToPoint:function(a,b){var c=b||new THREE.Vector3;c.subVectors(a,this.origin);var d= +c.dot(this.direction);return c.copy(this.direction).multiplyScalar(d).add(this.origin)},distanceToPoint:function(){var a=new THREE.Vector3;return function(b){var c=a.subVectors(b,this.origin).dot(this.direction);a.copy(this.direction).multiplyScalar(c).add(this.origin);return a.distanceTo(b)}}(),isIntersectionSphere:function(a){return this.distanceToPoint(a.center)<=a.radius},isIntersectionPlane:function(a){return 0!=a.normal.dot(this.direction)||0==a.distanceToPoint(this.origin)?!0:!1},distanceToPlane:function(a){var b= +a.normal.dot(this.direction);if(0==b){if(0==a.distanceToPoint(this.origin))return 0}else return-(this.origin.dot(a.normal)+a.constant)/b},intersectPlane:function(a,b){var c=this.distanceToPlane(a);return void 0===c?void 0:this.at(c,b)},applyMatrix4:function(a){this.direction.add(this.origin).applyMatrix4(a);this.origin.applyMatrix4(a);this.direction.sub(this.origin);return this},equals:function(a){return a.origin.equals(this.origin)&&a.direction.equals(this.direction)},clone:function(){return(new THREE.Ray).copy(this)}});THREE.Sphere=function(a,b){this.center=void 0!==a?a:new THREE.Vector3;this.radius=void 0!==b?b:0}; +THREE.extend(THREE.Sphere.prototype,{set:function(a,b){this.center.copy(a);this.radius=b;return this},setFromCenterAndPoints:function(a,b){for(var c=0,d=0,e=b.length;d<e;d++)var f=a.distanceToSquared(b[d]),c=Math.max(c,f);this.center=a;this.radius=Math.sqrt(c);return this},copy:function(a){this.center.copy(a.center);this.radius=a.radius;return this},empty:function(){return 0>=this.radius},containsPoint:function(a){return a.distanceToSquared(this.center)<=this.radius*this.radius},distanceToPoint:function(a){return a.distanceTo(this.center)- +this.radius},intersectsSphere:function(a){var b=this.radius+a.radius;return a.center.distanceToSquared(this.center)<=b*b},clampPoint:function(a,b){var c=this.center.distanceToSquared(a),d=b||new THREE.Vector3;d.copy(a);c>this.radius*this.radius&&(d.sub(this.center).normalize(),d.multiplyScalar(this.radius).add(this.center));return d},getBoundingBox:function(a){a=a||new THREE.Box3;a.set(this.center,this.center);a.expandByScalar(this.radius);return a},applyMatrix4:function(a){this.center.applyMatrix4(a); +this.radius*=a.getMaxScaleOnAxis();return this},translate:function(a){this.center.add(a);return this},equals:function(a){return a.center.equals(this.center)&&a.radius===this.radius},clone:function(){return(new THREE.Sphere).copy(this)}});THREE.Frustum=function(a,b,c,d,e,f){this.planes=[void 0!==a?a:new THREE.Plane,void 0!==b?b:new THREE.Plane,void 0!==c?c:new THREE.Plane,void 0!==d?d:new THREE.Plane,void 0!==e?e:new THREE.Plane,void 0!==f?f:new THREE.Plane]}; +THREE.extend(THREE.Frustum.prototype,{set:function(a,b,c,d,e,f){var g=this.planes;g[0].copy(a);g[1].copy(b);g[2].copy(c);g[3].copy(d);g[4].copy(e);g[5].copy(f);return this},copy:function(a){for(var b=this.planes,c=0;6>c;c++)b[c].copy(a.planes[c]);return this},setFromMatrix:function(a){var b=this.planes,c=a.elements,a=c[0],d=c[1],e=c[2],f=c[3],g=c[4],h=c[5],i=c[6],k=c[7],l=c[8],m=c[9],n=c[10],s=c[11],r=c[12],p=c[13],q=c[14],c=c[15];b[0].setComponents(f-a,k-g,s-l,c-r).normalize();b[1].setComponents(f+ +a,k+g,s+l,c+r).normalize();b[2].setComponents(f+d,k+h,s+m,c+p).normalize();b[3].setComponents(f-d,k-h,s-m,c-p).normalize();b[4].setComponents(f-e,k-i,s-n,c-q).normalize();b[5].setComponents(f+e,k+i,s+n,c+q).normalize();return this},intersectsObject:function(){var a=new THREE.Vector3;return function(b){var c=b.matrixWorld,d=this.planes,b=-b.geometry.boundingSphere.radius*c.getMaxScaleOnAxis();a.getPositionFromMatrix(c);for(c=0;6>c;c++)if(d[c].distanceToPoint(a)<b)return!1;return!0}}(),intersectsSphere:function(a){for(var b= +this.planes,c=a.center,a=-a.radius,d=0;6>d;d++)if(b[d].distanceToPoint(c)<a)return!1;return!0},containsPoint:function(a){for(var b=this.planes,c=0;6>c;c++)if(0>b[c].distanceToPoint(a))return!1;return!0},clone:function(){return(new THREE.Frustum).copy(this)}});THREE.Plane=function(a,b){this.normal=void 0!==a?a:new THREE.Vector3(1,0,0);this.constant=void 0!==b?b:0}; +THREE.extend(THREE.Plane.prototype,{set:function(a,b){this.normal.copy(a);this.constant=b;return this},setComponents:function(a,b,c,d){this.normal.set(a,b,c);this.constant=d;return this},setFromNormalAndCoplanarPoint:function(a,b){this.normal.copy(a);this.constant=-b.dot(this.normal);return this},setFromCoplanarPoints:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(c,d,e){d=a.subVectors(e,d).cross(b.subVectors(c,d)).normalize();this.setFromNormalAndCoplanarPoint(d,c);return this}}(), +copy:function(a){this.normal.copy(a.normal);this.constant=a.constant;return this},normalize:function(){var a=1/this.normal.length();this.normal.multiplyScalar(a);this.constant*=a;return this},negate:function(){this.constant*=-1;this.normal.negate();return this},distanceToPoint:function(a){return this.normal.dot(a)+this.constant},distanceToSphere:function(a){return this.distanceToPoint(a.center)-a.radius},projectPoint:function(a,b){return this.orthoPoint(a,b).sub(a).negate()},orthoPoint:function(a, +b){var c=this.distanceToPoint(a);return(b||new THREE.Vector3).copy(this.normal).multiplyScalar(c)},isIntersectionLine:function(a){var b=this.distanceToPoint(a.start),a=this.distanceToPoint(a.end);return 0>b&&0<a||0>a&&0<b},intersectLine:function(){var a=new THREE.Vector3;return function(b,c){var d=c||new THREE.Vector3,e=b.delta(a),f=this.normal.dot(e);if(0==f){if(0==this.distanceToPoint(b.start))return d.copy(b.start)}else return f=-(b.start.dot(this.normal)+this.constant)/f,0>f||1<f?void 0:d.copy(e).multiplyScalar(f).add(b.start)}}(), +coplanarPoint:function(a){return(a||new THREE.Vector3).copy(this.normal).multiplyScalar(-this.constant)},applyMatrix4:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(c,d){var d=d||(new THREE.Matrix3).getInverse(c).transpose(),e=a.copy(this.normal).applyMatrix3(d),f=this.coplanarPoint(b);f.applyMatrix4(c);this.setFromNormalAndCoplanarPoint(e,f);return this}}(),translate:function(a){this.constant-=a.dot(this.normal);return this},equals:function(a){return a.normal.equals(this.normal)&& +a.constant==this.constant},clone:function(){return(new THREE.Plane).copy(this)}});THREE.Math={clamp:function(a,b,c){return a<b?b:a>c?c:a},clampBottom:function(a,b){return a<b?b:a},mapLinear:function(a,b,c,d,e){return d+(a-b)*(e-d)/(c-b)},smoothstep:function(a,b,c){if(a<=b)return 0;if(a>=c)return 1;a=(a-b)/(c-b);return a*a*(3-2*a)},smootherstep:function(a,b,c){if(a<=b)return 0;if(a>=c)return 1;a=(a-b)/(c-b);return a*a*a*(a*(6*a-15)+10)},random16:function(){return(65280*Math.random()+255*Math.random())/65535},randInt:function(a,b){return a+Math.floor(Math.random()*(b-a+1))},randFloat:function(a, +b){return a+Math.random()*(b-a)},randFloatSpread:function(a){return a*(0.5-Math.random())},sign:function(a){return 0>a?-1:0<a?1:0},degToRad:function(){var a=Math.PI/180;return function(b){return b*a}}(),radToDeg:function(){var a=180/Math.PI;return function(b){return b*a}}()};THREE.Spline=function(a){function b(a,b,c,d,e,f,g){a=0.5*(c-a);d=0.5*(d-b);return(2*(b-c)+a+d)*g+(-3*(b-c)-2*a-d)*f+a*e+b}this.points=a;var c=[],d={x:0,y:0,z:0},e,f,g,h,i,k,l,m,n;this.initFromArray=function(a){this.points=[];for(var b=0;b<a.length;b++)this.points[b]={x:a[b][0],y:a[b][1],z:a[b][2]}};this.getPoint=function(a){e=(this.points.length-1)*a;f=Math.floor(e);g=e-f;c[0]=0===f?f:f-1;c[1]=f;c[2]=f>this.points.length-2?this.points.length-1:f+1;c[3]=f>this.points.length-3?this.points.length-1: +f+2;k=this.points[c[0]];l=this.points[c[1]];m=this.points[c[2]];n=this.points[c[3]];h=g*g;i=g*h;d.x=b(k.x,l.x,m.x,n.x,g,h,i);d.y=b(k.y,l.y,m.y,n.y,g,h,i);d.z=b(k.z,l.z,m.z,n.z,g,h,i);return d};this.getControlPointsArray=function(){var a,b,c=this.points.length,d=[];for(a=0;a<c;a++)b=this.points[a],d[a]=[b.x,b.y,b.z];return d};this.getLength=function(a){var b,c,d,e=b=b=0,f=new THREE.Vector3,g=new THREE.Vector3,h=[],i=0;h[0]=0;a||(a=100);c=this.points.length*a;f.copy(this.points[0]);for(a=1;a<c;a++)b= +a/c,d=this.getPoint(b),g.copy(d),i+=g.distanceTo(f),f.copy(d),b*=this.points.length-1,b=Math.floor(b),b!=e&&(h[b]=i,e=b);h[h.length]=i;return{chunks:h,total:i}};this.reparametrizeByArcLength=function(a){var b,c,d,e,f,g,h=[],i=new THREE.Vector3,k=this.getLength();h.push(i.copy(this.points[0]).clone());for(b=1;b<this.points.length;b++){c=k.chunks[b]-k.chunks[b-1];g=Math.ceil(a*c/k.total);e=(b-1)/(this.points.length-1);f=b/(this.points.length-1);for(c=1;c<g-1;c++)d=e+c*(1/g)*(f-e),d=this.getPoint(d), +h.push(i.copy(d).clone());h.push(i.copy(this.points[b]).clone())}this.points=h}};THREE.Triangle=function(a,b,c){this.a=void 0!==a?a:new THREE.Vector3;this.b=void 0!==b?b:new THREE.Vector3;this.c=void 0!==c?c:new THREE.Vector3};THREE.Triangle.normal=function(){var a=new THREE.Vector3;return function(b,c,d,e){e=e||new THREE.Vector3;e.subVectors(d,c);a.subVectors(b,c);e.cross(a);b=e.lengthSq();return 0<b?e.multiplyScalar(1/Math.sqrt(b)):e.set(0,0,0)}}(); +THREE.Triangle.barycoordFromPoint=function(){var a=new THREE.Vector3,b=new THREE.Vector3,c=new THREE.Vector3;return function(d,e,f,g,h){a.subVectors(g,e);b.subVectors(f,e);c.subVectors(d,e);var d=a.dot(a),e=a.dot(b),f=a.dot(c),i=b.dot(b),g=b.dot(c),k=d*i-e*e,h=h||new THREE.Vector3;if(0==k)return h.set(-2,-1,-1);k=1/k;i=(i*f-e*g)*k;d=(d*g-e*f)*k;return h.set(1-i-d,d,i)}}(); +THREE.Triangle.containsPoint=function(){var a=new THREE.Vector3;return function(b,c,d,e){b=THREE.Triangle.barycoordFromPoint(b,c,d,e,a);return 0<=b.x&&0<=b.y&&1>=b.x+b.y}}(); +THREE.extend(THREE.Triangle.prototype,{constructor:THREE.Triangle,set:function(a,b,c){this.a.copy(a);this.b.copy(b);this.c.copy(c);return this},setFromPointsAndIndices:function(a,b,c,d){this.a.copy(a[b]);this.b.copy(a[c]);this.c.copy(a[d]);return this},copy:function(a){this.a.copy(a.a);this.b.copy(a.b);this.c.copy(a.c);return this},area:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(){a.subVectors(this.c,this.b);b.subVectors(this.a,this.b);return 0.5*a.cross(b).length()}}(), +midpoint:function(a){return(a||new THREE.Vector3).addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)},normal:function(a){return THREE.Triangle.normal(this.a,this.b,this.c,a)},plane:function(a){return(a||new THREE.Plane).setFromCoplanarPoints(this.a,this.b,this.c)},barycoordFromPoint:function(a,b){return THREE.Triangle.barycoordFromPoint(a,this.a,this.b,this.c,b)},containsPoint:function(a){return THREE.Triangle.containsPoint(a,this.a,this.b,this.c)},equals:function(a){return a.a.equals(this.a)&& +a.b.equals(this.b)&&a.c.equals(this.c)},clone:function(){return(new THREE.Triangle).copy(this)}});THREE.Vertex=function(a){console.warn("THREE.Vertex has been DEPRECATED. Use THREE.Vector3 instead.");return a};THREE.UV=function(a,b){console.warn("THREE.UV has been DEPRECATED. Use THREE.Vector2 instead.");return new THREE.Vector2(a,b)};THREE.Clock=function(a){this.autoStart=void 0!==a?a:!0;this.elapsedTime=this.oldTime=this.startTime=0;this.running=!1}; +THREE.extend(THREE.Clock.prototype,{start:function(){this.oldTime=this.startTime=void 0!==window.performance&&void 0!==window.performance.now?window.performance.now():Date.now();this.running=!0},stop:function(){this.getElapsedTime();this.running=!1},getElapsedTime:function(){this.getDelta();return this.elapsedTime},getDelta:function(){var a=0;this.autoStart&&!this.running&&this.start();if(this.running){var b=void 0!==window.performance&&void 0!==window.performance.now?window.performance.now():Date.now(), +a=0.001*(b-this.oldTime);this.oldTime=b;this.elapsedTime+=a}return a}});THREE.EventDispatcher=function(){var a={};this.addEventListener=function(b,c){void 0===a[b]&&(a[b]=[]);-1===a[b].indexOf(c)&&a[b].push(c)};this.removeEventListener=function(b,c){var d=a[b].indexOf(c);-1!==d&&a[b].splice(d,1)};this.dispatchEvent=function(b){var c=a[b.type];if(void 0!==c){b.target=this;for(var d=0,e=c.length;d<e;d++)c[d].call(this,b)}}};(function(a){a.Raycaster=function(b,c,d,e){this.ray=new a.Ray(b,c);0<this.ray.direction.lengthSq()&&this.ray.direction.normalize();this.near=d||0;this.far=e||Infinity};var b=new a.Sphere,c=new a.Ray,d=new a.Plane,e=new a.Vector3,f=new a.Vector3,g=new a.Matrix4,h=function(a,b){return a.distance-b.distance},i=function(h,i,k){if(h instanceof a.Particle){f.getPositionFromMatrix(h.matrixWorld);i=i.ray.distanceToPoint(f);if(i>h.scale.x)return k;k.push({distance:i,point:h.position,face:null,object:h})}else if(h instanceof +a.Mesh){f.getPositionFromMatrix(h.matrixWorld);b.set(f,h.geometry.boundingSphere.radius*h.matrixWorld.getMaxScaleOnAxis());if(!i.ray.isIntersectionSphere(b))return k;var s=h.geometry,r=s.vertices,p=h.material instanceof a.MeshFaceMaterial,q=!0===p?h.material.materials:null,y=h.material.side,v,z,t,A=i.precision;h.matrixRotationWorld.extractRotation(h.matrixWorld);g.getInverse(h.matrixWorld);c.copy(i.ray).applyMatrix4(g);for(var I=0,C=s.faces.length;I<C;I++){var x=s.faces[I],y=!0===p?q[x.materialIndex]: +h.material;if(void 0!==y){d.setFromNormalAndCoplanarPoint(x.normal,r[x.a]);var G=c.distanceToPlane(d);if(!(Math.abs(G)<A)&&!(0>G)){y=y.side;if(y!==a.DoubleSide&&(v=c.direction.dot(d.normal),!(y===a.FrontSide?0>v:0<v)))continue;if(!(G<i.near||G>i.far)){e=c.at(G,e);if(x instanceof a.Face3){if(y=r[x.a],v=r[x.b],z=r[x.c],!a.Triangle.containsPoint(e,y,v,z))continue}else if(x instanceof a.Face4){if(y=r[x.a],v=r[x.b],z=r[x.c],t=r[x.d],!a.Triangle.containsPoint(e,y,v,t)&&!a.Triangle.containsPoint(e,v,z,t))continue}else throw Error("face type not supported"); +k.push({distance:G,point:i.ray.at(G),face:x,faceIndex:I,object:h})}}}}}},k=function(a,b,c){for(var a=a.getDescendants(),d=0,e=a.length;d<e;d++)i(a[d],b,c)};a.Raycaster.prototype.precision=1E-4;a.Raycaster.prototype.set=function(a,b){this.ray.set(a,b);0<this.ray.direction.length()&&this.ray.direction.normalize()};a.Raycaster.prototype.intersectObject=function(a,b){var c=[];!0===b&&k(a,this,c);i(a,this,c);c.sort(h);return c};a.Raycaster.prototype.intersectObjects=function(a,b){for(var c=[],d=0,e=a.length;d< +e;d++)i(a[d],this,c),!0===b&&k(a[d],this,c);c.sort(h);return c}})(THREE);THREE.Object3D=function(){this.id=THREE.Object3DIdCount++;this.name="";this.properties={};this.parent=void 0;this.children=[];this.up=new THREE.Vector3(0,1,0);this.position=new THREE.Vector3;this.rotation=new THREE.Vector3;this.eulerOrder=THREE.Object3D.defaultEulerOrder;this.scale=new THREE.Vector3(1,1,1);this.renderDepth=null;this.rotationAutoUpdate=!0;this.matrix=new THREE.Matrix4;this.matrixWorld=new THREE.Matrix4;this.matrixRotationWorld=new THREE.Matrix4;this.matrixWorldNeedsUpdate=this.matrixAutoUpdate= +!0;this.quaternion=new THREE.Quaternion;this.useQuaternion=!1;this.visible=!0;this.receiveShadow=this.castShadow=!1;this.frustumCulled=!0;this._vector=new THREE.Vector3}; +THREE.Object3D.prototype={constructor:THREE.Object3D,applyMatrix:function(a){this.matrix.multiplyMatrices(a,this.matrix);this.scale.getScaleFromMatrix(this.matrix);a=(new THREE.Matrix4).extractRotation(this.matrix);this.rotation.setEulerFromRotationMatrix(a,this.eulerOrder);this.position.getPositionFromMatrix(this.matrix)},translate:function(a,b){this.matrix.rotateAxis(b);this.position.add(b.multiplyScalar(a))},translateX:function(a){this.translate(a,this._vector.set(1,0,0))},translateY:function(a){this.translate(a, +this._vector.set(0,1,0))},translateZ:function(a){this.translate(a,this._vector.set(0,0,1))},localToWorld:function(a){return a.applyMatrix4(this.matrixWorld)},worldToLocal:function(a){return a.applyMatrix4(THREE.Object3D.__m1.getInverse(this.matrixWorld))},lookAt:function(a){this.matrix.lookAt(a,this.position,this.up);this.rotationAutoUpdate&&(!1===this.useQuaternion?this.rotation.setEulerFromRotationMatrix(this.matrix,this.eulerOrder):this.quaternion.copy(this.matrix.decompose()[1]))},add:function(a){if(a=== +this)console.warn("THREE.Object3D.add: An object can't be added as a child of itself.");else if(a instanceof THREE.Object3D){void 0!==a.parent&&a.parent.remove(a);a.parent=this;this.children.push(a);for(var b=this;void 0!==b.parent;)b=b.parent;void 0!==b&&b instanceof THREE.Scene&&b.__addObject(a)}},remove:function(a){var b=this.children.indexOf(a);if(-1!==b){a.parent=void 0;this.children.splice(b,1);for(b=this;void 0!==b.parent;)b=b.parent;void 0!==b&&b instanceof THREE.Scene&&b.__removeObject(a)}}, +traverse:function(a){a(this);for(var b=0,c=this.children.length;b<c;b++)this.children[b].traverse(a)},getChildByName:function(a,b){for(var c=0,d=this.children.length;c<d;c++){var e=this.children[c];if(e.name===a||!0===b&&(e=e.getChildByName(a,b),void 0!==e))return e}},getDescendants:function(a){void 0===a&&(a=[]);Array.prototype.push.apply(a,this.children);for(var b=0,c=this.children.length;b<c;b++)this.children[b].getDescendants(a);return a},updateMatrix:function(){this.matrix.setPosition(this.position); +!1===this.useQuaternion?this.matrix.setRotationFromEuler(this.rotation,this.eulerOrder):this.matrix.setRotationFromQuaternion(this.quaternion);(1!==this.scale.x||1!==this.scale.y||1!==this.scale.z)&&this.matrix.scale(this.scale);this.matrixWorldNeedsUpdate=!0},updateMatrixWorld:function(a){!0===this.matrixAutoUpdate&&this.updateMatrix();if(!0===this.matrixWorldNeedsUpdate||!0===a)void 0===this.parent?this.matrixWorld.copy(this.matrix):this.matrixWorld.multiplyMatrices(this.parent.matrixWorld,this.matrix), +this.matrixWorldNeedsUpdate=!1,a=!0;for(var b=0,c=this.children.length;b<c;b++)this.children[b].updateMatrixWorld(a)},clone:function(a){void 0===a&&(a=new THREE.Object3D);a.name=this.name;a.up.copy(this.up);a.position.copy(this.position);a.rotation instanceof THREE.Vector3&&a.rotation.copy(this.rotation);a.eulerOrder=this.eulerOrder;a.scale.copy(this.scale);a.renderDepth=this.renderDepth;a.rotationAutoUpdate=this.rotationAutoUpdate;a.matrix.copy(this.matrix);a.matrixWorld.copy(this.matrixWorld);a.matrixRotationWorld.copy(this.matrixRotationWorld); +a.matrixAutoUpdate=this.matrixAutoUpdate;a.matrixWorldNeedsUpdate=this.matrixWorldNeedsUpdate;a.quaternion.copy(this.quaternion);a.useQuaternion=this.useQuaternion;a.visible=this.visible;a.castShadow=this.castShadow;a.receiveShadow=this.receiveShadow;a.frustumCulled=this.frustumCulled;for(var b=0;b<this.children.length;b++)a.add(this.children[b].clone());return a}};THREE.Object3D.__m1=new THREE.Matrix4;THREE.Object3D.defaultEulerOrder="XYZ";THREE.Object3DIdCount=0;THREE.Projector=function(){function a(){if(f===h){var a=new THREE.RenderableObject;g.push(a);h++;f++;return a}return g[f++]}function b(){if(k===m){var a=new THREE.RenderableVertex;l.push(a);m++;k++;return a}return l[k++]}function c(a,b){return b.z-a.z}function d(a,b){var c=0,d=1,e=a.z+a.w,f=b.z+b.w,g=-a.z+a.w,h=-b.z+b.w;if(0<=e&&0<=f&&0<=g&&0<=h)return!0;if(0>e&&0>f||0>g&&0>h)return!1;0>e?c=Math.max(c,e/(e-f)):0>f&&(d=Math.min(d,e/(e-f)));0>g?c=Math.max(c,g/(g-h)):0>h&&(d=Math.min(d,g/(g-h)));if(d< +c)return!1;a.lerp(b,c);b.lerp(a,1-d);return!0}var e,f,g=[],h=0,i,k,l=[],m=0,n,s,r=[],p=0,q,y=[],v=0,z,t,A=[],I=0,C,x,G=[],J=0,E={objects:[],sprites:[],lights:[],elements:[]},H=new THREE.Vector3,B=new THREE.Vector4,W=new THREE.Box3(new THREE.Vector3(-1,-1,-1),new THREE.Vector3(1,1,1)),F=new THREE.Box3,K=Array(3),L=Array(4),U=new THREE.Matrix4,fa=new THREE.Matrix4,Ca,$a=new THREE.Matrix4,M=new THREE.Matrix3,ca=new THREE.Matrix3,qa=new THREE.Vector3,ha=new THREE.Frustum,ra=new THREE.Vector4,N=new THREE.Vector4; +this.projectVector=function(a,b){b.matrixWorldInverse.getInverse(b.matrixWorld);fa.multiplyMatrices(b.projectionMatrix,b.matrixWorldInverse);return a.applyProjection(fa)};this.unprojectVector=function(a,b){b.projectionMatrixInverse.getInverse(b.projectionMatrix);fa.multiplyMatrices(b.matrixWorld,b.projectionMatrixInverse);return a.applyProjection(fa)};this.pickingRay=function(a,b){a.z=-1;var c=new THREE.Vector3(a.x,a.y,1);this.unprojectVector(a,b);this.unprojectVector(c,b);c.sub(a).normalize();return new THREE.Raycaster(a, +c)};this.projectScene=function(g,h,m,Pa){var ta=!1,ka,aa,pa,Y,da,la,Z,oa,gb,nb,ia,Wa,ab;x=t=q=s=0;E.elements.length=0;g.updateMatrixWorld();void 0===h.parent&&h.updateMatrixWorld();U.copy(h.matrixWorldInverse.getInverse(h.matrixWorld));fa.multiplyMatrices(h.projectionMatrix,U);ca.getInverse(U);ca.transpose();ha.setFromMatrix(fa);f=0;E.objects.length=0;E.sprites.length=0;E.lights.length=0;var Fa=function(b){for(var c=0,d=b.children.length;c<d;c++){var f=b.children[c];if(!1!==f.visible){if(f instanceof +THREE.Light)E.lights.push(f);else if(f instanceof THREE.Mesh||f instanceof THREE.Line){if(!1===f.frustumCulled||!0===ha.intersectsObject(f))e=a(),e.object=f,null!==f.renderDepth?e.z=f.renderDepth:(H.getPositionFromMatrix(f.matrixWorld),H.applyProjection(fa),e.z=H.z),E.objects.push(e)}else f instanceof THREE.Sprite||f instanceof THREE.Particle?(e=a(),e.object=f,null!==f.renderDepth?e.z=f.renderDepth:(H.getPositionFromMatrix(f.matrixWorld),H.applyProjection(fa),e.z=H.z),E.sprites.push(e)):(e=a(),e.object= +f,null!==f.renderDepth?e.z=f.renderDepth:(H.getPositionFromMatrix(f.matrixWorld),H.applyProjection(fa),e.z=H.z),E.objects.push(e));Fa(f)}}};Fa(g);!0===m&&E.objects.sort(c);g=0;for(m=E.objects.length;g<m;g++)if(oa=E.objects[g].object,Ca=oa.matrixWorld,k=0,oa instanceof THREE.Mesh){gb=oa.geometry;pa=gb.vertices;nb=gb.faces;gb=gb.faceVertexUvs;M.getInverse(Ca);M.transpose();Wa=oa.material instanceof THREE.MeshFaceMaterial;ab=!0===Wa?oa.material:null;ka=0;for(aa=pa.length;ka<aa;ka++)i=b(),i.positionWorld.copy(pa[ka]).applyMatrix4(Ca), +i.positionScreen.copy(i.positionWorld).applyMatrix4(fa),i.positionScreen.x/=i.positionScreen.w,i.positionScreen.y/=i.positionScreen.w,i.positionScreen.z/=i.positionScreen.w,i.visible=!(-1>i.positionScreen.x||1<i.positionScreen.x||-1>i.positionScreen.y||1<i.positionScreen.y||-1>i.positionScreen.z||1<i.positionScreen.z);pa=0;for(ka=nb.length;pa<ka;pa++){aa=nb[pa];var Xa=!0===Wa?ab.materials[aa.materialIndex]:oa.material;if(void 0!==Xa){la=Xa.side;if(aa instanceof THREE.Face3)if(Y=l[aa.a],da=l[aa.b], +Z=l[aa.c],K[0]=Y.positionScreen,K[1]=da.positionScreen,K[2]=Z.positionScreen,!0===Y.visible||!0===da.visible||!0===Z.visible||W.isIntersectionBox(F.setFromPoints(K)))if(ta=0>(Z.positionScreen.x-Y.positionScreen.x)*(da.positionScreen.y-Y.positionScreen.y)-(Z.positionScreen.y-Y.positionScreen.y)*(da.positionScreen.x-Y.positionScreen.x),la===THREE.DoubleSide||ta===(la===THREE.FrontSide))s===p?(ia=new THREE.RenderableFace3,r.push(ia),p++,s++,n=ia):n=r[s++],n.v1.copy(Y),n.v2.copy(da),n.v3.copy(Z);else continue; +else continue;else if(aa instanceof THREE.Face4)if(Y=l[aa.a],da=l[aa.b],Z=l[aa.c],ia=l[aa.d],L[0]=Y.positionScreen,L[1]=da.positionScreen,L[2]=Z.positionScreen,L[3]=ia.positionScreen,!0===Y.visible||!0===da.visible||!0===Z.visible||!0===ia.visible||W.isIntersectionBox(F.setFromPoints(L)))if(ta=0>(ia.positionScreen.x-Y.positionScreen.x)*(da.positionScreen.y-Y.positionScreen.y)-(ia.positionScreen.y-Y.positionScreen.y)*(da.positionScreen.x-Y.positionScreen.x)||0>(da.positionScreen.x-Z.positionScreen.x)* +(ia.positionScreen.y-Z.positionScreen.y)-(da.positionScreen.y-Z.positionScreen.y)*(ia.positionScreen.x-Z.positionScreen.x),la===THREE.DoubleSide||ta===(la===THREE.FrontSide)){if(q===v){var ub=new THREE.RenderableFace4;y.push(ub);v++;q++;n=ub}else n=y[q++];n.v1.copy(Y);n.v2.copy(da);n.v3.copy(Z);n.v4.copy(ia)}else continue;else continue;n.normalModel.copy(aa.normal);!1===ta&&(la===THREE.BackSide||la===THREE.DoubleSide)&&n.normalModel.negate();n.normalModel.applyMatrix3(M).normalize();n.normalModelView.copy(n.normalModel).applyMatrix3(ca); +n.centroidModel.copy(aa.centroid).applyMatrix4(Ca);Z=aa.vertexNormals;Y=0;for(da=Z.length;Y<da;Y++)ia=n.vertexNormalsModel[Y],ia.copy(Z[Y]),!1===ta&&(la===THREE.BackSide||la===THREE.DoubleSide)&&ia.negate(),ia.applyMatrix3(M).normalize(),n.vertexNormalsModelView[Y].copy(ia).applyMatrix3(ca);n.vertexNormalsLength=Z.length;Y=0;for(da=gb.length;Y<da;Y++)if(ia=gb[Y][pa],void 0!==ia){la=0;for(Z=ia.length;la<Z;la++)n.uvs[Y][la]=ia[la]}n.color=aa.color;n.material=Xa;qa.copy(n.centroidModel).applyProjection(fa); +n.z=qa.z;E.elements.push(n)}}}else if(oa instanceof THREE.Line){$a.multiplyMatrices(fa,Ca);pa=oa.geometry.vertices;Y=b();Y.positionScreen.copy(pa[0]).applyMatrix4($a);nb=oa.type===THREE.LinePieces?2:1;ka=1;for(aa=pa.length;ka<aa;ka++)Y=b(),Y.positionScreen.copy(pa[ka]).applyMatrix4($a),0<(ka+1)%nb||(da=l[k-2],ra.copy(Y.positionScreen),N.copy(da.positionScreen),!0===d(ra,N)&&(ra.multiplyScalar(1/ra.w),N.multiplyScalar(1/N.w),t===I?(gb=new THREE.RenderableLine,A.push(gb),I++,t++,z=gb):z=A[t++],z.v1.positionScreen.copy(ra), +z.v2.positionScreen.copy(N),z.z=Math.max(ra.z,N.z),z.material=oa.material,E.elements.push(z)))}g=0;for(m=E.sprites.length;g<m;g++)oa=E.sprites[g].object,Ca=oa.matrixWorld,oa instanceof THREE.Particle&&(B.set(Ca.elements[12],Ca.elements[13],Ca.elements[14],1),B.applyMatrix4(fa),B.z/=B.w,0<B.z&&1>B.z&&(x===J?(ta=new THREE.RenderableParticle,G.push(ta),J++,x++,C=ta):C=G[x++],C.object=oa,C.x=B.x/B.w,C.y=B.y/B.w,C.z=B.z,C.rotation=oa.rotation.z,C.scale.x=oa.scale.x*Math.abs(C.x-(B.x+h.projectionMatrix.elements[0])/ +(B.w+h.projectionMatrix.elements[12])),C.scale.y=oa.scale.y*Math.abs(C.y-(B.y+h.projectionMatrix.elements[5])/(B.w+h.projectionMatrix.elements[13])),C.material=oa.material,E.elements.push(C)));!0===Pa&&E.elements.sort(c);return E}};THREE.Face3=function(a,b,c,d,e,f){this.a=a;this.b=b;this.c=c;this.normal=d instanceof THREE.Vector3?d:new THREE.Vector3;this.vertexNormals=d instanceof Array?d:[];this.color=e instanceof THREE.Color?e:new THREE.Color;this.vertexColors=e instanceof Array?e:[];this.vertexTangents=[];this.materialIndex=void 0!==f?f:0;this.centroid=new THREE.Vector3}; +THREE.Face3.prototype={constructor:THREE.Face3,clone:function(){var a=new THREE.Face3(this.a,this.b,this.c);a.normal.copy(this.normal);a.color.copy(this.color);a.centroid.copy(this.centroid);a.materialIndex=this.materialIndex;var b,c;b=0;for(c=this.vertexNormals.length;b<c;b++)a.vertexNormals[b]=this.vertexNormals[b].clone();b=0;for(c=this.vertexColors.length;b<c;b++)a.vertexColors[b]=this.vertexColors[b].clone();b=0;for(c=this.vertexTangents.length;b<c;b++)a.vertexTangents[b]=this.vertexTangents[b].clone(); +return a}};THREE.Face4=function(a,b,c,d,e,f,g){this.a=a;this.b=b;this.c=c;this.d=d;this.normal=e instanceof THREE.Vector3?e:new THREE.Vector3;this.vertexNormals=e instanceof Array?e:[];this.color=f instanceof THREE.Color?f:new THREE.Color;this.vertexColors=f instanceof Array?f:[];this.vertexTangents=[];this.materialIndex=void 0!==g?g:0;this.centroid=new THREE.Vector3}; +THREE.Face4.prototype={constructor:THREE.Face4,clone:function(){var a=new THREE.Face4(this.a,this.b,this.c,this.d);a.normal.copy(this.normal);a.color.copy(this.color);a.centroid.copy(this.centroid);a.materialIndex=this.materialIndex;var b,c;b=0;for(c=this.vertexNormals.length;b<c;b++)a.vertexNormals[b]=this.vertexNormals[b].clone();b=0;for(c=this.vertexColors.length;b<c;b++)a.vertexColors[b]=this.vertexColors[b].clone();b=0;for(c=this.vertexTangents.length;b<c;b++)a.vertexTangents[b]=this.vertexTangents[b].clone(); +return a}};THREE.Geometry=function(){THREE.EventDispatcher.call(this);this.id=THREE.GeometryIdCount++;this.name="";this.vertices=[];this.colors=[];this.normals=[];this.faces=[];this.faceUvs=[[]];this.faceVertexUvs=[[]];this.morphTargets=[];this.morphColors=[];this.morphNormals=[];this.skinWeights=[];this.skinIndices=[];this.lineDistances=[];this.boundingSphere=this.boundingBox=null;this.hasTangents=!1;this.dynamic=!0;this.buffersNeedUpdate=this.lineDistancesNeedUpdate=this.colorsNeedUpdate=this.tangentsNeedUpdate= +this.normalsNeedUpdate=this.uvsNeedUpdate=this.elementsNeedUpdate=this.verticesNeedUpdate=!1}; +THREE.Geometry.prototype={constructor:THREE.Geometry,applyMatrix:function(a){for(var b=(new THREE.Matrix3).getInverse(a).transpose(),c=0,d=this.vertices.length;c<d;c++)this.vertices[c].applyMatrix4(a);c=0;for(d=this.faces.length;c<d;c++){var e=this.faces[c];e.normal.applyMatrix3(b).normalize();for(var f=0,g=e.vertexNormals.length;f<g;f++)e.vertexNormals[f].applyMatrix3(b).normalize();e.centroid.applyMatrix4(a)}},computeCentroids:function(){var a,b,c;a=0;for(b=this.faces.length;a<b;a++)c=this.faces[a], +c.centroid.set(0,0,0),c instanceof THREE.Face3?(c.centroid.add(this.vertices[c.a]),c.centroid.add(this.vertices[c.b]),c.centroid.add(this.vertices[c.c]),c.centroid.divideScalar(3)):c instanceof THREE.Face4&&(c.centroid.add(this.vertices[c.a]),c.centroid.add(this.vertices[c.b]),c.centroid.add(this.vertices[c.c]),c.centroid.add(this.vertices[c.d]),c.centroid.divideScalar(4))},computeFaceNormals:function(){for(var a=new THREE.Vector3,b=new THREE.Vector3,c=0,d=this.faces.length;c<d;c++){var e=this.faces[c], +f=this.vertices[e.a],g=this.vertices[e.b];a.subVectors(this.vertices[e.c],g);b.subVectors(f,g);a.cross(b);a.normalize();e.normal.copy(a)}},computeVertexNormals:function(a){var b,c,d,e;if(void 0===this.__tmpVertices){e=this.__tmpVertices=Array(this.vertices.length);b=0;for(c=this.vertices.length;b<c;b++)e[b]=new THREE.Vector3;b=0;for(c=this.faces.length;b<c;b++)d=this.faces[b],d instanceof THREE.Face3?d.vertexNormals=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3]:d instanceof THREE.Face4&& +(d.vertexNormals=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3])}else{e=this.__tmpVertices;b=0;for(c=this.vertices.length;b<c;b++)e[b].set(0,0,0)}if(a){var f,g,h,i=new THREE.Vector3,k=new THREE.Vector3,l=new THREE.Vector3,m=new THREE.Vector3,n=new THREE.Vector3;b=0;for(c=this.faces.length;b<c;b++)d=this.faces[b],d instanceof THREE.Face3?(a=this.vertices[d.a],f=this.vertices[d.b],g=this.vertices[d.c],i.subVectors(g,f),k.subVectors(a,f),i.cross(k),e[d.a].add(i),e[d.b].add(i), +e[d.c].add(i)):d instanceof THREE.Face4&&(a=this.vertices[d.a],f=this.vertices[d.b],g=this.vertices[d.c],h=this.vertices[d.d],l.subVectors(h,f),k.subVectors(a,f),l.cross(k),e[d.a].add(l),e[d.b].add(l),e[d.d].add(l),m.subVectors(h,g),n.subVectors(f,g),m.cross(n),e[d.b].add(m),e[d.c].add(m),e[d.d].add(m))}else{b=0;for(c=this.faces.length;b<c;b++)d=this.faces[b],d instanceof THREE.Face3?(e[d.a].add(d.normal),e[d.b].add(d.normal),e[d.c].add(d.normal)):d instanceof THREE.Face4&&(e[d.a].add(d.normal),e[d.b].add(d.normal), +e[d.c].add(d.normal),e[d.d].add(d.normal))}b=0;for(c=this.vertices.length;b<c;b++)e[b].normalize();b=0;for(c=this.faces.length;b<c;b++)d=this.faces[b],d instanceof THREE.Face3?(d.vertexNormals[0].copy(e[d.a]),d.vertexNormals[1].copy(e[d.b]),d.vertexNormals[2].copy(e[d.c])):d instanceof THREE.Face4&&(d.vertexNormals[0].copy(e[d.a]),d.vertexNormals[1].copy(e[d.b]),d.vertexNormals[2].copy(e[d.c]),d.vertexNormals[3].copy(e[d.d]))},computeMorphNormals:function(){var a,b,c,d,e;c=0;for(d=this.faces.length;c< +d;c++){e=this.faces[c];e.__originalFaceNormal?e.__originalFaceNormal.copy(e.normal):e.__originalFaceNormal=e.normal.clone();e.__originalVertexNormals||(e.__originalVertexNormals=[]);a=0;for(b=e.vertexNormals.length;a<b;a++)e.__originalVertexNormals[a]?e.__originalVertexNormals[a].copy(e.vertexNormals[a]):e.__originalVertexNormals[a]=e.vertexNormals[a].clone()}var f=new THREE.Geometry;f.faces=this.faces;a=0;for(b=this.morphTargets.length;a<b;a++){if(!this.morphNormals[a]){this.morphNormals[a]={};this.morphNormals[a].faceNormals= +[];this.morphNormals[a].vertexNormals=[];var g=this.morphNormals[a].faceNormals,h=this.morphNormals[a].vertexNormals,i,k;c=0;for(d=this.faces.length;c<d;c++)e=this.faces[c],i=new THREE.Vector3,k=e instanceof THREE.Face3?{a:new THREE.Vector3,b:new THREE.Vector3,c:new THREE.Vector3}:{a:new THREE.Vector3,b:new THREE.Vector3,c:new THREE.Vector3,d:new THREE.Vector3},g.push(i),h.push(k)}g=this.morphNormals[a];f.vertices=this.morphTargets[a].vertices;f.computeFaceNormals();f.computeVertexNormals();c=0;for(d= +this.faces.length;c<d;c++)e=this.faces[c],i=g.faceNormals[c],k=g.vertexNormals[c],i.copy(e.normal),e instanceof THREE.Face3?(k.a.copy(e.vertexNormals[0]),k.b.copy(e.vertexNormals[1]),k.c.copy(e.vertexNormals[2])):(k.a.copy(e.vertexNormals[0]),k.b.copy(e.vertexNormals[1]),k.c.copy(e.vertexNormals[2]),k.d.copy(e.vertexNormals[3]))}c=0;for(d=this.faces.length;c<d;c++)e=this.faces[c],e.normal=e.__originalFaceNormal,e.vertexNormals=e.__originalVertexNormals},computeTangents:function(){function a(a,b,c, +d,e,f,x){h=a.vertices[b];i=a.vertices[c];k=a.vertices[d];l=g[e];m=g[f];n=g[x];s=i.x-h.x;r=k.x-h.x;p=i.y-h.y;q=k.y-h.y;y=i.z-h.z;v=k.z-h.z;z=m.x-l.x;t=n.x-l.x;A=m.y-l.y;I=n.y-l.y;C=1/(z*I-t*A);E.set((I*s-A*r)*C,(I*p-A*q)*C,(I*y-A*v)*C);H.set((z*r-t*s)*C,(z*q-t*p)*C,(z*v-t*y)*C);G[b].add(E);G[c].add(E);G[d].add(E);J[b].add(H);J[c].add(H);J[d].add(H)}var b,c,d,e,f,g,h,i,k,l,m,n,s,r,p,q,y,v,z,t,A,I,C,x,G=[],J=[],E=new THREE.Vector3,H=new THREE.Vector3,B=new THREE.Vector3,W=new THREE.Vector3,F=new THREE.Vector3; +b=0;for(c=this.vertices.length;b<c;b++)G[b]=new THREE.Vector3,J[b]=new THREE.Vector3;b=0;for(c=this.faces.length;b<c;b++)f=this.faces[b],g=this.faceVertexUvs[0][b],f instanceof THREE.Face3?a(this,f.a,f.b,f.c,0,1,2):f instanceof THREE.Face4&&(a(this,f.a,f.b,f.d,0,1,3),a(this,f.b,f.c,f.d,1,2,3));var K=["a","b","c","d"];b=0;for(c=this.faces.length;b<c;b++){f=this.faces[b];for(d=0;d<f.vertexNormals.length;d++)F.copy(f.vertexNormals[d]),e=f[K[d]],x=G[e],B.copy(x),B.sub(F.multiplyScalar(F.dot(x))).normalize(), +W.crossVectors(f.vertexNormals[d],x),e=W.dot(J[e]),e=0>e?-1:1,f.vertexTangents[d]=new THREE.Vector4(B.x,B.y,B.z,e)}this.hasTangents=!0},computeLineDistances:function(){for(var a=0,b=this.vertices,c=0,d=b.length;c<d;c++)0<c&&(a+=b[c].distanceTo(b[c-1])),this.lineDistances[c]=a},computeBoundingBox:function(){null===this.boundingBox&&(this.boundingBox=new THREE.Box3);this.boundingBox.setFromPoints(this.vertices)},computeBoundingSphere:function(){null===this.boundingSphere&&(this.boundingSphere=new THREE.Sphere); +this.boundingSphere.setFromCenterAndPoints(this.boundingSphere.center,this.vertices)},mergeVertices:function(){var a={},b=[],c=[],d,e=Math.pow(10,4),f,g,h,i,k;this.__tmpVertices=void 0;f=0;for(g=this.vertices.length;f<g;f++)d=this.vertices[f],d=[Math.round(d.x*e),Math.round(d.y*e),Math.round(d.z*e)].join("_"),void 0===a[d]?(a[d]=f,b.push(this.vertices[f]),c[f]=b.length-1):c[f]=c[a[d]];e=[];f=0;for(g=this.faces.length;f<g;f++)if(a=this.faces[f],a instanceof THREE.Face3){a.a=c[a.a];a.b=c[a.b];a.c=c[a.c]; +h=[a.a,a.b,a.c];d=-1;for(i=0;3>i;i++)if(h[i]==h[(i+1)%3]){e.push(f);break}}else if(a instanceof THREE.Face4){a.a=c[a.a];a.b=c[a.b];a.c=c[a.c];a.d=c[a.d];h=[a.a,a.b,a.c,a.d];d=-1;for(i=0;4>i;i++)h[i]==h[(i+1)%4]&&(0<=d&&e.push(f),d=i);if(0<=d){h.splice(d,1);var l=new THREE.Face3(h[0],h[1],h[2],a.normal,a.color,a.materialIndex);h=0;for(i=this.faceVertexUvs.length;h<i;h++)(k=this.faceVertexUvs[h][f])&&k.splice(d,1);a.vertexNormals&&0<a.vertexNormals.length&&(l.vertexNormals=a.vertexNormals,l.vertexNormals.splice(d, +1));a.vertexColors&&0<a.vertexColors.length&&(l.vertexColors=a.vertexColors,l.vertexColors.splice(d,1));this.faces[f]=l}}for(f=e.length-1;0<=f;f--){this.faces.splice(f,1);h=0;for(i=this.faceVertexUvs.length;h<i;h++)this.faceVertexUvs[h].splice(f,1)}c=this.vertices.length-b.length;this.vertices=b;return c},clone:function(){for(var a=new THREE.Geometry,b=this.vertices,c=0,d=b.length;c<d;c++)a.vertices.push(b[c].clone());b=this.faces;c=0;for(d=b.length;c<d;c++)a.faces.push(b[c].clone());b=this.faceVertexUvs[0]; +c=0;for(d=b.length;c<d;c++){for(var e=b[c],f=[],g=0,h=e.length;g<h;g++)f.push(new THREE.Vector2(e[g].x,e[g].y));a.faceVertexUvs[0].push(f)}return a},dispose:function(){this.dispatchEvent({type:"dispose"})}};THREE.GeometryIdCount=0;THREE.BufferGeometry=function(){THREE.EventDispatcher.call(this);this.id=THREE.GeometryIdCount++;this.attributes={};this.dynamic=!1;this.offsets=[];this.boundingSphere=this.boundingBox=null;this.hasTangents=!1;this.morphTargets=[]}; +THREE.BufferGeometry.prototype={constructor:THREE.BufferGeometry,applyMatrix:function(a){var b,c;this.attributes.position&&(b=this.attributes.position.array);this.attributes.normal&&(c=this.attributes.normal.array);void 0!==b&&(a.multiplyVector3Array(b),this.verticesNeedUpdate=!0);void 0!==c&&(b=new THREE.Matrix3,b.getInverse(a).transpose(),b.multiplyVector3Array(c),this.normalizeNormals(),this.normalsNeedUpdate=!0)},computeBoundingBox:function(){null===this.boundingBox&&(this.boundingBox=new THREE.Box3); +var a=this.attributes.position.array;if(a){var b=this.boundingBox,c,d,e;3<=a.length&&(b.min.x=b.max.x=a[0],b.min.y=b.max.y=a[1],b.min.z=b.max.z=a[2]);for(var f=3,g=a.length;f<g;f+=3)c=a[f],d=a[f+1],e=a[f+2],c<b.min.x?b.min.x=c:c>b.max.x&&(b.max.x=c),d<b.min.y?b.min.y=d:d>b.max.y&&(b.max.y=d),e<b.min.z?b.min.z=e:e>b.max.z&&(b.max.z=e)}if(void 0===a||0===a.length)this.boundingBox.min.set(0,0,0),this.boundingBox.max.set(0,0,0)},computeBoundingSphere:function(){null===this.boundingSphere&&(this.boundingSphere= +new THREE.Sphere);var a=this.attributes.position.array;if(a){for(var b,c=0,d,e,f=0,g=a.length;f<g;f+=3)b=a[f],d=a[f+1],e=a[f+2],b=b*b+d*d+e*e,b>c&&(c=b);this.boundingSphere.radius=Math.sqrt(c)}},computeVertexNormals:function(){if(this.attributes.position){var a,b,c,d;a=this.attributes.position.array.length;if(void 0===this.attributes.normal)this.attributes.normal={itemSize:3,array:new Float32Array(a),numItems:a};else{a=0;for(b=this.attributes.normal.array.length;a<b;a++)this.attributes.normal.array[a]= +0}var e=this.attributes.position.array,f=this.attributes.normal.array,g,h,i,k,l,m,n=new THREE.Vector3,s=new THREE.Vector3,r=new THREE.Vector3,p=new THREE.Vector3,q=new THREE.Vector3;if(this.attributes.index){var y=this.attributes.index.array,v=this.offsets;c=0;for(d=v.length;c<d;++c){b=v[c].start;g=v[c].count;var z=v[c].index;a=b;for(b+=g;a<b;a+=3)g=z+y[a],h=z+y[a+1],i=z+y[a+2],k=e[3*g],l=e[3*g+1],m=e[3*g+2],n.set(k,l,m),k=e[3*h],l=e[3*h+1],m=e[3*h+2],s.set(k,l,m),k=e[3*i],l=e[3*i+1],m=e[3*i+2],r.set(k, +l,m),p.subVectors(r,s),q.subVectors(n,s),p.cross(q),f[3*g]+=p.x,f[3*g+1]+=p.y,f[3*g+2]+=p.z,f[3*h]+=p.x,f[3*h+1]+=p.y,f[3*h+2]+=p.z,f[3*i]+=p.x,f[3*i+1]+=p.y,f[3*i+2]+=p.z}}else{a=0;for(b=e.length;a<b;a+=9)k=e[a],l=e[a+1],m=e[a+2],n.set(k,l,m),k=e[a+3],l=e[a+4],m=e[a+5],s.set(k,l,m),k=e[a+6],l=e[a+7],m=e[a+8],r.set(k,l,m),p.subVectors(r,s),q.subVectors(n,s),p.cross(q),f[a]=p.x,f[a+1]=p.y,f[a+2]=p.z,f[a+3]=p.x,f[a+4]=p.y,f[a+5]=p.z,f[a+6]=p.x,f[a+7]=p.y,f[a+8]=p.z}this.normalizeNormals();this.normalsNeedUpdate= +!0}},normalizeNormals:function(){for(var a=this.attributes.normal.array,b,c,d,e=0,f=a.length;e<f;e+=3)b=a[e],c=a[e+1],d=a[e+2],b=1/Math.sqrt(b*b+c*c+d*d),a[e]*=b,a[e+1]*=b,a[e+2]*=b},computeTangents:function(){function a(a){Ca.x=d[3*a];Ca.y=d[3*a+1];Ca.z=d[3*a+2];$a.copy(Ca);ca=i[a];U.copy(ca);U.sub(Ca.multiplyScalar(Ca.dot(ca))).normalize();fa.crossVectors($a,ca);qa=fa.dot(k[a]);M=0>qa?-1:1;h[4*a]=U.x;h[4*a+1]=U.y;h[4*a+2]=U.z;h[4*a+3]=M}if(void 0===this.attributes.index||void 0===this.attributes.position|| +void 0===this.attributes.normal||void 0===this.attributes.uv)console.warn("Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()");else{var b=this.attributes.index.array,c=this.attributes.position.array,d=this.attributes.normal.array,e=this.attributes.uv.array,f=c.length/3;if(void 0===this.attributes.tangent){var g=4*f;this.attributes.tangent={itemSize:4,array:new Float32Array(g),numItems:g}}for(var h=this.attributes.tangent.array,i=[],k=[],g=0;g<f;g++)i[g]= +new THREE.Vector3,k[g]=new THREE.Vector3;var l,m,n,s,r,p,q,y,v,z,t,A,I,C,x,f=new THREE.Vector3,g=new THREE.Vector3,G,J,E,H,B,W,F,K=this.offsets;E=0;for(H=K.length;E<H;++E){J=K[E].start;B=K[E].count;var L=K[E].index;G=J;for(J+=B;G<J;G+=3)B=L+b[G],W=L+b[G+1],F=L+b[G+2],l=c[3*B],m=c[3*B+1],n=c[3*B+2],s=c[3*W],r=c[3*W+1],p=c[3*W+2],q=c[3*F],y=c[3*F+1],v=c[3*F+2],z=e[2*B],t=e[2*B+1],A=e[2*W],I=e[2*W+1],C=e[2*F],x=e[2*F+1],s-=l,l=q-l,r-=m,m=y-m,p-=n,n=v-n,A-=z,z=C-z,I-=t,t=x-t,x=1/(A*t-z*I),f.set((t*s- +I*l)*x,(t*r-I*m)*x,(t*p-I*n)*x),g.set((A*l-z*s)*x,(A*m-z*r)*x,(A*n-z*p)*x),i[B].add(f),i[W].add(f),i[F].add(f),k[B].add(g),k[W].add(g),k[F].add(g)}var U=new THREE.Vector3,fa=new THREE.Vector3,Ca=new THREE.Vector3,$a=new THREE.Vector3,M,ca,qa;E=0;for(H=K.length;E<H;++E){J=K[E].start;B=K[E].count;L=K[E].index;G=J;for(J+=B;G<J;G+=3)B=L+b[G],W=L+b[G+1],F=L+b[G+2],a(B),a(W),a(F)}this.tangentsNeedUpdate=this.hasTangents=!0}},dispose:function(){this.dispatchEvent({type:"dispose"})}};THREE.Camera=function(){THREE.Object3D.call(this);this.matrixWorldInverse=new THREE.Matrix4;this.projectionMatrix=new THREE.Matrix4;this.projectionMatrixInverse=new THREE.Matrix4};THREE.Camera.prototype=Object.create(THREE.Object3D.prototype);THREE.Camera.prototype.lookAt=function(a){this.matrix.lookAt(this.position,a,this.up);!0===this.rotationAutoUpdate&&(!1===this.useQuaternion?this.rotation.setEulerFromRotationMatrix(this.matrix,this.eulerOrder):this.quaternion.copy(this.matrix.decompose()[1]))};THREE.OrthographicCamera=function(a,b,c,d,e,f){THREE.Camera.call(this);this.left=a;this.right=b;this.top=c;this.bottom=d;this.near=void 0!==e?e:0.1;this.far=void 0!==f?f:2E3;this.updateProjectionMatrix()};THREE.OrthographicCamera.prototype=Object.create(THREE.Camera.prototype);THREE.OrthographicCamera.prototype.updateProjectionMatrix=function(){this.projectionMatrix.makeOrthographic(this.left,this.right,this.top,this.bottom,this.near,this.far)};THREE.PerspectiveCamera=function(a,b,c,d){THREE.Camera.call(this);this.fov=void 0!==a?a:50;this.aspect=void 0!==b?b:1;this.near=void 0!==c?c:0.1;this.far=void 0!==d?d:2E3;this.updateProjectionMatrix()};THREE.PerspectiveCamera.prototype=Object.create(THREE.Camera.prototype);THREE.PerspectiveCamera.prototype.setLens=function(a,b){void 0===b&&(b=24);this.fov=2*THREE.Math.radToDeg(Math.atan(b/(2*a)));this.updateProjectionMatrix()}; +THREE.PerspectiveCamera.prototype.setViewOffset=function(a,b,c,d,e,f){this.fullWidth=a;this.fullHeight=b;this.x=c;this.y=d;this.width=e;this.height=f;this.updateProjectionMatrix()}; +THREE.PerspectiveCamera.prototype.updateProjectionMatrix=function(){if(this.fullWidth){var a=this.fullWidth/this.fullHeight,b=Math.tan(THREE.Math.degToRad(0.5*this.fov))*this.near,c=-b,d=a*c,a=Math.abs(a*b-d),c=Math.abs(b-c);this.projectionMatrix.makeFrustum(d+this.x*a/this.fullWidth,d+(this.x+this.width)*a/this.fullWidth,b-(this.y+this.height)*c/this.fullHeight,b-this.y*c/this.fullHeight,this.near,this.far)}else this.projectionMatrix.makePerspective(this.fov,this.aspect,this.near,this.far)};THREE.Light=function(a){THREE.Object3D.call(this);this.color=new THREE.Color(a)};THREE.Light.prototype=Object.create(THREE.Object3D.prototype);THREE.AmbientLight=function(a){THREE.Light.call(this,a)};THREE.AmbientLight.prototype=Object.create(THREE.Light.prototype);THREE.AreaLight=function(a,b){THREE.Light.call(this,a);this.normal=new THREE.Vector3(0,-1,0);this.right=new THREE.Vector3(1,0,0);this.intensity=void 0!==b?b:1;this.height=this.width=1;this.constantAttenuation=1.5;this.linearAttenuation=0.5;this.quadraticAttenuation=0.1};THREE.AreaLight.prototype=Object.create(THREE.Light.prototype);THREE.DirectionalLight=function(a,b){THREE.Light.call(this,a);this.position=new THREE.Vector3(0,1,0);this.target=new THREE.Object3D;this.intensity=void 0!==b?b:1;this.onlyShadow=this.castShadow=!1;this.shadowCameraNear=50;this.shadowCameraFar=5E3;this.shadowCameraLeft=-500;this.shadowCameraTop=this.shadowCameraRight=500;this.shadowCameraBottom=-500;this.shadowCameraVisible=!1;this.shadowBias=0;this.shadowDarkness=0.5;this.shadowMapHeight=this.shadowMapWidth=512;this.shadowCascade=!1;this.shadowCascadeOffset= +new THREE.Vector3(0,0,-1E3);this.shadowCascadeCount=2;this.shadowCascadeBias=[0,0,0];this.shadowCascadeWidth=[512,512,512];this.shadowCascadeHeight=[512,512,512];this.shadowCascadeNearZ=[-1,0.99,0.998];this.shadowCascadeFarZ=[0.99,0.998,1];this.shadowCascadeArray=[];this.shadowMatrix=this.shadowCamera=this.shadowMapSize=this.shadowMap=null};THREE.DirectionalLight.prototype=Object.create(THREE.Light.prototype);THREE.HemisphereLight=function(a,b,c){THREE.Light.call(this,a);this.groundColor=new THREE.Color(b);this.position=new THREE.Vector3(0,100,0);this.intensity=void 0!==c?c:1};THREE.HemisphereLight.prototype=Object.create(THREE.Light.prototype);THREE.PointLight=function(a,b,c){THREE.Light.call(this,a);this.position=new THREE.Vector3(0,0,0);this.intensity=void 0!==b?b:1;this.distance=void 0!==c?c:0};THREE.PointLight.prototype=Object.create(THREE.Light.prototype);THREE.SpotLight=function(a,b,c,d,e){THREE.Light.call(this,a);this.position=new THREE.Vector3(0,1,0);this.target=new THREE.Object3D;this.intensity=void 0!==b?b:1;this.distance=void 0!==c?c:0;this.angle=void 0!==d?d:Math.PI/2;this.exponent=void 0!==e?e:10;this.onlyShadow=this.castShadow=!1;this.shadowCameraNear=50;this.shadowCameraFar=5E3;this.shadowCameraFov=50;this.shadowCameraVisible=!1;this.shadowBias=0;this.shadowDarkness=0.5;this.shadowMapHeight=this.shadowMapWidth=512;this.shadowMatrix=this.shadowCamera= +this.shadowMapSize=this.shadowMap=null};THREE.SpotLight.prototype=Object.create(THREE.Light.prototype);THREE.Loader=function(a){this.statusDomElement=(this.showStatus=a)?THREE.Loader.prototype.addStatusElement():null;this.onLoadStart=function(){};this.onLoadProgress=function(){};this.onLoadComplete=function(){}}; +THREE.Loader.prototype={constructor:THREE.Loader,crossOrigin:"anonymous",addStatusElement:function(){var a=document.createElement("div");a.style.position="absolute";a.style.right="0px";a.style.top="0px";a.style.fontSize="0.8em";a.style.textAlign="left";a.style.background="rgba(0,0,0,0.25)";a.style.color="#fff";a.style.width="120px";a.style.padding="0.5em 0.5em 0.5em 0.5em";a.style.zIndex=1E3;a.innerHTML="Loading ...";return a},updateProgress:function(a){var b="Loaded ",b=a.total?b+((100*a.loaded/ +a.total).toFixed(0)+"%"):b+((a.loaded/1E3).toFixed(2)+" KB");this.statusDomElement.innerHTML=b},extractUrlBase:function(a){a=a.split("/");a.pop();return(1>a.length?".":a.join("/"))+"/"},initMaterials:function(a,b){for(var c=[],d=0;d<a.length;++d)c[d]=THREE.Loader.prototype.createMaterial(a[d],b);return c},needsTangents:function(a){for(var b=0,c=a.length;b<c;b++)if(a[b]instanceof THREE.ShaderMaterial)return!0;return!1},createMaterial:function(a,b){function c(a){a=Math.log(a)/Math.LN2;return Math.floor(a)== +a}function d(a){a=Math.log(a)/Math.LN2;return Math.pow(2,Math.round(a))}function e(a,e,f,h,i,k,q){var y=/\.dds$/i.test(f),v=b+"/"+f;if(y){var z=THREE.ImageUtils.loadCompressedTexture(v);a[e]=z}else z=document.createElement("canvas"),a[e]=new THREE.Texture(z);a[e].sourceFile=f;h&&(a[e].repeat.set(h[0],h[1]),1!==h[0]&&(a[e].wrapS=THREE.RepeatWrapping),1!==h[1]&&(a[e].wrapT=THREE.RepeatWrapping));i&&a[e].offset.set(i[0],i[1]);k&&(f={repeat:THREE.RepeatWrapping,mirror:THREE.MirroredRepeatWrapping},void 0!== +f[k[0]]&&(a[e].wrapS=f[k[0]]),void 0!==f[k[1]]&&(a[e].wrapT=f[k[1]]));q&&(a[e].anisotropy=q);if(!y){var t=a[e],a=new Image;a.onload=function(){if(!c(this.width)||!c(this.height)){var a=d(this.width),b=d(this.height);t.image.width=a;t.image.height=b;t.image.getContext("2d").drawImage(this,0,0,a,b)}else t.image=this;t.needsUpdate=!0};a.crossOrigin=g.crossOrigin;a.src=v}}function f(a){return(255*a[0]<<16)+(255*a[1]<<8)+255*a[2]}var g=this,h="MeshLambertMaterial",i={color:15658734,opacity:1,map:null, +lightMap:null,normalMap:null,bumpMap:null,wireframe:!1};if(a.shading){var k=a.shading.toLowerCase();"phong"===k?h="MeshPhongMaterial":"basic"===k&&(h="MeshBasicMaterial")}void 0!==a.blending&&void 0!==THREE[a.blending]&&(i.blending=THREE[a.blending]);if(void 0!==a.transparent||1>a.opacity)i.transparent=a.transparent;void 0!==a.depthTest&&(i.depthTest=a.depthTest);void 0!==a.depthWrite&&(i.depthWrite=a.depthWrite);void 0!==a.visible&&(i.visible=a.visible);void 0!==a.flipSided&&(i.side=THREE.BackSide); +void 0!==a.doubleSided&&(i.side=THREE.DoubleSide);void 0!==a.wireframe&&(i.wireframe=a.wireframe);void 0!==a.vertexColors&&("face"===a.vertexColors?i.vertexColors=THREE.FaceColors:a.vertexColors&&(i.vertexColors=THREE.VertexColors));a.colorDiffuse?i.color=f(a.colorDiffuse):a.DbgColor&&(i.color=a.DbgColor);a.colorSpecular&&(i.specular=f(a.colorSpecular));a.colorAmbient&&(i.ambient=f(a.colorAmbient));a.transparency&&(i.opacity=a.transparency);a.specularCoef&&(i.shininess=a.specularCoef);a.mapDiffuse&& +b&&e(i,"map",a.mapDiffuse,a.mapDiffuseRepeat,a.mapDiffuseOffset,a.mapDiffuseWrap,a.mapDiffuseAnisotropy);a.mapLight&&b&&e(i,"lightMap",a.mapLight,a.mapLightRepeat,a.mapLightOffset,a.mapLightWrap,a.mapLightAnisotropy);a.mapBump&&b&&e(i,"bumpMap",a.mapBump,a.mapBumpRepeat,a.mapBumpOffset,a.mapBumpWrap,a.mapBumpAnisotropy);a.mapNormal&&b&&e(i,"normalMap",a.mapNormal,a.mapNormalRepeat,a.mapNormalOffset,a.mapNormalWrap,a.mapNormalAnisotropy);a.mapSpecular&&b&&e(i,"specularMap",a.mapSpecular,a.mapSpecularRepeat, +a.mapSpecularOffset,a.mapSpecularWrap,a.mapSpecularAnisotropy);a.mapBumpScale&&(i.bumpScale=a.mapBumpScale);a.mapNormal?(h=THREE.ShaderLib.normalmap,k=THREE.UniformsUtils.clone(h.uniforms),k.tNormal.value=i.normalMap,a.mapNormalFactor&&k.uNormalScale.value.set(a.mapNormalFactor,a.mapNormalFactor),i.map&&(k.tDiffuse.value=i.map,k.enableDiffuse.value=!0),i.specularMap&&(k.tSpecular.value=i.specularMap,k.enableSpecular.value=!0),i.lightMap&&(k.tAO.value=i.lightMap,k.enableAO.value=!0),k.uDiffuseColor.value.setHex(i.color), +k.uSpecularColor.value.setHex(i.specular),k.uAmbientColor.value.setHex(i.ambient),k.uShininess.value=i.shininess,void 0!==i.opacity&&(k.uOpacity.value=i.opacity),h=new THREE.ShaderMaterial({fragmentShader:h.fragmentShader,vertexShader:h.vertexShader,uniforms:k,lights:!0,fog:!0}),i.transparent&&(h.transparent=!0)):h=new THREE[h](i);void 0!==a.DbgName&&(h.name=a.DbgName);return h}};THREE.ImageLoader=function(){THREE.EventDispatcher.call(this);this.crossOrigin=null};THREE.ImageLoader.prototype={constructor:THREE.ImageLoader,load:function(a,b){var c=this;void 0===b&&(b=new Image);b.addEventListener("load",function(){c.dispatchEvent({type:"load",content:b})},!1);b.addEventListener("error",function(){c.dispatchEvent({type:"error",message:"Couldn't load URL ["+a+"]"})},!1);c.crossOrigin&&(b.crossOrigin=c.crossOrigin);b.src=a}};THREE.JSONLoader=function(a){THREE.Loader.call(this,a);this.withCredentials=!1};THREE.JSONLoader.prototype=Object.create(THREE.Loader.prototype);THREE.JSONLoader.prototype.load=function(a,b,c){c=c&&"string"===typeof c?c:this.extractUrlBase(a);this.onLoadStart();this.loadAjaxJSON(this,a,b,c)}; +THREE.JSONLoader.prototype.loadAjaxJSON=function(a,b,c,d,e){var f=new XMLHttpRequest,g=0;f.onreadystatechange=function(){if(f.readyState===f.DONE)if(200===f.status||0===f.status){if(f.responseText){var h=JSON.parse(f.responseText);a.createModel(h,c,d)}else console.warn("THREE.JSONLoader: ["+b+"] seems to be unreachable or file there is empty");a.onLoadComplete()}else console.error("THREE.JSONLoader: Couldn't load ["+b+"] ["+f.status+"]");else f.readyState===f.LOADING?e&&(0===g&&(g=f.getResponseHeader("Content-Length")), +e({total:g,loaded:f.responseText.length})):f.readyState===f.HEADERS_RECEIVED&&(g=f.getResponseHeader("Content-Length"))};f.open("GET",b,!0);f.withCredentials=this.withCredentials;f.send(null)}; +THREE.JSONLoader.prototype.createModel=function(a,b,c){var d=new THREE.Geometry,e=void 0!==a.scale?1/a.scale:1,f,g,h,i,k,l,m,n,s,r,p,q,y,v,z,t=a.faces;r=a.vertices;var A=a.normals,I=a.colors,C=0;for(f=0;f<a.uvs.length;f++)a.uvs[f].length&&C++;for(f=0;f<C;f++)d.faceUvs[f]=[],d.faceVertexUvs[f]=[];i=0;for(k=r.length;i<k;)l=new THREE.Vector3,l.x=r[i++]*e,l.y=r[i++]*e,l.z=r[i++]*e,d.vertices.push(l);i=0;for(k=t.length;i<k;){r=t[i++];l=r&1;h=r&2;f=r&4;g=r&8;n=r&16;m=r&32;p=r&64;r&=128;l?(q=new THREE.Face4, +q.a=t[i++],q.b=t[i++],q.c=t[i++],q.d=t[i++],l=4):(q=new THREE.Face3,q.a=t[i++],q.b=t[i++],q.c=t[i++],l=3);h&&(h=t[i++],q.materialIndex=h);h=d.faces.length;if(f)for(f=0;f<C;f++)y=a.uvs[f],s=t[i++],z=y[2*s],s=y[2*s+1],d.faceUvs[f][h]=new THREE.Vector2(z,s);if(g)for(f=0;f<C;f++){y=a.uvs[f];v=[];for(g=0;g<l;g++)s=t[i++],z=y[2*s],s=y[2*s+1],v[g]=new THREE.Vector2(z,s);d.faceVertexUvs[f][h]=v}n&&(n=3*t[i++],g=new THREE.Vector3,g.x=A[n++],g.y=A[n++],g.z=A[n],q.normal=g);if(m)for(f=0;f<l;f++)n=3*t[i++],g= +new THREE.Vector3,g.x=A[n++],g.y=A[n++],g.z=A[n],q.vertexNormals.push(g);p&&(m=t[i++],m=new THREE.Color(I[m]),q.color=m);if(r)for(f=0;f<l;f++)m=t[i++],m=new THREE.Color(I[m]),q.vertexColors.push(m);d.faces.push(q)}if(a.skinWeights){i=0;for(k=a.skinWeights.length;i<k;i+=2)t=a.skinWeights[i],A=a.skinWeights[i+1],d.skinWeights.push(new THREE.Vector4(t,A,0,0))}if(a.skinIndices){i=0;for(k=a.skinIndices.length;i<k;i+=2)t=a.skinIndices[i],A=a.skinIndices[i+1],d.skinIndices.push(new THREE.Vector4(t,A,0,0))}d.bones= +a.bones;d.animation=a.animation;if(void 0!==a.morphTargets){i=0;for(k=a.morphTargets.length;i<k;i++){d.morphTargets[i]={};d.morphTargets[i].name=a.morphTargets[i].name;d.morphTargets[i].vertices=[];I=d.morphTargets[i].vertices;C=a.morphTargets[i].vertices;t=0;for(A=C.length;t<A;t+=3)r=new THREE.Vector3,r.x=C[t]*e,r.y=C[t+1]*e,r.z=C[t+2]*e,I.push(r)}}if(void 0!==a.morphColors){i=0;for(k=a.morphColors.length;i<k;i++){d.morphColors[i]={};d.morphColors[i].name=a.morphColors[i].name;d.morphColors[i].colors= +[];A=d.morphColors[i].colors;I=a.morphColors[i].colors;e=0;for(t=I.length;e<t;e+=3)C=new THREE.Color(16755200),C.setRGB(I[e],I[e+1],I[e+2]),A.push(C)}}d.computeCentroids();d.computeFaceNormals();a=this.initMaterials(a.materials,c);this.needsTangents(a)&&d.computeTangents();b(d,a)};THREE.LoadingMonitor=function(){THREE.EventDispatcher.call(this);var a=this,b=0,c=0,d=function(){b++;a.dispatchEvent({type:"progress",loaded:b,total:c});b===c&&a.dispatchEvent({type:"load"})};this.add=function(a){c++;a.addEventListener("load",d,!1)}};THREE.SceneLoader=function(){this.onLoadStart=function(){};this.onLoadProgress=function(){};this.onLoadComplete=function(){};this.callbackSync=function(){};this.callbackProgress=function(){};this.geometryHandlerMap={};this.hierarchyHandlerMap={};this.addGeometryHandler("ascii",THREE.JSONLoader)};THREE.SceneLoader.prototype.constructor=THREE.SceneLoader; +THREE.SceneLoader.prototype.load=function(a,b){var c=this,d=new XMLHttpRequest;d.onreadystatechange=function(){if(4===d.readyState)if(200===d.status||0===d.status){var e=JSON.parse(d.responseText);c.parse(e,b,a)}else console.error("THREE.SceneLoader: Couldn't load ["+a+"] ["+d.status+"]")};d.open("GET",a,!0);d.send(null)};THREE.SceneLoader.prototype.addGeometryHandler=function(a,b){this.geometryHandlerMap[a]={loaderClass:b}}; +THREE.SceneLoader.prototype.addHierarchyHandler=function(a,b){this.hierarchyHandlerMap[a]={loaderClass:b}}; +THREE.SceneLoader.prototype.parse=function(a,b,c){function d(a,b){return"relativeToHTML"==b?a:m+"/"+a}function e(){f(x.scene,J.objects)}function f(a,b){var c,e,g,i,k,m,p;for(p in b)if(void 0===x.objects[p]){var q=b[p],t=null;if(q.type&&q.type in l.hierarchyHandlerMap){if(void 0===q.loading){e={type:1,url:1,material:1,position:1,rotation:1,scale:1,visible:1,children:1,properties:1,skin:1,morph:1,mirroredLoop:1,duration:1};g={};for(var B in q)B in e||(g[B]=q[B]);s=x.materials[q.material];q.loading= +!0;e=l.hierarchyHandlerMap[q.type].loaderObject;e.options?e.load(d(q.url,J.urlBaseType),h(p,a,s,q)):e.load(d(q.url,J.urlBaseType),h(p,a,s,q),g)}}else if(void 0!==q.geometry){if(n=x.geometries[q.geometry]){t=!1;s=x.materials[q.material];t=s instanceof THREE.ShaderMaterial;g=q.position;i=q.rotation;k=q.scale;c=q.matrix;m=q.quaternion;q.material||(s=new THREE.MeshFaceMaterial(x.face_materials[q.geometry]));s instanceof THREE.MeshFaceMaterial&&0===s.materials.length&&(s=new THREE.MeshFaceMaterial(x.face_materials[q.geometry])); +if(s instanceof THREE.MeshFaceMaterial)for(e=0;e<s.materials.length;e++)t=t||s.materials[e]instanceof THREE.ShaderMaterial;t&&n.computeTangents();q.skin?t=new THREE.SkinnedMesh(n,s):q.morph?(t=new THREE.MorphAnimMesh(n,s),void 0!==q.duration&&(t.duration=q.duration),void 0!==q.time&&(t.time=q.time),void 0!==q.mirroredLoop&&(t.mirroredLoop=q.mirroredLoop),s.morphNormals&&n.computeMorphNormals()):t=new THREE.Mesh(n,s);t.name=p;c?(t.matrixAutoUpdate=!1,t.matrix.set(c[0],c[1],c[2],c[3],c[4],c[5],c[6], +c[7],c[8],c[9],c[10],c[11],c[12],c[13],c[14],c[15])):(t.position.set(g[0],g[1],g[2]),m?(t.quaternion.set(m[0],m[1],m[2],m[3]),t.useQuaternion=!0):t.rotation.set(i[0],i[1],i[2]),t.scale.set(k[0],k[1],k[2]));t.visible=q.visible;t.castShadow=q.castShadow;t.receiveShadow=q.receiveShadow;a.add(t);x.objects[p]=t}}else"DirectionalLight"===q.type||"PointLight"===q.type||"AmbientLight"===q.type?(v=void 0!==q.color?q.color:16777215,z=void 0!==q.intensity?q.intensity:1,"DirectionalLight"===q.type?(g=q.direction, +y=new THREE.DirectionalLight(v,z),y.position.set(g[0],g[1],g[2]),q.target&&(G.push({object:y,targetName:q.target}),y.target=null)):"PointLight"===q.type?(g=q.position,e=q.distance,y=new THREE.PointLight(v,z,e),y.position.set(g[0],g[1],g[2])):"AmbientLight"===q.type&&(y=new THREE.AmbientLight(v)),a.add(y),y.name=p,x.lights[p]=y,x.objects[p]=y):"PerspectiveCamera"===q.type||"OrthographicCamera"===q.type?("PerspectiveCamera"===q.type?r=new THREE.PerspectiveCamera(q.fov,q.aspect,q.near,q.far):"OrthographicCamera"=== +q.type&&(r=new THREE.OrthographicCamera(q.left,q.right,q.top,q.bottom,q.near,q.far)),g=q.position,r.position.set(g[0],g[1],g[2]),a.add(r),r.name=p,x.cameras[p]=r,x.objects[p]=r):(g=q.position,i=q.rotation,k=q.scale,m=q.quaternion,t=new THREE.Object3D,t.name=p,t.position.set(g[0],g[1],g[2]),m?(t.quaternion.set(m[0],m[1],m[2],m[3]),t.useQuaternion=!0):t.rotation.set(i[0],i[1],i[2]),t.scale.set(k[0],k[1],k[2]),t.visible=void 0!==q.visible?q.visible:!1,a.add(t),x.objects[p]=t,x.empties[p]=t);if(t){if(void 0!== +q.properties)for(var C in q.properties)t.properties[C]=q.properties[C];if(void 0!==q.groups)for(e=0;e<q.groups.length;e++)g=q.groups[e],void 0===x.groups[g]&&(x.groups[g]=[]),x.groups[g].push(p);void 0!==q.children&&f(t,q.children)}}}function g(a){return function(b,c){x.geometries[a]=b;x.face_materials[a]=c;e();t-=1;l.onLoadComplete();k()}}function h(a,b,c,d){return function(f){var f=f.content?f.content:f.dae?f.scene:f,g=d.position,h=d.rotation,i=d.quaternion,n=d.scale;f.position.set(g[0],g[1],g[2]); +i?(f.quaternion.set(i[0],i[1],i[2],i[3]),f.useQuaternion=!0):f.rotation.set(h[0],h[1],h[2]);f.scale.set(n[0],n[1],n[2]);c&&f.traverse(function(a){a.material=c});var m=void 0!==d.visible?d.visible:!0;f.traverse(function(a){a.visible=m});b.add(f);f.name=a;x.objects[a]=f;e();t-=1;l.onLoadComplete();k()}}function i(a){return function(b,c){x.geometries[a]=b;x.face_materials[a]=c}}function k(){l.callbackProgress({totalModels:I,totalTextures:C,loadedModels:I-t,loadedTextures:C-A},x);l.onLoadProgress();if(0=== +t&&0===A){for(var a=0;a<G.length;a++){var c=G[a],d=x.objects[c.targetName];d?c.object.target=d:(c.object.target=new THREE.Object3D,x.scene.add(c.object.target));c.object.target.properties.targetInverse=c.object}b(x)}}var l=this,m=THREE.Loader.prototype.extractUrlBase(c),n,s,r,p,q,y,v,z,t,A,I,C,x,G=[],J=a,E;for(E in this.geometryHandlerMap)a=this.geometryHandlerMap[E].loaderClass,this.geometryHandlerMap[E].loaderObject=new a;for(E in this.hierarchyHandlerMap)a=this.hierarchyHandlerMap[E].loaderClass, +this.hierarchyHandlerMap[E].loaderObject=new a;A=t=0;x={scene:new THREE.Scene,geometries:{},face_materials:{},materials:{},textures:{},objects:{},cameras:{},lights:{},fogs:{},empties:{},groups:{}};if(J.transform&&(E=J.transform.position,a=J.transform.rotation,c=J.transform.scale,E&&x.scene.position.set(E[0],E[1],E[2]),a&&x.scene.rotation.set(a[0],a[1],a[2]),c&&x.scene.scale.set(c[0],c[1],c[2]),E||a||c))x.scene.updateMatrix(),x.scene.updateMatrixWorld();E=function(a){return function(){A-=a;k();l.onLoadComplete()}}; +for(var H in J.fogs)a=J.fogs[H],"linear"===a.type?p=new THREE.Fog(0,a.near,a.far):"exp2"===a.type&&(p=new THREE.FogExp2(0,a.density)),a=a.color,p.color.setRGB(a[0],a[1],a[2]),x.fogs[H]=p;for(var B in J.geometries)p=J.geometries[B],p.type in this.geometryHandlerMap&&(t+=1,l.onLoadStart());for(var W in J.objects)p=J.objects[W],p.type&&p.type in this.hierarchyHandlerMap&&(t+=1,l.onLoadStart());I=t;for(B in J.geometries)if(p=J.geometries[B],"cube"===p.type)n=new THREE.CubeGeometry(p.width,p.height,p.depth, +p.widthSegments,p.heightSegments,p.depthSegments),x.geometries[B]=n;else if("plane"===p.type)n=new THREE.PlaneGeometry(p.width,p.height,p.widthSegments,p.heightSegments),x.geometries[B]=n;else if("sphere"===p.type)n=new THREE.SphereGeometry(p.radius,p.widthSegments,p.heightSegments),x.geometries[B]=n;else if("cylinder"===p.type)n=new THREE.CylinderGeometry(p.topRad,p.botRad,p.height,p.radSegs,p.heightSegs),x.geometries[B]=n;else if("torus"===p.type)n=new THREE.TorusGeometry(p.radius,p.tube,p.segmentsR, +p.segmentsT),x.geometries[B]=n;else if("icosahedron"===p.type)n=new THREE.IcosahedronGeometry(p.radius,p.subdivisions),x.geometries[B]=n;else if(p.type in this.geometryHandlerMap){W={};for(q in p)"type"!==q&&"url"!==q&&(W[q]=p[q]);this.geometryHandlerMap[p.type].loaderObject.load(d(p.url,J.urlBaseType),g(B),W)}else"embedded"===p.type&&(W=J.embeds[p.id],W.metadata=J.metadata,W&&this.geometryHandlerMap.ascii.loaderObject.createModel(W,i(B),""));for(var F in J.textures)if(B=J.textures[F],B.url instanceof +Array){A+=B.url.length;for(q=0;q<B.url.length;q++)l.onLoadStart()}else A+=1,l.onLoadStart();C=A;for(F in J.textures){B=J.textures[F];void 0!==B.mapping&&void 0!==THREE[B.mapping]&&(B.mapping=new THREE[B.mapping]);if(B.url instanceof Array){W=B.url.length;p=[];for(q=0;q<W;q++)p[q]=d(B.url[q],J.urlBaseType);q=(q=/\.dds$/i.test(p[0]))?THREE.ImageUtils.loadCompressedTextureCube(p,B.mapping,E(W)):THREE.ImageUtils.loadTextureCube(p,B.mapping,E(W))}else q=/\.dds$/i.test(B.url),W=d(B.url,J.urlBaseType),p= +E(1),q=q?THREE.ImageUtils.loadCompressedTexture(W,B.mapping,p):THREE.ImageUtils.loadTexture(W,B.mapping,p),void 0!==THREE[B.minFilter]&&(q.minFilter=THREE[B.minFilter]),void 0!==THREE[B.magFilter]&&(q.magFilter=THREE[B.magFilter]),B.anisotropy&&(q.anisotropy=B.anisotropy),B.repeat&&(q.repeat.set(B.repeat[0],B.repeat[1]),1!==B.repeat[0]&&(q.wrapS=THREE.RepeatWrapping),1!==B.repeat[1]&&(q.wrapT=THREE.RepeatWrapping)),B.offset&&q.offset.set(B.offset[0],B.offset[1]),B.wrap&&(W={repeat:THREE.RepeatWrapping, +mirror:THREE.MirroredRepeatWrapping},void 0!==W[B.wrap[0]]&&(q.wrapS=W[B.wrap[0]]),void 0!==W[B.wrap[1]]&&(q.wrapT=W[B.wrap[1]]));x.textures[F]=q}var K,L;for(K in J.materials){F=J.materials[K];for(L in F.parameters)"envMap"===L||"map"===L||"lightMap"===L||"bumpMap"===L?F.parameters[L]=x.textures[F.parameters[L]]:"shading"===L?F.parameters[L]="flat"===F.parameters[L]?THREE.FlatShading:THREE.SmoothShading:"side"===L?F.parameters[L]="double"==F.parameters[L]?THREE.DoubleSide:"back"==F.parameters[L]? +THREE.BackSide:THREE.FrontSide:"blending"===L?F.parameters[L]=F.parameters[L]in THREE?THREE[F.parameters[L]]:THREE.NormalBlending:"combine"===L?F.parameters[L]=F.parameters[L]in THREE?THREE[F.parameters[L]]:THREE.MultiplyOperation:"vertexColors"===L?"face"==F.parameters[L]?F.parameters[L]=THREE.FaceColors:F.parameters[L]&&(F.parameters[L]=THREE.VertexColors):"wrapRGB"===L&&(E=F.parameters[L],F.parameters[L]=new THREE.Vector3(E[0],E[1],E[2]));void 0!==F.parameters.opacity&&1>F.parameters.opacity&& +(F.parameters.transparent=!0);F.parameters.normalMap?(E=THREE.ShaderLib.normalmap,B=THREE.UniformsUtils.clone(E.uniforms),q=F.parameters.color,W=F.parameters.specular,p=F.parameters.ambient,H=F.parameters.shininess,B.tNormal.value=x.textures[F.parameters.normalMap],F.parameters.normalScale&&B.uNormalScale.value.set(F.parameters.normalScale[0],F.parameters.normalScale[1]),F.parameters.map&&(B.tDiffuse.value=F.parameters.map,B.enableDiffuse.value=!0),F.parameters.envMap&&(B.tCube.value=F.parameters.envMap, +B.enableReflection.value=!0,B.uReflectivity.value=F.parameters.reflectivity),F.parameters.lightMap&&(B.tAO.value=F.parameters.lightMap,B.enableAO.value=!0),F.parameters.specularMap&&(B.tSpecular.value=x.textures[F.parameters.specularMap],B.enableSpecular.value=!0),F.parameters.displacementMap&&(B.tDisplacement.value=x.textures[F.parameters.displacementMap],B.enableDisplacement.value=!0,B.uDisplacementBias.value=F.parameters.displacementBias,B.uDisplacementScale.value=F.parameters.displacementScale), +B.uDiffuseColor.value.setHex(q),B.uSpecularColor.value.setHex(W),B.uAmbientColor.value.setHex(p),B.uShininess.value=H,F.parameters.opacity&&(B.uOpacity.value=F.parameters.opacity),s=new THREE.ShaderMaterial({fragmentShader:E.fragmentShader,vertexShader:E.vertexShader,uniforms:B,lights:!0,fog:!0})):s=new THREE[F.type](F.parameters);x.materials[K]=s}for(K in J.materials)if(F=J.materials[K],F.parameters.materials){L=[];for(q=0;q<F.parameters.materials.length;q++)L.push(x.materials[F.parameters.materials[q]]); +x.materials[K].materials=L}e();x.cameras&&J.defaults.camera&&(x.currentCamera=x.cameras[J.defaults.camera]);x.fogs&&J.defaults.fog&&(x.scene.fog=x.fogs[J.defaults.fog]);l.callbackSync(x);k()};THREE.TextureLoader=function(){THREE.EventDispatcher.call(this);this.crossOrigin=null};THREE.TextureLoader.prototype={constructor:THREE.TextureLoader,load:function(a){var b=this,c=new Image;c.addEventListener("load",function(){var a=new THREE.Texture(c);a.needsUpdate=!0;b.dispatchEvent({type:"load",content:a})},!1);c.addEventListener("error",function(){b.dispatchEvent({type:"error",message:"Couldn't load URL ["+a+"]"})},!1);b.crossOrigin&&(c.crossOrigin=b.crossOrigin);c.src=a}};THREE.Material=function(){THREE.EventDispatcher.call(this);this.id=THREE.MaterialIdCount++;this.name="";this.side=THREE.FrontSide;this.opacity=1;this.transparent=!1;this.blending=THREE.NormalBlending;this.blendSrc=THREE.SrcAlphaFactor;this.blendDst=THREE.OneMinusSrcAlphaFactor;this.blendEquation=THREE.AddEquation;this.depthWrite=this.depthTest=!0;this.polygonOffset=!1;this.alphaTest=this.polygonOffsetUnits=this.polygonOffsetFactor=0;this.overdraw=!1;this.needsUpdate=this.visible=!0}; +THREE.Material.prototype.setValues=function(a){if(void 0!==a)for(var b in a){var c=a[b];if(void 0===c)console.warn("THREE.Material: '"+b+"' parameter is undefined.");else if(b in this){var d=this[b];d instanceof THREE.Color&&c instanceof THREE.Color?d.copy(c):d instanceof THREE.Color?d.set(c):d instanceof THREE.Vector3&&c instanceof THREE.Vector3?d.copy(c):this[b]=c}}}; +THREE.Material.prototype.clone=function(a){void 0===a&&(a=new THREE.Material);a.name=this.name;a.side=this.side;a.opacity=this.opacity;a.transparent=this.transparent;a.blending=this.blending;a.blendSrc=this.blendSrc;a.blendDst=this.blendDst;a.blendEquation=this.blendEquation;a.depthTest=this.depthTest;a.depthWrite=this.depthWrite;a.polygonOffset=this.polygonOffset;a.polygonOffsetFactor=this.polygonOffsetFactor;a.polygonOffsetUnits=this.polygonOffsetUnits;a.alphaTest=this.alphaTest;a.overdraw=this.overdraw; +a.visible=this.visible;return a};THREE.Material.prototype.dispose=function(){this.dispatchEvent({type:"dispose"})};THREE.MaterialIdCount=0;THREE.LineBasicMaterial=function(a){THREE.Material.call(this);this.color=new THREE.Color(16777215);this.linewidth=1;this.linejoin=this.linecap="round";this.vertexColors=!1;this.fog=!0;this.setValues(a)};THREE.LineBasicMaterial.prototype=Object.create(THREE.Material.prototype); +THREE.LineBasicMaterial.prototype.clone=function(){var a=new THREE.LineBasicMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.linewidth=this.linewidth;a.linecap=this.linecap;a.linejoin=this.linejoin;a.vertexColors=this.vertexColors;a.fog=this.fog;return a};THREE.LineDashedMaterial=function(a){THREE.Material.call(this);this.color=new THREE.Color(16777215);this.scale=this.linewidth=1;this.dashSize=3;this.gapSize=1;this.vertexColors=!1;this.fog=!0;this.setValues(a)};THREE.LineDashedMaterial.prototype=Object.create(THREE.Material.prototype); +THREE.LineDashedMaterial.prototype.clone=function(){var a=new THREE.LineDashedMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.linewidth=this.linewidth;a.scale=this.scale;a.dashSize=this.dashSize;a.gapSize=this.gapSize;a.vertexColors=this.vertexColors;a.fog=this.fog;return a};THREE.MeshBasicMaterial=function(a){THREE.Material.call(this);this.color=new THREE.Color(16777215);this.envMap=this.specularMap=this.lightMap=this.map=null;this.combine=THREE.MultiplyOperation;this.reflectivity=1;this.refractionRatio=0.98;this.fog=!0;this.shading=THREE.SmoothShading;this.wireframe=!1;this.wireframeLinewidth=1;this.wireframeLinejoin=this.wireframeLinecap="round";this.vertexColors=THREE.NoColors;this.morphTargets=this.skinning=!1;this.setValues(a)}; +THREE.MeshBasicMaterial.prototype=Object.create(THREE.Material.prototype); +THREE.MeshBasicMaterial.prototype.clone=function(){var a=new THREE.MeshBasicMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.map=this.map;a.lightMap=this.lightMap;a.specularMap=this.specularMap;a.envMap=this.envMap;a.combine=this.combine;a.reflectivity=this.reflectivity;a.refractionRatio=this.refractionRatio;a.fog=this.fog;a.shading=this.shading;a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;a.wireframeLinecap=this.wireframeLinecap;a.wireframeLinejoin= +this.wireframeLinejoin;a.vertexColors=this.vertexColors;a.skinning=this.skinning;a.morphTargets=this.morphTargets;return a};THREE.MeshLambertMaterial=function(a){THREE.Material.call(this);this.color=new THREE.Color(16777215);this.ambient=new THREE.Color(16777215);this.emissive=new THREE.Color(0);this.wrapAround=!1;this.wrapRGB=new THREE.Vector3(1,1,1);this.envMap=this.specularMap=this.lightMap=this.map=null;this.combine=THREE.MultiplyOperation;this.reflectivity=1;this.refractionRatio=0.98;this.fog=!0;this.shading=THREE.SmoothShading;this.wireframe=!1;this.wireframeLinewidth=1;this.wireframeLinejoin=this.wireframeLinecap= +"round";this.vertexColors=THREE.NoColors;this.morphNormals=this.morphTargets=this.skinning=!1;this.setValues(a)};THREE.MeshLambertMaterial.prototype=Object.create(THREE.Material.prototype); +THREE.MeshLambertMaterial.prototype.clone=function(){var a=new THREE.MeshLambertMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.ambient.copy(this.ambient);a.emissive.copy(this.emissive);a.wrapAround=this.wrapAround;a.wrapRGB.copy(this.wrapRGB);a.map=this.map;a.lightMap=this.lightMap;a.specularMap=this.specularMap;a.envMap=this.envMap;a.combine=this.combine;a.reflectivity=this.reflectivity;a.refractionRatio=this.refractionRatio;a.fog=this.fog;a.shading=this.shading; +a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;a.wireframeLinecap=this.wireframeLinecap;a.wireframeLinejoin=this.wireframeLinejoin;a.vertexColors=this.vertexColors;a.skinning=this.skinning;a.morphTargets=this.morphTargets;a.morphNormals=this.morphNormals;return a};THREE.MeshPhongMaterial=function(a){THREE.Material.call(this);this.color=new THREE.Color(16777215);this.ambient=new THREE.Color(16777215);this.emissive=new THREE.Color(0);this.specular=new THREE.Color(1118481);this.shininess=30;this.metal=!1;this.perPixel=!0;this.wrapAround=!1;this.wrapRGB=new THREE.Vector3(1,1,1);this.bumpMap=this.lightMap=this.map=null;this.bumpScale=1;this.normalMap=null;this.normalScale=new THREE.Vector2(1,1);this.envMap=this.specularMap=null;this.combine=THREE.MultiplyOperation; +this.reflectivity=1;this.refractionRatio=0.98;this.fog=!0;this.shading=THREE.SmoothShading;this.wireframe=!1;this.wireframeLinewidth=1;this.wireframeLinejoin=this.wireframeLinecap="round";this.vertexColors=THREE.NoColors;this.morphNormals=this.morphTargets=this.skinning=!1;this.setValues(a)};THREE.MeshPhongMaterial.prototype=Object.create(THREE.Material.prototype); +THREE.MeshPhongMaterial.prototype.clone=function(){var a=new THREE.MeshPhongMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.ambient.copy(this.ambient);a.emissive.copy(this.emissive);a.specular.copy(this.specular);a.shininess=this.shininess;a.metal=this.metal;a.perPixel=this.perPixel;a.wrapAround=this.wrapAround;a.wrapRGB.copy(this.wrapRGB);a.map=this.map;a.lightMap=this.lightMap;a.bumpMap=this.bumpMap;a.bumpScale=this.bumpScale;a.normalMap=this.normalMap;a.normalScale.copy(this.normalScale); +a.specularMap=this.specularMap;a.envMap=this.envMap;a.combine=this.combine;a.reflectivity=this.reflectivity;a.refractionRatio=this.refractionRatio;a.fog=this.fog;a.shading=this.shading;a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;a.wireframeLinecap=this.wireframeLinecap;a.wireframeLinejoin=this.wireframeLinejoin;a.vertexColors=this.vertexColors;a.skinning=this.skinning;a.morphTargets=this.morphTargets;a.morphNormals=this.morphNormals;return a};THREE.MeshDepthMaterial=function(a){THREE.Material.call(this);this.wireframe=!1;this.wireframeLinewidth=1;this.setValues(a)};THREE.MeshDepthMaterial.prototype=Object.create(THREE.Material.prototype);THREE.MeshDepthMaterial.prototype.clone=function(){var a=new THREE.LineBasicMaterial;THREE.Material.prototype.clone.call(this,a);a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;return a};THREE.MeshNormalMaterial=function(a){THREE.Material.call(this,a);this.shading=THREE.FlatShading;this.wireframe=!1;this.wireframeLinewidth=1;this.setValues(a)};THREE.MeshNormalMaterial.prototype=Object.create(THREE.Material.prototype);THREE.MeshNormalMaterial.prototype.clone=function(){var a=new THREE.MeshNormalMaterial;THREE.Material.prototype.clone.call(this,a);a.shading=this.shading;a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;return a};THREE.MeshFaceMaterial=function(a){this.materials=a instanceof Array?a:[]};THREE.MeshFaceMaterial.prototype.clone=function(){return new THREE.MeshFaceMaterial(this.materials.slice(0))};THREE.ParticleBasicMaterial=function(a){THREE.Material.call(this);this.color=new THREE.Color(16777215);this.map=null;this.size=1;this.sizeAttenuation=!0;this.vertexColors=!1;this.fog=!0;this.setValues(a)};THREE.ParticleBasicMaterial.prototype=Object.create(THREE.Material.prototype); +THREE.ParticleBasicMaterial.prototype.clone=function(){var a=new THREE.ParticleBasicMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.map=this.map;a.size=this.size;a.sizeAttenuation=this.sizeAttenuation;a.vertexColors=this.vertexColors;a.fog=this.fog;return a};THREE.ParticleCanvasMaterial=function(a){THREE.Material.call(this);this.color=new THREE.Color(16777215);this.program=function(){};this.setValues(a)};THREE.ParticleCanvasMaterial.prototype=Object.create(THREE.Material.prototype);THREE.ParticleCanvasMaterial.prototype.clone=function(){var a=new THREE.ParticleCanvasMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.program=this.program;return a};THREE.ShaderMaterial=function(a){THREE.Material.call(this);this.vertexShader=this.fragmentShader="void main() {}";this.uniforms={};this.defines={};this.attributes=null;this.shading=THREE.SmoothShading;this.wireframe=!1;this.wireframeLinewidth=1;this.lights=this.fog=!1;this.vertexColors=THREE.NoColors;this.morphNormals=this.morphTargets=this.skinning=!1;this.setValues(a)};THREE.ShaderMaterial.prototype=Object.create(THREE.Material.prototype); +THREE.ShaderMaterial.prototype.clone=function(){var a=new THREE.ShaderMaterial;THREE.Material.prototype.clone.call(this,a);a.fragmentShader=this.fragmentShader;a.vertexShader=this.vertexShader;a.uniforms=THREE.UniformsUtils.clone(this.uniforms);a.attributes=this.attributes;a.defines=this.defines;a.shading=this.shading;a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;a.fog=this.fog;a.lights=this.lights;a.vertexColors=this.vertexColors;a.skinning=this.skinning;a.morphTargets= +this.morphTargets;a.morphNormals=this.morphNormals;return a};THREE.SpriteMaterial=function(a){THREE.Material.call(this);this.color=new THREE.Color(16777215);this.map=new THREE.Texture;this.useScreenCoordinates=!0;this.depthTest=!this.useScreenCoordinates;this.sizeAttenuation=!this.useScreenCoordinates;this.scaleByViewport=!this.sizeAttenuation;this.alignment=THREE.SpriteAlignment.center.clone();this.fog=!1;this.uvOffset=new THREE.Vector2(0,0);this.uvScale=new THREE.Vector2(1,1);this.setValues(a);a=a||{};void 0===a.depthTest&&(this.depthTest=!this.useScreenCoordinates); +void 0===a.sizeAttenuation&&(this.sizeAttenuation=!this.useScreenCoordinates);void 0===a.scaleByViewport&&(this.scaleByViewport=!this.sizeAttenuation)};THREE.SpriteMaterial.prototype=Object.create(THREE.Material.prototype); +THREE.SpriteMaterial.prototype.clone=function(){var a=new THREE.SpriteMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.map=this.map;a.useScreenCoordinates=this.useScreenCoordinates;a.sizeAttenuation=this.sizeAttenuation;a.scaleByViewport=this.scaleByViewport;a.alignment.copy(this.alignment);a.uvOffset.copy(this.uvOffset);a.uvScale.copy(this.uvScale);a.fog=this.fog;return a};THREE.SpriteAlignment={};THREE.SpriteAlignment.topLeft=new THREE.Vector2(1,-1); +THREE.SpriteAlignment.topCenter=new THREE.Vector2(0,-1);THREE.SpriteAlignment.topRight=new THREE.Vector2(-1,-1);THREE.SpriteAlignment.centerLeft=new THREE.Vector2(1,0);THREE.SpriteAlignment.center=new THREE.Vector2(0,0);THREE.SpriteAlignment.centerRight=new THREE.Vector2(-1,0);THREE.SpriteAlignment.bottomLeft=new THREE.Vector2(1,1);THREE.SpriteAlignment.bottomCenter=new THREE.Vector2(0,1);THREE.SpriteAlignment.bottomRight=new THREE.Vector2(-1,1);THREE.Texture=function(a,b,c,d,e,f,g,h,i){THREE.EventDispatcher.call(this);this.id=THREE.TextureIdCount++;this.name="";this.image=a;this.mipmaps=[];this.mapping=void 0!==b?b:new THREE.UVMapping;this.wrapS=void 0!==c?c:THREE.ClampToEdgeWrapping;this.wrapT=void 0!==d?d:THREE.ClampToEdgeWrapping;this.magFilter=void 0!==e?e:THREE.LinearFilter;this.minFilter=void 0!==f?f:THREE.LinearMipMapLinearFilter;this.anisotropy=void 0!==i?i:1;this.format=void 0!==g?g:THREE.RGBAFormat;this.type=void 0!==h?h:THREE.UnsignedByteType; +this.offset=new THREE.Vector2(0,0);this.repeat=new THREE.Vector2(1,1);this.generateMipmaps=!0;this.premultiplyAlpha=!1;this.flipY=!0;this.unpackAlignment=4;this.needsUpdate=!1;this.onUpdate=null}; +THREE.Texture.prototype={constructor:THREE.Texture,clone:function(a){void 0===a&&(a=new THREE.Texture);a.image=this.image;a.mipmaps=this.mipmaps.slice(0);a.mapping=this.mapping;a.wrapS=this.wrapS;a.wrapT=this.wrapT;a.magFilter=this.magFilter;a.minFilter=this.minFilter;a.anisotropy=this.anisotropy;a.format=this.format;a.type=this.type;a.offset.copy(this.offset);a.repeat.copy(this.repeat);a.generateMipmaps=this.generateMipmaps;a.premultiplyAlpha=this.premultiplyAlpha;a.flipY=this.flipY;a.unpackAlignment= +this.unpackAlignment;return a},dispose:function(){this.dispatchEvent({type:"dispose"})}};THREE.TextureIdCount=0;THREE.CompressedTexture=function(a,b,c,d,e,f,g,h,i,k,l){THREE.Texture.call(this,null,f,g,h,i,k,d,e,l);this.image={width:b,height:c};this.mipmaps=a;this.generateMipmaps=!1};THREE.CompressedTexture.prototype=Object.create(THREE.Texture.prototype);THREE.CompressedTexture.prototype.clone=function(){var a=new THREE.CompressedTexture;THREE.Texture.prototype.clone.call(this,a);return a};THREE.DataTexture=function(a,b,c,d,e,f,g,h,i,k,l){THREE.Texture.call(this,null,f,g,h,i,k,d,e,l);this.image={data:a,width:b,height:c}};THREE.DataTexture.prototype=Object.create(THREE.Texture.prototype);THREE.DataTexture.prototype.clone=function(){var a=new THREE.DataTexture;THREE.Texture.prototype.clone.call(this,a);return a};THREE.Particle=function(a){THREE.Object3D.call(this);this.material=a};THREE.Particle.prototype=Object.create(THREE.Object3D.prototype);THREE.Particle.prototype.clone=function(a){void 0===a&&(a=new THREE.Particle(this.material));THREE.Object3D.prototype.clone.call(this,a);return a};THREE.ParticleSystem=function(a,b){THREE.Object3D.call(this);this.geometry=a;this.material=void 0!==b?b:new THREE.ParticleBasicMaterial({color:16777215*Math.random()});this.sortParticles=!1;this.geometry&&null===this.geometry.boundingSphere&&this.geometry.computeBoundingSphere();this.frustumCulled=!1};THREE.ParticleSystem.prototype=Object.create(THREE.Object3D.prototype); +THREE.ParticleSystem.prototype.clone=function(a){void 0===a&&(a=new THREE.ParticleSystem(this.geometry,this.material));a.sortParticles=this.sortParticles;THREE.Object3D.prototype.clone.call(this,a);return a};THREE.Line=function(a,b,c){THREE.Object3D.call(this);this.geometry=a;this.material=void 0!==b?b:new THREE.LineBasicMaterial({color:16777215*Math.random()});this.type=void 0!==c?c:THREE.LineStrip;this.geometry&&(this.geometry.boundingSphere||this.geometry.computeBoundingSphere())};THREE.LineStrip=0;THREE.LinePieces=1;THREE.Line.prototype=Object.create(THREE.Object3D.prototype); +THREE.Line.prototype.clone=function(a){void 0===a&&(a=new THREE.Line(this.geometry,this.material,this.type));THREE.Object3D.prototype.clone.call(this,a);return a};THREE.Mesh=function(a,b){THREE.Object3D.call(this);this.geometry=a;this.material=void 0!==b?b:new THREE.MeshBasicMaterial({color:16777215*Math.random(),wireframe:!0});void 0!==this.geometry&&(null===this.geometry.boundingSphere&&this.geometry.computeBoundingSphere(),this.updateMorphTargets())};THREE.Mesh.prototype=Object.create(THREE.Object3D.prototype); +THREE.Mesh.prototype.updateMorphTargets=function(){if(0<this.geometry.morphTargets.length){this.morphTargetBase=-1;this.morphTargetForcedOrder=[];this.morphTargetInfluences=[];this.morphTargetDictionary={};for(var a=0,b=this.geometry.morphTargets.length;a<b;a++)this.morphTargetInfluences.push(0),this.morphTargetDictionary[this.geometry.morphTargets[a].name]=a}}; +THREE.Mesh.prototype.getMorphTargetIndexByName=function(a){if(void 0!==this.morphTargetDictionary[a])return this.morphTargetDictionary[a];console.log("THREE.Mesh.getMorphTargetIndexByName: morph target "+a+" does not exist. Returning 0.");return 0};THREE.Mesh.prototype.clone=function(a){void 0===a&&(a=new THREE.Mesh(this.geometry,this.material));THREE.Object3D.prototype.clone.call(this,a);return a};THREE.Bone=function(a){THREE.Object3D.call(this);this.skin=a;this.skinMatrix=new THREE.Matrix4};THREE.Bone.prototype=Object.create(THREE.Object3D.prototype);THREE.Bone.prototype.update=function(a,b){this.matrixAutoUpdate&&(b|=this.updateMatrix());if(b||this.matrixWorldNeedsUpdate)a?this.skinMatrix.multiplyMatrices(a,this.matrix):this.skinMatrix.copy(this.matrix),this.matrixWorldNeedsUpdate=!1,b=!0;var c,d=this.children.length;for(c=0;c<d;c++)this.children[c].update(this.skinMatrix,b)};THREE.SkinnedMesh=function(a,b,c){THREE.Mesh.call(this,a,b);this.useVertexTexture=void 0!==c?c:!0;this.identityMatrix=new THREE.Matrix4;this.bones=[];this.boneMatrices=[];var d,e,f;if(this.geometry&&void 0!==this.geometry.bones){for(a=0;a<this.geometry.bones.length;a++)c=this.geometry.bones[a],d=c.pos,e=c.rotq,f=c.scl,b=this.addBone(),b.name=c.name,b.position.set(d[0],d[1],d[2]),b.quaternion.set(e[0],e[1],e[2],e[3]),b.useQuaternion=!0,void 0!==f?b.scale.set(f[0],f[1],f[2]):b.scale.set(1,1,1);for(a= +0;a<this.bones.length;a++)c=this.geometry.bones[a],b=this.bones[a],-1===c.parent?this.add(b):this.bones[c.parent].add(b);a=this.bones.length;this.useVertexTexture?(this.boneTextureHeight=this.boneTextureWidth=a=256<a?64:64<a?32:16<a?16:8,this.boneMatrices=new Float32Array(4*this.boneTextureWidth*this.boneTextureHeight),this.boneTexture=new THREE.DataTexture(this.boneMatrices,this.boneTextureWidth,this.boneTextureHeight,THREE.RGBAFormat,THREE.FloatType),this.boneTexture.minFilter=THREE.NearestFilter, +this.boneTexture.magFilter=THREE.NearestFilter,this.boneTexture.generateMipmaps=!1,this.boneTexture.flipY=!1):this.boneMatrices=new Float32Array(16*a);this.pose()}};THREE.SkinnedMesh.prototype=Object.create(THREE.Mesh.prototype);THREE.SkinnedMesh.prototype.addBone=function(a){void 0===a&&(a=new THREE.Bone(this));this.bones.push(a);return a}; +THREE.SkinnedMesh.prototype.updateMatrixWorld=function(a){this.matrixAutoUpdate&&this.updateMatrix();if(this.matrixWorldNeedsUpdate||a)this.parent?this.matrixWorld.multiplyMatrices(this.parent.matrixWorld,this.matrix):this.matrixWorld.copy(this.matrix),this.matrixWorldNeedsUpdate=!1;for(var a=0,b=this.children.length;a<b;a++){var c=this.children[a];c instanceof THREE.Bone?c.update(this.identityMatrix,!1):c.updateMatrixWorld(!0)}if(void 0==this.boneInverses){this.boneInverses=[];a=0;for(b=this.bones.length;a< +b;a++)c=new THREE.Matrix4,c.getInverse(this.bones[a].skinMatrix),this.boneInverses.push(c)}a=0;for(b=this.bones.length;a<b;a++)THREE.SkinnedMesh.offsetMatrix.multiplyMatrices(this.bones[a].skinMatrix,this.boneInverses[a]),THREE.SkinnedMesh.offsetMatrix.flattenToArrayOffset(this.boneMatrices,16*a);this.useVertexTexture&&(this.boneTexture.needsUpdate=!0)}; +THREE.SkinnedMesh.prototype.pose=function(){this.updateMatrixWorld(!0);for(var a=0;a<this.geometry.skinIndices.length;a++){var b=this.geometry.skinWeights[a],c=1/b.lengthManhattan();Infinity!==c?b.multiplyScalar(c):b.set(1)}};THREE.SkinnedMesh.prototype.clone=function(a){void 0===a&&(a=new THREE.SkinnedMesh(this.geometry,this.material,this.useVertexTexture));THREE.Mesh.prototype.clone.call(this,a);return a};THREE.SkinnedMesh.offsetMatrix=new THREE.Matrix4;THREE.MorphAnimMesh=function(a,b){THREE.Mesh.call(this,a,b);this.duration=1E3;this.mirroredLoop=!1;this.currentKeyframe=this.lastKeyframe=this.time=0;this.direction=1;this.directionBackwards=!1;this.setFrameRange(0,this.geometry.morphTargets.length-1)};THREE.MorphAnimMesh.prototype=Object.create(THREE.Mesh.prototype);THREE.MorphAnimMesh.prototype.setFrameRange=function(a,b){this.startKeyframe=a;this.endKeyframe=b;this.length=this.endKeyframe-this.startKeyframe+1}; +THREE.MorphAnimMesh.prototype.setDirectionForward=function(){this.direction=1;this.directionBackwards=!1};THREE.MorphAnimMesh.prototype.setDirectionBackward=function(){this.direction=-1;this.directionBackwards=!0}; +THREE.MorphAnimMesh.prototype.parseAnimations=function(){var a=this.geometry;a.animations||(a.animations={});for(var b,c=a.animations,d=/([a-z]+)(\d+)/,e=0,f=a.morphTargets.length;e<f;e++){var g=a.morphTargets[e].name.match(d);if(g&&1<g.length){g=g[1];c[g]||(c[g]={start:Infinity,end:-Infinity});var h=c[g];e<h.start&&(h.start=e);e>h.end&&(h.end=e);b||(b=g)}}a.firstAnimation=b}; +THREE.MorphAnimMesh.prototype.setAnimationLabel=function(a,b,c){this.geometry.animations||(this.geometry.animations={});this.geometry.animations[a]={start:b,end:c}};THREE.MorphAnimMesh.prototype.playAnimation=function(a,b){var c=this.geometry.animations[a];c?(this.setFrameRange(c.start,c.end),this.duration=1E3*((c.end-c.start)/b),this.time=0):console.warn("animation["+a+"] undefined")}; +THREE.MorphAnimMesh.prototype.updateAnimation=function(a){var b=this.duration/this.length;this.time+=this.direction*a;if(this.mirroredLoop){if(this.time>this.duration||0>this.time)this.direction*=-1,this.time>this.duration&&(this.time=this.duration,this.directionBackwards=!0),0>this.time&&(this.time=0,this.directionBackwards=!1)}else this.time%=this.duration,0>this.time&&(this.time+=this.duration);a=this.startKeyframe+THREE.Math.clamp(Math.floor(this.time/b),0,this.length-1);a!==this.currentKeyframe&& +(this.morphTargetInfluences[this.lastKeyframe]=0,this.morphTargetInfluences[this.currentKeyframe]=1,this.morphTargetInfluences[a]=0,this.lastKeyframe=this.currentKeyframe,this.currentKeyframe=a);b=this.time%b/b;this.directionBackwards&&(b=1-b);this.morphTargetInfluences[this.currentKeyframe]=b;this.morphTargetInfluences[this.lastKeyframe]=1-b}; +THREE.MorphAnimMesh.prototype.clone=function(a){void 0===a&&(a=new THREE.MorphAnimMesh(this.geometry,this.material));a.duration=this.duration;a.mirroredLoop=this.mirroredLoop;a.time=this.time;a.lastKeyframe=this.lastKeyframe;a.currentKeyframe=this.currentKeyframe;a.direction=this.direction;a.directionBackwards=this.directionBackwards;THREE.Mesh.prototype.clone.call(this,a);return a};THREE.Ribbon=function(a,b){THREE.Object3D.call(this);this.geometry=a;this.material=b};THREE.Ribbon.prototype=Object.create(THREE.Object3D.prototype);THREE.Ribbon.prototype.clone=function(a){void 0===a&&(a=new THREE.Ribbon(this.geometry,this.material));THREE.Object3D.prototype.clone.call(this,a);return a};THREE.LOD=function(){THREE.Object3D.call(this);this.LODs=[]};THREE.LOD.prototype=Object.create(THREE.Object3D.prototype);THREE.LOD.prototype.addLevel=function(a,b){void 0===b&&(b=0);for(var b=Math.abs(b),c=0;c<this.LODs.length&&!(b<this.LODs[c].visibleAtDistance);c++);this.LODs.splice(c,0,{visibleAtDistance:b,object3D:a});this.add(a)}; +THREE.LOD.prototype.update=function(a){if(1<this.LODs.length){a.matrixWorldInverse.getInverse(a.matrixWorld);a=a.matrixWorldInverse;a=-(a.elements[2]*this.matrixWorld.elements[12]+a.elements[6]*this.matrixWorld.elements[13]+a.elements[10]*this.matrixWorld.elements[14]+a.elements[14]);this.LODs[0].object3D.visible=!0;for(var b=1;b<this.LODs.length;b++)if(a>=this.LODs[b].visibleAtDistance)this.LODs[b-1].object3D.visible=!1,this.LODs[b].object3D.visible=!0;else break;for(;b<this.LODs.length;b++)this.LODs[b].object3D.visible= +!1}};THREE.LOD.prototype.clone=function(){};THREE.Sprite=function(a){THREE.Object3D.call(this);this.material=void 0!==a?a:new THREE.SpriteMaterial;this.rotation3d=this.rotation;this.rotation=0};THREE.Sprite.prototype=Object.create(THREE.Object3D.prototype);THREE.Sprite.prototype.updateMatrix=function(){this.matrix.setPosition(this.position);this.rotation3d.set(0,0,this.rotation);this.matrix.setRotationFromEuler(this.rotation3d);(1!==this.scale.x||1!==this.scale.y)&&this.matrix.scale(this.scale);this.matrixWorldNeedsUpdate=!0}; +THREE.Sprite.prototype.clone=function(a){void 0===a&&(a=new THREE.Sprite(this.material));THREE.Object3D.prototype.clone.call(this,a);return a};THREE.Scene=function(){THREE.Object3D.call(this);this.overrideMaterial=this.fog=null;this.matrixAutoUpdate=!1;this.__objects=[];this.__lights=[];this.__objectsAdded=[];this.__objectsRemoved=[]};THREE.Scene.prototype=Object.create(THREE.Object3D.prototype); +THREE.Scene.prototype.__addObject=function(a){if(a instanceof THREE.Light)-1===this.__lights.indexOf(a)&&this.__lights.push(a),a.target&&void 0===a.target.parent&&this.add(a.target);else if(!(a instanceof THREE.Camera||a instanceof THREE.Bone)&&-1===this.__objects.indexOf(a)){this.__objects.push(a);this.__objectsAdded.push(a);var b=this.__objectsRemoved.indexOf(a);-1!==b&&this.__objectsRemoved.splice(b,1)}for(b=0;b<a.children.length;b++)this.__addObject(a.children[b])}; +THREE.Scene.prototype.__removeObject=function(a){if(a instanceof THREE.Light){var b=this.__lights.indexOf(a);-1!==b&&this.__lights.splice(b,1)}else a instanceof THREE.Camera||(b=this.__objects.indexOf(a),-1!==b&&(this.__objects.splice(b,1),this.__objectsRemoved.push(a),b=this.__objectsAdded.indexOf(a),-1!==b&&this.__objectsAdded.splice(b,1)));for(b=0;b<a.children.length;b++)this.__removeObject(a.children[b])};THREE.Fog=function(a,b,c){this.name="";this.color=new THREE.Color(a);this.near=void 0!==b?b:1;this.far=void 0!==c?c:1E3};THREE.Fog.prototype.clone=function(){return new THREE.Fog(this.color.getHex(),this.near,this.far)};THREE.FogExp2=function(a,b){this.name="";this.color=new THREE.Color(a);this.density=void 0!==b?b:2.5E-4};THREE.FogExp2.prototype.clone=function(){return new THREE.FogExp2(this.color.getHex(),this.density)};THREE.CanvasRenderer=function(a){function b(a){C!==a&&(C=t.globalAlpha=a)}function c(a){x!==a&&(a===THREE.NormalBlending?t.globalCompositeOperation="source-over":a===THREE.AdditiveBlending?t.globalCompositeOperation="lighter":a===THREE.SubtractiveBlending&&(t.globalCompositeOperation="darker"),x=a)}function d(a){E!==a&&(E=t.lineWidth=a)}function e(a){H!==a&&(H=t.lineCap=a)}function f(a){B!==a&&(B=t.lineJoin=a)}function g(a){G!==a&&(G=t.strokeStyle=a)}function h(a){J!==a&&(J=t.fillStyle=a)}function i(a, +b){if(W!==a||F!==b)t.setLineDash([a,b]),W=a,F=b}console.log("THREE.CanvasRenderer",THREE.REVISION);var k=THREE.Math.smoothstep,a=a||{},l=this,m,n,s,r=new THREE.Projector,p=void 0!==a.canvas?a.canvas:document.createElement("canvas"),q,y,v,z,t=p.getContext("2d"),A=new THREE.Color(0),I=0,C=1,x=0,G=null,J=null,E=null,H=null,B=null,W=null,F=0,K,L,U,fa,Ca=new THREE.RenderableVertex,$a=new THREE.RenderableVertex,M,ca,qa,ha,ra,N,Ma,Na,mb,Pa,ta,ka,aa=new THREE.Color,pa=new THREE.Color,Y=new THREE.Color,da= +new THREE.Color,la=new THREE.Color,Z=new THREE.Color,oa=new THREE.Color,gb=new THREE.Color,nb={},ia={},Wa,ab,Fa,Xa,ub,Ib,Jb,fc,Ab,mc,pb=new THREE.Box2,Ka=new THREE.Box2,Va=new THREE.Box2,gc=!1,vb=new THREE.Color,Qa=new THREE.Color,La=new THREE.Color,bb=new THREE.Vector3,xb,j,yb,Ra,cb,Sa,zb=16;xb=document.createElement("canvas");xb.width=xb.height=2;j=xb.getContext("2d");j.fillStyle="rgba(0,0,0,1)";j.fillRect(0,0,2,2);yb=j.getImageData(0,0,2,2);Ra=yb.data;cb=document.createElement("canvas");cb.width= +cb.height=zb;Sa=cb.getContext("2d");Sa.translate(-zb/2,-zb/2);Sa.scale(zb,zb);zb--;void 0===t.setLineDash&&(t.setLineDash=void 0!==t.mozDash?function(a){t.mozDash=null!==a[0]?a:null}:function(){});this.domElement=p;this.devicePixelRatio=void 0!==a.devicePixelRatio?a.devicePixelRatio:void 0!==window.devicePixelRatio?window.devicePixelRatio:1;this.sortElements=this.sortObjects=this.autoClear=!0;this.info={render:{vertices:0,faces:0}};this.supportsVertexTextures=function(){};this.setFaceCulling=function(){}; +this.setSize=function(a,b){q=a*this.devicePixelRatio;y=b*this.devicePixelRatio;v=Math.floor(q/2);z=Math.floor(y/2);p.width=q;p.height=y;p.style.width=a+"px";p.style.height=b+"px";pb.set(new THREE.Vector2(-v,-z),new THREE.Vector2(v,z));Ka.set(new THREE.Vector2(-v,-z),new THREE.Vector2(v,z));C=1;x=0;B=H=E=J=G=null};this.setClearColor=function(a,b){A.copy(a);I=void 0!==b?b:1;Ka.set(new THREE.Vector2(-v,-z),new THREE.Vector2(v,z))};this.setClearColorHex=function(a,b){A.setHex(a);I=void 0!==b?b:1;Ka.set(new THREE.Vector2(-v, +-z),new THREE.Vector2(v,z))};this.getMaxAnisotropy=function(){return 0};this.clear=function(){t.setTransform(1,0,0,-1,v,z);!1===Ka.empty()&&(Ka.intersect(pb),Ka.expandByScalar(2),1>I&&t.clearRect(Ka.min.x|0,Ka.min.y|0,Ka.max.x-Ka.min.x|0,Ka.max.y-Ka.min.y|0),0<I&&(c(THREE.NormalBlending),b(1),h("rgba("+Math.floor(255*A.r)+","+Math.floor(255*A.g)+","+Math.floor(255*A.b)+","+I+")"),t.fillRect(Ka.min.x|0,Ka.min.y|0,Ka.max.x-Ka.min.x|0,Ka.max.y-Ka.min.y|0)),Ka.makeEmpty())};this.render=function(a,p){function q(a, +b,c){for(var d=0,e=s.length;d<e;d++){var f=s[d];gb.copy(f.color);if(f instanceof THREE.DirectionalLight){var g=bb.getPositionFromMatrix(f.matrixWorld).normalize(),j=b.dot(g);0>=j||(j*=f.intensity,c.add(gb.multiplyScalar(j)))}else f instanceof THREE.PointLight&&(g=bb.getPositionFromMatrix(f.matrixWorld),j=b.dot(bb.subVectors(g,a).normalize()),0>=j||(j*=0==f.distance?1:1-Math.min(a.distanceTo(g)/f.distance,1),0!=j&&(j*=f.intensity,c.add(gb.multiplyScalar(j)))))}}function x(a,d,e,f,g,j,h,i){l.info.render.vertices+= +3;l.info.render.faces++;b(i.opacity);c(i.blending);M=a.positionScreen.x;ca=a.positionScreen.y;qa=d.positionScreen.x;ha=d.positionScreen.y;ra=e.positionScreen.x;N=e.positionScreen.y;y(M,ca,qa,ha,ra,N);(i instanceof THREE.MeshLambertMaterial||i instanceof THREE.MeshPhongMaterial)&&null===i.map?(Z.copy(i.color),oa.copy(i.emissive),i.vertexColors===THREE.FaceColors&&Z.multiply(h.color),!0===gc?!1===i.wireframe&&i.shading==THREE.SmoothShading&&3==h.vertexNormalsLength?(pa.copy(vb),Y.copy(vb),da.copy(vb), +q(h.v1.positionWorld,h.vertexNormalsModel[0],pa),q(h.v2.positionWorld,h.vertexNormalsModel[1],Y),q(h.v3.positionWorld,h.vertexNormalsModel[2],da),pa.multiply(Z).add(oa),Y.multiply(Z).add(oa),da.multiply(Z).add(oa),la.addColors(Y,da).multiplyScalar(0.5),Fa=E(pa,Y,da,la),G(M,ca,qa,ha,ra,N,0,0,1,0,0,1,Fa)):(aa.copy(vb),q(h.centroidModel,h.normalModel,aa),aa.multiply(Z).add(oa),!0===i.wireframe?C(aa,i.wireframeLinewidth,i.wireframeLinecap,i.wireframeLinejoin):A(aa)):!0===i.wireframe?C(i.color,i.wireframeLinewidth, +i.wireframeLinecap,i.wireframeLinejoin):A(i.color)):i instanceof THREE.MeshBasicMaterial||i instanceof THREE.MeshLambertMaterial||i instanceof THREE.MeshPhongMaterial?null!==i.map?i.map.mapping instanceof THREE.UVMapping&&(Xa=h.uvs[0],F(M,ca,qa,ha,ra,N,Xa[f].x,Xa[f].y,Xa[g].x,Xa[g].y,Xa[j].x,Xa[j].y,i.map)):null!==i.envMap?i.envMap.mapping instanceof THREE.SphericalReflectionMapping&&(bb.copy(h.vertexNormalsModelView[f]),ub=0.5*bb.x+0.5,Ib=0.5*bb.y+0.5,bb.copy(h.vertexNormalsModelView[g]),Jb=0.5* +bb.x+0.5,fc=0.5*bb.y+0.5,bb.copy(h.vertexNormalsModelView[j]),Ab=0.5*bb.x+0.5,mc=0.5*bb.y+0.5,F(M,ca,qa,ha,ra,N,ub,Ib,Jb,fc,Ab,mc,i.envMap)):(aa.copy(i.color),i.vertexColors===THREE.FaceColors&&aa.multiply(h.color),!0===i.wireframe?C(aa,i.wireframeLinewidth,i.wireframeLinecap,i.wireframeLinejoin):A(aa)):i instanceof THREE.MeshDepthMaterial?(Wa=p.near,ab=p.far,pa.r=pa.g=pa.b=1-k(a.positionScreen.z*a.positionScreen.w,Wa,ab),Y.r=Y.g=Y.b=1-k(d.positionScreen.z*d.positionScreen.w,Wa,ab),da.r=da.g=da.b= +1-k(e.positionScreen.z*e.positionScreen.w,Wa,ab),la.addColors(Y,da).multiplyScalar(0.5),Fa=E(pa,Y,da,la),G(M,ca,qa,ha,ra,N,0,0,1,0,0,1,Fa)):i instanceof THREE.MeshNormalMaterial&&(i.shading==THREE.FlatShading?(a=h.normalModelView,aa.setRGB(a.x,a.y,a.z).multiplyScalar(0.5).addScalar(0.5),!0===i.wireframe?C(aa,i.wireframeLinewidth,i.wireframeLinecap,i.wireframeLinejoin):A(aa)):i.shading==THREE.SmoothShading&&(a=h.vertexNormalsModelView[f],pa.setRGB(a.x,a.y,a.z).multiplyScalar(0.5).addScalar(0.5),a= +h.vertexNormalsModelView[g],Y.setRGB(a.x,a.y,a.z).multiplyScalar(0.5).addScalar(0.5),a=h.vertexNormalsModelView[j],da.setRGB(a.x,a.y,a.z).multiplyScalar(0.5).addScalar(0.5),la.addColors(Y,da).multiplyScalar(0.5),Fa=E(pa,Y,da,la),G(M,ca,qa,ha,ra,N,0,0,1,0,0,1,Fa)))}function y(a,b,c,d,e,f){t.beginPath();t.moveTo(a,b);t.lineTo(c,d);t.lineTo(e,f);t.closePath()}function B(a,b,c,d,e,f,g,j){t.beginPath();t.moveTo(a,b);t.lineTo(c,d);t.lineTo(e,f);t.lineTo(g,j);t.closePath()}function C(a,b,c,j){d(b);e(c); +f(j);g(a.getStyle());t.stroke();Va.expandByScalar(2*b)}function A(a){h(a.getStyle());t.fill()}function F(a,b,c,d,e,f,g,j,i,wa,k,l,n){if(!(n instanceof THREE.DataTexture||void 0===n.image||0==n.image.width)){if(!0===n.needsUpdate){var m=n.wrapS==THREE.RepeatWrapping,hb=n.wrapT==THREE.RepeatWrapping;nb[n.id]=t.createPattern(n.image,!0===m&&!0===hb?"repeat":!0===m&&!1===hb?"repeat-x":!1===m&&!0===hb?"repeat-y":"no-repeat");n.needsUpdate=!1}void 0===nb[n.id]?h("rgba(0,0,0,1)"):h(nb[n.id]);var m=n.offset.x/ +n.repeat.x,hb=n.offset.y/n.repeat.y,p=n.image.width*n.repeat.x,q=n.image.height*n.repeat.y,g=(g+m)*p,j=(1-j+hb)*q,c=c-a,d=d-b,e=e-a,f=f-b,i=(i+m)*p-g,wa=(1-wa+hb)*q-j,k=(k+m)*p-g,l=(1-l+hb)*q-j,m=i*l-k*wa;0===m?(void 0===ia[n.id]&&(b=document.createElement("canvas"),b.width=n.image.width,b.height=n.image.height,b=b.getContext("2d"),b.drawImage(n.image,0,0),ia[n.id]=b.getImageData(0,0,n.image.width,n.image.height).data),b=ia[n.id],g=4*(Math.floor(g)+Math.floor(j)*n.image.width),aa.setRGB(b[g]/255, +b[g+1]/255,b[g+2]/255),A(aa)):(m=1/m,n=(l*c-wa*e)*m,wa=(l*d-wa*f)*m,c=(i*e-k*c)*m,d=(i*f-k*d)*m,a=a-n*g-c*j,g=b-wa*g-d*j,t.save(),t.transform(n,wa,c,d,a,g),t.fill(),t.restore())}}function G(a,b,c,d,e,f,g,j,i,h,wa,k,n){var l,m;l=n.width-1;m=n.height-1;g*=l;j*=m;c-=a;d-=b;e-=a;f-=b;i=i*l-g;h=h*m-j;wa=wa*l-g;k=k*m-j;m=1/(i*k-wa*h);l=(k*c-h*e)*m;h=(k*d-h*f)*m;c=(i*e-wa*c)*m;d=(i*f-wa*d)*m;a=a-l*g-c*j;b=b-h*g-d*j;t.save();t.transform(l,h,c,d,a,b);t.clip();t.drawImage(n,0,0);t.restore()}function E(a,b, +c,d){Ra[0]=255*a.r|0;Ra[1]=255*a.g|0;Ra[2]=255*a.b|0;Ra[4]=255*b.r|0;Ra[5]=255*b.g|0;Ra[6]=255*b.b|0;Ra[8]=255*c.r|0;Ra[9]=255*c.g|0;Ra[10]=255*c.b|0;Ra[12]=255*d.r|0;Ra[13]=255*d.g|0;Ra[14]=255*d.b|0;j.putImageData(yb,0,0);Sa.drawImage(xb,0,0);return cb}function I(a,b){var c=b.x-a.x,d=b.y-a.y,e=c*c+d*d;0!==e&&(e=1/Math.sqrt(e),c*=e,d*=e,b.x+=c,b.y+=d,a.x-=c,a.y-=d)}if(!1===p instanceof THREE.Camera)console.error("THREE.CanvasRenderer.render: camera is not an instance of THREE.Camera.");else{!0=== +this.autoClear&&this.clear();t.setTransform(1,0,0,-1,v,z);l.info.render.vertices=0;l.info.render.faces=0;m=r.projectScene(a,p,this.sortObjects,this.sortElements);n=m.elements;s=m.lights;gc=0<s.length;if(!0===gc){vb.setRGB(0,0,0);Qa.setRGB(0,0,0);La.setRGB(0,0,0);for(var J=0,W=s.length;J<W;J++){var P=s[J],X=P.color;P instanceof THREE.AmbientLight?vb.add(X):P instanceof THREE.DirectionalLight?Qa.add(X):P instanceof THREE.PointLight&&La.add(X)}}J=0;for(W=n.length;J<W;J++){var H=n[J],P=H.material;if(!(void 0=== +P||!1===P.visible)){Va.makeEmpty();if(H instanceof THREE.RenderableParticle){K=H;K.x*=v;K.y*=z;var X=K,wa=H;b(P.opacity);c(P.blending);var Bb=void 0,hb=void 0,Cb=void 0,Db=void 0,md=H=void 0,nd=void 0;P instanceof THREE.ParticleBasicMaterial?null===P.map?(Cb=wa.object.scale.x,Db=wa.object.scale.y,Cb*=wa.scale.x*v,Db*=wa.scale.y*z,Va.min.set(X.x-Cb,X.y-Db),Va.max.set(X.x+Cb,X.y+Db),!1!==pb.isIntersectionBox(Va)&&(h(P.color.getStyle()),t.save(),t.translate(X.x,X.y),t.rotate(-wa.rotation),t.scale(Cb, +Db),t.fillRect(-1,-1,2,2),t.restore())):(H=P.map.image,md=H.width>>1,nd=H.height>>1,Cb=wa.scale.x*v,Db=wa.scale.y*z,Bb=Cb*md,hb=Db*nd,Va.min.set(X.x-Bb,X.y-hb),Va.max.set(X.x+Bb,X.y+hb),!1!==pb.isIntersectionBox(Va)&&(t.save(),t.translate(X.x,X.y),t.rotate(-wa.rotation),t.scale(Cb,-Db),t.translate(-md,-nd),t.drawImage(H,0,0),t.restore())):P instanceof THREE.ParticleCanvasMaterial&&(Bb=wa.scale.x*v,hb=wa.scale.y*z,Va.min.set(X.x-Bb,X.y-hb),Va.max.set(X.x+Bb,X.y+hb),!1!==pb.isIntersectionBox(Va)&&(g(P.color.getStyle()), +h(P.color.getStyle()),t.save(),t.translate(X.x,X.y),t.rotate(-wa.rotation),t.scale(Bb,hb),P.program(t),t.restore()))}else if(H instanceof THREE.RenderableLine)K=H.v1,L=H.v2,K.positionScreen.x*=v,K.positionScreen.y*=z,L.positionScreen.x*=v,L.positionScreen.y*=z,Va.setFromPoints([K.positionScreen,L.positionScreen]),!0===pb.isIntersectionBox(Va)&&(X=K,wa=L,b(P.opacity),c(P.blending),t.beginPath(),t.moveTo(X.positionScreen.x,X.positionScreen.y),t.lineTo(wa.positionScreen.x,wa.positionScreen.y),P instanceof +THREE.LineBasicMaterial?(d(P.linewidth),e(P.linecap),f(P.linejoin),g(P.color.getStyle()),i(null,null),t.stroke(),Va.expandByScalar(2*P.linewidth)):P instanceof THREE.LineDashedMaterial&&(d(P.linewidth),e(P.linecap),f(P.linejoin),g(P.color.getStyle()),i(P.dashSize,P.gapSize),t.stroke(),Va.expandByScalar(2*P.linewidth)));else if(H instanceof THREE.RenderableFace3){K=H.v1;L=H.v2;U=H.v3;if(-1>K.positionScreen.z||1<K.positionScreen.z)continue;if(-1>L.positionScreen.z||1<L.positionScreen.z)continue;if(-1> +U.positionScreen.z||1<U.positionScreen.z)continue;K.positionScreen.x*=v;K.positionScreen.y*=z;L.positionScreen.x*=v;L.positionScreen.y*=z;U.positionScreen.x*=v;U.positionScreen.y*=z;!0===P.overdraw&&(I(K.positionScreen,L.positionScreen),I(L.positionScreen,U.positionScreen),I(U.positionScreen,K.positionScreen));Va.setFromPoints([K.positionScreen,L.positionScreen,U.positionScreen]);x(K,L,U,0,1,2,H,P)}else if(H instanceof THREE.RenderableFace4){K=H.v1;L=H.v2;U=H.v3;fa=H.v4;if(-1>K.positionScreen.z|| +1<K.positionScreen.z)continue;if(-1>L.positionScreen.z||1<L.positionScreen.z)continue;if(-1>U.positionScreen.z||1<U.positionScreen.z)continue;if(-1>fa.positionScreen.z||1<fa.positionScreen.z)continue;K.positionScreen.x*=v;K.positionScreen.y*=z;L.positionScreen.x*=v;L.positionScreen.y*=z;U.positionScreen.x*=v;U.positionScreen.y*=z;fa.positionScreen.x*=v;fa.positionScreen.y*=z;Ca.positionScreen.copy(L.positionScreen);$a.positionScreen.copy(fa.positionScreen);!0===P.overdraw&&(I(K.positionScreen,L.positionScreen), +I(L.positionScreen,fa.positionScreen),I(fa.positionScreen,K.positionScreen),I(U.positionScreen,Ca.positionScreen),I(U.positionScreen,$a.positionScreen));Va.setFromPoints([K.positionScreen,L.positionScreen,U.positionScreen,fa.positionScreen]);X=K;wa=L;Bb=U;hb=fa;Cb=Ca;Db=$a;l.info.render.vertices+=4;l.info.render.faces++;b(P.opacity);c(P.blending);void 0!==P.map&&null!==P.map||void 0!==P.envMap&&null!==P.envMap?(x(X,wa,hb,0,1,3,H,P),x(Cb,Bb,Db,1,2,3,H,P)):(M=X.positionScreen.x,ca=X.positionScreen.y, +qa=wa.positionScreen.x,ha=wa.positionScreen.y,ra=Bb.positionScreen.x,N=Bb.positionScreen.y,Ma=hb.positionScreen.x,Na=hb.positionScreen.y,mb=Cb.positionScreen.x,Pa=Cb.positionScreen.y,ta=Db.positionScreen.x,ka=Db.positionScreen.y,P instanceof THREE.MeshLambertMaterial||P instanceof THREE.MeshPhongMaterial?(Z.copy(P.color),oa.copy(P.emissive),P.vertexColors===THREE.FaceColors&&Z.multiply(H.color),!0===gc?!1===P.wireframe&&P.shading==THREE.SmoothShading&&4==H.vertexNormalsLength?(pa.copy(vb),Y.copy(vb), +da.copy(vb),la.copy(vb),q(H.v1.positionWorld,H.vertexNormalsModel[0],pa),q(H.v2.positionWorld,H.vertexNormalsModel[1],Y),q(H.v4.positionWorld,H.vertexNormalsModel[3],da),q(H.v3.positionWorld,H.vertexNormalsModel[2],la),pa.multiply(Z).add(oa),Y.multiply(Z).add(oa),da.multiply(Z).add(oa),la.multiply(Z).add(oa),Fa=E(pa,Y,da,la),y(M,ca,qa,ha,Ma,Na),G(M,ca,qa,ha,Ma,Na,0,0,1,0,0,1,Fa),y(mb,Pa,ra,N,ta,ka),G(mb,Pa,ra,N,ta,ka,1,0,1,1,0,1,Fa)):(aa.copy(vb),q(H.centroidModel,H.normalModel,aa),aa.multiply(Z).add(oa), +B(M,ca,qa,ha,ra,N,Ma,Na),!0===P.wireframe?C(aa,P.wireframeLinewidth,P.wireframeLinecap,P.wireframeLinejoin):A(aa)):(aa.addColors(Z,oa),B(M,ca,qa,ha,ra,N,Ma,Na),!0===P.wireframe?C(aa,P.wireframeLinewidth,P.wireframeLinecap,P.wireframeLinejoin):A(aa))):P instanceof THREE.MeshBasicMaterial?(aa.copy(P.color),P.vertexColors===THREE.FaceColors&&aa.multiply(H.color),B(M,ca,qa,ha,ra,N,Ma,Na),!0===P.wireframe?C(aa,P.wireframeLinewidth,P.wireframeLinecap,P.wireframeLinejoin):A(aa)):P instanceof THREE.MeshNormalMaterial? +(X=void 0,P.shading==THREE.FlatShading?(X=H.normalModelView,aa.setRGB(X.x,X.y,X.z).multiplyScalar(0.5).addScalar(0.5),B(M,ca,qa,ha,ra,N,Ma,Na),!0===P.wireframe?C(aa,P.wireframeLinewidth,P.wireframeLinecap,P.wireframeLinejoin):A(aa)):P.shading==THREE.SmoothShading&&(X=H.vertexNormalsModelView[0],pa.setRGB(X.x,X.y,X.z).multiplyScalar(0.5).addScalar(0.5),X=H.vertexNormalsModelView[1],Y.setRGB(X.x,X.y,X.z).multiplyScalar(0.5).addScalar(0.5),X=H.vertexNormalsModelView[3],da.setRGB(X.x,X.y,X.z).multiplyScalar(0.5).addScalar(0.5), +X=H.vertexNormalsModelView[2],la.setRGB(X.x,X.y,X.z).multiplyScalar(0.5).addScalar(0.5),Fa=E(pa,Y,da,la),y(M,ca,qa,ha,Ma,Na),G(M,ca,qa,ha,Ma,Na,0,0,1,0,0,1,Fa),y(mb,Pa,ra,N,ta,ka),G(mb,Pa,ra,N,ta,ka,1,0,1,1,0,1,Fa))):P instanceof THREE.MeshDepthMaterial&&(Wa=p.near,ab=p.far,pa.r=pa.g=pa.b=1-k(X.positionScreen.z*X.positionScreen.w,Wa,ab),Y.r=Y.g=Y.b=1-k(wa.positionScreen.z*wa.positionScreen.w,Wa,ab),da.r=da.g=da.b=1-k(hb.positionScreen.z*hb.positionScreen.w,Wa,ab),la.r=la.g=la.b=1-k(Bb.positionScreen.z* +Bb.positionScreen.w,Wa,ab),Fa=E(pa,Y,da,la),y(M,ca,qa,ha,Ma,Na),G(M,ca,qa,ha,Ma,Na,0,0,1,0,0,1,Fa),y(mb,Pa,ra,N,ta,ka),G(mb,Pa,ra,N,ta,ka,1,0,1,1,0,1,Fa)))}Ka.union(Va)}}t.setTransform(1,0,0,1,0,0)}}};THREE.ShaderChunk={fog_pars_fragment:"#ifdef USE_FOG\nuniform vec3 fogColor;\n#ifdef FOG_EXP2\nuniform float fogDensity;\n#else\nuniform float fogNear;\nuniform float fogFar;\n#endif\n#endif",fog_fragment:"#ifdef USE_FOG\nfloat depth = gl_FragCoord.z / gl_FragCoord.w;\n#ifdef FOG_EXP2\nconst float LOG2 = 1.442695;\nfloat fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );\nfogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );\n#else\nfloat fogFactor = smoothstep( fogNear, fogFar, depth );\n#endif\ngl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );\n#endif", +envmap_pars_fragment:"#ifdef USE_ENVMAP\nuniform float reflectivity;\nuniform samplerCube envMap;\nuniform float flipEnvMap;\nuniform int combine;\n#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\nuniform bool useRefract;\nuniform float refractionRatio;\n#else\nvarying vec3 vReflect;\n#endif\n#endif",envmap_fragment:"#ifdef USE_ENVMAP\nvec3 reflectVec;\n#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\nvec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\nif ( useRefract ) {\nreflectVec = refract( cameraToVertex, normal, refractionRatio );\n} else { \nreflectVec = reflect( cameraToVertex, normal );\n}\n#else\nreflectVec = vReflect;\n#endif\n#ifdef DOUBLE_SIDED\nfloat flipNormal = ( -1.0 + 2.0 * float( gl_FrontFacing ) );\nvec4 cubeColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n#else\nvec4 cubeColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n#endif\n#ifdef GAMMA_INPUT\ncubeColor.xyz *= cubeColor.xyz;\n#endif\nif ( combine == 1 ) {\ngl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularStrength * reflectivity );\n} else if ( combine == 2 ) {\ngl_FragColor.xyz += cubeColor.xyz * specularStrength * reflectivity;\n} else {\ngl_FragColor.xyz = mix( gl_FragColor.xyz, gl_FragColor.xyz * cubeColor.xyz, specularStrength * reflectivity );\n}\n#endif", +envmap_pars_vertex:"#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP )\nvarying vec3 vReflect;\nuniform float refractionRatio;\nuniform bool useRefract;\n#endif",worldpos_vertex:"#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )\n#ifdef USE_SKINNING\nvec4 worldPosition = modelMatrix * skinned;\n#endif\n#if defined( USE_MORPHTARGETS ) && ! defined( USE_SKINNING )\nvec4 worldPosition = modelMatrix * vec4( morphed, 1.0 );\n#endif\n#if ! defined( USE_MORPHTARGETS ) && ! defined( USE_SKINNING )\nvec4 worldPosition = modelMatrix * vec4( position, 1.0 );\n#endif\n#endif", +envmap_vertex:"#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP )\nvec3 worldNormal = mat3( modelMatrix[ 0 ].xyz, modelMatrix[ 1 ].xyz, modelMatrix[ 2 ].xyz ) * objectNormal;\nworldNormal = normalize( worldNormal );\nvec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );\nif ( useRefract ) {\nvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n} else {\nvReflect = reflect( cameraToVertex, worldNormal );\n}\n#endif",map_particle_pars_fragment:"#ifdef USE_MAP\nuniform sampler2D map;\n#endif", +map_particle_fragment:"#ifdef USE_MAP\ngl_FragColor = gl_FragColor * texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) );\n#endif",map_pars_vertex:"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )\nvarying vec2 vUv;\nuniform vec4 offsetRepeat;\n#endif",map_pars_fragment:"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )\nvarying vec2 vUv;\n#endif\n#ifdef USE_MAP\nuniform sampler2D map;\n#endif", +map_vertex:"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )\nvUv = uv * offsetRepeat.zw + offsetRepeat.xy;\n#endif",map_fragment:"#ifdef USE_MAP\nvec4 texelColor = texture2D( map, vUv );\n#ifdef GAMMA_INPUT\ntexelColor.xyz *= texelColor.xyz;\n#endif\ngl_FragColor = gl_FragColor * texelColor;\n#endif",lightmap_pars_fragment:"#ifdef USE_LIGHTMAP\nvarying vec2 vUv2;\nuniform sampler2D lightMap;\n#endif",lightmap_pars_vertex:"#ifdef USE_LIGHTMAP\nvarying vec2 vUv2;\n#endif", +lightmap_fragment:"#ifdef USE_LIGHTMAP\ngl_FragColor = gl_FragColor * texture2D( lightMap, vUv2 );\n#endif",lightmap_vertex:"#ifdef USE_LIGHTMAP\nvUv2 = uv2;\n#endif",bumpmap_pars_fragment:"#ifdef USE_BUMPMAP\nuniform sampler2D bumpMap;\nuniform float bumpScale;\nvec2 dHdxy_fwd() {\nvec2 dSTdx = dFdx( vUv );\nvec2 dSTdy = dFdy( vUv );\nfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\nfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\nfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\nreturn vec2( dBx, dBy );\n}\nvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\nvec3 vSigmaX = dFdx( surf_pos );\nvec3 vSigmaY = dFdy( surf_pos );\nvec3 vN = surf_norm;\nvec3 R1 = cross( vSigmaY, vN );\nvec3 R2 = cross( vN, vSigmaX );\nfloat fDet = dot( vSigmaX, R1 );\nvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\nreturn normalize( abs( fDet ) * surf_norm - vGrad );\n}\n#endif", +normalmap_pars_fragment:"#ifdef USE_NORMALMAP\nuniform sampler2D normalMap;\nuniform vec2 normalScale;\nvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {\nvec3 q0 = dFdx( eye_pos.xyz );\nvec3 q1 = dFdy( eye_pos.xyz );\nvec2 st0 = dFdx( vUv.st );\nvec2 st1 = dFdy( vUv.st );\nvec3 S = normalize( q0 * st1.t - q1 * st0.t );\nvec3 T = normalize( -q0 * st1.s + q1 * st0.s );\nvec3 N = normalize( surf_norm );\nvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\nmapN.xy = normalScale * mapN.xy;\nmat3 tsn = mat3( S, T, N );\nreturn normalize( tsn * mapN );\n}\n#endif", +specularmap_pars_fragment:"#ifdef USE_SPECULARMAP\nuniform sampler2D specularMap;\n#endif",specularmap_fragment:"float specularStrength;\n#ifdef USE_SPECULARMAP\nvec4 texelSpecular = texture2D( specularMap, vUv );\nspecularStrength = texelSpecular.r;\n#else\nspecularStrength = 1.0;\n#endif",lights_lambert_pars_vertex:"uniform vec3 ambient;\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 ambientLightColor;\n#if MAX_DIR_LIGHTS > 0\nuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\nuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n#endif\n#if MAX_HEMI_LIGHTS > 0\nuniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\nuniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\nuniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n#endif\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\nuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n#endif\n#if MAX_SPOT_LIGHTS > 0\nuniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\nuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\nuniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\nuniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\n#endif\n#ifdef WRAP_AROUND\nuniform vec3 wrapRGB;\n#endif", +lights_lambert_vertex:"vLightFront = vec3( 0.0 );\n#ifdef DOUBLE_SIDED\nvLightBack = vec3( 0.0 );\n#endif\ntransformedNormal = normalize( transformedNormal );\n#if MAX_DIR_LIGHTS > 0\nfor( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {\nvec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );\nvec3 dirVector = normalize( lDirection.xyz );\nfloat dotProduct = dot( transformedNormal, dirVector );\nvec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );\n#ifdef DOUBLE_SIDED\nvec3 directionalLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n#ifdef WRAP_AROUND\nvec3 directionalLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n#endif\n#endif\n#ifdef WRAP_AROUND\nvec3 directionalLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\ndirectionalLightWeighting = mix( directionalLightWeighting, directionalLightWeightingHalf, wrapRGB );\n#ifdef DOUBLE_SIDED\ndirectionalLightWeightingBack = mix( directionalLightWeightingBack, directionalLightWeightingHalfBack, wrapRGB );\n#endif\n#endif\nvLightFront += directionalLightColor[ i ] * directionalLightWeighting;\n#ifdef DOUBLE_SIDED\nvLightBack += directionalLightColor[ i ] * directionalLightWeightingBack;\n#endif\n}\n#endif\n#if MAX_POINT_LIGHTS > 0\nfor( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz - mvPosition.xyz;\nfloat lDistance = 1.0;\nif ( pointLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );\nlVector = normalize( lVector );\nfloat dotProduct = dot( transformedNormal, lVector );\nvec3 pointLightWeighting = vec3( max( dotProduct, 0.0 ) );\n#ifdef DOUBLE_SIDED\nvec3 pointLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n#ifdef WRAP_AROUND\nvec3 pointLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n#endif\n#endif\n#ifdef WRAP_AROUND\nvec3 pointLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\npointLightWeighting = mix( pointLightWeighting, pointLightWeightingHalf, wrapRGB );\n#ifdef DOUBLE_SIDED\npointLightWeightingBack = mix( pointLightWeightingBack, pointLightWeightingHalfBack, wrapRGB );\n#endif\n#endif\nvLightFront += pointLightColor[ i ] * pointLightWeighting * lDistance;\n#ifdef DOUBLE_SIDED\nvLightBack += pointLightColor[ i ] * pointLightWeightingBack * lDistance;\n#endif\n}\n#endif\n#if MAX_SPOT_LIGHTS > 0\nfor( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz - mvPosition.xyz;\nfloat spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - worldPosition.xyz ) );\nif ( spotEffect > spotLightAngleCos[ i ] ) {\nspotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );\nfloat lDistance = 1.0;\nif ( spotLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );\nlVector = normalize( lVector );\nfloat dotProduct = dot( transformedNormal, lVector );\nvec3 spotLightWeighting = vec3( max( dotProduct, 0.0 ) );\n#ifdef DOUBLE_SIDED\nvec3 spotLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n#ifdef WRAP_AROUND\nvec3 spotLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n#endif\n#endif\n#ifdef WRAP_AROUND\nvec3 spotLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\nspotLightWeighting = mix( spotLightWeighting, spotLightWeightingHalf, wrapRGB );\n#ifdef DOUBLE_SIDED\nspotLightWeightingBack = mix( spotLightWeightingBack, spotLightWeightingHalfBack, wrapRGB );\n#endif\n#endif\nvLightFront += spotLightColor[ i ] * spotLightWeighting * lDistance * spotEffect;\n#ifdef DOUBLE_SIDED\nvLightBack += spotLightColor[ i ] * spotLightWeightingBack * lDistance * spotEffect;\n#endif\n}\n}\n#endif\n#if MAX_HEMI_LIGHTS > 0\nfor( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\nvec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );\nvec3 lVector = normalize( lDirection.xyz );\nfloat dotProduct = dot( transformedNormal, lVector );\nfloat hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\nfloat hemiDiffuseWeightBack = -0.5 * dotProduct + 0.5;\nvLightFront += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\n#ifdef DOUBLE_SIDED\nvLightBack += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeightBack );\n#endif\n}\n#endif\nvLightFront = vLightFront * diffuse + ambient * ambientLightColor + emissive;\n#ifdef DOUBLE_SIDED\nvLightBack = vLightBack * diffuse + ambient * ambientLightColor + emissive;\n#endif", +lights_phong_pars_vertex:"#ifndef PHONG_PER_PIXEL\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\nuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\nvarying vec4 vPointLight[ MAX_POINT_LIGHTS ];\n#endif\n#if MAX_SPOT_LIGHTS > 0\nuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\nuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\nvarying vec4 vSpotLight[ MAX_SPOT_LIGHTS ];\n#endif\n#endif\n#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )\nvarying vec3 vWorldPosition;\n#endif", +lights_phong_vertex:"#ifndef PHONG_PER_PIXEL\n#if MAX_POINT_LIGHTS > 0\nfor( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz - mvPosition.xyz;\nfloat lDistance = 1.0;\nif ( pointLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );\nvPointLight[ i ] = vec4( lVector, lDistance );\n}\n#endif\n#if MAX_SPOT_LIGHTS > 0\nfor( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz - mvPosition.xyz;\nfloat lDistance = 1.0;\nif ( spotLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );\nvSpotLight[ i ] = vec4( lVector, lDistance );\n}\n#endif\n#endif\n#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )\nvWorldPosition = worldPosition.xyz;\n#endif", +lights_phong_pars_fragment:"uniform vec3 ambientLightColor;\n#if MAX_DIR_LIGHTS > 0\nuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\nuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n#endif\n#if MAX_HEMI_LIGHTS > 0\nuniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\nuniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\nuniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n#endif\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\n#ifdef PHONG_PER_PIXEL\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\nuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n#else\nvarying vec4 vPointLight[ MAX_POINT_LIGHTS ];\n#endif\n#endif\n#if MAX_SPOT_LIGHTS > 0\nuniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\nuniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\nuniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\n#ifdef PHONG_PER_PIXEL\nuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\n#else\nvarying vec4 vSpotLight[ MAX_SPOT_LIGHTS ];\n#endif\n#endif\n#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )\nvarying vec3 vWorldPosition;\n#endif\n#ifdef WRAP_AROUND\nuniform vec3 wrapRGB;\n#endif\nvarying vec3 vViewPosition;\nvarying vec3 vNormal;", +lights_phong_fragment:"vec3 normal = normalize( vNormal );\nvec3 viewPosition = normalize( vViewPosition );\n#ifdef DOUBLE_SIDED\nnormal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );\n#endif\n#ifdef USE_NORMALMAP\nnormal = perturbNormal2Arb( -viewPosition, normal );\n#elif defined( USE_BUMPMAP )\nnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n#endif\n#if MAX_POINT_LIGHTS > 0\nvec3 pointDiffuse = vec3( 0.0 );\nvec3 pointSpecular = vec3( 0.0 );\nfor ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\n#ifdef PHONG_PER_PIXEL\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz + vViewPosition.xyz;\nfloat lDistance = 1.0;\nif ( pointLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );\nlVector = normalize( lVector );\n#else\nvec3 lVector = normalize( vPointLight[ i ].xyz );\nfloat lDistance = vPointLight[ i ].w;\n#endif\nfloat dotProduct = dot( normal, lVector );\n#ifdef WRAP_AROUND\nfloat pointDiffuseWeightFull = max( dotProduct, 0.0 );\nfloat pointDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\nvec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );\n#else\nfloat pointDiffuseWeight = max( dotProduct, 0.0 );\n#endif\npointDiffuse += diffuse * pointLightColor[ i ] * pointDiffuseWeight * lDistance;\nvec3 pointHalfVector = normalize( lVector + viewPosition );\nfloat pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );\nfloat pointSpecularWeight = specularStrength * max( pow( pointDotNormalHalf, shininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( shininess + 2.0001 ) / 8.0;\nvec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, pointHalfVector ), 5.0 );\npointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance * specularNormalization;\n#else\npointSpecular += specular * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance;\n#endif\n}\n#endif\n#if MAX_SPOT_LIGHTS > 0\nvec3 spotDiffuse = vec3( 0.0 );\nvec3 spotSpecular = vec3( 0.0 );\nfor ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\n#ifdef PHONG_PER_PIXEL\nvec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz + vViewPosition.xyz;\nfloat lDistance = 1.0;\nif ( spotLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );\nlVector = normalize( lVector );\n#else\nvec3 lVector = normalize( vSpotLight[ i ].xyz );\nfloat lDistance = vSpotLight[ i ].w;\n#endif\nfloat spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );\nif ( spotEffect > spotLightAngleCos[ i ] ) {\nspotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );\nfloat dotProduct = dot( normal, lVector );\n#ifdef WRAP_AROUND\nfloat spotDiffuseWeightFull = max( dotProduct, 0.0 );\nfloat spotDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\nvec3 spotDiffuseWeight = mix( vec3 ( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );\n#else\nfloat spotDiffuseWeight = max( dotProduct, 0.0 );\n#endif\nspotDiffuse += diffuse * spotLightColor[ i ] * spotDiffuseWeight * lDistance * spotEffect;\nvec3 spotHalfVector = normalize( lVector + viewPosition );\nfloat spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );\nfloat spotSpecularWeight = specularStrength * max( pow( spotDotNormalHalf, shininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( shininess + 2.0001 ) / 8.0;\nvec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, spotHalfVector ), 5.0 );\nspotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * lDistance * specularNormalization * spotEffect;\n#else\nspotSpecular += specular * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * lDistance * spotEffect;\n#endif\n}\n}\n#endif\n#if MAX_DIR_LIGHTS > 0\nvec3 dirDiffuse = vec3( 0.0 );\nvec3 dirSpecular = vec3( 0.0 );\nfor( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {\nvec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );\nvec3 dirVector = normalize( lDirection.xyz );\nfloat dotProduct = dot( normal, dirVector );\n#ifdef WRAP_AROUND\nfloat dirDiffuseWeightFull = max( dotProduct, 0.0 );\nfloat dirDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\nvec3 dirDiffuseWeight = mix( vec3( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), wrapRGB );\n#else\nfloat dirDiffuseWeight = max( dotProduct, 0.0 );\n#endif\ndirDiffuse += diffuse * directionalLightColor[ i ] * dirDiffuseWeight;\nvec3 dirHalfVector = normalize( dirVector + viewPosition );\nfloat dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );\nfloat dirSpecularWeight = specularStrength * max( pow( dirDotNormalHalf, shininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( shininess + 2.0001 ) / 8.0;\nvec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( dirVector, dirHalfVector ), 5.0 );\ndirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;\n#else\ndirSpecular += specular * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight;\n#endif\n}\n#endif\n#if MAX_HEMI_LIGHTS > 0\nvec3 hemiDiffuse = vec3( 0.0 );\nvec3 hemiSpecular = vec3( 0.0 );\nfor( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\nvec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );\nvec3 lVector = normalize( lDirection.xyz );\nfloat dotProduct = dot( normal, lVector );\nfloat hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\nvec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\nhemiDiffuse += diffuse * hemiColor;\nvec3 hemiHalfVectorSky = normalize( lVector + viewPosition );\nfloat hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;\nfloat hemiSpecularWeightSky = specularStrength * max( pow( hemiDotNormalHalfSky, shininess ), 0.0 );\nvec3 lVectorGround = -lVector;\nvec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );\nfloat hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;\nfloat hemiSpecularWeightGround = specularStrength * max( pow( hemiDotNormalHalfGround, shininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat dotProductGround = dot( normal, lVectorGround );\nfloat specularNormalization = ( shininess + 2.0001 ) / 8.0;\nvec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, hemiHalfVectorSky ), 5.0 );\nvec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 5.0 );\nhemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );\n#else\nhemiSpecular += specular * hemiColor * ( hemiSpecularWeightSky + hemiSpecularWeightGround ) * hemiDiffuseWeight;\n#endif\n}\n#endif\nvec3 totalDiffuse = vec3( 0.0 );\nvec3 totalSpecular = vec3( 0.0 );\n#if MAX_DIR_LIGHTS > 0\ntotalDiffuse += dirDiffuse;\ntotalSpecular += dirSpecular;\n#endif\n#if MAX_HEMI_LIGHTS > 0\ntotalDiffuse += hemiDiffuse;\ntotalSpecular += hemiSpecular;\n#endif\n#if MAX_POINT_LIGHTS > 0\ntotalDiffuse += pointDiffuse;\ntotalSpecular += pointSpecular;\n#endif\n#if MAX_SPOT_LIGHTS > 0\ntotalDiffuse += spotDiffuse;\ntotalSpecular += spotSpecular;\n#endif\n#ifdef METAL\ngl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient + totalSpecular );\n#else\ngl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient ) + totalSpecular;\n#endif", +color_pars_fragment:"#ifdef USE_COLOR\nvarying vec3 vColor;\n#endif",color_fragment:"#ifdef USE_COLOR\ngl_FragColor = gl_FragColor * vec4( vColor, opacity );\n#endif",color_pars_vertex:"#ifdef USE_COLOR\nvarying vec3 vColor;\n#endif",color_vertex:"#ifdef USE_COLOR\n#ifdef GAMMA_INPUT\nvColor = color * color;\n#else\nvColor = color;\n#endif\n#endif",skinning_pars_vertex:"#ifdef USE_SKINNING\n#ifdef BONE_TEXTURE\nuniform sampler2D boneTexture;\nmat4 getBoneMatrix( const in float i ) {\nfloat j = i * 4.0;\nfloat x = mod( j, N_BONE_PIXEL_X );\nfloat y = floor( j / N_BONE_PIXEL_X );\nconst float dx = 1.0 / N_BONE_PIXEL_X;\nconst float dy = 1.0 / N_BONE_PIXEL_Y;\ny = dy * ( y + 0.5 );\nvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\nvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\nvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\nvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\nmat4 bone = mat4( v1, v2, v3, v4 );\nreturn bone;\n}\n#else\nuniform mat4 boneGlobalMatrices[ MAX_BONES ];\nmat4 getBoneMatrix( const in float i ) {\nmat4 bone = boneGlobalMatrices[ int(i) ];\nreturn bone;\n}\n#endif\n#endif", +skinbase_vertex:"#ifdef USE_SKINNING\nmat4 boneMatX = getBoneMatrix( skinIndex.x );\nmat4 boneMatY = getBoneMatrix( skinIndex.y );\n#endif",skinning_vertex:"#ifdef USE_SKINNING\n#ifdef USE_MORPHTARGETS\nvec4 skinVertex = vec4( morphed, 1.0 );\n#else\nvec4 skinVertex = vec4( position, 1.0 );\n#endif\nvec4 skinned = boneMatX * skinVertex * skinWeight.x;\nskinned \t += boneMatY * skinVertex * skinWeight.y;\n#endif",morphtarget_pars_vertex:"#ifdef USE_MORPHTARGETS\n#ifndef USE_MORPHNORMALS\nuniform float morphTargetInfluences[ 8 ];\n#else\nuniform float morphTargetInfluences[ 4 ];\n#endif\n#endif", +morphtarget_vertex:"#ifdef USE_MORPHTARGETS\nvec3 morphed = vec3( 0.0 );\nmorphed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\nmorphed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\nmorphed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\nmorphed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\n#ifndef USE_MORPHNORMALS\nmorphed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\nmorphed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\nmorphed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\nmorphed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\n#endif\nmorphed += position;\n#endif", +default_vertex:"vec4 mvPosition;\n#ifdef USE_SKINNING\nmvPosition = modelViewMatrix * skinned;\n#endif\n#if !defined( USE_SKINNING ) && defined( USE_MORPHTARGETS )\nmvPosition = modelViewMatrix * vec4( morphed, 1.0 );\n#endif\n#if !defined( USE_SKINNING ) && ! defined( USE_MORPHTARGETS )\nmvPosition = modelViewMatrix * vec4( position, 1.0 );\n#endif\ngl_Position = projectionMatrix * mvPosition;",morphnormal_vertex:"#ifdef USE_MORPHNORMALS\nvec3 morphedNormal = vec3( 0.0 );\nmorphedNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];\nmorphedNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];\nmorphedNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];\nmorphedNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];\nmorphedNormal += normal;\n#endif", +skinnormal_vertex:"#ifdef USE_SKINNING\nmat4 skinMatrix = skinWeight.x * boneMatX;\nskinMatrix \t+= skinWeight.y * boneMatY;\n#ifdef USE_MORPHNORMALS\nvec4 skinnedNormal = skinMatrix * vec4( morphedNormal, 0.0 );\n#else\nvec4 skinnedNormal = skinMatrix * vec4( normal, 0.0 );\n#endif\n#endif",defaultnormal_vertex:"vec3 objectNormal;\n#ifdef USE_SKINNING\nobjectNormal = skinnedNormal.xyz;\n#endif\n#if !defined( USE_SKINNING ) && defined( USE_MORPHNORMALS )\nobjectNormal = morphedNormal;\n#endif\n#if !defined( USE_SKINNING ) && ! defined( USE_MORPHNORMALS )\nobjectNormal = normal;\n#endif\n#ifdef FLIP_SIDED\nobjectNormal = -objectNormal;\n#endif\nvec3 transformedNormal = normalMatrix * objectNormal;", +shadowmap_pars_fragment:"#ifdef USE_SHADOWMAP\nuniform sampler2D shadowMap[ MAX_SHADOWS ];\nuniform vec2 shadowMapSize[ MAX_SHADOWS ];\nuniform float shadowDarkness[ MAX_SHADOWS ];\nuniform float shadowBias[ MAX_SHADOWS ];\nvarying vec4 vShadowCoord[ MAX_SHADOWS ];\nfloat unpackDepth( const in vec4 rgba_depth ) {\nconst vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );\nfloat depth = dot( rgba_depth, bit_shift );\nreturn depth;\n}\n#endif",shadowmap_fragment:"#ifdef USE_SHADOWMAP\n#ifdef SHADOWMAP_DEBUG\nvec3 frustumColors[3];\nfrustumColors[0] = vec3( 1.0, 0.5, 0.0 );\nfrustumColors[1] = vec3( 0.0, 1.0, 0.8 );\nfrustumColors[2] = vec3( 0.0, 0.5, 1.0 );\n#endif\n#ifdef SHADOWMAP_CASCADE\nint inFrustumCount = 0;\n#endif\nfloat fDepth;\nvec3 shadowColor = vec3( 1.0 );\nfor( int i = 0; i < MAX_SHADOWS; i ++ ) {\nvec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;\nbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\nbool inFrustum = all( inFrustumVec );\n#ifdef SHADOWMAP_CASCADE\ninFrustumCount += int( inFrustum );\nbvec3 frustumTestVec = bvec3( inFrustum, inFrustumCount == 1, shadowCoord.z <= 1.0 );\n#else\nbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n#endif\nbool frustumTest = all( frustumTestVec );\nif ( frustumTest ) {\nshadowCoord.z += shadowBias[ i ];\n#if defined( SHADOWMAP_TYPE_PCF )\nfloat shadow = 0.0;\nconst float shadowDelta = 1.0 / 9.0;\nfloat xPixelOffset = 1.0 / shadowMapSize[ i ].x;\nfloat yPixelOffset = 1.0 / shadowMapSize[ i ].y;\nfloat dx0 = -1.25 * xPixelOffset;\nfloat dy0 = -1.25 * yPixelOffset;\nfloat dx1 = 1.25 * xPixelOffset;\nfloat dy1 = 1.25 * yPixelOffset;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nshadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );\n#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\nfloat shadow = 0.0;\nfloat xPixelOffset = 1.0 / shadowMapSize[ i ].x;\nfloat yPixelOffset = 1.0 / shadowMapSize[ i ].y;\nfloat dx0 = -1.0 * xPixelOffset;\nfloat dy0 = -1.0 * yPixelOffset;\nfloat dx1 = 1.0 * xPixelOffset;\nfloat dy1 = 1.0 * yPixelOffset;\nmat3 shadowKernel;\nmat3 depthKernel;\ndepthKernel[0][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );\nif ( depthKernel[0][0] < shadowCoord.z ) shadowKernel[0][0] = 0.25;\nelse shadowKernel[0][0] = 0.0;\ndepthKernel[0][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );\nif ( depthKernel[0][1] < shadowCoord.z ) shadowKernel[0][1] = 0.25;\nelse shadowKernel[0][1] = 0.0;\ndepthKernel[0][2] = unpackDepth( texture2D( shadowMap[ i], shadowCoord.xy + vec2( dx0, dy1 ) ) );\nif ( depthKernel[0][2] < shadowCoord.z ) shadowKernel[0][2] = 0.25;\nelse shadowKernel[0][2] = 0.0;\ndepthKernel[1][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );\nif ( depthKernel[1][0] < shadowCoord.z ) shadowKernel[1][0] = 0.25;\nelse shadowKernel[1][0] = 0.0;\ndepthKernel[1][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );\nif ( depthKernel[1][1] < shadowCoord.z ) shadowKernel[1][1] = 0.25;\nelse shadowKernel[1][1] = 0.0;\ndepthKernel[1][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );\nif ( depthKernel[1][2] < shadowCoord.z ) shadowKernel[1][2] = 0.25;\nelse shadowKernel[1][2] = 0.0;\ndepthKernel[2][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );\nif ( depthKernel[2][0] < shadowCoord.z ) shadowKernel[2][0] = 0.25;\nelse shadowKernel[2][0] = 0.0;\ndepthKernel[2][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );\nif ( depthKernel[2][1] < shadowCoord.z ) shadowKernel[2][1] = 0.25;\nelse shadowKernel[2][1] = 0.0;\ndepthKernel[2][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );\nif ( depthKernel[2][2] < shadowCoord.z ) shadowKernel[2][2] = 0.25;\nelse shadowKernel[2][2] = 0.0;\nvec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[i].xy );\nshadowKernel[0] = mix( shadowKernel[1], shadowKernel[0], fractionalCoord.x );\nshadowKernel[1] = mix( shadowKernel[2], shadowKernel[1], fractionalCoord.x );\nvec4 shadowValues;\nshadowValues.x = mix( shadowKernel[0][1], shadowKernel[0][0], fractionalCoord.y );\nshadowValues.y = mix( shadowKernel[0][2], shadowKernel[0][1], fractionalCoord.y );\nshadowValues.z = mix( shadowKernel[1][1], shadowKernel[1][0], fractionalCoord.y );\nshadowValues.w = mix( shadowKernel[1][2], shadowKernel[1][1], fractionalCoord.y );\nshadow = dot( shadowValues, vec4( 1.0 ) );\nshadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );\n#else\nvec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );\nfloat fDepth = unpackDepth( rgbaDepth );\nif ( fDepth < shadowCoord.z )\nshadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] );\n#endif\n}\n#ifdef SHADOWMAP_DEBUG\n#ifdef SHADOWMAP_CASCADE\nif ( inFrustum && inFrustumCount == 1 ) gl_FragColor.xyz *= frustumColors[ i ];\n#else\nif ( inFrustum ) gl_FragColor.xyz *= frustumColors[ i ];\n#endif\n#endif\n}\n#ifdef GAMMA_OUTPUT\nshadowColor *= shadowColor;\n#endif\ngl_FragColor.xyz = gl_FragColor.xyz * shadowColor;\n#endif", +shadowmap_pars_vertex:"#ifdef USE_SHADOWMAP\nvarying vec4 vShadowCoord[ MAX_SHADOWS ];\nuniform mat4 shadowMatrix[ MAX_SHADOWS ];\n#endif",shadowmap_vertex:"#ifdef USE_SHADOWMAP\nfor( int i = 0; i < MAX_SHADOWS; i ++ ) {\nvShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;\n}\n#endif",alphatest_fragment:"#ifdef ALPHATEST\nif ( gl_FragColor.a < ALPHATEST ) discard;\n#endif",linear_to_gamma_fragment:"#ifdef GAMMA_OUTPUT\ngl_FragColor.xyz = sqrt( gl_FragColor.xyz );\n#endif"}; +THREE.UniformsUtils={merge:function(a){var b,c,d,e={};for(b=0;b<a.length;b++)for(c in d=this.clone(a[b]),d)e[c]=d[c];return e},clone:function(a){var b,c,d,e={};for(b in a)for(c in e[b]={},a[b])d=a[b][c],e[b][c]=d instanceof THREE.Color||d instanceof THREE.Vector2||d instanceof THREE.Vector3||d instanceof THREE.Vector4||d instanceof THREE.Matrix4||d instanceof THREE.Texture?d.clone():d instanceof Array?d.slice():d;return e}}; +THREE.UniformsLib={common:{diffuse:{type:"c",value:new THREE.Color(15658734)},opacity:{type:"f",value:1},map:{type:"t",value:null},offsetRepeat:{type:"v4",value:new THREE.Vector4(0,0,1,1)},lightMap:{type:"t",value:null},specularMap:{type:"t",value:null},envMap:{type:"t",value:null},flipEnvMap:{type:"f",value:-1},useRefract:{type:"i",value:0},reflectivity:{type:"f",value:1},refractionRatio:{type:"f",value:0.98},combine:{type:"i",value:0},morphTargetInfluences:{type:"f",value:0}},bump:{bumpMap:{type:"t", +value:null},bumpScale:{type:"f",value:1}},normalmap:{normalMap:{type:"t",value:null},normalScale:{type:"v2",value:new THREE.Vector2(1,1)}},fog:{fogDensity:{type:"f",value:2.5E-4},fogNear:{type:"f",value:1},fogFar:{type:"f",value:2E3},fogColor:{type:"c",value:new THREE.Color(16777215)}},lights:{ambientLightColor:{type:"fv",value:[]},directionalLightDirection:{type:"fv",value:[]},directionalLightColor:{type:"fv",value:[]},hemisphereLightDirection:{type:"fv",value:[]},hemisphereLightSkyColor:{type:"fv", +value:[]},hemisphereLightGroundColor:{type:"fv",value:[]},pointLightColor:{type:"fv",value:[]},pointLightPosition:{type:"fv",value:[]},pointLightDistance:{type:"fv1",value:[]},spotLightColor:{type:"fv",value:[]},spotLightPosition:{type:"fv",value:[]},spotLightDirection:{type:"fv",value:[]},spotLightDistance:{type:"fv1",value:[]},spotLightAngleCos:{type:"fv1",value:[]},spotLightExponent:{type:"fv1",value:[]}},particle:{psColor:{type:"c",value:new THREE.Color(15658734)},opacity:{type:"f",value:1},size:{type:"f", +value:1},scale:{type:"f",value:1},map:{type:"t",value:null},fogDensity:{type:"f",value:2.5E-4},fogNear:{type:"f",value:1},fogFar:{type:"f",value:2E3},fogColor:{type:"c",value:new THREE.Color(16777215)}},shadowmap:{shadowMap:{type:"tv",value:[]},shadowMapSize:{type:"v2v",value:[]},shadowBias:{type:"fv1",value:[]},shadowDarkness:{type:"fv1",value:[]},shadowMatrix:{type:"m4v",value:[]}}}; +THREE.ShaderLib={basic:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.common,THREE.UniformsLib.fog,THREE.UniformsLib.shadowmap]),vertexShader:[THREE.ShaderChunk.map_pars_vertex,THREE.ShaderChunk.lightmap_pars_vertex,THREE.ShaderChunk.envmap_pars_vertex,THREE.ShaderChunk.color_pars_vertex,THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.skinning_pars_vertex,THREE.ShaderChunk.shadowmap_pars_vertex,"void main() {",THREE.ShaderChunk.map_vertex,THREE.ShaderChunk.lightmap_vertex,THREE.ShaderChunk.color_vertex, +THREE.ShaderChunk.skinbase_vertex,"#ifdef USE_ENVMAP",THREE.ShaderChunk.morphnormal_vertex,THREE.ShaderChunk.skinnormal_vertex,THREE.ShaderChunk.defaultnormal_vertex,"#endif",THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.skinning_vertex,THREE.ShaderChunk.default_vertex,THREE.ShaderChunk.worldpos_vertex,THREE.ShaderChunk.envmap_vertex,THREE.ShaderChunk.shadowmap_vertex,"}"].join("\n"),fragmentShader:["uniform vec3 diffuse;\nuniform float opacity;",THREE.ShaderChunk.color_pars_fragment,THREE.ShaderChunk.map_pars_fragment, +THREE.ShaderChunk.lightmap_pars_fragment,THREE.ShaderChunk.envmap_pars_fragment,THREE.ShaderChunk.fog_pars_fragment,THREE.ShaderChunk.shadowmap_pars_fragment,THREE.ShaderChunk.specularmap_pars_fragment,"void main() {\ngl_FragColor = vec4( diffuse, opacity );",THREE.ShaderChunk.map_fragment,THREE.ShaderChunk.alphatest_fragment,THREE.ShaderChunk.specularmap_fragment,THREE.ShaderChunk.lightmap_fragment,THREE.ShaderChunk.color_fragment,THREE.ShaderChunk.envmap_fragment,THREE.ShaderChunk.shadowmap_fragment, +THREE.ShaderChunk.linear_to_gamma_fragment,THREE.ShaderChunk.fog_fragment,"}"].join("\n")},lambert:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.common,THREE.UniformsLib.fog,THREE.UniformsLib.lights,THREE.UniformsLib.shadowmap,{ambient:{type:"c",value:new THREE.Color(16777215)},emissive:{type:"c",value:new THREE.Color(0)},wrapRGB:{type:"v3",value:new THREE.Vector3(1,1,1)}}]),vertexShader:["#define LAMBERT\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\nvarying vec3 vLightBack;\n#endif", +THREE.ShaderChunk.map_pars_vertex,THREE.ShaderChunk.lightmap_pars_vertex,THREE.ShaderChunk.envmap_pars_vertex,THREE.ShaderChunk.lights_lambert_pars_vertex,THREE.ShaderChunk.color_pars_vertex,THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.skinning_pars_vertex,THREE.ShaderChunk.shadowmap_pars_vertex,"void main() {",THREE.ShaderChunk.map_vertex,THREE.ShaderChunk.lightmap_vertex,THREE.ShaderChunk.color_vertex,THREE.ShaderChunk.morphnormal_vertex,THREE.ShaderChunk.skinbase_vertex,THREE.ShaderChunk.skinnormal_vertex, +THREE.ShaderChunk.defaultnormal_vertex,THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.skinning_vertex,THREE.ShaderChunk.default_vertex,THREE.ShaderChunk.worldpos_vertex,THREE.ShaderChunk.envmap_vertex,THREE.ShaderChunk.lights_lambert_vertex,THREE.ShaderChunk.shadowmap_vertex,"}"].join("\n"),fragmentShader:["uniform float opacity;\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\nvarying vec3 vLightBack;\n#endif",THREE.ShaderChunk.color_pars_fragment,THREE.ShaderChunk.map_pars_fragment,THREE.ShaderChunk.lightmap_pars_fragment, +THREE.ShaderChunk.envmap_pars_fragment,THREE.ShaderChunk.fog_pars_fragment,THREE.ShaderChunk.shadowmap_pars_fragment,THREE.ShaderChunk.specularmap_pars_fragment,"void main() {\ngl_FragColor = vec4( vec3 ( 1.0 ), opacity );",THREE.ShaderChunk.map_fragment,THREE.ShaderChunk.alphatest_fragment,THREE.ShaderChunk.specularmap_fragment,"#ifdef DOUBLE_SIDED\nif ( gl_FrontFacing )\ngl_FragColor.xyz *= vLightFront;\nelse\ngl_FragColor.xyz *= vLightBack;\n#else\ngl_FragColor.xyz *= vLightFront;\n#endif",THREE.ShaderChunk.lightmap_fragment, +THREE.ShaderChunk.color_fragment,THREE.ShaderChunk.envmap_fragment,THREE.ShaderChunk.shadowmap_fragment,THREE.ShaderChunk.linear_to_gamma_fragment,THREE.ShaderChunk.fog_fragment,"}"].join("\n")},phong:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.common,THREE.UniformsLib.bump,THREE.UniformsLib.normalmap,THREE.UniformsLib.fog,THREE.UniformsLib.lights,THREE.UniformsLib.shadowmap,{ambient:{type:"c",value:new THREE.Color(16777215)},emissive:{type:"c",value:new THREE.Color(0)},specular:{type:"c", +value:new THREE.Color(1118481)},shininess:{type:"f",value:30},wrapRGB:{type:"v3",value:new THREE.Vector3(1,1,1)}}]),vertexShader:["#define PHONG\nvarying vec3 vViewPosition;\nvarying vec3 vNormal;",THREE.ShaderChunk.map_pars_vertex,THREE.ShaderChunk.lightmap_pars_vertex,THREE.ShaderChunk.envmap_pars_vertex,THREE.ShaderChunk.lights_phong_pars_vertex,THREE.ShaderChunk.color_pars_vertex,THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.skinning_pars_vertex,THREE.ShaderChunk.shadowmap_pars_vertex, +"void main() {",THREE.ShaderChunk.map_vertex,THREE.ShaderChunk.lightmap_vertex,THREE.ShaderChunk.color_vertex,THREE.ShaderChunk.morphnormal_vertex,THREE.ShaderChunk.skinbase_vertex,THREE.ShaderChunk.skinnormal_vertex,THREE.ShaderChunk.defaultnormal_vertex,"vNormal = normalize( transformedNormal );",THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.skinning_vertex,THREE.ShaderChunk.default_vertex,"vViewPosition = -mvPosition.xyz;",THREE.ShaderChunk.worldpos_vertex,THREE.ShaderChunk.envmap_vertex, +THREE.ShaderChunk.lights_phong_vertex,THREE.ShaderChunk.shadowmap_vertex,"}"].join("\n"),fragmentShader:["uniform vec3 diffuse;\nuniform float opacity;\nuniform vec3 ambient;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;",THREE.ShaderChunk.color_pars_fragment,THREE.ShaderChunk.map_pars_fragment,THREE.ShaderChunk.lightmap_pars_fragment,THREE.ShaderChunk.envmap_pars_fragment,THREE.ShaderChunk.fog_pars_fragment,THREE.ShaderChunk.lights_phong_pars_fragment,THREE.ShaderChunk.shadowmap_pars_fragment, +THREE.ShaderChunk.bumpmap_pars_fragment,THREE.ShaderChunk.normalmap_pars_fragment,THREE.ShaderChunk.specularmap_pars_fragment,"void main() {\ngl_FragColor = vec4( vec3 ( 1.0 ), opacity );",THREE.ShaderChunk.map_fragment,THREE.ShaderChunk.alphatest_fragment,THREE.ShaderChunk.specularmap_fragment,THREE.ShaderChunk.lights_phong_fragment,THREE.ShaderChunk.lightmap_fragment,THREE.ShaderChunk.color_fragment,THREE.ShaderChunk.envmap_fragment,THREE.ShaderChunk.shadowmap_fragment,THREE.ShaderChunk.linear_to_gamma_fragment, +THREE.ShaderChunk.fog_fragment,"}"].join("\n")},particle_basic:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.particle,THREE.UniformsLib.shadowmap]),vertexShader:["uniform float size;\nuniform float scale;",THREE.ShaderChunk.color_pars_vertex,THREE.ShaderChunk.shadowmap_pars_vertex,"void main() {",THREE.ShaderChunk.color_vertex,"vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n#ifdef USE_SIZEATTENUATION\ngl_PointSize = size * ( scale / length( mvPosition.xyz ) );\n#else\ngl_PointSize = size;\n#endif\ngl_Position = projectionMatrix * mvPosition;", +THREE.ShaderChunk.worldpos_vertex,THREE.ShaderChunk.shadowmap_vertex,"}"].join("\n"),fragmentShader:["uniform vec3 psColor;\nuniform float opacity;",THREE.ShaderChunk.color_pars_fragment,THREE.ShaderChunk.map_particle_pars_fragment,THREE.ShaderChunk.fog_pars_fragment,THREE.ShaderChunk.shadowmap_pars_fragment,"void main() {\ngl_FragColor = vec4( psColor, opacity );",THREE.ShaderChunk.map_particle_fragment,THREE.ShaderChunk.alphatest_fragment,THREE.ShaderChunk.color_fragment,THREE.ShaderChunk.shadowmap_fragment, +THREE.ShaderChunk.fog_fragment,"}"].join("\n")},dashed:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.common,THREE.UniformsLib.fog,{scale:{type:"f",value:1},dashSize:{type:"f",value:1},totalSize:{type:"f",value:2}}]),vertexShader:["uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;",THREE.ShaderChunk.color_pars_vertex,"void main() {",THREE.ShaderChunk.color_vertex,"vLineDistance = scale * lineDistance;\nvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\ngl_Position = projectionMatrix * mvPosition;\n}"].join("\n"), +fragmentShader:["uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;",THREE.ShaderChunk.color_pars_fragment,THREE.ShaderChunk.fog_pars_fragment,"void main() {\nif ( mod( vLineDistance, totalSize ) > dashSize ) {\ndiscard;\n}\ngl_FragColor = vec4( diffuse, opacity );",THREE.ShaderChunk.color_fragment,THREE.ShaderChunk.fog_fragment,"}"].join("\n")},depth:{uniforms:{mNear:{type:"f",value:1},mFar:{type:"f",value:2E3},opacity:{type:"f", +value:1}},vertexShader:"void main() {\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"uniform float mNear;\nuniform float mFar;\nuniform float opacity;\nvoid main() {\nfloat depth = gl_FragCoord.z / gl_FragCoord.w;\nfloat color = 1.0 - smoothstep( mNear, mFar, depth );\ngl_FragColor = vec4( vec3( color ), opacity );\n}"},normal:{uniforms:{opacity:{type:"f",value:1}},vertexShader:"varying vec3 vNormal;\nvoid main() {\nvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\nvNormal = normalize( normalMatrix * normal );\ngl_Position = projectionMatrix * mvPosition;\n}", +fragmentShader:"uniform float opacity;\nvarying vec3 vNormal;\nvoid main() {\ngl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, opacity );\n}"},normalmap:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.fog,THREE.UniformsLib.lights,THREE.UniformsLib.shadowmap,{enableAO:{type:"i",value:0},enableDiffuse:{type:"i",value:0},enableSpecular:{type:"i",value:0},enableReflection:{type:"i",value:0},enableDisplacement:{type:"i",value:0},tDisplacement:{type:"t",value:null},tDiffuse:{type:"t",value:null}, +tCube:{type:"t",value:null},tNormal:{type:"t",value:null},tSpecular:{type:"t",value:null},tAO:{type:"t",value:null},uNormalScale:{type:"v2",value:new THREE.Vector2(1,1)},uDisplacementBias:{type:"f",value:0},uDisplacementScale:{type:"f",value:1},uDiffuseColor:{type:"c",value:new THREE.Color(16777215)},uSpecularColor:{type:"c",value:new THREE.Color(1118481)},uAmbientColor:{type:"c",value:new THREE.Color(16777215)},uShininess:{type:"f",value:30},uOpacity:{type:"f",value:1},useRefract:{type:"i",value:0}, +uRefractionRatio:{type:"f",value:0.98},uReflectivity:{type:"f",value:0.5},uOffset:{type:"v2",value:new THREE.Vector2(0,0)},uRepeat:{type:"v2",value:new THREE.Vector2(1,1)},wrapRGB:{type:"v3",value:new THREE.Vector3(1,1,1)}}]),fragmentShader:["uniform vec3 uAmbientColor;\nuniform vec3 uDiffuseColor;\nuniform vec3 uSpecularColor;\nuniform float uShininess;\nuniform float uOpacity;\nuniform bool enableDiffuse;\nuniform bool enableSpecular;\nuniform bool enableAO;\nuniform bool enableReflection;\nuniform sampler2D tDiffuse;\nuniform sampler2D tNormal;\nuniform sampler2D tSpecular;\nuniform sampler2D tAO;\nuniform samplerCube tCube;\nuniform vec2 uNormalScale;\nuniform bool useRefract;\nuniform float uRefractionRatio;\nuniform float uReflectivity;\nvarying vec3 vTangent;\nvarying vec3 vBinormal;\nvarying vec3 vNormal;\nvarying vec2 vUv;\nuniform vec3 ambientLightColor;\n#if MAX_DIR_LIGHTS > 0\nuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\nuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n#endif\n#if MAX_HEMI_LIGHTS > 0\nuniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\nuniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\nuniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n#endif\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\nuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n#endif\n#if MAX_SPOT_LIGHTS > 0\nuniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\nuniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\nuniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\nuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\n#endif\n#ifdef WRAP_AROUND\nuniform vec3 wrapRGB;\n#endif\nvarying vec3 vWorldPosition;\nvarying vec3 vViewPosition;", +THREE.ShaderChunk.shadowmap_pars_fragment,THREE.ShaderChunk.fog_pars_fragment,"void main() {\ngl_FragColor = vec4( vec3( 1.0 ), uOpacity );\nvec3 specularTex = vec3( 1.0 );\nvec3 normalTex = texture2D( tNormal, vUv ).xyz * 2.0 - 1.0;\nnormalTex.xy *= uNormalScale;\nnormalTex = normalize( normalTex );\nif( enableDiffuse ) {\n#ifdef GAMMA_INPUT\nvec4 texelColor = texture2D( tDiffuse, vUv );\ntexelColor.xyz *= texelColor.xyz;\ngl_FragColor = gl_FragColor * texelColor;\n#else\ngl_FragColor = gl_FragColor * texture2D( tDiffuse, vUv );\n#endif\n}\nif( enableAO ) {\n#ifdef GAMMA_INPUT\nvec4 aoColor = texture2D( tAO, vUv );\naoColor.xyz *= aoColor.xyz;\ngl_FragColor.xyz = gl_FragColor.xyz * aoColor.xyz;\n#else\ngl_FragColor.xyz = gl_FragColor.xyz * texture2D( tAO, vUv ).xyz;\n#endif\n}\nif( enableSpecular )\nspecularTex = texture2D( tSpecular, vUv ).xyz;\nmat3 tsb = mat3( normalize( vTangent ), normalize( vBinormal ), normalize( vNormal ) );\nvec3 finalNormal = tsb * normalTex;\n#ifdef FLIP_SIDED\nfinalNormal = -finalNormal;\n#endif\nvec3 normal = normalize( finalNormal );\nvec3 viewPosition = normalize( vViewPosition );\n#if MAX_POINT_LIGHTS > 0\nvec3 pointDiffuse = vec3( 0.0 );\nvec3 pointSpecular = vec3( 0.0 );\nfor ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 pointVector = lPosition.xyz + vViewPosition.xyz;\nfloat pointDistance = 1.0;\nif ( pointLightDistance[ i ] > 0.0 )\npointDistance = 1.0 - min( ( length( pointVector ) / pointLightDistance[ i ] ), 1.0 );\npointVector = normalize( pointVector );\n#ifdef WRAP_AROUND\nfloat pointDiffuseWeightFull = max( dot( normal, pointVector ), 0.0 );\nfloat pointDiffuseWeightHalf = max( 0.5 * dot( normal, pointVector ) + 0.5, 0.0 );\nvec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );\n#else\nfloat pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );\n#endif\npointDiffuse += pointDistance * pointLightColor[ i ] * uDiffuseColor * pointDiffuseWeight;\nvec3 pointHalfVector = normalize( pointVector + viewPosition );\nfloat pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );\nfloat pointSpecularWeight = specularTex.r * max( pow( pointDotNormalHalf, uShininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( uShininess + 2.0001 ) / 8.0;\nvec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( pointVector, pointHalfVector ), 5.0 );\npointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * pointDistance * specularNormalization;\n#else\npointSpecular += pointDistance * pointLightColor[ i ] * uSpecularColor * pointSpecularWeight * pointDiffuseWeight;\n#endif\n}\n#endif\n#if MAX_SPOT_LIGHTS > 0\nvec3 spotDiffuse = vec3( 0.0 );\nvec3 spotSpecular = vec3( 0.0 );\nfor ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\nvec3 spotVector = lPosition.xyz + vViewPosition.xyz;\nfloat spotDistance = 1.0;\nif ( spotLightDistance[ i ] > 0.0 )\nspotDistance = 1.0 - min( ( length( spotVector ) / spotLightDistance[ i ] ), 1.0 );\nspotVector = normalize( spotVector );\nfloat spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );\nif ( spotEffect > spotLightAngleCos[ i ] ) {\nspotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );\n#ifdef WRAP_AROUND\nfloat spotDiffuseWeightFull = max( dot( normal, spotVector ), 0.0 );\nfloat spotDiffuseWeightHalf = max( 0.5 * dot( normal, spotVector ) + 0.5, 0.0 );\nvec3 spotDiffuseWeight = mix( vec3 ( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );\n#else\nfloat spotDiffuseWeight = max( dot( normal, spotVector ), 0.0 );\n#endif\nspotDiffuse += spotDistance * spotLightColor[ i ] * uDiffuseColor * spotDiffuseWeight * spotEffect;\nvec3 spotHalfVector = normalize( spotVector + viewPosition );\nfloat spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );\nfloat spotSpecularWeight = specularTex.r * max( pow( spotDotNormalHalf, uShininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( uShininess + 2.0001 ) / 8.0;\nvec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( spotVector, spotHalfVector ), 5.0 );\nspotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * spotDistance * specularNormalization * spotEffect;\n#else\nspotSpecular += spotDistance * spotLightColor[ i ] * uSpecularColor * spotSpecularWeight * spotDiffuseWeight * spotEffect;\n#endif\n}\n}\n#endif\n#if MAX_DIR_LIGHTS > 0\nvec3 dirDiffuse = vec3( 0.0 );\nvec3 dirSpecular = vec3( 0.0 );\nfor( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {\nvec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );\nvec3 dirVector = normalize( lDirection.xyz );\n#ifdef WRAP_AROUND\nfloat directionalLightWeightingFull = max( dot( normal, dirVector ), 0.0 );\nfloat directionalLightWeightingHalf = max( 0.5 * dot( normal, dirVector ) + 0.5, 0.0 );\nvec3 dirDiffuseWeight = mix( vec3( directionalLightWeightingFull ), vec3( directionalLightWeightingHalf ), wrapRGB );\n#else\nfloat dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );\n#endif\ndirDiffuse += directionalLightColor[ i ] * uDiffuseColor * dirDiffuseWeight;\nvec3 dirHalfVector = normalize( dirVector + viewPosition );\nfloat dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );\nfloat dirSpecularWeight = specularTex.r * max( pow( dirDotNormalHalf, uShininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( uShininess + 2.0001 ) / 8.0;\nvec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( dirVector, dirHalfVector ), 5.0 );\ndirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;\n#else\ndirSpecular += directionalLightColor[ i ] * uSpecularColor * dirSpecularWeight * dirDiffuseWeight;\n#endif\n}\n#endif\n#if MAX_HEMI_LIGHTS > 0\nvec3 hemiDiffuse = vec3( 0.0 );\nvec3 hemiSpecular = vec3( 0.0 );\nfor( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\nvec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );\nvec3 lVector = normalize( lDirection.xyz );\nfloat dotProduct = dot( normal, lVector );\nfloat hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\nvec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\nhemiDiffuse += uDiffuseColor * hemiColor;\nvec3 hemiHalfVectorSky = normalize( lVector + viewPosition );\nfloat hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;\nfloat hemiSpecularWeightSky = specularTex.r * max( pow( hemiDotNormalHalfSky, uShininess ), 0.0 );\nvec3 lVectorGround = -lVector;\nvec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );\nfloat hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;\nfloat hemiSpecularWeightGround = specularTex.r * max( pow( hemiDotNormalHalfGround, uShininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat dotProductGround = dot( normal, lVectorGround );\nfloat specularNormalization = ( uShininess + 2.0001 ) / 8.0;\nvec3 schlickSky = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( lVector, hemiHalfVectorSky ), 5.0 );\nvec3 schlickGround = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 5.0 );\nhemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );\n#else\nhemiSpecular += uSpecularColor * hemiColor * ( hemiSpecularWeightSky + hemiSpecularWeightGround ) * hemiDiffuseWeight;\n#endif\n}\n#endif\nvec3 totalDiffuse = vec3( 0.0 );\nvec3 totalSpecular = vec3( 0.0 );\n#if MAX_DIR_LIGHTS > 0\ntotalDiffuse += dirDiffuse;\ntotalSpecular += dirSpecular;\n#endif\n#if MAX_HEMI_LIGHTS > 0\ntotalDiffuse += hemiDiffuse;\ntotalSpecular += hemiSpecular;\n#endif\n#if MAX_POINT_LIGHTS > 0\ntotalDiffuse += pointDiffuse;\ntotalSpecular += pointSpecular;\n#endif\n#if MAX_SPOT_LIGHTS > 0\ntotalDiffuse += spotDiffuse;\ntotalSpecular += spotSpecular;\n#endif\n#ifdef METAL\ngl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * uAmbientColor + totalSpecular );\n#else\ngl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * uAmbientColor ) + totalSpecular;\n#endif\nif ( enableReflection ) {\nvec3 vReflect;\nvec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\nif ( useRefract ) {\nvReflect = refract( cameraToVertex, normal, uRefractionRatio );\n} else {\nvReflect = reflect( cameraToVertex, normal );\n}\nvec4 cubeColor = textureCube( tCube, vec3( -vReflect.x, vReflect.yz ) );\n#ifdef GAMMA_INPUT\ncubeColor.xyz *= cubeColor.xyz;\n#endif\ngl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularTex.r * uReflectivity );\n}", +THREE.ShaderChunk.shadowmap_fragment,THREE.ShaderChunk.linear_to_gamma_fragment,THREE.ShaderChunk.fog_fragment,"}"].join("\n"),vertexShader:["attribute vec4 tangent;\nuniform vec2 uOffset;\nuniform vec2 uRepeat;\nuniform bool enableDisplacement;\n#ifdef VERTEX_TEXTURES\nuniform sampler2D tDisplacement;\nuniform float uDisplacementScale;\nuniform float uDisplacementBias;\n#endif\nvarying vec3 vTangent;\nvarying vec3 vBinormal;\nvarying vec3 vNormal;\nvarying vec2 vUv;\nvarying vec3 vWorldPosition;\nvarying vec3 vViewPosition;", +THREE.ShaderChunk.skinning_pars_vertex,THREE.ShaderChunk.shadowmap_pars_vertex,"void main() {",THREE.ShaderChunk.skinbase_vertex,THREE.ShaderChunk.skinnormal_vertex,"#ifdef USE_SKINNING\nvNormal = normalize( normalMatrix * skinnedNormal.xyz );\nvec4 skinnedTangent = skinMatrix * vec4( tangent.xyz, 0.0 );\nvTangent = normalize( normalMatrix * skinnedTangent.xyz );\n#else\nvNormal = normalize( normalMatrix * normal );\nvTangent = normalize( normalMatrix * tangent.xyz );\n#endif\nvBinormal = normalize( cross( vNormal, vTangent ) * tangent.w );\nvUv = uv * uRepeat + uOffset;\nvec3 displacedPosition;\n#ifdef VERTEX_TEXTURES\nif ( enableDisplacement ) {\nvec3 dv = texture2D( tDisplacement, uv ).xyz;\nfloat df = uDisplacementScale * dv.x + uDisplacementBias;\ndisplacedPosition = position + normalize( normal ) * df;\n} else {\n#ifdef USE_SKINNING\nvec4 skinVertex = vec4( position, 1.0 );\nvec4 skinned = boneMatX * skinVertex * skinWeight.x;\nskinned \t += boneMatY * skinVertex * skinWeight.y;\ndisplacedPosition = skinned.xyz;\n#else\ndisplacedPosition = position;\n#endif\n}\n#else\n#ifdef USE_SKINNING\nvec4 skinVertex = vec4( position, 1.0 );\nvec4 skinned = boneMatX * skinVertex * skinWeight.x;\nskinned \t += boneMatY * skinVertex * skinWeight.y;\ndisplacedPosition = skinned.xyz;\n#else\ndisplacedPosition = position;\n#endif\n#endif\nvec4 mvPosition = modelViewMatrix * vec4( displacedPosition, 1.0 );\nvec4 worldPosition = modelMatrix * vec4( displacedPosition, 1.0 );\ngl_Position = projectionMatrix * mvPosition;\nvWorldPosition = worldPosition.xyz;\nvViewPosition = -mvPosition.xyz;\n#ifdef USE_SHADOWMAP\nfor( int i = 0; i < MAX_SHADOWS; i ++ ) {\nvShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;\n}\n#endif\n}"].join("\n")}, +cube:{uniforms:{tCube:{type:"t",value:null},tFlip:{type:"f",value:-1}},vertexShader:"varying vec3 vWorldPosition;\nvoid main() {\nvec4 worldPosition = modelMatrix * vec4( position, 1.0 );\nvWorldPosition = worldPosition.xyz;\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"uniform samplerCube tCube;\nuniform float tFlip;\nvarying vec3 vWorldPosition;\nvoid main() {\ngl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );\n}"}, +depthRGBA:{uniforms:{},vertexShader:[THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.skinning_pars_vertex,"void main() {",THREE.ShaderChunk.skinbase_vertex,THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.skinning_vertex,THREE.ShaderChunk.default_vertex,"}"].join("\n"),fragmentShader:"vec4 pack_depth( const in float depth ) {\nconst vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );\nconst vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );\nvec4 res = fract( depth * bit_shift );\nres -= res.xxyz * bit_mask;\nreturn res;\n}\nvoid main() {\ngl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );\n}"}};THREE.WebGLRenderer=function(a){function b(a){if(a.__webglCustomAttributesList)for(var b in a.__webglCustomAttributesList)j.deleteBuffer(a.__webglCustomAttributesList[b].buffer)}function c(a,b){var c=a.vertices.length,d=b.material;if(d.attributes){void 0===a.__webglCustomAttributesList&&(a.__webglCustomAttributesList=[]);for(var e in d.attributes){var f=d.attributes[e];if(!f.__webglInitialized||f.createUniqueBuffers){f.__webglInitialized=!0;var g=1;"v2"===f.type?g=2:"v3"===f.type?g=3:"v4"===f.type? +g=4:"c"===f.type&&(g=3);f.size=g;f.array=new Float32Array(c*g);f.buffer=j.createBuffer();f.buffer.belongsToAttribute=e;f.needsUpdate=!0}a.__webglCustomAttributesList.push(f)}}}function d(a,b){var c=b.geometry,d=a.faces3,h=a.faces4,i=3*d.length+4*h.length,k=1*d.length+2*h.length,h=3*d.length+4*h.length,d=e(b,a),n=g(d),l=f(d),m=d.vertexColors?d.vertexColors:!1;a.__vertexArray=new Float32Array(3*i);l&&(a.__normalArray=new Float32Array(3*i));c.hasTangents&&(a.__tangentArray=new Float32Array(4*i));m&& +(a.__colorArray=new Float32Array(3*i));if(n){if(0<c.faceUvs.length||0<c.faceVertexUvs.length)a.__uvArray=new Float32Array(2*i);if(1<c.faceUvs.length||1<c.faceVertexUvs.length)a.__uv2Array=new Float32Array(2*i)}b.geometry.skinWeights.length&&b.geometry.skinIndices.length&&(a.__skinIndexArray=new Float32Array(4*i),a.__skinWeightArray=new Float32Array(4*i));a.__faceArray=new Uint16Array(3*k);a.__lineArray=new Uint16Array(2*h);if(a.numMorphTargets){a.__morphTargetsArrays=[];c=0;for(n=a.numMorphTargets;c< +n;c++)a.__morphTargetsArrays.push(new Float32Array(3*i))}if(a.numMorphNormals){a.__morphNormalsArrays=[];c=0;for(n=a.numMorphNormals;c<n;c++)a.__morphNormalsArrays.push(new Float32Array(3*i))}a.__webglFaceCount=3*k;a.__webglLineCount=2*h;if(d.attributes){void 0===a.__webglCustomAttributesList&&(a.__webglCustomAttributesList=[]);for(var p in d.attributes){var k=d.attributes[p],c={},q;for(q in k)c[q]=k[q];if(!c.__webglInitialized||c.createUniqueBuffers)c.__webglInitialized=!0,h=1,"v2"===c.type?h=2: +"v3"===c.type?h=3:"v4"===c.type?h=4:"c"===c.type&&(h=3),c.size=h,c.array=new Float32Array(i*h),c.buffer=j.createBuffer(),c.buffer.belongsToAttribute=p,k.needsUpdate=!0,c.__original=k;a.__webglCustomAttributesList.push(c)}}a.__inittedArrays=!0}function e(a,b){return a.material instanceof THREE.MeshFaceMaterial?a.material.materials[b.materialIndex]:a.material}function f(a){return a instanceof THREE.MeshBasicMaterial&&!a.envMap||a instanceof THREE.MeshDepthMaterial?!1:a&&void 0!==a.shading&&a.shading=== +THREE.SmoothShading?THREE.SmoothShading:THREE.FlatShading}function g(a){return a.map||a.lightMap||a.bumpMap||a.normalMap||a.specularMap||a instanceof THREE.ShaderMaterial?!0:!1}function h(a){var b,c,d;for(b in a.attributes)d="index"===b?j.ELEMENT_ARRAY_BUFFER:j.ARRAY_BUFFER,c=a.attributes[b],c.buffer=j.createBuffer(),j.bindBuffer(d,c.buffer),j.bufferData(d,c.array,j.STATIC_DRAW)}function i(a,b,c){var d=a.attributes,e=d.index,f=d.position,g=d.normal,h=d.uv,i=d.color,d=d.tangent;a.elementsNeedUpdate&& +void 0!==e&&(j.bindBuffer(j.ELEMENT_ARRAY_BUFFER,e.buffer),j.bufferData(j.ELEMENT_ARRAY_BUFFER,e.array,b));a.verticesNeedUpdate&&void 0!==f&&(j.bindBuffer(j.ARRAY_BUFFER,f.buffer),j.bufferData(j.ARRAY_BUFFER,f.array,b));a.normalsNeedUpdate&&void 0!==g&&(j.bindBuffer(j.ARRAY_BUFFER,g.buffer),j.bufferData(j.ARRAY_BUFFER,g.array,b));a.uvsNeedUpdate&&void 0!==h&&(j.bindBuffer(j.ARRAY_BUFFER,h.buffer),j.bufferData(j.ARRAY_BUFFER,h.array,b));a.colorsNeedUpdate&&void 0!==i&&(j.bindBuffer(j.ARRAY_BUFFER, +i.buffer),j.bufferData(j.ARRAY_BUFFER,i.array,b));a.tangentsNeedUpdate&&void 0!==d&&(j.bindBuffer(j.ARRAY_BUFFER,d.buffer),j.bufferData(j.ARRAY_BUFFER,d.array,b));if(c)for(var k in a.attributes)delete a.attributes[k].array}function k(a){Ka[a]||(j.enableVertexAttribArray(a),Ka[a]=!0)}function l(){for(var a in Ka)Ka[a]&&(j.disableVertexAttribArray(a),Ka[a]=!1)}function m(a,b){return a.z!==b.z?b.z-a.z:b.id-a.id}function n(a,b){return b[0]-a[0]}function s(a,b,c){if(a.length)for(var d=0,e=a.length;d<e;d++)aa= +mb=null,ta=ka=la=da=Wa=ia=Z=-1,bb=!0,a[d].render(b,c,mc,pb),aa=mb=null,ta=ka=la=da=Wa=ia=Z=-1,bb=!0}function r(a,b,c,d,e,f,g,j){var h,i,k,n;b?(i=a.length-1,n=b=-1):(i=0,b=a.length,n=1);for(var l=i;l!==b;l+=n)if(h=a[l],h.render){i=h.object;k=h.buffer;if(j)h=j;else{h=h[c];if(!h)continue;g&&N.setBlending(h.blending,h.blendEquation,h.blendSrc,h.blendDst);N.setDepthTest(h.depthTest);N.setDepthWrite(h.depthWrite);E(h.polygonOffset,h.polygonOffsetFactor,h.polygonOffsetUnits)}N.setMaterialFaces(h);k instanceof +THREE.BufferGeometry?N.renderBufferDirect(d,e,f,h,k,i):N.renderBuffer(d,e,f,h,k,i)}}function p(a,b,c,d,e,f,g){for(var h,j,i=0,k=a.length;i<k;i++)if(h=a[i],j=h.object,j.visible){if(g)h=g;else{h=h[b];if(!h)continue;f&&N.setBlending(h.blending,h.blendEquation,h.blendSrc,h.blendDst);N.setDepthTest(h.depthTest);N.setDepthWrite(h.depthWrite);E(h.polygonOffset,h.polygonOffsetFactor,h.polygonOffsetUnits)}N.renderImmediateObject(c,d,e,h,j)}}function q(a,b,c){a.push({buffer:b,object:c,opaque:null,transparent:null})} +function y(a){for(var b in a.attributes)if(a.attributes[b].needsUpdate)return!0;return!1}function v(a){for(var b in a.attributes)a.attributes[b].needsUpdate=!1}function z(a,b){for(var c=a.length-1;0<=c;c--)a[c].object===b&&a.splice(c,1)}function t(a,b){for(var c=a.length-1;0<=c;c--)a[c]===b&&a.splice(c,1)}function A(a,b,c,d,e){Y=0;d.needsUpdate&&(d.program&&Pc(d),N.initMaterial(d,b,c,e),d.needsUpdate=!1);d.morphTargets&&!e.__webglMorphTargetInfluences&&(e.__webglMorphTargetInfluences=new Float32Array(N.maxMorphTargets)); +var f=!1,g=d.program,h=g.uniforms,i=d.uniforms;g!==mb&&(j.useProgram(g),mb=g,f=!0);d.id!==ta&&(ta=d.id,f=!0);if(f||a!==aa)j.uniformMatrix4fv(h.projectionMatrix,!1,a.projectionMatrix.elements),a!==aa&&(aa=a);if(d.skinning)if(tc&&e.useVertexTexture){if(null!==h.boneTexture){var k=I();j.uniform1i(h.boneTexture,k);N.setTexture(e.boneTexture,k)}}else null!==h.boneGlobalMatrices&&j.uniformMatrix4fv(h.boneGlobalMatrices,!1,e.boneMatrices);if(f){c&&d.fog&&(i.fogColor.value=c.color,c instanceof THREE.Fog? +(i.fogNear.value=c.near,i.fogFar.value=c.far):c instanceof THREE.FogExp2&&(i.fogDensity.value=c.density));if(d instanceof THREE.MeshPhongMaterial||d instanceof THREE.MeshLambertMaterial||d.lights){if(bb){for(var n,l=k=0,m=0,p,q,s,r=xb,t=r.directional.colors,v=r.directional.positions,y=r.point.colors,z=r.point.positions,B=r.point.distances,C=r.spot.colors,A=r.spot.positions,F=r.spot.distances,E=r.spot.directions,J=r.spot.anglesCos,K=r.spot.exponents,H=r.hemi.skyColors,M=r.hemi.groundColors,P=r.hemi.positions, +X=0,da=0,ka=0,fa=0,ca=0,pa=0,Ma=0,ha=0,O=n=0,c=s=O=0,f=b.length;c<f;c++)n=b[c],n.onlyShadow||(p=n.color,q=n.intensity,s=n.distance,n instanceof THREE.AmbientLight?n.visible&&(N.gammaInput?(k+=p.r*p.r,l+=p.g*p.g,m+=p.b*p.b):(k+=p.r,l+=p.g,m+=p.b)):n instanceof THREE.DirectionalLight?(ca+=1,n.visible&&(La.getPositionFromMatrix(n.matrixWorld),Qa.getPositionFromMatrix(n.target.matrixWorld),La.sub(Qa),La.normalize(),0===La.x&&0===La.y&&0===La.z||(n=3*X,v[n]=La.x,v[n+1]=La.y,v[n+2]=La.z,N.gammaInput?x(t, +n,p,q*q):G(t,n,p,q),X+=1))):n instanceof THREE.PointLight?(pa+=1,n.visible&&(O=3*da,N.gammaInput?x(y,O,p,q*q):G(y,O,p,q),Qa.getPositionFromMatrix(n.matrixWorld),z[O]=Qa.x,z[O+1]=Qa.y,z[O+2]=Qa.z,B[da]=s,da+=1)):n instanceof THREE.SpotLight?(Ma+=1,n.visible&&(O=3*ka,N.gammaInput?x(C,O,p,q*q):G(C,O,p,q),Qa.getPositionFromMatrix(n.matrixWorld),A[O]=Qa.x,A[O+1]=Qa.y,A[O+2]=Qa.z,F[ka]=s,La.copy(Qa),Qa.getPositionFromMatrix(n.target.matrixWorld),La.sub(Qa),La.normalize(),E[O]=La.x,E[O+1]=La.y,E[O+2]=La.z, +J[ka]=Math.cos(n.angle),K[ka]=n.exponent,ka+=1)):n instanceof THREE.HemisphereLight&&(ha+=1,n.visible&&(La.getPositionFromMatrix(n.matrixWorld),La.normalize(),0===La.x&&0===La.y&&0===La.z||(s=3*fa,P[s]=La.x,P[s+1]=La.y,P[s+2]=La.z,p=n.color,n=n.groundColor,N.gammaInput?(q*=q,x(H,s,p,q),x(M,s,n,q)):(G(H,s,p,q),G(M,s,n,q)),fa+=1))));c=3*X;for(f=Math.max(t.length,3*ca);c<f;c++)t[c]=0;c=3*da;for(f=Math.max(y.length,3*pa);c<f;c++)y[c]=0;c=3*ka;for(f=Math.max(C.length,3*Ma);c<f;c++)C[c]=0;c=3*fa;for(f= +Math.max(H.length,3*ha);c<f;c++)H[c]=0;c=3*fa;for(f=Math.max(M.length,3*ha);c<f;c++)M[c]=0;r.directional.length=X;r.point.length=da;r.spot.length=ka;r.hemi.length=fa;r.ambient[0]=k;r.ambient[1]=l;r.ambient[2]=m;bb=!1}c=xb;i.ambientLightColor.value=c.ambient;i.directionalLightColor.value=c.directional.colors;i.directionalLightDirection.value=c.directional.positions;i.pointLightColor.value=c.point.colors;i.pointLightPosition.value=c.point.positions;i.pointLightDistance.value=c.point.distances;i.spotLightColor.value= +c.spot.colors;i.spotLightPosition.value=c.spot.positions;i.spotLightDistance.value=c.spot.distances;i.spotLightDirection.value=c.spot.directions;i.spotLightAngleCos.value=c.spot.anglesCos;i.spotLightExponent.value=c.spot.exponents;i.hemisphereLightSkyColor.value=c.hemi.skyColors;i.hemisphereLightGroundColor.value=c.hemi.groundColors;i.hemisphereLightDirection.value=c.hemi.positions}if(d instanceof THREE.MeshBasicMaterial||d instanceof THREE.MeshLambertMaterial||d instanceof THREE.MeshPhongMaterial){i.opacity.value= +d.opacity;N.gammaInput?i.diffuse.value.copyGammaToLinear(d.color):i.diffuse.value=d.color;i.map.value=d.map;i.lightMap.value=d.lightMap;i.specularMap.value=d.specularMap;d.bumpMap&&(i.bumpMap.value=d.bumpMap,i.bumpScale.value=d.bumpScale);d.normalMap&&(i.normalMap.value=d.normalMap,i.normalScale.value.copy(d.normalScale));var Z;d.map?Z=d.map:d.specularMap?Z=d.specularMap:d.normalMap?Z=d.normalMap:d.bumpMap&&(Z=d.bumpMap);void 0!==Z&&(c=Z.offset,Z=Z.repeat,i.offsetRepeat.value.set(c.x,c.y,Z.x,Z.y)); +i.envMap.value=d.envMap;i.flipEnvMap.value=d.envMap instanceof THREE.WebGLRenderTargetCube?1:-1;i.reflectivity.value=d.reflectivity;i.refractionRatio.value=d.refractionRatio;i.combine.value=d.combine;i.useRefract.value=d.envMap&&d.envMap.mapping instanceof THREE.CubeRefractionMapping}d instanceof THREE.LineBasicMaterial?(i.diffuse.value=d.color,i.opacity.value=d.opacity):d instanceof THREE.LineDashedMaterial?(i.diffuse.value=d.color,i.opacity.value=d.opacity,i.dashSize.value=d.dashSize,i.totalSize.value= +d.dashSize+d.gapSize,i.scale.value=d.scale):d instanceof THREE.ParticleBasicMaterial?(i.psColor.value=d.color,i.opacity.value=d.opacity,i.size.value=d.size,i.scale.value=U.height/2,i.map.value=d.map):d instanceof THREE.MeshPhongMaterial?(i.shininess.value=d.shininess,N.gammaInput?(i.ambient.value.copyGammaToLinear(d.ambient),i.emissive.value.copyGammaToLinear(d.emissive),i.specular.value.copyGammaToLinear(d.specular)):(i.ambient.value=d.ambient,i.emissive.value=d.emissive,i.specular.value=d.specular), +d.wrapAround&&i.wrapRGB.value.copy(d.wrapRGB)):d instanceof THREE.MeshLambertMaterial?(N.gammaInput?(i.ambient.value.copyGammaToLinear(d.ambient),i.emissive.value.copyGammaToLinear(d.emissive)):(i.ambient.value=d.ambient,i.emissive.value=d.emissive),d.wrapAround&&i.wrapRGB.value.copy(d.wrapRGB)):d instanceof THREE.MeshDepthMaterial?(i.mNear.value=a.near,i.mFar.value=a.far,i.opacity.value=d.opacity):d instanceof THREE.MeshNormalMaterial&&(i.opacity.value=d.opacity);if(e.receiveShadow&&!d._shadowPass&& +i.shadowMatrix){c=Z=0;for(f=b.length;c<f;c++)if(k=b[c],k.castShadow&&(k instanceof THREE.SpotLight||k instanceof THREE.DirectionalLight&&!k.shadowCascade))i.shadowMap.value[Z]=k.shadowMap,i.shadowMapSize.value[Z]=k.shadowMapSize,i.shadowMatrix.value[Z]=k.shadowMatrix,i.shadowDarkness.value[Z]=k.shadowDarkness,i.shadowBias.value[Z]=k.shadowBias,Z++}b=d.uniformsList;i=0;for(Z=b.length;i<Z;i++)if(f=g.uniforms[b[i][1]])if(c=b[i][0],l=c.type,k=c.value,"i"===l)j.uniform1i(f,k);else if("f"===l)j.uniform1f(f, +k);else if("v2"===l)j.uniform2f(f,k.x,k.y);else if("v3"===l)j.uniform3f(f,k.x,k.y,k.z);else if("v4"===l)j.uniform4f(f,k.x,k.y,k.z,k.w);else if("c"===l)j.uniform3f(f,k.r,k.g,k.b);else if("iv1"===l)j.uniform1iv(f,k);else if("iv"===l)j.uniform3iv(f,k);else if("fv1"===l)j.uniform1fv(f,k);else if("fv"===l)j.uniform3fv(f,k);else if("v2v"===l){void 0===c._array&&(c._array=new Float32Array(2*k.length));l=0;for(m=k.length;l<m;l++)r=2*l,c._array[r]=k[l].x,c._array[r+1]=k[l].y;j.uniform2fv(f,c._array)}else if("v3v"=== +l){void 0===c._array&&(c._array=new Float32Array(3*k.length));l=0;for(m=k.length;l<m;l++)r=3*l,c._array[r]=k[l].x,c._array[r+1]=k[l].y,c._array[r+2]=k[l].z;j.uniform3fv(f,c._array)}else if("v4v"===l){void 0===c._array&&(c._array=new Float32Array(4*k.length));l=0;for(m=k.length;l<m;l++)r=4*l,c._array[r]=k[l].x,c._array[r+1]=k[l].y,c._array[r+2]=k[l].z,c._array[r+3]=k[l].w;j.uniform4fv(f,c._array)}else if("m4"===l)void 0===c._array&&(c._array=new Float32Array(16)),k.flattenToArray(c._array),j.uniformMatrix4fv(f, +!1,c._array);else if("m4v"===l){void 0===c._array&&(c._array=new Float32Array(16*k.length));l=0;for(m=k.length;l<m;l++)k[l].flattenToArrayOffset(c._array,16*l);j.uniformMatrix4fv(f,!1,c._array)}else if("t"===l){if(r=k,k=I(),j.uniform1i(f,k),r)if(r.image instanceof Array&&6===r.image.length){if(c=r,f=k,6===c.image.length)if(c.needsUpdate){c.image.__webglTextureCube||(c.image.__webglTextureCube=j.createTexture(),N.info.memory.textures++);j.activeTexture(j.TEXTURE0+f);j.bindTexture(j.TEXTURE_CUBE_MAP, +c.image.__webglTextureCube);j.pixelStorei(j.UNPACK_FLIP_Y_WEBGL,c.flipY);f=c instanceof THREE.CompressedTexture;k=[];for(l=0;6>l;l++)N.autoScaleCubemaps&&!f?(m=k,r=l,t=c.image[l],y=gd,t.width<=y&&t.height<=y||(z=Math.max(t.width,t.height),v=Math.floor(t.width*y/z),y=Math.floor(t.height*y/z),z=document.createElement("canvas"),z.width=v,z.height=y,z.getContext("2d").drawImage(t,0,0,t.width,t.height,0,0,v,y),t=z),m[r]=t):k[l]=c.image[l];l=k[0];m=0===(l.width&l.width-1)&&0===(l.height&l.height-1);r=L(c.format); +t=L(c.type);W(j.TEXTURE_CUBE_MAP,c,m);for(l=0;6>l;l++)if(f){y=k[l].mipmaps;z=0;for(B=y.length;z<B;z++)v=y[z],j.compressedTexImage2D(j.TEXTURE_CUBE_MAP_POSITIVE_X+l,z,r,v.width,v.height,0,v.data)}else j.texImage2D(j.TEXTURE_CUBE_MAP_POSITIVE_X+l,0,r,r,t,k[l]);c.generateMipmaps&&m&&j.generateMipmap(j.TEXTURE_CUBE_MAP);c.needsUpdate=!1;if(c.onUpdate)c.onUpdate()}else j.activeTexture(j.TEXTURE0+f),j.bindTexture(j.TEXTURE_CUBE_MAP,c.image.__webglTextureCube)}else r instanceof THREE.WebGLRenderTargetCube? +(c=r,j.activeTexture(j.TEXTURE0+k),j.bindTexture(j.TEXTURE_CUBE_MAP,c.__webglTexture)):N.setTexture(r,k)}else if("tv"===l){void 0===c._array&&(c._array=[]);l=0;for(m=c.value.length;l<m;l++)c._array[l]=I();j.uniform1iv(f,c._array);l=0;for(m=c.value.length;l<m;l++)r=c.value[l],k=c._array[l],r&&N.setTexture(r,k)}if((d instanceof THREE.ShaderMaterial||d instanceof THREE.MeshPhongMaterial||d.envMap)&&null!==h.cameraPosition)Qa.getPositionFromMatrix(a.matrixWorld),j.uniform3f(h.cameraPosition,Qa.x,Qa.y, +Qa.z);(d instanceof THREE.MeshPhongMaterial||d instanceof THREE.MeshLambertMaterial||d instanceof THREE.ShaderMaterial||d.skinning)&&null!==h.viewMatrix&&j.uniformMatrix4fv(h.viewMatrix,!1,a.matrixWorldInverse.elements)}j.uniformMatrix4fv(h.modelViewMatrix,!1,e._modelViewMatrix.elements);h.normalMatrix&&j.uniformMatrix3fv(h.normalMatrix,!1,e._normalMatrix.elements);null!==h.modelMatrix&&j.uniformMatrix4fv(h.modelMatrix,!1,e.matrixWorld.elements);return g}function I(){var a=Y;a>=Mc&&console.warn("WebGLRenderer: trying to use "+ +a+" texture units while this GPU supports only "+Mc);Y+=1;return a}function C(a,b){a._modelViewMatrix.multiplyMatrices(b.matrixWorldInverse,a.matrixWorld);a._normalMatrix.getInverse(a._modelViewMatrix);a._normalMatrix.transpose()}function x(a,b,c,d){a[b]=c.r*c.r*d;a[b+1]=c.g*c.g*d;a[b+2]=c.b*c.b*d}function G(a,b,c,d){a[b]=c.r*d;a[b+1]=c.g*d;a[b+2]=c.b*d}function J(a){a!==ub&&(j.lineWidth(a),ub=a)}function E(a,b,c){ab!==a&&(a?j.enable(j.POLYGON_OFFSET_FILL):j.disable(j.POLYGON_OFFSET_FILL),ab=a);if(a&& +(Fa!==b||Xa!==c))j.polygonOffset(b,c),Fa=b,Xa=c}function H(a){for(var a=a.split("\n"),b=0,c=a.length;b<c;b++)a[b]=b+1+": "+a[b];return a.join("\n")}function B(a,b){var c;"fragment"===a?c=j.createShader(j.FRAGMENT_SHADER):"vertex"===a&&(c=j.createShader(j.VERTEX_SHADER));j.shaderSource(c,b);j.compileShader(c);return!j.getShaderParameter(c,j.COMPILE_STATUS)?(console.error(j.getShaderInfoLog(c)),console.error(H(b)),null):c}function W(a,b,c){c?(j.texParameteri(a,j.TEXTURE_WRAP_S,L(b.wrapS)),j.texParameteri(a, +j.TEXTURE_WRAP_T,L(b.wrapT)),j.texParameteri(a,j.TEXTURE_MAG_FILTER,L(b.magFilter)),j.texParameteri(a,j.TEXTURE_MIN_FILTER,L(b.minFilter))):(j.texParameteri(a,j.TEXTURE_WRAP_S,j.CLAMP_TO_EDGE),j.texParameteri(a,j.TEXTURE_WRAP_T,j.CLAMP_TO_EDGE),j.texParameteri(a,j.TEXTURE_MAG_FILTER,K(b.magFilter)),j.texParameteri(a,j.TEXTURE_MIN_FILTER,K(b.minFilter)));if(cb&&b.type!==THREE.FloatType&&(1<b.anisotropy||b.__oldAnisotropy))j.texParameterf(a,cb.TEXTURE_MAX_ANISOTROPY_EXT,Math.min(b.anisotropy,Cc)),b.__oldAnisotropy= +b.anisotropy}function F(a,b){j.bindRenderbuffer(j.RENDERBUFFER,a);b.depthBuffer&&!b.stencilBuffer?(j.renderbufferStorage(j.RENDERBUFFER,j.DEPTH_COMPONENT16,b.width,b.height),j.framebufferRenderbuffer(j.FRAMEBUFFER,j.DEPTH_ATTACHMENT,j.RENDERBUFFER,a)):b.depthBuffer&&b.stencilBuffer?(j.renderbufferStorage(j.RENDERBUFFER,j.DEPTH_STENCIL,b.width,b.height),j.framebufferRenderbuffer(j.FRAMEBUFFER,j.DEPTH_STENCIL_ATTACHMENT,j.RENDERBUFFER,a)):j.renderbufferStorage(j.RENDERBUFFER,j.RGBA4,b.width,b.height)} +function K(a){return a===THREE.NearestFilter||a===THREE.NearestMipMapNearestFilter||a===THREE.NearestMipMapLinearFilter?j.NEAREST:j.LINEAR}function L(a){if(a===THREE.RepeatWrapping)return j.REPEAT;if(a===THREE.ClampToEdgeWrapping)return j.CLAMP_TO_EDGE;if(a===THREE.MirroredRepeatWrapping)return j.MIRRORED_REPEAT;if(a===THREE.NearestFilter)return j.NEAREST;if(a===THREE.NearestMipMapNearestFilter)return j.NEAREST_MIPMAP_NEAREST;if(a===THREE.NearestMipMapLinearFilter)return j.NEAREST_MIPMAP_LINEAR;if(a=== +THREE.LinearFilter)return j.LINEAR;if(a===THREE.LinearMipMapNearestFilter)return j.LINEAR_MIPMAP_NEAREST;if(a===THREE.LinearMipMapLinearFilter)return j.LINEAR_MIPMAP_LINEAR;if(a===THREE.UnsignedByteType)return j.UNSIGNED_BYTE;if(a===THREE.UnsignedShort4444Type)return j.UNSIGNED_SHORT_4_4_4_4;if(a===THREE.UnsignedShort5551Type)return j.UNSIGNED_SHORT_5_5_5_1;if(a===THREE.UnsignedShort565Type)return j.UNSIGNED_SHORT_5_6_5;if(a===THREE.ByteType)return j.BYTE;if(a===THREE.ShortType)return j.SHORT;if(a=== +THREE.UnsignedShortType)return j.UNSIGNED_SHORT;if(a===THREE.IntType)return j.INT;if(a===THREE.UnsignedIntType)return j.UNSIGNED_INT;if(a===THREE.FloatType)return j.FLOAT;if(a===THREE.AlphaFormat)return j.ALPHA;if(a===THREE.RGBFormat)return j.RGB;if(a===THREE.RGBAFormat)return j.RGBA;if(a===THREE.LuminanceFormat)return j.LUMINANCE;if(a===THREE.LuminanceAlphaFormat)return j.LUMINANCE_ALPHA;if(a===THREE.AddEquation)return j.FUNC_ADD;if(a===THREE.SubtractEquation)return j.FUNC_SUBTRACT;if(a===THREE.ReverseSubtractEquation)return j.FUNC_REVERSE_SUBTRACT; +if(a===THREE.ZeroFactor)return j.ZERO;if(a===THREE.OneFactor)return j.ONE;if(a===THREE.SrcColorFactor)return j.SRC_COLOR;if(a===THREE.OneMinusSrcColorFactor)return j.ONE_MINUS_SRC_COLOR;if(a===THREE.SrcAlphaFactor)return j.SRC_ALPHA;if(a===THREE.OneMinusSrcAlphaFactor)return j.ONE_MINUS_SRC_ALPHA;if(a===THREE.DstAlphaFactor)return j.DST_ALPHA;if(a===THREE.OneMinusDstAlphaFactor)return j.ONE_MINUS_DST_ALPHA;if(a===THREE.DstColorFactor)return j.DST_COLOR;if(a===THREE.OneMinusDstColorFactor)return j.ONE_MINUS_DST_COLOR; +if(a===THREE.SrcAlphaSaturateFactor)return j.SRC_ALPHA_SATURATE;if(void 0!==Sa){if(a===THREE.RGB_S3TC_DXT1_Format)return Sa.COMPRESSED_RGB_S3TC_DXT1_EXT;if(a===THREE.RGBA_S3TC_DXT1_Format)return Sa.COMPRESSED_RGBA_S3TC_DXT1_EXT;if(a===THREE.RGBA_S3TC_DXT3_Format)return Sa.COMPRESSED_RGBA_S3TC_DXT3_EXT;if(a===THREE.RGBA_S3TC_DXT5_Format)return Sa.COMPRESSED_RGBA_S3TC_DXT5_EXT}return 0}console.log("THREE.WebGLRenderer",THREE.REVISION);var a=a||{},U=void 0!==a.canvas?a.canvas:document.createElement("canvas"), +fa=void 0!==a.precision?a.precision:"highp",Ca=void 0!==a.alpha?a.alpha:!0,$a=void 0!==a.premultipliedAlpha?a.premultipliedAlpha:!0,M=void 0!==a.antialias?a.antialias:!1,ca=void 0!==a.stencil?a.stencil:!0,qa=void 0!==a.preserveDrawingBuffer?a.preserveDrawingBuffer:!1,ha=void 0!==a.clearColor?new THREE.Color(a.clearColor):new THREE.Color(0),ra=void 0!==a.clearAlpha?a.clearAlpha:0;this.domElement=U;this.context=null;this.devicePixelRatio=void 0!==a.devicePixelRatio?a.devicePixelRatio:void 0!==window.devicePixelRatio? +window.devicePixelRatio:1;this.autoUpdateScene=this.autoUpdateObjects=this.sortObjects=this.autoClearStencil=this.autoClearDepth=this.autoClearColor=this.autoClear=!0;this.shadowMapEnabled=this.physicallyBasedShading=this.gammaOutput=this.gammaInput=!1;this.shadowMapAutoUpdate=!0;this.shadowMapType=THREE.PCFShadowMap;this.shadowMapCullFace=THREE.CullFaceFront;this.shadowMapCascade=this.shadowMapDebug=!1;this.maxMorphTargets=8;this.maxMorphNormals=4;this.autoScaleCubemaps=!0;this.renderPluginsPre= +[];this.renderPluginsPost=[];this.info={memory:{programs:0,geometries:0,textures:0},render:{calls:0,vertices:0,faces:0,points:0}};var N=this,Ma=[],Na=0,mb=null,Pa=null,ta=-1,ka=null,aa=null,pa=0,Y=0,da=-1,la=-1,Z=-1,oa=-1,gb=-1,nb=-1,ia=-1,Wa=-1,ab=null,Fa=null,Xa=null,ub=null,Ib=0,Jb=0,fc=0,Ab=0,mc=0,pb=0,Ka={},Va=new THREE.Frustum,gc=new THREE.Matrix4,vb=new THREE.Matrix4,Qa=new THREE.Vector3,La=new THREE.Vector3,bb=!0,xb={ambient:[0,0,0],directional:{length:0,colors:[],positions:[]},point:{length:0, +colors:[],positions:[],distances:[]},spot:{length:0,colors:[],positions:[],distances:[],directions:[],anglesCos:[],exponents:[]},hemi:{length:0,skyColors:[],groundColors:[],positions:[]}},j,yb,Ra,cb,Sa;try{if(!(j=U.getContext("experimental-webgl",{alpha:Ca,premultipliedAlpha:$a,antialias:M,stencil:ca,preserveDrawingBuffer:qa})))throw"Error creating WebGL context.";}catch(zb){console.error(zb)}yb=j.getExtension("OES_texture_float");Ra=j.getExtension("OES_standard_derivatives");cb=j.getExtension("EXT_texture_filter_anisotropic")|| +j.getExtension("MOZ_EXT_texture_filter_anisotropic")||j.getExtension("WEBKIT_EXT_texture_filter_anisotropic");Sa=j.getExtension("WEBGL_compressed_texture_s3tc")||j.getExtension("MOZ_WEBGL_compressed_texture_s3tc")||j.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc");yb||console.log("THREE.WebGLRenderer: Float textures not supported.");Ra||console.log("THREE.WebGLRenderer: Standard derivatives not supported.");cb||console.log("THREE.WebGLRenderer: Anisotropic texture filtering not supported."); +Sa||console.log("THREE.WebGLRenderer: S3TC compressed textures not supported.");void 0===j.getShaderPrecisionFormat&&(j.getShaderPrecisionFormat=function(){return{rangeMin:1,rangeMax:1,precision:1}});j.clearColor(0,0,0,1);j.clearDepth(1);j.clearStencil(0);j.enable(j.DEPTH_TEST);j.depthFunc(j.LEQUAL);j.frontFace(j.CCW);j.cullFace(j.BACK);j.enable(j.CULL_FACE);j.enable(j.BLEND);j.blendEquation(j.FUNC_ADD);j.blendFunc(j.SRC_ALPHA,j.ONE_MINUS_SRC_ALPHA);j.clearColor(ha.r,ha.g,ha.b,ra);this.context=j; +var Mc=j.getParameter(j.MAX_TEXTURE_IMAGE_UNITS),fd=j.getParameter(j.MAX_VERTEX_TEXTURE_IMAGE_UNITS);j.getParameter(j.MAX_TEXTURE_SIZE);var gd=j.getParameter(j.MAX_CUBE_MAP_TEXTURE_SIZE),Cc=cb?j.getParameter(cb.MAX_TEXTURE_MAX_ANISOTROPY_EXT):0,sc=0<fd,tc=sc&&yb;Sa&&j.getParameter(j.COMPRESSED_TEXTURE_FORMATS);var jd=j.getShaderPrecisionFormat(j.VERTEX_SHADER,j.HIGH_FLOAT),kd=j.getShaderPrecisionFormat(j.VERTEX_SHADER,j.MEDIUM_FLOAT);j.getShaderPrecisionFormat(j.VERTEX_SHADER,j.LOW_FLOAT);var ld= +j.getShaderPrecisionFormat(j.FRAGMENT_SHADER,j.HIGH_FLOAT),id=j.getShaderPrecisionFormat(j.FRAGMENT_SHADER,j.MEDIUM_FLOAT);j.getShaderPrecisionFormat(j.FRAGMENT_SHADER,j.LOW_FLOAT);j.getShaderPrecisionFormat(j.VERTEX_SHADER,j.HIGH_INT);j.getShaderPrecisionFormat(j.VERTEX_SHADER,j.MEDIUM_INT);j.getShaderPrecisionFormat(j.VERTEX_SHADER,j.LOW_INT);j.getShaderPrecisionFormat(j.FRAGMENT_SHADER,j.HIGH_INT);j.getShaderPrecisionFormat(j.FRAGMENT_SHADER,j.MEDIUM_INT);j.getShaderPrecisionFormat(j.FRAGMENT_SHADER, +j.LOW_INT);var hd=0<jd.precision&&0<ld.precision,Nc=0<kd.precision&&0<id.precision;"highp"===fa&&!hd&&(Nc?(fa="mediump",console.warn("WebGLRenderer: highp not supported, using mediump")):(fa="lowp",console.warn("WebGLRenderer: highp and mediump not supported, using lowp")));"mediump"===fa&&!Nc&&(fa="lowp",console.warn("WebGLRenderer: mediump not supported, using lowp"));this.getContext=function(){return j};this.supportsVertexTextures=function(){return sc};this.supportsFloatTextures=function(){return yb}; +this.supportsStandardDerivatives=function(){return Ra};this.supportsCompressedTextureS3TC=function(){return Sa};this.getMaxAnisotropy=function(){return Cc};this.getPrecision=function(){return fa};this.setSize=function(a,b){U.width=a*this.devicePixelRatio;U.height=b*this.devicePixelRatio;U.style.width=a+"px";U.style.height=b+"px";this.setViewport(0,0,U.width,U.height)};this.setViewport=function(a,b,c,d){Ib=void 0!==a?a:0;Jb=void 0!==b?b:0;fc=void 0!==c?c:U.width;Ab=void 0!==d?d:U.height;j.viewport(Ib, +Jb,fc,Ab)};this.setScissor=function(a,b,c,d){j.scissor(a,b,c,d)};this.enableScissorTest=function(a){a?j.enable(j.SCISSOR_TEST):j.disable(j.SCISSOR_TEST)};this.setClearColorHex=function(a,b){ha.setHex(a);ra=b;j.clearColor(ha.r,ha.g,ha.b,ra)};this.setClearColor=function(a,b){ha.copy(a);ra=b;j.clearColor(ha.r,ha.g,ha.b,ra)};this.getClearColor=function(){return ha};this.getClearAlpha=function(){return ra};this.clear=function(a,b,c){var d=0;if(void 0===a||a)d|=j.COLOR_BUFFER_BIT;if(void 0===b||b)d|=j.DEPTH_BUFFER_BIT; +if(void 0===c||c)d|=j.STENCIL_BUFFER_BIT;j.clear(d)};this.clearTarget=function(a,b,c,d){this.setRenderTarget(a);this.clear(b,c,d)};this.addPostPlugin=function(a){a.init(this);this.renderPluginsPost.push(a)};this.addPrePlugin=function(a){a.init(this);this.renderPluginsPre.push(a)};this.updateShadowMap=function(a,b){mb=null;ta=ka=Wa=ia=Z=-1;bb=!0;la=da=-1;this.shadowMapPlugin.update(a,b)};var wd=function(a){a=a.target;a.removeEventListener("dispose",wd);a.__webglInit=void 0;void 0!==a.__webglVertexBuffer&& +j.deleteBuffer(a.__webglVertexBuffer);void 0!==a.__webglNormalBuffer&&j.deleteBuffer(a.__webglNormalBuffer);void 0!==a.__webglTangentBuffer&&j.deleteBuffer(a.__webglTangentBuffer);void 0!==a.__webglColorBuffer&&j.deleteBuffer(a.__webglColorBuffer);void 0!==a.__webglUVBuffer&&j.deleteBuffer(a.__webglUVBuffer);void 0!==a.__webglUV2Buffer&&j.deleteBuffer(a.__webglUV2Buffer);void 0!==a.__webglSkinIndicesBuffer&&j.deleteBuffer(a.__webglSkinIndicesBuffer);void 0!==a.__webglSkinWeightsBuffer&&j.deleteBuffer(a.__webglSkinWeightsBuffer); +void 0!==a.__webglFaceBuffer&&j.deleteBuffer(a.__webglFaceBuffer);void 0!==a.__webglLineBuffer&&j.deleteBuffer(a.__webglLineBuffer);void 0!==a.__webglLineDistanceBuffer&&j.deleteBuffer(a.__webglLineDistanceBuffer);if(void 0!==a.geometryGroups)for(var c in a.geometryGroups){var d=a.geometryGroups[c];if(void 0!==d.numMorphTargets)for(var e=0,f=d.numMorphTargets;e<f;e++)j.deleteBuffer(d.__webglMorphTargetsBuffers[e]);if(void 0!==d.numMorphNormals){e=0;for(f=d.numMorphNormals;e<f;e++)j.deleteBuffer(d.__webglMorphNormalsBuffers[e])}b(d)}b(a); +N.info.memory.geometries--},Oc=function(a){a=a.target;a.removeEventListener("dispose",Oc);a.image&&a.image.__webglTextureCube?j.deleteTexture(a.image.__webglTextureCube):a.__webglInit&&(a.__webglInit=!1,j.deleteTexture(a.__webglTexture));N.info.memory.textures--},P=function(a){a=a.target;a.removeEventListener("dispose",P);if(a&&a.__webglTexture)if(j.deleteTexture(a.__webglTexture),a instanceof THREE.WebGLRenderTargetCube)for(var b=0;6>b;b++)j.deleteFramebuffer(a.__webglFramebuffer[b]),j.deleteRenderbuffer(a.__webglRenderbuffer[b]); +else j.deleteFramebuffer(a.__webglFramebuffer),j.deleteRenderbuffer(a.__webglRenderbuffer);N.info.memory.textures--},X=function(a){a=a.target;a.removeEventListener("dispose",X);Pc(a)},Pc=function(a){var b=a.program;if(void 0!==b){a.program=void 0;var c,d,e=!1,a=0;for(c=Ma.length;a<c;a++)if(d=Ma[a],d.program===b){d.usedTimes--;0===d.usedTimes&&(e=!0);break}if(!0===e){e=[];a=0;for(c=Ma.length;a<c;a++)d=Ma[a],d.program!==b&&e.push(d);Ma=e;j.deleteProgram(b);N.info.memory.programs--}}};this.renderBufferImmediate= +function(a,b,c){a.hasPositions&&!a.__webglVertexBuffer&&(a.__webglVertexBuffer=j.createBuffer());a.hasNormals&&!a.__webglNormalBuffer&&(a.__webglNormalBuffer=j.createBuffer());a.hasUvs&&!a.__webglUvBuffer&&(a.__webglUvBuffer=j.createBuffer());a.hasColors&&!a.__webglColorBuffer&&(a.__webglColorBuffer=j.createBuffer());a.hasPositions&&(j.bindBuffer(j.ARRAY_BUFFER,a.__webglVertexBuffer),j.bufferData(j.ARRAY_BUFFER,a.positionArray,j.DYNAMIC_DRAW),j.enableVertexAttribArray(b.attributes.position),j.vertexAttribPointer(b.attributes.position, +3,j.FLOAT,!1,0,0));if(a.hasNormals){j.bindBuffer(j.ARRAY_BUFFER,a.__webglNormalBuffer);if(c.shading===THREE.FlatShading){var d,e,f,g,i,h,k,l,n,m,p,q=3*a.count;for(p=0;p<q;p+=9)m=a.normalArray,d=m[p],e=m[p+1],f=m[p+2],g=m[p+3],h=m[p+4],l=m[p+5],i=m[p+6],k=m[p+7],n=m[p+8],d=(d+g+i)/3,e=(e+h+k)/3,f=(f+l+n)/3,m[p]=d,m[p+1]=e,m[p+2]=f,m[p+3]=d,m[p+4]=e,m[p+5]=f,m[p+6]=d,m[p+7]=e,m[p+8]=f}j.bufferData(j.ARRAY_BUFFER,a.normalArray,j.DYNAMIC_DRAW);j.enableVertexAttribArray(b.attributes.normal);j.vertexAttribPointer(b.attributes.normal, +3,j.FLOAT,!1,0,0)}a.hasUvs&&c.map&&(j.bindBuffer(j.ARRAY_BUFFER,a.__webglUvBuffer),j.bufferData(j.ARRAY_BUFFER,a.uvArray,j.DYNAMIC_DRAW),j.enableVertexAttribArray(b.attributes.uv),j.vertexAttribPointer(b.attributes.uv,2,j.FLOAT,!1,0,0));a.hasColors&&c.vertexColors!==THREE.NoColors&&(j.bindBuffer(j.ARRAY_BUFFER,a.__webglColorBuffer),j.bufferData(j.ARRAY_BUFFER,a.colorArray,j.DYNAMIC_DRAW),j.enableVertexAttribArray(b.attributes.color),j.vertexAttribPointer(b.attributes.color,3,j.FLOAT,!1,0,0));j.drawArrays(j.TRIANGLES, +0,a.count);a.count=0};this.renderBufferDirect=function(a,b,c,d,e,f){if(!1!==d.visible)if(c=A(a,b,c,d,f),a=c.attributes,b=!1,c=16777215*e.id+2*c.id+(d.wireframe?1:0),c!==ka&&(ka=c,b=!0),b&&l(),f instanceof THREE.Mesh)if(d=e.attributes.index){f=e.offsets;1<f.length&&(b=!0);for(var c=0,g=f.length;c<g;c++){var i=f[c].index;if(b){var h=e.attributes.position,n=h.itemSize;j.bindBuffer(j.ARRAY_BUFFER,h.buffer);k(a.position);j.vertexAttribPointer(a.position,n,j.FLOAT,!1,0,4*i*n);n=e.attributes.normal;if(0<= +a.normal&&n){var m=n.itemSize;j.bindBuffer(j.ARRAY_BUFFER,n.buffer);k(a.normal);j.vertexAttribPointer(a.normal,m,j.FLOAT,!1,0,4*i*m)}n=e.attributes.uv;0<=a.uv&&n&&(m=n.itemSize,j.bindBuffer(j.ARRAY_BUFFER,n.buffer),k(a.uv),j.vertexAttribPointer(a.uv,m,j.FLOAT,!1,0,4*i*m));n=e.attributes.color;0<=a.color&&n&&(m=n.itemSize,j.bindBuffer(j.ARRAY_BUFFER,n.buffer),k(a.color),j.vertexAttribPointer(a.color,m,j.FLOAT,!1,0,4*i*m));n=e.attributes.tangent;0<=a.tangent&&n&&(m=n.itemSize,j.bindBuffer(j.ARRAY_BUFFER, +n.buffer),k(a.tangent),j.vertexAttribPointer(a.tangent,m,j.FLOAT,!1,0,4*i*m));j.bindBuffer(j.ELEMENT_ARRAY_BUFFER,d.buffer)}j.drawElements(j.TRIANGLES,f[c].count,j.UNSIGNED_SHORT,2*f[c].start);N.info.render.calls++;N.info.render.vertices+=f[c].count;N.info.render.faces+=f[c].count/3}}else b&&(h=e.attributes.position,n=h.itemSize,j.bindBuffer(j.ARRAY_BUFFER,h.buffer),k(a.position),j.vertexAttribPointer(a.position,n,j.FLOAT,!1,0,0),n=e.attributes.normal,0<=a.normal&&n&&(m=n.itemSize,j.bindBuffer(j.ARRAY_BUFFER, +n.buffer),k(a.normal),j.vertexAttribPointer(a.normal,m,j.FLOAT,!1,0,0)),n=e.attributes.uv,0<=a.uv&&n&&(m=n.itemSize,j.bindBuffer(j.ARRAY_BUFFER,n.buffer),k(a.uv),j.vertexAttribPointer(a.uv,m,j.FLOAT,!1,0,0)),n=e.attributes.color,0<=a.color&&n&&(m=n.itemSize,j.bindBuffer(j.ARRAY_BUFFER,n.buffer),k(a.color),j.vertexAttribPointer(a.color,m,j.FLOAT,!1,0,0)),n=e.attributes.tangent,0<=a.tangent&&n&&(m=n.itemSize,j.bindBuffer(j.ARRAY_BUFFER,n.buffer),k(a.tangent),j.vertexAttribPointer(a.tangent,m,j.FLOAT, +!1,0,0))),j.drawArrays(j.TRIANGLES,0,h.numItems/3),N.info.render.calls++,N.info.render.vertices+=h.numItems/3,N.info.render.faces+=h.numItems/3/3;else f instanceof THREE.ParticleSystem?b&&(h=e.attributes.position,n=h.itemSize,j.bindBuffer(j.ARRAY_BUFFER,h.buffer),k(a.position),j.vertexAttribPointer(a.position,n,j.FLOAT,!1,0,0),n=e.attributes.color,0<=a.color&&n&&(m=n.itemSize,j.bindBuffer(j.ARRAY_BUFFER,n.buffer),k(a.color),j.vertexAttribPointer(a.color,m,j.FLOAT,!1,0,0)),j.drawArrays(j.POINTS,0, +h.numItems/3),N.info.render.calls++,N.info.render.points+=h.numItems/3):f instanceof THREE.Line&&b&&(h=e.attributes.position,n=h.itemSize,j.bindBuffer(j.ARRAY_BUFFER,h.buffer),k(a.position),j.vertexAttribPointer(a.position,n,j.FLOAT,!1,0,0),n=e.attributes.color,0<=a.color&&n&&(m=n.itemSize,j.bindBuffer(j.ARRAY_BUFFER,n.buffer),k(a.color),j.vertexAttribPointer(a.color,m,j.FLOAT,!1,0,0)),J(d.linewidth),j.drawArrays(j.LINE_STRIP,0,h.numItems/3),N.info.render.calls++,N.info.render.points+=h.numItems)}; +this.renderBuffer=function(a,b,c,d,e,f){if(!1!==d.visible){var g,i,c=A(a,b,c,d,f),a=c.attributes,b=!1,c=16777215*e.id+2*c.id+(d.wireframe?1:0);c!==ka&&(ka=c,b=!0);b&&l();if(!d.morphTargets&&0<=a.position)b&&(j.bindBuffer(j.ARRAY_BUFFER,e.__webglVertexBuffer),k(a.position),j.vertexAttribPointer(a.position,3,j.FLOAT,!1,0,0));else if(f.morphTargetBase){c=d.program.attributes;-1!==f.morphTargetBase&&0<=c.position?(j.bindBuffer(j.ARRAY_BUFFER,e.__webglMorphTargetsBuffers[f.morphTargetBase]),k(c.position), +j.vertexAttribPointer(c.position,3,j.FLOAT,!1,0,0)):0<=c.position&&(j.bindBuffer(j.ARRAY_BUFFER,e.__webglVertexBuffer),k(c.position),j.vertexAttribPointer(c.position,3,j.FLOAT,!1,0,0));if(f.morphTargetForcedOrder.length){var h=0;i=f.morphTargetForcedOrder;for(g=f.morphTargetInfluences;h<d.numSupportedMorphTargets&&h<i.length;)0<=c["morphTarget"+h]&&(j.bindBuffer(j.ARRAY_BUFFER,e.__webglMorphTargetsBuffers[i[h]]),k(c["morphTarget"+h]),j.vertexAttribPointer(c["morphTarget"+h],3,j.FLOAT,!1,0,0)),0<= +c["morphNormal"+h]&&d.morphNormals&&(j.bindBuffer(j.ARRAY_BUFFER,e.__webglMorphNormalsBuffers[i[h]]),k(c["morphNormal"+h]),j.vertexAttribPointer(c["morphNormal"+h],3,j.FLOAT,!1,0,0)),f.__webglMorphTargetInfluences[h]=g[i[h]],h++}else{i=[];g=f.morphTargetInfluences;var m,p=g.length;for(m=0;m<p;m++)h=g[m],0<h&&i.push([h,m]);i.length>d.numSupportedMorphTargets?(i.sort(n),i.length=d.numSupportedMorphTargets):i.length>d.numSupportedMorphNormals?i.sort(n):0===i.length&&i.push([0,0]);for(h=0;h<d.numSupportedMorphTargets;)i[h]? +(m=i[h][1],0<=c["morphTarget"+h]&&(j.bindBuffer(j.ARRAY_BUFFER,e.__webglMorphTargetsBuffers[m]),k(c["morphTarget"+h]),j.vertexAttribPointer(c["morphTarget"+h],3,j.FLOAT,!1,0,0)),0<=c["morphNormal"+h]&&d.morphNormals&&(j.bindBuffer(j.ARRAY_BUFFER,e.__webglMorphNormalsBuffers[m]),k(c["morphNormal"+h]),j.vertexAttribPointer(c["morphNormal"+h],3,j.FLOAT,!1,0,0)),f.__webglMorphTargetInfluences[h]=g[m]):f.__webglMorphTargetInfluences[h]=0,h++}null!==d.program.uniforms.morphTargetInfluences&&j.uniform1fv(d.program.uniforms.morphTargetInfluences, +f.__webglMorphTargetInfluences)}if(b){if(e.__webglCustomAttributesList){g=0;for(i=e.__webglCustomAttributesList.length;g<i;g++)c=e.__webglCustomAttributesList[g],0<=a[c.buffer.belongsToAttribute]&&(j.bindBuffer(j.ARRAY_BUFFER,c.buffer),k(a[c.buffer.belongsToAttribute]),j.vertexAttribPointer(a[c.buffer.belongsToAttribute],c.size,j.FLOAT,!1,0,0))}0<=a.color&&(j.bindBuffer(j.ARRAY_BUFFER,e.__webglColorBuffer),k(a.color),j.vertexAttribPointer(a.color,3,j.FLOAT,!1,0,0));0<=a.normal&&(j.bindBuffer(j.ARRAY_BUFFER, +e.__webglNormalBuffer),k(a.normal),j.vertexAttribPointer(a.normal,3,j.FLOAT,!1,0,0));0<=a.tangent&&(j.bindBuffer(j.ARRAY_BUFFER,e.__webglTangentBuffer),k(a.tangent),j.vertexAttribPointer(a.tangent,4,j.FLOAT,!1,0,0));0<=a.uv&&(j.bindBuffer(j.ARRAY_BUFFER,e.__webglUVBuffer),k(a.uv),j.vertexAttribPointer(a.uv,2,j.FLOAT,!1,0,0));0<=a.uv2&&(j.bindBuffer(j.ARRAY_BUFFER,e.__webglUV2Buffer),k(a.uv2),j.vertexAttribPointer(a.uv2,2,j.FLOAT,!1,0,0));d.skinning&&(0<=a.skinIndex&&0<=a.skinWeight)&&(j.bindBuffer(j.ARRAY_BUFFER, +e.__webglSkinIndicesBuffer),k(a.skinIndex),j.vertexAttribPointer(a.skinIndex,4,j.FLOAT,!1,0,0),j.bindBuffer(j.ARRAY_BUFFER,e.__webglSkinWeightsBuffer),k(a.skinWeight),j.vertexAttribPointer(a.skinWeight,4,j.FLOAT,!1,0,0));0<=a.lineDistance&&(j.bindBuffer(j.ARRAY_BUFFER,e.__webglLineDistanceBuffer),k(a.lineDistance),j.vertexAttribPointer(a.lineDistance,1,j.FLOAT,!1,0,0))}f instanceof THREE.Mesh?(d.wireframe?(J(d.wireframeLinewidth),b&&j.bindBuffer(j.ELEMENT_ARRAY_BUFFER,e.__webglLineBuffer),j.drawElements(j.LINES, +e.__webglLineCount,j.UNSIGNED_SHORT,0)):(b&&j.bindBuffer(j.ELEMENT_ARRAY_BUFFER,e.__webglFaceBuffer),j.drawElements(j.TRIANGLES,e.__webglFaceCount,j.UNSIGNED_SHORT,0)),N.info.render.calls++,N.info.render.vertices+=e.__webglFaceCount,N.info.render.faces+=e.__webglFaceCount/3):f instanceof THREE.Line?(f=f.type===THREE.LineStrip?j.LINE_STRIP:j.LINES,J(d.linewidth),j.drawArrays(f,0,e.__webglLineCount),N.info.render.calls++):f instanceof THREE.ParticleSystem?(j.drawArrays(j.POINTS,0,e.__webglParticleCount), +N.info.render.calls++,N.info.render.points+=e.__webglParticleCount):f instanceof THREE.Ribbon&&(j.drawArrays(j.TRIANGLE_STRIP,0,e.__webglVertexCount),N.info.render.calls++)}};this.render=function(a,b,c,d){if(!1===b instanceof THREE.Camera)console.error("THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.");else{var e,f,g,i,h=a.__lights,k=a.fog;ta=-1;bb=!0;this.autoUpdateScene&&a.updateMatrixWorld();void 0===b.parent&&b.updateMatrixWorld();b.matrixWorldInverse.getInverse(b.matrixWorld); +gc.multiplyMatrices(b.projectionMatrix,b.matrixWorldInverse);Va.setFromMatrix(gc);this.autoUpdateObjects&&this.initWebGLObjects(a);s(this.renderPluginsPre,a,b);N.info.render.calls=0;N.info.render.vertices=0;N.info.render.faces=0;N.info.render.points=0;this.setRenderTarget(c);(this.autoClear||d)&&this.clear(this.autoClearColor,this.autoClearDepth,this.autoClearStencil);i=a.__webglObjects;d=0;for(e=i.length;d<e;d++)if(f=i[d],g=f.object,f.render=!1,g.visible&&(!(g instanceof THREE.Mesh||g instanceof +THREE.ParticleSystem)||!g.frustumCulled||Va.intersectsObject(g))){C(g,b);var n=f,l=n.buffer,q=void 0,t=q=void 0,t=n.object.material;if(t instanceof THREE.MeshFaceMaterial)q=l.materialIndex,q=t.materials[q],q.transparent?(n.transparent=q,n.opaque=null):(n.opaque=q,n.transparent=null);else if(q=t)q.transparent?(n.transparent=q,n.opaque=null):(n.opaque=q,n.transparent=null);f.render=!0;!0===this.sortObjects&&(null!==g.renderDepth?f.z=g.renderDepth:(Qa.getPositionFromMatrix(g.matrixWorld),Qa.applyProjection(gc), +f.z=Qa.z),f.id=g.id)}this.sortObjects&&i.sort(m);i=a.__webglObjectsImmediate;d=0;for(e=i.length;d<e;d++)f=i[d],g=f.object,g.visible&&(C(g,b),g=f.object.material,g.transparent?(f.transparent=g,f.opaque=null):(f.opaque=g,f.transparent=null));a.overrideMaterial?(d=a.overrideMaterial,this.setBlending(d.blending,d.blendEquation,d.blendSrc,d.blendDst),this.setDepthTest(d.depthTest),this.setDepthWrite(d.depthWrite),E(d.polygonOffset,d.polygonOffsetFactor,d.polygonOffsetUnits),r(a.__webglObjects,!1,"",b, +h,k,!0,d),p(a.__webglObjectsImmediate,"",b,h,k,!1,d)):(d=null,this.setBlending(THREE.NoBlending),r(a.__webglObjects,!0,"opaque",b,h,k,!1,d),p(a.__webglObjectsImmediate,"opaque",b,h,k,!1,d),r(a.__webglObjects,!1,"transparent",b,h,k,!0,d),p(a.__webglObjectsImmediate,"transparent",b,h,k,!0,d));s(this.renderPluginsPost,a,b);c&&(c.generateMipmaps&&c.minFilter!==THREE.NearestFilter&&c.minFilter!==THREE.LinearFilter)&&(c instanceof THREE.WebGLRenderTargetCube?(j.bindTexture(j.TEXTURE_CUBE_MAP,c.__webglTexture), +j.generateMipmap(j.TEXTURE_CUBE_MAP),j.bindTexture(j.TEXTURE_CUBE_MAP,null)):(j.bindTexture(j.TEXTURE_2D,c.__webglTexture),j.generateMipmap(j.TEXTURE_2D),j.bindTexture(j.TEXTURE_2D,null)));this.setDepthTest(!0);this.setDepthWrite(!0)}};this.renderImmediateObject=function(a,b,c,d,e){var f=A(a,b,c,d,e);ka=-1;N.setMaterialFaces(d);e.immediateRenderCallback?e.immediateRenderCallback(f,j,Va):e.render(function(a){N.renderBufferImmediate(a,f,d)})};this.initWebGLObjects=function(a){a.__webglObjects||(a.__webglObjects= +[],a.__webglObjectsImmediate=[],a.__webglSprites=[],a.__webglFlares=[]);for(;a.__objectsAdded.length;){var b=a.__objectsAdded[0],k=a,l=void 0,m=void 0,p=void 0,r=void 0;if(!b.__webglInit)if(b.__webglInit=!0,b._modelViewMatrix=new THREE.Matrix4,b._normalMatrix=new THREE.Matrix3,void 0!==b.geometry&&void 0===b.geometry.__webglInit&&(b.geometry.__webglInit=!0,b.geometry.addEventListener("dispose",wd)),b instanceof THREE.Mesh)if(m=b.geometry,p=b.material,m instanceof THREE.Geometry){if(void 0===m.geometryGroups){var s= +m,x=void 0,C=void 0,B=void 0,A=void 0,F=void 0,E=void 0,G={},I=s.morphTargets.length,J=s.morphNormals.length,K=p instanceof THREE.MeshFaceMaterial;s.geometryGroups={};x=0;for(C=s.faces.length;x<C;x++)B=s.faces[x],A=K?B.materialIndex:0,void 0===G[A]&&(G[A]={hash:A,counter:0}),E=G[A].hash+"_"+G[A].counter,void 0===s.geometryGroups[E]&&(s.geometryGroups[E]={faces3:[],faces4:[],materialIndex:A,vertices:0,numMorphTargets:I,numMorphNormals:J}),F=B instanceof THREE.Face3?3:4,65535<s.geometryGroups[E].vertices+ +F&&(G[A].counter+=1,E=G[A].hash+"_"+G[A].counter,void 0===s.geometryGroups[E]&&(s.geometryGroups[E]={faces3:[],faces4:[],materialIndex:A,vertices:0,numMorphTargets:I,numMorphNormals:J})),B instanceof THREE.Face3?s.geometryGroups[E].faces3.push(x):s.geometryGroups[E].faces4.push(x),s.geometryGroups[E].vertices+=F;s.geometryGroupsList=[];var L=void 0;for(L in s.geometryGroups)s.geometryGroups[L].id=pa++,s.geometryGroupsList.push(s.geometryGroups[L])}for(l in m.geometryGroups)if(r=m.geometryGroups[l], +!r.__webglVertexBuffer){var H=r;H.__webglVertexBuffer=j.createBuffer();H.__webglNormalBuffer=j.createBuffer();H.__webglTangentBuffer=j.createBuffer();H.__webglColorBuffer=j.createBuffer();H.__webglUVBuffer=j.createBuffer();H.__webglUV2Buffer=j.createBuffer();H.__webglSkinIndicesBuffer=j.createBuffer();H.__webglSkinWeightsBuffer=j.createBuffer();H.__webglFaceBuffer=j.createBuffer();H.__webglLineBuffer=j.createBuffer();var M=void 0,P=void 0;if(H.numMorphTargets){H.__webglMorphTargetsBuffers=[];M=0; +for(P=H.numMorphTargets;M<P;M++)H.__webglMorphTargetsBuffers.push(j.createBuffer())}if(H.numMorphNormals){H.__webglMorphNormalsBuffers=[];M=0;for(P=H.numMorphNormals;M<P;M++)H.__webglMorphNormalsBuffers.push(j.createBuffer())}N.info.memory.geometries++;d(r,b);m.verticesNeedUpdate=!0;m.morphTargetsNeedUpdate=!0;m.elementsNeedUpdate=!0;m.uvsNeedUpdate=!0;m.normalsNeedUpdate=!0;m.tangentsNeedUpdate=!0;m.colorsNeedUpdate=!0}}else m instanceof THREE.BufferGeometry&&h(m);else if(b instanceof THREE.Ribbon){if(m= +b.geometry,!m.__webglVertexBuffer){var U=m;U.__webglVertexBuffer=j.createBuffer();U.__webglColorBuffer=j.createBuffer();U.__webglNormalBuffer=j.createBuffer();N.info.memory.geometries++;var aa=m,W=b,Y=aa.vertices.length;aa.__vertexArray=new Float32Array(3*Y);aa.__colorArray=new Float32Array(3*Y);aa.__normalArray=new Float32Array(3*Y);aa.__webglVertexCount=Y;c(aa,W);m.verticesNeedUpdate=!0;m.colorsNeedUpdate=!0;m.normalsNeedUpdate=!0}}else if(b instanceof THREE.Line){if(m=b.geometry,!m.__webglVertexBuffer)if(m instanceof +THREE.Geometry){var Z=m;Z.__webglVertexBuffer=j.createBuffer();Z.__webglColorBuffer=j.createBuffer();Z.__webglLineDistanceBuffer=j.createBuffer();N.info.memory.geometries++;var X=m,da=b,ka=X.vertices.length;X.__vertexArray=new Float32Array(3*ka);X.__colorArray=new Float32Array(3*ka);X.__lineDistanceArray=new Float32Array(1*ka);X.__webglLineCount=ka;c(X,da);m.verticesNeedUpdate=!0;m.colorsNeedUpdate=!0;m.lineDistancesNeedUpdate=!0}else m instanceof THREE.BufferGeometry&&h(m)}else if(b instanceof THREE.ParticleSystem&& +(m=b.geometry,!m.__webglVertexBuffer))if(m instanceof THREE.Geometry){var fa=m;fa.__webglVertexBuffer=j.createBuffer();fa.__webglColorBuffer=j.createBuffer();N.info.memory.geometries++;var ca=m,Ma=b,ha=ca.vertices.length;ca.__vertexArray=new Float32Array(3*ha);ca.__colorArray=new Float32Array(3*ha);ca.__sortArray=[];ca.__webglParticleCount=ha;c(ca,Ma);m.verticesNeedUpdate=!0;m.colorsNeedUpdate=!0}else m instanceof THREE.BufferGeometry&&h(m);if(!b.__webglActive){if(b instanceof THREE.Mesh)if(m=b.geometry, +m instanceof THREE.BufferGeometry)q(k.__webglObjects,m,b);else{if(m instanceof THREE.Geometry)for(l in m.geometryGroups)r=m.geometryGroups[l],q(k.__webglObjects,r,b)}else b instanceof THREE.Ribbon||b instanceof THREE.Line||b instanceof THREE.ParticleSystem?(m=b.geometry,q(k.__webglObjects,m,b)):b instanceof THREE.ImmediateRenderObject||b.immediateRenderCallback?k.__webglObjectsImmediate.push({object:b,opaque:null,transparent:null}):b instanceof THREE.Sprite?k.__webglSprites.push(b):b instanceof THREE.LensFlare&& +k.__webglFlares.push(b);b.__webglActive=!0}a.__objectsAdded.splice(0,1)}for(;a.__objectsRemoved.length;){var Na=a.__objectsRemoved[0],la=a;Na instanceof THREE.Mesh||Na instanceof THREE.ParticleSystem||Na instanceof THREE.Ribbon||Na instanceof THREE.Line?z(la.__webglObjects,Na):Na instanceof THREE.Sprite?t(la.__webglSprites,Na):Na instanceof THREE.LensFlare?t(la.__webglFlares,Na):(Na instanceof THREE.ImmediateRenderObject||Na.immediateRenderCallback)&&z(la.__webglObjectsImmediate,Na);Na.__webglActive= +!1;a.__objectsRemoved.splice(0,1)}for(var oa=0,ra=a.__webglObjects.length;oa<ra;oa++){var ta=a.__webglObjects[oa].object,O=ta.geometry,mb=void 0,qa=void 0,ia=void 0;if(ta instanceof THREE.Mesh)if(O instanceof THREE.BufferGeometry)(O.verticesNeedUpdate||O.elementsNeedUpdate||O.uvsNeedUpdate||O.normalsNeedUpdate||O.colorsNeedUpdate||O.tangentsNeedUpdate)&&i(O,j.DYNAMIC_DRAW,!O.dynamic),O.verticesNeedUpdate=!1,O.elementsNeedUpdate=!1,O.uvsNeedUpdate=!1,O.normalsNeedUpdate=!1,O.colorsNeedUpdate=!1,O.tangentsNeedUpdate= +!1;else{for(var Ca=0,Ka=O.geometryGroupsList.length;Ca<Ka;Ca++)if(mb=O.geometryGroupsList[Ca],ia=e(ta,mb),O.buffersNeedUpdate&&d(mb,ta),qa=ia.attributes&&y(ia),O.verticesNeedUpdate||O.morphTargetsNeedUpdate||O.elementsNeedUpdate||O.uvsNeedUpdate||O.normalsNeedUpdate||O.colorsNeedUpdate||O.tangentsNeedUpdate||qa){var sa=mb,La=ta,Pa=j.DYNAMIC_DRAW,Va=!O.dynamic,Fa=ia;if(sa.__inittedArrays){var gb=f(Fa),Wa=Fa.vertexColors?Fa.vertexColors:!1,bb=g(Fa),$a=gb===THREE.SmoothShading,D=void 0,V=void 0,Ra=void 0, +Q=void 0,ab=void 0,Xa=void 0,Sa=void 0,nb=void 0,cb=void 0,pb=void 0,ub=void 0,R=void 0,S=void 0,T=void 0,na=void 0,Mb=void 0,Nb=void 0,Ob=void 0,xb=void 0,Pb=void 0,Qb=void 0,Rb=void 0,yb=void 0,Sb=void 0,Tb=void 0,Ub=void 0,zb=void 0,Vb=void 0,Wb=void 0,Xb=void 0,Ib=void 0,Yb=void 0,Zb=void 0,$b=void 0,Jb=void 0,xa=void 0,fc=void 0,nc=void 0,Ab=void 0,yc=void 0,db=void 0,mc=void 0,Ya=void 0,Za=void 0,oc=void 0,hc=void 0,Oa=0,Ua=0,ic=0,jc=0,Eb=0,kb=0,Aa=0,ob=0,Ta=0,ba=0,ja=0,w=0,ya=void 0,eb=sa.__vertexArray, +Dc=sa.__uvArray,Ec=sa.__uv2Array,Fb=sa.__normalArray,Ga=sa.__tangentArray,fb=sa.__colorArray,Ha=sa.__skinIndexArray,Ia=sa.__skinWeightArray,sc=sa.__morphTargetsArrays,tc=sa.__morphNormalsArrays,od=sa.__webglCustomAttributesList,u=void 0,ac=sa.__faceArray,wb=sa.__lineArray,qb=La.geometry,Mc=qb.elementsNeedUpdate,Cc=qb.uvsNeedUpdate,Nc=qb.normalsNeedUpdate,Oc=qb.tangentsNeedUpdate,Pc=qb.colorsNeedUpdate,fd=qb.morphTargetsNeedUpdate,uc=qb.vertices,ua=sa.faces3,va=sa.faces4,lb=qb.faces,pd=qb.faceVertexUvs[0], +qd=qb.faceVertexUvs[1],vc=qb.skinIndices,pc=qb.skinWeights,qc=qb.morphTargets,Qc=qb.morphNormals;if(qb.verticesNeedUpdate){D=0;for(V=ua.length;D<V;D++)Q=lb[ua[D]],R=uc[Q.a],S=uc[Q.b],T=uc[Q.c],eb[Ua]=R.x,eb[Ua+1]=R.y,eb[Ua+2]=R.z,eb[Ua+3]=S.x,eb[Ua+4]=S.y,eb[Ua+5]=S.z,eb[Ua+6]=T.x,eb[Ua+7]=T.y,eb[Ua+8]=T.z,Ua+=9;D=0;for(V=va.length;D<V;D++)Q=lb[va[D]],R=uc[Q.a],S=uc[Q.b],T=uc[Q.c],na=uc[Q.d],eb[Ua]=R.x,eb[Ua+1]=R.y,eb[Ua+2]=R.z,eb[Ua+3]=S.x,eb[Ua+4]=S.y,eb[Ua+5]=S.z,eb[Ua+6]=T.x,eb[Ua+7]=T.y,eb[Ua+ +8]=T.z,eb[Ua+9]=na.x,eb[Ua+10]=na.y,eb[Ua+11]=na.z,Ua+=12;j.bindBuffer(j.ARRAY_BUFFER,sa.__webglVertexBuffer);j.bufferData(j.ARRAY_BUFFER,eb,Pa)}if(fd){db=0;for(mc=qc.length;db<mc;db++){D=ja=0;for(V=ua.length;D<V;D++)oc=ua[D],Q=lb[oc],R=qc[db].vertices[Q.a],S=qc[db].vertices[Q.b],T=qc[db].vertices[Q.c],Ya=sc[db],Ya[ja]=R.x,Ya[ja+1]=R.y,Ya[ja+2]=R.z,Ya[ja+3]=S.x,Ya[ja+4]=S.y,Ya[ja+5]=S.z,Ya[ja+6]=T.x,Ya[ja+7]=T.y,Ya[ja+8]=T.z,Fa.morphNormals&&($a?(hc=Qc[db].vertexNormals[oc],Pb=hc.a,Qb=hc.b,Rb=hc.c): +Rb=Qb=Pb=Qc[db].faceNormals[oc],Za=tc[db],Za[ja]=Pb.x,Za[ja+1]=Pb.y,Za[ja+2]=Pb.z,Za[ja+3]=Qb.x,Za[ja+4]=Qb.y,Za[ja+5]=Qb.z,Za[ja+6]=Rb.x,Za[ja+7]=Rb.y,Za[ja+8]=Rb.z),ja+=9;D=0;for(V=va.length;D<V;D++)oc=va[D],Q=lb[oc],R=qc[db].vertices[Q.a],S=qc[db].vertices[Q.b],T=qc[db].vertices[Q.c],na=qc[db].vertices[Q.d],Ya=sc[db],Ya[ja]=R.x,Ya[ja+1]=R.y,Ya[ja+2]=R.z,Ya[ja+3]=S.x,Ya[ja+4]=S.y,Ya[ja+5]=S.z,Ya[ja+6]=T.x,Ya[ja+7]=T.y,Ya[ja+8]=T.z,Ya[ja+9]=na.x,Ya[ja+10]=na.y,Ya[ja+11]=na.z,Fa.morphNormals&&($a? +(hc=Qc[db].vertexNormals[oc],Pb=hc.a,Qb=hc.b,Rb=hc.c,yb=hc.d):yb=Rb=Qb=Pb=Qc[db].faceNormals[oc],Za=tc[db],Za[ja]=Pb.x,Za[ja+1]=Pb.y,Za[ja+2]=Pb.z,Za[ja+3]=Qb.x,Za[ja+4]=Qb.y,Za[ja+5]=Qb.z,Za[ja+6]=Rb.x,Za[ja+7]=Rb.y,Za[ja+8]=Rb.z,Za[ja+9]=yb.x,Za[ja+10]=yb.y,Za[ja+11]=yb.z),ja+=12;j.bindBuffer(j.ARRAY_BUFFER,sa.__webglMorphTargetsBuffers[db]);j.bufferData(j.ARRAY_BUFFER,sc[db],Pa);Fa.morphNormals&&(j.bindBuffer(j.ARRAY_BUFFER,sa.__webglMorphNormalsBuffers[db]),j.bufferData(j.ARRAY_BUFFER,tc[db], +Pa))}}if(pc.length){D=0;for(V=ua.length;D<V;D++)Q=lb[ua[D]],Vb=pc[Q.a],Wb=pc[Q.b],Xb=pc[Q.c],Ia[ba]=Vb.x,Ia[ba+1]=Vb.y,Ia[ba+2]=Vb.z,Ia[ba+3]=Vb.w,Ia[ba+4]=Wb.x,Ia[ba+5]=Wb.y,Ia[ba+6]=Wb.z,Ia[ba+7]=Wb.w,Ia[ba+8]=Xb.x,Ia[ba+9]=Xb.y,Ia[ba+10]=Xb.z,Ia[ba+11]=Xb.w,Yb=vc[Q.a],Zb=vc[Q.b],$b=vc[Q.c],Ha[ba]=Yb.x,Ha[ba+1]=Yb.y,Ha[ba+2]=Yb.z,Ha[ba+3]=Yb.w,Ha[ba+4]=Zb.x,Ha[ba+5]=Zb.y,Ha[ba+6]=Zb.z,Ha[ba+7]=Zb.w,Ha[ba+8]=$b.x,Ha[ba+9]=$b.y,Ha[ba+10]=$b.z,Ha[ba+11]=$b.w,ba+=12;D=0;for(V=va.length;D<V;D++)Q=lb[va[D]], +Vb=pc[Q.a],Wb=pc[Q.b],Xb=pc[Q.c],Ib=pc[Q.d],Ia[ba]=Vb.x,Ia[ba+1]=Vb.y,Ia[ba+2]=Vb.z,Ia[ba+3]=Vb.w,Ia[ba+4]=Wb.x,Ia[ba+5]=Wb.y,Ia[ba+6]=Wb.z,Ia[ba+7]=Wb.w,Ia[ba+8]=Xb.x,Ia[ba+9]=Xb.y,Ia[ba+10]=Xb.z,Ia[ba+11]=Xb.w,Ia[ba+12]=Ib.x,Ia[ba+13]=Ib.y,Ia[ba+14]=Ib.z,Ia[ba+15]=Ib.w,Yb=vc[Q.a],Zb=vc[Q.b],$b=vc[Q.c],Jb=vc[Q.d],Ha[ba]=Yb.x,Ha[ba+1]=Yb.y,Ha[ba+2]=Yb.z,Ha[ba+3]=Yb.w,Ha[ba+4]=Zb.x,Ha[ba+5]=Zb.y,Ha[ba+6]=Zb.z,Ha[ba+7]=Zb.w,Ha[ba+8]=$b.x,Ha[ba+9]=$b.y,Ha[ba+10]=$b.z,Ha[ba+11]=$b.w,Ha[ba+12]=Jb.x,Ha[ba+ +13]=Jb.y,Ha[ba+14]=Jb.z,Ha[ba+15]=Jb.w,ba+=16;0<ba&&(j.bindBuffer(j.ARRAY_BUFFER,sa.__webglSkinIndicesBuffer),j.bufferData(j.ARRAY_BUFFER,Ha,Pa),j.bindBuffer(j.ARRAY_BUFFER,sa.__webglSkinWeightsBuffer),j.bufferData(j.ARRAY_BUFFER,Ia,Pa))}if(Pc&&Wa){D=0;for(V=ua.length;D<V;D++)Q=lb[ua[D]],Sa=Q.vertexColors,nb=Q.color,3===Sa.length&&Wa===THREE.VertexColors?(Sb=Sa[0],Tb=Sa[1],Ub=Sa[2]):Ub=Tb=Sb=nb,fb[Ta]=Sb.r,fb[Ta+1]=Sb.g,fb[Ta+2]=Sb.b,fb[Ta+3]=Tb.r,fb[Ta+4]=Tb.g,fb[Ta+5]=Tb.b,fb[Ta+6]=Ub.r,fb[Ta+7]= +Ub.g,fb[Ta+8]=Ub.b,Ta+=9;D=0;for(V=va.length;D<V;D++)Q=lb[va[D]],Sa=Q.vertexColors,nb=Q.color,4===Sa.length&&Wa===THREE.VertexColors?(Sb=Sa[0],Tb=Sa[1],Ub=Sa[2],zb=Sa[3]):zb=Ub=Tb=Sb=nb,fb[Ta]=Sb.r,fb[Ta+1]=Sb.g,fb[Ta+2]=Sb.b,fb[Ta+3]=Tb.r,fb[Ta+4]=Tb.g,fb[Ta+5]=Tb.b,fb[Ta+6]=Ub.r,fb[Ta+7]=Ub.g,fb[Ta+8]=Ub.b,fb[Ta+9]=zb.r,fb[Ta+10]=zb.g,fb[Ta+11]=zb.b,Ta+=12;0<Ta&&(j.bindBuffer(j.ARRAY_BUFFER,sa.__webglColorBuffer),j.bufferData(j.ARRAY_BUFFER,fb,Pa))}if(Oc&&qb.hasTangents){D=0;for(V=ua.length;D<V;D++)Q= +lb[ua[D]],cb=Q.vertexTangents,Mb=cb[0],Nb=cb[1],Ob=cb[2],Ga[Aa]=Mb.x,Ga[Aa+1]=Mb.y,Ga[Aa+2]=Mb.z,Ga[Aa+3]=Mb.w,Ga[Aa+4]=Nb.x,Ga[Aa+5]=Nb.y,Ga[Aa+6]=Nb.z,Ga[Aa+7]=Nb.w,Ga[Aa+8]=Ob.x,Ga[Aa+9]=Ob.y,Ga[Aa+10]=Ob.z,Ga[Aa+11]=Ob.w,Aa+=12;D=0;for(V=va.length;D<V;D++)Q=lb[va[D]],cb=Q.vertexTangents,Mb=cb[0],Nb=cb[1],Ob=cb[2],xb=cb[3],Ga[Aa]=Mb.x,Ga[Aa+1]=Mb.y,Ga[Aa+2]=Mb.z,Ga[Aa+3]=Mb.w,Ga[Aa+4]=Nb.x,Ga[Aa+5]=Nb.y,Ga[Aa+6]=Nb.z,Ga[Aa+7]=Nb.w,Ga[Aa+8]=Ob.x,Ga[Aa+9]=Ob.y,Ga[Aa+10]=Ob.z,Ga[Aa+11]=Ob.w,Ga[Aa+ +12]=xb.x,Ga[Aa+13]=xb.y,Ga[Aa+14]=xb.z,Ga[Aa+15]=xb.w,Aa+=16;j.bindBuffer(j.ARRAY_BUFFER,sa.__webglTangentBuffer);j.bufferData(j.ARRAY_BUFFER,Ga,Pa)}if(Nc&&gb){D=0;for(V=ua.length;D<V;D++)if(Q=lb[ua[D]],ab=Q.vertexNormals,Xa=Q.normal,3===ab.length&&$a)for(xa=0;3>xa;xa++)nc=ab[xa],Fb[kb]=nc.x,Fb[kb+1]=nc.y,Fb[kb+2]=nc.z,kb+=3;else for(xa=0;3>xa;xa++)Fb[kb]=Xa.x,Fb[kb+1]=Xa.y,Fb[kb+2]=Xa.z,kb+=3;D=0;for(V=va.length;D<V;D++)if(Q=lb[va[D]],ab=Q.vertexNormals,Xa=Q.normal,4===ab.length&&$a)for(xa=0;4>xa;xa++)nc= +ab[xa],Fb[kb]=nc.x,Fb[kb+1]=nc.y,Fb[kb+2]=nc.z,kb+=3;else for(xa=0;4>xa;xa++)Fb[kb]=Xa.x,Fb[kb+1]=Xa.y,Fb[kb+2]=Xa.z,kb+=3;j.bindBuffer(j.ARRAY_BUFFER,sa.__webglNormalBuffer);j.bufferData(j.ARRAY_BUFFER,Fb,Pa)}if(Cc&&pd&&bb){D=0;for(V=ua.length;D<V;D++)if(Ra=ua[D],pb=pd[Ra],void 0!==pb)for(xa=0;3>xa;xa++)Ab=pb[xa],Dc[ic]=Ab.x,Dc[ic+1]=Ab.y,ic+=2;D=0;for(V=va.length;D<V;D++)if(Ra=va[D],pb=pd[Ra],void 0!==pb)for(xa=0;4>xa;xa++)Ab=pb[xa],Dc[ic]=Ab.x,Dc[ic+1]=Ab.y,ic+=2;0<ic&&(j.bindBuffer(j.ARRAY_BUFFER, +sa.__webglUVBuffer),j.bufferData(j.ARRAY_BUFFER,Dc,Pa))}if(Cc&&qd&&bb){D=0;for(V=ua.length;D<V;D++)if(Ra=ua[D],ub=qd[Ra],void 0!==ub)for(xa=0;3>xa;xa++)yc=ub[xa],Ec[jc]=yc.x,Ec[jc+1]=yc.y,jc+=2;D=0;for(V=va.length;D<V;D++)if(Ra=va[D],ub=qd[Ra],void 0!==ub)for(xa=0;4>xa;xa++)yc=ub[xa],Ec[jc]=yc.x,Ec[jc+1]=yc.y,jc+=2;0<jc&&(j.bindBuffer(j.ARRAY_BUFFER,sa.__webglUV2Buffer),j.bufferData(j.ARRAY_BUFFER,Ec,Pa))}if(Mc){D=0;for(V=ua.length;D<V;D++)ac[Eb]=Oa,ac[Eb+1]=Oa+1,ac[Eb+2]=Oa+2,Eb+=3,wb[ob]=Oa,wb[ob+ +1]=Oa+1,wb[ob+2]=Oa,wb[ob+3]=Oa+2,wb[ob+4]=Oa+1,wb[ob+5]=Oa+2,ob+=6,Oa+=3;D=0;for(V=va.length;D<V;D++)ac[Eb]=Oa,ac[Eb+1]=Oa+1,ac[Eb+2]=Oa+3,ac[Eb+3]=Oa+1,ac[Eb+4]=Oa+2,ac[Eb+5]=Oa+3,Eb+=6,wb[ob]=Oa,wb[ob+1]=Oa+1,wb[ob+2]=Oa,wb[ob+3]=Oa+3,wb[ob+4]=Oa+1,wb[ob+5]=Oa+2,wb[ob+6]=Oa+2,wb[ob+7]=Oa+3,ob+=8,Oa+=4;j.bindBuffer(j.ELEMENT_ARRAY_BUFFER,sa.__webglFaceBuffer);j.bufferData(j.ELEMENT_ARRAY_BUFFER,ac,Pa);j.bindBuffer(j.ELEMENT_ARRAY_BUFFER,sa.__webglLineBuffer);j.bufferData(j.ELEMENT_ARRAY_BUFFER, +wb,Pa)}if(od){xa=0;for(fc=od.length;xa<fc;xa++)if(u=od[xa],u.__original.needsUpdate){w=0;if(1===u.size)if(void 0===u.boundTo||"vertices"===u.boundTo){D=0;for(V=ua.length;D<V;D++)Q=lb[ua[D]],u.array[w]=u.value[Q.a],u.array[w+1]=u.value[Q.b],u.array[w+2]=u.value[Q.c],w+=3;D=0;for(V=va.length;D<V;D++)Q=lb[va[D]],u.array[w]=u.value[Q.a],u.array[w+1]=u.value[Q.b],u.array[w+2]=u.value[Q.c],u.array[w+3]=u.value[Q.d],w+=4}else{if("faces"===u.boundTo){D=0;for(V=ua.length;D<V;D++)ya=u.value[ua[D]],u.array[w]= +ya,u.array[w+1]=ya,u.array[w+2]=ya,w+=3;D=0;for(V=va.length;D<V;D++)ya=u.value[va[D]],u.array[w]=ya,u.array[w+1]=ya,u.array[w+2]=ya,u.array[w+3]=ya,w+=4}}else if(2===u.size)if(void 0===u.boundTo||"vertices"===u.boundTo){D=0;for(V=ua.length;D<V;D++)Q=lb[ua[D]],R=u.value[Q.a],S=u.value[Q.b],T=u.value[Q.c],u.array[w]=R.x,u.array[w+1]=R.y,u.array[w+2]=S.x,u.array[w+3]=S.y,u.array[w+4]=T.x,u.array[w+5]=T.y,w+=6;D=0;for(V=va.length;D<V;D++)Q=lb[va[D]],R=u.value[Q.a],S=u.value[Q.b],T=u.value[Q.c],na=u.value[Q.d], +u.array[w]=R.x,u.array[w+1]=R.y,u.array[w+2]=S.x,u.array[w+3]=S.y,u.array[w+4]=T.x,u.array[w+5]=T.y,u.array[w+6]=na.x,u.array[w+7]=na.y,w+=8}else{if("faces"===u.boundTo){D=0;for(V=ua.length;D<V;D++)T=S=R=ya=u.value[ua[D]],u.array[w]=R.x,u.array[w+1]=R.y,u.array[w+2]=S.x,u.array[w+3]=S.y,u.array[w+4]=T.x,u.array[w+5]=T.y,w+=6;D=0;for(V=va.length;D<V;D++)na=T=S=R=ya=u.value[va[D]],u.array[w]=R.x,u.array[w+1]=R.y,u.array[w+2]=S.x,u.array[w+3]=S.y,u.array[w+4]=T.x,u.array[w+5]=T.y,u.array[w+6]=na.x,u.array[w+ +7]=na.y,w+=8}}else if(3===u.size){var $;$="c"===u.type?["r","g","b"]:["x","y","z"];if(void 0===u.boundTo||"vertices"===u.boundTo){D=0;for(V=ua.length;D<V;D++)Q=lb[ua[D]],R=u.value[Q.a],S=u.value[Q.b],T=u.value[Q.c],u.array[w]=R[$[0]],u.array[w+1]=R[$[1]],u.array[w+2]=R[$[2]],u.array[w+3]=S[$[0]],u.array[w+4]=S[$[1]],u.array[w+5]=S[$[2]],u.array[w+6]=T[$[0]],u.array[w+7]=T[$[1]],u.array[w+8]=T[$[2]],w+=9;D=0;for(V=va.length;D<V;D++)Q=lb[va[D]],R=u.value[Q.a],S=u.value[Q.b],T=u.value[Q.c],na=u.value[Q.d], +u.array[w]=R[$[0]],u.array[w+1]=R[$[1]],u.array[w+2]=R[$[2]],u.array[w+3]=S[$[0]],u.array[w+4]=S[$[1]],u.array[w+5]=S[$[2]],u.array[w+6]=T[$[0]],u.array[w+7]=T[$[1]],u.array[w+8]=T[$[2]],u.array[w+9]=na[$[0]],u.array[w+10]=na[$[1]],u.array[w+11]=na[$[2]],w+=12}else if("faces"===u.boundTo){D=0;for(V=ua.length;D<V;D++)T=S=R=ya=u.value[ua[D]],u.array[w]=R[$[0]],u.array[w+1]=R[$[1]],u.array[w+2]=R[$[2]],u.array[w+3]=S[$[0]],u.array[w+4]=S[$[1]],u.array[w+5]=S[$[2]],u.array[w+6]=T[$[0]],u.array[w+7]=T[$[1]], +u.array[w+8]=T[$[2]],w+=9;D=0;for(V=va.length;D<V;D++)na=T=S=R=ya=u.value[va[D]],u.array[w]=R[$[0]],u.array[w+1]=R[$[1]],u.array[w+2]=R[$[2]],u.array[w+3]=S[$[0]],u.array[w+4]=S[$[1]],u.array[w+5]=S[$[2]],u.array[w+6]=T[$[0]],u.array[w+7]=T[$[1]],u.array[w+8]=T[$[2]],u.array[w+9]=na[$[0]],u.array[w+10]=na[$[1]],u.array[w+11]=na[$[2]],w+=12}else if("faceVertices"===u.boundTo){D=0;for(V=ua.length;D<V;D++)ya=u.value[ua[D]],R=ya[0],S=ya[1],T=ya[2],u.array[w]=R[$[0]],u.array[w+1]=R[$[1]],u.array[w+2]= +R[$[2]],u.array[w+3]=S[$[0]],u.array[w+4]=S[$[1]],u.array[w+5]=S[$[2]],u.array[w+6]=T[$[0]],u.array[w+7]=T[$[1]],u.array[w+8]=T[$[2]],w+=9;D=0;for(V=va.length;D<V;D++)ya=u.value[va[D]],R=ya[0],S=ya[1],T=ya[2],na=ya[3],u.array[w]=R[$[0]],u.array[w+1]=R[$[1]],u.array[w+2]=R[$[2]],u.array[w+3]=S[$[0]],u.array[w+4]=S[$[1]],u.array[w+5]=S[$[2]],u.array[w+6]=T[$[0]],u.array[w+7]=T[$[1]],u.array[w+8]=T[$[2]],u.array[w+9]=na[$[0]],u.array[w+10]=na[$[1]],u.array[w+11]=na[$[2]],w+=12}}else if(4===u.size)if(void 0=== +u.boundTo||"vertices"===u.boundTo){D=0;for(V=ua.length;D<V;D++)Q=lb[ua[D]],R=u.value[Q.a],S=u.value[Q.b],T=u.value[Q.c],u.array[w]=R.x,u.array[w+1]=R.y,u.array[w+2]=R.z,u.array[w+3]=R.w,u.array[w+4]=S.x,u.array[w+5]=S.y,u.array[w+6]=S.z,u.array[w+7]=S.w,u.array[w+8]=T.x,u.array[w+9]=T.y,u.array[w+10]=T.z,u.array[w+11]=T.w,w+=12;D=0;for(V=va.length;D<V;D++)Q=lb[va[D]],R=u.value[Q.a],S=u.value[Q.b],T=u.value[Q.c],na=u.value[Q.d],u.array[w]=R.x,u.array[w+1]=R.y,u.array[w+2]=R.z,u.array[w+3]=R.w,u.array[w+ +4]=S.x,u.array[w+5]=S.y,u.array[w+6]=S.z,u.array[w+7]=S.w,u.array[w+8]=T.x,u.array[w+9]=T.y,u.array[w+10]=T.z,u.array[w+11]=T.w,u.array[w+12]=na.x,u.array[w+13]=na.y,u.array[w+14]=na.z,u.array[w+15]=na.w,w+=16}else if("faces"===u.boundTo){D=0;for(V=ua.length;D<V;D++)T=S=R=ya=u.value[ua[D]],u.array[w]=R.x,u.array[w+1]=R.y,u.array[w+2]=R.z,u.array[w+3]=R.w,u.array[w+4]=S.x,u.array[w+5]=S.y,u.array[w+6]=S.z,u.array[w+7]=S.w,u.array[w+8]=T.x,u.array[w+9]=T.y,u.array[w+10]=T.z,u.array[w+11]=T.w,w+=12; +D=0;for(V=va.length;D<V;D++)na=T=S=R=ya=u.value[va[D]],u.array[w]=R.x,u.array[w+1]=R.y,u.array[w+2]=R.z,u.array[w+3]=R.w,u.array[w+4]=S.x,u.array[w+5]=S.y,u.array[w+6]=S.z,u.array[w+7]=S.w,u.array[w+8]=T.x,u.array[w+9]=T.y,u.array[w+10]=T.z,u.array[w+11]=T.w,u.array[w+12]=na.x,u.array[w+13]=na.y,u.array[w+14]=na.z,u.array[w+15]=na.w,w+=16}else if("faceVertices"===u.boundTo){D=0;for(V=ua.length;D<V;D++)ya=u.value[ua[D]],R=ya[0],S=ya[1],T=ya[2],u.array[w]=R.x,u.array[w+1]=R.y,u.array[w+2]=R.z,u.array[w+ +3]=R.w,u.array[w+4]=S.x,u.array[w+5]=S.y,u.array[w+6]=S.z,u.array[w+7]=S.w,u.array[w+8]=T.x,u.array[w+9]=T.y,u.array[w+10]=T.z,u.array[w+11]=T.w,w+=12;D=0;for(V=va.length;D<V;D++)ya=u.value[va[D]],R=ya[0],S=ya[1],T=ya[2],na=ya[3],u.array[w]=R.x,u.array[w+1]=R.y,u.array[w+2]=R.z,u.array[w+3]=R.w,u.array[w+4]=S.x,u.array[w+5]=S.y,u.array[w+6]=S.z,u.array[w+7]=S.w,u.array[w+8]=T.x,u.array[w+9]=T.y,u.array[w+10]=T.z,u.array[w+11]=T.w,u.array[w+12]=na.x,u.array[w+13]=na.y,u.array[w+14]=na.z,u.array[w+ +15]=na.w,w+=16}j.bindBuffer(j.ARRAY_BUFFER,u.buffer);j.bufferData(j.ARRAY_BUFFER,u.array,Pa)}}Va&&(delete sa.__inittedArrays,delete sa.__colorArray,delete sa.__normalArray,delete sa.__tangentArray,delete sa.__uvArray,delete sa.__uv2Array,delete sa.__faceArray,delete sa.__vertexArray,delete sa.__lineArray,delete sa.__skinIndexArray,delete sa.__skinWeightArray)}}O.verticesNeedUpdate=!1;O.morphTargetsNeedUpdate=!1;O.elementsNeedUpdate=!1;O.uvsNeedUpdate=!1;O.normalsNeedUpdate=!1;O.colorsNeedUpdate=!1; +O.tangentsNeedUpdate=!1;O.buffersNeedUpdate=!1;ia.attributes&&v(ia)}else if(ta instanceof THREE.Ribbon){ia=e(ta,O);qa=ia.attributes&&y(ia);if(O.verticesNeedUpdate||O.colorsNeedUpdate||O.normalsNeedUpdate||qa){var Gb=O,Rc=j.DYNAMIC_DRAW,Fc=void 0,Gc=void 0,Hc=void 0,Sc=void 0,za=void 0,Tc=void 0,Uc=void 0,Vc=void 0,xd=void 0,ib=void 0,zc=void 0,Da=void 0,rb=void 0,yd=Gb.vertices,zd=Gb.colors,Ad=Gb.normals,gd=yd.length,hd=zd.length,id=Ad.length,Wc=Gb.__vertexArray,Xc=Gb.__colorArray,Yc=Gb.__normalArray, +jd=Gb.colorsNeedUpdate,kd=Gb.normalsNeedUpdate,rd=Gb.__webglCustomAttributesList;if(Gb.verticesNeedUpdate){for(Fc=0;Fc<gd;Fc++)Sc=yd[Fc],za=3*Fc,Wc[za]=Sc.x,Wc[za+1]=Sc.y,Wc[za+2]=Sc.z;j.bindBuffer(j.ARRAY_BUFFER,Gb.__webglVertexBuffer);j.bufferData(j.ARRAY_BUFFER,Wc,Rc)}if(jd){for(Gc=0;Gc<hd;Gc++)Tc=zd[Gc],za=3*Gc,Xc[za]=Tc.r,Xc[za+1]=Tc.g,Xc[za+2]=Tc.b;j.bindBuffer(j.ARRAY_BUFFER,Gb.__webglColorBuffer);j.bufferData(j.ARRAY_BUFFER,Xc,Rc)}if(kd){for(Hc=0;Hc<id;Hc++)Uc=Ad[Hc],za=3*Hc,Yc[za]=Uc.x,Yc[za+ +1]=Uc.y,Yc[za+2]=Uc.z;j.bindBuffer(j.ARRAY_BUFFER,Gb.__webglNormalBuffer);j.bufferData(j.ARRAY_BUFFER,Yc,Rc)}if(rd){Vc=0;for(xd=rd.length;Vc<xd;Vc++)if(Da=rd[Vc],Da.needsUpdate&&(void 0===Da.boundTo||"vertices"===Da.boundTo)){za=0;zc=Da.value.length;if(1===Da.size)for(ib=0;ib<zc;ib++)Da.array[ib]=Da.value[ib];else if(2===Da.size)for(ib=0;ib<zc;ib++)rb=Da.value[ib],Da.array[za]=rb.x,Da.array[za+1]=rb.y,za+=2;else if(3===Da.size)if("c"===Da.type)for(ib=0;ib<zc;ib++)rb=Da.value[ib],Da.array[za]=rb.r, +Da.array[za+1]=rb.g,Da.array[za+2]=rb.b,za+=3;else for(ib=0;ib<zc;ib++)rb=Da.value[ib],Da.array[za]=rb.x,Da.array[za+1]=rb.y,Da.array[za+2]=rb.z,za+=3;else if(4===Da.size)for(ib=0;ib<zc;ib++)rb=Da.value[ib],Da.array[za]=rb.x,Da.array[za+1]=rb.y,Da.array[za+2]=rb.z,Da.array[za+3]=rb.w,za+=4;j.bindBuffer(j.ARRAY_BUFFER,Da.buffer);j.bufferData(j.ARRAY_BUFFER,Da.array,Rc)}}}O.verticesNeedUpdate=!1;O.colorsNeedUpdate=!1;O.normalsNeedUpdate=!1;ia.attributes&&v(ia)}else if(ta instanceof THREE.Line)if(O instanceof +THREE.BufferGeometry)(O.verticesNeedUpdate||O.colorsNeedUpdate)&&i(O,j.DYNAMIC_DRAW,!O.dynamic),O.verticesNeedUpdate=!1,O.colorsNeedUpdate=!1;else{ia=e(ta,O);qa=ia.attributes&&y(ia);if(O.verticesNeedUpdate||O.colorsNeedUpdate||O.lineDistancesNeedUpdate||qa){var Hb=O,Zc=j.DYNAMIC_DRAW,Ic=void 0,Jc=void 0,Kc=void 0,$c=void 0,Ja=void 0,ad=void 0,Bd=Hb.vertices,Cd=Hb.colors,Dd=Hb.lineDistances,ld=Bd.length,Jd=Cd.length,Kd=Dd.length,bd=Hb.__vertexArray,cd=Hb.__colorArray,Ed=Hb.__lineDistanceArray,Ld=Hb.colorsNeedUpdate, +Md=Hb.lineDistancesNeedUpdate,sd=Hb.__webglCustomAttributesList,dd=void 0,Fd=void 0,jb=void 0,Ac=void 0,sb=void 0,Ea=void 0;if(Hb.verticesNeedUpdate){for(Ic=0;Ic<ld;Ic++)$c=Bd[Ic],Ja=3*Ic,bd[Ja]=$c.x,bd[Ja+1]=$c.y,bd[Ja+2]=$c.z;j.bindBuffer(j.ARRAY_BUFFER,Hb.__webglVertexBuffer);j.bufferData(j.ARRAY_BUFFER,bd,Zc)}if(Ld){for(Jc=0;Jc<Jd;Jc++)ad=Cd[Jc],Ja=3*Jc,cd[Ja]=ad.r,cd[Ja+1]=ad.g,cd[Ja+2]=ad.b;j.bindBuffer(j.ARRAY_BUFFER,Hb.__webglColorBuffer);j.bufferData(j.ARRAY_BUFFER,cd,Zc)}if(Md){for(Kc=0;Kc< +Kd;Kc++)Ed[Kc]=Dd[Kc];j.bindBuffer(j.ARRAY_BUFFER,Hb.__webglLineDistanceBuffer);j.bufferData(j.ARRAY_BUFFER,Ed,Zc)}if(sd){dd=0;for(Fd=sd.length;dd<Fd;dd++)if(Ea=sd[dd],Ea.needsUpdate&&(void 0===Ea.boundTo||"vertices"===Ea.boundTo)){Ja=0;Ac=Ea.value.length;if(1===Ea.size)for(jb=0;jb<Ac;jb++)Ea.array[jb]=Ea.value[jb];else if(2===Ea.size)for(jb=0;jb<Ac;jb++)sb=Ea.value[jb],Ea.array[Ja]=sb.x,Ea.array[Ja+1]=sb.y,Ja+=2;else if(3===Ea.size)if("c"===Ea.type)for(jb=0;jb<Ac;jb++)sb=Ea.value[jb],Ea.array[Ja]= +sb.r,Ea.array[Ja+1]=sb.g,Ea.array[Ja+2]=sb.b,Ja+=3;else for(jb=0;jb<Ac;jb++)sb=Ea.value[jb],Ea.array[Ja]=sb.x,Ea.array[Ja+1]=sb.y,Ea.array[Ja+2]=sb.z,Ja+=3;else if(4===Ea.size)for(jb=0;jb<Ac;jb++)sb=Ea.value[jb],Ea.array[Ja]=sb.x,Ea.array[Ja+1]=sb.y,Ea.array[Ja+2]=sb.z,Ea.array[Ja+3]=sb.w,Ja+=4;j.bindBuffer(j.ARRAY_BUFFER,Ea.buffer);j.bufferData(j.ARRAY_BUFFER,Ea.array,Zc)}}}O.verticesNeedUpdate=!1;O.colorsNeedUpdate=!1;O.lineDistancesNeedUpdate=!1;ia.attributes&&v(ia)}else if(ta instanceof THREE.ParticleSystem)if(O instanceof +THREE.BufferGeometry)(O.verticesNeedUpdate||O.colorsNeedUpdate)&&i(O,j.DYNAMIC_DRAW,!O.dynamic),O.verticesNeedUpdate=!1,O.colorsNeedUpdate=!1;else{ia=e(ta,O);qa=ia.attributes&&y(ia);if(O.verticesNeedUpdate||O.colorsNeedUpdate||ta.sortParticles||qa){var bc=O,td=j.DYNAMIC_DRAW,Lc=ta,tb=void 0,cc=void 0,dc=void 0,ga=void 0,ec=void 0,rc=void 0,ed=bc.vertices,ud=ed.length,vd=bc.colors,Gd=vd.length,wc=bc.__vertexArray,xc=bc.__colorArray,kc=bc.__sortArray,Hd=bc.verticesNeedUpdate,Id=bc.colorsNeedUpdate, +lc=bc.__webglCustomAttributesList,Kb=void 0,Bc=void 0,ma=void 0,Lb=void 0,Ba=void 0,ea=void 0;if(Lc.sortParticles){vb.copy(gc);vb.multiply(Lc.matrixWorld);for(tb=0;tb<ud;tb++)dc=ed[tb],Qa.copy(dc),Qa.applyProjection(vb),kc[tb]=[Qa.z,tb];kc.sort(n);for(tb=0;tb<ud;tb++)dc=ed[kc[tb][1]],ga=3*tb,wc[ga]=dc.x,wc[ga+1]=dc.y,wc[ga+2]=dc.z;for(cc=0;cc<Gd;cc++)ga=3*cc,rc=vd[kc[cc][1]],xc[ga]=rc.r,xc[ga+1]=rc.g,xc[ga+2]=rc.b;if(lc){Kb=0;for(Bc=lc.length;Kb<Bc;Kb++)if(ea=lc[Kb],void 0===ea.boundTo||"vertices"=== +ea.boundTo)if(ga=0,Lb=ea.value.length,1===ea.size)for(ma=0;ma<Lb;ma++)ec=kc[ma][1],ea.array[ma]=ea.value[ec];else if(2===ea.size)for(ma=0;ma<Lb;ma++)ec=kc[ma][1],Ba=ea.value[ec],ea.array[ga]=Ba.x,ea.array[ga+1]=Ba.y,ga+=2;else if(3===ea.size)if("c"===ea.type)for(ma=0;ma<Lb;ma++)ec=kc[ma][1],Ba=ea.value[ec],ea.array[ga]=Ba.r,ea.array[ga+1]=Ba.g,ea.array[ga+2]=Ba.b,ga+=3;else for(ma=0;ma<Lb;ma++)ec=kc[ma][1],Ba=ea.value[ec],ea.array[ga]=Ba.x,ea.array[ga+1]=Ba.y,ea.array[ga+2]=Ba.z,ga+=3;else if(4=== +ea.size)for(ma=0;ma<Lb;ma++)ec=kc[ma][1],Ba=ea.value[ec],ea.array[ga]=Ba.x,ea.array[ga+1]=Ba.y,ea.array[ga+2]=Ba.z,ea.array[ga+3]=Ba.w,ga+=4}}else{if(Hd)for(tb=0;tb<ud;tb++)dc=ed[tb],ga=3*tb,wc[ga]=dc.x,wc[ga+1]=dc.y,wc[ga+2]=dc.z;if(Id)for(cc=0;cc<Gd;cc++)rc=vd[cc],ga=3*cc,xc[ga]=rc.r,xc[ga+1]=rc.g,xc[ga+2]=rc.b;if(lc){Kb=0;for(Bc=lc.length;Kb<Bc;Kb++)if(ea=lc[Kb],ea.needsUpdate&&(void 0===ea.boundTo||"vertices"===ea.boundTo))if(Lb=ea.value.length,ga=0,1===ea.size)for(ma=0;ma<Lb;ma++)ea.array[ma]= +ea.value[ma];else if(2===ea.size)for(ma=0;ma<Lb;ma++)Ba=ea.value[ma],ea.array[ga]=Ba.x,ea.array[ga+1]=Ba.y,ga+=2;else if(3===ea.size)if("c"===ea.type)for(ma=0;ma<Lb;ma++)Ba=ea.value[ma],ea.array[ga]=Ba.r,ea.array[ga+1]=Ba.g,ea.array[ga+2]=Ba.b,ga+=3;else for(ma=0;ma<Lb;ma++)Ba=ea.value[ma],ea.array[ga]=Ba.x,ea.array[ga+1]=Ba.y,ea.array[ga+2]=Ba.z,ga+=3;else if(4===ea.size)for(ma=0;ma<Lb;ma++)Ba=ea.value[ma],ea.array[ga]=Ba.x,ea.array[ga+1]=Ba.y,ea.array[ga+2]=Ba.z,ea.array[ga+3]=Ba.w,ga+=4}}if(Hd|| +Lc.sortParticles)j.bindBuffer(j.ARRAY_BUFFER,bc.__webglVertexBuffer),j.bufferData(j.ARRAY_BUFFER,wc,td);if(Id||Lc.sortParticles)j.bindBuffer(j.ARRAY_BUFFER,bc.__webglColorBuffer),j.bufferData(j.ARRAY_BUFFER,xc,td);if(lc){Kb=0;for(Bc=lc.length;Kb<Bc;Kb++)if(ea=lc[Kb],ea.needsUpdate||Lc.sortParticles)j.bindBuffer(j.ARRAY_BUFFER,ea.buffer),j.bufferData(j.ARRAY_BUFFER,ea.array,td)}}O.verticesNeedUpdate=!1;O.colorsNeedUpdate=!1;ia.attributes&&v(ia)}}};this.initMaterial=function(a,b,c,d){var e,f,g,i;a.addEventListener("dispose", +X);var h,k,m,n,l;a instanceof THREE.MeshDepthMaterial?l="depth":a instanceof THREE.MeshNormalMaterial?l="normal":a instanceof THREE.MeshBasicMaterial?l="basic":a instanceof THREE.MeshLambertMaterial?l="lambert":a instanceof THREE.MeshPhongMaterial?l="phong":a instanceof THREE.LineBasicMaterial?l="basic":a instanceof THREE.LineDashedMaterial?l="dashed":a instanceof THREE.ParticleBasicMaterial&&(l="particle_basic");if(l){var p=THREE.ShaderLib[l];a.uniforms=THREE.UniformsUtils.clone(p.uniforms);a.vertexShader= +p.vertexShader;a.fragmentShader=p.fragmentShader}var q,s,r;e=g=s=r=p=0;for(f=b.length;e<f;e++)q=b[e],q.onlyShadow||(q instanceof THREE.DirectionalLight&&g++,q instanceof THREE.PointLight&&s++,q instanceof THREE.SpotLight&&r++,q instanceof THREE.HemisphereLight&&p++);e=g;f=s;g=r;i=p;p=q=0;for(r=b.length;p<r;p++)s=b[p],s.castShadow&&(s instanceof THREE.SpotLight&&q++,s instanceof THREE.DirectionalLight&&!s.shadowCascade&&q++);n=q;tc&&d&&d.useVertexTexture?m=1024:(b=j.getParameter(j.MAX_VERTEX_UNIFORM_VECTORS), +b=Math.floor((b-20)/4),void 0!==d&&d instanceof THREE.SkinnedMesh&&(b=Math.min(d.bones.length,b),b<d.bones.length&&console.warn("WebGLRenderer: too many bones - "+d.bones.length+", this GPU supports just "+b+" (try OpenGL instead of ANGLE)")),m=b);a:{s=a.fragmentShader;r=a.vertexShader;p=a.uniforms;b=a.attributes;q=a.defines;var c={map:!!a.map,envMap:!!a.envMap,lightMap:!!a.lightMap,bumpMap:!!a.bumpMap,normalMap:!!a.normalMap,specularMap:!!a.specularMap,vertexColors:a.vertexColors,fog:c,useFog:a.fog, +fogExp:c instanceof THREE.FogExp2,sizeAttenuation:a.sizeAttenuation,skinning:a.skinning,maxBones:m,useVertexTexture:tc&&d&&d.useVertexTexture,boneTextureWidth:d&&d.boneTextureWidth,boneTextureHeight:d&&d.boneTextureHeight,morphTargets:a.morphTargets,morphNormals:a.morphNormals,maxMorphTargets:this.maxMorphTargets,maxMorphNormals:this.maxMorphNormals,maxDirLights:e,maxPointLights:f,maxSpotLights:g,maxHemiLights:i,maxShadows:n,shadowMapEnabled:this.shadowMapEnabled&&d.receiveShadow,shadowMapType:this.shadowMapType, +shadowMapDebug:this.shadowMapDebug,shadowMapCascade:this.shadowMapCascade,alphaTest:a.alphaTest,metal:a.metal,perPixel:a.perPixel,wrapAround:a.wrapAround,doubleSided:a.side===THREE.DoubleSide,flipSided:a.side===THREE.BackSide},t,v,y,d=[];l?d.push(l):(d.push(s),d.push(r));for(v in q)d.push(v),d.push(q[v]);for(t in c)d.push(t),d.push(c[t]);l=d.join();t=0;for(v=Ma.length;t<v;t++)if(d=Ma[t],d.code===l){d.usedTimes++;k=d.program;break a}t="SHADOWMAP_TYPE_BASIC";c.shadowMapType===THREE.PCFShadowMap?t="SHADOWMAP_TYPE_PCF": +c.shadowMapType===THREE.PCFSoftShadowMap&&(t="SHADOWMAP_TYPE_PCF_SOFT");v=[];for(y in q)d=q[y],!1!==d&&(d="#define "+y+" "+d,v.push(d));d=v.join("\n");y=j.createProgram();v=["precision "+fa+" float;",d,sc?"#define VERTEX_TEXTURES":"",N.gammaInput?"#define GAMMA_INPUT":"",N.gammaOutput?"#define GAMMA_OUTPUT":"",N.physicallyBasedShading?"#define PHYSICALLY_BASED_SHADING":"","#define MAX_DIR_LIGHTS "+c.maxDirLights,"#define MAX_POINT_LIGHTS "+c.maxPointLights,"#define MAX_SPOT_LIGHTS "+c.maxSpotLights, +"#define MAX_HEMI_LIGHTS "+c.maxHemiLights,"#define MAX_SHADOWS "+c.maxShadows,"#define MAX_BONES "+c.maxBones,c.map?"#define USE_MAP":"",c.envMap?"#define USE_ENVMAP":"",c.lightMap?"#define USE_LIGHTMAP":"",c.bumpMap?"#define USE_BUMPMAP":"",c.normalMap?"#define USE_NORMALMAP":"",c.specularMap?"#define USE_SPECULARMAP":"",c.vertexColors?"#define USE_COLOR":"",c.skinning?"#define USE_SKINNING":"",c.useVertexTexture?"#define BONE_TEXTURE":"",c.boneTextureWidth?"#define N_BONE_PIXEL_X "+c.boneTextureWidth.toFixed(1): +"",c.boneTextureHeight?"#define N_BONE_PIXEL_Y "+c.boneTextureHeight.toFixed(1):"",c.morphTargets?"#define USE_MORPHTARGETS":"",c.morphNormals?"#define USE_MORPHNORMALS":"",c.perPixel?"#define PHONG_PER_PIXEL":"",c.wrapAround?"#define WRAP_AROUND":"",c.doubleSided?"#define DOUBLE_SIDED":"",c.flipSided?"#define FLIP_SIDED":"",c.shadowMapEnabled?"#define USE_SHADOWMAP":"",c.shadowMapEnabled?"#define "+t:"",c.shadowMapDebug?"#define SHADOWMAP_DEBUG":"",c.shadowMapCascade?"#define SHADOWMAP_CASCADE": +"",c.sizeAttenuation?"#define USE_SIZEATTENUATION":"","uniform mat4 modelMatrix;\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\nuniform mat4 viewMatrix;\nuniform mat3 normalMatrix;\nuniform vec3 cameraPosition;\nattribute vec3 position;\nattribute vec3 normal;\nattribute vec2 uv;\nattribute vec2 uv2;\n#ifdef USE_COLOR\nattribute vec3 color;\n#endif\n#ifdef USE_MORPHTARGETS\nattribute vec3 morphTarget0;\nattribute vec3 morphTarget1;\nattribute vec3 morphTarget2;\nattribute vec3 morphTarget3;\n#ifdef USE_MORPHNORMALS\nattribute vec3 morphNormal0;\nattribute vec3 morphNormal1;\nattribute vec3 morphNormal2;\nattribute vec3 morphNormal3;\n#else\nattribute vec3 morphTarget4;\nattribute vec3 morphTarget5;\nattribute vec3 morphTarget6;\nattribute vec3 morphTarget7;\n#endif\n#endif\n#ifdef USE_SKINNING\nattribute vec4 skinIndex;\nattribute vec4 skinWeight;\n#endif\n"].join("\n"); +t=["precision "+fa+" float;",c.bumpMap||c.normalMap?"#extension GL_OES_standard_derivatives : enable":"",d,"#define MAX_DIR_LIGHTS "+c.maxDirLights,"#define MAX_POINT_LIGHTS "+c.maxPointLights,"#define MAX_SPOT_LIGHTS "+c.maxSpotLights,"#define MAX_HEMI_LIGHTS "+c.maxHemiLights,"#define MAX_SHADOWS "+c.maxShadows,c.alphaTest?"#define ALPHATEST "+c.alphaTest:"",N.gammaInput?"#define GAMMA_INPUT":"",N.gammaOutput?"#define GAMMA_OUTPUT":"",N.physicallyBasedShading?"#define PHYSICALLY_BASED_SHADING": +"",c.useFog&&c.fog?"#define USE_FOG":"",c.useFog&&c.fogExp?"#define FOG_EXP2":"",c.map?"#define USE_MAP":"",c.envMap?"#define USE_ENVMAP":"",c.lightMap?"#define USE_LIGHTMAP":"",c.bumpMap?"#define USE_BUMPMAP":"",c.normalMap?"#define USE_NORMALMAP":"",c.specularMap?"#define USE_SPECULARMAP":"",c.vertexColors?"#define USE_COLOR":"",c.metal?"#define METAL":"",c.perPixel?"#define PHONG_PER_PIXEL":"",c.wrapAround?"#define WRAP_AROUND":"",c.doubleSided?"#define DOUBLE_SIDED":"",c.flipSided?"#define FLIP_SIDED": +"",c.shadowMapEnabled?"#define USE_SHADOWMAP":"",c.shadowMapEnabled?"#define "+t:"",c.shadowMapDebug?"#define SHADOWMAP_DEBUG":"",c.shadowMapCascade?"#define SHADOWMAP_CASCADE":"","uniform mat4 viewMatrix;\nuniform vec3 cameraPosition;\n"].join("\n");t=B("fragment",t+s);v=B("vertex",v+r);j.attachShader(y,v);j.attachShader(y,t);j.linkProgram(y);j.getProgramParameter(y,j.LINK_STATUS)||console.error("Could not initialise shader\nVALIDATE_STATUS: "+j.getProgramParameter(y,j.VALIDATE_STATUS)+", gl error ["+ +j.getError()+"]");j.deleteShader(t);j.deleteShader(v);y.uniforms={};y.attributes={};var x;t="viewMatrix modelViewMatrix projectionMatrix normalMatrix modelMatrix cameraPosition morphTargetInfluences".split(" ");c.useVertexTexture?t.push("boneTexture"):t.push("boneGlobalMatrices");for(x in p)t.push(x);x=t;t=0;for(v=x.length;t<v;t++)p=x[t],y.uniforms[p]=j.getUniformLocation(y,p);t="position normal uv uv2 tangent color skinIndex skinWeight lineDistance".split(" ");for(x=0;x<c.maxMorphTargets;x++)t.push("morphTarget"+ +x);for(x=0;x<c.maxMorphNormals;x++)t.push("morphNormal"+x);for(k in b)t.push(k);k=t;x=0;for(b=k.length;x<b;x++)t=k[x],y.attributes[t]=j.getAttribLocation(y,t);y.id=Na++;Ma.push({program:y,code:l,usedTimes:1});N.info.memory.programs=Ma.length;k=y}a.program=k;x=a.program.attributes;if(a.morphTargets){a.numSupportedMorphTargets=0;b="morphTarget";for(k=0;k<this.maxMorphTargets;k++)y=b+k,0<=x[y]&&a.numSupportedMorphTargets++}if(a.morphNormals){a.numSupportedMorphNormals=0;b="morphNormal";for(k=0;k<this.maxMorphNormals;k++)y= +b+k,0<=x[y]&&a.numSupportedMorphNormals++}a.uniformsList=[];for(h in a.uniforms)a.uniformsList.push([a.uniforms[h],h])};this.setFaceCulling=function(a,b){a===THREE.CullFaceNone?j.disable(j.CULL_FACE):(b===THREE.FrontFaceDirectionCW?j.frontFace(j.CW):j.frontFace(j.CCW),a===THREE.CullFaceBack?j.cullFace(j.BACK):a===THREE.CullFaceFront?j.cullFace(j.FRONT):j.cullFace(j.FRONT_AND_BACK),j.enable(j.CULL_FACE))};this.setMaterialFaces=function(a){var b=a.side===THREE.DoubleSide,a=a.side===THREE.BackSide;da!== +b&&(b?j.disable(j.CULL_FACE):j.enable(j.CULL_FACE),da=b);la!==a&&(a?j.frontFace(j.CW):j.frontFace(j.CCW),la=a)};this.setDepthTest=function(a){ia!==a&&(a?j.enable(j.DEPTH_TEST):j.disable(j.DEPTH_TEST),ia=a)};this.setDepthWrite=function(a){Wa!==a&&(j.depthMask(a),Wa=a)};this.setBlending=function(a,b,c,d){a!==Z&&(a===THREE.NoBlending?j.disable(j.BLEND):a===THREE.AdditiveBlending?(j.enable(j.BLEND),j.blendEquation(j.FUNC_ADD),j.blendFunc(j.SRC_ALPHA,j.ONE)):a===THREE.SubtractiveBlending?(j.enable(j.BLEND), +j.blendEquation(j.FUNC_ADD),j.blendFunc(j.ZERO,j.ONE_MINUS_SRC_COLOR)):a===THREE.MultiplyBlending?(j.enable(j.BLEND),j.blendEquation(j.FUNC_ADD),j.blendFunc(j.ZERO,j.SRC_COLOR)):a===THREE.CustomBlending?j.enable(j.BLEND):(j.enable(j.BLEND),j.blendEquationSeparate(j.FUNC_ADD,j.FUNC_ADD),j.blendFuncSeparate(j.SRC_ALPHA,j.ONE_MINUS_SRC_ALPHA,j.ONE,j.ONE_MINUS_SRC_ALPHA)),Z=a);if(a===THREE.CustomBlending){if(b!==oa&&(j.blendEquation(L(b)),oa=b),c!==gb||d!==nb)j.blendFunc(L(c),L(d)),gb=c,nb=d}else nb= +gb=oa=null};this.setTexture=function(a,b){if(a.needsUpdate){a.__webglInit||(a.__webglInit=!0,a.addEventListener("dispose",Oc),a.__webglTexture=j.createTexture(),N.info.memory.textures++);j.activeTexture(j.TEXTURE0+b);j.bindTexture(j.TEXTURE_2D,a.__webglTexture);j.pixelStorei(j.UNPACK_FLIP_Y_WEBGL,a.flipY);j.pixelStorei(j.UNPACK_PREMULTIPLY_ALPHA_WEBGL,a.premultiplyAlpha);j.pixelStorei(j.UNPACK_ALIGNMENT,a.unpackAlignment);var c=a.image,d=0===(c.width&c.width-1)&&0===(c.height&c.height-1),e=L(a.format), +f=L(a.type);W(j.TEXTURE_2D,a,d);var g=a.mipmaps;if(a instanceof THREE.DataTexture)if(0<g.length&&d){for(var i=0,h=g.length;i<h;i++)c=g[i],j.texImage2D(j.TEXTURE_2D,i,e,c.width,c.height,0,e,f,c.data);a.generateMipmaps=!1}else j.texImage2D(j.TEXTURE_2D,0,e,c.width,c.height,0,e,f,c.data);else if(a instanceof THREE.CompressedTexture){i=0;for(h=g.length;i<h;i++)c=g[i],j.compressedTexImage2D(j.TEXTURE_2D,i,e,c.width,c.height,0,c.data)}else if(0<g.length&&d){i=0;for(h=g.length;i<h;i++)c=g[i],j.texImage2D(j.TEXTURE_2D, +i,e,e,f,c);a.generateMipmaps=!1}else j.texImage2D(j.TEXTURE_2D,0,e,e,f,a.image);a.generateMipmaps&&d&&j.generateMipmap(j.TEXTURE_2D);a.needsUpdate=!1;if(a.onUpdate)a.onUpdate()}else j.activeTexture(j.TEXTURE0+b),j.bindTexture(j.TEXTURE_2D,a.__webglTexture)};this.setRenderTarget=function(a){var b=a instanceof THREE.WebGLRenderTargetCube;if(a&&!a.__webglFramebuffer){void 0===a.depthBuffer&&(a.depthBuffer=!0);void 0===a.stencilBuffer&&(a.stencilBuffer=!0);a.addEventListener("dispose",P);a.__webglTexture= +j.createTexture();N.info.memory.textures++;var c=0===(a.width&a.width-1)&&0===(a.height&a.height-1),d=L(a.format),e=L(a.type);if(b){a.__webglFramebuffer=[];a.__webglRenderbuffer=[];j.bindTexture(j.TEXTURE_CUBE_MAP,a.__webglTexture);W(j.TEXTURE_CUBE_MAP,a,c);for(var f=0;6>f;f++){a.__webglFramebuffer[f]=j.createFramebuffer();a.__webglRenderbuffer[f]=j.createRenderbuffer();j.texImage2D(j.TEXTURE_CUBE_MAP_POSITIVE_X+f,0,d,a.width,a.height,0,d,e,null);var g=a,i=j.TEXTURE_CUBE_MAP_POSITIVE_X+f;j.bindFramebuffer(j.FRAMEBUFFER, +a.__webglFramebuffer[f]);j.framebufferTexture2D(j.FRAMEBUFFER,j.COLOR_ATTACHMENT0,i,g.__webglTexture,0);F(a.__webglRenderbuffer[f],a)}c&&j.generateMipmap(j.TEXTURE_CUBE_MAP)}else a.__webglFramebuffer=j.createFramebuffer(),a.__webglRenderbuffer=a.shareDepthFrom?a.shareDepthFrom.__webglRenderbuffer:j.createRenderbuffer(),j.bindTexture(j.TEXTURE_2D,a.__webglTexture),W(j.TEXTURE_2D,a,c),j.texImage2D(j.TEXTURE_2D,0,d,a.width,a.height,0,d,e,null),d=j.TEXTURE_2D,j.bindFramebuffer(j.FRAMEBUFFER,a.__webglFramebuffer), +j.framebufferTexture2D(j.FRAMEBUFFER,j.COLOR_ATTACHMENT0,d,a.__webglTexture,0),a.shareDepthFrom?a.depthBuffer&&!a.stencilBuffer?j.framebufferRenderbuffer(j.FRAMEBUFFER,j.DEPTH_ATTACHMENT,j.RENDERBUFFER,a.__webglRenderbuffer):a.depthBuffer&&a.stencilBuffer&&j.framebufferRenderbuffer(j.FRAMEBUFFER,j.DEPTH_STENCIL_ATTACHMENT,j.RENDERBUFFER,a.__webglRenderbuffer):F(a.__webglRenderbuffer,a),c&&j.generateMipmap(j.TEXTURE_2D);b?j.bindTexture(j.TEXTURE_CUBE_MAP,null):j.bindTexture(j.TEXTURE_2D,null);j.bindRenderbuffer(j.RENDERBUFFER, +null);j.bindFramebuffer(j.FRAMEBUFFER,null)}a?(b=b?a.__webglFramebuffer[a.activeCubeFace]:a.__webglFramebuffer,c=a.width,a=a.height,e=d=0):(b=null,c=fc,a=Ab,d=Ib,e=Jb);b!==Pa&&(j.bindFramebuffer(j.FRAMEBUFFER,b),j.viewport(d,e,c,a),Pa=b);mc=c;pb=a};this.shadowMapPlugin=new THREE.ShadowMapPlugin;this.addPrePlugin(this.shadowMapPlugin);this.addPostPlugin(new THREE.SpritePlugin);this.addPostPlugin(new THREE.LensFlarePlugin)};THREE.WebGLRenderTarget=function(a,b,c){THREE.EventDispatcher.call(this);this.width=a;this.height=b;c=c||{};this.wrapS=void 0!==c.wrapS?c.wrapS:THREE.ClampToEdgeWrapping;this.wrapT=void 0!==c.wrapT?c.wrapT:THREE.ClampToEdgeWrapping;this.magFilter=void 0!==c.magFilter?c.magFilter:THREE.LinearFilter;this.minFilter=void 0!==c.minFilter?c.minFilter:THREE.LinearMipMapLinearFilter;this.anisotropy=void 0!==c.anisotropy?c.anisotropy:1;this.offset=new THREE.Vector2(0,0);this.repeat=new THREE.Vector2(1,1); +this.format=void 0!==c.format?c.format:THREE.RGBAFormat;this.type=void 0!==c.type?c.type:THREE.UnsignedByteType;this.depthBuffer=void 0!==c.depthBuffer?c.depthBuffer:!0;this.stencilBuffer=void 0!==c.stencilBuffer?c.stencilBuffer:!0;this.generateMipmaps=!0;this.shareDepthFrom=null}; +THREE.WebGLRenderTarget.prototype.clone=function(){var a=new THREE.WebGLRenderTarget(this.width,this.height);a.wrapS=this.wrapS;a.wrapT=this.wrapT;a.magFilter=this.magFilter;a.minFilter=this.minFilter;a.anisotropy=this.anisotropy;a.offset.copy(this.offset);a.repeat.copy(this.repeat);a.format=this.format;a.type=this.type;a.depthBuffer=this.depthBuffer;a.stencilBuffer=this.stencilBuffer;a.generateMipmaps=this.generateMipmaps;a.shareDepthFrom=this.shareDepthFrom;return a}; +THREE.WebGLRenderTarget.prototype.dispose=function(){this.dispatchEvent({type:"dispose"})};THREE.WebGLRenderTargetCube=function(a,b,c){THREE.WebGLRenderTarget.call(this,a,b,c);this.activeCubeFace=0};THREE.WebGLRenderTargetCube.prototype=Object.create(THREE.WebGLRenderTarget.prototype);THREE.RenderableVertex=function(){this.positionWorld=new THREE.Vector3;this.positionScreen=new THREE.Vector4;this.visible=!0};THREE.RenderableVertex.prototype.copy=function(a){this.positionWorld.copy(a.positionWorld);this.positionScreen.copy(a.positionScreen)};THREE.RenderableFace3=function(){this.v1=new THREE.RenderableVertex;this.v2=new THREE.RenderableVertex;this.v3=new THREE.RenderableVertex;this.centroidModel=new THREE.Vector3;this.normalModel=new THREE.Vector3;this.normalModelView=new THREE.Vector3;this.vertexNormalsLength=0;this.vertexNormalsModel=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3];this.vertexNormalsModelView=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3];this.material=this.color=null;this.uvs=[[]];this.z=null};THREE.RenderableFace4=function(){this.v1=new THREE.RenderableVertex;this.v2=new THREE.RenderableVertex;this.v3=new THREE.RenderableVertex;this.v4=new THREE.RenderableVertex;this.centroidModel=new THREE.Vector3;this.normalModel=new THREE.Vector3;this.normalModelView=new THREE.Vector3;this.vertexNormalsLength=0;this.vertexNormalsModel=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3];this.vertexNormalsModelView=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3]; +this.material=this.color=null;this.uvs=[[]];this.z=null};THREE.RenderableObject=function(){this.z=this.object=null};THREE.RenderableParticle=function(){this.rotation=this.z=this.y=this.x=this.object=null;this.scale=new THREE.Vector2;this.material=null};THREE.RenderableLine=function(){this.z=null;this.v1=new THREE.RenderableVertex;this.v2=new THREE.RenderableVertex;this.material=null};THREE.GeometryUtils={merge:function(a,b){var c,d,e=a.vertices.length,f=b instanceof THREE.Mesh?b.geometry:b,g=a.vertices,h=f.vertices,i=a.faces,k=f.faces,l=a.faceVertexUvs[0],f=f.faceVertexUvs[0];b instanceof THREE.Mesh&&(b.matrixAutoUpdate&&b.updateMatrix(),c=b.matrix,d=new THREE.Matrix3,d.getInverse(c),d.transpose());for(var m=0,n=h.length;m<n;m++){var s=h[m].clone();c&&s.applyMatrix4(c);g.push(s)}m=0;for(n=k.length;m<n;m++){var s=k[m],r,p,q=s.vertexNormals,y=s.vertexColors;s instanceof THREE.Face3? +r=new THREE.Face3(s.a+e,s.b+e,s.c+e):s instanceof THREE.Face4&&(r=new THREE.Face4(s.a+e,s.b+e,s.c+e,s.d+e));r.normal.copy(s.normal);d&&r.normal.applyMatrix3(d).normalize();g=0;for(h=q.length;g<h;g++)p=q[g].clone(),d&&p.applyMatrix3(d).normalize(),r.vertexNormals.push(p);r.color.copy(s.color);g=0;for(h=y.length;g<h;g++)p=y[g],r.vertexColors.push(p.clone());r.materialIndex=s.materialIndex;r.centroid.copy(s.centroid);c&&r.centroid.applyMatrix4(c);i.push(r)}m=0;for(n=f.length;m<n;m++){c=f[m];d=[];g=0; +for(h=c.length;g<h;g++)d.push(new THREE.Vector2(c[g].x,c[g].y));l.push(d)}},removeMaterials:function(a,b){for(var c={},d=0,e=b.length;d<e;d++)c[b[d]]=!0;for(var f,g=[],d=0,e=a.faces.length;d<e;d++)f=a.faces[d],f.materialIndex in c||g.push(f);a.faces=g},randomPointInTriangle:function(a,b,c){var d,e,f,g=new THREE.Vector3,h=THREE.GeometryUtils.__v1;d=THREE.GeometryUtils.random();e=THREE.GeometryUtils.random();1<d+e&&(d=1-d,e=1-e);f=1-d-e;g.copy(a);g.multiplyScalar(d);h.copy(b);h.multiplyScalar(e);g.add(h); +h.copy(c);h.multiplyScalar(f);g.add(h);return g},randomPointInFace:function(a,b,c){var d,e,f;if(a instanceof THREE.Face3)return d=b.vertices[a.a],e=b.vertices[a.b],f=b.vertices[a.c],THREE.GeometryUtils.randomPointInTriangle(d,e,f);if(a instanceof THREE.Face4){d=b.vertices[a.a];e=b.vertices[a.b];f=b.vertices[a.c];var b=b.vertices[a.d],g;c?a._area1&&a._area2?(c=a._area1,g=a._area2):(c=THREE.GeometryUtils.triangleArea(d,e,b),g=THREE.GeometryUtils.triangleArea(e,f,b),a._area1=c,a._area2=g):(c=THREE.GeometryUtils.triangleArea(d, +e,b),g=THREE.GeometryUtils.triangleArea(e,f,b));return THREE.GeometryUtils.random()*(c+g)<c?THREE.GeometryUtils.randomPointInTriangle(d,e,b):THREE.GeometryUtils.randomPointInTriangle(e,f,b)}},randomPointsInGeometry:function(a,b){function c(a){function b(c,d){if(d<c)return c;var e=c+Math.floor((d-c)/2);return k[e]>a?b(c,e-1):k[e]<a?b(e+1,d):e}return b(0,k.length-1)}var d,e,f=a.faces,g=a.vertices,h=f.length,i=0,k=[],l,m,n,s;for(e=0;e<h;e++)d=f[e],d instanceof THREE.Face3?(l=g[d.a],m=g[d.b],n=g[d.c], +d._area=THREE.GeometryUtils.triangleArea(l,m,n)):d instanceof THREE.Face4&&(l=g[d.a],m=g[d.b],n=g[d.c],s=g[d.d],d._area1=THREE.GeometryUtils.triangleArea(l,m,s),d._area2=THREE.GeometryUtils.triangleArea(m,n,s),d._area=d._area1+d._area2),i+=d._area,k[e]=i;d=[];for(e=0;e<b;e++)g=THREE.GeometryUtils.random()*i,g=c(g),d[e]=THREE.GeometryUtils.randomPointInFace(f[g],a,!0);return d},triangleArea:function(a,b,c){var d=THREE.GeometryUtils.__v1,e=THREE.GeometryUtils.__v2;d.subVectors(b,a);e.subVectors(c,a); +d.cross(e);return 0.5*d.length()},center:function(a){a.computeBoundingBox();var b=a.boundingBox,c=new THREE.Vector3;c.addVectors(b.min,b.max);c.multiplyScalar(-0.5);a.applyMatrix((new THREE.Matrix4).makeTranslation(c.x,c.y,c.z));a.computeBoundingBox();return c},normalizeUVs:function(a){for(var a=a.faceVertexUvs[0],b=0,c=a.length;b<c;b++)for(var d=a[b],e=0,f=d.length;e<f;e++)1!==d[e].x&&(d[e].x-=Math.floor(d[e].x)),1!==d[e].y&&(d[e].y-=Math.floor(d[e].y))},triangulateQuads:function(a){var b,c,d,e, +f=[],g=[],h=[];b=0;for(c=a.faceUvs.length;b<c;b++)g[b]=[];b=0;for(c=a.faceVertexUvs.length;b<c;b++)h[b]=[];b=0;for(c=a.faces.length;b<c;b++)if(d=a.faces[b],d instanceof THREE.Face4){e=d.a;var i=d.b,k=d.c,l=d.d,m=new THREE.Face3,n=new THREE.Face3;m.color.copy(d.color);n.color.copy(d.color);m.materialIndex=d.materialIndex;n.materialIndex=d.materialIndex;m.a=e;m.b=i;m.c=l;n.a=i;n.b=k;n.c=l;4===d.vertexColors.length&&(m.vertexColors[0]=d.vertexColors[0].clone(),m.vertexColors[1]=d.vertexColors[1].clone(), +m.vertexColors[2]=d.vertexColors[3].clone(),n.vertexColors[0]=d.vertexColors[1].clone(),n.vertexColors[1]=d.vertexColors[2].clone(),n.vertexColors[2]=d.vertexColors[3].clone());f.push(m,n);d=0;for(e=a.faceVertexUvs.length;d<e;d++)a.faceVertexUvs[d].length&&(m=a.faceVertexUvs[d][b],i=m[1],k=m[2],l=m[3],m=[m[0].clone(),i.clone(),l.clone()],i=[i.clone(),k.clone(),l.clone()],h[d].push(m,i));d=0;for(e=a.faceUvs.length;d<e;d++)a.faceUvs[d].length&&(i=a.faceUvs[d][b],g[d].push(i,i))}else{f.push(d);d=0;for(e= +a.faceUvs.length;d<e;d++)g[d].push(a.faceUvs[d][b]);d=0;for(e=a.faceVertexUvs.length;d<e;d++)h[d].push(a.faceVertexUvs[d][b])}a.faces=f;a.faceUvs=g;a.faceVertexUvs=h;a.computeCentroids();a.computeFaceNormals();a.computeVertexNormals();a.hasTangents&&a.computeTangents()},setMaterialIndex:function(a,b,c,d){a=a.faces;d=d||a.length-1;for(c=c||0;c<=d;c++)a[c].materialIndex=b}};THREE.GeometryUtils.random=THREE.Math.random16;THREE.GeometryUtils.__v1=new THREE.Vector3;THREE.GeometryUtils.__v2=new THREE.Vector3;THREE.ImageUtils={crossOrigin:"anonymous",loadTexture:function(a,b,c,d){var e=new Image,f=new THREE.Texture(e,b),b=new THREE.ImageLoader;b.addEventListener("load",function(a){f.image=a.content;f.needsUpdate=!0;c&&c(f)});b.addEventListener("error",function(a){d&&d(a.message)});b.crossOrigin=this.crossOrigin;b.load(a,e);f.sourceFile=a;return f},loadCompressedTexture:function(a,b,c,d){var e=new THREE.CompressedTexture;e.mapping=b;var f=new XMLHttpRequest;f.onload=function(){var a=THREE.ImageUtils.parseDDS(f.response, +!0);e.format=a.format;e.mipmaps=a.mipmaps;e.image.width=a.width;e.image.height=a.height;e.generateMipmaps=!1;e.needsUpdate=!0;c&&c(e)};f.onerror=d;f.open("GET",a,!0);f.responseType="arraybuffer";f.send(null);return e},loadTextureCube:function(a,b,c,d){var e=[];e.loadCount=0;var f=new THREE.Texture;f.image=e;void 0!==b&&(f.mapping=b);f.flipY=!1;for(var b=0,g=a.length;b<g;++b){var h=new Image;e[b]=h;h.onload=function(){e.loadCount+=1;6===e.loadCount&&(f.needsUpdate=!0,c&&c(f))};h.onerror=d;h.crossOrigin= +this.crossOrigin;h.src=a[b]}return f},loadCompressedTextureCube:function(a,b,c,d){var e=[];e.loadCount=0;var f=new THREE.CompressedTexture;f.image=e;void 0!==b&&(f.mapping=b);f.flipY=!1;f.generateMipmaps=!1;b=function(a,b){return function(){var d=THREE.ImageUtils.parseDDS(a.response,!0);b.format=d.format;b.mipmaps=d.mipmaps;b.width=d.width;b.height=d.height;e.loadCount+=1;6===e.loadCount&&(f.format=d.format,f.needsUpdate=!0,c&&c(f))}};if(a instanceof Array)for(var g=0,h=a.length;g<h;++g){var i={}; +e[g]=i;var k=new XMLHttpRequest;k.onload=b(k,i);k.onerror=d;i=a[g];k.open("GET",i,!0);k.responseType="arraybuffer";k.send(null)}else k=new XMLHttpRequest,k.onload=function(){var a=THREE.ImageUtils.parseDDS(k.response,!0);if(a.isCubemap){for(var b=a.mipmaps.length/a.mipmapCount,d=0;d<b;d++){e[d]={mipmaps:[]};for(var g=0;g<a.mipmapCount;g++)e[d].mipmaps.push(a.mipmaps[d*a.mipmapCount+g]),e[d].format=a.format,e[d].width=a.width,e[d].height=a.height}f.format=a.format;f.needsUpdate=!0;c&&c(f)}},k.onerror= +d,k.open("GET",a,!0),k.responseType="arraybuffer",k.send(null);return f},parseDDS:function(a,b){function c(a){return a.charCodeAt(0)+(a.charCodeAt(1)<<8)+(a.charCodeAt(2)<<16)+(a.charCodeAt(3)<<24)}var d={mipmaps:[],width:0,height:0,format:null,mipmapCount:1},e=c("DXT1"),f=c("DXT3"),g=c("DXT5"),h=new Int32Array(a,0,31);if(542327876!==h[0])return console.error("ImageUtils.parseDDS(): Invalid magic number in DDS header"),d;if(!h[20]&4)return console.error("ImageUtils.parseDDS(): Unsupported format, must contain a FourCC code"), +d;var i=h[21];switch(i){case e:e=8;d.format=THREE.RGB_S3TC_DXT1_Format;break;case f:e=16;d.format=THREE.RGBA_S3TC_DXT3_Format;break;case g:e=16;d.format=THREE.RGBA_S3TC_DXT5_Format;break;default:return console.error("ImageUtils.parseDDS(): Unsupported FourCC code: ",String.fromCharCode(i&255,i>>8&255,i>>16&255,i>>24&255)),d}d.mipmapCount=1;h[2]&131072&&!1!==b&&(d.mipmapCount=Math.max(1,h[7]));d.isCubemap=h[28]&512?!0:!1;d.width=h[4];d.height=h[3];for(var h=h[1]+4,f=d.width,g=d.height,i=d.isCubemap? +6:1,k=0;k<i;k++){for(var l=0;l<d.mipmapCount;l++){var m=Math.max(4,f)/4*Math.max(4,g)/4*e,n={data:new Uint8Array(a,h,m),width:f,height:g};d.mipmaps.push(n);h+=m;f=Math.max(0.5*f,1);g=Math.max(0.5*g,1)}f=d.width;g=d.height}return d},getNormalMap:function(a,b){var c=function(a){var b=Math.sqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2]);return[a[0]/b,a[1]/b,a[2]/b]},b=b|1,d=a.width,e=a.height,f=document.createElement("canvas");f.width=d;f.height=e;var g=f.getContext("2d");g.drawImage(a,0,0);for(var h=g.getImageData(0, +0,d,e).data,i=g.createImageData(d,e),k=i.data,l=0;l<d;l++)for(var m=0;m<e;m++){var n=0>m-1?0:m-1,s=m+1>e-1?e-1:m+1,r=0>l-1?0:l-1,p=l+1>d-1?d-1:l+1,q=[],y=[0,0,h[4*(m*d+l)]/255*b];q.push([-1,0,h[4*(m*d+r)]/255*b]);q.push([-1,-1,h[4*(n*d+r)]/255*b]);q.push([0,-1,h[4*(n*d+l)]/255*b]);q.push([1,-1,h[4*(n*d+p)]/255*b]);q.push([1,0,h[4*(m*d+p)]/255*b]);q.push([1,1,h[4*(s*d+p)]/255*b]);q.push([0,1,h[4*(s*d+l)]/255*b]);q.push([-1,1,h[4*(s*d+r)]/255*b]);n=[];r=q.length;for(s=0;s<r;s++){var p=q[s],v=q[(s+1)% +r],p=[p[0]-y[0],p[1]-y[1],p[2]-y[2]],v=[v[0]-y[0],v[1]-y[1],v[2]-y[2]];n.push(c([p[1]*v[2]-p[2]*v[1],p[2]*v[0]-p[0]*v[2],p[0]*v[1]-p[1]*v[0]]))}q=[0,0,0];for(s=0;s<n.length;s++)q[0]+=n[s][0],q[1]+=n[s][1],q[2]+=n[s][2];q[0]/=n.length;q[1]/=n.length;q[2]/=n.length;y=4*(m*d+l);k[y]=255*((q[0]+1)/2)|0;k[y+1]=255*((q[1]+1)/2)|0;k[y+2]=255*q[2]|0;k[y+3]=255}g.putImageData(i,0,0);return f},generateDataTexture:function(a,b,c){for(var d=a*b,e=new Uint8Array(3*d),f=Math.floor(255*c.r),g=Math.floor(255*c.g), +c=Math.floor(255*c.b),h=0;h<d;h++)e[3*h]=f,e[3*h+1]=g,e[3*h+2]=c;a=new THREE.DataTexture(e,a,b,THREE.RGBFormat);a.needsUpdate=!0;return a}};THREE.SceneUtils={createMultiMaterialObject:function(a,b){for(var c=new THREE.Object3D,d=0,e=b.length;d<e;d++)c.add(new THREE.Mesh(a,b[d]));return c},detach:function(a,b,c){a.applyMatrix(b.matrixWorld);b.remove(a);c.add(a)},attach:function(a,b,c){var d=new THREE.Matrix4;d.getInverse(c.matrixWorld);a.applyMatrix(d);b.remove(a);c.add(a)}};THREE.FontUtils={faces:{},face:"helvetiker",weight:"normal",style:"normal",size:150,divisions:10,getFace:function(){return this.faces[this.face][this.weight][this.style]},loadFace:function(a){var b=a.familyName.toLowerCase();this.faces[b]=this.faces[b]||{};this.faces[b][a.cssFontWeight]=this.faces[b][a.cssFontWeight]||{};this.faces[b][a.cssFontWeight][a.cssFontStyle]=a;return this.faces[b][a.cssFontWeight][a.cssFontStyle]=a},drawText:function(a){for(var b=this.getFace(),c=this.size/b.resolution,d= +0,e=String(a).split(""),f=e.length,g=[],a=0;a<f;a++){var h=new THREE.Path,h=this.extractGlyphPoints(e[a],b,c,d,h),d=d+h.offset;g.push(h.path)}return{paths:g,offset:d/2}},extractGlyphPoints:function(a,b,c,d,e){var f=[],g,h,i,k,l,m,n,s,r,p,q,y=b.glyphs[a]||b.glyphs["?"];if(y){if(y.o){b=y._cachedOutline||(y._cachedOutline=y.o.split(" "));k=b.length;for(a=0;a<k;)switch(i=b[a++],i){case "m":i=b[a++]*c+d;l=b[a++]*c;e.moveTo(i,l);break;case "l":i=b[a++]*c+d;l=b[a++]*c;e.lineTo(i,l);break;case "q":i=b[a++]* +c+d;l=b[a++]*c;s=b[a++]*c+d;r=b[a++]*c;e.quadraticCurveTo(s,r,i,l);if(g=f[f.length-1]){m=g.x;n=g.y;g=1;for(h=this.divisions;g<=h;g++){var v=g/h;THREE.Shape.Utils.b2(v,m,s,i);THREE.Shape.Utils.b2(v,n,r,l)}}break;case "b":if(i=b[a++]*c+d,l=b[a++]*c,s=b[a++]*c+d,r=b[a++]*-c,p=b[a++]*c+d,q=b[a++]*-c,e.bezierCurveTo(i,l,s,r,p,q),g=f[f.length-1]){m=g.x;n=g.y;g=1;for(h=this.divisions;g<=h;g++)v=g/h,THREE.Shape.Utils.b3(v,m,s,p,i),THREE.Shape.Utils.b3(v,n,r,q,l)}}}return{offset:y.ha*c,path:e}}}}; +THREE.FontUtils.generateShapes=function(a,b){var b=b||{},c=void 0!==b.curveSegments?b.curveSegments:4,d=void 0!==b.font?b.font:"helvetiker",e=void 0!==b.weight?b.weight:"normal",f=void 0!==b.style?b.style:"normal";THREE.FontUtils.size=void 0!==b.size?b.size:100;THREE.FontUtils.divisions=c;THREE.FontUtils.face=d;THREE.FontUtils.weight=e;THREE.FontUtils.style=f;c=THREE.FontUtils.drawText(a).paths;d=[];e=0;for(f=c.length;e<f;e++)Array.prototype.push.apply(d,c[e].toShapes());return d}; +(function(a){var b=function(a){for(var b=a.length,e=0,f=b-1,g=0;g<b;f=g++)e+=a[f].x*a[g].y-a[g].x*a[f].y;return 0.5*e};a.Triangulate=function(a,d){var e=a.length;if(3>e)return null;var f=[],g=[],h=[],i,k,l;if(0<b(a))for(k=0;k<e;k++)g[k]=k;else for(k=0;k<e;k++)g[k]=e-1-k;var m=2*e;for(k=e-1;2<e;){if(0>=m--){console.log("Warning, unable to triangulate polygon!");break}i=k;e<=i&&(i=0);k=i+1;e<=k&&(k=0);l=k+1;e<=l&&(l=0);var n;a:{var s=n=void 0,r=void 0,p=void 0,q=void 0,y=void 0,v=void 0,z=void 0,t= +void 0,s=a[g[i]].x,r=a[g[i]].y,p=a[g[k]].x,q=a[g[k]].y,y=a[g[l]].x,v=a[g[l]].y;if(1E-10>(p-s)*(v-r)-(q-r)*(y-s))n=!1;else{var A=void 0,I=void 0,C=void 0,x=void 0,G=void 0,J=void 0,E=void 0,H=void 0,B=void 0,W=void 0,B=H=E=t=z=void 0,A=y-p,I=v-q,C=s-y,x=r-v,G=p-s,J=q-r;for(n=0;n<e;n++)if(!(n===i||n===k||n===l))if(z=a[g[n]].x,t=a[g[n]].y,E=z-s,H=t-r,B=z-p,W=t-q,z-=y,t-=v,B=A*W-I*B,E=G*H-J*E,H=C*t-x*z,0<=B&&0<=H&&0<=E){n=!1;break a}n=!0}}if(n){f.push([a[g[i]],a[g[k]],a[g[l]]]);h.push([g[i],g[k],g[l]]); +i=k;for(l=k+1;l<e;i++,l++)g[i]=g[l];e--;m=2*e}}return d?h:f};a.Triangulate.area=b;return a})(THREE.FontUtils);self._typeface_js={faces:THREE.FontUtils.faces,loadFace:THREE.FontUtils.loadFace};THREE.Curve=function(){};THREE.Curve.prototype.getPoint=function(){console.log("Warning, getPoint() not implemented!");return null};THREE.Curve.prototype.getPointAt=function(a){a=this.getUtoTmapping(a);return this.getPoint(a)};THREE.Curve.prototype.getPoints=function(a){a||(a=5);var b,c=[];for(b=0;b<=a;b++)c.push(this.getPoint(b/a));return c};THREE.Curve.prototype.getSpacedPoints=function(a){a||(a=5);var b,c=[];for(b=0;b<=a;b++)c.push(this.getPointAt(b/a));return c}; +THREE.Curve.prototype.getLength=function(){var a=this.getLengths();return a[a.length-1]};THREE.Curve.prototype.getLengths=function(a){a||(a=this.__arcLengthDivisions?this.__arcLengthDivisions:200);if(this.cacheArcLengths&&this.cacheArcLengths.length==a+1&&!this.needsUpdate)return this.cacheArcLengths;this.needsUpdate=!1;var b=[],c,d=this.getPoint(0),e,f=0;b.push(0);for(e=1;e<=a;e++)c=this.getPoint(e/a),f+=c.distanceTo(d),b.push(f),d=c;return this.cacheArcLengths=b}; +THREE.Curve.prototype.updateArcLengths=function(){this.needsUpdate=!0;this.getLengths()};THREE.Curve.prototype.getUtoTmapping=function(a,b){var c=this.getLengths(),d=0,e=c.length,f;f=b?b:a*c[e-1];for(var g=0,h=e-1,i;g<=h;)if(d=Math.floor(g+(h-g)/2),i=c[d]-f,0>i)g=d+1;else if(0<i)h=d-1;else{h=d;break}d=h;if(c[d]==f)return d/(e-1);g=c[d];return c=(d+(f-g)/(c[d+1]-g))/(e-1)};THREE.Curve.prototype.getTangent=function(a){var b=a-1E-4,a=a+1E-4;0>b&&(b=0);1<a&&(a=1);b=this.getPoint(b);return this.getPoint(a).clone().sub(b).normalize()}; +THREE.Curve.prototype.getTangentAt=function(a){a=this.getUtoTmapping(a);return this.getTangent(a)};THREE.LineCurve=function(a,b){this.v1=a;this.v2=b};THREE.LineCurve.prototype=Object.create(THREE.Curve.prototype);THREE.LineCurve.prototype.getPoint=function(a){var b=this.v2.clone().sub(this.v1);b.multiplyScalar(a).add(this.v1);return b};THREE.LineCurve.prototype.getPointAt=function(a){return this.getPoint(a)};THREE.LineCurve.prototype.getTangent=function(){return this.v2.clone().sub(this.v1).normalize()}; +THREE.QuadraticBezierCurve=function(a,b,c){this.v0=a;this.v1=b;this.v2=c};THREE.QuadraticBezierCurve.prototype=Object.create(THREE.Curve.prototype);THREE.QuadraticBezierCurve.prototype.getPoint=function(a){var b;b=THREE.Shape.Utils.b2(a,this.v0.x,this.v1.x,this.v2.x);a=THREE.Shape.Utils.b2(a,this.v0.y,this.v1.y,this.v2.y);return new THREE.Vector2(b,a)}; +THREE.QuadraticBezierCurve.prototype.getTangent=function(a){var b;b=THREE.Curve.Utils.tangentQuadraticBezier(a,this.v0.x,this.v1.x,this.v2.x);a=THREE.Curve.Utils.tangentQuadraticBezier(a,this.v0.y,this.v1.y,this.v2.y);b=new THREE.Vector2(b,a);b.normalize();return b};THREE.CubicBezierCurve=function(a,b,c,d){this.v0=a;this.v1=b;this.v2=c;this.v3=d};THREE.CubicBezierCurve.prototype=Object.create(THREE.Curve.prototype); +THREE.CubicBezierCurve.prototype.getPoint=function(a){var b;b=THREE.Shape.Utils.b3(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x);a=THREE.Shape.Utils.b3(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y);return new THREE.Vector2(b,a)};THREE.CubicBezierCurve.prototype.getTangent=function(a){var b;b=THREE.Curve.Utils.tangentCubicBezier(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x);a=THREE.Curve.Utils.tangentCubicBezier(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y);b=new THREE.Vector2(b,a);b.normalize();return b}; +THREE.SplineCurve=function(a){this.points=void 0==a?[]:a};THREE.SplineCurve.prototype=Object.create(THREE.Curve.prototype);THREE.SplineCurve.prototype.getPoint=function(a){var b=new THREE.Vector2,c=[],d=this.points,e;e=(d.length-1)*a;a=Math.floor(e);e-=a;c[0]=0==a?a:a-1;c[1]=a;c[2]=a>d.length-2?d.length-1:a+1;c[3]=a>d.length-3?d.length-1:a+2;b.x=THREE.Curve.Utils.interpolate(d[c[0]].x,d[c[1]].x,d[c[2]].x,d[c[3]].x,e);b.y=THREE.Curve.Utils.interpolate(d[c[0]].y,d[c[1]].y,d[c[2]].y,d[c[3]].y,e);return b}; +THREE.EllipseCurve=function(a,b,c,d,e,f,g){this.aX=a;this.aY=b;this.xRadius=c;this.yRadius=d;this.aStartAngle=e;this.aEndAngle=f;this.aClockwise=g};THREE.EllipseCurve.prototype=Object.create(THREE.Curve.prototype);THREE.EllipseCurve.prototype.getPoint=function(a){var b=this.aEndAngle-this.aStartAngle;this.aClockwise||(a=1-a);b=this.aStartAngle+a*b;a=this.aX+this.xRadius*Math.cos(b);b=this.aY+this.yRadius*Math.sin(b);return new THREE.Vector2(a,b)}; +THREE.ArcCurve=function(a,b,c,d,e,f){THREE.EllipseCurve.call(this,a,b,c,c,d,e,f)};THREE.ArcCurve.prototype=Object.create(THREE.EllipseCurve.prototype); +THREE.Curve.Utils={tangentQuadraticBezier:function(a,b,c,d){return 2*(1-a)*(c-b)+2*a*(d-c)},tangentCubicBezier:function(a,b,c,d,e){return-3*b*(1-a)*(1-a)+3*c*(1-a)*(1-a)-6*a*c*(1-a)+6*a*d*(1-a)-3*a*a*d+3*a*a*e},tangentSpline:function(a){return 6*a*a-6*a+(3*a*a-4*a+1)+(-6*a*a+6*a)+(3*a*a-2*a)},interpolate:function(a,b,c,d,e){var a=0.5*(c-a),d=0.5*(d-b),f=e*e;return(2*b-2*c+a+d)*e*f+(-3*b+3*c-2*a-d)*f+a*e+b}}; +THREE.Curve.create=function(a,b){a.prototype=Object.create(THREE.Curve.prototype);a.prototype.getPoint=b;return a};THREE.LineCurve3=THREE.Curve.create(function(a,b){this.v1=a;this.v2=b},function(a){var b=new THREE.Vector3;b.subVectors(this.v2,this.v1);b.multiplyScalar(a);b.add(this.v1);return b}); +THREE.QuadraticBezierCurve3=THREE.Curve.create(function(a,b,c){this.v0=a;this.v1=b;this.v2=c},function(a){var b,c;b=THREE.Shape.Utils.b2(a,this.v0.x,this.v1.x,this.v2.x);c=THREE.Shape.Utils.b2(a,this.v0.y,this.v1.y,this.v2.y);a=THREE.Shape.Utils.b2(a,this.v0.z,this.v1.z,this.v2.z);return new THREE.Vector3(b,c,a)}); +THREE.CubicBezierCurve3=THREE.Curve.create(function(a,b,c,d){this.v0=a;this.v1=b;this.v2=c;this.v3=d},function(a){var b,c;b=THREE.Shape.Utils.b3(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x);c=THREE.Shape.Utils.b3(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y);a=THREE.Shape.Utils.b3(a,this.v0.z,this.v1.z,this.v2.z,this.v3.z);return new THREE.Vector3(b,c,a)}); +THREE.SplineCurve3=THREE.Curve.create(function(a){this.points=void 0==a?[]:a},function(a){var b=new THREE.Vector3,c=[],d=this.points,e,a=(d.length-1)*a;e=Math.floor(a);a-=e;c[0]=0==e?e:e-1;c[1]=e;c[2]=e>d.length-2?d.length-1:e+1;c[3]=e>d.length-3?d.length-1:e+2;e=d[c[0]];var f=d[c[1]],g=d[c[2]],c=d[c[3]];b.x=THREE.Curve.Utils.interpolate(e.x,f.x,g.x,c.x,a);b.y=THREE.Curve.Utils.interpolate(e.y,f.y,g.y,c.y,a);b.z=THREE.Curve.Utils.interpolate(e.z,f.z,g.z,c.z,a);return b}); +THREE.ClosedSplineCurve3=THREE.Curve.create(function(a){this.points=void 0==a?[]:a},function(a){var b=new THREE.Vector3,c=[],d=this.points,e;e=(d.length-0)*a;a=Math.floor(e);e-=a;a+=0<a?0:(Math.floor(Math.abs(a)/d.length)+1)*d.length;c[0]=(a-1)%d.length;c[1]=a%d.length;c[2]=(a+1)%d.length;c[3]=(a+2)%d.length;b.x=THREE.Curve.Utils.interpolate(d[c[0]].x,d[c[1]].x,d[c[2]].x,d[c[3]].x,e);b.y=THREE.Curve.Utils.interpolate(d[c[0]].y,d[c[1]].y,d[c[2]].y,d[c[3]].y,e);b.z=THREE.Curve.Utils.interpolate(d[c[0]].z, +d[c[1]].z,d[c[2]].z,d[c[3]].z,e);return b});THREE.CurvePath=function(){this.curves=[];this.bends=[];this.autoClose=!1};THREE.CurvePath.prototype=Object.create(THREE.Curve.prototype);THREE.CurvePath.prototype.add=function(a){this.curves.push(a)};THREE.CurvePath.prototype.checkConnection=function(){};THREE.CurvePath.prototype.closePath=function(){var a=this.curves[0].getPoint(0),b=this.curves[this.curves.length-1].getPoint(1);a.equals(b)||this.curves.push(new THREE.LineCurve(b,a))}; +THREE.CurvePath.prototype.getPoint=function(a){for(var b=a*this.getLength(),c=this.getCurveLengths(),a=0;a<c.length;){if(c[a]>=b)return b=c[a]-b,a=this.curves[a],b=1-b/a.getLength(),a.getPointAt(b);a++}return null};THREE.CurvePath.prototype.getLength=function(){var a=this.getCurveLengths();return a[a.length-1]}; +THREE.CurvePath.prototype.getCurveLengths=function(){if(this.cacheLengths&&this.cacheLengths.length==this.curves.length)return this.cacheLengths;var a=[],b=0,c,d=this.curves.length;for(c=0;c<d;c++)b+=this.curves[c].getLength(),a.push(b);return this.cacheLengths=a}; +THREE.CurvePath.prototype.getBoundingBox=function(){var a=this.getPoints(),b,c,d,e,f,g;b=c=Number.NEGATIVE_INFINITY;e=f=Number.POSITIVE_INFINITY;var h,i,k,l,m=a[0]instanceof THREE.Vector3;l=m?new THREE.Vector3:new THREE.Vector2;i=0;for(k=a.length;i<k;i++)h=a[i],h.x>b?b=h.x:h.x<e&&(e=h.x),h.y>c?c=h.y:h.y<f&&(f=h.y),m&&(h.z>d?d=h.z:h.z<g&&(g=h.z)),l.add(h);a={minX:e,minY:f,maxX:b,maxY:c,centroid:l.divideScalar(k)};m&&(a.maxZ=d,a.minZ=g);return a}; +THREE.CurvePath.prototype.createPointsGeometry=function(a){a=this.getPoints(a,!0);return this.createGeometry(a)};THREE.CurvePath.prototype.createSpacedPointsGeometry=function(a){a=this.getSpacedPoints(a,!0);return this.createGeometry(a)};THREE.CurvePath.prototype.createGeometry=function(a){for(var b=new THREE.Geometry,c=0;c<a.length;c++)b.vertices.push(new THREE.Vector3(a[c].x,a[c].y,a[c].z||0));return b};THREE.CurvePath.prototype.addWrapPath=function(a){this.bends.push(a)}; +THREE.CurvePath.prototype.getTransformedPoints=function(a,b){var c=this.getPoints(a),d,e;b||(b=this.bends);d=0;for(e=b.length;d<e;d++)c=this.getWrapPoints(c,b[d]);return c};THREE.CurvePath.prototype.getTransformedSpacedPoints=function(a,b){var c=this.getSpacedPoints(a),d,e;b||(b=this.bends);d=0;for(e=b.length;d<e;d++)c=this.getWrapPoints(c,b[d]);return c}; +THREE.CurvePath.prototype.getWrapPoints=function(a,b){var c=this.getBoundingBox(),d,e,f,g,h,i;d=0;for(e=a.length;d<e;d++)f=a[d],g=f.x,h=f.y,i=g/c.maxX,i=b.getUtoTmapping(i,g),g=b.getPoint(i),h=b.getNormalVector(i).multiplyScalar(h),f.x=g.x+h.x,f.y=g.y+h.y;return a};THREE.Gyroscope=function(){THREE.Object3D.call(this)};THREE.Gyroscope.prototype=Object.create(THREE.Object3D.prototype); +THREE.Gyroscope.prototype.updateMatrixWorld=function(a){this.matrixAutoUpdate&&this.updateMatrix();if(this.matrixWorldNeedsUpdate||a)this.parent?(this.matrixWorld.multiplyMatrices(this.parent.matrixWorld,this.matrix),this.matrixWorld.decompose(this.translationWorld,this.rotationWorld,this.scaleWorld),this.matrix.decompose(this.translationObject,this.rotationObject,this.scaleObject),this.matrixWorld.compose(this.translationWorld,this.rotationObject,this.scaleWorld)):this.matrixWorld.copy(this.matrix), +this.matrixWorldNeedsUpdate=!1,a=!0;for(var b=0,c=this.children.length;b<c;b++)this.children[b].updateMatrixWorld(a)};THREE.Gyroscope.prototype.translationWorld=new THREE.Vector3;THREE.Gyroscope.prototype.translationObject=new THREE.Vector3;THREE.Gyroscope.prototype.rotationWorld=new THREE.Quaternion;THREE.Gyroscope.prototype.rotationObject=new THREE.Quaternion;THREE.Gyroscope.prototype.scaleWorld=new THREE.Vector3;THREE.Gyroscope.prototype.scaleObject=new THREE.Vector3;THREE.Path=function(a){THREE.CurvePath.call(this);this.actions=[];a&&this.fromPoints(a)};THREE.Path.prototype=Object.create(THREE.CurvePath.prototype);THREE.PathActions={MOVE_TO:"moveTo",LINE_TO:"lineTo",QUADRATIC_CURVE_TO:"quadraticCurveTo",BEZIER_CURVE_TO:"bezierCurveTo",CSPLINE_THRU:"splineThru",ARC:"arc",ELLIPSE:"ellipse"};THREE.Path.prototype.fromPoints=function(a){this.moveTo(a[0].x,a[0].y);for(var b=1,c=a.length;b<c;b++)this.lineTo(a[b].x,a[b].y)}; +THREE.Path.prototype.moveTo=function(a,b){var c=Array.prototype.slice.call(arguments);this.actions.push({action:THREE.PathActions.MOVE_TO,args:c})};THREE.Path.prototype.lineTo=function(a,b){var c=Array.prototype.slice.call(arguments),d=this.actions[this.actions.length-1].args,d=new THREE.LineCurve(new THREE.Vector2(d[d.length-2],d[d.length-1]),new THREE.Vector2(a,b));this.curves.push(d);this.actions.push({action:THREE.PathActions.LINE_TO,args:c})}; +THREE.Path.prototype.quadraticCurveTo=function(a,b,c,d){var e=Array.prototype.slice.call(arguments),f=this.actions[this.actions.length-1].args,f=new THREE.QuadraticBezierCurve(new THREE.Vector2(f[f.length-2],f[f.length-1]),new THREE.Vector2(a,b),new THREE.Vector2(c,d));this.curves.push(f);this.actions.push({action:THREE.PathActions.QUADRATIC_CURVE_TO,args:e})}; +THREE.Path.prototype.bezierCurveTo=function(a,b,c,d,e,f){var g=Array.prototype.slice.call(arguments),h=this.actions[this.actions.length-1].args,h=new THREE.CubicBezierCurve(new THREE.Vector2(h[h.length-2],h[h.length-1]),new THREE.Vector2(a,b),new THREE.Vector2(c,d),new THREE.Vector2(e,f));this.curves.push(h);this.actions.push({action:THREE.PathActions.BEZIER_CURVE_TO,args:g})}; +THREE.Path.prototype.splineThru=function(a){var b=Array.prototype.slice.call(arguments),c=this.actions[this.actions.length-1].args,c=[new THREE.Vector2(c[c.length-2],c[c.length-1])];Array.prototype.push.apply(c,a);c=new THREE.SplineCurve(c);this.curves.push(c);this.actions.push({action:THREE.PathActions.CSPLINE_THRU,args:b})};THREE.Path.prototype.arc=function(a,b,c,d,e,f){var g=this.actions[this.actions.length-1].args;this.absarc(a+g[g.length-2],b+g[g.length-1],c,d,e,f)}; +THREE.Path.prototype.absarc=function(a,b,c,d,e,f){this.absellipse(a,b,c,c,d,e,f)};THREE.Path.prototype.ellipse=function(a,b,c,d,e,f,g){var h=this.actions[this.actions.length-1].args;this.absellipse(a+h[h.length-2],b+h[h.length-1],c,d,e,f,g)};THREE.Path.prototype.absellipse=function(a,b,c,d,e,f,g){var h=Array.prototype.slice.call(arguments),i=new THREE.EllipseCurve(a,b,c,d,e,f,g);this.curves.push(i);i=i.getPoint(g?1:0);h.push(i.x);h.push(i.y);this.actions.push({action:THREE.PathActions.ELLIPSE,args:h})}; +THREE.Path.prototype.getSpacedPoints=function(a){a||(a=40);for(var b=[],c=0;c<a;c++)b.push(this.getPoint(c/a));return b}; +THREE.Path.prototype.getPoints=function(a,b){if(this.useSpacedPoints)return console.log("tata"),this.getSpacedPoints(a,b);var a=a||12,c=[],d,e,f,g,h,i,k,l,m,n,s,r,p;d=0;for(e=this.actions.length;d<e;d++)switch(f=this.actions[d],g=f.action,f=f.args,g){case THREE.PathActions.MOVE_TO:c.push(new THREE.Vector2(f[0],f[1]));break;case THREE.PathActions.LINE_TO:c.push(new THREE.Vector2(f[0],f[1]));break;case THREE.PathActions.QUADRATIC_CURVE_TO:h=f[2];i=f[3];m=f[0];n=f[1];0<c.length?(g=c[c.length-1],s=g.x, +r=g.y):(g=this.actions[d-1].args,s=g[g.length-2],r=g[g.length-1]);for(f=1;f<=a;f++)p=f/a,g=THREE.Shape.Utils.b2(p,s,m,h),p=THREE.Shape.Utils.b2(p,r,n,i),c.push(new THREE.Vector2(g,p));break;case THREE.PathActions.BEZIER_CURVE_TO:h=f[4];i=f[5];m=f[0];n=f[1];k=f[2];l=f[3];0<c.length?(g=c[c.length-1],s=g.x,r=g.y):(g=this.actions[d-1].args,s=g[g.length-2],r=g[g.length-1]);for(f=1;f<=a;f++)p=f/a,g=THREE.Shape.Utils.b3(p,s,m,k,h),p=THREE.Shape.Utils.b3(p,r,n,l,i),c.push(new THREE.Vector2(g,p));break;case THREE.PathActions.CSPLINE_THRU:g= +this.actions[d-1].args;p=[new THREE.Vector2(g[g.length-2],g[g.length-1])];g=a*f[0].length;p=p.concat(f[0]);p=new THREE.SplineCurve(p);for(f=1;f<=g;f++)c.push(p.getPointAt(f/g));break;case THREE.PathActions.ARC:h=f[0];i=f[1];n=f[2];k=f[3];g=f[4];m=!!f[5];s=g-k;r=2*a;for(f=1;f<=r;f++)p=f/r,m||(p=1-p),p=k+p*s,g=h+n*Math.cos(p),p=i+n*Math.sin(p),c.push(new THREE.Vector2(g,p));break;case THREE.PathActions.ELLIPSE:h=f[0];i=f[1];n=f[2];l=f[3];k=f[4];g=f[5];m=!!f[6];s=g-k;r=2*a;for(f=1;f<=r;f++)p=f/r,m|| +(p=1-p),p=k+p*s,g=h+n*Math.cos(p),p=i+l*Math.sin(p),c.push(new THREE.Vector2(g,p))}d=c[c.length-1];1E-10>Math.abs(d.x-c[0].x)&&1E-10>Math.abs(d.y-c[0].y)&&c.splice(c.length-1,1);b&&c.push(c[0]);return c}; +THREE.Path.prototype.toShapes=function(){var a,b,c,d,e=[],f=new THREE.Path;a=0;for(b=this.actions.length;a<b;a++)c=this.actions[a],d=c.args,c=c.action,c==THREE.PathActions.MOVE_TO&&0!=f.actions.length&&(e.push(f),f=new THREE.Path),f[c].apply(f,d);0!=f.actions.length&&e.push(f);if(0==e.length)return[];var g;d=[];a=!THREE.Shape.Utils.isClockWise(e[0].getPoints());if(1==e.length)return f=e[0],g=new THREE.Shape,g.actions=f.actions,g.curves=f.curves,d.push(g),d;if(a){g=new THREE.Shape;a=0;for(b=e.length;a< +b;a++)f=e[a],THREE.Shape.Utils.isClockWise(f.getPoints())?(g.actions=f.actions,g.curves=f.curves,d.push(g),g=new THREE.Shape):g.holes.push(f)}else{a=0;for(b=e.length;a<b;a++)f=e[a],THREE.Shape.Utils.isClockWise(f.getPoints())?(g&&d.push(g),g=new THREE.Shape,g.actions=f.actions,g.curves=f.curves):g.holes.push(f);d.push(g)}return d};THREE.Shape=function(){THREE.Path.apply(this,arguments);this.holes=[]};THREE.Shape.prototype=Object.create(THREE.Path.prototype);THREE.Shape.prototype.extrude=function(a){return new THREE.ExtrudeGeometry(this,a)};THREE.Shape.prototype.makeGeometry=function(a){return new THREE.ShapeGeometry(this,a)};THREE.Shape.prototype.getPointsHoles=function(a){var b,c=this.holes.length,d=[];for(b=0;b<c;b++)d[b]=this.holes[b].getTransformedPoints(a,this.bends);return d}; +THREE.Shape.prototype.getSpacedPointsHoles=function(a){var b,c=this.holes.length,d=[];for(b=0;b<c;b++)d[b]=this.holes[b].getTransformedSpacedPoints(a,this.bends);return d};THREE.Shape.prototype.extractAllPoints=function(a){return{shape:this.getTransformedPoints(a),holes:this.getPointsHoles(a)}};THREE.Shape.prototype.extractPoints=function(a){return this.useSpacedPoints?this.extractAllSpacedPoints(a):this.extractAllPoints(a)}; +THREE.Shape.prototype.extractAllSpacedPoints=function(a){return{shape:this.getTransformedSpacedPoints(a),holes:this.getSpacedPointsHoles(a)}}; +THREE.Shape.Utils={removeHoles:function(a,b){var c=a.concat(),d=c.concat(),e,f,g,h,i,k,l,m,n,s,r=[];for(i=0;i<b.length;i++){k=b[i];Array.prototype.push.apply(d,k);f=Number.POSITIVE_INFINITY;for(e=0;e<k.length;e++){n=k[e];s=[];for(m=0;m<c.length;m++)l=c[m],l=n.distanceToSquared(l),s.push(l),l<f&&(f=l,g=e,h=m)}e=0<=h-1?h-1:c.length-1;f=0<=g-1?g-1:k.length-1;var p=[k[g],c[h],c[e]];m=THREE.FontUtils.Triangulate.area(p);var q=[k[g],k[f],c[h]];n=THREE.FontUtils.Triangulate.area(q);s=h;l=g;h+=1;g+=-1;0> +h&&(h+=c.length);h%=c.length;0>g&&(g+=k.length);g%=k.length;e=0<=h-1?h-1:c.length-1;f=0<=g-1?g-1:k.length-1;p=[k[g],c[h],c[e]];p=THREE.FontUtils.Triangulate.area(p);q=[k[g],k[f],c[h]];q=THREE.FontUtils.Triangulate.area(q);m+n>p+q&&(h=s,g=l,0>h&&(h+=c.length),h%=c.length,0>g&&(g+=k.length),g%=k.length,e=0<=h-1?h-1:c.length-1,f=0<=g-1?g-1:k.length-1);m=c.slice(0,h);n=c.slice(h);s=k.slice(g);l=k.slice(0,g);f=[k[g],k[f],c[h]];r.push([k[g],c[h],c[e]]);r.push(f);c=m.concat(s).concat(l).concat(n)}return{shape:c, +isolatedPts:r,allpoints:d}},triangulateShape:function(a,b){var c=THREE.Shape.Utils.removeHoles(a,b),d=c.allpoints,e=c.isolatedPts,c=THREE.FontUtils.Triangulate(c.shape,!1),f,g,h,i,k={};f=0;for(g=d.length;f<g;f++)i=d[f].x+":"+d[f].y,void 0!==k[i]&&console.log("Duplicate point",i),k[i]=f;f=0;for(g=c.length;f<g;f++){h=c[f];for(d=0;3>d;d++)i=h[d].x+":"+h[d].y,i=k[i],void 0!==i&&(h[d]=i)}f=0;for(g=e.length;f<g;f++){h=e[f];for(d=0;3>d;d++)i=h[d].x+":"+h[d].y,i=k[i],void 0!==i&&(h[d]=i)}return c.concat(e)}, +isClockWise:function(a){return 0>THREE.FontUtils.Triangulate.area(a)},b2p0:function(a,b){var c=1-a;return c*c*b},b2p1:function(a,b){return 2*(1-a)*a*b},b2p2:function(a,b){return a*a*b},b2:function(a,b,c,d){return this.b2p0(a,b)+this.b2p1(a,c)+this.b2p2(a,d)},b3p0:function(a,b){var c=1-a;return c*c*c*b},b3p1:function(a,b){var c=1-a;return 3*c*c*a*b},b3p2:function(a,b){return 3*(1-a)*a*a*b},b3p3:function(a,b){return a*a*a*b},b3:function(a,b,c,d,e){return this.b3p0(a,b)+this.b3p1(a,c)+this.b3p2(a,d)+ +this.b3p3(a,e)}};THREE.AnimationHandler=function(){var a=[],b={},c={update:function(b){for(var c=0;c<a.length;c++)a[c].update(b)},addToUpdate:function(b){-1===a.indexOf(b)&&a.push(b)},removeFromUpdate:function(b){b=a.indexOf(b);-1!==b&&a.splice(b,1)},add:function(a){void 0!==b[a.name]&&console.log("THREE.AnimationHandler.add: Warning! "+a.name+" already exists in library. Overwriting.");b[a.name]=a;if(!0!==a.initialized){for(var c=0;c<a.hierarchy.length;c++){for(var d=0;d<a.hierarchy[c].keys.length;d++)if(0>a.hierarchy[c].keys[d].time&& +(a.hierarchy[c].keys[d].time=0),void 0!==a.hierarchy[c].keys[d].rot&&!(a.hierarchy[c].keys[d].rot instanceof THREE.Quaternion)){var h=a.hierarchy[c].keys[d].rot;a.hierarchy[c].keys[d].rot=new THREE.Quaternion(h[0],h[1],h[2],h[3])}if(a.hierarchy[c].keys.length&&void 0!==a.hierarchy[c].keys[0].morphTargets){h={};for(d=0;d<a.hierarchy[c].keys.length;d++)for(var i=0;i<a.hierarchy[c].keys[d].morphTargets.length;i++){var k=a.hierarchy[c].keys[d].morphTargets[i];h[k]=-1}a.hierarchy[c].usedMorphTargets=h; +for(d=0;d<a.hierarchy[c].keys.length;d++){var l={};for(k in h){for(i=0;i<a.hierarchy[c].keys[d].morphTargets.length;i++)if(a.hierarchy[c].keys[d].morphTargets[i]===k){l[k]=a.hierarchy[c].keys[d].morphTargetsInfluences[i];break}i===a.hierarchy[c].keys[d].morphTargets.length&&(l[k]=0)}a.hierarchy[c].keys[d].morphTargetsInfluences=l}}for(d=1;d<a.hierarchy[c].keys.length;d++)a.hierarchy[c].keys[d].time===a.hierarchy[c].keys[d-1].time&&(a.hierarchy[c].keys.splice(d,1),d--);for(d=0;d<a.hierarchy[c].keys.length;d++)a.hierarchy[c].keys[d].index= +d}d=parseInt(a.length*a.fps,10);a.JIT={};a.JIT.hierarchy=[];for(c=0;c<a.hierarchy.length;c++)a.JIT.hierarchy.push(Array(d));a.initialized=!0}},get:function(a){if("string"===typeof a){if(b[a])return b[a];console.log("THREE.AnimationHandler.get: Couldn't find animation "+a);return null}},parse:function(a){var b=[];if(a instanceof THREE.SkinnedMesh)for(var c=0;c<a.bones.length;c++)b.push(a.bones[c]);else d(a,b);return b}},d=function(a,b){b.push(a);for(var c=0;c<a.children.length;c++)d(a.children[c], +b)};c.LINEAR=0;c.CATMULLROM=1;c.CATMULLROM_FORWARD=2;return c}();THREE.Animation=function(a,b,c){this.root=a;this.data=THREE.AnimationHandler.get(b);this.hierarchy=THREE.AnimationHandler.parse(a);this.currentTime=0;this.timeScale=1;this.isPlaying=!1;this.loop=this.isPaused=!0;this.interpolationType=void 0!==c?c:THREE.AnimationHandler.LINEAR;this.points=[];this.target=new THREE.Vector3}; +THREE.Animation.prototype.play=function(a,b){if(!1===this.isPlaying){this.isPlaying=!0;this.loop=void 0!==a?a:!0;this.currentTime=void 0!==b?b:0;var c,d=this.hierarchy.length,e;for(c=0;c<d;c++){e=this.hierarchy[c];this.interpolationType!==THREE.AnimationHandler.CATMULLROM_FORWARD&&(e.useQuaternion=!0);e.matrixAutoUpdate=!0;void 0===e.animationCache&&(e.animationCache={},e.animationCache.prevKey={pos:0,rot:0,scl:0},e.animationCache.nextKey={pos:0,rot:0,scl:0},e.animationCache.originalMatrix=e instanceof +THREE.Bone?e.skinMatrix:e.matrix);var f=e.animationCache.prevKey;e=e.animationCache.nextKey;f.pos=this.data.hierarchy[c].keys[0];f.rot=this.data.hierarchy[c].keys[0];f.scl=this.data.hierarchy[c].keys[0];e.pos=this.getNextKeyWith("pos",c,1);e.rot=this.getNextKeyWith("rot",c,1);e.scl=this.getNextKeyWith("scl",c,1)}this.update(0)}this.isPaused=!1;THREE.AnimationHandler.addToUpdate(this)}; +THREE.Animation.prototype.pause=function(){!0===this.isPaused?THREE.AnimationHandler.addToUpdate(this):THREE.AnimationHandler.removeFromUpdate(this);this.isPaused=!this.isPaused};THREE.Animation.prototype.stop=function(){this.isPaused=this.isPlaying=!1;THREE.AnimationHandler.removeFromUpdate(this)}; +THREE.Animation.prototype.update=function(a){if(!1!==this.isPlaying){var b=["pos","rot","scl"],c,d,e,f,g,h,i,k,l;l=this.currentTime+=a*this.timeScale;k=this.currentTime%=this.data.length;parseInt(Math.min(k*this.data.fps,this.data.length*this.data.fps),10);for(var m=0,n=this.hierarchy.length;m<n;m++){a=this.hierarchy[m];i=a.animationCache;for(var s=0;3>s;s++){c=b[s];g=i.prevKey[c];h=i.nextKey[c];if(h.time<=l){if(k<l)if(this.loop){g=this.data.hierarchy[m].keys[0];for(h=this.getNextKeyWith(c,m,1);h.time< +k;)g=h,h=this.getNextKeyWith(c,m,h.index+1)}else{this.stop();return}else{do g=h,h=this.getNextKeyWith(c,m,h.index+1);while(h.time<k)}i.prevKey[c]=g;i.nextKey[c]=h}a.matrixAutoUpdate=!0;a.matrixWorldNeedsUpdate=!0;d=(k-g.time)/(h.time-g.time);e=g[c];f=h[c];if(0>d||1<d)console.log("THREE.Animation.update: Warning! Scale out of bounds:"+d+" on bone "+m),d=0>d?0:1;if("pos"===c)if(c=a.position,this.interpolationType===THREE.AnimationHandler.LINEAR)c.x=e[0]+(f[0]-e[0])*d,c.y=e[1]+(f[1]-e[1])*d,c.z=e[2]+ +(f[2]-e[2])*d;else{if(this.interpolationType===THREE.AnimationHandler.CATMULLROM||this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD)this.points[0]=this.getPrevKeyWith("pos",m,g.index-1).pos,this.points[1]=e,this.points[2]=f,this.points[3]=this.getNextKeyWith("pos",m,h.index+1).pos,d=0.33*d+0.33,e=this.interpolateCatmullRom(this.points,d),c.x=e[0],c.y=e[1],c.z=e[2],this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD&&(d=this.interpolateCatmullRom(this.points,1.01*d), +this.target.set(d[0],d[1],d[2]),this.target.sub(c),this.target.y=0,this.target.normalize(),d=Math.atan2(this.target.x,this.target.z),a.rotation.set(0,d,0))}else"rot"===c?THREE.Quaternion.slerp(e,f,a.quaternion,d):"scl"===c&&(c=a.scale,c.x=e[0]+(f[0]-e[0])*d,c.y=e[1]+(f[1]-e[1])*d,c.z=e[2]+(f[2]-e[2])*d)}}}}; +THREE.Animation.prototype.interpolateCatmullRom=function(a,b){var c=[],d=[],e,f,g,h,i,k;e=(a.length-1)*b;f=Math.floor(e);e-=f;c[0]=0===f?f:f-1;c[1]=f;c[2]=f>a.length-2?f:f+1;c[3]=f>a.length-3?f:f+2;f=a[c[0]];h=a[c[1]];i=a[c[2]];k=a[c[3]];c=e*e;g=e*c;d[0]=this.interpolate(f[0],h[0],i[0],k[0],e,c,g);d[1]=this.interpolate(f[1],h[1],i[1],k[1],e,c,g);d[2]=this.interpolate(f[2],h[2],i[2],k[2],e,c,g);return d}; +THREE.Animation.prototype.interpolate=function(a,b,c,d,e,f,g){a=0.5*(c-a);d=0.5*(d-b);return(2*(b-c)+a+d)*g+(-3*(b-c)-2*a-d)*f+a*e+b};THREE.Animation.prototype.getNextKeyWith=function(a,b,c){for(var d=this.data.hierarchy[b].keys,c=this.interpolationType===THREE.AnimationHandler.CATMULLROM||this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD?c<d.length-1?c:d.length-1:c%d.length;c<d.length;c++)if(void 0!==d[c][a])return d[c];return this.data.hierarchy[b].keys[0]}; +THREE.Animation.prototype.getPrevKeyWith=function(a,b,c){for(var d=this.data.hierarchy[b].keys,c=this.interpolationType===THREE.AnimationHandler.CATMULLROM||this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD?0<c?c:0:0<=c?c:c+d.length;0<=c;c--)if(void 0!==d[c][a])return d[c];return this.data.hierarchy[b].keys[d.length-1]};THREE.KeyFrameAnimation=function(a,b,c){this.root=a;this.data=THREE.AnimationHandler.get(b);this.hierarchy=THREE.AnimationHandler.parse(a);this.currentTime=0;this.timeScale=0.001;this.isPlaying=!1;this.loop=this.isPaused=!0;this.JITCompile=void 0!==c?c:!0;a=0;for(b=this.hierarchy.length;a<b;a++){var c=this.data.hierarchy[a].sids,d=this.hierarchy[a];if(this.data.hierarchy[a].keys.length&&c){for(var e=0;e<c.length;e++){var f=c[e],g=this.getNextKeyWith(f,a,0);g&&g.apply(f)}d.matrixAutoUpdate=!1;this.data.hierarchy[a].node.updateMatrix(); +d.matrixWorldNeedsUpdate=!0}}}; +THREE.KeyFrameAnimation.prototype.play=function(a,b){if(!this.isPlaying){this.isPlaying=!0;this.loop=void 0!==a?a:!0;this.currentTime=void 0!==b?b:0;this.startTimeMs=b;this.startTime=1E7;this.endTime=-this.startTime;var c,d=this.hierarchy.length,e,f;for(c=0;c<d;c++)e=this.hierarchy[c],f=this.data.hierarchy[c],e.useQuaternion=!0,void 0===f.animationCache&&(f.animationCache={},f.animationCache.prevKey=null,f.animationCache.nextKey=null,f.animationCache.originalMatrix=e instanceof THREE.Bone?e.skinMatrix: +e.matrix),e=this.data.hierarchy[c].keys,e.length&&(f.animationCache.prevKey=e[0],f.animationCache.nextKey=e[1],this.startTime=Math.min(e[0].time,this.startTime),this.endTime=Math.max(e[e.length-1].time,this.endTime));this.update(0)}this.isPaused=!1;THREE.AnimationHandler.addToUpdate(this)};THREE.KeyFrameAnimation.prototype.pause=function(){this.isPaused?THREE.AnimationHandler.addToUpdate(this):THREE.AnimationHandler.removeFromUpdate(this);this.isPaused=!this.isPaused}; +THREE.KeyFrameAnimation.prototype.stop=function(){this.isPaused=this.isPlaying=!1;THREE.AnimationHandler.removeFromUpdate(this);for(var a=0;a<this.data.hierarchy.length;a++){var b=this.hierarchy[a],c=this.data.hierarchy[a];if(void 0!==c.animationCache){var d=c.animationCache.originalMatrix;b instanceof THREE.Bone?(d.copy(b.skinMatrix),b.skinMatrix=d):(d.copy(b.matrix),b.matrix=d);delete c.animationCache}}}; +THREE.KeyFrameAnimation.prototype.update=function(a){if(this.isPlaying){var b,c,d,e,f=this.data.JIT.hierarchy,g,h,i;h=this.currentTime+=a*this.timeScale;g=this.currentTime%=this.data.length;g<this.startTimeMs&&(g=this.currentTime=this.startTimeMs+g);e=parseInt(Math.min(g*this.data.fps,this.data.length*this.data.fps),10);if((i=g<h)&&!this.loop){for(var a=0,k=this.hierarchy.length;a<k;a++){var l=this.data.hierarchy[a].keys,f=this.data.hierarchy[a].sids;d=l.length-1;e=this.hierarchy[a];if(l.length){for(l= +0;l<f.length;l++)g=f[l],(h=this.getPrevKeyWith(g,a,d))&&h.apply(g);this.data.hierarchy[a].node.updateMatrix();e.matrixWorldNeedsUpdate=!0}}this.stop()}else if(!(g<this.startTime)){a=0;for(k=this.hierarchy.length;a<k;a++){d=this.hierarchy[a];b=this.data.hierarchy[a];var l=b.keys,m=b.animationCache;if(this.JITCompile&&void 0!==f[a][e])d instanceof THREE.Bone?(d.skinMatrix=f[a][e],d.matrixWorldNeedsUpdate=!1):(d.matrix=f[a][e],d.matrixWorldNeedsUpdate=!0);else if(l.length){this.JITCompile&&m&&(d instanceof +THREE.Bone?d.skinMatrix=m.originalMatrix:d.matrix=m.originalMatrix);b=m.prevKey;c=m.nextKey;if(b&&c){if(c.time<=h){if(i&&this.loop){b=l[0];for(c=l[1];c.time<g;)b=c,c=l[b.index+1]}else if(!i)for(var n=l.length-1;c.time<g&&c.index!==n;)b=c,c=l[b.index+1];m.prevKey=b;m.nextKey=c}c.time>=g?b.interpolate(c,g):b.interpolate(c,c.time)}this.data.hierarchy[a].node.updateMatrix();d.matrixWorldNeedsUpdate=!0}}if(this.JITCompile&&void 0===f[0][e]){this.hierarchy[0].updateMatrixWorld(!0);for(a=0;a<this.hierarchy.length;a++)f[a][e]= +this.hierarchy[a]instanceof THREE.Bone?this.hierarchy[a].skinMatrix.clone():this.hierarchy[a].matrix.clone()}}}};THREE.KeyFrameAnimation.prototype.getNextKeyWith=function(a,b,c){b=this.data.hierarchy[b].keys;for(c%=b.length;c<b.length;c++)if(b[c].hasTarget(a))return b[c];return b[0]};THREE.KeyFrameAnimation.prototype.getPrevKeyWith=function(a,b,c){b=this.data.hierarchy[b].keys;for(c=0<=c?c:c+b.length;0<=c;c--)if(b[c].hasTarget(a))return b[c];return b[b.length-1]};THREE.CubeCamera=function(a,b,c){THREE.Object3D.call(this);var d=new THREE.PerspectiveCamera(90,1,a,b);d.up.set(0,-1,0);d.lookAt(new THREE.Vector3(1,0,0));this.add(d);var e=new THREE.PerspectiveCamera(90,1,a,b);e.up.set(0,-1,0);e.lookAt(new THREE.Vector3(-1,0,0));this.add(e);var f=new THREE.PerspectiveCamera(90,1,a,b);f.up.set(0,0,1);f.lookAt(new THREE.Vector3(0,1,0));this.add(f);var g=new THREE.PerspectiveCamera(90,1,a,b);g.up.set(0,0,-1);g.lookAt(new THREE.Vector3(0,-1,0));this.add(g);var h=new THREE.PerspectiveCamera(90, +1,a,b);h.up.set(0,-1,0);h.lookAt(new THREE.Vector3(0,0,1));this.add(h);var i=new THREE.PerspectiveCamera(90,1,a,b);i.up.set(0,-1,0);i.lookAt(new THREE.Vector3(0,0,-1));this.add(i);this.renderTarget=new THREE.WebGLRenderTargetCube(c,c,{format:THREE.RGBFormat,magFilter:THREE.LinearFilter,minFilter:THREE.LinearFilter});this.updateCubeMap=function(a,b){var c=this.renderTarget,n=c.generateMipmaps;c.generateMipmaps=!1;c.activeCubeFace=0;a.render(b,d,c);c.activeCubeFace=1;a.render(b,e,c);c.activeCubeFace= +2;a.render(b,f,c);c.activeCubeFace=3;a.render(b,g,c);c.activeCubeFace=4;a.render(b,h,c);c.generateMipmaps=n;c.activeCubeFace=5;a.render(b,i,c)}};THREE.CubeCamera.prototype=Object.create(THREE.Object3D.prototype);THREE.CombinedCamera=function(a,b,c,d,e,f,g){THREE.Camera.call(this);this.fov=c;this.left=-a/2;this.right=a/2;this.top=b/2;this.bottom=-b/2;this.cameraO=new THREE.OrthographicCamera(a/-2,a/2,b/2,b/-2,f,g);this.cameraP=new THREE.PerspectiveCamera(c,a/b,d,e);this.zoom=1;this.toPerspective()};THREE.CombinedCamera.prototype=Object.create(THREE.Camera.prototype); +THREE.CombinedCamera.prototype.toPerspective=function(){this.near=this.cameraP.near;this.far=this.cameraP.far;this.cameraP.fov=this.fov/this.zoom;this.cameraP.updateProjectionMatrix();this.projectionMatrix=this.cameraP.projectionMatrix;this.inPerspectiveMode=!0;this.inOrthographicMode=!1}; +THREE.CombinedCamera.prototype.toOrthographic=function(){var a=this.cameraP.aspect,b=(this.cameraP.near+this.cameraP.far)/2,b=Math.tan(this.fov/2)*b,a=2*b*a/2,b=b/this.zoom,a=a/this.zoom;this.cameraO.left=-a;this.cameraO.right=a;this.cameraO.top=b;this.cameraO.bottom=-b;this.cameraO.updateProjectionMatrix();this.near=this.cameraO.near;this.far=this.cameraO.far;this.projectionMatrix=this.cameraO.projectionMatrix;this.inPerspectiveMode=!1;this.inOrthographicMode=!0}; +THREE.CombinedCamera.prototype.setSize=function(a,b){this.cameraP.aspect=a/b;this.left=-a/2;this.right=a/2;this.top=b/2;this.bottom=-b/2};THREE.CombinedCamera.prototype.setFov=function(a){this.fov=a;this.inPerspectiveMode?this.toPerspective():this.toOrthographic()};THREE.CombinedCamera.prototype.updateProjectionMatrix=function(){this.inPerspectiveMode?this.toPerspective():(this.toPerspective(),this.toOrthographic())}; +THREE.CombinedCamera.prototype.setLens=function(a,b){void 0===b&&(b=24);var c=2*THREE.Math.radToDeg(Math.atan(b/(2*a)));this.setFov(c);return c};THREE.CombinedCamera.prototype.setZoom=function(a){this.zoom=a;this.inPerspectiveMode?this.toPerspective():this.toOrthographic()};THREE.CombinedCamera.prototype.toFrontView=function(){this.rotation.x=0;this.rotation.y=0;this.rotation.z=0;this.rotationAutoUpdate=!1}; +THREE.CombinedCamera.prototype.toBackView=function(){this.rotation.x=0;this.rotation.y=Math.PI;this.rotation.z=0;this.rotationAutoUpdate=!1};THREE.CombinedCamera.prototype.toLeftView=function(){this.rotation.x=0;this.rotation.y=-Math.PI/2;this.rotation.z=0;this.rotationAutoUpdate=!1};THREE.CombinedCamera.prototype.toRightView=function(){this.rotation.x=0;this.rotation.y=Math.PI/2;this.rotation.z=0;this.rotationAutoUpdate=!1}; +THREE.CombinedCamera.prototype.toTopView=function(){this.rotation.x=-Math.PI/2;this.rotation.y=0;this.rotation.z=0;this.rotationAutoUpdate=!1};THREE.CombinedCamera.prototype.toBottomView=function(){this.rotation.x=Math.PI/2;this.rotation.y=0;this.rotation.z=0;this.rotationAutoUpdate=!1};THREE.AsteriskGeometry=function(a,b){THREE.Geometry.call(this);for(var c=0.707*a,d=0.707*b,c=[[a,0,0],[b,0,0],[-a,0,0],[-b,0,0],[0,a,0],[0,b,0],[0,-a,0],[0,-b,0],[0,0,a],[0,0,b],[0,0,-a],[0,0,-b],[c,c,0],[d,d,0],[-c,-c,0],[-d,-d,0],[c,-c,0],[d,-d,0],[-c,c,0],[-d,d,0],[c,0,c],[d,0,d],[-c,0,-c],[-d,0,-d],[c,0,-c],[d,0,-d],[-c,0,c],[-d,0,d],[0,c,c],[0,d,d],[0,-c,-c],[0,-d,-d],[0,c,-c],[0,d,-d],[0,-c,c],[0,-d,d]],d=0,e=c.length;d<e;d++)this.vertices.push(new THREE.Vector3(c[d][0],c[d][1],c[d][2]))}; +THREE.AsteriskGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.CircleGeometry=function(a,b,c,d){THREE.Geometry.call(this);var a=a||50,c=void 0!==c?c:0,d=void 0!==d?d:2*Math.PI,b=void 0!==b?Math.max(3,b):8,e,f=[];e=new THREE.Vector3;var g=new THREE.Vector2(0.5,0.5);this.vertices.push(e);f.push(g);for(e=0;e<=b;e++){var h=new THREE.Vector3;h.x=a*Math.cos(c+e/b*d);h.y=a*Math.sin(c+e/b*d);this.vertices.push(h);f.push(new THREE.Vector2((h.x/a+1)/2,-(h.y/a+1)/2+1))}c=new THREE.Vector3(0,0,-1);for(e=1;e<=b;e++)this.faces.push(new THREE.Face3(e,e+1,0,[c,c,c])), +this.faceVertexUvs[0].push([f[e],f[e+1],g]);this.computeCentroids();this.computeFaceNormals();this.boundingSphere=new THREE.Sphere(new THREE.Vector3,a)};THREE.CircleGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.CubeGeometry=function(a,b,c,d,e,f){function g(a,b,c,d,e,f,g,p){var q,y=h.widthSegments,v=h.heightSegments,z=e/2,t=f/2,A=h.vertices.length;if("x"===a&&"y"===b||"y"===a&&"x"===b)q="z";else if("x"===a&&"z"===b||"z"===a&&"x"===b)q="y",v=h.depthSegments;else if("z"===a&&"y"===b||"y"===a&&"z"===b)q="x",y=h.depthSegments;var I=y+1,C=v+1,x=e/y,G=f/v,J=new THREE.Vector3;J[q]=0<g?1:-1;for(e=0;e<C;e++)for(f=0;f<I;f++){var E=new THREE.Vector3;E[a]=(f*x-z)*c;E[b]=(e*G-t)*d;E[q]=g;h.vertices.push(E)}for(e= +0;e<v;e++)for(f=0;f<y;f++)a=new THREE.Face4(f+I*e+A,f+I*(e+1)+A,f+1+I*(e+1)+A,f+1+I*e+A),a.normal.copy(J),a.vertexNormals.push(J.clone(),J.clone(),J.clone(),J.clone()),a.materialIndex=p,h.faces.push(a),h.faceVertexUvs[0].push([new THREE.Vector2(f/y,1-e/v),new THREE.Vector2(f/y,1-(e+1)/v),new THREE.Vector2((f+1)/y,1-(e+1)/v),new THREE.Vector2((f+1)/y,1-e/v)])}THREE.Geometry.call(this);var h=this;this.width=a;this.height=b;this.depth=c;this.widthSegments=d||1;this.heightSegments=e||1;this.depthSegments= +f||1;a=this.width/2;b=this.height/2;c=this.depth/2;g("z","y",-1,-1,this.depth,this.height,a,0);g("z","y",1,-1,this.depth,this.height,-a,1);g("x","z",1,1,this.width,this.depth,b,2);g("x","z",1,-1,this.width,this.depth,-b,3);g("x","y",1,-1,this.width,this.height,c,4);g("x","y",-1,-1,this.width,this.height,-c,5);this.computeCentroids();this.mergeVertices()};THREE.CubeGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.CylinderGeometry=function(a,b,c,d,e,f){THREE.Geometry.call(this);var a=void 0!==a?a:20,b=void 0!==b?b:20,c=void 0!==c?c:100,g=c/2,d=d||8,e=e||1,h,i,k=[],l=[];for(i=0;i<=e;i++){var m=[],n=[],s=i/e,r=s*(b-a)+a;for(h=0;h<=d;h++){var p=h/d,q=new THREE.Vector3;q.x=r*Math.sin(2*p*Math.PI);q.y=-s*c+g;q.z=r*Math.cos(2*p*Math.PI);this.vertices.push(q);m.push(this.vertices.length-1);n.push(new THREE.Vector2(p,1-s))}k.push(m);l.push(n)}c=(b-a)/c;for(h=0;h<d;h++){0!==a?(m=this.vertices[k[0][h]].clone(), +n=this.vertices[k[0][h+1]].clone()):(m=this.vertices[k[1][h]].clone(),n=this.vertices[k[1][h+1]].clone());m.setY(Math.sqrt(m.x*m.x+m.z*m.z)*c).normalize();n.setY(Math.sqrt(n.x*n.x+n.z*n.z)*c).normalize();for(i=0;i<e;i++){var s=k[i][h],r=k[i+1][h],p=k[i+1][h+1],q=k[i][h+1],y=m.clone(),v=m.clone(),z=n.clone(),t=n.clone(),A=l[i][h].clone(),I=l[i+1][h].clone(),C=l[i+1][h+1].clone(),x=l[i][h+1].clone();this.faces.push(new THREE.Face4(s,r,p,q,[y,v,z,t]));this.faceVertexUvs[0].push([A,I,C,x])}}if(!f&&0< +a){this.vertices.push(new THREE.Vector3(0,g,0));for(h=0;h<d;h++)s=k[0][h],r=k[0][h+1],p=this.vertices.length-1,y=new THREE.Vector3(0,1,0),v=new THREE.Vector3(0,1,0),z=new THREE.Vector3(0,1,0),A=l[0][h].clone(),I=l[0][h+1].clone(),C=new THREE.Vector2(I.u,0),this.faces.push(new THREE.Face3(s,r,p,[y,v,z])),this.faceVertexUvs[0].push([A,I,C])}if(!f&&0<b){this.vertices.push(new THREE.Vector3(0,-g,0));for(h=0;h<d;h++)s=k[i][h+1],r=k[i][h],p=this.vertices.length-1,y=new THREE.Vector3(0,-1,0),v=new THREE.Vector3(0, +-1,0),z=new THREE.Vector3(0,-1,0),A=l[i][h+1].clone(),I=l[i][h].clone(),C=new THREE.Vector2(I.u,1),this.faces.push(new THREE.Face3(s,r,p,[y,v,z])),this.faceVertexUvs[0].push([A,I,C])}this.computeCentroids();this.computeFaceNormals()};THREE.CylinderGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.ExtrudeGeometry=function(a,b){"undefined"!==typeof a&&(THREE.Geometry.call(this),a=a instanceof Array?a:[a],this.shapebb=a[a.length-1].getBoundingBox(),this.addShapeList(a,b),this.computeCentroids(),this.computeFaceNormals())};THREE.ExtrudeGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.ExtrudeGeometry.prototype.addShapeList=function(a,b){for(var c=a.length,d=0;d<c;d++)this.addShape(a[d],b)}; +THREE.ExtrudeGeometry.prototype.addShape=function(a,b){function c(a,b,c){b||console.log("die");return b.clone().multiplyScalar(c).add(a)}function d(a,b,c){var d=THREE.ExtrudeGeometry.__v1,e=THREE.ExtrudeGeometry.__v2,f=THREE.ExtrudeGeometry.__v3,g=THREE.ExtrudeGeometry.__v4,i=THREE.ExtrudeGeometry.__v5,h=THREE.ExtrudeGeometry.__v6;d.set(a.x-b.x,a.y-b.y);e.set(a.x-c.x,a.y-c.y);d=d.normalize();e=e.normalize();f.set(-d.y,d.x);g.set(e.y,-e.x);i.copy(a).add(f);h.copy(a).add(g);if(i.equals(h))return g.clone(); +i.copy(b).add(f);h.copy(c).add(g);f=d.dot(g);g=h.sub(i).dot(g);0===f&&(console.log("Either infinite or no solutions!"),0===g?console.log("Its finite solutions."):console.log("Too bad, no solutions."));g/=f;return 0>g?(b=Math.atan2(b.y-a.y,b.x-a.x),a=Math.atan2(c.y-a.y,c.x-a.x),b>a&&(a+=2*Math.PI),c=(b+a)/2,a=-Math.cos(c),c=-Math.sin(c),new THREE.Vector2(a,c)):d.multiplyScalar(g).add(i).sub(a).clone()}function e(c,d){var e,f;for(M=c.length;0<=--M;){e=M;f=M-1;0>f&&(f=c.length-1);for(var g=0,i=s+2*l, +g=0;g<i;g++){var h=fa*g,k=fa*(g+1),m=d+e+h,h=d+f+h,n=d+f+k,k=d+e+k,p=c,q=g,r=i,t=e,y=f,m=m+H,h=h+H,n=n+H,k=k+H;E.faces.push(new THREE.Face4(m,h,n,k,null,null,v));m=z.generateSideWallUV(E,a,p,b,m,h,n,k,q,r,t,y);E.faceVertexUvs[0].push(m)}}}function f(a,b,c){E.vertices.push(new THREE.Vector3(a,b,c))}function g(c,d,e,f){c+=H;d+=H;e+=H;E.faces.push(new THREE.Face3(c,d,e,null,null,y));c=f?z.generateBottomUV(E,a,b,c,d,e):z.generateTopUV(E,a,b,c,d,e);E.faceVertexUvs[0].push(c)}var h=void 0!==b.amount?b.amount: +100,i=void 0!==b.bevelThickness?b.bevelThickness:6,k=void 0!==b.bevelSize?b.bevelSize:i-2,l=void 0!==b.bevelSegments?b.bevelSegments:3,m=void 0!==b.bevelEnabled?b.bevelEnabled:!0,n=void 0!==b.curveSegments?b.curveSegments:12,s=void 0!==b.steps?b.steps:1,r=b.extrudePath,p,q=!1,y=b.material,v=b.extrudeMaterial,z=void 0!==b.UVGenerator?b.UVGenerator:THREE.ExtrudeGeometry.WorldUVGenerator,t,A,I,C;r&&(p=r.getSpacedPoints(s),q=!0,m=!1,t=void 0!==b.frames?b.frames:new THREE.TubeGeometry.FrenetFrames(r,s, +!1),A=new THREE.Vector3,I=new THREE.Vector3,C=new THREE.Vector3);m||(k=i=l=0);var x,G,J,E=this,H=this.vertices.length,n=a.extractPoints(n),B=n.shape,n=n.holes;if(r=!THREE.Shape.Utils.isClockWise(B)){B=B.reverse();G=0;for(J=n.length;G<J;G++)x=n[G],THREE.Shape.Utils.isClockWise(x)&&(n[G]=x.reverse());r=!1}var W=THREE.Shape.Utils.triangulateShape(B,n),r=B;G=0;for(J=n.length;G<J;G++)x=n[G],B=B.concat(x);var F,K,L,U,fa=B.length,Ca=W.length,$a=[],M=0,ca=r.length;F=ca-1;for(K=M+1;M<ca;M++,F++,K++)F===ca&& +(F=0),K===ca&&(K=0),$a[M]=d(r[M],r[F],r[K]);var qa=[],ha,ra=$a.concat();G=0;for(J=n.length;G<J;G++){x=n[G];ha=[];M=0;ca=x.length;F=ca-1;for(K=M+1;M<ca;M++,F++,K++)F===ca&&(F=0),K===ca&&(K=0),ha[M]=d(x[M],x[F],x[K]);qa.push(ha);ra=ra.concat(ha)}for(F=0;F<l;F++){x=F/l;L=i*(1-x);K=k*Math.sin(x*Math.PI/2);M=0;for(ca=r.length;M<ca;M++)U=c(r[M],$a[M],K),f(U.x,U.y,-L);G=0;for(J=n.length;G<J;G++){x=n[G];ha=qa[G];M=0;for(ca=x.length;M<ca;M++)U=c(x[M],ha[M],K),f(U.x,U.y,-L)}}K=k;for(M=0;M<fa;M++)U=m?c(B[M], +ra[M],K):B[M],q?(I.copy(t.normals[0]).multiplyScalar(U.x),A.copy(t.binormals[0]).multiplyScalar(U.y),C.copy(p[0]).add(I).add(A),f(C.x,C.y,C.z)):f(U.x,U.y,0);for(x=1;x<=s;x++)for(M=0;M<fa;M++)U=m?c(B[M],ra[M],K):B[M],q?(I.copy(t.normals[x]).multiplyScalar(U.x),A.copy(t.binormals[x]).multiplyScalar(U.y),C.copy(p[x]).add(I).add(A),f(C.x,C.y,C.z)):f(U.x,U.y,h/s*x);for(F=l-1;0<=F;F--){x=F/l;L=i*(1-x);K=k*Math.sin(x*Math.PI/2);M=0;for(ca=r.length;M<ca;M++)U=c(r[M],$a[M],K),f(U.x,U.y,h+L);G=0;for(J=n.length;G< +J;G++){x=n[G];ha=qa[G];M=0;for(ca=x.length;M<ca;M++)U=c(x[M],ha[M],K),q?f(U.x,U.y+p[s-1].y,p[s-1].x+L):f(U.x,U.y,h+L)}}if(m){i=0*fa;for(M=0;M<Ca;M++)h=W[M],g(h[2]+i,h[1]+i,h[0]+i,!0);i=fa*(s+2*l);for(M=0;M<Ca;M++)h=W[M],g(h[0]+i,h[1]+i,h[2]+i,!1)}else{for(M=0;M<Ca;M++)h=W[M],g(h[2],h[1],h[0],!0);for(M=0;M<Ca;M++)h=W[M],g(h[0]+fa*s,h[1]+fa*s,h[2]+fa*s,!1)}h=0;e(r,h);h+=r.length;G=0;for(J=n.length;G<J;G++)x=n[G],e(x,h),h+=x.length}; +THREE.ExtrudeGeometry.WorldUVGenerator={generateTopUV:function(a,b,c,d,e,f){b=a.vertices[e].x;e=a.vertices[e].y;c=a.vertices[f].x;f=a.vertices[f].y;return[new THREE.Vector2(a.vertices[d].x,a.vertices[d].y),new THREE.Vector2(b,e),new THREE.Vector2(c,f)]},generateBottomUV:function(a,b,c,d,e,f){return this.generateTopUV(a,b,c,d,e,f)},generateSideWallUV:function(a,b,c,d,e,f,g,h){var b=a.vertices[e].x,c=a.vertices[e].y,e=a.vertices[e].z,d=a.vertices[f].x,i=a.vertices[f].y,f=a.vertices[f].z,k=a.vertices[g].x, +l=a.vertices[g].y,g=a.vertices[g].z,m=a.vertices[h].x,n=a.vertices[h].y,a=a.vertices[h].z;return 0.01>Math.abs(c-i)?[new THREE.Vector2(b,1-e),new THREE.Vector2(d,1-f),new THREE.Vector2(k,1-g),new THREE.Vector2(m,1-a)]:[new THREE.Vector2(c,1-e),new THREE.Vector2(i,1-f),new THREE.Vector2(l,1-g),new THREE.Vector2(n,1-a)]}};THREE.ExtrudeGeometry.__v1=new THREE.Vector2;THREE.ExtrudeGeometry.__v2=new THREE.Vector2;THREE.ExtrudeGeometry.__v3=new THREE.Vector2;THREE.ExtrudeGeometry.__v4=new THREE.Vector2; +THREE.ExtrudeGeometry.__v5=new THREE.Vector2;THREE.ExtrudeGeometry.__v6=new THREE.Vector2;THREE.ShapeGeometry=function(a,b){THREE.Geometry.call(this);!1===a instanceof Array&&(a=[a]);this.shapebb=a[a.length-1].getBoundingBox();this.addShapeList(a,b);this.computeCentroids();this.computeFaceNormals()};THREE.ShapeGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.ShapeGeometry.prototype.addShapeList=function(a,b){for(var c=0,d=a.length;c<d;c++)this.addShape(a[c],b);return this}; +THREE.ShapeGeometry.prototype.addShape=function(a,b){void 0===b&&(b={});var c=b.material,d=void 0===b.UVGenerator?THREE.ExtrudeGeometry.WorldUVGenerator:b.UVGenerator,e,f,g,h=this.vertices.length;e=a.extractPoints(void 0!==b.curveSegments?b.curveSegments:12);var i=e.shape,k=e.holes;if(!THREE.Shape.Utils.isClockWise(i)){i=i.reverse();e=0;for(f=k.length;e<f;e++)g=k[e],THREE.Shape.Utils.isClockWise(g)&&(k[e]=g.reverse())}var l=THREE.Shape.Utils.triangulateShape(i,k);e=0;for(f=k.length;e<f;e++)g=k[e], +i=i.concat(g);k=i.length;f=l.length;for(e=0;e<k;e++)g=i[e],this.vertices.push(new THREE.Vector3(g.x,g.y,0));for(e=0;e<f;e++)k=l[e],i=k[0]+h,g=k[1]+h,k=k[2]+h,this.faces.push(new THREE.Face3(i,g,k,null,null,c)),this.faceVertexUvs[0].push(d.generateBottomUV(this,a,b,i,g,k))};THREE.LatheGeometry=function(a,b,c,d){THREE.Geometry.call(this);for(var b=b||12,c=c||0,d=d||2*Math.PI,e=1/(a.length-1),f=1/b,g=0,h=b;g<=h;g++)for(var i=c+g*f*d,k=Math.cos(i),l=Math.sin(i),i=0,m=a.length;i<m;i++){var n=a[i],s=new THREE.Vector3;s.x=k*n.x-l*n.y;s.y=l*n.x+k*n.y;s.z=n.z;this.vertices.push(s)}c=a.length;g=0;for(h=b;g<h;g++){i=0;for(m=a.length-1;i<m;i++)d=b=i+c*g,l=b+c,k=b+1+c,this.faces.push(new THREE.Face4(d,l,k,b+1)),k=g*f,b=i*e,d=k+f,l=b+e,this.faceVertexUvs[0].push([new THREE.Vector2(k, +b),new THREE.Vector2(d,b),new THREE.Vector2(d,l),new THREE.Vector2(k,l)])}this.mergeVertices();this.computeCentroids();this.computeFaceNormals();this.computeVertexNormals()};THREE.LatheGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.PlaneGeometry=function(a,b,c,d){THREE.Geometry.call(this);this.width=a;this.height=b;this.widthSegments=c||1;this.heightSegments=d||1;for(var c=a/2,e=b/2,d=this.widthSegments,f=this.heightSegments,g=d+1,h=f+1,i=this.width/d,k=this.height/f,l=new THREE.Vector3(0,0,1),a=0;a<h;a++)for(b=0;b<g;b++)this.vertices.push(new THREE.Vector3(b*i-c,-(a*k-e),0));for(a=0;a<f;a++)for(b=0;b<d;b++)c=new THREE.Face4(b+g*a,b+g*(a+1),b+1+g*(a+1),b+1+g*a),c.normal.copy(l),c.vertexNormals.push(l.clone(),l.clone(), +l.clone(),l.clone()),this.faces.push(c),this.faceVertexUvs[0].push([new THREE.Vector2(b/d,1-a/f),new THREE.Vector2(b/d,1-(a+1)/f),new THREE.Vector2((b+1)/d,1-(a+1)/f),new THREE.Vector2((b+1)/d,1-a/f)]);this.computeCentroids()};THREE.PlaneGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.SphereGeometry=function(a,b,c,d,e,f,g){THREE.Geometry.call(this);this.radius=a||50;this.widthSegments=Math.max(3,Math.floor(b)||8);this.heightSegments=Math.max(2,Math.floor(c)||6);for(var d=void 0!==d?d:0,e=void 0!==e?e:2*Math.PI,f=void 0!==f?f:0,g=void 0!==g?g:Math.PI,h=[],i=[],c=0;c<=this.heightSegments;c++){for(var k=[],l=[],b=0;b<=this.widthSegments;b++){var m=b/this.widthSegments,n=c/this.heightSegments,s=new THREE.Vector3;s.x=-this.radius*Math.cos(d+m*e)*Math.sin(f+n*g);s.y=this.radius* +Math.cos(f+n*g);s.z=this.radius*Math.sin(d+m*e)*Math.sin(f+n*g);this.vertices.push(s);k.push(this.vertices.length-1);l.push(new THREE.Vector2(m,1-n))}h.push(k);i.push(l)}for(c=0;c<this.heightSegments;c++)for(b=0;b<this.widthSegments;b++){var d=h[c][b+1],e=h[c][b],f=h[c+1][b],g=h[c+1][b+1],k=this.vertices[d].clone().normalize(),l=this.vertices[e].clone().normalize(),m=this.vertices[f].clone().normalize(),n=this.vertices[g].clone().normalize(),s=i[c][b+1].clone(),r=i[c][b].clone(),p=i[c+1][b].clone(), +q=i[c+1][b+1].clone();Math.abs(this.vertices[d].y)===this.radius?(this.faces.push(new THREE.Face3(d,f,g,[k,m,n])),this.faceVertexUvs[0].push([s,p,q])):Math.abs(this.vertices[f].y)===this.radius?(this.faces.push(new THREE.Face3(d,e,f,[k,l,m])),this.faceVertexUvs[0].push([s,r,p])):(this.faces.push(new THREE.Face4(d,e,f,g,[k,l,m,n])),this.faceVertexUvs[0].push([s,r,p,q]))}this.computeCentroids();this.computeFaceNormals();this.boundingSphere=new THREE.Sphere(new THREE.Vector3,a)}; +THREE.SphereGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.TextGeometry=function(a,b){var c=THREE.FontUtils.generateShapes(a,b);b.amount=void 0!==b.height?b.height:50;void 0===b.bevelThickness&&(b.bevelThickness=10);void 0===b.bevelSize&&(b.bevelSize=8);void 0===b.bevelEnabled&&(b.bevelEnabled=!1);THREE.ExtrudeGeometry.call(this,c,b)};THREE.TextGeometry.prototype=Object.create(THREE.ExtrudeGeometry.prototype);THREE.TorusGeometry=function(a,b,c,d,e){THREE.Geometry.call(this);this.radius=a||100;this.tube=b||40;this.radialSegments=c||8;this.tubularSegments=d||6;this.arc=e||2*Math.PI;e=new THREE.Vector3;a=[];b=[];for(c=0;c<=this.radialSegments;c++)for(d=0;d<=this.tubularSegments;d++){var f=d/this.tubularSegments*this.arc,g=2*c/this.radialSegments*Math.PI;e.x=this.radius*Math.cos(f);e.y=this.radius*Math.sin(f);var h=new THREE.Vector3;h.x=(this.radius+this.tube*Math.cos(g))*Math.cos(f);h.y=(this.radius+this.tube* +Math.cos(g))*Math.sin(f);h.z=this.tube*Math.sin(g);this.vertices.push(h);a.push(new THREE.Vector2(d/this.tubularSegments,c/this.radialSegments));b.push(h.clone().sub(e).normalize())}for(c=1;c<=this.radialSegments;c++)for(d=1;d<=this.tubularSegments;d++){var e=(this.tubularSegments+1)*c+d-1,f=(this.tubularSegments+1)*(c-1)+d-1,g=(this.tubularSegments+1)*(c-1)+d,h=(this.tubularSegments+1)*c+d,i=new THREE.Face4(e,f,g,h,[b[e],b[f],b[g],b[h]]);i.normal.add(b[e]);i.normal.add(b[f]);i.normal.add(b[g]);i.normal.add(b[h]); +i.normal.normalize();this.faces.push(i);this.faceVertexUvs[0].push([a[e].clone(),a[f].clone(),a[g].clone(),a[h].clone()])}this.computeCentroids()};THREE.TorusGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.TorusKnotGeometry=function(a,b,c,d,e,f,g){function h(a,b,c,d,e,f){var g=Math.cos(a);Math.cos(b);b=Math.sin(a);a*=c/d;c=Math.cos(a);g*=0.5*e*(2+c);b=0.5*e*(2+c)*b;e=0.5*f*e*Math.sin(a);return new THREE.Vector3(g,b,e)}THREE.Geometry.call(this);this.radius=a||100;this.tube=b||40;this.radialSegments=c||64;this.tubularSegments=d||8;this.p=e||2;this.q=f||3;this.heightScale=g||1;this.grid=Array(this.radialSegments);c=new THREE.Vector3;d=new THREE.Vector3;e=new THREE.Vector3;for(a=0;a<this.radialSegments;++a){this.grid[a]= +Array(this.tubularSegments);for(b=0;b<this.tubularSegments;++b){var i=2*(a/this.radialSegments)*this.p*Math.PI,g=2*(b/this.tubularSegments)*Math.PI,f=h(i,g,this.q,this.p,this.radius,this.heightScale),i=h(i+0.01,g,this.q,this.p,this.radius,this.heightScale);c.subVectors(i,f);d.addVectors(i,f);e.crossVectors(c,d);d.crossVectors(e,c);e.normalize();d.normalize();i=-this.tube*Math.cos(g);g=this.tube*Math.sin(g);f.x+=i*d.x+g*e.x;f.y+=i*d.y+g*e.y;f.z+=i*d.z+g*e.z;this.grid[a][b]=this.vertices.push(new THREE.Vector3(f.x, +f.y,f.z))-1}}for(a=0;a<this.radialSegments;++a)for(b=0;b<this.tubularSegments;++b){var e=(a+1)%this.radialSegments,f=(b+1)%this.tubularSegments,c=this.grid[a][b],d=this.grid[e][b],e=this.grid[e][f],f=this.grid[a][f],g=new THREE.Vector2(a/this.radialSegments,b/this.tubularSegments),i=new THREE.Vector2((a+1)/this.radialSegments,b/this.tubularSegments),k=new THREE.Vector2((a+1)/this.radialSegments,(b+1)/this.tubularSegments),l=new THREE.Vector2(a/this.radialSegments,(b+1)/this.tubularSegments);this.faces.push(new THREE.Face4(c, +d,e,f));this.faceVertexUvs[0].push([g,i,k,l])}this.computeCentroids();this.computeFaceNormals();this.computeVertexNormals()};THREE.TorusKnotGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.TubeGeometry=function(a,b,c,d,e,f){THREE.Geometry.call(this);this.path=a;this.segments=b||64;this.radius=c||1;this.radiusSegments=d||8;this.closed=e||!1;f&&(this.debug=new THREE.Object3D);this.grid=[];var g,h,e=this.segments+1,i,k,l,f=new THREE.Vector3,m,n,s,b=new THREE.TubeGeometry.FrenetFrames(this.path,this.segments,this.closed);m=b.tangents;n=b.normals;s=b.binormals;this.tangents=m;this.normals=n;this.binormals=s;for(b=0;b<e;b++){this.grid[b]=[];d=b/(e-1);l=a.getPointAt(d);d=m[b];g=n[b]; +h=s[b];this.debug&&(this.debug.add(new THREE.ArrowHelper(d,l,c,255)),this.debug.add(new THREE.ArrowHelper(g,l,c,16711680)),this.debug.add(new THREE.ArrowHelper(h,l,c,65280)));for(d=0;d<this.radiusSegments;d++)i=2*(d/this.radiusSegments)*Math.PI,k=-this.radius*Math.cos(i),i=this.radius*Math.sin(i),f.copy(l),f.x+=k*g.x+i*h.x,f.y+=k*g.y+i*h.y,f.z+=k*g.z+i*h.z,this.grid[b][d]=this.vertices.push(new THREE.Vector3(f.x,f.y,f.z))-1}for(b=0;b<this.segments;b++)for(d=0;d<this.radiusSegments;d++)e=this.closed? +(b+1)%this.segments:b+1,f=(d+1)%this.radiusSegments,a=this.grid[b][d],c=this.grid[e][d],e=this.grid[e][f],f=this.grid[b][f],m=new THREE.Vector2(b/this.segments,d/this.radiusSegments),n=new THREE.Vector2((b+1)/this.segments,d/this.radiusSegments),s=new THREE.Vector2((b+1)/this.segments,(d+1)/this.radiusSegments),g=new THREE.Vector2(b/this.segments,(d+1)/this.radiusSegments),this.faces.push(new THREE.Face4(a,c,e,f)),this.faceVertexUvs[0].push([m,n,s,g]);this.computeCentroids();this.computeFaceNormals(); +this.computeVertexNormals()};THREE.TubeGeometry.prototype=Object.create(THREE.Geometry.prototype); +THREE.TubeGeometry.FrenetFrames=function(a,b,c){new THREE.Vector3;var d=new THREE.Vector3;new THREE.Vector3;var e=[],f=[],g=[],h=new THREE.Vector3,i=new THREE.Matrix4,b=b+1,k,l,m;this.tangents=e;this.normals=f;this.binormals=g;for(k=0;k<b;k++)l=k/(b-1),e[k]=a.getTangentAt(l),e[k].normalize();f[0]=new THREE.Vector3;g[0]=new THREE.Vector3;a=Number.MAX_VALUE;k=Math.abs(e[0].x);l=Math.abs(e[0].y);m=Math.abs(e[0].z);k<=a&&(a=k,d.set(1,0,0));l<=a&&(a=l,d.set(0,1,0));m<=a&&d.set(0,0,1);h.crossVectors(e[0], +d).normalize();f[0].crossVectors(e[0],h);g[0].crossVectors(e[0],f[0]);for(k=1;k<b;k++)f[k]=f[k-1].clone(),g[k]=g[k-1].clone(),h.crossVectors(e[k-1],e[k]),1E-4<h.length()&&(h.normalize(),d=Math.acos(e[k-1].dot(e[k])),f[k].applyMatrix4(i.makeRotationAxis(h,d))),g[k].crossVectors(e[k],f[k]);if(c){d=Math.acos(f[0].dot(f[b-1]));d/=b-1;0<e[0].dot(h.crossVectors(f[0],f[b-1]))&&(d=-d);for(k=1;k<b;k++)f[k].applyMatrix4(i.makeRotationAxis(e[k],d*k)),g[k].crossVectors(e[k],f[k])}};THREE.PolyhedronGeometry=function(a,b,c,d){function e(a){var b=a.normalize().clone();b.index=i.vertices.push(b)-1;var c=Math.atan2(a.z,-a.x)/2/Math.PI+0.5,a=Math.atan2(-a.y,Math.sqrt(a.x*a.x+a.z*a.z))/Math.PI+0.5;b.uv=new THREE.Vector2(c,1-a);return b}function f(a,b,c,d){1>d?(d=new THREE.Face3(a.index,b.index,c.index,[a.clone(),b.clone(),c.clone()]),d.centroid.add(a).add(b).add(c).divideScalar(3),d.normal=d.centroid.clone().normalize(),i.faces.push(d),d=Math.atan2(d.centroid.z,-d.centroid.x),i.faceVertexUvs[0].push([h(a.uv, +a,d),h(b.uv,b,d),h(c.uv,c,d)])):(d-=1,f(a,g(a,b),g(a,c),d),f(g(a,b),b,g(b,c),d),f(g(a,c),g(b,c),c,d),f(g(a,b),g(b,c),g(a,c),d))}function g(a,b){m[a.index]||(m[a.index]=[]);m[b.index]||(m[b.index]=[]);var c=m[a.index][b.index];void 0===c&&(m[a.index][b.index]=m[b.index][a.index]=c=e((new THREE.Vector3).addVectors(a,b).divideScalar(2)));return c}function h(a,b,c){0>c&&1===a.x&&(a=new THREE.Vector2(a.x-1,a.y));0===b.x&&0===b.z&&(a=new THREE.Vector2(c/2/Math.PI+0.5,a.y));return a}THREE.Geometry.call(this); +for(var c=c||1,d=d||0,i=this,k=0,l=a.length;k<l;k++)e(new THREE.Vector3(a[k][0],a[k][1],a[k][2]));for(var m=[],a=this.vertices,k=0,l=b.length;k<l;k++)f(a[b[k][0]],a[b[k][1]],a[b[k][2]],d);this.mergeVertices();k=0;for(l=this.vertices.length;k<l;k++)this.vertices[k].multiplyScalar(c);this.computeCentroids();this.boundingSphere=new THREE.Sphere(new THREE.Vector3,c)};THREE.PolyhedronGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.IcosahedronGeometry=function(a,b){var c=(1+Math.sqrt(5))/2;THREE.PolyhedronGeometry.call(this,[[-1,c,0],[1,c,0],[-1,-c,0],[1,-c,0],[0,-1,c],[0,1,c],[0,-1,-c],[0,1,-c],[c,0,-1],[c,0,1],[-c,0,-1],[-c,0,1]],[[0,11,5],[0,5,1],[0,1,7],[0,7,10],[0,10,11],[1,5,9],[5,11,4],[11,10,2],[10,7,6],[7,1,8],[3,9,4],[3,4,2],[3,2,6],[3,6,8],[3,8,9],[4,9,5],[2,4,11],[6,2,10],[8,6,7],[9,8,1]],a,b)};THREE.IcosahedronGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.OctahedronGeometry=function(a,b){THREE.PolyhedronGeometry.call(this,[[1,0,0],[-1,0,0],[0,1,0],[0,-1,0],[0,0,1],[0,0,-1]],[[0,2,4],[0,4,3],[0,3,5],[0,5,2],[1,2,5],[1,5,3],[1,3,4],[1,4,2]],a,b)};THREE.OctahedronGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.TetrahedronGeometry=function(a,b){THREE.PolyhedronGeometry.call(this,[[1,1,1],[-1,-1,1],[-1,1,-1],[1,-1,-1]],[[2,1,0],[0,3,2],[1,3,0],[2,3,1]],a,b)};THREE.TetrahedronGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.ParametricGeometry=function(a,b,c,d){THREE.Geometry.call(this);var e=this.vertices,f=this.faces,g=this.faceVertexUvs[0],d=void 0===d?!1:d,h,i,k,l,m=b+1;for(h=0;h<=c;h++){l=h/c;for(i=0;i<=b;i++)k=i/b,k=a(k,l),e.push(k)}var n,s,r,p;for(h=0;h<c;h++)for(i=0;i<b;i++)a=h*m+i,e=h*m+i+1,l=(h+1)*m+i,k=(h+1)*m+i+1,n=new THREE.Vector2(i/b,h/c),s=new THREE.Vector2((i+1)/b,h/c),r=new THREE.Vector2(i/b,(h+1)/c),p=new THREE.Vector2((i+1)/b,(h+1)/c),d?(f.push(new THREE.Face3(a,e,l)),f.push(new THREE.Face3(e, +k,l)),g.push([n,s,r]),g.push([s,p,r])):(f.push(new THREE.Face4(a,e,k,l)),g.push([n,s,p,r]));this.computeCentroids();this.computeFaceNormals();this.computeVertexNormals()};THREE.ParametricGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.ConvexGeometry=function(a){function b(a){var b=a.length();return new THREE.Vector2(a.x/b,a.y/b)}THREE.Geometry.call(this);for(var c=[[0,1,2],[0,2,1]],d=3;d<a.length;d++){var e=d,f=a[e].clone(),g=f.length();f.x+=g*2E-6*(Math.random()-0.5);f.y+=g*2E-6*(Math.random()-0.5);f.z+=g*2E-6*(Math.random()-0.5);for(var g=[],h=0;h<c.length;){var i=c[h],k=f,l=a[i[0]],m;m=l;var n=a[i[1]],s=a[i[2]],r=new THREE.Vector3,p=new THREE.Vector3;r.subVectors(s,n);p.subVectors(m,n);r.cross(p);r.normalize();m=r;l=m.dot(l); +if(m.dot(k)>=l){for(k=0;3>k;k++){l=[i[k],i[(k+1)%3]];m=!0;for(n=0;n<g.length;n++)if(g[n][0]===l[1]&&g[n][1]===l[0]){g[n]=g[g.length-1];g.pop();m=!1;break}m&&g.push(l)}c[h]=c[c.length-1];c.pop()}else h++}for(n=0;n<g.length;n++)c.push([g[n][0],g[n][1],e])}e=0;f=Array(a.length);for(d=0;d<c.length;d++){g=c[d];for(h=0;3>h;h++)void 0===f[g[h]]&&(f[g[h]]=e++,this.vertices.push(a[g[h]])),g[h]=f[g[h]]}for(d=0;d<c.length;d++)this.faces.push(new THREE.Face3(c[d][0],c[d][1],c[d][2]));for(d=0;d<this.faces.length;d++)g= +this.faces[d],this.faceVertexUvs[0].push([b(this.vertices[g.a]),b(this.vertices[g.b]),b(this.vertices[g.c])]);this.computeCentroids();this.computeFaceNormals();this.computeVertexNormals()};THREE.ConvexGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.AxisHelper=function(a){var b=new THREE.Geometry;b.vertices.push(new THREE.Vector3,new THREE.Vector3(a||1,0,0),new THREE.Vector3,new THREE.Vector3(0,a||1,0),new THREE.Vector3,new THREE.Vector3(0,0,a||1));b.colors.push(new THREE.Color(16711680),new THREE.Color(16755200),new THREE.Color(65280),new THREE.Color(11206400),new THREE.Color(255),new THREE.Color(43775));a=new THREE.LineBasicMaterial({vertexColors:THREE.VertexColors});THREE.Line.call(this,b,a,THREE.LinePieces)}; +THREE.AxisHelper.prototype=Object.create(THREE.Line.prototype);THREE.ArrowHelper=function(a,b,c,d){THREE.Object3D.call(this);void 0===c&&(c=20);void 0===d&&(d=16776960);var e=new THREE.Geometry;e.vertices.push(new THREE.Vector3(0,0,0));e.vertices.push(new THREE.Vector3(0,1,0));this.line=new THREE.Line(e,new THREE.LineBasicMaterial({color:d}));this.add(this.line);e=new THREE.CylinderGeometry(0,0.05,0.25,5,1);this.cone=new THREE.Mesh(e,new THREE.MeshBasicMaterial({color:d}));this.cone.position.set(0,1,0);this.add(this.cone);b instanceof THREE.Vector3&&(this.position= +b);this.setDirection(a);this.setLength(c)};THREE.ArrowHelper.prototype=Object.create(THREE.Object3D.prototype);THREE.ArrowHelper.prototype.setDirection=function(a){var b=THREE.ArrowHelper.__v1.copy(a).normalize();0.999<b.y?this.rotation.set(0,0,0):-0.999>b.y?this.rotation.set(Math.PI,0,0):(a=THREE.ArrowHelper.__v2.set(b.z,0,-b.x).normalize(),b=Math.acos(b.y),a=THREE.ArrowHelper.__q1.setFromAxisAngle(a,b),this.rotation.setEulerFromQuaternion(a,this.eulerOrder))}; +THREE.ArrowHelper.prototype.setLength=function(a){this.scale.set(a,a,a)};THREE.ArrowHelper.prototype.setColor=function(a){this.line.material.color.setHex(a);this.cone.material.color.setHex(a)};THREE.ArrowHelper.__v1=new THREE.Vector3;THREE.ArrowHelper.__v2=new THREE.Vector3;THREE.ArrowHelper.__q1=new THREE.Quaternion;THREE.CameraHelper=function(a){function b(a,b,d){c(a,d);c(b,d)}function c(a,b){d.geometry.vertices.push(new THREE.Vector3);d.geometry.colors.push(new THREE.Color(b));void 0===d.pointMap[a]&&(d.pointMap[a]=[]);d.pointMap[a].push(d.geometry.vertices.length-1)}THREE.Line.call(this);var d=this;this.geometry=new THREE.Geometry;this.material=new THREE.LineBasicMaterial({color:16777215,vertexColors:THREE.FaceColors});this.type=THREE.LinePieces;this.matrixWorld=a.matrixWorld;this.matrixAutoUpdate=!1;this.pointMap= +{};b("n1","n2",16755200);b("n2","n4",16755200);b("n4","n3",16755200);b("n3","n1",16755200);b("f1","f2",16755200);b("f2","f4",16755200);b("f4","f3",16755200);b("f3","f1",16755200);b("n1","f1",16755200);b("n2","f2",16755200);b("n3","f3",16755200);b("n4","f4",16755200);b("p","n1",16711680);b("p","n2",16711680);b("p","n3",16711680);b("p","n4",16711680);b("u1","u2",43775);b("u2","u3",43775);b("u3","u1",43775);b("c","t",16777215);b("p","c",3355443);b("cn1","cn2",3355443);b("cn3","cn4",3355443);b("cf1", +"cf2",3355443);b("cf3","cf4",3355443);this.camera=a;this.update(a)};THREE.CameraHelper.prototype=Object.create(THREE.Line.prototype); +THREE.CameraHelper.prototype.update=function(){function a(a,d,e,f){THREE.CameraHelper.__v.set(d,e,f);THREE.CameraHelper.__projector.unprojectVector(THREE.CameraHelper.__v,THREE.CameraHelper.__c);a=b.pointMap[a];if(void 0!==a){d=0;for(e=a.length;d<e;d++)b.geometry.vertices[a[d]].copy(THREE.CameraHelper.__v)}}var b=this;THREE.CameraHelper.__c.projectionMatrix.copy(this.camera.projectionMatrix);a("c",0,0,-1);a("t",0,0,1);a("n1",-1,-1,-1);a("n2",1,-1,-1);a("n3",-1,1,-1);a("n4",1,1,-1);a("f1",-1,-1,1); +a("f2",1,-1,1);a("f3",-1,1,1);a("f4",1,1,1);a("u1",0.7,1.1,-1);a("u2",-0.7,1.1,-1);a("u3",0,2,-1);a("cf1",-1,0,1);a("cf2",1,0,1);a("cf3",0,-1,1);a("cf4",0,1,1);a("cn1",-1,0,-1);a("cn2",1,0,-1);a("cn3",0,-1,-1);a("cn4",0,1,-1);this.geometry.verticesNeedUpdate=!0};THREE.CameraHelper.__projector=new THREE.Projector;THREE.CameraHelper.__v=new THREE.Vector3;THREE.CameraHelper.__c=new THREE.Camera;THREE.DirectionalLightHelper=function(a,b){THREE.Object3D.call(this);this.light=a;this.position=a.position;this.direction=new THREE.Vector3;this.direction.subVectors(a.target.position,a.position);var c=THREE.Math.clamp(a.intensity,0,1);this.color=a.color.clone();this.color.multiplyScalar(c);var c=this.color.getHex(),d=new THREE.SphereGeometry(b,16,8),e=new THREE.AsteriskGeometry(1.25*b,2.25*b),f=new THREE.MeshBasicMaterial({color:c,fog:!1}),g=new THREE.LineBasicMaterial({color:c,fog:!1});this.lightSphere= +new THREE.Mesh(d,f);this.lightRays=new THREE.Line(e,g,THREE.LinePieces);this.add(this.lightSphere);this.add(this.lightRays);this.lightSphere.properties.isGizmo=!0;this.lightSphere.properties.gizmoSubject=a;this.lightSphere.properties.gizmoRoot=this;this.targetSphere=null;void 0!==a.target.properties.targetInverse&&(d=new THREE.SphereGeometry(b,8,4),e=new THREE.MeshBasicMaterial({color:c,wireframe:!0,fog:!1}),this.targetSphere=new THREE.Mesh(d,e),this.targetSphere.position=a.target.position,this.targetSphere.properties.isGizmo= +!0,this.targetSphere.properties.gizmoSubject=a.target,this.targetSphere.properties.gizmoRoot=this.targetSphere,c=new THREE.LineDashedMaterial({color:c,dashSize:4,gapSize:4,opacity:0.75,transparent:!0,fog:!1}),d=new THREE.Geometry,d.vertices.push(this.position.clone()),d.vertices.push(this.targetSphere.position.clone()),d.computeLineDistances(),this.targetLine=new THREE.Line(d,c),this.targetLine.properties.isGizmo=!0);this.properties.isGizmo=!0};THREE.DirectionalLightHelper.prototype=Object.create(THREE.Object3D.prototype); +THREE.DirectionalLightHelper.prototype.update=function(){this.direction.subVectors(this.light.target.position,this.light.position);var a=THREE.Math.clamp(this.light.intensity,0,1);this.color.copy(this.light.color);this.color.multiplyScalar(a);this.lightSphere.material.color.copy(this.color);this.lightRays.material.color.copy(this.color);null!==this.targetSphere&&(this.targetSphere.material.color.copy(this.color),this.targetLine.material.color.copy(this.color),this.targetLine.geometry.vertices[0].copy(this.light.position), +this.targetLine.geometry.vertices[1].copy(this.light.target.position),this.targetLine.geometry.computeLineDistances(),this.targetLine.geometry.verticesNeedUpdate=!0)};THREE.HemisphereLightHelper=function(a,b,c){THREE.Object3D.call(this);this.light=a;this.position=a.position;var d=THREE.Math.clamp(a.intensity,0,1);this.color=a.color.clone();this.color.multiplyScalar(d);var e=this.color.getHex();this.groundColor=a.groundColor.clone();this.groundColor.multiplyScalar(d);for(var d=this.groundColor.getHex(),f=new THREE.SphereGeometry(b,16,8,0,2*Math.PI,0,0.5*Math.PI),g=new THREE.SphereGeometry(b,16,8,0,2*Math.PI,0.5*Math.PI,Math.PI),h=new THREE.MeshBasicMaterial({color:e, +fog:!1}),i=new THREE.MeshBasicMaterial({color:d,fog:!1}),k=0,l=f.faces.length;k<l;k++)f.faces[k].materialIndex=0;k=0;for(l=g.faces.length;k<l;k++)g.faces[k].materialIndex=1;THREE.GeometryUtils.merge(f,g);this.lightSphere=new THREE.Mesh(f,new THREE.MeshFaceMaterial([h,i]));this.lightArrow=new THREE.ArrowHelper(new THREE.Vector3(0,1,0),new THREE.Vector3(0,1.1*(b+c),0),c,e);this.lightArrow.rotation.x=Math.PI;this.lightArrowGround=new THREE.ArrowHelper(new THREE.Vector3(0,1,0),new THREE.Vector3(0,-1.1* +(b+c),0),c,d);b=new THREE.Object3D;b.rotation.x=0.5*-Math.PI;b.add(this.lightSphere);b.add(this.lightArrow);b.add(this.lightArrowGround);this.add(b);this.lightSphere.properties.isGizmo=!0;this.lightSphere.properties.gizmoSubject=a;this.lightSphere.properties.gizmoRoot=this;this.properties.isGizmo=!0;this.target=new THREE.Vector3;this.lookAt(this.target)};THREE.HemisphereLightHelper.prototype=Object.create(THREE.Object3D.prototype); +THREE.HemisphereLightHelper.prototype.update=function(){var a=THREE.Math.clamp(this.light.intensity,0,1);this.color.copy(this.light.color);this.color.multiplyScalar(a);this.groundColor.copy(this.light.groundColor);this.groundColor.multiplyScalar(a);this.lightSphere.material.materials[0].color.copy(this.color);this.lightSphere.material.materials[1].color.copy(this.groundColor);this.lightArrow.setColor(this.color.getHex());this.lightArrowGround.setColor(this.groundColor.getHex());this.lookAt(this.target)};THREE.PointLightHelper=function(a,b){THREE.Object3D.call(this);this.light=a;this.position=a.position;var c=THREE.Math.clamp(a.intensity,0,1);this.color=a.color.clone();this.color.multiplyScalar(c);var d=this.color.getHex(),c=new THREE.SphereGeometry(b,16,8),e=new THREE.AsteriskGeometry(1.25*b,2.25*b),f=new THREE.IcosahedronGeometry(1,2),g=new THREE.MeshBasicMaterial({color:d,fog:!1}),h=new THREE.LineBasicMaterial({color:d,fog:!1}),d=new THREE.MeshBasicMaterial({color:d,fog:!1,wireframe:!0,opacity:0.1, +transparent:!0});this.lightSphere=new THREE.Mesh(c,g);this.lightRays=new THREE.Line(e,h,THREE.LinePieces);this.lightDistance=new THREE.Mesh(f,d);c=a.distance;0===c?this.lightDistance.visible=!1:this.lightDistance.scale.set(c,c,c);this.add(this.lightSphere);this.add(this.lightRays);this.add(this.lightDistance);this.lightSphere.properties.isGizmo=!0;this.lightSphere.properties.gizmoSubject=a;this.lightSphere.properties.gizmoRoot=this;this.properties.isGizmo=!0};THREE.PointLightHelper.prototype=Object.create(THREE.Object3D.prototype); +THREE.PointLightHelper.prototype.update=function(){var a=THREE.Math.clamp(this.light.intensity,0,1);this.color.copy(this.light.color);this.color.multiplyScalar(a);this.lightSphere.material.color.copy(this.color);this.lightRays.material.color.copy(this.color);this.lightDistance.material.color.copy(this.color);a=this.light.distance;0===a?this.lightDistance.visible=!1:(this.lightDistance.visible=!0,this.lightDistance.scale.set(a,a,a))};THREE.SpotLightHelper=function(a,b){THREE.Object3D.call(this);this.light=a;this.position=a.position;this.direction=new THREE.Vector3;this.direction.subVectors(a.target.position,a.position);var c=THREE.Math.clamp(a.intensity,0,1);this.color=a.color.clone();this.color.multiplyScalar(c);var c=this.color.getHex(),d=new THREE.SphereGeometry(b,16,8),e=new THREE.AsteriskGeometry(1.25*b,2.25*b),f=new THREE.CylinderGeometry(1E-4,1,1,8,1,!0),g=new THREE.Matrix4;g.rotateX(-Math.PI/2);g.translate(new THREE.Vector3(0, +-0.5,0));f.applyMatrix(g);var h=new THREE.MeshBasicMaterial({color:c,fog:!1}),g=new THREE.LineBasicMaterial({color:c,fog:!1}),i=new THREE.MeshBasicMaterial({color:c,fog:!1,wireframe:!0,opacity:0.3,transparent:!0});this.lightSphere=new THREE.Mesh(d,h);this.lightCone=new THREE.Mesh(f,i);d=a.distance?a.distance:1E4;f=2*d*Math.tan(0.5*a.angle);this.lightCone.scale.set(f,f,d);this.lightRays=new THREE.Line(e,g,THREE.LinePieces);this.gyroscope=new THREE.Gyroscope;this.gyroscope.add(this.lightSphere);this.gyroscope.add(this.lightRays); +this.add(this.gyroscope);this.add(this.lightCone);this.lookAt(a.target.position);this.lightSphere.properties.isGizmo=!0;this.lightSphere.properties.gizmoSubject=a;this.lightSphere.properties.gizmoRoot=this;this.targetSphere=null;void 0!==a.target.properties.targetInverse&&(e=new THREE.SphereGeometry(b,8,4),g=new THREE.MeshBasicMaterial({color:c,wireframe:!0,fog:!1}),this.targetSphere=new THREE.Mesh(e,g),this.targetSphere.position=a.target.position,this.targetSphere.properties.isGizmo=!0,this.targetSphere.properties.gizmoSubject= +a.target,this.targetSphere.properties.gizmoRoot=this.targetSphere,c=new THREE.LineDashedMaterial({color:c,dashSize:4,gapSize:4,opacity:0.75,transparent:!0,fog:!1}),e=new THREE.Geometry,e.vertices.push(this.position.clone()),e.vertices.push(this.targetSphere.position.clone()),e.computeLineDistances(),this.targetLine=new THREE.Line(e,c),this.targetLine.properties.isGizmo=!0);this.properties.isGizmo=!0};THREE.SpotLightHelper.prototype=Object.create(THREE.Object3D.prototype); +THREE.SpotLightHelper.prototype.update=function(){this.direction.subVectors(this.light.target.position,this.light.position);this.lookAt(this.light.target.position);var a=this.light.distance?this.light.distance:1E4,b=2*a*Math.tan(0.5*this.light.angle);this.lightCone.scale.set(b,b,a);a=THREE.Math.clamp(this.light.intensity,0,1);this.color.copy(this.light.color);this.color.multiplyScalar(a);this.lightSphere.material.color.copy(this.color);this.lightRays.material.color.copy(this.color);this.lightCone.material.color.copy(this.color); +null!==this.targetSphere&&(this.targetSphere.material.color.copy(this.color),this.targetLine.material.color.copy(this.color),this.targetLine.geometry.vertices[0].copy(this.light.position),this.targetLine.geometry.vertices[1].copy(this.light.target.position),this.targetLine.geometry.computeLineDistances(),this.targetLine.geometry.verticesNeedUpdate=!0)};THREE.ImmediateRenderObject=function(){THREE.Object3D.call(this);this.render=function(){}};THREE.ImmediateRenderObject.prototype=Object.create(THREE.Object3D.prototype);THREE.LensFlare=function(a,b,c,d,e){THREE.Object3D.call(this);this.lensFlares=[];this.positionScreen=new THREE.Vector3;this.customUpdateCallback=void 0;void 0!==a&&this.add(a,b,c,d,e)};THREE.LensFlare.prototype=Object.create(THREE.Object3D.prototype); +THREE.LensFlare.prototype.add=function(a,b,c,d,e,f){void 0===b&&(b=-1);void 0===c&&(c=0);void 0===f&&(f=1);void 0===e&&(e=new THREE.Color(16777215));void 0===d&&(d=THREE.NormalBlending);c=Math.min(c,Math.max(0,c));this.lensFlares.push({texture:a,size:b,distance:c,x:0,y:0,z:0,scale:1,rotation:1,opacity:f,color:e,blending:d})}; +THREE.LensFlare.prototype.updateLensFlares=function(){var a,b=this.lensFlares.length,c,d=2*-this.positionScreen.x,e=2*-this.positionScreen.y;for(a=0;a<b;a++)c=this.lensFlares[a],c.x=this.positionScreen.x+d*c.distance,c.y=this.positionScreen.y+e*c.distance,c.wantedRotation=0.25*c.x*Math.PI,c.rotation+=0.25*(c.wantedRotation-c.rotation)};THREE.MorphBlendMesh=function(a,b){THREE.Mesh.call(this,a,b);this.animationsMap={};this.animationsList=[];var c=this.geometry.morphTargets.length;this.createAnimation("__default",0,c-1,c/1);this.setAnimationWeight("__default",1)};THREE.MorphBlendMesh.prototype=Object.create(THREE.Mesh.prototype); +THREE.MorphBlendMesh.prototype.createAnimation=function(a,b,c,d){b={startFrame:b,endFrame:c,length:c-b+1,fps:d,duration:(c-b)/d,lastFrame:0,currentFrame:0,active:!1,time:0,direction:1,weight:1,directionBackwards:!1,mirroredLoop:!1};this.animationsMap[a]=b;this.animationsList.push(b)}; +THREE.MorphBlendMesh.prototype.autoCreateAnimations=function(a){for(var b=/([a-z]+)(\d+)/,c,d={},e=this.geometry,f=0,g=e.morphTargets.length;f<g;f++){var h=e.morphTargets[f].name.match(b);if(h&&1<h.length){var i=h[1];d[i]||(d[i]={start:Infinity,end:-Infinity});h=d[i];f<h.start&&(h.start=f);f>h.end&&(h.end=f);c||(c=i)}}for(i in d)h=d[i],this.createAnimation(i,h.start,h.end,a);this.firstAnimation=c}; +THREE.MorphBlendMesh.prototype.setAnimationDirectionForward=function(a){if(a=this.animationsMap[a])a.direction=1,a.directionBackwards=!1};THREE.MorphBlendMesh.prototype.setAnimationDirectionBackward=function(a){if(a=this.animationsMap[a])a.direction=-1,a.directionBackwards=!0};THREE.MorphBlendMesh.prototype.setAnimationFPS=function(a,b){var c=this.animationsMap[a];c&&(c.fps=b,c.duration=(c.end-c.start)/c.fps)}; +THREE.MorphBlendMesh.prototype.setAnimationDuration=function(a,b){var c=this.animationsMap[a];c&&(c.duration=b,c.fps=(c.end-c.start)/c.duration)};THREE.MorphBlendMesh.prototype.setAnimationWeight=function(a,b){var c=this.animationsMap[a];c&&(c.weight=b)};THREE.MorphBlendMesh.prototype.setAnimationTime=function(a,b){var c=this.animationsMap[a];c&&(c.time=b)};THREE.MorphBlendMesh.prototype.getAnimationTime=function(a){var b=0;if(a=this.animationsMap[a])b=a.time;return b}; +THREE.MorphBlendMesh.prototype.getAnimationDuration=function(a){var b=-1;if(a=this.animationsMap[a])b=a.duration;return b};THREE.MorphBlendMesh.prototype.playAnimation=function(a){var b=this.animationsMap[a];b?(b.time=0,b.active=!0):console.warn("animation["+a+"] undefined")};THREE.MorphBlendMesh.prototype.stopAnimation=function(a){if(a=this.animationsMap[a])a.active=!1}; +THREE.MorphBlendMesh.prototype.update=function(a){for(var b=0,c=this.animationsList.length;b<c;b++){var d=this.animationsList[b];if(d.active){var e=d.duration/d.length;d.time+=d.direction*a;if(d.mirroredLoop){if(d.time>d.duration||0>d.time)d.direction*=-1,d.time>d.duration&&(d.time=d.duration,d.directionBackwards=!0),0>d.time&&(d.time=0,d.directionBackwards=!1)}else d.time%=d.duration,0>d.time&&(d.time+=d.duration);var f=d.startFrame+THREE.Math.clamp(Math.floor(d.time/e),0,d.length-1),g=d.weight; +f!==d.currentFrame&&(this.morphTargetInfluences[d.lastFrame]=0,this.morphTargetInfluences[d.currentFrame]=1*g,this.morphTargetInfluences[f]=0,d.lastFrame=d.currentFrame,d.currentFrame=f);e=d.time%e/e;d.directionBackwards&&(e=1-e);this.morphTargetInfluences[d.currentFrame]=e*g;this.morphTargetInfluences[d.lastFrame]=(1-e)*g}}};THREE.LensFlarePlugin=function(){function a(a,c){var d=b.createProgram(),e=b.createShader(b.FRAGMENT_SHADER),f=b.createShader(b.VERTEX_SHADER),g="precision "+c+" float;\n";b.shaderSource(e,g+a.fragmentShader);b.shaderSource(f,g+a.vertexShader);b.compileShader(e);b.compileShader(f);b.attachShader(d,e);b.attachShader(d,f);b.linkProgram(d);return d}var b,c,d,e,f,g,h,i,k,l,m,n,s;this.init=function(r){b=r.context;c=r;d=r.getPrecision();e=new Float32Array(16);f=new Uint16Array(6);r=0;e[r++]=-1;e[r++]=-1; +e[r++]=0;e[r++]=0;e[r++]=1;e[r++]=-1;e[r++]=1;e[r++]=0;e[r++]=1;e[r++]=1;e[r++]=1;e[r++]=1;e[r++]=-1;e[r++]=1;e[r++]=0;e[r++]=1;r=0;f[r++]=0;f[r++]=1;f[r++]=2;f[r++]=0;f[r++]=2;f[r++]=3;g=b.createBuffer();h=b.createBuffer();b.bindBuffer(b.ARRAY_BUFFER,g);b.bufferData(b.ARRAY_BUFFER,e,b.STATIC_DRAW);b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,h);b.bufferData(b.ELEMENT_ARRAY_BUFFER,f,b.STATIC_DRAW);i=b.createTexture();k=b.createTexture();b.bindTexture(b.TEXTURE_2D,i);b.texImage2D(b.TEXTURE_2D,0,b.RGB,16,16, +0,b.RGB,b.UNSIGNED_BYTE,null);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_S,b.CLAMP_TO_EDGE);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_T,b.CLAMP_TO_EDGE);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MAG_FILTER,b.NEAREST);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MIN_FILTER,b.NEAREST);b.bindTexture(b.TEXTURE_2D,k);b.texImage2D(b.TEXTURE_2D,0,b.RGBA,16,16,0,b.RGBA,b.UNSIGNED_BYTE,null);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_S,b.CLAMP_TO_EDGE);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_T,b.CLAMP_TO_EDGE); +b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MAG_FILTER,b.NEAREST);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MIN_FILTER,b.NEAREST);0>=b.getParameter(b.MAX_VERTEX_TEXTURE_IMAGE_UNITS)?(l=!1,m=a(THREE.ShaderFlares.lensFlare,d)):(l=!0,m=a(THREE.ShaderFlares.lensFlareVertexTexture,d));n={};s={};n.vertex=b.getAttribLocation(m,"position");n.uv=b.getAttribLocation(m,"uv");s.renderType=b.getUniformLocation(m,"renderType");s.map=b.getUniformLocation(m,"map");s.occlusionMap=b.getUniformLocation(m,"occlusionMap");s.opacity= +b.getUniformLocation(m,"opacity");s.color=b.getUniformLocation(m,"color");s.scale=b.getUniformLocation(m,"scale");s.rotation=b.getUniformLocation(m,"rotation");s.screenPosition=b.getUniformLocation(m,"screenPosition")};this.render=function(a,d,e,f){var a=a.__webglFlares,v=a.length;if(v){var z=new THREE.Vector3,t=f/e,A=0.5*e,I=0.5*f,C=16/f,x=new THREE.Vector2(C*t,C),G=new THREE.Vector3(1,1,0),J=new THREE.Vector2(1,1),E=s,C=n;b.useProgram(m);b.enableVertexAttribArray(n.vertex);b.enableVertexAttribArray(n.uv); +b.uniform1i(E.occlusionMap,0);b.uniform1i(E.map,1);b.bindBuffer(b.ARRAY_BUFFER,g);b.vertexAttribPointer(C.vertex,2,b.FLOAT,!1,16,0);b.vertexAttribPointer(C.uv,2,b.FLOAT,!1,16,8);b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,h);b.disable(b.CULL_FACE);b.depthMask(!1);var H,B,W,F,K;for(H=0;H<v;H++)if(C=16/f,x.set(C*t,C),F=a[H],z.set(F.matrixWorld.elements[12],F.matrixWorld.elements[13],F.matrixWorld.elements[14]),z.applyMatrix4(d.matrixWorldInverse),z.applyProjection(d.projectionMatrix),G.copy(z),J.x=G.x*A+A, +J.y=G.y*I+I,l||0<J.x&&J.x<e&&0<J.y&&J.y<f){b.activeTexture(b.TEXTURE1);b.bindTexture(b.TEXTURE_2D,i);b.copyTexImage2D(b.TEXTURE_2D,0,b.RGB,J.x-8,J.y-8,16,16,0);b.uniform1i(E.renderType,0);b.uniform2f(E.scale,x.x,x.y);b.uniform3f(E.screenPosition,G.x,G.y,G.z);b.disable(b.BLEND);b.enable(b.DEPTH_TEST);b.drawElements(b.TRIANGLES,6,b.UNSIGNED_SHORT,0);b.activeTexture(b.TEXTURE0);b.bindTexture(b.TEXTURE_2D,k);b.copyTexImage2D(b.TEXTURE_2D,0,b.RGBA,J.x-8,J.y-8,16,16,0);b.uniform1i(E.renderType,1);b.disable(b.DEPTH_TEST); +b.activeTexture(b.TEXTURE1);b.bindTexture(b.TEXTURE_2D,i);b.drawElements(b.TRIANGLES,6,b.UNSIGNED_SHORT,0);F.positionScreen.copy(G);F.customUpdateCallback?F.customUpdateCallback(F):F.updateLensFlares();b.uniform1i(E.renderType,2);b.enable(b.BLEND);B=0;for(W=F.lensFlares.length;B<W;B++)K=F.lensFlares[B],0.001<K.opacity&&0.001<K.scale&&(G.x=K.x,G.y=K.y,G.z=K.z,C=K.size*K.scale/f,x.x=C*t,x.y=C,b.uniform3f(E.screenPosition,G.x,G.y,G.z),b.uniform2f(E.scale,x.x,x.y),b.uniform1f(E.rotation,K.rotation),b.uniform1f(E.opacity, +K.opacity),b.uniform3f(E.color,K.color.r,K.color.g,K.color.b),c.setBlending(K.blending,K.blendEquation,K.blendSrc,K.blendDst),c.setTexture(K.texture,1),b.drawElements(b.TRIANGLES,6,b.UNSIGNED_SHORT,0))}b.enable(b.CULL_FACE);b.enable(b.DEPTH_TEST);b.depthMask(!0)}}};THREE.ShadowMapPlugin=function(){var a,b,c,d,e,f,g=new THREE.Frustum,h=new THREE.Matrix4,i=new THREE.Vector3,k=new THREE.Vector3,l=new THREE.Vector3;this.init=function(g){a=g.context;b=g;var g=THREE.ShaderLib.depthRGBA,i=THREE.UniformsUtils.clone(g.uniforms);c=new THREE.ShaderMaterial({fragmentShader:g.fragmentShader,vertexShader:g.vertexShader,uniforms:i});d=new THREE.ShaderMaterial({fragmentShader:g.fragmentShader,vertexShader:g.vertexShader,uniforms:i,morphTargets:!0});e=new THREE.ShaderMaterial({fragmentShader:g.fragmentShader, +vertexShader:g.vertexShader,uniforms:i,skinning:!0});f=new THREE.ShaderMaterial({fragmentShader:g.fragmentShader,vertexShader:g.vertexShader,uniforms:i,morphTargets:!0,skinning:!0});c._shadowPass=!0;d._shadowPass=!0;e._shadowPass=!0;f._shadowPass=!0};this.render=function(a,c){b.shadowMapEnabled&&b.shadowMapAutoUpdate&&this.update(a,c)};this.update=function(m,n){var s,r,p,q,y,v,z,t,A,I=[];q=0;a.clearColor(1,1,1,1);a.disable(a.BLEND);a.enable(a.CULL_FACE);a.frontFace(a.CCW);b.shadowMapCullFace===THREE.CullFaceFront? +a.cullFace(a.FRONT):a.cullFace(a.BACK);b.setDepthTest(!0);s=0;for(r=m.__lights.length;s<r;s++)if(p=m.__lights[s],p.castShadow)if(p instanceof THREE.DirectionalLight&&p.shadowCascade)for(y=0;y<p.shadowCascadeCount;y++){var C;if(p.shadowCascadeArray[y])C=p.shadowCascadeArray[y];else{A=p;z=y;C=new THREE.DirectionalLight;C.isVirtual=!0;C.onlyShadow=!0;C.castShadow=!0;C.shadowCameraNear=A.shadowCameraNear;C.shadowCameraFar=A.shadowCameraFar;C.shadowCameraLeft=A.shadowCameraLeft;C.shadowCameraRight=A.shadowCameraRight; +C.shadowCameraBottom=A.shadowCameraBottom;C.shadowCameraTop=A.shadowCameraTop;C.shadowCameraVisible=A.shadowCameraVisible;C.shadowDarkness=A.shadowDarkness;C.shadowBias=A.shadowCascadeBias[z];C.shadowMapWidth=A.shadowCascadeWidth[z];C.shadowMapHeight=A.shadowCascadeHeight[z];C.pointsWorld=[];C.pointsFrustum=[];t=C.pointsWorld;v=C.pointsFrustum;for(var x=0;8>x;x++)t[x]=new THREE.Vector3,v[x]=new THREE.Vector3;t=A.shadowCascadeNearZ[z];A=A.shadowCascadeFarZ[z];v[0].set(-1,-1,t);v[1].set(1,-1,t);v[2].set(-1, +1,t);v[3].set(1,1,t);v[4].set(-1,-1,A);v[5].set(1,-1,A);v[6].set(-1,1,A);v[7].set(1,1,A);C.originalCamera=n;v=new THREE.Gyroscope;v.position=p.shadowCascadeOffset;v.add(C);v.add(C.target);n.add(v);p.shadowCascadeArray[y]=C;console.log("Created virtualLight",C)}z=p;t=y;A=z.shadowCascadeArray[t];A.position.copy(z.position);A.target.position.copy(z.target.position);A.lookAt(A.target);A.shadowCameraVisible=z.shadowCameraVisible;A.shadowDarkness=z.shadowDarkness;A.shadowBias=z.shadowCascadeBias[t];v=z.shadowCascadeNearZ[t]; +z=z.shadowCascadeFarZ[t];A=A.pointsFrustum;A[0].z=v;A[1].z=v;A[2].z=v;A[3].z=v;A[4].z=z;A[5].z=z;A[6].z=z;A[7].z=z;I[q]=C;q++}else I[q]=p,q++;s=0;for(r=I.length;s<r;s++){p=I[s];p.shadowMap||(y=THREE.LinearFilter,b.shadowMapType===THREE.PCFSoftShadowMap&&(y=THREE.NearestFilter),p.shadowMap=new THREE.WebGLRenderTarget(p.shadowMapWidth,p.shadowMapHeight,{minFilter:y,magFilter:y,format:THREE.RGBAFormat}),p.shadowMapSize=new THREE.Vector2(p.shadowMapWidth,p.shadowMapHeight),p.shadowMatrix=new THREE.Matrix4); +if(!p.shadowCamera){if(p instanceof THREE.SpotLight)p.shadowCamera=new THREE.PerspectiveCamera(p.shadowCameraFov,p.shadowMapWidth/p.shadowMapHeight,p.shadowCameraNear,p.shadowCameraFar);else if(p instanceof THREE.DirectionalLight)p.shadowCamera=new THREE.OrthographicCamera(p.shadowCameraLeft,p.shadowCameraRight,p.shadowCameraTop,p.shadowCameraBottom,p.shadowCameraNear,p.shadowCameraFar);else{console.error("Unsupported light type for shadow");continue}m.add(p.shadowCamera);b.autoUpdateScene&&m.updateMatrixWorld()}p.shadowCameraVisible&& +!p.cameraHelper&&(p.cameraHelper=new THREE.CameraHelper(p.shadowCamera),p.shadowCamera.add(p.cameraHelper));if(p.isVirtual&&C.originalCamera==n){y=n;q=p.shadowCamera;v=p.pointsFrustum;A=p.pointsWorld;i.set(Infinity,Infinity,Infinity);k.set(-Infinity,-Infinity,-Infinity);for(z=0;8>z;z++)t=A[z],t.copy(v[z]),THREE.ShadowMapPlugin.__projector.unprojectVector(t,y),t.applyMatrix4(q.matrixWorldInverse),t.x<i.x&&(i.x=t.x),t.x>k.x&&(k.x=t.x),t.y<i.y&&(i.y=t.y),t.y>k.y&&(k.y=t.y),t.z<i.z&&(i.z=t.z),t.z>k.z&& +(k.z=t.z);q.left=i.x;q.right=k.x;q.top=k.y;q.bottom=i.y;q.updateProjectionMatrix()}q=p.shadowMap;v=p.shadowMatrix;y=p.shadowCamera;y.position.getPositionFromMatrix(p.matrixWorld);l.getPositionFromMatrix(p.target.matrixWorld);y.lookAt(l);y.updateMatrixWorld();y.matrixWorldInverse.getInverse(y.matrixWorld);p.cameraHelper&&(p.cameraHelper.visible=p.shadowCameraVisible);p.shadowCameraVisible&&p.cameraHelper.update();v.set(0.5,0,0,0.5,0,0.5,0,0.5,0,0,0.5,0.5,0,0,0,1);v.multiply(y.projectionMatrix);v.multiply(y.matrixWorldInverse); +h.multiplyMatrices(y.projectionMatrix,y.matrixWorldInverse);g.setFromMatrix(h);b.setRenderTarget(q);b.clear();A=m.__webglObjects;p=0;for(q=A.length;p<q;p++)if(z=A[p],v=z.object,z.render=!1,v.visible&&v.castShadow&&(!(v instanceof THREE.Mesh||v instanceof THREE.ParticleSystem)||!v.frustumCulled||g.intersectsObject(v)))v._modelViewMatrix.multiplyMatrices(y.matrixWorldInverse,v.matrixWorld),z.render=!0;p=0;for(q=A.length;p<q;p++)z=A[p],z.render&&(v=z.object,z=z.buffer,x=v.material instanceof THREE.MeshFaceMaterial? +v.material.materials[0]:v.material,t=0<v.geometry.morphTargets.length&&x.morphTargets,x=v instanceof THREE.SkinnedMesh&&x.skinning,t=v.customDepthMaterial?v.customDepthMaterial:x?t?f:e:t?d:c,z instanceof THREE.BufferGeometry?b.renderBufferDirect(y,m.__lights,null,t,z,v):b.renderBuffer(y,m.__lights,null,t,z,v));A=m.__webglObjectsImmediate;p=0;for(q=A.length;p<q;p++)z=A[p],v=z.object,v.visible&&v.castShadow&&(v._modelViewMatrix.multiplyMatrices(y.matrixWorldInverse,v.matrixWorld),b.renderImmediateObject(y, +m.__lights,null,c,v))}s=b.getClearColor();r=b.getClearAlpha();a.clearColor(s.r,s.g,s.b,r);a.enable(a.BLEND);b.shadowMapCullFace===THREE.CullFaceFront&&a.cullFace(a.BACK)}};THREE.ShadowMapPlugin.__projector=new THREE.Projector;THREE.SpritePlugin=function(){function a(a,b){return a.z!==b.z?b.z-a.z:b.id-a.id}var b,c,d,e,f,g,h,i,k,l;this.init=function(a){b=a.context;c=a;d=a.getPrecision();e=new Float32Array(16);f=new Uint16Array(6);a=0;e[a++]=-1;e[a++]=-1;e[a++]=0;e[a++]=0;e[a++]=1;e[a++]=-1;e[a++]=1;e[a++]=0;e[a++]=1;e[a++]=1;e[a++]=1;e[a++]=1;e[a++]=-1;e[a++]=1;e[a++]=0;e[a++]=1;a=0;f[a++]=0;f[a++]=1;f[a++]=2;f[a++]=0;f[a++]=2;f[a++]=3;g=b.createBuffer();h=b.createBuffer();b.bindBuffer(b.ARRAY_BUFFER,g);b.bufferData(b.ARRAY_BUFFER, +e,b.STATIC_DRAW);b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,h);b.bufferData(b.ELEMENT_ARRAY_BUFFER,f,b.STATIC_DRAW);var a=THREE.ShaderSprite.sprite,n=b.createProgram(),s=b.createShader(b.FRAGMENT_SHADER),r=b.createShader(b.VERTEX_SHADER),p="precision "+d+" float;\n";b.shaderSource(s,p+a.fragmentShader);b.shaderSource(r,p+a.vertexShader);b.compileShader(s);b.compileShader(r);b.attachShader(n,s);b.attachShader(n,r);b.linkProgram(n);i=n;k={};l={};k.position=b.getAttribLocation(i,"position");k.uv=b.getAttribLocation(i, +"uv");l.uvOffset=b.getUniformLocation(i,"uvOffset");l.uvScale=b.getUniformLocation(i,"uvScale");l.rotation=b.getUniformLocation(i,"rotation");l.scale=b.getUniformLocation(i,"scale");l.alignment=b.getUniformLocation(i,"alignment");l.color=b.getUniformLocation(i,"color");l.map=b.getUniformLocation(i,"map");l.opacity=b.getUniformLocation(i,"opacity");l.useScreenCoordinates=b.getUniformLocation(i,"useScreenCoordinates");l.sizeAttenuation=b.getUniformLocation(i,"sizeAttenuation");l.screenPosition=b.getUniformLocation(i, +"screenPosition");l.modelViewMatrix=b.getUniformLocation(i,"modelViewMatrix");l.projectionMatrix=b.getUniformLocation(i,"projectionMatrix");l.fogType=b.getUniformLocation(i,"fogType");l.fogDensity=b.getUniformLocation(i,"fogDensity");l.fogNear=b.getUniformLocation(i,"fogNear");l.fogFar=b.getUniformLocation(i,"fogFar");l.fogColor=b.getUniformLocation(i,"fogColor");l.alphaTest=b.getUniformLocation(i,"alphaTest")};this.render=function(d,e,f,r){var p=d.__webglSprites,q=p.length;if(q){var y=k,v=l,z=r/ +f,f=0.5*f,t=0.5*r;b.useProgram(i);b.enableVertexAttribArray(y.position);b.enableVertexAttribArray(y.uv);b.disable(b.CULL_FACE);b.enable(b.BLEND);b.bindBuffer(b.ARRAY_BUFFER,g);b.vertexAttribPointer(y.position,2,b.FLOAT,!1,16,0);b.vertexAttribPointer(y.uv,2,b.FLOAT,!1,16,8);b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,h);b.uniformMatrix4fv(v.projectionMatrix,!1,e.projectionMatrix.elements);b.activeTexture(b.TEXTURE0);b.uniform1i(v.map,0);var A=y=0,I=d.fog;I?(b.uniform3f(v.fogColor,I.color.r,I.color.g,I.color.b), +I instanceof THREE.Fog?(b.uniform1f(v.fogNear,I.near),b.uniform1f(v.fogFar,I.far),b.uniform1i(v.fogType,1),A=y=1):I instanceof THREE.FogExp2&&(b.uniform1f(v.fogDensity,I.density),b.uniform1i(v.fogType,2),A=y=2)):(b.uniform1i(v.fogType,0),A=y=0);for(var C,x,G=[],I=0;I<q;I++)C=p[I],x=C.material,C.visible&&0!==x.opacity&&(x.useScreenCoordinates?C.z=-C.position.z:(C._modelViewMatrix.multiplyMatrices(e.matrixWorldInverse,C.matrixWorld),C.z=-C._modelViewMatrix.elements[14]));p.sort(a);for(I=0;I<q;I++)C= +p[I],x=C.material,C.visible&&0!==x.opacity&&(x.map&&x.map.image&&x.map.image.width)&&(b.uniform1f(v.alphaTest,x.alphaTest),!0===x.useScreenCoordinates?(b.uniform1i(v.useScreenCoordinates,1),b.uniform3f(v.screenPosition,(C.position.x*c.devicePixelRatio-f)/f,(t-C.position.y*c.devicePixelRatio)/t,Math.max(0,Math.min(1,C.position.z))),G[0]=c.devicePixelRatio,G[1]=c.devicePixelRatio):(b.uniform1i(v.useScreenCoordinates,0),b.uniform1i(v.sizeAttenuation,x.sizeAttenuation?1:0),b.uniformMatrix4fv(v.modelViewMatrix, +!1,C._modelViewMatrix.elements),G[0]=1,G[1]=1),e=d.fog&&x.fog?A:0,y!==e&&(b.uniform1i(v.fogType,e),y=e),e=1/(x.scaleByViewport?r:1),G[0]*=e*z*C.scale.x,G[1]*=e*C.scale.y,b.uniform2f(v.uvScale,x.uvScale.x,x.uvScale.y),b.uniform2f(v.uvOffset,x.uvOffset.x,x.uvOffset.y),b.uniform2f(v.alignment,x.alignment.x,x.alignment.y),b.uniform1f(v.opacity,x.opacity),b.uniform3f(v.color,x.color.r,x.color.g,x.color.b),b.uniform1f(v.rotation,C.rotation),b.uniform2fv(v.scale,G),c.setBlending(x.blending,x.blendEquation, +x.blendSrc,x.blendDst),c.setDepthTest(x.depthTest),c.setDepthWrite(x.depthWrite),c.setTexture(x.map,0),b.drawElements(b.TRIANGLES,6,b.UNSIGNED_SHORT,0));b.enable(b.CULL_FACE)}}};THREE.DepthPassPlugin=function(){this.enabled=!1;this.renderTarget=null;var a,b,c,d,e,f,g=new THREE.Frustum,h=new THREE.Matrix4;this.init=function(g){a=g.context;b=g;var g=THREE.ShaderLib.depthRGBA,h=THREE.UniformsUtils.clone(g.uniforms);c=new THREE.ShaderMaterial({fragmentShader:g.fragmentShader,vertexShader:g.vertexShader,uniforms:h});d=new THREE.ShaderMaterial({fragmentShader:g.fragmentShader,vertexShader:g.vertexShader,uniforms:h,morphTargets:!0});e=new THREE.ShaderMaterial({fragmentShader:g.fragmentShader, +vertexShader:g.vertexShader,uniforms:h,skinning:!0});f=new THREE.ShaderMaterial({fragmentShader:g.fragmentShader,vertexShader:g.vertexShader,uniforms:h,morphTargets:!0,skinning:!0});c._shadowPass=!0;d._shadowPass=!0;e._shadowPass=!0;f._shadowPass=!0};this.render=function(a,b){this.enabled&&this.update(a,b)};this.update=function(i,k){var l,m,n,s,r,p;a.clearColor(1,1,1,1);a.disable(a.BLEND);b.setDepthTest(!0);b.autoUpdateScene&&i.updateMatrixWorld();k.matrixWorldInverse.getInverse(k.matrixWorld);h.multiplyMatrices(k.projectionMatrix, +k.matrixWorldInverse);g.setFromMatrix(h);b.setRenderTarget(this.renderTarget);b.clear();p=i.__webglObjects;l=0;for(m=p.length;l<m;l++)if(n=p[l],r=n.object,n.render=!1,r.visible&&(!(r instanceof THREE.Mesh||r instanceof THREE.ParticleSystem)||!r.frustumCulled||g.intersectsObject(r)))r._modelViewMatrix.multiplyMatrices(k.matrixWorldInverse,r.matrixWorld),n.render=!0;var q;l=0;for(m=p.length;l<m;l++)if(n=p[l],n.render&&(r=n.object,n=n.buffer,!(r instanceof THREE.ParticleSystem)||r.customDepthMaterial))(q= +r.material instanceof THREE.MeshFaceMaterial?r.material.materials[0]:r.material)&&b.setMaterialFaces(r.material),s=0<r.geometry.morphTargets.length&&q.morphTargets,q=r instanceof THREE.SkinnedMesh&&q.skinning,s=r.customDepthMaterial?r.customDepthMaterial:q?s?f:e:s?d:c,n instanceof THREE.BufferGeometry?b.renderBufferDirect(k,i.__lights,null,s,n,r):b.renderBuffer(k,i.__lights,null,s,n,r);p=i.__webglObjectsImmediate;l=0;for(m=p.length;l<m;l++)n=p[l],r=n.object,r.visible&&(r._modelViewMatrix.multiplyMatrices(k.matrixWorldInverse, +r.matrixWorld),b.renderImmediateObject(k,i.__lights,null,c,r));l=b.getClearColor();m=b.getClearAlpha();a.clearColor(l.r,l.g,l.b,m);a.enable(a.BLEND)}};THREE.ShaderFlares={lensFlareVertexTexture:{vertexShader:"uniform lowp int renderType;\nuniform vec3 screenPosition;\nuniform vec2 scale;\nuniform float rotation;\nuniform sampler2D occlusionMap;\nattribute vec2 position;\nattribute vec2 uv;\nvarying vec2 vUV;\nvarying float vVisibility;\nvoid main() {\nvUV = uv;\nvec2 pos = position;\nif( renderType == 2 ) {\nvec4 visibility = texture2D( occlusionMap, vec2( 0.1, 0.1 ) ) +\ntexture2D( occlusionMap, vec2( 0.5, 0.1 ) ) +\ntexture2D( occlusionMap, vec2( 0.9, 0.1 ) ) +\ntexture2D( occlusionMap, vec2( 0.9, 0.5 ) ) +\ntexture2D( occlusionMap, vec2( 0.9, 0.9 ) ) +\ntexture2D( occlusionMap, vec2( 0.5, 0.9 ) ) +\ntexture2D( occlusionMap, vec2( 0.1, 0.9 ) ) +\ntexture2D( occlusionMap, vec2( 0.1, 0.5 ) ) +\ntexture2D( occlusionMap, vec2( 0.5, 0.5 ) );\nvVisibility = ( visibility.r / 9.0 ) *\n( 1.0 - visibility.g / 9.0 ) *\n( visibility.b / 9.0 ) *\n( 1.0 - visibility.a / 9.0 );\npos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;\npos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;\n}\ngl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );\n}", +fragmentShader:"uniform lowp int renderType;\nuniform sampler2D map;\nuniform float opacity;\nuniform vec3 color;\nvarying vec2 vUV;\nvarying float vVisibility;\nvoid main() {\nif( renderType == 0 ) {\ngl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );\n} else if( renderType == 1 ) {\ngl_FragColor = texture2D( map, vUV );\n} else {\nvec4 texture = texture2D( map, vUV );\ntexture.a *= opacity * vVisibility;\ngl_FragColor = texture;\ngl_FragColor.rgb *= color;\n}\n}"},lensFlare:{vertexShader:"uniform lowp int renderType;\nuniform vec3 screenPosition;\nuniform vec2 scale;\nuniform float rotation;\nattribute vec2 position;\nattribute vec2 uv;\nvarying vec2 vUV;\nvoid main() {\nvUV = uv;\nvec2 pos = position;\nif( renderType == 2 ) {\npos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;\npos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;\n}\ngl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );\n}", +fragmentShader:"precision mediump float;\nuniform lowp int renderType;\nuniform sampler2D map;\nuniform sampler2D occlusionMap;\nuniform float opacity;\nuniform vec3 color;\nvarying vec2 vUV;\nvoid main() {\nif( renderType == 0 ) {\ngl_FragColor = vec4( texture2D( map, vUV ).rgb, 0.0 );\n} else if( renderType == 1 ) {\ngl_FragColor = texture2D( map, vUV );\n} else {\nfloat visibility = texture2D( occlusionMap, vec2( 0.5, 0.1 ) ).a +\ntexture2D( occlusionMap, vec2( 0.9, 0.5 ) ).a +\ntexture2D( occlusionMap, vec2( 0.5, 0.9 ) ).a +\ntexture2D( occlusionMap, vec2( 0.1, 0.5 ) ).a;\nvisibility = ( 1.0 - visibility / 4.0 );\nvec4 texture = texture2D( map, vUV );\ntexture.a *= opacity * visibility;\ngl_FragColor = texture;\ngl_FragColor.rgb *= color;\n}\n}"}};THREE.ShaderSprite={sprite:{vertexShader:"uniform int useScreenCoordinates;\nuniform int sizeAttenuation;\nuniform vec3 screenPosition;\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\nuniform float rotation;\nuniform vec2 scale;\nuniform vec2 alignment;\nuniform vec2 uvOffset;\nuniform vec2 uvScale;\nattribute vec2 position;\nattribute vec2 uv;\nvarying vec2 vUV;\nvoid main() {\nvUV = uvOffset + uv * uvScale;\nvec2 alignedPosition = position + alignment;\nvec2 rotatedPosition;\nrotatedPosition.x = ( cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y ) * scale.x;\nrotatedPosition.y = ( sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y ) * scale.y;\nvec4 finalPosition;\nif( useScreenCoordinates != 0 ) {\nfinalPosition = vec4( screenPosition.xy + rotatedPosition, screenPosition.z, 1.0 );\n} else {\nfinalPosition = projectionMatrix * modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\nfinalPosition.xy += rotatedPosition * ( sizeAttenuation == 1 ? 1.0 : finalPosition.z );\n}\ngl_Position = finalPosition;\n}", +fragmentShader:"uniform vec3 color;\nuniform sampler2D map;\nuniform float opacity;\nuniform int fogType;\nuniform vec3 fogColor;\nuniform float fogDensity;\nuniform float fogNear;\nuniform float fogFar;\nuniform float alphaTest;\nvarying vec2 vUV;\nvoid main() {\nvec4 texture = texture2D( map, vUV );\nif ( texture.a < alphaTest ) discard;\ngl_FragColor = vec4( color * texture.xyz, texture.a * opacity );\nif ( fogType > 0 ) {\nfloat depth = gl_FragCoord.z / gl_FragCoord.w;\nfloat fogFactor = 0.0;\nif ( fogType == 1 ) {\nfogFactor = smoothstep( fogNear, fogFar, depth );\n} else {\nconst float LOG2 = 1.442695;\nfloat fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );\nfogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );\n}\ngl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );\n}\n}"}}; diff --git a/COGNET/lib/tween.min.js b/COGNET/lib/tween.min.js new file mode 100644 index 0000000000000000000000000000000000000000..eb7d584f0932825f3ab537f5cbaad477a0be8ed6 --- /dev/null +++ b/COGNET/lib/tween.min.js @@ -0,0 +1,14 @@ +// tween.js - http://github.com/sole/tween.js +'use strict'; +export var TWEEN=TWEEN||function(){var a=[];return{REVISION:"7",getAll:function(){return a},removeAll:function(){a=[]},add:function(c){a.push(c)},remove:function(c){c=a.indexOf(c);-1!==c&&a.splice(c,1)},update:function(c){if(0===a.length)return!1;for(var b=0,d=a.length,c=void 0!==c?c:Date.now();b<d;)a[b].update(c)?b++:(a.splice(b,1),d--);return!0}}}(); +TWEEN.Tween=function(a){var c={},b={},d=1E3,e=0,f=null,h=TWEEN.Easing.Linear.None,r=TWEEN.Interpolation.Linear,k=[],l=null,m=!1,n=null,p=null;this.to=function(a,c){null!==c&&(d=c);b=a;return this};this.start=function(d){TWEEN.add(this);m=!1;f=void 0!==d?d:Date.now();f+=e;for(var g in b)if(null!==a[g]){if(b[g]instanceof Array){if(0===b[g].length)continue;b[g]=[a[g]].concat(b[g])}c[g]=a[g]}return this};this.stop=function(){TWEEN.remove(this);return this};this.delay=function(a){e=a;return this};this.easing= +function(a){h=a;return this};this.interpolation=function(a){r=a;return this};this.chain=function(){k=arguments;return this};this.onStart=function(a){l=a;return this};this.onUpdate=function(a){n=a;return this};this.onComplete=function(a){p=a;return this};this.update=function(e){if(e<f)return!0;!1===m&&(null!==l&&l.call(a),m=!0);var g=(e-f)/d,g=1<g?1:g,i=h(g),j;for(j in c){var s=c[j],q=b[j];a[j]=q instanceof Array?r(q,i):s+(q-s)*i}null!==n&&n.call(a,i);if(1==g){null!==p&&p.call(a);g=0;for(i=k.length;g< +i;g++)k[g].start(e);return!1}return!0}}; +TWEEN.Easing={Linear:{None:function(a){return a}},Quadratic:{In:function(a){return a*a},Out:function(a){return a*(2-a)},InOut:function(a){return 1>(a*=2)?0.5*a*a:-0.5*(--a*(a-2)-1)}},Cubic:{In:function(a){return a*a*a},Out:function(a){return--a*a*a+1},InOut:function(a){return 1>(a*=2)?0.5*a*a*a:0.5*((a-=2)*a*a+2)}},Quartic:{In:function(a){return a*a*a*a},Out:function(a){return 1- --a*a*a*a},InOut:function(a){return 1>(a*=2)?0.5*a*a*a*a:-0.5*((a-=2)*a*a*a-2)}},Quintic:{In:function(a){return a*a*a* +a*a},Out:function(a){return--a*a*a*a*a+1},InOut:function(a){return 1>(a*=2)?0.5*a*a*a*a*a:0.5*((a-=2)*a*a*a*a+2)}},Sinusoidal:{In:function(a){return 1-Math.cos(a*Math.PI/2)},Out:function(a){return Math.sin(a*Math.PI/2)},InOut:function(a){return 0.5*(1-Math.cos(Math.PI*a))}},Exponential:{In:function(a){return 0===a?0:Math.pow(1024,a-1)},Out:function(a){return 1===a?1:1-Math.pow(2,-10*a)},InOut:function(a){return 0===a?0:1===a?1:1>(a*=2)?0.5*Math.pow(1024,a-1):0.5*(-Math.pow(2,-10*(a-1))+2)}},Circular:{In:function(a){return 1- +Math.sqrt(1-a*a)},Out:function(a){return Math.sqrt(1- --a*a)},InOut:function(a){return 1>(a*=2)?-0.5*(Math.sqrt(1-a*a)-1):0.5*(Math.sqrt(1-(a-=2)*a)+1)}},Elastic:{In:function(a){var c,b=0.1;if(0===a)return 0;if(1===a)return 1;!b||1>b?(b=1,c=0.1):c=0.4*Math.asin(1/b)/(2*Math.PI);return-(b*Math.pow(2,10*(a-=1))*Math.sin((a-c)*2*Math.PI/0.4))},Out:function(a){var c,b=0.1;if(0===a)return 0;if(1===a)return 1;!b||1>b?(b=1,c=0.1):c=0.4*Math.asin(1/b)/(2*Math.PI);return b*Math.pow(2,-10*a)*Math.sin((a-c)* +2*Math.PI/0.4)+1},InOut:function(a){var c,b=0.1;if(0===a)return 0;if(1===a)return 1;!b||1>b?(b=1,c=0.1):c=0.4*Math.asin(1/b)/(2*Math.PI);return 1>(a*=2)?-0.5*b*Math.pow(2,10*(a-=1))*Math.sin((a-c)*2*Math.PI/0.4):0.5*b*Math.pow(2,-10*(a-=1))*Math.sin((a-c)*2*Math.PI/0.4)+1}},Back:{In:function(a){return a*a*(2.70158*a-1.70158)},Out:function(a){return--a*a*(2.70158*a+1.70158)+1},InOut:function(a){return 1>(a*=2)?0.5*a*a*(3.5949095*a-2.5949095):0.5*((a-=2)*a*(3.5949095*a+2.5949095)+2)}},Bounce:{In:function(a){return 1- +TWEEN.Easing.Bounce.Out(1-a)},Out:function(a){return a<1/2.75?7.5625*a*a:a<2/2.75?7.5625*(a-=1.5/2.75)*a+0.75:a<2.5/2.75?7.5625*(a-=2.25/2.75)*a+0.9375:7.5625*(a-=2.625/2.75)*a+0.984375},InOut:function(a){return 0.5>a?0.5*TWEEN.Easing.Bounce.In(2*a):0.5*TWEEN.Easing.Bounce.Out(2*a-1)+0.5}}}; +TWEEN.Interpolation={Linear:function(a,c){var b=a.length-1,d=b*c,e=Math.floor(d),f=TWEEN.Interpolation.Utils.Linear;return 0>c?f(a[0],a[1],d):1<c?f(a[b],a[b-1],b-d):f(a[e],a[e+1>b?b:e+1],d-e)},Bezier:function(a,c){var b=0,d=a.length-1,e=Math.pow,f=TWEEN.Interpolation.Utils.Bernstein,h;for(h=0;h<=d;h++)b+=e(1-c,d-h)*e(c,h)*a[h]*f(d,h);return b},CatmullRom:function(a,c){var b=a.length-1,d=b*c,e=Math.floor(d),f=TWEEN.Interpolation.Utils.CatmullRom;return a[0]===a[b]?(0>c&&(e=Math.floor(d=b*(1+c))),f(a[(e- +1+b)%b],a[e],a[(e+1)%b],a[(e+2)%b],d-e)):0>c?a[0]-(f(a[0],a[0],a[1],a[1],-d)-a[0]):1<c?a[b]-(f(a[b],a[b],a[b-1],a[b-1],d-b)-a[b]):f(a[e?e-1:0],a[e],a[b<e+1?b:e+1],a[b<e+2?b:e+2],d-e)},Utils:{Linear:function(a,c,b){return(c-a)*b+a},Bernstein:function(a,c){var b=TWEEN.Interpolation.Utils.Factorial;return b(a)/b(c)/b(a-c)},Factorial:function(){var a=[1];return function(c){var b=1,d;if(a[c])return a[c];for(d=c;1<d;d--)b*=d;return a[c]=b}}(),CatmullRom:function(a,c,b,d,e){var a=0.5*(b-a),d=0.5*(d-c),f= +e*e;return(2*c-2*b+a+d)*e*f+(-3*c+3*b-2*a-d)*f+a*e+c}}}; diff --git a/COGNET/lib/uclass_BeveledBlockGeometry.js b/COGNET/lib/uclass_BeveledBlockGeometry.js new file mode 100644 index 0000000000000000000000000000000000000000..ad40d31dd8b31a4a2cdf31eee4c8023195eeb9a3 --- /dev/null +++ b/COGNET/lib/uclass_BeveledBlockGeometry.js @@ -0,0 +1,264 @@ +"use strict"; // good practice - see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode +/** + * @author Eric Haines / http://erichaines.com/ + * + * Make a block with beveled edges, to catch highlights. + * + * TODO: bug when bevel >= depth/2 (or width/2, or height/2) + */ +/*global THREE */ + +THREE.BeveledBlockGeometry = function ( width, height, depth, bevel, widthSegments, heightSegments, depthSegments ) { + "use strict"; + + THREE.Geometry.call( this ); + + var scope = this; + + this.width = width; + this.height = height; + this.depth = depth; + + this.bevel = bevel || 0; + + this.widthSegments = widthSegments || 1; + this.heightSegments = heightSegments || 1; + this.depthSegments = depthSegments || 1; + + var width_half = this.width / 2; + var height_half = this.height / 2; + var depth_half = this.depth / 2; + + var adjWidth = this.width - this.bevel*2; + var adjHeight = this.height - this.bevel*2; + var adjDepth = this.depth - this.bevel*2; + + if ( adjDepth > 0 && adjHeight > 0 ) { + buildPlane( 'z', 'y', - 1, - 1, adjDepth, adjHeight, width_half, 0 ); // px + buildPlane( 'z', 'y', 1, - 1, adjDepth, adjHeight, - width_half, 0 ); // nx + } + if ( adjWidth > 0 && adjDepth > 0 ) { + buildPlane( 'x', 'z', 1, 1, adjWidth, adjDepth, height_half, 0 ); // py + buildPlane( 'x', 'z', 1, - 1, adjWidth, adjDepth, - height_half, 0 ); // ny + } + if ( adjWidth > 0 && adjHeight > 0 ) { + buildPlane( 'x', 'y', 1, - 1, adjWidth, adjHeight, depth_half, 0 ); // pz + buildPlane( 'x', 'y', - 1, - 1, adjWidth, adjHeight, - depth_half, 0 ); // nz + } + + // bevels + if ( this.bevel > 0 ) + { + if ( adjWidth < 0 ) { adjWidth = 0; } + if ( adjHeight < 0 ) { adjHeight = 0; } + if ( adjDepth < 0 ) { adjDepth = 0; } + var adjHalfWidth = adjWidth / 2; + var adjHalfHeight = adjHeight / 2; + var adjHalfDepth = adjDepth / 2; + + // 12 edges + // -Y face neighbors + buildBevelSide( 'x', -adjHalfWidth, -height_half, -adjHalfDepth, adjHalfWidth, -adjHalfHeight, -depth_half, 0, -1, 0, 0, 0, -1 ); + buildBevelSide( 'x', adjHalfWidth, -height_half, adjHalfDepth, -adjHalfWidth, -adjHalfHeight, depth_half, 0, -1, 0, 0, 0, 1 ); + buildBevelSide( 'z', -adjHalfWidth, -height_half, adjHalfDepth, -width_half, -adjHalfHeight, -adjHalfDepth, 0, -1, 0, -1, 0, 0 ); + buildBevelSide( 'z', adjHalfWidth, -height_half, -adjHalfDepth, width_half, -adjHalfHeight, adjHalfDepth, 0, -1, 0, 1, 0, 0 ); + // +Y face neighbors + buildBevelSide( 'x', adjHalfWidth, height_half, -adjHalfDepth, -adjHalfWidth, adjHalfHeight, -depth_half, 0, 1, 0, 0, 0, -1 ); + buildBevelSide( 'x', -adjHalfWidth, height_half, adjHalfDepth, adjHalfWidth, adjHalfHeight, depth_half, 0, 1, 0, 0, 0, 1 ); + buildBevelSide( 'z', -adjHalfWidth, height_half, -adjHalfDepth, -width_half, adjHalfHeight, adjHalfDepth, 0, 1, 0, -1, 0, 0 ); + buildBevelSide( 'z', adjHalfWidth, height_half, adjHalfDepth, width_half, adjHalfHeight, -adjHalfDepth, 0, 1, 0, 1, 0, 0 ); + // Y side face neighbors + buildBevelSide( 'y', -width_half, adjHalfHeight, -adjHalfDepth, -adjHalfWidth, -adjHalfHeight, -depth_half, -1, 0, 0, 0, 0, -1 ); + buildBevelSide( 'y', -width_half, -adjHalfHeight, adjHalfDepth, -adjHalfWidth, adjHalfHeight, depth_half, -1, 0, 0, 0, 0, 1 ); + buildBevelSide( 'y', width_half, -adjHalfHeight, -adjHalfDepth, adjHalfWidth, adjHalfHeight, -depth_half, 1, 0, 0, 0, 0, -1 ); + buildBevelSide( 'y', width_half, adjHalfHeight, adjHalfDepth, adjHalfWidth, -adjHalfHeight, depth_half, 1, 0, 0, 0, 0, 1 ); + + // 8 corners + buildBevelCorners( adjHalfWidth, width_half, adjHalfHeight, height_half, adjHalfDepth, depth_half ); + } + + function buildPlane( u, v, udir, vdir, width, height, depth, materialIndex ) { + + var w, ix, iy, + gridX = scope.widthSegments, + gridY = scope.heightSegments, + width_half = width / 2, + height_half = height / 2, + offset = scope.vertices.length; + + if ( ( u === 'x' && v === 'y' ) || ( u === 'y' && v === 'x' ) ) { + + w = 'z'; + + } else if ( ( u === 'x' && v === 'z' ) || ( u === 'z' && v === 'x' ) ) { + + w = 'y'; + gridY = scope.depthSegments; + + } else if ( ( u === 'z' && v === 'y' ) || ( u === 'y' && v === 'z' ) ) { + + w = 'x'; + gridX = scope.depthSegments; + + } + + var gridX1 = gridX + 1, + gridY1 = gridY + 1, + segment_width = width / gridX, + segment_height = height / gridY, + normal = new THREE.Vector3(); + + normal[ w ] = depth > 0 ? 1 : - 1; + + for ( iy = 0; iy < gridY1; iy ++ ) { + + for ( ix = 0; ix < gridX1; ix ++ ) { + + var vector = new THREE.Vector3(); + vector[ u ] = ( ix * segment_width - width_half ) * udir; + vector[ v ] = ( iy * segment_height - height_half ) * vdir; + vector[ w ] = depth; + + scope.vertices.push( vector ); + + } + + } + + for ( iy = 0; iy < gridY; iy++ ) { + + for ( ix = 0; ix < gridX; ix++ ) { + + var a = ix + gridX1 * iy; + var b = ix + gridX1 * ( iy + 1 ); + var c = ( ix + 1 ) + gridX1 * ( iy + 1 ); + var d = ( ix + 1 ) + gridX1 * iy; + + var face = new THREE.Face4( a + offset, b + offset, c + offset, d + offset ); + // not needed? We don't compute others: face.normal.copy( normal ); + face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone(), normal.clone() ); + face.materialIndex = materialIndex; + + scope.faces.push( face ); + scope.faceVertexUvs[ 0 ].push( [ + new THREE.Vector2( ix / gridX, 1 - iy / gridY ), + new THREE.Vector2( ix / gridX, 1 - ( iy + 1 ) / gridY ), + new THREE.Vector2( ( ix + 1 ) / gridX, 1- ( iy + 1 ) / gridY ), + new THREE.Vector2( ( ix + 1 ) / gridX, 1 - iy / gridY ) + ] ); + } + } + } + + function buildBevelSide( longSide, xlo, ylo, zlo, xhi, yhi, zhi, xn1, yn1, zn1, xn2, yn2, zn2 ) { + + var vector; + var offset = scope.vertices.length; + + vector = new THREE.Vector3(xlo,ylo,zlo); + scope.vertices.push( vector ); + if ( longSide === 'x' ) { + vector = new THREE.Vector3(xlo,yhi,zhi); + scope.vertices.push( vector ); + vector = new THREE.Vector3(xhi,yhi,zhi); + scope.vertices.push( vector ); + vector = new THREE.Vector3(xhi,ylo,zlo); + scope.vertices.push( vector ); + } + else if ( longSide === 'y' ) { + vector = new THREE.Vector3(xhi,ylo,zhi); + scope.vertices.push( vector ); + vector = new THREE.Vector3(xhi,yhi,zhi); + scope.vertices.push( vector ); + vector = new THREE.Vector3(xlo,yhi,zlo); + scope.vertices.push( vector ); + } + else { + vector = new THREE.Vector3(xhi,yhi,zlo); + scope.vertices.push( vector ); + vector = new THREE.Vector3(xhi,yhi,zhi); + scope.vertices.push( vector ); + vector = new THREE.Vector3(xlo,ylo,zhi); + scope.vertices.push( vector ); + } + + var face = new THREE.Face4( offset, offset+1, offset+2, offset+3 ); + var vnorm1 = new THREE.Vector3( xn1, yn1, zn1 ); + var vnorm2 = new THREE.Vector3( xn2, yn2, zn2 ); + face.vertexNormals.push( vnorm1.clone(), vnorm2.clone(), vnorm2.clone(), vnorm1.clone() ); + face.materialIndex = 0; + + scope.faces.push( face ); + // these are certainly wrong + scope.faceVertexUvs[ 0 ].push( [ + new THREE.Vector2( 0, 0 ), + new THREE.Vector2( 0, 1 ), + new THREE.Vector2( 1, 1 ), + new THREE.Vector2( 1, 0 ) + ] ); + } + + function buildBevelCorners( xah, xh, yah, yh, zah, zh ) { + + var vector; + var offset = scope.vertices.length; + + var count = 0; + for ( var i = 0; i < 2; i++ ) { + var xsign = i ? 1 : -1; + for ( var j = 0; j < 2; j++ ) { + var ysign = j ? 1 : -1; + for ( var k = 0; k < 2; k++ ) { + var zsign = k ? 1 : -1; + + // first vertex + vector = new THREE.Vector3(xsign*xh,ysign*yah,zsign*zah); + scope.vertices.push( vector ); + var vnorm1 = new THREE.Vector3(xsign,0,0); + + vector = new THREE.Vector3(xsign*xah,ysign*yh,zsign*zah); + scope.vertices.push( vector ); + var vnorm2 = new THREE.Vector3(0,ysign,0); + + vector = new THREE.Vector3(xsign*xah,ysign*yah,zsign*zh); + scope.vertices.push( vector ); + var vnorm3 = new THREE.Vector3(0,0,zsign); + + var face; + face = new THREE.Face3( offset, offset+1, offset+2 ); + + if ( xsign * ysign * zsign === 1 ) + { + face = new THREE.Face3( offset, offset+1, offset+2 ); + face.vertexNormals.push( vnorm1, vnorm2, vnorm3 ); + } + else + { + face = new THREE.Face3( offset+2, offset+1, offset ); + face.vertexNormals.push( vnorm3, vnorm2, vnorm1 ); + } + face.materialIndex = 0; + + scope.faces.push( face ); + // these are certainly wrong + scope.faceVertexUvs[ 0 ].push( [ + new THREE.Vector2( 0, 0 ), + new THREE.Vector2( 0, 1 ), + new THREE.Vector2( 1, 1 ) + ] ); + + offset += 3; + + count++; + } + } + } + } + + this.computeCentroids(); + this.computeFaceNormals(); + this.mergeVertices(); + +}; + +THREE.BeveledBlockGeometry.prototype = Object.create( THREE.Geometry.prototype ); \ No newline at end of file diff --git a/COGNET/lib/uclass_TeacupGeometry.js b/COGNET/lib/uclass_TeacupGeometry.js new file mode 100644 index 0000000000000000000000000000000000000000..878beb88eda7c1176160e1fed02de26552994a69 --- /dev/null +++ b/COGNET/lib/uclass_TeacupGeometry.js @@ -0,0 +1,529 @@ +"use strict"; // good practice - see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode +/** + * @author Eric Haines / http://erichaines.com/ + * + * Created for the Udacity course "Interactive Rendering", http://bit.ly/ericity + * + * Tessellate a teacup into triangular patches. + * + * See http://www.sjbaker.org/wiki/index.php?title=The_History_of_The_Teacup for + * the history of the Teacup and teacup + * + * THREE.TeacupGeometry = function ( size, segments ) + * + * defaults: size = 50, segments = 10 + * + * size is a relative scale: I've scaled the Teacup to fit vertically between -1 and 1. + * Think of it as a "radius". + * segments - number of line segments to subdivide each patch edge; + * 1 is possible but gives degenerates, so two is the real minimum. + * + * segments 'n' determines the number of objects output. + * Total patches = 26*2*n*n + * + * size_factor # triangles + * 1 52 + * 2 208 + * 3 468 + * 4 832 + * 5 1300 + * 6 1872 + * + * 10 5200 + * 20 20800 + * 30 46800 + * 40 83200 + */ +/*global THREE */ + +THREE.TeacupGeometry = function ( size, segments ) { + "use strict"; + + // 26 * 4 * 4 Bezier spline patches, note +1 start + // Data from ftp://ftp.funet.fi/pub/sci/graphics/packages/objects/teaset.tar.Z + var TeacupPatches = [ +1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, +4,17,18,19,8,20,21,22,12,23,24,25,16,26,27,28, +19,29,30,31,22,32,33,34,25,35,36,37,28,38,39,40, +31,41,42,1,34,43,44,5,37,45,46,9,40,47,48,13, +13,14,15,16,49,50,51,52,53,54,55,56,57,58,59,60, +16,26,27,28,52,61,62,63,56,64,65,66,60,67,68,69, +28,38,39,40,63,70,71,72,66,73,74,75,69,76,77,78, +40,47,48,13,72,79,80,49,75,81,82,53,78,83,84,57, +193,194,195,196,197,198,199,200,201,202,203,204,1,2,3,4, +196,205,206,207,200,208,209,210,204,211,212,213,4,17,18,19, +207,214,215,216,210,217,218,219,213,220,221,222,19,29,30,31, +216,223,224,193,219,225,226,197,222,227,228,201,31,41,42,1, +229,230,231,28,232,233,234,235,236,237,238,239,240,241,242,243, +28,244,245,229,235,246,247,232,239,248,249,236,243,250,251,240, +57,58,59,60,85,86,87,88,89,90,91,92,93,94,95,96, +60,67,68,69,88,97,98,99,92,100,101,102,96,103,104,105, +69,76,77,78,99,106,107,108,102,109,110,111,105,112,113,114, +78,83,84,57,108,115,116,85,111,117,118,89,114,119,120,93, +93,94,95,96,121,122,123,124,125,126,127,128,129,130,131,132, +96,103,104,105,124,133,134,135,128,136,137,138,132,139,140,141, +105,112,113,114,135,142,143,144,138,145,146,147,141,148,149,150, +114,119,120,93,144,151,152,121,147,153,154,125,150,155,156,129, +129,130,131,132,157,158,159,160,161,162,163,164,165,166,167,168, +132,139,140,141,160,169,170,171,164,172,173,174,168,175,176,177, +141,148,149,150,171,178,179,180,174,181,182,183,177,184,185,186, +150,155,156,129,180,187,188,157,183,189,190,161,186,191,192,165 + ] ; + + var TeacupVertices = [ +0.409091,0.772727,0.0, +0.409091,0.772727,-0.229091, +0.229091,0.772727,-0.409091, +0.0,0.772727,-0.409091, +0.409091,0.886364,0.0, +0.409091,0.886364,-0.229091, +0.229091,0.886364,-0.409091, +0.0,0.886364,-0.409091, +0.454545,0.886364,0.0, +0.454545,0.886364,-0.254545, +0.254545,0.886364,-0.454545, +0.0,0.886364,-0.454545, +0.454545,0.772727,0.0, +0.454545,0.772727,-0.254545, +0.254545,0.772727,-0.454545, +0.0,0.772727,-0.454545, +-0.229091,0.772727,-0.409091, +-0.409091,0.772727,-0.229091, +-0.409091,0.772727,0.0, +-0.229091,0.886364,-0.409091, +-0.409091,0.886364,-0.229091, +-0.409091,0.886364,0.0, +-0.254545,0.886364,-0.454545, +-0.454545,0.886364,-0.254545, +-0.454545,0.886364,0.0, +-0.254545,0.772727,-0.454545, +-0.454545,0.772727,-0.254545, +-0.454545,0.772727,0.0, +-0.409091,0.772727,0.229091, +-0.229091,0.772727,0.409091, +0.0,0.772727,0.409091, +-0.409091,0.886364,0.229091, +-0.229091,0.886364,0.409091, +0.0,0.886364,0.409091, +-0.454545,0.886364,0.254545, +-0.254545,0.886364,0.454545, +0.0,0.886364,0.454545, +-0.454545,0.772727,0.254545, +-0.254545,0.772727,0.454545, +0.0,0.772727,0.454545, +0.229091,0.772727,0.409091, +0.409091,0.772727,0.229091, +0.229091,0.886364,0.409091, +0.409091,0.886364,0.229091, +0.254545,0.886364,0.454545, +0.454545,0.886364,0.254545, +0.254545,0.772727,0.454545, +0.454545,0.772727,0.254545, +0.454545,0.545455,0.0, +0.454545,0.545455,-0.254545, +0.254545,0.545455,-0.454545, +0.0,0.545455,-0.454545, +0.454545,0.272727,0.0, +0.454545,0.272727,-0.254545, +0.254545,0.272727,-0.454545, +0.0,0.272727,-0.454545, +0.318182,0.0454545,0.0, +0.318182,0.0454545,-0.178182, +0.178182,0.0454545,-0.318182, +0.0,0.0454545,-0.318182, +-0.254545,0.545455,-0.454545, +-0.454545,0.545455,-0.254545, +-0.454545,0.545455,0.0, +-0.254545,0.272727,-0.454545, +-0.454545,0.272727,-0.254545, +-0.454545,0.272727,0.0, +-0.178182,0.0454545,-0.318182, +-0.318182,0.0454545,-0.178182, +-0.318182,0.0454545,0.0, +-0.454545,0.545455,0.254545, +-0.254545,0.545455,0.454545, +0.0,0.545455,0.454545, +-0.454545,0.272727,0.254545, +-0.254545,0.272727,0.454545, +0.0,0.272727,0.454545, +-0.318182,0.0454545,0.178182, +-0.178182,0.0454545,0.318182, +0.0,0.0454545,0.318182, +0.254545,0.545455,0.454545, +0.454545,0.545455,0.254545, +0.254545,0.272727,0.454545, +0.454545,0.272727,0.254545, +0.178182,0.0454545,0.318182, +0.318182,0.0454545,0.178182, +0.545455,0.0454545,0.0, +0.545455,0.0454545,-0.305455, +0.305455,0.0454545,-0.545455, +0.0,0.0454545,-0.545455, +0.727273,0.136364,0.0, +0.727273,0.136364,-0.407273, +0.407273,0.136364,-0.727273, +0.0,0.136364,-0.727273, +0.909091,0.136364,0.0, +0.909091,0.136364,-0.509091, +0.509091,0.136364,-0.909091, +0.0,0.136364,-0.909091, +-0.305455,0.0454545,-0.545455, +-0.545455,0.0454545,-0.305455, +-0.545455,0.0454545,0.0, +-0.407273,0.136364,-0.727273, +-0.727273,0.136364,-0.407273, +-0.727273,0.136364,0.0, +-0.509091,0.136364,-0.909091, +-0.909091,0.136364,-0.509091, +-0.909091,0.136364,0.0, +-0.545455,0.0454545,0.305455, +-0.305455,0.0454545,0.545455, +0.0,0.0454545,0.545455, +-0.727273,0.136364,0.407273, +-0.407273,0.136364,0.727273, +0.0,0.136364,0.727273, +-0.909091,0.136364,0.509091, +-0.509091,0.136364,0.909091, +0.0,0.136364,0.909091, +0.305455,0.0454545,0.545455, +0.545455,0.0454545,0.305455, +0.407273,0.136364,0.727273, +0.727273,0.136364,0.407273, +0.509091,0.136364,0.909091, +0.909091,0.136364,0.509091, +1.0,0.136364,0.0, +1.0,0.136364,-0.56, +0.56,0.136364,-1.0, +0.0,0.136364,-1.0, +1.0,0.0909091,0.0, +1.0,0.0909091,-0.56, +0.56,0.0909091,-1.0, +0.0,0.0909091,-1.0, +0.909091,0.0909091,0.0, +0.909091,0.0909091,-0.509091, +0.509091,0.0909091,-0.909091, +0.0,0.0909091,-0.909091, +-0.56,0.136364,-1.0, +-1.0,0.136364,-0.56, +-1.0,0.136364,0.0, +-0.56,0.0909091,-1.0, +-1.0,0.0909091,-0.56, +-1.0,0.0909091,0.0, +-0.509091,0.0909091,-0.909091, +-0.909091,0.0909091,-0.509091, +-0.909091,0.0909091,0.0, +-1.0,0.136364,0.56, +-0.56,0.136364,1.0, +0.0,0.136364,1.0, +-1.0,0.0909091,0.56, +-0.56,0.0909091,1.0, +0.0,0.0909091,1.0, +-0.909091,0.0909091,0.509091, +-0.509091,0.0909091,0.909091, +0.0,0.0909091,0.909091, +0.56,0.136364,1.0, +1.0,0.136364,0.56, +0.56,0.0909091,1.0, +1.0,0.0909091,0.56, +0.509091,0.0909091,0.909091, +0.909091,0.0909091,0.509091, +0.727273,0.0909091,0.0, +0.727273,0.0909091,-0.407273, +0.407273,0.0909091,-0.727273, +0.0,0.0909091,-0.727273, +0.545455,0.0,0.0, +0.545455,0.0,-0.305455, +0.305455,0.0,-0.545455, +0.0,0.0,-0.545455, +0.318182,0.0,0.0, +0.318182,0.0,-0.178182, +0.178182,0.0,-0.318182, +0.0,0.0,-0.318182, +-0.407273,0.0909091,-0.727273, +-0.727273,0.0909091,-0.407273, +-0.727273,0.0909091,0.0, +-0.305455,0.0,-0.545455, +-0.545455,0.0,-0.305455, +-0.545455,0.0,0.0, +-0.178182,0.0,-0.318182, +-0.318182,0.0,-0.178182, +-0.318182,0.0,0.0, +-0.727273,0.0909091,0.407273, +-0.407273,0.0909091,0.727273, +0.0,0.0909091,0.727273, +-0.545455,0.0,0.305455, +-0.305455,0.0,0.545455, +0.0,0.0,0.545455, +-0.318182,0.0,0.178182, +-0.178182,0.0,0.318182, +0.0,0.0,0.318182, +0.407273,0.0909091,0.727273, +0.727273,0.0909091,0.407273, +0.305455,0.0,0.545455, +0.545455,0.0,0.305455, +0.178182,0.0,0.318182, +0.318182,0.0,0.178182, +0.272727,0.0454545,0.0, +0.272727,0.0454545,-0.152727, +0.152727,0.0454545,-0.272727, +0.0,0.0454545,-0.272727, +0.409091,0.272727,0.0, +0.409091,0.272727,-0.229091, +0.229091,0.272727,-0.409091, +0.0,0.272727,-0.409091, +0.409091,0.545455,0.0, +0.409091,0.545455,-0.229091, +0.229091,0.545455,-0.409091, +0.0,0.545455,-0.409091, +-0.152727,0.0454545,-0.272727, +-0.272727,0.0454545,-0.152727, +-0.272727,0.0454545,0.0, +-0.229091,0.272727,-0.409091, +-0.409091,0.272727,-0.229091, +-0.409091,0.272727,0.0, +-0.229091,0.545455,-0.409091, +-0.409091,0.545455,-0.229091, +-0.409091,0.545455,0.0, +-0.272727,0.0454545,0.152727, +-0.152727,0.0454545,0.272727, +0.0,0.0454545,0.272727, +-0.409091,0.272727,0.229091, +-0.229091,0.272727,0.409091, +0.0,0.272727,0.409091, +-0.409091,0.545455,0.229091, +-0.229091,0.545455,0.409091, +0.0,0.545455,0.409091, +0.152727,0.0454545,0.272727, +0.272727,0.0454545,0.152727, +0.229091,0.272727,0.409091, +0.409091,0.272727,0.229091, +0.229091,0.545455,0.409091, +0.409091,0.545455,0.229091, +-0.454545,0.704545,0.0, +-0.454545,0.704545,-0.0454545, +-0.454545,0.772727,-0.0454545, +-0.772727,0.863636,0.0, +-0.772727,0.863636,-0.0454545, +-0.818182,0.954545,-0.0454545, +-0.818182,0.954545,0.0, +-0.772727,0.522727,0.0, +-0.772727,0.522727,-0.0454545, +-0.909091,0.477273,-0.0454545, +-0.909091,0.477273,0.0, +-0.409091,0.363636,0.0, +-0.409091,0.363636,-0.0454545, +-0.409091,0.295455,-0.0454545, +-0.409091,0.295455,0.0, +-0.454545,0.772727,0.0454545, +-0.454545,0.704545,0.0454545, +-0.818182,0.954545,0.0454545, +-0.772727,0.863636,0.0454545, +-0.909091,0.477273,0.0454545, +-0.772727,0.522727,0.0454545, +-0.409091,0.295455,0.0454545, +-0.409091,0.363636,0.0454545 + ] ; + + var minPatches = 0; + var maxPatches = 26; + + THREE.Geometry.call( this ); + + this.size = size || 50; + + // number of segments per patch + this.segments = Math.max( 2, Math.floor( segments ) || 10 ); + + // scale the size to be the real scaling factor + var maxHeight = 0.857954740524292; + + var maxHeight2 = maxHeight/2; + var trueSize = this.size / maxHeight2; + + var normals = [], uvs = []; + // bezier form + var ms = new THREE.Matrix4( -1.0, 3.0, -3.0, 1.0, + 3.0, -6.0, 3.0, 0.0, + -3.0, 3.0, 0.0, 0.0, + 1.0, 0.0, 0.0, 0.0 ) ; + + var g = []; + var i, r, c; + + var sp = []; + var tp = []; + var dsp = []; + var dtp = []; + + // M * G * M matrix, sort of see + // http://www.cs.helsinki.fi/group/goa/mallinnus/curves/surfaces.html + var mgm = []; + + var vert = []; + var sdir = []; + var tdir = []; + + var norm = new THREE.Vector3(); + + var tcoord; + + var sstep, tstep; + var gmx, tmtx; + + var vertPerRow; + + var s, t, sval, tval, p, dsval, dtval; + + var vsp, vtp, vdsp, vdtp; + var vsdir, vtdir, vertOut; + var v1, v2, v3, v4; + + var mst = ms.clone(); + mst.transpose(); + + // internal function: test if triangle has any matching vertices; + // if so, don't output, since it won't display anything. + var notDegenerate = function ( vtx1, vtx2, vtx3 ) { + if ( vtx1.equals( vtx2 ) ) { return false; } + if ( vtx1.equals( vtx3 ) ) { return false; } + if ( vtx2.equals( vtx3 ) ) { return false; } + return true; + }; + + + for ( i = 0; i < 3; i++ ) + { + mgm[i] = new THREE.Matrix4(); + } + + vertPerRow = (this.segments+1); + + var surfCount = 0; + //var faceCount = 0; + + for ( var surf = minPatches ; surf < maxPatches ; surf++ ) { + // get M * G * M matrix for x,y,z + for ( i = 0 ; i < 3 ; i++ ) { + // get control patches + for ( r = 0 ; r < 4 ; r++ ) { + for ( c = 0 ; c < 4 ; c++ ) { + // transposed; note subtraction of 1 for index + g[c*4+r] = TeacupVertices[(TeacupPatches[surf*16 + r*4 + c]-1)*3 + i] ; + } + } + + // Shockingly, the following three.js does NOT work. Setting this way appears to give the order + // g[0], g[4], g[8], etc. to the elements! I could avoid the transpose above + // and things would "just work", but this weird ordering would be mysterious. + //var gmx = new THREE.Matrix4(); + //gmx.elements.set( g ); + // So, explicitly set the matrix this way: + gmx = new THREE.Matrix4( g[0], g[1], g[2], g[3], g[4], g[5], g[6], g[7], g[8], g[9], g[10], g[11], g[12], g[13], g[14], g[15] ); + + tmtx = new THREE.Matrix4(); + tmtx.multiplyMatrices( gmx, ms ); + mgm[i].multiplyMatrices( mst, tmtx ); + } + + // step along, get points, and output + for ( sstep = 0 ; sstep <= this.segments ; sstep++ ) { + s = sstep / this.segments; + + for ( tstep = 0 ; tstep <= this.segments ; tstep++ ) { + t = tstep / this.segments; + + // point from basis + // get power vectors and their derivatives + for ( p = 4, sval = tval = 1.0 ; p-- ; ) { + sp[p] = sval ; + tp[p] = tval ; + sval *= s ; + tval *= t ; + + if ( p === 3 ) { + dsp[p] = dtp[p] = 0.0 ; + dsval = dtval = 1.0 ; + } else { + dsp[p] = dsval * (3-p) ; + dtp[p] = dtval * (3-p) ; + dsval *= s ; + dtval *= t ; + } + } + + vsp = new THREE.Vector4( sp[0], sp[1], sp[2], sp[3] ); + vtp = new THREE.Vector4( tp[0], tp[1], tp[2], tp[3] ); + vdsp = new THREE.Vector4( dsp[0], dsp[1], dsp[2], dsp[3] ); + vdtp = new THREE.Vector4( dtp[0], dtp[1], dtp[2], dtp[3] ); + + // do for x,y,z + for ( i = 0 ; i < 3 ; i++ ) { + // multiply power vectors times matrix to get value + tcoord = vsp.clone(); + tcoord.applyMatrix4( mgm[i] ); + vert[i] = tcoord.dot( vtp ); + + // get s and t tangent vectors + tcoord = vdsp.clone(); + tcoord.applyMatrix4( mgm[i] ); + sdir[i] = tcoord.dot( vtp ) ; + + tcoord = vsp.clone(); + tcoord.applyMatrix4( mgm[i] ); + tdir[i] = tcoord.dot( vdtp ) ; + } + + // find normal + vsdir = new THREE.Vector3( sdir[0], sdir[1], sdir[2] ); + vtdir = new THREE.Vector3( tdir[0], tdir[1], tdir[2] ); + norm.crossVectors( vtdir, vsdir ); + norm.normalize(); + + // rotate on X axis + // interestingly, normals need to be reversed; I suspect the patch + // has opposite handedness from the teapot. Also, Y is up for the teacup. + normals.push( new THREE.Vector3( -norm.x, -norm.y, -norm.z ) ); + + // TODO: check texturing + uvs.push( new THREE.Vector2( 1-t, 1-s ) ); + + // three.js uses Y up, the code makes Y up, all is fine. + // Move teacup to be centered around origin, three.js style. + vertOut = new THREE.Vector3( trueSize*vert[0], trueSize*(vert[1]-maxHeight2), trueSize*vert[2] ); + + this.vertices.push( vertOut ); + + } + } + + // save the faces + for ( sstep = 0 ; sstep < this.segments ; sstep++ ) { + for ( tstep = 0 ; tstep < this.segments ; tstep++ ) { + v1 = surfCount * vertPerRow * vertPerRow + sstep * vertPerRow + tstep; + v2 = v1 + 1; + v3 = v2 + vertPerRow; + v4 = v1 + vertPerRow; + + if ( notDegenerate ( this.vertices[v1], this.vertices[v2], this.vertices[v3] ) ) { + this.faces.push( new THREE.Face3( v1, v2, v3, [ normals[v1], normals[v2], normals[v3] ] ) ); + this.faceVertexUvs[ 0 ].push( [ uvs[v1], uvs[v2], uvs[v3] ] ); + } + if ( notDegenerate ( this.vertices[v1], this.vertices[v3], this.vertices[v4] ) ) { + this.faces.push( new THREE.Face3( v1, v3, v4, [ normals[v1], normals[v3], normals[v4] ] ) ); + this.faceVertexUvs[ 0 ].push( [ uvs[v1], uvs[v3], uvs[v4] ] ); + } + //faceCount+=2; + } + } + // increment only if a surface was used + surfCount++; + } + + this.computeCentroids(); + this.computeFaceNormals(); + this.mergeVertices(); + +}; + + +THREE.TeacupGeometry.prototype = Object.create( THREE.Geometry.prototype ); diff --git a/COGNET/lib/uclass_TeapotGeometry.js b/COGNET/lib/uclass_TeapotGeometry.js new file mode 100644 index 0000000000000000000000000000000000000000..05efc78762f23838b6d304f1ee692d34ca3276bf --- /dev/null +++ b/COGNET/lib/uclass_TeapotGeometry.js @@ -0,0 +1,737 @@ +/** + * @author Eric Haines / http://erichaines.com/ + * + * Tessellates the famous Utah teapot database by Martin Newell into triangles. + * + * THREE.TeapotGeometry = function ( size, segments, bottom, lid, body, fitLid, blinn ) + * + * defaults: size = 50, segments = 10, bottom = true, lid = true, body = true, + * fitLid = false, blinn = true + * + * size is a relative scale: I've scaled the teapot to fit vertically between -1 and 1. + * Think of it as a "radius". + * segments - number of line segments to subdivide each patch edge; + * 1 is possible but gives degenerates, so two is the real minimum. + * bottom - boolean, if true (default) then the bottom patches are added. Some consider + * adding the bottom heresy, so set this to "false" to adhere to the One True Way. + * lid - to remove the lid and look inside, set to true. + * body - to remove the body and leave the lid, set this and "bottom" to false. + * fitLid - the lid is a tad small in the original. This stretches it a bit so you can't + * see the teapot's insides through the gap. + * blinn - Jim Blinn scaled the original data vertically by dividing by about 1.3 to look + * nicer. If you want to see the original teapot, similar to the real-world model, set + * this to false. True by default. + * See http://en.wikipedia.org/wiki/File:Original_Utah_Teapot.jpg for the original + * real-world teapot (from http://en.wikipedia.org/wiki/Utah_teapot). + * + * Note that the bottom (the last four patches) is not flat - blame Frank Crow, not me. + * + * The teapot should normally be rendered as a double sided object, since for some + * patches both sides can be seen, e.g., the gap around the lid and inside the spout. + * + * Segments 'n' determines the number of triangles output. + * Total triangles = 32*2*n*n - 8*n [degenerates at the top and bottom cusps are deleted] + * + * size_factor # triangles + * 1 56 + * 2 240 + * 3 552 + * 4 992 + * + * 10 6320 + * 20 25440 + * 30 57360 + * + * Code converted from my ancient SPD software, http://tog.acm.org/resources/SPD/ + * Created for the Udacity course "Interactive Rendering", http://bit.ly/ericity + * Lesson: https://www.udacity.com/course/viewer#!/c-cs291/l-68866048/m-106482448 + * YouTube video on teapot history: https://www.youtube.com/watch?v=DxMfblPzFNc + * + * See https://en.wikipedia.org/wiki/Utah_teapot for the history of the teapot + * + */ +/*global THREE */ + +THREE.TeapotGeometry = function ( size, segments, bottom, lid, body, fitLid, blinn ) { + + "use strict"; + + // 32 * 4 * 4 Bezier spline patches + var teapotPatches = [ +/*rim*/ +0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, +3,16,17,18,7,19,20,21,11,22,23,24,15,25,26,27, +18,28,29,30,21,31,32,33,24,34,35,36,27,37,38,39, +30,40,41,0,33,42,43,4,36,44,45,8,39,46,47,12, +/*body*/ +12,13,14,15,48,49,50,51,52,53,54,55,56,57,58,59, +15,25,26,27,51,60,61,62,55,63,64,65,59,66,67,68, +27,37,38,39,62,69,70,71,65,72,73,74,68,75,76,77, +39,46,47,12,71,78,79,48,74,80,81,52,77,82,83,56, +56,57,58,59,84,85,86,87,88,89,90,91,92,93,94,95, +59,66,67,68,87,96,97,98,91,99,100,101,95,102,103,104, +68,75,76,77,98,105,106,107,101,108,109,110,104,111,112,113, +77,82,83,56,107,114,115,84,110,116,117,88,113,118,119,92, +/*handle*/ +120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135, +123,136,137,120,127,138,139,124,131,140,141,128,135,142,143,132, +132,133,134,135,144,145,146,147,148,149,150,151,68,152,153,154, +135,142,143,132,147,155,156,144,151,157,158,148,154,159,160,68, +/*spout*/ +161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176, +164,177,178,161,168,179,180,165,172,181,182,169,176,183,184,173, +173,174,175,176,185,186,187,188,189,190,191,192,193,194,195,196, +176,183,184,173,188,197,198,185,192,199,200,189,196,201,202,193, +/*lid*/ +203,203,203,203,204,205,206,207,208,208,208,208,209,210,211,212, +203,203,203,203,207,213,214,215,208,208,208,208,212,216,217,218, +203,203,203,203,215,219,220,221,208,208,208,208,218,222,223,224, +203,203,203,203,221,225,226,204,208,208,208,208,224,227,228,209, +209,210,211,212,229,230,231,232,233,234,235,236,237,238,239,240, +212,216,217,218,232,241,242,243,236,244,245,246,240,247,248,249, +218,222,223,224,243,250,251,252,246,253,254,255,249,256,257,258, +224,227,228,209,252,259,260,229,255,261,262,233,258,263,264,237, +/*bottom*/ +265,265,265,265,266,267,268,269,270,271,272,273,92,119,118,113, +265,265,265,265,269,274,275,276,273,277,278,279,113,112,111,104, +265,265,265,265,276,280,281,282,279,283,284,285,104,103,102,95, +265,265,265,265,282,286,287,266,285,288,289,270,95,94,93,92 + ] ; + + var teapotVertices = [ +1.4,0,2.4, +1.4,-0.784,2.4, +0.784,-1.4,2.4, +0,-1.4,2.4, +1.3375,0,2.53125, +1.3375,-0.749,2.53125, +0.749,-1.3375,2.53125, +0,-1.3375,2.53125, +1.4375,0,2.53125, +1.4375,-0.805,2.53125, +0.805,-1.4375,2.53125, +0,-1.4375,2.53125, +1.5,0,2.4, +1.5,-0.84,2.4, +0.84,-1.5,2.4, +0,-1.5,2.4, +-0.784,-1.4,2.4, +-1.4,-0.784,2.4, +-1.4,0,2.4, +-0.749,-1.3375,2.53125, +-1.3375,-0.749,2.53125, +-1.3375,0,2.53125, +-0.805,-1.4375,2.53125, +-1.4375,-0.805,2.53125, +-1.4375,0,2.53125, +-0.84,-1.5,2.4, +-1.5,-0.84,2.4, +-1.5,0,2.4, +-1.4,0.784,2.4, +-0.784,1.4,2.4, +0,1.4,2.4, +-1.3375,0.749,2.53125, +-0.749,1.3375,2.53125, +0,1.3375,2.53125, +-1.4375,0.805,2.53125, +-0.805,1.4375,2.53125, +0,1.4375,2.53125, +-1.5,0.84,2.4, +-0.84,1.5,2.4, +0,1.5,2.4, +0.784,1.4,2.4, +1.4,0.784,2.4, +0.749,1.3375,2.53125, +1.3375,0.749,2.53125, +0.805,1.4375,2.53125, +1.4375,0.805,2.53125, +0.84,1.5,2.4, +1.5,0.84,2.4, +1.75,0,1.875, +1.75,-0.98,1.875, +0.98,-1.75,1.875, +0,-1.75,1.875, +2,0,1.35, +2,-1.12,1.35, +1.12,-2,1.35, +0,-2,1.35, +2,0,0.9, +2,-1.12,0.9, +1.12,-2,0.9, +0,-2,0.9, +-0.98,-1.75,1.875, +-1.75,-0.98,1.875, +-1.75,0,1.875, +-1.12,-2,1.35, +-2,-1.12,1.35, +-2,0,1.35, +-1.12,-2,0.9, +-2,-1.12,0.9, +-2,0,0.9, +-1.75,0.98,1.875, +-0.98,1.75,1.875, +0,1.75,1.875, +-2,1.12,1.35, +-1.12,2,1.35, +0,2,1.35, +-2,1.12,0.9, +-1.12,2,0.9, +0,2,0.9, +0.98,1.75,1.875, +1.75,0.98,1.875, +1.12,2,1.35, +2,1.12,1.35, +1.12,2,0.9, +2,1.12,0.9, +2,0,0.45, +2,-1.12,0.45, +1.12,-2,0.45, +0,-2,0.45, +1.5,0,0.225, +1.5,-0.84,0.225, +0.84,-1.5,0.225, +0,-1.5,0.225, +1.5,0,0.15, +1.5,-0.84,0.15, +0.84,-1.5,0.15, +0,-1.5,0.15, +-1.12,-2,0.45, +-2,-1.12,0.45, +-2,0,0.45, +-0.84,-1.5,0.225, +-1.5,-0.84,0.225, +-1.5,0,0.225, +-0.84,-1.5,0.15, +-1.5,-0.84,0.15, +-1.5,0,0.15, +-2,1.12,0.45, +-1.12,2,0.45, +0,2,0.45, +-1.5,0.84,0.225, +-0.84,1.5,0.225, +0,1.5,0.225, +-1.5,0.84,0.15, +-0.84,1.5,0.15, +0,1.5,0.15, +1.12,2,0.45, +2,1.12,0.45, +0.84,1.5,0.225, +1.5,0.84,0.225, +0.84,1.5,0.15, +1.5,0.84,0.15, +-1.6,0,2.025, +-1.6,-0.3,2.025, +-1.5,-0.3,2.25, +-1.5,0,2.25, +-2.3,0,2.025, +-2.3,-0.3,2.025, +-2.5,-0.3,2.25, +-2.5,0,2.25, +-2.7,0,2.025, +-2.7,-0.3,2.025, +-3,-0.3,2.25, +-3,0,2.25, +-2.7,0,1.8, +-2.7,-0.3,1.8, +-3,-0.3,1.8, +-3,0,1.8, +-1.5,0.3,2.25, +-1.6,0.3,2.025, +-2.5,0.3,2.25, +-2.3,0.3,2.025, +-3,0.3,2.25, +-2.7,0.3,2.025, +-3,0.3,1.8, +-2.7,0.3,1.8, +-2.7,0,1.575, +-2.7,-0.3,1.575, +-3,-0.3,1.35, +-3,0,1.35, +-2.5,0,1.125, +-2.5,-0.3,1.125, +-2.65,-0.3,0.9375, +-2.65,0,0.9375, +-2,-0.3,0.9, +-1.9,-0.3,0.6, +-1.9,0,0.6, +-3,0.3,1.35, +-2.7,0.3,1.575, +-2.65,0.3,0.9375, +-2.5,0.3,1.125, +-1.9,0.3,0.6, +-2,0.3,0.9, +1.7,0,1.425, +1.7,-0.66,1.425, +1.7,-0.66,0.6, +1.7,0,0.6, +2.6,0,1.425, +2.6,-0.66,1.425, +3.1,-0.66,0.825, +3.1,0,0.825, +2.3,0,2.1, +2.3,-0.25,2.1, +2.4,-0.25,2.025, +2.4,0,2.025, +2.7,0,2.4, +2.7,-0.25,2.4, +3.3,-0.25,2.4, +3.3,0,2.4, +1.7,0.66,0.6, +1.7,0.66,1.425, +3.1,0.66,0.825, +2.6,0.66,1.425, +2.4,0.25,2.025, +2.3,0.25,2.1, +3.3,0.25,2.4, +2.7,0.25,2.4, +2.8,0,2.475, +2.8,-0.25,2.475, +3.525,-0.25,2.49375, +3.525,0,2.49375, +2.9,0,2.475, +2.9,-0.15,2.475, +3.45,-0.15,2.5125, +3.45,0,2.5125, +2.8,0,2.4, +2.8,-0.15,2.4, +3.2,-0.15,2.4, +3.2,0,2.4, +3.525,0.25,2.49375, +2.8,0.25,2.475, +3.45,0.15,2.5125, +2.9,0.15,2.475, +3.2,0.15,2.4, +2.8,0.15,2.4, +0,0,3.15, +0.8,0,3.15, +0.8,-0.45,3.15, +0.45,-0.8,3.15, +0,-0.8,3.15, +0,0,2.85, +0.2,0,2.7, +0.2,-0.112,2.7, +0.112,-0.2,2.7, +0,-0.2,2.7, +-0.45,-0.8,3.15, +-0.8,-0.45,3.15, +-0.8,0,3.15, +-0.112,-0.2,2.7, +-0.2,-0.112,2.7, +-0.2,0,2.7, +-0.8,0.45,3.15, +-0.45,0.8,3.15, +0,0.8,3.15, +-0.2,0.112,2.7, +-0.112,0.2,2.7, +0,0.2,2.7, +0.45,0.8,3.15, +0.8,0.45,3.15, +0.112,0.2,2.7, +0.2,0.112,2.7, +0.4,0,2.55, +0.4,-0.224,2.55, +0.224,-0.4,2.55, +0,-0.4,2.55, +1.3,0,2.55, +1.3,-0.728,2.55, +0.728,-1.3,2.55, +0,-1.3,2.55, +1.3,0,2.4, +1.3,-0.728,2.4, +0.728,-1.3,2.4, +0,-1.3,2.4, +-0.224,-0.4,2.55, +-0.4,-0.224,2.55, +-0.4,0,2.55, +-0.728,-1.3,2.55, +-1.3,-0.728,2.55, +-1.3,0,2.55, +-0.728,-1.3,2.4, +-1.3,-0.728,2.4, +-1.3,0,2.4, +-0.4,0.224,2.55, +-0.224,0.4,2.55, +0,0.4,2.55, +-1.3,0.728,2.55, +-0.728,1.3,2.55, +0,1.3,2.55, +-1.3,0.728,2.4, +-0.728,1.3,2.4, +0,1.3,2.4, +0.224,0.4,2.55, +0.4,0.224,2.55, +0.728,1.3,2.55, +1.3,0.728,2.55, +0.728,1.3,2.4, +1.3,0.728,2.4, +0,0,0, +1.425,0,0, +1.425,0.798,0, +0.798,1.425,0, +0,1.425,0, +1.5,0,0.075, +1.5,0.84,0.075, +0.84,1.5,0.075, +0,1.5,0.075, +-0.798,1.425,0, +-1.425,0.798,0, +-1.425,0,0, +-0.84,1.5,0.075, +-1.5,0.84,0.075, +-1.5,0,0.075, +-1.425,-0.798,0, +-0.798,-1.425,0, +0,-1.425,0, +-1.5,-0.84,0.075, +-0.84,-1.5,0.075, +0,-1.5,0.075, +0.798,-1.425,0, +1.425,-0.798,0, +0.84,-1.5,0.075, +1.5,-0.84,0.075 + ] ; + + THREE.Geometry.call( this ); + + this.type = 'TeapotGeometry'; + + this.parameters = { + size: size, + segments: segments, + bottom: bottom, + lid: lid, + body: body, + fitLid: fitLid, + blinn: blinn + }; + + size = size || 50; + + // number of segments per patch + segments = segments !== undefined ? Math.max( 2, Math.floor( segments ) || 10 ) : 10; + + // which parts should be visible + bottom = bottom === undefined ? true : bottom; + lid = lid === undefined ? true : lid; + body = body === undefined ? true : body; + + // Should the lid be snug? It's not traditional, so off by default + fitLid = fitLid === undefined ? false : fitLid; + + // Jim Blinn scaled the teapot down in size by about 1.3 for + // some rendering tests. He liked the new proportions that he kept + // the data in this form. The model was distributed with these new + // proportions and became the norm. Trivia: comparing images of the + // real teapot and the computer model, the ratio for the bowl of the + // real teapot is more like 1.25, but since 1.3 is the traditional + // value given, we use it here. + var blinnScale = 1.3; + blinn = blinn === undefined ? true : blinn; + + // scale the size to be the real scaling factor + var maxHeight = 3.15 * ( blinn ? 1 : blinnScale ); + + var maxHeight2 = maxHeight / 2; + var trueSize = size / maxHeight2; + + // Number of elements depends on what is needed. Subtract degenerate + // triangles at tip of bottom and lid out in advance. + var numTriangles = bottom ? ( 8 * segments - 4 ) * segments : 0; + numTriangles += lid ? ( 16 * segments - 4 ) * segments : 0; + numTriangles += body ? 40 * segments * segments : 0; + + var numVertices = bottom ? 4 : 0; + numVertices += lid ? 8 : 0; + numVertices += body ? 20 : 0; + numVertices *= ( segments + 1 ) * ( segments + 1 ); + + var i; + var normals = []; + var uvs = []; + for ( i = 0; i < numVertices; i++ ) { + this.vertices.push( new THREE.Vector3() ); + normals.push( new THREE.Vector3() ); + uvs.push( new THREE.Vector2() ); + } + + // Bezier form + var ms = new THREE.Matrix4(); + ms.set( -1.0, 3.0, -3.0, 1.0, + 3.0, -6.0, 3.0, 0.0, + -3.0, 3.0, 0.0, 0.0, + 1.0, 0.0, 0.0, 0.0 ) ; + + var g = []; + var i, r, c; + + var sp = []; + var tp = []; + var dsp = []; + var dtp = []; + + // M * G * M matrix, sort of see + // http://www.cs.helsinki.fi/group/goa/mallinnus/curves/surfaces.html + var mgm = []; + + var vert = []; + var sdir = []; + var tdir = []; + + var norm = new THREE.Vector3(); + + var tcoord; + + var sstep, tstep; + var vertPerRow, eps; + + var s, t, sval, tval, p, dsval, dtval; + + var normOut = new THREE.Vector3(); + var v1, v2, v3, v4; + + var gmx = new THREE.Matrix4(); + var tmtx = new THREE.Matrix4(); + + var vsp = new THREE.Vector4(); + var vtp = new THREE.Vector4(); + var vdsp = new THREE.Vector4(); + var vdtp = new THREE.Vector4(); + + var vsdir = new THREE.Vector3(); + var vtdir = new THREE.Vector3(); + + var mst = ms.clone(); + mst.transpose(); + + // internal function: test if triangle has any matching vertices; + // if so, don't save triangle, since it won't display anything. + var notDegenerate = function ( vtx1, vtx2, vtx3 ) { + + // if any vertex matches, return false + if ( vtx1.equals( vtx2 ) ) { return false; } + if ( vtx1.equals( vtx3 ) ) { return false; } + if ( vtx2.equals( vtx3 ) ) { return false; } + return true; + + }; + + + for ( i = 0; i < 3; i ++ ) + { + + mgm[ i ] = new THREE.Matrix4(); + + } + + var minPatches = body ? 0 : 20; + var maxPatches = bottom ? 32 : 28; + + vertPerRow = segments + 1; + + eps = 0.0000001; + + var surfCount = 0; + var vertCount = 0; + var normCount = 0; + var uvCount = 0; + + for ( var surf = minPatches ; surf < maxPatches ; surf ++ ) { + + // lid is in the middle of the data, patches 20-27, + // so ignore it for this part of the loop if the lid is not desired + if ( lid || ( surf < 20 || surf >= 28 ) ) { + + // get M * G * M matrix for x,y,z + for ( i = 0 ; i < 3 ; i ++ ) { + + // get control patches + for ( r = 0 ; r < 4 ; r ++ ) { + + for ( c = 0 ; c < 4 ; c ++ ) { + + // transposed + g[ c * 4 + r ] = teapotVertices[ teapotPatches[ surf * 16 + r * 4 + c ] * 3 + i ] ; + + // is the lid to be made larger, and is this a point on the lid + // that is X or Y? + if ( fitLid && ( surf >= 20 && surf < 28 ) && ( i !== 2 ) ) { + + // increase XY size by 7.7%, found empirically. I don't + // increase Z so that the teapot will continue to fit in the + // space -1 to 1 for Y (Y is up for the final model). + g[ c * 4 + r ] *= 1.077; + + } + + // Blinn "fixed" the teapot by dividing Z by blinnScale, and that's the + // data we now use. The original teapot is taller. Fix it: + if ( ! blinn && ( i === 2 ) ) { + + g[ c * 4 + r ] *= blinnScale; + + } + + } + + } + + gmx.set( g[ 0 ], g[ 1 ], g[ 2 ], g[ 3 ], g[ 4 ], g[ 5 ], g[ 6 ], g[ 7 ], g[ 8 ], g[ 9 ], g[ 10 ], g[ 11 ], g[ 12 ], g[ 13 ], g[ 14 ], g[ 15 ] ); + + tmtx.multiplyMatrices( gmx, ms ); + mgm[ i ].multiplyMatrices( mst, tmtx ); + + } + + // step along, get points, and output + for ( sstep = 0 ; sstep <= segments ; sstep ++ ) { + + s = sstep / segments; + + for ( tstep = 0 ; tstep <= segments ; tstep ++ ) { + + t = tstep / segments; + + // point from basis + // get power vectors and their derivatives + for ( p = 4, sval = tval = 1.0 ; p -- ; ) { + + sp[ p ] = sval ; + tp[ p ] = tval ; + sval *= s ; + tval *= t ; + + if ( p === 3 ) { + + dsp[ p ] = dtp[ p ] = 0.0 ; + dsval = dtval = 1.0 ; + + } else { + + dsp[ p ] = dsval * ( 3 - p ) ; + dtp[ p ] = dtval * ( 3 - p ) ; + dsval *= s ; + dtval *= t ; + + } + + } + + vsp.set( sp[0], sp[1], sp[2], sp[3] ); + vtp.set( tp[0], tp[1], tp[2], tp[3] ); + vdsp.set( dsp[0], dsp[1], dsp[2], dsp[3] ); + vdtp.set( dtp[0], dtp[1], dtp[2], dtp[3] ); + + // do for x,y,z + for ( i = 0 ; i < 3 ; i ++ ) { + + // multiply power vectors times matrix to get value + tcoord = vsp.clone(); + tcoord.applyMatrix4( mgm[ i ] ); + vert[ i ] = tcoord.dot( vtp ); + + // get s and t tangent vectors + tcoord = vdsp.clone(); + tcoord.applyMatrix4( mgm[ i ] ); + sdir[ i ] = tcoord.dot( vtp ) ; + + tcoord = vsp.clone(); + tcoord.applyMatrix4( mgm[ i ] ); + tdir[ i ] = tcoord.dot( vdtp ) ; + + } + + // find normal + vsdir.set( sdir[0], sdir[1], sdir[2], sdir[3] ); + vtdir.set( tdir[0], tdir[1], tdir[2], tdir[3] ); + norm.crossVectors( vtdir, vsdir ); + norm.normalize(); + + // if X and Z length is 0, at the cusp, so point the normal up or down, depending on patch number + if ( vert[ 0 ] === 0 && vert[ 1 ] === 0 ) + { + + // if above the middle of the teapot, normal points up, else down + normOut.set( 0, vert[ 2 ] > maxHeight2 ? 1 : - 1, 0 ); + + } + else + { + + // standard output: rotate on X axis + normOut.set( norm.x, norm.z, - norm.y ); + + } + + // three.js uses Y up, the code makes Z up, so time for a trick: + // rotate on X axis, and offset down on Y axis so object ranges from -1 to 1 in Y + this.vertices[vertCount++].set( trueSize * vert[ 0 ], trueSize * ( vert[ 2 ] - maxHeight2 ), - trueSize * vert[ 1 ] ); + + normals[ normCount ++ ].set( normOut.x, normOut.y, normOut.z ); + + uvs[ uvCount ++ ].set( 1 - t, 1 - s ); + + } + + } + + // save the faces + for ( sstep = 0 ; sstep < segments ; sstep ++ ) { + + for ( tstep = 0 ; tstep < segments ; tstep ++ ) { + + v1 = surfCount * vertPerRow * vertPerRow + sstep * vertPerRow + tstep; + v2 = v1 + 1; + v3 = v2 + vertPerRow; + v4 = v1 + vertPerRow; + + // Normals and UVs cannot be shared. Without clone(), you can see the consequences + // of sharing if you call geometry.applyMatrix( matrix ). + if ( notDegenerate ( this.vertices[v1], this.vertices[v2], this.vertices[v3] ) ) { + + this.faces.push( new THREE.Face3( v1, v2, v3, [ normals[v1], normals[v2], normals[v3] ] ) ); + this.faceVertexUvs[ 0 ].push( [ uvs[v1], uvs[v2], uvs[v3] ] ); + + } + if ( notDegenerate ( this.vertices[v1], this.vertices[v3], this.vertices[v4] ) ) { + + this.faces.push( new THREE.Face3( v1, v3, v4, [ normals[v1], normals[v3], normals[v4] ] ) ); + this.faceVertexUvs[ 0 ].push( [ uvs[v1], uvs[v3], uvs[v4] ] ); + + } + + } + + } + + // increment only if a surface was used + surfCount ++; + + } + + } + + this.computeCentroids(); + this.computeFaceNormals(); + this.mergeVertices(); + +}; + + +THREE.TeapotGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.TeapotGeometry.prototype.constructor = THREE.TeapotGeometry; + +THREE.TeapotGeometry.prototype.clone = function () { + + var geometry = new THREE.TeapotGeometry( + this.parameters.size, + this.parameters.segments, + this.parameters.bottom, + this.parameters.lid, + this.parameters.body, + this.parameters.fitLid, + this.parameters.blinn + ); + + return geometry; + +}; diff --git a/COGNET/lib/uclass_TeaspoonGeometry.js b/COGNET/lib/uclass_TeaspoonGeometry.js new file mode 100644 index 0000000000000000000000000000000000000000..4df9ae5be891e4c88506097572294e4a9455cb58 --- /dev/null +++ b/COGNET/lib/uclass_TeaspoonGeometry.js @@ -0,0 +1,527 @@ +"use strict"; // good practice - see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode +/** + * @author Eric Haines / http://erichaines.com/ + * + * Created for the Udacity course "Interactive Rendering", http://bit.ly/ericity + * + * Tessellate a teaspoon into triangular patches. + * + * See http://www.sjbaker.org/wiki/index.php?title=The_History_of_The_Teaspoon for + * the history of the Teaspoon and teaspoon + * + * THREE.TeaspoonGeometry = function ( size, segments ) + * + * defaults: size = 50, segments = 10 + * + * size is a relative scale: I've scaled the Teaspoon to fit vertically between -1 and 1. + * Think of it as a "radius". + * segments - number of line segments to subdivide each patch edge; + * 1 is possible but gives degenerates, so two is the real minimum. + * + * segments 'n' determines the number of objects output. + * Total patches = 16*2*n*n + * + * size_factor # triangles + * 1 32 + * 2 128 + * 3 288 + * 4 512 + * 5 800 + * 6 1152 + * + * 10 3200 + * 20 12800 + * 30 28800 + * 40 51200 + */ +/*global THREE */ + +THREE.TeaspoonGeometry = function ( size, segments ) { + "use strict"; + + // 26 * 4 * 4 Bezier spline patches, note +1 start + // Data from ftp://ftp.funet.fi/pub/sci/graphics/packages/objects/teaset.tar.Z + var TeaspoonPatches = [ +1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, +17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32, +33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48, +49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64, +65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80, +81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96, +97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112, +113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128, +129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144, +145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160, +161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176, +177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192, +193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208, +209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224, +225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240, +241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256 + ] ; + + var TeaspoonVertices = [ +-0.000107143,0.205357,0.0, +0.0,0.196429,-0.0178571, +0.0,0.196429,-0.0178571, +0.000107143,0.205357,0.0, +-0.0535714,0.205357,0.0, +-0.0222714,0.178571,-0.0534286, +0.0222714,0.178571,-0.0534286, +0.0535714,0.205357,0.0, +-0.107143,0.0952429,-0.0178571, +-0.0446429,0.0952429,-0.0892857, +0.0446429,0.0952429,-0.0892857, +0.107143,0.0952429,-0.0178571, +-0.107143,0.0,-0.0178571, +-0.0446429,0.0,-0.0892857, +0.0446429,0.0,-0.0892857, +0.107143,0.0,-0.0178571, +0.000107143,0.205357,0.0, +0.000135714,0.207589,0.00446429, +0.000157143,0.216518,0.00446429, +0.000125,0.214286,0.0, +0.0535714,0.205357,0.0, +0.0613964,0.212054,0.0133571, +0.0714286,0.220982,0.015625, +0.0625,0.214286,0.0, +0.107143,0.0952429,-0.0178571, +0.122768,0.0952429,0.0, +0.142857,0.0952429,0.00446429, +0.125,0.0952429,-0.0178571, +0.107143,0.0,-0.0178571, +0.122768,0.0,0.0, +0.142857,0.0,0.00446429, +0.125,0.0,-0.0178571, +0.000125,0.214286,0.0, +0.0,0.205357,-0.0178571, +0.0,0.205357,-0.0178571, +-0.000125,0.214286,0.0, +0.0625,0.214286,0.0, +0.0267857,0.1875,-0.0625, +-0.0267857,0.1875,-0.0625, +-0.0625,0.214286,0.0, +0.125,0.0952429,-0.0178571, +0.0535714,0.0952429,-0.107143, +-0.0535714,0.0952429,-0.107143, +-0.125,0.0952429,-0.0178571, +0.125,0.0,-0.0178571, +0.0535714,0.0,-0.107143, +-0.0535714,0.0,-0.107143, +-0.125,0.0,-0.0178571, +-0.000125,0.214286,0.0, +-0.000157143,0.216518,0.00446429, +-0.000135714,0.207589,0.00446429, +-0.000107143,0.205357,0.0, +-0.0625,0.214286,0.0, +-0.0714286,0.220982,0.015625, +-0.0613964,0.212054,0.0133571, +-0.0535714,0.205357,0.0, +-0.125,0.0952429,-0.0178571, +-0.142857,0.0952429,0.00446429, +-0.122768,0.0952429,0.0, +-0.107143,0.0952429,-0.0178571, +-0.125,0.0,-0.0178571, +-0.142857,0.0,0.00446429, +-0.122768,0.0,0.0, +-0.107143,0.0,-0.0178571, +-0.107143,0.0,-0.0178571, +-0.0446429,0.0,-0.0892857, +0.0446429,0.0,-0.0892857, +0.107143,0.0,-0.0178571, +-0.107143,-0.142857,-0.0178571, +-0.0446429,-0.142857,-0.0892857, +0.0446429,-0.142857,-0.0892857, +0.107143,-0.142857,-0.0178571, +-0.0133929,-0.160714,0.0386893, +-0.00557857,-0.160714,0.0386893, +0.00557857,-0.160714,0.0386893, +0.0133929,-0.160714,0.0386893, +-0.0133929,-0.25,0.0535714, +-0.00557857,-0.25,0.0535714, +0.00557857,-0.25,0.0535714, +0.0133929,-0.25,0.0535714, +0.107143,0.0,-0.0178571, +0.122768,0.0,0.0, +0.142857,0.0,0.00446429, +0.125,0.0,-0.0178571, +0.107143,-0.142857,-0.0178571, +0.122768,-0.142857,0.0, +0.142857,-0.142857,0.00446429, +0.125,-0.142857,-0.0178571, +0.0133929,-0.160714,0.0386893, +0.0153464,-0.160714,0.0386893, +0.0178571,-0.160714,0.0314357, +0.015625,-0.160714,0.0297607, +0.0133929,-0.25,0.0535714, +0.0153464,-0.25,0.0535714, +0.0178571,-0.25,0.0463179, +0.015625,-0.25,0.0446429, +0.125,0.0,-0.0178571, +0.0535714,0.0,-0.107143, +-0.0535714,0.0,-0.107143, +-0.125,0.0,-0.0178571, +0.125,-0.142857,-0.0178571, +0.0535714,-0.142857,-0.107143, +-0.0535714,-0.142857,-0.107143, +-0.125,-0.142857,-0.0178571, +0.015625,-0.160714,0.0297607, +0.00669643,-0.160714,0.0230643, +-0.00781071,-0.160714,0.0208321, +-0.015625,-0.160714,0.0297607, +0.015625,-0.25,0.0446429, +0.00669643,-0.25,0.0379464, +-0.00781071,-0.25,0.0357143, +-0.015625,-0.25,0.0446429, +-0.125,0.0,-0.0178571, +-0.142857,0.0,0.00446429, +-0.122768,0.0,0.0, +-0.107143,0.0,-0.0178571, +-0.125,-0.142857,-0.0178571, +-0.142857,-0.142857,0.00446429, +-0.122768,-0.142857,0.0, +-0.107143,-0.142857,-0.0178571, +-0.015625,-0.160714,0.0297607, +-0.0175786,-0.160714,0.0319929, +-0.0153464,-0.160714,0.0386893, +-0.0133929,-0.160714,0.0386893, +-0.015625,-0.25,0.0446429, +-0.0175786,-0.25,0.046875, +-0.0153464,-0.25,0.0535714, +-0.0133929,-0.25,0.0535714, +-0.0133929,-0.25,0.0535714, +-0.00557857,-0.25,0.0535714, +0.00557857,-0.25,0.0535714, +0.0133929,-0.25,0.0535714, +-0.0133929,-0.46425,0.0892857, +-0.00557857,-0.46425,0.0892857, +0.00557857,-0.46425,0.0892857, +0.0133929,-0.46425,0.0892857, +-0.0446429,-0.678571,0.0535714, +-0.00892857,-0.678571,0.0625, +0.00892857,-0.678571,0.0625, +0.0446429,-0.678571,0.0535714, +-0.0446429,-0.857143,0.0357143, +-0.00892857,-0.857143,0.0446429, +0.00892857,-0.857143,0.0446429, +0.0446429,-0.857143,0.0357143, +0.0133929,-0.25,0.0535714, +0.0153464,-0.25,0.0535714, +0.0178571,-0.25,0.0463179, +0.015625,-0.25,0.0446429, +0.0133929,-0.46425,0.0892857, +0.0153464,-0.464286,0.0892857, +0.0178571,-0.46425,0.0820321, +0.015625,-0.46425,0.0803571, +0.0446429,-0.678571,0.0535714, +0.0535714,-0.678571,0.0513393, +0.0535714,-0.678571,0.0334821, +0.0446429,-0.678571,0.0357143, +0.0446429,-0.857143,0.0357143, +0.0535714,-0.857143,0.0334821, +0.0535714,-0.857143,0.015625, +0.0446429,-0.857143,0.0178571, +0.015625,-0.25,0.0446429, +0.00669643,-0.25,0.0379464, +-0.00781071,-0.25,0.0357143, +-0.015625,-0.25,0.0446429, +0.015625,-0.46425,0.0803571, +0.00669643,-0.464286,0.0736607, +-0.00781071,-0.46425,0.0714286, +-0.015625,-0.46425,0.0803571, +0.0446429,-0.678571,0.0357143, +0.00892857,-0.678571,0.0446429, +-0.00892857,-0.678571,0.0446429, +-0.0446429,-0.678571,0.0357143, +0.0446429,-0.857143,0.0178571, +0.00892857,-0.857143,0.0267857, +-0.00892857,-0.857143,0.0267857, +-0.0446429,-0.857143,0.0178571, +-0.015625,-0.25,0.0446429, +-0.0175786,-0.25,0.046875, +-0.0153464,-0.25,0.0535714, +-0.0133929,-0.25,0.0535714, +-0.015625,-0.46425,0.0803571, +-0.0175786,-0.464286,0.0825893, +-0.0153464,-0.464286,0.0892857, +-0.0133929,-0.46425,0.0892857, +-0.0446429,-0.678571,0.0357143, +-0.0535714,-0.678571,0.0334821, +-0.0535714,-0.678571,0.0513393, +-0.0446429,-0.678571,0.0535714, +-0.0446429,-0.857143,0.0178571, +-0.0535714,-0.857143,0.015625, +-0.0535714,-0.857143,0.0334821, +-0.0446429,-0.857143,0.0357143, +-0.0446429,-0.857143,0.0357143, +-0.00892857,-0.857143,0.0446429, +0.00892857,-0.857143,0.0446429, +0.0446429,-0.857143,0.0357143, +-0.0446429,-0.928571,0.0285714, +-0.00892857,-0.928571,0.0375, +0.00892857,-0.928571,0.0375, +0.0446429,-0.928571,0.0285714, +-0.0539286,-0.999643,0.0178571, +0.000357143,-0.999643,0.0178571, +0.0,-0.999643,0.0178571, +0.0535714,-0.999643,0.0178571, +-0.000357143,-1,0.0178571, +0.000357143,-1,0.0178571, +0.0,-1,0.0178571, +0.0,-1,0.0178571, +0.0446429,-0.857143,0.0357143, +0.0535714,-0.857143,0.0334821, +0.0535714,-0.857143,0.015625, +0.0446429,-0.857143,0.0178571, +0.0446429,-0.928571,0.0285714, +0.0535714,-0.928571,0.0263393, +0.0535714,-0.928571,0.00848214, +0.0446429,-0.928571,0.0107143, +0.0535714,-0.999643,0.0178571, +0.0669643,-0.999643,0.0178571, +0.0673214,-0.999643,0.0, +0.0539286,-0.999643,0.0, +0.0,-1,0.0178571, +0.0,-1,0.0178571, +0.000357143,-1,0.0, +0.000357143,-1,0.0, +0.0446429,-0.857143,0.0178571, +0.00892857,-0.857143,0.0267857, +-0.00892857,-0.857143,0.0267857, +-0.0446429,-0.857143,0.0178571, +0.0446429,-0.928571,0.0107143, +0.00892857,-0.928571,0.0196429, +-0.00892857,-0.928571,0.0196429, +-0.0446429,-0.928571,0.0107143, +0.0539286,-0.999643,0.0, +0.000357143,-0.999643,0.0, +-0.000357143,-0.999643,0.0, +-0.0539286,-0.999643,0.0, +0.000357143,-1,0.0, +0.000357143,-1,0.0, +-0.000357143,-1,0.0, +-0.000357143,-1,0.0, +-0.0446429,-0.857143,0.0178571, +-0.0535714,-0.857143,0.015625, +-0.0535714,-0.857143,0.0334821, +-0.0446429,-0.857143,0.0357143, +-0.0446429,-0.928571,0.0107143, +-0.0535714,-0.928571,0.00848214, +-0.0535714,-0.928571,0.0263393, +-0.0446429,-0.928571,0.0285714, +-0.0539286,-0.999643,0.0, +-0.0673214,-0.999643,0.0, +-0.0675,-0.999643,0.0178571, +-0.0539286,-0.999643,0.0178571, +-0.000357143,-1,0.0, +-0.000357143,-1,0.0, +-0.000535714,-1,0.0178571, +-0.000357143,-1,0.0178571 + ] ; + + var minPatches = 0; + var maxPatches = 16; + + THREE.Geometry.call( this ); + + this.size = size || 50; + + // number of segments per patch + this.segments = Math.max( 2, Math.floor( segments ) || 10 ); + + // scale the size to be the real scaling factor + var maxHeight = 0.21463862761855126; + var minHeight = -1; + + var fullHeight = maxHeight - minHeight; + var fullHeight2 = fullHeight/2; + var heightOffset = - fullHeight2 - minHeight; + var trueSize = this.size / fullHeight2; + + var normals = [], uvs = []; + // bezier form + var ms = new THREE.Matrix4( -1.0, 3.0, -3.0, 1.0, + 3.0, -6.0, 3.0, 0.0, + -3.0, 3.0, 0.0, 0.0, + 1.0, 0.0, 0.0, 0.0 ) ; + + var g = []; + var i, r, c; + + var sp = []; + var tp = []; + var dsp = []; + var dtp = []; + + // M * G * M matrix, sort of see + // http://www.cs.helsinki.fi/group/goa/mallinnus/curves/surfaces.html + var mgm = []; + + var vert = []; + var sdir = []; + var tdir = []; + + var norm = new THREE.Vector3(); + + var tcoord; + + var sstep, tstep; + var gmx, tmtx; + + var vertPerRow; + + var s, t, sval, tval, p, dsval, dtval; + + var vsp, vtp, vdsp, vdtp; + var vsdir, vtdir, vertOut; + var v1, v2, v3, v4; + + var mst = ms.clone(); + mst.transpose(); + + // internal function: test if triangle has any matching vertices; + // if so, don't output, since it won't display anything. + var notDegenerate = function ( vtx1, vtx2, vtx3 ) { + if ( vtx1.equals( vtx2 ) ) { return false; } + if ( vtx1.equals( vtx3 ) ) { return false; } + if ( vtx2.equals( vtx3 ) ) { return false; } + return true; + }; + + + for ( i = 0; i < 3; i++ ) + { + mgm[i] = new THREE.Matrix4(); + } + + vertPerRow = (this.segments+1); + + var surfCount = 0; + //var faceCount = 0; + + for ( var surf = minPatches ; surf < maxPatches ; surf++ ) { + // get M * G * M matrix for x,y,z + for ( i = 0 ; i < 3 ; i++ ) { + // get control patches + for ( r = 0 ; r < 4 ; r++ ) { + for ( c = 0 ; c < 4 ; c++ ) { + // transposed; note subtraction of 1 for index + g[c*4+r] = TeaspoonVertices[(TeaspoonPatches[surf*16 + r*4 + c]-1)*3 + i] ; + } + } + + // Shockingly, the following three.js does NOT work. Setting this way appears to give the order + // g[0], g[4], g[8], etc. to the elements! I could avoid the transpose above + // and things would "just work", but this weird ordering would be mysterious. + //var gmx = new THREE.Matrix4(); + //gmx.elements.set( g ); + // So, explicitly set the matrix this way: + gmx = new THREE.Matrix4( g[0], g[1], g[2], g[3], g[4], g[5], g[6], g[7], g[8], g[9], g[10], g[11], g[12], g[13], g[14], g[15] ); + + tmtx = new THREE.Matrix4(); + tmtx.multiplyMatrices( gmx, ms ); + mgm[i].multiplyMatrices( mst, tmtx ); + } + + // step along, get points, and output + for ( sstep = 0 ; sstep <= this.segments ; sstep++ ) { + s = sstep / this.segments; + + for ( tstep = 0 ; tstep <= this.segments ; tstep++ ) { + t = tstep / this.segments; + + // point from basis + // get power vectors and their derivatives + for ( p = 4, sval = tval = 1.0 ; p-- ; ) { + sp[p] = sval ; + tp[p] = tval ; + sval *= s ; + tval *= t ; + + if ( p === 3 ) { + dsp[p] = dtp[p] = 0.0 ; + dsval = dtval = 1.0 ; + } else { + dsp[p] = dsval * (3-p) ; + dtp[p] = dtval * (3-p) ; + dsval *= s ; + dtval *= t ; + } + } + + vsp = new THREE.Vector4( sp[0], sp[1], sp[2], sp[3] ); + vtp = new THREE.Vector4( tp[0], tp[1], tp[2], tp[3] ); + vdsp = new THREE.Vector4( dsp[0], dsp[1], dsp[2], dsp[3] ); + vdtp = new THREE.Vector4( dtp[0], dtp[1], dtp[2], dtp[3] ); + + // do for x,y,z + for ( i = 0 ; i < 3 ; i++ ) { + // multiply power vectors times matrix to get value + tcoord = vsp.clone(); + tcoord.applyMatrix4( mgm[i] ); + vert[i] = tcoord.dot( vtp ); + + // get s and t tangent vectors + tcoord = vdsp.clone(); + tcoord.applyMatrix4( mgm[i] ); + sdir[i] = tcoord.dot( vtp ) ; + + tcoord = vsp.clone(); + tcoord.applyMatrix4( mgm[i] ); + tdir[i] = tcoord.dot( vdtp ) ; + } + + // find normal + vsdir = new THREE.Vector3( sdir[0], sdir[1], sdir[2] ); + vtdir = new THREE.Vector3( tdir[0], tdir[1], tdir[2] ); + norm.crossVectors( vtdir, vsdir ); + norm.normalize(); + + // rotate on X axis + // interestingly, normals need to be reversed; I suspect the patch + // has opposite handedness from the teapot. Also, Y is along axis for the teaspoon. + normals.push( new THREE.Vector3( -norm.x, -norm.y, -norm.z ) ); + + // TODO: check texturing + uvs.push( new THREE.Vector2( 1-t, 1-s ) ); + + // three.js uses Y up, the code makes Y up, all is fine. + // Move teaspoon to be centered around origin, three.js style. + vertOut = new THREE.Vector3( trueSize*vert[0], trueSize*(vert[1]+heightOffset), trueSize*vert[2] ); + + this.vertices.push( vertOut ); + + } + } + + // save the faces + for ( sstep = 0 ; sstep < this.segments ; sstep++ ) { + for ( tstep = 0 ; tstep < this.segments ; tstep++ ) { + v1 = surfCount * vertPerRow * vertPerRow + sstep * vertPerRow + tstep; + v2 = v1 + 1; + v3 = v2 + vertPerRow; + v4 = v1 + vertPerRow; + + if ( notDegenerate ( this.vertices[v1], this.vertices[v2], this.vertices[v3] ) ) { + this.faces.push( new THREE.Face3( v1, v2, v3, [ normals[v1], normals[v2], normals[v3] ] ) ); + this.faceVertexUvs[ 0 ].push( [ uvs[v1], uvs[v2], uvs[v3] ] ); + } + if ( notDegenerate ( this.vertices[v1], this.vertices[v3], this.vertices[v4] ) ) { + this.faces.push( new THREE.Face3( v1, v3, v4, [ normals[v1], normals[v3], normals[v4] ] ) ); + this.faceVertexUvs[ 0 ].push( [ uvs[v1], uvs[v3], uvs[v4] ] ); + } + //faceCount+=2; + } + } + // increment only if a surface was used + surfCount++; + } + + this.computeCentroids(); + this.computeFaceNormals(); + this.mergeVertices(); + +}; + + +THREE.TeaspoonGeometry.prototype = Object.create( THREE.Geometry.prototype ); diff --git a/COGNET/lib/uclass_shaders.js b/COGNET/lib/uclass_shaders.js new file mode 100644 index 0000000000000000000000000000000000000000..462ec57cdbad3d79311c59d4fbc8a14050a79906 --- /dev/null +++ b/COGNET/lib/uclass_shaders.js @@ -0,0 +1,286 @@ +"use strict"; // good practice - see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode +/** + * @author Eric Haines / http://erichaines.com/ + * + * Various useful shaders for the Udacity course "Interactive Rendering" + * http://bit.ly/ericity + */ +/*global THREE */ + +THREE.ShaderTypes = { + +'gouraud' : { + + uniforms: { + + "uDirLightPos": { type: "v3", value: new THREE.Vector3() }, + "uDirLightColor": { type: "c", value: new THREE.Color( 0xFFFFFF ) }, + + "uAmbientLightColor": { type: "c", value: new THREE.Color( 0x050505 ) }, + + "uMaterialColor": { type: "c", value: new THREE.Color( 0xFFFFFF ) }, + "uSpecularColor": { type: "c", value: new THREE.Color( 0xFFFFFF ) }, + + uKd: { + type: "f", + value: 0.7 + }, + uKs: { + type: "f", + value: 0.3 + }, + shininess: { + type: "f", + value: 100.0 + } + }, + + vertexShader: [ + + "uniform vec3 uMaterialColor;", + "uniform vec3 uSpecularColor;", + + "uniform vec3 uDirLightPos;", + "uniform vec3 uDirLightColor;", + + "uniform vec3 uAmbientLightColor;", + + "uniform float uKd;", + "uniform float uKs;", + "uniform float shininess;", + + "varying vec3 vColor;", + + "void main() {", + + "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", + "vec3 vNormal = normalize( normalMatrix * normal );", + "vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );", + "vec3 vViewPosition = -mvPosition.xyz;", + + "vColor = uAmbientLightColor * uMaterialColor;", + + "vec4 lDirection = viewMatrix * vec4( uDirLightPos, 0.0 );", + "vec3 lVector = normalize( lDirection.xyz );", + + // diffuse: N * L + "float diffuse = max( dot( vNormal, lVector ), 0.0);", + + "vColor += uKd * uMaterialColor * uDirLightColor * diffuse;", + + // specular: N * H to a power. H is light vector + view vector + "vec3 viewPosition = normalize( vViewPosition );", + "vec3 pointHalfVector = normalize( lVector + viewPosition );", + "float pointDotNormalHalf = max( dot( vNormal, pointHalfVector ), 0.0 );", + "float specular = uKs * pow( pointDotNormalHalf, shininess );", + // however, if N * L is < 0, the light is below the horizon and should not affect the surface + // This can give a hard termination to the highlight, but it's better than some weird sparkle. + "if (diffuse <= 0.0) {", + "specular = 0.0;", + "}", + + "vColor += uDirLightColor * uSpecularColor * specular;", + "}" + + ].join("\n"), + + fragmentShader: [ + + "varying vec3 vColor;", + + "void main() {", + "gl_FragColor = vec4(vColor, 1.0);", + "}" + + ].join("\n") + +}, + + +'phong' : { + + uniforms: { + + "uDirLightPos": { type: "v3", value: new THREE.Vector3() }, + "uDirLightColor": { type: "c", value: new THREE.Color( 0xFFFFFF ) }, + + "uAmbientLightColor": { type: "c", value: new THREE.Color( 0x050505 ) }, + + "uMaterialColor": { type: "c", value: new THREE.Color( 0xFFFFFF ) }, + "uSpecularColor": { type: "c", value: new THREE.Color( 0xFFFFFF ) }, + + uKd: { + type: "f", + value: 0.7 + }, + uKs: { + type: "f", + value: 0.3 + }, + shininess: { + type: "f", + value: 100.0 + } + }, + + vertexShader: [ + + "varying vec3 vNormal;", + "varying vec3 vViewPosition;", + + "void main() {", + + "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", + "vNormal = normalize( normalMatrix * normal );", + "vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );", + "vViewPosition = -mvPosition.xyz;", + + "}" + + ].join("\n"), + + fragmentShader: [ + + "uniform vec3 uMaterialColor;", + "uniform vec3 uSpecularColor;", + + "uniform vec3 uDirLightPos;", + "uniform vec3 uDirLightColor;", + + "uniform vec3 uAmbientLightColor;", + + "uniform float uKd;", + "uniform float uKs;", + "uniform float shininess;", + + "varying vec3 vNormal;", + "varying vec3 vViewPosition;", + + "void main() {", + + // ambient + "gl_FragColor = vec4( uAmbientLightColor * uMaterialColor, 1.0 );", + + "vec4 lDirection = viewMatrix * vec4( uDirLightPos, 0.0 );", + "vec3 lVector = normalize( lDirection.xyz );", + + // diffuse: N * L. Normal must be normalized, since it's interpolated. + "vec3 normal = normalize( vNormal );", + "float diffuse = max( dot( normal, lVector ), 0.0);", + + "gl_FragColor.xyz += uKd * uMaterialColor * uDirLightColor * diffuse;", + + // specular: N * H to a power. H is light vector + view vector + "vec3 viewPosition = normalize( vViewPosition );", + "vec3 pointHalfVector = normalize( lVector + viewPosition );", + "float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );", + "float specular = uKs * pow( pointDotNormalHalf, shininess );", + // however, if N * L is < 0, the light is below the horizon and should not affect the surface + // This can give a hard termination to the highlight, but it's better than some weird sparkle. + "if (diffuse <= 0.0) {", + "specular = 0.0;", + "}", + + "gl_FragColor.xyz += uDirLightColor * uSpecularColor * specular;", + + "}" + + ].join("\n") + +}, + +'phongBalanced' : { + + uniforms: { + + "uDirLightPos": { type: "v3", value: new THREE.Vector3() }, + "uDirLightColor": { type: "c", value: new THREE.Color( 0xFFFFFF ) }, + + "uAmbientLightColor": { type: "c", value: new THREE.Color( 0x050505 ) }, + + "uMaterialColor": { type: "c", value: new THREE.Color( 0xFFFFFF ) }, + "uSpecularColor": { type: "c", value: new THREE.Color( 0xFFFFFF ) }, + + uKd: { + type: "f", + value: 0.7 + }, + uKs: { + type: "f", + value: 0.3 + }, + shininess: { + type: "f", + value: 100.0 + } + }, + + vertexShader: [ + + "varying vec3 vNormal;", + "varying vec3 vViewPosition;", + + "void main() {", + + "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", + "vNormal = normalize( normalMatrix * normal );", + "vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );", + "vViewPosition = -mvPosition.xyz;", + + "}" + + ].join("\n"), + + fragmentShader: [ + + "uniform vec3 uMaterialColor;", + "uniform vec3 uSpecularColor;", + + "uniform vec3 uDirLightPos;", + "uniform vec3 uDirLightColor;", + + "uniform vec3 uAmbientLightColor;", + + "uniform float uKd;", + "uniform float uKs;", + "uniform float shininess;", + + "varying vec3 vNormal;", + "varying vec3 vViewPosition;", + + "void main() {", + + // ambient + "gl_FragColor = vec4( uAmbientLightColor * uMaterialColor, 1.0 );", + + "vec4 lDirection = viewMatrix * vec4( uDirLightPos, 0.0 );", + "vec3 lVector = normalize( lDirection.xyz );", + + // diffuse: N * L. Normal must be normalized, since it's interpolated. + "vec3 normal = normalize( vNormal );", + "float diffuse = max( dot( normal, lVector ), 0.0);", + + "gl_FragColor.xyz += uKd * uMaterialColor * uDirLightColor * diffuse;", + + // specular: N * H to a power. H is light vector + view vector + "vec3 viewPosition = normalize( vViewPosition );", + "vec3 pointHalfVector = normalize( lVector + viewPosition );", + "float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );", + "float specular = uKs * pow( pointDotNormalHalf, shininess );", + "specular *= (8.0 + shininess)/(8.0*3.14);", + //"float specular = uKs * ((float)shininess + 8.0 ) * pow( pointDotNormalHalf, shininess ) / (8 * 3.14);", + // however, if N * L is < 0, the light is below the horizon and should not affect the surface + // This can give a hard termination to the highlight, but it's better than some weird sparkle. + "if (diffuse <= 0.0) {", + "specular = 0.0;", + "}", + + "gl_FragColor.xyz += uDirLightColor * uSpecularColor * specular;", + + "}" + + ].join("\n") + +} + +}; diff --git a/COGNET/main.js b/COGNET/main.js index 732ef8d481e1c3b49936a1aea12aa01c61cbdd19..379f630e740261345ab64830ce91b900847dd669 100644 --- a/COGNET/main.js +++ b/COGNET/main.js @@ -1,86 +1,81 @@ -"use strict"; - import * as THREE from 'three'; - -import { OBJLoader } from 'three/addons/loaders/OBJLoader.js'; import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; -import {dat} from '/lib/dat.gui.min.js'; -import {Coordinates} from './lib/Coordinates.js'; -import renderer from "three/src/renderers/common/Renderer"; +import { OBJLoader } from 'three/addons/loaders/OBJLoader.js'; -let camera, renderer; -let cameraControls; +// Initialisation de la scène, de la caméra et du rendu +const scene = new THREE.Scene(); +const renderer = new THREE.WebGLRenderer(); +renderer.setSize(window.innerWidth, window.innerHeight); +document.getElementById('webGL').appendChild(renderer.domElement); -let clock = new THREE.Clock(); -let scene = new THREE.Scene(); +let camera; -/** - * - */ -function fillScene() { +// Ajout des contrôles de la caméra +let controls; +function init() { + camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 20); + camera.position.z = 1.5; // Rapprochez la caméra -} + // scene + const ambientLight = new THREE.AmbientLight(0xffffff); + scene.add(ambientLight); -/** - * - */ -function addToDOM() { - let container = document.getElementById('webGL'); - let canvas = container.getElementsByTagName('canvas'); - if (canvas.length>0) { - container.removeChild(canvas[0]); - } - container.appendChild( renderer.domElement); -} + const pointLight = new THREE.PointLight(0xffffff, 1); + camera.add(pointLight); + scene.add(camera); -/** - * - */ -function init() { - let canvasWidth = window.innerWidth; - let canvasHeight = window.innerHeight; - let canvasRatio = canvasWidth / canvasHeight; - - // RENDERER - renderer = new THREE.WebGLRenderer( { antialias: true } ); - renderer.setSize(canvasWidth, canvasHeight); - renderer.setClearColor( 0xFFFFFF, 1.0 ); + // renderer + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.setAnimationLoop(animate); - // Camera: Y up, X right, Z up - camera = new THREE.PerspectiveCamera( 1, canvasRatio, 50, 150 ); - camera.position.set( 0.5, 0.5, 100 ); + // controls + controls = new OrbitControls(camera, renderer.domElement); + controls.minDistance = 1; + controls.maxDistance = 3; - // CONTROLS - cameraControls = new OrbitControls(camera, renderer.domElement); - cameraControls.target.set(0.5,0.5,0); + // resize event + window.addEventListener('resize', onWindowResize); + // Load the violin object with textures + ObjectWithTextures(); } -/** - * - */ -function animate() { - window.requestAnimationFrame(animate); - render(); +// Fonction pour charger l'objet avec des textures +function ObjectWithTextures() { + const textureLoader = new THREE.TextureLoader(); + const texture = textureLoader.load('textures/violon/map.jpg'); + + new OBJLoader() + .setPath('textures/violon/') + .load('Violin.obj', function (object) { + object.traverse(function (child) { + if (child.isMesh) { + child.material = new THREE.MeshStandardMaterial({ + map: texture, + color: 0x8B4513 // Wood color + }); + child.material.needsUpdate = true; + } + }); + object.position.set(0, 0, -1); // Position the object in front of the camera + object.scale.setScalar(0.05); // Augmentez l'échelle de l'objet + scene.add(object); + }); } -/** - * - */ -function render() { - let delta = clock.getDelta(); - cameraControls.update(delta); +// Fonction d'animation +function animate() { + requestAnimationFrame(animate); + controls.update(); renderer.render(scene, camera); } - -try { - init(); - fillScene(); - addToDOM(); - animate(); +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + renderer.setSize(window.innerWidth, window.innerHeight); } -catch(e) { - const errorReport = "Your program encountered an unrecoverable error, can not draw on canvas. Error was:<br/><br/>"; - $('#webGL').append(errorReport+e); -} \ No newline at end of file + +init(); +animate(); \ No newline at end of file diff --git a/COGNET/textures/violon/map.jpg b/COGNET/textures/violon/map.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c5e5cf87259d75dbf8fbfaa32e40c6dcf907786c Binary files /dev/null and b/COGNET/textures/violon/map.jpg differ diff --git a/DESERT/Hopper-Gas.png b/DESERT/Hopper-Gas.png deleted file mode 100644 index cc69447a760fcd1e90b165787c6667da75a001fd..0000000000000000000000000000000000000000 Binary files a/DESERT/Hopper-Gas.png and /dev/null differ diff --git a/DESERT/index.html b/DESERT/index.html deleted file mode 100644 index 76e27dc119783f47da855d49712c43bab0798e9a..0000000000000000000000000000000000000000 --- a/DESERT/index.html +++ /dev/null @@ -1 +0,0 @@ -Le travail n'a pas encore commencé!!! \ No newline at end of file diff --git a/DUFOUR/chambre.js b/DUFOUR/chambre.js new file mode 100644 index 0000000000000000000000000000000000000000..72205860ec44c6568adf0ec60771a74c3c3d6cc2 --- /dev/null +++ b/DUFOUR/chambre.js @@ -0,0 +1,106 @@ +"use strict";import * as THREE from 'three'; +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import { Coordinates } from './lib/Coordinates.js'; + +var camera, renderer; +var windowScale; +window.scene = new THREE.Scene(); +var cameraControls; +var clock = new THREE.Clock(); +var transparentCube; // Objet autour duquel la caméra tournera + +function fillScene() { + scene = new THREE.Scene(); + scene.fog = new THREE.Fog(0x808080, 2000, 4000); + + // LIGHTS + scene.add(new THREE.AmbientLight(0x222222)); + + var light = new THREE.DirectionalLight(0xFFFFFF, 0.7); + light.position.set(200, 500, 500); + scene.add(light); + + light = new THREE.DirectionalLight(0xFFFFFF, 0.9); + light.position.set(-200, -100, -400); + scene.add(light); + + Coordinates.drawGround({ size: 1000 }); + + // Cube Transparent au Centre + var transparentMaterial = new THREE.MeshBasicMaterial({ + transparent: true, + opacity: 0 + }); + + var cubeGeometry = new THREE.BoxGeometry(100, 100, 100); + transparentCube = new THREE.Mesh(cubeGeometry, transparentMaterial); + transparentCube.position.set(0, 50, 0); // Position du cube + scene.add(transparentCube); + + // Ajout du lit + + var bed = new THREE.TextureLoader().load('lit.png'); + var bedMaterial = new THREE.MeshBasicMaterial({ map: bed }); + var bedSizeLength = 400, bedSizeHeight = 200, bedSizeWidth = 200; + var bedGeometry = new THREE.BoxGeometry(bedSizeLength, bedSizeHeight, bedSizeWidth); + bed = new THREE.Mesh(bedGeometry, bedMaterial); + + //bed = new THREE.Mesh(bedGeometry); + bed.position.set(200, 100, 425); + window.scene.add(bed); +} + +function init() { + var canvasWidth = 846; + var canvasHeight = 494; + var canvasRatio = canvasWidth / canvasHeight; + + // RENDERER + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.gammaInput = true; + renderer.gammaOutput = true; + renderer.setSize(canvasWidth, canvasHeight); + renderer.setClearColor(0xAAAAAA, 1.0); + + // CAMERA + camera = new THREE.PerspectiveCamera(45, canvasRatio, 1, 4000); + camera.position.set(-500, 125, -100); + camera.lookAt(new THREE.Vector3(0, 0, 0)); + + // CONTROLS (L'utilisateur peut tourner la caméra) + cameraControls = new OrbitControls(camera, renderer.domElement); + cameraControls.enableDamping = true; // Ajoute un effet d'inertie + cameraControls.dampingFactor = 0.05; + cameraControls.rotateSpeed = 1.0; +} + +function addToDOM() { + var container = document.getElementById('webGL'); + var canvas = container.getElementsByTagName('canvas'); + if (canvas.length > 0) { + container.removeChild(canvas[0]); + } + container.appendChild(renderer.domElement); +} + +function animate() { + requestAnimationFrame(animate); + render(); +} + +function render() { + var delta = clock.getDelta(); + cameraControls.update(); // Mise à jour des contrôles de la caméra + renderer.render(window.scene, camera); +} + +// Lancement du programme +try { + init(); + fillScene(); + animate(); + addToDOM(); +} catch (e) { + var errorReport = "Your program encountered an unrecoverable error, cannot draw on canvas. Error was:<br/><br/>"; + $('#webGL').append(errorReport + e); +} \ No newline at end of file diff --git a/DUFOUR/index.html b/DUFOUR/index.html index 4f33134e592066054ae8d9f791363f61d7500805..eaa5e113f96d1718deb97ac395e71d6cf319eac3 100644 --- a/DUFOUR/index.html +++ b/DUFOUR/index.html @@ -1,95 +1,33 @@ -<template> - <div ref="container" style="width: 100%; height: 100vh;"></div> -</template> - -<script> - import * as THREE from "three"; - import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js"; - import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"; - - export default { - name: "Model", - data() { - return { - scene: null, - camera: null, - renderer: null, - control: null, - model: null, - }; - }, - methods: { - initScene() { - this.scene = new THREE.Scene(); - }, - initCamera() { - this.camera = new THREE.PerspectiveCamera( - 50, - window.innerWidth / window.innerHeight, - 0.01, - 1000 - ); - this.camera.position.set(0.02, 5, 10); - }, - initRenderer() { - this.renderer = new THREE.WebGLRenderer({ antialias: true }); - this.renderer.setSize(window.innerWidth, window.innerHeight); - this.$refs.container.appendChild(this.renderer.domElement); - }, - initLight() { - const ambientLight = new THREE.AmbientLight(0xffffff, 1); - this.scene.add(ambientLight); - - const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5); - directionalLight.position.set(5, 5, 5); - this.scene.add(directionalLight); - }, - initControl() { - this.control = new OrbitControls(this.camera, this.renderer.domElement); - this.control.enableDamping = true; - this.control.dampingFactor = 0.05; - this.control.autoRotate = true; - this.control.autoRotateSpeed = 2.0; - }, - initModel() { - const loader = new GLTFLoader(); - loader.load( - "elements/wooden_chair.glb", - (glb) => { - this.model = glb.scene; - this.scene.add(this.model); - }, - (xhr) => { - console.log((xhr.loaded / xhr.total) * 100 + "% loaded"); - }, - (error) => { - console.log("An error happened:", error); - } - ); - }, - init() { - this.initScene(); - this.initCamera(); - this.initRenderer(); - this.initLight(); - this.initControl(); - this.initModel(); - }, - animate() { - requestAnimationFrame(this.animate); - this.control.update(); - this.renderer.render(this.scene, this.camera); - }, - }, - mounted() { - this.init(); - this.animate(); - - window.addEventListener("resize", () => { - this.renderer.setSize(window.innerWidth, window.innerHeight); - this.camera.aspect = window.innerWidth / window.innerHeight; - this.camera.updateProjectionMatrix(); - }); - }, - }; -</script> \ No newline at end of file +<!DOCTYPE html> +<html> + <head> + <meta charset="UTF-8"> + <title>La Chambre de Van Gogh</title> + <style> + body { margin: 0; } + canvas { width: 100%; height: 100% } + .centre{text-align: center;} + </style> + </head> + <body> + <!-- API importe du site de Three.js --> + <script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims + .js"></script> + <script type="importmap"> + { + "imports": { + "three": "https://threejs.org/build/three.module.js", + "three/addons/": "https://threejs.org/examples/jsm/" + } + } + </script> + <!-- JQuery pour afficher les erreurs --> + <script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.min.js + "></script> + <!-- Un titre centre --> + <h1 class="centre"> La Chambre de Van Gogh</h1> + <div id="webGL" class="centre"></div> + <!-- Mon script avec un chemin relatif --> + <script type="module" src="chambre.js"></script> + </body> +</html> diff --git a/DUFOUR/lit.png b/DUFOUR/lit.png new file mode 100644 index 0000000000000000000000000000000000000000..8661fdc19b44b57cb4de437d2a0111847beca1e7 Binary files /dev/null and b/DUFOUR/lit.png differ diff --git a/HERRY-E/img.jpg b/HERRY-E/img.jpg deleted file mode 100644 index d642e136257de4fb317a18f7c422126216665b16..0000000000000000000000000000000000000000 Binary files a/HERRY-E/img.jpg and /dev/null differ diff --git a/HERRY-E/index.html b/HERRY-E/index.html deleted file mode 100644 index 76e27dc119783f47da855d49712c43bab0798e9a..0000000000000000000000000000000000000000 --- a/HERRY-E/index.html +++ /dev/null @@ -1 +0,0 @@ -Le travail n'a pas encore commencé!!! \ No newline at end of file diff --git a/HERRY-M--HERRY-E/TABLO.js b/HERRY-M--HERRY-E/TABLO.js new file mode 100644 index 0000000000000000000000000000000000000000..153766c1b8d165fd08d18e072234531dffddc5fd --- /dev/null +++ b/HERRY-M--HERRY-E/TABLO.js @@ -0,0 +1,44 @@ +"use strict"; + +// IMPORTS +import * as THREE from 'three'; +import { TWEEN } from 'https://unpkg.com/three@0.139.0/examples/jsm/libs/tween.module.min.js'; +import { OBJLoader } from 'three/addons/loaders/OBJLoader.js'; +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import { dat } from '../lib/dat.gui.min.js'; +import { Coordinates } from '../lib/Coordinates.js'; + +// DECLARATIONS +var camera, scene, renderer; +var windowScale; +var cameraControls, effectController; +var clock = new THREE.Clock(); +var gridX = true; +var gridY = false; +var gridZ = false; +var axes = true; +var ground = true; + +function init(){ + +} + +function fillscene(){ + +} + +function animate(){ + +} + +function render(){ + +} + +try { + init(); + animate(); +} catch (e) { + var errorReport = "Your program encountered an unrecoverable error, can not draw on canvas. Error was:<br/><br/>"; + $('#webGL').append(errorReport + e); +} \ No newline at end of file diff --git a/HERRY-M--HERRY-E/checklistProjet.md b/HERRY-M--HERRY-E/checklistProjet.md new file mode 100644 index 0000000000000000000000000000000000000000..9e90e5bc378d681035ffdc095f6996ad75bedfaf --- /dev/null +++ b/HERRY-M--HERRY-E/checklistProjet.md @@ -0,0 +1,20 @@ +- [ ] Esthetisme +- [ ] Mise en page de la page web +- [ ] Paragraphe(s) d'explications techniques +- [ ] Légèreté du dossier (<2Mo) +- [ ] Géométrie +- [ ] Couleur +- [ ] Transparence +- [ ] Eclairage +- [ ] Ombres portées +- [ ] Position de la caméra +- [ ] Brouillard +- [ ] Effet miroir +- [ ] Texture classique +- [ ] Texture avec transparence +- [ ] Sprites +- [ ] Environment map +- [ ] Skybox +- [ ] Animations +- [ ] normal maps +- [ ] Interaction par GUI \ No newline at end of file diff --git a/HERRY-M--HERRY-E/index.html b/HERRY-M--HERRY-E/index.html new file mode 100644 index 0000000000000000000000000000000000000000..2fe952cdc3b2e44569e1d4fc8236d3016d2bdeaa --- /dev/null +++ b/HERRY-M--HERRY-E/index.html @@ -0,0 +1,35 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="UTF-8"> + <title>TP 1</title> + <style> + body { margin: 0; } + canvas { width: 100%; height: 100% } + .centre{text-align: center;} + </style> + </head> + <body> + <!-- API importe du site de Three.js --> + <script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims + .js"></script> + <script type="importmap"> + { + "imports": { + "three": "https://threejs.org/build/three.module.js", + "three/addons/": "https://threejs.org/examples/jsm/" + } + } + </script> + <!-- JQuery pour afficher les erreurs --> + <script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.min.js + "></script> + + <!-- Un titre centre --> + <h1 class="centre"> HERRY Mattéo - HERRY Elwyn</h1> + <div id="webGL" class="centre"></div> + <!-- Mon script avec un chemin relatif --> + <script type="module" src="TABLO.js"></script> + <p class="centre"> LE TABLO</p> + </body> +</html> \ No newline at end of file diff --git a/HERRY-M--HERRY-E/peinture.jpg b/HERRY-M--HERRY-E/peinture.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5b057424873f13f1af1392d385a209ca9ef378e0 Binary files /dev/null and b/HERRY-M--HERRY-E/peinture.jpg differ diff --git a/HERRY-M/img.jpg b/HERRY-M/img.jpg deleted file mode 100644 index d642e136257de4fb317a18f7c422126216665b16..0000000000000000000000000000000000000000 Binary files a/HERRY-M/img.jpg and /dev/null differ diff --git a/HERRY-M/index.html b/HERRY-M/index.html deleted file mode 100644 index 76e27dc119783f47da855d49712c43bab0798e9a..0000000000000000000000000000000000000000 --- a/HERRY-M/index.html +++ /dev/null @@ -1 +0,0 @@ -Le travail n'a pas encore commencé!!! \ No newline at end of file diff --git a/KANY/img.jpg b/KANY/img.jpg deleted file mode 100644 index d642e136257de4fb317a18f7c422126216665b16..0000000000000000000000000000000000000000 Binary files a/KANY/img.jpg and /dev/null differ diff --git a/KANY/index.html b/KANY/index.html deleted file mode 100644 index 76e27dc119783f47da855d49712c43bab0798e9a..0000000000000000000000000000000000000000 --- a/KANY/index.html +++ /dev/null @@ -1 +0,0 @@ -Le travail n'a pas encore commencé!!! \ No newline at end of file diff --git a/MATEJKA/img.jpg b/MATEJKA/img.jpg index d642e136257de4fb317a18f7c422126216665b16..0ecc3860d6921f1cf813277a163f407a357846ef 100644 Binary files a/MATEJKA/img.jpg and b/MATEJKA/img.jpg differ diff --git a/MATEJKA_MAURICE_COLIN/.gitkeep b/MATEJKA_MAURICE_COLIN/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/MEHIAOUI/img.jpg b/MEHIAOUI/img.jpg index d642e136257de4fb317a18f7c422126216665b16..c2b1835cf967b66a0b1052c467dfa8d1ab6d6b5c 100644 Binary files a/MEHIAOUI/img.jpg and b/MEHIAOUI/img.jpg differ diff --git a/MEHIAOUI/index.html b/MEHIAOUI/index.html index 76e27dc119783f47da855d49712c43bab0798e9a..ed6977d2d62c452e5e2aa8d8569fa271f3f532ea 100644 --- a/MEHIAOUI/index.html +++ b/MEHIAOUI/index.html @@ -1 +1,31 @@ -Le travail n'a pas encore commencé!!! \ No newline at end of file +<!DOCTYPE html> +<html> + <head> + <meta charset="UTF-8"> + <title>TP 1</title> + <link rel="icon" type="image/x-icon" href="/images/favicon.ico"> + <style> + body { margin: 0; } + canvas { width: 100%; height: 100% } + .centre{text-align: center;} + </style> + </head> + <body> + <!-- API importe du site de Three.js --> + <script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script> + <script type="importmap"> + { + "imports": { + "three": "https://threejs.org/build/three.module.js", + "three/addons/": "https://threejs.org/examples/jsm/" + } + } + </script> + <!-- JQuery pour afficher les erreurs --> + <script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.min.js"></script> + <!-- Un titre centre --> + <div id="webGL" class="centre"></div> + <!-- Mon script avec un chemin relatif --> + <script type="module" src="projet.js"></script> + </body> +</html> \ No newline at end of file diff --git a/MEHIAOUI/projet.js b/MEHIAOUI/projet.js new file mode 100644 index 0000000000000000000000000000000000000000..24463d697b7ec296385c591ea5370b2940ab9d31 --- /dev/null +++ b/MEHIAOUI/projet.js @@ -0,0 +1,137 @@ +"use strict"; // good practice - see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode +//////////////////////////////////////////////////////////////////////////////// +// Particle System +//////////////////////////////////////////////////////////////////////////////// +/*global THREE, document, window, $*/ +import * as THREE from 'three'; +import { OBJLoader } from 'three/addons/loaders/OBJLoader.js'; +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import {dat} from '../../lib/dat.gui.min.js'; + + +var camera, scene, renderer; + +var windowScale; +window.scene = new THREE.Scene(); + +import {Coordinates} from '../../lib/Coordinates.js'; + +var cameraControls; + +var clock = new THREE.Clock(); + +function fillScene() { + window.scene.fog = new THREE.Fog( 0x808080, 2000, 4000 ); + + // LIGHTS + var ambientLight = new THREE.AmbientLight( 0x222222 ); + var light = new THREE.DirectionalLight( 0xFFFFFF, 1.0 ); + light.position.set( 200, 400, 500 ); + + var light2 = new THREE.DirectionalLight( 0xFFFFFF, 1.0 ); + light2.position.set( -500, 250, -200 ); + + window.scene.add(ambientLight); + window.scene.add(light); + window.scene.add(light2); + + //Chargement textures + var texture_bowl = new THREE.TextureLoader().load('textures/bowl_texture.jpg'); + + // table + var table = new THREE.Mesh(new THREE.CylinderGeometry(10, 10, 1, 32), new THREE.MeshPhongMaterial({color: 0xE3963E})); + table.position.set(-10, 0, 5); + + // bol de fruits + var bolGeometry = new THREE.SphereGeometry(5, 32, 32, 0, Math.PI * 2, 0, Math.PI / 2); + var bolMaterial = new THREE.MeshPhongMaterial({side: THREE.DoubleSide, map: texture_bowl }); + var bol = new THREE.Mesh(bolGeometry, bolMaterial); + bol.position.set(-15, 5, 5); + bol.rotation.x = Math.PI; + + + + // pomme sur la table + //var apple = new THREE.Mesh(new THREE.SphereGeometry(1, 22, 22), new THREE.MeshPhongMaterial({color: 0x00ff00})); + //apple.position.set(-15, 1.5, 10); + // tige de la pomme + //var tige = new THREE.Mesh(new THREE.CylinderGeometry(0.1, 0.1, 1, 32), new THREE.MeshPhongMaterial({color: 0x8B4513})); + //tige.position.set(-15, 2.5, 10); + + // texture de la pomme + /*var texture = new THREE.TextureLoader().load('textures_Pommes/texture_pomme_rouge.jpg'); + var material = new THREE.MeshPhongMaterial({map: texture}); + apple.material = material;*/ + + // mur derrière la table + var mur = new THREE.Mesh(new THREE.BoxGeometry(50, 50, 1), new THREE.MeshPhongMaterial({color: 0x8B413})); + mur.position.set(0, 25, -5.5); + + // ajout des objets à la scène + //window.scene.add(tige); + //window.scene.add(apple); + window.scene.add(table); + window.scene.add(mur); + window.scene.add(bol); + + + Coordinates.drawGround({size:10000}); // width and height of ground plane + //Coordinates.drawGrid({size:10000,scale:0.01}); + //Coordinates.drawAllAxes({axisLength:200,axisRadius:1,axisTess:50}); +} + +function init() { + //var canvasWidth = 846; + //var canvasHeight = 494; + // For grading the window is fixed in size; here's general code: + var canvasWidth = window.innerWidth; + var canvasHeight = window.innerHeight; + var canvasRatio = canvasWidth / canvasHeight; + + // RENDERER + renderer = new THREE.WebGLRenderer( { antialias: true } ); + renderer = new THREE.WebGLRenderer( { clearAlpha: 1 } ); + renderer.gammaInput = true; + renderer.gammaOutput = true; + renderer.setSize(canvasWidth, canvasHeight); + renderer.setClearColor( 0xAAAAAA, 1.0 ); + + // CAMERA + camera = new THREE.PerspectiveCamera( 35, canvasRatio, 2, 8000 ); + camera.position.set(0, 5, 50 ); + camera.lookAt(new THREE.Vector3(0,5,50)); + // CONTROLS + cameraControls = new OrbitControls(camera, renderer.domElement); + cameraControls.target.set(0,5,0); + +} + +function addToDOM() { + var container = document.getElementById('webGL'); + var canvas = container.getElementsByTagName('canvas'); + if (canvas.length>0) { + container.removeChild(canvas[0]); + } + container.appendChild( renderer.domElement ); +} + +function animate() { + window.requestAnimationFrame(animate); + render(); +} + +function render() { + var delta = clock.getDelta(); + cameraControls.update(delta); + renderer.render(window.scene, camera); +} + +try { + init(); + fillScene(); + addToDOM(); + animate(); +} catch(e) { + var errorReport = "Your program encountered an unrecoverable error, can not draw on canvas. Error was:<br/><br/>"; + $('#webGL').append(errorReport+e); +} \ No newline at end of file diff --git a/index.html b/index.html index 6095a47840d3dbd0d60658550340da1b7ce79716..3109813b583fd6f2d7dc3c1782ae298bb65e5bf0 100644 --- a/index.html +++ b/index.html @@ -89,15 +89,12 @@ <tr><td> QUANG-LIEM CLÉMENT TÉO </td><td> NGUYEN RALLI VINCENT </td><td><a href=" NGUYEN ">projet webGL</a></td><td><img src=" NGUYEN/img.jpg"></td></tr> <tr><td> ZAYNAB/CHAYIMAA </td><td> RIFI </td><td><a href=" RIFI/MEHRAZ ">projet webGL</a></td><td><img src=" RIFI/img.jpg"></td></tr> <tr><td> ALEXANDRE </td><td> ROBAIL </td><td><a href=" ROBAIL ">projet webGL</a></td><td><img src=" ROBAIL/img.jpg"></td></tr> -<tr><td> FELIPE </td><td> ALVARIZA BILLAR </td><td><a href=" ALVARIZA-BILLAR ">projet webGL</a></td><td><img src=" ALVARIZA-BILLAR/img.jpg"></td></tr> <tr><td> PAUL </td><td> BARTHELEMY </td><td><a href=" BARTHELEMY ">projet webGL</a></td><td><img src=" BARTHELEMY/img.jpg"></td></tr> -<tr><td> ROMAIN DESERT </td><td> THOMAS KANY </td><td><a href=" DESERT-KANY ">projet webGL</a></td><td><img src=" DESERT-KANY/Hopper-Gas.png"></td></tr> +<tr><td> FELIPE / ROMAIN / THOMAS </td><td> ALVARIZA-BILLAR / DESERT / KANY </td><td><a href=" ALVARIZA-BILLAR_DESERT_KANY ">projet webGL</a></td><td><img src=" ALVARIZA-BILLAR_DESERT_KANY/Hopper-Gas.png"></td></tr> <tr><td> ELIOT </td><td> DUBREUIL </td><td><a href=" DUBREUIL ">projet webGL</a></td><td><img src=" DUBREUIL/img.jpg"></td></tr> <tr><td> ELWYN </td><td> HERRY </td><td><a href=" HERRY-E ">projet webGL</a></td><td><img src=" HERRY-E/img.jpg"></td></tr> <tr><td> MATTEO </td><td> HERRY </td><td><a href=" HERRY-M ">projet webGL</a></td><td><img src=" HERRY-M/img.jpg"></td></tr> -<tr><td> MILAN </td><td> MATEJKA </td><td><a href=" MATEJKA ">projet webGL</a></td><td><img src=" MATEJKA/img.jpg"></td></tr> -<tr><td> SIMON </td><td> MAURICE </td><td><a href=" MAURICE ">projet webGL</a></td><td><img src=" MAURICE/img.jpg"></td></tr> -<tr><td> GABIN </td><td> COLIN </td><td><a href=" COLIN ">projet webGL</a></td><td><img src=" COLIN/img.jpg"></td></tr> +<tr><td> MILAN </td><td> MATEJKA </td><td> SIMON </td><td> MAURICE </td><td> GABIN </td><td> COLIN </td><td><a href=" MATEJKA ">projet webGL</a></td><td><img src=" MATEJKA/img.jpg"></td></tr> <tr><td> MOHAMED </td><td> MEHIAOUI </td><td><a href=" MEHIAOUI ">projet webGL</a></td><td><img src=" MEHIAOUI/img.jpg"></td></tr> <tr><td> AYAT </td><td> MERIMI </td><td><a href=" MERIMI ">projet webGL</a></td><td><img src=" MERIMI/img.jpg"></td></tr> <tr><td> TOM </td><td> NIRRENGARTEN </td><td><a href=" NIRRENGARTEN ">projet webGL</a></td><td><img src=" NIRRENGARTEN/img.jpg"></td></tr>