/** * @author zz85 / http://www.lab4games.net/zz85/blog * @author alteredq / http://alteredqualia.com/ * * For Text operations in three.js (See TextGeometry) * * It uses techniques used in: * * 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/ * */ THREE.FontUtils = { faces: {}, // Just for now. face[weight][style] face: 'helvetiker', weight: 'normal', style: 'normal', size: 150, divisions: 10, getFace: function () { try { return this.faces[ this.face.toLowerCase() ][ this.weight ][ this.style ]; } catch ( e ) { throw "The font " + this.face + " with " + this.weight + " weight and " + this.style + " style is missing." } }, 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; ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data; return data; }, drawText: function ( text ) { // RenderText var i, 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 b2 = THREE.ShapeUtils.b2; var b3 = THREE.ShapeUtils.b3; 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; b2( t, cpx0, cpx1, cpx ); 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( cpx1, cpy1, cpx2, cpy2, 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; b3( t, cpx0, cpx1, cpx2, cpx ); b3( t, cpy0, cpy1, cpy2, cpy ); } } break; } } } return { offset: glyph.ha * scale, path: path }; } }; THREE.FontUtils.generateShapes = function ( text, parameters ) { // Parameters parameters = 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; // Get a Font data json object var data = THREE.FontUtils.drawText( text ); var paths = data.paths; var shapes = []; for ( var p = 0, pl = paths.length; p < pl; p ++ ) { Array.prototype.push.apply( shapes, paths[ p ].toShapes() ); } return shapes; }; // To use the typeface.js face files, hook up the API THREE.typeface_js = { faces: THREE.FontUtils.faces, loadFace: THREE.FontUtils.loadFace }; if ( typeof self !== 'undefined' ) self._typeface_js = THREE.typeface_js;