Browse Source

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

Mr.doob 14 years ago
parent
commit
0113a407a0

File diff suppressed because it is too large
+ 107 - 106
build/Three.js


+ 3 - 3
build/custom/ThreeCanvas.js

@@ -76,9 +76,9 @@ THREE.Camera.prototype.update=function(a,b,c){if(this.useTarget)this.matrix.look
 THREE.AmbientLight.prototype.constructor=THREE.AmbientLight;THREE.DirectionalLight=function(a,b,c,d){THREE.Light.call(this,a);this.position=new THREE.Vector3(0,1,0);this.intensity=b||1;this.distance=c||0;this.castShadow=d!==void 0?d:!1};THREE.DirectionalLight.prototype=new THREE.Light;THREE.DirectionalLight.prototype.constructor=THREE.DirectionalLight;THREE.PointLight=function(a,b,c){THREE.Light.call(this,a);this.position=new THREE.Vector3;this.intensity=b||1;this.distance=c||0};
 THREE.PointLight.prototype=new THREE.Light;THREE.PointLight.prototype.constructor=THREE.PointLight;
 THREE.Material=function(a){this.id=THREE.MaterialCounter.value++;a=a||{};this.opacity=a.opacity!==void 0?a.opacity:1;this.transparent=a.transparent!==void 0?a.transparent:!1;this.blending=a.blending!==void 0?a.blending:THREE.NormalBlending;this.depthTest=a.depthTest!==void 0?a.depthTest:!0;this.polygonOffset=a.polygonOffset!==void 0?a.polygonOffset:!1;this.polygonOffsetFactor=a.polygonOffsetFactor!==void 0?a.polygonOffsetFactor:0;this.polygonOffsetUnits=a.polygonOffsetUnits!==void 0?a.polygonOffsetUnits:
-0};THREE.NoShading=0;THREE.FlatShading=1;THREE.SmoothShading=2;THREE.NoColors=0;THREE.FaceColors=1;THREE.VertexColors=2;THREE.NormalBlending=0;THREE.AdditiveBlending=1;THREE.SubtractiveBlending=2;THREE.MultiplyBlending=3;THREE.AdditiveAlphaBlending=4;THREE.MaterialCounter={value:0};THREE.CubeReflectionMapping=function(){};THREE.CubeRefractionMapping=function(){};THREE.LatitudeReflectionMapping=function(){};THREE.LatitudeRefractionMapping=function(){};THREE.SphericalReflectionMapping=function(){};
-THREE.SphericalRefractionMapping=function(){};THREE.UVMapping=function(){};THREE.LineBasicMaterial=function(a){THREE.Material.call(this,a);a=a||{};this.color=a.color!==void 0?new THREE.Color(a.color):new THREE.Color(16777215);this.linewidth=a.linewidth!==void 0?a.linewidth:1;this.linecap=a.linecap!==void 0?a.linecap:"round";this.linejoin=a.linejoin!==void 0?a.linejoin:"round";this.vertexColors=a.vertexColors?a.vertexColors:!1};THREE.LineBasicMaterial.prototype=new THREE.Material;
-THREE.LineBasicMaterial.prototype.constructor=THREE.LineBasicMaterial;
+0;this.alphaTest=a.alphaTest!==void 0?a.alphaTest:0};THREE.NoShading=0;THREE.FlatShading=1;THREE.SmoothShading=2;THREE.NoColors=0;THREE.FaceColors=1;THREE.VertexColors=2;THREE.NormalBlending=0;THREE.AdditiveBlending=1;THREE.SubtractiveBlending=2;THREE.MultiplyBlending=3;THREE.AdditiveAlphaBlending=4;THREE.MaterialCounter={value:0};THREE.CubeReflectionMapping=function(){};THREE.CubeRefractionMapping=function(){};THREE.LatitudeReflectionMapping=function(){};THREE.LatitudeRefractionMapping=function(){};
+THREE.SphericalReflectionMapping=function(){};THREE.SphericalRefractionMapping=function(){};THREE.UVMapping=function(){};THREE.LineBasicMaterial=function(a){THREE.Material.call(this,a);a=a||{};this.color=a.color!==void 0?new THREE.Color(a.color):new THREE.Color(16777215);this.linewidth=a.linewidth!==void 0?a.linewidth:1;this.linecap=a.linecap!==void 0?a.linecap:"round";this.linejoin=a.linejoin!==void 0?a.linejoin:"round";this.vertexColors=a.vertexColors?a.vertexColors:!1};
+THREE.LineBasicMaterial.prototype=new THREE.Material;THREE.LineBasicMaterial.prototype.constructor=THREE.LineBasicMaterial;
 THREE.MeshBasicMaterial=function(a){THREE.Material.call(this,a);a=a||{};this.color=a.color!==void 0?new THREE.Color(a.color):new THREE.Color(16777215);this.map=a.map!==void 0?a.map:null;this.lightMap=a.lightMap!==void 0?a.lightMap:null;this.envMap=a.envMap!==void 0?a.envMap:null;this.combine=a.combine!==void 0?a.combine:THREE.MultiplyOperation;this.reflectivity=a.reflectivity!==void 0?a.reflectivity:1;this.refractionRatio=a.refractionRatio!==void 0?a.refractionRatio:0.98;this.shading=a.shading!==
 void 0?a.shading:THREE.SmoothShading;this.wireframe=a.wireframe!==void 0?a.wireframe:!1;this.wireframeLinewidth=a.wireframeLinewidth!==void 0?a.wireframeLinewidth:1;this.wireframeLinecap=a.wireframeLinecap!==void 0?a.wireframeLinecap:"round";this.wireframeLinejoin=a.wireframeLinejoin!==void 0?a.wireframeLinejoin:"round";this.vertexColors=a.vertexColors!==void 0?a.vertexColors:!1;this.skinning=a.skinning!==void 0?a.skinning:!1;this.morphTargets=a.morphTargets!==void 0?a.morphTargets:!1};
 THREE.MeshBasicMaterial.prototype=new THREE.Material;THREE.MeshBasicMaterial.prototype.constructor=THREE.MeshBasicMaterial;

File diff suppressed because it is too large
+ 12 - 8
build/custom/ThreeExtras.js


+ 1 - 1
build/custom/ThreeSVG.js

@@ -76,7 +76,7 @@ THREE.Camera.prototype.update=function(a,b,c){if(this.useTarget)this.matrix.look
 THREE.AmbientLight.prototype.constructor=THREE.AmbientLight;THREE.DirectionalLight=function(a,b,c,d){THREE.Light.call(this,a);this.position=new THREE.Vector3(0,1,0);this.intensity=b||1;this.distance=c||0;this.castShadow=d!==void 0?d:!1};THREE.DirectionalLight.prototype=new THREE.Light;THREE.DirectionalLight.prototype.constructor=THREE.DirectionalLight;THREE.PointLight=function(a,b,c){THREE.Light.call(this,a);this.position=new THREE.Vector3;this.intensity=b||1;this.distance=c||0};
 THREE.PointLight.prototype=new THREE.Light;THREE.PointLight.prototype.constructor=THREE.PointLight;
 THREE.Material=function(a){this.id=THREE.MaterialCounter.value++;a=a||{};this.opacity=a.opacity!==void 0?a.opacity:1;this.transparent=a.transparent!==void 0?a.transparent:!1;this.blending=a.blending!==void 0?a.blending:THREE.NormalBlending;this.depthTest=a.depthTest!==void 0?a.depthTest:!0;this.polygonOffset=a.polygonOffset!==void 0?a.polygonOffset:!1;this.polygonOffsetFactor=a.polygonOffsetFactor!==void 0?a.polygonOffsetFactor:0;this.polygonOffsetUnits=a.polygonOffsetUnits!==void 0?a.polygonOffsetUnits:
-0};THREE.NoShading=0;THREE.FlatShading=1;THREE.SmoothShading=2;THREE.NoColors=0;THREE.FaceColors=1;THREE.VertexColors=2;THREE.NormalBlending=0;THREE.AdditiveBlending=1;THREE.SubtractiveBlending=2;THREE.MultiplyBlending=3;THREE.AdditiveAlphaBlending=4;THREE.MaterialCounter={value:0};
+0;this.alphaTest=a.alphaTest!==void 0?a.alphaTest:0};THREE.NoShading=0;THREE.FlatShading=1;THREE.SmoothShading=2;THREE.NoColors=0;THREE.FaceColors=1;THREE.VertexColors=2;THREE.NormalBlending=0;THREE.AdditiveBlending=1;THREE.SubtractiveBlending=2;THREE.MultiplyBlending=3;THREE.AdditiveAlphaBlending=4;THREE.MaterialCounter={value:0};
 THREE.LineBasicMaterial=function(a){THREE.Material.call(this,a);a=a||{};this.color=a.color!==void 0?new THREE.Color(a.color):new THREE.Color(16777215);this.linewidth=a.linewidth!==void 0?a.linewidth:1;this.linecap=a.linecap!==void 0?a.linecap:"round";this.linejoin=a.linejoin!==void 0?a.linejoin:"round";this.vertexColors=a.vertexColors?a.vertexColors:!1};THREE.LineBasicMaterial.prototype=new THREE.Material;THREE.LineBasicMaterial.prototype.constructor=THREE.LineBasicMaterial;
 THREE.MeshBasicMaterial=function(a){THREE.Material.call(this,a);a=a||{};this.color=a.color!==void 0?new THREE.Color(a.color):new THREE.Color(16777215);this.map=a.map!==void 0?a.map:null;this.lightMap=a.lightMap!==void 0?a.lightMap:null;this.envMap=a.envMap!==void 0?a.envMap:null;this.combine=a.combine!==void 0?a.combine:THREE.MultiplyOperation;this.reflectivity=a.reflectivity!==void 0?a.reflectivity:1;this.refractionRatio=a.refractionRatio!==void 0?a.refractionRatio:0.98;this.shading=a.shading!==
 void 0?a.shading:THREE.SmoothShading;this.wireframe=a.wireframe!==void 0?a.wireframe:!1;this.wireframeLinewidth=a.wireframeLinewidth!==void 0?a.wireframeLinewidth:1;this.wireframeLinecap=a.wireframeLinecap!==void 0?a.wireframeLinecap:"round";this.wireframeLinejoin=a.wireframeLinejoin!==void 0?a.wireframeLinejoin:"round";this.vertexColors=a.vertexColors!==void 0?a.vertexColors:!1;this.skinning=a.skinning!==void 0?a.skinning:!1;this.morphTargets=a.morphTargets!==void 0?a.morphTargets:!1};

File diff suppressed because it is too large
+ 11 - 11
build/custom/ThreeWebGL.js


+ 18 - 21
examples/canvas_geometry_text.html

@@ -20,11 +20,11 @@
 
 		<script type="text/javascript" src="js/RequestAnimationFrame.js"></script>
 		<script type="text/javascript" src="js/Stats.js"></script>
-		      
+
 		<!-- load the font file from canvas-text -->
 
 		<script type="text/javascript" src="fonts/helvetiker_regular.typeface.js"></script>
-        
+
 
 		<script type="text/javascript">
 
@@ -69,47 +69,44 @@
 				// Get text from hash
 
 				var theText = "Hello three.js! :)";
-				
+
 				var hash = document.location.hash.substr( 1 );
-				
+
 				if ( hash.length !== 0 ) {
-                   
+
 					theText = hash;
 
 				}
-                
-		var text3d = new THREE.TextGeometry( theText, {
 
-					size: 80, 
+				var text3d = new THREE.TextGeometry( theText, {
+
+					size: 80,
 					height: 20,
 					curveSegments: 2,
 					font: "helvetiker"
 
 				});
 
-                var textMaterial = new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff, wireframe:false } );
+				text3d.computeBoundingBox();
+				var centerOffset = -0.5 * ( text3d.boundingBox.x[ 1 ] - text3d.boundingBox.x[ 0 ] );
+
+                var textMaterial = new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff, wireframe: false } );
                 text = new THREE.Mesh( text3d, textMaterial );
 
                 text.doubleSided = false;
 
-                text.position.y = 0;
+                text.position.x = centerOffset;
                 text.position.y = 100;
                 text.position.z = 0;
 
                 text.rotation.x = 0;
-                text.rotation.y = Math.PI*2;
+                text.rotation.y = Math.PI * 2;
 				text.overdraw = true;
 
-                scene.addObject( text );
-
-				// Plane
-
-				plane = new THREE.Mesh( new THREE.PlaneGeometry( 800, 800 ), new THREE.MeshBasicMaterial( { color: 0xe0e0e0, wireframe:true }) );
-				plane.rotation.x = - 90 * ( Math.PI / 180 );
-                plane.position.x = 0;
-				plane.overdraw = true;
+				parent = new THREE.Object3D();
+                parent.addChild( text );
 
-				//scene.addObject( plane );
+				scene.addObject( parent );
 
 				renderer = new THREE.CanvasRenderer();
                 renderer.setSize( window.innerWidth, window.innerHeight );
@@ -205,7 +202,7 @@
 
 			function render() {
 
-				plane.rotation.z = text.rotation.y += ( targetRotation - text.rotation.y ) * 0.05;
+				parent.rotation.y += ( targetRotation - parent.rotation.y ) * 0.05;
 				renderer.render( scene, camera );
 
 			}

+ 49 - 9
examples/webgl_geometry_shapes.html

@@ -125,7 +125,7 @@
 
 				}
 
-				var extrudeSettings = {	amount: 20,  bevelEnabled: true, bevelSegments: 2, steps: 2 }; // amount: 40, steps: 2
+				var extrudeSettings = {	amount: 20,  bevelEnabled: true, bevelSegments: 2, steps: 2 }; // bevelSegments: 2, steps: 2 , bevelSegments: 5, bevelSize: 8, bevelThickness:5,
 
 				// California
 
@@ -266,12 +266,12 @@
 
 				var fishShape = new THREE.Shape();
 
-				fishShape.moveTo( x, y );
-				fishShape.quadraticCurveTo( x + 50, y + 80, x + 90, y + 10 );
-				fishShape.quadraticCurveTo( x + 100, y + 10, x + 115, y + 40 );
-				fishShape.quadraticCurveTo( x + 100, y, x + 115, y - 40 );
-				fishShape.quadraticCurveTo( x + 100, y + 10, x + 90, y - 10 );
-				fishShape.quadraticCurveTo( x + 50, y - 80, x, y );
+				fishShape.moveTo(x,y);
+				fishShape.quadraticCurveTo(x + 50, y - 80, x + 90, y - 10);
+				fishShape.quadraticCurveTo(x + 100, y - 10, x + 115, y - 40);
+				fishShape.quadraticCurveTo(x + 115, y, x + 115, y + 40);
+				fishShape.quadraticCurveTo(x + 100, y + 10, x + 90, y + 10);
+				fishShape.quadraticCurveTo(x + 50, y + 80, x, y);
 
 				var fish3d = fishShape.extrude( extrudeSettings );
 				var fishPoints = fishShape.createPointsGeometry();
