Explorar o código

Merge branch 'dev' into nodejsbuildsystem

ide user ide_gero3 %!s(int64=13) %!d(string=hai) anos
pai
achega
4218752254
Modificáronse 93 ficheiros con 10312 adicións e 3594 borrados
  1. 3 76
      README.md
  2. 419 388
      build/Three.js
  3. 181 160
      build/custom/ThreeCanvas.js
  4. 90 83
      build/custom/ThreeExtras.js
  5. 163 142
      build/custom/ThreeWebGL.js
  6. 2 2
      docs/api/cameras/OrthographicCamera.html
  7. 5 11
      docs/api/core/Geometry.html
  8. 2 2
      docs/api/materials/LineBasicMaterial.html
  9. 44 7
      examples/canvas_geometry_earth.html
  10. 110 23
      examples/js/MarchingCubes.js
  11. 6 8
      examples/js/Stats.js
  12. 83 1
      examples/js/UVsUtils.js
  13. 213 204
      examples/js/loaders/OBJLoader.js
  14. 60 53
      examples/js/loaders/VTKLoader.js
  15. 18 20
      examples/js/renderers/SoftwareRenderer2.js
  16. 427 0
      examples/js/renderers/SoftwareRenderer3.js
  17. 140 0
      examples/misc_camera_orbit.html
  18. 20 19
      examples/misc_camera_trackball.html
  19. 3 1
      examples/misc_software.html
  20. 111 0
      examples/misc_uv_tests.html
  21. 163 0
      examples/webgl_geometry_convex.html
  22. 276 276
      examples/webgl_geometry_extrude_splines.html
  23. 172 0
      examples/webgl_geometry_extrude_uvs2.html
  24. 8 8
      examples/webgl_lines_colors.html
  25. 8 8
      examples/webgl_lines_splines.html
  26. 10 9
      examples/webgl_loader_collada.html
  27. 8 2
      examples/webgl_loader_json_blender.html
  28. 22 4
      examples/webgl_loader_obj.html
  29. 48 38
      examples/webgl_loader_vtk.html
  30. 53 3
      examples/webgl_marching_cubes.html
  31. 3 1
      examples/webgl_materials_texture_filters.html
  32. 146 0
      examples/webgl_test_memory2.html
  33. 1 1
      examples/webgl_trackballcamera_earth.html
  34. BIN=BIN
      gui/files/inconsolata.woff
  35. 91 119
      gui/index.html
  36. 0 136
      gui/js/Code.Templates.js
  37. 0 226
      gui/js/Code.js
  38. 0 72
      gui/js/UI.Toolbar.js
  39. 0 257
      gui/js/UI.Viewport.js
  40. 452 15
      gui/js/UI.js
  41. 0 7
      gui/js/libs/signals.min.js
  42. 14 0
      gui/js/ui/MenuBar.js
  43. 15 0
      gui/js/ui/Sidebar.Outliner.js
  44. 267 0
      gui/js/ui/Sidebar.Properties.Geometry.js
  45. 73 0
      gui/js/ui/Sidebar.Properties.Material.js
  46. 106 0
      gui/js/ui/Sidebar.Properties.Object3D.js
  47. 13 0
      gui/js/ui/Sidebar.Properties.js
  48. 15 0
      gui/js/ui/Sidebar.js
  49. 229 0
      gui/js/ui/Viewport.js
  50. 15 1
      src/Three.js
  51. 1 1
      src/cameras/Camera.js
  52. 1 1
      src/core/EventTarget.js
  53. 2 0
      src/core/Geometry.js
  54. 19 2
      src/core/Object3D.js
  55. 208 51
      src/core/Quaternion.js
  56. 81 55
      src/core/Ray.js
  57. 188 61
      src/core/Vector3.js
  58. 153 0
      src/core/Vector4.js
  59. 474 0
      src/extras/FontUtils.js
  60. 30 9
      src/extras/ImageUtils.js
  61. 2 0
      src/extras/SceneUtils.js
  62. 3 1
      src/extras/controls/FirstPersonControls.js
  63. 3 1
      src/extras/controls/FlyControls.js
  64. 282 0
      src/extras/controls/OrbitControls.js
  65. 3 1
      src/extras/controls/RollControls.js
  66. 10 5
      src/extras/controls/TrackballControls.js
  67. 25 8
      src/extras/core/Curve.js
  68. 1 1
      src/extras/core/CurvePath.js
  69. 57 168
      src/extras/core/Path.js
  70. 0 68
      src/extras/core/TextPath.js
  71. 228 0
      src/extras/geometries/ConvexGeometry.js
  72. 17 8
      src/extras/geometries/ExtrudeGeometry.js
  73. 4 443
      src/extras/geometries/TextGeometry.js
  74. 2 2
      src/extras/helpers/ArrowHelper.js
  75. 1 1
      src/extras/modifiers/SubdivisionModifier.js
  76. 0 1
      src/extras/objects/LensFlare.js
  77. 0 1
      src/lights/Light.js
  78. 661 0
      src/loaders/GeometryLoader.js
  79. 27 14
      src/loaders/ImageLoader.js
  80. 1 1
      src/loaders/JSONLoader.js
  81. 36 0
      src/loaders/LoadingMonitor.js
  82. 44 0
      src/loaders/TextureLoader.js
  83. 0 1
      src/objects/Bone.js
  84. 0 1
      src/objects/LOD.js
  85. 1 2
      src/objects/Mesh.js
  86. 8 2
      src/renderers/CanvasRenderer.js
  87. 119 23
      src/renderers/WebGLRenderer.js
  88. 16 9
      src/textures/Texture.js
  89. 14 269
      utils/build.py
  90. 431 0
      utils/exporters/blender/2.63/scripts/addons/io_mesh_threejs/__init__.py
  91. 1939 0
      utils/exporters/blender/2.63/scripts/addons/io_mesh_threejs/export_threejs.py
  92. 633 0
      utils/exporters/blender/2.63/scripts/addons/io_mesh_threejs/import_threejs.py
  93. 279 0
      utils/files.json

+ 3 - 76
README.md

@@ -1,84 +1,11 @@
 three.js
 ========
 
-#### Javascript 3D library ####
+#### JavaScript 3D library ####
 
 The aim of the project is to create a lightweight 3D library with a very low level of complexity — in other words, for dummies. The library provides <canvas>, <svg> and WebGL renderers.
 
-[Contributors](http://github.com/mrdoob/three.js/contributors) — [Documentation](http://mrdoob.github.com/three.js/docs/latest/) — [Getting Started](http://www.aerotwist.com/lab/getting-started-with-three-js/)
-
-More? [#three.js on irc.freenode.net](http://webchat.freenode.net/?channels=three.js)
-
-
-### Featured Examples ([View all](http://mrdoob.github.com/three.js/)) ###
-
-
-#### WebGL (Context 3D) ####
-
-<a href="http://mrdoob.github.com/three.js/examples/webgl_panorama_equirectangular.html"><img src="http://mrdoob.github.com/three.js/assets/examples/44_equirectangular.png" width="102" height="77" alt="equirectangular"></a>
-<a href="http://mrdoob.github.com/three.js/examples/webgl_materials_texture_filters.html"><img src="http://mrdoob.github.com/three.js/assets/examples/42_scissors.png" width="102" height="77" alt="scissors"></a>
-<a href="http://mrdoob.github.com/three.js/examples/misc_lookat.html"><img src="http://mrdoob.github.com/three.js/assets/examples/41_lookat.png" width="102" height="77" alt="lookat"></a>
-<a href="http://mrdoob.github.com/three.js/examples/webgl_materials_video.html"><img src="http://mrdoob.github.com/three.js/assets/examples/40_video.png" width="102" height="77" alt="video"></a>
-<a href="http://mrdoob.github.com/three.js/examples/webgl_postprocessing_dof.html"><img src="http://mrdoob.github.com/three.js/assets/examples/39_dof.png" width="102" height="77" alt="dof"></a>
-<a href="http://mrdoob.github.com/three.js/examples/webgl_ribbons.html"><img src="http://mrdoob.github.com/three.js/assets/examples/38_ribbon.png" width="102" height="77" alt="ribbon"></a>
-<a href="http://mrdoob.github.com/three.js/examples/webgl_geometry_colors.html"><img src="http://mrdoob.github.com/three.js/assets/examples/37_vertexcolors.png" width="102" height="77" alt="vertexcolors"></a>
-<a href="http://mrdoob.github.com/three.js/examples/webgl_particles_billboards_colors.html"><img src="http://mrdoob.github.com/three.js/assets/examples/36_particles.png" width="102" height="77" alt="particles"></a>
-<a href="http://mrdoob.github.com/three.js/examples/webgl_lines_colors.html"><img src="http://mrdoob.github.com/three.js/assets/examples/35_lines.png" width="102" height="77" alt="lines"></a>
-<a href="http://mrdoob.github.com/three.js/examples/webgl_shader.html"><img src="http://mrdoob.github.com/three.js/assets/examples/34_shader.png" width="102" height="77" alt="shader"></a>
-<a href="http://mrdoob.github.com/three.js/examples/webgl_materials_normalmap2.html"><img src="http://mrdoob.github.com/three.js/assets/examples/33_materials_normalmap2.png" width="102" height="77" alt="materials_normalmap2"></a>
-<a href="http://mrdoob.github.com/three.js/examples/webgl_materials_grass.html"><img src="http://mrdoob.github.com/three.js/assets/examples/32_materials_grass.png" width="102" height="77" alt="materials_grass"></a>
-<a href="http://mrdoob.github.com/three.js/examples/webgl_materials_normalmap.html"><img src="http://mrdoob.github.com/three.js/assets/examples/31_materials_normalmap.png" width="102" height="77" alt="materials_normalmap"></a>
-<a href="http://mrdoob.github.com/three.js/examples/webgl_geometry_terrain.html"><img src="http://mrdoob.github.com/three.js/assets/examples/30_geometry_terrain_gl.png" width="102" height="77" alt="geometry_terrain_gl"></a>
-<a href="http://mrdoob.github.com/three.js/examples/webgl_geometry_minecraft_ao.html"><img src="http://mrdoob.github.com/three.js/assets/examples/29_geometry_minecraft.png" width="102" height="77" alt="geometry_minecraft"></a>
-<a href="http://mrdoob.github.com/three.js/examples/webgl_materials_shaders_fresnel.html"><img src="http://mrdoob.github.com/three.js/assets/examples/28_materials_shaders_fresnel.png" width="102" height="77" alt="materials_shader_fresnel"></a>
-<a href="http://mrdoob.github.com/three.js/examples/webgl_materials_cars.html"><img src="http://mrdoob.github.com/three.js/assets/examples/25_materials_cars.png" width="102" height="77" alt="materials_cars"></a>
-<a href="http://mrdoob.github.com/three.js/examples/webgl_materials_cubemap_refraction.html"><img src="http://mrdoob.github.com/three.js/assets/examples/18_materials_cubemap_refraction.png" width="102" height="77" alt="materials_cubemap_refraction"></a>
-<a href="http://mrdoob.github.com/three.js/examples/webgl_materials_cubemap_balls_reflection.html"><img src="http://mrdoob.github.com/three.js/assets/examples/15_materials_cubemap_balls_reflection.png" width="102" height="77" alt="materials_cubemap_balls_reflection"></a>
-<a href="http://mrdoob.github.com/three.js/examples/webgl_materials_cubemap_balls_refraction.html"><img src="http://mrdoob.github.com/three.js/assets/examples/16_materials_cubemap_balls_refraction.png" width="102" height="77" alt="materials_cubemap_balls_refraction"></a>
-<a href="http://mrdoob.github.com/three.js/examples/webgl_materials_cubemap_escher.html"><img src="http://mrdoob.github.com/three.js/assets/examples/17_materials_cubemap_escher.png" width="102" height="77" alt="materials_cubemap_escher"></a>
-<a href="http://mrdoob.github.com/three.js/examples/webgl_materials_cubemap.html"><img src="http://mrdoob.github.com/three.js/assets/examples/14_materials_cubemap.png" width="102" height="77" alt="materials_cubemap"></a>
-<a href="http://mrdoob.github.com/three.js/examples/webgl_materials.html"><img src="http://mrdoob.github.com/three.js/assets/examples/20_materials_gl.png" width="102" height="77" alt="materials_gl"></a>
-<a href="http://mrdoob.github.com/three.js/examples/webgl_geometry_large_mesh.html"><img src="http://mrdoob.github.com/three.js/assets/examples/12_large_mesh.png" width="102" height="77" alt="large_mesh"></a>
-
-
-#### Canvas (Context 2D) ####
-
-<a href="http://mrdoob.github.com/three.js/examples/canvas_materials_reflection.html"><img src="http://mrdoob.github.com/three.js/assets/examples/27_materials_reflection.png" width="102" height="77" alt="materials_reflection"></a>
-<a href="http://mrdoob.github.com/three.js/examples/canvas_materials.html"><img src="http://mrdoob.github.com/three.js/assets/examples/13_materials.png" width="102" height="77" alt="materials"></a>
-<a href="http://mrdoob.github.com/three.js/examples/canvas_materials_depth.html"><img src="http://mrdoob.github.com/three.js/assets/examples/19_materials_depth.png" width="102" height="77" alt="materials_depth"></a>
-<a href="http://mrdoob.github.com/three.js/examples/canvas_materials_normal.html"><img src="http://mrdoob.github.com/three.js/assets/examples/22_materials_normal.png" width="102" height="77" alt="materials_normal"></a>
-<a href="http://mrdoob.github.com/three.js/examples/canvas_lights_pointlights.html"><img src="http://mrdoob.github.com/three.js/assets/examples/09_walthead.png" width="102" height="77" alt="lights_pointlights"></a>
-<a href="http://mrdoob.github.com/three.js/examples/canvas_interactive_cubes.html"><img src="http://mrdoob.github.com/three.js/assets/examples/11_interactive.png" width="102" height="77" alt="interactive_cubes"></a>
-<a href="http://mrdoob.github.com/three.js/examples/canvas_camera_orthographic.html"><img src="http://mrdoob.github.com/three.js/assets/examples/10_orthographic.png" width="102" height="77" alt="camera_ortographic"></a>
-<a href="http://mrdoob.github.com/three.js/examples/canvas_geometry_birds.html"><img src="http://mrdoob.github.com/three.js/assets/examples/08_birds.png" width="102" height="77" alt="geometry_birds"></a>
-<a href="http://mrdoob.github.com/three.js/examples/canvas_geometry_earth.html"><img src="http://mrdoob.github.com/three.js/assets/examples/07_earth.png" width="102" height="77" alt="geometry_earth"></a>
-<a href="http://mrdoob.github.com/three.js/examples/canvas_geometry_terrain.html"><img src="http://mrdoob.github.com/three.js/assets/examples/06_terrain.png" width="102" height="77" alt="geometry_terrain"></a>
-<a href="http://mrdoob.github.com/three.js/examples/canvas_materials_video.html"><img src="http://mrdoob.github.com/three.js/assets/examples/24_materials_video.png" width="102" height="77" alt="materials_video"></a>
-<a href="http://mrdoob.github.com/three.js/examples/canvas_geometry_panorama.html"><img src="http://mrdoob.github.com/three.js/assets/examples/04_vr.png" width="102" height="77" alt="geometry_panorama"></a>
-<a href="http://mrdoob.github.com/three.js/examples/canvas_geometry_cube.html"><img src="http://mrdoob.github.com/three.js/assets/examples/03_cube.png" width="102" height="77" alt="geometry_cube"></a>
-<a href="http://mrdoob.github.com/three.js/examples/canvas_particles_sprites.html"><img src="http://mrdoob.github.com/three.js/assets/examples/26_particles_sprites.png" width="102" height="77" alt="particles_sprites"></a>
-<a href="http://mrdoob.github.com/three.js/examples/canvas_particles_random.html"><img src="http://mrdoob.github.com/three.js/assets/examples/02_random.png" width="102" height="77" alt="particles_random"></a>
-<a href="http://mrdoob.github.com/three.js/examples/canvas_particles_waves.html"><img src="http://mrdoob.github.com/three.js/assets/examples/01_waves.png" width="102" height="77" alt="particles_wave"></a>
-
-
-### Featured projects ###
-
-<a href="http://triggerrally.com/"><img src="http://mrdoob.github.com/three.js/assets/projects/26_triggerrally.png" width="102" height="77" alt="Trigger Rally"></a>
-<a href="http://yagiz.me/zombiesvscow/"><img src="http://mrdoob.github.com/three.js/assets/projects/25_zombiesvscow.png" width="102" height="77" alt="Zombies vs Cow"></a>
-<a href="http://blackjk3.github.com/threefab/"><img src="http://mrdoob.github.com/three.js/assets/projects/24_threefab.png" width="102" height="77" alt="ThreeFab"></a>
-<a href="http://dl.dropbox.com/u/6213850/WebGL/nyanCat/nyan.html"><img src="http://mrdoob.github.com/three.js/assets/projects/23_nyan.png" width="102" height="77" alt="Nyan Cat"></a>
-<a href="http://idflood.github.com/ThreeNodes.js/public/index.html"><img src="http://mrdoob.github.com/three.js/assets/projects/22_threenodes.png" width="102" height="77" alt="ThreeNodes"></a>
-<a href="http://www.adidas.com/football/uk/pages/f50/"><img src="http://mrdoob.github.com/three.js/assets/projects/21_f50.png" width="102" height="77" alt="f60"></a>
-<a href="http://lights.elliegoulding.com/"><img src="http://mrdoob.github.com/three.js/assets/projects/20_lights.png" width="102" height="77" alt="Lights"></a>
-<a href="http://inear.se/beanstalk/"><img src="http://mrdoob.github.com/three.js/assets/projects/19_beanstalk.png" width="102" height="77" alt="Infinite beanstalk"></a>
-<a href="http://superfad.com/missioncontrol/"><img src="http://mrdoob.github.com/three.js/assets/projects/18_missioncontrol.png" width="102" height="77" alt="Mission Control"></a>
-<a href="http://ro.me/"><img src="http://mrdoob.github.com/three.js/assets/projects/17_rome.png" width="102" height="77" alt="ROME"></a>
-<a href="http://data-arts.appspot.com/globe"><img src="http://mrdoob.github.com/three.js/assets/projects/16_globe.png" width="102" height="77" alt="Globe"></a>
-<a href="http://helloracer.com/webgl/"><img src="http://mrdoob.github.com/three.js/assets/projects/13_helloracer.png" width="102" height="77" alt="HelloRacer"></a>
-<a href="http://www.omiod.com/games/fastkat.php"><img src="http://mrdoob.github.com/three.js/assets/projects/12_fastkat.png" width="102" height="77" alt="FastKat"></a>
-<a href="http://mrdoob.com/projects/voxels/"><img src="http://mrdoob.github.com/three.js/assets/projects/10_voxels.png" width="102" height="77" alt="Voxels"></a>
-<a href="http://thewildernessdowntown.com/"><img src="http://mrdoob.github.com/three.js/assets/projects/09_arcadefire.png" width="102" height="77" alt="The Wilderness Downtown"></a>
-<a href="http://xplsv.com/prods/demos/xplsv_orsotheysay/"><img src="http://mrdoob.github.com/three.js/assets/projects/07_orsotheysay.png" width="102" height="77" alt="Or so they say..."></a>
+[Examples](http://mrdoob.github.com/three.js/) — [Documentation](http://mrdoob.github.com/three.js/docs/latest/)
 
 
 ### Usage ###
@@ -90,7 +17,7 @@ Alternatively see [how to build the library yourself](https://github.com/mrdoob/
 <script src="js/Three.js"></script>
 ```
 
-This code creates a camera, then creates a scene, adds a cube on it, creates a &lt;canvas&gt; renderer and adds its viewport in the document.body element.
+This code creates a scene, then creates a camera, adds the camera and cube to the scene, creates a &lt;canvas&gt; renderer and adds its viewport in the document.body element.
 
 ```html
 <script>

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 419 - 388
build/Three.js


+ 181 - 160
build/custom/ThreeCanvas.js

@@ -1,9 +1,9 @@
 // ThreeCanvas.js - http://github.com/mrdoob/three.js
-'use strict';var THREE=THREE||{REVISION:"49"};self.Int32Array||(self.Int32Array=Array,self.Float32Array=Array);
-(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"]}if(!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};if(!window.cancelAnimationFrame)window.cancelAnimationFrame=
+'use strict';var THREE=THREE||{REVISION:"50dev"};self.console||(self.console={info:function(){},log:function(){},debug:function(){},warn:function(){},error:function(){}});self.Int32Array||(self.Int32Array=Array,self.Float32Array=Array);
+(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"]}if(!window.requestAnimationFrame)window.requestAnimationFrame=function(b){var c=Date.now(),e=Math.max(0,16-(c-a)),g=window.setTimeout(function(){b(c+e)},e);a=c+e;return g};if(!window.cancelAnimationFrame)window.cancelAnimationFrame=
 function(a){clearTimeout(a)}})();THREE.Color=function(a){a!==void 0&&this.setHex(a);return this};
 THREE.Color.prototype={constructor:THREE.Color,r:1,g:1,b:1,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},setRGB:function(a,b,c){this.r=a;this.g=b;this.b=c;return this},setHSV:function(a,b,c){var d,e,f;if(c===0)this.r=this.g=this.b=0;else{d=Math.floor(a*6);e=a*6-d;a=c*(1-b);f=c*(1-b*e);b=c*(1-b*(1-e));switch(d){case 1:this.r=f;this.g=c;this.b=a;break;case 2:this.r=a;this.g=c;this.b=b;break;case 3:this.r=a;this.g=f;this.b=c;break;case 4:this.r=b;this.g=a;this.b=c;break;case 5:this.r=c;this.g=a;this.b=f;break;case 6:case 0:this.r=c;this.g=b;this.b=a}}return this},setHex:function(a){a=
+this.b=Math.sqrt(this.b);return this},setRGB:function(a,b,c){this.r=a;this.g=b;this.b=c;return this},setHSV:function(a,b,c){var d,f,e;if(c===0)this.r=this.g=this.b=0;else{d=Math.floor(a*6);f=a*6-d;a=c*(1-b);e=c*(1-b*f);b=c*(1-b*(1-f));switch(d){case 1:this.r=e;this.g=c;this.b=a;break;case 2:this.r=a;this.g=c;this.b=b;break;case 3:this.r=a;this.g=e;this.b=c;break;case 4:this.r=b;this.g=a;this.b=c;break;case 5:this.r=c;this.g=a;this.b=e;break;case 6:case 0:this.r=c;this.g=b;this.b=a}}return this},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},lerpSelf:function(a,b){this.r=this.r+(a.r-this.r)*b;this.g=this.g+(a.g-this.g)*b;this.b=this.b+(a.b-this.b)*b;return this},getHex:function(){return Math.floor(this.r*255)<<16^Math.floor(this.g*255)<<8^Math.floor(this.b*255)},getContextStyle:function(){return"rgb("+Math.floor(this.r*255)+","+Math.floor(this.g*255)+","+Math.floor(this.b*255)+")"},clone:function(){return(new THREE.Color).setRGB(this.r,this.g,this.b)}};
 THREE.Vector2=function(a,b){this.x=a||0;this.y=b||0};
 THREE.Vector2.prototype={constructor:THREE.Vector2,set:function(a,b){this.x=a;this.y=b;return this},copy:function(a){this.x=a.x;this.y=a.y;return this},add:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;return this},addSelf:function(a){this.x=this.x+a.x;this.y=this.y+a.y;return this},sub:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;return this},subSelf:function(a){this.x=this.x-a.x;this.y=this.y-a.y;return this},multiplyScalar:function(a){this.x=this.x*a;this.y=this.y*a;return this},divideScalar:function(a){if(a){this.x=
@@ -13,147 +13,169 @@ THREE.Vector3.prototype={constructor:THREE.Vector3,set:function(a,b,c){this.x=a;
 a;this.z=this.z+a;return this},sub:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;this.z=a.z-b.z;return this},subSelf:function(a){this.x=this.x-a.x;this.y=this.y-a.y;this.z=this.z-a.z;return this},multiply:function(a,b){this.x=a.x*b.x;this.y=a.y*b.y;this.z=a.z*b.z;return this},multiplySelf:function(a){this.x=this.x*a.x;this.y=this.y*a.y;this.z=this.z*a.z;return this},multiplyScalar:function(a){this.x=this.x*a;this.y=this.y*a;this.z=this.z*a;return this},divideSelf:function(a){this.x=this.x/a.x;this.y=
 this.y/a.y;this.z=this.z/a.z;return this},divideScalar:function(a){if(a){this.x=this.x/a;this.y=this.y/a;this.z=this.z/a}else this.z=this.y=this.x=0;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.lengthSq())},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){return this.normalize().multiplyScalar(a)},lerpSelf:function(a,b){this.x=this.x+(a.x-this.x)*b;this.y=this.y+(a.y-this.y)*b;this.z=this.z+(a.z-this.z)*b;return this},cross: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},crossSelf:function(a){var b=this.x,c=this.y,d=this.z;this.x=c*a.z-d*a.y;this.y=d*a.x-b*a.z;this.z=b*a.y-c*a.x;return this},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){return(new THREE.Vector3).sub(this,
-a).lengthSq()},getPositionFromMatrix:function(a){this.x=a.elements[12];this.y=a.elements[13];this.z=a.elements[14];return this},getRotationFromMatrix:function(a,b){var c=b?b.x:1,d=b?b.y:1,e=b?b.z:1,f=a.elements[0]/c,g=a.elements[4]/d,c=a.elements[1]/c,d=a.elements[5]/d,k=a.elements[9]/e,m=a.elements[10]/e;this.y=Math.asin(a.elements[8]/e);e=Math.cos(this.y);if(Math.abs(e)>1.0E-5){this.x=Math.atan2(-k/e,m/e);this.z=Math.atan2(-g/e,f/e)}else{this.x=0;this.z=Math.atan2(c,d)}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},equals:function(a){return a.x===this.x&&a.y===this.y&&a.z===this.z},isZero:function(){return this.lengthSq()<1.0E-4},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=d!==void 0?d:1};
+a).lengthSq()},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,f=d[0],e=d[4],g=d[8],m=d[1],k=d[5],l=d[9],h=d[2],n=d[6],d=d[10];switch(b||"XYZ"){case "YXZ":this.x=Math.asin(-c(l));if(Math.abs(l)<0.99999){this.y=Math.atan2(g,d);this.z=Math.atan2(m,k)}else{this.y=Math.atan2(-h,f);this.z=0}break;case "ZXY":this.x=Math.asin(c(n));if(Math.abs(n)<
+0.99999){this.y=Math.atan2(-h,d);this.z=Math.atan2(-e,k)}else{this.y=0;this.z=Math.atan2(g,f)}break;case "ZYX":this.y=Math.asin(-c(h));if(Math.abs(h)<0.99999){this.x=Math.atan2(n,d);this.z=Math.atan2(m,f)}else{this.x=0;this.z=Math.atan2(-e,k)}break;case "YZX":this.z=Math.asin(c(m));if(Math.abs(m)<0.99999){this.x=Math.atan2(-l,k);this.y=Math.atan2(-h,f)}else{this.x=0;this.y=Math.atan2(h,d)}break;case "XZY":this.z=Math.asin(-c(e));if(Math.abs(e)<0.99999){this.x=Math.atan2(n,k);this.y=Math.atan2(g,f)}else{this.x=
+Math.atan2(-g,d);this.y=0}break;default:this.y=Math.asin(c(g));if(Math.abs(g)<0.99999){this.x=Math.atan2(-l,d);this.z=Math.atan2(-e,f)}else{this.x=Math.atan2(m,k);this.z=0}}return this},setEulerFromQuaternion:function(a,b){function c(a){return Math.min(Math.max(a,-1),1)}var d=a.x*a.x,f=a.y*a.y,e=a.z*a.z,g=a.w*a.w;switch(b){case "YXZ":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-f+e);this.z=Math.atan2(2*(a.x*a.y+a.z*a.w),g-d+f-e);break;case "ZXY":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-f+e);this.z=Math.atan2(2*(a.z*a.w-a.x*a.y),g-d+f-e);break;case "ZYX":this.x=Math.atan2(2*(a.x*a.w+a.z*a.y),g-d-f+e);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-f-e);break;case "YZX":this.x=Math.atan2(2*(a.x*a.w-a.z*a.y),g-d+f-e);this.y=Math.atan2(2*(a.y*a.w-a.x*a.z),g+d-f-e);this.z=Math.asin(c(2*(a.x*a.y+a.z*a.w)));break;case "XZY":this.x=Math.atan2(2*(a.x*a.w+a.y*a.z),g-d+f-e);this.y=Math.atan2(2*
+(a.x*a.z+a.y*a.w),g+d-f-e);this.z=Math.asin(c(2*(a.z*a.w-a.x*a.y)));break;default:this.x=Math.atan2(2*(a.x*a.w-a.y*a.z),g-d-f+e);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-f-e)}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},equals:function(a){return a.x===
+this.x&&a.y===this.y&&a.z===this.z},isZero:function(){return this.lengthSq()<1.0E-4},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=d!==void 0?d:1};
 THREE.Vector4.prototype={constructor:THREE.Vector4,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!==void 0?a.w:1;return this},add: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},addSelf:function(a){this.x=this.x+a.x;this.y=this.y+a.y;this.z=this.z+a.z;this.w=this.w+a.w;return this},sub: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},subSelf:function(a){this.x=
 this.x-a.x;this.y=this.y-a.y;this.z=this.z-a.z;this.w=this.w-a.w;return this},multiplyScalar:function(a){this.x=this.x*a;this.y=this.y*a;this.z=this.z*a;this.w=this.w*a;return this},divideScalar:function(a){if(a){this.x=this.x/a;this.y=this.y/a;this.z=this.z/a;this.w=this.w/a}else{this.z=this.y=this.x=0;this.w=1}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.dot(this)},length:function(){return Math.sqrt(this.lengthSq())},
-normalize:function(){return this.divideScalar(this.length())},setLength:function(a){return this.normalize().multiplyScalar(a)},lerpSelf:function(a,b){this.x=this.x+(a.x-this.x)*b;this.y=this.y+(a.y-this.y)*b;this.z=this.z+(a.z-this.z)*b;this.w=this.w+(a.w-this.w)*b;return this},clone:function(){return new THREE.Vector4(this.x,this.y,this.z,this.w)}};THREE.Frustum=function(){this.planes=[new THREE.Vector4,new THREE.Vector4,new THREE.Vector4,new THREE.Vector4,new THREE.Vector4,new THREE.Vector4]};
-THREE.Frustum.prototype.setFromMatrix=function(a){var b,c=this.planes,d=a.elements,a=d[0];b=d[1];var e=d[2],f=d[3],g=d[4],k=d[5],m=d[6],j=d[7],h=d[8],i=d[9],o=d[10],n=d[11],p=d[12],l=d[13],q=d[14],d=d[15];c[0].set(f-a,j-g,n-h,d-p);c[1].set(f+a,j+g,n+h,d+p);c[2].set(f+b,j+k,n+i,d+l);c[3].set(f-b,j-k,n-i,d-l);c[4].set(f-e,j-m,n-o,d-q);c[5].set(f+e,j+m,n+o,d+q);for(a=0;a<6;a++){b=c[a];b.divideScalar(Math.sqrt(b.x*b.x+b.y*b.y+b.z*b.z))}};
-THREE.Frustum.prototype.contains=function(a){for(var b=this.planes,c=a.matrixWorld,d=c.elements,c=-a.geometry.boundingSphere.radius*c.getMaxScaleOnAxis(),e=0;e<6;e++){a=b[e].x*d[12]+b[e].y*d[13]+b[e].z*d[14]+b[e].w;if(a<=c)return false}return true};THREE.Frustum.__v1=new THREE.Vector3;
-THREE.Ray=function(a,b){function c(a,b,c){p.sub(c,a);u=p.dot(b);s=l.add(a,q.copy(b).multiplyScalar(u));return z=c.distanceTo(s)}function d(a,b,c,d){p.sub(d,b);l.sub(c,b);q.sub(a,b);A=p.dot(p);v=p.dot(l);D=p.dot(q);x=l.dot(l);G=l.dot(q);t=1/(A*x-v*v);y=(x*D-v*G)*t;C=(A*G-v*D)*t;return y>=0&&C>=0&&y+C<1}this.origin=a||new THREE.Vector3;this.direction=b||new THREE.Vector3;var e=1.0E-4;this.setPrecision=function(a){e=a};var f=new THREE.Vector3,g=new THREE.Vector3,k=new THREE.Vector3,m=new THREE.Vector3,
-j=new THREE.Vector3,h=new THREE.Vector3,i=new THREE.Vector3,o=new THREE.Vector3,n=new THREE.Vector3;this.intersectObject=function(a){var b,l=[];if(a instanceof THREE.Particle){var r=c(this.origin,this.direction,a.matrixWorld.getPosition());if(r>a.scale.x)return[];b={distance:r,point:a.position,face:null,object:a};l.push(b)}else if(a instanceof THREE.Mesh){var r=c(this.origin,this.direction,a.matrixWorld.getPosition()),p=THREE.Frustum.__v1.set(a.matrixWorld.getColumnX().length(),a.matrixWorld.getColumnY().length(),
-a.matrixWorld.getColumnZ().length());if(r>a.geometry.boundingSphere.radius*Math.max(p.x,Math.max(p.y,p.z)))return l;var q,s,t=a.geometry,u=t.vertices,w;a.matrixRotationWorld.extractRotation(a.matrixWorld);r=0;for(p=t.faces.length;r<p;r++){b=t.faces[r];j.copy(this.origin);h.copy(this.direction);w=a.matrixWorld;i=w.multiplyVector3(i.copy(b.centroid)).subSelf(j);o=a.matrixRotationWorld.multiplyVector3(o.copy(b.normal));q=h.dot(o);if(!(Math.abs(q)<e)){s=o.dot(i)/q;if(!(s<0)&&(a.doubleSided||(a.flipSided?
-q>0:q<0))){n.add(j,h.multiplyScalar(s));if(b instanceof THREE.Face3){f=w.multiplyVector3(f.copy(u[b.a]));g=w.multiplyVector3(g.copy(u[b.b]));k=w.multiplyVector3(k.copy(u[b.c]));if(d(n,f,g,k)){b={distance:j.distanceTo(n),point:n.clone(),face:b,object:a};l.push(b)}}else if(b instanceof THREE.Face4){f=w.multiplyVector3(f.copy(u[b.a]));g=w.multiplyVector3(g.copy(u[b.b]));k=w.multiplyVector3(k.copy(u[b.c]));m=w.multiplyVector3(m.copy(u[b.d]));if(d(n,f,g,m)||d(n,g,k,m)){b={distance:j.distanceTo(n),point:n.clone(),
-face:b,object:a};l.push(b)}}}}}}return l};this.intersectObjects=function(a){for(var b=[],c=0,d=a.length;c<d;c++)Array.prototype.push.apply(b,this.intersectObject(a[c]));b.sort(function(a,b){return a.distance-b.distance});return b};var p=new THREE.Vector3,l=new THREE.Vector3,q=new THREE.Vector3,u,s,z,A,v,D,x,G,t,y,C};
-THREE.Rectangle=function(){function a(){f=d-b;g=e-c}var b,c,d,e,f,g,k=true;this.getX=function(){return b};this.getY=function(){return c};this.getWidth=function(){return f};this.getHeight=function(){return g};this.getLeft=function(){return b};this.getTop=function(){return c};this.getRight=function(){return d};this.getBottom=function(){return e};this.set=function(f,g,h,i){k=false;b=f;c=g;d=h;e=i;a()};this.addPoint=function(f,g){if(k){k=false;b=f;c=g;d=f;e=g}else{b=b<f?b:f;c=c<g?c:g;d=d>f?d:f;e=e>g?
-e:g}a()};this.add3Points=function(f,g,h,i,o,n){if(k){k=false;b=f<h?f<o?f:o:h<o?h:o;c=g<i?g<n?g:n:i<n?i:n;d=f>h?f>o?f:o:h>o?h:o;e=g>i?g>n?g:n:i>n?i:n}else{b=f<h?f<o?f<b?f:b:o<b?o:b:h<o?h<b?h:b:o<b?o:b;c=g<i?g<n?g<c?g:c:n<c?n:c:i<n?i<c?i:c:n<c?n:c;d=f>h?f>o?f>d?f:d:o>d?o:d:h>o?h>d?h:d:o>d?o:d;e=g>i?g>n?g>e?g:e:n>e?n:e:i>n?i>e?i:e:n>e?n:e}a()};this.addRectangle=function(f){if(k){k=false;b=f.getLeft();c=f.getTop();d=f.getRight();e=f.getBottom()}else{b=b<f.getLeft()?b:f.getLeft();c=c<f.getTop()?c:f.getTop();
-d=d>f.getRight()?d:f.getRight();e=e>f.getBottom()?e:f.getBottom()}a()};this.inflate=function(f){b=b-f;c=c-f;d=d+f;e=e+f;a()};this.minSelf=function(f){b=b>f.getLeft()?b:f.getLeft();c=c>f.getTop()?c:f.getTop();d=d<f.getRight()?d:f.getRight();e=e<f.getBottom()?e:f.getBottom();a()};this.intersects=function(a){return d<a.getLeft()||b>a.getRight()||e<a.getTop()||c>a.getBottom()?false:true};this.empty=function(){k=true;e=d=c=b=0;a()};this.isEmpty=function(){return k}};
-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)},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 a<0?-1:a>0?1:0}};THREE.Matrix3=function(){this.elements=new Float32Array(9)};
-THREE.Matrix3.prototype={constructor:THREE.Matrix3,getInverse:function(a){var b=a.elements,a=b[10]*b[5]-b[6]*b[9],c=-b[10]*b[1]+b[2]*b[9],d=b[6]*b[1]-b[2]*b[5],e=-b[10]*b[4]+b[6]*b[8],f=b[10]*b[0]-b[2]*b[8],g=-b[6]*b[0]+b[2]*b[4],k=b[9]*b[4]-b[5]*b[8],m=-b[9]*b[0]+b[1]*b[8],j=b[5]*b[0]-b[1]*b[4],b=b[0]*a+b[1]*e+b[2]*k;b===0&&console.warn("Matrix3.getInverse(): determinant == 0");var b=1/b,h=this.elements;h[0]=b*a;h[1]=b*c;h[2]=b*d;h[3]=b*e;h[4]=b*f;h[5]=b*g;h[6]=b*k;h[7]=b*m;h[8]=b*j;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},transposeIntoArray:function(a){var b=this.m;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}};THREE.Matrix4=function(a,b,c,d,e,f,g,k,m,j,h,i,o,n,p,l){this.elements=new Float32Array(16);this.set(a!==void 0?a:1,b||0,c||0,d||0,e||0,f!==void 0?f:1,g||0,k||0,m||0,j||0,h!==void 0?h:1,i||0,o||0,n||0,p||0,l!==void 0?l:1)};
-THREE.Matrix4.prototype={constructor:THREE.Matrix4,set:function(a,b,c,d,e,f,g,k,m,j,h,i,o,n,p,l){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]=k;q[2]=m;q[6]=j;q[10]=h;q[14]=i;q[3]=o;q[7]=n;q[11]=p;q[15]=l;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},lookAt:function(a,b,c){var d=this.elements,
-e=THREE.Matrix4.__v1,f=THREE.Matrix4.__v2,g=THREE.Matrix4.__v3;g.sub(a,b).normalize();if(g.length()===0)g.z=1;e.cross(c,g).normalize();if(e.length()===0){g.x=g.x+1.0E-4;e.cross(c,g).normalize()}f.cross(g,e);d[0]=e.x;d[4]=f.x;d[8]=g.x;d[1]=e.y;d[5]=f.y;d[9]=g.y;d[2]=e.z;d[6]=f.z;d[10]=g.z;return this},multiply:function(a,b){var c=a.elements,d=b.elements,e=this.elements,f=c[0],g=c[4],k=c[8],m=c[12],j=c[1],h=c[5],i=c[9],o=c[13],n=c[2],p=c[6],l=c[10],q=c[14],u=c[3],s=c[7],z=c[11],c=c[15],A=d[0],v=d[4],
-D=d[8],x=d[12],G=d[1],t=d[5],y=d[9],C=d[13],L=d[2],Q=d[6],N=d[10],r=d[14],E=d[3],F=d[7],H=d[11],d=d[15];e[0]=f*A+g*G+k*L+m*E;e[4]=f*v+g*t+k*Q+m*F;e[8]=f*D+g*y+k*N+m*H;e[12]=f*x+g*C+k*r+m*d;e[1]=j*A+h*G+i*L+o*E;e[5]=j*v+h*t+i*Q+o*F;e[9]=j*D+h*y+i*N+o*H;e[13]=j*x+h*C+i*r+o*d;e[2]=n*A+p*G+l*L+q*E;e[6]=n*v+p*t+l*Q+q*F;e[10]=n*D+p*y+l*N+q*H;e[14]=n*x+p*C+l*r+q*d;e[3]=u*A+s*G+z*L+c*E;e[7]=u*v+s*t+z*Q+c*F;e[11]=u*D+s*y+z*N+c*H;e[15]=u*x+s*C+z*r+c*d;return this},multiplySelf:function(a){return this.multiply(this,
+normalize:function(){return this.divideScalar(this.length())},setLength:function(a){return this.normalize().multiplyScalar(a)},lerpSelf:function(a,b){this.x=this.x+(a.x-this.x)*b;this.y=this.y+(a.y-this.y)*b;this.z=this.z+(a.z-this.z)*b;this.w=this.w+(a.w-this.w)*b;return this},clone:function(){return new THREE.Vector4(this.x,this.y,this.z,this.w)},setAxisAngleFromQuaternion:function(a){this.w=2*Math.acos(a.w);var b=Math.sqrt(1-a.w*a.w);if(b<1.0E-4){this.x=1;this.z=this.y=0}else{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,f=a[0];d=a[4];var e=a[8],g=a[1],m=a[5],k=a[9];c=a[2];b=a[6];var l=a[10];if(Math.abs(d-g)<0.01&&Math.abs(e-c)<0.01&&Math.abs(k-b)<0.01){if(Math.abs(d+g)<0.1&&Math.abs(e+c)<0.1&&Math.abs(k+b)<0.1&&Math.abs(f+m+l-3)<0.1){this.set(1,0,0,0);return this}a=Math.PI;f=(f+1)/2;m=(m+1)/2;l=(l+1)/2;d=(d+g)/4;e=(e+c)/4;k=(k+b)/4;if(f>m&&f>l)if(f<0.01){b=0;d=c=0.707106781}else{b=Math.sqrt(f);c=d/b;d=e/b}else if(m>
+l)if(m<0.01){b=0.707106781;c=0;d=0.707106781}else{c=Math.sqrt(m);b=d/c;d=k/c}else if(l<0.01){c=b=0.707106781;d=0}else{d=Math.sqrt(l);b=e/d;c=k/d}this.set(b,c,d,a);return this}a=Math.sqrt((b-k)*(b-k)+(e-c)*(e-c)+(g-d)*(g-d));Math.abs(a)<0.001&&(a=1);this.x=(b-k)/a;this.y=(e-c)/a;this.z=(g-d)/a;this.w=Math.acos((f+m+l-1)/2);return this}};
+THREE.EventTarget=function(){var a={};this.addEventListener=function(b,c){a[b]===void 0&&(a[b]=[]);a[b].indexOf(c)===-1&&a[b].push(c)};this.dispatchEvent=function(b){for(var c in a[b.type])a[b.type][c](b)};this.removeEventListener=function(b,c){var d=a[b].indexOf(c);d!==-1&&a[b].splice(d,1)}};THREE.Frustum=function(){this.planes=[new THREE.Vector4,new THREE.Vector4,new THREE.Vector4,new THREE.Vector4,new THREE.Vector4,new THREE.Vector4]};
+THREE.Frustum.prototype.setFromMatrix=function(a){var b,c=this.planes,d=a.elements,a=d[0];b=d[1];var f=d[2],e=d[3],g=d[4],m=d[5],k=d[6],l=d[7],h=d[8],n=d[9],j=d[10],o=d[11],q=d[12],i=d[13],p=d[14],d=d[15];c[0].set(e-a,l-g,o-h,d-q);c[1].set(e+a,l+g,o+h,d+q);c[2].set(e+b,l+m,o+n,d+i);c[3].set(e-b,l-m,o-n,d-i);c[4].set(e-f,l-k,o-j,d-p);c[5].set(e+f,l+k,o+j,d+p);for(a=0;a<6;a++){b=c[a];b.divideScalar(Math.sqrt(b.x*b.x+b.y*b.y+b.z*b.z))}};
+THREE.Frustum.prototype.contains=function(a){for(var b=this.planes,c=a.matrixWorld,d=c.elements,c=-a.geometry.boundingSphere.radius*c.getMaxScaleOnAxis(),f=0;f<6;f++){a=b[f].x*d[12]+b[f].y*d[13]+b[f].z*d[14]+b[f].w;if(a<=c)return false}return true};THREE.Frustum.__v1=new THREE.Vector3;
+THREE.Ray=function(a,b,c,d){this.origin=a||new THREE.Vector3;this.direction=b||new THREE.Vector3;this.near=c||0;this.far=d||Infinity;var f=new THREE.Vector3,e=new THREE.Vector3,g=new THREE.Vector3,m=new THREE.Vector3,k=new THREE.Vector3,l=new THREE.Vector3,h=new THREE.Vector3,n=new THREE.Vector3,j=new THREE.Vector3,o=function(a,b){return a.distance-b.distance},q=new THREE.Vector3,i=new THREE.Vector3,p=new THREE.Vector3,r,s,v,A=function(a,b,c){q.sub(c,a);r=q.dot(b);s=i.add(a,p.copy(b).multiplyScalar(r));
+return v=c.distanceTo(s)},w,B,x,F,u,z,D,H,P=function(a,b,c,d){q.sub(d,b);i.sub(c,b);p.sub(a,b);w=q.dot(q);B=q.dot(i);x=q.dot(p);F=i.dot(i);u=i.dot(p);z=1/(w*F-B*B);D=(F*x-B*u)*z;H=(w*u-B*x)*z;return D>=0&&H>=0&&D+H<1},L=1.0E-4;this.setPrecision=function(a){L=a};this.intersectObject=function(a){var b,c=[];if(a instanceof THREE.Particle){v=A(this.origin,this.direction,a.matrixWorld.getPosition());if(v>a.scale.x)return[];b={distance:v,point:a.position,face:null,object:a};c.push(b)}else if(a instanceof
+THREE.Mesh){var d=THREE.Frustum.__v1.set(a.matrixWorld.getColumnX().length(),a.matrixWorld.getColumnY().length(),a.matrixWorld.getColumnZ().length()),d=a.geometry.boundingSphere.radius*Math.max(d.x,Math.max(d.y,d.z));v=A(this.origin,this.direction,a.matrixWorld.getPosition());if(v>d)return c;var i,q,y,S=a.geometry,p=S.vertices,r;a.matrixRotationWorld.extractRotation(a.matrixWorld);d=0;for(i=S.faces.length;d<i;d++){b=S.faces[d];k.copy(this.origin);l.copy(this.direction);r=a.matrixWorld;h=r.multiplyVector3(h.copy(b.centroid)).subSelf(k);
+n=a.matrixRotationWorld.multiplyVector3(n.copy(b.normal));q=l.dot(n);if(!(Math.abs(q)<L)){y=n.dot(h)/q;if(!(y<0)&&(a.doubleSided||(a.flipSided?q>0:q<0))){j.add(k,l.multiplyScalar(y));v=k.distanceTo(j);if(!(v<this.near)&&!(v>this.far))if(b instanceof THREE.Face3){f=r.multiplyVector3(f.copy(p[b.a]));e=r.multiplyVector3(e.copy(p[b.b]));g=r.multiplyVector3(g.copy(p[b.c]));if(P(j,f,e,g)){b={distance:v,point:j.clone(),face:b,object:a};c.push(b)}}else if(b instanceof THREE.Face4){f=r.multiplyVector3(f.copy(p[b.a]));
+e=r.multiplyVector3(e.copy(p[b.b]));g=r.multiplyVector3(g.copy(p[b.c]));m=r.multiplyVector3(m.copy(p[b.d]));if(P(j,f,e,m)||P(j,e,g,m)){b={distance:v,point:j.clone(),face:b,object:a};c.push(b)}}}}}}c.sort(o);return c};this.intersectObjects=function(a){for(var b=[],c=0,d=a.length;c<d;c++)Array.prototype.push.apply(b,this.intersectObject(a[c]));b.sort(o);return b}};
+THREE.Rectangle=function(){function a(){e=d-b;g=f-c}var b,c,d,f,e,g,m=true;this.getX=function(){return b};this.getY=function(){return c};this.getWidth=function(){return e};this.getHeight=function(){return g};this.getLeft=function(){return b};this.getTop=function(){return c};this.getRight=function(){return d};this.getBottom=function(){return f};this.set=function(e,g,h,n){m=false;b=e;c=g;d=h;f=n;a()};this.addPoint=function(e,g){if(m){m=false;b=e;c=g;d=e;f=g}else{b=b<e?b:e;c=c<g?c:g;d=d>e?d:e;f=f>g?
+f:g}a()};this.add3Points=function(e,g,h,n,j,o){if(m){m=false;b=e<h?e<j?e:j:h<j?h:j;c=g<n?g<o?g:o:n<o?n:o;d=e>h?e>j?e:j:h>j?h:j;f=g>n?g>o?g:o:n>o?n:o}else{b=e<h?e<j?e<b?e:b:j<b?j:b:h<j?h<b?h:b:j<b?j:b;c=g<n?g<o?g<c?g:c:o<c?o:c:n<o?n<c?n:c:o<c?o:c;d=e>h?e>j?e>d?e:d:j>d?j:d:h>j?h>d?h:d:j>d?j:d;f=g>n?g>o?g>f?g:f:o>f?o:f:n>o?n>f?n:f:o>f?o:f}a()};this.addRectangle=function(e){if(m){m=false;b=e.getLeft();c=e.getTop();d=e.getRight();f=e.getBottom()}else{b=b<e.getLeft()?b:e.getLeft();c=c<e.getTop()?c:e.getTop();
+d=d>e.getRight()?d:e.getRight();f=f>e.getBottom()?f:e.getBottom()}a()};this.inflate=function(e){b=b-e;c=c-e;d=d+e;f=f+e;a()};this.minSelf=function(e){b=b>e.getLeft()?b:e.getLeft();c=c>e.getTop()?c:e.getTop();d=d<e.getRight()?d:e.getRight();f=f<e.getBottom()?f:e.getBottom();a()};this.intersects=function(a){return d<a.getLeft()||b>a.getRight()||f<a.getTop()||c>a.getBottom()?false:true};this.empty=function(){m=true;f=d=c=b=0;a()};this.isEmpty=function(){return m}};
+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,f){return d+(a-b)*(f-d)/(c-b)},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 a<0?-1:a>0?1:0}};THREE.Matrix3=function(){this.elements=new Float32Array(9)};
+THREE.Matrix3.prototype={constructor:THREE.Matrix3,getInverse:function(a){var b=a.elements,a=b[10]*b[5]-b[6]*b[9],c=-b[10]*b[1]+b[2]*b[9],d=b[6]*b[1]-b[2]*b[5],f=-b[10]*b[4]+b[6]*b[8],e=b[10]*b[0]-b[2]*b[8],g=-b[6]*b[0]+b[2]*b[4],m=b[9]*b[4]-b[5]*b[8],k=-b[9]*b[0]+b[1]*b[8],l=b[5]*b[0]-b[1]*b[4],b=b[0]*a+b[1]*f+b[2]*m;b===0&&console.warn("Matrix3.getInverse(): determinant == 0");var b=1/b,h=this.elements;h[0]=b*a;h[1]=b*c;h[2]=b*d;h[3]=b*f;h[4]=b*e;h[5]=b*g;h[6]=b*m;h[7]=b*k;h[8]=b*l;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},transposeIntoArray:function(a){var b=this.m;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}};THREE.Matrix4=function(a,b,c,d,f,e,g,m,k,l,h,n,j,o,q,i){this.elements=new Float32Array(16);this.set(a!==void 0?a:1,b||0,c||0,d||0,f||0,e!==void 0?e:1,g||0,m||0,k||0,l||0,h!==void 0?h:1,n||0,j||0,o||0,q||0,i!==void 0?i:1)};
+THREE.Matrix4.prototype={constructor:THREE.Matrix4,set:function(a,b,c,d,f,e,g,m,k,l,h,n,j,o,q,i){var p=this.elements;p[0]=a;p[4]=b;p[8]=c;p[12]=d;p[1]=f;p[5]=e;p[9]=g;p[13]=m;p[2]=k;p[6]=l;p[10]=h;p[14]=n;p[3]=j;p[7]=o;p[11]=q;p[15]=i;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},lookAt:function(a,b,c){var d=this.elements,
+f=THREE.Matrix4.__v1,e=THREE.Matrix4.__v2,g=THREE.Matrix4.__v3;g.sub(a,b).normalize();if(g.length()===0)g.z=1;f.cross(c,g).normalize();if(f.length()===0){g.x=g.x+1.0E-4;f.cross(c,g).normalize()}e.cross(g,f);d[0]=f.x;d[4]=e.x;d[8]=g.x;d[1]=f.y;d[5]=e.y;d[9]=g.y;d[2]=f.z;d[6]=e.z;d[10]=g.z;return this},multiply:function(a,b){var c=a.elements,d=b.elements,f=this.elements,e=c[0],g=c[4],m=c[8],k=c[12],l=c[1],h=c[5],n=c[9],j=c[13],o=c[2],q=c[6],i=c[10],p=c[14],r=c[3],s=c[7],v=c[11],c=c[15],A=d[0],w=d[4],
+B=d[8],x=d[12],F=d[1],u=d[5],z=d[9],D=d[13],H=d[2],P=d[6],L=d[10],t=d[14],E=d[3],G=d[7],N=d[11],d=d[15];f[0]=e*A+g*F+m*H+k*E;f[4]=e*w+g*u+m*P+k*G;f[8]=e*B+g*z+m*L+k*N;f[12]=e*x+g*D+m*t+k*d;f[1]=l*A+h*F+n*H+j*E;f[5]=l*w+h*u+n*P+j*G;f[9]=l*B+h*z+n*L+j*N;f[13]=l*x+h*D+n*t+j*d;f[2]=o*A+q*F+i*H+p*E;f[6]=o*w+q*u+i*P+p*G;f[10]=o*B+q*z+i*L+p*N;f[14]=o*x+q*D+i*t+p*d;f[3]=r*A+s*F+v*H+c*E;f[7]=r*w+s*u+v*P+c*G;f[11]=r*B+s*z+v*L+c*N;f[15]=r*x+s*D+v*t+c*d;return this},multiplySelf:function(a){return this.multiply(this,
 a)},multiplyToArray:function(a,b,c){var d=this.elements;this.multiply(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]=b[0]*a;b[4]=b[4]*a;b[8]=b[8]*a;b[12]=b[12]*a;b[1]=b[1]*a;b[5]=b[5]*a;b[9]=b[9]*a;b[13]=b[13]*a;b[2]=b[2]*a;b[6]=b[6]*a;b[10]=b[10]*a;b[14]=b[14]*a;b[3]=b[3]*a;b[7]=b[7]*a;b[11]=b[11]*a;b[15]=
-b[15]*a;return this},multiplyVector3:function(a){var b=this.elements,c=a.x,d=a.y,e=a.z,f=1/(b[3]*c+b[7]*d+b[11]*e+b[15]);a.x=(b[0]*c+b[4]*d+b[8]*e+b[12])*f;a.y=(b[1]*c+b[5]*d+b[9]*e+b[13])*f;a.z=(b[2]*c+b[6]*d+b[10]*e+b[14])*f;return a},multiplyVector4:function(a){var b=this.elements,c=a.x,d=a.y,e=a.z,f=a.w;a.x=b[0]*c+b[4]*d+b[8]*e+b[12]*f;a.y=b[1]*c+b[5]*d+b[9]*e+b[13]*f;a.z=b[2]*c+b[6]*d+b[10]*e+b[14]*f;a.w=b[3]*c+b[7]*d+b[11]*e+b[15]*f;return a},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],k=a[9],m=a[13],j=a[2],h=a[6],i=a[10],o=a[14],n=a[3],p=a[7],
-l=a[11],a=a[15];return e*k*h*n-d*m*h*n-e*g*i*n+c*m*i*n+d*g*o*n-c*k*o*n-e*k*j*p+d*m*j*p+e*f*i*p-b*m*i*p-d*f*o*p+b*k*o*p+e*g*j*l-c*m*j*l-e*f*h*l+b*m*h*l+c*f*o*l-b*g*o*l-d*g*j*a+c*k*j*a+d*f*h*a-b*k*h*a-c*f*i*a+b*g*i*a},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];
+b[15]*a;return this},multiplyVector3:function(a){var b=this.elements,c=a.x,d=a.y,f=a.z,e=1/(b[3]*c+b[7]*d+b[11]*f+b[15]);a.x=(b[0]*c+b[4]*d+b[8]*f+b[12])*e;a.y=(b[1]*c+b[5]*d+b[9]*f+b[13])*e;a.z=(b[2]*c+b[6]*d+b[10]*f+b[14])*e;return a},multiplyVector4:function(a){var b=this.elements,c=a.x,d=a.y,f=a.z,e=a.w;a.x=b[0]*c+b[4]*d+b[8]*f+b[12]*e;a.y=b[1]*c+b[5]*d+b[9]*f+b[13]*e;a.z=b[2]*c+b[6]*d+b[10]*f+b[14]*e;a.w=b[3]*c+b[7]*d+b[11]*f+b[15]*e;return a},rotateAxis:function(a){var b=this.elements,c=a.x,
+d=a.y,f=a.z;a.x=c*b[0]+d*b[4]+f*b[8];a.y=c*b[1]+d*b[5]+f*b[9];a.z=c*b[2]+d*b[6]+f*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],f=a[12],e=a[1],g=a[5],m=a[9],k=a[13],l=a[2],h=a[6],n=a[10],j=a[14],o=a[3],q=a[7],
+i=a[11],a=a[15];return f*m*h*o-d*k*h*o-f*g*n*o+c*k*n*o+d*g*j*o-c*m*j*o-f*m*l*q+d*k*l*q+f*e*n*q-b*k*n*q-d*e*j*q+b*m*j*q+f*g*l*i-c*k*l*i-f*e*h*i+b*k*h*i+c*e*j*i-b*g*j*i-d*g*l*a+c*m*l*a+d*e*h*a-b*m*h*a-c*e*n*a+b*g*n*a},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=this.elements;return THREE.Matrix4.__v1.set(a[12],a[13],
-a[14])},setPosition:function(a){var b=this.elements;b[12]=a.x;b[13]=a.y;b[14]=a.z;return this},getColumnX:function(){var a=this.elements;return THREE.Matrix4.__v1.set(a[0],a[1],a[2])},getColumnY:function(){var a=this.elements;return THREE.Matrix4.__v1.set(a[4],a[5],a[6])},getColumnZ:function(){var a=this.elements;return THREE.Matrix4.__v1.set(a[8],a[9],a[10])},getInverse:function(a){var b=this.elements,c=a.elements,d=c[0],e=c[4],f=c[8],g=c[12],k=c[1],m=c[5],j=c[9],h=c[13],i=c[2],o=c[6],n=c[10],p=
-c[14],l=c[3],q=c[7],u=c[11],c=c[15];b[0]=j*p*q-h*n*q+h*o*u-m*p*u-j*o*c+m*n*c;b[4]=g*n*q-f*p*q-g*o*u+e*p*u+f*o*c-e*n*c;b[8]=f*h*q-g*j*q+g*m*u-e*h*u-f*m*c+e*j*c;b[12]=g*j*o-f*h*o-g*m*n+e*h*n+f*m*p-e*j*p;b[1]=h*n*l-j*p*l-h*i*u+k*p*u+j*i*c-k*n*c;b[5]=f*p*l-g*n*l+g*i*u-d*p*u-f*i*c+d*n*c;b[9]=g*j*l-f*h*l-g*k*u+d*h*u+f*k*c-d*j*c;b[13]=f*h*i-g*j*i+g*k*n-d*h*n-f*k*p+d*j*p;b[2]=m*p*l-h*o*l+h*i*q-k*p*q-m*i*c+k*o*c;b[6]=g*o*l-e*p*l-g*i*q+d*p*q+e*i*c-d*o*c;b[10]=e*h*l-g*m*l+g*k*q-d*h*q-e*k*c+d*m*c;b[14]=g*m*i-
-e*h*i-g*k*o+d*h*o+e*k*p-d*m*p;b[3]=j*o*l-m*n*l-j*i*q+k*n*q+m*i*u-k*o*u;b[7]=e*n*l-f*o*l+f*i*q-d*n*q-e*i*u+d*o*u;b[11]=f*m*l-e*j*l-f*k*q+d*j*q+e*k*u-d*m*u;b[15]=e*j*i-f*m*i+f*k*o-d*j*o-e*k*n+d*m*n;this.multiplyScalar(1/a.determinant());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),k=Math.cos(e),e=Math.sin(e),m=Math.cos(f),f=Math.sin(f);switch(b){case "YXZ":var j=k*m,h=k*f,i=e*m,o=e*f;c[0]=j+o*d;c[4]=i*d-h;c[8]=g*e;c[1]=g*f;c[5]=g*
-m;c[9]=-d;c[2]=h*d-i;c[6]=o+j*d;c[10]=g*k;break;case "ZXY":j=k*m;h=k*f;i=e*m;o=e*f;c[0]=j-o*d;c[4]=-g*f;c[8]=i+h*d;c[1]=h+i*d;c[5]=g*m;c[9]=o-j*d;c[2]=-g*e;c[6]=d;c[10]=g*k;break;case "ZYX":j=g*m;h=g*f;i=d*m;o=d*f;c[0]=k*m;c[4]=i*e-h;c[8]=j*e+o;c[1]=k*f;c[5]=o*e+j;c[9]=h*e-i;c[2]=-e;c[6]=d*k;c[10]=g*k;break;case "YZX":j=g*k;h=g*e;i=d*k;o=d*e;c[0]=k*m;c[4]=o-j*f;c[8]=i*f+h;c[1]=f;c[5]=g*m;c[9]=-d*m;c[2]=-e*m;c[6]=h*f+i;c[10]=j-o*f;break;case "XZY":j=g*k;h=g*e;i=d*k;o=d*e;c[0]=k*m;c[4]=-f;c[8]=e*m;
-c[1]=j*f+o;c[5]=g*m;c[9]=h*f-i;c[2]=i*f-h;c[6]=d*m;c[10]=o*f+j;break;default:j=g*m;h=g*f;i=d*m;o=d*f;c[0]=k*m;c[4]=-k*f;c[8]=e;c[1]=h+i*e;c[5]=j-o*e;c[9]=-d*k;c[2]=o-j*e;c[6]=i+h*e;c[10]=g*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,k=d+d,m=e+e,a=c*g,j=c*k,c=c*m,h=d*k,d=d*m,e=e*m,g=f*g,k=f*k,f=f*m;b[0]=1-(h+e);b[4]=j-f;b[8]=c+k;b[1]=j+f;b[5]=1-(a+e);b[9]=d-g;b[2]=c-k;b[6]=d+g;b[10]=1-(a+h);return this},compose:function(a,b,c){var d=this.elements,
-e=THREE.Matrix4.__m1,f=THREE.Matrix4.__m2;e.identity();e.setRotationFromQuaternion(b);f.makeScale(c.x,c.y,c.z);this.multiply(e,f);d[12]=a.x;d[13]=a.y;d[14]=a.z;return this},decompose:function(a,b,c){var d=this.elements,e=THREE.Matrix4.__v1,f=THREE.Matrix4.__v2,g=THREE.Matrix4.__v3;e.set(d[0],d[1],d[2]);f.set(d[4],d[5],d[6]);g.set(d[8],d[9],d[10]);a=a instanceof THREE.Vector3?a:new THREE.Vector3;b=b instanceof THREE.Quaternion?b:new THREE.Quaternion;c=c instanceof THREE.Vector3?c:new THREE.Vector3;
-c.x=e.length();c.y=f.length();c.z=g.length();a.x=d[12];a.y=d[13];a.z=d[14];d=THREE.Matrix4.__m1;d.copy(this);d.elements[0]=d.elements[0]/c.x;d.elements[1]=d.elements[1]/c.x;d.elements[2]=d.elements[2]/c.x;d.elements[4]=d.elements[4]/c.y;d.elements[5]=d.elements[5]/c.y;d.elements[6]=d.elements[6]/c.y;d.elements[8]=d.elements[8]/c.z;d.elements[9]=d.elements[9]/c.z;d.elements[10]=d.elements[10]/c.z;b.setFromRotationMatrix(d);return[a,b,c]},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(a){var b=this.elements,a=a.elements,c=THREE.Matrix4.__v1,d=1/c.set(a[0],a[1],a[2]).length(),e=1/c.set(a[4],a[5],a[6]).length(),c=1/c.set(a[8],a[9],a[10]).length();b[0]=a[0]*d;b[1]=a[1]*d;b[2]=a[2]*d;b[4]=a[4]*e;b[5]=a[5]*e;b[6]=a[6]*e;b[8]=a[8]*c;b[9]=a[9]*c;b[10]=a[10]*c;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],k=b[9],m=b[10],j=b[11],h=Math.cos(a),a=Math.sin(a);b[4]=h*c+a*g;b[5]=h*d+a*k;b[6]=h*e+a*m;b[7]=h*f+a*j;b[8]=h*g-a*c;b[9]=h*k-a*d;b[10]=h*m-a*e;b[11]=h*j-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],k=b[9],m=b[10],j=b[11],h=Math.cos(a),a=Math.sin(a);b[0]=h*c-a*g;b[1]=h*d-a*k;b[2]=h*e-a*m;b[3]=h*f-a*j;b[8]=h*g+a*c;b[9]=
-h*k+a*d;b[10]=h*m+a*e;b[11]=h*j+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],k=b[5],m=b[6],j=b[7],h=Math.cos(a),a=Math.sin(a);b[0]=h*c+a*g;b[1]=h*d+a*k;b[2]=h*e+a*m;b[3]=h*f+a*j;b[4]=h*g-a*c;b[5]=h*k-a*d;b[6]=h*m-a*e;b[7]=h*j-a*f;return this},rotateByAxis:function(a,b){var c=this.elements;if(a.x===1&&a.y===0&&a.z===0)return this.rotateX(b);if(a.x===0&&a.y===1&&a.z===0)return this.rotateY(b);if(a.x===0&&a.y===0&&a.z===1)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,k=e*e,m=f*f,j=Math.cos(b),h=Math.sin(b),i=1-j,o=d*e*i,n=d*f*i,i=e*f*i,d=d*h,p=e*h,h=f*h,f=g+(1-g)*j,g=o+h,e=n-p,o=o-h,k=k+(1-k)*j,h=i+d,n=n+p,i=i-d,m=m+(1-m)*j,j=c[0],d=c[1],p=c[2],l=c[3],q=c[4],u=c[5],s=c[6],z=c[7],A=c[8],v=c[9],D=c[10],x=c[11];c[0]=f*j+g*q+e*A;c[1]=f*d+g*u+e*v;c[2]=f*p+g*s+e*D;c[3]=f*l+g*z+e*x;c[4]=o*j+k*q+h*A;c[5]=o*d+k*u+h*v;c[6]=o*p+k*s+h*D;c[7]=o*l+k*z+h*x;c[8]=n*j+i*q+m*A;c[9]=n*d+i*u+m*v;c[10]=n*p+i*s+m*D;c[11]=
-n*l+i*z+m*x;return this},scale:function(a){var b=this.elements,c=a.x,d=a.y,a=a.z;b[0]=b[0]*c;b[4]=b[4]*d;b[8]=b[8]*a;b[1]=b[1]*c;b[5]=b[5]*d;b[9]=b[9]*a;b[2]=b[2]*c;b[6]=b[6]*d;b[10]=b[10]*a;b[3]=b[3]*c;b[7]=b[7]*d;b[11]=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,k=a.z,m=e*f,j=e*g;this.set(m*f+c,m*g-d*k,m*k+d*g,0,m*g+d*k,j*g+c,j*k-d*f,0,m*k-
-d*g,j*k+d*f,e*k*k+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(a*Math.PI/360),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,k=b-a,m=c-d,j=f-e;g[0]=2/k;g[4]=0;g[8]=0;g[12]=-((b+a)/k);g[1]=0;g[5]=2/m;g[9]=0;g[13]=-((c+d)/m);g[2]=0;g[6]=0;g[10]=-2/j;g[14]=-((f+e)/j);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.Matrix4.__v1=new THREE.Vector3;THREE.Matrix4.__v2=new THREE.Vector3;THREE.Matrix4.__v3=new THREE.Vector3;THREE.Matrix4.__m1=new THREE.Matrix4;
+a[14])},setPosition:function(a){var b=this.elements;b[12]=a.x;b[13]=a.y;b[14]=a.z;return this},getColumnX:function(){var a=this.elements;return THREE.Matrix4.__v1.set(a[0],a[1],a[2])},getColumnY:function(){var a=this.elements;return THREE.Matrix4.__v1.set(a[4],a[5],a[6])},getColumnZ:function(){var a=this.elements;return THREE.Matrix4.__v1.set(a[8],a[9],a[10])},getInverse:function(a){var b=this.elements,c=a.elements,d=c[0],f=c[4],e=c[8],g=c[12],m=c[1],k=c[5],l=c[9],h=c[13],n=c[2],j=c[6],o=c[10],q=
+c[14],i=c[3],p=c[7],r=c[11],c=c[15];b[0]=l*q*p-h*o*p+h*j*r-k*q*r-l*j*c+k*o*c;b[4]=g*o*p-e*q*p-g*j*r+f*q*r+e*j*c-f*o*c;b[8]=e*h*p-g*l*p+g*k*r-f*h*r-e*k*c+f*l*c;b[12]=g*l*j-e*h*j-g*k*o+f*h*o+e*k*q-f*l*q;b[1]=h*o*i-l*q*i-h*n*r+m*q*r+l*n*c-m*o*c;b[5]=e*q*i-g*o*i+g*n*r-d*q*r-e*n*c+d*o*c;b[9]=g*l*i-e*h*i-g*m*r+d*h*r+e*m*c-d*l*c;b[13]=e*h*n-g*l*n+g*m*o-d*h*o-e*m*q+d*l*q;b[2]=k*q*i-h*j*i+h*n*p-m*q*p-k*n*c+m*j*c;b[6]=g*j*i-f*q*i-g*n*p+d*q*p+f*n*c-d*j*c;b[10]=f*h*i-g*k*i+g*m*p-d*h*p-f*m*c+d*k*c;b[14]=g*k*n-
+f*h*n-g*m*j+d*h*j+f*m*q-d*k*q;b[3]=l*j*i-k*o*i-l*n*p+m*o*p+k*n*r-m*j*r;b[7]=f*o*i-e*j*i+e*n*p-d*o*p-f*n*r+d*j*r;b[11]=e*k*i-f*l*i-e*m*p+d*l*p+f*m*r-d*k*r;b[15]=f*l*n-e*k*n+e*m*j-d*l*j-f*m*o+d*k*o;this.multiplyScalar(1/a.determinant());return this},setRotationFromEuler:function(a,b){var c=this.elements,d=a.x,f=a.y,e=a.z,g=Math.cos(d),d=Math.sin(d),m=Math.cos(f),f=Math.sin(f),k=Math.cos(e),e=Math.sin(e);switch(b){case "YXZ":var l=m*k,h=m*e,n=f*k,j=f*e;c[0]=l+j*d;c[4]=n*d-h;c[8]=g*f;c[1]=g*e;c[5]=g*
+k;c[9]=-d;c[2]=h*d-n;c[6]=j+l*d;c[10]=g*m;break;case "ZXY":l=m*k;h=m*e;n=f*k;j=f*e;c[0]=l-j*d;c[4]=-g*e;c[8]=n+h*d;c[1]=h+n*d;c[5]=g*k;c[9]=j-l*d;c[2]=-g*f;c[6]=d;c[10]=g*m;break;case "ZYX":l=g*k;h=g*e;n=d*k;j=d*e;c[0]=m*k;c[4]=n*f-h;c[8]=l*f+j;c[1]=m*e;c[5]=j*f+l;c[9]=h*f-n;c[2]=-f;c[6]=d*m;c[10]=g*m;break;case "YZX":l=g*m;h=g*f;n=d*m;j=d*f;c[0]=m*k;c[4]=j-l*e;c[8]=n*e+h;c[1]=e;c[5]=g*k;c[9]=-d*k;c[2]=-f*k;c[6]=h*e+n;c[10]=l-j*e;break;case "XZY":l=g*m;h=g*f;n=d*m;j=d*f;c[0]=m*k;c[4]=-e;c[8]=f*k;
+c[1]=l*e+j;c[5]=g*k;c[9]=h*e-n;c[2]=n*e-h;c[6]=d*k;c[10]=j*e+l;break;default:l=g*k;h=g*e;n=d*k;j=d*e;c[0]=m*k;c[4]=-m*e;c[8]=f;c[1]=h+n*f;c[5]=l-j*f;c[9]=-d*m;c[2]=j-l*f;c[6]=n+h*f;c[10]=g*m}return this},setRotationFromQuaternion:function(a){var b=this.elements,c=a.x,d=a.y,f=a.z,e=a.w,g=c+c,m=d+d,k=f+f,a=c*g,l=c*m,c=c*k,h=d*m,d=d*k,f=f*k,g=e*g,m=e*m,e=e*k;b[0]=1-(h+f);b[4]=l-e;b[8]=c+m;b[1]=l+e;b[5]=1-(a+f);b[9]=d-g;b[2]=c-m;b[6]=d+g;b[10]=1-(a+h);return this},compose:function(a,b,c){var d=this.elements,
+f=THREE.Matrix4.__m1,e=THREE.Matrix4.__m2;f.identity();f.setRotationFromQuaternion(b);e.makeScale(c.x,c.y,c.z);this.multiply(f,e);d[12]=a.x;d[13]=a.y;d[14]=a.z;return this},decompose:function(a,b,c){var d=this.elements,f=THREE.Matrix4.__v1,e=THREE.Matrix4.__v2,g=THREE.Matrix4.__v3;f.set(d[0],d[1],d[2]);e.set(d[4],d[5],d[6]);g.set(d[8],d[9],d[10]);a=a instanceof THREE.Vector3?a:new THREE.Vector3;b=b instanceof THREE.Quaternion?b:new THREE.Quaternion;c=c instanceof THREE.Vector3?c:new THREE.Vector3;
+c.x=f.length();c.y=e.length();c.z=g.length();a.x=d[12];a.y=d[13];a.z=d[14];d=THREE.Matrix4.__m1;d.copy(this);d.elements[0]=d.elements[0]/c.x;d.elements[1]=d.elements[1]/c.x;d.elements[2]=d.elements[2]/c.x;d.elements[4]=d.elements[4]/c.y;d.elements[5]=d.elements[5]/c.y;d.elements[6]=d.elements[6]/c.y;d.elements[8]=d.elements[8]/c.z;d.elements[9]=d.elements[9]/c.z;d.elements[10]=d.elements[10]/c.z;b.setFromRotationMatrix(d);return[a,b,c]},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(a){var b=this.elements,a=a.elements,c=THREE.Matrix4.__v1,d=1/c.set(a[0],a[1],a[2]).length(),f=1/c.set(a[4],a[5],a[6]).length(),c=1/c.set(a[8],a[9],a[10]).length();b[0]=a[0]*d;b[1]=a[1]*d;b[2]=a[2]*d;b[4]=a[4]*f;b[5]=a[5]*f;b[6]=a[6]*f;b[8]=a[8]*c;b[9]=a[9]*c;b[10]=a[10]*c;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],f=b[6],e=b[7],g=b[8],m=b[9],k=b[10],l=b[11],h=Math.cos(a),a=Math.sin(a);b[4]=h*c+a*g;b[5]=h*d+a*m;b[6]=h*f+a*k;b[7]=h*e+a*l;b[8]=h*g-a*c;b[9]=h*m-a*d;b[10]=h*k-a*f;b[11]=h*l-a*e;return this},rotateY:function(a){var b=this.elements,c=b[0],d=b[1],f=b[2],e=b[3],g=b[8],m=b[9],k=b[10],l=b[11],h=Math.cos(a),a=Math.sin(a);b[0]=h*c-a*g;b[1]=h*d-a*m;b[2]=h*f-a*k;b[3]=h*e-a*l;b[8]=h*g+a*c;b[9]=
+h*m+a*d;b[10]=h*k+a*f;b[11]=h*l+a*e;return this},rotateZ:function(a){var b=this.elements,c=b[0],d=b[1],f=b[2],e=b[3],g=b[4],m=b[5],k=b[6],l=b[7],h=Math.cos(a),a=Math.sin(a);b[0]=h*c+a*g;b[1]=h*d+a*m;b[2]=h*f+a*k;b[3]=h*e+a*l;b[4]=h*g-a*c;b[5]=h*m-a*d;b[6]=h*k-a*f;b[7]=h*l-a*e;return this},rotateByAxis:function(a,b){var c=this.elements;if(a.x===1&&a.y===0&&a.z===0)return this.rotateX(b);if(a.x===0&&a.y===1&&a.z===0)return this.rotateY(b);if(a.x===0&&a.y===0&&a.z===1)return this.rotateZ(b);var d=a.x,
+f=a.y,e=a.z,g=Math.sqrt(d*d+f*f+e*e),d=d/g,f=f/g,e=e/g,g=d*d,m=f*f,k=e*e,l=Math.cos(b),h=Math.sin(b),n=1-l,j=d*f*n,o=d*e*n,n=f*e*n,d=d*h,q=f*h,h=e*h,e=g+(1-g)*l,g=j+h,f=o-q,j=j-h,m=m+(1-m)*l,h=n+d,o=o+q,n=n-d,k=k+(1-k)*l,l=c[0],d=c[1],q=c[2],i=c[3],p=c[4],r=c[5],s=c[6],v=c[7],A=c[8],w=c[9],B=c[10],x=c[11];c[0]=e*l+g*p+f*A;c[1]=e*d+g*r+f*w;c[2]=e*q+g*s+f*B;c[3]=e*i+g*v+f*x;c[4]=j*l+m*p+h*A;c[5]=j*d+m*r+h*w;c[6]=j*q+m*s+h*B;c[7]=j*i+m*v+h*x;c[8]=o*l+n*p+k*A;c[9]=o*d+n*r+k*w;c[10]=o*q+n*s+k*B;c[11]=
+o*i+n*v+k*x;return this},scale:function(a){var b=this.elements,c=a.x,d=a.y,a=a.z;b[0]=b[0]*c;b[4]=b[4]*d;b[8]=b[8]*a;b[1]=b[1]*c;b[5]=b[5]*d;b[9]=b[9]*a;b[2]=b[2]*c;b[6]=b[6]*d;b[10]=b[10]*a;b[3]=b[3]*c;b[7]=b[7]*d;b[11]=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),f=1-c,e=a.x,g=a.y,m=a.z,k=f*e,l=f*g;this.set(k*e+c,k*g-d*m,k*m+d*g,0,k*g+d*m,l*g+c,l*m-d*e,0,k*m-
+d*g,l*m+d*e,f*m*m+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,f,e){var g=this.elements;g[0]=2*f/(b-a);g[4]=0;g[8]=(b+a)/(b-a);g[12]=0;g[1]=0;g[5]=2*f/(d-c);g[9]=(d+c)/(d-c);g[13]=0;g[2]=0;g[6]=0;g[10]=-(e+f)/(e-f);g[14]=-2*e*f/(e-f);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(a*Math.PI/360),f=-a;return this.makeFrustum(f*b,a*b,f,a,c,d)},makeOrthographic:function(a,
+b,c,d,f,e){var g=this.elements,m=b-a,k=c-d,l=e-f;g[0]=2/m;g[4]=0;g[8]=0;g[12]=-((b+a)/m);g[1]=0;g[5]=2/k;g[9]=0;g[13]=-((c+d)/k);g[2]=0;g[6]=0;g[10]=-2/l;g[14]=-((e+f)/l);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.Matrix4.__v1=new THREE.Vector3;THREE.Matrix4.__v2=new THREE.Vector3;THREE.Matrix4.__v3=new THREE.Vector3;THREE.Matrix4.__m1=new THREE.Matrix4;
 THREE.Matrix4.__m2=new THREE.Matrix4;
 THREE.Object3D=function(){this.id=THREE.Object3DCount++;this.name="";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="XYZ";this.scale=new THREE.Vector3(1,1,1);this.flipSided=this.doubleSided=false;this.renderDepth=null;this.rotationAutoUpdate=true;this.matrix=new THREE.Matrix4;this.matrixWorld=new THREE.Matrix4;this.matrixRotationWorld=new THREE.Matrix4;this.matrixWorldNeedsUpdate=this.matrixAutoUpdate=
 true;this.quaternion=new THREE.Quaternion;this.useQuaternion=false;this.boundRadius=0;this.boundRadiusScale=1;this.visible=true;this.receiveShadow=this.castShadow=false;this.frustumCulled=true;this._vector=new THREE.Vector3};
-THREE.Object3D.prototype={constructor:THREE.Object3D,applyMatrix:function(a){this.matrix.multiply(a,this.matrix);this.scale.getScaleFromMatrix(this.matrix);this.rotation.getRotationFromMatrix(this.matrix,this.scale);this.position.getPositionFromMatrix(this.matrix)},translate:function(a,b){this.matrix.rotateAxis(b);this.position.addSelf(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))},lookAt:function(a){this.matrix.lookAt(a,this.position,this.up);this.rotationAutoUpdate&&this.rotation.getRotationFromMatrix(this.matrix)},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){a.parent!==void 0&&a.parent.remove(a);a.parent=this;this.children.push(a);for(var b=this;b.parent!==void 0;)b=b.parent;b!==void 0&&b instanceof THREE.Scene&&b.__addObject(a)}},remove:function(a){var b=
-this.children.indexOf(a);if(b!==-1){a.parent=void 0;this.children.splice(b,1);for(b=this;b.parent!==void 0;)b=b.parent;b!==void 0&&b instanceof THREE.Scene&&b.__removeObject(a)}},getChildByName:function(a,b){var c,d,e;c=0;for(d=this.children.length;c<d;c++){e=this.children[c];if(e.name===a)return e;if(b){e=e.getChildByName(a,b);if(e!==void 0)return e}}},updateMatrix:function(){this.matrix.setPosition(this.position);this.useQuaternion?this.matrix.setRotationFromQuaternion(this.quaternion):this.matrix.setRotationFromEuler(this.rotation,
-this.eulerOrder);if(this.scale.x!==1||this.scale.y!==1||this.scale.z!==1){this.matrix.scale(this.scale);this.boundRadiusScale=Math.max(this.scale.x,Math.max(this.scale.y,this.scale.z))}this.matrixWorldNeedsUpdate=true},updateMatrixWorld:function(a){this.matrixAutoUpdate&&this.updateMatrix();if(this.matrixWorldNeedsUpdate||a){this.parent?this.matrixWorld.multiply(this.parent.matrixWorld,this.matrix):this.matrixWorld.copy(this.matrix);this.matrixWorldNeedsUpdate=false;a=true}for(var b=0,c=this.children.length;b<
-c;b++)this.children[b].updateMatrixWorld(a)}};THREE.Object3DCount=0;
-THREE.Projector=function(){function a(){var a=g[f]=g[f]||new THREE.RenderableObject;f++;return a}function b(){var a=j[m]=j[m]||new THREE.RenderableVertex;m++;return a}function c(a,b){return b.z-a.z}function d(a,b){var c=0,d=1,f=a.z+a.w,e=b.z+b.w,g=-a.z+a.w,h=-b.z+b.w;if(f>=0&&e>=0&&g>=0&&h>=0)return true;if(f<0&&e<0||g<0&&h<0)return false;f<0?c=Math.max(c,f/(f-e)):e<0&&(d=Math.min(d,f/(f-e)));g<0?c=Math.max(c,g/(g-h)):h<0&&(d=Math.min(d,g/(g-h)));if(d<c)return false;a.lerpSelf(b,c);b.lerpSelf(a,1-
-d);return true}var e,f,g=[],k,m,j=[],h,i,o=[],n,p=[],l,q,u=[],s,z,A=[],v={objects:[],sprites:[],lights:[],elements:[]},D=new THREE.Vector3,x=new THREE.Vector4,G=new THREE.Matrix4,t=new THREE.Matrix4,y=new THREE.Frustum,C=new THREE.Vector4,L=new THREE.Vector4;this.projectVector=function(a,b){b.matrixWorldInverse.getInverse(b.matrixWorld);G.multiply(b.projectionMatrix,b.matrixWorldInverse);G.multiplyVector3(a);return a};this.unprojectVector=function(a,b){b.projectionMatrixInverse.getInverse(b.projectionMatrix);
-G.multiply(b.matrixWorld,b.projectionMatrixInverse);G.multiplyVector3(a);return a};this.pickingRay=function(a,b){var c;a.z=-1;c=new THREE.Vector3(a.x,a.y,1);this.unprojectVector(a,b);this.unprojectVector(c,b);c.subSelf(a).normalize();return new THREE.Ray(a,c)};this.projectGraph=function(b,d){f=0;v.objects.length=0;v.sprites.length=0;v.lights.length=0;var g=function(b){if(b.visible!==false){if((b instanceof THREE.Mesh||b instanceof THREE.Line)&&(b.frustumCulled===false||y.contains(b))){D.copy(b.matrixWorld.getPosition());
-G.multiplyVector3(D);e=a();e.object=b;e.z=D.z;v.objects.push(e)}else if(b instanceof THREE.Sprite||b instanceof THREE.Particle){D.copy(b.matrixWorld.getPosition());G.multiplyVector3(D);e=a();e.object=b;e.z=D.z;v.sprites.push(e)}else b instanceof THREE.Light&&v.lights.push(b);for(var c=0,d=b.children.length;c<d;c++)g(b.children[c])}};g(b);d&&v.objects.sort(c);return v};this.projectScene=function(a,f,e){var g=f.near,D=f.far,H=false,P,O,w,U,M,T,S,W,B,J,I,K,R,ja,da;z=q=n=i=0;v.elements.length=0;if(f.parent===
-void 0){console.warn("DEPRECATED: Camera hasn't been added to a Scene. Adding it...");a.add(f)}a.updateMatrixWorld();f.matrixWorldInverse.getInverse(f.matrixWorld);G.multiply(f.projectionMatrix,f.matrixWorldInverse);y.setFromMatrix(G);v=this.projectGraph(a,false);a=0;for(P=v.objects.length;a<P;a++){B=v.objects[a].object;J=B.matrixWorld;m=0;if(B instanceof THREE.Mesh){I=B.geometry;K=B.geometry.materials;U=I.vertices;R=I.faces;ja=I.faceVertexUvs;I=B.matrixRotationWorld.extractRotation(J);O=0;for(w=
-U.length;O<w;O++){k=b();k.positionWorld.copy(U[O]);J.multiplyVector3(k.positionWorld);k.positionScreen.copy(k.positionWorld);G.multiplyVector4(k.positionScreen);k.positionScreen.x=k.positionScreen.x/k.positionScreen.w;k.positionScreen.y=k.positionScreen.y/k.positionScreen.w;k.visible=k.positionScreen.z>g&&k.positionScreen.z<D}U=0;for(O=R.length;U<O;U++){w=R[U];if(w instanceof THREE.Face3){M=j[w.a];T=j[w.b];S=j[w.c];if(M.visible&&T.visible&&S.visible){H=(S.positionScreen.x-M.positionScreen.x)*(T.positionScreen.y-
-M.positionScreen.y)-(S.positionScreen.y-M.positionScreen.y)*(T.positionScreen.x-M.positionScreen.x)<0;if(B.doubleSided||H!=B.flipSided){W=o[i]=o[i]||new THREE.RenderableFace3;i++;h=W;h.v1.copy(M);h.v2.copy(T);h.v3.copy(S)}else continue}else continue}else if(w instanceof THREE.Face4){M=j[w.a];T=j[w.b];S=j[w.c];W=j[w.d];if(M.visible&&T.visible&&S.visible&&W.visible){H=(W.positionScreen.x-M.positionScreen.x)*(T.positionScreen.y-M.positionScreen.y)-(W.positionScreen.y-M.positionScreen.y)*(T.positionScreen.x-
-M.positionScreen.x)<0||(T.positionScreen.x-S.positionScreen.x)*(W.positionScreen.y-S.positionScreen.y)-(T.positionScreen.y-S.positionScreen.y)*(W.positionScreen.x-S.positionScreen.x)<0;if(B.doubleSided||H!=B.flipSided){da=p[n]=p[n]||new THREE.RenderableFace4;n++;h=da;h.v1.copy(M);h.v2.copy(T);h.v3.copy(S);h.v4.copy(W)}else continue}else continue}h.normalWorld.copy(w.normal);!H&&(B.flipSided||B.doubleSided)&&h.normalWorld.negate();I.multiplyVector3(h.normalWorld);h.centroidWorld.copy(w.centroid);J.multiplyVector3(h.centroidWorld);
-h.centroidScreen.copy(h.centroidWorld);G.multiplyVector3(h.centroidScreen);S=w.vertexNormals;M=0;for(T=S.length;M<T;M++){W=h.vertexNormalsWorld[M];W.copy(S[M]);!H&&(B.flipSided||B.doubleSided)&&W.negate();I.multiplyVector3(W)}M=0;for(T=ja.length;M<T;M++)if(da=ja[M][U]){S=0;for(W=da.length;S<W;S++)h.uvs[M][S]=da[S]}h.material=B.material;h.faceMaterial=w.materialIndex!==null?K[w.materialIndex]:null;h.z=h.centroidScreen.z;v.elements.push(h)}}else if(B instanceof THREE.Line){t.multiply(G,J);U=B.geometry.vertices;
-M=b();M.positionScreen.copy(U[0]);t.multiplyVector4(M.positionScreen);J=B.type===THREE.LinePieces?2:1;O=1;for(w=U.length;O<w;O++){M=b();M.positionScreen.copy(U[O]);t.multiplyVector4(M.positionScreen);if(!((O+1)%J>0)){T=j[m-2];C.copy(M.positionScreen);L.copy(T.positionScreen);if(d(C,L)){C.multiplyScalar(1/C.w);L.multiplyScalar(1/L.w);K=u[q]=u[q]||new THREE.RenderableLine;q++;l=K;l.v1.positionScreen.copy(C);l.v2.positionScreen.copy(L);l.z=Math.max(C.z,L.z);l.material=B.material;v.elements.push(l)}}}}}a=
-0;for(P=v.sprites.length;a<P;a++){B=v.sprites[a].object;J=B.matrixWorld;if(B instanceof THREE.Particle){x.set(J.elements[12],J.elements[13],J.elements[14],1);G.multiplyVector4(x);x.z=x.z/x.w;if(x.z>0&&x.z<1){g=A[z]=A[z]||new THREE.RenderableParticle;z++;s=g;s.x=x.x/x.w;s.y=x.y/x.w;s.z=x.z;s.rotation=B.rotation.z;s.scale.x=B.scale.x*Math.abs(s.x-(x.x+f.projectionMatrix.elements[0])/(x.w+f.projectionMatrix.elements[12]));s.scale.y=B.scale.y*Math.abs(s.y-(x.y+f.projectionMatrix.elements[5])/(x.w+f.projectionMatrix.elements[13]));
-s.material=B.material;v.elements.push(s)}}}e&&v.elements.sort(c);return v}};THREE.Quaternion=function(a,b,c,d){this.x=a||0;this.y=b||0;this.z=c||0;this.w=d!==void 0?d:1};
-THREE.Quaternion.prototype={constructor:THREE.Quaternion,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){var b=Math.PI/360,c=a.x*b,d=a.y*b,e=a.z*b,a=Math.cos(d),d=Math.sin(d),b=Math.cos(-e),e=Math.sin(-e),f=Math.cos(c),c=Math.sin(c),g=a*b,k=d*e;this.w=g*f-k*c;this.x=g*c+k*f;this.y=d*b*f+a*e*c;this.z=a*e*f-d*b*c;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=Math.pow(a.determinant(),1/3);this.w=Math.sqrt(Math.max(0,b+a.elements[0]+a.elements[5]+a.elements[10]))/2;this.x=Math.sqrt(Math.max(0,b+a.elements[0]-a.elements[5]-a.elements[10]))/2;this.y=Math.sqrt(Math.max(0,b-a.elements[0]+a.elements[5]-a.elements[10]))/2;this.z=Math.sqrt(Math.max(0,b-a.elements[0]-a.elements[5]+a.elements[10]))/2;this.x=a.elements[6]-a.elements[9]<0?-Math.abs(this.x):
-Math.abs(this.x);this.y=a.elements[8]-a.elements[2]<0?-Math.abs(this.y):Math.abs(this.y);this.z=a.elements[1]-a.elements[4]<0?-Math.abs(this.z):Math.abs(this.z);this.normalize();return this},calculateW:function(){this.w=-Math.sqrt(Math.abs(1-this.x*this.x-this.y*this.y-this.z*this.z));return this},inverse:function(){this.x=this.x*-1;this.y=this.y*-1;this.z=this.z*-1;return this},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=
-Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w);if(a===0)this.w=this.z=this.y=this.x=0;else{a=1/a;this.x=this.x*a;this.y=this.y*a;this.z=this.z*a;this.w=this.w*a}return this},multiply:function(a,b){this.x=a.x*b.w+a.y*b.z-a.z*b.y+a.w*b.x;this.y=-a.x*b.z+a.y*b.w+a.z*b.x+a.w*b.y;this.z=a.x*b.y-a.y*b.x+a.z*b.w+a.w*b.z;this.w=-a.x*b.x-a.y*b.y-a.z*b.z+a.w*b.w;return this},multiplySelf:function(a){var b=this.x,c=this.y,d=this.z,e=this.w,f=a.x,g=a.y,k=a.z,a=a.w;this.x=b*a+e*f+c*k-d*g;this.y=
-c*a+e*g+d*f-b*k;this.z=d*a+e*k+b*g-c*f;this.w=e*a-b*f-c*g-d*k;return this},multiplyVector3:function(a,b){b||(b=a);var c=a.x,d=a.y,e=a.z,f=this.x,g=this.y,k=this.z,m=this.w,j=m*c+g*e-k*d,h=m*d+k*c-f*e,i=m*e+f*d-g*c,c=-f*c-g*d-k*e;b.x=j*m+c*-f+h*-k-i*-g;b.y=h*m+c*-g+i*-f-j*-k;b.z=i*m+c*-k+j*-g-h*-f;return b},clone:function(){return new THREE.Quaternion(this.x,this.y,this.z,this.w)}};
-THREE.Quaternion.slerp=function(a,b,c,d){var e=a.w*b.w+a.x*b.x+a.y*b.y+a.z*b.z;if(e<0){c.w=-b.w;c.x=-b.x;c.y=-b.y;c.z=-b.z;e=-e}else c.copy(b);if(Math.abs(e)>=1){c.w=a.w;c.x=a.x;c.y=a.y;c.z=a.z;return c}var f=Math.acos(e),e=Math.sqrt(1-e*e);if(Math.abs(e)<0.0010){c.w=0.5*(a.w+b.w);c.x=0.5*(a.x+b.x);c.y=0.5*(a.y+b.y);c.z=0.5*(a.z+b.z);return c}b=Math.sin((1-d)*f)/e;d=Math.sin(d*f)/e;c.w=a.w*b+c.w*d;c.x=a.x*b+c.x*d;c.y=a.y*b+c.y*d;c.z=a.z*b+c.z*d;return c};THREE.Vertex=function(){console.warn("THREE.Vertex has been DEPRECATED. Use THREE.Vector3 instead.")};
-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=f;this.centroid=new THREE.Vector3};
+THREE.Object3D.prototype={constructor:THREE.Object3D,applyMatrix:function(a){this.matrix.multiply(a,this.matrix);this.scale.getScaleFromMatrix(this.matrix);this.rotation.setEulerFromRotationMatrix((new THREE.Matrix4).extractRotation(this.matrix),this.eulerOrder);this.position.getPositionFromMatrix(this.matrix)},translate:function(a,b){this.matrix.rotateAxis(b);this.position.addSelf(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))},lookAt:function(a){this.matrix.lookAt(a,this.position,this.up);this.rotationAutoUpdate&&this.rotation.setEulerFromRotationMatrix(this.matrix,this.eulerOrder)},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){a.parent!==void 0&&a.parent.remove(a);a.parent=this;this.children.push(a);for(var b=this;b.parent!==void 0;)b=
+b.parent;b!==void 0&&b instanceof THREE.Scene&&b.__addObject(a)}},remove:function(a){var b=this.children.indexOf(a);if(b!==-1){a.parent=void 0;this.children.splice(b,1);for(b=this;b.parent!==void 0;)b=b.parent;b!==void 0&&b instanceof THREE.Scene&&b.__removeObject(a)}},getChildByName:function(a,b){var c,d,f;c=0;for(d=this.children.length;c<d;c++){f=this.children[c];if(f.name===a)return f;if(b){f=f.getChildByName(a,b);if(f!==void 0)return f}}},updateMatrix:function(){this.matrix.setPosition(this.position);
+this.useQuaternion?this.matrix.setRotationFromQuaternion(this.quaternion):this.matrix.setRotationFromEuler(this.rotation,this.eulerOrder);if(this.scale.x!==1||this.scale.y!==1||this.scale.z!==1){this.matrix.scale(this.scale);this.boundRadiusScale=Math.max(this.scale.x,Math.max(this.scale.y,this.scale.z))}this.matrixWorldNeedsUpdate=true},updateMatrixWorld:function(a){this.matrixAutoUpdate&&this.updateMatrix();if(this.matrixWorldNeedsUpdate||a){this.parent?this.matrixWorld.multiply(this.parent.matrixWorld,
+this.matrix):this.matrixWorld.copy(this.matrix);this.matrixWorldNeedsUpdate=false;a=true}for(var b=0,c=this.children.length;b<c;b++)this.children[b].updateMatrixWorld(a)},worldToLocal:function(a){return THREE.Object3D.__m1.getInverse(this.matrixWorld).multiplyVector3(a)},localToWorld:function(a){return this.matrixWorld.multiplyVector3(a)}};THREE.Object3D.__m1=new THREE.Matrix4;THREE.Object3DCount=0;
+THREE.Projector=function(){function a(){var a=g[e]=g[e]||new THREE.RenderableObject;e++;return a}function b(){var a=l[k]=l[k]||new THREE.RenderableVertex;k++;return a}function c(a,b){return b.z-a.z}function d(a,b){var c=0,d=1,e=a.z+a.w,g=b.z+b.w,f=-a.z+a.w,h=-b.z+b.w;if(e>=0&&g>=0&&f>=0&&h>=0)return true;if(e<0&&g<0||f<0&&h<0)return false;e<0?c=Math.max(c,e/(e-g)):g<0&&(d=Math.min(d,e/(e-g)));f<0?c=Math.max(c,f/(f-h)):h<0&&(d=Math.min(d,f/(f-h)));if(d<c)return false;a.lerpSelf(b,c);b.lerpSelf(a,1-
+d);return true}var f,e,g=[],m,k,l=[],h,n,j=[],o,q=[],i,p,r=[],s,v,A=[],w={objects:[],sprites:[],lights:[],elements:[]},B=new THREE.Vector3,x=new THREE.Vector4,F=new THREE.Matrix4,u=new THREE.Matrix4,z=new THREE.Frustum,D=new THREE.Vector4,H=new THREE.Vector4;this.projectVector=function(a,b){b.matrixWorldInverse.getInverse(b.matrixWorld);F.multiply(b.projectionMatrix,b.matrixWorldInverse);F.multiplyVector3(a);return a};this.unprojectVector=function(a,b){b.projectionMatrixInverse.getInverse(b.projectionMatrix);
+F.multiply(b.matrixWorld,b.projectionMatrixInverse);F.multiplyVector3(a);return a};this.pickingRay=function(a,b){var c;a.z=-1;c=new THREE.Vector3(a.x,a.y,1);this.unprojectVector(a,b);this.unprojectVector(c,b);c.subSelf(a).normalize();return new THREE.Ray(a,c)};this.projectGraph=function(b,d){e=0;w.objects.length=0;w.sprites.length=0;w.lights.length=0;var g=function(b){if(b.visible!==false){if((b instanceof THREE.Mesh||b instanceof THREE.Line)&&(b.frustumCulled===false||z.contains(b))){B.copy(b.matrixWorld.getPosition());
+F.multiplyVector3(B);f=a();f.object=b;f.z=B.z;w.objects.push(f)}else if(b instanceof THREE.Sprite||b instanceof THREE.Particle){B.copy(b.matrixWorld.getPosition());F.multiplyVector3(B);f=a();f.object=b;f.z=B.z;w.sprites.push(f)}else b instanceof THREE.Light&&w.lights.push(b);for(var c=0,d=b.children.length;c<d;c++)g(b.children[c])}};g(b);d&&w.objects.sort(c);return w};this.projectScene=function(a,e,g){var f=e.near,G=e.far,B=false,Q,O,y,S,M,U,T,W,C,J,I,K,R,ja,da;v=p=o=n=0;w.elements.length=0;if(e.parent===
+void 0){console.warn("DEPRECATED: Camera hasn't been added to a Scene. Adding it...");a.add(e)}a.updateMatrixWorld();e.matrixWorldInverse.getInverse(e.matrixWorld);F.multiply(e.projectionMatrix,e.matrixWorldInverse);z.setFromMatrix(F);w=this.projectGraph(a,false);a=0;for(Q=w.objects.length;a<Q;a++){C=w.objects[a].object;J=C.matrixWorld;k=0;if(C instanceof THREE.Mesh){I=C.geometry;K=C.geometry.materials;S=I.vertices;R=I.faces;ja=I.faceVertexUvs;I=C.matrixRotationWorld.extractRotation(J);O=0;for(y=
+S.length;O<y;O++){m=b();m.positionWorld.copy(S[O]);J.multiplyVector3(m.positionWorld);m.positionScreen.copy(m.positionWorld);F.multiplyVector4(m.positionScreen);m.positionScreen.x=m.positionScreen.x/m.positionScreen.w;m.positionScreen.y=m.positionScreen.y/m.positionScreen.w;m.visible=m.positionScreen.z>f&&m.positionScreen.z<G}S=0;for(O=R.length;S<O;S++){y=R[S];if(y instanceof THREE.Face3){M=l[y.a];U=l[y.b];T=l[y.c];if(M.visible&&U.visible&&T.visible){B=(T.positionScreen.x-M.positionScreen.x)*(U.positionScreen.y-
+M.positionScreen.y)-(T.positionScreen.y-M.positionScreen.y)*(U.positionScreen.x-M.positionScreen.x)<0;if(C.doubleSided||B!=C.flipSided){W=j[n]=j[n]||new THREE.RenderableFace3;n++;h=W;h.v1.copy(M);h.v2.copy(U);h.v3.copy(T)}else continue}else continue}else if(y instanceof THREE.Face4){M=l[y.a];U=l[y.b];T=l[y.c];W=l[y.d];if(M.visible&&U.visible&&T.visible&&W.visible){B=(W.positionScreen.x-M.positionScreen.x)*(U.positionScreen.y-M.positionScreen.y)-(W.positionScreen.y-M.positionScreen.y)*(U.positionScreen.x-
+M.positionScreen.x)<0||(U.positionScreen.x-T.positionScreen.x)*(W.positionScreen.y-T.positionScreen.y)-(U.positionScreen.y-T.positionScreen.y)*(W.positionScreen.x-T.positionScreen.x)<0;if(C.doubleSided||B!=C.flipSided){da=q[o]=q[o]||new THREE.RenderableFace4;o++;h=da;h.v1.copy(M);h.v2.copy(U);h.v3.copy(T);h.v4.copy(W)}else continue}else continue}h.normalWorld.copy(y.normal);!B&&(C.flipSided||C.doubleSided)&&h.normalWorld.negate();I.multiplyVector3(h.normalWorld);h.centroidWorld.copy(y.centroid);J.multiplyVector3(h.centroidWorld);
+h.centroidScreen.copy(h.centroidWorld);F.multiplyVector3(h.centroidScreen);T=y.vertexNormals;M=0;for(U=T.length;M<U;M++){W=h.vertexNormalsWorld[M];W.copy(T[M]);!B&&(C.flipSided||C.doubleSided)&&W.negate();I.multiplyVector3(W)}M=0;for(U=ja.length;M<U;M++)if(da=ja[M][S]){T=0;for(W=da.length;T<W;T++)h.uvs[M][T]=da[T]}h.material=C.material;h.faceMaterial=y.materialIndex!==null?K[y.materialIndex]:null;h.z=h.centroidScreen.z;w.elements.push(h)}}else if(C instanceof THREE.Line){u.multiply(F,J);S=C.geometry.vertices;
+M=b();M.positionScreen.copy(S[0]);u.multiplyVector4(M.positionScreen);J=C.type===THREE.LinePieces?2:1;O=1;for(y=S.length;O<y;O++){M=b();M.positionScreen.copy(S[O]);u.multiplyVector4(M.positionScreen);if(!((O+1)%J>0)){U=l[k-2];D.copy(M.positionScreen);H.copy(U.positionScreen);if(d(D,H)){D.multiplyScalar(1/D.w);H.multiplyScalar(1/H.w);K=r[p]=r[p]||new THREE.RenderableLine;p++;i=K;i.v1.positionScreen.copy(D);i.v2.positionScreen.copy(H);i.z=Math.max(D.z,H.z);i.material=C.material;w.elements.push(i)}}}}}a=
+0;for(Q=w.sprites.length;a<Q;a++){C=w.sprites[a].object;J=C.matrixWorld;if(C instanceof THREE.Particle){x.set(J.elements[12],J.elements[13],J.elements[14],1);F.multiplyVector4(x);x.z=x.z/x.w;if(x.z>0&&x.z<1){f=A[v]=A[v]||new THREE.RenderableParticle;v++;s=f;s.x=x.x/x.w;s.y=x.y/x.w;s.z=x.z;s.rotation=C.rotation.z;s.scale.x=C.scale.x*Math.abs(s.x-(x.x+e.projectionMatrix.elements[0])/(x.w+e.projectionMatrix.elements[12]));s.scale.y=C.scale.y*Math.abs(s.y-(x.y+e.projectionMatrix.elements[5])/(x.w+e.projectionMatrix.elements[13]));
+s.material=C.material;w.elements.push(s)}}}g&&w.elements.sort(c);return w}};THREE.Quaternion=function(a,b,c,d){this.x=a||0;this.y=b||0;this.z=c||0;this.w=d!==void 0?d:1};
+THREE.Quaternion.prototype={constructor:THREE.Quaternion,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=b||"XYZ",d=Math.cos(a.x/2),f=Math.cos(a.y/2),e=Math.cos(a.z/2),g=Math.sin(a.x/2),m=Math.sin(a.y/2),k=Math.sin(a.z/2);switch(c){case "YXZ":this.x=g*f*e+d*m*k;this.y=d*m*e-g*f*k;this.z=d*f*k-g*m*e;this.w=d*f*e+g*m*k;break;case "ZXY":this.x=g*f*e-d*m*k;this.y=d*m*e+g*f*
+k;this.z=d*f*k+g*m*e;this.w=d*f*e-g*m*k;break;case "ZYX":this.x=g*f*e-d*m*k;this.y=d*m*e+g*f*k;this.z=d*f*k-g*m*e;this.w=d*f*e+g*m*k;break;case "YZX":this.x=g*f*e+d*m*k;this.y=d*m*e+g*f*k;this.z=d*f*k-g*m*e;this.w=d*f*e-g*m*k;break;case "XZY":this.x=g*f*e-d*m*k;this.y=d*m*e-g*f*k;this.z=d*f*k+g*m*e;this.w=d*f*e+g*m*k;break;default:this.x=g*f*e+d*m*k;this.y=d*m*e-g*f*k;this.z=d*f*k+g*m*e;this.w=d*f*e-g*m*k}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],f=b[1],e=b[5],g=b[9],m=b[2],k=b[6],b=b[10],l=c+e+b;if(l>0){c=0.5/Math.sqrt(l+1);this.w=0.25/c;this.x=(k-g)*c;this.y=(d-m)*c;this.z=(f-a)*c}else if(c>e&&c>b){c=2*Math.sqrt(1+c-e-b);this.w=(k-g)/c;this.x=0.25*c;this.y=(a+f)/c;this.z=(d+m)/c}else if(e>b){c=2*Math.sqrt(1+e-c-b);this.w=(d-m)/c;this.x=(a+f)/c;this.y=0.25*c;this.z=(g+k)/c}else{c=2*Math.sqrt(1+b-c-e);this.w=(f-a)/c;this.x=
+(d+m)/c;this.y=(g+k)/c;this.z=0.25*c}return this},calculateW:function(){this.w=-Math.sqrt(Math.abs(1-this.x*this.x-this.y*this.y-this.z*this.z));return this},inverse:function(){this.x=this.x*-1;this.y=this.y*-1;this.z=this.z*-1;return this},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=Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w);if(a===0)this.w=this.z=this.y=this.x=0;else{a=1/a;this.x=this.x*a;this.y=
+this.y*a;this.z=this.z*a;this.w=this.w*a}return this},multiply:function(a,b){this.x=a.x*b.w+a.y*b.z-a.z*b.y+a.w*b.x;this.y=-a.x*b.z+a.y*b.w+a.z*b.x+a.w*b.y;this.z=a.x*b.y-a.y*b.x+a.z*b.w+a.w*b.z;this.w=-a.x*b.x-a.y*b.y-a.z*b.z+a.w*b.w;return this},multiplySelf:function(a){var b=this.x,c=this.y,d=this.z,f=this.w,e=a.x,g=a.y,m=a.z,a=a.w;this.x=b*a+f*e+c*m-d*g;this.y=c*a+f*g+d*e-b*m;this.z=d*a+f*m+b*g-c*e;this.w=f*a-b*e-c*g-d*m;return this},multiplyVector3:function(a,b){b||(b=a);var c=a.x,d=a.y,f=a.z,
+e=this.x,g=this.y,m=this.z,k=this.w,l=k*c+g*f-m*d,h=k*d+m*c-e*f,n=k*f+e*d-g*c,c=-e*c-g*d-m*f;b.x=l*k+c*-e+h*-m-n*-g;b.y=h*k+c*-g+n*-e-l*-m;b.z=n*k+c*-m+l*-g-h*-e;return b},slerpSelf:function(a,b){var c=this.x,d=this.y,f=this.z,e=this.w,g=e*a.w+c*a.x+d*a.y+f*a.z;if(g<0){this.w=-a.w;this.x=-a.x;this.y=-a.y;this.z=-a.z;g=-g}else this.copy(a);if(g>=1){this.w=e;this.x=c;this.y=d;this.z=f;return this}var m=Math.acos(g),k=Math.sqrt(1-g*g);if(Math.abs(k)<0.001){this.w=0.5*(e+this.w);this.x=0.5*(c+this.x);
+this.y=0.5*(d+this.y);this.z=0.5*(f+this.z);return this}g=Math.sin((1-b)*m)/k;m=Math.sin(b*m)/k;this.w=e*g+this.w*m;this.x=c*g+this.x*m;this.y=d*g+this.y*m;this.z=f*g+this.z*m;return this},clone:function(){return new THREE.Quaternion(this.x,this.y,this.z,this.w)}};
+THREE.Quaternion.slerp=function(a,b,c,d){var f=a.w*b.w+a.x*b.x+a.y*b.y+a.z*b.z;if(f<0){c.w=-b.w;c.x=-b.x;c.y=-b.y;c.z=-b.z;f=-f}else c.copy(b);if(Math.abs(f)>=1){c.w=a.w;c.x=a.x;c.y=a.y;c.z=a.z;return c}var b=Math.acos(f),e=Math.sqrt(1-f*f);if(Math.abs(e)<0.001){c.w=0.5*(a.w+c.w);c.x=0.5*(a.x+c.x);c.y=0.5*(a.y+c.y);c.z=0.5*(a.z+c.z);return c}f=Math.sin((1-d)*b)/e;d=Math.sin(d*b)/e;c.w=a.w*f+c.w*d;c.x=a.x*f+c.x*d;c.y=a.y*f+c.y*d;c.z=a.z*f+c.z*d;return c};THREE.Vertex=function(){console.warn("THREE.Vertex has been DEPRECATED. Use THREE.Vector3 instead.")};
+THREE.Face3=function(a,b,c,d,f,e){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=f instanceof THREE.Color?f:new THREE.Color;this.vertexColors=f instanceof Array?f:[];this.vertexTangents=[];this.materialIndex=e;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=g;this.centroid=new THREE.Vector3};
+return a}};THREE.Face4=function(a,b,c,d,f,e,g){this.a=a;this.b=b;this.c=c;this.d=d;this.normal=f instanceof THREE.Vector3?f:new THREE.Vector3;this.vertexNormals=f instanceof Array?f:[];this.color=e instanceof THREE.Color?e:new THREE.Color;this.vertexColors=e instanceof Array?e:[];this.vertexTangents=[];this.materialIndex=g;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.UV=function(a,b){this.u=a||0;this.v=b||0};THREE.UV.prototype={constructor:THREE.UV,set:function(a,b){this.u=a;this.v=b;return this},copy:function(a){this.u=a.u;this.v=a.v;return this},lerpSelf:function(a,b){this.u=this.u+(a.u-this.u)*b;this.v=this.v+(a.v-this.v)*b;return this},clone:function(){return new THREE.UV(this.u,this.v)}};
-THREE.Geometry=function(){this.id=THREE.GeometryCount++;this.vertices=[];this.colors=[];this.materials=[];this.faces=[];this.faceUvs=[[]];this.faceVertexUvs=[[]];this.morphTargets=[];this.morphColors=[];this.morphNormals=[];this.skinWeights=[];this.skinIndices=[];this.boundingSphere=this.boundingBox=null;this.dynamic=this.hasTangents=false};
-THREE.Geometry.prototype={constructor:THREE.Geometry,applyMatrix:function(a){var b=new THREE.Matrix4;b.extractRotation(a);for(var c=0,d=this.vertices.length;c<d;c++)a.multiplyVector3(this.vertices[c]);c=0;for(d=this.faces.length;c<d;c++){var e=this.faces[c];b.multiplyVector3(e.normal);for(var f=0,g=e.vertexNormals.length;f<g;f++)b.multiplyVector3(e.vertexNormals[f]);a.multiplyVector3(e.centroid)}},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);if(c instanceof THREE.Face3){c.centroid.addSelf(this.vertices[c.a]);c.centroid.addSelf(this.vertices[c.b]);c.centroid.addSelf(this.vertices[c.c]);c.centroid.divideScalar(3)}else if(c instanceof THREE.Face4){c.centroid.addSelf(this.vertices[c.a]);c.centroid.addSelf(this.vertices[c.b]);c.centroid.addSelf(this.vertices[c.c]);c.centroid.addSelf(this.vertices[c.d]);c.centroid.divideScalar(4)}}},computeFaceNormals:function(){var a,b,c,d,e,f,g=new THREE.Vector3,k=new THREE.Vector3;a=0;for(b=this.faces.length;a<
-b;a++){c=this.faces[a];d=this.vertices[c.a];e=this.vertices[c.b];f=this.vertices[c.c];g.sub(f,e);k.sub(d,e);g.crossSelf(k);g.isZero()||g.normalize();c.normal.copy(g)}},computeVertexNormals:function(){var a,b,c,d;if(this.__tmpVertices===void 0){d=this.__tmpVertices=Array(this.vertices.length);a=0;for(b=this.vertices.length;a<b;a++)d[a]=new THREE.Vector3;a=0;for(b=this.faces.length;a<b;a++){c=this.faces[a];if(c instanceof THREE.Face3)c.vertexNormals=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3];
+THREE.Geometry=function(){this.id=THREE.GeometryCount++;this.name="";this.vertices=[];this.colors=[];this.materials=[];this.faces=[];this.faceUvs=[[]];this.faceVertexUvs=[[]];this.morphTargets=[];this.morphColors=[];this.morphNormals=[];this.skinWeights=[];this.skinIndices=[];this.boundingSphere=this.boundingBox=null;this.dynamic=this.hasTangents=false};
+THREE.Geometry.prototype={constructor:THREE.Geometry,applyMatrix:function(a){var b=new THREE.Matrix4;b.extractRotation(a);for(var c=0,d=this.vertices.length;c<d;c++)a.multiplyVector3(this.vertices[c]);c=0;for(d=this.faces.length;c<d;c++){var f=this.faces[c];b.multiplyVector3(f.normal);for(var e=0,g=f.vertexNormals.length;e<g;e++)b.multiplyVector3(f.vertexNormals[e]);a.multiplyVector3(f.centroid)}},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);if(c instanceof THREE.Face3){c.centroid.addSelf(this.vertices[c.a]);c.centroid.addSelf(this.vertices[c.b]);c.centroid.addSelf(this.vertices[c.c]);c.centroid.divideScalar(3)}else if(c instanceof THREE.Face4){c.centroid.addSelf(this.vertices[c.a]);c.centroid.addSelf(this.vertices[c.b]);c.centroid.addSelf(this.vertices[c.c]);c.centroid.addSelf(this.vertices[c.d]);c.centroid.divideScalar(4)}}},computeFaceNormals:function(){var a,b,c,d,f,e,g=new THREE.Vector3,m=new THREE.Vector3;a=0;for(b=this.faces.length;a<
+b;a++){c=this.faces[a];d=this.vertices[c.a];f=this.vertices[c.b];e=this.vertices[c.c];g.sub(e,f);m.sub(d,f);g.crossSelf(m);g.isZero()||g.normalize();c.normal.copy(g)}},computeVertexNormals:function(){var a,b,c,d;if(this.__tmpVertices===void 0){d=this.__tmpVertices=Array(this.vertices.length);a=0;for(b=this.vertices.length;a<b;a++)d[a]=new THREE.Vector3;a=0;for(b=this.faces.length;a<b;a++){c=this.faces[a];if(c instanceof THREE.Face3)c.vertexNormals=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3];
 else if(c instanceof THREE.Face4)c.vertexNormals=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3]}}else{d=this.__tmpVertices;a=0;for(b=this.vertices.length;a<b;a++)d[a].set(0,0,0)}a=0;for(b=this.faces.length;a<b;a++){c=this.faces[a];if(c instanceof THREE.Face3){d[c.a].addSelf(c.normal);d[c.b].addSelf(c.normal);d[c.c].addSelf(c.normal)}else if(c instanceof THREE.Face4){d[c.a].addSelf(c.normal);d[c.b].addSelf(c.normal);d[c.c].addSelf(c.normal);d[c.d].addSelf(c.normal)}}a=0;
-for(b=this.vertices.length;a<b;a++)d[a].normalize();a=0;for(b=this.faces.length;a<b;a++){c=this.faces[a];if(c instanceof THREE.Face3){c.vertexNormals[0].copy(d[c.a]);c.vertexNormals[1].copy(d[c.b]);c.vertexNormals[2].copy(d[c.c])}else if(c instanceof THREE.Face4){c.vertexNormals[0].copy(d[c.a]);c.vertexNormals[1].copy(d[c.b]);c.vertexNormals[2].copy(d[c.c]);c.vertexNormals[3].copy(d[c.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();if(!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,k=this.morphNormals[a].vertexNormals,m,j;c=0;for(d=this.faces.length;c<d;c++){e=this.faces[c];m=new THREE.Vector3;j=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(m);k.push(j)}}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];
-m=g.faceNormals[c];j=g.vertexNormals[c];m.copy(e.normal);if(e instanceof THREE.Face3){j.a.copy(e.vertexNormals[0]);j.b.copy(e.vertexNormals[1]);j.c.copy(e.vertexNormals[2])}else{j.a.copy(e.vertexNormals[0]);j.b.copy(e.vertexNormals[1]);j.c.copy(e.vertexNormals[2]);j.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,f,e,M){k=a.vertices[b];m=a.vertices[c];
-j=a.vertices[d];h=g[f];i=g[e];o=g[M];n=m.x-k.x;p=j.x-k.x;l=m.y-k.y;q=j.y-k.y;u=m.z-k.z;s=j.z-k.z;z=i.u-h.u;A=o.u-h.u;v=i.v-h.v;D=o.v-h.v;x=1/(z*D-A*v);C.set((D*n-v*p)*x,(D*l-v*q)*x,(D*u-v*s)*x);L.set((z*p-A*n)*x,(z*q-A*l)*x,(z*s-A*u)*x);t[b].addSelf(C);t[c].addSelf(C);t[d].addSelf(C);y[b].addSelf(L);y[c].addSelf(L);y[d].addSelf(L)}var b,c,d,e,f,g,k,m,j,h,i,o,n,p,l,q,u,s,z,A,v,D,x,G,t=[],y=[],C=new THREE.Vector3,L=new THREE.Vector3,Q=new THREE.Vector3,N=new THREE.Vector3,r=new THREE.Vector3;b=0;for(c=
-this.vertices.length;b<c;b++){t[b]=new THREE.Vector3;y[b]=new THREE.Vector3}b=0;for(c=this.faces.length;b<c;b++){f=this.faces[b];g=this.faceVertexUvs[0][b];if(f instanceof THREE.Face3)a(this,f.a,f.b,f.c,0,1,2);else if(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 E=["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++){r.copy(f.vertexNormals[d]);e=f[E[d]];G=t[e];Q.copy(G);Q.subSelf(r.multiplyScalar(r.dot(G))).normalize();
-N.cross(f.vertexNormals[d],G);e=N.dot(y[e]);e=e<0?-1:1;f.vertexTangents[d]=new THREE.Vector4(Q.x,Q.y,Q.z,e)}}this.hasTangents=true},computeBoundingBox:function(){if(!this.boundingBox)this.boundingBox={min:new THREE.Vector3,max:new THREE.Vector3};if(this.vertices.length>0){var a;a=this.vertices[0];this.boundingBox.min.copy(a);this.boundingBox.max.copy(a);for(var b=this.boundingBox.min,c=this.boundingBox.max,d=1,e=this.vertices.length;d<e;d++){a=this.vertices[d];if(a.x<b.x)b.x=a.x;else if(a.x>c.x)c.x=
-a.x;if(a.y<b.y)b.y=a.y;else if(a.y>c.y)c.y=a.y;if(a.z<b.z)b.z=a.z;else if(a.z>c.z)c.z=a.z}}else{this.boundingBox.min.set(0,0,0);this.boundingBox.max.set(0,0,0)}},computeBoundingSphere:function(){if(!this.boundingSphere)this.boundingSphere={radius:0};for(var a,b=0,c=0,d=this.vertices.length;c<d;c++){a=this.vertices[c].length();a>b&&(b=a)}this.boundingSphere.radius=b},mergeVertices:function(){var a={},b=[],c=[],d,e=Math.pow(10,4),f,g,k;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("_");if(a[d]===void 0){a[d]=f;b.push(this.vertices[f]);c[f]=b.length-1}else c[f]=c[a[d]]}f=0;for(g=this.faces.length;f<g;f++){e=this.faces[f];if(e instanceof THREE.Face3){e.a=c[e.a];e.b=c[e.b];e.c=c[e.c]}else if(e instanceof THREE.Face4){e.a=c[e.a];e.b=c[e.b];e.c=c[e.c];e.d=c[e.d];d=[e.a,e.b,e.c,e.d];for(a=3;a>0;a--)if(d.indexOf(e["abcd"[a]])!=a){d.splice(a,1);this.faces[f]=new THREE.Face3(d[0],d[1],d[2]);e=0;for(d=this.faceVertexUvs.length;e<d;e++)(k=
-this.faceVertexUvs[e][f])&&k.splice(a,1);break}}}c=this.vertices.length-b.length;this.vertices=b;return c}};THREE.GeometryCount=0;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=new THREE.Object3D;THREE.Camera.prototype.constructor=THREE.Camera;
-THREE.Camera.prototype.lookAt=function(a){this.matrix.lookAt(this.position,a,this.up);this.rotationAutoUpdate&&this.rotation.getRotationFromMatrix(this.matrix)};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=e!==void 0?e:0.1;this.far=f!==void 0?f:2E3;this.updateProjectionMatrix()};THREE.OrthographicCamera.prototype=new THREE.Camera;THREE.OrthographicCamera.prototype.constructor=THREE.OrthographicCamera;
+for(b=this.vertices.length;a<b;a++)d[a].normalize();a=0;for(b=this.faces.length;a<b;a++){c=this.faces[a];if(c instanceof THREE.Face3){c.vertexNormals[0].copy(d[c.a]);c.vertexNormals[1].copy(d[c.b]);c.vertexNormals[2].copy(d[c.c])}else if(c instanceof THREE.Face4){c.vertexNormals[0].copy(d[c.a]);c.vertexNormals[1].copy(d[c.b]);c.vertexNormals[2].copy(d[c.c]);c.vertexNormals[3].copy(d[c.d])}}},computeMorphNormals:function(){var a,b,c,d,f;c=0;for(d=this.faces.length;c<d;c++){f=this.faces[c];f.__originalFaceNormal?
+f.__originalFaceNormal.copy(f.normal):f.__originalFaceNormal=f.normal.clone();if(!f.__originalVertexNormals)f.__originalVertexNormals=[];a=0;for(b=f.vertexNormals.length;a<b;a++)f.__originalVertexNormals[a]?f.__originalVertexNormals[a].copy(f.vertexNormals[a]):f.__originalVertexNormals[a]=f.vertexNormals[a].clone()}var e=new THREE.Geometry;e.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,m=this.morphNormals[a].vertexNormals,k,l;c=0;for(d=this.faces.length;c<d;c++){f=this.faces[c];k=new THREE.Vector3;l=f 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(k);m.push(l)}}g=this.morphNormals[a];e.vertices=this.morphTargets[a].vertices;e.computeFaceNormals();e.computeVertexNormals();c=0;for(d=this.faces.length;c<d;c++){f=this.faces[c];
+k=g.faceNormals[c];l=g.vertexNormals[c];k.copy(f.normal);if(f instanceof THREE.Face3){l.a.copy(f.vertexNormals[0]);l.b.copy(f.vertexNormals[1]);l.c.copy(f.vertexNormals[2])}else{l.a.copy(f.vertexNormals[0]);l.b.copy(f.vertexNormals[1]);l.c.copy(f.vertexNormals[2]);l.d.copy(f.vertexNormals[3])}}}c=0;for(d=this.faces.length;c<d;c++){f=this.faces[c];f.normal=f.__originalFaceNormal;f.vertexNormals=f.__originalVertexNormals}},computeTangents:function(){function a(a,b,c,d,e,f,M){m=a.vertices[b];k=a.vertices[c];
+l=a.vertices[d];h=g[e];n=g[f];j=g[M];o=k.x-m.x;q=l.x-m.x;i=k.y-m.y;p=l.y-m.y;r=k.z-m.z;s=l.z-m.z;v=n.u-h.u;A=j.u-h.u;w=n.v-h.v;B=j.v-h.v;x=1/(v*B-A*w);D.set((B*o-w*q)*x,(B*i-w*p)*x,(B*r-w*s)*x);H.set((v*q-A*o)*x,(v*p-A*i)*x,(v*s-A*r)*x);u[b].addSelf(D);u[c].addSelf(D);u[d].addSelf(D);z[b].addSelf(H);z[c].addSelf(H);z[d].addSelf(H)}var b,c,d,f,e,g,m,k,l,h,n,j,o,q,i,p,r,s,v,A,w,B,x,F,u=[],z=[],D=new THREE.Vector3,H=new THREE.Vector3,P=new THREE.Vector3,L=new THREE.Vector3,t=new THREE.Vector3;b=0;for(c=
+this.vertices.length;b<c;b++){u[b]=new THREE.Vector3;z[b]=new THREE.Vector3}b=0;for(c=this.faces.length;b<c;b++){e=this.faces[b];g=this.faceVertexUvs[0][b];if(e instanceof THREE.Face3)a(this,e.a,e.b,e.c,0,1,2);else if(e instanceof THREE.Face4){a(this,e.a,e.b,e.d,0,1,3);a(this,e.b,e.c,e.d,1,2,3)}}var E=["a","b","c","d"];b=0;for(c=this.faces.length;b<c;b++){e=this.faces[b];for(d=0;d<e.vertexNormals.length;d++){t.copy(e.vertexNormals[d]);f=e[E[d]];F=u[f];P.copy(F);P.subSelf(t.multiplyScalar(t.dot(F))).normalize();
+L.cross(e.vertexNormals[d],F);f=L.dot(z[f]);f=f<0?-1:1;e.vertexTangents[d]=new THREE.Vector4(P.x,P.y,P.z,f)}}this.hasTangents=true},computeBoundingBox:function(){if(!this.boundingBox)this.boundingBox={min:new THREE.Vector3,max:new THREE.Vector3};if(this.vertices.length>0){var a;a=this.vertices[0];this.boundingBox.min.copy(a);this.boundingBox.max.copy(a);for(var b=this.boundingBox.min,c=this.boundingBox.max,d=1,f=this.vertices.length;d<f;d++){a=this.vertices[d];if(a.x<b.x)b.x=a.x;else if(a.x>c.x)c.x=
+a.x;if(a.y<b.y)b.y=a.y;else if(a.y>c.y)c.y=a.y;if(a.z<b.z)b.z=a.z;else if(a.z>c.z)c.z=a.z}}else{this.boundingBox.min.set(0,0,0);this.boundingBox.max.set(0,0,0)}},computeBoundingSphere:function(){if(!this.boundingSphere)this.boundingSphere={radius:0};for(var a,b=0,c=0,d=this.vertices.length;c<d;c++){a=this.vertices[c].length();a>b&&(b=a)}this.boundingSphere.radius=b},mergeVertices:function(){var a={},b=[],c=[],d,f=Math.pow(10,4),e,g,m;e=0;for(g=this.vertices.length;e<g;e++){d=this.vertices[e];d=[Math.round(d.x*
+f),Math.round(d.y*f),Math.round(d.z*f)].join("_");if(a[d]===void 0){a[d]=e;b.push(this.vertices[e]);c[e]=b.length-1}else c[e]=c[a[d]]}e=0;for(g=this.faces.length;e<g;e++){f=this.faces[e];if(f instanceof THREE.Face3){f.a=c[f.a];f.b=c[f.b];f.c=c[f.c]}else if(f instanceof THREE.Face4){f.a=c[f.a];f.b=c[f.b];f.c=c[f.c];f.d=c[f.d];d=[f.a,f.b,f.c,f.d];for(a=3;a>0;a--)if(d.indexOf(f["abcd"[a]])!=a){d.splice(a,1);this.faces[e]=new THREE.Face3(d[0],d[1],d[2]);f=0;for(d=this.faceVertexUvs.length;f<d;f++)(m=
+this.faceVertexUvs[f][e])&&m.splice(a,1);break}}}c=this.vertices.length-b.length;this.vertices=b;return c}};THREE.GeometryCount=0;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=new THREE.Object3D;THREE.Camera.prototype.constructor=THREE.Camera;
+THREE.Camera.prototype.lookAt=function(a){this.matrix.lookAt(this.position,a,this.up);this.rotationAutoUpdate&&this.rotation.setEulerFromRotationMatrix(this.matrix,this.eulerOrder)};THREE.OrthographicCamera=function(a,b,c,d,f,e){THREE.Camera.call(this);this.left=a;this.right=b;this.top=c;this.bottom=d;this.near=f!==void 0?f:0.1;this.far=e!==void 0?e:2E3;this.updateProjectionMatrix()};THREE.OrthographicCamera.prototype=new THREE.Camera;THREE.OrthographicCamera.prototype.constructor=THREE.OrthographicCamera;
 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=a!==void 0?a:50;this.aspect=b!==void 0?b:1;this.near=c!==void 0?c:0.1;this.far=d!==void 0?d:2E3;this.updateProjectionMatrix()};THREE.PerspectiveCamera.prototype=new THREE.Camera;THREE.PerspectiveCamera.prototype.constructor=THREE.PerspectiveCamera;
-THREE.PerspectiveCamera.prototype.setLens=function(a,b){this.fov=2*Math.atan((b!==void 0?b:24)/(a*2))*(180/Math.PI);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.setLens=function(a,b){this.fov=2*Math.atan((b!==void 0?b:24)/(a*2))*(180/Math.PI);this.updateProjectionMatrix()};THREE.PerspectiveCamera.prototype.setViewOffset=function(a,b,c,d,f,e){this.fullWidth=a;this.fullHeight=b;this.x=c;this.y=d;this.width=f;this.height=e;this.updateProjectionMatrix()};
 THREE.PerspectiveCamera.prototype.updateProjectionMatrix=function(){if(this.fullWidth){var a=this.fullWidth/this.fullHeight,b=Math.tan(this.fov*Math.PI/360)*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=new THREE.Object3D;THREE.Light.prototype.constructor=THREE.Light;THREE.Light.prototype.supr=THREE.Object3D.prototype;THREE.AmbientLight=function(a){THREE.Light.call(this,a)};THREE.AmbientLight.prototype=new THREE.Light;THREE.AmbientLight.prototype.constructor=THREE.AmbientLight;
+THREE.Light=function(a){THREE.Object3D.call(this);this.color=new THREE.Color(a)};THREE.Light.prototype=new THREE.Object3D;THREE.Light.prototype.constructor=THREE.Light;THREE.AmbientLight=function(a){THREE.Light.call(this,a)};THREE.AmbientLight.prototype=new THREE.Light;THREE.AmbientLight.prototype.constructor=THREE.AmbientLight;
 THREE.DirectionalLight=function(a,b,c){THREE.Light.call(this,a);this.position=new THREE.Vector3(0,1,0);this.target=new THREE.Object3D;this.intensity=b!==void 0?b:1;this.distance=c!==void 0?c:0;this.onlyShadow=this.castShadow=false;this.shadowCameraNear=50;this.shadowCameraFar=5E3;this.shadowCameraLeft=-500;this.shadowCameraTop=this.shadowCameraRight=500;this.shadowCameraBottom=-500;this.shadowCameraVisible=false;this.shadowBias=0;this.shadowDarkness=0.5;this.shadowMapHeight=this.shadowMapWidth=512;
 this.shadowCascade=false;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=new THREE.Light;THREE.DirectionalLight.prototype.constructor=THREE.DirectionalLight;
 THREE.PointLight=function(a,b,c){THREE.Light.call(this,a);this.position=new THREE.Vector3(0,0,0);this.intensity=b!==void 0?b:1;this.distance=c!==void 0?c:0};THREE.PointLight.prototype=new THREE.Light;THREE.PointLight.prototype.constructor=THREE.PointLight;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(a.length<1?".":a.join("/"))+"/"},initMaterials:function(a,b,c){a.materials=[];for(var d=0;d<b.length;++d)a.materials[d]=THREE.Loader.prototype.createMaterial(b[d],c)},hasNormals:function(a){var b,c,d=a.materials.length;for(c=0;c<d;c++){b=a.materials[c];if(b instanceof THREE.ShaderMaterial)return true}return false},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,b){var f=new Image;f.onload=function(){if(!c(this.width)||!c(this.height)){var b=d(this.width),f=d(this.height);a.image.width=b;a.image.height=f;a.image.getContext("2d").drawImage(this,0,0,b,f)}else a.image=this;a.needsUpdate=true};f.crossOrigin=k.crossOrigin;f.src=b}function f(a,c,d,f,g,h){var k=document.createElement("canvas");a[c]=new THREE.Texture(k);a[c].sourceFile=
-d;if(f){a[c].repeat.set(f[0],f[1]);if(f[0]!=1)a[c].wrapS=THREE.RepeatWrapping;if(f[1]!=1)a[c].wrapT=THREE.RepeatWrapping}g&&a[c].offset.set(g[0],g[1]);if(h){f={repeat:THREE.RepeatWrapping,mirror:THREE.MirroredRepeatWrapping};if(f[h[0]]!==void 0)a[c].wrapS=f[h[0]];if(f[h[1]]!==void 0)a[c].wrapT=f[h[1]]}e(a[c],b+"/"+d)}function g(a){return(a[0]*255<<16)+(a[1]*255<<8)+a[2]*255}var k=this,m="MeshLambertMaterial",j={color:15658734,opacity:1,map:null,lightMap:null,normalMap:null,wireframe:a.wireframe};
-if(a.shading){var h=a.shading.toLowerCase();h==="phong"?m="MeshPhongMaterial":h==="basic"&&(m="MeshBasicMaterial")}if(a.blending!==void 0&&THREE[a.blending]!==void 0)j.blending=THREE[a.blending];if(a.transparent!==void 0||a.opacity<1)j.transparent=a.transparent;if(a.depthTest!==void 0)j.depthTest=a.depthTest;if(a.depthWrite!==void 0)j.depthWrite=a.depthWrite;if(a.vertexColors!==void 0)if(a.vertexColors=="face")j.vertexColors=THREE.FaceColors;else if(a.vertexColors)j.vertexColors=THREE.VertexColors;
-if(a.colorDiffuse)j.color=g(a.colorDiffuse);else if(a.DbgColor)j.color=a.DbgColor;if(a.colorSpecular)j.specular=g(a.colorSpecular);if(a.colorAmbient)j.ambient=g(a.colorAmbient);if(a.transparency)j.opacity=a.transparency;if(a.specularCoef)j.shininess=a.specularCoef;a.mapDiffuse&&b&&f(j,"map",a.mapDiffuse,a.mapDiffuseRepeat,a.mapDiffuseOffset,a.mapDiffuseWrap);a.mapLight&&b&&f(j,"lightMap",a.mapLight,a.mapLightRepeat,a.mapLightOffset,a.mapLightWrap);a.mapNormal&&b&&f(j,"normalMap",a.mapNormal,a.mapNormalRepeat,
-a.mapNormalOffset,a.mapNormalWrap);a.mapSpecular&&b&&f(j,"specularMap",a.mapSpecular,a.mapSpecularRepeat,a.mapSpecularOffset,a.mapSpecularWrap);if(a.mapNormal){m=THREE.ShaderUtils.lib.normal;h=THREE.UniformsUtils.clone(m.uniforms);h.tNormal.texture=j.normalMap;if(a.mapNormalFactor)h.uNormalScale.value=a.mapNormalFactor;if(j.map){h.tDiffuse.texture=j.map;h.enableDiffuse.value=true}if(j.specularMap){h.tSpecular.texture=j.specularMap;h.enableSpecular.value=true}if(j.lightMap){h.tAO.texture=j.lightMap;
-h.enableAO.value=true}h.uDiffuseColor.value.setHex(j.color);h.uSpecularColor.value.setHex(j.specular);h.uAmbientColor.value.setHex(j.ambient);h.uShininess.value=j.shininess;if(j.opacity!==void 0)h.uOpacity.value=j.opacity;j=new THREE.ShaderMaterial({fragmentShader:m.fragmentShader,vertexShader:m.vertexShader,uniforms:h,lights:true,fog:true})}else j=new THREE[m](j);if(a.DbgName!==void 0)j.name=a.DbgName;return j}};THREE.BinaryLoader=function(a){THREE.Loader.call(this,a)};
-THREE.BinaryLoader.prototype=new THREE.Loader;THREE.BinaryLoader.prototype.constructor=THREE.BinaryLoader;THREE.BinaryLoader.prototype.load=function(a,b,c,d){var c=c?c:this.extractUrlBase(a),d=d?d:this.extractUrlBase(a),e=this.showProgress?THREE.Loader.prototype.updateProgress:null;this.onLoadStart();this.loadAjaxJSON(this,a,b,c,d,e)};
-THREE.BinaryLoader.prototype.loadAjaxJSON=function(a,b,c,d,e,f){var g=new XMLHttpRequest;g.onreadystatechange=function(){if(g.readyState==4)if(g.status==200||g.status==0){var k=JSON.parse(g.responseText);a.loadAjaxBuffers(k,c,e,d,f)}else console.error("THREE.BinaryLoader: Couldn't load ["+b+"] ["+g.status+"]")};g.open("GET",b,true);g.overrideMimeType&&g.overrideMimeType("text/plain; charset=x-user-defined");g.setRequestHeader("Content-Type","text/plain");g.send(null)};
-THREE.BinaryLoader.prototype.loadAjaxBuffers=function(a,b,c,d,e){var f=new XMLHttpRequest,g=c+"/"+a.buffers,k=0;f.onreadystatechange=function(){if(f.readyState==4)f.status==200||f.status==0?THREE.BinaryLoader.prototype.createBinModel(f.response,b,d,a.materials):console.error("THREE.BinaryLoader: Couldn't load ["+g+"] ["+f.status+"]");else if(f.readyState==3){if(e){k==0&&(k=f.getResponseHeader("Content-Length"));e({total:k,loaded:f.responseText.length})}}else f.readyState==2&&(k=f.getResponseHeader("Content-Length"))};
-f.open("GET",g,true);f.responseType="arraybuffer";f.send(null)};
-THREE.BinaryLoader.prototype.createBinModel=function(a,b,c,d){var e=function(b){var c,e,m,j,h,i,o,n,p,l,q,u,s,z,A;function v(a){return a%4?4-a%4:0}function D(a,b){return(new Uint8Array(a,b,1))[0]}function x(a,b){return(new Uint32Array(a,b,1))[0]}function G(b,c){var d,f,e,g,h,k,l,j,m=new Uint32Array(a,c,3*b);for(d=0;d<b;d++){f=m[d*3];e=m[d*3+1];g=m[d*3+2];h=F[f*2];f=F[f*2+1];k=F[e*2];l=F[e*2+1];e=F[g*2];j=F[g*2+1];g=N.faceVertexUvs[0];var n=[];n.push(new THREE.UV(h,f));n.push(new THREE.UV(k,l));n.push(new THREE.UV(e,
-j));g.push(n)}}function t(b,c){var d,f,e,g,h,k,l,j,m,n,o=new Uint32Array(a,c,4*b);for(d=0;d<b;d++){f=o[d*4];e=o[d*4+1];g=o[d*4+2];h=o[d*4+3];k=F[f*2];f=F[f*2+1];l=F[e*2];m=F[e*2+1];j=F[g*2];n=F[g*2+1];g=F[h*2];e=F[h*2+1];h=N.faceVertexUvs[0];var i=[];i.push(new THREE.UV(k,f));i.push(new THREE.UV(l,m));i.push(new THREE.UV(j,n));i.push(new THREE.UV(g,e));h.push(i)}}function y(b,c,d){for(var f,e,g,h,c=new Uint32Array(a,c,3*b),k=new Uint16Array(a,d,b),d=0;d<b;d++){f=c[d*3];e=c[d*3+1];g=c[d*3+2];h=k[d];
-N.faces.push(new THREE.Face3(f,e,g,null,null,h))}}function C(b,c,d){for(var f,e,g,h,k,c=new Uint32Array(a,c,4*b),l=new Uint16Array(a,d,b),d=0;d<b;d++){f=c[d*4];e=c[d*4+1];g=c[d*4+2];h=c[d*4+3];k=l[d];N.faces.push(new THREE.Face4(f,e,g,h,null,null,k))}}function L(b,c,d,f){for(var e,g,h,k,l,j,m,c=new Uint32Array(a,c,3*b),d=new Uint32Array(a,d,3*b),n=new Uint16Array(a,f,b),f=0;f<b;f++){e=c[f*3];g=c[f*3+1];h=c[f*3+2];l=d[f*3];j=d[f*3+1];m=d[f*3+2];k=n[f];var i=E[j*3],o=E[j*3+1];j=E[j*3+2];var p=E[m*3],
-q=E[m*3+1];m=E[m*3+2];N.faces.push(new THREE.Face3(e,g,h,[new THREE.Vector3(E[l*3],E[l*3+1],E[l*3+2]),new THREE.Vector3(i,o,j),new THREE.Vector3(p,q,m)],null,k))}}function Q(b,c,d,f){for(var e,g,h,k,l,j,m,n,i,c=new Uint32Array(a,c,4*b),d=new Uint32Array(a,d,4*b),o=new Uint16Array(a,f,b),f=0;f<b;f++){e=c[f*4];g=c[f*4+1];h=c[f*4+2];k=c[f*4+3];j=d[f*4];m=d[f*4+1];n=d[f*4+2];i=d[f*4+3];l=o[f];var p=E[m*3],q=E[m*3+1];m=E[m*3+2];var r=E[n*3],s=E[n*3+1];n=E[n*3+2];var t=E[i*3],u=E[i*3+1];i=E[i*3+2];N.faces.push(new THREE.Face4(e,
-g,h,k,[new THREE.Vector3(E[j*3],E[j*3+1],E[j*3+2]),new THREE.Vector3(p,q,m),new THREE.Vector3(r,s,n),new THREE.Vector3(t,u,i)],null,l))}}var N=this,r=0,E=[],F=[],H,P,O;THREE.Geometry.call(this);THREE.Loader.prototype.initMaterials(N,d,b);(function(a,b,c){for(var a=new Uint8Array(a,b,c),d="",f=0;f<c;f++)d=d+String.fromCharCode(a[b+f]);return d})(a,r,12);c=D(a,r+12);D(a,r+13);D(a,r+14);D(a,r+15);e=D(a,r+16);m=D(a,r+17);j=D(a,r+18);h=D(a,r+19);i=x(a,r+20);o=x(a,r+20+4);n=x(a,r+20+8);b=x(a,r+20+12);p=
-x(a,r+20+16);l=x(a,r+20+20);q=x(a,r+20+24);u=x(a,r+20+28);s=x(a,r+20+32);z=x(a,r+20+36);A=x(a,r+20+40);r=r+c;c=e*3+h;O=e*4+h;H=b*c;P=p*(c+m*3);e=l*(c+j*3);h=q*(c+m*3+j*3);c=u*O;m=s*(O+m*4);j=z*(O+j*4);r=r+function(b){var b=new Float32Array(a,b,i*3),c,d,f,e;for(c=0;c<i;c++){d=b[c*3];f=b[c*3+1];e=b[c*3+2];N.vertices.push(new THREE.Vector3(d,f,e))}return i*3*Float32Array.BYTES_PER_ELEMENT}(r);r=r+function(b){if(o){var b=new Int8Array(a,b,o*3),c,d,f,e;for(c=0;c<o;c++){d=b[c*3];f=b[c*3+1];e=b[c*3+2];E.push(d/
-127,f/127,e/127)}}return o*3*Int8Array.BYTES_PER_ELEMENT}(r);r=r+v(o*3);r=r+function(b){if(n){var b=new Float32Array(a,b,n*2),c,d,f;for(c=0;c<n;c++){d=b[c*2];f=b[c*2+1];F.push(d,f)}}return n*2*Float32Array.BYTES_PER_ELEMENT}(r);H=r+H+v(b*2);P=H+P+v(p*2);e=P+e+v(l*2);h=e+h+v(q*2);c=h+c+v(u*2);m=c+m+v(s*2);j=m+j+v(z*2);(function(a){if(l){var b=a+l*Uint32Array.BYTES_PER_ELEMENT*3;y(l,a,b+l*Uint32Array.BYTES_PER_ELEMENT*3);G(l,b)}})(P);(function(a){if(q){var b=a+q*Uint32Array.BYTES_PER_ELEMENT*3,c=b+
-q*Uint32Array.BYTES_PER_ELEMENT*3;L(q,a,b,c+q*Uint32Array.BYTES_PER_ELEMENT*3);G(q,c)}})(e);(function(a){if(z){var b=a+z*Uint32Array.BYTES_PER_ELEMENT*4;C(z,a,b+z*Uint32Array.BYTES_PER_ELEMENT*4);t(z,b)}})(m);(function(a){if(A){var b=a+A*Uint32Array.BYTES_PER_ELEMENT*4,c=b+A*Uint32Array.BYTES_PER_ELEMENT*4;Q(A,a,b,c+A*Uint32Array.BYTES_PER_ELEMENT*4);t(A,c)}})(j);b&&y(b,r,r+b*Uint32Array.BYTES_PER_ELEMENT*3);(function(a){if(p){var b=a+p*Uint32Array.BYTES_PER_ELEMENT*3;L(p,a,b,b+p*Uint32Array.BYTES_PER_ELEMENT*
-3)}})(H);u&&C(u,h,h+u*Uint32Array.BYTES_PER_ELEMENT*4);(function(a){if(s){var b=a+s*Uint32Array.BYTES_PER_ELEMENT*4;Q(s,a,b,b+s*Uint32Array.BYTES_PER_ELEMENT*4)}})(c);this.computeCentroids();this.computeFaceNormals();THREE.Loader.prototype.hasNormals(this)&&this.computeTangents()};e.prototype=new THREE.Geometry;e.prototype.constructor=e;b(new e(c))};THREE.JSONLoader=function(a){THREE.Loader.call(this,a)};THREE.JSONLoader.prototype=new THREE.Loader;THREE.JSONLoader.prototype.constructor=THREE.JSONLoader;
+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 f(a,b){var e=new Image;e.onload=function(){if(!c(this.width)||!c(this.height)){var b=d(this.width),e=d(this.height);a.image.width=b;a.image.height=e;a.image.getContext("2d").drawImage(this,0,0,b,e)}else a.image=this;a.needsUpdate=true};e.crossOrigin=m.crossOrigin;e.src=b}function e(a,c,d,e,g,h){var m=document.createElement("canvas");a[c]=new THREE.Texture(m);a[c].sourceFile=
+d;if(e){a[c].repeat.set(e[0],e[1]);if(e[0]!=1)a[c].wrapS=THREE.RepeatWrapping;if(e[1]!=1)a[c].wrapT=THREE.RepeatWrapping}g&&a[c].offset.set(g[0],g[1]);if(h){e={repeat:THREE.RepeatWrapping,mirror:THREE.MirroredRepeatWrapping};if(e[h[0]]!==void 0)a[c].wrapS=e[h[0]];if(e[h[1]]!==void 0)a[c].wrapT=e[h[1]]}f(a[c],b+"/"+d)}function g(a){return(a[0]*255<<16)+(a[1]*255<<8)+a[2]*255}var m=this,k="MeshLambertMaterial",l={color:15658734,opacity:1,map:null,lightMap:null,normalMap:null,wireframe:a.wireframe};
+if(a.shading){var h=a.shading.toLowerCase();h==="phong"?k="MeshPhongMaterial":h==="basic"&&(k="MeshBasicMaterial")}if(a.blending!==void 0&&THREE[a.blending]!==void 0)l.blending=THREE[a.blending];if(a.transparent!==void 0||a.opacity<1)l.transparent=a.transparent;if(a.depthTest!==void 0)l.depthTest=a.depthTest;if(a.depthWrite!==void 0)l.depthWrite=a.depthWrite;if(a.vertexColors!==void 0)if(a.vertexColors=="face")l.vertexColors=THREE.FaceColors;else if(a.vertexColors)l.vertexColors=THREE.VertexColors;
+if(a.colorDiffuse)l.color=g(a.colorDiffuse);else if(a.DbgColor)l.color=a.DbgColor;if(a.colorSpecular)l.specular=g(a.colorSpecular);if(a.colorAmbient)l.ambient=g(a.colorAmbient);if(a.transparency)l.opacity=a.transparency;if(a.specularCoef)l.shininess=a.specularCoef;a.mapDiffuse&&b&&e(l,"map",a.mapDiffuse,a.mapDiffuseRepeat,a.mapDiffuseOffset,a.mapDiffuseWrap);a.mapLight&&b&&e(l,"lightMap",a.mapLight,a.mapLightRepeat,a.mapLightOffset,a.mapLightWrap);a.mapNormal&&b&&e(l,"normalMap",a.mapNormal,a.mapNormalRepeat,
+a.mapNormalOffset,a.mapNormalWrap);a.mapSpecular&&b&&e(l,"specularMap",a.mapSpecular,a.mapSpecularRepeat,a.mapSpecularOffset,a.mapSpecularWrap);if(a.mapNormal){k=THREE.ShaderUtils.lib.normal;h=THREE.UniformsUtils.clone(k.uniforms);h.tNormal.texture=l.normalMap;if(a.mapNormalFactor)h.uNormalScale.value=a.mapNormalFactor;if(l.map){h.tDiffuse.texture=l.map;h.enableDiffuse.value=true}if(l.specularMap){h.tSpecular.texture=l.specularMap;h.enableSpecular.value=true}if(l.lightMap){h.tAO.texture=l.lightMap;
+h.enableAO.value=true}h.uDiffuseColor.value.setHex(l.color);h.uSpecularColor.value.setHex(l.specular);h.uAmbientColor.value.setHex(l.ambient);h.uShininess.value=l.shininess;if(l.opacity!==void 0)h.uOpacity.value=l.opacity;l=new THREE.ShaderMaterial({fragmentShader:k.fragmentShader,vertexShader:k.vertexShader,uniforms:h,lights:true,fog:true})}else l=new THREE[k](l);if(a.DbgName!==void 0)l.name=a.DbgName;return l}};THREE.BinaryLoader=function(a){THREE.Loader.call(this,a)};
+THREE.BinaryLoader.prototype=new THREE.Loader;THREE.BinaryLoader.prototype.constructor=THREE.BinaryLoader;THREE.BinaryLoader.prototype.load=function(a,b,c,d){var c=c?c:this.extractUrlBase(a),d=d?d:this.extractUrlBase(a),f=this.showProgress?THREE.Loader.prototype.updateProgress:null;this.onLoadStart();this.loadAjaxJSON(this,a,b,c,d,f)};
+THREE.BinaryLoader.prototype.loadAjaxJSON=function(a,b,c,d,f,e){var g=new XMLHttpRequest;g.onreadystatechange=function(){if(g.readyState==4)if(g.status==200||g.status==0){var m=JSON.parse(g.responseText);a.loadAjaxBuffers(m,c,f,d,e)}else console.error("THREE.BinaryLoader: Couldn't load ["+b+"] ["+g.status+"]")};g.open("GET",b,true);g.overrideMimeType&&g.overrideMimeType("text/plain; charset=x-user-defined");g.setRequestHeader("Content-Type","text/plain");g.send(null)};
+THREE.BinaryLoader.prototype.loadAjaxBuffers=function(a,b,c,d,f){var e=new XMLHttpRequest,g=c+"/"+a.buffers,m=0;e.onreadystatechange=function(){if(e.readyState==4)e.status==200||e.status==0?THREE.BinaryLoader.prototype.createBinModel(e.response,b,d,a.materials):console.error("THREE.BinaryLoader: Couldn't load ["+g+"] ["+e.status+"]");else if(e.readyState==3){if(f){m==0&&(m=e.getResponseHeader("Content-Length"));f({total:m,loaded:e.responseText.length})}}else e.readyState==2&&(m=e.getResponseHeader("Content-Length"))};
+e.open("GET",g,true);e.responseType="arraybuffer";e.send(null)};
+THREE.BinaryLoader.prototype.createBinModel=function(a,b,c,d){var f=function(b){var c,f,k,l,h,n,j,o,q,i,p,r,s,v,A;function w(a){return a%4?4-a%4:0}function B(a,b){return(new Uint8Array(a,b,1))[0]}function x(a,b){return(new Uint32Array(a,b,1))[0]}function F(b,c){var d,e,f,g,h,m,l,k,i=new Uint32Array(a,c,3*b);for(d=0;d<b;d++){e=i[d*3];f=i[d*3+1];g=i[d*3+2];h=G[e*2];e=G[e*2+1];m=G[f*2];l=G[f*2+1];f=G[g*2];k=G[g*2+1];g=L.faceVertexUvs[0];var j=[];j.push(new THREE.UV(h,e));j.push(new THREE.UV(m,l));j.push(new THREE.UV(f,
+k));g.push(j)}}function u(b,c){var d,e,f,g,h,m,l,k,i,j,n=new Uint32Array(a,c,4*b);for(d=0;d<b;d++){e=n[d*4];f=n[d*4+1];g=n[d*4+2];h=n[d*4+3];m=G[e*2];e=G[e*2+1];l=G[f*2];i=G[f*2+1];k=G[g*2];j=G[g*2+1];g=G[h*2];f=G[h*2+1];h=L.faceVertexUvs[0];var o=[];o.push(new THREE.UV(m,e));o.push(new THREE.UV(l,i));o.push(new THREE.UV(k,j));o.push(new THREE.UV(g,f));h.push(o)}}function z(b,c,d){for(var e,f,g,h,c=new Uint32Array(a,c,3*b),m=new Uint16Array(a,d,b),d=0;d<b;d++){e=c[d*3];f=c[d*3+1];g=c[d*3+2];h=m[d];
+L.faces.push(new THREE.Face3(e,f,g,null,null,h))}}function D(b,c,d){for(var e,f,g,h,m,c=new Uint32Array(a,c,4*b),l=new Uint16Array(a,d,b),d=0;d<b;d++){e=c[d*4];f=c[d*4+1];g=c[d*4+2];h=c[d*4+3];m=l[d];L.faces.push(new THREE.Face4(e,f,g,h,null,null,m))}}function H(b,c,d,e){for(var f,g,h,m,l,k,i,c=new Uint32Array(a,c,3*b),d=new Uint32Array(a,d,3*b),j=new Uint16Array(a,e,b),e=0;e<b;e++){f=c[e*3];g=c[e*3+1];h=c[e*3+2];l=d[e*3];k=d[e*3+1];i=d[e*3+2];m=j[e];var n=E[k*3],o=E[k*3+1];k=E[k*3+2];var p=E[i*3],
+q=E[i*3+1];i=E[i*3+2];L.faces.push(new THREE.Face3(f,g,h,[new THREE.Vector3(E[l*3],E[l*3+1],E[l*3+2]),new THREE.Vector3(n,o,k),new THREE.Vector3(p,q,i)],null,m))}}function P(b,c,d,e){for(var f,g,h,m,l,k,i,j,n,c=new Uint32Array(a,c,4*b),d=new Uint32Array(a,d,4*b),o=new Uint16Array(a,e,b),e=0;e<b;e++){f=c[e*4];g=c[e*4+1];h=c[e*4+2];m=c[e*4+3];k=d[e*4];i=d[e*4+1];j=d[e*4+2];n=d[e*4+3];l=o[e];var p=E[i*3],q=E[i*3+1];i=E[i*3+2];var r=E[j*3],t=E[j*3+1];j=E[j*3+2];var s=E[n*3],z=E[n*3+1];n=E[n*3+2];L.faces.push(new THREE.Face4(f,
+g,h,m,[new THREE.Vector3(E[k*3],E[k*3+1],E[k*3+2]),new THREE.Vector3(p,q,i),new THREE.Vector3(r,t,j),new THREE.Vector3(s,z,n)],null,l))}}var L=this,t=0,E=[],G=[],N,Q,O;THREE.Geometry.call(this);THREE.Loader.prototype.initMaterials(L,d,b);(function(a,b,c){for(var a=new Uint8Array(a,b,c),d="",e=0;e<c;e++)d=d+String.fromCharCode(a[b+e]);return d})(a,t,12);c=B(a,t+12);B(a,t+13);B(a,t+14);B(a,t+15);f=B(a,t+16);k=B(a,t+17);l=B(a,t+18);h=B(a,t+19);n=x(a,t+20);j=x(a,t+20+4);o=x(a,t+20+8);b=x(a,t+20+12);q=
+x(a,t+20+16);i=x(a,t+20+20);p=x(a,t+20+24);r=x(a,t+20+28);s=x(a,t+20+32);v=x(a,t+20+36);A=x(a,t+20+40);t=t+c;c=f*3+h;O=f*4+h;N=b*c;Q=q*(c+k*3);f=i*(c+l*3);h=p*(c+k*3+l*3);c=r*O;k=s*(O+k*4);l=v*(O+l*4);t=t+function(b){var b=new Float32Array(a,b,n*3),c,d,e,f;for(c=0;c<n;c++){d=b[c*3];e=b[c*3+1];f=b[c*3+2];L.vertices.push(new THREE.Vector3(d,e,f))}return n*3*Float32Array.BYTES_PER_ELEMENT}(t);t=t+function(b){if(j){var b=new Int8Array(a,b,j*3),c,d,e,f;for(c=0;c<j;c++){d=b[c*3];e=b[c*3+1];f=b[c*3+2];E.push(d/
+127,e/127,f/127)}}return j*3*Int8Array.BYTES_PER_ELEMENT}(t);t=t+w(j*3);t=t+function(b){if(o){var b=new Float32Array(a,b,o*2),c,d,e;for(c=0;c<o;c++){d=b[c*2];e=b[c*2+1];G.push(d,e)}}return o*2*Float32Array.BYTES_PER_ELEMENT}(t);N=t+N+w(b*2);Q=N+Q+w(q*2);f=Q+f+w(i*2);h=f+h+w(p*2);c=h+c+w(r*2);k=c+k+w(s*2);l=k+l+w(v*2);(function(a){if(i){var b=a+i*Uint32Array.BYTES_PER_ELEMENT*3;z(i,a,b+i*Uint32Array.BYTES_PER_ELEMENT*3);F(i,b)}})(Q);(function(a){if(p){var b=a+p*Uint32Array.BYTES_PER_ELEMENT*3,c=b+
+p*Uint32Array.BYTES_PER_ELEMENT*3;H(p,a,b,c+p*Uint32Array.BYTES_PER_ELEMENT*3);F(p,c)}})(f);(function(a){if(v){var b=a+v*Uint32Array.BYTES_PER_ELEMENT*4;D(v,a,b+v*Uint32Array.BYTES_PER_ELEMENT*4);u(v,b)}})(k);(function(a){if(A){var b=a+A*Uint32Array.BYTES_PER_ELEMENT*4,c=b+A*Uint32Array.BYTES_PER_ELEMENT*4;P(A,a,b,c+A*Uint32Array.BYTES_PER_ELEMENT*4);u(A,c)}})(l);b&&z(b,t,t+b*Uint32Array.BYTES_PER_ELEMENT*3);(function(a){if(q){var b=a+q*Uint32Array.BYTES_PER_ELEMENT*3;H(q,a,b,b+q*Uint32Array.BYTES_PER_ELEMENT*
+3)}})(N);r&&D(r,h,h+r*Uint32Array.BYTES_PER_ELEMENT*4);(function(a){if(s){var b=a+s*Uint32Array.BYTES_PER_ELEMENT*4;P(s,a,b,b+s*Uint32Array.BYTES_PER_ELEMENT*4)}})(c);this.computeCentroids();this.computeFaceNormals();THREE.Loader.prototype.hasNormals(this)&&this.computeTangents()};f.prototype=new THREE.Geometry;f.prototype.constructor=f;b(new f(c))};THREE.ImageLoader=function(){THREE.EventTarget.call(this);this.crossOrigin=null};
+THREE.ImageLoader.prototype={constructor:THREE.ImageLoader,load:function(a){var b=this,c=new Image;c.addEventListener("load",function(){b.dispatchEvent({type:"load",content:c})},false);c.addEventListener("error",function(){b.dispatchEvent({type:"error",message:"Couldn't load URL ["+a+"]"})},false);if(b.crossOrigin)c.crossOrigin=b.crossOrigin;c.src=a}};THREE.JSONLoader=function(a){THREE.Loader.call(this,a)};THREE.JSONLoader.prototype=new THREE.Loader;THREE.JSONLoader.prototype.constructor=THREE.JSONLoader;
 THREE.JSONLoader.prototype.load=function(a,b,c){c=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(f.status===200||f.status===0){if(f.responseText){var k=JSON.parse(f.responseText);a.createModel(k,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 if(f.readyState===f.LOADING){if(e){g===0&&(g=f.getResponseHeader("Content-Length"));
-e({total:g,loaded:f.responseText.length})}}else f.readyState===f.HEADERS_RECEIVED&&(g=f.getResponseHeader("Content-Length"))};f.open("GET",b,true);f.overrideMimeType&&f.overrideMimeType("text/plain; charset=x-user-defined");f.setRequestHeader("Content-Type","text/plain");f.send(null)};
-THREE.JSONLoader.prototype.createModel=function(a,b,c){var d=new THREE.Geometry,e=a.scale!==void 0?1/a.scale:1;this.initMaterials(d,a.materials,c);(function(b){var c,e,m,j,h,i,o,n,p,l,q,u,s,z,A=a.faces;i=a.vertices;var v=a.normals,D=a.colors,x=0;for(c=0;c<a.uvs.length;c++)a.uvs[c].length&&x++;for(c=0;c<x;c++){d.faceUvs[c]=[];d.faceVertexUvs[c]=[]}j=0;for(h=i.length;j<h;){o=new THREE.Vector3;o.x=i[j++]*b;o.y=i[j++]*b;o.z=i[j++]*b;d.vertices.push(o)}j=0;for(h=A.length;j<h;){b=A[j++];i=b&1;m=b&2;c=b&
-4;e=b&8;n=b&16;o=b&32;l=b&64;b=b&128;if(i){q=new THREE.Face4;q.a=A[j++];q.b=A[j++];q.c=A[j++];q.d=A[j++];i=4}else{q=new THREE.Face3;q.a=A[j++];q.b=A[j++];q.c=A[j++];i=3}if(m){m=A[j++];q.materialIndex=m}m=d.faces.length;if(c)for(c=0;c<x;c++){u=a.uvs[c];p=A[j++];z=u[p*2];p=u[p*2+1];d.faceUvs[c][m]=new THREE.UV(z,p)}if(e)for(c=0;c<x;c++){u=a.uvs[c];s=[];for(e=0;e<i;e++){p=A[j++];z=u[p*2];p=u[p*2+1];s[e]=new THREE.UV(z,p)}d.faceVertexUvs[c][m]=s}if(n){n=A[j++]*3;e=new THREE.Vector3;e.x=v[n++];e.y=v[n++];
-e.z=v[n];q.normal=e}if(o)for(c=0;c<i;c++){n=A[j++]*3;e=new THREE.Vector3;e.x=v[n++];e.y=v[n++];e.z=v[n];q.vertexNormals.push(e)}if(l){o=A[j++];o=new THREE.Color(D[o]);q.color=o}if(b)for(c=0;c<i;c++){o=A[j++];o=new THREE.Color(D[o]);q.vertexColors.push(o)}d.faces.push(q)}})(e);(function(){var b,c,e,m;if(a.skinWeights){b=0;for(c=a.skinWeights.length;b<c;b=b+2){e=a.skinWeights[b];m=a.skinWeights[b+1];d.skinWeights.push(new THREE.Vector4(e,m,0,0))}}if(a.skinIndices){b=0;for(c=a.skinIndices.length;b<c;b=
-b+2){e=a.skinIndices[b];m=a.skinIndices[b+1];d.skinIndices.push(new THREE.Vector4(e,m,0,0))}}d.bones=a.bones;d.animation=a.animation})();(function(b){if(a.morphTargets!==void 0){var c,e,m,j,h,i;c=0;for(e=a.morphTargets.length;c<e;c++){d.morphTargets[c]={};d.morphTargets[c].name=a.morphTargets[c].name;d.morphTargets[c].vertices=[];h=d.morphTargets[c].vertices;i=a.morphTargets[c].vertices;m=0;for(j=i.length;m<j;m=m+3){var o=new THREE.Vector3;o.x=i[m]*b;o.y=i[m+1]*b;o.z=i[m+2]*b;h.push(o)}}}if(a.morphColors!==
-void 0){c=0;for(e=a.morphColors.length;c<e;c++){d.morphColors[c]={};d.morphColors[c].name=a.morphColors[c].name;d.morphColors[c].colors=[];j=d.morphColors[c].colors;h=a.morphColors[c].colors;b=0;for(m=h.length;b<m;b=b+3){i=new THREE.Color(16755200);i.setRGB(h[b],h[b+1],h[b+2]);j.push(i)}}}})(e);d.computeCentroids();d.computeFaceNormals();this.hasNormals(d)&&d.computeTangents();b(d)};
-THREE.SceneLoader=function(){this.onLoadStart=function(){};this.onLoadProgress=function(){};this.onLoadComplete=function(){};this.callbackSync=function(){};this.callbackProgress=function(){}};THREE.SceneLoader.prototype.constructor=THREE.SceneLoader;
-THREE.SceneLoader.prototype.load=function(a,b){var c=this,d=new XMLHttpRequest;d.onreadystatechange=function(){if(d.readyState==4)if(d.status==200||d.status==0){var e=JSON.parse(d.responseText);c.createScene(e,b,a)}else console.error("THREE.SceneLoader: Couldn't load ["+a+"] ["+d.status+"]")};d.open("GET",a,true);d.overrideMimeType&&d.overrideMimeType("text/plain; charset=x-user-defined");d.setRequestHeader("Content-Type","text/plain");d.send(null)};
-THREE.SceneLoader.prototype.createScene=function(a,b,c){function d(a,b){return b=="relativeToHTML"?a:j+"/"+a}function e(){var a;for(o in r.objects)if(!w.objects[o]){u=r.objects[o];if(u.geometry!==void 0){if(C=w.geometries[u.geometry]){a=false;L=w.materials[u.materials[0]];(a=L instanceof THREE.ShaderMaterial)&&C.computeTangents();v=u.position;D=u.rotation;x=u.quaternion;G=u.scale;s=u.matrix;x=0;u.materials.length==0&&(L=new THREE.MeshFaceMaterial);u.materials.length>1&&(L=new THREE.MeshFaceMaterial);
-a=new THREE.Mesh(C,L);a.name=o;if(s){a.matrixAutoUpdate=false;a.matrix.set(s[0],s[1],s[2],s[3],s[4],s[5],s[6],s[7],s[8],s[9],s[10],s[11],s[12],s[13],s[14],s[15])}else{a.position.set(v[0],v[1],v[2]);if(x){a.quaternion.set(x[0],x[1],x[2],x[3]);a.useQuaternion=true}else a.rotation.set(D[0],D[1],D[2]);a.scale.set(G[0],G[1],G[2])}a.visible=u.visible;a.doubleSided=u.doubleSided;a.castShadow=u.castShadow;a.receiveShadow=u.receiveShadow;w.scene.add(a);w.objects[o]=a}}else{v=u.position;D=u.rotation;x=u.quaternion;
-G=u.scale;x=0;a=new THREE.Object3D;a.name=o;a.position.set(v[0],v[1],v[2]);if(x){a.quaternion.set(x[0],x[1],x[2],x[3]);a.useQuaternion=true}else a.rotation.set(D[0],D[1],D[2]);a.scale.set(G[0],G[1],G[2]);a.visible=u.visible!==void 0?u.visible:false;w.scene.add(a);w.objects[o]=a;w.empties[o]=a}}}function f(a){return function(b){w.geometries[a]=b;e();F=F-1;m.onLoadComplete();k()}}function g(a){return function(b){w.geometries[a]=b}}function k(){m.callbackProgress({totalModels:P,totalTextures:O,loadedModels:P-
-F,loadedTextures:O-H},w);m.onLoadProgress();F==0&&H==0&&b(w)}var m=this,j=THREE.Loader.prototype.extractUrlBase(c),h,i,o,n,p,l,q,u,s,z,A,v,D,x,G,t,y,C,L,Q,N,r,E,F,H,P,O,w;r=a;c=new THREE.BinaryLoader;E=new THREE.JSONLoader;H=F=0;w={scene:new THREE.Scene,geometries:{},materials:{},textures:{},objects:{},cameras:{},lights:{},fogs:{},empties:{}};if(r.transform){a=r.transform.position;z=r.transform.rotation;t=r.transform.scale;a&&w.scene.position.set(a[0],a[1],a[2]);z&&w.scene.rotation.set(z[0],z[1],
-z[2]);t&&w.scene.scale.set(t[0],t[1],t[2]);if(a||z||t){w.scene.updateMatrix();w.scene.updateMatrixWorld()}}a=function(){H=H-1;k();m.onLoadComplete()};for(p in r.cameras){t=r.cameras[p];t.type=="perspective"?Q=new THREE.PerspectiveCamera(t.fov,t.aspect,t.near,t.far):t.type=="ortho"&&(Q=new THREE.OrthographicCamera(t.left,t.right,t.top,t.bottom,t.near,t.far));v=t.position;z=t.target;t=t.up;Q.position.set(v[0],v[1],v[2]);Q.target=new THREE.Vector3(z[0],z[1],z[2]);t&&Q.up.set(t[0],t[1],t[2]);w.cameras[p]=
-Q}for(n in r.lights){z=r.lights[n];p=z.color!==void 0?z.color:16777215;Q=z.intensity!==void 0?z.intensity:1;if(z.type=="directional"){v=z.direction;A=new THREE.DirectionalLight(p,Q);A.position.set(v[0],v[1],v[2]);A.position.normalize()}else if(z.type=="point"){v=z.position;A=z.distance;A=new THREE.PointLight(p,Q,A);A.position.set(v[0],v[1],v[2])}else z.type=="ambient"&&(A=new THREE.AmbientLight(p));w.scene.add(A);w.lights[n]=A}for(l in r.fogs){n=r.fogs[l];n.type=="linear"?N=new THREE.Fog(0,n.near,
-n.far):n.type=="exp2"&&(N=new THREE.FogExp2(0,n.density));t=n.color;N.color.setRGB(t[0],t[1],t[2]);w.fogs[l]=N}if(w.cameras&&r.defaults.camera)w.currentCamera=w.cameras[r.defaults.camera];if(w.fogs&&r.defaults.fog)w.scene.fog=w.fogs[r.defaults.fog];t=r.defaults.bgcolor;w.bgColor=new THREE.Color;w.bgColor.setRGB(t[0],t[1],t[2]);w.bgColorAlpha=r.defaults.bgalpha;for(h in r.geometries){l=r.geometries[h];if(l.type=="bin_mesh"||l.type=="ascii_mesh"){F=F+1;m.onLoadStart()}}P=F;for(h in r.geometries){l=
-r.geometries[h];if(l.type=="cube"){C=new THREE.CubeGeometry(l.width,l.height,l.depth,l.segmentsWidth,l.segmentsHeight,l.segmentsDepth,null,l.flipped,l.sides);w.geometries[h]=C}else if(l.type=="plane"){C=new THREE.PlaneGeometry(l.width,l.height,l.segmentsWidth,l.segmentsHeight);w.geometries[h]=C}else if(l.type=="sphere"){C=new THREE.SphereGeometry(l.radius,l.segmentsWidth,l.segmentsHeight);w.geometries[h]=C}else if(l.type=="cylinder"){C=new THREE.CylinderGeometry(l.topRad,l.botRad,l.height,l.radSegs,
-l.heightSegs);w.geometries[h]=C}else if(l.type=="torus"){C=new THREE.TorusGeometry(l.radius,l.tube,l.segmentsR,l.segmentsT);w.geometries[h]=C}else if(l.type=="icosahedron"){C=new THREE.IcosahedronGeometry(l.radius,l.subdivisions);w.geometries[h]=C}else if(l.type=="bin_mesh")c.load(d(l.url,r.urlBaseType),f(h));else if(l.type=="ascii_mesh")E.load(d(l.url,r.urlBaseType),f(h));else if(l.type=="embedded_mesh"){l=r.embeds[l.id];l.metadata=r.metadata;l&&E.createModel(l,g(h),"")}}for(q in r.textures){h=r.textures[q];
-if(h.url instanceof Array){H=H+h.url.length;for(l=0;l<h.url.length;l++)m.onLoadStart()}else{H=H+1;m.onLoadStart()}}O=H;for(q in r.textures){h=r.textures[q];if(h.mapping!=void 0&&THREE[h.mapping]!=void 0)h.mapping=new THREE[h.mapping];if(h.url instanceof Array){l=[];for(N=0;N<h.url.length;N++)l[N]=d(h.url[N],r.urlBaseType);l=THREE.ImageUtils.loadTextureCube(l,h.mapping,a)}else{l=THREE.ImageUtils.loadTexture(d(h.url,r.urlBaseType),h.mapping,a);if(THREE[h.minFilter]!=void 0)l.minFilter=THREE[h.minFilter];
-if(THREE[h.magFilter]!=void 0)l.magFilter=THREE[h.magFilter];if(h.repeat){l.repeat.set(h.repeat[0],h.repeat[1]);if(h.repeat[0]!=1)l.wrapS=THREE.RepeatWrapping;if(h.repeat[1]!=1)l.wrapT=THREE.RepeatWrapping}h.offset&&l.offset.set(h.offset[0],h.offset[1]);if(h.wrap){N={repeat:THREE.RepeatWrapping,mirror:THREE.MirroredRepeatWrapping};if(N[h.wrap[0]]!==void 0)l.wrapS=N[h.wrap[0]];if(N[h.wrap[1]]!==void 0)l.wrapT=N[h.wrap[1]]}}w.textures[q]=l}for(i in r.materials){s=r.materials[i];for(y in s.parameters)if(y==
-"envMap"||y=="map"||y=="lightMap")s.parameters[y]=w.textures[s.parameters[y]];else if(y=="shading")s.parameters[y]=s.parameters[y]=="flat"?THREE.FlatShading:THREE.SmoothShading;else if(y=="blending")s.parameters[y]=THREE[s.parameters[y]]?THREE[s.parameters[y]]:THREE.NormalBlending;else if(y=="combine")s.parameters[y]=s.parameters[y]=="MixOperation"?THREE.MixOperation:THREE.MultiplyOperation;else if(y=="vertexColors")if(s.parameters[y]=="face")s.parameters[y]=THREE.FaceColors;else if(s.parameters[y])s.parameters[y]=
-THREE.VertexColors;if(s.parameters.opacity!==void 0&&s.parameters.opacity<1)s.parameters.transparent=true;if(s.parameters.normalMap){q=THREE.ShaderUtils.lib.normal;a=THREE.UniformsUtils.clone(q.uniforms);h=s.parameters.color;l=s.parameters.specular;N=s.parameters.ambient;c=s.parameters.shininess;a.tNormal.texture=w.textures[s.parameters.normalMap];if(s.parameters.normalMapFactor)a.uNormalScale.value=s.parameters.normalMapFactor;if(s.parameters.map){a.tDiffuse.texture=s.parameters.map;a.enableDiffuse.value=
-true}if(s.parameters.lightMap){a.tAO.texture=s.parameters.lightMap;a.enableAO.value=true}if(s.parameters.specularMap){a.tSpecular.texture=w.textures[s.parameters.specularMap];a.enableSpecular.value=true}a.uDiffuseColor.value.setHex(h);a.uSpecularColor.value.setHex(l);a.uAmbientColor.value.setHex(N);a.uShininess.value=c;if(s.parameters.opacity)a.uOpacity.value=s.parameters.opacity;L=new THREE.ShaderMaterial({fragmentShader:q.fragmentShader,vertexShader:q.vertexShader,uniforms:a,lights:true,fog:true})}else L=
-new THREE[s.type](s.parameters);w.materials[i]=L}e();m.callbackSync(w);k()};
+THREE.JSONLoader.prototype.loadAjaxJSON=function(a,b,c,d,f){var e=new XMLHttpRequest,g=0;e.onreadystatechange=function(){if(e.readyState===e.DONE)if(e.status===200||e.status===0){if(e.responseText){var m=JSON.parse(e.responseText);a.createModel(m,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+"] ["+e.status+"]");else if(e.readyState===e.LOADING){if(f){g===0&&(g=e.getResponseHeader("Content-Length"));
+f({total:g,loaded:e.responseText.length})}}else e.readyState===e.HEADERS_RECEIVED&&(g=e.getResponseHeader("Content-Length"))};e.open("GET",b,true);e.overrideMimeType&&e.overrideMimeType("text/plain; charset=x-user-defined");e.setRequestHeader("Content-Type","text/plain");e.send(null)};
+THREE.JSONLoader.prototype.createModel=function(a,b,c){var d=new THREE.Geometry,f=a.scale!==void 0?1/a.scale:1;this.initMaterials(d,a.materials,c);(function(b){var c,f,k,l,h,n,j,o,q,i,p,r,s,v,A=a.faces;n=a.vertices;var w=a.normals,B=a.colors,x=0;for(c=0;c<a.uvs.length;c++)a.uvs[c].length&&x++;for(c=0;c<x;c++){d.faceUvs[c]=[];d.faceVertexUvs[c]=[]}l=0;for(h=n.length;l<h;){j=new THREE.Vector3;j.x=n[l++]*b;j.y=n[l++]*b;j.z=n[l++]*b;d.vertices.push(j)}l=0;for(h=A.length;l<h;){b=A[l++];n=b&1;k=b&2;c=b&
+4;f=b&8;o=b&16;j=b&32;i=b&64;b=b&128;if(n){p=new THREE.Face4;p.a=A[l++];p.b=A[l++];p.c=A[l++];p.d=A[l++];n=4}else{p=new THREE.Face3;p.a=A[l++];p.b=A[l++];p.c=A[l++];n=3}if(k){k=A[l++];p.materialIndex=k}k=d.faces.length;if(c)for(c=0;c<x;c++){r=a.uvs[c];q=A[l++];v=r[q*2];q=r[q*2+1];d.faceUvs[c][k]=new THREE.UV(v,q)}if(f)for(c=0;c<x;c++){r=a.uvs[c];s=[];for(f=0;f<n;f++){q=A[l++];v=r[q*2];q=r[q*2+1];s[f]=new THREE.UV(v,q)}d.faceVertexUvs[c][k]=s}if(o){o=A[l++]*3;f=new THREE.Vector3;f.x=w[o++];f.y=w[o++];
+f.z=w[o];p.normal=f}if(j)for(c=0;c<n;c++){o=A[l++]*3;f=new THREE.Vector3;f.x=w[o++];f.y=w[o++];f.z=w[o];p.vertexNormals.push(f)}if(i){j=A[l++];j=new THREE.Color(B[j]);p.color=j}if(b)for(c=0;c<n;c++){j=A[l++];j=new THREE.Color(B[j]);p.vertexColors.push(j)}d.faces.push(p)}})(f);(function(){var b,c,f,k;if(a.skinWeights){b=0;for(c=a.skinWeights.length;b<c;b=b+2){f=a.skinWeights[b];k=a.skinWeights[b+1];d.skinWeights.push(new THREE.Vector4(f,k,0,0))}}if(a.skinIndices){b=0;for(c=a.skinIndices.length;b<c;b=
+b+2){f=a.skinIndices[b];k=a.skinIndices[b+1];d.skinIndices.push(new THREE.Vector4(f,k,0,0))}}d.bones=a.bones;d.animation=a.animation})();(function(b){if(a.morphTargets!==void 0){var c,f,k,l,h,n;c=0;for(f=a.morphTargets.length;c<f;c++){d.morphTargets[c]={};d.morphTargets[c].name=a.morphTargets[c].name;d.morphTargets[c].vertices=[];h=d.morphTargets[c].vertices;n=a.morphTargets[c].vertices;k=0;for(l=n.length;k<l;k=k+3){var j=new THREE.Vector3;j.x=n[k]*b;j.y=n[k+1]*b;j.z=n[k+2]*b;h.push(j)}}}if(a.morphColors!==
+void 0){c=0;for(f=a.morphColors.length;c<f;c++){d.morphColors[c]={};d.morphColors[c].name=a.morphColors[c].name;d.morphColors[c].colors=[];l=d.morphColors[c].colors;h=a.morphColors[c].colors;b=0;for(k=h.length;b<k;b=b+3){n=new THREE.Color(16755200);n.setRGB(h[b],h[b+1],h[b+2]);l.push(n)}}}})(f);d.computeCentroids();d.computeFaceNormals();this.hasNormals(d)&&d.computeTangents();b(d)};THREE.GeometryLoader=function(){THREE.EventTarget.call(this);this.path=this.crossOrigin=null};
+THREE.GeometryLoader.prototype={constructor:THREE.GeometryLoader,load:function(a){var b=this,c=null;if(b.path===null){var d=a.split("/");d.pop();b.path=d.length<1?".":d.join("/")}d=new XMLHttpRequest;d.addEventListener("load",function(d){d.target.responseText?c=b.parse(JSON.parse(d.target.responseText),f):b.dispatchEvent({type:"error",message:"Invalid file ["+a+"]"})},false);d.addEventListener("error",function(){b.dispatchEvent({type:"error",message:"Couldn't load URL ["+a+"]"})},false);d.open("GET",
+a,true);d.send(null);var f=new THREE.LoadingMonitor;f.addEventListener("load",function(){b.dispatchEvent({type:"load",content:c})});f.add(d)},parse:function(a,b){var c=this,d=new THREE.Geometry,f=a.scale!==void 0?1/a.scale:1;if(a.materials){d.materials=[];for(var e=0;e<a.materials.length;++e){var g=a.materials[e],m=function(a){a=Math.log(a)/Math.LN2;return Math.floor(a)==a},k=function(a){a=Math.log(a)/Math.LN2;return Math.pow(2,Math.round(a))},l=function(a,d,e,f,g,h){a[d]=new THREE.Texture;a[d].sourceFile=
+e;if(f){a[d].repeat.set(f[0],f[1]);if(f[0]!=1)a[d].wrapS=THREE.RepeatWrapping;if(f[1]!=1)a[d].wrapT=THREE.RepeatWrapping}g&&a[d].offset.set(g[0],g[1]);if(h){f={repeat:THREE.RepeatWrapping,mirror:THREE.MirroredRepeatWrapping};if(f[h[0]]!==void 0)a[d].wrapS=f[h[0]];if(f[h[1]]!==void 0)a[d].wrapT=f[h[1]]}var l=a[d],a=new THREE.ImageLoader;a.addEventListener("load",function(a){a=a.content;if(!m(a.width)||!m(a.height)){var b=k(a.width),c=k(a.height);l.image=document.createElement("canvas");l.image.width=
+b;l.image.height=c;l.image.getContext("2d").drawImage(a,0,0,b,c)}else l.image=a;l.needsUpdate=true});a.crossOrigin=c.crossOrigin;a.load(c.path+"/"+e);b&&b.add(a)},h=function(a){return(a[0]*255<<16)+(a[1]*255<<8)+a[2]*255},n="MeshLambertMaterial",j={color:15658734,opacity:1,map:null,lightMap:null,normalMap:null,wireframe:g.wireframe};if(g.shading){var o=g.shading.toLowerCase();o==="phong"?n="MeshPhongMaterial":o==="basic"&&(n="MeshBasicMaterial")}if(g.blending!==void 0&&THREE[g.blending]!==void 0)j.blending=
+THREE[g.blending];if(g.transparent!==void 0||g.opacity<1)j.transparent=g.transparent;if(g.depthTest!==void 0)j.depthTest=g.depthTest;if(g.depthWrite!==void 0)j.depthWrite=g.depthWrite;if(g.vertexColors!==void 0)if(g.vertexColors=="face")j.vertexColors=THREE.FaceColors;else if(g.vertexColors)j.vertexColors=THREE.VertexColors;if(g.colorDiffuse)j.color=h(g.colorDiffuse);else if(g.DbgColor)j.color=g.DbgColor;if(g.colorSpecular)j.specular=h(g.colorSpecular);if(g.colorAmbient)j.ambient=h(g.colorAmbient);
+if(g.transparency)j.opacity=g.transparency;if(g.specularCoef)j.shininess=g.specularCoef;g.mapDiffuse&&l(j,"map",g.mapDiffuse,g.mapDiffuseRepeat,g.mapDiffuseOffset,g.mapDiffuseWrap);g.mapLight&&l(j,"lightMap",g.mapLight,g.mapLightRepeat,g.mapLightOffset,g.mapLightWrap);g.mapNormal&&l(j,"normalMap",g.mapNormal,g.mapNormalRepeat,g.mapNormalOffset,g.mapNormalWrap);g.mapSpecular&&l(j,"specularMap",g.mapSpecular,g.mapSpecularRepeat,g.mapSpecularOffset,g.mapSpecularWrap);if(g.mapNormal){l=THREE.ShaderUtils.lib.normal;
+h=THREE.UniformsUtils.clone(l.uniforms);h.tNormal.texture=j.normalMap;if(g.mapNormalFactor)h.uNormalScale.value=g.mapNormalFactor;if(j.map){h.tDiffuse.texture=j.map;h.enableDiffuse.value=true}if(j.specularMap){h.tSpecular.texture=j.specularMap;h.enableSpecular.value=true}if(j.lightMap){h.tAO.texture=j.lightMap;h.enableAO.value=true}h.uDiffuseColor.value.setHex(j.color);h.uSpecularColor.value.setHex(j.specular);h.uAmbientColor.value.setHex(j.ambient);h.uShininess.value=j.shininess;if(j.opacity!==void 0)h.uOpacity.value=
+j.opacity;j=new THREE.ShaderMaterial({fragmentShader:l.fragmentShader,vertexShader:l.vertexShader,uniforms:h,lights:true,fog:true})}else j=new THREE[n](j);if(g.DbgName!==void 0)j.name=g.DbgName;d.materials[e]=j}}var g=a.faces,q=a.vertices,j=a.normals,l=a.colors,h=0;if(a.uvs)for(e=0;e<a.uvs.length;e++)a.uvs[e].length&&h++;for(e=0;e<h;e++){d.faceUvs[e]=[];d.faceVertexUvs[e]=[]}n=0;for(o=q.length;n<o;){var i=new THREE.Vector3;i.x=q[n++]*f;i.y=q[n++]*f;i.z=q[n++]*f;d.vertices.push(i)}n=0;for(o=g.length;n<
+o;){var p=g[n++],r=p&2,e=p&4,s=p&8,v=p&16,q=p&32,A=p&64,i=p&128;if(p&1){p=new THREE.Face4;p.a=g[n++];p.b=g[n++];p.c=g[n++];p.d=g[n++];var w=4}else{p=new THREE.Face3;p.a=g[n++];p.b=g[n++];p.c=g[n++];w=3}if(r){r=g[n++];p.materialIndex=r}var B=d.faces.length;if(e)for(e=0;e<h;e++){var x=a.uvs[e],r=g[n++],F=x[r*2],r=x[r*2+1];d.faceUvs[e][B]=new THREE.UV(F,r)}if(s)for(e=0;e<h;e++){for(var x=a.uvs[e],s=[],u=0;u<w;u++){r=g[n++];F=x[r*2];r=x[r*2+1];s[u]=new THREE.UV(F,r)}d.faceVertexUvs[e][B]=s}if(v){v=g[n++]*
+3;r=new THREE.Vector3;r.x=j[v++];r.y=j[v++];r.z=j[v];p.normal=r}if(q)for(e=0;e<w;e++){v=g[n++]*3;r=new THREE.Vector3;r.x=j[v++];r.y=j[v++];r.z=j[v];p.vertexNormals.push(r)}if(A){q=g[n++];p.color=new THREE.Color(l[q])}if(i)for(e=0;e<w;e++){q=g[n++];p.vertexColors.push(new THREE.Color(l[q]))}d.faces.push(p)}if(a.skinWeights){e=0;for(g=a.skinWeights.length;e<g;e=e+2)d.skinWeights.push(new THREE.Vector4(a.skinWeights[e],a.skinWeights[e+1],0,0))}if(a.skinIndices){e=0;for(g=a.skinIndices.length;e<g;e=e+
+2){j=0;d.skinIndices.push(new THREE.Vector4(a.skinIndices[e],a.skinIndices[e+1],j,0))}}d.bones=a.bones;d.animation=a.animation;if(a.morphTargets){e=0;for(g=a.morphTargets.length;e<g;e++){d.morphTargets[e]={};d.morphTargets[e].name=a.morphTargets[e].name;d.morphTargets[e].vertices=[];j=d.morphTargets[e].vertices;l=a.morphTargets[e].vertices;r=0;for(h=l.length;r<h;r=r+3){i=new THREE.Vector3;i.x=l[r]*f;i.y=l[r+1]*f;i.z=l[r+2]*f;j.push(i)}}}if(a.morphColors){e=0;for(g=a.morphColors.length;e<g;e++){d.morphColors[e]=
+{};d.morphColors[e].name=a.morphColors[e].name;d.morphColors[e].colors=[];f=d.morphColors[e].colors;l=a.morphColors[e].colors;j=0;for(h=l.length;j<h;j=j+3){n=new THREE.Color(16755200);n.setRGB(l[j],l[j+1],l[j+2]);f.push(n)}}}d.computeCentroids();d.computeFaceNormals();return d}};THREE.SceneLoader=function(){this.onLoadStart=function(){};this.onLoadProgress=function(){};this.onLoadComplete=function(){};this.callbackSync=function(){};this.callbackProgress=function(){}};
+THREE.SceneLoader.prototype.constructor=THREE.SceneLoader;THREE.SceneLoader.prototype.load=function(a,b){var c=this,d=new XMLHttpRequest;d.onreadystatechange=function(){if(d.readyState==4)if(d.status==200||d.status==0){var f=JSON.parse(d.responseText);c.createScene(f,b,a)}else console.error("THREE.SceneLoader: Couldn't load ["+a+"] ["+d.status+"]")};d.open("GET",a,true);d.overrideMimeType&&d.overrideMimeType("text/plain; charset=x-user-defined");d.setRequestHeader("Content-Type","text/plain");d.send(null)};
+THREE.SceneLoader.prototype.createScene=function(a,b,c){function d(a,b){return b=="relativeToHTML"?a:l+"/"+a}function f(){var a;for(j in t.objects)if(!y.objects[j]){r=t.objects[j];if(r.geometry!==void 0){if(D=y.geometries[r.geometry]){a=false;H=y.materials[r.materials[0]];(a=H instanceof THREE.ShaderMaterial)&&D.computeTangents();w=r.position;B=r.rotation;x=r.quaternion;F=r.scale;s=r.matrix;x=0;r.materials.length==0&&(H=new THREE.MeshFaceMaterial);r.materials.length>1&&(H=new THREE.MeshFaceMaterial);
+a=new THREE.Mesh(D,H);a.name=j;if(s){a.matrixAutoUpdate=false;a.matrix.set(s[0],s[1],s[2],s[3],s[4],s[5],s[6],s[7],s[8],s[9],s[10],s[11],s[12],s[13],s[14],s[15])}else{a.position.set(w[0],w[1],w[2]);if(x){a.quaternion.set(x[0],x[1],x[2],x[3]);a.useQuaternion=true}else a.rotation.set(B[0],B[1],B[2]);a.scale.set(F[0],F[1],F[2])}a.visible=r.visible;a.doubleSided=r.doubleSided;a.castShadow=r.castShadow;a.receiveShadow=r.receiveShadow;y.scene.add(a);y.objects[j]=a}}else{w=r.position;B=r.rotation;x=r.quaternion;
+F=r.scale;x=0;a=new THREE.Object3D;a.name=j;a.position.set(w[0],w[1],w[2]);if(x){a.quaternion.set(x[0],x[1],x[2],x[3]);a.useQuaternion=true}else a.rotation.set(B[0],B[1],B[2]);a.scale.set(F[0],F[1],F[2]);a.visible=r.visible!==void 0?r.visible:false;y.scene.add(a);y.objects[j]=a;y.empties[j]=a}}}function e(a){return function(b){y.geometries[a]=b;f();G=G-1;k.onLoadComplete();m()}}function g(a){return function(b){y.geometries[a]=b}}function m(){k.callbackProgress({totalModels:Q,totalTextures:O,loadedModels:Q-
+G,loadedTextures:O-N},y);k.onLoadProgress();G==0&&N==0&&b(y)}var k=this,l=THREE.Loader.prototype.extractUrlBase(c),h,n,j,o,q,i,p,r,s,v,A,w,B,x,F,u,z,D,H,P,L,t,E,G,N,Q,O,y;t=a;c=new THREE.BinaryLoader;E=new THREE.JSONLoader;N=G=0;y={scene:new THREE.Scene,geometries:{},materials:{},textures:{},objects:{},cameras:{},lights:{},fogs:{},empties:{}};if(t.transform){a=t.transform.position;v=t.transform.rotation;u=t.transform.scale;a&&y.scene.position.set(a[0],a[1],a[2]);v&&y.scene.rotation.set(v[0],v[1],
+v[2]);u&&y.scene.scale.set(u[0],u[1],u[2]);if(a||v||u){y.scene.updateMatrix();y.scene.updateMatrixWorld()}}a=function(){N=N-1;m();k.onLoadComplete()};for(q in t.cameras){u=t.cameras[q];u.type=="perspective"?P=new THREE.PerspectiveCamera(u.fov,u.aspect,u.near,u.far):u.type=="ortho"&&(P=new THREE.OrthographicCamera(u.left,u.right,u.top,u.bottom,u.near,u.far));w=u.position;v=u.target;u=u.up;P.position.set(w[0],w[1],w[2]);P.target=new THREE.Vector3(v[0],v[1],v[2]);u&&P.up.set(u[0],u[1],u[2]);y.cameras[q]=
+P}for(o in t.lights){v=t.lights[o];q=v.color!==void 0?v.color:16777215;P=v.intensity!==void 0?v.intensity:1;if(v.type=="directional"){w=v.direction;A=new THREE.DirectionalLight(q,P);A.position.set(w[0],w[1],w[2]);A.position.normalize()}else if(v.type=="point"){w=v.position;A=v.distance;A=new THREE.PointLight(q,P,A);A.position.set(w[0],w[1],w[2])}else v.type=="ambient"&&(A=new THREE.AmbientLight(q));y.scene.add(A);y.lights[o]=A}for(i in t.fogs){o=t.fogs[i];o.type=="linear"?L=new THREE.Fog(0,o.near,
+o.far):o.type=="exp2"&&(L=new THREE.FogExp2(0,o.density));u=o.color;L.color.setRGB(u[0],u[1],u[2]);y.fogs[i]=L}if(y.cameras&&t.defaults.camera)y.currentCamera=y.cameras[t.defaults.camera];if(y.fogs&&t.defaults.fog)y.scene.fog=y.fogs[t.defaults.fog];u=t.defaults.bgcolor;y.bgColor=new THREE.Color;y.bgColor.setRGB(u[0],u[1],u[2]);y.bgColorAlpha=t.defaults.bgalpha;for(h in t.geometries){i=t.geometries[h];if(i.type=="bin_mesh"||i.type=="ascii_mesh"){G=G+1;k.onLoadStart()}}Q=G;for(h in t.geometries){i=
+t.geometries[h];if(i.type=="cube"){D=new THREE.CubeGeometry(i.width,i.height,i.depth,i.segmentsWidth,i.segmentsHeight,i.segmentsDepth,null,i.flipped,i.sides);y.geometries[h]=D}else if(i.type=="plane"){D=new THREE.PlaneGeometry(i.width,i.height,i.segmentsWidth,i.segmentsHeight);y.geometries[h]=D}else if(i.type=="sphere"){D=new THREE.SphereGeometry(i.radius,i.segmentsWidth,i.segmentsHeight);y.geometries[h]=D}else if(i.type=="cylinder"){D=new THREE.CylinderGeometry(i.topRad,i.botRad,i.height,i.radSegs,
+i.heightSegs);y.geometries[h]=D}else if(i.type=="torus"){D=new THREE.TorusGeometry(i.radius,i.tube,i.segmentsR,i.segmentsT);y.geometries[h]=D}else if(i.type=="icosahedron"){D=new THREE.IcosahedronGeometry(i.radius,i.subdivisions);y.geometries[h]=D}else if(i.type=="bin_mesh")c.load(d(i.url,t.urlBaseType),e(h));else if(i.type=="ascii_mesh")E.load(d(i.url,t.urlBaseType),e(h));else if(i.type=="embedded_mesh"){i=t.embeds[i.id];i.metadata=t.metadata;i&&E.createModel(i,g(h),"")}}for(p in t.textures){h=t.textures[p];
+if(h.url instanceof Array){N=N+h.url.length;for(i=0;i<h.url.length;i++)k.onLoadStart()}else{N=N+1;k.onLoadStart()}}O=N;for(p in t.textures){h=t.textures[p];if(h.mapping!=void 0&&THREE[h.mapping]!=void 0)h.mapping=new THREE[h.mapping];if(h.url instanceof Array){i=[];for(L=0;L<h.url.length;L++)i[L]=d(h.url[L],t.urlBaseType);i=THREE.ImageUtils.loadTextureCube(i,h.mapping,a)}else{i=THREE.ImageUtils.loadTexture(d(h.url,t.urlBaseType),h.mapping,a);if(THREE[h.minFilter]!=void 0)i.minFilter=THREE[h.minFilter];
+if(THREE[h.magFilter]!=void 0)i.magFilter=THREE[h.magFilter];if(h.repeat){i.repeat.set(h.repeat[0],h.repeat[1]);if(h.repeat[0]!=1)i.wrapS=THREE.RepeatWrapping;if(h.repeat[1]!=1)i.wrapT=THREE.RepeatWrapping}h.offset&&i.offset.set(h.offset[0],h.offset[1]);if(h.wrap){L={repeat:THREE.RepeatWrapping,mirror:THREE.MirroredRepeatWrapping};if(L[h.wrap[0]]!==void 0)i.wrapS=L[h.wrap[0]];if(L[h.wrap[1]]!==void 0)i.wrapT=L[h.wrap[1]]}}y.textures[p]=i}for(n in t.materials){s=t.materials[n];for(z in s.parameters)if(z==
+"envMap"||z=="map"||z=="lightMap")s.parameters[z]=y.textures[s.parameters[z]];else if(z=="shading")s.parameters[z]=s.parameters[z]=="flat"?THREE.FlatShading:THREE.SmoothShading;else if(z=="blending")s.parameters[z]=THREE[s.parameters[z]]?THREE[s.parameters[z]]:THREE.NormalBlending;else if(z=="combine")s.parameters[z]=s.parameters[z]=="MixOperation"?THREE.MixOperation:THREE.MultiplyOperation;else if(z=="vertexColors")if(s.parameters[z]=="face")s.parameters[z]=THREE.FaceColors;else if(s.parameters[z])s.parameters[z]=
+THREE.VertexColors;if(s.parameters.opacity!==void 0&&s.parameters.opacity<1)s.parameters.transparent=true;if(s.parameters.normalMap){p=THREE.ShaderUtils.lib.normal;a=THREE.UniformsUtils.clone(p.uniforms);h=s.parameters.color;i=s.parameters.specular;L=s.parameters.ambient;c=s.parameters.shininess;a.tNormal.texture=y.textures[s.parameters.normalMap];if(s.parameters.normalMapFactor)a.uNormalScale.value=s.parameters.normalMapFactor;if(s.parameters.map){a.tDiffuse.texture=s.parameters.map;a.enableDiffuse.value=
+true}if(s.parameters.lightMap){a.tAO.texture=s.parameters.lightMap;a.enableAO.value=true}if(s.parameters.specularMap){a.tSpecular.texture=y.textures[s.parameters.specularMap];a.enableSpecular.value=true}a.uDiffuseColor.value.setHex(h);a.uSpecularColor.value.setHex(i);a.uAmbientColor.value.setHex(L);a.uShininess.value=c;if(s.parameters.opacity)a.uOpacity.value=s.parameters.opacity;H=new THREE.ShaderMaterial({fragmentShader:p.fragmentShader,vertexShader:p.vertexShader,uniforms:a,lights:true,fog:true})}else H=
+new THREE[s.type](s.parameters);y.materials[n]=H}f();k.callbackSync(y);m()};THREE.TextureLoader=function(){THREE.EventTarget.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=true;b.dispatchEvent({type:"load",content:a})},false);c.addEventListener("error",function(){b.dispatchEvent({type:"error",message:"Couldn't load URL ["+a+"]"})},false);if(b.crossOrigin)c.crossOrigin=b.crossOrigin;c.src=a}};
 THREE.Material=function(a){a=a||{};this.id=THREE.MaterialCount++;this.name="";this.opacity=a.opacity!==void 0?a.opacity:1;this.transparent=a.transparent!==void 0?a.transparent:false;this.blending=a.blending!==void 0?a.blending:THREE.NormalBlending;this.blendSrc=a.blendSrc!==void 0?a.blendSrc:THREE.SrcAlphaFactor;this.blendDst=a.blendDst!==void 0?a.blendDst:THREE.OneMinusSrcAlphaFactor;this.blendEquation=a.blendEquation!==void 0?a.blendEquation:THREE.AddEquation;this.depthTest=a.depthTest!==void 0?
 a.depthTest:true;this.depthWrite=a.depthWrite!==void 0?a.depthWrite:true;this.polygonOffset=a.polygonOffset!==void 0?a.polygonOffset:false;this.polygonOffsetFactor=a.polygonOffsetFactor!==void 0?a.polygonOffsetFactor:0;this.polygonOffsetUnits=a.polygonOffsetUnits!==void 0?a.polygonOffsetUnits:0;this.alphaTest=a.alphaTest!==void 0?a.alphaTest:0;this.overdraw=a.overdraw!==void 0?a.overdraw:false;this.needsUpdate=this.visible=true};THREE.MaterialCount=0;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.AdditiveAlphaBlending=5;THREE.CustomBlending=6;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;
@@ -172,16 +194,15 @@ a.morphTargets:false;this.morphNormals=a.morphNormals!==void 0?a.morphNormals:fa
 THREE.MeshDepthMaterial.prototype=new THREE.Material;THREE.MeshDepthMaterial.prototype.constructor=THREE.MeshDepthMaterial;THREE.MeshNormalMaterial=function(a){THREE.Material.call(this,a);a=a||{};this.shading=a.shading?a.shading:THREE.FlatShading;this.wireframe=a.wireframe?a.wireframe:false;this.wireframeLinewidth=a.wireframeLinewidth?a.wireframeLinewidth:1};THREE.MeshNormalMaterial.prototype=new THREE.Material;THREE.MeshNormalMaterial.prototype.constructor=THREE.MeshNormalMaterial;
 THREE.MeshFaceMaterial=function(){};THREE.ParticleBasicMaterial=function(a){THREE.Material.call(this,a);a=a||{};this.color=a.color!==void 0?new THREE.Color(a.color):new THREE.Color(16777215);this.map=a.map!==void 0?a.map:null;this.size=a.size!==void 0?a.size:1;this.sizeAttenuation=a.sizeAttenuation!==void 0?a.sizeAttenuation:true;this.vertexColors=a.vertexColors!==void 0?a.vertexColors:false;this.fog=a.fog!==void 0?a.fog:true};THREE.ParticleBasicMaterial.prototype=new THREE.Material;
 THREE.ParticleBasicMaterial.prototype.constructor=THREE.ParticleBasicMaterial;THREE.ParticleCanvasMaterial=function(a){THREE.Material.call(this,a);a=a||{};this.color=a.color!==void 0?new THREE.Color(a.color):new THREE.Color(16777215);this.program=a.program!==void 0?a.program:function(){}};THREE.ParticleCanvasMaterial.prototype=new THREE.Material;THREE.ParticleCanvasMaterial.prototype.constructor=THREE.ParticleCanvasMaterial;
-THREE.Texture=function(a,b,c,d,e,f,g,k){this.id=THREE.TextureCount++;this.image=a;this.mapping=b!==void 0?b:new THREE.UVMapping;this.wrapS=c!==void 0?c:THREE.ClampToEdgeWrapping;this.wrapT=d!==void 0?d:THREE.ClampToEdgeWrapping;this.magFilter=e!==void 0?e:THREE.LinearFilter;this.minFilter=f!==void 0?f:THREE.LinearMipMapLinearFilter;this.format=g!==void 0?g:THREE.RGBAFormat;this.type=k!==void 0?k:THREE.UnsignedByteType;this.offset=new THREE.Vector2(0,0);this.repeat=new THREE.Vector2(1,1);this.generateMipmaps=
+THREE.Texture=function(a,b,c,d,f,e,g,m){this.id=THREE.TextureCount++;this.image=a;this.mapping=b!==void 0?b:new THREE.UVMapping;this.wrapS=c!==void 0?c:THREE.ClampToEdgeWrapping;this.wrapT=d!==void 0?d:THREE.ClampToEdgeWrapping;this.magFilter=f!==void 0?f:THREE.LinearFilter;this.minFilter=e!==void 0?e:THREE.LinearMipMapLinearFilter;this.format=g!==void 0?g:THREE.RGBAFormat;this.type=m!==void 0?m:THREE.UnsignedByteType;this.offset=new THREE.Vector2(0,0);this.repeat=new THREE.Vector2(1,1);this.generateMipmaps=
 true;this.needsUpdate=this.premultiplyAlpha=false;this.onUpdate=null};THREE.Texture.prototype={constructor:THREE.Texture,clone:function(){var a=new THREE.Texture(this.image,this.mapping,this.wrapS,this.wrapT,this.magFilter,this.minFilter,this.format,this.type);a.offset.copy(this.offset);a.repeat.copy(this.repeat);return a}};THREE.TextureCount=0;THREE.MultiplyOperation=0;THREE.MixOperation=1;THREE.UVMapping=function(){};THREE.CubeReflectionMapping=function(){};THREE.CubeRefractionMapping=function(){};
-THREE.SphericalReflectionMapping=function(){};THREE.SphericalRefractionMapping=function(){};THREE.RepeatWrapping=0;THREE.ClampToEdgeWrapping=1;THREE.MirroredRepeatWrapping=2;THREE.NearestFilter=3;THREE.NearestMipMapNearestFilter=4;THREE.NearestMipMapLinearFilter=5;THREE.LinearFilter=6;THREE.LinearMipMapNearestFilter=7;THREE.LinearMipMapLinearFilter=8;THREE.ByteType=9;THREE.UnsignedByteType=10;THREE.ShortType=11;THREE.UnsignedShortType=12;THREE.IntType=13;THREE.UnsignedIntType=14;THREE.FloatType=15;
-THREE.AlphaFormat=16;THREE.RGBFormat=17;THREE.RGBAFormat=18;THREE.LuminanceFormat=19;THREE.LuminanceAlphaFormat=20;THREE.DataTexture=function(a,b,c,d,e,f,g,k,m,j){THREE.Texture.call(this,null,f,g,k,m,j,d,e);this.image={data:a,width:b,height:c}};THREE.DataTexture.prototype=new THREE.Texture;THREE.DataTexture.prototype.constructor=THREE.DataTexture;
+THREE.SphericalReflectionMapping=function(){};THREE.SphericalRefractionMapping=function(){};THREE.RepeatWrapping=0;THREE.ClampToEdgeWrapping=1;THREE.MirroredRepeatWrapping=2;THREE.NearestFilter=3;THREE.NearestMipMapNearestFilter=4;THREE.NearestMipMapLinearFilter=5;THREE.LinearFilter=6;THREE.LinearMipMapNearestFilter=7;THREE.LinearMipMapLinearFilter=8;THREE.UnsignedByteType=9;THREE.ByteType=10;THREE.ShortType=11;THREE.UnsignedShortType=12;THREE.IntType=13;THREE.UnsignedIntType=14;THREE.FloatType=15;
+THREE.UnsignedShort4444Type=16;THREE.UnsignedShort5551Type=17;THREE.UnsignedShort565Type=18;THREE.AlphaFormat=19;THREE.RGBFormat=20;THREE.RGBAFormat=21;THREE.LuminanceFormat=22;THREE.LuminanceAlphaFormat=23;THREE.DataTexture=function(a,b,c,d,f,e,g,m,k,l){THREE.Texture.call(this,null,e,g,m,k,l,d,f);this.image={data:a,width:b,height:c}};THREE.DataTexture.prototype=new THREE.Texture;THREE.DataTexture.prototype.constructor=THREE.DataTexture;
 THREE.DataTexture.prototype.clone=function(){var a=new THREE.DataTexture(this.image.data,this.image.width,this.image.height,this.format,this.type,this.mapping,this.wrapS,this.wrapT,this.magFilter,this.minFilter);a.offset.copy(this.offset);a.repeat.copy(this.repeat);return a};THREE.Particle=function(a){THREE.Object3D.call(this);this.material=a};THREE.Particle.prototype=new THREE.Object3D;THREE.Particle.prototype.constructor=THREE.Particle;
 THREE.Line=function(a,b,c){THREE.Object3D.call(this);this.geometry=a;this.material=b!==void 0?b:new THREE.LineBasicMaterial({color:Math.random()*16777215});this.type=c!==void 0?c:THREE.LineStrip;this.geometry&&(this.geometry.boundingSphere||this.geometry.computeBoundingSphere())};THREE.LineStrip=0;THREE.LinePieces=1;THREE.Line.prototype=new THREE.Object3D;THREE.Line.prototype.constructor=THREE.Line;
 THREE.Mesh=function(a,b){THREE.Object3D.call(this);this.geometry=a;this.material=b!==void 0?b:new THREE.MeshBasicMaterial({color:Math.random()*16777215,wireframe:true});if(this.geometry){this.geometry.boundingSphere||this.geometry.computeBoundingSphere();this.boundRadius=a.boundingSphere.radius;if(this.geometry.morphTargets.length){this.morphTargetBase=-1;this.morphTargetForcedOrder=[];this.morphTargetInfluences=[];this.morphTargetDictionary={};for(var c=0;c<this.geometry.morphTargets.length;c++){this.morphTargetInfluences.push(0);
-this.morphTargetDictionary[this.geometry.morphTargets[c].name]=c}}}};THREE.Mesh.prototype=new THREE.Object3D;THREE.Mesh.prototype.constructor=THREE.Mesh;THREE.Mesh.prototype.supr=THREE.Object3D.prototype;THREE.Mesh.prototype.getMorphTargetIndexByName=function(a){if(this.morphTargetDictionary[a]!==void 0)return this.morphTargetDictionary[a];console.log("THREE.Mesh.getMorphTargetIndexByName: morph target "+a+" does not exist. Returning 0.");return 0};
-THREE.Bone=function(a){THREE.Object3D.call(this);this.skin=a;this.skinMatrix=new THREE.Matrix4};THREE.Bone.prototype=new THREE.Object3D;THREE.Bone.prototype.constructor=THREE.Bone;THREE.Bone.prototype.supr=THREE.Object3D.prototype;
-THREE.Bone.prototype.update=function(a,b){this.matrixAutoUpdate&&(b=b|this.updateMatrix());if(b||this.matrixWorldNeedsUpdate){a?this.skinMatrix.multiply(a,this.matrix):this.skinMatrix.copy(this.matrix);this.matrixWorldNeedsUpdate=false;b=true}var c,d=this.children.length;for(c=0;c<d;c++)this.children[c].update(this.skinMatrix,b)};
+this.morphTargetDictionary[this.geometry.morphTargets[c].name]=c}}}};THREE.Mesh.prototype=new THREE.Object3D;THREE.Mesh.prototype.constructor=THREE.Mesh;THREE.Mesh.prototype.getMorphTargetIndexByName=function(a){if(this.morphTargetDictionary[a]!==void 0)return this.morphTargetDictionary[a];console.log("THREE.Mesh.getMorphTargetIndexByName: morph target "+a+" does not exist. Returning 0.");return 0};THREE.Bone=function(a){THREE.Object3D.call(this);this.skin=a;this.skinMatrix=new THREE.Matrix4};
+THREE.Bone.prototype=new THREE.Object3D;THREE.Bone.prototype.constructor=THREE.Bone;THREE.Bone.prototype.update=function(a,b){this.matrixAutoUpdate&&(b=b|this.updateMatrix());if(b||this.matrixWorldNeedsUpdate){a?this.skinMatrix.multiply(a,this.matrix):this.skinMatrix.copy(this.matrix);this.matrixWorldNeedsUpdate=false;b=true}var c,d=this.children.length;for(c=0;c<d;c++)this.children[c].update(this.skinMatrix,b)};
 THREE.Sprite=function(a){THREE.Object3D.call(this);this.color=a.color!==void 0?new THREE.Color(a.color):new THREE.Color(16777215);this.map=a.map!==void 0?a.map:new THREE.Texture;this.blending=a.blending!==void 0?a.blending:THREE.NormalBlending;this.blendSrc=a.blendSrc!==void 0?a.blendSrc:THREE.SrcAlphaFactor;this.blendDst=a.blendDst!==void 0?a.blendDst:THREE.OneMinusSrcAlphaFactor;this.blendEquation=a.blendEquation!==void 0?a.blendEquation:THREE.AddEquation;this.useScreenCoordinates=a.useScreenCoordinates!==
 void 0?a.useScreenCoordinates:true;this.mergeWith3D=a.mergeWith3D!==void 0?a.mergeWith3D:!this.useScreenCoordinates;this.affectedByDistance=a.affectedByDistance!==void 0?a.affectedByDistance:!this.useScreenCoordinates;this.scaleByViewport=a.scaleByViewport!==void 0?a.scaleByViewport:!this.affectedByDistance;this.alignment=a.alignment instanceof THREE.Vector2?a.alignment:THREE.SpriteAlignment.center;this.rotation3d=this.rotation;this.rotation=0;this.opacity=1;this.uvOffset=new THREE.Vector2(0,0);this.uvScale=
 new THREE.Vector2(1,1)};THREE.Sprite.prototype=new THREE.Object3D;THREE.Sprite.prototype.constructor=THREE.Sprite;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.boundRadiusScale=Math.max(this.scale.x,this.scale.y)}this.matrixWorldNeedsUpdate=true};THREE.SpriteAlignment={};
@@ -189,35 +210,35 @@ THREE.SpriteAlignment.topLeft=new THREE.Vector2(1,-1);THREE.SpriteAlignment.topC
 THREE.SpriteAlignment.bottomRight=new THREE.Vector2(-1,1);THREE.Scene=function(){THREE.Object3D.call(this);this.overrideMaterial=this.fog=null;this.matrixAutoUpdate=false;this.__objects=[];this.__lights=[];this.__objectsAdded=[];this.__objectsRemoved=[]};THREE.Scene.prototype=new THREE.Object3D;THREE.Scene.prototype.constructor=THREE.Scene;
 THREE.Scene.prototype.__addObject=function(a){if(a instanceof THREE.Light)this.__lights.indexOf(a)===-1&&this.__lights.push(a);else if(!(a instanceof THREE.Camera||a instanceof THREE.Bone)&&this.__objects.indexOf(a)===-1){this.__objects.push(a);this.__objectsAdded.push(a);var b=this.__objectsRemoved.indexOf(a);b!==-1&&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);b!==-1&&this.__lights.splice(b,1)}else if(!(a instanceof THREE.Camera)){b=this.__objects.indexOf(a);if(b!==-1){this.__objects.splice(b,1);this.__objectsRemoved.push(a);b=this.__objectsAdded.indexOf(a);b!==-1&&this.__objectsAdded.splice(b,1)}}for(b=0;b<a.children.length;b++)this.__removeObject(a.children[b])};
-THREE.CanvasRenderer=function(a){function b(a){if(s!=a)l.globalAlpha=s=a}function c(a){if(z!=a){switch(a){case THREE.NormalBlending:l.globalCompositeOperation="source-over";break;case THREE.AdditiveBlending:l.globalCompositeOperation="lighter"}z=a}}function d(a){if(A!=a)l.strokeStyle=A=a}function e(a){if(v!=a)l.fillStyle=v=a}console.log("THREE.CanvasRenderer",THREE.REVISION);var a=a||{},f=this,g,k,m,j=new THREE.Projector,h=a.canvas!==void 0?a.canvas:document.createElement("canvas"),i,o,n,p,l=h.getContext("2d"),
-q=new THREE.Color(0),u=0,s=1,z=0,A=null,v=null,D=null,x=null,G=null,t,y,C,L,Q=new THREE.RenderableVertex,N=new THREE.RenderableVertex,r,E,F,H,P,O,w,U,M,T,S,W,B=new THREE.Color,J=new THREE.Color,I=new THREE.Color,K=new THREE.Color,R=new THREE.Color,ja=[],da=[],ea,fa,ca,ka,za,Aa,Ba,Ca,Da,Ea,la=new THREE.Rectangle,$=new THREE.Rectangle,Z=new THREE.Rectangle,xa=false,Y=new THREE.Color,ma=new THREE.Color,na=new THREE.Color,V=new THREE.Vector3,ra,sa,ya,aa,ta,ua,a=16;ra=document.createElement("canvas");
-ra.width=ra.height=2;sa=ra.getContext("2d");sa.fillStyle="rgba(0,0,0,1)";sa.fillRect(0,0,2,2);ya=sa.getImageData(0,0,2,2);aa=ya.data;ta=document.createElement("canvas");ta.width=ta.height=a;ua=ta.getContext("2d");ua.translate(-a/2,-a/2);ua.scale(a,a);a--;this.domElement=h;this.sortElements=this.sortObjects=this.autoClear=true;this.info={render:{vertices:0,faces:0}};this.setSize=function(a,b){i=a;o=b;n=Math.floor(i/2);p=Math.floor(o/2);h.width=i;h.height=o;la.set(-n,-p,n,p);$.set(-n,-p,n,p);s=1;z=
-0;G=x=D=v=A=null};this.setClearColor=function(a,b){q.copy(a);u=b!==void 0?b:1;$.set(-n,-p,n,p)};this.setClearColorHex=function(a,b){q.setHex(a);u=b!==void 0?b:1;$.set(-n,-p,n,p)};this.clear=function(){l.setTransform(1,0,0,-1,n,p);if(!$.isEmpty()){$.minSelf(la);$.inflate(2);u<1&&l.clearRect(Math.floor($.getX()),Math.floor($.getY()),Math.floor($.getWidth()),Math.floor($.getHeight()));if(u>0){c(THREE.NormalBlending);b(1);e("rgba("+Math.floor(q.r*255)+","+Math.floor(q.g*255)+","+Math.floor(q.b*255)+","+
-u+")");l.fillRect(Math.floor($.getX()),Math.floor($.getY()),Math.floor($.getWidth()),Math.floor($.getHeight()))}$.empty()}};this.render=function(a,h){function i(a){var b,c,d,e;Y.setRGB(0,0,0);ma.setRGB(0,0,0);na.setRGB(0,0,0);b=0;for(c=a.length;b<c;b++){d=a[b];e=d.color;if(d instanceof THREE.AmbientLight){Y.r=Y.r+e.r;Y.g=Y.g+e.g;Y.b=Y.b+e.b}else if(d instanceof THREE.DirectionalLight){ma.r=ma.r+e.r;ma.g=ma.g+e.g;ma.b=ma.b+e.b}else if(d instanceof THREE.PointLight){na.r=na.r+e.r;na.g=na.g+e.g;na.b=
-na.b+e.b}}}function o(a,b,c,d){var e,f,g,h,j,l;e=0;for(f=a.length;e<f;e++){g=a[e];h=g.color;if(g instanceof THREE.DirectionalLight){j=g.matrixWorld.getPosition();l=c.dot(j);if(!(l<=0)){l=l*g.intensity;d.r=d.r+h.r*l;d.g=d.g+h.g*l;d.b=d.b+h.b*l}}else if(g instanceof THREE.PointLight){j=g.matrixWorld.getPosition();l=c.dot(V.sub(j,b).normalize());if(!(l<=0)){l=l*(g.distance==0?1:1-Math.min(b.distanceTo(j)/g.distance,1));if(l!=0){l=l*g.intensity;d.r=d.r+h.r*l;d.g=d.g+h.g*l;d.b=d.b+h.b*l}}}}}function q(a,
-f,g){b(g.opacity);c(g.blending);var h,j,m,k,o,i;if(g instanceof THREE.ParticleBasicMaterial){if(g.map){k=g.map.image;o=k.width>>1;i=k.height>>1;g=f.scale.x*n;m=f.scale.y*p;h=g*o;j=m*i;Z.set(a.x-h,a.y-j,a.x+h,a.y+j);if(la.intersects(Z)){l.save();l.translate(a.x,a.y);l.rotate(-f.rotation);l.scale(g,-m);l.translate(-o,-i);l.drawImage(k,0,0);l.restore()}}}else if(g instanceof THREE.ParticleCanvasMaterial){h=f.scale.x*n;j=f.scale.y*p;Z.set(a.x-h,a.y-j,a.x+h,a.y+j);if(la.intersects(Z)){d(g.color.getContextStyle());
-e(g.color.getContextStyle());l.save();l.translate(a.x,a.y);l.rotate(-f.rotation);l.scale(h,j);g.program(l);l.restore()}}}function s(a,e,f,g){b(g.opacity);c(g.blending);l.beginPath();l.moveTo(a.positionScreen.x,a.positionScreen.y);l.lineTo(e.positionScreen.x,e.positionScreen.y);l.closePath();if(g instanceof THREE.LineBasicMaterial){a=g.linewidth;if(D!=a)l.lineWidth=D=a;a=g.linecap;if(x!=a)l.lineCap=x=a;a=g.linejoin;if(G!=a)l.lineJoin=G=a;d(g.color.getContextStyle());l.stroke();Z.inflate(g.linewidth*
-2)}}function u(a,d,e,g,l,j,k,i){f.info.render.vertices=f.info.render.vertices+3;f.info.render.faces++;b(i.opacity);c(i.blending);r=a.positionScreen.x;E=a.positionScreen.y;F=d.positionScreen.x;H=d.positionScreen.y;P=e.positionScreen.x;O=e.positionScreen.y;z(r,E,F,H,P,O);if(i instanceof THREE.MeshBasicMaterial)if(i.map){if(i.map.mapping instanceof THREE.UVMapping){ka=k.uvs[0];Fa(r,E,F,H,P,O,ka[g].u,ka[g].v,ka[l].u,ka[l].v,ka[j].u,ka[j].v,i.map)}}else if(i.envMap){if(i.envMap.mapping instanceof THREE.SphericalReflectionMapping){a=
-h.matrixWorldInverse;V.copy(k.vertexNormalsWorld[g]);za=(V.x*a.elements[0]+V.y*a.elements[4]+V.z*a.elements[8])*0.5+0.5;Aa=-(V.x*a.elements[1]+V.y*a.elements[5]+V.z*a.elements[9])*0.5+0.5;V.copy(k.vertexNormalsWorld[l]);Ba=(V.x*a.elements[0]+V.y*a.elements[4]+V.z*a.elements[8])*0.5+0.5;Ca=-(V.x*a.elements[1]+V.y*a.elements[5]+V.z*a.elements[9])*0.5+0.5;V.copy(k.vertexNormalsWorld[j]);Da=(V.x*a.elements[0]+V.y*a.elements[4]+V.z*a.elements[8])*0.5+0.5;Ea=-(V.x*a.elements[1]+V.y*a.elements[5]+V.z*a.elements[9])*
-0.5+0.5;Fa(r,E,F,H,P,O,za,Aa,Ba,Ca,Da,Ea,i.envMap)}}else i.wireframe?ha(i.color,i.wireframeLinewidth,i.wireframeLinecap,i.wireframeLinejoin):ga(i.color);else if(i instanceof THREE.MeshLambertMaterial)if(xa)if(!i.wireframe&&i.shading==THREE.SmoothShading&&k.vertexNormalsWorld.length==3){J.r=I.r=K.r=Y.r;J.g=I.g=K.g=Y.g;J.b=I.b=K.b=Y.b;o(m,k.v1.positionWorld,k.vertexNormalsWorld[0],J);o(m,k.v2.positionWorld,k.vertexNormalsWorld[1],I);o(m,k.v3.positionWorld,k.vertexNormalsWorld[2],K);J.r=Math.max(0,Math.min(i.color.r*
-J.r,1));J.g=Math.max(0,Math.min(i.color.g*J.g,1));J.b=Math.max(0,Math.min(i.color.b*J.b,1));I.r=Math.max(0,Math.min(i.color.r*I.r,1));I.g=Math.max(0,Math.min(i.color.g*I.g,1));I.b=Math.max(0,Math.min(i.color.b*I.b,1));K.r=Math.max(0,Math.min(i.color.r*K.r,1));K.g=Math.max(0,Math.min(i.color.g*K.g,1));K.b=Math.max(0,Math.min(i.color.b*K.b,1));R.r=(I.r+K.r)*0.5;R.g=(I.g+K.g)*0.5;R.b=(I.b+K.b)*0.5;ca=va(J,I,K,R);pa(r,E,F,H,P,O,0,0,1,0,0,1,ca)}else{B.r=Y.r;B.g=Y.g;B.b=Y.b;o(m,k.centroidWorld,k.normalWorld,
-B);B.r=Math.max(0,Math.min(i.color.r*B.r,1));B.g=Math.max(0,Math.min(i.color.g*B.g,1));B.b=Math.max(0,Math.min(i.color.b*B.b,1));i.wireframe?ha(B,i.wireframeLinewidth,i.wireframeLinecap,i.wireframeLinejoin):ga(B)}else i.wireframe?ha(i.color,i.wireframeLinewidth,i.wireframeLinecap,i.wireframeLinejoin):ga(i.color);else if(i instanceof THREE.MeshDepthMaterial){ea=h.near;fa=h.far;J.r=J.g=J.b=1-oa(a.positionScreen.z,ea,fa);I.r=I.g=I.b=1-oa(d.positionScreen.z,ea,fa);K.r=K.g=K.b=1-oa(e.positionScreen.z,
-ea,fa);R.r=(I.r+K.r)*0.5;R.g=(I.g+K.g)*0.5;R.b=(I.b+K.b)*0.5;ca=va(J,I,K,R);pa(r,E,F,H,P,O,0,0,1,0,0,1,ca)}else if(i instanceof THREE.MeshNormalMaterial){B.r=qa(k.normalWorld.x);B.g=qa(k.normalWorld.y);B.b=qa(k.normalWorld.z);i.wireframe?ha(B,i.wireframeLinewidth,i.wireframeLinecap,i.wireframeLinejoin):ga(B)}}function v(a,d,e,g,l,j,k,i,n){f.info.render.vertices=f.info.render.vertices+4;f.info.render.faces++;b(i.opacity);c(i.blending);if(i.map||i.envMap){u(a,d,g,0,1,3,k,i,n);u(l,e,j,1,2,3,k,i,n)}else{r=
-a.positionScreen.x;E=a.positionScreen.y;F=d.positionScreen.x;H=d.positionScreen.y;P=e.positionScreen.x;O=e.positionScreen.y;w=g.positionScreen.x;U=g.positionScreen.y;M=l.positionScreen.x;T=l.positionScreen.y;S=j.positionScreen.x;W=j.positionScreen.y;if(i instanceof THREE.MeshBasicMaterial){A(r,E,F,H,P,O,w,U);i.wireframe?ha(i.color,i.wireframeLinewidth,i.wireframeLinecap,i.wireframeLinejoin):ga(i.color)}else if(i instanceof THREE.MeshLambertMaterial)if(xa)if(!i.wireframe&&i.shading==THREE.SmoothShading&&
-k.vertexNormalsWorld.length==4){J.r=I.r=K.r=R.r=Y.r;J.g=I.g=K.g=R.g=Y.g;J.b=I.b=K.b=R.b=Y.b;o(m,k.v1.positionWorld,k.vertexNormalsWorld[0],J);o(m,k.v2.positionWorld,k.vertexNormalsWorld[1],I);o(m,k.v4.positionWorld,k.vertexNormalsWorld[3],K);o(m,k.v3.positionWorld,k.vertexNormalsWorld[2],R);J.r=Math.max(0,Math.min(i.color.r*J.r,1));J.g=Math.max(0,Math.min(i.color.g*J.g,1));J.b=Math.max(0,Math.min(i.color.b*J.b,1));I.r=Math.max(0,Math.min(i.color.r*I.r,1));I.g=Math.max(0,Math.min(i.color.g*I.g,1));
-I.b=Math.max(0,Math.min(i.color.b*I.b,1));K.r=Math.max(0,Math.min(i.color.r*K.r,1));K.g=Math.max(0,Math.min(i.color.g*K.g,1));K.b=Math.max(0,Math.min(i.color.b*K.b,1));R.r=Math.max(0,Math.min(i.color.r*R.r,1));R.g=Math.max(0,Math.min(i.color.g*R.g,1));R.b=Math.max(0,Math.min(i.color.b*R.b,1));ca=va(J,I,K,R);z(r,E,F,H,w,U);pa(r,E,F,H,w,U,0,0,1,0,0,1,ca);z(M,T,P,O,S,W);pa(M,T,P,O,S,W,1,0,1,1,0,1,ca)}else{B.r=Y.r;B.g=Y.g;B.b=Y.b;o(m,k.centroidWorld,k.normalWorld,B);B.r=Math.max(0,Math.min(i.color.r*
-B.r,1));B.g=Math.max(0,Math.min(i.color.g*B.g,1));B.b=Math.max(0,Math.min(i.color.b*B.b,1));A(r,E,F,H,P,O,w,U);i.wireframe?ha(B,i.wireframeLinewidth,i.wireframeLinecap,i.wireframeLinejoin):ga(B)}else{A(r,E,F,H,P,O,w,U);i.wireframe?ha(i.color,i.wireframeLinewidth,i.wireframeLinecap,i.wireframeLinejoin):ga(i.color)}else if(i instanceof THREE.MeshNormalMaterial){B.r=qa(k.normalWorld.x);B.g=qa(k.normalWorld.y);B.b=qa(k.normalWorld.z);A(r,E,F,H,P,O,w,U);i.wireframe?ha(B,i.wireframeLinewidth,i.wireframeLinecap,
-i.wireframeLinejoin):ga(B)}else if(i instanceof THREE.MeshDepthMaterial){ea=h.near;fa=h.far;J.r=J.g=J.b=1-oa(a.positionScreen.z,ea,fa);I.r=I.g=I.b=1-oa(d.positionScreen.z,ea,fa);K.r=K.g=K.b=1-oa(g.positionScreen.z,ea,fa);R.r=R.g=R.b=1-oa(e.positionScreen.z,ea,fa);ca=va(J,I,K,R);z(r,E,F,H,w,U);pa(r,E,F,H,w,U,0,0,1,0,0,1,ca);z(M,T,P,O,S,W);pa(M,T,P,O,S,W,1,0,1,1,0,1,ca)}}}function z(a,b,c,d,e,f){l.beginPath();l.moveTo(a,b);l.lineTo(c,d);l.lineTo(e,f);l.lineTo(a,b)}function A(a,b,c,d,e,f,g,h){l.beginPath();
-l.moveTo(a,b);l.lineTo(c,d);l.lineTo(e,f);l.lineTo(g,h);l.lineTo(a,b)}function ha(a,b,c,e){if(D!=b)l.lineWidth=D=b;if(x!=c)l.lineCap=x=c;if(G!=e)l.lineJoin=G=e;d(a.getContextStyle());l.stroke();Z.inflate(b*2)}function ga(a){e(a.getContextStyle());l.fill()}function Fa(a,b,c,d,f,g,h,i,k,j,m,o,n){if(n.image.width!=0){if(n.needsUpdate==true||ja[n.id]==void 0){var p=n.wrapS==THREE.RepeatWrapping,q=n.wrapT==THREE.RepeatWrapping;ja[n.id]=l.createPattern(n.image,p&&q?"repeat":p&&!q?"repeat-x":!p&&q?"repeat-y":
-"no-repeat");n.needsUpdate=false}e(ja[n.id]);var p=n.offset.x/n.repeat.x,q=n.offset.y/n.repeat.y,r=n.image.width*n.repeat.x,s=n.image.height*n.repeat.y,h=(h+p)*r,i=(i+q)*s,c=c-a,d=d-b,f=f-a,g=g-b,k=(k+p)*r-h,j=(j+q)*s-i,m=(m+p)*r-h,o=(o+q)*s-i,p=k*o-m*j;if(p==0){if(da[n.id]===void 0){b=document.createElement("canvas");b.width=n.image.width;b.height=n.image.height;b=b.getContext("2d");b.drawImage(n.image,0,0);da[n.id]=b.getImageData(0,0,n.image.width,n.image.height).data}b=da[n.id];h=(Math.floor(h)+
-Math.floor(i)*n.image.width)*4;B.setRGB(b[h]/255,b[h+1]/255,b[h+2]/255);ga(B)}else{p=1/p;n=(o*c-j*f)*p;j=(o*d-j*g)*p;c=(k*f-m*c)*p;d=(k*g-m*d)*p;a=a-n*h-c*i;h=b-j*h-d*i;l.save();l.transform(n,j,c,d,a,h);l.fill();l.restore()}}}function pa(a,b,c,d,e,f,g,h,i,j,k,m,n){var o,p;o=n.width-1;p=n.height-1;g=g*o;h=h*p;c=c-a;d=d-b;e=e-a;f=f-b;i=i*o-g;j=j*p-h;k=k*o-g;m=m*p-h;p=1/(i*m-k*j);o=(m*c-j*e)*p;j=(m*d-j*f)*p;c=(i*e-k*c)*p;d=(i*f-k*d)*p;a=a-o*g-c*h;b=b-j*g-d*h;l.save();l.transform(o,j,c,d,a,b);l.clip();
-l.drawImage(n,0,0);l.restore()}function va(a,b,c,d){var e=~~(a.r*255),f=~~(a.g*255),a=~~(a.b*255),g=~~(b.r*255),h=~~(b.g*255),b=~~(b.b*255),i=~~(c.r*255),j=~~(c.g*255),c=~~(c.b*255),k=~~(d.r*255),l=~~(d.g*255),d=~~(d.b*255);aa[0]=e<0?0:e>255?255:e;aa[1]=f<0?0:f>255?255:f;aa[2]=a<0?0:a>255?255:a;aa[4]=g<0?0:g>255?255:g;aa[5]=h<0?0:h>255?255:h;aa[6]=b<0?0:b>255?255:b;aa[8]=i<0?0:i>255?255:i;aa[9]=j<0?0:j>255?255:j;aa[10]=c<0?0:c>255?255:c;aa[12]=k<0?0:k>255?255:k;aa[13]=l<0?0:l>255?255:l;aa[14]=d<0?
-0:d>255?255:d;sa.putImageData(ya,0,0);ua.drawImage(ra,0,0);return ta}function oa(a,b,c){a=(a-b)/(c-b);return a*a*(3-2*a)}function qa(a){a=(a+1)*0.5;return a<0?0:a>1?1:a}function ia(a,b){var c=b.x-a.x,d=b.y-a.y,e=c*c+d*d;if(e!=0){e=1/Math.sqrt(e);c=c*e;d=d*e;b.x=b.x+c;b.y=b.y+d;a.x=a.x-c;a.y=a.y-d}}var wa,Ga,X,ba;this.autoClear?this.clear():l.setTransform(1,0,0,-1,n,p);f.info.render.vertices=0;f.info.render.faces=0;g=j.projectScene(a,h,this.sortElements);k=g.elements;m=g.lights;(xa=m.length>0)&&i(m);
-wa=0;for(Ga=k.length;wa<Ga;wa++){X=k[wa];ba=X.material;ba=ba instanceof THREE.MeshFaceMaterial?X.faceMaterial:ba;if(!(ba===void 0||ba.visible===false)){Z.empty();if(X instanceof THREE.RenderableParticle){t=X;t.x=t.x*n;t.y=t.y*p;q(t,X,ba,a)}else if(X instanceof THREE.RenderableLine){t=X.v1;y=X.v2;t.positionScreen.x=t.positionScreen.x*n;t.positionScreen.y=t.positionScreen.y*p;y.positionScreen.x=y.positionScreen.x*n;y.positionScreen.y=y.positionScreen.y*p;Z.addPoint(t.positionScreen.x,t.positionScreen.y);
-Z.addPoint(y.positionScreen.x,y.positionScreen.y);la.intersects(Z)&&s(t,y,X,ba,a)}else if(X instanceof THREE.RenderableFace3){t=X.v1;y=X.v2;C=X.v3;t.positionScreen.x=t.positionScreen.x*n;t.positionScreen.y=t.positionScreen.y*p;y.positionScreen.x=y.positionScreen.x*n;y.positionScreen.y=y.positionScreen.y*p;C.positionScreen.x=C.positionScreen.x*n;C.positionScreen.y=C.positionScreen.y*p;if(ba.overdraw){ia(t.positionScreen,y.positionScreen);ia(y.positionScreen,C.positionScreen);ia(C.positionScreen,t.positionScreen)}Z.add3Points(t.positionScreen.x,
-t.positionScreen.y,y.positionScreen.x,y.positionScreen.y,C.positionScreen.x,C.positionScreen.y);la.intersects(Z)&&u(t,y,C,0,1,2,X,ba,a)}else if(X instanceof THREE.RenderableFace4){t=X.v1;y=X.v2;C=X.v3;L=X.v4;t.positionScreen.x=t.positionScreen.x*n;t.positionScreen.y=t.positionScreen.y*p;y.positionScreen.x=y.positionScreen.x*n;y.positionScreen.y=y.positionScreen.y*p;C.positionScreen.x=C.positionScreen.x*n;C.positionScreen.y=C.positionScreen.y*p;L.positionScreen.x=L.positionScreen.x*n;L.positionScreen.y=
-L.positionScreen.y*p;Q.positionScreen.copy(y.positionScreen);N.positionScreen.copy(L.positionScreen);if(ba.overdraw){ia(t.positionScreen,y.positionScreen);ia(y.positionScreen,L.positionScreen);ia(L.positionScreen,t.positionScreen);ia(C.positionScreen,Q.positionScreen);ia(C.positionScreen,N.positionScreen)}Z.addPoint(t.positionScreen.x,t.positionScreen.y);Z.addPoint(y.positionScreen.x,y.positionScreen.y);Z.addPoint(C.positionScreen.x,C.positionScreen.y);Z.addPoint(L.positionScreen.x,L.positionScreen.y);
-la.intersects(Z)&&v(t,y,C,L,Q,N,X,ba,a)}$.addRectangle(Z)}}l.setTransform(1,0,0,1,0,0)}};THREE.RenderableVertex=function(){this.positionWorld=new THREE.Vector3;this.positionScreen=new THREE.Vector4;this.visible=true};THREE.RenderableVertex.prototype.copy=function(a){this.positionWorld.copy(a.positionWorld);this.positionScreen.copy(a.positionScreen)};
+THREE.CanvasRenderer=function(a){function b(a){if(s!=a)i.globalAlpha=s=a}function c(a){if(v!=a){switch(a){case THREE.NormalBlending:i.globalCompositeOperation="source-over";break;case THREE.AdditiveBlending:i.globalCompositeOperation="lighter";break;case THREE.SubtractiveBlending:i.globalCompositeOperation="darker"}v=a}}function d(a){if(A!=a)i.strokeStyle=A=a}function f(a){if(w!=a)i.fillStyle=w=a}console.log("THREE.CanvasRenderer",THREE.REVISION);var a=a||{},e=this,g,m,k,l=new THREE.Projector,h=a.canvas!==
+void 0?a.canvas:document.createElement("canvas"),n,j,o,q,i=h.getContext("2d"),p=new THREE.Color(0),r=0,s=1,v=0,A=null,w=null,B=null,x=null,F=null,u,z,D,H,P=new THREE.RenderableVertex,L=new THREE.RenderableVertex,t,E,G,N,Q,O,y,S,M,U,T,W,C=new THREE.Color,J=new THREE.Color,I=new THREE.Color,K=new THREE.Color,R=new THREE.Color,ja=[],da=[],ea,fa,ca,ka,za,Aa,Ba,Ca,Da,Ea,la=new THREE.Rectangle,$=new THREE.Rectangle,Z=new THREE.Rectangle,xa=false,Y=new THREE.Color,ma=new THREE.Color,na=new THREE.Color,V=
+new THREE.Vector3,ra,sa,ya,aa,ta,ua,a=16;ra=document.createElement("canvas");ra.width=ra.height=2;sa=ra.getContext("2d");sa.fillStyle="rgba(0,0,0,1)";sa.fillRect(0,0,2,2);ya=sa.getImageData(0,0,2,2);aa=ya.data;ta=document.createElement("canvas");ta.width=ta.height=a;ua=ta.getContext("2d");ua.translate(-a/2,-a/2);ua.scale(a,a);a--;this.domElement=h;this.sortElements=this.sortObjects=this.autoClear=true;this.info={render:{vertices:0,faces:0}};this.setSize=function(a,b){n=a;j=b;o=Math.floor(n/2);q=Math.floor(j/
+2);h.width=n;h.height=j;la.set(-o,-q,o,q);$.set(-o,-q,o,q);s=1;v=0;F=x=B=w=A=null};this.setClearColor=function(a,b){p.copy(a);r=b!==void 0?b:1;$.set(-o,-q,o,q)};this.setClearColorHex=function(a,b){p.setHex(a);r=b!==void 0?b:1;$.set(-o,-q,o,q)};this.clear=function(){i.setTransform(1,0,0,-1,o,q);if(!$.isEmpty()){$.minSelf(la);$.inflate(2);r<1&&i.clearRect(Math.floor($.getX()),Math.floor($.getY()),Math.floor($.getWidth()),Math.floor($.getHeight()));if(r>0){c(THREE.NormalBlending);b(1);f("rgba("+Math.floor(p.r*
+255)+","+Math.floor(p.g*255)+","+Math.floor(p.b*255)+","+r+")");i.fillRect(Math.floor($.getX()),Math.floor($.getY()),Math.floor($.getWidth()),Math.floor($.getHeight()))}$.empty()}};this.render=function(a,h){function j(a){var b,c,d,e;Y.setRGB(0,0,0);ma.setRGB(0,0,0);na.setRGB(0,0,0);b=0;for(c=a.length;b<c;b++){d=a[b];e=d.color;if(d instanceof THREE.AmbientLight){Y.r=Y.r+e.r;Y.g=Y.g+e.g;Y.b=Y.b+e.b}else if(d instanceof THREE.DirectionalLight){ma.r=ma.r+e.r;ma.g=ma.g+e.g;ma.b=ma.b+e.b}else if(d instanceof
+THREE.PointLight){na.r=na.r+e.r;na.g=na.g+e.g;na.b=na.b+e.b}}}function n(a,b,c,d){var e,f,g,h,l,k;e=0;for(f=a.length;e<f;e++){g=a[e];h=g.color;if(g instanceof THREE.DirectionalLight){l=g.matrixWorld.getPosition();k=c.dot(l);if(!(k<=0)){k=k*g.intensity;d.r=d.r+h.r*k;d.g=d.g+h.g*k;d.b=d.b+h.b*k}}else if(g instanceof THREE.PointLight){l=g.matrixWorld.getPosition();k=c.dot(V.sub(l,b).normalize());if(!(k<=0)){k=k*(g.distance==0?1:1-Math.min(b.distanceTo(l)/g.distance,1));if(k!=0){k=k*g.intensity;d.r=d.r+
+h.r*k;d.g=d.g+h.g*k;d.b=d.b+h.b*k}}}}}function p(a,e,g){b(g.opacity);c(g.blending);var h,k,l,m,j,n;if(g instanceof THREE.ParticleBasicMaterial){if(g.map){m=g.map.image;j=m.width>>1;n=m.height>>1;g=e.scale.x*o;l=e.scale.y*q;h=g*j;k=l*n;Z.set(a.x-h,a.y-k,a.x+h,a.y+k);if(la.intersects(Z)){i.save();i.translate(a.x,a.y);i.rotate(-e.rotation);i.scale(g,-l);i.translate(-j,-n);i.drawImage(m,0,0);i.restore()}}}else if(g instanceof THREE.ParticleCanvasMaterial){h=e.scale.x*o;k=e.scale.y*q;Z.set(a.x-h,a.y-k,
+a.x+h,a.y+k);if(la.intersects(Z)){d(g.color.getContextStyle());f(g.color.getContextStyle());i.save();i.translate(a.x,a.y);i.rotate(-e.rotation);i.scale(h,k);g.program(i);i.restore()}}}function r(a,e,f,g){b(g.opacity);c(g.blending);i.beginPath();i.moveTo(a.positionScreen.x,a.positionScreen.y);i.lineTo(e.positionScreen.x,e.positionScreen.y);i.closePath();if(g instanceof THREE.LineBasicMaterial){a=g.linewidth;if(B!=a)i.lineWidth=B=a;a=g.linecap;if(x!=a)i.lineCap=x=a;a=g.linejoin;if(F!=a)i.lineJoin=F=
+a;d(g.color.getContextStyle());i.stroke();Z.inflate(g.linewidth*2)}}function s(a,d,f,g,l,m,i,j){e.info.render.vertices=e.info.render.vertices+3;e.info.render.faces++;b(j.opacity);c(j.blending);t=a.positionScreen.x;E=a.positionScreen.y;G=d.positionScreen.x;N=d.positionScreen.y;Q=f.positionScreen.x;O=f.positionScreen.y;v(t,E,G,N,Q,O);if(j instanceof THREE.MeshBasicMaterial)if(j.map){if(j.map.mapping instanceof THREE.UVMapping){ka=i.uvs[0];Fa(t,E,G,N,Q,O,ka[g].u,ka[g].v,ka[l].u,ka[l].v,ka[m].u,ka[m].v,
+j.map)}}else if(j.envMap){if(j.envMap.mapping instanceof THREE.SphericalReflectionMapping){a=h.matrixWorldInverse;V.copy(i.vertexNormalsWorld[g]);za=(V.x*a.elements[0]+V.y*a.elements[4]+V.z*a.elements[8])*0.5+0.5;Aa=-(V.x*a.elements[1]+V.y*a.elements[5]+V.z*a.elements[9])*0.5+0.5;V.copy(i.vertexNormalsWorld[l]);Ba=(V.x*a.elements[0]+V.y*a.elements[4]+V.z*a.elements[8])*0.5+0.5;Ca=-(V.x*a.elements[1]+V.y*a.elements[5]+V.z*a.elements[9])*0.5+0.5;V.copy(i.vertexNormalsWorld[m]);Da=(V.x*a.elements[0]+
+V.y*a.elements[4]+V.z*a.elements[8])*0.5+0.5;Ea=-(V.x*a.elements[1]+V.y*a.elements[5]+V.z*a.elements[9])*0.5+0.5;Fa(t,E,G,N,Q,O,za,Aa,Ba,Ca,Da,Ea,j.envMap)}}else j.wireframe?ha(j.color,j.wireframeLinewidth,j.wireframeLinecap,j.wireframeLinejoin):ga(j.color);else if(j instanceof THREE.MeshLambertMaterial)if(xa)if(!j.wireframe&&j.shading==THREE.SmoothShading&&i.vertexNormalsWorld.length==3){J.r=I.r=K.r=Y.r;J.g=I.g=K.g=Y.g;J.b=I.b=K.b=Y.b;n(k,i.v1.positionWorld,i.vertexNormalsWorld[0],J);n(k,i.v2.positionWorld,
+i.vertexNormalsWorld[1],I);n(k,i.v3.positionWorld,i.vertexNormalsWorld[2],K);J.r=Math.max(0,Math.min(j.color.r*J.r,1));J.g=Math.max(0,Math.min(j.color.g*J.g,1));J.b=Math.max(0,Math.min(j.color.b*J.b,1));I.r=Math.max(0,Math.min(j.color.r*I.r,1));I.g=Math.max(0,Math.min(j.color.g*I.g,1));I.b=Math.max(0,Math.min(j.color.b*I.b,1));K.r=Math.max(0,Math.min(j.color.r*K.r,1));K.g=Math.max(0,Math.min(j.color.g*K.g,1));K.b=Math.max(0,Math.min(j.color.b*K.b,1));R.r=(I.r+K.r)*0.5;R.g=(I.g+K.g)*0.5;R.b=(I.b+K.b)*
+0.5;ca=va(J,I,K,R);pa(t,E,G,N,Q,O,0,0,1,0,0,1,ca)}else{C.r=Y.r;C.g=Y.g;C.b=Y.b;n(k,i.centroidWorld,i.normalWorld,C);C.r=Math.max(0,Math.min(j.color.r*C.r,1));C.g=Math.max(0,Math.min(j.color.g*C.g,1));C.b=Math.max(0,Math.min(j.color.b*C.b,1));j.wireframe?ha(C,j.wireframeLinewidth,j.wireframeLinecap,j.wireframeLinejoin):ga(C)}else j.wireframe?ha(j.color,j.wireframeLinewidth,j.wireframeLinecap,j.wireframeLinejoin):ga(j.color);else if(j instanceof THREE.MeshDepthMaterial){ea=h.near;fa=h.far;J.r=J.g=J.b=
+1-oa(a.positionScreen.z,ea,fa);I.r=I.g=I.b=1-oa(d.positionScreen.z,ea,fa);K.r=K.g=K.b=1-oa(f.positionScreen.z,ea,fa);R.r=(I.r+K.r)*0.5;R.g=(I.g+K.g)*0.5;R.b=(I.b+K.b)*0.5;ca=va(J,I,K,R);pa(t,E,G,N,Q,O,0,0,1,0,0,1,ca)}else if(j instanceof THREE.MeshNormalMaterial){C.r=qa(i.normalWorld.x);C.g=qa(i.normalWorld.y);C.b=qa(i.normalWorld.z);j.wireframe?ha(C,j.wireframeLinewidth,j.wireframeLinecap,j.wireframeLinejoin):ga(C)}}function w(a,d,f,g,l,m,j,i,o){e.info.render.vertices=e.info.render.vertices+4;e.info.render.faces++;
+b(i.opacity);c(i.blending);if(i.map||i.envMap){s(a,d,g,0,1,3,j,i,o);s(l,f,m,1,2,3,j,i,o)}else{t=a.positionScreen.x;E=a.positionScreen.y;G=d.positionScreen.x;N=d.positionScreen.y;Q=f.positionScreen.x;O=f.positionScreen.y;y=g.positionScreen.x;S=g.positionScreen.y;M=l.positionScreen.x;U=l.positionScreen.y;T=m.positionScreen.x;W=m.positionScreen.y;if(i instanceof THREE.MeshBasicMaterial){A(t,E,G,N,Q,O,y,S);i.wireframe?ha(i.color,i.wireframeLinewidth,i.wireframeLinecap,i.wireframeLinejoin):ga(i.color)}else if(i instanceof
+THREE.MeshLambertMaterial)if(xa)if(!i.wireframe&&i.shading==THREE.SmoothShading&&j.vertexNormalsWorld.length==4){J.r=I.r=K.r=R.r=Y.r;J.g=I.g=K.g=R.g=Y.g;J.b=I.b=K.b=R.b=Y.b;n(k,j.v1.positionWorld,j.vertexNormalsWorld[0],J);n(k,j.v2.positionWorld,j.vertexNormalsWorld[1],I);n(k,j.v4.positionWorld,j.vertexNormalsWorld[3],K);n(k,j.v3.positionWorld,j.vertexNormalsWorld[2],R);J.r=Math.max(0,Math.min(i.color.r*J.r,1));J.g=Math.max(0,Math.min(i.color.g*J.g,1));J.b=Math.max(0,Math.min(i.color.b*J.b,1));I.r=
+Math.max(0,Math.min(i.color.r*I.r,1));I.g=Math.max(0,Math.min(i.color.g*I.g,1));I.b=Math.max(0,Math.min(i.color.b*I.b,1));K.r=Math.max(0,Math.min(i.color.r*K.r,1));K.g=Math.max(0,Math.min(i.color.g*K.g,1));K.b=Math.max(0,Math.min(i.color.b*K.b,1));R.r=Math.max(0,Math.min(i.color.r*R.r,1));R.g=Math.max(0,Math.min(i.color.g*R.g,1));R.b=Math.max(0,Math.min(i.color.b*R.b,1));ca=va(J,I,K,R);v(t,E,G,N,y,S);pa(t,E,G,N,y,S,0,0,1,0,0,1,ca);v(M,U,Q,O,T,W);pa(M,U,Q,O,T,W,1,0,1,1,0,1,ca)}else{C.r=Y.r;C.g=Y.g;
+C.b=Y.b;n(k,j.centroidWorld,j.normalWorld,C);C.r=Math.max(0,Math.min(i.color.r*C.r,1));C.g=Math.max(0,Math.min(i.color.g*C.g,1));C.b=Math.max(0,Math.min(i.color.b*C.b,1));A(t,E,G,N,Q,O,y,S);i.wireframe?ha(C,i.wireframeLinewidth,i.wireframeLinecap,i.wireframeLinejoin):ga(C)}else{A(t,E,G,N,Q,O,y,S);i.wireframe?ha(i.color,i.wireframeLinewidth,i.wireframeLinecap,i.wireframeLinejoin):ga(i.color)}else if(i instanceof THREE.MeshNormalMaterial){C.r=qa(j.normalWorld.x);C.g=qa(j.normalWorld.y);C.b=qa(j.normalWorld.z);
+A(t,E,G,N,Q,O,y,S);i.wireframe?ha(C,i.wireframeLinewidth,i.wireframeLinecap,i.wireframeLinejoin):ga(C)}else if(i instanceof THREE.MeshDepthMaterial){ea=h.near;fa=h.far;J.r=J.g=J.b=1-oa(a.positionScreen.z,ea,fa);I.r=I.g=I.b=1-oa(d.positionScreen.z,ea,fa);K.r=K.g=K.b=1-oa(g.positionScreen.z,ea,fa);R.r=R.g=R.b=1-oa(f.positionScreen.z,ea,fa);ca=va(J,I,K,R);v(t,E,G,N,y,S);pa(t,E,G,N,y,S,0,0,1,0,0,1,ca);v(M,U,Q,O,T,W);pa(M,U,Q,O,T,W,1,0,1,1,0,1,ca)}}}function v(a,b,c,d,e,f){i.beginPath();i.moveTo(a,b);
+i.lineTo(c,d);i.lineTo(e,f);i.lineTo(a,b)}function A(a,b,c,d,e,f,g,h){i.beginPath();i.moveTo(a,b);i.lineTo(c,d);i.lineTo(e,f);i.lineTo(g,h);i.lineTo(a,b)}function ha(a,b,c,e){if(B!=b)i.lineWidth=B=b;if(x!=c)i.lineCap=x=c;if(F!=e)i.lineJoin=F=e;d(a.getContextStyle());i.stroke();Z.inflate(b*2)}function ga(a){f(a.getContextStyle());i.fill()}function Fa(a,b,c,d,e,g,h,k,l,j,m,n,o){if(!(o.image===void 0||o.image.width===0)){if(o.needsUpdate===true||ja[o.id]===void 0){var p=o.wrapS==THREE.RepeatWrapping,
+q=o.wrapT==THREE.RepeatWrapping;ja[o.id]=i.createPattern(o.image,p&&q?"repeat":p&&!q?"repeat-x":!p&&q?"repeat-y":"no-repeat");o.needsUpdate=false}f(ja[o.id]);var p=o.offset.x/o.repeat.x,q=o.offset.y/o.repeat.y,r=o.image.width*o.repeat.x,s=o.image.height*o.repeat.y,h=(h+p)*r,k=(k+q)*s,c=c-a,d=d-b,e=e-a,g=g-b,l=(l+p)*r-h,j=(j+q)*s-k,m=(m+p)*r-h,n=(n+q)*s-k,p=l*n-m*j;if(p==0){if(da[o.id]===void 0){b=document.createElement("canvas");b.width=o.image.width;b.height=o.image.height;b=b.getContext("2d");b.drawImage(o.image,
+0,0);da[o.id]=b.getImageData(0,0,o.image.width,o.image.height).data}b=da[o.id];h=(Math.floor(h)+Math.floor(k)*o.image.width)*4;C.setRGB(b[h]/255,b[h+1]/255,b[h+2]/255);ga(C)}else{p=1/p;o=(n*c-j*e)*p;j=(n*d-j*g)*p;c=(l*e-m*c)*p;d=(l*g-m*d)*p;a=a-o*h-c*k;h=b-j*h-d*k;i.save();i.transform(o,j,c,d,a,h);i.fill();i.restore()}}}function pa(a,b,c,d,e,f,g,h,k,j,l,m,n){var o,p;o=n.width-1;p=n.height-1;g=g*o;h=h*p;c=c-a;d=d-b;e=e-a;f=f-b;k=k*o-g;j=j*p-h;l=l*o-g;m=m*p-h;p=1/(k*m-l*j);o=(m*c-j*e)*p;j=(m*d-j*f)*
+p;c=(k*e-l*c)*p;d=(k*f-l*d)*p;a=a-o*g-c*h;b=b-j*g-d*h;i.save();i.transform(o,j,c,d,a,b);i.clip();i.drawImage(n,0,0);i.restore()}function va(a,b,c,d){var e=~~(a.r*255),f=~~(a.g*255),a=~~(a.b*255),g=~~(b.r*255),h=~~(b.g*255),b=~~(b.b*255),i=~~(c.r*255),j=~~(c.g*255),c=~~(c.b*255),k=~~(d.r*255),l=~~(d.g*255),d=~~(d.b*255);aa[0]=e<0?0:e>255?255:e;aa[1]=f<0?0:f>255?255:f;aa[2]=a<0?0:a>255?255:a;aa[4]=g<0?0:g>255?255:g;aa[5]=h<0?0:h>255?255:h;aa[6]=b<0?0:b>255?255:b;aa[8]=i<0?0:i>255?255:i;aa[9]=j<0?0:
+j>255?255:j;aa[10]=c<0?0:c>255?255:c;aa[12]=k<0?0:k>255?255:k;aa[13]=l<0?0:l>255?255:l;aa[14]=d<0?0:d>255?255:d;sa.putImageData(ya,0,0);ua.drawImage(ra,0,0);return ta}function oa(a,b,c){a=(a-b)/(c-b);return a*a*(3-2*a)}function qa(a){a=(a+1)*0.5;return a<0?0:a>1?1:a}function ia(a,b){var c=b.x-a.x,d=b.y-a.y,e=c*c+d*d;if(e!=0){e=1/Math.sqrt(e);c=c*e;d=d*e;b.x=b.x+c;b.y=b.y+d;a.x=a.x-c;a.y=a.y-d}}var wa,Ga,X,ba;this.autoClear?this.clear():i.setTransform(1,0,0,-1,o,q);e.info.render.vertices=0;e.info.render.faces=
+0;g=l.projectScene(a,h,this.sortElements);m=g.elements;k=g.lights;(xa=k.length>0)&&j(k);wa=0;for(Ga=m.length;wa<Ga;wa++){X=m[wa];ba=X.material;ba=ba instanceof THREE.MeshFaceMaterial?X.faceMaterial:ba;if(!(ba===void 0||ba.visible===false)){Z.empty();if(X instanceof THREE.RenderableParticle){u=X;u.x=u.x*o;u.y=u.y*q;p(u,X,ba,a)}else if(X instanceof THREE.RenderableLine){u=X.v1;z=X.v2;u.positionScreen.x=u.positionScreen.x*o;u.positionScreen.y=u.positionScreen.y*q;z.positionScreen.x=z.positionScreen.x*
+o;z.positionScreen.y=z.positionScreen.y*q;Z.addPoint(u.positionScreen.x,u.positionScreen.y);Z.addPoint(z.positionScreen.x,z.positionScreen.y);la.intersects(Z)&&r(u,z,X,ba,a)}else if(X instanceof THREE.RenderableFace3){u=X.v1;z=X.v2;D=X.v3;u.positionScreen.x=u.positionScreen.x*o;u.positionScreen.y=u.positionScreen.y*q;z.positionScreen.x=z.positionScreen.x*o;z.positionScreen.y=z.positionScreen.y*q;D.positionScreen.x=D.positionScreen.x*o;D.positionScreen.y=D.positionScreen.y*q;if(ba.overdraw){ia(u.positionScreen,
+z.positionScreen);ia(z.positionScreen,D.positionScreen);ia(D.positionScreen,u.positionScreen)}Z.add3Points(u.positionScreen.x,u.positionScreen.y,z.positionScreen.x,z.positionScreen.y,D.positionScreen.x,D.positionScreen.y);la.intersects(Z)&&s(u,z,D,0,1,2,X,ba,a)}else if(X instanceof THREE.RenderableFace4){u=X.v1;z=X.v2;D=X.v3;H=X.v4;u.positionScreen.x=u.positionScreen.x*o;u.positionScreen.y=u.positionScreen.y*q;z.positionScreen.x=z.positionScreen.x*o;z.positionScreen.y=z.positionScreen.y*q;D.positionScreen.x=
+D.positionScreen.x*o;D.positionScreen.y=D.positionScreen.y*q;H.positionScreen.x=H.positionScreen.x*o;H.positionScreen.y=H.positionScreen.y*q;P.positionScreen.copy(z.positionScreen);L.positionScreen.copy(H.positionScreen);if(ba.overdraw){ia(u.positionScreen,z.positionScreen);ia(z.positionScreen,H.positionScreen);ia(H.positionScreen,u.positionScreen);ia(D.positionScreen,P.positionScreen);ia(D.positionScreen,L.positionScreen)}Z.addPoint(u.positionScreen.x,u.positionScreen.y);Z.addPoint(z.positionScreen.x,
+z.positionScreen.y);Z.addPoint(D.positionScreen.x,D.positionScreen.y);Z.addPoint(H.positionScreen.x,H.positionScreen.y);la.intersects(Z)&&w(u,z,D,H,P,L,X,ba,a)}$.addRectangle(Z)}}i.setTransform(1,0,0,1,0,0)}};THREE.RenderableVertex=function(){this.positionWorld=new THREE.Vector3;this.positionScreen=new THREE.Vector4;this.visible=true};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.centroidWorld=new THREE.Vector3;this.centroidScreen=new THREE.Vector3;this.normalWorld=new THREE.Vector3;this.vertexNormalsWorld=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3];this.faceMaterial=this.material=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.centroidWorld=new THREE.Vector3;this.centroidScreen=new THREE.Vector3;this.normalWorld=new THREE.Vector3;this.vertexNormalsWorld=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3];this.faceMaterial=this.material=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=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};

+ 90 - 83
build/custom/ThreeExtras.js

@@ -12,25 +12,25 @@ a.max);c.multiplyScalar(-0.5);b.applyMatrix((new THREE.Matrix4).makeTranslation(
 b.faces[a],d instanceof THREE.Face4){e=d.a;var i=d.b,j=d.c,l=d.d,n=new THREE.Face3,k=new THREE.Face3;n.color.copy(d.color);k.color.copy(d.color);n.materialIndex=d.materialIndex;k.materialIndex=d.materialIndex;n.a=e;n.b=i;n.c=l;k.a=i;k.b=j;k.c=l;4===d.vertexColors.length&&(n.vertexColors[0]=d.vertexColors[0].clone(),n.vertexColors[1]=d.vertexColors[1].clone(),n.vertexColors[2]=d.vertexColors[3].clone(),k.vertexColors[0]=d.vertexColors[1].clone(),k.vertexColors[1]=d.vertexColors[2].clone(),k.vertexColors[2]=
 d.vertexColors[3].clone());f.push(n,k);d=0;for(e=b.faceVertexUvs.length;d<e;d++)b.faceVertexUvs[d].length&&(n=b.faceVertexUvs[d][a],i=n[1],j=n[2],l=n[3],n=[n[0].clone(),i.clone(),l.clone()],i=[i.clone(),j.clone(),l.clone()],h[d].push(n,i));d=0;for(e=b.faceUvs.length;d<e;d++)b.faceUvs[d].length&&(i=b.faceUvs[d][a],g[d].push(i,i))}else{f.push(d);d=0;for(e=b.faceUvs.length;d<e;d++)g[d].push(b.faceUvs[d]);d=0;for(e=b.faceVertexUvs.length;d<e;d++)h[d].push(b.faceVertexUvs[d])}b.faces=f;b.faceUvs=g;b.faceVertexUvs=
 h;b.computeCentroids();b.computeFaceNormals();b.computeVertexNormals();b.hasTangents&&b.computeTangents()},explode:function(b){for(var a=[],c=0,d=b.faces.length;c<d;c++){var e=a.length,f=b.faces[c];if(f instanceof THREE.Face4){var g=f.a,h=f.b,i=f.c,g=b.vertices[g],h=b.vertices[h],i=b.vertices[i],j=b.vertices[f.d];a.push(g.clone());a.push(h.clone());a.push(i.clone());a.push(j.clone());f.a=e;f.b=e+1;f.c=e+2;f.d=e+3}else g=f.a,h=f.b,i=f.c,g=b.vertices[g],h=b.vertices[h],i=b.vertices[i],a.push(g.clone()),
-a.push(h.clone()),a.push(i.clone()),f.a=e,f.b=e+1,f.c=e+2}b.vertices=a;delete b.__tmpVertices},tessellate:function(b,a){var c,d,e,f,g,h,i,j,l,n,k,m,o,q,r,s,t,v,p,x=[],A=[];c=0;for(d=b.faceVertexUvs.length;c<d;c++)A[c]=[];c=0;for(d=b.faces.length;c<d;c++)if(e=b.faces[c],e instanceof THREE.Face3)if(f=e.a,g=e.b,h=e.c,j=b.vertices[f],l=b.vertices[g],n=b.vertices[h],m=j.distanceTo(l),o=l.distanceTo(n),k=j.distanceTo(n),m>a||o>a||k>a){i=b.vertices.length;v=e.clone();p=e.clone();m>=o&&m>=k?(j=j.clone(),
+a.push(h.clone()),a.push(i.clone()),f.a=e,f.b=e+1,f.c=e+2}b.vertices=a;delete b.__tmpVertices},tessellate:function(b,a){var c,d,e,f,g,h,i,j,l,n,k,m,o,q,r,s,t,v,p,x=[],z=[];c=0;for(d=b.faceVertexUvs.length;c<d;c++)z[c]=[];c=0;for(d=b.faces.length;c<d;c++)if(e=b.faces[c],e instanceof THREE.Face3)if(f=e.a,g=e.b,h=e.c,j=b.vertices[f],l=b.vertices[g],n=b.vertices[h],m=j.distanceTo(l),o=l.distanceTo(n),k=j.distanceTo(n),m>a||o>a||k>a){i=b.vertices.length;v=e.clone();p=e.clone();m>=o&&m>=k?(j=j.clone(),
 j.lerpSelf(l,0.5),v.a=f,v.b=i,v.c=h,p.a=i,p.b=g,p.c=h,3===e.vertexNormals.length&&(f=e.vertexNormals[0].clone(),f.lerpSelf(e.vertexNormals[1],0.5),v.vertexNormals[1].copy(f),p.vertexNormals[0].copy(f)),3===e.vertexColors.length&&(f=e.vertexColors[0].clone(),f.lerpSelf(e.vertexColors[1],0.5),v.vertexColors[1].copy(f),p.vertexColors[0].copy(f)),e=0):o>=m&&o>=k?(j=l.clone(),j.lerpSelf(n,0.5),v.a=f,v.b=g,v.c=i,p.a=i,p.b=h,p.c=f,3===e.vertexNormals.length&&(f=e.vertexNormals[1].clone(),f.lerpSelf(e.vertexNormals[2],
 0.5),v.vertexNormals[2].copy(f),p.vertexNormals[0].copy(f),p.vertexNormals[1].copy(e.vertexNormals[2]),p.vertexNormals[2].copy(e.vertexNormals[0])),3===e.vertexColors.length&&(f=e.vertexColors[1].clone(),f.lerpSelf(e.vertexColors[2],0.5),v.vertexColors[2].copy(f),p.vertexColors[0].copy(f),p.vertexColors[1].copy(e.vertexColors[2]),p.vertexColors[2].copy(e.vertexColors[0])),e=1):(j=j.clone(),j.lerpSelf(n,0.5),v.a=f,v.b=g,v.c=i,p.a=i,p.b=g,p.c=h,3===e.vertexNormals.length&&(f=e.vertexNormals[0].clone(),
 f.lerpSelf(e.vertexNormals[2],0.5),v.vertexNormals[2].copy(f),p.vertexNormals[0].copy(f)),3===e.vertexColors.length&&(f=e.vertexColors[0].clone(),f.lerpSelf(e.vertexColors[2],0.5),v.vertexColors[2].copy(f),p.vertexColors[0].copy(f)),e=2);x.push(v,p);b.vertices.push(j);f=0;for(g=b.faceVertexUvs.length;f<g;f++)b.faceVertexUvs[f].length&&(j=b.faceVertexUvs[f][c],p=j[0],h=j[1],v=j[2],0===e?(l=p.clone(),l.lerpSelf(h,0.5),j=[p.clone(),l.clone(),v.clone()],h=[l.clone(),h.clone(),v.clone()]):1===e?(l=h.clone(),
-l.lerpSelf(v,0.5),j=[p.clone(),h.clone(),l.clone()],h=[l.clone(),v.clone(),p.clone()]):(l=p.clone(),l.lerpSelf(v,0.5),j=[p.clone(),h.clone(),l.clone()],h=[l.clone(),h.clone(),v.clone()]),A[f].push(j,h))}else{x.push(e);f=0;for(g=b.faceVertexUvs.length;f<g;f++)A[f].push(b.faceVertexUvs[f][c])}else if(f=e.a,g=e.b,h=e.c,i=e.d,j=b.vertices[f],l=b.vertices[g],n=b.vertices[h],k=b.vertices[i],m=j.distanceTo(l),o=l.distanceTo(n),q=n.distanceTo(k),r=j.distanceTo(k),m>a||o>a||q>a||r>a){s=b.vertices.length;t=
+l.lerpSelf(v,0.5),j=[p.clone(),h.clone(),l.clone()],h=[l.clone(),v.clone(),p.clone()]):(l=p.clone(),l.lerpSelf(v,0.5),j=[p.clone(),h.clone(),l.clone()],h=[l.clone(),h.clone(),v.clone()]),z[f].push(j,h))}else{x.push(e);f=0;for(g=b.faceVertexUvs.length;f<g;f++)z[f].push(b.faceVertexUvs[f][c])}else if(f=e.a,g=e.b,h=e.c,i=e.d,j=b.vertices[f],l=b.vertices[g],n=b.vertices[h],k=b.vertices[i],m=j.distanceTo(l),o=l.distanceTo(n),q=n.distanceTo(k),r=j.distanceTo(k),m>a||o>a||q>a||r>a){s=b.vertices.length;t=
 b.vertices.length+1;v=e.clone();p=e.clone();m>=o&&m>=q&&m>=r||q>=o&&q>=m&&q>=r?(m=j.clone(),m.lerpSelf(l,0.5),l=n.clone(),l.lerpSelf(k,0.5),v.a=f,v.b=s,v.c=t,v.d=i,p.a=s,p.b=g,p.c=h,p.d=t,4===e.vertexNormals.length&&(f=e.vertexNormals[0].clone(),f.lerpSelf(e.vertexNormals[1],0.5),g=e.vertexNormals[2].clone(),g.lerpSelf(e.vertexNormals[3],0.5),v.vertexNormals[1].copy(f),v.vertexNormals[2].copy(g),p.vertexNormals[0].copy(f),p.vertexNormals[3].copy(g)),4===e.vertexColors.length&&(f=e.vertexColors[0].clone(),
 f.lerpSelf(e.vertexColors[1],0.5),g=e.vertexColors[2].clone(),g.lerpSelf(e.vertexColors[3],0.5),v.vertexColors[1].copy(f),v.vertexColors[2].copy(g),p.vertexColors[0].copy(f),p.vertexColors[3].copy(g)),e=0):(m=l.clone(),m.lerpSelf(n,0.5),l=k.clone(),l.lerpSelf(j,0.5),v.a=f,v.b=g,v.c=s,v.d=t,p.a=t,p.b=s,p.c=h,p.d=i,4===e.vertexNormals.length&&(f=e.vertexNormals[1].clone(),f.lerpSelf(e.vertexNormals[2],0.5),g=e.vertexNormals[3].clone(),g.lerpSelf(e.vertexNormals[0],0.5),v.vertexNormals[2].copy(f),v.vertexNormals[3].copy(g),
 p.vertexNormals[0].copy(g),p.vertexNormals[1].copy(f)),4===e.vertexColors.length&&(f=e.vertexColors[1].clone(),f.lerpSelf(e.vertexColors[2],0.5),g=e.vertexColors[3].clone(),g.lerpSelf(e.vertexColors[0],0.5),v.vertexColors[2].copy(f),v.vertexColors[3].copy(g),p.vertexColors[0].copy(g),p.vertexColors[1].copy(f)),e=1);x.push(v,p);b.vertices.push(m,l);f=0;for(g=b.faceVertexUvs.length;f<g;f++)b.faceVertexUvs[f].length&&(j=b.faceVertexUvs[f][c],p=j[0],h=j[1],v=j[2],j=j[3],0===e?(l=p.clone(),l.lerpSelf(h,
-0.5),n=v.clone(),n.lerpSelf(j,0.5),p=[p.clone(),l.clone(),n.clone(),j.clone()],h=[l.clone(),h.clone(),v.clone(),n.clone()]):(l=h.clone(),l.lerpSelf(v,0.5),n=j.clone(),n.lerpSelf(p,0.5),p=[p.clone(),h.clone(),l.clone(),n.clone()],h=[n.clone(),l.clone(),v.clone(),j.clone()]),A[f].push(p,h))}else{x.push(e);f=0;for(g=b.faceVertexUvs.length;f<g;f++)A[f].push(b.faceVertexUvs[f][c])}b.faces=x;b.faceVertexUvs=A}};THREE.GeometryUtils.random=THREE.Math.random16;THREE.GeometryUtils.__v1=new THREE.Vector3;
-THREE.ImageUtils={crossOrigin:"anonymous",loadTexture:function(b,a,c){var d=new Image,e=new THREE.Texture(d,a);d.onload=function(){e.needsUpdate=!0;c&&c(this)};d.crossOrigin=this.crossOrigin;d.src=b;return e},loadTextureCube:function(b,a,c){var d,e=[],f=new THREE.Texture(e,a),a=e.loadCount=0;for(d=b.length;a<d;++a)e[a]=new Image,e[a].onload=function(){e.loadCount+=1;6===e.loadCount&&(f.needsUpdate=!0);c&&c(this)},e[a].crossOrigin=this.crossOrigin,e[a].src=b[a];return f},getNormalMap:function(b,a){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]},a=a|1,d=b.width,e=b.height,f=document.createElement("canvas");f.width=d;f.height=e;var g=f.getContext("2d");g.drawImage(b,0,0);for(var h=g.getImageData(0,0,d,e).data,i=g.createImageData(d,e),j=i.data,l=0;l<d;l++)for(var n=0;n<e;n++){var k=0>n-1?0:n-1,m=n+1>e-1?e-1:n+1,o=0>l-1?0:l-1,q=l+1>d-1?d-1:l+1,r=[],s=[0,0,h[4*(n*d+l)]/255*a];r.push([-1,0,h[4*(n*d+o)]/255*a]);r.push([-1,-1,h[4*(k*d+o)]/255*a]);r.push([0,
--1,h[4*(k*d+l)]/255*a]);r.push([1,-1,h[4*(k*d+q)]/255*a]);r.push([1,0,h[4*(n*d+q)]/255*a]);r.push([1,1,h[4*(m*d+q)]/255*a]);r.push([0,1,h[4*(m*d+l)]/255*a]);r.push([-1,1,h[4*(m*d+o)]/255*a]);k=[];o=r.length;for(m=0;m<o;m++){var q=r[m],t=r[(m+1)%o],q=[q[0]-s[0],q[1]-s[1],q[2]-s[2]],t=[t[0]-s[0],t[1]-s[1],t[2]-s[2]];k.push(c([q[1]*t[2]-q[2]*t[1],q[2]*t[0]-q[0]*t[2],q[0]*t[1]-q[1]*t[0]]))}r=[0,0,0];for(m=0;m<k.length;m++)r[0]+=k[m][0],r[1]+=k[m][1],r[2]+=k[m][2];r[0]/=k.length;r[1]/=k.length;r[2]/=k.length;
-s=4*(n*d+l);j[s]=255*((r[0]+1)/2)|0;j[s+1]=255*(r[1]+0.5)|0;j[s+2]=255*r[2]|0;j[s+3]=255}g.putImageData(i,0,0);return f},generateDataTexture:function(b,a,c){for(var d=b*a,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;b=new THREE.DataTexture(e,b,a,THREE.RGBFormat);b.needsUpdate=!0;return b}};
+0.5),n=v.clone(),n.lerpSelf(j,0.5),p=[p.clone(),l.clone(),n.clone(),j.clone()],h=[l.clone(),h.clone(),v.clone(),n.clone()]):(l=h.clone(),l.lerpSelf(v,0.5),n=j.clone(),n.lerpSelf(p,0.5),p=[p.clone(),h.clone(),l.clone(),n.clone()],h=[n.clone(),l.clone(),v.clone(),j.clone()]),z[f].push(p,h))}else{x.push(e);f=0;for(g=b.faceVertexUvs.length;f<g;f++)z[f].push(b.faceVertexUvs[f][c])}b.faces=x;b.faceVertexUvs=z}};THREE.GeometryUtils.random=THREE.Math.random16;THREE.GeometryUtils.__v1=new THREE.Vector3;
+THREE.ImageUtils={crossOrigin:"anonymous",loadTexture:function(b,a,c,d){var e=new THREE.Texture(void 0,a),a=new THREE.ImageLoader;a.addEventListener("load",function(a){e.image=a.content;e.needsUpdate=!0;c&&c()});a.addEventListener("error",function(a){d&&d(a.message)});a.crossOrigin=this.crossOrigin;a.load(b);return e},loadTextureCube:function(b,a,c){var d,e=[],f=new THREE.Texture(e,a),a=e.loadCount=0;for(d=b.length;a<d;++a)e[a]=new Image,e[a].onload=function(){e.loadCount+=1;6===e.loadCount&&(f.needsUpdate=
+!0,c&&c())},e[a].crossOrigin=this.crossOrigin,e[a].src=b[a];return f},getNormalMap:function(b,a){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]},a=a|1,d=b.width,e=b.height,f=document.createElement("canvas");f.width=d;f.height=e;var g=f.getContext("2d");g.drawImage(b,0,0);for(var h=g.getImageData(0,0,d,e).data,i=g.createImageData(d,e),j=i.data,l=0;l<d;l++)for(var n=0;n<e;n++){var k=0>n-1?0:n-1,m=n+1>e-1?e-1:n+1,o=0>l-1?0:l-1,q=l+1>d-1?d-1:l+1,r=[],s=[0,
+0,h[4*(n*d+l)]/255*a];r.push([-1,0,h[4*(n*d+o)]/255*a]);r.push([-1,-1,h[4*(k*d+o)]/255*a]);r.push([0,-1,h[4*(k*d+l)]/255*a]);r.push([1,-1,h[4*(k*d+q)]/255*a]);r.push([1,0,h[4*(n*d+q)]/255*a]);r.push([1,1,h[4*(m*d+q)]/255*a]);r.push([0,1,h[4*(m*d+l)]/255*a]);r.push([-1,1,h[4*(m*d+o)]/255*a]);k=[];o=r.length;for(m=0;m<o;m++){var q=r[m],t=r[(m+1)%o],q=[q[0]-s[0],q[1]-s[1],q[2]-s[2]],t=[t[0]-s[0],t[1]-s[1],t[2]-s[2]];k.push(c([q[1]*t[2]-q[2]*t[1],q[2]*t[0]-q[0]*t[2],q[0]*t[1]-q[1]*t[0]]))}r=[0,0,0];for(m=
+0;m<k.length;m++)r[0]+=k[m][0],r[1]+=k[m][1],r[2]+=k[m][2];r[0]/=k.length;r[1]/=k.length;r[2]/=k.length;s=4*(n*d+l);j[s]=255*((r[0]+1)/2)|0;j[s+1]=255*((r[1]+1)/2)|0;j[s+2]=255*r[2]|0;j[s+3]=255}g.putImageData(i,0,0);return f},generateDataTexture:function(b,a,c){for(var d=b*a,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;b=new THREE.DataTexture(e,b,a,THREE.RGBFormat);b.needsUpdate=!0;return b}};
 THREE.SceneUtils={showHierarchy:function(b,a){THREE.SceneUtils.traverseHierarchy(b,function(b){b.visible=a})},traverseHierarchy:function(b,a){var c,d,e=b.children.length;for(d=0;d<e;d++)c=b.children[d],a(c),THREE.SceneUtils.traverseHierarchy(c,a)},createMultiMaterialObject:function(b,a){var c,d=a.length,e=new THREE.Object3D;for(c=0;c<d;c++){var f=new THREE.Mesh(b,a[c]);e.add(f)}return e},cloneObject:function(b){var a;b instanceof THREE.MorphAnimMesh?(a=new THREE.MorphAnimMesh(b.geometry,b.material),
 a.duration=b.duration,a.mirroredLoop=b.mirroredLoop,a.time=b.time,a.lastKeyframe=b.lastKeyframe,a.currentKeyframe=b.currentKeyframe,a.direction=b.direction,a.directionBackwards=b.directionBackwards):b instanceof THREE.SkinnedMesh?a=new THREE.SkinnedMesh(b.geometry,b.material):b instanceof THREE.Mesh?a=new THREE.Mesh(b.geometry,b.material):b instanceof THREE.Line?a=new THREE.Line(b.geometry,b.material,b.type):b instanceof THREE.Ribbon?a=new THREE.Ribbon(b.geometry,b.material):b instanceof THREE.ParticleSystem?
 (a=new THREE.ParticleSystem(b.geometry,b.material),a.sortParticles=b.sortParticles):b instanceof THREE.Particle?a=new THREE.Particle(b.material):b instanceof THREE.Sprite?(a=new THREE.Sprite({}),a.color.copy(b.color),a.map=b.map,a.blending=b.blending,a.useScreenCoordinates=b.useScreenCoordinates,a.mergeWith3D=b.mergeWith3D,a.affectedByDistance=b.affectedByDistance,a.scaleByViewport=b.scaleByViewport,a.alignment=b.alignment,a.rotation3d.copy(b.rotation3d),a.rotation=b.rotation,a.opacity=b.opacity,
-a.uvOffset.copy(b.uvOffset),a.uvScale.copy(b.uvScale)):b instanceof THREE.LOD?a=new THREE.LOD:b instanceof THREE.MarchingCubes?(a=new THREE.MarchingCubes(b.resolution,b.material),a.field.set(b.field),a.isolation=b.isolation):b instanceof THREE.Object3D&&(a=new THREE.Object3D);a.name=b.name;a.parent=b.parent;a.up.copy(b.up);a.position.copy(b.position);a.rotation instanceof THREE.Vector3&&a.rotation.copy(b.rotation);a.eulerOrder=b.eulerOrder;a.scale.copy(b.scale);a.dynamic=b.dynamic;a.doubleSided=b.doubleSided;
-a.flipSided=b.flipSided;a.renderDepth=b.renderDepth;a.rotationAutoUpdate=b.rotationAutoUpdate;a.matrix.copy(b.matrix);a.matrixWorld.copy(b.matrixWorld);a.matrixRotationWorld.copy(b.matrixRotationWorld);a.matrixAutoUpdate=b.matrixAutoUpdate;a.matrixWorldNeedsUpdate=b.matrixWorldNeedsUpdate;a.quaternion.copy(b.quaternion);a.useQuaternion=b.useQuaternion;a.boundRadius=b.boundRadius;a.boundRadiusScale=b.boundRadiusScale;a.visible=b.visible;a.castShadow=b.castShadow;a.receiveShadow=b.receiveShadow;a.frustumCulled=
-b.frustumCulled;for(var c=0;c<b.children.length;c++){var d=THREE.SceneUtils.cloneObject(b.children[c]);a.children[c]=d;d.parent=a}if(b instanceof THREE.LOD)for(c=0;c<b.LODs.length;c++)a.LODs[c]={visibleAtDistance:b.LODs[c].visibleAtDistance,object3D:a.children[c]};return a},detach:function(b,a,c){b.applyMatrix(a.matrixWorld);a.remove(b);c.add(b)},attach:function(b,a,c){var d=new THREE.Matrix4;d.getInverse(c.matrixWorld);b.applyMatrix(d);a.remove(b);c.add(b)}};
+a.uvOffset.copy(b.uvOffset),a.uvScale.copy(b.uvScale)):b instanceof THREE.LOD?a=new THREE.LOD:b instanceof THREE.Object3D&&(a=new THREE.Object3D);a.name=b.name;a.parent=b.parent;a.up.copy(b.up);a.position.copy(b.position);a.rotation instanceof THREE.Vector3&&a.rotation.copy(b.rotation);a.eulerOrder=b.eulerOrder;a.scale.copy(b.scale);a.dynamic=b.dynamic;a.doubleSided=b.doubleSided;a.flipSided=b.flipSided;a.renderDepth=b.renderDepth;a.rotationAutoUpdate=b.rotationAutoUpdate;a.matrix.copy(b.matrix);
+a.matrixWorld.copy(b.matrixWorld);a.matrixRotationWorld.copy(b.matrixRotationWorld);a.matrixAutoUpdate=b.matrixAutoUpdate;a.matrixWorldNeedsUpdate=b.matrixWorldNeedsUpdate;a.quaternion.copy(b.quaternion);a.useQuaternion=b.useQuaternion;a.boundRadius=b.boundRadius;a.boundRadiusScale=b.boundRadiusScale;a.visible=b.visible;a.castShadow=b.castShadow;a.receiveShadow=b.receiveShadow;a.frustumCulled=b.frustumCulled;for(var c=0;c<b.children.length;c++){var d=THREE.SceneUtils.cloneObject(b.children[c]);a.children[c]=
+d;d.parent=a}if(b instanceof THREE.LOD)for(c=0;c<b.LODs.length;c++)a.LODs[c]={visibleAtDistance:b.LODs[c].visibleAtDistance,object3D:a.children[c]};return a},detach:function(b,a,c){b.applyMatrix(a.matrixWorld);a.remove(b);c.add(b)},attach:function(b,a,c){var d=new THREE.Matrix4;d.getInverse(c.matrixWorld);b.applyMatrix(d);a.remove(b);c.add(b)}};
 THREE.WebGLRenderer&&(THREE.ShaderUtils={lib:{fresnel:{uniforms:{mRefractionRatio:{type:"f",value:1.02},mFresnelBias:{type:"f",value:0.1},mFresnelPower:{type:"f",value:2},mFresnelScale:{type:"f",value:1},tCube:{type:"t",value:1,texture:null}},fragmentShader:"uniform samplerCube tCube;\nvarying vec3 vReflect;\nvarying vec3 vRefract[3];\nvarying float vReflectionFactor;\nvoid main() {\nvec4 reflectedColor = textureCube( tCube, vec3( -vReflect.x, vReflect.yz ) );\nvec4 refractedColor = vec4( 1.0, 1.0, 1.0, 1.0 );\nrefractedColor.r = textureCube( tCube, vec3( -vRefract[0].x, vRefract[0].yz ) ).r;\nrefractedColor.g = textureCube( tCube, vec3( -vRefract[1].x, vRefract[1].yz ) ).g;\nrefractedColor.b = textureCube( tCube, vec3( -vRefract[2].x, vRefract[2].yz ) ).b;\nrefractedColor.a = 1.0;\ngl_FragColor = mix( refractedColor, reflectedColor, clamp( vReflectionFactor, 0.0, 1.0 ) );\n}",
 vertexShader:"uniform float mRefractionRatio;\nuniform float mFresnelBias;\nuniform float mFresnelScale;\nuniform float mFresnelPower;\nvarying vec3 vReflect;\nvarying vec3 vRefract[3];\nvarying float vReflectionFactor;\nvoid main() {\nvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\nvec4 mPosition = objectMatrix * vec4( position, 1.0 );\nvec3 nWorld = normalize ( mat3( objectMatrix[0].xyz, objectMatrix[1].xyz, objectMatrix[2].xyz ) * normal );\nvec3 I = mPosition.xyz - cameraPosition;\nvReflect = reflect( I, nWorld );\nvRefract[0] = refract( normalize( I ), nWorld, mRefractionRatio );\nvRefract[1] = refract( normalize( I ), nWorld, mRefractionRatio * 0.99 );\nvRefract[2] = refract( normalize( I ), nWorld, mRefractionRatio * 0.98 );\nvReflectionFactor = mFresnelBias + mFresnelScale * pow( 1.0 + dot( normalize( I ), nWorld ), mFresnelPower );\ngl_Position = projectionMatrix * mvPosition;\n}"},
 normal:{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},tDiffuse:{type:"t",value:0,texture:null},tCube:{type:"t",value:1,texture:null},tNormal:{type:"t",value:2,texture:null},tSpecular:{type:"t",value:3,texture:null},tAO:{type:"t",value:4,texture:null},tDisplacement:{type:"t",value:5,texture:null},uNormalScale:{type:"f",
@@ -40,6 +40,13 @@ THREE.ShaderChunk.shadowmap_pars_fragment,THREE.ShaderChunk.fog_pars_fragment,"v
 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;\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;\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\nvarying vec3 vViewPosition;",
 THREE.ShaderChunk.shadowmap_pars_vertex,"void main() {\nvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\nvViewPosition = -mvPosition.xyz;\nvNormal = normalMatrix * normal;\nvTangent = normalMatrix * tangent.xyz;\nvBinormal = cross( vNormal, vTangent ) * tangent.w;\nvUv = uv * uRepeat + uOffset;\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 );\nvPointLight[ i ] = vec4( lVector, lDistance );\n}\n#endif\n#ifdef VERTEX_TEXTURES\nvec3 dv = texture2D( tDisplacement, uv ).xyz;\nfloat df = uDisplacementScale * dv.x + uDisplacementBias;\nvec4 displacedPosition = vec4( normalize( vNormal.xyz ) * df, 0.0 ) + mvPosition;\ngl_Position = projectionMatrix * displacedPosition;\n#else\ngl_Position = projectionMatrix * mvPosition;\n#endif",
 THREE.ShaderChunk.shadowmap_vertex,"}"].join("\n")},cube:{uniforms:{tCube:{type:"t",value:1,texture:null},tFlip:{type:"f",value:-1}},vertexShader:"varying vec3 vViewPosition;\nvoid main() {\nvec4 mPosition = objectMatrix * vec4( position, 1.0 );\nvViewPosition = cameraPosition - mPosition.xyz;\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"uniform samplerCube tCube;\nuniform float tFlip;\nvarying vec3 vViewPosition;\nvoid main() {\nvec3 wPos = cameraPosition - vViewPosition;\ngl_FragColor = textureCube( tCube, vec3( tFlip * wPos.x, wPos.yz ) );\n}"}}});
+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(b){var a=b.familyName.toLowerCase();this.faces[a]=this.faces[a]||{};this.faces[a][b.cssFontWeight]=this.faces[a][b.cssFontWeight]||{};this.faces[a][b.cssFontWeight][b.cssFontStyle]=b;return this.faces[a][b.cssFontWeight][b.cssFontStyle]=b},drawText:function(b){for(var a=this.getFace(),c=this.size/a.resolution,d=
+0,e=(""+b).split(""),f=e.length,g=[],b=0;b<f;b++){var h=new THREE.Path,h=this.extractGlyphPoints(e[b],a,c,d,h),d=d+h.offset;g.push(h.path)}return{paths:g,offset:d/2}},extractGlyphPoints:function(b,a,c,d,e){var f=[],g,h,i,j,l,n,k,m,o,q,r,s=a.glyphs[b]||a.glyphs["?"];if(s){if(s.o){a=s._cachedOutline||(s._cachedOutline=s.o.split(" "));j=a.length;for(b=0;b<j;){i=a[b++];switch(i){case "m":i=a[b++]*c+d;l=a[b++]*c;e.moveTo(i,l);break;case "l":i=a[b++]*c+d;l=a[b++]*c;e.lineTo(i,l);break;case "q":i=a[b++]*
+c+d;l=a[b++]*c;m=a[b++]*c+d;o=a[b++]*c;e.quadraticCurveTo(m,o,i,l);if(g=f[f.length-1]){n=g.x;k=g.y;g=1;for(h=this.divisions;g<=h;g++){var t=g/h;THREE.Shape.Utils.b2(t,n,m,i);THREE.Shape.Utils.b2(t,k,o,l)}}break;case "b":i=a[b++]*c+d;l=a[b++]*c;m=a[b++]*c+d;o=a[b++]*-c;q=a[b++]*c+d;r=a[b++]*-c;e.bezierCurveTo(i,l,m,o,q,r);if(g=f[f.length-1]){n=g.x;k=g.y;g=1;for(h=this.divisions;g<=h;g++){t=g/h;THREE.Shape.Utils.b3(t,n,m,q,i);THREE.Shape.Utils.b3(t,k,o,r,l)}}}}}return{offset:s.ha*c,path:e}}}};
+THREE.FontUtils.generateShapes=function(b,a){var a=a||{},c=a.curveSegments!==void 0?a.curveSegments:4,d=a.font!==void 0?a.font:"helvetiker",e=a.weight!==void 0?a.weight:"normal",f=a.style!==void 0?a.style:"normal";THREE.FontUtils.size=a.size!==void 0?a.size:100;THREE.FontUtils.divisions=c;THREE.FontUtils.face=d;THREE.FontUtils.weight=e;THREE.FontUtils.style=f;c=THREE.FontUtils.drawText(b).paths;d=[];e=0;for(f=c.length;e<f;e++)Array.prototype.push.apply(d,c[e].toShapes());return d};
+(function(b){var a=function(a){for(var b=a.length,e=0,f=b-1,g=0;g<b;f=g++)e=e+(a[f].x*a[g].y-a[g].x*a[f].y);return e*0.5};b.Triangulate=function(b,d){var e=b.length;if(e<3)return null;var f=[],g=[],h=[],i,j,l;if(a(b)>0)for(j=0;j<e;j++)g[j]=j;else for(j=0;j<e;j++)g[j]=e-1-j;var n=2*e;for(j=e-1;e>2;){if(n--<=0){console.log("Warning, unable to triangulate polygon!");break}i=j;e<=i&&(i=0);j=i+1;e<=j&&(j=0);l=j+1;e<=l&&(l=0);var k;a:{k=b;var m=i,o=j,q=l,r=e,s=g,t=void 0,v=void 0,p=void 0,x=void 0,z=void 0,
+A=void 0,w=void 0,u=void 0,C=void 0,v=k[s[m]].x,p=k[s[m]].y,x=k[s[o]].x,z=k[s[o]].y,A=k[s[q]].x,w=k[s[q]].y;if(1.0E-10>(x-v)*(w-p)-(z-p)*(A-v))k=false;else{for(t=0;t<r;t++)if(!(t==m||t==o||t==q)){var u=k[s[t]].x,C=k[s[t]].y,B=void 0,E=void 0,G=void 0,L=void 0,H=void 0,D=void 0,K=void 0,F=void 0,N=void 0,I=void 0,M=void 0,J=void 0,B=G=H=void 0,B=A-x,E=w-z,G=v-A,L=p-w,H=x-v,D=z-p,K=u-v,F=C-p,N=u-x,I=C-z,M=u-A,J=C-w,B=B*I-E*N,H=H*F-D*K,G=G*J-L*M;if(B>=0&&G>=0&&H>=0){k=false;break a}}k=true}}if(k){f.push([b[g[i]],
+b[g[j]],b[g[l]]]);h.push([g[i],g[j],g[l]]);i=j;for(l=j+1;l<e;i++,l++)g[i]=g[l];e--;n=2*e}}return d?h:f};b.Triangulate.area=a;return b})(THREE.FontUtils);self._typeface_js={faces:THREE.FontUtils.faces,loadFace:THREE.FontUtils.loadFace};
 THREE.BufferGeometry=function(){this.id=THREE.GeometryCount++;this.vertexColorArray=this.vertexUvArray=this.vertexNormalArray=this.vertexPositionArray=this.vertexIndexArray=this.vertexColorBuffer=this.vertexUvBuffer=this.vertexNormalBuffer=this.vertexPositionBuffer=this.vertexIndexBuffer=null;this.dynamic=false;this.boundingSphere=this.boundingBox=null;this.morphTargets=[]};THREE.BufferGeometry.prototype={constructor:THREE.BufferGeometry,computeBoundingBox:function(){},computeBoundingSphere:function(){}};
 THREE.Curve=function(){};THREE.Curve.prototype.getPoint=function(){console.log("Warning, getPoint() not implemented!");return null};THREE.Curve.prototype.getPointAt=function(b){return this.getPoint(this.getUtoTmapping(b))};THREE.Curve.prototype.getPoints=function(b){b||(b=5);var a,c=[];for(a=0;a<=b;a++)c.push(this.getPoint(a/b));return c};THREE.Curve.prototype.getSpacedPoints=function(b){b||(b=5);var a,c=[];for(a=0;a<=b;a++)c.push(this.getPointAt(a/b));return c};
 THREE.Curve.prototype.getLength=function(){var b=this.getLengths();return b[b.length-1]};THREE.Curve.prototype.getLengths=function(b){b||(b=this.__arcLengthDivisions?this.__arcLengthDivisions:200);if(this.cacheArcLengths&&this.cacheArcLengths.length==b+1&&!this.needsUpdate)return this.cacheArcLengths;this.needsUpdate=false;var a=[],c,d=this.getPoint(0),e,f=0;a.push(0);for(e=1;e<=b;e++){c=this.getPoint(e/b);f=f+c.distanceTo(d);a.push(f);d=c}return this.cacheArcLengths=a};
@@ -50,7 +57,8 @@ THREE.QuadraticBezierCurve.prototype.getPoint=function(b){var a;a=THREE.Shape.Ut
 THREE.CubicBezierCurve=function(b,a,c,d){this.v0=b;this.v1=a;this.v2=c;this.v3=d};THREE.CubicBezierCurve.prototype=new THREE.Curve;THREE.CubicBezierCurve.prototype.constructor=THREE.CubicBezierCurve;THREE.CubicBezierCurve.prototype.getPoint=function(b){var a;a=THREE.Shape.Utils.b3(b,this.v0.x,this.v1.x,this.v2.x,this.v3.x);b=THREE.Shape.Utils.b3(b,this.v0.y,this.v1.y,this.v2.y,this.v3.y);return new THREE.Vector2(a,b)};
 THREE.CubicBezierCurve.prototype.getTangent=function(b){var a;a=THREE.Curve.Utils.tangentCubicBezier(b,this.v0.x,this.v1.x,this.v2.x,this.v3.x);b=THREE.Curve.Utils.tangentCubicBezier(b,this.v0.y,this.v1.y,this.v2.y,this.v3.y);a=new THREE.Vector2(a,b);a.normalize();return a};THREE.SplineCurve=function(b){this.points=b==void 0?[]:b};THREE.SplineCurve.prototype=new THREE.Curve;THREE.SplineCurve.prototype.constructor=THREE.SplineCurve;
 THREE.SplineCurve.prototype.getPoint=function(b){var a=new THREE.Vector2,c=[],d=this.points,e;e=(d.length-1)*b;b=Math.floor(e);e=e-b;c[0]=b==0?b:b-1;c[1]=b;c[2]=b>d.length-2?d.length-1:b+1;c[3]=b>d.length-3?d.length-1:b+2;a.x=THREE.Curve.Utils.interpolate(d[c[0]].x,d[c[1]].x,d[c[2]].x,d[c[3]].x,e);a.y=THREE.Curve.Utils.interpolate(d[c[0]].y,d[c[1]].y,d[c[2]].y,d[c[3]].y,e);return a};
-THREE.ArcCurve=function(b,a,c,d,e,f){this.aX=b;this.aY=a;this.aRadius=c;this.aStartAngle=d;this.aEndAngle=e;this.aClockwise=f};THREE.ArcCurve.prototype=new THREE.Curve;THREE.ArcCurve.prototype.constructor=THREE.ArcCurve;THREE.ArcCurve.prototype.getPoint=function(b){var a=this.aEndAngle-this.aStartAngle;this.aClockwise||(b=1-b);a=this.aStartAngle+b*a;b=this.aX+this.aRadius*Math.cos(a);a=this.aY+this.aRadius*Math.sin(a);return new THREE.Vector2(b,a)};
+THREE.EllipseCurve=function(b,a,c,d,e,f,g){this.aX=b;this.aY=a;this.xRadius=c;this.yRadius=d;this.aStartAngle=e;this.aEndAngle=f;this.aClockwise=g};THREE.EllipseCurve.prototype=new THREE.Curve;THREE.EllipseCurve.prototype.constructor=THREE.EllipseCurve;THREE.EllipseCurve.prototype.getPoint=function(b){var a=this.aEndAngle-this.aStartAngle;this.aClockwise||(b=1-b);a=this.aStartAngle+b*a;b=this.aX+this.xRadius*Math.cos(a);a=this.aY+this.yRadius*Math.sin(a);return new THREE.Vector2(b,a)};
+THREE.ArcCurve=function(b,a,c,d,e,f){THREE.EllipseCurve.call(this,b,a,c,c,d,e,f)};THREE.ArcCurve.prototype=new THREE.EllipseCurve;THREE.ArcCurve.prototype.constructor=THREE.ArcCurve;
 THREE.Curve.Utils={tangentQuadraticBezier:function(b,a,c,d){return 2*(1-b)*(c-a)+2*b*(d-c)},tangentCubicBezier:function(b,a,c,d,e){return-3*a*(1-b)*(1-b)+3*c*(1-b)*(1-b)-6*b*c*(1-b)+6*b*d*(1-b)-3*b*b*d+3*b*b*e},tangentSpline:function(b){return 6*b*b-6*b+(3*b*b-4*b+1)+(-6*b*b+6*b)+(3*b*b-2*b)},interpolate:function(b,a,c,d,e){var b=(c-b)*0.5,d=(d-a)*0.5,f=e*e;return(2*a-2*c+b+d)*e*f+(-3*a+3*c-2*b-d)*f+b*e+a}};
 THREE.Curve.create=function(b,a){b.prototype=new THREE.Curve;b.prototype.constructor=b;b.prototype.getPoint=a;return b};THREE.LineCurve3=THREE.Curve.create(function(b,a){this.v1=b;this.v2=a},function(b){var a=new THREE.Vector3;a.sub(this.v2,this.v1);a.multiplyScalar(b);a.addSelf(this.v1);return a});
 THREE.QuadraticBezierCurve3=THREE.Curve.create(function(b,a,c){this.v0=b;this.v1=a;this.v2=c},function(b){var a,c;a=THREE.Shape.Utils.b2(b,this.v0.x,this.v1.x,this.v2.x);c=THREE.Shape.Utils.b2(b,this.v0.y,this.v1.y,this.v2.y);b=THREE.Shape.Utils.b2(b,this.v0.z,this.v1.z,this.v2.z);return new THREE.Vector3(a,c,b)});
@@ -60,26 +68,23 @@ THREE.ClosedSplineCurve3=THREE.Curve.create(function(b){this.points=b==void 0?[]
 d[c[1]].z,d[c[2]].z,d[c[3]].z,e);return a});THREE.CurvePath=function(){this.curves=[];this.bends=[];this.autoClose=false};THREE.CurvePath.prototype=new THREE.Curve;THREE.CurvePath.prototype.constructor=THREE.CurvePath;THREE.CurvePath.prototype.add=function(b){this.curves.push(b)};THREE.CurvePath.prototype.checkConnection=function(){};
 THREE.CurvePath.prototype.closePath=function(){var b=this.curves[0].getPoint(0),a=this.curves[this.curves.length-1].getPoint(1);b.equals(a)||this.curves.push(new THREE.LineCurve(a,b))};THREE.CurvePath.prototype.getPoint=function(b){for(var a=b*this.getLength(),c=this.getCurveLengths(),b=0;b<c.length;){if(c[b]>=a){a=c[b]-a;b=this.curves[b];a=1-a/b.getLength();return b.getPointAt(a)}b++}return null};THREE.CurvePath.prototype.getLength=function(){var b=this.getCurveLengths();return b[b.length-1]};
 THREE.CurvePath.prototype.getCurveLengths=function(){if(this.cacheLengths&&this.cacheLengths.length==this.curves.length)return this.cacheLengths;var b=[],a=0,c,d=this.curves.length;for(c=0;c<d;c++){a=a+this.curves[c].getLength();b.push(a)}return this.cacheLengths=b};
-THREE.CurvePath.prototype.getBoundingBox=function(){var b=this.getPoints(),a,c,d,e;a=c=Number.NEGATIVE_INFINITY;d=e=Number.POSITIVE_INFINITY;var f,g,h,i;i=new THREE.Vector2;g=0;for(h=b.length;g<h;g++){f=b[g];if(f.x>a)a=f.x;else if(f.x<d)d=f.x;if(f.y>c)c=f.y;else if(f.y<c)e=f.y;i.addSelf(f.x,f.y)}return{minX:d,minY:e,maxX:a,maxY:c,centroid:i.divideScalar(h)}};THREE.CurvePath.prototype.createPointsGeometry=function(b){return this.createGeometry(this.getPoints(b,true))};
+THREE.CurvePath.prototype.getBoundingBox=function(){var b=this.getPoints(),a,c,d,e;a=c=Number.NEGATIVE_INFINITY;d=e=Number.POSITIVE_INFINITY;var f,g,h,i;i=new THREE.Vector2;g=0;for(h=b.length;g<h;g++){f=b[g];if(f.x>a)a=f.x;else if(f.x<d)d=f.x;if(f.y>c)c=f.y;else if(f.y<e)e=f.y;i.addSelf(f.x,f.y)}return{minX:d,minY:e,maxX:a,maxY:c,centroid:i.divideScalar(h)}};THREE.CurvePath.prototype.createPointsGeometry=function(b){return this.createGeometry(this.getPoints(b,true))};
 THREE.CurvePath.prototype.createSpacedPointsGeometry=function(b){return this.createGeometry(this.getSpacedPoints(b,true))};THREE.CurvePath.prototype.createGeometry=function(b){for(var a=new THREE.Geometry,c=0;c<b.length;c++)a.vertices.push(new THREE.Vector3(b[c].x,b[c].y,0));return a};THREE.CurvePath.prototype.addWrapPath=function(b){this.bends.push(b)};
 THREE.CurvePath.prototype.getTransformedPoints=function(b,a){var c=this.getPoints(b),d,e;if(!a)a=this.bends;d=0;for(e=a.length;d<e;d++)c=this.getWrapPoints(c,a[d]);return c};THREE.CurvePath.prototype.getTransformedSpacedPoints=function(b,a){var c=this.getSpacedPoints(b),d,e;if(!a)a=this.bends;d=0;for(e=a.length;d<e;d++)c=this.getWrapPoints(c,a[d]);return c};
-THREE.CurvePath.prototype.getWrapPoints=function(b,a){var c=this.getBoundingBox(),d,e,f,g,h,i;d=0;for(e=b.length;d<e;d++){f=b[d];g=f.x;h=f.y;i=g/c.maxX;i=a.getUtoTmapping(i,g);g=a.getPoint(i);h=a.getNormalVector(i).multiplyScalar(h);f.x=g.x+h.x;f.y=g.y+h.y}return b};
-THREE.EventTarget=function(){var b={};this.addEventListener=function(a,c){b[a]==void 0&&(b[a]=[]);b[a].indexOf(c)===-1&&b[a].push(c)};this.dispatchEvent=function(a){for(var c in b[a.type])b[a.type][c](a)};this.removeEventListener=function(a,c){var d=b[a].indexOf(c);d!==-1&&b[a].splice(d,1)}};THREE.Gyroscope=function(){THREE.Object3D.call(this)};THREE.Gyroscope.prototype=new THREE.Object3D;THREE.Gyroscope.prototype.constructor=THREE.Gyroscope;
+THREE.CurvePath.prototype.getWrapPoints=function(b,a){var c=this.getBoundingBox(),d,e,f,g,h,i;d=0;for(e=b.length;d<e;d++){f=b[d];g=f.x;h=f.y;i=g/c.maxX;i=a.getUtoTmapping(i,g);g=a.getPoint(i);h=a.getNormalVector(i).multiplyScalar(h);f.x=g.x+h.x;f.y=g.y+h.y}return b};THREE.Gyroscope=function(){THREE.Object3D.call(this)};THREE.Gyroscope.prototype=new THREE.Object3D;THREE.Gyroscope.prototype.constructor=THREE.Gyroscope;
 THREE.Gyroscope.prototype.updateMatrixWorld=function(b){this.matrixAutoUpdate&&this.updateMatrix();if(this.matrixWorldNeedsUpdate||b){if(this.parent){this.matrixWorld.multiply(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;b=true}for(var a=0,c=this.children.length;a<c;a++)this.children[a].updateMatrixWorld(b)};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(b){THREE.CurvePath.call(this);this.actions=[];b&&this.fromPoints(b)};THREE.Path.prototype=new THREE.CurvePath;THREE.Path.prototype.constructor=THREE.Path;THREE.PathActions={MOVE_TO:"moveTo",LINE_TO:"lineTo",QUADRATIC_CURVE_TO:"quadraticCurveTo",BEZIER_CURVE_TO:"bezierCurveTo",CSPLINE_THRU:"splineThru",ARC:"arc"};THREE.Path.prototype.fromPoints=function(b){this.moveTo(b[0].x,b[0].y);for(var a=1,c=b.length;a<c;a++)this.lineTo(b[a].x,b[a].y)};
+THREE.Path=function(b){THREE.CurvePath.call(this);this.actions=[];b&&this.fromPoints(b)};THREE.Path.prototype=new THREE.CurvePath;THREE.Path.prototype.constructor=THREE.Path;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(b){this.moveTo(b[0].x,b[0].y);for(var a=1,c=b.length;a<c;a++)this.lineTo(b[a].x,b[a].y)};
 THREE.Path.prototype.moveTo=function(b,a){var c=Array.prototype.slice.call(arguments);this.actions.push({action:THREE.PathActions.MOVE_TO,args:c})};THREE.Path.prototype.lineTo=function(b,a){var c=Array.prototype.slice.call(arguments),d=this.actions[this.actions.length-1].args;this.curves.push(new THREE.LineCurve(new THREE.Vector2(d[d.length-2],d[d.length-1]),new THREE.Vector2(b,a)));this.actions.push({action:THREE.PathActions.LINE_TO,args:c})};
 THREE.Path.prototype.quadraticCurveTo=function(b,a,c,d){var e=Array.prototype.slice.call(arguments),f=this.actions[this.actions.length-1].args;this.curves.push(new THREE.QuadraticBezierCurve(new THREE.Vector2(f[f.length-2],f[f.length-1]),new THREE.Vector2(b,a),new THREE.Vector2(c,d)));this.actions.push({action:THREE.PathActions.QUADRATIC_CURVE_TO,args:e})};
 THREE.Path.prototype.bezierCurveTo=function(b,a,c,d,e,f){var g=Array.prototype.slice.call(arguments),h=this.actions[this.actions.length-1].args;this.curves.push(new THREE.CubicBezierCurve(new THREE.Vector2(h[h.length-2],h[h.length-1]),new THREE.Vector2(b,a),new THREE.Vector2(c,d),new THREE.Vector2(e,f)));this.actions.push({action:THREE.PathActions.BEZIER_CURVE_TO,args:g})};
-THREE.Path.prototype.splineThru=function(b){var a=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,b);this.curves.push(new THREE.SplineCurve(c));this.actions.push({action:THREE.PathActions.CSPLINE_THRU,args:a})};
-THREE.Path.prototype.arc=function(b,a,c,d,e,f){var g=Array.prototype.slice.call(arguments),h=this.actions[this.actions.length-1],h=new THREE.ArcCurve(h.x+b,h.y+a,c,d,e,f);this.curves.push(h);h=h.getPoint(f?1:0);g.push(h.x);g.push(h.y);this.actions.push({action:THREE.PathActions.ARC,args:g})};
-THREE.Path.prototype.absarc=function(b,a,c,d,e,f){var g=Array.prototype.slice.call(arguments),h=new THREE.ArcCurve(b,a,c,d,e,f);this.curves.push(h);h=h.getPoint(f?1:0);g.push(h.x);g.push(h.y);this.actions.push({action:THREE.PathActions.ARC,args:g})};THREE.Path.prototype.getSpacedPoints=function(b){b||(b=40);for(var a=[],c=0;c<b;c++)a.push(this.getPoint(c/b));return a};
+THREE.Path.prototype.splineThru=function(b){var a=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,b);this.curves.push(new THREE.SplineCurve(c));this.actions.push({action:THREE.PathActions.CSPLINE_THRU,args:a})};THREE.Path.prototype.ellipse=function(b,a,c,d,e,f,g){var h=this.actions[this.actions.length-1];this.absellipse(h.x+b,h.y+a,c,d,e,f,g)};
+THREE.Path.prototype.arc=function(b,a,c,d,e,f){var g=this.actions[this.actions.length-1];this.absarc(g.x+b,g.y+a,c,d,e,f)};THREE.Path.prototype.absellipse=function(b,a,c,d,e,f,g){var h=Array.prototype.slice.call(arguments),i=new THREE.EllipseCurve(b,a,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.absarc=function(b,a,c,d,e,f){this.absellipse(b,a,c,c,d,e,f)};
+THREE.Path.prototype.getSpacedPoints=function(b){b||(b=40);for(var a=[],c=0;c<b;c++)a.push(this.getPoint(c/b));return a};
 THREE.Path.prototype.getPoints=function(b,a){if(this.useSpacedPoints){console.log("tata");return this.getSpacedPoints(b,a)}var b=b||12,c=[],d,e,f,g,h,i,j,l,n,k,m,o,q;d=0;for(e=this.actions.length;d<e;d++){f=this.actions[d];g=f.action;f=f.args;switch(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];n=f[0];k=f[1];if(c.length>0){g=c[c.length-1];
 m=g.x;o=g.y}else{g=this.actions[d-1].args;m=g[g.length-2];o=g[g.length-1]}for(f=1;f<=b;f++){q=f/b;g=THREE.Shape.Utils.b2(q,m,n,h);q=THREE.Shape.Utils.b2(q,o,k,i);c.push(new THREE.Vector2(g,q))}break;case THREE.PathActions.BEZIER_CURVE_TO:h=f[4];i=f[5];n=f[0];k=f[1];j=f[2];l=f[3];if(c.length>0){g=c[c.length-1];m=g.x;o=g.y}else{g=this.actions[d-1].args;m=g[g.length-2];o=g[g.length-1]}for(f=1;f<=b;f++){q=f/b;g=THREE.Shape.Utils.b3(q,m,n,j,h);q=THREE.Shape.Utils.b3(q,o,k,l,i);c.push(new THREE.Vector2(g,
-q))}break;case THREE.PathActions.CSPLINE_THRU:g=this.actions[d-1].args;q=[new THREE.Vector2(g[g.length-2],g[g.length-1])];g=b*f[0].length;q=q.concat(f[0]);q=new THREE.SplineCurve(q);for(f=1;f<=g;f++)c.push(q.getPointAt(f/g));break;case THREE.PathActions.ARC:h=f[0];i=f[1];j=f[2];n=f[3];k=!!f[5];l=f[4]-n;m=b*2;for(f=1;f<=m;f++){q=f/m;k||(q=1-q);q=n+q*l;g=h+j*Math.cos(q);q=i+j*Math.sin(q);c.push(new THREE.Vector2(g,q))}}}d=c[c.length-1];Math.abs(d.x-c[0].x)<1.0E-10&&Math.abs(d.y-c[0].y)<1.0E-10&&c.splice(c.length-
-1,1);a&&c.push(c[0]);return c};THREE.Path.prototype.transform=function(b,a){this.getBoundingBox();return this.getWrapPoints(this.getPoints(a),b)};THREE.Path.prototype.nltransform=function(b,a,c,d,e,f){var g=this.getPoints(),h,i,j,l,n;h=0;for(i=g.length;h<i;h++){j=g[h];l=j.x;n=j.y;j.x=b*l+a*n+c;j.y=d*n+e*l+f}return g};
-THREE.Path.prototype.debug=function(b){var a=this.getBoundingBox();if(!b){b=document.createElement("canvas");b.setAttribute("width",a.maxX+100);b.setAttribute("height",a.maxY+100);document.body.appendChild(b)}a=b.getContext("2d");a.fillStyle="white";a.fillRect(0,0,b.width,b.height);a.strokeStyle="black";a.beginPath();var c,d,e,b=0;for(c=this.actions.length;b<c;b++){d=this.actions[b];e=d.args;d=d.action;d!=THREE.PathActions.CSPLINE_THRU&&a[d].apply(a,e)}a.stroke();a.closePath();a.strokeStyle="red";
-d=this.getPoints();b=0;for(c=d.length;b<c;b++){e=d[b];a.beginPath();a.arc(e.x,e.y,1.5,0,Math.PI*2,false);a.stroke();a.closePath()}};
+q))}break;case THREE.PathActions.CSPLINE_THRU:g=this.actions[d-1].args;q=[new THREE.Vector2(g[g.length-2],g[g.length-1])];g=b*f[0].length;q=q.concat(f[0]);q=new THREE.SplineCurve(q);for(f=1;f<=g;f++)c.push(q.getPointAt(f/g));break;case THREE.PathActions.ARC:h=f[0];i=f[1];k=f[2];j=f[3];g=f[4];n=!!f[5];m=g-j;o=b*2;for(f=1;f<=o;f++){q=f/o;n||(q=1-q);q=j+q*m;g=h+k*Math.cos(q);q=i+k*Math.sin(q);c.push(new THREE.Vector2(g,q))}break;case THREE.PathActions.ELLIPSE:h=f[0];i=f[1];k=f[2];l=f[3];j=f[4];g=f[5];
+n=!!f[6];m=g-j;o=b*2;for(f=1;f<=o;f++){q=f/o;n||(q=1-q);q=j+q*m;g=h+k*Math.cos(q);q=i+l*Math.sin(q);c.push(new THREE.Vector2(g,q))}}}d=c[c.length-1];Math.abs(d.x-c[0].x)<1.0E-10&&Math.abs(d.y-c[0].y)<1.0E-10&&c.splice(c.length-1,1);a&&c.push(c[0]);return c};
 THREE.Path.prototype.toShapes=function(){var b,a,c,d,e=[],f=new THREE.Path;b=0;for(a=this.actions.length;b<a;b++){c=this.actions[b];d=c.args;c=c.action;if(c==THREE.PathActions.MOVE_TO&&f.actions.length!=0){e.push(f);f=new THREE.Path}f[c].apply(f,d)}f.actions.length!=0&&e.push(f);if(e.length==0)return[];var g;d=[];b=!THREE.Shape.Utils.isClockWise(e[0].getPoints());if(e.length==1){f=e[0];g=new THREE.Shape;g.actions=f.actions;g.curves=f.curves;d.push(g);return d}if(b){g=new THREE.Shape;b=0;for(a=e.length;b<
 a;b++){f=e[b];if(THREE.Shape.Utils.isClockWise(f.getPoints())){g.actions=f.actions;g.curves=f.curves;d.push(g);g=new THREE.Shape}else g.holes.push(f)}}else{b=0;for(a=e.length;b<a;b++){f=e[b];if(THREE.Shape.Utils.isClockWise(f.getPoints())){g&&d.push(g);g=new THREE.Shape;g.actions=f.actions;g.curves=f.curves}else g.holes.push(f)}d.push(g)}return d};THREE.Shape=function(){THREE.Path.apply(this,arguments);this.holes=[]};THREE.Shape.prototype=new THREE.Path;THREE.Shape.prototype.constructor=THREE.Path;
 THREE.Shape.prototype.extrude=function(b){return new THREE.ExtrudeGeometry(this,b)};THREE.Shape.prototype.getPointsHoles=function(b){var a,c=this.holes.length,d=[];for(a=0;a<c;a++)d[a]=this.holes[a].getTransformedPoints(b,this.bends);return d};THREE.Shape.prototype.getSpacedPointsHoles=function(b){var a,c=this.holes.length,d=[];for(a=0;a<c;a++)d[a]=this.holes[a].getTransformedSpacedPoints(b,this.bends);return d};
@@ -88,13 +93,12 @@ THREE.Shape.Utils={removeHoles:function(b,a){var c=b.concat(),d=c.concat(),e,f,g
 -1;h<0&&(h=h+c.length);h=h%c.length;g<0&&(g=g+j.length);g=g%j.length;e=h-1>=0?h-1:c.length-1;f=g-1>=0?g-1:j.length-1;q=[j[g],c[h],c[e]];q=THREE.FontUtils.Triangulate.area(q);r=[j[g],j[f],c[h]];r=THREE.FontUtils.Triangulate.area(r);if(n+k>q+r){h=m;g=l;h<0&&(h=h+c.length);h=h%c.length;g<0&&(g=g+j.length);g=g%j.length;e=h-1>=0?h-1:c.length-1;f=g-1>=0?g-1:j.length-1}n=c.slice(0,h);k=c.slice(h);m=j.slice(g);l=j.slice(0,g);f=[j[g],j[f],c[h]];o.push([j[g],c[h],c[e]]);o.push(f);c=n.concat(m).concat(l).concat(k)}return{shape:c,
 isolatedPts:o,allpoints:d}},triangulateShape:function(b,a){var c=THREE.Shape.Utils.removeHoles(b,a),d=c.allpoints,e=c.isolatedPts,c=THREE.FontUtils.Triangulate(c.shape,false),f,g,h,i,j={};f=0;for(g=d.length;f<g;f++){i=d[f].x+":"+d[f].y;j[i]!==void 0&&console.log("Duplicate point",i);j[i]=f}f=0;for(g=c.length;f<g;f++){h=c[f];for(d=0;d<3;d++){i=h[d].x+":"+h[d].y;i=j[i];i!==void 0&&(h[d]=i)}}f=0;for(g=e.length;f<g;f++){h=e[f];for(d=0;d<3;d++){i=h[d].x+":"+h[d].y;i=j[i];i!==void 0&&(h[d]=i)}}return c.concat(e)},
 isClockWise:function(b){return THREE.FontUtils.Triangulate.area(b)<0},b2p0:function(b,a){var c=1-b;return c*c*a},b2p1:function(b,a){return 2*(1-b)*b*a},b2p2:function(b,a){return b*b*a},b2:function(b,a,c,d){return this.b2p0(b,a)+this.b2p1(b,c)+this.b2p2(b,d)},b3p0:function(b,a){var c=1-b;return c*c*c*a},b3p1:function(b,a){var c=1-b;return 3*c*c*b*a},b3p2:function(b,a){return 3*(1-b)*b*b*a},b3p3:function(b,a){return b*b*b*a},b3:function(b,a,c,d,e){return this.b3p0(b,a)+this.b3p1(b,c)+this.b3p2(b,d)+
-this.b3p3(b,e)}};THREE.TextPath=function(b,a){THREE.Path.call(this);this.parameters=a||{};this.set(b)};THREE.TextPath.prototype.set=function(b,a){a=a||this.parameters;this.text=b;var c=a.curveSegments!==void 0?a.curveSegments:4,d=a.font!==void 0?a.font:"helvetiker",e=a.weight!==void 0?a.weight:"normal",f=a.style!==void 0?a.style:"normal";THREE.FontUtils.size=a.size!==void 0?a.size:100;THREE.FontUtils.divisions=c;THREE.FontUtils.face=d;THREE.FontUtils.weight=e;THREE.FontUtils.style=f};
-THREE.TextPath.prototype.toShapes=function(){for(var b=THREE.FontUtils.drawText(this.text).paths,a=[],c=0,d=b.length;c<d;c++)Array.prototype.push.apply(a,b[c].toShapes());return a};
-THREE.AnimationHandler=function(){var b=[],a={},c={update:function(a){for(var c=0;c<b.length;c++)b[c].update(a)},addToUpdate:function(a){b.indexOf(a)===-1&&b.push(a)},removeFromUpdate:function(a){a=b.indexOf(a);a!==-1&&b.splice(a,1)},add:function(b){a[b.name]!==void 0&&console.log("THREE.AnimationHandler.add: Warning! "+b.name+" already exists in library. Overwriting.");a[b.name]=b;if(b.initialized!==true){for(var c=0;c<b.hierarchy.length;c++){for(var d=0;d<b.hierarchy[c].keys.length;d++){if(b.hierarchy[c].keys[d].time<
-0)b.hierarchy[c].keys[d].time=0;if(b.hierarchy[c].keys[d].rot!==void 0&&!(b.hierarchy[c].keys[d].rot instanceof THREE.Quaternion)){var h=b.hierarchy[c].keys[d].rot;b.hierarchy[c].keys[d].rot=new THREE.Quaternion(h[0],h[1],h[2],h[3])}}if(b.hierarchy[c].keys.length&&b.hierarchy[c].keys[0].morphTargets!==void 0){h={};for(d=0;d<b.hierarchy[c].keys.length;d++)for(var i=0;i<b.hierarchy[c].keys[d].morphTargets.length;i++){var j=b.hierarchy[c].keys[d].morphTargets[i];h[j]=-1}b.hierarchy[c].usedMorphTargets=
-h;for(d=0;d<b.hierarchy[c].keys.length;d++){var l={};for(j in h){for(i=0;i<b.hierarchy[c].keys[d].morphTargets.length;i++)if(b.hierarchy[c].keys[d].morphTargets[i]===j){l[j]=b.hierarchy[c].keys[d].morphTargetsInfluences[i];break}i===b.hierarchy[c].keys[d].morphTargets.length&&(l[j]=0)}b.hierarchy[c].keys[d].morphTargetsInfluences=l}}for(d=1;d<b.hierarchy[c].keys.length;d++)if(b.hierarchy[c].keys[d].time===b.hierarchy[c].keys[d-1].time){b.hierarchy[c].keys.splice(d,1);d--}for(d=0;d<b.hierarchy[c].keys.length;d++)b.hierarchy[c].keys[d].index=
-d}d=parseInt(b.length*b.fps,10);b.JIT={};b.JIT.hierarchy=[];for(c=0;c<b.hierarchy.length;c++)b.JIT.hierarchy.push(Array(d));b.initialized=true}},get:function(b){if(typeof b==="string"){if(a[b])return a[b];console.log("THREE.AnimationHandler.get: Couldn't find animation "+b);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(b,a,c,d){this.root=b;this.data=THREE.AnimationHandler.get(a);this.hierarchy=THREE.AnimationHandler.parse(b);this.currentTime=0;this.timeScale=1;this.isPlaying=false;this.loop=this.isPaused=true;this.interpolationType=c!==void 0?c:THREE.AnimationHandler.LINEAR;this.JITCompile=d!==void 0?d:true;this.points=[];this.target=new THREE.Vector3};
+this.b3p3(b,e)}};
+THREE.AnimationHandler=function(){var b=[],a={},c={update:function(a){for(var c=0;c<b.length;c++)b[c].update(a)},addToUpdate:function(a){b.indexOf(a)===-1&&b.push(a)},removeFromUpdate:function(a){a=b.indexOf(a);a!==-1&&b.splice(a,1)},add:function(b){a[b.name]!==void 0&&console.log("THREE.AnimationHandler.add: Warning! "+b.name+" already exists in library. Overwriting.");a[b.name]=b;if(b.initialized!==true){for(var c=0;c<b.hierarchy.length;c++){for(var d=0;d<b.hierarchy[c].keys.length;d++){if(b.hierarchy[c].keys[d].time<0)b.hierarchy[c].keys[d].time=
+0;if(b.hierarchy[c].keys[d].rot!==void 0&&!(b.hierarchy[c].keys[d].rot instanceof THREE.Quaternion)){var h=b.hierarchy[c].keys[d].rot;b.hierarchy[c].keys[d].rot=new THREE.Quaternion(h[0],h[1],h[2],h[3])}}if(b.hierarchy[c].keys.length&&b.hierarchy[c].keys[0].morphTargets!==void 0){h={};for(d=0;d<b.hierarchy[c].keys.length;d++)for(var i=0;i<b.hierarchy[c].keys[d].morphTargets.length;i++){var j=b.hierarchy[c].keys[d].morphTargets[i];h[j]=-1}b.hierarchy[c].usedMorphTargets=h;for(d=0;d<b.hierarchy[c].keys.length;d++){var l=
+{};for(j in h){for(i=0;i<b.hierarchy[c].keys[d].morphTargets.length;i++)if(b.hierarchy[c].keys[d].morphTargets[i]===j){l[j]=b.hierarchy[c].keys[d].morphTargetsInfluences[i];break}i===b.hierarchy[c].keys[d].morphTargets.length&&(l[j]=0)}b.hierarchy[c].keys[d].morphTargetsInfluences=l}}for(d=1;d<b.hierarchy[c].keys.length;d++)if(b.hierarchy[c].keys[d].time===b.hierarchy[c].keys[d-1].time){b.hierarchy[c].keys.splice(d,1);d--}for(d=0;d<b.hierarchy[c].keys.length;d++)b.hierarchy[c].keys[d].index=d}d=parseInt(b.length*
+b.fps,10);b.JIT={};b.JIT.hierarchy=[];for(c=0;c<b.hierarchy.length;c++)b.JIT.hierarchy.push(Array(d));b.initialized=true}},get:function(b){if(typeof b==="string"){if(a[b])return a[b];console.log("THREE.AnimationHandler.get: Couldn't find animation "+b);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(b,a,c,d){this.root=b;this.data=THREE.AnimationHandler.get(a);this.hierarchy=THREE.AnimationHandler.parse(b);this.currentTime=0;this.timeScale=1;this.isPlaying=false;this.loop=this.isPaused=true;this.interpolationType=c!==void 0?c:THREE.AnimationHandler.LINEAR;this.JITCompile=d!==void 0?d:true;this.points=[];this.target=new THREE.Vector3};
 THREE.Animation.prototype.play=function(b,a){if(!this.isPlaying){this.isPlaying=true;this.loop=b!==void 0?b:true;this.currentTime=a!==void 0?a:0;var c,d=this.hierarchy.length,e;for(c=0;c<d;c++){e=this.hierarchy[c];if(this.interpolationType!==THREE.AnimationHandler.CATMULLROM_FORWARD)e.useQuaternion=true;e.matrixAutoUpdate=true;if(e.animationCache===void 0){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=false;THREE.AnimationHandler.addToUpdate(this)};
 THREE.Animation.prototype.pause=function(){this.isPaused?THREE.AnimationHandler.addToUpdate(this):THREE.AnimationHandler.removeFromUpdate(this);this.isPaused=!this.isPaused};
@@ -107,7 +111,7 @@ this.target.z);b.rotation.set(0,d,0)}}}else if(c==="rot")THREE.Quaternion.slerp(
 THREE.Animation.prototype.interpolateCatmullRom=function(b,a){var c=[],d=[],e,f,g,h,i,j;e=(b.length-1)*a;f=Math.floor(e);e=e-f;c[0]=f===0?f:f-1;c[1]=f;c[2]=f>b.length-2?f:f+1;c[3]=f>b.length-3?f:f+2;f=b[c[0]];h=b[c[1]];i=b[c[2]];j=b[c[3]];c=e*e;g=e*c;d[0]=this.interpolate(f[0],h[0],i[0],j[0],e,c,g);d[1]=this.interpolate(f[1],h[1],i[1],j[1],e,c,g);d[2]=this.interpolate(f[2],h[2],i[2],j[2],e,c,g);return d};
 THREE.Animation.prototype.interpolate=function(b,a,c,d,e,f,g){b=(c-b)*0.5;d=(d-a)*0.5;return(2*(a-c)+b+d)*g+(-3*(a-c)-2*b-d)*f+b*e+a};THREE.Animation.prototype.getNextKeyWith=function(b,a,c){for(var d=this.data.hierarchy[a].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(d[c][b]!==void 0)return d[c];return this.data.hierarchy[a].keys[0]};
 THREE.Animation.prototype.getPrevKeyWith=function(b,a,c){for(var d=this.data.hierarchy[a].keys,c=this.interpolationType===THREE.AnimationHandler.CATMULLROM||this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD?c>0?c:0:c>=0?c:c+d.length;c>=0;c--)if(d[c][b]!==void 0)return d[c];return this.data.hierarchy[a].keys[d.length-1]};
-THREE.KeyFrameAnimation=function(b,a,c){this.root=b;this.data=THREE.AnimationHandler.get(a);this.hierarchy=THREE.AnimationHandler.parse(b);this.currentTime=0;this.timeScale=0.0010;this.isPlaying=false;this.loop=this.isPaused=true;this.JITCompile=c!==void 0?c:true;b=0;for(a=this.hierarchy.length;b<a;b++){var c=this.data.hierarchy[b].sids,d=this.hierarchy[b];if(this.data.hierarchy[b].keys.length&&c){for(var e=0;e<c.length;e++){var f=c[e],g=this.getNextKeyWith(f,b,0);g&&g.apply(f)}d.matrixAutoUpdate=
+THREE.KeyFrameAnimation=function(b,a,c){this.root=b;this.data=THREE.AnimationHandler.get(a);this.hierarchy=THREE.AnimationHandler.parse(b);this.currentTime=0;this.timeScale=0.001;this.isPlaying=false;this.loop=this.isPaused=true;this.JITCompile=c!==void 0?c:true;b=0;for(a=this.hierarchy.length;b<a;b++){var c=this.data.hierarchy[b].sids,d=this.hierarchy[b];if(this.data.hierarchy[b].keys.length&&c){for(var e=0;e<c.length;e++){var f=c[e],g=this.getNextKeyWith(f,b,0);g&&g.apply(f)}d.matrixAutoUpdate=
 false;this.data.hierarchy[b].node.updateMatrix();d.matrixWorldNeedsUpdate=true}}};
 THREE.KeyFrameAnimation.prototype.play=function(b,a){if(!this.isPlaying){this.isPlaying=true;this.loop=b!==void 0?b:true;this.currentTime=a!==void 0?a:0;this.startTimeMs=a;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=true;if(f.animationCache===void 0){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;if(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=false;THREE.AnimationHandler.addToUpdate(this)};THREE.KeyFrameAnimation.prototype.pause=function(){this.isPaused?THREE.AnimationHandler.addToUpdate(this):THREE.AnimationHandler.removeFromUpdate(this);this.isPaused=!this.isPaused};
@@ -127,26 +131,26 @@ THREE.CombinedCamera.prototype.setSize=function(b,a){this.cameraP.aspect=b/a;thi
 THREE.CombinedCamera.prototype.setLens=function(b,a){var c=2*Math.atan((a!==void 0?a:24)/(b*2))*(180/Math.PI);this.setFov(c);return c};THREE.CombinedCamera.prototype.setZoom=function(b){this.zoom=b;this.inPersepectiveMode?this.toPerspective():this.toOrthographic()};THREE.CombinedCamera.prototype.toFrontView=function(){this.rotation.x=0;this.rotation.y=0;this.rotation.z=0;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};
-THREE.FirstPersonControls=function(b,a){function c(a,b){return function(){b.apply(a,arguments)}}this.object=b;this.target=new THREE.Vector3(0,0,0);this.domElement=a!==void 0?a:document;this.movementSpeed=1;this.lookSpeed=0.0050;this.noFly=false;this.lookVertical=true;this.autoForward=false;this.activeLook=true;this.heightSpeed=false;this.heightCoef=1;this.heightMin=0;this.constrainVertical=false;this.verticalMin=0;this.verticalMax=Math.PI;this.theta=this.phi=this.lon=this.lat=this.mouseY=this.mouseX=
+THREE.FirstPersonControls=function(b,a){function c(a,b){return function(){b.apply(a,arguments)}}this.object=b;this.target=new THREE.Vector3(0,0,0);this.domElement=a!==void 0?a:document;this.movementSpeed=1;this.lookSpeed=0.005;this.noFly=false;this.lookVertical=true;this.autoForward=false;this.activeLook=true;this.heightSpeed=false;this.heightCoef=1;this.heightMin=0;this.constrainVertical=false;this.verticalMin=0;this.verticalMax=Math.PI;this.theta=this.phi=this.lon=this.lat=this.mouseY=this.mouseX=
 this.autoSpeedFactor=0;this.mouseDragOn=this.freeze=this.moveRight=this.moveLeft=this.moveBackward=this.moveForward=false;if(this.domElement===document){this.viewHalfX=window.innerWidth/2;this.viewHalfY=window.innerHeight/2}else{this.viewHalfX=this.domElement.offsetWidth/2;this.viewHalfY=this.domElement.offsetHeight/2;this.domElement.setAttribute("tabindex",-1)}this.onMouseDown=function(a){this.domElement!==document&&this.domElement.focus();a.preventDefault();a.stopPropagation();if(this.activeLook)switch(a.button){case 0:this.moveForward=
 true;break;case 2:this.moveBackward=true}this.mouseDragOn=true};this.onMouseUp=function(a){a.preventDefault();a.stopPropagation();if(this.activeLook)switch(a.button){case 0:this.moveForward=false;break;case 2:this.moveBackward=false}this.mouseDragOn=false};this.onMouseMove=function(a){if(this.domElement===document){this.mouseX=a.pageX-this.viewHalfX;this.mouseY=a.pageY-this.viewHalfY}else{this.mouseX=a.pageX-this.domElement.offsetLeft-this.viewHalfX;this.mouseY=a.pageY-this.domElement.offsetTop-this.viewHalfY}};
-this.onKeyDown=function(a){switch(a.keyCode){case 38:case 87:this.moveForward=true;break;case 37:case 65:this.moveLeft=true;break;case 40:case 83:this.moveBackward=true;break;case 39:case 68:this.moveRight=true;break;case 82:this.moveUp=true;break;case 70:this.moveDown=true;break;case 81:this.freeze=!this.freeze}};this.onKeyUp=function(a){switch(a.keyCode){case 38:case 87:this.moveForward=false;break;case 37:case 65:this.moveLeft=false;break;case 40:case 83:this.moveBackward=false;break;case 39:case 68:this.moveRight=
-false;break;case 82:this.moveUp=false;break;case 70:this.moveDown=false}};this.update=function(a){var b=0;if(!this.freeze){if(this.heightSpeed){b=THREE.Math.clamp(this.object.position.y,this.heightMin,this.heightMax)-this.heightMin;this.autoSpeedFactor=a*b*this.heightCoef}else this.autoSpeedFactor=0;b=a*this.movementSpeed;(this.moveForward||this.autoForward&&!this.moveBackward)&&this.object.translateZ(-(b+this.autoSpeedFactor));this.moveBackward&&this.object.translateZ(b);this.moveLeft&&this.object.translateX(-b);
-this.moveRight&&this.object.translateX(b);this.moveUp&&this.object.translateY(b);this.moveDown&&this.object.translateY(-b);a=a*this.lookSpeed;this.activeLook||(a=0);this.lon=this.lon+this.mouseX*a;if(this.lookVertical)this.lat=this.lat-this.mouseY*a;this.lat=Math.max(-85,Math.min(85,this.lat));this.phi=(90-this.lat)*Math.PI/180;this.theta=this.lon*Math.PI/180;var b=this.target,c=this.object.position;b.x=c.x+100*Math.sin(this.phi)*Math.cos(this.theta);b.y=c.y+100*Math.cos(this.phi);b.z=c.z+100*Math.sin(this.phi)*
-Math.sin(this.theta);b=1;this.constrainVertical&&(b=Math.PI/(this.verticalMax-this.verticalMin));this.lon=this.lon+this.mouseX*a;if(this.lookVertical)this.lat=this.lat-this.mouseY*a*b;this.lat=Math.max(-85,Math.min(85,this.lat));this.phi=(90-this.lat)*Math.PI/180;this.theta=this.lon*Math.PI/180;if(this.constrainVertical)this.phi=THREE.Math.mapLinear(this.phi,0,Math.PI,this.verticalMin,this.verticalMax);b=this.target;c=this.object.position;b.x=c.x+100*Math.sin(this.phi)*Math.cos(this.theta);b.y=c.y+
-100*Math.cos(this.phi);b.z=c.z+100*Math.sin(this.phi)*Math.sin(this.theta);this.object.lookAt(b)}};this.domElement.addEventListener("contextmenu",function(a){a.preventDefault()},false);this.domElement.addEventListener("mousemove",c(this,this.onMouseMove),false);this.domElement.addEventListener("mousedown",c(this,this.onMouseDown),false);this.domElement.addEventListener("mouseup",c(this,this.onMouseUp),false);this.domElement.addEventListener("keydown",c(this,this.onKeyDown),false);this.domElement.addEventListener("keyup",
-c(this,this.onKeyUp),false)};
+this.onKeyDown=function(a){a.preventDefault();switch(a.keyCode){case 38:case 87:this.moveForward=true;break;case 37:case 65:this.moveLeft=true;break;case 40:case 83:this.moveBackward=true;break;case 39:case 68:this.moveRight=true;break;case 82:this.moveUp=true;break;case 70:this.moveDown=true;break;case 81:this.freeze=!this.freeze}};this.onKeyUp=function(a){switch(a.keyCode){case 38:case 87:this.moveForward=false;break;case 37:case 65:this.moveLeft=false;break;case 40:case 83:this.moveBackward=false;
+break;case 39:case 68:this.moveRight=false;break;case 82:this.moveUp=false;break;case 70:this.moveDown=false}};this.update=function(a){var b=0;if(!this.freeze){if(this.heightSpeed){b=THREE.Math.clamp(this.object.position.y,this.heightMin,this.heightMax)-this.heightMin;this.autoSpeedFactor=a*b*this.heightCoef}else this.autoSpeedFactor=0;b=a*this.movementSpeed;(this.moveForward||this.autoForward&&!this.moveBackward)&&this.object.translateZ(-(b+this.autoSpeedFactor));this.moveBackward&&this.object.translateZ(b);
+this.moveLeft&&this.object.translateX(-b);this.moveRight&&this.object.translateX(b);this.moveUp&&this.object.translateY(b);this.moveDown&&this.object.translateY(-b);a=a*this.lookSpeed;this.activeLook||(a=0);this.lon=this.lon+this.mouseX*a;if(this.lookVertical)this.lat=this.lat-this.mouseY*a;this.lat=Math.max(-85,Math.min(85,this.lat));this.phi=(90-this.lat)*Math.PI/180;this.theta=this.lon*Math.PI/180;var b=this.target,c=this.object.position;b.x=c.x+100*Math.sin(this.phi)*Math.cos(this.theta);b.y=
+c.y+100*Math.cos(this.phi);b.z=c.z+100*Math.sin(this.phi)*Math.sin(this.theta);b=1;this.constrainVertical&&(b=Math.PI/(this.verticalMax-this.verticalMin));this.lon=this.lon+this.mouseX*a;if(this.lookVertical)this.lat=this.lat-this.mouseY*a*b;this.lat=Math.max(-85,Math.min(85,this.lat));this.phi=(90-this.lat)*Math.PI/180;this.theta=this.lon*Math.PI/180;if(this.constrainVertical)this.phi=THREE.Math.mapLinear(this.phi,0,Math.PI,this.verticalMin,this.verticalMax);b=this.target;c=this.object.position;
+b.x=c.x+100*Math.sin(this.phi)*Math.cos(this.theta);b.y=c.y+100*Math.cos(this.phi);b.z=c.z+100*Math.sin(this.phi)*Math.sin(this.theta);this.object.lookAt(b)}};this.domElement.addEventListener("contextmenu",function(a){a.preventDefault()},false);this.domElement.addEventListener("mousemove",c(this,this.onMouseMove),false);this.domElement.addEventListener("mousedown",c(this,this.onMouseDown),false);this.domElement.addEventListener("mouseup",c(this,this.onMouseUp),false);this.domElement.addEventListener("keydown",
+c(this,this.onKeyDown),false);this.domElement.addEventListener("keyup",c(this,this.onKeyUp),false)};
 THREE.PathControls=function(b,a){function c(a){return(a=a*2)<1?0.5*a*a:-0.5*(--a*(a-2)-1)}function d(a,b){return function(){b.apply(a,arguments)}}function e(a,b,c,d){var e={name:c,fps:0.6,length:d,hierarchy:[]},f,g=b.getControlPointsArray(),h=b.getLength(),r=g.length,s=0;f=r-1;b={parent:-1,keys:[]};b.keys[0]={time:0,pos:g[0],rot:[0,0,0,1],scl:[1,1,1]};b.keys[f]={time:d,pos:g[f],rot:[0,0,0,1],scl:[1,1,1]};for(f=1;f<r-1;f++){s=d*h.chunks[f]/h.total;b.keys[f]={time:s,pos:g[f]}}e.hierarchy[0]=b;THREE.AnimationHandler.add(e);
 return new THREE.Animation(a,c,THREE.AnimationHandler.CATMULLROM_FORWARD,false)}function f(a,b){var c,d,e=new THREE.Geometry;for(c=0;c<a.points.length*b;c++){d=c/(a.points.length*b);d=a.getPoint(d);e.vertices[c]=new THREE.Vector3(d.x,d.y,d.z)}return e}this.object=b;this.domElement=a!==void 0?a:document;this.id="PathControls"+THREE.PathControlsIdCounter++;this.duration=1E4;this.waypoints=[];this.useConstantSpeed=true;this.resamplingCoef=50;this.debugPath=new THREE.Object3D;this.debugDummy=new THREE.Object3D;
-this.animationParent=new THREE.Object3D;this.lookSpeed=0.0050;this.lookHorizontal=this.lookVertical=true;this.verticalAngleMap={srcRange:[0,2*Math.PI],dstRange:[0,2*Math.PI]};this.horizontalAngleMap={srcRange:[0,2*Math.PI],dstRange:[0,2*Math.PI]};this.target=new THREE.Object3D;this.theta=this.phi=this.lon=this.lat=this.mouseY=this.mouseX=0;if(this.domElement===document){this.viewHalfX=window.innerWidth/2;this.viewHalfY=window.innerHeight/2}else{this.viewHalfX=this.domElement.offsetWidth/2;this.viewHalfY=
+this.animationParent=new THREE.Object3D;this.lookSpeed=0.005;this.lookHorizontal=this.lookVertical=true;this.verticalAngleMap={srcRange:[0,2*Math.PI],dstRange:[0,2*Math.PI]};this.horizontalAngleMap={srcRange:[0,2*Math.PI],dstRange:[0,2*Math.PI]};this.target=new THREE.Object3D;this.theta=this.phi=this.lon=this.lat=this.mouseY=this.mouseX=0;if(this.domElement===document){this.viewHalfX=window.innerWidth/2;this.viewHalfY=window.innerHeight/2}else{this.viewHalfX=this.domElement.offsetWidth/2;this.viewHalfY=
 this.domElement.offsetHeight/2;this.domElement.setAttribute("tabindex",-1)}var g=Math.PI*2,h=Math.PI/180;this.update=function(a){var b;if(this.lookHorizontal)this.lon=this.lon+this.mouseX*this.lookSpeed*a;if(this.lookVertical)this.lat=this.lat-this.mouseY*this.lookSpeed*a;this.lon=Math.max(0,Math.min(360,this.lon));this.lat=Math.max(-85,Math.min(85,this.lat));this.phi=(90-this.lat)*h;this.theta=this.lon*h;a=this.phi%g;this.phi=a>=0?a:a+g;b=this.verticalAngleMap.srcRange;a=this.verticalAngleMap.dstRange;
 b=THREE.Math.mapLinear(this.phi,b[0],b[1],a[0],a[1]);var d=a[1]-a[0];this.phi=c((b-a[0])/d)*d+a[0];b=this.horizontalAngleMap.srcRange;a=this.horizontalAngleMap.dstRange;b=THREE.Math.mapLinear(this.theta,b[0],b[1],a[0],a[1]);d=a[1]-a[0];this.theta=c((b-a[0])/d)*d+a[0];a=this.target.position;a.x=100*Math.sin(this.phi)*Math.cos(this.theta);a.y=100*Math.cos(this.phi);a.z=100*Math.sin(this.phi)*Math.sin(this.theta);this.object.lookAt(this.target.position)};this.onMouseMove=function(a){if(this.domElement===
 document){this.mouseX=a.pageX-this.viewHalfX;this.mouseY=a.pageY-this.viewHalfY}else{this.mouseX=a.pageX-this.domElement.offsetLeft-this.viewHalfX;this.mouseY=a.pageY-this.domElement.offsetTop-this.viewHalfY}};this.init=function(){this.spline=new THREE.Spline;this.spline.initFromArray(this.waypoints);this.useConstantSpeed&&this.spline.reparametrizeByArcLength(this.resamplingCoef);if(this.createDebugDummy){var a=new THREE.MeshLambertMaterial({color:30719}),b=new THREE.MeshLambertMaterial({color:65280}),
 c=new THREE.CubeGeometry(10,10,20),g=new THREE.CubeGeometry(2,2,10);this.animationParent=new THREE.Mesh(c,a);a=new THREE.Mesh(g,b);a.position.set(0,10,0);this.animation=e(this.animationParent,this.spline,this.id,this.duration);this.animationParent.add(this.object);this.animationParent.add(this.target);this.animationParent.add(a)}else{this.animation=e(this.animationParent,this.spline,this.id,this.duration);this.animationParent.add(this.target);this.animationParent.add(this.object)}if(this.createDebugPath){var a=
 this.debugPath,b=this.spline,g=f(b,10),c=f(b,10),h=new THREE.LineBasicMaterial({color:16711680,linewidth:3}),g=new THREE.Line(g,h),c=new THREE.ParticleSystem(c,new THREE.ParticleBasicMaterial({color:16755200,size:3}));g.scale.set(1,1,1);a.add(g);c.scale.set(1,1,1);a.add(c);for(var g=new THREE.SphereGeometry(1,16,8),h=new THREE.MeshBasicMaterial({color:65280}),m=0;m<b.points.length;m++){c=new THREE.Mesh(g,h);c.position.copy(b.points[m]);a.add(c)}}this.domElement.addEventListener("mousemove",d(this,
 this.onMouseMove),false)}};THREE.PathControlsIdCounter=0;
-THREE.FlyControls=function(b,a){function c(a,b){return function(){b.apply(a,arguments)}}this.object=b;this.domElement=a!==void 0?a:document;a&&this.domElement.setAttribute("tabindex",-1);this.movementSpeed=1;this.rollSpeed=0.0050;this.autoForward=this.dragToLook=false;this.object.useQuaternion=true;this.tmpQuaternion=new THREE.Quaternion;this.mouseStatus=0;this.moveState={up:0,down:0,left:0,right:0,forward:0,back:0,pitchUp:0,pitchDown:0,yawLeft:0,yawRight:0,rollLeft:0,rollRight:0};this.moveVector=
-new THREE.Vector3(0,0,0);this.rotationVector=new THREE.Vector3(0,0,0);this.handleEvent=function(a){if(typeof this[a.type]=="function")this[a.type](a)};this.keydown=function(a){if(!a.altKey){switch(a.keyCode){case 16:this.movementSpeedMultiplier=0.1;break;case 87:this.moveState.forward=1;break;case 83:this.moveState.back=1;break;case 65:this.moveState.left=1;break;case 68:this.moveState.right=1;break;case 82:this.moveState.up=1;break;case 70:this.moveState.down=1;break;case 38:this.moveState.pitchUp=
+THREE.FlyControls=function(b,a){function c(a,b){return function(){b.apply(a,arguments)}}this.object=b;this.domElement=a!==void 0?a:document;a&&this.domElement.setAttribute("tabindex",-1);this.movementSpeed=1;this.rollSpeed=0.005;this.autoForward=this.dragToLook=false;this.object.useQuaternion=true;this.tmpQuaternion=new THREE.Quaternion;this.mouseStatus=0;this.moveState={up:0,down:0,left:0,right:0,forward:0,back:0,pitchUp:0,pitchDown:0,yawLeft:0,yawRight:0,rollLeft:0,rollRight:0};this.moveVector=
+new THREE.Vector3(0,0,0);this.rotationVector=new THREE.Vector3(0,0,0);this.handleEvent=function(a){if(typeof this[a.type]=="function")this[a.type](a)};this.keydown=function(a){if(!a.altKey){a.preventDefault();switch(a.keyCode){case 16:this.movementSpeedMultiplier=0.1;break;case 87:this.moveState.forward=1;break;case 83:this.moveState.back=1;break;case 65:this.moveState.left=1;break;case 68:this.moveState.right=1;break;case 82:this.moveState.up=1;break;case 70:this.moveState.down=1;break;case 38:this.moveState.pitchUp=
 1;break;case 40:this.moveState.pitchDown=1;break;case 37:this.moveState.yawLeft=1;break;case 39:this.moveState.yawRight=1;break;case 81:this.moveState.rollLeft=1;break;case 69:this.moveState.rollRight=1}this.updateMovementVector();this.updateRotationVector()}};this.keyup=function(a){switch(a.keyCode){case 16:this.movementSpeedMultiplier=1;break;case 87:this.moveState.forward=0;break;case 83:this.moveState.back=0;break;case 65:this.moveState.left=0;break;case 68:this.moveState.right=0;break;case 82:this.moveState.up=
 0;break;case 70:this.moveState.down=0;break;case 38:this.moveState.pitchUp=0;break;case 40:this.moveState.pitchDown=0;break;case 37:this.moveState.yawLeft=0;break;case 39:this.moveState.yawRight=0;break;case 81:this.moveState.rollLeft=0;break;case 69:this.moveState.rollRight=0}this.updateMovementVector();this.updateRotationVector()};this.mousedown=function(a){this.domElement!==document&&this.domElement.focus();a.preventDefault();a.stopPropagation();if(this.dragToLook)this.mouseStatus++;else switch(a.button){case 0:this.object.moveForward=
 true;break;case 2:this.object.moveBackward=true}};this.mousemove=function(a){if(!this.dragToLook||this.mouseStatus>0){var b=this.getContainerDimensions(),c=b.size[0]/2,g=b.size[1]/2;this.moveState.yawLeft=-(a.pageX-b.offset[0]-c)/c;this.moveState.pitchDown=(a.pageY-b.offset[1]-g)/g;this.updateRotationVector()}};this.mouseup=function(a){a.preventDefault();a.stopPropagation();if(this.dragToLook){this.mouseStatus--;this.moveState.yawLeft=this.moveState.pitchDown=0}else switch(a.button){case 0:this.moveForward=
@@ -160,8 +164,8 @@ d.set(0,1,0);c.cross(d,e).normalize();d.cross(e,c).normalize();this.object.matri
 Math.cos(this.roll);this.object.matrix.multiplySelf(f);this.object.matrixWorldNeedsUpdate=true;this.object.matrix.elements[12]=this.object.position.x;this.object.matrix.elements[13]=this.object.position.y;this.object.matrix.elements[14]=this.object.position.z};this.translateX=function(a){this.object.position.x=this.object.position.x+this.object.matrix.elements[0]*a;this.object.position.y=this.object.position.y+this.object.matrix.elements[1]*a;this.object.position.z=this.object.position.z+this.object.matrix.elements[2]*
 a};this.translateY=function(a){this.object.position.x=this.object.position.x+this.object.matrix.elements[4]*a;this.object.position.y=this.object.position.y+this.object.matrix.elements[5]*a;this.object.position.z=this.object.position.z+this.object.matrix.elements[6]*a};this.translateZ=function(a){this.object.position.x=this.object.position.x-this.object.matrix.elements[8]*a;this.object.position.y=this.object.position.y-this.object.matrix.elements[9]*a;this.object.position.z=this.object.position.z-
 this.object.matrix.elements[10]*a};this.rotateHorizontally=function(a){c.set(this.object.matrix.elements[0],this.object.matrix.elements[1],this.object.matrix.elements[2]);c.multiplyScalar(a);this.forward.subSelf(c);this.forward.normalize()};this.rotateVertically=function(a){d.set(this.object.matrix.elements[4],this.object.matrix.elements[5],this.object.matrix.elements[6]);d.multiplyScalar(a);this.forward.addSelf(d);this.forward.normalize()};this.domElement.addEventListener("contextmenu",function(a){a.preventDefault()},
-false);this.domElement.addEventListener("mousemove",function(a){n=(a.clientX-m)/window.innerWidth;k=(a.clientY-o)/window.innerHeight},false);this.domElement.addEventListener("mousedown",function(a){a.preventDefault();a.stopPropagation();switch(a.button){case 0:i=1;break;case 2:i=-1}},false);this.domElement.addEventListener("mouseup",function(a){a.preventDefault();a.stopPropagation();switch(a.button){case 0:i=0;break;case 2:i=0}},false);this.domElement.addEventListener("keydown",function(a){switch(a.keyCode){case 38:case 87:i=
-1;break;case 37:case 65:j=-1;break;case 40:case 83:i=-1;break;case 39:case 68:j=1;break;case 81:g=true;h=1;break;case 69:g=true;h=-1;break;case 82:l=1;break;case 70:l=-1}},false);this.domElement.addEventListener("keyup",function(a){switch(a.keyCode){case 38:case 87:i=0;break;case 37:case 65:j=0;break;case 40:case 83:i=0;break;case 39:case 68:j=0;break;case 81:g=false;break;case 69:g=false;break;case 82:l=0;break;case 70:l=0}},false)};
+false);this.domElement.addEventListener("mousemove",function(a){n=(a.clientX-m)/window.innerWidth;k=(a.clientY-o)/window.innerHeight},false);this.domElement.addEventListener("mousedown",function(a){a.preventDefault();a.stopPropagation();switch(a.button){case 0:i=1;break;case 2:i=-1}},false);this.domElement.addEventListener("mouseup",function(a){a.preventDefault();a.stopPropagation();switch(a.button){case 0:i=0;break;case 2:i=0}},false);this.domElement.addEventListener("keydown",function(a){a.preventDefault();
+switch(a.keyCode){case 38:case 87:i=1;break;case 37:case 65:j=-1;break;case 40:case 83:i=-1;break;case 39:case 68:j=1;break;case 81:g=true;h=1;break;case 69:g=true;h=-1;break;case 82:l=1;break;case 70:l=-1}},false);this.domElement.addEventListener("keyup",function(a){switch(a.keyCode){case 38:case 87:i=0;break;case 37:case 65:j=0;break;case 40:case 83:i=0;break;case 39:case 68:j=0;break;case 81:g=false;break;case 69:g=false;break;case 82:l=0;break;case 70:l=0}},false)};
 THREE.TrackballControls=function(b,a){THREE.EventTarget.call(this);var c=this;this.object=b;this.domElement=a!==void 0?a:document;this.enabled=true;this.screen={width:window.innerWidth,height:window.innerHeight,offsetLeft:0,offsetTop:0};this.radius=(this.screen.width+this.screen.height)/4;this.rotateSpeed=1;this.zoomSpeed=1.2;this.panSpeed=0.3;this.staticMoving=this.noPan=this.noZoom=this.noRotate=false;this.dynamicDampingFactor=0.2;this.minDistance=0;this.maxDistance=Infinity;this.keys=[65,83,68];
 this.target=new THREE.Vector3;var d=new THREE.Vector3,e=false,f=-1,g=new THREE.Vector3,h=new THREE.Vector3,i=new THREE.Vector3,j=new THREE.Vector2,l=new THREE.Vector2,n=new THREE.Vector2,k=new THREE.Vector2,m={type:"change"};this.handleEvent=function(a){if(typeof this[a.type]=="function")this[a.type](a)};this.getMouseOnScreen=function(a,b){return new THREE.Vector2((a-c.screen.offsetLeft)/c.radius*0.5,(b-c.screen.offsetTop)/c.radius*0.5)};this.getMouseProjectionOnBall=function(a,b){var d=new THREE.Vector3((a-
 c.screen.width*0.5-c.screen.offsetLeft)/c.radius,(c.screen.height*0.5+c.screen.offsetTop-b)/c.radius,0),e=d.length();e>1?d.normalize():d.z=Math.sqrt(1-e*e);g.copy(c.object.position).subSelf(c.target);e=c.object.up.clone().setLength(d.y);e.addSelf(c.object.up.clone().crossSelf(g).setLength(d.x));e.addSelf(g.setLength(d.z));return e};this.rotateCamera=function(){var a=Math.acos(h.dot(i)/h.length()/i.length());if(a){var b=(new THREE.Vector3).cross(h,i).normalize(),d=new THREE.Quaternion,a=a*c.rotateSpeed;
@@ -169,24 +173,31 @@ d.setFromAxisAngle(b,-a);d.multiplyVector3(g);d.multiplyVector3(c.object.up);d.m
 b.addSelf(c.object.up.clone().setLength(a.y));c.object.position.addSelf(b);c.target.addSelf(b);c.staticMoving?n=k:n.addSelf(a.sub(k,n).multiplyScalar(c.dynamicDampingFactor))}};this.checkDistances=function(){if(!c.noZoom||!c.noPan){c.object.position.lengthSq()>c.maxDistance*c.maxDistance&&c.object.position.setLength(c.maxDistance);g.lengthSq()<c.minDistance*c.minDistance&&c.object.position.add(c.target,g.setLength(c.minDistance))}};this.update=function(){g.copy(c.object.position).subSelf(c.target);
 c.noRotate||c.rotateCamera();c.noZoom||c.zoomCamera();c.noPan||c.panCamera();c.object.position.add(c.target,g);c.checkDistances();c.object.lookAt(c.target);if(d.distanceTo(c.object.position)>0){c.dispatchEvent(m);d.copy(c.object.position)}};this.domElement.addEventListener("contextmenu",function(a){a.preventDefault()},false);this.domElement.addEventListener("mousemove",function(a){if(c.enabled){if(e){h=i=c.getMouseProjectionOnBall(a.clientX,a.clientY);j=l=c.getMouseOnScreen(a.clientX,a.clientY);n=
 k=c.getMouseOnScreen(a.clientX,a.clientY);e=false}f!==-1&&(f===0&&!c.noRotate?i=c.getMouseProjectionOnBall(a.clientX,a.clientY):f===1&&!c.noZoom?l=c.getMouseOnScreen(a.clientX,a.clientY):f===2&&!c.noPan&&(k=c.getMouseOnScreen(a.clientX,a.clientY)))}},false);this.domElement.addEventListener("mousedown",function(a){if(c.enabled){a.preventDefault();a.stopPropagation();if(f===-1){f=a.button;f===0&&!c.noRotate?h=i=c.getMouseProjectionOnBall(a.clientX,a.clientY):f===1&&!c.noZoom?j=l=c.getMouseOnScreen(a.clientX,
-a.clientY):this.noPan||(n=k=c.getMouseOnScreen(a.clientX,a.clientY))}}},false);this.domElement.addEventListener("mouseup",function(a){if(c.enabled){a.preventDefault();a.stopPropagation();f=-1}},false);window.addEventListener("keydown",function(a){if(c.enabled&&f===-1){a.keyCode===c.keys[0]&&!c.noRotate?f=0:a.keyCode===c.keys[1]&&!c.noZoom?f=1:a.keyCode===c.keys[2]&&!c.noPan&&(f=2);f!==-1&&(e=true)}},false);window.addEventListener("keyup",function(){c.enabled&&f!==-1&&(f=-1)},false)};
-THREE.CubeGeometry=function(b,a,c,d,e,f,g,h){function i(a,b,c,g,h,i,k,l){var m,n=d||1,o=e||1,q=h/2,r=i/2,s=j.vertices.length;if(a==="x"&&b==="y"||a==="y"&&b==="x")m="z";else if(a==="x"&&b==="z"||a==="z"&&b==="x"){m="y";o=f||1}else if(a==="z"&&b==="y"||a==="y"&&b==="z"){m="x";n=f||1}var t=n+1,v=o+1,L=h/n,J=i/o,M=new THREE.Vector3;M[m]=k>0?1:-1;for(h=0;h<v;h++)for(i=0;i<t;i++){var y=new THREE.Vector3;y[a]=(i*L-q)*c;y[b]=(h*J-r)*g;y[m]=k;j.vertices.push(y)}for(h=0;h<o;h++)for(i=0;i<n;i++){a=new THREE.Face4(i+
-t*h+s,i+t*(h+1)+s,i+1+t*(h+1)+s,i+1+t*h+s);a.normal.copy(M);a.vertexNormals.push(M.clone(),M.clone(),M.clone(),M.clone());a.materialIndex=l;j.faces.push(a);j.faceVertexUvs[0].push([new THREE.UV(i/n,h/o),new THREE.UV(i/n,(h+1)/o),new THREE.UV((i+1)/n,(h+1)/o),new THREE.UV((i+1)/n,h/o)])}}THREE.Geometry.call(this);var j=this,l=b/2,n=a/2,k=c/2,m,o,q,r,s,t;if(g!==void 0){if(g instanceof Array)this.materials=g;else{this.materials=[];for(m=0;m<6;m++)this.materials.push(g)}m=0;r=1;o=2;s=3;q=4;t=5}else this.materials=
+a.clientY):this.noPan||(n=k=c.getMouseOnScreen(a.clientX,a.clientY))}}},false);this.domElement.addEventListener("mouseup",function(a){if(c.enabled){a.preventDefault();a.stopPropagation();f=-1}},false);window.addEventListener("keydown",function(a){if(c.enabled){a.preventDefault();if(f===-1){a.keyCode===c.keys[0]&&!c.noRotate?f=0:a.keyCode===c.keys[1]&&!c.noZoom?f=1:a.keyCode===c.keys[2]&&!c.noPan&&(f=2);f!==-1&&(e=true)}}},false);window.addEventListener("keyup",function(){c.enabled&&f!==-1&&(f=-1)},
+false)};
+THREE.OrbitControls=function(b,a){var c,d,e;function f(){return 2*Math.PI/60/60*i.autoRotateSpeed}function g(a){a.preventDefault();if(p===c){n.set(a.clientX,a.clientY);k.sub(n,l);i.rotateLeft(2*Math.PI*k.x/j*i.userRotateSpeed);i.rotateUp(2*Math.PI*k.y/j*i.userRotateSpeed);l.copy(n)}else if(p===d){o.set(a.clientX,a.clientY);q.sub(o,m);q.y>0?i.zoomIn():i.zoomOut();m.copy(o)}}function h(){if(i.userRotate){document.removeEventListener("mousemove",g,false);document.removeEventListener("mouseup",h,false);
+p=e}}THREE.EventTarget.call(this);this.object=b;this.domElement=a!==void 0?a:document;this.center=new THREE.Vector3;this.userZoom=true;this.userZoomSpeed=1;this.userRotate=true;this.userRotateSpeed=1;this.autoRotate=false;this.autoRotateSpeed=2;var i=this,j=1800,l=new THREE.Vector2,n=new THREE.Vector2,k=new THREE.Vector2,m=new THREE.Vector2,o=new THREE.Vector2,q=new THREE.Vector2,r=0,s=0,t=1,v=new THREE.Vector3;e=-1;c=0;d=1;var p=e,x={type:"change"};this.rotateLeft=function(a){a===void 0&&(a=f());
+s=s-a};this.rotateRight=function(a){a===void 0&&(a=f());s=s+a};this.rotateUp=function(a){a===void 0&&(a=f());r=r-a};this.rotateDown=function(a){a===void 0&&(a=f());r=r+a};this.zoomIn=function(a){a===void 0&&(a=Math.pow(0.95,i.userZoomSpeed));t=t/a};this.zoomOut=function(a){a===void 0&&(a=Math.pow(0.95,i.userZoomSpeed));t=t*a};this.update=function(){var a=this.object.position,b=a.clone().subSelf(this.center),c=Math.atan2(b.x,b.z),d=Math.atan2(Math.sqrt(b.x*b.x+b.z*b.z),b.y);this.autoRotate&&this.rotateLeft(f());
+var c=c+s,d=d+r,d=Math.max(1.0E-6,Math.min(Math.PI-1.0E-6,d)),e=b.length();b.x=e*Math.sin(d)*Math.sin(c);b.y=e*Math.cos(d);b.z=e*Math.sin(d)*Math.cos(c);b.multiplyScalar(t);a.copy(this.center).addSelf(b);this.object.lookAt(this.center);r=s=0;t=1;if(v.distanceTo(this.object.position)>0){this.dispatchEvent(x);v.copy(this.object.position)}};this.domElement.addEventListener("contextmenu",function(a){a.preventDefault()},false);this.domElement.addEventListener("mousedown",function(a){if(i.userRotate){a.preventDefault();
+if(a.button===0||a.button===2){p=c;l.set(a.clientX,a.clientY)}else if(a.button===1){p=d;m.set(a.clientX,a.clientY)}document.addEventListener("mousemove",g,false);document.addEventListener("mouseup",h,false)}},false);this.domElement.addEventListener("mousewheel",function(a){i.userZoom&&(a.wheelDelta>0?i.zoomOut():i.zoomIn())},false)};
+THREE.CubeGeometry=function(b,a,c,d,e,f,g,h){function i(a,b,c,g,h,i,k,m){var l,n=d||1,o=e||1,q=h/2,r=i/2,s=j.vertices.length;if(a==="x"&&b==="y"||a==="y"&&b==="x")l="z";else if(a==="x"&&b==="z"||a==="z"&&b==="x"){l="y";o=f||1}else if(a==="z"&&b==="y"||a==="y"&&b==="z"){l="x";n=f||1}var t=n+1,v=o+1,I=h/n,M=i/o,J=new THREE.Vector3;J[l]=k>0?1:-1;for(h=0;h<v;h++)for(i=0;i<t;i++){var O=new THREE.Vector3;O[a]=(i*I-q)*c;O[b]=(h*M-r)*g;O[l]=k;j.vertices.push(O)}for(h=0;h<o;h++)for(i=0;i<n;i++){a=new THREE.Face4(i+
+t*h+s,i+t*(h+1)+s,i+1+t*(h+1)+s,i+1+t*h+s);a.normal.copy(J);a.vertexNormals.push(J.clone(),J.clone(),J.clone(),J.clone());a.materialIndex=m;j.faces.push(a);j.faceVertexUvs[0].push([new THREE.UV(i/n,h/o),new THREE.UV(i/n,(h+1)/o),new THREE.UV((i+1)/n,(h+1)/o),new THREE.UV((i+1)/n,h/o)])}}THREE.Geometry.call(this);var j=this,l=b/2,n=a/2,k=c/2,m,o,q,r,s,t;if(g!==void 0){if(g instanceof Array)this.materials=g;else{this.materials=[];for(m=0;m<6;m++)this.materials.push(g)}m=0;r=1;o=2;s=3;q=4;t=5}else this.materials=
 [];this.sides={px:true,nx:true,py:true,ny:true,pz:true,nz:true};if(h!=void 0)for(var v in h)this.sides[v]!==void 0&&(this.sides[v]=h[v]);this.sides.px&&i("z","y",-1,-1,c,a,l,m);this.sides.nx&&i("z","y",1,-1,c,a,-l,r);this.sides.py&&i("x","z",1,1,b,c,n,o);this.sides.ny&&i("x","z",1,-1,b,c,-n,s);this.sides.pz&&i("x","y",1,-1,b,a,k,q);this.sides.nz&&i("x","y",-1,-1,b,a,-k,t);this.computeCentroids();this.mergeVertices()};THREE.CubeGeometry.prototype=new THREE.Geometry;
 THREE.CubeGeometry.prototype.constructor=THREE.CubeGeometry;
 THREE.CylinderGeometry=function(b,a,c,d,e,f){THREE.Geometry.call(this);var b=b!==void 0?b:20,a=a!==void 0?a:20,c=c!==void 0?c:100,g=c/2,d=d||8,e=e||1,h,i,j=[],l=[];for(i=0;i<=e;i++){var n=[],k=[],m=i/e,o=m*(a-b)+b;for(h=0;h<=d;h++){var q=h/d,r=new THREE.Vector3;r.x=o*Math.sin(q*Math.PI*2);r.y=-m*c+g;r.z=o*Math.cos(q*Math.PI*2);this.vertices.push(r);n.push(this.vertices.length-1);k.push(new THREE.UV(q,m))}j.push(n);l.push(k)}c=(a-b)/c;for(h=0;h<d;h++){if(b!==0){n=this.vertices[j[0][h]].clone();k=this.vertices[j[0][h+
-1]].clone()}else{n=this.vertices[j[1][h]].clone();k=this.vertices[j[1][h+1]].clone()}n.setY(Math.sqrt(n.x*n.x+n.z*n.z)*c).normalize();k.setY(Math.sqrt(k.x*k.x+k.z*k.z)*c).normalize();for(i=0;i<e;i++){var m=j[i][h],o=j[i+1][h],q=j[i+1][h+1],r=j[i][h+1],s=n.clone(),t=n.clone(),v=k.clone(),p=k.clone(),x=l[i][h].clone(),A=l[i+1][h].clone(),z=l[i+1][h+1].clone(),u=l[i][h+1].clone();this.faces.push(new THREE.Face4(m,o,q,r,[s,t,v,p]));this.faceVertexUvs[0].push([x,A,z,u])}}if(!f&&b>0){this.vertices.push(new THREE.Vector3(0,
-g,0));for(h=0;h<d;h++){m=j[0][h];o=j[0][h+1];q=this.vertices.length-1;s=new THREE.Vector3(0,1,0);t=new THREE.Vector3(0,1,0);v=new THREE.Vector3(0,1,0);x=l[0][h].clone();A=l[0][h+1].clone();z=new THREE.UV(A.u,0);this.faces.push(new THREE.Face3(m,o,q,[s,t,v]));this.faceVertexUvs[0].push([x,A,z])}}if(!f&&a>0){this.vertices.push(new THREE.Vector3(0,-g,0));for(h=0;h<d;h++){m=j[i][h+1];o=j[i][h];q=this.vertices.length-1;s=new THREE.Vector3(0,-1,0);t=new THREE.Vector3(0,-1,0);v=new THREE.Vector3(0,-1,0);
-x=l[i][h+1].clone();A=l[i][h].clone();z=new THREE.UV(A.u,1);this.faces.push(new THREE.Face3(m,o,q,[s,t,v]));this.faceVertexUvs[0].push([x,A,z])}}this.computeCentroids();this.computeFaceNormals()};THREE.CylinderGeometry.prototype=new THREE.Geometry;THREE.CylinderGeometry.prototype.constructor=THREE.CylinderGeometry;
+1]].clone()}else{n=this.vertices[j[1][h]].clone();k=this.vertices[j[1][h+1]].clone()}n.setY(Math.sqrt(n.x*n.x+n.z*n.z)*c).normalize();k.setY(Math.sqrt(k.x*k.x+k.z*k.z)*c).normalize();for(i=0;i<e;i++){var m=j[i][h],o=j[i+1][h],q=j[i+1][h+1],r=j[i][h+1],s=n.clone(),t=n.clone(),v=k.clone(),p=k.clone(),x=l[i][h].clone(),z=l[i+1][h].clone(),A=l[i+1][h+1].clone(),w=l[i][h+1].clone();this.faces.push(new THREE.Face4(m,o,q,r,[s,t,v,p]));this.faceVertexUvs[0].push([x,z,A,w])}}if(!f&&b>0){this.vertices.push(new THREE.Vector3(0,
+g,0));for(h=0;h<d;h++){m=j[0][h];o=j[0][h+1];q=this.vertices.length-1;s=new THREE.Vector3(0,1,0);t=new THREE.Vector3(0,1,0);v=new THREE.Vector3(0,1,0);x=l[0][h].clone();z=l[0][h+1].clone();A=new THREE.UV(z.u,0);this.faces.push(new THREE.Face3(m,o,q,[s,t,v]));this.faceVertexUvs[0].push([x,z,A])}}if(!f&&a>0){this.vertices.push(new THREE.Vector3(0,-g,0));for(h=0;h<d;h++){m=j[i][h+1];o=j[i][h];q=this.vertices.length-1;s=new THREE.Vector3(0,-1,0);t=new THREE.Vector3(0,-1,0);v=new THREE.Vector3(0,-1,0);
+x=l[i][h+1].clone();z=l[i][h].clone();A=new THREE.UV(z.u,1);this.faces.push(new THREE.Face3(m,o,q,[s,t,v]));this.faceVertexUvs[0].push([x,z,A])}}this.computeCentroids();this.computeFaceNormals()};THREE.CylinderGeometry.prototype=new THREE.Geometry;THREE.CylinderGeometry.prototype.constructor=THREE.CylinderGeometry;
 THREE.ExtrudeGeometry=function(b,a){if(typeof b!=="undefined"){THREE.Geometry.call(this);b=b instanceof Array?b:[b];this.shapebb=b[b.length-1].getBoundingBox();this.addShapeList(b,a);this.computeCentroids();this.computeFaceNormals()}};THREE.ExtrudeGeometry.prototype=new THREE.Geometry;THREE.ExtrudeGeometry.prototype.constructor=THREE.ExtrudeGeometry;THREE.ExtrudeGeometry.prototype.addShapeList=function(b,a){for(var c=b.length,d=0;d<c;d++)this.addShape(b[d],a)};
 THREE.ExtrudeGeometry.prototype.addShape=function(b,a){function c(a,b,c){b||console.log("die");return b.clone().multiplyScalar(c).addSelf(a)}function d(a,b,c){var d=THREE.ExtrudeGeometry.__v1,e=THREE.ExtrudeGeometry.__v2,f=THREE.ExtrudeGeometry.__v3,g=THREE.ExtrudeGeometry.__v4,h=THREE.ExtrudeGeometry.__v5,i=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);h.copy(a).addSelf(f);i.copy(a).addSelf(g);if(h.equals(i))return g.clone();
 h.copy(b).addSelf(f);i.copy(c).addSelf(g);f=d.dot(g);g=i.subSelf(h).dot(g);if(f===0){console.log("Either infinite or no solutions!");g===0?console.log("Its finite solutions."):console.log("Too bad, no solutions.")}g=g/f;if(g<0){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=a+Math.PI*2);c=(b+a)/2;a=-Math.cos(c);c=-Math.sin(c);a=new THREE.Vector2(a,c)}else a=d.multiplyScalar(g).addSelf(h).subSelf(a).clone();return a}function e(c,d){var e,f;for(y=c.length;--y>=0;){e=y;f=y-1;f<0&&
-(f=c.length-1);for(var g=0,h=k+l*2,g=0;g<h;g++){var i=L*g,j=L*(g+1),m=d+e+i,i=d+f+i,n=d+f+j,j=d+e+j,o=c,q=g,p=h,m=m+C,i=i+C,n=n+C,j=j+C;F.faces.push(new THREE.Face4(m,i,n,j,null,null,t));m=Q.generateSideWallUV(F,b,o,a,m,i,n,j,q,p);F.faceVertexUvs[0].push(m)}}}function f(a,b,c){F.vertices.push(new THREE.Vector3(a,b,c))}function g(c,d,e,f){c=c+C;d=d+C;e=e+C;F.faces.push(new THREE.Face3(c,d,e,null,null,s));c=f?Q.generateBottomUV(F,b,a,c,d,e):Q.generateTopUV(F,b,a,c,d,e);F.faceVertexUvs[0].push(c)}var h=
-a.amount!==void 0?a.amount:100,i=a.bevelThickness!==void 0?a.bevelThickness:6,j=a.bevelSize!==void 0?a.bevelSize:i-2,l=a.bevelSegments!==void 0?a.bevelSegments:3,n=a.bevelEnabled!==void 0?a.bevelEnabled:true,k=a.steps!==void 0?a.steps:1,m=a.bendPath,o=a.extrudePath,q,r=false,s=a.material,t=a.extrudeMaterial,v,p,x,A;if(o){q=o.getSpacedPoints(k);r=true;n=false;v=new THREE.TubeGeometry.FrenetFrames(o,k,false);p=new THREE.Vector3;x=new THREE.Vector3;A=new THREE.Vector3}if(!n)j=i=l=0;var z,u,w,F=this,
-C=this.vertices.length;m&&b.addWrapPath(m);var o=b.extractPoints(),m=o.shape,B=o.holes;if(o=!THREE.Shape.Utils.isClockWise(m)){m=m.reverse();u=0;for(w=B.length;u<w;u++){z=B[u];THREE.Shape.Utils.isClockWise(z)&&(B[u]=z.reverse())}o=false}var I=THREE.Shape.Utils.triangulateShape(m,B),K=m;u=0;for(w=B.length;u<w;u++){z=B[u];m=m.concat(z)}var E,D,G,N,H,L=m.length,J,M=I.length,o=[],y=0;G=K.length;E=G-1;for(D=y+1;y<G;y++,E++,D++){E===G&&(E=0);D===G&&(D=0);o[y]=d(K[y],K[E],K[D])}var R=[],O,P=o.concat();u=
-0;for(w=B.length;u<w;u++){z=B[u];O=[];y=0;G=z.length;E=G-1;for(D=y+1;y<G;y++,E++,D++){E===G&&(E=0);D===G&&(D=0);O[y]=d(z[y],z[E],z[D])}R.push(O);P=P.concat(O)}for(E=0;E<l;E++){G=E/l;N=i*(1-G);D=j*Math.sin(G*Math.PI/2);y=0;for(G=K.length;y<G;y++){H=c(K[y],o[y],D);f(H.x,H.y,-N)}u=0;for(w=B.length;u<w;u++){z=B[u];O=R[u];y=0;for(G=z.length;y<G;y++){H=c(z[y],O[y],D);f(H.x,H.y,-N)}}}D=j;for(y=0;y<L;y++){H=n?c(m[y],P[y],D):m[y];if(r){x.copy(v.normals[0]).multiplyScalar(H.x);p.copy(v.binormals[0]).multiplyScalar(H.y);
-A.copy(q[0]).addSelf(x).addSelf(p);f(A.x,A.y,A.z)}else f(H.x,H.y,0)}for(G=1;G<=k;G++)for(y=0;y<L;y++){H=n?c(m[y],P[y],D):m[y];if(r){x.copy(v.normals[G]).multiplyScalar(H.x);p.copy(v.binormals[G]).multiplyScalar(H.y);A.copy(q[G]).addSelf(x).addSelf(p);f(A.x,A.y,A.z)}else f(H.x,H.y,h/k*G)}for(E=l-1;E>=0;E--){G=E/l;N=i*(1-G);D=j*Math.sin(G*Math.PI/2);y=0;for(G=K.length;y<G;y++){H=c(K[y],o[y],D);f(H.x,H.y,h+N)}u=0;for(w=B.length;u<w;u++){z=B[u];O=R[u];y=0;for(G=z.length;y<G;y++){H=c(z[y],O[y],D);r?f(H.x,
-H.y+q[k-1].y,q[k-1].x+N):f(H.x,H.y,h+N)}}}var Q=THREE.ExtrudeGeometry.WorldUVGenerator;(function(){if(n){var a;a=L*0;for(y=0;y<M;y++){J=I[y];g(J[2]+a,J[1]+a,J[0]+a,true)}a=k+l*2;a=L*a;for(y=0;y<M;y++){J=I[y];g(J[0]+a,J[1]+a,J[2]+a,false)}}else{for(y=0;y<M;y++){J=I[y];g(J[2],J[1],J[0],true)}for(y=0;y<M;y++){J=I[y];g(J[0]+L*k,J[1]+L*k,J[2]+L*k,false)}}})();(function(){var a=0;e(K,a);a=a+K.length;u=0;for(w=B.length;u<w;u++){z=B[u];e(z,a);a=a+z.length}})()};
+(f=c.length-1);for(var g=0,h=k+l*2,g=0;g<h;g++){var i=M*g,j=M*(g+1),n=d+e+i,i=d+f+i,m=d+f+j,j=d+e+j,o=c,q=g,p=h,r=e,s=f,n=n+E,i=i+E,m=m+E,j=j+E;B.faces.push(new THREE.Face4(n,i,m,j,null,null,t));n=v.generateSideWallUV(B,b,o,a,n,i,m,j,q,p,r,s);B.faceVertexUvs[0].push(n)}}}function f(a,b,c){B.vertices.push(new THREE.Vector3(a,b,c))}function g(c,d,e,f){c=c+E;d=d+E;e=e+E;B.faces.push(new THREE.Face3(c,d,e,null,null,s));c=f?v.generateBottomUV(B,b,a,c,d,e):v.generateTopUV(B,b,a,c,d,e);B.faceVertexUvs[0].push(c)}
+var h=a.amount!==void 0?a.amount:100,i=a.bevelThickness!==void 0?a.bevelThickness:6,j=a.bevelSize!==void 0?a.bevelSize:i-2,l=a.bevelSegments!==void 0?a.bevelSegments:3,n=a.bevelEnabled!==void 0?a.bevelEnabled:true,k=a.steps!==void 0?a.steps:1,m=a.bendPath,o=a.extrudePath,q,r=false,s=a.material,t=a.extrudeMaterial,v=a.UVGenerator!==void 0?a.UVGenerator:THREE.ExtrudeGeometry.WorldUVGenerator,p,x,z,A;if(o){q=o.getSpacedPoints(k);r=true;n=false;p=a.frames!==void 0?a.frames:new THREE.TubeGeometry.FrenetFrames(o,
+k,false);x=new THREE.Vector3;z=new THREE.Vector3;A=new THREE.Vector3}if(!n)j=i=l=0;var w,u,C,B=this,E=this.vertices.length;m&&b.addWrapPath(m);var o=b.extractPoints(),m=o.shape,G=o.holes;if(o=!THREE.Shape.Utils.isClockWise(m)){m=m.reverse();u=0;for(C=G.length;u<C;u++){w=G[u];THREE.Shape.Utils.isClockWise(w)&&(G[u]=w.reverse())}o=false}var L=THREE.Shape.Utils.triangulateShape(m,G),H=m;u=0;for(C=G.length;u<C;u++){w=G[u];m=m.concat(w)}var D,K,F,N,I,M=m.length,J,O=L.length,o=[],y=0;F=H.length;D=F-1;for(K=
+y+1;y<F;y++,D++,K++){D===F&&(D=0);K===F&&(K=0);o[y]=d(H[y],H[D],H[K])}var R=[],P,Q=o.concat();u=0;for(C=G.length;u<C;u++){w=G[u];P=[];y=0;F=w.length;D=F-1;for(K=y+1;y<F;y++,D++,K++){D===F&&(D=0);K===F&&(K=0);P[y]=d(w[y],w[D],w[K])}R.push(P);Q=Q.concat(P)}for(D=0;D<l;D++){F=D/l;N=i*(1-F);K=j*Math.sin(F*Math.PI/2);y=0;for(F=H.length;y<F;y++){I=c(H[y],o[y],K);f(I.x,I.y,-N)}u=0;for(C=G.length;u<C;u++){w=G[u];P=R[u];y=0;for(F=w.length;y<F;y++){I=c(w[y],P[y],K);f(I.x,I.y,-N)}}}K=j;for(y=0;y<M;y++){I=n?
+c(m[y],Q[y],K):m[y];if(r){z.copy(p.normals[0]).multiplyScalar(I.x);x.copy(p.binormals[0]).multiplyScalar(I.y);A.copy(q[0]).addSelf(z).addSelf(x);f(A.x,A.y,A.z)}else f(I.x,I.y,0)}for(F=1;F<=k;F++)for(y=0;y<M;y++){I=n?c(m[y],Q[y],K):m[y];if(r){z.copy(p.normals[F]).multiplyScalar(I.x);x.copy(p.binormals[F]).multiplyScalar(I.y);A.copy(q[F]).addSelf(z).addSelf(x);f(A.x,A.y,A.z)}else f(I.x,I.y,h/k*F)}for(D=l-1;D>=0;D--){F=D/l;N=i*(1-F);K=j*Math.sin(F*Math.PI/2);y=0;for(F=H.length;y<F;y++){I=c(H[y],o[y],
+K);f(I.x,I.y,h+N)}u=0;for(C=G.length;u<C;u++){w=G[u];P=R[u];y=0;for(F=w.length;y<F;y++){I=c(w[y],P[y],K);r?f(I.x,I.y+q[k-1].y,q[k-1].x+N):f(I.x,I.y,h+N)}}}(function(){if(n){var a;a=M*0;for(y=0;y<O;y++){J=L[y];g(J[2]+a,J[1]+a,J[0]+a,true)}a=k+l*2;a=M*a;for(y=0;y<O;y++){J=L[y];g(J[0]+a,J[1]+a,J[2]+a,false)}}else{for(y=0;y<O;y++){J=L[y];g(J[2],J[1],J[0],true)}for(y=0;y<O;y++){J=L[y];g(J[0]+M*k,J[1]+M*k,J[2]+M*k,false)}}})();(function(){var a=0;e(H,a);a=a+H.length;u=0;for(C=G.length;u<C;u++){w=G[u];e(w,
+a);a=a+w.length}})()};
 THREE.ExtrudeGeometry.WorldUVGenerator={generateTopUV:function(b,a,c,d,e,f){a=b.vertices[e].x;e=b.vertices[e].y;c=b.vertices[f].x;f=b.vertices[f].y;return[new THREE.UV(b.vertices[d].x,1-b.vertices[d].y),new THREE.UV(a,1-e),new THREE.UV(c,1-f)]},generateBottomUV:function(b,a,c,d,e,f){return this.generateTopUV(b,a,c,d,e,f)},generateSideWallUV:function(b,a,c,d,e,f,g,h){var a=b.vertices[e].x,c=b.vertices[e].y,e=b.vertices[e].z,d=b.vertices[f].x,i=b.vertices[f].y,f=b.vertices[f].z,j=b.vertices[g].x,l=
 b.vertices[g].y,g=b.vertices[g].z,n=b.vertices[h].x,k=b.vertices[h].y,b=b.vertices[h].z;return Math.abs(c-i)<0.01?[new THREE.UV(a,e),new THREE.UV(d,f),new THREE.UV(j,g),new THREE.UV(n,b)]:[new THREE.UV(c,e),new THREE.UV(i,f),new THREE.UV(l,g),new THREE.UV(k,b)]}};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;
@@ -197,15 +208,8 @@ THREE.PlaneGeometry=function(b,a,c,d){THREE.Geometry.call(this);for(var e=b/2,f=
 THREE.SphereGeometry=function(b,a,c,d,e,f,g){THREE.Geometry.call(this);var b=b||50,d=d!==void 0?d:0,e=e!==void 0?e:Math.PI*2,f=f!==void 0?f:0,g=g!==void 0?g:Math.PI,a=Math.max(3,Math.floor(a)||8),c=Math.max(2,Math.floor(c)||6),h,i,j=[],l=[];for(i=0;i<=c;i++){var n=[],k=[];for(h=0;h<=a;h++){var m=h/a,o=i/c,q=new THREE.Vector3;q.x=-b*Math.cos(d+m*e)*Math.sin(f+o*g);q.y=b*Math.cos(f+o*g);q.z=b*Math.sin(d+m*e)*Math.sin(f+o*g);this.vertices.push(q);n.push(this.vertices.length-1);k.push(new THREE.UV(m,
 o))}j.push(n);l.push(k)}for(i=0;i<c;i++)for(h=0;h<a;h++){var d=j[i][h+1],e=j[i][h],f=j[i+1][h],g=j[i+1][h+1],n=this.vertices[d].clone().normalize(),k=this.vertices[e].clone().normalize(),m=this.vertices[f].clone().normalize(),o=this.vertices[g].clone().normalize(),q=l[i][h+1].clone(),r=l[i][h].clone(),s=l[i+1][h].clone(),t=l[i+1][h+1].clone();if(Math.abs(this.vertices[d].y)==b){this.faces.push(new THREE.Face3(d,f,g,[n,m,o]));this.faceVertexUvs[0].push([q,s,t])}else if(Math.abs(this.vertices[f].y)==
 b){this.faces.push(new THREE.Face3(d,e,f,[n,k,m]));this.faceVertexUvs[0].push([q,r,s])}else{this.faces.push(new THREE.Face4(d,e,f,g,[n,k,m,o]));this.faceVertexUvs[0].push([q,r,s,t])}}this.computeCentroids();this.computeFaceNormals();this.boundingSphere={radius:b}};THREE.SphereGeometry.prototype=new THREE.Geometry;THREE.SphereGeometry.prototype.constructor=THREE.SphereGeometry;
-THREE.TextGeometry=function(b,a){var c=(new THREE.TextPath(b,a)).toShapes();a.amount=a.height!==void 0?a.height:50;if(a.bevelThickness===void 0)a.bevelThickness=10;if(a.bevelSize===void 0)a.bevelSize=8;if(a.bevelEnabled===void 0)a.bevelEnabled=false;if(a.bend){var d=c[c.length-1].getBoundingBox().maxX;a.bendPath=new THREE.QuadraticBezierCurve(new THREE.Vector2(0,0),new THREE.Vector2(d/2,120),new THREE.Vector2(d,0))}THREE.ExtrudeGeometry.call(this,c,a)};THREE.TextGeometry.prototype=new THREE.ExtrudeGeometry;
+THREE.TextGeometry=function(b,a){var c=THREE.FontUtils.generateShapes(b,a);a.amount=a.height!==void 0?a.height:50;if(a.bevelThickness===void 0)a.bevelThickness=10;if(a.bevelSize===void 0)a.bevelSize=8;if(a.bevelEnabled===void 0)a.bevelEnabled=false;if(a.bend){var d=c[c.length-1].getBoundingBox().maxX;a.bendPath=new THREE.QuadraticBezierCurve(new THREE.Vector2(0,0),new THREE.Vector2(d/2,120),new THREE.Vector2(d,0))}THREE.ExtrudeGeometry.call(this,c,a)};THREE.TextGeometry.prototype=new THREE.ExtrudeGeometry;
 THREE.TextGeometry.prototype.constructor=THREE.TextGeometry;
-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(b){var a=b.familyName.toLowerCase();this.faces[a]=this.faces[a]||{};this.faces[a][b.cssFontWeight]=this.faces[a][b.cssFontWeight]||{};this.faces[a][b.cssFontWeight][b.cssFontStyle]=b;return this.faces[a][b.cssFontWeight][b.cssFontStyle]=b},drawText:function(b){for(var a=this.getFace(),c=this.size/a.resolution,d=
-0,e=(""+b).split(""),f=e.length,g=[],b=0;b<f;b++){var h=new THREE.Path,h=this.extractGlyphPoints(e[b],a,c,d,h),d=d+h.offset;g.push(h.path)}return{paths:g,offset:d/2}},extractGlyphPoints:function(b,a,c,d,e){var f=[],g,h,i,j,l,n,k,m,o,q,r,s=a.glyphs[b]||a.glyphs["?"];if(s){if(s.o){a=s._cachedOutline||(s._cachedOutline=s.o.split(" "));j=a.length;for(b=0;b<j;){i=a[b++];switch(i){case "m":i=a[b++]*c+d;l=a[b++]*c;f.push(new THREE.Vector2(i,l));e.moveTo(i,l);break;case "l":i=a[b++]*c+d;l=a[b++]*c;f.push(new THREE.Vector2(i,
-l));e.lineTo(i,l);break;case "q":i=a[b++]*c+d;l=a[b++]*c;m=a[b++]*c+d;o=a[b++]*c;e.quadraticCurveTo(m,o,i,l);if(g=f[f.length-1]){n=g.x;k=g.y;g=1;for(h=this.divisions;g<=h;g++){var t=g/h,v=THREE.Shape.Utils.b2(t,n,m,i),t=THREE.Shape.Utils.b2(t,k,o,l);f.push(new THREE.Vector2(v,t))}}break;case "b":i=a[b++]*c+d;l=a[b++]*c;m=a[b++]*c+d;o=a[b++]*-c;q=a[b++]*c+d;r=a[b++]*-c;e.bezierCurveTo(i,l,m,o,q,r);if(g=f[f.length-1]){n=g.x;k=g.y;g=1;for(h=this.divisions;g<=h;g++){t=g/h;v=THREE.Shape.Utils.b3(t,n,m,
-q,i);t=THREE.Shape.Utils.b3(t,k,o,r,l);f.push(new THREE.Vector2(v,t))}}}}}return{offset:s.ha*c,points:f,path:e}}}};
-(function(b){var a=function(a){for(var b=a.length,e=0,f=b-1,g=0;g<b;f=g++)e=e+(a[f].x*a[g].y-a[g].x*a[f].y);return e*0.5};b.Triangulate=function(b,d){var e=b.length;if(e<3)return null;var f=[],g=[],h=[],i,j,l;if(a(b)>0)for(j=0;j<e;j++)g[j]=j;else for(j=0;j<e;j++)g[j]=e-1-j;var n=2*e;for(j=e-1;e>2;){if(n--<=0){console.log("Warning, unable to triangulate polygon!");break}i=j;e<=i&&(i=0);j=i+1;e<=j&&(j=0);l=j+1;e<=l&&(l=0);var k;a:{k=b;var m=i,o=j,q=l,r=e,s=g,t=void 0,v=void 0,p=void 0,x=void 0,A=void 0,
-z=void 0,u=void 0,w=void 0,F=void 0,v=k[s[m]].x,p=k[s[m]].y,x=k[s[o]].x,A=k[s[o]].y,z=k[s[q]].x,u=k[s[q]].y;if(1.0E-10>(x-v)*(u-p)-(A-p)*(z-v))k=false;else{for(t=0;t<r;t++)if(!(t==m||t==o||t==q)){var w=k[s[t]].x,F=k[s[t]].y,C=void 0,B=void 0,I=void 0,K=void 0,E=void 0,D=void 0,G=void 0,N=void 0,H=void 0,L=void 0,J=void 0,M=void 0,C=I=E=void 0,C=z-x,B=u-A,I=v-z,K=p-u,E=x-v,D=A-p,G=w-v,N=F-p,H=w-x,L=F-A,J=w-z,M=F-u,C=C*L-B*H,E=E*N-D*G,I=I*M-K*J;if(C>=0&&I>=0&&E>=0){k=false;break a}}k=true}}if(k){f.push([b[g[i]],
-b[g[j]],b[g[l]]]);h.push([g[i],g[j],g[l]]);i=j;for(l=j+1;l<e;i++,l++)g[i]=g[l];e--;n=2*e}}return d?h:f};b.Triangulate.area=a;return b})(THREE.FontUtils);self._typeface_js={faces:THREE.FontUtils.faces,loadFace:THREE.FontUtils.loadFace};
 THREE.TorusGeometry=function(b,a,c,d,e){THREE.Geometry.call(this);this.radius=b||100;this.tube=a||40;this.segmentsR=c||8;this.segmentsT=d||6;this.arc=e||Math.PI*2;e=new THREE.Vector3;b=[];a=[];for(c=0;c<=this.segmentsR;c++)for(d=0;d<=this.segmentsT;d++){var f=d/this.segmentsT*this.arc,g=c/this.segmentsR*Math.PI*2;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);b.push(new THREE.UV(d/this.segmentsT,1-c/this.segmentsR));a.push(h.clone().subSelf(e).normalize())}for(c=1;c<=this.segmentsR;c++)for(d=1;d<=this.segmentsT;d++){var e=(this.segmentsT+1)*c+d-1,f=(this.segmentsT+1)*(c-1)+d-1,g=(this.segmentsT+1)*(c-1)+d,h=(this.segmentsT+1)*c+d,i=new THREE.Face4(e,f,g,h,[a[e],a[f],a[g],a[h]]);i.normal.addSelf(a[e]);i.normal.addSelf(a[f]);i.normal.addSelf(a[g]);i.normal.addSelf(a[h]);i.normal.normalize();this.faces.push(i);
 this.faceVertexUvs[0].push([b[e].clone(),b[f].clone(),b[g].clone(),b[h].clone()])}this.computeCentroids()};THREE.TorusGeometry.prototype=new THREE.Geometry;THREE.TorusGeometry.prototype.constructor=THREE.TorusGeometry;
@@ -225,12 +229,15 @@ for(var c=c||1,d=d||0,i=this,j=0,l=b.length;j<l;j++)e(new THREE.Vector3(b[j][0],
 THREE.IcosahedronGeometry=function(b,a){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]],b,a)};THREE.IcosahedronGeometry.prototype=new THREE.Geometry;THREE.IcosahedronGeometry.prototype.constructor=THREE.IcosahedronGeometry;
 THREE.OctahedronGeometry=function(b,a){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]],b,a)};THREE.OctahedronGeometry.prototype=new THREE.Geometry;THREE.OctahedronGeometry.prototype.constructor=THREE.OctahedronGeometry;THREE.TetrahedronGeometry=function(b,a){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]],b,a)};
 THREE.TetrahedronGeometry.prototype=new THREE.Geometry;THREE.TetrahedronGeometry.prototype.constructor=THREE.TetrahedronGeometry;
-THREE.ParametricGeometry=function(b,a,c,d){THREE.Geometry.call(this);var e=this.vertices,f=this.faces,g=this.faceVertexUvs[0],d=d===void 0?false:d,h,i,j,l,n=a+1;for(h=0;h<=c;h++){l=h/c;for(i=0;i<=a;i++){j=i/a;j=b(j,l);e.push(j)}}var k,m,o,q;for(h=0;h<c;h++)for(i=0;i<a;i++){b=h*n+i;e=h*n+i+1;l=(h+1)*n+i;j=(h+1)*n+i+1;k=new THREE.UV(h/a,i/c);m=new THREE.UV(h/a,(i+1)/c);o=new THREE.UV((h+1)/a,i/c);q=new THREE.UV((h+1)/a,(i+1)/c);if(d){f.push(new THREE.Face3(b,e,l));f.push(new THREE.Face3(e,j,l));g.push([k,
-m,o]);g.push([m,q,o])}else{f.push(new THREE.Face4(b,e,j,l));g.push([k,m,o,q])}}this.computeCentroids();this.computeFaceNormals();this.computeVertexNormals()};THREE.ParametricGeometry.prototype=new THREE.Geometry;THREE.ParametricGeometry.prototype.constructor=THREE.ParametricGeometry;
+THREE.ParametricGeometry=function(b,a,c,d){THREE.Geometry.call(this);var e=this.vertices,f=this.faces,g=this.faceVertexUvs[0],d=d===void 0?false:d,h,i,j,l,n=a+1;for(h=0;h<=c;h++){l=h/c;for(i=0;i<=a;i++){j=i/a;j=b(j,l);e.push(j)}}var k,m,o,q;for(h=0;h<c;h++)for(i=0;i<a;i++){b=h*n+i;e=h*n+i+1;l=(h+1)*n+i;j=(h+1)*n+i+1;k=new THREE.UV(i/a,h/c);m=new THREE.UV((i+1)/a,h/c);o=new THREE.UV(i/a,(h+1)/c);q=new THREE.UV((i+1)/a,(h+1)/c);if(d){f.push(new THREE.Face3(b,e,l));f.push(new THREE.Face3(e,j,l));g.push([k,
+m,o]);g.push([m,q,o])}else{f.push(new THREE.Face4(b,e,j,l));g.push([k,m,q,o])}}this.computeCentroids();this.computeFaceNormals();this.computeVertexNormals()};THREE.ParametricGeometry.prototype=new THREE.Geometry;THREE.ParametricGeometry.prototype.constructor=THREE.ParametricGeometry;
+THREE.ConvexGeometry=function(b){function a(a){var d=b[a].clone(),f=d.length();d.x=d.x+f*c();d.y=d.y+f*c();d.z=d.z+f*c();for(var f=[],g=0;g<e.length;){var h=e[g],i=d,j=b[h[0]],s;s=j;var t=b[h[1]],v=b[h[2]],p=new THREE.Vector3,x=new THREE.Vector3;p.sub(v,t);x.sub(s,t);p.crossSelf(x);p.isZero()||p.normalize();s=p;j=s.dot(j);if(s.dot(i)>=j){for(i=0;i<3;i++){j=[h[i],h[(i+1)%3]];s=true;for(t=0;t<f.length;t++)if(f[t][0]===j[1]&&f[t][1]===j[0]){f[t]=f[f.length-1];f.pop();s=false;break}s&&f.push(j)}e[g]=
+e[e.length-1];e.pop()}else g++}for(t=0;t<f.length;t++)e.push([f[t][0],f[t][1],a])}function c(){return(Math.random()-0.5)*2.0E-6}function d(a){var b=a.length();return new THREE.UV(a.x/b,a.y/b)}THREE.Geometry.call(this);for(var e=[[0,1,2],[0,2,1]],f=3;f<b.length;f++)a(f);for(var g=0,h=Array(b.length),f=0;f<e.length;f++)for(var i=e[f],j=0;j<3;j++){if(h[i[j]]===void 0){h[i[j]]=g++;this.vertices.push(b[i[j]])}i[j]=h[i[j]]}for(f=0;f<e.length;f++)this.faces.push(new THREE.Face3(e[f][0],e[f][1],e[f][2]));
+for(f=0;f<this.faces.length;f++){i=this.faces[f];this.faceVertexUvs[0].push([d(this.vertices[i.a]),d(this.vertices[i.b]),d(this.vertices[i.c])])}this.computeCentroids();this.computeFaceNormals();this.computeVertexNormals()};THREE.ConvexGeometry.prototype=new THREE.Geometry;THREE.ConvexGeometry.prototype.constructor=THREE.ConvexGeometry;
 THREE.AxisHelper=function(){THREE.Object3D.call(this);var b=new THREE.Geometry;b.vertices.push(new THREE.Vector3);b.vertices.push(new THREE.Vector3(0,100,0));var a=new THREE.CylinderGeometry(0,5,25,5,1),c;c=new THREE.Line(b,new THREE.LineBasicMaterial({color:16711680}));c.rotation.z=-Math.PI/2;this.add(c);c=new THREE.Mesh(a,new THREE.MeshBasicMaterial({color:16711680}));c.position.x=100;c.rotation.z=-Math.PI/2;this.add(c);c=new THREE.Line(b,new THREE.LineBasicMaterial({color:65280}));this.add(c);
 c=new THREE.Mesh(a,new THREE.MeshBasicMaterial({color:65280}));c.position.y=100;this.add(c);c=new THREE.Line(b,new THREE.LineBasicMaterial({color:255}));c.rotation.x=Math.PI/2;this.add(c);c=new THREE.Mesh(a,new THREE.MeshBasicMaterial({color:255}));c.position.z=100;c.rotation.x=Math.PI/2;this.add(c)};THREE.AxisHelper.prototype=new THREE.Object3D;THREE.AxisHelper.prototype.constructor=THREE.AxisHelper;
 THREE.ArrowHelper=function(b,a,c,d){THREE.Object3D.call(this);d===void 0&&(d=16776960);c===void 0&&(c=20);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);if(a instanceof THREE.Vector3)this.position=
-a;this.setDirection(b);this.setLength(c)};THREE.ArrowHelper.prototype=new THREE.Object3D;THREE.ArrowHelper.prototype.constructor=THREE.ArrowHelper;THREE.ArrowHelper.prototype.setDirection=function(b){var a=(new THREE.Vector3(0,1,0)).crossSelf(b),b=Math.acos((new THREE.Vector3(0,1,0)).dot(b.clone().normalize()));this.matrix=(new THREE.Matrix4).makeRotationAxis(a.normalize(),b);this.rotation.getRotationFromMatrix(this.matrix,this.scale)};
+a;this.setDirection(b);this.setLength(c)};THREE.ArrowHelper.prototype=new THREE.Object3D;THREE.ArrowHelper.prototype.constructor=THREE.ArrowHelper;THREE.ArrowHelper.prototype.setDirection=function(b){var a=(new THREE.Vector3(0,1,0)).crossSelf(b),b=Math.acos((new THREE.Vector3(0,1,0)).dot(b.clone().normalize()));this.matrix=(new THREE.Matrix4).makeRotationAxis(a.normalize(),b);this.rotation.setEulerFromRotationMatrix(this.matrix,this.eulerOrder)};
 THREE.ArrowHelper.prototype.setLength=function(b){this.scale.set(b,b,b)};THREE.ArrowHelper.prototype.setColor=function(b){this.line.material.color.setHex(b);this.cone.material.color.setHex(b)};
 THREE.CameraHelper=function(b){function a(a,b,d){c(a,d);c(b,d)}function c(a,b){d.lineGeometry.vertices.push(new THREE.Vector3);d.lineGeometry.colors.push(new THREE.Color(b));d.pointMap[a]===void 0&&(d.pointMap[a]=[]);d.pointMap[a].push(d.lineGeometry.vertices.length-1)}THREE.Object3D.call(this);var d=this;this.lineGeometry=new THREE.Geometry;this.lineMaterial=new THREE.LineBasicMaterial({color:16777215,vertexColors:THREE.FaceColors});this.pointMap={};a("n1","n2",16755200);a("n2","n4",16755200);a("n4",
 "n3",16755200);a("n3","n1",16755200);a("f1","f2",16755200);a("f2","f4",16755200);a("f4","f3",16755200);a("f3","f1",16755200);a("n1","f1",16755200);a("n2","f2",16755200);a("n3","f3",16755200);a("n4","f4",16755200);a("p","n1",16711680);a("p","n2",16711680);a("p","n3",16711680);a("p","n4",16711680);a("u1","u2",43775);a("u2","u3",43775);a("u3","u1",43775);a("c","t",16777215);a("p","c",3355443);a("cn1","cn2",3355443);a("cn3","cn4",3355443);a("cf1","cf2",3355443);a("cf3","cf4",3355443);this.camera=b;this.update(b);
@@ -238,16 +245,16 @@ this.lines=new THREE.Line(this.lineGeometry,this.lineMaterial,THREE.LinePieces);
 THREE.CameraHelper.prototype.update=function(){function b(b,d,e,f){THREE.CameraHelper.__v.set(d,e,f);THREE.CameraHelper.__projector.unprojectVector(THREE.CameraHelper.__v,THREE.CameraHelper.__c);b=a.pointMap[b];if(b!==void 0){d=0;for(e=b.length;d<e;d++)a.lineGeometry.vertices[b[d]].copy(THREE.CameraHelper.__v)}}var a=this;THREE.CameraHelper.__c.projectionMatrix.copy(this.camera.projectionMatrix);b("c",0,0,-1);b("t",0,0,1);b("n1",-1,-1,-1);b("n2",1,-1,-1);b("n3",-1,1,-1);b("n4",1,1,-1);b("f1",-1,-1,
 1);b("f2",1,-1,1);b("f3",-1,1,1);b("f4",1,1,1);b("u1",0.7,1.1,-1);b("u2",-0.7,1.1,-1);b("u3",0,2,-1);b("cf1",-1,0,1);b("cf2",1,0,1);b("cf3",0,-1,1);b("cf4",0,1,1);b("cn1",-1,0,-1);b("cn2",1,0,-1);b("cn3",0,-1,-1);b("cn4",0,1,-1);this.lineGeometry.verticesNeedUpdate=true};THREE.CameraHelper.__projector=new THREE.Projector;THREE.CameraHelper.__v=new THREE.Vector3;THREE.CameraHelper.__c=new THREE.Camera;
 THREE.SubdivisionModifier=function(b){this.subdivisions=b===void 0?1:b;this.useOldVertexColors=false;this.supportUVs=true;this.debug=false};THREE.SubdivisionModifier.prototype.constructor=THREE.SubdivisionModifier;THREE.SubdivisionModifier.prototype.modify=function(b){for(var a=this.subdivisions;a-- >0;)this.smooth(b)};
-THREE.SubdivisionModifier.prototype.smooth=function(b){function a(){k.debug&&console.log.apply(console,arguments)}function c(){console&&console.log.apply(console,arguments)}function d(b,c,d,e,g,h,i){var j=new THREE.Face4(b,c,d,e,null,g.color,g.material);if(k.useOldVertexColors){j.vertexColors=[];for(var m,o,q,p=0;p<4;p++){q=h[p];m=new THREE.Color;m.setRGB(0,0,0);for(var r=0;r<q.length;r++){o=g.vertexColors[q[r]-1];m.r=m.r+o.r;m.g=m.g+o.g;m.b=m.b+o.b}m.r=m.r/q.length;m.g=m.g/q.length;m.b=m.b/q.length;
-j.vertexColors[p]=m}}l.push(j);if(k.supportUVs){g=[f(b,""),f(c,i),f(d,i),f(e,i)];g[0]?g[1]?g[2]?g[3]?n.push(g):a("d :( ",e+":"+i):a("c :( ",d+":"+i):a("b :( ",c+":"+i):a("a :( ",b+":"+i)}}function e(a,b){return Math.min(a,b)+"_"+Math.max(a,b)}function f(b,d){var e=b+":"+d,f=t[e];if(!f){b>=v&&b<v+o.length?a("face pt"):a("edge pt");c("warning, UV not found for",e);return null}return f}function g(a,b,d){var e=a+":"+b;e in t?c("dup vertexNo",a,"oldFaceNo",b,"value",d,"key",e,t[e]):t[e]=d}function h(a,
-b){I[a]===void 0&&(I[a]=[]);I[a].push(b)}function i(a,b,c){K[a]===void 0&&(K[a]={});K[a][b]=c}var j=[],l=[],n=[],k=this,m=b.vertices,o=b.faces,j=m.concat(),q=[],r={},s={},t={},v=m.length,p,x,A,z,u,w=b.faceVertexUvs[0],F;a("originalFaces, uvs, originalVerticesLength",o.length,w.length,v);if(k.supportUVs){p=0;for(x=w.length;p<x;p++){A=0;for(z=w[p].length;A<z;A++){F=o[p]["abcd".charAt(A)];g(F,p,w[p][A])}}}if(w.length==0)k.supportUVs=false;p=0;for(u in t)p++;if(!p){k.supportUVs=false;a("no uvs")}a("-- Original Faces + Vertices UVs completed",
-t,"vs",w.length);p=0;for(x=o.length;p<x;p++){u=o[p];q.push(u.centroid);j.push(u.centroid);if(k.supportUVs){w=new THREE.UV;if(u instanceof THREE.Face3){w.u=f(u.a,p).u+f(u.b,p).u+f(u.c,p).u;w.v=f(u.a,p).v+f(u.b,p).v+f(u.c,p).v;w.u=w.u/3;w.v=w.v/3}else if(u instanceof THREE.Face4){w.u=f(u.a,p).u+f(u.b,p).u+f(u.c,p).u+f(u.d,p).u;w.v=f(u.a,p).v+f(u.b,p).v+f(u.c,p).v+f(u.d,p).v;w.u=w.u/4;w.v=w.v/4}g(v+p,"",w)}}a("-- added UVs for new Faces",t);x=function(a){function b(a,c){h[a]===void 0&&(h[a]=[]);h[a].push(c)}
-var c,d,f,g,h={};c=0;for(d=a.faces.length;c<d;c++){f=a.faces[c];if(f instanceof THREE.Face3){g=e(f.a,f.b);b(g,c);g=e(f.b,f.c);b(g,c);g=e(f.c,f.a);b(g,c)}else if(f instanceof THREE.Face4){g=e(f.a,f.b);b(g,c);g=e(f.b,f.c);b(g,c);g=e(f.c,f.d);b(g,c);g=e(f.d,f.a);b(g,c)}}return h}(b);F=0;var C,B,I={},K={};for(p in x){w=x[p];C=p.split("_");B=C[0];C=C[1];h(B,[B,C]);h(C,[B,C]);A=0;for(z=w.length;A<z;A++){u=w[A];i(B,u,p);i(C,u,p)}w.length<2&&(s[p]=true)}a("vertexEdgeMap",I,"vertexFaceMap",K);for(p in x){w=
-x[p];u=w[0];z=w[1];C=p.split("_");B=C[0];C=C[1];w=new THREE.Vector3;if(s[p]){w.addSelf(m[B]);w.addSelf(m[C]);w.multiplyScalar(0.5)}else{w.addSelf(q[u]);w.addSelf(q[z]);w.addSelf(m[B]);w.addSelf(m[C]);w.multiplyScalar(0.25)}r[p]=v+o.length+F;j.push(w);F++;if(k.supportUVs){w=new THREE.UV;w.u=f(B,u).u+f(C,u).u;w.v=f(B,u).v+f(C,u).v;w.u=w.u/2;w.v=w.v/2;g(r[p],u,w);if(!s[p]){w=new THREE.UV;w.u=f(B,z).u+f(C,z).u;w.v=f(B,z).v+f(C,z).v;w.u=w.u/2;w.v=w.v/2;g(r[p],z,w)}}}a("-- Step 2 done");var E,D;z=["123",
-"12","2","23"];C=["123","23","3","31"];var G=["123","31","1","12"],N=["1234","12","2","23"],H=["1234","23","3","34"],L=["1234","34","4","41"],J=["1234","41","1","12"];p=0;for(x=q.length;p<x;p++){u=o[p];w=v+p;if(u instanceof THREE.Face3){F=e(u.a,u.b);B=e(u.b,u.c);E=e(u.c,u.a);d(w,r[F],u.b,r[B],u,z,p);d(w,r[B],u.c,r[E],u,C,p);d(w,r[E],u.a,r[F],u,G,p)}else if(u instanceof THREE.Face4){F=e(u.a,u.b);B=e(u.b,u.c);E=e(u.c,u.d);D=e(u.d,u.a);d(w,r[F],u.b,r[B],u,N,p);d(w,r[B],u.c,r[E],u,H,p);d(w,r[E],u.d,r[D],
-u,L,p);d(w,r[D],u.a,r[F],u,J,p)}else a("face should be a face!",u)}r=new THREE.Vector3;u=new THREE.Vector3;p=0;for(x=m.length;p<x;p++)if(I[p]!==void 0){r.set(0,0,0);u.set(0,0,0);B=new THREE.Vector3(0,0,0);w=0;for(A in K[p]){r.addSelf(q[A]);w++}z=0;F=I[p].length;for(A=0;A<F;A++)s[e(I[p][A][0],I[p][A][1])]&&z++;if(z!=2){r.divideScalar(w);for(A=0;A<F;A++){w=I[p][A];w=m[w[0]].clone().addSelf(m[w[1]]).divideScalar(2);u.addSelf(w)}u.divideScalar(F);B.addSelf(m[p]);B.multiplyScalar(F-3);B.addSelf(r);B.addSelf(u.multiplyScalar(2));
-B.divideScalar(F);j[p]=B}}b.vertices=j;b.faces=l;b.faceVertexUvs[0]=n;delete b.__tmpVertices;b.computeCentroids();b.computeFaceNormals();b.computeVertexNormals()};THREE.ImmediateRenderObject=function(){THREE.Object3D.call(this);this.render=function(){}};THREE.ImmediateRenderObject.prototype=new THREE.Object3D;THREE.ImmediateRenderObject.prototype.constructor=THREE.ImmediateRenderObject;
-THREE.LensFlare=function(b,a,c,d,e){THREE.Object3D.call(this);this.lensFlares=[];this.positionScreen=new THREE.Vector3;this.customUpdateCallback=void 0;b!==void 0&&this.add(b,a,c,d,e)};THREE.LensFlare.prototype=new THREE.Object3D;THREE.LensFlare.prototype.constructor=THREE.LensFlare;THREE.LensFlare.prototype.supr=THREE.Object3D.prototype;
+THREE.SubdivisionModifier.prototype.smooth=function(b){function a(){k.debug&&console.log.apply(console,arguments)}function c(){console&&console.log.apply(console,arguments)}function d(b,c,d,e,g,h,i){var j=new THREE.Face4(b,c,d,e,null,g.color,g.materialIndex);if(k.useOldVertexColors){j.vertexColors=[];for(var m,o,q,p=0;p<4;p++){q=h[p];m=new THREE.Color;m.setRGB(0,0,0);for(var r=0;r<q.length;r++){o=g.vertexColors[q[r]-1];m.r=m.r+o.r;m.g=m.g+o.g;m.b=m.b+o.b}m.r=m.r/q.length;m.g=m.g/q.length;m.b=m.b/
+q.length;j.vertexColors[p]=m}}l.push(j);if(k.supportUVs){g=[f(b,""),f(c,i),f(d,i),f(e,i)];g[0]?g[1]?g[2]?g[3]?n.push(g):a("d :( ",e+":"+i):a("c :( ",d+":"+i):a("b :( ",c+":"+i):a("a :( ",b+":"+i)}}function e(a,b){return Math.min(a,b)+"_"+Math.max(a,b)}function f(b,d){var e=b+":"+d,f=t[e];if(!f){b>=v&&b<v+o.length?a("face pt"):a("edge pt");c("warning, UV not found for",e);return null}return f}function g(a,b,d){var e=a+":"+b;e in t?c("dup vertexNo",a,"oldFaceNo",b,"value",d,"key",e,t[e]):t[e]=d}function h(a,
+b){G[a]===void 0&&(G[a]=[]);G[a].push(b)}function i(a,b,c){L[a]===void 0&&(L[a]={});L[a][b]=c}var j=[],l=[],n=[],k=this,m=b.vertices,o=b.faces,j=m.concat(),q=[],r={},s={},t={},v=m.length,p,x,z,A,w,u=b.faceVertexUvs[0],C;a("originalFaces, uvs, originalVerticesLength",o.length,u.length,v);if(k.supportUVs){p=0;for(x=u.length;p<x;p++){z=0;for(A=u[p].length;z<A;z++){C=o[p]["abcd".charAt(z)];g(C,p,u[p][z])}}}if(u.length==0)k.supportUVs=false;p=0;for(w in t)p++;if(!p){k.supportUVs=false;a("no uvs")}a("-- Original Faces + Vertices UVs completed",
+t,"vs",u.length);p=0;for(x=o.length;p<x;p++){w=o[p];q.push(w.centroid);j.push(w.centroid);if(k.supportUVs){u=new THREE.UV;if(w instanceof THREE.Face3){u.u=f(w.a,p).u+f(w.b,p).u+f(w.c,p).u;u.v=f(w.a,p).v+f(w.b,p).v+f(w.c,p).v;u.u=u.u/3;u.v=u.v/3}else if(w instanceof THREE.Face4){u.u=f(w.a,p).u+f(w.b,p).u+f(w.c,p).u+f(w.d,p).u;u.v=f(w.a,p).v+f(w.b,p).v+f(w.c,p).v+f(w.d,p).v;u.u=u.u/4;u.v=u.v/4}g(v+p,"",u)}}a("-- added UVs for new Faces",t);x=function(a){function b(a,c){h[a]===void 0&&(h[a]=[]);h[a].push(c)}
+var c,d,f,g,h={};c=0;for(d=a.faces.length;c<d;c++){f=a.faces[c];if(f instanceof THREE.Face3){g=e(f.a,f.b);b(g,c);g=e(f.b,f.c);b(g,c);g=e(f.c,f.a);b(g,c)}else if(f instanceof THREE.Face4){g=e(f.a,f.b);b(g,c);g=e(f.b,f.c);b(g,c);g=e(f.c,f.d);b(g,c);g=e(f.d,f.a);b(g,c)}}return h}(b);C=0;var B,E,G={},L={};for(p in x){u=x[p];B=p.split("_");E=B[0];B=B[1];h(E,[E,B]);h(B,[E,B]);z=0;for(A=u.length;z<A;z++){w=u[z];i(E,w,p);i(B,w,p)}u.length<2&&(s[p]=true)}a("vertexEdgeMap",G,"vertexFaceMap",L);for(p in x){u=
+x[p];w=u[0];A=u[1];B=p.split("_");E=B[0];B=B[1];u=new THREE.Vector3;if(s[p]){u.addSelf(m[E]);u.addSelf(m[B]);u.multiplyScalar(0.5)}else{u.addSelf(q[w]);u.addSelf(q[A]);u.addSelf(m[E]);u.addSelf(m[B]);u.multiplyScalar(0.25)}r[p]=v+o.length+C;j.push(u);C++;if(k.supportUVs){u=new THREE.UV;u.u=f(E,w).u+f(B,w).u;u.v=f(E,w).v+f(B,w).v;u.u=u.u/2;u.v=u.v/2;g(r[p],w,u);if(!s[p]){u=new THREE.UV;u.u=f(E,A).u+f(B,A).u;u.v=f(E,A).v+f(B,A).v;u.u=u.u/2;u.v=u.v/2;g(r[p],A,u)}}}a("-- Step 2 done");var H,D;A=["123",
+"12","2","23"];B=["123","23","3","31"];var K=["123","31","1","12"],F=["1234","12","2","23"],N=["1234","23","3","34"],I=["1234","34","4","41"],M=["1234","41","1","12"];p=0;for(x=q.length;p<x;p++){w=o[p];u=v+p;if(w instanceof THREE.Face3){C=e(w.a,w.b);E=e(w.b,w.c);H=e(w.c,w.a);d(u,r[C],w.b,r[E],w,A,p);d(u,r[E],w.c,r[H],w,B,p);d(u,r[H],w.a,r[C],w,K,p)}else if(w instanceof THREE.Face4){C=e(w.a,w.b);E=e(w.b,w.c);H=e(w.c,w.d);D=e(w.d,w.a);d(u,r[C],w.b,r[E],w,F,p);d(u,r[E],w.c,r[H],w,N,p);d(u,r[H],w.d,r[D],
+w,I,p);d(u,r[D],w.a,r[C],w,M,p)}else a("face should be a face!",w)}r=new THREE.Vector3;w=new THREE.Vector3;p=0;for(x=m.length;p<x;p++)if(G[p]!==void 0){r.set(0,0,0);w.set(0,0,0);E=new THREE.Vector3(0,0,0);u=0;for(z in L[p]){r.addSelf(q[z]);u++}A=0;C=G[p].length;for(z=0;z<C;z++)s[e(G[p][z][0],G[p][z][1])]&&A++;if(A!=2){r.divideScalar(u);for(z=0;z<C;z++){u=G[p][z];u=m[u[0]].clone().addSelf(m[u[1]]).divideScalar(2);w.addSelf(u)}w.divideScalar(C);E.addSelf(m[p]);E.multiplyScalar(C-3);E.addSelf(r);E.addSelf(w.multiplyScalar(2));
+E.divideScalar(C);j[p]=E}}b.vertices=j;b.faces=l;b.faceVertexUvs[0]=n;delete b.__tmpVertices;b.computeCentroids();b.computeFaceNormals();b.computeVertexNormals()};THREE.ImmediateRenderObject=function(){THREE.Object3D.call(this);this.render=function(){}};THREE.ImmediateRenderObject.prototype=new THREE.Object3D;THREE.ImmediateRenderObject.prototype.constructor=THREE.ImmediateRenderObject;
+THREE.LensFlare=function(b,a,c,d,e){THREE.Object3D.call(this);this.lensFlares=[];this.positionScreen=new THREE.Vector3;this.customUpdateCallback=void 0;b!==void 0&&this.add(b,a,c,d,e)};THREE.LensFlare.prototype=new THREE.Object3D;THREE.LensFlare.prototype.constructor=THREE.LensFlare;
 THREE.LensFlare.prototype.add=function(b,a,c,d,e,f){a===void 0&&(a=-1);c===void 0&&(c=0);f===void 0&&(f=1);e===void 0&&(e=new THREE.Color(16777215));if(d===void 0)d=THREE.NormalBlending;c=Math.min(c,Math.max(0,c));this.lensFlares.push({texture:b,size:a,distance:c,x:0,y:0,z:0,scale:1,rotation:1,opacity:f,color:e,blending:d})};
 THREE.LensFlare.prototype.updateLensFlares=function(){var b,a=this.lensFlares.length,c,d=-this.positionScreen.x*2,e=-this.positionScreen.y*2;for(b=0;b<a;b++){c=this.lensFlares[b];c.x=this.positionScreen.x+d*c.distance;c.y=this.positionScreen.y+e*c.distance;c.wantedRotation=c.x*Math.PI*0.25;c.rotation=c.rotation+(c.wantedRotation-c.rotation)*0.25}};
 THREE.MorphBlendMesh=function(b,a){THREE.Mesh.call(this,b,a);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=new THREE.Mesh;THREE.MorphBlendMesh.prototype.constructor=THREE.MorphBlendMesh;
@@ -262,11 +269,11 @@ THREE.LensFlarePlugin=function(){function b(b){var c=a.createProgram(),d=a.creat
 0;d[o++]=1;d[o++]=1;d[o++]=1;d[o++]=1;d[o++]=-1;d[o++]=1;d[o++]=0;d[o++]=1;o=0;e[o++]=0;e[o++]=1;e[o++]=2;e[o++]=0;e[o++]=2;e[o++]=3;f=a.createBuffer();g=a.createBuffer();a.bindBuffer(a.ARRAY_BUFFER,f);a.bufferData(a.ARRAY_BUFFER,d,a.STATIC_DRAW);a.bindBuffer(a.ELEMENT_ARRAY_BUFFER,g);a.bufferData(a.ELEMENT_ARRAY_BUFFER,e,a.STATIC_DRAW);h=a.createTexture();i=a.createTexture();a.bindTexture(a.TEXTURE_2D,h);a.texImage2D(a.TEXTURE_2D,0,a.RGB,16,16,0,a.RGB,a.UNSIGNED_BYTE,null);a.texParameteri(a.TEXTURE_2D,
 a.TEXTURE_WRAP_S,a.CLAMP_TO_EDGE);a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_T,a.CLAMP_TO_EDGE);a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MAG_FILTER,a.NEAREST);a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MIN_FILTER,a.NEAREST);a.bindTexture(a.TEXTURE_2D,i);a.texImage2D(a.TEXTURE_2D,0,a.RGBA,16,16,0,a.RGBA,a.UNSIGNED_BYTE,null);a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_S,a.CLAMP_TO_EDGE);a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_T,a.CLAMP_TO_EDGE);a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MAG_FILTER,a.NEAREST);
 a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MIN_FILTER,a.NEAREST);if(a.getParameter(a.MAX_VERTEX_TEXTURE_IMAGE_UNITS)<=0){j=false;l=b(THREE.ShaderFlares.lensFlare)}else{j=true;l=b(THREE.ShaderFlares.lensFlareVertexTexture)}n={};k={};n.vertex=a.getAttribLocation(l,"position");n.uv=a.getAttribLocation(l,"uv");k.renderType=a.getUniformLocation(l,"renderType");k.map=a.getUniformLocation(l,"map");k.occlusionMap=a.getUniformLocation(l,"occlusionMap");k.opacity=a.getUniformLocation(l,"opacity");k.color=a.getUniformLocation(l,
-"color");k.scale=a.getUniformLocation(l,"scale");k.rotation=a.getUniformLocation(l,"rotation");k.screenPosition=a.getUniformLocation(l,"screenPosition");m=false};this.render=function(b,d,e,s){var b=b.__webglFlares,t=b.length;if(t){var v=new THREE.Vector3,p=s/e,x=e*0.5,A=s*0.5,z=16/s,u=new THREE.Vector2(z*p,z),w=new THREE.Vector3(1,1,0),F=new THREE.Vector2(1,1),C=k,z=n;a.useProgram(l);if(!m){a.enableVertexAttribArray(n.vertex);a.enableVertexAttribArray(n.uv);m=true}a.uniform1i(C.occlusionMap,0);a.uniform1i(C.map,
-1);a.bindBuffer(a.ARRAY_BUFFER,f);a.vertexAttribPointer(z.vertex,2,a.FLOAT,false,16,0);a.vertexAttribPointer(z.uv,2,a.FLOAT,false,16,8);a.bindBuffer(a.ELEMENT_ARRAY_BUFFER,g);a.disable(a.CULL_FACE);a.depthMask(false);var B,I,K,E,D;for(B=0;B<t;B++){z=16/s;u.set(z*p,z);E=b[B];v.set(E.matrixWorld.elements[12],E.matrixWorld.elements[13],E.matrixWorld.elements[14]);d.matrixWorldInverse.multiplyVector3(v);d.projectionMatrix.multiplyVector3(v);w.copy(v);F.x=w.x*x+x;F.y=w.y*A+A;if(j||F.x>0&&F.x<e&&F.y>0&&
-F.y<s){a.activeTexture(a.TEXTURE1);a.bindTexture(a.TEXTURE_2D,h);a.copyTexImage2D(a.TEXTURE_2D,0,a.RGB,F.x-8,F.y-8,16,16,0);a.uniform1i(C.renderType,0);a.uniform2f(C.scale,u.x,u.y);a.uniform3f(C.screenPosition,w.x,w.y,w.z);a.disable(a.BLEND);a.enable(a.DEPTH_TEST);a.drawElements(a.TRIANGLES,6,a.UNSIGNED_SHORT,0);a.activeTexture(a.TEXTURE0);a.bindTexture(a.TEXTURE_2D,i);a.copyTexImage2D(a.TEXTURE_2D,0,a.RGBA,F.x-8,F.y-8,16,16,0);a.uniform1i(C.renderType,1);a.disable(a.DEPTH_TEST);a.activeTexture(a.TEXTURE1);
-a.bindTexture(a.TEXTURE_2D,h);a.drawElements(a.TRIANGLES,6,a.UNSIGNED_SHORT,0);E.positionScreen.copy(w);E.customUpdateCallback?E.customUpdateCallback(E):E.updateLensFlares();a.uniform1i(C.renderType,2);a.enable(a.BLEND);I=0;for(K=E.lensFlares.length;I<K;I++){D=E.lensFlares[I];if(D.opacity>0.0010&&D.scale>0.0010){w.x=D.x;w.y=D.y;w.z=D.z;z=D.size*D.scale/s;u.x=z*p;u.y=z;a.uniform3f(C.screenPosition,w.x,w.y,w.z);a.uniform2f(C.scale,u.x,u.y);a.uniform1f(C.rotation,D.rotation);a.uniform1f(C.opacity,D.opacity);
-a.uniform3f(C.color,D.color.r,D.color.g,D.color.b);c.setBlending(D.blending,D.blendEquation,D.blendSrc,D.blendDst);c.setTexture(D.texture,1);a.drawElements(a.TRIANGLES,6,a.UNSIGNED_SHORT,0)}}}}a.enable(a.CULL_FACE);a.enable(a.DEPTH_TEST);a.depthMask(true)}}};
+"color");k.scale=a.getUniformLocation(l,"scale");k.rotation=a.getUniformLocation(l,"rotation");k.screenPosition=a.getUniformLocation(l,"screenPosition");m=false};this.render=function(b,d,e,s){var b=b.__webglFlares,t=b.length;if(t){var v=new THREE.Vector3,p=s/e,x=e*0.5,z=s*0.5,A=16/s,w=new THREE.Vector2(A*p,A),u=new THREE.Vector3(1,1,0),C=new THREE.Vector2(1,1),B=k,A=n;a.useProgram(l);if(!m){a.enableVertexAttribArray(n.vertex);a.enableVertexAttribArray(n.uv);m=true}a.uniform1i(B.occlusionMap,0);a.uniform1i(B.map,
+1);a.bindBuffer(a.ARRAY_BUFFER,f);a.vertexAttribPointer(A.vertex,2,a.FLOAT,false,16,0);a.vertexAttribPointer(A.uv,2,a.FLOAT,false,16,8);a.bindBuffer(a.ELEMENT_ARRAY_BUFFER,g);a.disable(a.CULL_FACE);a.depthMask(false);var E,G,L,H,D;for(E=0;E<t;E++){A=16/s;w.set(A*p,A);H=b[E];v.set(H.matrixWorld.elements[12],H.matrixWorld.elements[13],H.matrixWorld.elements[14]);d.matrixWorldInverse.multiplyVector3(v);d.projectionMatrix.multiplyVector3(v);u.copy(v);C.x=u.x*x+x;C.y=u.y*z+z;if(j||C.x>0&&C.x<e&&C.y>0&&
+C.y<s){a.activeTexture(a.TEXTURE1);a.bindTexture(a.TEXTURE_2D,h);a.copyTexImage2D(a.TEXTURE_2D,0,a.RGB,C.x-8,C.y-8,16,16,0);a.uniform1i(B.renderType,0);a.uniform2f(B.scale,w.x,w.y);a.uniform3f(B.screenPosition,u.x,u.y,u.z);a.disable(a.BLEND);a.enable(a.DEPTH_TEST);a.drawElements(a.TRIANGLES,6,a.UNSIGNED_SHORT,0);a.activeTexture(a.TEXTURE0);a.bindTexture(a.TEXTURE_2D,i);a.copyTexImage2D(a.TEXTURE_2D,0,a.RGBA,C.x-8,C.y-8,16,16,0);a.uniform1i(B.renderType,1);a.disable(a.DEPTH_TEST);a.activeTexture(a.TEXTURE1);
+a.bindTexture(a.TEXTURE_2D,h);a.drawElements(a.TRIANGLES,6,a.UNSIGNED_SHORT,0);H.positionScreen.copy(u);H.customUpdateCallback?H.customUpdateCallback(H):H.updateLensFlares();a.uniform1i(B.renderType,2);a.enable(a.BLEND);G=0;for(L=H.lensFlares.length;G<L;G++){D=H.lensFlares[G];if(D.opacity>0.001&&D.scale>0.001){u.x=D.x;u.y=D.y;u.z=D.z;A=D.size*D.scale/s;w.x=A*p;w.y=A;a.uniform3f(B.screenPosition,u.x,u.y,u.z);a.uniform2f(B.scale,w.x,w.y);a.uniform1f(B.rotation,D.rotation);a.uniform1f(B.opacity,D.opacity);
+a.uniform3f(B.color,D.color.r,D.color.g,D.color.b);c.setBlending(D.blending,D.blendEquation,D.blendSrc,D.blendDst);c.setTexture(D.texture,1);a.drawElements(a.TRIANGLES,6,a.UNSIGNED_SHORT,0)}}}}a.enable(a.CULL_FACE);a.enable(a.DEPTH_TEST);a.depthMask(true)}}};
 THREE.ShadowMapPlugin=function(){var b,a,c,d,e=new THREE.Frustum,f=new THREE.Matrix4,g=new THREE.Vector3,h=new THREE.Vector3;this.init=function(e){b=e.context;a=e;var e=THREE.ShaderLib.depthRGBA,f=THREE.UniformsUtils.clone(e.uniforms);c=new THREE.ShaderMaterial({fragmentShader:e.fragmentShader,vertexShader:e.vertexShader,uniforms:f});d=new THREE.ShaderMaterial({fragmentShader:e.fragmentShader,vertexShader:e.vertexShader,uniforms:f,morphTargets:true});c._shadowPass=true;d._shadowPass=true};this.render=
 function(b,c){a.shadowMapEnabled&&a.shadowMapAutoUpdate&&this.update(b,c)};this.update=function(i,j){var l,n,k,m,o,q,r,s,t,v=[];m=0;b.clearColor(1,1,1,1);b.disable(b.BLEND);b.enable(b.CULL_FACE);a.shadowMapCullFrontFaces?b.cullFace(b.FRONT):b.cullFace(b.BACK);a.setDepthTest(true);l=0;for(n=i.__lights.length;l<n;l++){k=i.__lights[l];if(k.castShadow)if(k instanceof THREE.DirectionalLight&&k.shadowCascade)for(o=0;o<k.shadowCascadeCount;o++){var p;if(k.shadowCascadeArray[o])p=k.shadowCascadeArray[o];
 else{t=k;r=o;p=new THREE.DirectionalLight;p.isVirtual=true;p.onlyShadow=true;p.castShadow=true;p.shadowCameraNear=t.shadowCameraNear;p.shadowCameraFar=t.shadowCameraFar;p.shadowCameraLeft=t.shadowCameraLeft;p.shadowCameraRight=t.shadowCameraRight;p.shadowCameraBottom=t.shadowCameraBottom;p.shadowCameraTop=t.shadowCameraTop;p.shadowCameraVisible=t.shadowCameraVisible;p.shadowDarkness=t.shadowDarkness;p.shadowBias=t.shadowCascadeBias[r];p.shadowMapWidth=t.shadowCascadeWidth[r];p.shadowMapHeight=t.shadowCascadeHeight[r];
@@ -282,9 +289,9 @@ THREE.SpritePlugin=function(){function b(a,b){return b.z-a.z}var a,c,d,e,f,g,h,i
 g);a.bufferData(a.ELEMENT_ARRAY_BUFFER,e,a.STATIC_DRAW);var b=THREE.ShaderSprite.sprite,k=a.createProgram(),m=a.createShader(a.FRAGMENT_SHADER),o=a.createShader(a.VERTEX_SHADER);a.shaderSource(m,b.fragmentShader);a.shaderSource(o,b.vertexShader);a.compileShader(m);a.compileShader(o);a.attachShader(k,m);a.attachShader(k,o);a.linkProgram(k);h=k;i={};j={};i.position=a.getAttribLocation(h,"position");i.uv=a.getAttribLocation(h,"uv");j.uvOffset=a.getUniformLocation(h,"uvOffset");j.uvScale=a.getUniformLocation(h,
 "uvScale");j.rotation=a.getUniformLocation(h,"rotation");j.scale=a.getUniformLocation(h,"scale");j.alignment=a.getUniformLocation(h,"alignment");j.color=a.getUniformLocation(h,"color");j.map=a.getUniformLocation(h,"map");j.opacity=a.getUniformLocation(h,"opacity");j.useScreenCoordinates=a.getUniformLocation(h,"useScreenCoordinates");j.affectedByDistance=a.getUniformLocation(h,"affectedByDistance");j.screenPosition=a.getUniformLocation(h,"screenPosition");j.modelViewMatrix=a.getUniformLocation(h,"modelViewMatrix");
 j.projectionMatrix=a.getUniformLocation(h,"projectionMatrix");l=false};this.render=function(d,e,m,o){var d=d.__webglSprites,q=d.length;if(q){var r=i,s=j,t=o/m,m=m*0.5,v=o*0.5,p=true;a.useProgram(h);if(!l){a.enableVertexAttribArray(r.position);a.enableVertexAttribArray(r.uv);l=true}a.disable(a.CULL_FACE);a.enable(a.BLEND);a.depthMask(true);a.bindBuffer(a.ARRAY_BUFFER,f);a.vertexAttribPointer(r.position,2,a.FLOAT,false,16,0);a.vertexAttribPointer(r.uv,2,a.FLOAT,false,16,8);a.bindBuffer(a.ELEMENT_ARRAY_BUFFER,
-g);a.uniformMatrix4fv(s.projectionMatrix,false,e._projectionMatrixArray);a.activeTexture(a.TEXTURE0);a.uniform1i(s.map,0);for(var x,A=[],r=0;r<q;r++){x=d[r];if(x.visible&&x.opacity!==0)if(x.useScreenCoordinates)x.z=-x.position.z;else{x._modelViewMatrix.multiply(e.matrixWorldInverse,x.matrixWorld);x.z=-x._modelViewMatrix.elements[14]}}d.sort(b);for(r=0;r<q;r++){x=d[r];if(x.visible&&x.opacity!==0&&x.map&&x.map.image&&x.map.image.width){if(x.useScreenCoordinates){a.uniform1i(s.useScreenCoordinates,1);
-a.uniform3f(s.screenPosition,(x.position.x-m)/m,(v-x.position.y)/v,Math.max(0,Math.min(1,x.position.z)))}else{a.uniform1i(s.useScreenCoordinates,0);a.uniform1i(s.affectedByDistance,x.affectedByDistance?1:0);a.uniformMatrix4fv(s.modelViewMatrix,false,x._modelViewMatrix.elements)}e=x.map.image.width/(x.scaleByViewport?o:1);A[0]=e*t*x.scale.x;A[1]=e*x.scale.y;a.uniform2f(s.uvScale,x.uvScale.x,x.uvScale.y);a.uniform2f(s.uvOffset,x.uvOffset.x,x.uvOffset.y);a.uniform2f(s.alignment,x.alignment.x,x.alignment.y);
-a.uniform1f(s.opacity,x.opacity);a.uniform3f(s.color,x.color.r,x.color.g,x.color.b);a.uniform1f(s.rotation,x.rotation);a.uniform2fv(s.scale,A);if(x.mergeWith3D&&!p){a.enable(a.DEPTH_TEST);p=true}else if(!x.mergeWith3D&&p){a.disable(a.DEPTH_TEST);p=false}c.setBlending(x.blending,x.blendEquation,x.blendSrc,x.blendDst);c.setTexture(x.map,0);a.drawElements(a.TRIANGLES,6,a.UNSIGNED_SHORT,0)}}a.enable(a.CULL_FACE);a.enable(a.DEPTH_TEST);a.depthMask(true)}}};
+g);a.uniformMatrix4fv(s.projectionMatrix,false,e._projectionMatrixArray);a.activeTexture(a.TEXTURE0);a.uniform1i(s.map,0);for(var x,z=[],r=0;r<q;r++){x=d[r];if(x.visible&&x.opacity!==0)if(x.useScreenCoordinates)x.z=-x.position.z;else{x._modelViewMatrix.multiply(e.matrixWorldInverse,x.matrixWorld);x.z=-x._modelViewMatrix.elements[14]}}d.sort(b);for(r=0;r<q;r++){x=d[r];if(x.visible&&x.opacity!==0&&x.map&&x.map.image&&x.map.image.width){if(x.useScreenCoordinates){a.uniform1i(s.useScreenCoordinates,1);
+a.uniform3f(s.screenPosition,(x.position.x-m)/m,(v-x.position.y)/v,Math.max(0,Math.min(1,x.position.z)))}else{a.uniform1i(s.useScreenCoordinates,0);a.uniform1i(s.affectedByDistance,x.affectedByDistance?1:0);a.uniformMatrix4fv(s.modelViewMatrix,false,x._modelViewMatrix.elements)}e=x.map.image.width/(x.scaleByViewport?o:1);z[0]=e*t*x.scale.x;z[1]=e*x.scale.y;a.uniform2f(s.uvScale,x.uvScale.x,x.uvScale.y);a.uniform2f(s.uvOffset,x.uvOffset.x,x.uvOffset.y);a.uniform2f(s.alignment,x.alignment.x,x.alignment.y);
+a.uniform1f(s.opacity,x.opacity);a.uniform3f(s.color,x.color.r,x.color.g,x.color.b);a.uniform1f(s.rotation,x.rotation);a.uniform2fv(s.scale,z);if(x.mergeWith3D&&!p){a.enable(a.DEPTH_TEST);p=true}else if(!x.mergeWith3D&&p){a.disable(a.DEPTH_TEST);p=false}c.setBlending(x.blending,x.blendEquation,x.blendSrc,x.blendDst);c.setTexture(x.map,0);a.drawElements(a.TRIANGLES,6,a.UNSIGNED_SHORT,0)}}a.enable(a.CULL_FACE);a.enable(a.DEPTH_TEST);a.depthMask(true)}}};
 THREE.DepthPassPlugin=function(){this.enabled=false;this.renderTarget=null;var b,a,c,d,e=new THREE.Frustum,f=new THREE.Matrix4;this.init=function(e){b=e.context;a=e;var e=THREE.ShaderLib.depthRGBA,f=THREE.UniformsUtils.clone(e.uniforms);c=new THREE.ShaderMaterial({fragmentShader:e.fragmentShader,vertexShader:e.vertexShader,uniforms:f});d=new THREE.ShaderMaterial({fragmentShader:e.fragmentShader,vertexShader:e.vertexShader,uniforms:f,morphTargets:true});c._shadowPass=true;d._shadowPass=true};this.render=
 function(a,b){this.enabled&&this.update(a,b)};this.update=function(g,h){var i,j,l,n,k,m;b.clearColor(1,1,1,1);b.disable(b.BLEND);a.setDepthTest(true);a.autoUpdateScene&&g.updateMatrixWorld();if(!h._viewMatrixArray)h._viewMatrixArray=new Float32Array(16);if(!h._projectionMatrixArray)h._projectionMatrixArray=new Float32Array(16);h.matrixWorldInverse.getInverse(h.matrixWorld);h.matrixWorldInverse.flattenToArray(h._viewMatrixArray);h.projectionMatrix.flattenToArray(h._projectionMatrixArray);f.multiply(h.projectionMatrix,
 h.matrixWorldInverse);e.setFromMatrix(f);a.setRenderTarget(this.renderTarget);a.clear();m=g.__webglObjects;i=0;for(j=m.length;i<j;i++){l=m[i];k=l.object;l.render=false;if(k.visible&&(!(k instanceof THREE.Mesh)||!k.frustumCulled||e.contains(k))){k._modelViewMatrix.multiply(h.matrixWorldInverse,k.matrixWorld);l.render=true}}i=0;for(j=m.length;i<j;i++){l=m[i];if(l.render){k=l.object;l=l.buffer;a.setObjectFaces(k);n=k.customDepthMaterial?k.customDepthMaterial:k.geometry.morphTargets.length?d:c;l instanceof

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 163 - 142
build/custom/ThreeWebGL.js


+ 2 - 2
docs/api/cameras/OrthographicCamera.html

@@ -33,10 +33,10 @@ far — Camera frustum far plane.
 <h3>.[page:Float right]</h3>
 <div>Camera frustum right plane.</div>
 
-<h3>.[page:Float left]</h3>
+<h3>.[page:Float top]</h3>
 <div>Camera frustum top plane.</div>
 
-<h3>.[page:Float right]</h3>
+<h3>.[page:Float bottom]</h3>
 <div>Camera frustum bottom plane.</div>
 
 <h3>.[page:Float near]</h3>

+ 5 - 11
docs/api/core/Geometry.html

@@ -5,19 +5,13 @@
 
 <h2>Example</h2>
 
-<code>// geometry with random points
+<code>var geometry = new THREE.Geometry()
 
-var geometry = new THREE.Geometry()
+geometry.vertices.push( new THREE.Vector3( -10,  10, 0 ) );
+geometry.vertices.push( new THREE.Vector3( -10, -10, 0 ) );
+geometry.vertices.push( new THREE.Vector3(  10, -10, 0 ) );
 
-for ( var i = 0; i < 10000; i ++ ) {
-
-	var vertex = new THREE.Vector3();
-	vertex.x = Math.random() * 1000 - 500;
-	vertex.y = Math.random() * 1000 - 500;
-	vertex.z = Math.random() * 1000 - 500;
-	geometry.vertices.push( vertex );
-
-}
+geometry.faces.push( new THREE.Face3( 0, 1, 2 ) );
 
 geometry.computeBoundingSphere();
 </code>

+ 2 - 2
docs/api/materials/LineBasicMaterial.html

@@ -11,7 +11,7 @@
 
 <div>parameters is an object with one or more properties defining the material's appearance.</div>
 <div>
-color — An instance of [page:Color Color]. Default is white.<br />
+color — Line color in hexadecimal. Default is 0xffffff.<br />
 linewidth — Line thickness. Default is 1.<br />
 linecap — Define appearance of line ends. Default is 'round'.<br />
 linejoin — Define appearance of line joints. Default is 'round'.<br />
@@ -22,7 +22,7 @@ fog — Define whether the material color is affected by global fog settings. De
 <h2>Properties</h2>
 
 <h3>.[page:Color color]</h3>
-<div>An instance of [page:Color THREE.Color]. Default is a white (0xffffff) instance.</div>
+<div>Default is white.</div>
 
 <h3>.[page:Float linewidth]</h3>
 <div>Controls line thickness. Default is 1.</div>

+ 44 - 7
examples/canvas_geometry_earth.html

@@ -41,7 +41,7 @@
 
 			var container, stats;
 			var camera, scene, renderer;
-			var mesh;
+			var group;
 			var mouseX = 0, mouseY = 0;
 
 			var windowHalfX = window.innerWidth / 2;
@@ -60,12 +60,49 @@
 				camera.position.z = 500;
 				scene.add( camera );
 
-				mesh = new THREE.Mesh( new THREE.PlaneGeometry( 300, 300, 3, 3 ), new THREE.MeshBasicMaterial( { map: THREE.ImageUtils.loadTexture( 'textures/shadow.png' ), overdraw: true } ) );
-				mesh.position.y = - 250;
-				scene.add( mesh );
+				group = new THREE.Object3D();
+				scene.add( group );
+
+				// earth
+				
+				var earthTexture = new THREE.Texture();
+				var loader = new THREE.ImageLoader();
+
+				loader.addEventListener( 'load', function ( event ) {
+
+					earthTexture.image = event.content;
+					earthTexture.needsUpdate = true;
+
+				} );
+
+				loader.load( 'textures/land_ocean_ice_cloud_2048.jpg' );
+
+				var geometry = new THREE.SphereGeometry( 200, 20, 20 );
+				var material = new THREE.MeshBasicMaterial( { map: earthTexture, overdraw: true } );
 
-				mesh = new THREE.Mesh( new THREE.SphereGeometry( 200, 20, 20 ), new THREE.MeshBasicMaterial( { map: THREE.ImageUtils.loadTexture( 'textures/land_ocean_ice_cloud_2048.jpg' ), overdraw: true } ) );
-				scene.add( mesh );
+				var mesh = new THREE.Mesh( geometry, material );
+				group.add( mesh );
+
+				// shadow
+				
+				var shadowTexture = new THREE.Texture();
+				var loader = new THREE.ImageLoader();
+
+				loader.addEventListener( 'load', function ( event ) {
+				
+					shadowTexture.image = event.content;
+					shadowTexture.needsUpdate = true;
+
+				} );
+
+				loader.load( 'textures/shadow.png' );
+
+				var geometry = new THREE.PlaneGeometry( 300, 300, 3, 3 );
+				var material = new THREE.MeshBasicMaterial( { map: shadowTexture, overdraw: true } );
+
+				var mesh = new THREE.Mesh( geometry, material );
+				mesh.position.y = - 250;
+				group.add( mesh );
 
 				renderer = new THREE.CanvasRenderer();
 				renderer.setSize( window.innerWidth, window.innerHeight );
@@ -105,7 +142,7 @@
 				camera.position.y += ( - mouseY - camera.position.y ) * 0.05;
 				camera.lookAt( scene.position );
 
-				mesh.rotation.y -= 0.005;
+				group.rotation.y -= 0.005;
 
 				renderer.render( scene, camera );
 

+ 110 - 23
examples/js/MarchingCubes.js

@@ -5,12 +5,15 @@
  * http://webglsamples.googlecode.com/hg/blob/blob.html
  */
 
-THREE.MarchingCubes = function ( resolution, material ) {
+THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors ) {
 
 	THREE.ImmediateRenderObject.call( this );
 
 	this.material = material;
 
+	this.enableUvs = enableUvs !== undefined ? enableUvs : false;
+	this.enableColors = enableColors !== undefined ? enableColors : false;
+
 	// functions have to be object properties
 	// prototype functions kill performance
 	// (tested and it was 4x slower !!!)
@@ -50,12 +53,27 @@ THREE.MarchingCubes = function ( resolution, material ) {
 
 		this.maxCount = 4096; // TODO: find the fastest size for this buffer
 		this.count = 0;
-		this.hasPos = false;
-		this.hasNormal = false;
+
+		this.hasPositions = false;
+		this.hasNormals = false;
+		this.hasColors = false;
+		this.hasUvs = false;
 
 		this.positionArray = new Float32Array( this.maxCount * 3 );
 		this.normalArray   = new Float32Array( this.maxCount * 3 );
 
+		if ( this.enableUvs ) {
+
+			this.uvArray = new Float32Array( this.maxCount * 2 );
+
+		}
+
+		if ( this.enableColors ) {
+
+			this.colorArray   = new Float32Array( this.maxCount * 3 );
+
+		}
+
 	};
 
 	///////////////////////
@@ -117,7 +135,7 @@ THREE.MarchingCubes = function ( resolution, material ) {
 
 		var q3 = q * 3;
 
-		if ( this.normal_cache [ q3 ] === 0.0 ) {
+		if ( this.normal_cache[ q3 ] === 0.0 ) {
 
 			this.normal_cache[ q3     ] = this.field[ q - 1  ] 	    - this.field[ q + 1 ];
 			this.normal_cache[ q3 + 1 ] = this.field[ q - this.yd ] - this.field[ q + this.yd ];
@@ -307,7 +325,9 @@ THREE.MarchingCubes = function ( resolution, material ) {
 
 		var c = this.count * 3;
 
-		this.positionArray[ c ] = pos[ o1 ];
+		// positions
+
+		this.positionArray[ c ] 	= pos[ o1 ];
 		this.positionArray[ c + 1 ] = pos[ o1 + 1 ];
 		this.positionArray[ c + 2 ] = pos[ o1 + 2 ];
 
@@ -319,7 +339,9 @@ THREE.MarchingCubes = function ( resolution, material ) {
 		this.positionArray[ c + 7 ] = pos[ o3 + 1 ];
 		this.positionArray[ c + 8 ] = pos[ o3 + 2 ];
 
-		this.normalArray[ c ] = norm[ o1 ];
+		// normals
+
+		this.normalArray[ c ] 	  = norm[ o1 ];
 		this.normalArray[ c + 1 ] = norm[ o1 + 1 ];
 		this.normalArray[ c + 2 ] = norm[ o1 + 2 ];
 
@@ -331,13 +353,60 @@ THREE.MarchingCubes = function ( resolution, material ) {
 		this.normalArray[ c + 7 ] = norm[ o3 + 1 ];
 		this.normalArray[ c + 8 ] = norm[ o3 + 2 ];
 
-		this.hasPos = true;
-		this.hasNormal = true;
+		// uvs
+
+		if ( this.enableUvs ) {
+
+			var d = this.count * 2;
+
+			this.uvArray[ d ] 	  = pos[ o1 ];
+			this.uvArray[ d + 1 ] = pos[ o1 + 2 ];
+
+			this.uvArray[ d + 2 ] = pos[ o2 ];
+			this.uvArray[ d + 3 ] = pos[ o2 + 2 ];
+
+			this.uvArray[ d + 4 ] = pos[ o3 ];
+			this.uvArray[ d + 5 ] = pos[ o3 + 2 ];
+
+		}
+
+		// colors
+
+		if ( this.enableColors ) {
+
+			this.colorArray[ c ] 	 = pos[ o1 ];
+			this.colorArray[ c + 1 ] = pos[ o1 + 1 ];
+			this.colorArray[ c + 2 ] = pos[ o1 + 2 ];
+
+			this.colorArray[ c + 3 ] = pos[ o2 ];
+			this.colorArray[ c + 4 ] = pos[ o2 + 1 ];
+			this.colorArray[ c + 5 ] = pos[ o2 + 2 ];
+
+			this.colorArray[ c + 6 ] = pos[ o3 ];
+			this.colorArray[ c + 7 ] = pos[ o3 + 1 ];
+			this.colorArray[ c + 8 ] = pos[ o3 + 2 ];
+
+		}
 
 		this.count += 3;
 
 		if ( this.count >= this.maxCount - 3 ) {
 
+			this.hasPositions = true;
+			this.hasNormals = true;
+
+			if ( this.enableUvs ) {
+
+				this.hasUvs = true;
+
+			}
+
+			if ( this.enableColors ) {
+
+				this.hasColors = true;
+
+			}
+
 			renderCallback( this );
 
 		}
@@ -347,8 +416,11 @@ THREE.MarchingCubes = function ( resolution, material ) {
 	this.begin = function( ) {
 
 		this.count = 0;
-		this.hasPos = false;
-		this.hasNormal = false;
+
+		this.hasPositions = false;
+		this.hasNormals = false;
+		this.hasUvs = false;
+		this.hasColors = false;
 
 	};
 
@@ -360,6 +432,21 @@ THREE.MarchingCubes = function ( resolution, material ) {
 		for ( var i = this.count * 3; i < this.positionArray.length; i ++ )
 			this.positionArray[ i ] = 0.0;
 
+		this.hasPositions = true;
+		this.hasNormals = true;
+
+		if ( this.enableUvs ) {
+
+			this.hasUvs = true;
+
+		}
+
+		if ( this.enableColors ) {
+
+			this.hasColors = true;
+
+		}
+
 		renderCallback( this );
 
 	};
@@ -438,7 +525,7 @@ THREE.MarchingCubes = function ( resolution, material ) {
 
 		if ( dist > size ) dist = size;
 
-		for ( x = 0; x < dist; x++ ) {
+		for ( x = 0; x < dist; x ++ ) {
 
 			xdiv = x / size;
 			xx = xdiv * xdiv;
@@ -446,11 +533,11 @@ THREE.MarchingCubes = function ( resolution, material ) {
 
 			if ( val > 0.0 ) {
 
-				for ( y = 0; y < size; y++ ) {
+				for ( y = 0; y < size; y ++ ) {
 
 					cxy = x + y * yd;
 
-					for ( z = 0; z < size; z++ ) {
+					for ( z = 0; z < size; z ++ ) {
 
 						field[ zd * z + cxy ] += val;
 
@@ -478,7 +565,7 @@ THREE.MarchingCubes = function ( resolution, material ) {
 
 		if ( dist > size ) dist = size;
 
-		for ( y = 0; y < dist; y++ ) {
+		for ( y = 0; y < dist; y ++ ) {
 
 			ydiv = y / size;
 			yy = ydiv * ydiv;
@@ -488,11 +575,11 @@ THREE.MarchingCubes = function ( resolution, material ) {
 
 				cy = y * yd;
 
-				for ( x = 0; x < size; x++ ) {
+				for ( x = 0; x < size; x ++ ) {
 
 					cxy = cy + x;
 
-					for ( z = 0; z < size; z++ )
+					for ( z = 0; z < size; z ++ )
 						field[ zd * z + cxy ] += val;
 
 				}
@@ -517,7 +604,7 @@ THREE.MarchingCubes = function ( resolution, material ) {
 
 		if ( dist > size ) dist = size;
 
-		for ( z = 0; z < dist; z++ ) {
+		for ( z = 0; z < dist; z ++ ) {
 
 			zdiv = z / size;
 			zz = zdiv * zdiv;
@@ -526,12 +613,12 @@ THREE.MarchingCubes = function ( resolution, material ) {
 
 				cz = zd * z;
 
-				for ( y = 0; y < size; y++ ) {
+				for ( y = 0; y < size; y ++ ) {
 
-						cyz = cz + y * yd;
+					cyz = cz + y * yd;
 
-						for ( x = 0; x < size; x++ )
-							field[ cyz + x ] += val;
+					for ( x = 0; x < size; x ++ )
+						field[ cyz + x ] += val;
 
 				}
 
@@ -606,7 +693,7 @@ THREE.MarchingCubes = function ( resolution, material ) {
 				face, a, b, c, na, nb, nc, nfaces;
 
 
-			for ( i = 0; i < object.count; i++ ) {
+			for ( i = 0; i < object.count; i ++ ) {
 
 				a = i * 3;
 				b = a + 1;
@@ -630,7 +717,7 @@ THREE.MarchingCubes = function ( resolution, material ) {
 
 			nfaces = object.count / 3;
 
-			for ( i = 0; i < nfaces; i++ ) {
+			for ( i = 0; i < nfaces; i ++ ) {
 
 				a = ( start + i ) * 3;
 				b = a + 1;

+ 6 - 8
examples/js/Stats.js

@@ -1,8 +1,6 @@
-// stats.js r8 - http://github.com/mrdoob/stats.js
-var Stats=function(){var h,a,n=0,o=0,i=Date.now(),u=i,p=i,l=0,q=1E3,r=0,e,j,f,b=[[16,16,48],[0,255,255]],m=0,s=1E3,t=0,d,k,g,c=[[16,48,16],[0,255,0]];h=document.createElement("div");h.style.cursor="pointer";h.style.width="80px";h.style.opacity="0.9";h.style.zIndex="10001";h.addEventListener("mousedown",function(a){a.preventDefault();n=(n+1)%2;n==0?(e.style.display="block",d.style.display="none"):(e.style.display="none",d.style.display="block")},!1);e=document.createElement("div");e.style.textAlign=
-"left";e.style.lineHeight="1.2em";e.style.backgroundColor="rgb("+Math.floor(b[0][0]/2)+","+Math.floor(b[0][1]/2)+","+Math.floor(b[0][2]/2)+")";e.style.padding="0 0 3px 3px";h.appendChild(e);j=document.createElement("div");j.style.fontFamily="Helvetica, Arial, sans-serif";j.style.fontSize="9px";j.style.color="rgb("+b[1][0]+","+b[1][1]+","+b[1][2]+")";j.style.fontWeight="bold";j.innerHTML="FPS";e.appendChild(j);f=document.createElement("div");f.style.position="relative";f.style.width="74px";f.style.height=
-"30px";f.style.backgroundColor="rgb("+b[1][0]+","+b[1][1]+","+b[1][2]+")";for(e.appendChild(f);f.children.length<74;)a=document.createElement("span"),a.style.width="1px",a.style.height="30px",a.style.cssFloat="left",a.style.backgroundColor="rgb("+b[0][0]+","+b[0][1]+","+b[0][2]+")",f.appendChild(a);d=document.createElement("div");d.style.textAlign="left";d.style.lineHeight="1.2em";d.style.backgroundColor="rgb("+Math.floor(c[0][0]/2)+","+Math.floor(c[0][1]/2)+","+Math.floor(c[0][2]/2)+")";d.style.padding=
-"0 0 3px 3px";d.style.display="none";h.appendChild(d);k=document.createElement("div");k.style.fontFamily="Helvetica, Arial, sans-serif";k.style.fontSize="9px";k.style.color="rgb("+c[1][0]+","+c[1][1]+","+c[1][2]+")";k.style.fontWeight="bold";k.innerHTML="MS";d.appendChild(k);g=document.createElement("div");g.style.position="relative";g.style.width="74px";g.style.height="30px";g.style.backgroundColor="rgb("+c[1][0]+","+c[1][1]+","+c[1][2]+")";for(d.appendChild(g);g.children.length<74;)a=document.createElement("span"),
-a.style.width="1px",a.style.height=Math.random()*30+"px",a.style.cssFloat="left",a.style.backgroundColor="rgb("+c[0][0]+","+c[0][1]+","+c[0][2]+")",g.appendChild(a);return{domElement:h,update:function(){i=Date.now();m=i-u;s=Math.min(s,m);t=Math.max(t,m);k.textContent=m+" MS ("+s+"-"+t+")";var a=Math.min(30,30-m/200*30);g.appendChild(g.firstChild).style.height=a+"px";u=i;o++;if(i>p+1E3)l=Math.round(o*1E3/(i-p)),q=Math.min(q,l),r=Math.max(r,l),j.textContent=l+" FPS ("+q+"-"+r+")",a=Math.min(30,30-l/
-100*30),f.appendChild(f.firstChild).style.height=a+"px",p=i,o=0}}};
-
+// stats.js r10 - http://github.com/mrdoob/stats.js
+var Stats=function(){var l=Date.now(),m=l,g=0,n=1E3,o=0,h=0,p=1E3,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{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()}}};

+ 83 - 1
examples/js/UVsUtils.js

@@ -1,5 +1,87 @@
+/*
+ * @author gyuque / https://github.com/gyuque
+ *
+ * Cylinder Mapping for ExtrudeGeometry
+ *
+ */
+
+THREE.UVsUtils = {
+
+};
+
+THREE.UVsUtils.CylinderUVGenerator = function() {
+    this.uRepeat = 1;
+    this.targetGeometry = null;
+    this.lengthCache = null;
+};
+
+THREE.UVsUtils.CylinderUVGenerator.prototype = {
+    generateTopUV: THREE.ExtrudeGeometry.WorldUVGenerator.generateTopUV,
+    generateBottomUV: THREE.ExtrudeGeometry.WorldUVGenerator.generateBottomUV,
+    
+    generateSideWallUV: function( geometry, extrudedShape, wallContour, extrudeOptions,
+                                  indexA, indexB, indexC, indexD, stepIndex, stepsLength,
+                                  contourIndex1, contourIndex2 ) {
+        // first call
+        if (this.targetGeometry !== geometry) {
+            this.prepare(geometry, wallContour);
+        }
+
+        // generate uv
+        var u_list = this.lengthCache;
+        var v1 = stepIndex / stepsLength;
+        var v2 = ( stepIndex + 1 ) / stepsLength;
+        
+        var u1 = u_list[contourIndex1];
+        var u2 = u_list[contourIndex2];
+        if (u1 < u2) {u1 += 1.0;}
+        
+        u1 *= this.uRepeat;
+        u2 *= this.uRepeat;
+        return [
+            new THREE.UV( u1, v1 ),
+            new THREE.UV( u2, v1 ),
+            new THREE.UV( u2, v2 ),
+            new THREE.UV( u1, v2 )
+        ];
+    },
+    
+    prepare: function(geometry, wallContour) {
+        var p1, p2;
+        var u_list = [];
+        var lengthSum = 0;
+        var len = wallContour.length;
+        for (var i = 0;i < len;i++) {
+            p1 = wallContour[ i ];
+            p2 = wallContour[ (i+1) % len ];
+
+            var dx = p1.x - p2.x;
+            var dy = p1.y - p2.y;
+            var segmentLength = Math.sqrt(dx*dx + dy*dy);
+            
+            u_list.push(lengthSum);
+            lengthSum += segmentLength;
+        }
+        
+        this.normalizeArray(u_list, lengthSum);
+        this.targetGeometry = geometry;
+        this.lengthCache = u_list;
+    },
+    
+    normalizeArray: function(ls, v) {
+        var len = ls.length;
+        for (var i = 0;i < len;i++) {
+            ls[i] /= v;
+        }
+        
+        return ls;
+    }
+};
+
+
+
 /* 
- * @author https://github.com/zz85 | @blurspline
+ * @author zz85 / https://github.com/zz85
  *
  * tool for "unwrapping" and debugging three.js 
  * geometries UV mapping

+ 213 - 204
examples/js/loaders/OBJLoader.js

@@ -2,302 +2,311 @@
  * @author mrdoob / http://mrdoob.com/
  */
 
-THREE.OBJLoader = function () {};
+THREE.OBJLoader = function () {
 
-THREE.OBJLoader.prototype = new THREE.Loader();
-THREE.OBJLoader.prototype.constructor = THREE.OBJLoader;
+	THREE.EventTarget.call( this );
 
-THREE.OBJLoader.prototype.load = function ( url, callback ) {
+};
 
-	var that = this;
-	var xhr = new XMLHttpRequest();
+THREE.OBJLoader.prototype = {
 
-	xhr.onreadystatechange = function () {
+	constructor: THREE.OBJLoader,
 
-		if ( xhr.readyState == 4 ) {
+	load: function ( url ) {
 
-			if ( xhr.status == 200 || xhr.status == 0 ) {
+		var scope = this;
+		var xhr = new XMLHttpRequest();
 
-				callback( that.parse( xhr.responseText ) );
+		xhr.addEventListener( 'load', function ( event ) {
 
-			} else {
+			scope.dispatchEvent( { type: 'load', content: scope.parse( event.target.responseText ) } );
 
-				console.error( 'THREE.OBJLoader: Couldn\'t load ' + url + ' (' + xhr.status + ')' );
+		}, false );
 
-			}
+		xhr.addEventListener( 'progress', function ( event ) {
 
-		}
+			scope.dispatchEvent( { type: 'progress', loaded: event.loaded, total: event.total } );
 
-	};
+		}, false );
 
-	xhr.open( "GET", url, true );
-	xhr.send( null );
+		xhr.addEventListener( 'error', function () {
 
-};
+			scope.dispatchEvent( { type: 'error', message: 'Couldn\'t load URL [' + url + ']' } );
 
-THREE.OBJLoader.prototype.parse = function ( data ) {
+		}, false );
 
-	function vector( x, y, z ) {
+		xhr.open( 'GET', url, true );
+		xhr.send( null );
 
-		return new THREE.Vector3( x, y, z );
+	},
 
-	}
+	parse: function ( data ) {
 
-	function uv( u, v ) {
+		function vector( x, y, z ) {
 
-		return new THREE.UV( u, 1.0 - v );
+			return new THREE.Vector3( x, y, z );
 
-	}
+		}
 
-	function face3( a, b, c, normals ) {
+		function uv( u, v ) {
 
-		return new THREE.Face3( a, b, c, normals );
+			return new THREE.UV( u, 1.0 - v );
 
-	}
+		}
 
-	function face4( a, b, c, d, normals ) {
+		function face3( a, b, c, normals ) {
 
-		return new THREE.Face4( a, b, c, d, normals );
+			return new THREE.Face3( a, b, c, normals );
 
-	}
+		}
 
-	var group = new THREE.Object3D();
+		function face4( a, b, c, d, normals ) {
 
-	var vertices = [];
-	var normals = [];
-	var uvs = [];
+			return new THREE.Face4( a, b, c, d, normals );
 
-	var pattern, result;
+		}
 
-	// v float float float
+		var group = new THREE.Object3D();
 
-	pattern = /v( [\d|\.|\+|\-|e]+)( [\d|\.|\+|\-|e]+)( [\d|\.|\+|\-|e]+)/g;
+		var vertices = [];
+		var normals = [];
+		var uvs = [];
 
-	while ( ( result = pattern.exec( data ) ) != null ) {
+		var pattern, result;
 
-		// ["v 1.0 2.0 3.0", "1.0", "2.0", "3.0"]
+		// v float float float
 
-		vertices.push( vector(
-			parseFloat( result[ 1 ] ),
-			parseFloat( result[ 2 ] ),
-			parseFloat( result[ 3 ] )
-		) );
+		pattern = /v( [\d|\.|\+|\-|e]+)( [\d|\.|\+|\-|e]+)( [\d|\.|\+|\-|e]+)/g;
 
-	}
+		while ( ( result = pattern.exec( data ) ) != null ) {
 
+			// ["v 1.0 2.0 3.0", "1.0", "2.0", "3.0"]
 
-	// vn float float float
+			vertices.push( vector(
+				parseFloat( result[ 1 ] ),
+				parseFloat( result[ 2 ] ),
+				parseFloat( result[ 3 ] )
+			) );
 
-	pattern = /vn( [\d|\.|\+|\-|e]+)( [\d|\.|\+|\-|e]+)( [\d|\.|\+|\-|e]+)/g;
+		}
 
-	while ( ( result = pattern.exec( data ) ) != null ) {
 
-		// ["vn 1.0 2.0 3.0", "1.0", "2.0", "3.0"]
+		// vn float float float
 
-		normals.push( vector(
-			parseFloat( result[ 1 ] ),
-			parseFloat( result[ 2 ] ),
-			parseFloat( result[ 3 ] )
-		) );
+		pattern = /vn( [\d|\.|\+|\-|e]+)( [\d|\.|\+|\-|e]+)( [\d|\.|\+|\-|e]+)/g;
 
-	}
+		while ( ( result = pattern.exec( data ) ) != null ) {
 
-	// vt float float
+			// ["vn 1.0 2.0 3.0", "1.0", "2.0", "3.0"]
 
-	pattern = /vt( [\d|\.|\+|\-|e]+)( [\d|\.|\+|\-|e]+)/g;
+			normals.push( vector(
+				parseFloat( result[ 1 ] ),
+				parseFloat( result[ 2 ] ),
+				parseFloat( result[ 3 ] )
+			) );
 
-	while ( ( result = pattern.exec( data ) ) != null ) {
+		}
 
-		// ["vt 0.1 0.2", "0.1", "0.2"]
+		// vt float float
 
-		uvs.push( uv(
-			parseFloat( result[ 1 ] ),
-			parseFloat( result[ 2 ] )
-		) );
+		pattern = /vt( [\d|\.|\+|\-|e]+)( [\d|\.|\+|\-|e]+)/g;
 
-	}
+		while ( ( result = pattern.exec( data ) ) != null ) {
 
-	var data = data.split( '\no ');
+			// ["vt 0.1 0.2", "0.1", "0.2"]
 
-	for ( var i = 0, l = data.length; i < l; i ++ ) {
+			uvs.push( uv(
+				parseFloat( result[ 1 ] ),
+				parseFloat( result[ 2 ] )
+			) );
 
-		var object = data[ i ];
+		}
+
+		var data = data.split( '\no ');
+
+		for ( var i = 0, l = data.length; i < l; i ++ ) {
 
-		var geometry = new THREE.Geometry();
+			var object = data[ i ];
 
-		geometry.vertices = vertices;
+			var geometry = new THREE.Geometry();
 
-		// f vertex vertex vertex ...
+			geometry.vertices = vertices;
 
-		pattern = /f( [\d]+)( [\d]+)( [\d]+)( [\d]+)?/g;
+			// f vertex vertex vertex ...
 
-		while ( ( result = pattern.exec( object ) ) != null ) {
+			pattern = /f( [\d]+)( [\d]+)( [\d]+)( [\d]+)?/g;
 
-			// ["f 1 2 3", "1", "2", "3", undefined]
+			while ( ( result = pattern.exec( object ) ) != null ) {
 
-			if ( result[ 4 ] === undefined ) {
+				// ["f 1 2 3", "1", "2", "3", undefined]
+
+				if ( result[ 4 ] === undefined ) {
 			
-				geometry.faces.push( face3(
-					parseInt( result[ 1 ] ) - 1,
-					parseInt( result[ 2 ] ) - 1,
-					parseInt( result[ 3 ] ) - 1
-				) );
+					geometry.faces.push( face3(
+						parseInt( result[ 1 ] ) - 1,
+						parseInt( result[ 2 ] ) - 1,
+						parseInt( result[ 3 ] ) - 1
+					) );
 
-			} else {
+				} else {
 
-				geometry.faces.push( face4(
-					parseInt( result[ 1 ] ) - 1,
-					parseInt( result[ 2 ] ) - 1,
-					parseInt( result[ 3 ] ) - 1,
-					parseInt( result[ 4 ] ) - 1
-				) );
+					geometry.faces.push( face4(
+						parseInt( result[ 1 ] ) - 1,
+						parseInt( result[ 2 ] ) - 1,
+						parseInt( result[ 3 ] ) - 1,
+						parseInt( result[ 4 ] ) - 1
+					) );
 
-			}
+				}
 
-		}
+			}
 
-		// f vertex/uv vertex/uv vertex/uv ...
+			// f vertex/uv vertex/uv vertex/uv ...
 
-		pattern = /f( ([\d]+)\/([\d]+))( ([\d]+)\/([\d]+))( ([\d]+)\/([\d]+))( ([\d]+)\/([\d]+))?/g;
+			pattern = /f( ([\d]+)\/([\d]+))( ([\d]+)\/([\d]+))( ([\d]+)\/([\d]+))( ([\d]+)\/([\d]+))?/g;
 
-		while ( ( result = pattern.exec( object ) ) != null ) {
+			while ( ( result = pattern.exec( object ) ) != null ) {
 
-			// ["f 1/1 2/2 3/3", " 1/1", "1", "1", " 2/2", "2", "2", " 3/3", "3", "3", undefined, undefined, undefined]
+				// ["f 1/1 2/2 3/3", " 1/1", "1", "1", " 2/2", "2", "2", " 3/3", "3", "3", undefined, undefined, undefined]
 
-			if ( result[ 10 ] === undefined ) {
+				if ( result[ 10 ] === undefined ) {
 			
-				geometry.faces.push( face3(
-					parseInt( result[ 2 ] ) - 1,
-					parseInt( result[ 5 ] ) - 1,
-					parseInt( result[ 8 ] ) - 1
-				) );
-
-				geometry.faceVertexUvs[ 0 ].push( [
-					uvs[ parseInt( result[ 3 ] ) - 1 ],
-					uvs[ parseInt( result[ 6 ] ) - 1 ],
-					uvs[ parseInt( result[ 9 ] ) - 1 ]
-				] );
-
-			} else {
-
-				geometry.faces.push( face4(
-					parseInt( result[ 2 ] ) - 1,
-					parseInt( result[ 5 ] ) - 1,
-					parseInt( result[ 8 ] ) - 1,
-					parseInt( result[ 11 ] ) - 1
-				) );
-
-				geometry.faceVertexUvs[ 0 ].push( [
-					uvs[ parseInt( result[ 3 ] ) - 1 ],
-					uvs[ parseInt( result[ 6 ] ) - 1 ],
-					uvs[ parseInt( result[ 9 ] ) - 1 ],
-					uvs[ parseInt( result[ 12 ] ) - 1 ]
-				] );
+					geometry.faces.push( face3(
+						parseInt( result[ 2 ] ) - 1,
+						parseInt( result[ 5 ] ) - 1,
+						parseInt( result[ 8 ] ) - 1
+					) );
+
+					geometry.faceVertexUvs[ 0 ].push( [
+						uvs[ parseInt( result[ 3 ] ) - 1 ],
+						uvs[ parseInt( result[ 6 ] ) - 1 ],
+						uvs[ parseInt( result[ 9 ] ) - 1 ]
+					] );
+
+				} else {
+
+					geometry.faces.push( face4(
+						parseInt( result[ 2 ] ) - 1,
+						parseInt( result[ 5 ] ) - 1,
+						parseInt( result[ 8 ] ) - 1,
+						parseInt( result[ 11 ] ) - 1
+					) );
+
+					geometry.faceVertexUvs[ 0 ].push( [
+						uvs[ parseInt( result[ 3 ] ) - 1 ],
+						uvs[ parseInt( result[ 6 ] ) - 1 ],
+						uvs[ parseInt( result[ 9 ] ) - 1 ],
+						uvs[ parseInt( result[ 12 ] ) - 1 ]
+					] );
+
+				}
 
 			}
 
-		}
-
-		// f vertex/uv/normal vertex/uv/normal vertex/uv/normal ...
+			// f vertex/uv/normal vertex/uv/normal vertex/uv/normal ...
 
-		pattern = /f( ([\d]+)\/([\d]+)\/([\d]+))( ([\d]+)\/([\d]+)\/([\d]+))( ([\d]+)\/([\d]+)\/([\d]+))( ([\d]+)\/([\d]+)\/([\d]+))?/g;
+			pattern = /f( ([\d]+)\/([\d]+)\/([\d]+))( ([\d]+)\/([\d]+)\/([\d]+))( ([\d]+)\/([\d]+)\/([\d]+))( ([\d]+)\/([\d]+)\/([\d]+))?/g;
 
-		while ( ( result = pattern.exec( object ) ) != null ) {
+			while ( ( result = pattern.exec( object ) ) != null ) {
 
-			// ["f 1/1/1 2/2/2 3/3/3", " 1/1/1", "1", "1", "1", " 2/2/2", "2", "2", "2", " 3/3/3", "3", "3", "3", undefined, undefined, undefined, undefined]
+				// ["f 1/1/1 2/2/2 3/3/3", " 1/1/1", "1", "1", "1", " 2/2/2", "2", "2", "2", " 3/3/3", "3", "3", "3", undefined, undefined, undefined, undefined]
 
-			if ( result[ 13 ] === undefined ) {
+				if ( result[ 13 ] === undefined ) {
 			
-				geometry.faces.push( face3(
-					parseInt( result[ 2 ] ) - 1,
-					parseInt( result[ 6 ] ) - 1,
-					parseInt( result[ 10 ] ) - 1,
-					[
-						normals[ parseInt( result[ 4 ] ) - 1 ],
-						normals[ parseInt( result[ 8 ] ) - 1 ],
-						normals[ parseInt( result[ 12 ] ) - 1 ]
-					]
-				) );
-
-				geometry.faceVertexUvs[ 0 ].push( [
-					uvs[ parseInt( result[ 3 ] ) - 1 ],
-					uvs[ parseInt( result[ 7 ] ) - 1 ],
-					uvs[ parseInt( result[ 11 ] ) - 1 ]
-				] );
-
-			} else {
-
-				geometry.faces.push( face4(
-					parseInt( result[ 2 ] ) - 1,
-					parseInt( result[ 6 ] ) - 1,
-					parseInt( result[ 10 ] ) - 1,
-					parseInt( result[ 14 ] ) - 1,
-					[
-						normals[ parseInt( result[ 4 ] ) - 1 ],
-						normals[ parseInt( result[ 8 ] ) - 1 ],
-						normals[ parseInt( result[ 12 ] ) - 1 ],
-						normals[ parseInt( result[ 16 ] ) - 1 ]
-					]
-				) );
-
-				geometry.faceVertexUvs[ 0 ].push( [
-					uvs[ parseInt( result[ 3 ] ) - 1 ],
-					uvs[ parseInt( result[ 7 ] ) - 1 ],
-					uvs[ parseInt( result[ 11 ] ) - 1 ],
-					uvs[ parseInt( result[ 15 ] ) - 1 ]
-				] );
-
-			}
+					geometry.faces.push( face3(
+						parseInt( result[ 2 ] ) - 1,
+						parseInt( result[ 6 ] ) - 1,
+						parseInt( result[ 10 ] ) - 1,
+						[
+							normals[ parseInt( result[ 4 ] ) - 1 ],
+							normals[ parseInt( result[ 8 ] ) - 1 ],
+							normals[ parseInt( result[ 12 ] ) - 1 ]
+						]
+					) );
+
+					geometry.faceVertexUvs[ 0 ].push( [
+						uvs[ parseInt( result[ 3 ] ) - 1 ],
+						uvs[ parseInt( result[ 7 ] ) - 1 ],
+						uvs[ parseInt( result[ 11 ] ) - 1 ]
+					] );
+
+				} else {
+
+					geometry.faces.push( face4(
+						parseInt( result[ 2 ] ) - 1,
+						parseInt( result[ 6 ] ) - 1,
+						parseInt( result[ 10 ] ) - 1,
+						parseInt( result[ 14 ] ) - 1,
+						[
+							normals[ parseInt( result[ 4 ] ) - 1 ],
+							normals[ parseInt( result[ 8 ] ) - 1 ],
+							normals[ parseInt( result[ 12 ] ) - 1 ],
+							normals[ parseInt( result[ 16 ] ) - 1 ]
+						]
+					) );
+
+					geometry.faceVertexUvs[ 0 ].push( [
+						uvs[ parseInt( result[ 3 ] ) - 1 ],
+						uvs[ parseInt( result[ 7 ] ) - 1 ],
+						uvs[ parseInt( result[ 11 ] ) - 1 ],
+						uvs[ parseInt( result[ 15 ] ) - 1 ]
+					] );
+
+				}
 
 
-		}
+			}
 
-		// f vertex//normal vertex//normal vertex//normal ...
+			// f vertex//normal vertex//normal vertex//normal ...
 
-		pattern = /f( ([\d]+)\/\/([\d]+))( ([\d]+)\/\/([\d]+))( ([\d]+)\/\/([\d]+))( ([\d]+)\/\/([\d]+))?/g;
+			pattern = /f( ([\d]+)\/\/([\d]+))( ([\d]+)\/\/([\d]+))( ([\d]+)\/\/([\d]+))( ([\d]+)\/\/([\d]+))?/g;
 
-		while ( ( result = pattern.exec( object ) ) != null ) {
+			while ( ( result = pattern.exec( object ) ) != null ) {
 
-			// ["f 1//1 2//2 3//3", " 1//1", "1", "1", " 2//2", "2", "2", " 3//3", "3", "3", undefined, undefined, undefined]
+				// ["f 1//1 2//2 3//3", " 1//1", "1", "1", " 2//2", "2", "2", " 3//3", "3", "3", undefined, undefined, undefined]
 
-			if ( result[ 10 ] === undefined ) {
+				if ( result[ 10 ] === undefined ) {
 			
-				geometry.faces.push( face3(
-					parseInt( result[ 2 ] ) - 1,
-					parseInt( result[ 5 ] ) - 1,
-					parseInt( result[ 8 ] ) - 1,
-					[
-						normals[ parseInt( result[ 3 ] ) - 1 ],
-						normals[ parseInt( result[ 6 ] ) - 1 ],
-						normals[ parseInt( result[ 9 ] ) - 1 ]
-					]
-				) );
-
-			} else {
-
-				geometry.faces.push( face4(
-					parseInt( result[ 2 ] ) - 1,
-					parseInt( result[ 5 ] ) - 1,
-					parseInt( result[ 8 ] ) - 1,
-					parseInt( result[ 11 ] ) - 1,
-					[
-						normals[ parseInt( result[ 3 ] ) - 1 ],
-						normals[ parseInt( result[ 6 ] ) - 1 ],
-						normals[ parseInt( result[ 9 ] ) - 1 ],
-						normals[ parseInt( result[ 12 ] ) - 1 ]
-					]
-				) );
+					geometry.faces.push( face3(
+						parseInt( result[ 2 ] ) - 1,
+						parseInt( result[ 5 ] ) - 1,
+						parseInt( result[ 8 ] ) - 1,
+						[
+							normals[ parseInt( result[ 3 ] ) - 1 ],
+							normals[ parseInt( result[ 6 ] ) - 1 ],
+							normals[ parseInt( result[ 9 ] ) - 1 ]
+						]
+					) );
+
+				} else {
+
+					geometry.faces.push( face4(
+						parseInt( result[ 2 ] ) - 1,
+						parseInt( result[ 5 ] ) - 1,
+						parseInt( result[ 8 ] ) - 1,
+						parseInt( result[ 11 ] ) - 1,
+						[
+							normals[ parseInt( result[ 3 ] ) - 1 ],
+							normals[ parseInt( result[ 6 ] ) - 1 ],
+							normals[ parseInt( result[ 9 ] ) - 1 ],
+							normals[ parseInt( result[ 12 ] ) - 1 ]
+						]
+					) );
+
+				}
 
 			}
 
-		}
+			geometry.computeCentroids();
+			geometry.computeFaceNormals();
+			geometry.computeBoundingSphere();
+
+			group.add( new THREE.Mesh( geometry, new THREE.MeshLambertMaterial() ) );
 
-		geometry.computeCentroids();
+		}
 
-		group.add( new THREE.Mesh( geometry, new THREE.MeshLambertMaterial() ) );
+		return group;
 
 	}
 
-	return group;
-
 }

+ 60 - 53
examples/js/loaders/VTKLoader.js

@@ -2,104 +2,111 @@
  * @author mrdoob / http://mrdoob.com/
  */
 
-THREE.VTKLoader = function () {};
+THREE.VTKLoader = function () {
 
-THREE.VTKLoader.prototype = new THREE.Loader();
-THREE.VTKLoader.prototype.constructor = THREE.VTKLoader;
+	THREE.EventTarget.call( this );
 
-THREE.VTKLoader.prototype.load = function ( url, callback ) {
+};
 
-	var that = this;
-	var xhr = new XMLHttpRequest();
+THREE.VTKLoader.prototype = {
 
-	xhr.onreadystatechange = function () {
+	constructor: THREE.VTKLoader,
 
-		if ( xhr.readyState == 4 ) {
+	load: function ( url ) {
 
-			if ( xhr.status == 200 || xhr.status == 0 ) {
+		var scope = this;
+		var xhr = new XMLHttpRequest();
 
-				callback( that.parse( xhr.responseText ) );
+		xhr.addEventListener( 'load', function ( event ) {
 
-			} else {
+			scope.dispatchEvent( { type: 'load', content: scope.parse( event.target.responseText ) } );
 
-				console.error( 'THREE.VTKLoader: Couldn\'t load ' + url + ' (' + xhr.status + ')' );
+		}, false );
 
-			}
+		xhr.addEventListener( 'progress', function ( event ) {
 
-		}
+			scope.dispatchEvent( { type: 'progress', loaded: event.loaded, total: event.total } );
 
-	};
+		}, false );
 
-	xhr.open( "GET", url, true );
-	xhr.send( null );
+		xhr.addEventListener( 'error', function () {
 
-};
+			scope.dispatchEvent( { type: 'error', message: 'Couldn\'t load URL [' + url + ']' } );
 
-THREE.VTKLoader.prototype.parse = function ( data ) {
+		}, false );
 
-	var geometry = new THREE.Geometry();
+		xhr.open( 'GET', url, true );
+		xhr.send( null );
 
-	function vertex( x, y, z ) {
+	},
 
-		geometry.vertices.push( new THREE.Vector3( x, y, z ) );
+	parse: function ( data ) {
 
-	}
+		var geometry = new THREE.Geometry();
 
-	function face3( a, b, c ) {
+		function vertex( x, y, z ) {
 
-		geometry.faces.push( new THREE.Face3( a, b, c ) );
+			geometry.vertices.push( new THREE.Vector3( x, y, z ) );
 
-	}
+		}
 
-	function face4( a, b, c, d ) {
+		function face3( a, b, c ) {
 
-		geometry.faces.push( new THREE.Face4( a, b, c, d ) );
+			geometry.faces.push( new THREE.Face3( a, b, c ) );
 
-	}
+		}
 
-	var pattern, result;
+		function face4( a, b, c, d ) {
 
-	// float float float
+			geometry.faces.push( new THREE.Face4( a, b, c, d ) );
 
-	pattern = /([\d|\.|\+|\-|e]+)[ ]+([\d|\.|\+|\-|e]+)[ ]+([\d|\.|\+|\-|e]+)/g;
+		}
 
-	while ( ( result = pattern.exec( data ) ) != null ) {
+		var pattern, result;
 
-		// ["1.0 2.0 3.0", "1.0", "2.0", "3.0"]
+		// float float float
 
-		vertex( parseFloat( result[ 1 ] ), parseFloat( result[ 2 ] ), parseFloat( result[ 3 ] ) );
+		pattern = /([\d|\.|\+|\-|e]+)[ ]+([\d|\.|\+|\-|e]+)[ ]+([\d|\.|\+|\-|e]+)/g;
 
-	}
+		while ( ( result = pattern.exec( data ) ) != null ) {
 
-	// 3 int int int
+			// ["1.0 2.0 3.0", "1.0", "2.0", "3.0"]
 
-	pattern = /3[ ]+([\d]+)[ ]+([\d]+)[ ]+([\d]+)/g;
+			vertex( parseFloat( result[ 1 ] ), parseFloat( result[ 2 ] ), parseFloat( result[ 3 ] ) );
 
-	while ( ( result = pattern.exec( data ) ) != null ) {
+		}
 
-		// ["3 1 2 3", "1", "2", "3"]
+		// 3 int int int
 
-		face3( parseInt( result[ 1 ] ), parseInt( result[ 2 ] ), parseInt( result[ 3 ] ) );
+		pattern = /3[ ]+([\d]+)[ ]+([\d]+)[ ]+([\d]+)/g;
 
-	}
+		while ( ( result = pattern.exec( data ) ) != null ) {
 
-	// 4 int int int int
+			// ["3 1 2 3", "1", "2", "3"]
 
-	pattern = /4[ ]+([\d]+)[ ]+([\d]+)[ ]+([\d]+)[ ]+([\d]+)/g;
+			face3( parseInt( result[ 1 ] ), parseInt( result[ 2 ] ), parseInt( result[ 3 ] ) );
 
-	while ( ( result = pattern.exec( data ) ) != null ) {
+		}
 
-		// ["4 1 2 3 4", "1", "2", "3", "4"]
+		// 4 int int int int
 
-		face4( parseInt( result[ 1 ] ), parseInt( result[ 2 ] ), parseInt( result[ 3 ] ), parseInt( result[ 4 ] ) );
+		pattern = /4[ ]+([\d]+)[ ]+([\d]+)[ ]+([\d]+)[ ]+([\d]+)/g;
 
-	}
+		while ( ( result = pattern.exec( data ) ) != null ) {
+
+			// ["4 1 2 3 4", "1", "2", "3", "4"]
 
-	geometry.computeCentroids();
-	geometry.computeFaceNormals();
-	geometry.computeVertexNormals();
-	geometry.computeBoundingSphere();
+			face4( parseInt( result[ 1 ] ), parseInt( result[ 2 ] ), parseInt( result[ 3 ] ), parseInt( result[ 4 ] ) );
 
-	return geometry;
+		}
+
+		geometry.computeCentroids();
+		geometry.computeFaceNormals();
+		geometry.computeVertexNormals();
+		geometry.computeBoundingSphere();
+
+		return geometry;
+
+	}
 
 }

+ 18 - 20
examples/js/renderers/SoftwareRenderer2.js

@@ -18,10 +18,10 @@ THREE.SoftwareRenderer2 = function () {
 	var canvasWidthHalf = canvasWidth / 2;
 	var canvasHeightHalf = canvasHeight / 2;
 
-	var rectx1 = 0, recty1 = 0;
+	var rectx1 = Infinity, recty1 = Infinity;
 	var rectx2 = 0, recty2 = 0;
 
-	var prevrectx1 = 0, prevrecty1 = 0;
+	var prevrectx1 = Infinity, prevrecty1 = Infinity;
 	var prevrectx2 = 0, prevrecty2 = 0;
 
 	var projector = new THREE.Projector();
@@ -54,8 +54,8 @@ THREE.SoftwareRenderer2 = function () {
 
 	this.render = function ( scene, camera ) {
 
-		rectx1 = canvasWidth;
-		recty1 = canvasHeight;
+		rectx1 = Infinity;
+		recty1 = Infinity;
 		rectx2 = 0;
 		recty2 = 0;
 
@@ -64,7 +64,7 @@ THREE.SoftwareRenderer2 = function () {
 		var renderData = projector.projectScene( scene, camera );
 		var elements = renderData.elements;
 
-		elements.sort( painterSort );
+		elements.sort( numericalSort );
 
 		for ( var e = 0, el = elements.length; e < el; e ++ ) {
 
@@ -128,6 +128,13 @@ THREE.SoftwareRenderer2 = function () {
 		var width = Math.max( rectx2, prevrectx2 ) - x;
 		var height = Math.max( recty2, prevrecty2 ) - y;
 
+		/*
+		console.log( rectx1, recty1, rectx2, recty2 );
+		console.log( prevrectx1, prevrecty1, prevrectx2, prevrecty2 );
+		console.log( x, y, width, height );
+		console.log( canvasWidth, canvasHeight );
+		*/
+
 		context.putImageData( imagedata, 0, 0, x, y, width, height );
 
 		prevrectx1 = rectx1; prevrecty1 = recty1;
@@ -135,7 +142,7 @@ THREE.SoftwareRenderer2 = function () {
 
 	};
 
-	function painterSort( a, b ) {
+	function numericalSort( a, b ) {
 
 		return a.z - b.z;
 
@@ -156,16 +163,15 @@ THREE.SoftwareRenderer2 = function () {
 
 	function clearRectangle( x1, y1, x2, y2 ) {
 
-		var offset = 0;
-
 		var xmin = Math.max( Math.min( x1, x2 ), 0 );
 		var xmax = Math.min( Math.max( x1, x2 ), canvasWidth );
 		var ymin = Math.max( Math.min( y1, y2 ), 0 );
 		var ymax = Math.min( Math.max( y1, y2 ), canvasHeight );
 
-		for ( var y = ymin; y < ymax; y ++ ) {
+		var offset = ( xmin + ymin * canvasWidth ) * 4 + 3;
+		var linestep = ( canvasWidth - ( xmax - xmin ) ) * 4;
 
-			offset = ( xmin + y * canvasWidth ) * 4 + 3;
+		for ( var y = ymin; y < ymax; y ++ ) {
 
 			for ( var x = xmin; x < xmax; x ++ ) {
 
@@ -174,6 +180,8 @@ THREE.SoftwareRenderer2 = function () {
 
 			}
 
+			offset += linestep;
+
 		}
 
 	}
@@ -391,16 +399,6 @@ THREE.SoftwareRenderer2 = function () {
 
 	}
 
-	function computeDelta( x1, y1, z1, x2, y2, z2, x3, y3, z3 ) {
-
-		var A = (z3 - z1) * (y2 - y1) - (z2 - z1) * (y3 - y1);
-		var B = (x3 - x1) * (z2 - z1) - (x2 - x1) * (z3 - z1);
-		var C = (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1);
-
-		return [ - A / C, - B / C ];
-
-	}
-
 	function normalToComponent( normal ) {
 
 		var component = ( normal + 1 ) * 127;

+ 427 - 0
examples/js/renderers/SoftwareRenderer3.js

@@ -0,0 +1,427 @@
+/**
+ * @author mr.doob / http://mrdoob.com/
+ */
+
+THREE.SoftwareRenderer3 = function () {
+
+	console.log( 'THREE.SoftwareRenderer', THREE.REVISION );
+
+	var canvas = document.createElement( 'canvas' );
+	var context = canvas.getContext( '2d' );
+
+	var canvasWidth = canvas.width;
+	var canvasHeight = canvas.height;
+
+	var canvasWidthHalf = canvasWidth / 2;
+	var canvasHeightHalf = canvasHeight / 2;
+
+	var imagedata = context.getImageData( 0, 0, canvas.width, canvas.height );
+	var data = imagedata.data;
+
+	var blocksize = 8;
+
+	var canvasWBlocks = Math.floor( ( canvasWidth + blocksize - 1 ) / blocksize );
+	var canvasHBlocks = Math.floor( ( canvasHeight + blocksize - 1 ) / blocksize );
+
+	var block_full = new Uint8Array( canvasWBlocks * canvasHBlocks );
+
+	var rectx1 = Infinity, recty1 = Infinity;
+	var rectx2 = 0, recty2 = 0;
+
+	var prevrectx1 = Infinity, prevrecty1 = Infinity;
+	var prevrectx2 = 0, prevrecty2 = 0;
+
+	var projector = new THREE.Projector();
+
+	this.domElement = canvas;
+
+	this.autoClear = true;
+
+	this.setSize = function ( width, height ) {
+
+		canvas.width = width;
+		canvas.height = height;
+
+		canvasWidth = canvas.width;
+		canvasHeight = canvas.height;
+
+		canvasWidthHalf = width / 2;
+		canvasHeightHalf = height / 2;
+
+		imagedata = context.getImageData( 0, 0, width, height );
+		data = imagedata.data;
+
+		canvasWBlocks = Math.floor( ( canvasWidth + blocksize - 1 ) / blocksize );
+		canvasHBlocks = Math.floor( ( canvasHeight + blocksize - 1 ) / blocksize );
+
+		console.log( canvasWBlocks, canvasHBlocks );
+
+		block_full = new Uint8Array( canvasWBlocks * canvasHBlocks )
+
+	};
+
+	this.clear = function () {
+
+		clearRectangle( prevrectx1, prevrecty1, prevrectx2, prevrecty2 );
+
+		for ( var i = 0, l = block_full.length; i < l; i ++ ) {
+
+			block_full[ i ] = 0;
+
+		}
+
+	};
+
+	this.render = function ( scene, camera ) {
+
+		rectx1 = Infinity;
+		recty1 = Infinity;
+		rectx2 = 0;
+		recty2 = 0;
+
+		if ( this.autoClear ) this.clear();
+
+		var renderData = projector.projectScene( scene, camera );
+		var elements = renderData.elements;
+
+		elements.sort( numericalSort );
+
+		for ( var e = 0, el = elements.length; e < el; e ++ ) {
+
+			var element = elements[ e ];
+
+			if ( element instanceof THREE.RenderableFace3 ) {
+
+				var v1 = element.v1.positionScreen;
+				var v2 = element.v2.positionScreen;
+				var v3 = element.v3.positionScreen;
+
+				drawTriangle(
+					v1.x * canvasWidthHalf + canvasWidthHalf,
+					- v1.y * canvasHeightHalf + canvasHeightHalf,
+					v2.x * canvasWidthHalf + canvasWidthHalf,
+					- v2.y * canvasHeightHalf + canvasHeightHalf,
+					v3.x * canvasWidthHalf + canvasWidthHalf,
+					- v3.y * canvasHeightHalf + canvasHeightHalf,
+					normalToComponent( element.normalWorld.x ),
+					normalToComponent( element.normalWorld.y ),
+					normalToComponent( element.normalWorld.z )
+				)
+
+			} else if ( element instanceof THREE.RenderableFace4 ) {
+
+				var v1 = element.v1.positionScreen;
+				var v2 = element.v2.positionScreen;
+				var v3 = element.v3.positionScreen;
+				var v4 = element.v4.positionScreen;
+
+				drawTriangle(
+					v1.x * canvasWidthHalf + canvasWidthHalf,
+					- v1.y * canvasHeightHalf + canvasHeightHalf,
+					v2.x * canvasWidthHalf + canvasWidthHalf,
+					- v2.y * canvasHeightHalf + canvasHeightHalf,
+					v3.x * canvasWidthHalf + canvasWidthHalf,
+					- v3.y * canvasHeightHalf + canvasHeightHalf,
+					normalToComponent( element.normalWorld.x ),
+					normalToComponent( element.normalWorld.y ),
+					normalToComponent( element.normalWorld.z )
+				);
+
+				drawTriangle(
+					v3.x * canvasWidthHalf + canvasWidthHalf,
+					- v3.y * canvasHeightHalf + canvasHeightHalf,
+					v4.x * canvasWidthHalf + canvasWidthHalf,
+					- v4.y * canvasHeightHalf + canvasHeightHalf,
+					v1.x * canvasWidthHalf + canvasWidthHalf,
+					- v1.y * canvasHeightHalf + canvasHeightHalf,
+					normalToComponent( element.normalWorld.x ),
+					normalToComponent( element.normalWorld.y ),
+					normalToComponent( element.normalWorld.z )
+				);
+
+			}
+
+		}
+
+		var x = Math.min( rectx1, prevrectx1 );
+		var y = Math.min( recty1, prevrecty1 );
+		var width = Math.max( rectx2, prevrectx2 ) - x;
+		var height = Math.max( recty2, prevrecty2 ) - y;
+
+		context.putImageData( imagedata, 0, 0, x, y, width, height );
+
+		prevrectx1 = rectx1; prevrecty1 = recty1;
+		prevrectx2 = rectx2; prevrecty2 = recty2;
+
+	};
+
+	function numericalSort( a, b ) {
+
+		return a.z - b.z;
+
+	}
+
+	function drawPixel( x, y, r, g, b ) {
+
+		var offset = ( x + y * canvasWidth ) * 4;
+
+		if ( data[ offset + 3 ] ) return;
+
+		data[ offset ] = r;
+		data[ offset + 1 ] = g;
+		data[ offset + 2 ] = b;
+		data[ offset + 3 ] = 255;
+
+	}
+
+	function clearRectangle( x1, y1, x2, y2 ) {
+
+		var xmin = Math.max( Math.min( x1, x2 ), 0 );
+		var xmax = Math.min( Math.max( x1, x2 ), canvasWidth );
+		var ymin = Math.max( Math.min( y1, y2 ), 0 );
+		var ymax = Math.min( Math.max( y1, y2 ), canvasHeight );
+
+		var offset = ( xmin + ymin * canvasWidth ) * 4 + 3;
+		var linestep = ( canvasWidth - ( xmax - xmin ) ) * 4;
+
+		for ( var y = ymin; y < ymax; y ++ ) {
+
+			for ( var x = xmin; x < xmax; x ++ ) {
+
+				data[ offset ] = 0;
+				offset += 4;
+
+			}
+
+			offset += linestep;
+
+		}
+
+	}
+
+	function drawTriangle( x1, y1, x2, y2, x3, y3, r, g, b ) {
+
+		// https://gist.github.com/2486101
+		// explanation: ttp://pouet.net/topic.php?which=8760&page=1
+
+		// 28.4 fixed-point coordinates
+
+		var x1 = Math.round( 16 * x1 );
+		var x2 = Math.round( 16 * x2 );
+		var x3 = Math.round( 16 * x3 );
+
+		var y1 = Math.round( 16 * y1 );
+		var y2 = Math.round( 16 * y2 );
+		var y3 = Math.round( 16 * y3 );
+
+		// Deltas
+
+		var dx12 = x1 - x2, dy12 = y2 - y1;
+		var dx23 = x2 - x3, dy23 = y3 - y2;
+		var dx31 = x3 - x1, dy31 = y1 - y3;
+
+		// Bounding rectangle
+
+		var minx = Math.max( ( Math.min( x1, x2, x3 ) + 0xf ) >> 4, 0 );
+		var maxx = Math.min( ( Math.max( x1, x2, x3 ) + 0xf ) >> 4, canvasWidth );
+		var miny = Math.max( ( Math.min( y1, y2, y3 ) + 0xf ) >> 4, 0 );
+		var maxy = Math.min( ( Math.max( y1, y2, y3 ) + 0xf ) >> 4, canvasHeight );
+
+		rectx1 = Math.min( minx, rectx1 );
+		rectx2 = Math.max( maxx, rectx2 );
+		recty1 = Math.min( miny, recty1 );
+		recty2 = Math.max( maxy, recty2 );
+
+		// Block size, standard 8x8 (must be power of two)
+
+		var q = blocksize;
+
+		// Start in corner of 8x8 block
+
+		minx &= ~(q - 1);
+		miny &= ~(q - 1);
+
+		// Constant part of half-edge functions
+
+		var c1 = dy12 * ((minx << 4) - x1) + dx12 * ((miny << 4) - y1);
+		var c2 = dy23 * ((minx << 4) - x2) + dx23 * ((miny << 4) - y2);
+		var c3 = dy31 * ((minx << 4) - x3) + dx31 * ((miny << 4) - y3);
+
+		// Correct for fill convention
+
+		if ( dy12 > 0 || ( dy12 == 0 && dx12 > 0 ) ) c1 ++;
+		if ( dy23 > 0 || ( dy23 == 0 && dx23 > 0 ) ) c2 ++;
+		if ( dy31 > 0 || ( dy31 == 0 && dx31 > 0 ) ) c3 ++;
+
+		// Note this doesn't kill subpixel precision, but only because we test for >=0 (not >0).
+		// It's a bit subtle. :)
+		c1 = (c1 - 1) >> 4;
+		c2 = (c2 - 1) >> 4;
+		c3 = (c3 - 1) >> 4;
+
+		// Set up min/max corners
+		var qm1 = q - 1; // for convenience
+		var nmin1 = 0, nmax1 = 0;
+		var nmin2 = 0, nmax2 = 0;
+		var nmin3 = 0, nmax3 = 0;
+		if (dx12 >= 0) nmax1 -= qm1*dx12; else nmin1 -= qm1*dx12;
+		if (dy12 >= 0) nmax1 -= qm1*dy12; else nmin1 -= qm1*dy12;
+		if (dx23 >= 0) nmax2 -= qm1*dx23; else nmin2 -= qm1*dx23;
+		if (dy23 >= 0) nmax2 -= qm1*dy23; else nmin2 -= qm1*dy23;
+		if (dx31 >= 0) nmax3 -= qm1*dx31; else nmin3 -= qm1*dx31;
+		if (dy31 >= 0) nmax3 -= qm1*dy31; else nmin3 -= qm1*dy31;
+
+		// Loop through blocks
+		var linestep = (canvasWidth - q) * 4;
+		var scale = 255.0 / (c1 + c2 + c3);
+
+		var cb1 = c1;
+		var cb2 = c2;
+		var cb3 = c3;
+		var qstep = -q;
+		var e1x = qstep * dy12;
+		var e2x = qstep * dy23;
+		var e3x = qstep * dy31;
+		var x0 = minx;
+
+		for (var y0 = miny; y0 < maxy; y0 += q) {
+
+			// New block line - keep hunting for tri outer edge in old block line dir
+			while (x0 >= minx && x0 < maxx && cb1 >= nmax1 && cb2 >= nmax2 && cb3 >= nmax3) {
+
+				x0 += qstep;
+				cb1 += e1x;
+				cb2 += e2x;
+				cb3 += e3x;
+
+			}
+
+			// Okay, we're now in a block we know is outside. Reverse direction and go into main loop.
+			qstep = -qstep;
+			e1x = -e1x;
+			e2x = -e2x;
+			e3x = -e3x;
+
+			while (1) {
+
+				// Step everything
+				x0 += qstep;
+				cb1 += e1x;
+				cb2 += e2x;
+				cb3 += e3x;
+
+				// We're done with this block line when at least one edge completely out
+				// If an edge function is too small and decreasing in the current traversal
+				// dir, we're done with this line.
+				if (x0 < minx || x0 >= maxx) break;
+				if (cb1 < nmax1) if (e1x < 0) break; else continue;
+				if (cb2 < nmax2) if (e2x < 0) break; else continue;
+				if (cb3 < nmax3) if (e3x < 0) break; else continue;
+
+				// We can skip this block if it's already fully covered
+				var blockX = (x0 / q) | 0;
+				var blockY = (y0 / q) | 0;
+				var blockInd = blockX + blockY * canvasWBlocks;
+				if (block_full[blockInd]) continue;
+
+				// Offset at top-left corner
+				var offset = (x0 + y0 * canvasWidth) * 4;
+
+				// Accept whole block when fully covered
+				if (cb1 >= nmin1 && cb2 >= nmin2 && cb3 >= nmin3) {
+
+					var cy1 = cb1;
+					var cy2 = cb2;
+
+					for ( var iy = 0; iy < q; iy ++ ) {
+
+						var cx1 = cy1;
+						var cx2 = cy2;
+
+						for ( var ix = 0; ix < q; ix ++ ) {
+
+							if (!data[offset + 3]) {
+
+								var u = cx1 * scale; // 0-255!
+								var v = cx2 * scale; // 0-255!
+								data[offset] = u;
+								data[offset + 1] = v;
+								data[offset + 2] = 0;
+								data[offset + 3] = 255;
+
+							}
+
+							cx1 += dy12;
+							cx2 += dy23;
+							offset += 4;
+
+						}
+
+						cy1 += dx12;
+						cy2 += dx23;
+						offset += linestep;
+
+					}
+
+					block_full[blockInd] = 1;
+
+				} else { // Partially covered block
+
+					var cy1 = cb1;
+					var cy2 = cb2;
+					var cy3 = cb3;
+
+					for ( var iy = 0; iy < q; iy ++ ) {
+
+						var cx1 = cy1;
+						var cx2 = cy2;
+						var cx3 = cy3;
+
+						for ( var ix = 0; ix < q; ix ++ ) {
+
+							if ( (cx1 | cx2 | cx3) >= 0 && !data[offset+3]) {
+
+								var u = cx1 * scale; // 0-255!
+								var v = cx2 * scale; // 0-255!
+								data[offset] = u;
+								data[offset + 1] = v; 
+								data[offset + 2] = 0;
+								data[offset + 3] = 255;
+
+							}
+
+							cx1 += dy12;
+							cx2 += dy23;
+							cx3 += dy31;
+							offset += 4;
+
+						}
+
+						cy1 += dx12;
+						cy2 += dx23;
+						cy3 += dx31;
+						offset += linestep;
+
+					}
+
+				}
+
+			}
+
+			// Advance to next row of blocks
+			cb1 += q*dx12;
+			cb2 += q*dx23;
+			cb3 += q*dx31;
+
+		}
+
+	}
+
+	function normalToComponent( normal ) {
+
+		var component = ( normal + 1 ) * 127;
+		return component < 0 ? 0 : ( component > 255 ? 255 : component );
+
+	}
+
+};

+ 140 - 0
examples/misc_camera_orbit.html

@@ -0,0 +1,140 @@
+<!doctype html>
+<html lang="en">
+	<head>
+		<title>three.js webgl - orbit camera</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<style>
+			body {
+				color: #000;
+				font-family:Monospace;
+				font-size:13px;
+				text-align:center;
+				font-weight: bold;
+
+				background-color: #fff;
+				margin: 0px;
+				overflow: hidden;
+			}
+
+			#info {
+				color:#000;
+				position: absolute;
+				top: 0px; width: 100%;
+				padding: 5px;
+
+			}
+
+			a {
+				color: red;
+			}
+		</style>
+	</head>
+
+	<body>
+		<div id="container"></div>
+		<div id="info">
+			<a href="http://github.com/mrdoob/three.js" target="_blank">three.js</a> - orbit camera example
+		</div>
+
+		<script src="../build/Three.js"></script>
+
+		<script src="js/Detector.js"></script>
+		<script src="js/Stats.js"></script>
+
+		<script>
+
+			if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
+
+			var container, stats;
+
+			var camera, controls, scene, renderer;
+
+			var cross;
+
+			init();
+			animate();
+
+			function init() {
+
+				// scene and camera
+
+				scene = new THREE.Scene();
+				scene.fog = new THREE.FogExp2( 0xcccccc, 0.002 );
+
+				camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 1000 );
+				camera.position.z = 500;
+
+				scene.add( camera );
+
+				controls = new THREE.OrbitControls( camera );
+				controls.addEventListener( 'change', render );
+
+				// world
+
+				var geometry = new THREE.CylinderGeometry( 0, 10, 30, 4, 1 );
+				var material =  new THREE.MeshLambertMaterial( { color:0xffffff, shading: THREE.FlatShading } );
+
+				for ( var i = 0; i < 500; i ++ ) {
+
+					var mesh = new THREE.Mesh( geometry, material );
+					mesh.position.x = ( Math.random() - 0.5 ) * 1000;
+					mesh.position.y = ( Math.random() - 0.5 ) * 1000;
+					mesh.position.z = ( Math.random() - 0.5 ) * 1000;
+					mesh.updateMatrix();
+					mesh.matrixAutoUpdate = false;
+					scene.add( mesh );
+
+				}
+
+
+				// lights
+
+				light = new THREE.DirectionalLight( 0xffffff );
+				light.position.set( 1, 1, 1 );
+				scene.add( light );
+
+				light = new THREE.DirectionalLight( 0x002288 );
+				light.position.set( -1, -1, -1 );
+				scene.add( light );
+
+				light = new THREE.AmbientLight( 0x222222 );
+				scene.add( light );
+
+
+				// renderer
+
+				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer.setClearColor( scene.fog.color, 1 );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+				container = document.getElementById( 'container' );
+				container.appendChild( renderer.domElement );
+
+				stats = new Stats();
+				stats.domElement.style.position = 'absolute';
+				stats.domElement.style.top = '0px';
+				stats.domElement.style.zIndex = 100;
+				container.appendChild( stats.domElement );
+
+			}
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+				controls.update();
+
+			}
+
+			function render() {
+
+				renderer.render( scene, camera );
+				stats.update();
+
+			}
+
+
+		</script>
+
+	</body>
+</html>

+ 20 - 19
examples/misc_camera_trackball.html

@@ -5,28 +5,29 @@
 		<meta charset="utf-8">
 		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
 		<style>
-		    body {
-			color: #000;
-			font-family:Monospace;
-			font-size:13px;
-			text-align:center;
-			font-weight: bold;
-
-			background-color: #fff;
-			margin: 0px;
-			overflow: hidden;
-		    }
-
-		    #info {
-					color:#000;
-			position: absolute;
-			top: 0px; width: 100%;
-			padding: 5px;
+			body {
+				color: #000;
+				font-family:Monospace;
+				font-size:13px;
+				text-align:center;
+				font-weight: bold;
+
+				background-color: #fff;
+				margin: 0px;
+				overflow: hidden;
+			}
 
-		    }
+			#info {
+				color:#000;
+				position: absolute;
+				top: 0px; width: 100%;
+				padding: 5px;
 
-		    a { color: red; }
+			}
 
+			a {
+				color: red;
+			}
 		</style>
 	</head>
 

+ 3 - 1
examples/misc_software.html

@@ -18,6 +18,7 @@
 		<script src="../build/Three.js"></script>
 		<script src="js/renderers/SoftwareRenderer.js"></script>
 		<script src="js/renderers/SoftwareRenderer2.js"></script>
+		<script src="js/renderers/SoftwareRenderer3.js"></script>
 		<script src="js/Stats.js"></script>
 
 		<script>
@@ -32,6 +33,7 @@
 
 			init();
 			animate();
+			// render();
 
 			function init() {
 
@@ -50,7 +52,7 @@
 
 				camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 10000 );
 				camera.position.y = 150;
-				camera.position.z = 500;
+				camera.position.z = 600;
 				scene.add( camera );
 
 				controls = new THREE.TrackballControls( camera );

+ 111 - 0
examples/misc_uv_tests.html

@@ -0,0 +1,111 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8 />
+<title>three.js - uv mapping tests</title>
+<style>
+  article, aside, figure, footer, header, hgroup, 
+  menu, nav, section { display: block; }
+</style>
+  <script src="../build/Three.js"></script>
+  <script src="js/UVsUtils.js"></script>
+
+</head>
+<body>
+  <b id="hello">Doing UV wrap tests here!</b>
+  <i>Please wait while it loads</i>
+  <script>
+/* 
+ * This is to help debug UVs problems in geometry, 
+ * as well as allow a new user to visualize what UVs are about. 
+ */
+
+
+function test(name, geometry) {
+  
+  var d = document.createElement('div');
+  d.innerHTML = '<br><br>' + name + '<br>';
+  d.appendChild(THREE.UVsDebug(geometry));
+  document.body.appendChild(d);
+  
+}
+
+
+test('new THREE.PlaneGeometry( 100, 100, 4, 4 )', new THREE.PlaneGeometry( 100, 100, 4, 4 ));
+test('new THREE.SphereGeometry( 75, 12, 6 )', new THREE.SphereGeometry( 75, 12, 6 ));
+
+test('new THREE.IcosahedronGeometry( 30, 1 )', new THREE.IcosahedronGeometry( 30, 1 ));
+test('new THREE.OctahedronGeometry( 30, 2 )', new THREE.OctahedronGeometry( 30, 2 ));
+
+test('new THREE.CylinderGeometry( 25, 75, 100, 10, 5 )', new THREE.CylinderGeometry( 25, 75, 100, 10, 5 ));
+
+test('new THREE.CubeGeometry( 100, 100, 100, 4, 4, 4 )', new THREE.CubeGeometry( 100, 100, 100, 4, 4, 4 ));
+
+var points = [];
+
+for ( var i = 0; i < 10; i ++ ) {
+
+    points.push( new THREE.Vector3( Math.sin( i * 0.2 ) * 15 + 50, 0, ( i - 5 ) * 2 ) );
+
+}
+
+
+test('new THREE.LatheGeometry( points, 8 )', new THREE.LatheGeometry( points, 8 ));
+test('new THREE.TorusGeometry( 50, 20, 8, 8 )', new THREE.TorusGeometry( 50, 20, 8, 8 ));
+test('new THREE.TorusKnotGeometry( 50, 10, 12, 6 )', new THREE.TorusKnotGeometry( 50, 10, 12, 6 ));
+
+/*
+Not sure how UVs for ExtrudeGeometry are done currently...
+*/
+
+var pts = [], starPoints = 5, l;
+for (i=0; i<starPoints*2;i++) {
+  if (i%2==1) {
+    l = 5;
+  } else {
+    l = 10;
+  }
+
+  var a = i / starPoints * Math.PI;
+  pts.push(new THREE.Vector2(Math.cos(a) * l,Math.sin(a) * l ));
+}
+var starShape = new THREE.Shape(pts);
+var extrudeSettings = { amount: 200,  bevelEnabled: true, bevelSegments: 2, steps: 10 }; 
+
+test('new THREE.ExtrudeGeometry(starShape, extrudeSettings);', new THREE.ExtrudeGeometry(starShape, extrudeSettings));
+
+var uvGenerator = new THREE.UVsUtils.CylinderUVGenerator();
+		testShape = setupShape(8, 3);
+		holeShape = setupShape(8, 2);
+		testShape.holes.push(holeShape);
+
+function setupShape(n, r) {
+		// Make shape
+		var sh = new THREE.Shape();
+		for (var i = 0; i < n;i++) {
+			var method = i ? 'lineTo' : 'moveTo';
+			var a = (i/n) * Math.PI * 2;
+			var x = Math.cos(a) * r;
+			var y = Math.sin(a) * r;
+			sh[method](x, y);
+		}
+
+		return sh;
+	}
+
+var exoption = {
+	bevelEnabled: true,
+	bevelSize: 1,
+	amount: 3,
+	extrudeMaterial: 0,
+	material: 1,
+	uvGenerator: uvGenerator
+};
+
+var geom = testShape.extrude(exoption);
+test('new THREE.ExtrudeGeometry with CylinderUVGenerator;', geom);
+
+
+  </script>
+</body>
+</html>

+ 163 - 0
examples/webgl_geometry_convex.html

@@ -0,0 +1,163 @@
+<!doctype html>
+<html lang="en">
+	<head>
+		<title>three.js webgl - convex geometry</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<style>
+			body {
+				font-family: Monospace;
+				background-color: #000;
+				margin: 0px;
+				overflow: hidden;
+			}
+		</style>
+	</head>
+	<body>
+
+		<script src="../build/Three.js"></script>
+		<script src="js/Detector.js"></script>
+		<script src="js/Stats.js"></script>
+
+		<script>
+
+			if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
+
+			var container, stats;
+
+			var camera, scene, renderer;
+
+			init();
+			animate();
+
+			function init() {
+
+				container = document.createElement( 'div' );
+				document.body.appendChild( container );
+
+				scene = new THREE.Scene();
+
+				camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2000 );
+				camera.position.y = 400;
+				scene.add( camera );
+
+				var light, object, materials;
+
+				scene.add( new THREE.AmbientLight( 0x404040 ) );
+
+				light = new THREE.DirectionalLight( 0xffffff );
+				light.position.set( 0, 1, 0 );
+				scene.add( light );
+
+				materials = [
+					new THREE.MeshLambertMaterial( { ambient: 0xbbbbbb, map: THREE.ImageUtils.loadTexture( 'textures/ash_uvgrid01.jpg' ) } ),
+					new THREE.MeshBasicMaterial( { color: 0xffffff, wireframe: true, transparent: true, opacity: 0.1 } )
+				];
+
+
+				// tetrahedron
+				var points = [
+					new THREE.Vector3( 100, 0, 0 ),
+					new THREE.Vector3( 0, 100, 0 ),
+					new THREE.Vector3( 0, 0, 100 ),
+					new THREE.Vector3( 0, 0, 0 )
+				];
+
+				object = THREE.SceneUtils.createMultiMaterialObject( new THREE.ConvexGeometry( points ), materials );
+				object.position.set( 0, 0, 0 );
+				scene.add( object );
+
+				// cube
+				var points = [
+					new THREE.Vector3( 50, 50, 50 ),
+					new THREE.Vector3( 50, 50, -50 ),
+					new THREE.Vector3( -50, 50, -50 ),
+					new THREE.Vector3( -50, 50, 50 ),
+					new THREE.Vector3( 50, -50, 50 ),
+					new THREE.Vector3( 50, -50, -50 ),
+					new THREE.Vector3( -50, -50, -50 ),
+					new THREE.Vector3( -50, -50, 50 ),
+				];
+
+				object = THREE.SceneUtils.createMultiMaterialObject( new THREE.ConvexGeometry( points ), materials );
+				object.position.set( -200, 0, -200 );
+				scene.add( object );
+
+				// random convex
+				points = [];
+				for ( var i = 0; i < 30; i++ ) {
+					points.push( randomPointInSphere( 50 ) );
+				}
+
+				object = THREE.SceneUtils.createMultiMaterialObject( new THREE.ConvexGeometry( points ), materials );
+				object.position.set( -200, 0, 200 );
+				scene.add( object );
+
+
+				object = new THREE.AxisHelper();
+				object.position.set( 200, 0, -200 );
+				object.scale.x = object.scale.y = object.scale.z = 0.5;
+				scene.add( object );
+
+				object = new THREE.ArrowHelper( new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( 0, 0, 0 ), 50 );
+				object.position.set( 200, 0, 400 );
+				scene.add( object );
+
+				renderer = new THREE.WebGLRenderer( { antialias: true } );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+				container.appendChild( renderer.domElement );
+
+				stats = new Stats();
+				stats.domElement.style.position = 'absolute';
+				stats.domElement.style.top = '0px';
+				container.appendChild( stats.domElement );
+
+			}
+
+
+			function randomPointInSphere( radius ) {
+
+				return new THREE.Vector3( 
+					( Math.random() - 0.5 ) * 2 * radius,
+					( Math.random() - 0.5 ) * 2 * radius,
+					( Math.random() - 0.5 ) * 2 * radius
+				);
+
+			}
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+
+				render();
+				stats.update();
+
+			}
+
+			function render() {
+
+				var timer = Date.now() * 0.0001;
+
+				camera.position.x = Math.cos( timer ) * 800;
+				camera.position.z = Math.sin( timer ) * 800;
+
+				camera.lookAt( scene.position );
+
+				for ( var i = 0, l = scene.children.length; i < l; i ++ ) {
+
+					var object = scene.children[ i ];
+
+					object.rotation.x += 0.01;
+					object.rotation.y += 0.005;
+
+				}
+
+				renderer.render( scene, camera );
+
+			}
+
+		</script>
+
+	</body>
+</html>

+ 276 - 276
examples/webgl_geometry_extrude_splines.html

@@ -1,394 +1,394 @@
 
 <!doctype html>
 <html lang="en">
-  <head>
-    <title>three.js webgl - geometry - shapes</title>
-    <meta charset="utf-8">
-    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
-    <style>
-      body {
-        font-family: Monospace;
-        background-color: #f0f0f0;
-        margin: 0px;
-        overflow: hidden;
-      }
-    </style>
-  </head>
-  <body>
-  
-    <script src="../build/Three.js"></script>
-    <script src="../src/extras/core/Curve.js"></script>
-    <script src="../src/extras/geometries/TubeGeometry.js"></script>
-    <script src="../src/extras/helpers/CameraHelper.js"></script>
-
-    <!-- where curves formulas are defined -->
-    <script src="js/CurveExtras.js"></script>
-
-    <script src="js/Stats.js"></script>
-
-
-    <script>
-    var container, stats;
+	<head>
+		<title>three.js webgl - geometry - shapes</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<style>
+			body {
+				font-family: Monospace;
+				background-color: #f0f0f0;
+				margin: 0px;
+				overflow: hidden;
+			}
+		</style>
+	</head>
+	<body>
+	
+		<script src="../build/Three.js"></script>
+		<script src="../src/extras/core/Curve.js"></script>
+		<script src="../src/extras/geometries/TubeGeometry.js"></script>
+		<script src="../src/extras/helpers/CameraHelper.js"></script>
+
+		<!-- where curves formulas are defined -->
+		<script src="js/CurveExtras.js"></script>
+
+		<script src="js/Stats.js"></script>
+
+
+		<script>
+		var container, stats;
 
-    var camera, scene, renderer, splineCamera, cameraHelper, cameraEye;
+		var camera, scene, renderer, splineCamera, cameraHelper, cameraEye;
 
-    var text, plane;
+		var text, plane;
 
-    var targetRotation = 0;
-    var targetRotationOnMouseDown = 0;
+		var targetRotation = 0;
+		var targetRotationOnMouseDown = 0;
 
-    var mouseX = 0;
-    var mouseXOnMouseDown = 0;
+		var mouseX = 0;
+		var mouseXOnMouseDown = 0;
 
-    var windowHalfX = window.innerWidth / 2;
-    var windowHalfY = window.innerHeight / 2;
-
-    var binormal = new THREE.Vector3();
-    var normal = new THREE.Vector3();
-
-
-    var pipeSpline = new THREE.SplineCurve3([
-        new THREE.Vector3(0, 10, -10), new THREE.Vector3(10, 0, -10), new THREE.Vector3(20, 0, 0), new THREE.Vector3(30, 0, 10), new THREE.Vector3(30, 0, 20), new THREE.Vector3(20, 0, 30), new THREE.Vector3(10, 0, 30), new THREE.Vector3(0, 0, 30), new THREE.Vector3(-10, 10, 30), new THREE.Vector3(-10, 20, 30), new THREE.Vector3(0, 30, 30), new THREE.Vector3(10, 30, 30), new THREE.Vector3(20, 30, 15), new THREE.Vector3(10, 30, 10), new THREE.Vector3(0, 30, 10), new THREE.Vector3(-10, 20, 10), new THREE.Vector3(-10, 10, 10), new THREE.Vector3(0, 0, 10), new THREE.Vector3(10, -10, 10), new THREE.Vector3(20, -15, 10), new THREE.Vector3(30, -15, 10), new THREE.Vector3(40, -15, 10), new THREE.Vector3(50, -15, 10), new THREE.Vector3(60, 0, 10), new THREE.Vector3(70, 0, 0), new THREE.Vector3(80, 0, 0), new THREE.Vector3(90, 0, 0), new THREE.Vector3(100, 0, 0)]);
-
-    var sampleClosedSpline = new THREE.ClosedSplineCurve3([
-      new THREE.Vector3(0, -40, -40),
-      new THREE.Vector3(0, 40, -40),
-      new THREE.Vector3(0, 140, -40),
-      new THREE.Vector3(0, 40, 40),
-      new THREE.Vector3(0, -40, 40),
-    ]);
+		var windowHalfX = window.innerWidth / 2;
+		var windowHalfY = window.innerHeight / 2;
+
+		var binormal = new THREE.Vector3();
+		var normal = new THREE.Vector3();
+
+
+		var pipeSpline = new THREE.SplineCurve3([
+				new THREE.Vector3(0, 10, -10), new THREE.Vector3(10, 0, -10), new THREE.Vector3(20, 0, 0), new THREE.Vector3(30, 0, 10), new THREE.Vector3(30, 0, 20), new THREE.Vector3(20, 0, 30), new THREE.Vector3(10, 0, 30), new THREE.Vector3(0, 0, 30), new THREE.Vector3(-10, 10, 30), new THREE.Vector3(-10, 20, 30), new THREE.Vector3(0, 30, 30), new THREE.Vector3(10, 30, 30), new THREE.Vector3(20, 30, 15), new THREE.Vector3(10, 30, 10), new THREE.Vector3(0, 30, 10), new THREE.Vector3(-10, 20, 10), new THREE.Vector3(-10, 10, 10), new THREE.Vector3(0, 0, 10), new THREE.Vector3(10, -10, 10), new THREE.Vector3(20, -15, 10), new THREE.Vector3(30, -15, 10), new THREE.Vector3(40, -15, 10), new THREE.Vector3(50, -15, 10), new THREE.Vector3(60, 0, 10), new THREE.Vector3(70, 0, 0), new THREE.Vector3(80, 0, 0), new THREE.Vector3(90, 0, 0), new THREE.Vector3(100, 0, 0)]);
+
+		var sampleClosedSpline = new THREE.ClosedSplineCurve3([
+			new THREE.Vector3(0, -40, -40),
+			new THREE.Vector3(0, 40, -40),
+			new THREE.Vector3(0, 140, -40),
+			new THREE.Vector3(0, 40, 40),
+			new THREE.Vector3(0, -40, 40),
+		]);
 
-    // Keep a diction of Curve instances
-    var splines = {
-      GrannyKnot: new THREE.Curves.GrannyKnot(),
-      HeartCurve: new THREE.Curves.HeartCurve(3.5),
-      VivianiCurve: new THREE.Curves.VivianiCurve(70),
-      KnotCurve: new THREE.Curves.KnotCurve(),
-      HelixCurve: new THREE.Curves.HelixCurve(),
-      TrefoilKnot: new THREE.Curves.TrefoilKnot(),
-      TorusKnot: new THREE.Curves.TorusKnot(20),
-      CinquefoilKnot: new THREE.Curves.CinquefoilKnot(20),
-      TrefoilPolynomialKnot: new THREE.Curves.TrefoilPolynomialKnot(14),
-      FigureEightPolynomialKnot: new THREE.Curves.FigureEightPolynomialKnot(),
-      DecoratedTorusKnot4a: new THREE.Curves.DecoratedTorusKnot4a(),
-      DecoratedTorusKnot4b: new THREE.Curves.DecoratedTorusKnot4b(),
-      DecoratedTorusKnot5a: new THREE.Curves.DecoratedTorusKnot5a(),
-      DecoratedTorusKnot5c: new THREE.Curves.DecoratedTorusKnot5c(),
-      PipeSpline: pipeSpline,
-      SampleClosedSpline: sampleClosedSpline
-    };
+		// Keep a dictionary of Curve instances
+		var splines = {
+			GrannyKnot: new THREE.Curves.GrannyKnot(),
+			HeartCurve: new THREE.Curves.HeartCurve(3.5),
+			VivianiCurve: new THREE.Curves.VivianiCurve(70),
+			KnotCurve: new THREE.Curves.KnotCurve(),
+			HelixCurve: new THREE.Curves.HelixCurve(),
+			TrefoilKnot: new THREE.Curves.TrefoilKnot(),
+			TorusKnot: new THREE.Curves.TorusKnot(20),
+			CinquefoilKnot: new THREE.Curves.CinquefoilKnot(20),
+			TrefoilPolynomialKnot: new THREE.Curves.TrefoilPolynomialKnot(14),
+			FigureEightPolynomialKnot: new THREE.Curves.FigureEightPolynomialKnot(),
+			DecoratedTorusKnot4a: new THREE.Curves.DecoratedTorusKnot4a(),
+			DecoratedTorusKnot4b: new THREE.Curves.DecoratedTorusKnot4b(),
+			DecoratedTorusKnot5a: new THREE.Curves.DecoratedTorusKnot5a(),
+			DecoratedTorusKnot5c: new THREE.Curves.DecoratedTorusKnot5c(),
+			PipeSpline: pipeSpline,
+			SampleClosedSpline: sampleClosedSpline
+		};
 
 
 
 
-    extrudePath = new THREE.Curves.TrefoilKnot();
+		extrudePath = new THREE.Curves.TrefoilKnot();
 
-    var dropdown = '<select id="dropdown" onchange="addTube(this.value)">';
+		var dropdown = '<select id="dropdown" onchange="addTube(this.value)">';
 
-    var s;
-    for ( s in splines ) {
-      dropdown += '<option value="' + s + '"';
-      dropdown += '>' + s + '</option>';
-    }
+		var s;
+		for ( s in splines ) {
+			dropdown += '<option value="' + s + '"';
+			dropdown += '>' + s + '</option>';
+		}
 
-    dropdown += '</select>';
+		dropdown += '</select>';
 
-    var closed2 = true;
-    var debug = true;
-    var parent;
-    var tube, tubeMesh;
-    var animation = false, lookAhead = false;
-    var scale;
-    var showCameraHelper = false;
+		var closed2 = true;
+		var debug = true;
+		var parent;
+		var tube, tubeMesh;
+		var animation = false, lookAhead = false;
+		var scale;
+		var showCameraHelper = false;
 
-    function addTube() {
+		function addTube() {
 
-      var value = document.getElementById('dropdown').value;
-      
-      var segments = parseInt(document.getElementById('segments').value);
-      closed2 = document.getElementById('closed').checked;
-      debug = document.getElementById('debug').checked;
+			var value = document.getElementById('dropdown').value;
+			
+			var segments = parseInt(document.getElementById('segments').value);
+			closed2 = document.getElementById('closed').checked;
+			debug = document.getElementById('debug').checked;
 
-      var radiusSegments = parseInt(document.getElementById('radiusSegments').value);
+			var radiusSegments = parseInt(document.getElementById('radiusSegments').value);
 
-      console.log('adding tube', value, closed2, debug, radiusSegments);
-      if (tubeMesh) parent.remove(tubeMesh);
+			console.log('adding tube', value, closed2, debug, radiusSegments);
+			if (tubeMesh) parent.remove(tubeMesh);
 
-      extrudePath = splines[value];
-      
-      tube = new THREE.TubeGeometry(extrudePath, segments, 2, radiusSegments, closed2, debug);
+			extrudePath = splines[value];
+			
+			tube = new THREE.TubeGeometry(extrudePath, segments, 2, radiusSegments, closed2, debug);
 
-      addGeometry(tube, 0xff00ff);
-      setScale();
-    
-    }
+			addGeometry(tube, 0xff00ff);
+			setScale();
+		
+		}
 
-    function setScale() {
+		function setScale() {
 
-      scale = parseInt(document.getElementById('scale').value);
-      tubeMesh.scale.set(scale, scale, scale);
+			scale = parseInt(document.getElementById('scale').value);
+			tubeMesh.scale.set(scale, scale, scale);
 
-    }
+		}
 
 
-    function addGeometry(geometry, color) {
+		function addGeometry(geometry, color) {
 
-        // 3d shape
-        tubeMesh = THREE.SceneUtils.createMultiMaterialObject(geometry, [
-          new THREE.MeshLambertMaterial({
-              color: color,
-              opacity: (geometry.debug) ? 0.2 : 0.8,
-              transparent: true
-          }),
-         new THREE.MeshBasicMaterial({
-            color: 0x000000,
-            opacity: 0.5,
-            wireframe: true
-        })]);
+				// 3d shape
+				tubeMesh = THREE.SceneUtils.createMultiMaterialObject(geometry, [
+					new THREE.MeshLambertMaterial({
+							color: color,
+							opacity: (geometry.debug) ? 0.2 : 0.8,
+							transparent: true
+					}),
+				 new THREE.MeshBasicMaterial({
+						color: 0x000000,
+						opacity: 0.5,
+						wireframe: true
+				})]);
 
-        if (geometry.debug) tubeMesh.add(geometry.debug);
+				if (geometry.debug) tubeMesh.add(geometry.debug);
 
-        //mesh.children[0].doubleSided = true;
-        parent.add(tubeMesh);
+				//mesh.children[0].doubleSided = true;
+				parent.add(tubeMesh);
 
-    }
+		}
 
-    function animateCamera(toggle) {
+		function animateCamera(toggle) {
 
-      if (toggle) {
-        animation = !animation;
-        document.getElementById('animation').value = 'Camera Spline Animation View: ' + (animation? 'ON': 'OFF');
-      }
-      
-      lookAhead = document.getElementById('lookAhead').checked;
+			if (toggle) {
+				animation = !animation;
+				document.getElementById('animation').value = 'Camera Spline Animation View: ' + (animation? 'ON': 'OFF');
+			}
+			
+			lookAhead = document.getElementById('lookAhead').checked;
 
-      showCameraHelper = document.getElementById('cameraHelper').checked;
+			showCameraHelper = document.getElementById('cameraHelper').checked;
 
-      cameraHelper.children[0].visible = showCameraHelper;
-      cameraEye.visible = showCameraHelper;
-    }
+			cameraHelper.children[0].visible = showCameraHelper;
+			cameraEye.visible = showCameraHelper;
+		}
 
 
-    init();
-    animate();
+		init();
+		animate();
 
-    function init() {
+		function init() {
 
-      container = document.createElement('div');
-      document.body.appendChild(container);
+			container = document.createElement('div');
+			document.body.appendChild(container);
 
-      var info = document.createElement('div');
-      info.style.position = 'absolute';
-      info.style.top = '10px';
-      info.style.width = '100%';
-      info.style.textAlign = 'center';
-      info.innerHTML = 'Spline Extrusion Examples by <a href="http://www.lab4games.net/zz85/blog">zz85</a><br/>Select spline:';
+			var info = document.createElement('div');
+			info.style.position = 'absolute';
+			info.style.top = '10px';
+			info.style.width = '100%';
+			info.style.textAlign = 'center';
+			info.innerHTML = 'Spline Extrusion Examples by <a href="http://www.lab4games.net/zz85/blog">zz85</a><br/>Select spline:';
 
-      info.innerHTML += dropdown;
+			info.innerHTML += dropdown;
 
-      info.innerHTML += '<br/>Scale: <select id="scale" onchange="setScale()"><option>1</option><option>2</option><option selected>4</option><option>6</option><option>10</option></select>';
-      info.innerHTML += '<br/>Extrusion Segments: <select onchange="addTube()" id="segments"><option>50</option><option selected>100</option><option>200</option><option>400</option></select>';
-      info.innerHTML += '<br/>Radius Segments: <select id="radiusSegments" onchange="addTube()"><option>1</option><option>2</option><option selected>3</option><option>4</option><option>5</option><option>6</option><option>8</option><option>12</option></select>';
-      info.innerHTML += '<br/>Debug normals: <input id="debug" type="checkbox" onchange="addTube()"  /> Closed:<input id="closed" onchange="addTube()" type="checkbox" checked />';
+			info.innerHTML += '<br/>Scale: <select id="scale" onchange="setScale()"><option>1</option><option>2</option><option selected>4</option><option>6</option><option>10</option></select>';
+			info.innerHTML += '<br/>Extrusion Segments: <select onchange="addTube()" id="segments"><option>50</option><option selected>100</option><option>200</option><option>400</option></select>';
+			info.innerHTML += '<br/>Radius Segments: <select id="radiusSegments" onchange="addTube()"><option>1</option><option>2</option><option selected>3</option><option>4</option><option>5</option><option>6</option><option>8</option><option>12</option></select>';
+			info.innerHTML += '<br/>Debug normals: <input id="debug" type="checkbox" onchange="addTube()"  /> Closed:<input id="closed" onchange="addTube()" type="checkbox" checked />';
 
-      info.innerHTML += '<br/><br/><input id="animation" type="button" onclick="animateCamera(true)" value="Camera Spline Animation View: OFF"/><br/> Look Ahead <input id="lookAhead" type="checkbox" onchange="animateCamera()" /> Camera Helper <input id="cameraHelper" type="checkbox" onchange="animateCamera()" />';
+			info.innerHTML += '<br/><br/><input id="animation" type="button" onclick="animateCamera(true)" value="Camera Spline Animation View: OFF"/><br/> Look Ahead <input id="lookAhead" type="checkbox" onchange="animateCamera()" /> Camera Helper <input id="cameraHelper" type="checkbox" onchange="animateCamera()" />';
 
-      container.appendChild(info);
+			container.appendChild(info);
 
-      scene = new THREE.Scene();
+			scene = new THREE.Scene();
 
-      // 
-      camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.01, 1000);
-      splineCamera = new THREE.PerspectiveCamera(84, window.innerWidth / window.innerHeight, 0.01, 1000);
-      cameraHelper = new THREE.CameraHelper(splineCamera);
+			// 
+			camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.01, 1000);
+			splineCamera = new THREE.PerspectiveCamera(84, window.innerWidth / window.innerHeight, 0.01, 1000);
+			cameraHelper = new THREE.CameraHelper(splineCamera);
 
-      camera.position.set(0, 50, 500);
-      
-      scene.add(camera);
+			camera.position.set(0, 50, 500);
+			
+			scene.add(camera);
 
-      
-      var light = new THREE.DirectionalLight(0xffffff);
-      light.position.set(0, 0, 1);
-      scene.add(light);
+			
+			var light = new THREE.DirectionalLight(0xffffff);
+			light.position.set(0, 0, 1);
+			scene.add(light);
 
-      parent = new THREE.Object3D();
-      parent.position.y = 100;
-      scene.add(parent);
+			parent = new THREE.Object3D();
+			parent.position.y = 100;
+			scene.add(parent);
 
-      addTube();
+			addTube();
 
-      // Debug point
-      cameraEye = new THREE.Mesh(new THREE.SphereGeometry(5), new THREE.MeshBasicMaterial({
-          color: 0xdddddd
-      }));
+			// Debug point
+			cameraEye = new THREE.Mesh(new THREE.SphereGeometry(5), new THREE.MeshBasicMaterial({
+					color: 0xdddddd
+			}));
 
-      cameraHelper.children[0].visible = showCameraHelper;
-      cameraEye.visible = showCameraHelper;
+			cameraHelper.children[0].visible = showCameraHelper;
+			cameraEye.visible = showCameraHelper;
 
-      parent.add(cameraEye);
+			parent.add(cameraEye);
 
-      cameraHelper.scale.multiplyScalar(0.1);
-      splineCamera.add(cameraHelper);
-      parent.add(splineCamera);
+			cameraHelper.scale.multiplyScalar(0.1);
+			splineCamera.add(cameraHelper);
+			parent.add(splineCamera);
 
-      //
-      renderer = new THREE.WebGLRenderer({
-          antialias: true
-      });
-      renderer.setSize(window.innerWidth, window.innerHeight);
+			//
+			renderer = new THREE.WebGLRenderer({
+					antialias: true
+			});
+			renderer.setSize(window.innerWidth, window.innerHeight);
 
-      container.appendChild(renderer.domElement);
+			container.appendChild(renderer.domElement);
 
-      stats = new Stats();
-      stats.domElement.style.position = 'absolute';
-      stats.domElement.style.top = '0px';
-      container.appendChild(stats.domElement);
+			stats = new Stats();
+			stats.domElement.style.position = 'absolute';
+			stats.domElement.style.top = '0px';
+			container.appendChild(stats.domElement);
 
-      renderer.domElement.addEventListener('mousedown', onDocumentMouseDown, false);
-      renderer.domElement.addEventListener('touchstart', onDocumentTouchStart, false);
-      renderer.domElement.addEventListener('touchmove', onDocumentTouchMove, false);
+			renderer.domElement.addEventListener('mousedown', onDocumentMouseDown, false);
+			renderer.domElement.addEventListener('touchstart', onDocumentTouchStart, false);
+			renderer.domElement.addEventListener('touchmove', onDocumentTouchMove, false);
 
-    }
+		}
 
-    //
+		//
 
-    function onDocumentMouseDown(event) {
+		function onDocumentMouseDown(event) {
 
-      event.preventDefault();
+			event.preventDefault();
 
-      renderer.domElement.addEventListener('mousemove', onDocumentMouseMove, false);
-      renderer.domElement.addEventListener('mouseup', onDocumentMouseUp, false);
-      renderer.domElement.addEventListener('mouseout', onDocumentMouseOut, false);
+			renderer.domElement.addEventListener('mousemove', onDocumentMouseMove, false);
+			renderer.domElement.addEventListener('mouseup', onDocumentMouseUp, false);
+			renderer.domElement.addEventListener('mouseout', onDocumentMouseOut, false);
 
-      mouseXOnMouseDown = event.clientX - windowHalfX;
-      targetRotationOnMouseDown = targetRotation;
+			mouseXOnMouseDown = event.clientX - windowHalfX;
+			targetRotationOnMouseDown = targetRotation;
 
-    }
+		}
 
-    function onDocumentMouseMove(event) {
+		function onDocumentMouseMove(event) {
 
-      mouseX = event.clientX - windowHalfX;
+			mouseX = event.clientX - windowHalfX;
 
-      targetRotation = targetRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.02;
+			targetRotation = targetRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.02;
 
-    }
+		}
 
-    function onDocumentMouseUp(event) {
+		function onDocumentMouseUp(event) {
 
-      renderer.domElement.removeEventListener('mousemove', onDocumentMouseMove, false);
-      renderer.domElement.removeEventListener('mouseup', onDocumentMouseUp, false);
-      renderer.domElement.removeEventListener('mouseout', onDocumentMouseOut, false);
+			renderer.domElement.removeEventListener('mousemove', onDocumentMouseMove, false);
+			renderer.domElement.removeEventListener('mouseup', onDocumentMouseUp, false);
+			renderer.domElement.removeEventListener('mouseout', onDocumentMouseOut, false);
 
-    }
+		}
 
-    function onDocumentMouseOut(event) {
+		function onDocumentMouseOut(event) {
 
-      renderer.domElement.removeEventListener('mousemove', onDocumentMouseMove, false);
-      renderer.domElement.removeEventListener('mouseup', onDocumentMouseUp, false);
-      renderer.domElement.removeEventListener('mouseout', onDocumentMouseOut, false);
+			renderer.domElement.removeEventListener('mousemove', onDocumentMouseMove, false);
+			renderer.domElement.removeEventListener('mouseup', onDocumentMouseUp, false);
+			renderer.domElement.removeEventListener('mouseout', onDocumentMouseOut, false);
 
-    }
+		}
 
-    function onDocumentTouchStart(event) {
+		function onDocumentTouchStart(event) {
 
-      if (event.touches.length == 1) {
+			if (event.touches.length == 1) {
 
-          event.preventDefault();
+					event.preventDefault();
 
-          mouseXOnMouseDown = event.touches[0].pageX - windowHalfX;
-          targetRotationOnMouseDown = targetRotation;
+					mouseXOnMouseDown = event.touches[0].pageX - windowHalfX;
+					targetRotationOnMouseDown = targetRotation;
 
-      }
+			}
 
-    }
+		}
 
-    function onDocumentTouchMove(event) {
+		function onDocumentTouchMove(event) {
 
-      if (event.touches.length == 1) {
+			if (event.touches.length == 1) {
 
-          event.preventDefault();
+					event.preventDefault();
 
-          mouseX = event.touches[0].pageX - windowHalfX;
-          targetRotation = targetRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.05;
+					mouseX = event.touches[0].pageX - windowHalfX;
+					targetRotation = targetRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.05;
 
-      }
+			}
 
-    }
+		}
 
-    //
+		//
 
-    function animate() {
+		function animate() {
 
-      requestAnimationFrame(animate);
+			requestAnimationFrame(animate);
 
-      render();
-      stats.update();
+			render();
+			stats.update();
 
-    }
+		}
 
-    function render() {
+		function render() {
 
-      // Try Animate Camera Along Spline
-      var time = Date.now();
-      var looptime = 20 * 1000;
-      var t = (time % looptime) / looptime;
+			// Try Animate Camera Along Spline
+			var time = Date.now();
+			var looptime = 20 * 1000;
+			var t = (time % looptime) / looptime;
 
-      var pos = tube.path.getPointAt(t);
-      pos.multiplyScalar(scale);
+			var pos = tube.path.getPointAt(t);
+			pos.multiplyScalar(scale);
 
-      // interpolation
-      var segments = tube.tangents.length;
-      var pickt = t * segments;
-      var pick = Math.floor(pickt);
-      var pickNext = (pick + 1) % segments;
+			// interpolation
+			var segments = tube.tangents.length;
+			var pickt = t * segments;
+			var pick = Math.floor(pickt);
+			var pickNext = (pick + 1) % segments;
 
-      binormal.sub(tube.binormals[pickNext], tube.binormals[pick]);
-      binormal.multiplyScalar(pickt - pick).addSelf(tube.binormals[pick]);
+			binormal.sub(tube.binormals[pickNext], tube.binormals[pick]);
+			binormal.multiplyScalar(pickt - pick).addSelf(tube.binormals[pick]);
 
 
-      var dir = tube.path.getTangentAt(t);
+			var dir = tube.path.getTangentAt(t);
 
-      var offset = 15;
+			var offset = 15;
 
-      normal.copy(binormal).crossSelf(dir);
+			normal.copy(binormal).crossSelf(dir);
 
-      // We move on a offset on its binormal
-      pos.addSelf(normal.clone().multiplyScalar(offset));
+			// We move on a offset on its binormal
+			pos.addSelf(normal.clone().multiplyScalar(offset));
 
-      splineCamera.position = pos;
-      cameraEye.position = pos;
+			splineCamera.position = pos;
+			cameraEye.position = pos;
 
 
-      // Camera Orientation 1 - default look at
-      // splineCamera.lookAt(lookAt);
+			// Camera Orientation 1 - default look at
+			// splineCamera.lookAt(lookAt);
 
-      // Using arclength for stablization in look ahead.
-      var lookAt = tube.path.getPointAt((t + 30/tube.path.getLength()) % 1).multiplyScalar(scale);
-      
-      // Camera Orientation 2 - up orientation via normal
-      if (!lookAhead)
-      lookAt.copy(pos).addSelf(dir);
-      splineCamera.matrix.lookAt(splineCamera.position, lookAt, normal);
-      splineCamera.rotation.getRotationFromMatrix(splineCamera.matrix);
+			// Using arclength for stablization in look ahead.
+			var lookAt = tube.path.getPointAt((t + 30/tube.path.getLength()) % 1).multiplyScalar(scale);
+			
+			// Camera Orientation 2 - up orientation via normal
+			if (!lookAhead)
+			lookAt.copy(pos).addSelf(dir);
+			splineCamera.matrix.lookAt(splineCamera.position, lookAt, normal);
+			splineCamera.rotation.setEulerFromRotationMatrix(splineCamera.matrix, splineCamera.eulerOrder);
 
-      cameraHelper.update();
+			cameraHelper.update();
 
-      parent.rotation.y += (targetRotation - parent.rotation.y) * 0.05;
+			parent.rotation.y += (targetRotation - parent.rotation.y) * 0.05;
 
-      if (animation) {
+			if (animation) {
 
-        renderer.render(scene, splineCamera);
+				renderer.render(scene, splineCamera);
 
-      } else {
+			} else {
 
-        renderer.render(scene, camera);
+				renderer.render(scene, camera);
 
-      }
+			}
 
-      
-      
-    }
+			
+			
+		}
 	</script>
 
-  </body>
+	</body>
 </html>

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 172 - 0
examples/webgl_geometry_extrude_uvs2.html


+ 8 - 8
examples/webgl_lines_colors.html

@@ -119,14 +119,14 @@
 
 				// lines
 
-				material = new THREE.LineBasicMaterial( { color: 0xffffff, opacity: 1, linewidth: 3 } );
-
-				var line, p, scale = 0.3, d = 225,
-					parameters =  [ [ material, scale*1.5, [-d,0,0],  geometry ],
-									[ material, scale*1.5, [0,0,0],  geometry2 ],
-									[ material, scale*1.5, [d,0,0],  geometry3 ] ];
-
-				material.vertexColors = true;
+				material = new THREE.LineBasicMaterial( { color: 0xffffff, opacity: 1, linewidth: 3, vertexColors: THREE.VertexColors } );
+
+				var line, p, scale = 0.3, d = 225;
+				var parameters =  [
+					[ material, scale*1.5, [-d,0,0],  geometry ],
+					[ material, scale*1.5, [0,0,0],  geometry2 ],
+					[ material, scale*1.5, [d,0,0],  geometry3 ]
+				];
 
 				for ( i = 0; i < parameters.length; ++i ) {
 

+ 8 - 8
examples/webgl_lines_splines.html

@@ -121,14 +121,14 @@
 
 				// lines
 
-				material = new THREE.LineBasicMaterial( { color: 0xffffff, opacity: 1, linewidth: 3 } );
-
-				var line, p, scale = 0.3, d = 225,
-					parameters =  [ [ material, scale*1.5, [-d,0,0],  geometry ],
-									[ material, scale*1.5, [0,0,0],  geometry2 ],
-									[ material, scale*1.5, [d,0,0],  geometry3 ] ];
-
-				material.vertexColors = true;
+				material = new THREE.LineBasicMaterial( { color: 0xffffff, opacity: 1, linewidth: 3, vertexColors: THREE.VertexColors } );
+
+				var line, p, scale = 0.3, d = 225;
+				var parameters =  [
+					[ material, scale*1.5, [-d,0,0],  geometry ],
+					[ material, scale*1.5, [0,0,0],  geometry2 ],
+					[ material, scale*1.5, [d,0,0],  geometry3 ]
+				];
 
 				for ( i = 0; i < parameters.length; ++ i ) {
 

+ 10 - 9
examples/webgl_loader_collada.html

@@ -77,21 +77,22 @@
 
 				// Grid
 
-				var line_material = new THREE.LineBasicMaterial( { color: 0xcccccc, opacity: 0.2 } ),
-					geometry = new THREE.Geometry(),
-					floor = -0.04, step = 1, size = 14;
+				var size = 14, step = 1;
 
-				for ( var i = 0; i <= size / step * 2; i ++ ) {
+				var geometry = new THREE.Geometry();
+				var material = new THREE.LineBasicMaterial( { color: 0xcccccc, opacity: 0.2 } );
 
-					geometry.vertices.push( new THREE.Vector3( - size, floor, i * step - size ) );
-					geometry.vertices.push( new THREE.Vector3(   size, floor, i * step - size ) );
+				for ( var i = - size; i <= size; i += step ) {
 
-					geometry.vertices.push( new THREE.Vector3( i * step - size, floor, -size ) );
-					geometry.vertices.push( new THREE.Vector3( i * step - size, floor,  size ) );
+					geometry.vertices.push( new THREE.Vector3( - size, - 0.04, i ) );
+					geometry.vertices.push( new THREE.Vector3(   size, - 0.04, i ) );
+
+					geometry.vertices.push( new THREE.Vector3( i, - 0.04, - size ) );
+					geometry.vertices.push( new THREE.Vector3( i, - 0.04,   size ) );
 
 				}
 
-				var line = new THREE.Line( geometry, line_material, THREE.LinePieces );
+				var line = new THREE.Line( geometry, material, THREE.LinePieces );
 				scene.add( line );
 
 				// Add the COLLADA

+ 8 - 2
examples/webgl_loader_json_blender.html

@@ -34,6 +34,9 @@
 
 		<script src="../build/Three.js"></script>
 
+		<script src="../src/loaders/LoadingMonitor.js"></script>
+		<script src="../src/loaders/GeometryLoader.js"></script>
+
 		<script src="js/loaders/ColladaLoader.js"></script>
 
 		<script src="js/Detector.js"></script>
@@ -85,8 +88,10 @@
 
 				// Add Blender exported Collada model
 
-				var loader = new THREE.JSONLoader();
-				loader.load( "models/animated/monster/monster.js", function ( geometry ) {
+				var loader = new THREE.GeometryLoader();
+				loader.addEventListener( 'load', function ( event ) {
+
+					var geometry = event.content;
 
 					// adjust color a bit
 
@@ -134,6 +139,7 @@
 					}
 
 				} );
+				loader.load( 'models/animated/monster/monster.js' );
 
 
 				// Add the COLLADA

+ 22 - 4
examples/webgl_loader_obj.html

@@ -57,6 +57,8 @@
 				container = document.createElement( 'div' );
 				document.body.appendChild( container );
 
+				// scene
+
 				scene = new THREE.Scene();
 
 				camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2000 );
@@ -70,10 +72,25 @@
 				directionalLight.position.set( 0, 0, 1 ).normalize();
 				scene.add( directionalLight );
 
-				var texture = THREE.ImageUtils.loadTexture( 'textures/ash_uvgrid01.jpg' );
+				// texture
+
+				var texture = new THREE.Texture();
+
+				var loader = new THREE.ImageLoader();
+				loader.addEventListener( 'load', function ( event ) {
+
+					texture.image = event.content;
+					texture.needsUpdate = true;
+
+				} );
+				loader.load( 'textures/ash_uvgrid01.jpg' );
+
+				// model
 
 				var loader = new THREE.OBJLoader();
-				loader.load( "obj/male02/male02.obj", function ( object ) {
+				loader.addEventListener( 'load', function ( event ) {
+
+					var object = event.content;
 
 					for ( var i = 0, l = object.children.length; i < l; i ++ ) {
 
@@ -84,9 +101,10 @@
 					object.position.y = - 80;
 					scene.add( object );
 
-				} );
+				});
+				loader.load( 'obj/male02/male02.obj' );
 
-				// RENDERER
+				// 
 
 				renderer = new THREE.WebGLRenderer();
 				renderer.setSize( window.innerWidth, window.innerHeight );

+ 48 - 38
examples/webgl_loader_vtk.html

@@ -48,71 +48,81 @@
 
 			var cross;
 
+			init();
+			animate();
 
-			// scene and camera
+			function init() {
 
-			scene = new THREE.Scene();
+				// scene and camera
 
-			camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.01, 1e10 );
-			camera.position.z = 0.2;
+				scene = new THREE.Scene();
 
+				camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.01, 1e10 );
+				camera.position.z = 0.2;
+				scene.add( camera );
 
-			scene.add( camera );
+				controls = new THREE.TrackballControls( camera );
 
-			controls = new THREE.TrackballControls( camera );
+				controls.rotateSpeed = 5.0;
+				controls.zoomSpeed = 5;
+				controls.panSpeed = 2;
 
-			controls.rotateSpeed = 5.0;
-			controls.zoomSpeed = 5;
-			controls.panSpeed = 2;
+				controls.noZoom = false;
+				controls.noPan = false;
 
-			controls.noZoom = false;
-			controls.noPan = false;
+				controls.staticMoving = true;
+				controls.dynamicDampingFactor = 0.3;
 
-			controls.staticMoving = true;
-			controls.dynamicDampingFactor = 0.3;
+				// light
 
-			// light
+				var dirLight = new THREE.DirectionalLight( 0xffffff );
+				dirLight.position.set( 200, 200, 1000 ).normalize();
+				camera.add( dirLight );
+				camera.add( dirLight.target );
 
-			var dirLight = new THREE.DirectionalLight( 0xffffff );
-			dirLight.position.set( 200, 200, 1000 ).normalize();
-			camera.add( dirLight );
-			camera.add( dirLight.target );
+				var material = new THREE.MeshLambertMaterial( { color:0xffffff} );
 
-			// renderer
+				var loader = new THREE.VTKLoader();
+				loader.addEventListener( 'load', function ( event ) {
 
-			renderer = new THREE.WebGLRenderer( { antialias: false } );
-			renderer.setClearColorHex( 0x000000, 1 );
-			renderer.setSize( window.innerWidth, window.innerHeight );
+					var geometry = event.content;
 
-			container = document.createElement( 'div' );
-			document.body.appendChild( container );
-			container.appendChild( renderer.domElement );
+					var mesh = new THREE.Mesh( geometry, material );
+					mesh.doubleSided = true;
+					mesh.position.setY( - 0.09 );
+					scene.add( mesh );
 
-			stats = new Stats();
-			stats.domElement.style.position = 'absolute';
-			stats.domElement.style.top = '0px';
-			container.appendChild( stats.domElement );
+				} );
+				loader.load ( "models/vtk/bunny.vtk" );
 
+				// renderer
 
-			var material =  new THREE.MeshLambertMaterial( { color:0xffffff} );
+				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer.setClearColorHex( 0x000000, 1 );
+				renderer.setSize( window.innerWidth, window.innerHeight );
 
-			var loader=new THREE.VTKLoader();
-			loader.load ("models/vtk/bunny.vtk", function(geom){
-				var mesh = new THREE.Mesh(geom, material );
-				mesh.doubleSided=true;
-				mesh.position.setY(-0.09);
-				scene.add( mesh );
-				animate();
-				});
+				container = document.createElement( 'div' );
+				document.body.appendChild( container );
+				container.appendChild( renderer.domElement );
+
+				stats = new Stats();
+				stats.domElement.style.position = 'absolute';
+				stats.domElement.style.top = '0px';
+				container.appendChild( stats.domElement );
+
+			}
 
 			function animate() {
 
 				requestAnimationFrame( animate );
+
 				controls.update();
 				renderer.render( scene, camera );
+
 				stats.update();
 
 			}
+
 		</script>
 
 	</body>

+ 53 - 3
examples/webgl_marching_cubes.html

@@ -146,9 +146,13 @@
 			resolution = 28;
 			numBlobs = 10;
 
-			effect = new THREE.MarchingCubes( resolution, materials[ current_material ].m );
+			effect = new THREE.MarchingCubes( resolution, materials[ current_material ].m, true, true );
 			effect.position.set( 0, 0, 0 );
 			effect.scale.set( 700, 700, 700 );
+
+			effect.enableUvs = false;
+			effect.enableColors = false;
+
 			scene.add( effect );
 
 			// RENDERER
@@ -284,6 +288,9 @@
 			dottedMaterial2.uniforms.uBaseColor.value.setRGB( 0, 0, 0 );
 			dottedMaterial2.uniforms.uLineColor1.value.setHSV( 0.05, 1.0, 1.0 );
 
+			var texture = THREE.ImageUtils.loadTexture( "textures/ash_uvgrid01.jpg" );
+			texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
+
 			var materials = {
 
 			"chrome" :
@@ -310,6 +317,24 @@
 				h: 0, s: 0, v: 1
 			},
 
+			"flat" :
+			{
+				m: new THREE.MeshPhongMaterial( { color: 0x000000, specular: 0x111111, shininess: 1, shading: THREE.FlatShading, perPixel: true } ),
+				h: 0, s: 0, v: 1
+			},
+
+			"textured" :
+			{
+				m: new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0x111111, shininess: 1, map: texture, perPixel: true } ),
+				h: 0, s: 0, v: 1
+			},
+
+			"colors" :
+			{
+				m: new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0xffffff, shininess: 2, vertexColors: THREE.VertexColors, perPixel: true } ),
+				h: 0, s: 0, v: 1
+			},
+
 			"plastic" :
 			{
 				m: new THREE.MeshPhongMaterial( { color: 0x000000, specular: 0x888888, ambient: 0x000000, shininess: 250, perPixel: true } ),
@@ -402,17 +427,42 @@
 
 					mm.setValue( current_material );
 
+					if ( current_material === "textured" ) {
+
+						effect.enableUvs = true;
+
+					} else {
+
+						effect.enableUvs = false;
+
+					}
+
+					if ( current_material === "colors" ) {
+
+						effect.enableColors = true;
+
+					} else {
+
+						effect.enableColors = false;
+
+					}
+
 				};
 
 			};
 
 			function toggle( e ) {
 
-				if ( e.style.display === "block" )
+				if ( e.style.display === "block" ) {
+
 					e.style.display = "none";
-				else
+
+				} else {
+
 					e.style.display = "block";
 
+				}
+
 			}
 
 			effectController = {

+ 3 - 1
examples/webgl_materials_texture_filters.html

@@ -140,7 +140,9 @@
 
 				// PAINTING
 
-				var callbackPainting = function( image ) {
+				var callbackPainting = function() {
+
+					var image = texturePainting.image;
 
 					texturePainting2.image = image;
 					texturePainting2.needsUpdate = true;

+ 146 - 0
examples/webgl_test_memory2.html

@@ -0,0 +1,146 @@
+<!doctype html>
+<html lang="en">
+	<head>
+		<title>three.js - webgl</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<style>
+			body {
+				background:#fff;
+				padding:0;
+				margin:0;
+				overflow:hidden;
+			}
+
+		</style>
+	</head>
+
+	<body>
+		<script type="x-shader/x-fragment" id="fragmentShader">
+
+			void main() {
+
+				if ( mod ( gl_FragCoord.x, 4.0001 ) < 1.0 || mod ( gl_FragCoord.y, 4.0001 ) < 1.0 )
+
+					gl_FragColor = vec4( XXX, 1.0 );
+
+				else
+
+					gl_FragColor = vec4( 1.0 );
+
+			}
+
+		</script>
+
+		<script type="x-shader/x-vertex" id="vertexShader">
+
+			void main() {
+
+				vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
+				gl_Position = projectionMatrix * mvPosition;
+
+			}
+
+		</script>
+
+		<script src="../build/Three.js"></script>
+
+		<script>
+
+			var N = 100;
+
+			var container;
+
+			var camera, scene, renderer;
+
+			var geometry, meshes = [];
+
+			var fragmentShader, vertexShader;
+
+			init();
+			setInterval( render, 1000 / 60 );
+
+			function init() {
+
+				container = document.createElement( 'div' );
+				document.body.appendChild( container );
+
+				vertexShader = document.getElementById( "vertexShader" ).textContent;
+				fragmentShader = document.getElementById( "fragmentShader" ).textContent;
+
+				scene = new THREE.Scene();
+
+				camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 10000 );
+				camera.position.z = 2000;
+				scene.add( camera );
+
+				geometry = new THREE.SphereGeometry( 15, 64, 32 );
+
+				for ( var i = 0; i < N; i ++ ) {
+
+					var material = new THREE.ShaderMaterial( { vertexShader: vertexShader, fragmentShader: generateFragmentShader() } );
+
+					mesh = new THREE.Mesh( geometry, material );
+
+					mesh.position.x = ( 0.5 - Math.random() ) * 1000;
+					mesh.position.y = ( 0.5 - Math.random() ) * 1000;
+					mesh.position.z = ( 0.5 - Math.random() ) * 1000;
+
+					scene.add( mesh );
+
+					meshes.push( mesh );
+
+				}
+
+				renderer = new THREE.WebGLRenderer();
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				container.appendChild( renderer.domElement );
+
+			}
+
+			//
+
+			function generateFragmentShader() {
+
+				return fragmentShader.replace( "XXX", Math.random() + "," + Math.random() + "," + Math.random() );
+
+			}
+
+			//
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+
+				render();
+
+			}
+
+			function render() {
+
+				for ( var i = 0; i < N; i ++ ) {
+
+					var mesh = meshes[ i ];
+					mesh.material = new THREE.ShaderMaterial( { vertexShader: vertexShader, fragmentShader: generateFragmentShader() } );
+
+				}
+
+				renderer.render( scene, camera );
+
+				console.log( "before", renderer.info.memory.programs );
+
+				for ( var i = 0; i < N; i ++ ) {
+
+					var mesh = meshes[ i ];
+					renderer.deallocateMaterial( mesh.material );
+
+				}
+
+				console.log( "after", renderer.info.memory.programs );
+
+			}
+
+		</script>
+
+	</body>
+</html>

+ 1 - 1
examples/webgl_trackballcamera_earth.html

@@ -259,7 +259,7 @@
 				controls.screen.width = width;
 				controls.screen.height = height;
 
-				camera.radius = ( width + height ) / 4;
+				controls.radius = ( width + height ) / 4;
 
 			};
 

BIN=BIN
gui/files/inconsolata.woff


+ 91 - 119
gui/index.html

@@ -1,122 +1,77 @@
-<html>
+<!DOCTYPE html>
+<html lang="en">
 	<head>
 		<title>three.js gui</title>
 		<style>
-			@font-face {
-
-				font-family: 'Inconsolata';
-				src: url('files/inconsolata.woff') format('woff');
-				font-weight: normal;
-				font-style: normal;
-
-			}
-
 			body {
-
+				font-family: Arial, sans-serif;
+				font-size: 14px;
 				margin: 0;
 				overflow: hidden;
-
 			}
 
-			button {
-
-				cursor: pointer;
-
+			hr {
+				border: 0px;
+				border-top: 1px solid #ccc;
 			}
 
-			pre {
-
-				font-family: 'Inconsolata';
-
-			}
 		</style>
 	</head>
 	<body>
 
 		<script type="text/javascript" src="../build/Three.js"></script>
+		<script type="text/javascript" src="../examples/js/loaders/ColladaLoader.js"></script>
+		<script type="text/javascript" src="../examples/js/loaders/OBJLoader.js"></script>
+		<script type="text/javascript" src="../examples/js/loaders/UTF8Loader.js"></script>
+		<script type="text/javascript" src="../examples/js/loaders/VTKLoader.js"></script>
 
 		<script type="text/javascript" src="js/libs/signals.min.js"></script>
 
 		<script type="text/javascript" src="js/UI.js"></script>
-		<script type="text/javascript" src="js/UI.Viewport.js"></script>
-		<script type="text/javascript" src="js/UI.Toolbar.js"></script>
-		<script type="text/javascript" src="js/Code.js"></script>
-		<script type="text/javascript" src="js/Code.Templates.js"></script>
+		<script type="text/javascript" src="js/ui/Viewport.js"></script>
+		<script type="text/javascript" src="js/ui/Sidebar.js"></script>
+		<script type="text/javascript" src="js/ui/Sidebar.Outliner.js"></script>
+		<script type="text/javascript" src="js/ui/Sidebar.Properties.js"></script>
+		<script type="text/javascript" src="js/ui/Sidebar.Properties.Object3D.js"></script>
+		<script type="text/javascript" src="js/ui/Sidebar.Properties.Geometry.js"></script>
+		<script type="text/javascript" src="js/ui/Sidebar.Properties.Material.js"></script>
+		<script type="text/javascript" src="js/ui/MenuBar.js"></script>
 
 		<script>
 
+			window.URL = window.URL || window.webkitURL;
 			window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder;
-			window.URL = window.URL || window.webkitURL || window.mozURL;
 
-			var Signal = signals.Signal;
+			var SIGNALS = signals;
 
 			var signals = {
 
-				added: new Signal(),
-				updated: new Signal()
+				objectAdded: new SIGNALS.Signal(),
+				objectSelected: new SIGNALS.Signal(),
+				objectChanged: new SIGNALS.Signal(),
+				windowResize: new SIGNALS.Signal()
 
 			};
 
-			var ui = new UI();
-			document.body.appendChild( ui.getDOMElement() );
-
-			var code = new Code()
-			document.body.appendChild( code.getDOMElement() );
-
-			var xhalf = 0.7;
-
-			var xr = document.createElement( 'div' );
-			xr.style.position = 'absolute';
-			xr.style.top = '0px';
-			xr.style.width = '1px';
-			xr.style.cursor = 'col-resize';
-			xr.addEventListener( 'mousedown', function ( event ) {
-
-				event.preventDefault();
-
-				document.body.style.cursor = 'col-resize';
-				document.addEventListener( 'mousemove', onMouseMove, false );
-				document.addEventListener( 'mouseup', onMouseUp, false );
-
-				function onMouseMove( event ) {
-
-					event.preventDefault();
-
-					xhalf = Math.max( 0, Math.min( 1, event.clientX / window.innerWidth ) );
-
-					update();
-
-				}
-
-				function onMouseUp( event ) {
-
-					document.body.style.cursor = 'auto';
-					document.removeEventListener( 'mousemove', onMouseMove, false );
-					document.removeEventListener( 'mouseup', onMouseUp, false );
-
-				}
-
-			}, false );
-			xr.addEventListener( 'dblclick', function ( event ) {
-
-				xhalf = 0.7;
-				update();
-
-			}, false );
-			document.body.appendChild( xr );
-
 			//
 
-			document.addEventListener( 'dragover', function ( event ) {
+			var menubar = new MenuBar( signals );
+			menubar.setWidth( '100%' );
+			menubar.setHeight( '32px' );
+			document.body.appendChild( menubar.dom );
 
-				event.preventDefault();
+			var viewport = new Viewport( signals );
+			viewport.setTop( '32px' );
+			viewport.setWidth( '-webkit-calc(100% - 300px)', '-moz-calc(100% - 300px)', 'calc(100% - 300px)' );
+			viewport.setHeight( '-webkit-calc(100% - 32px)', '-moz-calc(100% - 32px)', 'calc(100% - 32px)' );
+			document.body.appendChild( viewport.dom );
 
-			}, false );
-			document.addEventListener( 'dragleave', function ( event ) {
+			var sidebar = new Sidebar( signals );
+			sidebar.setLeft( '-webkit-calc(100% - 300px)', '-moz-calc(100% - 300px)', 'calc(100% - 300px)' );
+			sidebar.setTop( '32px' );
+			sidebar.setHeight( '-webkit-calc(100% - 32px)', '-moz-calc(100% - 32px)', 'calc(100% - 32px)' );
+			document.body.appendChild( sidebar.dom );
 
-				event.preventDefault();
-
-			}, false );
 			document.addEventListener( 'drop', function ( event ) {
 
 				event.preventDefault();
@@ -131,45 +86,65 @@
 
 					switch ( extension ) {
 
-						case 'js':
+						case 'dae':
 
-							var loader = new THREE.JSONLoader();
-							loader.createModel( JSON.parse( contents ), function ( geometry ) {
+							var parser = new DOMParser();
+							var xml = parser.parseFromString( contents, 'text/xml' );
 
-								geometry.gui = {
-									paremeters: {
-									},
-									getCode: function () {
+							// TODO: Update ColladaLoader
 
-										return 'new THREE.JSONLoader( TODO )';
+							var loader = new THREE.ColladaLoader();
+							loader.parse( xml, function ( collada ) {
 
-									}
-								};
+								signals.objectAdded.dispatch( collada.scene );
+								signals.objectSelected.dispatch( collada.scene );
 
-								var material = new THREE.MeshBasicMaterial( { color: 0xffffff, wireframe: true } );
-								var mesh = new THREE.Mesh( geometry, material );
+							} );
 
-								signals.added.dispatch( mesh );
+							break;
 
-							} );
+						case 'js':
+
+							var loader = new THREE.GeometryLoader();
+
+							var geometry = loader.parse( JSON.parse( contents ) );
+							var material = new THREE.MeshLambertMaterial( { color: 0xffffff } );
+							var mesh = new THREE.Mesh( geometry, material );
+
+							signals.objectAdded.dispatch( mesh );
+							signals.objectSelected.dispatch( mesh );
 
 							break;
 
-						case 'dae':
+						case 'obj':
 
-							var parser = new DOMParser();
-							var xml = parser.parseFromString( contents, 'text/xml' );
+							var loader = new THREE.OBJLoader();
 
-							var loader = new THREE.ColladaLoader();
-							loader.parse( xml, function ( collada ) {
+							var object = loader.parse( contents );
 
-								signals.added.dispatch( collada.scene );
+							signals.objectAdded.dispatch( object );
+							signals.objectSelected.dispatch( object );
 
-							} );
+							break;
+
+						case 'utf8':
+
+							// TODO
 
 							break;
 
+						case 'vtk':
+
+							var loader = new THREE.VTKLoader();
 
+							var geometry = loader.parse( contents );
+							var material = new THREE.MeshLambertMaterial( { color: 0xffffff } );
+							var mesh = new THREE.Mesh( geometry, material );
+
+							signals.objectAdded.dispatch( mesh );
+							signals.objectSelected.dispatch( mesh );
+
+							break;
 
 					}
 
@@ -179,30 +154,27 @@
 
 			}, false );
 
-			// Add Sphere
 
-			var geometry = new THREE.SphereGeometry( 75, 20, 10 );
-			var material = new THREE.MeshBasicMaterial( { color: 0xffffff, wireframe: true } );
+			//
+
+			var geometry = new THREE.SphereGeometry( 75, 25, 15 );
+			var material = new THREE.MeshLambertMaterial( { color: Math.random() * 0xffffff } );
 			var mesh = new THREE.Mesh( geometry, material );
 
-			signals.added.dispatch( mesh );
+			signals.objectAdded.dispatch( mesh );
+			signals.objectSelected.dispatch( mesh );
 
 			//
 
-			update();
-			window.addEventListener( 'resize', function ( event ) { update() }, false );
-
-			function update() {
+			var onWindowResize = function ( event ) {
 
-				ui.setSize( Math.floor( window.innerWidth * xhalf ), window.innerHeight );
+				signals.windowResize.dispatch();
 
-				code.setPosition( Math.floor( window.innerWidth * xhalf ), 0 );
-				code.setSize( window.innerWidth - Math.floor( window.innerWidth * xhalf ), window.innerHeight );
+			};
 
-				xr.style.left = Math.floor( window.innerWidth * xhalf )  + 'px';
-				xr.style.height = window.innerHeight + 'px';
+			onWindowResize();
 
-			}
+			window.addEventListener( 'resize', onWindowResize, false );
 
 		</script>
 	</body>

+ 0 - 136
gui/js/Code.Templates.js

@@ -1,136 +0,0 @@
-// CubeGeometry
-
-THREE._CubeGeometry = THREE.CubeGeometry;
-THREE.CubeGeometry = function ( width, height, depth, segmentsWidth, segmentsHeight, segmentsDepth, materials, flipped, sides ) {
-
-	var geometry = new THREE._CubeGeometry( width, height, depth, segmentsWidth, segmentsHeight, segmentsDepth, materials, flipped, sides );
-
-	geometry.gui = {
-
-		parameters: {
-
-			width: width,
-			height: height,
-			depth: depth,
-			segmentsWidth: segmentsWidth,
-			segmentsHeight: segmentsHeight,
-			segmentsDepth: segmentsDepth,
-			materials: materials,
-			flipped: flipped,
-			sides: sides
-
-		},
-
-		getCode: function () {
-
-			return 'new THREE.CubeGeometry( ' + [
-
-					geometry.gui.parameters.width,
-					geometry.gui.parameters.height,
-					geometry.gui.parameters.depth,
-					geometry.gui.parameters.segmentsWidth,
-					geometry.gui.parameters.segmentsHeight,
-					geometry.gui.parameters.segmentsDepth
-					// ,
-					// geometry.gui.parameters.materials,
-					// geometry.gui.parameters.flipped,
-					// geometry.gui.parameters.sides
-
-				].join( ', ' ) + ' )';
-
-		}
-
-	}
-
-	return geometry;
-
-};
-
-// SphereGeometry
-
-THREE._SphereGeometry = THREE.SphereGeometry;
-THREE.SphereGeometry = function ( radius, segmentsWidth, segmentsHeight ) {
-
-	var geometry = new THREE._SphereGeometry( radius, segmentsWidth, segmentsHeight );
-
-	geometry.gui = {
-
-		parameters: {
-
-			radius: radius,
-			segmentsWidth: segmentsWidth,
-			segmentsHeight: segmentsHeight
-
-		},
-
-		getCode: function () {
-
-			return 'new THREE.SphereGeometry( ' + [
-
-					geometry.gui.parameters.radius,
-					geometry.gui.parameters.segmentsWidth,
-					geometry.gui.parameters.segmentsHeight
-
-				].join( ', ' ) + ' )';
-
-		}
-
-	}
-
-	return geometry;
-
-};
-
-// TorusGeometry
-
-THREE._TorusGeometry = THREE.TorusGeometry;
-THREE.TorusGeometry = function ( radius, tube, segmentsR, segmentsT, arc ) {
-
-	var geometry = new THREE._TorusGeometry( radius, tube, segmentsR, segmentsT, arc );
-
-	geometry.gui = {
-
-		parameters: {
-
-			radius: radius,
-			tube: tube,
-			segmentsR: segmentsR,
-			segmentsT: segmentsT,
-			arc: arc
-
-		},
-
-		getCode: function () {
-
-			return 'new THREE.TorusGeometry( ' + [
-
-					geometry.gui.parameters.radius,
-					geometry.gui.parameters.tube,
-					geometry.gui.parameters.segmentsR,
-					geometry.gui.parameters.segmentsT
-
-				].join( ', ' ) + ' )';
-
-		}
-
-	}
-
-	return geometry;
-
-};
-
-// MeshBasicMaterial
-
-THREE.MeshBasicMaterial.prototype.gui = {
-
-	getCode: function () {
-
-		return 'new THREE.MeshBasicMaterial( { ' + [
-
-				'color: 0x' + material.color.getHex().toString(16)
-
-			].join( ', ' ) + ' } )';
-
-	}
-
-};

+ 0 - 226
gui/js/Code.js

@@ -1,226 +0,0 @@
-var Code = function () {
-
-	var _domElement = document.createElement( 'div' );
-	_domElement.style.position = 'absolute';
-	_domElement.style.backgroundColor = '#f0f0f0';
-	_domElement.style.overflow = 'auto';
-
-	//
-
-	var _html = false;
-
-	var _checkbox = document.createElement( 'input' );
-	_checkbox.type = 'checkbox';
-	_checkbox.style.margin = '20px 6px 0px 20px';
-	_checkbox.addEventListener( 'click', function () { _html = !_html; _update(); }, false );
-	_domElement.appendChild( _checkbox );
-
-	var _preview = document.createElement( 'a' );
-	_preview.href = '#';
-	_preview.innerHTML = 'preview';
-	_preview.style.margin = '20px 6px 0px 20px';
-	_preview.addEventListener( 'click', function () { 
-
-			// Get unescaped code gen
-
-			var temp=document.createElement("pre");
-			temp.innerHTML = _codegen( true );
-			temp = temp.firstChild.nodeValue;
-			temp = temp.replace("js/Three.js", "../build/Three.js");
-
-			var opener = window.open('','myconsole',
-			  'width=800,height=400'
-			   +',menubar=1'
-			   +',toolbar=0'
-			   +',status=1'
-			   +',scrollbars=1'
-			   +',resizable=1');
-
-			opener.document.writeln( temp );
-			opener.document.close();
-
-		}, false 
-	);
-	_domElement.appendChild( _preview );
-
-
-	/*
-	var _checkboxText = document.createElement( 'span' );
-	_checkboxText.style.fontFamily = 'Monospace';
-	_checkboxText.innerText = 'HTML';
-	_domElement.appendChild( _checkboxText );
-	*/
-
-	//
-
-	var _code = document.createElement( 'pre' );
-	_code.style.color = '#404040';
-	_code.style.margin = '20px';
-	_code.style.fontSize = '13px';
-	_code.style.whiteSpace = 'pre'; // 'pre-wrap'
-	_domElement.appendChild( _code );
-
-	//
-
-	var _list = [];
-
-	var _codegen = function (html) {
-		var string = '';
-
-		console.log(_list);
-		string += [
-
-			'var camera, scene, renderer;',
-			'',
-			'init();',
-			'animate();',
-			'',
-			'function init() {',
-			'',
-			'\tcamera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );',
-			'\tcamera.position.z = 500;',
-			'',
-			'\tscene = new THREE.Scene();',
-			''
-
-		].join( '\n' );
-
-		for ( var i = 0, l = _list.length; i < l; i ++ ) {
-
-			string += _list[ i ] + '\n';
-
-		}
-
-		string += [
-
-			'',
-			'\trenderer = new THREE.WebGLRenderer()',
-			'\trenderer.setSize( window.innerWidth, window.innerHeight );',
-			'\tdocument.body.appendChild( renderer.domElement );',
-			'',
-			'}',
-			'',
-			'function animate() {',
-			'',
-			'\trequestAnimationFrame( animate );',
-			'\trender();',
-			'',
-			'}',
-			'',
-			'function render() {',
-			'',
-			'\trenderer.render( scene, camera );',
-			'',
-			'}'
-
-		].join( '\n' );
-
-		if ( html ) {
-
-			string = '&lt;!doctype html&gt;\n&lt;html&gt;\n\t&lt;body&gt;\
-			\n\t\t&lt;style&gt; body {background-color: #f0f0f0;} &lt;/style&gt;\
-			\n\t\t&lt;script src=\"js/Three.js\"&gt;&lt;/script&gt;\
-			\n\t\t&lt;script&gt;\n' 
-			+ ( '\n' + string ).replace( /\n/gi, '\n\t\t\t' ) + 
-			'\n\n\t\t&lt;/script&gt;\n\t&lt;/body&gt;\n&lt;/html&gt;';
-		}
-
-		return string;
-	}
-
-	var _update = function () {
-
-		_code.innerHTML = _codegen( _html );
-
-	}
-
-	var _strfor = function(str) {
-	    for (var i=1; i<arguments.length; i++) {
-	    	if (arguments[i].toFixed) {
-	    		arguments[i] = arguments[i].toFixed(2);
-	    	}
-	        str = str.replace('{'+(i-1)+'}', arguments[i]);
-	    }
-	    return str;
-	}
-
-	// signals
-
-	signals.updated.add( function ( scene ) {
-
-		_list.length = 0;
-
-		for ( var i = 0, l = scene.children.length; i < l; i ++ ) {
-
-			var object = scene.children[ i ];
-
-			if ( object.geometry == undefined || object.geometry.gui == undefined ) {
-
-				if (object instanceof THREE.Camera) {
-					var string = '';
-					string += _strfor( '\n\tcamera.position.set({0},{1},{2});', object.position.x, object.position.y, object.position.z);
-					string += _strfor( '\n\tcamera.rotation.set({0},{1},{2});', object.rotation.x, object.rotation.y, object.rotation.z);
-
-					_list.push( string );
-
-				} else {
-					_list.push( 'TODO' );
-				}
-				continue;
-
-			}
-
-			if ( object instanceof THREE.Mesh ) {
-
-				var string = '';
-				string += '\n\tvar geometry = ' + object.geometry.gui.getCode() + ';';
-				string += '\n\tvar material = ' + object.material.gui.getCode() + ';';
-				string += '\n\tvar mesh = new THREE.Mesh( geometry, material );';
-
-				if ( object.position.x != 0 ) string += '\n\tmesh.position.x = ' + object.position.x + ';';
-				if ( object.position.y != 0 ) string += '\n\tmesh.position.y = ' + object.position.y + ';';
-				if ( object.position.z != 0 ) string += '\n\tmesh.position.z = ' + object.position.z + ';';
-
-				if ( object.rotation.x != 0 ) string += '\n\tmesh.rotation.x = ' + object.rotation.x + ';';
-				if ( object.rotation.y != 0 ) string += '\n\tmesh.rotation.y = ' + object.rotation.y + ';';
-				if ( object.rotation.z != 0 ) string += '\n\tmesh.rotation.z = ' + object.rotation.z + ';';
-
-				if ( object.scale.x != 1 ) string += '\n\tmesh.scale.x = ' + object.scale.x + ';';
-				if ( object.scale.y != 1 ) string += '\n\tmesh.scale.y = ' + object.scale.y + ';';
-				if ( object.scale.z != 1 ) string += '\n\tmesh.scale.z = ' + object.scale.z + ';';
-
-				string += '\n\tscene.add( mesh );';
-
-				_list.push( string );
-
-			}
-
-		}
-
-		_update();
-
-	} );
-
-	//
-
-	this.getDOMElement = function () {
-
-		return _domElement;
-
-	}
-
-	this.setPosition = function ( x, y ) {
-
-		_domElement.style.left = x + 'px';
-		_domElement.style.top = y + 'px';
-
-	}
-
-	this.setSize = function ( width, height ) {
-
-		_domElement.style.width = width + 'px';
-		_domElement.style.height = height + 'px';
-
-	}
-
-}

+ 0 - 72
gui/js/UI.Toolbar.js

@@ -1,72 +0,0 @@
-UI.Toolbar = function () {
-
-	var _domElement = document.createElement( 'div' );
-	_domElement.style.position = 'absolute';
-	_domElement.style.backgroundColor = '#404040';
-
-	// CUBE
-
-	var _button = document.createElement( 'button' );
-	_button.innerHTML = 'Cube';
-	_button.addEventListener( 'click', function ( event ) {
-
-		var geometry = new THREE.CubeGeometry( 100, 100, 100, 4, 4, 4 );
-		var material = new THREE.MeshBasicMaterial( { color: 0xffffff } );
-		var mesh = new THREE.Mesh( geometry, material );
-
-		signals.added.dispatch( mesh );
-
-	}, false );
-	_domElement.appendChild( _button );
-
-	// SPHERE
-
-	var _button = document.createElement( 'button' );
-	_button.innerHTML = 'Sphere';
-	_button.addEventListener( 'click', function ( event ) {
-
-		var geometry = new THREE.SphereGeometry( 75, 20, 10 );
-		var material = new THREE.MeshBasicMaterial( { color: 0xffffff } );
-		var mesh = new THREE.Mesh( geometry, material );
-
-		signals.added.dispatch( mesh );
-
-	}, false );
-	_domElement.appendChild( _button );
-
-	// TORUS
-
-	var _button = document.createElement( 'button' );
-	_button.innerHTML = 'Torus';
-	_button.addEventListener( 'click', function ( event ) {
-
-		var geometry = new THREE.TorusGeometry( 50, 20, 20, 20 );
-		var material = new THREE.MeshBasicMaterial( { color: 0xffffff } );
-		var mesh = new THREE.Mesh( geometry, material );
-
-		signals.added.dispatch( mesh );
-
-	}, false );
-	_domElement.appendChild( _button );
-
-	this.getDOMElement = function () {
-
-		return _domElement;
-
-	};
-
-	this.setPosition = function ( x, y ) {
-
-		_domElement.style.left = x + 'px';
-		_domElement.style.top = y + 'px';
-
-	};
-
-	this.setSize = function ( width, height ) {
-
-		_domElement.style.width = width + 'px';
-		_domElement.style.height = height + 'px';
-
-	};
-
-};

+ 0 - 257
gui/js/UI.Viewport.js

@@ -1,257 +0,0 @@
-UI.Viewport = function () {
-
-	var _width, _height;
-	var _isMouseDown = false;
-	var _snapToAxis = null;
-
-	var _HOVERED, _SELECTED;
-	var _offset = new THREE.Vector3();
-
-	//
-
-	var _domElement = document.createElement( 'div' );
-	_domElement.style.position = 'absolute';
-	_domElement.style.backgroundColor = '#808080';
-
-	//
-
-	var _camera = new THREE.PerspectiveCamera( 50, 1, 1, 5000 );
-	_camera.position.x = 500;
-	_camera.position.y = 250;
-	_camera.position.z = 500;
-	_camera.lookAt( new THREE.Vector3() );
-
-	var _controls = new THREE.TrackballControls( _camera );
-	_controls.rotateSpeed = 1.0;
-	_controls.zoomSpeed = 1.2;
-	_controls.panSpeed = 0.8;
-	_controls.noZoom = false;
-	_controls.noPan = false;
-	_controls.staticMoving = true;
-	_controls.dynamicDampingFactor = 0.3;
-
-	// guides
-
-	var _sceneHelpers = new THREE.Scene();
-
-	var _grid = new THREE.Mesh( new THREE.PlaneGeometry( 1000, 1000, 20, 20 ), new THREE.MeshBasicMaterial( { color: 0x606060, wireframe: true, transparent: true } ) );
-	_sceneHelpers.add( _grid );
-
-	//
-
-	var _scene = new THREE.Scene();
-
-	_scene.add(_camera);
-
-	/*
-	var light = new THREE.AmbientLight( 0x404040 );
-	_scene.add( light );
-
-	var light = new THREE.DirectionalLight( 0xffffff );
-	light.position.set( 1000, 1000, - 1000 );
-	light.position.normalize();
-	_scene.add( light );
-	*/
-
-	var _plane = new THREE.Mesh( new THREE.PlaneGeometry( 2000, 2000, 8, 8 ), new THREE.MeshBasicMaterial( { color: 0x000000, opacity: 0.25, transparent: true, wireframe: true } ) );
-	_plane.visible = false;
-	_plane.geometry.applyMatrix( new THREE.Matrix4().makeRotationX( Math.PI / 2 ) );
-
-	_sceneHelpers.add( _plane );
-
-	var _projector = new THREE.Projector();
-
-	var _renderer = new THREE.WebGLRenderer();
-	_renderer.autoClear = false;
-	_renderer.domElement.addEventListener( 'mousedown', function ( event ) {
-
-		event.preventDefault();
-
-		_isMouseDown = true;
-
-		var vector = new THREE.Vector3( ( event.clientX / _width ) * 2 - 1, - ( event.clientY / _height ) * 2 + 1, 0.5 );
-		_projector.unprojectVector( vector, _camera );
-
-		var ray = new THREE.Ray( _camera.position, vector.subSelf( _camera.position ).normalize() );
-		var intersects = ray.intersectObjects( _scene.children );
-
-		if ( intersects.length ) {
-
-			_SELECTED = intersects[ 0 ].object;
-
-			_controls.enabled = false;
-
-			var intersects = ray.intersectObject( _plane );
-			_offset.copy( intersects[ 0 ].point ).subSelf( _plane.position );
-
-		}
-
-	}, false );
-	_renderer.domElement.addEventListener( 'mousemove', function ( event ) {
-
-		event.preventDefault();
-
-		var vector = new THREE.Vector3( ( event.clientX / _width ) * 2 - 1, - ( event.clientY / _height ) * 2 + 1, 0.5 );
-		_projector.unprojectVector( vector, _camera );
-
-		var ray = new THREE.Ray( _camera.position, vector.subSelf( _camera.position ).normalize() );
-		var intersects = ray.intersectObjects( _scene.children );
-
-		if ( _SELECTED ) {
-
-			var intersects = ray.intersectObject( _plane );
-			_SELECTED.position.copy( intersects[ 0 ].point.subSelf( _offset ) );
-
-			switch ( _snapToAxis ) {
-
-				case 'x':
-					_SELECTED.position.y = _plane.position.y;
-					_SELECTED.position.z = _plane.position.z;
-					break;
-
-				case 'y':
-					_SELECTED.position.x = _plane.position.x;
-					_SELECTED.position.z = _plane.position.z;
-					break;
-
-				case 'z':
-					_SELECTED.position.x = _plane.position.x;
-					_SELECTED.position.y = _plane.position.y;
-					break;
-
-			}
-
-			_render();
-
-			signals.updated.dispatch( _scene );
-
-			return;
-
-		}
-
-		if ( intersects.length ) {
-
-			_HOVERED = intersects[ 0 ].object;
-
-			_plane.position.set( 0, 0, 0 );
-			_plane.lookAt( _camera.position );
-			_plane.position.copy( _HOVERED.position );
-
-		} else {
-
-			_HOVERED = null;
-
-		}
-
-		_render();
-
-	}, false );
-	_renderer.domElement.addEventListener( 'mouseup', function ( event ) {
-
-		// event.preventDefault();
-
-		_isMouseDown = false; 
-		_snapToAxis = null;
-
-		_controls.enabled = true;
-
-		if ( _SELECTED ) {
-
-			_plane.position.copy( _SELECTED.position );
-			_SELECTED = null;
-
-		}
-
-	}, false );
-	/*
-	_renderer.domElement.addEventListener( 'mousewheel', function ( event ) {
-
-		if ( event.wheelDeltaY ) {
-
-			event.preventDefault();
-
-			var vector = _camera.position.clone();
-			var amount = event.wheelDeltaY * 0.2;
-
-			if ( vector.length() - amount < 10 ) return;
-
-			vector.normalize().multiplyScalar( amount );
-			_camera.position.subSelf( vector );
-
-			_render();
-
-		}
-
-	}, false );
-	*/
-	document.addEventListener( 'keydown', function ( event ) {
-
-		if ( _isMouseDown ) {
-
-			// console.log( event.keyCode );
-
-			switch ( event.keyCode ) {
-
-				case 88: // x
-					_snapToAxis = 'x';
-					break;
-
-				case 89: // y
-					_snapToAxis = 'y';
-					break;
-
-				case 90: // z
-					_snapToAxis = 'z';
-					break;
-
-			}
-
-		}
-
-	}, false );
-	_domElement.appendChild( _renderer.domElement );
-
-	// signals
-
-	signals.added.add( function ( object ) {
-
-		_scene.add( object );
-		_render();
-
-		signals.updated.dispatch( _scene );
-
-	} );
-
-	//
-
-	this.getDOMElement = function () {
-
-		return _domElement;
-
-	};
-
-	this.setSize = function ( width, height ) {
-
-		_width = width;
-		_height = height;
-
-		_camera.aspect = width / height;
-		_camera.updateProjectionMatrix();
-
-		_renderer.setSize( width, height );
-
-		_render();
-
-	};
-
-	var _render = function () {
-
-		_controls.update();
-
-		_renderer.clear();
-		_renderer.render( _sceneHelpers, _camera );
-		_renderer.render( _scene, _camera );
-
-	};
-
-}

+ 452 - 15
gui/js/UI.js

@@ -1,30 +1,467 @@
-var UI = function () {
+var UI = {};
 
-	var _domElement = document.createElement( 'div' );
-	_domElement.style.position = 'absolute';
+UI.Element = function () {};
 
-	var _viewport = new UI.Viewport();
-	_domElement.appendChild( _viewport.getDOMElement() );
+UI.Element.prototype = {
 
-	var _toolbar = new UI.Toolbar();
-	_domElement.appendChild( _toolbar.getDOMElement() );
+	setStyle: function ( style, array ) {
 
-	this.getDOMElement = function () {
+		for ( var i = 0; i < array.length; i ++ ) {
 
-		return _domElement;
+			this.dom.style[ style ] = array[ i ];
+
+		}
+
+	},
+
+	setLeft: function () {
+
+		this.setStyle( 'left', arguments );
+		return this;
+
+	},
+
+	setTop: function () {
+
+		this.setStyle( 'top', arguments );
+		return this;
+
+	},
+
+	setRight: function () {
+
+		this.setStyle( 'right', arguments );
+		return this;
+
+	},
+
+	setBottom: function () {
+
+		this.setStyle( 'bottom', arguments );
+		return this;
+
+	},
+
+	setWidth: function () {
+
+		this.setStyle( 'width', arguments );
+		return this;
+
+	},
+
+	setHeight: function () {
+
+		this.setStyle( 'height', arguments );
+		return this;
+
+	},
+
+	// border
+
+	setBorder: function () {
+
+		this.setStyle( 'border', arguments );
+		return this;
+
+	},
+
+	setBorderTop: function () {
+
+		this.setStyle( 'borderTop', arguments );
+		return this;
+
+	},
+
+	setBorderBottom: function () {
+
+		this.setStyle( 'borderBottom', arguments );
+		return this;
+
+	},
+
+	setBorderLeft: function () {
+
+		this.setStyle( 'borderLeft', arguments );
+		return this;
+
+	},
+
+	setBorderRight: function () {
+
+		this.setStyle( 'borderRight', arguments );
+		return this;
+
+	},
+
+	// margin
+
+	setMargin: function () {
+
+		this.setStyle( 'margin', arguments );
+		return this;
+
+	},
+
+	setMarginTop: function () {
+
+		this.setStyle( 'marginTop', arguments );
+		return this;
+
+	},
+
+	setMarginBottom: function () {
+
+		this.setStyle( 'marginBottom', arguments );
+		return this;
+
+	},
+
+	setMarginLeft: function () {
+
+		this.setStyle( 'marginLeft', arguments );
+		return this;
+
+	},
+
+	setMarginRight: function () {
+
+		this.setStyle( 'marginRight', arguments );
+		return this;
+
+	},
+
+	// padding
+
+	setPadding: function () {
+
+		this.setStyle( 'padding', arguments );
+		return this;
+
+	},
+
+	//
+
+	setFontSize: function () {
+
+		this.setStyle( 'fontSize', arguments );
+		return this;
+
+	},
+
+	setFontWeight: function () {
+
+		this.setStyle( 'fontWeight', arguments );
+		return this;
+
+	},
+
+	//
+
+	setColor: function () {
+
+		this.setStyle( 'color', arguments );
+		return this;
+
+	},
+
+	setBackgroundColor: function () {
+
+		this.setStyle( 'backgroundColor', arguments );
+		return this;
+
+	},
+
+	setDisplay: function () {
+
+		this.setStyle( 'display', arguments );
+		return this;
 
 	}
 
-	this.setSize = function ( width, height ) {
+}
+
+
+// Panel
+
+UI.Panel = function ( position ) {
+
+	UI.Element.call( this );
+
+	this.dom = document.createElement( 'div' );
+	this.dom.style.position = position || 'relative';
+
+	this.dom.addEventListener( 'mousedown', function ( event ) { event.preventDefault() }, false );
+
+	return this;
+};
+
+UI.Panel.prototype = new UI.Element();
+UI.Panel.prototype.constructor = UI.Panel;
 
-		_domElement.style.width = width + 'px';
-		_domElement.style.height = height + 'px';
+UI.Panel.prototype.add = function () {
 
-		_viewport.setSize( width, height - 50 );
+	for ( var i = 0; i < arguments.length; i ++ ) {
 
-		_toolbar.setPosition( 0, height - 50 );
-		_toolbar.setSize( width, 50 );
+		this.dom.appendChild( arguments[ i ].dom );
 
 	}
 
+	return this;
+
+};
+
+
+// Text
+
+UI.Text = function ( position ) {
+
+	UI.Element.call( this );
+
+	this.dom = document.createElement( 'span' );
+	this.dom.style.position = position || 'relative';
+
+	return this;
+
+};
+
+UI.Text.prototype = new UI.Element();
+UI.Text.prototype.constructor = UI.Text;
+
+UI.Text.prototype.setText = function ( value ) {
+
+	this.dom.textContent = value;
+	return this;
+
+};
+
+
+// IntNumber
+
+UI.IntNumber = function ( position ) {
+
+	UI.Element.call( this );
+
+	this.dom = document.createElement( 'span' );
+	this.dom.style.position = position || 'relative';
+	this.dom.textContent = '0.00';
+	this.dom.style.marginTop = '2px';
+	this.dom.style.color = '#0080f0';
+	this.dom.style.fontSize = '12px';
+	this.dom.style.textDecoration = 'underline';
+
+	this.onChangeCallback = null;
+
+	var scope = this;
+	var onMouseDownValue, onMouseDownScreenX, onMouseDownScreenY;
+
+	var onMouseDown = function ( event ) {
+
+		event.preventDefault();
+
+		onMouseDownValue = parseInt( scope.dom.textContent );
+		onMouseDownScreenX = event.screenX;
+		onMouseDownScreenY = event.screenY;
+
+		document.addEventListener( 'mousemove', onMouseMove, false );
+		document.addEventListener( 'mouseup', onMouseUp, false );
+
+	}
+
+	var onMouseMove = function ( event ) {
+
+		var dx = event.screenX - onMouseDownScreenX;
+		var dy = event.screenY - onMouseDownScreenY;
+
+		scope.dom.textContent = ( onMouseDownValue + ( dx - dy ) / ( event.shiftKey ? 10 : 100 ) ).toFixed( 0 );
+		scope.onChangeCallback();
+
+	}
+
+	var onMouseUp = function ( event ) {
+
+		document.removeEventListener( 'mousemove', onMouseMove, false );
+		document.removeEventListener( 'mouseup', onMouseUp, false );
+
+	}
+
+	this.dom.addEventListener( 'mousedown', onMouseDown, false );
+
+	return this;
+
+};
+
+UI.IntNumber.prototype = new UI.Element();
+UI.IntNumber.prototype.constructor = UI.IntNumber;
+
+UI.IntNumber.prototype.getValue = function () {
+
+	return parseInt( this.dom.textContent );
+
+};
+
+UI.IntNumber.prototype.setValue = function ( value ) {
+
+	this.dom.textContent = value.toFixed( 0 );
+	return this;
+
+};
+
+UI.IntNumber.prototype.onChange = function ( callback ) {
+
+	this.onChangeCallback = callback;
+	return this;
+
+};
+
+
+
+// FloatNumber
+
+UI.FloatNumber = function ( position ) {
+
+	UI.Element.call( this );
+
+	this.dom = document.createElement( 'span' );
+	this.dom.style.position = position || 'relative';
+	this.dom.textContent = '0.00';
+	this.dom.style.marginTop = '2px';
+	this.dom.style.color = '#0080f0';
+	this.dom.style.fontSize = '12px';
+	this.dom.style.textDecoration = 'underline';
+
+	this.onChangeCallback = null;
+
+	var scope = this;
+	var onMouseDownValue, onMouseDownScreenX, onMouseDownScreenY;
+
+	var onMouseDown = function ( event ) {
+
+		event.preventDefault();
+
+		onMouseDownValue = parseFloat( scope.dom.textContent );
+		onMouseDownScreenX = event.screenX;
+		onMouseDownScreenY = event.screenY;
+
+		document.addEventListener( 'mousemove', onMouseMove, false );
+		document.addEventListener( 'mouseup', onMouseUp, false );
+
+	}
+
+	var onMouseMove = function ( event ) {
+
+		var dx = event.screenX - onMouseDownScreenX;
+		var dy = event.screenY - onMouseDownScreenY;
+
+		scope.dom.textContent = ( onMouseDownValue + ( dx - dy ) / ( event.shiftKey ? 10 : 100 ) ).toFixed( 2 );
+		scope.onChangeCallback();
+
+	}
+
+	var onMouseUp = function ( event ) {
+
+		document.removeEventListener( 'mousemove', onMouseMove, false );
+		document.removeEventListener( 'mouseup', onMouseUp, false );
+
+	}
+
+	this.dom.addEventListener( 'mousedown', onMouseDown, false );
+
+	return this;
+
+};
+
+UI.FloatNumber.prototype = new UI.Element();
+UI.FloatNumber.prototype.constructor = UI.FloatNumber;
+
+UI.FloatNumber.prototype.getValue = function () {
+
+	return parseFloat( this.dom.textContent );
+
+};
+
+UI.FloatNumber.prototype.setValue = function ( value ) {
+
+	this.dom.textContent = value.toFixed( 2 );
+	return this;
+
+};
+
+UI.FloatNumber.prototype.onChange = function ( callback ) {
+
+	this.onChangeCallback = callback;
+	return this;
+
+};
+
+
+// Break
+
+UI.Break = function () {
+
+	UI.Element.call( this );
+
+	this.dom = document.createElement( 'br' );
+
+	return this;
+
+};
+
+UI.Break.prototype = new UI.Element();
+UI.Break.prototype.constructor = UI.Break;
+
+
+// HorizontalRule
+
+UI.HorizontalRule = function ( position ) {
+
+	UI.Element.call( this );
+
+	this.dom = document.createElement( 'hr' );
+	this.dom.style.position = position || 'relative';
+
+	return this;
+
+};
+
+UI.HorizontalRule.prototype = new UI.Element();
+UI.HorizontalRule.prototype.constructor = UI.HorizontalRule;
+
+// Button
+
+UI.Button = function ( position ) {
+
+	UI.Element.call( this );
+
+	this.dom = document.createElement( 'button' );
+	this.dom.style.position = position || 'relative';
+
+	this.onClickCallback = null;
+
+	var scope = this;
+
+	this.dom.addEventListener( 'click', function ( event ) {
+
+		scope.onClickCallback();
+
+	}, false );
+
+	return this;
+
+};
+
+UI.Button.prototype = new UI.Element();
+UI.Button.prototype.constructor = UI.Button;
+
+UI.Button.prototype.setText = function ( value ) {
+
+	this.dom.textContent = value;
+	return this;
+
+};
+
+UI.Button.prototype.onClick = function ( callback ) {
+
+	this.onClickCallback = callback;
+	return this;
+
 };

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 7
gui/js/libs/signals.min.js


+ 14 - 0
gui/js/ui/MenuBar.js

@@ -0,0 +1,14 @@
+var MenuBar = function ( signals ) {
+
+	var container = new UI.Panel( 'absolute' );
+	container.setBackgroundColor( '#eee' );
+
+	var options = new UI.Panel();
+	options.setMargin( '8px' );
+	options.add( new UI.Text().setText( 'File' ).setColor( '#666' ).setMarginRight( '10px' ) );
+	options.add( new UI.Text().setText( 'About' ).setColor( '#666' ).setMarginRight( '10px' ) );
+	container.add( options );
+
+	return container;
+
+}

+ 15 - 0
gui/js/ui/Sidebar.Outliner.js

@@ -0,0 +1,15 @@
+Sidebar.Outliner = function ( signals ) {
+
+	var selected = null;
+
+	var container = new UI.Panel();
+	container.setPadding( '8px' );
+	container.setBorderTop( '1px solid #ccc' );
+
+	container.add( new UI.Text().setText( 'SCENE' ).setColor( '#666' ) );
+
+	container.add( new UI.Break(), new UI.Break() );
+
+	return container;
+
+}

+ 267 - 0
gui/js/ui/Sidebar.Properties.Geometry.js

@@ -0,0 +1,267 @@
+Sidebar.Properties.Geometry = function ( signals ) {
+
+	var container = new UI.Panel();
+	container.setDisplay( 'none' );
+
+	container.add( new UI.Text().setText( 'GEOMETRY' ).setColor( '#666' ) );
+
+	var button = new UI.Button( 'absolute' ).setRight( '0px' ).setText( 'Export' ).onClick( exportGeometry );
+	button.download = 'test.js';
+	container.add( button );
+
+	container.add( new UI.Break(), new UI.Break() );
+
+	container.add( new UI.Text().setText( 'Name' ).setColor( '#666' ) );
+
+	var geometryName = new UI.Text( 'absolute' ).setLeft( '90px' ).setColor( '#444' ).setFontSize( '12px' );
+
+	container.add( geometryName );
+
+	container.add( new UI.HorizontalRule() );
+
+	container.add( new UI.Text().setText( 'Class' ).setColor( '#666' ) );
+
+	var geometryClass = new UI.Text( 'absolute' ).setLeft( '90px' ).setColor( '#444' ).setFontSize( '12px' );
+	container.add( geometryClass );
+
+	container.add( new UI.HorizontalRule() );
+
+	container.add( new UI.Text().setText( 'Vertices' ).setColor( '#666' ) );
+	
+	var verticesCount = new UI.Text( 'absolute' ).setLeft( '90px' ).setColor( '#444' ).setFontSize( '12px' );
+	container.add( verticesCount );
+
+	container.add( new UI.HorizontalRule() );
+
+	container.add( new UI.Text().setText( 'Faces' ).setColor( '#666' ) );
+
+	var facesCount = new UI.Text( 'absolute' ).setLeft( '90px' ).setColor( '#444' ).setFontSize( '12px' );
+	container.add( facesCount );
+
+	container.add( new UI.Break(), new UI.Break(), new UI.Break() );
+
+	//
+
+	var selected = null;
+
+	signals.objectSelected.add( function ( object ) {
+
+		if ( object && object.geometry ) {
+
+			selected = object.geometry;
+
+			container.setDisplay( 'block' );
+
+			geometryName.setText( object.geometry.name );
+			geometryClass.setText( getGeometryInstanceName( object.geometry ) );
+			verticesCount.setText( object.geometry.vertices.length );
+			facesCount.setText( object.geometry.faces.length );
+
+		} else {
+
+			selected = null;
+
+			container.setDisplay( 'none' );
+
+		}
+
+	} );
+
+	function getGeometryInstanceName( geometry ) {
+
+		// TODO: Is there a way of doing this automatically?
+
+		if ( geometry instanceof THREE.ConvexGeometry ) return "ConvexGeometry";
+		if ( geometry instanceof THREE.CubeGeometry ) return "CubeGeometry";
+		if ( geometry instanceof THREE.CylinderGeometry ) return "CylinderGeometry";
+		if ( geometry instanceof THREE.ExtrudeGeometry ) return "ExtrudeGeometry";
+		if ( geometry instanceof THREE.IcosahedronGeometry ) return "IcosahedronGeometry";
+		if ( geometry instanceof THREE.LatheGeometry ) return "LatheGeometry";
+		if ( geometry instanceof THREE.OctahedronGeometry ) return "OctahedronGeometry";
+		if ( geometry instanceof THREE.ParametricGeometry ) return "ParametricGeometry";
+		if ( geometry instanceof THREE.PlaneGeometry ) return "PlaneGeometry";
+		if ( geometry instanceof THREE.PolyhedronGeometry ) return "PolyhedronGeometry";
+		if ( geometry instanceof THREE.SphereGeometry ) return "SphereGeometry";
+		if ( geometry instanceof THREE.TetrahedronGeometry ) return "TetrahedronGeometry";
+		if ( geometry instanceof THREE.TextGeometry ) return "TextGeometry";
+		if ( geometry instanceof THREE.TorusGeometry ) return "TorusGeometry";
+		if ( geometry instanceof THREE.TorusKnotGeometry ) return "TorusKnotGeometry";
+		if ( geometry instanceof THREE.TubeGeometry ) return "TubeGeometry";
+		if ( geometry instanceof THREE.Geometry ) return "Geometry";
+
+	}
+
+	function exportGeometry() {
+
+		var geometry = selected;
+
+		var vertices = [];
+
+		for ( var i = 0; i < geometry.vertices.length; i ++ ) {
+
+			var vertex = geometry.vertices[ i ];
+			vertices.push( vertex.x, vertex.y, vertex.z );
+
+		}
+
+		var faces = [];
+		var uvs = [[]];
+		var normals = [];
+
+		for ( var i = 0; i < geometry.faces.length; i ++ ) {
+
+			var face = geometry.faces[ i ];
+
+			var isTriangle = face instanceof THREE.Face3;
+			var hasMaterial = face.materialIndex !== undefined;
+			var hasFaceUv = geometry.faceUvs[ 0 ][ i ] !== undefined;
+			var hasFaceVertexUv = geometry.faceVertexUvs[ 0 ][ i ] !== undefined;
+			var hasFaceNormal = face.normal.length() > 0;
+			var hasFaceVertexNormal = face.vertexNormals[ 0 ] !== undefined;
+			var hasFaceColor = face.color;
+			var hasFaceVertexColor = face.vertexColors[ 0 ] !== undefined;
+
+			var faceType = 0
+			faceType = setBit( faceType, 0, ! isTriangle );
+			/*
+			faceType = setBit( faceType, 1, hasMaterial );
+			faceType = setBit( faceType, 2, hasFaceUv );
+			faceType = setBit( faceType, 3, hasFaceVertexUv );
+			faceType = setBit( faceType, 4, hasFaceNormal );
+			faceType = setBit( faceType, 5, hasFaceVertexNormal );
+			faceType = setBit( faceType, 6, hasFaceColor );
+			faceType = setBit( faceType, 7, hasFaceVertexColor );
+			*/
+
+			faces.push( faceType );
+
+			if ( isTriangle ) {
+
+				faces.push( face.a, face.b, face.c );
+
+			} else {
+
+				faces.push( face.a, face.b, face.c, face.d );
+
+			}
+
+			if ( hasMaterial ) {
+
+				faces.push( face.materialIndex );
+
+			}
+
+			if ( hasFaceUv ) {
+
+				/*
+				var uv = geometry.faceUvs[ 0 ][ i ];
+				uvs[ 0 ].push( uv.u, uv.v );
+				*/
+
+			}
+
+			if ( hasFaceVertexUv ) {
+
+				/*
+				var uvs = geometry.faceVertexUvs[ 0 ][ i ];
+
+				if ( isTriangle ) {
+
+					faces.push(
+						uvs[ 0 ].u, uvs[ 0 ].v,
+						uvs[ 1 ].u, uvs[ 1 ].v,
+						uvs[ 2 ].u, uvs[ 2 ].v
+					);
+
+				} else {
+
+					faces.push(
+						uvs[ 0 ].u, uvs[ 0 ].v,
+						uvs[ 1 ].u, uvs[ 1 ].v,
+						uvs[ 2 ].u, uvs[ 2 ].v,
+						uvs[ 3 ].u, uvs[ 3 ].v
+					);
+
+				}
+				*/
+
+			}
+
+			if ( hasFaceNormal ) {
+
+				/*
+				var normal = face.normal;
+				faces.push( normal.x, normal.y, normal.z );
+				*/
+
+			}
+
+			if ( hasFaceVertexNormal ) {
+
+				/*
+				var normals = face.vertexNormals;
+
+				if ( isTriangle ) {
+
+					faces.push(
+						normals[ 0 ].u, normals[ 0 ].y, normals[ 0 ].z,
+						normals[ 1 ].u, normals[ 1 ].y, normals[ 1 ].z,
+						normals[ 2 ].u, normals[ 2 ].y, normals[ 2 ].z
+					);
+
+				} else {
+
+					faces.push(
+						normals[ 0 ].x, normals[ 0 ].y, normals[ 0 ].z,
+						normals[ 1 ].x, normals[ 1 ].y, normals[ 1 ].z,
+						normals[ 2 ].x, normals[ 2 ].y, normals[ 2 ].z,
+						normals[ 3 ].x, normals[ 3 ].y, normals[ 3 ].z
+					);
+
+				}
+				*/
+
+			}
+
+		}
+
+		function setBit( value, position, enabled ) {
+
+			return enabled ? value | ( 1 << position ) : value & ( ~ ( 1 << position) );
+
+		}
+
+		//
+
+		var output = [
+			'{',
+			'	"metadata": {',
+			'		"formatVersion" : 3',
+			'	},',
+			'	"vertices": ' + JSON.stringify( vertices ) + ',',
+			'	"normals": ' + JSON.stringify( normals ) + ',',
+			'	"uvs": ' + JSON.stringify( uvs ) + ',',
+			'	"faces": ' + JSON.stringify( faces ),
+			'}'
+		].join( '\n' );
+
+		var file = new BlobBuilder();
+		file.append( output );
+
+		var objectURL = URL.createObjectURL( file.getBlob( 'text/json' ) );
+
+		var clickEvent = document.createEvent( 'MouseEvent' );
+		clickEvent.initMouseEvent( 'click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null );
+
+		var download = document.createElement( 'a' );
+		download.href = objectURL;
+		download.download = 'geometry.js';
+		download.dispatchEvent( clickEvent );
+
+		URL.revokeObjectURL( objectURL );
+
+	}
+
+	return container;
+
+}

+ 73 - 0
gui/js/ui/Sidebar.Properties.Material.js

@@ -0,0 +1,73 @@
+Sidebar.Properties.Material = function ( signals ) {
+
+	var container = new UI.Panel();
+	container.setDisplay( 'none' );
+
+	container.add( new UI.Text().setText( 'MATERIAL' ).setColor( '#666' ) );
+
+	container.add( new UI.Break(), new UI.Break() );
+
+	container.add( new UI.Text().setText( 'Name' ).setColor( '#666' ) );
+
+	var materialName = new UI.Text( 'absolute' ).setLeft( '90px' ).setColor( '#444' ).setFontSize( '12px' );
+
+	container.add( materialName );
+
+	container.add( new UI.HorizontalRule() );
+
+	container.add( new UI.Text().setText( 'Class' ).setColor( '#666' ) );
+
+	var materialClass = new UI.Text( 'absolute' ).setLeft( '90px' ).setColor( '#444' ).setFontSize( '12px' );
+
+	container.add( materialClass );
+
+	container.add( new UI.HorizontalRule() );
+
+	container.add( new UI.Text().setText( 'Color' ).setColor( '#666' ) );
+
+	var materialColor = new UI.Text( 'absolute' ).setLeft( '90px' ).setColor( '#444' ).setFontSize( '12px' );
+
+	container.add( materialColor );
+
+	//
+
+	signals.objectSelected.add( function ( object ) {
+
+		if ( object && object.material ) {
+
+			container.setDisplay( 'block' );
+
+			materialName.setText( object.material.name );
+			materialClass.setText( getMaterialInstanceName( object.material ) );
+			materialColor.setText( '#' + object.material.color.getHex().toString(16) );
+
+		} else {
+
+			container.setDisplay( 'none' );
+
+		}
+
+	} );
+
+	function getMaterialInstanceName( material ) {
+
+		// TODO: Is there a way of doing this automatically?
+
+		if ( material instanceof THREE.LineBasicMaterial ) return "LineBasicMaterial";
+		if ( material instanceof THREE.MeshBasicMaterial ) return "MeshBasicMaterial";
+		if ( material instanceof THREE.MeshDepthMaterial ) return "MeshDepthMaterial";
+		if ( material instanceof THREE.MeshFaceMaterial ) return "MeshFaceMaterial";
+		if ( material instanceof THREE.MeshLambertMaterial ) return "MeshLambertMaterial";
+		if ( material instanceof THREE.MeshNormalMaterial ) return "MeshNormalMaterial";
+		if ( material instanceof THREE.MeshPhongMaterial ) return "MeshPhongMaterial";
+		if ( material instanceof THREE.ParticleBasicMaterial ) return "ParticleBasicMaterial";
+		if ( material instanceof THREE.ParticleCanvasMaterial ) return "ParticleCanvasMaterial";
+		if ( material instanceof THREE.ParticleDOMMaterial ) return "ParticleDOMMaterial";
+		if ( material instanceof THREE.ShaderMaterial ) return "ShaderMaterial";
+		if ( material instanceof THREE.Material ) return "Material";
+
+	}
+
+	return container;
+
+}

+ 106 - 0
gui/js/ui/Sidebar.Properties.Object3D.js

@@ -0,0 +1,106 @@
+Sidebar.Properties.Object3D = function ( signals ) {
+
+	var selected = null;
+
+	var container = new UI.Panel();
+	container.setDisplay( 'none' );
+
+	container.add( new UI.Text().setText( 'OBJECT' ).setColor( '#666' ) );
+
+	container.add( new UI.Break(), new UI.Break() );
+
+	container.add( new UI.Text().setText( 'Name' ).setColor( '#666' ) );
+
+	var objectName = new UI.Text( 'absolute' ).setLeft( '90px' ).setColor( '#444' ).setFontSize( '12px' );
+
+	container.add( objectName );
+
+	container.add( new UI.HorizontalRule() );
+
+	container.add( new UI.Text().setText( 'Position' ).setColor( '#666' ) );
+
+	var positionX = new UI.FloatNumber( 'absolute' ).setLeft( '90px' ).onChange( update );
+	var positionY = new UI.FloatNumber( 'absolute' ).setLeft( '160px' ).onChange( update );
+	var positionZ = new UI.FloatNumber( 'absolute' ).setLeft( '230px' ).onChange( update );
+
+	container.add( positionX, positionY, positionZ );
+
+	container.add( new UI.HorizontalRule() );
+
+	container.add( new UI.Text().setText( 'Rotation' ).setColor( '#666' ) );
+
+	var rotationX = new UI.FloatNumber( 'absolute' ).setLeft( '90px' ).onChange( update );
+	var rotationY = new UI.FloatNumber( 'absolute' ).setLeft( '160px' ).onChange( update );
+	var rotationZ = new UI.FloatNumber( 'absolute' ).setLeft( '230px' ).onChange( update );
+
+	container.add( rotationX, rotationY, rotationZ );
+
+	container.add( new UI.HorizontalRule() );
+
+	container.add( new UI.Text().setText( 'Scale' ).setColor( '#666' ) );
+
+	var scaleX = new UI.FloatNumber( 'absolute' ).setValue( 1 ).setLeft( '90px' ).onChange( update );
+	var scaleY = new UI.FloatNumber( 'absolute' ).setValue( 1 ).setLeft( '160px' ).onChange( update );
+	var scaleZ = new UI.FloatNumber( 'absolute' ).setValue( 1 ).setLeft( '230px' ).onChange( update );
+
+	container.add( scaleX, scaleY, scaleZ );
+
+	container.add( new UI.Break(), new UI.Break(), new UI.Break() );
+
+	//
+
+	function update() {
+
+		if ( selected ) {
+
+			selected.position.x = positionX.getValue();
+			selected.position.y = positionY.getValue();
+			selected.position.z = positionZ.getValue();
+
+			selected.rotation.x = rotationX.getValue();
+			selected.rotation.y = rotationY.getValue();
+			selected.rotation.z = rotationZ.getValue();
+
+			selected.scale.x = scaleX.getValue();
+			selected.scale.y = scaleY.getValue();
+			selected.scale.z = scaleZ.getValue();
+
+			signals.objectChanged.dispatch( selected );
+
+		}
+
+	}
+
+	signals.objectSelected.add( function ( object ) {
+
+		selected = object;
+
+		if ( object ) {
+
+			container.setDisplay( 'block' );
+
+			objectName.setText( object.name );
+
+			positionX.setValue( object.position.x );
+			positionY.setValue( object.position.y );
+			positionZ.setValue( object.position.z );
+
+			rotationX.setValue( object.rotation.x );
+			rotationY.setValue( object.rotation.y );
+			rotationZ.setValue( object.rotation.z );
+
+			scaleX.setValue( object.scale.x );
+			scaleY.setValue( object.scale.y );
+			scaleZ.setValue( object.scale.z );
+
+		} else {
+
+			container.setDisplay( 'none' );
+
+		}
+
+	} );
+
+	return container;
+
+}

+ 13 - 0
gui/js/ui/Sidebar.Properties.js

@@ -0,0 +1,13 @@
+Sidebar.Properties = function ( signals ) {
+
+	var container = new UI.Panel();
+	container.setPadding( '8px' );
+	container.setBorderTop( '1px solid #ccc' );
+
+	container.add( new Sidebar.Properties.Object3D( signals ) );
+	container.add( new Sidebar.Properties.Geometry( signals ) );
+	container.add( new Sidebar.Properties.Material( signals ) );
+
+	return container;
+
+}

+ 15 - 0
gui/js/ui/Sidebar.js

@@ -0,0 +1,15 @@
+var Sidebar = function ( signals ) {
+
+	var container = new UI.Panel( 'absolute' );
+	container.setWidth( '300px' ).setHeight( '100%' );
+	container.setBackgroundColor( '#eee' );
+
+	var outliner = new Sidebar.Outliner( signals );
+	container.add( outliner );
+
+	var properties = new Sidebar.Properties( signals );
+	container.add( properties );
+
+	return container;
+
+}

+ 229 - 0
gui/js/ui/Viewport.js

@@ -0,0 +1,229 @@
+var Viewport = function ( signals ) {
+
+	var container = new UI.Panel( 'absolute' );
+	container.setBackgroundColor( '#aaa' );
+
+	//
+
+	var objects = [];
+
+	var sceneHelpers = new THREE.Scene();
+
+	var size = 500, step = 25;
+	var geometry = new THREE.Geometry();
+	var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } );
+	var color1 = new THREE.Color( 0x444444 ), color2 = new THREE.Color( 0x888888 );
+
+	for ( var i = - size; i <= size; i += step ) {
+
+		geometry.vertices.push( new THREE.Vector3( -size, 0, i ) );
+		geometry.vertices.push( new THREE.Vector3(  size, 0, i ) );
+
+		geometry.vertices.push( new THREE.Vector3( i, 0, -size ) );
+		geometry.vertices.push( new THREE.Vector3( i, 0,  size ) );
+
+		var color = i === 0 ? color1 : color2;
+
+		geometry.colors.push( color, color, color, color );
+
+	}
+
+	var grid = new THREE.Line( geometry, material, THREE.LinePieces );
+	sceneHelpers.add( grid );
+
+	var selectionBox = new THREE.Mesh( new THREE.CubeGeometry( 1, 1, 1 ), new THREE.MeshBasicMaterial( { color: 0xffff00, wireframe: true } ) );
+	selectionBox.geometry.dynamic = true;
+	selectionBox.matrixAutoUpdate = false;
+	selectionBox.visible = false;
+	sceneHelpers.add( selectionBox );
+
+	//
+
+	var scene = new THREE.Scene();
+
+	var camera = new THREE.PerspectiveCamera( 50, 1, 1, 5000 );
+	camera.position.set( 500, 250, 500 );
+	camera.lookAt( scene.position );
+	scene.add( camera );
+
+	var controls = new THREE.TrackballControls( camera, container.dom );
+	controls.rotateSpeed = 1.0;
+	controls.zoomSpeed = 1.2;
+	controls.panSpeed = 0.8;
+	controls.noZoom = false;
+	controls.noPan = false;
+	controls.staticMoving = true;
+	controls.dynamicDampingFactor = 0.3;
+	controls.addEventListener( 'change', render );
+
+	var light = new THREE.DirectionalLight( 0xffffff );
+	light.position.set( 1, 0.5, 0 ).normalize();
+	scene.add( light );
+
+	var light = new THREE.DirectionalLight( 0xffffff, 0.5 );
+	light.position.set( - 1, - 0.5, 0 ).normalize();
+	scene.add( light );
+
+
+	// object picking
+
+	var projector = new THREE.Projector();
+
+	container.dom.addEventListener( 'mousedown', function ( event ) {
+
+		event.preventDefault();
+
+		var vector = new THREE.Vector3(
+			( ( event.clientX - container.dom.offsetLeft ) / container.dom.offsetWidth ) * 2 - 1,
+			- ( ( event.clientY - container.dom.offsetTop ) / container.dom.offsetHeight ) * 2 + 1,
+			0.5
+		);
+		projector.unprojectVector( vector, camera );
+
+		var ray = new THREE.Ray( camera.position, vector.subSelf( camera.position ).normalize() );
+		var intersects = ray.intersectObjects( objects );
+
+		if ( intersects.length ) {
+
+			signals.objectSelected.dispatch( intersects[ 0 ].object );
+
+			// controls.enabled = false;
+
+		} else {
+
+			signals.objectSelected.dispatch( null );
+
+		}
+
+	}, false );
+
+	// events
+
+	signals.objectAdded.add( function ( object ) {
+
+		THREE.SceneUtils.traverseHierarchy( object, function ( child ) {
+
+			objects.push( child );
+
+		} );
+
+		objects.push( object );
+
+		scene.add( object );
+		render();
+
+	} );
+
+	signals.objectChanged.add( function ( object ) {
+
+		selectionBox.matrixWorld.copy( object.matrixWorld );
+
+		render();
+
+	} );
+
+	signals.objectSelected.add( function ( object ) {
+
+		if ( object === null ) {
+
+			selectionBox.visible = false;
+
+		} else if ( object.geometry ) {
+
+			var geometry = object.geometry;
+
+			if ( geometry.boundingBox === null ) {
+
+				geometry.computeBoundingBox();
+
+			}
+
+			selectionBox.geometry.vertices[ 0 ].x = geometry.boundingBox.max.x;
+			selectionBox.geometry.vertices[ 0 ].y = geometry.boundingBox.max.y;
+			selectionBox.geometry.vertices[ 0 ].z = geometry.boundingBox.max.z;
+
+			selectionBox.geometry.vertices[ 1 ].x = geometry.boundingBox.max.x;
+			selectionBox.geometry.vertices[ 1 ].y = geometry.boundingBox.max.y;
+			selectionBox.geometry.vertices[ 1 ].z = geometry.boundingBox.min.z;
+
+			selectionBox.geometry.vertices[ 2 ].x = geometry.boundingBox.max.x;
+			selectionBox.geometry.vertices[ 2 ].y = geometry.boundingBox.min.y;
+			selectionBox.geometry.vertices[ 2 ].z = geometry.boundingBox.max.z;
+
+			selectionBox.geometry.vertices[ 3 ].x = geometry.boundingBox.max.x;
+			selectionBox.geometry.vertices[ 3 ].y = geometry.boundingBox.min.y;
+			selectionBox.geometry.vertices[ 3 ].z = geometry.boundingBox.min.z;
+
+			selectionBox.geometry.vertices[ 4 ].x = geometry.boundingBox.min.x;
+			selectionBox.geometry.vertices[ 4 ].y = geometry.boundingBox.max.y;
+			selectionBox.geometry.vertices[ 4 ].z = geometry.boundingBox.min.z;
+
+			selectionBox.geometry.vertices[ 5 ].x = geometry.boundingBox.min.x;
+			selectionBox.geometry.vertices[ 5 ].y = geometry.boundingBox.max.y;
+			selectionBox.geometry.vertices[ 5 ].z = geometry.boundingBox.max.z;
+
+			selectionBox.geometry.vertices[ 6 ].x = geometry.boundingBox.min.x;
+			selectionBox.geometry.vertices[ 6 ].y = geometry.boundingBox.min.y;
+			selectionBox.geometry.vertices[ 6 ].z = geometry.boundingBox.min.z;
+
+			selectionBox.geometry.vertices[ 7 ].x = geometry.boundingBox.min.x;
+			selectionBox.geometry.vertices[ 7 ].y = geometry.boundingBox.min.y;
+			selectionBox.geometry.vertices[ 7 ].z = geometry.boundingBox.max.z;
+
+			selectionBox.geometry.computeBoundingSphere();
+
+			selectionBox.geometry.verticesNeedUpdate = true;
+
+			selectionBox.matrixWorld.copy( object.matrixWorld );
+
+			selectionBox.visible = true;
+
+		}
+
+		render();
+
+	} );
+
+	signals.windowResize.add( function () {
+
+		camera.aspect = container.dom.offsetWidth / container.dom.offsetHeight;
+		camera.updateProjectionMatrix();
+
+		renderer.setSize( container.dom.offsetWidth, container.dom.offsetHeight );
+
+		render();
+
+	} );
+
+	//
+
+	var renderer = new THREE.WebGLRenderer( { antialias: true, alpha: false, clearColor: 0xaaaaaa, clearAlpha: 1 } );
+	renderer.autoClear = false;
+	renderer.autoUpdateScene = false;
+	container.dom.appendChild( renderer.domElement );
+
+	animate();
+
+	//
+
+	function animate() {
+
+		requestAnimationFrame( animate );
+		controls.update();
+
+	}
+
+	function render() {
+
+		scene.updateMatrixWorld();
+		sceneHelpers.updateMatrixWorld();
+
+		renderer.clear();
+		renderer.render( scene, camera );
+		renderer.render( sceneHelpers, camera );
+
+	}
+
+	return container;
+
+}

+ 15 - 1
src/Three.js

@@ -2,7 +2,21 @@
  * @author mr.doob / http://mrdoob.com/
  */
 
-var THREE = THREE || { REVISION: '49' };
+var THREE = THREE || { REVISION: '50dev' };
+
+if ( ! self.console ) {
+
+	self.console = {
+
+		info: function () {},
+		log: function () {},
+		debug: function () {},
+		warn: function () {},
+		error: function () {}
+
+	};
+
+}
 
 if ( ! self.Int32Array ) {
 

+ 1 - 1
src/cameras/Camera.js

@@ -25,7 +25,7 @@ THREE.Camera.prototype.lookAt = function ( vector ) {
 
 	if ( this.rotationAutoUpdate ) {
 
-		this.rotation.getRotationFromMatrix( this.matrix );
+		this.rotation.setEulerFromRotationMatrix( this.matrix, this.eulerOrder );
 
 	}
 

+ 1 - 1
src/extras/core/EventTarget.js → src/core/EventTarget.js

@@ -8,7 +8,7 @@ THREE.EventTarget = function () {
 
 	this.addEventListener = function ( type, listener ) {
 
-		if ( listeners[ type ] == undefined ) {
+		if ( listeners[ type ] === undefined ) {
 
 			listeners[ type ] = [];
 

+ 2 - 0
src/core/Geometry.js

@@ -10,6 +10,8 @@ THREE.Geometry = function () {
 
 	this.id = THREE.GeometryCount ++;
 
+	this.name = '';
+
 	this.vertices = [];
 	this.colors = []; // one-to-one vertex colors, used in ParticleSystem, Line and Ribbon
 

+ 19 - 2
src/core/Object3D.js

@@ -61,7 +61,10 @@ THREE.Object3D.prototype = {
 		this.matrix.multiply( matrix, this.matrix );
 
 		this.scale.getScaleFromMatrix( this.matrix );
-		this.rotation.getRotationFromMatrix( this.matrix, this.scale );
+		
+		var mat = new THREE.Matrix4().extractRotation( this.matrix );
+		this.rotation.setEulerFromRotationMatrix( mat, this.eulerOrder );
+		
 		this.position.getPositionFromMatrix( this.matrix );
 
 	},
@@ -99,7 +102,7 @@ THREE.Object3D.prototype = {
 
 		if ( this.rotationAutoUpdate ) {
 
-			this.rotation.getRotationFromMatrix( this.matrix );
+			this.rotation.setEulerFromRotationMatrix( this.matrix, this.eulerOrder );
 
 		}
 
@@ -263,8 +266,22 @@ THREE.Object3D.prototype = {
 
 		}
 
+	},
+
+	worldToLocal: function ( vector ) {
+
+		return THREE.Object3D.__m1.getInverse( this.matrixWorld ).multiplyVector3( vector );
+
+	},
+
+	localToWorld: function ( vector ) {
+
+		return this.matrixWorld.multiplyVector3( vector );
+
 	}
 
 };
 
+THREE.Object3D.__m1 = new THREE.Matrix4();
+
 THREE.Object3DCount = 0;

+ 208 - 51
src/core/Quaternion.js

@@ -1,6 +1,7 @@
 /**
  * @author mikael emtinger / http://gomo.se/
  * @author alteredq / http://alteredqualia.com/
+ * @author WestLangley / http://github.com/WestLangley
  */
 
 THREE.Quaternion = function( x, y, z, w ) {
@@ -38,28 +39,79 @@ THREE.Quaternion.prototype = {
 
 	},
 
-	setFromEuler: function ( vector ) {
-
-		var c = Math.PI / 360, // 0.5 * Math.PI / 360, // 0.5 is an optimization
-		x = vector.x * c,
-		y = vector.y * c,
-		z = vector.z * c,
-
-		c1 = Math.cos( y  ),
-		s1 = Math.sin( y  ),
-		c2 = Math.cos( -z ),
-		s2 = Math.sin( -z ),
-		c3 = Math.cos( x  ),
-		s3 = Math.sin( x  ),
-
-		c1c2 = c1 * c2,
-		s1s2 = s1 * s2;
-
-		this.w = c1c2 * c3  - s1s2 * s3;
-	  	this.x = c1c2 * s3  + s1s2 * c3;
-		this.y = s1 * c2 * c3 + c1 * s2 * s3;
-		this.z = c1 * s2 * c3 - s1 * c2 * s3;
-
+	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 _order = order || 'XYZ',
+		
+			c1 = Math.cos( v.x / 2 ),
+			c2 = Math.cos( v.y / 2 ),
+			c3 = Math.cos( v.z / 2 ),
+			s1 = Math.sin( v.x / 2 ),
+			s2 = Math.sin( v.y / 2 ),
+			s3 = Math.sin( v.z / 2 );
+				
+		switch ( _order ) {
+	
+			case '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;
+	
+				break;
+				
+			case '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;
+	
+				break;
+				
+			case '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;
+	
+				break;
+				
+			case '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;
+	
+				break;
+				
+			case '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;
+	
+				break;
+				
+			default: // '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;
+		
+				break;
+				
+		}
+		
 		return this;
 
 	},
@@ -83,24 +135,57 @@ THREE.Quaternion.prototype = {
 
 	setFromRotationMatrix: function ( m ) {
 
-		// Adapted from: http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
-
-		function copySign( a, b ) {
-
-			return b < 0 ? -Math.abs( a ) : Math.abs( a );
-
+		// 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;
+		
 		}
-
-		var absQ = Math.pow( m.determinant(), 1.0 / 3.0 );
-		this.w = Math.sqrt( Math.max( 0, absQ + m.elements[0] + m.elements[5] + m.elements[10] ) ) / 2;
-		this.x = Math.sqrt( Math.max( 0, absQ + m.elements[0] - m.elements[5] - m.elements[10] ) ) / 2;
-		this.y = Math.sqrt( Math.max( 0, absQ - m.elements[0] + m.elements[5] - m.elements[10] ) ) / 2;
-		this.z = Math.sqrt( Math.max( 0, absQ - m.elements[0] - m.elements[5] + m.elements[10] ) ) / 2;
-		this.x = copySign( this.x, ( m.elements[6] - m.elements[9] ) );
-		this.y = copySign( this.y, ( m.elements[8] - m.elements[2] ) );
-		this.z = copySign( this.z, ( m.elements[1] - m.elements[4] ) );
-		this.normalize();
-
+	
 		return this;
 
 	},
@@ -206,6 +291,66 @@ THREE.Quaternion.prototype = {
 
 	},
 
+	slerpSelf: 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;
+
+	},
+
 	clone: function () {
 
 		return new THREE.Quaternion( this.x, this.y, this.z, this.w );
@@ -220,36 +365,48 @@ THREE.Quaternion.slerp = function ( qa, qb, qm, t ) {
 
 	var cosHalfTheta = qa.w * qb.w + qa.x * qb.x + qa.y * qb.y + qa.z * qb.z;
 
-	if (cosHalfTheta < 0) {
-		qm.w = -qb.w; qm.x = -qb.x; qm.y = -qb.y; qm.z = -qb.z;
+	if ( cosHalfTheta < 0 ) {
+
+		qm.w = -qb.w;
+		qm.x = -qb.x;
+		qm.y = -qb.y;
+		qm.z = -qb.z;
+
 		cosHalfTheta = -cosHalfTheta;
+
 	} else {
-		qm.copy(qb);
+
+		qm.copy( qb );
+
 	}
 
 	if ( Math.abs( cosHalfTheta ) >= 1.0 ) {
 
-		qm.w = qa.w; qm.x = qa.x; qm.y = qa.y; qm.z = qa.z;
+		qm.w = qa.w;
+		qm.x = qa.x;
+		qm.y = qa.y;
+		qm.z = qa.z;
+
 		return qm;
 
 	}
 
-	var halfTheta = Math.acos( cosHalfTheta ),
-	sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta );
+	var halfTheta = Math.acos( cosHalfTheta );
+	var sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta );
 
 	if ( Math.abs( sinHalfTheta ) < 0.001 ) {
 
-		qm.w = 0.5 * ( qa.w + qb.w );
-		qm.x = 0.5 * ( qa.x + qb.x );
-		qm.y = 0.5 * ( qa.y + qb.y );
-		qm.z = 0.5 * ( qa.z + qb.z );
+		qm.w = 0.5 * ( qa.w + qm.w );
+		qm.x = 0.5 * ( qa.x + qm.x );
+		qm.y = 0.5 * ( qa.y + qm.y );
+		qm.z = 0.5 * ( qa.z + qm.z );
 
 		return qm;
 
 	}
 
-	var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta,
-	ratioB = Math.sin( t * halfTheta ) / sinHalfTheta;
+	var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta;
+	var ratioB = Math.sin( t * halfTheta ) / sinHalfTheta;
 
 	qm.w = ( qa.w * ratioA + qm.w * ratioB );
 	qm.x = ( qa.x * ratioA + qm.x * ratioB );

+ 81 - 55
src/core/Ray.js

@@ -2,18 +2,14 @@
  * @author mr.doob / http://mrdoob.com/
  */
 
-THREE.Ray = function ( origin, direction ) {
+THREE.Ray = function ( origin, direction, near, far ) {
 
 	this.origin = origin || new THREE.Vector3();
 	this.direction = direction || new THREE.Vector3();
+	this.near = near || 0;
+	this.far = far || Infinity;
 
-	var precision = 0.0001;
-
-	this.setPrecision = function ( value ) {
-
-		precision = value;
-
-	};
+	//
 
 	var a = new THREE.Vector3();
 	var b = new THREE.Vector3();
@@ -25,7 +21,64 @@ THREE.Ray = function ( origin, direction ) {
 
 	var vector = new THREE.Vector3();
 	var normal = new THREE.Vector3();
-	var intersectPoint = new THREE.Vector3()
+	var intersectPoint = new THREE.Vector3();
+	
+	var descSort = function ( a, b ) {
+	
+			return a.distance - b.distance;
+			
+	};
+
+	//
+
+	var v0 = new THREE.Vector3(), v1 = new THREE.Vector3(), v2 = new THREE.Vector3();
+	var dot, intersect, distance;
+
+	var distanceFromIntersection = function ( origin, direction, position ) {
+
+		v0.sub( position, origin );
+		dot = v0.dot( direction );
+
+		intersect = v1.add( origin, v2.copy( direction ).multiplyScalar( dot ) );
+		distance = position.distanceTo( intersect );
+
+		return distance;
+
+	}
+
+	// http://www.blackpawn.com/texts/pointinpoly/default.html
+
+	var dot00, dot01, dot02, dot11, dot12, invDenom, u, v;
+
+	var pointInFace3 = function ( p, a, b, c ) {
+
+		v0.sub( c, a );
+		v1.sub( b, a );
+		v2.sub( p, a );
+
+		dot00 = v0.dot( v0 );
+		dot01 = v0.dot( v1 );
+		dot02 = v0.dot( v2 );
+		dot11 = v1.dot( v1 );
+		dot12 = v1.dot( v2 );
+
+		invDenom = 1 / ( dot00 * dot11 - dot01 * dot01 );
+		u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
+		v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
+
+		return ( u >= 0 ) && ( v >= 0 ) && ( u + v < 1 );
+
+	}
+
+	//
+
+	var precision = 0.0001;
+
+	this.setPrecision = function ( value ) {
+
+		precision = value;
+
+	};
 
 	this.intersectObject = function ( object ) {
 
@@ -33,7 +86,7 @@ THREE.Ray = function ( origin, direction ) {
 
 		if ( object instanceof THREE.Particle ) {
 
-			var distance = distanceFromIntersection( this.origin, this.direction, object.matrixWorld.getPosition() );
+			distance = distanceFromIntersection( this.origin, this.direction, object.matrixWorld.getPosition() );
 
 			if ( distance > object.scale.x ) {
 
@@ -56,10 +109,14 @@ THREE.Ray = function ( origin, direction ) {
 
 			// Checking boundingSphere
 
-			var distance = distanceFromIntersection( this.origin, this.direction, object.matrixWorld.getPosition() );
 			var scale = THREE.Frustum.__v1.set( object.matrixWorld.getColumnX().length(), object.matrixWorld.getColumnY().length(), object.matrixWorld.getColumnZ().length() );
+			var scaledRadius = object.geometry.boundingSphere.radius * Math.max( scale.x, Math.max( scale.y, scale.z ) ); 
+
+			// Checking distance to ray
+		
+			distance = distanceFromIntersection( this.origin, this.direction, object.matrixWorld.getPosition() );
 
-			if ( distance > object.geometry.boundingSphere.radius * Math.max( scale.x, Math.max( scale.y, scale.z ) ) ) {
+			if ( distance > scaledRadius) {
 
 				return intersects;
 
@@ -68,6 +125,7 @@ THREE.Ray = function ( origin, direction ) {
 			// Checking faces
 
 			var f, fl, face, dot, scalar,
+			rangeSq = this.range*this.range,
 			geometry = object.geometry,
 			vertices = geometry.vertices,
 			objMatrix;
@@ -106,6 +164,11 @@ THREE.Ray = function ( origin, direction ) {
 
 					intersectPoint.add( originCopy, directionCopy.multiplyScalar( scalar ) );
 
+					distance = originCopy.distanceTo( intersectPoint );
+
+					if ( distance < this.near ) continue;
+					if ( distance > this.far ) continue;
+
 					if ( face instanceof THREE.Face3 ) {
 
 						a = objMatrix.multiplyVector3( a.copy( vertices[ face.a ] ) );
@@ -116,7 +179,7 @@ THREE.Ray = function ( origin, direction ) {
 
 							intersect = {
 
-								distance: originCopy.distanceTo( intersectPoint ),
+								distance: distance,
 								point: intersectPoint.clone(),
 								face: face,
 								object: object
@@ -138,7 +201,7 @@ THREE.Ray = function ( origin, direction ) {
 
 							intersect = {
 
-								distance: originCopy.distanceTo( intersectPoint ),
+								distance: distance,
 								point: intersectPoint.clone(),
 								face: face,
 								object: object
@@ -157,9 +220,11 @@ THREE.Ray = function ( origin, direction ) {
 
 		}
 
+		intersects.sort( descSort );
+
 		return intersects;
 
-	}
+	};
 
 	this.intersectObjects = function ( objects ) {
 
@@ -171,49 +236,10 @@ THREE.Ray = function ( origin, direction ) {
 
 		}
 
-		intersects.sort( function ( a, b ) { return a.distance - b.distance; } );
+		intersects.sort( descSort );
 
 		return intersects;
 
 	};
 
-	var v0 = new THREE.Vector3(), v1 = new THREE.Vector3(), v2 = new THREE.Vector3();
-	var dot, intersect, distance;
-
-	function distanceFromIntersection( origin, direction, position ) {
-
-		v0.sub( position, origin );
-		dot = v0.dot( direction );
-
-		intersect = v1.add( origin, v2.copy( direction ).multiplyScalar( dot ) );
-		distance = position.distanceTo( intersect );
-
-		return distance;
-
-	}
-
-	// http://www.blackpawn.com/texts/pointinpoly/default.html
-
-	var dot00, dot01, dot02, dot11, dot12, invDenom, u, v;
-
-	function pointInFace3( p, a, b, c ) {
-
-		v0.sub( c, a );
-		v1.sub( b, a );
-		v2.sub( p, a );
-
-		dot00 = v0.dot( v0 );
-		dot01 = v0.dot( v1 );
-		dot02 = v0.dot( v2 );
-		dot11 = v1.dot( v1 );
-		dot12 = v1.dot( v2 );
-
-		invDenom = 1 / ( dot00 * dot11 - dot01 * dot01 );
-		u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
-		v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
-
-		return ( u >= 0 ) && ( v >= 0 ) && ( u + v < 1 );
-
-	}
-
 };

+ 188 - 61
src/core/Vector3.js

@@ -4,6 +4,7 @@
  * @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 ) {
@@ -270,89 +271,215 @@ THREE.Vector3.prototype = {
 
 	},
 
-	getRotationFromMatrix: function ( m, scale ) {
+	setEulerFromRotationMatrix: function ( m, order ) {
 
-		var sx = scale ? scale.x : 1;
-		var sy = scale ? scale.y : 1;
-		var sz = scale ? scale.z : 1;
+		// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
+	
+		// clamp, to handle numerical problems
 
-		var m11 = m.elements[0] / sx, m12 = m.elements[4] / sy, m13 = m.elements[8] / sz;
-		var m21 = m.elements[1] / sx, m22 = m.elements[5] / sy, m23 = m.elements[9] / sz;
-		var m33 = m.elements[10] / sz;
+		function clamp( x ) {
 
-		this.y = Math.asin( m13 );
-
-		var cosY = Math.cos( this.y );
-
-		if ( Math.abs( cosY ) > 0.00001 ) {
-
-			this.x = Math.atan2( - m23 / cosY, m33 / cosY );
-			this.z = Math.atan2( - m12 / cosY, m11 / cosY );
-
-		} else {
-
-			this.x = 0;
-			this.z = Math.atan2( m21, m22 );
+			return Math.min( Math.max( x, -1 ), 1 );
 
 		}
-
+		
+		var _order = order || 'XYZ',
+		
+			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];
+	
+		switch ( _order ) {
+	
+			case '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;
+					
+				}
+				
+				break;
+				
+			case '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( m13, m11 );
+					
+				}
+				
+				break;
+				
+			case '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 );
+					
+				}
+				
+				break;
+				
+			case '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( m31, m33 );
+			
+				}
+				
+				break;
+				
+			case '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( - m13, m33 );
+					this.y = 0;
+			
+				}
+				
+				break;
+				
+			default: // '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( m21, m22 );
+					this.z = 0;
+			
+				}
+				
+				break;
+				
+		}
+		
 		return this;
 
 	},
 
-	/*
+	setEulerFromQuaternion: function ( q, order ) {
 
-	// from http://www.mathworks.com/matlabcentral/fileexchange/20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/content/SpinCalc.m
-	// order XYZ
+		// q is assumed to be normalized
 
-	getEulerXYZFromQuaternion: function ( q ) {
+		// clamp, to handle numerical problems
 
-		this.x = Math.atan2( 2 * ( q.x * q.w - q.y * q.z ), ( q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z ) );
-		this.y = Math.asin( 2 *  ( q.x * q.z + q.y * q.w ) );
-		this.z = Math.atan2( 2 * ( q.z * q.w - q.x * q.y ), ( q.w * q.w + q.x * q.x - q.y * q.y - q.z * q.z ) );
-
-	},
+		function clamp( x ) {
 
-	// from http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/index.htm
-	// order YZX (assuming heading == y, attitude == z, bank == x)
+			return Math.min( Math.max( x, -1 ), 1 );
 
-	getEulerYZXFromQuaternion: function ( q ) {
+		}
 
-		var sqw = q.w * q.w;
+		// 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 unit = sqx + sqy + sqz + sqw; // if normalised is one, otherwise is correction factor
-		var test = q.x * q.y + q.z * q.w;
-
-		if ( test > 0.499 * unit ) { // singularity at north pole
-
-			this.y = 2 * Math.atan2( q.x, q.w );
-			this.z = Math.PI / 2;
-			this.x = 0;
-
-			return;
-
-		}
-
-		if ( test < -0.499 * unit ) { // singularity at south pole
-
-			this.y = -2 * Math.atan2( q.x, q.w );
-			this.z = -Math.PI / 2;
-			this.x = 0;
-
-			return;
-
+		var sqw = q.w * q.w;
+	
+		switch ( order ) {
+	
+			case '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 ) );
+				
+				break;
+	
+			case '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 ) );
+				
+				break;
+			
+			case '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 ) );
+				
+				break;
+	
+			case '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 ) ) );
+				
+				break;
+			
+			case '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 ) ) );
+				
+				break;
+	
+			default: // '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 ) );
+	
 		}
-
-		this.y = Math.atan2( 2 * q.y * q.w - 2 * q.x * q.z, sqx - sqy - sqz + sqw );
-		this.z = Math.asin( 2 * test / unit );
-		this.x = Math.atan2( 2 * q.x * q.w - 2 * q.y * q.z, -sqx + sqy - sqz + sqw );
+		
+		return this;
 
 	},
 
-	*/
-
 	getScaleFromMatrix: function ( m ) {
 
 		var sx = this.set( m.elements[0], m.elements[1], m.elements[2] ).length();

+ 153 - 0
src/core/Vector4.js

@@ -3,6 +3,7 @@
  * @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 ) {
@@ -169,6 +170,158 @@ THREE.Vector4.prototype = {
 
 		return new THREE.Vector4( this.x, this.y, this.z, this.w );
 
+	},
+
+	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;
+
 	}
 
 };

+ 474 - 0
src/extras/FontUtils.js

@@ -0,0 +1,474 @@
+/**
+ * @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 ] );
+				result.push( contour[ b ] );
+				result.push( contour[ c ] );
+				*/
+				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;
+
+	};
+
+	// see if p is inside triangle abc
+
+	var insideTriangle = function( ax, ay,
+								   bx, by,
+								   cx, cy,
+								   px, py ) {
+
+		  var aX, aY, bX, bY;
+		  var cX, cY, apx, apy;
+		  var 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;
+		  apx= px  -ax;  apy= py - ay;
+		  bpx= px - bx;  bpy= py - by;
+		  cpx= px - cx;  cpy= py - cy;
+
+		  aCROSSbp = aX*bpy - aY*bpx;
+		  cCROSSap = cX*apy - cY*apx;
+		  bCROSScp = bX*cpy - bY*cpx;
+
+		  return ( (aCROSSbp >= 0.0) && (bCROSScp >= 0.0) && (cCROSSap >= 0.0) );
+
+	};
+
+
+	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;
+
+			for ( p = 0; p < n; p++ ) {
+
+				if( (p == u) || (p == v) || (p == w) ) continue;
+
+				px = contour[ verts[ p ] ].x
+				py = contour[ verts[ p ] ].y
+
+				if ( insideTriangle( ax, ay, bx, by, cx, cy, px, py ) ) 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 };

+ 30 - 9
src/extras/ImageUtils.js

@@ -7,19 +7,35 @@ THREE.ImageUtils = {
 
 	crossOrigin: 'anonymous',
 
-	loadTexture: function ( path, mapping, callback ) {
+	loadTexture: function ( url, mapping, onLoad, onError ) {
 
-		var image = new Image(), texture = new THREE.Texture( image, mapping );
+		var texture = new THREE.Texture( undefined, mapping );
 
-		image.onload = function () { texture.needsUpdate = true; if ( callback ) callback( this ); };
-		image.crossOrigin = this.crossOrigin;
-		image.src = path;
+		var loader = new THREE.ImageLoader();
+
+		loader.addEventListener( 'load', function ( event ) {
+
+			texture.image = event.content;
+			texture.needsUpdate = true;
+			
+			if ( onLoad ) onLoad();
+
+		} );
+
+		loader.addEventListener( 'error', function ( event ) {
+
+			if ( onError ) onError( event.message );
+
+		} );
+
+		loader.crossOrigin = this.crossOrigin;
+		loader.load( url );
 
 		return texture;
 
 	},
 
-	loadTextureCube: function ( array, mapping, callback ) {
+	loadTextureCube: function ( array, mapping, onLoad ) {
 
 		var i, l, images = [], texture = new THREE.Texture( images, mapping );
 
@@ -31,8 +47,13 @@ THREE.ImageUtils = {
 			images[ i ].onload = function () {
 
 				images.loadCount += 1;
-				if ( images.loadCount === 6 ) texture.needsUpdate = true;
-				if ( callback ) callback( this );
+
+				if ( images.loadCount === 6 ) {
+
+					texture.needsUpdate = true;
+					if ( onLoad ) onLoad();
+
+				}
 
 			};
 
@@ -134,7 +155,7 @@ THREE.ImageUtils = {
 				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 + 1 ] = ( ( normal[ 1 ] + 1.0 ) / 2.0 * 255 ) | 0;
 				output[ idx + 2 ] = ( normal[ 2 ] * 255 ) | 0;
 				output[ idx + 3 ] = 255;
 

+ 2 - 0
src/extras/SceneUtils.js

@@ -113,11 +113,13 @@ THREE.SceneUtils = {
 
 			object = new THREE.LOD();
 
+		/*
 		} else if ( source instanceof THREE.MarchingCubes ) {
 
 			object = new THREE.MarchingCubes( source.resolution, source.material );
 			object.field.set( source.field );
 			object.isolation = source.isolation;
+		*/
 
 		} else if ( source instanceof THREE.Object3D ) {
 

+ 3 - 1
src/extras/controls/FirstPersonControls.js

@@ -124,7 +124,9 @@ THREE.FirstPersonControls = function ( object, domElement ) {
 
 	this.onKeyDown = function ( event ) {
 
-		switch( event.keyCode ) {
+		event.preventDefault();
+
+		switch ( event.keyCode ) {
 
 			case 38: /*up*/
 			case 87: /*W*/ this.moveForward = true; break;

+ 3 - 1
src/extras/controls/FlyControls.js

@@ -49,7 +49,9 @@ THREE.FlyControls = function ( object, domElement ) {
 
 		}
 
-		switch( event.keyCode ) {
+		event.preventDefault();
+
+		switch ( event.keyCode ) {
 
 			case 16: /* shift */ this.movementSpeedMultiplier = .1; break;
 

+ 282 - 0
src/extras/controls/OrbitControls.js

@@ -0,0 +1,282 @@
+/**
+ * @author qiao / https://github.com/qiao
+ * @author mrdoob / http://mrdoob.com
+ * @author alteredq / http://alteredqualia.com/
+ */
+
+THREE.OrbitControls = function ( object, domElement ) {
+
+	THREE.EventTarget.call( this );
+
+	this.object = object;
+	this.domElement = ( domElement !== undefined ) ? domElement : document;
+
+	// API
+
+	this.center = new THREE.Vector3();
+
+	this.userZoom = true;
+	this.userZoomSpeed = 1.0;
+
+	this.userRotate = true;
+	this.userRotateSpeed = 1.0;
+
+	this.autoRotate = false;
+	this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60
+
+	// internals
+
+	var scope = this;
+
+	var EPS = 0.000001;
+	var PIXELS_PER_ROUND = 1800;
+
+	var rotateStart = new THREE.Vector2();
+	var rotateEnd = new THREE.Vector2();
+	var rotateDelta = new THREE.Vector2();
+
+	var zoomStart = new THREE.Vector2();
+	var zoomEnd = new THREE.Vector2();
+	var zoomDelta = new THREE.Vector2();
+
+	var phiDelta = 0;
+	var thetaDelta = 0;
+	var scale = 1;
+
+	var lastPosition = new THREE.Vector3();
+
+	var STATE = { NONE : -1, ROTATE : 0, ZOOM : 1 };
+	var state = STATE.NONE;
+
+	// events
+
+	var changeEvent = { type: 'change' };
+
+
+	this.rotateLeft = function ( angle ) {
+
+		if ( angle === undefined ) {
+
+			angle = getAutoRotationAngle();
+
+		}
+
+		thetaDelta -= angle;
+
+	};
+
+	this.rotateRight = function ( angle ) {
+
+		if ( angle === undefined ) {
+
+			angle = getAutoRotationAngle();
+
+		}
+
+		thetaDelta += angle;
+
+	};
+
+	this.rotateUp = function ( angle ) {
+
+		if ( angle === undefined ) {
+
+			angle = getAutoRotationAngle();
+
+		}
+
+		phiDelta -= angle;
+
+	};
+
+	this.rotateDown = function ( angle ) {
+
+		if ( angle === undefined ) {
+
+			angle = getAutoRotationAngle();
+
+		}
+
+		phiDelta += angle;
+
+	};
+
+	this.zoomIn = function ( zoomScale ) {
+
+		if ( zoomScale === undefined ) {
+
+			zoomScale = getZoomScale();
+
+		}
+
+		scale /= zoomScale;
+
+	};
+
+	this.zoomOut = function ( zoomScale ) {
+
+		if ( zoomScale === undefined ) {
+
+			zoomScale = getZoomScale();
+
+		}
+
+		scale *= zoomScale;
+
+	};
+
+	this.update = function () {
+
+		var position = this.object.position;
+		var offset = position.clone().subSelf( this.center )
+
+		// 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 betwee EPS and PI-EPS
+
+		phi = Math.max( EPS, Math.min( Math.PI - EPS, phi ) );
+
+		var radius = offset.length();
+		offset.x = radius * Math.sin( phi ) * Math.sin( theta );
+		offset.y = radius * Math.cos( phi );
+		offset.z = radius * Math.sin( phi ) * Math.cos( theta );
+		offset.multiplyScalar( scale );
+
+		position.copy( this.center ).addSelf( offset );
+
+		this.object.lookAt( this.center );
+
+		thetaDelta = 0;
+		phiDelta = 0;
+		scale = 1;
+
+		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.userZoomSpeed );
+
+	}
+
+	function onMouseDown( event ) {
+
+		if ( !scope.userRotate ) return;
+
+		event.preventDefault();
+
+		if ( event.button === 0 || event.button === 2 ) {
+
+			state = STATE.ROTATE;
+
+			rotateStart.set( event.clientX, event.clientY );
+
+		} else if ( event.button === 1 ) {
+
+			state = STATE.ZOOM;
+
+			zoomStart.set( event.clientX, event.clientY );
+
+		}
+
+		document.addEventListener( 'mousemove', onMouseMove, false );
+		document.addEventListener( 'mouseup', onMouseUp, false );
+
+	}
+
+	function onMouseMove( event ) {
+
+		event.preventDefault();
+
+		if ( state === STATE.ROTATE ) {
+
+			rotateEnd.set( event.clientX, event.clientY );
+			rotateDelta.sub( rotateEnd, rotateStart );
+
+			scope.rotateLeft( 2 * Math.PI * rotateDelta.x / PIXELS_PER_ROUND * scope.userRotateSpeed );
+			scope.rotateUp( 2 * Math.PI * rotateDelta.y / PIXELS_PER_ROUND * scope.userRotateSpeed );
+
+			rotateStart.copy( rotateEnd );
+
+		} else if ( state === STATE.ZOOM ) {
+
+			zoomEnd.set( event.clientX, event.clientY );
+			zoomDelta.sub( zoomEnd, zoomStart );
+
+			if ( zoomDelta.y > 0 ) {
+
+				scope.zoomIn();
+
+			} else {
+
+				scope.zoomOut();
+
+			}
+
+			zoomStart.copy( zoomEnd );
+
+		}
+
+	}
+
+	function onMouseUp( event ) {
+
+		if ( ! scope.userRotate ) return;
+
+		document.removeEventListener( 'mousemove', onMouseMove, false );
+		document.removeEventListener( 'mouseup', onMouseUp, false );
+
+		state = STATE.NONE;
+
+	}
+
+	function onMouseWheel( event ) {
+
+		if ( ! scope.userZoom ) return;
+
+		if ( event.wheelDelta > 0 ) {
+
+			scope.zoomOut();
+
+		} else {
+
+			scope.zoomIn();
+
+		}
+
+	}
+
+	this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );
+	this.domElement.addEventListener( 'mousedown', onMouseDown, false );
+	this.domElement.addEventListener( 'mousewheel', onMouseWheel, false );
+
+};

+ 3 - 1
src/extras/controls/RollControls.js

@@ -164,7 +164,9 @@ THREE.RollControls = function ( object, domElement ) {
 
 	function onKeyDown( event ) {
 
-		switch( event.keyCode ) {
+		event.preventDefault();
+
+		switch ( event.keyCode ) {
 
 			case 38: /*up*/
 			case 87: /*W*/ forwardSpeed = 1; break;

+ 10 - 5
src/extras/controls/TrackballControls.js

@@ -258,6 +258,8 @@ THREE.TrackballControls = function ( object, domElement ) {
 
 		if ( ! _this.enabled ) return;
 
+		event.preventDefault();
+
 		if ( _state !== STATE.NONE ) {
 
 			return;
@@ -282,7 +284,7 @@ THREE.TrackballControls = function ( object, domElement ) {
 
 		}
 
-	};
+	}
 
 	function keyup( event ) {
 
@@ -294,7 +296,7 @@ THREE.TrackballControls = function ( object, domElement ) {
 
 		}
 
-	};
+	}
 
 	function mousedown( event ) {
 
@@ -323,7 +325,7 @@ THREE.TrackballControls = function ( object, domElement ) {
 
 		}
 
-	};
+	}
 
 	function mousemove( event ) {
 
@@ -357,7 +359,7 @@ THREE.TrackballControls = function ( object, domElement ) {
 
 		}
 
-	};
+	}
 
 	function mouseup( event ) {
 
@@ -368,7 +370,7 @@ THREE.TrackballControls = function ( object, domElement ) {
 
 		_state = STATE.NONE;
 
-	};
+	}
 
 	this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );
 
@@ -376,6 +378,9 @@ THREE.TrackballControls = function ( object, domElement ) {
 	this.domElement.addEventListener( 'mousedown', mousedown, false );
 	this.domElement.addEventListener( 'mouseup', mouseup, false );
 
+	// this.domElement.addEventListener( 'DOMMouseScroll', mousewheel, false );
+	// this.domElement.addEventListener( 'mousewheel', mousewheel, false );
+
 	window.addEventListener( 'keydown', keydown, false );
 	window.addEventListener( 'keyup', keyup, false );
 

+ 25 - 8
src/extras/core/Curve.js

@@ -437,17 +437,18 @@ THREE.SplineCurve.prototype.getPoint = function ( t ) {
 };
 
 /**************************************************************
- *	Arc curve
+ *	Ellipse curve
  **************************************************************/
 
-THREE.ArcCurve = function ( aX, aY, aRadius,
+THREE.EllipseCurve = function ( aX, aY, xRadius, yRadius,
 							aStartAngle, aEndAngle,
 							aClockwise ) {
 
 	this.aX = aX;
 	this.aY = aY;
 
-	this.aRadius = aRadius;
+	this.xRadius = xRadius;
+	this.yRadius = yRadius;
 
 	this.aStartAngle = aStartAngle;
 	this.aEndAngle = aEndAngle;
@@ -456,10 +457,10 @@ THREE.ArcCurve = function ( aX, aY, aRadius,
 
 };
 
-THREE.ArcCurve.prototype = new THREE.Curve();
-THREE.ArcCurve.prototype.constructor = THREE.ArcCurve;
+THREE.EllipseCurve.prototype = new THREE.Curve();
+THREE.EllipseCurve.prototype.constructor = THREE.EllipseCurve;
 
-THREE.ArcCurve.prototype.getPoint = function ( t ) {
+THREE.EllipseCurve.prototype.getPoint = function ( t ) {
 
 	var deltaAngle = this.aEndAngle - this.aStartAngle;
 
@@ -471,13 +472,29 @@ THREE.ArcCurve.prototype.getPoint = function ( t ) {
 
 	var angle = this.aStartAngle + t * deltaAngle;
 
-	var tx = this.aX + this.aRadius * Math.cos( angle );
-	var ty = this.aY + this.aRadius * Math.sin( angle );
+	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 = new THREE.EllipseCurve();
+THREE.ArcCurve.prototype.constructor = THREE.ArcCurve;
+
+
 /**************************************************************
  *	Utils
  **************************************************************/

+ 1 - 1
src/extras/core/CurvePath.js

@@ -159,7 +159,7 @@ THREE.CurvePath.prototype.getBoundingBox = function () {
 		else if ( p.x < minX ) minX = p.x;
 
 		if ( p.y > maxY ) maxY = p.y;
-		else if ( p.y < maxY ) minY = p.y;
+		else if ( p.y < minY ) minY = p.y;
 
 		sum.addSelf( p.x, p.y );
 

+ 57 - 168
src/extras/core/Path.js

@@ -29,8 +29,8 @@ THREE.PathActions = {
 	QUADRATIC_CURVE_TO: 'quadraticCurveTo', // Bezier quadratic curve
 	BEZIER_CURVE_TO: 'bezierCurveTo', 		// Bezier cubic curve
 	CSPLINE_THRU: 'splineThru',				// Catmull-rom spline
-	ARC: 'arc'								// Circle
-
+	ARC: 'arc',								// Circle
+	ELLIPSE: 'ellipse'
 };
 
 // TODO Clean up PATH API
@@ -133,16 +133,31 @@ THREE.Path.prototype.splineThru = function( pts /*Array of Vector*/ ) {
 };
 
 // FUTURE: Change the API or follow canvas API?
-// TODO ARC ( x, y, x - radius, y - radius, startAngle, endAngle )
 
-THREE.Path.prototype.arc = function ( aX, aY, aRadius,
+THREE.Path.prototype.ellipse = function ( aX, aY, xRadius, yRadius,
 									  aStartAngle, aEndAngle, aClockwise ) {
 
-	var args = Array.prototype.slice.call( arguments );
+	var laste = this.actions[ this.actions.length - 1];
+	this.absellipse(laste.x + aX, laste.y + aY, xRadius, yRadius,
+									aStartAngle, aEndAngle, aClockwise );
+ };
+ 
+THREE.Path.prototype.arc = function ( aX, aY, aRadius,
+									  aStartAngle, aEndAngle, aClockwise ) {
 
 	var laste = this.actions[ this.actions.length - 1];
+	this.absarc(laste.x + aX, laste.y + aY, aRadius,
+									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.ArcCurve( laste.x + aX, laste.y + aY, aRadius,
+	var curve = new THREE.EllipseCurve( aX, aY, xRadius, yRadius,
 									aStartAngle, aEndAngle, aClockwise );
 	this.curves.push( curve );
 
@@ -152,29 +167,14 @@ THREE.Path.prototype.arc = function ( aX, aY, aRadius,
 	args.push(lastPoint.x);
 	args.push(lastPoint.y);
 
-	this.actions.push( { action: THREE.PathActions.ARC, args: args } );
+	this.actions.push( { action: THREE.PathActions.ELLIPSE, args: args } );
 
  };
 
 THREE.Path.prototype.absarc = function ( aX, aY, aRadius,
 									  aStartAngle, aEndAngle, aClockwise ) {
-
-	var args = Array.prototype.slice.call( arguments );
-
-	var curve = new THREE.ArcCurve( aX, aY, aRadius,
-									aStartAngle, aEndAngle, aClockwise );
-	this.curves.push( curve );
-
-	// console.log( 'arc', args );
-
-        // All of the other actions look to the last two elements in the list to
-        // find the ending point, so we need to append them.
-        var lastPoint = curve.getPoint(aClockwise ? 1 : 0);
-        args.push(lastPoint.x);
-        args.push(lastPoint.y);
-
-	this.actions.push( { action: THREE.PathActions.ARC, args: args } );
-
+	this.absellipse(aX, aY, aRadius, aRadius,
+		aStartAngle, aEndAngle, aClockwise);
  };
 
 
@@ -342,8 +342,6 @@ THREE.Path.prototype.getPoints = function( divisions, closedPath ) {
 
 		case THREE.PathActions.ARC:
 
-			laste = this.actions[ i - 1 ].args;
-
 			var aX = args[ 0 ], aY = args[ 1 ],
 				aRadius = args[ 2 ],
 				aStartAngle = args[ 3 ], aEndAngle = args[ 4 ],
@@ -378,173 +376,64 @@ THREE.Path.prototype.getPoints = function( divisions, closedPath ) {
 			//console.log(points);
 
 		  break;
+		  
+		case THREE.PathActions.ELLIPSE:
 
-		} // 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;
-
-};
-
-
-
-// This was used for testing purposes. Should be removed soon.
-
-THREE.Path.prototype.transform = function( path, segments ) {
-
-	var bounds = this.getBoundingBox();
-	var oldPts = this.getPoints( segments ); // getPoints getSpacedPoints
-
-	//console.log( path.cacheArcLengths() );
-	//path.getLengths(400);
-	//segments = 40;
-
-	return this.getWrapPoints( oldPts, path );
-
-};
-
-// Read http://www.tinaja.com/glib/nonlingr.pdf
-// nonlinear transforms
-
-THREE.Path.prototype.nltransform = function( a, b, c, d, e, f ) {
-
-	// a - horizontal size
-	// b - lean
-	// c - x offset
-	// d - vertical size
-	// e - climb
-	// f - y offset
-
-	var oldPts = this.getPoints();
-
-	var i, il, p, oldX, oldY;
-
-	for ( i = 0, il = oldPts.length; i < il; i ++ ) {
+			var aX = args[ 0 ], aY = args[ 1 ],
+				xRadius = args[ 2 ],
+				yRadius = args[3]
+				aStartAngle = args[ 4 ], aEndAngle = args[ 5 ],
+				aClockwise = !!args[ 6 ];
 
-		p = oldPts[i];
 
-		oldX = p.x;
-		oldY = p.y;
+			var deltaAngle = aEndAngle - aStartAngle;
+			var angle;
+			var tdivisions = divisions * 2;
 
-		p.x = a * oldX + b * oldY + c;
-		p.y = d * oldY + e * oldX + f;
+			for ( j = 1; j <= tdivisions; j ++ ) {
 
-	}
+				t = j / tdivisions;
 
-	return oldPts;
+				if ( ! aClockwise ) {
 
-};
+					t = 1 - t;
 
+				}
 
-// FUTURE Export JSON Format
+				angle = aStartAngle + t * deltaAngle;
 
-/* Draws this path onto a 2d canvas easily */
+				tx = aX + xRadius * Math.cos( angle );
+				ty = aY + yRadius * Math.sin( angle );
 
-THREE.Path.prototype.debug = function( canvas ) {
+				//console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty);
 
-	var bounds = this.getBoundingBox();
+				points.push( new THREE.Vector2( tx, ty ) );
 
-	if ( !canvas ) {
+			}
 
-		canvas = document.createElement( "canvas" );
+			//console.log(points);
 
-		canvas.setAttribute( 'width',  bounds.maxX + 100 );
-		canvas.setAttribute( 'height', bounds.maxY + 100 );
+		  break;
 
-		document.body.appendChild( canvas );
+		} // end switch
 
 	}
 
-	var ctx = canvas.getContext( "2d" );
-	ctx.fillStyle = "white";
-	ctx.fillRect( 0, 0, canvas.width, canvas.height );
-
-	ctx.strokeStyle = "black";
-	ctx.beginPath();
-
-	var i, il, item, action, args;
-
-	// Debug Path
-
-	for ( i = 0, il = this.actions.length; i < il; i ++ ) {
-
-		item = this.actions[ i ];
-
-		args = item.args;
-		action = item.action;
-
-		// Short hand for now
 
-		if ( action != THREE.PathActions.CSPLINE_THRU ) {
 
-			ctx[ action ].apply( ctx, args );
-
-		}
-
-		/*
-		switch ( action ) {
-
-			case THREE.PathActions.MOVE_TO:
-
-				ctx[ action ]( args[ 0 ], args[ 1 ] );
-				break;
-
-			case THREE.PathActions.LINE_TO:
-
-				ctx[ action ]( args[ 0 ], args[ 1 ] );
-				break;
-
-			case THREE.PathActions.QUADRATIC_CURVE_TO:
-
-				ctx[ action ]( args[ 0 ], args[ 1 ], args[ 2 ], args[ 3 ] );
-				break;
-
-			case THREE.PathActions.CUBIC_CURVE_TO:
-
-				ctx[ action ]( args[ 0 ], args[ 1 ], args[ 2 ], args[ 3 ], args[ 4 ], args[ 5 ] );
-				break;
+	// 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 ] );
 
 	}
 
-	ctx.stroke();
-	ctx.closePath();
-
-	// Debug Points
-
-	ctx.strokeStyle = "red";
-
-	/* TO CLEAN UP */
-
-	var p, points = this.getPoints();
-
-	for ( i = 0, il = points.length; i < il; i ++ ) {
-
-		p = points[ i ];
-
-		ctx.beginPath();
-		ctx.arc( p.x, p.y, 1.5, 0, Math.PI * 2, false );
-		ctx.stroke();
-		ctx.closePath();
-
-	}
+	return points;
 
 };
 

+ 0 - 68
src/extras/core/TextPath.js

@@ -1,68 +0,0 @@
-/**
- * @author zz85 / http://www.lab4games.net/zz85/blog
- *
- * TextPath
- *
- **/
-
-THREE.TextPath = function ( text, parameters ) {
-
-	THREE.Path.call( this );
-
-	this.parameters = parameters || {};
-
-	this.set( text );
-
-};
-
-THREE.TextPath.prototype.set = function ( text, parameters ) {
-
-	parameters = parameters || this.parameters;
-
-	this.text = text;
-
-	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;
-
-};
-
-
-
-THREE.TextPath.prototype.toShapes = function () {
-
-	// Get a Font data json object
-
-	var data = THREE.FontUtils.drawText( this.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;
-
-	//console.log(path);
-	//console.log(fontShapes);
-
-	// Either find actions or curves.
-
-	//var text3d = new THREE.ExtrudeGeometry( shapes , { amount: 20, bevelEnabled:true, bevelThickness:3	} );
-
-	//return text3d;
-
-};

+ 228 - 0
src/extras/geometries/ConvexGeometry.js

@@ -0,0 +1,228 @@
+/**
+ * @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.sub( vc, vb );
+		ab.sub( va, vb );
+		cb.crossSelf( ab );
+
+		if ( !cb.isZero() ) {
+			
+			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.UV( 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 = new THREE.Geometry();
+THREE.ConvexGeometry.prototype.constructor = THREE.ConvexGeometry;

+ 17 - 8
src/extras/geometries/ExtrudeGeometry.js

@@ -16,11 +16,13 @@
  *  bevelSize:		<float>, 		// how far from text outline is bevel
  *  bevelSegments:	<int>, 			// number of bevel layers
  *
- *  extrudePath:	<THREE.CurvePath>	// 2d/3d spline path to extrude shape orthogonality to
+ *  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
  *  bendPath:		<THREE.CurvePath> 	// 2d path for bend the shape around x/y plane
  *
  *  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
  *
  *  }
   **/
@@ -88,6 +90,9 @@ THREE.ExtrudeGeometry.prototype.addShape = function( shape, options ) {
 	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();
 
@@ -105,7 +110,10 @@ THREE.ExtrudeGeometry.prototype.addShape = function( shape, options ) {
 
 		// Reuse TNB from TubeGeomtry for now.
 		// TODO1 - have a .isClosed in spline?
-		splineTube = new THREE.TubeGeometry.FrenetFrames(extrudePath, steps, false);
+
+		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);
 
@@ -523,8 +531,7 @@ THREE.ExtrudeGeometry.prototype.addShape = function( shape, options ) {
 
 	}
 
-	// set UV generator
-	var uvgen = THREE.ExtrudeGeometry.WorldUVGenerator;
+
 
 	////
 	///   Handle Faces
@@ -618,7 +625,7 @@ THREE.ExtrudeGeometry.prototype.addShape = function( shape, options ) {
 					c = layeroffset + k + slen2,
 					d = layeroffset + j + slen2;
 
-				f4( a, b, c, d, contour, s, sl );
+				f4( a, b, c, d, contour, s, sl, j, k );
 			}
 		}
 	}
@@ -642,7 +649,7 @@ THREE.ExtrudeGeometry.prototype.addShape = function( shape, options ) {
  		scope.faceVertexUvs[ 0 ].push(uvs);
 	}
 
-	function f4( a, b, c, d, wallContour, stepIndex, stepsLength ) {
+	function f4( a, b, c, d, wallContour, stepIndex, stepsLength, contourIndex1, contourIndex2 ) {
 		a += shapesOffset;
 		b += shapesOffset;
 		c += shapesOffset;
@@ -650,7 +657,8 @@ THREE.ExtrudeGeometry.prototype.addShape = function( shape, options ) {
 
  		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);
+ 		var uvs = uvgen.generateSideWallUV( scope, shape, wallContour, options, a, b, c, d,
+ 		                                    stepIndex, stepsLength, contourIndex1, contourIndex2 );
  		scope.faceVertexUvs[ 0 ].push(uvs);
 	}
 
@@ -681,7 +689,8 @@ THREE.ExtrudeGeometry.WorldUVGenerator = {
 	},
 
 	generateSideWallUV: function( geometry, extrudedShape, wallContour, extrudeOptions,
-	                              indexA, indexB, indexC, indexD, stepIndex, stepsLength) {
+	                              indexA, indexB, indexC, indexD, stepIndex, stepsLength,
+	                              contourIndex1, contourIndex2 ) {
 		var ax = geometry.vertices[ indexA ].x,
 			ay = geometry.vertices[ indexA ].y,
 			az = geometry.vertices[ indexA ].z,

+ 4 - 443
src/extras/geometries/TextGeometry.js

@@ -23,20 +23,8 @@
  *  bendPath:       <curve>         // wraps text according to bend Path
  *  }
  *
- * 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/
- *
  */
+
 /*	Usage Examples
 	
 	// TextGeometry wrapper
@@ -45,8 +33,7 @@
 
 	// Complete manner
 
-	var textPath = new THREE.TextPath( text, options );
-	var textShapes = textPath.toShapes();
+	var textShapes = THREE.FontUtils.generateShapes( text, options );
 	var text3d = new ExtrudeGeometry( textShapes, options );
 	
 */
@@ -54,8 +41,7 @@
 
 THREE.TextGeometry = function ( text, parameters ) {
 
-	var textPath = new THREE.TextPath( text, parameters );
-	var textShapes = textPath.toShapes();
+	var textShapes = THREE.FontUtils.generateShapes( text, parameters );
 
 	// translate parameters to ExtrudeGeometry API
 
@@ -83,429 +69,4 @@ THREE.TextGeometry = function ( text, parameters ) {
 };
 
 THREE.TextGeometry.prototype = new THREE.ExtrudeGeometry();
-THREE.TextGeometry.prototype.constructor = THREE.TextGeometry;
-
-
-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;
-			//characterPts.push( ret.points );
-			//allPts = allPts.concat( ret.points );
-			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;
-
-					pts.push( new THREE.Vector2( x, y ) );
-
-					path.moveTo( x, y );
-					break;
-
-				case 'l':
-
-					// Line To
-
-					x = outline[ i++ ] * scaleX + offset;
-					y = outline[ i++ ] * scaleY;
-					pts.push( new THREE.Vector2( x, y ) );
-					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 );
-							pts.push( new THREE.Vector2( tx, ty ) );
-
-					  }
-
-				  }
-
-				  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 );
-							pts.push( new THREE.Vector2( tx, ty ) );
-
-						}
-
-					}
-
-					break;
-
-				}
-
-			}
-		}
-
-
-
-		return { offset: glyph.ha*scale, points:pts, path:path};
-	}
-
-};
-
-
-
-/**
- * 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 ] );
-				result.push( contour[ b ] );
-				result.push( contour[ c ] );
-				*/
-				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;
-
-	};
-
-	// see if p is inside triangle abc
-
-	var insideTriangle = function( ax, ay,
-								   bx, by,
-								   cx, cy,
-								   px, py ) {
-
-		  var aX, aY, bX, bY;
-		  var cX, cY, apx, apy;
-		  var 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;
-		  apx= px  -ax;  apy= py - ay;
-		  bpx= px - bx;  bpy= py - by;
-		  cpx= px - cx;  cpy= py - cy;
-
-		  aCROSSbp = aX*bpy - aY*bpx;
-		  cCROSSap = cX*apy - cY*apx;
-		  bCROSScp = bX*cpy - bY*cpx;
-
-		  return ( (aCROSSbp >= 0.0) && (bCROSScp >= 0.0) && (cCROSSap >= 0.0) );
-
-	};
-
-
-	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;
-
-			for ( p = 0; p < n; p++ ) {
-
-				if( (p == u) || (p == v) || (p == w) ) continue;
-
-				px = contour[ verts[ p ] ].x
-				py = contour[ verts[ p ] ].y
-
-				if ( insideTriangle( ax, ay, bx, by, cx, cy, px, py ) ) 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 };
+THREE.TextGeometry.prototype.constructor = THREE.TextGeometry;

+ 2 - 2
src/extras/helpers/ArrowHelper.js

@@ -1,5 +1,5 @@
 /**
- * @author WestLangley / https://github.com/WestLangley
+ * @author WestLangley / http://github.com/WestLangley
  * @author zz85 / https://github.com/zz85
  *
  * Creates an arrow for visualizing directions
@@ -49,7 +49,7 @@ THREE.ArrowHelper.prototype.setDirection = function ( dir ) {
 
 	this.matrix = new THREE.Matrix4().makeRotationAxis( axis.normalize(), radians );
 
-	this.rotation.getRotationFromMatrix( this.matrix, this.scale );
+	this.rotation.setEulerFromRotationMatrix( this.matrix, this.eulerOrder );
 
 };
 

+ 1 - 1
src/extras/modifiers/SubdivisionModifier.js

@@ -75,7 +75,7 @@ THREE.SubdivisionModifier.prototype.smooth = function ( oldGeometry ) {
 		
 		// TODO move vertex selection over here!
 		
-		var newFace = new THREE.Face4( a, b, c, d, null, oldFace.color, oldFace.material );
+		var newFace = new THREE.Face4( a, b, c, d, null, oldFace.color, oldFace.materialIndex );
 		
 		if (scope.useOldVertexColors) {
 			

+ 0 - 1
src/extras/objects/LensFlare.js

@@ -22,7 +22,6 @@ THREE.LensFlare = function ( texture, size, distance, blending, color ) {
 
 THREE.LensFlare.prototype = new THREE.Object3D();
 THREE.LensFlare.prototype.constructor = THREE.LensFlare;
-THREE.LensFlare.prototype.supr = THREE.Object3D.prototype;
 
 
 /*

+ 0 - 1
src/lights/Light.js

@@ -13,4 +13,3 @@ THREE.Light = function ( hex ) {
 
 THREE.Light.prototype = new THREE.Object3D();
 THREE.Light.prototype.constructor = THREE.Light;
-THREE.Light.prototype.supr = THREE.Object3D.prototype;

+ 661 - 0
src/loaders/GeometryLoader.js

@@ -0,0 +1,661 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ * @author alteredq / http://alteredqualia.com/
+ */
+
+THREE.GeometryLoader = function () {
+
+	THREE.EventTarget.call( this );
+
+	this.crossOrigin = null;
+	this.path = null;
+
+
+};
+
+THREE.GeometryLoader.prototype = {
+
+	constructor: THREE.GeometryLoader,
+
+	load: function ( url ) {
+
+		var scope = this;
+		var geometry = null;
+
+		if ( scope.path === null ) {
+
+			var parts = url.split( '/' ); parts.pop();
+			scope.path = ( parts.length < 1 ? '.' : parts.join( '/' ) );
+
+		}
+
+		//
+
+		var xhr = new XMLHttpRequest();
+
+		xhr.addEventListener( 'load', function ( event ) {
+
+			if ( event.target.responseText ) {
+
+				geometry = scope.parse( JSON.parse( event.target.responseText ), monitor );
+				
+			} else {
+
+				scope.dispatchEvent( { type: 'error', message: 'Invalid file [' + url + ']' } );
+
+			}
+
+		}, false );
+
+		xhr.addEventListener( 'error', function () {
+
+			scope.dispatchEvent( { type: 'error', message: 'Couldn\'t load URL [' + url + ']' } );
+
+		}, false );
+
+		xhr.open( 'GET', url, true );
+		xhr.send( null );
+
+		//
+
+		var monitor = new THREE.LoadingMonitor();
+
+		monitor.addEventListener( 'load', function ( event ) {
+
+			scope.dispatchEvent( { type: 'load', content: geometry } );
+
+		} );
+
+		monitor.add( xhr );
+
+	},
+
+	parse: function ( data, monitor ) {
+
+		var scope = this;
+		var geometry = new THREE.Geometry();
+
+		var scale = ( data.scale !== undefined ) ? 1 / data.scale : 1;
+
+		// materials
+
+		if ( data.materials ) {
+
+			geometry.materials = [];
+
+			for ( var i = 0; i < data.materials.length; ++ i ) {
+
+				var m = data.materials[ i ];
+
+				function isPow2( n ) {
+
+					var l = Math.log( n ) / Math.LN2;
+					return Math.floor( l ) == l;
+
+				}
+
+				function nearestPow2( n ) {
+
+					var l = Math.log( n ) / Math.LN2;
+					return Math.pow( 2, Math.round(  l ) );
+
+				}
+
+				function createTexture( where, name, sourceFile, repeat, offset, wrap ) {
+
+					where[ name ] = new THREE.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 ] ];
+
+					}
+
+					// load image
+
+					var texture = where[ name ];
+
+					var loader = new THREE.ImageLoader();
+					loader.addEventListener( 'load', function ( event ) {
+
+						var image = event.content;
+
+						if ( !isPow2( image.width ) || !isPow2( image.height ) ) {
+
+							var width = nearestPow2( image.width );
+							var height = nearestPow2( image.height );
+
+							texture.image = document.createElement( 'canvas' );
+							texture.image.width = width;
+							texture.image.height = height;
+							texture.image.getContext( '2d' ).drawImage( image, 0, 0, width, height );
+
+						} else {
+
+							texture.image = image;
+
+						}
+
+						texture.needsUpdate = true;
+
+					} );
+					loader.crossOrigin = scope.crossOrigin;
+					loader.load( scope.path + '/' + sourceFile );
+
+					if ( monitor ) monitor.add( loader );
+
+				}
+
+				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, wireframe: m.wireframe };
+
+				// 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.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 ) {
+
+					createTexture( mpars, "map", m.mapDiffuse, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap );
+
+				}
+
+				if ( m.mapLight ) {
+
+					createTexture( mpars, "lightMap", m.mapLight, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap );
+
+				}
+
+				if ( m.mapNormal ) {
+
+					createTexture( mpars, "normalMap", m.mapNormal, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap );
+
+				}
+
+				if ( m.mapSpecular ) {
+
+					createTexture( mpars, "specularMap", m.mapSpecular, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap );
+
+				}
+
+				// special case for normal mapped material
+
+				if ( m.mapNormal ) {
+
+					var shader = THREE.ShaderUtils.lib[ "normal" ];
+					var uniforms = THREE.UniformsUtils.clone( shader.uniforms );
+
+					uniforms[ "tNormal" ].texture = mpars.normalMap;
+
+					if ( m.mapNormalFactor ) {
+
+						uniforms[ "uNormalScale" ].value = m.mapNormalFactor;
+
+					}
+
+					if ( mpars.map ) {
+
+						uniforms[ "tDiffuse" ].texture = mpars.map;
+						uniforms[ "enableDiffuse" ].value = true;
+
+					}
+
+					if ( mpars.specularMap ) {
+
+						uniforms[ "tSpecular" ].texture = mpars.specularMap;
+						uniforms[ "enableSpecular" ].value = true;
+
+					}
+
+					if ( mpars.lightMap ) {
+
+						uniforms[ "tAO" ].texture = 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 );
+
+				} else {
+
+					var material = new THREE[ mtype ]( mpars );
+
+				}
+
+				if ( m.DbgName !== undefined ) material.name = m.DbgName;
+
+				geometry.materials[ i ] = material;
+
+			}
+
+		}
+
+		// geometry
+
+		function isBitSet( value, position ) {
+
+			return value & ( 1 << position );
+
+		}
+	
+		var faces = data.faces;
+		var vertices = data.vertices;
+		var normals = data.normals;
+		var colors = data.colors;
+		var nUvLayers = 0;
+
+		// disregard empty arrays
+
+		if ( data.uvs ) {
+
+			for ( var i = 0; i < data.uvs.length; i ++ ) {
+
+				if ( data.uvs[ i ].length ) nUvLayers ++;
+
+			}
+
+		}
+
+		for ( var i = 0; i < nUvLayers; i ++ ) {
+
+			geometry.faceUvs[ i ] = [];
+			geometry.faceVertexUvs[ i ] = [];
+
+		}
+
+		var offset = 0;
+		var zLength = vertices.length;
+
+		while ( offset < zLength ) {
+
+			var 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 ) {
+
+			var type = faces[ offset ++ ];
+
+			var isQuad = isBitSet( type, 0 );
+
+			var hasMaterial = isBitSet( type, 1 );
+			var hasFaceUv = isBitSet( type, 2 );
+			var hasFaceVertexUv = isBitSet( type, 3 );
+			var hasFaceNormal = isBitSet( type, 4 );
+			var hasFaceVertexNormal = isBitSet( type, 5 );
+			var hasFaceColor = isBitSet( type, 6 );
+			var hasFaceVertexColor = isBitSet( type, 7 );
+
+			// console.log("type", type, "bits", isQuad, hasMaterial, hasFaceUv, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor);
+
+			if ( isQuad ) {
+
+				var face = new THREE.Face4();
+
+				face.a = faces[ offset ++ ];
+				face.b = faces[ offset ++ ];
+				face.c = faces[ offset ++ ];
+				face.d = faces[ offset ++ ];
+
+				var nVertices = 4;
+
+			} else {
+
+				var face = new THREE.Face3();
+
+				face.a = faces[ offset ++ ];
+				face.b = faces[ offset ++ ];
+				face.c = faces[ offset ++ ];
+
+				var nVertices = 3;
+
+			}
+
+			if ( hasMaterial ) {
+
+				var materialIndex = faces[ offset ++ ];
+				face.materialIndex = materialIndex;
+
+			}
+
+			// to get face <=> uv index correspondence
+
+			var fi = geometry.faces.length;
+
+			if ( hasFaceUv ) {
+
+				for ( var i = 0; i < nUvLayers; i ++ ) {
+
+					var uvLayer = data.uvs[ i ];
+
+					var uvIndex = faces[ offset ++ ];
+
+					var u = uvLayer[ uvIndex * 2 ];
+					var v = uvLayer[ uvIndex * 2 + 1 ];
+
+					geometry.faceUvs[ i ][ fi ] = new THREE.UV( u, v );
+
+				}
+
+			}
+
+			if ( hasFaceVertexUv ) {
+
+				for ( var i = 0; i < nUvLayers; i ++ ) {
+
+					var uvLayer = data.uvs[ i ];
+
+					var uvs = [];
+
+					for ( var j = 0; j < nVertices; j ++ ) {
+
+						var uvIndex = faces[ offset ++ ];
+
+						var u = uvLayer[ uvIndex * 2 ];
+						var v = uvLayer[ uvIndex * 2 + 1 ];
+
+						uvs[ j ] = new THREE.UV( u, v );
+
+					}
+
+					geometry.faceVertexUvs[ i ][ fi ] = uvs;
+
+				}
+
+			}
+
+			if ( hasFaceNormal ) {
+
+				var normalIndex = faces[ offset ++ ] * 3;
+
+				var 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 ++ ) {
+
+					var normalIndex = faces[ offset ++ ] * 3;
+
+					var normal = new THREE.Vector3();
+
+					normal.x = normals[ normalIndex ++ ];
+					normal.y = normals[ normalIndex ++ ];
+					normal.z = normals[ normalIndex ];
+
+					face.vertexNormals.push( normal );
+
+				}
+
+			}
+
+
+			if ( hasFaceColor ) {
+
+				var colorIndex = faces[ offset ++ ];
+
+				face.color = new THREE.Color( colors[ colorIndex ] );
+
+			}
+
+
+			if ( hasFaceVertexColor ) {
+
+				for ( var i = 0; i < nVertices; i ++ ) {
+
+					var colorIndex = faces[ offset ++ ];
+
+					face.vertexColors.push( new THREE.Color( colors[ colorIndex ] ) );
+
+				}
+
+			}
+
+			geometry.faces.push( face );
+
+		}
+
+
+		// skin
+
+		if ( data.skinWeights ) {
+
+			for ( var i = 0, l = data.skinWeights.length; i < l; i += 2 ) {
+
+				var x = data.skinWeights[ i ];
+				var y = data.skinWeights[ i + 1 ];
+				var z = 0;
+				var w = 0;
+
+				geometry.skinWeights.push( new THREE.Vector4( x, y, z, w ) );
+
+			}
+
+		}
+
+		if ( data.skinIndices ) {
+
+			for ( var i = 0, l = data.skinIndices.length; i < l; i += 2 ) {
+
+				var a = data.skinIndices[ i ];
+				var b = data.skinIndices[ i + 1 ];
+				var c = 0;
+				var d = 0;
+
+				geometry.skinIndices.push( new THREE.Vector4( a, b, c, d ) );
+
+			}
+
+		}
+
+		geometry.bones = data.bones;
+		geometry.animation = data.animation;
+
+
+		// morphing
+
+		if ( data.morphTargets ) {
+
+			for ( var i = 0, l = data.morphTargets.length; i < l; i ++ ) {
+
+				geometry.morphTargets[ i ] = {};
+				geometry.morphTargets[ i ].name = data.morphTargets[ i ].name;
+				geometry.morphTargets[ i ].vertices = [];
+
+				var dstVertices = geometry.morphTargets[ i ].vertices;
+				var srcVertices = data.morphTargets [ i ].vertices;
+
+				for( var 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 ( data.morphColors ) {
+
+			for ( var i = 0, l = data.morphColors.length; i < l; i++ ) {
+
+				geometry.morphColors[ i ] = {};
+				geometry.morphColors[ i ].name = data.morphColors[ i ].name;
+				geometry.morphColors[ i ].colors = [];
+
+				var dstColors = geometry.morphColors[ i ].colors;
+				var srcColors = data.morphColors [ i ].colors;
+
+				for ( var c = 0, cl = srcColors.length; c < cl; c += 3 ) {
+
+					var color = new THREE.Color( 0xffaa00 );
+					color.setRGB( srcColors[ c ], srcColors[ c + 1 ], srcColors[ c + 2 ] );
+
+					dstColors.push( color );
+
+				}
+
+			}
+
+		}
+
+		geometry.computeCentroids();
+		geometry.computeFaceNormals();
+
+		return geometry;
+
+	}
+
+};

+ 27 - 14
src/loaders/ImageLoader.js

@@ -2,27 +2,40 @@
  * @author mrdoob / http://mrdoob.com/
  */
 
-THREE.ImageLoader = function () {};
+THREE.ImageLoader = function () {
 
-THREE.ImageLoader.prototype = new THREE.Loader();
-THREE.ImageLoader.prototype.constructor = THREE.ImageLoader;
+	THREE.EventTarget.call( this );
 
-THREE.ImageLoader.prototype.load = function ( url, callback ) {
+	this.crossOrigin = null;
 
-	var that = this;
-	var image = new Image();
+};
 
-	image.onload = function () {
+THREE.ImageLoader.prototype = {
 
-		callback( image );
+	constructor: THREE.ImageLoader,
 
-		that.onLoadComplete();
+	load: function ( url ) {
 
-	};
+		var scope = this;
 
-	image.crossOrigin = this.crossOrigin;
-	image.src = path;
+		var image = new Image();
+		
+		image.addEventListener( 'load', function () {
 
-	that.onLoadStart();
+			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;
+
+	}
+
+}

+ 1 - 1
src/loaders/JSONLoader.js

@@ -14,7 +14,7 @@ THREE.JSONLoader.prototype.constructor = THREE.JSONLoader;
 
 THREE.JSONLoader.prototype.load = function ( url, callback, texturePath ) {
 
-	var worker, scope = this;
+	var scope = this;
 
 	texturePath = texturePath ? texturePath : this.extractUrlBase( url );
 

+ 36 - 0
src/loaders/LoadingMonitor.js

@@ -0,0 +1,36 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
+
+THREE.LoadingMonitor = function () {
+
+	THREE.EventTarget.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 );
+
+	};
+
+};

+ 44 - 0
src/loaders/TextureLoader.js

@@ -0,0 +1,44 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
+
+THREE.TextureLoader = function () {
+
+	THREE.EventTarget.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;
+
+	}
+
+}

+ 0 - 1
src/objects/Bone.js

@@ -14,7 +14,6 @@ THREE.Bone = function( belongsToSkin ) {
 
 THREE.Bone.prototype = new THREE.Object3D();
 THREE.Bone.prototype.constructor = THREE.Bone;
-THREE.Bone.prototype.supr = THREE.Object3D.prototype;
 
 
 THREE.Bone.prototype.update = function( parentSkinMatrix, forceUpdate ) {

+ 0 - 1
src/objects/LOD.js

@@ -14,7 +14,6 @@ THREE.LOD = function () {
 
 THREE.LOD.prototype = new THREE.Object3D();
 THREE.LOD.prototype.constructor = THREE.LOD;
-THREE.LOD.prototype.supr = THREE.Object3D.prototype;
 
 THREE.LOD.prototype.addLevel = function ( object3D, visibleAtDistance ) {
 

+ 1 - 2
src/objects/Mesh.js

@@ -15,7 +15,7 @@ THREE.Mesh = function ( geometry, material ) {
 
 		// calc bound radius
 
-		if( ! this.geometry.boundingSphere ) {
+		if ( ! this.geometry.boundingSphere ) {
 
 			this.geometry.computeBoundingSphere();
 
@@ -48,7 +48,6 @@ THREE.Mesh = function ( geometry, material ) {
 
 THREE.Mesh.prototype = new THREE.Object3D();
 THREE.Mesh.prototype.constructor = THREE.Mesh;
-THREE.Mesh.prototype.supr = THREE.Object3D.prototype;
 
 
 /*

+ 8 - 2
src/renderers/CanvasRenderer.js

@@ -835,9 +835,9 @@ THREE.CanvasRenderer = function ( parameters ) {
 
 		function patternPath( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, texture ) {
 
-			if ( texture.image.width == 0 ) return;
+			if ( texture.image === undefined || texture.image.width === 0 ) return;
 
-			if ( texture.needsUpdate == true || _patterns[ texture.id ] == undefined ) {
+			if ( texture.needsUpdate === true || _patterns[ texture.id ] === undefined ) {
 
 				var repeatX = texture.wrapS == THREE.RepeatWrapping;
 				var repeatY = texture.wrapT == THREE.RepeatWrapping;
@@ -1053,6 +1053,12 @@ THREE.CanvasRenderer = function ( parameters ) {
 
 					break;
 
+				case THREE.SubtractiveBlending:
+
+					_context.globalCompositeOperation = 'darker';
+
+					break;
+
 			}
 
 			_contextGlobalCompositeOperation = value;

+ 119 - 23
src/renderers/WebGLRenderer.js

@@ -104,6 +104,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 	_gl,
 
 	_programs = [],
+	_programs_counter = 0,
 
 	// internal state cache
 
@@ -369,6 +370,69 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 	};
 
+	this.deallocateMaterial = function ( material ) {
+
+		var program = material.program;
+
+		if ( ! program ) 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 ) {
+
+			// 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 --;
+
+		}
+
+	};
+
 	// Rendering
 
 	this.updateShadowMap = function ( scene, camera ) {
@@ -2816,12 +2880,14 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 	// Buffer rendering
 
-	this.renderBufferImmediate = function ( object, program, shading ) {
+	this.renderBufferImmediate = function ( object, program, material ) {
 
-		if ( ! object.__webglVertexBuffer ) object.__webglVertexBuffer = _gl.createBuffer();
-		if ( ! object.__webglNormalBuffer ) object.__webglNormalBuffer = _gl.createBuffer();
+		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.hasPos ) {
+		if ( object.hasPositions ) {
 
 			_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglVertexBuffer );
 			_gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW );
@@ -2830,11 +2896,11 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 		}
 
-		if ( object.hasNormal ) {
+		if ( object.hasNormals ) {
 
 			_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglNormalBuffer );
 
-			if ( shading === THREE.FlatShading ) {
+			if ( material.shading === THREE.FlatShading ) {
 
 				var nx, ny, nz,
 					nax, nbx, ncx, nay, nby, ncy, naz, nbz, ncz,
@@ -2883,6 +2949,24 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 		}
 
+		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;
@@ -3311,7 +3395,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 		// load updated influences uniform
 
-		if( material.program.uniforms.morphTargetInfluences !== null ) {
+		if ( material.program.uniforms.morphTargetInfluences !== null ) {
 
 			_gl.uniform1fv( material.program.uniforms.morphTargetInfluences, object.__webglMorphTargetInfluences );
 
@@ -3682,7 +3766,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 		} else {
 
-			object.render( function( object ) { _this.renderBufferImmediate( object, program, material.shading ); } );
+			object.render( function( object ) { _this.renderBufferImmediate( object, program, material ); } );
 
 		}
 
@@ -4425,7 +4509,9 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 	function setProgram( camera, lights, fog, material, object ) {
 
-		if ( ! material.program || material.needsUpdate ) {
+		if ( material.needsUpdate ) {
+
+			if ( material.program ) _this.deallocateMaterial( material );
 
 			_this.initMaterial( material, lights, fog, object );
 			material.needsUpdate = false;
@@ -4438,12 +4524,6 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 				object.__webglMorphTargetInfluences = new Float32Array( _this.maxMorphTargets );
 
-				for ( var i = 0, il = _this.maxMorphTargets; i < il; i ++ ) {
-
-					object.__webglMorphTargetInfluences[ i ] = 0;
-
-				}
-
 			}
 
 		}
@@ -5057,7 +5137,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 			light = lights[ l ];
 
-			if ( light.onlyShadow ) continue;
+			if ( light.onlyShadow || ! light.visible ) continue;
 
 			color = light.color;
 			intensity = light.intensity;
@@ -5463,11 +5543,15 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 		for ( p = 0, pl = _programs.length; p < pl; p ++ ) {
 
-			if ( _programs[ p ].code === code ) {
+			var programInfo = _programs[ p ];
+
+			if ( programInfo.code === code ) {
 
 				// console.log( "Code already compiled." /*: \n\n" + code*/ );
 
-				return _programs[ p ].program;
+				programInfo.usedTimes ++;
+
+				return programInfo.program;
 
 			}
 
@@ -5611,8 +5695,11 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 		].join("\n");
 
-		_gl.attachShader( program, getShader( "fragment", prefix_fragment + fragmentShader ) );
-		_gl.attachShader( program, getShader( "vertex", prefix_vertex + vertexShader ) );
+		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 );
 
@@ -5622,6 +5709,11 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 		}
 
+		// clean up
+
+		_gl.deleteShader( glFragmentShader );
+		_gl.deleteShader( glVertexShader );
+
 		//console.log( prefix_fragment + fragmentShader );
 		//console.log( prefix_vertex + vertexShader );
 
@@ -5676,9 +5768,9 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 		cacheAttributeLocations( program, identifiers );
 
-		program.id = _programs.length;
+		program.id = _programs_counter ++;
 
-		_programs.push( { program: program, code: code } );
+		_programs.push( { program: program, code: code, usedTimes: 1 } );
 
 		_this.info.memory.programs = _programs.length;
 
@@ -6131,8 +6223,12 @@ THREE.WebGLRenderer = function ( parameters ) {
 			case THREE.LinearMipMapNearestFilter: return _gl.LINEAR_MIPMAP_NEAREST; break;
 			case THREE.LinearMipMapLinearFilter: return _gl.LINEAR_MIPMAP_LINEAR; break;
 
-			case THREE.ByteType: return _gl.BYTE; break;
 			case THREE.UnsignedByteType: return _gl.UNSIGNED_BYTE; break;
+			case THREE.UnsignedShort4444Type: return _gl.UNSIGNED_SHORT_4_4_4_4; break;
+			case THREE.UnsignedShort5551Type: return _gl.UNSIGNED_SHORT_5_5_5_1; break;
+			case THREE.UnsignedShort565Type: return _gl.UNSIGNED_SHORT_5_6_5; break;
+
+			case THREE.ByteType: return _gl.BYTE; break;
 			case THREE.ShortType: return _gl.SHORT; break;
 			case THREE.UnsignedShortType: return _gl.UNSIGNED_SHORT; break;
 			case THREE.IntType: return _gl.INT; break;

+ 16 - 9
src/textures/Texture.js

@@ -79,20 +79,27 @@ THREE.LinearFilter = 6;
 THREE.LinearMipMapNearestFilter = 7;
 THREE.LinearMipMapLinearFilter = 8;
 
-// Types
+// Data types
 
-THREE.ByteType = 9;
-THREE.UnsignedByteType = 10;
+THREE.UnsignedByteType = 9;
+THREE.ByteType = 10;
 THREE.ShortType = 11;
 THREE.UnsignedShortType = 12;
 THREE.IntType = 13;
 THREE.UnsignedIntType = 14;
 THREE.FloatType = 15;
 
-// Formats
+// Pixel types
 
-THREE.AlphaFormat = 16;
-THREE.RGBFormat = 17;
-THREE.RGBAFormat = 18;
-THREE.LuminanceFormat = 19;
-THREE.LuminanceAlphaFormat = 20;
+//THREE.UnsignedByteType = 9;
+THREE.UnsignedShort4444Type = 16;
+THREE.UnsignedShort5551Type = 17;
+THREE.UnsignedShort565Type = 18;
+
+// Pixel formats
+
+THREE.AlphaFormat = 19;
+THREE.RGBFormat = 20;
+THREE.RGBAFormat = 21;
+THREE.LuminanceFormat = 22;
+THREE.LuminanceAlphaFormat = 23;

+ 14 - 269
utils/build.py

@@ -10,271 +10,7 @@ except ImportError:
 import os
 import tempfile
 import sys
-
-COMMON_FILES = [
-'Three.js',
-'core/Clock.js',
-'core/Color.js',
-'core/Vector2.js',
-'core/Vector3.js',
-'core/Vector4.js',
-'core/Frustum.js',
-'core/Ray.js',
-'core/Rectangle.js',
-'core/Math.js',
-'core/Matrix3.js',
-'core/Matrix4.js',
-'core/Object3D.js',
-'core/Projector.js',
-'core/Quaternion.js',
-'core/Vertex.js',
-'core/Face3.js',
-'core/Face4.js',
-'core/UV.js',
-'core/Geometry.js',
-'core/Spline.js',
-'cameras/Camera.js',
-'cameras/OrthographicCamera.js',
-'cameras/PerspectiveCamera.js',
-'lights/Light.js',
-'lights/AmbientLight.js',
-'lights/DirectionalLight.js',
-'lights/PointLight.js',
-'lights/SpotLight.js',
-'loaders/Loader.js',
-'loaders/BinaryLoader.js',
-'loaders/JSONLoader.js',
-'loaders/SceneLoader.js',
-'materials/Material.js',
-'materials/LineBasicMaterial.js',
-'materials/MeshBasicMaterial.js',
-'materials/MeshLambertMaterial.js',
-'materials/MeshPhongMaterial.js',
-'materials/MeshDepthMaterial.js',
-'materials/MeshNormalMaterial.js',
-'materials/MeshFaceMaterial.js',
-'materials/ParticleBasicMaterial.js',
-'materials/ParticleCanvasMaterial.js',
-'materials/ParticleDOMMaterial.js',
-'materials/ShaderMaterial.js',
-'textures/Texture.js',
-'textures/DataTexture.js',
-'objects/Particle.js',
-'objects/ParticleSystem.js',
-'objects/Line.js',
-'objects/Mesh.js',
-'objects/Bone.js',
-'objects/SkinnedMesh.js',
-'objects/MorphAnimMesh.js',
-'objects/Ribbon.js',
-'objects/LOD.js',
-'objects/Sprite.js',
-'scenes/Scene.js',
-'scenes/Fog.js',
-'scenes/FogExp2.js',
-'renderers/CanvasRenderer.js',
-'renderers/WebGLShaders.js',
-'renderers/WebGLRenderer.js',
-'renderers/WebGLRenderTarget.js',
-'renderers/WebGLRenderTargetCube.js',
-'renderers/renderables/RenderableVertex.js',
-'renderers/renderables/RenderableFace3.js',
-'renderers/renderables/RenderableFace4.js',
-'renderers/renderables/RenderableObject.js',
-'renderers/renderables/RenderableParticle.js',
-'renderers/renderables/RenderableLine.js'
-]
-
-EXTRAS_FILES = [
-'extras/ColorUtils.js',
-'extras/GeometryUtils.js',
-'extras/ImageUtils.js',
-'extras/SceneUtils.js',
-'extras/ShaderUtils.js',
-'extras/core/BufferGeometry.js',
-'extras/core/Curve.js',
-'extras/core/CurvePath.js',
-'extras/core/EventTarget.js',
-'extras/core/Gyroscope.js',
-'extras/core/Path.js',
-'extras/core/Shape.js',
-'extras/core/TextPath.js',
-'extras/animation/AnimationHandler.js',
-'extras/animation/Animation.js',
-'extras/animation/KeyFrameAnimation.js',
-'extras/cameras/CubeCamera.js',
-'extras/cameras/CombinedCamera.js',
-'extras/controls/FirstPersonControls.js',
-'extras/controls/PathControls.js',
-'extras/controls/FlyControls.js',
-'extras/controls/RollControls.js',
-'extras/controls/TrackballControls.js',
-'extras/geometries/CubeGeometry.js',
-'extras/geometries/CylinderGeometry.js',
-'extras/geometries/ExtrudeGeometry.js',
-'extras/geometries/LatheGeometry.js',
-'extras/geometries/PlaneGeometry.js',
-'extras/geometries/SphereGeometry.js',
-'extras/geometries/TextGeometry.js',
-'extras/geometries/TorusGeometry.js',
-'extras/geometries/TorusKnotGeometry.js',
-'extras/geometries/TubeGeometry.js',
-'extras/geometries/PolyhedronGeometry.js',
-'extras/geometries/IcosahedronGeometry.js',
-'extras/geometries/OctahedronGeometry.js',
-'extras/geometries/TetrahedronGeometry.js',
-'extras/geometries/ParametricGeometry.js',
-'extras/helpers/AxisHelper.js',
-'extras/helpers/ArrowHelper.js',
-'extras/helpers/CameraHelper.js',
-'extras/modifiers/SubdivisionModifier.js',
-'extras/objects/ImmediateRenderObject.js',
-'extras/objects/LensFlare.js',
-'extras/objects/MorphBlendMesh.js',
-'extras/renderers/plugins/LensFlarePlugin.js',
-'extras/renderers/plugins/ShadowMapPlugin.js',
-'extras/renderers/plugins/SpritePlugin.js',
-'extras/renderers/plugins/DepthPassPlugin.js',
-'extras/shaders/ShaderFlares.js',
-'extras/shaders/ShaderSprite.js'
-]
-
-CANVAS_FILES = [
-'Three.js',
-'core/Color.js',
-'core/Vector2.js',
-'core/Vector3.js',
-'core/Vector4.js',
-'core/Frustum.js',
-'core/Ray.js',
-'core/Rectangle.js',
-'core/Math.js',
-'core/Matrix3.js',
-'core/Matrix4.js',
-'core/Object3D.js',
-'core/Projector.js',
-'core/Quaternion.js',
-'core/Vertex.js',
-'core/Face3.js',
-'core/Face4.js',
-'core/UV.js',
-'core/Geometry.js',
-'cameras/Camera.js',
-'cameras/OrthographicCamera.js',
-'cameras/PerspectiveCamera.js',
-'lights/Light.js',
-'lights/AmbientLight.js',
-'lights/DirectionalLight.js',
-'lights/PointLight.js',
-'loaders/Loader.js',
-'loaders/BinaryLoader.js',
-'loaders/JSONLoader.js',
-'loaders/SceneLoader.js',
-'materials/Material.js',
-'materials/LineBasicMaterial.js',
-'materials/MeshBasicMaterial.js',
-'materials/MeshLambertMaterial.js',
-'materials/MeshPhongMaterial.js',
-'materials/MeshDepthMaterial.js',
-'materials/MeshNormalMaterial.js',
-'materials/MeshFaceMaterial.js',
-'materials/ParticleBasicMaterial.js',
-'materials/ParticleCanvasMaterial.js',
-'textures/Texture.js',
-'textures/DataTexture.js',
-'objects/Particle.js',
-'objects/Line.js',
-'objects/Mesh.js',
-'objects/Bone.js',
-'objects/Sprite.js',
-'scenes/Scene.js',
-'renderers/CanvasRenderer.js',
-'renderers/renderables/RenderableVertex.js',
-'renderers/renderables/RenderableFace3.js',
-'renderers/renderables/RenderableFace4.js',
-'renderers/renderables/RenderableObject.js',
-'renderers/renderables/RenderableParticle.js',
-'renderers/renderables/RenderableLine.js'
-]
-
-WEBGL_FILES = [
-'Three.js',
-'core/Color.js',
-'core/Vector2.js',
-'core/Vector3.js',
-'core/Vector4.js',
-'core/Frustum.js',
-'core/Ray.js',
-'core/Rectangle.js',
-'core/Math.js',
-'core/Matrix3.js',
-'core/Matrix4.js',
-'core/Object3D.js',
-'core/Projector.js',
-'core/Quaternion.js',
-'core/Vertex.js',
-'core/Face3.js',
-'core/Face4.js',
-'core/UV.js',
-'core/Geometry.js',
-'core/Spline.js',
-'cameras/Camera.js',
-'cameras/OrthographicCamera.js',
-'cameras/PerspectiveCamera.js',
-'lights/Light.js',
-'lights/AmbientLight.js',
-'lights/DirectionalLight.js',
-'lights/PointLight.js',
-'lights/SpotLight.js',
-'loaders/Loader.js',
-'loaders/BinaryLoader.js',
-'loaders/JSONLoader.js',
-'loaders/SceneLoader.js',
-'materials/Material.js',
-'materials/LineBasicMaterial.js',
-'materials/MeshBasicMaterial.js',
-'materials/MeshLambertMaterial.js',
-'materials/MeshPhongMaterial.js',
-'materials/MeshDepthMaterial.js',
-'materials/MeshNormalMaterial.js',
-'materials/MeshFaceMaterial.js',
-'materials/ParticleBasicMaterial.js',
-'materials/ShaderMaterial.js',
-'textures/Texture.js',
-'textures/DataTexture.js',
-'objects/Particle.js',
-'objects/ParticleSystem.js',
-'objects/Line.js',
-'objects/Mesh.js',
-'objects/Bone.js',
-'objects/SkinnedMesh.js',
-'objects/Ribbon.js',
-'objects/LOD.js',
-'objects/Sprite.js',
-'scenes/Scene.js',
-'scenes/Fog.js',
-'scenes/FogExp2.js',
-'renderers/WebGLShaders.js',
-'renderers/WebGLRenderer.js',
-'renderers/WebGLRenderTarget.js',
-'renderers/WebGLRenderTargetCube.js',
-'renderers/renderables/RenderableVertex.js',
-'renderers/renderables/RenderableFace3.js',
-'renderers/renderables/RenderableFace4.js',
-'renderers/renderables/RenderableObject.js',
-'renderers/renderables/RenderableParticle.js',
-'renderers/renderables/RenderableLine.js',
-'extras/core/BufferGeometry.js',
-'extras/core/Gyroscope.js',
-'extras/helpers/CameraHelper.js',
-'extras/objects/LensFlare.js',
-'extras/objects/ImmediateRenderObject.js',
-'extras/renderers/plugins/LensFlarePlugin.js',
-'extras/renderers/plugins/ShadowMapPlugin.js',
-'extras/renderers/plugins/SpritePlugin.js',
-'extras/shaders/ShaderFlares.js',
-'extras/shaders/ShaderSprite.js'
-]
+import json
 
 def merge(files):
 
@@ -364,6 +100,14 @@ def buildIncludes(files, filename):
 	text = "\n".join(template % f for f in files)
 
 	output(text, filename + '.js')
+	
+def getFileNames():
+	
+	file =  open(os.path.join('.', 'files.json'), 'r')
+	data = json.load(file)
+	file.close()
+	
+	return data
 
 
 def parse_args():
@@ -407,12 +151,13 @@ def main(argv=None):
 	args = parse_args()
 	debug = args.debug
 	minified = args.minified
+	files = getFileNames()
 
 	config = [
-	['Three', 'includes', '', COMMON_FILES + EXTRAS_FILES, args.common],
-	['ThreeCanvas', 'includes_canvas', '', CANVAS_FILES, args.canvas],
-	['ThreeWebGL', 'includes_webgl', '', WEBGL_FILES, args.webgl],
-	['ThreeExtras', 'includes_extras', 'externs_extras', EXTRAS_FILES, args.extras]
+	['Three', 'includes', '', files["COMMON"] + files["EXTRAS"], args.common],
+	['ThreeCanvas', 'includes_canvas', '', files["CANVAS"], args.canvas],
+	['ThreeWebGL', 'includes_webgl', '', files["WEBGL"], args.webgl],
+	['ThreeExtras', 'includes_extras', 'externs_extras', files["EXTRAS"], args.extras]
 	]
 
 	for fname_lib, fname_inc, fname_externs, files, enabled in config:

+ 431 - 0
utils/exporters/blender/2.63/scripts/addons/io_mesh_threejs/__init__.py

@@ -0,0 +1,431 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# ################################################################
+# Init
+# ################################################################
+
+
+bl_info = {
+    "name": "three.js format",
+    "author": "mrdoob, kikko, alteredq, remoe, pxf",
+    "version": (1, 3, 0),
+    "blender": (2, 6, 0),
+    "api": 35622,
+    "location": "File > Import-Export",
+    "description": "Import-Export three.js meshes",
+    "warning": "",
+    "wiki_url": "https://github.com/mrdoob/three.js/tree/master/utils/exporters/blender",
+    "tracker_url": "https://github.com/mrdoob/three.js/issues",
+    "category": "Import-Export"}
+
+# To support reload properly, try to access a package var,
+# if it's there, reload everything
+
+import bpy
+
+if "bpy" in locals():
+    import imp
+    if "export_threejs" in locals():
+        imp.reload(export_threejs)
+    if "import_threejs" in locals():
+        imp.reload(import_threejs)
+
+from bpy.props import *
+from bpy_extras.io_utils import ExportHelper, ImportHelper
+
+# ################################################################
+# Custom properties
+# ################################################################
+
+bpy.types.Object.THREE_castShadow = bpy.props.BoolProperty()
+bpy.types.Object.THREE_receiveShadow = bpy.props.BoolProperty()
+bpy.types.Object.THREE_doubleSided = bpy.props.BoolProperty()
+bpy.types.Object.THREE_exportGeometry = bpy.props.BoolProperty(default = True)
+
+bpy.types.Material.THREE_useVertexColors = bpy.props.BoolProperty()
+bpy.types.Material.THREE_depthWrite = bpy.props.BoolProperty(default = True)
+bpy.types.Material.THREE_depthTest = bpy.props.BoolProperty(default = True)
+
+THREE_material_types = [("Basic", "Basic", "Basic"), ("Phong", "Phong", "Phong"), ("Lambert", "Lambert", "Lambert")]
+bpy.types.Material.THREE_materialType = EnumProperty(name = "Material type", description = "Material type", items = THREE_material_types, default = "Lambert")
+
+THREE_blending_types = [("NoBlending", "NoBlending", "NoBlending"), ("NormalBlending", "NormalBlending", "NormalBlending"),
+                        ("AdditiveBlending", "AdditiveBlending", "AdditiveBlending"), ("SubtractiveBlending", "SubtractiveBlending", "SubtractiveBlending"),
+                        ("MultiplyBlending", "MultiplyBlending", "MultiplyBlending"), ("AdditiveAlphaBlending", "AdditiveAlphaBlending", "AdditiveAlphaBlending")]
+bpy.types.Material.THREE_blendingType = EnumProperty(name = "Blending type", description = "Blending type", items = THREE_blending_types, default = "NormalBlending")
+
+class OBJECT_PT_hello( bpy.types.Panel ):
+
+    bl_label = "THREE"
+    bl_space_type = "PROPERTIES"
+    bl_region_type = "WINDOW"
+    bl_context = "object"
+
+    def draw(self, context):
+        layout = self.layout
+        obj = context.object
+
+        row = layout.row()
+        row.label(text="Selected object: " + obj.name )
+
+        row = layout.row()
+        row.prop( obj, "THREE_exportGeometry", text="Export geometry" )
+
+        row = layout.row()
+        row.prop( obj, "THREE_castShadow", text="Casts shadow" )
+
+        row = layout.row()
+        row.prop( obj, "THREE_receiveShadow", text="Receives shadow" )
+
+        row = layout.row()
+        row.prop( obj, "THREE_doubleSided", text="Double sided" )
+
+class MATERIAL_PT_hello( bpy.types.Panel ):
+
+    bl_label = "THREE"
+    bl_space_type = "PROPERTIES"
+    bl_region_type = "WINDOW"
+    bl_context = "material"
+
+    def draw(self, context):
+        layout = self.layout
+        mat = context.material
+
+        row = layout.row()
+        row.label(text="Selected material: " + mat.name )
+
+        row = layout.row()
+        row.prop( mat, "THREE_materialType", text="Material type" )
+
+        row = layout.row()
+        row.prop( mat, "THREE_blendingType", text="Blending type" )
+
+        row = layout.row()
+        row.prop( mat, "THREE_useVertexColors", text="Use vertex colors" )
+
+        row = layout.row()
+        row.prop( mat, "THREE_depthWrite", text="Enable depth writing" )
+
+        row = layout.row()
+        row.prop( mat, "THREE_depthTest", text="Enable depth testing" )
+
+
+# ################################################################
+# Importer
+# ################################################################
+
+class ImportTHREEJS(bpy.types.Operator, ImportHelper):
+    '''Load a Three.js ASCII JSON model'''
+
+    bl_idname = "import.threejs"
+    bl_label = "Import Three.js"
+
+    filename_ext = ".js"
+    filter_glob = StringProperty(default="*.js", options={'HIDDEN'})
+
+    option_flip_yz = BoolProperty(name="Flip YZ", description="Flip YZ", default=True)
+    recalculate_normals = BoolProperty(name="Recalculate normals", description="Recalculate vertex normals", default=True)
+    option_worker = BoolProperty(name="Worker", description="Old format using workers", default=False)
+
+    def execute(self, context):
+        import io_mesh_threejs.import_threejs
+        return io_mesh_threejs.import_threejs.load(self, context, **self.properties)
+
+
+    def draw(self, context):
+        layout = self.layout
+
+        row = layout.row()
+        row.prop(self.properties, "option_flip_yz")
+
+        row = layout.row()
+        row.prop(self.properties, "recalculate_normals")
+
+        row = layout.row()
+        row.prop(self.properties, "option_worker")
+
+
+# ################################################################
+# Exporter - settings
+# ################################################################
+
+SETTINGS_FILE_EXPORT = "threejs_settings_export.js"
+
+import os
+import json
+
+def file_exists(filename):
+    """Return true if file exists and accessible for reading.
+
+    Should be safer than just testing for existence due to links and
+    permissions magic on Unix filesystems.
+
+    @rtype: boolean
+    """
+
+    try:
+        f = open(filename, 'r')
+        f.close()
+        return True
+    except IOError:
+        return False
+
+def get_settings_fullpath():
+    return os.path.join(bpy.app.tempdir, SETTINGS_FILE_EXPORT)
+
+def save_settings_export(properties):
+
+    settings = {
+    "option_export_scene" : properties.option_export_scene,
+    "option_embed_meshes" : properties.option_embed_meshes,
+    "option_url_base_html" : properties.option_url_base_html,
+    "option_copy_textures" : properties.option_copy_textures,
+
+    "option_lights" : properties.option_lights,
+    "option_cameras" : properties.option_cameras,
+
+    "option_animation" : properties.option_animation,
+    "option_frame_step" : properties.option_frame_step,
+    "option_all_meshes" : properties.option_all_meshes,
+
+    "option_flip_yz"      : properties.option_flip_yz,
+
+    "option_materials"       : properties.option_materials,
+    "option_normals"         : properties.option_normals,
+    "option_colors"          : properties.option_colors,
+    "option_uv_coords"       : properties.option_uv_coords,
+    "option_faces"           : properties.option_faces,
+    "option_vertices"        : properties.option_vertices,
+
+    "option_vertices_truncate" : properties.option_vertices_truncate,
+    "option_scale"        : properties.option_scale,
+
+    "align_model"         : properties.align_model
+    }
+
+    fname = get_settings_fullpath()
+    f = open(fname, "w")
+    json.dump(settings, f)
+
+def restore_settings_export(properties):
+
+    settings = {}
+
+    fname = get_settings_fullpath()
+    if file_exists(fname):
+        f = open(fname, "r")
+        settings = json.load(f)
+
+    properties.option_vertices = settings.get("option_vertices", True)
+    properties.option_vertices_truncate = settings.get("option_vertices_truncate", False)
+    properties.option_faces = settings.get("option_faces", True)
+    properties.option_normals = settings.get("option_normals", True)
+
+    properties.option_colors = settings.get("option_colors", True)
+    properties.option_uv_coords = settings.get("option_uv_coords", True)
+    properties.option_materials = settings.get("option_materials", True)
+
+    properties.align_model = settings.get("align_model", "None")
+
+    properties.option_scale = settings.get("option_scale", 1.0)
+    properties.option_flip_yz = settings.get("option_flip_yz", True)
+
+    properties.option_export_scene = settings.get("option_export_scene", False)
+    properties.option_embed_meshes = settings.get("option_embed_meshes", True)
+    properties.option_url_base_html = settings.get("option_url_base_html", False)
+    properties.option_copy_textures = settings.get("option_copy_textures", False)
+
+    properties.option_lights = settings.get("option_lights", False)
+    properties.option_cameras = settings.get("option_cameras", False)
+
+    properties.option_animation = settings.get("option_animation", False)
+    properties.option_frame_step = settings.get("option_frame_step", 1)
+    properties.option_all_meshes = settings.get("option_all_meshes", True)
+
+# ################################################################
+# Exporter
+# ################################################################
+
+class ExportTHREEJS(bpy.types.Operator, ExportHelper):
+    '''Export selected object / scene for Three.js (ASCII JSON format).'''
+
+    bl_idname = "export.threejs"
+    bl_label = "Export Three.js"
+
+    filename_ext = ".js"
+
+    option_vertices = BoolProperty(name = "Vertices", description = "Export vertices", default = True)
+    option_vertices_deltas = BoolProperty(name = "Deltas", description = "Delta vertices", default = False)
+    option_vertices_truncate = BoolProperty(name = "Truncate", description = "Truncate vertices", default = False)
+
+    option_faces = BoolProperty(name = "Faces", description = "Export faces", default = True)
+    option_faces_deltas = BoolProperty(name = "Deltas", description = "Delta faces", default = False)
+
+    option_normals = BoolProperty(name = "Normals", description = "Export normals", default = True)
+
+    option_colors = BoolProperty(name = "Colors", description = "Export vertex colors", default = True)
+    option_uv_coords = BoolProperty(name = "UVs", description = "Export texture coordinates", default = True)
+    option_materials = BoolProperty(name = "Materials", description = "Export materials", default = True)
+
+    align_types = [("None","None","None"), ("Center","Center","Center"), ("Bottom","Bottom","Bottom"), ("Top","Top","Top")]
+    align_model = EnumProperty(name = "Align model", description = "Align model", items = align_types, default = "None")
+
+    option_scale = FloatProperty(name = "Scale", description = "Scale vertices", min = 0.01, max = 1000.0, soft_min = 0.01, soft_max = 1000.0, default = 1.0)
+    option_flip_yz = BoolProperty(name = "Flip YZ", description = "Flip YZ", default = True)
+
+    option_export_scene = BoolProperty(name = "Scene", description = "Export scene", default = False)
+    option_embed_meshes = BoolProperty(name = "Embed meshes", description = "Embed meshes", default = True)
+    option_copy_textures = BoolProperty(name = "Copy textures", description = "Copy textures", default = False)
+    option_url_base_html = BoolProperty(name = "HTML as url base", description = "Use HTML as url base ", default = False)
+
+    option_lights = BoolProperty(name = "Lights", description = "Export default scene lights", default = False)
+    option_cameras = BoolProperty(name = "Cameras", description = "Export default scene cameras", default = False)
+
+    option_animation = BoolProperty(name = "Animation", description = "Export animation (morphs)", default = False)
+    option_frame_step = IntProperty(name = "Frame step", description = "Animation frame step", min = 1, max = 1000, soft_min = 1, soft_max = 1000, default = 1)
+    option_all_meshes = BoolProperty(name = "All meshes", description = "All meshes (merged)", default = True)
+
+    def invoke(self, context, event):
+        restore_settings_export(self.properties)
+        return ExportHelper.invoke(self, context, event)
+
+    @classmethod
+    def poll(cls, context):
+        return context.active_object != None
+
+    def execute(self, context):
+        print("Selected: " + context.active_object.name)
+
+        if not self.properties.filepath:
+            raise Exception("filename not set")
+
+        save_settings_export(self.properties)
+
+        filepath = self.filepath
+
+        import io_mesh_threejs.export_threejs
+        return io_mesh_threejs.export_threejs.save(self, context, **self.properties)
+
+    def draw(self, context):
+        layout = self.layout
+
+        row = layout.row()
+        row.label(text="Geometry:")
+
+        row = layout.row()
+        row.prop(self.properties, "option_vertices")
+        # row = layout.row()
+        # row.enabled = self.properties.option_vertices
+        # row.prop(self.properties, "option_vertices_deltas")
+        row.prop(self.properties, "option_vertices_truncate")
+        layout.separator()
+
+        row = layout.row()
+        row.prop(self.properties, "option_faces")
+        row = layout.row()
+        row.enabled = self.properties.option_faces
+        # row.prop(self.properties, "option_faces_deltas")
+        layout.separator()
+
+        row = layout.row()
+        row.prop(self.properties, "option_normals")
+        layout.separator()
+
+        row = layout.row()
+        row.label(text="Materials:")
+
+        row = layout.row()
+        row.prop(self.properties, "option_uv_coords")
+        row.prop(self.properties, "option_colors")
+        row = layout.row()
+        row.prop(self.properties, "option_materials")
+        layout.separator()
+
+        row = layout.row()
+        row.label(text="Settings:")
+
+        row = layout.row()
+        row.prop(self.properties, "align_model")
+        row = layout.row()
+        row.prop(self.properties, "option_flip_yz")
+        row.prop(self.properties, "option_scale")
+        layout.separator()
+
+        row = layout.row()
+        row.label(text="--------- Experimental ---------")
+        layout.separator()
+
+        row = layout.row()
+        row.label(text="Scene:")
+
+        row = layout.row()
+        row.prop(self.properties, "option_export_scene")
+        row.prop(self.properties, "option_embed_meshes")
+
+        row = layout.row()
+        row.prop(self.properties, "option_lights")
+        row.prop(self.properties, "option_cameras")
+        layout.separator()
+
+        row = layout.row()
+        row.label(text="Animation:")
+
+        row = layout.row()
+        row.prop(self.properties, "option_animation")
+        row.prop(self.properties, "option_frame_step")
+        layout.separator()
+
+        row = layout.row()
+        row.label(text="Settings:")
+
+        row = layout.row()
+        row.prop(self.properties, "option_all_meshes")
+
+        row = layout.row()
+        row.prop(self.properties, "option_copy_textures")
+
+        row = layout.row()
+        row.prop(self.properties, "option_url_base_html")
+
+        layout.separator()
+
+
+# ################################################################
+# Common
+# ################################################################
+
+def menu_func_export(self, context):
+    default_path = bpy.data.filepath.replace(".blend", ".js")
+    self.layout.operator(ExportTHREEJS.bl_idname, text="Three.js (.js)").filepath = default_path
+
+def menu_func_import(self, context):
+    self.layout.operator(ImportTHREEJS.bl_idname, text="Three.js (.js)")
+
+def register():
+    bpy.utils.register_module(__name__)
+    bpy.types.INFO_MT_file_export.append(menu_func_export)
+    bpy.types.INFO_MT_file_import.append(menu_func_import)
+
+def unregister():
+    bpy.utils.unregister_module(__name__)
+    bpy.types.INFO_MT_file_export.remove(menu_func_export)
+    bpy.types.INFO_MT_file_import.remove(menu_func_import)
+
+if __name__ == "__main__":
+    register()

+ 1939 - 0
utils/exporters/blender/2.63/scripts/addons/io_mesh_threejs/export_threejs.py

@@ -0,0 +1,1939 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+"""
+Blender exporter for Three.js (ASCII JSON format).
+
+TODO
+    - binary format
+"""
+
+import bpy
+import mathutils
+
+import shutil
+import os
+import os.path
+import math
+import operator
+import random
+
+# #####################################################
+# Configuration
+# #####################################################
+
+DEFAULTS = {
+"bgcolor" : [0, 0, 0],
+"bgalpha" : 1.0,
+
+"position" : [0, 0, 0],
+"rotation" : [-math.pi/2, 0, 0],
+"scale"    : [1, 1, 1],
+
+"camera"  :
+    {
+        "name" : "default_camera",
+        "type" : "perspective",
+        "near" : 1,
+        "far"  : 10000,
+        "fov"  : 60,
+        "aspect": 1.333,
+        "position" : [0, 0, 10],
+        "target"   : [0, 0, 0]
+    },
+
+"light" :
+ {
+    "name"       : "default_light",
+    "type"       : "directional",
+    "direction"  : [0, 1, 1],
+    "color"      : [1, 1, 1],
+    "intensity"  : 0.8
+ }
+}
+
+# default colors for debugging (each material gets one distinct color):
+# white, red, green, blue, yellow, cyan, magenta
+COLORS = [0xeeeeee, 0xee0000, 0x00ee00, 0x0000ee, 0xeeee00, 0x00eeee, 0xee00ee]
+
+
+# #####################################################
+# Templates - scene
+# #####################################################
+
+TEMPLATE_SCENE_ASCII = """\
+{
+
+"metadata" :
+{
+    "formatVersion" : 3,
+    "sourceFile"    : "%(fname)s",
+    "generatedBy"   : "Blender 2.63 Exporter",
+    "objects"       : %(nobjects)s,
+    "geometries"    : %(ngeometries)s,
+    "materials"     : %(nmaterials)s,
+    "textures"      : %(ntextures)s
+},
+
+"type" : "scene",
+"urlBaseType" : %(basetype)s,
+
+%(sections)s
+
+"transform" :
+{
+    "position"  : %(position)s,
+    "rotation"  : %(rotation)s,
+    "scale"     : %(scale)s
+},
+
+"defaults" :
+{
+    "bgcolor" : %(bgcolor)s,
+    "bgalpha" : %(bgalpha)f,
+    "camera"  : %(defcamera)s
+}
+
+}
+"""
+
+TEMPLATE_SECTION = """
+"%s" :
+{
+%s
+},
+"""
+
+TEMPLATE_OBJECT = """\
+    %(object_id)s : {
+        "geometry"  : %(geometry_id)s,
+        "groups"    : [ %(group_id)s ],
+        "materials" : [ %(material_id)s ],
+        "position"  : %(position)s,
+        "rotation"  : %(rotation)s,
+        "quaternion": %(quaternion)s,
+        "scale"     : %(scale)s,
+        "visible"       : %(visible)s,
+        "castShadow"    : %(castShadow)s,
+        "receiveShadow" : %(receiveShadow)s,
+        "doubleSided"   : %(doubleSided)s
+    }"""
+
+TEMPLATE_EMPTY = """\
+    %(object_id)s : {
+        "groups"    : [ %(group_id)s ],
+        "position"  : %(position)s,
+        "rotation"  : %(rotation)s,
+        "quaternion": %(quaternion)s,
+        "scale"     : %(scale)s
+    }"""
+
+TEMPLATE_GEOMETRY_LINK = """\
+    %(geometry_id)s : {
+        "type" : "ascii_mesh",
+        "url"  : %(model_file)s
+    }"""
+
+TEMPLATE_GEOMETRY_EMBED = """\
+    %(geometry_id)s : {
+        "type" : "embedded_mesh",
+        "id"  : %(embed_id)s
+    }"""
+
+TEMPLATE_TEXTURE = """\
+    %(texture_id)s : {
+        "url": %(texture_file)s%(extras)s
+    }"""
+
+TEMPLATE_MATERIAL_SCENE = """\
+    %(material_id)s : {
+        "type": %(type)s,
+        "parameters": { %(parameters)s }
+    }"""
+
+TEMPLATE_CAMERA_PERSPECTIVE = """\
+    %(camera_id)s : {
+        "type"  : "perspective",
+        "fov"   : %(fov)f,
+        "aspect": %(aspect)f,
+        "near"  : %(near)f,
+        "far"   : %(far)f,
+        "position": %(position)s,
+        "target"  : %(target)s
+    }"""
+
+TEMPLATE_CAMERA_ORTHO = """\
+    %(camera_id)s: {
+        "type"  : "ortho",
+        "left"  : %(left)f,
+        "right" : %(right)f,
+        "top"   : %(top)f,
+        "bottom": %(bottom)f,
+        "near"  : %(near)f,
+        "far"   : %(far)f,
+        "position": %(position)s,
+        "target"  : %(target)s
+    }"""
+
+TEMPLATE_LIGHT_DIRECTIONAL = """\
+    %(light_id)s: {
+        "type"    	 : "directional",
+        "direction"	 : %(direction)s,
+        "color" 	 : %(color)d,
+        "intensity"	 : %(intensity).2f
+    }"""
+
+TEMPLATE_LIGHT_POINT = """\
+    %(light_id)s: {
+        "type"	     : "point",
+        "position"   : %(position)s,
+        "color"      : %(color)d,
+        "intensity"	 : %(intensity).3f
+    }"""
+
+TEMPLATE_VEC4 = '[ %f, %f, %f, %f ]'
+TEMPLATE_VEC3 = '[ %f, %f, %f ]'
+TEMPLATE_VEC2 = '[ %f, %f ]'
+TEMPLATE_STRING = '"%s"'
+TEMPLATE_HEX = "0x%06x"
+
+# #####################################################
+# Templates - model
+# #####################################################
+
+TEMPLATE_FILE_ASCII = """\
+{
+
+    "metadata" :
+    {
+        "formatVersion" : 3,
+        "generatedBy"   : "Blender 2.63 Exporter",
+        "vertices"      : %(nvertex)d,
+        "faces"         : %(nface)d,
+        "normals"       : %(nnormal)d,
+        "colors"        : %(ncolor)d,
+        "uvs"           : %(nuv)d,
+        "materials"     : %(nmaterial)d,
+        "morphTargets"  : %(nmorphTarget)d
+    },
+
+%(model)s
+
+}
+"""
+
+TEMPLATE_MODEL_ASCII = """\
+    "scale" : %(scale)f,
+
+    "materials": [%(materials)s],
+
+    "vertices": [%(vertices)s],
+
+    "morphTargets": [%(morphTargets)s],
+
+    "normals": [%(normals)s],
+
+    "colors": [%(colors)s],
+
+    "uvs": [[%(uvs)s]],
+
+    "faces": [%(faces)s]
+
+"""
+
+TEMPLATE_VERTEX = "%f,%f,%f"
+TEMPLATE_VERTEX_TRUNCATE = "%d,%d,%d"
+
+TEMPLATE_N = "%f,%f,%f"
+TEMPLATE_UV = "%f,%f"
+TEMPLATE_C = "%d"
+
+# #####################################################
+# Utils
+# #####################################################
+
+def veckey3(x,y,z):
+    return round(x, 6), round(y, 6), round(z, 6)
+
+def veckey3d(v):
+    return veckey3(v.x, v.y, v.z)
+
+def veckey2d(v):
+    return round(v[0], 6), round(v[1], 6)
+
+def get_faces(obj):
+    if hasattr(obj, "tessfaces"):
+        return obj.tessfaces
+    else:
+        return obj.faces
+
+def get_normal_indices(v, normals, mesh):
+    n = []
+    mv = mesh.vertices
+
+    for i in v:
+        normal = mv[i].normal
+        key = veckey3d(normal)
+
+        n.append( normals[key] )
+
+    return n
+
+def get_uv_indices(face_index, uvs, mesh):
+    uv = []
+    uv_layer = mesh.tessface_uv_textures.active.data
+    for i in uv_layer[face_index].uv:
+        uv.append( uvs[veckey2d(i)] )
+    return uv
+
+def get_color_indices(face_index, colors, mesh):
+    c = []
+    color_layer = mesh.vertex_colors.active.data
+    face_colors = color_layer[face_index]
+    face_colors = face_colors.color1, face_colors.color2, face_colors.color3, face_colors.color4
+    for i in face_colors:
+        c.append( colors[hexcolor(i)] )
+    return c
+
+def rgb2int(rgb):
+    color = (int(rgb[0]*255) << 16) + (int(rgb[1]*255) << 8) + int(rgb[2]*255);
+    return color
+
+# #####################################################
+# Utils - files
+# #####################################################
+
+def write_file(fname, content):
+    out = open(fname, "w")
+    out.write(content)
+    out.close()
+
+def ensure_folder_exist(foldername):
+    """Create folder (with whole path) if it doesn't exist yet."""
+
+    if not os.access(foldername, os.R_OK|os.W_OK|os.X_OK):
+        os.makedirs(foldername)
+
+def ensure_extension(filepath, extension):
+    if not filepath.lower().endswith(extension):
+        filepath += extension
+    return filepath
+
+def generate_mesh_filename(meshname, filepath):
+    normpath = os.path.normpath(filepath)
+    path, ext = os.path.splitext(normpath)
+    return "%s.%s%s" % (path, meshname, ext)
+
+
+# #####################################################
+# Utils - alignment
+# #####################################################
+
+def bbox(vertices):
+    """Compute bounding box of vertex array.
+    """
+
+    if len(vertices)>0:
+        minx = maxx = vertices[0].co.x
+        miny = maxy = vertices[0].co.y
+        minz = maxz = vertices[0].co.z
+
+        for v in vertices[1:]:
+            if v.co.x < minx:
+                minx = v.co.x
+            elif v.co.x > maxx:
+                maxx = v.co.x
+
+            if v.co.y < miny:
+                miny = v.co.y
+            elif v.co.y > maxy:
+                maxy = v.co.y
+
+            if v.co.z < minz:
+                minz = v.co.z
+            elif v.co.z > maxz:
+                maxz = v.co.z
+
+        return { 'x':[minx,maxx], 'y':[miny,maxy], 'z':[minz,maxz] }
+
+    else:
+        return { 'x':[0,0], 'y':[0,0], 'z':[0,0] }
+
+def translate(vertices, t):
+    """Translate array of vertices by vector t.
+    """
+
+    for i in range(len(vertices)):
+        vertices[i].co.x += t[0]
+        vertices[i].co.y += t[1]
+        vertices[i].co.z += t[2]
+
+def center(vertices):
+    """Center model (middle of bounding box).
+    """
+
+    bb = bbox(vertices)
+
+    cx = bb['x'][0] + (bb['x'][1] - bb['x'][0])/2.0
+    cy = bb['y'][0] + (bb['y'][1] - bb['y'][0])/2.0
+    cz = bb['z'][0] + (bb['z'][1] - bb['z'][0])/2.0
+
+    translate(vertices, [-cx,-cy,-cz])
+
+def top(vertices):
+    """Align top of the model with the floor (Y-axis) and center it around X and Z.
+    """
+
+    bb = bbox(vertices)
+
+    cx = bb['x'][0] + (bb['x'][1] - bb['x'][0])/2.0
+    cy = bb['y'][1]
+    cz = bb['z'][0] + (bb['z'][1] - bb['z'][0])/2.0
+
+    translate(vertices, [-cx,-cy,-cz])
+
+def bottom(vertices):
+    """Align bottom of the model with the floor (Y-axis) and center it around X and Z.
+    """
+
+    bb = bbox(vertices)
+
+    cx = bb['x'][0] + (bb['x'][1] - bb['x'][0])/2.0
+    cy = bb['y'][0]
+    cz = bb['z'][0] + (bb['z'][1] - bb['z'][0])/2.0
+
+    translate(vertices, [-cx,-cy,-cz])
+
+# #####################################################
+# Elements rendering
+# #####################################################
+
+def hexcolor(c):
+    return ( int(c[0] * 255) << 16  ) + ( int(c[1] * 255) << 8 ) + int(c[2] * 255)
+
+def generate_vertices(vertices, option_vertices_truncate, option_vertices):
+    if not option_vertices:
+        return ""
+
+    return ",".join(generate_vertex(v, option_vertices_truncate) for v in vertices)
+
+def generate_vertex(v, option_vertices_truncate):
+    if not option_vertices_truncate:
+        return TEMPLATE_VERTEX % (v.co.x, v.co.y, v.co.z)
+    else:
+        return TEMPLATE_VERTEX_TRUNCATE % (v.co.x, v.co.y, v.co.z)
+
+def generate_normal(n):
+    return TEMPLATE_N % (n[0], n[1], n[2])
+
+def generate_vertex_color(c):
+    return TEMPLATE_C % c
+
+def generate_uv(uv):
+    return TEMPLATE_UV % (uv[0], 1.0 - uv[1])
+
+# #####################################################
+# Model exporter - faces
+# #####################################################
+
+def setBit(value, position, on):
+    if on:
+        mask = 1 << position
+        return (value | mask)
+    else:
+        mask = ~(1 << position)
+        return (value & mask)
+
+def generate_faces(normals, uvs, colors, meshes, option_normals, option_colors, option_uv_coords, option_materials, option_faces):
+
+    if not option_faces:
+        return "", 0
+
+    vertex_offset = 0
+    material_offset = 0
+
+    chunks = []
+    for mesh, object in meshes:
+
+        faceUV = (len(mesh.uv_textures) > 0)
+        vertexUV = (len(mesh.sticky) > 0)
+        vertexColors = len(mesh.vertex_colors) > 0
+
+        mesh_colors = option_colors and vertexColors
+        mesh_uvs = option_uv_coords and (faceUV or vertexUV)
+
+        if faceUV or vertexUV:
+            active_uv_layer = mesh.uv_textures.active
+            if not active_uv_layer:
+                mesh_extract_uvs = False
+
+        if vertexColors:
+            active_col_layer = mesh.vertex_colors.active
+            if not active_col_layer:
+                mesh_extract_colors = False
+
+        for i, f in enumerate(get_faces(mesh)):
+            face = generate_face(f, i, normals, uvs, colors, mesh, option_normals, mesh_colors, mesh_uvs, option_materials, vertex_offset, material_offset)
+            chunks.append(face)
+
+        vertex_offset += len(mesh.vertices)
+
+        material_count = len(mesh.materials)
+        if material_count == 0:
+            material_count = 1
+
+        material_offset += material_count
+
+    return ",".join(chunks), len(chunks)
+
+def generate_face(f, faceIndex, normals, uvs, colors, mesh, option_normals, option_colors, option_uv_coords, option_materials, vertex_offset, material_offset):
+    isTriangle = ( len(f.vertices) == 3 )
+
+    if isTriangle:
+        nVertices = 3
+    else:
+        nVertices = 4
+
+    hasMaterial = option_materials
+
+    hasFaceUvs = False # not supported in Blender
+    hasFaceVertexUvs = option_uv_coords
+
+    hasFaceNormals = False # don't export any face normals (as they are computed in engine)
+    hasFaceVertexNormals = option_normals
+
+    hasFaceColors = False       # not supported in Blender
+    hasFaceVertexColors = option_colors
+
+    faceType = 0
+    faceType = setBit(faceType, 0, not isTriangle)
+    faceType = setBit(faceType, 1, hasMaterial)
+    faceType = setBit(faceType, 2, hasFaceUvs)
+    faceType = setBit(faceType, 3, hasFaceVertexUvs)
+    faceType = setBit(faceType, 4, hasFaceNormals)
+    faceType = setBit(faceType, 5, hasFaceVertexNormals)
+    faceType = setBit(faceType, 6, hasFaceColors)
+    faceType = setBit(faceType, 7, hasFaceVertexColors)
+
+    faceData = []
+
+    # order is important, must match order in JSONLoader
+
+    # face type
+    # vertex indices
+    # material index
+    # face uvs index
+    # face vertex uvs indices
+    # face color index
+    # face vertex colors indices
+
+    faceData.append(faceType)
+
+    # must clamp in case on polygons bigger than quads
+
+    for i in range(nVertices):
+        index = f.vertices[i] + vertex_offset
+        faceData.append(index)
+
+    if hasMaterial:
+        index = f.material_index + material_offset
+        faceData.append( index )
+
+    if hasFaceVertexUvs:
+        uv = get_uv_indices(faceIndex, uvs, mesh)
+        for i in range(nVertices):
+            index = uv[i]
+            faceData.append(index)
+
+    if hasFaceVertexNormals:
+        n = get_normal_indices(f.vertices, normals, mesh)
+        for i in range(nVertices):
+            index = n[i]
+            faceData.append(index)
+
+    if hasFaceVertexColors:
+        c = get_color_indices(faceIndex, colors, mesh)
+        for i in range(nVertices):
+            index = c[i]
+            faceData.append(index)
+
+    return ",".join( map(str, faceData) )
+
+
+# #####################################################
+# Model exporter - normals
+# #####################################################
+
+def extract_vertex_normals(mesh, normals, count):
+    for f in get_faces(mesh):
+        for v in f.vertices:
+
+            normal = mesh.vertices[v].normal
+            key = veckey3d(normal)
+
+            if key not in normals:
+                normals[key] = count
+                count += 1
+
+    return count
+
+def generate_normals(normals, option_normals):
+    if not option_normals:
+        return ""
+
+    chunks = []
+    for key, index in sorted(normals.items(), key = operator.itemgetter(1)):
+        chunks.append(key)
+
+    return ",".join(generate_normal(n) for n in chunks)
+
+# #####################################################
+# Model exporter - vertex colors
+# #####################################################
+
+def extract_vertex_colors(mesh, colors, count):
+    color_layer = mesh.vertex_colors.active.data
+
+    for face_index, face in enumerate(get_faces(mesh)):
+
+        face_colors = color_layer[face_index]
+        face_colors = face_colors.color1, face_colors.color2, face_colors.color3, face_colors.color4
+
+        for c in face_colors:
+            key = hexcolor(c)
+            if key not in colors:
+                colors[key] = count
+                count += 1
+
+    return count
+
+def generate_vertex_colors(colors, option_colors):
+    if not option_colors:
+        return ""
+
+    chunks = []
+    for key, index in sorted(colors.items(), key=operator.itemgetter(1)):
+        chunks.append(key)
+
+    return ",".join(generate_vertex_color(c) for c in chunks)
+
+# #####################################################
+# Model exporter - UVs
+# #####################################################
+
+def extract_uvs(mesh, uvs, count):
+    uv_layer = mesh.tessface_uv_textures.active.data
+
+    for face_index, face in enumerate(get_faces(mesh)):
+
+        for uv_index, uv in enumerate(uv_layer[face_index].uv):
+
+            key = veckey2d(uv)
+            if key not in uvs:
+                uvs[key] = count
+                count += 1
+
+    return count
+
+def generate_uvs(uvs, option_uv_coords):
+    if not option_uv_coords:
+        return ""
+
+    chunks = []
+    for key, index in sorted(uvs.items(), key=operator.itemgetter(1)):
+        chunks.append(key)
+
+    return ",".join(generate_uv(n) for n in chunks)
+
+# #####################################################
+# Model exporter - materials
+# #####################################################
+
+def generate_color(i):
+    """Generate hex color corresponding to integer.
+
+    Colors should have well defined ordering.
+    First N colors are hardcoded, then colors are random
+    (must seed random number  generator with deterministic value
+    before getting colors).
+    """
+
+    if i < len(COLORS):
+        #return "0x%06x" % COLORS[i]
+        return COLORS[i]
+    else:
+        #return "0x%06x" % int(0xffffff * random.random())
+        return int(0xffffff * random.random())
+
+def generate_mtl(materials):
+    """Generate dummy materials.
+    """
+
+    mtl = {}
+    for m in materials:
+        index = materials[m]
+        mtl[m] = {
+            "DbgName": m,
+            "DbgIndex": index,
+            "DbgColor": generate_color(index),
+            "vertexColors" : False
+        }
+    return mtl
+
+def value2string(v):
+    if type(v) == str and v[0:2] != "0x":
+        return '"%s"' % v
+    elif type(v) == bool:
+        return str(v).lower()
+    elif type(v) == list:
+        return "[%s]" % (", ".join(value2string(x) for x in v))
+    return str(v)
+
+def generate_materials(mtl, materials, draw_type):
+    """Generate JS array of materials objects
+    """
+
+    mtl_array = []
+    for m in mtl:
+        index = materials[m]
+
+        # add debug information
+        #  materials should be sorted according to how
+        #  they appeared in OBJ file (for the first time)
+        #  this index is identifier used in face definitions
+        mtl[m]['DbgName'] = m
+        mtl[m]['DbgIndex'] = index
+        mtl[m]['DbgColor'] = generate_color(index)
+
+        if draw_type in [ "BOUNDS", "WIRE" ]:
+            mtl[m]['wireframe'] = True
+            mtl[m]['DbgColor'] = 0xff0000
+
+        mtl_raw = ",\n".join(['\t"%s" : %s' % (n, value2string(v)) for n,v in sorted(mtl[m].items())])
+        mtl_string = "\t{\n%s\n\t}" % mtl_raw
+        mtl_array.append([index, mtl_string])
+
+    return ",\n\n".join([m for i,m in sorted(mtl_array)]), len(mtl_array)
+
+def extract_materials(mesh, scene, option_colors, option_copy_textures, filepath):
+    world = scene.world
+
+    materials = {}
+    for m in mesh.materials:
+        if m:
+            materials[m.name] = {}
+            material = materials[m.name]
+
+            material['colorDiffuse'] = [m.diffuse_intensity * m.diffuse_color[0],
+                                        m.diffuse_intensity * m.diffuse_color[1],
+                                        m.diffuse_intensity * m.diffuse_color[2]]
+
+            material['colorSpecular'] = [m.specular_intensity * m.specular_color[0],
+                                         m.specular_intensity * m.specular_color[1],
+                                         m.specular_intensity * m.specular_color[2]]
+
+            world_ambient_color = [0, 0, 0]
+            if world:
+                world_ambient_color = world.ambient_color
+
+            material['colorAmbient'] = [m.ambient * world_ambient_color[0],
+                                        m.ambient * world_ambient_color[1],
+                                        m.ambient * world_ambient_color[2]]
+
+            material['transparency'] = m.alpha
+
+            # not sure about mapping values to Blinn-Phong shader
+            # Blender uses INT from [1, 511] with default 0
+            # http://www.blender.org/documentation/blender_python_api_2_54_0/bpy.types.Material.html#bpy.types.Material.specular_hardness
+
+            material["specularCoef"] = m.specular_hardness
+
+            textures = guess_material_textures(m)
+
+            handle_texture('diffuse', textures, material, filepath, option_copy_textures)
+            handle_texture('light', textures, material, filepath, option_copy_textures)
+            handle_texture('normal', textures, material, filepath, option_copy_textures)
+            handle_texture('specular', textures, material, filepath, option_copy_textures)
+
+            material["vertexColors"] = m.THREE_useVertexColors and option_colors
+
+            # can't really use this reliably to tell apart Phong from Lambert
+            # as Blender defaults to non-zero specular color
+            #if m.specular_intensity > 0.0 and (m.specular_color[0] > 0 or m.specular_color[1] > 0 or m.specular_color[2] > 0):
+            #    material['shading'] = "Phong"
+            #else:
+            #    material['shading'] = "Lambert"
+
+            if textures['normal']:
+                material['shading'] = "Phong"
+            else:
+                material['shading'] = m.THREE_materialType
+
+            material['blending'] = m.THREE_blendingType
+            material['depthWrite'] = m.THREE_depthWrite
+            material['depthTest'] = m.THREE_depthTest
+            material['transparent'] = m.use_transparency
+
+    return materials
+
+def generate_materials_string(mesh, scene, option_colors, draw_type, option_copy_textures, filepath, offset):
+
+    random.seed(42) # to get well defined color order for debug materials
+
+    materials = {}
+    if mesh.materials:
+        for i, m in enumerate(mesh.materials):
+            mat_id = i + offset
+            if m:
+                materials[m.name] = mat_id
+            else:
+                materials["undefined_dummy_%0d" % mat_id] = mat_id
+
+
+    if not materials:
+        materials = { 'default': 0 }
+
+    # default dummy materials
+
+    mtl = generate_mtl(materials)
+
+    # extract real materials from the mesh
+
+    mtl.update(extract_materials(mesh, scene, option_colors, option_copy_textures, filepath))
+
+    return generate_materials(mtl, materials, draw_type)
+
+def handle_texture(id, textures, material, filepath, option_copy_textures):
+
+    if textures[id]:
+        texName     = 'map%s'       % id.capitalize()
+        repeatName  = 'map%sRepeat' % id.capitalize()
+        wrapName    = 'map%sWrap'   % id.capitalize()
+
+        slot = textures[id]['slot']
+        texture = textures[id]['texture']
+        image = texture.image
+        fname = extract_texture_filename(image)
+        material[texName] = fname
+
+        if option_copy_textures:
+            save_image(image, fname, filepath)
+
+        if texture.repeat_x != 1 or texture.repeat_y != 1:
+            material[repeatName] = [texture.repeat_x, texture.repeat_y]
+
+        if texture.extension == "REPEAT":
+            wrap_x = "repeat"
+            wrap_y = "repeat"
+
+            if texture.use_mirror_x:
+                wrap_x = "mirror"
+            if texture.use_mirror_y:
+                wrap_y = "mirror"
+
+            material[wrapName] = [wrap_x, wrap_y]
+
+        if slot.use_map_normal:
+            if slot.normal_factor != 1.0:
+                material['mapNormalFactor'] = slot.normal_factor
+
+
+# #####################################################
+# ASCII model generator
+# #####################################################
+
+def generate_ascii_model(meshes, morphs,
+                         scene,
+                         option_vertices,
+                         option_vertices_truncate,
+                         option_faces,
+                         option_normals,
+                         option_uv_coords,
+                         option_materials,
+                         option_colors,
+                         align_model,
+                         flipyz,
+                         option_scale,
+                         option_copy_textures,
+                         filepath,
+                         option_animation,
+                         option_frame_step):
+
+    vertices = []
+
+    vertex_offset = 0
+    vertex_offsets = []
+
+    nnormal = 0
+    normals = {}
+
+    ncolor = 0
+    colors = {}
+
+    nuv = 0
+    uvs = {}
+
+    nmaterial = 0
+    materials = []
+
+    for mesh, object in meshes:
+
+        faceUV = (len(mesh.uv_textures) > 0)
+        vertexUV = (len(mesh.sticky) > 0)
+        vertexColors = len(mesh.vertex_colors) > 0
+
+        mesh_extract_colors = option_colors and vertexColors
+        mesh_extract_uvs = option_uv_coords and (faceUV or vertexUV)
+
+        if faceUV or vertexUV:
+            active_uv_layer = mesh.uv_textures.active
+            if not active_uv_layer:
+                mesh_extract_uvs = False
+
+        if vertexColors:
+            active_col_layer = mesh.vertex_colors.active
+            if not active_col_layer:
+                mesh_extract_colors = False
+
+        vertex_offsets.append(vertex_offset)
+        vertex_offset += len(vertices)
+
+        vertices.extend(mesh.vertices[:])
+
+        if option_normals:
+            nnormal = extract_vertex_normals(mesh, normals, nnormal)
+
+        if mesh_extract_colors:
+            ncolor = extract_vertex_colors(mesh, colors, ncolor)
+
+        if mesh_extract_uvs:
+            nuv = extract_uvs(mesh, uvs, nuv)
+
+        if option_materials:
+            mesh_materials, nmaterial = generate_materials_string(mesh, scene, mesh_extract_colors, object.draw_type, option_copy_textures, filepath, nmaterial)
+            materials.append(mesh_materials)
+
+
+    morphTargets_string = ""
+    nmorphTarget = 0
+
+    if option_animation:
+        chunks = []
+        for i, morphVertices in enumerate(morphs):
+            morphTarget = '{ "name": "%s_%06d", "vertices": [%s] }' % ("animation", i, morphVertices)
+            chunks.append(morphTarget)
+
+        morphTargets_string = ",\n\t".join(chunks)
+        nmorphTarget = len(morphs)
+
+    if align_model == 1:
+        center(vertices)
+    elif align_model == 2:
+        bottom(vertices)
+    elif align_model == 3:
+        top(vertices)
+
+    faces_string, nfaces = generate_faces(normals, uvs, colors, meshes, option_normals, option_colors, option_uv_coords, option_materials, option_faces)
+
+    materials_string = ",\n\n".join(materials)
+
+    model_string = TEMPLATE_MODEL_ASCII % {
+    "scale" : option_scale,
+
+    "uvs"       : generate_uvs(uvs, option_uv_coords),
+    "normals"   : generate_normals(normals, option_normals),
+    "colors"    : generate_vertex_colors(colors, option_colors),
+
+    "materials" : materials_string,
+
+    "vertices" : generate_vertices(vertices, option_vertices_truncate, option_vertices),
+
+    "faces"    : faces_string,
+
+    "morphTargets" : morphTargets_string
+    }
+
+    text = TEMPLATE_FILE_ASCII % {
+    "nvertex"   : len(vertices),
+    "nface"     : nfaces,
+    "nuv"       : nuv,
+    "nnormal"   : nnormal,
+    "ncolor"    : ncolor,
+    "nmaterial" : nmaterial,
+    "nmorphTarget": nmorphTarget,
+
+    "model"     : model_string
+    }
+
+
+    return text, model_string
+
+
+# #####################################################
+# Model exporter - export single mesh
+# #####################################################
+
+def extract_meshes(objects, scene, export_single_model, option_scale, flipyz):
+
+    meshes = []
+
+    for object in objects:
+
+        if object.type == "MESH" and object.THREE_exportGeometry:
+
+            # collapse modifiers into mesh
+
+            mesh = object.to_mesh(scene, True, 'RENDER')
+
+            if not mesh:
+                raise Exception("Error, could not get mesh data from object [%s]" % object.name)
+
+            if export_single_model:
+                if flipyz:
+                    # that's what Blender's native export_obj.py does
+                    # to flip YZ
+                    X_ROT = mathutils.Matrix.Rotation(-math.pi/2, 4, 'X')
+                    mesh.transform(X_ROT * object.matrix_world)
+                else:
+                    mesh.transform(object.matrix_world)
+
+            mesh.calc_normals()
+            mesh.transform(mathutils.Matrix.Scale(option_scale, 4))
+            meshes.append([mesh, object])
+
+    return meshes
+
+def generate_mesh_string(objects, scene,
+                option_vertices,
+                option_vertices_truncate,
+                option_faces,
+                option_normals,
+                option_uv_coords,
+                option_materials,
+                option_colors,
+                align_model,
+                flipyz,
+                option_scale,
+                export_single_model,
+                option_copy_textures,
+                filepath,
+                option_animation,
+                option_frame_step):
+
+    meshes = extract_meshes(objects, scene, export_single_model, option_scale, flipyz)
+
+    morphs = []
+
+    if option_animation:
+
+        original_frame = scene.frame_current # save animation state
+
+        scene_frames = range(scene.frame_start, scene.frame_end + 1, option_frame_step)
+
+        for frame in scene_frames:
+            scene.frame_set(frame, 0.0)
+
+            anim_meshes = extract_meshes(objects, scene, export_single_model, option_scale, flipyz)
+
+            frame_vertices = []
+
+            for mesh, object in anim_meshes:
+                frame_vertices.extend(mesh.vertices[:])
+
+            morphVertices = generate_vertices(frame_vertices, option_vertices_truncate, option_vertices)
+            morphs.append(morphVertices)
+
+            # remove temp meshes
+
+            for mesh, object in anim_meshes:
+                bpy.data.meshes.remove(mesh)
+
+        scene.frame_set(original_frame, 0.0) # restore animation state
+
+
+    text, model_string = generate_ascii_model(meshes, morphs,
+                                scene,
+                                option_vertices,
+                                option_vertices_truncate,
+                                option_faces,
+                                option_normals,
+                                option_uv_coords,
+                                option_materials,
+                                option_colors,
+                                align_model,
+                                flipyz,
+                                option_scale,
+                                option_copy_textures,
+                                filepath,
+                                option_animation,
+                                option_frame_step)
+
+    # remove temp meshes
+
+    for mesh, object in meshes:
+        bpy.data.meshes.remove(mesh)
+
+    return text, model_string
+
+def export_mesh(objects,
+                scene, filepath,
+                option_vertices,
+                option_vertices_truncate,
+                option_faces,
+                option_normals,
+                option_uv_coords,
+                option_materials,
+                option_colors,
+                align_model,
+                flipyz,
+                option_scale,
+                export_single_model,
+                option_copy_textures,
+                option_animation,
+                option_frame_step):
+
+    """Export single mesh"""
+
+    text, model_string = generate_mesh_string(objects,
+                scene,
+                option_vertices,
+                option_vertices_truncate,
+                option_faces,
+                option_normals,
+                option_uv_coords,
+                option_materials,
+                option_colors,
+                align_model,
+                flipyz,
+                option_scale,
+                export_single_model,
+                option_copy_textures,
+                filepath,
+                option_animation,
+                option_frame_step)
+
+    write_file(filepath, text)
+
+    print("writing", filepath, "done")
+
+
+# #####################################################
+# Scene exporter - render elements
+# #####################################################
+
+def generate_vec4(vec):
+    return TEMPLATE_VEC4 % (vec[0], vec[1], vec[2], vec[3])
+
+def generate_vec3(vec):
+    return TEMPLATE_VEC3 % (vec[0], vec[1], vec[2])
+
+def generate_vec2(vec):
+    return TEMPLATE_VEC2 % (vec[0], vec[1])
+
+def generate_hex(number):
+    return TEMPLATE_HEX % number
+
+def generate_string(s):
+    return TEMPLATE_STRING % s
+
+def generate_string_list(src_list):
+    return ", ".join(generate_string(item) for item in src_list)
+
+def generate_section(label, content):
+    return TEMPLATE_SECTION % (label, content)
+
+def get_mesh_filename(mesh):
+    object_id = mesh["data"]["name"]
+    filename = "%s.js" % sanitize(object_id)
+    return filename
+
+def generate_material_id_list(materials):
+    chunks = []
+    for material in materials:
+        chunks.append(material.name)
+
+    return chunks
+
+def generate_group_id_list(obj):
+    chunks = []
+
+    for group in bpy.data.groups:
+        if obj.name in group.objects:
+            chunks.append(group.name)
+
+    return chunks
+
+def generate_bool_property(property):
+    if property:
+        return "true"
+    return "false"
+
+# #####################################################
+# Scene exporter - objects
+# #####################################################
+
+def generate_objects(data):
+    chunks = []
+
+    for obj in data["objects"]:
+
+        if obj.type == "MESH" and obj.THREE_exportGeometry:
+            object_id = obj.name
+
+            if len(obj.modifiers) > 0:
+                geo_name = obj.name
+            else:
+                geo_name = obj.data.name
+
+            geometry_id = "geo_%s" % geo_name
+
+            material_ids = generate_material_id_list(obj.material_slots)
+            group_ids = generate_group_id_list(obj)
+
+            position, quaternion, scale = obj.matrix_world.decompose()
+            rotation = quaternion.to_euler("XYZ")
+
+            material_string = ""
+            if len(material_ids) > 0:
+                material_string = generate_string_list(material_ids)
+
+            group_string = ""
+            if len(group_ids) > 0:
+                group_string = generate_string_list(group_ids)
+
+            castShadow = obj.THREE_castShadow
+            receiveShadow = obj.THREE_receiveShadow
+            doubleSided = obj.THREE_doubleSided
+
+            visible = True
+
+            geometry_string = generate_string(geometry_id)
+
+            object_string = TEMPLATE_OBJECT % {
+            "object_id"   : generate_string(object_id),
+            "geometry_id" : geometry_string,
+            "group_id"    : group_string,
+            "material_id" : material_string,
+
+            "position"    : generate_vec3(position),
+            "rotation"    : generate_vec3(rotation),
+            "quaternion"  : generate_vec4(quaternion),
+            "scale"       : generate_vec3(scale),
+
+            "castShadow"  : generate_bool_property(castShadow),
+            "receiveShadow"  : generate_bool_property(receiveShadow),
+            "doubleSided"  : generate_bool_property(doubleSided),
+            "visible"      : generate_bool_property(visible)
+            }
+            chunks.append(object_string)
+
+        elif obj.type == "EMPTY" or (obj.type == "MESH" and not obj.THREE_exportGeometry):
+
+            object_id = obj.name
+            group_ids = generate_group_id_list(obj)
+
+            position, quaternion, scale = obj.matrix_world.decompose()
+            rotation = quaternion.to_euler("XYZ")
+
+            group_string = ""
+            if len(group_ids) > 0:
+                group_string = generate_string_list(group_ids)
+
+            object_string = TEMPLATE_EMPTY % {
+            "object_id"   : generate_string(object_id),
+            "group_id"    : group_string,
+
+            "position"    : generate_vec3(position),
+            "rotation"    : generate_vec3(rotation),
+            "quaternion"  : generate_vec4(quaternion),
+            "scale"       : generate_vec3(scale)
+            }
+            chunks.append(object_string)
+
+    return ",\n\n".join(chunks), len(chunks)
+
+# #####################################################
+# Scene exporter - geometries
+# #####################################################
+
+def generate_geometries(data):
+    chunks = []
+
+    geo_set = set()
+
+    for obj in data["objects"]:
+        if obj.type == "MESH" and obj.THREE_exportGeometry:
+
+            if len(obj.modifiers) > 0:
+                name = obj.name
+            else:
+                name = obj.data.name
+
+            if name not in geo_set:
+
+                geometry_id = "geo_%s" % name
+
+                if data["embed_meshes"]:
+
+                    embed_id = "emb_%s" % name
+
+                    geometry_string = TEMPLATE_GEOMETRY_EMBED % {
+                    "geometry_id" : generate_string(geometry_id),
+                    "embed_id"  : generate_string(embed_id)
+                    }
+
+                else:
+
+                    model_filename = os.path.basename(generate_mesh_filename(name, data["filepath"]))
+
+                    geometry_string = TEMPLATE_GEOMETRY_LINK % {
+                    "geometry_id" : generate_string(geometry_id),
+                    "model_file"  : generate_string(model_filename)
+                    }
+
+                chunks.append(geometry_string)
+
+                geo_set.add(name)
+
+    return ",\n\n".join(chunks), len(chunks)
+
+# #####################################################
+# Scene exporter - textures
+# #####################################################
+
+def generate_textures_scene(data):
+    chunks = []
+
+    # TODO: extract just textures actually used by some objects in the scene
+
+    for texture in bpy.data.textures:
+
+        if texture.type == 'IMAGE' and texture.image:
+
+            img = texture.image
+
+            texture_id = img.name
+            texture_file = extract_texture_filename(img)
+
+            if data["copy_textures"]:
+                save_image(img, texture_file, data["filepath"])
+
+            extras = ""
+
+            if texture.repeat_x != 1 or texture.repeat_y != 1:
+                extras += ',\n        "repeat": [%f, %f]' % (texture.repeat_x, texture.repeat_y)
+
+            if texture.extension == "REPEAT":
+                wrap_x = "repeat"
+                wrap_y = "repeat"
+
+                if texture.use_mirror_x:
+                    wrap_x = "mirror"
+                if texture.use_mirror_y:
+                    wrap_y = "mirror"
+
+                extras += ',\n        "wrap": ["%s", "%s"]' % (wrap_x, wrap_y)
+
+            texture_string = TEMPLATE_TEXTURE % {
+            "texture_id"   : generate_string(texture_id),
+            "texture_file" : generate_string(texture_file),
+            "extras"       : extras
+            }
+            chunks.append(texture_string)
+
+    return ",\n\n".join(chunks), len(chunks)
+
+def extract_texture_filename(image):
+    fn = bpy.path.abspath(image.filepath)
+    fn = os.path.normpath(fn)
+    fn_strip = os.path.basename(fn)
+    return fn_strip
+
+def save_image(img, name, fpath):
+    dst_dir = os.path.dirname(fpath)
+    dst_path = os.path.join(dst_dir, name)
+
+    ensure_folder_exist(dst_dir)
+
+    if img.packed_file:
+        img.save_render(dst_path)
+
+    else:
+        src_path = bpy.path.abspath(img.filepath)
+        shutil.copy(src_path, dst_dir)
+
+# #####################################################
+# Scene exporter - materials
+# #####################################################
+
+def extract_material_data(m, option_colors):
+    world = bpy.context.scene.world
+
+    material = { 'name': m.name }
+
+    material['colorDiffuse'] = [m.diffuse_intensity * m.diffuse_color[0],
+                                m.diffuse_intensity * m.diffuse_color[1],
+                                m.diffuse_intensity * m.diffuse_color[2]]
+
+    material['colorSpecular'] = [m.specular_intensity * m.specular_color[0],
+                                 m.specular_intensity * m.specular_color[1],
+                                 m.specular_intensity * m.specular_color[2]]
+
+    world_ambient_color = [0, 0, 0]
+    if world:
+        world_ambient_color = world.ambient_color
+
+    material['colorAmbient'] = [m.ambient * world_ambient_color[0],
+                                m.ambient * world_ambient_color[1],
+                                m.ambient * world_ambient_color[2]]
+
+    material['transparency'] = m.alpha
+
+    # not sure about mapping values to Blinn-Phong shader
+    # Blender uses INT from [1,511] with default 0
+    # http://www.blender.org/documentation/blender_python_api_2_54_0/bpy.types.Material.html#bpy.types.Material.specular_hardness
+
+    material["specularCoef"] = m.specular_hardness
+
+    material["vertexColors"] = m.THREE_useVertexColors and option_colors
+
+    material['mapDiffuse'] = ""
+    material['mapLight'] = ""
+    material['mapSpecular'] = ""
+    material['mapNormal'] = ""
+    material['mapNormalFactor'] = 1.0
+
+    textures = guess_material_textures(m)
+
+    if textures['diffuse']:
+        material['mapDiffuse'] = textures['diffuse']['texture'].image.name
+
+    if textures['light']:
+        material['mapLight'] = textures['light']['texture'].image.name
+
+    if textures['specular']:
+        material['mapSpecular'] = textures['specular']['texture'].image.name
+
+    if textures['normal']:
+        material['mapNormal'] = textures['normal']['texture'].image.name
+        if textures['normal']['slot'].use_map_normal:
+            material['mapNormalFactor'] = textures['normal']['slot'].normal_factor
+
+    material['shading'] = m.THREE_materialType
+    material['blending'] = m.THREE_blendingType
+    material['depthWrite'] = m.THREE_depthWrite
+    material['depthTest'] = m.THREE_depthTest
+    material['transparent'] = m.use_transparency
+
+    return material
+
+def guess_material_textures(material):
+    textures = {
+        'diffuse' : None,
+        'light'   : None,
+        'normal'  : None,
+        'specular': None
+    }
+
+    # just take first textures of each, for the moment three.js materials can't handle more
+    # assume diffuse comes before lightmap, normalmap has checked flag
+
+    for i in range(len(material.texture_slots)):
+        slot = material.texture_slots[i]
+        if slot:
+            texture = slot.texture
+            if slot.use and texture and texture.type == 'IMAGE':
+
+                if texture.use_normal_map:
+                    textures['normal'] = { "texture": texture, "slot": slot }
+
+                elif slot.use_map_specular or slot.use_map_hardness:
+                    textures['specular'] = { "texture": texture, "slot": slot }
+
+                else:
+                    if not textures['diffuse']:
+                        textures['diffuse'] = { "texture": texture, "slot": slot }
+
+                    else:
+                        textures['light'] = { "texture": texture, "slot": slot }
+
+                if textures['diffuse'] and textures['normal'] and textures['light'] and textures['specular']:
+                    break
+
+    return textures
+
+def generate_material_string(material):
+
+    material_id = material["name"]
+
+    # default to Lambert
+
+    shading = material.get("shading", "Lambert")
+
+    # normal mapped materials must use Phong
+    # to get all required parameters for normal shader
+
+    if material['mapNormal']:
+        shading = "Phong"
+
+    type_map = {
+    "Lambert"   : "MeshLambertMaterial",
+    "Phong"     : "MeshPhongMaterial"
+    }
+
+    material_type = type_map.get(shading, "MeshBasicMaterial")
+
+    parameters = '"color": %d' % rgb2int(material["colorDiffuse"])
+    parameters += ', "opacity": %.2g' % material["transparency"]
+
+    if shading == "Phong":
+        parameters += ', "ambient": %d' % rgb2int(material["colorAmbient"])
+        parameters += ', "specular": %d' % rgb2int(material["colorSpecular"])
+        parameters += ', "shininess": %.1g' % material["specularCoef"]
+
+    colorMap = material['mapDiffuse']
+    lightMap = material['mapLight']
+    specularMap = material['mapSpecular']
+    normalMap = material['mapNormal']
+    normalMapFactor = material['mapNormalFactor']
+
+    if colorMap:
+        parameters += ', "map": %s' % generate_string(colorMap)
+    if lightMap:
+        parameters += ', "lightMap": %s' % generate_string(lightMap)
+    if specularMap:
+        parameters += ', "specularMap": %s' % generate_string(specularMap)
+    if normalMap:
+        parameters += ', "normalMap": %s' % generate_string(normalMap)
+
+    if normalMapFactor != 1.0:
+        parameters += ', "normalMapFactor": %f' % normalMapFactor
+
+    if material['vertexColors']:
+        parameters += ', "vertexColors": "vertex"'
+
+    if material['transparent']:
+        parameters += ', "transparent": true'
+
+    parameters += ', "blending": "%s"' % material['blending']
+
+    if not material['depthWrite']:
+        parameters += ', "depthWrite": false'
+
+    if not material['depthTest']:
+        parameters += ', "depthTest": false'
+
+
+    material_string = TEMPLATE_MATERIAL_SCENE % {
+    "material_id" : generate_string(material_id),
+    "type"        : generate_string(material_type),
+    "parameters"  : parameters
+    }
+
+    return material_string
+
+def generate_materials_scene(data):
+    chunks = []
+
+    # TODO: extract just materials actually used by some objects in the scene
+
+    for m in bpy.data.materials:
+        material = extract_material_data(m, data["use_colors"])
+        material_string = generate_material_string(material)
+        chunks.append(material_string)
+
+    return ",\n\n".join(chunks), len(chunks)
+
+# #####################################################
+# Scene exporter - cameras
+# #####################################################
+
+def generate_cameras(data):
+    if data["use_cameras"]:
+
+        cams = bpy.data.objects
+        cams = [ob for ob in cams if (ob.type == 'CAMERA' and ob.select)]
+
+        chunks = []
+
+        if not cams:
+            camera = DEFAULTS["camera"]
+
+            if camera["type"] == "perspective":
+
+                camera_string = TEMPLATE_CAMERA_PERSPECTIVE % {
+                "camera_id" : generate_string(camera["name"]),
+                "fov"       : camera["fov"],
+                "aspect"    : camera["aspect"],
+                "near"      : camera["near"],
+                "far"       : camera["far"],
+                "position"  : generate_vec3(camera["position"]),
+                "target"    : generate_vec3(camera["target"])
+                }
+
+            elif camera["type"] == "ortho":
+
+                camera_string = TEMPLATE_CAMERA_ORTHO % {
+                "camera_id" : generate_string(camera["name"]),
+                "left"      : camera["left"],
+                "right"     : camera["right"],
+                "top"       : camera["top"],
+                "bottom"    : camera["bottom"],
+                "near"      : camera["near"],
+                "far"       : camera["far"],
+                "position"  : generate_vec3(camera["position"]),
+                "target"    : generate_vec3(camera["target"])
+                }
+
+            chunks.append(camera_string)
+
+        else:
+
+            for cameraobj in cams:
+                camera = bpy.data.cameras[cameraobj.name]
+
+                # TODO:
+                #   Support more than perspective camera
+                #   Calculate a target/lookat
+                #   Get correct aspect ratio
+                if camera.id_data.type == "PERSP":
+
+                    camera_string = TEMPLATE_CAMERA_PERSPECTIVE % {
+                    "camera_id" : generate_string(camera.name),
+                    "fov"       : (camera.angle / 3.14) * 180.0,
+                    "aspect"    : 1.333,
+                    "near"      : camera.clip_start,
+                    "far"       : camera.clip_end,
+                    "position"  : generate_vec3([cameraobj.location[0], -cameraobj.location[1], cameraobj.location[2]]),
+                    "target"    : generate_vec3([0, 0, 0])
+                    }
+
+                chunks.append(camera_string)
+
+        return ",\n\n".join(chunks)
+
+    return ""
+
+# #####################################################
+# Scene exporter - lights
+# #####################################################
+
+def generate_lights(data):
+
+    if data["use_lights"]:
+
+        lights = data.get("lights", [])
+        if not lights:
+            lights.append(DEFAULTS["light"])
+
+        chunks = []
+        for light in lights:
+
+            if light["type"] == "directional":
+                light_string = TEMPLATE_LIGHT_DIRECTIONAL % {
+                "light_id"      : generate_string(light["name"]),
+                "direction"     : generate_vec3(light["direction"]),
+                "color"         : rgb2int(light["color"]),
+                "intensity"     : light["intensity"]
+                }
+
+            elif light["type"] == "point":
+                light_string = TEMPLATE_LIGHT_POINT % {
+                "light_id"      : generate_string(light["name"]),
+                "position"      : generate_vec3(light["position"]),
+                "color"         : rgb2int(light["color"]),
+                "intensity"     : light["intensity"]
+                }
+
+            chunks.append(light_string)
+
+        return ",\n\n".join(chunks)
+
+    return ""
+
+# #####################################################
+# Scene exporter - embedded meshes
+# #####################################################
+
+def generate_embeds(data):
+
+    if data["embed_meshes"]:
+
+        chunks = []
+
+        for e in data["embeds"]:
+
+            embed = '"emb_%s": {%s}' % (e, data["embeds"][e])
+            chunks.append(embed)
+
+        return ",\n\n".join(chunks)
+
+    return ""
+
+# #####################################################
+# Scene exporter - generate ASCII scene
+# #####################################################
+
+def generate_ascii_scene(data):
+
+    objects, nobjects = generate_objects(data)
+    geometries, ngeometries = generate_geometries(data)
+    textures, ntextures = generate_textures_scene(data)
+    materials, nmaterials = generate_materials_scene(data)
+
+    cameras = generate_cameras(data)
+    lights = generate_lights(data)
+
+    embeds = generate_embeds(data)
+
+    basetype = "relativeTo"
+
+    if data["base_html"]:
+        basetype += "HTML"
+    else:
+        basetype += "Scene"
+
+    sections = [
+    ["objects",    objects],
+    ["geometries", geometries],
+    ["textures",   textures],
+    ["materials",  materials],
+    ["cameras",    cameras],
+    ["lights",     lights],
+    ["embeds",     embeds]
+    ]
+
+    chunks = []
+    for label, content in sections:
+        if content:
+            chunks.append(generate_section(label, content))
+
+    sections_string = "\n".join(chunks)
+
+    default_camera = ""
+    if data["use_cameras"]:
+        cams = [ob for ob in bpy.data.objects if (ob.type == 'CAMERA' and ob.select)]
+        if not cams:
+            default_camera = "default_camera"
+        else:
+            default_camera = cams[0].name
+
+    parameters = {
+    "fname"     : data["source_file"],
+
+    "sections"  : sections_string,
+
+    "bgcolor"   : generate_vec3(DEFAULTS["bgcolor"]),
+    "bgalpha"   : DEFAULTS["bgalpha"],
+    "defcamera" :  generate_string(default_camera),
+
+    "nobjects"      : nobjects,
+    "ngeometries"   : ngeometries,
+    "ntextures"     : ntextures,
+    "basetype"      : generate_string(basetype),
+    "nmaterials"    : nmaterials,
+
+    "position"      : generate_vec3(DEFAULTS["position"]),
+    "rotation"      : generate_vec3(DEFAULTS["rotation"]),
+    "scale"         : generate_vec3(DEFAULTS["scale"])
+    }
+
+    text = TEMPLATE_SCENE_ASCII % parameters
+
+    return text
+
+def export_scene(scene, filepath, flipyz, option_colors, option_lights, option_cameras, option_embed_meshes, embeds, option_url_base_html, option_copy_textures):
+
+    source_file = os.path.basename(bpy.data.filepath)
+
+    # objects are contained in scene and linked groups
+    objects = []
+
+    # get scene objects
+    sceneobjects = scene.objects
+    for obj in sceneobjects:
+      objects.append(obj)
+
+    # get linked group objcts
+    for group in bpy.data.groups:
+       for object in group.objects:
+          objects.append(object)
+
+    scene_text = ""
+    data = {
+    "scene"        : scene,
+    "objects"      : objects,
+    "embeds"       : embeds,
+    "source_file"  : source_file,
+    "filepath"     : filepath,
+    "flipyz"       : flipyz,
+    "use_colors"   : option_colors,
+    "use_lights"   : option_lights,
+    "use_cameras"  : option_cameras,
+    "embed_meshes" : option_embed_meshes,
+    "base_html"    : option_url_base_html,
+    "copy_textures": option_copy_textures
+    }
+    scene_text += generate_ascii_scene(data)
+
+    write_file(filepath, scene_text)
+
+# #####################################################
+# Main
+# #####################################################
+
+def save(operator, context, filepath = "",
+         option_flip_yz = True,
+         option_vertices = True,
+         option_vertices_truncate = False,
+         option_faces = True,
+         option_normals = True,
+         option_uv_coords = True,
+         option_materials = True,
+         option_colors = True,
+         align_model = 0,
+         option_export_scene = False,
+         option_lights = False,
+         option_cameras = False,
+         option_scale = 1.0,
+         option_embed_meshes = True,
+         option_url_base_html = False,
+         option_copy_textures = False,
+         option_animation = False,
+         option_frame_step = 1,
+         option_all_meshes = True):
+
+    #print("URL TYPE", option_url_base_html)
+
+    filepath = ensure_extension(filepath, '.js')
+
+    scene = context.scene
+
+    if scene.objects.active:
+        bpy.ops.object.mode_set(mode='OBJECT')
+
+    if option_all_meshes:
+        sceneobjects = scene.objects
+    else:
+        sceneobjects = context.selected_objects
+
+    # objects are contained in scene and linked groups
+    objects = []
+
+    # get scene objects
+    for obj in sceneobjects:
+      objects.append(obj)
+
+    # get objects in linked groups
+    for group in bpy.data.groups:
+       for object in group.objects:
+          objects.append(object)
+
+    if option_export_scene:
+
+        geo_set = set()
+        embeds = {}
+
+        for object in objects:
+            if object.type == "MESH" and object.THREE_exportGeometry:
+
+                # create extra copy of geometry with applied modifiers
+                # (if they exist)
+
+                if len(object.modifiers) > 0:
+                    name = object.name
+
+                # otherwise can share geometry
+
+                else:
+                    name = object.data.name
+
+                if name not in geo_set:
+
+                    if option_embed_meshes:
+
+                        text, model_string = generate_mesh_string([object], scene,
+                                                        option_vertices,
+                                                        option_vertices_truncate,
+                                                        option_faces,
+                                                        option_normals,
+                                                        option_uv_coords,
+                                                        option_materials,
+                                                        option_colors,
+                                                        False,          # align_model
+                                                        option_flip_yz,
+                                                        option_scale,
+                                                        False,          # export_single_model
+                                                        False,          # option_copy_textures
+                                                        filepath,
+                                                        option_animation,
+                                                        option_frame_step)
+
+                        embeds[name] = model_string
+
+                    else:
+
+                        fname = generate_mesh_filename(name, filepath)
+                        export_mesh([object], scene,
+                                    fname,
+                                    option_vertices,
+                                    option_vertices_truncate,
+                                    option_faces,
+                                    option_normals,
+                                    option_uv_coords,
+                                    option_materials,
+                                    option_colors,
+                                    False,          # align_model
+                                    option_flip_yz,
+                                    option_scale,
+                                    False,          # export_single_model
+                                    option_copy_textures,
+                                    option_animation,
+                                    option_frame_step)
+
+                    geo_set.add(name)
+
+        export_scene(scene, filepath,
+                     option_flip_yz,
+                     option_colors,
+                     option_lights,
+                     option_cameras,
+                     option_embed_meshes,
+                     embeds,
+                     option_url_base_html,
+                     option_copy_textures)
+
+    else:
+
+        export_mesh(objects, scene, filepath,
+                    option_vertices,
+                    option_vertices_truncate,
+                    option_faces,
+                    option_normals,
+                    option_uv_coords,
+                    option_materials,
+                    option_colors,
+                    align_model,
+                    option_flip_yz,
+                    option_scale,
+                    True,            # export_single_model
+                    option_copy_textures,
+                    option_animation,
+                    option_frame_step)
+
+    return {'FINISHED'}

+ 633 - 0
utils/exporters/blender/2.63/scripts/addons/io_mesh_threejs/import_threejs.py

@@ -0,0 +1,633 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+"""
+Blender importer for Three.js (ASCII JSON format).
+
+"""
+
+import os
+import time
+import json
+import bpy
+import mathutils
+from mathutils.geometry import tesselate_polygon
+from bpy_extras.image_utils import load_image
+
+# #####################################################
+# Generators
+# #####################################################
+def setColor(c, t):
+    c.r = t[0]
+    c.g = t[1]
+    c.b = t[2]
+
+def create_texture(filename, modelpath):
+    name = filename
+    texture = bpy.data.textures.new(name, type='IMAGE')
+
+    image = load_image(filename, modelpath)
+    has_data = False
+
+    if image:
+        texture.image = image
+        has_data = image.has_data
+
+    return texture
+
+def create_materials(data, modelpath):
+    materials = []
+    materials_data = data.get("materials", [])
+
+    for i, m in enumerate(materials_data):
+
+        name = m.get("DbgName", "material_%d" % i)
+
+        colorAmbient = m.get("colorAmbient", None)
+        colorDiffuse = m.get("colorDiffuse", None)
+        colorSpecular = m.get("colorSpecular", None)
+        alpha = m.get("transparency", 1.0)
+        specular_hardness = m.get("specularCoef", 0)
+
+        mapDiffuse = m.get("mapDiffuse", None)
+        mapLightmap = m.get("mapLightmap", None)
+
+        vertexColorsType = m.get("vertexColors", False)
+
+        useVertexColors = False
+        if vertexColorsType:
+            useVertexColors = True
+
+        material = bpy.data.materials.new(name)
+
+        material.THREE_useVertexColors = useVertexColors
+
+        if colorDiffuse:
+            setColor(material.diffuse_color, colorDiffuse)
+            material.diffuse_intensity = 1.0
+
+        if colorSpecular:
+            setColor(material.specular_color, colorSpecular)
+            material.specular_intensity = 1.0
+
+        if alpha < 1.0:
+            material.alpha = alpha
+            material.use_transparency = True
+
+        if specular_hardness:
+            material.specular_hardness = specular_hardness
+
+        if mapDiffuse:
+            texture = create_texture(mapDiffuse, modelpath)
+            mtex = material.texture_slots.add()
+            mtex.texture = texture
+            mtex.texture_coords = 'UV'
+            mtex.use = True
+            mtex.use_map_color_diffuse = True
+
+            material.active_texture = texture
+
+        materials.append(material)
+
+    return materials
+
+def create_mesh_object(name, vertices, materials, face_data, flipYZ, recalculate_normals):
+
+    faces         = face_data["faces"]
+    vertexNormals = face_data["vertexNormals"]
+    vertexColors  = face_data["vertexColors"]
+    vertexUVs     = face_data["vertexUVs"]
+    faceMaterials = face_data["materials"]
+    faceColors    = face_data["faceColors"]
+
+    edges = []
+
+    # Create a new mesh
+
+    me = bpy.data.meshes.new(name)
+    me.from_pydata(vertices, edges, faces)
+
+    # Handle normals
+
+    if not recalculate_normals:
+        me.update(calc_edges = True)
+
+    if face_data["hasVertexNormals"]:
+
+        print("setting vertex normals")
+
+        for fi in range(len(faces)):
+
+            if vertexNormals[fi]:
+
+                #print("setting face %i with %i vertices" % (fi, len(normals[fi])))
+
+                # if me.update() is called after setting vertex normals
+                # setting face.use_smooth overrides these normals
+                #  - this fixes weird shading artefacts (seems to come from sharing
+                #    of vertices between faces, didn't find a way how to set vertex normals
+                #    per face use of vertex as opposed to per vertex),
+                #  - probably this just overrides all custom vertex normals
+                #  - to preserve vertex normals from the original data
+                #    call me.update() before setting them
+
+                me.faces[fi].use_smooth = True
+
+                if not recalculate_normals:
+                    for j in range(len(vertexNormals[fi])):
+
+                        vertexNormal = vertexNormals[fi][j]
+
+                        x = vertexNormal[0]
+                        y = vertexNormal[1]
+                        z = vertexNormal[2]
+
+                        if flipYZ:
+                            tmp = y
+                            y = -z
+                            z = tmp
+
+                            # flip normals (this make them look consistent with the original before export)
+
+                            #x = -x
+                            #y = -y
+                            #z = -z
+
+                        vi = me.faces[fi].vertices[j]
+
+                        me.vertices[vi].normal.x = x
+                        me.vertices[vi].normal.y = y
+                        me.vertices[vi].normal.z = z
+
+    if recalculate_normals:
+        me.update(calc_edges = True)
+
+    # Handle colors
+
+    if face_data["hasVertexColors"]:
+
+        print("setting vertex colors")
+
+        me.vertex_colors.new("vertex_color_layer_0")
+
+        for fi in range(len(faces)):
+
+            if vertexColors[fi]:
+
+                face_colors = me.vertex_colors[0].data[fi]
+                face_colors = face_colors.color1, face_colors.color2, face_colors.color3, face_colors.color4
+
+                for vi in range(len(vertexColors[fi])):
+
+                    r = vertexColors[fi][vi][0]
+                    g = vertexColors[fi][vi][1]
+                    b = vertexColors[fi][vi][2]
+
+                    face_colors[vi].r = r
+                    face_colors[vi].g = g
+                    face_colors[vi].b = b
+
+    elif face_data["hasFaceColors"]:
+
+        print("setting vertex colors from face colors")
+
+        me.vertex_colors.new("vertex_color_layer_0")
+
+        for fi in range(len(faces)):
+
+            if faceColors[fi]:
+
+                r = faceColors[fi][0]
+                g = faceColors[fi][1]
+                b = faceColors[fi][2]
+
+                face_colors = me.vertex_colors[0].data[fi]
+                face_colors = face_colors.color1, face_colors.color2, face_colors.color3, face_colors.color4
+
+                for vi in range(len(faces[fi])):
+
+                    face_colors[vi].r = r
+                    face_colors[vi].g = g
+                    face_colors[vi].b = b
+
+    # Handle uvs
+
+    if face_data["hasVertexUVs"]:
+
+        print("setting vertex uvs")
+
+        for li, layer in enumerate(vertexUVs):
+
+            me.uv_textures.new("uv_layer_%d" % li)
+
+            for fi in range(len(faces)):
+
+                if layer[fi]:
+
+                    uv_face = me.uv_textures[li].data[fi]
+                    face_uvs = uv_face.uv1, uv_face.uv2, uv_face.uv3, uv_face.uv4
+
+                    for vi in range(len(layer[fi])):
+
+                        u = layer[fi][vi][0]
+                        v = layer[fi][vi][1]
+
+                        face_uvs[vi].x = u
+                        face_uvs[vi].y = 1.0 - v
+
+                    active_texture = materials[faceMaterials[fi]].active_texture
+
+                    if active_texture:
+                        uv_face.image = active_texture.image
+
+
+    # Handle materials # 1
+
+    if face_data["hasMaterials"]:
+
+
+        print("setting materials (mesh)")
+
+        for m in materials:
+
+            me.materials.append(m)
+
+        print("setting materials (faces)")
+
+        for fi in range(len(faces)):
+
+            if faceMaterials[fi] >= 0:
+
+                me.faces[fi].material_index = faceMaterials[fi]
+
+    # Create a new object
+
+    ob = bpy.data.objects.new(name, me)
+    ob.data = me                                # link the mesh data to the object
+
+
+    scene = bpy.context.scene                   # get the current scene
+    scene.objects.link(ob)                      # link the object into the scene
+
+    ob.location = scene.cursor_location         # position object at 3d-cursor
+
+
+# #####################################################
+# Faces
+# #####################################################
+
+def extract_faces(data):
+
+    result = {
+    "faces"         : [],
+    "materials"     : [],
+    "faceUVs"       : [],
+    "vertexUVs"     : [],
+    "faceNormals"   : [],
+    "vertexNormals" : [],
+    "faceColors"    : [],
+    "vertexColors"  : [],
+
+    "hasVertexNormals"  : False,
+    "hasVertexUVs"      : False,
+    "hasVertexColors"   : False,
+    "hasFaceColors"     : False,
+    "hasMaterials"      : False
+    }
+
+    faces = data.get("faces", [])
+    normals = data.get("normals", [])
+    colors = data.get("colors", [])
+
+    offset = 0
+    zLength = len(faces)
+
+    # disregard empty arrays
+
+    nUvLayers = 0
+
+    for layer in data["uvs"]:
+
+        if len(layer) > 0:
+            nUvLayers += 1
+            result["faceUVs"].append([])
+            result["vertexUVs"].append([])
+
+
+    while ( offset < zLength ):
+
+        type = faces[ offset ]
+        offset += 1
+
+        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 )
+
+        #print("type", type, "bits", isQuad, hasMaterial, hasFaceUv, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor)
+
+        result["hasVertexUVs"] = result["hasVertexUVs"] or hasFaceVertexUv
+        result["hasVertexNormals"] = result["hasVertexNormals"] or hasFaceVertexNormal
+        result["hasVertexColors"] = result["hasVertexColors"] or hasFaceVertexColor
+        result["hasFaceColors"] = result["hasFaceColors"] or hasFaceColor
+        result["hasMaterials"] = result["hasMaterials"] or hasMaterial
+
+        # vertices
+
+        if isQuad:
+
+            a = faces[ offset ]
+            offset += 1
+
+            b = faces[ offset ]
+            offset += 1
+
+            c = faces[ offset ]
+            offset += 1
+
+            d = faces[ offset ]
+            offset += 1
+
+            face = [a, b, c, d]
+
+            nVertices = 4
+
+        else:
+
+            a = faces[ offset ]
+            offset += 1
+
+            b = faces[ offset ]
+            offset += 1
+
+            c = faces[ offset ]
+            offset += 1
+
+            face = [a, b, c]
+
+            nVertices = 3
+
+        result["faces"].append(face)
+
+        # material
+
+        if hasMaterial:
+
+            materialIndex = faces[ offset ]
+            offset += 1
+
+        else:
+
+            materialIndex = -1
+
+        result["materials"].append(materialIndex)
+
+        # uvs
+
+        for i in range(nUvLayers):
+
+            faceUv = None
+
+            if hasFaceUv:
+
+                uvLayer = data["uvs"][ i ]
+
+                uvIndex = faces[ offset ]
+                offset += 1
+
+                u = uvLayer[ uvIndex * 2 ]
+                v = uvLayer[ uvIndex * 2 + 1 ]
+
+                faceUv = [u, v]
+
+            result["faceUVs"][i].append(faceUv)
+
+
+            if hasFaceVertexUv:
+
+                uvLayer = data["uvs"][ i ]
+
+                vertexUvs = []
+
+                for j in range(nVertices):
+
+                    uvIndex = faces[ offset ]
+                    offset += 1
+
+                    u = uvLayer[ uvIndex * 2 ]
+                    v = uvLayer[ uvIndex * 2 + 1 ]
+
+                    vertexUvs.append([u, v])
+
+            result["vertexUVs"][i].append(vertexUvs)
+
+
+        if hasFaceNormal:
+
+            normalIndex = faces[ offset ] * 3
+            offset += 1
+
+            x = normals[ normalIndex ]
+            y = normals[ normalIndex + 1 ]
+            z = normals[ normalIndex + 2 ]
+
+            faceNormal = [x, y, z]
+
+        else:
+
+            faceNormal = None
+
+        result["faceNormals"].append(faceNormal)
+
+
+        if hasFaceVertexNormal:
+
+            vertexNormals = []
+
+            for j in range(nVertices):
+
+                normalIndex = faces[ offset ] * 3
+                offset += 1
+
+                x = normals[ normalIndex ]
+                y = normals[ normalIndex + 1 ]
+                z = normals[ normalIndex + 2 ]
+
+                vertexNormals.append( [x, y, z] )
+
+
+        else:
+
+            vertexNormals = None
+
+        result["vertexNormals"].append(vertexNormals)
+
+
+        if hasFaceColor:
+
+            colorIndex = faces[ offset ]
+            offset += 1
+
+            faceColor = hexToTuple( colors[ colorIndex ] )
+
+        else:
+
+            faceColor = None
+
+        result["faceColors"].append(faceColor)
+
+
+        if hasFaceVertexColor:
+
+            vertexColors = []
+
+            for j in range(nVertices):
+
+                colorIndex = faces[ offset ]
+                offset += 1
+
+                color = hexToTuple( colors[ colorIndex ] )
+                vertexColors.append( color )
+
+        else:
+
+            vertexColors = None
+
+        result["vertexColors"].append(vertexColors)
+
+
+    return result
+
+# #####################################################
+# Utils
+# #####################################################
+
+def hexToTuple( hexColor ):
+    r = (( hexColor >> 16 ) & 0xff) / 255.0
+    g = (( hexColor >> 8 ) & 0xff) / 255.0
+    b = ( hexColor & 0xff) / 255.0
+    return (r, g, b)
+
+def isBitSet(value, position):
+    return value & ( 1 << position )
+
+def splitArray(data, chunkSize):
+    result = []
+    chunk = []
+    for i in range(len(data)):
+        if i > 0 and i % chunkSize == 0:
+            result.append(chunk)
+            chunk = []
+        chunk.append(data[i])
+    result.append(chunk)
+    return result
+
+
+def extract_json_string(text):
+    marker_begin = "var model ="
+    marker_end = "postMessage"
+
+    start = text.find(marker_begin) + len(marker_begin)
+    end = text.find(marker_end)
+    end = text.rfind("}", start, end)
+    return text[start:end+1].strip()
+
+def get_name(filepath):
+    return os.path.splitext(os.path.basename(filepath))[0]
+
+def get_path(filepath):
+    return os.path.dirname(filepath)
+
+# #####################################################
+# Parser
+# #####################################################
+
+def load(operator, context, filepath, option_flip_yz = True, recalculate_normals = True, option_worker = False):
+
+    print('\nimporting %r' % filepath)
+
+    time_main = time.time()
+
+    print("\tparsing JSON file...")
+
+    time_sub = time.time()
+
+    file = open(filepath, 'rU')
+    rawcontent = file.read()
+    file.close()
+
+    if option_worker:
+        json_string = extract_json_string(rawcontent)
+    else:
+        json_string = rawcontent
+    data = json.loads( json_string )
+
+    time_new = time.time()
+
+    print('parsing %.4f sec' % (time_new - time_sub))
+
+    time_sub = time_new
+
+    # flip YZ
+
+    vertices = splitArray(data["vertices"], 3)
+
+    if option_flip_yz:
+        vertices[:] = [(v[0], -v[2], v[1]) for v in vertices]
+
+    # extract faces
+
+    face_data = extract_faces(data)
+
+    # deselect all
+
+    bpy.ops.object.select_all(action='DESELECT')
+
+    nfaces = len(face_data["faces"])
+    nvertices = len(vertices)
+    nnormals = len(data.get("normals", [])) / 3
+    ncolors = len(data.get("colors", [])) / 3
+    nuvs = len(data.get("uvs", [])) / 2
+    nmaterials = len(data.get("materials", []))
+
+    print('\tbuilding geometry...\n\tfaces:%i, vertices:%i, vertex normals: %i, vertex uvs: %i, vertex colors: %i, materials: %i ...' % (
+        nfaces, nvertices, nnormals, nuvs, ncolors, nmaterials ))
+
+    # Create materials
+
+    materials = create_materials(data, get_path(filepath))
+
+    # Create new obj
+
+    create_mesh_object(get_name(filepath), vertices, materials, face_data, option_flip_yz, recalculate_normals)
+
+    scene = bpy.context.scene
+    scene.update()
+
+    time_new = time.time()
+
+    print('finished importing: %r in %.4f sec.' % (filepath, (time_new - time_main)))
+    return {'FINISHED'}
+
+
+if __name__ == "__main__":
+    register()

+ 279 - 0
utils/files.json

@@ -0,0 +1,279 @@
+{
+	"COMMON" : [
+		"Three.js",
+		"core/Clock.js",
+		"core/Color.js",
+		"core/Vector2.js",
+		"core/Vector3.js",
+		"core/Vector4.js",
+		"core/EventTarget.js",
+		"core/Frustum.js",
+		"core/Ray.js",
+		"core/Rectangle.js",
+		"core/Math.js",
+		"core/Matrix3.js",
+		"core/Matrix4.js",
+		"core/Object3D.js",
+		"core/Projector.js",
+		"core/Quaternion.js",
+		"core/Vertex.js",
+		"core/Face3.js",
+		"core/Face4.js",
+		"core/UV.js",
+		"core/Geometry.js",
+		"core/Spline.js",
+		"cameras/Camera.js",
+		"cameras/OrthographicCamera.js",
+		"cameras/PerspectiveCamera.js",
+		"lights/Light.js",
+		"lights/AmbientLight.js",
+		"lights/DirectionalLight.js",
+		"lights/PointLight.js",
+		"lights/SpotLight.js",
+		"loaders/Loader.js",
+		"loaders/BinaryLoader.js",
+		"loaders/ImageLoader.js",
+		"loaders/JSONLoader.js",
+		"loaders/GeometryLoader.js",
+		"loaders/SceneLoader.js",
+		"loaders/TextureLoader.js",
+		"materials/Material.js",
+		"materials/LineBasicMaterial.js",
+		"materials/MeshBasicMaterial.js",
+		"materials/MeshLambertMaterial.js",
+		"materials/MeshPhongMaterial.js",
+		"materials/MeshDepthMaterial.js",
+		"materials/MeshNormalMaterial.js",
+		"materials/MeshFaceMaterial.js",
+		"materials/ParticleBasicMaterial.js",
+		"materials/ParticleCanvasMaterial.js",
+		"materials/ParticleDOMMaterial.js",
+		"materials/ShaderMaterial.js",
+		"textures/Texture.js",
+		"textures/DataTexture.js",
+		"objects/Particle.js",
+		"objects/ParticleSystem.js",
+		"objects/Line.js",
+		"objects/Mesh.js",
+		"objects/Bone.js",
+		"objects/SkinnedMesh.js",
+		"objects/MorphAnimMesh.js",
+		"objects/Ribbon.js",
+		"objects/LOD.js",
+		"objects/Sprite.js",
+		"scenes/Scene.js",
+		"scenes/Fog.js",
+		"scenes/FogExp2.js",
+		"renderers/CanvasRenderer.js",
+		"renderers/WebGLShaders.js",
+		"renderers/WebGLRenderer.js",
+		"renderers/WebGLRenderTarget.js",
+		"renderers/WebGLRenderTargetCube.js",
+		"renderers/renderables/RenderableVertex.js",
+		"renderers/renderables/RenderableFace3.js",
+		"renderers/renderables/RenderableFace4.js",
+		"renderers/renderables/RenderableObject.js",
+		"renderers/renderables/RenderableParticle.js",
+		"renderers/renderables/RenderableLine.js"
+	],
+
+	"EXTRAS" : [
+		"extras/ColorUtils.js",
+		"extras/GeometryUtils.js",
+		"extras/ImageUtils.js",
+		"extras/SceneUtils.js",
+		"extras/ShaderUtils.js",
+		"extras/FontUtils.js",
+		"extras/core/BufferGeometry.js",
+		"extras/core/Curve.js",
+		"extras/core/CurvePath.js",
+		"extras/core/Gyroscope.js",
+		"extras/core/Path.js",
+		"extras/core/Shape.js",
+		"extras/animation/AnimationHandler.js",
+		"extras/animation/Animation.js",
+		"extras/animation/KeyFrameAnimation.js",
+		"extras/cameras/CubeCamera.js",
+		"extras/cameras/CombinedCamera.js",
+		"extras/controls/FirstPersonControls.js",
+		"extras/controls/PathControls.js",
+		"extras/controls/FlyControls.js",
+		"extras/controls/RollControls.js",
+		"extras/controls/TrackballControls.js",
+		"extras/controls/OrbitControls.js",
+		"extras/geometries/CubeGeometry.js",
+		"extras/geometries/CylinderGeometry.js",
+		"extras/geometries/ExtrudeGeometry.js",
+		"extras/geometries/LatheGeometry.js",
+		"extras/geometries/PlaneGeometry.js",
+		"extras/geometries/SphereGeometry.js",
+		"extras/geometries/TextGeometry.js",
+		"extras/geometries/TorusGeometry.js",
+		"extras/geometries/TorusKnotGeometry.js",
+		"extras/geometries/TubeGeometry.js",
+		"extras/geometries/PolyhedronGeometry.js",
+		"extras/geometries/IcosahedronGeometry.js",
+		"extras/geometries/OctahedronGeometry.js",
+		"extras/geometries/TetrahedronGeometry.js",
+		"extras/geometries/ParametricGeometry.js",
+		"extras/geometries/ConvexGeometry.js",
+		"extras/helpers/AxisHelper.js",
+		"extras/helpers/ArrowHelper.js",
+		"extras/helpers/CameraHelper.js",
+		"extras/modifiers/SubdivisionModifier.js",
+		"extras/objects/ImmediateRenderObject.js",
+		"extras/objects/LensFlare.js",
+		"extras/objects/MorphBlendMesh.js",
+		"extras/renderers/plugins/LensFlarePlugin.js",
+		"extras/renderers/plugins/ShadowMapPlugin.js",
+		"extras/renderers/plugins/SpritePlugin.js",
+		"extras/renderers/plugins/DepthPassPlugin.js",
+		"extras/shaders/ShaderFlares.js",
+		"extras/shaders/ShaderSprite.js"
+	],
+
+	"CANVAS" : [
+		"Three.js",
+		"core/Color.js",
+		"core/Vector2.js",
+		"core/Vector3.js",
+		"core/Vector4.js",
+		"core/EventTarget.js",
+		"core/Frustum.js",
+		"core/Ray.js",
+		"core/Rectangle.js",
+		"core/Math.js",
+		"core/Matrix3.js",
+		"core/Matrix4.js",
+		"core/Object3D.js",
+		"core/Projector.js",
+		"core/Quaternion.js",
+		"core/Vertex.js",
+		"core/Face3.js",
+		"core/Face4.js",
+		"core/UV.js",
+		"core/Geometry.js",
+		"cameras/Camera.js",
+		"cameras/OrthographicCamera.js",
+		"cameras/PerspectiveCamera.js",
+		"lights/Light.js",
+		"lights/AmbientLight.js",
+		"lights/DirectionalLight.js",
+		"lights/PointLight.js",
+		"loaders/Loader.js",
+		"loaders/BinaryLoader.js",
+		"loaders/ImageLoader.js",
+		"loaders/JSONLoader.js",
+		"loaders/GeometryLoader.js",
+		"loaders/SceneLoader.js",
+		"loaders/TextureLoader.js",
+		"materials/Material.js",
+		"materials/LineBasicMaterial.js",
+		"materials/MeshBasicMaterial.js",
+		"materials/MeshLambertMaterial.js",
+		"materials/MeshPhongMaterial.js",
+		"materials/MeshDepthMaterial.js",
+		"materials/MeshNormalMaterial.js",
+		"materials/MeshFaceMaterial.js",
+		"materials/ParticleBasicMaterial.js",
+		"materials/ParticleCanvasMaterial.js",
+		"textures/Texture.js",
+		"textures/DataTexture.js",
+		"objects/Particle.js",
+		"objects/Line.js",
+		"objects/Mesh.js",
+		"objects/Bone.js",
+		"objects/Sprite.js",
+		"scenes/Scene.js",
+		"renderers/CanvasRenderer.js",
+		"renderers/renderables/RenderableVertex.js",
+		"renderers/renderables/RenderableFace3.js",
+		"renderers/renderables/RenderableFace4.js",
+		"renderers/renderables/RenderableObject.js",
+		"renderers/renderables/RenderableParticle.js",
+		"renderers/renderables/RenderableLine.js"
+	],
+
+	"WEBGL" : [
+		"Three.js",
+		"core/Color.js",
+		"core/Vector2.js",
+		"core/Vector3.js",
+		"core/Vector4.js",
+		"core/EventTarget.js",
+		"core/Frustum.js",
+		"core/Ray.js",
+		"core/Rectangle.js",
+		"core/Math.js",
+		"core/Matrix3.js",
+		"core/Matrix4.js",
+		"core/Object3D.js",
+		"core/Projector.js",
+		"core/Quaternion.js",
+		"core/Vertex.js",
+		"core/Face3.js",
+		"core/Face4.js",
+		"core/UV.js",
+		"core/Geometry.js",
+		"core/Spline.js",
+		"cameras/Camera.js",
+		"cameras/OrthographicCamera.js",
+		"cameras/PerspectiveCamera.js",
+		"lights/Light.js",
+		"lights/AmbientLight.js",
+		"lights/DirectionalLight.js",
+		"lights/PointLight.js",
+		"lights/SpotLight.js",
+		"loaders/Loader.js",
+		"loaders/BinaryLoader.js",
+		"loaders/ImageLoader.js",
+		"loaders/JSONLoader.js",
+		"loaders/GeometryLoader.js",
+		"loaders/SceneLoader.js",
+		"loaders/TextureLoader.js",
+		"materials/Material.js",
+		"materials/LineBasicMaterial.js",
+		"materials/MeshBasicMaterial.js",
+		"materials/MeshLambertMaterial.js",
+		"materials/MeshPhongMaterial.js",
+		"materials/MeshDepthMaterial.js",
+		"materials/MeshNormalMaterial.js",
+		"materials/MeshFaceMaterial.js",
+		"materials/ParticleBasicMaterial.js",
+		"materials/ShaderMaterial.js",
+		"textures/Texture.js",
+		"textures/DataTexture.js",
+		"objects/Particle.js",
+		"objects/ParticleSystem.js",
+		"objects/Line.js",
+		"objects/Mesh.js",
+		"objects/Bone.js",
+		"objects/SkinnedMesh.js",
+		"objects/Ribbon.js",
+		"objects/LOD.js",
+		"objects/Sprite.js",
+		"scenes/Scene.js",
+		"scenes/Fog.js",
+		"scenes/FogExp2.js",
+		"renderers/WebGLShaders.js",
+		"renderers/WebGLRenderer.js",
+		"renderers/WebGLRenderTarget.js",
+		"renderers/WebGLRenderTargetCube.js",
+		"renderers/renderables/RenderableVertex.js",
+		"renderers/renderables/RenderableFace3.js",
+		"renderers/renderables/RenderableFace4.js",
+		"renderers/renderables/RenderableObject.js",
+		"renderers/renderables/RenderableParticle.js",
+		"renderers/renderables/RenderableLine.js",
+		"extras/core/BufferGeometry.js",
+		"extras/core/Gyroscope.js",
+		"extras/helpers/CameraHelper.js",
+		"extras/objects/LensFlare.js",
+		"extras/objects/ImmediateRenderObject.js",
+		"extras/renderers/plugins/LensFlarePlugin.js",
+		"extras/renderers/plugins/ShadowMapPlugin.js",
+		"extras/renderers/plugins/SpritePlugin.js",
+		"extras/shaders/ShaderFlares.js",
+		"extras/shaders/ShaderSprite.js"
+	]
+}

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio