diff --git a/packages/core/src/2d/assembler/ISpriteAssembler.ts b/packages/core/src/2d/assembler/ISpriteAssembler.ts index 4a446f06d5..5e575e3672 100644 --- a/packages/core/src/2d/assembler/ISpriteAssembler.ts +++ b/packages/core/src/2d/assembler/ISpriteAssembler.ts @@ -2,7 +2,7 @@ import { Matrix, Vector2, Vector3 } from "@galacean/engine-math"; import { ISpriteRenderer } from "./ISpriteRenderer"; /** - * @internal + * Interface for sprite assembler. */ export interface ISpriteAssembler { resetData(renderer: ISpriteRenderer, vertexCount?: number): void; diff --git a/packages/core/src/2d/assembler/ISpriteRenderer.ts b/packages/core/src/2d/assembler/ISpriteRenderer.ts index e05ca6b537..a72f4e9436 100644 --- a/packages/core/src/2d/assembler/ISpriteRenderer.ts +++ b/packages/core/src/2d/assembler/ISpriteRenderer.ts @@ -4,6 +4,9 @@ import { SubPrimitiveChunk } from "../../RenderPipeline/SubPrimitiveChunk"; import { SpriteTileMode } from "../enums/SpriteTileMode"; import { Sprite } from "../sprite"; +/** + * Interface for sprite renderer. + */ export interface ISpriteRenderer { sprite: Sprite; color?: Color; diff --git a/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts b/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts index 03aa991c22..a1545d9764 100644 --- a/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts +++ b/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts @@ -4,7 +4,7 @@ import { ISpriteAssembler } from "./ISpriteAssembler"; import { ISpriteRenderer } from "./ISpriteRenderer"; /** - * @internal + * Assemble vertex data for the sprite renderer in simple mode. */ @StaticInterfaceImplement() export class SimpleSpriteAssembler { diff --git a/packages/core/src/2d/assembler/SlicedSpriteAssembler.ts b/packages/core/src/2d/assembler/SlicedSpriteAssembler.ts index 39727f2351..e8e14a5aa3 100644 --- a/packages/core/src/2d/assembler/SlicedSpriteAssembler.ts +++ b/packages/core/src/2d/assembler/SlicedSpriteAssembler.ts @@ -4,7 +4,7 @@ import { ISpriteAssembler } from "./ISpriteAssembler"; import { ISpriteRenderer } from "./ISpriteRenderer"; /** - * @internal + * Assemble vertex data for the sprite renderer in sliced mode. */ @StaticInterfaceImplement() export class SlicedSpriteAssembler { diff --git a/packages/core/src/2d/assembler/TiledSpriteAssembler.ts b/packages/core/src/2d/assembler/TiledSpriteAssembler.ts index 43eaf47c7f..c4427802f0 100644 --- a/packages/core/src/2d/assembler/TiledSpriteAssembler.ts +++ b/packages/core/src/2d/assembler/TiledSpriteAssembler.ts @@ -8,7 +8,7 @@ import { ISpriteRenderer } from "./ISpriteRenderer"; import { SimpleSpriteAssembler } from "./SimpleSpriteAssembler"; /** - * @internal + * Assemble vertex data for the sprite renderer in tiled mode. */ @StaticInterfaceImplement() export class TiledSpriteAssembler { diff --git a/packages/core/src/2d/enums/SpriteModifyFlags.ts b/packages/core/src/2d/enums/SpriteModifyFlags.ts index 14772de837..3654997f85 100644 --- a/packages/core/src/2d/enums/SpriteModifyFlags.ts +++ b/packages/core/src/2d/enums/SpriteModifyFlags.ts @@ -2,13 +2,22 @@ * Sprite Property Dirty Flag. */ export enum SpriteModifyFlags { + /** The texture of sprite changes. */ texture = 0x1, + /** The size of sprite changes. */ size = 0x2, + /** The rotation of sprite changes. */ atlasRotate = 0x4, + /** The atlasRegion of sprite changes. */ atlasRegion = 0x8, + /** The atlasRegionOffset of sprite changes. */ atlasRegionOffset = 0x10, + /** The region of sprite changes. */ region = 0x20, + /** The pivot of sprite changes. */ pivot = 0x40, + /** The border of sprite changes. */ border = 0x80, + /** The sprite destroyed. */ destroy = 0x100 } diff --git a/packages/core/src/2d/index.ts b/packages/core/src/2d/index.ts index e61337269a..47be64ccfc 100644 --- a/packages/core/src/2d/index.ts +++ b/packages/core/src/2d/index.ts @@ -13,4 +13,4 @@ export { TextHorizontalAlignment, TextVerticalAlignment } from "./enums/TextAlig export { OverflowMode } from "./enums/TextOverflow"; export * from "./sprite/index"; export * from "./text/index"; -export type { ITextRenderer } from "./text/ITextRenderer"; \ No newline at end of file +export type { ITextRenderer } from "./text/ITextRenderer"; diff --git a/packages/core/src/2d/sprite/SpriteMask.ts b/packages/core/src/2d/sprite/SpriteMask.ts index eddd97ea15..e837c67b08 100644 --- a/packages/core/src/2d/sprite/SpriteMask.ts +++ b/packages/core/src/2d/sprite/SpriteMask.ts @@ -70,6 +70,7 @@ export class SpriteMask extends Renderer implements ISpriteRenderer { if (this._customWidth !== undefined) { return this._customWidth; } else { + this._dirtyUpdateFlag & SpriteMaskUpdateFlags.AutomaticSize && this._calDefaultSize(); return this._automaticWidth; } } @@ -92,6 +93,7 @@ export class SpriteMask extends Renderer implements ISpriteRenderer { if (this._customHeight !== undefined) { return this._customHeight; } else { + this._dirtyUpdateFlag & SpriteMaskUpdateFlags.AutomaticSize && this._calDefaultSize(); return this._automaticHeight; } } @@ -336,6 +338,7 @@ export class SpriteMask extends Renderer implements ISpriteRenderer { } else { this._automaticWidth = this._automaticHeight = 0; } + this._dirtyUpdateFlag &= ~SpriteMaskUpdateFlags.AutomaticSize; } @ignoreClone @@ -345,9 +348,9 @@ export class SpriteMask extends Renderer implements ISpriteRenderer { this.shaderData.setTexture(SpriteMask._textureProperty, this.sprite.texture); break; case SpriteModifyFlags.size: + this._dirtyUpdateFlag |= SpriteMaskUpdateFlags.AutomaticSize; if (this._customWidth === undefined || this._customHeight === undefined) { - this._calDefaultSize(); - this._dirtyUpdateFlag |= RendererUpdateFlags.AllPositionAndBounds; + this._dirtyUpdateFlag |= RendererUpdateFlags.AllBounds; } break; case SpriteModifyFlags.region: @@ -374,9 +377,10 @@ export class SpriteMask extends Renderer implements ISpriteRenderer { */ enum SpriteMaskUpdateFlags { UV = 0x10, + AutomaticSize = 0x20, /** LocalPosition | WorldPosition | UV */ AllPositionAndUV = 0x13, /** LocalPosition | WorldPosition | UV | LocalBounds | WorldBounds */ - All = 0x1f + All = 0x3f } diff --git a/packages/core/src/2d/sprite/SpriteRenderer.ts b/packages/core/src/2d/sprite/SpriteRenderer.ts index 7ce6d2be20..78a2456a6e 100644 --- a/packages/core/src/2d/sprite/SpriteRenderer.ts +++ b/packages/core/src/2d/sprite/SpriteRenderer.ts @@ -8,7 +8,6 @@ import { SubPrimitiveChunk } from "../../RenderPipeline/SubPrimitiveChunk"; import { SubRenderElement } from "../../RenderPipeline/SubRenderElement"; import { Renderer, RendererUpdateFlags } from "../../Renderer"; import { assignmentClone, deepClone, ignoreClone } from "../../clone/CloneManager"; -import { ComponentType } from "../../enums/ComponentType"; import { ShaderProperty } from "../../shader/ShaderProperty"; import { ISpriteAssembler } from "../assembler/ISpriteAssembler"; import { ISpriteRenderer } from "../assembler/ISpriteRenderer"; @@ -143,7 +142,6 @@ export class SpriteRenderer extends Renderer implements ISpriteRenderer { this.shaderData.setTexture(SpriteRenderer._textureProperty, null); } this._sprite = value; - this._calDefaultSize(); } } @@ -171,6 +169,7 @@ export class SpriteRenderer extends Renderer implements ISpriteRenderer { if (this._customWidth !== undefined) { return this._customWidth; } else { + this._dirtyUpdateFlag & SpriteRendererUpdateFlags.AutomaticSize && this._calDefaultSize(); return this._automaticWidth; } } @@ -180,7 +179,7 @@ export class SpriteRenderer extends Renderer implements ISpriteRenderer { this._customWidth = value; this._dirtyUpdateFlag |= this._drawMode === SpriteDrawMode.Tiled - ? SpriteRendererUpdateFlags.All + ? SpriteRendererUpdateFlags.AllPositionBoundsUVAndColor : RendererUpdateFlags.AllPositionAndBounds; } } @@ -196,6 +195,7 @@ export class SpriteRenderer extends Renderer implements ISpriteRenderer { if (this._customHeight !== undefined) { return this._customHeight; } else { + this._dirtyUpdateFlag & SpriteRendererUpdateFlags.AutomaticSize && this._calDefaultSize(); return this._automaticHeight; } } @@ -205,7 +205,7 @@ export class SpriteRenderer extends Renderer implements ISpriteRenderer { this._customHeight = value; this._dirtyUpdateFlag |= this._drawMode === SpriteDrawMode.Tiled - ? SpriteRendererUpdateFlags.All + ? SpriteRendererUpdateFlags.AllPositionBoundsUVAndColor : RendererUpdateFlags.AllPositionAndBounds; } } @@ -267,7 +267,6 @@ export class SpriteRenderer extends Renderer implements ISpriteRenderer { */ constructor(entity: Entity) { super(entity); - this._componentType = ComponentType.SpriteRenderer; this.drawMode = SpriteDrawMode.Simple; this._dirtyUpdateFlag |= SpriteRendererUpdateFlags.Color; this.setMaterial(this._engine._basicResources.spriteDefaultMaterial); @@ -410,6 +409,7 @@ export class SpriteRenderer extends Renderer implements ISpriteRenderer { } else { this._automaticWidth = this._automaticHeight = 0; } + this._dirtyUpdateFlag &= ~SpriteRendererUpdateFlags.AutomaticSize; } @ignoreClone @@ -419,8 +419,8 @@ export class SpriteRenderer extends Renderer implements ISpriteRenderer { this.shaderData.setTexture(SpriteRenderer._textureProperty, this.sprite.texture); break; case SpriteModifyFlags.size: + this._dirtyUpdateFlag |= SpriteRendererUpdateFlags.AutomaticSize; if (this._customWidth === undefined || this._customHeight === undefined) { - this._calDefaultSize(); this._dirtyUpdateFlag |= RendererUpdateFlags.AllBounds; } switch (this._drawMode) { @@ -479,11 +479,14 @@ export class SpriteRenderer extends Renderer implements ISpriteRenderer { enum SpriteRendererUpdateFlags { UV = 0x10, Color = 0x20, + AutomaticSize = 0x40, /** LocalPosition | WorldPosition | UV */ AllPositionAndUV = 0x13, /** LocalPosition | WorldPosition | UV | Color */ AllPositionUVAndColor = 0x33, - /** LocalPosition | WorldPosition | UV | Color | LocalBounds | WorldBounds */ - All = 0x3f + /** LocalPosition | WorldPosition | LocalBounds | WorldBounds | UV | Color */ + AllPositionBoundsUVAndColor = 0x3f, + /** LocalPosition | WorldPosition | LocalBounds | WorldBounds | UV | Color | AutomaticSize */ + All = 0x7f } diff --git a/packages/core/src/Camera.ts b/packages/core/src/Camera.ts index 8f7a2006b9..7b17a9455a 100644 --- a/packages/core/src/Camera.ts +++ b/packages/core/src/Camera.ts @@ -298,7 +298,7 @@ export class Camera extends Component { } else { this.shaderData.disableMacro("CAMERA_ORTHOGRAPHIC"); } - this._dispatchModify(CameraModifyFlags.CameraType); + this._dispatchModify(CameraModifyFlags.ProjectionType); } } @@ -654,7 +654,7 @@ export class Camera extends Component { Logger.error("mipLevel only take effect in WebGL2.0"); } let ignoreClearFlags: CameraClearFlags; - if (this._cameraType === CameraType.XRCamera && !this._renderTarget && !this.independentCanvasEnabled) { + if (this._cameraType !== CameraType.Normal && !this._renderTarget && !this.independentCanvasEnabled) { ignoreClearFlags = engine.xrManager._getCameraIgnoreClearFlags(this._cameraType); } this._renderPipeline.render(context, cubeFace, mipLevel, ignoreClearFlags); @@ -760,10 +760,7 @@ export class Camera extends Component { //@ts-ignore this._viewport._onValueChanged = null; this.engine.canvas._sizeUpdateFlagManager.removeListener(this._onPixelViewportChanged); - if (this._updateFlagManager) { - this._updateFlagManager.removeAllListeners(); - this._updateFlagManager = null; - } + this._updateFlagManager = null; this._entity = null; this._globalShaderMacro = null; diff --git a/packages/core/src/Component.ts b/packages/core/src/Component.ts index 9b561ea986..0615805153 100644 --- a/packages/core/src/Component.ts +++ b/packages/core/src/Component.ts @@ -3,16 +3,12 @@ import { EngineObject } from "./base"; import { assignmentClone, ignoreClone } from "./clone/CloneManager"; import { Entity } from "./Entity"; import { ActiveChangeFlag } from "./enums/ActiveChangeFlag"; -import { ComponentType } from "./enums/ComponentType"; import { Scene } from "./Scene"; /** * The base class of the components. */ export class Component extends EngineObject { - /** @internal */ - @ignoreClone - _componentType: ComponentType = ComponentType.Component; /** @internal */ @ignoreClone _entity: Entity; diff --git a/packages/core/src/ComponentsManager.ts b/packages/core/src/ComponentsManager.ts index ed8b0900ce..1921cc1f0e 100644 --- a/packages/core/src/ComponentsManager.ts +++ b/packages/core/src/ComponentsManager.ts @@ -1,9 +1,9 @@ -import { IUICanvas } from "@galacean/engine-design"; import { Camera } from "./Camera"; import { Component } from "./Component"; import { Renderer } from "./Renderer"; import { Script } from "./Script"; import { Animator } from "./animation"; +import { IUICanvas } from "./ui/IUICanvas"; import { DisorderedArray } from "./utils/DisorderedArray"; /** @@ -20,7 +20,7 @@ export class ComponentsManager { /** @internal */ _overlayCanvases: DisorderedArray = new DisorderedArray(); /* @internal */ - _overlayCanvasesSortingFlag: boolean = false; + _overlayCanvasesSortingDirty: boolean = false; /** @internal */ _canvases: DisorderedArray = new DisorderedArray(); @@ -81,7 +81,7 @@ export class ComponentsManager { let canvases: DisorderedArray; if (isOverlay) { canvases = this._overlayCanvases; - this._overlayCanvasesSortingFlag = true; + this._overlayCanvasesSortingDirty = true; } else { canvases = this._canvases; } @@ -93,7 +93,7 @@ export class ComponentsManager { let canvases: DisorderedArray; if (isOverlay) { canvases = this._overlayCanvases; - this._overlayCanvasesSortingFlag = true; + this._overlayCanvasesSortingDirty = true; } else { canvases = this._canvases; } @@ -102,14 +102,14 @@ export class ComponentsManager { uiCanvas._canvasIndex = -1; } - sortUICanvases(): void { - if (this._overlayCanvasesSortingFlag) { + sortOverlayUICanvases(): void { + if (this._overlayCanvasesSortingDirty) { const overlayCanvases = this._overlayCanvases; overlayCanvases.sort((a, b) => a.sortOrder - b.sortOrder); for (let i = 0, n = overlayCanvases.length; i < n; i++) { overlayCanvases.get(i)._canvasIndex = i; } - this._overlayCanvasesSortingFlag = false; + this._overlayCanvasesSortingDirty = false; } } diff --git a/packages/core/src/Engine.ts b/packages/core/src/Engine.ts index 17c5f249c5..55e0d32f2d 100644 --- a/packages/core/src/Engine.ts +++ b/packages/core/src/Engine.ts @@ -515,7 +515,7 @@ export class Engine extends EventDispatcher { const uiCanvas = componentsManager._overlayCanvases; if (uiCanvas.length > 0) { - componentsManager.sortUICanvases(); + componentsManager.sortOverlayUICanvases(); UIUtils.render(this, uiCanvas); } } diff --git a/packages/core/src/Entity.ts b/packages/core/src/Entity.ts index e83d818a81..aedf7095be 100644 --- a/packages/core/src/Entity.ts +++ b/packages/core/src/Entity.ts @@ -548,10 +548,7 @@ export class Entity extends EngineObject { } this.isActive = false; - if (this._updateFlagManager) { - this._updateFlagManager.removeAllListeners(); - this._updateFlagManager = null; - } + this._updateFlagManager = null; } /** @@ -626,7 +623,7 @@ export class Entity extends EngineObject { */ _setParentChange() { this._transform._parentChange(); - this._dispatchModify(EntityModifyFlags.Parent); + this._dispatchModify(EntityModifyFlags.Parent, this); } /** @@ -792,7 +789,7 @@ export class Entity extends EngineObject { } } } - this._dispatchModify(EntityModifyFlags.SiblingIndex); + this._dispatchModify(EntityModifyFlags.SiblingIndex, this); } //--------------------------------------------------------------deprecated---------------------------------------------------------------- diff --git a/packages/core/src/Renderer.ts b/packages/core/src/Renderer.ts index cb07946dcc..ccd95c0230 100644 --- a/packages/core/src/Renderer.ts +++ b/packages/core/src/Renderer.ts @@ -6,10 +6,9 @@ import { DependentMode, dependentComponents } from "./ComponentsDependencies"; import { Entity } from "./Entity"; import { RenderContext } from "./RenderPipeline/RenderContext"; import { SubRenderElement } from "./RenderPipeline/SubRenderElement"; -import { Transform } from "./Transform"; +import { Transform, TransformModifyFlags } from "./Transform"; import { assignmentClone, deepClone, ignoreClone } from "./clone/CloneManager"; import { IComponentCustomClone } from "./clone/ComponentCloner"; -import { ComponentType } from "./enums/ComponentType"; import { SpriteMaskLayer } from "./enums/SpriteMaskLayer"; import { Material } from "./material"; import { ShaderMacro, ShaderProperty } from "./shader"; @@ -67,6 +66,8 @@ export class Renderer extends Component implements IComponentCustomClone { @ignoreClone protected _localBounds: BoundingBox = new BoundingBox(); @ignoreClone + protected _customLocalBounds: BoundingBox; + @ignoreClone protected _bounds: BoundingBox = new BoundingBox(); @ignoreClone protected _transformEntity: Entity; @@ -142,6 +143,7 @@ export class Renderer extends Component implements IComponentCustomClone { * The local bounding volume of the renderer. */ get localBounds(): BoundingBox { + if (this._customLocalBounds) return this._customLocalBounds; if (this._dirtyUpdateFlag & RendererUpdateFlags.LocalBounds) { this._updateLocalBounds(this._localBounds); this._dirtyUpdateFlag &= ~RendererUpdateFlags.LocalBounds; @@ -149,6 +151,15 @@ export class Renderer extends Component implements IComponentCustomClone { return this._localBounds; } + set localBounds(value: BoundingBox) { + if (value) { + (this._customLocalBounds ||= new BoundingBox()).copyFrom(value); + } else { + this._customLocalBounds = null; + } + this._dirtyUpdateFlag |= RendererUpdateFlags.WorldBounds; + } + /** * The world bounding volume of the renderer. */ @@ -178,7 +189,6 @@ export class Renderer extends Component implements IComponentCustomClone { super(entity); const prototype = Renderer.prototype; const shaderData = this.shaderData; - this._componentType = ComponentType.Renderer; this._overrideUpdate = this.update !== prototype.update; this._addResourceReferCount(this.shaderData, 1); @@ -540,7 +550,7 @@ export class Renderer extends Component implements IComponentCustomClone { } @ignoreClone - protected _onTransformChanged(type: number): void { + protected _onTransformChanged(type: TransformModifyFlags): void { this._dirtyUpdateFlag |= RendererUpdateFlags.WorldPositionAndBounds; } } diff --git a/packages/core/src/Transform.ts b/packages/core/src/Transform.ts index ff7d2bf2f1..2da281da2b 100644 --- a/packages/core/src/Transform.ts +++ b/packages/core/src/Transform.ts @@ -3,7 +3,6 @@ import { BoolUpdateFlag } from "./BoolUpdateFlag"; import { Component } from "./Component"; import { Entity } from "./Entity"; import { assignmentClone, deepClone, ignoreClone } from "./clone/CloneManager"; -import { Logger } from "./base"; /** * Used to implement transformation related functions. @@ -26,35 +25,35 @@ export class Transform extends Component { @deepClone protected _rotationQuaternion: Quaternion = new Quaternion(); @deepClone - private _scale: Vector3 = new Vector3(1, 1, 1); + protected _scale: Vector3 = new Vector3(1, 1, 1); @assignmentClone - private _localUniformScaling: boolean = true; + protected _localUniformScaling: boolean = true; @deepClone protected _worldPosition: Vector3 = new Vector3(); @deepClone protected _worldRotation: Vector3 = new Vector3(); @deepClone - private _worldRotationQuaternion: Quaternion = new Quaternion(); + protected _worldRotationQuaternion: Quaternion = new Quaternion(); @assignmentClone - private _worldUniformScaling: boolean = true; + protected _worldUniformScaling: boolean = true; @deepClone - private _lossyWorldScale: Vector3 = new Vector3(1, 1, 1); + protected _lossyWorldScale: Vector3 = new Vector3(1, 1, 1); @deepClone protected _localMatrix: Matrix = new Matrix(); @deepClone protected _worldMatrix: Matrix = new Matrix(); @ignoreClone - private _worldForward: Vector3 = null; + protected _worldForward: Vector3 = null; @ignoreClone - private _worldRight: Vector3 = null; + protected _worldRight: Vector3 = null; @ignoreClone - private _worldUp: Vector3 = null; + protected _worldUp: Vector3 = null; @ignoreClone - private _isParentDirty: boolean = true; + protected _isParentDirty: boolean = true; @ignoreClone - private _parentTransformCache: Transform = null; - private _dirtyFlag: number = TransformModifyFlags.WmWpWeWqWs; + protected _parentTransformCache: Transform = null; + protected _dirtyFlag: number = TransformModifyFlags.WmWpWeWqWs; /** * Local position. diff --git a/packages/core/src/UpdateFlagManager.ts b/packages/core/src/UpdateFlagManager.ts index 33a3d2c0ae..82dda34349 100644 --- a/packages/core/src/UpdateFlagManager.ts +++ b/packages/core/src/UpdateFlagManager.ts @@ -56,13 +56,6 @@ export class UpdateFlagManager { Utils.removeFromArray(this._listeners, listener); } - /** - * Remove all listeners. - */ - removeAllListeners(): void { - this._listeners.length = 0; - } - /** * Dispatch a event. * @param type - Event type, usually in the form of enumeration diff --git a/packages/core/src/enums/CameraModifyFlags.ts b/packages/core/src/enums/CameraModifyFlags.ts index f29cfbb006..727ad9039c 100644 --- a/packages/core/src/enums/CameraModifyFlags.ts +++ b/packages/core/src/enums/CameraModifyFlags.ts @@ -1,8 +1,17 @@ +/** + * The camera modify flags. + */ export enum CameraModifyFlags { - CameraType = 0x1, + /** The types of camera projections changes. */ + ProjectionType = 0x1, + /** The aspect ratio of the camera changes. */ AspectRatio = 0x2, + /** The field of view of the camera changes. */ FieldOfView = 0x4, + /** The orthographic size of the camera changes. */ OrthographicSize = 0x8, + /** The camera becomes active in the scene. */ EnableInScene = 0x10, + /** The camera becomes inactive in the scene. */ DisableInScene = 0x20 } diff --git a/packages/core/src/enums/CameraType.ts b/packages/core/src/enums/CameraType.ts index 29f904dfb3..8ce03a4331 100644 --- a/packages/core/src/enums/CameraType.ts +++ b/packages/core/src/enums/CameraType.ts @@ -5,6 +5,5 @@ export enum CameraType { Normal = 0x0, XRCenterCamera = 0x1, XRLeftCamera = 0x2, - XRRightCamera = 0x4, - XRCamera = CameraType.XRCenterCamera | CameraType.XRLeftCamera | CameraType.XRRightCamera + XRRightCamera = 0x4 } diff --git a/packages/core/src/enums/ComponentType.ts b/packages/core/src/enums/ComponentType.ts deleted file mode 100644 index 3c3dd885e6..0000000000 --- a/packages/core/src/enums/ComponentType.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * @internal - */ -export enum ComponentType { - // Base components - Component = 0x1, - Script = 0x2, - - // Renderers - Renderer = 0x4, - MeshRenderer = 0x8, - SkinnedMeshRenderer = 0x10, - SpriteRenderer = 0x20, - TextRenderer = 0x40, - - // UI components - UICanvas = 0x80, - UIGroup = 0x100, - UIRenderer = 0x200, - UIInteractive = 0x400, - UIGroupAble = 0x600, - UIElement = 0x680 -} diff --git a/packages/core/src/enums/EntityModifyFlags.ts b/packages/core/src/enums/EntityModifyFlags.ts index e99b5e1149..619d1e0906 100644 --- a/packages/core/src/enums/EntityModifyFlags.ts +++ b/packages/core/src/enums/EntityModifyFlags.ts @@ -1,4 +1,9 @@ +/** + * The entity modify flags. + */ export enum EntityModifyFlags { + /** The parent changes. */ Parent = 0x1, + /** The sibling index changes. */ SiblingIndex = 0x2 } diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index e017d663ee..11dbe1e36b 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -12,7 +12,7 @@ export { Entity } from "./Entity"; export { Component } from "./Component"; export { Script } from "./Script"; export { Renderer, RendererUpdateFlags } from "./Renderer"; -export { DependentMode, dependentComponents } from "./ComponentsDependencies"; +export { dependentComponents, DependentMode } from "./ComponentsDependencies"; export { Camera } from "./Camera"; export { Transform } from "./Transform"; export { BoolUpdateFlag } from "./BoolUpdateFlag"; @@ -34,10 +34,8 @@ export * from "./base"; export { Background } from "./Background"; export { BackgroundMode } from "./enums/BackgroundMode"; -export { BackgroundTextureFillMode } from "./enums/BackgroundTextureFillMode"; export { DepthTextureMode } from "./enums/DepthTextureMode"; export { FogMode } from "./enums/FogMode"; -export { ComponentType } from "./enums/ComponentType"; export { CameraClearFlags } from "./enums/CameraClearFlags"; export { CameraType } from "./enums/CameraType"; export { CameraModifyFlags } from "./enums/CameraModifyFlags"; @@ -46,6 +44,7 @@ export { MSAASamples } from "./enums/MSAASamples"; export { ReplacementFailureStrategy } from "./enums/ReplacementFailureStrategy"; export { Downsampling } from "./enums/Downsampling"; export { ColorSpace } from "./enums/ColorSpace"; +export { BackgroundTextureFillMode } from "./enums/BackgroundTextureFillMode"; export { SpriteMaskLayer } from "./enums/SpriteMaskLayer"; export { XRManager } from "./xr/XRManager"; export * from "./utils/index"; diff --git a/packages/core/src/input/pointer/PointerEventData.ts b/packages/core/src/input/pointer/PointerEventData.ts index b311ad4b7f..a131b06057 100644 --- a/packages/core/src/input/pointer/PointerEventData.ts +++ b/packages/core/src/input/pointer/PointerEventData.ts @@ -3,10 +3,17 @@ import { Entity } from "../../Entity"; import { IPoolElement } from "../../utils/ObjectPool"; import { Pointer } from "./Pointer"; +/** + * Pointer event data. + */ export class PointerEventData implements IPoolElement { + /** The entity that listens to this event. */ target: Entity; + /** The entity currently handling this event. */ currentTarget: Entity; + /** The pointer that triggers this event. */ pointer: Pointer; + /** The position of the event trigger (in world space). */ position: Vector3 = new Vector3(); dispose() { diff --git a/packages/core/src/physics/CharacterController.ts b/packages/core/src/physics/CharacterController.ts index 0d677008fa..a4d1b49ccc 100644 --- a/packages/core/src/physics/CharacterController.ts +++ b/packages/core/src/physics/CharacterController.ts @@ -1,7 +1,6 @@ import { ICharacterController } from "@galacean/engine-design"; import { Vector3 } from "@galacean/engine-math"; import { Entity } from "../Entity"; -import { ignoreClone } from "../clone/CloneManager"; import { Collider } from "./Collider"; import { PhysicsScene } from "./PhysicsScene"; import { ControllerNonWalkableMode } from "./enums/ControllerNonWalkableMode"; @@ -167,7 +166,6 @@ export class CharacterController extends Collider { (this._nativeCollider).getWorldPosition(this.entity.transform.worldPosition); } - @ignoreClone private _setUpDirection(): void { (this._nativeCollider).setUpDirection(this._upDirection); } diff --git a/packages/core/src/physics/PhysicsScene.ts b/packages/core/src/physics/PhysicsScene.ts index 023b4f3d90..726a320a02 100644 --- a/packages/core/src/physics/PhysicsScene.ts +++ b/packages/core/src/physics/PhysicsScene.ts @@ -1,15 +1,14 @@ import { ICharacterController, ICollider, IPhysics, IPhysicsScene } from "@galacean/engine-design"; import { MathUtil, Ray, Vector3 } from "@galacean/engine-math"; -import { Engine } from "../Engine"; import { Layer } from "../Layer"; import { Scene } from "../Scene"; -import { Script } from "../Script"; -import { ignoreClone } from "../clone/CloneManager"; -import { DisorderedArray } from "../utils/DisorderedArray"; import { CharacterController } from "./CharacterController"; import { Collider } from "./Collider"; import { Collision } from "./Collision"; import { HitResult } from "./HitResult"; +import { Script } from "../Script"; +import { DisorderedArray } from "../utils/DisorderedArray"; +import { Engine } from "../Engine"; /** * A physics scene is a collection of colliders and constraints which can interact. @@ -437,7 +436,6 @@ export class PhysicsScene { this._colliders.garbageCollection(); } - @ignoreClone private _setGravity(): void { this._nativePhysicsScene.setGravity(this._gravity); } diff --git a/packages/core/src/physics/shape/BoxColliderShape.ts b/packages/core/src/physics/shape/BoxColliderShape.ts index 1d25279cda..c329f8b9d8 100644 --- a/packages/core/src/physics/shape/BoxColliderShape.ts +++ b/packages/core/src/physics/shape/BoxColliderShape.ts @@ -1,8 +1,8 @@ +import { ColliderShape } from "./ColliderShape"; import { IBoxColliderShape } from "@galacean/engine-design"; import { Vector3 } from "@galacean/engine-math"; -import { deepClone, ignoreClone } from "../../clone/CloneManager"; import { PhysicsScene } from "../PhysicsScene"; -import { ColliderShape } from "./ColliderShape"; +import { deepClone, ignoreClone } from "../../clone/CloneManager"; /** * Physical collider shape for box. diff --git a/packages/core/src/physics/shape/ColliderShape.ts b/packages/core/src/physics/shape/ColliderShape.ts index c4476a8ac7..79e6dc4239 100644 --- a/packages/core/src/physics/shape/ColliderShape.ts +++ b/packages/core/src/physics/shape/ColliderShape.ts @@ -1,10 +1,10 @@ import { IColliderShape } from "@galacean/engine-design"; +import { PhysicsMaterial } from "../PhysicsMaterial"; import { Vector3 } from "@galacean/engine-math"; +import { Collider } from "../Collider"; import { deepClone, ignoreClone } from "../../clone/CloneManager"; import { ICustomClone } from "../../clone/ComponentCloner"; import { Engine } from "../../Engine"; -import { Collider } from "../Collider"; -import { PhysicsMaterial } from "../PhysicsMaterial"; /** * Abstract class for collider shapes. diff --git a/packages/core/src/shader/index.ts b/packages/core/src/shader/index.ts index c855187eaf..b727fed74a 100644 --- a/packages/core/src/shader/index.ts +++ b/packages/core/src/shader/index.ts @@ -1,19 +1,19 @@ -export { Shader } from "./Shader"; -export { ShaderData } from "./ShaderData"; -export { ShaderMacro } from "./ShaderMacro"; -export { ShaderPass } from "./ShaderPass"; -export { ShaderProperty } from "./ShaderProperty"; -export { ShaderTagKey } from "./ShaderTagKey"; -export { SubShader } from "./SubShader"; export { BlendFactor } from "./enums/BlendFactor"; export { BlendOperation } from "./enums/BlendOperation"; export { ColorWriteMask } from "./enums/ColorWriteMask"; export { CompareFunction } from "./enums/CompareFunction"; export { CullMode } from "./enums/CullMode"; -export { RenderQueueType } from "./enums/RenderQueueType"; export { RenderStateElementKey as RenderStateDataKey } from "./enums/RenderStateElementKey"; +export { RenderQueueType } from "./enums/RenderQueueType"; export { ShaderDataGroup } from "./enums/ShaderDataGroup"; -export { ShaderPlatformTarget } from "./enums/ShaderPlatformTarget"; export { ShaderPropertyType } from "./enums/ShaderPropertyType"; export { StencilOperation } from "./enums/StencilOperation"; +export { ShaderPlatformTarget } from "./enums/ShaderPlatformTarget"; +export { Shader } from "./Shader"; +export { ShaderData } from "./ShaderData"; +export { ShaderMacro } from "./ShaderMacro"; +export { ShaderPass } from "./ShaderPass"; +export { ShaderProperty } from "./ShaderProperty"; +export { ShaderTagKey } from "./ShaderTagKey"; +export { SubShader } from "./SubShader"; export * from "./state"; diff --git a/packages/core/src/ui/IUICanvas.ts b/packages/core/src/ui/IUICanvas.ts new file mode 100644 index 0000000000..1b5bd5e555 --- /dev/null +++ b/packages/core/src/ui/IUICanvas.ts @@ -0,0 +1,14 @@ +import { Entity } from "../Entity"; +import { RenderContext } from "../RenderPipeline/RenderContext"; +import { RenderElement } from "../RenderPipeline/RenderElement"; + +/** + * @internal + */ +export interface IUICanvas { + entity: Entity; + sortOrder: number; + _canvasIndex: number; + _renderElement: RenderElement; + _prepareRender(renderContext: RenderContext): void; +} diff --git a/packages/core/src/ui/UIUtils.ts b/packages/core/src/ui/UIUtils.ts index 868b61b166..7244179fb0 100644 --- a/packages/core/src/ui/UIUtils.ts +++ b/packages/core/src/ui/UIUtils.ts @@ -1,4 +1,3 @@ -import { IUICanvas } from "@galacean/engine-design"; import { Matrix, Vector4 } from "@galacean/engine-math"; import { Engine } from "../Engine"; import { RenderQueue } from "../RenderPipeline"; @@ -6,6 +5,7 @@ import { ContextRendererUpdateFlag } from "../RenderPipeline/RenderContext"; import { VirtualCamera } from "../VirtualCamera"; import { RenderQueueType } from "../shader"; import { DisorderedArray } from "../utils/DisorderedArray"; +import { IUICanvas } from "./IUICanvas"; export class UIUtils { private static _renderQueue: RenderQueue; diff --git a/packages/design/src/index.ts b/packages/design/src/index.ts index 194fb5c2e2..1dd007de42 100644 --- a/packages/design/src/index.ts +++ b/packages/design/src/index.ts @@ -3,5 +3,4 @@ export * from "./input/index"; export * from "./physics/index"; export * from "./renderingHardwareInterface/index"; export * from "./shader-lab/index"; -export * from "./ui/index"; export * from "./xr/index"; diff --git a/packages/design/src/ui/IUICanvas.ts b/packages/design/src/ui/IUICanvas.ts deleted file mode 100644 index dd878e9b10..0000000000 --- a/packages/design/src/ui/IUICanvas.ts +++ /dev/null @@ -1,7 +0,0 @@ -export interface IUICanvas { - entity: any; - sortOrder: number; - _canvasIndex: number; - _renderElement: any; - _prepareRender(renderContext: any): void; -} diff --git a/packages/design/src/ui/index.ts b/packages/design/src/ui/index.ts deleted file mode 100644 index eb1df2dabf..0000000000 --- a/packages/design/src/ui/index.ts +++ /dev/null @@ -1 +0,0 @@ -export type { IUICanvas } from "./IUICanvas"; diff --git a/packages/ui/src/Utils.ts b/packages/ui/src/Utils.ts index a788fe8968..b3df3cf0d4 100644 --- a/packages/ui/src/Utils.ts +++ b/packages/ui/src/Utils.ts @@ -1,69 +1,82 @@ -import { ComponentType, Entity } from "@galacean/engine"; +import { Entity } from "@galacean/engine"; import { UICanvas } from "./component/UICanvas"; import { GroupModifyFlags, UIGroup } from "./component/UIGroup"; import { IElement } from "./interface/IElement"; import { IGroupAble } from "./interface/IGroupAble"; export class Utils { - static _registerListener( - entity: Entity, - root: Entity, - listener: (flag: number, param?: any) => void, - listeningEntities: Entity[] - ): void { - let count = 0; - while (entity && entity !== root) { - const preEntity = listeningEntities[count]; - if (preEntity !== entity) { - // @ts-ignore - preEntity?._unRegisterModifyListener(listener); - listeningEntities[count] = entity; - // @ts-ignore - entity._registerModifyListener(listener); - } - entity = entity.parent; - count++; - } - listeningEntities.length = count; + static setRootCanvasDirty(element: IElement): void { + if (element._isRootCanvasDirty) return; + element._isRootCanvasDirty = true; + this._registerRootCanvas(element, null); } - static _unRegisterListener(listener: (flag: number, param?: any) => void, listeningEntities: Entity[]): void { - for (let i = 0, n = listeningEntities.length; i < n; i++) { - // @ts-ignore - listeningEntities[i]._unRegisterModifyListener(listener); - } - listeningEntities.length = 0; + static setRootCanvas(element: IElement, rootCanvas: UICanvas): void { + element._isRootCanvasDirty = false; + this._registerRootCanvas(element, rootCanvas); + const fromEntity = element instanceof UICanvas ? element.entity.parent : element.entity; + const toEntity = rootCanvas?.entity ?? null; + this._registerListener(fromEntity, toEntity, element._rootCanvasListener, element._rootCanvasListeningEntities); } - static getRootCanvasInParents(entity: Entity, root?: Entity): UICanvas { - entity = entity.parent; - let rootCanvas: UICanvas = null; - while (entity && entity !== root) { + static cleanRootCanvas(element: IElement): void { + this._registerRootCanvas(element, null); + this._unRegisterListener(element._rootCanvasListener, element._rootCanvasListeningEntities); + } + + static searchRootCanvasInParents(element: IElement): UICanvas { + let entity = element instanceof UICanvas ? element.entity.parent : element.entity; + while (entity) { // @ts-ignore const components = entity._components; for (let i = 0, n = components.length; i < n; i++) { const component = components[i]; - if (component.enabled && component._componentType === ComponentType.UICanvas) { - rootCanvas = component; - if (rootCanvas._isRootCanvas) { - return rootCanvas; - } + if (component.enabled && component instanceof UICanvas && component._isRootCanvas) { + return component; } } entity = entity.parent; } - return rootCanvas; + return null; + } + + static setGroupDirty(element: IGroupAble): void { + if (element._isGroupDirty) return; + element._isGroupDirty = true; + this._registerGroup(element, null); + element._onGroupModify(GroupModifyFlags.All); + } + + static setGroup(element: IGroupAble, group: UIGroup): void { + element._isGroupDirty = false; + this._registerGroup(element, group); + const rootCanvas = element._getRootCanvas(); + if (rootCanvas) { + const fromEntity = element instanceof UIGroup ? element.entity.parent : element.entity; + const toEntity = group?.entity ?? rootCanvas.entity.parent; + this._registerListener(fromEntity, toEntity, element._groupListener, element._groupListeningEntities); + } else { + this._unRegisterListener(element._groupListener, element._groupListeningEntities); + } } - static getGroupInParents(entity: Entity, canvasEntity: Entity): UIGroup { - const root = canvasEntity.parent; - while (entity && entity !== root) { + static cleanGroup(element: IGroupAble): void { + this._registerGroup(element, null); + this._unRegisterListener(element._groupListener, element._groupListeningEntities); + } + + static searchGroupInParents(element: IGroupAble): UIGroup { + const rootCanvas = element._getRootCanvas(); + if (!rootCanvas) return null; + let entity = element instanceof UIGroup ? element.entity.parent : element.entity; + const rootCanvasParent = rootCanvas.entity.parent; + while (entity && entity !== rootCanvasParent) { // @ts-ignore const components = entity._components; for (let i = 0, n = components.length; i < n; i++) { const component = components[i]; - if (component.enabled && component._componentType === ComponentType.UIGroup) { - return component; + if (component.enabled && component instanceof UIGroup) { + return component; } } entity = entity.parent; @@ -71,80 +84,68 @@ export class Utils { return null; } - static _registerElementToCanvas(element: IElement, pre: UICanvas, cur: UICanvas): void { - if (pre !== cur) { - if (pre) { - const replaced = pre._disorderedElements.deleteByIndex(element._indexInCanvas); - replaced && (replaced._indexInCanvas = element._indexInCanvas); - element._indexInCanvas = -1; + private static _registerRootCanvas(element: IElement, canvas: UICanvas): void { + const preCanvas = element._rootCanvas; + if (preCanvas !== canvas) { + if (preCanvas) { + const replaced = preCanvas._disorderedElements.deleteByIndex(element._indexInRootCanvas); + replaced && (replaced._indexInRootCanvas = element._indexInRootCanvas); + element._indexInRootCanvas = -1; } - if (cur) { - const disorderedElements = cur._disorderedElements; - element._indexInCanvas = disorderedElements.length; + if (canvas) { + const disorderedElements = canvas._disorderedElements; + element._indexInRootCanvas = disorderedElements.length; disorderedElements.add(element); } - // @ts-ignore - element._canvas = cur; + element._rootCanvas = canvas; } } - static _registerElementToCanvasListener(element: IElement, canvas: UICanvas): void { - Utils._registerListener(element.entity, canvas?.entity, element._canvasListener, element._canvasListeningEntities); - } - - static _registerCanvasToCanvasListener(canvas: UICanvas, rootCanvas: UICanvas): void { - Utils._registerListener( - canvas.entity.parent, - rootCanvas?.entity, - canvas._canvasListener, - canvas._canvasListeningEntities - ); - } - - static _registerElementToGroup(element: IGroupAble, pre: UIGroup, cur: UIGroup): void { - if (pre !== cur) { - if (pre) { - const replaced = pre._disorderedElements.deleteByIndex(element._indexInGroup); + private static _registerGroup(element: IGroupAble, group: UIGroup): void { + const preGroup = element._group; + if (preGroup !== group) { + if (preGroup) { + const replaced = preGroup._disorderedElements.deleteByIndex(element._indexInGroup); replaced && (replaced._indexInGroup = element._indexInGroup); element._indexInGroup = -1; } - if (cur) { - const disorderedElements = cur._disorderedElements; + if (group) { + const disorderedElements = group._disorderedElements; element._indexInGroup = disorderedElements.length; disorderedElements.add(element); } - // @ts-ignore - element._group = cur; + element._group = group; + element._onGroupModify(GroupModifyFlags.All); } } - static _registerElementToGroupListener(element: IGroupAble, canvas: UICanvas): void { - Utils._registerListener(element.entity, canvas?.entity, element._groupListener, element._groupListeningEntities); - } - - static _registerGroupToGroupListener(group: UIGroup, canvas: UICanvas): void { - Utils._registerListener(group.entity.parent, canvas?.entity, group._groupListener, group._groupListeningEntities); - } - - static _onGroupDirty(element: IGroupAble, preGroup: UIGroup): void { - if (element._isGroupDirty) return; - element._isGroupDirty = true; - if (preGroup) { - const replaced = preGroup._disorderedElements.deleteByIndex(element._indexInGroup); - replaced && (replaced._indexInGroup = element._indexInGroup); - element._indexInGroup = -1; + private static _registerListener( + entity: Entity, + root: Entity, + listener: (flag: number, param?: any) => void, + listeningEntities: Entity[] + ): void { + let count = 0; + while (entity && entity !== root) { + const preEntity = listeningEntities[count]; + if (preEntity !== entity) { + // @ts-ignore + preEntity?._unRegisterModifyListener(listener); + listeningEntities[count] = entity; + // @ts-ignore + entity._registerModifyListener(listener); + } + entity = entity.parent; + count++; } - element._onGroupModify(GroupModifyFlags.All); + listeningEntities.length = count; } - static _onCanvasDirty(element: IElement, preCanvas: UICanvas, isGraphics: boolean = false): void { - if (element._isCanvasDirty) return; - element._isCanvasDirty = true; - if (preCanvas) { - const replaced = preCanvas._disorderedElements.deleteByIndex(element._indexInCanvas); - replaced && (replaced._indexInCanvas = element._indexInCanvas); - element._indexInCanvas = -1; - isGraphics && (preCanvas._hierarchyDirty = true); + private static _unRegisterListener(listener: (flag: number, param?: any) => void, listeningEntities: Entity[]): void { + for (let i = 0, n = listeningEntities.length; i < n; i++) { + // @ts-ignore + listeningEntities[i]._unRegisterModifyListener(listener); } + listeningEntities.length = 0; } } diff --git a/packages/ui/src/component/UICanvas.ts b/packages/ui/src/component/UICanvas.ts index bc297e7704..cbd8c12f68 100644 --- a/packages/ui/src/component/UICanvas.ts +++ b/packages/ui/src/component/UICanvas.ts @@ -2,7 +2,6 @@ import { Camera, CameraModifyFlags, Component, - ComponentType, DependentMode, DisorderedArray, Entity, @@ -20,12 +19,16 @@ import { Utils } from "../Utils"; import { CanvasRenderMode } from "../enums/CanvasRenderMode"; import { ResolutionAdaptationStrategy } from "../enums/ResolutionAdaptationStrategy"; import { IElement } from "../interface/IElement"; -import { IGraphics } from "../interface/IGraphics"; import { IGroupAble } from "../interface/IGroupAble"; import { UIGroup } from "./UIGroup"; import { UIRenderer } from "./UIRenderer"; import { UITransform } from "./UITransform"; +import { UIInteractive } from "./interactive/UIInteractive"; +/** + * The UI Canvas component serves as the root node for UI elements, + * handling rendering and events based on it. + */ @dependentComponents(UITransform, DependentMode.AutoAdd) export class UICanvas extends Component implements IElement { /** @internal */ @@ -33,36 +36,35 @@ export class UICanvas extends Component implements IElement { /** @internal */ @ignoreClone - _isRootCanvas: boolean = false; + _rootCanvas: UICanvas; /** @internal */ @ignoreClone - _canvasListeningEntities: Entity[] = []; + _indexInRootCanvas: number = -1; /** @internal */ @ignoreClone - _hierarchyDirty: boolean = false; + _isRootCanvasDirty: boolean = false; /** @internal */ @ignoreClone - _canvas: UICanvas; - /** @internal */ - _indexInCanvas: number = -1; + _rootCanvasListeningEntities: Entity[] = []; + /** @internal */ @ignoreClone - _renderElement; + _isRootCanvas: boolean = false; /** @internal */ @ignoreClone - _sortDistance: number = 0; + _renderElement: any; /** @internal */ @ignoreClone - _disorderedElements: DisorderedArray = new DisorderedArray(); + _sortDistance: number = 0; /** @internal */ @ignoreClone - _orderedGraphics: IGraphics[] = []; + _orderedRenderers: UIRenderer[] = []; /** @internal */ @ignoreClone _realRenderMode: number = CanvasRealRenderMode.None; /** @internal */ @ignoreClone - _isCanvasDirty: boolean = false; + _disorderedElements: DisorderedArray = new DisorderedArray(); @ignoreClone private _renderMode = CanvasRenderMode.WorldSpace; @@ -76,24 +78,26 @@ export class UICanvas extends Component implements IElement { private _sortOrder: number = 0; @ignoreClone private _distance: number = 10; - @ignoreClone - private _transform: UITransform; @deepClone private _referenceResolution: Vector2 = new Vector2(800, 600); @ignoreClone - private _pendingDestroy: boolean = false; + private _hierarchyVersion: number = -1; /** @internal */ - get elements(): IGraphics[] { - const elements = this._orderedGraphics; - if (this._hierarchyDirty) { - elements.length = this._walk(this.entity, elements); + get renderers(): UIRenderer[] { + const { _orderedRenderers: renderers, entity } = this; + const uiHierarchyVersion = entity._uiHierarchyVersion; + if (this._hierarchyVersion !== uiHierarchyVersion) { + renderers.length = this._walk(this.entity, renderers); UICanvas._tempGroupAbleList.length = 0; - this._hierarchyDirty = false; + this._hierarchyVersion = uiHierarchyVersion; } - return elements; + return renderers; } + /** + * The reference resolution of the UI canvas in `ScreenSpaceCamera` and `ScreenSpaceOverlay` mode. + */ get referenceResolution(): Vector2 { return this._referenceResolution; } @@ -104,6 +108,9 @@ export class UICanvas extends Component implements IElement { (referenceResolution.x !== val.x || referenceResolution.y !== val.y) && referenceResolution.copyFrom(val); } + /** + * The rendering mode of the UI canvas. + */ get renderMode(): CanvasRenderMode { return this._renderMode; } @@ -117,6 +124,10 @@ export class UICanvas extends Component implements IElement { } } + /** + * The camera used to render the UI canvas in `ScreenSpaceCamera` mode. + * @remarks If set `ScreenSpaceCamera` but no corresponding camera is assigned, the actual rendering mode defaults to `ScreenSpaceOverlay`. + */ get renderCamera(): Camera { return this._renderCamera; } @@ -130,6 +141,9 @@ export class UICanvas extends Component implements IElement { } } + /** + * The screen resolution adaptation strategy of the UI canvas in `ScreenSpaceCamera` and `ScreenSpaceOverlay` mode. + */ get resolutionAdaptationStrategy(): ResolutionAdaptationStrategy { return this._resolutionAdaptationStrategy; } @@ -147,6 +161,9 @@ export class UICanvas extends Component implements IElement { } } + /** + * The rendering order priority of the UI canvas in `ScreenSpaceOverlay` mode. + */ get sortOrder(): number { return this._sortOrder; } @@ -160,6 +177,9 @@ export class UICanvas extends Component implements IElement { } } + /** + * The distance between the UI canvas and the camera in `ScreenSpaceCamera` mode. + */ get distance(): number { return this._distance; } @@ -179,22 +199,19 @@ export class UICanvas extends Component implements IElement { */ constructor(entity: Entity) { super(entity); - // @ts-ignore - this._componentType = ComponentType.UICanvas; - this._transform = entity.transform; this._onCanvasSizeListener = this._onCanvasSizeListener.bind(this); this._onCameraModifyListener = this._onCameraModifyListener.bind(this); this._onCameraTransformListener = this._onCameraTransformListener.bind(this); this._onReferenceResolutionChanged = this._onReferenceResolutionChanged.bind(this); // @ts-ignore this._referenceResolution._onValueChanged = this._onReferenceResolutionChanged; - this._canvasListener = this._canvasListener.bind(this); + this._rootCanvasListener = this._rootCanvasListener.bind(this); } raycast(ray: Ray, out: HitResult, distance: number = Number.MAX_SAFE_INTEGER): boolean { - const { elements } = this; - for (let i = elements.length - 1; i >= 0; i--) { - const element = elements[i]; + const { renderers } = this; + for (let i = renderers.length - 1; i >= 0; i--) { + const element = renderers[i]; if (element.raycastEnable && element._raycast(ray, out, distance)) { return true; } @@ -210,15 +227,15 @@ export class UICanvas extends Component implements IElement { /** * @internal */ - _getCanvas(): UICanvas { - return this._canvas; + _getRootCanvas(): UICanvas { + return this._rootCanvas; } /** * @internal */ _prepareRender(context): void { - const { engine, elements, _realRenderMode: mode } = this; + const { engine, renderers, _realRenderMode: mode } = this; const { enableFrustumCulling, cullingMask, _frustum: frustum } = context.camera; const { frameCount } = engine.time; // @ts-ignore @@ -227,8 +244,8 @@ export class UICanvas extends Component implements IElement { renderElement.set(this.sortOrder, this._sortDistance); const { width, height } = engine.canvas; - for (let i = 0, n = elements.length; i < n; i++) { - const renderer = elements[i] as unknown as UIRenderer; + for (let i = 0, n = renderers.length; i < n; i++) { + const renderer = renderers[i]; // Filter by camera culling mask if (!(cullingMask & renderer.entity.layer)) { continue; @@ -269,7 +286,7 @@ export class UICanvas extends Component implements IElement { this._sortDistance = this._distance; break; case CanvasRenderMode.WorldSpace: - this._sortDistance = Vector3.distance(cameraPosition, this._transform.worldPosition); + this._sortDistance = Vector3.distance(cameraPosition, this.entity.transform.worldPosition); break; } } @@ -279,62 +296,43 @@ export class UICanvas extends Component implements IElement { const entity = this.entity; // @ts-ignore entity._dispatchModify(EntityUIModifyFlags.CanvasEnableInScene, this); - const rootCanvas = Utils.getRootCanvasInParents(entity); - if (rootCanvas) { - this._setIsRootCanvas(false); - Utils._registerElementToCanvas(this, null, rootCanvas); - } else { - this._setIsRootCanvas(true); - } - Utils._registerCanvasToCanvasListener(this, rootCanvas); + const rootCanvas = Utils.searchRootCanvasInParents(this); + this._setIsRootCanvas(!rootCanvas); + Utils.setRootCanvas(this, rootCanvas); } // @ts-ignore override _onDisableInScene(): void { - this._isRootCanvas && this._setIsRootCanvas(false); - Utils._unRegisterListener(this._canvasListener, this._canvasListeningEntities); + this._setIsRootCanvas(false); + Utils.cleanRootCanvas(this); } /** * @internal */ @ignoreClone - _canvasListener(flag: number, param: any): void { + _rootCanvasListener(flag: number, param: any): void { if (this._isRootCanvas) { if (flag === EntityModifyFlags.Parent) { - const rootCanvas = Utils.getRootCanvasInParents(this.entity); - if (rootCanvas) { - this._setIsRootCanvas(false); - Utils._registerElementToCanvas(this, null, rootCanvas); - } - Utils._registerCanvasToCanvasListener(this, rootCanvas); + const rootCanvas = Utils.searchRootCanvasInParents(this); + this._setIsRootCanvas(!rootCanvas); + Utils.setRootCanvas(this, rootCanvas); } else if (flag === EntityUIModifyFlags.CanvasEnableInScene) { this._setIsRootCanvas(false); - const rootCanvas = param as UICanvas; - Utils._registerElementToCanvas(this, null, rootCanvas); - Utils._registerCanvasToCanvasListener(this, rootCanvas); + Utils.setRootCanvas(this, param); } } else { if (flag === EntityModifyFlags.Parent) { - const rootCanvas = Utils.getRootCanvasInParents(this.entity); - if (rootCanvas) { - this._setIsRootCanvas(false); - Utils._registerElementToCanvas(this, this._canvas, rootCanvas); - } else { - this._setIsRootCanvas(true); - } - Utils._registerCanvasToCanvasListener(this, rootCanvas); + const rootCanvas = Utils.searchRootCanvasInParents(this); + this._setIsRootCanvas(!rootCanvas); + Utils.setRootCanvas(this, rootCanvas); } } } - protected override _onDestroy(): void { - this._pendingDestroy = true; - super._onDestroy(); - } - private _adapterPoseInScreenSpace(): void { - const { _transform: transform, _realRenderMode: realRenderMode } = this; + const transform = this.entity.transform; + const realRenderMode = this._realRenderMode; if (realRenderMode === CanvasRenderMode.ScreenSpaceCamera) { const { transform: cameraTransform } = this._renderCamera.entity; const { worldPosition: cameraWorldPosition, worldForward: cameraWorldForward } = cameraTransform; @@ -353,7 +351,8 @@ export class UICanvas extends Component implements IElement { } private _adapterSizeInScreenSpace(): void { - const { _transform: transform, _realRenderMode: realRenderMode } = this; + const transform = this.entity.transform; + const realRenderMode = this._realRenderMode; const { x: width, y: height } = this._referenceResolution; let curWidth: number; let curHeight: number; @@ -394,7 +393,7 @@ export class UICanvas extends Component implements IElement { transform.size.set(curWidth / expectX, curHeight / expectY); } - private _walk(entity: Entity, elements: IGraphics[], depth = 0, group: UIGroup = null): number { + private _walk(entity: Entity, renderers: UIRenderer[], depth = 0, group: UIGroup = null): number { // @ts-ignore const components: Component[] = entity._components; const tempGroupAbleList = UICanvas._tempGroupAbleList; @@ -402,41 +401,31 @@ export class UICanvas extends Component implements IElement { for (let i = 0, n = components.length; i < n; i++) { const component = components[i]; if (!component.enabled) continue; - // @ts-ignore - const componentType = component._componentType; - switch (componentType) { - case ComponentType.UIRenderer: - elements[depth] = component as unknown as IGraphics; - ++depth; - case ComponentType.UIInteractive: - if ((component as unknown as IGroupAble)._isGroupDirty) { - tempGroupAbleList[groupAbleCount++] = component as unknown as IGroupAble; - } - if ((component as unknown as IElement)._isCanvasDirty) { - Utils._registerElementToCanvas(component as unknown as IElement, null, this); - Utils._registerElementToCanvasListener(component as unknown as IElement, this); - (component as unknown as IElement)._isCanvasDirty = false; - } - break; - case ComponentType.UIGroup: - group = component as unknown as UIGroup; - break; - default: - break; + if (component instanceof UIRenderer) { + renderers[depth] = component; + ++depth; + component._isRootCanvasDirty && Utils.setRootCanvas(component, this); + if (component._isGroupDirty) { + tempGroupAbleList[groupAbleCount++] = component; + } + } else if (component instanceof UIInteractive) { + component._isRootCanvasDirty && Utils.setRootCanvas(component, this); + if (component._isGroupDirty) { + tempGroupAbleList[groupAbleCount++] = component; + } + } else if (component instanceof UIGroup) { + component._isRootCanvasDirty && Utils.setRootCanvas(component, this); + component._isGroupDirty && Utils.setGroup(component, group); + group = component; } } - if (groupAbleCount > 0) { - for (let i = 0; i < groupAbleCount; i++) { - const groupAble = tempGroupAbleList[i]; - Utils._registerElementToGroup(groupAble, null, group); - Utils._registerElementToGroupListener(groupAble, this); - groupAble._isGroupDirty = false; - } + for (let i = 0; i < groupAbleCount; i++) { + Utils.setGroup(tempGroupAbleList[i], group); } const children = entity.children; for (let i = 0, n = children.length; i < n; i++) { const child = children[i]; - child.isActive && (depth = this._walk(child, elements, depth)); + child.isActive && (depth = this._walk(child, renderers, depth, group)); } return depth; } @@ -466,7 +455,7 @@ export class UICanvas extends Component implements IElement { private _onCameraModifyListener(flag: CameraModifyFlags): void { if (this._realRenderMode === CanvasRenderMode.ScreenSpaceCamera) { switch (flag) { - case CameraModifyFlags.CameraType: + case CameraModifyFlags.ProjectionType: case CameraModifyFlags.AspectRatio: this._adapterSizeInScreenSpace(); break; @@ -505,7 +494,7 @@ export class UICanvas extends Component implements IElement { @ignoreClone private _onCanvasSizeListener(): void { const { canvas } = this.engine; - this._transform.setWorldPosition(canvas.width * 0.5, canvas.height * 0.5, 0); + this.entity.transform.setWorldPosition(canvas.width * 0.5, canvas.height * 0.5, 0); this._adapterSizeInScreenSpace(); } @@ -526,42 +515,22 @@ export class UICanvas extends Component implements IElement { this._updateCameraObserver(); this._setRealRenderMode(this._getRealRenderMode()); if (isRootCanvas) { - this._hierarchyDirty = true; + this.entity._updateUIHierarchyVersion(this.engine.time.frameCount); } else { const { _disorderedElements: disorderedElements } = this; - // Canvas is destroyed or disabled - if (this._pendingDestroy || !this.enabled) { - const root = this.entity; - disorderedElements.forEach((element: IElement) => { - // @ts-ignore - const componentType = (element as unknown as Component)._componentType; - if (componentType === ComponentType.UICanvas) { - const canvas = element as unknown as UICanvas; - const rootCanvas = Utils.getRootCanvasInParents(element.entity, root); - if (rootCanvas) { - canvas._setIsRootCanvas(false); - Utils._registerElementToCanvas(canvas, this, rootCanvas); - } else { - canvas._setIsRootCanvas(true); - Utils._registerElementToCanvas(canvas, this, null); - } - Utils._registerCanvasToCanvasListener(canvas, rootCanvas); - } else if (componentType === ComponentType.UIRenderer) { - Utils._onCanvasDirty(element, this, true); - } else { - Utils._onCanvasDirty(element, this); - } - }); - } else { - disorderedElements.forEach((element: IElement) => { - // @ts-ignore - const isGraphics = (element as unknown as Component)._componentType === ComponentType.UIRenderer; - Utils._onCanvasDirty(element, this, isGraphics); - }); - } + disorderedElements.forEach((element: IElement) => { + if (element instanceof UICanvas) { + const rootCanvas = Utils.searchRootCanvasInParents(element); + element._setIsRootCanvas(!rootCanvas); + Utils.setRootCanvas(element, rootCanvas); + } else { + Utils.setRootCanvasDirty(this); + Utils.setGroupDirty(element); + } + }); disorderedElements.length = 0; disorderedElements.garbageCollection(); - this._orderedGraphics.length = 0; + this._orderedRenderers.length = 0; } } } diff --git a/packages/ui/src/component/UIGroup.ts b/packages/ui/src/component/UIGroup.ts index 410ef2ce63..54bc8998fd 100644 --- a/packages/ui/src/component/UIGroup.ts +++ b/packages/ui/src/component/UIGroup.ts @@ -1,12 +1,4 @@ -import { - Component, - ComponentType, - DisorderedArray, - Entity, - EntityModifyFlags, - assignmentClone, - ignoreClone -} from "@galacean/engine"; +import { Component, DisorderedArray, Entity, EntityModifyFlags, assignmentClone, ignoreClone } from "@galacean/engine"; import { Utils } from "../Utils"; import { IGroupAble } from "../interface/IGroupAble"; import { EntityUIModifyFlags, UICanvas } from "./UICanvas"; @@ -17,16 +9,16 @@ export class UIGroup extends Component implements IGroupAble { _indexInGroup: number = -1; /** @internal */ @ignoreClone - _indexInCanvas: number = -1; + _indexInRootCanvas: number = -1; /** @internal */ @ignoreClone _group: UIGroup; /** @internal */ @ignoreClone - _canvas: UICanvas; + _rootCanvas: UICanvas; /** @internal */ @ignoreClone - _disorderedElements: DisorderedArray = new DisorderedArray(); + _disorderedElements: DisorderedArray = new DisorderedArray(); /** @internal */ @ignoreClone @@ -43,13 +35,13 @@ export class UIGroup extends Component implements IGroupAble { /** @internal */ @ignoreClone - _canvasListeningEntities: Entity[] = []; + _rootCanvasListeningEntities: Entity[] = []; /** @internal */ @ignoreClone _groupListeningEntities: Entity[] = []; /** @internal */ @ignoreClone - _isCanvasDirty: boolean = true; + _isRootCanvasDirty: boolean = true; /** @internal */ @ignoreClone _isGroupDirty: boolean = true; @@ -119,57 +111,44 @@ export class UIGroup extends Component implements IGroupAble { constructor(entity: Entity) { super(entity); - // @ts-ignore - this._componentType = ComponentType.UIGroup; - this._canvasListener = this._canvasListener.bind(this); + this._rootCanvasListener = this._rootCanvasListener.bind(this); this._groupListener = this._groupListener.bind(this); } // @ts-ignore override _onEnableInScene(): void { - Utils._onCanvasDirty(this, this._canvas); - Utils._onGroupDirty(this, this._group); + Utils.setRootCanvasDirty(this); + Utils.setGroupDirty(this); // @ts-ignore this.entity._dispatchModify(EntityUIModifyFlags.GroupEnableInScene); } // @ts-ignore override _onDisableInScene(): void { - Utils._unRegisterListener(this._groupListener, this._groupListeningEntities); - Utils._unRegisterListener(this._canvasListener, this._canvasListeningEntities); + Utils.cleanRootCanvas(this); + Utils.cleanGroup(this); const disorderedElements = this._disorderedElements; disorderedElements.forEach((element: IGroupAble) => { - Utils._onGroupDirty(element, this); + Utils.setGroupDirty(element); }); disorderedElements.length = 0; disorderedElements.garbageCollection(); - this._isCanvasDirty = this._isGroupDirty = false; + this._isRootCanvasDirty = this._isGroupDirty = false; } /** * @internal */ - _getCanvas(): UICanvas { - if (this._isCanvasDirty) { - const curCanvas = Utils.getRootCanvasInParents(this.entity); - Utils._registerElementToCanvas(this, this._canvas, curCanvas); - Utils._registerElementToCanvasListener(this, curCanvas); - this._isCanvasDirty = false; - } - return this._canvas; + _getRootCanvas(): UICanvas { + this._isRootCanvasDirty && Utils.setRootCanvas(this, Utils.searchRootCanvasInParents(this)); + return this._rootCanvas; } /** * @internal */ _getGroup(): UIGroup { - if (this._isGroupDirty) { - const canvas = this._getCanvas(); - const group = canvas ? Utils.getGroupInParents(this.entity.parent, canvas.entity) : null; - Utils._registerElementToGroup(this, this._group, group); - Utils._registerGroupToGroupListener(this, canvas); - this._isGroupDirty = false; - } + this._isGroupDirty && Utils.setGroup(this, Utils.searchGroupInParents(this)); return this._group; } @@ -180,7 +159,7 @@ export class UIGroup extends Component implements IGroupAble { _groupListener(flag: number): void { if (this._isGroupDirty) return; if (flag === EntityModifyFlags.Parent || flag === EntityUIModifyFlags.GroupEnableInScene) { - Utils._onGroupDirty(this, this._group); + Utils.setGroupDirty(this); } } @@ -188,11 +167,11 @@ export class UIGroup extends Component implements IGroupAble { * @internal */ @ignoreClone - _canvasListener(flag: number): void { - if (this._isCanvasDirty) return; + _rootCanvasListener(flag: number): void { + if (this._isRootCanvasDirty) return; if (flag === EntityModifyFlags.Parent || flag === EntityUIModifyFlags.CanvasEnableInScene) { - Utils._onCanvasDirty(this, this._canvas); - Utils._onGroupDirty(this, this._group); + Utils.setRootCanvasDirty(this); + Utils.setGroupDirty(this); } } diff --git a/packages/ui/src/component/UIRenderer.ts b/packages/ui/src/component/UIRenderer.ts index 4fdd4d43dc..f41933f8ae 100644 --- a/packages/ui/src/component/UIRenderer.ts +++ b/packages/ui/src/component/UIRenderer.ts @@ -1,7 +1,6 @@ import { BatchUtils, Color, - ComponentType, DependentMode, Entity, EntityModifyFlags, @@ -38,39 +37,39 @@ export abstract class UIRenderer extends Renderer implements IGraphics { /** @internal */ static _textureProperty: ShaderProperty = ShaderProperty.getByName("renderer_UITexture"); + /** + * Custom boundary for raycast detection. + * @remarks this is based on `this.entity.transform`. + */ @deepClone raycastPadding: Vector4 = new Vector4(0, 0, 0, 0); - - /** @internal */ - @ignoreClone - _group: UIGroup; /** @internal */ @ignoreClone - _indexInGroup: number = -1; + _rootCanvas: UICanvas; /** @internal */ @ignoreClone - _canvas: UICanvas; + _indexInRootCanvas: number = -1; /** @internal */ @ignoreClone - _indexInCanvas: number = -1; + _isRootCanvasDirty: boolean = false; /** @internal */ @ignoreClone - _subChunk; + _rootCanvasListeningEntities: Entity[] = []; /** @internal */ @ignoreClone - _isGroupDirty: boolean = false; + _group: UIGroup; /** @internal */ @ignoreClone - _isCanvasDirty: boolean = false; + _indexInGroup: number = -1; /** @internal */ @ignoreClone - _canvasListeningEntities: Entity[] = []; + _isGroupDirty: boolean = false; /** @internal */ @ignoreClone _groupListeningEntities: Entity[] = []; - /**@internal */ + /** @internal */ @ignoreClone - _onUIUpdateIndex: number = 0; + _subChunk; @ignoreClone private _raycastEnable: boolean = true; @@ -92,6 +91,9 @@ export abstract class UIRenderer extends Renderer implements IGraphics { } } + /** + * Whether this renderer be picked up by raycast. + */ get raycastEnable(): boolean { return this._raycastEnable; } @@ -105,14 +107,12 @@ export abstract class UIRenderer extends Renderer implements IGraphics { */ constructor(entity: Entity) { super(entity); - // @ts-ignore - this._componentType = ComponentType.UIRenderer; this._dirtyUpdateFlag = RendererUpdateFlags.AllBounds | UIRendererUpdateFlags.Color; this._onColorChange = this._onColorChange.bind(this); //@ts-ignore this._color._onValueChanged = this._onColorChange; this._groupListener = this._groupListener.bind(this); - this._canvasListener = this._canvasListener.bind(this); + this._rootCanvasListener = this._rootCanvasListener.bind(this); } // @ts-ignore @@ -154,43 +154,32 @@ export abstract class UIRenderer extends Renderer implements IGraphics { override _onEnableInScene(): void { // @ts-ignore this._overrideUpdate && this.scene._componentsManager.addOnUpdateRenderers(this); - Utils._onCanvasDirty(this, this._canvas, true); - Utils._onGroupDirty(this, this._group); + this.entity._updateUIHierarchyVersion(this.engine.time.frameCount); + Utils.setRootCanvasDirty(this); + Utils.setGroupDirty(this); } // @ts-ignore override _onDisableInScene(): void { // @ts-ignore this._overrideUpdate && this.scene._componentsManager.removeOnUpdateRenderers(this); - Utils._unRegisterListener(this._canvasListener, this._canvasListeningEntities); - Utils._unRegisterListener(this._groupListener, this._groupListeningEntities); - this._isCanvasDirty = this._isGroupDirty = false; + Utils.cleanRootCanvas(this); + Utils.cleanGroup(this); } /** * @internal */ - _getCanvas(): UICanvas { - if (this._isCanvasDirty) { - const curCanvas = Utils.getRootCanvasInParents(this.entity); - Utils._registerElementToCanvas(this, this._canvas, curCanvas); - Utils._registerElementToCanvasListener(this, curCanvas); - this._isCanvasDirty = false; - } - return this._canvas; + _getRootCanvas(): UICanvas { + this._isRootCanvasDirty && Utils.setRootCanvas(this, Utils.searchRootCanvasInParents(this)); + return this._rootCanvas; } /** * @internal */ _getGroup(): UIGroup { - if (this._isGroupDirty) { - const canvas = this._getCanvas(); - const group = canvas ? Utils.getGroupInParents(this.entity, canvas.entity) : null; - Utils._registerElementToGroup(this, this._group, group); - Utils._registerElementToGroupListener(this, canvas); - this._isGroupDirty = false; - } + this._isGroupDirty && Utils.setGroup(this, Utils.searchGroupInParents(this)); return this._group; } @@ -201,7 +190,7 @@ export abstract class UIRenderer extends Renderer implements IGraphics { _groupListener(flag: number): void { if (this._isGroupDirty) return; if (flag === EntityModifyFlags.Parent || flag === EntityUIModifyFlags.GroupEnableInScene) { - Utils._onGroupDirty(this, this._group); + Utils.setGroupDirty(this); } } @@ -209,14 +198,17 @@ export abstract class UIRenderer extends Renderer implements IGraphics { * @internal */ @ignoreClone - _canvasListener(flag: number): void { - if (this._isCanvasDirty) return; - if (flag === EntityModifyFlags.SiblingIndex) { - const rootCanvas = this._getCanvas(); - rootCanvas && (rootCanvas._hierarchyDirty = true); - } else if (flag === EntityModifyFlags.Parent || flag === EntityUIModifyFlags.CanvasEnableInScene) { - Utils._onCanvasDirty(this, this._canvas, true); - Utils._onGroupDirty(this, this._group); + _rootCanvasListener(flag: number, entity: Entity): void { + if (this._isRootCanvasDirty) return; + switch (flag) { + case EntityModifyFlags.Parent: + Utils.setRootCanvasDirty(this); + Utils.setGroupDirty(this); + case EntityModifyFlags.SiblingIndex: + entity._updateUIHierarchyVersion(this.engine.time.frameCount); + break; + default: + break; } } diff --git a/packages/ui/src/component/UITransform.ts b/packages/ui/src/component/UITransform.ts index 40cfb623a2..4194d4e646 100644 --- a/packages/ui/src/component/UITransform.ts +++ b/packages/ui/src/component/UITransform.ts @@ -1,11 +1,17 @@ import { Entity, Transform, Vector2, deepClone, ignoreClone } from "@galacean/engine"; +/** + * The Transform component exclusive to the UI element. + */ export class UITransform extends Transform { @deepClone private _size: Vector2 = new Vector2(100, 100); @deepClone private _pivot: Vector2 = new Vector2(0.5, 0.5); + /** + * Width and height of UI element. + */ get size(): Vector2 { return this._size; } @@ -16,6 +22,9 @@ export class UITransform extends Transform { (size.x !== val.x || size.y !== val.y) && size.copyFrom(val); } + /** + * Pivot of UI element. + */ get pivot(): Vector2 { return this._pivot; } @@ -26,6 +35,9 @@ export class UITransform extends Transform { (pivot.x !== val.x || pivot.y !== val.y) && pivot.copyFrom(val); } + /** + * @internal + */ constructor(entity: Entity) { super(entity); // @ts-ignore diff --git a/packages/ui/src/component/advanced/Image.ts b/packages/ui/src/component/advanced/Image.ts index 678965e80f..47ac36440c 100644 --- a/packages/ui/src/component/advanced/Image.ts +++ b/packages/ui/src/component/advanced/Image.ts @@ -22,6 +22,9 @@ import { CanvasRenderMode } from "../../enums/CanvasRenderMode"; import { UIRenderer, UIRendererUpdateFlags } from "../UIRenderer"; import { UITransform, UITransformModifyFlags } from "../UITransform"; +/** + * UI element that renders an image. + */ export class Image extends UIRenderer implements ISpriteRenderer { private static _tempVec2: Vector2 = new Vector2(); private static _tempUnit8Array: Uint8ClampedArray = new Uint8ClampedArray(4); @@ -39,6 +42,11 @@ export class Image extends UIRenderer implements ISpriteRenderer { @assignmentClone private _alphaHitTestMinimumThreshold: number = 0.0; + /** + * When this value is greater than 0, raycast will perform pixel-level detection; + * otherwise, it will only check the rectangular area of the UI element. + * @remarks enabling this will decrease performance. + */ get alphaHitTestMinimumThreshold(): number { return this._alphaHitTestMinimumThreshold; } @@ -48,7 +56,7 @@ export class Image extends UIRenderer implements ISpriteRenderer { } /** - * The draw mode of the sprite renderer. + * The draw mode of the image. */ get drawMode(): SpriteDrawMode { return this._drawMode; @@ -76,7 +84,7 @@ export class Image extends UIRenderer implements ISpriteRenderer { } /** - * The tiling mode of the sprite renderer. (Only works in tiled mode.) + * The tiling mode of the image. (Only works in tiled mode.) */ get tileMode(): SpriteTileMode { return this._tileMode; @@ -245,7 +253,7 @@ export class Image extends UIRenderer implements ISpriteRenderer { this._dirtyUpdateFlag = dirtyUpdateFlag; // Init sub render element. const { engine } = context.camera; - const canvas = this._getCanvas(); + const canvas = this._getRootCanvas(); const subRenderElement = engine._subRenderElementPool.get(); const subChunk = this._subChunk; subRenderElement.set(this, material, subChunk.chunk.primitive, subChunk.subMesh, this.sprite.texture, subChunk); diff --git a/packages/ui/src/component/advanced/Label.ts b/packages/ui/src/component/advanced/Label.ts index 8174974dde..e43a4fe864 100644 --- a/packages/ui/src/component/advanced/Label.ts +++ b/packages/ui/src/component/advanced/Label.ts @@ -24,6 +24,9 @@ import { CanvasRenderMode } from "../../enums/CanvasRenderMode"; import { UIRenderer, UIRendererUpdateFlags } from "../UIRenderer"; import { UITransform, UITransformModifyFlags } from "../UITransform"; +/** + * UI component used to render text. + */ export class Label extends UIRenderer implements ITextRenderer { private static _textTextureProperty = ShaderProperty.getByName("renderElement_TextTexture"); private static _worldPositions = [new Vector3(), new Vector3(), new Vector3(), new Vector3()]; @@ -293,7 +296,7 @@ export class Label extends UIRenderer implements ITextRenderer { const engine = context.camera.engine; const textSubRenderElementPool = engine._textSubRenderElementPool; const material = this.getMaterial(); - const canvas = this._getCanvas(); + const canvas = this._getRootCanvas(); const renderElement = canvas._renderElement; const textChunks = this._textChunks; const isOverlay = canvas._realRenderMode === CanvasRenderMode.ScreenSpaceOverlay; diff --git a/packages/ui/src/component/interactive/UIInteractive.ts b/packages/ui/src/component/interactive/UIInteractive.ts index d420c158d7..388d779c00 100644 --- a/packages/ui/src/component/interactive/UIInteractive.ts +++ b/packages/ui/src/component/interactive/UIInteractive.ts @@ -6,34 +6,35 @@ import { EntityUIModifyFlags, UICanvas } from "../UICanvas"; import { GroupModifyFlags } from "../UIGroup"; import { Transition } from "./transition/Transition"; +/** + * Interactive component. + */ export class UIInteractive extends Script implements IGroupAble { /** @internal */ @ignoreClone - _canvas: UICanvas; + _rootCanvas: UICanvas; /** @internal */ @ignoreClone - _indexInCanvas: number = -1; + _indexInRootCanvas: number = -1; /** @internal */ @ignoreClone - _group: UIGroup; + _isRootCanvasDirty: boolean = false; /** @internal */ @ignoreClone - _indexInGroup: number = -1; + _rootCanvasListeningEntities: Entity[] = []; /** @internal */ @ignoreClone - _canvasListeningEntities: Entity[] = []; + _group: UIGroup; /** @internal */ @ignoreClone - _groupListeningEntities: Entity[] = []; - /**@internal */ - @ignoreClone - _onUIUpdateIndex: number = 0; + _indexInGroup: number = -1; /** @internal */ @ignoreClone _isGroupDirty: boolean = false; /** @internal */ @ignoreClone - _isCanvasDirty: boolean = false; + _groupListeningEntities: Entity[] = []; + /** @internal */ @ignoreClone _globalInteractive: boolean = false; @@ -49,6 +50,9 @@ export class UIInteractive extends Script implements IGroupAble { private _isPointerInside: boolean = false; private _isPointerDragging: boolean = false; + /** + * Whether the interactive is enabled. + */ get interactive() { return this._interactive; } @@ -60,17 +64,29 @@ export class UIInteractive extends Script implements IGroupAble { } } + /** + * Whether the interactive is enabled globally. + * @remarks The global interactive is determined by the interactive of itself and its group. + */ get globalInteractive(): boolean { this._updateGlobalInteractive(); return this._globalInteractive; } + /** + * @internal + */ constructor(entity: Entity) { super(entity); this._groupListener = this._groupListener.bind(this); - this._canvasListener = this._canvasListener.bind(this); + this._rootCanvasListener = this._rootCanvasListener.bind(this); } + /** + * Get transition which match the type. + * @param type - The type of the transition + * @returns Transitions which match type + */ getTransitions(type: new (interactive: UIInteractive) => T, results: T[]): T[] { results.length = 0; const transitions = this._transitions; @@ -83,6 +99,11 @@ export class UIInteractive extends Script implements IGroupAble { return results; } + /** + * Get transition which match the type. + * @param type - The type of the transition + * @returns The first transition which match type + */ getTransition(type: new (interactive: UIInteractive) => T): T | null { const transitions = this._transitions; for (let i = 0, n = transitions.length; i < n; i++) { @@ -94,6 +115,11 @@ export class UIInteractive extends Script implements IGroupAble { return null; } + /** + * Add transition based on the transition type. + * @param type - The type of the transition + * @returns The transition which has been added + */ addTransition Transition>(type: T): InstanceType { const transition = new type(this) as InstanceType; this._transitions.push(transition); @@ -130,12 +156,28 @@ export class UIInteractive extends Script implements IGroupAble { this._transitions.forEach((transition) => transition.destroy()); } + /** + * @internal + */ + _getRootCanvas(): UICanvas { + this._isRootCanvasDirty && Utils.setRootCanvas(this, Utils.searchRootCanvasInParents(this)); + return this._rootCanvas; + } + + /** + * @internal + */ + _getGroup(): UIGroup { + this._isGroupDirty && Utils.setGroup(this, Utils.searchGroupInParents(this)); + return this._group; + } + // @ts-ignore override _onEnableInScene(): void { // @ts-ignore super._onEnableInScene(); - Utils._onCanvasDirty(this, this._canvas); - Utils._onGroupDirty(this, this._group); + Utils.setRootCanvasDirty(this); + Utils.setGroupDirty(this); this._updateState(true); } @@ -143,37 +185,9 @@ export class UIInteractive extends Script implements IGroupAble { override _onDisableInScene(): void { // @ts-ignore super._onDisableInScene(); - Utils._unRegisterListener(this._canvasListener, this._canvasListeningEntities); - Utils._unRegisterListener(this._groupListener, this._groupListeningEntities); + Utils.cleanRootCanvas(this); + Utils.cleanGroup(this); this._isPointerInside = this._isPointerDragging = false; - this._isCanvasDirty = this._isGroupDirty = false; - } - - /** - * @internal - */ - _getCanvas(): UICanvas { - if (this._isCanvasDirty) { - const curCanvas = Utils.getRootCanvasInParents(this.entity); - Utils._registerElementToCanvas(this, this._canvas, curCanvas); - Utils._registerElementToCanvasListener(this, curCanvas); - this._isCanvasDirty = false; - } - return this._canvas; - } - - /** - * @internal - */ - _getGroup(): UIGroup { - if (this._isGroupDirty) { - const canvas = this._getCanvas(); - const group = canvas ? Utils.getGroupInParents(this.entity, canvas.entity) : null; - Utils._registerElementToGroup(this, this._group, group); - Utils._registerElementToGroupListener(this, canvas); - this._isGroupDirty = false; - } - return this._group; } /** @@ -196,7 +210,7 @@ export class UIInteractive extends Script implements IGroupAble { _groupListener(flag: number): void { if (this._isGroupDirty) return; if (flag === EntityModifyFlags.Parent || flag === EntityUIModifyFlags.GroupEnableInScene) { - Utils._onGroupDirty(this, this._group); + Utils.setGroupDirty(this); } } @@ -204,11 +218,11 @@ export class UIInteractive extends Script implements IGroupAble { * @internal */ @ignoreClone - _canvasListener(flag: number): void { - if (this._isCanvasDirty) return; + _rootCanvasListener(flag: number): void { + if (this._isRootCanvasDirty) return; if (flag === EntityModifyFlags.Parent || flag === EntityUIModifyFlags.CanvasEnableInScene) { - Utils._onCanvasDirty(this, this._canvas); - Utils._onGroupDirty(this, this._group); + Utils.setRootCanvasDirty(this); + Utils.setGroupDirty(this); } } diff --git a/packages/ui/src/component/interactive/transition/ColorTransition.ts b/packages/ui/src/component/interactive/transition/ColorTransition.ts index 4641cc42a7..ad8c7aa314 100644 --- a/packages/ui/src/component/interactive/transition/ColorTransition.ts +++ b/packages/ui/src/component/interactive/transition/ColorTransition.ts @@ -3,6 +3,9 @@ import { UIRenderer } from "../../UIRenderer"; import { Transition } from "./Transition"; import { InteractiveState, UIInteractive } from "../UIInteractive"; +/** + * Color transition. + */ export class ColorTransition extends Transition { private _color: Color = new Color(); constructor(interactive: UIInteractive) { diff --git a/packages/ui/src/component/interactive/transition/ScaleTransition.ts b/packages/ui/src/component/interactive/transition/ScaleTransition.ts index 5bc4995bca..947816b8f9 100644 --- a/packages/ui/src/component/interactive/transition/ScaleTransition.ts +++ b/packages/ui/src/component/interactive/transition/ScaleTransition.ts @@ -2,6 +2,9 @@ import { UIRenderer } from "../../UIRenderer"; import { UIInteractive } from "../UIInteractive"; import { Transition } from "./Transition"; +/** + * Scale transition. + */ export class ScaleTransition extends Transition { constructor(interactive: UIInteractive) { super(interactive); diff --git a/packages/ui/src/component/interactive/transition/SpriteTransition.ts b/packages/ui/src/component/interactive/transition/SpriteTransition.ts index 6deaaf7787..35e9d420ed 100644 --- a/packages/ui/src/component/interactive/transition/SpriteTransition.ts +++ b/packages/ui/src/component/interactive/transition/SpriteTransition.ts @@ -2,6 +2,9 @@ import { Sprite } from "@galacean/engine"; import { Image } from "../../advanced/Image"; import { Transition } from "./Transition"; +/** + * Sprite transition. + */ export class SpriteTransition extends Transition { /** * @internal diff --git a/packages/ui/src/component/interactive/transition/Transition.ts b/packages/ui/src/component/interactive/transition/Transition.ts index a4e84e907b..b45fd56c9a 100644 --- a/packages/ui/src/component/interactive/transition/Transition.ts +++ b/packages/ui/src/component/interactive/transition/Transition.ts @@ -2,6 +2,9 @@ import { Color, ReferResource, Sprite } from "@galacean/engine"; import { UIRenderer } from "../../UIRenderer"; import { InteractiveState, UIInteractive } from "../UIInteractive"; +/** + * The transition behavior of UIInteractive. + */ export abstract class Transition< T extends TransitionValueType = TransitionValueType, K extends UIRenderer = UIRenderer @@ -18,6 +21,9 @@ export abstract class Transition< protected _currentValue: T; protected _finalState: InteractiveState = InteractiveState.Normal; + /** + * The normal state of the transition. + */ get normal(): T { return this._normal; } @@ -30,6 +36,9 @@ export abstract class Transition< } } + /** + * The pressed state of the transition. + */ get pressed(): T { return this._pressed; } @@ -42,6 +51,9 @@ export abstract class Transition< } } + /** + * The hover state of the transition. + */ get hover(): T { return this._hover; } @@ -54,6 +66,9 @@ export abstract class Transition< } } + /** + * The disabled state of the transition. + */ get disabled(): T { return this._disabled; } @@ -66,6 +81,9 @@ export abstract class Transition< } } + /** + * The target of the transition. + */ get target(): K { return this._target; } @@ -77,6 +95,9 @@ export abstract class Transition< } } + /** + * The duration of the transition. + */ get duration(): number { return this._duration; } diff --git a/packages/ui/src/enums/CanvasRenderMode.ts b/packages/ui/src/enums/CanvasRenderMode.ts index 79e7f44fb6..4379d355d2 100644 --- a/packages/ui/src/enums/CanvasRenderMode.ts +++ b/packages/ui/src/enums/CanvasRenderMode.ts @@ -2,7 +2,21 @@ * Render mode for ui canvas. */ export enum CanvasRenderMode { + /** + * The UI canvas will be rendered directly onto the screen and adapted to screen space, + * overlaying other rendering elements in the same scene. + * @remarks if the `engine.canvas` size change, the UI canvas will automatically adapt. + */ ScreenSpaceOverlay = 0, + /** + * The UI canvas is placed at a specified distance in front of the camera and adapted to screen space, + * with all objects rendered by the camera. + * @remarks if the camera's properties or the `engine.canvas` size change, the UI canvas will automatically adapt. + * @remarks if set `ScreenSpaceCamera` but no corresponding camera is assigned, the actual rendering mode defaults to `ScreenSpaceOverlay`. + */ ScreenSpaceCamera = 1, + /** + * The UI canvas is placed in the 3D world space and rendered by every camera in the same scene. + */ WorldSpace = 2 } diff --git a/packages/ui/src/enums/ResolutionAdaptationStrategy.ts b/packages/ui/src/enums/ResolutionAdaptationStrategy.ts index 68c36fe8ae..2758456707 100644 --- a/packages/ui/src/enums/ResolutionAdaptationStrategy.ts +++ b/packages/ui/src/enums/ResolutionAdaptationStrategy.ts @@ -1,10 +1,16 @@ /** * Resolution adaptation strategy. + * @remarks Only effective in screen space. */ export enum ResolutionAdaptationStrategy { + /** Adapt based on width.(`referenceResolution.x`) */ WidthAdaptation, + /** Adapt based on height.(`referenceResolution.y`) */ HeightAdaptation, + /** Adapt based on both width and height.(`referenceResolution`) */ BothAdaptation, + /** Adapt to the side with a larger ratio. */ ExpandAdaptation, + /** Adapt to the side with smaller ratio. */ ShrinkAdaptation } diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts index 3e606365a8..480067c46e 100644 --- a/packages/ui/src/index.ts +++ b/packages/ui/src/index.ts @@ -1,3 +1,4 @@ +import { Entity } from "@galacean/engine"; export { UICanvas } from "./component/UICanvas"; export { UIGroup } from "./component/UIGroup"; export { UIRenderer } from "./component/UIRenderer"; @@ -12,3 +13,37 @@ export { Transition } from "./component/interactive/transition/Transition"; export { CanvasRenderMode } from "./enums/CanvasRenderMode"; export { ResolutionAdaptationStrategy } from "./enums/ResolutionAdaptationStrategy"; export { UIPointerEventEmitter } from "./input/UIPointerEventEmitter"; + +export class EntityExtension { + _uiHierarchyVersion = 0; + _updateUIHierarchyVersion(version: number): void { + if (this._uiHierarchyVersion !== version) { + this._uiHierarchyVersion = version; + // @ts-ignore + this.parent?._updateUIHierarchyVersion(version); + } + } +} + +declare module "@galacean/engine" { + interface Entity { + // @internal + _uiHierarchyVersion: number; + // @internal + _updateUIHierarchyVersion(version: number): void; + } +} + +function ApplyMixins(derivedCtor: any, baseCtors: any[]): void { + baseCtors.forEach((baseCtor) => { + Object.getOwnPropertyNames(baseCtor.prototype).forEach((name) => { + Object.defineProperty( + derivedCtor.prototype, + name, + Object.getOwnPropertyDescriptor(baseCtor.prototype, name) || Object.create(null) + ); + }); + }); +} + +ApplyMixins(Entity, [EntityExtension]); diff --git a/packages/ui/src/input/UIPointerEventEmitter.ts b/packages/ui/src/input/UIPointerEventEmitter.ts index 4764557728..4d87b75a2f 100644 --- a/packages/ui/src/input/UIPointerEventEmitter.ts +++ b/packages/ui/src/input/UIPointerEventEmitter.ts @@ -1,7 +1,5 @@ import { CameraClearFlags, - Component, - ComponentType, Entity, Pointer, PointerEventData, @@ -11,7 +9,7 @@ import { Script, registerPointerEventEmitter } from "@galacean/engine"; -import { IGraphics } from "../interface/IGraphics"; +import { UIRenderer } from "../component/UIRenderer"; @registerPointerEventEmitter() export class UIPointerEventEmitter extends PointerEventEmitter { @@ -19,9 +17,9 @@ export class UIPointerEventEmitter extends PointerEventEmitter { private static _path0: Entity[] = []; private static _path1: Entity[] = []; - private _enteredElement: Component; - private _pressedElement: Component; - private _draggedElement: Component; + private _enteredElement: UIRenderer; + private _pressedElement: UIRenderer; + private _draggedElement: UIRenderer; override processRaycast(scenes: readonly Scene[], pointer: Pointer): void { const { _tempRay: ray } = PointerEventEmitter; @@ -39,7 +37,7 @@ export class UIPointerEventEmitter extends PointerEventEmitter { ray.direction.set(0, 0, -1); for (let j = canvasElements.length - 1; j >= 0; j--) { if (canvasElements.get(j).raycast(ray, hitResult)) { - this._updateRaycast(hitResult.component, pointer); + this._updateRaycast(hitResult.component, pointer); return; } } @@ -76,7 +74,7 @@ export class UIPointerEventEmitter extends PointerEventEmitter { const canvas = canvasElements.get(k); if (canvas.renderCamera !== camera) continue; if (canvas.raycast(ray, hitResult, farClipPlane)) { - this._updateRaycast(hitResult.component, pointer); + this._updateRaycast(hitResult.component, pointer); return; } } @@ -165,7 +163,7 @@ export class UIPointerEventEmitter extends PointerEventEmitter { this._enteredElement = this._pressedElement = this._draggedElement = null; } - private _updateRaycast(element: Component, pointer: Pointer = null): void { + private _updateRaycast(element: UIRenderer, pointer: Pointer = null): void { const enteredElement = this._enteredElement; if (element !== enteredElement) { let prePath = this._composedPath(enteredElement, UIPointerEventEmitter._path0); @@ -213,22 +211,16 @@ export class UIPointerEventEmitter extends PointerEventEmitter { ); } - private _composedPath(element: Component, path: Entity[]): Entity[] { + private _composedPath(element: UIRenderer, path: Entity[]): Entity[] { if (!element) { path.length = 0; return path; } let entity = (path[0] = element.entity); let i = 1; - // @ts-ignore - if (element._componentType === ComponentType.UICanvas && element._isRootCanvas) { - path.length = 1; - return path; - } else { - const rootEntity = (element as unknown as IGraphics)._getCanvas().entity; - for (; i < UIPointerEventEmitter._MAX_PATH_DEPTH && !!entity && entity !== rootEntity; i++) { - entity = path[i] = entity.parent; - } + const rootEntity = element._getRootCanvas().entity; + for (; i < UIPointerEventEmitter._MAX_PATH_DEPTH && !!entity && entity !== rootEntity; i++) { + entity = path[i] = entity.parent; } path.length = i; return path; diff --git a/packages/ui/src/interface/IElement.ts b/packages/ui/src/interface/IElement.ts index d8868b6862..eac1adcac5 100644 --- a/packages/ui/src/interface/IElement.ts +++ b/packages/ui/src/interface/IElement.ts @@ -1,12 +1,13 @@ import { Entity } from "@galacean/engine"; -import { UICanvas } from "../component/UICanvas"; +import { UICanvas } from ".."; export interface IElement { entity: Entity; - _indexInCanvas: number; - _isCanvasDirty: boolean; - _canvasListeningEntities: Entity[]; + _rootCanvas: UICanvas; + _indexInRootCanvas: number; + _rootCanvasListeningEntities: Entity[]; + _isRootCanvasDirty: boolean; - _getCanvas(): UICanvas; - _canvasListener: (flag: number, param?: any) => void; + _getRootCanvas(): UICanvas; + _rootCanvasListener: (flag: number, param?: any) => void; } diff --git a/packages/ui/src/interface/IGroupAble.ts b/packages/ui/src/interface/IGroupAble.ts index de6fe00155..0e6bfd2923 100644 --- a/packages/ui/src/interface/IGroupAble.ts +++ b/packages/ui/src/interface/IGroupAble.ts @@ -3,13 +3,15 @@ import { GroupModifyFlags, UIGroup } from "../component/UIGroup"; import { IElement } from "./IElement"; export interface IGroupAble extends IElement { + _group: UIGroup; _indexInGroup: number; _groupListeningEntities: Entity[]; _isGroupDirty: boolean; + _globalAlpha?: number; _globalInteractive?: boolean; _getGroup(): UIGroup; _onGroupModify(flag: GroupModifyFlags, isPass?: boolean): void; - _groupListener: (flag: number) => void; + _groupListener(flag: number): void; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 01ce2c16d7..ca35d5c840 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -46,7 +46,7 @@ importers: version: 6.21.0(eslint@8.57.1)(typescript@5.6.3) '@vitest/coverage-v8': specifier: 2.1.3 - version: 2.1.3(@vitest/browser@2.1.3)(vitest@2.1.3) + version: 2.1.3(@vitest/browser@2.1.3(@types/node@18.19.64)(@vitest/spy@2.1.3)(playwright@1.48.2)(typescript@5.6.3)(vite@5.4.11(@types/node@18.19.64)(sass@1.81.0))(vitest@2.1.3))(vitest@2.1.3(@types/node@18.19.64)(@vitest/browser@2.1.3)(msw@2.6.5(@types/node@18.19.64)(typescript@5.6.3))(sass@1.81.0)) bumpp: specifier: ^9.5.2 version: 9.8.1(magicast@0.3.5) @@ -247,7 +247,13 @@ importers: specifier: workspace:* version: link:../design - packages/ui + packages/shader-shaderlab: + devDependencies: + '@galacean/engine': + specifier: workspace:* + version: link:../galacean + + packages/ui: devDependencies: '@galacean/engine': specifier: workspace:* @@ -5344,7 +5350,7 @@ snapshots: - utf-8-validate - vite - '@vitest/coverage-v8@2.1.3(@vitest/browser@2.1.3)(vitest@2.1.3)': + '@vitest/coverage-v8@2.1.3(@vitest/browser@2.1.3(@types/node@18.19.64)(@vitest/spy@2.1.3)(playwright@1.48.2)(typescript@5.6.3)(vite@5.4.11(@types/node@18.19.64)(sass@1.81.0))(vitest@2.1.3))(vitest@2.1.3(@types/node@18.19.64)(@vitest/browser@2.1.3)(msw@2.6.5(@types/node@18.19.64)(typescript@5.6.3))(sass@1.81.0))': dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 0.2.3 diff --git a/tests/src/core/SkinnedMeshRenderer.test.ts b/tests/src/core/SkinnedMeshRenderer.test.ts index 4f6c04cec2..f92eab1595 100644 --- a/tests/src/core/SkinnedMeshRenderer.test.ts +++ b/tests/src/core/SkinnedMeshRenderer.test.ts @@ -1,7 +1,7 @@ import { BlendShape, Entity, ModelMesh, Skin, SkinnedMeshRenderer } from "@galacean/engine-core"; -import { BoundingBox, Matrix, Vector3 } from "@galacean/engine-math"; +import { Matrix, Vector3 } from "@galacean/engine-math"; import { WebGLEngine } from "@galacean/engine-rhi-webgl"; -import { describe, beforeAll, expect, it } from "vitest"; +import { beforeAll, describe, expect, it } from "vitest"; describe("SkinnedMeshRenderer", async () => { let engine: WebGLEngine; diff --git a/tests/src/core/SpriteMask.test.ts b/tests/src/core/SpriteMask.test.ts index 27d0ea3487..63961f3205 100644 --- a/tests/src/core/SpriteMask.test.ts +++ b/tests/src/core/SpriteMask.test.ts @@ -1,7 +1,7 @@ import { Sprite, SpriteMask, SpriteMaskLayer, Texture2D } from "@galacean/engine-core"; import { Rect, Vector2, Vector3, Vector4 } from "@galacean/engine-math"; import { WebGLEngine } from "@galacean/engine-rhi-webgl"; -import { describe, beforeEach, expect, it } from "vitest"; +import { beforeEach, describe, expect, it } from "vitest"; describe("SpriteMask", async () => { const canvas = document.createElement("canvas"); @@ -118,34 +118,34 @@ describe("SpriteMask", async () => { expect(spriteMask.shaderData.getTexture(property)).to.eq(texture2d); // @ts-ignore - spriteMask._dirtyUpdateFlag &= ~0x5; + spriteMask._dirtyUpdateFlag &= ~SpriteMaskUpdateFlags.AllPositionAndBounds; sprite.width = 10; // @ts-ignore - expect(!!(spriteMask._dirtyUpdateFlag & 0x5)).to.eq(true); + expect(!!(spriteMask._dirtyUpdateFlag & SpriteMaskUpdateFlags.AllPositionAndBounds)).to.eq(true); // @ts-ignore - spriteMask._dirtyUpdateFlag &= ~0x3; + spriteMask._dirtyUpdateFlag &= ~SpriteMaskUpdateFlags.AllPositionAndUV; sprite.region = new Rect(); // @ts-ignore - expect(!!(spriteMask._dirtyUpdateFlag & 0x3)).to.eq(true); + expect(!!(spriteMask._dirtyUpdateFlag & SpriteMaskUpdateFlags.AllPositionAndUV)).to.eq(true); // @ts-ignore - spriteMask._dirtyUpdateFlag &= ~0x3; + spriteMask._dirtyUpdateFlag &= ~SpriteMaskUpdateFlags.AllPositionAndUV; sprite.atlasRegionOffset = new Vector4(); // @ts-ignore - expect(!!(spriteMask._dirtyUpdateFlag & 0x3)).to.eq(true); + expect(!!(spriteMask._dirtyUpdateFlag & SpriteMaskUpdateFlags.AllPositionAndUV)).to.eq(true); // @ts-ignore - spriteMask._dirtyUpdateFlag &= ~0x2; + spriteMask._dirtyUpdateFlag &= ~SpriteMaskUpdateFlags.UV; sprite.atlasRegion = new Rect(); // @ts-ignore - expect(!!(spriteMask._dirtyUpdateFlag & 0x2)).to.eq(true); + expect(!!(spriteMask._dirtyUpdateFlag & SpriteMaskUpdateFlags.UV)).to.eq(true); // @ts-ignore - spriteMask._dirtyUpdateFlag &= ~0x1; + spriteMask._dirtyUpdateFlag &= ~SpriteMaskUpdateFlags.AllPositionAndBounds; sprite.pivot = new Vector2(0.3, 0.2); // @ts-ignore - expect(!!(spriteMask._dirtyUpdateFlag & 0x1)).to.eq(true); + expect(!!(spriteMask._dirtyUpdateFlag & SpriteMaskUpdateFlags.AllPositionAndBounds)).to.eq(true); }); it("clone", () => { @@ -222,3 +222,31 @@ describe("SpriteMask", async () => { expect(spriteMask.bounds.max).to.deep.eq(new Vector3(0.5, 1, 0)); }); }); + +/** + * @remarks Extends `RendererUpdateFlags`. + */ +enum SpriteMaskUpdateFlags { + None = 0x0, + LocalPosition = 0x1, + WorldPosition = 0x2, + LocalBounds = 0x4, + WorldBounds = 0x8, + UV = 0x10, + AutomaticSize = 0x20, + + /** LocalPosition | WorldPosition */ + AllPositions = 0x3, + /** LocalPosition | LocalBounds */ + LocalPositionAndBounds = 0x5, + /** WorldPosition | WorldBounds */ + WorldPositionAndBounds = 0xa, + /** LocalBounds | WorldBounds */ + AllBounds = 0xc, + /** LocalPosition | WorldPosition | LocalBounds | WorldBounds */ + AllPositionAndBounds = 0xf, + /** LocalPosition | WorldPosition | UV */ + AllPositionAndUV = 0x13, + /** LocalPosition | WorldPosition | UV | LocalBounds | WorldBounds */ + All = 0x3f +} diff --git a/tests/src/core/SpriteRenderer.test.ts b/tests/src/core/SpriteRenderer.test.ts index 2877946f57..09e7cebcdf 100644 --- a/tests/src/core/SpriteRenderer.test.ts +++ b/tests/src/core/SpriteRenderer.test.ts @@ -1446,54 +1446,54 @@ describe("SpriteRenderer", async () => { expect(spriteRenderer.shaderData.getTexture(property)).to.eq(texture2d); // @ts-ignore - spriteRenderer._dirtyUpdateFlag &= ~0x5; + spriteRenderer._dirtyUpdateFlag &= ~SpriteRendererUpdateFlags.AllPositionAndBounds; sprite.width = 10; // @ts-ignore - expect(!!(spriteRenderer._dirtyUpdateFlag & 0x5)).to.eq(true); + expect(!!(spriteRenderer._dirtyUpdateFlag & SpriteRendererUpdateFlags.AllPositionAndBounds)).to.eq(true); spriteRenderer.drawMode = SpriteDrawMode.Tiled; // @ts-ignore - spriteRenderer._dirtyUpdateFlag &= ~0x7; + spriteRenderer._dirtyUpdateFlag &= SpriteRendererUpdateFlags.AllPositionBoundsUVAndColor; sprite.width = 11; // @ts-ignore - expect(!!(spriteRenderer._dirtyUpdateFlag & 0x7)).to.eq(true); + expect(!!(spriteRenderer._dirtyUpdateFlag & SpriteRendererUpdateFlags.AllPositionBoundsUVAndColor)).to.eq(true); spriteRenderer.drawMode = SpriteDrawMode.Sliced; // @ts-ignore - spriteRenderer._dirtyUpdateFlag &= ~0x5; + spriteRenderer._dirtyUpdateFlag &= ~SpriteRendererUpdateFlags.AllPositionAndBounds; sprite.width = 12; // @ts-ignore - expect(!!(spriteRenderer._dirtyUpdateFlag & 0x5)).to.eq(true); + expect(!!(spriteRenderer._dirtyUpdateFlag & SpriteRendererUpdateFlags.AllPositionAndBounds)).to.eq(true); // @ts-ignore - spriteRenderer._dirtyUpdateFlag &= ~0x3; + spriteRenderer._dirtyUpdateFlag &= ~SpriteRendererUpdateFlags.AllPositionAndUV; sprite.border = new Vector4(); // @ts-ignore - expect(!!(spriteRenderer._dirtyUpdateFlag & 0x3)).to.eq(true); + expect(!!(spriteRenderer._dirtyUpdateFlag & SpriteRendererUpdateFlags.AllPositionAndUV)).to.eq(true); // @ts-ignore - spriteRenderer._dirtyUpdateFlag &= ~0x3; + spriteRenderer._dirtyUpdateFlag &= ~SpriteRendererUpdateFlags.AllPositionAndUV; sprite.region = new Rect(); // @ts-ignore - expect(!!(spriteRenderer._dirtyUpdateFlag & 0x3)).to.eq(true); + expect(!!(spriteRenderer._dirtyUpdateFlag & SpriteRendererUpdateFlags.AllPositionAndUV)).to.eq(true); // @ts-ignore - spriteRenderer._dirtyUpdateFlag &= ~0x3; + spriteRenderer._dirtyUpdateFlag &= ~SpriteRendererUpdateFlags.AllPositionAndUV; sprite.atlasRegionOffset = new Vector4(); // @ts-ignore - expect(!!(spriteRenderer._dirtyUpdateFlag & 0x3)).to.eq(true); + expect(!!(spriteRenderer._dirtyUpdateFlag & SpriteRendererUpdateFlags.AllPositionAndUV)).to.eq(true); // @ts-ignore - spriteRenderer._dirtyUpdateFlag &= ~0x2; + spriteRenderer._dirtyUpdateFlag &= ~SpriteRendererUpdateFlags.UV; sprite.atlasRegion = new Rect(); // @ts-ignore - expect(!!(spriteRenderer._dirtyUpdateFlag & 0x2)).to.eq(true); + expect(!!(spriteRenderer._dirtyUpdateFlag & SpriteRendererUpdateFlags.UV)).to.eq(true); // @ts-ignore - spriteRenderer._dirtyUpdateFlag &= ~0x1; + spriteRenderer._dirtyUpdateFlag &= ~SpriteRendererUpdateFlags.AllPositionAndBounds; sprite.pivot = new Vector2(0.3, 0.2); // @ts-ignore - expect(!!(spriteRenderer._dirtyUpdateFlag & 0x1)).to.eq(true); + expect(!!(spriteRenderer._dirtyUpdateFlag & SpriteRendererUpdateFlags.AllPositionAndBounds)).to.eq(true); }); it("clone", () => { @@ -1578,21 +1578,35 @@ describe("SpriteRenderer", async () => { }); }); -function log(positions: Vector3[], uv: Vector2[]): void { - for (let i = 0; i < positions.length; i++) { - console.log( - "expect(Vector3.equals(positions[", - i, - "], new Vector3(", - positions[i].x, - ", ", - positions[i].y, - ", ", - positions[i].z, - "))).to.eq(true);" - ); - } - for (let i = 0; i < uv.length; i++) { - console.log("expect(Vector2.equals(uvs[", i, "], new Vector2(", uv[i].x, ", ", uv[i].y, "))).to.eq(true);"); - } +/** + * @remarks Extends `RendererUpdateFlags`. + */ +enum SpriteRendererUpdateFlags { + None = 0x0, + LocalPosition = 0x1, + WorldPosition = 0x2, + LocalBounds = 0x4, + WorldBounds = 0x8, + UV = 0x10, + Color = 0x20, + AutomaticSize = 0x40, + + /** LocalPosition | WorldPosition */ + AllPositions = 0x3, + /** LocalPosition | LocalBounds */ + LocalPositionAndBounds = 0x5, + /** WorldPosition | WorldBounds */ + WorldPositionAndBounds = 0xa, + /** LocalBounds | WorldBounds */ + AllBounds = 0xc, + /** LocalPosition | WorldPosition | LocalBounds | WorldBounds */ + AllPositionAndBounds = 0xf, + /** LocalPosition | WorldPosition | UV */ + AllPositionAndUV = 0x13, + /** LocalPosition | WorldPosition | UV | Color */ + AllPositionUVAndColor = 0x33, + /** LocalPosition | WorldPosition | LocalBounds | WorldBounds | UV | Color */ + AllPositionBoundsUVAndColor = 0x3f, + /** LocalPosition | WorldPosition | LocalBounds | WorldBounds | UV | Color | AutomaticSize */ + All = 0x7f } diff --git a/tests/src/ui/label.test.ts b/tests/src/ui/label.test.ts index 3f9016f527..a844d76eea 100644 --- a/tests/src/ui/label.test.ts +++ b/tests/src/ui/label.test.ts @@ -59,21 +59,21 @@ describe("Label", async () => { const textEntity = canvasEntity.createChild("text"); const label1 = textEntity.addComponent(Label); - const transform1 = label1._transformEntity.transform; + const transform1 = label1.entity.transform; const size1 = transform1.size; size1.x = 2; size1.y = 3; label1.enableWrapping = true; label1.text = "helloworld dfd dlfgds dd df\n ds f"; const label2 = textEntity.addComponent(Label); - const transform2 = label2._transformEntity.transform; + const transform2 = label2.entity.transform; const size2 = transform2.size; size2.x = 2; size2.y = 3; label2.enableWrapping = true; label2.text = "a a a a a a a a a b a a"; const label3 = textEntity.addComponent(Label); - const transform3 = label3._transformEntity.transform; + const transform3 = label3.entity.transform; const size3 = transform3.size; size3.x = 2; size3.y = 3;