Browse Source

Merge remote-tracking branch 'zz85/master' into dev

Mr.doob 13 years ago
parent
commit
bc02397f33

+ 11 - 0
examples/canvas_camera_orthographic2.html

@@ -183,6 +183,17 @@
 				stats.domElement.style.top = '0px';
 				container.appendChild( stats.domElement );
 
+				window.addEventListener( 'resize', onWindowResize, false );
+
+				function onWindowResize(){
+
+				    camera.setSize( window.innerWidth, window.innerHeight );
+				    camera.updateProjectionMatrix();
+
+				    renderer.setSize( window.innerWidth, window.innerHeight );
+
+				}
+
 			}
 
 			//

+ 316 - 0
examples/js/CurveExtras.js

@@ -0,0 +1,316 @@
+/*
+ * A bunch of curves
+ * @author zz85
+ */
+
+// Lets define some curves
+THREE.Curves = {};
+
+// Formula from http://mathworld.wolfram.com/HeartCurve.html
+THREE.Curves.HeartCurve = THREE.Curve.create(
+
+function(s) {
+
+	this.scale = (s === undefined) ? 5 : s;
+
+},
+
+function(t) {
+
+	t *= 2 * Math.PI;
+
+	var tx = 16 * Math.pow(Math.sin(t), 3);
+	ty = 13 * Math.cos(t) - 5 * Math.cos(2 * t) - 2 * Math.cos(3 * t) - Math.cos(4 * t), tz = 0;
+
+	return new THREE.Vector3(tx, ty, tz).multiplyScalar(this.scale);
+
+}
+
+);
+
+
+
+// Viviani's Curve
+// http://en.wikipedia.org/wiki/Viviani%27s_curve
+THREE.Curves.VivianiCurve = THREE.Curve.create(
+
+function(radius) {
+
+	this.radius = radius;
+},
+
+function(t) {
+
+	t = t * 4 * Math.PI; // Normalized to 0..1
+	var a = this.radius / 2;
+	var tx = a * (1 + Math.cos(t)),
+		ty = a * Math.sin(t),
+		tz = 2 * a * Math.sin(t / 2);
+
+	return new THREE.Vector3(tx, ty, tz);
+
+}
+
+);
+
+
+THREE.Curves.KnotCurve = THREE.Curve.create(
+
+function() {
+
+},
+
+function(t) {
+
+	t *= 2 * Math.PI;
+
+	var R = 10;
+	var s = 50;
+	var tx = s * Math.sin(t),
+		ty = Math.cos(t) * (R + s * Math.cos(t)),
+		tz = Math.sin(t) * (R + s * Math.cos(t));
+
+	return new THREE.Vector3(tx, ty, tz);
+
+}
+
+);
+
+THREE.Curves.HelixCurve = THREE.Curve.create(
+
+function() {
+
+},
+
+function(t) {
+
+	var a = 30; // radius
+	var b = 150; //height
+	var t2 = 2 * Math.PI * t * b / 30;
+	var tx = Math.cos(t2) * a,
+		ty = Math.sin(t2) * a,
+		tz = b * t;
+
+	return new THREE.Vector3(tx, ty, tz);
+
+}
+
+);
+
+// Replacement for TorusKnotGeometry?
+THREE.Curves.TrefoilKnot = THREE.Curve.create(
+
+function(s) {
+
+	this.scale = (s === undefined) ? 10 : s;
+
+},
+
+function(t) {
+
+	t *= Math.PI * 2;
+	var tx = (2 + Math.cos(3 * t)) * Math.cos(2 * t),
+		ty = (2 + Math.cos(3 * t)) * Math.sin(2 * t),
+		tz = Math.sin(3 * t);
+
+	return new THREE.Vector3(tx, ty, tz).multiplyScalar(this.scale);
+
+}
+
+);
+
+// Formulas from http://mathdl.maa.org/images/upload_library/23/stemkoski/knots/page6.html
+THREE.Curves.TorusKnot = THREE.Curve.create(
+
+function(s) {
+
+	this.scale = (s === undefined) ? 10 : s;
+
+},
+
+function(t) {
+
+	var p = 3,
+		q = 4;
+	t *= Math.PI * 2;
+	var tx = (2 + Math.cos(q * t)) * Math.cos(p * t),
+		ty = (2 + Math.cos(q * t)) * Math.sin(p * t),
+		tz = Math.sin(q * t);
+
+	return new THREE.Vector3(tx, ty, tz).multiplyScalar(this.scale);
+
+}
+
+);
+
+
+THREE.Curves.CinquefoilKnot = THREE.Curve.create(
+
+function(s) {
+
+	this.scale = (s === undefined) ? 10 : s;
+
+},
+
+function(t) {
+
+	var p = 2,
+		q = 5;
+	t *= Math.PI * 2;
+	var tx = (2 + Math.cos(q * t)) * Math.cos(p * t),
+		ty = (2 + Math.cos(q * t)) * Math.sin(p * t),
+		tz = Math.sin(q * t);
+
+	return new THREE.Vector3(tx, ty, tz).multiplyScalar(this.scale);
+
+}
+
+);
+
+
+THREE.Curves.TrefoilPolynomialKnot = THREE.Curve.create(
+
+function(s) {
+
+	this.scale = (s === undefined) ? 10 : s;
+
+},
+
+function(t) {
+
+	t = t * 4 - 2;
+	var tx = Math.pow(t, 3) - 3 * t,
+		ty = Math.pow(t, 4) - 4 * t * t,
+		tz = 1 / 5 * Math.pow(t, 5) - 2 * t;
+
+	return new THREE.Vector3(tx, ty, tz).multiplyScalar(this.scale);
+
+}
+
+);
+
+var sin = Math.sin,
+	pow = Math.pow,
+	cos = Math.cos;
+// var scaleTo = function(x, y) {
+//   var r = y - x;
+//   return function(t) {
+//     t * r + x;
+//   };
+// }
+var scaleTo = function(x, y, t) {
+
+		var r = y - x;
+		return t * r + x;
+
+	}
+
+THREE.Curves.FigureEightPolynomialKnot = THREE.Curve.create(
+
+function(s) {
+
+	this.scale = (s === undefined) ? 1 : s;
+
+},
+
+function(t) {
+
+	t = scaleTo(-4, 4, t);
+	var tx = 2 / 5 * t * (t * t - 7) * (t * t - 10),
+		ty = pow(t, 4) - 13 * t * t,
+		tz = 1 / 10 * t * (t * t - 4) * (t * t - 9) * (t * t - 12);
+
+	return new THREE.Vector3(tx, ty, tz).multiplyScalar(this.scale);
+
+}
+
+);
+
+// When there's time, try more formulas at http://mathdl.maa.org/images/upload_library/23/stemkoski/knots/page4.html
+
+//http://www.mi.sanu.ac.rs/vismath/taylorapril2011/Taylor.pdf
+THREE.Curves.DecoratedTorusKnot4a = THREE.Curve.create(
+
+function(s) {
+
+	this.scale = (s === undefined) ? 40 : s;
+
+},
+
+function(t) {
+
+	t *= Math.PI * 2;
+	var
+	x = cos(2 * t) * (1 + 0.6 * (cos(5 * t) + 0.75 * cos(10 * t))),
+		y = sin(2 * t) * (1 + 0.6 * (cos(5 * t) + 0.75 * cos(10 * t))),
+		z = 0.35 * sin(5 * t);
+
+	return new THREE.Vector3(x, y, z).multiplyScalar(this.scale);
+
+}
+
+);
+
+
+THREE.Curves.DecoratedTorusKnot4b = THREE.Curve.create(
+
+function(s) {
+
+	this.scale = (s === undefined) ? 40 : s;
+
+},
+
+function(t) {
+	var fi = t * Math.PI * 2;
+	var x = cos(2 * fi) * (1 + 0.45 * cos(3 * fi) + 0.4 * cos(9 * fi)),
+		y = sin(2 * fi) * (1 + 0.45 * cos(3 * fi) + 0.4 * cos(9 * fi)),
+		z = 0.2 * sin(9 * fi);
+
+	return new THREE.Vector3(x, y, z).multiplyScalar(this.scale);
+
+}
+
+);
+
+
+THREE.Curves.DecoratedTorusKnot5a = THREE.Curve.create(
+
+function(s) {
+
+	this.scale = (s === undefined) ? 40 : s;
+
+},
+
+function(t) {
+
+	var fi = t * Math.PI * 2;
+	var x = cos(3 * fi) * (1 + 0.3 * cos(5 * fi) + 0.5 * cos(10 * fi)),
+		y = sin(3 * fi) * (1 + 0.3 * cos(5 * fi) + 0.5 * cos(10 * fi)),
+		z = 0.2 * sin(20 * fi);
+
+	return new THREE.Vector3(x, y, z).multiplyScalar(this.scale);
+
+}
+
+);
+
+THREE.Curves.DecoratedTorusKnot5c = THREE.Curve.create(
+
+function(s) {
+
+	this.scale = (s === undefined) ? 40 : s;
+
+},
+
+function(t) {
+
+	var fi = t * Math.PI * 2;
+	var x = cos(4 * fi) * (1 + 0.5 * (cos(5 * fi) + 0.4 * cos(20 * fi))),
+		y = sin(4 * fi) * (1 + 0.5 * (cos(5 * fi) + 0.4 * cos(20 * fi))),
+		z = 0.35 * sin(15 * fi);
+
+	return new THREE.Vector3(x, y, z).multiplyScalar(this.scale);
+
+}
+
+);

+ 21 - 30
examples/webgl_geometry_extrude_shapes.html

@@ -114,21 +114,11 @@
           new THREE.Vector3( 10, 60, 49),
           new THREE.Vector3( 25, 80, 40)
 
