js/Mobilizing/renderer/3D/three/shape/3D/composite/TextOpentype.js
import * as THREE from 'three';
import Mesh from "../../Mesh";
import Transform from '../../../scene/Transform';
import Font from "../../../../../../text/Font";
import Material from '../../../scene/Material';
/**
* 3D Text is created from a standard font file compatible with opentype.js.
*/
export default class TextOpentype extends Mesh {
/**
* @param {Object} params Parameters object, given by the constructor.
* @param {Number} [params.text="text"] the text string
* @param {Number} [params.fontSize=1] the text font height
* @param {Number} [params.depth=1] the glyph extrusion height. 0 to have flat letters.
* @param {Number} [params.bevelSegments=5] the text bevel details and tesselation
* @param {Boolean} [params.bevelEnabled=false] the text geometry uses curves
* @param {Number} [params.bevelSize=1] the text geometry bevel
* @param {Number} params.font the text font to use.
*/
constructor({
text = "text",
fontSize = 1,
depth = 1,
steps = 1,
bevelEnabled = false,
bevelSegments = 1,
bevelThickness = 1,
bevelSize = 1,
fontFile = undefined,
lineMode = undefined,
lineModeDivision = 5
} = {}) {
super(...arguments);
this.text = text;
this.fontSize = fontSize;
this.depth = depth;
this.steps = steps;
this.bevelEnabled = bevelEnabled;
this.bevelSegments = bevelSegments;
this.bevelThickness = bevelThickness;
this.bevelSize = bevelSize;
this.fontFile = fontFile;
this.lineMode = lineMode;
this.lineModeDivision = lineModeDivision;
this._extrudeSettings = {
steps: this.steps,
depth: this.depth,
bevelEnabled: this.bevelEnabled,
bevelThickness: this.bevelThickness,
bevelSize: this.bevelSize,
bevelSegments: this.bevelSegments
};
this._font = new Font({ "fontFile": this.fontFile }).getFont();
const shapes = this.makeShapes(this.text);
//manage the material according to the passed params, see the attachMaterial method below
this.attachMaterial(this.material);
if (!this.lineMode) {
this.createTextGeometry(shapes);
}
else {
this.createTextLines(shapes);
}
this.geometryVerticesAttributes = this.geometry.attributes.position;
this.geometryNormalAttributes = this.geometry.attributes.normal;
this.geometryUVAttributes = this.geometry.attributes.uv;
this.transform = new Transform(this);
}
setText(text) {
const shapes = this.makeShapes(text);
if (!this.lineMode) {
this.createTextGeometry(shapes);
}
else {
this.createTextLines(shapes);
}
}
makeShapes(text) {
const paths = this._font.getPath(text, 0, 0, this.fontSize);
//console.log("paths", paths);
const allCommands = paths.commands;
let shapes = []
const path = new THREE.ShapePath();
for (let i = 0; i < allCommands.length; i++) {
const command = allCommands[i];
switch (command.type) {
case "M":
path.moveTo(command.x, command.y);
break;
case "L":
path.lineTo(command.x, command.y);
break;
case "C":
path.bezierCurveTo(command.x1, command.y1, command.x2, command.y2, command.x, command.y);
break;
case "Q":
path.quadraticCurveTo(command.x1, command.y1, command.x, command.y);
break;
case "Z":
path.currentPath = new THREE.Path();
path.subPaths.push(path.currentPath);
break;
default:
console.error("error");
}
}
shapes = shapes.concat(path.toShapes(true, false));
return shapes;
}
createTextGeometry(shapes) {
if (this.geometry) {
this.erase();
}
this.geometry = new THREE.ExtrudeGeometry(shapes, this._extrudeSettings);
this.geometry.computeBoundingBox();
//this.geometry.computeVertexNormals();
if (this._mesh) {
this._mesh.geometry = this.geometry;
this.setScale(1, -1, 1);
//console.log("textMesh", this._mesh);
}
else {
const textMesh = new THREE.Mesh(this.geometry, this.material._material);
this._mesh = textMesh;
const centerOffset = -0.5 * (this.geometry.boundingBox.max.x - this.geometry.boundingBox.min.x);
textMesh.position.x = centerOffset;
textMesh.position.y = 0;
textMesh.position.z = 0;
textMesh.rotation.x = 0;
textMesh.rotation.y = Math.PI * 2;
textMesh.scale.y *= -1;
//console.log("textMesh", this._mesh);
}
//console.log(this._mesh);
}
createTextLines(shapes) {
//console.log(shapes);
let points = [];
this.indices = [];
this.index = 0;
shapes.forEach((shape) => {
const spacedPoints = shape.extractPoints(this.lineModeDivision);
//console.log("spacedPoints", spacedPoints);
if (spacedPoints.shape.length > 0) {
points = points.concat(spacedPoints.shape);
}
if (spacedPoints.holes.length > 0) {
spacedPoints.holes.forEach((hole) => {
points = points.concat(hole);
});
}
});
this.geometry = new THREE.BufferGeometry().setFromPoints(points);
this.geometryVerticesAttributes = this.geometry.attributes.position;
for (let i = 0; i < this.geometryVerticesAttributes.count; i++) {
this.indices.push(i);
}
this.geometry.setIndex(this.indices);
//console.log("this.geometry", this.geometry);
this.material = new Material({ type: "line" });
const textMesh = new THREE.Line(this.geometry, this.material._material);
this._mesh = textMesh;
this.geometry.computeBoundingBox();
const centerOffset = -0.5 * (this.geometry.boundingBox.max.x - this.geometry.boundingBox.min.x);
textMesh.position.x = centerOffset;
textMesh.position.y = 0;
textMesh.position.z = 0;
textMesh.rotation.x = 0;
textMesh.rotation.y = Math.PI * 2;
textMesh.scale.y *= -1;
//console.log("textMesh", this._mesh);
}
//console.log(this._mesh);
}