@needle-tools/engine
Version:
Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in.
204 lines • 7.82 kB
JavaScript
import { Matrix4, MeshStandardMaterial } from "three";
import { GameObject } from "../../../Component.js";
import { RectTransform } from "../../../ui/RectTransform.js";
import { Text } from "../../../ui/Text.js";
import { TextAnchor } from "../../../ui/Text.js";
import { getMaterialNameForUSD } from "../ThreeUSDZExporter.js";
export var TextWrapMode;
(function (TextWrapMode) {
TextWrapMode["singleLine"] = "singleLine";
TextWrapMode["hardBreaks"] = "hardBreaks";
TextWrapMode["flowing"] = "flowing";
})(TextWrapMode || (TextWrapMode = {}));
export var HorizontalAlignment;
(function (HorizontalAlignment) {
HorizontalAlignment["left"] = "left";
HorizontalAlignment["center"] = "center";
HorizontalAlignment["right"] = "right";
HorizontalAlignment["justified"] = "justified";
})(HorizontalAlignment || (HorizontalAlignment = {}));
export var VerticalAlignment;
(function (VerticalAlignment) {
VerticalAlignment["top"] = "top";
VerticalAlignment["middle"] = "middle";
VerticalAlignment["lowerMiddle"] = "lowerMiddle";
VerticalAlignment["baseline"] = "baseline";
VerticalAlignment["bottom"] = "bottom";
})(VerticalAlignment || (VerticalAlignment = {}));
export class USDZText {
static global_id = 0;
static getId() {
return this.global_id++;
}
id;
content = "";
font = [];
pointSize = 144;
width;
height;
depth;
wrapMode;
horizontalAlignment;
verticalAlignment;
material;
setDepth(depth) {
this.depth = depth;
return this;
}
setPointSize(pointSize) {
this.pointSize = pointSize;
return this;
}
setHorizontalAlignment(align) {
this.horizontalAlignment = align;
return this;
}
setVerticalAlignment(align) {
this.verticalAlignment = align;
return this;
}
constructor(id) {
this.id = id;
}
writeTo(_document, writer) {
writer.beginBlock(`def Preliminary_Text "${this.id}"`, "(", false);
writer.appendLine(`prepend apiSchemas = ["MaterialBindingAPI"]`);
writer.closeBlock(")");
writer.beginBlock();
if (this.content)
writer.appendLine(`string content = "${this.content}"`);
if (!this.font || this.font.length <= 0) {
this.font ||= [];
this.font?.push("sans-serif");
}
const str = this.font.map(s => `"${s}"`).join(", ");
writer.appendLine(`string[] font = [ ${str} ]`);
writer.appendLine(`double pointSize = ${this.pointSize}`);
if (typeof this.width === "number")
writer.appendLine(`double width = ${this.width}`);
if (typeof this.height === "number")
writer.appendLine(`double height = ${this.height}`);
if (typeof this.depth === "number")
writer.appendLine(`double depth = ${this.depth}`);
if (this.wrapMode)
writer.appendLine(`token wrapMode = "${this.wrapMode}"`);
if (this.horizontalAlignment)
writer.appendLine(`token horizontalAlignment = "${this.horizontalAlignment}"`);
if (this.verticalAlignment)
writer.appendLine(`token verticalAlignment = "${this.verticalAlignment}"`);
if (this.material !== undefined) {
writer.appendLine(`rel material:binding = </StageRoot/Materials/${getMaterialNameForUSD(this.material)}>`);
}
writer.closeBlock();
}
}
export class TextBuilder {
static singleLine(str, pointSize, depth) {
const text = new USDZText("text_" + USDZText.getId());
text.content = str;
if (pointSize)
text.pointSize = pointSize;
if (depth)
text.depth = depth;
return text;
}
static multiLine(str, width, height, horizontal, vertical, wrapMode) {
const text = new USDZText("text_" + USDZText.getId());
text.content = str;
text.width = width;
text.height = height;
text.horizontalAlignment = horizontal;
text.verticalAlignment = vertical;
if (wrapMode !== undefined)
text.wrapMode = wrapMode;
return text;
}
}
const rotateYAxisMatrix = new Matrix4().makeRotationY(Math.PI);
const invertX = new Matrix4().makeScale(-1, 1, -1);
export class TextExtension {
get extensionName() {
return "text";
}
exportText(object, newModel, _context) {
const text = GameObject.getComponent(object, Text);
if (!text)
return;
const rt = GameObject.getComponent(object, RectTransform);
let width = 100;
let height = 100;
if (rt) {
width = rt.width;
height = rt.height;
}
const mat = rotateYAxisMatrix.clone();
if (rt) // Not ideal but works for now:
mat.premultiply(invertX);
newModel.setMatrix(mat);
const color = text.color.clone();
newModel.material = new MeshStandardMaterial({ color: color, emissive: color });
newModel.addEventListener("serialize", (writer, _context) => {
let txt = text.text;
// Some texts use \r\n for newlines, we remove the \r here.
// Also encountered a single text ending with \r which broke the output.
txt = txt.replace(/\r/g, "");
txt = txt.replace(/\n/g, "\\n");
const textObj = TextBuilder.multiLine(txt, width, height, HorizontalAlignment.center, VerticalAlignment.bottom, TextWrapMode.flowing);
this.setTextAlignment(textObj, text.alignment);
this.setOverflow(textObj, text);
if (newModel.material)
textObj.material = newModel.material;
textObj.pointSize = this.convertToTextSize(text.fontSize);
textObj.depth = .001;
textObj.writeTo(undefined, writer);
});
}
convertToTextSize(pixel) {
return 1 / 0.0502 * 144 * pixel;
}
setOverflow(textObj, text) {
if (text.horizontalOverflow) {
textObj.wrapMode = TextWrapMode.singleLine;
}
else {
textObj.wrapMode = TextWrapMode.flowing;
}
}
setTextAlignment(text, alignment) {
switch (alignment) {
case TextAnchor.LowerLeft:
case TextAnchor.MiddleLeft:
case TextAnchor.UpperLeft:
text.horizontalAlignment = HorizontalAlignment.left;
break;
case TextAnchor.LowerCenter:
case TextAnchor.MiddleCenter:
case TextAnchor.UpperCenter:
text.horizontalAlignment = HorizontalAlignment.center;
break;
case TextAnchor.LowerRight:
case TextAnchor.MiddleRight:
case TextAnchor.UpperRight:
text.horizontalAlignment = HorizontalAlignment.right;
break;
}
switch (alignment) {
case TextAnchor.LowerLeft:
case TextAnchor.LowerCenter:
case TextAnchor.LowerRight:
text.verticalAlignment = VerticalAlignment.bottom;
break;
case TextAnchor.MiddleLeft:
case TextAnchor.MiddleCenter:
case TextAnchor.MiddleRight:
text.verticalAlignment = VerticalAlignment.middle;
break;
case TextAnchor.UpperLeft:
case TextAnchor.UpperCenter:
case TextAnchor.UpperRight:
text.verticalAlignment = VerticalAlignment.top;
break;
}
}
}
//# sourceMappingURL=USDZText.js.map