| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 | ( function () {	/** * 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. */	class TTFLoader extends THREE.Loader {		constructor( manager ) {			super( manager );			this.reversed = false;		}		load( url, onLoad, onProgress, onError ) {			const scope = this;			const loader = new THREE.FileLoader( this.manager );			loader.setPath( this.path );			loader.setResponseType( 'arraybuffer' );			loader.setRequestHeader( this.requestHeader );			loader.setWithCredentials( this.withCredentials );			loader.load( url, function ( buffer ) {				try {					onLoad( scope.parse( buffer ) );				} catch ( e ) {					if ( onError ) {						onError( e );					} else {						console.error( e );					}					scope.manager.itemError( url );				}			}, onProgress, onError );		}		parse( arraybuffer ) {			function convert( font, reversed ) {				const round = Math.round;				const glyphs = {};				const scale = 100000 / ( ( font.unitsPerEm || 2048 ) * 72 );				const glyphIndexMap = font.encoding.cmap.glyphIndexMap;				const unicodes = Object.keys( glyphIndexMap );				for ( let i = 0; i < unicodes.length; i ++ ) {					const unicode = unicodes[ i ];					const glyph = font.glyphs.glyphs[ glyphIndexMap[ unicode ] ];					if ( unicode !== undefined ) {						const 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 ) {							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.fromCodePoint( glyph.unicode ) ] = token;					}				}				return {					glyphs: glyphs,					familyName: font.getEnglishName( 'fullName' ),					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				};			}			function reverseCommands( commands ) {				const paths = [];				let path;				commands.forEach( function ( c ) {					if ( c.type.toLowerCase() === 'm' ) {						path = [ c ];						paths.push( path );					} else if ( c.type.toLowerCase() !== 'z' ) {						path.push( c );					}				} );				const reversed = [];				paths.forEach( function ( p ) {					const result = {						type: 'm',						x: p[ p.length - 1 ].x,						y: p[ p.length - 1 ].y					};					reversed.push( result );					for ( let i = p.length - 1; i > 0; i -- ) {						const command = p[ i ];						const 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 );					}				} );				return reversed;			}			if ( typeof opentype === 'undefined' ) {				console.warn( 'THREE.TTFLoader: The loader requires opentype.js. Make sure it\'s included before using the loader.' );				return null;			}			return convert( opentype.parse( arraybuffer ), this.reversed ); // eslint-disable-line no-undef		}	}	THREE.TTFLoader = TTFLoader;} )();
 |