Skip to content
115 changes: 115 additions & 0 deletions e2e/case/ui-mask.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/**
* @title UI Mask
* @category UI
*/
import {
Camera,
Color,
Sprite,
SpriteMaskInteraction,
Texture2D,
TextureFormat,
Vector3,
WebGLEngine
} from "@galacean/engine";
import {
CanvasRenderMode,
Image,
Mask,
Text,
UICanvas,
UITransform
} from "../../packages/ui/dist/module.js";
import { initScreenshot, updateForE2E } from "./.mockForE2E";

WebGLEngine.create({ canvas: "canvas" }).then((engine) => {
engine.canvas.resizeByClientSize();

const scene = engine.sceneManager.activeScene;
scene.background.solidColor = new Color(0.03, 0.04, 0.07, 1);
const root = scene.createRootEntity("Root");

const cameraEntity = root.createChild("Camera");
cameraEntity.transform.setPosition(0, 0, 10);
const camera = cameraEntity.addComponent(Camera);

const canvasEntity = root.createChild("UICanvas");
const uiCanvas = canvasEntity.addComponent(UICanvas);
uiCanvas.renderMode = CanvasRenderMode.ScreenSpaceCamera;
uiCanvas.camera = camera;
uiCanvas.referenceResolutionPerUnit = 1;
uiCanvas.referenceResolution.set(1200, 800);

const solidSprite = createSolidSprite(engine);

// --- Left group: VisibleInsideMask ---
const leftGroupEntity = canvasEntity.createChild("LeftGroup");
const leftGroupTransform = leftGroupEntity.transform as UITransform;
leftGroupTransform.setPosition(-300, 0, 0);

// Mask (stencil writer)
const maskEntity = leftGroupEntity.createChild("Mask");
const maskTransform = maskEntity.transform as UITransform;
maskTransform.size.set(300, 300);
const mask = maskEntity.addComponent(Mask);
mask.sprite = solidSprite;

// Image behind mask (VisibleInsideMask)
const insideImageEntity = leftGroupEntity.createChild("InsideImage");
const insideImageTransform = insideImageEntity.transform as UITransform;
insideImageTransform.size.set(500, 500);
const insideImage = insideImageEntity.addComponent(Image);
insideImage.sprite = solidSprite;
insideImage.color.set(0.91, 0.3, 0.24, 1);
insideImage.maskInteraction = SpriteMaskInteraction.VisibleInsideMask;

// Label
const leftLabelEntity = leftGroupEntity.createChild("Label");
const leftLabelTransform = leftLabelEntity.transform as UITransform;
leftLabelTransform.size.set(300, 60);
leftLabelTransform.setPosition(0, -210, 0);
const leftLabel = leftLabelEntity.addComponent(Text);
leftLabel.text = "VisibleInsideMask";
leftLabel.fontSize = 30;
leftLabel.color.set(1, 1, 1, 1);

// --- Right group: VisibleOutsideMask ---
const rightGroupEntity = canvasEntity.createChild("RightGroup");
const rightGroupTransform = rightGroupEntity.transform as UITransform;
rightGroupTransform.setPosition(300, 0, 0);

// Mask (stencil writer)
const maskEntity2 = rightGroupEntity.createChild("Mask");
const maskTransform2 = maskEntity2.transform as UITransform;
maskTransform2.size.set(300, 300);
const mask2 = maskEntity2.addComponent(Mask);
mask2.sprite = solidSprite;

// Image behind mask (VisibleOutsideMask)
const outsideImageEntity = rightGroupEntity.createChild("OutsideImage");
const outsideImageTransform = outsideImageEntity.transform as UITransform;
outsideImageTransform.size.set(500, 500);
const outsideImage = outsideImageEntity.addComponent(Image);
outsideImage.sprite = solidSprite;
outsideImage.color.set(0.16, 0.5, 0.73, 1);
outsideImage.maskInteraction = SpriteMaskInteraction.VisibleOutsideMask;

// Label
const rightLabelEntity = rightGroupEntity.createChild("Label");
const rightLabelTransform = rightLabelEntity.transform as UITransform;
rightLabelTransform.size.set(300, 60);
rightLabelTransform.setPosition(0, -210, 0);
const rightLabel = rightLabelEntity.addComponent(Text);
rightLabel.text = "VisibleOutsideMask";
rightLabel.fontSize = 30;
rightLabel.color.set(1, 1, 1, 1);

updateForE2E(engine);
initScreenshot(engine, camera);
});

function createSolidSprite(engine: WebGLEngine): Sprite {
const texture = new Texture2D(engine, 1, 1, TextureFormat.R8G8B8A8, false);
texture.setPixelBuffer(new Uint8Array([255, 255, 255, 255]));
return new Sprite(engine, texture);
}
124 changes: 124 additions & 0 deletions e2e/case/ui-rectMask.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/**
* @title UI RectMask2D
* @category UI
*/
import { Camera, Color, Sprite, Texture2D, TextureFormat, WebGLEngine } from "@galacean/engine";
import {
CanvasRenderMode,
Image,
RectMask2D,
Text,
UICanvas,
UITransform
} from "../../packages/ui/dist/module.js";
import { initScreenshot, updateForE2E } from "./.mockForE2E";

