| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571 |
- /**
- * @author zz85 / http://www.lab4games.net/zz85/blog
- * @author alteredq / http://alteredqualia.com/
- *
- * For creating 3D text geometry in three.js
- *
- * Text = 3D Text
- *
- * 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
- *
- * bend: <bool> // bend according to hardcoded curve (generates bendPath)
- * 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/
- *
- */
- THREE.TextGeometry = function ( text, parameters ) {
- var textPath = new THREE.TextPath( text, parameters );
- var textShapes = textPath.toShapes();
- // translate parameters to ExtrudeGeometry API
- parameters.amount = parameters.height !== undefined ? parameters.height : 50;
- // defaults
- if ( parameters.bevelThickness === undefined ) parameters.bevelThickness = 10;
- if ( parameters.bevelSize === undefined ) parameters.bevelSize = 8;
- if ( parameters.bevelEnabled === undefined ) parameters.bevelEnabled = false;
- if ( parameters.bend ) {
- var b = textShapes[ textShapes.length - 1 ].getBoundingBox();
- var max = b.maxX;
- parameters.bendPath = new THREE.QuadraticBezierCurve( new THREE.Vector2( 0, 0 ),
- new THREE.Vector2( max / 2, 120 ),
- new THREE.Vector2( max, 0 ) );
- }
- // // Bend Testings.
- //
- // var path = new THREE.CurvePath();
- //
- // path.add(new THREE.CubicBezierCurve(
- // new THREE.Vector2(0, 0),
- // new THREE.Vector2(10, 100),
- // new THREE.Vector2(200, -10),
- // new THREE.Vector2(300, 0)
- // ));
- //
- // path.add(new THREE.QuadraticBezierCurve(
- // new THREE.Vector2(300, 0),
- // new THREE.Vector2(450, -10),
- // new THREE.Vector2(500, 100)
- // ));
- //
- // parameters.bendPath = path;
- // var path = new THREE.CurvePath();
- // path.add(new THREE.LineCurve( 0, 50, 250, 150));
- // path.add(new THREE.LineCurve( 250, 150, 400, 50));
- // path.add(new THREE.LineCurve( 400, 50, 0, 50));
- // parameters.bendPath = path;
-
- // var path = new THREE.ArcCurve(0, 0, 200, Math.PI * 0, Math.PI * 2, true);
- // parameters.bendPath = path;
-
- // var path = new THREE.SplineCurve([
- // new THREE.Vector2(0, 0),
- // new THREE.Vector2(100, 40),
- // new THREE.Vector2(200, 0),
- // new THREE.Vector2(400, 20)
- // ]);
- //
- // console.log(path);
- //
- // path = new THREE.LineCurve( new THREE.Vector2(0, 0), new THREE.Vector2(400, 100));
- // var bend = new THREE.Path();
- // bend.moveTo(0,0);
- // bend.quadraticCurveTo( 500, 100, 1000, 0 );
- //
- // parameters.bendPath = bend;
- THREE.ExtrudeGeometry.call( this, textShapes, parameters );
- };
- THREE.TextGeometry.prototype = new THREE.ExtrudeGeometry();
- THREE.TextGeometry.prototype.constructor = THREE.TextGeometry;
- /*
- // TextGeometry wrapper
- var text3d = new TextGeometry( text, options );
- // Complete manner
- var textPath = new TextPath( text, options );
- var textShapes = textPath.toShapes();
- var text3d = new ExtrudeGeometry( textShapes, options );
- // Factory Method
- var textShapes = FontUtils.getTextShapes( text, options );
- text3d = new ExtrudeGeometry( textShapes, options );
- */
- 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 ];
- },
- getTextShapes: function( text, options ) {
- var textPath = new TextPath( text, options );
- var textShapes = textPath.toShapes();
- return textShapes;
- },
- 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;
- //characterPts.push( ret.points );
- //allPts = allPts.concat( ret.points );
- 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,
- outline, action, length,
- scaleX, scaleY,
- x, y, cpx, cpy, cpx0, cpy0, cpx1, cpy1, cpx2, cpy2,
- laste,
- glyph = face.glyphs[ c ] || face.glyphs[ ctxt.options.fallbackCharacter ];
- 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;
- pts.push( new THREE.Vector2( x, y ) );
- path.moveTo( x, y );
- break;
- case 'l':
- // Line To
- x = outline[ i++ ] * scaleX + offset;
- y = outline[ i++ ] * scaleY;
- pts.push( new THREE.Vector2( x, y ) );
- 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 );
- pts.push( new THREE.Vector2( tx, ty ) );
- }
- }
- 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 );
- pts.push( new THREE.Vector2( tx, ty ) );
- }
- }
- break;
- }
- }
- }
- return { offset: glyph.ha*scale, points:pts, 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
- window._typeface_js = { faces: THREE.FontUtils.faces, loadFace: THREE.FontUtils.loadFace };
|