diff --git a/examples/canvas_geometry_shape.html b/examples/canvas_geometry_shape.html new file mode 100644 index 00000000..e3cb443c --- /dev/null +++ b/examples/canvas_geometry_shape.html @@ -0,0 +1,318 @@ + + + + three.js canvas/webgl - geometry - text + + + + + + + + + + + + + + + + + + + + diff --git a/src/extras/geometries/Path.js b/src/extras/geometries/Path.js new file mode 100644 index 00000000..7393e073 --- /dev/null +++ b/src/extras/geometries/Path.js @@ -0,0 +1,407 @@ +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * Creates free form path. + **/ + +THREE.Path = function (points) { + this.path = []; + if (points) { + this.fromPoints(points); + } +}; + +var ACTIONS = { + MOVE_TO: 'moveTo', + LINE_TO: 'lineTo', + QUADRATIC_CURVE_TO: 'quadraticCurveTo', //BEZIER quadratic CURVE + BEZIER_CURVE_TO: 'bezierCurveTo', //BEZIER cubic CURVE + CSPLINE_TO: 'cSplineTo' // TODO cardinal splines +}; + +/* create path using straight lines to connect all points */ +THREE.Path.prototype.fromPoints = function(vectors) { + var v = 0, vlen = vectors.length; + this.moveTo(vectors[0].x, vectors[0].y); + for (v=1; v 0 ) { + laste = pts[ pts.length - 1 ]; + cpx0 = laste.x; + cpy0 = laste.y; + } else { + laste = this.path[x-1].args; + cpx0 = laste[laste.length-2]; + cpy0 = laste[laste.length-1]; + } + + for ( i2 = 1; i2 <= divisions; i2++ ) { + // TODO use LOD for divions + var t = i2 / divisions; + var tx = THREE.FontUtils.b2( t, cpx0, cpx1, cpx ); + var ty = THREE.FontUtils.b2( t, cpy0, cpy1, cpy ); + pts.push( new THREE.Vector2( tx, ty ) ); + + } + + + + break; + + case ACTIONS.BEZIER_CURVE_TO: + cpx = args[4]; + cpy = args[5]; + + cpx1 = args[0]; + cpy1 = args[1]; + + cpx2 = args[2]; + cpy2 = args[3]; + + var laste, cpx0, cpy0; + if (pts.length > 0 ) { + laste = pts[ pts.length - 1 ]; + cpx0 = laste.x; + cpy0 = laste.y; + } else { + laste = this.path[x-1].args; + cpx0 = laste[laste.length-2]; + cpy0 = laste[laste.length-1]; + } + + + for ( i2 = 1; 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 ); + pts.push( new THREE.Vector2( tx, ty ) ); + + } + + + break; + + } + + } + + return pts; + +}; + + +THREE.Path.prototype.getMinAndMax = function() { + var pts = this.getPoints(); + var maxX = maxY = Number.NEGATIVE_INFINITY; + var minX = minY = Number.POSITIVE_INFINITY; + var p, pt; + for (p in pts) { + pt = pts[p]; + if (pt.x > maxX) maxX = pt.x; + if (pt.y > maxY) maxY = pt.y; + if (pt.x < minX) minX = pt.x; + if (pt.y < maxY) minY = pt.y; + + } + + // TODO find mid-pt? + return { + minX: minX, + minY: minY, + maxX: maxX, + maxY: maxY + }; + +}; + +/* Draws this path onto a 2d canvas easily */ +THREE.Path.prototype.debug = function(canvas) { + // JUST A STUB + if (!canvas) { + canvas = document.createElement("canvas"); + canvas.setAttribute('width', 200); + canvas.setAttribute('height', 200); + document.body.appendChild(canvas); + + } + + var ctx = canvas.getContext("2d"); + ctx.fillStyle = "white"; + ctx.fillRect(0,0,200,200); + + ctx.strokeStyle = "black"; + ctx.beginPath(); + + + var i,o, a; + + // Debug Path + for (i in this.path) { + o = this.path[i]; + a = o.args; + + // Short hand for now + ctx[o.action].apply(ctx, a); + + /* + switch (o.action) { + case ACTIONS.MOVE_TO: + ctx[o.action](a[0],a[1]); + break; + case ACTIONS.LINE_TO: + ctx[o.action](a[0],a[1]); + break; + case ACTIONS.QUADRATIC_CURVE_TO: + ctx[o.action](a[0],a[1],a[2],a[3]); + break; + case ACTIONS.CUBIC_CURVE_TO: + ctx[o.action](a[0],a[1],a[2],a[3], a[4], a[5]); + break; + }*/ + + + } + ctx.stroke(); + ctx.closePath(); + + + + + // DebugPoints + ctx.strokeStyle = "red"; + var pts = this.getPoints(); + + for (var p in pts) { + ctx.beginPath(); + ctx.arc(pts[p].x,pts[p].y, 1.5,0, Math.PI*2, false); + ctx.stroke(); + ctx.closePath(); + } + + + +}; + +// STEP 1 Create a path. +// STEP 2 Turn path into shape. +// STEP 3 Extrude Geometry takes in Shape/Shapes +// STEP 3a - Extract points from each shape, turn to Vertics +// STEP 3b - Triangulate Each Shape + +/* Defines a 2d shape plane using paths */ + +THREE.Shape = function ( ) { + + THREE.Path.apply( this, arguments); + this.holes = []; + +}; + +THREE.Shape.prototype = new THREE.Path(); + +THREE.Shape.prototype.constructor = THREE.Path; + +/* Returns vertices of triangulated faces | get faces */ +THREE.Shape.prototype.triangulate = function() { + return THREE.FontUtils.Triangulate( this.getPoints(), true ); +}; + +/* Convienence Method to return ExtrudeGeometry */ +THREE.Shape.prototype.extrude = function(options) { + var extruded = new THREE.ExtrudeGeometry(this, options); + return extruded; +}; + +THREE.ExtrudeGeometry = function(shape, options) { + var amount; + if (!options.amount) { + amount = 100; + } else { + amount = options.amount; + } + + + THREE.Geometry.call( this ); + + vertices = shape.getPoints(); + faces = shape.triangulate(); + contour = vertices; + bezelEnabled = false; + + var scope = this; + + var i, + vert, vlen = vertices.length, + face, flen = faces.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, amount ); + + } + + if ( bezelEnabled ) { + + for ( i = 0; i < blen; i++ ) { + + bezelPt = bezelPoints[ i ]; + v( bezelPt.x, bezelPt.y, bezelThickness ); + + } + + for ( i = 0; i < blen; i++ ) { + + bezelPt = bezelPoints[ i ]; + v( bezelPt.x, bezelPt.y, amount - bezelThickness ); + + } + + } + + // 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; + + + // Faces Sides + + contour.push(contour[0]); // in order not to check for boundary indics every time. + + i = contour.length; + + while ( --i > 0 ) { + + lastV = contour[ i ]; + + 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 ) { + + scope.vertices.push( new THREE.Vertex( new THREE.Vector3( x, y, z ) ) ); + + } + + function f3( a, b, c ) { + + scope.faces.push( new THREE.Face3( a, b, c) ); + + } + + function f4( a, b, c, d ) { + + scope.faces.push( new THREE.Face4( a, b, c, d) ); + + } + + +}; + + + +THREE.ExtrudeGeometry.prototype = new THREE.Geometry(); +THREE.ExtrudeGeometry.prototype.constructor = THREE.ExtrudeGeometry; diff --git a/src/extras/geometries/TextGeometry.js b/src/extras/geometries/TextGeometry.js index a0b7de31..cd0e7fc7 100644 --- a/src/extras/geometries/TextGeometry.js +++ b/src/extras/geometries/TextGeometry.js @@ -663,6 +663,8 @@ THREE.FontUtils = { offset = 0, chars = String( text ).split( '' ), length = chars.length; + + var fontPaths = []; for ( i = 0; i < length; i++ ) { @@ -670,6 +672,7 @@ THREE.FontUtils = { offset += ret.offset; characterPts.push( ret.points ); allPts = allPts.concat( ret.points ); + fontPaths.push( ret.path ); } @@ -849,6 +852,8 @@ THREE.FontUtils = { extractGlyphPoints : function( c, face, scale, offset ) { var pts = []; + var path = new THREE.Path(); + var i, i2, outline, action, length, @@ -880,6 +885,8 @@ THREE.FontUtils = { x = outline[ i++ ] * scaleX + offset; y = outline[ i++ ] * scaleY; pts.push( new THREE.Vector2( x, y ) ); + + path.moveTo(x,y); break; case 'l': @@ -889,6 +896,7 @@ THREE.FontUtils = { x = outline[ i++ ] * scaleX + offset; y = outline[ i++ ] * scaleY; pts.push( new THREE.Vector2( x, y ) ); + path.lineTo(x,y); break; case 'q': @@ -899,6 +907,8 @@ THREE.FontUtils = { cpy = outline[ i++ ] * scaleY; cpx1 = outline[ i++ ] * scaleX + offset; cpy1 = outline[ i++ ] * scaleY; + + path.quadraticCurveTo(cpx1, cpy1, cpx, cpy); laste = pts[ pts.length - 1 ]; @@ -930,6 +940,8 @@ THREE.FontUtils = { cpy1 = outline[ i++ ] * -scaleY; cpx2 = outline[ i++ ] * scaleX + offset; cpy2 = outline[ i++ ] * -scaleY; + + path.quadraticCurveTo(cpx, cpy, cpx1, cpy1, cpx2, cpy2); laste = pts[ pts.length - 1 ]; @@ -955,8 +967,11 @@ THREE.FontUtils = { } } + + path.debug(document.getElementById("boo")); + console.log(path); - return { offset: glyph.ha*scale, points:pts }; + return { offset: glyph.ha*scale, points:pts, path:path}; } };