WebGLEngine.create({ canvas: "canvas" }).then((engine) => {
engine.canvas.resizeByClientSize();

const scene = engine.sceneManager.activeScene;
scene.background.solidColor = new Color(0.03, 0.04, 0.07, 1);
const root = scene.createRootEntity("Root");

const cameraEntity = root.createChild("Camera");
cameraEntity.transform.setPosition(0, 0, 10);
const camera = cameraEntity.addComponent(Camera);

const canvasEntity = root.createChild("UICanvas");
const uiCanvas = canvasEntity.addComponent(UICanvas);
uiCanvas.renderMode = CanvasRenderMode.ScreenSpaceCamera;
uiCanvas.camera = camera;
uiCanvas.referenceResolutionPerUnit = 1;
uiCanvas.referenceResolution.set(1200, 800);

const solidSprite = createSolidSprite(engine);

// --- Left: RectMask2D with alphaClip clipping a grid of tiles ---
const frameEntity = canvasEntity.createChild("Frame");
const frameTransform = frameEntity.transform as UITransform;
frameTransform.size.set(520, 420);
frameTransform.setPosition(-170, 20, 0);
const frameBackground = frameEntity.addComponent(Image);
frameBackground.sprite = solidSprite;
frameBackground.color.set(0.09, 0.11, 0.15, 1);

const viewportEntity = frameEntity.createChild("Viewport");
const viewportTransform = viewportEntity.transform as UITransform;
viewportTransform.size.set(440, 320);
viewportTransform.setPosition(30, -10, 0);
const viewportBackground = viewportEntity.addComponent(Image);
viewportBackground.sprite = solidSprite;
viewportBackground.color.set(0.17, 0.18, 0.2, 1);

const rectMask = viewportEntity.addComponent(RectMask2D);
rectMask.alphaClip = true;

const contentEntity = viewportEntity.createChild("Content");
const contentTransform = contentEntity.transform as UITransform;
contentTransform.size.set(740, 560);
contentTransform.setPosition(90, -70, 0);

const colors = [
new Color(0.91, 0.3, 0.24, 1),
new Color(0.16, 0.5, 0.73, 1),
new Color(0.18, 0.8, 0.44, 1),
new Color(0.95, 0.61, 0.07, 1),
new Color(0.56, 0.27, 0.68, 1),
new Color(0.2, 0.6, 0.86, 1),
new Color(0.83, 0.33, 0.33, 1),
new Color(0.1, 0.74, 0.61, 1),
new Color(0.93, 0.78, 0.0, 1)
];

const tileWidth = 180;
const tileHeight = 180;
const gap = 10;

for (let row = 0; row < 3; row++) {
for (let col = 0; col < 3; col++) {
const index = row * 3 + col;
const tileEntity = contentEntity.createChild(`Tile_${index}`);
const tileTransform = tileEntity.transform as UITransform;
tileTransform.size.set(tileWidth, tileHeight);
tileTransform.setPosition(col * (tileWidth + gap) - 170, 170 - row * (tileHeight + gap), 0);

const tile = tileEntity.addComponent(Image);
tile.sprite = solidSprite;
tile.color = colors[index];

const labelEntity = tileEntity.createChild("Label");
const labelTransform = labelEntity.transform as UITransform;
labelTransform.size.set(tileWidth, tileHeight);
const label = labelEntity.addComponent(Text);
label.text = `${index + 1}`;
label.fontSize = 56;
label.color.set(1, 1, 1, 1);
}
}

// --- Right: description ---
const noteEntity = canvasEntity.createChild("Note");
const noteTransform = noteEntity.transform as UITransform;
noteTransform.size.set(340, 180);
noteTransform.setPosition(290, 10, 0);
const noteCard = noteEntity.addComponent(Image);
noteCard.sprite = solidSprite;
noteCard.color.set(0.08, 0.09, 0.12, 1);

const noteTextEntity = noteEntity.createChild("Copy");
const noteTextTransform = noteTextEntity.transform as UITransform;
noteTextTransform.size.set(260, 120);
const noteText = noteTextEntity.addComponent(Text);
noteText.text = "RectMask2D clips\nImage and Text\nby axis-aligned rect.";
noteText.fontSize = 28;
noteText.color.set(0.77, 0.82, 0.89, 1);

updateForE2E(engine);
initScreenshot(engine, camera);
});

function createSolidSprite(engine: WebGLEngine): Sprite {
const texture = new Texture2D(engine, 1, 1, TextureFormat.R8G8B8A8, false);
texture.setPixelBuffer(new Uint8Array([255, 255, 255, 255]));
return new Sprite(engine, texture);
}
14 changes: 14 additions & 0 deletions e2e/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,20 @@ export const E2E_CONFIG = {
diffPercentage: 0.0
}
},
UI: {
Mask: {
category: "UI",
caseFileName: "ui-mask",
threshold: 0,
diffPercentage: 0
},
RectMask2D: {
category: "UI",
caseFileName: "ui-rectMask",
threshold: 0,
diffPercentage: 0
}
},
Trail: {
basic: {
category: "Trail",
Expand Down
3 changes: 3 additions & 0 deletions e2e/fixtures/originImage/UI_ui-mask.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions e2e/fixtures/originImage/UI_ui-rectMask.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading