184 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			184 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|  | import { | ||
|  | 	FileLoader, | ||
|  | 	Loader, | ||
|  | 	ShapePath | ||
|  | } from '../../three.module.min.js'; | ||
|  | 
 | ||
|  | 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( this.withCredentials ); | ||
|  | 		loader.load( url, function ( text ) { | ||
|  | 
 | ||
|  | 			const font = scope.parse( JSON.parse( text ) ); | ||
|  | 
 | ||
|  | 			if ( onLoad ) onLoad( font ); | ||
|  | 
 | ||
|  | 		}, onProgress, onError ); | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	parse( json ) { | ||
|  | 
 | ||
|  | 		return new Font( json ); | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | } | ||
|  | 
 | ||
|  | //
 | ||
|  | 
 | ||
|  | class Font { | ||
|  | 
 | ||
|  | 	constructor( data ) { | ||
|  | 
 | ||
|  | 		this.isFont = true; | ||
|  | 
 | ||
|  | 		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 ++ ) { | ||
|  | 
 | ||
|  | 			shapes.push( ...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 }; | ||
|  | 
 | ||
|  | } | ||
|  | 
 | ||
|  | export { FontLoader, Font }; |