UNPKG

@polygonjs/polygonjs

Version:

node-based WebGL 3D engine https://polygonjs.com

208 lines (207 loc) 6.85 kB
"use strict"; import { TypedSopNode } from "./_Base"; import { NodeParamsConfig, ParamConfig } from "../utils/params/ParamsConfig"; import { CoreLoaderFont } from "../../../core/loader/font/CoreFontLoader"; import { Poly } from "../../Poly"; import { DEFAULT_FONT_URL_JSON } from "../../../core/Assets"; import { TextSopJustifiyMode, TEXT_SOP_JUSTIFY_MODES } from "../../../core/geometry/text/TextJustify"; import { textBuildGeometries } from "../../../core/geometry/text/TextGeometries"; import { TextType, TEXT_TYPES } from "../../../core/geometry/text/TextType"; import { textMergeLetters } from "../../../core/geometry/text/TextMergeLetters"; import { isBooleanTrue } from "../../../core/Type"; import { SopType } from "../../poly/registers/nodes/types/Sop"; import { EXTENSIONS_BY_NODE_TYPE_BY_CONTEXT } from "../../../core/loader/FileExtensionRegister"; import { NodeContext } from "../../poly/NodeContext"; const GENERATION_ERROR_MESSAGE = `failed to generate geometry. Try to remove some characters`; class TextSopParamsConfig extends NodeParamsConfig { constructor() { super(...arguments); /** @param font used */ this.font = ParamConfig.STRING(DEFAULT_FONT_URL_JSON, { fileBrowse: { extensions: EXTENSIONS_BY_NODE_TYPE_BY_CONTEXT[NodeContext.SOP][SopType.TEXT] } }); /** @param text created */ this.text = ParamConfig.STRING("polygonjs", { multiline: true }); /** @param type of geometry created */ this.type = ParamConfig.INTEGER(0, { menu: { entries: TEXT_TYPES.map((type, i) => { return { name: type, value: i }; }) } }); /** @param font size */ this.size = ParamConfig.FLOAT(1, { range: [0, 1], rangeLocked: [true, false] }); /** @param extrude depth */ this.extrude = ParamConfig.FLOAT(0.1, { visibleIf: { type: TEXT_TYPES.indexOf(TextType.MESH) } }); /** @param segments count */ this.segments = ParamConfig.INTEGER(1, { range: [1, 20], rangeLocked: [true, false], visibleIf: { type: TEXT_TYPES.indexOf(TextType.MESH) } }); /** @param bevelEnabled */ this.bevelEnabled = ParamConfig.BOOLEAN(false, { visibleIf: { type: TEXT_TYPES.indexOf(TextType.MESH) } }); /** @param bevelThickness */ this.bevelThickness = ParamConfig.FLOAT(0, { visibleIf: { type: TEXT_TYPES.indexOf(TextType.MESH), bevelEnabled: true } }); /** @param bevelSize */ this.bevelSize = ParamConfig.FLOAT(0, { visibleIf: { type: TEXT_TYPES.indexOf(TextType.MESH), bevelEnabled: true } }); /** @param bevelOffset */ this.bevelOffset = ParamConfig.FLOAT(0, { visibleIf: { type: TEXT_TYPES.indexOf(TextType.MESH), bevelEnabled: true } }); /** @param bevelSegments */ this.bevelSegments = ParamConfig.INTEGER(2, { range: [1, 6], visibleIf: { type: TEXT_TYPES.indexOf(TextType.MESH), bevelEnabled: true } }); /** @param stroke width */ this.strokeWidth = ParamConfig.FLOAT(0.02, { visibleIf: { type: TEXT_TYPES.indexOf(TextType.STROKE) } }); /** @param line height */ this.lineHeight = ParamConfig.FLOAT(1, { range: [0, 2], rangeLocked: [false, false] }); /** @param create one object per letter */ this.splitPerLetter = ParamConfig.BOOLEAN(0); /** @param when creating one object per letter, define if the characters like space create an object */ this.keepEmptyGeometries = ParamConfig.BOOLEAN(0, { visibleIf: { splitPerLetter: 1 } }); /** @param justify mode */ this.justifyMode = ParamConfig.INTEGER(TEXT_SOP_JUSTIFY_MODES.indexOf(TextSopJustifiyMode.LEFT), { menu: { entries: TEXT_SOP_JUSTIFY_MODES.map((name, value) => ({ name, value })) } }); /** @param open advanced options */ this.tadvanced = ParamConfig.BOOLEAN(0); /** @param is counter clock wise: defines the vertex order when parsing the font */ this.isCCW = ParamConfig.BOOLEAN(0, { visibleIf: { tadvanced: true } }); } /** @param defines if holes should be found when parsing the font */ // noHoles = ParamConfig.BOOLEAN(0, { // visibleIf: {tadvanced: true}, // }); } const ParamsConfig = new TextSopParamsConfig(); export class TextSopNode extends TypedSopNode { constructor() { super(...arguments); this.paramsConfig = ParamsConfig; this._loadedFonts = /* @__PURE__ */ new Map(); } static type() { return SopType.TEXT; } dispose() { super.dispose(); Poly.blobs.clearBlobsForNode(this); } setTextType(type) { this.p.type.set(TEXT_TYPES.indexOf(type)); } async cook() { const fontUrl = this.pv.font; let font = this._loadedFonts.get(fontUrl); try { if (!font) { const loader = new CoreLoaderFont(this.pv.font, this); font = await loader.load(); if (font) { this._loadedFonts.set(fontUrl, font); } } } catch (err) { console.warn("error:", err); this.states.error.set(`could not load font (${this.pv.font}, reason:${err.message})`); this.cookController.endCook(); return; } if (!font) { this.cookController.endCook(); return; } const textType = TEXT_TYPES[this.pv.type]; if (!TEXT_TYPES.includes(textType)) { this.cookController.endCook(); return; } const textWithoutSpaces = this.pv.text.replace(/\s/g, ""); if (textWithoutSpaces.length == 0) { return this.setObjects([]); } const geometries = await await textBuildGeometries({ text: this.pv.text, textType, font, size: this.pv.size, extrude: this.pv.extrude, curveSegments: this.pv.segments, strokeWidth: this.pv.strokeWidth, // bevel bevelEnabled: this.pv.bevelEnabled, bevelThickness: this.pv.bevelThickness, bevelSize: this.pv.bevelSize, bevelOffset: this.pv.bevelOffset, bevelSegments: this.pv.bevelSegments, // isCCW: isBooleanTrue(this.pv.tadvanced) ? this.pv.isCCW : void 0 // noHoles: isBooleanTrue(this.pv.tadvanced) ? this.pv.noHoles : undefined, }); if (geometries) { const objects = textMergeLetters({ text: this.pv.text, geometries, textType, splitPerLetter: this.pv.splitPerLetter, keepEmptyGeometries: this.pv.keepEmptyGeometries, justifyMode: TEXT_SOP_JUSTIFY_MODES[this.pv.justifyMode], lineHeight: this.pv.lineHeight }); if (objects) { return this.setObjects(objects); } } this.states.error.set(GENERATION_ERROR_MESSAGE); this.cookController.endCook(); } }