-          // new THREE.Vector3( 0, 12, 83),
-          // new THREE.Vector3( 0, 20, 67),
-          // new THREE.Vector3( 0, 40, 99),
-          // new THREE.Vector3( 0, 60, 49),
-          // new THREE.Vector3( 0, 80, 40)
-
-          // new THREE.Vector3( 12, 83, 0 ),
-          // new THREE.Vector3( 20, 67, 0 ),
-          // new THREE.Vector3( 40, 99, 0 ),
-          // new THREE.Vector3( 60, 49, 0 ),
-          // new THREE.Vector3( 80, 40, 0 )
-          ]);
-
-            var pipeSpline = new THREE.SplineCurve3([
-        new THREE.Vector3(0, 10, -10), new THREE.Vector3(10, 0, -10), new THREE.Vector3(20, 0, 0), new THREE.Vector3(30, 0, 10), new THREE.Vector3(30, 0, 20), new THREE.Vector3(20, 0, 30), new THREE.Vector3(10, 0, 30), new THREE.Vector3(0, 0, 30), new THREE.Vector3(-10, 10, 30), new THREE.Vector3(-10, 20, 30), new THREE.Vector3(0, 30, 30), new THREE.Vector3(10, 30, 30), new THREE.Vector3(20, 30, 15), new THREE.Vector3(10, 30, 10), new THREE.Vector3(0, 30, 10), new THREE.Vector3(-10, 20, 10), new THREE.Vector3(-10, 10, 10), new THREE.Vector3(0, 0, 10), new THREE.Vector3(10, -10, 10), new THREE.Vector3(20, -15, 10), new THREE.Vector3(30, -15, 10), new THREE.Vector3(40, -15, 10), new THREE.Vector3(50, -15, 10), new THREE.Vector3(60, 0, 10), new THREE.Vector3(70, 0, 0), new THREE.Vector3(80, 0, 0), new THREE.Vector3(90, 0, 0), new THREE.Vector3(100, 0, 0)]);
+        ]);
+
+        var pipeSpline = new THREE.SplineCurve3([
+        
+          new THREE.Vector3(0, 10, -10), new THREE.Vector3(10, 0, -10), new THREE.Vector3(20, 0, 0), new THREE.Vector3(30, 0, 10), new THREE.Vector3(30, 0, 20), new THREE.Vector3(20, 0, 30), new THREE.Vector3(10, 0, 30), new THREE.Vector3(0, 0, 30), new THREE.Vector3(-10, 10, 30), new THREE.Vector3(-10, 20, 30), new THREE.Vector3(0, 30, 30), new THREE.Vector3(10, 30, 30), new THREE.Vector3(20, 30, 15), new THREE.Vector3(10, 30, 10), new THREE.Vector3(0, 30, 10), new THREE.Vector3(-10, 20, 10), new THREE.Vector3(-10, 10, 10), new THREE.Vector3(0, 0, 10), new THREE.Vector3(10, -10, 10), new THREE.Vector3(20, -15, 10), new THREE.Vector3(30, -15, 10), new THREE.Vector3(40, -15, 10), new THREE.Vector3(50, -15, 10), new THREE.Vector3(60, 0, 10), new THREE.Vector3(70, 0, 0), new THREE.Vector3(80, 0, 0), new THREE.Vector3(90, 0, 0), new THREE.Vector3(100, 0, 0)]);
 
         var sampleClosedSpline = new THREE.ClosedSplineCurve3([
           new THREE.Vector3(0, -40, -40),
@@ -163,11 +153,6 @@
         var rectLength = 12, rectWidth = 4;
 
         var rectShape = new THREE.Shape();
-        // rectShape.moveTo( 0,0 );
-        // rectShape.lineTo( 0, rectWidth );
-        // rectShape.lineTo( rectLength, rectWidth );
-        // rectShape.lineTo( rectLength, 0 );
-        // rectShape.lineTo( 0, 0 );
 
         rectShape.moveTo( -rectLength/2, -rectWidth/2 );
         rectShape.lineTo( -rectLength/2, rectWidth/2 );
@@ -176,6 +161,21 @@
         rectShape.lineTo( -rectLength/2, -rectLength/2 );
 
 
+       
+        
+        var pts = [], starPoints = 5, l;
+        for (i=0; i<starPoints*2;i++) {
+          if (i%2==1) {
+            l = 5;
+          } else {
+            l = 10;
+          }
+
+          var a = i / starPoints * Math.PI;
+          pts.push(new THREE.Vector2(Math.cos(a) * l,Math.sin(a) * l ));
+        }
+      var starShape = new THREE.Shape(pts);
+
         // Smiley
 
         var smileyShape = new THREE.Shape();
@@ -193,12 +193,6 @@
         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 );
@@ -208,10 +202,7 @@
 
         smileyShape.holes.push( smileyMouthPath );
 
-
-
-
-        var circle3d = rectShape.extrude( extrudeSettings ); //circleShape rectShape smileyShape
+        var circle3d = starShape.extrude( extrudeSettings ); //circleShape rectShape smileyShape starShape
         // var circle3d = new THREE.ExtrudeGeometry(circleShape, extrudeBend, extrudeSettings );
         
         var tube = new THREE.TubeGeometry(extrudeSettings.extrudePath, 150, 4, 5, false, true);

+ 29 - 343
examples/webgl_geometry_extrude_splines.html

@@ -20,336 +20,17 @@
     <script src="../src/extras/core/Curve.js"></script>
     <script src="../src/extras/geometries/TubeGeometry.js"></script>
     <script src="../src/extras/helpers/CameraHelper.js"></script>
-    <script src="js/Stats.js"></script>
-
-
-    <script>
-
-    // Lets define some curves
-    THREE.Curves = {};
-
-    // Formula from http://mathworld.wolfram.com/HeartCurve.html
-
-    THREE.Curves.HeartCurve = THREE.Curve.create(
-
-      function ( s ) {
-
-        this.scale = (s === undefined) ? 5 : s;
-
-      },
-
-      function ( t ) {
-
-          t *= 2 * Math.PI;
-
-          var tx = 16 * Math.pow(Math.sin(t), 3);
-              ty = 13 * Math.cos(t)
-                - 5 * Math.cos(2 * t)
-                - 2 * Math.cos(3 * t)
-                - Math.cos(4 * t ),
-              tz = 0;
-
-          return new THREE.Vector3(tx, ty, tz).multiplyScalar(this.scale);
-
-      }
-
-    );
-
-
-
-    // Viviani's Curve
-    // http://en.wikipedia.org/wiki/Viviani%27s_curve
-
-    THREE.Curves.VivianiCurve = THREE.Curve.create(
-
-      function( radius ) {
-
-          this.radius = radius;
-      },
-
-      function( t ) {
-
-          t = t * 4 * Math.PI; // Normalized to 0..1
-          var a = this.radius / 2;
-          var tx = a * (1 + Math.cos(t)),
-              ty = a * Math.sin(t),
-              tz = 2 * a * Math.sin(t / 2);
-
-          return new THREE.Vector3(tx, ty, tz);
-
-      }
-
-    );
-
-
-    THREE.Curves.KnotCurve = THREE.Curve.create(
-
-    function() {
-
-    },
-
-    function(t) {
-
-        t *= 2 * Math.PI;
-
-        var R = 10;
-        var s = 50;
-        var tx = s * Math.sin(t),
-            ty = Math.cos(t) * (R + s * Math.cos(t)),
-            tz = Math.sin(t) * (R + s * Math.cos(t));
-
-        return new THREE.Vector3(tx, ty, tz);
-
-    }
-
-    );
-
-    THREE.Curves.HelixCurve = THREE.Curve.create(
-
-    function() {
-
-    },
-
-    function(t) {
-
-        var a = 30; // radius
-        var b = 150; //height
-        var t2 = 2 * Math.PI * t * b / 30;
-        var tx = Math.cos(t2) * a,
-            ty = Math.sin(t2) * a,
-            tz = b * t;
-
-        return new THREE.Vector3(tx, ty, tz);
-
-    }
-
-    );
-
-    // Replacement for TorusKnotGeometry?
-
-    THREE.Curves.TrefoilKnot = THREE.Curve.create(
-
-    function(s) {
-
-      this.scale = (s === undefined) ? 10 : s;
-
-    },
-
-    function(t) {
-
-        t *= Math.PI * 2;
-        var tx = (2 + Math.cos(3 * t)) * Math.cos(2 * t),
-        ty = (2 + Math.cos(3* t)) * Math.sin(2 * t),
-        tz = Math.sin(3 * t);
-
-        return new THREE.Vector3(tx, ty, tz).multiplyScalar(this.scale);
-
-    }
-
-    );
-
-    // Formulas from http://mathdl.maa.org/images/upload_library/23/stemkoski/knots/page6.html
-
-    THREE.Curves.TorusKnot = THREE.Curve.create(
-
-    function(s) {
-
-      this.scale = (s === undefined) ? 10 : s;
-
-    },
-
-    function(t) {
-
-      var p = 3, q = 4;
-        t *= Math.PI * 2;
-        var tx = (2 + Math.cos(q * t)) * Math.cos(p * t),
-        ty = (2 + Math.cos(q* t)) * Math.sin(p * t),
-        tz = Math.sin(q * t);
-
-        return new THREE.Vector3(tx, ty, tz).multiplyScalar(this.scale);
-
-    }
-
-    );
-
-
-    THREE.Curves.CinquefoilKnot = THREE.Curve.create(
-
-    function(s) {
-
-      this.scale = (s === undefined) ? 10 : s;
-
-    },
-
-    function(t) {
-
-      var p = 2, q = 5;
-        t *= Math.PI * 2;
-        var tx = (2 + Math.cos(q * t)) * Math.cos(p * t),
-        ty = (2 + Math.cos(q* t)) * Math.sin(p * t),
-        tz = Math.sin(q * t);
-
-        return new THREE.Vector3(tx, ty, tz).multiplyScalar(this.scale);
-
-    }
-
-    );
-
-
-    THREE.Curves.TrefoilPolynomialKnot = THREE.Curve.create(
-
-    function(s) {
-
-      this.scale = (s === undefined) ? 10 : s;
-
-    },
-
-    function(t) {
-
-        t = t * 4 - 2;
-        var tx = Math.pow(t, 3) - 3 * t,
-        ty = Math.pow(t, 4) - 4 * t * t,
-        tz = 1/ 5 * Math.pow(t, 5) - 2 * t;
-
-        return new THREE.Vector3(tx, ty, tz).multiplyScalar(this.scale);
-
-    }
-
-    );
-
-    var sin = Math.sin, pow = Math.pow, cos = Math.cos;
-    // var scaleTo = function(x, y) {
-    //   var r = y - x;
-    //   return function(t) {
-    //     t * r + x;
-    //   };
-    // }
-
-    var scaleTo = function(x, y, t) {
-
-      var r = y - x;
-      return t * r + x;
-
-    }
-
-    THREE.Curves.FigureEightPolynomialKnot = THREE.Curve.create(
-
-    function(s) {
-
-      this.scale = (s === undefined) ? 1 : s;
-
-    },
-
-    function(t) {
-
-        t = scaleTo(-4,4, t);
-        var tx = 2 / 5 * t * (t * t - 7) * (t * t - 10),
-        ty = pow(t, 4) - 13 * t * t,
-        tz = 1/10 * t * (t * t - 4) * (t * t - 9) * (t * t - 12);
-
-        return new THREE.Vector3(tx, ty, tz).multiplyScalar(this.scale);
-
-    }
-
-    );
-
-    // When there's time, try more formulas at http://mathdl.maa.org/images/upload_library/23/stemkoski/knots/page4.html
-
-
-    //http://www.mi.sanu.ac.rs/vismath/taylorapril2011/Taylor.pdf
-
-    THREE.Curves.DecoratedTorusKnot4a = THREE.Curve.create(
-
-    function(s) {
-
-      this.scale = (s === undefined) ? 40 : s;
-
-    },
-
-    function(t) {
-
-        t *= Math.PI * 2;
-        var
-        x = cos(2*t) * (1+0.6*(cos(5*t) + 0.75*cos(10*t))),
-         y = sin(2*t) * (1+0.6*(cos(5*t) + 0.75*cos(10*t))),
-          z = 0.35*sin(5*t);
-
-        return new THREE.Vector3(x, y, z).multiplyScalar(this.scale);
-
-    }
-
-    );
-
-
-    THREE.Curves.DecoratedTorusKnot4b = THREE.Curve.create(
-
-    function(s) {
-
-      this.scale = (s === undefined) ? 40 : s;
-
-    },
-
-    function(t) {
-        var fi = t  * Math.PI * 2;
-        var	x = cos(2*fi) * (1 + 0.45*cos(3*fi) + 0.4*cos(9*fi)),
-			y = sin(2*fi) * (1 + 0.45*cos(3*fi) + 0.4*cos(9*fi)),
-			z = 0.2*sin(9*fi);
-
-        return new THREE.Vector3(x, y, z).multiplyScalar(this.scale);
-
-    }
-
-    );
-
-
-    THREE.Curves.DecoratedTorusKnot5a = THREE.Curve.create(
-
-    function(s) {
-
-      this.scale = (s === undefined) ? 40 : s;
-
-    },
-
-    function(t) {
-
-        var fi = t  * Math.PI * 2;
-        var x = cos(3*fi) * (1 + 0.3*cos(5*fi) + 0.5*cos(10*fi)),
-			y = sin(3*fi) * (1 + 0.3*cos(5*fi) + 0.5*cos(10*fi)),
-			z = 0.2*sin(20*fi);
-
-        return new THREE.Vector3(x, y, z).multiplyScalar(this.scale);
-
-    }
-
-    );
-
-    THREE.Curves.DecoratedTorusKnot5c = THREE.Curve.create(
-
-    function(s) {
-
-      this.scale = (s === undefined) ? 40 : s;
-
-    },
-
-    function(t) {
-
-        var fi = t  * Math.PI * 2;
-        var x = cos(4*fi) * (1 + 0.5*(cos(5*fi) + 0.4*cos(20*fi))),
-			y = sin(4*fi) * (1 + 0.5*(cos(5*fi) + 0.4*cos(20*fi))),
-			z = 0.35*sin(15*fi);
-
-        return new THREE.Vector3(x, y, z).multiplyScalar(this.scale);
-
-    }
-
-    );
 
+    <!-- where curves formulas are defined -->
+    <script src="js/CurveExtras.js"></script>
 
+    <script src="js/Stats.js"></script>
 
 
+    <script>
     var container, stats;
 
-    var camera, scene, renderer, splineCamera, cameraHelper, cameraPos;
+    var camera, scene, renderer, splineCamera, cameraHelper, cameraEye;
 
     var text, plane;
 
@@ -377,6 +58,7 @@
       new THREE.Vector3(0, -40, 40),
     ]);
 
