UNPKG

playcanvas

Version:

PlayCanvas WebGL game engine

494 lines (491 loc) 22.3 kB
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.0; pixelData[1] = 255.0; pixelData[2] = 255.0; pixelData[3] = 255.0; 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 !== undefined) { 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 !== undefined) { 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) > 0.001; const splitVerAnchors = Math.abs(component.anchor.y - component.anchor.w) > 0.001; let _marginChange = false; let color; if (data.margin !== undefined) { 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 !== undefined) { component._margin.x = data.left; _marginChange = true; } if (data.bottom !== undefined) { component._margin.y = data.bottom; _marginChange = true; } if (data.right !== undefined) { component._margin.z = data.right; _marginChange = true; } if (data.top !== undefined) { component._margin.w = data.top; _marginChange = true; } if (_marginChange) { component.margin = component._margin; } let shouldForceSetAnchor = false; if (data.width !== undefined && !splitHorAnchors) { component.width = data.width; } else if (splitHorAnchors) { shouldForceSetAnchor = true; } if (data.height !== undefined && !splitVerAnchors) { component.height = data.height; } else if (splitVerAnchors) { shouldForceSetAnchor = true; } if (shouldForceSetAnchor) { component.anchor = component.anchor; } if (data.enabled !== undefined) { component.enabled = data.enabled; } if (data.useInput !== undefined) { component.useInput = data.useInput; } if (data.fitMode !== undefined) { component.fitMode = data.fitMode; } component.batchGroupId = data.batchGroupId === undefined || data.batchGroupId === null ? -1 : data.batchGroupId; if (data.layers && Array.isArray(data.layers)) { component.layers = data.layers.slice(0); } if (data.type !== undefined) { component.type = data.type; } if (component.type === ELEMENTTYPE_IMAGE) { if (data.rect !== undefined) { component.rect = data.rect; } if (data.color !== undefined) { 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 !== undefined) component.opacity = data.opacity; if (data.textureAsset !== undefined) component.textureAsset = data.textureAsset; if (data.texture) component.texture = data.texture; if (data.spriteAsset !== undefined) component.spriteAsset = data.spriteAsset; if (data.sprite) component.sprite = data.sprite; if (data.spriteFrame !== undefined) component.spriteFrame = data.spriteFrame; if (data.pixelsPerUnit !== undefined && data.pixelsPerUnit !== null) component.pixelsPerUnit = data.pixelsPerUnit; if (data.materialAsset !== undefined) component.materialAsset = data.materialAsset; if (data.material) component.material = data.material; if (data.mask !== undefined) { component.mask = data.mask; } } else if (component.type === ELEMENTTYPE_TEXT) { if (data.autoWidth !== undefined) component.autoWidth = data.autoWidth; if (data.autoHeight !== undefined) component.autoHeight = data.autoHeight; if (data.rtlReorder !== undefined) component.rtlReorder = data.rtlReorder; if (data.unicodeConverter !== undefined) component.unicodeConverter = data.unicodeConverter; if (data.text !== null && data.text !== undefined) { component.text = data.text; } else if (data.key !== null && data.key !== undefined) { component.key = data.key; } if (data.color !== undefined) { color = data.color; if (!(color instanceof Color)) { color = new Color(color[0], color[1], color[2]); } component.color = color; } if (data.opacity !== undefined) { component.opacity = data.opacity; } if (data.spacing !== undefined) component.spacing = data.spacing; if (data.fontSize !== undefined) { component.fontSize = data.fontSize; if (!data.lineHeight) component.lineHeight = data.fontSize; } if (data.lineHeight !== undefined) component.lineHeight = data.lineHeight; if (data.maxLines !== undefined) component.maxLines = data.maxLines; if (data.wrapLines !== undefined) component.wrapLines = data.wrapLines; if (data.minFontSize !== undefined) component.minFontSize = data.minFontSize; if (data.maxFontSize !== undefined) component.maxFontSize = data.maxFontSize; if (data.autoFitWidth) component.autoFitWidth = data.autoFitWidth; if (data.autoFitHeight) component.autoFitHeight = data.autoFitHeight; if (data.fontAsset !== undefined) component.fontAsset = data.fontAsset; if (data.font !== undefined) component.font = data.font; if (data.alignment !== undefined) component.alignment = data.alignment; if (data.outlineColor !== undefined) component.outlineColor = data.outlineColor; if (data.outlineThickness !== undefined) component.outlineThickness = data.outlineThickness; if (data.shadowColor !== undefined) component.shadowColor = data.shadowColor; if (data.shadowOffset !== undefined) component.shadowOffset = data.shadowOffset; if (data.enableMarkup !== undefined) 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 !== undefined && 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 };