Browse Source

Merge remote-tracking branch 'upstream/dev' into dev

zhaoy 7 years ago
parent
commit
0b67533be9
100 changed files with 6425 additions and 5138 deletions
  1. 1 1
      .github/CONTRIBUTING.md
  2. 2 2
      .github/ISSUE_TEMPLATE.md
  3. 73 56
      build/three.js
  4. 341 389
      build/three.min.js
  5. 73 56
      build/three.module.js
  6. 1 1
      docs/api/loaders/FontLoader.html
  7. 0 4
      docs/api/loaders/managers/DefaultLoadingManager.html
  8. 1 1
      docs/api/materials/MeshLambertMaterial.html
  9. 5 1
      docs/api/math/Quaternion.html
  10. 4 0
      docs/api/objects/LOD.html
  11. 1 1
      docs/api/renderers/WebGLRenderer.html
  12. 0 39
      docs/api/renderers/webgl/plugins/SpritePlugin.html
  13. 3 3
      docs/examples/controls/OrbitControls.html
  14. 0 4
      docs/list.js
  15. 6 6
      editor/css/dark.css
  16. 6 6
      editor/css/light.css
  17. 134 63
      editor/examples/arkanoid.app.json
  18. 106 43
      editor/examples/camera.app.json
  19. 53 17
      editor/examples/particles.app.json
  20. 74 39
      editor/examples/pong.app.json
  21. 8 7
      editor/examples/shaders.app.json
  22. 3 3
      editor/index.html
  23. 9 3
      editor/js/Toolbar.js
  24. 4 2
      editor/js/libs/app.js
  25. 13 0
      examples/js/Detector.js
  26. 769 752
      examples/js/MarchingCubes.js
  27. 10 8
      examples/js/controls/EditorControls.js
  28. 23 12
      examples/js/controls/MapControls.js
  29. 20 8
      examples/js/controls/OrbitControls.js
  30. 13 1
      examples/js/loaders/ColladaLoader.js
  31. 119 34
      examples/js/loaders/FBXLoader.js
  32. 74 405
      examples/js/loaders/NodeMaterialLoader.js
  33. 0 774
      examples/js/modifiers/BufferSubdivisionModifier.js
  34. 14 0
      examples/js/modifiers/SubdivisionModifier.js
  35. 0 55
      examples/js/nodes/AttributeNode.js
  36. 0 110
      examples/js/nodes/ConstNode.js
  37. 0 92
      examples/js/nodes/FunctionCallNode.js
  38. 0 158
      examples/js/nodes/GLNode.js
  39. 0 65
      examples/js/nodes/InputNode.js
  40. 0 259
      examples/js/nodes/NodeBuilder.js
  41. 0 34
      examples/js/nodes/NodeFrame.js
  42. 0 216
      examples/js/nodes/NodeLib.js
  43. 0 661
      examples/js/nodes/NodeMaterial.js
  44. 106 0
      examples/js/nodes/Nodes.js
  45. 0 53
      examples/js/nodes/RawNode.js
  46. 205 0
      examples/js/nodes/THREE.Nodes.js
  47. 0 134
      examples/js/nodes/TempNode.js
  48. 0 43
      examples/js/nodes/VarNode.js
  49. 97 50
      examples/js/nodes/accessors/CameraNode.js
  50. 25 16
      examples/js/nodes/accessors/ColorsNode.js
  51. 21 9
      examples/js/nodes/accessors/LightNode.js
  52. 53 24
      examples/js/nodes/accessors/NormalNode.js
  53. 60 32
      examples/js/nodes/accessors/PositionNode.js
  54. 46 31
      examples/js/nodes/accessors/ReflectNode.js
  55. 53 0
      examples/js/nodes/accessors/ResolutionNode.js
  56. 21 9
      examples/js/nodes/accessors/ScreenUVNode.js
  57. 37 16
      examples/js/nodes/accessors/UVNode.js
  58. 50 0
      examples/js/nodes/bsdfs/BlinnExponentToRoughnessNode.js
  59. 31 0
      examples/js/nodes/bsdfs/BlinnShininessExponentNode.js
  60. 91 0
      examples/js/nodes/bsdfs/RoughnessToBlinnExponentNode.js
  61. 70 0
      examples/js/nodes/core/AttributeNode.js
  62. 125 0
      examples/js/nodes/core/ConstNode.js
  63. 108 0
      examples/js/nodes/core/FunctionCallNode.js
  64. 56 34
      examples/js/nodes/core/FunctionNode.js
  65. 176 0
      examples/js/nodes/core/GLNode.js
  66. 85 0
      examples/js/nodes/core/InputNode.js
  67. 1007 0
      examples/js/nodes/core/NodeBuilder.js
  68. 42 0
      examples/js/nodes/core/NodeFrame.js
  69. 68 0
      examples/js/nodes/core/NodeLib.js
  70. 9 2
      examples/js/nodes/core/NodeUniform.js
  71. 75 0
      examples/js/nodes/core/NodeUtils.js
  72. 107 0
      examples/js/nodes/core/StructNode.js
  73. 133 0
      examples/js/nodes/core/TempNode.js
  74. 66 0
      examples/js/nodes/core/VarNode.js
  75. 168 0
      examples/js/nodes/effects/BlurNode.js
  76. 136 0
      examples/js/nodes/effects/ColorAdjustmentNode.js
  77. 73 0
      examples/js/nodes/effects/LuminanceNode.js
  78. 22 9
      examples/js/nodes/inputs/ColorNode.js
  79. 33 28
      examples/js/nodes/inputs/CubeTextureNode.js
  80. 19 9
      examples/js/nodes/inputs/FloatNode.js
  81. 19 7
      examples/js/nodes/inputs/IntNode.js
  82. 40 9
      examples/js/nodes/inputs/Matrix3Node.js
  83. 39 9
      examples/js/nodes/inputs/Matrix4Node.js
  84. 57 0
      examples/js/nodes/inputs/PropertyNode.js
  85. 37 19
      examples/js/nodes/inputs/ReflectorNode.js
  86. 13 8
      examples/js/nodes/inputs/ScreenNode.js
  87. 36 29
      examples/js/nodes/inputs/TextureNode.js
  88. 22 9
      examples/js/nodes/inputs/Vector2Node.js
  89. 22 10
      examples/js/nodes/inputs/Vector3Node.js
  90. 22 9
      examples/js/nodes/inputs/Vector4Node.js
  91. 34 0
      examples/js/nodes/materials/MeshStandardNodeMaterial.js
  92. 189 0
      examples/js/nodes/materials/NodeMaterial.js
  93. 26 7
      examples/js/nodes/materials/PhongNodeMaterial.js
  94. 17 7
      examples/js/nodes/materials/SpriteNodeMaterial.js
  95. 28 7
      examples/js/nodes/materials/StandardNodeMaterial.js
  96. 109 0
      examples/js/nodes/materials/nodes/MeshStandardNode.js
  97. 76 37
      examples/js/nodes/materials/nodes/PhongNode.js
  98. 62 0
      examples/js/nodes/materials/nodes/RawNode.js
  99. 41 17
      examples/js/nodes/materials/nodes/SpriteNode.js
  100. 99 64
      examples/js/nodes/materials/nodes/StandardNode.js

+ 1 - 1
.github/CONTRIBUTING.md

@@ -14,7 +14,7 @@
 1. Specify the revision number of the three.js library where the bug occurred.
 2. Specify your browser version, operating system, and graphics card. (for example, Chrome 23.0.1271.95, Windows 7, Nvidia Quadro 2000M)
 3. Describe the problem in detail. Explain what happened, and what you expected would happen.
-4. Provide a small test-case (http://jsfiddle.net). [Here is a fiddle](http://jsfiddle.net/akmcv7Lh/) you can edit that runs the current version. [And here is a fiddle](http://jsfiddle.net/hw9rcLL8/) that uses the dev branch. If a test-case is not possible, provide a link to a live version of your application.
+4. Provide a small test-case (http://jsfiddle.net). [Here is a fiddle](https://jsfiddle.net/3foLr7sn/) you can edit that runs the current version. [And here is a fiddle](https://jsfiddle.net/qgu17w5o/) that uses the dev branch. If a test-case is not possible, provide a link to a live version of your application.
 5. If helpful, include a screenshot. Annotate the screenshot for clarity.
 
 ---

+ 2 - 2
.github/ISSUE_TEMPLATE.md

@@ -11,8 +11,8 @@ Always include a code snippet, screenshots, and any relevant models or textures
 
 Please also include a live example if possible. You can start from these templates:
 
-* [jsfiddle](https://jsfiddle.net/s3rjfcc3/) (latest release branch)
-* [jsfiddle](https://jsfiddle.net/ptgwhemb/) (dev branch)
+* [jsfiddle](https://jsfiddle.net/3foLr7sn/) (latest release branch)
+* [jsfiddle](https://jsfiddle.net/qgu17w5o/) (dev branch)
 * [codepen](https://codepen.io/anon/pen/aEBKxR) (latest release branch)
 * [codepen](https://codepen.io/anon/pen/BJWzaN) (dev branch)
 

File diff suppressed because it is too large
+ 73 - 56
build/three.js


File diff suppressed because it is too large
+ 341 - 389
build/three.min.js


File diff suppressed because it is too large
+ 73 - 56
build/three.module.js


+ 1 - 1
docs/api/loaders/FontLoader.html

@@ -29,7 +29,7 @@
 		var loader = new THREE.FontLoader();
 		var font = loader.load(
 			// resource URL
-			'fonts/helvetiker_bold.typeface.json'
+			'fonts/helvetiker_bold.typeface.json',
 
 			// onLoad callback
 			function ( font ) {

+ 0 - 4
docs/api/loaders/managers/DefaultLoadingManager.html

@@ -19,10 +19,6 @@
 
 		<h2>Example</h2>
 
-		<p>
-			[example:webgl_loader_scene WebGL / loader / scene]<br />
-		</p>
-
 		<p>
 			You can optionally set the [page:LoadingManager.onStart onStart], [page:LoadingManager.onLoad onLoad],
 			[page:LoadingManager.onProgress onProgress], [page:LoadingManager.onStart onError] functions for the manager.

+ 1 - 1
docs/api/materials/MeshLambertMaterial.html

@@ -101,7 +101,7 @@
 
 		<h3>[property:Texture emissiveMap]</h3>
 		<p>
-		Set emisssive (glow) map. Default is null. The emissive map color is modulated by
+		Set emissive (glow) map. Default is null. The emissive map color is modulated by
 		the emissive color and the emissive intensity. If you have an emissive map, be sure to
 		set the emissive color to something other than black.
 		</p>

+ 5 - 1
docs/api/math/Quaternion.html

@@ -59,13 +59,17 @@
 
 		<h2>Methods</h2>
 
+		<h3>[method:Float angleTo]( [param:Quaternion q] )</h3>
+		<p>
+			Returns the angle between this quaternion and quaternion [page:Quaternion q] in radians.
+		</p>
+
 		<h3>[method:Quaternion clone]()</h3>
 		<p>
 			Creates a new Quaternion with identical [page:.x x], [page:.y y],
 			[page:.z z] and [page:.w w] properties to this one.
 		</p>
 
-
 		<h3>[method:Quaternion conjugate]()</h3>
 		<p>
 		Returns the rotational conjugate of this quaternion. The conjugate of a quaternion

+ 4 - 0
docs/api/objects/LOD.html

@@ -21,6 +21,10 @@
 		</p>
 
 		<h2>Example</h2>
+		
+		<p>
+			[example:webgl_lod webgl / lod ]
+		</p>
 
 		<code>
 var lod = new THREE.LOD();

+ 1 - 1
docs/api/renderers/WebGLRenderer.html

@@ -211,7 +211,7 @@
 			Keep in mind that the standard materials only allow 4 MorphNormals.
 		</p>
 
-		<h3>[property:Integer physicallyCorrectLights]</h3>
+		<h3>[property:Boolean physicallyCorrectLights]</h3>
 		<p>
 		Whether to use physically correct lighting mode. Default is *false*.
 		See the [example:webgl_lights_physical lights / physical] example.

+ 0 - 39
docs/api/renderers/webgl/plugins/SpritePlugin.html

@@ -1,39 +0,0 @@
-<!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>
-
-		<p class="desc">The Webglrenderer plugin class that allows Sprites to be rendered in the WebglRenderer. This plugin is automatically loaded in the Webglrenderer.</p>
-
-
-		<h2>Constructor</h2>
-
-		<h3>[name]()</h3>
-		<p>
-		Creates a new [name].
-		</p>
-
-
-		<h2>Methods</h2>
-
-		<h3>[method:null render]( [param:Scene scene], [param:Camera camera] )</h3>
-		<p>
-		scene -- The scene to render. <br />
-		camera -- The camera to render.
-		</p>
-		<p>
-		Renders the sprites defined in the scene. This gets automatically called as post-render function to draw the lensflares.
-		</p>
-
-		<h2>Source</h2>
-
-		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
-	</body>
-</html>

+ 3 - 3
docs/examples/controls/OrbitControls.html

@@ -190,9 +190,9 @@ controls.keys = {
 			This object contains references to the mouse buttons used for the controls.
 			<code>
 controls.mouseButtons = {
-	ORBIT: THREE.MOUSE.LEFT,
-	ZOOM: THREE.MOUSE.MIDDLE,
-	PAN: THREE.MOUSE.RIGHT
+	LEFT: THREE.MOUSE.LEFT,
+	MIDDLE: THREE.MOUSE.MIDDLE,
+	RIGHT: THREE.MOUSE.RIGHT
 }
 			</code>
 		</p>

+ 0 - 4
docs/list.js

@@ -416,10 +416,6 @@ var list = {
 			"WebGLProgram": "api/renderers/webgl/WebGLProgram",
 			"WebGLShader": "api/renderers/webgl/WebGLShader",
 			"WebGLState": "api/renderers/webgl/WebGLState"
-		},
-
-		"WebGLRenderer / Plugins": {
-			"SpritePlugin": "api/renderers/webgl/plugins/SpritePlugin"
 		}
 
 	}

+ 6 - 6
editor/css/dark.css

@@ -53,7 +53,7 @@ select {
 	top: 32px;
 	left: 0;
 	right: 300px;
-	bottom: 32px;
+	bottom: 0;
 }
 
 	#viewport #info {
@@ -66,7 +66,7 @@ select {
 	top: 32px;
 	left: 0;
 	right: 300px;
-	bottom: 32px;
+	bottom: 0;
 	opacity: 0.9;
 }
 
@@ -75,7 +75,7 @@ select {
 	top: 32px;
 	left: 0;
 	right: 300px;
-	bottom: 32px;
+	bottom: 0;
 }
 
 #menubar {
@@ -201,9 +201,9 @@ select {
 
 #toolbar {
 	position: absolute;
-	left: 0;
-	right: 300px;
-	bottom: 0;
+	left: calc(50% - 290px); /* ( ( 100% - 300px ) / 2.0 ) - 140px */
+	width: 280px;
+	bottom: 16px;
 	height: 32px;
 	background-color: #111;
 	color: #333;

+ 6 - 6
editor/css/light.css

@@ -49,7 +49,7 @@ select {
 	top: 32px;
 	left: 0;
 	right: 300px;
-	bottom: 32px;
+	bottom: 0;
 }
 
 	#viewport #info {
@@ -62,7 +62,7 @@ select {
 	top: 32px;
 	left: 0;
 	right: 300px;
-	bottom: 32px;
+	bottom: 0;
 	opacity: 0.9;
 }
 
@@ -71,7 +71,7 @@ select {
 	top: 32px;
 	left: 0;
 	right: 300px;
-	bottom: 32px;
+	bottom: 0;
 }
 
 #menubar {
@@ -194,9 +194,9 @@ select {
 
 #toolbar {
 	position: absolute;
-	left: 0;
-	right: 300px;
-	bottom: 0;
+	left: calc(50% - 290px); /* ( ( 100% - 300px ) / 2.0 ) - 140px */
+	width: 280px;
+	bottom: 16px;
 	height: 32px;
 	background: #eee;
 	color: #333;

+ 134 - 63
editor/examples/arkanoid.app.json

@@ -3,65 +3,72 @@
 		"type": "App"
 	},
 	"project": {
+		"gammaInput": true,
+		"gammaOutput": true,
 		"shadows": true,
 		"vr": false
 	},
 	"camera": {
 		"metadata": {
-			"version": 4.4,
+			"version": 4.5,
 			"type": "Object",
 			"generator": "Object3D.toJSON"
 		},
 		"object": {
-			"uuid": "E41E9F54-8B31-4D1F-8D09-AF5E802E9A22",
+			"uuid": "0C0DD0AD-3A7F-4ECD-A9FE-CECD97D5CBD9",
 			"type": "PerspectiveCamera",
 			"name": "Camera",
-			"matrix": [0.9392361044883728,-2.8092810300250903e-9,-0.3432718515396118,0,-0.14778217673301697,0.902585506439209,-0.404351145029068,0,0.3098321855068207,0.43051064014434814,0.847740888595581,0,142.32125854492188,202.75485229492188,389.40936279296875,1],
+			"layers": 1,
+			"matrix": [0.939236,0,-0.343272,0,-0.147782,0.902586,-0.404351,0,0.309832,0.430511,0.847741,0,11.713146,19.228675,40.388679,1],
 			"fov": 50,
-			"aspect": 1.536388140161725,
+			"zoom": 1,
 			"near": 0.1,
-			"far": 100000
+			"far": 100000,
+			"focus": 10,
+			"aspect": 1.428977,
+			"filmGauge": 35,
+			"filmOffset": 0
 		}
 	},
 	"scene": {
 		"metadata": {
-			"version": 4.4,
+			"version": 4.5,
 			"type": "Object",
 			"generator": "Object3D.toJSON"
 		},
 		"geometries": [
 			{
-				"uuid": "8F05A1F2-3877-478B-8DFC-F572AC61AB3A",
+				"uuid": "BBEE74D1-E43D-4C32-A9F3-4656E78C26F3",
 				"type": "PlaneGeometry",
-				"width": 300,
-				"height": 400,
+				"width": 30,
+				"height": 40,
 				"widthSegments": 1,
 				"heightSegments": 1
 			},
 			{
-				"uuid": "EEDF0A9A-D174-44E4-9C2F-A2F5BB8BE7F5",
-				"type": "CylinderGeometry",
-				"radiusTop": 5,
-				"radiusBottom": 5,
-				"height": 20,
-				"radialSegments": 32,
-				"heightSegments": 1,
-				"openEnded": false
-			},
-			{
-				"uuid": "7149652B-DBD7-4CB7-A600-27A9AC005C95",
+				"uuid": "C1722F5F-89AD-45D8-B78C-D1D34AF2A012",
 				"type": "BoxGeometry",
-				"width": 20,
-				"height": 10,
-				"depth": 10,
+				"width": 2,
+				"height": 1,
+				"depth": 1,
 				"widthSegments": 1,
 				"heightSegments": 1,
 				"depthSegments": 1
 			},
 			{
-				"uuid": "CABCC711-1331-4D4C-9FF6-409299F10C68",
+				"uuid": "327EFFCF-649C-4EF3-86D4-B422C5A86E89",
+				"type": "CylinderGeometry",
+				"radiusTop": 0.5,
+				"radiusBottom": 0.5,
+				"height": 2,
+				"radialSegments": 32,
+				"heightSegments": 1,
+				"openEnded": false
+			},
+			{
+				"uuid": "0791211B-BB02-4E57-82B5-64C05DE92B39",
 				"type": "SphereGeometry",
-				"radius": 5,
+				"radius": 0.5,
 				"widthSegments": 32,
 				"heightSegments": 16,
 				"phiStart": 0,
@@ -70,14 +77,24 @@
 				"thetaLength": 3.14
 			},
 			{
-				"uuid": "EFBF641D-F092-462E-B7FB-0BFAD1591EFC",
+				"uuid": "73F12A47-9EA7-47FD-BCF3-89B8219B2626",
 				"type": "BoxGeometry",
-				"width": 20,
-				"height": 10,
-				"depth": 10,
+				"width": 2,
+				"height": 1,
+				"depth": 1,
 				"widthSegments": 1,
 				"heightSegments": 1,
 				"depthSegments": 1
+			},
+			{
+				"uuid": "3BDEB9FB-BDD4-44AD-8A47-008BED1C8982",
+				"type": "CylinderGeometry",
+				"radiusTop": 0.5,
+				"radiusBottom": 0.5,
+				"height": 2,
+				"radialSegments": 32,
+				"heightSegments": 1,
+				"openEnded": false
 			}],
 		"materials": [
 			{
@@ -86,7 +103,19 @@
 				"color": 86015,
 				"emissive": 0,
 				"specular": 1118481,
-				"shininess": 30
+				"shininess": 30,
+				"depthFunc": 3,
+				"depthTest": true,
+				"depthWrite": true
+			},
+			{
+				"uuid": "D98FC4D1-169E-420A-92EA-20E55009A46D",
+				"type": "MeshBasicMaterial",
+				"color": 63744,
+				"depthFunc": 3,
+				"depthTest": true,
+				"depthWrite": true,
+				"wireframe": true
 			},
 			{
 				"uuid": "3B9DE64D-E1C8-4C24-9F73-3A9E10E3E655",
@@ -94,13 +123,10 @@
 				"color": 16777215,
 				"emissive": 0,
 				"specular": 1118481,
-				"shininess": 30
-			},
-			{
-				"uuid": "D98FC4D1-169E-420A-92EA-20E55009A46D",
-				"type": "MeshBasicMaterial",
-				"wireframe": true,
-				"color": 63744
+				"shininess": 30,
+				"depthFunc": 3,
+				"depthTest": true,
+				"depthWrite": true
 			},
 			{
 				"uuid": "043B208C-1F83-42C6-802C-E0E35621C27C",
@@ -108,100 +134,145 @@
 				"color": 16777215,
 				"emissive": 0,
 				"specular": 1118481,
-				"shininess": 30
+				"shininess": 30,
+				"depthFunc": 3,
+				"depthTest": true,
+				"depthWrite": true
 			},
 			{
 				"uuid": "40EC9BDA-91C0-4671-937A-2BCB6DA7EEBB",
 				"type": "MeshBasicMaterial",
-				"wireframe": true,
-				"color": 63744
+				"color": 63744,
+				"depthFunc": 3,
+				"depthTest": true,
+				"depthWrite": true,
+				"wireframe": true
 			}],
 		"object": {
 			"uuid": "31517222-A9A7-4EAF-B5F6-60751C0BABA3",
 			"type": "Scene",
 			"name": "Scene",
+			"layers": 1,
 			"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],
 			"children": [
 				{
 					"uuid": "EBBB1E63-6318-4752-AE2E-440A4E0B3EF3",
 					"type": "Mesh",
 					"name": "Ground",
-					"matrix": [1,0,0,0,0,0.0007960614748299122,-0.9999997019767761,0,0,0.9999997019767761,0.0007960614748299122,0,0,0,0,1],
-					"geometry": "8F05A1F2-3877-478B-8DFC-F572AC61AB3A",
+					"layers": 1,
+					"matrix": [1,0,0,0,0,0.000796,-1,0,0,1,0.000796,0,0,0,0,1],
+					"geometry": "BBEE74D1-E43D-4C32-A9F3-4656E78C26F3",
 					"material": "2F69AF3A-DDF5-4BBA-87B5-80159F90DDBF"
 				},
 				{
 					"uuid": "6EE2E764-43E0-48E0-85F2-E0C8823C20DC",
 					"type": "DirectionalLight",
 					"name": "DirectionalLight 1",
-					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,100,200,150,1],
+					"layers": 1,
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,10,20,15,1],
 					"color": 16777215,
-					"intensity": 1
+					"intensity": 1,
+					"shadow": {
+						"camera": {
+							"uuid": "3BC010F7-9766-4087-BA04-1D4FD7721ABA",
+							"type": "OrthographicCamera",
+							"layers": 1,
+							"zoom": 1,
+							"left": -5,
+							"right": 5,
+							"top": 5,
+							"bottom": -5,
+							"near": 0.5,
+							"far": 500
+						}
+					}
 				},
 				{
 					"uuid": "38219749-1E67-45F2-AB15-E64BA0940CAD",
 					"type": "Mesh",
 					"name": "Brick",
-					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,5,0,1],
+					"layers": 1,
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0.5,0,1],
+					"geometry": "C1722F5F-89AD-45D8-B78C-D1D34AF2A012",
+					"material": "D98FC4D1-169E-420A-92EA-20E55009A46D",
 					"children": [
 						{
 							"uuid": "711A5955-8F17-4A8B-991A-7604D27E6FA0",
 							"type": "Mesh",
 							"name": "Cylinder",
-							"matrix": [0.0007962009985931218,0.0007962677045725286,0.9999995231628418,0,-0.9999997615814209,3.462185702574061e-7,0.0007962677045725286,0,2.210134084634774e-7,-0.9999997615814209,0.0007962008821777999,0,0,0,0,1],
-							"geometry": "EEDF0A9A-D174-44E4-9C2F-A2F5BB8BE7F5",
+							"layers": 1,
+							"matrix": [0.000795,0.000795,1,0,-1.000001,-0.000001,0.000795,0,0.000001,-1.000001,0.000795,0,0,0,0,1],
+							"geometry": "327EFFCF-649C-4EF3-86D4-B422C5A86E89",
 							"material": "3B9DE64D-E1C8-4C24-9F73-3A9E10E3E655"
-						}],
-					"geometry": "7149652B-DBD7-4CB7-A600-27A9AC005C95",
-					"material": "D98FC4D1-169E-420A-92EA-20E55009A46D"
+						}]
 				},
 				{
 					"uuid": "18FFA67C-F893-4E7A-8A76-8D996DEBE0C6",
 					"type": "Mesh",
 					"name": "Ball",
-					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,5,35.54999923706055,1],
-					"geometry": "CABCC711-1331-4D4C-9FF6-409299F10C68",
+					"layers": 1,
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0.5,3.55,1],
+					"geometry": "0791211B-BB02-4E57-82B5-64C05DE92B39",
 					"material": "043B208C-1F83-42C6-802C-E0E35621C27C"
 				},
 				{
 					"uuid": "6D660D49-39B8-40C3-95F6-E4E007AA8D79",
 					"type": "Mesh",
 					"name": "Paddle",
-					"matrix": [2,0,0,0,0,1,0,0,0,0,1,0,0,5,159.5399932861328,1],
+					"layers": 1,
+					"matrix": [2,0,0,0,0,1,0,0,0,0,1,0,0,0.5,15.95,1],
+					"geometry": "73F12A47-9EA7-47FD-BCF3-89B8219B2626",
+					"material": "40EC9BDA-91C0-4671-937A-2BCB6DA7EEBB",
 					"children": [
 						{
 							"uuid": "4F5F884C-9E1B-45E6-8F1E-4D538A46D8CB",
 							"type": "Mesh",
 							"name": "Cylinder",
-							"matrix": [0.0007962009985931218,0.0007962677045725286,0.9999995231628418,0,-0.9999997615814209,3.462185702574061e-7,0.0007962677045725286,0,2.210134084634774e-7,-0.9999997615814209,0.0007962008821777999,0,0,0,0,1],
-							"geometry": "EEDF0A9A-D174-44E4-9C2F-A2F5BB8BE7F5",
+							"layers": 1,
+							"matrix": [0.000795,0.000795,1,0,-1.000001,-0.000001,0.000795,0,0.000001,-1.000001,0.000795,0,0,0,0,1],
+							"geometry": "3BDEB9FB-BDD4-44AD-8A47-008BED1C8982",
 							"material": "3B9DE64D-E1C8-4C24-9F73-3A9E10E3E655"
-						}],
-					"geometry": "EFBF641D-F092-462E-B7FB-0BFAD1591EFC",
-					"material": "40EC9BDA-91C0-4671-937A-2BCB6DA7EEBB"
+						}]
 				},
 				{
 					"uuid": "B0BEAF69-8B5D-4D87-ADCA-FDE83A02762D",
 					"type": "PointLight",
 					"name": "PointLight 2",
-					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,-116.54356384277344,69.48957061767578,-206.8248291015625,1],
+					"layers": 1,
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,-11.65,6.949,-20.682,1],
 					"color": 16777215,
 					"intensity": 1,
 					"distance": 0,
-					"decay": 1
-				}]
+					"decay": 1,
+					"shadow": {
+						"camera": {
+							"uuid": "2F0DA21A-EFB8-4E9A-83C5-A601D6113780",
+							"type": "PerspectiveCamera",
+							"layers": 1,
+							"fov": 90,
+							"zoom": 1,
+							"near": 0.5,
+							"far": 500,
+							"focus": 10,
+							"aspect": 1,
+							"filmGauge": 35,
+							"filmOffset": 0
+						}
+					}
+				}],
+			"background": 11184810
 		}
 	},
 	"scripts": {
 		"6D660D49-39B8-40C3-95F6-E4E007AA8D79": [
 			{
 				"name": "User",
-				"source": "function mousemove( event ) {\n\n\tthis.position.x = ( event.clientX / player.width ) * 300 - 150;\n\n}\n\n// function update( event ) {}"
+				"source": "function mousemove( event ) {\n\n\tthis.position.x = ( event.clientX / player.width ) * 30 - 15;\n\n}\n\n// function update( event ) {}"
 			}],
 		"31517222-A9A7-4EAF-B5F6-60751C0BABA3": [
 			{
 				"name": "Game Logic",
-				"source": "var ball = this.getObjectByName( 'Ball' );\n\nvar direction = new THREE.Vector3();\ndirection.x = Math.random() - 0.5;\ndirection.z = - 0.5;\ndirection.normalize();\n\nvar speed = new THREE.Vector3();\n\n//\n\nvar group = new THREE.Group();\nthis.add( group );\n\nvar paddle = this.getObjectByName( 'Paddle' );\npaddle.material.visible = false;\ngroup.add( paddle );\n\nvar brick = this.getObjectByName( 'Brick' );\n\nfor ( var j = 0; j < 8; j ++ ) {\n\n\tvar material = new THREE.MeshPhongMaterial( { color: Math.random() * 0xffffff } );\n\n\tfor ( var i = 0; i < 12; i ++ ) {\n\t\t\n\t\tvar object = brick.clone();\n\t\tobject.position.x = i * 22 - 120;\n\t\tobject.position.z = j * 14 - 120;\n\t\tgroup.add( object );\n\n\t\tvar cylinder = object.getObjectByName( 'Cylinder' );\n\t\tcylinder.material = material;\n\n\t}\n\t\n}\n\nbrick.visible = false;\nbrick.material.visible = false;\n\n//\n\nvar raycaster = new THREE.Raycaster();\n\nfunction update( event ) {\n\t\n\tif ( ball.position.x < - 150 || ball.position.x > 150 ) direction.x = - direction.x;\n\tif ( ball.position.z < - 200 || ball.position.z > 200 ) direction.z = - direction.z;\n\n\tball.position.x = Math.max( - 150, Math.min( 150, ball.position.x ) );\n\tball.position.z = Math.max( - 200, Math.min( 200, ball.position.z ) );\n\t\n\tball.position.add( speed.copy( direction ).multiplyScalar( event.delta / 4 ) );\n\t\n\traycaster.set( ball.position, direction );\n\t\n\tvar intersections = raycaster.intersectObjects( group.children );\n\t\n\tif ( intersections.length > 0 ) {\n\t\n\t\tvar intersection = intersections[ 0 ];\n\t\t\n\t\tif ( intersection.distance < 5 ) {\n\t\t\t\n\t\t\tif ( intersection.object !== paddle ) {\n\n\t\t\t\tgroup.remove( intersection.object );\n\t\t\t\t\n\t\t\t}\n\t\t\t\n\t\t\tdirection.reflect( intersection.face.normal );\n\t\t\t\n\t\t}\n\t\t\n\t}\n\n}"
+				"source": "var ball = this.getObjectByName( 'Ball' );\n\nvar direction = new THREE.Vector3();\ndirection.x = Math.random() - 0.5;\ndirection.z = - 0.5;\ndirection.normalize();\n\nvar speed = new THREE.Vector3();\n\n//\n\nvar group = new THREE.Group();\nthis.add( group );\n\nvar paddle = this.getObjectByName( 'Paddle' );\npaddle.material.visible = false;\ngroup.add( paddle );\n\nvar brick = this.getObjectByName( 'Brick' );\n\nfor ( var j = 0; j < 8; j ++ ) {\n\n\tvar material = new THREE.MeshPhongMaterial( { color: Math.random() * 0xffffff } );\n\n\tfor ( var i = 0; i < 12; i ++ ) {\n\t\t\n\t\tvar object = brick.clone();\n\t\tobject.position.x = i * 2.2 - 12;\n\t\tobject.position.z = j * 1.4 - 12;\n\t\tgroup.add( object );\n\n\t\tvar cylinder = object.getObjectByName( 'Cylinder' );\n\t\tcylinder.material = material;\n\n\t}\n\t\n}\n\nbrick.visible = false;\nbrick.material.visible = false;\n\n//\n\nvar raycaster = new THREE.Raycaster();\n\nfunction update( event ) {\n\t\n\tif ( ball.position.x < - 15 || ball.position.x > 15 ) direction.x = - direction.x;\n\tif ( ball.position.z < - 20 || ball.position.z > 20 ) direction.z = - direction.z;\n\n\tball.position.x = Math.max( - 15, Math.min( 15, ball.position.x ) );\n\tball.position.z = Math.max( - 20, Math.min( 20, ball.position.z ) );\n\t\n\tball.position.add( speed.copy( direction ).multiplyScalar( event.delta / 40 ) );\n\t\n\traycaster.set( ball.position, direction );\n\t\n\tvar intersections = raycaster.intersectObjects( group.children );\n\t\n\tif ( intersections.length > 0 ) {\n\t\n\t\tvar intersection = intersections[ 0 ];\n\t\t\n\t\tif ( intersection.distance < 0.5 ) {\n\t\t\t\n\t\t\tif ( intersection.object !== paddle ) {\n\n\t\t\t\tgroup.remove( intersection.object );\n\t\t\t\t\n\t\t\t}\n\t\t\t\n\t\t\tdirection.reflect( intersection.face.normal );\n\t\t\t\n\t\t}\n\t\t\n\t}\n\n}"
 			}]
 	}
 }

+ 106 - 43
editor/examples/camera.app.json

@@ -3,65 +3,72 @@
 		"type": "App"
 	},
 	"project": {
+		"gammaInput": true,
+		"gammaOutput": true,
 		"shadows": true,
 		"vr": false
 	},
 	"camera": {
 		"metadata": {
-			"version": 4.3,
+			"version": 4.5,
 			"type": "Object",
-			"generator": "ObjectExporter"
+			"generator": "Object3D.toJSON"
 		},
 		"object": {
-			"uuid": "C7FB195B-270E-47B4-95C9-1754652A9D11",
+			"uuid": "60EBAF60-53DA-47B0-A028-8FC031B708F6",
 			"type": "PerspectiveCamera",
 			"name": "Camera",
+			"layers": 1,
+			"matrix": [0.970041,0,-0.242943,0,-0.048226,0.980099,-0.192562,0,0.238108,0.198509,0.950736,0,1.548,1.29,6.18,1],
 			"fov": 50,
-			"aspect": 1.2252042007001167,
+			"zoom": 1,
 			"near": 0.1,
 			"far": 100000,
-			"matrix": [0.9700406789779663,-2.851828329042405e-9,-0.24294254183769226,0,-0.04822639003396034,0.9800989627838135,-0.1925622522830963,0,0.23810774087905884,0.19850945472717285,0.950735867023468,0,154.7735595703125,129.03408813476562,617.992431640625,1]
+			"focus": 10,
+			"aspect": 1.428977,
+			"filmGauge": 35,
+			"filmOffset": 0
 		}
 	},
 	"scene": {
 		"metadata": {
-			"version": 4.3,
+			"version": 4.5,
 			"type": "Object",
-			"generator": "ObjectExporter"
+			"generator": "Object3D.toJSON"
 		},
 		"geometries": [
 			{
-				"uuid": "51BB3E54-D2DF-4576-9953-FB8E940588B5",
+				"uuid": "6D90C4BE-EBA6-4E21-8F54-7CFDAA61F30B",
 				"type": "PlaneGeometry",
-				"width": 1000,
-				"height": 1000,
+				"width": 10,
+				"height": 10,
 				"widthSegments": 1,
 				"heightSegments": 1
 			},
 			{
-				"uuid": "D8E200D3-27BC-49F8-A5C5-7384206E70FE",
+				"uuid": "D3008B2A-ACDD-43CC-87F7-4F942607D21A",
 				"type": "BoxGeometry",
-				"width": 100,
-				"height": 100,
-				"depth": 100,
+				"width": 1,
+				"height": 1,
+				"depth": 1,
 				"widthSegments": 1,
 				"heightSegments": 1,
 				"depthSegments": 1
 			},
 			{
-				"uuid": "25BA32DB-8B02-4ABA-A77C-69868C464A1A",
+				"uuid": "F482ACD4-013A-49CF-AE0F-C9FF4ADAE409",
 				"type": "CylinderGeometry",
 				"radiusTop": 0,
-				"radiusBottom": 40,
-				"height": 75,
+				"radiusBottom": 0.4,
+				"height": 0.75,
 				"radialSegments": 4,
 				"heightSegments": 1,
 				"openEnded": false
 			},
 			{
-				"uuid": "4DECFAB5-6FD1-4D84-9A29-565807B074EA",
+				"uuid": "51CDDCED-BC71-4B1B-A485-725B6A48204B",
 				"type": "IcosahedronGeometry",
-				"radius": 40,
+				"radius": 0.4,
 				"detail": 2
 			}],
 		"materials": [
@@ -71,7 +78,10 @@
 				"color": 16777215,
 				"emissive": 0,
 				"specular": 1118481,
-				"shininess": 30
+				"shininess": 30,
+				"depthFunc": 3,
+				"depthTest": true,
+				"depthWrite": true
 			},
 			{
 				"uuid": "B5943856-E404-45D9-A427-4774202C2CD0",
@@ -79,7 +89,10 @@
 				"color": 37119,
 				"emissive": 0,
 				"specular": 1118481,
-				"shininess": 30
+				"shininess": 30,
+				"depthFunc": 3,
+				"depthTest": true,
+				"depthWrite": true
 			},
 			{
 				"uuid": "3F872310-2067-4BE4-9250-5B3F4E43797E",
@@ -87,7 +100,10 @@
 				"color": 15859456,
 				"emissive": 0,
 				"specular": 1118481,
-				"shininess": 30
+				"shininess": 30,
+				"depthFunc": 3,
+				"depthTest": true,
+				"depthWrite": true
 			},
 			{
 				"uuid": "E1826901-7922-4584-A25D-6D487E2C9BBD",
@@ -95,83 +111,130 @@
 				"color": 16711680,
 				"emissive": 0,
 				"specular": 1118481,
-				"shininess": 30
+				"shininess": 30,
+				"depthFunc": 3,
+				"depthTest": true,
+				"depthWrite": true
 			}],
 		"object": {
 			"uuid": "3741222A-BD8F-401C-A5D2-5A907E891896",
 			"type": "Scene",
 			"name": "Scene",
+			"layers": 1,
 			"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],
 			"children": [
 				{
 					"uuid": "B7CBBC6F-EC26-49B5-8D0D-67D9C535924B",
 					"type": "Group",
 					"name": "Dummy",
-					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,100,400,1],
+					"layers": 1,
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,1,4,1],
 					"children": [
 						{
 							"uuid": "60B69C58-4201-43FD-815E-AD2EDFBBD0CE",
 							"type": "PerspectiveCamera",
 							"name": "PerspectiveCamera",
+							"layers": 1,
+							"matrix": [-1,0,0,0,0,1,0,0,0,0,-1,0,0,0,0,1],
 							"fov": 50,
+							"zoom": 1,
+							"near": 0.1,
+							"far": 100,
+							"focus": 10,
 							"aspect": 1,
-							"near": 100,
-							"far": 10000,
-							"matrix": [-1,0,-1.2246468525851679e-16,0,0,1,0,0,1.2246468525851679e-16,0,-1,0,0,0,0,1]
+							"filmGauge": 35,
+							"filmOffset": 0
 						}]
 				},
 				{
 					"uuid": "A460C230-DC88-4A8F-A3FB-AA0FE735F3ED",
 					"type": "Mesh",
 					"name": "Plane",
-					"geometry": "51BB3E54-D2DF-4576-9953-FB8E940588B5",
-					"material": "4AE8130E-B6A8-47BC-ACCF-060973C74044",
-					"matrix": [1,0,0,0,0,0.040785226970911026,-0.9991679191589355,0,0,0.9991679191589355,0.040785226970911026,0,0,-50,0,1]
+					"layers": 1,
+					"matrix": [1,0,0,0,0,0.040785,-0.999168,0,0,0.999168,0.040785,0,0,-0.5,0,1],
+					"geometry": "6D90C4BE-EBA6-4E21-8F54-7CFDAA61F30B",
+					"material": "4AE8130E-B6A8-47BC-ACCF-060973C74044"
 				},
 				{
 					"uuid": "26DAAD69-725D-43B7-AF9D-990A99DEF8C5",
 					"type": "Mesh",
 					"name": "Box",
-					"geometry": "D8E200D3-27BC-49F8-A5C5-7384206E70FE",
-					"material": "B5943856-E404-45D9-A427-4774202C2CD0",
-					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]
+					"layers": 1,
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],
+					"geometry": "D3008B2A-ACDD-43CC-87F7-4F942607D21A",
+					"material": "B5943856-E404-45D9-A427-4774202C2CD0"
 				},
 				{
 					"uuid": "AAAFF2D6-4725-4AFC-A9FE-26419B11011F",
 					"type": "Mesh",
 					"name": "Cylinder",
-					"geometry": "25BA32DB-8B02-4ABA-A77C-69868C464A1A",
-					"material": "3F872310-2067-4BE4-9250-5B3F4E43797E",
-					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,-130,-15,0,1]
+					"layers": 1,
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,-1.3,-0.15,0,1],
+					"geometry": "F482ACD4-013A-49CF-AE0F-C9FF4ADAE409",
+					"material": "3F872310-2067-4BE4-9250-5B3F4E43797E"
 				},
 				{
 					"uuid": "B855E267-A266-4098-ACD6-6A1FDE7B88BA",
 					"type": "Mesh",
 					"name": "Icosahedron",
-					"geometry": "4DECFAB5-6FD1-4D84-9A29-565807B074EA",
-					"material": "E1826901-7922-4584-A25D-6D487E2C9BBD",
-					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,130,-10,0,1]
+					"layers": 1,
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,1.3,-0.1,0,1],
+					"geometry": "51CDDCED-BC71-4B1B-A485-725B6A48204B",
+					"material": "E1826901-7922-4584-A25D-6D487E2C9BBD"
 				},
 				{
 					"uuid": "E2939A7B-5E40-438A-8C1B-32126FBC6892",
 					"type": "PointLight",
 					"name": "PointLight 1",
+					"layers": 1,
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,-0.939,1.271,-1.143,1],
 					"color": 9474221,
 					"intensity": 0.75,
 					"distance": 0,
 					"decay": 1,
-					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,-93.86000061035156,127.12999725341797,-114.30000305175781,1]
+					"shadow": {
+						"camera": {
+							"uuid": "EFF42F46-1E27-4B36-B9D9-CF7D879D258E",
+							"type": "PerspectiveCamera",
+							"layers": 1,
+							"fov": 90,
+							"zoom": 1,
+							"near": 0.5,
+							"far": 500,
+							"focus": 10,
+							"aspect": 1,
+							"filmGauge": 35,
+							"filmOffset": 0
+						}
+					}
 				},
 				{
 					"uuid": "3412781E-27CC-43C3-A5DB-54C0C8E42ED6",
 					"type": "PointLight",
 					"name": "PointLight 2",
+					"layers": 1,
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0.881,0.083,1.254,1],
 					"color": 12773063,
 					"intensity": 1,
 					"distance": 0,
 					"decay": 1,
-					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,88.12999725341797,8.3100004196167,125.44999694824219,1]
-				}]
+					"shadow": {
+						"camera": {
+							"uuid": "81E800FE-E8A7-4A9E-AFAA-4F04FD56AFE4",
+							"type": "PerspectiveCamera",
+							"layers": 1,
+							"fov": 90,
+							"zoom": 1,
+							"near": 0.5,
+							"far": 500,
+							"focus": 10,
+							"aspect": 1,
+							"filmGauge": 35,
+							"filmOffset": 0
+						}
+					}
+				}],
+			"background": 11184810
 		}
 	},
 	"scripts": {
@@ -183,7 +246,7 @@
 		"B7CBBC6F-EC26-49B5-8D0D-67D9C535924B": [
 			{
 				"name": "Orbit",
-				"source": "function update( event ) {\n\n\tvar time = event.time * 0.001;\n\n\tthis.position.x = Math.sin( time ) * 400;\n\tthis.position.z = Math.cos( time ) * 400;\n\tthis.lookAt( scene.position );\n\n}"
+				"source": "function update( event ) {\n\n\tvar time = event.time * 0.001;\n\n\tthis.position.x = Math.sin( time ) * 4;\n\tthis.position.z = Math.cos( time ) * 4;\n\tthis.lookAt( scene.position );\n\n}"
 			}]
 	}
 }

+ 53 - 17
editor/examples/particles.app.json

@@ -3,42 +3,45 @@
 		"type": "App"
 	},
 	"project": {
+		"gammaInput": true,
+		"gammaOutput": true,
 		"shadows": true,
 		"vr": false
 	},
 	"camera": {
 		"metadata": {
-			"version": 4.4,
+			"version": 4.5,
 			"type": "Object",
 			"generator": "Object3D.toJSON"
 		},
 		"object": {
-			"uuid": "763F3000-7D7C-4BE6-80B6-914DEEBD9AA2",
+			"uuid": "056199EB-6985-481B-97CC-A57FB7C87809",
 			"type": "PerspectiveCamera",
 			"name": "Camera",
-			"matrix": [0.7071067690849304,-3.398992198810902e-11,-0.7071068286895752,0,-0.2357022613286972,0.9428090453147888,-0.235702246427536,0,0.6666666865348816,0.3333333134651184,0.6666666269302368,0,41.824005126953125,20.912002563476562,41.824005126953125,1],
+			"layers": 1,
+			"matrix": [0.707107,0,-0.707107,0,-0.235702,0.942809,-0.235702,0,0.666667,0.333333,0.666667,0,4.182,2.091,4.182,1],
 			"fov": 50,
 			"zoom": 1,
 			"near": 0.1,
 			"far": 100000,
 			"focus": 10,
-			"aspect": 0.46657381615598886,
+			"aspect": 0.666193,
 			"filmGauge": 35,
 			"filmOffset": 0
 		}
 	},
 	"scene": {
 		"metadata": {
-			"version": 4.4,
+			"version": 4.5,
 			"type": "Object",
 			"generator": "Object3D.toJSON"
 		},
 		"geometries": [
 			{
-				"uuid": "E80D9EC5-D722-4812-8226-5F355EAC9B96",
+				"uuid": "C3C0CE7D-10B8-43FC-8F74-011CC6E57800",
 				"type": "PlaneGeometry",
-				"width": 1000,
-				"height": 1000,
+				"width": 100,
+				"height": 100,
 				"widthSegments": 1,
 				"heightSegments": 1
 			}],
@@ -49,51 +52,84 @@
 				"color": 5465019,
 				"roughness": 1,
 				"metalness": 0,
-				"emissive": 0
+				"emissive": 0,
+				"depthFunc": 3,
+				"depthTest": true,
+				"depthWrite": true
 			},
 			{
 				"uuid": "F5361474-F5F1-412F-8D99-3699B868092D",
 				"type": "SpriteMaterial",
-				"color": 16777215
+				"color": 16777215,
+				"transparent": true,
+				"depthFunc": 3,
+				"depthTest": true,
+				"depthWrite": true
 			}],
 		"object": {
 			"uuid": "3741222A-BD8F-401C-A5D2-5A907E891896",
 			"type": "Scene",
 			"name": "Scene",
+			"layers": 1,
 			"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],
 			"children": [
 				{
 					"uuid": "05B57416-1BE5-4A96-BB05-9D9CD112D52B",
 					"type": "Mesh",
 					"name": "Ground",
-					"matrix": [1,0,0,0,0,0.0007959486683830619,-0.9999997019767761,0,0,0.9999997019767761,0.0007959486683830619,0,0,-0.5,0,1],
-					"geometry": "E80D9EC5-D722-4812-8226-5F355EAC9B96",
+					"layers": 1,
+					"matrix": [1,0,0,0,0,0.000796,-1,0,0,1,0.000796,0,0,-0.5,0,1],
+					"geometry": "C3C0CE7D-10B8-43FC-8F74-011CC6E57800",
 					"material": "3A9449D2-62DB-4BB4-ABBD-6F3F9D46DE1A"
 				},
 				{
 					"uuid": "0A3CB873-07E6-4EEB-830B-68192504111B",
 					"type": "Sprite",
 					"name": "Particle",
-					"matrix": [0.4000000059604645,0,0,0,0,0.4000000059604645,0,0,0,0,0.4000000059604645,0,0,0,0,1],
+					"layers": 1,
+					"matrix": [0.04,0,0,0,0,0.04,0,0,0,0,0.04,0,0,0,0,1],
 					"material": "F5361474-F5F1-412F-8D99-3699B868092D"
 				},
 				{
 					"uuid": "40E5CDA4-0E39-4265-9293-3E9EC3207F61",
 					"type": "PointLight",
 					"name": "PointLight",
-					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,11.828879356384277,0,1],
+					"layers": 1,
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,1.183,0,1],
 					"color": 16777215,
 					"intensity": 1,
 					"distance": 0,
-					"decay": 1
-				}]
+					"decay": 1,
+					"shadow": {
+						"camera": {
+							"uuid": "B6D3493E-E5C9-4D65-9E26-BB788D127BE1",
+							"type": "PerspectiveCamera",
+							"layers": 1,
+							"fov": 90,
+							"zoom": 1,
+							"near": 0.5,
+							"far": 500,
+							"focus": 10,
+							"aspect": 1,
+							"filmGauge": 35,
+							"filmOffset": 0
+						}
+					}
+				}],
+			"background": 2171689,
+			"fog": {
+				"type": "Fog",
+				"color": 2171688,
+				"near": 1,
+				"far": 50
+			}
 		}
 	},
 	"scripts": {
 		"3741222A-BD8F-401C-A5D2-5A907E891896": [
 			{
 				"name": "Fountain",
-				"source": "var original = this.getObjectByName( 'Particle' );\n\nvar particles = [];\n\nfor ( var i = 0; i < 100; i ++ ) {\n\n\tvar particle = original.clone();\n\tparticle.userData.velocity = new THREE.Vector3();\n\tthis.add( particle );\n\n\tparticles.push( particle );\n\n}\n\nfunction update( event ) {\n\t\n\tvar particle = particles.shift();\n\tparticles.push( particle );\n\t\t\n\tvar velocity = particle.userData.velocity;\n\tvelocity.x = Math.random() - 0.5;\n\tvelocity.y = Math.random() + 1;\n\tvelocity.z = Math.random() - 0.5;\n\n\tfor ( var i = 0; i < particles.length; i ++ ) {\n\n\t\tvar particle = particles[ i ];\n\n\t\tvar velocity = particle.userData.velocity;\n\n\t\tvelocity.y -= 0.098;\n\n\t\tparticle.position.add( velocity );\n\n\t\tif ( particle.position.y < 0 ) {\n\n\t\t\tparticle.position.y = 0;\n\n\t\t\tvelocity.y = - velocity.y;\n\t\t\tvelocity.multiplyScalar( 0.6 );\n\n\t\t}\n\n\t}\n\n}"
+				"source": "var original = this.getObjectByName( 'Particle' );\n\nvar particles = [];\n\nfor ( var i = 0; i < 100; i ++ ) {\n\n\tvar particle = original.clone();\n\tparticle.userData.velocity = new THREE.Vector3();\n\tthis.add( particle );\n\n\tparticles.push( particle );\n\n}\n\nfunction update( event ) {\n\t\n\tvar particle = particles.shift();\n\tparticles.push( particle );\n\t\t\n\tvar velocity = particle.userData.velocity;\n\tvelocity.x = Math.random() * 0.1 - 0.05;\n\tvelocity.y = Math.random() * 0.1 + 0.1;\n\tvelocity.z = Math.random() * 0.1 - 0.05;\n\n\tfor ( var i = 0; i < particles.length; i ++ ) {\n\n\t\tvar particle = particles[ i ];\n\n\t\tvar velocity = particle.userData.velocity;\n\n\t\tvelocity.y -= 0.0098;\n\n\t\tparticle.position.add( velocity );\n\n\t\tif ( particle.position.y < 0 ) {\n\n\t\t\tparticle.position.y = 0;\n\n\t\t\tvelocity.y = - velocity.y;\n\t\t\tvelocity.multiplyScalar( 0.6 );\n\n\t\t}\n\n\t}\n\n}"
 			}]
 	}
 }

+ 74 - 39
editor/examples/pong.app.json

@@ -3,69 +3,74 @@
 		"type": "App"
 	},
 	"project": {
-		"shadows": false,
+		"gammaInput": true,
+		"gammaOutput": true,
+		"shadows": true,
 		"vr": false
 	},
 	"camera": {
 		"metadata": {
-			"version": 4.4,
+			"version": 4.5,
 			"type": "Object",
 			"generator": "Object3D.toJSON"
 		},
 		"object": {
-			"uuid": "B901700E-2B1B-4D74-9201-164193F8304E",
+			"uuid": "4AC7ADED-CC22-4B16-8218-2E0A0C38C8F8",
 			"type": "PerspectiveCamera",
 			"name": "Camera",
-			"matrix": [0.9522120356559753,4.608077919243669e-9,-0.3054378032684326,0,-0.17742955684661865,0.8139732480049133,-0.553142249584198,0,0.24861818552017212,0.5809023976325989,0.7750750780105591,0,18.645999908447266,43.56800079345703,58.13100051879883,1],
-			"focalLength": 10,
-			"zoom": 1,
+			"layers": 1,
+			"matrix": [0.952212,0,-0.305438,0,-0.17743,0.813973,-0.553142,0,0.248618,0.580902,0.775075,0,1.865,4.357,5.813,1],
 			"fov": 50,
-			"aspect": 1.3217270194986073,
+			"zoom": 1,
 			"near": 0.1,
-			"far": 100000
+			"far": 100000,
+			"focus": 10,
+			"aspect": 1.428977,
+			"filmGauge": 35,
+			"filmOffset": 0
 		}
 	},
 	"scene": {
 		"metadata": {
-			"version": 4.4,
+			"version": 4.5,
 			"type": "Object",
 			"generator": "Object3D.toJSON"
 		},
 		"geometries": [
 			{
-				"uuid": "713F75F5-5D04-4069-89CB-2035F5619AC3",
+				"uuid": "490CEBA3-6A25-4BE1-B517-C5FB11A5D18A",
 				"type": "PlaneGeometry",
-				"width": 60,
-				"height": 40,
+				"width": 6,
+				"height": 4,
 				"widthSegments": 1,
 				"heightSegments": 1
 			},
 			{
-				"uuid": "4537EA66-3CD6-43A1-97A9-EB59F3258BF9",
+				"uuid": "D9A92F2D-2F08-4851-99C7-12D8D1CA13C7",
 				"type": "BoxGeometry",
-				"width": 1,
-				"height": 1,
-				"depth": 1,
+				"width": 0.1,
+				"height": 0.1,
+				"depth": 0.1,
 				"widthSegments": 1,
 				"heightSegments": 1,
 				"depthSegments": 1
 			},
 			{
-				"uuid": "3C546CA4-FF0F-4BA1-9406-0CD0D560A396",
+				"uuid": "5E63B8CF-E225-4ABC-994A-4D06BD4E21EB",
 				"type": "BoxGeometry",
-				"width": 2,
-				"height": 2,
-				"depth": 10,
+				"width": 0.2,
+				"height": 0.2,
+				"depth": 1,
 				"widthSegments": 1,
 				"heightSegments": 1,
 				"depthSegments": 1
 			},
 			{
-				"uuid": "4628F4A7-D572-45C2-9A67-807D71FF19EC",
+				"uuid": "D61532B4-24C3-4BC4-B56B-7245E8163E09",
 				"type": "BoxGeometry",
-				"width": 2,
-				"height": 2,
-				"depth": 10,
+				"width": 0.2,
+				"height": 0.2,
+				"depth": 1,
 				"widthSegments": 1,
 				"heightSegments": 1,
 				"depthSegments": 1
@@ -77,7 +82,10 @@
 				"color": 16777215,
 				"emissive": 0,
 				"specular": 16777215,
-				"shininess": 30
+				"shininess": 30,
+				"depthFunc": 3,
+				"depthTest": true,
+				"depthWrite": true
 			},
 			{
 				"uuid": "B1CAF098-FE36-45E1-BEBE-8D6AC04821CC",
@@ -85,7 +93,10 @@
 				"color": 16711680,
 				"emissive": 0,
 				"specular": 1118481,
-				"shininess": 30
+				"shininess": 30,
+				"depthFunc": 3,
+				"depthTest": true,
+				"depthWrite": true
 			},
 			{
 				"uuid": "FBDBE66D-B613-4741-802D-5AE1DE07DE46",
@@ -93,61 +104,85 @@
 				"color": 2752767,
 				"emissive": 0,
 				"specular": 1118481,
-				"shininess": 30
+				"shininess": 30,
+				"depthFunc": 3,
+				"depthTest": true,
+				"depthWrite": true
 			}],
 		"object": {
 			"uuid": "31517222-A9A7-4EAF-B5F6-60751C0BABA3",
 			"type": "Scene",
 			"name": "Scene",
+			"layers": 1,
 			"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],
 			"children": [
 				{
 					"uuid": "B47D0BFC-D63A-4CBB-985E-9C4DBDF086E4",
 					"type": "Mesh",
 					"name": "Ground",
-					"matrix": [1,0,0,0,0,0.0007960238144733012,-0.9999997019767761,0,0,0.9999997019767761,0.0007960238144733012,0,0,-1,0,1],
-					"geometry": "713F75F5-5D04-4069-89CB-2035F5619AC3",
+					"layers": 1,
+					"matrix": [1,0,0,0,0,0.000796,-1,0,0,1,0.000796,0,0,-0.1,0,1],
+					"geometry": "490CEBA3-6A25-4BE1-B517-C5FB11A5D18A",
 					"material": "7EDF7C08-6325-418A-BBAB-89341C694730"
 				},
 				{
 					"uuid": "CE13E58A-4E8B-4F72-9E2E-7DE57C58F989",
 					"type": "Mesh",
 					"name": "Ball",
+					"layers": 1,
 					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],
-					"geometry": "4537EA66-3CD6-43A1-97A9-EB59F3258BF9",
+					"geometry": "D9A92F2D-2F08-4851-99C7-12D8D1CA13C7",
 					"material": "B1CAF098-FE36-45E1-BEBE-8D6AC04821CC"
 				},
 				{
 					"uuid": "2AAEA3AA-EC45-492B-B450-10473D1EC6C5",
 					"type": "Mesh",
 					"name": "Pad 1",
-					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,-24,0,0,1],
-					"geometry": "3C546CA4-FF0F-4BA1-9406-0CD0D560A396",
+					"layers": 1,
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,-2.4,0,0,1],
+					"geometry": "5E63B8CF-E225-4ABC-994A-4D06BD4E21EB",
 					"material": "FBDBE66D-B613-4741-802D-5AE1DE07DE46"
 				},
 				{
 					"uuid": "F1DD46A7-6584-4A37-BC76-852C3911077E",
 					"type": "Mesh",
 					"name": "Pad 2",
-					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,24,0,0,1],
-					"geometry": "4628F4A7-D572-45C2-9A67-807D71FF19EC",
+					"layers": 1,
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,2.4,0,0,1],
+					"geometry": "D61532B4-24C3-4BC4-B56B-7245E8163E09",
 					"material": "FBDBE66D-B613-4741-802D-5AE1DE07DE46"
 				},
 				{
 					"uuid": "C62AAE9F-9E51-46A5-BD2B-71BA804FC0B3",
 					"type": "DirectionalLight",
-					"name": "DirectionalLight 3",
-					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,10,20,15,1],
+					"name": "DirectionalLight",
+					"layers": 1,
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,1,2,1.5,1],
 					"color": 16777215,
-					"intensity": 1
-				}]
+					"intensity": 1,
+					"shadow": {
+						"camera": {
+							"uuid": "2CF1F42A-8992-4E8D-8D94-7CC20979344C",
+							"type": "OrthographicCamera",
+							"layers": 1,
+							"zoom": 1,
+							"left": -5,
+							"right": 5,
+							"top": 5,
+							"bottom": -5,
+							"near": 0.5,
+							"far": 500
+						}
+					}
+				}],
+			"background": 11184810
 		}
 	},
 	"scripts": {
 		"31517222-A9A7-4EAF-B5F6-60751C0BABA3": [
 			{
 				"name": "Game logic",
-				"source": "var ball = this.getObjectByName( 'Ball' );\n\nvar position = ball.position;\n\nvar velocity = new THREE.Vector3();\n\nvar direction = new THREE.Vector3();\ndirection.x = Math.random() - 0.5;\ndirection.z = Math.random() - 0.5;\ndirection.normalize();\n\nvar pad1 = this.getObjectByName( 'Pad 1' );\nvar pad2 = this.getObjectByName( 'Pad 2' );\n\nvar raycaster = new THREE.Raycaster();\nvar objects = [ pad1, pad2 ];\n\n//\n\nfunction mousemove( event ) {\n\n\tpad1.position.z = ( event.clientX / player.width ) * 30 - 15;\n\tpad2.position.z = - pad1.position.z;\n\n}\n\nfunction update( event ) {\n\t\n\tif ( position.x < -30 || position.x > 30 ) direction.x = - direction.x;\n\tif ( position.z < -20 || position.z > 20 ) direction.z = - direction.z;\n\t\n\tposition.x = Math.max( - 30, Math.min( 30, position.x ) );\n\tposition.z = Math.max( - 20, Math.min( 20, position.z ) );\n\t\n\traycaster.set( position, direction );\n\t\n\tvar intersections = raycaster.intersectObjects( objects );\n\t\n\tif ( intersections.length > 0 ) {\n\n\t\tvar intersection = intersections[ 0 ];\n\t\t\n\t\tif ( intersection.distance < 1 ) {\n\t\t\t\n\t\t\tdirection.reflect( intersection.face.normal );\n\t\t\t\n\t\t}\n\t\t\n\t}\n\n\tposition.add( velocity.copy( direction ).multiplyScalar( event.delta / 20 ) );\n\n}"
+				"source": "var ball = this.getObjectByName( 'Ball' );\n\nvar position = ball.position;\n\nvar velocity = new THREE.Vector3();\n\nvar direction = new THREE.Vector3();\ndirection.x = Math.random() - 0.5;\ndirection.z = Math.random() - 0.5;\ndirection.normalize().multiplyScalar( 0.1 );\n\nvar pad1 = this.getObjectByName( 'Pad 1' );\nvar pad2 = this.getObjectByName( 'Pad 2' );\n\nvar raycaster = new THREE.Raycaster();\nvar objects = [ pad1, pad2 ];\n\n//\n\nfunction mousemove( event ) {\n\n\tpad1.position.z = ( event.clientX / player.width ) * 3 - 1.5;\n\tpad2.position.z = - pad1.position.z;\n\n}\n\nfunction update( event ) {\n\t\n\tif ( position.x < -3 || position.x > 3 ) direction.x = - direction.x;\n\tif ( position.z < -2 || position.z > 2 ) direction.z = - direction.z;\n\t\n\tposition.x = Math.max( - 3, Math.min( 3, position.x ) );\n\tposition.z = Math.max( - 2, Math.min( 2, position.z ) );\n\t\n\traycaster.set( position, direction );\n\t\n\tvar intersections = raycaster.intersectObjects( objects );\n\t\n\tif ( intersections.length > 0 ) {\n\n\t\tvar intersection = intersections[ 0 ];\n\t\t\n\t\tif ( intersection.distance < 0.1 ) {\n\t\t\t\n\t\t\tdirection.reflect( intersection.face.normal );\n\t\t\t\n\t\t}\n\t\t\n\t}\n\n\tposition.add( velocity.copy( direction ).multiplyScalar( event.delta / 20 ) );\n\n}"
 			}]
 	}
 }

+ 8 - 7
editor/examples/shaders.app.json

@@ -10,28 +10,29 @@
 	},
 	"camera": {
 		"metadata": {
-			"version": 4.4,
+			"version": 4.5,
 			"type": "Object",
 			"generator": "Object3D.toJSON"
 		},
 		"object": {
-			"uuid": "FC3E973B-5A4A-4177-BD9C-A58E61E0593B",
+			"uuid": "4AC7ADED-CC22-4B16-8218-2E0A0C38C8F8",
 			"type": "PerspectiveCamera",
 			"name": "Camera",
+			"layers": 1,
 			"matrix": [0.605503,0,-0.795843,0,-0.261526,0.944464,-0.198978,0,0.751645,0.328615,0.571876,0,2.571484,1.124239,1.956469,1],
 			"fov": 50,
 			"zoom": 1,
 			"near": 0.1,
 			"far": 10000,
 			"focus": 10,
-			"aspect": 1.368715,
+			"aspect": 1.428977,
 			"filmGauge": 35,
 			"filmOffset": 0
 		}
 	},
 	"scene": {
 		"metadata": {
-			"version": 4.4,
+			"version": 4.5,
 			"type": "Object",
 			"generator": "Object3D.toJSON"
 		},
@@ -50,11 +51,9 @@
 				"depthTest": true,
 				"depthWrite": true,
 				"wireframe": true,
-				"skinning": false,
-				"morphTargets": false,
 				"uniforms": {
 					"time": {
-						"value": 0.0
+						"value": 0
 					}
 				},
 				"vertexShader": "uniform float time;\nvarying vec3 vPosition;\nvoid main() {\n\tvPosition = position;\n\tvPosition.x += sin( time + vPosition.z * 4.0 ) / 4.0;\n\tvPosition.y += cos( time + vPosition.z * 4.0 ) / 4.0;\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( vPosition, 1.0 );\n}",
@@ -64,12 +63,14 @@
 			"uuid": "5FC9ACA9-2A93-474D-AA32-FACC76551914",
 			"type": "Scene",
 			"name": "Scene",
+			"layers": 1,
 			"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],
 			"children": [
 				{
 					"uuid": "FC7B6CF2-6386-4F47-9CE6-8ADB9FCA6E1F",
 					"type": "Mesh",
 					"name": "Icosahedron 1",
+					"layers": 1,
 					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],
 					"geometry": "EA781333-F3AE-470D-9110-A9724FCB42AA",
 					"material": "50ED51F1-DEA4-4B61-8082-BF41609E8C27"

+ 3 - 3
editor/index.html

@@ -181,15 +181,15 @@
 			var viewport = new Viewport( editor );
 			document.body.appendChild( viewport.dom );
 
+			var toolbar = new Toolbar( editor );
+			document.body.appendChild( toolbar.dom );
+
 			var script = new Script( editor );
 			document.body.appendChild( script.dom );
 
 			var player = new Player( editor );
 			document.body.appendChild( player.dom );
 
-			var toolbar = new Toolbar( editor );
-			document.body.appendChild( toolbar.dom );
-
 			var menubar = new Menubar( editor );
 			document.body.appendChild( menubar.dom );
 

+ 9 - 3
editor/js/Toolbar.js

@@ -8,6 +8,7 @@ var Toolbar = function ( editor ) {
 
 	var container = new UI.Panel();
 	container.setId( 'toolbar' );
+	container.setDisplay( 'none' );
 
 	var buttons = new UI.Panel();
 	container.add( buttons );
@@ -15,7 +16,6 @@ var Toolbar = function ( editor ) {
 	// translate / rotate / scale
 
 	var translate = new UI.Button( 'translate' );
-	translate.dom.title = 'W';
 	translate.dom.className = 'Button selected';
 	translate.onClick( function () {
 
@@ -25,7 +25,6 @@ var Toolbar = function ( editor ) {
 	buttons.add( translate );
 
 	var rotate = new UI.Button( 'rotate' );
-	rotate.dom.title = 'E';
 	rotate.onClick( function () {
 
 		signals.transformModeChanged.dispatch( 'rotate' );
@@ -34,7 +33,6 @@ var Toolbar = function ( editor ) {
 	buttons.add( rotate );
 
 	var scale = new UI.Button( 'scale' );
-	scale.dom.title = 'R';
 	scale.onClick( function () {
 
 		signals.transformModeChanged.dispatch( 'scale' );
@@ -50,6 +48,14 @@ var Toolbar = function ( editor ) {
 	} );
 	buttons.add( local );
 
+	//
+
+	signals.objectSelected.add( function ( object ) {
+
+		container.setDisplay( object === null ? 'none' : '' );
+
+	} );
+
 	signals.transformModeChanged.add( function ( mode ) {
 
 		translate.dom.classList.remove( 'selected' );

+ 4 - 2
editor/js/libs/app.js

@@ -155,9 +155,11 @@ var APP = {
 
 		}
 
-		var prevTime;
+		var time, prevTime;
 
-		function animate( time ) {
+		function animate() {
+
+			time = performance.now();
 
 			try {
 

+ 13 - 0
examples/js/Detector.js

@@ -18,6 +18,19 @@ var Detector = {
 
 		}
 
+	} )(),
+	webgl2: ( function () {
+
+		try {
+
+			var canvas = document.createElement( 'canvas' ); return !! ( window.WebGL2RenderingContext && ( canvas.getContext( 'webgl2' ) ) );
+
+		} catch ( e ) {
+
+			return false;
+
+		}
+
 	} )(),
 	workers: !! window.Worker,
 	fileapi: window.File && window.FileReader && window.FileList && window.Blob,

+ 769 - 752
examples/js/MarchingCubes.js

@@ -4,548 +4,573 @@
  * Port of http://webglsamples.org/blob/blob.html
  */
 
-THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors ) {
+( function ( THREE ) {
 
-	THREE.ImmediateRenderObject.call( this, material );
+	THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors ) {
 
-	var scope = this;
+		THREE.ImmediateRenderObject.call( this, material );
 
-	// temp buffers used in polygonize
+		var scope = this;
 
-	var vlist = new Float32Array( 12 * 3 );
-	var nlist = new Float32Array( 12 * 3 );
+		var yd, zd;
+		var field, normal_cache;
 
-	this.enableUvs = enableUvs !== undefined ? enableUvs : false;
-	this.enableColors = enableColors !== undefined ? enableColors : false;
+		// temp buffers used in polygonize
 
-	// functions have to be object properties
-	// prototype functions kill performance
-	// (tested and it was 4x slower !!!)
+		var vlist = new Float32Array( 12 * 3 );
+		var nlist = new Float32Array( 12 * 3 );
 
-	this.init = function ( resolution ) {
+		this.enableUvs = enableUvs !== undefined ? enableUvs : false;
+		this.enableColors = enableColors !== undefined ? enableColors : false;
 
-		this.resolution = resolution;
+		// functions have to be object properties
+		// prototype functions kill performance
+		// (tested and it was 4x slower !!!)
 
-		// parameters
+		this.init = function ( resolution ) {
 
-		this.isolation = 80.0;
+			this.resolution = resolution;
 
-		// size of field, 32 is pushing it in Javascript :)
+			// parameters
 
-		this.size = resolution;
-		this.size2 = this.size * this.size;
-		this.size3 = this.size2 * this.size;
-		this.halfsize = this.size / 2.0;
+			this.isolation = 80.0;
 
-		// deltas
+			// size of field, 32 is pushing it in Javascript :)
 
-		this.delta = 2.0 / this.size;
-		this.yd = this.size;
-		this.zd = this.size2;
+			this.size = resolution;
+			this.size2 = this.size * this.size;
+			this.size3 = this.size2 * this.size;
+			this.halfsize = this.size / 2.0;
 
-		this.field = new Float32Array( this.size3 );
-		this.normal_cache = new Float32Array( this.size3 * 3 );
+			// deltas
 
-		// immediate render mode simulator
+			this.delta = 2.0 / this.size;
 
-		this.maxCount = 4096; // TODO: find the fastest size for this buffer
-		this.count = 0;
+			yd = this.size;
+			zd = this.size2;
 
-		this.hasPositions = false;
-		this.hasNormals = false;
-		this.hasColors = false;
-		this.hasUvs = false;
+			field = new Float32Array( this.size3 );
+			normal_cache = new Float32Array( this.size3 * 3 );
 
-		this.positionArray = new Float32Array( this.maxCount * 3 );
-		this.normalArray = new Float32Array( this.maxCount * 3 );
+			// immediate render mode simulator
 
-		if ( this.enableUvs ) {
+			this.maxCount = 4096; // TODO: find the fastest size for this buffer
+			this.count = 0;
 
-			this.uvArray = new Float32Array( this.maxCount * 2 );
+			this.hasPositions = false;
+			this.hasNormals = false;
+			this.hasColors = false;
+			this.hasUvs = false;
 
-		}
+			this.positionArray = new Float32Array( this.maxCount * 3 );
+			this.normalArray = new Float32Array( this.maxCount * 3 );
 
-		if ( this.enableColors ) {
+			if ( this.enableUvs ) {
 
-			this.colorArray = new Float32Array( this.maxCount * 3 );
+				this.uvArray = new Float32Array( this.maxCount * 2 );
 
-		}
+			}
 
-	};
+			if ( this.enableColors ) {
 
-	///////////////////////
-	// Polygonization
-	///////////////////////
+				this.colorArray = new Float32Array( this.maxCount * 3 );
 
-	function lerp( a, b, t ) {
+			}
 
-		return a + ( b - a ) * t;
+		};
 
-	}
+		///////////////////////
+		// Polygonization
+		///////////////////////
 
-	function VIntX( q, offset, isol, x, y, z, valp1, valp2 ) {
+		function lerp( a, b, t ) {
 
-		var mu = ( isol - valp1 ) / ( valp2 - valp1 ),
-			nc = scope.normal_cache;
+			return a + ( b - a ) * t;
 
-		vlist[ offset + 0 ] = x + mu * scope.delta;
-		vlist[ offset + 1 ] = y;
-		vlist[ offset + 2 ] = z;
+		}
 
-		nlist[ offset + 0 ] = lerp( nc[ q + 0 ], nc[ q + 3 ], mu );
-		nlist[ offset + 1 ] = lerp( nc[ q + 1 ], nc[ q + 4 ], mu );
-		nlist[ offset + 2 ] = lerp( nc[ q + 2 ], nc[ q + 5 ], mu );
+		function VIntX( q, offset, isol, x, y, z, valp1, valp2 ) {
 
-	}
+			var mu = ( isol - valp1 ) / ( valp2 - valp1 );
 
-	function VIntY( q, offset, isol, x, y, z, valp1, valp2 ) {
+			vlist[ offset + 0 ] = x + mu * scope.delta;
+			vlist[ offset + 1 ] = y;
+			vlist[ offset + 2 ] = z;
 
-		var mu = ( isol - valp1 ) / ( valp2 - valp1 ),
-			nc = scope.normal_cache;
+			nlist[ offset + 0 ] = lerp( normal_cache[ q + 0 ], normal_cache[ q + 3 ], mu );
+			nlist[ offset + 1 ] = lerp( normal_cache[ q + 1 ], normal_cache[ q + 4 ], mu );
+			nlist[ offset + 2 ] = lerp( normal_cache[ q + 2 ], normal_cache[ q + 5 ], mu );
 
-		vlist[ offset + 0 ] = x;
-		vlist[ offset + 1 ] = y + mu * scope.delta;
-		vlist[ offset + 2 ] = z;
+		}
 
-		var q2 = q + scope.yd * 3;
+		function VIntY( q, offset, isol, x, y, z, valp1, valp2 ) {
 
-		nlist[ offset + 0 ] = lerp( nc[ q + 0 ], nc[ q2 + 0 ], mu );
-		nlist[ offset + 1 ] = lerp( nc[ q + 1 ], nc[ q2 + 1 ], mu );
-		nlist[ offset + 2 ] = lerp( nc[ q + 2 ], nc[ q2 + 2 ], mu );
+			var mu = ( isol - valp1 ) / ( valp2 - valp1 );
 
-	}
+			vlist[ offset + 0 ] = x;
+			vlist[ offset + 1 ] = y + mu * scope.delta;
+			vlist[ offset + 2 ] = z;
 
-	function VIntZ( q, offset, isol, x, y, z, valp1, valp2 ) {
+			var q2 = q + yd * 3;
 
-		var mu = ( isol - valp1 ) / ( valp2 - valp1 ),
-			nc = scope.normal_cache;
+			nlist[ offset + 0 ] = lerp( normal_cache[ q + 0 ], normal_cache[ q2 + 0 ], mu );
+			nlist[ offset + 1 ] = lerp( normal_cache[ q + 1 ], normal_cache[ q2 + 1 ], mu );
+			nlist[ offset + 2 ] = lerp( normal_cache[ q + 2 ], normal_cache[ q2 + 2 ], mu );
 
-		vlist[ offset + 0 ] = x;
-		vlist[ offset + 1 ] = y;
-		vlist[ offset + 2 ] = z + mu * scope.delta;
+		}
 
-		var q2 = q + scope.zd * 3;
+		function VIntZ( q, offset, isol, x, y, z, valp1, valp2 ) {
 
-		nlist[ offset + 0 ] = lerp( nc[ q + 0 ], nc[ q2 + 0 ], mu );
-		nlist[ offset + 1 ] = lerp( nc[ q + 1 ], nc[ q2 + 1 ], mu );
-		nlist[ offset + 2 ] = lerp( nc[ q + 2 ], nc[ q2 + 2 ], mu );
+			var mu = ( isol - valp1 ) / ( valp2 - valp1 );
 
-	}
+			vlist[ offset + 0 ] = x;
+			vlist[ offset + 1 ] = y;
+			vlist[ offset + 2 ] = z + mu * scope.delta;
 
-	function compNorm( q ) {
+			var q2 = q + zd * 3;
 
-		var q3 = q * 3;
+			nlist[ offset + 0 ] = lerp( normal_cache[ q + 0 ], normal_cache[ q2 + 0 ], mu );
+			nlist[ offset + 1 ] = lerp( normal_cache[ q + 1 ], normal_cache[ q2 + 1 ], mu );
+			nlist[ offset + 2 ] = lerp( normal_cache[ q + 2 ], normal_cache[ q2 + 2 ], mu );
 
-		if ( scope.normal_cache[ q3 ] === 0.0 ) {
+		}
 
-			scope.normal_cache[ q3 + 0 ] = scope.field[ q - 1 ] - scope.field[ q + 1 ];
-			scope.normal_cache[ q3 + 1 ] = scope.field[ q - scope.yd ] - scope.field[ q + scope.yd ];
-			scope.normal_cache[ q3 + 2 ] = scope.field[ q - scope.zd ] - scope.field[ q + scope.zd ];
+		function compNorm( q ) {
 
-		}
+			var q3 = q * 3;
 
-	}
+			if ( normal_cache[ q3 ] === 0.0 ) {
 
-	// Returns total number of triangles. Fills triangles.
-	// (this is where most of time is spent - it's inner work of O(n3) loop )
+				normal_cache[ q3 + 0 ] = field[ q - 1 ] - field[ q + 1 ];
+				normal_cache[ q3 + 1 ] = field[ q - yd ] - field[ q + yd ];
+				normal_cache[ q3 + 2 ] = field[ q - zd ] - field[ q + zd ];
 
-	function polygonize( fx, fy, fz, q, isol, renderCallback ) {
+			}
 
-		// cache indices
-		var q1 = q + 1,
-			qy = q + scope.yd,
-			qz = q + scope.zd,
-			q1y = q1 + scope.yd,
-			q1z = q1 + scope.zd,
-			qyz = q + scope.yd + scope.zd,
-			q1yz = q1 + scope.yd + scope.zd;
+		}
 
-		var cubeindex = 0,
-			field0 = scope.field[ q ],
-			field1 = scope.field[ q1 ],
-			field2 = scope.field[ qy ],
-			field3 = scope.field[ q1y ],
-			field4 = scope.field[ qz ],
-			field5 = scope.field[ q1z ],
-			field6 = scope.field[ qyz ],
-			field7 = scope.field[ q1yz ];
+		// Returns total number of triangles. Fills triangles.
+		// (this is where most of time is spent - it's inner work of O(n3) loop )
+
+		function polygonize( fx, fy, fz, q, isol, renderCallback ) {
+
+			// cache indices
+			var q1 = q + 1,
+				qy = q + yd,
+				qz = q + zd,
+				q1y = q1 + yd,
+				q1z = q1 + zd,
+				qyz = q + yd + zd,
+				q1yz = q1 + yd + zd;
+
+			var cubeindex = 0,
+				field0 = field[ q ],
+				field1 = field[ q1 ],
+				field2 = field[ qy ],
+				field3 = field[ q1y ],
+				field4 = field[ qz ],
+				field5 = field[ q1z ],
+				field6 = field[ qyz ],
+				field7 = field[ q1yz ];
+
+			if ( field0 < isol ) cubeindex |= 1;
+			if ( field1 < isol ) cubeindex |= 2;
+			if ( field2 < isol ) cubeindex |= 8;
+			if ( field3 < isol ) cubeindex |= 4;
+			if ( field4 < isol ) cubeindex |= 16;
+			if ( field5 < isol ) cubeindex |= 32;
+			if ( field6 < isol ) cubeindex |= 128;
+			if ( field7 < isol ) cubeindex |= 64;
+
+			// if cube is entirely in/out of the surface - bail, nothing to draw
+
+			var bits = EdgeTable[ cubeindex ];
+			if ( bits === 0 ) return 0;
+
+			var d = scope.delta,
+				fx2 = fx + d,
+				fy2 = fy + d,
+				fz2 = fz + d;
+
+			// top of the cube
+
+			if ( bits & 1 ) {
+
+				compNorm( q );
+				compNorm( q1 );
+				VIntX( q * 3, 0, isol, fx, fy, fz, field0, field1 );
 
-		if ( field0 < isol ) cubeindex |= 1;
-		if ( field1 < isol ) cubeindex |= 2;
-		if ( field2 < isol ) cubeindex |= 8;
-		if ( field3 < isol ) cubeindex |= 4;
-		if ( field4 < isol ) cubeindex |= 16;
-		if ( field5 < isol ) cubeindex |= 32;
-		if ( field6 < isol ) cubeindex |= 128;
-		if ( field7 < isol ) cubeindex |= 64;
+			}
 
-		// if cube is entirely in/out of the surface - bail, nothing to draw
+			if ( bits & 2 ) {
 
-		var bits = THREE.edgeTable[ cubeindex ];
-		if ( bits === 0 ) return 0;
+				compNorm( q1 );
+				compNorm( q1y );
+				VIntY( q1 * 3, 3, isol, fx2, fy, fz, field1, field3 );
 
-		var d = scope.delta,
-			fx2 = fx + d,
-			fy2 = fy + d,
-			fz2 = fz + d;
+			}
 
-		// top of the cube
+			if ( bits & 4 ) {
 
-		if ( bits & 1 ) {
+				compNorm( qy );
+				compNorm( q1y );
+				VIntX( qy * 3, 6, isol, fx, fy2, fz, field2, field3 );
 
-			compNorm( q );
-			compNorm( q1 );
-			VIntX( q * 3, 0, isol, fx, fy, fz, field0, field1 );
+			}
 
-		}
+			if ( bits & 8 ) {
 
-		if ( bits & 2 ) {
+				compNorm( q );
+				compNorm( qy );
+				VIntY( q * 3, 9, isol, fx, fy, fz, field0, field2 );
 
-			compNorm( q1 );
-			compNorm( q1y );
-			VIntY( q1 * 3, 3, isol, fx2, fy, fz, field1, field3 );
+			}
 
-		}
+			// bottom of the cube
 
-		if ( bits & 4 ) {
+			if ( bits & 16 ) {
 
-			compNorm( qy );
-			compNorm( q1y );
-			VIntX( qy * 3, 6, isol, fx, fy2, fz, field2, field3 );
+				compNorm( qz );
+				compNorm( q1z );
+				VIntX( qz * 3, 12, isol, fx, fy, fz2, field4, field5 );
 
-		}
+			}
 
-		if ( bits & 8 ) {
+			if ( bits & 32 ) {
 
-			compNorm( q );
-			compNorm( qy );
-			VIntY( q * 3, 9, isol, fx, fy, fz, field0, field2 );
+				compNorm( q1z );
+				compNorm( q1yz );
+				VIntY( q1z * 3, 15, isol, fx2, fy, fz2, field5, field7 );
 
-		}
+			}
 
-		// bottom of the cube
+			if ( bits & 64 ) {
 
-		if ( bits & 16 ) {
+				compNorm( qyz );
+				compNorm( q1yz );
+				VIntX( qyz * 3, 18, isol, fx, fy2, fz2, field6, field7 );
 
-			compNorm( qz );
-			compNorm( q1z );
-			VIntX( qz * 3, 12, isol, fx, fy, fz2, field4, field5 );
+			}
 
-		}
+			if ( bits & 128 ) {
 
-		if ( bits & 32 ) {
+				compNorm( qz );
+				compNorm( qyz );
+				VIntY( qz * 3, 21, isol, fx, fy, fz2, field4, field6 );
 
-			compNorm( q1z );
-			compNorm( q1yz );
-			VIntY( q1z * 3, 15, isol, fx2, fy, fz2, field5, field7 );
+			}
 
-		}
+			// vertical lines of the cube
 
-		if ( bits & 64 ) {
+			if ( bits & 256 ) {
 
-			compNorm( qyz );
-			compNorm( q1yz );
-			VIntX( qyz * 3, 18, isol, fx, fy2, fz2, field6, field7 );
+				compNorm( q );
+				compNorm( qz );
+				VIntZ( q * 3, 24, isol, fx, fy, fz, field0, field4 );
 
-		}
+			}
 
-		if ( bits & 128 ) {
+			if ( bits & 512 ) {
 
-			compNorm( qz );
-			compNorm( qyz );
-			VIntY( qz * 3, 21, isol, fx, fy, fz2, field4, field6 );
+				compNorm( q1 );
+				compNorm( q1z );
+				VIntZ( q1 * 3, 27, isol, fx2, fy, fz, field1, field5 );
 
-		}
+			}
 
-		// vertical lines of the cube
+			if ( bits & 1024 ) {
 
-		if ( bits & 256 ) {
+				compNorm( q1y );
+				compNorm( q1yz );
+				VIntZ( q1y * 3, 30, isol, fx2, fy2, fz, field3, field7 );
 
-			compNorm( q );
-			compNorm( qz );
-			VIntZ( q * 3, 24, isol, fx, fy, fz, field0, field4 );
+			}
 
-		}
+			if ( bits & 2048 ) {
 
-		if ( bits & 512 ) {
+				compNorm( qy );
+				compNorm( qyz );
+				VIntZ( qy * 3, 33, isol, fx, fy2, fz, field2, field6 );
 
-			compNorm( q1 );
-			compNorm( q1z );
-			VIntZ( q1 * 3, 27, isol, fx2, fy, fz, field1, field5 );
+			}
 
-		}
+			cubeindex <<= 4; // re-purpose cubeindex into an offset into triTable
 
-		if ( bits & 1024 ) {
+			var o1, o2, o3, numtris = 0, i = 0;
 
-			compNorm( q1y );
-			compNorm( q1yz );
-			VIntZ( q1y * 3, 30, isol, fx2, fy2, fz, field3, field7 );
+			// here is where triangles are created
 
-		}
+			while ( TriTable[ cubeindex + i ] != - 1 ) {
+
+				o1 = cubeindex + i;
+				o2 = o1 + 1;
+				o3 = o1 + 2;
 
-		if ( bits & 2048 ) {
+				posnormtriv( vlist, nlist,
+					3 * TriTable[ o1 ],
+					3 * TriTable[ o2 ],
+					3 * TriTable[ o3 ],
+					renderCallback );
 
-			compNorm( qy );
-			compNorm( qyz );
-			VIntZ( qy * 3, 33, isol, fx, fy2, fz, field2, field6 );
+				i += 3;
+				numtris ++;
+
+			}
+
+			return numtris;
 
 		}
 
-		cubeindex <<= 4; // re-purpose cubeindex into an offset into triTable
+		/////////////////////////////////////
+		// Immediate render mode simulator
+		/////////////////////////////////////
 
-		var o1, o2, o3, numtris = 0, i = 0;
+		function posnormtriv( pos, norm, o1, o2, o3, renderCallback ) {
 
-		// here is where triangles are created
+			var c = scope.count * 3;
 
-		while ( THREE.triTable[ cubeindex + i ] != - 1 ) {
+			// positions
 
-			o1 = cubeindex + i;
-			o2 = o1 + 1;
-			o3 = o1 + 2;
+			scope.positionArray[ c + 0 ] = pos[ o1 ];
+			scope.positionArray[ c + 1 ] = pos[ o1 + 1 ];
+			scope.positionArray[ c + 2 ] = pos[ o1 + 2 ];
 
-			posnormtriv( vlist, nlist,
-				3 * THREE.triTable[ o1 ],
-				3 * THREE.triTable[ o2 ],
-				3 * THREE.triTable[ o3 ],
-				renderCallback );
+			scope.positionArray[ c + 3 ] = pos[ o2 ];
+			scope.positionArray[ c + 4 ] = pos[ o2 + 1 ];
+			scope.positionArray[ c + 5 ] = pos[ o2 + 2 ];
 
-			i += 3;
-			numtris ++;
+			scope.positionArray[ c + 6 ] = pos[ o3 ];
+			scope.positionArray[ c + 7 ] = pos[ o3 + 1 ];
+			scope.positionArray[ c + 8 ] = pos[ o3 + 2 ];
 
-		}
+			// normals
 
-		return numtris;
+			if ( scope.material.flatShading === true ) {
 
-	}
+				var nx = ( norm[ o1 + 0 ] + norm[ o2 + 0 ] + norm[ o3 + 0 ] ) / 3;
+				var ny = ( norm[ o1 + 1 ] + norm[ o2 + 1 ] + norm[ o3 + 1 ] ) / 3;
+				var nz = ( norm[ o1 + 2 ] + norm[ o2 + 2 ] + norm[ o3 + 2 ] ) / 3;
 
-	/////////////////////////////////////
-	// Immediate render mode simulator
-	/////////////////////////////////////
+				scope.normalArray[ c + 0 ] = nx;
+				scope.normalArray[ c + 1 ] = ny;
+				scope.normalArray[ c + 2 ] = nz;
 
-	function posnormtriv( pos, norm, o1, o2, o3, renderCallback ) {
+				scope.normalArray[ c + 3 ] = nx;
+				scope.normalArray[ c + 4 ] = ny;
+				scope.normalArray[ c + 5 ] = nz;
 
-		var c = scope.count * 3;
+				scope.normalArray[ c + 6 ] = nx;
+				scope.normalArray[ c + 7 ] = ny;
+				scope.normalArray[ c + 8 ] = nz;
 
-		// positions
 
-		scope.positionArray[ c + 0 ] = pos[ o1 ];
-		scope.positionArray[ c + 1 ] = pos[ o1 + 1 ];
-		scope.positionArray[ c + 2 ] = pos[ o1 + 2 ];
+			} else {
 
-		scope.positionArray[ c + 3 ] = pos[ o2 ];
-		scope.positionArray[ c + 4 ] = pos[ o2 + 1 ];
-		scope.positionArray[ c + 5 ] = pos[ o2 + 2 ];
+				scope.normalArray[ c + 0 ] = norm[ o1 + 0 ];
+				scope.normalArray[ c + 1 ] = norm[ o1 + 1 ];
+				scope.normalArray[ c + 2 ] = norm[ o1 + 2 ];
 
-		scope.positionArray[ c + 6 ] = pos[ o3 ];
-		scope.positionArray[ c + 7 ] = pos[ o3 + 1 ];
-		scope.positionArray[ c + 8 ] = pos[ o3 + 2 ];
+				scope.normalArray[ c + 3 ] = norm[ o2 + 0 ];
+				scope.normalArray[ c + 4 ] = norm[ o2 + 1 ];
+				scope.normalArray[ c + 5 ] = norm[ o2 + 2 ];
 
-		// normals
+				scope.normalArray[ c + 6 ] = norm[ o3 + 0 ];
+				scope.normalArray[ c + 7 ] = norm[ o3 + 1 ];
+				scope.normalArray[ c + 8 ] = norm[ o3 + 2 ];
 
-		scope.normalArray[ c + 0 ] = norm[ o1 ];
-		scope.normalArray[ c + 1 ] = norm[ o1 + 1 ];
-		scope.normalArray[ c + 2 ] = norm[ o1 + 2 ];
+			}
 
-		scope.normalArray[ c + 3 ] = norm[ o2 ];
-		scope.normalArray[ c + 4 ] = norm[ o2 + 1 ];
-		scope.normalArray[ c + 5 ] = norm[ o2 + 2 ];
+			// uvs
 
-		scope.normalArray[ c + 6 ] = norm[ o3 ];
-		scope.normalArray[ c + 7 ] = norm[ o3 + 1 ];
-		scope.normalArray[ c + 8 ] = norm[ o3 + 2 ];
+			if ( scope.enableUvs ) {
 
-		// uvs
+				var d = scope.count * 2;
 
-		if ( scope.enableUvs ) {
+				scope.uvArray[ d + 0 ] = pos[ o1 + 0 ];
+				scope.uvArray[ d + 1 ] = pos[ o1 + 2 ];
 
-			var d = scope.count * 2;
+				scope.uvArray[ d + 2 ] = pos[ o2 + 0 ];
+				scope.uvArray[ d + 3 ] = pos[ o2 + 2 ];
 
-			scope.uvArray[ d + 0 ] = pos[ o1 ];
-			scope.uvArray[ d + 1 ] = pos[ o1 + 2 ];
+				scope.uvArray[ d + 4 ] = pos[ o3 + 0 ];
+				scope.uvArray[ d + 5 ] = pos[ o3 + 2 ];
 
-			scope.uvArray[ d + 2 ] = pos[ o2 ];
-			scope.uvArray[ d + 3 ] = pos[ o2 + 2 ];
+			}
 
-			scope.uvArray[ d + 4 ] = pos[ o3 ];
-			scope.uvArray[ d + 5 ] = pos[ o3 + 2 ];
+			// colors
 
-		}
+			if ( scope.enableColors ) {
 
-		// colors
+				scope.colorArray[ c + 0 ] = pos[ o1 + 0 ];
+				scope.colorArray[ c + 1 ] = pos[ o1 + 1 ];
+				scope.colorArray[ c + 2 ] = pos[ o1 + 2 ];
 
-		if ( scope.enableColors ) {
+				scope.colorArray[ c + 3 ] = pos[ o2 + 0 ];
+				scope.colorArray[ c + 4 ] = pos[ o2 + 1 ];
+				scope.colorArray[ c + 5 ] = pos[ o2 + 2 ];
 
-			scope.colorArray[ c + 0 ] = pos[ o1 ];
-			scope.colorArray[ c + 1 ] = pos[ o1 + 1 ];
-			scope.colorArray[ c + 2 ] = pos[ o1 + 2 ];
+				scope.colorArray[ c + 6 ] = pos[ o3 + 0 ];
+				scope.colorArray[ c + 7 ] = pos[ o3 + 1 ];
+				scope.colorArray[ c + 8 ] = pos[ o3 + 2 ];
 
-			scope.colorArray[ c + 3 ] = pos[ o2 ];
-			scope.colorArray[ c + 4 ] = pos[ o2 + 1 ];
-			scope.colorArray[ c + 5 ] = pos[ o2 + 2 ];
+			}
 
-			scope.colorArray[ c + 6 ] = pos[ o3 ];
-			scope.colorArray[ c + 7 ] = pos[ o3 + 1 ];
-			scope.colorArray[ c + 8 ] = pos[ o3 + 2 ];
+			scope.count += 3;
 
-		}
+			if ( scope.count >= scope.maxCount - 3 ) {
 
-		scope.count += 3;
+				scope.hasPositions = true;
+				scope.hasNormals = true;
 
-		if ( scope.count >= scope.maxCount - 3 ) {
+				if ( scope.enableUvs ) {
 
-			scope.hasPositions = true;
-			scope.hasNormals = true;
+					scope.hasUvs = true;
 
-			if ( scope.enableUvs ) {
+				}
 
-				scope.hasUvs = true;
+				if ( scope.enableColors ) {
 
-			}
+					scope.hasColors = true;
 
-			if ( scope.enableColors ) {
+				}
 
-				scope.hasColors = true;
+				renderCallback( scope );
 
 			}
 
-			renderCallback( scope );
-
 		}
 
-	}
+		function begin() {
 
-	this.begin = function () {
+			scope.count = 0;
 
-		this.count = 0;
+			scope.hasPositions = false;
+			scope.hasNormals = false;
+			scope.hasUvs = false;
+			scope.hasColors = false;
 
-		this.hasPositions = false;
-		this.hasNormals = false;
-		this.hasUvs = false;
-		this.hasColors = false;
+		}
 
-	};
+		function end( renderCallback ) {
 
-	this.end = function ( renderCallback ) {
+			if ( scope.count === 0 ) return;
 
-		if ( this.count === 0 ) return;
+			for ( var i = scope.count * 3; i < scope.positionArray.length; i ++ ) {
 
-		for ( var i = this.count * 3; i < this.positionArray.length; i ++ ) {
+				scope.positionArray[ i ] = 0.0;
 
-			this.positionArray[ i ] = 0.0;
+			}
 
-		}
+			scope.hasPositions = true;
+			scope.hasNormals = true;
 
-		this.hasPositions = true;
-		this.hasNormals = true;
+			if ( scope.enableUvs && scope.material.map ) {
 
-		if ( this.enableUvs ) {
+				scope.hasUvs = true;
 
-			this.hasUvs = true;
+			}
 
-		}
+			if ( scope.enableColors && scope.material.vertexColors !== THREE.NoColors ) {
 
-		if ( this.enableColors ) {
+				scope.hasColors = true;
 
-			this.hasColors = true;
+			}
 
-		}
+			renderCallback( scope );
 
-		renderCallback( this );
+		}
 
-	};
+		/////////////////////////////////////
+		// Metaballs
+		/////////////////////////////////////
 
-	/////////////////////////////////////
-	// Metaballs
-	/////////////////////////////////////
+		// Adds a reciprocal ball (nice and blobby) that, to be fast, fades to zero after
+		// a fixed distance, determined by strength and subtract.
 
-	// Adds a reciprocal ball (nice and blobby) that, to be fast, fades to zero after
-	// a fixed distance, determined by strength and subtract.
+		this.addBall = function ( ballx, bally, ballz, strength, subtract ) {
 
-	this.addBall = function ( ballx, bally, ballz, strength, subtract ) {
+			var sign = Math.sign( strength );
+			strength = Math.abs( strength );
 
-		var sign = Math.sign( strength );
-		strength = Math.abs( strength );
+			// Let's solve the equation to find the radius:
+			// 1.0 / (0.000001 + radius^2) * strength - subtract = 0
+			// strength / (radius^2) = subtract
+			// strength = subtract * radius^2
+			// radius^2 = strength / subtract
+			// radius = sqrt(strength / subtract)
 
-		// Let's solve the equation to find the radius:
-		// 1.0 / (0.000001 + radius^2) * strength - subtract = 0
-		// strength / (radius^2) = subtract
-		// strength = subtract * radius^2
-		// radius^2 = strength / subtract
-		// radius = sqrt(strength / subtract)
+			var radius = this.size * Math.sqrt( strength / subtract ),
+				zs = ballz * this.size,
+				ys = bally * this.size,
+				xs = ballx * this.size;
 
-		var radius = this.size * Math.sqrt( strength / subtract ),
-			zs = ballz * this.size,
-			ys = bally * this.size,
-			xs = ballx * this.size;
+			var min_z = Math.floor( zs - radius ); if ( min_z < 1 ) min_z = 1;
+			var max_z = Math.floor( zs + radius ); if ( max_z > this.size - 1 ) max_z = this.size - 1;
+			var min_y = Math.floor( ys - radius ); if ( min_y < 1 ) min_y = 1;
+			var max_y = Math.floor( ys + radius ); if ( max_y > this.size - 1 ) max_y = this.size - 1;
+			var min_x = Math.floor( xs - radius ); if ( min_x < 1 ) min_x = 1;
+			var max_x = Math.floor( xs + radius ); if ( max_x > this.size - 1 ) max_x = this.size - 1;
 
-		var min_z = Math.floor( zs - radius ); if ( min_z < 1 ) min_z = 1;
-		var max_z = Math.floor( zs + radius ); if ( max_z > this.size - 1 ) max_z = this.size - 1;
-		var min_y = Math.floor( ys - radius ); if ( min_y < 1 ) min_y = 1;
-		var max_y = Math.floor( ys + radius ); if ( max_y > this.size - 1 ) max_y = this.size - 1;
-		var min_x = Math.floor( xs - radius ); if ( min_x < 1 ) min_x = 1;
-		var max_x = Math.floor( xs + radius ); if ( max_x > this.size - 1 ) max_x = this.size - 1;
 
+			// Don't polygonize in the outer layer because normals aren't
+			// well-defined there.
 
-		// Don't polygonize in the outer layer because normals aren't
-		// well-defined there.
+			var x, y, z, y_offset, z_offset, fx, fy, fz, fz2, fy2, val;
 
-		var x, y, z, y_offset, z_offset, fx, fy, fz, fz2, fy2, val;
+			for ( z = min_z; z < max_z; z ++ ) {
 
-		for ( z = min_z; z < max_z; z ++ ) {
+				z_offset = this.size2 * z;
+				fz = z / this.size - ballz;
+				fz2 = fz * fz;
 
-			z_offset = this.size2 * z;
-			fz = z / this.size - ballz;
-			fz2 = fz * fz;
+				for ( y = min_y; y < max_y; y ++ ) {
 
-			for ( y = min_y; y < max_y; y ++ ) {
+					y_offset = z_offset + this.size * y;
+					fy = y / this.size - bally;
+					fy2 = fy * fy;
 
-				y_offset = z_offset + this.size * y;
-				fy = y / this.size - bally;
-				fy2 = fy * fy;
+					for ( x = min_x; x < max_x; x ++ ) {
 
-				for ( x = min_x; x < max_x; x ++ ) {
+						fx = x / this.size - ballx;
+						val = strength / ( 0.000001 + fx * fx + fy2 + fz2 ) - subtract;
+						if ( val > 0.0 ) field[ y_offset + x ] += val * sign;
 
-					fx = x / this.size - ballx;
-					val = strength / ( 0.000001 + fx * fx + fy2 + fz2 ) - subtract;
-					if ( val > 0.0 ) this.field[ y_offset + x ] += val * sign;
+					}
 
 				}
 
 			}
 
-		}
+		};
 
-	};
+		this.addPlaneX = function ( strength, subtract ) {
 
-	this.addPlaneX = function ( strength, subtract ) {
+			var x, y, z, xx, val, xdiv, cxy,
 
-		var x, y, z, xx, val, xdiv, cxy,
+				// cache attribute lookups
+				size = this.size,
 
-			// cache attribute lookups
-			size = this.size,
-			yd = this.yd,
-			zd = this.zd,
-			field = this.field,
+				dist = size * Math.sqrt( strength / subtract );
 
-			dist = size * Math.sqrt( strength / subtract );
+			if ( dist > size ) dist = size;
 
-		if ( dist > size ) dist = size;
+			for ( x = 0; x < dist; x ++ ) {
 
-		for ( x = 0; x < dist; x ++ ) {
+				xdiv = x / size;
+				xx = xdiv * xdiv;
+				val = strength / ( 0.0001 + xx ) - subtract;
 
-			xdiv = x / size;
-			xx = xdiv * xdiv;
-			val = strength / ( 0.0001 + xx ) - subtract;
+				if ( val > 0.0 ) {
 
-			if ( val > 0.0 ) {
+					for ( y = 0; y < size; y ++ ) {
 
-				for ( y = 0; y < size; y ++ ) {
+						cxy = x + y * yd;
 
-					cxy = x + y * yd;
+						for ( z = 0; z < size; z ++ ) {
 
-					for ( z = 0; z < size; z ++ ) {
+							field[ zd * z + cxy ] += val;
 
-						field[ zd * z + cxy ] += val;
+						}
 
 					}
 
@@ -553,492 +578,484 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 
 			}
 
-		}
+		};
 
-	};
+		this.addPlaneY = function ( strength, subtract ) {
 
-	this.addPlaneY = function ( strength, subtract ) {
+			var x, y, z, yy, val, ydiv, cy, cxy,
 
-		var x, y, z, yy, val, ydiv, cy, cxy,
+				// cache attribute lookups
+				size = this.size,
 
-			// cache attribute lookups
-			size = this.size,
-			yd = this.yd,
-			zd = this.zd,
-			field = this.field,
+				dist = size * Math.sqrt( strength / subtract );
 
-			dist = size * Math.sqrt( strength / subtract );
+			if ( dist > size ) dist = size;
 
-		if ( dist > size ) dist = size;
+			for ( y = 0; y < dist; y ++ ) {
 
-		for ( y = 0; y < dist; y ++ ) {
+				ydiv = y / size;
+				yy = ydiv * ydiv;
+				val = strength / ( 0.0001 + yy ) - subtract;
 
-			ydiv = y / size;
-			yy = ydiv * ydiv;
-			val = strength / ( 0.0001 + yy ) - subtract;
+				if ( val > 0.0 ) {
 
-			if ( val > 0.0 ) {
+					cy = y * yd;
 
-				cy = y * yd;
+					for ( x = 0; x < size; x ++ ) {
 
-				for ( x = 0; x < size; x ++ ) {
+						cxy = cy + x;
 
-					cxy = cy + x;
+						for ( z = 0; z < size; z ++ )
+							field[ zd * z + cxy ] += val;
 
-					for ( z = 0; z < size; z ++ )
-						field[ zd * z + cxy ] += val;
+					}
 
 				}
 
 			}
 
-		}
+		};
 
-	};
+		this.addPlaneZ = function ( strength, subtract ) {
 
-	this.addPlaneZ = function ( strength, subtract ) {
+			var x, y, z, zz, val, zdiv, cz, cyz,
 
-		var x, y, z, zz, val, zdiv, cz, cyz,
+				// cache attribute lookups
+				size = this.size,
 
-			// cache attribute lookups
-			size = this.size,
-			yd = this.yd,
-			zd = this.zd,
-			field = this.field,
+				dist = size * Math.sqrt( strength / subtract );
 
-			dist = size * Math.sqrt( strength / subtract );
+			if ( dist > size ) dist = size;
 
-		if ( dist > size ) dist = size;
+			for ( z = 0; z < dist; z ++ ) {
 
-		for ( z = 0; z < dist; z ++ ) {
+				zdiv = z / size;
+				zz = zdiv * zdiv;
+				val = strength / ( 0.0001 + zz ) - subtract;
+				if ( val > 0.0 ) {
 
-			zdiv = z / size;
-			zz = zdiv * zdiv;
-			val = strength / ( 0.0001 + zz ) - subtract;
-			if ( val > 0.0 ) {
+					cz = zd * z;
 
-				cz = zd * z;
+					for ( y = 0; y < size; y ++ ) {
 
-				for ( y = 0; y < size; y ++ ) {
+						cyz = cz + y * yd;
 
-					cyz = cz + y * yd;
+						for ( x = 0; x < size; x ++ )
+							field[ cyz + x ] += val;
 
-					for ( x = 0; x < size; x ++ )
-						field[ cyz + x ] += val;
+					}
 
 				}
 
 			}
 
-		}
+		};
 
-	};
+		/////////////////////////////////////
+		// Updates
+		/////////////////////////////////////
 
-	/////////////////////////////////////
-	// Updates
-	/////////////////////////////////////
+		this.reset = function () {
 
-	this.reset = function () {
+			// wipe the normal cache
 
-		var i;
+			for ( var i = 0; i < this.size3; i ++ ) {
 
-		// wipe the normal cache
+				normal_cache[ i * 3 ] = 0.0;
+				field[ i ] = 0.0;
 
-		for ( i = 0; i < this.size3; i ++ ) {
+			}
 
-			this.normal_cache[ i * 3 ] = 0.0;
-			this.field[ i ] = 0.0;
+		};
 
-		}
+		this.render = function ( renderCallback ) {
 
-	};
+			begin();
 
-	this.render = function ( renderCallback ) {
+			// Triangulate. Yeah, this is slow.
 
-		this.begin();
+			var smin2 = this.size - 2;
 
-		// Triangulate. Yeah, this is slow.
+			for ( var z = 1; z < smin2; z ++ ) {
 
-		var smin2 = this.size - 2;
+				var z_offset = this.size2 * z;
+				var fz = ( z - this.halfsize ) / this.halfsize; //+ 1
 
-		for ( var z = 1; z < smin2; z ++ ) {
+				for ( var y = 1; y < smin2; y ++ ) {
 
-			var z_offset = this.size2 * z;
-			var fz = ( z - this.halfsize ) / this.halfsize; //+ 1
+					var y_offset = z_offset + this.size * y;
+					var fy = ( y - this.halfsize ) / this.halfsize; //+ 1
 
-			for ( var y = 1; y < smin2; y ++ ) {
+					for ( var x = 1; x < smin2; x ++ ) {
 
-				var y_offset = z_offset + this.size * y;
-				var fy = ( y - this.halfsize ) / this.halfsize; //+ 1
+						var fx = ( x - this.halfsize ) / this.halfsize; //+ 1
+						var q = y_offset + x;
 
-				for ( var x = 1; x < smin2; x ++ ) {
+						polygonize( fx, fy, fz, q, this.isolation, renderCallback );
 
-					var fx = ( x - this.halfsize ) / this.halfsize; //+ 1
-					var q = y_offset + x;
-
-					polygonize( fx, fy, fz, q, this.isolation, renderCallback );
+					}
 
 				}
 
 			}
 
-		}
+			end( renderCallback );
 
-		this.end( renderCallback );
+		};
 
-	};
+		this.generateGeometry = function () {
 
-	this.generateGeometry = function () {
+			console.warn( 'THREE.MarchingCubes: generateGeometry() now returns THREE.BufferGeometry' );
+			return this.generateBufferGeometry();
 
-		console.warn( 'THREE.MarchingCubes: generateGeometry() now returns THREE.BufferGeometry' );
-		return this.generateBufferGeometry();
+		};
 
-	};
+		function concatenate( a, b, length ) {
 
-	function concatenate( a, b, length ) {
+			var result = new Float32Array( a.length + length );
+			result.set( a, 0 );
+			result.set( b.slice( 0, length ), a.length );
+			return result;
 
-		var result = new Float32Array( a.length + length );
-		result.set( a, 0 );
-		result.set( b.slice( 0, length ), a.length );
-		return result;
+		}
 
-	}
+		this.generateBufferGeometry = function () {
 
-	this.generateBufferGeometry = function () {
+			var geo = new THREE.BufferGeometry();
+			var posArray = new Float32Array();
+			var normArray = new Float32Array();
+			var colorArray = new Float32Array();
+			var uvArray = new Float32Array();
+			var scope = this;
 
-		var geo = new THREE.BufferGeometry();
-		var posArray = new Float32Array();
-		var normArray = new Float32Array();
-		var colorArray = new Float32Array();
-		var uvArray = new Float32Array();
-		var scope = this;
+			var geo_callback = function ( object ) {
 
-		var geo_callback = function ( object ) {
+				if ( scope.hasPositions ) posArray = concatenate( posArray, object.positionArray, object.count * 3 );
+				if ( scope.hasNormals ) normArray = concatenate( normArray, object.normalArray, object.count * 3 );
+				if ( scope.hasColors ) colorArray = concatenate( colorArray, object.colorArray, object.count * 3 );
+				if ( scope.hasUvs ) uvArray = concatenate( uvArray, object.uvArray, object.count * 2 );
 
-			if ( scope.hasPositions ) posArray = concatenate( posArray, object.positionArray, object.count * 3 );
-			if ( scope.hasNormals ) normArray = concatenate( normArray, object.normalArray, object.count * 3 );
-			if ( scope.hasColors ) colorArray = concatenate( colorArray, object.colorArray, object.count * 3 );
-			if ( scope.hasUvs ) uvArray = concatenate( uvArray, object.uvArray, object.count * 2 );
+				object.count = 0;
 
-			object.count = 0;
+			};
 
-		};
+			this.render( geo_callback );
 
-		this.render( geo_callback );
+			if ( this.hasPositions ) geo.addAttribute( 'position', new THREE.BufferAttribute( posArray, 3 ) );
+			if ( this.hasNormals ) geo.addAttribute( 'normal', new THREE.BufferAttribute( normArray, 3 ) );
+			if ( this.hasColors ) geo.addAttribute( 'color', new THREE.BufferAttribute( colorArray, 3 ) );
+			if ( this.hasUvs ) geo.addAttribute( 'uv', new THREE.BufferAttribute( uvArray, 2 ) );
 
-		if ( this.hasPositions ) geo.addAttribute( 'position', new THREE.BufferAttribute( posArray, 3 ) );
-		if ( this.hasNormals ) geo.addAttribute( 'normal', new THREE.BufferAttribute( normArray, 3 ) );
-		if ( this.hasColors ) geo.addAttribute( 'color', new THREE.BufferAttribute( colorArray, 3 ) );
-		if ( this.hasUvs ) geo.addAttribute( 'uv', new THREE.BufferAttribute( uvArray, 2 ) );
+			return geo;
 
-		return geo;
+		};
+
+		this.init( resolution );
 
 	};
 
-	this.init( resolution );
-
-};
-
-THREE.MarchingCubes.prototype = Object.create( THREE.ImmediateRenderObject.prototype );
-THREE.MarchingCubes.prototype.constructor = THREE.MarchingCubes;
-
-
-/////////////////////////////////////
-// Marching cubes lookup tables
-/////////////////////////////////////
-
-// These tables are straight from Paul Bourke's page:
-// http://local.wasp.uwa.edu.au/~pbourke/geometry/polygonise/
-// who in turn got them from Cory Gene Bloyd.
-
-THREE.edgeTable = new Int32Array( [
-	0x0, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c,
-	0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
-	0x190, 0x99, 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c,
-	0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
-	0x230, 0x339, 0x33, 0x13a, 0x636, 0x73f, 0x435, 0x53c,
-	0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
-	0x3a0, 0x2a9, 0x1a3, 0xaa, 0x7a6, 0x6af, 0x5a5, 0x4ac,
-	0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
-	0x460, 0x569, 0x663, 0x76a, 0x66, 0x16f, 0x265, 0x36c,
-	0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
-	0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff, 0x3f5, 0x2fc,
-	0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
-	0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55, 0x15c,
-	0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
-	0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc,
-	0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
-	0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc,
-	0xcc, 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
-	0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c,
-	0x15c, 0x55, 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
-	0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc,
-	0x2fc, 0x3f5, 0xff, 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
-	0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c,
-	0x36c, 0x265, 0x16f, 0x66, 0x76a, 0x663, 0x569, 0x460,
-	0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac,
-	0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa, 0x1a3, 0x2a9, 0x3a0,
-	0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c,
-	0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33, 0x339, 0x230,
-	0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c,
-	0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99, 0x190,
-	0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c,
-	0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0 ] );
-
-THREE.triTable = new Int32Array( [
-	- 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	0, 8, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	0, 1, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	1, 8, 3, 9, 8, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	1, 2, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	0, 8, 3, 1, 2, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	9, 2, 10, 0, 2, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	2, 8, 3, 2, 10, 8, 10, 9, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	3, 11, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	0, 11, 2, 8, 11, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	1, 9, 0, 2, 3, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	1, 11, 2, 1, 9, 11, 9, 8, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	3, 10, 1, 11, 10, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	0, 10, 1, 0, 8, 10, 8, 11, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	3, 9, 0, 3, 11, 9, 11, 10, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	9, 8, 10, 10, 8, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	4, 7, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	4, 3, 0, 7, 3, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	0, 1, 9, 8, 4, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	4, 1, 9, 4, 7, 1, 7, 3, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	1, 2, 10, 8, 4, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	3, 4, 7, 3, 0, 4, 1, 2, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	9, 2, 10, 9, 0, 2, 8, 4, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, - 1, - 1, - 1, - 1,
-	8, 4, 7, 3, 11, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	11, 4, 7, 11, 2, 4, 2, 0, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	9, 0, 1, 8, 4, 7, 2, 3, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, - 1, - 1, - 1, - 1,
-	3, 10, 1, 3, 11, 10, 7, 8, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, - 1, - 1, - 1, - 1,
-	4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, - 1, - 1, - 1, - 1,
-	4, 7, 11, 4, 11, 9, 9, 11, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	9, 5, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	9, 5, 4, 0, 8, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	0, 5, 4, 1, 5, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	8, 5, 4, 8, 3, 5, 3, 1, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	1, 2, 10, 9, 5, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	3, 0, 8, 1, 2, 10, 4, 9, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	5, 2, 10, 5, 4, 2, 4, 0, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, - 1, - 1, - 1, - 1,
-	9, 5, 4, 2, 3, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	0, 11, 2, 0, 8, 11, 4, 9, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	0, 5, 4, 0, 1, 5, 2, 3, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, - 1, - 1, - 1, - 1,
-	10, 3, 11, 10, 1, 3, 9, 5, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, - 1, - 1, - 1, - 1,
-	5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, - 1, - 1, - 1, - 1,
-	5, 4, 8, 5, 8, 10, 10, 8, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	9, 7, 8, 5, 7, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	9, 3, 0, 9, 5, 3, 5, 7, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	0, 7, 8, 0, 1, 7, 1, 5, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	1, 5, 3, 3, 5, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	9, 7, 8, 9, 5, 7, 10, 1, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, - 1, - 1, - 1, - 1,
-	8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, - 1, - 1, - 1, - 1,
-	2, 10, 5, 2, 5, 3, 3, 5, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	7, 9, 5, 7, 8, 9, 3, 11, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, - 1, - 1, - 1, - 1,
-	2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, - 1, - 1, - 1, - 1,
-	11, 2, 1, 11, 1, 7, 7, 1, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, - 1, - 1, - 1, - 1,
-	5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, - 1,
-	11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, - 1,
-	11, 10, 5, 7, 11, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	10, 6, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	0, 8, 3, 5, 10, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	9, 0, 1, 5, 10, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	1, 8, 3, 1, 9, 8, 5, 10, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	1, 6, 5, 2, 6, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	1, 6, 5, 1, 2, 6, 3, 0, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	9, 6, 5, 9, 0, 6, 0, 2, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, - 1, - 1, - 1, - 1,
-	2, 3, 11, 10, 6, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	11, 0, 8, 11, 2, 0, 10, 6, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	0, 1, 9, 2, 3, 11, 5, 10, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, - 1, - 1, - 1, - 1,
-	6, 3, 11, 6, 5, 3, 5, 1, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, - 1, - 1, - 1, - 1,
-	3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, - 1, - 1, - 1, - 1,
-	6, 5, 9, 6, 9, 11, 11, 9, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	5, 10, 6, 4, 7, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	4, 3, 0, 4, 7, 3, 6, 5, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	1, 9, 0, 5, 10, 6, 8, 4, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, - 1, - 1, - 1, - 1,
-	6, 1, 2, 6, 5, 1, 4, 7, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, - 1, - 1, - 1, - 1,
-	8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, - 1, - 1, - 1, - 1,
-	7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, - 1,
-	3, 11, 2, 7, 8, 4, 10, 6, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, - 1, - 1, - 1, - 1,
-	0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, - 1, - 1, - 1, - 1,
-	9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, - 1,
-	8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, - 1, - 1, - 1, - 1,
-	5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, - 1,
-	0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, - 1,
-	6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, - 1, - 1, - 1, - 1,
-	10, 4, 9, 6, 4, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	4, 10, 6, 4, 9, 10, 0, 8, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	10, 0, 1, 10, 6, 0, 6, 4, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, - 1, - 1, - 1, - 1,
-	1, 4, 9, 1, 2, 4, 2, 6, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, - 1, - 1, - 1, - 1,
-	0, 2, 4, 4, 2, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	8, 3, 2, 8, 2, 4, 4, 2, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	10, 4, 9, 10, 6, 4, 11, 2, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, - 1, - 1, - 1, - 1,
-	3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, - 1, - 1, - 1, - 1,
-	6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, - 1,
-	9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, - 1, - 1, - 1, - 1,
-	8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, - 1,
-	3, 11, 6, 3, 6, 0, 0, 6, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	6, 4, 8, 11, 6, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	7, 10, 6, 7, 8, 10, 8, 9, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, - 1, - 1, - 1, - 1,
-	10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, - 1, - 1, - 1, - 1,
-	10, 6, 7, 10, 7, 1, 1, 7, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, - 1, - 1, - 1, - 1,
-	2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, - 1,
-	7, 8, 0, 7, 0, 6, 6, 0, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	7, 3, 2, 6, 7, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, - 1, - 1, - 1, - 1,
-	2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, - 1,
-	1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, - 1,
-	11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, - 1, - 1, - 1, - 1,
-	8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, - 1,
-	0, 9, 1, 11, 6, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, - 1, - 1, - 1, - 1,
-	7, 11, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	7, 6, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	3, 0, 8, 11, 7, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	0, 1, 9, 11, 7, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	8, 1, 9, 8, 3, 1, 11, 7, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	10, 1, 2, 6, 11, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	1, 2, 10, 3, 0, 8, 6, 11, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	2, 9, 0, 2, 10, 9, 6, 11, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, - 1, - 1, - 1, - 1,
-	7, 2, 3, 6, 2, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	7, 0, 8, 7, 6, 0, 6, 2, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	2, 7, 6, 2, 3, 7, 0, 1, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, - 1, - 1, - 1, - 1,
-	10, 7, 6, 10, 1, 7, 1, 3, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, - 1, - 1, - 1, - 1,
-	0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, - 1, - 1, - 1, - 1,
-	7, 6, 10, 7, 10, 8, 8, 10, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	6, 8, 4, 11, 8, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	3, 6, 11, 3, 0, 6, 0, 4, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	8, 6, 11, 8, 4, 6, 9, 0, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, - 1, - 1, - 1, - 1,
-	6, 8, 4, 6, 11, 8, 2, 10, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, - 1, - 1, - 1, - 1,
-	4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, - 1, - 1, - 1, - 1,
-	10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, - 1,
-	8, 2, 3, 8, 4, 2, 4, 6, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	0, 4, 2, 4, 6, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, - 1, - 1, - 1, - 1,
-	1, 9, 4, 1, 4, 2, 2, 4, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, - 1, - 1, - 1, - 1,
-	10, 1, 0, 10, 0, 6, 6, 0, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, - 1,
-	10, 9, 4, 6, 10, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	4, 9, 5, 7, 6, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	0, 8, 3, 4, 9, 5, 11, 7, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	5, 0, 1, 5, 4, 0, 7, 6, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, - 1, - 1, - 1, - 1,
-	9, 5, 4, 10, 1, 2, 7, 6, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, - 1, - 1, - 1, - 1,
-	7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, - 1, - 1, - 1, - 1,
-	3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, - 1,
-	7, 2, 3, 7, 6, 2, 5, 4, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, - 1, - 1, - 1, - 1,
-	3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, - 1, - 1, - 1, - 1,
-	6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, - 1,
-	9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, - 1, - 1, - 1, - 1,
-	1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, - 1,
-	4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, - 1,
-	7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, - 1, - 1, - 1, - 1,
-	6, 9, 5, 6, 11, 9, 11, 8, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, - 1, - 1, - 1, - 1,
-	0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, - 1, - 1, - 1, - 1,
-	6, 11, 3, 6, 3, 5, 5, 3, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, - 1, - 1, - 1, - 1,
-	0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, - 1,
-	11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, - 1,
-	6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, - 1, - 1, - 1, - 1,
-	5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, - 1, - 1, - 1, - 1,
-	9, 5, 6, 9, 6, 0, 0, 6, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, - 1,
-	1, 5, 6, 2, 1, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, - 1,
-	10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, - 1, - 1, - 1, - 1,
-	0, 3, 8, 5, 6, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	10, 5, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	11, 5, 10, 7, 5, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	11, 5, 10, 11, 7, 5, 8, 3, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	5, 11, 7, 5, 10, 11, 1, 9, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, - 1, - 1, - 1, - 1,
-	11, 1, 2, 11, 7, 1, 7, 5, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, - 1, - 1, - 1, - 1,
-	9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, - 1, - 1, - 1, - 1,
-	7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, - 1,
-	2, 5, 10, 2, 3, 5, 3, 7, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, - 1, - 1, - 1, - 1,
-	9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, - 1, - 1, - 1, - 1,
-	9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, - 1,
-	1, 3, 5, 3, 7, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	0, 8, 7, 0, 7, 1, 1, 7, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	9, 0, 3, 9, 3, 5, 5, 3, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	9, 8, 7, 5, 9, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	5, 8, 4, 5, 10, 8, 10, 11, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, - 1, - 1, - 1, - 1,
-	0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, - 1, - 1, - 1, - 1,
-	10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, - 1,
-	2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, - 1, - 1, - 1, - 1,
-	0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, - 1,
-	0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, - 1,
-	9, 4, 5, 2, 11, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, - 1, - 1, - 1, - 1,
-	5, 10, 2, 5, 2, 4, 4, 2, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, - 1,
-	5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, - 1, - 1, - 1, - 1,
-	8, 4, 5, 8, 5, 3, 3, 5, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	0, 4, 5, 1, 0, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, - 1, - 1, - 1, - 1,
-	9, 4, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	4, 11, 7, 4, 9, 11, 9, 10, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, - 1, - 1, - 1, - 1,
-	1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, - 1, - 1, - 1, - 1,
-	3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, - 1,
-	4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, - 1, - 1, - 1, - 1,
-	9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, - 1,
-	11, 7, 4, 11, 4, 2, 2, 4, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, - 1, - 1, - 1, - 1,
-	2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, - 1, - 1, - 1, - 1,
-	9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, - 1,
-	3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, - 1,
-	1, 10, 2, 8, 7, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	4, 9, 1, 4, 1, 7, 7, 1, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, - 1, - 1, - 1, - 1,
-	4, 0, 3, 7, 4, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	4, 8, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	9, 10, 8, 10, 11, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	3, 0, 9, 3, 9, 11, 11, 9, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	0, 1, 10, 0, 10, 8, 8, 10, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	3, 1, 10, 11, 3, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	1, 2, 11, 1, 11, 9, 9, 11, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, - 1, - 1, - 1, - 1,
-	0, 2, 11, 8, 0, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	3, 2, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	2, 3, 8, 2, 8, 10, 10, 8, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	9, 10, 2, 0, 9, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, - 1, - 1, - 1, - 1,
-	1, 10, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	1, 3, 8, 9, 1, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	0, 9, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	0, 3, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-	- 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1 ] );
+	THREE.MarchingCubes.prototype = Object.create( THREE.ImmediateRenderObject.prototype );
+	THREE.MarchingCubes.prototype.constructor = THREE.MarchingCubes;
+
+
+	/////////////////////////////////////
+	// Marching cubes lookup tables
+	/////////////////////////////////////
+
+	// These tables are straight from Paul Bourke's page:
+	// http://local.wasp.uwa.edu.au/~pbourke/geometry/polygonise/
+	// who in turn got them from Cory Gene Bloyd.
+
+	var EdgeTable = new Int32Array( [
+		0x0, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c,
+		0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
+		0x190, 0x99, 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c,
+		0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
+		0x230, 0x339, 0x33, 0x13a, 0x636, 0x73f, 0x435, 0x53c,
+		0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
+		0x3a0, 0x2a9, 0x1a3, 0xaa, 0x7a6, 0x6af, 0x5a5, 0x4ac,
+		0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
+		0x460, 0x569, 0x663, 0x76a, 0x66, 0x16f, 0x265, 0x36c,
+		0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
+		0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff, 0x3f5, 0x2fc,
+		0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
+		0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55, 0x15c,
+		0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
+		0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc,
+		0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
+		0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc,
+		0xcc, 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
+		0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c,
+		0x15c, 0x55, 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
+		0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc,
+		0x2fc, 0x3f5, 0xff, 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
+		0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c,
+		0x36c, 0x265, 0x16f, 0x66, 0x76a, 0x663, 0x569, 0x460,
+		0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac,
+		0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa, 0x1a3, 0x2a9, 0x3a0,
+		0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c,
+		0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33, 0x339, 0x230,
+		0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c,
+		0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99, 0x190,
+		0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c,
+		0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0 ] );
+
+	var TriTable = new Int32Array( [
+		- 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		0, 8, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		0, 1, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		1, 8, 3, 9, 8, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		1, 2, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		0, 8, 3, 1, 2, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		9, 2, 10, 0, 2, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		2, 8, 3, 2, 10, 8, 10, 9, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		3, 11, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		0, 11, 2, 8, 11, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		1, 9, 0, 2, 3, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		1, 11, 2, 1, 9, 11, 9, 8, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		3, 10, 1, 11, 10, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		0, 10, 1, 0, 8, 10, 8, 11, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		3, 9, 0, 3, 11, 9, 11, 10, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		9, 8, 10, 10, 8, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		4, 7, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		4, 3, 0, 7, 3, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		0, 1, 9, 8, 4, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		4, 1, 9, 4, 7, 1, 7, 3, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		1, 2, 10, 8, 4, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		3, 4, 7, 3, 0, 4, 1, 2, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		9, 2, 10, 9, 0, 2, 8, 4, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, - 1, - 1, - 1, - 1,
+		8, 4, 7, 3, 11, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		11, 4, 7, 11, 2, 4, 2, 0, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		9, 0, 1, 8, 4, 7, 2, 3, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, - 1, - 1, - 1, - 1,
+		3, 10, 1, 3, 11, 10, 7, 8, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, - 1, - 1, - 1, - 1,
+		4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, - 1, - 1, - 1, - 1,
+		4, 7, 11, 4, 11, 9, 9, 11, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		9, 5, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		9, 5, 4, 0, 8, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		0, 5, 4, 1, 5, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		8, 5, 4, 8, 3, 5, 3, 1, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		1, 2, 10, 9, 5, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		3, 0, 8, 1, 2, 10, 4, 9, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		5, 2, 10, 5, 4, 2, 4, 0, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, - 1, - 1, - 1, - 1,
+		9, 5, 4, 2, 3, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		0, 11, 2, 0, 8, 11, 4, 9, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		0, 5, 4, 0, 1, 5, 2, 3, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, - 1, - 1, - 1, - 1,
+		10, 3, 11, 10, 1, 3, 9, 5, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, - 1, - 1, - 1, - 1,
+		5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, - 1, - 1, - 1, - 1,
+		5, 4, 8, 5, 8, 10, 10, 8, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		9, 7, 8, 5, 7, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		9, 3, 0, 9, 5, 3, 5, 7, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		0, 7, 8, 0, 1, 7, 1, 5, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		1, 5, 3, 3, 5, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		9, 7, 8, 9, 5, 7, 10, 1, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, - 1, - 1, - 1, - 1,
+		8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, - 1, - 1, - 1, - 1,
+		2, 10, 5, 2, 5, 3, 3, 5, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		7, 9, 5, 7, 8, 9, 3, 11, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, - 1, - 1, - 1, - 1,
+		2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, - 1, - 1, - 1, - 1,
+		11, 2, 1, 11, 1, 7, 7, 1, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, - 1, - 1, - 1, - 1,
+		5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, - 1,
+		11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, - 1,
+		11, 10, 5, 7, 11, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		10, 6, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		0, 8, 3, 5, 10, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		9, 0, 1, 5, 10, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		1, 8, 3, 1, 9, 8, 5, 10, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		1, 6, 5, 2, 6, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		1, 6, 5, 1, 2, 6, 3, 0, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		9, 6, 5, 9, 0, 6, 0, 2, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, - 1, - 1, - 1, - 1,
+		2, 3, 11, 10, 6, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		11, 0, 8, 11, 2, 0, 10, 6, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		0, 1, 9, 2, 3, 11, 5, 10, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, - 1, - 1, - 1, - 1,
+		6, 3, 11, 6, 5, 3, 5, 1, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, - 1, - 1, - 1, - 1,
+		3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, - 1, - 1, - 1, - 1,
+		6, 5, 9, 6, 9, 11, 11, 9, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		5, 10, 6, 4, 7, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		4, 3, 0, 4, 7, 3, 6, 5, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		1, 9, 0, 5, 10, 6, 8, 4, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, - 1, - 1, - 1, - 1,
+		6, 1, 2, 6, 5, 1, 4, 7, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, - 1, - 1, - 1, - 1,
+		8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, - 1, - 1, - 1, - 1,
+		7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, - 1,
+		3, 11, 2, 7, 8, 4, 10, 6, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, - 1, - 1, - 1, - 1,
+		0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, - 1, - 1, - 1, - 1,
+		9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, - 1,
+		8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, - 1, - 1, - 1, - 1,
+		5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, - 1,
+		0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, - 1,
+		6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, - 1, - 1, - 1, - 1,
+		10, 4, 9, 6, 4, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		4, 10, 6, 4, 9, 10, 0, 8, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		10, 0, 1, 10, 6, 0, 6, 4, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, - 1, - 1, - 1, - 1,
+		1, 4, 9, 1, 2, 4, 2, 6, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, - 1, - 1, - 1, - 1,
+		0, 2, 4, 4, 2, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		8, 3, 2, 8, 2, 4, 4, 2, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		10, 4, 9, 10, 6, 4, 11, 2, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, - 1, - 1, - 1, - 1,
+		3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, - 1, - 1, - 1, - 1,
+		6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, - 1,
+		9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, - 1, - 1, - 1, - 1,
+		8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, - 1,
+		3, 11, 6, 3, 6, 0, 0, 6, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		6, 4, 8, 11, 6, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		7, 10, 6, 7, 8, 10, 8, 9, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, - 1, - 1, - 1, - 1,
+		10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, - 1, - 1, - 1, - 1,
+		10, 6, 7, 10, 7, 1, 1, 7, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, - 1, - 1, - 1, - 1,
+		2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, - 1,
+		7, 8, 0, 7, 0, 6, 6, 0, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		7, 3, 2, 6, 7, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, - 1, - 1, - 1, - 1,
+		2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, - 1,
+		1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, - 1,
+		11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, - 1, - 1, - 1, - 1,
+		8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, - 1,
+		0, 9, 1, 11, 6, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, - 1, - 1, - 1, - 1,
+		7, 11, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		7, 6, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		3, 0, 8, 11, 7, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		0, 1, 9, 11, 7, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		8, 1, 9, 8, 3, 1, 11, 7, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		10, 1, 2, 6, 11, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		1, 2, 10, 3, 0, 8, 6, 11, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		2, 9, 0, 2, 10, 9, 6, 11, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, - 1, - 1, - 1, - 1,
+		7, 2, 3, 6, 2, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		7, 0, 8, 7, 6, 0, 6, 2, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		2, 7, 6, 2, 3, 7, 0, 1, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, - 1, - 1, - 1, - 1,
+		10, 7, 6, 10, 1, 7, 1, 3, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, - 1, - 1, - 1, - 1,
+		0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, - 1, - 1, - 1, - 1,
+		7, 6, 10, 7, 10, 8, 8, 10, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		6, 8, 4, 11, 8, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		3, 6, 11, 3, 0, 6, 0, 4, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		8, 6, 11, 8, 4, 6, 9, 0, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, - 1, - 1, - 1, - 1,
+		6, 8, 4, 6, 11, 8, 2, 10, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, - 1, - 1, - 1, - 1,
+		4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, - 1, - 1, - 1, - 1,
+		10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, - 1,
+		8, 2, 3, 8, 4, 2, 4, 6, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		0, 4, 2, 4, 6, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, - 1, - 1, - 1, - 1,
+		1, 9, 4, 1, 4, 2, 2, 4, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, - 1, - 1, - 1, - 1,
+		10, 1, 0, 10, 0, 6, 6, 0, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, - 1,
+		10, 9, 4, 6, 10, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		4, 9, 5, 7, 6, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		0, 8, 3, 4, 9, 5, 11, 7, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		5, 0, 1, 5, 4, 0, 7, 6, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, - 1, - 1, - 1, - 1,
+		9, 5, 4, 10, 1, 2, 7, 6, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, - 1, - 1, - 1, - 1,
+		7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, - 1, - 1, - 1, - 1,
+		3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, - 1,
+		7, 2, 3, 7, 6, 2, 5, 4, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, - 1, - 1, - 1, - 1,
+		3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, - 1, - 1, - 1, - 1,
+		6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, - 1,
+		9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, - 1, - 1, - 1, - 1,
+		1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, - 1,
+		4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, - 1,
+		7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, - 1, - 1, - 1, - 1,
+		6, 9, 5, 6, 11, 9, 11, 8, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, - 1, - 1, - 1, - 1,
+		0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, - 1, - 1, - 1, - 1,
+		6, 11, 3, 6, 3, 5, 5, 3, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, - 1, - 1, - 1, - 1,
+		0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, - 1,
+		11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, - 1,
+		6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, - 1, - 1, - 1, - 1,
+		5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, - 1, - 1, - 1, - 1,
+		9, 5, 6, 9, 6, 0, 0, 6, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, - 1,
+		1, 5, 6, 2, 1, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, - 1,
+		10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, - 1, - 1, - 1, - 1,
+		0, 3, 8, 5, 6, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		10, 5, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		11, 5, 10, 7, 5, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		11, 5, 10, 11, 7, 5, 8, 3, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		5, 11, 7, 5, 10, 11, 1, 9, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, - 1, - 1, - 1, - 1,
+		11, 1, 2, 11, 7, 1, 7, 5, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, - 1, - 1, - 1, - 1,
+		9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, - 1, - 1, - 1, - 1,
+		7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, - 1,
+		2, 5, 10, 2, 3, 5, 3, 7, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, - 1, - 1, - 1, - 1,
+		9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, - 1, - 1, - 1, - 1,
+		9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, - 1,
+		1, 3, 5, 3, 7, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		0, 8, 7, 0, 7, 1, 1, 7, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		9, 0, 3, 9, 3, 5, 5, 3, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		9, 8, 7, 5, 9, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		5, 8, 4, 5, 10, 8, 10, 11, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, - 1, - 1, - 1, - 1,
+		0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, - 1, - 1, - 1, - 1,
+		10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, - 1,
+		2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, - 1, - 1, - 1, - 1,
+		0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, - 1,
+		0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, - 1,
+		9, 4, 5, 2, 11, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, - 1, - 1, - 1, - 1,
+		5, 10, 2, 5, 2, 4, 4, 2, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, - 1,
+		5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, - 1, - 1, - 1, - 1,
+		8, 4, 5, 8, 5, 3, 3, 5, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		0, 4, 5, 1, 0, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, - 1, - 1, - 1, - 1,
+		9, 4, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		4, 11, 7, 4, 9, 11, 9, 10, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, - 1, - 1, - 1, - 1,
+		1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, - 1, - 1, - 1, - 1,
+		3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, - 1,
+		4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, - 1, - 1, - 1, - 1,
+		9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, - 1,
+		11, 7, 4, 11, 4, 2, 2, 4, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, - 1, - 1, - 1, - 1,
+		2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, - 1, - 1, - 1, - 1,
+		9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, - 1,
+		3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, - 1,
+		1, 10, 2, 8, 7, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		4, 9, 1, 4, 1, 7, 7, 1, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, - 1, - 1, - 1, - 1,
+		4, 0, 3, 7, 4, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		4, 8, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		9, 10, 8, 10, 11, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		3, 0, 9, 3, 9, 11, 11, 9, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		0, 1, 10, 0, 10, 8, 8, 10, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		3, 1, 10, 11, 3, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		1, 2, 11, 1, 11, 9, 9, 11, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, - 1, - 1, - 1, - 1,
+		0, 2, 11, 8, 0, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		3, 2, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		2, 3, 8, 2, 8, 10, 10, 8, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		9, 10, 2, 0, 9, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, - 1, - 1, - 1, - 1,
+		1, 10, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		1, 3, 8, 9, 1, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		0, 9, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		0, 3, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+		- 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1 ] );
+
+} )( THREE )

+ 10 - 8
examples/js/controls/EditorControls.js

@@ -21,6 +21,8 @@ THREE.EditorControls = function ( object, domElement ) {
 
 	var scope = this;
 	var vector = new THREE.Vector3();
+	var delta = new THREE.Vector3();
+	var box = new THREE.Box3();
 
 	var STATE = { NONE: - 1, ROTATE: 0, ZOOM: 1, PAN: 2 };
 	var state = STATE.NONE;
@@ -37,10 +39,10 @@ THREE.EditorControls = function ( object, domElement ) {
 
 	this.focus = function ( target ) {
 
-		var box = new THREE.Box3().setFromObject( target );
-
 		var distance;
 
+		box.setFromObject( target );
+
 		if ( box.isEmpty() === false ) {
 
 			center.copy( box.getCenter() );
@@ -55,7 +57,7 @@ THREE.EditorControls = function ( object, domElement ) {
 
 		}
 
-		var delta = new THREE.Vector3( 0, 0, 1 );
+		delta.set( 0, 0, 1 );
 		delta.applyQuaternion( object.quaternion );
 		delta.multiplyScalar( distance * 4 );
 
@@ -156,15 +158,15 @@ THREE.EditorControls = function ( object, domElement ) {
 
 		if ( state === STATE.ROTATE ) {
 
-			scope.rotate( new THREE.Vector3( - movementX * scope.rotationSpeed, - movementY * scope.rotationSpeed, 0 ) );
+			scope.rotate( delta.set( - movementX * scope.rotationSpeed, - movementY * scope.rotationSpeed, 0 ) );
 
 		} else if ( state === STATE.ZOOM ) {
 
-			scope.zoom( new THREE.Vector3( 0, 0, movementY ) );
+			scope.zoom( delta.set( 0, 0, movementY ) );
 
 		} else if ( state === STATE.PAN ) {
 
-			scope.pan( new THREE.Vector3( - movementX, movementY, 0 ) );
+			scope.pan( delta.set( - movementX, movementY, 0 ) );
 
 		}
 
@@ -188,7 +190,7 @@ THREE.EditorControls = function ( object, domElement ) {
 		event.preventDefault();
 
 		// Normalize deltaY due to https://bugzilla.mozilla.org/show_bug.cgi?id=1392460
-		scope.zoom( new THREE.Vector3( 0, 0, event.deltaY > 0 ? 1 : - 1 ) );
+		scope.zoom( delta.set( 0, 0, event.deltaY > 0 ? 1 : - 1 ) );
 
 	}
 
@@ -283,7 +285,7 @@ THREE.EditorControls = function ( object, domElement ) {
 				touches[ 0 ].set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY, 0 );
 				touches[ 1 ].set( event.touches[ 1 ].pageX, event.touches[ 1 ].pageY, 0 );
 				var distance = touches[ 0 ].distanceTo( touches[ 1 ] );
-				scope.zoom( new THREE.Vector3( 0, 0, prevDistance - distance ) );
+				scope.zoom( delta.set( 0, 0, prevDistance - distance ) );
 				prevDistance = distance;
 
 

+ 23 - 12
examples/js/controls/MapControls.js

@@ -11,11 +11,10 @@
 // Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default).
 // This is very similar to OrbitControls, another set of touch behavior
 //
-//    Orbit - right mouse / touch: two-finger rotate
+//    Orbit - right mouse, or left mouse + ctrl/metaKey / touch: two-finger rotate
 //    Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish
 //    Pan - left mouse, or arrow keys / touch: one-finger move
 
-
 THREE.MapControls = function ( object, domElement ) {
 
 	this.object = object;
@@ -78,7 +77,7 @@ THREE.MapControls = function ( object, domElement ) {
 	this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 };
 
 	// Mouse buttons
-	this.mouseButtons = { ORBIT: THREE.MOUSE.RIGHT, ZOOM: THREE.MOUSE.MIDDLE, PAN: THREE.MOUSE.LEFT };
+	this.mouseButtons = { LEFT: THREE.MOUSE.LEFT, MIDDLE: THREE.MOUSE.MIDDLE, RIGHT: THREE.MOUSE.RIGHT };
 
 	// for reset
 	this.target0 = this.target.clone();
@@ -776,17 +775,29 @@ THREE.MapControls = function ( object, domElement ) {
 
 		switch ( event.button ) {
 
-			case scope.mouseButtons.ORBIT:
+			case scope.mouseButtons.LEFT:
 
-				if ( scope.enableRotate === false ) return;
+				if ( event.ctrlKey || event.metaKey ) {
 
-				handleMouseDownRotate( event );
+					if ( scope.enableRotate === false ) return;
 
-				state = STATE.ROTATE;
+					handleMouseDownRotate( event );
+
+					state = STATE.ROTATE;
+
+				} else {
+
+					if ( scope.enablePan === false ) return;
+
+					handleMouseDownPan( event );
+
+					state = STATE.PAN;
+
+				}
 
 				break;
 
-			case scope.mouseButtons.ZOOM:
+			case scope.mouseButtons.MIDDLE:
 
 				if ( scope.enableZoom === false ) return;
 
@@ -796,13 +807,13 @@ THREE.MapControls = function ( object, domElement ) {
 
 				break;
 
-			case scope.mouseButtons.PAN:
+			case scope.mouseButtons.RIGHT:
 
-				if ( scope.enablePan === false ) return;
+				if ( scope.enableRotate === false ) return;
 
-				handleMouseDownPan( event );
+				handleMouseDownRotate( event );
 
-				state = STATE.PAN;
+				state = STATE.ROTATE;
 
 				break;
 

+ 20 - 8
examples/js/controls/OrbitControls.js

@@ -11,7 +11,7 @@
 //
 //    Orbit - left mouse / touch: one-finger move
 //    Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish
-//    Pan - right mouse, or arrow keys / touch: two-finger move
+//    Pan - right mouse, or left mouse + ctrl/metaKey, or arrow keys / touch: two-finger move
 
 THREE.OrbitControls = function ( object, domElement ) {
 
@@ -75,7 +75,7 @@ THREE.OrbitControls = function ( object, domElement ) {
 	this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 };
 
 	// Mouse buttons
-	this.mouseButtons = { ORBIT: THREE.MOUSE.LEFT, ZOOM: THREE.MOUSE.MIDDLE, PAN: THREE.MOUSE.RIGHT };
+	this.mouseButtons = { LEFT: THREE.MOUSE.LEFT, MIDDLE: THREE.MOUSE.MIDDLE, RIGHT: THREE.MOUSE.RIGHT };
 
 	// for reset
 	this.target0 = this.target.clone();
@@ -677,17 +677,29 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 		switch ( event.button ) {
 
-			case scope.mouseButtons.ORBIT:
+			case scope.mouseButtons.LEFT:
 
-				if ( scope.enableRotate === false ) return;
+				if ( event.ctrlKey || event.metaKey ) {
+
+					if ( scope.enablePan === false ) return;
+
+					handleMouseDownPan( event );
+
+					state = STATE.PAN;
+
+				} else {
+
+					if ( scope.enableRotate === false ) return;
+
+					handleMouseDownRotate( event );
 
-				handleMouseDownRotate( event );
+					state = STATE.ROTATE;
 
-				state = STATE.ROTATE;
+				}
 
 				break;
 
-			case scope.mouseButtons.ZOOM:
+			case scope.mouseButtons.MIDDLE:
 
 				if ( scope.enableZoom === false ) return;
 
@@ -697,7 +709,7 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 				break;
 
-			case scope.mouseButtons.PAN:
+			case scope.mouseButtons.RIGHT:
 
 				if ( scope.enablePan === false ) return;
 

+ 13 - 1
examples/js/loaders/ColladaLoader.js

@@ -3519,6 +3519,8 @@ THREE.ColladaLoader.prototype = {
 
 		}
 
+		var fallbackMaterial = new THREE.MeshBasicMaterial( { color: 0xff00ff } );
+
 		function resolveMaterialBinding( keys, instanceMaterials ) {
 
 			var materials = [];
@@ -3526,7 +3528,17 @@ THREE.ColladaLoader.prototype = {
 			for ( var i = 0, l = keys.length; i < l; i ++ ) {
 
 				var id = instanceMaterials[ keys[ i ] ];
-				materials.push( getMaterial( id ) );
+
+				if ( id === undefined ) {
+
+					console.warn( 'THREE.ColladaLoader: Material with key %s not found. Apply fallback material.', keys[ i ] );
+					materials.push( fallbackMaterial );
+
+				} else {
+
+					materials.push( getMaterial( id ) );
+
+				}
 
 			}
 

+ 119 - 34
examples/js/loaders/FBXLoader.js

@@ -51,7 +51,7 @@
 
 				} catch ( error ) {
 
-					window.setTimeout( function () {
+					setTimeout( function () {
 
 						if ( onError ) onError( error );
 
@@ -110,7 +110,7 @@
 			var materials = parseMaterials( FBXTree, textures, connections );
 			var deformers = parseDeformers( FBXTree, connections );
 			var geometryMap = parseGeometries( FBXTree, connections, deformers );
-			var sceneGraph = parseScene( FBXTree, connections, deformers.skeletons, geometryMap, materials );
+			var sceneGraph = parseScene( FBXTree, connections, deformers, geometryMap, materials );
 
 			return sceneGraph;
 
@@ -371,7 +371,7 @@
 
 		var texture;
 
-		if ( textureNode.FileName.slice( -3 ).toLowerCase() === 'tga' ) {
+		if ( textureNode.FileName.slice( - 3 ).toLowerCase() === 'tga' ) {
 
  			texture = THREE.Loader.Handlers.get( '.tga' ).load( fileName );
 
@@ -419,7 +419,7 @@
 		var name = materialNode.attrName;
 		var type = materialNode.ShadingModel;
 
-		//Case where FBX wraps shading model in property object.
+		// Case where FBX wraps shading model in property object.
 		if ( typeof type === 'object' ) {
 
 			type = type.value;
@@ -633,11 +633,10 @@
 						id: nodeID,
 					};
 
-					morphTarget.rawTargets = parseMorphTargets( relationships, deformerNode, DeformerNodes, connections );
+					morphTarget.rawTargets = parseMorphTargets( relationships, DeformerNodes, connections );
 					morphTarget.id = nodeID;
 
 					if ( relationships.parents.length > 1 ) console.warn( 'THREE.FBXLoader: morph target attached to more than one geometry is not supported.' );
-					morphTarget.parentGeoID = relationships.parents[ 0 ].ID;
 
 					morphTargets[ nodeID ] = morphTarget;
 
@@ -701,7 +700,7 @@
 	}
 
 	// The top level morph deformer node has type "BlendShape" and sub nodes have type "BlendShapeChannel"
-	function parseMorphTargets( relationships, deformerNode, deformerNodes, connections ) {
+	function parseMorphTargets( relationships, deformerNodes, connections ) {
 
 		var rawMorphTargets = [];
 
@@ -734,18 +733,7 @@
 
 			targetRelationships.children.forEach( function ( child ) {
 
-				if ( child.relationship === 'DeformPercent' ) {
-
-					// TODO: animation of morph targets is currently unsupported
-					rawMorphTarget.weightCurveID = child.ID;
-					// weightCurve = FBXTree.Objects.AnimationCurveNode[ weightCurveID ];
-
-				} else {
-
-					rawMorphTarget.geoID = child.ID;
-					// morphGeo = FBXTree.Objects.Geometry[ geoID ];
-
-				}
+				if ( child.relationship === undefined ) rawMorphTarget.geoID = child.ID;
 
 			} );
 
@@ -1626,11 +1614,11 @@
 	}
 
 	// create the main THREE.Group() to be returned by the loader
-	function parseScene( FBXTree, connections, skeletons, geometryMap, materialMap ) {
+	function parseScene( FBXTree, connections, deformers, geometryMap, materialMap ) {
 
 		var sceneGraph = new THREE.Group();
 
-		var modelMap = parseModels( FBXTree, skeletons, geometryMap, materialMap, connections );
+		var modelMap = parseModels( FBXTree, deformers.skeletons, geometryMap, materialMap, connections );
 
 		var modelNodes = FBXTree.Objects.Model;
 
@@ -1657,16 +1645,52 @@
 
 		} );
 
-		bindSkeleton( FBXTree, skeletons, geometryMap, modelMap, connections );
-
+		bindSkeleton( FBXTree, deformers.skeletons, geometryMap, modelMap, connections );
 		addAnimations( FBXTree, connections, sceneGraph );
-
 		createAmbientLight( FBXTree, sceneGraph );
 
+		setupMorphMaterials( sceneGraph );
+
 		return sceneGraph;
 
 	}
 
+	function setupMorphMaterials( sceneGraph ) {
+
+		sceneGraph.traverse( function ( child ) {
+
+			if ( child.isMesh ) {
+
+				if ( child.geometry.morphAttributes.position || child.geometry.morphAttributes.normal ) {
+
+					var uuid = child.uuid;
+					var matUuid = child.material.uuid;
+
+					// if a geometry has morph targets, it cannot share the material with other geometries
+					var sharedMat = false;
+
+					sceneGraph.traverse( function ( child ) {
+
+						if ( child.isMesh ) {
+
+							if ( child.material.uuid === matUuid && child.uuid !== uuid ) sharedMat = true;
+
+						}
+
+					} );
+
+					if ( sharedMat === true ) child.material = child.material.clone();
+
+					child.material.morphTargets = true;
+
+				}
+
+			}
+
+		} );
+
+	}
+
 	// parse nodes in FBXTree.Objects.Model
 	function parseModels( FBXTree, skeletons, geometryMap, materialMap, connections ) {
 
@@ -2273,7 +2297,6 @@
 		var curveNodesMap = parseAnimationCurveNodes( FBXTree );
 
 		parseAnimationCurves( FBXTree, connections, curveNodesMap );
-
 		var layersMap = parseAnimationLayers( FBXTree, connections, curveNodesMap );
 		var rawClips = parseAnimStacks( FBXTree, connections, layersMap );
 
@@ -2294,7 +2317,7 @@
 
 			var rawCurveNode = rawCurveNodes[ nodeID ];
 
-			if ( rawCurveNode.attrName.match( /S|R|T/ ) !== null ) {
+			if ( rawCurveNode.attrName.match( /S|R|T|DeformPercent/ ) !== null ) {
 
 				var curveNode = {
 
@@ -2321,6 +2344,13 @@
 
 		var rawCurves = FBXTree.Objects.AnimationCurve;
 
+		// TODO: Many values are identical up to roundoff error, but won't be optimised
+		// e.g. position times: [0, 0.4, 0. 8]
+		// position values: [7.23538335023477e-7, 93.67518615722656, -0.9982695579528809, 7.23538335023477e-7, 93.67518615722656, -0.9982695579528809, 7.235384487103147e-7, 93.67520904541016, -0.9982695579528809]
+		// clearly, this should be optimised to
+		// times: [0], positions [7.23538335023477e-7, 93.67518615722656, -0.9982695579528809]
+		// this shows up in nearly every FBX file, and generally time array is length > 100
+
 		for ( var nodeID in rawCurves ) {
 
 			var animationCurve = {
@@ -2350,6 +2380,10 @@
 
 					curveNodesMap.get( animationCurveID ).curves[ 'z' ] = animationCurve;
 
+				} else if ( animationCurveRelationship.match( /d|DeformPercent/ ) ) {
+
+					curveNodesMap.get( animationCurveID ).curves[ 'morph' ] = animationCurve;
+
 				}
 
 			}
@@ -2424,9 +2458,40 @@
 
 							layerCurveNodes[ i ][ curveNode.attr ] = curveNode;
 
-						}
+						} else if ( curveNode.curves.morph !== undefined ) {
 
+							if ( layerCurveNodes[ i ] === undefined ) {
+
+								var deformerID;
+
+								connections.get( child.ID ).parents.forEach( function ( parent ) {
+
+									if ( parent.relationship !== undefined ) deformerID = parent.ID;
+
+								} );
+
+								var morpherID = connections.get( deformerID ).parents[ 0 ].ID;
+								var geoID = connections.get( morpherID ).parents[ 0 ].ID;
+
+								// assuming geometry is not used in more than one model
+								var modelID = connections.get( geoID ).parents[ 0 ].ID;
+
+								var rawModel = FBXTree.Objects.Model[ modelID ];
+
+								var node = {
+
+									modelName: THREE.PropertyBinding.sanitizeNodeName( rawModel.attrName ),
+									morphName: FBXTree.Objects.Deformer[ deformerID ].attrName,
+
+								};
+
+								layerCurveNodes[ i ] = node;
 
+							}
+
+							layerCurveNodes[ i ][ curveNode.attr ] = curveNode;
+
+						}
 
 					}
 
@@ -2478,7 +2543,7 @@
 
 	}
 
-	// take raw animation data from parseAnimations and connect it up to the loaded models
+	// take raw animation clips and turn them into three.js animation clips
 	function addAnimations( FBXTree, connections, sceneGraph ) {
 
 		sceneGraph.animations = [];
@@ -2487,12 +2552,11 @@
 
 		if ( rawClips === undefined ) return;
 
-
 		for ( var key in rawClips ) {
 
 			var rawClip = rawClips[ key ];
 
-			var clip = addClip( rawClip );
+			var clip = addClip( rawClip, sceneGraph );
 
 			sceneGraph.animations.push( clip );
 
@@ -2500,13 +2564,13 @@
 
 	}
 
-	function addClip( rawClip ) {
+	function addClip( rawClip, sceneGraph ) {
 
 		var tracks = [];
 
 		rawClip.layer.forEach( function ( rawTracks ) {
 
-			tracks = tracks.concat( generateTracks( rawTracks ) );
+			tracks = tracks.concat( generateTracks( rawTracks, sceneGraph ) );
 
 		} );
 
@@ -2514,7 +2578,7 @@
 
 	}
 
-	function generateTracks( rawTracks ) {
+	function generateTracks( rawTracks, sceneGraph ) {
 
 		var tracks = [];
 
@@ -2539,6 +2603,12 @@
 
 		}
 
+		if ( rawTracks.DeformPercent !== undefined ) {
+			var morphTrack = generateMorphTrack( rawTracks, sceneGraph );
+			if ( morphTrack !== undefined ) tracks.push( morphTrack );
+
+		}
+
 		return tracks;
 
 	}
@@ -2607,6 +2677,21 @@
 
 	}
 
+	function generateMorphTrack( rawTracks, sceneGraph ) {
+
+		var curves = rawTracks.DeformPercent.curves.morph;
+		var values = curves.values.map( function ( val ) {
+
+			return val / 100;
+
+		} );
+
+		var morphNum = sceneGraph.getObjectByName( rawTracks.modelName ).morphTargetDictionary[ rawTracks.morphName ];
+
+		return new THREE.NumberKeyframeTrack( rawTracks.modelName + '.morphTargetInfluences[' + morphNum + ']', curves.times, values );
+
+	}
+
 	function getKeyframeTrackValues( times, curves, initialValue ) {
 
 		var prevValue = initialValue;
@@ -3363,7 +3448,7 @@
 
 					}
 
-					if ( window.Zlib === undefined ) {
+					if ( typeof Zlib === 'undefined' ) {
 
 						console.error( 'THREE.FBXLoader: External library Inflate.min.js required, obtain or import from https://github.com/imaya/zlib.js' );
 

+ 74 - 405
examples/js/loaders/NodeMaterialLoader.js

@@ -91,7 +91,11 @@ Object.assign( THREE.NodeMaterialLoader.prototype, {
 
 	getObjectById: function ( uuid ) {
 
-		return this.library[ uuid ] || this.nodes[ uuid ] || this.names[ uuid ];
+		return this.library[ uuid ] || 
+			this.nodes[ uuid ] || 
+			this.materials[ uuid ] ||
+			this.passes[ uuid ] || 
+			this.names[ uuid ];
 
 	},
 
@@ -109,15 +113,62 @@ Object.assign( THREE.NodeMaterialLoader.prototype, {
 
 	},
 
-	parse: function ( json ) {
-
-		var uuid, node, object, prop, i;
+	resolve: function( json ) {
+		
+		switch( typeof json ) {
+			
+			case "boolean":
+			case "number":
+			
+				return json;
+			
+			case "string":
+			
+				if (/^\w{8}-\w{4}-\w{4}-\w{4}-\w{12}$/i.test(json) || this.library[ json ]) {
+					
+					return this.getNode( json );
+					
+				}
+				
+				return json;
+
+			default:
+			
+				if ( Array.isArray( json ) ) {
+			
+					for(var i = 0; i < json.length; i++) {
+						
+						json[i] = this.resolve( json[i] );
+						
+					}
+					
+				} else {
+					
+					for ( var prop in json ) {
+						
+						if (prop === "uuid") continue;
+						
+						json[ prop ] = this.resolve( json[ prop ] );
+						
+					}
+					
+				}
+				
+		}
+		
+		return json;
+		
+	},
+	
+	declare: function( json ) {
+		
+		var uuid, node, object;
 
 		for ( uuid in json.nodes ) {
 
 			node = json.nodes[ uuid ];
 
-			object = new THREE[ node.type ]();
+			object = new THREE[ node.nodeType + "Node" ]();
 
 			if ( node.name ) {
 
@@ -125,15 +176,8 @@ Object.assign( THREE.NodeMaterialLoader.prototype, {
 
 				this.names[ object.name ] = object;
 
-			} else {
-
-				// ignore "uniform" shader input ( for optimization )
-				object.readonly = true;
-
 			}
 
-			if ( node.readonly !== undefined ) object.readonly = node.readonly;
-
 			this.nodes[ uuid ] = object;
 
 		}
@@ -174,410 +218,35 @@ Object.assign( THREE.NodeMaterialLoader.prototype, {
 
 		}
 
-		if ( json.material ) this.material = this.materials[ uuid ];
-		if ( json.pass ) this.pass = this.passes[ uuid ];
+		if ( json.material ) this.material = this.materials[ json.material ];
+		
+		if ( json.pass ) this.pass = this.passes[ json.pass ];
+		
+		return json;
+		
+	},
+	
+	parse: function ( json ) {
 
+		var uuid;
+	
+		json = this.resolve( this.declare( json ) );
+		
 		for ( uuid in json.nodes ) {
 
-			node = json.nodes[ uuid ];
-			object = this.nodes[ uuid ];
-
-			switch ( node.type ) {
-
-				case "IntNode":
-				case "FloatNode":
-
-					object.value = node.value;
-
-					break;
-
-				case "ColorNode":
-
-					object.value.copy( node );
-
-					break;
-
-				case "Vector2Node":
-
-					object.x = node.x;
-					object.y = node.y;
-
-					break;
-
-
-				case "Vector3Node":
-
-					object.x = node.x;
-					object.y = node.y;
-					object.z = node.z;
-
-					break;
-
-				case "Vector4Node":
-
-					object.x = node.x;
-					object.y = node.y;
-					object.z = node.z;
-					object.w = node.w;
-
-					break;
-
-				case "Matrix3Node":
-				case "Matrix4Node":
-
-					object.value.fromArray( node.elements );
-
-					break;
-
-				case "OperatorNode":
-
-					object.a = this.getNode( node.a );
-					object.b = this.getNode( node.b );
-					object.op = node.op;
-
-					break;
-
-				case "Math1Node":
-
-					object.a = this.getNode( node.a );
-					object.method = node.method;
-
-					break;
-
-				case "Math2Node":
-
-					object.a = this.getNode( node.a );
-					object.b = this.getNode( node.b );
-					object.method = node.method;
-
-					break;
-
-				case "Math3Node":
-
-					object.a = this.getNode( node.a );
-					object.b = this.getNode( node.b );
-					object.c = this.getNode( node.c );
-					object.method = node.method;
-
-					break;
-
-				case "UVNode":
-				case "ColorsNode":
-
-					object.index = node.index;
-
-					break;
-
-
-				case "LuminanceNode":
-
-					object.rgb = this.getNode( node.rgb );
-
-					break;
-
-				case "PositionNode":
-				case "NormalNode":
-				case "ReflectNode":
-				case "LightNode":
-
-					object.scope = node.scope;
-
-					break;
-
-				case "SwitchNode":
-
-					object.node = this.getNode( node.node );
-					object.components = node.components;
-
-					break;
-
-				case "JoinNode":
-
-					for ( prop in node.inputs ) {
-
-						object[ prop ] = this.getNode( node.inputs[ prop ] );
-
-					}
-
-					break;
-
-				case "CameraNode":
-
-					object.setScope( node.scope );
-
-					if ( node.camera ) object.setCamera( this.getNode( node.camera ) );
-
-					switch ( node.scope ) {
-
-						case THREE.CameraNode.DEPTH:
-
-							object.near.number = node.near;
-							object.far.number = node.far;
-
-							break;
-
-					}
-
-					break;
-
-				case "ColorAdjustmentNode":
-
-					object.rgb = this.getNode( node.rgb );
-					object.adjustment = this.getNode( node.adjustment );
-					object.method = node.method;
-
-					break;
-
-				case "UVTransformNode":
-
-					object.uv = this.getNode( node.uv );
-					object.transform = this.getNode( node.transform );
-
-					break;
-
-				case "BumpNode":
-
-					object.value = this.getNode( node.value );
-					object.coord = this.getNode( node.coord );
-					object.scale = this.getNode( node.scale );
-
-					break;
-
-				case "BlurNode":
-
-					object.value = this.getNode( node.value );
-					object.coord = this.getNode( node.coord );
-					object.scale = this.getNode( node.scale );
-
-					object.value = this.getNode( node.value );
-					object.coord = this.getNode( node.coord );
-					object.radius = this.getNode( node.radius );
-
-					if ( node.size !== undefined ) object.size = new THREE.Vector2( node.size.x, node.size.y );
-
-					object.blurX = node.blurX;
-					object.blurY = node.blurY;
-
-					break;
-
-				case "ResolutionNode":
-
-					object.renderer = this.getNode( node.renderer );
-
-					break;
-
-				case "ScreenUVNode":
-
-					object.resolution = this.getNode( node.resolution );
-
-					break;
-
-				case "VelocityNode":
-
-					if ( node.target ) object.setTarget( this.getNode( node.target ) );
-					object.setParams( node.params );
-
-					break;
-
-				case "TimerNode":
-
-					object.scope = node.scope;
-					object.scale = node.scale;
-
-					break;
-
-				case "ConstNode":
-
-					object.name = node.name;
-					object.type = node.out;
-					object.value = node.value;
-					object.useDefine = node.useDefine === true;
-
-					break;
-
-				case "AttributeNode":
-				case "VarNode":
-
-					object.type = node.out;
-
-					break;
-
-
-				case "ReflectorNode":
-
-					object.setMirror( this.getNode( node.mirror ) );
-
-					if ( node.offset ) object.offset = this.getNode( node.offset );
-
-					break;
-
-				case "NoiseNode":
-
-					object.coord = this.getNode( node.coord );
-
-					break;
-
-				case "FunctionNode":
-
-					object.isMethod = node.isMethod;
-					object.useKeywords = node.useKeywords;
-
-					object.extensions = node.extensions;
-					object.keywords = {};
-
-					for ( prop in node.keywords ) {
-
-						object.keywords[ prop ] = this.getNode( node.keywords[ prop ] );
-
-					}
-
-					if ( node.includes ) {
-
-						for ( i = 0; i < node.includes.length; i ++ ) {
-
-							object.includes.push( this.getNode( node.includes[ i ] ) );
-
-						}
-
-					}
-
-					object.eval( node.src, object.includes, object.extensions, object.keywords );
-
-					if ( ! object.isMethod ) object.type = node.out;
-
-					break;
-
-				case "FunctionCallNode":
-
-					for ( prop in node.inputs ) {
-
-						object.inputs[ prop ] = this.getNode( node.inputs[ prop ] );
-
-					}
-
-					object.value = this.getNode( node.value );
-
-					break;
-
-				case "TextureNode":
-				case "CubeTextureNode":
-				case "ScreenNode":
-
-					if ( node.value ) object.value = this.getNode( node.value );
-
-					object.coord = this.getNode( node.coord );
-
-					if ( node.bias ) object.bias = this.getNode( node.bias );
-					if ( object.project !== undefined ) object.project = node.project;
-
-					break;
-
-				case "RoughnessToBlinnExponentNode":
-					break;
-
-				case "RawNode":
-
-					object.value = this.getNode( node.value );
-
-					break;
-
-				case "StandardNode":
-				case "PhongNode":
-				case "SpriteNode":
-
-					object.color = this.getNode( node.color );
-
-					if ( node.alpha ) object.alpha = this.getNode( node.alpha );
-
-					if ( node.specular ) object.specular = this.getNode( node.specular );
-					if ( node.shininess ) object.shininess = this.getNode( node.shininess );
-
-					if ( node.roughness ) object.roughness = this.getNode( node.roughness );
-					if ( node.metalness ) object.metalness = this.getNode( node.metalness );
-
-					if ( node.reflectivity ) object.reflectivity = this.getNode( node.reflectivity );
-
-					if ( node.clearCoat ) object.clearCoat = this.getNode( node.clearCoat );
-					if ( node.clearCoatRoughness ) object.clearCoatRoughness = this.getNode( node.clearCoatRoughness );
-
-					if ( node.normal ) object.normal = this.getNode( node.normal );
-					if ( node.normalScale ) object.normalScale = this.getNode( node.normalScale );
-
-					if ( node.emissive ) object.emissive = this.getNode( node.emissive );
-					if ( node.ambient ) object.ambient = this.getNode( node.ambient );
-
-					if ( node.shadow ) object.shadow = this.getNode( node.shadow );
-					if ( node.light ) object.light = this.getNode( node.light );
-
-					if ( node.ao ) object.ao = this.getNode( node.ao );
-
-					if ( node.environment ) object.environment = this.getNode( node.environment );
-					if ( node.environmentAlpha ) object.environmentAlpha = this.getNode( node.environmentAlpha );
-
-					if ( node.transform ) object.transform = this.getNode( node.transform );
-
-					if ( node.spherical === false ) object.spherical = false;
-
-					break;
-
-				default:
-
-					console.warn( node.type, "not supported." );
-
-			}
+			this.nodes[ uuid ].copy( json.nodes[ uuid ] );
 
 		}
-
+		
 		for ( uuid in json.materials ) {
 
-			node = json.materials[ uuid ];
-			object = this.materials[ uuid ];
-
-			if ( node.name !== undefined ) object.name = node.name;
-
-			if ( node.blending !== undefined ) object.blending = node.blending;
-			if ( node.flatShading !== undefined ) object.flatShading = node.flatShading;
-			if ( node.side !== undefined ) object.side = node.side;
-
-			object.depthFunc = node.depthFunc;
-			object.depthTest = node.depthTest;
-			object.depthWrite = node.depthWrite;
-
-			if ( node.wireframe !== undefined ) object.wireframe = node.wireframe;
-			if ( node.wireframeLinewidth !== undefined ) object.wireframeLinewidth = node.wireframeLinewidth;
-			if ( node.wireframeLinecap !== undefined ) object.wireframeLinecap = node.wireframeLinecap;
-			if ( node.wireframeLinejoin !== undefined ) object.wireframeLinejoin = node.wireframeLinejoin;
-
-			if ( node.skinning !== undefined ) object.skinning = node.skinning;
-			if ( node.morphTargets !== undefined ) object.morphTargets = node.morphTargets;
-
-			if ( node.visible !== undefined ) object.visible = node.visible;
-			if ( node.userData !== undefined ) object.userData = node.userData;
-
-			object.vertex = this.getNode( node.vertex );
-			object.fragment = this.getNode( node.fragment );
-
-			if ( object.vertex === object.fragment ) {
-
-				// replace main node
-
-				object.node = object.vertex;
-
-			}
-
-			if ( node.fog !== undefined ) object.fog = node.fog;
-			if ( node.lights !== undefined ) object.lights = node.lights;
-
-			if ( node.transparent !== undefined ) object.transparent = node.transparent;
+			this.materials[ uuid ].copy( json.materials[ uuid ] );
 
 		}
-
+		
 		for ( uuid in json.passes ) {
 
-			node = json.passes[ uuid ];
-			object = this.passes[ uuid ];
-
-			object.value = this.getNode( node.value );
+			this.passes[ uuid ].copy( json.passes[ uuid ] );
 
 		}
 

+ 0 - 774
examples/js/modifiers/BufferSubdivisionModifier.js

@@ -1,774 +0,0 @@
-/*
- * @author zz85 / http://twitter.com/blurspline / http://www.lab4games.net/zz85/blog
- * @author Matthew Adams / http://www.centerionware.com - added UV support and rewrote to use buffergeometry.
- *
- * Subdivision Geometry Modifier using Loop Subdivision Scheme for Geometry / BufferGeometry
- *
- * References:
- *	http://graphics.stanford.edu/~mdfisher/subdivision.html
- *	http://www.holmes3d.net/graphics/subdivision/
- *	http://www.cs.rutgers.edu/~decarlo/readings/subdiv-sg00c.pdf
- *
- * Known Issues:
- *	- currently doesn't handle "Sharp Edges"
- *	- no checks to prevent breaking when uv's don't exist.
- *	- vertex colors are unsupported.
- *	**DDS Images when using corrected uv's passed to subdivision modifier will have their uv's flipy'd within the correct uv set
- *	**Either flipy the DDS image, or use shaders. Don't try correcting the uv's before passing into subdiv (eg: v=1-v).
- *
- * @input THREE.Geometry, or index'd THREE.BufferGeometry with faceUV's (Not vertex uv's)
- * @output non-indexed vertex points, uv's, normals.
- *
- * The TypedArrayHelper class is designed to assist managing typed arrays, and to allow the removal of all 'new Vector3, new Face3, new Vector2'.
- *
- * It will automatically resize them if trying to push a new element to an array that isn't long enough
- * It provides 'registers' that the units can be mapped to. This allows a small set of objects
- * (ex: vector3's, face3's, vector2's) to be allocated then used, to eliminate any need to rewrite all
- * the features those classes offer while not requiring some_huge_number to be allocated.
- * It should be moved into it's own file honestly, then included before the BufferSubdivisionModifier - maybe in three's core?
- *
- */
-
-THREE.Face3.prototype.set = function( a, b, c ) {
-
-	this.a = a;
-	this.b = b;
-	this.c = c;
-
-};
-
-var TypedArrayHelper = function( size, registers, register_type, array_type, unit_size, accessors ) {
-
-	this.array_type = array_type;
-	this.register_type = register_type;
-	this.unit_size = unit_size;
-	this.accessors = accessors;
-	this.buffer = new array_type( size * unit_size );
-	this.register = [];
-	this.length = 0;
-	this.real_length = size;
-	this.available_registers = registers;
-
-	for ( var i = 0; i < registers; i++ ) {
-
-		this.register.push( new register_type() );
-
-	}
-
-};
-
-TypedArrayHelper.prototype = {
-
-	constructor: TypedArrayHelper,
-
-	index_to_register: function( index, register, isLoop ) {
-
-		var base = index * this.unit_size;
-
-		if ( register >= this.available_registers ) {
-
-			throw new Error( 'THREE.BufferSubdivisionModifier: Not enough registers in TypedArrayHelper.' );
-
-		}
-
-		if ( index > this.length ) {
-
-			throw new Error( 'THREE.BufferSubdivisionModifier: Index is out of range in TypedArrayHelper.' );
-
-		}
-
-		for ( var i = 0; i < this.unit_size; i++ ) {
-
-			( this.register[ register ] )[ this.accessors[ i ] ] = this.buffer[ base + i ];
-
-		}
-
-	},
-
-	resize: function( new_size ) {
-
-		if ( new_size === 0 ) {
-
-			new_size = 8;
-
-		}
-
-		if ( new_size < this.length ) {
-
-			this.buffer = this.buffer.subarray( 0, this.length * this.unit_size );
-
-		} else {
-
-			var nBuffer;
-
-			if ( this.buffer.length < new_size * this.unit_size ) {
-
-				nBuffer = new this.array_type( new_size * this.unit_size );
-				nBuffer.set( this.buffer );
-				this.buffer = nBuffer;
-				this.real_length = new_size;
-
-			} else {
-
-				nBuffer = new this.array_type( new_size * this.unit_size );
-				nBuffer.set( this.buffer.subarray( 0, this.length * this.unit_size ) );
-				this.buffer = nBuffer;
-				this.real_length = new_size;
-
-			}
-
-		}
-
-	},
-
-	from_existing: function( oldArray ) {
-
-		var new_size = oldArray.length;
-		this.buffer = new this.array_type( new_size );
-		this.buffer.set( oldArray );
-		this.length = oldArray.length / this.unit_size;
-		this.real_length = this.length;
-
-	},
-
-	push_element: function( vector ) {
-
-		if ( this.length + 1 > this.real_length ) {
-
-			this.resize( this.real_length * 2 );
-
-		}
-
-		var bpos = this.length * this.unit_size;
-
-		for ( var i = 0; i < this.unit_size; i++ ) {
-
-			this.buffer[ bpos + i ] = vector[ this.accessors[ i ] ];
-
-		}
-
-		this.length++;
-
-	},
-
-	trim_size: function() {
-
-		if ( this.length < this.real_length ) {
-
-			this.resize( this.length );
-
-		}
-
-	}
-
-};
-
-
-function convertGeometryToIndexedBuffer( geometry ) {
-
-	var BGeom = new THREE.BufferGeometry();
-
-	// create a new typed array
-	var vertArray = new TypedArrayHelper( geometry.vertices.length, 0, THREE.Vector3, Float32Array, 3, [ 'x', 'y', 'z' ] );
-	var indexArray = new TypedArrayHelper( geometry.faces.length, 0, THREE.Face3, Uint32Array, 3, [ 'a', 'b', 'c' ] );
-	var uvArray = new TypedArrayHelper( geometry.faceVertexUvs[0].length * 3 * 3, 0, THREE.Vector2, Float32Array, 2, [ 'x', 'y' ] );
-
-	for ( var i = 0, il = geometry.vertices.length; i < il; i++ ) {
-
-		vertArray.push_element( geometry.vertices[ i ] );
-
-	}
-
-	for ( var i = 0, il = geometry.faces.length; i < il; i++ ) {
-
-		indexArray.push_element( geometry.faces[ i ] );
-
-	}
-
-	for ( var i = 0, il = geometry.faceVertexUvs[ 0 ].length; i < il; i++ ) {
-
-		uvArray.push_element( geometry.faceVertexUvs[ 0 ][ i ][ 0 ] );
-		uvArray.push_element( geometry.faceVertexUvs[ 0 ][ i ][ 1 ] );
-		uvArray.push_element( geometry.faceVertexUvs[ 0 ][ i ][ 2 ] );
-
-	}
-
-	indexArray.trim_size();
-	vertArray.trim_size();
-	uvArray.trim_size();
-
-	BGeom.setIndex( new THREE.BufferAttribute( indexArray.buffer, 3 ) );
-	BGeom.addAttribute( 'position', new THREE.BufferAttribute( vertArray.buffer, 3 ) );
-	BGeom.addAttribute( 'uv', new THREE.BufferAttribute( uvArray.buffer, 2 ) );
-
-	return BGeom;
-
-}
-
-function compute_vertex_normals( geometry ) {
-
-	var ABC = [ 'a', 'b', 'c' ];
-	var XYZ = [ 'x', 'y', 'z' ];
-	var XY = [ 'x', 'y' ];
-
-	var oldVertices = new TypedArrayHelper( 0, 5, THREE.Vector3, Float32Array, 3, XYZ );
-	var oldFaces = new TypedArrayHelper( 0, 3, THREE.Face3, Uint32Array, 3, ABC );
-	oldVertices.from_existing( geometry.getAttribute( 'position' ).array );
-	var newNormals = new TypedArrayHelper( oldVertices.length * 3, 4, THREE.Vector3, Float32Array, 3, XYZ );
-	var newNormalFaces = new TypedArrayHelper( oldVertices.length, 1, function () { this.x = 0; }, Float32Array, 1, [ 'x' ] );
-
-	newNormals.length = oldVertices.length;
-	oldFaces.from_existing( geometry.index.array );
-	var a, b, c;
-	var my_weight;
-	var full_weights = [ 0.0, 0.0, 0.0 ];
-
-	for ( var i = 0, il = oldFaces.length; i < il; i++ ) {
-
-		oldFaces.index_to_register( i, 0 );
-
-		oldVertices.index_to_register( oldFaces.register[ 0 ].a, 0 );
-		oldVertices.index_to_register( oldFaces.register[ 0 ].b, 1 );
-		oldVertices.index_to_register( oldFaces.register[ 0 ].c, 2 );
-
-		newNormals.register[ 0 ].subVectors( oldVertices.register[ 1 ], oldVertices.register[ 0 ] );
-		newNormals.register[ 1 ].subVectors( oldVertices.register[ 2 ], oldVertices.register[ 1 ] );
-		newNormals.register[ 0 ].cross( newNormals.register[ 1 ] );
-		my_weight = Math.abs( newNormals.register[ 0 ].length() );
-
-		newNormalFaces.buffer[ oldFaces.register[ 0 ].a ] += my_weight;
-		newNormalFaces.buffer[ oldFaces.register[ 0 ].b ] += my_weight;
-		newNormalFaces.buffer[ oldFaces.register[ 0 ].c ] += my_weight;
-
-	}
-
-	var t_len;
-
-	for ( var i = 0, il = oldFaces.length; i < il; i++ ) {
-
-		oldFaces.index_to_register( i, 0 );
-		oldVertices.index_to_register( oldFaces.register[ 0 ].a, 0 );
-		oldVertices.index_to_register( oldFaces.register[ 0 ].b, 1 );
-		oldVertices.index_to_register( oldFaces.register[ 0 ].c, 2 );
-
-		newNormals.register[ 0 ].subVectors( oldVertices.register[ 1 ], oldVertices.register[ 0 ] );
-		newNormals.register[ 1 ].subVectors( oldVertices.register[ 2 ], oldVertices.register[ 0 ] );
-
-		newNormals.register[ 3 ].set( 0, 0, 0 );
-		newNormals.register[ 3 ].x = ( newNormals.register[ 0 ].y * newNormals.register[ 1 ].z ) - ( newNormals.register[ 0 ].z * newNormals.register[ 1 ].y );
-		newNormals.register[ 3 ].y = ( newNormals.register[ 0 ].z * newNormals.register[ 1 ].x ) - ( newNormals.register[ 0 ].x * newNormals.register[ 1 ].z );
-		newNormals.register[ 3 ].z = ( newNormals.register[ 0 ].x * newNormals.register[ 1 ].y ) - ( newNormals.register[ 0 ].y * newNormals.register[ 1 ].x );
-
-		newNormals.register[ 0 ].cross( newNormals.register[ 1 ] );
-
-		my_weight = Math.abs( newNormals.register[ 0 ].length() );
-
-		full_weights[ 0 ] = ( my_weight / newNormalFaces.buffer[ oldFaces.register[ 0 ].a ] );
-		full_weights[ 1 ] = ( my_weight / newNormalFaces.buffer[ oldFaces.register[ 0 ].b ] );
-		full_weights[ 2 ] = ( my_weight / newNormalFaces.buffer[ oldFaces.register[ 0 ].c ] );
-
-		newNormals.buffer[ ( oldFaces.register[ 0 ].a * 3 ) + 0 ] += newNormals.register[ 3 ].x * full_weights[ 0 ];
-		newNormals.buffer[ ( oldFaces.register[ 0 ].a * 3 ) + 1 ] += newNormals.register[ 3 ].y * full_weights[ 0 ];
-		newNormals.buffer[ ( oldFaces.register[ 0 ].a * 3 ) + 2 ] += newNormals.register[ 3 ].z * full_weights[ 0 ];
-
-		newNormals.buffer[ ( oldFaces.register[ 0 ].b * 3 ) + 0 ] += newNormals.register[ 3 ].x * full_weights[ 1 ];
-		newNormals.buffer[ ( oldFaces.register[ 0 ].b * 3 ) + 1 ] += newNormals.register[ 3 ].y * full_weights[ 1 ];
-		newNormals.buffer[ ( oldFaces.register[ 0 ].b * 3 ) + 2 ] += newNormals.register[ 3 ].z * full_weights[ 1 ];
-
-		newNormals.buffer[ ( oldFaces.register[ 0 ].c * 3 ) + 0 ] += newNormals.register[ 3 ].x * full_weights[ 2 ];
-		newNormals.buffer[ ( oldFaces.register[ 0 ].c * 3 ) + 1 ] += newNormals.register[ 3 ].y * full_weights[ 2 ];
-		newNormals.buffer[ ( oldFaces.register[ 0 ].c * 3 ) + 2 ] += newNormals.register[ 3 ].z * full_weights[ 2 ];
-
-	}
-
-	newNormals.trim_size();
-	geometry.addAttribute( 'normal', new THREE.BufferAttribute( newNormals.buffer, 3 ) );
-
-}
-
-function unIndexIndexedGeometry( geometry ) {
-
-	var ABC = [ 'a', 'b', 'c' ];
-	var XYZ = [ 'x', 'y', 'z' ];
-	var XY = [ 'x', 'y' ];
-
-	var oldVertices = new TypedArrayHelper( 0, 3, THREE.Vector3, Float32Array, 3, XYZ );
-	var oldFaces = new TypedArrayHelper( 0, 3, THREE.Face3, Uint32Array, 3, ABC );
-	var oldUvs = new TypedArrayHelper( 0, 3, THREE.Vector2, Float32Array, 2, XY );
-	var oldNormals = new TypedArrayHelper( 0, 3, THREE.Vector3, Float32Array, 3, XYZ );
-
-	oldVertices.from_existing( geometry.getAttribute( 'position' ).array );
-	oldFaces.from_existing( geometry.index.array );
-	oldUvs.from_existing( geometry.getAttribute( 'uv' ).array );
-
-	compute_vertex_normals( geometry );
-	oldNormals.from_existing( geometry.getAttribute( 'normal' ).array );
-
-	var newVertices = new TypedArrayHelper( oldFaces.length * 3, 3, THREE.Vector3, Float32Array, 3, XYZ );
-	var newNormals = new TypedArrayHelper( oldFaces.length * 3, 3, THREE.Vector3, Float32Array, 3, XYZ );
-	var newUvs = new TypedArrayHelper( oldFaces.length * 3, 3, THREE.Vector2, Float32Array, 2, XY );
-	var v, w;
-
-	for ( var i = 0, il = oldFaces.length; i < il; i++ ) {
-
-		oldFaces.index_to_register( i, 0 );
-
-		oldVertices.index_to_register( oldFaces.register[ 0 ].a, 0 );
-		oldVertices.index_to_register( oldFaces.register[ 0 ].b, 1 );
-		oldVertices.index_to_register( oldFaces.register[ 0 ].c, 2 );
-
-		newVertices.push_element( oldVertices.register[ 0 ] );
-		newVertices.push_element( oldVertices.register[ 1 ] );
-		newVertices.push_element( oldVertices.register[ 2 ] );
-
-			if ( oldUvs.length !== 0 ) {
-
-				oldUvs.index_to_register( ( i * 3 ) + 0, 0 );
-				oldUvs.index_to_register( ( i * 3 ) + 1, 1 );
-				oldUvs.index_to_register( ( i * 3 ) + 2, 2 );
-
-				newUvs.push_element( oldUvs.register[ 0 ] );
-				newUvs.push_element( oldUvs.register[ 1 ] );
-				newUvs.push_element( oldUvs.register[ 2 ] );
-
-			}
-
-		oldNormals.index_to_register( oldFaces.register[ 0 ].a, 0 );
-		oldNormals.index_to_register( oldFaces.register[ 0 ].b, 1 );
-		oldNormals.index_to_register( oldFaces.register[ 0 ].c, 2 );
-
-		newNormals.push_element( oldNormals.register[ 0 ] );
-		newNormals.push_element( oldNormals.register[ 1 ] );
-		newNormals.push_element( oldNormals.register[ 2 ] );
-
-	}
-
-	newVertices.trim_size();
-	newUvs.trim_size();
-	newNormals.trim_size();
-
-	geometry.index = null;
-
-	geometry.addAttribute( 'position', new THREE.BufferAttribute( newVertices.buffer, 3 ) );
-	geometry.addAttribute( 'normal', new THREE.BufferAttribute( newNormals.buffer, 3 ) );
-
-	if ( newUvs.length !== 0 ) {
-
-		geometry.addAttribute( 'uv', new THREE.BufferAttribute( newUvs.buffer, 2 ) );
-
-	}
-
-	return geometry;
-
-}
-
-THREE.BufferSubdivisionModifier = function( subdivisions ) {
-
-	this.subdivisions = ( subdivisions === undefined ) ? 1 : subdivisions;
-
-};
-
-THREE.BufferSubdivisionModifier.prototype.modify = function( geometry ) {
-
-	if ( geometry instanceof THREE.Geometry ) {
-
-		geometry.mergeVertices();
-
-		if ( typeof geometry.normals === 'undefined' ) {
-
-			geometry.normals = [];
-
-		}
-
-		geometry = convertGeometryToIndexedBuffer( geometry );
-
-	} else if ( !( geometry instanceof THREE.BufferGeometry ) ) {
-
-		console.error( 'THREE.BufferSubdivisionModifier: Geometry is not an instance of THREE.BufferGeometry or THREE.Geometry' );
-
-	}
-
-	var repeats = this.subdivisions;
-
-	while ( repeats -- > 0 ) {
-
-		this.smooth( geometry );
-
-	}
-
-	return unIndexIndexedGeometry( geometry );
-
-};
-
-var edge_type = function ( a, b ) {
-
-	this.a = a;
-	this.b = b;
-	this.faces = [];
-	this.newEdge = null;
-
-};
-
-( function () {
-
-	// Some constants
-	var ABC = [ 'a', 'b', 'c' ];
-	var XYZ = [ 'x', 'y', 'z' ];
-	var XY = [ 'x', 'y' ];
-
-	function getEdge( a, b, map ) {
-
-		var key = Math.min( a, b ) + '_' + Math.max( a, b );
-		return map[ key ];
-
-	}
-
-
-	function processEdge( a, b, vertices, map, face, metaVertices ) {
-
-		var vertexIndexA = Math.min( a, b );
-		var vertexIndexB = Math.max( a, b );
-
-		var key = vertexIndexA + '_' + vertexIndexB;
-
-		var edge;
-
-		if ( key in map ) {
-
-			edge = map[ key ];
-
-		} else {
-
-			edge = new edge_type( vertexIndexA,vertexIndexB );
-			map[key] = edge;
-
-		}
-
-		edge.faces.push( face );
-
-		metaVertices[ a ].edges.push( edge );
-		metaVertices[ b ].edges.push( edge );
-
-	}
-
-	function generateLookups( vertices, faces, metaVertices, edges ) {
-
-		var i, il, face, edge;
-
-		for ( i = 0, il = vertices.length; i < il; i++ ) {
-
-			metaVertices[ i ] = { edges: [] };
-
-		}
-
-		for ( i = 0, il = faces.length; i < il; i++ ) {
-
-			faces.index_to_register( i, 0 );
-			face = faces.register[ 0 ]; // Faces is now a TypedArrayHelper class, not a face3.
-
-			processEdge( face.a, face.b, vertices, edges, i, metaVertices );
-			processEdge( face.b, face.c, vertices, edges, i, metaVertices );
-			processEdge( face.c, face.a, vertices, edges, i, metaVertices );
-
-		}
-
-	}
-
-	function newFace( newFaces, face ) {
-
-		newFaces.push_element( face );
-
-	}
-
-	function midpoint( a, b ) {
-
-		return ( Math.abs( b - a ) / 2 ) + Math.min( a, b );
-
-	}
-
-	function newUv( newUvs, a, b, c ) {
-
-		newUvs.push_element( a );
-		newUvs.push_element( b );
-		newUvs.push_element( c );
-
-	}
-
-	/////////////////////////////
-
-	// Performs one iteration of Subdivision
-
-	THREE.BufferSubdivisionModifier.prototype.smooth = function ( geometry ) {
-
-		var oldVertices, oldFaces, oldUvs;
-		var newVertices, newFaces, newUVs;
-
-		var n, l, i, il, j, k;
-		var metaVertices, sourceEdges;
-
-		oldVertices = new TypedArrayHelper( 0, 3, THREE.Vector3, Float32Array, 3, XYZ );
-		oldFaces = new TypedArrayHelper( 0, 3, THREE.Face3, Uint32Array, 3, ABC );
-		oldUvs = new TypedArrayHelper( 0, 3, THREE.Vector2, Float32Array, 2, XY );
-		oldVertices.from_existing( geometry.getAttribute( 'position' ).array );
-		oldFaces.from_existing( geometry.index.array );
-		oldUvs.from_existing( geometry.getAttribute( 'uv' ).array );
-
-		var doUvs = false;
-
-		if ( typeof oldUvs !== 'undefined' && oldUvs.length !== 0 ) {
-
-			doUvs = true;
-
-		}
-		/******************************************************
-		*
-		* Step 0: Preprocess Geometry to Generate edges Lookup
-		*
-		*******************************************************/
-
-		metaVertices = new Array( oldVertices.length );
-		sourceEdges = {}; // Edge => { oldVertex1, oldVertex2, faces[]  }
-
-		generateLookups( oldVertices, oldFaces, metaVertices, sourceEdges );
-
-
-		/******************************************************
-		*
-		*	Step 1.
-		*	For each edge, create a new Edge Vertex,
-		*	then position it.
-		*
-		*******************************************************/
-
-		newVertices = new TypedArrayHelper( ( geometry.getAttribute( 'position' ).array.length * 2 ) / 3, 2, THREE.Vector3, Float32Array, 3, XYZ );
-		var other, currentEdge, newEdge, face;
-		var edgeVertexWeight, adjacentVertexWeight, connectedFaces;
-
-		var tmp = newVertices.register[ 1 ];
-		for ( i in sourceEdges ) {
-
-		currentEdge = sourceEdges[ i ];
-		newEdge = newVertices.register[ 0 ];
-
-		edgeVertexWeight = 3 / 8;
-		adjacentVertexWeight = 1 / 8;
-
-		connectedFaces = currentEdge.faces.length;
-
-		// check how many linked faces. 2 should be correct.
-		if ( connectedFaces !== 2 ) {
-
-			// if length is not 2, handle condition
-			edgeVertexWeight = 0.5;
-			adjacentVertexWeight = 0;
-
-		}
-
-		oldVertices.index_to_register( currentEdge.a, 0 );
-		oldVertices.index_to_register( currentEdge.b, 1 );
-		newEdge.addVectors( oldVertices.register[ 0 ], oldVertices.register[ 1 ] ).multiplyScalar( edgeVertexWeight );
-
-		tmp.set( 0, 0, 0 );
-
-		for ( j = 0; j < connectedFaces; j++ ) {
-
-			oldFaces.index_to_register( currentEdge.faces[ j ], 0 );
-			face = oldFaces.register[ 0 ];
-
-			for ( k = 0; k < 3; k++ ) {
-
-				oldVertices.index_to_register( face[ ABC[ k ] ], 2 );
-				other = oldVertices.register[ 2 ];
-
-				if ( face[ ABC[ k ] ] !== currentEdge.a && face[ ABC[ k ] ] !== currentEdge.b) {
-
-					break;
-
-				}
-
-		}
-
-		tmp.add( other );
-
-		}
-
-		tmp.multiplyScalar( adjacentVertexWeight );
-		newEdge.add( tmp );
-
-		currentEdge.newEdge = newVertices.length;
-		newVertices.push_element( newEdge );
-
-		}
-
-		var edgeLength = newVertices.length;
-		/******************************************************
-		*
-		*	Step 2.
-		*	Reposition each source vertices.
-		*
-		*******************************************************/
-
-		var beta, sourceVertexWeight, connectingVertexWeight;
-		var connectingEdge, connectingEdges, oldVertex, newSourceVertex;
-
-		for ( i = 0, il = oldVertices.length; i < il; i++ ) {
-
-			oldVertices.index_to_register( i, 0, XYZ );
-			oldVertex = oldVertices.register[ 0 ];
-
-			// find all connecting edges (using lookupTable)
-			connectingEdges = metaVertices[ i ].edges;
-			n = connectingEdges.length;
-
-			if ( n === 3 ) {
-
-				beta = 3 / 16;
-
-			} else if (n > 3) {
-
-				beta = 3 / (8 * n); // Warren's modified formula
-
-			}
-
-			// Loop's original beta formula
-			// beta = 1 / n * ( 5/8 - Math.pow( 3/8 + 1/4 * Math.cos( 2 * Math. PI / n ), 2) );
-
-			sourceVertexWeight = 1 - n * beta;
-			connectingVertexWeight = beta;
-
-			if ( n <= 2 ) {
-
-				// crease and boundary rules
-
-				if ( n === 2 ) {
-
-					sourceVertexWeight = 3 / 4;
-					connectingVertexWeight = 1 / 8;
-
-				}
-
-			}
-
-			newSourceVertex = oldVertex.multiplyScalar( sourceVertexWeight );
-
-			tmp.set( 0, 0, 0 );
-
-			for ( j = 0; j < n; j++ ) {
-
-				connectingEdge = connectingEdges[ j ];
-				other = connectingEdge.a !== i ? connectingEdge.a : connectingEdge.b;
-				oldVertices.index_to_register( other, 1, XYZ );
-				tmp.add( oldVertices.register[ 1 ] );
-
-			}
-
-			tmp.multiplyScalar( connectingVertexWeight );
-			newSourceVertex.add( tmp );
-
-			newVertices.push_element( newSourceVertex,XYZ );
-
-		}
-
-
-		/******************************************************
-		*
-		*	Step 3.
-		*	Generate faces between source vertices and edge vertices.
-		*
-		*******************************************************/
-
-
-		var edge1, edge2, edge3;
-		newFaces = new TypedArrayHelper( ( geometry.index.array.length * 4 ) / 3, 1, THREE.Face3, Float32Array, 3, ABC );
-		newUVs = new TypedArrayHelper( ( geometry.getAttribute( 'uv' ).array.length * 4 ) / 2, 3, THREE.Vector2, Float32Array, 2, XY );
-		var x3 = newUVs.register[ 0 ];
-		var x4 = newUVs.register[ 1 ];
-		var x5 = newUVs.register[ 2 ];
-		var tFace = newFaces.register[ 0 ];
-
-		for ( i = 0, il = oldFaces.length; i < il; i++ ) {
-
-			oldFaces.index_to_register( i, 0 );
-			face = oldFaces.register[ 0 ];
-
-			// find the 3 new edges vertex of each old face
-			// The new source verts are added after the new edge verts now..
-
-			edge1 = getEdge( face.a, face.b, sourceEdges ).newEdge;
-			edge2 = getEdge( face.b, face.c, sourceEdges ).newEdge;
-			edge3 = getEdge( face.c, face.a, sourceEdges ).newEdge;
-
-			// create 4 faces.
-			tFace.set( edge1, edge2, edge3 );
-			newFace( newFaces, tFace );
-			tFace.set( face.a + edgeLength, edge1, edge3 );
-			newFace( newFaces, tFace );
-			tFace.set( face.b + edgeLength, edge2, edge1 );
-			newFace( newFaces, tFace );
-			tFace.set( face.c + edgeLength, edge3, edge2 );
-			newFace( newFaces, tFace );
-
-
-			/*
-				0________C_______2
-				 \      /\      /
-				  \ F2 /  \ F4 /
-				   \  / F1 \  /
-				    \/______\/
-				   A \      / B
-				      \ F3 /
-				       \  /
-				        \/
-				         1
-
-				Draw orders:
-				F1: ABC x3,x4,x5
-				F2: 0AC x0,x3,x5
-				F3: 1BA x1,x4,x3
-				F4: 2CB x2,x5,x4
-
-				0: x0
-				1: x1
-				2: x2
-				A: x3
-				B: x4
-				C: x5
-			*/
-
-			if ( doUvs === true ) {
-
-				oldUvs.index_to_register( ( i * 3 ) + 0, 0 );
-				oldUvs.index_to_register( ( i * 3 ) + 1, 1 );
-				oldUvs.index_to_register( ( i * 3 ) + 2, 2 );
-
-				var x0 = oldUvs.register[ 0 ]; // uv[0];
-				var x1 = oldUvs.register[ 1 ]; // uv[1];
-				var x2 = oldUvs.register[ 2 ]; // uv[2];
-
-				x3.set( midpoint( x0.x, x1.x ), midpoint( x0.y, x1.y ) );
-				x4.set( midpoint( x1.x, x2.x ), midpoint( x1.y, x2.y ) );
-				x5.set( midpoint( x0.x, x2.x ), midpoint( x0.y, x2.y ) );
-
-				newUv( newUVs, x3, x4, x5 );
-				newUv( newUVs, x0, x3, x5 );
-
-				newUv( newUVs, x1, x4, x3 );
-				newUv( newUVs, x2, x5, x4 );
-
-			}
-
-		}
-
-		// Overwrite old arrays
-
-		newFaces.trim_size();
-		newVertices.trim_size();
-		newUVs.trim_size();
-
-		geometry.setIndex( new THREE.BufferAttribute( newFaces.buffer ,3 ) );
-		geometry.addAttribute( 'position', new THREE.BufferAttribute( newVertices.buffer, 3 ) );
-		geometry.addAttribute( 'uv', new THREE.BufferAttribute( newUVs.buffer, 2 ) );
-
-	};
-
-} ) ();

+ 14 - 0
examples/js/modifiers/SubdivisionModifier.js

@@ -23,6 +23,18 @@ THREE.SubdivisionModifier = function ( subdivisions ) {
 // Applies the "modify" pattern
 THREE.SubdivisionModifier.prototype.modify = function ( geometry ) {
 
+	if ( geometry.isBufferGeometry ) {
+
+		geometry = new THREE.Geometry().fromBufferGeometry( geometry );
+
+	} else {
+
+		geometry = geometry.clone();
+
+	}
+
+	geometry.mergeVertices();
+
 	var repeats = this.subdivisions;
 
 	while ( repeats -- > 0 ) {
@@ -34,6 +46,8 @@ THREE.SubdivisionModifier.prototype.modify = function ( geometry ) {
 	geometry.computeFaceNormals();
 	geometry.computeVertexNormals();
 
+	return geometry;
+
 };
 
 ( function () {

+ 0 - 55
examples/js/nodes/AttributeNode.js

@@ -1,55 +0,0 @@
-/**
- * @author sunag / http://www.sunag.com.br/
- */
-
-THREE.AttributeNode = function ( name, type ) {
-
-	THREE.GLNode.call( this, type );
-
-	this.name = name;
-
-};
-
-THREE.AttributeNode.prototype = Object.create( THREE.GLNode.prototype );
-THREE.AttributeNode.prototype.constructor = THREE.AttributeNode;
-THREE.AttributeNode.prototype.nodeType = "Attribute";
-
-THREE.AttributeNode.prototype.getAttributeType = function ( builder ) {
-
-	return typeof this.type === 'number' ? builder.getConstructorFromLength( this.type ) : this.type;
-
-};
-
-THREE.AttributeNode.prototype.getType = function ( builder ) {
-
-	var type = this.getAttributeType( builder );
-
-	return builder.getTypeByFormat( type );
-
-};
-
-THREE.AttributeNode.prototype.generate = function ( builder, output ) {
-
-	var type = this.getAttributeType( builder );
-
-	var attribute = builder.material.getAttribute( this.name, type );
-
-	return builder.format( builder.isShader( 'vertex' ) ? this.name : attribute.varying.name, this.getType( builder ), output );
-
-};
-
-THREE.AttributeNode.prototype.toJSON = function ( meta ) {
-
-	var data = this.getJSONNode( meta );
-
-	if ( ! data ) {
-
-		data = this.createJSONNode( meta );
-
-		data.out = this.type;
-
-	}
-
-	return data;
-
-};

+ 0 - 110
examples/js/nodes/ConstNode.js

@@ -1,110 +0,0 @@
-/**
- * @author sunag / http://www.sunag.com.br/
- */
-
-THREE.ConstNode = function ( src, useDefine ) {
-
-	THREE.TempNode.call( this );
-
-	this.eval( src || THREE.ConstNode.PI, useDefine );
-
-};
-
-THREE.ConstNode.PI = 'PI';
-THREE.ConstNode.PI2 = 'PI2';
-THREE.ConstNode.RECIPROCAL_PI = 'RECIPROCAL_PI';
-THREE.ConstNode.RECIPROCAL_PI2 = 'RECIPROCAL_PI2';
-THREE.ConstNode.LOG2 = 'LOG2';
-THREE.ConstNode.EPSILON = 'EPSILON';
-
-THREE.ConstNode.prototype = Object.create( THREE.TempNode.prototype );
-THREE.ConstNode.prototype.constructor = THREE.ConstNode;
-THREE.ConstNode.prototype.nodeType = "Const";
-
-THREE.ConstNode.prototype.getType = function ( builder ) {
-
-	return builder.getTypeByFormat( this.type );
-
-};
-
-THREE.ConstNode.prototype.eval = function ( src, useDefine ) {
-
-	src = ( src || '' ).trim();
-
-	var name, type, value = "";
-
-	var rDeclaration = /^([a-z_0-9]+)\s([a-z_0-9]+)\s?\=?\s?(.*?)(\;|$)/i;
-	var match = src.match( rDeclaration );
-
-	this.useDefine = useDefine;
-
-	if ( match && match.length > 1 ) {
-
-		type = match[ 1 ];
-		name = match[ 2 ];
-		value = match[ 3 ];
-
-	} else {
-
-		name = src;
-		type = 'fv1';
-
-	}
-
-	this.name = name;
-	this.type = type;
-	this.value = value;
-
-};
-
-THREE.ConstNode.prototype.build = function ( builder, output ) {
-
-	if ( output === 'source' ) {
-
-		if ( this.value ) {
-
-			if ( this.useDefine ) {
-
-				return '#define ' + this.name + ' ' + this.value;
-
-			}
-
-			return 'const ' + this.type + ' ' + this.name + ' = ' + this.value + ';';
-
-		}
-
-	} else {
-
-		builder.include( this );
-
-		return builder.format( this.name, this.getType( builder ), output );
-
-	}
-
-};
-
-THREE.ConstNode.prototype.generate = function ( builder, output ) {
-
-	return builder.format( this.name, this.getType( builder ), output );
-
-};
-
-THREE.ConstNode.prototype.toJSON = function ( meta ) {
-
-	var data = this.getJSONNode( meta );
-
-	if ( ! data ) {
-
-		data = this.createJSONNode( meta );
-
-		data.name = this.name;
-		data.out = this.type;
-
-		if ( this.value ) data.value = this.value;
-		if ( data.useDefine === true ) data.useDefine = true;
-
-	}
-
-	return data;
-
-};

+ 0 - 92
examples/js/nodes/FunctionCallNode.js

@@ -1,92 +0,0 @@
-/**
- * @author sunag / http://www.sunag.com.br/
- */
-
-THREE.FunctionCallNode = function ( func, inputs ) {
-
-	THREE.TempNode.call( this );
-
-	this.setFunction( func, inputs );
-
-};
-
-THREE.FunctionCallNode.prototype = Object.create( THREE.TempNode.prototype );
-THREE.FunctionCallNode.prototype.constructor = THREE.FunctionCallNode;
-THREE.FunctionCallNode.prototype.nodeType = "FunctionCall";
-
-THREE.FunctionCallNode.prototype.setFunction = function ( func, inputs ) {
-
-	this.value = func;
-	this.inputs = inputs || [];
-
-};
-
-THREE.FunctionCallNode.prototype.getFunction = function () {
-
-	return this.value;
-
-};
-
-THREE.FunctionCallNode.prototype.getType = function ( builder ) {
-
-	return this.value.getType( builder );
-
-};
-
-THREE.FunctionCallNode.prototype.generate = function ( builder, output ) {
-
-	var material = builder.material;
-
-	var type = this.getType( builder );
-	var func = this.value;
-
-	var code = func.build( builder, output ) + '(';
-	var params = [];
-
-	for ( var i = 0; i < func.inputs.length; i ++ ) {
-
-		var inpt = func.inputs[ i ];
-		var param = this.inputs[ i ] || this.inputs[ inpt.name ];
-
-		params.push( param.build( builder, builder.getTypeByFormat( inpt.type ) ) );
-
-	}
-
-	code += params.join( ',' ) + ')';
-
-	return builder.format( code, type, output );
-
-};
-
-THREE.FunctionCallNode.prototype.toJSON = function ( meta ) {
-
-	var data = this.getJSONNode( meta );
-
-	if ( ! data ) {
-
-		var func = this.value;
-
-		data = this.createJSONNode( meta );
-
-		data.value = this.value.toJSON( meta ).uuid;
-
-		if ( func.inputs.length ) {
-
-			data.inputs = {};
-
-			for ( var i = 0; i < func.inputs.length; i ++ ) {
-
-				var inpt = func.inputs[ i ];
-				var node = this.inputs[ i ] || this.inputs[ inpt.name ];
-
-				data.inputs[ inpt.name ] = node.toJSON( meta ).uuid;
-
-			}
-
-		}
-
-	}
-
-	return data;
-
-};

+ 0 - 158
examples/js/nodes/GLNode.js

@@ -1,158 +0,0 @@
-/**
- * @author sunag / http://www.sunag.com.br/
- */
-
-THREE.GLNode = function ( type ) {
-
-	this.uuid = THREE.Math.generateUUID();
-
-	this.name = "";
-	this.allows = {};
-
-	this.type = type;
-
-	this.userData = {};
-
-};
-
-THREE.GLNode.prototype.isNode = true;
-
-THREE.GLNode.prototype.parse = function ( builder, context ) {
-
-	context = context || {};
-
-	builder.parsing = true;
-
-	var material = builder.material;
-
-	this.build( builder.addCache( context.cache, context.requires ).addSlot( context.slot ), 'v4' );
-
-	material.clearVertexNode();
-	material.clearFragmentNode();
-
-	builder.removeCache().removeSlot();
-
-	builder.parsing = false;
-
-};
-
-THREE.GLNode.prototype.parseAndBuildCode = function ( builder, output, context ) {
-
-	context = context || {};
-
-	this.parse( builder, context );
-
-	return this.buildCode( builder, output, context );
-
-};
-
-THREE.GLNode.prototype.buildCode = function ( builder, output, context ) {
-
-	context = context || {};
-
-	var material = builder.material;
-
-	var data = { result: this.build( builder.addCache( context.cache, context.requires ).addSlot( context.slot ), output ) };
-
-	if ( builder.isShader( 'vertex' ) ) data.code = material.clearVertexNode();
-	else data.code = material.clearFragmentNode();
-
-	builder.removeCache().removeSlot();
-
-	return data;
-
-};
-
-THREE.GLNode.prototype.build = function ( builder, output, uuid ) {
-
-	output = output || this.getType( builder, output );
-
-	var material = builder.material, data = material.getDataNode( uuid || this.uuid );
-
-	if ( builder.parsing ) this.appendDepsNode( builder, data, output );
-
-	if ( this.allows[ builder.shader ] === false ) {
-
-		throw new Error( 'Shader ' + shader + ' is not compatible with this node.' );
-
-	}
-
-	if ( material.nodes.indexOf( this ) === - 1 ) {
-
-		material.nodes.push( this );
-
-	}
-
-	if ( this.updateFrame !== undefined && material.updaters.indexOf( this ) === - 1 ) {
-
-		material.updaters.push( this );
-
-	}
-
-	return this.generate( builder, output, uuid );
-
-};
-
-THREE.GLNode.prototype.appendDepsNode = function ( builder, data, output ) {
-
-	data.deps = ( data.deps || 0 ) + 1;
-
-	var outputLen = builder.getFormatLength( output );
-
-	if ( outputLen > ( data.outputMax || 0 ) || this.getType( builder, output ) ) {
-
-		data.outputMax = outputLen;
-		data.output = output;
-
-	}
-
-};
-
-THREE.GLNode.prototype.getType = function ( builder, output ) {
-
-	return output === 'sampler2D' || output === 'samplerCube' ? output : this.type;
-
-};
-
-THREE.GLNode.prototype.getJSONNode = function ( meta ) {
-
-	var isRootObject = ( meta === undefined || typeof meta === 'string' );
-
-	if ( ! isRootObject && meta.nodes[ this.uuid ] !== undefined ) {
-
-		return meta.nodes[ this.uuid ];
-
-	}
-
-};
-
-THREE.GLNode.prototype.createJSONNode = function ( meta ) {
-
-	var isRootObject = ( meta === undefined || typeof meta === 'string' );
-
-	var data = {};
-
-	if ( typeof this.nodeType !== "string" ) throw new Error( "Node does not allow serialization." );
-
-	data.uuid = this.uuid;
-	data.type = this.nodeType + "Node";
-
-	if ( this.name !== "" ) data.name = this.name;
-
-	if ( JSON.stringify( this.userData ) !== '{}' ) data.userData = this.userData;
-
-	if ( ! isRootObject ) {
-
-		meta.nodes[ this.uuid ] = data;
-
-	}
-
-	return data;
-
-};
-
-THREE.GLNode.prototype.toJSON = function ( meta ) {
-
-	return this.getJSONNode( meta ) || this.createJSONNode( meta );
-
-};

+ 0 - 65
examples/js/nodes/InputNode.js

@@ -1,65 +0,0 @@
-/**
- * @author sunag / http://www.sunag.com.br/
- */
-
-THREE.InputNode = function ( type, params ) {
-
-	params = params || {};
-	params.shared = params.shared !== undefined ? params.shared : false;
-
-	THREE.TempNode.call( this, type, params );
-
-	this.readonly = false;
-
-};
-
-THREE.InputNode.prototype = Object.create( THREE.TempNode.prototype );
-THREE.InputNode.prototype.constructor = THREE.InputNode;
-
-THREE.InputNode.prototype.isReadonly = function ( builder ) {
-
-	return this.readonly;
-
-};
-
-THREE.InputNode.prototype.generate = function ( builder, output, uuid, type, ns, needsUpdate ) {
-
-	var material = builder.material;
-
-	uuid = builder.getUuid( uuid || this.getUuid() );
-	type = type || this.getType( builder );
-
-	var data = material.getDataNode( uuid ),
-		readonly = this.isReadonly( builder ) && this.generateReadonly !== undefined;
-
-	if ( readonly ) {
-
-		return this.generateReadonly( builder, output, uuid, type, ns, needsUpdate );
-
-	} else {
-
-		if ( builder.isShader( 'vertex' ) ) {
-
-			if ( ! data.vertex ) {
-
-				data.vertex = material.createVertexUniform( type, this, ns, needsUpdate );
-
-			}
-
-			return builder.format( data.vertex.name, type, output );
-
-		} else {
-
-			if ( ! data.fragment ) {
-
-				data.fragment = material.createFragmentUniform( type, this, ns, needsUpdate );
-
-			}
-
-			return builder.format( data.fragment.name, type, output );
-
-		}
-
-	}
-
-};

+ 0 - 259
examples/js/nodes/NodeBuilder.js

@@ -1,259 +0,0 @@
-/**
- * @author sunag / http://www.sunag.com.br/
- */
-
-THREE.NodeBuilder = function ( material, renderer ) {
-
-	this.material = material;
-	this.renderer = renderer;
-
-	this.caches = [];
-	this.slots = [];
-
-	this.keywords = {};
-
-	this.parsing = false;
-	this.optimize = true;
-
-	this.update();
-
-};
-
-THREE.NodeBuilder.type = {
-	float: 'fv1',
-	vec2: 'v2',
-	vec3: 'v3',
-	vec4: 'v4',
-	mat4: 'v4',
-	int: 'iv1'
-};
-
-THREE.NodeBuilder.constructors = [
-	'float',
-	'vec2',
-	'vec3',
-	'vec4'
-];
-
-THREE.NodeBuilder.elements = [
-	'x',
-	'y',
-	'z',
-	'w'
-];
-
-THREE.NodeBuilder.prototype = {
-
-	constructor: THREE.NodeBuilder,
-
-	addCache: function ( name, requires ) {
-
-		this.caches.push( {
-			name: name || '',
-			requires: requires || {}
-		} );
-
-		return this.update();
-
-	},
-
-	removeCache: function () {
-
-		this.caches.pop();
-
-		return this.update();
-
-	},
-
-	addSlot: function ( name ) {
-
-		this.slots.push( {
-			name: name || ''
-		} );
-
-		return this.update();
-
-	},
-
-	removeSlot: function () {
-
-		this.slots.pop();
-
-		return this.update();
-
-	},
-
-	isCache: function ( name ) {
-
-		var i = this.caches.length;
-
-		while ( i -- ) {
-
-			if ( this.caches[ i ].name == name ) return true;
-
-		}
-
-		return false;
-
-	},
-
-	isSlot: function ( name ) {
-
-		var i = this.slots.length;
-
-		while ( i -- ) {
-
-			if ( this.slots[ i ].name == name ) return true;
-
-		}
-
-		return false;
-
-	},
-
-	update: function () {
-
-		var cache = this.caches[ this.caches.length - 1 ];
-		var slot = this.slots[ this.slots.length - 1 ];
-
-		this.slot = slot ? slot.name : '';
-		this.cache = cache ? cache.name : '';
-		this.requires = cache ? cache.requires : {};
-
-		return this;
-
-	},
-
-	require: function ( name, node ) {
-
-		this.requires[ name ] = node;
-
-		return this;
-
-	},
-
-	include: function ( node, parent, source ) {
-
-		this.material.include( this, node, parent, source );
-
-		return this;
-
-	},
-
-	colorToVector: function ( color ) {
-
-		return color.replace( 'r', 'x' ).replace( 'g', 'y' ).replace( 'b', 'z' ).replace( 'a', 'w' );
-
-	},
-
-	getConstructorFromLength: function ( len ) {
-
-		return THREE.NodeBuilder.constructors[ len - 1 ];
-
-	},
-
-	getFormatName: function ( format ) {
-
-		return format.replace( /c/g, 'v3' ).replace( /fv1/g, 'v1' ).replace( /iv1/g, 'i' );
-
-	},
-
-	isFormatMatrix: function ( format ) {
-
-		return /^m/.test( format );
-
-	},
-
-	getFormatLength: function ( format ) {
-
-		return parseInt( this.getFormatName( format ).substr( 1 ) );
-
-	},
-
-	getFormatFromLength: function ( len ) {
-
-		if ( len == 1 ) return 'fv1';
-
-		return 'v' + len;
-
-	},
-
-	format: function ( code, from, to ) {
-
-		var format = this.getFormatName( to + '=' + from );
-
-		switch ( format ) {
-
-			case 'v1=v2': return code + '.x';
-			case 'v1=v3': return code + '.x';
-			case 'v1=v4': return code + '.x';
-			case 'v1=i': return 'float(' + code + ')';
-
-			case 'v2=v1': return 'vec2(' + code + ')';
-			case 'v2=v3': return code + '.xy';
-			case 'v2=v4': return code + '.xy';
-			case 'v2=i': return 'vec2(float(' + code + '))';
-
-			case 'v3=v1': return 'vec3(' + code + ')';
-			case 'v3=v2': return 'vec3(' + code + ',0.0)';
-			case 'v3=v4': return code + '.xyz';
-			case 'v3=i': return 'vec2(float(' + code + '))';
-
-			case 'v4=v1': return 'vec4(' + code + ')';
-			case 'v4=v2': return 'vec4(' + code + ',0.0,1.0)';
-			case 'v4=v3': return 'vec4(' + code + ',1.0)';
-			case 'v4=i': return 'vec4(float(' + code + '))';
-
-			case 'i=v1': return 'int(' + code + ')';
-			case 'i=v2': return 'int(' + code + '.x)';
-			case 'i=v3': return 'int(' + code + '.x)';
-			case 'i=v4': return 'int(' + code + '.x)';
-
-		}
-
-		return code;
-
-	},
-
-	getTypeByFormat: function ( format ) {
-
-		return THREE.NodeBuilder.type[ format ] || format;
-
-	},
-
-	getUuid: function ( uuid, useCache ) {
-
-		useCache = useCache !== undefined ? useCache : true;
-
-		if ( useCache && this.cache ) uuid = this.cache + '-' + uuid;
-
-		return uuid;
-
-	},
-
-	getElementByIndex: function ( index ) {
-
-		return THREE.NodeBuilder.elements[ index ];
-
-	},
-
-	getIndexByElement: function ( elm ) {
-
-		return THREE.NodeBuilder.elements.indexOf( elm );
-
-	},
-
-	isShader: function ( shader ) {
-
-		return this.shader == shader;
-
-	},
-
-	setShader: function ( shader ) {
-
-		this.shader = shader;
-
-		return this;
-
-	}
-};

+ 0 - 34
examples/js/nodes/NodeFrame.js

@@ -1,34 +0,0 @@
-/**
- * @author sunag / http://www.sunag.com.br/
- */
-
-THREE.NodeFrame = function ( time ) {
-
-	this.time = time !== undefined ? time : 0;
-
-	this.frameId = 0;
-
-};
-
-THREE.NodeFrame.prototype.update = function ( delta ) {
-
-	++this.frameId;
-
-	this.time += delta;
-	this.delta = delta;
-
-	return this;
-
-};
-
-THREE.NodeFrame.prototype.updateNode = function ( node ) {
-
-	if ( node.frameId === this.frameId ) return this;
-
-	node.updateFrame( this );
-
-	node.frameId = this.frameId;
-
-	return this;
-
-};

+ 0 - 216
examples/js/nodes/NodeLib.js

@@ -1,216 +0,0 @@
-/**
- * @author sunag / http://www.sunag.com.br/
- */
-
-THREE.NodeLib = {
-
-	nodes: {},
-	keywords: {},
-
-	add: function ( node ) {
-
-		this.nodes[ node.name ] = node;
-
-	},
-
-	addKeyword: function ( name, callback, cache ) {
-
-		cache = cache !== undefined ? cache : true;
-
-		this.keywords[ name ] = { callback: callback, cache: cache };
-
-	},
-
-	remove: function ( node ) {
-
-		delete this.nodes[ node.name ];
-
-	},
-
-	removeKeyword: function ( name ) {
-
-		delete this.keywords[ name ];
-
-	},
-
-	get: function ( name ) {
-
-		return this.nodes[ name ];
-
-	},
-
-	getKeyword: function ( name, material ) {
-
-		return this.keywords[ name ].callback.call( this, material );
-
-	},
-
-	getKeywordData: function ( name ) {
-
-		return this.keywords[ name ];
-
-	},
-
-	contains: function ( name ) {
-
-		return this.nodes[ name ] != undefined;
-
-	},
-
-	containsKeyword: function ( name ) {
-
-		return this.keywords[ name ] != undefined;
-
-	}
-
-};
-
-//
-//	Keywords
-//
-
-THREE.NodeLib.addKeyword( 'uv', function () {
-
-	return new THREE.UVNode();
-
-} );
-
-THREE.NodeLib.addKeyword( 'uv2', function () {
-
-	return new THREE.UVNode( 1 );
-
-} );
-
-THREE.NodeLib.addKeyword( 'position', function () {
-
-	return new THREE.PositionNode();
-
-} );
-
-THREE.NodeLib.addKeyword( 'worldPosition', function () {
-
-	return new THREE.PositionNode( THREE.PositionNode.WORLD );
-
-} );
-
-THREE.NodeLib.addKeyword( 'normal', function () {
-
-	return new THREE.NormalNode();
-
-} );
-
-THREE.NodeLib.addKeyword( 'worldNormal', function () {
-
-	return new THREE.NormalNode( THREE.NormalNode.WORLD );
-
-} );
-
-THREE.NodeLib.addKeyword( 'viewPosition', function () {
-
-	return new THREE.PositionNode( THREE.NormalNode.VIEW );
-
-} );
-
-THREE.NodeLib.addKeyword( 'viewNormal', function () {
-
-	return new THREE.NormalNode( THREE.NormalNode.VIEW );
-
-} );
-
-THREE.NodeLib.addKeyword( 'time', function () {
-
-	return new THREE.TimerNode();
-
-} );
-
-//
-//	Luma
-//
-
-THREE.NodeLib.add( new THREE.ConstNode( "vec3 LUMA vec3(0.2125, 0.7154, 0.0721)" ) );
-
-//
-//	NormalMap
-//
-
-THREE.NodeLib.add( new THREE.FunctionNode( [
-// Per-Pixel Tangent Space Normal Mapping
-// http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html
-	"vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm, vec3 map, vec2 mUv, vec2 scale ) {",
-	"	vec3 q0 = dFdx( eye_pos );",
-	"	vec3 q1 = dFdy( eye_pos );",
-	"	vec2 st0 = dFdx( mUv.st );",
-	"	vec2 st1 = dFdy( mUv.st );",
-	"	float factor = sign( st1.t * st0.s - st0.t * st1.s );",
-	"	factor *= float( gl_FrontFacing ) * 2.0 - 1.0;",
-	"	vec3 S = normalize( ( q0 * st1.t - q1 * st0.t ) * factor );",
-	"	vec3 T = normalize( ( -q0 * st1.s + q1 * st0.s ) * factor );",
-	"	vec3 N = normalize( surf_norm );",
-	"	vec3 mapN = map * 2.0 - 1.0;",
-	"	mapN.xy = scale * mapN.xy;",
-	"	mat3 tsn = mat3( S, T, N );",
-	"	return normalize( tsn * mapN );",
-	"}"
-].join( "\n" ), null, { derivatives: true } ) );
-
-//
-//	Noise
-//
-
-THREE.NodeLib.add( new THREE.FunctionNode( [
-	"float snoise(vec2 co) {",
-	"	return fract( sin( dot(co.xy, vec2(12.9898,78.233) ) ) * 43758.5453 );",
-	"}"
-].join( "\n" ) ) );
-
-//
-//	Hue
-//
-
-THREE.NodeLib.add( new THREE.FunctionNode( [
-	"vec3 hue_rgb(vec3 rgb, float adjustment) {",
-	"	const mat3 RGBtoYIQ = mat3(0.299, 0.587, 0.114, 0.595716, -0.274453, -0.321263, 0.211456, -0.522591, 0.311135);",
-	"	const mat3 YIQtoRGB = mat3(1.0, 0.9563, 0.6210, 1.0, -0.2721, -0.6474, 1.0, -1.107, 1.7046);",
-	"	vec3 yiq = RGBtoYIQ * rgb;",
-	"	float hue = atan(yiq.z, yiq.y) + adjustment;",
-	"	float chroma = sqrt(yiq.z * yiq.z + yiq.y * yiq.y);",
-	"	return YIQtoRGB * vec3(yiq.x, chroma * cos(hue), chroma * sin(hue));",
-	"}"
-].join( "\n" ) ) );
-
-//
-//	Saturation
-//
-
-THREE.NodeLib.add( new THREE.FunctionNode( [
-// Algorithm from Chapter 16 of OpenGL Shading Language
-	"vec3 saturation_rgb(vec3 rgb, float adjustment) {",
-	"	vec3 intensity = vec3(dot(rgb, LUMA));",
-	"	return mix(intensity, rgb, adjustment);",
-	"}"
-].join( "\n" ) ) );
-
-//
-//	Luminance
-//
-
-THREE.NodeLib.add( new THREE.FunctionNode( [
-// Algorithm from Chapter 10 of Graphics Shaders
-	"float luminance_rgb(vec3 rgb) {",
-	"	return dot(rgb, LUMA);",
-	"}"
-].join( "\n" ) ) );
-
-//
-//	Vibrance
-//
-
-THREE.NodeLib.add( new THREE.FunctionNode( [
-// Shader by Evan Wallace adapted by @lo-th
-	"vec3 vibrance_rgb(vec3 rgb, float adjustment) {",
-	"	float average = (rgb.r + rgb.g + rgb.b) / 3.0;",
-	"	float mx = max(rgb.r, max(rgb.g, rgb.b));",
-	"	float amt = (mx - average) * (-3.0 * adjustment);",
-	"	return mix(rgb.rgb, vec3(mx), amt);",
-	"}"
-].join( "\n" ) ) );

+ 0 - 661
examples/js/nodes/NodeMaterial.js

@@ -1,661 +0,0 @@
-/**
- * @author sunag / http://www.sunag.com.br/
- */
-
-THREE.NodeMaterial = function ( vertex, fragment ) {
-
-	THREE.ShaderMaterial.call( this );
-
-	this.defines.UUID = this.uuid;
-
-	this.vertex = vertex || new THREE.RawNode( new THREE.PositionNode( THREE.PositionNode.PROJECTION ) );
-	this.fragment = fragment || new THREE.RawNode( new THREE.ColorNode( 0xFF0000 ) );
-
-	this.updaters = [];
-
-};
-
-THREE.NodeMaterial.types = {
-	t: 'sampler2D',
-	tc: 'samplerCube',
-	bv1: 'bool',
-	iv1: 'int',
-	fv1: 'float',
-	c: 'vec3',
-	v2: 'vec2',
-	v3: 'vec3',
-	v4: 'vec4',
-	m3: 'mat3',
-	m4: 'mat4'
-};
-
-THREE.NodeMaterial.addShortcuts = function ( proto, prop, list ) {
-
-	function applyShortcut( prop, name ) {
-
-		return {
-			get: function () {
-
-				return this[ prop ][ name ];
-
-			},
-			set: function ( val ) {
-
-				this[ prop ][ name ] = val;
-
-			}
-		};
-
-	}
-
-	return ( function () {
-
-		var shortcuts = {};
-
-		for ( var i = 0; i < list.length; ++ i ) {
-
-			var name = list[ i ];
-
-			shortcuts[ name ] = applyShortcut( prop, name );
-
-		}
-
-		Object.defineProperties( proto, shortcuts );
-
-	} )();
-
-};
-
-THREE.NodeMaterial.prototype = Object.create( THREE.ShaderMaterial.prototype );
-THREE.NodeMaterial.prototype.constructor = THREE.NodeMaterial;
-THREE.NodeMaterial.prototype.type = "NodeMaterial";
-
-THREE.NodeMaterial.prototype.updateFrame = function ( frame ) {
-
-	for ( var i = 0; i < this.updaters.length; ++ i ) {
-
-		frame.updateNode( this.updaters[ i ] );
-
-	}
-
-};
-
-THREE.NodeMaterial.prototype.onBeforeCompile = function ( shader, renderer ) {
-
-	if ( this.needsUpdate ) {
-
-		this.build( { dispose: false, renderer: renderer } );
-
-		shader.uniforms = this.uniforms;
-		shader.vertexShader = this.vertexShader;
-		shader.fragmentShader = this.fragmentShader;
-
-	}
-
-};
-
-THREE.NodeMaterial.prototype.build = function ( params ) {
-
-	params = params || {};
-	params.dispose = params.dispose !== undefined ? params.dispose : true;
-
-	var vertex, fragment;
-
-	this.nodes = [];
-
-	this.defines = { UUID: this.uuid };
-	this.uniforms = {};
-	this.attributes = {};
-
-	this.extensions = {};
-
-	this.nodeData = {};
-
-	this.vertexUniform = [];
-	this.fragmentUniform = [];
-
-	this.vars = [];
-	this.vertexTemps = [];
-	this.fragmentTemps = [];
-
-	this.uniformList = [];
-
-	this.consts = [];
-	this.functions = [];
-
-	this.updaters = [];
-
-	this.requires = {
-		uv: [],
-		color: [],
-		lights: this.lights,
-		fog: this.fog
-	};
-
-	this.vertexPars = '';
-	this.fragmentPars = '';
-
-	this.vertexCode = '';
-	this.fragmentCode = '';
-
-	this.vertexNode = '';
-	this.fragmentNode = '';
-
-	this.prefixCode = [
-		"#ifdef GL_EXT_shader_texture_lod",
-
-		"	#define texCube(a, b) textureCube(a, b)",
-		"	#define texCubeBias(a, b, c) textureCubeLodEXT(a, b, c)",
-
-		"	#define tex2D(a, b) texture2D(a, b)",
-		"	#define tex2DBias(a, b, c) texture2DLodEXT(a, b, c)",
-
-		"#else",
-
-		"	#define texCube(a, b) textureCube(a, b)",
-		"	#define texCubeBias(a, b, c) textureCube(a, b, c)",
-
-		"	#define tex2D(a, b) texture2D(a, b)",
-		"	#define tex2DBias(a, b, c) texture2D(a, b, c)",
-
-		"#endif",
-
-		"#include <packing>"
-
-	].join( "\n" );
-
-	var builder = new THREE.NodeBuilder( this, params.renderer );
-
-	vertex = this.vertex.build( builder.setShader( 'vertex' ), 'v4' );
-	fragment = this.fragment.build( builder.setShader( 'fragment' ), 'v4' );
-
-	if ( this.requires.uv[ 0 ] ) {
-
-		this.addVertexPars( 'varying vec2 vUv;' );
-		this.addFragmentPars( 'varying vec2 vUv;' );
-
-		this.addVertexCode( 'vUv = uv;' );
-
-	}
-
-	if ( this.requires.uv[ 1 ] ) {
-
-		this.addVertexPars( 'varying vec2 vUv2; attribute vec2 uv2;' );
-		this.addFragmentPars( 'varying vec2 vUv2;' );
-
-		this.addVertexCode( 'vUv2 = uv2;' );
-
-	}
-
-	if ( this.requires.color[ 0 ] ) {
-
-		this.addVertexPars( 'varying vec4 vColor; attribute vec4 color;' );
-		this.addFragmentPars( 'varying vec4 vColor;' );
-
-		this.addVertexCode( 'vColor = color;' );
-
-	}
-
-	if ( this.requires.color[ 1 ] ) {
-
-		this.addVertexPars( 'varying vec4 vColor2; attribute vec4 color2;' );
-		this.addFragmentPars( 'varying vec4 vColor2;' );
-
-		this.addVertexCode( 'vColor2 = color2;' );
-
-	}
-
-	if ( this.requires.position ) {
-
-		this.addVertexPars( 'varying vec3 vPosition;' );
-		this.addFragmentPars( 'varying vec3 vPosition;' );
-
-		this.addVertexCode( 'vPosition = transformed;' );
-
-	}
-
-	if ( this.requires.worldPosition ) {
-
-		this.addVertexPars( 'varying vec3 vWPosition;' );
-		this.addFragmentPars( 'varying vec3 vWPosition;' );
-
-		this.addVertexCode( 'vWPosition = ( modelMatrix * vec4( transformed, 1.0 ) ).xyz;' );
-
-	}
-
-	if ( this.requires.normal ) {
-
-		this.addVertexPars( 'varying vec3 vObjectNormal;' );
-		this.addFragmentPars( 'varying vec3 vObjectNormal;' );
-
-		this.addVertexCode( 'vObjectNormal = normal;' );
-
-	}
-
-	if ( this.requires.worldNormal ) {
-
-		this.addVertexPars( 'varying vec3 vWNormal;' );
-		this.addFragmentPars( 'varying vec3 vWNormal;' );
-
-		this.addVertexCode( 'vWNormal = ( modelMatrix * vec4( objectNormal, 0.0 ) ).xyz;' );
-
-	}
-
-	this.fog = this.requires.fog;
-	this.lights = this.requires.lights;
-
-	this.transparent = this.requires.transparent || this.blending > THREE.NormalBlending;
-
-	this.vertexShader = [
-		this.prefixCode,
-		this.vertexPars,
-		this.getCodePars( this.vertexUniform, 'uniform' ),
-		this.getIncludes( this.consts[ 'vertex' ] ),
-		this.getIncludes( this.functions[ 'vertex' ] ),
-		'void main(){',
-		this.getCodePars( this.vertexTemps ),
-		vertex,
-		this.vertexCode,
-		'}'
-	].join( "\n" );
-
-	this.fragmentShader = [
-		this.prefixCode,
-		this.fragmentPars,
-		this.getCodePars( this.fragmentUniform, 'uniform' ),
-		this.getIncludes( this.consts[ 'fragment' ] ),
-		this.getIncludes( this.functions[ 'fragment' ] ),
-		'void main(){',
-		this.getCodePars( this.fragmentTemps ),
-		this.fragmentCode,
-		fragment,
-		'}'
-	].join( "\n" );
-
-	if ( params.dispose ) {
-
-		// force update
-
-		this.dispose();
-
-	}
-
-	return this;
-
-};
-
-THREE.NodeMaterial.prototype.define = function ( name, value ) {
-
-	this.defines[ name ] = value == undefined ? 1 : value;
-
-};
-
-THREE.NodeMaterial.prototype.isDefined = function ( name ) {
-
-	return this.defines[ name ] != undefined;
-
-};
-
-THREE.NodeMaterial.prototype.mergeUniform = function ( uniforms ) {
-
-	for ( var name in uniforms ) {
-
-		this.uniforms[ name ] = uniforms[ name ];
-
-	}
-
-};
-
-THREE.NodeMaterial.prototype.createUniform = function ( type, node, ns, needsUpdate ) {
-
-	var index = this.uniformList.length;
-
-	var uniform = new THREE.NodeUniform( {
-		type: type,
-		name: ns ? ns : 'nVu' + index + '_' + THREE.Math.generateUUID().substr(0, 8),
-		node: node,
-		needsUpdate: needsUpdate
-	} );
-
-	this.uniformList.push( uniform );
-
-	return uniform;
-
-};
-
-THREE.NodeMaterial.prototype.getVertexTemp = function ( uuid, type, ns ) {
-
-	var data = this.vertexTemps[ uuid ];
-
-	if ( ! data ) {
-
-		var index = this.vertexTemps.length,
-			name = ns ? ns : 'nVt' + index;
-
-		data = { name: name, type: type };
-
-		this.vertexTemps.push( data );
-		this.vertexTemps[ uuid ] = data;
-
-	}
-
-	return data;
-
-};
-
-THREE.NodeMaterial.prototype.getFragmentTemp = function ( uuid, type, ns ) {
-
-	var data = this.fragmentTemps[ uuid ];
-
-	if ( ! data ) {
-
-		var index = this.fragmentTemps.length,
-			name = ns ? ns : 'nVt' + index;
-
-		data = { name: name, type: type };
-
-		this.fragmentTemps.push( data );
-		this.fragmentTemps[ uuid ] = data;
-
-	}
-
-	return data;
-
-};
-
-THREE.NodeMaterial.prototype.getVar = function ( uuid, type, ns ) {
-
-	var data = this.vars[ uuid ];
-
-	if ( ! data ) {
-
-		var index = this.vars.length,
-			name = ns ? ns : 'nVv' + index;
-
-		data = { name: name, type: type };
-
-		this.vars.push( data );
-		this.vars[ uuid ] = data;
-
-		this.addVertexPars( 'varying ' + type + ' ' + name + ';' );
-		this.addFragmentPars( 'varying ' + type + ' ' + name + ';' );
-
-	}
-
-	return data;
-
-};
-
-THREE.NodeMaterial.prototype.getAttribute = function ( name, type ) {
-
-	if ( ! this.attributes[ name ] ) {
-
-		var varying = this.getVar( name, type );
-
-		this.addVertexPars( 'attribute ' + type + ' ' + name + ';' );
-		this.addVertexCode( varying.name + ' = ' + name + ';' );
-
-		this.attributes[ name ] = { varying: varying, name: name, type: type };
-
-	}
-
-	return this.attributes[ name ];
-
-};
-
-THREE.NodeMaterial.prototype.getIncludes = function () {
-
-	function sortByPosition( a, b ) {
-
-		return a.deps.length - b.deps.length;
-
-	}
-
-	return function ( incs ) {
-
-		if ( ! incs ) return '';
-
-		var code = '', incs = incs.sort( sortByPosition );
-
-		for ( var i = 0; i < incs.length; i ++ ) {
-
-			if ( incs[ i ].src ) code += incs[ i ].src + '\n';
-
-		}
-
-		return code;
-
-	};
-
-}();
-
-THREE.NodeMaterial.prototype.addVertexPars = function ( code ) {
-
-	this.vertexPars += code + '\n';
-
-};
-
-THREE.NodeMaterial.prototype.addFragmentPars = function ( code ) {
-
-	this.fragmentPars += code + '\n';
-
-};
-
-THREE.NodeMaterial.prototype.addVertexCode = function ( code ) {
-
-	this.vertexCode += code + '\n';
-
-};
-
-THREE.NodeMaterial.prototype.addFragmentCode = function ( code ) {
-
-	this.fragmentCode += code + '\n';
-
-};
-
-THREE.NodeMaterial.prototype.addVertexNode = function ( code ) {
-
-	this.vertexNode += code + '\n';
-
-};
-
-THREE.NodeMaterial.prototype.clearVertexNode = function () {
-
-	var code = this.vertexNode;
-
-	this.vertexNode = '';
-
-	return code;
-
-};
-
-THREE.NodeMaterial.prototype.addFragmentNode = function ( code ) {
-
-	this.fragmentNode += code + '\n';
-
-};
-
-THREE.NodeMaterial.prototype.clearFragmentNode = function () {
-
-	var code = this.fragmentNode;
-
-	this.fragmentNode = '';
-
-	return code;
-
-};
-
-THREE.NodeMaterial.prototype.getCodePars = function ( pars, prefix ) {
-
-	prefix = prefix || '';
-
-	var code = '';
-
-	for ( var i = 0, l = pars.length; i < l; ++ i ) {
-
-		var parsType = pars[ i ].type;
-		var parsName = pars[ i ].name;
-		var parsValue = pars[ i ].value;
-
-		if ( parsType == 't' && parsValue instanceof THREE.CubeTexture ) parsType = 'tc';
-
-		var type = THREE.NodeMaterial.types[ parsType ];
-
-		if ( type == undefined ) throw new Error( "Node pars " + parsType + " not found." );
-
-		code += prefix + ' ' + type + ' ' + parsName + ';\n';
-
-	}
-
-	return code;
-
-};
-
-THREE.NodeMaterial.prototype.createVertexUniform = function ( type, node, ns, needsUpdate ) {
-
-	var uniform = this.createUniform( type, node, ns, needsUpdate );
-
-	this.vertexUniform.push( uniform );
-	this.vertexUniform[ uniform.name ] = uniform;
-
-	this.uniforms[ uniform.name ] = uniform;
-
-	return uniform;
-
-};
-
-THREE.NodeMaterial.prototype.createFragmentUniform = function ( type, node, ns, needsUpdate ) {
-
-	var uniform = this.createUniform( type, node, ns, needsUpdate );
-
-	this.fragmentUniform.push( uniform );
-	this.fragmentUniform[ uniform.name ] = uniform;
-
-	this.uniforms[ uniform.name ] = uniform;
-
-	return uniform;
-
-};
-
-THREE.NodeMaterial.prototype.getDataNode = function ( uuid ) {
-
-	return this.nodeData[ uuid ] = this.nodeData[ uuid ] || {};
-
-};
-
-THREE.NodeMaterial.prototype.include = function ( builder, node, parent, source ) {
-
-	var includes;
-
-	node = typeof node === 'string' ? THREE.NodeLib.get( node ) : node;
-
-	if ( node instanceof THREE.FunctionNode ) {
-
-		includes = this.functions[ builder.shader ] = this.functions[ builder.shader ] || [];
-
-	} else if ( node instanceof THREE.ConstNode ) {
-
-		includes = this.consts[ builder.shader ] = this.consts[ builder.shader ] || [];
-
-	}
-
-	var included = includes[ node.name ];
-
-	if ( ! included ) {
-
-		included = includes[ node.name ] = {
-			node: node,
-			deps: []
-		};
-
-		includes.push( included );
-
-		included.src = node.build( builder, 'source' );
-
-	}
-
-	if ( node instanceof THREE.FunctionNode && parent && includes[ parent.name ] && includes[ parent.name ].deps.indexOf( node ) == - 1 ) {
-
-		includes[ parent.name ].deps.push( node );
-
-		if ( node.includes && node.includes.length ) {
-
-			var i = 0;
-
-			do {
-
-				this.include( builder, node.includes[ i ++ ], parent );
-
-			} while ( i < node.includes.length );
-
-		}
-
-	}
-
-	if ( source ) {
-
-		included.src = source;
-
-	}
-
-};
-
-THREE.NodeMaterial.prototype.toJSON = function ( meta ) {
-
-	var isRootObject = ( meta === undefined || typeof meta === 'string' );
-
-	if ( isRootObject ) {
-
-		meta = {
-			nodes: {}
-		};
-
-	}
-
-	if ( meta && ! meta.materials ) meta.materials = {};
-
-	if ( ! meta.materials[ this.uuid ] ) {
-
-		var data = {};
-
-		data.uuid = this.uuid;
-		data.type = this.type;
-
-		meta.materials[ data.uuid ] = data;
-
-		if ( this.name !== "" ) data.name = this.name;
-
-		if ( this.blending !== THREE.NormalBlending ) data.blending = this.blending;
-		if ( this.flatShading === true ) data.flatShading = this.flatShading;
-		if ( this.side !== THREE.FrontSide ) data.side = this.side;
-
-		if ( this.transparent === true ) data.transparent = this.transparent;
-
-		data.depthFunc = this.depthFunc;
-		data.depthTest = this.depthTest;
-		data.depthWrite = this.depthWrite;
-
-		if ( this.wireframe === true ) data.wireframe = this.wireframe;
-		if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth;
-		if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap;
-		if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin;
-
-		if ( this.morphTargets === true ) data.morphTargets = true;
-		if ( this.skinning === true ) data.skinning = true;
-
-		data.fog = this.fog;
-		data.lights = this.lights;
-
-		if ( this.visible === false ) data.visible = false;
-		if ( JSON.stringify( this.userData ) !== '{}' ) data.userData = this.userData;
-
-		data.vertex = this.vertex.toJSON( meta ).uuid;
-		data.fragment = this.fragment.toJSON( meta ).uuid;
-
-	}
-
-	meta.material = this.uuid;
-
-	return meta;
-
-};

+ 106 - 0
examples/js/nodes/Nodes.js

@@ -0,0 +1,106 @@
+// TODO: all nodes
+
+// core
+
+export { GLNode } from './core/GLNode.js';
+export { TempNode } from './core/TempNode.js';
+export { InputNode } from './core/InputNode.js';
+export { ConstNode } from './core/ConstNode.js';
+export { VarNode } from './core/VarNode.js';
+export { StructNode } from './core/StructNode.js';
+export { AttributeNode } from './core/AttributeNode.js';
+export { FunctionNode } from './core/FunctionNode.js';
+export { FunctionCallNode } from './core/FunctionCallNode.js';
+export { NodeLib } from './core/NodeLib.js';
+export { NodeUtils } from './core/NodeUtils.js';
+export { NodeFrame } from './core/NodeFrame.js';
+export { NodeUniform } from './core/NodeUniform.js';
+export { NodeBuilder } from './core/NodeBuilder.js';
+
+// inputs
+
+export { IntNode } from './inputs/IntNode.js';
+export { FloatNode } from './inputs/FloatNode.js';
+export { Vector2Node } from './inputs/Vector2Node.js';
+export { Vector3Node } from './inputs/Vector3Node.js';
+export { Vector4Node } from './inputs/Vector4Node.js';
+export { ColorNode } from './inputs/ColorNode.js';
+export { Matrix3Node } from './inputs/Matrix3Node.js';
+export { Matrix4Node } from './inputs/Matrix4Node.js';
+export { TextureNode } from './inputs/TextureNode.js';
+export { CubeTextureNode } from './inputs/CubeTextureNode.js';
+export { ScreenNode } from './inputs/ScreenNode.js';
+export { ReflectorNode } from './inputs/ReflectorNode.js';
+export { PropertyNode } from './inputs/PropertyNode.js';
+
+// accessors
+
+export { UVNode } from './accessors/UVNode.js';
+export { ColorsNode } from './accessors/ColorsNode.js';
+export { PositionNode } from './accessors/PositionNode.js';
+export { NormalNode } from './accessors/NormalNode.js';
+export { CameraNode } from './accessors/CameraNode.js';
+export { LightNode } from './accessors/LightNode.js';
+export { ReflectNode } from './accessors/ReflectNode.js';
+export { ScreenUVNode } from './accessors/ScreenUVNode.js';
+export { ResolutionNode } from './accessors/ResolutionNode.js';
+
+// math
+
+export { Math1Node } from './math/Math1Node.js';
+export { Math2Node } from './math/Math2Node.js';
+export { Math3Node } from './math/Math3Node.js';
+export { OperatorNode } from './math/OperatorNode.js';
+
+// procedural
+
+export { NoiseNode } from './procedural/NoiseNode.js';
+
+// bsdfs
+
+export { BlinnShininessExponentNode } from './bsdfs/BlinnShininessExponentNode.js';
+export { BlinnExponentToRoughnessNode } from './bsdfs/BlinnExponentToRoughnessNode.js';
+export { RoughnessToBlinnExponentNode } from './bsdfs/RoughnessToBlinnExponentNode.js';
+
+// misc
+
+export { TextureCubeUVNode } from './misc/TextureCubeUVNode.js';
+export { TextureCubeNode } from './misc/TextureCubeNode.js';
+export { NormalMapNode } from './misc/NormalMapNode.js';
+export { BumpMapNode } from './misc/BumpMapNode.js';
+
+// utils
+
+export { BypassNode } from './utils/BypassNode.js';
+export { JoinNode } from './utils/JoinNode.js';
+export { SwitchNode } from './utils/SwitchNode.js';
+export { TimerNode } from './utils/TimerNode.js';
+export { VelocityNode } from './utils/VelocityNode.js';
+export { UVTransformNode } from './utils/UVTransformNode.js';
+export { MaxMIPLevelNode } from './utils/MaxMIPLevelNode.js';
+
+// effects
+
+export { BlurNode } from './effects/BlurNode.js';
+export { ColorAdjustmentNode } from './effects/ColorAdjustmentNode.js';
+export { LuminanceNode } from './effects/LuminanceNode.js';
+
+// material nodes
+
+export { RawNode } from './materials/nodes/RawNode.js';
+export { SpriteNode } from './materials/nodes/SpriteNode.js';
+export { PhongNode } from './materials/nodes/PhongNode.js';
+export { StandardNode } from './materials/nodes/StandardNode.js';
+export { MeshStandardNode } from './materials/nodes/MeshStandardNode.js';
+
+// materials
+
+export { NodeMaterial } from './materials/NodeMaterial.js';
+export { SpriteNodeMaterial } from './materials/SpriteNodeMaterial.js';
+export { PhongNodeMaterial } from './materials/PhongNodeMaterial.js';
+export { StandardNodeMaterial } from './materials/StandardNodeMaterial.js';
+export { MeshStandardNodeMaterial } from './materials/MeshStandardNodeMaterial.js';
+
+// postprocessing
+
+//export { NodePass } from './postprocessing/NodePass.js';

+ 0 - 53
examples/js/nodes/RawNode.js

@@ -1,53 +0,0 @@
-/**
- * @author sunag / http://www.sunag.com.br/
- */
-
-THREE.RawNode = function ( value ) {
-
-	THREE.GLNode.call( this, 'v4' );
-
-	this.value = value;
-
-};
-
-THREE.RawNode.prototype = Object.create( THREE.GLNode.prototype );
-THREE.RawNode.prototype.constructor = THREE.RawNode;
-THREE.RawNode.prototype.nodeType = "Raw";
-
-THREE.RawNode.prototype.generate = function ( builder ) {
-
-	var material = builder.material;
-
-	var data = this.value.parseAndBuildCode( builder, this.type );
-
-	var code = data.code + '\n';
-
-	if ( builder.shader == 'vertex' ) {
-
-		code += 'gl_Position = ' + data.result + ';';
-
-	} else {
-
-		code += 'gl_FragColor = ' + data.result + ';';
-
-	}
-
-	return code;
-
-};
-
-THREE.RawNode.prototype.toJSON = function ( meta ) {
-
-	var data = this.getJSONNode( meta );
-
-	if ( ! data ) {
-
-		data = this.createJSONNode( meta );
-
-		data.value = this.value.toJSON( meta ).uuid;
-
-	}
-
-	return data;
-
-};

+ 205 - 0
examples/js/nodes/THREE.Nodes.js

@@ -0,0 +1,205 @@
+import { 
+
+	// core
+	
+	GLNode,
+	TempNode,
+	InputNode,
+	ConstNode,
+	VarNode,
+	StructNode,
+	AttributeNode,
+	FunctionNode,
+	FunctionCallNode,
+	NodeLib,
+	NodeUtils,
+	NodeFrame,
+	NodeUniform,
+	NodeBuilder,
+	
+	// inputs
+	
+	IntNode,
+	FloatNode,
+	Vector2Node,
+	Vector3Node,
+	Vector4Node,
+	ColorNode,
+	Matrix3Node,
+	Matrix4Node,
+	TextureNode,
+	CubeTextureNode,
+	ScreenNode,
+	ReflectorNode,
+	PropertyNode,
+	
+	// accessors
+	
+	UVNode,
+	ColorsNode,
+	PositionNode,
+	NormalNode,
+	CameraNode,
+	LightNode,
+	ReflectNode,
+	ScreenUVNode,
+	ResolutionNode,
+	
+	// math
+	
+	Math1Node,
+	Math2Node,
+	Math3Node,
+	OperatorNode,
+	
+	// procedural
+	
+	NoiseNode,
+	
+	// bsdfs
+	
+	BlinnShininessExponentNode,
+	BlinnExponentToRoughnessNode,
+	RoughnessToBlinnExponentNode,
+	
+	// misc
+	
+	TextureCubeUVNode,
+	TextureCubeNode,
+	NormalMapNode,
+	BumpMapNode,
+	
+	// utils
+	
+	BypassNode,
+	JoinNode,
+	SwitchNode,
+	TimerNode,
+	VelocityNode,
+	UVTransformNode,
+	MaxMIPLevelNode,
+	
+	// effects
+	
+	BlurNode,
+	ColorAdjustmentNode,
+	LuminanceNode,
+
+	// material nodes
+	
+	RawNode,
+	SpriteNode,
+	PhongNode,
+	StandardNode,
+	MeshStandardNode,
+	
+	// materials
+	
+	NodeMaterial,
+	SpriteNodeMaterial,
+	PhongNodeMaterial,
+	StandardNodeMaterial,
+	MeshStandardNodeMaterial
+	
+} from './Nodes.js';
+
+// core
+
+THREE.GLNode = GLNode;
+THREE.TempNode = TempNode;
+THREE.InputNode = InputNode;
+THREE.ConstNode = ConstNode;
+THREE.VarNode = VarNode;
+THREE.StructNode = StructNode;
+THREE.AttributeNode = AttributeNode;
+THREE.FunctionNode = FunctionNode;
+THREE.FunctionCallNode = FunctionCallNode;
+THREE.NodeLib = NodeLib;
+THREE.NodeUtils = NodeUtils;
+THREE.NodeFrame = NodeFrame;
+THREE.NodeUniform = NodeUniform;
+THREE.NodeBuilder = NodeBuilder;
+
+// inputs
+
+THREE.IntNode = IntNode;
+THREE.FloatNode = FloatNode;
+THREE.Vector2Node = Vector2Node;
+THREE.Vector3Node = Vector3Node;
+THREE.Vector4Node = Vector4Node;
+THREE.ColorNode = ColorNode;
+THREE.Matrix3Node = Matrix3Node;
+THREE.Matrix4Node = Matrix4Node;
+THREE.TextureNode = TextureNode;
+THREE.CubeTextureNode = CubeTextureNode;
+THREE.ScreenNode = ScreenNode;
+THREE.ReflectorNode = ReflectorNode;
+THREE.PropertyNode = PropertyNode;
+
+// accessors
+
+THREE.UVNode = UVNode;
+THREE.ColorsNode = ColorsNode;
+THREE.PositionNode = PositionNode;
+THREE.NormalNode = NormalNode;
+THREE.CameraNode = CameraNode;
+THREE.LightNode = LightNode;
+THREE.ReflectNode = ReflectNode;
+THREE.ScreenUVNode = ScreenUVNode;
+THREE.ResolutionNode = ResolutionNode;
+
+// math
+
+THREE.Math1Node = Math1Node;
+THREE.Math2Node = Math2Node;
+THREE.Math3Node = Math3Node;
+THREE.OperatorNode = OperatorNode;
+
+// procedural
+
+THREE.NoiseNode = NoiseNode;
+
+// bsdfs
+
+THREE.BlinnShininessExponentNode = BlinnShininessExponentNode;
+THREE.BlinnExponentToRoughnessNode = BlinnExponentToRoughnessNode;
+THREE.RoughnessToBlinnExponentNode = RoughnessToBlinnExponentNode;
+
+// misc
+
+THREE.TextureCubeUVNode = TextureCubeUVNode;
+THREE.TextureCubeNode = TextureCubeNode;
+THREE.NormalMapNode = NormalMapNode;
+THREE.BumpMapNode = BumpMapNode;
+
+// utils
+
+THREE.BypassNode = BypassNode;
+THREE.JoinNode = JoinNode;
+THREE.SwitchNode = SwitchNode;
+THREE.TimerNode = TimerNode;
+THREE.VelocityNode = VelocityNode;
+THREE.UVTransformNode = UVTransformNode;
+THREE.MaxMIPLevelNode = MaxMIPLevelNode;
+
+// effects
+
+THREE.BlurNode = BlurNode;
+THREE.ColorAdjustmentNode = ColorAdjustmentNode;
+THREE.LuminanceNode = LuminanceNode;
+
+// material nodes
+
+THREE.RawNode = RawNode;
+THREE.SpriteNode = SpriteNode;
+THREE.PhongNode = PhongNode;
+THREE.StandardNode = StandardNode;
+THREE.MeshStandardNode = MeshStandardNode;
+
+// materials
+
+THREE.NodeMaterial = NodeMaterial;
+THREE.SpriteNodeMaterial = SpriteNodeMaterial;
+THREE.PhongNodeMaterial = PhongNodeMaterial;
+THREE.StandardNodeMaterial = StandardNodeMaterial;
+THREE.MeshStandardNodeMaterial = MeshStandardNodeMaterial;

+ 0 - 134
examples/js/nodes/TempNode.js

@@ -1,134 +0,0 @@
-/**
- * Automatic node cache
- * @author sunag / http://www.sunag.com.br/
- */
-
-THREE.TempNode = function ( type, params ) {
-
-	THREE.GLNode.call( this, type );
-
-	params = params || {};
-
-	this.shared = params.shared !== undefined ? params.shared : true;
-	this.unique = params.unique !== undefined ? params.unique : false;
-
-};
-
-THREE.TempNode.prototype = Object.create( THREE.GLNode.prototype );
-THREE.TempNode.prototype.constructor = THREE.TempNode;
-
-THREE.TempNode.prototype.build = function ( builder, output, uuid, ns ) {
-
-	output = output || this.getType( builder );
-
-	var material = builder.material;
-
-	if ( this.isShared( builder, output ) ) {
-
-		var isUnique = this.isUnique( builder, output );
-
-		if ( isUnique && this.constructor.uuid === undefined ) {
-
-			this.constructor.uuid = THREE.Math.generateUUID();
-
-		}
-
-		uuid = builder.getUuid( uuid || this.getUuid(), ! isUnique );
-
-		var data = material.getDataNode( uuid );
-
-		if ( builder.parsing ) {
-
-			if ( data.deps || 0 > 0 ) {
-
-				this.appendDepsNode( builder, data, output );
-
-				return this.generate( builder, type, uuid );
-
-			}
-
-			return THREE.GLNode.prototype.build.call( this, builder, output, uuid );
-
-		} else if ( isUnique ) {
-
-			data.name = data.name || THREE.GLNode.prototype.build.call( this, builder, output, uuid );
-
-			return data.name;
-
-		} else if ( ! builder.optimize || data.deps == 1 ) {
-
-			return THREE.GLNode.prototype.build.call( this, builder, output, uuid );
-
-		}
-
-		uuid = this.getUuid( false );
-
-		var name = this.getTemp( builder, uuid );
-		var type = data.output || this.getType( builder );
-
-		if ( name ) {
-
-			return builder.format( name, type, output );
-
-		} else {
-
-			name = THREE.TempNode.prototype.generate.call( this, builder, output, uuid, data.output, ns );
-
-			var code = this.generate( builder, type, uuid );
-
-			if ( builder.isShader( 'vertex' ) ) material.addVertexNode( name + '=' + code + ';' );
-			else material.addFragmentNode( name + '=' + code + ';' );
-
-			return builder.format( name, type, output );
-
-		}
-
-	}
-
-	return THREE.GLNode.prototype.build.call( this, builder, output, uuid );
-
-};
-
-THREE.TempNode.prototype.isShared = function ( builder, output ) {
-
-	return output !== 'sampler2D' && output !== 'samplerCube' && this.shared;
-
-};
-
-THREE.TempNode.prototype.isUnique = function ( builder, output ) {
-
-	return this.unique;
-
-};
-
-THREE.TempNode.prototype.getUuid = function ( unique ) {
-
-	var uuid = unique || unique == undefined ? this.constructor.uuid || this.uuid : this.uuid;
-
-	if ( typeof this.scope == "string" ) uuid = this.scope + '-' + uuid;
-
-	return uuid;
-
-};
-
-THREE.TempNode.prototype.getTemp = function ( builder, uuid ) {
-
-	uuid = uuid || this.uuid;
-
-	var material = builder.material;
-
-	if ( builder.isShader( 'vertex' ) && material.vertexTemps[ uuid ] ) return material.vertexTemps[ uuid ].name;
-	else if ( material.fragmentTemps[ uuid ] ) return material.fragmentTemps[ uuid ].name;
-
-};
-
-THREE.TempNode.prototype.generate = function ( builder, output, uuid, type, ns ) {
-
-	if ( ! this.isShared( builder, output ) ) console.error( "THREE.TempNode is not shared!" );
-
-	uuid = uuid || this.uuid;
-
-	if ( builder.isShader( 'vertex' ) ) return builder.material.getVertexTemp( uuid, type || this.getType( builder ), ns ).name;
-	else return builder.material.getFragmentTemp( uuid, type || this.getType( builder ), ns ).name;
-
-};

+ 0 - 43
examples/js/nodes/VarNode.js

@@ -1,43 +0,0 @@
-/**
- * @author sunag / http://www.sunag.com.br/
- */
-
-THREE.VarNode = function ( type ) {
-
-	THREE.GLNode.call( this, type );
-
-};
-
-THREE.VarNode.prototype = Object.create( THREE.GLNode.prototype );
-THREE.VarNode.prototype.constructor = THREE.VarNode;
-THREE.VarNode.prototype.nodeType = "Var";
-
-THREE.VarNode.prototype.getType = function ( builder ) {
-
-	return builder.getTypeByFormat( this.type );
-
-};
-
-THREE.VarNode.prototype.generate = function ( builder, output ) {
-
-	var varying = builder.material.getVar( this.uuid, this.type );
-
-	return builder.format( varying.name, this.getType( builder ), output );
-
-};
-
-THREE.VarNode.prototype.toJSON = function ( meta ) {
-
-	var data = this.getJSONNode( meta );
-
-	if ( ! data ) {
-
-		data = this.createJSONNode( meta );
-
-		data.out = this.type;
-
-	}
-
-	return data;
-
-};

+ 97 - 50
examples/js/nodes/accessors/CameraNode.js

@@ -2,46 +2,66 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.CameraNode = function ( scope, camera ) {
+import { TempNode } from '../core/TempNode.js';
+import { FunctionNode } from '../core/FunctionNode.js';
+import { FloatNode } from '../inputs/FloatNode.js';
+import { PositionNode } from '../accessors/PositionNode.js';
+ 
+function CameraNode( scope, camera ) {
 
-	THREE.TempNode.call( this, 'v3' );
+	TempNode.call( this, 'v3' );
 
-	this.setScope( scope || THREE.CameraNode.POSITION );
+	this.setScope( scope || CameraNode.POSITION );
 	this.setCamera( camera );
 
 };
 
-THREE.CameraNode.fDepthColor = new THREE.FunctionNode( [
-	"float depthColor( float mNear, float mFar ) {",
-	"	#ifdef USE_LOGDEPTHBUF_EXT",
-	"		float depth = gl_FragDepthEXT / gl_FragCoord.w;",
-	"	#else",
-	"		float depth = gl_FragCoord.z / gl_FragCoord.w;",
-	"	#endif",
-	"	return 1.0 - smoothstep( mNear, mFar, depth );",
-	"}"
-].join( "\n" ) );
-
-THREE.CameraNode.POSITION = 'position';
-THREE.CameraNode.DEPTH = 'depth';
-THREE.CameraNode.TO_VERTEX = 'toVertex';
-
-THREE.CameraNode.prototype = Object.create( THREE.TempNode.prototype );
-THREE.CameraNode.prototype.constructor = THREE.CameraNode;
-THREE.CameraNode.prototype.nodeType = "Camera";
-
-THREE.CameraNode.prototype.setCamera = function ( camera ) {
+CameraNode.Nodes = (function() {
+	
+	var depthColor = new FunctionNode( [
+		"float depthColor( float mNear, float mFar ) {",
+		
+		"	#ifdef USE_LOGDEPTHBUF_EXT",
+		
+		"		float depth = gl_FragDepthEXT / gl_FragCoord.w;",
+		
+		"	#else",
+		
+		"		float depth = gl_FragCoord.z / gl_FragCoord.w;",
+		
+		"	#endif",
+		
+		"	return 1.0 - smoothstep( mNear, mFar, depth );",
+		
+		"}"
+	].join( "\n" ) );
+	
+	return {
+		depthColor: depthColor
+	};
+	
+})();
+
+CameraNode.POSITION = 'position';
+CameraNode.DEPTH = 'depth';
+CameraNode.TO_VERTEX = 'toVertex';
+
+CameraNode.prototype = Object.create( TempNode.prototype );
+CameraNode.prototype.constructor = CameraNode;
+CameraNode.prototype.nodeType = "Camera";
+
+CameraNode.prototype.setCamera = function ( camera ) {
 
 	this.camera = camera;
 	this.updateFrame = camera !== undefined ? this.onUpdateFrame : undefined;
 
 };
 
-THREE.CameraNode.prototype.setScope = function ( scope ) {
+CameraNode.prototype.setScope = function ( scope ) {
 
 	switch ( this.scope ) {
 
-		case THREE.CameraNode.DEPTH:
+		case CameraNode.DEPTH:
 
 			delete this.near;
 			delete this.far;
@@ -54,12 +74,12 @@ THREE.CameraNode.prototype.setScope = function ( scope ) {
 
 	switch ( scope ) {
 
-		case THREE.CameraNode.DEPTH:
+		case CameraNode.DEPTH:
 
 			var camera = this.camera;
 
-			this.near = new THREE.FloatNode( camera ? camera.near : 1 );
-			this.far = new THREE.FloatNode( camera ? camera.far : 1200 );
+			this.near = new FloatNode( camera ? camera.near : 1 );
+			this.far = new FloatNode( camera ? camera.far : 1200 );
 
 			break;
 
@@ -67,12 +87,13 @@ THREE.CameraNode.prototype.setScope = function ( scope ) {
 
 };
 
-THREE.CameraNode.prototype.getType = function ( builder ) {
+CameraNode.prototype.getType = function ( builder ) {
 
 	switch ( this.scope ) {
 
-		case THREE.CameraNode.DEPTH:
-			return 'fv1';
+		case CameraNode.DEPTH:
+		
+			return 'f';
 
 	}
 
@@ -80,12 +101,13 @@ THREE.CameraNode.prototype.getType = function ( builder ) {
 
 };
 
-THREE.CameraNode.prototype.isUnique = function ( builder ) {
+CameraNode.prototype.isUnique = function ( builder ) {
 
 	switch ( this.scope ) {
 
-		case THREE.CameraNode.DEPTH:
-		case THREE.CameraNode.TO_VERTEX:
+		case CameraNode.DEPTH:
+		case CameraNode.TO_VERTEX:
+		
 			return true;
 
 	}
@@ -94,11 +116,12 @@ THREE.CameraNode.prototype.isUnique = function ( builder ) {
 
 };
 
-THREE.CameraNode.prototype.isShared = function ( builder ) {
+CameraNode.prototype.isShared = function ( builder ) {
 
 	switch ( this.scope ) {
 
-		case THREE.CameraNode.POSITION:
+		case CameraNode.POSITION:
+		
 			return false;
 
 	}
@@ -107,32 +130,29 @@ THREE.CameraNode.prototype.isShared = function ( builder ) {
 
 };
 
-THREE.CameraNode.prototype.generate = function ( builder, output ) {
+CameraNode.prototype.generate = function ( builder, output ) {
 
-	var material = builder.material;
 	var result;
 
 	switch ( this.scope ) {
 
-		case THREE.CameraNode.POSITION:
+		case CameraNode.POSITION:
 
 			result = 'cameraPosition';
 
 			break;
 
-		case THREE.CameraNode.DEPTH:
-
-			var func = THREE.CameraNode.fDepthColor;
+		case CameraNode.DEPTH:
 
-			builder.include( func );
+			var depthColor = builder.include( CameraNode.Nodes.depthColor );
 
-			result = func.name + '(' + this.near.build( builder, 'fv1' ) + ',' + this.far.build( builder, 'fv1' ) + ')';
+			result = depthColor + '( ' + this.near.build( builder, 'f' ) + ', ' + this.far.build( builder, 'f' ) + ' )';
 
 			break;
 
-		case THREE.CameraNode.TO_VERTEX:
+		case CameraNode.TO_VERTEX:
 
-			result = 'normalize( ' + new THREE.PositionNode( THREE.PositionNode.WORLD ).build( builder, 'v3' ) + ' - cameraPosition )';
+			result = 'normalize( ' + new PositionNode( PositionNode.WORLD ).build( builder, 'v3' ) + ' - cameraPosition )';
 
 			break;
 
@@ -142,11 +162,11 @@ THREE.CameraNode.prototype.generate = function ( builder, output ) {
 
 };
 
-THREE.CameraNode.prototype.onUpdateFrame = function ( frame ) {
+CameraNode.prototype.onUpdateFrame = function ( frame ) {
 
 	switch ( this.scope ) {
 
-		case THREE.CameraNode.DEPTH:
+		case CameraNode.DEPTH:
 
 			var camera = this.camera;
 
@@ -159,7 +179,32 @@ THREE.CameraNode.prototype.onUpdateFrame = function ( frame ) {
 
 };
 
-THREE.CameraNode.prototype.toJSON = function ( meta ) {
+CameraNode.prototype.copy = function ( source ) {
+			
+	TempNode.prototype.copy.call( this, source );
+	
+	this.setScope( source.scope );
+
+	if ( source.camera ) {
+		
+		this.setCamera( source.camera );
+		
+	}
+
+	switch ( source.scope ) {
+
+		case CameraNode.DEPTH:
+
+			this.near.number = source.near;
+			this.far.number = source.far;
+
+			break;
+
+	}
+	
+};
+
+CameraNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -173,7 +218,7 @@ THREE.CameraNode.prototype.toJSON = function ( meta ) {
 
 		switch ( this.scope ) {
 
-			case THREE.CameraNode.DEPTH:
+			case CameraNode.DEPTH:
 
 				data.near = this.near.value;
 				data.far = this.far.value;
@@ -187,3 +232,5 @@ THREE.CameraNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { CameraNode };

+ 25 - 16
examples/js/nodes/accessors/ColorsNode.js

@@ -1,36 +1,43 @@
 /**
  * @author sunag / http://www.sunag.com.br/
  */
+ 
+import { TempNode } from '../core/TempNode.js';
+import { NodeLib } from '../core/NodeLib.js';
+ 
+var vertexDict = [ 'color', 'color2' ],
+	fragmentDict = [ 'vColor', 'vColor2' ];
+ 
+function ColorsNode( index ) {
 
-THREE.ColorsNode = function ( index ) {
-
-	THREE.TempNode.call( this, 'v4', { shared: false } );
+	TempNode.call( this, 'v4', { shared: false } );
 
 	this.index = index || 0;
 
 };
 
-THREE.ColorsNode.vertexDict = [ 'color', 'color2' ];
-THREE.ColorsNode.fragmentDict = [ 'vColor', 'vColor2' ];
-
-THREE.ColorsNode.prototype = Object.create( THREE.TempNode.prototype );
-THREE.ColorsNode.prototype.constructor = THREE.ColorsNode;
-
-THREE.ColorsNode.prototype.generate = function ( builder, output ) {
+ColorsNode.prototype = Object.create( TempNode.prototype );
+ColorsNode.prototype.constructor = ColorsNode;
 
-	var material = builder.material;
-	var result;
+ColorsNode.prototype.generate = function ( builder, output ) {
 
-	material.requires.color[ this.index ] = true;
+	builder.requires.color[ this.index ] = true;
 
-	if ( builder.isShader( 'vertex' ) ) result = THREE.ColorsNode.vertexDict[ this.index ];
-	else result = THREE.ColorsNode.fragmentDict[ this.index ];
+	var result = builder.isShader( 'vertex' ) ? vertexDict[ this.index ] : fragmentDict[ this.index ];
 
 	return builder.format( result, this.getType( builder ), output );
 
 };
 
-THREE.ColorsNode.prototype.toJSON = function ( meta ) {
+ColorsNode.prototype.copy = function ( source ) {
+			
+	TempNode.prototype.copy.call( this, source );
+	
+	this.index = source.index;
+	
+};
+
+ColorsNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -45,3 +52,5 @@ THREE.ColorsNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { ColorsNode };

+ 21 - 9
examples/js/nodes/accessors/LightNode.js

@@ -2,21 +2,23 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.LightNode = function ( scope ) {
+import { TempNode } from '../core/TempNode.js';
 
-	THREE.TempNode.call( this, 'v3', { shared: false } );
+function LightNode( scope ) {
 
-	this.scope = scope || THREE.LightNode.TOTAL;
+	TempNode.call( this, 'v3', { shared: false } );
+
+	this.scope = scope || LightNode.TOTAL;
 
 };
 
-THREE.LightNode.TOTAL = 'total';
+LightNode.TOTAL = 'total';
 
-THREE.LightNode.prototype = Object.create( THREE.TempNode.prototype );
-THREE.LightNode.prototype.constructor = THREE.LightNode;
-THREE.LightNode.prototype.nodeType = "Light";
+LightNode.prototype = Object.create( TempNode.prototype );
+LightNode.prototype.constructor = LightNode;
+LightNode.prototype.nodeType = "Light";
 
-THREE.LightNode.prototype.generate = function ( builder, output ) {
+LightNode.prototype.generate = function ( builder, output ) {
 
 	if ( builder.isCache( 'light' ) ) {
 
@@ -32,7 +34,15 @@ THREE.LightNode.prototype.generate = function ( builder, output ) {
 
 };
 
-THREE.LightNode.prototype.toJSON = function ( meta ) {
+LightNode.prototype.copy = function ( source ) {
+			
+	TempNode.prototype.copy.call( this, source );
+	
+	this.scope = source.scope;
+	
+};
+
+LightNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -47,3 +57,5 @@ THREE.LightNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { LightNode };

+ 53 - 24
examples/js/nodes/accessors/NormalNode.js

@@ -2,27 +2,31 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.NormalNode = function ( scope ) {
+import { TempNode } from '../core/TempNode.js';
+import { NodeLib } from '../core/NodeLib.js';
+ 
+function NormalNode( scope ) {
 
-	THREE.TempNode.call( this, 'v3' );
+	TempNode.call( this, 'v3' );
 
-	this.scope = scope || THREE.NormalNode.LOCAL;
+	this.scope = scope || NormalNode.LOCAL;
 
 };
 
-THREE.NormalNode.LOCAL = 'local';
-THREE.NormalNode.WORLD = 'world';
-THREE.NormalNode.VIEW = 'view';
+NormalNode.LOCAL = 'local';
+NormalNode.WORLD = 'world';
+NormalNode.VIEW = 'view';
 
-THREE.NormalNode.prototype = Object.create( THREE.TempNode.prototype );
-THREE.NormalNode.prototype.constructor = THREE.NormalNode;
-THREE.NormalNode.prototype.nodeType = "Normal";
+NormalNode.prototype = Object.create( TempNode.prototype );
+NormalNode.prototype.constructor = NormalNode;
+NormalNode.prototype.nodeType = "Normal";
 
-THREE.NormalNode.prototype.isShared = function ( builder ) {
+NormalNode.prototype.isShared = function ( builder ) {
 
 	switch ( this.scope ) {
 
-		case THREE.NormalNode.WORLD:
+		case NormalNode.WORLD:
+
 			return true;
 
 	}
@@ -31,32 +35,29 @@ THREE.NormalNode.prototype.isShared = function ( builder ) {
 
 };
 
-THREE.NormalNode.prototype.generate = function ( builder, output ) {
+NormalNode.prototype.generate = function ( builder, output ) {
 
-	var material = builder.material;
 	var result;
 
 	switch ( this.scope ) {
 
-		case THREE.NormalNode.LOCAL:
+		case NormalNode.LOCAL:
 
-			material.requires.normal = true;
+			builder.requires.normal = true;
 
-			if ( builder.isShader( 'vertex' ) ) result = 'normal';
-			else result = 'vObjectNormal';
+			result = builder.isShader( 'vertex' ) ? 'normal' : 'vObjectNormal';
 
 			break;
 
-		case THREE.NormalNode.WORLD:
-
-			material.requires.worldNormal = true;
+		case NormalNode.WORLD:
 
-			if ( builder.isShader( 'vertex' ) ) result = '( modelMatrix * vec4( objectNormal, 0.0 ) ).xyz';
-			else result = 'vWNormal';
+			builder.requires.worldNormal = true;
 
+			result = builder.isShader( 'vertex' ) ? '( modelMatrix * vec4( objectNormal, 0.0 ) ).xyz' : 'vWNormal';
+			
 			break;
 
-		case THREE.NormalNode.VIEW:
+		case NormalNode.VIEW:
 
 			result = 'vNormal';
 
@@ -68,7 +69,15 @@ THREE.NormalNode.prototype.generate = function ( builder, output ) {
 
 };
 
-THREE.NormalNode.prototype.toJSON = function ( meta ) {
+NormalNode.prototype.copy = function ( source ) {
+	
+	TempNode.prototype.copy.call( this, source );
+	
+	this.scope = source.scope;
+	
+};
+
+NormalNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -83,3 +92,23 @@ THREE.NormalNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+NodeLib.addKeyword( 'normal', function () {
+
+	return new NormalNode();
+
+} );
+
+NodeLib.addKeyword( 'worldNormal', function () {
+
+	return new NormalNode( NormalNode.WORLD );
+
+} );
+
+NodeLib.addKeyword( 'viewNormal', function () {
+
+	return new NormalNode( NormalNode.VIEW );
+
+} );
+
+export { NormalNode };

+ 60 - 32
examples/js/nodes/accessors/PositionNode.js

@@ -2,28 +2,32 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.PositionNode = function ( scope ) {
+import { TempNode } from '../core/TempNode.js';
+import { NodeLib } from '../core/NodeLib.js';
+ 
+function PositionNode( scope ) {
 
-	THREE.TempNode.call( this, 'v3' );
+	TempNode.call( this, 'v3' );
 
-	this.scope = scope || THREE.PositionNode.LOCAL;
+	this.scope = scope || PositionNode.LOCAL;
 
 };
 
-THREE.PositionNode.LOCAL = 'local';
-THREE.PositionNode.WORLD = 'world';
-THREE.PositionNode.VIEW = 'view';
-THREE.PositionNode.PROJECTION = 'projection';
+PositionNode.LOCAL = 'local';
+PositionNode.WORLD = 'world';
+PositionNode.VIEW = 'view';
+PositionNode.PROJECTION = 'projection';
 
-THREE.PositionNode.prototype = Object.create( THREE.TempNode.prototype );
-THREE.PositionNode.prototype.constructor = THREE.PositionNode;
-THREE.PositionNode.prototype.nodeType = "Position";
+PositionNode.prototype = Object.create( TempNode.prototype );
+PositionNode.prototype.constructor = PositionNode;
+PositionNode.prototype.nodeType = "Position";
 
-THREE.PositionNode.prototype.getType = function ( builder ) {
+PositionNode.prototype.getType = function ( builder ) {
 
 	switch ( this.scope ) {
 
-		case THREE.PositionNode.PROJECTION:
+		case PositionNode.PROJECTION:
+		
 			return 'v4';
 
 	}
@@ -32,12 +36,13 @@ THREE.PositionNode.prototype.getType = function ( builder ) {
 
 };
 
-THREE.PositionNode.prototype.isShared = function ( builder ) {
+PositionNode.prototype.isShared = function ( builder ) {
 
 	switch ( this.scope ) {
 
-		case THREE.PositionNode.LOCAL:
-		case THREE.PositionNode.WORLD:
+		case PositionNode.LOCAL:
+		case PositionNode.WORLD:
+		
 			return false;
 
 	}
@@ -46,42 +51,37 @@ THREE.PositionNode.prototype.isShared = function ( builder ) {
 
 };
 
-THREE.PositionNode.prototype.generate = function ( builder, output ) {
+PositionNode.prototype.generate = function ( builder, output ) {
 
-	var material = builder.material;
 	var result;
 
 	switch ( this.scope ) {
 
-		case THREE.PositionNode.LOCAL:
+		case PositionNode.LOCAL:
 
-			material.requires.position = true;
+			builder.requires.position = true;
 
-			if ( builder.isShader( 'vertex' ) ) result = 'transformed';
-			else result = 'vPosition';
+			result = builder.isShader( 'vertex' ) ? 'transformed' : 'vPosition';
 
 			break;
 
-		case THREE.PositionNode.WORLD:
+		case PositionNode.WORLD:
 
-			material.requires.worldPosition = true;
+			builder.requires.worldPosition = true;
 
-			if ( builder.isShader( 'vertex' ) ) result = 'vWPosition';
-			else result = 'vWPosition';
+			result = 'vWPosition';
 
 			break;
 
-		case THREE.PositionNode.VIEW:
+		case PositionNode.VIEW:
 
-			if ( builder.isShader( 'vertex' ) ) result = '-mvPosition.xyz';
-			else result = 'vViewPosition';
+			result = builder.isShader( 'vertex' ) ? '-mvPosition.xyz' : 'vViewPosition';
 
 			break;
 
-		case THREE.PositionNode.PROJECTION:
+		case PositionNode.PROJECTION:
 
-			if ( builder.isShader( 'vertex' ) ) result = '(projectionMatrix * modelViewMatrix * vec4( position, 1.0 ))';
-			else result = 'vec4( 0.0 )';
+			result = builder.isShader( 'vertex' ) ? '( projectionMatrix * modelViewMatrix * vec4( position, 1.0 ) )' : 'vec4( 0.0 )';
 
 			break;
 
@@ -91,7 +91,15 @@ THREE.PositionNode.prototype.generate = function ( builder, output ) {
 
 };
 
-THREE.PositionNode.prototype.toJSON = function ( meta ) {
+PositionNode.prototype.copy = function ( source ) {
+			
+	TempNode.prototype.copy.call( this, source );
+	
+	this.scope = source.scope;
+	
+};
+
+PositionNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -106,3 +114,23 @@ THREE.PositionNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+NodeLib.addKeyword( 'position', function () {
+
+	return new PositionNode();
+
+} );
+
+NodeLib.addKeyword( 'worldPosition', function () {
+
+	return new PositionNode( PositionNode.WORLD );
+
+} );
+
+NodeLib.addKeyword( 'viewPosition', function () {
+
+	return new PositionNode( NormalNode.VIEW );
+
+} );
+
+export { PositionNode };

+ 46 - 31
examples/js/nodes/accessors/ReflectNode.js

@@ -2,27 +2,30 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.ReflectNode = function ( scope ) {
+import { TempNode } from '../core/TempNode.js';
 
-	THREE.TempNode.call( this, 'v3', { unique: true } );
+function ReflectNode( scope ) {
 
-	this.scope = scope || THREE.ReflectNode.CUBE;
+	TempNode.call( this, 'v3', { unique: true } );
+
+	this.scope = scope || ReflectNode.CUBE;
 
 };
 
-THREE.ReflectNode.CUBE = 'cube';
-THREE.ReflectNode.SPHERE = 'sphere';
-THREE.ReflectNode.VECTOR = 'vector';
+ReflectNode.CUBE = 'cube';
+ReflectNode.SPHERE = 'sphere';
+ReflectNode.VECTOR = 'vector';
 
-THREE.ReflectNode.prototype = Object.create( THREE.TempNode.prototype );
-THREE.ReflectNode.prototype.constructor = THREE.ReflectNode;
-THREE.ReflectNode.prototype.nodeType = "Reflect";
+ReflectNode.prototype = Object.create( TempNode.prototype );
+ReflectNode.prototype.constructor = ReflectNode;
+ReflectNode.prototype.nodeType = "Reflect";
 
-THREE.ReflectNode.prototype.getType = function ( builder ) {
+ReflectNode.prototype.getType = function ( builder ) {
 
 	switch ( this.scope ) {
 
-		case THREE.ReflectNode.SPHERE:
+		case ReflectNode.SPHERE:
+
 			return 'v2';
 
 	}
@@ -31,47 +34,57 @@ THREE.ReflectNode.prototype.getType = function ( builder ) {
 
 };
 
-THREE.ReflectNode.prototype.generate = function ( builder, output ) {
+ReflectNode.prototype.generate = function ( builder, output ) {
 
-	var result;
+	if ( builder.isShader( 'fragment' ) ) {
+		
+		var result;
 
-	switch ( this.scope ) {
+		switch ( this.scope ) {
 
-		case THREE.ReflectNode.VECTOR:
+			case ReflectNode.VECTOR:
 
-			builder.material.addFragmentNode( 'vec3 reflectVec = inverseTransformDirection( reflect( -normalize( vViewPosition ), normal ), viewMatrix );' );
+				builder.addNodeCode( 'vec3 reflectVec = inverseTransformDirection( reflect( -normalize( vViewPosition ), normal ), viewMatrix );' );
 
-			result = 'reflectVec';
+				result = 'reflectVec';
 
-			break;
+				break;
 
-		case THREE.ReflectNode.CUBE:
+			case ReflectNode.CUBE:
 
-			var reflectVec = new THREE.ReflectNode( THREE.ReflectNode.VECTOR ).build( builder, 'v3' );
+				var reflectVec = new ReflectNode( ReflectNode.VECTOR ).build( builder, 'v3' );
 
-			builder.material.addFragmentNode( 'vec3 reflectCubeVec = vec3( -1.0 * ' + reflectVec + '.x, ' + reflectVec + '.yz );' );
+				builder.addNodeCode( 'vec3 reflectCubeVec = vec3( -1.0 * ' + reflectVec + '.x, ' + reflectVec + '.yz );' );
 
-			result = 'reflectCubeVec';
+				result = 'reflectCubeVec';
 
-			break;
+				break;
 
-		case THREE.ReflectNode.SPHERE:
+			case ReflectNode.SPHERE:
 
-			var reflectVec = new THREE.ReflectNode( THREE.ReflectNode.VECTOR ).build( builder, 'v3' );
+				var reflectVec = new ReflectNode( ReflectNode.VECTOR ).build( builder, 'v3' );
 
-			builder.material.addFragmentNode( 'vec2 reflectSphereVec = normalize((viewMatrix * vec4(' + reflectVec + ', 0.0 )).xyz + vec3(0.0,0.0,1.0)).xy * 0.5 + 0.5;' );
+				builder.addNodeCode( 'vec2 reflectSphereVec = normalize( ( viewMatrix * vec4( ' + reflectVec + ', 0.0 ) ).xyz + vec3( 0.0, 0.0, 1.0 ) ).xy * 0.5 + 0.5;' );
 
-			result = 'reflectSphereVec';
+				result = 'reflectSphereVec';
 
-			break;
+				break;
 
-	}
+		}
 
-	return builder.format( result, this.getType( this.type ), output );
+		return builder.format( result, this.getType( this.type ), output );
+	
+	} else {
+		
+		console.warn( "THREE.ReflectNode is not compatible with " + builder.shader + " shader." );
+
+		return builder.format( 'vec3( 0.0 )', this.type, output );
+		
+	}
 
 };
 
-THREE.ReflectNode.prototype.toJSON = function ( meta ) {
+ReflectNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -86,3 +99,5 @@ THREE.ReflectNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { ReflectNode };

+ 53 - 0
examples/js/nodes/accessors/ResolutionNode.js

@@ -0,0 +1,53 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { Vector2Node } from '../inputs/Vector2Node.js';
+ 
+function ResolutionNode( renderer ) {
+
+	Vector2Node.call( this );
+
+	this.renderer = renderer;
+
+};
+
+ResolutionNode.prototype = Object.create( Vector2Node.prototype );
+ResolutionNode.prototype.constructor = ResolutionNode;
+ResolutionNode.prototype.nodeType = "Resolution";
+
+ResolutionNode.prototype.updateFrame = function ( frame ) {
+
+	var size = this.renderer.getSize(),
+		pixelRatio = this.renderer.getPixelRatio();
+
+	this.x = size.width * pixelRatio;
+	this.y = size.height * pixelRatio;
+
+};
+
+ResolutionNode.prototype.copy = function ( source ) {
+			
+	Vector2Node.prototype.copy.call( this, source );
+	
+	this.renderer = source.renderer;
+	
+};
+
+ResolutionNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.renderer = this.renderer.uuid;
+
+	}
+
+	return data;
+
+};
+
+export { ResolutionNode };

+ 21 - 9
examples/js/nodes/accessors/ScreenUVNode.js

@@ -2,26 +2,27 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.ScreenUVNode = function ( resolution ) {
+import { TempNode } from '../core/TempNode.js';
+ 
+function ScreenUVNode( resolution ) {
 
-	THREE.TempNode.call( this, 'v2' );
+	TempNode.call( this, 'v2' );
 
 	this.resolution = resolution;
 
 };
 
-THREE.ScreenUVNode.prototype = Object.create( THREE.TempNode.prototype );
-THREE.ScreenUVNode.prototype.constructor = THREE.ScreenUVNode;
-THREE.ScreenUVNode.prototype.nodeType = "ScreenUV";
+ScreenUVNode.prototype = Object.create( TempNode.prototype );
+ScreenUVNode.prototype.constructor = ScreenUVNode;
+ScreenUVNode.prototype.nodeType = "ScreenUV";
 
-THREE.ScreenUVNode.prototype.generate = function ( builder, output ) {
+ScreenUVNode.prototype.generate = function ( builder, output ) {
 
-	var material = builder.material;
 	var result;
 
 	if ( builder.isShader( 'fragment' ) ) {
 
-		result = '(gl_FragCoord.xy/' + this.resolution.build( builder, 'v2' ) + ')';
+		result = '( gl_FragCoord.xy / ' + this.resolution.build( builder, 'v2' ) + ')';
 
 	} else {
 
@@ -35,7 +36,15 @@ THREE.ScreenUVNode.prototype.generate = function ( builder, output ) {
 
 };
 
-THREE.ScreenUVNode.prototype.toJSON = function ( meta ) {
+ScreenUVNode.prototype.copy = function ( source ) {
+			
+	TempNode.prototype.copy.call( this, source );
+	
+	this.resolution = source.resolution;
+	
+};
+
+ScreenUVNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -50,3 +59,6 @@ THREE.ScreenUVNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { ScreenUVNode };
+

+ 37 - 16
examples/js/nodes/accessors/UVNode.js

@@ -2,36 +2,43 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.UVNode = function ( index ) {
+import { TempNode } from '../core/TempNode.js';
+import { NodeLib } from '../core/NodeLib.js';
+ 
+var vertexDict = [ 'uv', 'uv2' ],
+	fragmentDict = [ 'vUv', 'vUv2' ];
+ 
+function UVNode( index ) {
 
-	THREE.TempNode.call( this, 'v2', { shared: false } );
+	TempNode.call( this, 'v2', { shared: false } );
 
 	this.index = index || 0;
 
 };
 
-THREE.UVNode.vertexDict = [ 'uv', 'uv2' ];
-THREE.UVNode.fragmentDict = [ 'vUv', 'vUv2' ];
+UVNode.prototype = Object.create( TempNode.prototype );
+UVNode.prototype.constructor = UVNode;
+UVNode.prototype.nodeType = "UV";
 
-THREE.UVNode.prototype = Object.create( THREE.TempNode.prototype );
-THREE.UVNode.prototype.constructor = THREE.UVNode;
-THREE.UVNode.prototype.nodeType = "UV";
+UVNode.prototype.generate = function ( builder, output ) {
 
-THREE.UVNode.prototype.generate = function ( builder, output ) {
+	builder.requires.uv[ this.index ] = true;
 
-	var material = builder.material;
-	var result;
-
-	material.requires.uv[ this.index ] = true;
-
-	if ( builder.isShader( 'vertex' ) ) result = THREE.UVNode.vertexDict[ this.index ];
-	else result = THREE.UVNode.fragmentDict[ this.index ];
+	var result = builder.isShader( 'vertex' ) ? vertexDict[ this.index ] : fragmentDict[ this.index ];
 
 	return builder.format( result, this.getType( builder ), output );
 
 };
 
-THREE.UVNode.prototype.toJSON = function ( meta ) {
+UVNode.prototype.copy = function ( source ) {
+		
+	TempNode.prototype.copy.call( this, source );
+	
+	this.index = source.index;
+	
+};
+
+UVNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -46,3 +53,17 @@ THREE.UVNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+NodeLib.addKeyword( 'uv', function () {
+
+	return new UVNode();
+
+} );
+
+NodeLib.addKeyword( 'uv2', function () {
+
+	return new UVNode( 1 );
+
+} );
+
+export { UVNode };

+ 50 - 0
examples/js/nodes/bsdfs/BlinnExponentToRoughnessNode.js

@@ -0,0 +1,50 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { TempNode } from '../core/TempNode.js';
+import { BlinnShininessExponentNode } from './BlinnShininessExponentNode.js';
+
+function BlinnExponentToRoughnessNode( blinnExponent ) {
+
+	TempNode.call( this, 'f' );
+
+	this.blinnExponent = blinnExponent || new BlinnShininessExponentNode();
+
+};
+
+BlinnExponentToRoughnessNode.prototype = Object.create( TempNode.prototype );
+BlinnExponentToRoughnessNode.prototype.constructor = BlinnExponentToRoughnessNode;
+BlinnExponentToRoughnessNode.prototype.nodeType = "BlinnExponentToRoughness";
+
+BlinnExponentToRoughnessNode.prototype.generate = function ( builder, output ) {
+
+	return builder.format( 'BlinnExponentToGGXRoughness( ' + this.blinnExponent.build( builder, 'f' ) + ' )', this.type, output );
+
+};
+
+BlinnExponentToRoughnessNode.prototype.copy = function ( source ) {
+			
+	TempNode.prototype.copy.call( this, source );
+	
+	this.blinnExponent = source.blinnExponent;
+	
+};
+
+BlinnExponentToRoughnessNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.blinnExponent = this.blinnExponent;
+
+	}
+
+	return data;
+
+};
+
+export { BlinnExponentToRoughnessNode };

+ 31 - 0
examples/js/nodes/bsdfs/BlinnShininessExponentNode.js

@@ -0,0 +1,31 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { TempNode } from '../core/TempNode.js';
+
+function BlinnShininessExponentNode() {
+
+	TempNode.call( this, 'f' );
+
+};
+
+BlinnShininessExponentNode.prototype = Object.create( TempNode.prototype );
+BlinnShininessExponentNode.prototype.constructor = BlinnShininessExponentNode;
+BlinnShininessExponentNode.prototype.nodeType = "BlinnShininessExponent";
+
+BlinnShininessExponentNode.prototype.generate = function ( builder, output ) {
+
+	if ( builder.isCache( 'clearCoat' ) ) {
+
+		return builder.format( 'Material_ClearCoat_BlinnShininessExponent( material )', this.type, output );
+
+	} else {
+
+		return builder.format( 'Material_BlinnShininessExponent( material )', this.type, output );
+
+	}
+
+};
+
+export { BlinnShininessExponentNode };

+ 91 - 0
examples/js/nodes/bsdfs/RoughnessToBlinnExponentNode.js

@@ -0,0 +1,91 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { TempNode } from '../core/TempNode.js';
+import { FunctionNode } from '../core/FunctionNode.js';
+import { MaxMIPLevelNode } from '../utils/MaxMIPLevelNode.js';
+import { BlinnShininessExponentNode } from './BlinnShininessExponentNode.js';
+ 
+function RoughnessToBlinnExponentNode( texture ) {
+
+	TempNode.call( this, 'f' );
+
+	this.texture = texture;
+
+	this.maxMIPLevel = new MaxMIPLevelNode( texture );
+	this.blinnShininessExponent = new BlinnShininessExponentNode();
+
+};
+
+RoughnessToBlinnExponentNode.Nodes = (function() {
+
+	var getSpecularMIPLevel = new FunctionNode( [
+		// taken from here: http://casual-effects.blogspot.ca/2011/08/plausible-environment-lighting-in-two.html
+		"float getSpecularMIPLevel( const in float blinnShininessExponent, const in float maxMIPLevelScalar ) {",
+
+		//	float envMapWidth = pow( 2.0, maxMIPLevelScalar );
+		//	float desiredMIPLevel = log2( envMapWidth * sqrt( 3.0 ) ) - 0.5 * log2( pow2( blinnShininessExponent ) + 1.0 );
+
+		"	float desiredMIPLevel = maxMIPLevelScalar - 0.79248 - 0.5 * log2( pow2( blinnShininessExponent ) + 1.0 );",
+
+		// clamp to allowable LOD ranges.
+		"	return clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );",
+		"}"
+	].join( "\n" ) );
+	
+	return {
+		getSpecularMIPLevel: getSpecularMIPLevel
+	};
+	
+})();
+
+RoughnessToBlinnExponentNode.prototype = Object.create( TempNode.prototype );
+RoughnessToBlinnExponentNode.prototype.constructor = RoughnessToBlinnExponentNode;
+RoughnessToBlinnExponentNode.prototype.nodeType = "RoughnessToBlinnExponent";
+
+RoughnessToBlinnExponentNode.prototype.generate = function ( builder, output ) {
+
+	if ( builder.isShader( 'fragment' ) ) {
+
+		this.maxMIPLevel.texture = this.texture;
+	
+		var getSpecularMIPLevel = builder.include( RoughnessToBlinnExponentNode.Nodes.getSpecularMIPLevel );
+
+		return builder.format( getSpecularMIPLevel + '( ' + this.blinnShininessExponent.build( builder, 'f' ) + ', ' + this.maxMIPLevel.build( builder, 'f' ) + ' )', this.type, output );
+
+	} else {
+
+		console.warn( "THREE.RoughnessToBlinnExponentNode is not compatible with " + builder.shader + " shader." );
+
+		return builder.format( '0.0', this.type, output );
+
+	}
+
+};
+
+RoughnessToBlinnExponentNode.prototype.copy = function ( source ) {
+			
+	TempNode.prototype.copy.call( this, source );
+	
+	this.texture = source.texture;
+	
+};
+
+RoughnessToBlinnExponentNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.texture = this.texture;
+
+	}
+
+	return data;
+
+};
+
+export { RoughnessToBlinnExponentNode };

+ 70 - 0
examples/js/nodes/core/AttributeNode.js

@@ -0,0 +1,70 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { GLNode } from './GLNode.js';
+
+function AttributeNode( name, type ) {
+
+	GLNode.call( this, type );
+
+	this.name = name;
+
+};
+
+AttributeNode.prototype = Object.create( GLNode.prototype );
+AttributeNode.prototype.constructor = AttributeNode;
+AttributeNode.prototype.nodeType = "Attribute";
+
+AttributeNode.prototype.getAttributeType = function ( builder ) {
+
+	return typeof this.type === 'number' ? builder.getConstructorFromLength( this.type ) : this.type;
+
+};
+
+AttributeNode.prototype.getType = function ( builder ) {
+
+	var type = this.getAttributeType( builder );
+
+	return builder.getTypeByFormat( type );
+
+};
+
+AttributeNode.prototype.generate = function ( builder, output ) {
+
+	var type = this.getAttributeType( builder );
+
+	var attribute = builder.getAttribute( this.name, type ),
+		name = builder.isShader( 'vertex' ) ? this.name : attribute.varying.name;
+
+	console.log( attribute );
+		
+	return builder.format( name, this.getType( builder ), output );
+
+};
+
+AttributeNode.prototype.copy = function ( source ) {
+			
+	GLNode.prototype.copy.call( this, source );
+	
+	this.type = source.type;
+	
+};
+
+AttributeNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.type = this.type;
+
+	}
+
+	return data;
+
+};
+
+export { AttributeNode };

+ 125 - 0
examples/js/nodes/core/ConstNode.js

@@ -0,0 +1,125 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { TempNode } from './TempNode.js';
+
+function ConstNode( src, useDefine ) {
+
+	TempNode.call( this );
+
+	this.eval( src || ConstNode.PI, useDefine );
+
+};
+
+ConstNode.PI = 'PI';
+ConstNode.PI2 = 'PI2';
+ConstNode.RECIPROCAL_PI = 'RECIPROCAL_PI';
+ConstNode.RECIPROCAL_PI2 = 'RECIPROCAL_PI2';
+ConstNode.LOG2 = 'LOG2';
+ConstNode.EPSILON = 'EPSILON';
+
+ConstNode.rDeclaration = /^([a-z_0-9]+)\s([a-z_0-9]+)\s?\=?\s?(.*?)(\;|$)/i;
+
+ConstNode.prototype = Object.create( TempNode.prototype );
+ConstNode.prototype.constructor = ConstNode;
+ConstNode.prototype.nodeType = "Const";
+
+ConstNode.prototype.getType = function ( builder ) {
+
+	return builder.getTypeByFormat( this.type );
+
+};
+
+ConstNode.prototype.eval = function ( src, useDefine ) {
+
+	this.src = src || '';
+
+	var name, type, value = "";
+
+	var match = this.src.match( ConstNode.rDeclaration );
+
+	this.useDefine = useDefine || this.src.charAt(0) === '#';
+
+	if ( match && match.length > 1 ) {
+
+		type = match[ 1 ];
+		name = match[ 2 ];
+		value = match[ 3 ];
+
+	} else {
+
+		name = this.src;
+		type = 'f';
+
+	}
+
+	this.name = name;
+	this.type = type;
+	this.value = value;
+
+};
+
+ConstNode.prototype.build = function ( builder, output ) {
+
+	if ( output === 'source' ) {
+
+		if ( this.value ) {
+
+			if ( this.useDefine ) {
+
+				return '#define ' + this.name + ' ' + this.value;
+
+			}
+
+			return 'const ' + this.type + ' ' + this.name + ' = ' + this.value + ';';
+
+		} else if (this.useDefine) {
+		
+			return this.src;
+			
+		}
+
+	} else {
+
+		builder.include( this );
+
+		return builder.format( this.name, this.getType( builder ), output );
+
+	}
+
+};
+
+ConstNode.prototype.generate = function ( builder, output ) {
+
+	return builder.format( this.name, this.getType( builder ), output );
+
+};
+
+ConstNode.prototype.copy = function ( source ) {
+	
+	TempNode.prototype.copy.call( this, source );
+	
+	this.eval( source.src, source.useDefine );	
+	
+};
+
+ConstNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.src = this.src;
+
+		if ( data.useDefine === true ) data.useDefine = true;
+
+	}
+
+	return data;
+
+};
+
+export { ConstNode };

+ 108 - 0
examples/js/nodes/core/FunctionCallNode.js

@@ -0,0 +1,108 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { TempNode } from './TempNode.js';
+ 
+function FunctionCallNode( func, inputs ) {
+
+	TempNode.call( this );
+
+	this.setFunction( func, inputs );
+
+};
+
+FunctionCallNode.prototype = Object.create( TempNode.prototype );
+FunctionCallNode.prototype.constructor = FunctionCallNode;
+FunctionCallNode.prototype.nodeType = "FunctionCall";
+
+FunctionCallNode.prototype.setFunction = function ( func, inputs ) {
+
+	this.value = func;
+	this.inputs = inputs || [];
+
+};
+
+FunctionCallNode.prototype.getFunction = function () {
+
+	return this.value;
+
+};
+
+FunctionCallNode.prototype.getType = function ( builder ) {
+
+	return this.value.getType( builder );
+
+};
+
+FunctionCallNode.prototype.generate = function ( builder, output ) {
+
+	var type = this.getType( builder ),
+		func = this.value;
+
+	var code = func.build( builder, output ) + '( ',
+		params = [];
+
+	for ( var i = 0; i < func.inputs.length; i ++ ) {
+
+		var inpt = func.inputs[ i ],
+			param = this.inputs[ i ] || this.inputs[ inpt.name ];
+
+		params.push( param.build( builder, builder.getTypeByFormat( inpt.type ) ) );
+
+	}
+
+	code += params.join( ', ' ) + ' )';
+
+	return builder.format( code, type, output );
+
+};
+
+FunctionCallNode.prototype.copy = function ( source ) {
+			
+	TempNode.prototype.copy.call( this, source );
+	
+	for ( var prop in source.inputs ) {
+
+		this.inputs[ prop ] = source.inputs[ prop ];
+
+	}
+
+	this.value = source.value;
+	
+};
+
+FunctionCallNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		var func = this.value;
+
+		data = this.createJSONNode( meta );
+
+		data.value = this.value.toJSON( meta ).uuid;
+
+		if ( func.inputs.length ) {
+
+			data.inputs = {};
+
+			for ( var i = 0; i < func.inputs.length; i ++ ) {
+
+				var inpt = func.inputs[ i ],
+					node = this.inputs[ i ] || this.inputs[ inpt.name ];
+
+				data.inputs[ inpt.name ] = node.toJSON( meta ).uuid;
+
+			}
+
+		}
+
+	}
+
+	return data;
+
+};
+
+export { FunctionCallNode };

+ 56 - 34
examples/js/nodes/FunctionNode.js → examples/js/nodes/core/FunctionNode.js

@@ -3,40 +3,48 @@
  * @thanks bhouston / https://clara.io/
  */
 
-THREE.FunctionNode = function ( src, includesOrType, extensionsOrIncludes, keywordsOrExtensions ) {
+import { TempNode } from './TempNode.js';
+import { NodeLib } from './NodeLib.js';
 
-	src = src || '';
+function FunctionNode( src, includesOrType, extensionsOrKeywords, keywordsOrExtensions, includes ) {
 
 	this.isMethod = typeof includesOrType !== "string";
 	this.useKeywords = true;
 
-	THREE.TempNode.call( this, this.isMethod ? null : includesOrType );
+	TempNode.call( this, this.isMethod ? null : includesOrType );
 
-	if ( this.isMethod ) this.eval( src, includesOrType, extensionsOrIncludes, keywordsOrExtensions );
-	else this.eval( src, extensionsOrIncludes, keywordsOrExtensions );
+	if ( this.isMethod ) {
+		
+		this.eval( src, includesOrType, extensionsOrKeywords, keywordsOrExtensions );
+		
+	} else {
+		
+		this.eval( src, includes, keywordsOrExtensions, extensionsOrKeywords );
+
+	}
 
 };
 
-THREE.FunctionNode.rDeclaration = /^([a-z_0-9]+)\s([a-z_0-9]+)\s?\((.*?)\)/i;
-THREE.FunctionNode.rProperties = /[a-z_0-9]+/ig;
+FunctionNode.rDeclaration = /^([a-z_0-9]+)\s([a-z_0-9]+)\s*\((.*?)\)/i;
+FunctionNode.rProperties = /[a-z_0-9]+/ig;
 
-THREE.FunctionNode.prototype = Object.create( THREE.TempNode.prototype );
-THREE.FunctionNode.prototype.constructor = THREE.FunctionNode;
-THREE.FunctionNode.prototype.nodeType = "Function";
+FunctionNode.prototype = Object.create( TempNode.prototype );
+FunctionNode.prototype.constructor = FunctionNode;
+FunctionNode.prototype.nodeType = "Function";
 
-THREE.FunctionNode.prototype.isShared = function ( builder, output ) {
+FunctionNode.prototype.isShared = function ( builder, output ) {
 
 	return ! this.isMethod;
 
 };
 
-THREE.FunctionNode.prototype.getType = function ( builder ) {
+FunctionNode.prototype.getType = function ( builder ) {
 
 	return builder.getTypeByFormat( this.type );
 
 };
 
-THREE.FunctionNode.prototype.getInputByName = function ( name ) {
+FunctionNode.prototype.getInputByName = function ( name ) {
 
 	var i = this.inputs.length;
 
@@ -49,7 +57,7 @@ THREE.FunctionNode.prototype.getInputByName = function ( name ) {
 
 };
 
-THREE.FunctionNode.prototype.getIncludeByName = function ( name ) {
+FunctionNode.prototype.getIncludeByName = function ( name ) {
 
 	var i = this.includes.length;
 
@@ -62,9 +70,9 @@ THREE.FunctionNode.prototype.getIncludeByName = function ( name ) {
 
 };
 
-THREE.FunctionNode.prototype.generate = function ( builder, output ) {
+FunctionNode.prototype.generate = function ( builder, output ) {
 
-	var match, offset = 0, src = this.value;
+	var match, offset = 0, src = this.src;
 
 	for ( var i = 0; i < this.includes.length; i ++ ) {
 
@@ -74,26 +82,27 @@ THREE.FunctionNode.prototype.generate = function ( builder, output ) {
 
 	for ( var ext in this.extensions ) {
 
-		builder.material.extensions[ ext ] = true;
+		builder.extensions[ ext ] = true;
 
 	}
 
-	while ( match = THREE.FunctionNode.rProperties.exec( this.value ) ) {
+	while ( match = FunctionNode.rProperties.exec( this.src ) ) {
 
-		var prop = match[ 0 ], isGlobal = this.isMethod ? ! this.getInputByName( prop ) : true;
-		var reference = prop;
+		var prop = match[ 0 ], 
+			isGlobal = this.isMethod ? ! this.getInputByName( prop ) : true,
+			reference = prop;
 
-		if ( this.keywords[ prop ] || ( this.useKeywords && isGlobal && THREE.NodeLib.containsKeyword( prop ) ) ) {
+		if ( this.keywords[ prop ] || ( this.useKeywords && isGlobal && NodeLib.containsKeyword( prop ) ) ) {
 
 			var node = this.keywords[ prop ];
 
 			if ( ! node ) {
 
-				var keyword = THREE.NodeLib.getKeywordData( prop );
+				var keyword = NodeLib.getKeywordData( prop );
 
 				if ( keyword.cache ) node = builder.keywords[ prop ];
 
-				node = node || THREE.NodeLib.getKeyword( prop, builder );
+				node = node || NodeLib.getKeyword( prop, builder );
 
 				if ( keyword.cache ) builder.keywords[ prop ] = node;
 
@@ -111,9 +120,9 @@ THREE.FunctionNode.prototype.generate = function ( builder, output ) {
 
 		}
 
-		if ( this.getIncludeByName( reference ) === undefined && THREE.NodeLib.contains( reference ) ) {
+		if ( this.getIncludeByName( reference ) === undefined && NodeLib.contains( reference ) ) {
 
-			builder.include( THREE.NodeLib.get( reference ) );
+			builder.include( NodeLib.get( reference ) );
 
 		}
 
@@ -131,15 +140,15 @@ THREE.FunctionNode.prototype.generate = function ( builder, output ) {
 
 	} else {
 
-		return builder.format( "(" + src + ")", this.getType( builder ), output );
+		return builder.format( '( ' + src + ' )', this.getType( builder ), output );
 
 	}
 
 };
 
-THREE.FunctionNode.prototype.eval = function ( src, includes, extensions, keywords ) {
+FunctionNode.prototype.eval = function ( src, includes, extensions, keywords ) {
 
-	src = ( src || '' ).trim();
+	this.src = src || '';
 
 	this.includes = includes || [];
 	this.extensions = extensions || {};
@@ -147,7 +156,7 @@ THREE.FunctionNode.prototype.eval = function ( src, includes, extensions, keywor
 
 	if ( this.isMethod ) {
 
-		var match = src.match( THREE.FunctionNode.rDeclaration );
+		var match = this.src.match( FunctionNode.rDeclaration );
 
 		this.inputs = [];
 
@@ -156,7 +165,7 @@ THREE.FunctionNode.prototype.eval = function ( src, includes, extensions, keywor
 			this.type = match[ 1 ];
 			this.name = match[ 2 ];
 
-			var inputs = match[ 3 ].match( THREE.FunctionNode.rProperties );
+			var inputs = match[ 3 ].match( FunctionNode.rProperties );
 
 			if ( inputs ) {
 
@@ -199,11 +208,22 @@ THREE.FunctionNode.prototype.eval = function ( src, includes, extensions, keywor
 
 	}
 
-	this.value = src;
+};
 
+FunctionNode.prototype.copy = function ( source ) {
+			
+	TempNode.prototype.copy.call( this, source );
+	
+	this.isMethod = source.isMethod;
+	this.useKeywords = source.useKeywords;
+	
+	this.eval( source.src, source.includes, source.extensions, source.keywords );
+
+	if ( source.type !== undefined ) this.type = source.type;
+	
 };
 
-THREE.FunctionNode.prototype.toJSON = function ( meta ) {
+FunctionNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -211,11 +231,11 @@ THREE.FunctionNode.prototype.toJSON = function ( meta ) {
 
 		data = this.createJSONNode( meta );
 
-		data.src = this.value;
+		data.src = this.src;
 		data.isMethod = this.isMethod;
 		data.useKeywords = this.useKeywords;
 
-		if ( ! this.isMethod ) data.out = this.type;
+		if ( ! this.isMethod ) data.type = this.type;
 
 		data.extensions = JSON.parse( JSON.stringify( this.extensions ) );
 		data.keywords = {};
@@ -243,3 +263,5 @@ THREE.FunctionNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { FunctionNode };

+ 176 - 0
examples/js/nodes/core/GLNode.js

@@ -0,0 +1,176 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+function GLNode( type ) {
+
+	this.uuid = THREE.Math.generateUUID();
+
+	this.name = "";
+
+	this.type = type;
+
+	this.userData = {};
+
+};
+
+GLNode.prototype = {
+
+	constructor: GLNode,
+	
+	isNode: true,
+	
+	parse: function ( builder, settings ) {
+
+		settings = settings || {};
+
+		builder.parsing = true;
+
+		this.build( builder.addCache( settings.cache, settings.requires ).addSlot( settings.slot ), 'v4' );
+
+		builder.clearVertexNodeCode()
+		builder.clearFragmentNodeCode();
+
+		builder.removeCache().removeSlot();
+
+		builder.parsing = false;
+
+	},
+	
+	parseAndBuildCode: function ( builder, output, settings ) {
+
+		settings = settings || {};
+
+		this.parse( builder, settings );
+
+		return this.buildCode( builder, output, settings );
+	
+	},
+	
+	buildCode: function ( builder, output, settings ) {
+
+		settings = settings || {};
+
+		var data = { result: this.build( builder.addCache( settings.cache, settings.context ).addSlot( settings.slot ), output ) };
+
+		data.code = builder.clearNodeCode();
+
+		builder.removeCache().removeSlot();
+
+		return data;
+	
+	},
+
+	build: function ( builder, output, uuid ) {
+
+		output = output || this.getType( builder, output );
+
+		var data = builder.getNodeData( uuid || this );
+
+		if ( builder.parsing ) this.appendDepsNode( builder, data, output );
+
+		if ( builder.nodes.indexOf( this ) === - 1 ) {
+
+			builder.nodes.push( this );
+
+		}
+
+		if ( this.updateFrame !== undefined && builder.updaters.indexOf( this ) === - 1 ) {
+
+			builder.updaters.push( this );
+
+		}
+
+		return this.generate( builder, output, uuid );
+	
+	},
+	
+	appendDepsNode: function ( builder, data, output ) {
+
+		data.deps = ( data.deps || 0 ) + 1;
+
+		var outputLen = builder.getTypeLength( output );
+
+		if ( outputLen > ( data.outputMax || 0 ) || this.getType( builder, output ) ) {
+
+			data.outputMax = outputLen;
+			data.output = output;
+
+		}
+	
+	},
+	
+	setName: function( name ) {
+		
+		this.name = name;
+		
+		return this;
+		
+	},
+	
+	getName: function( builder ) {
+		
+		return this.name;
+		
+	},
+	
+	getType: function ( builder, output ) {
+
+		return output === 'sampler2D' || output === 'samplerCube' ? output : this.type;
+	
+	},
+	
+	getJSONNode: function ( meta ) {
+
+		var isRootObject = ( meta === undefined || typeof meta === 'string' );
+
+		if ( ! isRootObject && meta.nodes[ this.uuid ] !== undefined ) {
+
+			return meta.nodes[ this.uuid ];
+
+		}
+	
+	},
+	
+	copy: function ( source ) {
+
+		if ( source.name !== undefined ) this.name = source.name;
+	
+		if ( source.userData !== undefined ) this.userData = JSON.parse( JSON.stringify( source.userData ) );
+	
+	},
+	
+	createJSONNode: function ( meta ) {
+
+		var isRootObject = ( meta === undefined || typeof meta === 'string' );
+
+		var data = {};
+
+		if ( typeof this.nodeType !== "string" ) throw new Error( "Node does not allow serialization." );
+
+		data.uuid = this.uuid;
+		data.nodeType = this.nodeType;
+
+		if ( this.name !== "" ) data.name = this.name;
+
+		if ( JSON.stringify( this.userData ) !== '{}' ) data.userData = this.userData;
+
+		if ( ! isRootObject ) {
+
+			meta.nodes[ this.uuid ] = data;
+
+		}
+
+		return data;
+	
+	},
+	
+	toJSON: function ( meta ) {
+
+		return this.getJSONNode( meta ) || this.createJSONNode( meta );
+	
+	}
+	
+};
+
+export { GLNode };

+ 85 - 0
examples/js/nodes/core/InputNode.js

@@ -0,0 +1,85 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { TempNode } from './TempNode.js';
+
+function InputNode( type, params ) {
+
+	params = params || {};
+	params.shared = params.shared !== undefined ? params.shared : false;
+
+	TempNode.call( this, type, params );
+
+	this.readonly = false;
+
+};
+
+InputNode.prototype = Object.create( TempNode.prototype );
+InputNode.prototype.constructor = InputNode;
+
+InputNode.prototype.isReadonly = function ( builder ) {
+
+	return this.readonly;
+
+};
+
+InputNode.prototype.copy = function ( source ) {
+	
+	TempNode.prototype.copy.call( this, source );
+	
+	if ( source.readonly !== undefined ) this.readonly = source.readonly;
+	
+};
+
+InputNode.prototype.createJSONNode = function ( meta ) {
+
+	var data = TempNode.prototype.createJSONNode.call( this, meta );
+	
+	if ( this.readonly === true ) data.readonly = this.readonly;
+
+	return data;
+
+};
+
+InputNode.prototype.generate = function ( builder, output, uuid, type, ns, needsUpdate ) {
+
+	uuid = builder.getUuid( uuid || this.getUuid() );
+	type = type || this.getType( builder );
+
+	var data = builder.getNodeData( uuid ),
+		readonly = this.isReadonly( builder ) && this.generateReadonly !== undefined;
+
+	if ( readonly ) {
+
+		return this.generateReadonly( builder, output, uuid, type, ns, needsUpdate );
+
+	} else {
+
+		if ( builder.isShader( 'vertex' ) ) {
+
+			if ( ! data.vertex ) {
+
+				data.vertex = builder.createVertexUniform( type, this, ns, needsUpdate );
+
+			}
+
+			return builder.format( data.vertex.name, type, output );
+
+		} else {
+
+			if ( ! data.fragment ) {
+
+				data.fragment = builder.createFragmentUniform( type, this, ns, needsUpdate );
+
+			}
+
+			return builder.format( data.fragment.name, type, output );
+
+		}
+
+	}
+
+};
+
+export { InputNode };

+ 1007 - 0
examples/js/nodes/core/NodeBuilder.js

@@ -0,0 +1,1007 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { NodeUniform } from './NodeUniform.js';
+import { NodeUtils } from './NodeUtils.js';
+import { NodeLib } from './NodeLib.js';
+import { FunctionNode } from './FunctionNode.js';
+import { ConstNode } from './ConstNode.js';
+import { StructNode } from './StructNode.js';
+import { Vector2Node } from '../inputs/Vector2Node.js';
+import { Vector3Node } from '../inputs/Vector3Node.js';
+import { Vector4Node } from '../inputs/Vector4Node.js';
+import { TextureNode } from '../inputs/TextureNode.js';
+import { CubeTextureNode } from '../inputs/CubeTextureNode.js';
+
+var elements = NodeUtils.elements,
+	constructors = [ 'float', 'vec2', 'vec3', 'vec4' ],
+	convertFormatToType = {
+		float: 'f',
+		vec2: 'v2',
+		vec3: 'v3',
+		vec4: 'v4',
+		mat4: 'v4',
+		int: 'i'
+	},
+	convertTypeToFormat = {
+		t: 'sampler2D',
+		tc: 'samplerCube',
+		b: 'bool',
+		i: 'int',
+		f: 'float',
+		c: 'vec3',
+		v2: 'vec2',
+		v3: 'vec3',
+		v4: 'vec4',
+		m3: 'mat3',
+		m4: 'mat4'
+	};
+ 
+function NodeBuilder() {
+
+	this.caches = [];
+	this.slots = [];
+
+	this.keywords = {};
+	
+	this.nodeData = {};
+	
+	this.requires = {
+		uv: [],
+		color: [],
+		lights: false,
+		fog: false
+	};
+
+	this.includes = {
+		consts: [],
+		functions: [],
+		structs: []
+	};
+	
+	this.attributes = {};
+	
+	this.prefixCode = [
+		"#ifdef GL_EXT_shader_texture_lod",
+
+		"	#define texCube(a, b) textureCube(a, b)",
+		"	#define texCubeBias(a, b, c) textureCubeLodEXT(a, b, c)",
+
+		"	#define tex2D(a, b) texture2D(a, b)",
+		"	#define tex2DBias(a, b, c) texture2DLodEXT(a, b, c)",
+
+		"#else",
+
+		"	#define texCube(a, b) textureCube(a, b)",
+		"	#define texCubeBias(a, b, c) textureCube(a, b, c)",
+
+		"	#define tex2D(a, b) texture2D(a, b)",
+		"	#define tex2DBias(a, b, c) texture2D(a, b, c)",
+
+		"#endif",
+
+		"#include <packing>"
+
+	].join( "\n" );
+	
+	this.parsCode = {
+		vertex: '',
+		fragment: ''
+	};
+	
+	this.code = {
+		vertex: '',
+		fragment: ''
+	};
+	
+	this.nodeCode = {
+		vertex: '',
+		fragment: ''
+	};
+	
+	this.resultCode = {
+		vertex: '',
+		fragment: ''
+	};
+	
+	this.finalCode = {
+		vertex: '',
+		fragment: ''
+	};
+	
+	this.inputs = {
+		uniforms: {
+			list: [],
+			vertex: [],
+			fragment: []
+		},
+		vars: {
+			varying: [],
+			vertex: [],
+			fragment: []
+		}
+	};
+	
+	// send to material
+	
+	this.defines = {};
+	
+	this.uniforms = {};
+	
+	this.extensions = {};
+	
+	this.updaters = [];
+	
+	this.nodes = [];
+	
+	// --
+	
+	this.parsing = false;
+	this.optimize = true;
+
+	this.update();
+
+};
+
+NodeBuilder.prototype = {
+
+	constructor: NodeBuilder,
+
+	build: function( vertex, fragment ) {
+		
+		this.buildShader( 'vertex', vertex );
+		this.buildShader( 'fragment', fragment );
+		
+		if ( this.requires.uv[ 0 ] ) {
+
+			this.addVaryCode( 'varying vec2 vUv;' );
+		
+			this.addVertexFinalCode( 'vUv = uv;' );
+
+		}
+		
+		if ( this.requires.uv[ 1 ] ) {
+
+			this.addVaryCode( 'varying vec2 vUv2;' );
+			this.addVertexParsCode( 'attribute vec2 uv2;' );
+
+			this.addVertexFinalCode( 'vUv2 = uv2;' );
+
+		}
+		
+		if ( this.requires.color[ 0 ] ) {
+
+			this.addVaryCode( 'varying vec4 vColor;' );
+			this.addVertexParsCode( 'attribute vec4 color;' );
+
+			this.addVertexFinalCode( 'vColor = color;' );
+
+		}
+		
+		if ( this.requires.color[ 1 ] ) {
+
+			this.addVaryCode( 'varying vec4 vColor2;' );
+			this.addVertexParsCode( 'attribute vec4 color2;' );
+
+			this.addVertexFinalCode( 'vColor2 = color2;' );
+
+		}
+		
+		if ( this.requires.position ) {
+
+			this.addVaryCode( 'varying vec3 vPosition;' );
+
+			this.addVertexFinalCode( 'vPosition = transformed;' );
+
+		}
+		
+		if ( this.requires.worldPosition ) {
+
+			this.addVaryCode( 'varying vec3 vWPosition;' );
+			
+			this.addVertexFinalCode( 'vWPosition = ( modelMatrix * vec4( transformed, 1.0 ) ).xyz;' );
+
+		}
+		
+		if ( this.requires.normal ) {
+
+			this.addVaryCode( 'varying vec3 vObjectNormal;' );
+
+			this.addVertexFinalCode( 'vObjectNormal = normal;' );
+
+		}
+		
+		if ( this.requires.worldNormal ) {
+
+			this.addVaryCode( 'varying vec3 vWNormal;' );
+
+			this.addVertexFinalCode( 'vWNormal = ( modelMatrix * vec4( objectNormal, 0.0 ) ).xyz;' );
+
+		}
+		
+		return this;
+		
+	},
+	
+	buildShader: function( shader, node ) {
+		
+		this.resultCode[shader] = node.build( this.setShader( shader ), 'v4' );
+		
+	},
+	
+	setMaterial: function( material, renderer ) {
+		
+		this.material = material;
+		this.renderer = renderer;
+		
+		this.requires.lights = material.lights;
+		this.requires.fog = material.fog;
+		
+		return this;
+		
+	},
+	
+	addCache: function ( name, context ) {
+
+		this.caches.push( {
+			name: name || '',
+			context: context || {}
+		} );
+
+		return this.update();
+
+	},
+
+	removeCache: function () {
+
+		this.caches.pop();
+
+		return this.update();
+
+	},
+
+	addSlot: function ( name ) {
+
+		this.slots.push( {
+			name: name || ''
+		} );
+
+		return this.update();
+
+	},
+
+	removeSlot: function () {
+
+		this.slots.pop();
+
+		return this.update();
+
+	},
+
+	
+	addVertexCode: function ( code ) {
+
+		this.addCode( code, 'vertex' );
+
+	},
+
+	addFragmentCode: function ( code ) {
+
+		this.addCode( code, 'fragment' );
+
+	},
+	
+	addCode: function ( code, shader ) {
+
+		this.code[shader || this.shader] += code + '\n';
+
+	},
+	
+	
+	addVertexNodeCode: function ( code ) {
+
+		this.addNodeCode( code, 'vertex' );
+
+	},
+
+	addFragmentNodeCode: function ( code ) {
+
+		this.addNodeCode( code, 'fragment' );
+
+	},
+	
+	addNodeCode: function ( code, shader ) {
+
+		this.nodeCode[shader || this.shader] += code + '\n';
+
+	},
+	
+	clearNodeCode: function ( shader ) {
+
+		shader = shader || this.shader;
+	
+		var code = this.nodeCode[shader];
+		
+		this.nodeCode[shader] = '';
+
+		return code;
+		
+	},
+	
+	clearVertexNodeCode: function (  ) {
+
+		return this.clearNodeCode( 'vertex' );
+
+	},
+	
+	clearFragmentNodeCode: function (  ) {
+
+		return this.clearNodeCode( 'fragment' );
+
+	},
+	
+	addVertexFinalCode: function ( code ) {
+
+		this.addFinalCode( code, 'vertex' );
+
+	},
+
+	addFragmentFinalCode: function ( code ) {
+
+		this.addFinalCode( code, 'fragment' );
+
+	},
+	
+	addFinalCode: function ( code, shader ) {
+
+		this.finalCode[shader || this.shader] += code + '\n';
+
+	},
+	
+	
+	addVertexParsCode: function ( code ) {
+
+		this.addParsCode( code, 'vertex' );
+
+	},
+	
+	addFragmentParsCode: function ( code ) {
+
+		this.addParsCode( code, 'fragment' );
+
+	},
+	
+	addParsCode: function ( code, shader ) {
+
+		this.parsCode[shader || this.shader] += code + '\n';
+
+	},
+	
+	
+	addVaryCode: function ( code ) {
+
+		this.addVertexParsCode( code );
+		this.addFragmentParsCode( code );
+
+	},
+	
+	
+	isCache: function ( name ) {
+
+		var i = this.caches.length;
+
+		while ( i -- ) {
+
+			if ( this.caches[ i ].name === name ) return true;
+
+		}
+
+		return false;
+
+	},
+
+	isSlot: function ( name ) {
+
+		var i = this.slots.length;
+
+		while ( i -- ) {
+
+			if ( this.slots[ i ].name === name ) return true;
+
+		}
+
+		return false;
+
+	},
+
+	update: function () {
+
+		var cache = this.caches[ this.caches.length - 1 ];
+		var slot = this.slots[ this.slots.length - 1 ];
+
+		this.slot = slot ? slot.name : '';
+		this.cache = cache ? cache.name : '';
+		this.context = cache ? cache.context : {};
+
+		return this;
+
+	},
+
+	define: function ( name, value ) {
+
+		this.defines[ name ] = value === undefined ? 1 : value;
+
+	},
+	
+	isDefined: function ( name ) {
+
+		return this.defines[ name ] !== undefined;
+
+	},
+
+	getVar: function ( uuid, type, ns, shader ) {
+
+		shader = shader || 'varying';
+	
+		var vars = this.getVars(shader),
+			data = vars[ uuid ];
+
+		if ( ! data ) {
+
+			var index = vars.length,
+				name = ns ? ns : 'nVv' + index;
+
+			data = { name: name, type: type };
+
+			vars.push( data );
+			vars[ uuid ] = data;
+
+		}
+
+		return data;
+
+	},
+	
+	getTempVar: function ( uuid, type, ns ) {
+
+		return this.getVar( uuid, type, ns, this.shader );
+
+	},
+	
+	getAttribute: function ( name, type ) {
+
+		if ( ! this.attributes[ name ] ) {
+
+			var varying = this.getVar( name, type );
+
+			this.addVertexParsCode( 'attribute ' + type + ' ' + name + ';' );
+			this.addVertexFinalCode( varying.name + ' = ' + name + ';' );
+
+			this.attributes[ name ] = { varying: varying, name: name, type: type };
+
+		}
+
+		return this.attributes[ name ];
+
+	},
+	
+	getCode: function( shader ) {
+		
+		return [
+			this.prefixCode,
+			this.parsCode[ shader ],
+			this.getVarListCode( this.getVars('varying'), 'varying' ),
+			this.getVarListCode( this.inputs.uniforms[shader], 'uniform' ),
+			this.getIncludesCode( 'consts', shader ),
+			this.getIncludesCode( 'structs', shader ),
+			this.getIncludesCode( 'functions', shader ),
+			'void main() {',
+				this.getVarListCode( this.getVars(shader) ),
+				this.code[ shader ], 
+				this.resultCode[ shader ],
+				this.finalCode[ shader ],
+			'}'
+		].join( "\n" );
+		
+	},
+	
+	getVarListCode: function ( vars, prefix ) {
+
+		prefix = prefix || '';
+	
+		var code = '';
+
+		for ( var i = 0, l = vars.length; i < l; ++ i ) {
+
+			var nVar = vars[i],
+				type = nVar.type,
+				name = nVar.name;
+			
+			var formatType = this.getFormatByType( type );
+
+			if ( formatType === undefined ) {
+				
+				throw new Error( "Node pars " + formatType + " not found." );
+				
+			}
+
+			code += prefix + ' ' + formatType + ' ' + name + ';\n';
+
+		}
+
+		return code;
+
+	},
+	
+	getVars: function ( shader ) {
+
+		return this.inputs.vars[ shader || this.shader ];
+
+	},
+	
+	getNodeData: function ( node ) {
+
+		var uuid = node.isNode ? node.uuid : node;
+	
+		return this.nodeData[ uuid ] = this.nodeData[ uuid ] || {};
+
+	},
+	
+	createUniform: function ( shader, type, node, ns, needsUpdate ) {
+
+		var uniforms = this.inputs.uniforms,
+			index = uniforms.list.length;
+
+		var uniform = new NodeUniform( {
+			type: type,
+			name: ns ? ns : 'nVu' + index + '_' + THREE.Math.generateUUID().substr(0, 8),
+			node: node,
+			needsUpdate: needsUpdate
+		} );
+
+		uniforms.list.push( uniform );
+
+		uniforms[shader].push( uniform );
+		uniforms[shader][ uniform.name ] = uniform;
+		
+		this.uniforms[ uniform.name ] = uniform;
+		
+		return uniform;
+
+	},
+	
+	createVertexUniform: function ( type, node, ns, needsUpdate ) {
+
+		return this.createUniform( 'vertex', type, node, ns, needsUpdate );
+
+	},
+	
+	createFragmentUniform: function ( type, node, ns, needsUpdate ) {
+
+		return this.createUniform( 'fragment', type, node, ns, needsUpdate );
+
+	},
+	
+	include: function ( node, parent, source ) {
+
+		var includesStruct;
+
+		node = typeof node === 'string' ? NodeLib.get( node ) : node;
+
+		if ( node instanceof FunctionNode ) {
+
+			includesStruct = this.includes.functions;
+
+		} else if ( node instanceof ConstNode ) {
+
+			includesStruct = this.includes.consts;
+			
+		} else if ( node instanceof StructNode ) {
+
+			includesStruct = this.includes.structs;
+
+		}
+		
+		var includes = includesStruct[ this.shader ] = includesStruct[ this.shader ] || [];
+
+		if (node) {
+		
+			var included = includes[ node.name ];
+
+			if ( ! included ) {
+
+				included = includes[ node.name ] = {
+					node: node,
+					deps: []
+				};
+
+				includes.push( included );
+
+				included.src = node.build( this, 'source' );
+
+			}
+
+			if ( node instanceof FunctionNode && parent && includes[ parent.name ] && includes[ parent.name ].deps.indexOf( node ) == - 1 ) {
+
+				includes[ parent.name ].deps.push( node );
+
+				if ( node.includes && node.includes.length ) {
+
+					var i = 0;
+
+					do {
+
+						this.include( node.includes[ i ++ ], parent );
+
+					} while ( i < node.includes.length );
+
+				}
+
+			}
+
+			if ( source ) {
+
+				included.src = source;
+
+			}
+			
+			return node.name;
+			
+		} else {
+			
+			throw new Error("Include not found.");
+			
+		}
+
+	},
+
+	colorToVectorProperties: function ( color ) {
+
+		return color.replace( 'r', 'x' ).replace( 'g', 'y' ).replace( 'b', 'z' ).replace( 'a', 'w' );
+
+	},
+	
+	colorToVector: function ( color ) {
+
+		return color.replace( /c/g, 'v3' );
+
+	},
+
+	getIncludes: function ( type, shader ) {
+
+		return this.includes[type][shader || this.shader];
+
+	},
+	
+	getIncludesCode: function () {
+
+		function sortByPosition( a, b ) {
+
+			return a.deps.length - b.deps.length;
+
+		}
+
+		return function getIncludesCode( type, shader ) {
+
+			var includes = this.getIncludes( type, shader );
+	
+			if ( ! includes ) return '';
+
+			var code = '', 
+				includes = includes.sort( sortByPosition );
+
+			for ( var i = 0; i < includes.length; i ++ ) {
+
+				if ( includes[ i ].src ) code += includes[ i ].src + '\n';
+
+			}
+
+			return code;
+
+		};
+
+	}(),
+	
+	getConstructorFromLength: function ( len ) {
+
+		return constructors[ len - 1 ];
+
+	},
+
+	isTypeMatrix: function ( format ) {
+
+		return /^m/.test( format );
+
+	},
+
+	getTypeLength: function ( type ) {
+
+		if ( type === 'f' ) return 1;
+	
+		return parseInt( this.colorToVector( type ).substr( 1 ) );
+
+	},
+
+	getTypeFromLength: function ( len ) {
+
+		if ( len === 1 ) return 'f';
+
+		return 'v' + len;
+
+	},
+	
+	findNode: function() {
+		
+		for(var i = 0; i < arguments.length; i++) {
+			
+			var nodeCandidate = arguments[i];
+			
+			if (nodeCandidate !== undefined && nodeCandidate.isNode) {
+				
+				return nodeCandidate;
+				
+			}
+			
+		}
+		
+	},
+	
+	resolve: function() {
+		
+		for(var i = 0; i < arguments.length; i++) {
+			
+			var nodeCandidate = arguments[i];
+			
+			if (nodeCandidate !== undefined) {
+				
+				if (nodeCandidate.isNode) {
+				
+					return nodeCandidate;
+					
+				} else if (nodeCandidate.isTexture) {
+					
+					switch( nodeCandidate.mapping ) {
+					
+						case THREE.CubeReflectionMapping:
+						case THREE.CubeRefractionMapping:
+
+							return new CubeTextureNode( nodeCandidate );
+
+							break;
+						
+						case THREE.CubeUVReflectionMapping:
+						case THREE.CubeUVRefractionMapping:
+
+							return new TextureCubeNode( new TextureNode( nodeCandidate ) );
+
+							break;
+							
+						default:
+						
+							return new TextureNode( nodeCandidate );
+						
+					}
+					
+				} else if (nodeCandidate.isVector2) {
+					
+					return new Vector2Node( nodeCandidate );
+					
+				} else if (nodeCandidate.isVector3) {
+					
+					return new Vector3Node( nodeCandidate );
+					
+				} else if (nodeCandidate.isVector4) {
+					
+					return new Vector4Node( nodeCandidate );
+					
+				}
+				
+			}
+			
+		}
+		
+	},
+
+	format: function ( code, from, to ) {
+
+		var typeToType = this.colorToVector( to + ' = ' + from );
+
+		switch ( typeToType ) {
+
+			case 'f = v2': return code + '.x';
+			case 'f = v3': return code + '.x';
+			case 'f = v4': return code + '.x';
+			case 'f = i': return 'float( ' + code + ' )';
+
+			case 'v2 = f': return 'vec2( ' + code + ' )';
+			case 'v2 = v3': return code + '.xy';
+			case 'v2 = v4': return code + '.xy';
+			case 'v2 = i': return 'vec2( float( ' + code + ' ) )';
+
+			case 'v3 = f': return 'vec3( ' + code + ' )';
+			case 'v3 = v2': return 'vec3( ' + code + ', 0.0 )';
+			case 'v3 = v4': return code + '.xyz';
+			case 'v3 = i': return 'vec2( float( ' + code + ' ) )';
+
+			case 'v4 = f': return 'vec4( ' + code + ' )';
+			case 'v4 = v2': return 'vec4( ' + code + ', 0.0, 1.0 )';
+			case 'v4 = v3': return 'vec4( ' + code + ', 1.0 )';
+			case 'v4 = i': return 'vec4( float( ' + code + ' ) )';
+
+			case 'i = f': return 'int( ' + code + ' )';
+			case 'i = v2': return 'int( ' + code + '.x )';
+			case 'i = v3': return 'int( ' + code + '.x )';
+			case 'i = v4': return 'int( ' + code + '.x )';
+
+		}
+
+		return code;
+
+	},
+
+	getTypeByFormat: function ( format ) {
+
+		return convertFormatToType[ format ] || format;
+
+	},
+	
+	getFormatByType: function ( type ) {
+
+		return convertTypeToFormat[ type ] || type;
+
+	},
+
+	getUuid: function ( uuid, useCache ) {
+
+		useCache = useCache !== undefined ? useCache : true;
+
+		if ( useCache && this.cache ) uuid = this.cache + '-' + uuid;
+
+		return uuid;
+
+	},
+
+	getElementByIndex: function ( index ) {
+
+		return elements[ index ];
+
+	},
+
+	getIndexByElement: function ( elm ) {
+
+		return elements.indexOf( elm );
+
+	},
+
+	isShader: function ( shader ) {
+
+		return this.shader === shader;
+
+	},
+
+	setShader: function ( shader ) {
+
+		this.shader = shader;
+
+		return this;
+
+	},
+	
+	mergeUniform: function ( uniforms ) {
+
+		for ( var name in uniforms ) {
+
+			this.uniforms[ name ] = uniforms[ name ];
+
+		}
+
+	},
+
+	getTexelDecodingFunctionFromTexture: function( code, texture ) {
+
+		var gammaOverrideLinear = this.getTextureEncodingFromMap( texture, this.context.gamma && ( this.renderer ? this.renderer.gammaInput : false ) )
+
+		return this.getTexelDecodingFunction( code, gammaOverrideLinear );
+
+	},
+
+	getTexelDecodingFunction: function( value, encoding ) {
+
+		var components = this.getEncodingComponents( encoding );
+
+		return components[ 0 ] + 'ToLinear' + components[ 1 ].replace( 'value', value );
+
+	},
+
+	getTexelEncodingFunction: function( value, encoding ) {
+
+		var components = this.getEncodingComponents( encoding );
+
+		return 'LinearTo' + components[ 0 ] + components[ 1 ].replace( 'value', value );
+
+	},
+
+	getEncodingComponents: function( encoding ) {
+
+		switch ( encoding ) {
+
+			case THREE.LinearEncoding:
+				return [ 'Linear', '( value )' ];
+			case THREE.sRGBEncoding:
+				return [ 'sRGB', '( value )' ];
+			case THREE.RGBEEncoding:
+				return [ 'RGBE', '( value )' ];
+			case THREE.RGBM7Encoding:
+				return [ 'RGBM', '( value, 7.0 )' ];
+			case THREE.RGBM16Encoding:
+				return [ 'RGBM', '( value, 16.0 )' ];
+			case THREE.RGBDEncoding:
+				return [ 'RGBD', '( value, 256.0 )' ];
+			case THREE.GammaEncoding:
+				return [ 'Gamma', '( value, float( GAMMA_FACTOR ) )' ];
+			default:
+				throw new Error( 'unsupported encoding: ' + encoding );
+
+		}
+
+	},
+
+	getEncodingComponents: function( encoding ) {
+
+		switch ( encoding ) {
+
+			case THREE.LinearEncoding:
+				return [ 'Linear', '( value )' ];
+			case THREE.sRGBEncoding:
+				return [ 'sRGB', '( value )' ];
+			case THREE.RGBEEncoding:
+				return [ 'RGBE', '( value )' ];
+			case THREE.RGBM7Encoding:
+				return [ 'RGBM', '( value, 7.0 )' ];
+			case THREE.RGBM16Encoding:
+				return [ 'RGBM', '( value, 16.0 )' ];
+			case THREE.RGBDEncoding:
+				return [ 'RGBD', '( value, 256.0 )' ];
+			case THREE.GammaEncoding:
+				return [ 'Gamma', '( value, float( GAMMA_FACTOR ) )' ];
+			default:
+				throw new Error( 'unsupported encoding: ' + encoding );
+
+		}
+
+	},
+	
+	getTextureEncodingFromMap: function ( map, gammaOverrideLinear ) {
+
+		var encoding;
+
+		if ( ! map ) {
+
+			encoding = THREE.LinearEncoding;
+
+		} else if ( map.isTexture ) {
+
+			encoding = map.encoding;
+
+		} else if ( map.isWebGLRenderTarget ) {
+
+			console.warn( "THREE.WebGLPrograms.getTextureEncodingFromMap: don't use render targets as textures. Use their .texture property instead." );
+			encoding = map.texture.encoding;
+
+		}
+
+		// add backwards compatibility for WebGLRenderer.gammaInput/gammaOutput parameter, should probably be removed at some point.
+		if ( encoding === THREE.LinearEncoding && gammaOverrideLinear ) {
+
+			encoding = THREE.GammaEncoding;
+
+		}
+
+		return encoding;
+
+	}
+
+};
+
+export { NodeBuilder };

+ 42 - 0
examples/js/nodes/core/NodeFrame.js

@@ -0,0 +1,42 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+function NodeFrame( time ) {
+
+	this.time = time !== undefined ? time : 0;
+
+	this.frameId = 0;
+
+};
+
+NodeFrame.prototype = {
+
+	constructor: NodeFrame,
+
+	update: function ( delta ) {
+
+		++this.frameId;
+
+		this.time += delta;
+		this.delta = delta;
+
+		return this;
+
+	},
+	
+	updateNode: function ( node ) {
+
+		if ( node.frameId === this.frameId ) return this;
+
+		node.updateFrame( this );
+
+		node.frameId = this.frameId;
+
+		return this;
+
+	}
+	
+};
+
+export { NodeFrame };

+ 68 - 0
examples/js/nodes/core/NodeLib.js

@@ -0,0 +1,68 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+var NodeLib = {
+
+	nodes: {},
+	keywords: {},
+
+	add: function ( node ) {
+
+		this.nodes[ node.name ] = node;
+
+	},
+
+	addKeyword: function ( name, callback, cache ) {
+
+		cache = cache !== undefined ? cache : true;
+
+		this.keywords[ name ] = { callback: callback, cache: cache };
+
+	},
+
+	remove: function ( node ) {
+
+		delete this.nodes[ node.name ];
+
+	},
+
+	removeKeyword: function ( name ) {
+
+		delete this.keywords[ name ];
+
+	},
+
+	get: function ( name ) {
+
+		return this.nodes[ name ];
+
+	},
+
+	getKeyword: function ( name, material ) {
+
+		return this.keywords[ name ].callback.call( this, material );
+
+	},
+
+	getKeywordData: function ( name ) {
+
+		return this.keywords[ name ];
+
+	},
+
+	contains: function ( name ) {
+
+		return this.nodes[ name ] != undefined;
+
+	},
+
+	containsKeyword: function ( name ) {
+
+		return this.keywords[ name ] != undefined;
+
+	}
+
+};
+
+export { NodeLib };

+ 9 - 2
examples/js/nodes/NodeUniform.js → examples/js/nodes/core/NodeUniform.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.NodeUniform = function ( params ) {
+function NodeUniform( params ) {
 
 	params = params || {};
 
@@ -13,17 +13,24 @@ THREE.NodeUniform = function ( params ) {
 
 };
 
-Object.defineProperties( THREE.NodeUniform.prototype, {
+Object.defineProperties( NodeUniform.prototype, {
+	
 	value: {
+		
 		get: function () {
 
 			return this.node.value;
 
 		},
+		
 		set: function ( val ) {
 
 			this.node.value = val;
 
 		}
+		
 	}
+	
 } );
+
+export { NodeUniform };

+ 75 - 0
examples/js/nodes/core/NodeUtils.js

@@ -0,0 +1,75 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+var NodeUtils = {
+
+	elements: [ 'x', 'y', 'z', 'w' ],
+
+	addShortcuts: function () {
+
+		function applyShortcut( proxy, property, subProperty ) {
+
+			if ( subProperty ) {
+
+				return {
+					
+					get: function () {
+
+						return this[ proxy ][ property ][ subProperty ];
+
+					},
+					
+					set: function ( val ) {
+
+						this[ proxy ][ property ][ subProperty ] = val;
+
+					}
+					
+				};
+
+			} else {
+
+				return {
+					
+					get: function () {
+
+						return this[ proxy ][ property ];
+
+					},
+					
+					set: function ( val ) {
+
+						this[ proxy ][ property ] = val;
+
+					}
+					
+				};
+
+			}
+
+		}
+
+		return function addShortcuts( proto, proxy, list ) {
+
+			var shortcuts = {};
+
+			for ( var i = 0; i < list.length; ++ i ) {
+
+				var data = list[ i ].split( "." ),
+					property = data[0],
+					subProperty = data[1];
+
+				shortcuts[ property ] = applyShortcut( proxy, property, subProperty );
+
+			}
+
+			Object.defineProperties( proto, shortcuts );
+
+		};
+
+	}()
+	
+};
+
+export { NodeUtils };

+ 107 - 0
examples/js/nodes/core/StructNode.js

@@ -0,0 +1,107 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { TempNode } from './TempNode.js';
+import { FunctionNode } from './FunctionNode.js';
+
+function StructNode( src ) {
+
+	TempNode.call( this);
+
+	this.eval( src );
+
+};
+
+StructNode.rDeclaration = /^struct\s*([a-z_0-9]+)\s*{\s*((.|\n)*?)}/img;
+StructNode.rProperties = /\s*(\w*?)\s*(\w*?)(\=|\;)/img;
+
+StructNode.prototype = Object.create( TempNode.prototype );
+StructNode.prototype.constructor = StructNode;
+StructNode.prototype.nodeType = "Struct";
+
+StructNode.prototype.getType = function ( builder ) {
+
+	return builder.getTypeByFormat( this.name );
+
+};
+
+StructNode.prototype.getInputByName = function ( name ) {
+
+	var i = this.inputs.length;
+
+	while ( i -- ) {
+
+		if ( this.inputs[ i ].name === name )
+			return this.inputs[ i ];
+
+	}
+
+};
+
+StructNode.prototype.generate = function ( builder, output ) {
+
+	if ( output === 'source' ) {
+
+		return this.src + ';';
+
+	} else {
+
+		return builder.format( "(" + src + ")", this.getType( builder ), output );
+
+	}
+
+};
+
+StructNode.prototype.eval = function ( src ) {
+
+	this.src = src || '';
+	
+	this.inputs = [];
+	
+	var declaration = StructNode.rDeclaration.exec( this.src );
+	
+	if (declaration) {
+		
+		var properties = declaration[2], matchType, matchName;
+		
+		while ( matchType = FunctionNode.rProperties.exec( properties ) ) {
+			
+			matchName = FunctionNode.rProperties.exec( properties )[0];
+			
+			this.inputs.push( {
+				name: matchName,
+				type: matchType
+			} );
+			
+		}
+		
+		this.name = declaration[1];
+
+	} else {
+		
+		this.name = '';
+		
+	}
+	
+	this.type = this.name;
+
+};
+
+StructNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.src = this.src;
+
+	}
+
+	return data;
+
+};
+
+export { StructNode };

+ 133 - 0
examples/js/nodes/core/TempNode.js

@@ -0,0 +1,133 @@
+/**
+ * Automatic node cache
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { GLNode } from './GLNode.js';
+
+function TempNode( type, params ) {
+
+	GLNode.call( this, type );
+
+	params = params || {};
+
+	this.shared = params.shared !== undefined ? params.shared : true;
+	this.unique = params.unique !== undefined ? params.unique : false;
+
+};
+
+TempNode.prototype = Object.create( GLNode.prototype );
+TempNode.prototype.constructor = TempNode;
+
+TempNode.prototype.build = function ( builder, output, uuid, ns ) {
+
+	output = output || this.getType( builder );
+
+	if ( this.isShared( builder, output ) ) {
+
+		var isUnique = this.isUnique( builder, output );
+
+		if ( isUnique && this.constructor.uuid === undefined ) {
+
+			this.constructor.uuid = THREE.Math.generateUUID();
+
+		}
+
+		uuid = builder.getUuid( uuid || this.getUuid(), ! isUnique );
+
+		var data = builder.getNodeData( uuid );
+
+		if ( builder.parsing ) {
+
+			if ( data.deps || 0 > 0 ) {
+
+				this.appendDepsNode( builder, data, output );
+
+				return this.generate( builder, type, uuid );
+
+			}
+
+			return GLNode.prototype.build.call( this, builder, output, uuid );
+
+		} else if ( isUnique ) {
+
+			data.name = data.name || GLNode.prototype.build.call( this, builder, output, uuid );
+
+			return data.name;
+
+		} else if ( ! builder.optimize || data.deps == 1 ) {
+
+			return GLNode.prototype.build.call( this, builder, output, uuid );
+
+		}
+
+		uuid = this.getUuid( false );
+
+		var name = this.getTemp( builder, uuid ),
+			type = data.output || this.getType( builder );
+
+		if ( name ) {
+
+			return builder.format( name, type, output );
+
+		} else {
+
+			name = TempNode.prototype.generate.call( this, builder, output, uuid, data.output, ns );
+
+			var code = this.generate( builder, type, uuid );
+
+			builder.addNodeCode( name + ' = ' + code + ';' );
+
+			return builder.format( name, type, output );
+
+		}
+
+	}
+
+	return GLNode.prototype.build.call( this, builder, output, uuid );
+
+};
+
+TempNode.prototype.isShared = function ( builder, output ) {
+
+	return output !== 'sampler2D' && output !== 'samplerCube' && this.shared;
+
+};
+
+TempNode.prototype.isUnique = function ( builder, output ) {
+
+	return this.unique;
+
+};
+
+TempNode.prototype.getUuid = function ( unique ) {
+
+	var uuid = unique || unique == undefined ? this.constructor.uuid || this.uuid : this.uuid;
+
+	if ( typeof this.scope == "string" ) uuid = this.scope + '-' + uuid;
+
+	return uuid;
+
+};
+
+TempNode.prototype.getTemp = function ( builder, uuid ) {
+
+	uuid = uuid || this.uuid;
+
+	var tempVar = builder.getVars()[uuid]
+	
+	return tempVar ? tempVar.name : undefined;
+	
+};
+
+TempNode.prototype.generate = function ( builder, output, uuid, type, ns ) {
+
+	if ( ! this.isShared( builder, output ) ) console.error( "THREE.TempNode is not shared!" );
+
+	uuid = uuid || this.uuid;
+
+	return builder.getTempVar( uuid, type || this.getType( builder ), ns ).name;
+
+};
+
+export { TempNode };

+ 66 - 0
examples/js/nodes/core/VarNode.js

@@ -0,0 +1,66 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { GLNode } from './GLNode.js';
+
+function VarNode( type, value ) {
+
+	GLNode.call( this, type );
+	
+	this.value = value;
+
+};
+
+VarNode.prototype = Object.create( GLNode.prototype );
+VarNode.prototype.constructor = VarNode;
+VarNode.prototype.nodeType = "Var";
+
+VarNode.prototype.getType = function ( builder ) {
+
+	return builder.getTypeByFormat( this.type );
+
+};
+
+VarNode.prototype.generate = function ( builder, output ) {
+
+	var varying = builder.getVar( this.uuid, this.type );
+
+	if ( this.value && builder.isShader( 'vertex' ) ) {
+
+		builder.addNodeCode( varying.name + ' = ' + this.value.build( builder, this.getType( builder ) ) + ';' );
+
+	}
+	
+	return builder.format( varying.name, this.getType( builder ), output );
+
+};
+
+VarNode.prototype.copy = function ( source ) {
+	
+	GLNode.prototype.copy.call( this, source );
+	
+	this.type = source.type;
+	this.value = source.value;
+	
+};
+
+VarNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.type = this.type;
+
+		if ( this.value ) data.value = this.value.toJSON( meta ).uuid;
+
+	}
+
+	return data;
+
+};
+
+export { VarNode };

+ 168 - 0
examples/js/nodes/effects/BlurNode.js

@@ -0,0 +1,168 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { TempNode } from '../core/TempNode.js';
+import { FunctionNode } from '../core/FunctionNode.js';
+import { FloatNode } from '../inputs/FloatNode.js';
+import { Vector2Node } from '../inputs/Vector2Node.js';
+import { UVNode } from '../accessors/UVNode.js';
+
+function BlurNode( value, uv, radius, size ) {
+
+	TempNode.call( this, 'v4' );
+
+	this.value = value;
+	this.uv = uv || new UVNode();
+	this.radius = new Vector2Node( 1, 1 );
+
+	this.size = size;
+
+	this.blurX = true;
+	this.blurY = true;
+
+	this.horizontal = new FloatNode( 1 / 64 );
+	this.vertical = new FloatNode( 1 / 64 );
+
+};
+
+BlurNode.Nodes = (function() {
+	
+	var blurX = new FunctionNode( [
+		"vec4 blurX( sampler2D texture, vec2 uv, float s ) {",
+		"	vec4 sum = vec4( 0.0 );",
+		"	sum += texture2D( texture, vec2( uv.x - 4.0 * s, uv.y ) ) * 0.051;",
+		"	sum += texture2D( texture, vec2( uv.x - 3.0 * s, uv.y ) ) * 0.0918;",
+		"	sum += texture2D( texture, vec2( uv.x - 2.0 * s, uv.y ) ) * 0.12245;",
+		"	sum += texture2D( texture, vec2( uv.x - 1.0 * s, uv.y ) ) * 0.1531;",
+		"	sum += texture2D( texture, vec2( uv.x, uv.y ) ) * 0.1633;",
+		"	sum += texture2D( texture, vec2( uv.x + 1.0 * s, uv.y ) ) * 0.1531;",
+		"	sum += texture2D( texture, vec2( uv.x + 2.0 * s, uv.y ) ) * 0.12245;",
+		"	sum += texture2D( texture, vec2( uv.x + 3.0 * s, uv.y ) ) * 0.0918;",
+		"	sum += texture2D( texture, vec2( uv.x + 4.0 * s, uv.y ) ) * 0.051;",
+		"	return sum;",
+		"}"
+	].join( "\n" ) );
+	
+	var blurY = new FunctionNode( [
+		"vec4 blurY( sampler2D texture, vec2 uv, float s ) {",
+		"	vec4 sum = vec4( 0.0 );",
+		"	sum += texture2D( texture, vec2( uv.x, uv.y - 4.0 * s ) ) * 0.051;",
+		"	sum += texture2D( texture, vec2( uv.x, uv.y - 3.0 * s ) ) * 0.0918;",
+		"	sum += texture2D( texture, vec2( uv.x, uv.y - 2.0 * s ) ) * 0.12245;",
+		"	sum += texture2D( texture, vec2( uv.x, uv.y - 1.0 * s ) ) * 0.1531;",
+		"	sum += texture2D( texture, vec2( uv.x, uv.y ) ) * 0.1633;",
+		"	sum += texture2D( texture, vec2( uv.x, uv.y + 1.0 * s ) ) * 0.1531;",
+		"	sum += texture2D( texture, vec2( uv.x, uv.y + 2.0 * s ) ) * 0.12245;",
+		"	sum += texture2D( texture, vec2( uv.x, uv.y + 3.0 * s ) ) * 0.0918;",
+		"	sum += texture2D( texture, vec2( uv.x, uv.y + 4.0 * s ) ) * 0.051;",
+		"	return sum;",
+		"}"
+	].join( "\n" ) );
+	
+	return {
+		blurX: blurX,
+		blurY: blurY
+	};
+	
+})();
+
+
+BlurNode.prototype = Object.create( TempNode.prototype );
+BlurNode.prototype.constructor = BlurNode;
+BlurNode.prototype.nodeType = "Blur";
+
+BlurNode.prototype.updateFrame = function ( frame ) {
+
+	if ( this.size ) {
+
+		this.horizontal.value = this.radius.x / this.size.x;
+		this.vertical.value = this.radius.y / this.size.y;
+
+	} else if ( this.value.value && this.value.value.image ) {
+
+		var image = this.value.value.image;
+
+		this.horizontal.value = this.radius.x / image.width;
+		this.vertical.value = this.radius.y / image.height;
+
+	}
+
+};
+
+BlurNode.prototype.generate = function ( builder, output ) {
+
+	if ( builder.isShader( 'fragment' ) ) {
+
+		var blurCode = [], code;
+
+		var blurX = builder.include( BlurNode.Nodes.blurX ),
+			blurY = builder.include( BlurNode.Nodes.blurY );
+		
+		if ( this.blurX ) {
+
+			blurCode.push( blurX + '( ' + this.value.build( builder, 'sampler2D' ) + ', ' + this.uv.build( builder, 'v2' ) + ', ' + this.horizontal.build( builder, 'f' ) + ' )' );
+
+		}
+
+		if ( this.blurY ) {
+
+			blurCode.push( blurY + '( ' + this.value.build( builder, 'sampler2D' ) + ', ' + this.uv.build( builder, 'v2' ) + ', ' + this.vertical.build( builder, 'f' ) + ' )' );
+
+		}
+
+		if ( blurCode.length == 2 ) code = '( ' + blurCode.join( ' + ' ) + '/ 2.0 )';
+		else if ( blurCode.length ) code = '( ' + blurCode[ 0 ] + ' )';
+		else code = 'vec4( 0.0 )';
+
+		return builder.format( code, this.getType( builder ), output );
+
+	} else {
+
+		console.warn( "THREE.BlurNode is not compatible with " + builder.shader + " shader." );
+
+		return builder.format( 'vec4( 0.0 )', this.getType( builder ), output );
+
+	}
+
+};
+
+BlurNode.prototype.copy = function ( source ) {
+			
+	TempNode.prototype.copy.call( this, source );
+	
+	this.value = source.value;
+	this.uv = source.uv;
+	this.radius = source.radius;
+
+	if ( source.size !== undefined ) this.size = new THREE.Vector2( source.size.x, source.size.y );
+
+	this.blurX = source.blurX;
+	this.blurY = source.blurY;
+					
+};
+
+BlurNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.value = this.value.toJSON( meta ).uuid;
+		data.uv = this.uv.toJSON( meta ).uuid;
+		data.radius = this.radius.toJSON( meta ).uuid;
+
+		if ( this.size ) data.size = { x: this.size.x, y: this.size.y };
+
+		data.blurX = this.blurX;
+		data.blurY = this.blurY;
+
+	}
+
+	return data;
+
+};
+
+export { BlurNode };

+ 136 - 0
examples/js/nodes/effects/ColorAdjustmentNode.js

@@ -0,0 +1,136 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { TempNode } from '../core/TempNode.js';
+import { FunctionNode } from '../core/FunctionNode.js';
+import { LuminanceNode } from './LuminanceNode.js';
+
+function ColorAdjustmentNode( rgb, adjustment, method ) {
+
+	TempNode.call( this, 'v3' );
+
+	this.rgb = rgb;
+	this.adjustment = adjustment;
+
+	this.method = method || ColorAdjustmentNode.SATURATION;
+
+};
+
+ColorAdjustmentNode.Nodes = (function() {
+	
+	var hue = new FunctionNode( [
+		"vec3 hue(vec3 rgb, float adjustment) {",
+		
+		"	const mat3 RGBtoYIQ = mat3(0.299, 0.587, 0.114, 0.595716, -0.274453, -0.321263, 0.211456, -0.522591, 0.311135);",
+		"	const mat3 YIQtoRGB = mat3(1.0, 0.9563, 0.6210, 1.0, -0.2721, -0.6474, 1.0, -1.107, 1.7046);",
+		
+		"	vec3 yiq = RGBtoYIQ * rgb;",
+		
+		"	float hue = atan(yiq.z, yiq.y) + adjustment;",
+		"	float chroma = sqrt(yiq.z * yiq.z + yiq.y * yiq.y);",
+		
+		"	return YIQtoRGB * vec3(yiq.x, chroma * cos(hue), chroma * sin(hue));",
+		
+		"}"
+	].join( "\n" ) );
+	
+	var saturation = new FunctionNode( [
+		// Algorithm from Chapter 16 of OpenGL Shading Language
+		"vec3 saturation(vec3 rgb, float adjustment) {",
+		
+		"	vec3 intensity = vec3( luminance( rgb ) );",
+		
+		"	return mix( intensity, rgb, adjustment );",
+		
+		"}"
+	].join( "\n" ), [ LuminanceNode.Nodes.luminance ] ); // include LuminanceNode function
+	
+	var vibrance = new FunctionNode( [
+		// Shader by Evan Wallace adapted by @lo-th
+		"vec3 vibrance(vec3 rgb, float adjustment) {",
+		
+		"	float average = (rgb.r + rgb.g + rgb.b) / 3.0;",
+		
+		"	float mx = max(rgb.r, max(rgb.g, rgb.b));",
+		"	float amt = (mx - average) * (-3.0 * adjustment);",
+		
+		"	return mix(rgb.rgb, vec3(mx), amt);",
+		
+		"}"
+	].join( "\n" ) );
+	
+	return {
+		hue: hue,
+		saturation: saturation,
+		vibrance: vibrance
+	};
+	
+})();
+
+ColorAdjustmentNode.SATURATION = 'saturation';
+ColorAdjustmentNode.HUE = 'hue';
+ColorAdjustmentNode.VIBRANCE = 'vibrance';
+ColorAdjustmentNode.BRIGHTNESS = 'brightness';
+ColorAdjustmentNode.CONTRAST = 'contrast';
+
+ColorAdjustmentNode.prototype = Object.create( TempNode.prototype );
+ColorAdjustmentNode.prototype.constructor = ColorAdjustmentNode;
+ColorAdjustmentNode.prototype.nodeType = "ColorAdjustment";
+
+ColorAdjustmentNode.prototype.generate = function ( builder, output ) {
+
+	var rgb = this.rgb.build( builder, 'v3' ),
+		adjustment = this.adjustment.build( builder, 'f' );
+
+	switch ( this.method ) {
+
+		case ColorAdjustmentNode.BRIGHTNESS:
+
+			return builder.format( '( ' + rgb + ' + ' + adjustment + ' )', this.getType( builder ), output );
+
+			break;
+
+		case ColorAdjustmentNode.CONTRAST:
+
+			return builder.format( '( ' + rgb + ' * ' + adjustment + ' )', this.getType( builder ), output );
+
+			break;
+
+	}
+
+	var method = builder.include( ColorAdjustmentNode.Nodes[this.method] );
+
+	return builder.format( method + '( ' + rgb + ', ' + adjustment + ' )', this.getType( builder ), output );
+
+};
+
+ColorAdjustmentNode.prototype.copy = function ( source ) {
+			
+	TempNode.prototype.copy.call( this, source );
+	
+	this.rgb = source.rgb;
+	this.adjustment = source.adjustment;
+	this.method = source.method;
+
+};
+
+ColorAdjustmentNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.rgb = this.rgb.toJSON( meta ).uuid;
+		data.adjustment = this.adjustment.toJSON( meta ).uuid;
+		data.method = this.method;
+
+	}
+
+	return data;
+
+};
+
+export { ColorAdjustmentNode };

+ 73 - 0
examples/js/nodes/effects/LuminanceNode.js

@@ -0,0 +1,73 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { TempNode } from '../core/TempNode.js';
+import { ConstNode } from '../core/ConstNode.js';
+import { FunctionNode } from '../core/FunctionNode.js';
+
+function LuminanceNode( rgb ) {
+
+	TempNode.call( this, 'f' );
+
+	this.rgb = rgb;
+
+};
+
+LuminanceNode.Nodes = (function() {
+	
+	var LUMA = new ConstNode( "vec3 LUMA vec3( 0.2125, 0.7154, 0.0721 )" );
+
+	var luminance = new FunctionNode( [
+		// Algorithm from Chapter 10 of Graphics Shaders
+		"float luminance( vec3 rgb ) {",
+		
+		"	return dot( rgb, LUMA );",
+		
+		"}"
+	].join( "\n" ), [ LUMA ] );
+
+	return {
+		LUMA: LUMA,
+		luminance: luminance
+	};
+	
+})();
+
+LuminanceNode.prototype = Object.create( TempNode.prototype );
+LuminanceNode.prototype.constructor = LuminanceNode;
+LuminanceNode.prototype.nodeType = "Luminance";
+
+LuminanceNode.prototype.generate = function ( builder, output ) {
+
+	var luminance = builder.include( LuminanceNode.Nodes.luminance );
+
+	return builder.format( luminance + '( ' + this.rgb.build( builder, 'v3' ) + ' )', this.getType( builder ), output );
+
+};
+
+LuminanceNode.prototype.copy = function ( source ) {
+			
+	TempNode.prototype.copy.call( this, source );
+	
+	this.rgb = source.rgb;
+	
+};
+
+LuminanceNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.rgb = this.rgb.toJSON( meta ).uuid;
+
+	}
+
+	return data;
+
+};
+
+export { LuminanceNode };

+ 22 - 9
examples/js/nodes/inputs/ColorNode.js

@@ -2,27 +2,38 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.ColorNode = function ( color ) {
+import { InputNode } from '../core/InputNode.js';
+import { NodeUtils } from '../core/NodeUtils.js';
 
-	THREE.InputNode.call( this, 'c' );
+function ColorNode( color, g, b ) {
 
-	this.value = new THREE.Color( color || 0 );
+	InputNode.call( this, 'c' );
+
+	this.value = color instanceof THREE.Color ? color : new THREE.Color( color || 0, g, b );
 
 };
 
-THREE.ColorNode.prototype = Object.create( THREE.InputNode.prototype );
-THREE.ColorNode.prototype.constructor = THREE.ColorNode;
-THREE.ColorNode.prototype.nodeType = "Color";
+ColorNode.prototype = Object.create( InputNode.prototype );
+ColorNode.prototype.constructor = ColorNode;
+ColorNode.prototype.nodeType = "Color";
 
-THREE.NodeMaterial.addShortcuts( THREE.ColorNode.prototype, 'value', [ 'r', 'g', 'b' ] );
+NodeUtils.addShortcuts( ColorNode.prototype, 'value', [ 'r', 'g', 'b' ] );
 
-THREE.ColorNode.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
+ColorNode.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
 
 	return builder.format( "vec3( " + this.r + ", " + this.g + ", " + this.b + " )", type, output );
 
 };
 
-THREE.ColorNode.prototype.toJSON = function ( meta ) {
+ColorNode.prototype.copy = function ( source ) {
+			
+	InputNode.prototype.copy.call( this, source );
+	
+	this.value.copy( source );
+	
+};
+
+ColorNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -41,3 +52,5 @@ THREE.ColorNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { ColorNode };

+ 33 - 28
examples/js/nodes/inputs/CubeTextureNode.js

@@ -2,27 +2,30 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.CubeTextureNode = function ( value, coord, bias ) {
+import { InputNode } from '../core/InputNode.js';
+import { ReflectNode } from '../accessors/ReflectNode.js';
 
-	THREE.InputNode.call( this, 'v4', { shared: true } );
+function CubeTextureNode( value, uv, bias ) {
+
+	InputNode.call( this, 'v4', { shared: true } );
 
 	this.value = value;
-	this.coord = coord || new THREE.ReflectNode();
+	this.uv = uv || new ReflectNode();
 	this.bias = bias;
 
 };
 
-THREE.CubeTextureNode.prototype = Object.create( THREE.InputNode.prototype );
-THREE.CubeTextureNode.prototype.constructor = THREE.CubeTextureNode;
-THREE.CubeTextureNode.prototype.nodeType = "CubeTexture";
+CubeTextureNode.prototype = Object.create( InputNode.prototype );
+CubeTextureNode.prototype.constructor = CubeTextureNode;
+CubeTextureNode.prototype.nodeType = "CubeTexture";
 
-THREE.CubeTextureNode.prototype.getTexture = function ( builder, output ) {
+CubeTextureNode.prototype.getTexture = function ( builder, output ) {
 
-	return THREE.InputNode.prototype.generate.call( this, builder, output, this.value.uuid, 't' );
+	return InputNode.prototype.generate.call( this, builder, output, this.value.uuid, 'tc' );
 
 };
 
-THREE.CubeTextureNode.prototype.generate = function ( builder, output ) {
+CubeTextureNode.prototype.generate = function ( builder, output ) {
 
 	if ( output === 'samplerCube' ) {
 
@@ -31,39 +34,39 @@ THREE.CubeTextureNode.prototype.generate = function ( builder, output ) {
 	}
 
 	var cubetex = this.getTexture( builder, output );
-	var coord = this.coord.build( builder, 'v3' );
-	var bias = this.bias ? this.bias.build( builder, 'fv1' ) : undefined;
+	var uv = this.uv.build( builder, 'v3' );
+	var bias = this.bias ? this.bias.build( builder, 'f' ) : undefined;
 
-	if ( bias == undefined && builder.requires.bias ) {
+	if ( bias === undefined && builder.context.bias ) {
 
-		bias = builder.requires.bias.build( builder, 'fv1' );
+		bias = new builder.context.bias( this ).build( builder, 'f' );
 
 	}
 
 	var code;
 
-	if ( bias ) code = 'texCubeBias(' + cubetex + ',' + coord + ',' + bias + ')';
-	else code = 'texCube(' + cubetex + ',' + coord + ')';
-
-	if ( builder.isSlot( 'color' ) ) {
-
-		code = 'mapTexelToLinear(' + code + ')';
+	if ( bias ) code = 'texCubeBias( ' + cubetex + ', ' + uv + ', ' + bias + ' )';
+	else code = 'texCube( ' + cubetex + ', ' + uv + ' )';
 
-	} else if ( builder.isSlot( 'emissive' ) ) {
+	code = builder.getTexelDecodingFunctionFromTexture( code, this.value );
 
-		code = 'emissiveMapTexelToLinear(' + code + ')';
-
-	} else if ( builder.isSlot( 'environment' ) ) {
+	return builder.format( code, this.type, output );
 
-		code = 'envMapTexelToLinear(' + code + ')';
+};
 
-	}
+CubeTextureNode.prototype.copy = function ( source ) {
+			
+	InputNode.prototype.copy.call( this, source );
+	
+	if ( source.value ) this.value = source.value;
 
-	return builder.format( code, this.type, output );
+	this.uv = source.uv;
 
+	if ( source.bias ) this.bias = source.bias;
+	
 };
 
-THREE.CubeTextureNode.prototype.toJSON = function ( meta ) {
+CubeTextureNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -72,7 +75,7 @@ THREE.CubeTextureNode.prototype.toJSON = function ( meta ) {
 		data = this.createJSONNode( meta );
 
 		data.value = this.value.uuid;
-		data.coord = this.coord.toJSON( meta ).uuid;
+		data.uv = this.uv.toJSON( meta ).uuid;
 
 		if ( this.bias ) data.bias = this.bias.toJSON( meta ).uuid;
 
@@ -81,3 +84,5 @@ THREE.CubeTextureNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { CubeTextureNode };

+ 19 - 9
examples/js/nodes/inputs/FloatNode.js

@@ -2,27 +2,35 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.FloatNode = function ( value ) {
+import { InputNode } from '../core/InputNode.js';
 
-	THREE.InputNode.call( this, 'fv1' );
+function FloatNode( value ) {
+
+	InputNode.call( this, 'f' );
 
 	this.value = value || 0;
 
 };
 
-THREE.FloatNode.prototype = Object.create( THREE.InputNode.prototype );
-THREE.FloatNode.prototype.constructor = THREE.FloatNode;
-THREE.FloatNode.prototype.nodeType = "Float";
+FloatNode.prototype = Object.create( InputNode.prototype );
+FloatNode.prototype.constructor = FloatNode;
+FloatNode.prototype.nodeType = "Float";
 
-THREE.FloatNode.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
+FloatNode.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
 
-	var val = this.value;
+	return builder.format( this.value + ( this.value % 1 ? '' : '.0' ), type, output );
 
-	return builder.format( Math.floor( val ) !== val ? val : val + ".0", type, output );
+};
 
+FloatNode.prototype.copy = function ( source ) {
+			
+	InputNode.prototype.copy.call( this, source );
+	
+	this.value = source.value;
+	
 };
 
-THREE.FloatNode.prototype.toJSON = function ( meta ) {
+FloatNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -39,3 +47,5 @@ THREE.FloatNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { FloatNode };

+ 19 - 7
examples/js/nodes/inputs/IntNode.js

@@ -2,25 +2,35 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.IntNode = function ( value ) {
+import { InputNode } from '../core/InputNode.js';
 
-	THREE.InputNode.call( this, 'iv1' );
+function IntNode( value ) {
+
+	InputNode.call( this, 'i' );
 
 	this.value = Math.floor( value || 0 );
 
 };
 
-THREE.IntNode.prototype = Object.create( THREE.InputNode.prototype );
-THREE.IntNode.prototype.constructor = THREE.IntNode;
-THREE.IntNode.prototype.nodeType = "Int";
+IntNode.prototype = Object.create( InputNode.prototype );
+IntNode.prototype.constructor = IntNode;
+IntNode.prototype.nodeType = "Int";
 
-THREE.IntNode.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
+IntNode.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
 
 	return builder.format( this.value, type, output );
 
 };
 
-THREE.IntNode.prototype.toJSON = function ( meta ) {
+IntNode.prototype.copy = function ( source ) {
+			
+	InputNode.prototype.copy.call( this, source );
+	
+	this.value = source.value;
+	
+};
+
+IntNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -37,3 +47,5 @@ THREE.IntNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { IntNode };

+ 40 - 9
examples/js/nodes/inputs/Matrix3Node.js

@@ -2,25 +2,56 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.Matrix3Node = function ( matrix ) {
+import { InputNode } from '../core/InputNode.js';
 
-	THREE.InputNode.call( this, 'm3' );
+function Matrix3Node( matrix ) {
+
+	InputNode.call( this, 'm3' );
 
 	this.value = matrix || new THREE.Matrix3();
 
 };
 
-THREE.Matrix3Node.prototype = Object.create( THREE.InputNode.prototype );
-THREE.Matrix3Node.prototype.constructor = THREE.Matrix3Node;
-THREE.Matrix3Node.prototype.nodeType = "Matrix3";
+Matrix3Node.prototype = Object.create( InputNode.prototype );
+Matrix3Node.prototype.constructor = Matrix3Node;
+Matrix3Node.prototype.nodeType = "Matrix3";
+
+Object.defineProperties( Matrix3Node.prototype, {
+
+	elements: {
+		
+		set: function (val) {
+
+			this.value.elements = val;
+
+		},
+		
+		get: function () {
+
+			return this.value.elements;
+
+		}
+		
+	}
+
+} );
 
-THREE.Matrix3Node.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
+Matrix3Node.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
 
 	return builder.format( "mat3( " + this.value.elements.join( ", " ) + " )", type, output );
 
 };
 
-THREE.Matrix3Node.prototype.toJSON = function ( meta ) {
+
+Matrix3Node.prototype.copy = function ( source ) {
+			
+	InputNode.prototype.copy.call( this, source );
+	
+	this.value.fromArray( source.elements );
+	
+};
+
+Matrix3Node.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -30,10 +61,10 @@ THREE.Matrix3Node.prototype.toJSON = function ( meta ) {
 
 		data.elements = this.value.elements.concat();
 
-		if ( this.readonly === true ) data.readonly = true;
-
 	}
 
 	return data;
 
 };
+
+export { Matrix3Node };

+ 39 - 9
examples/js/nodes/inputs/Matrix4Node.js

@@ -2,25 +2,55 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.Matrix4Node = function ( matrix ) {
+import { InputNode } from '../core/InputNode.js';
 
-	THREE.InputNode.call( this, 'm4' );
+function Matrix4Node( matrix ) {
+
+	InputNode.call( this, 'm4' );
 
 	this.value = matrix || new THREE.Matrix4();
 
 };
 
-THREE.Matrix4Node.prototype = Object.create( THREE.InputNode.prototype );
-THREE.Matrix4Node.prototype.constructor = THREE.Matrix4Node;
-THREE.Matrix4Node.prototype.nodeType = "Matrix4";
+Matrix4Node.prototype = Object.create( InputNode.prototype );
+Matrix4Node.prototype.constructor = Matrix4Node;
+Matrix4Node.prototype.nodeType = "Matrix4";
+
+Object.defineProperties( Matrix4Node.prototype, {
+
+	elements: {
+		
+		set: function (val) {
+
+			this.value.elements = val;
 
-THREE.Matrix4Node.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
+		},
+		
+		get: function () {
+
+			return this.value.elements;
+
+		}
+		
+	}
+
+} );
+
+Matrix4Node.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
 
 	return builder.format( "mat4( " + this.value.elements.join( ", " ) + " )", type, output );
 
 };
 
-THREE.Matrix4Node.prototype.toJSON = function ( meta ) {
+Matrix4Node.prototype.copy = function ( source ) {
+			
+	InputNode.prototype.copy.call( this, source );
+	
+	this.scope.value.fromArray( source.elements );
+	
+};
+
+Matrix4Node.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -30,10 +60,10 @@ THREE.Matrix4Node.prototype.toJSON = function ( meta ) {
 
 		data.elements = this.value.elements.concat();
 
-		if ( this.readonly === true ) data.readonly = true;
-
 	}
 
 	return data;
 
 };
+
+export { Matrix4Node };

+ 57 - 0
examples/js/nodes/inputs/PropertyNode.js

@@ -0,0 +1,57 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { InputNode } from '../core/InputNode.js';
+ 
+function PropertyNode( object, property, type ) {
+
+	InputNode.call( this, type );
+	
+	this.object = object;
+	this.property = property;
+
+};
+
+PropertyNode.prototype = Object.create( InputNode.prototype );
+PropertyNode.prototype.constructor = PropertyNode;
+PropertyNode.prototype.nodeType = "Property";
+
+Object.defineProperties( PropertyNode.prototype, {
+
+	value: {
+		
+		get: function () {
+
+			return this.object[ this.property ];
+
+		},
+		
+		set: function ( val ) { 
+		
+			this.object[ this.property ] = val;
+		
+		}
+		
+	}
+
+} );
+
+PropertyNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.value = this.value;
+		data.property = this.property;
+
+	}
+
+	return data;
+
+};
+
+export { PropertyNode };

+ 37 - 19
examples/js/nodes/inputs/ReflectorNode.js

@@ -1,38 +1,46 @@
-THREE.ReflectorNode = function ( mirror ) {
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
 
-	THREE.TempNode.call( this, 'v4' );
+import { TempNode } from '../core/TempNode.js';
+import { PositionNode } from '../accessors/PositionNode.js';
+import { OperatorNode } from '../math/OperatorNode.js';
+import { TextureNode } from './TextureNode.js';
+import { Matrix4Node } from './Matrix4Node.js';
+
+function ReflectorNode( mirror ) {
+
+	TempNode.call( this, 'v4' );
 
 	if ( mirror ) this.setMirror( mirror );
 
 };
 
-THREE.ReflectorNode.prototype = Object.create( THREE.TempNode.prototype );
-THREE.ReflectorNode.prototype.constructor = THREE.ReflectorNode;
-THREE.ReflectorNode.prototype.nodeType = "Reflector";
+ReflectorNode.prototype = Object.create( TempNode.prototype );
+ReflectorNode.prototype.constructor = ReflectorNode;
+ReflectorNode.prototype.nodeType = "Reflector";
 
-THREE.ReflectorNode.prototype.setMirror = function ( mirror ) {
+ReflectorNode.prototype.setMirror = function ( mirror ) {
 
 	this.mirror = mirror;
 
-	this.textureMatrix = new THREE.Matrix4Node( this.mirror.material.uniforms.textureMatrix.value );
+	this.textureMatrix = new Matrix4Node( this.mirror.material.uniforms.textureMatrix.value );
 
-	this.localPosition = new THREE.PositionNode( THREE.PositionNode.LOCAL );
+	this.localPosition = new PositionNode( PositionNode.LOCAL );
 
-	this.coord = new THREE.OperatorNode( this.textureMatrix, this.localPosition, THREE.OperatorNode.MUL );
-	this.coordResult = new THREE.OperatorNode( null, this.coord, THREE.OperatorNode.ADD );
+	this.uv = new OperatorNode( this.textureMatrix, this.localPosition, OperatorNode.MUL );
+	this.uvResult = new OperatorNode( null, this.uv, OperatorNode.ADD );
 
-	this.texture = new THREE.TextureNode( this.mirror.material.uniforms.tDiffuse.value, this.coord, null, true );
+	this.texture = new TextureNode( this.mirror.material.uniforms.tDiffuse.value, this.uv, null, true );
 
 };
 
-THREE.ReflectorNode.prototype.generate = function ( builder, output ) {
-
-	var material = builder.material;
-
+ReflectorNode.prototype.generate = function ( builder, output ) {
+	
 	if ( builder.isShader( 'fragment' ) ) {
 
-		this.coordResult.a = this.offset;
-		this.texture.coord = this.offset ? this.coordResult : this.coord;
+		this.uvResult.a = this.offset;
+		this.texture.uv = this.offset ? this.uvResult : this.uv;
 
 		if ( output === 'sampler2D' ) {
 
@@ -46,13 +54,21 @@ THREE.ReflectorNode.prototype.generate = function ( builder, output ) {
 
 		console.warn( "THREE.ReflectorNode is not compatible with " + builder.shader + " shader." );
 
-		return builder.format( 'vec4(0.0)', this.type, output );
+		return builder.format( 'vec4( 0.0 )', this.type, output );
 
 	}
 
 };
 
-THREE.ReflectorNode.prototype.toJSON = function ( meta ) {
+ReflectorNode.prototype.copy = function ( source ) {
+			
+	InputNode.prototype.copy.call( this, source );
+	
+	this.scope.mirror = source.mirror;
+
+};
+
+ReflectorNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -69,3 +85,5 @@ THREE.ReflectorNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { ReflectorNode };

+ 13 - 8
examples/js/nodes/inputs/ScreenNode.js

@@ -2,24 +2,29 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.ScreenNode = function ( coord ) {
+import { InputNode } from '../core/InputNode.js';
+import { TextureNode } from './TextureNode.js';
 
-	THREE.TextureNode.call( this, undefined, coord );
+function ScreenNode( uv ) {
+
+	TextureNode.call( this, undefined, uv );
 
 };
 
-THREE.ScreenNode.prototype = Object.create( THREE.TextureNode.prototype );
-THREE.ScreenNode.prototype.constructor = THREE.ScreenNode;
-THREE.ScreenNode.prototype.nodeType = "Screen";
+ScreenNode.prototype = Object.create( TextureNode.prototype );
+ScreenNode.prototype.constructor = ScreenNode;
+ScreenNode.prototype.nodeType = "Screen";
 
-THREE.ScreenNode.prototype.isUnique = function () {
+ScreenNode.prototype.isUnique = function () {
 
 	return true;
 
 };
 
-THREE.ScreenNode.prototype.getTexture = function ( builder, output ) {
+ScreenNode.prototype.getTexture = function ( builder, output ) {
 
-	return THREE.InputNode.prototype.generate.call( this, builder, output, this.getUuid(), 't', 'renderTexture' );
+	return InputNode.prototype.generate.call( this, builder, output, this.getUuid(), 't', 'renderTexture' );
 
 };
+
+export { ScreenNode };

+ 36 - 29
examples/js/nodes/inputs/TextureNode.js

@@ -2,28 +2,32 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.TextureNode = function ( value, coord, bias, project ) {
+import { InputNode } from '../core/InputNode.js';
+import { NodeBuilder } from '../core/NodeBuilder.js';
+import { UVNode } from '../accessors/UVNode.js';
 
-	THREE.InputNode.call( this, 'v4', { shared: true } );
+function TextureNode( value, uv, bias, project ) {
+
+	InputNode.call( this, 'v4', { shared: true } );
 
 	this.value = value;
-	this.coord = coord || new THREE.UVNode();
+	this.uv = uv || new UVNode();
 	this.bias = bias;
 	this.project = project !== undefined ? project : false;
 
 };
 
-THREE.TextureNode.prototype = Object.create( THREE.InputNode.prototype );
-THREE.TextureNode.prototype.constructor = THREE.TextureNode;
-THREE.TextureNode.prototype.nodeType = "Texture";
+TextureNode.prototype = Object.create( InputNode.prototype );
+TextureNode.prototype.constructor = TextureNode;
+TextureNode.prototype.nodeType = "Texture";
 
-THREE.TextureNode.prototype.getTexture = function ( builder, output ) {
+TextureNode.prototype.getTexture = function ( builder, output ) {
 
-	return THREE.InputNode.prototype.generate.call( this, builder, output, this.value.uuid, 't' );
+	return InputNode.prototype.generate.call( this, builder, output, this.value.uuid, 't' );
 
 };
 
-THREE.TextureNode.prototype.generate = function ( builder, output ) {
+TextureNode.prototype.generate = function ( builder, output ) {
 
 	if ( output === 'sampler2D' ) {
 
@@ -31,13 +35,13 @@ THREE.TextureNode.prototype.generate = function ( builder, output ) {
 
 	}
 
-	var tex = this.getTexture( builder, output );
-	var coord = this.coord.build( builder, this.project ? 'v4' : 'v2' );
-	var bias = this.bias ? this.bias.build( builder, 'fv1' ) : undefined;
+	var tex = this.getTexture( builder, output ),
+		uv = this.uv.build( builder, this.project ? 'v4' : 'v2' ),
+		bias = this.bias ? this.bias.build( builder, 'f' ) : undefined;
 
-	if ( bias == undefined && builder.requires.bias ) {
+	if ( bias == undefined && builder.context.bias ) {
 
-		bias = builder.requires.bias.build( builder, 'fv1' );
+		bias = new builder.context.bias( this ).build( builder, 'f' );
 
 	}
 
@@ -46,28 +50,29 @@ THREE.TextureNode.prototype.generate = function ( builder, output ) {
 	if ( this.project ) method = 'texture2DProj';
 	else method = bias ? 'tex2DBias' : 'tex2D';
 
-	if ( bias ) code = method + '(' + tex + ',' + coord + ',' + bias + ')';
-	else code = method + '(' + tex + ',' + coord + ')';
-
-	if ( builder.isSlot( 'color' ) ) {
-
-		code = 'mapTexelToLinear(' + code + ')';
+	if ( bias ) code = method + '( ' + tex + ', ' + uv + ', ' + bias + ' )';
+	else code = method + '( ' + tex + ', ' + uv + ' )';
 
-	} else if ( builder.isSlot( 'emissive' ) ) {
+	code = builder.getTexelDecodingFunctionFromTexture( code, this.value );
 
-		code = 'emissiveMapTexelToLinear(' + code + ')';
-
-	} else if ( builder.isSlot( 'environment' ) ) {
+	return builder.format( code, this.type, output );
 
-		code = 'envMapTexelToLinear(' + code + ')';
+};
 
-	}
+TextureNode.prototype.copy = function ( source ) {
+			
+	InputNode.prototype.copy.call( this, source );
+	
+	if ( source.value ) this.value = source.value;
 
-	return builder.format( code, this.type, output );
+	this.uv = source.uv;
 
+	if ( source.bias ) this.bias = source.bias;
+	if ( source.project !== undefined ) this.project = source.project;
+	
 };
 
-THREE.TextureNode.prototype.toJSON = function ( meta ) {
+TextureNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -77,7 +82,7 @@ THREE.TextureNode.prototype.toJSON = function ( meta ) {
 
 		if ( this.value ) data.value = this.value.uuid;
 
-		data.coord = this.coord.toJSON( meta ).uuid;
+		data.uv = this.uv.toJSON( meta ).uuid;
 		data.project = this.project;
 
 		if ( this.bias ) data.bias = this.bias.toJSON( meta ).uuid;
@@ -87,3 +92,5 @@ THREE.TextureNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { TextureNode };

+ 22 - 9
examples/js/nodes/inputs/Vector2Node.js

@@ -2,27 +2,38 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.Vector2Node = function ( x, y ) {
+import { InputNode } from '../core/InputNode.js';
+import { NodeUtils } from '../core/NodeUtils.js';
 
-	THREE.InputNode.call( this, 'v2' );
+function Vector2Node( x, y ) {
 
-	this.value = new THREE.Vector2( x, y );
+	InputNode.call( this, 'v2' );
+
+	this.value = x instanceof THREE.Vector2 ? x : new THREE.Vector2( x, y );
 
 };
 
-THREE.Vector2Node.prototype = Object.create( THREE.InputNode.prototype );
-THREE.Vector2Node.prototype.constructor = THREE.Vector2Node;
-THREE.Vector2Node.prototype.nodeType = "Vector2";
+Vector2Node.prototype = Object.create( InputNode.prototype );
+Vector2Node.prototype.constructor = Vector2Node;
+Vector2Node.prototype.nodeType = "Vector2";
 
-THREE.NodeMaterial.addShortcuts( THREE.Vector2Node.prototype, 'value', [ 'x', 'y' ] );
+NodeUtils.addShortcuts( Vector2Node.prototype, 'value', [ 'x', 'y' ] );
 
-THREE.Vector2Node.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
+Vector2Node.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
 
 	return builder.format( "vec2( " + this.x + ", " + this.y + " )", type, output );
 
 };
 
-THREE.Vector2Node.prototype.toJSON = function ( meta ) {
+Vector2Node.prototype.copy = function ( source ) {
+			
+	InputNode.prototype.copy.call( this, source );
+	
+	this.value.copy( source );
+
+};
+
+Vector2Node.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -40,3 +51,5 @@ THREE.Vector2Node.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { Vector2Node };

+ 22 - 10
examples/js/nodes/inputs/Vector3Node.js

@@ -2,28 +2,38 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.Vector3Node = function ( x, y, z ) {
+import { InputNode } from '../core/InputNode.js';
+import { NodeUtils } from '../core/NodeUtils.js';
 
-	THREE.InputNode.call( this, 'v3' );
+function Vector3Node( x, y, z ) {
 
-	this.type = 'v3';
-	this.value = new THREE.Vector3( x, y, z );
+	InputNode.call( this, 'v3' );
+
+	this.value = x instanceof THREE.Vector3 ? x : new THREE.Vector3( x, y, z );
 
 };
 
-THREE.Vector3Node.prototype = Object.create( THREE.InputNode.prototype );
-THREE.Vector3Node.prototype.constructor = THREE.Vector3Node;
-THREE.Vector3Node.prototype.nodeType = "Vector3";
+Vector3Node.prototype = Object.create( InputNode.prototype );
+Vector3Node.prototype.constructor = Vector3Node;
+Vector3Node.prototype.nodeType = "Vector3";
 
-THREE.NodeMaterial.addShortcuts( THREE.Vector3Node.prototype, 'value', [ 'x', 'y', 'z' ] );
+NodeUtils.addShortcuts( Vector3Node.prototype, 'value', [ 'x', 'y', 'z' ] );
 
-THREE.Vector3Node.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
+Vector3Node.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
 
 	return builder.format( "vec3( " + this.x + ", " + this.y + ", " + this.z + " )", type, output );
 
 };
 
-THREE.Vector3Node.prototype.toJSON = function ( meta ) {
+Vector3Node.prototype.copy = function ( source ) {
+			
+	InputNode.prototype.copy.call( this, source );
+	
+	this.value.copy( source );
+	
+};
+
+Vector3Node.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -42,3 +52,5 @@ THREE.Vector3Node.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { Vector3Node };

+ 22 - 9
examples/js/nodes/inputs/Vector4Node.js

@@ -2,27 +2,38 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.Vector4Node = function ( x, y, z, w ) {
+import { InputNode } from '../core/InputNode.js';
+import { NodeUtils } from '../core/NodeUtils.js';
 
-	THREE.InputNode.call( this, 'v4' );
+function Vector4Node( x, y, z, w ) {
 
-	this.value = new THREE.Vector4( x, y, z, w );
+	InputNode.call( this, 'v4' );
+
+	this.value = x instanceof THREE.Vector4 ? x : new THREE.Vector4( x, y, z, w );
 
 };
 
-THREE.Vector4Node.prototype = Object.create( THREE.InputNode.prototype );
-THREE.Vector4Node.prototype.constructor = THREE.Vector4Node;
-THREE.Vector4Node.prototype.nodeType = "Vector4";
+Vector4Node.prototype = Object.create( InputNode.prototype );
+Vector4Node.prototype.constructor = Vector4Node;
+Vector4Node.prototype.nodeType = "Vector4";
 
-THREE.NodeMaterial.addShortcuts( THREE.Vector4Node.prototype, 'value', [ 'x', 'y', 'z', 'w' ] );
+NodeUtils.addShortcuts( Vector4Node.prototype, 'value', [ 'x', 'y', 'z', 'w' ] );
 
-THREE.Vector4Node.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
+Vector4Node.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
 
 	return builder.format( "vec4( " + this.x + ", " + this.y + ", " + this.z + ", " + this.w + " )", type, output );
 
 };
 
-THREE.Vector4Node.prototype.toJSON = function ( meta ) {
+Vector4Node.prototype.copy = function ( source ) {
+			
+	InputNode.prototype.copy.call( this, source );
+	
+	this.value.copy( source );
+
+};
+
+Vector4Node.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -42,3 +53,5 @@ THREE.Vector4Node.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { Vector4Node };

+ 34 - 0
examples/js/nodes/materials/MeshStandardNodeMaterial.js

@@ -0,0 +1,34 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { MeshStandardNode } from './nodes/MeshStandardNode.js';
+import { NodeMaterial } from './NodeMaterial.js';
+import { NodeUtils } from '../core/NodeUtils.js';
+
+function MeshStandardNodeMaterial() {
+
+	var node = new MeshStandardNode();
+
+	NodeMaterial.call( this, node, node );
+
+	this.type = "MeshStandardNodeMaterial";
+
+};
+
+MeshStandardNodeMaterial.prototype = Object.create( NodeMaterial.prototype );
+MeshStandardNodeMaterial.prototype.constructor = MeshStandardNodeMaterial;
+
+NodeUtils.addShortcuts( MeshStandardNodeMaterial.prototype, 'properties', [
+	"color",
+	"roughness",
+	"metalness",
+	"map",
+	"normalMap",
+	"normalScale",
+	"metalnessMap",
+	"roughnessMap",
+	"envMap"
+] );
+
+export { MeshStandardNodeMaterial };

+ 189 - 0
examples/js/nodes/materials/NodeMaterial.js

@@ -0,0 +1,189 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { NodeBuilder } from '../core/NodeBuilder.js';
+import { ColorNode } from '../inputs/ColorNode.js';
+import { PositionNode } from '../accessors/PositionNode.js';
+import { RawNode } from './nodes/RawNode.js';
+ 
+function NodeMaterial( vertex, fragment ) {
+
+	THREE.ShaderMaterial.call( this );
+
+	// prevent code share conflict, remove in future
+	
+	this.defines.UUID = this.uuid;
+
+	this.vertex = vertex || new RawNode( new PositionNode( PositionNode.PROJECTION ) );
+	this.fragment = fragment || new RawNode( new ColorNode( 0xFF0000 ) );
+
+	this.updaters = [];
+
+};
+
+NodeMaterial.prototype = Object.create( THREE.ShaderMaterial.prototype );
+NodeMaterial.prototype.constructor = NodeMaterial;
+NodeMaterial.prototype.type = "NodeMaterial";
+
+NodeMaterial.prototype.isNodeMaterial = true;
+
+Object.defineProperties( NodeMaterial.prototype, {
+
+	properties: {
+		
+		get: function () {
+
+			return this.fragment.properties;
+
+		}
+		
+	}
+
+} );
+
+NodeMaterial.prototype.updateFrame = function ( frame ) {
+
+	for ( var i = 0; i < this.updaters.length; ++ i ) {
+
+		frame.updateNode( this.updaters[ i ] );
+
+	}
+
+};
+
+NodeMaterial.prototype.onBeforeCompile = function ( shader, renderer ) {
+
+	if ( this.needsUpdate ) {
+
+		this.build( { renderer: renderer } );
+
+		shader.uniforms = this.uniforms;
+		shader.vertexShader = this.vertexShader;
+		shader.fragmentShader = this.fragmentShader;
+
+	}
+
+};
+
+NodeMaterial.prototype.build = function ( params ) {
+
+	params = params || {};
+
+	var builder = params.builder || new NodeBuilder();
+	
+	builder.setMaterial( this, params.renderer );
+	builder.build( this.vertex, this.fragment );
+	
+	this.vertexShader = builder.getCode('vertex');
+	this.fragmentShader = builder.getCode('fragment');
+	
+	this.defines = builder.defines;
+	this.uniforms = builder.uniforms;
+	this.extensions = builder.extensions;
+	this.updaters = builder.updaters;
+	
+	this.fog = builder.requires.fog;
+	this.lights = builder.requires.lights;
+
+	this.transparent = builder.requires.transparent || this.blending > THREE.NormalBlending;
+
+	this.needsUpdate = false;
+	
+	return this;
+
+};
+
+NodeMaterial.prototype.copy = function ( source ) {
+	
+	var uuid = this.uuid;
+	
+	for (var name in source) {
+		
+		this[name] = source[name];
+		
+	}
+	
+	this.uuid = uuid;
+	
+	if ( source.userData !== undefined) {
+		
+		this.userData = JSON.parse( JSON.stringify( source.userData ) );
+		
+	}
+	
+};
+
+NodeMaterial.prototype.toJSON = function ( meta ) {
+
+	var isRootObject = ( meta === undefined || typeof meta === 'string' );
+
+	if ( isRootObject ) {
+
+		meta = {
+			nodes: {}
+		};
+
+	}
+
+	if ( meta && ! meta.materials ) meta.materials = {};
+
+	if ( ! meta.materials[ this.uuid ] ) {
+
+		var data = {};
+
+		data.uuid = this.uuid;
+		data.type = this.type;
+
+		meta.materials[ data.uuid ] = data;
+
+		if ( this.name !== "" ) data.name = this.name;
+
+		if ( this.size !== undefined ) data.size = this.size;
+		if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation;
+
+		if ( this.blending !== THREE.NormalBlending ) data.blending = this.blending;
+		if ( this.flatShading === true ) data.flatShading = this.flatShading;
+		if ( this.side !== THREE.FrontSide ) data.side = this.side;
+		if ( this.vertexColors !== THREE.NoColors ) data.vertexColors = this.vertexColors;
+
+		if ( this.depthFunc !== THREE.LessEqualDepth ) data.depthFunc = this.depthFunc;
+		if ( this.depthTest === false ) data.depthTest = this.depthTest;
+		if ( this.depthWrite === false ) data.depthWrite = this.depthWrite;
+
+		if ( this.linewidth !== 1 ) data.linewidth = this.linewidth;
+		if ( this.dashSize !== undefined ) data.dashSize = this.dashSize;
+		if ( this.gapSize !== undefined ) data.gapSize = this.gapSize;
+		if ( this.scale !== undefined ) data.scale = this.scale;
+
+		if ( this.dithering === true ) data.dithering = true;
+		
+		if ( this.wireframe === true ) data.wireframe = this.wireframe;
+		if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth;
+		if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap;
+		if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin;
+
+		if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest;
+		if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = this.premultipliedAlpha;
+		
+		if ( this.morphTargets === true ) data.morphTargets = true;
+		if ( this.skinning === true ) data.skinning = true;
+
+		if ( this.visible === false ) data.visible = false;
+		if ( JSON.stringify( this.userData ) !== '{}' ) data.userData = this.userData;
+
+		data.fog = this.fog;
+		data.lights = this.lights;
+		
+		data.vertex = this.vertex.toJSON( meta ).uuid;
+		data.fragment = this.fragment.toJSON( meta ).uuid;
+
+	}
+
+	meta.material = this.uuid;
+
+	return meta;
+
+};
+
+export { NodeMaterial };

+ 26 - 7
examples/js/nodes/materials/PhongNodeMaterial.js

@@ -2,18 +2,37 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.PhongNodeMaterial = function () {
+import { PhongNode } from './nodes/PhongNode.js';
+import { NodeMaterial } from './NodeMaterial.js';
+import { NodeUtils } from '../core/NodeUtils.js';
 
-	this.node = new THREE.PhongNode();
+function PhongNodeMaterial() {
 
-	THREE.NodeMaterial.call( this, this.node, this.node );
+	var node = new PhongNode();
+
+	NodeMaterial.call( this, node, node );
 
 	this.type = "PhongNodeMaterial";
 
 };
 
-THREE.PhongNodeMaterial.prototype = Object.create( THREE.NodeMaterial.prototype );
-THREE.PhongNodeMaterial.prototype.constructor = THREE.PhongNodeMaterial;
+PhongNodeMaterial.prototype = Object.create( NodeMaterial.prototype );
+PhongNodeMaterial.prototype.constructor = PhongNodeMaterial;
+
+NodeUtils.addShortcuts( PhongNodeMaterial.prototype, 'fragment', [ 
+	'color', 
+	'alpha', 
+	'specular', 
+	'shininess', 
+	'normal', 
+	'emissive', 
+	'ambient', 
+	'light', 
+	'shadow', 
+	'ao', 
+	'environment', 
+	'environmentAlpha',
+	'transform' 
+] );
 
-THREE.NodeMaterial.addShortcuts( THREE.PhongNodeMaterial.prototype, 'node',
-	[ 'color', 'alpha', 'specular', 'shininess', 'normal', 'normalScale', 'emissive', 'ambient', 'light', 'shadow', 'ao', 'environment', 'environmentAlpha', 'transform' ] );
+export { PhongNodeMaterial };

+ 17 - 7
examples/js/nodes/materials/SpriteNodeMaterial.js

@@ -2,18 +2,28 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.SpriteNodeMaterial = function () {
+import { SpriteNode } from './nodes/SpriteNode.js';
+import { NodeMaterial } from './NodeMaterial.js';
+import { NodeUtils } from '../core/NodeUtils.js';
 
-	this.node = new THREE.SpriteNode();
+function SpriteNodeMaterial() {
 
-	THREE.NodeMaterial.call( this, this.node, this.node );
+	var node = new SpriteNode();
+
+	NodeMaterial.call( this, node, node );
 
 	this.type = "SpriteNodeMaterial";
 
 };
 
-THREE.SpriteNodeMaterial.prototype = Object.create( THREE.NodeMaterial.prototype );
-THREE.SpriteNodeMaterial.prototype.constructor = THREE.SpriteNodeMaterial;
+SpriteNodeMaterial.prototype = Object.create( NodeMaterial.prototype );
+SpriteNodeMaterial.prototype.constructor = SpriteNodeMaterial;
+
+NodeUtils.addShortcuts( SpriteNodeMaterial.prototype, 'fragment', [ 
+	'color', 
+	'alpha', 
+	'transform', 
+	'spherical' 
+] );
 
-THREE.NodeMaterial.addShortcuts( THREE.SpriteNodeMaterial.prototype, 'node',
-	[ 'color', 'alpha', 'transform', 'spherical' ] );
+export { SpriteNodeMaterial };

+ 28 - 7
examples/js/nodes/materials/StandardNodeMaterial.js

@@ -2,18 +2,39 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.StandardNodeMaterial = function () {
+import { StandardNode } from './nodes/StandardNode.js';
+import { NodeMaterial } from './NodeMaterial.js';
+import { NodeUtils } from '../core/NodeUtils.js';
 
-	this.node = new THREE.StandardNode();
+function StandardNodeMaterial() {
 
-	THREE.NodeMaterial.call( this, this.node, this.node );
+	var node = new StandardNode();
+
+	NodeMaterial.call( this, node, node );
 
 	this.type = "StandardNodeMaterial";
 
 };
 
-THREE.StandardNodeMaterial.prototype = Object.create( THREE.NodeMaterial.prototype );
-THREE.StandardNodeMaterial.prototype.constructor = THREE.StandardNodeMaterial;
+StandardNodeMaterial.prototype = Object.create( NodeMaterial.prototype );
+StandardNodeMaterial.prototype.constructor = StandardNodeMaterial;
+
+NodeUtils.addShortcuts( StandardNodeMaterial.prototype, 'fragment', [ 
+	'color', 
+	'alpha', 
+	'roughness', 
+	'metalness', 
+	'reflectivity', 
+	'clearCoat', 
+	'clearCoatRoughness', 
+	'normal', 
+	'emissive', 
+	'ambient', 
+	'light', 
+	'shadow', 
+	'ao', 
+	'environment', 
+	'transform' 
+] );
 
-THREE.NodeMaterial.addShortcuts( THREE.StandardNodeMaterial.prototype, 'node',
-	[ 'color', 'alpha', 'roughness', 'metalness', 'reflectivity', 'clearCoat', 'clearCoatRoughness', 'normal', 'normalScale', 'emissive', 'ambient', 'light', 'shadow', 'ao', 'environment', 'transform' ] );
+export { StandardNodeMaterial };

+ 109 - 0
examples/js/nodes/materials/nodes/MeshStandardNode.js

@@ -0,0 +1,109 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { StandardNode } from './StandardNode.js';
+import { PropertyNode } from '../../inputs/PropertyNode.js';
+import { OperatorNode } from '../../math/OperatorNode.js';
+import { SwitchNode } from '../../utils/SwitchNode.js';
+import { NormalMapNode } from '../../misc/NormalMapNode.js';
+
+function MeshStandardNode() {
+
+	StandardNode.call( this );
+
+	this.properties = {
+		color: new THREE.Color( 0xffffff ),
+		roughness: 0.5,
+		metalness: 0.5,
+		normalScale: new THREE.Vector2( 1, 1 )
+	};
+	
+	this.inputs = {
+		color: new PropertyNode( this.properties, 'color', 'c' ),
+		roughness: new PropertyNode( this.properties, 'roughness', 'f' ),
+		metalness: new PropertyNode( this.properties, 'metalness', 'f' ),
+		normalScale: new PropertyNode( this.properties, 'normalScale', 'v2' )
+	};
+
+};
+
+MeshStandardNode.prototype = Object.create( StandardNode.prototype );
+MeshStandardNode.prototype.constructor = MeshStandardNode;
+MeshStandardNode.prototype.nodeType = "MeshStandard";
+
+MeshStandardNode.prototype.build = function ( builder ) {
+
+	var props = this.properties,
+		inputs = this.inputs;
+
+	if ( builder.isShader('fragment') ) {
+		
+		// slots
+		// * color
+		// * map
+		
+		var color = builder.findNode( props.color, inputs.color ),
+			map = builder.resolve( props.map );
+		
+		this.color = map ? new OperatorNode( color, map, OperatorNode.MUL ) : color;
+		
+		// slots
+		// * roughness
+		// * roughnessMap
+		
+		var roughness = builder.findNode( props.roughness, inputs.roughness ),
+			roughnessMap = builder.resolve( props.roughnessMap );
+		
+		this.roughness = roughnessMap ? new OperatorNode( roughness, new SwitchNode( roughnessMap, "g" ), OperatorNode.MUL ) : roughness;
+		
+		// slots
+		// * metalness
+		// * metalnessMap
+		
+		var metalness = builder.findNode( props.metalness, inputs.metalness ),
+			metalnessMap = builder.resolve( props.metalnessMap );
+		
+		this.metalness = metalnessMap ? new OperatorNode( metalness, new SwitchNode( metalnessMap, "b" ), OperatorNode.MUL ) : metalness;
+
+		// slots
+		// * normalMap
+		// * normalScale
+		
+		if ( props.normalMap ) {
+			
+			this.normal = new NormalMapNode( builder.resolve( props.normalMap ) );
+			this.normal.scale = builder.findNode( props.normalScale, inputs.normalScale )
+
+		}
+
+		// slots
+		// * envMap
+		
+		this.environment = builder.resolve( props.envMap );
+		
+	}
+	
+	// build code
+
+	return StandardNode.prototype.build.call( this, builder );
+
+};
+
+MeshStandardNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+		
+		console.warn(".toJSON not implemented in", this);
+		
+	}
+
+	return data;
+
+};
+
+export { MeshStandardNode };

+ 76 - 37
examples/js/nodes/materials/PhongNode.js → examples/js/nodes/materials/nodes/PhongNode.js

@@ -2,42 +2,45 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.PhongNode = function () {
+import { GLNode } from '../../core/GLNode.js';
+import { ColorNode } from '../../inputs/ColorNode.js';
+import { FloatNode } from '../../inputs/FloatNode.js';
+ 
+function PhongNode() {
 
-	THREE.GLNode.call( this );
+	GLNode.call( this );
 
-	this.color = new THREE.ColorNode( 0xEEEEEE );
-	this.specular = new THREE.ColorNode( 0x111111 );
-	this.shininess = new THREE.FloatNode( 30 );
+	this.color = new ColorNode( 0xEEEEEE );
+	this.specular = new ColorNode( 0x111111 );
+	this.shininess = new FloatNode( 30 );
 
 };
 
-THREE.PhongNode.prototype = Object.create( THREE.GLNode.prototype );
-THREE.PhongNode.prototype.constructor = THREE.PhongNode;
-THREE.PhongNode.prototype.nodeType = "Phong";
+PhongNode.prototype = Object.create( GLNode.prototype );
+PhongNode.prototype.constructor = PhongNode;
+PhongNode.prototype.nodeType = "Phong";
 
-THREE.PhongNode.prototype.build = function ( builder ) {
+PhongNode.prototype.build = function ( builder ) {
 
-	var material = builder.material;
 	var code;
 
-	material.define( 'PHONG' );
-	material.define( 'ALPHATEST', '0.0' );
+	builder.define( 'PHONG' );
+	builder.define( 'ALPHATEST', '0.0' );
 
-	material.requires.lights = true;
+	builder.requires.lights = true;
 
 	if ( builder.isShader( 'vertex' ) ) {
 
 		var transform = this.transform ? this.transform.parseAndBuildCode( builder, 'v3', { cache: 'transform' } ) : undefined;
 
-		material.mergeUniform( THREE.UniformsUtils.merge( [
+		builder.mergeUniform( THREE.UniformsUtils.merge( [
 
 			THREE.UniformsLib[ "fog" ],
 			THREE.UniformsLib[ "lights" ]
 
 		] ) );
 
-		material.addVertexPars( [
+		builder.addParsCode( [
 			"varying vec3 vViewPosition;",
 
 			"#ifndef FLAT_SHADED",
@@ -47,6 +50,7 @@ THREE.PhongNode.prototype.build = function ( builder ) {
 			"#endif",
 
 			"#include <common>",
+			"#include <encodings_pars_fragment>", // encoding functions
 			"#include <fog_pars_vertex>",
 			"#include <morphtarget_pars_vertex>",
 			"#include <skinning_pars_vertex>",
@@ -74,7 +78,7 @@ THREE.PhongNode.prototype.build = function ( builder ) {
 
 			output.push(
 				transform.code,
-				"transformed = " + transform.result + ";"
+				transform.result ? "transformed = " + transform.result + ";" : ''
 			);
 
 		}
@@ -121,26 +125,26 @@ THREE.PhongNode.prototype.build = function ( builder ) {
 
 		var color = this.color.buildCode( builder, 'c', { slot: 'color' } );
 		var specular = this.specular.buildCode( builder, 'c' );
-		var shininess = this.shininess.buildCode( builder, 'fv1' );
+		var shininess = this.shininess.buildCode( builder, 'f' );
 
-		var alpha = this.alpha ? this.alpha.buildCode( builder, 'fv1' ) : undefined;
+		var alpha = this.alpha ? this.alpha.buildCode( builder, 'f' ) : undefined;
 
 		var normal = this.normal ? this.normal.buildCode( builder, 'v3' ) : undefined;
 		var normalScale = this.normalScale && this.normal ? this.normalScale.buildCode( builder, 'v2' ) : undefined;
 
 		var light = this.light ? this.light.buildCode( builder, 'v3', { cache: 'light' } ) : undefined;
 
-		var ao = this.ao ? this.ao.buildCode( builder, 'fv1' ) : undefined;
+		var ao = this.ao ? this.ao.buildCode( builder, 'f' ) : undefined;
 		var ambient = this.ambient ? this.ambient.buildCode( builder, 'c' ) : undefined;
 		var shadow = this.shadow ? this.shadow.buildCode( builder, 'c' ) : undefined;
 		var emissive = this.emissive ? this.emissive.buildCode( builder, 'c', { slot: 'emissive' } ) : undefined;
 
 		var environment = this.environment ? this.environment.buildCode( builder, 'c', { slot: 'environment' } ) : undefined;
-		var environmentAlpha = this.environmentAlpha && this.environment ? this.environmentAlpha.buildCode( builder, 'fv1' ) : undefined;
+		var environmentAlpha = this.environmentAlpha && this.environment ? this.environmentAlpha.buildCode( builder, 'f' ) : undefined;
 
-		material.requires.transparent = alpha != undefined;
+		builder.requires.transparent = alpha != undefined;
 
-		material.addFragmentPars( [
+		builder.addParsCode( [
 			"#include <common>",
 			"#include <fog_pars_fragment>",
 			"#include <bsdfs>",
@@ -167,7 +171,7 @@ THREE.PhongNode.prototype.build = function ( builder ) {
 			"	vec3 specular = " + specular.result + ";",
 
 			shininess.code,
-			"	float shininess = max(0.0001," + shininess.result + ");",
+			"	float shininess = max( 0.0001, " + shininess.result + " );",
 
 			"	float specularStrength = 1.0;" // Ignored in MaterialNode ( replace to specular )
 		];
@@ -183,19 +187,11 @@ THREE.PhongNode.prototype.build = function ( builder ) {
 
 		if ( normal ) {
 
-			builder.include( 'perturbNormal2Arb' );
-
-			output.push( normal.code );
-
-			if ( normalScale ) output.push( normalScale.code );
-
 			output.push(
-				'normal = perturbNormal2Arb(-vViewPosition,normal,' +
-				normal.result + ',' +
-				new THREE.UVNode().build( builder, 'v2' ) + ',' +
-				( normalScale ? normalScale.result : 'vec2( 1.0 )' ) + ');'
+				normal.code,
+				'normal = ' + normal.result + ';'
 			);
-
+		
 		}
 
 		// optimization for now
@@ -285,7 +281,19 @@ THREE.PhongNode.prototype.build = function ( builder ) {
 			}
 
 		}
-
+/*
+		switch( builder.material.combine ) {
+
+			case THREE.ENVMAP_BLENDING_MULTIPLY:
+				
+				//output.push( "vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular;" );
+				//outgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );
+				
+				break;
+			
+			
+		}
+	*/	
 		if ( alpha ) {
 
 			output.push( "gl_FragColor = vec4( outgoingLight, " + alpha.result + " );" );
@@ -311,8 +319,38 @@ THREE.PhongNode.prototype.build = function ( builder ) {
 
 };
 
+PhongNode.prototype.copy = function ( source ) {
+			
+	GLNode.prototype.copy.call( this, source );
+	
+	// vertex
+
+	if ( source.transform ) this.transform = source.transform;
+
+	// fragment
+
+	this.color = source.color;
+	this.specular = source.specular;
+	this.shininess = source.shininess;
 
-THREE.PhongNode.prototype.toJSON = function ( meta ) {
+	if ( source.alpha ) this.alpha = source.alpha;
+
+	if ( source.normal ) this.normal = source.normal;
+
+	if ( source.light ) this.light = source.light;
+	if ( source.shadow ) this.shadow = source.shadow;
+
+	if ( source.ao ) this.ao = source.ao;
+	
+	if ( source.emissive ) this.emissive = source.emissive;
+	if ( source.ambient ) this.ambient = source.ambient;
+
+	if ( source.environment ) this.environment = source.environment;
+	if ( source.environmentAlpha ) this.environmentAlpha = source.environmentAlpha;
+
+};
+
+PhongNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -333,7 +371,6 @@ THREE.PhongNode.prototype.toJSON = function ( meta ) {
 		if ( this.alpha ) data.alpha = this.alpha.toJSON( meta ).uuid;
 
 		if ( this.normal ) data.normal = this.normal.toJSON( meta ).uuid;
-		if ( this.normalScale ) data.normalScale = this.normalScale.toJSON( meta ).uuid;
 
 		if ( this.light ) data.light = this.light.toJSON( meta ).uuid;
 
@@ -350,3 +387,5 @@ THREE.PhongNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { PhongNode };

+ 62 - 0
examples/js/nodes/materials/nodes/RawNode.js

@@ -0,0 +1,62 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { GLNode } from '../../core/GLNode.js';
+
+function RawNode( value ) {
+
+	GLNode.call( this, 'v4' );
+
+	this.value = value;
+
+};
+
+RawNode.prototype = Object.create( GLNode.prototype );
+RawNode.prototype.constructor = RawNode;
+RawNode.prototype.nodeType = "Raw";
+
+RawNode.prototype.generate = function ( builder ) {
+
+	var data = this.value.parseAndBuildCode( builder, this.type ),
+		code = data.code + '\n';
+
+	if ( builder.isShader( 'vertex' ) ) {
+
+		code += 'gl_Position = ' + data.result + ';';
+
+	} else {
+
+		code += 'gl_FragColor = ' + data.result + ';';
+
+	}
+
+	return code;
+
+};
+
+RawNode.prototype.copy = function ( source ) {
+	
+	GLNode.prototype.copy.call( this, source );
+	
+	this.value = source.value;
+	
+};
+
+RawNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.value = this.value.toJSON( meta ).uuid;
+
+	}
+
+	return data;
+
+};
+
+export { RawNode };

+ 41 - 17
examples/js/nodes/materials/SpriteNode.js → examples/js/nodes/materials/nodes/SpriteNode.js

@@ -2,38 +2,40 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.SpriteNode = function () {
+import { GLNode } from '../../core/GLNode.js';
+import { ColorNode } from '../../inputs/ColorNode.js';
 
-	THREE.GLNode.call( this );
+function SpriteNode() {
 
-	this.color = new THREE.ColorNode( 0xEEEEEE );
+	GLNode.call( this );
+
+	this.color = new ColorNode( 0xEEEEEE );
 	this.spherical = true;
 
 };
 
-THREE.SpriteNode.prototype = Object.create( THREE.GLNode.prototype );
-THREE.SpriteNode.prototype.constructor = THREE.SpriteNode;
-THREE.SpriteNode.prototype.nodeType = "Sprite";
+SpriteNode.prototype = Object.create( GLNode.prototype );
+SpriteNode.prototype.constructor = SpriteNode;
+SpriteNode.prototype.nodeType = "Sprite";
 
-THREE.SpriteNode.prototype.build = function ( builder ) {
+SpriteNode.prototype.build = function ( builder ) {
 
-	var material = builder.material;
 	var output, code;
 
-	material.define( 'SPRITE' );
+	builder.define( 'SPRITE' );
 
-	material.requires.lights = false;
-	material.requires.transparent = this.alpha != undefined;
+	builder.requires.lights = false;
+	builder.requires.transparent = this.alpha != undefined;
 
 	if ( builder.isShader( 'vertex' ) ) {
 
 		var transform = this.transform ? this.transform.parseAndBuildCode( builder, 'v3', { cache: 'transform' } ) : undefined;
 
-		material.mergeUniform( THREE.UniformsUtils.merge( [
+		builder.mergeUniform( THREE.UniformsUtils.merge( [
 			THREE.UniformsLib[ "fog" ]
 		] ) );
 
-		material.addVertexPars( [
+		builder.addParsCode( [
 			"#include <fog_pars_vertex>"
 		].join( "\n" ) );
 
@@ -45,7 +47,7 @@ THREE.SpriteNode.prototype.build = function ( builder ) {
 
 			output.push(
 				transform.code,
-				"transformed = " + transform.result + ";"
+				transform.result ? "transformed = " + transform.result + ";" : ''
 			);
 
 		}
@@ -102,19 +104,20 @@ THREE.SpriteNode.prototype.build = function ( builder ) {
 
 	} else {
 
-		material.addFragmentPars( [
+		builder.addParsCode( [
 			"#include <fog_pars_fragment>",
 		].join( "\n" ) );
 
 		// parse all nodes to reuse generate codes
 
 		this.color.parse( builder, { slot: 'color' } );
+
 		if ( this.alpha ) this.alpha.parse( builder );
 
 		// build code
 
 		var color = this.color.buildCode( builder, 'c', { slot: 'color' } );
-		var alpha = this.alpha ? this.alpha.buildCode( builder, 'fv1' ) : undefined;
+		var alpha = this.alpha ? this.alpha.buildCode( builder, 'f' ) : undefined;
 
 		output = [ color.code ];
 
@@ -139,7 +142,25 @@ THREE.SpriteNode.prototype.build = function ( builder ) {
 
 };
 
-THREE.SpriteNode.prototype.toJSON = function ( meta ) {
+SpriteNode.prototype.copy = function ( source ) {
+			
+	GLNode.prototype.copy.call( this, source );
+	
+	// vertex
+	
+	if ( source.transform ) this.transform = source.transform;
+	
+	// fragment
+	
+	this.color = source.color;
+	
+	if ( source.spherical !== undefined ) this.spherical = source.transform;
+	
+	if ( source.alpha ) this.alpha = source.alpha;
+
+};
+
+SpriteNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -154,6 +175,7 @@ THREE.SpriteNode.prototype.toJSON = function ( meta ) {
 		// fragment
 
 		data.color = this.color.toJSON( meta ).uuid;
+		
 		if ( this.spherical === false ) data.spherical = false;
 
 		if ( this.alpha ) data.alpha = this.alpha.toJSON( meta ).uuid;
@@ -163,3 +185,5 @@ THREE.SpriteNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { SpriteNode };

+ 99 - 64
examples/js/nodes/materials/StandardNode.js → examples/js/nodes/materials/nodes/StandardNode.js

@@ -2,47 +2,48 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.StandardNode = function () {
+import { GLNode } from '../../core/GLNode.js';
+import { ColorNode } from '../../inputs/ColorNode.js';
+import { FloatNode } from '../../inputs/FloatNode.js';
+import { RoughnessToBlinnExponentNode } from '../../bsdfs/RoughnessToBlinnExponentNode.js';
+ 
+function StandardNode() {
 
-	THREE.GLNode.call( this );
+	GLNode.call( this );
 
-	this.color = new THREE.ColorNode( 0xEEEEEE );
-	this.roughness = new THREE.FloatNode( 0.5 );
-	this.metalness = new THREE.FloatNode( 0.5 );
+	this.color = new ColorNode( 0xEEEEEE );
+	this.roughness = new FloatNode( 0.5 );
+	this.metalness = new FloatNode( 0.5 );
 
 };
 
-THREE.StandardNode.prototype = Object.create( THREE.GLNode.prototype );
-THREE.StandardNode.prototype.constructor = THREE.StandardNode;
-THREE.StandardNode.prototype.nodeType = "Standard";
+StandardNode.prototype = Object.create( GLNode.prototype );
+StandardNode.prototype.constructor = StandardNode;
+StandardNode.prototype.nodeType = "Standard";
 
-THREE.StandardNode.prototype.build = function ( builder ) {
+StandardNode.prototype.build = function ( builder ) {
 
-	var material = builder.material;
 	var code;
 
-	material.define( 'PHYSICAL' );
+	builder.define( this.clearCoat || this.clearCoatRoughness ? 'PHYSICAL' : 'STANDARD' );
+	builder.define( 'ALPHATEST', '0.0' );
 
-	if ( ! this.clearCoat && ! this.clearCoatRoughness ) material.define( 'STANDARD' );
+	builder.requires.lights = true;
 
-	material.define( 'ALPHATEST', '0.0' );
-
-	material.requires.lights = true;
-
-	material.extensions.shaderTextureLOD = true;
+	builder.extensions.shaderTextureLOD = true;
 
 	if ( builder.isShader( 'vertex' ) ) {
 
 		var transform = this.transform ? this.transform.parseAndBuildCode( builder, 'v3', { cache: 'transform' } ) : undefined;
 
-		material.mergeUniform( THREE.UniformsUtils.merge( [
+		builder.mergeUniform( THREE.UniformsUtils.merge( [
 
 			THREE.UniformsLib[ "fog" ],
 			THREE.UniformsLib[ "lights" ]
 
 		] ) );
 
-		material.addVertexPars( [
+		builder.addParsCode( [
 			"varying vec3 vViewPosition;",
 
 			"#ifndef FLAT_SHADED",
@@ -52,6 +53,7 @@ THREE.StandardNode.prototype.build = function ( builder ) {
 			"#endif",
 
 			"#include <common>",
+			"#include <encodings_pars_fragment>", // encoding functions
 			"#include <fog_pars_vertex>",
 			"#include <morphtarget_pars_vertex>",
 			"#include <skinning_pars_vertex>",
@@ -83,7 +85,7 @@ THREE.StandardNode.prototype.build = function ( builder ) {
 
 			output.push(
 				transform.code,
-				"transformed = " + transform.result + ";"
+				transform.result ? "transformed = " + transform.result + ";" : ''
 			);
 
 		}
@@ -105,19 +107,20 @@ THREE.StandardNode.prototype.build = function ( builder ) {
 
 	} else {
 
-		// blur textures for PBR effect
+		var contextEnvironment = {
+			bias: RoughnessToBlinnExponentNode,
+			gamma: true
+		};
 
-		var requires = {
-			bias: new THREE.RoughnessToBlinnExponentNode(),
-			offsetU: 0,
-			offsetV: 0
+		var contextGammaOnly = {
+			gamma: true
 		};
 
-		var useClearCoat = ! material.isDefined( 'STANDARD' );
+		var useClearCoat = ! builder.isDefined( 'STANDARD' );
 
 		// parse all nodes to reuse generate codes
 
-		this.color.parse( builder, { slot: 'color' } );
+		this.color.parse( builder, { slot: 'color', context: contextGammaOnly } );
 		this.roughness.parse( builder );
 		this.metalness.parse( builder );
 
@@ -138,38 +141,38 @@ THREE.StandardNode.prototype.build = function ( builder ) {
 		if ( this.shadow ) this.shadow.parse( builder );
 		if ( this.emissive ) this.emissive.parse( builder, { slot: 'emissive' } );
 
-		if ( this.environment ) this.environment.parse( builder, { cache: 'env', requires: requires, slot: 'environment' } ); // isolate environment from others inputs ( see TextureNode, CubeTextureNode )
+		if ( this.environment ) this.environment.parse( builder, { cache: 'env', context: contextEnvironment, slot: 'environment' } ); // isolate environment from others inputs ( see TextureNode, CubeTextureNode )
 
 		// build code
 
-		var color = this.color.buildCode( builder, 'c', { slot: 'color' } );
-		var roughness = this.roughness.buildCode( builder, 'fv1' );
-		var metalness = this.metalness.buildCode( builder, 'fv1' );
+		var color = this.color.buildCode( builder, 'c', { slot: 'color', context: contextGammaOnly } );
+		var roughness = this.roughness.buildCode( builder, 'f' );
+		var metalness = this.metalness.buildCode( builder, 'f' );
 
-		var alpha = this.alpha ? this.alpha.buildCode( builder, 'fv1' ) : undefined;
+		var alpha = this.alpha ? this.alpha.buildCode( builder, 'f' ) : undefined;
 
 		var normal = this.normal ? this.normal.buildCode( builder, 'v3' ) : undefined;
 		var normalScale = this.normalScale && this.normal ? this.normalScale.buildCode( builder, 'v2' ) : undefined;
 
-		var clearCoat = this.clearCoat ? this.clearCoat.buildCode( builder, 'fv1' ) : undefined;
-		var clearCoatRoughness = this.clearCoatRoughness ? this.clearCoatRoughness.buildCode( builder, 'fv1' ) : undefined;
+		var clearCoat = this.clearCoat ? this.clearCoat.buildCode( builder, 'f' ) : undefined;
+		var clearCoatRoughness = this.clearCoatRoughness ? this.clearCoatRoughness.buildCode( builder, 'f' ) : undefined;
 
-		var reflectivity = this.reflectivity ? this.reflectivity.buildCode( builder, 'fv1' ) : undefined;
+		var reflectivity = this.reflectivity ? this.reflectivity.buildCode( builder, 'f' ) : undefined;
 
 		var light = this.light ? this.light.buildCode( builder, 'v3', { cache: 'light' } ) : undefined;
 
-		var ao = this.ao ? this.ao.buildCode( builder, 'fv1' ) : undefined;
+		var ao = this.ao ? this.ao.buildCode( builder, 'f' ) : undefined;
 		var ambient = this.ambient ? this.ambient.buildCode( builder, 'c' ) : undefined;
 		var shadow = this.shadow ? this.shadow.buildCode( builder, 'c' ) : undefined;
 		var emissive = this.emissive ? this.emissive.buildCode( builder, 'c', { slot: 'emissive' } ) : undefined;
 
-		var environment = this.environment ? this.environment.buildCode( builder, 'c', { cache: 'env', requires: requires, slot: 'environment' } ) : undefined;
+		var environment = this.environment ? this.environment.buildCode( builder, 'c', { cache: 'env', context: contextEnvironment, slot: 'environment' } ) : undefined;
 
-		var clearCoatEnv = useClearCoat && environment ? this.environment.buildCode( builder, 'c', { cache: 'clearCoat', requires: requires, slot: 'environment' } ) : undefined;
+		var clearCoatEnv = useClearCoat && environment ? this.environment.buildCode( builder, 'c', { cache: 'clearCoat', context: contextEnvironment, slot: 'environment' } ) : undefined;
 
-		material.requires.transparent = alpha != undefined;
+		builder.requires.transparent = alpha !== undefined;
 
-		material.addFragmentPars( [
+		builder.addParsCode( [
 
 			"varying vec3 vViewPosition;",
 
@@ -221,28 +224,18 @@ THREE.StandardNode.prototype.build = function ( builder ) {
 
 		if ( normal ) {
 
-			builder.include( 'perturbNormal2Arb' );
-
-			output.push( normal.code );
-
-			if ( normalScale ) output.push( normalScale.code );
-
 			output.push(
-				'normal = perturbNormal2Arb(-vViewPosition,normal,' +
-				normal.result + ',' +
-				new THREE.UVNode().build( builder, 'v2' ) + ',' +
-				( normalScale ? normalScale.result : 'vec2( 1.0 )' ) + ');'
+				normal.code,
+				'normal = ' + normal.result + ';'
 			);
-
+		
 		}
 
 		// optimization for now
 
-		output.push( 'material.diffuseColor = ' + ( light ? 'vec3( 1.0 )' : 'diffuseColor * (1.0 - metalnessFactor)' ) + ';' );
-
 		output.push(
-			// accumulation
-			'material.specularRoughness = clamp( roughnessFactor, DEFAULT_SPECULAR_COEFFICIENT, 1.0 );' // disney's remapping of [ 0, 1 ] roughness to [ 0.001, 1 ]
+			'material.diffuseColor = ' + ( light ? 'vec3( 1.0 )' : 'diffuseColor * (1.0 - metalnessFactor)' ) + ';',
+			'material.specularRoughness = clamp( roughnessFactor, 0.04, 1.0 );'
 		);
 
 		if ( clearCoat ) {
@@ -262,7 +255,7 @@ THREE.StandardNode.prototype.build = function ( builder ) {
 
 			output.push(
 				clearCoatRoughness.code,
-				'material.clearCoatRoughness = clamp( ' + clearCoatRoughness.result + ', DEFAULT_SPECULAR_COEFFICIENT, 1.0 );'
+				'material.clearCoatRoughness = clamp( ' + clearCoatRoughness.result + ', 0.04, 1.0 );'
 			);
 
 		} else if ( useClearCoat ) {
@@ -287,8 +280,7 @@ THREE.StandardNode.prototype.build = function ( builder ) {
 		}
 
 		output.push(
-			"#include <lights_fragment_begin>",
-			"#include <lights_fragment_end>"
+			"#include <lights_fragment_begin>"
 		);
 
 		if ( light ) {
@@ -361,9 +353,13 @@ THREE.StandardNode.prototype.build = function ( builder ) {
 
 			}
 
-			output.push( "RE_IndirectSpecular(" + environment.result + ", clearCoatRadiance, geometry, material, reflectedLight );" );
+			output.push( "radiance += " + environment.result + ";" );
 
 		}
+		
+		output.push(
+			"#include <lights_fragment_end>"
+		);
 
 		output.push( "vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular;" );
 
@@ -381,7 +377,9 @@ THREE.StandardNode.prototype.build = function ( builder ) {
 			"#include <premultiplied_alpha_fragment>",
 			"#include <tonemapping_fragment>",
 			"#include <encodings_fragment>",
-			"#include <fog_fragment>"
+			"#include <fog_fragment>",
+			"#include <premultiplied_alpha_fragment>",
+			"#include <dithering_fragment>"
 		);
 
 		code = output.join( "\n" );
@@ -392,7 +390,42 @@ THREE.StandardNode.prototype.build = function ( builder ) {
 
 };
 
-THREE.StandardNode.prototype.toJSON = function ( meta ) {
+StandardNode.prototype.copy = function ( source ) {
+			
+	GLNode.prototype.copy.call( this, source );
+	
+	// vertex
+
+	if ( source.transform ) this.transform = source.transform;
+
+	// fragment
+
+	this.color = source.color;
+	this.roughness = source.roughness;
+	this.metalness = source.metalness;
+
+	if ( source.alpha ) this.alpha = source.alpha;
+
+	if ( source.normal ) this.normal = source.normal;
+
+	if ( source.clearCoat ) this.clearCoat = source.clearCoat;
+	if ( source.clearCoatRoughness ) this.clearCoatRoughness = source.clearCoatRoughness;
+
+	if ( source.reflectivity ) this.reflectivity = source.reflectivity;
+
+	if ( source.light ) this.light = source.light;
+	if ( source.shadow ) this.shadow = source.shadow;
+
+	if ( source.ao ) this.ao = source.ao;
+	
+	if ( source.emissive ) this.emissive = source.emissive;
+	if ( source.ambient ) this.ambient = source.ambient;
+
+	if ( source.environment ) this.environment = source.environment;
+
+};
+
+StandardNode.prototype.toJSON = function ( meta ) {
 
 	var data = this.getJSONNode( meta );
 
@@ -413,7 +446,6 @@ THREE.StandardNode.prototype.toJSON = function ( meta ) {
 		if ( this.alpha ) data.alpha = this.alpha.toJSON( meta ).uuid;
 
 		if ( this.normal ) data.normal = this.normal.toJSON( meta ).uuid;
-		if ( this.normalScale ) data.normalScale = this.normalScale.toJSON( meta ).uuid;
 
 		if ( this.clearCoat ) data.clearCoat = this.clearCoat.toJSON( meta ).uuid;
 		if ( this.clearCoatRoughness ) data.clearCoatRoughness = this.clearCoatRoughness.toJSON( meta ).uuid;
@@ -421,11 +453,12 @@ THREE.StandardNode.prototype.toJSON = function ( meta ) {
 		if ( this.reflectivity ) data.reflectivity = this.reflectivity.toJSON( meta ).uuid;
 
 		if ( this.light ) data.light = this.light.toJSON( meta ).uuid;
+		if ( this.shadow ) data.shadow = this.shadow.toJSON( meta ).uuid;
 
 		if ( this.ao ) data.ao = this.ao.toJSON( meta ).uuid;
-		if ( this.ambient ) data.ambient = this.ambient.toJSON( meta ).uuid;
-		if ( this.shadow ) data.shadow = this.shadow.toJSON( meta ).uuid;
+		
 		if ( this.emissive ) data.emissive = this.emissive.toJSON( meta ).uuid;
+		if ( this.ambient ) data.ambient = this.ambient.toJSON( meta ).uuid;
 
 		if ( this.environment ) data.environment = this.environment.toJSON( meta ).uuid;
 
@@ -434,3 +467,5 @@ THREE.StandardNode.prototype.toJSON = function ( meta ) {
 	return data;
 
 };
+
+export { StandardNode };

Some files were not shown because too many files changed in this diff