Repository

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";

/**
* 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,
    } = {}) {
        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._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);

        this.createTextGeometry(shapes);

        this.transform = new Transform(this);
    }

    setText(text) {
        const shapes = this.makeShapes(text);
        this.createTextGeometry(shapes);
    }

    makeShapes(text) {
        const paths = this._font.getPath(text, 0, 0, this.fontSize);

        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 "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.clear();
            this.erase();
        }

        this.geometry = new THREE.ExtrudeGeometry(shapes, this._extrudeSettings);

        this.geometry.computeBoundingBox();
        this.geometry.computeVertexNormals();

        if (this._mesh) {
            this._mesh.geometry = this.geometry;
        }
        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(this._mesh);
    }
}