@@ -291,6 +291,44 @@
 				var arc3d = arcShape.extrude( extrudeSettings );
 				var arcPoints = arcShape.createPointsGeometry();
 				var arcSpacedPoints = arcShape.createSpacedPointsGeometry();
+				
+				
+				// Smiley 
+
+				var smileyShape = new THREE.Shape();
+				smileyShape.moveTo( 0, 0 );
+				smileyShape.arc( 40, 40, 40, 0, Math.PI*2, false );
+
+				var smileyEye1Path = new THREE.Path();
+				smileyEye1Path.moveTo( 0, 0 );
+				smileyEye1Path.arc( 25, 20, 10, 0, Math.PI*2, true );
+				smileyShape.holes.push( smileyEye1Path );
+				
+				var smileyEye2Path = new THREE.Path();
+				smileyEye2Path.moveTo( 0, 0 );
+				smileyEye2Path.arc( 55, 20, 10, 0, Math.PI*2, true );
+				smileyShape.holes.push( smileyEye2Path );
+			
+				var smileyMouthPath = new THREE.Path();
+				// ugly box mouth
+				// smileyMouthPath.moveTo( 20, 40 );
+				// smileyMouthPath.lineTo( 60, 40 );
+				// smileyMouthPath.lineTo( 60, 60 );
+				// smileyMouthPath.lineTo( 20, 60 );
+				// smileyMouthPath.lineTo( 20, 40 );
+				
+				smileyMouthPath.moveTo( 20, 40 );
+				smileyMouthPath.quadraticCurveTo( 40, 60, 60, 40 );
+				smileyMouthPath.bezierCurveTo( 70, 45, 70, 50, 60, 60 );
+				smileyMouthPath.quadraticCurveTo( 40, 80, 20, 60 );
+				smileyMouthPath.quadraticCurveTo( 5, 50, 20, 40 );
+				
+				smileyShape.holes.push( smileyMouthPath );
+				
+				
+				var smiley3d = smileyShape.extrude( extrudeSettings );
+				var smileyPoints = smileyShape.createPointsGeometry();
+				var smileySpacedPoints = smileyShape.createSpacedPointsGeometry();
 
 				// Spline shape + path extrusion
 
@@ -326,10 +364,12 @@
 				addGeometry( square3d, squarePoints, squareSpacedPoints,				0x0055ff,  150,  100, 0,     0, 0, 0, 1 );
 				addGeometry( heart3d, heartPoints, heartSpacedPoints,					0xff1100,    0,  100, 0,   3.14, 0, 0, 1 );
 				addGeometry( circle3d, circlePoints, circleSpacedPoints,				0x00ff11,  120,  250, 0,     0, 0, 0, 1 );
-				addGeometry( fish3d, fishPoints, fishSpacedPoints,						0x222222,  -50,  200, 0,     0, 0, 0, 1 );
+				addGeometry( fish3d, fishPoints, fishSpacedPoints,						0x222222,  -60,  200, 0,     0, 0, 0, 1 );
 				addGeometry( splineShape3d, splinePoints, splineSpacedPoints,			0x888888,  -50,  -100, -50,  0, 0, 0, 0.2 );
 				addGeometry( arc3d, arcPoints, arcSpacedPoints,							0xbb4422,  150,    0, 0,     0, 0, 0, 1 );
-
+				addGeometry( smiley3d, smileyPoints, smileySpacedPoints,				0xee00ff,  -270,    250, 0,     Math.PI, 0, 0, 1 );
+			
+				
 				//
 
 				renderer = new THREE.WebGLRenderer( { antialias: true } );

+ 23 - 53
examples/webgl_geometry_text.html

@@ -84,6 +84,7 @@
 
 				bevelThickness = 2,
 				bevelSize = 1.5,
+				bevelSegments = 3,
 				bevelEnabled = true,
 
 				font = "optimer", 		// helvetiker, optimer, gentilis, droid sans, droid serif
@@ -204,55 +205,15 @@
 
 				}
 
-				textGeo = new THREE.TextGeometry( text, {
-
-					size: size,
-					height: height,
-					curveSegments: curveSegments,
-
-					font: font,
-					weight: weight,
-					style: style,
-
-					bevelThickness: bevelThickness,
-					bevelSize: bevelSize,
-					bevelEnabled: bevelEnabled
-
-				});
-
 				textMaterial = new THREE.MeshPhongMaterial( { color: 0xffffff, wireframe: false } );
 
 				parent = new THREE.Object3D();
-
-				textMesh1 = new THREE.Mesh( textGeo, textMaterial );
-
-				textMesh1.position.x = 0;
-				textMesh1.position.y = hover;
-				textMesh1.position.z = 0;
-
-				textMesh1.rotation.x = 0;
-				textMesh1.rotation.y = Math.PI * 2;
-
-				parent.addChild( textMesh1 );
-
-				if ( mirror ) {
-
-					textMesh2 = new THREE.Mesh( textGeo, textMaterial );
-
-					textMesh2.position.x = 0;
-					textMesh2.position.y = -hover;
-					textMesh2.position.z = height;
-
-					textMesh2.rotation.x = Math.PI;
-					textMesh2.rotation.y = Math.PI * 2;
-
-					parent.addChild( textMesh2 );
-
-				}
-
 				parent.position.y = 100;
+
 				scene.addChild( parent );
 
+				createText();
+
 				var plane = new THREE.Mesh( new THREE.PlaneGeometry( 10000, 10000 ), new THREE.MeshBasicMaterial( { color: 0xffffff, opacity: 0.5, transparent: true } ) );
 				plane.rotation.x = -1.57;
 				plane.position.y = 100;
@@ -414,11 +375,7 @@
 
 			}
 
-			function refreshText() {
-
-				updatePermalink();
-
-				scene.removeChild( textMesh1 );
+			function createText() {
 
 				textGeo = new THREE.TextGeometry( text, {
 
@@ -436,9 +393,12 @@
 
 				});
 
+				textGeo.computeBoundingBox();
+				var centerOffset = -0.5 * ( textGeo.boundingBox.x[ 1 ] - textGeo.boundingBox.x[ 0 ] );
+
 				textMesh1 = new THREE.Mesh( textGeo, textMaterial );
 
-				textMesh1.position.x = 0;
+				textMesh1.position.x = centerOffset;
 				textMesh1.position.y = hover;
 				textMesh1.position.z = 0;
 
@@ -449,24 +409,34 @@
 
 				if ( mirror ) {
 
-					scene.removeChild( textMesh2 );
-
 					textMesh2 = new THREE.Mesh( textGeo, textMaterial );
 
-					textMesh2.position.x = 0;
+					textMesh2.position.x = centerOffset;
 					textMesh2.position.y = -hover;
 					textMesh2.position.z = height;
 
 					textMesh2.rotation.x = Math.PI;
 					textMesh2.rotation.y = Math.PI * 2;
 
-
 					parent.addChild( textMesh2 );
 
 				}
 
 			}
 
+			function refreshText() {
+
+				updatePermalink();
+
+				scene.removeChild( textMesh1 );
+				if ( mirror ) scene.removeChild( textMesh2 );
+
+				if ( !text ) return;
+
+				createText();
+
+			}
+
 			function onDocumentMouseDown( event ) {
 
 				event.preventDefault();

+ 6 - 2
examples/webgl_shadowmap.html

@@ -188,21 +188,25 @@
 
 					size: 200,
 					height: 50,
-					curveSegments: 7,
+					curveSegments: 12,
 
 					font: "helvetiker",
 					weight: "bold",
 					style: "normal",
 
-					bevelThickness: 1,
+					bevelThickness: 2,
 					bevelSize: 5,
 					bevelEnabled: true
 
 				});
 
+				textGeo.computeBoundingBox();
+				var centerOffset = -0.5 * ( textGeo.boundingBox.x[ 1 ] - textGeo.boundingBox.x[ 0 ] );
+
 				var textMaterial = new THREE.MeshPhongMaterial( { color: 0xff0000, specular: 0xffffff, ambient: 0xaa0000 } );
 
 				var mesh = new THREE.Mesh( textGeo, textMaterial );
+				mesh.position.x = centerOffset;
 				mesh.position.y = FLOOR + 67;
 
 				mesh.castShadow = true;

+ 244 - 0
src/extras/GeometryUtils.js

@@ -179,6 +179,250 @@ THREE.GeometryUtils = {
 
 		return cloneGeo;
 
+	},
+
+	// Get random point in triangle (via barycentric coordinates)
+	// 	(uniform distribution)
+	// 	http://www.cgafaq.info/wiki/Random_Point_In_Triangle
+
+	randomPointInTriangle: function( vectorA, vectorB, vectorC ) {
+
+		var a, b, c,
+			point = new THREE.Vector3(),
+			tmp = THREE.GeometryUtils.__v1;
+
+		a = Math.random();
+		b = Math.random();
+
+		if ( ( a + b ) > 1 ) {
+
+			a = 1 - a;
+			b = 1 - b;
+
+		}
+
+		c = 1 - a - b;
+
+		point.copy( vectorA );
+		point.multiplyScalar( a );
+
+		tmp.copy( vectorB );
+		tmp.multiplyScalar( b );
+
+		point.addSelf( tmp );
+
+		tmp.copy( vectorC );
+		tmp.multiplyScalar( c );
+
+		point.addSelf( tmp );
+
+		return point;
+
+	},
+
+	// Get random point in face (triangle / quad)
+	// (uniform distribution)
+
+	randomPointInFace: function( face, geometry, useCachedAreas ) {
+
+		var vA, vB, vC, vD;
+
+		if ( face instanceof THREE.Face3 ) {
+
+			vA = geometry.vertices[ face.a ].position;
+			vB = geometry.vertices[ face.b ].position;
+			vC = geometry.vertices[ face.c ].position;
+
+			return THREE.GeometryUtils.randomPointInTriangle( vA, vB, vC );
+
+		} else if ( face instanceof THREE.Face4 ) {
+
+			vA = geometry.vertices[ face.a ].position;
+			vB = geometry.vertices[ face.b ].position;
+			vC = geometry.vertices[ face.c ].position;
+			vD = geometry.vertices[ face.d ].position;
+
+			var area1, area2;
+
+			if ( useCachedAreas ) {
+
+				if ( face._area1 && face._area2 ) {
+
+					area1 = face._area1;
+					area2 = face._area2;
+
+				} else {
+
+					area1 = THREE.GeometryUtils.triangleArea( vA, vB, vD );
+					area2 = THREE.GeometryUtils.triangleArea( vB, vC, vD );
+
+					face._area1 = area1;
+					face._area2 = area2;
+
+				}
+
+			} else {
+
+				area1 = THREE.GeometryUtils.triangleArea( vA, vB, vD ),
+				area2 = THREE.GeometryUtils.triangleArea( vB, vC, vD );
+
+			}
+
+			var r = Math.random() * ( area1 + area2 );
+
+			if ( r < area1 ) {
+
+				return THREE.GeometryUtils.randomPointInTriangle( vA, vB, vD );
+
+			} else {
+
+				return THREE.GeometryUtils.randomPointInTriangle( vB, vC, vD );
+
+			}
+
+		}
+
+	},
+
+	// Get uniformly distributed random points in mesh
+	// 	- create array with cumulative sums of face areas
+	//  - pick random number from 0 to total area
+	//  - find corresponding place in area array by binary search
+	//	- get random point in face
+
+	randomPointsInGeometry: function( geometry, n ) {
+
+		var face, i,
+			faces = geometry.faces,
+			vertices = geometry.vertices,
+			il = faces.length,
+			totalArea = 0,
+			cumulativeAreas = [],
+			vA, vB, vC, vD;
+
+		// precompute face areas
+
+		for ( i = 0; i < il; i ++ ) {
+
+			face = faces[ i ];
+
+			if ( face instanceof THREE.Face3 ) {
+
+				vA = vertices[ face.a ].position;
+				vB = vertices[ face.b ].position;
+				vC = vertices[ face.c ].position;
+
+				face._area = THREE.GeometryUtils.triangleArea( vA, vB, vC );
+
+			} else if ( face instanceof THREE.Face4 ) {
+
+				vA = vertices[ face.a ].position;
+				vB = vertices[ face.b ].position;
+				vC = vertices[ face.c ].position;
+				vD = vertices[ face.d ].position;
+
+				face._area1 = THREE.GeometryUtils.triangleArea( vA, vB, vD );
+				face._area2 = THREE.GeometryUtils.triangleArea( vB, vC, vD );
+
+				face._area = face._area1 + face._area2;
+
+			}
+
+			totalArea += face._area;
+
+			cumulativeAreas[ i ] = totalArea;
+
+		}
+
+		// binary search cumulative areas array
+
+		function binarySearchIndices( value ) {
+
+			function binarySearch( start, end ) {
+
+				// return closest larger index
+				// if exact number is not found
+
+				if ( end < start )
+					return start;
+
+				var mid = start + Math.floor( ( end - start ) / 2 );
+
+				if ( cumulativeAreas[ mid ] > value ) {
+
+					return binarySearch( start, mid - 1 );
+
+				} else if ( cumulativeAreas[ mid ] < value ) {
+
+					return binarySearch( mid + 1, end );
+
+				} else {
+
+					return mid;
+
+				}
+
+			}
+
+			var result = binarySearch( 0, cumulativeAreas.length - 1 )
+			return result;
+
+		}
+
+		// pick random face weighted by face area
+
+		var r, index,
+			result = [];
+
+		var stats = {};
+
+		for ( i = 0; i < n; i ++ ) {
+
+			r = Math.random() * totalArea;
+
+			index = binarySearchIndices( r );
+
+			result[ i ] = THREE.GeometryUtils.randomPointInFace( faces[ index ], geometry, true );
+
+			if ( ! stats[ index ] ) {
+
+				stats[ index ] = 1;
+
+			} else {
+
+				stats[ index ] += 1;
+
+			}
+
+		}
+
+		return result;
+
+	},
+
+	// Get triangle area (by Heron's formula)
+	// 	http://en.wikipedia.org/wiki/Heron%27s_formula
+
+	triangleArea: function( vectorA, vectorB, vectorC ) {
+
+		var s, a, b, c,
+			tmp = THREE.GeometryUtils.__v1;
+
+		tmp.sub( vectorA, vectorB );
+		a = tmp.length();
+
+		tmp.sub( vectorA, vectorC );
+		b = tmp.length();
+
+		tmp.sub( vectorB, vectorC );
+		c = tmp.length();
+
+		s = 0.5 * ( a + b + c );
+
+		return Math.sqrt( s * ( s - a ) * ( s - b ) * ( s - c ) );
+
 	}
 
 };
