TTFLoader.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /**
  2. * @author gero3 / https://github.com/gero3
  3. * @author tentone / https://github.com/tentone
  4. *
  5. * Requires opentype.js to be included in the project.
  6. * Loads TTF files and converts them into typeface JSON that can be used directly
  7. * to create THREE.Font objects.
  8. */
  9. THREE.TTFLoader = function ( manager ) {
  10. this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
  11. this.reversed = false;
  12. };
  13. THREE.TTFLoader.prototype = {
  14. constructor: THREE.TTFLoader,
  15. load: function ( url, onLoad, onProgress, onError ) {
  16. var scope = this;
  17. var loader = new THREE.FileLoader( this.manager );
  18. loader.setResponseType( 'arraybuffer' );
  19. loader.load( url, function ( buffer ) {
  20. onLoad( scope.parse( buffer ) );
  21. }, onProgress, onError );
  22. },
  23. parse: function ( arraybuffer ) {
  24. function convert( font, reversed ) {
  25. var round = Math.round;
  26. var glyphs = {};
  27. var scale = ( 100000 ) / ( ( font.unitsPerEm || 2048 ) * 72 );
  28. for ( var i = 0; i < font.glyphs.length; i ++ ) {
  29. var glyph = font.glyphs.glyphs[ i ];
  30. if ( glyph.unicode !== undefined ) {
  31. var token = {
  32. ha: round( glyph.advanceWidth * scale ),
  33. x_min: round( glyph.xMin * scale ),
  34. x_max: round( glyph.xMax * scale ),
  35. o: ''
  36. };
  37. if ( reversed ) {
  38. glyph.path.commands = reverseCommands( glyph.path.commands );
  39. }
  40. glyph.path.commands.forEach( function ( command, i ) {
  41. if ( command.type.toLowerCase() === 'c' ) {
  42. command.type = 'b';
  43. }
  44. token.o += command.type.toLowerCase() + ' ';
  45. if ( command.x !== undefined && command.y !== undefined ) {
  46. token.o += round( command.x * scale ) + ' ' + round( command.y * scale ) + ' ';
  47. }
  48. if ( command.x1 !== undefined && command.y1 !== undefined ) {
  49. token.o += round( command.x1 * scale ) + ' ' + round( command.y1 * scale ) + ' ';
  50. }
  51. if ( command.x2 !== undefined && command.y2 !== undefined ) {
  52. token.o += round( command.x2 * scale ) + ' ' + round( command.y2 * scale ) + ' ';
  53. }
  54. } );
  55. glyphs[ String.fromCharCode( glyph.unicode ) ] = token;
  56. }
  57. }
  58. return {
  59. glyphs: glyphs,
  60. familyName: font.familyName,
  61. ascender: round( font.ascender * scale ),
  62. descender: round( font.descender * scale ),
  63. underlinePosition: font.tables.post.underlinePosition,
  64. underlineThickness: font.tables.post.underlineThickness,
  65. boundingBox: {
  66. xMin: font.tables.head.xMin,
  67. xMax: font.tables.head.xMax,
  68. yMin: font.tables.head.yMin,
  69. yMax: font.tables.head.yMax
  70. },
  71. resolution: 1000,
  72. original_font_information: font.tables.name
  73. };
  74. }
  75. function reverseCommands( commands ) {
  76. var paths = [];
  77. var path;
  78. commands.forEach( function ( c ) {
  79. if ( c.type.toLowerCase() === 'm' ) {
  80. path = [ c ];
  81. paths.push( path );
  82. } else if ( c.type.toLowerCase() !== 'z' ) {
  83. path.push( c );
  84. }
  85. } );
  86. var reversed = [];
  87. paths.forEach( function ( p ) {
  88. var result = {
  89. type: 'm',
  90. x: p[ p.length - 1 ].x,
  91. y: p[ p.length - 1 ].y
  92. };
  93. reversed.push( result );
  94. for ( var i = p.length - 1; i > 0; i -- ) {
  95. var command = p[ i ];
  96. var result = { type: command.type };
  97. if ( command.x2 !== undefined && command.y2 !== undefined ) {
  98. result.x1 = command.x2;
  99. result.y1 = command.y2;
  100. result.x2 = command.x1;
  101. result.y2 = command.y1;
  102. } else if ( command.x1 !== undefined && command.y1 !== undefined ) {
  103. result.x1 = command.x1;
  104. result.y1 = command.y1;
  105. }
  106. result.x = p[ i - 1 ].x;
  107. result.y = p[ i - 1 ].y;
  108. reversed.push( result );
  109. }
  110. } );
  111. return reversed;
  112. }
  113. if ( typeof opentype === 'undefined' ) {
  114. console.warn( 'THREE.TTFLoader: The loader requires opentype.js. Make sure it\'s included before using the loader.' );
  115. return null;
  116. }
  117. return convert( opentype.parse( arraybuffer ), this.reversed );
  118. }
  119. };