|
@@ -2,166 +2,192 @@
|
|
* @author gero3 / https://github.com/gero3
|
|
* @author gero3 / https://github.com/gero3
|
|
* @author tentone / https://github.com/tentone
|
|
* @author tentone / https://github.com/tentone
|
|
* Requires opentype.js to be included in the project
|
|
* Requires opentype.js to be included in the project
|
|
- * Loads TTF files and converts them into typeface JSON that can be used directly to create THREE.Font objects
|
|
|
|
|
|
+ * Loads TTF files and converts them into typeface JSON that can be used directly
|
|
|
|
+ * to create THREE.Font objects
|
|
*/
|
|
*/
|
|
|
|
|
|
-"use strict";
|
|
|
|
|
|
+'use strict';
|
|
|
|
|
|
-THREE.TTFLoader = function(manager)
|
|
|
|
-{
|
|
|
|
- this.manager = (manager !== undefined) ? manager : THREE.DefaultLoadingManager;
|
|
|
|
|
|
+THREE.TTFLoader = function ( manager ) {
|
|
|
|
+
|
|
|
|
+ this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
|
|
this.reversed = false;
|
|
this.reversed = false;
|
|
-}
|
|
|
|
-
|
|
|
|
-THREE.TTFLoader.prototype.load = function(url, onLoad, onProgress, onError)
|
|
|
|
-{
|
|
|
|
- var self = this;
|
|
|
|
- var loader = new THREE.XHRLoader(this.manager);
|
|
|
|
- loader.setResponseType("arraybuffer");
|
|
|
|
- loader.load(url, function(buffer)
|
|
|
|
- {
|
|
|
|
- var json = self.parse( buffer );
|
|
|
|
- if(onLoad !== undefined)
|
|
|
|
- {
|
|
|
|
- onLoad(json);
|
|
|
|
|
|
+
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+THREE.TTFLoader.prototype.load = function ( url, onLoad, onProgress, onError ) {
|
|
|
|
+
|
|
|
|
+ var scope = this;
|
|
|
|
+
|
|
|
|
+ var loader = new THREE.XHRLoader( this.manager );
|
|
|
|
+ loader.setResponseType( 'arraybuffer' );
|
|
|
|
+ loader.load( url, function ( buffer ) {
|
|
|
|
+
|
|
|
|
+ if ( onLoad !== undefined ) {
|
|
|
|
+
|
|
|
|
+ onLoad( scope.parse( buffer ) );
|
|
|
|
+
|
|
}
|
|
}
|
|
- }, onProgress, onError);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-THREE.TTFLoader.prototype.parse = function(arraybuffer)
|
|
|
|
-{
|
|
|
|
- if(typeof opentype === "undefined")
|
|
|
|
- {
|
|
|
|
- console.warn("TTFLoader requires opentype.js Make sure it\'s included before using the loader");
|
|
|
|
|
|
+
|
|
|
|
+ }, onProgress, onError );
|
|
|
|
+
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+THREE.TTFLoader.prototype.parse = function ( arraybuffer ) {
|
|
|
|
+
|
|
|
|
+ if ( typeof opentype === 'undefined' ) {
|
|
|
|
+
|
|
|
|
+ console.warn( 'TTFLoader requires opentype.js Make sure it\'s included before using the loader' );
|
|
return null;
|
|
return null;
|
|
|
|
+
|
|
}
|
|
}
|
|
|
|
|
|
- var font = opentype.parse(arraybuffer);
|
|
|
|
- return THREE.TTFLoader.convert(font, this.reversed);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-THREE.TTFLoader.convert = function(font, reversed)
|
|
|
|
-{
|
|
|
|
- var scale = (100000) / ((font.unitsPerEm || 2048) * 72);
|
|
|
|
- var result = {};
|
|
|
|
- result.glyphs = {};
|
|
|
|
-
|
|
|
|
- for(var i = 0; i < font.glyphs.length; i++)
|
|
|
|
- {
|
|
|
|
- var glyph = font.glyphs.glyphs[i];
|
|
|
|
-
|
|
|
|
- if(glyph.unicode !== undefined)
|
|
|
|
- {
|
|
|
|
- var token = {};
|
|
|
|
- token.ha = Math.round(glyph.advanceWidth * scale);
|
|
|
|
- token.x_min = Math.round(glyph.xMin * scale);
|
|
|
|
- token.x_max = Math.round(glyph.xMax * scale);
|
|
|
|
- token.o = ""
|
|
|
|
-
|
|
|
|
- if(reversed)
|
|
|
|
- {
|
|
|
|
- glyph.path.commands = TTFLoader.reverseCommands(glyph.path.commands);
|
|
|
|
- }
|
|
|
|
|
|
+ function convert( font, reversed ) {
|
|
|
|
+
|
|
|
|
+ var round = Math.round;
|
|
|
|
+
|
|
|
|
+ var glyphs = {};
|
|
|
|
+ var scale = ( 100000 ) / ( ( font.unitsPerEm || 2048 ) * 72 );
|
|
|
|
+
|
|
|
|
+ for ( var i = 0; i < font.glyphs.length; i ++ ) {
|
|
|
|
+
|
|
|
|
+ var glyph = font.glyphs.glyphs[ i ];
|
|
|
|
+
|
|
|
|
+ if ( glyph.unicode !== undefined ) {
|
|
|
|
+
|
|
|
|
+ var token = {
|
|
|
|
+ ha: round( glyph.advanceWidth * scale ),
|
|
|
|
+ x_min: round( glyph.xMin * scale ),
|
|
|
|
+ x_max: round( glyph.xMax * scale ),
|
|
|
|
+ o: ''
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ if ( reversed ) {
|
|
|
|
+
|
|
|
|
+ glyph.path.commands = reverseCommands( glyph.path.commands );
|
|
|
|
|
|
- glyph.path.commands.forEach(function(command, i)
|
|
|
|
- {
|
|
|
|
- if(command.type.toLowerCase() === "c")
|
|
|
|
- {
|
|
|
|
- command.type = "b";
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- token.o += command.type.toLowerCase();
|
|
|
|
- token.o += " "
|
|
|
|
-
|
|
|
|
- if(command.x !== undefined && command.y !== undefined){
|
|
|
|
- token.o += Math.round(command.x * scale);
|
|
|
|
- token.o += " "
|
|
|
|
- token.o += Math.round(command.y * scale);
|
|
|
|
- token.o += " "
|
|
|
|
- }
|
|
|
|
- if(command.x1 !== undefined && command.y1 !== undefined)
|
|
|
|
- {
|
|
|
|
- token.o += Math.round(command.x1 * scale);
|
|
|
|
- token.o += " "
|
|
|
|
- token.o += Math.round(command.y1 * scale);
|
|
|
|
- token.o += " "
|
|
|
|
- }
|
|
|
|
- if(command.x2 !== undefined && command.y2 !== undefined)
|
|
|
|
- {
|
|
|
|
- token.o += Math.round(command.x2 * scale);
|
|
|
|
- token.o += " "
|
|
|
|
- token.o += Math.round(command.y2 * scale);
|
|
|
|
- token.o += " "
|
|
|
|
}
|
|
}
|
|
- });
|
|
|
|
- result.glyphs[String.fromCharCode(glyph.unicode)] = token;
|
|
|
|
|
|
+
|
|
|
|
+ glyph.path.commands.forEach( function ( command, i ) {
|
|
|
|
+
|
|
|
|
+ if ( command.type.toLowerCase() === 'c' ) {
|
|
|
|
+
|
|
|
|
+ command.type = 'b';
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ token.o += command.type.toLowerCase() + ' ';
|
|
|
|
+
|
|
|
|
+ if ( command.x !== undefined && command.y !== undefined ) {
|
|
|
|
+
|
|
|
|
+ token.o += round( command.x * scale ) + ' ' + round( command.y * scale ) + ' ';
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if ( command.x1 !== undefined && command.y1 !== undefined ) {
|
|
|
|
+
|
|
|
|
+ token.o += round( command.x1 * scale ) + ' ' + round( command.y1 * scale ) + ' ';
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if ( command.x2 !== undefined && command.y2 !== undefined ) {
|
|
|
|
+
|
|
|
|
+ token.o += round( command.x2 * scale ) + ' ' + round( command.y2 * scale ) + ' ';
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ } );
|
|
|
|
+
|
|
|
|
+ glyphs[ String.fromCharCode( glyph.unicode ) ] = token;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ return {
|
|
|
|
+ glyphs: glyphs,
|
|
|
|
+
|
|
|
|
+ familyName: font.familyName,
|
|
|
|
+ ascender: round( font.ascender * scale ),
|
|
|
|
+ descender: round( font.descender * scale ),
|
|
|
|
+ underlinePosition: font.tables.post.underlinePosition,
|
|
|
|
+ underlineThickness: font.tables.post.underlineThickness,
|
|
|
|
+ boundingBox: {
|
|
|
|
+ xMin: font.tables.head.xMin,
|
|
|
|
+ xMax: font.tables.head.xMax,
|
|
|
|
+ yMin: font.tables.head.yMin,
|
|
|
|
+ yMax: font.tables.head.yMax
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ resolution: 1000,
|
|
|
|
+ original_font_information: font.tables.name
|
|
|
|
+ };
|
|
|
|
+
|
|
}
|
|
}
|
|
|
|
|
|
- result.familyName = font.familyName;
|
|
|
|
- result.ascender = Math.round(font.ascender * scale);
|
|
|
|
- result.descender = Math.round(font.descender * scale);
|
|
|
|
- result.underlinePosition = font.tables.post.underlinePosition;
|
|
|
|
- result.underlineThickness = font.tables.post.underlineThickness;
|
|
|
|
- result.boundingBox =
|
|
|
|
- {
|
|
|
|
- "yMin": font.tables.head.yMin,
|
|
|
|
- "xMin": font.tables.head.xMin,
|
|
|
|
- "yMax": font.tables.head.yMax,
|
|
|
|
- "xMax": font.tables.head.xMax
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- result.resolution = 1000;
|
|
|
|
- result.original_font_information = font.tables.name;
|
|
|
|
-
|
|
|
|
- return result;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-THREE.TTFLoader.reverseCommands = function(commands)
|
|
|
|
-{
|
|
|
|
- var paths = [];
|
|
|
|
- var path;
|
|
|
|
-
|
|
|
|
- commands.forEach(function(c)
|
|
|
|
- {
|
|
|
|
- if(c.type.toLowerCase() === "m")
|
|
|
|
- {
|
|
|
|
- path = [c];
|
|
|
|
- paths.push(path);
|
|
|
|
- }
|
|
|
|
- else if(c.type.toLowerCase() !== "z")
|
|
|
|
- {
|
|
|
|
- path.push(c);
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- var reversed = [];
|
|
|
|
- paths.forEach(function(p)
|
|
|
|
- {
|
|
|
|
- var result = {"type":"m" , "x" : p[p.length-1].x, "y": p[p.length-1].y};
|
|
|
|
- reversed.push(result);
|
|
|
|
-
|
|
|
|
- for(var i = p.length - 1; i > 0; i--)
|
|
|
|
- {
|
|
|
|
- var command = p[i];
|
|
|
|
- result = {"type":command.type};
|
|
|
|
- if(command.x2 !== undefined && command.y2 !== undefined)
|
|
|
|
- {
|
|
|
|
- result.x1 = command.x2;
|
|
|
|
- result.y1 = command.y2;
|
|
|
|
- result.x2 = command.x1;
|
|
|
|
- result.y2 = command.y1;
|
|
|
|
|
|
+ function reverseCommands( commands ) {
|
|
|
|
+
|
|
|
|
+ var paths = [];
|
|
|
|
+ var path;
|
|
|
|
+
|
|
|
|
+ commands.forEach( function ( c ) {
|
|
|
|
+
|
|
|
|
+ if ( c.type.toLowerCase() === 'm' ) {
|
|
|
|
+
|
|
|
|
+ path = [ c ];
|
|
|
|
+ paths.push( path );
|
|
|
|
+
|
|
|
|
+ } else if ( c.type.toLowerCase() !== 'z' ) {
|
|
|
|
+
|
|
|
|
+ path.push( c );
|
|
|
|
+
|
|
}
|
|
}
|
|
- else if(command.x1 !== undefined && command.y1 !== undefined)
|
|
|
|
- {
|
|
|
|
- result.x1 = command.x1;
|
|
|
|
- result.y1 = command.y1;
|
|
|
|
|
|
+
|
|
|
|
+ } );
|
|
|
|
+
|
|
|
|
+ var reversed = [];
|
|
|
|
+
|
|
|
|
+ paths.forEach( function ( p ) {
|
|
|
|
+
|
|
|
|
+ var result = {
|
|
|
|
+ type: 'm',
|
|
|
|
+ x: p[ p.length - 1 ].x,
|
|
|
|
+ y: p[ p.length - 1 ].y
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ reversed.push( result );
|
|
|
|
+
|
|
|
|
+ for ( var i = p.length - 1; i > 0; i -- ) {
|
|
|
|
+
|
|
|
|
+ var command = p[ i ];
|
|
|
|
+ var result = { type: command.type };
|
|
|
|
+
|
|
|
|
+ if ( command.x2 !== undefined && command.y2 !== undefined ) {
|
|
|
|
+
|
|
|
|
+ result.x1 = command.x2;
|
|
|
|
+ result.y1 = command.y2;
|
|
|
|
+ result.x2 = command.x1;
|
|
|
|
+ result.y2 = command.y1;
|
|
|
|
+
|
|
|
|
+ } else if ( command.x1 !== undefined && command.y1 !== undefined ) {
|
|
|
|
+
|
|
|
|
+ result.x1 = command.x1;
|
|
|
|
+ result.y1 = command.y1;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ result.x = p[ i - 1 ].x;
|
|
|
|
+ result.y = p[ i - 1 ].y;
|
|
|
|
+ reversed.push( result );
|
|
|
|
+
|
|
}
|
|
}
|
|
- result.x = p[i-1].x;
|
|
|
|
- result.y = p[i-1].y;
|
|
|
|
- reversed.push(result);
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- return reversed;
|
|
|
|
-}
|
|
|
|
|
|
+
|
|
|
|
+ } );
|
|
|
|
+
|
|
|
|
+ return reversed;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return convert( opentype.parse( arraybuffer ), this.reversed );
|
|
|
|
+
|
|
|
|
+};
|