text: import {
  	FileLoader,
  	Loader,
  	ShapePath
  } from 'three';
  
  class FontLoader extends Loader {
  
  	constructor( manager ) {
  
  		super( manager );
  
  	}
  
  	load( url, onLoad, onProgress, onError ) {
  
  		const scope = this;
  
  		const loader = new FileLoader( this.manager );
  		loader.setPath( this.path );
  		loader.setRequestHeader( this.requestHeader );
  		loader.setWithCredentials( scope.withCredentials );
  		loader.load( url, function ( text ) {
  
  			let json;
  
  			try {
  
  				json = JSON.parse( text );
  
  			} catch ( e ) {
  
  				console.warn( 'THREE.FontLoader: typeface.js support is being deprecated. Use typeface.json instead.' );
  				json = JSON.parse( text.substring( 65, text.length - 2 ) );
  
  			}
  
  			const font = scope.parse( json );
  
  			if ( onLoad ) onLoad( font );
  
  		}, onProgress, onError );
  
  	}
  
  	parse( json ) {
  
  		return new Font( json );
  
  	}
  
  }
  
  //
  
  class Font {
  
  	constructor( data ) {
  
  		this.type = 'Font';
  
  		this.data = data;
  
  	}
  
  	generateShapes( text, size = 100 ) {
  
  		const shapes = [];
  		const paths = createPaths( text, size, this.data );
  
  		for ( let p = 0, pl = paths.length; p < pl; p ++ ) {
  
  			Array.prototype.push.apply( shapes, paths[ p ].toShapes() );
  
  		}
  
  		return shapes;
  
  	}
  
  }
  
  function createPaths( text, size, data ) {
  
  	const chars = Array.from( text );
  	const scale = size / data.resolution;
  	const line_height = ( data.boundingBox.yMax - data.boundingBox.yMin + data.underlineThickness ) * scale;
  
  	const paths = [];
  
  	let offsetX = 0, offsetY = 0;
  
  	for ( let i = 0; i < chars.length; i ++ ) {
  
  		const char = chars[ i ];
  
  		if ( char === '\n' ) {
  
  			offsetX = 0;
  			offsetY -= line_height;
  
  		} else {
  
  			const ret = createPath( char, scale, offsetX, offsetY, data );
  			offsetX += ret.offsetX;
  			paths.push( ret.path );
  
  		}
  
  	}
  
  	return paths;
  
  }
  
  function createPath( char, scale, offsetX, offsetY, data ) {
  
  	const glyph = data.glyphs[ char ] || data.glyphs[ '?' ];
  
  	if ( ! glyph ) {
  
  		console.error( 'THREE.Font: character "' + char + '" does not exists in font family ' + data.familyName + '.' );
  
  		return;
  
  	}
  
  	const path = new ShapePath();
  
  	let x, y, cpx, cpy, cpx1, cpy1, cpx2, cpy2;
  
  	if ( glyph.o ) {
  
  		const outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) );
  
  		for ( let i = 0, l = outline.length; i < l; ) {
  
  			const action = outline[ i ++ ];
  
  			switch ( action ) {
  
  				case 'm': // moveTo
  
  					x = outline[ i ++ ] * scale + offsetX;
  					y = outline[ i ++ ] * scale + offsetY;
  
  					path.moveTo( x, y );
  
  					break;
  
  				case 'l': // lineTo
  
  					x = outline[ i ++ ] * scale + offsetX;
  					y = outline[ i ++ ] * scale + offsetY;
  
  					path.lineTo( x, y );
  
  					break;
  
  				case 'q': // quadraticCurveTo
  
  					cpx = outline[ i ++ ] * scale + offsetX;
  					cpy = outline[ i ++ ] * scale + offsetY;
  					cpx1 = outline[ i ++ ] * scale + offsetX;
  					cpy1 = outline[ i ++ ] * scale + offsetY;
  
  					path.quadraticCurveTo( cpx1, cpy1, cpx, cpy );
  
  					break;
  
  				case 'b': // bezierCurveTo
  
  					cpx = outline[ i ++ ] * scale + offsetX;
  					cpy = outline[ i ++ ] * scale + offsetY;
  					cpx1 = outline[ i ++ ] * scale + offsetX;
  					cpy1 = outline[ i ++ ] * scale + offsetY;
  					cpx2 = outline[ i ++ ] * scale + offsetX;
  					cpy2 = outline[ i ++ ] * scale + offsetY;
  
  					path.bezierCurveTo( cpx1, cpy1, cpx2, cpy2, cpx, cpy );
  
  					break;
  
  			}
  
  		}
  
  	}
  
  	return { offsetX: glyph.ha * scale, path: path };
  
  }
  
  Font.prototype.isFont = true;
  
  export { FontLoader, Font };
  