فهرست منبع

Merge branch 'master' of https://github.com/mrdoob/three.js into dev

Andrii Iudin 8 سال پیش
والد
کامیت
e4123712a3
100فایلهای تغییر یافته به همراه11301 افزوده شده و 8445 حذف شده
  1. 1 1
      .github/ISSUE_TEMPLATE.md
  2. 1 1
      .gitignore
  3. 2 4
      build/three.js
  4. 117 350
      build/three.min.js
  5. 2 4
      build/three.module.js
  6. 354 352
      docs/api/animation/AnimationAction.html
  7. 133 133
      docs/api/animation/AnimationClip.html
  8. 97 97
      docs/api/animation/AnimationMixer.html
  9. 59 59
      docs/api/animation/AnimationObjectGroup.html
  10. 54 54
      docs/api/animation/AnimationUtils.html
  11. 234 234
      docs/api/animation/KeyframeTrack.html
  12. 88 88
      docs/api/animation/PropertyBinding.html
  13. 68 68
      docs/api/animation/PropertyMixer.html
  14. 75 75
      docs/api/animation/tracks/BooleanKeyframeTrack.html
  15. 59 59
      docs/api/animation/tracks/ColorKeyframeTrack.html
  16. 59 59
      docs/api/animation/tracks/NumberKeyframeTrack.html
  17. 53 53
      docs/api/animation/tracks/QuaternionKeyframeTrack.html
  18. 58 58
      docs/api/animation/tracks/StringKeyframeTrack.html
  19. 44 44
      docs/api/animation/tracks/VectorKeyframeTrack.html
  20. 7 7
      docs/api/core/BufferGeometry.html
  21. 133 133
      docs/api/core/Face3.html
  22. 7 1
      docs/api/core/Object3D.html
  23. 4 1
      docs/api/deprecated/DeprecatedList.html
  24. 1 1
      docs/api/extras/SceneUtils.html
  25. 21 20
      docs/api/extras/core/Curve.html
  26. 3 1
      docs/api/geometries/TubeBufferGeometry.html
  27. 3 1
      docs/api/geometries/TubeGeometry.html
  28. 10 3
      docs/api/helpers/BoxHelper.html
  29. 3 3
      docs/api/lights/RectAreaLight.html
  30. 6 1
      docs/api/loaders/JSONLoader.html
  31. 231 231
      docs/api/loaders/ObjectLoader.html
  32. 8 2
      docs/api/materials/Material.html
  33. 4 3
      docs/api/materials/ShaderMaterial.html
  34. 7 3
      docs/api/materials/ShadowMaterial.html
  35. 37 37
      docs/api/math/Color.html
  36. 12 0
      docs/api/math/Matrix3.html
  37. 8 14
      docs/api/math/Matrix4.html
  38. 1 1
      docs/api/objects/LOD.html
  39. 3 0
      docs/api/renderers/WebGLRenderer.html
  40. 1 1
      docs/examples/loaders/OBJLoader.html
  41. 114 0
      docs/examples/loaders/OBJLoader2.html
  42. 404 0
      docs/examples/loaders/WWOBJLoader2.html
  43. 216 0
      docs/index.css
  44. 328 322
      docs/index.html
  45. 375 391
      docs/list.js
  46. 119 119
      docs/manual/introduction/Animation-system.html
  47. 1 1
      docs/manual/introduction/Code-style-guide.html
  48. 4 3
      docs/manual/introduction/How-to-update-things.html
  49. 0 7
      docs/manual/introduction/Useful-links.html
  50. 0 0
      docs/manual/introduction/WebGL-compatibility-check.html
  51. 8 4
      docs/page.css
  52. 29 3
      docs/page.js
  53. 3 1
      docs/scenes/js/geometry.js
  54. 0 8
      editor/css/dark.css
  55. 0 26
      editor/css/main.css
  56. 0 2
      editor/index.html
  57. 1 2
      editor/js/Editor.js
  58. 0 13
      editor/js/Loader.js
  59. 3 22
      editor/js/Script.js
  60. 0 85
      editor/js/Sidebar.Animation.js
  61. 2 1
      editor/js/Sidebar.Material.js
  62. 21 1
      editor/js/Sidebar.Scene.js
  63. 5 5
      editor/js/Viewport.js
  64. 1 13
      editor/js/commands/SetScriptValueCommand.js
  65. 0 4
      editor/js/libs/tern-threejs/threejs.js
  66. 9 3
      examples/files.js
  67. 1 1
      examples/index.html
  68. 0 182
      examples/js/BlendCharacter.js
  69. 0 207
      examples/js/BlendCharacterGui.js
  70. 2 2
      examples/js/Cloth.js
  71. 37 3
      examples/js/CurveExtras.js
  72. 313 321
      examples/js/GPUParticleSystem.js
  73. 0 73
      examples/js/MorphAnimation.js
  74. 43 21
      examples/js/ParametricGeometries.js
  75. 59 59
      examples/js/RollerCoaster.js
  76. 28 1
      examples/js/WaterShader.js
  77. 4 2
      examples/js/controls/DragControls.js
  78. 37 21
      examples/js/controls/OrbitControls.js
  79. 0 24
      examples/js/controls/VRControls.js
  80. 2 1
      examples/js/curves/NURBSCurve.js
  81. 5 0
      examples/js/exporters/OBJExporter.js
  82. 5 2
      examples/js/loaders/ColladaLoader.js
  83. 51 40
      examples/js/loaders/DRACOLoader.js
  84. 1114 1965
      examples/js/loaders/FBXLoader2.js
  85. 48 26
      examples/js/loaders/GLTF2Loader.js
  86. 9 0
      examples/js/loaders/GLTFLoader.js
  87. 1 2
      examples/js/loaders/OBJLoader.js
  88. 1027 0
      examples/js/loaders/OBJLoader2.js
  89. 1407 0
      examples/js/loaders/WWOBJLoader2.js
  90. 1580 1045
      examples/js/loaders/XLoader.js
  91. 0 1132
      examples/js/loaders/deprecated/SceneLoader.js
  92. 0 0
      examples/js/loaders/draco_decoder.js
  93. 26 4
      examples/js/postprocessing/AdaptiveToneMappingPass.js
  94. 4 2
      examples/js/shaders/ToneMapShader.js
  95. 18 16
      examples/js/vr/WebVR.js
  96. BIN
      examples/models/gltf/BoomBox/glTF-pbrSpecularGlossiness/BoomBox_metallicRoughness.png
  97. BIN
      examples/models/gltf/BoomBox/glTF/BoomBox_metallicRoughness.png
  98. 1769 0
      examples/models/json/pump/pump.json
  99. BIN
      examples/models/json/pump/pump_body.jpg
  100. BIN
      examples/models/json/pump/pump_gears.jpg

+ 1 - 1
.github/ISSUE_TEMPLATE.md

@@ -14,7 +14,7 @@ http://jsfiddle.net/hw9rcLL8/ (dev)
 ##### Three.js version
 
 - [ ] Dev
-- [ ] r84
+- [ ] r85
 - [ ] ...
 
 ##### Browser

+ 1 - 1
.gitignore

@@ -5,4 +5,4 @@ node_modules
 .idea/
 .vscode/
 npm-debug.log
-
+.jshintrc

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 2 - 4
build/three.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 117 - 350
build/three.min.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 2 - 4
build/three.module.js


+ 354 - 352
docs/api/animation/AnimationAction.html

@@ -8,356 +8,358 @@
 		<link type="text/css" rel="stylesheet" href="page.css" />
 	</head>
 	<body>
-    <h1>[name]</h1>
-
-    <div class="desc">
-        AnimationActions schedule the performance of the animations which are stored in
-        [page:AnimationClip AnimationClips].<br /><br />
-        
-        Note: Most of AnimationAction's methods can be chained.<br /><br />
-        
-        For an overview of the different elements of the three.js animation system see the
-        "Animation System" article in the "Next Steps" section of the manual.
-    </div>
-    
-
-    <h2>Constructor</h2>
-    
-
-    <h3>[name]( [page:AnimationMixer mixer], [page:AnimationClip clip], [page:Object3D localRoot] )</h3>
-    <div>       
-        [page:AnimationMixer mixer] - the *AnimationMixer* that is controlled by this action.<br />
-        [page:AnimationClip clip] - the *AnimationClip* that holds the animation data for this action.<br />
-        [page:Object3D localRoot] - the root object on which this action is performed.<br /><br />
-        
-        Note: Instead of calling this constructor directly you should instantiate an AnimationAction with 
-        [page:AnimationMixer.clipAction] since this method provides caching for better performance.
-    </div>   
-    
-   
-    <h2>Properties</h2>
-       
-        
-    <h3>[property:Boolean clampWhenFinished]</h3>
-    <div>
-        If *clampWhenFinished* is set to true the animation will automatically be [page:.paused paused] 
-        on its last frame.<br /><br />
-         
-        If *clampWhenFinished* is set to false, [page:.enabled enabled] will automatically be switched 
-        to false when the last loop of the action has finished, so that this action has no further 
-        impact.<br /><br />
-        
-        Default is false.<br /><br />
-        
-        Note: *clampWhenFinished* has no impact if the action is interrupted (it has only an effect if 
-        its last loop has really finished).
-    </div>    
-
-    <h3>[property:Boolean enabled]</h3>
-    <div>
-        Setting *enabled* to *false* disables this action, so that it has no impact. Default is *true*.<br /><br />
-        
-        When the action is re-enabled, the animation continues from its current [page:.time time] 
-        (setting *enabled* to *false* doesn't reset the action).<br /><br />
-
-        Note: Setting *enabled* to *true* doesn’t automatically restart the animation. Setting *enabled* 
-        to *true* will only restart the animation immediately if the following condition is fulfilled: 
-        [page:.paused paused] is *false*, this action has not been deactivated in the meantime (by 
-        executing a [page:.stop stop] or [page:.reset reset] command), and neither [page:.weight weight] 
-        nor [page:.timeScale timeScale] is 0.
-    </div>
-    
-    <h3>[property:Number loop]</h3>
-    <div>
-        The looping mode (can be changed with [page:.setLoop setLoop]). Default is 
-        [page:Animation THREE.LoopRepeat] (with an infinite number of [page:.repetitions repetitions])<br /><br />
-        
-        Must be one of these constants:<br /><br /> 
-        [page:Animation THREE.LoopOnce] - playing the clip once,<br /> 
-        [page:Animation THREE.LoopRepeat] - playing the clip with the choosen number of *repetitions*, 
-        each time jumping from the end of the clip directly to its beginning,<br /> 
-        [page:Animation THREE.LoopPingPong] - playing the clip with the choosen number of *repetitions*, 
-        alternately playing forward and backward.
-    </div>
-    
-    <h3>[property:Boolean paused]</h3>
-    <div>
-        Setting *paused* to *true* pauses the execution of the action by setting the effective time scale
-        to 0. Default is *false*.<br /><br />
-    </div>    
-    
-    <h3>[property:Number repetitions]</h3>
-    <div>
-        The number of repetitions of the performed [page:AnimationClip] over the course of this action.
-        Can be set via [page:.setLoop setLoop]. Default is *Infinity*.<br /><br />
-        Setting this number has no effect, if the [page:.loop loop mode] is set to 
-        [page:Animation THREE.LoopOnce].<br /><br />
-
-        Note: The first run is not taken into account. For example: if *repetition* is set to 2, the 
-        total number of executed rounds will be 3.
-    </div>
-
-    <h3>[property:Number time]</h3>
-    <div>
-        The local time of this action (in seconds, starting with 0).<br /><br />
-        
-        The value gets clamped or wrapped to 0...clip.duration (according to the loop state). It can be 
-        scaled relativly to the global mixer time by changing [page:.timeScale timeScale] (using 
-        [page:.setEffectiveTimeScale setEffectiveTimeScale] or [page:.setDuration setDuration]).<br />
-    </div>
-
-    <h3>[property:Number timeScale]</h3>
-    <div>  
-        Scaling factor for the [page:.time time]. A value of 0 causes the animation to pause. Negative 
-        values cause the animation to play backwards. Default is 1.<br /><br />
-        Properties/methods concerning *timeScale* (respectively *time*) are:
-        [page:.getEffectiveTimeScale getEffectiveTimeScale], 
-        [page:.halt halt], 
-        [page:.paused paused], 
-        [page:.setDuration setDuration], 
-        [page:.setEffectiveTimeScale setEffectiveTimeScale], 
-        [page:.stopWarping stopWarping],
-        [page:.syncWith syncWith], 
-        [page:.warp warp]. 
-    </div>    
-
-    <h3>[property:Number weight]</h3>
-    <div>
-        The degree of influence of this action (in the interval [0, 1]). Values between 0 (no impact) 
-        and 1 (full impact) can be used to blend between several actions. Default is 1. <br /><br />
-        Properties/methods concerning  *weight* are:
-        [page:.crossFadeFrom crossFadeFrom], 
-        [page:.crossFadeTo crossFadeTo], 
-        [page:.enabled enabled], 
-        [page:.fadeIn fadeIn], 
-        [page:.fadeOut fadeOut], 
-        [page:.getEffectiveWeight getEffectiveWeight], 
-        [page:.setEffectiveWeight setEffectiveWeight], 
-        [page:.stopFading stopFading].
-    </div>
-
-    <h3>[property:Boolean zeroSlopeAtEnd]</h3>
-    <div>
-        Enables smooth interpolation without separate clips for start, loop and end. Default is *true*.
-    </div>
-    
-    <h3>[property:Boolean zeroSlopeAtStart]</h3>
-    <div>
-        Enables smooth interpolation without separate clips for start, loop and end. Default is *true*.
-    </div>
-    
-
-    <h2>Methods</h2> 
-       
-
-    <h3>[method:AnimationAction crossFadeFrom]( [page:AnimationAction fadeOutAction], [page:Number durationInSeconds], [page:Boolean warpBoolean] )</h3>
-    <div>
-        Causes this action to [page:.fadeIn fade in], fading out another action simultaneously, within 
-        the passed time interval. This method can be chained.<br /><br />
-        
-        If warpBoolean is true, additional [page:.warp warping] (gradually changes of the time scales) 
-        will be applied.<br /><br />
-        
-        Note: Like with *fadeIn*/*fadeOut*, the fading starts/ends with a weight of 1.
-        
-    </div>
-
-    <h3>[method:AnimationAction crossFadeTo]( [page:AnimationAction fadeInAction], [page:Number durationInSeconds], [page:Boolean warpBoolean] )</h3>
-    <div>
-        Causes this action to [page:.fadeOut fade out], fading in another action simultaneously, within 
-        the passed time interval. This method can be chained.<br /><br />
-        If warpBoolean is true, additional [page:.warp warping] (gradually changes of the time scales) 
-        will be applied.<br /><br />
-        
-        Note: Like with *fadeIn*/*fadeOut*, the fading starts/ends with a weight of 1.
-    </div>    
-
-    <h3>[method:AnimationAction fadeIn]( [page:Number durationInSeconds] )</h3>
-    <div>
-        Increases the [page:.weight weight] of this action gradually from 0 to 1, within the passed time 
-        interval. This method can be chained.
-    </div>
-
-    <h3>[method:AnimationAction fadeOut]( [page:Number durationInSeconds] )</h3>
-    <div>
-        Decreases the [page:.weight weight] of this action gradually from 1 to 0, within the passed time 
-        interval. This method can be chained.
-    </div>
-    
-    <h3>[method:Number getEffectiveTimeScale]()</h3>
-    <div>
-        Returns the effective time scale (considering the current states of warping and 
-        [page:.paused paused]).
-    </div>
-
-    <h3>[method:number getEffectiveWeight]()</h3>
-    <div>
-        Returns the effective weight (considering the current states of fading and 
-        [page:.enabled enabled]).
-    </div>
-
-    <h3>[method:AnimationClip getClip]()</h3>
-    <div>
-        Returns the clip which holds the animation data for this action.
-    </div>
-
-    <h3>[method:AnimationMixer getMixer]()</h3>
-    <div>
-        Returns the mixer which is responsible for playing this action.
-    </div>
-
-    <h3>[method:Object3D getRoot]()</h3>
-    <div>
-        Returns the root object on which this action is performed.
-    </div>    
-    
-    <h3>[method:AnimationAction halt]( [page:Number durationInSeconds] )</h3>
-    <div>
-        Decelerates this animation's speed to 0 by decreasing [page:.timeScale timeScale] gradually 
-        (starting from its current value), within the passed time interval. This method can be chained.
-    </div>    
-
-    <h3>[method:Boolean isRunning]()</h3>
-    <div>
-        Returns true if this action is activated in the mixer and currently playing (as opposed to 
-        [page:.isScheduled isScheduled]).<br /><br />
-         
-        In addition to being activated in the mixer the following conditions must be fulfilled: 
-        [page:.paused paused] is equal to false, [page:.enabled enabled] is equal to true, 
-        [page:.timeScale timeScale] is different from 0, and there is no scheduling for a delayed start 
-        ([page:.startAt startAt]).
-    </div>
-
-    <h3>[method:Boolean isScheduled]()</h3>
-    <div>
-        Returns true, if this action is activated in the mixer.<br /><br />
-        Note: This doesn’t necessarily mean that the animation is actually running (compare the additional 
-        conditions for [page:.isRunning isRunning]).
-    </div>
-
-    <h3>[method:AnimationAction play]()</h3>
-    <div>
-        Tells the mixer to activate the action. This method can be chained.<br /><br />
-        
-        Note: Activating this action doesn’t necessarily mean that the animation starts immediately: 
-        If the action had already finished before (by reaching the end of its last loop), or if a time 
-        for a delayed start has been set (via [page:.startAt startAt]), a [page:.reset reset] must be 
-        executed first. Some other settings ([page:.paused paused]=true, [page:.enabled enabled]=false, 
-        [page:.weight weight]=0, [page:.timeScale timeScale]=0) can prevent the animation from playing, 
-        too.
-    </div>
-
-    <h3>[method:AnimationAction reset]()</h3>
-    <div>
-        Resets the action. This method can be chained.<br /><br />
-        
-        This method sets [page:.paused paused] to false, [page:.enabled enabled] to true, 
-        [page:.time time] to 0, interrupts any scheduled fading and warping, and removes the internal 
-        loop count and scheduling for delayed starting.<br /><br />
-
-        Note: .*reset* is always called by [page:.stop stop], but .*reset* doesn’t call .*stop* itself.
-        This means: If you want both, resetting and stopping, don’t call .*reset*; call .*stop* instead.
-    </div>
-
-    <h3>[method:AnimationAction setDuration]( [page:Number durationInSeconds] )</h3>
-    <div>
-        Sets the duration for a single loop of this action (by adjusting [page:.timeScale timeScale] 
-        and stopping any scheduled warping). This method can be chained.
-    </div>
-
-    <h3>[method:AnimationAction setEffectiveTimeScale]( [page:Number timeScale] )</h3>
-    <div>
-        Sets the [page:.timeScale timeScale] and stops any scheduled warping. This method can be chained.<br /><br />
-        
-        If [page:.paused paused] is false, the effective time scale (an internal property) will also be set 
-        to this value; otherwise the effective time scale (directly affecting the animation at 
-        this moment) will be set to 0.<br /><br />
-        
-        Note: .*paused* will not be switched to *true* automatically, if .*timeScale* is set to 0 by 
-        this method.
-    </div>    
-
-    <h3>[method:AnimationAction setEffectiveWeight]( [page:Number weight] )</h3>
-    <div>
-        Sets the [page:.weight weight] and stops any scheduled fading. This method can be chained.<br /><br />
- 
-        If [page:.enabled enabled] is true, the effective weight (an internal property) will also be set 
-        to this value; otherwise the effective weight (directly affecting the animation at this moment) 
-        will be set to 0.<br /><br />
-
-        Note: .*enabled* will not be switched to *false* automatically, if .*weight* is set to 0 by 
-        this method.
-    </div>
-    
-    <h3>[method:AnimationAction setLoop]( [page:Number loopMode], [page:Number repetitions] )</h3>
-    <div>
-        Sets the [page:.loop loop mode] and the number of [page:.repetitions repetitions]. This method 
-        can be chained.
-    </div>  
-
-    <h3>[method:AnimationAction startAt]( [page:Number startTimeInSeconds] )</h3>
-    <div>
-        Defines the time for a delayed start (usually passed as [page:AnimationMixer.time] + 
-        deltaTimeInSeconds). This method can be chained.<br /><br />
-        
-        Note: The animation will only start at the given time, if .*startAt* is chained with 
-        [page:.play play], or if the action has already been activated in the mixer (by a previous 
-        call of .*play*, without stopping or resetting it in the meantime).
-    </div>
-
-    <h3>[method:AnimationAction stop]()</h3>
-    <div>
-        Tells the mixer to deactivate this action. This method can be chained.<br /><br />
-        
-        The action will be immediately stopped and completely [page:.reset reset].<br /><br />
-        
-        Note: You can stop all active actions on the same mixer in one go via 
-        [page:AnimationMixer.stopAllAction mixer.stopAllAction].
-    </div>
-    
-    <h3>[method:AnimationAction stopFading]()</h3>
-    <div>
-        Stops any scheduled [page:.fadeIn fading] which is applied to this action. This method can be 
-        chained.
-    </div>
-
-    <h3>[method:AnimationAction stopWarping]()</h3>
-    <div>
-        Stops any scheduled [page:.warp warping] which is applied to this action. This method can be 
-        chained.
-    </div>
-
-    <h3>[method:AnimationAction syncWith]( [page:AnimationAction otherAction] )</h3>
-    <div>
-        Synchronizes this action with the passed other action. This method can be chained.<br /><br />
-        
-        Synchronizing is done by setting this action’s [page:.time time] and [page:.timeScale timeScale] values 
-        to the corresponding values of the other action (stopping any scheduled warping).<br /><br />
-
-        Note: Future changes of the other action's *time* and *timeScale* will not be detected.
-    </div>
-
-    <h3>[method:AnimationAction warp]( [page:Number startTimeScale], [page:Number endTimeScale], [page:Number durationInSeconds] )</h3>
-    <div>
-        Changes the playback speed, within the passed time interval, by modifying 
-        [page:.timeScale timeScale] gradually from *startTimeScale* to *endTimeScale*. This method can 
-        be chained.
-    </div>
-
-
-    <h2>Events</h2>
-    
-    
-    <div class="desc">
-        There are two events indicating when a single loop of the action respectively the entire action has finished. You can react to them with:
-    </div>
-    <code>
-mixer.addEventListener( 'loop', function( e ) { …} ); // properties of e: type, action and loopDelta        
-mixer.addEventListener( 'finished', function( e ) { …} ); // properties of e: type, action and direction
-    </code>    
-
-    <h2>Source</h2>
-
-    [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
-  </body>
+		<h1>[name]</h1>
+
+		<div class="desc">
+			AnimationActions schedule the performance of the animations which are stored in
+			[page:AnimationClip AnimationClips].<br /><br />
+
+			Note: Most of AnimationAction's methods can be chained.<br /><br />
+
+			For an overview of the different elements of the three.js animation system see the
+			"Animation System" article in the "Next Steps" section of the manual.
+		</div>
+
+
+		<h2>Constructor</h2>
+
+
+		<h3>[name]( [page:AnimationMixer mixer], [page:AnimationClip clip], [page:Object3D localRoot] )</h3>
+		<div>
+			[page:AnimationMixer mixer] - the *AnimationMixer* that is controlled by this action.<br />
+			[page:AnimationClip clip] - the *AnimationClip* that holds the animation data for this action.<br />
+			[page:Object3D localRoot] - the root object on which this action is performed.<br /><br />
+
+			Note: Instead of calling this constructor directly you should instantiate an AnimationAction with
+			[page:AnimationMixer.clipAction] since this method provides caching for better performance.
+		</div>
+
+
+		<h2>Properties</h2>
+
+
+		<h3>[property:Boolean clampWhenFinished]</h3>
+		<div>
+			If *clampWhenFinished* is set to true the animation will automatically be [page:.paused paused]
+			on its last frame.<br /><br />
+
+			If *clampWhenFinished* is set to false, [page:.enabled enabled] will automatically be switched
+			to false when the last loop of the action has finished, so that this action has no further
+			impact.<br /><br />
+
+			Default is false.<br /><br />
+
+			Note: *clampWhenFinished* has no impact if the action is interrupted (it has only an effect if
+			its last loop has really finished).
+		</div>
+
+		<h3>[property:Boolean enabled]</h3>
+		<div>
+			Setting *enabled* to *false* disables this action, so that it has no impact. Default is *true*.<br /><br />
+
+			When the action is re-enabled, the animation continues from its current [page:.time time]
+			(setting *enabled* to *false* doesn't reset the action).<br /><br />
+
+			Note: Setting *enabled* to *true* doesn’t automatically restart the animation. Setting *enabled*
+			to *true* will only restart the animation immediately if the following condition is fulfilled:
+			[page:.paused paused] is *false*, this action has not been deactivated in the meantime (by
+			executing a [page:.stop stop] or [page:.reset reset] command), and neither [page:.weight weight]
+			nor [page:.timeScale timeScale] is 0.
+		</div>
+
+		<h3>[property:Number loop]</h3>
+		<div>
+			The looping mode (can be changed with [page:.setLoop setLoop]). Default is
+			[page:Animation THREE.LoopRepeat] (with an infinite number of [page:.repetitions repetitions])<br /><br />
+
+			Must be one of these constants:<br /><br />
+			[page:Animation THREE.LoopOnce] - playing the clip once,<br />
+			[page:Animation THREE.LoopRepeat] - playing the clip with the choosen number of *repetitions*,
+			each time jumping from the end of the clip directly to its beginning,<br />
+			[page:Animation THREE.LoopPingPong] - playing the clip with the choosen number of *repetitions*,
+			alternately playing forward and backward.
+		</div>
+
+		<h3>[property:Boolean paused]</h3>
+		<div>
+			Setting *paused* to *true* pauses the execution of the action by setting the effective time scale
+			to 0. Default is *false*.<br /><br />
+		</div>
+
+		<h3>[property:Number repetitions]</h3>
+		<div>
+			The number of repetitions of the performed [page:AnimationClip] over the course of this action.
+			Can be set via [page:.setLoop setLoop]. Default is *Infinity*.<br /><br />
+			Setting this number has no effect, if the [page:.loop loop mode] is set to
+			[page:Animation THREE.LoopOnce].<br /><br />
+
+			Note: The first run is not taken into account. For example: if *repetition* is set to 2, the
+			total number of executed rounds will be 3.
+		</div>
+
+		<h3>[property:Number time]</h3>
+		<div>
+			The local time of this action (in seconds, starting with 0).<br /><br />
+
+			The value gets clamped or wrapped to 0...clip.duration (according to the loop state). It can be
+			scaled relativly to the global mixer time by changing [page:.timeScale timeScale] (using
+			[page:.setEffectiveTimeScale setEffectiveTimeScale] or [page:.setDuration setDuration]).<br />
+		</div>
+
+		<h3>[property:Number timeScale]</h3>
+		<div>
+			Scaling factor for the [page:.time time]. A value of 0 causes the animation to pause. Negative
+			values cause the animation to play backwards. Default is 1.<br /><br />
+			Properties/methods concerning *timeScale* (respectively *time*) are:
+			[page:.getEffectiveTimeScale getEffectiveTimeScale],
+			[page:.halt halt],
+			[page:.paused paused],
+			[page:.setDuration setDuration],
+			[page:.setEffectiveTimeScale setEffectiveTimeScale],
+			[page:.stopWarping stopWarping],
+			[page:.syncWith syncWith],
+			[page:.warp warp].
+		</div>
+
+		<h3>[property:Number weight]</h3>
+		<div>
+			The degree of influence of this action (in the interval [0, 1]). Values between 0 (no impact)
+			and 1 (full impact) can be used to blend between several actions. Default is 1. <br /><br />
+			Properties/methods concerning  *weight* are:
+			[page:.crossFadeFrom crossFadeFrom],
+			[page:.crossFadeTo crossFadeTo],
+			[page:.enabled enabled],
+			[page:.fadeIn fadeIn],
+			[page:.fadeOut fadeOut],
+			[page:.getEffectiveWeight getEffectiveWeight],
+			[page:.setEffectiveWeight setEffectiveWeight],
+			[page:.stopFading stopFading].
+		</div>
+
+		<h3>[property:Boolean zeroSlopeAtEnd]</h3>
+		<div>
+			Enables smooth interpolation without separate clips for start, loop and end. Default is *true*.
+		</div>
+
+		<h3>[property:Boolean zeroSlopeAtStart]</h3>
+		<div>
+			Enables smooth interpolation without separate clips for start, loop and end. Default is *true*.
+		</div>
+
+
+		<h2>Methods</h2>
+
+
+		<h3>[method:AnimationAction crossFadeFrom]( [page:AnimationAction fadeOutAction], [page:Number durationInSeconds], [page:Boolean warpBoolean] )</h3>
+		<div>
+			Causes this action to [page:.fadeIn fade in], fading out another action simultaneously, within
+			the passed time interval. This method can be chained.<br /><br />
+
+			If warpBoolean is true, additional [page:.warp warping] (gradually changes of the time scales)
+			will be applied.<br /><br />
+
+			Note: Like with *fadeIn*/*fadeOut*, the fading starts/ends with a weight of 1.
+
+		</div>
+
+		<h3>[method:AnimationAction crossFadeTo]( [page:AnimationAction fadeInAction], [page:Number durationInSeconds], [page:Boolean warpBoolean] )</h3>
+		<div>
+			Causes this action to [page:.fadeOut fade out], fading in another action simultaneously, within
+			the passed time interval. This method can be chained.<br /><br />
+			If warpBoolean is true, additional [page:.warp warping] (gradually changes of the time scales)
+			will be applied.<br /><br />
+
+			Note: Like with *fadeIn*/*fadeOut*, the fading starts/ends with a weight of 1.
+		</div>
+
+		<h3>[method:AnimationAction fadeIn]( [page:Number durationInSeconds] )</h3>
+		<div>
+			Increases the [page:.weight weight] of this action gradually from 0 to 1, within the passed time
+			interval. This method can be chained.
+		</div>
+
+		<h3>[method:AnimationAction fadeOut]( [page:Number durationInSeconds] )</h3>
+		<div>
+			Decreases the [page:.weight weight] of this action gradually from 1 to 0, within the passed time
+			interval. This method can be chained.
+		</div>
+
+		<h3>[method:Number getEffectiveTimeScale]()</h3>
+		<div>
+			Returns the effective time scale (considering the current states of warping and
+			[page:.paused paused]).
+		</div>
+
+		<h3>[method:number getEffectiveWeight]()</h3>
+		<div>
+			Returns the effective weight (considering the current states of fading and
+			[page:.enabled enabled]).
+		</div>
+
+		<h3>[method:AnimationClip getClip]()</h3>
+		<div>
+			Returns the clip which holds the animation data for this action.
+		</div>
+
+		<h3>[method:AnimationMixer getMixer]()</h3>
+		<div>
+			Returns the mixer which is responsible for playing this action.
+		</div>
+
+		<h3>[method:Object3D getRoot]()</h3>
+		<div>
+			Returns the root object on which this action is performed.
+		</div>
+
+		<h3>[method:AnimationAction halt]( [page:Number durationInSeconds] )</h3>
+		<div>
+			Decelerates this animation's speed to 0 by decreasing [page:.timeScale timeScale] gradually
+			(starting from its current value), within the passed time interval. This method can be chained.
+		</div>
+
+		<h3>[method:Boolean isRunning]()</h3>
+		<div>
+			Returns true if the action’s [page:.time time] is currently running.<br /><br />
+
+			In addition to being activated in the mixer (see [page:.isScheduled isScheduled]) the following conditions must be fulfilled:
+			[page:.paused paused] is equal to false, [page:.enabled enabled] is equal to true,
+			[page:.timeScale timeScale] is different from 0, and there is no scheduling for a delayed start
+			([page:.startAt startAt]).<br /><br />
+
+			Note: *isRunning* being true doesn’t necessarily mean that the animation can actually be seen.
+			This is only the case, if [page:.weight weight] is additionally set to a non-zero value.
+		</div>
+
+		<h3>[method:Boolean isScheduled]()</h3>
+		<div>
+			Returns true, if this action is activated in the mixer.<br /><br />
+			Note: This doesn’t necessarily mean that the animation is actually running (compare the additional
+			conditions for [page:.isRunning isRunning]).
+		</div>
+
+		<h3>[method:AnimationAction play]()</h3>
+		<div>
+			Tells the mixer to activate the action. This method can be chained.<br /><br />
+
+			Note: Activating this action doesn’t necessarily mean that the animation starts immediately:
+			If the action had already finished before (by reaching the end of its last loop), or if a time
+			for a delayed start has been set (via [page:.startAt startAt]), a [page:.reset reset] must be
+			executed first. Some other settings ([page:.paused paused]=true, [page:.enabled enabled]=false,
+			[page:.weight weight]=0, [page:.timeScale timeScale]=0) can prevent the animation from playing,
+			too.
+		</div>
+
+		<h3>[method:AnimationAction reset]()</h3>
+		<div>
+			Resets the action. This method can be chained.<br /><br />
+
+			This method sets [page:.paused paused] to false, [page:.enabled enabled] to true,
+			[page:.time time] to 0, interrupts any scheduled fading and warping, and removes the internal
+			loop count and scheduling for delayed starting.<br /><br />
+
+			Note: .*reset* is always called by [page:.stop stop], but .*reset* doesn’t call .*stop* itself.
+			This means: If you want both, resetting and stopping, don’t call .*reset*; call .*stop* instead.
+		</div>
+
+		<h3>[method:AnimationAction setDuration]( [page:Number durationInSeconds] )</h3>
+		<div>
+			Sets the duration for a single loop of this action (by adjusting [page:.timeScale timeScale]
+			and stopping any scheduled warping). This method can be chained.
+		</div>
+
+		<h3>[method:AnimationAction setEffectiveTimeScale]( [page:Number timeScale] )</h3>
+		<div>
+			Sets the [page:.timeScale timeScale] and stops any scheduled warping. This method can be chained.<br /><br />
+
+			If [page:.paused paused] is false, the effective time scale (an internal property) will also be set
+			to this value; otherwise the effective time scale (directly affecting the animation at
+			this moment) will be set to 0.<br /><br />
+
+			Note: .*paused* will not be switched to *true* automatically, if .*timeScale* is set to 0 by
+			this method.
+		</div>
+
+		<h3>[method:AnimationAction setEffectiveWeight]( [page:Number weight] )</h3>
+		<div>
+			Sets the [page:.weight weight] and stops any scheduled fading. This method can be chained.<br /><br />
+
+			If [page:.enabled enabled] is true, the effective weight (an internal property) will also be set
+			to this value; otherwise the effective weight (directly affecting the animation at this moment)
+			will be set to 0.<br /><br />
+
+			Note: .*enabled* will not be switched to *false* automatically, if .*weight* is set to 0 by
+			this method.
+		</div>
+
+		<h3>[method:AnimationAction setLoop]( [page:Number loopMode], [page:Number repetitions] )</h3>
+		<div>
+			Sets the [page:.loop loop mode] and the number of [page:.repetitions repetitions]. This method
+			can be chained.
+		</div>
+
+		<h3>[method:AnimationAction startAt]( [page:Number startTimeInSeconds] )</h3>
+		<div>
+			Defines the time for a delayed start (usually passed as [page:AnimationMixer.time] +
+			deltaTimeInSeconds). This method can be chained.<br /><br />
+
+			Note: The animation will only start at the given time, if .*startAt* is chained with
+			[page:.play play], or if the action has already been activated in the mixer (by a previous
+			call of .*play*, without stopping or resetting it in the meantime).
+		</div>
+
+		<h3>[method:AnimationAction stop]()</h3>
+		<div>
+			Tells the mixer to deactivate this action. This method can be chained.<br /><br />
+
+			The action will be immediately stopped and completely [page:.reset reset].<br /><br />
+
+			Note: You can stop all active actions on the same mixer in one go via 
+			[page:AnimationMixer.stopAllAction mixer.stopAllAction].
+		</div>
+
+		<h3>[method:AnimationAction stopFading]()</h3>
+		<div>
+			Stops any scheduled [page:.fadeIn fading] which is applied to this action. This method can be
+			chained.
+		</div>
+
+		<h3>[method:AnimationAction stopWarping]()</h3>
+		<div>
+			Stops any scheduled [page:.warp warping] which is applied to this action. This method can be
+			chained.
+		</div>
+
+		<h3>[method:AnimationAction syncWith]( [page:AnimationAction otherAction] )</h3>
+		<div>
+			Synchronizes this action with the passed other action. This method can be chained.<br /><br />
+
+			Synchronizing is done by setting this action’s [page:.time time] and [page:.timeScale timeScale] values
+			to the corresponding values of the other action (stopping any scheduled warping).<br /><br />
+
+			Note: Future changes of the other action's *time* and *timeScale* will not be detected.
+		</div>
+
+		<h3>[method:AnimationAction warp]( [page:Number startTimeScale], [page:Number endTimeScale], [page:Number durationInSeconds] )</h3>
+		<div>
+			Changes the playback speed, within the passed time interval, by modifying 
+			[page:.timeScale timeScale] gradually from *startTimeScale* to *endTimeScale*. This method can
+			be chained.
+		</div>
+
+
+		<h2>Events</h2>
+
+
+		<div class="desc">
+			There are two events indicating when a single loop of the action respectively the entire action has finished. You can react to them with:
+		</div>
+		<code>
+		mixer.addEventListener( 'loop', function( e ) { …} ); // properties of e: type, action and loopDelta
+		mixer.addEventListener( 'finished', function( e ) { …} ); // properties of e: type, action and direction
+		</code>
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
 </html>

+ 133 - 133
docs/api/animation/AnimationClip.html

@@ -1,136 +1,136 @@
 <!DOCTYPE html>
 <html lang="en">
-  <head>
-    <meta charset="utf-8" />
-    <base href="../../" />
-    <script src="list.js"></script>
-    <script src="page.js"></script>
-    <link type="text/css" rel="stylesheet" href="page.css" />
-  </head>
-  <body>
-    <h1>[name]</h1>
-
-    <div class="desc">
-    An AnimationClip is a reusable set of keyframe tracks which represent an animation.<br /><br />
-    
-    For an overview of the different elements of the three.js animation system see the
-    "Animation System" article in the "Next Steps" section of the manual.
-    </div>
-    
-
-    <h2>Constructor</h2>
-    
-    
-    <h3>[name]( [page:String name], [page:Number duration], [page:Array tracks] )</h3>
-    <div>
-        [page:String name] - a name for this clip.<br />
-        [page:Number duration] - the duration of this clip (in seconds). If a negative value is passed,
-        the duration will be calculated from the passed *tracks* array.<br />
-        [page:Array tracks] - an array of [page:KeyframeTrack KeyframeTracks].<br /><br />
-    
-        Note: Instead of instantiating an AnimationClip directly with the constructor, you can use one 
-        of its static methods to create AnimationClips: from JSON ([page:.parse parse]), from morph 
-        target sequences ([page:.CreateFromMorphTargetSequence CreateFromMorphTargetSequence],
-        [page:.CreateClipsFromMorphTargetSequences CreateClipsFromMorphTargetSequences]) or from 
-        animation hierarchies ([page:.parseAnimation parseAnimation]) - if your model doesn't already 
-        hold AnimationClips in its geometry's animations array.
-    </div>
-    
-    
-    <h2>Properties</h2>
-    
-
-    <h3>[property:Number duration]</h3>
-    <div>
-        The duration of this clip (in seconds). This can be calculated from the [page:.tracks tracks] 
-        array via [page:.resetDuration resetDuration].
-    </div>     
-
-    <h3>[property:String name]</h3>
-    <div>
-        A name for this clip. A certain clip can be searched via [page:.findByName findByName].
-    </div>    
-
-    <h3>[property:Array tracks]</h3>
-    <div>
-        An array containing a [page:KeyframeTrack] for each property that are animated by this clip.
-    </div> 
-
-    <h3>[property:String uuid]</h3>
-    <div>
-        The [link:http://en.wikipedia.org/wiki/Universally_unique_identifier UUID] of this clip instance.
-        It gets automatically assigned and shouldn't be edited.
-    </div>
-       
-
-    <h2>Methods</h2>
-
-
-    <h3>[method:AnimationClip optimize]()</h3>
-    <div>
-        Optimizes each track by removing equivalent sequential keys (which are common in morph target 
-        sequences).
-    </div>
-
-    <h3>[method:null resetDuration]()</h3>
-    <div>
-        Sets the [page:.duration duration] of the clip to the duration of its longest 
-        [page:KeyframeTrack].
-    </div>
-
-    <h3>[method:AnimationClip trim]()</h3>
-    <div>
-        Trims all tracks to the clip's duration.
-    </div>
-
-
-    <h2>Static Methods</h2>
-
-
-    <h3>[method:Array CreateClipsFromMorphTargetSequences]( [page:String name], [page:Array morphTargetSequence], [page:Number fps], [page:Boolean noLoop] )</h3>
-    <div>
-        Returns an array of new AnimationClips created from the [page:Geometry.morphTargets morph 
-        target sequences] of a geometry, trying to sort morph target names into animation-group-based 
-        patterns like "Walk_001, Walk_002, Run_001, Run_002 ..."<br /><br />
-        
-        This method is called by the [page:JSONLoader] internally, and it uses 
-        [page:.CreateFromMorphTargetSequence CreateFromMorphTargetSequence].
-    </div>
-
-    <h3>[method:AnimationClip CreateFromMorphTargetSequence]( [page:String name], [page:Array morphTargetSequence], [page:Number fps], [page:Boolean noLoop] )</h3>
-    <div>
-        Returns a new AnimationClip from the passed [page:Geometry.morphTargets morph targets array] 
-        of a geometry, taking a name and the number of frames per second.<br /><br />
-
-        Note: The fps parameter is required, but the animation speed can be overridden in an 
-        *AnimationAction* via [page:AnimationAction.setDuration animationAction.setDuration].
-    </div>
-    
-    <h3>[method:AnimationClip findByName]( [page:Object objectOrClipArray], [page:String name] )</h3>
-    <div>
-        Searches for an AnimationClip by name, taking as its first parameter either an array of 
-        AnimationClips, or a mesh or geometry that contains an array named "animations".  
-    </div>
-
-    <h3>[method:AnimationClip parse]( [page:Object json] )</h3>
-    <div>
-        Parses a JSON representation of a clip and returns an AnimationClip.
-    </div>
-    
-    <h3>[method:AnimationClip parseAnimation]( [page:Object animation], [page:Array bones] )</h3>
-    <div>
-        Parses the animation.hierarchy format and returns an AnimationClip.
-    </div>    
-
-    <h3>[method:Object toJSON]( [page:AnimationClip clip] )</h3>
-    <div>
-        Takes an AnimationClip and returns a JSON object.
-    </div>
-    
-
-    <h2>Source</h2>
-
-
-    [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
-  </body>
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		<h1>[name]</h1>
+
+		<div class="desc">
+			An AnimationClip is a reusable set of keyframe tracks which represent an animation.<br /><br />
+
+			For an overview of the different elements of the three.js animation system see the
+			"Animation System" article in the "Next Steps" section of the manual.
+		</div>
+
+
+		<h2>Constructor</h2>
+
+
+		<h3>[name]( [page:String name], [page:Number duration], [page:Array tracks] )</h3>
+		<div>
+			[page:String name] - a name for this clip.<br />
+			[page:Number duration] - the duration of this clip (in seconds). If a negative value is passed,
+			the duration will be calculated from the passed *tracks* array.<br />
+			[page:Array tracks] - an array of [page:KeyframeTrack KeyframeTracks].<br /><br />
+
+			Note: Instead of instantiating an AnimationClip directly with the constructor, you can use one
+			of its static methods to create AnimationClips: from JSON ([page:.parse parse]), from morph
+			target sequences ([page:.CreateFromMorphTargetSequence CreateFromMorphTargetSequence],
+			[page:.CreateClipsFromMorphTargetSequences CreateClipsFromMorphTargetSequences]) or from
+			animation hierarchies ([page:.parseAnimation parseAnimation]) - if your model doesn't already
+			hold AnimationClips in its geometry's animations array.
+		</div>
+
+
+		<h2>Properties</h2>
+
+
+		<h3>[property:Number duration]</h3>
+		<div>
+			The duration of this clip (in seconds). This can be calculated from the [page:.tracks tracks]
+			array via [page:.resetDuration resetDuration].
+		</div>
+
+		<h3>[property:String name]</h3>
+		<div>
+			A name for this clip. A certain clip can be searched via [page:.findByName findByName].
+		</div>
+
+		<h3>[property:Array tracks]</h3>
+		<div>
+			An array containing a [page:KeyframeTrack] for each property that are animated by this clip.
+		</div>
+
+		<h3>[property:String uuid]</h3>
+		<div>
+			The [link:http://en.wikipedia.org/wiki/Universally_unique_identifier UUID] of this clip instance.
+			It gets automatically assigned and shouldn't be edited.
+		</div>
+
+
+		<h2>Methods</h2>
+
+
+		<h3>[method:AnimationClip optimize]()</h3>
+		<div>
+			Optimizes each track by removing equivalent sequential keys (which are common in morph target
+			sequences).
+		</div>
+
+		<h3>[method:null resetDuration]()</h3>
+		<div>
+			Sets the [page:.duration duration] of the clip to the duration of its longest
+			[page:KeyframeTrack].
+		</div>
+
+		<h3>[method:AnimationClip trim]()</h3>
+		<div>
+			Trims all tracks to the clip's duration.
+		</div>
+
+
+		<h2>Static Methods</h2>
+
+
+		<h3>[method:Array CreateClipsFromMorphTargetSequences]( [page:String name], [page:Array morphTargetSequence], [page:Number fps], [page:Boolean noLoop] )</h3>
+		<div>
+			Returns an array of new AnimationClips created from the [page:Geometry.morphTargets morph
+			target sequences] of a geometry, trying to sort morph target names into animation-group-based
+			patterns like "Walk_001, Walk_002, Run_001, Run_002 ..."<br /><br />
+
+			This method is called by the [page:JSONLoader] internally, and it uses
+			[page:.CreateFromMorphTargetSequence CreateFromMorphTargetSequence].
+		</div>
+
+		<h3>[method:AnimationClip CreateFromMorphTargetSequence]( [page:String name], [page:Array morphTargetSequence], [page:Number fps], [page:Boolean noLoop] )</h3>
+		<div>
+			Returns a new AnimationClip from the passed [page:Geometry.morphTargets morph targets array]
+			of a geometry, taking a name and the number of frames per second.<br /><br />
+
+			Note: The fps parameter is required, but the animation speed can be overridden in an 
+			*AnimationAction* via [page:AnimationAction.setDuration animationAction.setDuration].
+		</div>
+
+		<h3>[method:AnimationClip findByName]( [page:Object objectOrClipArray], [page:String name] )</h3>
+		<div>
+			Searches for an AnimationClip by name, taking as its first parameter either an array of
+			AnimationClips, or a mesh or geometry that contains an array named "animations".
+		</div>
+
+		<h3>[method:AnimationClip parse]( [page:Object json] )</h3>
+		<div>
+			Parses a JSON representation of a clip and returns an AnimationClip.
+		</div>
+
+		<h3>[method:AnimationClip parseAnimation]( [page:Object animation], [page:Array bones] )</h3>
+		<div>
+			Parses the animation.hierarchy format and returns an AnimationClip.
+		</div>
+
+		<h3>[method:Object toJSON]( [page:AnimationClip clip] )</h3>
+		<div>
+			Takes an AnimationClip and returns a JSON object.
+		</div>
+
+
+		<h2>Source</h2>
+
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
 </html>

+ 97 - 97
docs/api/animation/AnimationMixer.html

@@ -10,102 +10,102 @@
 	<body>
 		<h1>[name]</h1>
 
-	<div class="desc">
-		The AnimationMixer is a player for animations on a particular object in the scene. When 
-        multiple objects in the scene are animated independently, one AnimationMixer may be used for 
-        each object.<br /><br />
-        		
-        For an overview of the different elements of the three.js animation system see the
-        "Animation System" article in the "Next Steps" section of the manual.
-    </div>
-
-
-    <h2>Constructor</h2>
-    
-
-    <h3>[name]( [page:Object3D rootObject] )</h3>
-    <div>
-        [page:Object3D rootObject] - the object whose animations shall be played by this mixer.<br />
-    </div>
-    
-   
-    <h2>Properties</h2>
-
-
-    <h3>[property:Number time]</h3>
-    <div>
-        The global mixer time (in seconds; starting with 0 on the mixer's creation).
-    </div>
-      
-    <h3>[property:Number timeScale]</h3>
-    <div>
-        A scaling factor for the global [page:.time mixer time].<br /><br />
-        
-        Note: Setting the mixer's timeScale to 0 and later back to 1 is a possibility to pause/unpause 
-        all actions that are controlled by this mixer.
-    </div>
-    
-
-    <h2>Methods</h2>
-
-
-    <h3>[method:AnimationAction clipAction]([page:AnimationClip clip], [page:Object3D optionalRoot])</h3>
-    <div>
-        Returns an [page:AnimationAction] for the passed clip, optionally using a root object different 
-        from the mixer's default root. The first parameter can be either an [page:AnimationClip] object 
-        or the name of an AnimationClip.<br /><br />
-        
-        If an action fitting these parameters doesn't yet exist, it will be created by this method.<br /><br />
- 
-        Note: Calling this method several times with the same parameters returns always the same clip 
-        instance.
-    </div>
-
-    <h3>[method:AnimationAction existingAction]([page:AnimationClip clip], [page:Object3D optionalRoot])</h3>
-    <div>
-        Returns an existing [page:AnimationAction] for the passed clip, optionally using a root object
-        different from the mixer's default root.<br /><br />
-        
-        The first parameter can be either an [page:AnimationClip] object or the name of an AnimationClip.
-    </div>
-
-    <h3>[method:AnimationMixer stopAllAction]()</h3>
-    <div>
-        Deactivates all previously scheduled actions on this mixer.
-    </div>
-
-    <h3>[method:AnimationMixer update]([page:Number deltaTimeInSeconds]) </h3>
-    <div>
-        Advances the global mixer time and updates the animation.<br /><br />
-         
-        This is usually done in the render loop, passing [page:Clock.getDelta clock.getDelta] scaled by the mixer's [page:.timeScale timeScale]).
-    </div>
-
-    <h3>[method:Object3D getRoot]()</h3>
-    <div>
-        Returns this mixer's root object.
-    </div>
-
-    <h3>[method:null uncacheClip]([page:AnimationClip clip])</h3>
-
-    <div>
-        Deallocates all memory resources for a clip.
-    </div>
-
-    <h3>[method:null uncacheRoot]([page:Object3D root]) </h3>
-    <div>
-        Deallocates all memory resources for a root object.
-    </div>
-
-    <h3>[method:null uncacheAction]([page:AnimationClip clip], [page:Object3D optionalRoot])</h3>
-    <div>
-        Deallocates all memory resources for an action.
-    </div>
-
-
-    <h2>Source</h2>
-
-
-    [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+		<div class="desc">
+			The AnimationMixer is a player for animations on a particular object in the scene. When
+			multiple objects in the scene are animated independently, one AnimationMixer may be used for
+			each object.<br /><br />
+
+			For an overview of the different elements of the three.js animation system see the
+			"Animation System" article in the "Next Steps" section of the manual.
+		</div>
+
+
+		<h2>Constructor</h2>
+
+
+		<h3>[name]( [page:Object3D rootObject] )</h3>
+		<div>
+			[page:Object3D rootObject] - the object whose animations shall be played by this mixer.<br />
+		</div>
+
+
+		<h2>Properties</h2>
+
+
+		<h3>[property:Number time]</h3>
+		<div>
+			The global mixer time (in seconds; starting with 0 on the mixer's creation).
+		</div>
+
+		<h3>[property:Number timeScale]</h3>
+		<div>
+			A scaling factor for the global [page:.time mixer time].<br /><br />
+
+			Note: Setting the mixer's timeScale to 0 and later back to 1 is a possibility to pause/unpause
+			all actions that are controlled by this mixer.
+		</div>
+
+
+		<h2>Methods</h2>
+
+
+		<h3>[method:AnimationAction clipAction]([page:AnimationClip clip], [page:Object3D optionalRoot])</h3>
+		<div>
+			Returns an [page:AnimationAction] for the passed clip, optionally using a root object different
+			from the mixer's default root. The first parameter can be either an [page:AnimationClip] object
+			or the name of an AnimationClip.<br /><br />
+
+			If an action fitting these parameters doesn't yet exist, it will be created by this method.<br /><br />
+
+			Note: Calling this method several times with the same parameters returns always the same clip 
+			instance.
+		</div>
+
+		<h3>[method:AnimationAction existingAction]([page:AnimationClip clip], [page:Object3D optionalRoot])</h3>
+		<div>
+			Returns an existing [page:AnimationAction] for the passed clip, optionally using a root object
+			different from the mixer's default root.<br /><br />
+
+			The first parameter can be either an [page:AnimationClip] object or the name of an AnimationClip.
+		</div>
+
+		<h3>[method:Object3D getRoot]()</h3>
+		<div>
+			Returns this mixer's root object.
+		</div>
+
+		<h3>[method:AnimationMixer stopAllAction]()</h3>
+		<div>
+			Deactivates all previously scheduled actions on this mixer.
+		</div>
+
+		<h3>[method:AnimationMixer update]([page:Number deltaTimeInSeconds]) </h3>
+		<div>
+			Advances the global mixer time and updates the animation.<br /><br />
+
+			This is usually done in the render loop, passing [page:Clock.getDelta clock.getDelta] scaled by the mixer's [page:.timeScale timeScale]).
+		</div>
+
+		<h3>[method:null uncacheClip]([page:AnimationClip clip])</h3>
+
+		<div>
+			Deallocates all memory resources for a clip.
+		</div>
+
+		<h3>[method:null uncacheRoot]([page:Object3D root]) </h3>
+		<div>
+			Deallocates all memory resources for a root object.
+		</div>
+
+		<h3>[method:null uncacheAction]([page:AnimationClip clip], [page:Object3D optionalRoot])</h3>
+		<div>
+			Deallocates all memory resources for an action.
+		</div>
+
+
+		<h2>Source</h2>
+
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
 	</body>
 </html>

+ 59 - 59
docs/api/animation/AnimationObjectGroup.html

@@ -1,85 +1,85 @@
 <!DOCTYPE html>
 <html lang="en">
-  <head>
-    <meta charset="utf-8" />
-    <base href="../../" />
-    <script src="list.js"></script>
-    <script src="page.js"></script>
-    <link type="text/css" rel="stylesheet" href="page.css" />
-  </head>
-  <body>
-    <h1>[name]</h1>
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		<h1>[name]</h1>
 
-    <div class="desc">A group of objects that receives a shared animation state.<br /><br />
-        		
-        For an overview of the different elements of the three.js animation system see the
-        "Animation System" article in the "Next Steps" section of the manual.
-    </div>
+		<div class="desc">A group of objects that receives a shared animation state.<br /><br />
 
-    <h2>Usage:</h2>
+			For an overview of the different elements of the three.js animation system see the
+			"Animation System" article in the "Next Steps" section of the manual.
+		</div>
 
-    <div class="desc">
-        Add objects you would otherwise pass as 'root' to the	constructor or the [page:AnimationMixer.clipAction clipAction]
-        method of [page:AnimationMixer AnimationMixer] and instead pass this object as 'root'.<br /><br />
+		<h2>Usage:</h2>
 
-        Note that objects of this class appear as one object to the mixer,
-        so cache control of the individual objects must be done	on the group.
-    </div>
+		<div class="desc">
+			Add objects you would otherwise pass as 'root' to the constructor or the [page:AnimationMixer.clipAction clipAction]
+			method of [page:AnimationMixer AnimationMixer] and instead pass this object as 'root'.<br /><br />
 
+			Note that objects of this class appear as one object to the mixer,
+			so cache control of the individual objects must be done	on the group.
+		</div>
 
-    <h2>Limitations</h2>
-    <div class="desc">
-        The animated properties must be compatible among all objects in the group.<br /><br />
 
-        A single property can either be controlled through a target group or directly, but not both.
-    </div>
+		<h2>Limitations</h2>
+		<div class="desc">
+			The animated properties must be compatible among all objects in the group.<br /><br />
 
+			A single property can either be controlled through a target group or directly, but not both.
+		</div>
 
-    <h2>Constructor</h2>
 
+		<h2>Constructor</h2>
 
-    <h3>[name]( [page:object obj1], [page:object obj2], [page:object obj3], ... )</h3>
-      [page:object obj] - an abitrary number of meshes that share the same animation state.<br />
 
-   
-    <h2>Properties</h2>
-    
+		<h3>[name]( [page:object obj1], [page:object obj2], [page:object obj3], ... )</h3>
+		[page:object obj] - an abitrary number of meshes that share the same animation state.<br />
 
-    <h3>[property:object stats]</h3>
-    <div>
-        An object that contains some informations of this *AnimationObjectGroup* (total number, number 
-        in use, number of bindings per object)
-    </div>    
-    
-    <h3>[property:String uuid]</h3>
-    <div>
-        The [link:http://en.wikipedia.org/wiki/Universally_unique_identifier UUID] of this 
-        *AnimationObjectGroup*. It gets automatically assigned and shouldn't be edited.
-    </div>
 
+		<h2>Properties</h2>
 
-    <h2>Methods</h2>
 
+		<h3>[property:object stats]</h3>
+		<div>
+			An object that contains some informations of this *AnimationObjectGroup* (total number, number
+			in use, number of bindings per object)
+		</div>
 
-    <h3>[method:null add]( [page:object obj1], [page:object obj2], [page:object obj3], ... )</h3>
-    <div>
-        Adds an arbitrary number of objects to this *AnimationObjectGroup*.
-    </div>
+		<h3>[property:String uuid]</h3>
+		<div>
+			The [link:http://en.wikipedia.org/wiki/Universally_unique_identifier UUID] of this
+			*AnimationObjectGroup*. It gets automatically assigned and shouldn't be edited.
+		</div>
 
-    <h3>[method:null remove]( [page:object obj1], [page:object obj2], [page:object obj3], ... )</h3>
-    <div>
-        Removes an arbitrary number of objects from this *AnimationObjectGroup*.
-    </div>
 
-    <h3>[method:null uncache]( [page:object obj1], [page:object obj2], [page:object obj3], ... )</h3>
-    <div>
-        Deallocates all memory resources for the passed objects of this *AnimationObjectGroup*.
-    </div>
+		<h2>Methods</h2>
 
 
-    <h2>Source</h2>
+		<h3>[method:null add]( [page:object obj1], [page:object obj2], [page:object obj3], ... )</h3>
+		<div>
+			Adds an arbitrary number of objects to this *AnimationObjectGroup*.
+		</div>
 
+		<h3>[method:null remove]( [page:object obj1], [page:object obj2], [page:object obj3], ... )</h3>
+		<div>
+			Removes an arbitrary number of objects from this *AnimationObjectGroup*.
+		</div>
 
-    [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
-  </body>
+		<h3>[method:null uncache]( [page:object obj1], [page:object obj2], [page:object obj3], ... )</h3>
+		<div>
+			Deallocates all memory resources for the passed objects of this *AnimationObjectGroup*.
+		</div>
+
+
+		<h2>Source</h2>
+
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
 </html>

+ 54 - 54
docs/api/animation/AnimationUtils.html

@@ -1,57 +1,57 @@
 <!DOCTYPE html>
 <html lang="en">
-  <head>
-    <meta charset="utf-8" />
-    <base href="../../" />
-    <script src="list.js"></script>
-    <script src="page.js"></script>
-    <link type="text/css" rel="stylesheet" href="page.css" />
-  </head>
-  <body>
-    <h1>[name]</h1>
-
-    <div class="desc">
-    An object with various functions to assist with animations, used internally.
-    </div>
-    
-
-    <h2>Methods</h2>
-    
-
-    <h3>[method:Array arraySlice]( array, from, to )</h3>
-    <div>
-    This is the same as  Array.prototype.slice, but also works on typed arrays.
-    </div>
-
-    <h3>[method:Array convertArray]( array, type, forceClone )</h3>
-    <div>
-    Converts an array to a specific type.
-    </div>
-
-    <h3>[method:Array flattenJSON]( jsonKeys, times, values, valuePropertyName  )</h3>
-    <div>
-    Used for parsing AOS keyframe formats.
-    </div>
-
-    <h3>[method:Array getKeyframeOrder]( times )</h3>
-    <div>
-    Returns an array by which times and values can be sorted.
-    </div>
-
-    <h3>[method:Boolean isTypedArray]( object )</h3>
-    <div>
-    Returns *true* if the object is a typed array.
-    </div>
-
-    <h3>[method:Array sortedArray]( values, stride, order )</h3>
-    <div>
-    Sorts the array previously returned by [page:AnimationUtils.getKeyframeOrder getKeyframeOrder].
-    </div>
-    
-
-    <h2>Source</h2>
-
-
-    [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
-  </body>
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		<h1>[name]</h1>
+
+		<div class="desc">
+		An object with various functions to assist with animations, used internally.
+		</div>
+
+
+		<h2>Methods</h2>
+
+
+		<h3>[method:Array arraySlice]( array, from, to )</h3>
+		<div>
+		This is the same as  Array.prototype.slice, but also works on typed arrays.
+		</div>
+
+		<h3>[method:Array convertArray]( array, type, forceClone )</h3>
+		<div>
+		Converts an array to a specific type.
+		</div>
+
+		<h3>[method:Array flattenJSON]( jsonKeys, times, values, valuePropertyName  )</h3>
+		<div>
+		Used for parsing AOS keyframe formats.
+		</div>
+
+		<h3>[method:Array getKeyframeOrder]( times )</h3>
+		<div>
+		Returns an array by which times and values can be sorted.
+		</div>
+
+		<h3>[method:Boolean isTypedArray]( object )</h3>
+		<div>
+		Returns *true* if the object is a typed array.
+		</div>
+
+		<h3>[method:Array sortedArray]( values, stride, order )</h3>
+		<div>
+		Sorts the array previously returned by [page:AnimationUtils.getKeyframeOrder getKeyframeOrder].
+		</div>
+
+
+		<h2>Source</h2>
+
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
 </html>

+ 234 - 234
docs/api/animation/KeyframeTrack.html

@@ -1,237 +1,237 @@
 <!DOCTYPE html>
 <html lang="en">
-  <head>
-    <meta charset="utf-8" />
-    <base href="../../" />
-    <script src="list.js"></script>
-    <script src="page.js"></script>
-    <link type="text/css" rel="stylesheet" href="page.css" />
-  </head>
-  <body>
-
-    <h1>[name]</h1>
-
-    <div class="desc">
-        A KeyframeTrack is a timed sequence of [link:https://en.wikipedia.org/wiki/Key_frame keyframes], 
-        which are composed of lists of times and related values, and which are used to animate a 
-        specific property of an object.<br /><br />
-
-        For an overview of the different elements of the three.js animation system see the
-        "Animation System" article in the "Next Steps" section of the manual.<br /><br />
-
-        In contrast to the animation hierarchy of the 
-        [link:https://github.com/mrdoob/three.js/wiki/JSON-Model-format-3 JSON model format] a 
-        *KeyframeTrack* doesn't store its single keyframes as objects in a "keys" array (holding the 
-        times and the values for each frame together in one place).<br /><br />
-         
-        Instead of this there are always two arrays in a *KeyframeTrack*: the [page:.times times] array 
-        stores the time values for all keyframes of this track in sequential order, and the 
-        [page:.values values] array contains the corresponding changing values of the animated property.<br /><br />
-         
-        A single value, belonging to a certain point of time, can not only be a simple number, but (for 
-        example) a vector (if a position is animated) or a quaternion (if a rotation is animated). For 
-        this reason the values array (which is a flat array, too) might be three or four times as long as the 
-        times array.<br /><br />
-
-        Corresponding to the different possible types of animated values there are several subclasses of 
-        *KeyframeTrack*, inheriting the most properties and methods:
-        
-        <ul> 
-            <li>[page:BooleanKeyframeTrack]</li> 
-            <li>[page:ColorKeyframeTrack]</li>
-            <li>[page:NumberKeyframeTrack]</li>
-            <li>[page:QuaternionKeyframeTrack]</li>
-            <li>[page:StringKeyframeTrack]</li> 
-            <li>[page:VectorKeyframeTrack]</li>
-        </ul>
-        Some examples of how to manually create [page:AnimationClip AnimationClips] with different sorts 
-        of KeyframeTracks can be found in the [link:https://threejs.org/examples/js/AnimationClipCreator.js] 
-        file.<br /><br />
-
-        Since explicit values are only specified for the discrete points of time stored in the times array, 
-        all values in between have to be interpolated.<br /><br />
-        
-        The track's name is important for the connection of this track with a specific property of the 
-        animated node (done by [page:PropertyBinding]).
-    
-
-    </div>
-
-
-    <h2>Constructor</h2>
-
-
-    <h3>[name]( [page:String name], [page:Array times], [page:Array values], [page:Constant interpolation] )</h3>
-    <div>
-      [page:String name] - the identifier for the *KeyframeTrack*.<br />
-      [page:Array times] - an array of keyframe times, converted internally to a 
-      [link:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float32Array Float32Array].<br />
-      [page:Array values] - an array with the values related to the times array, converted internally to a 
-      [link:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float32Array Float32Array].<br />
-      [page:Constant interpolation] - the type of interpolation to use. See 
-      [page:Animation Animation Constants] for possible values. Default is [page:Animation InterpolateLinear].
-    </div>
-    
-
-    <h2>Properties</h2>
-
-
-    <h3>[property:String name]</h3>
-    <div>
-        The track's name can refer to [page:Geometry.morphTargets morph targets] or 
-        [page:SkinnedMesh bones] or possibly other values within an animated object. See 
-        [page:PropertyBinding.parseTrackName] for the forms of strings that can be parsed for property 
-        binding:<br /><br />
-
-        The name can specify the node either using its name or its uuid (although it needs to be in the 
-        subtree of the scene graph node passed into the mixer). Or, if the track name starts with a dot, 
-        the track applies to the root node that was passed into the mixer.<br /><br />
-
-        Usually after the node a property will be specified directly. But you can also specify a 
-        subproperty, such as .rotation[x], if you just want to drive the X component of the rotation 
-        via a float track.<br /><br />
-
-        You can also specify bones or multimaterials by using an object name, for example: 
-        .bones[R_hand].scale; the red channel of the diffuse color of the fourth material in a 
-        materials array - as a further example - can be accessed with .materials[3].diffuse[r].<br /><br />
-
-        PropertyBinding will also resolve morph target names, for example: .morphTargetInfluences[run].<br /><br />
-
-        Note: The track's name does not necessarily have to be unique. Multiple tracks can drive the same 
-        property. The result should be based on a weighted blend between the multiple tracks according to 
-        the weights of their respective actions.
-    </div>
-
-    <h3>[property:Float32Array times]</h3>
-    <div>
-        A [link:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float32Array Float32Array], 
-        converted from the times array which is passed in the constructor.
-    </div>
-
-    <h3>[property:Float32Array values]</h3>
-    <div>
-        A [link:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float32Array Float32Array], 
-        converted from the values array which is passed in the constructor.
-    </div>
-
-    <h3>[property:Constant DefaultInterpolation]</h3>
-    <div>
-        The default interpolation type: [page:Animation InterpolateLinear].
-    </div>    
-    
-    <h3>[property:Constant TimeBufferType ]</h3>
-    <div>
-        [link:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float32Array Float32Array],
-        the type of the buffer internally used for the times.
-    </div>    
-    
-    <h3>[property:Constant ValueBufferType ]</h3>
-    <div>
-        [link:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float32Array Float32Array],
-        the type of the buffer internally used for the values.
-    </div>
-
-
-    <h2>Methods</h2>
-    
-
-    <h3>[method:null createInterpolant]()</h3>
-    <div>
-      Creates a [page:LinearInterpolant LinearInterpolant], [page:CubicInterpolant CubicInterpolant]
-      or [page:DiscreteInterpolant DiscreteInterpolant], depending on the value of the interpolation 
-      parameter passed in the constructor.
-    </div>
-
-    <h3>[method:null getInterpolation]()</h3>
-    <div>
-      Returns the interpolation type.
-    </div>
-
-    <h3>[method:Number getValueSize]()</h3>
-    <div>
-      Returns the size of each value (that is the length of the [page:.values values] array divided 
-      by the length of the [page:.times times] array).
-    </div>
-
-    <h3>[method:DiscreteInterpolant InterpolantFactoryMethodDiscrete]( [link:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float32Array result] )</h3>
-    <div>
-      Creates a new [page:DiscreteInterpolant DiscreteInterpolant] from the 
-      [page:KeyframeTrack.times times] and [page:KeyframeTrack.times values]. A Float32Array can be 
-      passed which will receive the results. Otherwise a new array with the appropriate size will be 
-      created automatically.
-    </div>
-
-    <h3>[method:null InterpolantFactoryMethodLinear]( [link:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float32Array result] )</h3>
-    <div>
-      Creates a new [page:LinearInterpolant LinearInterpolant] from the 
-      [page:KeyframeTrack.times times] and [page:KeyframeTrack.times values]. A Float32Array can be 
-      passed which will receive the results. Otherwise a new array with the appropriate size will be 
-      created automatically.
-    </div>
-
-    <h3>[method:null InterpolantFactoryMethodSmooth]( [link:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float32Array result] )</h3>
-    <div>
-      Create a new [page:CubicInterpolant CubicInterpolant] from the 
-      [page:KeyframeTrack.times times] and [page:KeyframeTrack.times values]. A Float32Array can be 
-      passed which will receive the results. Otherwise a new array with the appropriate size will be 
-      created automatically.
-    </div>
-
-    <h3>[method:null optimize]()</h3>
-    <div>
-      Removes equivalent sequential keys, which are common in morph target sequences. Called 
-      automatically by the constructor.
-    </div>
-
-    <h3>[method:null scale]()</h3>
-    <div>
-      Scales all keyframe times by a factor.<br /><br />
-      
-      Note: This is useful, for example, for conversions to a certain rate of frames per seconds (as it
-      is done internally by 
-      [page:AnimationClip.CreateFromMorphTargetSequence animationClip.CreateFromMorphTargetSequence]).
-    </div>
-
-    <h3>[method:null setInterpolation]( [page:Constant interpolationType] )</h3>
-    <div>
-      Sets the interpolation type. See [page:Animation Animation Constants] for choices.
-    </div>
-
-    <h3>[method:null shift]( [page:Number timeOffsetInSeconds] )</h3>
-    <div>
-      Moves all keyframes either forward or backward in time.
-    </div>
-
-
-    <h3>[method:null trim]( [page:Number startTimeInSeconds], [page:Number endTimeInSeconds] )</h3>
-    <div>
-      Removes keyframes before *startTime* and after *endTime*,
-      without changing any values within the range [*startTime*, *endTime*].
-    </div>
-
-    <h3>[method:null validate]()</h3>
-    <div>
-      Performs minimal validation on the tracks. Called automatically by the constructor.<br /><br />
-      This method logs errors to the console, if a track is empty, if the [page:.valueSize value size] is not valid, if an item
-      in the [page:.times times] or [page:.values values] array is not a valid number or if the items in the *times* array are out of order. 
-    </div>
-    
-    <h2>Static Methods</h2>
-
-    <h3>[method:KeyframeTrack parse]( [page:JSON json] )</h3>
-    <div>
-    Parses a JSON object and returns a new keyframe track of the correct type.
-    </div>    
-
-    <h3>[method:JSON toJSON]( [page:KeyframeTrack track] )</h3>
-    <div>
-    Converts the track to JSON.
-    </div>
-    
-
-    <h2>Source</h2>
-
-
-    [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
-  </body>
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+
+		<h1>[name]</h1>
+
+		<div class="desc">
+			A KeyframeTrack is a timed sequence of [link:https://en.wikipedia.org/wiki/Key_frame keyframes],
+			which are composed of lists of times and related values, and which are used to animate a
+			specific property of an object.<br /><br />
+
+			For an overview of the different elements of the three.js animation system see the
+			"Animation System" article in the "Next Steps" section of the manual.<br /><br />
+
+			In contrast to the animation hierarchy of the
+			[link:https://github.com/mrdoob/three.js/wiki/JSON-Model-format-3 JSON model format] a
+			*KeyframeTrack* doesn't store its single keyframes as objects in a "keys" array (holding the
+			times and the values for each frame together in one place).<br /><br />
+
+			Instead of this there are always two arrays in a *KeyframeTrack*: the [page:.times times] array
+			stores the time values for all keyframes of this track in sequential order, and the
+			[page:.values values] array contains the corresponding changing values of the animated property.<br /><br />
+
+			A single value, belonging to a certain point of time, can not only be a simple number, but (for
+			example) a vector (if a position is animated) or a quaternion (if a rotation is animated). For
+			this reason the values array (which is a flat array, too) might be three or four times as long as the
+			times array.<br /><br />
+
+			Corresponding to the different possible types of animated values there are several subclasses of
+			*KeyframeTrack*, inheriting the most properties and methods:
+
+			<ul>
+				<li>[page:BooleanKeyframeTrack]</li>
+				<li>[page:ColorKeyframeTrack]</li>
+				<li>[page:NumberKeyframeTrack]</li>
+				<li>[page:QuaternionKeyframeTrack]</li>
+				<li>[page:StringKeyframeTrack]</li>
+				<li>[page:VectorKeyframeTrack]</li>
+			</ul>
+			Some examples of how to manually create [page:AnimationClip AnimationClips] with different sorts
+			of KeyframeTracks can be found in the [link:https://threejs.org/examples/js/AnimationClipCreator.js]
+			file.<br /><br />
+
+			Since explicit values are only specified for the discrete points of time stored in the times array,
+			all values in between have to be interpolated.<br /><br />
+
+			The track's name is important for the connection of this track with a specific property of the
+			animated node (done by [page:PropertyBinding]).
+
+
+		</div>
+
+
+		<h2>Constructor</h2>
+
+
+		<h3>[name]( [page:String name], [page:Array times], [page:Array values], [page:Constant interpolation] )</h3>
+		<div>
+			[page:String name] - the identifier for the *KeyframeTrack*.<br />
+			[page:Array times] - an array of keyframe times, converted internally to a
+			[link:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float32Array Float32Array].<br />
+			[page:Array values] - an array with the values related to the times array, converted internally to a
+			[link:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float32Array Float32Array].<br />
+			[page:Constant interpolation] - the type of interpolation to use. See
+			[page:Animation Animation Constants] for possible values. Default is [page:Animation InterpolateLinear].
+		</div>
+
+
+		<h2>Properties</h2>
+
+
+		<h3>[property:String name]</h3>
+		<div>
+			The track's name can refer to [page:Geometry.morphTargets morph targets] or
+			[page:SkinnedMesh bones] or possibly other values within an animated object. See
+			[page:PropertyBinding.parseTrackName] for the forms of strings that can be parsed for property
+			binding:<br /><br />
+
+			The name can specify the node either using its name or its uuid (although it needs to be in the
+			subtree of the scene graph node passed into the mixer). Or, if the track name starts with a dot,
+			the track applies to the root node that was passed into the mixer.<br /><br />
+
+			Usually after the node a property will be specified directly. But you can also specify a
+			subproperty, such as .rotation[x], if you just want to drive the X component of the rotation
+			via a float track.<br /><br />
+
+			You can also specify bones or multimaterials by using an object name, for example:
+			.bones[R_hand].scale; the red channel of the diffuse color of the fourth material in a
+			materials array - as a further example - can be accessed with .materials[3].diffuse[r].<br /><br />
+
+			PropertyBinding will also resolve morph target names, for example: .morphTargetInfluences[run].<br /><br />
+
+			Note: The track's name does not necessarily have to be unique. Multiple tracks can drive the same
+			property. The result should be based on a weighted blend between the multiple tracks according to
+			the weights of their respective actions.
+		</div>
+
+		<h3>[property:Float32Array times]</h3>
+		<div>
+			A [link:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float32Array Float32Array],
+			converted from the times array which is passed in the constructor.
+		</div>
+
+		<h3>[property:Float32Array values]</h3>
+		<div>
+			A [link:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float32Array Float32Array],
+			converted from the values array which is passed in the constructor.
+		</div>
+
+		<h3>[property:Constant DefaultInterpolation]</h3>
+		<div>
+			The default interpolation type: [page:Animation InterpolateLinear].
+		</div>
+
+		<h3>[property:Constant TimeBufferType ]</h3>
+		<div>
+			[link:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float32Array Float32Array],
+			the type of the buffer internally used for the times.
+		</div>
+
+		<h3>[property:Constant ValueBufferType ]</h3>
+		<div>
+			[link:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float32Array Float32Array],
+			the type of the buffer internally used for the values.
+		</div>
+
+
+		<h2>Methods</h2>
+
+
+		<h3>[method:null createInterpolant]()</h3>
+		<div>
+			Creates a [page:LinearInterpolant LinearInterpolant], [page:CubicInterpolant CubicInterpolant]
+			or [page:DiscreteInterpolant DiscreteInterpolant], depending on the value of the interpolation
+			parameter passed in the constructor.
+		</div>
+
+		<h3>[method:null getInterpolation]()</h3>
+		<div>
+			Returns the interpolation type.
+		</div>
+
+		<h3>[method:Number getValueSize]()</h3>
+		<div>
+			Returns the size of each value (that is the length of the [page:.values values] array divided
+			by the length of the [page:.times times] array).
+		</div>
+
+		<h3>[method:DiscreteInterpolant InterpolantFactoryMethodDiscrete]( [link:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float32Array result] )</h3>
+		<div>
+			Creates a new [page:DiscreteInterpolant DiscreteInterpolant] from the
+			[page:KeyframeTrack.times times] and [page:KeyframeTrack.times values]. A Float32Array can be
+			passed which will receive the results. Otherwise a new array with the appropriate size will be
+			created automatically.
+		</div>
+
+		<h3>[method:null InterpolantFactoryMethodLinear]( [link:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float32Array result] )</h3>
+		<div>
+			Creates a new [page:LinearInterpolant LinearInterpolant] from the
+			[page:KeyframeTrack.times times] and [page:KeyframeTrack.times values]. A Float32Array can be
+			passed which will receive the results. Otherwise a new array with the appropriate size will be
+			created automatically.
+		</div>
+
+		<h3>[method:null InterpolantFactoryMethodSmooth]( [link:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float32Array result] )</h3>
+		<div>
+			Create a new [page:CubicInterpolant CubicInterpolant] from the
+			[page:KeyframeTrack.times times] and [page:KeyframeTrack.times values]. A Float32Array can be
+			passed which will receive the results. Otherwise a new array with the appropriate size will be
+			created automatically.
+		</div>
+
+		<h3>[method:null optimize]()</h3>
+		<div>
+			Removes equivalent sequential keys, which are common in morph target sequences. Called
+			automatically by the constructor.
+		</div>
+
+		<h3>[method:null scale]()</h3>
+		<div>
+			Scales all keyframe times by a factor.<br /><br />
+
+			Note: This is useful, for example, for conversions to a certain rate of frames per seconds (as it
+			is done internally by
+			[page:AnimationClip.CreateFromMorphTargetSequence animationClip.CreateFromMorphTargetSequence]).
+		</div>
+
+		<h3>[method:null setInterpolation]( [page:Constant interpolationType] )</h3>
+		<div>
+			Sets the interpolation type. See [page:Animation Animation Constants] for choices.
+		</div>
+
+		<h3>[method:null shift]( [page:Number timeOffsetInSeconds] )</h3>
+		<div>
+			Moves all keyframes either forward or backward in time.
+		</div>
+
+
+		<h3>[method:null trim]( [page:Number startTimeInSeconds], [page:Number endTimeInSeconds] )</h3>
+		<div>
+			Removes keyframes before *startTime* and after *endTime*,
+			without changing any values within the range [*startTime*, *endTime*].
+		</div>
+
+		<h3>[method:null validate]()</h3>
+		<div>
+			Performs minimal validation on the tracks. Called automatically by the constructor.<br /><br />
+			This method logs errors to the console, if a track is empty, if the [page:.valueSize value size] is not valid, if an item
+			in the [page:.times times] or [page:.values values] array is not a valid number or if the items in the *times* array are out of order.
+		</div>
+
+		<h2>Static Methods</h2>
+
+		<h3>[method:KeyframeTrack parse]( [page:JSON json] )</h3>
+		<div>
+		Parses a JSON object and returns a new keyframe track of the correct type.
+		</div>
+
+		<h3>[method:JSON toJSON]( [page:KeyframeTrack track] )</h3>
+		<div>
+		Converts the track to JSON.
+		</div>
+
+
+		<h2>Source</h2>
+
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
 </html>

+ 88 - 88
docs/api/animation/PropertyBinding.html

@@ -1,131 +1,131 @@
 <!DOCTYPE html>
 <html lang="en">
-  <head>
-    <meta charset="utf-8" />
-    <base href="../../" />
-    <script src="list.js"></script>
-    <script src="page.js"></script>
-    <link type="text/css" rel="stylesheet" href="page.css" />
-  </head>
-  <body>
-    <h1>[name]</h1>
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		<h1>[name]</h1>
 
-    <div class="desc">
-    This holds a reference to a real property in the scene graph; used internally.
-    </div>
+		<div class="desc">
+			This holds a reference to a real property in the scene graph; used internally.
+		</div>
 
 
-    <h2>Constructor</h2>
+		<h2>Constructor</h2>
 
 
-    <h3>[name]( [page:Object3D rootNode], path, parsedPath )</h3>
-    <div>
-      -- [page:Object3D rootNode]:
-      -- path
-      -- parsedPath (optional)
+		<h3>[name]( [page:Object3D rootNode], path, parsedPath )</h3>
+		<div>
+			-- [page:Object3D rootNode]:
+			-- path
+			-- parsedPath (optional)
 
-    </div>
+		</div>
 
-    <h2>Properties</h2>
+		<h2>Properties</h2>
 
-    <h3>[property:Number path]</h3>
-    <div>
+		<h3>[property:Number path]</h3>
+		<div>
 
-    </div>
+		</div>
 
-    <h3>[property:Number parsedPath]</h3>
-    <div>
+		<h3>[property:Number parsedPath]</h3>
+		<div>
 
-    </div>
+		</div>
 
-    <h3>[property:Number node]</h3>
-    <div>
+		<h3>[property:Number node]</h3>
+		<div>
 
-    </div>
+		</div>
 
-    <h3>[property:Number rootNode]</h3>
-    <div>
+		<h3>[property:Number rootNode]</h3>
+		<div>
 
-    </div>
+		</div>
 
-    <h3>[property:Object BindingType]</h3>
-    <div>
+		<h3>[property:Object BindingType]</h3>
+		<div>
 
-    </div>
+		</div>
 
-    <h3>[property:Object Versioning]</h3>
-    <div>
+		<h3>[property:Object Versioning]</h3>
+		<div>
 
-    </div>
+		</div>
 
-    <h3>[property:Array GetterByBindingType]</h3>
-    <div>
+		<h3>[property:Array GetterByBindingType]</h3>
+		<div>
 
-    </div>
+		</div>
 
-    <h3>[property:Array SetterByBindingTypeAndVersioning]</h3>
-    <div>
+		<h3>[property:Array SetterByBindingTypeAndVersioning]</h3>
+		<div>
 
-    </div>
+		</div>
 
 
 
-    <h2>Methods</h2>
+		<h2>Methods</h2>
 
-    <h3>[method:null getValue]( [page:Array targetArray], [page:Number offset] )</h3>
-    <div>
-    </div>
+		<h3>[method:null getValue]( [page:Array targetArray], [page:Number offset] )</h3>
+		<div>
+		</div>
 
-    <h3>[method:null setValue]( [page:Array sourceArray], [page:Number offset] )</h3>
-    <div>
-    </div>
+		<h3>[method:null setValue]( [page:Array sourceArray], [page:Number offset] )</h3>
+		<div>
+		</div>
 
-    <h3>[method:null bind]( )</h3>
-    <div>
-      Create getter / setter pair for a property in the scene graph. Used internally by
-      [page:PropertyBinding.getValue getValue] and [page:PropertyBinding.setValue setValue].
-    </div>
+		<h3>[method:null bind]( )</h3>
+		<div>
+			Create getter / setter pair for a property in the scene graph. Used internally by
+			[page:PropertyBinding.getValue getValue] and [page:PropertyBinding.setValue setValue].
+		</div>
 
-    <h3>[method:null unbind]( )</h3>
-    <div>
-      Unbind getter / setter pair for a property in the scene graph.
-    </div>
+		<h3>[method:null unbind]( )</h3>
+		<div>
+			Unbind getter / setter pair for a property in the scene graph.
+		</div>
 
-    <h3>[method:Constructor Composite]( targetGroup, path, optionalParsedPath )</h3>
-    <div>
-      Create a new Composite PropertyBinding.
-    </div>
+		<h3>[method:Constructor Composite]( targetGroup, path, optionalParsedPath )</h3>
+		<div>
+			Create a new Composite PropertyBinding.
+		</div>
 
-    <h3>[method:Constructor create]( root, path, parsedPath )</h3>
-    <div>
-      Create a new Composite PropertyBinding (if root is an [page:AnimationObjectGroup]) or PropertyBinding.
-    </div>
+		<h3>[method:Constructor create]( root, path, parsedPath )</h3>
+		<div>
+			Create a new Composite PropertyBinding (if root is an [page:AnimationObjectGroup]) or PropertyBinding.
+		</div>
 
-    <h3>[method:Constructor parseTrackName]( trackName )</h3>
-    <div>
-      Matches strings in the following forms:<br />
-      -- nodeName.property<br />
-      -- nodeName.property[accessor]<br />
-      -- nodeName.material.property[accessor]<br />
-      -- uuid.property[accessor]<br />
-      -- uuid.objectName[objectIndex].propertyName[propertyIndex]<br />
-      -- parentName/nodeName.property<br />
-      -- parentName/parentName/nodeName.property[index]<br />
-      -- .bone[Armature.DEF_cog].position<br />
-      -- scene:helium_balloon_model:helium_balloon_model.position
-    </div>
+		<h3>[method:Constructor parseTrackName]( trackName )</h3>
+		<div>
+			Matches strings in the following forms:<br />
+			-- nodeName.property<br />
+			-- nodeName.property[accessor]<br />
+			-- nodeName.material.property[accessor]<br />
+			-- uuid.property[accessor]<br />
+			-- uuid.objectName[objectIndex].propertyName[propertyIndex]<br />
+			-- parentName/nodeName.property<br />
+			-- parentName/parentName/nodeName.property[index]<br />
+			-- .bone[Armature.DEF_cog].position<br />
+			-- scene:helium_balloon_model:helium_balloon_model.position
+		</div>
 
-    <h3>[method:Constructor findNode]( root, nodeName )</h3>
-    <div>
-      Find a node in a node tree or [page:Skeleton Skeleton].
-    </div>
+		<h3>[method:Constructor findNode]( root, nodeName )</h3>
+		<div>
+			Find a node in a node tree or [page:Skeleton Skeleton].
+		</div>
 
 
 
 
-    <h2>Source</h2>
+		<h2>Source</h2>
 
 
-    [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
-  </body>
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
 </html>

+ 68 - 68
docs/api/animation/PropertyMixer.html

@@ -1,99 +1,99 @@
 <!DOCTYPE html>
 <html lang="en">
-  <head>
-    <meta charset="utf-8" />
-    <base href="../../" />
-    <script src="list.js"></script>
-    <script src="page.js"></script>
-    <link type="text/css" rel="stylesheet" href="page.css" />
-  </head>
-  <body>
-    <h1>[name]</h1>
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		<h1>[name]</h1>
 
-    <div class="desc">
-    Buffered scene graph property that allows weighted accumulation; used internally.
-    </div>
+		<div class="desc">
+		Buffered scene graph property that allows weighted accumulation; used internally.
+		</div>
 
 
-    <h2>Constructor</h2>
+		<h2>Constructor</h2>
 
 
-    <h3>[name]( binding, typeName, valueSize )</h3>
-    <div>
-      -- binding <br />
-      -- typeName <br />
-      -- valueSize <br />
-    </div>
+		<h3>[name]( binding, typeName, valueSize )</h3>
+		<div>
+			-- binding <br />
+			-- typeName <br />
+			-- valueSize <br />
+		</div>
 
 
-    <h2>Properties</h2>
+		<h2>Properties</h2>
 
 
-    <h3>[property:Number binding]</h3>
-    <div>
+		<h3>[property:Number binding]</h3>
+		<div>
 
-    </div>
+		</div>
 
-    <h3>[property:Number buffer]</h3>
-    <div>
-      Buffer with size [page:PropertyMixer valueSize] * 4. <br /><br />
-      This has the layout: [ incoming | accu0 | accu1 | orig ]<br /><br />
-      Interpolators can use .buffer as their .result and the data then goes to 'incoming'.<br />
-      'accu0' and 'accu1' are used frame-interleaved for the cumulative result and
-      are compared to detect changes.<br />
-      'orig' stores the original state of the property.<br />
-    </div>
+		<h3>[property:Number buffer]</h3>
+		<div>
+			Buffer with size [page:PropertyMixer valueSize] * 4. <br /><br />
+			This has the layout: [ incoming | accu0 | accu1 | orig ]<br /><br />
+			Interpolators can use .buffer as their .result and the data then goes to 'incoming'.<br />
+			'accu0' and 'accu1' are used frame-interleaved for the cumulative result and
+			are compared to detect changes.<br />
+			'orig' stores the original state of the property.<br />
+		</div>
 
-    <h3>[property:Number cumulativeWeight]</h3>
-    <div>
-      Default is *0*.
-    </div>
+		<h3>[property:Number cumulativeWeight]</h3>
+		<div>
+			Default is *0*.
+		</div>
 
-    <h3>[property:Number valueSize]</h3>
-    <div>
+		<h3>[property:Number valueSize]</h3>
+		<div>
 
-    </div>
+		</div>
 
-    <h3>[property:Number referenceCount]</h3>
-    <div>
-      Default is *0*.
-    </div>
+		<h3>[property:Number referenceCount]</h3>
+		<div>
+			Default is *0*.
+		</div>
 
-    <h3>[property:Number useCount]</h3>
-    <div>
-      Default is *0*.
-    </div>
+		<h3>[property:Number useCount]</h3>
+		<div>
+			Default is *0*.
+		</div>
 
 
-    <h2>Methods</h2>
+		<h2>Methods</h2>
 
 
-    <h3>[method:null accumulate]( accuIndex, weight )</h3>
-    <div>
-      Accumulate data in [page:PropertyMixer.buffer buffer][accuIndex] 'incoming' region into 'accu[i]'.<br />
+		<h3>[method:null accumulate]( accuIndex, weight )</h3>
+		<div>
+			Accumulate data in [page:PropertyMixer.buffer buffer][accuIndex] 'incoming' region into 'accu[i]'.<br />
 
-      If weight is *0* this does nothing.
-    </div>
+			If weight is *0* this does nothing.
+		</div>
 
-    <h3>[method:null apply]( accuIndex )</h3>
-    <div>
-      Apply the state of [page:PropertyMixer.buffer buffer] 'accu[i]' to the binding when accus differ.
-    </div>
+		<h3>[method:null apply]( accuIndex )</h3>
+		<div>
+			Apply the state of [page:PropertyMixer.buffer buffer] 'accu[i]' to the binding when accus differ.
+		</div>
 
-    <h3>[method:null saveOriginalState]( )</h3>
-    <div>
-      Remember the state of the bound property and copy it to both accus.
-    </div>
+		<h3>[method:null saveOriginalState]( )</h3>
+		<div>
+			Remember the state of the bound property and copy it to both accus.
+		</div>
 
-    <h3>[method:null restoreOriginalState](  )</h3>
-    <div>
-      Apply the state previously taken via 'saveOriginalState' to the binding.
-    </div>
+		<h3>[method:null restoreOriginalState](  )</h3>
+		<div>
+			Apply the state previously taken via 'saveOriginalState' to the binding.
+		</div>
 
 
-    <h2>Source</h2>
+		<h2>Source</h2>
 
 
-    [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
-  </body>
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
 </html>

+ 75 - 75
docs/api/animation/tracks/BooleanKeyframeTrack.html

@@ -1,78 +1,78 @@
 <!DOCTYPE html>
 <html lang="en">
-  <head>
-    <meta charset="utf-8" />
-    <base href="../../../" />
-    <script src="list.js"></script>
-    <script src="page.js"></script>
-    <link type="text/css" rel="stylesheet" href="page.css" />
-  </head>
-  <body>
-
-	[page:KeyframeTrack] &rarr;
-
-    <h1>[name]</h1>
-
-    <div class="desc">
-     A Track of boolean keyframe values.
-    </div>
-
-
-    <h2>Constructor</h2>
-
-
-    <h3>[name]( [page:String name], [page:Array times], [page:Array values] )</h3>
-    <div>
-      [page:String name] - (required) identifier for the KeyframeTrack.<br />
-      [page:Array times] - (required) array of keyframe times.<br />
-      [page:Array values] - values for the keyframes at the times specified.<br />
-    </div>
-    
-
-    <h2>Properties</h2>
-    
-    
-    <div class="desc">
-		See [page:KeyframeTrack] for inherited properties.
-    </div>
-
-    <h3>[property:Constant DefaultInterpolation]</h3>
-    <div>
-    The default interpolation type to use, [page:Animation InterpolateDiscrete].
-    </div>
-
-    <h3>[property:Array ValueBufferType]</h3>
-    <div>
-        A normal Array (no Float32Array in this case, unlike *ValueBufferType* of [page:KeyframeTrack]).
-    </div>
-
-    <h3>[property:String ValueTypeName]</h3>
-    <div>
-        String 'bool'.
-    </div>
-    
-
-    <h2>Methods</h2>
-    
-    
-    <div class="desc">
-		See [page:KeyframeTrack] for inherited methods.
-    </div>
-    
-    <h3>[method:null InterpolantFactoryMethodLinear ]()</h3>
-    <div>
-        The value of this method here is 'undefined', as it does not make sense for discrete properties.
-    </div>
-
-    <h3>[method:null InterpolantFactoryMethodSmooth ]()</h3>
-    <div>
-        The value of this method here is 'undefined', as it does not make sense for discrete properties.
-    </div>
-
-
-    <h2>Source</h2>
-
-
-    [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
-  </body>
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+
+		[page:KeyframeTrack] &rarr;
+
+		<h1>[name]</h1>
+
+		<div class="desc">
+			A Track of boolean keyframe values.
+		</div>
+
+
+		<h2>Constructor</h2>
+
+
+		<h3>[name]( [page:String name], [page:Array times], [page:Array values] )</h3>
+		<div>
+			[page:String name] - (required) identifier for the KeyframeTrack.<br />
+			[page:Array times] - (required) array of keyframe times.<br />
+			[page:Array values] - values for the keyframes at the times specified.<br />
+		</div>
+
+
+		<h2>Properties</h2>
+
+
+		<div class="desc">
+			See [page:KeyframeTrack] for inherited properties.
+		</div>
+
+		<h3>[property:Constant DefaultInterpolation]</h3>
+		<div>
+			The default interpolation type to use, [page:Animation InterpolateDiscrete].
+		</div>
+
+		<h3>[property:Array ValueBufferType]</h3>
+		<div>
+			A normal Array (no Float32Array in this case, unlike *ValueBufferType* of [page:KeyframeTrack]).
+		</div>
+
+		<h3>[property:String ValueTypeName]</h3>
+		<div>
+			String 'bool'.
+		</div>
+
+
+		<h2>Methods</h2>
+
+
+		<div class="desc">
+			See [page:KeyframeTrack] for inherited methods.
+		</div>
+
+		<h3>[method:null InterpolantFactoryMethodLinear ]()</h3>
+		<div>
+			The value of this method here is 'undefined', as it does not make sense for discrete properties.
+		</div>
+
+		<h3>[method:null InterpolantFactoryMethodSmooth ]()</h3>
+		<div>
+			The value of this method here is 'undefined', as it does not make sense for discrete properties.
+		</div>
+
+
+		<h2>Source</h2>
+
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
 </html>

+ 59 - 59
docs/api/animation/tracks/ColorKeyframeTrack.html

@@ -1,62 +1,62 @@
 <!DOCTYPE html>
 <html lang="en">
-  <head>
-    <meta charset="utf-8" />
-    <base href="../../../" />
-    <script src="list.js"></script>
-    <script src="page.js"></script>
-    <link type="text/css" rel="stylesheet" href="page.css" />
-  </head>
-  <body>
-
-    [page:KeyframeTrack] &rarr;
-
-    <h1>[name]</h1>
-
-    <div class="desc">
-        A Track of keyframe values that represent color changes.<br /><br />
-        The very basic implementation of this subclass has nothing special yet. However, this is the place 
-        for color space parameterization.
-    </div>
-
-
-    <h2>Constructor</h2>
-
-
-    <h3>[name]( [page:String name], [page:Array times], [page:Array values] )</h3>
-    <div>
-        [page:String name] - (required) identifier for the KeyframeTrack.<br />
-        [page:Array times] - (required) array of keyframe times.<br />
-        [page:Array values] - values for the keyframes at the times specified.<br />
-        [page:Constant interpolation] - the type of interpolation to use. See 
-        [page:Animation Animation Constants] for possible values. Default is 
-        [page:Animation InterpolateLinear].
-    </div>
-    
-
-    <h2>Properties</h2>
-    
-    
-    <div class="desc">
-		See [page:KeyframeTrack] for inherited properties.
-    </div>
-    
-    <h3>[property:String ValueTypeName]</h3>
-    <div>
-        String 'color'.
-    </div>
-    
-
-    <h2>Methods</h2>
-    
-    
-    <div class="desc">
-		See [page:KeyframeTrack] for inherited methods.
-    </div>
-
-    <h2>Source</h2>
-
-
-    [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
-  </body>
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+
+		[page:KeyframeTrack] &rarr;
+
+		<h1>[name]</h1>
+
+		<div class="desc">
+			A Track of keyframe values that represent color changes.<br /><br />
+			The very basic implementation of this subclass has nothing special yet. However, this is the place
+			for color space parameterization.
+		</div>
+
+
+		<h2>Constructor</h2>
+
+
+		<h3>[name]( [page:String name], [page:Array times], [page:Array values] )</h3>
+		<div>
+			[page:String name] - (required) identifier for the KeyframeTrack.<br />
+			[page:Array times] - (required) array of keyframe times.<br />
+			[page:Array values] - values for the keyframes at the times specified.<br />
+			[page:Constant interpolation] - the type of interpolation to use. See
+			[page:Animation Animation Constants] for possible values. Default is
+			[page:Animation InterpolateLinear].
+		</div>
+
+
+		<h2>Properties</h2>
+
+
+		<div class="desc">
+			See [page:KeyframeTrack] for inherited properties.
+		</div>
+
+		<h3>[property:String ValueTypeName]</h3>
+		<div>
+			String 'color'.
+		</div>
+
+
+		<h2>Methods</h2>
+
+
+		<div class="desc">
+			See [page:KeyframeTrack] for inherited methods.
+		</div>
+
+		<h2>Source</h2>
+
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
 </html>

+ 59 - 59
docs/api/animation/tracks/NumberKeyframeTrack.html

@@ -1,62 +1,62 @@
 <!DOCTYPE html>
 <html lang="en">
-  <head>
-    <meta charset="utf-8" />
-    <base href="../../../" />
-    <script src="list.js"></script>
-    <script src="page.js"></script>
-    <link type="text/css" rel="stylesheet" href="page.css" />
-  </head>
-  <body>
-
-    [page:KeyframeTrack] &rarr;
-
-    <h1>[name]</h1>
-
-    <div class="desc">
-        A Track of numeric keyframe values.
-    </div>
-
-
-    <h2>Constructor</h2>
-
-
-    <h3>[name]( [page:String name], [page:Array times], [page:Array values] )</h3>
-    <div>
-        [page:String name] - (required) identifier for the KeyframeTrack.<br />
-        [page:Array times] - (required) array of keyframe times.<br />
-        [page:Array values] - values for the keyframes at the times specified.<br />
-        [page:Constant interpolation] - the type of interpolation to use. See 
-        [page:Animation Animation Constants] for possible values. Default is 
-        [page:Animation InterpolateLinear].
-    </div>
-    
-
-    <h2>Properties</h2>
-    
-    
-    <div class="desc">
-		See [page:KeyframeTrack] for inherited properties.
-    </div>
-    
-
-    <h3>[property:String ValueTypeName]</h3>
-    <div>
-        String 'number'.
-    </div>
-    
-
-    <h2>Methods</h2>
-    
-    
-    <div class="desc">
-		See [page:KeyframeTrack] for inherited methods.
-    </div>
-    
-
-    <h2>Source</h2>
-
-
-    [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
-  </body>
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+
+		[page:KeyframeTrack] &rarr;
+
+		<h1>[name]</h1>
+
+		<div class="desc">
+			A Track of numeric keyframe values.
+		</div>
+
+
+		<h2>Constructor</h2>
+
+
+		<h3>[name]( [page:String name], [page:Array times], [page:Array values] )</h3>
+		<div>
+			[page:String name] - (required) identifier for the KeyframeTrack.<br />
+			[page:Array times] - (required) array of keyframe times.<br />
+			[page:Array values] - values for the keyframes at the times specified.<br />
+			[page:Constant interpolation] - the type of interpolation to use. See
+			[page:Animation Animation Constants] for possible values. Default is
+			[page:Animation InterpolateLinear].
+		</div>
+
+
+		<h2>Properties</h2>
+
+
+		<div class="desc">
+			See [page:KeyframeTrack] for inherited properties.
+		</div>
+
+
+		<h3>[property:String ValueTypeName]</h3>
+		<div>
+			String 'number'.
+		</div>
+
+
+		<h2>Methods</h2>
+
+
+		<div class="desc">
+			See [page:KeyframeTrack] for inherited methods.
+		</div>
+
+
+		<h2>Source</h2>
+
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
 </html>

+ 53 - 53
docs/api/animation/tracks/QuaternionKeyframeTrack.html

@@ -1,73 +1,73 @@
 <!DOCTYPE html>
 <html lang="en">
-  <head>
-    <meta charset="utf-8" />
-    <base href="../../../" />
-    <script src="list.js"></script>
-    <script src="page.js"></script>
-    <link type="text/css" rel="stylesheet" href="page.css" />
-  </head>
-  <body>
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
 
-    [page:KeyframeTrack] &rarr;
+		[page:KeyframeTrack] &rarr;
 
-    <h1>[name]</h1>
+		<h1>[name]</h1>
 
-    <div class="desc">
-        A Track of quaternion keyframe values.
-    </div>
+		<div class="desc">
+			A Track of quaternion keyframe values.
+		</div>
 
 
-    <h2>Constructor</h2>
+		<h2>Constructor</h2>
 
 
-    <h3>[name]( [page:String name], [page:Array times], [page:Array values] )</h3>
-    <div>
-        [page:String name] (required) identifier for the KeyframeTrack.<br />
-        [page:Array times] (required) array of keyframe times.<br />
-        [page:Array values] values for the keyframes at the times specified.<br />
-        [page:Constant interpolation] the type of interpolation to use. See 
-        [page:Animation Animation Constants] for possible values. Default is 
-        [page:Animation InterpolateLinear].
-    </div>
-    
+		<h3>[name]( [page:String name], [page:Array times], [page:Array values] )</h3>
+		<div>
+			[page:String name] (required) identifier for the KeyframeTrack.<br />
+			[page:Array times] (required) array of keyframe times.<br />
+			[page:Array values] values for the keyframes at the times specified.<br />
+			[page:Constant interpolation] the type of interpolation to use. See
+			[page:Animation Animation Constants] for possible values. Default is
+			[page:Animation InterpolateLinear].
+		</div>
 
-    <h2>Properties</h2>
-    
 
-    <div class="desc">
-    	See [page:KeyframeTrack] for inherited properties.
-    </div>
+		<h2>Properties</h2>
 
-    <h3>[property:Constant DefaultInterpolation]</h3>
-    <div>
-        The default interpolation type to use, [page:Animation InterpolateLinear].
-    </div>
 
-    <h3>[property:String ValueTypeName]</h3>
-    <div>
-        String 'quaternion'.
-    </div>
+		<div class="desc">
+			See [page:KeyframeTrack] for inherited properties.
+		</div>
 
+		<h3>[property:Constant DefaultInterpolation]</h3>
+		<div>
+			The default interpolation type to use, [page:Animation InterpolateLinear].
+		</div>
 
-    <h2>Methods</h2>
-    
-    
-    <div class="desc">
-		See [page:KeyframeTrack] for inherited methods.
-    </div>    
+		<h3>[property:String ValueTypeName]</h3>
+		<div>
+			String 'quaternion'.
+		</div>
 
-    <h3>[method:null InterpolantFactoryMethodLinear]()</h3>
-    <div>
-        Returns a new [page:QuaternionLinearInterpolant QuaternionLinearInterpolant] based on the 
-        [page:KeyframeTrack.values values], [page:KeyframeTrack.times times] and 
-        [page:KeyframeTrack.valueSize valueSize] of the keyframes.
-    </div>
 
+		<h2>Methods</h2>
 
-    <h2>Source</h2>
-    
 
-    [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
-  </body>
+		<div class="desc">
+			See [page:KeyframeTrack] for inherited methods.
+		</div>
+
+		<h3>[method:null InterpolantFactoryMethodLinear]()</h3>
+		<div>
+			Returns a new [page:QuaternionLinearInterpolant QuaternionLinearInterpolant] based on the 
+			[page:KeyframeTrack.values values], [page:KeyframeTrack.times times] and 
+			[page:KeyframeTrack.valueSize valueSize] of the keyframes.
+		</div>
+
+
+		<h2>Source</h2>
+
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
 </html>

+ 58 - 58
docs/api/animation/tracks/StringKeyframeTrack.html

@@ -1,81 +1,81 @@
 <!DOCTYPE html>
 <html lang="en">
-  <head>
-    <meta charset="utf-8" />
-    <base href="../../../" />
-    <script src="list.js"></script>
-    <script src="page.js"></script>
-    <link type="text/css" rel="stylesheet" href="page.css" />
-  </head>
-  <body>
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
 
-	[page:KeyframeTrack] &rarr;
+		[page:KeyframeTrack] &rarr;
 
-    <h1>[name]</h1>
+		<h1>[name]</h1>
 
-    <div class="desc">
-        A Track of string keyframe values.
-    </div>
+		<div class="desc">
+			A Track of string keyframe values.
+		</div>
 
 
-    <h2>Constructor</h2>
+		<h2>Constructor</h2>
 
 
-    <h3>[name]( [page:String name], [page:Array times], [page:Array values] )</h3>
-    <div>
-        [page:String name] - (required) identifier for the KeyframeTrack.<br />
-        [page:Array times] - (required) array of keyframe times.<br />
-        [page:Array values] - values for the keyframes at the times specified.<br />
-        [page:Constant interpolation] - the type of interpolation to use. See 
-        [page:Animation Animation Constants] for possible values. Default is 
-        [page:Animation InterpolateDiscrete].
-    </div>
-    
+		<h3>[name]( [page:String name], [page:Array times], [page:Array values] )</h3>
+		<div>
+			[page:String name] - (required) identifier for the KeyframeTrack.<br />
+			[page:Array times] - (required) array of keyframe times.<br />
+			[page:Array values] - values for the keyframes at the times specified.<br />
+			[page:Constant interpolation] - the type of interpolation to use. See
+			[page:Animation Animation Constants] for possible values. Default is
+			[page:Animation InterpolateDiscrete].
+		</div>
 
-    <h2>Properties</h2>
-    
 
-    <div class="desc">
-    	See [page:KeyframeTrack] for inherited properties.
-    </div>    
+		<h2>Properties</h2>
 
-    <h3>[property:Constant DefaultInterpolation]</h3>
-    <div>
-        The default interpolation type to use, [page:Animation InterpolateDiscrete].
-    </div>
 
-    <h3>[property:Array ValueBufferType]</h3>
-    <div>
-        A normal Array (no Float32Array in this case, unlike *ValueBufferType* of [page:KeyframeTrack]).
-    </div>
+		<div class="desc">
+			See [page:KeyframeTrack] for inherited properties.
+		</div>
 
-    <h3>[property:String ValueTypeName]</h3>
-    <div>
-        String 'string'.
-    </div>
+		<h3>[property:Constant DefaultInterpolation]</h3>
+		<div>
+			The default interpolation type to use, [page:Animation InterpolateDiscrete].
+		</div>
 
+		<h3>[property:Array ValueBufferType]</h3>
+		<div>
+			A normal Array (no Float32Array in this case, unlike *ValueBufferType* of [page:KeyframeTrack]).
+		</div>
 
-    <h2>Methods</h2>
-    
+		<h3>[property:String ValueTypeName]</h3>
+		<div>
+			String 'string'.
+		</div>
 
-    <div class="desc">
-		See [page:KeyframeTrack] for inherited methods.
-    </div>    
 
-    <h3>[method:null InterpolantFactoryMethodLinear]()</h3>
-    <div>
-      The value of this method here is 'undefined', as it does not make sense for discrete properties.
-    </div>
+		<h2>Methods</h2>
 
-    <h3>[method:null InterpolantFactoryMethodSmooth]()</h3>
-    <div>
-      The value of this method here is 'undefined', as it does not make sense for discrete properties.
-    </div>
-    
 
-    <h2>Source</h2>
+		<div class="desc">
+			See [page:KeyframeTrack] for inherited methods.
+		</div>
 
+		<h3>[method:null InterpolantFactoryMethodLinear]()</h3>
+		<div>
+		  The value of this method here is 'undefined', as it does not make sense for discrete properties.
+		</div>
 
-    [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
-  </body>
+		<h3>[method:null InterpolantFactoryMethodSmooth]()</h3>
+		<div>
+		  The value of this method here is 'undefined', as it does not make sense for discrete properties.
+		</div>
+
+
+		<h2>Source</h2>
+
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
 </html>

+ 44 - 44
docs/api/animation/tracks/VectorKeyframeTrack.html

@@ -1,61 +1,61 @@
 <!DOCTYPE html>
 <html lang="en">
-  <head>
-    <meta charset="utf-8" />
-    <base href="../../../" />
-    <script src="list.js"></script>
-    <script src="page.js"></script>
-    <link type="text/css" rel="stylesheet" href="page.css" />
-  </head>
-  <body>
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
 
-    [page:KeyframeTrack] &rarr;
+		[page:KeyframeTrack] &rarr;
 
-    <h1>[name]</h1>
+		<h1>[name]</h1>
 
-    <div class="desc">
-        A Track of vector keyframe values.
-    </div>
+		<div class="desc">
+			A Track of vector keyframe values.
+		</div>
 
 
-    <h2>Constructor</h2>
+		<h2>Constructor</h2>
 
 
-    <h3>[name]( [page:String name], [page:Array times], [page:Array values] )</h3>
-    <div>
-        [page:String name] - (required) identifier for the KeyframeTrack.<br />
-        [page:Array times] - (required) array of keyframe times.<br />
-        [page:Array values] - values for the keyframes at the times specified.<br />
-        [page:Constant interpolation] - the type of interpolation to use. See 
-        [page:Animation Animation Constants] for possible values. Default is 
-        [page:Animation InterpolateLinear].
-    </div>
-    
+		<h3>[name]( [page:String name], [page:Array times], [page:Array values] )</h3>
+		<div>
+			[page:String name] - (required) identifier for the KeyframeTrack.<br />
+			[page:Array times] - (required) array of keyframe times.<br />
+			[page:Array values] - values for the keyframes at the times specified.<br />
+			[page:Constant interpolation] - the type of interpolation to use. See 
+			[page:Animation Animation Constants] for possible values. Default is 
+			[page:Animation InterpolateLinear].
+		</div>
 
-    <h2>Properties</h2>
-    
 
-    <div class="desc">
-    	See [page:KeyframeTrack] for inherited properties.
-    </div>  
+		<h2>Properties</h2>
 
-    <h3>[property:String ValueTypeName]</h3>
-    <div>
-        String 'vector'.
-    </div>
-    
 
-    <h2>Methods</h2>
-    
-    
-    <div class="desc">
-		See [page:KeyframeTrack] for inherited methods.
-    </div>
-    
+		<div class="desc">
+			See [page:KeyframeTrack] for inherited properties.
+		</div>
 
-    <h2>Source</h2>
+		<h3>[property:String ValueTypeName]</h3>
+		<div>
+			String 'vector'.
+		</div>
 
 
-    [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
-  </body>
+		<h2>Methods</h2>
+
+
+		<div class="desc">
+			See [page:KeyframeTrack] for inherited methods.
+		</div>
+
+
+		<h2>Source</h2>
+
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
 </html>

+ 7 - 7
docs/api/core/BufferGeometry.html

@@ -138,12 +138,12 @@
 		<h3>[property:Array groups]</h3>
 		<div>
 			Split the geometry into groups, each of which will be rendered in a separate WebGL draw call.
-			This allows a [page:MultiMaterial] to be used with the bufferGeometry.<br /><br />
+			This allows an array of materials to be used with the bufferGeometry.<br /><br />
 
 			Each group is an object of the form:
 			<code>{ start: Integer, count: Integer, materialIndex: Integer }</code>
 			where start specifies the index of the first vertex in this draw call, count specifies
-			how many vertices are included, and materialIndex specifies the [page:MultiMaterial] index to use.<br /><br />
+			how many vertices are included, and materialIndex specifies the material array index to use.<br /><br />
 
 			Use [page:.addGroup] to add groups, rather than modifying this array directly.
 		</div>
@@ -329,11 +329,11 @@
 		<div>
 		Translate the geometry. This is typically done as a one time operation, and not during a loop.
     Use [page:Object3D.position] for typical real-time mesh translation.
-		</div>
-
-		<h3>[method:BufferGeometry updateFromObject] ( [page:Object3D object] )</h3>
-		<div>Updates the attributes for this BufferGeometry from an [page:Object3D].</div>
-
+		</div>
+
+		<h3>[method:BufferGeometry updateFromObject] ( [page:Object3D object] )</h3>
+		<div>Updates the attributes for this BufferGeometry from an [page:Object3D].</div>
+
 
 
 

+ 133 - 133
docs/api/core/Face3.html

@@ -1,134 +1,134 @@
-<!DOCTYPE html>
-<html lang="en">
-	<head>
+<!DOCTYPE html>
+<html lang="en">
+	<head>
 		<meta charset="utf-8" />
-		<base href="../../" />
-		<script src="list.js"></script>
-		<script src="page.js"></script>
-		<link type="text/css" rel="stylesheet" href="page.css" />
-	</head>
-	<body>
-		<h1>[name]</h1>
-
-		<div class="desc">
-		Triangular face used in [page:Geometry]. These are created automatically for all
-		standard geometry types, however if you are building a custom geometry you will have to
-		create them manually.
-		</div>
-
-
-		<h2>Examples</h2>
-
-		<div>[example:misc_ubiquity_test ubiquity / test ]</div>
-		<div>[example:svg_sandbox svg / sandbox ]</div>
-		<div>[example:webgl_exporter_obj WebGL / exporter / obj ]</div>
-		<div>[example:webgl_shaders_vector WebGL / shaders / vector ]</div>
-
-
-		<code>
-var material = new THREE.MeshStandardMaterial( { color : 0x00cc00 } );
-
-//create a triangular geometry
-var geometry = new THREE.Geometry();
-geometry.vertices.push( new THREE.Vector3( -50, -50, 0 ) );
-geometry.vertices.push( new THREE.Vector3(  50, -50, 0 ) );
-geometry.vertices.push( new THREE.Vector3(  50,  50, 0 ) );
-
-//create a new face using vertices 0, 1, 2
-var normal = new THREE.Vector3( 0, 1, 0 ); //optional
-var color = new THREE.Color( 0xffaa00 ); //optional
-var materialIndex = 0; //optional
-var face = new THREE.Face3( 0, 1, 2, normal, color, materialIndex );
-
-//add the face to the geometry's faces array
-geometry.faces.push( face );
-
-//the face normals and vertex normals can be calculated automatically if not supplied above
-geometry.computeFaceNormals();
-geometry.computeVertexNormals();
-
-scene.add( new THREE.Mesh( geometry, material ) );
-	</code>
-
-
-		<h2>Constructor</h2>
-
-		<h3>[name]( [page:Integer a], [page:Integer b], [page:Integer c], [page:Vector3 normal], [page:Color color], [page:Integer materialIndex] )</h3>
-		<div>
-		a — Vertex A index.<br />
-		b — Vertex B index.<br />
-		c — Vertex C index.<br /><br />
-
-		normal — (optional) Face normal ([page:Vector3 Vector3]) or array of vertex normals.
-		If a single vector is passed in, this sets [page:.normal], otherwise if an array of three
-		vectors is passed in this sets [page:.vertexNormals]<br /><br />
-
-		color — (optional) Face [page:Color color] or array of vertex [page:Color colors].
-		If a single vector is passed in, this sets [page:.color], otherwise if an array of three
-		vectors is passed in this sets [page:.vertexColors]<br /><br />
-
-		materialIndex — (optional) which index of a [page:MultiMaterial] to associate
-		with the face.
-		</div>
-
-		<h2>Properties</h2>
-
-		<h3>[property:Integer a]</h3>
-		<div>
-		Vertex A index.
-		</div>
-
-		<h3>[property:Integer b]</h3>
-		<div>
-		Vertex B index.
-		</div>
-
-		<h3>[property:Integer c]</h3>
-		<div>
-		Vertex C index.
-		</div>
-
-		<h3>[property:Vector3 normal]</h3>
-		<div>
-		Face normal - vector showing the direction of the Face3. If calculated automatically
-		(using [page:Geometry.computeFaceNormals]), this is the normalized cross product of two edges of the
-		triangle. Default is *(0, 0, 0)*.
-		</div>
-
-		<h3>[property:Color color]</h3>
-		<div>
-		Face color - for this to be used a material's [page:Material.vertexColors vertexColors] property
-		must be set to [page:Materials THREE.FaceColors].
-		</div>
-
-		<h3>[property:Array vertexNormals]</h3>
-		<div>
-		Array of 3 [page:Vector3 vertex normals].
-		</div>
-
-		<h3>[property:Array vertexColors]</h3>
-		<div>
-		Array of 3 vertex colors - for these to be used a material's [page:Material.vertexColors vertexColors] property
-		must be set to [page:Materials THREE.VertexColors].
-		</div>
-
-
-		<h3>[property:Integer materialIndex]</h3>
-		<div>
-		Material index (points to [page:MultiMaterial MultiMaterial.materials]). Default is *0*.
-		</div>
-
-		<h2>Methods</h2>
-
-		<h3>[method:Face3 clone]()</h3>
-		<div>Creates a new clone of the Face3 object.</div>
-
-		<h3>[method:Face3 copy]( [page:Face3 face3] )</h3>
-		<div>Copy the paramaters of another Face3 into this.</div>
-
-
-		<h2>Source</h2>
-
-		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
-	</body>
-</html>
+		<base href="../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		<h1>[name]</h1>
+
+		<div class="desc">
+		Triangular face used in [page:Geometry]. These are created automatically for all
+		standard geometry types, however if you are building a custom geometry you will have to
+		create them manually.
+		</div>
+
+
+		<h2>Examples</h2>
+
+		<div>[example:misc_ubiquity_test ubiquity / test ]</div>
+		<div>[example:svg_sandbox svg / sandbox ]</div>
+		<div>[example:webgl_exporter_obj WebGL / exporter / obj ]</div>
+		<div>[example:webgl_shaders_vector WebGL / shaders / vector ]</div>
+
+
+		<code>
+var material = new THREE.MeshStandardMaterial( { color : 0x00cc00 } );
+
+//create a triangular geometry
+var geometry = new THREE.Geometry();
+geometry.vertices.push( new THREE.Vector3( -50, -50, 0 ) );
+geometry.vertices.push( new THREE.Vector3(  50, -50, 0 ) );
+geometry.vertices.push( new THREE.Vector3(  50,  50, 0 ) );
+
+//create a new face using vertices 0, 1, 2
+var normal = new THREE.Vector3( 0, 1, 0 ); //optional
+var color = new THREE.Color( 0xffaa00 ); //optional
+var materialIndex = 0; //optional
+var face = new THREE.Face3( 0, 1, 2, normal, color, materialIndex );
+
+//add the face to the geometry's faces array
+geometry.faces.push( face );
+
+//the face normals and vertex normals can be calculated automatically if not supplied above
+geometry.computeFaceNormals();
+geometry.computeVertexNormals();
+
+scene.add( new THREE.Mesh( geometry, material ) );
+	</code>
+
+
+		<h2>Constructor</h2>
+
+		<h3>[name]( [page:Integer a], [page:Integer b], [page:Integer c], [page:Vector3 normal], [page:Color color], [page:Integer materialIndex] )</h3>
+		<div>
+		a — Vertex A index.<br />
+		b — Vertex B index.<br />
+		c — Vertex C index.<br /><br />
+
+		normal — (optional) Face normal ([page:Vector3 Vector3]) or array of vertex normals.
+		If a single vector is passed in, this sets [page:.normal], otherwise if an array of three
+		vectors is passed in this sets [page:.vertexNormals]<br /><br />
+
+		color — (optional) Face [page:Color color] or array of vertex [page:Color colors].
+		If a single vector is passed in, this sets [page:.color], otherwise if an array of three
+		vectors is passed in this sets [page:.vertexColors]<br /><br />
+
+		materialIndex — (optional) which index of an array of materials to associate
+		with the face.
+		</div>
+
+		<h2>Properties</h2>
+
+		<h3>[property:Integer a]</h3>
+		<div>
+		Vertex A index.
+		</div>
+
+		<h3>[property:Integer b]</h3>
+		<div>
+		Vertex B index.
+		</div>
+
+		<h3>[property:Integer c]</h3>
+		<div>
+		Vertex C index.
+		</div>
+
+		<h3>[property:Vector3 normal]</h3>
+		<div>
+		Face normal - vector showing the direction of the Face3. If calculated automatically
+		(using [page:Geometry.computeFaceNormals]), this is the normalized cross product of two edges of the
+		triangle. Default is *(0, 0, 0)*.
+		</div>
+
+		<h3>[property:Color color]</h3>
+		<div>
+		Face color - for this to be used a material's [page:Material.vertexColors vertexColors] property
+		must be set to [page:Materials THREE.FaceColors].
+		</div>
+
+		<h3>[property:Array vertexNormals]</h3>
+		<div>
+		Array of 3 [page:Vector3 vertex normals].
+		</div>
+
+		<h3>[property:Array vertexColors]</h3>
+		<div>
+		Array of 3 vertex colors - for these to be used a material's [page:Material.vertexColors vertexColors] property
+		must be set to [page:Materials THREE.VertexColors].
+		</div>
+
+
+		<h3>[property:Integer materialIndex]</h3>
+		<div>
+		Material index (points to an index in the associated array of materials). Default is *0*.
+		</div>
+
+		<h2>Methods</h2>
+
+		<h3>[method:Face3 clone]()</h3>
+		<div>Creates a new clone of the Face3 object.</div>
+
+		<h3>[method:Face3 copy]( [page:Face3 face3] )</h3>
+		<div>Copy the paramaters of another Face3 into this.</div>
+
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
+</html>

+ 7 - 1
docs/api/core/Object3D.html

@@ -86,7 +86,13 @@
 		<div>Optional name of the object (doesn't need to be unique). Default is an empty string.</div>
 
 		<h3>[property:Matrix3 normalMatrix]</h3>
-		<div>This is passed to the shader and used to calculate lighting for the object.</div>
+		<div>
+		This is passed to the shader and used to calculate lighting for the object. It is the transpose of the inverse of the upper left 3x3 sub-matrix of this object's modelViewMatrix.<br /><br />
+
+		The reason for this special matrix is that simply using the modelViewMatrix could result in a non-unit length of normals (on scaling) or in a non-perpendicular direction (on non-uniform scaling).<br /><br />
+
+		On the other hand the translation part of the modelViewMatrix is not relevant for the calculation of normals. Thus a Matrix3 is sufficient.
+		</div>
 
 		<h3>[property:function onAfterRender]</h3>
 		<div>

+ 4 - 1
docs/api/deprecated/DeprecatedList.html

@@ -411,7 +411,10 @@
 		</div>
 
 		<h3>[page:MeshFaceMaterial]</h3>
-		<div>MeshFaceMaterial has been removed. Use [page:MultiMaterial] instead.</div>
+		<div>MeshFaceMaterial has been removed. Use an array of materials instead.</div>
+
+		<h3>[page:MultiMaterial]</h3>
+		<div>MultiMaterial has been removed. Use an array of materials instead.</div>
 
 		<h3>[page:MeshPhongMaterial]</h3>
 		<div>MeshPhongMaterial.metal has been removed. Use [page:MeshStandardMaterial] instead.</div>

+ 1 - 1
docs/api/extras/SceneUtils.html

@@ -22,7 +22,7 @@
 		materials -- The materials for the object.
 		</div>
 		<div>
-		Creates a new Group that contains a new mesh for each material defined in materials. Beware that this is not the same as MultiMaterial which defines multiple material for 1 mesh.<br />
+		Creates a new Group that contains a new mesh for each material defined in materials. Beware that this is not the same as an array of materials which defines multiple materials for 1 mesh.<br />
 		This is mostly useful for objects that need both a material and a wireframe implementation.
 		</div>
 

+ 21 - 20
docs/api/extras/core/Curve.html

@@ -11,14 +11,10 @@
 		<h1>[name]</h1>
 
 		<div class="desc">
-		An abstract base class for creating a curve object that contains methods for interpolation.
-		For an array of Curves see [page:CurvePath].
+		An abstract base class for creating a [name] object that contains methods for interpolation.
+		For an array of [name]s see [page:CurvePath].
 		</div>
 
-		<h2>Examples</h2>
-
-		<h3>[example:webgl_geometry_extrude_splines geometry / extrude / splines ]</h3>
-
 		<h2>Constructor</h2>
 
 
@@ -27,26 +23,31 @@
 		This constructor creates a new [name].
 		</div>
 
+		<h2>Properties</h2>
+
+		<h3>[property:Integer arcLengthDivisions]</h3>
+		<div>This value determines the amount of divisions when calculating the cumulative segment lengths of a curve via [page:.getLengths].
+			To ensure precision when using methods like [page:.getSpacedPoints], it is recommended to increase [page:.arcLengthDivisions] if the curve is very large. Default is 200.</div>
 
 		<h2>Methods</h2>
 
-		<h3>[method:Vector getPoint]( [page:Number t] )</h3>
-		<div>Returns a vector for point t of the curve where t is between 0 and 1. Must be implemented in the extending class.</div>
+		<h3>[method:Vector getPoint]( [page:Float t] )</h3>
+		<div>Returns a vector for point t of the curve where t is between 0 and 1. Must be implemented in the extending curve.</div>
 
-		<h3>[method:Vector getPointAt]( [page:Number u] )</h3>
+		<h3>[method:Vector getPointAt]( [page:Float u] )</h3>
 		<div>
 			Returns a vector for point at a relative position in curve according to arc length.
 			u is in the range [0, 1].
 		</div>
 
-		<h3>[method:Array getPoints]( [page:integer divisions] )</h3>
+		<h3>[method:Array getPoints]( [page:Integer divisions] )</h3>
 		<div>
 			divisions -- number of pieces to divide the curve into. Default is *5*.<br /><br />
 
 			Returns a set of divisions + 1 points using getPoint( t ).
 		</div>
 
-		<h3>[method:Array getSpacedPoints]( divisions )</h3>
+		<h3>[method:Array getSpacedPoints]( [page:Integer divisions] )</h3>
 		<div>
 			divisions -- number of pieces to divide the curve into. Default is *5*.<br /><br />
 
@@ -56,33 +57,33 @@
 		<h3>[method:Float getLength]()</h3>
 		<div>Get total curve arc length.</div>
 
-		<h3>[method:Array getLengths]( divisions )</h3>
+		<h3>[method:Array getLengths]( [page:Integer divisions] )</h3>
 		<div>Get list of cumulative segment lengths.</div>
 
 		<h3>[method:null updateArcLengths]()</h3>
 		<div>Update the cumlative segment distance cache.</div>
 
-		<h3>[method:Float getUtoTmapping]( [page:Number u], distance )</h3>
+		<h3>[method:Float getUtoTmapping]( [page:Float u], [page:Float distance] )</h3>
 		<div>
-			Given u in the range ( 0 .. 1 ), returns [page:Number t] also in the range ( 0 .. 1 ).
+			Given u in the range ( 0 .. 1 ), returns [page:Float t] also in the range ( 0 .. 1 ).
 			u and t can then be used to give you points which are equidistant from the ends of the curve,
 			using [page:.getPoint].
 		 </div>
 
-		<h3>[method:Vector getTangent]( [page:Number t] )</h3>
+		<h3>[method:Vector getTangent]( [page:Float t] )</h3>
 		<div>
-			Returns a unit vector tangent at t. If the subclassed curve do not implement its
-			tangent derivation, 2 points a small delta apart will be used to find its gradient
-			which seems to give a reasonable approximation
+			Returns a unit vector tangent at t. If the derived curve does not implement its
+			tangent derivation, two points a small delta apart will be used to find its gradient
+			which seems to give a reasonable approximation.
 		</div>
 
-		<h3>[method:Vector getTangentAt]( [page:Number u] )</h3>
+		<h3>[method:Vector getTangentAt]( [page:Float u] )</h3>
 		<div>
 			Returns tangent at a point which is equidistant to the ends of the curve from the
 			point given in [page:.getTangent].
 		</div>
 
-		<h3>[method:Object computeFrenetFrames]( segments, closed )</h3>
+		<h3>[method:Object computeFrenetFrames]( [page:Integer segments], [page:Boolean closed] )</h3>
 		<div>
 		Generates the Frenet Frames. Used in geometries like [page:TubeGeometry] or [page:ExtrudeGeometry].
 		</div>

+ 3 - 1
docs/api/geometries/TubeBufferGeometry.html

@@ -35,7 +35,9 @@
 		<h2>Example</h2>
 
 		<code>
-		function CustomSinCurve( scale ){
+		function CustomSinCurve( scale ) {
+
+			THREE.Curve.call( this );
 
 			this.scale = ( scale === undefined ) ? 1 : scale;
 

+ 3 - 1
docs/api/geometries/TubeGeometry.html

@@ -35,7 +35,9 @@
 		<h2>Example</h2>
 
 		<code>
-		function CustomSinCurve( scale ){
+		function CustomSinCurve( scale ) {
+
+			THREE.Curve.call( this );
 
 			this.scale = ( scale === undefined ) ? 1 : scale;
 

+ 10 - 3
docs/api/helpers/BoxHelper.html

@@ -54,10 +54,17 @@
 		<h2>Methods</h2>
 		<div>See the base [page:LineSegments] class for common methods.</div>
 
-		<h3>[method:null update]( [page:Object3D object] )</h3>
+		<h3>[method:null update]()</h3>
 		<div>
-			Updates the helper's geometry to match the dimensions of the
-		 	of the passed object, including any children. See [page:Box3.setFromObject].
+			Updates the helper's geometry to match the dimensions
+			of the object, including any children. See [page:Box3.setFromObject].
+		</div>
+
+		<h3>[method:BoxHelper setFromObject]( [page:Object3D object] )</h3>
+		<div>
+			[page:Object3D object] - [page:Object3D] to create the helper of.<br /><br />
+
+			Updates the wireframe box for the passed object.
 		</div>
 
 		<h2>Source</h2>

+ 3 - 3
docs/api/lights/RectAreaLight.html

@@ -35,13 +35,13 @@
 var width = 2;
 var height = 10;
 var rectLight = new THREE.RectAreaLight( 0xffffff, undefined,  width, height );
-rectLight.matrixAutoUpdate = true;
 rectLight.intensity = 70.0;
 rectLight.position.set( 5, 5, 0 );
+scene.add( rectLight )
+
 rectLightHelper = new THREE.RectAreaLightHelper( rectLight );
-rectLight.add( rectLightHelper );
+scene.add( rectLightHelper );
 
-scene.add(rectLight)
 			</code>
 		</div>
 

+ 6 - 1
docs/api/loaders/JSONLoader.html

@@ -28,13 +28,18 @@
 
 		// load a resource
 		loader.load(
+
 			// resource URL
 			'models/animated/monster/monster.js',
+
 			// Function when resource is loaded
 			function ( geometry, materials ) {
-				var material = new THREE.MultiMaterial( materials );
+
+				var material = materials[ 0 ];
 				var object = new THREE.Mesh( geometry, material );
+
 				scene.add( object );
+
 			}
 		);
 		</code>

+ 231 - 231
docs/api/loaders/ObjectLoader.html

@@ -1,232 +1,232 @@
-<!DOCTYPE html>
-<html lang="en">
-	<head>
+<!DOCTYPE html>
+<html lang="en">
+	<head>
 		<meta charset="utf-8" />
-		<base href="../../" />
-		<script src="list.js"></script>
-		<script src="page.js"></script>
-		<link type="text/css" rel="stylesheet" href="page.css" />
-	</head>
-	<body>
-		<h1>[name]</h1>
-
-		<div class="desc">
-			A loader for loading a JSON resource. Unlike the [page:JSONLoader], this one make use of the
-			<em>.type</em> attributes of objects to map them to their original classes.<br /><br />
-
-			Note that this loader can't load [page:Geometries]. Use [page:JSONLoader] instead for that.<br /><br />
-
-			This uses the [page:FileLoader] internally for loading files.
-		</div>
-
-		<h2>Example</h2>
-
-		<div>
-
-			[example:webgl_animation_scene WebGL / animation / scene]<br />
-			[example:webgl_loader_json_claraio WebGL / loader / json / claraio]<br />
-			[example:webgl_loader_msgpack WebGL / loader / msgpack]
-		</div>
-
-		<code>
-var loader = new THREE.ObjectLoader();
-
-loader.load(
-    // resource URL
-    "models/json/example.json"
-
-    // pass the loaded data to the onLoad function.
-		//Here it is assumed to be an object
-    function ( obj ) {
-				//add the loaded object to the scene
-        scene.add( obj );
-    },
-
-    // Function called when download progresses
-    function ( xhr ) {
-        console.log( (xhr.loaded / xhr.total * 100) + '% loaded' );
-    },
-
-    // Function called when download errors
-    function ( xhr ) {
-        console.error( 'An error happened' );
-    }
-);
-
-
-// Alternatively, to parse a previously loaded JSON structure
-var object = loader.parse( a_json_object );
-
-scene.add( object );
-		</code>
-
-
-
-		<h2>Constructor</h2>
-
-		<h3>[name]( [page:LoadingManager manager] )</h3>
-		<div>
-		[page:LoadingManager manager] — The [page:LoadingManager loadingManager] for the loader to use. Default is [page:LoadingManager THREE.DefaultLoadingManager].<br /><br />
-
-		Creates a new [name].
-		</div>
-
-
-		<h2>Properties</h2>
-
-		<h3>[property:String crossOrigin]</h3>
-		<div>
-		If set, assigns the [link:https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes crossOrigin]
-	 attribute of the image to the value of *crossOrigin*,
-		prior to starting the load. Default is *undefined*.
-		</div>
-
-		<h3>[property:LoadingManager manager]</h3>
-		<div>
-			The [page:LoadingManager loadingManager]  the loader is using. Default is [page:DefaultLoadingManager].
-		</div>
-
-		<h3>[property:String texturePath]</h3>
-		<div>
-			The base path or URL from which textures will be loaded. See [page:.setTexturePath].
-			Default is the empty string.
-		</div>
-
-		<h2>Methods</h2>
-
-		<h3>[method:null load]( [page:String url], [page:Function onLoad], [page:Function onProgress], [page:Function onError] )</h3>
-		<div>
-		[page:String url] — the path or URL to the file. This can also be a
-			[link:https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs Data URI].<br />
-		[page:Function onLoad] — Will be called when load completes. The argument will be the loaded [page:Object3D object].<br />
-		[page:Function onProgress] — Will be called while load progresses. The argument will be the XmlHttpRequest instance, that contain .[page:Integer total] and .[page:Integer loaded] bytes.<br />
-		[page:Function onError] — Will be called when load errors.<br />
-		</div>
-		<div>
-		Begin loading from url and call onLoad with the parsed response content.
-		</div>
-
-
-		<h3>[method:Object3D parse]( [page:Object json], [page:Function onLoad]  )</h3>
-		<div>
-		[page:Object json] — required. The JSON source to parse.<br /><br />
-		[page:Function onLoad] — Will be called when parsed completes. The argument will be the parsed [page:Object3D object].<br />
-
-		Parse a <em>JSON</em> structure and return a threejs object.
-		This is used internally by [page:.load], but can also be used directly to parse
-		a previously loaded JSON structure.
-		</div>
-
-		<h3>[method:Object3D parseGeometries]( [page:Object json] )</h3>
-		<div>
-		[page:Object json] — required. The JSON source to parse.<br /><br />
-
-		This is used [page:.parse] to parse any [page:Geometry geometries] or [page:BufferGeometry buffer geometries]  in the JSON structure.
-		Internally it uses [page:JSONLoader] for geometries and [page:BufferGeometryLoader] for buffer geometries.
-		</div>
-
-		<h3>[method:Object3D parseMaterials]( [page:Object json] )</h3>
-		<div>
-		[page:Object json] — required. The JSON source to parse.<br /><br />
-
-		This is used [page:.parse] to parse any materials in the JSON structure using [page:MaterialLoader].
-		</div>
-
-		<h3>[method:Object3D parseAnimations]( [page:Object json] )</h3>
-		<div>
-		[page:Object json] — required. The JSON source to parse.<br /><br />
-
-		This is used [page:.parse] to parse any animations in the JSON structure, using [page:AnimationClip.parse].
-		</div>
-
-		<h3>[method:Object3D parseImages]( [page:Object json] )</h3>
-		<div>
-		[page:Object json] — required. The JSON source to parse.<br /><br />
-
-		This is used [page:.parse] to parse any images in the JSON structure, using [page:ImageLoader].
-		</div>
-
-		<h3>[method:Object3D parseTextures]( [page:Object json] )</h3>
-		<div>
-		[page:Object json] — required. The JSON source to parse.<br /><br />
-
-		This is used [page:.parse] to parse any textures in the JSON structure.
-		</div>
-
-		<h3>[method:Object3D parseObject]( [page:Object json] )</h3>
-		<div>
-		[page:Object json] — required. The JSON source to parse.<br /><br />
-
-		This is used [page:.parse] to parse any objects in the JSON structure.
-		Objects can be of the following types:
-
-		<ul>
-			<li>
-				[page:Scene]
-			</li>
-			<li>
-				[page:PerspectiveCamera]
-			</li>
-			<li>
-				[page:OrthographicCamera]
-			</li>
-			<li>
-				[page:AmbientLight]
-			</li>
-			<li>
-				[page:DirectionalLight]
-			</li>
-			<li>
-				[page:PointLight]
-			</li>
-			<li>
-				[page:SpotLight]
-			</li>
-			<li>
-				[page:HemisphereLight]
-			</li>
-			<li>
-				[page:Mesh]
-			</li>
-			<li>
-				[page:LOD]
-			</li>
-			<li>
-				[page:Line]
-			</li>
-			<li>
-				[page:LineSegments]
-			</li>
-			<li>
-				[page:Points]
-			</li>
-			<li>
-				[page:Sprite]
-			</li>
-			<li>
-				[page:Group]
-			</li>
-			<li>
-				[page:Object3D]
-			</li>
-
-		</ul>
-		</div>
-
-		<h3>[method:null setCrossOrigin]( [page:String value] )</h3>
-		<div>
-		[page:String value] — The crossOrigin string to implement CORS for loading the url from a different domain that allows CORS.
-		</div>
-
-		<h3>[method:null setTexturePath]( [page:String value] )</h3>
-		<div>
-		[page:String value] — The base path or URL from which textures will be loaded.<br /><br />
-
-
-		</div>
-
-		<h2>Source</h2>
-
-		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
-	</body>
-</html>
+		<base href="../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		<h1>[name]</h1>
+
+		<div class="desc">
+			A loader for loading a JSON resource. Unlike the [page:JSONLoader], this one make use of the
+			<em>.type</em> attributes of objects to map them to their original classes.<br /><br />
+
+			Note that this loader can't load [page:Geometries]. Use [page:JSONLoader] instead for that.<br /><br />
+
+			This uses the [page:FileLoader] internally for loading files.
+		</div>
+
+		<h2>Example</h2>
+
+		<div>
+
+			[example:webgl_animation_scene WebGL / animation / scene]<br />
+			[example:webgl_loader_json_claraio WebGL / loader / json / claraio]<br />
+			[example:webgl_loader_msgpack WebGL / loader / msgpack]
+		</div>
+
+		<code>
+var loader = new THREE.ObjectLoader();
+
+loader.load(
+    // resource URL
+    "models/json/example.json",
+
+    // pass the loaded data to the onLoad function.
+		//Here it is assumed to be an object
+    function ( obj ) {
+				//add the loaded object to the scene
+        scene.add( obj );
+    },
+
+    // Function called when download progresses
+    function ( xhr ) {
+        console.log( (xhr.loaded / xhr.total * 100) + '% loaded' );
+    },
+
+    // Function called when download errors
+    function ( xhr ) {
+        console.error( 'An error happened' );
+    }
+);
+
+
+// Alternatively, to parse a previously loaded JSON structure
+var object = loader.parse( a_json_object );
+
+scene.add( object );
+		</code>
+
+
+
+		<h2>Constructor</h2>
+
+		<h3>[name]( [page:LoadingManager manager] )</h3>
+		<div>
+		[page:LoadingManager manager] — The [page:LoadingManager loadingManager] for the loader to use. Default is [page:LoadingManager THREE.DefaultLoadingManager].<br /><br />
+
+		Creates a new [name].
+		</div>
+
+
+		<h2>Properties</h2>
+
+		<h3>[property:String crossOrigin]</h3>
+		<div>
+		If set, assigns the [link:https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes crossOrigin]
+	 attribute of the image to the value of *crossOrigin*,
+		prior to starting the load. Default is *undefined*.
+		</div>
+
+		<h3>[property:LoadingManager manager]</h3>
+		<div>
+			The [page:LoadingManager loadingManager]  the loader is using. Default is [page:DefaultLoadingManager].
+		</div>
+
+		<h3>[property:String texturePath]</h3>
+		<div>
+			The base path or URL from which textures will be loaded. See [page:.setTexturePath].
+			Default is the empty string.
+		</div>
+
+		<h2>Methods</h2>
+
+		<h3>[method:null load]( [page:String url], [page:Function onLoad], [page:Function onProgress], [page:Function onError] )</h3>
+		<div>
+		[page:String url] — the path or URL to the file. This can also be a
+			[link:https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs Data URI].<br />
+		[page:Function onLoad] — Will be called when load completes. The argument will be the loaded [page:Object3D object].<br />
+		[page:Function onProgress] — Will be called while load progresses. The argument will be the XmlHttpRequest instance, that contain .[page:Integer total] and .[page:Integer loaded] bytes.<br />
+		[page:Function onError] — Will be called when load errors.<br />
+		</div>
+		<div>
+		Begin loading from url and call onLoad with the parsed response content.
+		</div>
+
+
+		<h3>[method:Object3D parse]( [page:Object json], [page:Function onLoad]  )</h3>
+		<div>
+		[page:Object json] — required. The JSON source to parse.<br /><br />
+		[page:Function onLoad] — Will be called when parsed completes. The argument will be the parsed [page:Object3D object].<br />
+
+		Parse a <em>JSON</em> structure and return a threejs object.
+		This is used internally by [page:.load], but can also be used directly to parse
+		a previously loaded JSON structure.
+		</div>
+
+		<h3>[method:Object3D parseGeometries]( [page:Object json] )</h3>
+		<div>
+		[page:Object json] — required. The JSON source to parse.<br /><br />
+
+		This is used [page:.parse] to parse any [page:Geometry geometries] or [page:BufferGeometry buffer geometries]  in the JSON structure.
+		Internally it uses [page:JSONLoader] for geometries and [page:BufferGeometryLoader] for buffer geometries.
+		</div>
+
+		<h3>[method:Object3D parseMaterials]( [page:Object json] )</h3>
+		<div>
+		[page:Object json] — required. The JSON source to parse.<br /><br />
+
+		This is used [page:.parse] to parse any materials in the JSON structure using [page:MaterialLoader].
+		</div>
+
+		<h3>[method:Object3D parseAnimations]( [page:Object json] )</h3>
+		<div>
+		[page:Object json] — required. The JSON source to parse.<br /><br />
+
+		This is used [page:.parse] to parse any animations in the JSON structure, using [page:AnimationClip.parse].
+		</div>
+
+		<h3>[method:Object3D parseImages]( [page:Object json] )</h3>
+		<div>
+		[page:Object json] — required. The JSON source to parse.<br /><br />
+
+		This is used [page:.parse] to parse any images in the JSON structure, using [page:ImageLoader].
+		</div>
+
+		<h3>[method:Object3D parseTextures]( [page:Object json] )</h3>
+		<div>
+		[page:Object json] — required. The JSON source to parse.<br /><br />
+
+		This is used [page:.parse] to parse any textures in the JSON structure.
+		</div>
+
+		<h3>[method:Object3D parseObject]( [page:Object json] )</h3>
+		<div>
+		[page:Object json] — required. The JSON source to parse.<br /><br />
+
+		This is used [page:.parse] to parse any objects in the JSON structure.
+		Objects can be of the following types:
+
+		<ul>
+			<li>
+				[page:Scene]
+			</li>
+			<li>
+				[page:PerspectiveCamera]
+			</li>
+			<li>
+				[page:OrthographicCamera]
+			</li>
+			<li>
+				[page:AmbientLight]
+			</li>
+			<li>
+				[page:DirectionalLight]
+			</li>
+			<li>
+				[page:PointLight]
+			</li>
+			<li>
+				[page:SpotLight]
+			</li>
+			<li>
+				[page:HemisphereLight]
+			</li>
+			<li>
+				[page:Mesh]
+			</li>
+			<li>
+				[page:LOD]
+			</li>
+			<li>
+				[page:Line]
+			</li>
+			<li>
+				[page:LineSegments]
+			</li>
+			<li>
+				[page:Points]
+			</li>
+			<li>
+				[page:Sprite]
+			</li>
+			<li>
+				[page:Group]
+			</li>
+			<li>
+				[page:Object3D]
+			</li>
+
+		</ul>
+		</div>
+
+		<h3>[method:null setCrossOrigin]( [page:String value] )</h3>
+		<div>
+		[page:String value] — The crossOrigin string to implement CORS for loading the url from a different domain that allows CORS.
+		</div>
+
+		<h3>[method:null setTexturePath]( [page:String value] )</h3>
+		<div>
+		[page:String value] — The base path or URL from which textures will be loaded.<br /><br />
+
+
+		</div>
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
+</html>

+ 8 - 2
docs/api/materials/Material.html

@@ -17,8 +17,8 @@
 		They are defined in a (mostly) renderer-independent way, so you don't have to
 		rewrite materials if you decide to use a different renderer.<br /><br />
 
-		With the exception of [page:MultiMaterial MultiMaterial], the following properties
-		and methods are inherited by all other material types (although they may have different defaults).
+		The following properties and methods are inherited by all other material types
+		(although they may have different defaults).
 		</div>
 
 		<h2>Constructor</h2>
@@ -198,6 +198,12 @@
 		Default is *false*.
 		</div>
 
+		<h3>[property:Boolean dithering]</h3>
+		<div>
+		Whether to apply dithering to the color to remove the appearance of banding.
+		Default is *false*.
+		</div>
+
 		<h3>[property:Integer shading]</h3>
 		<div>
 		Defines how the material is shaded.

+ 4 - 3
docs/api/materials/ShaderMaterial.html

@@ -86,13 +86,14 @@
 		var material = new THREE.ShaderMaterial( {
 
 			uniforms: {
+
 				time: { value: 1.0 },
 				resolution: { value: new THREE.Vector2() }
+
 			},
-			attributes: {
-				vertexOpacity: { value: [] }
-			},
+
 			vertexShader: document.getElementById( 'vertexShader' ).textContent,
+
 			fragmentShader: document.getElementById( 'fragmentShader' ).textContent
 
 		} );

+ 7 - 3
docs/api/materials/ShadowMaterial.html

@@ -13,11 +13,11 @@
 		<h1>[name]</h1>
 
 		<div class="desc">
-		This material can recieve shadows, but otherwise is completely transparent.
+		This material can receive shadows, but otherwise is completely transparent.
 		</div>
 
 		<h3>Example</h3>
-		[example:webgl_geometry_spline_editor gemoetry / spline / editor]
+		[example:webgl_geometry_spline_editor geometry / spline / editor]
 
 		<code>
 var planeGeometry = new THREE.PlaneGeometry( 2000, 2000 );
@@ -34,7 +34,11 @@ scene.add( plane );
 
 		<h2>Constructor</h2>
 
-		<h3>[name]( )</h3>
+		<h3>[name]( [page:Object parameters] )</h3>
+		<div>
+			[page:Object parameters] - (optional) an object with one or more properties defining the material's appearance.
+			Any property of the material (including any property inherited from [page:Material] and [page:ShaderMaterial]) can be passed in here.<br /><br />
+		</div>
 
 
 		<h2>Properties</h2>

+ 37 - 37
docs/api/math/Color.html

@@ -44,22 +44,22 @@ var color = new THREE.Color( 1, 0, 0 );
 		<h2>Constructor</h2>
 
 
-		<h3>[name]( [page:Multi r], [page:Float g], [page:Float b] )</h3>
+		<h3>[name]( [page:Color_Hex_or_String r], [page:Float g], [page:Float b] )</h3>
 		<div>
-		[page:Multi r] - (optional) the red component of the color if arguments g and b are defined.
-		If they are not defined, it can be a [link:https://en.wikipedia.org/wiki/Web_colors#Hex_triplet hexadecimal triplet] (recommended) or a CSS-style string or another Color instance.<br />
-		[page:Float g] - (optional) The green component of the color if it is defined.<br />
-		[page:Float b] - (optional) The blue component of the color if it is defined.<br /><br />
+		[page:Color_Hex_or_String r] - (optional) If arguments [page:Float g] and [page:Float b] are defined, the red component of the color.
+		If they are not defined, it can be a [link:https://en.wikipedia.org/wiki/Web_colors#Hex_triplet hexadecimal triplet] (recommended), a CSS-style string, or another Color instance.<br />
+		[page:Float g] - (optional) If it is defined, the green component of the color.<br />
+		[page:Float b] - (optional) If it is defined, the blue component of the color.<br /><br />
 
 		Note that standard method of specifying color in three.js is with a [link:https://en.wikipedia.org/wiki/Web_colors#Hex_triplet hexadecimal triplet], and that method is used
 		throughout the rest of the documentation.<br /><br />
 
-		When all arguments are defined then r is the red component, g is the green component and b is the blue component of the color.<br />
-		When only r is defined:<br />
+		When all arguments are defined then [page:Color_Hex_or_String r] is the red component, [page:Float g] is the green component and [page:Float b] is the blue component of the color.<br />
+		When only [page:Color_Hex_or_String r] is defined:<br />
 		<ul>
 			<li>It can be a [link:https://en.wikipedia.org/wiki/Web_colors#Hex_triplet hexadecimal triplet] representing the color (recommended).</li>
 			<li>It can be an another Color instance.</li>
-			<li>It can be a CSS style string. For Instance:
+			<li>It can be a CSS-style string. For example:
 				<ul>
 					<li>'rgb(250, 0,0)'</li>
 					<li>'rgb(100%,0%,0%)'</li>
@@ -114,7 +114,7 @@ var color = new THREE.Color( 1, 0, 0 );
 		<div>Adds [page:Number s] to the RGB values of this color.</div>
 
 		<h3>[method:Color clone]() </h3>
-		<div>Returns a new Color with the same  [page:.r r], [page:.g g] and [page:.b b] parameters a this one.</div>
+		<div>Returns a new Color with the same [page:.r r], [page:.g g] and [page:.b b] values as this one.</div>
 
 		<h3>[method:Color copy]( [page:Color color] ) </h3>
 		<div>
@@ -122,17 +122,17 @@ var color = new THREE.Color( 1, 0, 0 );
 		</div>
 
 		<h3>[method:Color convertGammaToLinear]() </h3>
-		<div>Converts this color from gamma to linear space (squares the values of [page:.r r], [page:.g g] and [page:.b b] ).</div>
+		<div>Converts this color from gamma to linear space by squaring the values of [page:.r r], [page:.g g] and [page:.b b] ).</div>
 
 		<h3>[method:Color convertLinearToGamma]() </h3>
-		<div>Converts this color from linear to gamma space (takes the squareroot of [page:.r r], [page:.g g] and [page:.b b]).</div>
+		<div>Converts this color from linear to gamma space by taking the square root of [page:.r r], [page:.g g] and [page:.b b]).</div>
 
 		<h3>[method:Color copyGammaToLinear]( [page:Color color], [page:Float gammaFactor] ) </h3>
 		<div>
 		[page:Color color] — Color to copy.<br />
 		[page:Float gammaFactor] - (optional). Default is *2.0*.<br /><br />
 
-		Copies given color making conversion from gamma to linear space,
+		Copies the given color into this color while converting it from gamma to linear space
 		by taking [page:.r r], [page:.g g] and [page:.b b] to the power of [page:Float gammaFactor].
 		</div>
 
@@ -141,16 +141,16 @@ var color = new THREE.Color( 1, 0, 0 );
 		[page:Color color] — Color to copy.<br />
 		[page:Float gammaFactor] - (optional). Default is *2.0*.<br /><br />
 
-		Copies given color making conversion from linear to gamma space,
+		Copies the given color into this color while converting it from linear to gamma space
 		by taking [page:.r r], [page:.g g] and [page:.b b] to the power of 1 / [page:Float gammaFactor].
 		</div>
 
 		<h3>[method:Boolean equals]( [page:Color color] ) </h3>
-		<div>Compares [page:Color color] with this one and returns true if they are the same, false otherwise.</div>
+		<div>Compares the RGB values of [page:Color color] with those of this object. Returns true if they are the same, false otherwise.</div>
 
 		<h3>[method:Color fromArray]( [page:Array array], [page:Integer offset] ) </h3>
 		<div>
-		[page:Array array] - [page:Array] of float in the form [ [page:Float r], [page:Float g], [page:Float b] ].<br />
+		[page:Array array] - [page:Array] of floats in the form [ [page:Float r], [page:Float g], [page:Float b] ].<br />
 		[page:Integer offset] - An optional offset into the array.<br /><br />
 
 		Sets this color's components based on an array formatted like [ [page:Float r], [page:Float g], [page:Float b] ].
@@ -160,14 +160,14 @@ var color = new THREE.Color( 1, 0, 0 );
 		<div>Returns the hexadecimal value of this color.</div>
 
 		<h3>[method:String getHexString]()</h3>
-		<div>Returns the string formatted hexadecimal value of this color.</div>
+		<div>Returns the hexadecimal value of this color as a string (for example, 'FFFFFF').</div>
 
 		<h3>[method:Object getHSL]( [page:Object optionalTarget] )</h3>
 		<div>
-			[page:Object optionalTarget] — (optional) if specified, adds h, s and l keys to object (if not already present)
-			and sets the results there, otherwise a new Object will be created. <br /><br />
+			[page:Object optionalTarget] — (optional) if specified, adds h, s and l keys to the object (if not already present)
+			and sets the results there. Otherwise, a new Object will be created. <br /><br />
 
-			Convert the values [page:.r r], [page:.g g] and [page:.b b] to [link:https://en.wikipedia.org/wiki/HSL_and_HSV HSL]
+			Convert this Color's [page:.r r], [page:.g g] and [page:.b b] values to [link:https://en.wikipedia.org/wiki/HSL_and_HSV HSL]
 			format and returns an object of the form:
 
 			<code>
@@ -177,37 +177,37 @@ var color = new THREE.Color( 1, 0, 0 );
 		</div>
 
 		<h3>[method:String getStyle]()</h3>
-		<div>Returns the value of this color as a CSS-style string. Example: 'rgb(255,0,0)'.</div>
+		<div>Returns the value of this color as a CSS style string. Example: 'rgb(255,0,0)'.</div>
 
 		<h3>[method:Color lerp]( [page:Color color], [page:Float alpha] ) </h3>
 		<div>
 		[page:Color color] - color to converge on.<br />
 		[page:Float alpha] - interpolation factor in the closed interval [0, 1].<br /><br />
 
-		Linear interpolation of this colors RGB values and the RGB values of the passed argument.
-		The alpha argument can be thought of as the percent between the two colors, where 0 is
-		this color and 1 is the first argument.
+		Linearly interpolates this color's RGB values toward the RGB values of the passed argument.
+		The alpha argument can be thought of as the ratio between the two colors, where 0.0 is
+		this color and 1.0 is the first argument.
 		</div>
 
 		<h3>[method:Color multiply]( [page:Color color] ) </h3>
-		<div>Multiplies this color's RGB values by given [page:Color color]'s RGB values.</div>
+		<div>Multiplies this color's RGB values by the given [page:Color color]'s RGB values.</div>
 
 		<h3>[method:Color multiplyScalar]( [page:Number s] ) </h3>
 		<div>Multiplies this color's RGB values by [page:Number s].</div>
 
 		<h3>[method:Color offsetHSL]( [page:Float h], [page:Float s], [page:Float l] ) </h3>
 		<div>
-			Adds given [page:Float h], [page:Float s], and [page:Float l] to this color's existing values.
-			Internally this converts the [page:.r r], [page:.g g] and [page:.b b] values to HSL, adds
-			[page:Float h], [page:Float s], and [page:Float l] and then converts back to RGB.
+			Adds the given [page:Float h], [page:Float s], and [page:Float l] to this color's values.
+			Internally, this converts the color's [page:.r r], [page:.g g] and [page:.b b] values to HSL, adds
+			[page:Float h], [page:Float s], and [page:Float l], and then converts the color back to RGB.
 		</div>
 
-		<h3>[method:Color set]( [page:Multi value] ) </h3>
+		<h3>[method:Color set]( [page:Color_Hex_or_String value] ) </h3>
 		<div>
-		[page:Multi value] - Value to set this color to.<br /><br />
+		[page:Color_Hex_or_String value] - Value to set this color to.<br /><br />
 
-		See the Constructor above for full details of what [page:Multi value] can be.
-		Delegates to [page:.copy], .setStyle, or .setHex depending on input type.
+		See the Constructor above for full details of what [page:Color_Hex_or_String value] can be.
+		Delegates to [page:.copy], [page:.setStyle], or [page:.setHex] depending on input type.
 		</div>
 
 		<h3>[method:Color setHex]( [page:Integer hex] ) </h3>
@@ -228,9 +228,9 @@ var color = new THREE.Color( 1, 0, 0 );
 
 		<h3>[method:Color setRGB]( [page:Float r], [page:Float g], [page:Float b] ) </h3>
 		<div>
-		[page:Float r] — Red channel value between 0 and 1.<br />
-		[page:Float g] — Green channel value between 0 and 1.<br />
-		[page:Float b] — Blue channel value between 0 and 1.<br /><br />
+		[page:Float r] — Red channel value between 0.0 and 1.0.<br />
+		[page:Float g] — Green channel value between 0.0 and 1.0.<br />
+		[page:Float b] — Blue channel value between 0.0 and 1.0.<br /><br />
 
 		Sets this color from RGB values.
 		</div>
@@ -255,7 +255,7 @@ var color = new THREE.Color( 1, 0, 0 );
 		"red" ( or any [link:https://en.wikipedia.org/wiki/X11_color_names#Color_name_chart X11 color name]
 		- all 140 color names are supported ).<br />
 
-		Transluent colors such as "rgba(255, 0, 0, 0.5)" and "hsla(0, 100%, 50%, 0.5)" are also accepted,
+		Translucent colors such as "rgba(255, 0, 0, 0.5)" and "hsla(0, 100%, 50%, 0.5)" are also accepted,
 		but the alpha-channel coordinate will be discarded.<br /><br />
 
 		Note that for X11 color names, multiple words such as Dark Orange become the string 'darkorange' (all lowercase).
@@ -263,8 +263,8 @@ var color = new THREE.Color( 1, 0, 0 );
 
 		<h3>[method:Color sub]( [page:Color color] ) </h3>
 		<div>
-		Subtracts RGB components of the given color from the RGB components of this color.
-		If a component is negative, it is set to zero.
+		Subtracts the RGB components of the given color from the RGB components of this color.
+		If this results in a negative component, that component is set to zero.
 		</div>
 
 		<h3>[method:Array toArray]( [page:Array array], [page:Integer offset] ) </h3>

+ 12 - 0
docs/api/math/Matrix3.html

@@ -92,6 +92,9 @@ m.elements = [ 11, 21, 31,
 		[link:https://en.wikipedia.org/wiki/Determinant determinant] of this matrix.
 		</div>
 
+		<h3>[method:Boolean equals]( [page:Matrix3 m] )</h3>
+		<div>Return true if this matrix and [page:Matrix3 m] are equal.</div>
+
 		<h3>[method:Matrix3 fromArray]( [page:Array array], [page:Integer offset] )</h3>
 		<div>
 		[page:Array array] - the array to read the elements from.<br />
@@ -132,6 +135,12 @@ m.elements = [ 11, 21, 31,
 
 		</div>
 
+		<h3>[method:Matrix3 multiply]( [page:Matrix3 m] )</h3>
+		<div>Post-multiplies this matrix by [page:Matrix3 m].</div>
+
+		<h3>[method:Matrix3 multiplyMatrices]( [page:Matrix3 a], [page:Matrix3 b] )</h3>
+		<div>Sets this matrix to [page:Matrix3 a] x [page:Matrix3 b].</div>
+
 		<h3>[method:Matrix3 multiplyScalar]( [page:Float s] )</h3>
 		<div>Multiplies every component of the matrix by the scalar value *s*.</div>
 
@@ -154,6 +163,9 @@ m.elements = [ 11, 21, 31,
 		sequence of values.
 		</div>
 
+		<h3>[method:Matrix3 premultiply]( [page:Matrix3 m] )</h3>
+		<div>Pre-multiplies this matrix by [page:Matrix3 m].</div>
+
 		<h3>[method:Matrix3 setFromMatrix4]( [page:Matrix4 m] )</h3>
 		<div>Set this matrx to the upper 3x3 matrix of the Matrix4 [page:Matrix4 m].</div>
 

+ 8 - 14
docs/api/math/Matrix4.html

@@ -29,23 +29,25 @@
 					[page:Object3D.matrix]: This stores the local transform of the object.
 				</li>
 				<li>
-					[page:Object3D.matrixWorld]: The global or world transform of the object. This is the objects transformation relative to its parent.
+					[page:Object3D.matrixWorld]: The global or world transform of the object. This is the object's transformation relative to its parent.
 					If the object has no parent, then this is identical to the local transform.
 				</li>
 				<li>
-					[page:Object3D.modelViewMatrix]:
+					[page:Object3D.modelViewMatrix]: This represents the object's transformation relative to the camera's coordinate system.
+					An object's modelViewMatrix is the object's matrixWorld pre-multiplied by the camera's matrixWorldInverse.
 				</li>
 			</ul>
 
-			[page:Camera Cameras] have two additional matrix4s:
+			[page:Camera Cameras] have two additional Matrix4s:
 			<ul>
 				<li>
-					[page:Object3D.matrixWorldInverse]: The inverse of the [page:Object3D.matrixWorld] described above.
+					[page:Camera.matrixWorldInverse]: The view matrix - the inverse of the Camera's [page:Object3D.matrixWorld matrixWorld].
 				</li>
 				<li>
-					[page:Object3D.projectionMatrix]:
+					[page:Camera.projectionMatrix]: Represents the information how to project the scene to clip space.
 				</li>
 			</ul>
+			Note: [page:Object3D.normalMatrix] is not a Matrix4, but a [page:Matrix3].
 		</div>
 
 		<h2>A Note on Row-Major and Column-Major Ordering</h2>
@@ -166,7 +168,7 @@ m, n, o, p
 		then the [page:Vector3 xAxis], [page:Vector3 yAxis], [page:Vector3 zAxis] will be set to:
 		<code>
 xAxis = (a, e, i)
-yAxis = (d, f, j)
+yAxis = (b, f, j)
 zAxis = (c, g, k)
 		</code>
 		</div>
@@ -361,14 +363,6 @@ x, y, 1, 0,
 		<h3>[method:Matrix4 multiplyScalar]( [page:Float s] )</h3>
 		<div>Multiplies every component of the matrix by a scalar value [page:Float s].</div>
 
-		<h3>[method:Matrix4 multiplyToArray]( [page:Matrix4 a], [page:Matrix4 b], [page:Array r] )</h3>
-		<div>
-		Sets this matrix to [page:Matrix4 a] x [page:Matrix4 b] and stores the result into the flat array [page:Array r],
-		in [link:https://en.wikipedia.org/wiki/Row-_and_column-major_order#Column-major_order column-major] order.
-
-		[page:Array r] can be either a regular Array or a [link:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays TypedArray].
-		</div>
-
 		<h3>[method:Matrix4 premultiply]( [page:Matrix4 m] )</h3>
 		<div>Pre-multiplies this matrix by [page:Matrix4 m].</div>
 

+ 1 - 1
docs/api/objects/LOD.html

@@ -31,7 +31,7 @@ for( var i = 0; i < 3; i++ ) {
 
 	var geometry = new THREE.IcosahedronBufferGeometry( 10, 3 - i )
 
-	new THREE.Mesh( geometry, material );
+	var mesh = new THREE.Mesh( geometry, material );
 
 	lod.addLevel( mesh, i * 75 );
 

+ 3 - 0
docs/api/renderers/WebGLRenderer.html

@@ -305,6 +305,9 @@
 		This method clears a rendertarget. To do this, it activates the rendertarget.
 		</div>
 
+		<h3>[method:null compile]( [page:Scene scene], [page:Camera camera] )</h3>
+		<div>Compiles all materials in the scene with the camera. This is useful to precompile shaders before the first rendering.</div>
+		
 		<h3>[method:null dispose]( )</h3>
 		<div>Dispose of the current rendering context.</div>
 

+ 1 - 1
docs/examples/loaders/OBJLoader.html

@@ -67,7 +67,7 @@
 		<div>
 		Returns an [page:Object3D]. It contains the parsed meshes as [page:Mesh] and lines as [page:LineSegments].<br />
 		All geometry is created as [page:BufferGeometry]. Default materials are created as [page:MeshPhongMaterial].<br />
-		If an <em>obj</em> object or group uses multiple materials while declaring faces geometry groups and a [page:MultiMaterial] is used.
+		If an <em>obj</em> object or group uses multiple materials while declaring faces geometry groups and an array of materials are used.
 		</div>
 
 		<h2>Source</h2>

+ 114 - 0
docs/examples/loaders/OBJLoader2.html

@@ -0,0 +1,114 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+
+		<h1>[name]</h1>
+
+		<div class="desc">A loader for loading an <em>.obj</em> resource.</div>
+
+		<h2>Example</h2>
+
+		<code>
+		// instantiate the loader
+		var loader = new THREE.OBJLoader2();
+
+		// function called on successful load
+		var intergrateIntoScene = function ( object ) {
+			scene.add( object );
+		};
+
+		// load a resource from provided URL
+		loader.load( 'obj/female02/female02.obj', intergrateIntoScene );
+		</code>
+
+		[example:webgl_loader_obj2]
+
+
+		<h2>Constructor</h2>
+
+		<h3>[name]( [page:LoadingManager manager] )</h3>
+		<div>
+		[page:LoadingManager manager] — The [page:LoadingManager loadingManager] for the loader to use. Default is [page:LoadingManager THREE.DefaultLoadingManager].
+		</div>
+		<div>
+			Use [name] to load OBJ data from files or to parse OBJ data from arraybuffer or text.
+		</div>
+
+		<h2>Properties</h2>
+
+
+		<h2>Methods</h2>
+
+		<h3>[method:null load]( [page:String url], [page:Function onLoad], [page:Function onProgress], [page:Function onError], [page:Boolean useArrayBuffer] )</h3>
+		<div>
+			[page:String url] — URL of the file to load<br />
+			[page:Function onLoad] — Called after loading was successfully completed. The argument will be the loaded [page:Object3D].<br />
+			[page:Function onProgress] — Called to report progress of loading. The argument will be the XmlHttpRequest instance, that contain .[page:Integer total] and .[page:Integer loaded] bytes.<br />
+			[page:Function onError]  Called after an error occurred during loading.<br />
+			[page:boolean useArrayBuffer] — Set this to false to force string based parsing<br />
+		</div>
+		<div>
+			Use this convenient method to load an OBJ file at the given URL. Per default the fileLoader uses an arraybuffer
+		</div>
+
+		<h3>[method:Object3D parse]( [page:ArrayBuffer arrayBuffer] )</h3>
+		<div>
+			[page:ArrayBuffer arrayBuffer] — OBJ data as Uint8Array
+		</div>
+		<div>
+			Default parse function: Parses OBJ file content stored in arrayBuffer and returns the [page:Object3D sceneGraphBaseNode].
+		</div>
+
+		<h3>[method:Object3D parseText]( [page:String test] )</h3>
+		<div>
+			[page:String text] — OBJ data as string
+		</div>
+		<div>
+			Legacy parse function: Parses OBJ file content stored in string and returns the [page:Object3D sceneGraphBaseNode].
+		</div>
+
+		<h3>[method:null setMaterials] ( Array of [page:Material materials] )</h3>
+		<div>
+			Array of [page:Material materials] — Array of [page:Material Materials] from MTLLoader
+		</div>
+		<div>
+			Set materials loaded by MTLLoader or any other supplier of an Array of [page:Material Materials].
+		</div>
+
+		<h3>[method:null setPath] ( [page:String path] )</h3>
+		<div>
+			[page:String path] — The basePath
+		</div>
+		<div>
+			Base path to use.
+		</div>
+
+		<h3>[method:null setSceneGraphBaseNode] ( [page:Object3D sceneGraphBaseNode] )</h3>
+		<div>
+			[page:Object3D sceneGraphBaseNode] — Scenegraph object where meshes will be attached
+		</div>
+		<div>
+			Set the node where the loaded objects will be attached.
+		</div>
+
+		<h3>[method:null setDebug]( [page:Boolean parserDebug], [page:Boolean meshCreatorDebug] )</h3>
+		<div>
+			[page:Boolean parserDebug] — Internal Parser will produce debug output<br>
+			[page:Boolean meshCreatorDebug] — Internal MeshCreator will produce debug output
+		</div>
+		<div>
+			Allows to set debug mode for the parser and the meshCreator.
+		</div>
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/OBJLoader2.js examples/js/loaders/OBJLoader2.js]
+	</body>
+</html>

+ 404 - 0
docs/examples/loaders/WWOBJLoader2.html

@@ -0,0 +1,404 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+
+		<h1>[name]</h1>
+
+		<div class="desc">A loader for loading an <em>.obj</em> resource within a web worker.</div>
+
+		<h2>Sub-Classes</h2>
+		[page:WWOBJLoader2.PrepDataArrayBuffer]<br>
+		[page:WWOBJLoader2.PrepDataFile]<br>
+		[page:WWOBJLoader2.PrepDataCallbacks]<br>
+		[page:WWOBJLoader2.LoadedMeshUserOverride]<br>
+		[page:WWOBJLoader2.WWOBJLoader2Director]
+
+		<h2>Example</h2>
+
+		<code>
+			// instantiate the loader
+			var loader = new THREE.OBJLoader2.WWOBJLoader2();
+
+			// load an OBJ file by providing a name, the path and the file name
+			var prepData = new THREE.OBJLoader2.WWOBJLoader2.PrepDataFile(
+				'female02',
+				'obj/female02/',
+				'female02.obj'
+			);
+
+			// set where to add the loaded data in the scene graph.
+			prepData.setSceneGraphBaseNode( scene );
+
+			// provide the preparation data to the loader and let it run.
+			loader.prepareRun( prepData );
+			loader.run();
+		</code>
+
+		[example:webgl_loader_obj2_ww] — Simple example that allows to load own models via file selection.<br>
+		[example:webgl_loader_obj2_ww_parallels] — Advanced example using [page:WWOBJLoader2.WWOBJLoader2Director] for orchestration of multiple workers.
+
+
+		<h2>Constructor</h2>
+
+		<h3>[name]()</h3>
+		<div>
+			OBJ data will be loaded by dynamically created web worker.<br>
+			First feed instructions with: [page:WWOBJLoader2.prepareRun prepareRun]<br>
+			Then execute with: [page:WWOBJLoader2.run run]
+		</div>
+
+		<h2>Properties</h2>
+
+
+		<h2>Methods</h2>
+
+		<h3>[method:null prepareRun]( [page:Object params] )</h3>
+		<div>
+			[page:Object params] — Either [page:WWOBJLoader2.PrepDataArrayBuffer] or [page:WWOBJLoader2.PrepDataFile]
+		</div>
+		<div>
+			Set all parameters for required for execution of [page:WWOBJLoader2.run run].
+		</div>
+
+
+		<h3>[method:null run]()</h3>
+		<div>
+			Run the loader according the preparation instruction provided in [page:WWOBJLoader2.prepareRun prepareRun].
+		</div>
+
+
+		<h3>[method:null setCrossOrigin]( [page:String crossOrigin] )</h3>
+		<div>
+			[page:String crossOrigin] — CORS value
+		</div>
+		<div>
+			Sets the CORS string to be used.
+		</div>
+
+
+		<h3>[method:null setDebug]( [page:Boolean enabled] )</h3>
+		<div>
+			[page:Boolean enabled] — True or false
+		</div>
+		<div>
+			Enable or disable debug logging.
+		</div>
+
+
+		<h3>[method:null setRequestTerminate]( [page:Boolean requestTerminate] )</h3>
+		<div>
+			[page:Boolean requestTerminate] — True or false
+		</div>
+		<div>
+			Call requestTerminate to terminate the web worker and free local resource after execution.
+		</div>
+
+
+		<h3>[method:null registerCallbackCompletedLoading]( [page:Function callbackCompletedLoading] )</h3>
+		<div>
+			[page:Function callbackCompletedLoading] — 	Callback function for described functionality
+		</div>
+		<div>
+			Register callback function that is called once loading of the complete model is completed.
+		</div>
+
+
+		<h3>[method:null registerCallbackProgress]( [page:Function callbackProgress] )</h3>
+		<div>
+			[page:Function callbackProgress] — 	Callback function for described functionality
+		</div>
+		<div>
+			Register callback function that is invoked by internal function "_announceProgress" to print feedback.
+		</div>
+
+
+		<h3>[method:null registerCallbackMaterialsLoaded]( [page:Function callbackMaterialsLoaded] )</h3>
+		<div>
+			[page:Function callbackMaterialsLoaded] — 	Callback function for described functionality
+		</div>
+		<div>
+			Register callback function that is called once materials have been loaded. It allows to alter and return materials.
+		</div>
+
+
+		<h3>[method:null registerCallbackMeshLoaded]( [page:Function callbackMeshLoaded] )</h3>
+		<div>
+			[page:Function callbackMeshLoaded] — 	Callback function for described functionality
+		</div>
+		<div>
+			Register callback function that is called every time a mesh was loaded. Use [page:WWOBJLoader2.LoadedMeshUserOverride] for alteration instructions (geometry, material or disregard mesh).
+		</div>
+
+		<h3>[method:null registerCallbackErrorWhileLoading]( [page:Function callbackErrorWhileLoading] )</h3>
+		<div>
+			[page:Function callbackErrorWhileLoading] — 	Callback function for described functionality
+		</div>
+		<div>
+			Register callback function that is called to report an error that prevented loading.
+		</div>
+
+
+		<h3>[method:null clearAllCallbacks]()</h3>
+		<div>
+			Clears all registered callbacks.
+		</div>
+
+
+		<h2>Sub-Classes</h2>
+		<br>
+		<a name="PrepDataArrayBuffer"></a><h1>PrepDataArrayBuffer</h1>
+		<h2>Constructor</h2>
+
+		<h3>PrepDataArrayBuffer( [page:String modelName], [page:Uint8Array objAsArrayBuffer], [page:String pathTexture], [page:String mtlAsString] )</h3>
+		<div>
+			[page:String modelName] — Overall name of the model<br>
+			[page:Uint8Array objAsArrayBuffer] — OBJ file content as ArrayBuffer<br>
+			[page:String pathTexture] — Path to texture files<br>
+			[page:String mtlAsString] — MTL file content as string
+		</div>
+		<div>
+			Instruction to configure [page:WWOBJLoader2.prepareRun] to load OBJ from given ArrayBuffer and MTL from given String.
+		</div>
+
+		<h2>Methods</h2>
+
+		<h3>[method:PrepDataCallbacks getCallbacks]()</h3>
+		<div>
+			Returns all callbacks as [page:WWOBJLoader2.PrepDataCallbacks].
+		</div>
+
+
+		<h3>[method:null setRequestTerminate]( [page:Boolean requestTerminate] )</h3>
+		<div>
+			[page:Boolean requestTerminate] — Default is false
+		</div>
+		<div>
+			Request termination of web worker and free local resources after execution.
+		</div>
+
+
+		<h3>[method:null setSceneGraphBaseNode]( [page:THREE.Object3D sceneGraphBaseNode] )</h3>
+		<div>
+			[page:Object3D sceneGraphBaseNode] — Scene graph object
+		</div>
+		<div>
+			[page:Object3D] where meshes will be attached.
+		</div>
+
+
+		<h3>[method:null setStreamMeshes]( [page:Boolean streamMeshes] )</h3>
+		<div>
+			[page:Boolean streamMeshes] — Default is true
+		</div>
+		<div>
+			Singles meshes are directly integrated into scene when loaded or later.
+		</div>
+		<br>
+		<br>
+
+
+		<a name="PrepDataFile"></a><h1>PrepDataFile</h1>
+		<h2>Constructor</h2>
+
+		<h3>PrepDataFile( [page:String modelName], [page:String pathObj], [page:String fileObj], [page:String pathTexture], [page:String fileMtl] )</h3>
+		<div>
+			[page:String modelName] — Overall name of the model<br>
+			[page:String pathObj] — Path to OBJ file<br>
+			[page:String fileObj] — OBJ file name<br>
+			[page:String pathTexture] — Path to texture files<br>
+			[page:String fileMtl] — MTL file name
+		</div>
+		<div>
+			Instruction to configure [page:WWOBJLoader2.prepareRun] to load OBJ and MTL from files.
+		</div>
+
+		<h2>Methods</h2>
+
+		<h3>[method:PrepDataCallbacks getCallbacks]()</h3>
+		<div>
+			Returns all callbacks as [page:WWOBJLoader2.PrepDataCallbacks].
+		</div>
+
+
+		<h3>[method:null setRequestTerminate]( [page:Boolean requestTerminate] )</h3>
+		<div>
+			[page:Boolean requestTerminate] — Default is false
+		</div>
+		<div>
+			Request termination of web worker and free local resources after execution.
+		</div>
+
+
+		<h3>[method:null setSceneGraphBaseNode]( [page:THREE.Object3D sceneGraphBaseNode] )</h3>
+		<div>
+			[page:Object3D sceneGraphBaseNode] — Scene graph object
+		</div>
+		<div>
+			[page:Object3D] where meshes will be attached.
+		</div>
+
+
+		<h3>[method:null setStreamMeshes]( [page:Boolean streamMeshes] )</h3>
+		<div>
+			[page:Boolean streamMeshes] — Default is true
+		</div>
+		<div>
+			Singles meshes are directly integrated into scene when loaded or later.
+		</div>
+		<br>
+		<br>
+
+
+		<a name="PrepDataCallbacks"></a><h1>PrepDataCallbacks</h1>
+		<h2>Constructor</h2>
+
+		<h3>PrepDataCallbacks()</h3>
+		<div>
+			Callbacks utilized by functions working with [page:WWOBJLoader2.PrepDataArrayBuffer] or [page:WWOBJLoader2.PrepDataFile].
+		</div>
+
+		<h2>Methods</h2>
+
+		<h3>[method:null registerCallbackCompletedLoading]( [page:Function callbackCompletedLoading] )</h3>
+		<div>
+			[page:Function callbackCompletedLoading] — Callback function for described functionality
+		</div>
+		<div>
+			Register callback function that is called once loading of the complete model is completed.
+		</div>
+
+
+		<h3>[method:null registerCallbackProgress]( [page:Function callbackProgress] )</h3>
+		<div>
+			[page:Function callbackProgress] — Callback function for described functionality
+		</div>
+		<div>
+			Register callback function that is invoked by internal function "_announceProgress" to print feedback.
+		</div>
+
+
+		<h3>[method:null registerCallbackErrorWhileLoading]( [page:Function callbackErrorWhileLoading] )</h3>
+		<div>
+			[page:Function callbackErrorWhileLoading] — Callback function for described functionality
+		</div>
+		<div>
+			Report if an error prevented loading.
+		</div>
+
+
+		<h3>[method:null registerCallbackMaterialsLoaded]( [page:Function callbackMaterialsLoaded] )</h3>
+		<div>
+			[page:Function callbackMaterialsLoaded] — Callback function for described functionality
+		</div>
+		<div>
+			Register callback function that is called once materials have been loaded. It allows to alter and return materials.
+		</div>
+
+
+		<h3>[method:null registerCallbackMeshLoaded]( [page:Function callbackMeshLoaded] )</h3>
+		<div>
+			[page:Function callbackMeshLoaded] — Callback function for described functionality
+		</div>
+		<div>
+			Register callback function that is called every time a mesh was loaded. Use [page:WWOBJLoader2.LoadedMeshUserOverride] for alteration instructions (geometry, material or disregard mesh).
+		</div>
+		<br>
+		<br>
+
+
+		<a name="LoadedMeshUserOverride"></a><h1>LoadedMeshUserOverride</h1>
+		<h2>Constructor</h2>
+
+		<h3>LoadedMeshUserOverride( [page:Boolean disregardMesh], [page:THREE.BufferGeometry bufferGeometry], [page:THREE.Material material] )</h3>
+		<div>
+			[page:Boolean disregardMesh] — Tell [page:WWOBJLoader2] to completely disregard this mesh<br>
+			[page:BufferGeometry bufferGeometry] — The [page:BufferGeometry] to be used<br>
+			[page:Material material] — The [page:Material] to be used
+		</div>
+		<div>
+			Object to return by THREE.OBJLoader2.WWOBJLoader2.callbacks.meshLoaded. Used to adjust bufferGeometry or material or prevent complete loading of mesh.
+		</div>
+		<br>
+		<br>
+
+
+		<a name="WWOBJLoader2Director"></a><h1>WWOBJLoader2Director</h1>
+		<h2>Constructor</h2>
+
+		<h3>WWOBJLoader2Director()</h3>
+		<div>
+			Orchestrate loading of multiple OBJ files/data from an instruction queue with a configurable amount of workers (1-16).<br>
+			Workflow:<br>
+				prepareWorkers<br>
+				enqueueForRun<br>
+				processQueue<br>
+				deregister
+		</div>
+
+		<h3>[method:null prepareWorkers]( [page:WWOBJLoader2.PrepDataCallbacks globalCallbacks], [page:Number maxQueueSize], [page:Number maxWebWorkers] )</h3>
+		<div>
+			[page:WWOBJLoader2.PrepDataCallbacks globalCallbacks] — Register global callbacks used by all web workers<br>
+			[page:Number maxQueueSize] — Set the maximum size of the instruction queue (1-1024)<br>
+			[page:Number maxWebWorkers] — Set the maximum amount of workers (1-16)
+		</div>
+		<div>
+			Create or destroy workers according limits. Set the name and register callbacks for dynamically created web workers.
+		</div>
+
+
+		<h3>[method:null enqueueForRun]( [page:Object runParams] )</h3>
+		<div>
+			[page:Object runParams] — Either [page:WWOBJLoader2.PrepDataArrayBuffer] or [page:WWOBJLoader2.PrepDataFile]
+		</div>
+		<div>
+			Store run instructions in internal instructionQueue.
+		</div>
+
+
+		<h3>[method:null processQueue]()</h3>
+		<div>
+			Process the instructionQueue until it is depleted.
+		</div>
+
+
+		<h3>[method:null deregister]()</h3>
+		<div>
+			Terminate all workers
+		</div>
+
+
+		<h3>[method:null getMaxQueueSize]()</h3>
+		<div>
+			Returns the maximum length of the instruction queue.
+		</div>
+
+
+		<h3>[method:null getMaxWebWorkers]()</h3>
+		<div>
+			Returns the maximum number of workers.
+		</div>
+
+
+		<h3>[method:null setCrossOrigin]( [page:String crossOrigin] )</h3>
+		<div>
+			[page:String crossOrigin] — CORS value
+		</div>
+		<div>
+			Sets the CORS string to be used.
+		</div>
+
+
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/OBJLoader2.js examples/js/loaders/OBJLoader2.js]
+
+	</body>
+</html>

+ 216 - 0
docs/index.css

@@ -0,0 +1,216 @@
+@font-face {
+	font-family: 'inconsolata';
+	src: url('files/inconsolata.woff') format('woff');
+	font-weight: normal;
+	font-style: normal;
+}
+
+*{
+	box-sizing: border-box;
+}
+
+html {
+	height: 100%;
+}
+
+body {
+	background-color: #ffffff;
+	margin: 0px;
+	height: 100%;
+	color: #555;
+	font-family: 'inconsolata';
+	font-size: 15px;
+	line-height: 18px;
+	overflow: hidden;
+}
+
+h1 {
+	margin-top: 30px;
+	margin-bottom: 40px;
+	margin-left: 20px;
+	font-size: 25px;
+	font-weight: normal;
+}
+
+h2 {
+	color: #454545;
+	font-size: 18px;
+	font-weight: normal;
+
+	margin-top: 20px;
+	margin-left: 20px;
+}
+
+h3 {
+	color: #666;
+	font-size: 16px;
+	font-weight: normal;
+
+	margin-top: 20px;
+	margin-left: 20px;
+}
+
+a {
+	color: #2194CE;
+	text-decoration: none;
+}
+
+#panel {
+	position: fixed;
+	left: 0px;
+	width: 260px;
+	height: 100%;
+	overflow: auto;
+	background: #fafafa;
+}
+
+#panel ul {
+	list-style-type: none;
+	padding: 0px;
+	margin-left: 20px;
+}
+
+iframe {
+	position: absolute;
+	border: 0px;
+	left: 260px;
+	width: calc(100% - 260px);
+	height: 100%;
+	overflow: auto;
+}
+
+.filterBlock{
+	margin: 20px;
+	position: relative;
+}
+
+.filterBlock p {
+	margin: 0;
+}
+
+#filterInput {
+	width: 100%;
+	padding: 5px;
+	font-family: inherit;
+	font-size: 15px;
+	outline: none;
+	border: 1px solid #dedede;
+}
+
+#filterInput:focus{
+	border: 1px solid #2194CE;
+}
+
+#clearFilterButton {
+	position: absolute;
+	right: 6px;
+	top: 50%;
+	margin-top: -8px;
+	width: 16px;
+	height: 16px;
+	font-size: 14px;
+	color: grey;
+	text-align: center;
+	line-height: 0;
+	padding-top: 7px;
+	opacity: .5;
+}
+
+#clearFilterButton:hover {
+	opacity: 1;
+}
+
+.hidden {
+	display: none;
+}
+
+#panel li b {
+	font-weight: bold;
+}
+
+/* mobile */
+
+#expandButton {
+	display: none;
+	position: absolute;
+	right: 20px;
+	top: 12px;
+	width: 32px;
+	height: 32px;
+}
+
+#expandButton span {
+	height: 2px;
+	background-color: #2194CE;
+	width: 16px;
+	position: absolute;
+	left: 8px;
+	top: 10px;
+}
+
+#expandButton span:nth-child(1) {
+	top: 16px;
+}
+
+#expandButton span:nth-child(2) {
+	top: 22px;
+}
+
+@media all and ( max-width: 640px ) {
+
+	h1{
+		margin-top: 20px;
+		margin-bottom: 20px;
+	}
+
+	#panel{
+		position: absolute;
+		left: 0;
+		top: 0;
+		height: 100%;
+		width: 100%;
+		right: 0;
+		z-index: 100;
+		overflow: hidden;
+		border-bottom: 1px solid #dedede;
+	}
+
+	#content{
+		position: absolute;
+		left: 0;
+		top: 90px;
+		right: 0;
+		bottom: 0;
+		font-size: 17px;
+		line-height: 22px;
+		overflow: auto;
+	}
+
+	#navigation{
+		position: absolute;
+		left: 0;
+		top: 90px;
+		right: 0;
+		bottom: 0;
+		font-size: 17px;
+		line-height: 22px;
+		overflow: auto;
+	}
+
+	iframe{
+		position: absolute;
+		left: 0;
+		top: 56px;
+		width: 100%;
+		height: calc(100% - 56px);
+	}
+
+	#expandButton{
+		display: block;
+	}
+
+	#panel.collapsed{
+		height: 56px;
+	}
+
+}

+ 328 - 322
docs/index.html

@@ -4,421 +4,426 @@
 		<meta charset="utf-8">
 		<title>three.js / documentation</title>
 		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
-		<style>
+		<link type="text/css" rel="stylesheet" href="index.css">
+	</head>
+	<body>
 
-			@font-face {
-				font-family: 'inconsolata';
-				src: url('files/inconsolata.woff') format('woff');
-				font-weight: normal;
-				font-style: normal;
-			}
+		<div id="panel" class="collapsed">
 
-			*{
-				box-sizing: border-box;
-			}
+			<h1><a href="http://threejs.org">three.js</a> / docs</h1>
 
-			html {
-				height: 100%;
-			}
+			<a id="expandButton" href="#">
+				<span></span>
+				<span></span>
+				<span></span>
+			</a>
 
-			body {
-				background-color: #ffffff;
-				margin: 0px;
-				height: 100%;
-				color: #555;
-				font-family: 'inconsolata';
-				font-size: 15px;
-				line-height: 18px;
-				overflow: hidden;
-			}
+			<div class="filterBlock" >
+				<input type="text" id="filterInput" placeholder="Type to filter">
+				<a href="#" id="clearFilterButton">x</a>
+			</div>
+			<div id="content"></div>
 
-				h1 {
-					margin-top: 30px;
-					margin-bottom: 40px;
-					margin-left: 20px;
-					font-size: 25px;
-					font-weight: normal;
-				}
+		</div>
 
-				h2 {
-					color: #454545;
-					font-size: 18px;
-					font-weight: normal;
+		<iframe></iframe>
 
-					margin-top: 20px;
-					margin-left: 20px;
-				}
+		<script src="list.js"></script>
 
-				h3 {
-					color: #666;
-					font-size: 16px;
-					font-weight: normal;
+		<script>
 
-					margin-top: 20px;
-					margin-left: 20px;
-				}
+			var panel = document.getElementById( 'panel' );
+			var content = document.getElementById( 'content' );
+			var clearFilterButton = document.getElementById( 'clearFilterButton' );
+			var expandButton = document.getElementById( 'expandButton' );
+			var filterInput = document.getElementById( 'filterInput' );
+			var iframe = document.querySelector( 'iframe' );
 
-			a {
-				color: #2194CE;
-				text-decoration: none;
-			}
+			var pageProperties = {};
+			var titles = {};
+			var categoryElements = [];
 
-			#panel {
-				position: fixed;
-				left: 0px;
-				width: 260px;
-				height: 100%;
-				overflow: auto;
-				background: #fafafa;
-			}
 
-				#panel ul {
-					list-style-type: none;
-					padding: 0px;
-					margin-left: 20px;
-				}
+// ----------------------------------------------------------------------------
+// Initialization
+// ----------------------------------------------------------------------------
 
-			#viewer {
-				position: absolute;
-				border: 0px;
-				left: 260px;
-				width: calc(100% - 260px);
-				height: 100%;
-				overflow: auto;
-			}
 
-			.filterBlock{
-				margin: 20px;
-				position: relative;
-			}
-			.filterBlock p {
-				margin: 0;
-			}
+			// Functionality for hamburger button (on small devices)
 
-			#filterInput {
-				width: 100%;
-				padding: 5px;
-				font-family: inherit;
-				font-size: 15px;
-				outline: none;
-				border: 1px solid #dedede;
-			}
+			expandButton.onclick = function ( event ) {
 
-			#filterInput:focus{
-				border: 1px solid #2194CE;
-			}
+				event.preventDefault();
+				panel.classList.toggle( 'collapsed' );
 
-			#clearFilterButton {
-				position: absolute;
-				right: 6px;
-				top: 50%;
-				margin-top: -8px;
-				width: 16px;
-				height: 16px;
-				font-size: 14px;
-				color: grey;
-				text-align: center;
-				line-height: 0;
-				padding-top: 7px;
-				opacity: .5;
-			}
+			};
 
-			#clearFilterButton:hover {
-				opacity: 1;
-			}
 
-			.filtered {
-				display: none;
-			}
+			// Functionality for search/filter input field
 
-			#panel li b {
-				font-weight: bold;
-			}
+			filterInput.oninput = function ( event ) {
 
-			/* mobile */
+				updateFilter();
 
-			#expandButton {
-				display: none;
-				position: absolute;
-				right: 20px;
-				top: 12px;
-				width: 32px;
-				height: 32px;
-			}
+			};
 
-				#expandButton span {
-					height: 2px;
-					background-color: #2194CE;
-					width: 16px;
-					position: absolute;
-					left: 8px;
-					top: 10px;
-				}
 
-				#expandButton span:nth-child(1) {
-					top: 16px;
-				}
+			// Functionality for filter clear button
 
-				#expandButton span:nth-child(2) {
-					top: 22px;
-				}
+			clearFilterButton.onclick = function ( event ) {
 
-			@media all and ( max-width: 640px ) {
-				h1{
-					margin-top: 20px;
-					margin-bottom: 20px;
-				}
-				#panel{
-					position: absolute;
-					left: 0;
-					top: 0;
-					height: 480px;
-					width: 100%;
-					right: 0;
-					z-index: 100;
-					overflow: hidden;
-					border-bottom: 1px solid #dedede;
-				}
-				#content{
-					position: absolute;
-					left: 0;
-					top: 90px;
-					right: 0;
-					bottom: 0;
-					font-size: 17px;
-					line-height: 22px;
-					overflow: auto;
-				}
-				#viewer{
-					position: absolute;
-					left: 0;
-					top: 56px;
-					width: 100%;
-					height: calc(100% - 56px);
-				}
-				#expandButton{
-					display: block;
-				}
-				#panel.collapsed{
-					height: 56px;
-				}
-			}
-		</style>
-	</head>
-	<body>
+				event.preventDefault();
 
-		<div id="panel" class="collapsed">
-			<h1><a href="http://threejs.org">three.js</a> / docs</h1>
-			<a id="expandButton" href="#">
-				<span></span>
-				<span></span>
-				<span></span>
-			</a>
-			<div class="filterBlock" >
-				<input type="text" id="filterInput" placeholder="Type to filter"/>
-				<a href="#" id="clearFilterButton" >x</a>
-			</div>
-			<div id="content"></div>
-		</div>
-		<iframe id="viewer"></iframe>
+				filterInput.value = '';
+				updateFilter();
 
-		<script src="list.js"></script>
-		<script>
+			};
 
-			function extractQuery() {
-				var p = window.location.search.indexOf( '?q=' );
-				if( p !== -1 ) {
-					return window.location.search.substr( 3 );
-				}
-				return ''
-			}
 
-			var panel = document.getElementById( 'panel' );
-			var viewer = document.getElementById( 'viewer' );
+			// Activate content and title change on browser navigation
 
-			var expandButton = document.getElementById( 'expandButton' );
-			expandButton.addEventListener( 'click', function ( event ) {
-				panel.classList.toggle( 'collapsed' );
-				event.preventDefault();
-			} );
+			window.onpopstate = createNewIframe;
 
-			var filterInput = document.getElementById( 'filterInput' );
-			var clearFilterButton = document.getElementById( 'clearFilterButton' );
 
-			var DELIMITER = '/';
-			var MEMBER_DELIMITER = '.';
-			var nameCategoryMap = {};
-			var sections = [];
+			// Create the navigation panel and configure the iframe
 
-			var content = document.getElementById( 'content' );
+			createNavigation();
+			createNewIframe();
+
+
+// ----------------------------------------------------------------------------
+// Navigation Panel
+// ----------------------------------------------------------------------------
+
+
+			function createNavigation () {
+
+				// Create the navigation panel using data from list.js
+
+				var navigation = createAndAppendDOMElement( { type: 'div', parent: content } );
+
+				for ( var section in list ) {
 
-			for ( var section in list ) {
+					// Create sections
 
-				var h2 = document.createElement( 'h2' );
-				h2.textContent = section;
+					var categories = list[ section ];
 
-				content.appendChild( h2 );
+					var sectionHead = createAndAppendDOMElement( { type: 'h2', parent: navigation, content: section } )
 
-				for ( var category in list[ section ] ) {
+					for ( var category in categories ) {
 
-					var div = document.createElement( 'div' );
+						// Create categories
 
-					var h3 = document.createElement( 'h3' );
-					h3.textContent = category;
+						var pages = categories[ category ];
 
-					div.appendChild( h3 );
+						var categoryContainer = createAndAppendDOMElement( { type: 'div', parent: navigation } );
+						var categoryHead = createAndAppendDOMElement( { type: 'h3', parent: categoryContainer, content: category } );
+						var categoryContent = createAndAppendDOMElement( { type: 'ul', parent: categoryContainer } );
 
-					var ul = document.createElement( 'ul' );
-					div.appendChild( ul );
+						for ( var pageName in pages ) {
 
-					for ( var i = 0; i < list[ section ][ category ].length; i ++ ) {
+							// Create page links
 
-						var page = list[ section ][ category ][ i ];
+							var pageURL = pages[ pageName ];
 
-						var li = document.createElement( 'li' );
-						var a = document.createElement( 'a' );
-						a.setAttribute( 'href', '#' );
-						( function( s, c, p ) {
-							a.addEventListener( 'click', function( e ) {
-								goTo( s, c, p );
-								e.preventDefault();
-							} )
-						} )( section, category, page[ 0 ] );
-						a.textContent = page[ 0 ];
-						li.appendChild( a );
-						ul.appendChild( li );
+							var listElement = createAndAppendDOMElement( { type: 'li', parent: categoryContent } );
+							var linkElement = createAndAppendDOMElement( { type: 'a', parent: listElement, content: pageName } );
 
-						nameCategoryMap[page[0]] = {
-							section: section,
-							category: category,
-							name: page[0],
-							element: a
-						};
+							// The href attribute is only used for the option to create a new tab by right click
+
+							linkElement.setAttribute( 'href', '#' + pageURL );
+
+							addClickHandlers( linkElement, pageURL );
+
+							// Gather the main properties for the current subpage
+
+							pageProperties[ pageName ] = {
+								section: section,
+								category: category,
+								pageURL: pageURL,
+								linkElement: linkElement
+							};
+
+						// Gather the document titles (used for easy access on browser navigation)
+
+						titles[ pageURL ] = pageName;
+
+						}
+
+						// Gather the category elements for easy access on filtering
+
+						categoryElements.push( categoryContent );
 
 					}
 
-					content.appendChild( div );
-					sections.push( ul );
+				}
+
+			};
+
+
+			function createAndAppendDOMElement( properties ) {
+
+				// Helper function for creating and appending new DOM elements
+
+				var newElement = document.createElement( properties.type );
+
+				properties.parent.appendChild( newElement );
+
+				if ( properties.content ) {
+
+					newElement.textContent = properties.content;
 
 				}
 
+				return newElement;
 
 			}
 
-			panel.appendChild( content );
 
-			function layoutList() {
+			function addClickHandlers ( linkElement, pageURL ) {
+
+				// Helper function for adding ClickHandlers to the page links
+
+				linkElement.onclick = function ( event ) {
+
+					event.preventDefault();
+
+					window.location.hash = pageURL;
+					createNewIframe();
+
+					panel.classList.add( 'collapsed' );
+
+				};
+
+			};
+
+
+// ----------------------------------------------------------------------------
+// Query Strings (optional)
+// ----------------------------------------------------------------------------
+
+
+//			(uncomment the following lines and the first line in updateFilter(), if you want query strings):
+
+//			filterInput.value = extractFromQueryString();
+//			updateFilter();
+//
+//
+//			function extractFromQueryString() {
+//
+//				var queryString = window.location.search;
+//
+//				if ( queryString.indexOf( '?q=' ) === -1 ) return '';
+//
+//				return queryString.substr( 3 );
+//
+//			}
+//
+//			function updateQueryString() {
+//
+//				var searchString = filterInput.value;
+//				var query = '';
+//
+//				if (searchString !== '') {
+//
+//					query = '?q=' + searchString;
+//
+//				}
+//
+//				window.history.replaceState( {} , '', window.location.pathname + query + window.location.hash ); 
+//
+//			}
+
+
+// ----------------------------------------------------------------------------
+// Filtering
+// ----------------------------------------------------------------------------
+
+
+			function updateFilter() {
+
+//			(uncomment the following line and the "Query strings" section, if you want query strings):
+//			updateQueryString();
+
+				var regExp = new RegExp( filterInput.value, 'gi' );
+
+				for ( var pageName in pageProperties ) {
+
+					var linkElement = pageProperties[ pageName ].linkElement;
+					var categoryClassList = linkElement.parentElement.classList;
+					var filterResults = pageName.match( regExp );
+
+					if ( filterResults && filterResults.length > 0 ) {
+
+						// Accentuate matching characters
+
+						for ( var i = 0; i < filterResults.length; i++ ) {
+
+							var result = filterResults[ i ];
+
+							if ( result !== '' ) {
+								pageName = pageName.replace( result, '<b>' + result + '</b>' );
+							}
 
-				sections.forEach( function( el ) {
-					var collapsed = true;
-					Array.prototype.slice.apply( el.children ).forEach( function( item ) {
-						if( !item.classList.contains( 'filtered' ) ) {
-							collapsed = false;
 						}
-					} );
-					if( collapsed ) {
-						el.parentElement.classList.add( 'filtered' );
+
+						categoryClassList.remove( 'hidden' );
+						linkElement.innerHTML = pageName;
+
 					} else {
-						el.parentElement.classList.remove( 'filtered' );
+
+						// Hide all non-matching page names
+
+						categoryClassList.add( 'hidden' );
+
 					}
-				} );
+
+				}
+
+				displayFilteredPanel();
+
 			}
 
-			filterInput.addEventListener( 'input', function( e ) {
-				updateFilter();
-			} );
 
-			clearFilterButton.addEventListener( 'click', function( e ) {
-				filterInput.value = '';
-				updateFilter();
-				e.preventDefault();
-			} );
+			function displayFilteredPanel() {
 
-			function updateFilter() {
+				// Show/hide categories depending on their content
+				// First check if at least one page in this category is not hidden
 
-				var v = filterInput.value;
-				if( v !== '' ) {
-					window.history.replaceState( {} , '', '?q=' + v + window.location.hash );
-				} else {
-					window.history.replaceState( {} , '', window.location.pathname + window.location.hash );
-				}
+				categoryElements.forEach( function ( category ) {
+
+					var pages = category.children;
+					var pagesLength = pages.length;
+					var sectionClassList = category.parentElement.classList;
+
+					var hideCategory = true;
+
+					for ( var i = 0; i < pagesLength; i ++ ) {
+
+						var pageClassList = pages[ i ].classList;
+
+						if ( ! pageClassList.contains( 'hidden' ) ) {
+
+							hideCategory = false;
 
-				var exp = new RegExp( filterInput.value, 'gi' );
-				for( var j in nameCategoryMap ) {
-					var res = nameCategoryMap[ j ].name.match( exp );
-					if( res && res.length > 0 ) {
-						nameCategoryMap[ j ].element.parentElement.classList.remove( 'filtered' );
-						var str = nameCategoryMap[ j ].name;
-						for( var i = 0; i < res.length; i++ ) {
-							str = str.replace( res[ i ], '<b>' + res[ i ] + '</b>' );
 						}
-						nameCategoryMap[ j ].element.innerHTML = str;
+
+					}
+
+					// If and only if all page names are hidden, hide the whole category
+
+					if ( hideCategory ) {
+
+						sectionClassList.add( 'hidden' );
+
 					} else {
-						nameCategoryMap[ j ].element.parentElement.classList.add( 'filtered' );
-						nameCategoryMap[ j ].element.textContent = nameCategoryMap[ j ].name;
+
+						sectionClassList.remove( 'hidden' );
+
 					}
-				}
-				layoutList();
+
+				} );
 
 			}
 
-			function encodeUrl( path ) {
 
-				return path.replace(/\ \/\ /g, '.').replace(/\ /g, '_');
+// ----------------------------------------------------------------------------
+// Routing
+// ----------------------------------------------------------------------------
 
-			}
 
-			function decodeUrl( path ) {
+			function setUrlFragment( pageName ) {
 
-				return path.replace(/_/g, ' ').replace(/\./g, ' / ');
+				// Handle navigation from the subpages (iframes):
+				// First separate the memeber (if existing) from the page name,
+				// then identify the subpage's URL and set it as URL fragment (re-adding the member)
 
-			}
+				var splitPageName = decomposePageName( pageName, '.', '.' );
 
-			// Page loading
+				var currentProperties = pageProperties[ splitPageName[ 0 ] ];
 
-			function goTo( section, category, name, member ) {
-				var parts, location;
+				if ( currentProperties ) {
 
-				// Fully resolve links that only provide a name
-				if(arguments.length == 1) {
+					window.location.hash = currentProperties.pageURL + splitPageName[ 1 ];
 
-					// Resolve links of the form 'Class.member'
-					if(section.indexOf(MEMBER_DELIMITER) !== -1) {
-						parts = section.split(MEMBER_DELIMITER);
-						section = parts[0];
-						member = parts[1];
-					}
+					createNewIframe();
 
-					location = nameCategoryMap[section];
-					if (!location) return;
-					section = location.section;
-					category = location.category;
-					name = location.name;
 				}
 
-				var title = 'three.js - documentation - ' + section + ' - ' + name;
-				var url = encodeUrl(section) + DELIMITER + encodeUrl( category ) + DELIMITER + encodeUrl(name) + (!!member ? MEMBER_DELIMITER + encodeUrl(member) : '');
+			}
+
+
+			function createNewIframe() {
+
+				// Change the content displayed in the iframe
+				// First separate the member part of the fragment (if existing)
+
+				var hash = window.location.hash.substring( 1 );
+				var splitHash = decomposePageName( hash, '.', '#' );
 
-				window.location.hash = url;
-				window.document.title = title;
+				// Creating a new Iframe instead of assigning a new src is
+				// a cross-browser solution to allow normal browser navigation;
+				// - only assigning a new src would result in two history states each time.
 
-				viewer.src = pages[ section ][ category ][ name ] + '.html' + (!!member ? '#'+member : '');
+				// Note: iframe.contentWindow.location.replace(hash) should work, too,
+				// but it doesn't work in Edge with links from the subpages!
 
-				panel.classList.add( 'collapsed' );
+				var oldIframe;
+				var subtitle;
+
+				oldIframe = iframe;
+				iframe = oldIframe.cloneNode();
+
+				if(hash) {
+
+					iframe.src = splitHash[ 0 ] + '.html' + splitHash[ 1 ];
+					subtitle = ' - ' + titles[ splitHash[ 0 ] ] + splitHash[ 1 ];
+
+				} else {
+
+					iframe.src = '';
+					subtitle = '';
+
+				}
+
+				document.body.replaceChild( iframe, oldIframe );
+				document.title = 'three.js docs' + subtitle;
 
 			}
 
-			function goToHash() {
 
-				var hash = window.location.hash.substring( 1 ).split(DELIMITER);
-				var member = hash[2].split(MEMBER_DELIMITER);
-				goTo( decodeUrl(hash[0]), decodeUrl(hash[1]), decodeUrl(member[0]), decodeUrl(member.length > 1 ? member[1] : '') );
+			function decomposePageName ( pageName, oldDelimiter, newDelimiter ) {
+
+				// Helper function for separating the member (if existing) from the pageName
+				// For example: 'Geometry.morphTarget' can be converted to 
+				// ['Geometry', '.morphTarget'] or ['Geometry', '#morphTarget']
+				// Note: According RFC 3986 no '#' allowed inside of an URL fragment!
+
+				var parts = [];
+
+				var dotIndex = pageName.indexOf( oldDelimiter );
+
+				if ( dotIndex !== -1 ) {
+
+					parts = pageName.split( oldDelimiter );
+					parts[ 1 ] = newDelimiter + parts[ 1 ];
+
+				} else {
+
+					parts[ 0 ] = pageName;
+					parts[ 1 ] = '';
+
+				}
+
+				return parts;
 
 			}
 
-			window.addEventListener( 'hashchange', goToHash, false );
 
-			if ( window.location.hash.length > 0 ) goToHash();
+// ----------------------------------------------------------------------------
+// ASCII Art ;-)
+// ----------------------------------------------------------------------------
+
 
 			console.log([
 				'    __     __',
@@ -431,10 +436,11 @@
 				'                                         \\/____/\\/_____/'
 			].join('\n'));
 
-			filterInput.value = extractQuery();
-			updateFilter( )
 
 		</script>
+
 		<script src="../build/three.min.js"></script> <!-- console sandbox -->
+
 	</body>
+
 </html>

+ 375 - 391
docs/list.js

@@ -1,413 +1,397 @@
 var list = {
 
 	"Manual": {
-		"Getting Started": [
-			[ "Creating a scene", "manual/introduction/Creating-a-scene" ],
-			[ "Detecting WebGL and browser compatibility", "manual/introduction/Detecting-WebGL-and-browser-compatibility" ],
-			[ "How to run things locally", "manual/introduction/How-to-run-thing-locally" ],
-			[ "Drawing Lines", "manual/introduction/Drawing-lines" ],
-			[ "Creating Text", "manual/introduction/Creating-text" ],
-			[ "Migration Guide", "manual/introduction/Migration-guide" ],
-			[ "Code Style Guide", "manual/introduction/Code-style-guide" ],
-			[ "FAQ", "manual/introduction/FAQ" ],
-			[ "Useful links", "manual/introduction/Useful-links" ]
-		],
-
-		"Next Steps": [
-			[ "How to update things", "manual/introduction/How-to-update-things" ],
-			[ "Matrix transformations", "manual/introduction/Matrix-transformations" ],
-            [ "Animation System", "manual/introduction/Animation-system" ]
-		],
-
-		"Build Tools": [
-			[ "Testing with NPM", "manual/buildTools/Testing-with-NPM" ]
-		]
+
+		"Getting Started": {
+			"Creating a scene": "manual/introduction/Creating-a-scene",
+			"WebGL compatibility check": "manual/introduction/WebGL-compatibility-check",
+			"How to run things locally": "manual/introduction/How-to-run-thing-locally",
+			"Drawing Lines": "manual/introduction/Drawing-lines",
+			"Creating Text": "manual/introduction/Creating-text",
+			"Migration Guide": "manual/introduction/Migration-guide",
+			"Code Style Guide": "manual/introduction/Code-style-guide",
+			"FAQ": "manual/introduction/FAQ",
+			"Useful links": "manual/introduction/Useful-links"
+		},
+
+		"Next Steps": {
+			"How to update things": "manual/introduction/How-to-update-things",
+			"Matrix transformations": "manual/introduction/Matrix-transformations",
+			"Animation System": "manual/introduction/Animation-system"
+		},
+
+		"Build Tools": {
+			"Testing with NPM": "manual/buildTools/Testing-with-NPM"
+		}
+
 	},
 
 	"Reference": {
 
-		"Animation": [
-			[ "AnimationAction", "api/animation/AnimationAction" ],
-			[ "AnimationClip", "api/animation/AnimationClip" ],
-			[ "AnimationMixer", "api/animation/AnimationMixer" ],
-			[ "AnimationObjectGroup", "api/animation/AnimationObjectGroup" ],
-			[ "AnimationUtils", "api/animation/AnimationUtils" ],
-			[ "KeyframeTrack", "api/animation/KeyframeTrack" ],
-			[ "PropertyBinding", "api/animation/PropertyBinding" ],
-			[ "PropertyMixer", "api/animation/PropertyMixer" ]
-		],
-
-		"Animation / Tracks": [
-		  [ "BooleanKeyframeTrack", "api/animation/tracks/BooleanKeyframeTrack" ],
-		  [ "ColorKeyframeTrack", "api/animation/tracks/ColorKeyframeTrack" ],
-		  [ "NumberKeyframeTrack", "api/animation/tracks/NumberKeyframeTrack" ],
-		  [ "QuaternionKeyframeTrack", "api/animation/tracks/QuaternionKeyframeTrack" ],
-		  [ "StringKeyframeTrack", "api/animation/tracks/StringKeyframeTrack" ],
-		  [ "VectorKeyframeTrack", "api/animation/tracks/VectorKeyframeTrack" ]
-		],
-
-		"Audio": [
-			[ "Audio", "api/audio/Audio" ],
-			[ "AudioAnalyser", "api/audio/AudioAnalyser" ],
-			[ "AudioContext", "api/audio/AudioContext" ],
-			[ "AudioListener", "api/audio/AudioListener" ],
-			[ "PositionalAudio", "api/audio/PositionalAudio" ]
-		],
-
-		"Cameras": [
-			[ "Camera", "api/cameras/Camera" ],
-			[ "CubeCamera", "api/cameras/CubeCamera" ],
-			[ "OrthographicCamera", "api/cameras/OrthographicCamera" ],
-			[ "PerspectiveCamera", "api/cameras/PerspectiveCamera" ],
-			[ "StereoCamera", "api/cameras/StereoCamera" ]
-		],
-
-		"Constants": [
-			[ "Animation", "api/constants/Animation" ],
-			[ "Core", "api/constants/Core" ],
-			[ "CustomBlendingEquation", "api/constants/CustomBlendingEquations" ],
-			[ "DrawModes", "api/constants/DrawModes" ],
-			[ "Materials", "api/constants/Materials" ],
-			[ "Renderer", "api/constants/Renderer" ],
-			[ "Textures", "api/constants/Textures" ]
-		],
-
-		"Core": [
-			[ "BufferAttribute", "api/core/BufferAttribute" ],
-			[ "BufferGeometry", "api/core/BufferGeometry" ],
-			[ "Clock", "api/core/Clock" ],
-			[ "DirectGeometry", "api/core/DirectGeometry" ],
-			[ "EventDispatcher", "api/core/EventDispatcher" ],
-			[ "Face3", "api/core/Face3" ],
-			[ "Geometry", "api/core/Geometry" ],
-			[ "InstancedBufferAttribute", "api/core/InstancedBufferAttribute" ],
-			[ "InstancedBufferGeometry", "api/core/InstancedBufferGeometry" ],
-			[ "InstancedInterleavedBuffer", "api/core/InstancedInterleavedBuffer" ],
-			[ "InterleavedBuffer", "api/core/InterleavedBuffer" ],
-			[ "InterleavedBufferAttribute", "api/core/InterleavedBufferAttribute" ],
-			[ "Layers", "api/core/Layers" ],
-			[ "Object3D", "api/core/Object3D" ],
-			[ "Raycaster", "api/core/Raycaster" ],
-			[ "Uniform", "api/core/Uniform" ]
-		],
-
-		"Core / BufferAttributes": [
-			[ "BufferAttribute Types", "api/core/bufferAttributeTypes/BufferAttributeTypes" ]
-		],
-
-		"Deprecated": [
-			[ "DeprecatedList", "api/deprecated/DeprecatedList" ]
-		],
-
-		"Extras": [
-			[ "CurveUtils", "api/extras/CurveUtils" ],
-			[ "SceneUtils", "api/extras/SceneUtils" ],
-			[ "ShapeUtils", "api/extras/ShapeUtils" ]
-		],
-
-		"Extras / Core": [
-			[ "Curve", "api/extras/core/Curve" ],
-			[ "CurvePath", "api/extras/core/CurvePath" ],
-			[ "Font", "api/extras/core/Font" ],
-			[ "Path", "api/extras/core/Path" ],
-			[ "Shape", "api/extras/core/Shape" ],
-			[ "ShapePath", "api/extras/core/ShapePath" ]
-		],
-
-		"Extras / Curves": [
-			[ "ArcCurve", "api/extras/curves/ArcCurve" ],
-			[ "CatmullRomCurve3", "api/extras/curves/CatmullRomCurve3" ],
-			[ "CubicBezierCurve", "api/extras/curves/CubicBezierCurve" ],
-			[ "CubicBezierCurve3", "api/extras/curves/CubicBezierCurve3" ],
-			[ "EllipseCurve", "api/extras/curves/EllipseCurve" ],
-			[ "LineCurve", "api/extras/curves/LineCurve" ],
-			[ "LineCurve3", "api/extras/curves/LineCurve3" ],
-			[ "QuadraticBezierCurve", "api/extras/curves/QuadraticBezierCurve" ],
-			[ "QuadraticBezierCurve3", "api/extras/curves/QuadraticBezierCurve3" ],
-			[ "SplineCurve", "api/extras/curves/SplineCurve" ]
-		],
-
-		"Extras / Objects": [
-			[ "ImmediateRenderObject", "api/extras/objects/ImmediateRenderObject" ],
-			[ "MorphBlendMesh", "api/extras/objects/MorphBlendMesh" ]
-		],
-
-		"Geometries": [
-			[ "BoxBufferGeometry", "api/geometries/BoxBufferGeometry" ],
-			[ "BoxGeometry", "api/geometries/BoxGeometry" ],
-			[ "CircleBufferGeometry", "api/geometries/CircleBufferGeometry" ],
-			[ "CircleGeometry", "api/geometries/CircleGeometry" ],
-			[ "ConeBufferGeometry", "api/geometries/ConeBufferGeometry" ],
-			[ "ConeGeometry", "api/geometries/ConeGeometry" ],
-			[ "CylinderBufferGeometry", "api/geometries/CylinderBufferGeometry" ],
-			[ "CylinderGeometry", "api/geometries/CylinderGeometry" ],
-			[ "DodecahedronBufferGeometry", "api/geometries/DodecahedronBufferGeometry" ],
-			[ "DodecahedronGeometry", "api/geometries/DodecahedronGeometry" ],
-			[ "EdgesGeometry", "api/geometries/EdgesGeometry" ],
-			[ "ExtrudeGeometry", "api/geometries/ExtrudeGeometry" ],
-			[ "ExtrudeBufferGeometry", "api/geometries/ExtrudeBufferGeometry" ],
-			[ "IcosahedronBufferGeometry", "api/geometries/IcosahedronBufferGeometry" ],
-			[ "IcosahedronGeometry", "api/geometries/IcosahedronGeometry" ],
-			[ "LatheBufferGeometry", "api/geometries/LatheBufferGeometry" ],
-			[ "LatheGeometry", "api/geometries/LatheGeometry" ],
-			[ "OctahedronBufferGeometry", "api/geometries/OctahedronBufferGeometry" ],
-			[ "OctahedronGeometry", "api/geometries/OctahedronGeometry" ],
-			[ "ParametricBufferGeometry", "api/geometries/ParametricBufferGeometry" ],
-			[ "ParametricGeometry", "api/geometries/ParametricGeometry" ],
-			[ "PlaneBufferGeometry", "api/geometries/PlaneBufferGeometry" ],
-			[ "PlaneGeometry", "api/geometries/PlaneGeometry" ],
-			[ "PolyhedronBufferGeometry", "api/geometries/PolyhedronBufferGeometry" ],
-			[ "PolyhedronGeometry", "api/geometries/PolyhedronGeometry" ],
-			[ "RingBufferGeometry", "api/geometries/RingBufferGeometry" ],
-			[ "RingGeometry", "api/geometries/RingGeometry" ],
-			[ "ShapeBufferGeometry", "api/geometries/ShapeBufferGeometry" ],
-			[ "ShapeGeometry", "api/geometries/ShapeGeometry" ],
-			[ "SphereBufferGeometry", "api/geometries/SphereBufferGeometry" ],
-			[ "SphereGeometry", "api/geometries/SphereGeometry" ],
-			[ "TetrahedronBufferGeometry", "api/geometries/TetrahedronBufferGeometry" ],
-			[ "TetrahedronGeometry", "api/geometries/TetrahedronGeometry" ],
-			[ "TextGeometry", "api/geometries/TextGeometry" ],
-			[ "TorusBufferGeometry", "api/geometries/TorusBufferGeometry" ],
-			[ "TorusGeometry", "api/geometries/TorusGeometry" ],
-			[ "TorusKnotBufferGeometry", "api/geometries/TorusKnotBufferGeometry" ],
-			[ "TorusKnotGeometry", "api/geometries/TorusKnotGeometry" ],
-			[ "TubeGeometry", "api/geometries/TubeGeometry" ],
-			[ "TubeBufferGeometry", "api/geometries/TubeBufferGeometry" ],
-			[ "WireframeGeometry", "api/geometries/WireframeGeometry" ]
-		],
-
-		"Helpers": [
-			[ "ArrowHelper", "api/helpers/ArrowHelper" ],
-			[ "AxisHelper", "api/helpers/AxisHelper" ],
-			[ "BoxHelper", "api/helpers/BoxHelper" ],
-			[ "CameraHelper", "api/helpers/CameraHelper" ],
-			[ "DirectionalLightHelper", "api/helpers/DirectionalLightHelper" ],
-			[ "FaceNormalsHelper", "api/helpers/FaceNormalsHelper" ],
-			[ "GridHelper", "api/helpers/GridHelper" ],
-			[ "PolarGridHelper", "api/helpers/PolarGridHelper" ],
-			[ "HemisphereLightHelper", "api/helpers/HemisphereLightHelper" ],
-			[ "PointLightHelper", "api/helpers/PointLightHelper" ],
-			[ "RectAreaLightHelper", "api/helpers/RectAreaLightHelper" ],
-			[ "SkeletonHelper", "api/helpers/SkeletonHelper" ],
-			[ "SpotLightHelper", "api/helpers/SpotLightHelper" ],
-			[ "VertexNormalsHelper", "api/helpers/VertexNormalsHelper" ]
-		],
-
-		"Lights": [
-			[ "AmbientLight", "api/lights/AmbientLight" ],
-			[ "DirectionalLight", "api/lights/DirectionalLight" ],
-			[ "HemisphereLight", "api/lights/HemisphereLight" ],
-			[ "Light", "api/lights/Light" ],
-			[ "PointLight", "api/lights/PointLight" ],
-			[ "RectAreaLight", "api/lights/RectAreaLight" ],
-			[ "SpotLight", "api/lights/SpotLight" ]
-		],
-
-		"Lights / Shadows": [
-			[ "DirectionalLightShadow", "api/lights/shadows/DirectionalLightShadow" ],
-			[ "LightShadow", "api/lights/shadows/LightShadow" ],
-			[ "RectAreaLightShadow", "api/lights/shadows/RectAreaLightShadow" ],
-			[ "SpotLightShadow", "api/lights/shadows/SpotLightShadow" ]
-		],
-
-		"Loaders": [
-			[ "AnimationLoader", "api/loaders/AnimationLoader" ],
-			[ "AudioLoader", "api/loaders/AudioLoader" ],
-			[ "BufferGeometryLoader", "api/loaders/BufferGeometryLoader" ],
-			[ "Cache", "api/loaders/Cache" ],
-			[ "CompressedTextureLoader", "api/loaders/CompressedTextureLoader" ],
-			[ "CubeTextureLoader", "api/loaders/CubeTextureLoader" ],
-			[ "DataTextureLoader", "api/loaders/DataTextureLoader" ],
-			[ "FileLoader", "api/loaders/FileLoader" ],
-			[ "FontLoader", "api/loaders/FontLoader" ],
-			[ "ImageLoader", "api/loaders/ImageLoader" ],
-			[ "JSONLoader", "api/loaders/JSONLoader" ],
-			[ "Loader", "api/loaders/Loader" ],
-			[ "MaterialLoader", "api/loaders/MaterialLoader" ],
-			[ "ObjectLoader", "api/loaders/ObjectLoader" ],
-			[ "TextureLoader", "api/loaders/TextureLoader" ]
-		],
-
-		"Loaders / Managers": [
-			[ "DefaultLoadingManager", "api/loaders/managers/DefaultLoadingManager" ],
-			[ "LoadingManager", "api/loaders/managers/LoadingManager" ]
-		],
-
-		"Materials": [
-			[ "LineBasicMaterial", "api/materials/LineBasicMaterial" ],
-			[ "LineDashedMaterial", "api/materials/LineDashedMaterial" ],
-			[ "Material", "api/materials/Material" ],
-			[ "MeshBasicMaterial", "api/materials/MeshBasicMaterial" ],
-			[ "MeshDepthMaterial", "api/materials/MeshDepthMaterial" ],
-			[ "MeshLambertMaterial", "api/materials/MeshLambertMaterial" ],
-			[ "MeshNormalMaterial", "api/materials/MeshNormalMaterial" ],
-			[ "MeshPhongMaterial", "api/materials/MeshPhongMaterial" ],
-			[ "MeshPhysicalMaterial", "api/materials/MeshPhysicalMaterial" ],
-			[ "MeshStandardMaterial", "api/materials/MeshStandardMaterial" ],
-			[ "MeshToonMaterial", "api/materials/MeshToonMaterial" ],
-			[ "PointsMaterial", "api/materials/PointsMaterial" ],
-			[ "RawShaderMaterial", "api/materials/RawShaderMaterial" ],
-			[ "ShaderMaterial", "api/materials/ShaderMaterial" ],
-			[ "ShadowMaterial", "api/materials/ShadowMaterial" ],
-			[ "SpriteMaterial", "api/materials/SpriteMaterial" ]
-		],
-
-		"Math": [
-			[ "Box2", "api/math/Box2" ],
-			[ "Box3", "api/math/Box3" ],
-			[ "Color", "api/math/Color" ],
-			[ "Cylindrical", "api/math/Cylindrical" ],
-			[ "Euler", "api/math/Euler" ],
-			[ "Frustum", "api/math/Frustum" ],
-			[ "Interpolant", "api/math/Interpolant" ],
-			[ "Line3", "api/math/Line3" ],
-			[ "Math", "api/math/Math" ],
-			[ "Matrix3", "api/math/Matrix3" ],
-			[ "Matrix4", "api/math/Matrix4" ],
-			[ "Plane", "api/math/Plane" ],
-			[ "Quaternion", "api/math/Quaternion" ],
-			[ "Ray", "api/math/Ray" ],
-			[ "Sphere", "api/math/Sphere" ],
-			[ "Spherical", "api/math/Spherical" ],
-			[ "Triangle", "api/math/Triangle" ],
-			[ "Vector2", "api/math/Vector2" ],
-			[ "Vector3", "api/math/Vector3" ],
-			[ "Vector4", "api/math/Vector4" ]
-		],
-
-		"Math / Interpolants": [
-			[ "CubicInterpolant", "api/math/interpolants/CubicInterpolant" ],
-			[ "DiscreteInterpolant", "api/math/interpolants/DiscreteInterpolant" ],
-			[ "LinearInterpolant", "api/math/interpolants/LinearInterpolant" ],
-			[ "QuaternionLinearInterpolant", "api/math/interpolants/QuaternionLinearInterpolant" ]
-		],
-
-		"Objects": [
-			[ "Bone", "api/objects/Bone" ],
-			[ "Group", "api/objects/Group" ],
-			[ "LensFlare", "api/objects/LensFlare" ],
-			[ "Line", "api/objects/Line" ],
-			[ "LineLoop", "api/objects/LineLoop" ],
-			[ "LineSegments", "api/objects/LineSegments" ],
-			[ "LOD", "api/objects/LOD" ],
-			[ "Mesh", "api/objects/Mesh" ],
-			[ "Points", "api/objects/Points" ],
-			[ "Skeleton", "api/objects/Skeleton" ],
-			[ "SkinnedMesh", "api/objects/SkinnedMesh" ],
-			[ "Sprite", "api/objects/Sprite" ]
-		],
-
-		"Renderers": [
-			[ "WebGLRenderer", "api/renderers/WebGLRenderer" ],
-			[ "WebGLRenderTarget", "api/renderers/WebGLRenderTarget" ],
-			[ "WebGLRenderTargetCube", "api/renderers/WebGLRenderTargetCube" ]
-		],
-
-		"Renderers / Shaders": [
-			[ "ShaderChunk", "api/renderers/shaders/ShaderChunk" ],
-			[ "ShaderLib", "api/renderers/shaders/ShaderLib" ],
-			[ "UniformsLib", "api/renderers/shaders/UniformsLib" ],
-			[ "UniformsUtils", "api/renderers/shaders/UniformsUtils" ]
-		],
-
-		"Scenes": [
-			[ "Fog", "api/scenes/Fog" ],
-			[ "FogExp2", "api/scenes/FogExp2" ],
-			[ "Scene", "api/scenes/Scene" ]
-		],
-
-		"Textures": [
-			[ "CanvasTexture", "api/textures/CanvasTexture" ],
-			[ "CompressedTexture", "api/textures/CompressedTexture" ],
-			[ "CubeTexture", "api/textures/CubeTexture" ],
-			[ "DataTexture", "api/textures/DataTexture" ],
-			[ "DepthTexture", "api/textures/DepthTexture" ],
-			[ "Texture", "api/textures/Texture" ],
-			[ "VideoTexture", "api/textures/VideoTexture" ]
-		]
+		"Animation": {
+			"AnimationAction": "api/animation/AnimationAction",
+			"AnimationClip": "api/animation/AnimationClip",
+			"AnimationMixer": "api/animation/AnimationMixer",
+			"AnimationObjectGroup": "api/animation/AnimationObjectGroup",
+			"AnimationUtils": "api/animation/AnimationUtils",
+			"KeyframeTrack": "api/animation/KeyframeTrack",
+			"PropertyBinding": "api/animation/PropertyBinding",
+			"PropertyMixer": "api/animation/PropertyMixer"
+		},
+
+		"Animation / Tracks": {
+			"BooleanKeyframeTrack": "api/animation/tracks/BooleanKeyframeTrack",
+			"ColorKeyframeTrack": "api/animation/tracks/ColorKeyframeTrack",
+			"NumberKeyframeTrack": "api/animation/tracks/NumberKeyframeTrack",
+			"QuaternionKeyframeTrack": "api/animation/tracks/QuaternionKeyframeTrack",
+			"StringKeyframeTrack": "api/animation/tracks/StringKeyframeTrack",
+			"VectorKeyframeTrack": "api/animation/tracks/VectorKeyframeTrack"
+		},
+
+		"Audio": {
+			"Audio": "api/audio/Audio",
+			"AudioAnalyser": "api/audio/AudioAnalyser",
+			"AudioContext": "api/audio/AudioContext",
+			"AudioListener": "api/audio/AudioListener",
+			"PositionalAudio": "api/audio/PositionalAudio"
+		},
+
+		"Cameras": {
+			"Camera": "api/cameras/Camera",
+			"CubeCamera": "api/cameras/CubeCamera",
+			"OrthographicCamera": "api/cameras/OrthographicCamera",
+			"PerspectiveCamera": "api/cameras/PerspectiveCamera",
+			"StereoCamera": "api/cameras/StereoCamera"
+		},
+
+		"Constants": {
+			"Animation": "api/constants/Animation",
+			"Core": "api/constants/Core",
+			"CustomBlendingEquation": "api/constants/CustomBlendingEquations",
+			"DrawModes": "api/constants/DrawModes",
+			"Materials": "api/constants/Materials",
+			"Renderer": "api/constants/Renderer",
+			"Textures": "api/constants/Textures"
+		},
+
+		"Core": {
+			"BufferAttribute": "api/core/BufferAttribute",
+			"BufferGeometry": "api/core/BufferGeometry",
+			"Clock": "api/core/Clock",
+			"DirectGeometry": "api/core/DirectGeometry",
+			"EventDispatcher": "api/core/EventDispatcher",
+			"Face3": "api/core/Face3",
+			"Geometry": "api/core/Geometry",
+			"InstancedBufferAttribute": "api/core/InstancedBufferAttribute",
+			"InstancedBufferGeometry": "api/core/InstancedBufferGeometry",
+			"InstancedInterleavedBuffer": "api/core/InstancedInterleavedBuffer",
+			"InterleavedBuffer": "api/core/InterleavedBuffer",
+			"InterleavedBufferAttribute": "api/core/InterleavedBufferAttribute",
+			"Layers": "api/core/Layers",
+			"Object3D": "api/core/Object3D",
+			"Raycaster": "api/core/Raycaster",
+			"Uniform": "api/core/Uniform"
+		},
+
+		"Core / BufferAttributes": {
+			"BufferAttribute Types": "api/core/bufferAttributeTypes/BufferAttributeTypes"
+		},
+
+		"Deprecated": {
+			"DeprecatedList": "api/deprecated/DeprecatedList"
+		},
+
+		"Extras": {
+			"CurveUtils": "api/extras/CurveUtils",
+			"SceneUtils": "api/extras/SceneUtils",
+			"ShapeUtils": "api/extras/ShapeUtils"
+		},
+
+		"Extras / Core": {
+			"Curve": "api/extras/core/Curve",
+			"CurvePath": "api/extras/core/CurvePath",
+			"Font": "api/extras/core/Font",
+			"Path": "api/extras/core/Path",
+			"Shape": "api/extras/core/Shape",
+			"ShapePath": "api/extras/core/ShapePath"
+		},
+
+		"Extras / Curves": {
+			"ArcCurve": "api/extras/curves/ArcCurve",
+			"CatmullRomCurve3": "api/extras/curves/CatmullRomCurve3",
+			"CubicBezierCurve": "api/extras/curves/CubicBezierCurve",
+			"CubicBezierCurve3": "api/extras/curves/CubicBezierCurve3",
+			"EllipseCurve": "api/extras/curves/EllipseCurve",
+			"LineCurve": "api/extras/curves/LineCurve",
+			"LineCurve3": "api/extras/curves/LineCurve3",
+			"QuadraticBezierCurve": "api/extras/curves/QuadraticBezierCurve",
+			"QuadraticBezierCurve3": "api/extras/curves/QuadraticBezierCurve3",
+			"SplineCurve": "api/extras/curves/SplineCurve"
+		},
+
+		"Extras / Objects": {
+			"ImmediateRenderObject": "api/extras/objects/ImmediateRenderObject",
+			"MorphBlendMesh": "api/extras/objects/MorphBlendMesh"
+		},
+
+		"Geometries": {
+			"BoxBufferGeometry": "api/geometries/BoxBufferGeometry",
+			"BoxGeometry": "api/geometries/BoxGeometry",
+			"CircleBufferGeometry": "api/geometries/CircleBufferGeometry",
+			"CircleGeometry": "api/geometries/CircleGeometry",
+			"ConeBufferGeometry": "api/geometries/ConeBufferGeometry",
+			"ConeGeometry": "api/geometries/ConeGeometry",
+			"CylinderBufferGeometry": "api/geometries/CylinderBufferGeometry",
+			"CylinderGeometry": "api/geometries/CylinderGeometry",
+			"DodecahedronBufferGeometry": "api/geometries/DodecahedronBufferGeometry",
+			"DodecahedronGeometry": "api/geometries/DodecahedronGeometry",
+			"EdgesGeometry": "api/geometries/EdgesGeometry",
+			"ExtrudeGeometry": "api/geometries/ExtrudeGeometry",
+			"ExtrudeBufferGeometry": "api/geometries/ExtrudeBufferGeometry",
+			"IcosahedronBufferGeometry": "api/geometries/IcosahedronBufferGeometry",
+			"IcosahedronGeometry": "api/geometries/IcosahedronGeometry",
+			"LatheBufferGeometry": "api/geometries/LatheBufferGeometry",
+			"LatheGeometry": "api/geometries/LatheGeometry",
+			"OctahedronBufferGeometry": "api/geometries/OctahedronBufferGeometry",
+			"OctahedronGeometry": "api/geometries/OctahedronGeometry",
+			"ParametricBufferGeometry": "api/geometries/ParametricBufferGeometry",
+			"ParametricGeometry": "api/geometries/ParametricGeometry",
+			"PlaneBufferGeometry": "api/geometries/PlaneBufferGeometry",
+			"PlaneGeometry": "api/geometries/PlaneGeometry",
+			"PolyhedronBufferGeometry": "api/geometries/PolyhedronBufferGeometry",
+			"PolyhedronGeometry": "api/geometries/PolyhedronGeometry",
+			"RingBufferGeometry": "api/geometries/RingBufferGeometry",
+			"RingGeometry": "api/geometries/RingGeometry",
+			"ShapeBufferGeometry": "api/geometries/ShapeBufferGeometry",
+			"ShapeGeometry": "api/geometries/ShapeGeometry",
+			"SphereBufferGeometry": "api/geometries/SphereBufferGeometry",
+			"SphereGeometry": "api/geometries/SphereGeometry",
+			"TetrahedronBufferGeometry": "api/geometries/TetrahedronBufferGeometry",
+			"TetrahedronGeometry": "api/geometries/TetrahedronGeometry",
+			"TextGeometry": "api/geometries/TextGeometry",
+			"TorusBufferGeometry": "api/geometries/TorusBufferGeometry",
+			"TorusGeometry": "api/geometries/TorusGeometry",
+			"TorusKnotBufferGeometry": "api/geometries/TorusKnotBufferGeometry",
+			"TorusKnotGeometry": "api/geometries/TorusKnotGeometry",
+			"TubeGeometry": "api/geometries/TubeGeometry",
+			"TubeBufferGeometry": "api/geometries/TubeBufferGeometry",
+			"WireframeGeometry": "api/geometries/WireframeGeometry"
+		},
+
+		"Helpers": {
+			"ArrowHelper": "api/helpers/ArrowHelper",
+			"AxisHelper": "api/helpers/AxisHelper",
+			"BoxHelper": "api/helpers/BoxHelper",
+			"CameraHelper": "api/helpers/CameraHelper",
+			"DirectionalLightHelper": "api/helpers/DirectionalLightHelper",
+			"FaceNormalsHelper": "api/helpers/FaceNormalsHelper",
+			"GridHelper": "api/helpers/GridHelper",
+			"PolarGridHelper": "api/helpers/PolarGridHelper",
+			"HemisphereLightHelper": "api/helpers/HemisphereLightHelper",
+			"PointLightHelper": "api/helpers/PointLightHelper",
+			"RectAreaLightHelper": "api/helpers/RectAreaLightHelper",
+			"SkeletonHelper": "api/helpers/SkeletonHelper",
+			"SpotLightHelper": "api/helpers/SpotLightHelper",
+			"VertexNormalsHelper": "api/helpers/VertexNormalsHelper"
+		},
+
+		"Lights": {
+			"AmbientLight": "api/lights/AmbientLight",
+			"DirectionalLight": "api/lights/DirectionalLight",
+			"HemisphereLight": "api/lights/HemisphereLight",
+			"Light": "api/lights/Light",
+			"PointLight": "api/lights/PointLight",
+			"RectAreaLight": "api/lights/RectAreaLight",
+			"SpotLight": "api/lights/SpotLight"
+		},
+
+		"Lights / Shadows": {
+			"DirectionalLightShadow": "api/lights/shadows/DirectionalLightShadow",
+			"LightShadow": "api/lights/shadows/LightShadow",
+			"RectAreaLightShadow": "api/lights/shadows/RectAreaLightShadow",
+			"SpotLightShadow": "api/lights/shadows/SpotLightShadow"
+		},
+
+		"Loaders": {
+			"AnimationLoader": "api/loaders/AnimationLoader",
+			"AudioLoader": "api/loaders/AudioLoader",
+			"BufferGeometryLoader": "api/loaders/BufferGeometryLoader",
+			"Cache": "api/loaders/Cache",
+			"CompressedTextureLoader": "api/loaders/CompressedTextureLoader",
+			"CubeTextureLoader": "api/loaders/CubeTextureLoader",
+			"DataTextureLoader": "api/loaders/DataTextureLoader",
+			"FileLoader": "api/loaders/FileLoader",
+			"FontLoader": "api/loaders/FontLoader",
+			"ImageLoader": "api/loaders/ImageLoader",
+			"JSONLoader": "api/loaders/JSONLoader",
+			"Loader": "api/loaders/Loader",
+			"MaterialLoader": "api/loaders/MaterialLoader",
+			"ObjectLoader": "api/loaders/ObjectLoader",
+			"TextureLoader": "api/loaders/TextureLoader"
+		},
+
+		"Loaders / Managers": {
+			"DefaultLoadingManager": "api/loaders/managers/DefaultLoadingManager",
+			"LoadingManager": "api/loaders/managers/LoadingManager"
+		},
+
+		"Materials": {
+			"LineBasicMaterial": "api/materials/LineBasicMaterial",
+			"LineDashedMaterial": "api/materials/LineDashedMaterial",
+			"Material": "api/materials/Material",
+			"MeshBasicMaterial": "api/materials/MeshBasicMaterial",
+			"MeshDepthMaterial": "api/materials/MeshDepthMaterial",
+			"MeshLambertMaterial": "api/materials/MeshLambertMaterial",
+			"MeshNormalMaterial": "api/materials/MeshNormalMaterial",
+			"MeshPhongMaterial": "api/materials/MeshPhongMaterial",
+			"MeshPhysicalMaterial": "api/materials/MeshPhysicalMaterial",
+			"MeshStandardMaterial": "api/materials/MeshStandardMaterial",
+			"MeshToonMaterial": "api/materials/MeshToonMaterial",
+			"PointsMaterial": "api/materials/PointsMaterial",
+			"RawShaderMaterial": "api/materials/RawShaderMaterial",
+			"ShaderMaterial": "api/materials/ShaderMaterial",
+			"ShadowMaterial": "api/materials/ShadowMaterial",
+			"SpriteMaterial": "api/materials/SpriteMaterial"
+		},
+
+		"Math": {
+			"Box2": "api/math/Box2",
+			"Box3": "api/math/Box3",
+			"Color": "api/math/Color",
+			"Cylindrical": "api/math/Cylindrical",
+			"Euler": "api/math/Euler",
+			"Frustum": "api/math/Frustum",
+			"Interpolant": "api/math/Interpolant",
+			"Line3": "api/math/Line3",
+			"Math": "api/math/Math",
+			"Matrix3": "api/math/Matrix3",
+			"Matrix4": "api/math/Matrix4",
+			"Plane": "api/math/Plane",
+			"Quaternion": "api/math/Quaternion",
+			"Ray": "api/math/Ray",
+			"Sphere": "api/math/Sphere",
+			"Spherical": "api/math/Spherical",
+			"Triangle": "api/math/Triangle",
+			"Vector2": "api/math/Vector2",
+			"Vector3": "api/math/Vector3",
+			"Vector4": "api/math/Vector4"
+		},
+
+		"Math / Interpolants": {
+			"CubicInterpolant": "api/math/interpolants/CubicInterpolant",
+			"DiscreteInterpolant": "api/math/interpolants/DiscreteInterpolant",
+			"LinearInterpolant": "api/math/interpolants/LinearInterpolant",
+			"QuaternionLinearInterpolant": "api/math/interpolants/QuaternionLinearInterpolant"
+		},
+
+		"Objects": {
+			"Bone": "api/objects/Bone",
+			"Group": "api/objects/Group",
+			"LensFlare": "api/objects/LensFlare",
+			"Line": "api/objects/Line",
+			"LineLoop": "api/objects/LineLoop",
+			"LineSegments": "api/objects/LineSegments",
+			"LOD": "api/objects/LOD",
+			"Mesh": "api/objects/Mesh",
+			"Points": "api/objects/Points",
+			"Skeleton": "api/objects/Skeleton",
+			"SkinnedMesh": "api/objects/SkinnedMesh",
+			"Sprite": "api/objects/Sprite"
+		},
+
+		"Renderers": {
+			"WebGLRenderer": "api/renderers/WebGLRenderer",
+			"WebGLRenderTarget": "api/renderers/WebGLRenderTarget",
+			"WebGLRenderTargetCube": "api/renderers/WebGLRenderTargetCube"
+		},
+
+		"Renderers / Shaders": {
+			"ShaderChunk": "api/renderers/shaders/ShaderChunk",
+			"ShaderLib": "api/renderers/shaders/ShaderLib",
+			"UniformsLib": "api/renderers/shaders/UniformsLib",
+			"UniformsUtils": "api/renderers/shaders/UniformsUtils"
+		},
+
+		"Scenes": {
+			"Fog": "api/scenes/Fog",
+			"FogExp2": "api/scenes/FogExp2",
+			"Scene": "api/scenes/Scene"
+		},
+
+		"Textures": {
+			"CanvasTexture": "api/textures/CanvasTexture",
+			"CompressedTexture": "api/textures/CompressedTexture",
+			"CubeTexture": "api/textures/CubeTexture",
+			"DataTexture": "api/textures/DataTexture",
+			"DepthTexture": "api/textures/DepthTexture",
+			"Texture": "api/textures/Texture",
+			"VideoTexture": "api/textures/VideoTexture"
+		}
 
 	},
 
 	"Examples": {
 
-		"Collada Animation": [
-			[ "ColladaAnimation", "examples/collada/Animation" ],
-			[ "AnimationHandler", "examples/collada/AnimationHandler" ],
-			[ "KeyFrameAnimation", "examples/collada/KeyFrameAnimation" ]
-		],
-
-		"Geometries": [
-			[ "ConvexBufferGeometry", "examples/geometries/ConvexBufferGeometry" ],
-			[ "ConvexGeometry", "examples/geometries/ConvexGeometry" ]
-		],
-
-		"Loaders": [
-			[ "BabylonLoader", "examples/loaders/BabylonLoader" ],
-			[ "ColladaLoader", "examples/loaders/ColladaLoader" ],
-			[ "GLTF2Loader", "examples/loaders/GLTF2Loader" ],
-			[ "MTLLoader", "examples/loaders/MTLLoader" ],
-			[ "OBJLoader", "examples/loaders/OBJLoader" ],
-			[ "PCDLoader", "examples/loaders/PCDLoader" ],
-			[ "PDBLoader", "examples/loaders/PDBLoader" ],
-			[ "SVGLoader", "examples/loaders/SVGLoader" ],
-			[ "TGALoader", "examples/loaders/TGALoader" ]
-		],
-
-		"Plugins": [
-			[ "CombinedCamera", "examples/cameras/CombinedCamera" ],
-			[ "LookupTable", "examples/Lut" ],
-			[ "SpriteCanvasMaterial", "examples/SpriteCanvasMaterial" ]
-		],
-
-		"QuickHull": [
-			[ "Face", "examples/quickhull/Face" ],
-			[ "HalfEdge", "examples/quickhull/HalfEdge" ],
-			[ "QuickHull", "examples/quickhull/QuickHull" ],
-			[ "VertexNode", "examples/quickhull/VertexNode" ],
-			[ "VertexList", "examples/quickhull/VertexList" ]
-		],
-
-		"Renderers": [
-			[ "CanvasRenderer", "examples/renderers/CanvasRenderer" ]
-		]
+		"Collada Animation": {
+			"ColladaAnimation": "examples/collada/Animation",
+			"AnimationHandler": "examples/collada/AnimationHandler",
+			"KeyFrameAnimation": "examples/collada/KeyFrameAnimation"
+		},
+
+		"Geometries": {
+			"ConvexBufferGeometry": "examples/geometries/ConvexBufferGeometry",
+			"ConvexGeometry": "examples/geometries/ConvexGeometry"
+		},
+
+		"Loaders": {
+			"BabylonLoader": "examples/loaders/BabylonLoader",
+			"ColladaLoader": "examples/loaders/ColladaLoader",
+			"GLTF2Loader": "examples/loaders/GLTF2Loader",
+			"MTLLoader": "examples/loaders/MTLLoader",
+			"OBJLoader": "examples/loaders/OBJLoader",
+			"OBJLoader2": "examples/loaders/OBJLoader2",
+			"WWOBJLoader2": "examples/loaders/WWOBJLoader2",
+			"PCDLoader": "examples/loaders/PCDLoader",
+			"PDBLoader": "examples/loaders/PDBLoader",
+			"SVGLoader": "examples/loaders/SVGLoader",
+			"TGALoader": "examples/loaders/TGALoader"
+		},
+
+		"Plugins": {
+			"CombinedCamera": "examples/cameras/CombinedCamera",
+			"LookupTable": "examples/Lut",
+			"SpriteCanvasMaterial": "examples/SpriteCanvasMaterial"
+		},
+
+		"QuickHull": {
+			"Face": "examples/quickhull/Face",
+			"HalfEdge": "examples/quickhull/HalfEdge",
+			"QuickHull": "examples/quickhull/QuickHull",
+			"VertexNode": "examples/quickhull/VertexNode",
+			"VertexList": "examples/quickhull/VertexList"
+		},
+
+		"Renderers": {
+			"CanvasRenderer": "examples/renderers/CanvasRenderer"
+		}
 
 	},
 
 	"Developer Reference": {
-		"Polyfills": [
-			[ "Polyfills", "api/Polyfills" ]
-		],
-
-		"WebGLRenderer": [
-			[ "WebGLProgram", "api/renderers/webgl/WebGLProgram" ],
-			[ "WebGLShader", "api/renderers/webgl/WebGLShader" ],
-			[ "WebGLState", "api/renderers/webgl/WebGLState" ]
-		],
-
-		"WebGLRenderer / Plugins": [
-			[ "LensFlarePlugin", "api/renderers/webgl/plugins/LensFlarePlugin" ],
-			[ "SpritePlugin", "api/renderers/webgl/plugins/SpritePlugin" ]
-		]
-
-	}
-
-};
-
-var pages = {};
-
-for ( var section in list ) {
-
-	pages[ section ] = {};
-
-	for ( var category in list[ section ] ) {
-
-		pages[ section ][ category ] = {};
 
-		for ( var i = 0; i < list[ section ][ category ].length; i ++ ) {
+		"Polyfills": {
+			"Polyfills": "api/Polyfills"
+		},
 
-			var page = list[ section ][ category ][ i ];
-			pages[ section ][ category ][ page[ 0 ] ] = page[ 1 ];
+		"WebGLRenderer": {
+			"WebGLProgram": "api/renderers/webgl/WebGLProgram",
+			"WebGLShader": "api/renderers/webgl/WebGLShader",
+			"WebGLState": "api/renderers/webgl/WebGLState"
+		},
 
+		"WebGLRenderer / Plugins": {
+			"LensFlarePlugin": "api/renderers/webgl/plugins/LensFlarePlugin",
+			"SpritePlugin": "api/renderers/webgl/plugins/SpritePlugin"
 		}
 
 	}

+ 119 - 119
docs/manual/introduction/Animation-system.html

@@ -8,123 +8,123 @@
 		<link type="text/css" rel="stylesheet" href="page.css" />
 	</head>
 	<body>
-    <h1>[name]</h1>
-       
-    <h2>Overview</h2>
-
-    <div class="desc">
-        Within the three.js animation system you can animate various properties of your models:
-        the bones of a [page:SkinnedMesh skinned and rigged model], 
-        [page:Geometry.morphTargets morph targets], different material properties (colors, 
-        opacity, booleans), visibility and transforms. The animated properties can be faded in,
-        faded out, crossfaded and warped. The weight and time scales of different simultaneous 
-        animations on the same object as well as on different objects can be changed 
-        independently. Various animations on the same and on different objects can be 
-        synchronized.<br /><br />
-
-        To achieve all this in one homogeneous system, the three.js animation system
-        [link:https://github.com/mrdoob/three.js/issues/6881 has completely changed in 2015]
-        (be aware of outdated information!), and it has now an architecture similar to 
-        Unity/Unreal Engine 4. This page gives a short overview of the main components of the 
-        system and how they work together.
-        
-    </div>
-           
-    <h3>Animation Clips</h3>
-        
-    <div class="desc">        
-       
-        If you have successfully imported an animated 3D object (it doesn't matter if it has
-        bones or morph targets or both) - for example exporting it from Blender with the 
-        [link:https://github.com/mrdoob/three.js/tree/master/utils/exporters/blender/addons/io_three Blender exporter] and
-        loading it into a three.js scene using [page:JSONLoader] -, one of the geometry's 
-        properties of the loaded mesh should be an array named "animations", containing the 
-        [page:AnimationClip AnimationClips] for this model (see a list of possible loaders below).<br /><br />
-
-        Each *AnimationClip* usually holds the data for a certain activity of the object. If the 
-        mesh is a character, for example, there may be one AnimationClip for a walkcycle, a second 
-        for a jump, a third for sidestepping and so on.
-
-    </div>
-           
-    <h3>Keyframe Tracks</h3>
-        
-    <div class="desc">        
-       
-        Inside of such an *AnimationClip* the data for each animated property are stored in a 
-        separate [page:KeyframeTrack]. Assumed a character object has a [page:Skeleton skeleton],
-        one keyframe track could store the data for the position changes of the lower arm bone 
-        over time, a different track the data for the rotation changes of the same bone, a third 
-        the track position, rotation or scaling of another bone, and so on. It should be clear, 
-        that an AnimationClip can be composed of lots of such tracks.<br /><br />
-        
-        Assumed the model has [page:Geometry.morphTargets morph targets] (for example one morph 
-        target showing a friendly face and another showing an angry face), each track holds the 
-        information as to how the [page:Mesh.morphTargetInfluences influence] of a certain morph 
-        target changes during the performance of the clip.
-
-    </div>
-           
-    <h3>Animation Mixer</h3>
-        
-    <div class="desc">
-        
-        The stored data form only the basis for the animations - actual playback is controlled by 
-        the [page:AnimationMixer]. You can imagine this not only as a player for animations, but 
-        as a simulation of a hardware like a real mixer console, which can control several animations 
-        simultaneously, blending and merging them.
-
-    </div>
-           
-    <h3>Animation Actions</h3>
-        
-    <div class="desc">
-              
-        The *AnimationMixer* itself has only very few (general) properties and methods, because it 
-        can be controlled by the [page:AnimationAction AnimationActions]. By configuring an 
-        *AnimationAction* you can determine when a certain *AnimationClip* shall be played, paused 
-        or stopped on one of the mixers, if and how often the clip has to be repeated, whether it 
-        shall be performed with a fade or a time scaling, and some additional things, such crossfading 
-        or synchronizing.
-
-    </div>          
-           
-    <h3>Animation Object Groups</h3>
-        
-    <div class="desc">
-              
-        If you want a group of objects to receive a shared animation state, you can use an
-        [page:AnimationObjectGroup].  
-
-    </div>          
-            
-    <h3>Supported Formats and Loaders</h3>
-        
-    <div class="desc">
-		Note that not all model formats include animation (OBJ notably does not), and that only some
-		three.js loaders support [page:AnimationClip AnimationClip] sequences. Several that <i>do</i>
-		support this animation type:
-    </div>
-
-		<ul>
-			<li>[page:JSONLoader THREE.JSONLoader]</li>
-			<li>[page:ObjectLoader THREE.ObjectLoader]</li>
-			<li>THREE.BVHLoader</li>
-			<li>THREE.FBXLoader</li>
-			<li>THREE.FBXLoader2</li>
-			<li>[page:GLTFLoader THREE.GLTFLoader]</li>
-			<li>THREE.MMDLoader</li>
-			<li>THREE.SEA3DLoader</li>
-		</ul>
-   
-    <div class="desc">
-		Note that 3ds max and Maya currently can't export multiple animations (meaning animations which are not
-        on the same timeline) directly to a single file.
-    </div>
-    
-	<h2>Example</h2>
-
-	<code>
+		<h1>[name]</h1>
+
+		<h2>Overview</h2>
+
+		<div class="desc">
+			Within the three.js animation system you can animate various properties of your models:
+			the bones of a [page:SkinnedMesh skinned and rigged model],
+			[page:Geometry.morphTargets morph targets], different material properties (colors,
+			opacity, booleans), visibility and transforms. The animated properties can be faded in,
+			faded out, crossfaded and warped. The weight and time scales of different simultaneous
+			animations on the same object as well as on different objects can be changed
+			independently. Various animations on the same and on different objects can be
+			synchronized.<br /><br />
+
+			To achieve all this in one homogeneous system, the three.js animation system
+			[link:https://github.com/mrdoob/three.js/issues/6881 has completely changed in 2015]
+			(be aware of outdated information!), and it has now an architecture similar to
+			Unity/Unreal Engine 4. This page gives a short overview of the main components of the
+			system and how they work together.
+
+		</div>
+
+		<h3>Animation Clips</h3>
+
+		<div class="desc">
+
+			If you have successfully imported an animated 3D object (it doesn't matter if it has
+			bones or morph targets or both) - for example exporting it from Blender with the
+			[link:https://github.com/mrdoob/three.js/tree/master/utils/exporters/blender/addons/io_three Blender exporter] and
+			loading it into a three.js scene using [page:JSONLoader] -, one of the geometry's
+			properties of the loaded mesh should be an array named "animations", containing the
+			[page:AnimationClip AnimationClips] for this model (see a list of possible loaders below).<br /><br />
+
+			Each *AnimationClip* usually holds the data for a certain activity of the object. If the
+			mesh is a character, for example, there may be one AnimationClip for a walkcycle, a second
+			for a jump, a third for sidestepping and so on.
+
+		</div>
+
+		<h3>Keyframe Tracks</h3>
+
+		<div class="desc">
+
+			Inside of such an *AnimationClip* the data for each animated property are stored in a
+			separate [page:KeyframeTrack]. Assumed a character object has a [page:Skeleton skeleton],
+			one keyframe track could store the data for the position changes of the lower arm bone
+			over time, a different track the data for the rotation changes of the same bone, a third
+			the track position, rotation or scaling of another bone, and so on. It should be clear,
+			that an AnimationClip can be composed of lots of such tracks.<br /><br />
+
+			Assumed the model has [page:Geometry.morphTargets morph targets] (for example one morph
+			target showing a friendly face and another showing an angry face), each track holds the
+			information as to how the [page:Mesh.morphTargetInfluences influence] of a certain morph
+			target changes during the performance of the clip.
+
+		</div>
+
+		<h3>Animation Mixer</h3>
+
+		<div class="desc">
+
+			The stored data form only the basis for the animations - actual playback is controlled by
+			the [page:AnimationMixer]. You can imagine this not only as a player for animations, but
+			as a simulation of a hardware like a real mixer console, which can control several animations
+			simultaneously, blending and merging them.
+
+		</div>
+
+		<h3>Animation Actions</h3>
+
+		<div class="desc">
+
+			The *AnimationMixer* itself has only very few (general) properties and methods, because it
+			can be controlled by the [page:AnimationAction AnimationActions]. By configuring an
+			*AnimationAction* you can determine when a certain *AnimationClip* shall be played, paused
+			or stopped on one of the mixers, if and how often the clip has to be repeated, whether it
+			shall be performed with a fade or a time scaling, and some additional things, such crossfading
+			or synchronizing.
+
+		</div>
+
+		<h3>Animation Object Groups</h3>
+
+		<div class="desc">
+
+			If you want a group of objects to receive a shared animation state, you can use an
+			[page:AnimationObjectGroup]. 
+
+		</div>
+
+		<h3>Supported Formats and Loaders</h3>
+
+		<div class="desc">
+			Note that not all model formats include animation (OBJ notably does not), and that only some
+			three.js loaders support [page:AnimationClip AnimationClip] sequences. Several that <i>do</i>
+			support this animation type:
+		</div>
+
+			<ul>
+				<li>[page:JSONLoader THREE.JSONLoader]</li>
+				<li>[page:ObjectLoader THREE.ObjectLoader]</li>
+				<li>THREE.BVHLoader</li>
+				<li>THREE.FBXLoader</li>
+				<li>THREE.FBXLoader2</li>
+				<li>[page:GLTF2Loader THREE.GLTF2Loader]</li>
+				<li>THREE.MMDLoader</li>
+				<li>THREE.SEA3DLoader</li>
+			</ul>
+
+		<div class="desc">
+			Note that 3ds max and Maya currently can't export multiple animations (meaning animations which are not
+			on the same timeline) directly to a single file.
+		</div>
+
+		<h2>Example</h2>
+
+		<code>
 		var mesh;
 
 		// Create an AnimationMixer, and get the list of AnimationClip instances
@@ -145,7 +145,7 @@
 		clips.forEach( function ( clip ) {
 			mixer.clipAction( clip ).play();
 		} );
-	</code>
+		</code>
 
-  </body>
+	</body>
 </html>

+ 1 - 1
docs/manual/introduction/Code-style-guide.html

@@ -16,7 +16,7 @@
 			if you are adding code to the library or examples then you must follow this guide.<br /><br />
 
 			You can find details
-			<a href="https://github.com/mrdoob/three.js/wiki/Mr.doob%27s-Code-Style%E2%84%A2">here</a>.
+			<a href="https://github.com/mrdoob/three.js/wiki/Mr.doob%27s-Code-Style%E2%84%A2" target="_blank">here</a>.
 		</div>
 	</body>
 </html>

+ 4 - 3
docs/manual/introduction/How-to-update-things.html

@@ -69,14 +69,14 @@ var positions = new Float32Array( MAX_POINTS * 3 ); // 3 vertices per point
 geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
 
 // draw range
-drawCount = 2; // draw the first 2 points, only
+var drawCount = 2; // draw the first 2 points, only
 geometry.setDrawRange( 0, drawCount );
 
 // material
 var material = new THREE.LineBasicMaterial( { color: 0xff0000, linewidth: 2 } );
 
 // line
-line = new THREE.Line( geometry,  material );
+var line = new THREE.Line( geometry,  material );
 scene.add( line );
 				</code>
 			 	<p>
@@ -85,7 +85,8 @@ scene.add( line );
 				<code>
 var positions = line.geometry.attributes.position.array;
 
-var x = y = z = index = 0;
+var x, y, z, index;
+x = y = z = index = 0;
 
 for ( var i = 0, l = MAX_POINTS; i < l; i ++ ) {
 

+ 0 - 7
docs/manual/introduction/Useful-links.html

@@ -70,19 +70,12 @@
 			<li>
 				[link:http://www.natural-science.or.jp/article/20120220155529.php Building A Physics Simulation Environment] - three.js tutorial in Japanese
 			</li>
-			<li>
-		 	 [link:http://www.senaeh.de/einstieg-in-webgl-mit-three-js/ Einstieg in WebGL mit three.js] - three.js tutorial in German
-		  </li>
 
 		</ul>
 
 
 		<h2>More documentation</h2>
 		<ul>
-			<li>
-				[link:http://threejsdoc.appspot.com/doc/index.html threejsdoc] - less descriptive than the official docs here, however this is
-				useful because it links every API element to every official three.js [link:https://threejs.org/examples/ example] that uses it.
-			</li>
 			<li>
 				[link:http://ushiroad.com/3j/ Three.js walking map] - a graphical breakdown of the structure of a three.js scene.
 			</li>

+ 0 - 0
docs/manual/introduction/Detecting-WebGL-and-browser-compatibility.html → docs/manual/introduction/WebGL-compatibility-check.html


+ 8 - 4
docs/page.css

@@ -17,6 +17,8 @@ body {
 
 a {
 	color: #1184CE;
+	cursor: pointer;
+	text-decoration: underline;
 }
 
 h1 {
@@ -56,6 +58,7 @@ pre, code {
 	margin-top: 20px;
 	margin-bottom: 20px;
 }
+
 code {
 	display: block;
 	width: -webkit-calc( 100% - 40px );
@@ -77,6 +80,7 @@ th {
 	padding: 10px;
 	text-decoration: underline;
 }
+
 td {
 	text-align: center;
 }
@@ -102,10 +106,10 @@ strong {
 	opacity: 0.5;
 }
 
-	#button:hover {
-		cursor: pointer;
-		opacity: 1;
-	}
+#button:hover {
+	cursor: pointer;
+	opacity: 1;
+}
 
 a.permalink {
 	float: right;

+ 29 - 3
docs/page.js

@@ -1,3 +1,29 @@
+if ( !window.frameElement && window.location.protocol !== 'file:' ) {
+
+	// If the page is not yet displayed as an iframe of the index page (navigation panel/working links),
+	// redirect to the index page (using the current URL without extension as the new fragment).
+	// If this URL itself has a fragment, append it with a dot (since '#' in an URL fragment is not allowed).
+
+	var href = window.location.href;
+	var splitIndex = href.lastIndexOf( '/docs/' ) + 6;
+	var docsBaseURL = href.substr( 0, splitIndex );
+
+	var hash = window.location.hash;
+
+	if ( hash !== '' ) {
+
+		href = href.replace( hash, '' );
+		hash = hash.replace( '#', '.' );
+
+	}
+
+	var pathSnippet = href.slice( splitIndex, -5 );
+
+	window.location.replace( docsBaseURL + '#' + pathSnippet + hash );
+
+}
+
+
 var onDocumentLoad = function ( event ) {
 
 	var path;
@@ -30,11 +56,11 @@ var onDocumentLoad = function ( event ) {
 	text = text.replace( /\[path\]/gi, path );
 	text = text.replace( /\[page:([\w\.]+)\]/gi, "[page:$1 $1]" ); // [page:name] to [page:name title]
 	text = text.replace( /\[page:\.([\w\.]+) ([\w\.\s]+)\]/gi, "[page:" + name + ".$1 $2]" ); // [page:.member title] to [page:name.member title]
-	text = text.replace( /\[page:([\w\.]+) ([\w\.\s]+)\]/gi, "<a href=\"javascript:window.parent.goTo('$1')\" title=\"$1\">$2</a>" ); // [page:name title]
-	// text = text.replace( /\[member:.([\w]+) ([\w\.\s]+)\]/gi, "<a href=\"javascript:window.parent.goTo('" + name + ".$1')\" title=\"$1\">$2</a>" );
+	text = text.replace( /\[page:([\w\.]+) ([\w\.\s]+)\]/gi, "<a onclick=\"window.parent.setUrlFragment('$1')\" title=\"$1\">$2</a>" ); // [page:name title]
+	// text = text.replace( /\[member:.([\w]+) ([\w\.\s]+)\]/gi, "<a onclick=\"window.parent.setUrlFragment('" + name + ".$1')\" title=\"$1\">$2</a>" );
 
 	text = text.replace( /\[(?:member|property|method):([\w]+)\]/gi, "[member:$1 $1]" ); // [member:name] to [member:name title]
-	text = text.replace( /\[(?:member|property|method):([\w]+) ([\w\.\s]+)\]/gi, "<a href=\"javascript:window.parent.goTo('" + name + ".$2')\" target=\"_parent\" title=\"" + name + ".$2\" class=\"permalink\">#</a> .<a href=\"javascript:window.parent.goTo('$1')\" title=\"$1\" id=\"$2\">$2</a> " );
+	text = text.replace( /\[(?:member|property|method):([\w]+) ([\w\.\s]+)\]/gi, "<a onclick=\"window.parent.setUrlFragment('" + name + ".$2')\" target=\"_parent\" title=\"" + name + ".$2\" class=\"permalink\">#</a> .<a onclick=\"window.parent.setUrlFragment('$1')\" title=\"$1\" id=\"$2\">$2</a> " );
 
 	text = text.replace( /\[link:([\w|\:|\/|\.|\-|\_]+)\]/gi, "[link:$1 $1]" ); // [link:url] to [link:url title]
 	text = text.replace( /\[link:([\w|\:|\/|\.|\-|\_|\(|\)|\#]+) ([\w|\:|\/|\.|\-|\_|\s]+)\]/gi, "<a href=\"$1\"  target=\"_blank\">$2</a>" ); // [link:url title]

+ 3 - 1
docs/scenes/js/geometry.js

@@ -91,7 +91,9 @@ function updateGroupGeometry( mesh, geometry ) {
 
 }
 
-function CustomSinCurve( scale ){
+function CustomSinCurve( scale ) {
+
+	THREE.Curve.call( this );
 
 	this.scale = ( scale === undefined ) ? 1 : scale;
 

+ 0 - 8
editor/css/dark.css

@@ -245,11 +245,3 @@ select {
 	.Outliner .option.active {
 		background-color: rgba(21,60,94,1);
 	}
-
-.Panel.Collapsible.collapsed .Static .Button {
-	border-left-color: #444;
-}
-
-.Panel.Collapsible:not(.collapsed) .Static .Button {
-	border-top-color: #444;
-}

+ 0 - 26
editor/css/main.css

@@ -41,32 +41,6 @@ textarea, input { outline: none; } /* osx */
 	user-select: none;
 }
 
-	.Panel.Collapsible .Static {
-		margin: 0;
-	}
-
-	.Panel.Collapsible .Static .Button {
-		float: left;
-		margin-right: 6px;
-		width: 0;
-		height: 0;
-		border: 6px solid transparent;
-	}
-
-	.Panel.Collapsible.collapsed .Static .Button {
-		margin-top: 2px;
-		border-left-color: #bbb;
-	}
-
-	.Panel.Collapsible:not(.collapsed) .Static .Button {
-		margin-top: 6px;
-		border-top-color: #bbb;
-	}
-
-	.Panel.Collapsible.collapsed .Content {
-		display: none;
-	}
-
 /* CodeMirror */
 
 .CodeMirror {

+ 0 - 2
editor/index.html

@@ -38,8 +38,6 @@
 		<script src="../examples/js/exporters/OBJExporter.js"></script>
 		<script src="../examples/js/exporters/STLExporter.js"></script>
 
-		<script src="../examples/js/loaders/deprecated/SceneLoader.js"></script>
-
 		<script src="../examples/js/renderers/Projector.js"></script>
 		<script src="../examples/js/renderers/CanvasRenderer.js"></script>
 		<script src="../examples/js/renderers/RaytracingRenderer.js"></script>

+ 1 - 2
editor/js/Editor.js

@@ -75,8 +75,7 @@ var Editor = function () {
 
 		showGridChanged: new Signal(),
 		refreshSidebarObject3D: new Signal(),
-		historyChanged: new Signal(),
-		refreshScriptEditor: new Signal()
+		historyChanged: new Signal()
 
 	};
 

+ 0 - 13
editor/js/Loader.js

@@ -525,19 +525,6 @@ var Loader = function ( editor ) {
 
 				break;
 
-			case 'scene':
-
-				// DEPRECATED
-
-				var loader = new THREE.SceneLoader();
-				loader.parse( data, function ( result ) {
-
-					editor.execute( new SetSceneCommand( result.scene ) );
-
-				}, '' );
-
-				break;
-
 			case 'app':
 
 				editor.fromJSON( data );

+ 3 - 22
editor/js/Script.js

@@ -84,7 +84,7 @@ var Script = function ( editor ) {
 
 				if ( value !== currentScript.source ) {
 
-					editor.execute( new SetScriptValueCommand( currentObject, currentScript, 'source', value, codemirror.getCursor(), codemirror.getScrollInfo() ) );
+					editor.execute( new SetScriptValueCommand( currentObject, currentScript, 'source', value ) );
 
 				}
 				return;
@@ -407,7 +407,8 @@ var Script = function ( editor ) {
 
 		container.setDisplay( '' );
 		codemirror.setValue( source );
-		if (mode === 'json' ) mode = { name: 'javascript', json: true };
+		codemirror.clearHistory();
+		if ( mode === 'json' ) mode = { name: 'javascript', json: true };
 		codemirror.setOption( 'mode', mode );
 
 	} );
@@ -422,26 +423,6 @@ var Script = function ( editor ) {
 
 	} );
 
-	signals.refreshScriptEditor.add( function ( object, script, cursorPosition, scrollInfo ) {
-
-		if ( currentScript !== script ) return;
-
-		// copying the codemirror history because "codemirror.setValue(...)" alters its history
-
-		var history = codemirror.getHistory();
-		title.setValue( object.name + ' / ' + script.name );
-		codemirror.setValue( script.source );
-
-		if ( cursorPosition !== undefined ) {
-
-			codemirror.setCursor( cursorPosition );
-			codemirror.scrollTo( scrollInfo.left, scrollInfo.top );
-
-		}
-		codemirror.setHistory( history ); // setting the history to previous state
-
-	} );
-
 	return container;
 
 };

+ 0 - 85
editor/js/Sidebar.Animation.js

@@ -19,91 +19,6 @@ Sidebar.Animation = function ( editor ) {
 	var animationsRow = new UI.Row();
 	container.add( animationsRow );
 
-	/*
-
-	var animations = {};
-
-	signals.objectAdded.add( function ( object ) {
-
-		object.traverse( function ( child ) {
-
-			if ( child instanceof THREE.SkinnedMesh ) {
-
-				var material = child.material;
-
-				if ( material instanceof THREE.MultiMaterial ) {
-
-					for ( var i = 0; i < material.materials.length; i ++ ) {
-
-						material.materials[ i ].skinning = true;
-
-					}
-
-				} else {
-
-					child.material.skinning = true;
-
-				}
-
-				animations[ child.id ] = new THREE.Animation( child, child.geometry.animation );
-
-			} else if ( child instanceof THREE.MorphAnimMesh ) {
-
-				var animation = new THREE.MorphAnimation( child );
-				animation.duration = 30;
-
-				// temporal hack for THREE.AnimationHandler
-				animation._play = animation.play;
-				animation.play = function () {
-					this._play();
-					THREE.AnimationHandler.play( this );
-				};
-				animation.resetBlendWeights = function () {};
-				animation.stop = function () {
-					this.pause();
-					THREE.AnimationHandler.stop( this );
-				};
-
-				animations[ child.id ] = animation;
-
-			}
-
-		} );
-
-	} );
-
-	signals.objectSelected.add( function ( object ) {
-
-		container.setDisplay( 'none' );
-
-		if ( object instanceof THREE.SkinnedMesh || object instanceof THREE.MorphAnimMesh ) {
-
-			animationsRow.clear();
-
-			var animation = animations[ object.id ];
-
-			var playButton = new UI.Button( 'Play' ).onClick( function () {
-
-				animation.play();
-
-			} );
-			animationsRow.add( playButton );
-
-			var pauseButton = new UI.Button( 'Stop' ).onClick( function () {
-
-				animation.stop();
-
-			} );
-			animationsRow.add( pauseButton );
-
-			container.setDisplay( 'block' );
-
-		}
-
-	} );
-
-	*/
-
 	return container;
 
 };

+ 2 - 1
editor/js/Sidebar.Material.js

@@ -1279,7 +1279,8 @@ Sidebar.Material = function ( editor ) {
 
 	signals.objectSelected.add( function ( object ) {
 
-		if ( object && object.material ) {
+		if ( object && object.material &&
+			Array.isArray( object.material ) === false ) {
 
 			var objectChanged = object !== currentObject;
 

+ 21 - 1
editor/js/Sidebar.Scene.js

@@ -23,6 +23,26 @@ Sidebar.Scene = function ( editor ) {
 
 	}
 
+	function getMaterialName( material ) {
+
+		if ( Array.isArray( material ) ) {
+
+			var array = [];
+
+			for ( var i = 0; i < material.length; i ++ ) {
+
+				array.push( material[ i ].name );
+
+			}
+
+			return array.join( ',' );
+
+		}
+
+		return material.name;
+
+	}
+
 	function buildHTML( object ) {
 
 		var html = '<span class="type ' + object.type + '"></span> ' + object.name;
@@ -33,7 +53,7 @@ Sidebar.Scene = function ( editor ) {
 			var material = object.material;
 
 			html += ' <span class="type ' + geometry.type + '"></span> ' + geometry.name;
-			html += ' <span class="type ' + material.type + '"></span> ' + material.name;
+			html += ' <span class="type ' + material.type + '"></span> ' + getMaterialName( material );
 
 		}
 

+ 5 - 5
editor/js/Viewport.js

@@ -60,7 +60,7 @@ var Viewport = function ( editor ) {
 
 		if ( object !== undefined ) {
 
-			selectionBox.update( object );
+			selectionBox.setFromObject( object );
 
 			if ( editor.helpers[ object.id ] !== undefined ) {
 
@@ -379,13 +379,13 @@ var Viewport = function ( editor ) {
 		selectionBox.visible = false;
 		transformControls.detach();
 
-		if ( object !== null && object !== scene ) {
+		if ( object !== null && object !== scene && object !== camera ) {
 
 			box.setFromObject( object );
 
 			if ( box.isEmpty() === false ) {
 
-				selectionBox.update( box );
+				selectionBox.setFromObject( object );
 				selectionBox.visible = true;
 
 			}
@@ -408,7 +408,7 @@ var Viewport = function ( editor ) {
 
 		if ( object !== undefined ) {
 
-			selectionBox.update( object );
+			selectionBox.setFromObject( object );
 
 		}
 
@@ -430,7 +430,7 @@ var Viewport = function ( editor ) {
 
 		if ( editor.selected === object ) {
 
-			selectionBox.update( object );
+			selectionBox.setFromObject( object );
 			transformControls.update();
 
 		}

+ 1 - 13
editor/js/commands/SetScriptValueCommand.js

@@ -8,12 +8,10 @@
  * @param script javascript object
  * @param attributeName string
  * @param newValue string, object
- * @param cursorPosition javascript object with format {line: 2, ch: 3}
- * @param scrollInfo javascript object with values {left, top, width, height, clientWidth, clientHeight}
  * @constructor
  */
 
-var SetScriptValueCommand = function ( object, script, attributeName, newValue, cursorPosition, scrollInfo ) {
+var SetScriptValueCommand = function ( object, script, attributeName, newValue ) {
 
 	Command.call( this );
 
@@ -27,8 +25,6 @@ var SetScriptValueCommand = function ( object, script, attributeName, newValue,
 	this.attributeName = attributeName;
 	this.oldValue = ( script !== undefined ) ? script[ this.attributeName ] : undefined;
 	this.newValue = newValue;
-	this.cursorPosition = cursorPosition;
-	this.scrollInfo = scrollInfo;
 
 };
 
@@ -39,7 +35,6 @@ SetScriptValueCommand.prototype = {
 		this.script[ this.attributeName ] = this.newValue;
 
 		this.editor.signals.scriptChanged.dispatch();
-		this.editor.signals.refreshScriptEditor.dispatch( this.object, this.script, this.cursorPosition, this.scrollInfo );
 
 	},
 
@@ -48,14 +43,11 @@ SetScriptValueCommand.prototype = {
 		this.script[ this.attributeName ] = this.oldValue;
 
 		this.editor.signals.scriptChanged.dispatch();
-		this.editor.signals.refreshScriptEditor.dispatch( this.object, this.script, this.cursorPosition, this.scrollInfo );
 
 	},
 
 	update: function ( cmd ) {
 
-		this.cursorPosition = cmd.cursorPosition;
-		this.scrollInfo = cmd.scrollInfo;
 		this.newValue = cmd.newValue;
 
 	},
@@ -69,8 +61,6 @@ SetScriptValueCommand.prototype = {
 		output.attributeName = this.attributeName;
 		output.oldValue = this.oldValue;
 		output.newValue = this.newValue;
-		output.cursorPosition = this.cursorPosition;
-		output.scrollInfo = this.scrollInfo;
 
 		return output;
 
@@ -85,8 +75,6 @@ SetScriptValueCommand.prototype = {
 		this.attributeName = json.attributeName;
 		this.object = this.editor.objectByUuid( json.objectUuid );
 		this.script = this.editor.scripts[ json.objectUuid ][ json.index ];
-		this.cursorPosition = json.cursorPosition;
-		this.scrollInfo = json.scrollInfo;
 
 	}
 

+ 0 - 4
editor/js/libs/tern-threejs/threejs.js

@@ -3831,10 +3831,6 @@
           "!type": "fn(a: +THREE.Matrix4, b: +THREE.Matrix4) -> +THREE.Matrix4",
           "!doc": "Sets this matrix to *a x b*."
         },
-        "multiplyToArray": {
-          "!type": "fn(a: +THREE.Matrix4, b: +THREE.Matrix4, r: []) -> +THREE.Matrix4",
-          "!doc": "Sets this matrix to *a x b* and stores the result into the flat array *r*.<br>\n\t\t*r* can be either a regular Array or a TypedArray."
-        },
         "multiplyScalar": {
           "!type": "fn(s: number) -> +THREE.Matrix4",
           "!doc": "Multiplies this matrix by *s*."

+ 9 - 3
examples/files.js

@@ -1,6 +1,7 @@
 var files = {
 	"webgl": [
 		"webgl_animation_cloth",
+		"webgl_animation_keyframes_json",
 		"webgl_animation_scene",
 		"webgl_animation_skinning_blending",
 		"webgl_animation_skinning_morph",
@@ -43,6 +44,7 @@ var files = {
 		"webgl_geometry_text",
 		"webgl_geometry_text_earcut",
 		"webgl_geometry_text_pnltri",
+		"webgl_geometry_text_shapes",
 		"webgl_gpgpu_birds",
 		"webgl_gpgpu_water",
 		"webgl_gpgpu_protoplanet",
@@ -67,7 +69,6 @@ var files = {
 		"webgl_lights_pointlights2",
 		"webgl_lights_spotlight",
 		"webgl_lights_spotlights",
-		"webgl_lights_arealight",
 		"webgl_lights_rectarealight",
 		"webgl_lines_colors",
 		"webgl_lines_cubes",
@@ -102,6 +103,9 @@ var files = {
 		"webgl_loader_msgpack",
 		"webgl_loader_obj",
 		"webgl_loader_obj_mtl",
+		"webgl_loader_obj2",
+		"webgl_loader_obj2_ww",
+		"webgl_loader_obj2_ww_parallels",
 		"webgl_loader_nrrd",
 		"webgl_loader_pcd",
 		"webgl_loader_pdb",
@@ -114,7 +118,6 @@ var files = {
 		"webgl_loader_sea3d_physics",
 		"webgl_loader_sea3d_skinning",
 		"webgl_loader_sea3d_sound",
-		"webgl_loader_scene",
 		"webgl_loader_stl",
 		"webgl_loader_utf8",
 		"webgl_loader_vrml",
@@ -129,6 +132,7 @@ var files = {
 		"webgl_materials_bumpmap_skin",
 		"webgl_materials_cars",
 		"webgl_materials_channels",
+		"webgl_materials_compile",
 		"webgl_materials_cubemap",
 		"webgl_materials_cubemap_balls_reflection",
 		"webgl_materials_cubemap_balls_refraction",
@@ -252,6 +256,7 @@ var files = {
 		"webgl_buffergeometry_custom_attributes_particles",
 		"webgl_buffergeometry_drawcalls",
 		"webgl_buffergeometry_instancing",
+		"webgl_buffergeometry_instancing2",
 		"webgl_buffergeometry_instancing_billboards",
 		"webgl_buffergeometry_instancing_dynamic",
 		"webgl_buffergeometry_instancing_interleaved_dynamic",
@@ -280,10 +285,11 @@ var files = {
 		"webvr_daydream",
 		"webvr_panorama",
 		"webvr_rollercoaster",
-		"webvr_shadow",
+		"webvr_sandbox",
 		"webvr_video",
 		"webvr_vive",
 		"webvr_vive_dragging",
+		"webvr_vive_camerarig",
 		"webvr_vive_paint",
 		"webvr_vive_sculpt"
 	],

+ 1 - 1
examples/index.html

@@ -473,7 +473,7 @@
 		}
 
 		filterInput.value = extractQuery();
-		updateFilter( )
+		updateFilter();
 
 		</script>
 

+ 0 - 182
examples/js/BlendCharacter.js

@@ -1,182 +0,0 @@
-/**
- * @author Michael Guerrero / http://realitymeltdown.com
- */
-
-THREE.BlendCharacter = function () {
-
-	this.weightSchedule = [];
-	this.warpSchedule = [];
-
-	this.load = function ( url, onLoad ) {
-
-		var scope = this;
-
-		var loader = new THREE.ObjectLoader();
-		loader.load( url, function( loadedObject ) {
-
-			// The exporter does not currently allow exporting a skinned mesh by itself
-			// so we must fish it out of the hierarchy it is embedded in (scene)
-			loadedObject.traverse( function( object ) {
-
-				if ( object instanceof THREE.SkinnedMesh ) {
-
-					scope.skinnedMesh = object;
-
-				}
-
-			} );
-
-			THREE.SkinnedMesh.call( scope, scope.skinnedMesh.geometry, scope.skinnedMesh.material );
-
-			// If we didn't successfully find the mesh, bail out
-			if ( scope.skinnedMesh == undefined ) {
-
-				console.log( 'unable to find skinned mesh in ' + url );
-				return;
-
-			}
-
-			scope.material.skinning = true;
-
-			scope.mixer = new THREE.AnimationMixer( scope );
-
-			// Create the animations
-			for ( var i = 0; i < scope.geometry.animations.length; ++ i ) {
-
-				scope.mixer.clipAction( scope.geometry.animations[ i ] );
-
-			}
-
-			// Loading is complete, fire the callback
-			if ( onLoad !== undefined ) onLoad();
-
-		} );
-
-	};
-
-	this.loadJSON = function ( url, onLoad ) {
-
-		var scope = this;
-
-		var loader = new THREE.JSONLoader();
-		loader.load( url, function( geometry, materials ) {
-
-			var originalMaterial = materials[ 0 ];
-			originalMaterial.skinning = true;
-
-			THREE.SkinnedMesh.call( scope, geometry, originalMaterial );
-
-			var mixer = new THREE.AnimationMixer( scope );
-			scope.mixer = mixer;
-
-			// Create the animations
-			for ( var i = 0; i < geometry.animations.length; ++ i ) {
-
-				mixer.clipAction( geometry.animations[ i ] );
-
-			}
-
-			// Loading is complete, fire the callback
-			if ( onLoad !== undefined ) onLoad();
-
-		} );
-
-	};
-	
-	this.update = function( dt ) {
-
-		this.mixer.update( dt );
-
-	};
-
-	this.play = function( animName, weight ) {
-
-		//console.log("play('%s', %f)", animName, weight);
-		return this.mixer.clipAction( animName ).
-				setEffectiveWeight( weight ).play();
-	};
-
-	this.crossfade = function( fromAnimName, toAnimName, duration ) {
-
-		this.mixer.stopAllAction();
-
-		var fromAction = this.play( fromAnimName, 1 );
-		var toAction = this.play( toAnimName, 1 );
-
-		fromAction.crossFadeTo( toAction, duration, false );
-
-	};
-
-	this.warp = function( fromAnimName, toAnimName, duration ) {
-
-		this.mixer.stopAllAction();
-
-		var fromAction = this.play( fromAnimName, 1 );
-		var toAction = this.play( toAnimName, 1 );
-
-		fromAction.crossFadeTo( toAction, duration, true );
-
-	};
-
-	this.applyWeight = function( animName, weight ) {
-
-		this.mixer.clipAction( animName ).setEffectiveWeight( weight );
-
-	};
-
-	this.getWeight = function( animName ) {
-
-		return this.mixer.clipAction( animName ).getEffectiveWeight();
-
-	};
-
-	this.pauseAll = function() {
-
-		this.mixer.timeScale = 0;
-
-	};
-
-	this.unPauseAll = function() {
-
-		this.mixer.timeScale = 1;
-
-	};
-
-
-	this.stopAll = function() {
-
-		this.mixer.stopAllAction();
-
-	};
-
-	this.showModel = function( boolean ) {
-
-		this.visible = boolean;
-
-	};
-
-};
-
-
-THREE.BlendCharacter.prototype = Object.create( THREE.SkinnedMesh.prototype );
-THREE.BlendCharacter.prototype.constructor = THREE.BlendCharacter;
-
-THREE.BlendCharacter.prototype.getForward = function() {
-
-	var forward = new THREE.Vector3();
-
-	return function() {
-
-		// pull the character's forward basis vector out of the matrix
-		forward.set(
-			- this.matrix.elements[ 8 ],
-			- this.matrix.elements[ 9 ],
-			- this.matrix.elements[ 10 ]
-		);
-
-		return forward;
-
-	}
-
-};
-

+ 0 - 207
examples/js/BlendCharacterGui.js

@@ -1,207 +0,0 @@
-/**
- * @author Michael Guerrero / http://realitymeltdown.com
- */
-
-function BlendCharacterGui( blendMesh ) {
-
-	var controls = {
-
-		gui: null,
-		"Show Model": true,
-		"Show Skeleton": false,
-		"Time Scale": 1.0,
-		"Step Size": 0.016,
-		"Crossfade Time": 3.5,
-		"idle": 0.33,
-		"walk": 0.33,
-		"run": 0.33
-
-	};
-
-	var blendMesh = blendMesh;
-
-	this.showModel = function() {
-
-		return controls[ 'Show Model' ];
-
-	};
-
-	this.showSkeleton = function() {
-
-		return controls[ 'Show Skeleton' ];
-
-	};
-
-	this.getTimeScale = function() {
-
-		return controls[ 'Time Scale' ];
-
-	};
-
-	this.update = function( time ) {
-
-		controls[ 'idle' ] = blendMesh.getWeight( 'idle' );
-		controls[ 'walk' ] = blendMesh.getWeight( 'walk' );
-		controls[ 'run' ] = blendMesh.getWeight( 'run' );
-
-	};
-
-	var init = function() {
-
-		controls.gui = new dat.GUI();
-
-		var settings = controls.gui.addFolder( 'Settings' );
-		var playback = controls.gui.addFolder( 'Playback' );
-		var blending = controls.gui.addFolder( 'Blend Tuning' );
-
-		settings.add( controls, "Show Model" ).onChange( controls.showModelChanged );
-		settings.add( controls, "Show Skeleton" ).onChange( controls.showSkeletonChanged );
-		settings.add( controls, "Time Scale", 0, 1, 0.01 );
-		settings.add( controls, "Step Size", 0.01, 0.1, 0.01 );
-		settings.add( controls, "Crossfade Time", 0.1, 6.0, 0.05 );
-
-		// These controls execute functions
-		playback.add( controls, "start" );
-		playback.add( controls, "pause" );
-		playback.add( controls, "step" );
-		playback.add( controls, "idle to walk" );
-		playback.add( controls, "walk to run" );
-		playback.add( controls, "warp walk to run" );
-
-		blending.add( controls, "idle", 0, 1, 0.01 ).listen().onChange( controls.weight );
-		blending.add( controls, "walk", 0, 1, 0.01 ).listen().onChange( controls.weight );
-		blending.add( controls, "run", 0, 1, 0.01 ).listen().onChange( controls.weight );
-
-		settings.open();
-		playback.open();
-		blending.open();
-
-	};
-
-	var getAnimationData = function() {
-
-		return {
-
-			detail: {
-
-				anims: [ "idle", "walk", "run" ],
-
-				weights: [ controls[ 'idle' ],
-						   controls[ 'walk' ],
-						   controls[ 'run' ] ]
-			}
-
-		};
-
-	};
-
-	controls.start = function() {
-
-		var startEvent = new CustomEvent( 'start-animation', getAnimationData() );
-		window.dispatchEvent( startEvent );
-
-	};
-
-	controls.stop = function() {
-
-		var stopEvent = new CustomEvent( 'stop-animation' );
-		window.dispatchEvent( stopEvent );
-
-	};
-
-	controls.pause = function() {
-
-		var pauseEvent = new CustomEvent( 'pause-animation' );
-		window.dispatchEvent( pauseEvent );
-
-	};
-
-	controls.step = function() {
-
-		var stepData = { detail: { stepSize: controls[ 'Step Size' ] } };
-		window.dispatchEvent( new CustomEvent( 'step-animation', stepData ) );
-
-	};
-
-	controls.weight = function() {
-
-		// renormalize
-		var sum = controls[ 'idle' ] + controls[ 'walk' ] + controls[ 'run' ];
-		controls[ 'idle' ] /= sum;
-		controls[ 'walk' ] /= sum;
-		controls[ 'run' ] /= sum;
-
-		var weightEvent = new CustomEvent( 'weight-animation', getAnimationData() );
-		window.dispatchEvent( weightEvent );
-
-	};
-
-	controls.crossfade = function( from, to ) {
-
-		var fadeData = getAnimationData();
-		fadeData.detail.from = from;
-		fadeData.detail.to = to;
-		fadeData.detail.time = controls[ "Crossfade Time" ];
-
-		window.dispatchEvent( new CustomEvent( 'crossfade', fadeData ) );
-
-	};
-
-	controls.warp = function( from, to ) {
-
-		var warpData = getAnimationData();
-		warpData.detail.from = 'walk';
-		warpData.detail.to = 'run';
-		warpData.detail.time = controls[ "Crossfade Time" ];
-
-		window.dispatchEvent( new CustomEvent( 'warp', warpData ) );
-
-	};
-
-	controls[ 'idle to walk' ] = function() {
-
-		controls.crossfade( 'idle', 'walk' );
-
-	};
-
-	controls[ 'walk to run' ] = function() {
-
-		controls.crossfade( 'walk', 'run' );
-
-	};
-
-	controls[ 'warp walk to run' ] = function() {
-
-		controls.warp( 'walk', 'run' );
-
-	};
-
-	controls.showSkeletonChanged = function() {
-
-		var data = {
-			detail: {
-				shouldShow: controls[ 'Show Skeleton' ]
-			}
-		};
-
-		window.dispatchEvent( new CustomEvent( 'toggle-show-skeleton', data ) );
-
-	};
-
-
-	controls.showModelChanged = function() {
-
-		var data = {
-			detail: {
-				shouldShow: controls[ 'Show Model' ]
-			}
-		};
-
-		window.dispatchEvent( new CustomEvent( 'toggle-show-model', data ) );
-
-	};
-
-
-	init.call( this );
-
-}

+ 2 - 2
examples/js/Cloth.js

@@ -101,7 +101,7 @@ Particle.prototype.integrate = function( timesq ) {
 
 var diff = new THREE.Vector3();
 
-function satisifyConstraints( p1, p2, distance ) {
+function satisfyConstraints( p1, p2, distance ) {
 
 	diff.subVectors( p2.position, p1.position );
 	var currentDist = diff.length();
@@ -272,7 +272,7 @@ function simulate( time ) {
 	for ( i = 0; i < il; i ++ ) {
 
 		constraint = constraints[ i ];
-		satisifyConstraints( constraint[ 0 ], constraint[ 1 ], constraint[ 2 ] );
+		satisfyConstraints( constraint[ 0 ], constraint[ 1 ], constraint[ 2 ] );
 
 	}
 

+ 37 - 3
examples/js/CurveExtras.js

@@ -15,7 +15,11 @@
 
 	// GrannyKnot
 
-	function GrannyKnot() {}
+	function GrannyKnot() {
+
+		THREE.Curve.call( this );
+
+	}
 
 	GrannyKnot.prototype = Object.create( THREE.Curve.prototype );
 	GrannyKnot.prototype.constructor = GrannyKnot;
@@ -36,6 +40,8 @@
 
 	function HeartCurve( s ) {
 
+		THREE.Curve.call( this );
+
 		this.scale = ( s === undefined ) ? 5 : s;
 
 	}
@@ -59,6 +65,8 @@
 
 	function VivianiCurve( radius ) {
 
+		THREE.Curve.call( this );
+
 		this.radius = radius;
 
 	}
@@ -81,7 +89,11 @@
 
 	// KnotCurve
 
-	function KnotCurve() {}
+	function KnotCurve() {
+
+		THREE.Curve.call( this );
+
+	}
 
 	KnotCurve.prototype = Object.create( THREE.Curve.prototype );
 	KnotCurve.prototype.constructor = KnotCurve;
@@ -103,7 +115,11 @@
 
 	// HelixCurve
 
-	function HelixCurve() {}
+	function HelixCurve() {
+
+		THREE.Curve.call( this );
+
+	}
 
 	HelixCurve.prototype = Object.create( THREE.Curve.prototype );
 	HelixCurve.prototype.constructor = HelixCurve;
@@ -127,6 +143,8 @@
 
 	function TrefoilKnot( s ) {
 
+		THREE.Curve.call( this );
+
 		this.scale = ( s === undefined ) ? 10 : s;
 
 	}
@@ -150,6 +168,8 @@
 
 	function TorusKnot( s ) {
 
+		THREE.Curve.call( this );
+
 		this.scale = ( s === undefined ) ? 10 : s;
 
 	}
@@ -176,6 +196,8 @@
 
 	function CinquefoilKnot( s ) {
 
+		THREE.Curve.call( this );
+
 		this.scale = ( s === undefined ) ? 10 : s;
 
 	}
@@ -202,6 +224,8 @@
 
 	function TrefoilPolynomialKnot( s ) {
 
+		THREE.Curve.call( this );
+
 		this.scale = ( s === undefined ) ? 10 : s;
 
 	}
@@ -232,6 +256,8 @@
 
 	function FigureEightPolynomialKnot( s ) {
 
+		THREE.Curve.call( this );
+
 		this.scale = ( s === undefined ) ? 1 : s;
 
 	}
@@ -255,6 +281,8 @@
 
 	function DecoratedTorusKnot4a( s ) {
 
+		THREE.Curve.call( this );
+
 		this.scale = ( s === undefined ) ? 40 : s;
 
 	}
@@ -278,6 +306,8 @@
 
 	function DecoratedTorusKnot4b( s ) {
 
+		THREE.Curve.call( this );
+
 		this.scale = ( s === undefined ) ? 40 : s;
 
 	}
@@ -301,6 +331,8 @@
 
 	function DecoratedTorusKnot5a( s ) {
 
+		THREE.Curve.call( this );
+
 		this.scale = ( s === undefined ) ? 40 : s;
 
 	}
@@ -324,6 +356,8 @@
 
 	function DecoratedTorusKnot5c( s ) {
 
+		THREE.Curve.call( this );
+
 		this.scale = ( s === undefined ) ? 40 : s;
 
 	}

+ 313 - 321
examples/js/GPUParticleSystem.js

@@ -15,156 +15,115 @@
  *
  */
 
-THREE.GPUParticleSystem = function(options) {
+THREE.GPUParticleSystem = function( options ) {
 
-	var self = this;
-	var options = options || {};
+	THREE.Object3D.apply( this, arguments );
+
+	options = options || {};
 
 	// parse options and use defaults
-	self.PARTICLE_COUNT = options.maxParticles || 1000000;
-	self.PARTICLE_CONTAINERS = options.containerCount || 1;
-	
-	self.PARTICLE_NOISE_TEXTURE = options.particleNoiseTex || null;
-	self.PARTICLE_SPRITE_TEXTURE = options.particleSpriteTex || null;
-	
-	self.PARTICLES_PER_CONTAINER = Math.ceil(self.PARTICLE_COUNT / self.PARTICLE_CONTAINERS);
-	self.PARTICLE_CURSOR = 0;
-	self.time = 0;
-
-
-	// Custom vertex and fragement shader
-	var GPUParticleShader = {
 
-		vertexShader: [
+	this.PARTICLE_COUNT = options.maxParticles || 1000000;
+	this.PARTICLE_CONTAINERS = options.containerCount || 1;
 
-			'precision highp float;',
-			'const vec4 bitSh = vec4(256. * 256. * 256., 256. * 256., 256., 1.);',
-			'const vec4 bitMsk = vec4(0.,vec3(1./256.0));',
-			'const vec4 bitShifts = vec4(1.) / bitSh;',
+	this.PARTICLE_NOISE_TEXTURE = options.particleNoiseTex || null;
+	this.PARTICLE_SPRITE_TEXTURE = options.particleSpriteTex || null;
 
-			'#define FLOAT_MAX	1.70141184e38',
-			'#define FLOAT_MIN	1.17549435e-38',
+	this.PARTICLES_PER_CONTAINER = Math.ceil( this.PARTICLE_COUNT / this.PARTICLE_CONTAINERS );
+	this.PARTICLE_CURSOR = 0;
+	this.time = 0;
+	this.particleContainers = [];
+	this.rand = [];
 
-			'lowp vec4 encode_float(highp float v) {',
-			'highp float av = abs(v);',
+	// custom vertex and fragement shader
 
-			'//Handle special cases',
-			'if(av < FLOAT_MIN) {',
-			'return vec4(0.0, 0.0, 0.0, 0.0);',
-			'} else if(v > FLOAT_MAX) {',
-			'return vec4(127.0, 128.0, 0.0, 0.0) / 255.0;',
-			'} else if(v < -FLOAT_MAX) {',
-			'return vec4(255.0, 128.0, 0.0, 0.0) / 255.0;',
-			'}',
+	var GPUParticleShader = {
 
-			'highp vec4 c = vec4(0,0,0,0);',
+		vertexShader: [
 
-			'//Compute exponent and mantissa',
-			'highp float e = floor(log2(av));',
-			'highp float m = av * pow(2.0, -e) - 1.0;',
+			'uniform float uTime;',
+			'uniform float uScale;',
+			'uniform sampler2D tNoise;',
 
-			//Unpack mantissa
-			'c[1] = floor(128.0 * m);',
-			'm -= c[1] / 128.0;',
-			'c[2] = floor(32768.0 * m);',
-			'm -= c[2] / 32768.0;',
-			'c[3] = floor(8388608.0 * m);',
+			'attribute vec3 positionStart;',
+			'attribute float startTime;',
+			'attribute vec3 velocity;',
+			'attribute float turbulence;',
+			'attribute vec3 color;',
+			'attribute float size;',
+			'attribute float lifeTime;',
 
-			'//Unpack exponent',
-			'highp float ebias = e + 127.0;',
-			'c[0] = floor(ebias / 2.0);',
-			'ebias -= c[0] * 2.0;',
-			'c[1] += floor(ebias) * 128.0;',
+			'varying vec4 vColor;',
+			'varying float lifeLeft;',
 
-			'//Unpack sign bit',
-			'c[0] += 128.0 * step(0.0, -v);',
+			'void main() {',
 
-			'//Scale back to range',
-			'return c / 255.0;',
-			'}',
+			// unpack things from our attributes'
 
-			'vec4 pack(const in float depth)',
-			'{',
-			'const vec4 bit_shift = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);',
-			'const vec4 bit_mask	= vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);',
-			'vec4 res = mod(depth*bit_shift*vec4(255), vec4(256))/vec4(255);',
-			'res -= res.xxyz * bit_mask;',
-			'return res;',
-			'}',
+			'	vColor = vec4( color, 1.0 );',
 
-			'float unpack(const in vec4 rgba_depth)',
-			'{',
-			'const vec4 bit_shift = vec4(1.0/(256.0*256.0*256.0), 1.0/(256.0*256.0), 1.0/256.0, 1.0);',
-			'float depth = dot(rgba_depth, bit_shift);',
-			'return depth;',
-			'}',
+			// convert our velocity back into a value we can use'
 
-			'uniform float uTime;',
-			'uniform float uScale;',
-			'uniform sampler2D tNoise;',
+			'	vec3 newPosition;',
+			'	vec3 v;',
 
-			'attribute vec4 particlePositionsStartTime;',
-			'attribute vec4 particleVelColSizeLife;',
+			'	float timeElapsed = uTime - startTime;',
 
-			'varying vec4 vColor;',
-			'varying float lifeLeft;',
+			'	lifeLeft = 1.0 - ( timeElapsed / lifeTime );',
 
-			'void main() {',
+			'	gl_PointSize = ( uScale * size ) * lifeLeft;',
 
-			'// unpack things from our attributes',
-			'vColor = encode_float( particleVelColSizeLife.y );',
+			'	v.x = ( velocity.x - 0.5 ) * 3.0;',
+			'	v.y = ( velocity.y - 0.5 ) * 3.0;',
+			'	v.z = ( velocity.z - 0.5 ) * 3.0;',
 
-			'// convert our velocity back into a value we can use',
-			'vec4 velTurb = encode_float( particleVelColSizeLife.x );',
-			'vec3 velocity = vec3( velTurb.xyz );',
-			'float turbulence = velTurb.w;',
+			'	newPosition = positionStart + ( v * 10.0 ) * ( uTime - startTime );',
 
-			'vec3 newPosition;',
+			'	vec3 noise = texture2D( tNoise, vec2( newPosition.x * 0.015 + ( uTime * 0.05 ), newPosition.y * 0.02 + ( uTime * 0.015 ) ) ).rgb;',
+			'	vec3 noiseVel = ( noise.rgb - 0.5 ) * 30.0;',
 
-			'float timeElapsed = uTime - particlePositionsStartTime.a;',
+			'	newPosition = mix( newPosition, newPosition + vec3( noiseVel * ( turbulence * 5.0 ) ), ( timeElapsed / lifeTime ) );',
 
-			'lifeLeft = 1. - (timeElapsed / particleVelColSizeLife.w);',
+			'	if( v.y > 0. && v.y < .05 ) {',
 
-			'gl_PointSize = ( uScale * particleVelColSizeLife.z ) * lifeLeft;',
+			'		lifeLeft = 0.0;',
 
-			'velocity.x = ( velocity.x - .5 ) * 3.;',
-			'velocity.y = ( velocity.y - .5 ) * 3.;',
-			'velocity.z = ( velocity.z - .5 ) * 3.;',
+			'	}',
 
-			'newPosition = particlePositionsStartTime.xyz + ( velocity * 10. ) * ( uTime - particlePositionsStartTime.a );',
+			'	if( v.x < - 1.45 ) {',
 
-			'vec3 noise = texture2D( tNoise, vec2( newPosition.x * .015 + (uTime * .05), newPosition.y * .02 + (uTime * .015) )).rgb;',
-			'vec3 noiseVel = ( noise.rgb - .5 ) * 30.;',
+			'		lifeLeft = 0.0;',
 
-			'newPosition = mix(newPosition, newPosition + vec3(noiseVel * ( turbulence * 5. ) ), (timeElapsed / particleVelColSizeLife.a) );',
+			'	}',
 
-			'if( velocity.y > 0. && velocity.y < .05 ) {',
-			'lifeLeft = 0.;',
-			'}',
+			'	if( timeElapsed > 0.0 ) {',
 
-			'if( velocity.x < -1.45 ) {',
-			'lifeLeft = 0.;',
-			'}',
+			'		gl_Position = projectionMatrix * modelViewMatrix * vec4( newPosition, 1.0 );',
+
+			'	} else {',
+
+			'		gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );',
+			'		lifeLeft = 0.0;',
+			'		gl_PointSize = 0.;',
+
+			'	}',
 
-			'if( timeElapsed > 0. ) {',
-			'gl_Position = projectionMatrix * modelViewMatrix * vec4( newPosition, 1.0 );',
-			'} else {',
-			'gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );',
-			'lifeLeft = 0.;',
-			'gl_PointSize = 0.;',
-			'}',
 			'}'
 
-		].join("\n"),
+		].join( '\n' ),
 
 		fragmentShader: [
 
-			'float scaleLinear(float value, vec2 valueDomain) {',
-			'return (value - valueDomain.x) / (valueDomain.y - valueDomain.x);',
+			'float scaleLinear( float value, vec2 valueDomain ) {',
+
+			'	return ( value - valueDomain.x ) / ( valueDomain.y - valueDomain.x );',
+
 			'}',
 
-			'float scaleLinear(float value, vec2 valueDomain, vec2 valueRange) {',
-			'return mix(valueRange.x, valueRange.y, scaleLinear(value, valueDomain));',
+			'float scaleLinear( float value, vec2 valueDomain, vec2 valueRange ) {',
+
+			'	return mix( valueRange.x, valueRange.y, scaleLinear( value, valueDomain ) );',
+
 			'}',
 
 			'varying vec4 vColor;',
@@ -174,335 +133,368 @@ THREE.GPUParticleSystem = function(options) {
 
 			'void main() {',
 
-			'float alpha = 0.;',
+			'	float alpha = 0.;',
 
-			'if( lifeLeft > .995 ) {',
-			'alpha = scaleLinear( lifeLeft, vec2(1., .995), vec2(0., 1.));//mix( 0., 1., ( lifeLeft - .95 ) * 100. ) * .75;',
-			'} else {',
-			'alpha = lifeLeft * .75;',
-			'}',
+			'	if( lifeLeft > 0.995 ) {',
+
+			'		alpha = scaleLinear( lifeLeft, vec2( 1.0, 0.995 ), vec2( 0.0, 1.0 ) );',
 
-			'vec4 tex = texture2D( tSprite, gl_PointCoord );',
+			'	} else {',
+
+			'		alpha = lifeLeft * 0.75;',
+
+			'	}',
+
+			'	vec4 tex = texture2D( tSprite, gl_PointCoord );',
+			'	gl_FragColor = vec4( vColor.rgb * tex.a, alpha * tex.a );',
 
-			'gl_FragColor = vec4( vColor.rgb * tex.a, alpha * tex.a );',
 			'}'
 
-		].join("\n")
+		].join( '\n' )
 
 	};
 
 	// preload a million random numbers
-	self.rand = [];
 
-	for (var i = 1e5; i > 0; i--) {
-		self.rand.push(Math.random() - .5);
+	var i;
+
+	for ( i = 1e5; i > 0; i-- ) {
+
+		this.rand.push( Math.random() - 0.5 );
+
 	}
 
-	self.random = function() {
-		return ++i >= self.rand.length ? self.rand[i = 1] : self.rand[i];
+	this.random = function() {
+
+		return ++ i >= this.rand.length ? this.rand[ i = 1 ] : this.rand[ i ];
+
 	};
 
 	var textureLoader = new THREE.TextureLoader();
 
-	self.particleNoiseTex = self.PARTICLE_NOISE_TEXTURE || textureLoader.load("textures/perlin-512.png");
-	self.particleNoiseTex.wrapS = self.particleNoiseTex.wrapT = THREE.RepeatWrapping;
+	this.particleNoiseTex = this.PARTICLE_NOISE_TEXTURE || textureLoader.load( 'textures/perlin-512.png' );
+	this.particleNoiseTex.wrapS = this.particleNoiseTex.wrapT = THREE.RepeatWrapping;
 
-	self.particleSpriteTex = self.PARTICLE_SPRITE_TEXTURE || textureLoader.load("textures/particle2.png");
-	self.particleSpriteTex.wrapS = self.particleSpriteTex.wrapT = THREE.RepeatWrapping;
+	this.particleSpriteTex = this.PARTICLE_SPRITE_TEXTURE || textureLoader.load( 'textures/particle2.png' );
+	this.particleSpriteTex.wrapS = this.particleSpriteTex.wrapT = THREE.RepeatWrapping;
 
-	self.particleShaderMat = new THREE.ShaderMaterial({
+	this.particleShaderMat = new THREE.ShaderMaterial( {
 		transparent: true,
 		depthWrite: false,
 		uniforms: {
-			"uTime": {
+			'uTime': {
 				value: 0.0
 			},
-			"uScale": {
+			'uScale': {
 				value: 1.0
 			},
-			"tNoise": {
-				value: self.particleNoiseTex
+			'tNoise': {
+				value: this.particleNoiseTex
 			},
-			"tSprite": {
-				value: self.particleSpriteTex
+			'tSprite': {
+				value: this.particleSpriteTex
 			}
 		},
 		blending: THREE.AdditiveBlending,
 		vertexShader: GPUParticleShader.vertexShader,
 		fragmentShader: GPUParticleShader.fragmentShader
-	});
+	} );
 
 	// define defaults for all values
-	self.particleShaderMat.defaultAttributeValues.particlePositionsStartTime = [0, 0, 0, 0];
-	self.particleShaderMat.defaultAttributeValues.particleVelColSizeLife = [0, 0, 0, 0];
-
-	self.particleContainers = [];
 
-
-	// extend Object3D
-	THREE.Object3D.apply(this, arguments);
+	this.particleShaderMat.defaultAttributeValues.particlePositionsStartTime = [ 0, 0, 0, 0 ];
+	this.particleShaderMat.defaultAttributeValues.particleVelColSizeLife = [ 0, 0, 0, 0 ];
 
 	this.init = function() {
 
-		for (var i = 0; i < self.PARTICLE_CONTAINERS; i++) {
+		for ( var i = 0; i < this.PARTICLE_CONTAINERS; i ++ ) {
 
-			var c = new THREE.GPUParticleContainer(self.PARTICLES_PER_CONTAINER, self);
-			self.particleContainers.push(c);
-			self.add(c);
+			var c = new THREE.GPUParticleContainer( this.PARTICLES_PER_CONTAINER, this );
+			this.particleContainers.push( c );
+			this.add( c );
 
 		}
 
 	};
 
-	this.spawnParticle = function(options) {
+	this.spawnParticle = function( options ) {
+
+		this.PARTICLE_CURSOR ++;
+
+		if ( this.PARTICLE_CURSOR >= this.PARTICLE_COUNT ) {
+
+			this.PARTICLE_CURSOR = 1;
 
-		self.PARTICLE_CURSOR++;
-		if (self.PARTICLE_CURSOR >= self.PARTICLE_COUNT) {
-			self.PARTICLE_CURSOR = 1;
 		}
 
-		var currentContainer = self.particleContainers[Math.floor(self.PARTICLE_CURSOR / self.PARTICLES_PER_CONTAINER)];
+		var currentContainer = this.particleContainers[ Math.floor( this.PARTICLE_CURSOR / this.PARTICLES_PER_CONTAINER ) ];
 
-		currentContainer.spawnParticle(options);
+		currentContainer.spawnParticle( options );
 
 	};
 
-	this.update = function(time) {
-		for (var i = 0; i < self.PARTICLE_CONTAINERS; i++) {
+	this.update = function( time ) {
+
+		for ( var i = 0; i < this.PARTICLE_CONTAINERS; i ++ ) {
 
-			self.particleContainers[i].update(time);
+			this.particleContainers[ i ].update( time );
 
 		}
+
+	};
+
+	this.dispose = function() {
+
+		this.particleShaderMat.dispose();
+		this.particleNoiseTex.dispose();
+		this.particleSpriteTex.dispose();
+
+		for ( var i = 0; i < this.PARTICLE_CONTAINERS; i ++ ) {
+
+			this.particleContainers[ i ].dispose();
+
+		}
+
 	};
 
 	this.init();
 
 };
 
-THREE.GPUParticleSystem.prototype = Object.create(THREE.Object3D.prototype);
+THREE.GPUParticleSystem.prototype = Object.create( THREE.Object3D.prototype );
 THREE.GPUParticleSystem.prototype.constructor = THREE.GPUParticleSystem;
 
 
 // Subclass for particle containers, allows for very large arrays to be spread out
-THREE.GPUParticleContainer = function(maxParticles, particleSystem) {
-
-	var self = this;
-	self.PARTICLE_COUNT = maxParticles || 100000;
-	self.PARTICLE_CURSOR = 0;
-	self.time = 0;
-	self.DPR = window.devicePixelRatio;
-	self.GPUParticleSystem = particleSystem;
-
-	var particlesPerArray = Math.floor(self.PARTICLE_COUNT / self.MAX_ATTRIBUTES);
-
-	// extend Object3D
-	THREE.Object3D.apply(this, arguments);
-
-	// construct a couple small arrays used for packing variables into floats etc
-	var UINT8_VIEW = new Uint8Array(4);
-	var FLOAT_VIEW = new Float32Array(UINT8_VIEW.buffer);
-
-	function decodeFloat(x, y, z, w) {
-		UINT8_VIEW[0] = Math.floor(w);
-		UINT8_VIEW[1] = Math.floor(z);
-		UINT8_VIEW[2] = Math.floor(y);
-		UINT8_VIEW[3] = Math.floor(x);
-		return FLOAT_VIEW[0]
-	}
 
-	function componentToHex(c) {
-		var hex = c.toString(16);
-		return hex.length == 1 ? "0" + hex : hex;
-	}
+THREE.GPUParticleContainer = function( maxParticles, particleSystem ) {
 
-	function rgbToHex(r, g, b) {
-		return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
-	}
+	THREE.Object3D.apply( this, arguments );
 
-	function hexToRgb(hex) {
-		var r = hex >> 16;
-		var g = (hex & 0x00FF00) >> 8;
-		var b = hex & 0x0000FF;
+	this.PARTICLE_COUNT = maxParticles || 100000;
+	this.PARTICLE_CURSOR = 0;
+	this.time = 0;
+	this.offset = 0;
+	this.count = 0;
+	this.DPR = window.devicePixelRatio;
+	this.GPUParticleSystem = particleSystem;
+	this.particleUpdate = false;
 
-		if (r > 0) r--;
-		if (g > 0) g--;
-		if (b > 0) b--;
+	// geometry
 
-		return [r, g, b];
-	}
+	this.particleShaderGeo = new THREE.BufferGeometry();
 
-	self.particles = [];
-	self.deadParticles = [];
-	self.particlesAvailableSlot = [];
+	this.particleShaderGeo.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( this.PARTICLE_COUNT * 3 ), 3 ).setDynamic( true ) );
+	this.particleShaderGeo.addAttribute( 'positionStart', new THREE.BufferAttribute( new Float32Array( this.PARTICLE_COUNT * 3 ), 3 ).setDynamic( true ) );
+	this.particleShaderGeo.addAttribute( 'startTime', new THREE.BufferAttribute( new Float32Array( this.PARTICLE_COUNT ), 1 ).setDynamic( true ) );
+	this.particleShaderGeo.addAttribute( 'velocity', new THREE.BufferAttribute( new Float32Array( this.PARTICLE_COUNT * 3 ), 3 ).setDynamic( true ) );
+	this.particleShaderGeo.addAttribute( 'turbulence', new THREE.BufferAttribute( new Float32Array( this.PARTICLE_COUNT ), 1 ).setDynamic( true ) );
+	this.particleShaderGeo.addAttribute( 'color', new THREE.BufferAttribute( new Float32Array( this.PARTICLE_COUNT * 3 ), 3 ).setDynamic( true ) );
+	this.particleShaderGeo.addAttribute( 'size', new THREE.BufferAttribute( new Float32Array( this.PARTICLE_COUNT ), 1 ).setDynamic( true ) );
+	this.particleShaderGeo.addAttribute( 'lifeTime', new THREE.BufferAttribute( new Float32Array( this.PARTICLE_COUNT ), 1 ).setDynamic( true ) );
 
-	// create a container for particles
-	self.particleUpdate = false;
+	// material
 
-	// Shader Based Particle System
-	self.particleShaderGeo = new THREE.BufferGeometry();
+	this.particleShaderMat = this.GPUParticleSystem.particleShaderMat;
 
-	// new hyper compressed attributes
-	self.particleVertices = new Float32Array(self.PARTICLE_COUNT * 3); // position
-	self.particlePositionsStartTime = new Float32Array(self.PARTICLE_COUNT * 4); // position
-	self.particleVelColSizeLife = new Float32Array(self.PARTICLE_COUNT * 4);
+	var position = new THREE.Vector3();
+	var velocity = new THREE.Vector3();
+	var color = new THREE.Color();
 
-	for (var i = 0; i < self.PARTICLE_COUNT; i++) {
-		self.particlePositionsStartTime[i * 4 + 0] = 100; //x
-		self.particlePositionsStartTime[i * 4 + 1] = 0; //y
-		self.particlePositionsStartTime[i * 4 + 2] = 0.0; //z
-		self.particlePositionsStartTime[i * 4 + 3] = 0.0; //startTime
+	this.spawnParticle = function( options ) {
 
-		self.particleVertices[i * 3 + 0] = 0; //x
-		self.particleVertices[i * 3 + 1] = 0; //y
-		self.particleVertices[i * 3 + 2] = 0.0; //z
+		var positionStartAttribute = this.particleShaderGeo.getAttribute( 'positionStart' );
+		var startTimeAttribute = this.particleShaderGeo.getAttribute( 'startTime' );
+		var velocityAttribute = this.particleShaderGeo.getAttribute( 'velocity' );
+		var turbulenceAttribute = this.particleShaderGeo.getAttribute( 'turbulence' );
+		var colorAttribute = this.particleShaderGeo.getAttribute( 'color' );
+		var sizeAttribute = this.particleShaderGeo.getAttribute( 'size' );
+		var lifeTimeAttribute = this.particleShaderGeo.getAttribute( 'lifeTime' );
 
-		self.particleVelColSizeLife[i * 4 + 0] = decodeFloat(128, 128, 0, 0); //vel
-		self.particleVelColSizeLife[i * 4 + 1] = decodeFloat(0, 254, 0, 254); //color
-		self.particleVelColSizeLife[i * 4 + 2] = 1.0; //size
-		self.particleVelColSizeLife[i * 4 + 3] = 0.0; //lifespan
-	}
+		options = options || {};
 
-	self.particleShaderGeo.addAttribute('position', new THREE.BufferAttribute(self.particleVertices, 3));
-	self.particleShaderGeo.addAttribute('particlePositionsStartTime', new THREE.BufferAttribute(self.particlePositionsStartTime, 4).setDynamic(true));
-	self.particleShaderGeo.addAttribute('particleVelColSizeLife', new THREE.BufferAttribute(self.particleVelColSizeLife, 4).setDynamic(true));
+		// setup reasonable default values for all arguments
 
-	self.posStart = self.particleShaderGeo.getAttribute('particlePositionsStartTime');
-	self.velCol = self.particleShaderGeo.getAttribute('particleVelColSizeLife');
+		position = options.position !== undefined ? position.copy( options.position ) : position.set( 0, 0, 0 );
+		velocity = options.velocity !== undefined ? velocity.copy( options.velocity ) : velocity.set( 0, 0, 0 );
+		color = options.color !== undefined ? color.set( options.color ) : color.set( 0xffffff );
 
-	self.particleShaderMat = self.GPUParticleSystem.particleShaderMat;
+		var positionRandomness = options.positionRandomness !== undefined ? options.positionRandomness : 0;
+		var velocityRandomness = options.velocityRandomness !== undefined ? options.velocityRandomness : 0;
+		var colorRandomness = options.colorRandomness !== undefined ? options.colorRandomness : 1;
+		var turbulence = options.turbulence !== undefined ? options.turbulence : 1;
+		var lifetime = options.lifetime !== undefined ? options.lifetime : 5;
+		var size = options.size !== undefined ? options.size : 10;
+		var sizeRandomness = options.sizeRandomness !== undefined ? options.sizeRandomness : 0;
+		var smoothPosition = options.smoothPosition !== undefined ? options.smoothPosition : false;
 
-	this.init = function() {
-		self.particleSystem = new THREE.Points(self.particleShaderGeo, self.particleShaderMat);
-		self.particleSystem.frustumCulled = false;
-		this.add(self.particleSystem);
-	};
+		if ( this.DPR !== undefined ) size *= this.DPR;
 
-	var options = {},
-		position = new THREE.Vector3(),
-		velocity = new THREE.Vector3(),
-		positionRandomness = 0.,
-		velocityRandomness = 0.,
-		color = 0xffffff,
-		colorRandomness = 0.,
-		turbulence = 0.,
-		lifetime = 0.,
-		size = 0.,
-		sizeRandomness = 0.,
-		smoothPosition = false,
-		i;
-
-	var maxVel = 2;
-	var maxSource = 250;
-	this.offset = 0;
-	this.count = 0;
+		i = this.PARTICLE_CURSOR;
 
-	this.spawnParticle = function(options) {
+		// position
 
-		options = options || {};
+		positionStartAttribute.array[ i * 3 + 0 ] = position.x + ( particleSystem.random() * positionRandomness );
+		positionStartAttribute.array[ i * 3 + 1 ] = position.y + ( particleSystem.random() * positionRandomness );
+		positionStartAttribute.array[ i * 3 + 2 ] = position.z + ( particleSystem.random() * positionRandomness );
+
+		if ( smoothPosition === true ) {
+
+			positionStartAttribute.array[ i * 3 + 0 ] += - ( velocity.x * particleSystem.random() );
+			positionStartAttribute.array[ i * 3 + 1 ] += - ( velocity.y * particleSystem.random() );
+			positionStartAttribute.array[ i * 3 + 2 ] += - ( velocity.z * particleSystem.random() );
 
-		// setup reasonable default values for all arguments
-		position = options.position !== undefined ? position.copy(options.position) : position.set(0., 0., 0.);
-		velocity = options.velocity !== undefined ? velocity.copy(options.velocity) : velocity.set(0., 0., 0.);
-		positionRandomness = options.positionRandomness !== undefined ? options.positionRandomness : 0.0;
-		velocityRandomness = options.velocityRandomness !== undefined ? options.velocityRandomness : 0.0;
-		color = options.color !== undefined ? options.color : 0xffffff;
-		colorRandomness = options.colorRandomness !== undefined ? options.colorRandomness : 1.0;
-		turbulence = options.turbulence !== undefined ? options.turbulence : 1.0;
-		lifetime = options.lifetime !== undefined ? options.lifetime : 5.0;
-		size = options.size !== undefined ? options.size : 10;
-		sizeRandomness = options.sizeRandomness !== undefined ? options.sizeRandomness : 0.0;
-		smoothPosition = options.smoothPosition !== undefined ? options.smoothPosition : false;
-
-		if (self.DPR !== undefined) size *= self.DPR;
-
-		i = self.PARTICLE_CURSOR;
-
-		self.posStart.array[i * 4 + 0] = position.x + ((particleSystem.random()) * positionRandomness); // - ( velocity.x * particleSystem.random() ); //x
-		self.posStart.array[i * 4 + 1] = position.y + ((particleSystem.random()) * positionRandomness); // - ( velocity.y * particleSystem.random() ); //y
-		self.posStart.array[i * 4 + 2] = position.z + ((particleSystem.random()) * positionRandomness); // - ( velocity.z * particleSystem.random() ); //z
-		self.posStart.array[i * 4 + 3] = self.time + (particleSystem.random() * 2e-2); //startTime
-
-		if (smoothPosition === true) {
-			self.posStart.array[i * 4 + 0] += -(velocity.x * particleSystem.random()); //x
-			self.posStart.array[i * 4 + 1] += -(velocity.y * particleSystem.random()); //y
-			self.posStart.array[i * 4 + 2] += -(velocity.z * particleSystem.random()); //z
 		}
 
-		var velX = velocity.x + (particleSystem.random()) * velocityRandomness;
-		var velY = velocity.y + (particleSystem.random()) * velocityRandomness;
-		var velZ = velocity.z + (particleSystem.random()) * velocityRandomness;
+		// velocity
 
-		// convert turbulence rating to something we can pack into a vec4
-		var turbulence = Math.floor(turbulence * 254);
+		var maxVel = 2;
 
-		// clamp our value to between 0. and 1.
-		velX = Math.floor(maxSource * ((velX - -maxVel) / (maxVel - -maxVel)));
-		velY = Math.floor(maxSource * ((velY - -maxVel) / (maxVel - -maxVel)));
-		velZ = Math.floor(maxSource * ((velZ - -maxVel) / (maxVel - -maxVel)));
+		var velX = velocity.x + particleSystem.random() * velocityRandomness;
+		var velY = velocity.y + particleSystem.random() * velocityRandomness;
+		var velZ = velocity.z + particleSystem.random() * velocityRandomness;
 
-		self.velCol.array[i * 4 + 0] = decodeFloat(velX, velY, velZ, turbulence); //vel
+		velX = THREE.Math.clamp( ( velX - ( - maxVel ) ) / ( maxVel - ( - maxVel ) ), 0, 1 );
+		velY = THREE.Math.clamp( ( velY - ( - maxVel ) ) / ( maxVel - ( - maxVel ) ), 0, 1 );
+		velZ = THREE.Math.clamp( ( velZ - ( - maxVel ) ) / ( maxVel - ( - maxVel ) ), 0, 1 );
 
-		var rgb = hexToRgb(color);
+		velocityAttribute.array[ i * 3 + 0 ] = velX;
+		velocityAttribute.array[ i * 3 + 1 ] = velY;
+		velocityAttribute.array[ i * 3 + 2 ] = velZ;
 
-		for (var c = 0; c < rgb.length; c++) {
-			rgb[c] = Math.floor(rgb[c] + ((particleSystem.random()) * colorRandomness) * 254);
-			if (rgb[c] > 254) rgb[c] = 254;
-			if (rgb[c] < 0) rgb[c] = 0;
-		}
+		// color
+
+		color.r = THREE.Math.clamp( color.r + particleSystem.random() * colorRandomness, 0, 1 );
+		color.g = THREE.Math.clamp( color.g + particleSystem.random() * colorRandomness, 0, 1 );
+		color.b = THREE.Math.clamp( color.b + particleSystem.random() * colorRandomness, 0, 1 );
+
+		colorAttribute.array[ i * 3 + 0 ] = color.r;
+		colorAttribute.array[ i * 3 + 1 ] = color.g;
+		colorAttribute.array[ i * 3 + 2 ] = color.b;
 
-		self.velCol.array[i * 4 + 1] = decodeFloat(rgb[0], rgb[1], rgb[2], 254); //color
-		self.velCol.array[i * 4 + 2] = size + (particleSystem.random()) * sizeRandomness; //size
-		self.velCol.array[i * 4 + 3] = lifetime; //lifespan
+		// turbulence, size, lifetime and starttime
+
+		turbulenceAttribute.array[ i ] = turbulence;
+		sizeAttribute.array[ i ] = size + particleSystem.random() * sizeRandomness;
+		lifeTimeAttribute.array[ i ] = lifetime;
+		startTimeAttribute.array[ i ] = this.time + particleSystem.random() * 2e-2;
+
+		// offset
+
+		if ( this.offset === 0 ) {
+
+			this.offset = this.PARTICLE_CURSOR;
 
-		if (this.offset == 0) {
-			this.offset = self.PARTICLE_CURSOR;
 		}
 
-		self.count++;
+		// counter and cursor
 
-		self.PARTICLE_CURSOR++;
+		this.count ++;
+		this.PARTICLE_CURSOR ++;
+
+		if ( this.PARTICLE_CURSOR >= this.PARTICLE_COUNT ) {
+
+			this.PARTICLE_CURSOR = 0;
 
-		if (self.PARTICLE_CURSOR >= self.PARTICLE_COUNT) {
-			self.PARTICLE_CURSOR = 0;
 		}
 
-		self.particleUpdate = true;
+		this.particleUpdate = true;
 
 	};
 
-	this.update = function(time) {
+	this.init = function() {
 
-		self.time = time;
-		self.particleShaderMat.uniforms['uTime'].value = time;
+		this.particleSystem = new THREE.Points( this.particleShaderGeo, this.particleShaderMat );
+		this.particleSystem.frustumCulled = false;
+		this.add( this.particleSystem );
+
+	};
+
+	this.update = function( time ) {
+
+		this.time = time;
+		this.particleShaderMat.uniforms.uTime.value = time;
 
 		this.geometryUpdate();
 
 	};
 
 	this.geometryUpdate = function() {
-		if (self.particleUpdate == true) {
-			self.particleUpdate = false;
 
-			// if we can get away with a partial buffer update, do so
-			if (self.offset + self.count < self.PARTICLE_COUNT) {
-				self.posStart.updateRange.offset = self.velCol.updateRange.offset = self.offset * 4;
-				self.posStart.updateRange.count = self.velCol.updateRange.count = self.count * 4;
+		if ( this.particleUpdate === true ) {
+
+			this.particleUpdate = false;
+
+			var positionStartAttribute = this.particleShaderGeo.getAttribute( 'positionStart' );
+			var startTimeAttribute = this.particleShaderGeo.getAttribute( 'startTime' );
+			var velocityAttribute = this.particleShaderGeo.getAttribute( 'velocity' );
+			var turbulenceAttribute = this.particleShaderGeo.getAttribute( 'turbulence' );
+			var colorAttribute = this.particleShaderGeo.getAttribute( 'color' );
+			var sizeAttribute = this.particleShaderGeo.getAttribute( 'size' );
+			var lifeTimeAttribute = this.particleShaderGeo.getAttribute( 'lifeTime' );
+
+			if ( this.offset + this.count < this.PARTICLE_COUNT ) {
+
+				positionStartAttribute.updateRange.offset = this.offset * positionStartAttribute.itemSize;
+				startTimeAttribute.updateRange.offset = this.offset * startTimeAttribute.itemSize;
+				velocityAttribute.updateRange.offset = this.offset * velocityAttribute.itemSize;
+				turbulenceAttribute.updateRange.offset = this.offset * turbulenceAttribute.itemSize;
+				colorAttribute.updateRange.offset = this.offset * colorAttribute.itemSize;
+				sizeAttribute.updateRange.offset = this.offset * sizeAttribute.itemSize;
+				lifeTimeAttribute.updateRange.offset = this.offset * lifeTimeAttribute.itemSize;
+
+				positionStartAttribute.updateRange.count = this.count * positionStartAttribute.itemSize;
+				startTimeAttribute.updateRange.count = this.count * startTimeAttribute.itemSize;
+				velocityAttribute.updateRange.count = this.count * velocityAttribute.itemSize;
+				turbulenceAttribute.updateRange.count = this.count * turbulenceAttribute.itemSize;
+				colorAttribute.updateRange.count = this.count * colorAttribute.itemSize;
+				sizeAttribute.updateRange.count = this.count * sizeAttribute.itemSize;
+				lifeTimeAttribute.updateRange.count = this.count * lifeTimeAttribute.itemSize;
+
 			} else {
-				self.posStart.updateRange.offset = 0;
-				self.posStart.updateRange.count = self.velCol.updateRange.count = (self.PARTICLE_COUNT * 4);
+
+				positionStartAttribute.updateRange.offset = 0;
+				startTimeAttribute.updateRange.offset = 0;
+				velocityAttribute.updateRange.offset = 0;
+				turbulenceAttribute.updateRange.offset = 0;
+				colorAttribute.updateRange.offset = 0;
+				sizeAttribute.updateRange.offset = 0;
+				lifeTimeAttribute.updateRange.offset = 0;
+
+				positionStartAttribute.updateRange.count = positionStartAttribute.count;
+				startTimeAttribute.updateRange.count = startTimeAttribute.count;
+				velocityAttribute.updateRange.count = velocityAttribute.count;
+				turbulenceAttribute.updateRange.count = turbulenceAttribute.count;
+				colorAttribute.updateRange.count = colorAttribute.count;
+				sizeAttribute.updateRange.count = sizeAttribute.count;
+				lifeTimeAttribute.updateRange.count = lifeTimeAttribute.count;
+
 			}
 
-			self.posStart.needsUpdate = true;
-			self.velCol.needsUpdate = true;
+			positionStartAttribute.needsUpdate = true;
+			startTimeAttribute.needsUpdate = true;
+			velocityAttribute.needsUpdate = true;
+			turbulenceAttribute.needsUpdate = true;
+			colorAttribute.needsUpdate = true;
+			sizeAttribute.needsUpdate = true;
+			lifeTimeAttribute.needsUpdate = true;
+
+			this.offset = 0;
+			this.count = 0;
 
-			self.offset = 0;
-			self.count = 0;
 		}
+
+	};
+
+	this.dispose = function() {
+
+		this.particleShaderGeo.dispose();
+
 	};
 
 	this.init();
 
 };
 
-THREE.GPUParticleContainer.prototype = Object.create(THREE.Object3D.prototype);
+THREE.GPUParticleContainer.prototype = Object.create( THREE.Object3D.prototype );
 THREE.GPUParticleContainer.prototype.constructor = THREE.GPUParticleContainer;

+ 0 - 73
examples/js/MorphAnimation.js

@@ -1,73 +0,0 @@
-/**
- * @author mrdoob / http://mrdoob.com
- * @author willy-vvu / http://willy-vvu.github.io
- */
-
-THREE.MorphAnimation = function ( mesh ) {
-
-	this.mesh = mesh;
-	this.frames = mesh.morphTargetInfluences.length;
-	this.currentTime = 0;
-	this.duration = 1000;
-	this.loop = true;
-	this.lastFrame = 0;
-	this.currentFrame = 0;
-
-	this.isPlaying = false;
-
-};
-
-THREE.MorphAnimation.prototype = {
-
-	constructor: THREE.MorphAnimation,
-
-	play: function () {
-
-		this.isPlaying = true;
-
-	},
-
-	pause: function () {
-
-		this.isPlaying = false;
-
-	},
-
-	update: function ( delta ) {
-
-		if ( this.isPlaying === false ) return;
-
-		this.currentTime += delta;
-
-		if ( this.loop === true && this.currentTime > this.duration ) {
-
-			this.currentTime %= this.duration;
-
-		}
-
-		this.currentTime = Math.min( this.currentTime, this.duration );
-
-		var frameTime = this.duration / this.frames;
-		var frame = Math.floor( this.currentTime / frameTime );
-
-		var influences = this.mesh.morphTargetInfluences;
-
-		if ( frame !== this.currentFrame ) {
-
-			influences[ this.lastFrame ] = 0;
-			influences[ this.currentFrame ] = 1;
-			influences[ frame ] = 0;
-
-			this.lastFrame = this.currentFrame;
-			this.currentFrame = frame;
-
-		}
-
-		var mix = ( this.currentTime % frameTime ) / frameTime;
-
-		influences[ frame ] = mix;
-		influences[ this.lastFrame ] = 1 - mix;
-
-	}
-
-};

+ 43 - 21
examples/js/ParametricGeometries.js

@@ -7,7 +7,9 @@
 
 THREE.ParametricGeometries = {
 
-	klein: function ( v, u ) {
+	klein: function ( v, u, optionalTarget ) {
+
+		var result = optionalTarget || new THREE.Vector3();
 
 		u *= Math.PI;
 		v *= 2 * Math.PI;
@@ -28,25 +30,29 @@ THREE.ParametricGeometries = {
 
 		y = - 2 * ( 1 - Math.cos( u ) / 2 ) * Math.sin( v );
 
-		return new THREE.Vector3( x, y, z );
+		return result.set( x, y, z );
 
 	},
 
 	plane: function ( width, height ) {
 
-		return function( u, v ) {
+		return function( u, v, optionalTarget ) {
+
+			var result = optionalTarget || new THREE.Vector3();
 
 			var x = u * width;
 			var y = 0;
 			var z = v * height;
 
-			return new THREE.Vector3( x, y, z );
+			return result.set( x, y, z );
 
 		};
 
 	},
 
-	mobius: function( u, t ) {
+	mobius: function( u, t, optionalTarget ) {
+
+		var result = optionalTarget || new THREE.Vector3();
 
 		// flat mobius strip
 		// http://www.wolframalpha.com/input/?i=M%C3%B6bius+strip+parametric+equations&lk=1&a=ClashPrefs_*Surface.MoebiusStrip.SurfaceProperty.ParametricEquations-
@@ -56,28 +62,36 @@ THREE.ParametricGeometries = {
 		var x, y, z;
 
 		var a = 2;
+
 		x = Math.cos( v ) * ( a + u * Math.cos( v / 2 ) );
 		y = Math.sin( v ) * ( a + u * Math.cos( v / 2 ) );
 		z = u * Math.sin( v / 2 );
-		return new THREE.Vector3( x, y, z );
+
+		return result.set( x, y, z );
 
 	},
 
-	mobius3d: function( u, t ) {
+	mobius3d: function( u, t, optionalTarget ) {
+
+		var result = optionalTarget || new THREE.Vector3();
 
 		// volumetric mobius strip
+
 		u *= Math.PI;
 		t *= 2 * Math.PI;
 
 		u = u * 2;
 		var phi = u / 2;
 		var major = 2.25, a = 0.125, b = 0.65;
+
 		var x, y, z;
+
 		x = a * Math.cos( t ) * Math.cos( phi ) - b * Math.sin( t ) * Math.sin( phi );
 		z = a * Math.cos( t ) * Math.sin( phi ) + b * Math.sin( t ) * Math.cos( phi );
 		y = ( major + x ) * Math.sin( u );
 		x = ( major + x ) * Math.cos( u );
-		return new THREE.Vector3( x, y, z );
+
+		return result.set( x, y, z );
 
 	}
 
@@ -108,7 +122,7 @@ THREE.ParametricGeometries.TubeGeometry = function( path, segments, radius, segm
 
 		x, y, z, tx, ty, tz, u, v,
 
-		cx, cy, pos, pos2 = new THREE.Vector3(),
+		cx, cy, pos,
 		i, j, ip, jp, a, b, c, d, uva, uvb, uvc, uvd;
 
 	var frames = path.computeFrenetFrames( segments, closed ),
@@ -123,7 +137,9 @@ THREE.ParametricGeometries.TubeGeometry = function( path, segments, radius, segm
 
 
 
-	var ParametricTube = function( u, v ) {
+	var ParametricTube = function( u, v, optionalTarget ) {
+
+		var result = optionalTarget || new THREE.Vector3();
 
 		v *= 2 * Math.PI;
 
@@ -147,12 +163,11 @@ THREE.ParametricGeometries.TubeGeometry = function( path, segments, radius, segm
 		cx = - scope.radius * Math.cos( v ); // TODO: Hack: Negating it so it faces outside.
 		cy = scope.radius * Math.sin( v );
 
-		pos2.copy( pos );
-		pos2.x += cx * normal.x + cy * binormal.x;
-		pos2.y += cx * normal.y + cy * binormal.y;
-		pos2.z += cx * normal.z + cy * binormal.z;
+		pos.x += cx * normal.x + cy * binormal.x;
+		pos.y += cx * normal.y + cy * binormal.y;
+		pos.z += cx * normal.z + cy * binormal.z;
 
-		return pos2.clone();
+		return result.copy( pos );
 
 	};
 
@@ -180,7 +195,11 @@ THREE.ParametricGeometries.TorusKnotGeometry = function ( radius, tube, segments
 	this.p = p || 2;
 	this.q = q || 3;
 
-	function TorusKnotCurve() {}
+	function TorusKnotCurve() {
+
+		THREE.Curve.call( this );
+
+	}
 
 	TorusKnotCurve.prototype = Object.create( THREE.Curve.prototype );
 	TorusKnotCurve.prototype.constructor = TorusKnotCurve;
@@ -218,7 +237,9 @@ THREE.ParametricGeometries.TorusKnotGeometry.prototype.constructor = THREE.Param
   *********************************************/
 THREE.ParametricGeometries.SphereGeometry = function( size, u, v ) {
 
-	function sphere( u, v ) {
+	function sphere( u, v, optionalTarget ) {
+
+		var result = optionalTarget || new THREE.Vector3();
 
 		u *= Math.PI;
 		v *= 2 * Math.PI;
@@ -227,8 +248,7 @@ THREE.ParametricGeometries.SphereGeometry = function( size, u, v ) {
 		var y = size * Math.sin( u ) * Math.sin( v );
 		var z = size * Math.cos( u );
 
-
-		return new THREE.Vector3( x, y, z );
+		return result.set( x, y, z );
 
 	}
 
@@ -248,13 +268,15 @@ THREE.ParametricGeometries.SphereGeometry.prototype.constructor = THREE.Parametr
 
 THREE.ParametricGeometries.PlaneGeometry = function( width, depth, segmentsWidth, segmentsDepth ) {
 
-	function plane( u, v ) {
+	function plane( u, v, optionalTarget ) {
+
+		var result = optionalTarget || new THREE.Vector3();
 
 		var x = u * width;
 		var y = 0;
 		var z = v * depth;
 
-		return new THREE.Vector3( x, y, z );
+		return result.set( x, y, z );
 
 	}
 

+ 59 - 59
examples/js/RollerCoaster.js

@@ -2,7 +2,7 @@
  * @author mrdoob / http://mrdoob.com/
  */
 
-var RollerCoasterGeometry = function ( curve, size ) {
+function RollerCoasterGeometry( curve, divisions ) {
 
 	THREE.BufferGeometry.call( this );
 
@@ -28,13 +28,13 @@ var RollerCoasterGeometry = function ( curve, size ) {
 	// shapes
 
 	var step = [
-		new THREE.Vector3( -2.25,  0, 0 ),
-		new THREE.Vector3(  0,  -0.5, 0 ),
-		new THREE.Vector3(  0, -1.75, 0 ),
+		new THREE.Vector3( -0.225,  0, 0 ),
+		new THREE.Vector3(  0, -0.050, 0 ),
+		new THREE.Vector3(  0, -0.175, 0 ),
 
-		new THREE.Vector3(  0,  -0.5, 0 ),
-		new THREE.Vector3(  2.25,  0, 0 ),
-		new THREE.Vector3(  0, -1.75, 0 )
+		new THREE.Vector3(  0, -0.050, 0 ),
+		new THREE.Vector3(  0.225,  0, 0 ),
+		new THREE.Vector3(  0, -0.175, 0 )
 	];
 
 	var PI2 = Math.PI * 2;
@@ -45,7 +45,7 @@ var RollerCoasterGeometry = function ( curve, size ) {
 	for ( var i = 0; i < sides; i ++ ) {
 
 		var angle = ( i / sides ) * PI2;
-		tube1.push( new THREE.Vector3( Math.sin( angle ) * 0.6, Math.cos( angle ) * 0.6, 0 ) );
+		tube1.push( new THREE.Vector3( Math.sin( angle ) * 0.06, Math.cos( angle ) * 0.06, 0 ) );
 
 	}
 
@@ -55,14 +55,14 @@ var RollerCoasterGeometry = function ( curve, size ) {
 	for ( var i = 0; i < sides; i ++ ) {
 
 		var angle = ( i / sides ) * PI2;
-		tube2.push( new THREE.Vector3( Math.sin( angle ) * 0.25, Math.cos( angle ) * 0.25, 0 ) );
+		tube2.push( new THREE.Vector3( Math.sin( angle ) * 0.025, Math.cos( angle ) * 0.025, 0 ) );
 
 	}
 
 	var vector = new THREE.Vector3();
 	var normal = new THREE.Vector3();
 
-	var drawShape = function ( shape, color ) {
+	function drawShape( shape, color ) {
 
 		normal.set( 0, 0, -1 ).applyQuaternion( quaternion );
 
@@ -104,7 +104,7 @@ var RollerCoasterGeometry = function ( curve, size ) {
 	var normal3 = new THREE.Vector3();
 	var normal4 = new THREE.Vector3();
 
-	var extrudeShape = function ( shape, offset, color ) {
+	function extrudeShape( shape, offset, color ) {
 
 		for ( var j = 0, jl = shape.length; j < jl; j ++ ) {
 
@@ -175,9 +175,9 @@ var RollerCoasterGeometry = function ( curve, size ) {
 
 	var offset = new THREE.Vector3();
 
-	for ( var i = 1; i <= size; i ++ ) {
+	for ( var i = 1; i <= divisions; i ++ ) {
 
-		point.copy( curve.getPointAt( i / size ) );
+		point.copy( curve.getPointAt( i / divisions ) );
 
 		up.set( 0, 1, 0 );
 
@@ -195,9 +195,9 @@ var RollerCoasterGeometry = function ( curve, size ) {
 
 		}
 
-		extrudeShape( tube1, offset.set( 0, -1.25, 0 ), color2 );
-		extrudeShape( tube2, offset.set( 2, 0, 0 ), color1 );
-		extrudeShape( tube2, offset.set( -2, 0, 0 ), color1 );
+		extrudeShape( tube1, offset.set(  0,  -0.125, 0 ), color2 );
+		extrudeShape( tube2, offset.set(  0.2, 0,     0 ), color1 );
+		extrudeShape( tube2, offset.set( -0.2, 0,     0 ), color1 );
 
 		prevPoint.copy( point );
 		prevQuaternion.copy( quaternion );
@@ -214,7 +214,7 @@ var RollerCoasterGeometry = function ( curve, size ) {
 
 RollerCoasterGeometry.prototype = Object.create( THREE.BufferGeometry.prototype );
 
-var RollerCoasterLiftersGeometry = function ( curve, size ) {
+function RollerCoasterLiftersGeometry( curve, divisions ) {
 
 	THREE.BufferGeometry.call( this );
 
@@ -231,21 +231,21 @@ var RollerCoasterLiftersGeometry = function ( curve, size ) {
 	// shapes
 
 	var tube1 = [
-		new THREE.Vector3(  0,  0.5, -0.5 ),
-		new THREE.Vector3(  0,  0.5,  0.5 ),
-		new THREE.Vector3(  0, -0.5,  0 )
+		new THREE.Vector3(  0,  0.05, -0.05 ),
+		new THREE.Vector3(  0,  0.05,  0.05 ),
+		new THREE.Vector3(  0, -0.05,  0 )
 	];
 
 	var tube2 = [
-		new THREE.Vector3( -0.5, 0,  0.5 ),
-		new THREE.Vector3( -0.5, 0, -0.5 ),
-		new THREE.Vector3(  0.5, 0,  0 )
+		new THREE.Vector3( -0.05, 0,  0.05 ),
+		new THREE.Vector3( -0.05, 0, -0.05 ),
+		new THREE.Vector3(  0.05, 0,  0 )
 	];
 
 	var tube3 = [
-		new THREE.Vector3(  0.5, 0, -0.5 ),
-		new THREE.Vector3(  0.5, 0,  0.5 ),
-		new THREE.Vector3( -0.5, 0,  0 )
+		new THREE.Vector3(  0.05, 0, -0.05 ),
+		new THREE.Vector3(  0.05, 0,  0.05 ),
+		new THREE.Vector3( -0.05, 0,  0 )
 	];
 
 	var vector1 = new THREE.Vector3();
@@ -258,7 +258,7 @@ var RollerCoasterLiftersGeometry = function ( curve, size ) {
 	var normal3 = new THREE.Vector3();
 	var normal4 = new THREE.Vector3();
 
-	var extrudeShape = function ( shape, fromPoint, toPoint ) {
+	function extrudeShape( shape, fromPoint, toPoint ) {
 
 		for ( var j = 0, jl = shape.length; j < jl; j ++ ) {
 
@@ -322,10 +322,10 @@ var RollerCoasterLiftersGeometry = function ( curve, size ) {
 	var fromPoint = new THREE.Vector3();
 	var toPoint = new THREE.Vector3();
 
-	for ( var i = 1; i <= size; i ++ ) {
+	for ( var i = 1; i <= divisions; i ++ ) {
 
-		point.copy( curve.getPointAt( i / size ) );
-		tangent.copy( curve.getTangentAt( i / size ) );
+		point.copy( curve.getPointAt( i / divisions ) );
+		tangent.copy( curve.getTangentAt( i / divisions ) );
 
 		var angle = Math.atan2( tangent.x, tangent.z );
 
@@ -333,33 +333,33 @@ var RollerCoasterLiftersGeometry = function ( curve, size ) {
 
 		//
 
-		if ( point.y > 100 ) {
+		if ( point.y > 10 ) {
 
-			fromPoint.set( -7.5, -3.5, 0 );
+			fromPoint.set( -0.75, -0.35, 0 );
 			fromPoint.applyQuaternion( quaternion );
 			fromPoint.add( point );
 
-			toPoint.set( 7.5, -3.5, 0 );
+			toPoint.set( 0.75, -0.35, 0 );
 			toPoint.applyQuaternion( quaternion );
 			toPoint.add( point );
 
 			extrudeShape( tube1, fromPoint, toPoint );
 
-			fromPoint.set( -7, -3, 0 );
+			fromPoint.set( -0.7, -0.3, 0 );
 			fromPoint.applyQuaternion( quaternion );
 			fromPoint.add( point );
 
-			toPoint.set( -7, -point.y, 0 );
+			toPoint.set( -0.7, -point.y, 0 );
 			toPoint.applyQuaternion( quaternion );
 			toPoint.add( point );
 
 			extrudeShape( tube2, fromPoint, toPoint );
 
-			fromPoint.set( 7, -3, 0 );
+			fromPoint.set( 0.7, -0.3, 0 );
 			fromPoint.applyQuaternion( quaternion );
 			fromPoint.add( point );
 
-			toPoint.set( 7, -point.y, 0 );
+			toPoint.set( 0.7, -point.y, 0 );
 			toPoint.applyQuaternion( quaternion );
 			toPoint.add( point );
 
@@ -367,7 +367,7 @@ var RollerCoasterLiftersGeometry = function ( curve, size ) {
 
 		} else {
 
-			fromPoint.set( 0, -2, 0 );
+			fromPoint.set( 0, -0.2, 0 );
 			fromPoint.applyQuaternion( quaternion );
 			fromPoint.add( point );
 
@@ -388,7 +388,7 @@ var RollerCoasterLiftersGeometry = function ( curve, size ) {
 
 RollerCoasterLiftersGeometry.prototype = Object.create( THREE.BufferGeometry.prototype );
 
-var RollerCoasterShadowGeometry = function ( curve, size ) {
+function RollerCoasterShadowGeometry( curve, divisions ) {
 
 	THREE.BufferGeometry.call( this );
 
@@ -412,9 +412,9 @@ var RollerCoasterShadowGeometry = function ( curve, size ) {
 	var vector3 = new THREE.Vector3();
 	var vector4 = new THREE.Vector3();
 
-	for ( var i = 1; i <= size; i ++ ) {
+	for ( var i = 1; i <= divisions; i ++ ) {
 
-		point.copy( curve.getPointAt( i / size ) );
+		point.copy( curve.getPointAt( i / divisions ) );
 		point.y = 0;
 
 		forward.subVectors( point, prevPoint );
@@ -423,19 +423,19 @@ var RollerCoasterShadowGeometry = function ( curve, size ) {
 
 		quaternion.setFromAxisAngle( up, angle );
 
-		vector1.set( -3, 0, 0 );
+		vector1.set( -0.3, 0, 0 );
 		vector1.applyQuaternion( quaternion );
 		vector1.add( point );
 
-		vector2.set(  3, 0, 0 );
+		vector2.set(  0.3, 0, 0 );
 		vector2.applyQuaternion( quaternion );
 		vector2.add( point );
 
-		vector3.set(  3, 0, 0 );
+		vector3.set(  0.3, 0, 0 );
 		vector3.applyQuaternion( prevQuaternion );
 		vector3.add( prevPoint );
 
-		vector4.set( -3, 0, 0 );
+		vector4.set( -0.3, 0, 0 );
 		vector4.applyQuaternion( prevQuaternion );
 		vector4.add( prevPoint );
 
@@ -458,7 +458,7 @@ var RollerCoasterShadowGeometry = function ( curve, size ) {
 
 RollerCoasterShadowGeometry.prototype = Object.create( THREE.BufferGeometry.prototype );
 
-var SkyGeometry = function () {
+function SkyGeometry() {
 
 	THREE.BufferGeometry.call( this );
 
@@ -466,11 +466,11 @@ var SkyGeometry = function () {
 
 	for ( var i = 0; i < 100; i ++ ) {
 
-		var x = Math.random() * 8000 - 4000;
-		var y = Math.random() * 500 + 500;
-		var z = Math.random() * 8000 - 4000;
+		var x = Math.random() * 800 - 400;
+		var y = Math.random() * 50 + 50;
+		var z = Math.random() * 800 - 400;
 
-		var size = Math.random() * 400 + 200;
+		var size = Math.random() * 40 + 20;
 
 		vertices.push( x - size, y, z - size );
 		vertices.push( x + size, y, z - size );
@@ -489,7 +489,7 @@ var SkyGeometry = function () {
 
 SkyGeometry.prototype = Object.create( THREE.BufferGeometry.prototype );
 
-var TreesGeometry = function ( landscape ) {
+function TreesGeometry( landscape ) {
 
 	THREE.BufferGeometry.call( this );
 
@@ -501,10 +501,10 @@ var TreesGeometry = function ( landscape ) {
 
 	for ( var i = 0; i < 2000; i ++ ) {
 
-		var x = Math.random() * 5000 - 2500;
-		var z = Math.random() * 5000 - 2500;
+		var x = Math.random() * 500 - 250;
+		var z = Math.random() * 500 - 250;
 
-		raycaster.ray.origin.set( x, 500, z );
+		raycaster.ray.origin.set( x, 50, z );
 
 		var intersections = raycaster.intersectObject( landscape );
 
@@ -512,19 +512,19 @@ var TreesGeometry = function ( landscape ) {
 
 		var y = intersections[ 0 ].point.y;
 
-		var height = Math.random() * 50 + 5;
+		var height = Math.random() * 5 + 0.5;
 
 		var angle = Math.random() * Math.PI * 2;
 
-		vertices.push( x + Math.sin( angle ) * 10, y, z + Math.cos( angle ) * 10 );
+		vertices.push( x + Math.sin( angle ), y, z + Math.cos( angle ) );
 		vertices.push( x, y + height, z );
-		vertices.push( x + Math.sin( angle + Math.PI ) * 10, y, z + Math.cos( angle + Math.PI ) * 10 );
+		vertices.push( x + Math.sin( angle + Math.PI ), y, z + Math.cos( angle + Math.PI ) );
 
 		angle += Math.PI / 2;
 
-		vertices.push( x + Math.sin( angle ) * 10, y, z + Math.cos( angle ) * 10 );
+		vertices.push( x + Math.sin( angle ), y, z + Math.cos( angle ) );
 		vertices.push( x, y + height, z );
-		vertices.push( x + Math.sin( angle + Math.PI ) * 10, y, z + Math.cos( angle + Math.PI ) * 10 );
+		vertices.push( x + Math.sin( angle + Math.PI ), y, z + Math.cos( angle + Math.PI ) );
 
 		var random = Math.random() * 0.1;
 

+ 28 - 1
examples/js/WaterShader.js

@@ -210,9 +210,36 @@ THREE.Water = function ( renderer, camera, scene, options ) {
 
 };
 
-THREE.Water.prototype = Object.create( THREE.Mirror.prototype );
+THREE.Water.prototype = Object.create( THREE.Object3D.prototype );
 THREE.Water.prototype.constructor = THREE.Water;
 
+THREE.Water.prototype.render = function () {
+
+	if ( this.matrixNeedsUpdate ) this.updateTextureMatrix();
+
+	this.matrixNeedsUpdate = true;
+
+	// Render the mirrored view of the current scene into the target texture
+	var scene = this;
+
+	while ( scene.parent !== null ) {
+
+		scene = scene.parent;
+
+	}
+
+	if ( scene !== undefined && scene instanceof THREE.Scene ) {
+
+		this.material.visible = false;
+
+		this.renderer.render( scene, this.mirrorCamera, this.renderTarget, true );
+
+		this.material.visible = true;
+
+	}
+
+};
+
 
 THREE.Water.prototype.updateTextureMatrix = function () {
 

+ 4 - 2
examples/js/controls/DragControls.js

@@ -52,8 +52,10 @@ THREE.DragControls = function ( _objects, _camera, _domElement ) {
 
 		event.preventDefault();
 
-		_mouse.x = ( event.clientX / _domElement.clientWidth ) * 2 - 1;
-		_mouse.y = - ( event.clientY / _domElement.clientHeight ) * 2 + 1;
+		var rect = _domElement.getBoundingClientRect();
+
+		_mouse.x = ( (event.clientX - rect.left) / rect.width ) * 2 - 1;
+		_mouse.y = - ( (event.clientY - rect.top) / rect.height ) * 2 + 1;
 
 		_raycaster.setFromCamera( _mouse, _camera );
 

+ 37 - 21
examples/js/controls/OrbitControls.js

@@ -662,29 +662,37 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 		event.preventDefault();
 
-		if ( event.button === scope.mouseButtons.ORBIT ) {
+		switch ( event.button ) {
 
-			if ( scope.enableRotate === false ) return;
+			case scope.mouseButtons.ORBIT:
 
-			handleMouseDownRotate( event );
+				if ( scope.enableRotate === false ) return;
+
+				handleMouseDownRotate( event );
+
+				state = STATE.ROTATE;
+
+				break;
 
-			state = STATE.ROTATE;
+			case scope.mouseButtons.ZOOM:
 
-		} else if ( event.button === scope.mouseButtons.ZOOM ) {
+				if ( scope.enableZoom === false ) return;
 
-			if ( scope.enableZoom === false ) return;
+				handleMouseDownDolly( event );
 
-			handleMouseDownDolly( event );
+				state = STATE.DOLLY;
 
-			state = STATE.DOLLY;
+				break;
 
-		} else if ( event.button === scope.mouseButtons.PAN ) {
+			case scope.mouseButtons.PAN:
 
-			if ( scope.enablePan === false ) return;
+				if ( scope.enablePan === false ) return;
 
-			handleMouseDownPan( event );
+				handleMouseDownPan( event );
 
-			state = STATE.PAN;
+				state = STATE.PAN;
+
+				break;
 
 		}
 
@@ -705,23 +713,31 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 		event.preventDefault();
 
-		if ( state === STATE.ROTATE ) {
+		switch ( state ) {
 
-			if ( scope.enableRotate === false ) return;
+			case STATE.ROTATE:
 
-			handleMouseMoveRotate( event );
+				if ( scope.enableRotate === false ) return;
+
+				handleMouseMoveRotate( event );
+
+				break;
+
+			case STATE.DOLLY:
 
-		} else if ( state === STATE.DOLLY ) {
+				if ( scope.enableZoom === false ) return;
 
-			if ( scope.enableZoom === false ) return;
+				handleMouseMoveDolly( event );
 
-			handleMouseMoveDolly( event );
+				break;
 
-		} else if ( state === STATE.PAN ) {
+			case STATE.PAN:
 
-			if ( scope.enablePan === false ) return;
+				if ( scope.enablePan === false ) return;
 
-			handleMouseMovePan( event );
+				handleMouseMovePan( event );
+
+				break;
 
 		}
 

+ 0 - 24
examples/js/controls/VRControls.js

@@ -140,30 +140,6 @@ THREE.VRControls = function ( object, onError ) {
 
 	};
 
-	this.resetPose = function () {
-
-		if ( vrDisplay ) {
-
-			vrDisplay.resetPose();
-
-		}
-
-	};
-
-	this.resetSensor = function () {
-
-		console.warn( 'THREE.VRControls: .resetSensor() is now .resetPose().' );
-		this.resetPose();
-
-	};
-
-	this.zeroSensor = function () {
-
-		console.warn( 'THREE.VRControls: .zeroSensor() is now .resetPose().' );
-		this.resetPose();
-
-	};
-
 	this.dispose = function () {
 
 		vrDisplay = null;

+ 2 - 1
examples/js/curves/NURBSCurve.js

@@ -15,6 +15,8 @@
 
 THREE.NURBSCurve = function ( degree, knots /* array of reals */, controlPoints /* array of Vector(2|3|4) */, startKnot /* index in knots */, endKnot /* index in knots */ ) {
 
+	THREE.Curve.call( this );
+
 	this.degree = degree;
 	this.knots = knots;
 	this.controlPoints = [];
@@ -65,4 +67,3 @@ THREE.NURBSCurve.prototype.getTangent = function ( t ) {
 	return tangent;
 
 };
-

+ 5 - 0
examples/js/exporters/OBJExporter.js

@@ -49,6 +49,11 @@ THREE.OBJExporter.prototype = {
 				// name of the mesh object
 				output += 'o ' + mesh.name + '\n';
 
+				// name of the mesh material
+				if ( mesh.material && mesh.material.name ) {
+					output += 'usemtl ' + mesh.material.name + '\n';
+				}
+
 				// vertices
 
 				if( vertices !== undefined ) {

+ 5 - 2
examples/js/loaders/ColladaLoader.js

@@ -907,12 +907,14 @@ THREE.ColladaLoader = function () {
 						var transforms = jointData.transforms;
 
 						var matrix = new THREE.Matrix4();
+						var m1 = new THREE.Matrix4();
 
 						for (i = 0; i < transforms.length; i ++ ) {
 
 							var transform = transforms[ i ];
 
 							// kinda ghetto joint detection
+
 							if ( transform.sid && transform.sid.indexOf( 'joint' + jointIndex ) !== -1 ) {
 
 								// apply actual joint value here
@@ -937,8 +939,6 @@ THREE.ColladaLoader = function () {
 
 							} else {
 
-								var m1 = new THREE.Matrix4();
-
 								switch ( transform.type ) {
 
 									case 'matrix':
@@ -988,6 +988,9 @@ THREE.ColladaLoader = function () {
 
 						threejsNode.matrix.set.apply( threejsNode.matrix, elementsRowMajor );
 						threejsNode.matrix.decompose( threejsNode.position, threejsNode.quaternion, threejsNode.scale );
+
+						jointMap[ jointIndex ].position = value;
+
 					}
 
 				} else {

+ 51 - 40
examples/js/loaders/DRACOLoader.js

@@ -44,49 +44,37 @@ THREE.DRACOLoader.prototype = {
         this.verbosity = level;
     },
 
-    decodeDracoFile: ( function() {
-        let dracoDecoder;
+    decodeDracoFile: function(rawBuffer) {
+      const dracoDecoder = THREE.DRACOLoader.getDecoder();
+      /*
+       * Here is how to use Draco Javascript decoder and get the geometry.
+       */
+      const buffer = new dracoDecoder.DecoderBuffer();
+      buffer.Init(new Int8Array(rawBuffer), rawBuffer.byteLength);
+      const wrapper = new dracoDecoder.WebIDLWrapper();
 
-        if (typeof DracoModule === 'function') {
-          dracoDecoder = DracoModule();
-        } else {
-          console.error('THREE.DRACOLoader: DracoModule not found.');
-          return;
+      /*
+       * Determine what type is this file: mesh or point cloud.
+       */
+      const geometryType = wrapper.GetEncodedGeometryType(buffer);
+      if (geometryType == dracoDecoder.TRIANGULAR_MESH) {
+        if (this.verbosity > 0) {
+          console.log('Loaded a mesh.');
         }
-
-        return function(rawBuffer) {
-          const scope = this;
-          /*
-           * Here is how to use Draco Javascript decoder and get the geometry.
-           */
-          const buffer = new dracoDecoder.DecoderBuffer();
-          buffer.Init(new Int8Array(rawBuffer), rawBuffer.byteLength);
-          const wrapper = new dracoDecoder.WebIDLWrapper();
-
-          /*
-           * Determine what type is this file: mesh or point cloud.
-           */
-          const geometryType = wrapper.GetEncodedGeometryType(buffer);
-          if (geometryType == dracoDecoder.TRIANGULAR_MESH) {
-            if (this.verbosity > 0) {
-              console.log('Loaded a mesh.');
-            }
-          } else if (geometryType == dracoDecoder.POINT_CLOUD) {
-            if (this.verbosity > 0) {
-              console.log('Loaded a point cloud.');
-            }
-          } else {
-            const errorMsg = 'THREE.DRACOLoader: Unknown geometry type.'
-            console.error(errorMsg);
-            throw new Error(errorMsg);
-          }
-          return scope.convertDracoGeometryTo3JS(wrapper, geometryType, buffer,
-                                                 dracoDecoder);
+      } else if (geometryType == dracoDecoder.POINT_CLOUD) {
+        if (this.verbosity > 0) {
+          console.log('Loaded a point cloud.');
         }
-    } )(),
+      } else {
+        const errorMsg = 'THREE.DRACOLoader: Unknown geometry type.'
+        console.error(errorMsg);
+        throw new Error(errorMsg);
+      }
+      return this.convertDracoGeometryTo3JS(wrapper, geometryType, buffer);
+    },
 
-    convertDracoGeometryTo3JS: function(wrapper, geometryType, buffer,
-                                        dracoDecoder) {
+    convertDracoGeometryTo3JS: function(wrapper, geometryType, buffer) {
+        const dracoDecoder = THREE.DRACOLoader.getDecoder();
         let dracoGeometry;
         const start_time = performance.now();
         if (geometryType == dracoDecoder.TRIANGULAR_MESH) {
@@ -273,5 +261,28 @@ THREE.DRACOLoader.prototype = {
           console.log('Import time: ' + this.import_time);
         }
         return geometry;
+    },
+
+    isVersionSupported: function(version) {
+        return THREE.DRACOLoader.getDecoder().isVersionSupported(version);
     }
-};
+};
+
+/**
+ * Returns a singleton instance of the DracoModule decoder. Creating multiple
+ * copies of the decoder is expensive.
+ */
+THREE.DRACOLoader.getDecoder = (function() {
+    let decoder;
+
+    return function() {
+        if (typeof DracoModule === 'undefined') {
+          throw new Error('THREE.DRACOLoader: DracoModule not found.');
+        }
+
+        decoder = decoder || DracoModule();
+
+        return decoder;
+    };
+
+})();

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1114 - 1965
examples/js/loaders/FBXLoader2.js


+ 48 - 26
examples/js/loaders/GLTF2Loader.js

@@ -718,12 +718,12 @@ THREE.GLTF2Loader = ( function () {
 
 			switch ( semantic ) {
 
-				case "POSITION":
+				case 'POSITION':
 
 					shaderText = shaderText.replace( regEx, 'position' );
 					break;
 
-				case "NORMAL":
+				case 'NORMAL':
 
 					shaderText = shaderText.replace( regEx, 'normal' );
 					break;
@@ -735,6 +735,11 @@ THREE.GLTF2Loader = ( function () {
 					shaderText = shaderText.replace( regEx, 'uv' );
 					break;
 
+				case 'TEXCOORD_1':
+
+					shaderText = shaderText.replace( regEx, 'uv2' );
+					break;
+
 				case 'COLOR_0':
 				case 'COLOR0':
 				case 'COLOR':
@@ -742,12 +747,14 @@ THREE.GLTF2Loader = ( function () {
 					shaderText = shaderText.replace( regEx, 'color' );
 					break;
 
-				case "WEIGHT":
+				case 'WEIGHTS_0':
+				case 'WEIGHT': // WEIGHT semantic deprecated.
 
 					shaderText = shaderText.replace( regEx, 'skinWeight' );
 					break;
 
-				case "JOINT":
+				case 'JOINTS_0':
+				case 'JOINT': // JOINT semantic deprecated.
 
 					shaderText = shaderText.replace( regEx, 'skinIndex' );
 					break;
@@ -1689,9 +1696,15 @@ THREE.GLTF2Loader = ( function () {
 
 					var primitive = primitives[ name ];
 
+					var material = primitive.material !== undefined ? dependencies.materials[ primitive.material ] : createDefaultMaterial();
+
+					var geometry;
+
+					var meshNode;
+
 					if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLES || primitive.mode === undefined ) {
 
-						var geometry = new THREE.BufferGeometry();
+						geometry = new THREE.BufferGeometry();
 
 						var attributes = primitive.attributes;
 
@@ -1706,30 +1719,43 @@ THREE.GLTF2Loader = ( function () {
 							switch ( attributeId ) {
 
 								case 'POSITION':
+
 									geometry.addAttribute( 'position', bufferAttribute );
 									break;
 
 								case 'NORMAL':
+
 									geometry.addAttribute( 'normal', bufferAttribute );
 									break;
 
 								case 'TEXCOORD_0':
 								case 'TEXCOORD0':
 								case 'TEXCOORD':
+
 									geometry.addAttribute( 'uv', bufferAttribute );
 									break;
 
+								case 'TEXCOORD_1':
+
+									geometry.addAttribute( 'uv2', bufferAttribute );
+									break;
+
 								case 'COLOR_0':
 								case 'COLOR0':
 								case 'COLOR':
+
 									geometry.addAttribute( 'color', bufferAttribute );
 									break;
 
-								case 'WEIGHT':
+								case 'WEIGHTS_0':
+								case 'WEIGHT': // WEIGHT semantic deprecated.
+
 									geometry.addAttribute( 'skinWeight', bufferAttribute );
 									break;
 
-								case 'JOINT':
+								case 'JOINTS_0':
+								case 'JOINT': // JOINT semantic deprecated.
+
 									geometry.addAttribute( 'skinIndex', bufferAttribute );
 									break;
 
@@ -1743,19 +1769,12 @@ THREE.GLTF2Loader = ( function () {
 
 						}
 
-						var material = dependencies.materials !== undefined ? dependencies.materials[ primitive.material ] : createDefaultMaterial();
-
-						var meshNode = new THREE.Mesh( geometry, material );
+						meshNode = new THREE.Mesh( geometry, material );
 						meshNode.castShadow = true;
-						meshNode.name = ( name === "0" ? group.name : group.name + name );
-
-						if ( primitive.extras ) meshNode.userData = primitive.extras;
-
-						group.add( meshNode );
 
 					} else if ( primitive.mode === WEBGL_CONSTANTS.LINES ) {
 
-						var geometry = new THREE.BufferGeometry();
+						geometry = new THREE.BufferGeometry();
 
 						var attributes = primitive.attributes;
 
@@ -1783,10 +1802,6 @@ THREE.GLTF2Loader = ( function () {
 
 						}
 
-						var material = dependencies.materials[ primitive.material ];
-
-						var meshNode;
-
 						if ( primitive.indices !== undefined ) {
 
 							geometry.setIndex( dependencies.accessors[ primitive.indices ] );
@@ -1799,18 +1814,25 @@ THREE.GLTF2Loader = ( function () {
 
 						}
 
-						meshNode.name = ( name === "0" ? group.name : group.name + name );
+					} else {
 
-						if ( primitive.extras ) meshNode.userData = primitive.extras;
+						throw new Error( "Only triangular and line primitives are supported" );
 
-						group.add( meshNode );
+					}
 
-					} else {
+					if ( geometry.attributes.color !== undefined ) {
 
-						console.warn( "Only triangular and line primitives are supported" );
+						material.vertexColors = THREE.VertexColors;
+						material.needsUpdate = true;
 
 					}
 
+					meshNode.name = ( name === "0" ? group.name : group.name + name );
+
+					if ( primitive.extras ) meshNode.userData = primitive.extras;
+
+					group.add( meshNode );
+
 				}
 
 				return group;
@@ -1911,7 +1933,7 @@ THREE.GLTF2Loader = ( function () {
 					if ( sampler ) {
 
 						var target = channel.target;
-						var name = target.id;
+						var name = target.node || target.id; // NOTE: target.id is deprecated.
 						var input = animation.parameters !== undefined ? animation.parameters[ sampler.input ] : sampler.input;
 						var output = animation.parameters !== undefined ? animation.parameters[ sampler.output ] : sampler.output;
 

+ 9 - 0
examples/js/loaders/GLTFLoader.js

@@ -745,6 +745,11 @@ THREE.GLTFLoader = ( function () {
 					shaderText = shaderText.replace( regEx, 'uv' );
 					break;
 
+				case 'TEXCOORD_1':
+
+					shaderText = shaderText.replace( regEx, 'uv2' );
+					break;
+
 				case 'COLOR_0':
 				case 'COLOR0':
 				case 'COLOR':
@@ -1625,6 +1630,10 @@ THREE.GLTFLoader = ( function () {
 									geometry.addAttribute( 'uv', bufferAttribute );
 									break;
 
+								case 'TEXCOORD_1':
+									geometry.addAttribute( 'uv2', bufferAttribute );
+									break;
+
 								case 'COLOR_0':
 								case 'COLOR0':
 								case 'COLOR':

+ 1 - 2
examples/js/loaders/OBJLoader.js

@@ -720,8 +720,7 @@ THREE.OBJLoader.prototype = {
 
 				}
 
-				var multiMaterial = new THREE.MultiMaterial( createdMaterials );
-				mesh = ( ! isLine ? new THREE.Mesh( buffergeometry, multiMaterial ) : new THREE.LineSegments( buffergeometry, multiMaterial ) );
+				mesh = ( ! isLine ? new THREE.Mesh( buffergeometry, createdMaterials ) : new THREE.LineSegments( buffergeometry, createdMaterials ) );
 
 			} else {
 

+ 1027 - 0
examples/js/loaders/OBJLoader2.js

@@ -0,0 +1,1027 @@
+/**
+  * @author Kai Salmen / https://kaisalmen.de
+  * Development repository: https://github.com/kaisalmen/WWOBJLoader
+  */
+
+'use strict';
+
+if ( THREE.OBJLoader2 === undefined ) { THREE.OBJLoader2 = {} }
+
+/**
+ * Use this class to load OBJ data from files or to parse OBJ data from arraybuffer or text
+ * @class
+ *
+ * @param {THREE.DefaultLoadingManager} [manager] The loadingManager for the loader to use. Default is {@link THREE.DefaultLoadingManager}
+ */
+THREE.OBJLoader2 = (function () {
+
+	var OBJLOADER2_VERSION = '1.2.1';
+
+	function OBJLoader2( manager ) {
+		console.log( "Using THREE.OBJLoader2 version: " + OBJLOADER2_VERSION );
+		this.manager = Validator.verifyInput( manager, THREE.DefaultLoadingManager );
+
+		this.path = '';
+		this.fileLoader = new THREE.FileLoader( this.manager );
+
+		this.meshCreator = new MeshCreator();
+		this.parser = new Parser( this.meshCreator );
+
+		this.validated = false;
+	}
+
+	/**
+	 * Base path to use.
+	 * @memberOf THREE.OBJLoader2
+	 *
+	 * @param {string} path The basepath
+	 */
+	OBJLoader2.prototype.setPath = function ( path ) {
+		this.path = Validator.verifyInput( path, this.path );
+	};
+
+	/**
+	 * Set the node where the loaded objects will be attached.
+	 * @memberOf THREE.OBJLoader2
+	 *
+	 * @param {THREE.Object3D} sceneGraphBaseNode Scenegraph object where meshes will be attached
+	 */
+	OBJLoader2.prototype.setSceneGraphBaseNode = function ( sceneGraphBaseNode ) {
+		this.meshCreator.setSceneGraphBaseNode( sceneGraphBaseNode );
+	};
+
+	/**
+	 * Set materials loaded by MTLLoader or any other supplier of an Array of {@link THREE.Material}.
+	 * @memberOf THREE.OBJLoader2
+	 *
+	 * @param {THREE.Material[]} materials  Array of {@link THREE.Material} from MTLLoader
+	 */
+	OBJLoader2.prototype.setMaterials = function ( materials ) {
+		this.meshCreator.setMaterials( materials );
+	};
+
+	/**
+	 * Allows to set debug mode for the parser and the meshCreator.
+	 * @memberOf THREE.OBJLoader2
+	 *
+	 * @param {boolean} parserDebug Internal Parser will produce debug output
+	 * @param {boolean} meshCreatorDebug Internal MeshCreator will produce debug output
+	 */
+	OBJLoader2.prototype.setDebug = function ( parserDebug, meshCreatorDebug ) {
+		this.parser.setDebug( parserDebug );
+		this.meshCreator.setDebug( meshCreatorDebug );
+	};
+
+	/**
+	 * Use this convenient method to load an OBJ file at the given URL. Per default the fileLoader uses an arraybuffer
+	 * @memberOf THREE.OBJLoader2
+	 *
+	 * @param {string} url URL of the file to load
+	 * @param {callback} onLoad Called after loading was successfully completed
+	 * @param {callback} onProgress Called to report progress of loading. The argument will be the XmlHttpRequest instance, that contain {integer total} and {integer loaded} bytes.
+	 * @param {callback} onError Called after an error occurred during loading
+	 * @param {boolean} [useArrayBuffer=true] Set this to false to force string based parsing
+	 */
+	OBJLoader2.prototype.load = function ( url, onLoad, onProgress, onError, useArrayBuffer ) {
+		this._validate();
+		this.fileLoader.setPath( this.path );
+		this.fileLoader.setResponseType( useArrayBuffer !== false ? 'arraybuffer' : 'text' );
+
+		var scope = this;
+		scope.fileLoader.load( url, function ( content ) {
+
+			// only use parseText if useArrayBuffer is explicitly set to false
+			onLoad( useArrayBuffer !== false ? scope.parse( content ) : scope.parseText( content ) );
+
+		}, onProgress, onError );
+	};
+
+	/**
+	 * Default parse function: Parses OBJ file content stored in arrayBuffer and returns the sceneGraphBaseNode
+	 * @memberOf THREE.OBJLoader2
+	 *
+	 * @param {Uint8Array} arrayBuffer OBJ data as Uint8Array
+	 */
+	OBJLoader2.prototype.parse = function ( arrayBuffer ) {
+		// fast-fail on bad type
+		if ( ! ( arrayBuffer instanceof ArrayBuffer || arrayBuffer instanceof Uint8Array ) ) {
+
+			throw 'Provided input is not of type arraybuffer! Aborting...';
+
+		}
+		console.log( 'Parsing arrayBuffer...' );
+		console.time( 'parseArrayBuffer' );
+
+		this._validate();
+		this.parser.parseArrayBuffer( arrayBuffer );
+		var sceneGraphAttach = this._finalize();
+
+		console.timeEnd( 'parseArrayBuffer' );
+
+		return sceneGraphAttach;
+	};
+
+	/**
+	 * Legacy parse function: Parses OBJ file content stored in string and returns the sceneGraphBaseNode
+	 * @memberOf THREE.OBJLoader2
+	 *
+	 * @param {string} text OBJ data as string
+	 */
+	OBJLoader2.prototype.parseText = function ( text ) {
+		// fast-fail on bad type
+		if ( ! ( typeof( text ) === 'string' || text instanceof String ) ) {
+
+			throw 'Provided input is not of type String! Aborting...';
+
+		}
+		console.log( 'Parsing text...' );
+		console.time( 'parseText' );
+
+		this._validate();
+		this.parser.parseText( text );
+		var sceneGraphBaseNode = this._finalize();
+
+		console.timeEnd( 'parseText' );
+
+		return sceneGraphBaseNode;
+	};
+
+	OBJLoader2.prototype._validate = function () {
+		if ( this.validated ) return;
+
+		this.fileLoader = Validator.verifyInput( this.fileLoader, new THREE.FileLoader( this.manager ) );
+		this.parser.validate();
+		this.meshCreator.validate();
+
+		this.validated = true;
+	};
+
+	OBJLoader2.prototype._finalize = function () {
+		console.log( 'Global output object count: ' + this.meshCreator.globalObjectCount );
+
+		this.parser.finalize();
+		this.fileLoader = null;
+		var sceneGraphBaseNode = this.meshCreator.sceneGraphBaseNode;
+		this.meshCreator.finalize();
+		this.validated = false;
+
+		return sceneGraphBaseNode;
+	};
+
+	/**
+	 * Constants used by THREE.OBJLoader2
+	 */
+	var Consts = {
+		CODE_LF: 10,
+		CODE_CR: 13,
+		CODE_SPACE: 32,
+		CODE_SLASH: 47,
+		STRING_LF: '\n',
+		STRING_CR: '\r',
+		STRING_SPACE: ' ',
+		STRING_SLASH: '/',
+		LINE_F: 'f',
+		LINE_G: 'g',
+		LINE_L: 'l',
+		LINE_O: 'o',
+		LINE_S: 's',
+		LINE_V: 'v',
+		LINE_VT: 'vt',
+		LINE_VN: 'vn',
+		LINE_MTLLIB: 'mtllib',
+		LINE_USEMTL: 'usemtl',
+		/*
+		 * Build Face/Quad: first element in indexArray is the line identification, therefore offset of one needs to be taken into account
+		 * N-Gons are not supported
+		 * Quad Faces: FaceA: 0, 1, 2  FaceB: 2, 3, 0
+		 *
+		 * 0: "f vertex/uv/normal	vertex/uv/normal	vertex/uv/normal	(vertex/uv/normal)"
+		 * 1: "f vertex/uv		  	vertex/uv		   	vertex/uv		   	(vertex/uv		 )"
+		 * 2: "f vertex//normal	 	vertex//normal	  	vertex//normal	  	(vertex//normal  )"
+		 * 3: "f vertex			 	vertex			  	vertex			  	(vertex		  	 )"
+		 *
+		 * @param indexArray
+		 * @param faceType
+		 */
+		QUAD_INDICES_1: [ 1, 2, 3, 3, 4, 1 ],
+		QUAD_INDICES_2: [ 1, 3, 5, 5, 7, 1 ],
+		QUAD_INDICES_3: [ 1, 4, 7, 7, 10, 1 ]
+	};
+
+	var Validator = {
+		/**
+		 * If given input is null or undefined, false is returned otherwise true.
+		 *
+		 * @param input Anything
+		 * @returns {boolean}
+		 */
+		isValid: function( input ) {
+			return ( input !== null && input !== undefined );
+		},
+		/**
+		 * If given input is null or undefined, the defaultValue is returned otherwise the given input.
+		 *
+		 * @param input Anything
+		 * @param defaultValue Anything
+		 * @returns {*}
+		 */
+		verifyInput: function( input, defaultValue ) {
+			return ( input === null || input === undefined ) ? defaultValue : input;
+		}
+	};
+
+	OBJLoader2.prototype._getValidator = function () {
+		return Validator;
+	};
+
+	/**
+	 * Parse OBJ data either from ArrayBuffer or string
+	 * @class
+	 */
+	var Parser = (function () {
+
+		function Parser( meshCreator ) {
+			this.meshCreator = meshCreator;
+			this.rawObject = null;
+			this.inputObjectCount = 1;
+			this.debug = false;
+		}
+
+		Parser.prototype.setDebug = function ( debug ) {
+			if ( debug === true || debug === false ) this.debug = debug;
+		};
+
+		Parser.prototype.validate = function () {
+			this.rawObject = new RawObject();
+			this.inputObjectCount = 1;
+		};
+
+		/**
+		 * Parse the provided arraybuffer
+		 * @memberOf Parser
+		 *
+		 * @param {Uint8Array} arrayBuffer OBJ data as Uint8Array
+		 */
+		Parser.prototype.parseArrayBuffer = function ( arrayBuffer ) {
+			var arrayBufferView = new Uint8Array( arrayBuffer );
+			var length = arrayBufferView.byteLength;
+			var buffer = new Array( 32 );
+			var bufferPointer = 0;
+			var slashes = new Array( 32 );
+			var slashesPointer = 0;
+			var reachedFaces = false;
+			var code;
+			var word = '';
+			for ( var i = 0; i < length; i++ ) {
+
+				code = arrayBufferView[ i ];
+				switch ( code ) {
+					case Consts.CODE_SPACE:
+						if ( word.length > 0 ) buffer[ bufferPointer++ ] = word;
+						word = '';
+						break;
+
+					case Consts.CODE_SLASH:
+						slashes[ slashesPointer++ ] = i;
+						if ( word.length > 0 ) buffer[ bufferPointer++ ] = word;
+						word = '';
+						break;
+
+					case Consts.CODE_LF:
+						if ( word.length > 0 ) buffer[ bufferPointer++ ] = word;
+						word = '';
+						reachedFaces = this.processLine( buffer, bufferPointer, slashes, slashesPointer, reachedFaces );
+						slashesPointer = 0;
+						bufferPointer = 0;
+						break;
+
+					case Consts.CODE_CR:
+						break;
+
+					default:
+						word += String.fromCharCode( code );
+						break;
+				}
+			}
+		};
+
+		/**
+		 * Parse the provided text
+		 * @memberOf Parser
+		 *
+		 * @param {string} text OBJ data as string
+		 */
+		Parser.prototype.parseText = function ( text ) {
+			var length = text.length;
+			var buffer = new Array( 32 );
+			var bufferPointer = 0;
+			var slashes = new Array( 32 );
+			var slashesPointer = 0;
+			var reachedFaces = false;
+			var char;
+			var word = '';
+			for ( var i = 0; i < length; i++ ) {
+
+				char = text[ i ];
+				switch ( char ) {
+					case Consts.STRING_SPACE:
+						if ( word.length > 0 ) buffer[ bufferPointer++ ] = word;
+						word = '';
+						break;
+
+					case Consts.STRING_SLASH:
+						slashes[ slashesPointer++ ] = i;
+						if ( word.length > 0 ) buffer[ bufferPointer++ ] = word;
+						word = '';
+						break;
+
+					case Consts.STRING_LF:
+						if ( word.length > 0 ) buffer[ bufferPointer++ ] = word;
+						word = '';
+						reachedFaces = this.processLine( buffer, bufferPointer, slashes, slashesPointer, reachedFaces );
+						slashesPointer = 0;
+						bufferPointer = 0;
+						break;
+
+					case Consts.STRING_CR:
+						break;
+
+					default:
+						word += char;
+				}
+			}
+		};
+
+		Parser.prototype.processLine = function ( buffer, bufferPointer, slashes, slashesPointer, reachedFaces ) {
+			if ( bufferPointer < 1 ) return reachedFaces;
+
+			var bufferLength = bufferPointer - 1;
+			switch ( buffer[ 0 ] ) {
+				case Consts.LINE_V:
+
+					// object complete instance required if reached faces already (= reached next block of v)
+					if ( reachedFaces ) {
+
+						this.processCompletedObject( null, this.rawObject.groupName );
+						reachedFaces = false;
+
+					}
+					this.rawObject.pushVertex( buffer );
+					break;
+
+				case Consts.LINE_VT:
+					this.rawObject.pushUv( buffer );
+					break;
+
+				case Consts.LINE_VN:
+					this.rawObject.pushNormal( buffer );
+					break;
+
+				case Consts.LINE_F:
+					reachedFaces = true;
+					/*
+					 * 0: "f vertex/uv/normal ..."
+					 * 1: "f vertex/uv ..."
+					 * 2: "f vertex//normal ..."
+					 * 3: "f vertex ..."
+					 */
+					var haveQuad = bufferLength % 4 === 0;
+					if ( slashesPointer > 1 && ( slashes[ 1 ] - slashes[ 0 ] ) === 1 ) {
+
+						if ( haveQuad ) {
+							this.rawObject.buildQuadVVn( buffer );
+						} else {
+							this.rawObject.buildFaceVVn( buffer );
+						}
+
+					} else if ( bufferLength === slashesPointer * 2 ) {
+
+						if ( haveQuad ) {
+							this.rawObject.buildQuadVVt( buffer );
+						} else {
+							this.rawObject.buildFaceVVt( buffer );
+						}
+
+					} else if ( bufferLength * 2 === slashesPointer * 3 ) {
+
+						if ( haveQuad ) {
+							this.rawObject.buildQuadVVtVn( buffer );
+						} else {
+							this.rawObject.buildFaceVVtVn( buffer );
+						}
+
+					} else {
+
+						if ( haveQuad ) {
+							this.rawObject.buildQuadV( buffer );
+						} else {
+							this.rawObject.buildFaceV( buffer );
+						}
+
+					}
+					break;
+
+				case Consts.LINE_L:
+					if ( bufferLength === slashesPointer * 2 ) {
+
+						this.rawObject.buildLineVvt( buffer );
+
+					} else {
+
+						this.rawObject.buildLineV( buffer );
+
+					}
+					break;
+
+				case Consts.LINE_S:
+					this.rawObject.pushSmoothingGroup( buffer[ 1 ] );
+					break;
+
+				case Consts.LINE_G:
+					this.processCompletedGroup( buffer[ 1 ] );
+					break;
+
+				case Consts.LINE_O:
+					if ( this.rawObject.vertices.length > 0 ) {
+
+						this.processCompletedObject( buffer[ 1 ], null );
+						reachedFaces = false;
+
+					} else {
+
+						this.rawObject.pushObject( buffer[ 1 ] );
+
+					}
+					break;
+
+				case Consts.LINE_MTLLIB:
+					this.rawObject.pushMtllib( buffer[ 1 ] );
+					break;
+
+				case Consts.LINE_USEMTL:
+					this.rawObject.pushUsemtl( buffer[ 1 ] );
+					break;
+
+				default:
+					break;
+			}
+			return reachedFaces;
+		};
+
+		Parser.prototype.processCompletedObject = function ( objectName, groupName ) {
+			this.rawObject.finalize( this.meshCreator, this.inputObjectCount, this.debug );
+			this.inputObjectCount++;
+			this.rawObject = this.rawObject.newInstanceFromObject( objectName, groupName );
+		};
+
+		Parser.prototype.processCompletedGroup = function ( groupName ) {
+			var notEmpty = this.rawObject.finalize( this.meshCreator, this.inputObjectCount, this.debug );
+			if ( notEmpty ) {
+
+				this.inputObjectCount ++;
+				this.rawObject = this.rawObject.newInstanceFromGroup( groupName );
+
+			} else {
+
+				// if a group was set that did not lead to object creation in finalize, then the group name has to be updated
+				this.rawObject.pushGroup( groupName );
+
+			}
+		};
+
+		Parser.prototype.finalize = function () {
+			this.rawObject.finalize( this.meshCreator, this.inputObjectCount, this.debug );
+			this.inputObjectCount++;
+		};
+
+		return Parser;
+	})();
+
+	/**
+	 * {@link RawObject} is only used by {@link Parser}.
+	 * The user of OBJLoader2 does not need to care about this class.
+	 * It is defined publicly for inclusion in web worker based OBJ loader ({@link THREE.OBJLoader2.WWOBJLoader2})
+	 */
+	var RawObject = (function () {
+
+		function RawObject( objectName, groupName, mtllibName ) {
+			this.globalVertexOffset = 1;
+			this.globalUvOffset = 1;
+			this.globalNormalOffset = 1;
+
+			this.vertices = [];
+			this.normals = [];
+			this.uvs = [];
+
+			// faces are stored according combined index of group, material and smoothingGroup (0 or not)
+			this.mtllibName = Validator.verifyInput( mtllibName, 'none' );
+			this.objectName = Validator.verifyInput( objectName, 'none' );
+			this.groupName = Validator.verifyInput( groupName, 'none' );
+			this.activeMtlName = 'none';
+			this.activeSmoothingGroup = 1;
+
+			this.mtlCount = 0;
+			this.smoothingGroupCount = 0;
+
+			this.rawObjectDescriptions = [];
+			// this default index is required as it is possible to define faces without 'g' or 'usemtl'
+			var index = this.buildIndex( this.activeMtlName, this.activeSmoothingGroup );
+			this.rawObjectDescriptionInUse = new RawObjectDescription( this.objectName, this.groupName, this.activeMtlName, this.activeSmoothingGroup );
+			this.rawObjectDescriptions[ index ] = this.rawObjectDescriptionInUse;
+		}
+
+		RawObject.prototype.buildIndex = function ( materialName, smoothingGroup) {
+			return materialName + '|' + smoothingGroup;
+		};
+
+		RawObject.prototype.newInstanceFromObject = function ( objectName, groupName ) {
+			var newRawObject = new RawObject( objectName, groupName, this.mtllibName );
+
+			// move indices forward
+			newRawObject.globalVertexOffset = this.globalVertexOffset + this.vertices.length / 3;
+			newRawObject.globalUvOffset = this.globalUvOffset + this.uvs.length / 2;
+			newRawObject.globalNormalOffset = this.globalNormalOffset + this.normals.length / 3;
+
+			return newRawObject;
+		};
+
+		RawObject.prototype.newInstanceFromGroup = function ( groupName ) {
+			var newRawObject = new RawObject( this.objectName, groupName, this.mtllibName );
+
+			// keep current buffers and indices forward
+			newRawObject.vertices = this.vertices;
+			newRawObject.uvs = this.uvs;
+			newRawObject.normals = this.normals;
+			newRawObject.globalVertexOffset = this.globalVertexOffset;
+			newRawObject.globalUvOffset = this.globalUvOffset;
+			newRawObject.globalNormalOffset = this.globalNormalOffset;
+
+			return newRawObject;
+		};
+
+		RawObject.prototype.pushVertex = function ( buffer ) {
+			this.vertices.push( parseFloat( buffer[ 1 ] ) );
+			this.vertices.push( parseFloat( buffer[ 2 ] ) );
+			this.vertices.push( parseFloat( buffer[ 3 ] ) );
+		};
+
+		RawObject.prototype.pushUv = function ( buffer ) {
+			this.uvs.push( parseFloat( buffer[ 1 ] ) );
+			this.uvs.push( parseFloat( buffer[ 2 ] ) );
+		};
+
+		RawObject.prototype.pushNormal = function ( buffer ) {
+			this.normals.push( parseFloat( buffer[ 1 ] ) );
+			this.normals.push( parseFloat( buffer[ 2 ] ) );
+			this.normals.push( parseFloat( buffer[ 3 ] ) );
+		};
+
+		RawObject.prototype.pushObject = function ( objectName ) {
+			this.objectName = objectName;
+		};
+
+		RawObject.prototype.pushMtllib = function ( mtllibName ) {
+			this.mtllibName = mtllibName;
+		};
+
+		RawObject.prototype.pushGroup = function ( groupName ) {
+			this.groupName = groupName;
+			this.verifyIndex();
+		};
+
+		RawObject.prototype.pushUsemtl = function ( mtlName ) {
+			if ( this.activeMtlName === mtlName || ! Validator.isValid( mtlName ) ) return;
+			this.activeMtlName = mtlName;
+			this.mtlCount++;
+
+			this.verifyIndex();
+		};
+
+		RawObject.prototype.pushSmoothingGroup = function ( activeSmoothingGroup ) {
+			var normalized = activeSmoothingGroup === 'off' ? 0 : activeSmoothingGroup;
+			if ( this.activeSmoothingGroup === normalized ) return;
+			this.activeSmoothingGroup = normalized;
+			this.smoothingGroupCount++;
+
+			this.verifyIndex();
+		};
+
+		RawObject.prototype.verifyIndex = function () {
+			var index = this.buildIndex( this.activeMtlName, ( this.activeSmoothingGroup === 0 ) ? 0 : 1 );
+			this.rawObjectDescriptionInUse = this.rawObjectDescriptions[ index ];
+			if ( ! Validator.isValid( this.rawObjectDescriptionInUse ) ) {
+
+				this.rawObjectDescriptionInUse = new RawObjectDescription( this.objectName, this.groupName, this.activeMtlName, this.activeSmoothingGroup );
+				this.rawObjectDescriptions[ index ] = this.rawObjectDescriptionInUse;
+
+			}
+		};
+
+		RawObject.prototype.buildQuadVVtVn = function ( indexArray ) {
+			for ( var i = 0; i < 6; i ++ ) {
+				this.attachFaceV_( indexArray[ Consts.QUAD_INDICES_3[ i ] ] );
+				this.attachFaceVt( indexArray[ Consts.QUAD_INDICES_3[ i ] + 1 ] );
+				this.attachFaceVn( indexArray[ Consts.QUAD_INDICES_3[ i ] + 2 ] );
+			}
+		};
+
+		RawObject.prototype.buildQuadVVt = function ( indexArray ) {
+			for ( var i = 0; i < 6; i ++ ) {
+				this.attachFaceV_( indexArray[ Consts.QUAD_INDICES_2[ i ] ] );
+				this.attachFaceVt( indexArray[ Consts.QUAD_INDICES_2[ i ] + 1 ] );
+			}
+		};
+
+		RawObject.prototype.buildQuadVVn = function ( indexArray ) {
+			for ( var i = 0; i < 6; i ++ ) {
+				this.attachFaceV_( indexArray[ Consts.QUAD_INDICES_2[ i ] ] );
+				this.attachFaceVn( indexArray[ Consts.QUAD_INDICES_2[ i ] + 1 ] );
+			}
+		};
+
+		RawObject.prototype.buildQuadV = function ( indexArray ) {
+			for ( var i = 0; i < 6; i ++ ) {
+				this.attachFaceV_( indexArray[ Consts.QUAD_INDICES_1[ i ] ] );
+			}
+		};
+
+		RawObject.prototype.buildFaceVVtVn = function ( indexArray ) {
+			for ( var i = 1; i < 10; i += 3 ) {
+				this.attachFaceV_( indexArray[ i ] );
+				this.attachFaceVt( indexArray[ i + 1 ] );
+				this.attachFaceVn( indexArray[ i + 2 ] );
+			}
+		};
+
+		RawObject.prototype.buildFaceVVt = function ( indexArray ) {
+			for ( var i = 1; i < 7; i += 2 ) {
+				this.attachFaceV_( indexArray[ i ] );
+				this.attachFaceVt( indexArray[ i + 1 ] );
+			}
+		};
+
+		RawObject.prototype.buildFaceVVn = function ( indexArray ) {
+			for ( var i = 1; i < 7; i += 2 ) {
+				this.attachFaceV_( indexArray[ i ] );
+				this.attachFaceVn( indexArray[ i + 1 ] );
+			}
+		};
+
+		RawObject.prototype.buildFaceV = function ( indexArray ) {
+			for ( var i = 1; i < 4; i ++ ) {
+				this.attachFaceV_( indexArray[ i ] );
+			}
+		};
+
+		RawObject.prototype.attachFaceV_ = function ( faceIndex ) {
+			var faceIndexInt =  parseInt( faceIndex );
+			var index = ( faceIndexInt - this.globalVertexOffset ) * 3;
+
+			var rodiu = this.rawObjectDescriptionInUse;
+			rodiu.vertices.push( this.vertices[ index++ ] );
+			rodiu.vertices.push( this.vertices[ index++ ] );
+			rodiu.vertices.push( this.vertices[ index ] );
+		};
+
+		RawObject.prototype.attachFaceVt = function ( faceIndex ) {
+			var faceIndexInt =  parseInt( faceIndex );
+			var index = ( faceIndexInt - this.globalUvOffset ) * 2;
+
+			var rodiu = this.rawObjectDescriptionInUse;
+			rodiu.uvs.push( this.uvs[ index++ ] );
+			rodiu.uvs.push( this.uvs[ index ] );
+		};
+
+		RawObject.prototype.attachFaceVn = function ( faceIndex ) {
+			var faceIndexInt =  parseInt( faceIndex );
+			var index = ( faceIndexInt - this.globalNormalOffset ) * 3;
+
+			var rodiu = this.rawObjectDescriptionInUse;
+			rodiu.normals.push( this.normals[ index++ ] );
+			rodiu.normals.push( this.normals[ index++ ] );
+			rodiu.normals.push( this.normals[ index ] );
+		};
+
+		/*
+		 * Support for lines with or without texture. irst element in indexArray is the line identification
+		 * 0: "f vertex/uv		vertex/uv 		..."
+		 * 1: "f vertex			vertex 			..."
+		 */
+		RawObject.prototype.buildLineVvt = function ( lineArray ) {
+			var length = lineArray.length;
+			for ( var i = 1; i < length; i ++ ) {
+				this.vertices.push( parseInt( lineArray[ i ] ) );
+				this.uvs.push( parseInt( lineArray[ i ] ) );
+			}
+		};
+
+		RawObject.prototype.buildLineV = function ( lineArray ) {
+			var length = lineArray.length;
+			for ( var i = 1; i < length; i++ ) {
+				this.vertices.push( parseInt( lineArray[ i ] ) );
+			}
+		};
+
+		/**
+		 * Clear any empty rawObjectDescription and calculate absolute vertex, normal and uv counts
+		 */
+		RawObject.prototype.finalize = function ( meshCreator, inputObjectCount, debug ) {
+			var temp = this.rawObjectDescriptions;
+			this.rawObjectDescriptions = [];
+			var rawObjectDescription;
+			var index = 0;
+			var absoluteVertexCount = 0;
+			var absoluteNormalCount = 0;
+			var absoluteUvCount = 0;
+
+			for ( var name in temp ) {
+
+				rawObjectDescription = temp[ name ];
+				if ( rawObjectDescription.vertices.length > 0 ) {
+
+					if ( rawObjectDescription.objectName === 'none' ) rawObjectDescription.objectName = rawObjectDescription.groupName;
+					this.rawObjectDescriptions[ index++ ] = rawObjectDescription;
+					absoluteVertexCount += rawObjectDescription.vertices.length;
+					absoluteUvCount += rawObjectDescription.uvs.length;
+					absoluteNormalCount += rawObjectDescription.normals.length;
+
+				}
+			}
+
+			// don not continue if no result
+			var notEmpty = false;
+			if ( index > 0 ) {
+
+				if ( debug ) this.createReport( inputObjectCount, true );
+				meshCreator.buildMesh(
+					this.rawObjectDescriptions,
+					inputObjectCount,
+					absoluteVertexCount,
+					absoluteNormalCount,
+					absoluteUvCount
+				);
+				notEmpty = true;
+
+			}
+			return notEmpty;
+		};
+
+		RawObject.prototype.createReport = function ( inputObjectCount, printDirectly ) {
+			var report = {
+				name: this.objectName ? this.objectName : 'groups',
+				mtllibName: this.mtllibName,
+				vertexCount: this.vertices.length / 3,
+				normalCount: this.normals.length / 3,
+				uvCount: this.uvs.length / 2,
+				smoothingGroupCount: this.smoothingGroupCount,
+				mtlCount: this.mtlCount,
+				rawObjectDescriptions: this.rawObjectDescriptions.length
+			};
+
+			if ( printDirectly ) {
+				console.log( 'Input Object number: ' + inputObjectCount + ' Object name: ' + report.name );
+				console.log( 'Mtllib name: ' + report.mtllibName );
+				console.log( 'Vertex count: ' + report.vertexCount );
+				console.log( 'Normal count: ' + report.normalCount );
+				console.log( 'UV count: ' + report.uvCount );
+				console.log( 'SmoothingGroup count: ' + report.smoothingGroupCount );
+				console.log( 'Material count: ' + report.mtlCount );
+				console.log( 'Real RawObjectDescription count: ' + report.rawObjectDescriptions );
+				console.log( '' );
+			}
+
+			return report;
+		};
+
+		return RawObject;
+	})();
+
+	/**
+	 * Descriptive information and data (vertices, normals, uvs) to passed on to mesh building function.
+	 * @class
+	 *
+	 * @param {string} objectName Name of the mesh
+	 * @param {string} groupName Name of the group
+	 * @param {string} materialName Name of the material
+	 * @param {number} smoothingGroup Normalized smoothingGroup (0: THREE.FlatShading, 1: THREE.SmoothShading)
+	 */
+	var RawObjectDescription = (function () {
+
+		function RawObjectDescription( objectName, groupName, materialName, smoothingGroup ) {
+			this.objectName = objectName;
+			this.groupName = groupName;
+			this.materialName = materialName;
+			this.smoothingGroup = smoothingGroup;
+			this.vertices = [];
+			this.uvs = [];
+			this.normals = [];
+		}
+
+		return RawObjectDescription;
+	})();
+
+	/**
+	 * MeshCreator is used to transform RawObjectDescriptions to THREE.Mesh
+	 *
+	 * @class
+	 */
+	var MeshCreator = (function () {
+
+		function MeshCreator() {
+			this.sceneGraphBaseNode = null;
+			this.materials = null;
+			this.debug = false;
+			this.globalObjectCount = 1;
+
+			this.validated = false;
+		}
+
+		MeshCreator.prototype.setSceneGraphBaseNode = function ( sceneGraphBaseNode ) {
+			this.sceneGraphBaseNode = Validator.verifyInput( sceneGraphBaseNode, this.sceneGraphBaseNode );
+			this.sceneGraphBaseNode = Validator.verifyInput( this.sceneGraphBaseNode, new THREE.Group() );
+		};
+
+		MeshCreator.prototype.setMaterials = function ( materials ) {
+			this.materials = Validator.verifyInput( materials, this.materials );
+			this.materials = Validator.verifyInput( this.materials, { materials: [] } );
+		};
+
+		MeshCreator.prototype.setDebug = function ( debug ) {
+			if ( debug === true || debug === false ) this.debug = debug;
+		};
+
+		MeshCreator.prototype.validate = function () {
+			if ( this.validated ) return;
+
+			this.setSceneGraphBaseNode( null );
+			this.setMaterials( null );
+			this.setDebug( null );
+			this.globalObjectCount = 1;
+		};
+
+		MeshCreator.prototype.finalize = function () {
+			this.sceneGraphBaseNode = null;
+			this.materials = null;
+			this.validated = false;
+		};
+
+		/**
+		 * This is an internal function, but due to its importance to Parser it is documented.
+		 * RawObjectDescriptions are transformed to THREE.Mesh.
+		 * It is ensured that rawObjectDescriptions only contain objects with vertices (no need to check).
+		 * This method shall be overridden by the web worker implementation
+		 *
+		 * @param {RawObjectDescription[]} rawObjectDescriptions Array of descriptive information and data (vertices, normals, uvs) about the parsed object(s)
+		 * @param {number} inputObjectCount Number of objects already retrieved from OBJ
+		 * @param {number} absoluteVertexCount Sum of all vertices of all rawObjectDescriptions
+		 * @param {number} absoluteNormalCount Sum of all normals of all rawObjectDescriptions
+		 * @param {number} absoluteUvCount Sum of all uvs of all rawObjectDescriptions
+		 */
+		MeshCreator.prototype.buildMesh = function ( rawObjectDescriptions, inputObjectCount, absoluteVertexCount, absoluteNormalCount, absoluteUvCount ) {
+
+			if ( this.debug ) console.log( 'MeshCreator.buildRawMeshData:\nInput object no.: ' + inputObjectCount );
+
+			var bufferGeometry = new THREE.BufferGeometry();
+			var vertexBA = new THREE.BufferAttribute( new Float32Array( absoluteVertexCount ), 3 );
+			bufferGeometry.addAttribute( 'position', vertexBA );
+
+			var normalBA;
+			if ( absoluteNormalCount > 0 ) {
+
+				normalBA = new THREE.BufferAttribute( new Float32Array( absoluteNormalCount ), 3 );
+				bufferGeometry.addAttribute( 'normal', normalBA );
+
+			}
+			var uvBA;
+			if ( absoluteUvCount > 0 ) {
+
+				uvBA = new THREE.BufferAttribute( new Float32Array( absoluteUvCount ), 2 );
+				bufferGeometry.addAttribute( 'uv', uvBA );
+
+			}
+
+			if ( this.debug ) console.log( 'Creating Multi-Material for object no.: ' + this.globalObjectCount );
+
+			var rawObjectDescription;
+			var material;
+			var materialName;
+			var createMultiMaterial = rawObjectDescriptions.length > 1;
+			var materials = [];
+			var materialIndex = 0;
+			var materialIndexMapping = [];
+			var selectedMaterialIndex;
+
+			var vertexBAOffset = 0;
+			var vertexGroupOffset = 0;
+			var vertexLength;
+			var normalOffset = 0;
+			var uvOffset = 0;
+
+			for ( var oodIndex in rawObjectDescriptions ) {
+				rawObjectDescription = rawObjectDescriptions[ oodIndex ];
+
+				materialName = rawObjectDescription.materialName;
+				material = this.materials[ materialName ];
+				if ( ! material ) {
+
+					material = this.materials[ 'defaultMaterial' ];
+					if ( ! material ) {
+
+						material = new THREE.MeshStandardMaterial( { color: 0xDCF1FF} );
+						material.name = 'defaultMaterial';
+						this.materials[ 'defaultMaterial' ] = material;
+
+					}
+					console.warn( 'object_group "' + rawObjectDescription.objectName + '_' + rawObjectDescription.groupName + '" was defined without material! Assigning "defaultMaterial".' );
+
+				}
+				// clone material in case flat shading is needed due to smoothingGroup 0
+				if ( rawObjectDescription.smoothingGroup === 0 ) {
+
+					materialName = material.name + '_flat';
+					var materialClone = this.materials[ materialName ];
+					if ( ! materialClone ) {
+
+						materialClone = material.clone();
+						materialClone.name = materialName;
+						materialClone.shading = THREE.FlatShading;
+						this.materials[ materialName ] = name;
+
+					}
+
+				}
+
+				vertexLength = rawObjectDescription.vertices.length;
+				if ( createMultiMaterial ) {
+
+					// re-use material if already used before. Reduces materials array size and eliminates duplicates
+					selectedMaterialIndex = materialIndexMapping[ materialName ];
+					if ( ! selectedMaterialIndex ) {
+
+						selectedMaterialIndex = materialIndex;
+						materialIndexMapping[ materialName ] = materialIndex;
+						materials.push( material );
+						materialIndex++;
+
+					}
+
+					bufferGeometry.addGroup( vertexGroupOffset, vertexLength / 3, selectedMaterialIndex );
+					vertexGroupOffset += vertexLength / 3;
+				}
+
+				vertexBA.set( rawObjectDescription.vertices, vertexBAOffset );
+				vertexBAOffset += vertexLength;
+
+				if ( normalBA ) {
+
+					normalBA.set( rawObjectDescription.normals, normalOffset );
+					normalOffset += rawObjectDescription.normals.length;
+
+				}
+				if ( uvBA ) {
+
+					uvBA.set( rawObjectDescription.uvs, uvOffset );
+					uvOffset += rawObjectDescription.uvs.length;
+
+				}
+				if ( this.debug ) this.printReport( rawObjectDescription, selectedMaterialIndex );
+
+			}
+			if ( ! normalBA ) bufferGeometry.computeVertexNormals();
+
+			if ( createMultiMaterial ) material = materials;
+			var mesh = new THREE.Mesh( bufferGeometry, material );
+			this.sceneGraphBaseNode.add( mesh );
+
+			this.globalObjectCount++;
+		};
+
+		MeshCreator.prototype.printReport = function ( rawObjectDescription, selectedMaterialIndex ) {
+			console.log(
+				' Output Object no.: ' + this.globalObjectCount +
+				'\n objectName: ' + rawObjectDescription.objectName +
+				'\n groupName: ' + rawObjectDescription.groupName +
+				'\n materialName: ' + rawObjectDescription.materialName +
+				'\n materialIndex: ' + selectedMaterialIndex +
+				'\n smoothingGroup: ' + rawObjectDescription.smoothingGroup +
+				'\n #vertices: ' + rawObjectDescription.vertices.length / 3 +
+				'\n #uvs: ' + rawObjectDescription.uvs.length / 2 +
+				'\n #normals: ' + rawObjectDescription.normals.length / 3
+			);
+		};
+
+		return MeshCreator;
+	})();
+
+	OBJLoader2.prototype._buildWebWorkerCode = function ( funcBuildObject, funcBuildSingelton ) {
+		var workerCode = '';
+		workerCode += funcBuildObject( 'Consts', Consts );
+		workerCode += funcBuildObject( 'Validator', Validator );
+		workerCode += funcBuildSingelton( 'Parser', 'Parser', Parser );
+		workerCode += funcBuildSingelton( 'RawObject', 'RawObject', RawObject );
+		workerCode += funcBuildSingelton( 'RawObjectDescription', 'RawObjectDescription', RawObjectDescription );
+		return workerCode;
+	};
+
+	return OBJLoader2;
+})();

+ 1407 - 0
examples/js/loaders/WWOBJLoader2.js

@@ -0,0 +1,1407 @@
+/**
+  * @author Kai Salmen / https://kaisalmen.de
+  * Development repository: https://github.com/kaisalmen/WWOBJLoader
+  */
+
+'use strict';
+
+if ( THREE.OBJLoader2 === undefined ) { THREE.OBJLoader2 = {} }
+
+/**
+ * OBJ data will be loaded by dynamically created web worker.
+ * First feed instructions with: prepareRun
+ * Then: Execute with: run
+ * @class
+ */
+THREE.OBJLoader2.WWOBJLoader2 = (function () {
+
+	var WWOBJLOADER2_VERSION = '1.2.1';
+
+	var Validator = THREE.OBJLoader2.prototype._getValidator();
+
+	function WWOBJLoader2() {
+		this._init();
+	}
+
+	WWOBJLoader2.prototype._init = function () {
+		console.log( "Using THREE.OBJLoader2.WWOBJLoader2 version: " + WWOBJLOADER2_VERSION );
+		
+		// check worker support first
+		if ( window.Worker === undefined ) throw "This browser does not support web workers!";
+		if ( window.Blob === undefined  ) throw "This browser does not support Blob!";
+		if ( ! typeof window.URL.createObjectURL === 'function'  ) throw "This browser does not support Object creation from URL!";
+
+		this.instanceNo = 0;
+		this.worker = null;
+		this.workerCode = null;
+		this.debug = false;
+
+		this.sceneGraphBaseNode = null;
+		this.streamMeshes = true;
+		this.meshStore = null;
+		this.modelName = 'none';
+		this.validated = false;
+		this.running = false;
+		this.requestTerminate = false;
+
+		this.clearAllCallbacks();
+
+		this.manager = THREE.DefaultLoadingManager;
+		this.fileLoader = new THREE.FileLoader( this.manager );
+		this.mtlLoader = null;
+		this.crossOrigin = null;
+
+		this.dataAvailable = false;
+		this.objAsArrayBuffer = null;
+		this.fileObj = null;
+		this.pathObj = null;
+
+		this.fileMtl = null;
+		this.mtlAsString = null;
+		this.texturePath = null;
+
+		this.materials = [];
+		this.counter = 0;
+	};
+
+	/**
+	 * Enable or disable debug logging.
+	 * @memberOf THREE.OBJLoader2.WWOBJLoader2
+	 *
+	 * @param {boolean} enabled True or false
+	 */
+	WWOBJLoader2.prototype.setDebug = function ( enabled ) {
+		this.debug = enabled;
+	};
+
+	/**
+	 * Sets the CORS string to be used.
+	 * @memberOf THREE.OBJLoader2.WWOBJLoader2
+	 *
+	 * @param {string} crossOrigin CORS value
+	 */
+	WWOBJLoader2.prototype.setCrossOrigin = function ( crossOrigin ) {
+		this.crossOrigin = crossOrigin;
+	};
+
+	/**
+	 * Register callback function that is invoked by internal function "_announceProgress" to print feedback.
+	 * @memberOf THREE.OBJLoader2.WWOBJLoader2
+	 *
+	 * @param {callback} callbackProgress Callback function for described functionality
+	 */
+	WWOBJLoader2.prototype.registerCallbackProgress = function ( callbackProgress ) {
+		if ( Validator.isValid( callbackProgress ) ) this.callbacks.progress.push( callbackProgress );
+	};
+
+	/**
+	 * Register callback function that is called once loading of the complete model is completed.
+	 * @memberOf THREE.OBJLoader2.WWOBJLoader2
+	 *
+	 * @param {callback} callbackCompletedLoading Callback function for described functionality
+	 */
+	WWOBJLoader2.prototype.registerCallbackCompletedLoading = function ( callbackCompletedLoading ) {
+		if ( Validator.isValid( callbackCompletedLoading ) ) this.callbacks.completedLoading.push( callbackCompletedLoading );
+	};
+
+	/**
+	 * Register callback function that is called once materials have been loaded. It allows to alter and return materials.
+	 * @memberOf THREE.OBJLoader2.WWOBJLoader2
+	 *
+	 * @param {callback} callbackMaterialsLoaded Callback function for described functionality
+	 */
+	WWOBJLoader2.prototype.registerCallbackMaterialsLoaded = function ( callbackMaterialsLoaded ) {
+		if ( Validator.isValid( callbackMaterialsLoaded ) ) this.callbacks.materialsLoaded.push( callbackMaterialsLoaded );
+	};
+
+	/**
+	 * Register callback function that is called every time a mesh was loaded.
+	 * Use {@link THREE.OBJLoader2.WWOBJLoader2.LoadedMeshUserOverride} for alteration instructions (geometry, material or disregard mesh).
+	 * @memberOf THREE.OBJLoader2.WWOBJLoader2
+	 *
+	 * @param {callback} callbackMeshLoaded Callback function for described functionality
+	 */
+	WWOBJLoader2.prototype.registerCallbackMeshLoaded = function ( callbackMeshLoaded ) {
+		if ( Validator.isValid( callbackMeshLoaded ) ) this.callbacks.meshLoaded.push( callbackMeshLoaded );
+	};
+
+	/**
+	 * Register callback function that is called to report an error that prevented loading.
+	 * @memberOf THREE.OBJLoader2.WWOBJLoader2
+	 *
+	 * @param {callback} callbackErrorWhileLoading Callback function for described functionality
+	 */
+	WWOBJLoader2.prototype.registerCallbackErrorWhileLoading = function ( callbackErrorWhileLoading ) {
+		if ( Validator.isValid( callbackErrorWhileLoading ) ) this.callbacks.errorWhileLoading.push( callbackErrorWhileLoading );
+	};
+
+	/**
+	 * Clears all registered callbacks.
+	 * @memberOf THREE.OBJLoader2.WWOBJLoader2
+	 */
+	WWOBJLoader2.prototype.clearAllCallbacks = function () {
+		this.callbacks = {
+			progress: [],
+			completedLoading: [],
+			errorWhileLoading: [],
+			materialsLoaded: [],
+			meshLoaded: []
+		};
+	};
+
+	/**
+	 * Call requestTerminate to terminate the web worker and free local resource after execution.
+	 * @memberOf THREE.OBJLoader2.WWOBJLoader2
+	 *
+	 * @param {boolean} requestTerminate True or false
+	 */
+	WWOBJLoader2.prototype.setRequestTerminate = function ( requestTerminate ) {
+		this.requestTerminate = requestTerminate === true;
+	};
+
+	WWOBJLoader2.prototype._validate = function () {
+		if ( this.validated ) return;
+		if ( ! Validator.isValid( this.worker ) ) {
+
+			this._buildWebWorkerCode();
+			var blob = new Blob( [ this.workerCode ], { type: 'text/plain' } );
+			this.worker = new Worker( window.URL.createObjectURL( blob ) );
+
+			var scope = this;
+			var scopeFunction = function ( e ) {
+				scope._receiveWorkerMessage( e );
+			};
+			this.worker.addEventListener( 'message', scopeFunction, false );
+
+		}
+
+		this.sceneGraphBaseNode = null;
+		this.streamMeshes = true;
+		this.meshStore = [];
+		this.modelName = 'none';
+		this.validated = true;
+		this.running = true;
+		this.requestTerminate = false;
+
+		this.fileLoader = Validator.verifyInput( this.fileLoader, new THREE.FileLoader( this.manager ) );
+		this.mtlLoader = Validator.verifyInput( this.mtlLoader, new THREE.MTLLoader() );
+		if ( Validator.isValid( this.crossOrigin ) ) this.mtlLoader.setCrossOrigin( this.crossOrigin );
+
+		this.dataAvailable = false;
+		this.fileObj = null;
+		this.pathObj = null;
+		this.fileMtl = null;
+		this.texturePath = null;
+
+		this.objAsArrayBuffer = null;
+		this.mtlAsString = null;
+
+		this.materials = [];
+		var defaultMaterial = new THREE.MeshStandardMaterial( { color: 0xDCF1FF } );
+		defaultMaterial.name = 'defaultMaterial';
+		this.materials[ defaultMaterial.name ] = defaultMaterial;
+
+		this.counter = 0;
+	};
+
+	/**
+	 * Set all parameters for required for execution of "run".
+	 * @memberOf THREE.OBJLoader2.WWOBJLoader2
+	 *
+	 * @param {Object} params Either {@link THREE.OBJLoader2.WWOBJLoader2.PrepDataArrayBuffer} or {@link THREE.OBJLoader2.WWOBJLoader2.PrepDataFile}
+	 */
+	WWOBJLoader2.prototype.prepareRun = function ( params ) {
+		this._validate();
+		this.dataAvailable = params.dataAvailable;
+		this.modelName = params.modelName;
+		console.time( 'WWOBJLoader2' );
+		if ( this.dataAvailable ) {
+
+			// fast-fail on bad type
+			if ( ! ( params.objAsArrayBuffer instanceof Uint8Array ) ) {
+				throw 'Provided input is not of type arraybuffer! Aborting...';
+			}
+
+			this.worker.postMessage( {
+				cmd: 'init',
+				debug: this.debug
+			} );
+
+			this.objAsArrayBuffer = params.objAsArrayBuffer;
+			this.mtlAsString = params.mtlAsString;
+
+		} else {
+
+			// fast-fail on bad type
+			if ( ! ( typeof( params.fileObj ) === 'string' || params.fileObj instanceof String ) ) {
+				throw 'Provided file is not properly defined! Aborting...';
+			}
+
+			this.worker.postMessage( {
+				cmd: 'init',
+				debug: this.debug
+			} );
+
+			this.fileObj = params.fileObj;
+			this.pathObj = params.pathObj;
+			this.fileMtl = params.fileMtl;
+
+		}
+		this.setRequestTerminate( params.requestTerminate );
+		this.pathTexture = params.pathTexture;
+		this.sceneGraphBaseNode = params.sceneGraphBaseNode;
+		this.streamMeshes = params.streamMeshes;
+		if ( ! this.streamMeshes ) this.meshStore = [];
+	};
+
+	/**
+	 * Run the loader according the preparation instruction provided in "prepareRun".
+	 * @memberOf THREE.OBJLoader2.WWOBJLoader2
+	 */
+	WWOBJLoader2.prototype.run = function () {
+		var scope = this;
+		var processLoadedMaterials = function ( materialCreator ) {
+			var materialCreatorMaterials = [];
+			var materialNames = [];
+			if ( Validator.isValid( materialCreator ) ) {
+
+				materialCreator.preload();
+				materialCreatorMaterials = materialCreator.materials;
+				for ( var materialName in materialCreatorMaterials ) {
+
+					if ( materialCreatorMaterials.hasOwnProperty( materialName ) ) {
+
+						materialNames.push( materialName );
+						scope.materials[ materialName ] = materialCreatorMaterials[ materialName ];
+
+					}
+
+				}
+
+			}
+			scope.worker.postMessage( {
+				cmd: 'setMaterials',
+				materialNames: materialNames
+			} );
+
+			var materialsFromCallback;
+			var callbackMaterialsLoaded;
+			for ( var index in scope.callbacks.materialsLoaded ) {
+
+				callbackMaterialsLoaded = scope.callbacks.materialsLoaded[ index ];
+				materialsFromCallback = callbackMaterialsLoaded( scope.materials );
+				if ( Validator.isValid( materialsFromCallback ) ) scope.materials = materialsFromCallback;
+
+			}
+			if ( scope.dataAvailable && scope.objAsArrayBuffer ) {
+
+				scope.worker.postMessage({
+					cmd: 'run',
+					objAsArrayBuffer: scope.objAsArrayBuffer
+				}, [ scope.objAsArrayBuffer.buffer ] );
+
+			} else {
+
+				var refPercentComplete = 0;
+				var percentComplete = 0;
+				var output;
+				var onLoad = function ( objAsArrayBuffer ) {
+
+					scope._announceProgress( 'Running web worker!' );
+					scope.objAsArrayBuffer = new Uint8Array( objAsArrayBuffer );
+					scope.worker.postMessage( {
+						cmd: 'run',
+						objAsArrayBuffer: scope.objAsArrayBuffer
+					}, [ scope.objAsArrayBuffer.buffer ] );
+
+				};
+
+				var onProgress = function ( event ) {
+					if ( ! event.lengthComputable ) return;
+
+					percentComplete = Math.round( event.loaded / event.total * 100 );
+					if ( percentComplete > refPercentComplete ) {
+
+						refPercentComplete = percentComplete;
+						output = 'Download of "' + scope.fileObj + '": ' + percentComplete + '%';
+						console.log( output );
+						scope._announceProgress( output );
+
+					}
+				};
+
+				var onError = function ( event ) {
+					output = 'Error occurred while downloading "' + scope.fileObj + '"';
+					console.error( output + ': ' + event );
+					scope._announceProgress( output );
+					scope._finalize( 'error' );
+
+				};
+
+				scope.fileLoader.setPath( scope.pathObj );
+				scope.fileLoader.setResponseType( 'arraybuffer' );
+				scope.fileLoader.load( scope.fileObj, onLoad, onProgress, onError );
+			}
+			console.timeEnd( 'Loading MTL textures' );
+		};
+
+
+		this.mtlLoader.setPath( this.pathTexture );
+		if ( this.dataAvailable ) {
+
+			processLoadedMaterials( Validator.isValid( this.mtlAsString ) ? this.mtlLoader.parse( this.mtlAsString ) : null );
+
+		} else {
+
+			if ( Validator.isValid( this.fileMtl ) ) {
+
+				var onError = function ( event ) {
+					output = 'Error occurred while downloading "' + scope.fileMtl + '"';
+					console.error( output + ': ' + event );
+					scope._announceProgress( output );
+					scope._finalize( 'error' );
+				};
+
+				this.mtlLoader.load( this.fileMtl, processLoadedMaterials, undefined, onError );
+
+			} else {
+
+				processLoadedMaterials();
+
+			}
+
+		}
+	};
+
+	WWOBJLoader2.prototype._receiveWorkerMessage = function ( event ) {
+		var payload = event.data;
+
+		switch ( payload.cmd ) {
+			case 'objData':
+
+				this.counter++;
+				var meshName = payload.meshName;
+
+				var bufferGeometry = new THREE.BufferGeometry();
+				bufferGeometry.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( payload.vertices ), 3 ) );
+				if ( Validator.isValid( payload.normals ) ) {
+
+					bufferGeometry.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( payload.normals ), 3 ) );
+
+				} else {
+
+					bufferGeometry.computeVertexNormals();
+
+				}
+				if ( Validator.isValid( payload.uvs ) ) {
+
+					bufferGeometry.addAttribute( 'uv', new THREE.BufferAttribute( new Float32Array( payload.uvs ), 2 ) );
+
+				}
+
+				var materialDescriptions = payload.materialDescriptions;
+				var materialDescription;
+				var material;
+				var materialName;
+				var createMultiMaterial = payload.multiMaterial;
+				var multiMaterials = [];
+
+				var key;
+				for ( key in materialDescriptions ) {
+
+					materialDescription = materialDescriptions[ key ];
+					material = this.materials[ materialDescription.name ];
+
+					if ( materialDescription.default ) {
+
+						material = this.materials[ 'defaultMaterial' ];
+
+					} else if ( materialDescription.clone ) {
+
+						materialName = material.name + '_flat';
+						var materialClone = this.materials[ materialName ];
+						if ( ! materialClone ) {
+
+							materialClone = material.clone();
+							materialClone.name = materialName;
+							materialClone.shading = THREE.FlatShading;
+							this.materials[ materialName ] = name;
+
+						}
+
+					} else if ( ! material ) {
+
+						material = this.materials[ 'defaultMaterial' ];
+
+					}
+					if ( createMultiMaterial ) multiMaterials.push( material );
+
+				}
+				if ( createMultiMaterial ) {
+
+					material = multiMaterials;
+					var materialGroups = payload.materialGroups;
+					var materialGroup;
+					for ( key in materialGroups ) {
+
+						materialGroup = materialGroups[ key ];
+						bufferGeometry.addGroup( materialGroup.start, materialGroup.count, materialGroup.index );
+
+					}
+
+				}
+
+				var callbackMeshLoaded;
+				var callbackMeshLoadedResult;
+				var disregardMesh = false;
+				for ( var index in this.callbacks.meshLoaded ) {
+
+					callbackMeshLoaded = this.callbacks.meshLoaded[ index ];
+					callbackMeshLoadedResult = callbackMeshLoaded( meshName, bufferGeometry, material );
+
+					if ( Validator.isValid( callbackMeshLoadedResult ) ) {
+
+						if ( callbackMeshLoadedResult.disregardMesh ) {
+
+							// if one callback disregards the mesh, then processing stops
+							disregardMesh = true;
+							break;
+
+						}
+						if ( callbackMeshLoadedResult.replaceBufferGeometry ) bufferGeometry = callbackMeshLoadedResult.bufferGeometry;
+						if ( callbackMeshLoadedResult.replaceMaterial ) material = callbackMeshLoadedResult.material;
+
+					}
+
+				}
+
+				if ( !disregardMesh ) {
+
+					var mesh = new THREE.Mesh( bufferGeometry, material );
+					mesh.name = meshName;
+
+					if ( this.streamMeshes ) {
+
+						this.sceneGraphBaseNode.add( mesh );
+
+					} else {
+
+						this.meshStore.push( mesh );
+
+					}
+					this._announceProgress( 'Adding mesh (' + this.counter + '):', meshName );
+
+				} else {
+
+					this._announceProgress( 'Removing mesh:', meshName );
+
+				}
+				break;
+
+			case 'complete':
+
+				if ( ! this.streamMeshes ) {
+
+					for ( var meshStoreKey in this.meshStore ) {
+
+						if ( this.meshStore.hasOwnProperty( meshStoreKey ) ) this.sceneGraphBaseNode.add( this.meshStore[ meshStoreKey ] );
+
+					}
+
+				}
+
+				console.timeEnd( 'WWOBJLoader2' );
+				if ( Validator.isValid( payload.msg ) ) {
+
+					this._announceProgress( payload.msg );
+
+				} else {
+
+					this._announceProgress( '' );
+
+				}
+
+				this._finalize( 'complete' );
+				break;
+
+			case 'report_progress':
+				this._announceProgress( '', payload.output );
+				break;
+
+			default:
+				console.error( 'Received unknown command: ' + payload.cmd );
+				break;
+
+		}
+	};
+
+	WWOBJLoader2.prototype._terminate = function () {
+		if ( Validator.isValid( this.worker ) ) {
+
+			if ( this.running ) throw 'Unable to gracefully terminate worker as it is currently running!';
+
+			this.worker.terminate();
+			this.worker = null;
+			this.workerCode = null;
+			this._finalize( 'terminate' );
+
+		}
+		this.fileLoader = null;
+		this.mtlLoader = null;
+	};
+
+	WWOBJLoader2.prototype._finalize = function ( reason, requestTerminate ) {
+		this.running = false;
+		var index;
+		var callback;
+
+		if ( reason === 'complete' ) {
+
+			for ( index in this.callbacks.completedLoading ) {
+
+				callback = this.callbacks.completedLoading[ index ];
+				callback( this.modelName, this.instanceNo, this.requestTerminate );
+
+			}
+
+		} else if ( reason === 'error' ) {
+
+			for ( index in this.callbacks.errorWhileLoading ) {
+
+				callback = this.callbacks.errorWhileLoading[ index ];
+				callback( this.modelName, this.instanceNo, this.requestTerminate );
+
+			}
+
+		}
+		this.validated = false;
+
+		this.setRequestTerminate( requestTerminate );
+
+		if ( this.requestTerminate ) {
+			this._terminate();
+		}
+	};
+
+	WWOBJLoader2.prototype._announceProgress = function ( baseText, text ) {
+		var output = Validator.isValid( baseText ) ? baseText: "";
+		output = Validator.isValid( text ) ? output + " " + text : output;
+
+		var callbackProgress;
+		for ( var index in this.callbacks.progress ) {
+
+			callbackProgress = this.callbacks.progress[ index ];
+			callbackProgress( output );
+
+		}
+
+		if ( this.debug ) console.log( output );
+	};
+
+	WWOBJLoader2.prototype._buildWebWorkerCode = function ( existingWorkerCode ) {
+		if ( Validator.isValid( existingWorkerCode ) ) this.workerCode = existingWorkerCode;
+		if ( ! Validator.isValid( this.workerCode ) ) {
+
+			console.time( 'buildWebWorkerCode' );
+			var wwDef = (function () {
+
+				function WWOBJLoader() {
+					this.wwMeshCreator = new WWMeshCreator();
+					this.parser = new Parser( this.wwMeshCreator );
+					this.validated = false;
+					this.cmdState = 'created';
+
+					this.debug = false;
+				}
+
+				/**
+				 * Allows to set debug mode for the parser and the meshCreatorDebug
+				 *
+				 * @param parserDebug
+				 * @param meshCreatorDebug
+				 */
+				WWOBJLoader.prototype.setDebug = function ( parserDebug, meshCreatorDebug ) {
+					this.parser.setDebug( parserDebug );
+					this.wwMeshCreator.setDebug( meshCreatorDebug );
+				};
+
+				/**
+				 * Validate status, then parse arrayBuffer, finalize and return objGroup
+				 *
+				 * @param arrayBuffer
+				 */
+				WWOBJLoader.prototype.parse = function ( arrayBuffer ) {
+					console.log( 'Parsing arrayBuffer...' );
+					console.time( 'parseArrayBuffer' );
+
+					this.validate();
+					this.parser.parseArrayBuffer( arrayBuffer );
+					var objGroup = this._finalize();
+
+					console.timeEnd( 'parseArrayBuffer' );
+
+					return objGroup;
+				};
+
+				WWOBJLoader.prototype.validate = function () {
+					if ( this.validated ) return;
+
+					this.parser.validate();
+					this.wwMeshCreator.validate();
+
+					this.validated = true;
+				};
+
+				WWOBJLoader.prototype._finalize = function () {
+					console.log( 'Global output object count: ' + this.wwMeshCreator.globalObjectCount );
+					this.parser.finalize();
+					this.wwMeshCreator.finalize();
+					this.validated = false;
+				};
+
+				WWOBJLoader.prototype.init = function ( payload ) {
+					this.cmdState = 'init';
+					this.setDebug( payload.debug, payload.debug );
+				};
+
+				WWOBJLoader.prototype.setMaterials = function ( payload ) {
+					this.cmdState = 'setMaterials';
+					this.wwMeshCreator.setMaterials( payload.materialNames );
+				};
+
+				WWOBJLoader.prototype.run = function ( payload ) {
+					this.cmdState = 'run';
+
+					this.parse( payload.objAsArrayBuffer );
+					console.log( 'OBJ loading complete!' );
+
+					this.cmdState = 'complete';
+					self.postMessage( {
+						cmd: this.cmdState,
+						msg: null
+					} );
+				};
+
+				return WWOBJLoader;
+			})();
+
+			var wwMeshCreatorDef = (function () {
+
+				function WWMeshCreator() {
+					this.materials = null;
+					this.debug = false;
+					this.globalObjectCount = 1;
+					this.validated = false;
+				}
+
+				WWMeshCreator.prototype.setMaterials = function ( materials ) {
+					this.materials = Validator.verifyInput( materials, this.materials );
+					this.materials = Validator.verifyInput( this.materials, { materials: [] } );
+				};
+
+				WWMeshCreator.prototype.setDebug = function ( debug ) {
+					if ( debug === true || debug === false ) this.debug = debug;
+				};
+
+				WWMeshCreator.prototype.validate = function () {
+					if ( this.validated ) return;
+
+					this.setMaterials( null );
+					this.setDebug( null );
+					this.globalObjectCount = 1;
+				};
+
+				WWMeshCreator.prototype.finalize = function () {
+					this.materials = null;
+					this.validated = false;
+				};
+
+				/**
+				 * RawObjectDescriptions are transformed to THREE.Mesh.
+				 * It is ensured that rawObjectDescriptions only contain objects with vertices (no need to check).
+				 *
+				 * @param rawObjectDescriptions
+				 * @param inputObjectCount
+				 * @param absoluteVertexCount
+				 * @param absoluteNormalCount
+				 * @param absoluteUvCount
+				 */
+				WWMeshCreator.prototype.buildMesh = function ( rawObjectDescriptions, inputObjectCount, absoluteVertexCount, absoluteNormalCount, absoluteUvCount ) {
+					if ( this.debug ) console.log( 'OBJLoader.buildMesh:\nInput object no.: ' + inputObjectCount );
+
+					var vertexFa = new Float32Array( absoluteVertexCount );
+					var normalFA = ( absoluteNormalCount > 0 ) ? new Float32Array( absoluteNormalCount ) : null;
+					var uvFA = ( absoluteUvCount > 0 ) ? new Float32Array( absoluteUvCount ) : null;
+
+					var rawObjectDescription;
+					var materialDescription;
+					var materialDescriptions = [];
+
+					var createMultiMaterial = ( rawObjectDescriptions.length > 1 );
+					var materialIndex = 0;
+					var materialIndexMapping = [];
+					var selectedMaterialIndex;
+					var materialGroup;
+					var materialGroups = [];
+
+					var vertexBAOffset = 0;
+					var vertexGroupOffset = 0;
+					var vertexLength;
+					var normalOffset = 0;
+					var uvOffset = 0;
+
+					for ( var oodIndex in rawObjectDescriptions ) {
+						if ( ! rawObjectDescriptions.hasOwnProperty( oodIndex ) ) continue;
+						rawObjectDescription = rawObjectDescriptions[ oodIndex ];
+
+						materialDescription = { name: rawObjectDescription.materialName, flat: false, default: false };
+						if ( this.materials[ materialDescription.name ] === null ) {
+
+							materialDescription.default = true;
+							console.warn( 'object_group "' + rawObjectDescription.objectName + '_' + rawObjectDescription.groupName + '" was defined without material! Assigning "defaultMaterial".' );
+
+						}
+						// Attach '_flat' to materialName in case flat shading is needed due to smoothingGroup 0
+						if ( rawObjectDescription.smoothingGroup === 0 ) materialDescription.flat = true;
+
+						vertexLength = rawObjectDescription.vertices.length;
+						if ( createMultiMaterial ) {
+
+							// re-use material if already used before. Reduces materials array size and eliminates duplicates
+
+							selectedMaterialIndex = materialIndexMapping[ materialDescription.name ];
+							if ( ! selectedMaterialIndex ) {
+
+								selectedMaterialIndex = materialIndex;
+								materialIndexMapping[ materialDescription.name ] = materialIndex;
+								materialDescriptions.push( materialDescription );
+								materialIndex++;
+
+							}
+							materialGroup = {
+								start: vertexGroupOffset,
+								count: vertexLength / 3,
+								index: selectedMaterialIndex
+							};
+							materialGroups.push( materialGroup );
+							vertexGroupOffset += vertexLength / 3;
+
+						} else {
+
+							materialDescriptions.push( materialDescription );
+
+						}
+
+						vertexFa.set( rawObjectDescription.vertices, vertexBAOffset );
+						vertexBAOffset += vertexLength;
+
+						if ( normalFA ) {
+
+							normalFA.set( rawObjectDescription.normals, normalOffset );
+							normalOffset += rawObjectDescription.normals.length;
+
+						}
+						if ( uvFA ) {
+
+							uvFA.set( rawObjectDescription.uvs, uvOffset );
+							uvOffset += rawObjectDescription.uvs.length;
+
+						}
+						if ( this.debug ) this.printReport( rawObjectDescription, selectedMaterialIndex );
+
+					}
+
+					self.postMessage( {
+						cmd: 'objData',
+						meshName: rawObjectDescription.objectName,
+						multiMaterial: createMultiMaterial,
+						materialDescriptions: materialDescriptions,
+						materialGroups: materialGroups,
+						vertices: vertexFa,
+						normals: normalFA,
+						uvs: uvFA
+					}, [ vertexFa.buffer ], normalFA !== null ? [ normalFA.buffer ] : null, uvFA !== null ? [ uvFA.buffer ] : null );
+
+					this.globalObjectCount++;
+				};
+
+				return WWMeshCreator;
+			})();
+
+			var wwObjLoaderRunnerDef = (function () {
+
+				function WWOBJLoaderRunner() {
+					self.addEventListener( 'message', this.runner, false );
+				}
+
+				WWOBJLoaderRunner.prototype.runner = function ( event ) {
+					var payload = event.data;
+
+					console.log( 'Command state before: ' + WWOBJLoaderRef.cmdState );
+
+					switch ( payload.cmd ) {
+						case 'init':
+
+							WWOBJLoaderRef.init( payload );
+							break;
+
+						case 'setMaterials':
+
+							WWOBJLoaderRef.setMaterials( payload );
+							break;
+
+						case 'run':
+
+							WWOBJLoaderRef.run( payload );
+							break;
+
+						default:
+
+							console.error( 'OBJLoader: Received unknown command: ' + payload.cmd );
+							break;
+
+					}
+
+					console.log( 'Command state after: ' + WWOBJLoaderRef.cmdState );
+				};
+
+				return WWOBJLoaderRunner;
+			})();
+
+			var buildObject = function ( fullName, object ) {
+				var objectString = fullName + ' = {\n';
+				var part;
+				for ( var name in object ) {
+
+					part = object[ name ];
+					if ( typeof( part ) === 'string' || part instanceof String ) {
+
+						part = part.replace( '\n', '\\n' );
+						part = part.replace( '\r', '\\r' );
+						objectString += '\t' + name + ': "' + part + '",\n';
+
+					} else if ( part instanceof Array ) {
+
+						objectString += '\t' + name + ': [' + part + '],\n';
+
+					} else if ( Number.isInteger( part ) ) {
+
+						objectString += '\t' + name + ': ' + part + ',\n';
+
+					} else if ( typeof part === 'function' ) {
+
+						objectString += '\t' + name + ': ' + part + ',\n';
+
+					}
+
+				}
+				objectString += '}\n\n';
+
+				return objectString;
+			};
+
+			var buildSingelton = function ( fullName, internalName, object ) {
+				var objectString = fullName + ' = (function () {\n\n';
+				objectString += '\t' + object.prototype.constructor.toString() + '\n\n';
+
+				var funcString;
+				var objectPart;
+				for ( var name in object.prototype ) {
+
+					objectPart = object.prototype[ name ];
+					if ( typeof objectPart === 'function' ) {
+
+						funcString = objectPart.toString();
+						objectString += '\t' + internalName + '.prototype.' + name + ' = ' + funcString + ';\n\n';
+
+					}
+
+				}
+				objectString += '\treturn ' + internalName + ';\n';
+				objectString += '})();\n\n';
+
+				return objectString;
+			};
+
+			this.workerCode = '';
+			this.workerCode += '/**\n';
+			this.workerCode += '  * This code was constructed by WWOBJLoader2._buildWebWorkerCode\n';
+			this.workerCode += '  */\n\n';
+
+			// parser re-construction
+			this.workerCode += THREE.OBJLoader2.prototype._buildWebWorkerCode( buildObject, buildSingelton );
+
+			// web worker construction
+			this.workerCode += buildSingelton( 'WWOBJLoader', 'WWOBJLoader', wwDef );
+			this.workerCode += buildSingelton( 'WWMeshCreator', 'WWMeshCreator', wwMeshCreatorDef );
+			this.workerCode += 'WWOBJLoaderRef = new WWOBJLoader();\n\n';
+			this.workerCode += buildSingelton( 'WWOBJLoaderRunner', 'WWOBJLoaderRunner', wwObjLoaderRunnerDef );
+			this.workerCode += 'new WWOBJLoaderRunner();\n\n';
+
+			console.timeEnd( 'buildWebWorkerCode' );
+		}
+
+		return this.workerCode;
+	};
+
+	return WWOBJLoader2;
+
+})();
+
+/**
+ * Instruction to configure {@link THREE.OBJLoader2.WWOBJLoader2}.prepareRun to load OBJ from given ArrayBuffer and MTL from given String.
+ *
+ * @param {string} modelName Overall name of the model
+ * @param {Uint8Array} objAsArrayBuffer OBJ file content as ArrayBuffer
+ * @param {string} pathTexture Path to texture files
+ * @param {string} mtlAsString MTL file content as string
+ *
+ * @returns {{modelName: string, dataAvailable: boolean, objAsArrayBuffer: null, pathTexture: null, mtlAsString: null, sceneGraphBaseNode: null, streamMeshes: boolean, requestTerminate: boolean}}
+ * @constructor
+ */
+THREE.OBJLoader2.WWOBJLoader2.PrepDataArrayBuffer = function ( modelName, objAsArrayBuffer, pathTexture, mtlAsString ) {
+
+	var Validator = THREE.OBJLoader2.prototype._getValidator();
+
+	return {
+
+		/**
+		 * {@link THREE.Object3D} where meshes will be attached.
+		 * @memberOf THREE.OBJLoader2.WWOBJLoader2.PrepDataArrayBuffer
+		 *
+		 * @param {THREE.Object3D} sceneGraphBaseNode Scene graph object
+		 */
+		setSceneGraphBaseNode: function ( sceneGraphBaseNode ) {
+			this.sceneGraphBaseNode = Validator.verifyInput( sceneGraphBaseNode, null );
+		},
+
+		/**
+		 * Singles meshes are directly integrated into scene when loaded or later.
+		 * @memberOf THREE.OBJLoader2.WWOBJLoader2.PrepDataArrayBuffer
+		 *
+		 * @param {boolean} streamMeshes=true Default is true
+		 */
+		setStreamMeshes: function ( streamMeshes ) {
+			this.streamMeshes = streamMeshes !== false;
+		},
+
+		/**
+		 * Request termination of web worker and free local resources after execution.
+		 * @memberOf THREE.OBJLoader2.WWOBJLoader2.PrepDataArrayBuffer
+		 *
+		 * @param {boolean} requestTerminate=false Default is false
+		 */
+		setRequestTerminate: function ( requestTerminate ) {
+			this.requestTerminate = requestTerminate === true;
+		},
+
+		/**
+		 * Returns all callbacks as {@link THREE.OBJLoader2.WWOBJLoader2.PrepDataCallbacks}
+		 * @memberOf THREE.OBJLoader2.WWOBJLoader2.PrepDataArrayBuffer
+		 *
+		 * @returns {THREE.OBJLoader2.WWOBJLoader2.PrepDataCallbacks}
+		 */
+		getCallbacks: function () {
+			return this.callbacks;
+		},
+		modelName: Validator.verifyInput( modelName, 'none' ),
+		dataAvailable: true,
+		objAsArrayBuffer: Validator.verifyInput( objAsArrayBuffer, null ),
+		pathTexture: Validator.verifyInput( pathTexture, null ),
+		mtlAsString: Validator.verifyInput( mtlAsString, null ),
+		sceneGraphBaseNode: null,
+		streamMeshes: true,
+		requestTerminate: false,
+		callbacks: new THREE.OBJLoader2.WWOBJLoader2.PrepDataCallbacks()
+	};
+};
+
+/**
+ * Instruction to configure {@link THREE.OBJLoader2.WWOBJLoader2}.prepareRun to load OBJ and MTL from files.
+ *
+ * @param {string} modelName Overall name of the model
+ * @param {string} pathObj Path to OBJ file
+ * @param {string} fileObj OBJ file name
+ * @param {string} pathTexture Path to texture files
+ * @param {string} fileMtl MTL file name
+ *
+ * @returns {{modelName: string, dataAvailable: boolean, pathObj: null, fileObj: null, pathTexture: null, fileMtl: null, sceneGraphBaseNode: null, streamMeshes: boolean,  requestTerminate: boolean}}
+ * @constructor
+ */
+THREE.OBJLoader2.WWOBJLoader2.PrepDataFile = function ( modelName, pathObj, fileObj, pathTexture, fileMtl ) {
+
+	var Validator = THREE.OBJLoader2.prototype._getValidator();
+
+	return {
+
+		/**
+		 * {@link THREE.Object3D} where meshes will be attached.
+		 * @memberOf THREE.OBJLoader2.WWOBJLoader2.PrepDataFile
+		 *
+		 * @param {THREE.Object3D} sceneGraphBaseNode Scene graph object
+		 */
+		setSceneGraphBaseNode: function ( sceneGraphBaseNode ) {
+			this.sceneGraphBaseNode = Validator.verifyInput( sceneGraphBaseNode, null );
+		},
+
+		/**
+		 * Singles meshes are directly integrated into scene when loaded or later.
+		 * @memberOf THREE.OBJLoader2.WWOBJLoader2.PrepDataFile
+		 *
+		 * @param {boolean} streamMeshes=true Default is true
+		 */
+		setStreamMeshes: function ( streamMeshes ) {
+			this.streamMeshes = streamMeshes !== false;
+		},
+
+		/**
+		 * Request termination of web worker and free local resources after execution.
+		 * @memberOf THREE.OBJLoader2.WWOBJLoader2.PrepDataFile
+		 *
+		 * @param {boolean} requestTerminate=false Default is false
+		 */
+		setRequestTerminate: function ( requestTerminate ) {
+			this.requestTerminate = requestTerminate === true;
+		},
+
+		/**
+		 * Returns all callbacks as {@link THREE.OBJLoader2.WWOBJLoader2.PrepDataCallbacks}
+		 * @memberOf THREE.OBJLoader2.WWOBJLoader2.PrepDataFile
+		 *
+		 * @returns {THREE.OBJLoader2.WWOBJLoader2.PrepDataCallbacks}
+		 */
+		getCallbacks: function () {
+			return this.callbacks;
+		},
+		modelName: Validator.verifyInput( modelName, 'none' ),
+		dataAvailable: false,
+		pathObj: Validator.verifyInput( pathObj, null ),
+		fileObj: Validator.verifyInput( fileObj, null ),
+		pathTexture: Validator.verifyInput( pathTexture, null ),
+		fileMtl: Validator.verifyInput( fileMtl, null ),
+		sceneGraphBaseNode: null,
+		streamMeshes: true,
+		requestTerminate: false,
+		callbacks: new THREE.OBJLoader2.WWOBJLoader2.PrepDataCallbacks()
+	};
+};
+
+/**
+ * Callbacks utilized by functions working with {@link THREE.OBJLoader2.WWOBJLoader2.PrepDataArrayBuffer} or {@link THREE.OBJLoader2.WWOBJLoader2.PrepDataFile}
+ *
+ * @returns {{registerCallbackProgress: THREE.OBJLoader2.WWOBJLoader2.PrepDataCallbacks.registerCallbackProgress, registerCallbackCompletedLoading: THREE.OBJLoader2.WWOBJLoader2.PrepDataCallbacks.registerCallbackCompletedLoading, registerCallbackMaterialsLoaded: THREE.OBJLoader2.WWOBJLoader2.PrepDataCallbacks.registerCallbackMaterialsLoaded, registerCallbackMeshLoaded: THREE.OBJLoader2.WWOBJLoader2.PrepDataCallbacks.registerCallbackMeshLoaded, registerCallbackErrorWhileLoading: THREE.OBJLoader2.WWOBJLoader2.PrepDataCallbacks.registerCallbackErrorWhileLoading, progress: null, completedLoading: null, errorWhileLoading: null, materialsLoaded: null, meshLoaded: null}}
+ * @constructor
+ */
+THREE.OBJLoader2.WWOBJLoader2.PrepDataCallbacks = function () {
+
+	var Validator = THREE.OBJLoader2.prototype._getValidator();
+
+	return {
+		/**
+		 * Register callback function that is invoked by internal function "_announceProgress" to print feedback.
+		 * @memberOf THREE.OBJLoader2.WWOBJLoader2.PrepDataCallbacks
+		 *
+		 * @param {callback} callbackProgress Callback function for described functionality
+		 */
+		registerCallbackProgress: function ( callbackProgress ) {
+			if ( Validator.isValid( callbackProgress ) ) this.progress = callbackProgress;
+		},
+
+		/**
+		 * Register callback function that is called once loading of the complete model is completed.
+		 * @memberOf THREE.OBJLoader2.WWOBJLoader2.PrepDataCallbacks
+		 *
+		 * @param {callback} callbackCompletedLoading Callback function for described functionality
+		 */
+		registerCallbackCompletedLoading: function ( callbackCompletedLoading ) {
+			if ( Validator.isValid( callbackCompletedLoading ) ) this.completedLoading = callbackCompletedLoading;
+		},
+
+		/**
+		 * Register callback function that is called once materials have been loaded. It allows to alter and return materials.
+		 * @memberOf THREE.OBJLoader2.WWOBJLoader2.PrepDataCallbacks
+		 *
+		 * @param {callback} callbackMaterialsLoaded Callback function for described functionality
+		 */
+		registerCallbackMaterialsLoaded: function ( callbackMaterialsLoaded ) {
+			if ( Validator.isValid( callbackMaterialsLoaded ) ) this.materialsLoaded = callbackMaterialsLoaded;
+		},
+
+		/**
+		 * Register callback function that is called every time a mesh was loaded.
+		 * Use {@link THREE.OBJLoader2.WWOBJLoader2.LoadedMeshUserOverride} for alteration instructions (geometry, material or disregard mesh).
+		 * @memberOf THREE.OBJLoader2.WWOBJLoader2.PrepDataCallbacks
+		 *
+		 * @param {callback} callbackMeshLoaded Callback function for described functionality
+		 */
+		registerCallbackMeshLoaded: function ( callbackMeshLoaded ) {
+			if ( Validator.isValid( callbackMeshLoaded ) ) this.meshLoaded = callbackMeshLoaded;
+		},
+
+		/**
+		 * Report if an error prevented loading.
+		 * @memberOf THREE.OBJLoader2.WWOBJLoader2.PrepDataCallbacks
+		 *
+		 * @param {callback} callbackErrorWhileLoading Callback function for described functionality
+		 */
+		registerCallbackErrorWhileLoading: function ( callbackErrorWhileLoading ) {
+			if ( Validator.isValid( callbackErrorWhileLoading ) ) this.errorWhileLoading = callbackErrorWhileLoading;
+		},
+
+		progress: null,
+		completedLoading: null,
+		errorWhileLoading: null,
+		materialsLoaded: null,
+		meshLoaded: null
+	};
+};
+
+
+/**
+ * Object to return by {@link THREE.OBJLoader2.WWOBJLoader2}.callbacks.meshLoaded. Used to adjust bufferGeometry or material or prevent complete loading of mesh
+ *
+ * @param {boolean} disregardMesh=false Tell WWOBJLoader2 to completely disregard this mesh
+ * @param {THREE.BufferGeometry} bufferGeometry The {@link THREE.BufferGeometry} to be used
+ * @param {THREE.Material} material The {@link THREE.Material} to be used
+ *
+ * @returns {{ disregardMesh: boolean, replaceBufferGeometry: boolean, bufferGeometry: THREE.BufferGeometry, replaceMaterial: boolean, material: THREE.Material}}
+ * @constructor
+ */
+THREE.OBJLoader2.WWOBJLoader2.LoadedMeshUserOverride = function ( disregardMesh, bufferGeometry, material ) {
+
+	var Validator = THREE.OBJLoader2.prototype._getValidator();
+
+	return {
+		disregardMesh: disregardMesh === true,
+		replaceBufferGeometry: Validator.isValid( bufferGeometry ),
+		bufferGeometry: Validator.verifyInput( bufferGeometry, null ),
+		replaceMaterial: Validator.isValid( material ),
+		material: Validator.verifyInput( material, null )
+	};
+};
+
+/**
+ * Orchestrate loading of multiple OBJ files/data from an instruction queue with a configurable amount of workers (1-16).
+ * Workflow:
+ *   prepareWorkers
+ *   enqueueForRun
+ *   processQueue
+ *   deregister
+ *
+ * @class
+ */
+THREE.OBJLoader2.WWOBJLoader2Director = (function () {
+
+	var Validator = THREE.OBJLoader2.prototype._getValidator();
+
+	var MAX_WEB_WORKER = 16;
+	var MAX_QUEUE_SIZE = 1024;
+
+	function WWOBJLoader2Director() {
+		this.maxQueueSize = MAX_QUEUE_SIZE ;
+		this.maxWebWorkers = MAX_WEB_WORKER;
+		this.crossOrigin = null;
+
+		this.workerDescription = {
+			prototypeDef: THREE.OBJLoader2.WWOBJLoader2.prototype,
+			globalCallbacks: {},
+			webWorkers: [],
+			codeBuffer: null
+		};
+		this.objectsCompleted = 0;
+		this.instructionQueue = [];
+	}
+
+	/**
+	 * Returns the maximum length of the instruction queue.
+	 * @memberOf THREE.OBJLoader2.WWOBJLoader2Director
+	 *
+	 * @returns {number}
+	 */
+	WWOBJLoader2Director.prototype.getMaxQueueSize = function () {
+		return this.maxQueueSize;
+	};
+
+	/**
+	 * Returns the maximum number of workers.
+	 * @memberOf THREE.OBJLoader2.WWOBJLoader2Director
+	 *
+	 * @returns {number}
+	 */
+	WWOBJLoader2Director.prototype.getMaxWebWorkers = function () {
+		return this.maxWebWorkers;
+	};
+
+	/**
+	 * Sets the CORS string to be used.
+	 * @memberOf THREE.OBJLoader2.WWOBJLoader2Director
+	 *
+	 * @param {string} crossOrigin CORS value
+	 */
+	WWOBJLoader2Director.prototype.setCrossOrigin = function ( crossOrigin ) {
+		this.crossOrigin = crossOrigin;
+	};
+
+	/**
+	 * Create or destroy workers according limits. Set the name and register callbacks for dynamically created web workers.
+	 * @memberOf THREE.OBJLoader2.WWOBJLoader2Director
+	 *
+	 * @param {THREE.OBJLoader2.WWOBJLoader2.PrepDataCallbacks} globalCallbacks  Register global callbacks used by all web workers
+	 * @param {number} maxQueueSize Set the maximum size of the instruction queue (1-1024)
+	 * @param {number} maxWebWorkers Set the maximum amount of workers (1-16)
+	 */
+	WWOBJLoader2Director.prototype.prepareWorkers = function ( globalCallbacks, maxQueueSize, maxWebWorkers ) {
+		if ( Validator.isValid( globalCallbacks ) ) this.workerDescription.globalCallbacks = globalCallbacks;
+		this.maxQueueSize = Math.min( maxQueueSize, MAX_QUEUE_SIZE );
+		this.maxWebWorkers = Math.min( maxWebWorkers, MAX_WEB_WORKER );
+		this.objectsCompleted = 0;
+		this.instructionQueue = [];
+
+		var start = this.workerDescription.webWorkers.length;
+		if ( start < this.maxWebWorkers ) {
+
+			for ( i = start; i < this.maxWebWorkers; i ++ ) {
+
+				webWorker = this._buildWebWorker();
+				this.workerDescription.webWorkers[ i ] = webWorker;
+
+			}
+
+		} else {
+
+			for ( var webWorker, i = start - 1; i >= this.maxWebWorkers; i-- ) {
+
+				webWorker = this.workerDescription.webWorkers[ i ];
+				webWorker.setRequestTerminate( true );
+
+				this.workerDescription.webWorkers.pop();
+
+			}
+
+		}
+	};
+
+	/**
+	 * Store run instructions in internal instructionQueue.
+	 * @memberOf THREE.OBJLoader2.WWOBJLoader2Director
+	 *
+	 * @param {Object} runParams Either {@link THREE.OBJLoader2.WWOBJLoader2.PrepDataArrayBuffer} or {@link THREE.OBJLoader2.WWOBJLoader2.PrepDataFile}
+	 */
+	WWOBJLoader2Director.prototype.enqueueForRun = function ( runParams ) {
+		if ( this.instructionQueue.length < this.maxQueueSize ) {
+			this.instructionQueue.push( runParams );
+		}
+	};
+
+	/**
+	 * Process the instructionQueue until it is depleted.
+	 * @memberOf THREE.OBJLoader2.WWOBJLoader2Director
+	 */
+	WWOBJLoader2Director.prototype.processQueue = function () {
+		if ( this.instructionQueue.length === 0 ) return;
+
+		var length = Math.min( this.maxWebWorkers, this.instructionQueue.length );
+		for ( var i = 0; i < length; i++ ) {
+
+			this._kickWebWorkerRun( this.workerDescription.webWorkers[ i ], this.instructionQueue[ 0 ] );
+			this.instructionQueue.shift();
+
+		}
+	};
+
+	WWOBJLoader2Director.prototype._kickWebWorkerRun = function( worker, runParams ) {
+		worker.clearAllCallbacks();
+		var key;
+		var globalCallbacks = this.workerDescription.globalCallbacks;
+		var workerCallbacks = worker.callbacks;
+		var selectedGlobalCallback;
+		for ( key in globalCallbacks ) {
+
+			if ( workerCallbacks.hasOwnProperty( key ) && globalCallbacks.hasOwnProperty( key ) ) {
+
+				selectedGlobalCallback = globalCallbacks[ key ];
+				if ( Validator.isValid( selectedGlobalCallback ) ) workerCallbacks[ key ].push( selectedGlobalCallback );
+
+			}
+
+		}
+		// register per object callbacks
+		var runCallbacks = runParams.callbacks;
+		if ( Validator.isValid( runCallbacks ) ) {
+
+			for ( key in runCallbacks ) {
+
+				if ( workerCallbacks.hasOwnProperty( key ) && runCallbacks.hasOwnProperty( key ) && Validator.isValid( runCallbacks[ key ] ) ) {
+
+					workerCallbacks[ key ].push( runCallbacks[ key ] );
+
+				}
+
+			}
+
+		}
+
+		var scope = this;
+		var directorCompletedLoading = function ( modelName, instanceNo, requestTerminate ) {
+			scope.objectsCompleted++;
+			if ( ! requestTerminate ) {
+
+				var worker = scope.workerDescription.webWorkers[ instanceNo ];
+				var runParams = scope.instructionQueue[ 0 ];
+				if ( Validator.isValid( runParams ) ) {
+
+					console.log( '\nAssigning next item from queue to worker (queue length: ' + scope.instructionQueue.length + ')\n\n' );
+					scope._kickWebWorkerRun( worker, runParams );
+					scope.instructionQueue.shift();
+
+				}
+
+			}
+		};
+		worker.registerCallbackCompletedLoading( directorCompletedLoading );
+
+		worker.prepareRun( runParams );
+		worker.run();
+	};
+
+	WWOBJLoader2Director.prototype._buildWebWorker = function () {
+		var webWorker = Object.create( this.workerDescription.prototypeDef );
+		webWorker._init();
+		if ( Validator.isValid( this.crossOrigin ) ) webWorker.setCrossOrigin( this.crossOrigin );
+
+		// Ensure code string is built once and then it is just passed on to every new instance
+		if ( Validator.isValid( this.workerDescription.codeBuffer ) ) {
+
+			webWorker._buildWebWorkerCode( this.workerDescription.codeBuffer );
+
+		} else {
+
+			this.workerDescription.codeBuffer = webWorker._buildWebWorkerCode();
+
+		}
+
+		webWorker.instanceNo = this.workerDescription.webWorkers.length;
+		this.workerDescription.webWorkers.push( webWorker );
+		return webWorker;
+	};
+
+	/**
+	 * Terminate all workers.
+	 * @memberOf THREE.OBJLoader2.WWOBJLoader2Director
+	 */
+	WWOBJLoader2Director.prototype.deregister = function () {
+		console.log( 'WWOBJLoader2Director received the unregister call. Terminating all workers!' );
+		for ( var i = 0, webWorker, length = this.workerDescription.webWorkers.length; i < length; i++ ) {
+
+			webWorker = this.workerDescription.webWorkers[ i ];
+			webWorker.setRequestTerminate( true );
+
+		}
+		this.workerDescription.globalCallbacks = {};
+		this.workerDescription.webWorkers = [];
+		this.workerDescription.codeBuffer = null;
+	};
+
+	return WWOBJLoader2Director;
+
+})();

+ 1580 - 1045
examples/js/loaders/XLoader.js

@@ -20,1080 +20,1615 @@
  *  - morph
  *  - scene
  */
-
 var XfileLoadMode$1 = XfileLoadMode = {
-    none: -1,
-    Element: 1,
-    FrameTransformMatrix_Read: 3,
-    Mesh: 5,
-    Vartex_init: 10,
-    Vartex_Read: 11,
-    Index_init: 20,
-    index_Read: 21,
-    Uv_init: 30,
-    Uv_Read: 31,
-    Normal_V_init: 40,
-    Normal_V_Read: 41,
-    Normal_I_init: 42,
-    Normal_I_Read: 43,
-    Mat_Face_init: 101,
-    Mat_Face_len_Read: 102,
-    Mat_Face_Set: 103,
-    Mat_Set: 111,
-    Mat_Set_Texture: 121,
-    Mat_Set_LightTex: 122,
-    Mat_Set_EmissiveTex: 123,
-    Mat_Set_BumpTex: 124,
-    Mat_Set_NormalTex: 125,
-    Mat_Set_EnvTex: 126,
-    Weit_init: 201,
-    Weit_IndexLength: 202,
-    Weit_Read_Index: 203,
-    Weit_Read_Value: 204,
-    Weit_Read_Matrx: 205,
-    Anim_init: 1001,
-    Anim_Reading: 1002,
-    Anim_KeyValueTypeRead: 1003,
-    Anim_KeyValueLength: 1004,
-    Anime_ReadKeyFrame: 1005
+	none: - 1,
+	Element: 1,
+	FrameTransformMatrix_Read: 3,
+	Mesh: 5,
+	Vartex_init: 10,
+	Vartex_Read: 11,
+	Index_init: 20,
+	index_Read: 21,
+	Uv_init: 30,
+	Uv_Read: 31,
+	Normal_V_init: 40,
+	Normal_V_Read: 41,
+	Normal_I_init: 42,
+	Normal_I_Read: 43,
+	Mat_Face_init: 101,
+	Mat_Face_len_Read: 102,
+	Mat_Face_Set: 103,
+	Mat_Set: 111,
+	Mat_detail: 121,
+	Mat_Set_Texture: 121,
+	Mat_Set_LightTex: 122,
+	Mat_Set_EmissiveTex: 123,
+	Mat_Set_BumpTex: 124,
+	Mat_Set_NormalTex: 125,
+	Mat_Set_EnvTex: 126,
+	Weit_init: 201,
+	Weit_IndexLength: 202,
+	Weit_Read_Index: 203,
+	Weit_Read_Value: 204,
+	Weit_Read_Matrx: 205,
+	Anim_init: 1001,
+	Anim_Reading: 1002,
+	Anim_KeyValueTypeRead: 1003,
+	Anim_KeyValueLength: 1004,
+	Anime_ReadKeyFrame: 1005
 };
 
-var classCallCheck = function (instance, Constructor) {
-  if (!(instance instanceof Constructor)) {
-    throw new TypeError("Cannot call a class as a function");
-  }
+var classCallCheck = function ( instance, Constructor ) {
+
+	if ( ! ( instance instanceof Constructor ) ) {
+
+		throw new TypeError( "Cannot call a class as a function" );
+
+	}
+
 };
 
 var createClass = function () {
-  function defineProperties(target, props) {
-    for (var i = 0; i < props.length; i++) {
-      var descriptor = props[i];
-      descriptor.enumerable = descriptor.enumerable || false;
-      descriptor.configurable = true;
-      if ("value" in descriptor) descriptor.writable = true;
-      Object.defineProperty(target, descriptor.key, descriptor);
-    }
-  }
-
-  return function (Constructor, protoProps, staticProps) {
-    if (protoProps) defineProperties(Constructor.prototype, protoProps);
-    if (staticProps) defineProperties(Constructor, staticProps);
-    return Constructor;
-  };
+
+	function defineProperties( target, props ) {
+
+		for ( var i = 0; i < props.length; i ++ ) {
+
+			var descriptor = props[ i ];
+			descriptor.enumerable = descriptor.enumerable || false;
+			descriptor.configurable = true;
+			if ( "value" in descriptor ) descriptor.writable = true;
+			Object.defineProperty( target, descriptor.key, descriptor );
+
+		}
+
+	}
+
+	return function ( Constructor, protoProps, staticProps ) {
+
+		if ( protoProps ) defineProperties( Constructor.prototype, protoProps );
+		if ( staticProps ) defineProperties( Constructor, staticProps );
+		return Constructor;
+
+	};
+
 }();
 
 var XAnimationObj = function () {
-    function XAnimationObj() {
-        classCallCheck(this, XAnimationObj);
-
-        this.fps = 30;
-        this.name = 'xanimation';
-        this.length = 0;
-        this.hierarchy = [];
-    }
-
-    createClass(XAnimationObj, [{
-        key: 'make',
-        value: function make(XAnimationInfoArray, mesh) {
-            var keys = Object.keys(XAnimationInfoArray);
-            var hierarchy_tmp = [];
-            for (var i = 0; i < keys.length; i++) {
-                var bone = null;
-                var parent = -1;
-                var baseIndex = -1;
-                for (var m = 0; m < mesh.skeleton.bones.length; m++) {
-                    if (mesh.skeleton.bones[m].name == XAnimationInfoArray[keys[i]].boneName) {
-                        bone = XAnimationInfoArray[keys[i]].boneName;
-                        parent = mesh.skeleton.bones[m].parent.name;
-                        baseIndex = m;
-                        break;
-                    }
-                }
-                hierarchy_tmp[baseIndex] = this.makeBonekeys(XAnimationInfoArray[keys[i]], bone, parent);
-            }
-            var keys2 = Object.keys(hierarchy_tmp);
-            for (var _i = 0; _i < keys2.length; _i++) {
-                this.hierarchy.push(hierarchy_tmp[_i]);
-                var parentId = -1;
-                for (var _m = 0; _m < this.hierarchy.length; _m++) {
-                    if (_i != _m && this.hierarchy[_i].parent === this.hierarchy[_m].name) {
-                        parentId = _m;
-                        break;
-                    }
-                }
-                this.hierarchy[_i].parent = parentId;
-            }
-        }
-    }, {
-        key: 'makeBonekeys',
-        value: function makeBonekeys(XAnimationInfo, bone, parent) {
-            var refObj = {};
-            refObj.name = bone;
-            refObj.parent = parent;
-            refObj.keys = [];
-            for (var i = 0; i < XAnimationInfo.keyFrames.length; i++) {
-                var keyframe = {};
-                keyframe.time = XAnimationInfo.keyFrames[i].time * this.fps;
-                keyframe.matrix = XAnimationInfo.keyFrames[i].matrix;
-                keyframe.pos = new THREE.Vector3().setFromMatrixPosition(keyframe.matrix);
-                keyframe.rot = new THREE.Quaternion().setFromRotationMatrix(keyframe.matrix);
-                keyframe.scl = new THREE.Vector3().setFromMatrixScale(keyframe.matrix);
-                refObj.keys.push(keyframe);
-            }
-            return refObj;
-        }
-    }]);
-    return XAnimationObj;
+
+	function XAnimationObj() {
+
+		classCallCheck( this, XAnimationObj );
+
+		this.fps = 30;
+		this.name = 'xanimation';
+		this.length = 0;
+		this.hierarchy = [];
+
+	}
+
+	createClass( XAnimationObj, [ {
+		key: 'make',
+		value: function make( XAnimationInfoArray, mesh ) {
+
+			var keys = Object.keys( XAnimationInfoArray );
+			var hierarchy_tmp = [];
+			for ( var i = 0; i < keys.length; i ++ ) {
+
+				var bone = null;
+				var parent = - 1;
+				var baseIndex = - 1;
+				for ( var m = 0; m < mesh.skeleton.bones.length; m ++ ) {
+
+					if ( mesh.skeleton.bones[ m ].name == XAnimationInfoArray[ keys[ i ] ].boneName ) {
+
+					bone = XAnimationInfoArray[ keys[ i ] ];
+					parent = mesh.skeleton.bones[ m ].parent.name;
+					baseIndex = m;
+					break;
+
+				}
+
+				}
+				hierarchy_tmp[ baseIndex ] = this.makeBonekeys( XAnimationInfoArray[ keys[ i ] ], bone, parent );
+
+			}
+			var keys2 = Object.keys( hierarchy_tmp );
+			for ( var _i = 0; _i < keys2.length; _i ++ ) {
+
+				this.hierarchy.push( hierarchy_tmp[ _i ] );
+				var parentId = - 1;
+				for ( var _m = 0; _m < this.hierarchy.length; _m ++ ) {
+
+					if ( _i != _m && this.hierarchy[ _i ].parent === this.hierarchy[ _m ].name ) {
+
+					parentId = _m;
+					break;
+
+				}
+
+				}
+				this.hierarchy[ _i ].parent = parentId;
+
+			}
+
+		}
+	}, {
+		key: 'makeBonekeys',
+		value: function makeBonekeys( XAnimationInfo, bone, parent ) {
+
+			var refObj = {};
+			refObj.name = bone.boneName;
+			refObj.parent = parent;
+			refObj.keys = [];
+			for ( var i = 0; i < XAnimationInfo.keyFrames.length; i ++ ) {
+
+				var keyframe = {};
+				keyframe.time = XAnimationInfo.keyFrames[ i ].time * this.fps;
+				keyframe.matrix = XAnimationInfo.keyFrames[ i ].matrix;
+				keyframe.pos = new THREE.Vector3().setFromMatrixPosition( keyframe.matrix );
+				keyframe.rot = new THREE.Quaternion().setFromRotationMatrix( keyframe.matrix );
+				keyframe.scl = new THREE.Vector3().setFromMatrixScale( keyframe.matrix );
+				refObj.keys.push( keyframe );
+
+			}
+			return refObj;
+
+		}
+	} ] );
+	return XAnimationObj;
+
 }();
 
 var Xdata = function Xdata() {
-    classCallCheck(this, Xdata);
 
-    this.FrameInfo = [];
-    this.FrameInfo_Raw = [];
-    this.AnimationSetInfo = [];
-    this.AnimTicksPerSecond = 60;
-    this.XAnimationObj = null;
+	classCallCheck( this, Xdata );
+
+	this.FrameInfo = [];
+	this.FrameInfo_Raw = [];
+	this.AnimationSetInfo = [];
+	this.AnimTicksPerSecond = 60;
+	this.XAnimationObj = null;
+
 };
 
 var XboneInf = function XboneInf() {
-    classCallCheck(this, XboneInf);
-
-    this.boneName = "";
-    this.BoneIndex = 0;
-    this.Indeces = [];
-    this.Weights = [];
-    this.initMatrix = null;
-    this.OffsetMatrix = null;
+
+	classCallCheck( this, XboneInf );
+
+	this.boneName = "";
+	this.BoneIndex = 0;
+	this.Indeces = [];
+	this.Weights = [];
+	this.initMatrix = null;
+	this.OffsetMatrix = null;
+
 };
 
 var XAnimationInfo$1 = XAnimationInfo = function XAnimationInfo() {
-    this.animeName = "";
-    this.boneName = "";
-    this.targetBone = null;
-    this.frameStartLv = 0;
-    this.keyFrames = [];
-    this.InverseMx = null;
+
+	this.animeName = "";
+	this.boneName = "";
+	this.targetBone = null;
+	this.frameStartLv = 0;
+	this.keyFrames = [];
+	this.InverseMx = null;
+
 };
 
 var XFrameInfo$1 = XFrameInfo = function XFrameInfo() {
-    this.Mesh = null;
-    this.Geometry = null;
-    this.FrameName = "";
-    this.ParentName = "";
-    this.frameStartLv = 0;
-    this.FrameTransformMatrix = null;
-    this.children = [];
-    this.BoneInfs = [];
-    this.VertexSetedBoneCount = [];
-    this.Materials = [];
+
+	this.Mesh = null;
+	this.Geometry = null;
+	this.FrameName = "";
+	this.ParentName = "";
+	this.frameStartLv = 0;
+	this.FrameTransformMatrix = null;
+	this.children = [];
+	this.BoneInfs = [];
+	this.VertexSetedBoneCount = [];
+	this.Materials = [];
+
 };
 
 var XKeyFrameInfo = function XKeyFrameInfo() {
-    classCallCheck(this, XKeyFrameInfo);
 
-    this.index = 0;
-    this.Frame = 0;
-    this.time = 0.0;
-    this.matrix = null;
+	classCallCheck( this, XKeyFrameInfo );
+
+	this.index = 0;
+	this.Frame = 0;
+	this.time = 0.0;
+	this.matrix = null;
+
 };
 
 THREE.XLoader = function () {
-    function XLoader(manager, Texloader, _zflg) {
-        classCallCheck(this, XLoader);
-
-        this.manager = manager !== undefined ? manager : new THREE.LoadingManager();
-        this.Texloader = Texloader !== undefined ? Texloader : new THREE.TextureLoader();
-        this.zflg = _zflg === undefined ? false : _zflg;
-        this.url = "";
-        this.baseDir = "";
-        this.nowReadMode = XfileLoadMode$1.none;
-        this.nowAnimationKeyType = 4;
-        this.tgtLength = 0;
-        this.nowReaded = 0;
-        this.elementLv = 0;
-        this.geoStartLv = Number.MAX_VALUE;
-        this.frameStartLv = Number.MAX_VALUE;
-        this.matReadLine = 0;
-        this.putMatLength = 0;
-        this.nowMat = null;
-        this.BoneInf = new XboneInf();
-        this.tmpUvArray = [];
-        this.normalVectors = [];
-        this.facesNormal = [];
-        this.nowFrameName = "";
-        this.nowAnimationSetName = "";
-        this.frameHierarchie = [];
-        this.endLineCount = 0;
-        this.geometry = null;
-        this.loadingXdata = null;
-        this.lines = null;
-        this.keyInfo = null;
-        this.animeKeyNames = null;
-        this.data = null;
-        this.onLoad = null;
-    }
-
-    createClass(XLoader, [{
-        key: 'load',
-        value: function load(_arg, onLoad, onProgress, onError) {
-            var _this = this;
-
-            var loader = new THREE.FileLoader(this.manager);
-            loader.setResponseType('arraybuffer');
-            for (var i = 0; i < _arg.length; i++) {
-                switch (i) {
-                    case 0:
-                        this.url = _arg[i];break;
-                    case 1:
-                        this.zflg = _arg[i];break;
-                }
-            }
-            loader.load(this.url, function (response) {
-                _this.parse(response, onLoad);
-            }, onProgress, onError);
-        }
-    }, {
-        key: 'isBinary',
-        value: function isBinary(binData) {
-            var reader = new DataView(binData);
-            var face_size = 32 / 8 * 3 + 32 / 8 * 3 * 3 + 16 / 8;
-            var n_faces = reader.getUint32(80, true);
-            var expect = 80 + 32 / 8 + n_faces * face_size;
-            if (expect === reader.byteLength) {
-                return true;
-            }
-            var fileLength = reader.byteLength;
-            for (var index = 0; index < fileLength; index++) {
-                if (reader.getUint8(index, false) > 127) {
-                    return true;
-                }
-            }
-            return false;
-        }
-    }, {
-        key: 'ensureBinary',
-        value: function ensureBinary(buf) {
-            if (typeof buf === "string") {
-                var array_buffer = new Uint8Array(buf.length);
-                for (var i = 0; i < buf.length; i++) {
-                    array_buffer[i] = buf.charCodeAt(i) & 0xff;
-                }
-                return array_buffer.buffer || array_buffer;
-            } else {
-                return buf;
-            }
-        }
-    }, {
-        key: 'ensureString',
-        value: function ensureString(buf) {
-            if (typeof buf !== "string") {
-                var array_buffer = new Uint8Array(buf);
-                var str = '';
-                for (var i = 0; i < buf.byteLength; i++) {
-                    str += String.fromCharCode(array_buffer[i]);
-                }
-                return str;
-            } else {
-                return buf;
-            }
-        }
-    }, {
-        key: 'parse',
-        value: function parse(data, onLoad) {
-            var binData = this.ensureBinary(data);
-            this.data = this.ensureString(data);
-            this.onLoad = onLoad;
-            return this.isBinary(binData) ? this.parseBinary(binData) : this.parseASCII();
-        }
-    }, {
-        key: 'parseBinary',
-        value: function parseBinary(data) {
-            return parseASCII(String.fromCharCode.apply(null, data));
-        }
-    }, {
-        key: 'parseASCII',
-        value: function parseASCII() {
-            var baseDir = "";
-            if (this.url.lastIndexOf("/") > 0) {
-                this.baseDir = this.url.substr(0, this.url.lastIndexOf("/") + 1);
-            }
-            this.loadingXdata = new Xdata();
-            this.lines = this.data.split("\n");
-            this.mainloop();
-        }
-    }, {
-        key: 'mainloop',
-        value: function mainloop() {
-            var _this2 = this;
-
-            var EndFlg = false;
-            for (var i = 0; i < 100; i++) {
-                this.lineRead(this.lines[this.endLineCount].trim());
-                this.endLineCount++;
-                if (this.endLineCount >= this.lines.length - 1) {
-                    EndFlg = true;
-                    this.readFinalize();
-                    setTimeout(function () {
-                        _this2.animationFinalize();
-                    }, 1);
-                    break;
-                }
-            }
-            if (!EndFlg) {
-                setTimeout(function () {
-                    _this2.mainloop();
-                }, 1);
-            }
-        }
-    }, {
-        key: 'lineRead',
-        value: function lineRead(line) {
-            if (line.indexOf("template ") > -1) {
-                return;
-            }
-            if (line.length === 0) {
-                return;
-            }
-            if (line.indexOf("{") > -1) {
-                this.elementLv++;
-            }
-            if (line.indexOf("AnimTicksPerSecond") > -1) {
-                var findA = line.indexOf("{");
-                this.loadingXdata.AnimTicksPerSecond = parseInt(line.substr(findA + 1, line.indexOf(";") - findA + 1), 10);
-            }
-            if (line.indexOf("}") > -1) {
-                if (this.elementLv < 1 || this.nowFrameName === "") {
-                    this.elementLv = 0;return;
-                }
-                this.endElement();
-                return;
-            }
-            if (line.indexOf("Frame ") > -1) {
-                this.beginFrame(line);
-                return;
-            }
-            if (line.indexOf("FrameTransformMatrix") > -1) {
-                this.nowReadMode = XfileLoadMode$1.FrameTransformMatrix_Read;
-                return;
-            }
-            if (this.nowReadMode === XfileLoadMode$1.FrameTransformMatrix_Read) {
-                var data = line.split(",");
-                this.loadingXdata.FrameInfo_Raw[this.nowFrameName].FrameTransformMatrix = new THREE.Matrix4();
-                this.ParseMatrixData(this.loadingXdata.FrameInfo_Raw[this.nowFrameName].FrameTransformMatrix, data);
-                this.nowReadMode = XfileLoadMode$1.Element;
-                return;
-            }
-            if (line.indexOf("Mesh ") > -1) {
-                this.beginReadMesh(line);return;
-            }
-            if (this.nowReadMode === XfileLoadMode$1.Vartex_init) {
-                this.readVertexCount(line);return;
-            }
-            if (this.nowReadMode === XfileLoadMode$1.Vartex_Read) {
-                if (this.readVertex(line)) {
-                    return;
-                }
-            }
-            if (this.nowReadMode === XfileLoadMode$1.Index_init) {
-                this.readIndexLength(line);return;
-            }
-            if (this.nowReadMode === XfileLoadMode$1.index_Read) {
-                if (this.readVertexIndex(line)) {
-                    return;
-                }
-            }
-            if (line.indexOf("MeshNormals ") > -1) {
-                this.beginMeshNormal(line);return;
-            }
-            if (this.nowReadMode === XfileLoadMode$1.Normal_V_init) {
-                this.readMeshNormalCount(line);return;
-            }
-            if (this.nowReadMode === XfileLoadMode$1.Normal_V_Read) {
-                if (this.readMeshNormalVertex(line)) {
-                    return;
-                }
-            }
-            if (this.nowReadMode === XfileLoadMode$1.Normal_I_init) {
-                this.readMeshNormalIndexCount(line);return;
-            }
-            if (this.nowReadMode === XfileLoadMode$1.Normal_I_Read) {
-                if (this.readMeshNormalIndex(line)) {
-                    return;
-                }
-            }
-            if (line.indexOf("MeshTextureCoords ") > -1) {
-                this.nowReadMode = XfileLoadMode$1.Uv_init;return;
-            }
-            if (this.nowReadMode === XfileLoadMode$1.Uv_init) {
-                this.readUvInit(line);return;
-            }
-            if (this.nowReadMode === XfileLoadMode$1.Uv_Read) {
-                if (this.readUv(line)) {
-                    return;
-                }
-            }
-            if (line.indexOf("MeshMaterialList ") > -1) {
-                this.nowReadMode = XfileLoadMode$1.Mat_Face_init;
-                return;
-            }
-            if (this.nowReadMode === XfileLoadMode$1.Mat_Face_init) {
-                this.nowReadMode = XfileLoadMode$1.Mat_Face_len_Read;
-                return;
-            }
-            if (this.nowReadMode === XfileLoadMode$1.Mat_Face_len_Read) {
-                this.readMatrixSetLength(line);return;
-            }
-            if (this.nowReadMode === XfileLoadMode$1.Mat_Face_Set) {
-                if (this.readMaterialBind(line)) {
-                    return;
-                }
-            }
-            if (line.indexOf("Material ") > -1) {
-                this.readMaterialInit(line);return;
-            }
-            if (this.nowReadMode === XfileLoadMode$1.Mat_Set) {
-                this.readandSetMaterial(line);return;
-            }
-            if (this.nowReadMode >= XfileLoadMode$1.Mat_Set_Texture && this.nowReadMode < XfileLoadMode$1.Weit_init) {
-                this.readandSetMaterialTexture(line);return;
-            }
-            if (line.indexOf("SkinWeights ") > -1 && this.nowReadMode >= XfileLoadMode$1.Element) {
-                this.readBoneInit(line);return;
-            }
-            if (this.nowReadMode === XfileLoadMode$1.Weit_init) {
-                this.readBoneName(line);return;
-            }
-            if (this.nowReadMode === XfileLoadMode$1.Weit_IndexLength) {
-                this.readBoneVertexLength(line);return;
-            }
-            if (this.nowReadMode === XfileLoadMode$1.Weit_Read_Index) {
-                this.readandSetBoneVertex(line);return;
-            }
-            if (this.nowReadMode === XfileLoadMode$1.Weit_Read_Value) {
-                this.readandSetBoneWeightValue(line);return;
-            }
-            if (this.nowReadMode === XfileLoadMode$1.Weit_Read_Matrx) {
-                this.readandSetBoneOffsetMatrixValue(line);return;
-            }
-            if (line.indexOf("AnimationSet ") > -1) {
-                this.readandCreateAnimationSet(line);return;
-            }
-            if (line.indexOf("Animation ") > -1 && this.nowReadMode === XfileLoadMode$1.Anim_init) {
-                this.readAndCreateAnimation(line);return;
-            }
-            if (line.indexOf("AnimationKey ") > -1) {
-                this.nowReadMode = XfileLoadMode$1.Anim_KeyValueTypeRead;return;
-            }
-            if (this.nowReadMode === XfileLoadMode$1.Anim_KeyValueTypeRead) {
-                this.nowAnimationKeyType = parseInt(line.substr(0, line.length - 1), 10);
-                this.nowReadMode = XfileLoadMode$1.Anim_KeyValueLength;
-                return;
-            }
-            if (this.nowReadMode === XfileLoadMode$1.Anim_KeyValueLength) {
-                this.tgtLength = parseInt(line.substr(0, line.length - 1), 10);
-                this.nowReaded = 0;
-                this.nowReadMode = XfileLoadMode$1.Anime_ReadKeyFrame;
-                return;
-            }
-            if (this.nowReadMode === XfileLoadMode$1.Anime_ReadKeyFrame) {
-                this.readAnimationKeyFrame(line);return;
-            }
-        }
-    }, {
-        key: 'endElement',
-        value: function endElement(line) {
-            if (this.nowReadMode < XfileLoadMode$1.Anim_init && this.loadingXdata.FrameInfo_Raw[this.nowFrameName].FrameStartLv === this.elementLv && this.nowReadMode > XfileLoadMode$1.none) {
-                if (this.frameHierarchie.length > 0) {
-                    this.loadingXdata.FrameInfo_Raw[this.nowFrameName].children = [];
-                    var keys = Object.keys(this.loadingXdata.FrameInfo_Raw);
-                    for (var m = 0; m < keys.length; m++) {
-                        if (this.loadingXdata.FrameInfo_Raw[keys[m]].ParentName === this.nowFrameName) {
-                            this.loadingXdata.FrameInfo_Raw[this.nowFrameName].children.push(keys[m]);
-                        }
-                    }
-                    this.frameHierarchie.pop();
-                }
-                this.MakeOutputGeometry(this.nowFrameName, this.zflg);
-                this.frameStartLv = this.loadingXdata.FrameInfo_Raw[this.nowFrameName].FrameStartLv;
-                if (this.frameHierarchie.length > 0) {
-                    this.nowFrameName = this.frameHierarchie[this.frameHierarchie.length - 1];
-                    this.frameStartLv = this.loadingXdata.FrameInfo_Raw[this.nowFrameName].FrameStartLv;
-                } else {
-                    this.nowFrameName = "";
-                }
-            }
-            if (this.nowReadMode === XfileLoadMode$1.Mat_Set) {
-                this.loadingXdata.FrameInfo_Raw[this.nowFrameName].Materials.push(this.nowMat);
-                this.nowReadMode = XfileLoadMode$1.Element;
-            }
-            this.elementLv--;
-        }
-    }, {
-        key: 'beginFrame',
-        value: function beginFrame(line) {
-            this.frameStartLv = this.elementLv;
-            this.nowReadMode = XfileLoadMode$1.Element;
-            this.nowFrameName = line.substr(6, line.length - 8);
-            this.loadingXdata.FrameInfo_Raw[this.nowFrameName] = new XFrameInfo$1();
-            this.loadingXdata.FrameInfo_Raw[this.nowFrameName].FrameName = this.nowFrameName;
-            if (this.frameHierarchie.length > 0) {
-                this.loadingXdata.FrameInfo_Raw[this.nowFrameName].ParentName = this.frameHierarchie[this.frameHierarchie.length - 1];
-            }
-            this.frameHierarchie.push(this.nowFrameName);
-            this.loadingXdata.FrameInfo_Raw[this.nowFrameName].FrameStartLv = this.frameStartLv;
-        }
-    }, {
-        key: 'beginReadMesh',
-        value: function beginReadMesh(line) {
-            if (this.nowFrameName === "") {
-                this.frameStartLv = this.elementLv;
-                this.nowFrameName = line.substr(5, line.length - 6);
-                if (this.nowFrameName === "") {
-                    this.nowFrameName = "mesh_" + this.loadingXdata.FrameInfo_Raw.length;
-                }
-                this.loadingXdata.FrameInfo_Raw[this.nowFrameName] = new XFrameInfo$1();
-                this.loadingXdata.FrameInfo_Raw[this.nowFrameName].FrameName = this.nowFrameName;
-                this.loadingXdata.FrameInfo_Raw[this.nowFrameName].FrameStartLv = this.frameStartLv;
-            }
-            this.loadingXdata.FrameInfo_Raw[this.nowFrameName].Geometry = new THREE.Geometry();
-            this.geoStartLv = this.elementLv;
-            this.nowReadMode = XfileLoadMode$1.Vartex_init;
-            Bones = [];
-            this.loadingXdata.FrameInfo_Raw[this.nowFrameName].Materials = [];
-        }
-    }, {
-        key: 'readVertexCount',
-        value: function readVertexCount(line) {
-            this.nowReadMode = XfileLoadMode$1.Vartex_Read;
-            this.tgtLength = parseInt(line.substr(0, line.length - 1), 10);
-            this.nowReaded = 0;
-        }
-    }, {
-        key: 'readVertex',
-        value: function readVertex(line) {
-            var data = line.substr(0, line.length - 2).split(";");
-            this.loadingXdata.FrameInfo_Raw[this.nowFrameName].Geometry.vertices.push(new THREE.Vector3(parseFloat(data[0]), parseFloat(data[1]), parseFloat(data[2])));
-            this.loadingXdata.FrameInfo_Raw[this.nowFrameName].Geometry.skinIndices.push(new THREE.Vector4(0, 0, 0, 0));
-            this.loadingXdata.FrameInfo_Raw[this.nowFrameName].Geometry.skinWeights.push(new THREE.Vector4(1, 0, 0, 0));
-            this.loadingXdata.FrameInfo_Raw[this.nowFrameName].VertexSetedBoneCount.push(0);
-            this.nowReaded++;
-            if (this.nowReaded >= this.tgtLength) {
-                this.nowReadMode = XfileLoadMode$1.Index_init;
-                return true;
-            }
-            return false;
-        }
-    }, {
-        key: 'readIndexLength',
-        value: function readIndexLength(line) {
-            this.nowReadMode = XfileLoadMode$1.index_Read;
-            this.tgtLength = parseInt(line.substr(0, line.length - 1), 10);
-            this.nowReaded = 0;
-        }
-    }, {
-        key: 'readVertexIndex',
-        value: function readVertexIndex(line) {
-            var data = line.substr(2, line.length - 4).split(",");
-            if (this.zflg) {
-                this.loadingXdata.FrameInfo_Raw[this.nowFrameName].Geometry.faces.push(new THREE.Face3(parseInt(data[2], 10), parseInt(data[1], 10), parseInt(data[0], 10), new THREE.Vector3(1, 1, 1).normalize()));
-            } else {
-                this.loadingXdata.FrameInfo_Raw[this.nowFrameName].Geometry.faces.push(new THREE.Face3(parseInt(data[0], 10), parseInt(data[1], 10), parseInt(data[2], 10), new THREE.Vector3(1, 1, 1).normalize()));
-            }
-            this.nowReaded++;
-            if (this.nowReaded >= this.tgtLength) {
-                this.nowReadMode = XfileLoadMode$1.Element;
-                return true;
-            }
-            return false;
-        }
-    }, {
-        key: 'beginMeshNormal',
-        value: function beginMeshNormal(line) {
-            this.nowReadMode = XfileLoadMode$1.Normal_V_init;
-            this.normalVectors = [];
-            this.facesNormal = [];
-        }
-    }, {
-        key: 'readMeshNormalCount',
-        value: function readMeshNormalCount(line) {
-            this.nowReadMode = XfileLoadMode$1.Normal_V_Read;
-            this.tgtLength = parseInt(line.substr(0, line.length - 1), 10);
-            this.nowReaded = 0;
-        }
-    }, {
-        key: 'readMeshNormalVertex',
-        value: function readMeshNormalVertex(line) {
-            var data = line.split(";");
-            this.normalVectors.push([parseFloat(data[0]), parseFloat(data[1]), parseFloat(data[2])]);
-            this.nowReaded++;
-            if (this.nowReaded >= this.tgtLength) {
-                this.nowReadMode = XfileLoadMode$1.Normal_I_init;
-                return true;
-            }
-            return false;
-        }
-    }, {
-        key: 'readMeshNormalIndexCount',
-        value: function readMeshNormalIndexCount(line) {
-            this.nowReadMode = XfileLoadMode$1.Normal_I_Read;
-            this.tgtLength = parseInt(line.substr(0, line.length - 1), 10);
-            this.nowReaded = 0;
-        }
-    }, {
-        key: 'readMeshNormalIndex',
-        value: function readMeshNormalIndex(line) {
-            var data = line.substr(2, line.length - 4).split(",");
-            var nowID = parseInt(data[0], 10);
-            var v1 = new THREE.Vector3(this.normalVectors[nowID][0], this.normalVectors[nowID][1], this.normalVectors[nowID][2]);
-            nowID = parseInt(data[1], 10);
-            var v2 = new THREE.Vector3(this.normalVectors[nowID][0], this.normalVectors[nowID][1], this.normalVectors[nowID][2]);
-            nowID = parseInt(data[2], 10);
-            var v3 = new THREE.Vector3(this.normalVectors[nowID][0], this.normalVectors[nowID][1], this.normalVectors[nowID][2]);
-            if (this.zflg) {
-                this.loadingXdata.FrameInfo_Raw[this.nowFrameName].Geometry.faces[this.nowReaded].vertexNormals = [v3, v2, v1];
-            } else {
-                this.loadingXdata.FrameInfo_Raw[this.nowFrameName].Geometry.faces[this.nowReaded].vertexNormals = [v1, v2, v3];
-            }
-            this.facesNormal.push(v1.normalize());
-            this.nowReaded++;
-            if (this.nowReaded >= this.tgtLength) {
-                this.nowReadMode = XfileLoadMode$1.Element;
-                return true;
-            }
-            return false;
-        }
-    }, {
-        key: 'readUvInit',
-        value: function readUvInit(line) {
-            this.nowReadMode = XfileLoadMode$1.Uv_Read;
-            this.tgtLength = parseInt(line.substr(0, line.length - 1), 10);
-            this.nowReaded = 0;
-            this.tmpUvArray = [];
-            this.loadingXdata.FrameInfo_Raw[this.nowFrameName].Geometry.faceVertexUvs[0] = [];
-        }
-    }, {
-        key: 'readUv',
-        value: function readUv(line) {
-            var data = line.split(";");
-            if (THREE.XLoader.IsUvYReverse) {
-                this.tmpUvArray.push(new THREE.Vector2(parseFloat(data[0]), 1 - parseFloat(data[1])));
-            } else {
-                this.tmpUvArray.push(new THREE.Vector2(parseFloat(data[0]), parseFloat(data[1])));
-            }
-            this.nowReaded++;
-            if (this.nowReaded >= this.tgtLength) {
-                this.loadingXdata.FrameInfo_Raw[this.nowFrameName].Geometry.faceVertexUvs[0] = [];
-                for (var m = 0; m < this.loadingXdata.FrameInfo_Raw[this.nowFrameName].Geometry.faces.length; m++) {
-                    this.loadingXdata.FrameInfo_Raw[this.nowFrameName].Geometry.faceVertexUvs[0][m] = [];
-                    this.loadingXdata.FrameInfo_Raw[this.nowFrameName].Geometry.faceVertexUvs[0][m].push(this.tmpUvArray[this.loadingXdata.FrameInfo_Raw[this.nowFrameName].Geometry.faces[m].a]);
-                    this.loadingXdata.FrameInfo_Raw[this.nowFrameName].Geometry.faceVertexUvs[0][m].push(this.tmpUvArray[this.loadingXdata.FrameInfo_Raw[this.nowFrameName].Geometry.faces[m].b]);
-                    this.loadingXdata.FrameInfo_Raw[this.nowFrameName].Geometry.faceVertexUvs[0][m].push(this.tmpUvArray[this.loadingXdata.FrameInfo_Raw[this.nowFrameName].Geometry.faces[m].c]);
-                }
-                this.nowReadMode = XfileLoadMode$1.Element;
-                this.loadingXdata.FrameInfo_Raw[this.nowFrameName].Geometry.uvsNeedUpdate = true;
-                return true;
-            }
-            return false;
-        }
-    }, {
-        key: 'readMatrixSetLength',
-        value: function readMatrixSetLength(line) {
-            this.nowReadMode = XfileLoadMode$1.Mat_Face_Set;
-            this.tgtLength = parseInt(line.substr(0, line.length - 1), 10);
-            this.nowReaded = 0;
-        }
-    }, {
-        key: 'readMaterialBind',
-        value: function readMaterialBind(line) {
-            var data = line.split(",");
-            this.loadingXdata.FrameInfo_Raw[this.nowFrameName].Geometry.faces[this.nowReaded].materialIndex = parseInt(data[0]);
-            this.nowReaded++;
-            if (this.nowReaded >= this.tgtLength) {
-                this.nowReadMode = XfileLoadMode$1.Element;
-                return true;
-            }
-            return false;
-        }
-    }, {
-        key: 'readMaterialInit',
-        value: function readMaterialInit(line) {
-            this.nowReadMode = XfileLoadMode$1.Mat_Set;
-            this.matReadLine = 0;
-            this.nowMat = new THREE.MeshPhongMaterial({ color: Math.random() * 0xffffff });
-            var matName = line.substr(9, line.length - 10);
-            if (matName !== "") {
-                this.nowMat.name = matName;
-            }
-            if (this.zflg) {
-                this.nowMat.side = THREE.BackSide;
-            } else {
-                this.nowMat.side = THREE.FrontSide;
-            }
-            this.nowMat.side = THREE.FrontSide;
-        }
-    }, {
-        key: 'readandSetMaterial',
-        value: function readandSetMaterial(line) {
-            var data = line.split(";");
-            this.matReadLine++;
-            switch (this.matReadLine) {
-                case 1:
-                    this.nowMat.color.r = data[0];
-                    this.nowMat.color.g = data[1];
-                    this.nowMat.color.b = data[2];
-                    break;
-                case 2:
-                    this.nowMat.shininess = data[0];
-                    break;
-                case 3:
-                    this.nowMat.specular.r = data[0];
-                    this.nowMat.specular.g = data[1];
-                    this.nowMat.specular.b = data[2];
-                    break;
-                case 4:
-                    this.nowMat.emissive.r = data[0];
-                    this.nowMat.emissive.g = data[1];
-                    this.nowMat.emissive.b = data[2];
-                    break;
-            }
-            if (line.indexOf("TextureFilename") > -1) {
-                this.nowReadMode = XfileLoadMode$1.Mat_Set_Texture;
-            } else if (line.indexOf("BumpMapFilename") > -1) {
-                this.nowReadMode = XfileLoadMode$1.Mat_Set_BumpTex;
-                this.nowMat.bumpScale = 0.05;
-            } else if (line.indexOf("NormalMapFilename") > -1) {
-                this.nowReadMode = XfileLoadMode$1.Mat_Set_NormalTex;
-                this.nowMat.normalScale = new THREE.Vector2(2, 2);
-            } else if (line.indexOf("EmissiveMapFilename") > -1) {
-                this.nowReadMode = XfileLoadMode$1.Mat_Set_EmissiveTex;
-            } else if (line.indexOf("LightMapFilename") > -1) {
-                this.nowReadMode = XfileLoadMode$1.Mat_Set_LightTex;
-            }
-        }
-    }, {
-        key: 'readandSetMaterialTexture',
-        value: function readandSetMaterialTexture(line) {
-            var data = line.substr(1, line.length - 3);
-            if (data != undefined && data.length > 0) {
-                switch (this.nowReadMode) {
-                    case XfileLoadMode$1.Mat_Set_Texture:
-                        this.nowMat.map = this.Texloader.load(this.baseDir + data);
-                        break;
-                    case XfileLoadMode$1.Mat_Set_BumpTex:
-                        this.nowMat.bumpMap = this.Texloader.load(this.baseDir + data);
-                        break;
-                    case XfileLoadMode$1.Mat_Set_NormalTex:
-                        this.nowMat.normalMap = this.Texloader.load(this.baseDir + data);
-                        break;
-                    case XfileLoadMode$1.Mat_Set_EmissiveTex:
-                        this.nowMat.emissiveMap = this.Texloader.load(this.baseDir + data);
-                        break;
-                    case XfileLoadMode$1.Mat_Set_LightTex:
-                        this.nowMat.lightMap = this.Texloader.load(this.baseDir + data);
-                        break;
-                    case XfileLoadMode$1.Mat_Set_EnvTex:
-                        this.nowMat.envMap = this.Texloader.load(this.baseDir + data);
-                        break;
-                }
-            }
-            this.nowReadMode = XfileLoadMode$1.Mat_Set;
-            this.endLineCount++;
-            this.elementLv--;
-        }
-    }, {
-        key: 'readBoneInit',
-        value: function readBoneInit(line) {
-            this.nowReadMode = XfileLoadMode$1.Weit_init;
-            this.BoneInf = new XboneInf();
-        }
-    }, {
-        key: 'readBoneName',
-        value: function readBoneName(line) {
-            this.nowReadMode = XfileLoadMode$1.Weit_IndexLength;
-            this.BoneInf.boneName = line.substr(1, line.length - 3);
-            this.BoneInf.BoneIndex = this.loadingXdata.FrameInfo_Raw[this.nowFrameName].BoneInfs.length;
-            this.nowReaded = 0;
-        }
-    }, {
-        key: 'readBoneVertexLength',
-        value: function readBoneVertexLength(line) {
-            this.nowReadMode = XfileLoadMode$1.Weit_Read_Index;
-            this.tgtLength = parseInt(line.substr(0, line.length - 1), 10);
-            this.nowReaded = 0;
-        }
-    }, {
-        key: 'readandSetBoneVertex',
-        value: function readandSetBoneVertex(line) {
-            this.BoneInf.Indeces.push(parseInt(line.substr(0, line.length - 1), 10));
-            this.nowReaded++;
-            if (this.nowReaded >= this.tgtLength || line.indexOf(";") > -1) {
-                this.nowReadMode = XfileLoadMode$1.Weit_Read_Value;
-                this.nowReaded = 0;
-            }
-        }
-    }, {
-        key: 'readandSetBoneWeightValue',
-        value: function readandSetBoneWeightValue(line) {
-            var nowVal = parseFloat(line.substr(0, line.length - 1));
-            this.BoneInf.Weights.push(nowVal);
-            this.nowReaded++;
-            if (this.nowReaded >= this.tgtLength || line.indexOf(";") > -1) {
-                this.nowReadMode = XfileLoadMode$1.Weit_Read_Matrx;
-            }
-        }
-    }, {
-        key: 'readandSetBoneOffsetMatrixValue',
-        value: function readandSetBoneOffsetMatrixValue(line) {
-            var data = line.split(",");
-            this.BoneInf.initMatrix = new THREE.Matrix4();
-            this.ParseMatrixData(this.BoneInf.initMatrix, data);
-            this.BoneInf.OffsetMatrix = new THREE.Matrix4();
-            this.BoneInf.OffsetMatrix.getInverse(this.BoneInf.initMatrix);
-            this.loadingXdata.FrameInfo_Raw[this.nowFrameName].BoneInfs.push(this.BoneInf);
-            this.nowReadMode = XfileLoadMode$1.Element;
-        }
-    }, {
-        key: 'readandCreateAnimationSet',
-        value: function readandCreateAnimationSet(line) {
-            this.frameStartLv = this.elementLv;
-            this.nowReadMode = XfileLoadMode$1.Anim_init;
-            this.nowAnimationSetName = line.substr(13, line.length - 14).trim();
-            this.loadingXdata.AnimationSetInfo[this.nowAnimationSetName] = [];
-        }
-    }, {
-        key: 'readAndCreateAnimation',
-        value: function readAndCreateAnimation(line) {
-            this.nowFrameName = line.substr(10, line.length - 11).trim();
-            this.loadingXdata.AnimationSetInfo[this.nowAnimationSetName][this.nowFrameName] = new XAnimationInfo$1();
-            this.loadingXdata.AnimationSetInfo[this.nowAnimationSetName][this.nowFrameName].animeName = this.nowFrameName;
-            this.loadingXdata.AnimationSetInfo[this.nowAnimationSetName][this.nowFrameName].FrameStartLv = this.frameStartLv;
-            while (true) {
-                this.endLineCount++;
-                line = this.lines[this.endLineCount].trim();
-                if (line.indexOf("{") > -1 && line.indexOf("}") > -1) {
-                    this.loadingXdata.AnimationSetInfo[this.nowAnimationSetName][this.nowFrameName].boneName = line.replace(/{/g, "").replace(/}/g, "").trim();
-                    break;
-                }
-            }
-        }
-    }, {
-        key: 'readAnimationKeyFrame',
-        value: function readAnimationKeyFrame(line) {
-            this.keyInfo = null;
-            var data = line.split(";");
-            var nowKeyframe = parseInt(data[0], 10);
-            var frameFound = false;
-            var tmpM = new THREE.Matrix4();
-            if (this.nowAnimationKeyType != 4) {
-                for (var mm = 0; mm < this.loadingXdata.AnimationSetInfo[this.nowAnimationSetName][this.nowFrameName].keyFrames.length; mm++) {
-                    if (this.loadingXdata.AnimationSetInfo[this.nowAnimationSetName][this.nowFrameName].keyFrames[mm].Frame === nowKeyframe) {
-                        this.keyInfo = this.loadingXdata.AnimationSetInfo[this.nowAnimationSetName][this.nowFrameName].keyFrames[mm];
-                        frameFound = true;
-                        break;
-                    }
-                }
-            }
-            if (!frameFound) {
-                this.keyInfo = new XKeyFrameInfo();
-                this.keyInfo.matrix = new THREE.Matrix4();
-                this.keyInfo.Frame = nowKeyframe;
-            }
-            var data2 = data[2].split(",");
-            switch (this.nowAnimationKeyType) {
-                case 0:
-                    tmpM.makeRotationFromQuaternion(new THREE.Quaternion(parseFloat(data2[0]), parseFloat(data2[1]), parseFloat(data2[2])));
-                    this.keyInfo.matrix.multiply(tmpM);
-                    break;
-                case 1:
-                    tmpM.makeScale(parseFloat(data2[0]), parseFloat(data2[1]), parseFloat(data2[2]));
-                    this.keyInfo.matrix.multiply(tmpM);
-                    break;
-                case 2:
-                    tmpM.makeTranslation(parseFloat(data2[0]), parseFloat(data2[1]), parseFloat(data2[2]));
-                    this.keyInfo.matrix.multiply(tmpM);
-                    break;
-                case 4:
-                    this.ParseMatrixData(this.keyInfo.matrix, data2);
-                    break;
-            }
-            if (!frameFound) {
-                this.keyInfo.index = this.loadingXdata.AnimationSetInfo[this.nowAnimationSetName][this.nowFrameName].keyFrames.length;
-                this.keyInfo.time = /*1.0 / this.loadingXdata.AnimTicksPerSecond * */this.keyInfo.Frame;
-                this.loadingXdata.AnimationSetInfo[this.nowAnimationSetName][this.nowFrameName].keyFrames.push(this.keyInfo);
-            }
-            this.nowReaded++;
-            if (this.nowReaded >= this.tgtLength || line.indexOf(";;;") > -1) {
-                this.nowReadMode = XfileLoadMode$1.Anim_init;
-            }
-        }
-    }, {
-        key: 'readFinalize',
-        value: function readFinalize() {
-            this.loadingXdata.FrameInfo = [];
-            var keys = Object.keys(this.loadingXdata.FrameInfo_Raw);
-            for (var i = 0; i < keys.length; i++) {
-                if (this.loadingXdata.FrameInfo_Raw[keys[i]].Mesh != null) {
-                    this.loadingXdata.FrameInfo.push(this.loadingXdata.FrameInfo_Raw[keys[i]].Mesh);
-                }
-            }
-            if (this.loadingXdata.FrameInfo != null & this.loadingXdata.FrameInfo.length > 0) {
-                for (var _i = 0; _i < this.loadingXdata.FrameInfo.length; _i++) {
-                    if (this.loadingXdata.FrameInfo[_i].parent == null) {
-                        this.loadingXdata.FrameInfo[_i].zflag = this.zflg;
-                        if (this.zflg) {
-                            this.loadingXdata.FrameInfo[_i].scale.set(-1, 1, 1);
-                        }
-                    }
-                }
-            }
-        }
-    }, {
-        key: 'ParseMatrixData',
-        value: function ParseMatrixData(targetMatrix, data) {
-            targetMatrix.set(parseFloat(data[0]), parseFloat(data[4]), parseFloat(data[8]), parseFloat(data[12]), parseFloat(data[1]), parseFloat(data[5]), parseFloat(data[9]), parseFloat(data[13]), parseFloat(data[2]), parseFloat(data[6]), parseFloat(data[10]), parseFloat(data[14]), parseFloat(data[3]), parseFloat(data[7]), parseFloat(data[11]), parseFloat(data[15]));
-        }
-    }, {
-        key: 'MakeOutputGeometry',
-        value: function MakeOutputGeometry(nowFrameName, _zflg) {
-            if (this.loadingXdata.FrameInfo_Raw[nowFrameName].Geometry != null) {
-                this.loadingXdata.FrameInfo_Raw[nowFrameName].Geometry.computeBoundingBox();
-                this.loadingXdata.FrameInfo_Raw[nowFrameName].Geometry.computeBoundingSphere();
-                this.loadingXdata.FrameInfo_Raw[nowFrameName].Geometry.verticesNeedUpdate = true;
-                this.loadingXdata.FrameInfo_Raw[nowFrameName].Geometry.normalsNeedUpdate = true;
-                this.loadingXdata.FrameInfo_Raw[nowFrameName].Geometry.colorsNeedUpdate = true;
-                this.loadingXdata.FrameInfo_Raw[nowFrameName].Geometry.uvsNeedUpdate = true;
-                this.loadingXdata.FrameInfo_Raw[nowFrameName].Geometry.groupsNeedUpdate = true;
-                var putBones = [];
-                var BoneDics = [];
-                var rootBone = new THREE.Bone();
-                if (this.loadingXdata.FrameInfo_Raw[nowFrameName].BoneInfs != null && this.loadingXdata.FrameInfo_Raw[nowFrameName].BoneInfs.length) {
-                    var keys = Object.keys(this.loadingXdata.FrameInfo_Raw);
-                    var BoneDics_Name = [];
-                    for (var m = 0; m < keys.length; m++) {
-                        if (this.loadingXdata.FrameInfo_Raw[keys[m]].FrameStartLv <= this.loadingXdata.FrameInfo_Raw[nowFrameName].FrameStartLv && nowFrameName != keys[m]) {
-                            continue;
-                        }
-                        var b = new THREE.Bone();
-                        b.name = keys[m];
-                        b.applyMatrix(this.loadingXdata.FrameInfo_Raw[keys[m]].FrameTransformMatrix);
-                        b.matrixWorld = b.matrix;
-                        b.FrameTransformMatrix = this.loadingXdata.FrameInfo_Raw[keys[m]].FrameTransformMatrix;
-                        BoneDics_Name[b.name] = putBones.length;
-                        putBones.push(b);
-                    }
-                    for (var _m = 0; _m < putBones.length; _m++) {
-                        for (var dx = 0; dx < this.loadingXdata.FrameInfo_Raw[putBones[_m].name].children.length; dx++) {
-                            var nowBoneIndex = BoneDics_Name[this.loadingXdata.FrameInfo_Raw[putBones[_m].name].children[dx]];
-                            if (putBones[nowBoneIndex] != null) {
-                                putBones[_m].add(putBones[nowBoneIndex]);
-                            }
-                        }
-                    }
-                }
-                var mesh = null;
-                var bufferGeometry = new THREE.BufferGeometry();
-                if (putBones.length > 0) {
-                    if (this.loadingXdata.FrameInfo_Raw[putBones[0].name].children.length === 0 && nowFrameName != putBones[0].name) {
-                        putBones[0].add(putBones[1]);
-                        putBones[0].zflag = _zflg;
-                    }
-                    for (var _m2 = 0; _m2 < putBones.length; _m2++) {
-                        if (putBones[_m2].parent === null) {
-                            putBones[_m2].zflag = _zflg;
-                        }
-                        for (var bi = 0; bi < this.loadingXdata.FrameInfo_Raw[nowFrameName].BoneInfs.length; bi++) {
-                            if (putBones[_m2].name === this.loadingXdata.FrameInfo_Raw[nowFrameName].BoneInfs[bi].boneName) {
-                                for (var vi = 0; vi < this.loadingXdata.FrameInfo_Raw[nowFrameName].BoneInfs[bi].Indeces.length; vi++) {
-                                    var nowVertexID = this.loadingXdata.FrameInfo_Raw[nowFrameName].BoneInfs[bi].Indeces[vi];
-                                    var nowVal = this.loadingXdata.FrameInfo_Raw[nowFrameName].BoneInfs[bi].Weights[vi];
-                                    switch (this.loadingXdata.FrameInfo_Raw[nowFrameName].VertexSetedBoneCount[nowVertexID]) {
-                                        case 0:
-                                            this.loadingXdata.FrameInfo_Raw[nowFrameName].Geometry.skinIndices[nowVertexID].x = _m2;
-                                            this.loadingXdata.FrameInfo_Raw[nowFrameName].Geometry.skinWeights[nowVertexID].x = nowVal;
-                                            break;
-                                        case 1:
-                                            this.loadingXdata.FrameInfo_Raw[nowFrameName].Geometry.skinIndices[nowVertexID].y = _m2;
-                                            this.loadingXdata.FrameInfo_Raw[nowFrameName].Geometry.skinWeights[nowVertexID].y = nowVal;
-                                            break;
-                                        case 2:
-                                            this.loadingXdata.FrameInfo_Raw[nowFrameName].Geometry.skinIndices[nowVertexID].z = _m2;
-                                            this.loadingXdata.FrameInfo_Raw[nowFrameName].Geometry.skinWeights[nowVertexID].z = nowVal;
-                                            break;
-                                        case 3:
-                                            this.loadingXdata.FrameInfo_Raw[nowFrameName].Geometry.skinIndices[nowVertexID].w = _m2;
-                                            this.loadingXdata.FrameInfo_Raw[nowFrameName].Geometry.skinWeights[nowVertexID].w = nowVal;
-                                            break;
-                                    }
-                                    this.loadingXdata.FrameInfo_Raw[nowFrameName].VertexSetedBoneCount[nowVertexID]++;
-                                }
-                            }
-                        }
-                    }
-                    for (var sk = 0; sk < this.loadingXdata.FrameInfo_Raw[nowFrameName].Materials.length; sk++) {
-                        this.loadingXdata.FrameInfo_Raw[nowFrameName].Materials[sk].skinning = true;
-                    }
-                    mesh = new THREE.SkinnedMesh(bufferGeometry.fromGeometry(this.loadingXdata.FrameInfo_Raw[nowFrameName].Geometry), new THREE.MultiMaterial(this.loadingXdata.FrameInfo_Raw[nowFrameName].Materials));
-                    var skeleton = new THREE.Skeleton(putBones);
-                    mesh.add(putBones[0]);
-                    mesh.bind(skeleton);
-                } else {
-                    mesh = new THREE.Mesh(bufferGeometry.fromGeometry(this.loadingXdata.FrameInfo_Raw[nowFrameName].Geometry), new THREE.MultiMaterial(this.loadingXdata.FrameInfo_Raw[nowFrameName].Materials));
-                }
-                mesh.name = nowFrameName;
-                this.loadingXdata.FrameInfo_Raw[nowFrameName].Mesh = mesh;
-                this.loadingXdata.FrameInfo_Raw[nowFrameName].Geometry = null;
-            }
-        }
-    }, {
-        key: 'animationFinalize',
-        value: function animationFinalize() {
-            this.animeKeyNames = Object.keys(this.loadingXdata.AnimationSetInfo);
-            if (this.animeKeyNames != null && this.animeKeyNames.length > 0) {
-                this.nowReaded = 0;
-                this.loadingXdata.XAnimationObj = [];
-                this.animationFinalize_step();
-            } else {
-                this.finalproc();
-            }
-        }
-    }, {
-        key: 'animationFinalize_step',
-        value: function animationFinalize_step() {
-            var i = this.nowReaded;
-            var keys = Object.keys(this.loadingXdata.FrameInfo_Raw);
-            var tgtModel = null;
-            for (var m = 0; m < this.loadingXdata.FrameInfo.length; m++) {
-                var keys2 = Object.keys(this.loadingXdata.AnimationSetInfo[this.animeKeyNames[i]]);
-                if (this.loadingXdata.AnimationSetInfo[this.animeKeyNames[i]][keys2[0]].boneName == this.loadingXdata.FrameInfo[m].name) {
-                    tgtModel = this.loadingXdata.FrameInfo[m];
-                }
-            }
-            if (tgtModel != null) {
-                this.loadingXdata.XAnimationObj[i] = new XAnimationObj();
-                this.loadingXdata.XAnimationObj[i].fps = this.loadingXdata.AnimTicksPerSecond;
-                this.loadingXdata.XAnimationObj[i].name = this.animeKeyNames[i];
-                this.loadingXdata.XAnimationObj[i].make(this.loadingXdata.AnimationSetInfo[this.animeKeyNames[i]], tgtModel);
-            }
-            this.nowReaded++;
-            if (this.nowReaded >= this.animeKeyNames.length) {
-                this.loadingXdata.AnimationSetInfo = null;
-                this.finalproc();
-            } else {
-                this.animationFinalize_step();
-            }
-        }
-    }, {
-        key: 'finalproc',
-        value: function finalproc() {
-            var _this3 = this;
-
-            setTimeout(function () {
-                _this3.onLoad(_this3.loadingXdata);
-            }, 1);
-        }
-    }]);
-    return XLoader;
+
+	function XLoader( manager, Texloader, _zflg ) {
+
+		classCallCheck( this, XLoader );
+
+		this.manager = manager !== undefined ? manager : new THREE.DefaultLoadingManager();
+		this.Texloader = Texloader !== undefined ? Texloader : new THREE.TextureLoader();
+		this.zflg = _zflg === undefined ? false : _zflg;
+		this.url = "";
+		this.baseDir = "";
+		this.nowReadMode = XfileLoadMode$1.none;
+		this.nowAnimationKeyType = 4;
+		this.tgtLength = 0;
+		this.nowReaded = 0;
+		this.elementLv = 0;
+		this.geoStartLv = Number.MAX_VALUE;
+		this.frameStartLv = Number.MAX_VALUE;
+		this.matReadLine = 0;
+		this.putMatLength = 0;
+		this.nowMat = null;
+		this.BoneInf = new XboneInf();
+		this.tmpUvArray = [];
+		this.normalVectors = [];
+		this.facesNormal = [];
+		this.nowFrameName = "";
+		this.nowAnimationSetName = "";
+		this.frameHierarchie = [];
+		this.endLineCount = 0;
+		this.geometry = null;
+		this.loadingXdata = null;
+		this.lines = null;
+		this.keyInfo = null;
+		this.animeKeyNames = null;
+		this.data = null;
+		this.onLoad = null;
+
+	}
+
+	createClass( XLoader, [ {
+		key: 'load',
+		value: function load( _arg, onLoad, onProgress, onError ) {
+
+			var _this = this;
+
+			var loader = new THREE.FileLoader( this.manager );
+			loader.setResponseType( 'arraybuffer' );
+			for ( var i = 0; i < _arg.length; i ++ ) {
+
+				switch ( i ) {
+
+					case 0:
+						this.url = _arg[ i ]; break;
+					case 1:
+						this.zflg = _arg[ i ]; break;
+
+				}
+
+			}
+			loader.load( this.url, function ( response ) {
+
+				_this.parse( response, onLoad );
+
+			}, onProgress, onError );
+
+		}
+	}, {
+		key: 'isBinary',
+		value: function isBinary( binData ) {
+
+			var reader = new DataView( binData );
+			var face_size = 32 / 8 * 3 + 32 / 8 * 3 * 3 + 16 / 8;
+			var n_faces = reader.getUint32( 80, true );
+			var expect = 80 + 32 / 8 + n_faces * face_size;
+			if ( expect === reader.byteLength ) {
+
+				return true;
+
+			}
+			var fileLength = reader.byteLength;
+			for ( var index = 0; index < fileLength; index ++ ) {
+
+				if ( reader.getUint8( index, false ) > 127 ) {
+
+				return true;
+
+			}
+
+			}
+			return false;
+
+		}
+	}, {
+		key: 'ensureBinary',
+		value: function ensureBinary( buf ) {
+
+			if ( typeof buf === "string" ) {
+
+			var array_buffer = new Uint8Array( buf.length );
+			for ( var i = 0; i < buf.length; i ++ ) {
+
+				array_buffer[ i ] = buf.charCodeAt( i ) & 0xff;
+
+			}
+			return array_buffer.buffer || array_buffer;
+
+		} else {
+
+			return buf;
+
+		}
+
+		}
+	}, {
+		key: 'ensureString',
+		value: function ensureString( buf ) {
+
+		if ( typeof buf !== "string" ) {
+
+			var array_buffer = new Uint8Array( buf );
+			var str = '';
+			for ( var i = 0; i < buf.byteLength; i ++ ) {
+
+				str += String.fromCharCode( array_buffer[ i ] );
+
+			}
+			return str;
+
+		} else {
+
+			return buf;
+
+		}
+
+	}
+	}, {
+	key: 'parse',
+	value: function parse( data, onLoad ) {
+
+		var binData = this.ensureBinary( data );
+		this.data = this.ensureString( data );
+		this.onLoad = onLoad;
+		return this.isBinary( binData ) ? this.parseBinary( binData ) : this.parseASCII();
+
+	}
+}, {
+	key: 'parseBinary',
+	value: function parseBinary( data ) {
+
+		return parseASCII( String.fromCharCode.apply( null, data ) );
+
+	}
+}, {
+	key: 'parseASCII',
+	value: function parseASCII() {
+
+		var baseDir = "";
+		if ( this.url.lastIndexOf( "/" ) > 0 ) {
+
+			this.baseDir = this.url.substr( 0, this.url.lastIndexOf( "/" ) + 1 );
+
+		}
+		this.loadingXdata = new Xdata();
+		this.loadingXdata.vertexNormalFromFile = false;
+		this.loadingXdata.faceNormalFromFile = false;
+		this.lines = this.data;
+		this.readedLength = 0;
+		this.mainloop();
+
+	}
+}, {
+	key: 'mainloop',
+	value: function mainloop() {
+
+		var _this2 = this;
+
+		var EndFlg = false;
+		for ( var i = 0; i < 10; i ++ ) {
+
+			var forceBreak = this.SectionRead();
+			this .endLineCount++;
+			if ( this.readedLength >= this.data.length ) {
+
+				EndFlg = true;
+				this.readFinalize();
+				setTimeout( function () {
+
+					_this2.animationFinalize();
+
+				}, 1 );
+				break;
+
+			}
+			if ( forceBreak ) {
+
+				break;
+
+			}
+
+		}
+		if ( ! EndFlg ) {
+
+			setTimeout( function () {
+
+				_this2.mainloop();
+
+			}, 1 );
+
+		}
+
+	}
+}, {
+	key: 'getNextSection',
+	value: function getNextSection( _offset, _start, _end ) {
+
+		var find = this.data.indexOf( "{", _offset );
+		return [ this.data.substr( _offset, _start - _offset ).trim(), this.data.substr( _start + 1, _end - _start - 1 ) ];
+
+	}
+}, {
+	key: 'getNextSection2',
+	value: function getNextSection2( _obj, _offset, _start, _end ) {
+
+		var find = _obj.indexOf( "{", _offset );
+		return [ _obj.substr( _offset, _start - _offset ).trim(), _obj.substr( _start + 1, _end - _start - 1 ) ];
+
+	}
+}, {
+	key: 'readMeshSection',
+	value: function readMeshSection( _baseOffset ) {
+
+		this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].Geometry = new THREE.Geometry();
+		this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].Materials = [];
+		var find_2semi = this.data.indexOf( ";;", _baseOffset );
+		var offset = 0;
+		var v_data = this.getVertextDataSection( this.data.substr( _baseOffset, find_2semi - _baseOffset ), 0 );
+		for ( var i = 0; i < v_data[ 0 ].length; i ++ ) {
+
+			this.readVertex( v_data[ 0 ][ i ] );
+
+		}
+		offset = find_2semi + 2;
+		find_2semi = this.data.indexOf( ";;", offset );
+		var v_data2 = this.getVertextDataSection( this.data.substr( offset + 1, find_2semi - offset + 1 ), 0 );
+		for ( var _i = 0; _i < v_data2[ 0 ].length; _i ++ ) {
+
+			this.readVertexIndex( v_data2[ 0 ][ _i ] );
+
+		}
+		this.readedLength = offset + v_data2[ 1 ] + 1;
+
+	}
+}, {
+	key: 'getVertextDataSection',
+	value: function getVertextDataSection( _data, _offset ) {
+
+		var find = _data.indexOf( ";", _offset );
+		var find_2semi = _data.indexOf( ";;", _offset );
+		if ( find_2semi === - 1 ) {
+
+			find_2semi = _data.length - 1;
+
+		}
+		var v_data_base = _data.substr( find + 1, find_2semi - find + 2 );
+		return [ v_data_base.split( ";," ), find_2semi + 2 ];
+
+	}
+}, {
+	key: 'readVertexLines',
+	value: function readVertexLines( _data, find, find2, _readFunc ) {}
+}, {
+	key: 'readMeshMaterialSet',
+	value: function readMeshMaterialSet( _baseOffset ) {
+
+		var find = this.data.indexOf( ";", _baseOffset );
+		find = this.data.indexOf( ";", find + 2 );
+		find2 = this.data.indexOf( ";", find + 2 );
+		var _data = this.data.substr( find + 1, find2 - find + 1 );
+		var v_data = _data.split( "," );
+		for ( var i = 0; i < v_data.length; i ++ ) {
+
+			this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].Geometry.faces[ i ].materialIndex = parseInt( v_data[ i ], 10 );
+
+		}
+		this.readedLength = find2 + 1;
+
+	}
+}, {
+	key: 'readMaterial',
+	value: function readMaterial( _dataLine ) {
+
+		this.nowMat = new THREE.MeshPhongMaterial( { color: Math.random() * 0xffffff } );
+		if ( this.zflg ) {
+
+			this.nowMat.side = THREE.BackSide;
+
+		} else {
+
+			this.nowMat.side = THREE.FrontSide;
+
+		}
+		var find = _dataLine.indexOf( ";;" );
+		var _diff = _dataLine.substr( 0, find ).split( ";" );
+		this.nowMat.color.r = parseFloat( _diff[ 0 ] );
+		this.nowMat.color.g = parseFloat( _diff[ 1 ] );
+		this.nowMat.color.b = parseFloat( _diff[ 2 ] );
+		var find2 = _dataLine.indexOf( ";", find + 3 );
+		this.nowMat.shininess = parseFloat( _dataLine.substr( find + 2, find2 - find - 2 ) );
+		find = _dataLine.indexOf( ";;", find2 + 1 );
+		var _specular = _dataLine.substr( find2 + 1, find - find2 ).split( ";" );
+		this.nowMat.specular.r = parseFloat( _specular[ 0 ] );
+		this.nowMat.specular.g = parseFloat( _specular[ 1 ] );
+		this.nowMat.specular.b = parseFloat( _specular[ 2 ] );
+		find2 = _dataLine.indexOf( ";;", find + 2 );
+		var _emissive = _dataLine.substr( find + 2, find2 - find - 2 ).split( ";" );
+		this.nowMat.emissive.r = parseFloat( _emissive[ 0 ] );
+		this.nowMat.emissive.g = parseFloat( _emissive[ 1 ] );
+		this.nowMat.emissive.b = parseFloat( _emissive[ 2 ] );
+
+	}
+}, {
+	key: 'readSkinWeights',
+	value: function readSkinWeights( _data ) {
+
+		this.BoneInf = new XboneInf();
+		var find = _data.indexOf( ";" );
+		this.readBoneName( _data.substr( 0, find - 1 ).replace( '"', '' ) );
+		var find_1 = _data.indexOf( ";", find + 1 ) + 1;
+		var matrixStart = 0;
+		if ( parseInt( _data.substr( find, find_1 - find ), 10 ) === 0 ) {
+
+			matrixStart = find_1 + 1;
+
+		} else {
+
+			var _find = _data.indexOf( ";", find_1 + 1 );
+			var i_data = _data.substr( find_1, _find - find_1 ).split( "," );
+			for ( var i = 0; i < i_data.length; i ++ ) {
+
+				this.BoneInf.Indeces.push( parseInt( i_data[ i ], 10 ) );
+
+			}
+			var find3 = _data.indexOf( ";", _find + 1 );
+			var w_data = _data.substr( _find + 1, find3 - _find ).split( "," );
+			for ( var _i2 = 0; _i2 < w_data.length; _i2 ++ ) {
+
+				this.BoneInf.Weights.push( parseFloat( w_data[ _i2 ] ) );
+
+			}
+			matrixStart = find3 + 1;
+
+		}
+		var find4 = _data.indexOf( ";;", matrixStart + 1 );
+		var m_data = _data.substr( matrixStart, find4 - matrixStart ).split( "," );
+		this.BoneInf.initMatrix = new THREE.Matrix4();
+		this.ParseMatrixData( this.BoneInf.initMatrix, m_data );
+		this.BoneInf.OffsetMatrix = new THREE.Matrix4();
+		this.BoneInf.OffsetMatrix.getInverse( this.BoneInf.initMatrix );
+		this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].BoneInfs.push( this.BoneInf );
+
+	}
+}, {
+	key: 'getPlaneStr',
+	value: function getPlaneStr( _str ) {
+
+		var firstDbl = _str.indexOf( '"' ) + 1;
+		var dbl2 = _str.indexOf( '"', firstDbl );
+		return _str.substr( firstDbl, dbl2 - firstDbl );
+
+	}
+}, {
+	key: 'readAnimationKeyFrame',
+	value: function readAnimationKeyFrame( _data ) {
+
+		var find1 = _data.indexOf( ';' );
+		this.nowAnimationKeyType = parseInt( _data.substr( 0, find1 ), 10 );
+		var find2 = _data.indexOf( ';', find1 + 1 );
+		var lines = _data.substr( find2 + 1 ).split( ';;,' );
+		for ( var i = 0; i < lines.length; i ++ ) {
+
+			this.readAnimationKeyFrameValue( lines[ i ] );
+
+		}
+
+	}
+}, {
+	key: 'SectionRead',
+	value: function SectionRead() {
+
+		var find = this.data.indexOf( "{", this.readedLength );
+		if ( find === - 1 ) {
+
+			this.readedLength = this.data.length; return;
+
+		}
+		var lines = this.data.substr( this.readedLength, find - this.readedLength ).split( /\r\n|\r|\n/ );
+		var line = lines[ 0 ];
+		for ( var i = lines.length - 1; i >= 0; i -- ) {
+
+			if ( lines[ i ].trim().length > 0 && lines[ i ].indexOf( '//' ) < 0 ) {
+
+				line = lines[ i ];
+				break;
+
+			}
+
+		}
+		var find2 = this.data.indexOf( "{", find + 1 );
+		var find3 = this.data.indexOf( "}", find + 1 );
+		var find4 = this.data.indexOf( "}", this.readedLength );
+		if ( find4 < find ) {
+
+			if ( this.elementLv < 1 || this.nowFrameName === "" ) {
+
+				this.elementLv = 0;
+
+			} else {
+
+				this.endElement();
+
+			}
+			this.readedLength = find4 + 1;
+			return false;
+
+		}
+		if ( find3 > find2 ) {
+
+			this .elementLv++;
+			if ( line.indexOf( "Frame " ) > - 1 ) {
+
+				this.beginFrame( line );
+
+			} else if ( line.indexOf( "Mesh " ) > - 1 ) {
+
+				this.readMeshSection( find + 1 );
+				this.nowReadMode = XfileLoadMode$1.Mesh;
+				return true;
+
+			} else if ( line.indexOf( "MeshMaterialList " ) > - 1 ) {
+
+			this.readMeshMaterialSet( find + 1 );
+			this.nowReadMode = XfileLoadMode$1.Mat_Set;
+			return true;
+
+		} else if ( line.indexOf( "Material " ) > - 1 ) {
+
+		var nextSemic = this.data.indexOf( ";;", find + 1 );
+		nextSemic = this.data.indexOf( ";;", nextSemic + 1 );
+		nextSemic = this.data.indexOf( ";;", nextSemic + 1 );
+		this.readMaterial( this.data.substr( find + 1, nextSemic - find + 1 ) );
+		this.readedLength = nextSemic + 2;
+		this.nowReadMode = XfileLoadMode$1.Mat_detail;
+		return true;
+
+	} else if ( line.indexOf( "AnimationSet " ) > - 1 ) {
+
+	this.readandCreateAnimationSet( line );
+	this.nowReadMode = XfileLoadMode$1.Anim_init;
+	this.readedLength = find + 1;
+	return false;
+
+} else if ( line.indexOf( "Animation " ) > - 1 ) {
+
+	this.readAndCreateAnimation( line );
+	this.nowReadMode = XfileLoadMode$1.Anim_Reading;
+	var tgtBoneName = this.data.substr( find2 + 1, find3 - find2 - 1 ).trim();
+	this.loadingXdata.AnimationSetInfo[ this.nowAnimationSetName ][ this.nowFrameName ].boneName = tgtBoneName;
+	this.readedLength = find3 + 1;
+	return false;
+
+}
+			this.readedLength = find + 1;
+			return false;
+
+		} else {
+
+			var section = this.getNextSection( this.readedLength, find, find3 );
+			this.readedLength = find3 + 1;
+			if ( line.indexOf( "template " ) > - 1 ) {
+
+				this.elementLv = 0;
+				return false;
+
+			} else if ( line.indexOf( "AnimTicksPerSecond" ) > - 1 ) {
+
+				this.loadingXdata.AnimTicksPerSecond = parseInt( section[ 1 ].substr( 0, section[ 1 ].indexOf( ";" ) ), 10 );
+				this.elementLv = 0;
+				return false;
+
+			} else if ( line.indexOf( "FrameTransformMatrix" ) > - 1 ) {
+
+			var data = section[ 1 ].split( "," );
+			data[ 15 ] = data[ 15 ].substr( 0, data[ 15 ].indexOf( ';;' ) );
+			this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].FrameTransformMatrix = new THREE.Matrix4();
+			this.ParseMatrixData( this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].FrameTransformMatrix, data );
+			this.nowReadMode = XfileLoadMode$1.Element;
+			return false;
+
+		} else if ( line.indexOf( "MeshTextureCoords" ) > - 1 ) {
+
+		var v_data = this.getVertextDataSection( section[ 1 ], 0 );
+		for ( var _i3 = 0; _i3 < v_data[ 0 ].length; _i3 ++ ) {
+
+		this.readUv( v_data[ 0 ][ _i3 ] );
+
+	}
+		this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].Geometry.faceVertexUvs[ 0 ] = [];
+		for ( var m = 0; m < this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].Geometry.faces.length; m ++ ) {
+
+		this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].Geometry.faceVertexUvs[ 0 ][ m ] = [];
+		this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].Geometry.faceVertexUvs[ 0 ][ m ].push( this.tmpUvArray[ this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].Geometry.faces[ m ].a ] );
+		this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].Geometry.faceVertexUvs[ 0 ][ m ].push( this.tmpUvArray[ this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].Geometry.faces[ m ].b ] );
+		this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].Geometry.faceVertexUvs[ 0 ][ m ].push( this.tmpUvArray[ this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].Geometry.faces[ m ].c ] );
+
+	}
+		this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].Geometry.uvsNeedUpdate = true;
+		return true;
+
+	} else if ( line.indexOf( "Material " ) > - 1 ) {
+
+	this.readMaterial( section[ 1 ] );
+	this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].Materials.push( this.nowMat );
+	return false;
+
+} else if ( line.indexOf( "TextureFilename" ) > - 1 ) {
+
+	if ( section[ 1 ].length > 0 ) {
+
+		this.nowMat.map = this.Texloader.load( this.baseDir + this.getPlaneStr( section[ 1 ] ) );
+
+	}
+	return false;
+
+} else if ( line.indexOf( "BumpMapFilename" ) > - 1 ) {
+
+	if ( section[ 1 ].length > 0 ) {
+
+		this.nowMat.bumpMap = this.Texloader.load( this.baseDir + this.getPlaneStr( section[ 1 ] ) );
+		this.nowMat.bumpScale = 0.05;
+
+	}
+	return false;
+
+} else if ( line.indexOf( "NormalMapFilename" ) > - 1 ) {
+
+	if ( section[ 1 ].length > 0 ) {
+
+		this.nowMat.normalMap = this.Texloader.load( this.baseDir + this.getPlaneStr( section[ 1 ] ) );
+		this.nowMat.normalScale = new THREE.Vector2( 2, 2 );
+
+	}
+	return false;
+
+} else if ( line.indexOf( "EmissiveMapFilename" ) > - 1 ) {
+
+	if ( section[ 1 ].length > 0 ) {
+
+		this.nowMat.emissiveMap = this.Texloader.load( this.baseDir + this.getPlaneStr( section[ 1 ] ) );
+
+	}
+	return false;
+
+} else if ( line.indexOf( "LightMapFilename" ) > - 1 ) {
+
+	if ( section[ 1 ].length > 0 ) {
+
+		this.nowMat.lightMap = this.Texloader.load( this.baseDir + this.getPlaneStr( section[ 1 ] ) );
+
+	}
+	return false;
+
+} else if ( line.indexOf( "XSkinMeshHeader" ) > - 1 ) {
+
+	return false;
+
+} else if ( line.indexOf( "SkinWeights" ) > - 1 ) {
+
+	this.readSkinWeights( section[ 1 ] );
+	return true;
+
+} else if ( line.indexOf( "AnimationKey" ) > - 1 ) {
+
+	this.readAnimationKeyFrame( section[ 1 ] );
+	return true;
+
+}
+
+		}
+		return false;
+
+	}
+}, {
+	key: 'endElement',
+	value: function endElement( line ) {
+
+		if ( this.nowReadMode == XfileLoadMode$1.Mesh ) {
+
+			this.nowReadMode = XfileLoadMode$1.Element;
+
+		} else if ( this.nowReadMode == XfileLoadMode$1.Mat_Set ) {
+
+			this.nowReadMode = XfileLoadMode$1.Mesh;
+
+		} else if ( this.nowReadMode == XfileLoadMode$1.Mat_detail ) {
+
+			this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].Materials.push( this.nowMat );
+			this.nowReadMode = XfileLoadMode$1.Mat_Set;
+
+		} else if ( this.nowReadMode == XfileLoadMode$1.Anim_Reading ) {
+
+		this.nowReadMode = XfileLoadMode$1.Anim_init;
+
+	} else if ( this.nowReadMode < XfileLoadMode$1.Anim_init && this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].FrameStartLv === this.elementLv && this.nowReadMode > XfileLoadMode$1.none ) {
+
+	if ( this.frameHierarchie.length > 0 ) {
+
+		this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].children = [];
+		var keys = Object.keys( this.loadingXdata.FrameInfo_Raw );
+		for ( var m = 0; m < keys.length; m ++ ) {
+
+			if ( this.loadingXdata.FrameInfo_Raw[ keys[ m ] ].ParentName === this.nowFrameName ) {
+
+				this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].children.push( keys[ m ] );
+
+			}
+
+		}
+		this.frameHierarchie.pop();
+
+	}
+	this.MakeOutputGeometry( this.nowFrameName, this.zflg );
+	this.frameStartLv = this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].FrameStartLv;
+	if ( this.frameHierarchie.length > 0 ) {
+
+		this.nowFrameName = this.frameHierarchie[ this.frameHierarchie.length - 1 ];
+		this.frameStartLv = this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].FrameStartLv;
+
+	} else {
+
+		this.nowFrameName = "";
+
+	}
+
+} else if ( this.nowReadMode == XfileLoadMode$1.Anim_init ) {
+
+	this.nowReadMode = XfileLoadMode$1.Element;
+
+}
+		this .elementLv--;
+
+	}
+}, {
+	key: 'beginFrame',
+	value: function beginFrame( line ) {
+
+		this.frameStartLv = this.elementLv;
+		this.nowReadMode = XfileLoadMode$1.Element;
+		var findindex = line.indexOf( "Frame " );
+		this.nowFrameName = line.substr( findindex + 6, line.length - findindex + 1 ).trim();
+		this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ] = new XFrameInfo$1();
+		this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].FrameName = this.nowFrameName;
+		if ( this.frameHierarchie.length > 0 ) {
+
+			this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].ParentName = this.frameHierarchie[ this.frameHierarchie.length - 1 ];
+
+		}
+		this.frameHierarchie.push( this.nowFrameName );
+		this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].FrameStartLv = this.frameStartLv;
+
+	}
+}, {
+	key: 'beginReadMesh',
+	value: function beginReadMesh( line ) {
+
+		if ( this.nowFrameName === "" ) {
+
+			this.frameStartLv = this.elementLv;
+			this.nowFrameName = line.substr( 5, line.length - 6 );
+			if ( this.nowFrameName === "" ) {
+
+				this.nowFrameName = "mesh_" + this.loadingXdata.FrameInfo_Raw.length;
+
+			}
+			this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ] = new XFrameInfo$1();
+			this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].FrameName = this.nowFrameName;
+			this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].FrameStartLv = this.frameStartLv;
+
+		}
+		this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].Geometry = new THREE.Geometry();
+		this.geoStartLv = this.elementLv;
+		this.nowReadMode = XfileLoadMode$1.Vartex_init;
+		Bones = [];
+		this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].Materials = [];
+
+	}
+}, {
+	key: 'readVertexCount',
+	value: function readVertexCount( line ) {
+
+		this.nowReadMode = XfileLoadMode$1.Vartex_Read;
+		this.tgtLength = parseInt( line.substr( 0, line.length - 1 ), 10 );
+		this.nowReaded = 0;
+
+	}
+}, {
+	key: 'readVertex',
+	value: function readVertex( line ) {
+
+		var data = line.substr( 0, line.length - 2 ).split( ";" );
+		this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].Geometry.vertices.push( new THREE.Vector3( parseFloat( data[ 0 ] ), parseFloat( data[ 1 ] ), parseFloat( data[ 2 ] ) ) );
+		this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].Geometry.skinIndices.push( new THREE.Vector4( 0, 0, 0, 0 ) );
+		this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].Geometry.skinWeights.push( new THREE.Vector4( 1, 0, 0, 0 ) );
+		this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].VertexSetedBoneCount.push( 0 );
+		this .nowReaded++;
+		return false;
+
+	}
+}, {
+	key: 'readIndexLength',
+	value: function readIndexLength( line ) {
+
+		this.nowReadMode = XfileLoadMode$1.index_Read;
+		this.tgtLength = parseInt( line.substr( 0, line.length - 1 ), 10 );
+		this.nowReaded = 0;
+
+	}
+}, {
+	key: 'readVertexIndex',
+	value: function readVertexIndex( line ) {
+
+		var firstFind = line.indexOf( ';' ) + 1;
+		var data = line.substr( firstFind ).split( "," );
+		if ( this.zflg ) {
+
+			this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].Geometry.faces.push( new THREE.Face3( parseInt( data[ 2 ], 10 ), parseInt( data[ 1 ], 10 ), parseInt( data[ 0 ], 10 ), new THREE.Vector3( 1, 1, 1 ).normalize() ) );
+
+		} else {
+
+			this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].Geometry.faces.push( new THREE.Face3( parseInt( data[ 0 ], 10 ), parseInt( data[ 1 ], 10 ), parseInt( data[ 2 ], 10 ), new THREE.Vector3( 1, 1, 1 ).normalize() ) );
+
+		}
+		return false;
+
+	}
+}, {
+	key: 'beginMeshNormal',
+	value: function beginMeshNormal( line ) {
+
+		this.nowReadMode = XfileLoadMode$1.Normal_V_init;
+		this.normalVectors = [];
+		this.facesNormal = [];
+
+	}
+}, {
+	key: 'readMeshNormalCount',
+	value: function readMeshNormalCount( line ) {
+
+		this.nowReadMode = XfileLoadMode$1.Normal_V_Read;
+		this.tgtLength = parseInt( line.substr( 0, line.length - 1 ), 10 );
+		this.nowReaded = 0;
+
+	}
+}, {
+	key: 'readMeshNormalVertex',
+	value: function readMeshNormalVertex( line ) {
+
+		var data = line.split( ";" );
+		this.normalVectors.push( [ parseFloat( data[ 0 ] ), parseFloat( data[ 1 ] ), parseFloat( data[ 2 ] ) ] );
+		this .nowReaded++;
+		if ( this.nowReaded >= this.tgtLength ) {
+
+			this.nowReadMode = XfileLoadMode$1.Normal_I_init;
+			return true;
+
+		}
+		return false;
+
+	}
+}, {
+	key: 'readMeshNormalIndexCount',
+	value: function readMeshNormalIndexCount( line ) {
+
+		this.nowReadMode = XfileLoadMode$1.Normal_I_Read;
+		this.tgtLength = parseInt( line.substr( 0, line.length - 1 ), 10 );
+		this.nowReaded = 0;
+
+	}
+}, {
+	key: 'readMeshNormalIndex',
+	value: function readMeshNormalIndex( line ) {
+
+		var data = line.substr( 2, line.length - 4 ).split( "," );
+		var nowID = parseInt( data[ 0 ], 10 );
+		var v1 = new THREE.Vector3( this.normalVectors[ nowID ][ 0 ], this.normalVectors[ nowID ][ 1 ], this.normalVectors[ nowID ][ 2 ] );
+		nowID = parseInt( data[ 1 ], 10 );
+		var v2 = new THREE.Vector3( this.normalVectors[ nowID ][ 0 ], this.normalVectors[ nowID ][ 1 ], this.normalVectors[ nowID ][ 2 ] );
+		nowID = parseInt( data[ 2 ], 10 );
+		var v3 = new THREE.Vector3( this.normalVectors[ nowID ][ 0 ], this.normalVectors[ nowID ][ 1 ], this.normalVectors[ nowID ][ 2 ] );
+		if ( this.zflg ) {
+
+			this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].Geometry.faces[ this.nowReaded ].vertexNormals = [ v3, v2, v1 ];
+
+		} else {
+
+			this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].Geometry.faces[ this.nowReaded ].vertexNormals = [ v1, v2, v3 ];
+
+		}
+		this.facesNormal.push( v1.normalize() );
+		this .nowReaded++;
+		if ( this.nowReaded >= this.tgtLength ) {
+
+			this.nowReadMode = XfileLoadMode$1.Element;
+			return true;
+
+		}
+		return false;
+
+	}
+}, {
+	key: 'readUvInit',
+	value: function readUvInit( line ) {
+
+		this.nowReadMode = XfileLoadMode$1.Uv_Read;
+		this.tgtLength = parseInt( line.substr( 0, line.length - 1 ), 10 );
+		this.nowReaded = 0;
+		this.tmpUvArray = [];
+		this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].Geometry.faceVertexUvs[ 0 ] = [];
+
+	}
+}, {
+	key: 'readUv',
+	value: function readUv( line ) {
+
+		var data = line.split( ";" );
+		if ( THREE.XLoader.IsUvYReverse ) {
+
+			this.tmpUvArray.push( new THREE.Vector2( parseFloat( data[ 0 ] ), 1 - parseFloat( data[ 1 ] ) ) );
+
+		} else {
+
+			this.tmpUvArray.push( new THREE.Vector2( parseFloat( data[ 0 ] ), parseFloat( data[ 1 ] ) ) );
+
+		}
+		this .nowReaded++;
+		if ( this.nowReaded >= this.tgtLength ) {
+
+			return true;
+
+		}
+		return false;
+
+	}
+}, {
+	key: 'readMatrixSetLength',
+	value: function readMatrixSetLength( line ) {
+
+		this.nowReadMode = XfileLoadMode$1.Mat_Face_Set;
+		this.tgtLength = parseInt( line.substr( 0, line.length - 1 ), 10 );
+		this.nowReaded = 0;
+
+	}
+}, {
+	key: 'readMaterialBind',
+	value: function readMaterialBind( line ) {
+
+		var data = line.split( "," );
+		this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].Geometry.faces[ this.nowReaded ].materialIndex = parseInt( data[ 0 ] );
+		this .nowReaded++;
+		if ( this.nowReaded >= this.tgtLength ) {
+
+			this.nowReadMode = XfileLoadMode$1.Element;
+			return true;
+
+		}
+		return false;
+
+	}
+}, {
+	key: 'readMaterialInit',
+	value: function readMaterialInit( line ) {
+
+		this.nowReadMode = XfileLoadMode$1.Mat_Set;
+		this.matReadLine = 0;
+		this.nowMat = new THREE.MeshPhongMaterial( { color: Math.random() * 0xffffff } );
+		var matName = line.substr( 9, line.length - 10 );
+		if ( matName !== "" ) {
+
+			this.nowMat.name = matName;
+
+		}
+		if ( this.zflg ) {
+
+			this.nowMat.side = THREE.BackSide;
+
+		} else {
+
+			this.nowMat.side = THREE.FrontSide;
+
+		}
+		this.nowMat.side = THREE.FrontSide;
+
+	}
+}, {
+	key: 'readandSetMaterial',
+	value: function readandSetMaterial( line ) {
+
+		var data = line.split( ";" );
+		this .matReadLine++;
+		switch ( this.matReadLine ) {
+
+			case 1:
+				this.nowMat.color.r = data[ 0 ];
+				this.nowMat.color.g = data[ 1 ];
+				this.nowMat.color.b = data[ 2 ];
+				break;
+			case 2:
+				this.nowMat.shininess = data[ 0 ];
+				break;
+			case 3:
+				this.nowMat.specular.r = data[ 0 ];
+				this.nowMat.specular.g = data[ 1 ];
+				this.nowMat.specular.b = data[ 2 ];
+				break;
+			case 4:
+				this.nowMat.emissive.r = data[ 0 ];
+				this.nowMat.emissive.g = data[ 1 ];
+				this.nowMat.emissive.b = data[ 2 ];
+				break;
+
+		}
+		if ( line.indexOf( "TextureFilename" ) > - 1 ) {
+
+			this.nowReadMode = XfileLoadMode$1.Mat_Set_Texture;
+
+		} else if ( line.indexOf( "BumpMapFilename" ) > - 1 ) {
+
+			this.nowReadMode = XfileLoadMode$1.Mat_Set_BumpTex;
+			this.nowMat.bumpScale = 0.05;
+
+		} else if ( line.indexOf( "NormalMapFilename" ) > - 1 ) {
+
+			this.nowReadMode = XfileLoadMode$1.Mat_Set_NormalTex;
+			this.nowMat.normalScale = new THREE.Vector2( 2, 2 );
+
+		} else if ( line.indexOf( "EmissiveMapFilename" ) > - 1 ) {
+
+		this.nowReadMode = XfileLoadMode$1.Mat_Set_EmissiveTex;
+
+	} else if ( line.indexOf( "LightMapFilename" ) > - 1 ) {
+
+	this.nowReadMode = XfileLoadMode$1.Mat_Set_LightTex;
+
+}
+
+	}
+}, {
+	key: 'readandSetMaterialTexture',
+	value: function readandSetMaterialTexture( line ) {
+
+		var data = line.substr( 1, line.length - 3 );
+		if ( data != undefined && data.length > 0 ) {
+
+			switch ( this.nowReadMode ) {
+
+				case XfileLoadMode$1.Mat_Set_Texture:
+					this.nowMat.map = this.Texloader.load( this.baseDir + data );
+					break;
+				case XfileLoadMode$1.Mat_Set_BumpTex:
+					this.nowMat.bumpMap = this.Texloader.load( this.baseDir + data );
+					break;
+				case XfileLoadMode$1.Mat_Set_NormalTex:
+					this.nowMat.normalMap = this.Texloader.load( this.baseDir + data );
+					break;
+				case XfileLoadMode$1.Mat_Set_EmissiveTex:
+					this.nowMat.emissiveMap = this.Texloader.load( this.baseDir + data );
+					break;
+				case XfileLoadMode$1.Mat_Set_LightTex:
+					this.nowMat.lightMap = this.Texloader.load( this.baseDir + data );
+					break;
+				case XfileLoadMode$1.Mat_Set_EnvTex:
+					this.nowMat.envMap = this.Texloader.load( this.baseDir + data );
+					break;
+
+			}
+
+		}
+		this.nowReadMode = XfileLoadMode$1.Mat_Set;
+		this .endLineCount++;
+		this .elementLv--;
+
+	}
+}, {
+	key: 'readBoneInit',
+	value: function readBoneInit( line ) {
+
+		this.nowReadMode = XfileLoadMode$1.Weit_init;
+		this.BoneInf = new XboneInf();
+
+	}
+}, {
+	key: 'readBoneName',
+	value: function readBoneName( line ) {
+
+		this.BoneInf.boneName = line.trim();
+		this.BoneInf.BoneIndex = this.loadingXdata.FrameInfo_Raw[ this.nowFrameName ].BoneInfs.length;
+		this.nowReaded = 0;
+
+	}
+}, {
+	key: 'readBoneVertexLength',
+	value: function readBoneVertexLength( line ) {
+
+		this.nowReadMode = XfileLoadMode$1.Weit_Read_Index;
+		this.tgtLength = parseInt( line.substr( 0, line.length - 1 ), 10 );
+		this.nowReaded = 0;
+
+	}
+}, {
+	key: 'readandSetBoneVertex',
+	value: function readandSetBoneVertex( line ) {
+
+		this.BoneInf.Indeces.push( parseInt( line.substr( 0, line.length - 1 ), 10 ) );
+		this .nowReaded++;
+		if ( this.nowReaded >= this.tgtLength || line.indexOf( ";" ) > - 1 ) {
+
+			this.nowReadMode = XfileLoadMode$1.Weit_Read_Value;
+			this.nowReaded = 0;
+
+		}
+
+	}
+}, {
+	key: 'readandSetBoneWeightValue',
+	value: function readandSetBoneWeightValue( line ) {
+
+		var nowVal = parseFloat( line.substr( 0, line.length - 1 ) );
+		this.BoneInf.Weights.push( nowVal );
+		this .nowReaded++;
+		if ( this.nowReaded >= this.tgtLength || line.indexOf( ";" ) > - 1 ) {
+
+			this.nowReadMode = XfileLoadMode$1.Weit_Read_Matrx;
+
+		}
+
+	}
+}, {
+	key: 'readandCreateAnimationSet',
+	value: function readandCreateAnimationSet( line ) {
+
+		this.frameStartLv = this.elementLv;
+		this.nowReadMode = XfileLoadMode$1.Anim_init;
+		this.nowAnimationSetName = line.substr( 13, line.length - 14 ).trim();
+		this.loadingXdata.AnimationSetInfo[ this.nowAnimationSetName ] = [];
+
+	}
+}, {
+	key: 'readAndCreateAnimation',
+	value: function readAndCreateAnimation( line ) {
+
+		this.nowFrameName = line.substr( 10, line.length - 11 ).trim();
+		this.loadingXdata.AnimationSetInfo[ this.nowAnimationSetName ][ this.nowFrameName ] = new XAnimationInfo$1();
+		this.loadingXdata.AnimationSetInfo[ this.nowAnimationSetName ][ this.nowFrameName ].animeName = this.nowFrameName;
+		this.loadingXdata.AnimationSetInfo[ this.nowAnimationSetName ][ this.nowFrameName ].FrameStartLv = this.frameStartLv;
+
+	}
+}, {
+	key: 'readAnimationKeyFrameValue',
+	value: function readAnimationKeyFrameValue( line ) {
+
+		this.keyInfo = null;
+		var data = line.split( ";" );
+		if ( data == null || data.length < 3 ) {
+
+			return;
+
+		}
+		var nowKeyframe = parseInt( data[ 0 ], 10 );
+		var frameFound = false;
+		var tmpM = new THREE.Matrix4();
+		if ( this.nowAnimationKeyType != 4 ) {
+
+			for ( var mm = 0; mm < this.loadingXdata.AnimationSetInfo[ this.nowAnimationSetName ][ this.nowFrameName ].keyFrames.length; mm ++ ) {
+
+				if ( this.loadingXdata.AnimationSetInfo[ this.nowAnimationSetName ][ this.nowFrameName ].keyFrames[ mm ].Frame === nowKeyframe ) {
+
+					this.keyInfo = this.loadingXdata.AnimationSetInfo[ this.nowAnimationSetName ][ this.nowFrameName ].keyFrames[ mm ];
+					frameFound = true;
+					break;
+
+				}
+
+			}
+
+		}
+		if ( ! frameFound ) {
+
+			this.keyInfo = new XKeyFrameInfo();
+			this.keyInfo.matrix = new THREE.Matrix4();
+			this.keyInfo.Frame = nowKeyframe;
+
+		}
+		var data2 = data[ 2 ].split( "," );
+		switch ( this.nowAnimationKeyType ) {
+
+			case 0:
+				tmpM.makeRotationFromQuaternion( new THREE.Quaternion( parseFloat( data2[ 0 ] ), parseFloat( data2[ 1 ] ), parseFloat( data2[ 2 ] ), parseFloat( data2[ 3 ] ) ) );
+				this.keyInfo.matrix.multiply( tmpM );
+				break;
+			case 1:
+				tmpM.makeScale( parseFloat( data2[ 0 ] ), parseFloat( data2[ 1 ] ), parseFloat( data2[ 2 ] ) );
+				this.keyInfo.matrix.multiply( tmpM );
+				break;
+			case 2:
+				tmpM.makeTranslation( parseFloat( data2[ 0 ] ), parseFloat( data2[ 1 ] ), parseFloat( data2[ 2 ] ) );
+				this.keyInfo.matrix.multiply( tmpM );
+				break;
+			case 3:
+			case 4:
+				this.ParseMatrixData( this.keyInfo.matrix, data2 );
+				break;
+
+		}
+		if ( ! frameFound ) {
+
+			this.keyInfo.index = this.loadingXdata.AnimationSetInfo[ this.nowAnimationSetName ][ this.nowFrameName ].keyFrames.length;
+			this.keyInfo.time = /*1.0 / this.loadingXdata.AnimTicksPerSecond * */this.keyInfo.Frame;
+			this.loadingXdata.AnimationSetInfo[ this.nowAnimationSetName ][ this.nowFrameName ].keyFrames.push( this.keyInfo );
+
+		}
+
+	}
+}, {
+	key: 'readFinalize',
+	value: function readFinalize() {
+
+		this.loadingXdata.FrameInfo = [];
+		var keys = Object.keys( this.loadingXdata.FrameInfo_Raw );
+		for ( var i = 0; i < keys.length; i ++ ) {
+
+			if ( this.loadingXdata.FrameInfo_Raw[ keys[ i ] ].Mesh != null ) {
+
+				this.loadingXdata.FrameInfo.push( this.loadingXdata.FrameInfo_Raw[ keys[ i ] ].Mesh );
+
+			}
+
+		}
+		if ( this.loadingXdata.FrameInfo != null & this.loadingXdata.FrameInfo.length > 0 ) {
+
+			for ( var _i4 = 0; _i4 < this.loadingXdata.FrameInfo.length; _i4 ++ ) {
+
+				if ( this.loadingXdata.FrameInfo[ _i4 ].parent == null ) {
+
+					this.loadingXdata.FrameInfo[ _i4 ].zflag = this.zflg;
+					if ( this.zflg ) {
+
+					this.loadingXdata.FrameInfo[ _i4 ].scale.set( - 1, 1, 1 );
+
+				}
+
+				}
+
+			}
+
+		}
+
+	}
+}, {
+	key: 'ParseMatrixData',
+	value: function ParseMatrixData( targetMatrix, data ) {
+
+		targetMatrix.set( parseFloat( data[ 0 ] ), parseFloat( data[ 4 ] ), parseFloat( data[ 8 ] ), parseFloat( data[ 12 ] ), parseFloat( data[ 1 ] ), parseFloat( data[ 5 ] ), parseFloat( data[ 9 ] ), parseFloat( data[ 13 ] ), parseFloat( data[ 2 ] ), parseFloat( data[ 6 ] ), parseFloat( data[ 10 ] ), parseFloat( data[ 14 ] ), parseFloat( data[ 3 ] ), parseFloat( data[ 7 ] ), parseFloat( data[ 11 ] ), parseFloat( data[ 15 ] ) );
+
+	}
+}, {
+	key: 'MakeOutputGeometry',
+	value: function MakeOutputGeometry( nowFrameName, _zflg ) {
+
+		if ( this.loadingXdata.FrameInfo_Raw[ nowFrameName ].Geometry != null ) {
+
+			this.loadingXdata.FrameInfo_Raw[ nowFrameName ].Geometry.computeBoundingBox();
+			this.loadingXdata.FrameInfo_Raw[ nowFrameName ].Geometry.computeBoundingSphere();
+			if ( ! this.loadingXdata.faceNormalFromFile ) {
+
+				this.loadingXdata.FrameInfo_Raw[ nowFrameName ].Geometry.computeFaceNormals();
+
+			}
+			if ( ! this.loadingXdata.vertexNormalFromFile ) {
+
+				this.loadingXdata.FrameInfo_Raw[ nowFrameName ].Geometry.computeVertexNormals();
+
+			}
+			this.loadingXdata.FrameInfo_Raw[ nowFrameName ].Geometry.verticesNeedUpdate = true;
+			this.loadingXdata.FrameInfo_Raw[ nowFrameName ].Geometry.normalsNeedUpdate = true;
+			this.loadingXdata.FrameInfo_Raw[ nowFrameName ].Geometry.colorsNeedUpdate = true;
+			this.loadingXdata.FrameInfo_Raw[ nowFrameName ].Geometry.uvsNeedUpdate = true;
+			this.loadingXdata.FrameInfo_Raw[ nowFrameName ].Geometry.groupsNeedUpdate = true;
+			var putBones = [];
+			var BoneInverse = [];
+			var BoneDics = [];
+			var rootBone = new THREE.Bone();
+			if ( this.loadingXdata.FrameInfo_Raw[ nowFrameName ].BoneInfs != null && this.loadingXdata.FrameInfo_Raw[ nowFrameName ].BoneInfs.length ) {
+
+				var keys = Object.keys( this.loadingXdata.FrameInfo_Raw );
+				var BoneDics_Name = [];
+				for ( var m = 0; m < keys.length; m ++ ) {
+
+					if ( this.loadingXdata.FrameInfo_Raw[ keys[ m ] ].FrameStartLv <= this.loadingXdata.FrameInfo_Raw[ nowFrameName ].FrameStartLv && nowFrameName != keys[ m ] ) {
+
+					continue;
+
+				}
+					var b = new THREE.Bone();
+					b.name = keys[ m ];
+					b.applyMatrix( this.loadingXdata.FrameInfo_Raw[ keys[ m ] ].FrameTransformMatrix );
+					BoneDics_Name[ b.name ] = putBones.length;
+					putBones.push( b );
+					var ivm = new THREE.Matrix4();
+					ivm.getInverse( this.loadingXdata.FrameInfo_Raw[ keys[ m ] ].FrameTransformMatrix );
+					BoneInverse.push( ivm );
+
+				}
+				for ( var _m = 0; _m < putBones.length; _m ++ ) {
+
+					for ( var dx = 0; dx < this.loadingXdata.FrameInfo_Raw[ putBones[ _m ].name ].children.length; dx ++ ) {
+
+					var nowBoneIndex = BoneDics_Name[ this.loadingXdata.FrameInfo_Raw[ putBones[ _m ].name ].children[ dx ] ];
+					if ( putBones[ nowBoneIndex ] != null ) {
+
+					putBones[ _m ].add( putBones[ nowBoneIndex ] );
+
+				}
+
+				}
+
+				}
+
+			}
+			var mesh = null;
+			var bufferGeometry = new THREE.BufferGeometry();
+			if ( putBones.length > 0 ) {
+
+				if ( this.loadingXdata.FrameInfo_Raw[ putBones[ 0 ].name ].children.length === 0 && nowFrameName != putBones[ 0 ].name ) {
+
+					putBones[ 0 ].add( putBones[ 1 ] );
+					putBones[ 0 ].zflag = _zflg;
+
+				}
+				for ( var _m2 = 0; _m2 < putBones.length; _m2 ++ ) {
+
+					if ( putBones[ _m2 ].parent === null ) {
+
+					putBones[ _m2 ].zflag = _zflg;
+
+				}
+					for ( var bi = 0; bi < this.loadingXdata.FrameInfo_Raw[ nowFrameName ].BoneInfs.length; bi ++ ) {
+
+					if ( putBones[ _m2 ].name === this.loadingXdata.FrameInfo_Raw[ nowFrameName ].BoneInfs[ bi ].boneName ) {
+
+					for ( var vi = 0; vi < this.loadingXdata.FrameInfo_Raw[ nowFrameName ].BoneInfs[ bi ].Indeces.length; vi ++ ) {
+
+					var nowVertexID = this.loadingXdata.FrameInfo_Raw[ nowFrameName ].BoneInfs[ bi ].Indeces[ vi ];
+					var nowVal = this.loadingXdata.FrameInfo_Raw[ nowFrameName ].BoneInfs[ bi ].Weights[ vi ];
+					switch ( this.loadingXdata.FrameInfo_Raw[ nowFrameName ].VertexSetedBoneCount[ nowVertexID ] ) {
+
+					case 0:
+						this.loadingXdata.FrameInfo_Raw[ nowFrameName ].Geometry.skinIndices[ nowVertexID ].x = _m2;
+						this.loadingXdata.FrameInfo_Raw[ nowFrameName ].Geometry.skinWeights[ nowVertexID ].x = nowVal;
+						break;
+					case 1:
+						this.loadingXdata.FrameInfo_Raw[ nowFrameName ].Geometry.skinIndices[ nowVertexID ].y = _m2;
+						this.loadingXdata.FrameInfo_Raw[ nowFrameName ].Geometry.skinWeights[ nowVertexID ].y = nowVal;
+						break;
+					case 2:
+						this.loadingXdata.FrameInfo_Raw[ nowFrameName ].Geometry.skinIndices[ nowVertexID ].z = _m2;
+						this.loadingXdata.FrameInfo_Raw[ nowFrameName ].Geometry.skinWeights[ nowVertexID ].z = nowVal;
+						break;
+					case 3:
+						this.loadingXdata.FrameInfo_Raw[ nowFrameName ].Geometry.skinIndices[ nowVertexID ].w = _m2;
+						this.loadingXdata.FrameInfo_Raw[ nowFrameName ].Geometry.skinWeights[ nowVertexID ].w = nowVal;
+						break;
+
+				}
+					this .loadingXdata.FrameInfo_Raw[ nowFrameName ].VertexSetedBoneCount[ nowVertexID ]++;
+
+				}
+					break;
+
+				}
+
+				}
+
+				}
+				for ( var sk = 0; sk < this.loadingXdata.FrameInfo_Raw[ nowFrameName ].Materials.length; sk ++ ) {
+
+					this.loadingXdata.FrameInfo_Raw[ nowFrameName ].Materials[ sk ].skinning = true;
+
+				}
+				mesh = new THREE.SkinnedMesh( bufferGeometry.fromGeometry( this.loadingXdata.FrameInfo_Raw[ nowFrameName ].Geometry ), new THREE.MultiMaterial( this.loadingXdata.FrameInfo_Raw[ nowFrameName ].Materials ) );
+				var skeleton = new THREE.Skeleton( putBones /*, BoneInverse*/ );
+				mesh.add( putBones[ 0 ] );
+				mesh.bind( skeleton );
+
+			} else {
+
+				mesh = new THREE.Mesh( bufferGeometry.fromGeometry( this.loadingXdata.FrameInfo_Raw[ nowFrameName ].Geometry ), new THREE.MultiMaterial( this.loadingXdata.FrameInfo_Raw[ nowFrameName ].Materials ) );
+
+			}
+			mesh.name = nowFrameName;
+			this.loadingXdata.FrameInfo_Raw[ nowFrameName ].Mesh = mesh;
+			this.loadingXdata.FrameInfo_Raw[ nowFrameName ].Geometry = null;
+
+		}
+
+	}
+}, {
+	key: 'animationFinalize',
+	value: function animationFinalize() {
+
+		this.animeKeyNames = Object.keys( this.loadingXdata.AnimationSetInfo );
+		if ( this.animeKeyNames != null && this.animeKeyNames.length > 0 ) {
+
+			this.nowReaded = 0;
+			this.loadingXdata.XAnimationObj = [];
+			this.animationFinalize_step();
+
+		} else {
+
+			this.finalproc();
+
+		}
+
+	}
+}, {
+	key: 'animationFinalize_step',
+	value: function animationFinalize_step() {
+
+		var i = this.nowReaded;
+		var keys = Object.keys( this.loadingXdata.FrameInfo_Raw );
+		var tgtModel = null;
+		for ( var m = 0; m < this.loadingXdata.FrameInfo.length; m ++ ) {
+
+			var keys2 = Object.keys( this.loadingXdata.AnimationSetInfo[ this.animeKeyNames[ i ] ] );
+			if ( this.loadingXdata.AnimationSetInfo[ this.animeKeyNames[ i ] ][ keys2[ 0 ] ].boneName == this.loadingXdata.FrameInfo[ m ].name ) {
+
+				tgtModel = this.loadingXdata.FrameInfo[ m ];
+				break;
+
+			}
+
+		}
+		if ( tgtModel != null ) {
+
+			this.loadingXdata.XAnimationObj[ i ] = new XAnimationObj();
+			this.loadingXdata.XAnimationObj[ i ].fps = this.loadingXdata.AnimTicksPerSecond;
+			this.loadingXdata.XAnimationObj[ i ].name = this.animeKeyNames[ i ];
+			this.loadingXdata.XAnimationObj[ i ].make( this.loadingXdata.AnimationSetInfo[ this.animeKeyNames[ i ] ], tgtModel );
+
+		}
+		this .nowReaded++;
+		if ( this.nowReaded >= this.animeKeyNames.length ) {
+
+			this.loadingXdata.AnimationSetInfo = null;
+			this.finalproc();
+
+		} else {
+
+			this.animationFinalize_step();
+
+		}
+
+	}
+}, {
+	key: 'finalproc',
+	value: function finalproc() {
+
+		var _this3 = this;
+
+		setTimeout( function () {
+
+			_this3.onLoad( _this3.loadingXdata );
+
+		}, 1 );
+
+	}
+} ] );
+	return XLoader;
+
 }();
 
 

+ 0 - 1132
examples/js/loaders/deprecated/SceneLoader.js

@@ -1,1132 +0,0 @@
-/**
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.SceneLoader = function ( manager ) {
-
-	this.onLoadStart = function () {};
-	this.onLoadProgress = function() {};
-	this.onLoadComplete = function () {};
-
-	this.callbackSync = function () {};
-	this.callbackProgress = function () {};
-
-	this.geometryHandlers = {};
-	this.hierarchyHandlers = {};
-
-	this.addGeometryHandler( "ascii", THREE.JSONLoader );
-
-	this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
-
-};
-
-THREE.SceneLoader.prototype = {
-
-	constructor: THREE.SceneLoader,
-
-	load: function ( url, onLoad, onProgress, onError ) {
-
-		var scope = this;
-
-		var loader = new THREE.FileLoader( scope.manager );
-		loader.load( url, function ( text ) {
-
-			scope.parse( JSON.parse( text ), onLoad, url );
-
-		}, onProgress, onError );
-
-	},
-
-	addGeometryHandler: function ( typeID, loaderClass ) {
-
-		this.geometryHandlers[ typeID ] = { "loaderClass": loaderClass };
-
-	},
-
-	addHierarchyHandler: function ( typeID, loaderClass ) {
-
-		this.hierarchyHandlers[ typeID ] = { "loaderClass": loaderClass };
-
-	},
-
-	parse: function ( json, callbackFinished, url ) {
-
-		var scope = this;
-
-		var urlBase = THREE.Loader.prototype.extractUrlBase( url );
-
-		var geometry, material, camera, fog,
-			texture, images, color,
-			light, hex, intensity,
-			counter_models, counter_textures,
-			total_models, total_textures,
-			result;
-
-		var target_array = [];
-
-		var data = json;
-
-		// async geometry loaders
-
-		for ( var typeID in this.geometryHandlers ) {
-
-			var loaderClass = this.geometryHandlers[ typeID ][ "loaderClass" ];
-			this.geometryHandlers[ typeID ][ "loaderObject" ] = new loaderClass();
-
-		}
-
-		// async hierachy loaders
-
-		for ( var typeID in this.hierarchyHandlers ) {
-
-			var loaderClass = this.hierarchyHandlers[ typeID ][ "loaderClass" ];
-			this.hierarchyHandlers[ typeID ][ "loaderObject" ] = new loaderClass();
-
-		}
-
-		counter_models = 0;
-		counter_textures = 0;
-
-		result = {
-
-			scene: new THREE.Scene(),
-			geometries: {},
-			face_materials: {},
-			materials: {},
-			textures: {},
-			objects: {},
-			cameras: {},
-			lights: {},
-			fogs: {},
-			empties: {},
-			groups: {}
-
-		};
-
-		if ( data.transform ) {
-
-			var position = data.transform.position,
-				rotation = data.transform.rotation,
-				scale = data.transform.scale;
-
-			if ( position ) {
-
-				result.scene.position.fromArray( position );
-
-			}
-
-			if ( rotation ) {
-
-				result.scene.rotation.fromArray( rotation );
-
-			}
-
-			if ( scale ) {
-
-				result.scene.scale.fromArray( scale );
-
-			}
-
-			if ( position || rotation || scale ) {
-
-				result.scene.updateMatrix();
-				result.scene.updateMatrixWorld();
-
-			}
-
-		}
-
-		function get_url( source_url, url_type ) {
-
-			if ( url_type == "relativeToHTML" ) {
-
-				return source_url;
-
-			} else {
-
-				return urlBase + source_url;
-
-			}
-
-		}
-
-		// toplevel loader function, delegates to handle_children
-
-		function handle_objects() {
-
-			handle_children( result.scene, data.objects );
-
-		}
-
-		// handle all the children from the loaded json and attach them to given parent
-
-		function handle_children( parent, children ) {
-
-			var mat, dst, pos, rot, scl, quat;
-
-			for ( var objID in children ) {
-
-				// check by id if child has already been handled,
-				// if not, create new object
-
-				var object = result.objects[ objID ];
-				var objJSON = children[ objID ];
-
-				if ( object === undefined ) {
-
-					// meshes
-
-					if ( objJSON.type && ( objJSON.type in scope.hierarchyHandlers ) ) {
-
-						if ( objJSON.loading === undefined ) {
-
-							material = result.materials[ objJSON.material ];
-
-							objJSON.loading = true;
-
-							var loader = scope.hierarchyHandlers[ objJSON.type ][ "loaderObject" ];
-
-							// ColladaLoader
-
-							if ( loader.options ) {
-
-								loader.load( get_url( objJSON.url, data.urlBaseType ), create_callback_hierachy( objID, parent, material, objJSON ) );
-
-							// UTF8Loader
-							// OBJLoader
-
-							} else {
-
-								loader.load( get_url( objJSON.url, data.urlBaseType ), create_callback_hierachy( objID, parent, material, objJSON ) );
-
-							}
-
-						}
-
-					} else if ( objJSON.geometry !== undefined ) {
-
-						geometry = result.geometries[ objJSON.geometry ];
-
-						// geometry already loaded
-
-						if ( geometry ) {
-
-							material = result.materials[ objJSON.material ];
-
-							pos = objJSON.position;
-							rot = objJSON.rotation;
-							scl = objJSON.scale;
-							mat = objJSON.matrix;
-							quat = objJSON.quaternion;
-
-							// use materials from the model file
-							// if there is no material specified in the object
-
-							if ( ! objJSON.material ) {
-
-								material = new THREE.MultiMaterial( result.face_materials[ objJSON.geometry ] );
-
-							}
-
-							// use materials from the model file
-							// if there is just empty face material
-							// (must create new material as each model has its own face material)
-
-							if ( ( material instanceof THREE.MultiMaterial ) && material.materials.length === 0 ) {
-
-								material = new THREE.MultiMaterial( result.face_materials[ objJSON.geometry ] );
-
-							}
-
-							if ( objJSON.skin ) {
-
-								object = new THREE.SkinnedMesh( geometry, material );
-
-							} else if ( objJSON.morph ) {
-
-								object = new THREE.MorphAnimMesh( geometry, material );
-
-								if ( objJSON.duration !== undefined ) {
-
-									object.duration = objJSON.duration;
-
-								}
-
-								if ( objJSON.time !== undefined ) {
-
-									object.time = objJSON.time;
-
-								}
-
-								if ( objJSON.mirroredLoop !== undefined ) {
-
-									object.mirroredLoop = objJSON.mirroredLoop;
-
-								}
-
-								if ( material.morphNormals ) {
-
-									geometry.computeMorphNormals();
-
-								}
-
-							} else {
-
-								object = new THREE.Mesh( geometry, material );
-
-							}
-
-							object.name = objID;
-
-							if ( mat ) {
-
-								object.matrixAutoUpdate = false;
-								object.matrix.set(
-									mat[ 0 ],  mat[ 1 ],  mat[ 2 ],  mat[ 3 ],
-									mat[ 4 ],  mat[ 5 ],  mat[ 6 ],  mat[ 7 ],
-									mat[ 8 ],  mat[ 9 ],  mat[ 10 ], mat[ 11 ],
-									mat[ 12 ], mat[ 13 ], mat[ 14 ], mat[ 15 ]
-								);
-
-							} else {
-
-								object.position.fromArray( pos );
-
-								if ( quat ) {
-
-									object.quaternion.fromArray( quat );
-
-								} else {
-
-									object.rotation.fromArray( rot );
-
-								}
-
-								object.scale.fromArray( scl );
-
-							}
-
-							object.visible = objJSON.visible;
-							object.castShadow = objJSON.castShadow;
-							object.receiveShadow = objJSON.receiveShadow;
-
-							parent.add( object );
-
-							result.objects[ objID ] = object;
-
-						}
-
-					// lights
-
-					} else if ( objJSON.type === "AmbientLight" || objJSON.type === "PointLight" ||
-						objJSON.type === "DirectionalLight" || objJSON.type === "SpotLight" ||
-						objJSON.type === "HemisphereLight" ) {
-
-						var color = objJSON.color;
-						var intensity = objJSON.intensity;
-						var distance = objJSON.distance;
-						var position = objJSON.position;
-						var rotation = objJSON.rotation;
-
-						switch ( objJSON.type ) {
-
-							case 'AmbientLight':
-								light = new THREE.AmbientLight( color );
-								break;
-
-							case 'PointLight':
-								light = new THREE.PointLight( color, intensity, distance );
-								light.position.fromArray( position );
-								break;
-
-							case 'DirectionalLight':
-								light = new THREE.DirectionalLight( color, intensity );
-								light.position.fromArray( objJSON.direction );
-								break;
-
-							case 'SpotLight':
-								light = new THREE.SpotLight( color, intensity, distance );
-								light.angle = objJSON.angle;
-								light.position.fromArray( position );
-								light.target.set( position[ 0 ], position[ 1 ] - distance, position[ 2 ] );
-								light.target.applyEuler( new THREE.Euler( rotation[ 0 ], rotation[ 1 ], rotation[ 2 ], 'XYZ' ) );
-								break;
-
-							case 'HemisphereLight':
-								light = new THREE.DirectionalLight( color, intensity, distance );
-								light.target.set( position[ 0 ], position[ 1 ] - distance, position[ 2 ] );
-								light.target.applyEuler( new THREE.Euler( rotation[ 0 ], rotation[ 1 ], rotation[ 2 ], 'XYZ' ) );
-								break;
-
-						}
-
-						parent.add( light );
-
-						light.name = objID;
-						result.lights[ objID ] = light;
-						result.objects[ objID ] = light;
-
-					// cameras
-
-					} else if ( objJSON.type === "PerspectiveCamera" || objJSON.type === "OrthographicCamera" ) {
-
-						pos = objJSON.position;
-						rot = objJSON.rotation;
-						quat = objJSON.quaternion;
-
-						if ( objJSON.type === "PerspectiveCamera" ) {
-
-							camera = new THREE.PerspectiveCamera( objJSON.fov, objJSON.aspect, objJSON.near, objJSON.far );
-
-						} else if ( objJSON.type === "OrthographicCamera" ) {
-
-							camera = new THREE.OrthographicCamera( objJSON.left, objJSON.right, objJSON.top, objJSON.bottom, objJSON.near, objJSON.far );
-
-						}
-
-						camera.name = objID;
-						camera.position.fromArray( pos );
-
-						if ( quat !== undefined ) {
-
-							camera.quaternion.fromArray( quat );
-
-						} else if ( rot !== undefined ) {
-
-							camera.rotation.fromArray( rot );
-
-						} else if ( objJSON.target ) {
-
-							camera.lookAt( new THREE.Vector3().fromArray( objJSON.target ) );
-
-						}
-
-						parent.add( camera );
-
-						result.cameras[ objID ] = camera;
-						result.objects[ objID ] = camera;
-
-					// pure Object3D
-
-					} else {
-
-						pos = objJSON.position;
-						rot = objJSON.rotation;
-						scl = objJSON.scale;
-						quat = objJSON.quaternion;
-
-						object = new THREE.Object3D();
-						object.name = objID;
-						object.position.fromArray( pos );
-
-						if ( quat ) {
-
-							object.quaternion.fromArray( quat );
-
-						} else {
-
-							object.rotation.fromArray( rot );
-
-						}
-
-						object.scale.fromArray( scl );
-						object.visible = ( objJSON.visible !== undefined ) ? objJSON.visible : false;
-
-						parent.add( object );
-
-						result.objects[ objID ] = object;
-						result.empties[ objID ] = object;
-
-					}
-
-					if ( object ) {
-
-						if ( objJSON.userData !== undefined ) {
-
-							for ( var key in objJSON.userData ) {
-
-								var value = objJSON.userData[ key ];
-								object.userData[ key ] = value;
-
-							}
-
-						}
-
-						if ( objJSON.groups !== undefined ) {
-
-							for ( var i = 0; i < objJSON.groups.length; i ++ ) {
-
-								var groupID = objJSON.groups[ i ];
-
-								if ( result.groups[ groupID ] === undefined ) {
-
-									result.groups[ groupID ] = [];
-
-								}
-
-								result.groups[ groupID ].push( objID );
-
-							}
-
-						}
-
-					}
-
-				}
-
-				if ( object !== undefined && objJSON.children !== undefined ) {
-
-					handle_children( object, objJSON.children );
-
-				}
-
-			}
-
-		}
-
-		function handle_mesh( geo, mat, id ) {
-
-			result.geometries[ id ] = geo;
-			result.face_materials[ id ] = mat;
-			handle_objects();
-
-		}
-
-		function handle_hierarchy( node, id, parent, material, obj ) {
-
-			var p = obj.position;
-			var r = obj.rotation;
-			var q = obj.quaternion;
-			var s = obj.scale;
-
-			node.position.fromArray( p );
-
-			if ( q ) {
-
-				node.quaternion.fromArray( q );
-
-			} else {
-
-				node.rotation.fromArray( r );
-
-			}
-
-			node.scale.fromArray( s );
-
-			// override children materials
-			// if object material was specified in JSON explicitly
-
-			if ( material ) {
-
-				node.traverse( function ( child ) {
-
-					child.material = material;
-
-				} );
-
-			}
-
-			// override children visibility
-			// with root node visibility as specified in JSON
-
-			var visible = ( obj.visible !== undefined ) ? obj.visible : true;
-
-			node.traverse( function ( child ) {
-
-				child.visible = visible;
-
-			} );
-
-			parent.add( node );
-
-			node.name = id;
-
-			result.objects[ id ] = node;
-			handle_objects();
-
-		}
-
-		function create_callback_geometry( id ) {
-
-			return function ( geo, mat ) {
-
-				geo.name = id;
-
-				handle_mesh( geo, mat, id );
-
-				counter_models -= 1;
-
-				scope.onLoadComplete();
-
-				async_callback_gate();
-
-			}
-
-		}
-
-		function create_callback_hierachy( id, parent, material, obj ) {
-
-			return function ( event ) {
-
-				var result;
-
-				// loaders which use EventDispatcher
-
-				if ( event.content ) {
-
-					result = event.content;
-
-				// ColladaLoader
-
-				} else if ( event.dae ) {
-
-					result = event.scene;
-
-
-				// UTF8Loader
-
-				} else {
-
-					result = event;
-
-				}
-
-				handle_hierarchy( result, id, parent, material, obj );
-
-				counter_models -= 1;
-
-				scope.onLoadComplete();
-
-				async_callback_gate();
-
-			}
-
-		}
-
-		function create_callback_embed( id ) {
-
-			return function ( geo, mat ) {
-
-				geo.name = id;
-
-				result.geometries[ id ] = geo;
-				result.face_materials[ id ] = mat;
-
-			}
-
-		}
-
-		function async_callback_gate() {
-
-			var progress = {
-
-				totalModels : total_models,
-				totalTextures : total_textures,
-				loadedModels : total_models - counter_models,
-				loadedTextures : total_textures - counter_textures
-
-			};
-
-			scope.callbackProgress( progress, result );
-
-			scope.onLoadProgress();
-
-			if ( counter_models === 0 && counter_textures === 0 ) {
-
-				finalize();
-				callbackFinished( result );
-
-			}
-
-		}
-
-		function finalize() {
-
-			// take care of targets which could be asynchronously loaded objects
-
-			for ( var i = 0; i < target_array.length; i ++ ) {
-
-				var ta = target_array[ i ];
-
-				var target = result.objects[ ta.targetName ];
-
-				if ( target ) {
-
-					ta.object.target = target;
-
-				} else {
-
-					// if there was error and target of specified name doesn't exist in the scene file
-					// create instead dummy target
-					// (target must be added to scene explicitly as parent is already added)
-
-					ta.object.target = new THREE.Object3D();
-					result.scene.add( ta.object.target );
-
-				}
-
-				ta.object.target.userData.targetInverse = ta.object;
-
-			}
-
-		}
-
-		var callbackTexture = function ( count ) {
-
-			counter_textures -= count;
-			async_callback_gate();
-
-			scope.onLoadComplete();
-
-		};
-
-		// must use this instead of just directly calling callbackTexture
-		// because of closure in the calling context loop
-
-		var generateTextureCallback = function ( count ) {
-
-			return function () {
-
-				callbackTexture( count );
-
-			};
-
-		};
-
-		function traverse_json_hierarchy( objJSON, callback ) {
-
-			callback( objJSON );
-
-			if ( objJSON.children !== undefined ) {
-
-				for ( var objChildID in objJSON.children ) {
-
-					traverse_json_hierarchy( objJSON.children[ objChildID ], callback );
-
-				}
-
-			}
-
-		}
-
-		// first go synchronous elements
-
-		// fogs
-
-		var fogID, fogJSON;
-
-		for ( fogID in data.fogs ) {
-
-			fogJSON = data.fogs[ fogID ];
-
-			if ( fogJSON.type === "linear" ) {
-
-				fog = new THREE.Fog( 0x000000, fogJSON.near, fogJSON.far );
-
-			} else if ( fogJSON.type === "exp2" ) {
-
-				fog = new THREE.FogExp2( 0x000000, fogJSON.density );
-
-			}
-
-			color = fogJSON.color;
-			fog.color.setRGB( color[ 0 ], color[ 1 ], color[ 2 ] );
-
-			result.fogs[ fogID ] = fog;
-
-		}
-
-		// now come potentially asynchronous elements
-
-		// geometries
-
-		// count how many geometries will be loaded asynchronously
-
-		var geoID, geoJSON;
-
-		for ( geoID in data.geometries ) {
-
-			geoJSON = data.geometries[ geoID ];
-
-			if ( geoJSON.type in this.geometryHandlers ) {
-
-				counter_models += 1;
-
-				scope.onLoadStart();
-
-			}
-
-		}
-
-		// count how many hierarchies will be loaded asynchronously
-
-		for ( var objID in data.objects ) {
-
-			traverse_json_hierarchy( data.objects[ objID ], function ( objJSON ) {
-
-				if ( objJSON.type && ( objJSON.type in scope.hierarchyHandlers ) ) {
-
-					counter_models += 1;
-
-					scope.onLoadStart();
-
-				}
-
-			} );
-
-		}
-
-		total_models = counter_models;
-
-		for ( geoID in data.geometries ) {
-
-			geoJSON = data.geometries[ geoID ];
-
-			if ( geoJSON.type === "cube" ) {
-
-				geometry = new THREE.BoxGeometry( geoJSON.width, geoJSON.height, geoJSON.depth, geoJSON.widthSegments, geoJSON.heightSegments, geoJSON.depthSegments );
-				geometry.name = geoID;
-				result.geometries[ geoID ] = geometry;
-
-			} else if ( geoJSON.type === "plane" ) {
-
-				geometry = new THREE.PlaneGeometry( geoJSON.width, geoJSON.height, geoJSON.widthSegments, geoJSON.heightSegments );
-				geometry.name = geoID;
-				result.geometries[ geoID ] = geometry;
-
-			} else if ( geoJSON.type === "sphere" ) {
-
-				geometry = new THREE.SphereGeometry( geoJSON.radius, geoJSON.widthSegments, geoJSON.heightSegments );
-				geometry.name = geoID;
-				result.geometries[ geoID ] = geometry;
-
-			} else if ( geoJSON.type === "cylinder" ) {
-
-				geometry = new THREE.CylinderGeometry( geoJSON.topRad, geoJSON.botRad, geoJSON.height, geoJSON.radSegs, geoJSON.heightSegs );
-				geometry.name = geoID;
-				result.geometries[ geoID ] = geometry;
-
-			} else if ( geoJSON.type === "torus" ) {
-
-				geometry = new THREE.TorusGeometry( geoJSON.radius, geoJSON.tube, geoJSON.segmentsR, geoJSON.segmentsT );
-				geometry.name = geoID;
-				result.geometries[ geoID ] = geometry;
-
-			} else if ( geoJSON.type === "icosahedron" ) {
-
-				geometry = new THREE.IcosahedronGeometry( geoJSON.radius, geoJSON.subdivisions );
-				geometry.name = geoID;
-				result.geometries[ geoID ] = geometry;
-
-			} else if ( geoJSON.type in this.geometryHandlers ) {
-
-				var loader = this.geometryHandlers[ geoJSON.type ][ "loaderObject" ];
-				loader.load( get_url( geoJSON.url, data.urlBaseType ), create_callback_geometry( geoID ) );
-
-			} else if ( geoJSON.type === "embedded" ) {
-
-				var modelJson = data.embeds[ geoJSON.id ],
-					texture_path = "";
-
-				// pass metadata along to jsonLoader so it knows the format version
-
-				modelJson.metadata = data.metadata;
-
-				if ( modelJson ) {
-
-					var jsonLoader = this.geometryHandlers[ "ascii" ][ "loaderObject" ];
-					var model = jsonLoader.parse( modelJson, texture_path );
-					create_callback_embed( geoID )( model.geometry, model.materials );
-
-				}
-
-			}
-
-		}
-
-		// textures
-
-		// count how many textures will be loaded asynchronously
-
-		var textureID, textureJSON;
-
-		for ( textureID in data.textures ) {
-
-			textureJSON = data.textures[ textureID ];
-
-			if ( Array.isArray( textureJSON.url ) ) {
-
-				counter_textures += textureJSON.url.length;
-
-				for ( var n = 0; n < textureJSON.url.length; n ++ ) {
-
-					scope.onLoadStart();
-
-				}
-
-			} else {
-
-				counter_textures += 1;
-
-				scope.onLoadStart();
-
-			}
-
-		}
-
-		total_textures = counter_textures;
-
-		for ( textureID in data.textures ) {
-
-			textureJSON = data.textures[ textureID ];
-
-			if ( textureJSON.mapping !== undefined && THREE[ textureJSON.mapping ] !== undefined ) {
-
-				textureJSON.mapping = THREE[ textureJSON.mapping ];
-
-			}
-
-			var texture;
-
-			if ( Array.isArray( textureJSON.url ) ) {
-
-				var count = textureJSON.url.length;
-				var urls = [];
-
-				for ( var i = 0; i < count; i ++ ) {
-
-					urls[ i ] = get_url( textureJSON.url[ i ], data.urlBaseType );
-
-				}
-
-				var loader = THREE.Loader.Handlers.get( urls[ 0 ] );
-
-				if ( loader !== null ) {
-
-					texture = loader.load( urls, generateTextureCallback( count ) );
-
-					if ( textureJSON.mapping !== undefined )
-						texture.mapping = textureJSON.mapping;
-
-				} else {
-
-					texture = new THREE.CubeTextureLoader().load( urls, generateTextureCallback( count ) );
-					texture.mapping = textureJSON.mapping;
-
-				}
-
-			} else {
-
-				var fullUrl = get_url( textureJSON.url, data.urlBaseType );
-				var textureCallback = generateTextureCallback( 1 );
-
-				var loader = THREE.Loader.Handlers.get( fullUrl );
-
-				if ( loader !== null ) {
-
-					texture = loader.load( fullUrl, textureCallback );
-
-				} else {
-
-					texture = new THREE.Texture();
-					loader = new THREE.ImageLoader();
-
-					( function ( texture ) {
-
-						loader.load( fullUrl, function ( image ) {
-
-							texture.image = image;
-							texture.needsUpdate = true;
-
-							textureCallback();
-
-						} );
-
-					} )( texture )
-
-
-				}
-
-				if ( textureJSON.mapping !== undefined )
-					texture.mapping = textureJSON.mapping;
-
-				if ( THREE[ textureJSON.minFilter ] !== undefined )
-					texture.minFilter = THREE[ textureJSON.minFilter ];
-
-				if ( THREE[ textureJSON.magFilter ] !== undefined )
-					texture.magFilter = THREE[ textureJSON.magFilter ];
-
-				if ( textureJSON.anisotropy ) texture.anisotropy = textureJSON.anisotropy;
-
-				if ( textureJSON.repeat ) {
-
-					texture.repeat.set( textureJSON.repeat[ 0 ], textureJSON.repeat[ 1 ] );
-
-					if ( textureJSON.repeat[ 0 ] !== 1 ) texture.wrapS = THREE.RepeatWrapping;
-					if ( textureJSON.repeat[ 1 ] !== 1 ) texture.wrapT = THREE.RepeatWrapping;
-
-				}
-
-				if ( textureJSON.offset ) {
-
-					texture.offset.set( textureJSON.offset[ 0 ], textureJSON.offset[ 1 ] );
-
-				}
-
-				// handle wrap after repeat so that default repeat can be overriden
-
-				if ( textureJSON.wrap ) {
-
-					var wrapMap = {
-						"repeat": THREE.RepeatWrapping,
-						"mirror": THREE.MirroredRepeatWrapping
-					};
-
-					if ( wrapMap[ textureJSON.wrap[ 0 ] ] !== undefined ) texture.wrapS = wrapMap[ textureJSON.wrap[ 0 ] ];
-					if ( wrapMap[ textureJSON.wrap[ 1 ] ] !== undefined ) texture.wrapT = wrapMap[ textureJSON.wrap[ 1 ] ];
-
-				}
-
-			}
-
-			result.textures[ textureID ] = texture;
-
-		}
-
-		// materials
-
-		var matID, matJSON;
-		var parID;
-
-		for ( matID in data.materials ) {
-
-			matJSON = data.materials[ matID ];
-
-			for ( parID in matJSON.parameters ) {
-
-				if ( parID === "envMap" || parID === "map" || parID === "lightMap" || parID === "bumpMap" || parID === "normalMap" || parID === "alphaMap" ) {
-
-					matJSON.parameters[ parID ] = result.textures[ matJSON.parameters[ parID ] ];
-
-				} else if ( parID === "shading" ) {
-
-					matJSON.parameters[ parID ] = ( matJSON.parameters[ parID ] === "flat" ) ? THREE.FlatShading : THREE.SmoothShading;
-
-				} else if ( parID === "side" ) {
-
-					if ( matJSON.parameters[ parID ] == "double" ) {
-
-						matJSON.parameters[ parID ] = THREE.DoubleSide;
-
-					} else if ( matJSON.parameters[ parID ] == "back" ) {
-
-						matJSON.parameters[ parID ] = THREE.BackSide;
-
-					} else {
-
-						matJSON.parameters[ parID ] = THREE.FrontSide;
-
-					}
-
-				} else if ( parID === "blending" ) {
-
-					matJSON.parameters[ parID ] = matJSON.parameters[ parID ] in THREE ? THREE[ matJSON.parameters[ parID ] ] : THREE.NormalBlending;
-
-				} else if ( parID === "combine" ) {
-
-					matJSON.parameters[ parID ] = matJSON.parameters[ parID ] in THREE ? THREE[ matJSON.parameters[ parID ] ] : THREE.MultiplyOperation;
-
-				} else if ( parID === "vertexColors" ) {
-
-					if ( matJSON.parameters[ parID ] == "face" ) {
-
-						matJSON.parameters[ parID ] = THREE.FaceColors;
-
-					// default to vertex colors if "vertexColors" is anything else face colors or 0 / null / false
-
-					} else if ( matJSON.parameters[ parID ] ) {
-
-						matJSON.parameters[ parID ] = THREE.VertexColors;
-
-					}
-
-				} else if ( parID === "wrapRGB" ) {
-
-					var v3 = matJSON.parameters[ parID ];
-					matJSON.parameters[ parID ] = new THREE.Vector3( v3[ 0 ], v3[ 1 ], v3[ 2 ] );
-
-				} else if ( parID === "normalScale" ) {
-
-					var v2 = matJSON.parameters[ parID ];
-					matJSON.parameters[ parID ] = new THREE.Vector2( v2[ 0 ], v2[ 1 ] );
-
-				}
-
-			}
-
-			if ( matJSON.parameters.opacity !== undefined && matJSON.parameters.opacity < 1.0 ) {
-
-				matJSON.parameters.transparent = true;
-
-			}
-
-			material = new THREE[ matJSON.type ]( matJSON.parameters );
-			material.name = matID;
-
-			result.materials[ matID ] = material;
-
-		}
-
-		// second pass through all materials to initialize MultiMaterials
-		// that could be referring to other materials out of order
-
-		for ( matID in data.materials ) {
-
-			matJSON = data.materials[ matID ];
-
-			if ( matJSON.parameters.materials ) {
-
-				var materialArray = [];
-
-				for ( var i = 0; i < matJSON.parameters.materials.length; i ++ ) {
-
-					var label = matJSON.parameters.materials[ i ];
-					materialArray.push( result.materials[ label ] );
-
-				}
-
-				result.materials[ matID ].materials = materialArray;
-
-			}
-
-		}
-
-		// objects ( synchronous init of procedural primitives )
-
-		handle_objects();
-
-		// defaults
-
-		if ( result.cameras && data.defaults.camera ) {
-
-			result.currentCamera = result.cameras[ data.defaults.camera ];
-
-		}
-
-		if ( result.fogs && data.defaults.fog ) {
-
-			result.scene.fog = result.fogs[ data.defaults.fog ];
-
-		}
-
-		// synchronous callback
-
-		scope.callbackSync( result );
-
-		// just in case there are no async elements
-
-		async_callback_gate();
-
-	}
-
-};

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
examples/js/loaders/draco_decoder.js


+ 26 - 4
examples/js/postprocessing/AdaptiveToneMappingPass.js

@@ -54,6 +54,7 @@ THREE.AdaptiveToneMappingPass = function ( adaptive, resolution ) {
 		uniforms: {
 			"lastLum": { value: null },
 			"currentLum": { value: null },
+			"minLuminance": { value: 0.01 },
 			"delta": { value: 0.016 },
 			"tau": { value: 1.0 }
 		},
@@ -72,6 +73,7 @@ THREE.AdaptiveToneMappingPass = function ( adaptive, resolution ) {
 
 			"uniform sampler2D lastLum;",
 			"uniform sampler2D currentLum;",
+			"uniform float minLuminance;",
 			"uniform float delta;",
 			"uniform float tau;",
 
@@ -80,8 +82,8 @@ THREE.AdaptiveToneMappingPass = function ( adaptive, resolution ) {
 				"vec4 lastLum = texture2D( lastLum, vUv, MIP_LEVEL_1X1 );",
 				"vec4 currentLum = texture2D( currentLum, vUv, MIP_LEVEL_1X1 );",
 
-				"float fLastLum = lastLum.r;",
-				"float fCurrentLum = currentLum.r;",
+				"float fLastLum = max( minLuminance, lastLum.r );",
+				"float fCurrentLum = max( minLuminance, currentLum.r );",
 
 				//The adaption seems to work better in extreme lighting differences
 				//if the input luminance is squared.
@@ -90,7 +92,7 @@ THREE.AdaptiveToneMappingPass = function ( adaptive, resolution ) {
 				// Adapt the luminance using Pattanaik's technique
 				"float fAdaptedLum = fLastLum + (fCurrentLum - fLastLum) * (1.0 - exp(-delta * tau));",
 				// "fAdaptedLum = sqrt(fAdaptedLum);",
-				"gl_FragColor = vec4( vec3( fAdaptedLum ), 1.0 );",
+				"gl_FragColor.r = fAdaptedLum;",
 			"}"
 		].join( '\n' )
 	};
@@ -165,7 +167,16 @@ THREE.AdaptiveToneMappingPass.prototype = Object.assign( Object.create( THREE.Pa
 
 		this.quad.material = this.materialToneMap;
 		this.materialToneMap.uniforms.tDiffuse.value = readBuffer.texture;
-		renderer.render( this.scene, this.camera, writeBuffer, this.clear );
+
+		if ( this.renderToScreen ) {
+
+			renderer.render( this.scene, this.camera );
+
+		} else {
+
+			renderer.render( this.scene, this.camera, writeBuffer, this.clear );
+
+		}
 
 	},
 
@@ -249,6 +260,17 @@ THREE.AdaptiveToneMappingPass.prototype = Object.assign( Object.create( THREE.Pa
 
 	},
 
+	setMinLuminance: function( minLum ) {
+
+		if ( minLum ) {
+
+			this.materialToneMap.uniforms.minLuminance.value = minLum;
+			this.materialAdaptiveLum.uniforms.minLuminance.value = minLum;
+
+		}
+
+	},
+
 	setMaxLuminance: function( maxLum ) {
 
 		if ( maxLum ) {

+ 4 - 2
examples/js/shaders/ToneMapShader.js

@@ -1,7 +1,7 @@
 /**
  * @author miibond
  *
- * Full-screen tone-mapping shader based on http://www.graphics.cornell.edu/~jaf/publications/sig02_paper.pdf
+ * Full-screen tone-mapping shader based on http://www.cis.rit.edu/people/faculty/ferwerda/publications/sig02_paper.pdf
  */
 
 THREE.ToneMapShader = {
@@ -12,6 +12,7 @@ THREE.ToneMapShader = {
 		"averageLuminance":  { value: 1.0 },
 		"luminanceMap":  { value: null },
 		"maxLuminance":  { value: 16.0 },
+		"minLuminance":  { value: 0.01 },
 		"middleGrey":  { value: 0.6 }
 	},
 
@@ -35,6 +36,7 @@ THREE.ToneMapShader = {
 		"varying vec2 vUv;",
 
 		"uniform float middleGrey;",
+		"uniform float minLuminance;",
 		"uniform float maxLuminance;",
 		"#ifdef ADAPTED_LUMINANCE",
 			"uniform sampler2D luminanceMap;",
@@ -56,7 +58,7 @@ THREE.ToneMapShader = {
 			"float fLumPixel = dot(vColor, LUM_CONVERT);",
 
 			// Apply the modified operator (Eq. 4)
-			"float fLumScaled = (fLumPixel * middleGrey) / fLumAvg;",
+			"float fLumScaled = (fLumPixel * middleGrey) / max( minLuminance, fLumAvg );",
 
 			"float fLumCompressed = (fLumScaled * (1.0 + (fLumScaled / (maxLuminance * maxLuminance)))) / (1.0 + fLumScaled);",
 			"return fLumCompressed * vColor;",

+ 18 - 16
examples/js/vr/WebVR.js

@@ -24,12 +24,7 @@ var WEBVR = {
 
 			navigator.getVRDisplays()
 				.then( function ( displays ) {
-
 					onDisplay( displays[ 0 ] );
-
-				} )
-				.catch( function () {
-					// no displays
 				} );
 
 		}
@@ -85,14 +80,12 @@ var WEBVR = {
 
 	getButton: function ( display, canvas ) {
 
-		/*
-		if ( display instanceof VRDisplay === false ) {
+		if ( 'VREffect' in THREE && display instanceof THREE.VREffect ) {
 
 			console.error( 'WebVR.getButton() now expects a VRDisplay.' );
-			return;
+			return document.createElement( 'button' );
 
 		}
-		*/
 
 		var button = document.createElement( 'button' );
 		button.style.position = 'absolute';
@@ -109,18 +102,27 @@ var WEBVR = {
 		button.style.fontStyle = 'normal';
 		button.style.textAlign = 'center';
 		button.style.zIndex = '999';
-		button.textContent = 'ENTER VR';
-		button.onclick = function () {
 
-			display.isPresenting ? display.exitPresent() : display.requestPresent( [ { source: canvas } ] );
+		if ( display ) {
+
+			button.textContent = 'ENTER VR';
+			button.onclick = function () {
+
+				display.isPresenting ? display.exitPresent() : display.requestPresent( [ { source: canvas } ] );
+
+			};
 
-		};
+			window.addEventListener( 'vrdisplaypresentchange', function () {
 
-		window.addEventListener( 'vrdisplaypresentchange', function () {
+				button.textContent = display.isPresenting ? 'EXIT VR' : 'ENTER VR';
 
-			button.textContent = display.isPresenting ? 'EXIT VR' : 'ENTER VR';
+			}, false );
 
-		}, false );
+		} else {
+
+			button.textContent = 'NO VR DISPLAY';
+
+		}
 
 		return button;
 

BIN
examples/models/gltf/BoomBox/glTF-pbrSpecularGlossiness/BoomBox_metallicRoughness.png


BIN
examples/models/gltf/BoomBox/glTF/BoomBox_metallicRoughness.png


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1769 - 0
examples/models/json/pump/pump.json


BIN
examples/models/json/pump/pump_body.jpg


BIN
examples/models/json/pump/pump_gears.jpg


برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است