polygonjs-engine
Version:
node-based webgl 3D engine https://polygonjs.com
181 lines (148 loc) • 4.54 kB
JavaScript
//
//
// COPY of TTFLoader from three.js
// in order to avoid the require calls from the opentype shipped with three.js
//
//
import {FileLoader} from 'three/src/loaders/FileLoader';
import {Loader} from 'three/src/loaders/Loader';
import opentype from 'opentype.js/dist/opentype.module';
/**
* 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.
*/
var TTFLoader = function (manager) {
Loader.call(this, manager);
this.reversed = false;
};
TTFLoader.prototype = Object.assign(Object.create(Loader.prototype), {
constructor: TTFLoader,
load: function (url, onLoad, onProgress, onError) {
var scope = this;
var loader = new 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: function (arraybuffer) {
function convert(font, reversed) {
var round = Math.round;
var glyphs = {};
var scale = 100000 / ((font.unitsPerEm || 2048) * 72);
var glyphIndexMap = font.encoding.cmap.glyphIndexMap;
var unicodes = Object.keys(glyphIndexMap);
for (var i = 0; i < unicodes.length; i++) {
var unicode = unicodes[i];
var glyph = font.glyphs.glyphs[glyphIndexMap[unicode]];
if (unicode !== undefined) {
var 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) {
var paths = [];
var path;
commands.forEach(function (c) {
if (c.type.toLowerCase() === 'm') {
path = [c];
paths.push(path);
} else if (c.type.toLowerCase() !== 'z') {
path.push(c);
}
});
var reversed = [];
paths.forEach(function (p) {
var result = {
type: 'm',
x: p[p.length - 1].x,
y: p[p.length - 1].y,
};
reversed.push(result);
for (var i = p.length - 1; i > 0; i--) {
var command = p[i];
var 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
},
});
export {TTFLoader};