提交 95c1a08a 编写于 作者: M Mugen87

TTFLoader: Refactoring

上级 05207c5b
/** /**
* @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 * Loads TTF files and converts them into typeface JSON that can be used directly
* to create THREE.Font objects * to create THREE.Font objects.
*/ */
'use strict';
THREE.TTFLoader = function ( manager ) { THREE.TTFLoader = function ( manager ) {
this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
...@@ -15,179 +14,179 @@ THREE.TTFLoader = function ( manager ) { ...@@ -15,179 +14,179 @@ THREE.TTFLoader = function ( manager ) {
}; };
THREE.TTFLoader.prototype.load = function ( url, onLoad, onProgress, onError ) { THREE.TTFLoader.prototype = {
var scope = this;
var loader = new THREE.FileLoader( this.manager ); constructor: THREE.TTFLoader,
loader.setResponseType( 'arraybuffer' );
loader.load( url, function ( buffer ) {
if ( onLoad !== undefined ) { load: function ( url, onLoad, onProgress, onError ) {
onLoad( scope.parse( buffer ) ); var scope = this;
}
}, onProgress, onError ); var loader = new THREE.FileLoader( this.manager );
loader.setResponseType( 'arraybuffer' );
loader.load( url, function ( buffer ) {
}; onLoad( scope.parse( buffer ) );
THREE.TTFLoader.prototype.parse = function ( arraybuffer ) { }, onProgress, onError );
if ( typeof opentype === 'undefined' ) { },
console.warn( 'TTFLoader requires opentype.js Make sure it\'s included before using the loader' ); parse: function ( arraybuffer ) {
return null;
} function convert( font, reversed ) {
function convert( font, reversed ) { var round = Math.round;
var round = Math.round; var glyphs = {};
var scale = ( 100000 ) / ( ( font.unitsPerEm || 2048 ) * 72 );
var glyphs = {}; for ( var i = 0; i < font.glyphs.length; i ++ ) {
var scale = ( 100000 ) / ( ( font.unitsPerEm || 2048 ) * 72 );
for ( var i = 0; i < font.glyphs.length; i ++ ) { var glyph = font.glyphs.glyphs[ i ];
var glyph = font.glyphs.glyphs[ i ]; if ( glyph.unicode !== undefined ) {
if ( glyph.unicode !== undefined ) { var token = {
ha: round( glyph.advanceWidth * scale ),
x_min: round( glyph.xMin * scale ),
x_max: round( glyph.xMax * scale ),
o: ''
};
var token = { if ( reversed ) {
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 = reverseCommands( glyph.path.commands ); }
} glyph.path.commands.forEach( function ( command, i ) {
glyph.path.commands.forEach( function ( command, i ) { if ( command.type.toLowerCase() === 'c' ) {
if ( command.type.toLowerCase() === 'c' ) { command.type = 'b';
command.type = 'b'; }
} token.o += command.type.toLowerCase() + ' ';
token.o += command.type.toLowerCase() + ' '; if ( command.x !== undefined && command.y !== undefined ) {
if ( command.x !== undefined && command.y !== undefined ) { token.o += round( command.x * scale ) + ' ' + round( command.y * scale ) + ' ';
token.o += round( command.x * scale ) + ' ' + round( command.y * scale ) + ' '; }
} if ( command.x1 !== undefined && command.y1 !== undefined ) {
if ( command.x1 !== undefined && command.y1 !== undefined ) { token.o += round( command.x1 * scale ) + ' ' + round( command.y1 * scale ) + ' ';
token.o += round( command.x1 * scale ) + ' ' + round( command.y1 * scale ) + ' '; }
} if ( command.x2 !== undefined && command.y2 !== undefined ) {
if ( command.x2 !== undefined && command.y2 !== undefined ) { token.o += round( command.x2 * scale ) + ' ' + round( command.y2 * scale ) + ' ';
token.o += round( command.x2 * scale ) + ' ' + round( command.y2 * scale ) + ' '; }
} } );
} ); glyphs[ String.fromCharCode( glyph.unicode ) ] = token;
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
};
} }
return { function reverseCommands( commands ) {
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
};
} var paths = [];
var path;
function reverseCommands( commands ) { commands.forEach( function ( c ) {
var paths = []; if ( c.type.toLowerCase() === 'm' ) {
var path;
commands.forEach( function ( c ) { path = [ c ];
paths.push( path );
if ( c.type.toLowerCase() === 'm' ) { } else if ( c.type.toLowerCase() !== 'z' ) {
path = [ c ]; path.push( c );
paths.push( path );
} else if ( c.type.toLowerCase() !== 'z' ) { }
path.push( c ); } );
} var reversed = [];
} ); paths.forEach( function ( p ) {
var reversed = []; var result = {
type: 'm',
x: p[ p.length - 1 ].x,
y: p[ p.length - 1 ].y
};
paths.forEach( function ( p ) { reversed.push( result );
var result = { for ( var i = p.length - 1; i > 0; i -- ) {
type: 'm',
x: p[ p.length - 1 ].x,
y: p[ p.length - 1 ].y
};
reversed.push( result ); var command = p[ i ];
var result = { type: command.type };
for ( var i = p.length - 1; i > 0; i -- ) { if ( command.x2 !== undefined && command.y2 !== undefined ) {
var command = p[ i ]; result.x1 = command.x2;
var result = { type: command.type }; result.y1 = command.y2;
result.x2 = command.x1;
result.y2 = command.y1;
if ( command.x2 !== undefined && command.y2 !== undefined ) { } else if ( command.x1 !== undefined && command.y1 !== undefined ) {
result.x1 = command.x2; result.x1 = command.x1;
result.y1 = command.y2; result.y1 = command.y1;
result.x2 = command.x1;
result.y2 = command.y1;
} else if ( command.x1 !== undefined && command.y1 !== undefined ) { }
result.x1 = command.x1; result.x = p[ i - 1 ].x;
result.y1 = command.y1; 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; 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 ); }
return convert( opentype.parse( arraybuffer ), this.reversed );
}
}; };
...@@ -5,16 +5,14 @@ ...@@ -5,16 +5,14 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"> <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style> <style>
body body {
{
font-family: Monospace; font-family: Monospace;
background-color: #000; background-color: #000;
color: #fff; color: #fff;
margin: 0px; margin: 0px;
overflow: hidden; overflow: hidden;
} }
#info #info {
{
position: absolute; position: absolute;
top: 10px; top: 10px;
width: 100%; width: 100%;
...@@ -22,8 +20,7 @@ ...@@ -22,8 +20,7 @@
z-index: 100; z-index: 100;
display:block; display:block;
} }
#info a, .button #info a {
{
color: #f00; color: #f00;
font-weight: bold; font-weight: bold;
text-decoration: underline; text-decoration: underline;
...@@ -33,15 +30,12 @@ ...@@ -33,15 +30,12 @@
</head> </head>
<body> <body>
<script src="../build/three.js"></script> <script src="../build/three.js"></script>
<script src="js/utils/GeometryUtils.js"></script>
<script src="js/Detector.js"></script> <script src="js/Detector.js"></script>
<script src="js/loaders/TTFLoader.js"></script> <script src="js/loaders/TTFLoader.js"></script>
<script src="js/libs/opentype.min.js"></script> <script src="js/libs/opentype.min.js"></script>
<div id="info"> <div id="info">
<a href="http://threejs.org" target="_blank" rel="noopener">three.js</a> - TTFLoader using opentype by gero3 <a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - TTFLoader using opentype by gero3
<br/>type to enter new text, drag to spin the text <br/>type to enter new text, drag to spin the text
<br/><span class="button" id="color">change color</span>,
<span class="button" id="bevel">change bevel</span>
</div> </div>
...@@ -49,28 +43,21 @@ ...@@ -49,28 +43,21 @@
if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
THREE.Cache.enabled = true; var container, color;
var container, hex, color;
var camera, cameraTarget, scene, renderer; var camera, cameraTarget, scene, renderer;
var group, textMesh1, textMesh2, textGeo, material; var group, textMesh1, textMesh2, textGeo, material;
var firstLetter = true; var firstLetter = true;
var text = "three.js", var text = 'three.js',
height = 20, height = 20,
size = 70, size = 70,
hover = 30, hover = 30,
curveSegments = 4, curveSegments = 4,
bevelThickness = 2, bevelThickness = 2,
bevelSize = 1.5, bevelSize = 1.5,
bevelSegments = 3, bevelSegments = 3;
bevelEnabled = true;
var font = null; var font = null;
var mirror = true; var mirror = true;
var targetRotation = 0; var targetRotation = 0;
...@@ -85,14 +72,6 @@ ...@@ -85,14 +72,6 @@
init(); init();
animate(); animate();
function decimalToHex( d ) {
var hex = Number( d ).toString( 16 );
hex = "000000".substr( 0, 6 - hex.length ) + hex;
return hex.toUpperCase();
}
function init() { function init() {
container = document.createElement( 'div' ); container = document.createElement( 'div' );
...@@ -118,37 +97,9 @@ ...@@ -118,37 +97,9 @@
var pointLight = new THREE.PointLight( 0xffffff, 1.5 ); var pointLight = new THREE.PointLight( 0xffffff, 1.5 );
pointLight.position.set( 0, 100, 90 ); pointLight.position.set( 0, 100, 90 );
pointLight.color.setHSL( Math.random(), 1, 0.5 );
scene.add( pointLight ); scene.add( pointLight );
// Get text from hash
var hash = document.location.hash.substr( 1 );
if ( hash.length !== 0 ) {
var colorhash = hash.substring( 0, 6 );
var fonthash = hash.substring( 6, 7 );
var weighthash = hash.substring( 7, 8 );
var bevelhash = hash.substring( 8, 9 );
var texthash = hash.substring( 10 );
hex = colorhash;
pointLight.color.setHex( parseInt( colorhash, 16 ) );
fontName = reverseFontMap[ parseInt( fonthash ) ];
fontWeight = reverseWeightMap[ parseInt( weighthash ) ];
bevelEnabled = parseInt( bevelhash );
text = decodeURI( texthash );
} else {
pointLight.color.setHSL( Math.random(), 1, 0.5 );
hex = decimalToHex( pointLight.color.getHex() );
}
material = new THREE.MeshPhongMaterial( { color: 0xffffff, shading: THREE.FlatShading } ); material = new THREE.MeshPhongMaterial( { color: 0xffffff, shading: THREE.FlatShading } );
group = new THREE.Group(); group = new THREE.Group();
...@@ -159,8 +110,7 @@ ...@@ -159,8 +110,7 @@
var loader = new THREE.TTFLoader(); var loader = new THREE.TTFLoader();
loader.load( 'fonts/ttf/kenpixel.ttf', function ( json ) { loader.load( 'fonts/ttf/kenpixel.ttf', function ( json ) {
font = new THREE.Font(json); font = new THREE.Font( json );
//scene.add( font );
createText(); createText();
} ); } );
...@@ -188,23 +138,8 @@ ...@@ -188,23 +138,8 @@
document.addEventListener( 'keypress', onDocumentKeyPress, false ); document.addEventListener( 'keypress', onDocumentKeyPress, false );
document.addEventListener( 'keydown', onDocumentKeyDown, false ); document.addEventListener( 'keydown', onDocumentKeyDown, false );
document.getElementById( "color" ).addEventListener( 'click', function() {
pointLight.color.setHSL( Math.random(), 1, 0.5 );
hex = decimalToHex( pointLight.color.getHex() );
}, false );
document.getElementById( "bevel" ).addEventListener( 'click', function(){
bevelEnabled = !bevelEnabled;
refreshText();
}, false );
window.addEventListener( 'resize', onWindowResize, false ); window.addEventListener( 'resize', onWindowResize, false );
} }
function onWindowResize() { function onWindowResize() {
...@@ -224,7 +159,7 @@ ...@@ -224,7 +159,7 @@
if ( firstLetter ) { if ( firstLetter ) {
firstLetter = false; firstLetter = false;
text = ""; text = '';
} }
...@@ -232,7 +167,7 @@ ...@@ -232,7 +167,7 @@
// backspace // backspace
if ( keyCode == 8 ) { if ( keyCode === 8 ) {
event.preventDefault(); event.preventDefault();
...@@ -251,7 +186,7 @@ ...@@ -251,7 +186,7 @@
// backspace // backspace
if ( keyCode == 8 ) { if ( keyCode === 8 ) {
event.preventDefault(); event.preventDefault();
...@@ -278,7 +213,7 @@ ...@@ -278,7 +213,7 @@
bevelThickness: bevelThickness, bevelThickness: bevelThickness,
bevelSize: bevelSize, bevelSize: bevelSize,
bevelEnabled: bevelEnabled, bevelEnabled: true,
material: 0, material: 0,
extrudeMaterial: 1 extrudeMaterial: 1
...@@ -288,49 +223,7 @@ ...@@ -288,49 +223,7 @@
textGeo.computeBoundingBox(); textGeo.computeBoundingBox();
textGeo.computeVertexNormals(); textGeo.computeVertexNormals();
// "fix" side normals by removing z-component of normals for side faces var centerOffset = - 0.5 * ( textGeo.boundingBox.max.x - textGeo.boundingBox.min.x );
// (this doesn't work well for beveled geometry as then we lose nice curvature around z-axis)
if ( ! bevelEnabled ) {
var triangleAreaHeuristics = 0.1 * ( height * size );
for ( var i = 0; i < textGeo.faces.length; i ++ ) {
var face = textGeo.faces[ i ];
if ( face.materialIndex == 1 ) {
for ( var j = 0; j < face.vertexNormals.length; j ++ ) {
face.vertexNormals[ j ].z = 0;
face.vertexNormals[ j ].normalize();
}
var va = textGeo.vertices[ face.a ];
var vb = textGeo.vertices[ face.b ];
var vc = textGeo.vertices[ face.c ];
var s = THREE.GeometryUtils.triangleArea( va, vb, vc );
if ( s > triangleAreaHeuristics ) {
for ( var j = 0; j < face.vertexNormals.length; j ++ ) {
face.vertexNormals[ j ].copy( face.normal );
}
}
}
}
}
var centerOffset = -0.5 * ( textGeo.boundingBox.max.x - textGeo.boundingBox.min.x );
textMesh1 = new THREE.Mesh( textGeo, material ); textMesh1 = new THREE.Mesh( textGeo, material );
...@@ -410,7 +303,7 @@ ...@@ -410,7 +303,7 @@
function onDocumentTouchStart( event ) { function onDocumentTouchStart( event ) {
if ( event.touches.length == 1 ) { if ( event.touches.length === 1 ) {
event.preventDefault(); event.preventDefault();
...@@ -423,7 +316,7 @@ ...@@ -423,7 +316,7 @@
function onDocumentTouchMove( event ) { function onDocumentTouchMove( event ) {
if ( event.touches.length == 1 ) { if ( event.touches.length === 1 ) {
event.preventDefault(); event.preventDefault();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册