+
+THREE.GeometryUtils.__v1 = new THREE.Vector3();

+ 11 - 2
src/extras/ShaderUtils.js

@@ -1,6 +1,15 @@
 /**
  * @author alteredq / http://alteredqualia.com/
  * @author mr.doob / http://mrdoob.com/
+ *
+ * ShaderUtils currently contains
+ *	fresnel
+ *	normal
+ * 	cube
+ * 	convolution
+ * 	film
+ * 	screen
+ *	basic
  */
 
 if ( THREE.WebGLRenderer ) {
@@ -197,7 +206,7 @@ THREE.ShaderUtils = {
 
 					"#if MAX_POINT_LIGHTS > 0",
 
-						"vec4 pointTotal  = vec4( 0.0 );",
+						"vec4 pointTotal = vec4( vec3( 0.0 ), 1.0 );",
 
 						"for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {",
 
@@ -222,7 +231,7 @@ THREE.ShaderUtils = {
 
 					"#if MAX_DIR_LIGHTS > 0",
 
-						"vec4 dirTotal  = vec4( 0.0 );",
+						"vec4 dirTotal = vec4( vec3( 0.0 ), 1.0 );",
 
 						"for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {",
 

+ 83 - 8
src/extras/geometries/Curve.js

@@ -206,8 +206,8 @@ THREE.QuadraticBezierCurve.prototype.getPoint = function ( t ) {
 
 	var tx, ty;
 
-	tx = THREE.FontUtils.b2( t, this.x0, this.x1, this.x2 );
-	ty = THREE.FontUtils.b2( t, this.y0, this.y1, this.y2 );
+	tx = THREE.Shape.Utils.b2( t, this.x0, this.x1, this.x2 );
+	ty = THREE.Shape.Utils.b2( t, this.y0, this.y1, this.y2 );
 
 	return new THREE.Vector2( tx, ty );
 
@@ -270,8 +270,8 @@ THREE.CubicBezierCurve.prototype.getPoint = function ( t ) {
 
 	var tx, ty;
 
-	tx = THREE.FontUtils.b3( t, this.x0, this.x1, this.x2, this.x3 );
-	ty = THREE.FontUtils.b3( t, this.y0, this.y1, this.y2, this.y3 );
+	tx = THREE.Shape.Utils.b3( t, this.x0, this.x1, this.x2, this.x3 );
+	ty = THREE.Shape.Utils.b3( t, this.y0, this.y1, this.y2, this.y3 );
 
 	return new THREE.Vector2( tx, ty );
 
@@ -281,7 +281,7 @@ THREE.CubicBezierCurve.prototype.getPoint = function ( t ) {
  *	Spline curve
  **************************************************************/
 
-THREE.SplineCurve = function ( points ) {
+THREE.SplineCurve = function ( points /* array of Vector2*/ ) {
 
 	this.points = points;
 
@@ -392,8 +392,6 @@ THREE.Curve.Utils = {
 };
 
 
-
-
 /*
 getPoint DONE
 getLength DONE
@@ -403,4 +401,81 @@ curve.getPoints(); DONE
 curve.getPointAtArcLength(t); DONE
 curve.transform(params);
 curve.getTangentAt(t)
-*/
+*/
+
+/**************************************************************
+ *	3D Curves
+ **************************************************************/
+
+// A Factory method for creating new curve subclasses
+
+THREE.Curve.create = function( constructor, getPointFunc ) {
+
+    var subClass = constructor;
+
+	subClass.prototype = new THREE.Curve();
+
+	subClass.prototype.constructor = constructor;
+    subClass.prototype.getPoint = getPointFunc;
+
+	return subClass;
+
+};
+
+
+/**************************************************************
+ *	Line3D
+ **************************************************************/
+
+THREE.LineCurve3 = THREE.Curve.create(
+
+	function ( v1, v2 ) {
+
+		this.v1 = v1;
+		this.v2 = v2;
+
+	},
+
+	function ( t ) {
+
+		var r = new THREE.Vector3();
+
+
+		r.sub( v2, v1 ); // diff
+		r.multiplyScalar( t );
+		r.addSelf( this.v1 );
+
+		return r;
+
+	}
+
+);
+
+
+/**************************************************************
+ *	Quadratic Bezier 3D curve
+ **************************************************************/
+
+THREE.QuadraticBezierCurve3 = THREE.Curve.create(
+
+	function ( v0, v1, v2 ) { // Qn should we use 2 Vector3 instead?
+
+		this.v0 = v0;
+		this.v1 = v1;
+		this.v2 = v2;
+
+	},
+
+	function ( t ) {
+
+		var tx, ty, tz;
+
+		tx = THREE.Shape.Utils.b2( t, this.v0.x, this.v1.x, this.v2.x );
+		ty = THREE.Shape.Utils.b2( t, this.v0.y, this.v1.y, this.v2.y );
+		tz = THREE.Shape.Utils.b2( t, this.v0.z, this.v1.z, this.v2.z );
+
+		return new THREE.Vector3( tx, ty, tz );
+
+	}
+
+);

+ 322 - 70
src/extras/geometries/ExtrudeGeometry.js

@@ -1,23 +1,66 @@
 /**
  * @author zz85 / http://www.lab4games.net/zz85/blog
+ *
  * Creates extruded geometry from a path shape.
- **/
+ *
+ * parameters = {
+ *  size: 			<float>, 	// size of the text
+ *  height: 		<float>, 	// thickness to extrude text
+ *  curveSegments: 	<int>,		// number of points on the curves
+ *
+ *  font: 			<string>,		// font name
+ *  weight: 		<string>,		// font weight (normal, bold)
+ *  style: 			<string>,		// font style  (normal, italics)
+ *
+ *  bevelEnabled:	<bool>,			// turn on bevel
+ *  bevelThickness: <float>, 		// how deep into text bevel goes
+ *  bevelSize:		<float>, 		// how far from text outline is bevel
+ *  bevelSegments:	<int>, 			// number of bevel layers
+ *  }
+  **/
+
+THREE.ExtrudeGeometry = function( shapes, options ) {
+
+	if( typeof( shapes ) == "undefined" ) {
+
+		shapes = [];
+		return;
 
-THREE.ExtrudeGeometry = function ( shape, options ) {
+	}
 
-	var amount = options.amount !== undefined ? options.amount : 100;
+	THREE.Geometry.call( this );
 
-	// todo: bevel
+	shapes = shapes instanceof Array ? shapes : [ shapes ];
 
-	var bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 8; // 10
-	var bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness; // 8
-	var bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true; // false
-	var bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3;
+	var s, sl = shapes.length, shape;
+
+	for ( s = 0; s < sl; s ++ ) {
+
+		shape = shapes[ s ];
+
+		this.addShape( shape, options );
+
+	}
+
+};
+
+THREE.ExtrudeGeometry.prototype = new THREE.Geometry();
+THREE.ExtrudeGeometry.prototype.constructor = THREE.ExtrudeGeometry;
+
+
+THREE.ExtrudeGeometry.prototype.addShape = function( shape, options ) {
+
+	//var startTime = Date.now();
 
-	// We should set bevel segments to 0 if bevel is not enabled.
+	var amount = options.amount !== undefined ? options.amount : 100;
+
+	var bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 6; // 10
+	var bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 2; // 8
+	var bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3;
 
-	if ( !bevelEnabled ) bevelSegments = 0;
+	var bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true; // false
 
+	var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12;
 
 	var steps = options.steps !== undefined ? options.steps : 1;
 
@@ -26,16 +69,25 @@ THREE.ExtrudeGeometry = function ( shape, options ) {
 
 	if ( extrudePath ) {
 
-		extrudePts = extrudePath.getPoints();
+		extrudePts = extrudePath.getPoints( curveSegments );
 		steps = extrudePts.length;
 		extrudeByPath = true;
+		bevelEnabled = false; // bevels not supported for path extrusion
 
 	}
 
+	// Safeguards if bevels are not enabled
 
-	// TODO, extrude by path's tangents? also via 3d path?
+	if ( !bevelEnabled ) {
 
-	THREE.Geometry.call( this );
+		bevelSegments = 0;
+		bevelThickness = 0;
+		bevelSize = 0;
+
+	}
+
+
+	// TODO, extrude by path's tangents? also via 3d path?
 
 	// Variables initalization
 
@@ -43,7 +95,9 @@ THREE.ExtrudeGeometry = function ( shape, options ) {
 	var scope = this;
 	var bevelPoints = [];
 
-	var shapePoints = shape.extractAllPoints(); // use shape.extractAllSpacedPoints() for points with equal divisions
+	var shapesOffset = this.vertices.length;
+
+	var shapePoints = shape.extractAllPoints( curveSegments ); // use shape.extractAllSpacedPoints( curveSegments ) for points with equal divisions
 
     var vertices = shapePoints.shape;
 	var holes = shapePoints.holes;
@@ -56,7 +110,7 @@ THREE.ExtrudeGeometry = function ( shape, options ) {
 
 		// Maybe we should also check if holes are in the opposite direction, just to be safe ...
 
-		for ( h = 0, hl = holes.length;  h < hl; h ++ ) {
+		for ( h = 0, hl = holes.length; h < hl; h ++ ) {
 
 			ahole = holes[ h ];
 
@@ -92,78 +146,261 @@ THREE.ExtrudeGeometry = function ( shape, options ) {
 
 	}
 
-	// Find all centroids of shapes and holes
 
 	var i, il;
-	var sum = new THREE.Vector2();
 
-	for ( i = 0, il = contour.length; i < il; i ++ ) {
+	// We no longer need centroids
 
-		sum.addSelf( contour[ i ] );
+	// Find all centroids of shapes and holes
+
+	//var sum = new THREE.Vector2();
+
+	// for ( i = 0, il = contour.length; i < il; i ++ ) {
+	//
+	// 	sum.addSelf( contour[ i ] );
+	//
+	// }
+	//
+	// var contourCentroid = sum.divideScalar( contour.length );
+	//
+	// var holesCentroids = [];
+	//
+	// for ( h = 0, hl = holes.length; h < hl; h ++ ) {
+	//
+	// 	sum = new THREE.Vector2();
+	// 	ahole = holes[ h ];
+	//
+	// 	for ( i=0, il = ahole.length; i < il; i ++ ) {
+	//
+	// 		sum.addSelf( ahole[ i ] );
+	//
+	// 	}
+	//
+	// 	holesCentroids[ h ] = sum.divideScalar( ahole.length );
+	//
+	// }
+	//
+	// function scalePt ( pt, centroid, size, expandOutwards /* Boolean */ ) {
+	//
+	// 	var vectorFromCentroid = pt.clone().subSelf( centroid );
+	// 	var adj = size / vectorFromCentroid.length();
+	//
+	// 	if ( expandOutwards ) {
+	//
+	// 		adj = 1 + adj;
+	//
+	// 	}  else {
+	//
+	// 		adj = 1 - adj;
+	//
+	// 	}
+	//
+	// 	return vectorFromCentroid.multiplyScalar( adj ).addSelf( centroid );
+	//
+	// }
+
+
+	function scalePt2 ( pt, vec, size ) {
+
+		if ( !vec ) console.log( "die" );
+
+		return vec.clone().multiplyScalar( size ).addSelf( pt );
 
 	}
 
-	var contourCentroid = sum.divideScalar( contour.length );
+	var b, bs, t, z,
+		vert, vlen = vertices.length,
+		face, flen = faces.length,
+		cont, clen = contour.length;
+
 
-	var holesCentroids = [];
+	//------
+	// Find directions for point movement
+	//
 
-	for ( h = 0, hl = holes.length; h < hl; h ++ ) {
+	var RAD_TO_DEGREES = 180 / Math.PI;
 
-		sum = new THREE.Vector2();
-		ahole = holes[ h ];
 
-		for ( i=0, il = ahole.length; i < il; i ++ ) {
+	function getBevelVec( pt_i, pt_j, pt_k ) {
+
+		// Algorithm 2
+
+		return getBevelVec2( pt_i, pt_j, pt_k );
+
+	}
+
+	function getBevelVec1( pt_i, pt_j, pt_k ) {
+
+		var anglea = Math.atan2( pt_j.y - pt_i.y, pt_j.x - pt_i.x );
+		var angleb = Math.atan2( pt_k.y - pt_i.y, pt_k.x - pt_i.x );
+
+		if ( anglea > angleb ) {
 
-			sum.addSelf( ahole[ i ] );
+			angleb += Math.PI * 2;
 
 		}
 
-		holesCentroids[ h ] = sum.divideScalar( ahole.length );
+		anglec = ( anglea + angleb ) / 2;
+
+
+		//console.log('angle1', anglea * RAD_TO_DEGREES,'angle2', angleb * RAD_TO_DEGREES, 'anglec', anglec *RAD_TO_DEGREES);
+
+		var x = - Math.cos( anglec );
+		var y = - Math.sin( anglec );
+
+		var vec = new THREE.Vector2( x, y ); //.normalize();
+
+		return vec;
 
 	}
 
-	function scalePt ( pt, centroid, size, expandOutwards /* Boolean */ ) {
+	function getBevelVec2( pt_i, pt_j, pt_k ) {
+
+		var a = THREE.ExtrudeGeometry.__v1,
+			b = THREE.ExtrudeGeometry.__v2,
+			v_hat = THREE.ExtrudeGeometry.__v3,
+			w_hat = THREE.ExtrudeGeometry.__v4,
+			p = THREE.ExtrudeGeometry.__v5,
+			q = THREE.ExtrudeGeometry.__v6,
+			v, w,
+			v_dot_w_hat, q_sub_p_dot_w_hat,
+			s, intersection;
+
+		// good reading for line-line intersection
+		// http://sputsoft.com/blog/2010/03/line-line-intersection.html
+
+		// define a as vector j->i
+		// define b as vectot k->i
+
+		a.set( pt_i.x - pt_j.x, pt_i.y - pt_j.y );
+		b.set( pt_i.x - pt_k.x, pt_i.y - pt_k.y );
+
+		// get unit vectors
 
-		var vectorFromCentroid = pt.clone().subSelf( centroid );
-		var adj = size / vectorFromCentroid.length();
+		v = a.normalize();
+		w = b.normalize();
 
-		if ( expandOutwards ) {
+		// normals from pt i
 
-			adj = 1 + adj;
+		v_hat.set( -v.y, v.x );
+		w_hat.set( w.y, -w.x );
 
-		}  else {
+		// pts from i
 
-			adj = 1 - adj;
+		p.copy( pt_i ).addSelf( v_hat );
+		q.copy( pt_i ).addSelf( w_hat );
+
+		if ( p.equals( q ) ) {
+
+			//console.log("Warning: lines are straight");
+			return w_hat.clone();
+
+		}
+
+		// Points from j, k. helps prevents points cross overover most of the time
+
+		p.copy( pt_j ).addSelf( v_hat );
+		q.copy( pt_k ).addSelf( w_hat );
+
+		v_dot_w_hat = v.dot( w_hat );
+		q_sub_p_dot_w_hat = q.subSelf( p ).dot( w_hat );
+
+		// We should not reach these conditions
+
+		if ( v_dot_w_hat == 0 ) {
+
+			console.log( "Either infinite or no solutions!" );
+
+			if ( q_sub_p_dot_w_hat == 0 ) {
+
+				console.log( "Its finite solutions." );
+
+			} else {
+
+				console.log( "Too bad, no solutions." );
+
+			}
+
+		}
+
+		s = q_sub_p_dot_w_hat / v_dot_w_hat;
+
+		if ( s < 0 ) {
+
+			// in case of emergecy, revert to algorithm 1.
+			// console.log("opps");
+
+			return getBevelVec1( pt_i, pt_j, pt_k );
 
 		}
 
-		return vectorFromCentroid.multiplyScalar( adj ).addSelf( centroid );
+		intersection = v.multiplyScalar( s ).addSelf( p );
+
+		return intersection.subSelf( pt_i ).clone(); // Don't normalize!, otherwise sharp corners become ugly
 
 	}
 
+	var contourMovements = [];
+
+	for ( i = 0, il = contour.length, j = il-1, k = i + 1; i < il; i++, j++, k++ ) {
+
+		if ( j == il ) j = 0;
+		if ( k == il ) k = 0;
+
+		//  (j)---(i)---(k)
+		// console.log('i,j,k', i, j , k)
+
+		var pt_i = contour[ i ];
+		var pt_j = contour[ j ];
+		var pt_k = contour[ k ];
+
+		contourMovements[ i ]= getBevelVec( contour[ i ], contour[ j ], contour[ k ] );
+
+	}
+
+	var holesMovements = [], oneHoleMovements, verticesMovements = contourMovements.concat();
+
+	for ( h = 0, hl = holes.length; h < hl; h++ ) {
+
+		ahole = holes[ h ];
+
+		oneHoleMovements = [];
+
+		for ( i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i++, j++, k++ ) {
+
+			if ( j == il ) j = 0;
+			if ( k == il ) k = 0;
+
+			//  (j)---(i)---(k)
+			oneHoleMovements[ i ]= getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] );
+
+		}
+
+		holesMovements.push( oneHoleMovements );
+		verticesMovements = verticesMovements.concat( oneHoleMovements );
+
+	}
 
-	var b, bs, t, z,
-		vert, vlen = vertices.length,
-		face, flen = faces.length,
-		cont, clen = contour.length;
 
 	// Loop bevelSegments, 1 for the front, 1 for the back
 
-	for ( b = bevelSegments; b > 0; b -- ) {
+	for ( b = 0; b < bevelSegments; b ++ ) {
+	//for ( b = bevelSegments; b > 0; b -- ) {
 
 		t = b / bevelSegments;
-		z = bevelThickness * t;
-
-		// Formula could probably be simplified
+		z = bevelThickness * ( 1 - t );
 
-		bs = bevelSize * ( 1 - Math.sin ( ( 1 - t ) * Math.PI/2 ) ) ; // bevelSize * t ;
+		//z = bevelThickness * t;
+		bs = bevelSize * ( Math.sin ( t * Math.PI/2 ) ) ; // curved
+		//bs = bevelSize * t ; // linear
 
 		// contract shape
 
 		for ( i = 0, il = contour.length; i < il; i ++ ) {
 
-			vert = scalePt( contour[ i ], contourCentroid, bs, false );
-			v( vert.x, vert.y, -z );
+			vert = scalePt2( contour[ i ], contourMovements[ i ], bs );
+			//vert = scalePt( contour[ i ], contourCentroid, bs, false );
+			v( vert.x, vert.y,  - z );
 
 		}
 
@@ -172,10 +409,13 @@ THREE.ExtrudeGeometry = function ( shape, options ) {
 		for ( h = 0, hl = holes.length; h < hl; h++ ) {
 
 			ahole = holes[ h ];
+			oneHoleMovements = holesMovements[ h ];
 
 			for ( i = 0, il = ahole.length; i < il; i++ ) {
 
-				vert = scalePt( ahole[ i ], holesCentroids[ h ], bs, true );
+				vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );
+				//vert = scalePt( ahole[ i ], holesCentroids[ h ], bs, true );
+
 				v( vert.x, vert.y,  -z );
 
 			}
@@ -184,13 +424,13 @@ THREE.ExtrudeGeometry = function ( shape, options ) {
 
 	}
 
+	bs = bevelSize;
 
 	// Back facing vertices
 
 	for ( i = 0; i < vlen; i ++ ) {
 
-		vert = vertices[ i ];
-		//v( vert.x, vert.y, 0 );
+		vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];
 
 		if ( !extrudeByPath ) {
 
@@ -213,7 +453,7 @@ THREE.ExtrudeGeometry = function ( shape, options ) {
 
 		for ( i = 0; i < vlen; i ++ ) {
 
-			vert = vertices[ i ];
+			vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];
 
 			if ( !extrudeByPath ) {
 
@@ -232,30 +472,35 @@ THREE.ExtrudeGeometry = function ( shape, options ) {
 
 	// Add bevel segments planes
 
-	for ( b = 1; b <= bevelSegments; b ++ ) {
+	//for ( b = 1; b <= bevelSegments; b ++ ) {
+	for ( b = bevelSegments - 1; b >= 0; b -- ) {
 
 		t = b / bevelSegments;
-		z = bevelThickness * t;
-		bs = bevelSize * ( 1-Math.sin ( ( 1 - t ) * Math.PI/2 ) );
+		z = bevelThickness * ( 1 - t );
+		//bs = bevelSize * ( 1-Math.sin ( ( 1 - t ) * Math.PI/2 ) );
+		bs = bevelSize * Math.sin ( t * Math.PI/2 ) ;
 
 		// contract shape
 
-		for ( i = 0, il = contour.length; i < il; i++ ) {
+		for ( i = 0, il = contour.length; i < il; i ++ ) {
 
-			vert = scalePt( contour[ i ], contourCentroid, bs, false );
-			v( vert.x, vert.y,  amount + z);
+			vert = scalePt2( contour[ i ], contourMovements[ i ], bs );
+			//vert = scalePt( contour[ i ], contourCentroid, bs, false );
+			v( vert.x, vert.y,  amount + z );
 
 		}
 
 		// expand holes
 
-		for ( h = 0, hl = holes.length; h < hl; h++ ) {
+		for ( h = 0, hl = holes.length; h < hl; h ++ ) {
 
 			ahole = holes[ h ];
+			oneHoleMovements = holesMovements[ h ];
 
 			for ( i = 0, il = ahole.length; i < il; i++ ) {
 
-				vert = scalePt( ahole[ i ], holesCentroids[h], bs, true );
+				//vert = scalePt( ahole[ i ], holesCentroids[h], bs, true );
+				vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );
 
 				if ( !extrudeByPath ) {
 
@@ -263,7 +508,7 @@ THREE.ExtrudeGeometry = function ( shape, options ) {
 
 				} else {
 
-					v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x +z );
+					v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z );
 
 				}
 
@@ -380,11 +625,14 @@ THREE.ExtrudeGeometry = function ( shape, options ) {
 	}
 
 	// UVs to be added
+	// How can we create UVs on this?
 
 	this.computeCentroids();
 	this.computeFaceNormals();
 	//this.computeVertexNormals();
 
+	//console.log( "took", ( Date.now() - startTime ) );
+
 	function v( x, y, z ) {
 
 		scope.vertices.push( new THREE.Vertex( new THREE.Vector3( x, y, z ) ) );
@@ -393,20 +641,20 @@ THREE.ExtrudeGeometry = function ( shape, options ) {
 
 	function f3( a, b, c ) {
 
-		// if ( reverse ) { // Can now be removed
-		//
-		// 		scope.faces.push( new THREE.Face3( c, b, a ) );
-		//
-		// 	} else {
-		//
-		 		scope.faces.push( new THREE.Face3( a, b, c ) );
-		//
-		// 	}
+		a += shapesOffset;
+		b += shapesOffset;
+		c += shapesOffset;
+
+		scope.faces.push( new THREE.Face3( a, b, c ) );
 
 	}
 
 	function f4( a, b, c, d ) {
 
+		a += shapesOffset;
+		b += shapesOffset;
+		c += shapesOffset;
+		d += shapesOffset;
 
  		scope.faces.push( new THREE.Face4( a, b, c, d ) );
 
@@ -415,5 +663,9 @@ THREE.ExtrudeGeometry = function ( shape, options ) {
 };
 
 
-THREE.ExtrudeGeometry.prototype = new THREE.Geometry();
-THREE.ExtrudeGeometry.prototype.constructor = THREE.ExtrudeGeometry;
+THREE.ExtrudeGeometry.__v1 = new THREE.Vector2();
+THREE.ExtrudeGeometry.__v2 = new THREE.Vector2();
+THREE.ExtrudeGeometry.__v3 = new THREE.Vector2();
+THREE.ExtrudeGeometry.__v4 = new THREE.Vector2();
+THREE.ExtrudeGeometry.__v5 = new THREE.Vector2();
+THREE.ExtrudeGeometry.__v6 = new THREE.Vector2();

+ 129 - 37
src/extras/geometries/Path.js

@@ -149,21 +149,6 @@ THREE.Path.prototype.arc = function ( aX, aY, aRadius,
 
  };
 
-/*
-// FUTURE ENHANCEMENTS
-
- example usage?
-
- Path.addExprFunc('sineCurveTo', sineCurveGetPtFunction)
- Path.sineCurveTo(x,y, amptitude);
- sineCurve.getPoint(t);
- return sine(disnt) * ampt
-
- // Create a new func eg. sin (theta) x
- THREE.Path.prototype.addExprFunc = function(exprName, func) {
- };
-*/
-
 
 THREE.Path.prototype.getSpacedPoints = function ( divisions, closedPath ) {
 
@@ -251,8 +236,8 @@ THREE.Path.prototype.getPoints = function( divisions, closedPath ) {
 
 				t = j / divisions;
 
-				tx = THREE.FontUtils.b2( t, cpx0, cpx1, cpx );
-				ty = THREE.FontUtils.b2( t, cpy0, cpy1, cpy );
+				tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx );
+				ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy );
 
 				points.push( new THREE.Vector2( tx, ty ) );
 
@@ -292,8 +277,8 @@ THREE.Path.prototype.getPoints = function( divisions, closedPath ) {
 
 				t = j / divisions;
 
-				tx = THREE.FontUtils.b3( t, cpx0, cpx1, cpx2, cpx );
-				ty = THREE.FontUtils.b3( t, cpy0, cpy1, cpy2, cpy );
+				tx = THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx );
+				ty = THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy );
 
 				points.push( new THREE.Vector2( tx, ty ) );
 
@@ -384,7 +369,10 @@ THREE.Path.prototype.getPoints = function( divisions, closedPath ) {
 
 };
 
-THREE.Path.prototype.getMinAndMax = function () {
+
+// Returns min and max coordinates, as well as centroid
+
+THREE.Path.prototype.getBoundingBox = function () {
 
 	var points = this.getPoints();
 
@@ -394,7 +382,9 @@ THREE.Path.prototype.getMinAndMax = function () {
 	maxX = maxY = Number.NEGATIVE_INFINITY;
 	minX = minY = Number.POSITIVE_INFINITY;
 
-	var p, i, il;
+	var p, i, il, sum;
+
+	sum = new THREE.Vector2();
 
 	for ( i = 0, il = points.length; i < il; i ++ ) {
 
@@ -406,16 +396,17 @@ THREE.Path.prototype.getMinAndMax = function () {
 		if ( p.y > maxY ) maxY = p.y;
 		else if ( p.y < maxY ) minY = p.y;
 
-	}
+		sum.addSelf( p.x, p.y );
 
-	// TODO Include CG or find mid-pt?
+	}
 
 	return {
 
 		minX: minX,
 		minY: minY,
 		maxX: maxX,
-		maxY: maxY
+		maxY: maxY,
+		centroid: sum.divideScalar( il )
 
 	};
 
@@ -534,7 +525,7 @@ THREE.Path.prototype.transform = function( path ) {
 
 	console.log( path.cacheArcLengths() );
 
-	var thisBounds = this.getMinAndMax();
+	var thisBounds = this.getBoundingBox();
 	var oldPts = this.getPoints();
 
 	var i, il, p, oldX, oldY, xNorm;
@@ -605,7 +596,7 @@ THREE.Path.prototype.nltransform = function( a, b, c, d, e, f ) {
 
 THREE.Path.prototype.debug = function( canvas ) {
 
-	var bounds = this.getMinAndMax();
+	var bounds = this.getBoundingBox();
 
 	if ( !canvas ) {
 
@@ -681,10 +672,10 @@ THREE.Path.prototype.debug = function( canvas ) {
 
 	/* TO CLEAN UP */
 
-	//var p, points = this.getPoints();
+	var p, points = this.getPoints();
 
-	var theta = -90 /180 * Math.PI;
-	var p, points = this.transform( 0.866, - 0.866,0, 0.500 , 0.50,-50 );
+	//var theta = -90 /180 * Math.PI;
+	//var p, points = this.transform( 0.866, - 0.866,0, 0.500 , 0.50,-50 );
 
 	//0.866, - 0.866,0, 0.500 , 0.50,-50
 
@@ -693,14 +684,6 @@ THREE.Path.prototype.debug = function( canvas ) {
 
 	// translate, scale, rotation
 
-	// a - horizontal size
-	// b - lean
-	// c - x offset
-	// d - vertical size
-	// e - climb
-	// f - y offset
-	// 1,0,0,
-	// -1,0,100
 
 	for ( i = 0, il = points.length; i < il; i ++ ) {
 
@@ -714,3 +697,112 @@ THREE.Path.prototype.debug = function( canvas ) {
 	}
 
 };
+
+// Breaks path into shapes
+
+THREE.Path.prototype.toShapes = function() {
+
+	var i, il, item, action, args;
+
+	var subPaths = [], lastPath = new THREE.Path();
+
+	for ( i = 0, il = this.actions.length; i < il; i ++ ) {
+
+		item = this.actions[ i ];
+
+		args = item.args;
+		action = item.action;
+
+		if ( action == THREE.PathActions.MOVE_TO ) {
+
+			if ( lastPath.actions.length != 0 ) {
+
+				subPaths.push( lastPath );
+				lastPath = new THREE.Path();
+
+			}
+
+		}
+
+		lastPath[ action ].apply( lastPath, args );
+
+	}
+
+	if ( lastPath.actions.length != 0 ) {
+
+		subPaths.push( lastPath );
+
+	}
+
+	//console.log(subPaths);
+
+	if ( subPaths.length ==0 ) return [];
+
+	var holesFirst = !THREE.Shape.Utils.isClockWise( subPaths[ 0 ].getPoints() );
+
+	var tmpPath, tmpShape, shapes = [];
+
+	//console.log("Holes first", holesFirst);
+
+	if ( holesFirst ) {
+
+		tmpShape = new THREE.Shape();
+
+		for ( i = 0, il = subPaths.length; i < il; i ++ ) {
+
+			tmpPath = subPaths[ i ];
+
+			if ( THREE.Shape.Utils.isClockWise( tmpPath.getPoints() ) ) {
+
+				tmpShape.actions = tmpPath.actions;
+				tmpShape.curves = tmpPath.curves;
+
+				shapes.push( tmpShape );
+				tmpShape = new THREE.Shape();
+
+				//console.log('cw', i);
+
+			} else {
+
+				tmpShape.holes.push( tmpPath );
+
+				//console.log('ccw', i);
+
+			}
+
+		}
+
+	} else {
+
+		// Shapes first
+
+		for ( i = 0, il = subPaths.length; i < il; i ++ ) {
+
+			tmpPath = subPaths[ i ];
+
+			if ( THREE.Shape.Utils.isClockWise( tmpPath.getPoints() ) ) {
+
+
+				if ( tmpShape ) shapes.push( tmpShape );
+
+				tmpShape = new THREE.Shape();
+				tmpShape.actions = tmpPath.actions;
+				tmpShape.curves = tmpPath.curves;
+
+			} else {
+
+				tmpShape.holes.push( tmpPath );
+
+			}
+
+		}
+
+		shapes.push( tmpShape );
+
+	}
+
+	//console.log("shape", shapes);
+
+	return shapes;
+
+};

+ 129 - 36
src/extras/geometries/Shape.js

@@ -7,7 +7,7 @@
 // STEP 2 Turn path into shape.
 // STEP 3 ExtrudeGeometry takes in Shape/Shapes
 // STEP 3a - Extract points from each shape, turn to vertices
-// STEP 3b - Triangulate each shape
+// STEP 3b - Triangulate each shape, add faces.
 
 THREE.Shape = function ( ) {
 
@@ -30,13 +30,14 @@ THREE.Shape.prototype.extrude = function ( options ) {
 
 // Get points of holes
 
-THREE.Shape.prototype.getPointsHoles = function () {
+THREE.Shape.prototype.getPointsHoles = function ( divisions ) {
+
 
 	var i, il = this.holes.length, holesPts = [];
 
 	for ( i = 0; i < il; i ++ ) {
 
-		holesPts[ i ] = this.holes[ i ].getPoints();
+		holesPts[ i ] = this.holes[ i ].getPoints( divisions );
 
 	}
 
@@ -46,13 +47,13 @@ THREE.Shape.prototype.getPointsHoles = function () {
 
 // Get points of holes (spaced by regular distance)
 
-THREE.Shape.prototype.getSpacedPointsHoles = function () {
+THREE.Shape.prototype.getSpacedPointsHoles = function ( divisions ) {
 
 	var i, il = this.holes.length, holesPts = [];
 
 	for ( i = 0; i < il; i ++ ) {
 
-		holesPts[ i ] = this.holes[ i ].getSpacedPoints();
+		holesPts[ i ] = this.holes[ i ].getSpacedPoints( divisions );
 
 	}
 
@@ -60,14 +61,15 @@ THREE.Shape.prototype.getSpacedPointsHoles = function () {
 
 };
 
+
 // Get points of shape and holes (keypoints based on segments parameter)
 
-THREE.Shape.prototype.extractAllPoints = function () {
+THREE.Shape.prototype.extractAllPoints = function ( divisions ) {
 
 	return {
 
-		shape: this.getPoints(),
-		holes: this.getPointsHoles()
+		shape: this.getPoints( divisions ),
+		holes: this.getPointsHoles( divisions )
 
 	};
 
@@ -75,17 +77,21 @@ THREE.Shape.prototype.extractAllPoints = function () {
 
 // Get points of shape and holes (spaced by regular distance)
 
-THREE.Shape.prototype.extractAllSpacedPoints = function () {
+THREE.Shape.prototype.extractAllSpacedPoints = function ( divisions ) {
 
 	return {
 
-		shape: this.getSpacedPoints(),
-		holes: this.getSpacedPointsHoles()
+		shape: this.getSpacedPoints( divisions ),
+		holes: this.getSpacedPointsHoles( divisions )
 
 	};
 
 };
 
+/**************************************************************
+ *	Utils
+ **************************************************************/
+
 THREE.Shape.Utils = {
 
 	/*
@@ -113,7 +119,6 @@ THREE.Shape.Utils = {
 			verts = [];
 
 		for ( h = 0; h < holes.length; h++ ) {
-		//for ( h = holes.length; h-- > 0; ) {
 
 			hole = holes[ h ];
 
@@ -130,8 +135,9 @@ THREE.Shape.Utils = {
 
 			// Find the shortest pair of pts between shape and hole
 
-			// TODO we could optimize with
-			// http://en.wikipedia.org/wiki/Proximity_problems
+			// Note: Actually, I'm not sure now if we could optimize this to be faster than O(m*n)
+			// Using distanceToSquared() intead of distanceTo() should speed a little
+			// since running square roots operations are reduced.
 			// http://en.wikipedia.org/wiki/Closest_pair_of_points
 			// http://stackoverflow.com/questions/1602164/shortest-distance-between-points-algorithm
 
@@ -143,7 +149,7 @@ THREE.Shape.Utils = {
 				for ( p = 0; p < shape.length; p++ ) {
 
 					pts2 = shape[ p ];
-					d = pts1.distanceTo( pts2 );
+					d = pts1.distanceToSquared( pts2 );
 					dist.push( d );
 
 					if ( d < shortest ) {
@@ -297,24 +303,45 @@ THREE.Shape.Utils = {
 
 		// To maintain reference to old shape, one must match coordinates, or offset the indices from original arrays. It's probably easier to do the first.
 
-		//console.log("triangles",triangles, triangles.length);
-		//console.log("allpoints",allpoints, allpoints.length);
+		//console.log( "triangles",triangles, triangles.length );
+		//console.log( "allpoints",allpoints, allpoints.length );
+
+		var i, il, f, face,
+			key, index,
+			allPointsMap = {},
+			isolatedPointsMap = {};
 
-		var v, f, i, face;
+		// prepare all points map
 
-		for ( v = 0; v < triangles.length; v++ ) {
+		for ( i = 0, il = allpoints.length; i < il; i ++ ) {
 
-			face = triangles[ v ];
+			key = allpoints[ i ].x + ":" + allpoints[ i ].y;
 
-			for ( f = 0; f < 3; f++ ) { // For 3 pts in faces
+			if ( allPointsMap[ key ] !== undefined ) {
 
-				for ( i = 0; i < allpoints.length; i++ ) { // Go through all points
+				console.log( "Duplicate point", key );
 
-					if ( allpoints[ i ].equals( face[ f ] ) ) { // If matches
+			}
 
-						face[ f ] = i; // face now has reference to index
+			allPointsMap[ key ] = i;
 
-					}
+		}
+
+		// check all face vertices against all points map
+
+		for ( i = 0, il = triangles.length; i < il; i ++ ) {
+
+			face = triangles[ i ];
+
+			for ( f = 0; f < 3; f ++ ) {
+
+				key = face[ f ].x + ":" + face[ f ].y;
+
+				index = allPointsMap[ key ];
+
+				if ( index !== undefined ) {
+
+					face[ f ] = index;
 
 				}
 
@@ -322,19 +349,21 @@ THREE.Shape.Utils = {
 
 		}
 
-		for ( v = 0; v < isolatedPts.length; v++ ) {
+		// check isolated points vertices against all points map
 
-			face = isolatedPts[ v ];
+		for ( i = 0, il = isolatedPts.length; i < il; i ++ ) {
 
-			for ( f = 0; f < 3; f++ ) { // For 3 pts in faces
+			face = isolatedPts[ i ];
 
-				for ( i = 0; i < allpoints.length; i++ ) { // Go thru all points
+			for ( f = 0; f < 3; f ++ ) {
 
-					if ( allpoints[ i ].equals( face[ f ] ) ) { // If matches
+				key = face[ f ].x + ":" + face[ f ].y;
 
-						face[ f ] = i; // face now has reference to index
+				index = allPointsMap[ key ];
 
-					}
+				if ( index !== undefined ) {
+
+					face[ f ] = index;
 
 				}
 
@@ -342,7 +371,6 @@ THREE.Shape.Utils = {
 
 		}
 
-		//console.log("edited?" , triangles);
 		return triangles.concat( isolatedPts );
 
 	}, // end triangulate shapes
@@ -350,9 +378,8 @@ THREE.Shape.Utils = {
 	/*
 	triangulate2 : function( pts, holes ) {
 
-		// For use Poly2Tri.js
+		// For use with Poly2Tri.js
 
-		//var pts = this.getPoints();
 		var allpts = pts.concat();
 		var shape = [];
 		for (var p in pts) {
@@ -380,6 +407,7 @@ THREE.Shape.Utils = {
 			}
 			return -1;
 		};
+
 		// triangulate
 		js.poly2tri.sweep.Triangulate(swctx);
 
@@ -402,12 +430,77 @@ THREE.Shape.Utils = {
 		// Returns array of faces with 3 element each
 	return facesPts;
 	},
-	*/
+*/
 
 	isClockWise: function ( pts ) {
 
 		return THREE.FontUtils.Triangulate.area( pts ) < 0;
 
+	},
+
+	// Bezier Curves formulas obtained from
+	// http://en.wikipedia.org/wiki/B%C3%A9zier_curve
+
+	// Quad Bezier Functions
+
+	b2p0: function ( t, p ) {
+
+		var k = 1 - t;
+		return k * k * p;
+
+	},
+
+	b2p1: function ( t, p ) {
+
+		return 2 * ( 1 - t ) * t * p;
+
+	},
+
+	b2p2: function ( t, p ) {
+
+		return t * t * p;
+
+	},
+
+	b2: function ( t, p0, p1, p2 ) {
+
+		return this.b2p0( t, p0 ) + this.b2p1( t, p1 ) + this.b2p2( t, p2 );
+
+	},
+
+	// Cubic Bezier Functions
+
+	b3p0: function ( t, p ) {
+
+		var k = 1 - t;
+		return k * k * k * p;
+
+	},
+
+	b3p1: function ( t, p ) {
+
+		var k = 1 - t;
+		return 3 * k * k * t * p;
+
+	},
+
+	b3p2: function ( t, p ) {
+
+		var k = 1 - t;
+		return 3 * k * t * t * p;
+
+	},
+
+	b3p3: function ( t, p ) {
+
+		return t * t * t * p;
+
+	},
+
+	b3: function ( t, p0, p1, p2, p3 ) {
+
+		return this.b3p0( t, p0 ) + this.b3p1( t, p1 ) + this.b3p2( t, p2 ) +  this.b3p3( t, p3 );
+
 	}
 
 };

+ 61 - 387
src/extras/geometries/TextGeometry.js

@@ -37,229 +37,46 @@
 
 THREE.TextGeometry = function ( text, parameters ) {
 
-	THREE.Geometry.call( this );
+	var textPath = new THREE.TextPath( text, parameters );
+	var textShapes = textPath.toShapes();
 
-	this.parameters = parameters || {};
-	this.set( text );
+	// translate parameters to ExtrudeGeometry API
 
-};
-
-THREE.TextGeometry.prototype = new THREE.Geometry();
-THREE.TextGeometry.prototype.constructor = THREE.TextGeometry;
-
-THREE.TextGeometry.prototype.set = function ( text, parameters ) {
-
-	this.text = text;
-	var parameters = parameters || this.parameters;
-
-	var size = parameters.size !== undefined ? parameters.size : 100;
-	var height = parameters.height !== undefined ? parameters.height : 50;
-	var curveSegments = parameters.curveSegments !== undefined ? parameters.curveSegments: 4;
-
-	var font = parameters.font !== undefined ? parameters.font : "helvetiker";
-	var weight = parameters.weight !== undefined ? parameters.weight : "normal";
-	var style = parameters.style !== undefined ? parameters.style : "normal";
-
-	var bevelThickness = parameters.bevelThickness !== undefined ? parameters.bevelThickness : 10;
-	var bevelSize = parameters.bevelSize !== undefined ? parameters.bevelSize : 8;
-	var bevelEnabled = parameters.bevelEnabled !== undefined ? parameters.bevelEnabled : false;
-
-	THREE.FontUtils.size = size;
-	THREE.FontUtils.divisions = curveSegments;
-
-	THREE.FontUtils.face = font;
-	THREE.FontUtils.weight = weight;
-	THREE.FontUtils.style = style;
-
-	THREE.FontUtils.bevelSize = bevelSize;
-
-	// Get a Font data json object
-
-	var data = THREE.FontUtils.drawText( text );
-
-	var vertices = data.points;
-	var faces = data.faces;
-	var contour = data.contour;
-	var bevelPoints = data.bevel;
-
-	var scope = this;
-
-	scope.vertices = [];
-	scope.faces = [];
-
-	var i,
-		vert, vlen = vertices.length,
-		face, flen = faces.length,
-		bevelPt, blen = bevelPoints.length;
-
-	// Back facing vertices
-
-	for ( i = 0; i < vlen; i++ ) {
-
-		vert = vertices[ i ];
-		v( vert.x, vert.y, 0 );
-
-	}
-
-	// Front facing vertices
-
-	for ( i = 0; i < vlen; i++ ) {
-
-		vert = vertices[ i ];
-		v( vert.x, vert.y, height );
-
-	}
-
-	if ( bevelEnabled ) {
-
-		for ( i = 0; i < blen; i++ ) {
-
-			bevelPt = bevelPoints[ i ];
-			v( bevelPt.x, bevelPt.y, bevelThickness );
-
-		}
-
-		for ( i = 0; i < blen; i++ ) {
-
-			bevelPt = bevelPoints[ i ];
-			v( bevelPt.x, bevelPt.y, height - bevelThickness );
-
-		}
-
-	}
-
-	// Bottom faces
-
-	for ( i = 0; i < flen; i++ ) {
-
-		face = faces[ i ];
-		f3( face[ 2 ], face[ 1 ], face[ 0 ] );
-
-	}
-
-	// Top faces
-
-	for ( i = 0; i < flen; i++ ) {
-
-		face = faces[ i ];
-		f3( face[ 0 ] + vlen, face[ 1 ] + vlen, face[ 2 ] + vlen );
-
-	}
-
-	var lastV;
-	var j, k, l, m;
-
-	if ( bevelEnabled ) {
-
-		i = bevelPoints.length;
+	parameters.amount = parameters.height !== undefined ? parameters.height : 50;
 
-		while ( --i > 0 ) {
+	// defaults
 
-			if ( !lastV ) {
+	if ( parameters.bevelThickness === undefined ) parameters.bevelThickness = 10;
+	if ( parameters.bevelSize === undefined ) parameters.bevelSize = 8;
+	if ( parameters.bevelEnabled === undefined ) parameters.bevelEnabled = false;
 
-				lastV = contour[ i ];
+	THREE.ExtrudeGeometry.call( this, textShapes, parameters );
 
-			} else if ( lastV.equals( contour[ i ] ) ) {
-
-				// We reached the last point of a closed loop
-
-				lastV = null;
-				continue;
-
-			}
-
-			l = vlen * 2 + i;
-			m = l - 1;
-
-			// Create faces for the z-sides of the text
-
-			f4( l, m, m + blen, l + blen );
-
-			for ( j = 0; j < vlen; j++ ) {
-
-				if ( vertices[ j ].equals( contour[ i ] ) ) break;
-
-			}
-
-			for ( k = 0; k < vlen; k++ ) {
-
-				if ( vertices[ k ].equals( contour[ i - 1 ] ) ) break;
-
-			}
-
-			// Create faces for the z-sides of the text
-
-			f4( j, k, m, l );
-			f4( l + blen, m + blen, k + vlen, j + vlen );
-
-		}
-
-	} else {
-
-		i = contour.length;
-
-		while ( --i > 0 ) {
-
-			if ( !lastV ) {
-
-				lastV = contour[ i ];
-
-			} else if ( lastV.equals( contour[ i ] ) ) {
-
-				// We reached the last point of a closed loop
-
-				lastV = null;
-				continue;
-
-			}
-
-			for ( j = 0; j < vlen; j++ ) {
-
-				if ( vertices[ j ].equals( contour[ i ] ) ) break;
-
-			}
-
-			for ( k = 0; k < vlen; k++ ) {
-
-				if ( vertices[ k ].equals( contour[ i - 1 ] ) ) break;
-
-			}
-
-			// Create faces for the z-sides of the text
-
-			f4( j, k, k + vlen, j + vlen );
-
-		}
-	}
-
-
-	// UVs to be added
-
-	this.computeCentroids();
-	this.computeFaceNormals();
-	//this.computeVertexNormals();
+};
 
-	function v( x, y, z ) {
+THREE.TextGeometry.prototype = new THREE.ExtrudeGeometry();
+THREE.TextGeometry.prototype.constructor = THREE.TextGeometry;
 
-		scope.vertices.push( new THREE.Vertex( new THREE.Vector3( x, y, z ) ) );
 
-	}
+/*
+	// TextGeometry wrapper
 
-	function f3( a, b, c ) {
+	var text3d = new TextGeometry( text, options );
 
-		scope.faces.push( new THREE.Face3( a, b, c ) );
+	// Complete manner
 
-	}
+	var textPath = new TextPath( text, options );
+	var textShapes = textPath.toShapes();
+	var text3d = new ExtrudeGeometry( textShapes, options );
 
-	function f4( a, b, c, d ) {
+	// Factory Method
 
-		scope.faces.push( new THREE.Face4( a, b, c, d ) );
+	var textShapes = FontUtils.getTextShapes( text, options );
+	text3d = new ExtrudeGeometry( textShapes, options );
 
-	}
+*/
 
 
-};
-
 THREE.FontUtils = {
 
 	faces : {},
@@ -278,6 +95,14 @@ THREE.FontUtils = {
 
 	},
 
+	getTextShapes: function( text, options ) {
+
+		var textPath = new TextPath( text, options );
+		var textShapes = textPath.toShapes();
+		return textShapes;
+
+	},
+
 	loadFace : function( data ) {
 
 		var family = data.familyName.toLowerCase();
@@ -295,6 +120,7 @@ THREE.FontUtils = {
 
 	},
 
+/* LEGACY CODE
 
 	extractPoints : function( allPoints, charactersPoints ) {
 
@@ -414,7 +240,7 @@ THREE.FontUtils = {
 
 		//console.log("isolatedShapes", isolatedShapes);
 
-		/* For each isolated shape, find the closest points and break to the hole to allow triangulation*/
+		// For each isolated shape, find the closest points and break to the hole to allow triangulation
 
 		// Find closest points between holes
 
@@ -649,7 +475,7 @@ THREE.FontUtils = {
 
 		};
 
-	},
+	},*/
 
 	drawText : function( text ) {
 
@@ -666,200 +492,45 @@ THREE.FontUtils = {
 
 		var fontPaths = [];
 
-		var path = new THREE.Path();
-		for ( i = 0; i < length; i++ ) {
+		for ( i = 0; i < length; i ++ ) {
+
+			var path = new THREE.Path();
 
 			var ret = this.extractGlyphPoints( chars[ i ], face, scale, offset, path );
 			offset += ret.offset;
-			characterPts.push( ret.points );
-			allPts = allPts.concat( ret.points );
-			//fontPaths.push( ret.path );
+			//characterPts.push( ret.points );
+			//allPts = allPts.concat( ret.points );
+			fontPaths.push( ret.path );
 
 		}
 
-		//path.debug(document.getElementById("boo"));
-		//console.log(path);
-
-
 		// get the width
 
 		var width = offset / 2;
+		//
+		// for ( p = 0; p < allPts.length; p++ ) {
+		//
+		// 	allPts[ p ].x -= width;
+		//
+		// }
 
-		for ( p = 0; p < allPts.length; p++ ) {
-
-			allPts[ p ].x -= width;
-
-		}
-
-		var extract = this.extractPoints( allPts, characterPts );
-		extract.contour = allPts;
-
-		var bevelPoints = [];
-
-		var centroids = [], forCentroids = [], expandOutwards = [], sum = new THREE.Vector2(), lastV;
-
-		i = allPts.length;
-
-		while ( --i >= 0 ) {
-
-			if ( !lastV ) {
-
-				lastV = allPts[ i ];
-
-			} else if ( lastV.equals( allPts[ i ] ) ) {
-
-				// We reached the last point of a closed loop
-
-				lastV = null;
-
-				var bool = this.Triangulate.area( forCentroids ) > 0;
-				expandOutwards.push( bool );
-				centroids.push( sum.divideScalar( forCentroids.length ) );
-				forCentroids = [];
-
-				sum = new THREE.Vector2();
-				continue;
-
-			}
-
-			sum.addSelf( allPts[ i ] );
-			forCentroids.push( allPts[ i ] );
-
-		}
-
-
-		i = allPts.length;
-		p = 0;
-		var pt, centroid ;
-		var dirV, adj;
-
-		while ( --i >= 0 ) {
-
-			pt = allPts[ i ];
-			centroid = centroids[ p ];
-
-			dirV = pt.clone().subSelf( centroid );
-			adj = this.bevelSize / dirV.length();
-
-			if ( expandOutwards[ p ] ) {
-
-				adj += 1;
-
-			}  else {
-
-				adj = 1 - adj;
-
-			}
-
-			adj = dirV.multiplyScalar( adj ).addSelf( centroid );
-			bevelPoints.unshift( adj );
-
-
-			if ( !lastV ) {
-
-				lastV = allPts[ i ];
-
-			} else if ( lastV.equals( allPts[ i ] ) ) {
-
-				// We reached the last point of a closed loop
-
-				lastV = null;
-				p++;
-				continue;
-
-			}
-
-		}
-
-
-		/*
-		for ( p = 0; p < allPts.length; p++ ) {
-
-			pt = allPts[ p ];
-			bevelPoints.push( new THREE.Vector2( pt.x + this.bevelSize, pt.y + this.bevelSize ) );
-
-		}
-		*/
-
-		extract.bevel = bevelPoints;
-
-		return extract;
-
-	},
-
-
-	// Bezier Curves formulas obtained from
-	// http://en.wikipedia.org/wiki/B%C3%A9zier_curve
-
-	// Quad Bezier Functions
-
-	b2p0: function ( t, p ) {
-
-		var k = 1 - t;
-		return k * k * p;
-
-	},
-
-	b2p1: function ( t, p ) {
-
-		return 2 * ( 1 - t ) * t * p;
-
-	},
-
-	b2p2: function ( t, p ) {
-
-		return t * t * p;
-
-	},
+		//var extract = this.extractPoints( allPts, characterPts );
+		//extract.contour = allPts;
 
-	b2: function ( t, p0, p1, p2 ) {
+		//extract.paths = fontPaths;
+		//extract.offset = width;
 
-		return this.b2p0( t, p0 ) + this.b2p1( t, p1 ) + this.b2p2( t, p2 );
+		return { paths : fontPaths, offset : width };
 
 	},
 
-	// Cubic Bezier Functions
-
-	b3p0: function ( t, p ) {
-
-		var k = 1 - t;
-		return k * k * k * p;
-
-	},
-
-	b3p1: function ( t, p ) {
-
-		var k = 1 - t;
-		return 3 * k * k * t * p;
-
-	},
-
-	b3p2: function ( t, p ) {
-
-		var k = 1 - t;
-		return 3 * k * t * t * p;
-
-	},
 
-	b3p3: function ( t, p ) {
-
-		return t * t * t * p;
-
-	},
-
-	b3: function ( t, p0, p1, p2, p3 ) {
-
-		return this.b3p0( t, p0 ) + this.b3p1( t, p1 ) + this.b3p2( t, p2 ) +  this.b3p3( t, p3 );
-
-	},
 
 
 	extractGlyphPoints : function( c, face, scale, offset, path ) {
 
 		var pts = [];
 
-
-
 		var i, i2,
 			outline, action, length,
 			scaleX, scaleY,
@@ -879,8 +550,10 @@ THREE.FontUtils = {
 
 			for ( i = 0; i < length; ) {
 
-				action = outline[ i++ ];
-				//console.log(action);
+				action = outline[ i ++ ];
+
+				//console.log( action );
+
 				switch( action ) {
 
 				case 'm':
@@ -889,9 +562,10 @@ THREE.FontUtils = {
 
 					x = outline[ i++ ] * scaleX + offset;
 					y = outline[ i++ ] * scaleY;
+
 					pts.push( new THREE.Vector2( x, y ) );
 
-					path.moveTo(x,y);
+					path.moveTo( x, y );
 					break;
 
 				case 'l':
@@ -925,8 +599,8 @@ THREE.FontUtils = {
 						for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2++ ) {
 
 							var t = i2 / divisions;
-							var tx = THREE.FontUtils.b2( t, cpx0, cpx1, cpx );
-							var ty = THREE.FontUtils.b2( t, cpy0, cpy1, cpy );
+							var tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx );
+							var ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy );
 							pts.push( new THREE.Vector2( tx, ty ) );
 
 					  }
@@ -958,8 +632,8 @@ THREE.FontUtils = {
 						for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2++ ) {
 
 							var t = i2 / divisions;
-							var tx = THREE.FontUtils.b3( t, cpx0, cpx1, cpx2, cpx );
-							var ty = THREE.FontUtils.b3( t, cpy0, cpy1, cpy2, cpy );
+							var tx = THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx );
+							var ty = THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy );
 							pts.push( new THREE.Vector2( tx, ty ) );
 
 						}

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

@@ -0,0 +1,68 @@
+/**
+ * @author zz85 / http://www.lab4games.net/zz85/blog
+ *
+ * TextPath
+ *
+ **/
+
+THREE.TextPath = function ( text, parameters ) {
+
+	THREE.Path.call( this );
+
+	this.parameters = parameters || {};
+
+	this.set( text );
+
+};
+
+THREE.TextPath.prototype.set = function ( text, parameters ) {
+
+	this.text = text;
+
+	var parameters = parameters || this.parameters;
+
+	var size = parameters.size !== undefined ? parameters.size : 100;
+	var curveSegments = parameters.curveSegments !== undefined ? parameters.curveSegments: 4;
+
+	var font = parameters.font !== undefined ? parameters.font : "helvetiker";
+	var weight = parameters.weight !== undefined ? parameters.weight : "normal";
+	var style = parameters.style !== undefined ? parameters.style : "normal";
+
+	THREE.FontUtils.size = size;
+	THREE.FontUtils.divisions = curveSegments;
+
+	THREE.FontUtils.face = font;
+	THREE.FontUtils.weight = weight;
+	THREE.FontUtils.style = style;
+
+};
+
+
+
+THREE.TextPath.prototype.toShapes = function () {
+
+	// Get a Font data json object
+
+	var data = THREE.FontUtils.drawText( this.text );
+
+	var paths = data.paths;
+	var shapes = [];
+
+	for ( var p = 0, pl = paths.length; p < pl; p ++ ) {
+
+		shapes = shapes.concat( paths[ p ].toShapes() );
+
+	}
+
+	return shapes;
+
+	//console.log(path);
+	//console.log(fontShapes);
+
+	// Either find actions or curves.
+
+	//var text3d = new THREE.ExtrudeGeometry( shapes , { amount: 20, bevelEnabled:true, bevelThickness:3	} );
+
+	//return text3d;
+
+};

+ 31 - 0
src/materials/DataTexture.js

@@ -0,0 +1,31 @@
+/**
+ * @author alteredq / http://alteredqualia.com/
+ */
+
+THREE.DataTexture = function ( data, width, height, format, mapping, wrapS, wrapT, magFilter, minFilter ) {
+
+	THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter );
+
+	this.image = { data: data, width: width, height: height };
+
+	this.format = format !== undefined ? format : THREE.RGBAFormat;
+
+};
+
+THREE.DataTexture.prototype = new THREE.Texture();
+THREE.DataTexture.prototype.constructor = THREE.DataTexture;
+
+THREE.DataTexture.prototype = {
+
+	clone: function () {
+
+		var clonedTexture = new THREE.DataTexture( this.data.slice( 0 ), this.mapping, this.wrapS, this.wrapT, this.magFilter, this.minFilter );
+
+		clonedTexture.offset.copy( this.offset );
+		clonedTexture.repeat.copy( this.repeat );
+
+		return clonedTexture;
+
+	}
+
+};

+ 2 - 0
src/materials/Material.js

@@ -18,6 +18,8 @@ THREE.Material = function ( parameters ) {
 	this.polygonOffsetFactor = parameters.polygonOffsetFactor !== undefined ? parameters.polygonOffsetFactor : 0;
 	this.polygonOffsetUnits = parameters.polygonOffsetUnits !== undefined ? parameters.polygonOffsetUnits : 0;
 
+	this.alphaTest = parameters.alphaTest !== undefined ? parameters.alphaTest : 0;
+
 }
 
 THREE.NoShading = 0;

+ 23 - 15
src/renderers/WebGLRenderer.js

@@ -2650,7 +2650,8 @@ THREE.WebGLRenderer = function ( parameters ) {
 			shadowMapSoft: this.shadowMapSoft,
 			shadowMapWidth: this.shadowMapWidth,
 			shadowMapHeight: this.shadowMapHeight,
-			maxShadows: maxShadows
+			maxShadows: maxShadows,
+			alphaTest: material.alphaTest
 
 		};
 
@@ -5137,6 +5138,8 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 			"#define MAX_SHADOWS " + parameters.maxShadows,
 
+			parameters.alphaTest ? "#define ALPHATEST " + parameters.alphaTest: "",
+
 			parameters.fog ? "#define USE_FOG" : "",
 			parameters.fog instanceof THREE.FogExp2 ? "#define FOG_EXP2" : "",
 
@@ -5433,22 +5436,22 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 		if ( texture.needsUpdate ) {
 
-			if ( !texture.__webglInit ) {
+			if ( ! texture.__webglInit ) {
 
 				texture.__webglTexture = _gl.createTexture();
+				texture.__webglInit = true;
 
-				_gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
-				// _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, true );
-				_gl.texImage2D( _gl.TEXTURE_2D, 0, _gl.RGBA, _gl.RGBA, _gl.UNSIGNED_BYTE, texture.image );
+			}
 
-				texture.__webglInit = true;
+			_gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
+
+			if ( texture.image.data ) {
+
+				_gl.texImage2D( _gl.TEXTURE_2D, 0, paramThreeToGL( texture.format ), texture.image.width, texture.image.height, 0, paramThreeToGL( texture.format ), _gl.UNSIGNED_BYTE, texture.image.data );
 
 			} else {
 
-				_gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
-				// _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, true );
 				_gl.texImage2D( _gl.TEXTURE_2D, 0, _gl.RGBA, _gl.RGBA, _gl.UNSIGNED_BYTE, texture.image );
-				// _gl.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, _gl.RGBA, _gl.UNSIGNED_BYTE, texture.image );
 
 			}
 
@@ -5463,16 +5466,21 @@ THREE.WebGLRenderer = function ( parameters ) {
 		/*
 		if ( texture.needsUpdate ) {
 
-			if ( texture.__webglTexture ) {
+			if ( !texture.__webglInit ) {
 
-				texture.__webglTexture = _gl.deleteTexture( texture.__webglTexture );
+				texture.__webglTexture = _gl.createTexture();
 
-			}
+				_gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
+				_gl.texImage2D( _gl.TEXTURE_2D, 0, _gl.RGBA, _gl.RGBA, _gl.UNSIGNED_BYTE, texture.image );
 
-			texture.__webglTexture = _gl.createTexture();
+				texture.__webglInit = true;
 
-			_gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
-			_gl.texImage2D( _gl.TEXTURE_2D, 0, _gl.RGBA, _gl.RGBA, _gl.UNSIGNED_BYTE, texture.image );
+			} else {
+
+				_gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
+				 _gl.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, _gl.RGBA, _gl.UNSIGNED_BYTE, texture.image );
+
+			}
 
 			setTextureParameters( _gl.TEXTURE_2D, texture, texture.image );
 

+ 37 - 7
src/renderers/WebGLShaders.js

@@ -340,8 +340,8 @@ THREE.ShaderChunk = {
 
 	"#if MAX_POINT_LIGHTS > 0",
 
-		"vec4 pointDiffuse  = vec4( 0.0 );",
-		"vec4 pointSpecular = vec4( 0.0 );",
+		"vec4 pointDiffuse  = vec4( vec3( 0.0 ), 1.0 );",
+		"vec4 pointSpecular = vec4( vec3( 0.0 ), 1.0 );",
 
 		"for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {",
 
@@ -366,8 +366,8 @@ THREE.ShaderChunk = {
 
 	"#if MAX_DIR_LIGHTS > 0",
 
-		"vec4 dirDiffuse  = vec4( 0.0 );",
-		"vec4 dirSpecular = vec4( 0.0 );" ,
+		"vec4 dirDiffuse  = vec4( vec3( 0.0 ), 1.0 );",
+		"vec4 dirSpecular = vec4( vec3( 0.0 ), 1.0 );" ,
 
 		"for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {",
 
@@ -658,6 +658,18 @@ THREE.ShaderChunk = {
 
 	].join("\n"),
 
+	// ALPHATEST
+
+	alphatest_fragment: [
+
+	"#ifdef ALPHATEST",
+
+		"if ( gl_FragColor.a < ALPHATEST ) discard;",
+
+	"#endif"
+
+	].join("\n")
+
 };
 
 THREE.UniformsUtils = {
@@ -1208,6 +1220,7 @@ THREE.ShaderLib = {
 				"gl_FragColor = vec4( diffuse, opacity );",
 
 				THREE.ShaderChunk[ "map_fragment" ],
+				THREE.ShaderChunk[ "alphatest_fragment" ],
 				THREE.ShaderChunk[ "lightmap_fragment" ],
 				THREE.ShaderChunk[ "color_fragment" ],
 				THREE.ShaderChunk[ "envmap_fragment" ],
@@ -1275,9 +1288,12 @@ THREE.ShaderLib = {
 			"void main() {",
 
 				"gl_FragColor = vec4( diffuse, opacity );",
-				"gl_FragColor = gl_FragColor * vec4( vLightWeighting, 1.0 );",
 
 				THREE.ShaderChunk[ "map_fragment" ],
+				THREE.ShaderChunk[ "alphatest_fragment" ],
+
+				"gl_FragColor = gl_FragColor * vec4( vLightWeighting, 1.0 );",
+
 				THREE.ShaderChunk[ "lightmap_fragment" ],
 				THREE.ShaderChunk[ "color_fragment" ],
 				THREE.ShaderChunk[ "envmap_fragment" ],
@@ -1364,9 +1380,12 @@ THREE.ShaderLib = {
 			"void main() {",
 
 				"gl_FragColor = vec4( vLightWeighting, 1.0 );",
-				THREE.ShaderChunk[ "lights_fragment" ],
 
 				THREE.ShaderChunk[ "map_fragment" ],
+				THREE.ShaderChunk[ "alphatest_fragment" ],
+
+				THREE.ShaderChunk[ "lights_fragment" ],
+
 				THREE.ShaderChunk[ "lightmap_fragment" ],
 				THREE.ShaderChunk[ "color_fragment" ],
 				THREE.ShaderChunk[ "envmap_fragment" ],
@@ -1428,7 +1447,12 @@ THREE.ShaderLib = {
 
 	'particle_basic': {
 
-		uniforms: THREE.UniformsLib[ "particle" ],
+		uniforms:  THREE.UniformsUtils.merge( [
+
+			THREE.UniformsLib[ "particle" ],
+			THREE.UniformsLib[ "shadowmap" ]
+
+		] ),
 
 		fragmentShader: [
 
@@ -1438,13 +1462,16 @@ THREE.ShaderLib = {
 			THREE.ShaderChunk[ "color_pars_fragment" ],
 			THREE.ShaderChunk[ "map_particle_pars_fragment" ],
 			THREE.ShaderChunk[ "fog_pars_fragment" ],
+			THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
 
 			"void main() {",
 
 				"gl_FragColor = vec4( psColor, opacity );",
 
 				THREE.ShaderChunk[ "map_particle_fragment" ],
+				THREE.ShaderChunk[ "alphatest_fragment" ],
 				THREE.ShaderChunk[ "color_fragment" ],
+				THREE.ShaderChunk[ "shadowmap_fragment" ],
 				THREE.ShaderChunk[ "fog_fragment" ],
 
 			"}"
@@ -1457,6 +1484,7 @@ THREE.ShaderLib = {
 			"uniform float scale;",
 
 			THREE.ShaderChunk[ "color_pars_vertex" ],
+			THREE.ShaderChunk[ "shadowmap_pars_vertex" ],
 
 			"void main() {",
 
@@ -1472,6 +1500,8 @@ THREE.ShaderLib = {
 
 				"gl_Position = projectionMatrix * mvPosition;",
 
+				THREE.ShaderChunk[ "shadowmap_vertex" ],
+
 			"}"
 
 		].join("\n")

+ 2 - 0
utils/build.py

@@ -52,6 +52,7 @@ COMMON_FILES = [
 'materials/ParticleCanvasMaterial.js',
 'materials/ParticleDOMMaterial.js',
 'materials/Texture.js',
+'materials/DataTexture.js',
 'objects/Particle.js',
 'objects/ParticleSystem.js',
 'objects/Line.js',
@@ -97,6 +98,7 @@ EXTRAS_FILES = [
 'extras/geometries/Curve.js',
 'extras/geometries/Path.js',
 'extras/geometries/Shape.js',
+'extras/geometries/TextPath.js',
 'extras/geometries/CubeGeometry.js',
 'extras/geometries/CylinderGeometry.js',
 'extras/geometries/ExtrudeGeometry.js',

+ 118 - 118
utils/exporters/max/ThreeJSExporter.ms

@@ -34,34 +34,34 @@ rollout ThreeJSExporter "ThreeJSExporter"
 	triNFormat = "%,%,%,%,%,%,%",
 	triUVNFormat = "%,%,%,%,%,%,%,%,%,%",
 
-	footerFormat = "}\n\npostMessage( model );"
+	footerFormat = "}\n\npostMessage( model );\nclose();"
 
 	-------------------------------------------------------------------------------------
 	-- User interface
 
 
-	group "ThreeJSExporter  v0.6"
+	group "ThreeJSExporter  v0.7"
 	(
 
 		label msg "Exports selected meshes in Three.js ascii JSON format" align:#left
 		hyperLink lab1 "Original source at GitHub" address:"https://github.com/alteredq/three.js/blob/master/utils/exporters/max/ThreeJSExporter.ms" color:(color 255 120 0) align:#left
 
 		label dummy1 "--------------------------------------------------------" align:#left
-		
+
 		checkbox exportColor "Export vertex colors" checked:false enabled:true
 		checkbox exportUv "Export uvs" checked:true enabled:true
 		checkbox exportNormal "Export normals" checked:true enabled:true
 		checkbox smoothNormal "Use vertex normals" checked:false enabled:true
-		
+
 		label dummy2 "--------------------------------------------------------" align:#left
-		
+
 		checkbox flipYZ "Flip YZ" checked:true enabled:true
 		checkbox flipUV "Flip UV" checked:true enabled:true
 		checkbox flipFace "Flip all faces" checked:false enabled:true
 		checkbox autoflipFace "Try fixing flipped faces" checked:false enabled:true
 
 		label dummy3 "--------------------------------------------------------" align:#left
-		
+
 		button btn_export "Export selected objects"
 
 	)
@@ -70,7 +70,7 @@ rollout ThreeJSExporter "ThreeJSExporter"
 	-------------------------------------------------------------------------------------
 	-- Dump vertices
 
-	function DumpVertices src = 
+	function DumpVertices src =
 	(
 
 		Format "\"vertices\": [" to:ostream
@@ -102,9 +102,9 @@ rollout ThreeJSExporter "ThreeJSExporter"
 					z = vert.z
 
 				)
-				
+
 				Format vertexFormat x y z to:ostream
-				
+
 				if i < num then Format "," to:ostream
 
 			)
@@ -114,11 +114,11 @@ rollout ThreeJSExporter "ThreeJSExporter"
 		Format "],\n\n" to:ostream
 
 	)
-	
+
 	-------------------------------------------------------------------------------------
 	-- Dump colors
 
-	function DumpColors src useColors = 
+	function DumpColors src useColors =
 	(
 
 		Format "\"colors\": [" to:ostream
@@ -132,19 +132,19 @@ rollout ThreeJSExporter "ThreeJSExporter"
 			(
 
 				col = src[i]
-				
+
 				r = col.r as Integer
 				g = col.g as Integer
 				b = col.b as Integer
-				
+
 				hexNum = ( bit.shift r 16 ) + ( bit.shift g 8 ) + b
-				
+
 				-- hexColor = formattedPrint hexNum format:"#x"
 				-- Format "%" hexColor to:ostream
 
 				decColor = formattedPrint hexNum format:"#d"
 				Format "%" decColor to:ostream
-				
+
 				if i < num then Format "," to:ostream
 
 			)
@@ -153,12 +153,12 @@ rollout ThreeJSExporter "ThreeJSExporter"
 
 		Format "],\n\n" to:ostream
 
-	)	
+	)
 
 	-------------------------------------------------------------------------------------
 	-- Dump normals
 
-	function DumpNormals src = 
+	function DumpNormals src =
 	(
 
 		Format "\"normals\": [" to:ostream
@@ -180,9 +180,9 @@ rollout ThreeJSExporter "ThreeJSExporter"
 					x = normal.x
 					y = normal.z
 					z = normal.y
-					
+
 					z *= -1
-					
+
 				)
 				else
 				(
@@ -208,7 +208,7 @@ rollout ThreeJSExporter "ThreeJSExporter"
 	-------------------------------------------------------------------------------------
 	-- Dump uvs
 
-	function DumpUvs src = 
+	function DumpUvs src =
 	(
 
 		Format "\"uvs\": [[" to:ostream
@@ -225,7 +225,7 @@ rollout ThreeJSExporter "ThreeJSExporter"
 
 				u = uvw.x
 
-				if flipUV.checked then 
+				if flipUV.checked then
 				(
 					v = 1 - uvw.y
 				)
@@ -249,11 +249,11 @@ rollout ThreeJSExporter "ThreeJSExporter"
 	-------------------------------------------------------------------------------------
 	-- Dump faces
 
-	function DumpFaces src useColors = 
+	function DumpFaces src useColors =
 	(
 
 		Format "\"faces\": [" to:ostream
-		
+
 		num = src.count
 
 		if num > 0 then
@@ -268,9 +268,9 @@ rollout ThreeJSExporter "ThreeJSExporter"
 				fuv = zface[2]
 				m   = zface[3] - 1
 				fc  = zface[4]
-				
+
 				needsFlip = zface[5]
-				
+
 				isTriangle = true
 				hasMaterial = true
 				hasFaceUvs = false
@@ -289,12 +289,12 @@ rollout ThreeJSExporter "ThreeJSExporter"
 				faceType = bit.set faceType 6 hasFaceVertexNormals
 				faceType = bit.set faceType 7 hasFaceColors
 				faceType = bit.set faceType 8 hasFaceVertexColors
-				
+
 				if i > 1 then
 				(
 					Format "," faceType to:ostream
 				)
-				
+
 				Format "%" faceType to:ostream
 
 				if isTriangle then
@@ -303,8 +303,8 @@ rollout ThreeJSExporter "ThreeJSExporter"
 					va = (fv.x - 1) as Integer
 					vb = (fv.y - 1) as Integer
 					vc = (fv.z - 1) as Integer
-					
-					if flipFace.checked or needsFlip then 
+
+					if flipFace.checked or needsFlip then
 					(
 
 						tmp = vb
@@ -312,26 +312,26 @@ rollout ThreeJSExporter "ThreeJSExporter"
 						vc = tmp
 
 					)
-					
-					
+
+
 					Format ",%,%,%" va vb vc to:ostream
 
-				
-					if hasMaterial then 
+
+					if hasMaterial then
 					(
 
 						Format ",%" m to:ostream
 
 					)
-					
+
 					if hasFaceVertexUvs then
 					(
 
 						ua = (fuv.x - 1) as Integer
 						ub = (fuv.y - 1) as Integer
 						uc = (fuv.z - 1) as Integer
-						
-						if flipFace.checked or needsFlip then 
+
+						if flipFace.checked or needsFlip then
 						(
 
 							tmp = ub
@@ -339,15 +339,15 @@ rollout ThreeJSExporter "ThreeJSExporter"
 							uc = tmp
 
 						)
-						
+
 						Format ",%,%,%" ua ub uc to:ostream
 
 					)
-				
+
 					if hasFaceVertexNormals then
 					(
 
-						if smoothNormal.checked then 
+						if smoothNormal.checked then
 						(
 
 							-- normals have the same indices as vertices
@@ -357,7 +357,7 @@ rollout ThreeJSExporter "ThreeJSExporter"
 							nc = vc
 
 						)
-						else 
+						else
 						(
 							-- normals have the same indices as face
 
@@ -366,8 +366,8 @@ rollout ThreeJSExporter "ThreeJSExporter"
 							nc = na
 
 						)
-						
-						if flipFace.checked or needsFlip then 
+
+						if flipFace.checked or needsFlip then
 						(
 
 							tmp = nb
@@ -375,20 +375,20 @@ rollout ThreeJSExporter "ThreeJSExporter"
 							nc = tmp
 
 						)
-						
+
 						Format ",%,%,%" na nb nc to:ostream
 
 					)
 
-				
+
 					if hasFaceVertexColors then
 					(
 
 						ca = (fc.x - 1) as Integer
 						cb = (fc.y - 1) as Integer
 						cc = (fc.z - 1) as Integer
-						
-						if flipFace.checked or needsFlip then 
+
+						if flipFace.checked or needsFlip then
 						(
 
 							tmp = cb
@@ -396,13 +396,13 @@ rollout ThreeJSExporter "ThreeJSExporter"
 							cc = tmp
 
 						)
-						
+
 						Format ",%,%,%" ca cb cc to:ostream
 
 					)
 
 				)
-				
+
 			)
 
 		)
@@ -414,7 +414,7 @@ rollout ThreeJSExporter "ThreeJSExporter"
 	-------------------------------------------------------------------------------------
 	-- Dump color
 
-	function DumpColor pcolor label = 
+	function DumpColor pcolor label =
 	(
 		r = pcolor.r / 255
 		g = pcolor.g / 255
@@ -426,19 +426,19 @@ rollout ThreeJSExporter "ThreeJSExporter"
 
 		Format "\"%\"  : [%, %, %],\n" label fr fg fb to:ostream
 
-	)	
+	)
 
 	-------------------------------------------------------------------------------------
 	-- Dump map
 
-	function DumpMap pmap label = 
+	function DumpMap pmap label =
 	(
 
 		if classof pmap == BitmapTexture then
 		(
 			bm = pmap.bitmap
 
-			if bm != undefined then 
+			if bm != undefined then
 			(
 
 				fname = filenameFromPath bm.filename
@@ -453,7 +453,7 @@ rollout ThreeJSExporter "ThreeJSExporter"
 	-------------------------------------------------------------------------------------
 	-- Export materials
 
-	function ExportMaterials zmaterials zcolors = 
+	function ExportMaterials zmaterials zcolors =
 	(
 
 		Format "\"materials\": [\n" to:ostream
@@ -474,9 +474,9 @@ rollout ThreeJSExporter "ThreeJSExporter"
 			(
 
 				useVertexColors = zcolors[i]
-				
+
 				Format "\"DbgName\"  : \"%\",\n" mat.name to:ostream
-				
+
 				-- colors
 
 				DumpColor mat.diffuse  "colorDiffuse"
@@ -485,7 +485,7 @@ rollout ThreeJSExporter "ThreeJSExporter"
 
 				t = mat.opacity / 100
 				s = mat.glossiness
-				
+
 				Format "\"transparency\"  : %,\n" t to:ostream
 				Format "\"specularCoef\"  : %,\n" s to:ostream
 
@@ -498,24 +498,24 @@ rollout ThreeJSExporter "ThreeJSExporter"
 				DumpMap mat.opacityMap 	"mapAlpha"
 
 			)
-			else 
+			else
 			(
-				
+
 				useVertexColors = false
-				
+
 				Format "\"DbgName\"  : \"%\",\n" "dummy" to:ostream
-				
+
 				DumpColor red "colorDiffuse"
-				
+
 			)
-				
+
 			Format "\"vertexColors\" : %\n" useVertexColors to:ostream
 			Format "}" to:ostream
 
 			if ( i < totalMaterials ) then Format "," to:ostream
 			Format "\n\n" to:ostream
 
-		)		
+		)
 
 		Format "],\n\n" to:ostream
 
@@ -546,7 +546,7 @@ rollout ThreeJSExporter "ThreeJSExporter"
 	(
 
 		nColors = GetNumCPVVerts obj
-		
+
 		if nColors > 0 then
 		(
 
@@ -573,8 +573,8 @@ rollout ThreeJSExporter "ThreeJSExporter"
 		(
 
 			num = obj.numVerts
-			
-			for i = 1 to num do 
+
+			for i = 1 to num do
 			(
 
 				n = GetNormal obj i
@@ -596,7 +596,7 @@ rollout ThreeJSExporter "ThreeJSExporter"
 
 			num = obj.numFaces
 
-			for i = 1 to num do 
+			for i = 1 to num do
 			(
 
 				n = GetFaceNormal obj i
@@ -622,8 +622,8 @@ rollout ThreeJSExporter "ThreeJSExporter"
 	function ExtractUvs obj whereto =
 	(
 		n = obj.numTVerts
-		
-		for i = 1 to n do 
+
+		for i = 1 to n do
 		(
 
 			v = GetTVert obj i
@@ -643,10 +643,10 @@ rollout ThreeJSExporter "ThreeJSExporter"
 
 		useMultiMaterial = false
 		materialIDList = #()
-		
+
 		materialClass = classof objMaterial
-		
-		if materialClass == StandardMaterial then 
+
+		if materialClass == StandardMaterial then
 		(
 
 			fm = findItem allMaterials objMaterial
@@ -657,12 +657,12 @@ rollout ThreeJSExporter "ThreeJSExporter"
 
 			useMultiMaterial = true
 
-			for i = 1 to n do 
+			for i = 1 to n do
 			(
 
 				mID = GetFaceMatID objMesh i
 				materialIndex = findItem objMaterial.materialIDList mID
-				
+
 				if materialIndex > 0 then
 				(
 
@@ -670,7 +670,7 @@ rollout ThreeJSExporter "ThreeJSExporter"
 
 					mMergedIndex = findItem allMaterials subMaterial
 
-					if mMergedIndex > 0 then 
+					if mMergedIndex > 0 then
 					(
 
 						materialIDList[mID] = mMergedIndex
@@ -696,29 +696,29 @@ rollout ThreeJSExporter "ThreeJSExporter"
 		)
 		else
 		(
-			
+
 			-- undefined material
-			
+
 			fm = findItem allMaterials false
-			
+
 		)
-		
-		for i = 1 to n do 
+
+		for i = 1 to n do
 		(
 
 			zface = #()
-			
+
 			fv = GetFace objMesh i
 
 			fv.x += offsetVert
 			fv.y += offsetVert
 			fv.z += offsetVert
 
-			if useMultiMaterial then 
+			if useMultiMaterial then
 			(
 
 				mID = GetFaceMatID objMesh i
-				fm = materialIDList[mID]				
+				fm = materialIDList[mID]
 
 			)
 
@@ -726,7 +726,7 @@ rollout ThreeJSExporter "ThreeJSExporter"
 			(
 
 				fuv = GetTVFace objMesh i
-				
+
 				fuv.x += offsetUv
 				fuv.y += offsetUv
 				fuv.z += offsetUv
@@ -738,12 +738,12 @@ rollout ThreeJSExporter "ThreeJSExporter"
 				fuv = false
 
 			)
-			
+
 			if hasVColors then
 			(
 
 				fc = GetVCFace objMesh i
-				
+
 				fc.x += offsetColor
 				fc.y += offsetColor
 				fc.z += offsetColor
@@ -756,7 +756,7 @@ rollout ThreeJSExporter "ThreeJSExporter"
 
 			)
 
-			append zface fv 
+			append zface fv
 			append zface fuv
 			append zface fm
 			append zface fc
@@ -770,10 +770,10 @@ rollout ThreeJSExporter "ThreeJSExporter"
 
 	-------------------------------------------------------------------------------------
 	-- Extract materials from eventual multi-material
-	
+
 	function ExtractMaterials objMesh objMaterial whereto wheretoColors zname hasVColors =
 	(
-		
+
 		materialClass = classof objMaterial
 
 		if materialClass == StandardMaterial then
@@ -792,13 +792,13 @@ rollout ThreeJSExporter "ThreeJSExporter"
 		(
 
 			n = objMesh.numFaces
-			
-			for i = 1 to n do 
+
+			for i = 1 to n do
 			(
-			
+
 				mID = getFaceMatId objMesh i
 				materialIndex = findItem objMaterial.materialIDList mID
-				
+
 				if materialIndex > 0 then
 				(
 
@@ -812,16 +812,16 @@ rollout ThreeJSExporter "ThreeJSExporter"
 
 					)
 
-				)				
+				)
 
 			)
 
 		)
 		else
 		(
-			
+
 			-- unknown or undefined material
-			
+
 			append whereto false
 			append wheretoColors false
 
@@ -831,8 +831,8 @@ rollout ThreeJSExporter "ThreeJSExporter"
 
 	-------------------------------------------------------------------------------------
 	-- Hack to figure out if normals are messed up
-	
-	function NeedsFaceFlip node = 
+
+	function NeedsFaceFlip node =
 	(
 		needsFlip = false
 
@@ -865,29 +865,29 @@ rollout ThreeJSExporter "ThreeJSExporter"
 		(
 			needsFlip = false
 			hasVColors = false
-			
+
 			zmesh = SnapshotAsMesh node
-			
+
 			if autoflipFace.checked then
 			(
 
 				needsFlip = NeedsFaceFlip node
 
 			)
-			
+
 			if exportColor.checked and ( getNumCPVVerts zmesh ) > 0 then
 			(
 
 				hasVColors = true
 
 			)
-			
+
 			return #( zmesh, node.name, node.material, needsFlip, hasVColors )
 
 		)
 
 		-- Not geometry ... could be a camera, light, etc.
-		
+
 		return #( false, node.name, 0, false, false )
 
 	)
@@ -905,31 +905,31 @@ rollout ThreeJSExporter "ThreeJSExporter"
 		mergedVertices = #()
 		mergedNormals = #()
 		mergedColors = #()
-		
+
 		mergedUvs = #()
 		mergedFaces = #()
-		
+
 		mergedMaterials = #()
 		mergedMaterialsColors = #()
-		
+
 		sceneHasVColors = false
-		
-		for obj in selection do 
+
+		for obj in selection do
 		(
 
 			result = ExtractMesh obj
 			meshObj = result[1]
 
-			if ClassOf meshObj == TriMesh then 
+			if ClassOf meshObj == TriMesh then
 			(
 
 				meshName     = result[2]
 				meshMaterial = result[3]
 				needsFlip    = result[4]
 				hasVColors   = result[5]
-				
+
 				sceneHasVColors = sceneHasVColors or hasVColors
-				
+
 				append meshObjects result
 
 				vertexOffset = mergedVertices.count
@@ -941,7 +941,7 @@ rollout ThreeJSExporter "ThreeJSExporter"
 				ExtractVertices meshObj mergedVertices
 				ExtractNormals meshObj mergedNormals needsFlip
 				ExtractColors meshObj mergedColors
-				
+
 				ExtractUvs meshObj mergedUvs
 
 				ExtractFaces meshObj meshMaterial mergedFaces mergedMaterials needsFlip hasVColors vertexOffset uvOffset colorOffset
@@ -953,13 +953,13 @@ rollout ThreeJSExporter "ThreeJSExporter"
 		totalVertices = mergedVertices.count
 		totalFaces = mergedFaces.count
 		totalMaterials = mergedMaterials.count
-		
+
 		totalColors = 0
 		totalNormals = 0
 		totalUvs = 0
-		
+
 		useColors = false
-		
+
 		if sceneHasVColors and exportColor.checked then
 		(
 
@@ -968,7 +968,7 @@ rollout ThreeJSExporter "ThreeJSExporter"
 
 		)
 
-		if exportNormal.checked then 
+		if exportNormal.checked then
 		(
 
 			totalNormals = mergedNormals.count
@@ -993,7 +993,7 @@ rollout ThreeJSExporter "ThreeJSExporter"
 
 		i = 0
 
-		for obj in meshObjects do 
+		for obj in meshObjects do
 		(
 
 			meshName = obj[2]
@@ -1070,5 +1070,5 @@ rollout ThreeJSExporter "ThreeJSExporter"
 
 	)
 
-) 
+)
 createDialog ThreeJSExporter width:300

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