source: other-projects/playing-in-the-street/summer-2013/trunk/Playing-in-the-Street-WPF/Content/Web/mrdoob-three.js-4862f5f/src/extras/FontUtils.js@ 28897

Last change on this file since 28897 was 28897, checked in by davidb, 10 years ago

GUI front-end to server base plus web page content

File size: 9.2 KB
Line 
1/**
2 * @author zz85 / http://www.lab4games.net/zz85/blog
3 * @author alteredq / http://alteredqualia.com/
4 *
5 * For Text operations in three.js (See TextGeometry)
6 *
7 * It uses techniques used in:
8 *
9 * typeface.js and canvastext
10 * For converting fonts and rendering with javascript
11 * http://typeface.neocracy.org
12 *
13 * Triangulation ported from AS3
14 * Simple Polygon Triangulation
15 * http://actionsnippet.com/?p=1462
16 *
17 * A Method to triangulate shapes with holes
18 * http://www.sakri.net/blog/2009/06/12/an-approach-to-triangulating-polygons-with-holes/
19 *
20 */
21
22THREE.FontUtils = {
23
24 faces : {},
25
26 // Just for now. face[weight][style]
27
28 face : "helvetiker",
29 weight: "normal",
30 style : "normal",
31 size : 150,
32 divisions : 10,
33
34 getFace : function() {
35
36 return this.faces[ this.face ][ this.weight ][ this.style ];
37
38 },
39
40 loadFace : function( data ) {
41
42 var family = data.familyName.toLowerCase();
43
44 var ThreeFont = this;
45
46 ThreeFont.faces[ family ] = ThreeFont.faces[ family ] || {};
47
48 ThreeFont.faces[ family ][ data.cssFontWeight ] = ThreeFont.faces[ family ][ data.cssFontWeight ] || {};
49 ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data;
50
51 var face = ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data;
52
53 return data;
54
55 },
56
57 drawText : function( text ) {
58
59 var characterPts = [], allPts = [];
60
61 // RenderText
62
63 var i, p,
64 face = this.getFace(),
65 scale = this.size / face.resolution,
66 offset = 0,
67 chars = String( text ).split( '' ),
68 length = chars.length;
69
70 var fontPaths = [];
71
72 for ( i = 0; i < length; i ++ ) {
73
74 var path = new THREE.Path();
75
76 var ret = this.extractGlyphPoints( chars[ i ], face, scale, offset, path );
77 offset += ret.offset;
78
79 fontPaths.push( ret.path );
80
81 }
82
83 // get the width
84
85 var width = offset / 2;
86 //
87 // for ( p = 0; p < allPts.length; p++ ) {
88 //
89 // allPts[ p ].x -= width;
90 //
91 // }
92
93 //var extract = this.extractPoints( allPts, characterPts );
94 //extract.contour = allPts;
95
96 //extract.paths = fontPaths;
97 //extract.offset = width;
98
99 return { paths : fontPaths, offset : width };
100
101 },
102
103
104
105
106 extractGlyphPoints : function( c, face, scale, offset, path ) {
107
108 var pts = [];
109
110 var i, i2, divisions,
111 outline, action, length,
112 scaleX, scaleY,
113 x, y, cpx, cpy, cpx0, cpy0, cpx1, cpy1, cpx2, cpy2,
114 laste,
115 glyph = face.glyphs[ c ] || face.glyphs[ '?' ];
116
117 if ( !glyph ) return;
118
119 if ( glyph.o ) {
120
121 outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) );
122 length = outline.length;
123
124 scaleX = scale;
125 scaleY = scale;
126
127 for ( i = 0; i < length; ) {
128
129 action = outline[ i ++ ];
130
131 //console.log( action );
132
133 switch( action ) {
134
135 case 'm':
136
137 // Move To
138
139 x = outline[ i++ ] * scaleX + offset;
140 y = outline[ i++ ] * scaleY;
141
142 path.moveTo( x, y );
143 break;
144
145 case 'l':
146
147 // Line To
148
149 x = outline[ i++ ] * scaleX + offset;
150 y = outline[ i++ ] * scaleY;
151 path.lineTo(x,y);
152 break;
153
154 case 'q':
155
156 // QuadraticCurveTo
157
158 cpx = outline[ i++ ] * scaleX + offset;
159 cpy = outline[ i++ ] * scaleY;
160 cpx1 = outline[ i++ ] * scaleX + offset;
161 cpy1 = outline[ i++ ] * scaleY;
162
163 path.quadraticCurveTo(cpx1, cpy1, cpx, cpy);
164
165 laste = pts[ pts.length - 1 ];
166
167 if ( laste ) {
168
169 cpx0 = laste.x;
170 cpy0 = laste.y;
171
172 for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) {
173
174 var t = i2 / divisions;
175 var tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx );
176 var ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy );
177 }
178
179 }
180
181 break;
182
183 case 'b':
184
185 // Cubic Bezier Curve
186
187 cpx = outline[ i++ ] * scaleX + offset;
188 cpy = outline[ i++ ] * scaleY;
189 cpx1 = outline[ i++ ] * scaleX + offset;
190 cpy1 = outline[ i++ ] * -scaleY;
191 cpx2 = outline[ i++ ] * scaleX + offset;
192 cpy2 = outline[ i++ ] * -scaleY;
193
194 path.bezierCurveTo( cpx, cpy, cpx1, cpy1, cpx2, cpy2 );
195
196 laste = pts[ pts.length - 1 ];
197
198 if ( laste ) {
199
200 cpx0 = laste.x;
201 cpy0 = laste.y;
202
203 for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) {
204
205 var t = i2 / divisions;
206 var tx = THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx );
207 var ty = THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy );
208
209 }
210
211 }
212
213 break;
214
215 }
216
217 }
218 }
219
220
221
222 return { offset: glyph.ha*scale, path:path};
223 }
224
225};
226
227
228THREE.FontUtils.generateShapes = function( text, parameters ) {
229
230 // Parameters
231
232 parameters = parameters || {};
233
234 var size = parameters.size !== undefined ? parameters.size : 100;
235 var curveSegments = parameters.curveSegments !== undefined ? parameters.curveSegments: 4;
236
237 var font = parameters.font !== undefined ? parameters.font : "helvetiker";
238 var weight = parameters.weight !== undefined ? parameters.weight : "normal";
239 var style = parameters.style !== undefined ? parameters.style : "normal";
240
241 THREE.FontUtils.size = size;
242 THREE.FontUtils.divisions = curveSegments;
243
244 THREE.FontUtils.face = font;
245 THREE.FontUtils.weight = weight;
246 THREE.FontUtils.style = style;
247
248 // Get a Font data json object
249
250 var data = THREE.FontUtils.drawText( text );
251
252 var paths = data.paths;
253 var shapes = [];
254
255 for ( var p = 0, pl = paths.length; p < pl; p ++ ) {
256
257 Array.prototype.push.apply( shapes, paths[ p ].toShapes() );
258
259 }
260
261 return shapes;
262
263};
264
265
266/**
267 * This code is a quick port of code written in C++ which was submitted to
268 * flipcode.com by John W. Ratcliff // July 22, 2000
269 * See original code and more information here:
270 * http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml
271 *
272 * ported to actionscript by Zevan Rosser
273 * www.actionsnippet.com
274 *
275 * ported to javascript by Joshua Koo
276 * http://www.lab4games.net/zz85/blog
277 *
278 */
279
280
281( function( namespace ) {
282
283 var EPSILON = 0.0000000001;
284
285 // takes in an contour array and returns
286
287 var process = function( contour, indices ) {
288
289 var n = contour.length;
290
291 if ( n < 3 ) return null;
292
293 var result = [],
294 verts = [],
295 vertIndices = [];
296
297 /* we want a counter-clockwise polygon in verts */
298
299 var u, v, w;
300
301 if ( area( contour ) > 0.0 ) {
302
303 for ( v = 0; v < n; v++ ) verts[ v ] = v;
304
305 } else {
306
307 for ( v = 0; v < n; v++ ) verts[ v ] = ( n - 1 ) - v;
308
309 }
310
311 var nv = n;
312
313 /* remove nv - 2 vertices, creating 1 triangle every time */
314
315 var count = 2 * nv; /* error detection */
316
317 for( v = nv - 1; nv > 2; ) {
318
319 /* if we loop, it is probably a non-simple polygon */
320
321 if ( ( count-- ) <= 0 ) {
322
323 //** Triangulate: ERROR - probable bad polygon!
324
325 //throw ( "Warning, unable to triangulate polygon!" );
326 //return null;
327 // Sometimes warning is fine, especially polygons are triangulated in reverse.
328 console.log( "Warning, unable to triangulate polygon!" );
329
330 if ( indices ) return vertIndices;
331 return result;
332
333 }
334
335 /* three consecutive vertices in current polygon, <u,v,w> */
336
337 u = v; if ( nv <= u ) u = 0; /* previous */
338 v = u + 1; if ( nv <= v ) v = 0; /* new v */
339 w = v + 1; if ( nv <= w ) w = 0; /* next */
340
341 if ( snip( contour, u, v, w, nv, verts ) ) {
342
343 var a, b, c, s, t;
344
345 /* true names of the vertices */
346
347 a = verts[ u ];
348 b = verts[ v ];
349 c = verts[ w ];
350
351 /* output Triangle */
352
353 result.push( [ contour[ a ],
354 contour[ b ],
355 contour[ c ] ] );
356
357
358 vertIndices.push( [ verts[ u ], verts[ v ], verts[ w ] ] );
359
360 /* remove v from the remaining polygon */
361
362 for( s = v, t = v + 1; t < nv; s++, t++ ) {
363
364 verts[ s ] = verts[ t ];
365
366 }
367
368 nv--;
369
370 /* reset error detection counter */
371
372 count = 2 * nv;
373
374 }
375
376 }
377
378 if ( indices ) return vertIndices;
379 return result;
380
381 };
382
383 // calculate area of the contour polygon
384
385 var area = function ( contour ) {
386
387 var n = contour.length;
388 var a = 0.0;
389
390 for( var p = n - 1, q = 0; q < n; p = q++ ) {
391
392 a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y;
393
394 }
395
396 return a * 0.5;
397
398 };
399
400 var snip = function ( contour, u, v, w, n, verts ) {
401
402 var p;
403 var ax, ay, bx, by;
404 var cx, cy, px, py;
405
406 ax = contour[ verts[ u ] ].x;
407 ay = contour[ verts[ u ] ].y;
408
409 bx = contour[ verts[ v ] ].x;
410 by = contour[ verts[ v ] ].y;
411
412 cx = contour[ verts[ w ] ].x;
413 cy = contour[ verts[ w ] ].y;
414
415 if ( EPSILON > (((bx-ax)*(cy-ay)) - ((by-ay)*(cx-ax))) ) return false;
416
417 var aX, aY, bX, bY, cX, cY;
418 var apx, apy, bpx, bpy, cpx, cpy;
419 var cCROSSap, bCROSScp, aCROSSbp;
420
421 aX = cx - bx; aY = cy - by;
422 bX = ax - cx; bY = ay - cy;
423 cX = bx - ax; cY = by - ay;
424
425 for ( p = 0; p < n; p++ ) {
426
427 if( (p === u) || (p === v) || (p === w) ) continue;
428
429 px = contour[ verts[ p ] ].x
430 py = contour[ verts[ p ] ].y
431
432 apx = px - ax; apy = py - ay;
433 bpx = px - bx; bpy = py - by;
434 cpx = px - cx; cpy = py - cy;
435
436 // see if p is inside triangle abc
437
438 aCROSSbp = aX*bpy - aY*bpx;
439 cCROSSap = cX*apy - cY*apx;
440 bCROSScp = bX*cpy - bY*cpx;
441
442 if ( (aCROSSbp >= -EPSILON) && (bCROSScp >= -EPSILON) && (cCROSSap >= -EPSILON) ) return false;
443
444 }
445
446 return true;
447
448 };
449
450
451 namespace.Triangulate = process;
452 namespace.Triangulate.area = area;
453
454 return namespace;
455
456})(THREE.FontUtils);
457
458// To use the typeface.js face files, hook up the API
459self._typeface_js = { faces: THREE.FontUtils.faces, loadFace: THREE.FontUtils.loadFace };
460THREE.typeface_js = self._typeface_js;
Note: See TracBrowser for help on using the repository browser.