+    // Keep a diction of Curve instances
     var splines = {
       HeartCurve: new THREE.Curves.HeartCurve(3.5),
       VivianiCurve: new THREE.Curves.VivianiCurve(70),
@@ -405,22 +87,18 @@
     var s;
     for ( s in splines ) {
       dropdown += '<option value="' + s + '"';
-
-      // dropdown += (geometryIndex == i)  ? ' selected' : '';
-
       dropdown += '>' + s + '</option>';
     }
 
     dropdown += '</select>';
 
-
-
     var closed2 = true;
     var debug = true;
     var parent;
     var tube, tubeMesh;
     var animation = false, lookAhead = false;
     var scale;
+    var showCameraHelper = true;
 
     function addTube() {
 
@@ -469,16 +147,24 @@
 
         if (geometry.debug) tubeMesh.add(geometry.debug);
 
-        // tubeMesh.position.set(x, y, z);
-        // tubeMesh.rotation.set(rx, ry, rz);
         //mesh.children[0].doubleSided = true;
         parent.add(tubeMesh);
 
     }
 
-    function animateCamera() {
-      animation = document.getElementById('animation').checked;
+    function animateCamera(toggle) {
+
+      if (toggle) {
+        animation = !animation;
+        document.getElementById('animation').value = 'Camera Spline Animation View: ' + (animation? 'ON': 'OFF');
+      }
+      
       lookAhead = document.getElementById('lookAhead').checked;
+
+      showCameraHelper = document.getElementById('cameraHelper').checked;
+
+      cameraHelper.children[0].visible = showCameraHelper;
+      cameraEye.visible = showCameraHelper;
     }
 
 
@@ -501,11 +187,10 @@
 
       info.innerHTML += '<br/>Scale: <select id="scale" onchange="setScale()"><option>1</option><option>2</option><option selected>4</option><option>6</option><option>10</option></select>';
       info.innerHTML += '<br/>Extrusion Segments: <select onchange="addTube()" id="segments"><option>50</option><option selected>100</option><option>200</option><option>400</option></select>';
-      info.innerHTML += '<br/>Debug: <input id="debug" type="checkbox" onchange="addTube()" checked /> Closed:<input id="closed" onchange="addTube()" type="checkbox" checked />';
-
       info.innerHTML += '<br/>Radius Segments: <select id="radiusSegments" onchange="addTube()"><option>1</option><option>2</option><option selected>3</option><option>4</option><option>5</option><option>6</option><option>8</option><option>12</option></select>';
+      info.innerHTML += '<br/>Debug normals: <input id="debug" type="checkbox" onchange="addTube()" checked /> Closed:<input id="closed" onchange="addTube()" type="checkbox" checked />';
 
-      info.innerHTML += '<br/>Camera Spline Animation: <input id="animation" type="checkbox" onchange="animateCamera()" /> Look Ahead <input id="lookAhead" type="checkbox" onchange="animateCamera()" />'; //checkbox button
+      info.innerHTML += '<br/><br/><input id="animation" type="button" onclick="animateCamera(true)" value="Camera Spline Animation View: OFF"/><br/> Look Ahead <input id="lookAhead" type="checkbox" onchange="animateCamera()" /> Camera Helper <input id="cameraHelper" type="checkbox" onchange="animateCamera()" checked />';
 
       container.appendChild(info);
 
@@ -532,11 +217,14 @@
       addTube();
 
       // Debug point
-      cameraPos = new THREE.Mesh(new THREE.SphereGeometry(5), new THREE.MeshBasicMaterial({
-            color: 0xdddddd
-        }));
+      cameraEye = new THREE.Mesh(new THREE.SphereGeometry(5), new THREE.MeshBasicMaterial({
+          color: 0xdddddd
+      }));
+
+      cameraHelper.children[0].visible = showCameraHelper;
+      cameraEye.visible = showCameraHelper;
 
-      parent.add(cameraPos);
+      parent.add(cameraEye);
 
       cameraHelper.scale.multiplyScalar(0.1);
       splineCamera.add(cameraHelper);
@@ -647,8 +335,6 @@
       var pos = tube.path.getPointAt(t);
       pos.multiplyScalar(scale);
 
-
-
       // interpolation
       var segments = tube.tangents.length;
       var pickt = t * segments;
@@ -669,7 +355,7 @@
       pos.addSelf(normal.clone().multiplyScalar(offset));
 
       splineCamera.position = pos;
-      cameraPos.position = pos;
+      cameraEye.position = pos;
 
 
       // Camera Orientation 1 - default look at

+ 5 - 15
examples/webgl_geometry_shapes.html

@@ -342,22 +342,12 @@
 				//splineShape.debug( document.getElementById("debug") );
 
 				// TODO 3d path?
-				var extrudePath = new THREE.Path();
-
-				extrudePath.moveTo( 0, 0 );
-				extrudePath.lineTo( 10, 10 );
-				extrudePath.quadraticCurveTo( 80, 60, 160, 10 );
-				extrudePath.quadraticCurveTo( 240, -40, 320, 10 );
-
-				// QUICK HACK, conversion from 2d to 3d spline
-				// Still broken and need fixes.
+				
 				var apath = new THREE.SplineCurve3();
-				var tmpPoints = extrudePath.getPoints();
-				for (t in tmpPoints) {
-					var tmpPt = tmpPoints[t];
-					apath.points.push(new THREE.Vector3(tmpPt.x, tmpPt.y,0 ));
-				}
-
+				apath.points.push(new THREE.Vector3(-50, 150, 10));
+				apath.points.push(new THREE.Vector3(-20, 180, 20));
+				apath.points.push(new THREE.Vector3(40, 220, 50));
+				apath.points.push(new THREE.Vector3(200, 290, 100));
 
 				extrudeSettings.extrudePath = apath;
 				extrudeSettings.bevelEnabled = false;

+ 6 - 2
examples/webgl_geometry_subdivison.html

@@ -23,6 +23,7 @@
 		<script src="../src/extras/geometries/CubeGeometry.js"></script>
 		<script src="../src/extras/geometries/CylinderGeometry.js"></script>
 		<script src="../src/extras/geometries/TorusGeometry.js"></script>
+		<script src="../src/extras/geometries/LatheGeometry.js"></script>
 		<script src="../src/extras/modifiers/SubdivisionModifier.js"></script>
 
 		<script src="fonts/helvetiker_regular.typeface.js"></script>
@@ -223,8 +224,11 @@
 				smooth = THREE.GeometryUtils.clone( geometry );
 
 				// mergeVertices(); is run in case of duplicated vertices
-				smooth.mergeVertices();
-				smooth.computeCentroids();
+				if (! (geometry instanceof THREE.LatheGeometry) ) {
+					smooth.mergeVertices();
+				}
+				
+				// smooth.computeCentroids();
 				// smooth.computeFaceNormals();
 				// smooth.computeVertexNormals();
 				modifier.modify( smooth );

+ 30 - 6
src/extras/cameras/CombinedCamera.js

@@ -1,8 +1,10 @@
 /*
  *	@author zz85 / http://twitter.com/blurspline / http://www.lab4games.net/zz85/blog 
  * 
- *	A handy general perpose camera, for setting FOV, Lens Focal Length,  
+ *	A general perpose camera, for setting FOV, Lens Focal Length,  
  *		and switching between perspective and orthographic views easily.
+ *		Use this only if you do not wish to manage 
+ *		both a Orthographic and Perspective Camera
  *
  */
 
@@ -35,9 +37,10 @@ THREE.CombinedCamera = function ( width, height, fov, near, far, orthonear, orth
 };
 
 THREE.CombinedCamera.prototype = new THREE.Camera();
-THREE.CombinedCamera.prototype.constructor = THREE.CoolCamera;
+THREE.CombinedCamera.prototype.constructor = THREE.CombinedCamera;
 
 THREE.CombinedCamera.prototype.toPerspective = function () {
+	// Switches to the Perspective Camera
 
 	this.near = this.cameraP.near;
 	this.far = this.cameraP.far;
@@ -52,14 +55,14 @@ THREE.CombinedCamera.prototype.toPerspective = function () {
 
 THREE.CombinedCamera.prototype.toOrthographic = function () {
 
-	// Orthographic from Perspective
+	// Switches to the Orthographic camera estimating viewport from Perspective
 	var fov = this.fov;
 	var aspect = this.cameraP.aspect;
 	var near = this.cameraP.near;
 	var far = this.cameraP.far;
 	
 	
-	// Just pretend we want the mid plane of the viewing frustum
+	// The size that we set is the mid plane of the viewing frustum
 	var hyperfocus = ( near + far ) / 2; 
 	
 	var halfHeight = Math.tan( fov / 2 ) * hyperfocus;
@@ -96,6 +99,18 @@ THREE.CombinedCamera.prototype.toOrthographic = function () {
 
 };
 
+	
+THREE.CombinedCamera.prototype.setSize = function(width, height) {
+
+	this.cameraP.aspect = width / height;
+	this.left = -width / 2;
+	this.right = width / 2
+	this.top = height / 2;
+	this.bottom = -height / 2;
+
+}
+
+
 THREE.CombinedCamera.prototype.setFov = function(fov) {	
 	this.fov = fov;
 	
@@ -107,6 +122,16 @@ THREE.CombinedCamera.prototype.setFov = function(fov) {
 
 };
 
+// For mantaining similar API with PerspectiveCamera
+THREE.CombinedCamera.prototype.updateProjectionMatrix = function() {
+	if (this.inPersepectiveMode) {
+		this.toPerspective();
+	} else {
+		this.toPerspective();
+		this.toOrthographic();
+	}
+};
+
 /*
 * Uses Focal Length (in mm) to estimate and set FOV
 * 35mm (fullframe) camera is used if frame size is not specified;
@@ -141,8 +166,7 @@ THREE.CombinedCamera.prototype.toFrontView = function() {
 	this.rotation.x = 0;
 	this.rotation.y = 0;
 	this.rotation.z = 0;
-	
-	//TODO: Better way to disable camera.lookAt()?
+	// should we be modifing the matrix instead?
 	this.rotationAutoUpdate = false;
 };
 

+ 19 - 70
src/extras/core/Curve.js

@@ -7,6 +7,7 @@
  * .getPointAt(u), getTagentAt(u)
  * .getPoints(), .getSpacedPoints()
  * .getLength()
+ * .updateArcLengths()
  *
  * This file contains following classes:
  *
@@ -25,6 +26,8 @@
  * THREE.SplineCurve3
  * THREE.ClosedSplineCurve3
  *
+ * A series of curves can be represented as a THREE.CurvePath
+ *
  **/
 
 /**************************************************************
@@ -67,7 +70,7 @@ THREE.Curve.prototype.getPoints = function ( divisions ) {
 
 		pts.push( this.getPoint( d / divisions ) );
 
-	};
+	}
 
 	return pts;
 
@@ -85,13 +88,13 @@ THREE.Curve.prototype.getSpacedPoints = function ( divisions ) {
 
 		pts.push( this.getPointAt( d / divisions ) );
 
-	};
+	}
 
 	return pts;
 
 };
 
-// Get total curve length
+// Get total curve arc length
 
 THREE.Curve.prototype.getLength = function () {
 
@@ -174,9 +177,9 @@ THREE.Curve.prototype.getUtoTmapping = function ( u, distance ) {
 
 		i = Math.floor( low + ( high - low ) / 2 ); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats
 
-	  	comparison = arcLengths[ i ] - targetArcLength;
+		comparison = arcLengths[ i ] - targetArcLength;
 
-	  	if ( comparison < 0 ) {
+		if ( comparison < 0 ) {
 
 			low = i + 1;
 			continue;
@@ -221,16 +224,16 @@ THREE.Curve.prototype.getUtoTmapping = function ( u, distance ) {
 
     // add that fractional amount to t
 
-    t = ( i + segmentFraction ) / ( il -1 );
+    var t = ( i + segmentFraction ) / ( il -1 );
 
 	return t;
 
 };
 
-// In case any sub curve does not implement its tangent / normal finding,
-// we get 2 points with a small delta and find a gradient of the 2 points
-// which seems to make a reasonable approximation
 
+// In 2D space, there are actually 2 normal vectors,
+// and in 3D space, infinte
+// TODO this should be depreciated.
 THREE.Curve.prototype.getNormalVector = function( t ) {
 
 	var vec = this.getTangent( t );
@@ -240,6 +243,9 @@ THREE.Curve.prototype.getNormalVector = function( t ) {
 };
 
 // Returns a unit vector tangent at t
+// In case any sub curve does not implement its tangent / normal finding,
+// we get 2 points with a small delta and find a gradient of the 2 points
+// which seems to make a reasonable approximation
 
 THREE.Curve.prototype.getTangent = function( t ) {
 
@@ -274,34 +280,17 @@ THREE.Curve.prototype.getTangentAt = function ( u ) {
 
 THREE.LineCurve = function ( v1, v2 ) {
 
-	if ( ! ( v1 instanceof THREE.Vector2 ) ) {
-
-		// Fall back for old constuctor signature - should be removed over time
-
-		THREE.LineCurve.oldConstructor.apply( this, arguments );
-		return;
-
-	}
-
 	this.v1 = v1;
 	this.v2 = v2;
 
 };
 
-THREE.LineCurve.oldConstructor = function ( x1, y1, x2, y2 ) {
-
-	this.constructor( new THREE.Vector2( x1, y1 ), new THREE.Vector2( x2, y2 ) );
-
-};
-
 THREE.LineCurve.prototype = new THREE.Curve();
 THREE.LineCurve.prototype.constructor = THREE.LineCurve;
 
 THREE.LineCurve.prototype.getPoint = function ( t ) {
 
-	var point = new THREE.Vector2();
-
-	point.sub( this.v2, this.v1 );
+	var point = this.v2.clone().subSelf(this.v1);
 	point.multiplyScalar( t ).addSelf( this.v1 );
 
 	return point;
@@ -318,12 +307,9 @@ THREE.LineCurve.prototype.getPointAt = function ( u ) {
 
 THREE.LineCurve.prototype.getTangent = function( t ) {
 
-	var tangent = new THREE.Vector2();
+	var tangent = this.v2.clone().subSelf(this.v1);
 
-	tangent.sub( this.v2, this.v1 );
-	tangent.normalize();
-
-	return tangent;
+	return tangent.normalize();
 
 };
 
@@ -334,16 +320,6 @@ THREE.LineCurve.prototype.getTangent = function( t ) {
 
 THREE.QuadraticBezierCurve = function ( v0, v1, v2 ) {
 
-	if ( !( v1 instanceof THREE.Vector2 ) ) {
-
-		var args = Array.prototype.slice.call( arguments );
-
-		v0 = new THREE.Vector2( args[ 0 ], args[ 1 ] );
-		v1 = new THREE.Vector2( args[ 2 ], args[ 3 ] );
-		v2 = new THREE.Vector2( args[ 4 ], args[ 5 ] );
-
-	}
-
 	this.v0 = v0;
 	this.v1 = v1;
 	this.v2 = v2;
@@ -368,11 +344,6 @@ THREE.QuadraticBezierCurve.prototype.getPoint = function ( t ) {
 
 THREE.QuadraticBezierCurve.prototype.getTangent = function( t ) {
 
-	// iterate sub segments
-	// 	get lengths for sub segments
-	// 	if segment is bezier
-	//		perform subdivisions
-
 	var tx, ty;
 
 	tx = THREE.Curve.Utils.tangentQuadraticBezier( t, this.v0.x, this.v1.x, this.v2.x );
@@ -394,17 +365,6 @@ THREE.QuadraticBezierCurve.prototype.getTangent = function( t ) {
 
 THREE.CubicBezierCurve = function ( v0, v1, v2, v3 ) {
 
-	if ( ! ( v1 instanceof THREE.Vector2 ) ) {
-
-		var args = Array.prototype.slice.call( arguments );
-
-		v0 = new THREE.Vector2( args[ 0 ], args[ 1 ] );
-		v1 = new THREE.Vector2( args[ 2 ], args[ 3 ] );
-		v2 = new THREE.Vector2( args[ 4 ], args[ 5 ] );
-		v3 = new THREE.Vector2( args[ 6 ], args[ 7 ] );
-
-	}
-
 	this.v0 = v0;
 	this.v1 = v1;
 	this.v2 = v2;
@@ -433,8 +393,6 @@ THREE.CubicBezierCurve.prototype.getTangent = function( t ) {
 	tx = THREE.Curve.Utils.tangentCubicBezier( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x );
 	ty = THREE.Curve.Utils.tangentCubicBezier( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y );
 
-	// return normal unit vector
-
 	var tangent = new THREE.Vector2( tx, ty );
 	tangent.normalize();
 
@@ -571,16 +529,7 @@ THREE.Curve.Utils = {
 };
 
 
-/*
-getPoint DONE
-getLength DONE
-getLengths DONE
-
-curve.getPoints(); DONE
-curve.getPointAtArcLength(t); DONE
-curve.transform(params);
-curve.getTangentAt(t); DONE
-*/
+// TODO: Transformation for Curves?
 
 /**************************************************************
  *	3D Curves

+ 2 - 3
src/extras/geometries/ExtrudeGeometry.js

@@ -105,9 +105,8 @@ THREE.ExtrudeGeometry.prototype.addShape = function( shape, options ) {
 
 		// Reuse TNB from TubeGeomtry for now.
 		// TODO1 - have a .isClosed in spline?
-		// TODO2 - have have TNBs calculation refactored from TubeGeometry?
-		splineTube = new THREE.TubeGeometry(extrudePath, steps, 1, 1, false, false);
-		
+		splineTube = new THREE.TubeGeometry.FrenetFrames(extrudePath, steps, false);
+
 		// console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length);
 
 		binormal = new THREE.Vector3();

+ 19 - 22
src/extras/geometries/LatheGeometry.js

@@ -1,5 +1,6 @@
 /**
  * @author astrodud / http://astrodud.isgreat.org/
+ * @author zz85 / https://github.com/zz85
  */
 
 THREE.LatheGeometry = function ( points, steps, angle ) {
@@ -10,7 +11,7 @@ THREE.LatheGeometry = function ( points, steps, angle ) {
 	this.angle = angle || 2 * Math.PI;
 
 	var stepSize = this.angle / this.steps,
-	newV = [], oldInds = [], newInds = [], startInds = [],
+	newV = [],
 	matrix = new THREE.Matrix4().makeRotationZ( stepSize );
 
 	for ( var j = 0; j < points.length; j ++ ) {
@@ -18,46 +19,42 @@ THREE.LatheGeometry = function ( points, steps, angle ) {
 		this.vertices.push( new THREE.Vertex( points[ j ] ) );
 
 		newV[ j ] = points[ j ].clone();
-		oldInds[ j ] = this.vertices.length - 1;
 
 	}
 
-	for ( var r = 0; r <= this.angle + 0.001; r += stepSize ) { // need the +0.001 for it go up to angle
+	for ( var i = 0; i < this.steps; i ++ ) {
 
 		for ( var j = 0; j < newV.length; j ++ ) {
 
-			if ( r < this.angle ) {
-
 				newV[ j ] = matrix.multiplyVector3( newV[ j ].clone() );
 				this.vertices.push( new THREE.Vertex( newV[ j ] ) );
-				newInds[ j ] = this.vertices.length - 1;
-
-			} else {
-
-				newInds = startInds; // wrap it up!
-
-			}
 
 		}
 
-		if ( r == 0 ) startInds = oldInds;
+		var a, b, c, d;
+		var steps = this.steps;
+		for ( var k = 0, kl = points.length; k < kl-1; k++) {
 
-		for ( var j = 0; j < oldInds.length - 1; j ++ ) {
+			a = i * kl + k;
+			b = ((i + 1) % steps) * kl + k;
+			c = ((i + 1) % steps) * kl + (k + 1) % kl;
+			d = i * kl + (k + 1) % kl;
+			
 
-			this.faces.push( new THREE.Face4( newInds[ j ], newInds[ j + 1 ], oldInds[ j + 1 ], oldInds[ j ] ) );
-			this.faceVertexUvs[ 0 ].push( [
+			this.faces.push( new THREE.Face4( a, b, c, d ) );
 
-				new THREE.UV( 1 - r / this.angle, j / points.length ),
-				new THREE.UV( 1 - r / this.angle, ( j + 1 ) / points.length ),
-				new THREE.UV( 1 - ( r - stepSize ) / this.angle, ( j + 1 ) / points.length ),
-				new THREE.UV( 1 - ( r - stepSize ) / this.angle, j / points.length )
+			this.faceVertexUvs[ 0 ].push( [
 
+				// UV mappings which wraps around
+				new THREE.UV( 1 - i / steps, k / kl ),
+				new THREE.UV( 1 - (i + 1) / steps, k / kl ),
+				new THREE.UV( 1 - (i + 1) / steps, ( k+ 1 ) / kl ),
+				new THREE.UV( 1 - i / steps, ( k + 1 ) / kl ),
+				
 			] );
 
 		}
 
-		oldInds = newInds;
-		newInds = [];
 
 	}
 

+ 129 - 99
src/extras/geometries/TubeGeometry.js

@@ -25,62 +25,166 @@ THREE.TubeGeometry = function( path, segments, radius, segmentsRadius, closed, d
 	this.grid = [];
 
 	var scope = this,
-		tangent = new THREE.Vector3(),
-		normal = new THREE.Vector3(),
-		binormal = new THREE.Vector3(),
-
-		vec = new THREE.Vector3(),
-		mat = new THREE.Matrix4(),
 
-		tangents = [],
-		normals = [],
-		binormals = [],
+		tangent,
+		normal,
+		binormal,
 
 		numpoints = this.segments + 1,
-		theta,
-		epsilon = 0.0001,
-		smallest,
+		
 		x, y, z,
 		tx, ty, tz,
 		u, v,
-		p1, p2,
+
 		cx, cy,
-		pos, pos2,
+		pos, pos2 = new THREE.Vector3(),
 		i, j,
 		ip, jp,
 		a, b, c, d,
 		uva, uvb, uvc, uvd;
 
-	// expose internals
+	var frames = new THREE.TubeGeometry.FrenetFrames(path, segments, closed),
+		tangents = frames.tangents,
+		normals = frames.normals,
+		binormals = frames.binormals;
+
+	// proxy internals
 	this.tangents = tangents;
 	this.normals = normals;
 	this.binormals = binormals;
 
-
+	
 	function vert( x, y, z ) {
 
 		return scope.vertices.push( new THREE.Vertex( new THREE.Vector3( x, y, z ) ) ) - 1;
 
 	}
 
+
+
+
+	// consruct the grid
+
+	for ( i = 0; i < numpoints; i++ ) {
+
+		this.grid[ i ] = [];
+
+		u = i / ( numpoints - 1 );
+
+		pos = path.getPointAt( u );
+
+		tangent = tangents[ i ];
+		normal = normals[ i ];
+		binormal = binormals[ i ];
+
+		if ( this.debug ) {
+
+			this.debug.add(new THREE.ArrowHelper(tangent, pos, radius, 0x0000ff));	
+			this.debug.add(new THREE.ArrowHelper(normal, pos, radius, 0xff0000));
+			this.debug.add(new THREE.ArrowHelper(binormal, pos, radius, 0x00ff00));
+
+		}
+
+		for ( j = 0; j < this.segmentsRadius; j++ ) {
+
+			v = j / this.segmentsRadius * 2 * Math.PI;
+
+			cx = -this.radius * Math.cos( v ); // TODO: Hack: Negating it so it faces outside.
+			cy = this.radius * Math.sin( v );
+
+            pos2.copy( pos );
+            pos2.x += cx * normal.x + cy * binormal.x;
+            pos2.y += cx * normal.y + cy * binormal.y;
+            pos2.z += cx * normal.z + cy * binormal.z;
+
+            this.grid[ i ][ j ] = vert( pos2.x, pos2.y, pos2.z );
+
+		}
+	}
+
+
+	// construct the mesh
+
+	for ( i = 0; i < this.segments; i++ ) {
+
+		for ( j = 0; j < this.segmentsRadius; j++ ) {
+
+			ip = ( closed ) ? (i + 1) % this.segments : i + 1;
+			jp = (j + 1) % this.segmentsRadius;
+
+			a = this.grid[ i ][ j ];		// *** NOT NECESSARILY PLANAR ! ***
+			b = this.grid[ ip ][ j ];
+			c = this.grid[ ip ][ jp ];
+			d = this.grid[ i ][ jp ];
+
+			uva = new THREE.UV( i / this.segments, j / this.segmentsRadius );
+			uvb = new THREE.UV( ( i + 1 ) / this.segments, j / this.segmentsRadius );
+			uvc = new THREE.UV( ( i + 1 ) / this.segments, ( j + 1 ) / this.segmentsRadius );
+			uvd = new THREE.UV( i / this.segments, ( j + 1 ) / this.segmentsRadius );
+
+			this.faces.push( new THREE.Face4( a, b, c, d ) );
+			this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvc, uvd ] );
+
+		}
+	}
+
+	this.computeCentroids();
+	this.computeFaceNormals();
+	this.computeVertexNormals();
+
+};
+
+THREE.TubeGeometry.prototype = new THREE.Geometry();
+THREE.TubeGeometry.prototype.constructor = THREE.TubeGeometry;
+
+
+// For computing of Frenet frames, exposing the tangents, normals and binormals the spline
+THREE.TubeGeometry.FrenetFrames = function(path, segments, closed) {
+
+	var 
+		tangent = new THREE.Vector3(),
+		normal = new THREE.Vector3(),
+		binormal = new THREE.Vector3(),
+
+		tangents = [],
+		normals = [],
+		binormals = [],
+
+		vec = new THREE.Vector3(),
+		mat = new THREE.Matrix4(),
+
+		numpoints = segments + 1,
+		theta,
+		epsilon = 0.0001,
+		smallest,
+
+		tx, ty, tz,
+		i, u, v;
+
+
+	// expose internals
+	this.tangents = tangents;
+	this.normals = normals;
+	this.binormals = binormals;
+
 	// compute the tangent vectors for each segment on the path
 
 	for ( i = 0; i < numpoints; i++ ) {
 
 		u = i / ( numpoints - 1 );
 
-		tangents[ i ] = this.path.getTangentAt( u );
+		tangents[ i ] = path.getTangentAt( u );
 		tangents[ i ].normalize();
 
 	}
 
 	initialNormal3();
 
-	function initialNormal1() {
+	function initialNormal1(lastBinormal) {
 		// fixed start binormal. Has dangers of 0 vectors
 		normals[ 0 ] = new THREE.Vector3();
 		binormals[ 0 ] = new THREE.Vector3();
-		var lastBinormal = new THREE.Vector3( 0, 0, 1 );
+		if (lastBinormal===undefined) lastBinormal = new THREE.Vector3( 0, 0, 1 );
 		normals[ 0 ].cross( lastBinormal, tangents[ 0 ] ).normalize();
 		binormals[ 0 ].cross( tangents[ 0 ], normals[ 0 ] ).normalize();
 	}
@@ -90,7 +194,7 @@ THREE.TubeGeometry = function( path, segments, radius, segmentsRadius, closed, d
 		// This uses the Frenet-Serret formula for deriving binormal
 		var t2 = path.getTangentAt( epsilon );
 
-		normals[ 0 ] = new THREE.Vector3().sub( t2, tangents[ 0 ] ).normalize()
+		normals[ 0 ] = new THREE.Vector3().sub( t2, tangents[ 0 ] ).normalize();
 		binormals[ 0 ] = new THREE.Vector3().cross( tangents[ 0 ], normals[ 0 ] );
 
 		normals[ 0 ].cross( binormals[ 0 ], tangents[ 0 ] ).normalize(); // last binormal x tangent
@@ -111,19 +215,19 @@ THREE.TubeGeometry = function( path, segments, radius, segmentsRadius, closed, d
 
 		if ( tx <= smallest ) {
 			smallest = tx;
-			vec.set( 1, 0, 0 );
+			normal.set( 1, 0, 0 );
 		}
 
 		if ( ty <= smallest ) {
 			smallest = ty;
-			vec.set( 0, 1, 0 );
+			normal.set( 0, 1, 0 );
 		}
 
 		if ( tz <= smallest ) {
-			vec.set( 0, 0, 1 );
+			normal.set( 0, 0, 1 );
 		}
 
-		// vec.cross( tangents[ 0 ], normal ).normalize();
+		vec.cross( tangents[ 0 ], normal ).normalize();
 
 		normals[ 0 ].cross( tangents[ 0 ], vec );
 		binormals[ 0 ].cross( tangents[ 0 ], normals[ 0 ] );
@@ -157,7 +261,7 @@ THREE.TubeGeometry = function( path, segments, radius, segmentsRadius, closed, d
 
 	// if the curve is closed, postprocess the vectors so the first and last normal vectors are the same
 
-	if ( this.closed ) {
+	if ( closed ) {
 
 		theta = Math.acos( normals[ 0 ].dot( normals[ numpoints-1 ] ) );
 		theta /= ( numpoints - 1 );
@@ -177,78 +281,4 @@ THREE.TubeGeometry = function( path, segments, radius, segmentsRadius, closed, d
 		}
 
 	}
-
-
-	// consruct the grid
-
-	for ( i = 0; i < numpoints; i++ ) {
-
-		this.grid[ i ] = [];
-
-		u = i / ( numpoints - 1 );
-
-		pos = this.path.getPointAt( u );
-
-		tangent = tangents[ i ];
-		normal = normals[ i ];
-		binormal = binormals[ i ];
-
-		if ( this.debug ) {
-
-			this.debug.add(new THREE.ArrowHelper(tangent, pos, radius, 0x0000ff));	
-			this.debug.add(new THREE.ArrowHelper(normal, pos, radius, 0xff0000));
-			this.debug.add(new THREE.ArrowHelper(binormal, pos, radius, 0x00ff00));
-
-		}
-
-		for ( j = 0; j < this.segmentsRadius; j++ ) {
-
-			v = j / this.segmentsRadius * 2 * Math.PI;
-
-			cx = -this.radius * Math.cos( v ); // TODO: Hack: Negating it so it faces outside.
-			cy = this.radius * Math.sin( v );
-
-            pos2 = new THREE.Vector3().copy( pos );
-            pos2.x += cx * normal.x + cy * binormal.x;
-            pos2.y += cx * normal.y + cy * binormal.y;
-            pos2.z += cx * normal.z + cy * binormal.z;
-
-            this.grid[ i ][ j ] = vert( pos2.x, pos2.y, pos2.z );
-
-		}
-	}
-
-
-	// construct the mesh
-
-	for ( i = 0; i < this.segments; i++ ) {
-
-		for ( j = 0; j < this.segmentsRadius; j++ ) {
-
-			ip = ( closed ) ? (i + 1) % this.segments : i + 1;
-			jp = (j + 1) % this.segmentsRadius;
-
-			a = this.grid[ i ][ j ];		// *** NOT NECESSARILY PLANAR ! ***
-			b = this.grid[ ip ][ j ];
-			c = this.grid[ ip ][ jp ];
-			d = this.grid[ i ][ jp ];
-
-			uva = new THREE.UV( i / this.segments, j / this.segmentsRadius );
-			uvb = new THREE.UV( ( i + 1 ) / this.segments, j / this.segmentsRadius );
-			uvc = new THREE.UV( ( i + 1 ) / this.segments, ( j + 1 ) / this.segmentsRadius );
-			uvd = new THREE.UV( i / this.segments, ( j + 1 ) / this.segmentsRadius );
-
-			this.faces.push( new THREE.Face4( a, b, c, d ) );
-			this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvc, uvd ] );
-
-		}
-	}
-
-	this.computeCentroids();
-	this.computeFaceNormals();
-	this.computeVertexNormals();
-
 };
-
-THREE.TubeGeometry.prototype = new THREE.Geometry();
-THREE.TubeGeometry.prototype.constructor = THREE.TubeGeometry;

+ 174 - 106
src/extras/modifiers/SubdivisionModifier.js

@@ -29,6 +29,7 @@ THREE.SubdivisionModifier = function( subdivisions ) {
 	// Settings
 	this.useOldVertexColors = false;
 	this.supportUVs = true;
+	this.debug = false;
 	
 };
 
@@ -50,7 +51,7 @@ THREE.SubdivisionModifier.prototype.modify = function ( geometry ) {
 // Performs an iteration of Catmull-Clark Subdivision
 THREE.SubdivisionModifier.prototype.smooth = function ( oldGeometry ) {
 	
-	//console.log( 'running smooth' );
+	//debug( 'running smooth' );
 	
 	// New set of vertices, faces and uvs
 	var newVertices = [], newFaces = [], newUVs = [];
@@ -61,7 +62,16 @@ THREE.SubdivisionModifier.prototype.smooth = function ( oldGeometry ) {
 	
 	var scope = this;
 
-	function f4( a, b, c, d, oldFace, orders ) {
+	function debug() {
+		if (scope.debug) console.log.apply(console, arguments);
+	}
+
+	function warn() {
+		if (console)
+		console.log.apply(console, arguments);
+	}
+
+	function f4( a, b, c, d, oldFace, orders, facei ) {
 		
 		// TODO move vertex selection over here!
 		
@@ -96,15 +106,23 @@ THREE.SubdivisionModifier.prototype.smooth = function ( oldGeometry ) {
 		}
 		
 		newFaces.push( newFace );
-		
-		if (!scope.supportUVs || uvForVertices.length!=0) {
-			newUVs.push( [
-				uvForVertices[a],
-				uvForVertices[b],
-				uvForVertices[c],
-				uvForVertices[d]
-			] );
+
+		if (scope.supportUVs) {
+
+			var aUv = [
+				getUV(a, ''),
+				getUV(b, facei),
+				getUV(c, facei),
+				getUV(d, facei)
+			];
 			
+			if (!aUv[0]) debug('a :( ', a+':'+facei);
+			else if (!aUv[1]) debug('b :( ', b+':'+facei);
+			else if (!aUv[2]) debug('c :( ', c+':'+facei);
+			else if (!aUv[3]) debug('d :( ', d+':'+facei);
+			else 
+				newUVs.push( aUv );
+
 		}
 	}
 	
@@ -112,27 +130,27 @@ THREE.SubdivisionModifier.prototype.smooth = function ( oldGeometry ) {
 
 		return Math.min( a, b ) + "_" + Math.max( a, b );
 
-	};
+	}
 	
 	function computeEdgeFaces( geometry ) {
 
-		function addToMap( map, hash, i ) {
+		var i, il, v1, v2, j, k,
+			face, faceIndices, faceIndex,
+			edge,
+			hash,
+			edgeFaceMap = {};
 
-			if ( map[ hash ] === undefined ) {
+		function mapEdgeHash( hash, i ) {
+			
+			if ( edgeFaceMap[ hash ] === undefined ) {
 
-				map[ hash ] = [];
+				edgeFaceMap[ hash ] = [];
 				
-			} 
+			}
 			
-			map[ hash ].push( i );
-
-		};
+			edgeFaceMap[ hash ].push( i );
+		}
 
-		var i, il, v1, v2, j, k,
-			face, faceIndices, faceIndex,
-			edge,
-			hash,
-			vfMap = {};
 
 		// construct vertex -> face map
 
@@ -143,27 +161,27 @@ THREE.SubdivisionModifier.prototype.smooth = function ( oldGeometry ) {
 			if ( face instanceof THREE.Face3 ) {
 
 				hash = edge_hash( face.a, face.b );
-				addToMap( vfMap, hash, i );
+				mapEdgeHash( hash, i );
 
 				hash = edge_hash( face.b, face.c );
-				addToMap( vfMap, hash, i );
+				mapEdgeHash( hash, i );
 
 				hash = edge_hash( face.c, face.a );
-				addToMap( vfMap, hash, i );
+				mapEdgeHash( hash, i );
 
 			} else if ( face instanceof THREE.Face4 ) {
 
 				hash = edge_hash( face.a, face.b );
-				addToMap( vfMap, hash, i );
+				mapEdgeHash( hash, i );
 
 				hash = edge_hash( face.b, face.c );
-				addToMap( vfMap, hash, i );
+				mapEdgeHash( hash, i );
 
 				hash = edge_hash( face.c, face.d );
-				addToMap( vfMap, hash, i );
+				mapEdgeHash( hash, i );
 				
 				hash = edge_hash( face.d, face.a );
-				addToMap( vfMap, hash, i );
+				mapEdgeHash( hash, i );
 
 			}
 
@@ -174,19 +192,19 @@ THREE.SubdivisionModifier.prototype.smooth = function ( oldGeometry ) {
 		// var edges = [];
 		// 
 		// var numOfEdges = 0;
-		// for (i in vfMap) {
+		// for (i in edgeFaceMap) {
 		// 	numOfEdges++;
 		// 	
-		// 	edge = vfMap[i];
+		// 	edge = edgeFaceMap[i];
 		// 	edges.push(edge);
 		// 	
 		// }
 		
-		//console.log('vfMap', vfMap, 'geometry.edges',geometry.edges, 'numOfEdges', numOfEdges);
+		//debug('edgeFaceMap', edgeFaceMap, 'geometry.edges',geometry.edges, 'numOfEdges', numOfEdges);
 
-		return vfMap;
+		return edgeFaceMap;
 
-	};
+	}
 	
 	var originalPoints = oldGeometry.vertices;
 	var originalFaces = oldGeometry.faces;
@@ -197,31 +215,80 @@ THREE.SubdivisionModifier.prototype.smooth = function ( oldGeometry ) {
 	
 	var sharpEdges = {}, sharpVertices = [], sharpFaces = [];
 	
-	var uvForVertices = [];
+	var uvForVertices = {}; // Stored in {vertex}:{old face} format
+
+	var originalVerticesLength = originalPoints.length;
+
+	function getUV(vertexNo, oldFaceNo) {
+		var j,jl;
+
+		var key = vertexNo+':'+oldFaceNo;
+		var theUV = uvForVertices[key];
+
+		if (!theUV) {
+			if (vertexNo>=originalVerticesLength && vertexNo < (originalVerticesLength + originalFaces.length)) {
+				debug('face pt');
+			} else {
+				debug('edge pt');
+			}
+
+			warn('warning, UV not found for', key);
+
+			return null;
+		}
+
+		return theUV;
+ 
+		// Original faces -> Vertex Nos. 
+		// new Facepoint -> Vertex Nos.
+		// edge Points
+
+	}
+
+	function addUV(vertexNo, oldFaceNo, value) {
+
+		var key = vertexNo+':'+oldFaceNo;
+		if (!(key in uvForVertices)) {
+			uvForVertices[key] = value;
+		} else {
+			warn('dup vertexNo', vertexNo, 'oldFaceNo', oldFaceNo, 'value', value, 'key', key, uvForVertices[key]);
+		}
+	}
 	
 	// Step 1
 	//	For each face, add a face point
 	//	Set each face point to be the centroid of all original points for the respective face.
-	
+	// debug(oldGeometry);
 	var i, il, j, jl, face;
 	
 	// For Uvs
 	var uvs = oldGeometry.faceVertexUvs[0];
 	var abcd = 'abcd', vertice;
-	
+
+	debug('originalFaces, uvs, originalVerticesLength', originalFaces.length, uvs.length, originalVerticesLength);
+	if (scope.supportUVs)
 	for (i=0, il = uvs.length; i<il; i++ ) {
 		for (j=0,jl=uvs[i].length;j<jl;j++) {
 			vertice = originalFaces[i][abcd.charAt(j)];
 			
-			if (!uvForVertices[vertice]) {
-				uvForVertices[vertice] = uvs[i][j];
-			} else {
-				//console.log('dup', 	uvForVertices[vertice]);
-			}
-			
+			addUV(vertice, i, uvs[i][j]);
 			
 		}
 	}
+
+	if (uvs.length == 0) scope.supportUVs = false;
+
+	// Additional UVs check, if we index original 
+	var uvCount = 0;
+	for (var u in uvForVertices) {
+		uvCount++;
+	}
+	if (!uvCount) {
+		scope.supportUVs = false;
+		debug('no uvs');
+	}
+
+	debug('-- Original Faces + Vertices UVs completed', uvForVertices, 'vs', uvs.length);
 			
 	var avgUv ;
 	for (i=0, il = originalFaces.length; i<il ;i++) {
@@ -230,66 +297,69 @@ THREE.SubdivisionModifier.prototype.smooth = function ( oldGeometry ) {
 		newPoints.push( new THREE.Vertex(face.centroid) );
 		
 		
-		if (!scope.supportUVs || uvForVertices.length==0) continue;
+		if (!scope.supportUVs) continue;
 		
 		// Prepare subdivided uv
 		
 		avgUv = new THREE.UV();
 		
 		if ( face instanceof THREE.Face3 ) {
-			avgUv.u = uvForVertices[face.a].u + uvForVertices[face.b].u + uvForVertices[face.c].u;
-			avgUv.v = uvForVertices[face.a].v + uvForVertices[face.b].v + uvForVertices[face.c].v;
+			avgUv.u = getUV(face.a, i).u + getUV(face.b, i).u + getUV(face.c, i).u;
+			avgUv.v = getUV(face.a, i).v + getUV(face.b, i).v + getUV(face.c, i).v;
 			avgUv.u /= 3;
 			avgUv.v /= 3;
 			
 		} else if ( face instanceof THREE.Face4 ) {
-			avgUv.u = uvForVertices[face.a].u + uvForVertices[face.b].u + uvForVertices[face.c].u + uvForVertices[face.d].u;
-			avgUv.v = uvForVertices[face.a].v + uvForVertices[face.b].v + uvForVertices[face.c].v + uvForVertices[face.d].v;
+			avgUv.u = getUV(face.a,i).u + getUV(face.b, i).u + getUV(face.c, i).u + getUV(face.d, i).u;
+			avgUv.v = getUV(face.a,i).v + getUV(face.b, i).v + getUV(face.c, i).v + getUV(face.d, i).v;
 			avgUv.u /= 4;
 			avgUv.v /= 4;
 		}
-	
-		uvForVertices.push(avgUv);
+
+		addUV(originalVerticesLength + i, '', avgUv);
+
 	}
 
+	debug('-- added UVs for new Faces', uvForVertices);
+
 	// Step 2
 	//	For each edge, add an edge point.
 	//	Set each edge point to be the average of the two neighbouring face points and its two original endpoints.
 	
-	var vfMap = computeEdgeFaces ( oldGeometry );
+	var edgeFaceMap = computeEdgeFaces ( oldGeometry ); // Edge Hash -> Faces Index
 	var edge, faceIndexA, faceIndexB, avg;
 	
-	//console.log('vfMap', vfMap);
+	// debug('edgeFaceMap', edgeFaceMap);
 
 	var edgeCount = 0;
-	var originalVerticesLength = originalPoints.length;
+
 	var edgeVertex, edgeVertexA, edgeVertexB;
 	
 	////
 	
-	var vertexEdgeMap = {};
-	var vertexFaceMap = {};
+	var vertexEdgeMap = {}; // Gives edges connecting from each vertex
+	var vertexFaceMap = {}; // Gives faces connecting from each vertex
 	
-	var addVertexEdgeMap = function(vertex, edge) {
+	function addVertexEdgeMap(vertex, edge) {
 		if (vertexEdgeMap[vertex]===undefined) {
 			vertexEdgeMap[vertex] = [];
 		}
 		
 		vertexEdgeMap[vertex].push(edge);
-	};
+	}
 	
-	var addVertexFaceMap = function(vertex, face, edge) {
+	function addVertexFaceMap(vertex, face, edge) {
 		if (vertexFaceMap[vertex]===undefined) {
 			vertexFaceMap[vertex] = {};
 		}
 		
-		//vertexFaceMap[vertex][face] = edge;
-		vertexFaceMap[vertex][face] = null;
-	};
+		vertexFaceMap[vertex][face] = edge;
+		// vertexFaceMap[vertex][face] = null;
+	}
 	
 	// Prepares vertexEdgeMap and vertexFaceMap
-	for (i in vfMap) { // This is for every edge
-		edge = vfMap[i];
+	for (i in edgeFaceMap) { // This is for every edge
+		edge = edgeFaceMap[i];
 		
 		edgeVertex = i.split('_');
 		edgeVertexA = edgeVertex[0];
@@ -300,22 +370,6 @@ THREE.SubdivisionModifier.prototype.smooth = function ( oldGeometry ) {
 		addVertexEdgeMap(edgeVertexB, [edgeVertexA, edgeVertexB] );
 		
 		
-		// faceIndexA = edge[0]; // face index a
-		// faceIndexB = edge[1]; // face index b
-		// 
-		// // Add connecting faces for edge
-		// addVertexFaceMap(edgeVertexA, faceIndexA);
-		// addVertexFaceMap(edgeVertexB, faceIndexA);
-		// 
-		// 
-		// if (faceIndexB) {
-		// 	addVertexFaceMap(edgeVertexA, faceIndexB);
-		// 	addVertexFaceMap(edgeVertexB, faceIndexB);
-		// } else {
-		// 	addVertexFaceMap(edgeVertexA, faceIndexA);
-		// 	addVertexFaceMap(edgeVertexB, faceIndexA);
-		// }
-		
 		for (j=0,jl=edge.length;j<jl;j++) {
 			face = edge[j];
 			
@@ -333,13 +387,11 @@ THREE.SubdivisionModifier.prototype.smooth = function ( oldGeometry ) {
 		
 	}
 	
+	debug('vertexEdgeMap',vertexEdgeMap, 'vertexFaceMap', vertexFaceMap);
 	
 	
-	//console.log('vertexEdgeMap',vertexEdgeMap, 'vertexFaceMap', vertexFaceMap);
-	
-	
-	for (i in vfMap) {
-		edge = vfMap[i];
+	for (i in edgeFaceMap) {
+		edge = edgeFaceMap[i];
 		
 		faceIndexA = edge[0]; // face index a
 		faceIndexB = edge[1]; // face index b
@@ -351,10 +403,10 @@ THREE.SubdivisionModifier.prototype.smooth = function ( oldGeometry ) {
 		
 		avg = new THREE.Vector3();
 		
-		//console.log(i, faceIndexB,facePoints[faceIndexB]);
+		//debug(i, faceIndexB,facePoints[faceIndexB]);
 		
 		if (sharpEdges[i]) {
-			//console.log('warning, ', i, 'edge has only 1 connecting face', edge);
+			//debug('warning, ', i, 'edge has only 1 connecting face', edge);
 			
 			// For a sharp edge, average the edge end points.
 			avg.addSelf(originalPoints[edgeVertexA].position);
@@ -377,27 +429,43 @@ THREE.SubdivisionModifier.prototype.smooth = function ( oldGeometry ) {
 		}
 		
 		edgePoints[i] = originalVerticesLength + originalFaces.length + edgeCount;
-		//console.log(edgePoints[i], newPoints.length);
 		
 		newPoints.push( new THREE.Vertex(avg) );
 	
 		edgeCount ++;
 		
-		if (!scope.supportUVs || uvForVertices.length==0) continue;
-		
+		if (!scope.supportUVs) {
+			continue;
+		}
+
+		// debug('faceIndexAB', faceIndexA, faceIndexB, sharpEdges[i]);
+
 		// Prepare subdivided uv
 		
 		avgUv = new THREE.UV();
 		
-		avgUv.u = uvForVertices[edgeVertexA].u + uvForVertices[edgeVertexB].u;
-		avgUv.v = uvForVertices[edgeVertexA].v + uvForVertices[edgeVertexB].v;
+		avgUv.u = getUV(edgeVertexA, faceIndexA).u + getUV(edgeVertexB, faceIndexA).u;
+		avgUv.v = getUV(edgeVertexA, faceIndexA).v + getUV(edgeVertexB, faceIndexA).v;
+		avgUv.u /= 2;
+		avgUv.v /= 2;
+
+		addUV(edgePoints[i], faceIndexA, avgUv);
+
+		if (!sharpEdges[i]) {
+		avgUv = new THREE.UV();
+		
+		avgUv.u = getUV(edgeVertexA, faceIndexB).u + getUV(edgeVertexB, faceIndexB).u;
+		avgUv.v = getUV(edgeVertexA, faceIndexB).v + getUV(edgeVertexB, faceIndexB).v;
 		avgUv.u /= 2;
 		avgUv.v /= 2;
-	
-		uvForVertices.push(avgUv);
+		
+		addUV(edgePoints[i], faceIndexB, avgUv);
+		}
 		
 	}
-	
+
+	debug('-- Step 2 done');
+
 	// Step 3
 	//	For each face point, add an edge for every edge of the face, 
 	//	connecting the face point to each edge point for the face.
@@ -429,9 +497,9 @@ THREE.SubdivisionModifier.prototype.smooth = function ( oldGeometry ) {
 			hashBC = edge_hash( face.b, face.c );
 			hashCA = edge_hash( face.c, face.a );
 			
-			f4( currentVerticeIndex, edgePoints[hashAB], face.b, edgePoints[hashBC], face, abc123 );
-			f4( currentVerticeIndex, edgePoints[hashBC], face.c, edgePoints[hashCA], face, bca123 );
-			f4( currentVerticeIndex, edgePoints[hashCA], face.a, edgePoints[hashAB], face, cab123 );
+			f4( currentVerticeIndex, edgePoints[hashAB], face.b, edgePoints[hashBC], face, abc123, i );
+			f4( currentVerticeIndex, edgePoints[hashBC], face.c, edgePoints[hashCA], face, bca123, i );
+			f4( currentVerticeIndex, edgePoints[hashCA], face.a, edgePoints[hashAB], face, cab123, i );
 			
 		} else if ( face instanceof THREE.Face4 ) {
 			// create 4 face4s
@@ -441,21 +509,21 @@ THREE.SubdivisionModifier.prototype.smooth = function ( oldGeometry ) {
 			hashCD = edge_hash( face.c, face.d );
 			hashDA = edge_hash( face.d, face.a );
 			
-			f4( currentVerticeIndex, edgePoints[hashAB], face.b, edgePoints[hashBC], face, abc1234 );
-			f4( currentVerticeIndex, edgePoints[hashBC], face.c, edgePoints[hashCD], face, bcd1234 );
-			f4( currentVerticeIndex, edgePoints[hashCD], face.d, edgePoints[hashDA], face, cda1234 );
-			f4( currentVerticeIndex, edgePoints[hashDA], face.a, edgePoints[hashAB], face, dab1234  );
+			f4( currentVerticeIndex, edgePoints[hashAB], face.b, edgePoints[hashBC], face, abc1234, i );
+			f4( currentVerticeIndex, edgePoints[hashBC], face.c, edgePoints[hashCD], face, bcd1234, i );
+			f4( currentVerticeIndex, edgePoints[hashCD], face.d, edgePoints[hashDA], face, cda1234, i );
+			f4( currentVerticeIndex, edgePoints[hashDA], face.a, edgePoints[hashAB], face, dab1234, i );
 
 				
 		} else {
-			console.log('face should be a face!', face);
+			debug('face should be a face!', face);
 		}
 	}
 	
 	newVertices = newPoints;
 	
-	// console.log('original ', oldGeometry.vertices.length, oldGeometry.faces.length );
-	// console.log('new points', newPoints.length, 'faces', newFaces.length );
+	// debug('original ', oldGeometry.vertices.length, oldGeometry.faces.length );
+	// debug('new points', newPoints.length, 'faces', newFaces.length );
 	
 	// Step 4
 	
@@ -521,7 +589,7 @@ THREE.SubdivisionModifier.prototype.smooth = function ( oldGeometry ) {
 			// R.addSelf(originalPoints[edge[1]].position);
 		}
 		
-		R.divideScalar(n)
+		R.divideScalar(n);
 		
 		newPos.addSelf(originalPoints[i].position);
 		newPos.multiplyScalar(n - 3);