|
@@ -23,20 +23,8 @@
|
|
* bendPath: <curve> // wraps text according to bend Path
|
|
* bendPath: <curve> // wraps text according to bend Path
|
|
* }
|
|
* }
|
|
*
|
|
*
|
|
- * It uses techniques used in:
|
|
|
|
- *
|
|
|
|
- * typeface.js and canvastext
|
|
|
|
- * For converting fonts and rendering with javascript
|
|
|
|
- * http://typeface.neocracy.org
|
|
|
|
- *
|
|
|
|
- * Triangulation ported from AS3
|
|
|
|
- * Simple Polygon Triangulation
|
|
|
|
- * http://actionsnippet.com/?p=1462
|
|
|
|
- *
|
|
|
|
- * A Method to triangulate shapes with holes
|
|
|
|
- * http://www.sakri.net/blog/2009/06/12/an-approach-to-triangulating-polygons-with-holes/
|
|
|
|
- *
|
|
|
|
*/
|
|
*/
|
|
|
|
+
|
|
/* Usage Examples
|
|
/* Usage Examples
|
|
|
|
|
|
// TextGeometry wrapper
|
|
// TextGeometry wrapper
|
|
@@ -45,8 +33,7 @@
|
|
|
|
|
|
// Complete manner
|
|
// Complete manner
|
|
|
|
|
|
- var textPath = new THREE.TextPath( text, options );
|
|
|
|
- var textShapes = textPath.toShapes();
|
|
|
|
|
|
+ var textShapes = THREE.FontUtils.generateShapes( text, options );
|
|
var text3d = new ExtrudeGeometry( textShapes, options );
|
|
var text3d = new ExtrudeGeometry( textShapes, options );
|
|
|
|
|
|
*/
|
|
*/
|
|
@@ -54,8 +41,7 @@
|
|
|
|
|
|
THREE.TextGeometry = function ( text, parameters ) {
|
|
THREE.TextGeometry = function ( text, parameters ) {
|
|
|
|
|
|
- var textPath = new THREE.TextPath( text, parameters );
|
|
|
|
- var textShapes = textPath.toShapes();
|
|
|
|
|
|
+ var textShapes = THREE.FontUtils.generateShapes( text, parameters );
|
|
|
|
|
|
// translate parameters to ExtrudeGeometry API
|
|
// translate parameters to ExtrudeGeometry API
|
|
|
|
|
|
@@ -83,422 +69,4 @@ THREE.TextGeometry = function ( text, parameters ) {
|
|
};
|
|
};
|
|
|
|
|
|
THREE.TextGeometry.prototype = new THREE.ExtrudeGeometry();
|
|
THREE.TextGeometry.prototype = new THREE.ExtrudeGeometry();
|
|
-THREE.TextGeometry.prototype.constructor = THREE.TextGeometry;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-THREE.FontUtils = {
|
|
|
|
-
|
|
|
|
- faces : {},
|
|
|
|
-
|
|
|
|
- // Just for now. face[weight][style]
|
|
|
|
-
|
|
|
|
- face : "helvetiker",
|
|
|
|
- weight: "normal",
|
|
|
|
- style : "normal",
|
|
|
|
- size : 150,
|
|
|
|
- divisions : 10,
|
|
|
|
-
|
|
|
|
- getFace : function() {
|
|
|
|
-
|
|
|
|
- return this.faces[ this.face ][ this.weight ][ this.style ];
|
|
|
|
-
|
|
|
|
- },
|
|
|
|
-
|
|
|
|
- loadFace : function( data ) {
|
|
|
|
-
|
|
|
|
- var family = data.familyName.toLowerCase();
|
|
|
|
-
|
|
|
|
- var ThreeFont = this;
|
|
|
|
-
|
|
|
|
- ThreeFont.faces[ family ] = ThreeFont.faces[ family ] || {};
|
|
|
|
-
|
|
|
|
- ThreeFont.faces[ family ][ data.cssFontWeight ] = ThreeFont.faces[ family ][ data.cssFontWeight ] || {};
|
|
|
|
- ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data;
|
|
|
|
-
|
|
|
|
- var face = ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data;
|
|
|
|
-
|
|
|
|
- return data;
|
|
|
|
-
|
|
|
|
- },
|
|
|
|
-
|
|
|
|
- drawText : function( text ) {
|
|
|
|
-
|
|
|
|
- var characterPts = [], allPts = [];
|
|
|
|
-
|
|
|
|
- // RenderText
|
|
|
|
-
|
|
|
|
- var i, p,
|
|
|
|
- face = this.getFace(),
|
|
|
|
- scale = this.size / face.resolution,
|
|
|
|
- offset = 0,
|
|
|
|
- chars = String( text ).split( '' ),
|
|
|
|
- length = chars.length;
|
|
|
|
-
|
|
|
|
- var fontPaths = [];
|
|
|
|
-
|
|
|
|
- for ( i = 0; i < length; i ++ ) {
|
|
|
|
-
|
|
|
|
- var path = new THREE.Path();
|
|
|
|
-
|
|
|
|
- var ret = this.extractGlyphPoints( chars[ i ], face, scale, offset, path );
|
|
|
|
- offset += ret.offset;
|
|
|
|
-
|
|
|
|
- fontPaths.push( ret.path );
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // get the width
|
|
|
|
-
|
|
|
|
- var width = offset / 2;
|
|
|
|
- //
|
|
|
|
- // for ( p = 0; p < allPts.length; p++ ) {
|
|
|
|
- //
|
|
|
|
- // allPts[ p ].x -= width;
|
|
|
|
- //
|
|
|
|
- // }
|
|
|
|
-
|
|
|
|
- //var extract = this.extractPoints( allPts, characterPts );
|
|
|
|
- //extract.contour = allPts;
|
|
|
|
-
|
|
|
|
- //extract.paths = fontPaths;
|
|
|
|
- //extract.offset = width;
|
|
|
|
-
|
|
|
|
- return { paths : fontPaths, offset : width };
|
|
|
|
-
|
|
|
|
- },
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- extractGlyphPoints : function( c, face, scale, offset, path ) {
|
|
|
|
-
|
|
|
|
- var pts = [];
|
|
|
|
-
|
|
|
|
- var i, i2, divisions,
|
|
|
|
- outline, action, length,
|
|
|
|
- scaleX, scaleY,
|
|
|
|
- x, y, cpx, cpy, cpx0, cpy0, cpx1, cpy1, cpx2, cpy2,
|
|
|
|
- laste,
|
|
|
|
- glyph = face.glyphs[ c ] || face.glyphs[ '?' ];
|
|
|
|
-
|
|
|
|
- if ( !glyph ) return;
|
|
|
|
-
|
|
|
|
- if ( glyph.o ) {
|
|
|
|
-
|
|
|
|
- outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) );
|
|
|
|
- length = outline.length;
|
|
|
|
-
|
|
|
|
- scaleX = scale;
|
|
|
|
- scaleY = scale;
|
|
|
|
-
|
|
|
|
- for ( i = 0; i < length; ) {
|
|
|
|
-
|
|
|
|
- action = outline[ i ++ ];
|
|
|
|
-
|
|
|
|
- //console.log( action );
|
|
|
|
-
|
|
|
|
- switch( action ) {
|
|
|
|
-
|
|
|
|
- case 'm':
|
|
|
|
-
|
|
|
|
- // Move To
|
|
|
|
-
|
|
|
|
- x = outline[ i++ ] * scaleX + offset;
|
|
|
|
- y = outline[ i++ ] * scaleY;
|
|
|
|
-
|
|
|
|
- path.moveTo( x, y );
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
- case 'l':
|
|
|
|
-
|
|
|
|
- // Line To
|
|
|
|
-
|
|
|
|
- x = outline[ i++ ] * scaleX + offset;
|
|
|
|
- y = outline[ i++ ] * scaleY;
|
|
|
|
- path.lineTo(x,y);
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
- case 'q':
|
|
|
|
-
|
|
|
|
- // QuadraticCurveTo
|
|
|
|
-
|
|
|
|
- cpx = outline[ i++ ] * scaleX + offset;
|
|
|
|
- cpy = outline[ i++ ] * scaleY;
|
|
|
|
- cpx1 = outline[ i++ ] * scaleX + offset;
|
|
|
|
- cpy1 = outline[ i++ ] * scaleY;
|
|
|
|
-
|
|
|
|
- path.quadraticCurveTo(cpx1, cpy1, cpx, cpy);
|
|
|
|
-
|
|
|
|
- laste = pts[ pts.length - 1 ];
|
|
|
|
-
|
|
|
|
- if ( laste ) {
|
|
|
|
-
|
|
|
|
- cpx0 = laste.x;
|
|
|
|
- cpy0 = laste.y;
|
|
|
|
-
|
|
|
|
- for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) {
|
|
|
|
-
|
|
|
|
- var t = i2 / divisions;
|
|
|
|
- var tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx );
|
|
|
|
- var ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy );
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
- case 'b':
|
|
|
|
-
|
|
|
|
- // Cubic Bezier Curve
|
|
|
|
-
|
|
|
|
- cpx = outline[ i++ ] * scaleX + offset;
|
|
|
|
- cpy = outline[ i++ ] * scaleY;
|
|
|
|
- cpx1 = outline[ i++ ] * scaleX + offset;
|
|
|
|
- cpy1 = outline[ i++ ] * -scaleY;
|
|
|
|
- cpx2 = outline[ i++ ] * scaleX + offset;
|
|
|
|
- cpy2 = outline[ i++ ] * -scaleY;
|
|
|
|
-
|
|
|
|
- path.bezierCurveTo( cpx, cpy, cpx1, cpy1, cpx2, cpy2 );
|
|
|
|
-
|
|
|
|
- laste = pts[ pts.length - 1 ];
|
|
|
|
-
|
|
|
|
- if ( laste ) {
|
|
|
|
-
|
|
|
|
- cpx0 = laste.x;
|
|
|
|
- cpy0 = laste.y;
|
|
|
|
-
|
|
|
|
- for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) {
|
|
|
|
-
|
|
|
|
- var t = i2 / divisions;
|
|
|
|
- var tx = THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx );
|
|
|
|
- var ty = THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy );
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- return { offset: glyph.ha*scale, path:path};
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-/**
|
|
|
|
- * This code is a quick port of code written in C++ which was submitted to
|
|
|
|
- * flipcode.com by John W. Ratcliff // July 22, 2000
|
|
|
|
- * See original code and more information here:
|
|
|
|
- * http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml
|
|
|
|
- *
|
|
|
|
- * ported to actionscript by Zevan Rosser
|
|
|
|
- * www.actionsnippet.com
|
|
|
|
- *
|
|
|
|
- * ported to javascript by Joshua Koo
|
|
|
|
- * http://www.lab4games.net/zz85/blog
|
|
|
|
- *
|
|
|
|
- */
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-( function( namespace ) {
|
|
|
|
-
|
|
|
|
- var EPSILON = 0.0000000001;
|
|
|
|
-
|
|
|
|
- // takes in an contour array and returns
|
|
|
|
-
|
|
|
|
- var process = function( contour, indices ) {
|
|
|
|
-
|
|
|
|
- var n = contour.length;
|
|
|
|
-
|
|
|
|
- if ( n < 3 ) return null;
|
|
|
|
-
|
|
|
|
- var result = [],
|
|
|
|
- verts = [],
|
|
|
|
- vertIndices = [];
|
|
|
|
-
|
|
|
|
- /* we want a counter-clockwise polygon in verts */
|
|
|
|
-
|
|
|
|
- var u, v, w;
|
|
|
|
-
|
|
|
|
- if ( area( contour ) > 0.0 ) {
|
|
|
|
-
|
|
|
|
- for ( v = 0; v < n; v++ ) verts[ v ] = v;
|
|
|
|
-
|
|
|
|
- } else {
|
|
|
|
-
|
|
|
|
- for ( v = 0; v < n; v++ ) verts[ v ] = ( n - 1 ) - v;
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- var nv = n;
|
|
|
|
-
|
|
|
|
- /* remove nv - 2 vertices, creating 1 triangle every time */
|
|
|
|
-
|
|
|
|
- var count = 2 * nv; /* error detection */
|
|
|
|
-
|
|
|
|
- for( v = nv - 1; nv > 2; ) {
|
|
|
|
-
|
|
|
|
- /* if we loop, it is probably a non-simple polygon */
|
|
|
|
-
|
|
|
|
- if ( ( count-- ) <= 0 ) {
|
|
|
|
-
|
|
|
|
- //** Triangulate: ERROR - probable bad polygon!
|
|
|
|
-
|
|
|
|
- //throw ( "Warning, unable to triangulate polygon!" );
|
|
|
|
- //return null;
|
|
|
|
- // Sometimes warning is fine, especially polygons are triangulated in reverse.
|
|
|
|
- console.log( "Warning, unable to triangulate polygon!" );
|
|
|
|
-
|
|
|
|
- if ( indices ) return vertIndices;
|
|
|
|
- return result;
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /* three consecutive vertices in current polygon, <u,v,w> */
|
|
|
|
-
|
|
|
|
- u = v; if ( nv <= u ) u = 0; /* previous */
|
|
|
|
- v = u + 1; if ( nv <= v ) v = 0; /* new v */
|
|
|
|
- w = v + 1; if ( nv <= w ) w = 0; /* next */
|
|
|
|
-
|
|
|
|
- if ( snip( contour, u, v, w, nv, verts ) ) {
|
|
|
|
-
|
|
|
|
- var a, b, c, s, t;
|
|
|
|
-
|
|
|
|
- /* true names of the vertices */
|
|
|
|
-
|
|
|
|
- a = verts[ u ];
|
|
|
|
- b = verts[ v ];
|
|
|
|
- c = verts[ w ];
|
|
|
|
-
|
|
|
|
- /* output Triangle */
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- result.push( contour[ a ] );
|
|
|
|
- result.push( contour[ b ] );
|
|
|
|
- result.push( contour[ c ] );
|
|
|
|
- */
|
|
|
|
- result.push( [ contour[ a ],
|
|
|
|
- contour[ b ],
|
|
|
|
- contour[ c ] ] );
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- vertIndices.push( [ verts[ u ], verts[ v ], verts[ w ] ] );
|
|
|
|
-
|
|
|
|
- /* remove v from the remaining polygon */
|
|
|
|
-
|
|
|
|
- for( s = v, t = v + 1; t < nv; s++, t++ ) {
|
|
|
|
-
|
|
|
|
- verts[ s ] = verts[ t ];
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- nv--;
|
|
|
|
-
|
|
|
|
- /* reset error detection counter */
|
|
|
|
-
|
|
|
|
- count = 2 * nv;
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if ( indices ) return vertIndices;
|
|
|
|
- return result;
|
|
|
|
-
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- // calculate area of the contour polygon
|
|
|
|
-
|
|
|
|
- var area = function ( contour ) {
|
|
|
|
-
|
|
|
|
- var n = contour.length;
|
|
|
|
- var a = 0.0;
|
|
|
|
-
|
|
|
|
- for( var p = n - 1, q = 0; q < n; p = q++ ) {
|
|
|
|
-
|
|
|
|
- a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y;
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return a * 0.5;
|
|
|
|
-
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- // see if p is inside triangle abc
|
|
|
|
-
|
|
|
|
- var insideTriangle = function( ax, ay,
|
|
|
|
- bx, by,
|
|
|
|
- cx, cy,
|
|
|
|
- px, py ) {
|
|
|
|
-
|
|
|
|
- var aX, aY, bX, bY;
|
|
|
|
- var cX, cY, apx, apy;
|
|
|
|
- var bpx, bpy, cpx, cpy;
|
|
|
|
- var cCROSSap, bCROSScp, aCROSSbp;
|
|
|
|
-
|
|
|
|
- aX = cx - bx; aY = cy - by;
|
|
|
|
- bX = ax - cx; bY = ay - cy;
|
|
|
|
- cX = bx - ax; cY = by - ay;
|
|
|
|
- apx= px -ax; apy= py - ay;
|
|
|
|
- bpx= px - bx; bpy= py - by;
|
|
|
|
- cpx= px - cx; cpy= py - cy;
|
|
|
|
-
|
|
|
|
- aCROSSbp = aX*bpy - aY*bpx;
|
|
|
|
- cCROSSap = cX*apy - cY*apx;
|
|
|
|
- bCROSScp = bX*cpy - bY*cpx;
|
|
|
|
-
|
|
|
|
- return ( (aCROSSbp >= 0.0) && (bCROSScp >= 0.0) && (cCROSSap >= 0.0) );
|
|
|
|
-
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- var snip = function ( contour, u, v, w, n, verts ) {
|
|
|
|
-
|
|
|
|
- var p;
|
|
|
|
- var ax, ay, bx, by;
|
|
|
|
- var cx, cy, px, py;
|
|
|
|
-
|
|
|
|
- ax = contour[ verts[ u ] ].x;
|
|
|
|
- ay = contour[ verts[ u ] ].y;
|
|
|
|
-
|
|
|
|
- bx = contour[ verts[ v ] ].x;
|
|
|
|
- by = contour[ verts[ v ] ].y;
|
|
|
|
-
|
|
|
|
- cx = contour[ verts[ w ] ].x;
|
|
|
|
- cy = contour[ verts[ w ] ].y;
|
|
|
|
-
|
|
|
|
- if ( EPSILON > (((bx-ax)*(cy-ay)) - ((by-ay)*(cx-ax))) ) return false;
|
|
|
|
-
|
|
|
|
- for ( p = 0; p < n; p++ ) {
|
|
|
|
-
|
|
|
|
- if( (p == u) || (p == v) || (p == w) ) continue;
|
|
|
|
-
|
|
|
|
- px = contour[ verts[ p ] ].x
|
|
|
|
- py = contour[ verts[ p ] ].y
|
|
|
|
-
|
|
|
|
- if ( insideTriangle( ax, ay, bx, by, cx, cy, px, py ) ) return false;
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return true;
|
|
|
|
-
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- namespace.Triangulate = process;
|
|
|
|
- namespace.Triangulate.area = area;
|
|
|
|
-
|
|
|
|
- return namespace;
|
|
|
|
-
|
|
|
|
-})(THREE.FontUtils);
|
|
|
|
-
|
|
|
|
-// To use the typeface.js face files, hook up the API
|
|
|
|
-self._typeface_js = { faces: THREE.FontUtils.faces, loadFace: THREE.FontUtils.loadFace };
|
|
|
|
|
|
+THREE.TextGeometry.prototype.constructor = THREE.TextGeometry;
|