playcanvas
Version:
Open-source WebGL/WebGPU 3D engine for the web
492 lines (491 loc) • 20.5 kB
JavaScript
import { Color } from "../../../core/math/color.js";
import { Vec2 } from "../../../core/math/vec2.js";
import { Vec4 } from "../../../core/math/vec4.js";
import { PIXELFORMAT_SRGBA8 } from "../../../platform/graphics/constants.js";
import { Texture } from "../../../platform/graphics/texture.js";
import { BLEND_PREMULTIPLIED, SPRITE_RENDERMODE_SLICED, SPRITE_RENDERMODE_TILED } from "../../../scene/constants.js";
import { StandardMaterial } from "../../../scene/materials/standard-material.js";
import { ComponentSystem } from "../system.js";
import { ELEMENTTYPE_IMAGE, ELEMENTTYPE_TEXT } from "./constants.js";
import { ElementComponent } from "./component.js";
import { ElementComponentData } from "./data.js";
const _schema = ["enabled"];
class ElementComponentSystem extends ComponentSystem {
constructor(app) {
super(app);
this.id = "element";
this.ComponentType = ElementComponent;
this.DataType = ElementComponentData;
this.schema = _schema;
this._unicodeConverter = null;
this._rtlReorder = null;
this._defaultTexture = new Texture(app.graphicsDevice, {
width: 1,
height: 1,
format: PIXELFORMAT_SRGBA8,
name: "element-system"
});
const pixels = this._defaultTexture.lock();
const pixelData = new Uint8Array(4);
pixelData[0] = 255;
pixelData[1] = 255;
pixelData[2] = 255;
pixelData[3] = 255;
pixels.set(pixelData);
this._defaultTexture.unlock();
this.defaultImageMaterial = null;
this.defaultImage9SlicedMaterial = null;
this.defaultImage9TiledMaterial = null;
this.defaultImageMaskMaterial = null;
this.defaultImage9SlicedMaskMaterial = null;
this.defaultImage9TiledMaskMaterial = null;
this.defaultScreenSpaceImageMaterial = null;
this.defaultScreenSpaceImage9SlicedMaterial = null;
this.defaultScreenSpaceImage9TiledMaterial = null;
this.defaultScreenSpaceImageMask9SlicedMaterial = null;
this.defaultScreenSpaceImageMask9TiledMaterial = null;
this.defaultScreenSpaceImageMaskMaterial = null;
this._defaultTextMaterials = {};
this.defaultImageMaterials = [];
this.on("add", this.onAddComponent, this);
this.on("beforeremove", this.onRemoveComponent, this);
}
destroy() {
super.destroy();
this._defaultTexture.destroy();
}
initializeComponentData(component, data, properties) {
component._beingInitialized = true;
if (data.anchor !== void 0) {
if (data.anchor instanceof Vec4) {
component.anchor.copy(data.anchor);
} else {
component.anchor.set(data.anchor[0], data.anchor[1], data.anchor[2], data.anchor[3]);
}
}
if (data.pivot !== void 0) {
if (data.pivot instanceof Vec2) {
component.pivot.copy(data.pivot);
} else {
component.pivot.set(data.pivot[0], data.pivot[1]);
}
}
const splitHorAnchors = Math.abs(component.anchor.x - component.anchor.z) > 1e-3;
const splitVerAnchors = Math.abs(component.anchor.y - component.anchor.w) > 1e-3;
let _marginChange = false;
let color;
if (data.margin !== void 0) {
if (data.margin instanceof Vec4) {
component.margin.copy(data.margin);
} else {
component._margin.set(data.margin[0], data.margin[1], data.margin[2], data.margin[3]);
}
_marginChange = true;
}
if (data.left !== void 0) {
component._margin.x = data.left;
_marginChange = true;
}
if (data.bottom !== void 0) {
component._margin.y = data.bottom;
_marginChange = true;
}
if (data.right !== void 0) {
component._margin.z = data.right;
_marginChange = true;
}
if (data.top !== void 0) {
component._margin.w = data.top;
_marginChange = true;
}
if (_marginChange) {
component.margin = component._margin;
}
let shouldForceSetAnchor = false;
if (data.width !== void 0 && !splitHorAnchors) {
component.width = data.width;
} else if (splitHorAnchors) {
shouldForceSetAnchor = true;
}
if (data.height !== void 0 && !splitVerAnchors) {
component.height = data.height;
} else if (splitVerAnchors) {
shouldForceSetAnchor = true;
}
if (shouldForceSetAnchor) {
component.anchor = component.anchor;
}
if (data.enabled !== void 0) {
component.enabled = data.enabled;
}
if (data.useInput !== void 0) {
component.useInput = data.useInput;
}
if (data.fitMode !== void 0) {
component.fitMode = data.fitMode;
}
component.batchGroupId = data.batchGroupId === void 0 || data.batchGroupId === null ? -1 : data.batchGroupId;
if (data.layers && Array.isArray(data.layers)) {
component.layers = data.layers.slice(0);
}
if (data.type !== void 0) {
component.type = data.type;
}
if (component.type === ELEMENTTYPE_IMAGE) {
if (data.rect !== void 0) {
component.rect = data.rect;
}
if (data.color !== void 0) {
color = data.color;
if (!(color instanceof Color)) {
color = new Color(data.color[0], data.color[1], data.color[2]);
}
component.color = color;
}
if (data.opacity !== void 0) component.opacity = data.opacity;
if (data.textureAsset !== void 0) component.textureAsset = data.textureAsset;
if (data.texture) component.texture = data.texture;
if (data.spriteAsset !== void 0) component.spriteAsset = data.spriteAsset;
if (data.sprite) component.sprite = data.sprite;
if (data.spriteFrame !== void 0) component.spriteFrame = data.spriteFrame;
if (data.pixelsPerUnit !== void 0 && data.pixelsPerUnit !== null) component.pixelsPerUnit = data.pixelsPerUnit;
if (data.materialAsset !== void 0) component.materialAsset = data.materialAsset;
if (data.material) component.material = data.material;
if (data.mask !== void 0) {
component.mask = data.mask;
}
} else if (component.type === ELEMENTTYPE_TEXT) {
if (data.autoWidth !== void 0) component.autoWidth = data.autoWidth;
if (data.autoHeight !== void 0) component.autoHeight = data.autoHeight;
if (data.rtlReorder !== void 0) component.rtlReorder = data.rtlReorder;
if (data.unicodeConverter !== void 0) component.unicodeConverter = data.unicodeConverter;
if (data.text !== null && data.text !== void 0) {
component.text = data.text;
} else if (data.key !== null && data.key !== void 0) {
component.key = data.key;
}
if (data.color !== void 0) {
color = data.color;
if (!(color instanceof Color)) {
color = new Color(color[0], color[1], color[2]);
}
component.color = color;
}
if (data.opacity !== void 0) {
component.opacity = data.opacity;
}
if (data.spacing !== void 0) component.spacing = data.spacing;
if (data.fontSize !== void 0) {
component.fontSize = data.fontSize;
if (!data.lineHeight) component.lineHeight = data.fontSize;
}
if (data.lineHeight !== void 0) component.lineHeight = data.lineHeight;
if (data.maxLines !== void 0) component.maxLines = data.maxLines;
if (data.wrapLines !== void 0) component.wrapLines = data.wrapLines;
if (data.minFontSize !== void 0) component.minFontSize = data.minFontSize;
if (data.maxFontSize !== void 0) component.maxFontSize = data.maxFontSize;
if (data.autoFitWidth) component.autoFitWidth = data.autoFitWidth;
if (data.autoFitHeight) component.autoFitHeight = data.autoFitHeight;
if (data.fontAsset !== void 0) component.fontAsset = data.fontAsset;
if (data.font !== void 0) component.font = data.font;
if (data.alignment !== void 0) component.alignment = data.alignment;
if (data.outlineColor !== void 0) component.outlineColor = data.outlineColor;
if (data.outlineThickness !== void 0) component.outlineThickness = data.outlineThickness;
if (data.shadowColor !== void 0) component.shadowColor = data.shadowColor;
if (data.shadowOffset !== void 0) component.shadowOffset = data.shadowOffset;
if (data.enableMarkup !== void 0) component.enableMarkup = data.enableMarkup;
}
const result = component._parseUpToScreen();
if (result.screen) {
component._updateScreen(result.screen);
}
super.initializeComponentData(component, data, properties);
component._beingInitialized = false;
if (component.type === ELEMENTTYPE_IMAGE && component._image._meshDirty) {
component._image._updateMesh(component._image.mesh);
}
}
onAddComponent(entity, component) {
entity.fire("element:add");
}
onRemoveComponent(entity, component) {
component.onRemove();
}
cloneComponent(entity, clone) {
const source = entity.element;
const data = {
enabled: source.enabled,
width: source.width,
height: source.height,
anchor: source.anchor.clone(),
pivot: source.pivot.clone(),
margin: source.margin.clone(),
alignment: source.alignment && source.alignment.clone() || source.alignment,
autoWidth: source.autoWidth,
autoHeight: source.autoHeight,
type: source.type,
rect: source.rect && source.rect.clone() || source.rect,
rtlReorder: source.rtlReorder,
unicodeConverter: source.unicodeConverter,
materialAsset: source.materialAsset,
material: source.material,
color: source.color && source.color.clone() || source.color,
opacity: source.opacity,
textureAsset: source.textureAsset,
texture: source.texture,
spriteAsset: source.spriteAsset,
sprite: source.sprite,
spriteFrame: source.spriteFrame,
pixelsPerUnit: source.pixelsPerUnit,
spacing: source.spacing,
lineHeight: source.lineHeight,
wrapLines: source.wrapLines,
layers: source.layers,
fontSize: source.fontSize,
minFontSize: source.minFontSize,
maxFontSize: source.maxFontSize,
autoFitWidth: source.autoFitWidth,
autoFitHeight: source.autoFitHeight,
maxLines: source.maxLines,
fontAsset: source.fontAsset,
font: source.font,
useInput: source.useInput,
fitMode: source.fitMode,
batchGroupId: source.batchGroupId,
mask: source.mask,
outlineColor: source.outlineColor && source.outlineColor.clone() || source.outlineColor,
outlineThickness: source.outlineThickness,
shadowColor: source.shadowColor && source.shadowColor.clone() || source.shadowColor,
shadowOffset: source.shadowOffset && source.shadowOffset.clone() || source.shadowOffset,
enableMarkup: source.enableMarkup
};
if (source.key !== void 0 && source.key !== null) {
data.key = source.key;
} else {
data.text = source.text;
}
return this.addComponent(clone, data);
}
getTextElementMaterial(screenSpace, msdf, textAttibutes) {
const hash = (screenSpace && 1 << 0) | (msdf && 1 << 1) | (textAttibutes && 1 << 2);
let material = this._defaultTextMaterials[hash];
if (material) {
return material;
}
let name = "TextMaterial";
material = new StandardMaterial();
if (msdf) {
material.msdfMap = this._defaultTexture;
material.msdfTextAttribute = textAttibutes;
material.emissive.set(1, 1, 1);
} else {
name = `Bitmap${name}`;
material.emissive.set(1, 1, 1);
material.emissiveMap = this._defaultTexture;
material.opacityMap = this._defaultTexture;
material.opacityMapChannel = "a";
}
if (screenSpace) {
name = `ScreenSpace${name}`;
material.depthTest = false;
}
material.name = `default${name}`;
material.useLighting = false;
material.useTonemap = false;
material.useFog = false;
material.useSkybox = false;
material.diffuse.set(0, 0, 0);
material.opacity = 0.5;
material.blendType = BLEND_PREMULTIPLIED;
material.depthWrite = false;
material.emissiveVertexColor = true;
material.update();
this._defaultTextMaterials[hash] = material;
return material;
}
_createBaseImageMaterial() {
const material = new StandardMaterial();
material.diffuse.set(0, 0, 0);
material.emissive.set(1, 1, 1);
material.emissiveMap = this._defaultTexture;
material.opacityMap = this._defaultTexture;
material.opacityMapChannel = "a";
material.useLighting = false;
material.useTonemap = false;
material.useFog = false;
material.useSkybox = false;
material.blendType = BLEND_PREMULTIPLIED;
material.depthWrite = false;
return material;
}
getImageElementMaterial(screenSpace, mask, nineSliced, nineSliceTiled) {
if (screenSpace) {
if (mask) {
if (nineSliced) {
if (!this.defaultScreenSpaceImageMask9SlicedMaterial) {
this.defaultScreenSpaceImageMask9SlicedMaterial = this._createBaseImageMaterial();
this.defaultScreenSpaceImageMask9SlicedMaterial.name = "defaultScreenSpaceImageMask9SlicedMaterial";
this.defaultScreenSpaceImageMask9SlicedMaterial.nineSlicedMode = SPRITE_RENDERMODE_SLICED;
this.defaultScreenSpaceImageMask9SlicedMaterial.depthTest = false;
this.defaultScreenSpaceImageMask9SlicedMaterial.alphaTest = 1;
this.defaultScreenSpaceImageMask9SlicedMaterial.redWrite = false;
this.defaultScreenSpaceImageMask9SlicedMaterial.greenWrite = false;
this.defaultScreenSpaceImageMask9SlicedMaterial.blueWrite = false;
this.defaultScreenSpaceImageMask9SlicedMaterial.alphaWrite = false;
this.defaultScreenSpaceImageMask9SlicedMaterial.update();
this.defaultImageMaterials.push(this.defaultScreenSpaceImageMask9SlicedMaterial);
}
return this.defaultScreenSpaceImageMask9SlicedMaterial;
} else if (nineSliceTiled) {
if (!this.defaultScreenSpaceImageMask9TiledMaterial) {
this.defaultScreenSpaceImageMask9TiledMaterial = this.defaultScreenSpaceImage9TiledMaterial.clone();
this.defaultScreenSpaceImageMask9TiledMaterial.name = "defaultScreenSpaceImageMask9TiledMaterial";
this.defaultScreenSpaceImageMask9TiledMaterial.nineSlicedMode = SPRITE_RENDERMODE_TILED;
this.defaultScreenSpaceImageMask9TiledMaterial.depthTest = false;
this.defaultScreenSpaceImageMask9TiledMaterial.alphaTest = 1;
this.defaultScreenSpaceImageMask9TiledMaterial.redWrite = false;
this.defaultScreenSpaceImageMask9TiledMaterial.greenWrite = false;
this.defaultScreenSpaceImageMask9TiledMaterial.blueWrite = false;
this.defaultScreenSpaceImageMask9TiledMaterial.alphaWrite = false;
this.defaultScreenSpaceImageMask9TiledMaterial.update();
this.defaultImageMaterials.push(this.defaultScreenSpaceImageMask9TiledMaterial);
}
return this.defaultScreenSpaceImageMask9TiledMaterial;
} else {
if (!this.defaultScreenSpaceImageMaskMaterial) {
this.defaultScreenSpaceImageMaskMaterial = this._createBaseImageMaterial();
this.defaultScreenSpaceImageMaskMaterial.name = "defaultScreenSpaceImageMaskMaterial";
this.defaultScreenSpaceImageMaskMaterial.depthTest = false;
this.defaultScreenSpaceImageMaskMaterial.alphaTest = 1;
this.defaultScreenSpaceImageMaskMaterial.redWrite = false;
this.defaultScreenSpaceImageMaskMaterial.greenWrite = false;
this.defaultScreenSpaceImageMaskMaterial.blueWrite = false;
this.defaultScreenSpaceImageMaskMaterial.alphaWrite = false;
this.defaultScreenSpaceImageMaskMaterial.update();
this.defaultImageMaterials.push(this.defaultScreenSpaceImageMaskMaterial);
}
return this.defaultScreenSpaceImageMaskMaterial;
}
} else {
if (nineSliced) {
if (!this.defaultScreenSpaceImage9SlicedMaterial) {
this.defaultScreenSpaceImage9SlicedMaterial = this._createBaseImageMaterial();
this.defaultScreenSpaceImage9SlicedMaterial.name = "defaultScreenSpaceImage9SlicedMaterial";
this.defaultScreenSpaceImage9SlicedMaterial.nineSlicedMode = SPRITE_RENDERMODE_SLICED;
this.defaultScreenSpaceImage9SlicedMaterial.depthTest = false;
this.defaultScreenSpaceImage9SlicedMaterial.update();
this.defaultImageMaterials.push(this.defaultScreenSpaceImage9SlicedMaterial);
}
return this.defaultScreenSpaceImage9SlicedMaterial;
} else if (nineSliceTiled) {
if (!this.defaultScreenSpaceImage9TiledMaterial) {
this.defaultScreenSpaceImage9TiledMaterial = this._createBaseImageMaterial();
this.defaultScreenSpaceImage9TiledMaterial.name = "defaultScreenSpaceImage9TiledMaterial";
this.defaultScreenSpaceImage9TiledMaterial.nineSlicedMode = SPRITE_RENDERMODE_TILED;
this.defaultScreenSpaceImage9TiledMaterial.depthTest = false;
this.defaultScreenSpaceImage9TiledMaterial.update();
this.defaultImageMaterials.push(this.defaultScreenSpaceImage9TiledMaterial);
}
return this.defaultScreenSpaceImage9TiledMaterial;
} else {
if (!this.defaultScreenSpaceImageMaterial) {
this.defaultScreenSpaceImageMaterial = this._createBaseImageMaterial();
this.defaultScreenSpaceImageMaterial.name = "defaultScreenSpaceImageMaterial";
this.defaultScreenSpaceImageMaterial.depthTest = false;
this.defaultScreenSpaceImageMaterial.update();
this.defaultImageMaterials.push(this.defaultScreenSpaceImageMaterial);
}
return this.defaultScreenSpaceImageMaterial;
}
}
} else {
if (mask) {
if (nineSliced) {
if (!this.defaultImage9SlicedMaskMaterial) {
this.defaultImage9SlicedMaskMaterial = this._createBaseImageMaterial();
this.defaultImage9SlicedMaskMaterial.name = "defaultImage9SlicedMaskMaterial";
this.defaultImage9SlicedMaskMaterial.nineSlicedMode = SPRITE_RENDERMODE_SLICED;
this.defaultImage9SlicedMaskMaterial.alphaTest = 1;
this.defaultImage9SlicedMaskMaterial.redWrite = false;
this.defaultImage9SlicedMaskMaterial.greenWrite = false;
this.defaultImage9SlicedMaskMaterial.blueWrite = false;
this.defaultImage9SlicedMaskMaterial.alphaWrite = false;
this.defaultImage9SlicedMaskMaterial.update();
this.defaultImageMaterials.push(this.defaultImage9SlicedMaskMaterial);
}
return this.defaultImage9SlicedMaskMaterial;
} else if (nineSliceTiled) {
if (!this.defaultImage9TiledMaskMaterial) {
this.defaultImage9TiledMaskMaterial = this._createBaseImageMaterial();
this.defaultImage9TiledMaskMaterial.name = "defaultImage9TiledMaskMaterial";
this.defaultImage9TiledMaskMaterial.nineSlicedMode = SPRITE_RENDERMODE_TILED;
this.defaultImage9TiledMaskMaterial.alphaTest = 1;
this.defaultImage9TiledMaskMaterial.redWrite = false;
this.defaultImage9TiledMaskMaterial.greenWrite = false;
this.defaultImage9TiledMaskMaterial.blueWrite = false;
this.defaultImage9TiledMaskMaterial.alphaWrite = false;
this.defaultImage9TiledMaskMaterial.update();
this.defaultImageMaterials.push(this.defaultImage9TiledMaskMaterial);
}
return this.defaultImage9TiledMaskMaterial;
} else {
if (!this.defaultImageMaskMaterial) {
this.defaultImageMaskMaterial = this._createBaseImageMaterial();
this.defaultImageMaskMaterial.name = "defaultImageMaskMaterial";
this.defaultImageMaskMaterial.alphaTest = 1;
this.defaultImageMaskMaterial.redWrite = false;
this.defaultImageMaskMaterial.greenWrite = false;
this.defaultImageMaskMaterial.blueWrite = false;
this.defaultImageMaskMaterial.alphaWrite = false;
this.defaultImageMaskMaterial.update();
this.defaultImageMaterials.push(this.defaultImageMaskMaterial);
}
return this.defaultImageMaskMaterial;
}
} else {
if (nineSliced) {
if (!this.defaultImage9SlicedMaterial) {
this.defaultImage9SlicedMaterial = this._createBaseImageMaterial();
this.defaultImage9SlicedMaterial.name = "defaultImage9SlicedMaterial";
this.defaultImage9SlicedMaterial.nineSlicedMode = SPRITE_RENDERMODE_SLICED;
this.defaultImage9SlicedMaterial.update();
this.defaultImageMaterials.push(this.defaultImage9SlicedMaterial);
}
return this.defaultImage9SlicedMaterial;
} else if (nineSliceTiled) {
if (!this.defaultImage9TiledMaterial) {
this.defaultImage9TiledMaterial = this._createBaseImageMaterial();
this.defaultImage9TiledMaterial.name = "defaultImage9TiledMaterial";
this.defaultImage9TiledMaterial.nineSlicedMode = SPRITE_RENDERMODE_TILED;
this.defaultImage9TiledMaterial.update();
this.defaultImageMaterials.push(this.defaultImage9TiledMaterial);
}
return this.defaultImage9TiledMaterial;
} else {
if (!this.defaultImageMaterial) {
this.defaultImageMaterial = this._createBaseImageMaterial();
this.defaultImageMaterial.name = "defaultImageMaterial";
this.defaultImageMaterial.update();
this.defaultImageMaterials.push(this.defaultImageMaterial);
}
return this.defaultImageMaterial;
}
}
}
}
registerUnicodeConverter(func) {
this._unicodeConverter = func;
}
registerRtlReorder(func) {
this._rtlReorder = func;
}
getUnicodeConverter() {
return this._unicodeConverter;
}
getRtlReorder() {
return this._rtlReorder;
}
}
export {
ElementComponentSystem
};