diff --git a/.eslintrc.yaml b/.eslintrc.yaml index 617274b6c5b..b4c45b3bc5f 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -71,7 +71,8 @@ rules: import/extensions: off # typescript doesn't support this import/no-unresolved: off # TODO: fix internal modules import/prefer-default-export: off # prefer named exports - indent: [warn, 4] # we use 4-space convention + indent: off # use @typescript-eslint/indent instead for better compatibility + lines-between-class-members: off # be more lenient on member declarations max-classes-per-file: off # helper classes are common max-len: [warn, 150] # more lenient on max length per line @@ -96,6 +97,9 @@ rules: ##### TYPESCRIPT-SPECIFIC RULE OVERRIDES ##### + '@typescript-eslint/indent': [warn, 4, { + SwitchCase: 0 + }] '@typescript-eslint/no-unused-expressions': warn # TODO: this is just too much work diff --git a/@types/jsb.d.ts b/@types/jsb.d.ts index 1a817fecfba..f9c3c991758 100644 --- a/@types/jsb.d.ts +++ b/@types/jsb.d.ts @@ -82,6 +82,7 @@ declare namespace jsb { export let onOrientationChanged: (event: {orientation: number}) => void | undefined; // TODO: enum orientation type export let onResume: () => void | undefined; export let onPause: () => void | undefined; + export let onClose: () => void | undefined; export function openURL(url: string): void; export function garbageCollect(): void; diff --git a/@types/pal/input.d.ts b/@types/pal/input.d.ts index b1922339a85..dac473a21fc 100644 --- a/@types/pal/input.d.ts +++ b/@types/pal/input.d.ts @@ -3,7 +3,7 @@ declare module 'pal/input' { /** * Type of the input event used to quickly distinguish between event types. */ - readonly type: string; + readonly type: import('../../cocos/core/platform/event-manager/event-enum').SystemEventTypeUnion; /** * Timestamp when the input event is triggered. */ @@ -132,7 +132,7 @@ declare module 'pal/input' { /** * Numerical code identifying the unique value of the pressed key. */ - readonly code: number; + readonly code: import('../../cocos/core/platform/event-manager/key-code').KeyCode; } type KeyboardCallback = (res: KeyboardInputEvent) => void; /** @@ -144,6 +144,12 @@ declare module 'pal/input' { * @param cb */ public onDown (cb: KeyboardCallback); + /** + * Register the key pressing event callback. + * NOTE: Compability for the deprecated KEY_DOWN event type. It should be removed in the future. + * @param cb + */ + public onPressing (cb: KeyboardCallback); /** * Register the key up event callback. * @param cb diff --git a/@types/pal/system.d.ts b/@types/pal/system.d.ts index 7735823bc9a..a20644f1b8f 100644 --- a/@types/pal/system.d.ts +++ b/@types/pal/system.d.ts @@ -50,13 +50,17 @@ declare module 'pal/system' { public now (): number; public restartJSVM (): void; + public close (); + public onHide (cb: () => void); public onShow (cb: () => void); + public onClose (cb: () => void); public onViewResize (cb: () => void); public onOrientationChange (cb: () => void); public offHide (cb?: () => void); public offShow (cb?: () => void); + public offClose (cb?: () => void); public offViewResize (cb?: () => void); public offOrientationChange (cb?: () => void); diff --git a/EngineErrorMap.md b/EngineErrorMap.md index fa019748fc6..dd4a5737861 100644 --- a/EngineErrorMap.md +++ b/EngineErrorMap.md @@ -2355,6 +2355,14 @@ cc.ParticleSystem: unknown image format with Data cc.ParticleSystem.initWithDictionary() : error loading the texture +### 6033 + +cc.ParticleSystem: not allowing create to be invoked twice with different particle system + +### 6034 + +cc.ParticleSystem: shouldn't be initialized repetitively, otherwise there will be potential leak + ### 6100 @@ -3022,6 +3030,14 @@ The PrivateNode is deprecated, please use Node directly with CCObject.Flags.Dont SubModel can only support %d passes. +### 12005 + +Material already initialized, request aborted. + +### 12006 + +Pass already destroyed. + ### 12100 The font size is too big to be fitted into texture atlas. Please switch to other label cache modes or choose a smaller font size. diff --git a/cc.config.json b/cc.config.json index 9581c9050cc..c9030089c8d 100644 --- a/cc.config.json +++ b/cc.config.json @@ -45,7 +45,8 @@ "cocos/core/gfx/index.ts": "cocos/core/gfx/index.jsb.ts", "cocos/core/gfx/pipeline-state.ts": "cocos/core/gfx/pipeline-state.jsb.ts", "cocos/spine/index.ts": "cocos/spine/index.jsb.ts", - "cocos/dragon-bones/index.ts": "cocos/dragon-bones/index.jsb.ts" + "cocos/dragon-bones/index.ts": "cocos/dragon-bones/index.jsb.ts", + "cocos/core/renderer/scene/native-scene.ts": "cocos/core/renderer/scene/native-scene.jsb.ts" } }, { diff --git a/cocos/2d/assembler/sprite/simple.ts b/cocos/2d/assembler/sprite/simple.ts index f77898f0ccf..a20d8793c0e 100644 --- a/cocos/2d/assembler/sprite/simple.ts +++ b/cocos/2d/assembler/sprite/simple.ts @@ -92,10 +92,13 @@ export const simple: IAssembler = { // sprite.renderData!.indicesCount, // ); // const commitBuffer: IUIRenderData = renderer.createUIRenderData(); - const dataList: IRenderData[] = sprite.renderData!.data; + const renderData = sprite.renderData; + + const dataList: IRenderData[] = renderData!.data; const node = sprite.node; let buffer = renderer.acquireBufferBatch()!; + let vertexOffset = buffer.byteOffset >> 2; let indicesOffset = buffer.indicesOffset; let vertexId = buffer.vertexOffset; @@ -111,41 +114,75 @@ export const simple: IAssembler = { // buffer data may be reallocated, need get reference after request. const vBuf = buffer.vData!; const iBuf = buffer.iData!; - const vData = sprite.renderData!.vData!; + const vData = renderData!.vData!; + const data0 = dataList[0]; const data3 = dataList[3]; const matrix = node.worldMatrix; const a = matrix.m00; const b = matrix.m01; const c = matrix.m04; const d = matrix.m05; + + const justTranslate = a === 1 && b === 0 && c === 0 && d === 1; + const tx = matrix.m12; const ty = matrix.m13; const vl = data0.x; const vr = data3.x; const vb = data0.y; const vt = data3.y; - const al = a * vl; const ar = a * vr; - const bl = b * vl; const br = b * vr; - const cb = c * vb; const ct = c * vt; - const db = d * vb; const dt = d * vt; - // left bottom - vData[0] = al + cb + tx; - vData[1] = bl + db + ty; - // right bottom - vData[9] = ar + cb + tx; - vData[10] = br + db + ty; - // left top - vData[18] = al + ct + tx; - vData[19] = bl + dt + ty; - // right top - vData[27] = ar + ct + tx; - vData[28] = br + dt + ty; + + if (justTranslate) { + const vltx = vl + tx; + const vrtx = vr + tx; + const vbty = vb + ty; + const vtty = vt + ty; + + // left bottom + vData[0] = vltx; + vData[1] = vbty; + // right bottom + vData[9] = vrtx; + vData[10] = vbty; + // left top + vData[18] = vltx; + vData[19] = vtty; + // right top + vData[27] = vrtx; + vData[28] = vtty; + } else { + const al = a * vl; const ar = a * vr; + const bl = b * vl; const br = b * vr; + const cb = c * vb; const ct = c * vt; + const db = d * vb; const dt = d * vt; + + const cbtx = cb + tx; + const cttx = ct + tx; + const dbty = db + ty; + const dtty = dt + ty; + + // left bottom + vData[0] = al + cbtx; + vData[1] = bl + dbty; + // right bottom + vData[9] = ar + cbtx; + vData[10] = br + dbty; + // left top + vData[18] = al + cttx; + vData[19] = bl + dtty; + // right top + vData[27] = ar + cttx; + vData[28] = br + dtty; + } vBuf.set(vData, vertexOffset); + const index0 = vertexId; const index1 = vertexId + 1; + const index2 = vertexId + 2; const index3 = vertexId + 3; + // fill index data - iBuf[indicesOffset++] = vertexId; - iBuf[indicesOffset++] = vertexId + 1; - iBuf[indicesOffset++] = vertexId + 2; - iBuf[indicesOffset++] = vertexId + 2; - iBuf[indicesOffset++] = vertexId + 1; - iBuf[indicesOffset++] = vertexId + 3; + iBuf[indicesOffset++] = index0; + iBuf[indicesOffset++] = index1; + iBuf[indicesOffset++] = index2; + iBuf[indicesOffset++] = index2; + iBuf[indicesOffset++] = index1; + iBuf[indicesOffset++] = index3; }, updateVertexData (sprite: Sprite) { diff --git a/cocos/2d/components/graphics.ts b/cocos/2d/components/graphics.ts index 1cdc1c420fd..dd0df2c42c4 100644 --- a/cocos/2d/components/graphics.ts +++ b/cocos/2d/components/graphics.ts @@ -244,6 +244,8 @@ export class Graphics extends Renderable2D { protected _isDrawing = false; protected _isNeedUploadData = true; + private _graphicsUseSubMeshes: RenderingSubMesh[] = []; + constructor () { super(); this._instanceMaterialType = InstanceMaterialType.ADD_COLOR; @@ -280,6 +282,14 @@ export class Graphics extends Renderable2D { this.model = null; } + const subMeshLength = this._graphicsUseSubMeshes.length; + if (subMeshLength > 0) { + for (let i = 0; i < subMeshLength; ++i) { + this._graphicsUseSubMeshes[i].destroy(); + } + this._graphicsUseSubMeshes.length = 0; + } + if (!this.impl) { return; } @@ -599,6 +609,7 @@ export class Graphics extends Renderable2D { renderMesh.subMeshIdx = 0; this.model.initSubModel(idx, renderMesh, this.getMaterialInstance(0)!); + this._graphicsUseSubMeshes.push(renderMesh); } } diff --git a/cocos/2d/components/label.ts b/cocos/2d/components/label.ts index 4455fb4ec29..d24d29b5afe 100644 --- a/cocos/2d/components/label.ts +++ b/cocos/2d/components/label.ts @@ -814,8 +814,9 @@ export class Label extends Renderable2D { this._ttfSpriteFrame = new SpriteFrame(); this._assemblerData = this._assembler!.getAssemblerData(); const image = new ImageAsset(this._assemblerData!.canvas); - const tex = image._texture; - this._ttfSpriteFrame.texture = tex; + const texture = new Texture2D(); + texture.image = image; + this._ttfSpriteFrame.texture = texture; } if (this.cacheMode !== CacheMode.CHAR) { diff --git a/cocos/2d/components/mask.ts b/cocos/2d/components/mask.ts index b7d393999d2..762192a6a86 100644 --- a/cocos/2d/components/mask.ts +++ b/cocos/2d/components/mask.ts @@ -32,7 +32,7 @@ import { ccclass, help, executionOrder, menu, tooltip, displayOrder, type, visible, override, serializable, range, slide } from 'cc.decorator'; import { InstanceMaterialType, Renderable2D } from '../framework/renderable-2d'; import { clamp, Color, Mat4, Vec2, Vec3 } from '../../core/math'; -import { SystemEventType, warnID } from '../../core/platform'; +import { warnID } from '../../core/platform'; import { Batcher2D } from '../renderer/batcher-2d'; import { ccenum } from '../../core/value-types/enum'; import { Graphics } from './graphics'; @@ -352,6 +352,8 @@ export class Mask extends Renderable2D { protected _graphics: Graphics | null = null; + private _clearModelMesh: RenderingSubMesh| null = null; + constructor () { super(); this._instanceMaterialType = InstanceMaterialType.ADD_COLOR; @@ -389,8 +391,9 @@ export class Mask extends Renderable2D { public onDestroy () { super.onDestroy(); - if (this._clearModel) { + if (this._clearModel && this._clearModelMesh) { director.root!.destroyModel(this._clearModel); + this._clearModelMesh.destroy(); } if (this._clearStencilMtl) { @@ -561,10 +564,10 @@ export class Mask extends Renderable2D { const ib = new Uint16Array([0, 1, 2, 2, 1, 3]); indexBuffer.update(ib); - const renderMesh = new RenderingSubMesh([vertexBuffer], vfmt, PrimitiveMode.TRIANGLE_LIST, indexBuffer); - renderMesh.subMeshIdx = 0; + this._clearModelMesh = new RenderingSubMesh([vertexBuffer], vfmt, PrimitiveMode.TRIANGLE_LIST, indexBuffer); + this._clearModelMesh.subMeshIdx = 0; - this._clearModel.initSubModel(0, renderMesh, this._clearStencilMtl); + this._clearModel.initSubModel(0, this._clearModelMesh, this._clearStencilMtl); } } diff --git a/cocos/2d/components/rich-text.ts b/cocos/2d/components/rich-text.ts index 3e68ee2a36f..bed8d9c5c6f 100644 --- a/cocos/2d/components/rich-text.ts +++ b/cocos/2d/components/rich-text.ts @@ -32,7 +32,7 @@ import { ccclass, executeInEditMode, executionOrder, help, menu, tooltip, multiline, type, serializable } from 'cc.decorator'; import { DEV, EDITOR } from 'internal:constants'; import { Font, SpriteAtlas, TTFFont, SpriteFrame } from '../assets'; -import { assert, EventTouch, SystemEventType, warnID } from '../../core/platform'; +import { assert, EventTouch, warnID } from '../../core/platform'; import { BASELINE_RATIO, fragmentText, isUnicodeCJK, isUnicodeSpace } from '../utils/text-utils'; import { HtmlTextParser, IHtmlTextParserResultObj, IHtmlTextParserStack } from '../utils/html-text-parser'; import Pool from '../../core/utils/pool'; @@ -46,6 +46,7 @@ import { legacyCC } from '../../core/global-exports'; import { Component } from '../../core/components'; import assetManager from '../../core/asset-manager/asset-manager'; import { CCObject } from '../../core'; +import { NodeEventType } from '../../core/scene-graph/node-event'; const _htmlTextParser = new HtmlTextParser(); const RichTextChildName = 'RICHTEXT_CHILD'; @@ -458,7 +459,7 @@ export class RichText extends UIComponent { } public onLoad () { - this.node.on(SystemEventType.LAYER_CHANGED, this._applyLayer, this); + this.node.on(NodeEventType.LAYER_CHANGED, this._applyLayer, this); } public onEnable () { @@ -480,7 +481,7 @@ export class RichText extends UIComponent { public start () { this._onTTFLoaded(); - this.node.on(Node.EventType.ANCHOR_CHANGED, this._updateRichTextPosition, this); + this.node.on(NodeEventType.ANCHOR_CHANGED, this._updateRichTextPosition, this); } public onRestore () { @@ -508,16 +509,16 @@ export class RichText extends UIComponent { } } - this.node.off(Node.EventType.ANCHOR_CHANGED, this._updateRichTextPosition, this); - this.node.off(SystemEventType.LAYER_CHANGED, this._applyLayer, this); + this.node.off(NodeEventType.ANCHOR_CHANGED, this._updateRichTextPosition, this); + this.node.off(NodeEventType.LAYER_CHANGED, this._applyLayer, this); } protected _addEventListeners () { - this.node.on(Node.EventType.TOUCH_END, this._onTouchEnded, this); + this.node.on(NodeEventType.TOUCH_END, this._onTouchEnded, this); } protected _removeEventListeners () { - this.node.off(Node.EventType.TOUCH_END, this._onTouchEnded, this); + this.node.off(NodeEventType.TOUCH_END, this._onTouchEnded, this); } protected _updateLabelSegmentTextAttributes () { diff --git a/cocos/2d/components/sprite.ts b/cocos/2d/components/sprite.ts index 154462ca639..61ffbeeb958 100644 --- a/cocos/2d/components/sprite.ts +++ b/cocos/2d/components/sprite.ts @@ -33,7 +33,6 @@ import { ccclass, help, executionOrder, menu, tooltip, displayOrder, type, range import { EDITOR } from 'internal:constants'; import { SpriteAtlas } from '../assets/sprite-atlas'; import { SpriteFrame } from '../assets/sprite-frame'; -import { SystemEventType } from '../../core/platform/event-manager/event-enum'; import { Vec2 } from '../../core/math'; import { ccenum } from '../../core/value-types/enum'; import { clamp } from '../../core/math/utils'; @@ -42,7 +41,8 @@ import { Renderable2D, InstanceMaterialType } from '../framework/renderable-2d'; import { legacyCC } from '../../core/global-exports'; import { PixelFormat } from '../../core/assets/asset-enum'; import { TextureBase } from '../../core/assets/texture-base'; -import { Material, RenderTexture } from '../../core'; +import { Material, Node, RenderTexture } from '../../core'; +import { NodeEventType } from '../../core/scene-graph/node-event'; /** * @en @@ -479,7 +479,7 @@ export class Sprite extends Renderable2D { if (EDITOR) { this._resized(); - this.node.on(SystemEventType.SIZE_CHANGED, this._resized, this); + this.node.on(NodeEventType.SIZE_CHANGED, this._resized, this); } if (this._spriteFrame) { @@ -516,7 +516,7 @@ export class Sprite extends Renderable2D { public onDestroy () { this.destroyRenderData(); if (EDITOR) { - this.node.off(SystemEventType.SIZE_CHANGED, this._resized, this); + this.node.off(NodeEventType.SIZE_CHANGED, this._resized, this); } if (this._spriteFrame && !this._spriteFrame.loaded) { diff --git a/cocos/2d/framework/canvas.ts b/cocos/2d/framework/canvas.ts index b84bf4c352f..20e1a45e716 100644 --- a/cocos/2d/framework/canvas.ts +++ b/cocos/2d/framework/canvas.ts @@ -38,10 +38,11 @@ import { game } from '../../core/game'; import { Vec3 } from '../../core/math'; import { view } from '../../core/platform/view'; import { legacyCC } from '../../core/global-exports'; -import { SystemEventType } from '../../core/platform/event-manager'; import { Enum } from '../../core/value-types/enum'; import visibleRect from '../../core/platform/visible-rect'; import { RenderRoot2D } from './render-root-2d'; +import { Node } from '../../core'; +import { NodeEventType } from '../../core/scene-graph/node-event'; const _worldPos = new Vec3(); @@ -189,7 +190,7 @@ export class Canvas extends RenderRoot2D { this._objFlags |= legacyCC.Object.Flags.IsPositionLocked | legacyCC.Object.Flags.IsSizeLocked | legacyCC.Object.Flags.IsAnchorLocked; } - this.node.on(SystemEventType.TRANSFORM_CHANGED, this._thisOnCameraResized); + this.node.on(NodeEventType.TRANSFORM_CHANGED, this._thisOnCameraResized); } public onDestroy () { @@ -199,7 +200,7 @@ export class Canvas extends RenderRoot2D { legacyCC.director.off(legacyCC.Director.EVENT_AFTER_UPDATE, this._fitDesignResolution!, this); } - this.node.off(SystemEventType.TRANSFORM_CHANGED, this._thisOnCameraResized); + this.node.off(NodeEventType.TRANSFORM_CHANGED, this._thisOnCameraResized); } protected _onResizeCamera () { diff --git a/cocos/2d/framework/renderable-2d.ts b/cocos/2d/framework/renderable-2d.ts index 6160f484d8a..109e4b43546 100644 --- a/cocos/2d/framework/renderable-2d.ts +++ b/cocos/2d/framework/renderable-2d.ts @@ -31,7 +31,6 @@ import { EDITOR } from 'internal:constants'; import { ccclass, executeInEditMode, requireComponent, disallowMultiple, tooltip, type, displayOrder, serializable, override, visible, displayName } from 'cc.decorator'; import { Color } from '../../core/math'; -import { SystemEventType } from '../../core/platform/event-manager/event-enum'; import { ccenum } from '../../core/value-types/enum'; import { builtinResMgr } from '../../core/builtin'; import { Material } from '../../core/assets'; @@ -47,6 +46,7 @@ import { RenderableComponent } from '../../core/components/renderable-component' import { Stage } from '../renderer/stencil-manager'; import { warnID } from '../../core/platform/debug'; import { legacyCC } from '../../core/global-exports'; +import { NodeEventType } from '../../core/scene-graph/node-event'; // hack ccenum(BlendFactor); @@ -254,7 +254,7 @@ export class Renderable2D extends RenderableComponent { this._colorDirty = true; if (EDITOR) { const clone = value.clone(); - this.node.emit(SystemEventType.COLOR_CHANGED, clone); + this.node.emit(NodeEventType.COLOR_CHANGED, clone); } } @@ -330,8 +330,8 @@ export class Renderable2D extends RenderableComponent { } public onEnable () { - this.node.on(SystemEventType.ANCHOR_CHANGED, this._nodeStateChange, this); - this.node.on(SystemEventType.SIZE_CHANGED, this._nodeStateChange, this); + this.node.on(NodeEventType.ANCHOR_CHANGED, this._nodeStateChange, this); + this.node.on(NodeEventType.SIZE_CHANGED, this._nodeStateChange, this); this.updateMaterial(); this._renderFlag = this._canRender(); } @@ -343,8 +343,8 @@ export class Renderable2D extends RenderableComponent { } public onDisable () { - this.node.off(SystemEventType.ANCHOR_CHANGED, this._nodeStateChange, this); - this.node.off(SystemEventType.SIZE_CHANGED, this._nodeStateChange, this); + this.node.off(NodeEventType.ANCHOR_CHANGED, this._nodeStateChange, this); + this.node.off(NodeEventType.SIZE_CHANGED, this._nodeStateChange, this); this._renderFlag = false; } @@ -460,10 +460,8 @@ export class Renderable2D extends RenderableComponent { protected _updateColor () { this._updateWorldAlpha(); - if ((this._colorDirty || this._cacheAlpha !== this.node._uiProps.opacity) - && this._renderFlag && this._assembler && this._assembler.updateColor) { + if (this._colorDirty && this._assembler && this._assembler.updateColor) { this._assembler.updateColor(this); - this._cacheAlpha = this.node._uiProps.opacity; this._colorDirty = false; } } @@ -471,8 +469,11 @@ export class Renderable2D extends RenderableComponent { protected _updateWorldAlpha () { let localAlpha = this.color.a / 255; if (localAlpha === 1) localAlpha = this.node._uiProps.localOpacity; // Hack for Mask use ui-opacity - this.node._uiProps.opacity = (this.node.parent && this.node.parent._uiProps) ? this.node.parent._uiProps.opacity * localAlpha : localAlpha; - this._renderFlag = this._canRender(); + const parent = this.node.parent; + const alpha = (parent && parent._uiProps) ? parent._uiProps.opacity * localAlpha : localAlpha; + this.node._uiProps.opacity = alpha; + this._colorDirty = this._colorDirty || alpha !== this._cacheAlpha; + this._cacheAlpha = alpha; } public _updateBlendFunc () { diff --git a/cocos/2d/framework/ui-transform.ts b/cocos/2d/framework/ui-transform.ts index 19425b38e5c..387c5fe4617 100644 --- a/cocos/2d/framework/ui-transform.ts +++ b/cocos/2d/framework/ui-transform.ts @@ -31,7 +31,6 @@ import { ccclass, help, executeInEditMode, executionOrder, menu, tooltip, displayOrder, serializable, disallowMultiple, visible } from 'cc.decorator'; import { EDITOR } from 'internal:constants'; import { Component } from '../../core/components'; -import { SystemEventType } from '../../core/platform/event-manager/event-enum'; import { EventListener } from '../../core/platform/event-manager/event-listener'; import { Mat4, Rect, Size, Vec2, Vec3 } from '../../core/math'; import { AABB } from '../../core/geometry'; @@ -39,6 +38,7 @@ import { Node } from '../../core/scene-graph'; import { legacyCC } from '../../core/global-exports'; import { Director, director } from '../../core/director'; import { warnID } from '../../core/platform/debug'; +import { NodeEventType } from '../../core/scene-graph/node-event'; const _vec2a = new Vec2(); const _vec2b = new Vec2(); @@ -88,9 +88,9 @@ export class UITransform extends Component { this._contentSize.set(value); if (EDITOR) { // @ts-expect-error EDITOR condition - this.node.emit(SystemEventType.SIZE_CHANGED, clone); + this.node.emit(NodeEventType.SIZE_CHANGED, clone); } else { - this.node.emit(SystemEventType.SIZE_CHANGED); + this.node.emit(NodeEventType.SIZE_CHANGED); } } @@ -111,9 +111,9 @@ export class UITransform extends Component { this._contentSize.width = value; if (EDITOR) { // @ts-expect-error EDITOR condition - this.node.emit(SystemEventType.SIZE_CHANGED, clone); + this.node.emit(NodeEventType.SIZE_CHANGED, clone); } else { - this.node.emit(SystemEventType.SIZE_CHANGED); + this.node.emit(NodeEventType.SIZE_CHANGED); } } @@ -134,9 +134,9 @@ export class UITransform extends Component { this._contentSize.height = value; if (EDITOR) { // @ts-expect-error EDITOR condition - this.node.emit(SystemEventType.SIZE_CHANGED, clone); + this.node.emit(NodeEventType.SIZE_CHANGED, clone); } else { - this.node.emit(SystemEventType.SIZE_CHANGED); + this.node.emit(NodeEventType.SIZE_CHANGED); } } @@ -160,7 +160,7 @@ export class UITransform extends Component { } this._anchorPoint.set(value); - this.node.emit(SystemEventType.ANCHOR_CHANGED, this._anchorPoint); + this.node.emit(NodeEventType.ANCHOR_CHANGED, this._anchorPoint); } get anchorX () { @@ -173,7 +173,7 @@ export class UITransform extends Component { } this._anchorPoint.x = value; - this.node.emit(SystemEventType.ANCHOR_CHANGED, this._anchorPoint); + this.node.emit(NodeEventType.ANCHOR_CHANGED, this._anchorPoint); } get anchorY () { @@ -186,7 +186,7 @@ export class UITransform extends Component { } this._anchorPoint.y = value; - this.node.emit(SystemEventType.ANCHOR_CHANGED, this._anchorPoint); + this.node.emit(NodeEventType.ANCHOR_CHANGED, this._anchorPoint); } /** @@ -239,7 +239,7 @@ export class UITransform extends Component { return camera ? camera.priority : 0; } - public static EventType = SystemEventType; + public static EventType = NodeEventType; @serializable protected _contentSize = new Size(100, 100); @@ -257,11 +257,11 @@ export class UITransform extends Component { } public onEnable () { - this.node.on(SystemEventType.PARENT_CHANGED, this._parentChanged, this); + this.node.on(NodeEventType.PARENT_CHANGED, this._parentChanged, this); } public onDisable () { - this.node.off(SystemEventType.PARENT_CHANGED, this._parentChanged, this); + this.node.off(NodeEventType.PARENT_CHANGED, this._parentChanged, this); } public onDestroy () { @@ -331,9 +331,9 @@ export class UITransform extends Component { if (EDITOR) { // @ts-expect-error EDITOR condition - this.node.emit(SystemEventType.SIZE_CHANGED, clone); + this.node.emit(NodeEventType.SIZE_CHANGED, clone); } else { - this.node.emit(SystemEventType.SIZE_CHANGED); + this.node.emit(NodeEventType.SIZE_CHANGED); } } @@ -363,7 +363,7 @@ export class UITransform extends Component { * node.setAnchorPoint(1, 1); * ``` */ - public setAnchorPoint (point: Vec2 | number, y?: number) { + public setAnchorPoint (point: Readonly | number, y?: number) { const locAnchorPoint = this._anchorPoint; if (y === undefined) { point = point as Vec2; @@ -382,7 +382,7 @@ export class UITransform extends Component { // this.setLocalDirty(LocalDirtyFlag.POSITION); // if (this._eventMask & ANCHOR_ON) { - this.node.emit(SystemEventType.ANCHOR_CHANGED, this._anchorPoint); + this.node.emit(NodeEventType.ANCHOR_CHANGED, this._anchorPoint); // } } diff --git a/cocos/2d/renderer/batcher-2d.ts b/cocos/2d/renderer/batcher-2d.ts index c8dfeadebd1..5e22df0419f 100644 --- a/cocos/2d/renderer/batcher-2d.ts +++ b/cocos/2d/renderer/batcher-2d.ts @@ -31,7 +31,7 @@ import { Camera, Model } from 'cocos/core/renderer/scene'; import { UIStaticBatch } from '../components'; import { Material } from '../../core/assets/material'; import { RenderRoot2D, Renderable2D, UIComponent } from '../framework'; -import { Texture, Device, Attribute, Sampler, DescriptorSetInfo, Buffer, BufferInfo, BufferUsageBit, MemoryUsageBit } from '../../core/gfx'; +import { Texture, Device, Attribute, Sampler, DescriptorSetInfo, Buffer, BufferInfo, BufferUsageBit, MemoryUsageBit, DescriptorSet } from '../../core/gfx'; import { Pool, RecyclePool } from '../../core/memop'; import { CachedArray } from '../../core/memop/cached-array'; import { RenderScene } from '../../core/renderer/scene/render-scene'; @@ -42,7 +42,6 @@ import { Stage, StencilManager } from './stencil-manager'; import { DrawBatch2D } from './draw-batch'; import * as VertexFormat from './vertex-format'; import { legacyCC } from '../../core/global-exports'; -import { DescriptorSetHandle, DSPool, SubModelPool, SubModelView } from '../../core/renderer/core/memory-pools'; import { ModelLocalBindings, UBOLocal } from '../../core/pipeline/define'; import { RenderTexture } from '../../core/assets'; import { SpriteFrame } from '../assets'; @@ -265,7 +264,7 @@ export class Batcher2D { subModels[j].priority = batchPriority++; } } else { - batch.hDescriptorSet = this._descriptorSetCache.getDescriptorSet(batch); + batch.descriptorSet = this._descriptorSetCache.getDescriptorSet(batch); } batch.renderScene.addBatch(batch); } @@ -453,8 +452,8 @@ export class Batcher2D { curDrawBatch.useLocalData = null; if (!depthStencil) { depthStencil = null; } curDrawBatch.fillPasses(mat, depthStencil, dssHash, null, 0, subModel.patches); - curDrawBatch.hDescriptorSet = SubModelPool.get(subModel.handle, SubModelView.DESCRIPTOR_SET); - curDrawBatch.hInputAssembler = SubModelPool.get(subModel.handle, SubModelView.INPUT_ASSEMBLER); + curDrawBatch.descriptorSet = subModel.descriptorSet; + curDrawBatch.inputAssembler = subModel.inputAssembler; curDrawBatch.model!.visFlags = curDrawBatch.visFlags; this._batches.push(curDrawBatch); } @@ -494,9 +493,9 @@ export class Batcher2D { */ public autoMergeBatches (renderComp?: Renderable2D) { const buffer = this.currBufferBatch; - const hIA = buffer?.recordBatch(); + const ia = buffer?.recordBatch(); const mat = this._currMaterial; - if (!hIA || !mat || !buffer) { + if (!ia || !mat || !buffer) { return; } let blendState; @@ -520,7 +519,7 @@ export class Batcher2D { curDrawBatch.bufferBatch = buffer; curDrawBatch.texture = this._currTexture!; curDrawBatch.sampler = this._currSampler; - curDrawBatch.hInputAssembler = hIA; + curDrawBatch.inputAssembler = ia; curDrawBatch.useLocalData = this._currTransform; curDrawBatch.textureHash = this._currTextureHash; curDrawBatch.samplerHash = this._currSamplerHash; @@ -680,18 +679,18 @@ export class Batcher2D { } } -class LocalDescriptorSet { - public get handle () { - return this._handle; - } - private _handle: DescriptorSetHandle | null = null; +class LocalDescriptorSet { + private _descriptorSet: DescriptorSet | null = null; private _transform: Node | null = null; private _textureHash = 0; private _samplerHash = 0; private _localBuffer: Buffer | null = null; private _transformUpdate = true; private declare _localData; - private declare _descriptorSet; + + public get descriptorSet (): DescriptorSet | null { + return this._descriptorSet; + } constructor () { const device = legacyCC.director.root.device; @@ -710,17 +709,12 @@ class LocalDescriptorSet { this._textureHash = batch.textureHash; this._samplerHash = batch.samplerHash; _dsInfo.layout = batch.passes[0].localSetLayout; - if (this._handle) { - DSPool.free(this._handle); - this._handle = null; - } - this._handle = DSPool.alloc(device, _dsInfo); - this._descriptorSet = DSPool.get(this._handle); - this._descriptorSet.bindBuffer(UBOLocal.BINDING, this._localBuffer); + this._descriptorSet = device.createDescriptorSet(_dsInfo); + this._descriptorSet!.bindBuffer(UBOLocal.BINDING, this._localBuffer!); const binding = ModelLocalBindings.SAMPLER_SPRITE; - this._descriptorSet.bindTexture(binding, batch.texture!); - this._descriptorSet.bindSampler(binding, batch.sampler!); - this._descriptorSet.update(); + this._descriptorSet!.bindTexture(binding, batch.texture!); + this._descriptorSet!.bindSampler(binding, batch.sampler!); + this._descriptorSet!.update(); this._transformUpdate = true; } @@ -752,9 +746,9 @@ class LocalDescriptorSet { this._localBuffer = null; } - if (this._handle) { - DSPool.free(this._handle); - this._handle = null; + if (this._descriptorSet) { + this._descriptorSet.destroy(); + this._descriptorSet = null; } this._localData = null; @@ -786,7 +780,7 @@ class LocalDescriptorSet { } class DescriptorSetCache { - private _descriptorSetCache = new Map>(); + private _descriptorSetCache = new Map>(); private _localDescriptorSetCache: LocalDescriptorSet[] = []; private _localCachePool: Pool; @@ -794,39 +788,39 @@ class DescriptorSetCache { this._localCachePool = new Pool(() => new LocalDescriptorSet(), 16); } - public getDescriptorSet (batch): DescriptorSetHandle { + public getDescriptorSet (batch): DescriptorSet { const root = legacyCC.director.root; if (batch.useLocalData) { const caches = this._localDescriptorSetCache; for (let i = 0, len = caches.length; i < len; i++) { const cache: LocalDescriptorSet = caches[i]; if (cache.equals(batch.useLocalData, batch.textureHash, batch.samplerHash)) { - return cache.handle as DescriptorSetHandle; + return cache.descriptorSet!; } } const localDs = this._localCachePool.alloc(); localDs.initialize(batch); this._localDescriptorSetCache.push(localDs); - return localDs.handle as DescriptorSetHandle; + return localDs.descriptorSet!; } else { const descriptorSetTextureMap = this._descriptorSetCache.get(batch.textureHash); if (descriptorSetTextureMap && descriptorSetTextureMap.has(batch.samplerHash)) { return descriptorSetTextureMap.get(batch.samplerHash)!; } else { + const device = legacyCC.director.root.device; _dsInfo.layout = batch.passes[0].localSetLayout; - const handle = DSPool.alloc(root.device, _dsInfo); - const descriptorSet = DSPool.get(handle); + const descriptorSet = root.device.createDescriptorSet(_dsInfo); const binding = ModelLocalBindings.SAMPLER_SPRITE; descriptorSet.bindTexture(binding, batch.texture!); descriptorSet.bindSampler(binding, batch.sampler!); descriptorSet.update(); if (descriptorSetTextureMap) { - this._descriptorSetCache.get(batch.textureHash)!.set(batch.samplerHash, handle); + this._descriptorSetCache.get(batch.textureHash)!.set(batch.samplerHash, descriptorSet); } else { - this._descriptorSetCache.set(batch.textureHash, new Map([[batch.samplerHash, handle]])); + this._descriptorSetCache.set(batch.textureHash, new Map([[batch.samplerHash, descriptorSet]])); } - return handle; + return descriptorSet as DescriptorSet; } } } @@ -849,7 +843,7 @@ class DescriptorSetCache { public releaseDescriptorSetCache (textureHash) { if (this._descriptorSetCache.has(textureHash)) { this._descriptorSetCache.get(textureHash)!.forEach((value) => { - DSPool.free(value); + value.destroy(); }); this._descriptorSetCache.delete(textureHash); } @@ -857,8 +851,8 @@ class DescriptorSetCache { public destroy () { this._descriptorSetCache.forEach((value, key, map) => { - value.forEach((hDescriptorSet) => { - DSPool.free(hDescriptorSet); + value.forEach((descriptorSet) => { + descriptorSet.destroy(); }); }); this._descriptorSetCache.clear(); diff --git a/cocos/2d/renderer/draw-batch.ts b/cocos/2d/renderer/draw-batch.ts index 8dcbff40761..d092738b594 100644 --- a/cocos/2d/renderer/draw-batch.ts +++ b/cocos/2d/renderer/draw-batch.ts @@ -28,42 +28,54 @@ * @hidden */ +import { JSB } from 'internal:constants'; import { MeshBuffer } from './mesh-buffer'; import { Material } from '../../core/assets/material'; -import { Texture, Sampler } from '../../core/gfx'; +import { Texture, Sampler, InputAssembler, DescriptorSet, Shader } from '../../core/gfx'; import { Node } from '../../core/scene-graph'; import { Camera } from '../../core/renderer/scene/camera'; import { RenderScene } from '../../core/renderer/scene/render-scene'; import { Model } from '../../core/renderer/scene/model'; import { Batcher2D } from './batcher-2d'; -import { NULL_HANDLE, BatchHandle2D, BatchPool2D, BatchView2D, PassPool } from '../../core/renderer/core/memory-pools'; import { Layers } from '../../core/scene-graph/layers'; import { legacyCC } from '../../core/global-exports'; import { Pass } from '../../core/renderer/core/pass'; +import { NativeDrawBatch2D, NativePass } from '../../core/renderer/scene'; const UI_VIS_FLAG = Layers.Enum.NONE | Layers.Enum.UI_3D; export class DrawBatch2D { - public get handle () { - return this._handle; + public get native (): NativeDrawBatch2D { + return this._nativeObj!; } - public get hInputAssembler () { - return BatchPool2D.get(this._handle, BatchView2D.INPUT_ASSEMBLER); + + public get inputAssembler () { + return this._inputAssember; } - public set hInputAssembler (handle) { - BatchPool2D.set(this._handle, BatchView2D.INPUT_ASSEMBLER, handle); + public set inputAssembler (ia: InputAssembler | null) { + this._inputAssember = ia; + if (JSB) { + this._nativeObj!.inputAssembler = ia; + } } - public get hDescriptorSet () { - return BatchPool2D.get(this._handle, BatchView2D.DESCRIPTOR_SET); + public get descriptorSet () { + return this._descriptorSet; } - public set hDescriptorSet (handle) { - BatchPool2D.set(this._handle, BatchView2D.DESCRIPTOR_SET, handle); + public set descriptorSet (ds: DescriptorSet | null) { + this._descriptorSet = ds; + if (JSB) { + this._nativeObj!.descriptorSet = ds; + } } public get visFlags () { - return BatchPool2D.get(this._handle, BatchView2D.VIS_FLAGS); + return this._visFlags; } public set visFlags (vis) { - BatchPool2D.set(this._handle, BatchView2D.VIS_FLAGS, vis); + this._visFlags = vis; + + if (JSB) { + this._nativeObj!.visFlags = vis; + } } public get passes () { return this._passes; @@ -79,33 +91,30 @@ export class DrawBatch2D { public isStatic = false; public textureHash = 0; public samplerHash = 0; - private _handle: BatchHandle2D = NULL_HANDLE; private _passes: Pass[] = []; + private _visFlags: number = UI_VIS_FLAG; + private _inputAssember: InputAssembler | null = null; + private _descriptorSet: DescriptorSet | null = null; + private declare _nativeObj: NativeDrawBatch2D | null; constructor () { - this._handle = BatchPool2D.alloc(); - BatchPool2D.set(this._handle, BatchView2D.VIS_FLAGS, UI_VIS_FLAG); - BatchPool2D.set(this._handle, BatchView2D.INPUT_ASSEMBLER, NULL_HANDLE); - BatchPool2D.set(this._handle, BatchView2D.DESCRIPTOR_SET, NULL_HANDLE); + if (JSB) { + this._nativeObj = new NativeDrawBatch2D(); + this._nativeObj.visFlags = this._visFlags; + } } public destroy (ui: Batcher2D) { - if (this._handle) { - const length = this.passes.length; - for (let i = 0; i < length; i++) { - // @ts-expect-error hack for UI destroyHandle - this.passes[i]._destroyHandle(); - } - this._passes = []; - BatchPool2D.free(this._handle); - this._handle = NULL_HANDLE; + this._passes = []; + if (JSB) { + this._nativeObj = null; } } public clear () { this.bufferBatch = null; - this.hInputAssembler = NULL_HANDLE; - this.hDescriptorSet = NULL_HANDLE; + this.inputAssembler = null; + this.descriptorSet = null; this.camera = null; this.texture = null; this.sampler = null; @@ -121,15 +130,16 @@ export class DrawBatch2D { const passes = mat.passes; if (!passes) { return; } - BatchPool2D.set(this._handle, BatchView2D.PASS_COUNT, passes.length); - let passOffset = BatchView2D.PASS_0; - let shaderOffset = BatchView2D.SHADER_0; let hashFactor = 0; - for (let i = 0; i < passes.length; i++, passOffset++, shaderOffset++) { + + for (let i = 0; i < passes.length; i++) { if (!this._passes[i]) { this._passes[i] = new Pass(legacyCC.director.root); - // @ts-expect-error hack for UI use pass object - this._passes[i]._handle = PassPool.alloc(); + + if (JSB) { + // @ts-expect-error hack for UI use pass object + this._passes[i]._nativeObj = new NativePass(); + } } const mtlPass = passes[i]; const passInUse = this._passes[i]; @@ -142,8 +152,19 @@ export class DrawBatch2D { mtlPass.update(); // @ts-expect-error hack for UI use pass object passInUse._initPassFromTarget(mtlPass, dss, bs, hashFactor); - BatchPool2D.set(this._handle, passOffset, passInUse.handle); - BatchPool2D.set(this._handle, shaderOffset, passInUse.getShaderVariant(patches)); + } + + if (JSB) { + const nativePasses: NativePass[] = []; + const nativeShaders: Shader[] = []; + const passes = this._passes; + for (let i = 0; i < passes.length; i++) { + nativePasses.push(passes[i].native); + nativeShaders.push(passes[i].getShaderVariant()!); + } + + this._nativeObj!.passes = nativePasses; + this._nativeObj!.shaders = nativeShaders; } } } diff --git a/cocos/2d/renderer/mesh-buffer.ts b/cocos/2d/renderer/mesh-buffer.ts index 657f1b2d4cf..f080927e6e7 100644 --- a/cocos/2d/renderer/mesh-buffer.ts +++ b/cocos/2d/renderer/mesh-buffer.ts @@ -27,9 +27,8 @@ * @packageDocumentation * @module ui */ -import { BufferUsageBit, MemoryUsageBit, InputAssemblerInfo, Attribute, Buffer, BufferInfo } from '../../core/gfx'; +import { BufferUsageBit, MemoryUsageBit, InputAssemblerInfo, Attribute, Buffer, BufferInfo, InputAssembler } from '../../core/gfx'; import { Batcher2D } from './batcher-2d'; -import { InputAssemblerHandle, NULL_HANDLE, IAPool } from '../../core/renderer/core/memory-pools'; import { getComponentPerVertex } from './vertex-format'; export class MeshBuffer { @@ -64,7 +63,7 @@ export class MeshBuffer { private _initVDataCount = 0; private _initIDataCount = 256 * 6; private _outOfCallback: ((...args: number[]) => void) | null = null; - private _hInputAssemblers: InputAssemblerHandle[] = []; + private _hInputAssemblers: InputAssembler[] = []; private _nextFreeIAHandle = 0; constructor (batcher: Batcher2D) { @@ -165,28 +164,27 @@ export class MeshBuffer { this._indexBuffer = null!; for (let i = 0; i < this._hInputAssemblers.length; i++) { - IAPool.free(this._hInputAssemblers[i]); + this._hInputAssemblers[i].destroy(); } this._hInputAssemblers.length = 0; } - public recordBatch (): InputAssemblerHandle { + public recordBatch (): InputAssembler | null { const vCount = this.indicesOffset - this.indicesStart; if (!vCount) { - return NULL_HANDLE as InputAssemblerHandle; + return null; } if (this._hInputAssemblers.length <= this._nextFreeIAHandle) { - this._hInputAssemblers.push(IAPool.alloc(this._batcher.device, this._iaInfo)); + this._hInputAssemblers.push(this._batcher.device.createInputAssembler(this._iaInfo)); } - const hIA = this._hInputAssemblers[this._nextFreeIAHandle++]; + const ia = this._hInputAssemblers[this._nextFreeIAHandle++]; - const ia = IAPool.get(hIA); ia.firstIndex = this.indicesStart; ia.indexCount = vCount; - return hIA; + return ia; } public uploadBuffers () { diff --git a/cocos/3d/models/baked-skinning-model.ts b/cocos/3d/models/baked-skinning-model.ts index 2002d7b77fa..e071ce0bfb0 100644 --- a/cocos/3d/models/baked-skinning-model.ts +++ b/cocos/3d/models/baked-skinning-model.ts @@ -43,8 +43,6 @@ import { IAnimInfo, IJointTextureHandle, jointTextureSamplerHash } from '../skel import { MorphModel } from './morph-model'; import { legacyCC } from '../../core/global-exports'; -import { AABBPool, AABBView } from '../../core/renderer/core/memory-pools'; - interface IJointsInfo { buffer: Buffer | null; jointTextureInfo: Float32Array; @@ -121,8 +119,6 @@ export class BakedSkinningModel extends MorphModel { const node = this.transform; // @ts-expect-error TS2339 skelBound.transform(node._mat, node._pos, node._rot, node._scale, worldBounds); - AABBPool.setVec3(this._hWorldBounds, AABBView.CENTER, worldBounds.center); - AABBPool.setVec3(this._hWorldBounds, AABBView.HALF_EXTENSION, worldBounds.halfExtents); } } diff --git a/cocos/3d/models/morph-model.ts b/cocos/3d/models/morph-model.ts index b96d5fb6196..f6d9bfac3ee 100644 --- a/cocos/3d/models/morph-model.ts +++ b/cocos/3d/models/morph-model.ts @@ -55,6 +55,11 @@ export class MorphModel extends Model { ); } + public destroy () { + super.destroy(); + this._morphRenderingInstance = null; + } + public setSubModelMaterial (subModelIndex: number, material: Material) { return super.setSubModelMaterial(subModelIndex, this._launderMaterial(material)); } diff --git a/cocos/3d/models/skinning-model.ts b/cocos/3d/models/skinning-model.ts index 449cd82cbea..80cf4b68775 100644 --- a/cocos/3d/models/skinning-model.ts +++ b/cocos/3d/models/skinning-model.ts @@ -40,7 +40,6 @@ import { Node } from '../../core/scene-graph/node'; import { ModelType } from '../../core/renderer/scene/model'; import { uploadJointData } from '../skeletal-animation/skeletal-animation-utils'; import { MorphModel } from './morph-model'; -import { AABBPool, AABBView } from '../../core/renderer/core/memory-pools'; import { deleteTransform, getTransform, getWorldMatrix, IJointTransform } from '../../core/animation/skeletal-animation-utils'; import { IMacroPatch } from '../../core/renderer'; @@ -155,8 +154,7 @@ export class SkinningModel extends MorphModel { AABB.fromPoints(this._modelBounds, v3_min, v3_max); // @ts-expect-error TS2445 this._modelBounds.transform(root._mat, root._pos, root._rot, root._scale, this._worldBounds); - AABBPool.setVec3(this._hWorldBounds, AABBView.CENTER, worldBounds.center); - AABBPool.setVec3(this._hWorldBounds, AABBView.HALF_EXTENSION, worldBounds.halfExtents); + this._updateNativeWorldBounds(); } } diff --git a/cocos/3d/skeletal-animation/skeletal-animation-blending.ts b/cocos/3d/skeletal-animation/skeletal-animation-blending.ts index 3d3c41235bd..f9c3d5df6ea 100644 --- a/cocos/3d/skeletal-animation/skeletal-animation-blending.ts +++ b/cocos/3d/skeletal-animation/skeletal-animation-blending.ts @@ -30,29 +30,41 @@ import { Vec3, Quat } from '../../core/math'; import { Node } from '../../core/scene-graph'; -import { IValueProxyFactory } from '../../core/animation/value-proxy'; -import { assertIsNonNullable } from '../../core/data/utils/asserts'; import { AnimationState } from '../../core/animation/animation-state'; +import { IBoundTarget } from '../../core/animation/bound-target'; export class BlendStateBuffer { private _nodeBlendStates: Map = new Map(); - private _states = new Set(); - public ref (node: Node, property: BlendingProperty) { + public createWriter

( + node: Node, + property: P, + host: BlendStateWriterHost, + constants: boolean, + ): Omit, 'node' | 'property'> { + const propertyBlendState = this.ref(node, property); + return new BlendStateWriterInternal

( + node, + property, + propertyBlendState, + host, + constants, + ); + } + + public destroyWriter

(writer: BlendStateWriter

) { + const internal = writer as BlendStateWriterInternal

; + this.deRef(internal.node, internal.property); + } + + public ref

(node: Node, property: P): PropertyBlendStateTypeMap[P] { let nodeBlendState = this._nodeBlendStates.get(node); if (!nodeBlendState) { - nodeBlendState = { dirty: false, properties: {} }; + nodeBlendState = new NodeBlendState(); this._nodeBlendStates.set(node, nodeBlendState); } - let propertyBlendState = nodeBlendState.properties[property]; - if (!propertyBlendState) { - propertyBlendState = nodeBlendState.properties[property] = new PropertyBlendState( - nodeBlendState, - (isVec3Property(property) ? new Vec3() : new Quat()) as any, - ); - } - ++propertyBlendState.refCount; - return propertyBlendState; + const propertyBlendState = nodeBlendState.refProperty(property); + return propertyBlendState as PropertyBlendStateTypeMap[P]; } public deRef (node: Node, property: BlendingProperty) { @@ -60,213 +72,243 @@ export class BlendStateBuffer { if (!nodeBlendState) { return; } - const propertyBlendState = nodeBlendState.properties[property]; - if (!propertyBlendState) { - return; - } - --propertyBlendState.refCount; - if (propertyBlendState.refCount > 0) { - return; - } - delete nodeBlendState.properties[property]; - if (isEmptyNodeBlendState(nodeBlendState)) { + nodeBlendState.deRefProperty(property); + if (nodeBlendState.empty) { this._nodeBlendStates.delete(node); } } public apply () { this._nodeBlendStates.forEach((nodeBlendState, node) => { - if (!nodeBlendState.dirty) { - return; - } - nodeBlendState.dirty = false; - const { position, scale, rotation, eulerAngles } = nodeBlendState.properties; - let t: Vec3 | undefined; - let s: Vec3 | undefined; - let r: Quat | Vec3 | undefined; - let anyChanged = false; - if (position && position.weight !== 0) { - position.weight = 0; - t = position.value; - anyChanged = true; - } - if (scale && scale.weight !== 0) { - scale.weight = 0; - s = scale.value; - anyChanged = true; - } - - // Note: rotation and eulerAngles can not co-exist. - if (rotation && rotation.weight !== 0) { - rotation.weight = 0; - r = rotation.value; - anyChanged = true; - } - if (eulerAngles && eulerAngles.weight !== 0) { - eulerAngles.weight = 0; - r = eulerAngles.value; - anyChanged = true; - } - - if (anyChanged) { - node.setRTS(r, t, s); - } - }); - - this._states.forEach((state) => { - state.onBlendFinished(); + nodeBlendState.apply(node); }); } +} - public bindState (state: AnimationState) { - this._states.add(state); - } +export interface BlendStateWriterHost { + readonly weight: number; +} - public unbindState (state: AnimationState) { - this._states.delete(state); +class BlendStateWriterInternal

implements IBoundTarget { + constructor ( + private _node: Node, + private _property: P, + private _propertyBlendState: PropertyBlendStateTypeMap[P], + private _host: BlendStateWriterHost, + private _constants: boolean, + ) { } -} -export type IBlendStateWriter = IValueProxyFactory & { destroy: () => void }; + get node () { + return this._node; + } -export interface IBlendStateWriterHost { - readonly weight: number; - readonly enabled: boolean; -} + get property () { + return this._property; + } -export function createBlendStateWriter

( - blendState: BlendStateBuffer, - node: Node, - property: P, - host: IBlendStateWriterHost, - /** - * True if this writer will write constant value each time. - */ - constants: boolean, -): IBlendStateWriter { - const blendFunction: BlendFunction> = isVec3Property(property) ? additive3D as any : additiveQuat as any; - let propertyBlendState: PropertyBlendState> | null = blendState.ref(node, property); - let isConstCacheValid = false; - let lastWeight = -1; - return { - destroy () { - assertIsNonNullable(propertyBlendState); - if (propertyBlendState) { - blendState.deRef(node, property); - propertyBlendState = null; - } - }, - forTarget: () => ({ - /** - * Gets the node's actual property for now. - */ - get: () => node[property], - set: (value: BlendingPropertyValue

) => { - if (!propertyBlendState || !host.enabled) { - return; - } - const weight = host.weight; - if (constants) { - if (weight !== 1 - || weight !== lastWeight) { - // If there are multi writer for this property at this time, - // or if the weight has been changed since last write, - // we should invalidate the cache. - isConstCacheValid = false; - } else if (isConstCacheValid) { - // Otherwise, we may keep to use the cache. - // i.e we leave the weight to 0 to prevent the property from modifying. - return; - } - } - blendFunction(value, weight, propertyBlendState); - propertyBlendState.weight += weight; - propertyBlendState.markAsDirty(); - isConstCacheValid = true; - lastWeight = weight; - }, - }), - }; -} + public getValue () { + return this._node[this._property]; + } -function isQuatProperty (property: BlendingProperty) { - return property === 'rotation'; + public setValue (value: BlendingPropertyValue

) { + const { + _propertyBlendState: propertyBlendState, + _host: host, + } = this; + const weight = host.weight; + // @ts-expect-error Complex typing + propertyBlendState.blend(value, weight); + } } -function isVec3Property (property: BlendingProperty) { - return !isQuatProperty(property); -} +export type BlendStateWriter

= Omit, 'node' | 'property'>; -type BlendingProperty = keyof NodeBlendState['properties']; +type BlendingProperty = keyof NodeBlendState['_properties']; -type BlendingPropertyValue

= NonNullable['value']; +type BlendingPropertyValue

= NonNullable['blendedValue']; class PropertyBlendState { - public weight = 0; - public value: T; + /** + * Sum of all weights to blend. + */ + public blendedWeight = 0.0; + + /** + * Current blended value. + */ + public blendedValue: T; /** * How many writer reference this property. */ public refCount = 0; - private _node: NodeBlendState; + constructor (value: T) { + this.blendedValue = value; + } +} + +class Vec3PropertyBlendState extends PropertyBlendState { + constructor () { + super(new Vec3()); + } - constructor (node: NodeBlendState, value: T) { - this._node = node; - this.value = value; + public blend (value: Readonly, weight: number) { + const { blendedValue } = this; + if (weight === 1.0) { + Vec3.copy(blendedValue, value); + } else { + Vec3.scaleAndAdd(blendedValue, blendedValue, value, weight); + } + this.blendedWeight += weight; } - public markAsDirty () { - this._node.dirty = true; + public reset () { + this.blendedWeight = 0.0; + Vec3.zero(this.blendedValue); } } -interface NodeBlendState { - dirty: boolean; - properties: { - position?: PropertyBlendState; - rotation?: PropertyBlendState; - eulerAngles?: PropertyBlendState; - scale?: PropertyBlendState; - }; -} +class QuatPropertyBlendState extends PropertyBlendState { + constructor () { + super(new Quat()); + } + + public blend (value: Readonly, weight: number) { + const { blendedValue, blendedWeight } = this; + if (weight === 1.0) { + Quat.copy(blendedValue, value); + } else { + const t = weight / (blendedWeight + weight); + Quat.slerp(blendedValue, blendedValue, value, t); + } + this.blendedWeight += weight; + } -function isEmptyNodeBlendState (nodeBlendState: NodeBlendState) { - // Which is equal to `Object.keys(nodeBlendState.properties).length === 0`. - return !nodeBlendState.properties.position - && !nodeBlendState.properties.rotation - && !nodeBlendState.properties.eulerAngles - && !nodeBlendState.properties.scale; + public reset () { + this.blendedWeight = 0.0; + Quat.identity(this.blendedValue); + } } -/** - * If propertyBlendState.weight equals to zero, the propertyBlendState.value is dirty. - * You shall handle this situation correctly. - */ -type BlendFunction = (value: T, weight: number, propertyBlendState: PropertyBlendState) => T; +interface PropertyBlendStateTypeMap { + 'rotation': QuatPropertyBlendState; + 'position': Vec3PropertyBlendState; + 'scale': Vec3PropertyBlendState; + 'eulerAngles': Vec3PropertyBlendState; +} -function additive3D (value: Vec3, weight: number, propertyBlendState: PropertyBlendState) { - if (propertyBlendState.weight === 0) { - Vec3.zero(propertyBlendState.value); +class NodeBlendState { + get empty () { + const { _properties: properties } = this; + return !properties.position + && !properties.rotation + && !properties.eulerAngles + && !properties.scale; } - if (weight === 0) { - return propertyBlendState.value; - } else if (weight === 1) { - return Vec3.copy(propertyBlendState.value, value); + + public refProperty

(property: BlendingProperty): PropertyBlendStateTypeMap[P] { + const { _properties: properties } = this; + let propertyBlendState: Vec3PropertyBlendState | QuatPropertyBlendState; + switch (property) { + default: + case 'position': + case 'scale': + case 'eulerAngles': + propertyBlendState = properties[property] ??= new Vec3PropertyBlendState(); + break; + case 'rotation': + propertyBlendState = properties[property] ??= new QuatPropertyBlendState(); + break; + } + ++propertyBlendState.refCount; + return propertyBlendState as PropertyBlendStateTypeMap[P]; } - return Vec3.scaleAndAdd(propertyBlendState.value, propertyBlendState.value, value, weight); -} -function additiveQuat (value: Quat, weight: number, propertyBlendState: PropertyBlendState) { - if (propertyBlendState.weight === 0) { - Quat.identity(propertyBlendState.value); + public deRefProperty (property: BlendingProperty) { + const { _properties: properties } = this; + + const propertyBlendState = properties[property]; + if (!propertyBlendState) { + return; + } + + --propertyBlendState.refCount; + if (propertyBlendState.refCount > 0) { + return; + } + + delete properties[property]; } - if (weight === 0) { - return propertyBlendState.value; - } else if (weight === 1) { - return Quat.copy(propertyBlendState.value, value); + + public apply (node: Node) { + const { _properties: { position, scale, rotation, eulerAngles } } = this; + + let t: Vec3 | undefined; + let s: Vec3 | undefined; + let r: Quat | Vec3 | undefined; + + let tFlags = false; + let sFlags = false; + let rFlags = false; + let eFlags = false; + + if (position && position.blendedWeight) { + tFlags = true; + if (position.blendedWeight < 1.0) { + position.blend(node.position, 1.0 - position.blendedWeight); + } + t = position.blendedValue; + } + + if (scale && scale.blendedWeight) { + sFlags = true; + if (scale.blendedWeight < 1.0) { + scale.blend(node.scale, 1.0 - scale.blendedWeight); + } + s = scale.blendedValue; + } + + if (eulerAngles && eulerAngles.blendedWeight) { + eFlags = true; + if (eulerAngles.blendedWeight < 1.0) { + eulerAngles.blend(node.eulerAngles, 1.0 - eulerAngles.blendedWeight); + } + r = eulerAngles.blendedValue; + } + + if (rotation && rotation.blendedWeight) { + rFlags = true; + if (rotation.blendedWeight < 1.0) { + rotation.blend(node.rotation, 1.0 - rotation.blendedWeight); + } + r = rotation.blendedValue; + } + + if (r || t || s) { + node.setRTS(r, t, s); + } + + // Reset transforms + if (tFlags) { + position!.reset(); + } + if (sFlags) { + scale!.reset(); + } + if (rFlags) { + rotation!.reset(); + } + if (eFlags) { + eulerAngles!.reset(); + } } - const t = weight / (propertyBlendState.weight + weight); - return Quat.slerp(propertyBlendState.value, propertyBlendState.value, value, t); + + private _properties: { + position?: PropertyBlendStateTypeMap['position']; + rotation?: PropertyBlendStateTypeMap['rotation']; + eulerAngles?: PropertyBlendStateTypeMap['eulerAngles']; + scale?: PropertyBlendStateTypeMap['scale']; + } = {}; } diff --git a/cocos/3d/skeletal-animation/skeletal-animation-state.ts b/cocos/3d/skeletal-animation/skeletal-animation-state.ts index 5092542732c..929467c1d0c 100644 --- a/cocos/3d/skeletal-animation/skeletal-animation-state.ts +++ b/cocos/3d/skeletal-animation/skeletal-animation-state.ts @@ -154,7 +154,7 @@ export class SkeletalAnimationState extends AnimationState { } else if (downstream) { // fallback to default pose if no animation curve can be found upstream mat = downstream; } else { // bottom line: render the original mesh as-is - mat = Mat4.IDENTITY; + mat = new Mat4(); } const tfm = { pos: new Vec3(), rot: new Quat(), scale: new Vec3() }; Mat4.toRTS(mat, tfm.rot, tfm.pos, tfm.scale); diff --git a/cocos/3d/skeletal-animation/skeletal-animation-utils.ts b/cocos/3d/skeletal-animation/skeletal-animation-utils.ts index 28966d9d1a8..20ee03f893e 100644 --- a/cocos/3d/skeletal-animation/skeletal-animation-utils.ts +++ b/cocos/3d/skeletal-animation/skeletal-animation-utils.ts @@ -55,7 +55,7 @@ export function selectJointsMediumFormat (device: Device): Format { } // Linear Blending Skinning -function uploadJointDataLBS (out: Float32Array, base: number, mat: Mat4, firstBone: boolean) { +function uploadJointDataLBS (out: Float32Array, base: number, mat: Readonly, firstBone: boolean) { out[base + 0] = mat.m00; out[base + 1] = mat.m01; out[base + 2] = mat.m02; diff --git a/cocos/audio/audio-source.ts b/cocos/audio/audio-source.ts index 6a527a83f02..d3e2c6f7236 100644 --- a/cocos/audio/audio-source.ts +++ b/cocos/audio/audio-source.ts @@ -36,6 +36,11 @@ import { clamp } from '../core/math'; import { AudioClip } from './audio-clip'; import { audioManager } from './audio-manager'; +enum AudioSourceEventType { + STARTED = 'started', + ENDED = 'ended', +} + /** * @en * A representation of a single audio source,
@@ -52,6 +57,8 @@ export class AudioSource extends Component { } public static AudioState = AudioState; + public static EventType = AudioSourceEventType; + @type(AudioClip) protected _clip: AudioClip | null = null; protected _player: AudioPlayer | null = null; @@ -119,6 +126,7 @@ export class AudioSource extends Component { this._player = player; player.onEnded(() => { audioManager.removePlaying(player); + this.node.emit(AudioSourceEventType.ENDED, this); }); player.onInterruptionBegin(() => { audioManager.removePlaying(player); @@ -229,6 +237,7 @@ export class AudioSource extends Component { } this._player?.play().then(() => { audioManager.addPlaying(this._player!); + this.node.emit(AudioSourceEventType.STARTED, this); }).catch((e) => {}); } diff --git a/cocos/core/algorithm/move.ts b/cocos/core/algorithm/move.ts new file mode 100644 index 00000000000..cd541ca0433 --- /dev/null +++ b/cocos/core/algorithm/move.ts @@ -0,0 +1,27 @@ +import { assertsArrayIndex } from '../data/utils/asserts'; + +/** + * Moves an array element to new location. + * @param array The array. + * @param index Index to the array element to move. + * @param newIndex New array index it should have. + */ +export function move (array: T[], index: number, newIndex: number) { + assertsArrayIndex(array, index); + assertsArrayIndex(array, newIndex); + if (index === newIndex) { + return array; + } + const element = array[index]; + if (index < newIndex) { // Shift right + for (let iElement = index + 1; iElement <= newIndex; ++iElement) { + array[iElement - 1] = array[iElement]; + } + } else { // Shift left + for (let iElement = index; iElement !== newIndex; --iElement) { + array[iElement] = array[iElement - 1]; + } + } + array[newIndex] = element; + return array; +} diff --git a/cocos/core/animation/animation-state.ts b/cocos/core/animation/animation-state.ts index b56e44fdbef..361037e0ba4 100644 --- a/cocos/core/animation/animation-state.ts +++ b/cocos/core/animation/animation-state.ts @@ -36,11 +36,11 @@ import { createBoundTarget, createBufferedTarget, IBufferedTarget, IBoundTarget import { Playable } from './playable'; import { WrapMode, WrapModeMask, WrappedInfo } from './types'; import { HierarchyPath, evaluatePath, TargetPath } from './target-path'; -import { BlendStateBuffer, createBlendStateWriter, IBlendStateWriter } from '../../3d/skeletal-animation/skeletal-animation-blending'; +import { BlendStateBuffer, BlendStateWriter } from '../../3d/skeletal-animation/skeletal-animation-blending'; import { legacyCC } from '../global-exports'; import { ccenum } from '../value-types/enum'; import { IValueProxyFactory } from './value-proxy'; -import { assertIsTrue } from '../data/utils/asserts'; +import { assertIsNonNullable, assertIsTrue } from '../data/utils/asserts'; import { debug } from '../platform/debug'; /** @@ -326,7 +326,14 @@ export class AnimationState extends Playable { /** * The weight. */ - public weight = 0; + get weight () { + return this._weight; + } + + set weight (value) { + this._weight = value; + this._blendStateWriterHost.weight = value; + } public frameRate = 0; @@ -367,15 +374,15 @@ export class AnimationState extends Playable { private _lastWrapInfoEvent: WrappedInfo | null = null; private _wrappedInfo = new WrappedInfo(); private _blendStateBuffer: BlendStateBuffer | null = null; - private _blendStateWriters: IBlendStateWriter[] = []; + private _blendStateWriters: BlendStateWriter[] = []; private _allowLastFrame = false; private _blendStateWriterHost = { weight: 0, - enabled: false, }; private _playbackRange: { min: number; max: number; }; private _playbackDuration = 0; private _invDuration = 1.0; + private _weight = 0.0; constructor (clip: AnimationClip, name = '') { super(); @@ -404,9 +411,6 @@ export class AnimationState extends Playable { this._destroyBlendStateWriters(); this._samplerSharedGroups.length = 0; this._blendStateBuffer = legacyCC.director.getAnimationManager()?.blendState ?? null; - if (this._blendStateBuffer) { - this._blendStateBuffer.bindState(this); - } this._targetNode = root; const clip = this._clip; @@ -430,41 +434,37 @@ export class AnimationState extends Playable { /** * Create the bound target. Especially optimized for skeletal case. */ - const createBoundTargetOptimized = ( - createFn: (...args: Parameters) => BoundTargetT | null, + const createBoundTargetOptimized = ( rootTarget: any, path: TargetPath[], valueAdapter: IValueProxyFactory | undefined, isConstant: boolean, - ): BoundTargetT | null => { + ): IBoundTarget | null => { if (!clip.enableTrsBlending || !isTargetingTRS(path) || !this._blendStateBuffer) { - return createFn(rootTarget, path, valueAdapter); + return createBoundTarget(rootTarget, path, valueAdapter); } else { const targetNode = evaluatePath(rootTarget, ...path.slice(0, path.length - 1)); if (targetNode !== null && targetNode instanceof Node) { const propertyName = path[path.length - 1] as 'position' | 'rotation' | 'scale' | 'eulerAngles'; - const blendStateWriter = createBlendStateWriter( - this._blendStateBuffer, + const blendStateWriter = this._blendStateBuffer.createWriter( targetNode, propertyName, this._blendStateWriterHost, isConstant, ); this._blendStateWriters.push(blendStateWriter); - return createFn(rootTarget, [], blendStateWriter); + return blendStateWriter; } } return null; }; this._commonTargetStatuses = clip.commonTargets.map((commonTarget, index) => { - const target = createBoundTargetOptimized( - createBufferedTarget, - root, - commonTarget.modifiers, - commonTarget.valueAdapter, - false, - ); + const boundTarget = createBoundTargetOptimized(root, commonTarget.modifiers, commonTarget.valueAdapter, false); + if (!boundTarget) { + return null; + } + const target = createBufferedTarget(boundTarget); if (target === null) { return null; } else { @@ -501,7 +501,6 @@ export class AnimationState extends Playable { } const boundTarget = createBoundTargetOptimized( - createBoundTarget, rootTarget, propertyCurve.modifiers, propertyCurve.valueAdapter, @@ -526,13 +525,6 @@ export class AnimationState extends Playable { this._destroyBlendStateWriters(); } - /** - * @private - */ - public onBlendFinished () { - this._blendStateWriterHost.enabled = false; - } - /** * @deprecated Since V1.1.1, animation states were no longer defined as event targets. * To process animation events, use `Animation` instead. @@ -679,9 +671,6 @@ export class AnimationState extends Playable { } protected _sampleCurves (ratio: number) { - this._blendStateWriterHost.weight = this.weight; - this._blendStateWriterHost.enabled = true; - const commonTargetStatuses = this._commonTargetStatuses; // Before we sample, we pull values of common targets. for (let iCommonTarget = 0, length = commonTargetStatuses.length; iCommonTarget < length; ++iCommonTarget) { @@ -1001,15 +990,16 @@ export class AnimationState extends Playable { } private _destroyBlendStateWriters () { + if (this._blendStateWriters.length) { + assertIsNonNullable(this._blendStateBuffer); + } for (let iBlendStateWriter = 0; iBlendStateWriter < this._blendStateWriters.length; ++iBlendStateWriter) { - this._blendStateWriters[iBlendStateWriter].destroy(); + this._blendStateBuffer!.destroyWriter(this._blendStateWriters[iBlendStateWriter]); } this._blendStateWriters.length = 0; if (this._blendStateBuffer) { - this._blendStateBuffer.unbindState(this); this._blendStateBuffer = null; } - this._blendStateWriterHost.enabled = false; } } diff --git a/cocos/core/animation/bound-target.ts b/cocos/core/animation/bound-target.ts index 4669e386da5..ed7eb1d5969 100644 --- a/cocos/core/animation/bound-target.ts +++ b/cocos/core/animation/bound-target.ts @@ -87,8 +87,7 @@ export function createBoundTarget (target: any, modifiers: TargetPath[], valueAd } } -export function createBufferedTarget (target: any, modifiers: TargetPath[], valueAdapter?: IValueProxyFactory): null | IBufferedTarget { - const boundTarget = createBoundTarget(target, modifiers, valueAdapter); +export function createBufferedTarget (boundTarget: IBoundTarget): null | IBufferedTarget { if (boundTarget === null) { return null; } diff --git a/cocos/core/animation/cross-fade.ts b/cocos/core/animation/cross-fade.ts index c990841d053..1cc0aeb96b8 100644 --- a/cocos/core/animation/cross-fade.ts +++ b/cocos/core/animation/cross-fade.ts @@ -69,13 +69,6 @@ export class CrossFade extends Playable { } else { this._calculateWeights(deltaTime); } - - for (let iManagedState = 0; iManagedState < managedStates.length; ++iManagedState) { - const state = managedStates[iManagedState].state; - if (state && state.isMotionless) { - state.sample(); - } - } } /** diff --git a/cocos/core/assets/image-asset.ts b/cocos/core/assets/image-asset.ts index 3ac332c8c60..83500cc11da 100644 --- a/cocos/core/assets/image-asset.ts +++ b/cocos/core/assets/image-asset.ts @@ -35,7 +35,7 @@ import { Device, Feature } from '../gfx'; import { Asset } from './asset'; import { PixelFormat } from './asset-enum'; import { legacyCC } from '../global-exports'; -import { warnID, getError } from '../platform/debug'; +import { warnID } from '../platform/debug'; /** * @en Image source in memory @@ -56,6 +56,7 @@ export interface IMemoryImageSource { export type ImageSource = HTMLCanvasElement | HTMLImageElement | IMemoryImageSource | ImageBitmap; function isImageBitmap (imageSource: any): imageSource is ImageBitmap { + // eslint-disable-next-line @typescript-eslint/no-unsafe-return return legacyCC.sys.capabilities.imageBitmap && imageSource instanceof ImageBitmap; } @@ -149,29 +150,10 @@ export class ImageAsset extends Asset { return this.nativeUrl; } - /** - * @private - */ - set _texture (tex) { - this._tex = tex; - } - - get _texture () { - if (!this._tex) { - const tex = new legacyCC.Texture2D(); - tex.name = this.nativeUrl; - tex.image = this; - this._tex = tex; - } - return this._tex; - } - private static extnames = ['.png', '.jpg', '.jpeg', '.bmp', '.webp', '.pvr', '.pkm', '.astc']; private _nativeData: ImageSource; - private _tex; - private _exportedExts: string[] | null | undefined = undefined; private _format: PixelFormat = PixelFormat.RGBA8888; @@ -246,6 +228,7 @@ export class ImageAsset extends Asset { // SERIALIZATION + // eslint-disable-next-line consistent-return public _serialize () { if (EDITOR || TEST) { let targetExtensions = this._exportedExts; @@ -359,6 +342,7 @@ export class ImageAsset extends Asset { function _getGlobalDevice (): Device | null { if (legacyCC.director.root) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-return return legacyCC.director.root.device; } return null; diff --git a/cocos/core/assets/material.ts b/cocos/core/assets/material.ts index 220e8261a4b..9dc71d5df59 100644 --- a/cocos/core/assets/material.ts +++ b/cocos/core/assets/material.ts @@ -35,11 +35,11 @@ import { RenderTexture } from './render-texture'; import { RenderableComponent } from '../components/renderable-component'; import { Texture } from '../gfx'; import { TextureBase } from './texture-base'; -import { builtinResMgr } from '../builtin/builtin-res-mgr'; import { legacyCC } from '../global-exports'; import { IPassInfoFull, Pass, PassOverrides } from '../renderer/core/pass'; import { MacroRecord, MaterialProperty, PropertyType } from '../renderer/core/pass-utils'; import { Color } from '../math/color'; +import { warnID } from '../platform/debug'; /** * @en The basic infos for material initialization. @@ -190,6 +190,11 @@ export class Material extends Asset { * @param info Material description info. */ public initialize (info: IMaterialInfo) { + if (this._passes.length) { + warnID(12005); + return; + } + if (!this._defines) { this._defines = []; } if (!this._states) { this._states = []; } if (!this._props) { this._props = []; } @@ -392,11 +397,6 @@ export class Material extends Asset { protected _update (keepProps = true) { if (this._effectAsset) { - if (this._passes && this._passes.length) { - for (const pass of this._passes) { - pass.destroy(); - } - } this._passes = this._createPasses(); // handle property values const totalPasses = this._effectAsset.techniques[this._techIdx].passes.length; @@ -466,11 +466,7 @@ export class Material extends Asset { pass.destroy(); } } - this._effectAsset = null; this._passes.length = 0; - this._props.length = 0; - this._defines.length = 0; - this._states.length = 0; } public initDefault (uuid?: string) { diff --git a/cocos/core/assets/rendering-sub-mesh.ts b/cocos/core/assets/rendering-sub-mesh.ts index 3faf0b8a31a..a4e0e85ca22 100644 --- a/cocos/core/assets/rendering-sub-mesh.ts +++ b/cocos/core/assets/rendering-sub-mesh.ts @@ -34,10 +34,6 @@ import { Attribute, Device, InputAssemblerInfo, Buffer, BufferInfo, AttributeName, BufferUsageBit, Format, FormatInfos, MemoryUsageBit, PrimitiveMode, getTypedArrayConstructor, } from '../gfx'; -import { - FlatBufferArrayPool, FlatBufferPool, FlatBufferView, NULL_HANDLE, RawBufferPool, - SubMeshHandle, SubMeshPool, SubMeshView, freeHandleArray, -} from '../renderer/core/memory-pools'; import { Vec3 } from '../math'; import { Mesh } from '../../3d/assets/mesh'; @@ -74,7 +70,7 @@ export interface IGeometricInfo { * @en The bounding box * @zh 此几何体的轴对齐包围盒。 */ - boundingBox: { max: Vec3; min: Vec3 }; + boundingBox: { max: Readonly; min: Readonly }; } /** @@ -118,7 +114,8 @@ export class RenderingSubMesh { private _iaInfo: InputAssemblerInfo; - private _handle: SubMeshHandle = NULL_HANDLE; + private _init () { + } constructor ( vertexBuffers: Buffer[], attributes: Attribute[], primitiveMode: PrimitiveMode, @@ -130,9 +127,7 @@ export class RenderingSubMesh { this._indirectBuffer = indirectBuffer; this._primitiveMode = primitiveMode; this._iaInfo = new InputAssemblerInfo(attributes, vertexBuffers, indexBuffer, indirectBuffer); - this._handle = SubMeshPool.alloc(); - const fbArrayHandle = FlatBufferArrayPool.alloc(); - SubMeshPool.set(this._handle, SubMeshView.FLAT_BUFFER_ARRAY, fbArrayHandle); + this._init(); } /** @@ -169,7 +164,7 @@ export class RenderingSubMesh { * @en The geometric info of the sub mesh, used for raycast. * @zh (用于射线检测的)几何信息。 */ - get geometricInfo () { + get geometricInfo (): IGeometricInfo { if (this._geometricInfo) { return this._geometricInfo; } @@ -226,7 +221,6 @@ export class RenderingSubMesh { const { mesh } = this; let idxCount = 0; const prim = mesh.struct.primitives[this.subMeshIdx]; - const fbArrayHandle = SubMeshPool.get(this._handle, SubMeshView.FLAT_BUFFER_ARRAY); if (prim.indexView) { idxCount = prim.indexView.count; } for (let i = 0; i < prim.vertexBundelIndices.length; i++) { const bundleIdx = prim.vertexBundelIndices[i]; @@ -235,16 +229,7 @@ export class RenderingSubMesh { const vbStride = vertexBundle.view.stride; const vbSize = vbStride * vbCount; const view = new Uint8Array(mesh.data.buffer, vertexBundle.view.offset, vertexBundle.view.length); - - const hBuffer = RawBufferPool.alloc(prim.indexView ? vbSize : vertexBundle.view.length); - const hFlatBuffer = FlatBufferPool.alloc(); - FlatBufferPool.set(hFlatBuffer, FlatBufferView.STRIDE, vbStride); - FlatBufferPool.set(hFlatBuffer, FlatBufferView.AMOUNT, vbCount); - FlatBufferPool.set(hFlatBuffer, FlatBufferView.BUFFER, hBuffer); - FlatBufferArrayPool.push(fbArrayHandle, hFlatBuffer); - - const buffer = RawBufferPool.getBuffer(hBuffer); - const sharedView = new Uint8Array(buffer); + const sharedView = new Uint8Array(prim.indexView ? vbSize : vertexBundle.view.length); if (!prim.indexView) { sharedView.set(mesh.data.subarray(vertexBundle.view.offset, vertexBundle.view.offset + vertexBundle.view.length)); @@ -320,10 +305,6 @@ export class RenderingSubMesh { get iaInfo () { return this._iaInfo; } - get handle () { - return this._handle; - } - public destroy () { for (let i = 0; i < this.vertexBuffers.length; i++) { this.vertexBuffers[i].destroy(); @@ -344,13 +325,6 @@ export class RenderingSubMesh { this._indirectBuffer.destroy(); this._indirectBuffer = null; } - if (this._handle) { - const fbArrayHandle = SubMeshPool.get(this._handle, SubMeshView.FLAT_BUFFER_ARRAY); - freeHandleArray(fbArrayHandle, FlatBufferArrayPool, FlatBufferPool); - - SubMeshPool.free(this._handle); - this._handle = NULL_HANDLE; - } } /** diff --git a/cocos/core/assets/texture-2d.ts b/cocos/core/assets/texture-2d.ts index 1e677176d96..0ff1e4d2c45 100644 --- a/cocos/core/assets/texture-2d.ts +++ b/cocos/core/assets/texture-2d.ts @@ -260,7 +260,6 @@ export class Texture2D extends SimpleTexture { } const mipmapUUID = data.mipmaps[i]; handle.result.push(this._mipmaps, `${i}`, mipmapUUID, js._getClassId(ImageAsset)); - this._mipmaps[i]._texture = this; } } diff --git a/cocos/core/builtin/builtin-res-mgr.ts b/cocos/core/builtin/builtin-res-mgr.ts index 669e71710f2..72dcbfa20e7 100644 --- a/cocos/core/builtin/builtin-res-mgr.ts +++ b/cocos/core/builtin/builtin-res-mgr.ts @@ -148,7 +148,9 @@ class BuiltinResMgr { if (legacyCC.SpriteFrame) { const spriteFrame = new legacyCC.SpriteFrame() as SpriteFrame; - const texture = imgAsset._texture; + const image = imgAsset; + const texture = new Texture2D(); + texture.image = image; spriteFrame.texture = texture; spriteFrame._uuid = 'default-spriteframe'; resources[spriteFrame._uuid] = spriteFrame; diff --git a/cocos/core/components/camera-component.ts b/cocos/core/components/camera-component.ts index b958578c603..fd48d8b1580 100644 --- a/cocos/core/components/camera-component.ts +++ b/cocos/core/components/camera-component.ts @@ -482,7 +482,7 @@ export class Camera extends Component { return out; } - public worldToScreen (worldPos: Vec3, out?: Vec3) { + public worldToScreen (worldPos: Readonly, out?: Vec3) { if (!out) { out = new Vec3(); } if (this._camera) { this._camera.worldToScreen(out, worldPos); } return out; @@ -508,7 +508,7 @@ export class Camera extends Component { * uiNode.position = out; * ``` */ - public convertToUINode (wpos: Vec3, uiNode: Node, out?: Vec3) { + public convertToUINode (wpos: Readonly, uiNode: Node, out?: Vec3) { if (!out) { out = new Vec3(); } diff --git a/cocos/core/data/editor-extendable.ts b/cocos/core/data/editor-extendable.ts new file mode 100644 index 00000000000..04bc947f95d --- /dev/null +++ b/cocos/core/data/editor-extendable.ts @@ -0,0 +1,60 @@ +import { EDITOR } from 'internal:constants'; +import { js } from '../utils/js'; +import { CCClass } from './class'; +import { EditorExtendableObject, editorExtrasTag } from './editor-extras-tag'; + +// Functions and classes exposed from this module are useful to +// make a class to be `EditorExtendableObject`. +// +// These helpers are used internally, don't expose them to user. + +/** + * Creates a mixin class which inherits from specific base class and implements the `EditorExtendableObject` interface. + * @param Base The base class. + * @param className Assign an optional cc class name. If the base class is not cc class, this param is required. + * @returns The mixin class. + */ +export function EditorExtendableMixin (Base: new (...args: any[]) => T, className?: string) { + return editorExtendableInternal(Base); +} + +/** + * Class which implements the `EditorExtendableObject` interface. + */ +export const EditorExtendable = editorExtendableInternal(); + +export type EditorExtendable = InstanceType; + +// eslint-disable-next-line @typescript-eslint/ban-types +function editorExtendableInternal (Base?: (new (...args: any[]) => T), className?: string) { + type ResultType = new (...args: any[]) => (T & EditorExtendableObject); + + if (!EDITOR) { + return (Base ?? Object) as unknown as ResultType; + } + + let name: string; + if (className) { + name = className; + } else if (!Base) { + name = `cc.EditorExtendable`; + } else { + const baseName = js.getClassName(Base); + if (baseName) { + name = `cc.EditorExtendable/${baseName}`; + } else { + throw new Error(`You should supply a class name to EditorExtendable when mixin with ${Base.name}.`); + } + } + + const EditorExtendable = Base ? class EditorExtendable extends (Base as unknown as any) implements EditorExtendableObject { + public [editorExtrasTag]!: unknown; + } : class EditorExtendable implements EditorExtendableObject { + public [editorExtrasTag]!: unknown; + }; + + CCClass.fastDefine(name, EditorExtendable, { [editorExtrasTag]: {} }); + CCClass.Attr.setClassAttr(EditorExtendable, editorExtrasTag, 'editorOnly', true); + + return EditorExtendable as unknown as ResultType; +} diff --git a/cocos/core/data/editor-extras-tag.ts b/cocos/core/data/editor-extras-tag.ts new file mode 100644 index 00000000000..574ab8cd6e4 --- /dev/null +++ b/cocos/core/data/editor-extras-tag.ts @@ -0,0 +1,31 @@ +/** + * Tag to visit editor extras of an object. Never concern about its value please. + */ +export const editorExtrasTag = '__editorExtras__'; + +/** + * Engine classes with this kind of signatures are integrated with editor extendability. + */ +export interface EditorExtendableObject { + /** + * The editor extras on this object. + * + * BE CAREFUL: this property is currently governed by Cocos Creator Editor. + * Its definition is not visible and is unknown to both engine code or users codes, + * they SHALL NOT operates it. + * + * You should use editor extras tag to visit this property. + * @example + * ```ts + * import { editorExtrasTag } from 'cc'; + * node[editorExtrasTag] = {}; + * node[editorExtrasTag].someWhat; + * ``` + * Even if you know `editorExtrasTag === '__editorExtras__'` in current, + * don't access the property through that: + * ```ts + * node.__editorExtras__ = {}; // Error: might be break in future. + * ``` + */ + [editorExtrasTag]: unknown; +} diff --git a/cocos/core/data/index.ts b/cocos/core/data/index.ts index d0818872a38..61d976f9935 100644 --- a/cocos/core/data/index.ts +++ b/cocos/core/data/index.ts @@ -40,3 +40,4 @@ export { Details } from './deserialize'; export { instantiate } from './instantiate'; export { CCInteger, CCFloat, CCBoolean, CCString } from './utils/attribute'; export { CompactValueTypeArray } from './utils/compact-value-type-array'; +export { editorExtrasTag } from './editor-extras-tag'; diff --git a/cocos/core/data/object.ts b/cocos/core/data/object.ts index d7fe2b1a14a..05a3452b154 100644 --- a/cocos/core/data/object.ts +++ b/cocos/core/data/object.ts @@ -33,6 +33,7 @@ import * as js from '../utils/js'; import { CCClass } from './class'; import { errorID, warnID } from '../platform/debug'; import { legacyCC } from '../global-exports'; +import { EditorExtendableObject, editorExtrasTag } from './editor-extras-tag'; // definitions for CCObject.Flags @@ -168,7 +169,7 @@ function compileDestruct (obj, ctor) { * 大部分对象的基类。 * @private */ -class CCObject { +class CCObject implements EditorExtendableObject { public static _deferredDestroy () { const deleteCount = objectsToDestroy.length; for (let i = 0; i < deleteCount; ++i) { @@ -190,6 +191,8 @@ class CCObject { } } + public declare [editorExtrasTag]: unknown; + public _objFlags: number; protected _name: string; @@ -441,7 +444,8 @@ prototype._deserialize = null; // @ts-expect-error prototype._onPreDestroy = null; -CCClass.fastDefine('cc.Object', CCObject, { _name: '', _objFlags: 0 }); +CCClass.fastDefine('cc.Object', CCObject, { _name: '', _objFlags: 0, [editorExtrasTag]: {} }); +CCClass.Attr.setClassAttr(CCObject, editorExtrasTag, 'editorOnly', true); /** * Bit mask that controls object states. diff --git a/cocos/core/data/utils/asserts.ts b/cocos/core/data/utils/asserts.ts index f89ef8ff009..df7c16d1d75 100644 --- a/cocos/core/data/utils/asserts.ts +++ b/cocos/core/data/utils/asserts.ts @@ -44,3 +44,7 @@ export function assertIsTrue (expr: boolean, message?: string) { throw new Error(`Assertion failed: ${message ?? ''}`); } } + +export function assertsArrayIndex (array: T[], index: number) { + assertIsTrue(index >= 0 && index < array.length, `Array index ${index} out of bounds: [0, ${array.length})`); +} diff --git a/cocos/core/director.ts b/cocos/core/director.ts index 4a6fade71c0..6801178344b 100644 --- a/cocos/core/director.ts +++ b/cocos/core/director.ts @@ -906,7 +906,8 @@ export class Director extends EventTarget { this.emit(Director.EVENT_AFTER_DRAW); eventManager.frameUpdateListeners(); - Node.clearBooks(); + Node.resetHasChangedFlags(); + Node.clearNodeArray(); this._totalFrames++; } } diff --git a/cocos/core/event/event.ts b/cocos/core/event/event.ts index 44f861aa476..d738b794204 100644 --- a/cocos/core/event/event.ts +++ b/cocos/core/event/event.ts @@ -30,6 +30,7 @@ */ import { legacyCC } from '../global-exports'; +import { DeviceEvent, KeyboardEvent, MouseEvent, SystemEventType, SystemEventTypeUnion, TouchEvent } from '../platform/event-manager/event-enum'; /** * @en @@ -47,6 +48,8 @@ export default class Event { * * @zh * 没有类型的事件。 + * + * @deprecated since v3.3, please use SystemEventType.NO_TYPE instead */ public static NO_TYPE = 'no_type'; @@ -56,6 +59,8 @@ export default class Event { * * @zh * 触摸事件类型。 + * + * @deprecated since v3.3, please use SystemEvent.TouchEvent.TOUCH_START, SystemEvent.TouchEvent.TOUCH_MOVE, SystemEvent.TouchEvent.TOUCH_END and SystemEvent.TouchEvent.TOUCH_CANCEL instead */ public static TOUCH = 'touch'; /** @@ -64,6 +69,8 @@ export default class Event { * * @zh * 鼠标事件类型。 + * + * @deprecated since v3.3, please use SystemEvent.MouseEvent.MOUSE_DOWN, SystemEvent.MouseEvent.MOUSE_MOVE, SystemEvent.MouseEvent.MOUSE_UP, SystemEvent.MouseEvent.MOUSE_WHEEL, Node.EventType.MOUSE_ENTER and Node.EventType.MOUSE_LEAVE instead */ public static MOUSE = 'mouse'; /** @@ -72,6 +79,8 @@ export default class Event { * * @zh * 键盘事件类型。 + * + * @deprecated since v3.3, please use SystemEvent.KeyboardEvent.KEY_DOWN and SystemEvent.KeyboardEvent.KEY_UP instead */ public static KEYBOARD = 'keyboard'; /** @@ -80,6 +89,8 @@ export default class Event { * * @zh * 加速器事件类型。 + * + * @deprecated since v3.3, please use SystemEvent.DeviceEvent.DEVICEMOTION instead */ public static ACCELERATION = 'acceleration'; @@ -126,12 +137,12 @@ export default class Event { /** * @en - * The name of the event (case-sensitive), e.g. "click", "fire", or "submit". + * The name of the event * * @zh * 事件类型。 */ - public type: string; + public type: SystemEventTypeUnion; /** * @en @@ -199,7 +210,7 @@ export default class Event { * @param type - The name of the event (case-sensitive), e.g. "click", "fire", or "submit" * @param bubbles - A boolean indicating whether the event bubbles up through the tree or not */ - constructor (type: string, bubbles?: boolean) { + constructor (type: SystemEventTypeUnion, bubbles?: boolean) { this.type = type; this.bubbles = !!bubbles; } @@ -212,7 +223,7 @@ export default class Event { * 重置事件对象以便在对象池中存储。 */ public unuse () { - this.type = Event.NO_TYPE; + this.type = SystemEventType.NO_TYPE; this.target = null; this.currentTarget = null; this.eventPhase = Event.NONE; @@ -228,7 +239,7 @@ export default class Event { * @param type - The name of the event (case-sensitive), e.g. "click", "fire", or "submit" * @param bubbles - A boolean indicating whether the event bubbles up through the tree or not */ - public reuse (type: string, bubbles?: boolean) { + public reuse (type: SystemEventTypeUnion, bubbles?: boolean) { this.type = type; this.bubbles = bubbles || false; } diff --git a/cocos/core/game.ts b/cocos/core/game.ts index 0bcb6f0a722..5c7f21b1d29 100644 --- a/cocos/core/game.ts +++ b/cocos/core/game.ts @@ -424,11 +424,7 @@ export class Game extends EventTarget { * @zh 退出游戏 */ public end () { - if (this._gfxDevice) { - this._gfxDevice.destroy(); - this._gfxDevice = null; - } - window.close(); + system.close(); } /** @@ -779,8 +775,18 @@ export class Game extends EventTarget { if (this.renderType === Game.RENDER_TYPE_WEBGL) { const ctors: Constructor[] = []; + const opts = new DeviceInfo( + this.canvas as HTMLCanvasElement, + EDITOR || macro.ENABLE_WEBGL_ANTIALIAS, + false, + window.devicePixelRatio, + sys.windowPixelResolution.width, + sys.windowPixelResolution.height, + bindingMappingInfo, + ); + if (JSB && window.gfx) { - this._gfxDevice = gfx.deviceInstance; + this._gfxDevice = gfx.DeviceManager.create(opts); } else { let useWebGL2 = (!!window.WebGL2RenderingContext); const userAgent = window.navigator.userAgent.toLowerCase(); @@ -796,15 +802,6 @@ export class Game extends EventTarget { ctors.push(legacyCC.WebGLDevice); } - const opts = new DeviceInfo( - this.canvas as HTMLCanvasElement, - EDITOR || macro.ENABLE_WEBGL_ANTIALIAS, - false, - window.devicePixelRatio, - sys.windowPixelResolution.width, - sys.windowPixelResolution.height, - bindingMappingInfo, - ); for (let i = 0; i < ctors.length; i++) { this._gfxDevice = new ctors[i](); if (this._gfxDevice.initialize(opts)) { break; } diff --git a/cocos/core/geometry/aabb.ts b/cocos/core/geometry/aabb.ts index 6271fc66909..cc22f2f7bc6 100644 --- a/cocos/core/geometry/aabb.ts +++ b/cocos/core/geometry/aabb.ts @@ -40,7 +40,7 @@ const _v3_tmp4 = new Vec3(); const _m3_tmp = new Mat3(); // https://zeuxcg.org/2010/10/17/aabb-from-obb-with-component-wise-abs/ -const transform_extent_m4 = (out: Vec3, extent: Vec3, m4: Mat4) => { +const transform_extent_m4 = (out: Vec3, extent: Vec3, m4: Readonly) => { _m3_tmp.m00 = Math.abs(m4.m00); _m3_tmp.m01 = Math.abs(m4.m01); _m3_tmp.m02 = Math.abs(m4.m02); _m3_tmp.m03 = Math.abs(m4.m04); _m3_tmp.m04 = Math.abs(m4.m05); _m3_tmp.m05 = Math.abs(m4.m06); _m3_tmp.m06 = Math.abs(m4.m08); _m3_tmp.m07 = Math.abs(m4.m09); _m3_tmp.m08 = Math.abs(m4.m10); @@ -48,53 +48,53 @@ const transform_extent_m4 = (out: Vec3, extent: Vec3, m4: Mat4) => { }; /** - * @en - * Basic Geometry: Axis-aligned bounding box, using center and half extents structure. - * @zh - * 基础几何 轴对齐包围盒,使用中心点和半长宽高的结构。 - */ + * @en + * Basic Geometry: Axis-aligned bounding box, using center and half extents structure. + * @zh + * 基础几何 轴对齐包围盒,使用中心点和半长宽高的结构。 + */ export class AABB { /** - * @en - * create a new AABB - * @zh - * 创建一个新的 AABB 实例。 - * @param px - AABB 的原点的 X 坐标。 - * @param py - AABB 的原点的 Y 坐标。 - * @param pz - AABB 的原点的 Z 坐标。 - * @param hw - AABB 宽度的一半。 - * @param hh - AABB 高度的一半。 - * @param hl - AABB 长度的一半。 - * @returns 返回新创建的 AABB 实例。 - */ + * @en + * create a new AABB + * @zh + * 创建一个新的 AABB 实例。 + * @param px - AABB 的原点的 X 坐标。 + * @param py - AABB 的原点的 Y 坐标。 + * @param pz - AABB 的原点的 Z 坐标。 + * @param hw - AABB 宽度的一半。 + * @param hh - AABB 高度的一半。 + * @param hl - AABB 长度的一半。 + * @returns 返回新创建的 AABB 实例。 + */ public static create (px?: number, py?: number, pz?: number, hw?: number, hh?: number, hl?: number) { return new AABB(px, py, pz, hw, hh, hl); } /** - * @en - * clone a new AABB - * @zh - * 克隆一个 AABB。 - * @param a - 克隆的目标。 - * @returns 克隆出的 AABB。 - */ - public static clone (a: AABB) { + * @en + * clone a new AABB + * @zh + * 克隆一个 AABB。 + * @param a - 克隆的目标。 + * @returns 克隆出的 AABB。 + */ + public static clone (a: Readonly) { return new AABB(a.center.x, a.center.y, a.center.z, a.halfExtents.x, a.halfExtents.y, a.halfExtents.z); } /** - * @en - * copy the values from one AABB to another - * @zh - * 将从一个 AABB 的值复制到另一个 AABB。 - * @param {AABB} out 接受操作的 AABB。 - * @param {AABB} a 被复制的 AABB。 - * @return {AABB} out 接受操作的 AABB。 - */ - public static copy (out: AABB, a: AABB): AABB { + * @en + * copy the values from one AABB to another + * @zh + * 将从一个 AABB 的值复制到另一个 AABB。 + * @param {AABB} out 接受操作的 AABB。 + * @param {AABB} a 被复制的 AABB。 + * @return {AABB} out 接受操作的 AABB。 + */ + public static copy (out: AABB, a: Readonly): AABB { Vec3.copy(out.center, a.center); Vec3.copy(out.halfExtents, a.halfExtents); @@ -102,16 +102,16 @@ export class AABB { } /** - * @en - * create a new AABB from two corner points - * @zh - * 从两个点创建一个新的 AABB。 - * @param out - 接受操作的 AABB。 - * @param minPos - AABB 的最小点。 - * @param maxPos - AABB 的最大点。 - * @returns {AABB} out 接受操作的 AABB。 - */ - public static fromPoints (out: AABB, minPos: IVec3Like, maxPos: IVec3Like): AABB { + * @en + * create a new AABB from two corner points + * @zh + * 从两个点创建一个新的 AABB。 + * @param out - 接受操作的 AABB。 + * @param minPos - AABB 的最小点。 + * @param maxPos - AABB 的最大点。 + * @returns {AABB} out 接受操作的 AABB。 + */ + public static fromPoints (out: AABB, minPos: Readonly, maxPos: Readonly): AABB { Vec3.add(_v3_tmp, maxPos, minPos); Vec3.subtract(_v3_tmp2, maxPos, minPos); Vec3.multiplyScalar(out.center, _v3_tmp, 0.5); @@ -120,19 +120,19 @@ export class AABB { } /** - * @en - * Set the components of a AABB to the given values - * @zh - * 将 AABB 的属性设置为给定的值。 - * @param {AABB} out 接受操作的 AABB。 - * @param px - AABB 的原点的 X 坐标。 - * @param py - AABB 的原点的 Y 坐标。 - * @param pz - AABB 的原点的 Z 坐标。 - * @param hw - AABB 宽度的一半。 - * @param hh - AABB 高度的一半。 - * @param hl - AABB 长度度的一半。 - * @return {AABB} out 接受操作的 AABB。 - */ + * @en + * Set the components of a AABB to the given values + * @zh + * 将 AABB 的属性设置为给定的值。 + * @param {AABB} out 接受操作的 AABB。 + * @param px - AABB 的原点的 X 坐标。 + * @param py - AABB 的原点的 Y 坐标。 + * @param pz - AABB 的原点的 Z 坐标。 + * @param hw - AABB 宽度的一半。 + * @param hh - AABB 高度的一半。 + * @param hl - AABB 长度度的一半。 + * @return {AABB} out 接受操作的 AABB。 + */ public static set (out: AABB, px: number, py: number, pz: number, hw: number, hh: number, hl: number): AABB { Vec3.set(out.center, px, py, pz); Vec3.set(out.halfExtents, hw, hh, hl); @@ -140,16 +140,16 @@ export class AABB { } /** - * @en - * Merge tow AABB. - * @zh - * 合并两个 AABB 到 out。 - * @param out 接受操作的 AABB。 - * @param a 输入的 AABB。 - * @param b 输入的 AABB。 - * @returns {AABB} out 接受操作的 AABB。 - */ - public static merge (out: AABB, a: AABB, b: AABB): AABB { + * @en + * Merge tow AABB. + * @zh + * 合并两个 AABB 到 out。 + * @param out 接受操作的 AABB。 + * @param a 输入的 AABB。 + * @param b 输入的 AABB。 + * @returns {AABB} out 接受操作的 AABB。 + */ + public static merge (out: AABB, a: Readonly, b: Readonly): AABB { Vec3.subtract(_v3_tmp, a.center, a.halfExtents); Vec3.subtract(_v3_tmp2, b.center, b.halfExtents); Vec3.add(_v3_tmp3, a.center, a.halfExtents); @@ -160,14 +160,14 @@ export class AABB { } /** - * @en - * AABB to sphere - * @zh - * 包围盒转包围球 - * @param out 接受操作的 sphere。 - * @param a 输入的 AABB。 - */ - public static toBoundingSphere (out: Sphere, a: AABB) { + * @en + * AABB to sphere + * @zh + * 包围盒转包围球 + * @param out 接受操作的 sphere。 + * @param a 输入的 AABB。 + */ + public static toBoundingSphere (out: Sphere, a: Readonly) { a.getBoundary(_v3_tmp, _v3_tmp2); // Initialize sphere @@ -187,96 +187,96 @@ export class AABB { } /** - * @en - * Transform this AABB. - * @zh - * 变换一个 AABB 到 out 中。 - * @param out 接受操作的 AABB。 - * @param a 输入的源 AABB。 - * @param matrix 矩阵。 - * @returns {AABB} out 接受操作的 AABB。 - */ - public static transform (out: AABB, a: AABB, matrix: Mat4): AABB { + * @en + * Transform this AABB. + * @zh + * 变换一个 AABB 到 out 中。 + * @param out 接受操作的 AABB。 + * @param a 输入的源 AABB。 + * @param matrix 矩阵。 + * @returns {AABB} out 接受操作的 AABB。 + */ + public static transform (out: AABB, a: Readonly, matrix: Readonly): AABB { Vec3.transformMat4(out.center, a.center, matrix); transform_extent_m4(out.halfExtents, a.halfExtents, matrix); return out; } - /** - * @zh - * 本地坐标的中心点。 - */ - public center: Vec3; + /** + * @zh + * 本地坐标的中心点。 + */ + public center: Vec3; - /** - * @zh - * 长宽高的一半。 - */ - public halfExtents: Vec3; + /** + * @zh + * 长宽高的一半。 + */ + public halfExtents: Vec3; - /** - * @en - * Gets the type of the shape. - * @zh - * 获取形状的类型。 - */ - get type () { - return this._type; - } + /** + * @en + * Gets the type of the shape. + * @zh + * 获取形状的类型。 + */ + get type () { + return this._type; + } - protected readonly _type: number; + protected readonly _type: number; - constructor (px = 0, py = 0, pz = 0, hw = 1, hh = 1, hl = 1) { - this._type = enums.SHAPE_AABB; - this.center = new Vec3(px, py, pz); - this.halfExtents = new Vec3(hw, hh, hl); - } + constructor (px = 0, py = 0, pz = 0, hw = 1, hh = 1, hl = 1) { + this._type = enums.SHAPE_AABB; + this.center = new Vec3(px, py, pz); + this.halfExtents = new Vec3(hw, hh, hl); + } - /** - * @en - * Get the bounding points of this shape - * @zh - * 获取 AABB 的最小点和最大点。 - * @param {Vec3} minPos 最小点。 - * @param {Vec3} maxPos 最大点。 - */ - public getBoundary (minPos: IVec3Like, maxPos: IVec3Like) { - Vec3.subtract(minPos, this.center, this.halfExtents); - Vec3.add(maxPos, this.center, this.halfExtents); - } + /** + * @en + * Get the bounding points of this shape + * @zh + * 获取 AABB 的最小点和最大点。 + * @param {Vec3} minPos 最小点。 + * @param {Vec3} maxPos 最大点。 + */ + public getBoundary (minPos: IVec3Like, maxPos: IVec3Like) { + Vec3.subtract(minPos, this.center, this.halfExtents); + Vec3.add(maxPos, this.center, this.halfExtents); + } - /** - * @en - * Transform this shape - * @zh - * 将 out 根据这个 AABB 的数据进行变换。 - * @param m 变换的矩阵。 - * @param pos 变换的位置部分。 - * @param rot 变换的旋转部分。 - * @param scale 变换的缩放部分。 - * @param out 变换的目标。 - */ - public transform (m: Mat4, pos: Vec3 | null, rot: Quat | null, scale: Vec3 | null, out: AABB) { - Vec3.transformMat4(out.center, this.center, m); - transform_extent_m4(out.halfExtents, this.halfExtents, m); - } + /** + * @en + * Transform this shape + * @zh + * 将 out 根据这个 AABB 的数据进行变换。 + * @param m 变换的矩阵。 + * @param pos 变换的位置部分。 + * @param rot 变换的旋转部分。 + * @param scale 变换的缩放部分。 + * @param out 变换的目标。 + */ + public transform (m: Mat4, pos: Vec3 | null, rot: Quat | null, scale: Vec3 | null, out: AABB) { + Vec3.transformMat4(out.center, this.center, m); + transform_extent_m4(out.halfExtents, this.halfExtents, m); + } - /** - * @zh - * 获得克隆。 - * @returns {AABB} - */ - public clone (): AABB { - return AABB.clone(this); - } + /** + * @zh + * 获得克隆。 + * @returns {AABB} + */ + public clone (): AABB { + return AABB.clone(this); + } - /** - * @zh - * 拷贝对象。 - * @param a 拷贝的目标。 - * @returns {AABB} - */ - public copy (a: AABB): AABB { - return AABB.copy(this, a); - } + /** + * @zh + * 拷贝对象。 + * @param a 拷贝的目标。 + * @returns {AABB} + */ + public copy (a: Readonly): AABB { + return AABB.copy(this, a); + } } diff --git a/cocos/core/geometry/frustum.ts b/cocos/core/geometry/frustum.ts index 838d36ad655..09b5538a789 100644 --- a/cocos/core/geometry/frustum.ts +++ b/cocos/core/geometry/frustum.ts @@ -29,7 +29,6 @@ */ import { Mat4, Vec3 } from '../math'; -import { FrustumHandle, FrustumPool, FrustumView, NULL_HANDLE } from '../renderer/core/memory-pools'; import enums from './enums'; import { Plane } from './plane'; @@ -240,30 +239,3 @@ export class Frustum { Plane.fromPoints(this.planes[0], this.vertices[7], this.vertices[6], this.vertices[5]); } } - -/** - * @en - * Record frustum to shared memory. - * @zh - * 记录 frustum 数据到共享内存。并不是每个 frustum 都是需要记录到共享内存的。 - * @param handle The frustum handle - * @param frstm The frustum object - */ -export function recordFrustumToSharedMemory (handle: FrustumHandle, frstm: Frustum) { - if (!frstm || handle === NULL_HANDLE) { - return; - } - - const vertices = frstm.vertices; - let vertexOffset = FrustumView.VERTICES as const; - for (let i = 0; i < 8; ++i) { - FrustumPool.setVec3(handle, vertexOffset, vertices[i]); - vertexOffset += 3; - } - - const planes = frstm.planes; - let planeOffset = FrustumView.PLANES as const; - for (let i = 0; i < 6; i++, planeOffset += 4) { - FrustumPool.setVec4(handle, planeOffset, planes[i]); - } -} diff --git a/cocos/core/geometry/sphere.ts b/cocos/core/geometry/sphere.ts index c799f4fcd4d..bc30c6dda9b 100644 --- a/cocos/core/geometry/sphere.ts +++ b/cocos/core/geometry/sphere.ts @@ -31,7 +31,6 @@ import { Mat4, Quat, Vec3 } from '../math'; import enums from './enums'; import { AABB } from './aabb'; -import { NULL_HANDLE, SphereHandle, SpherePool, SphereView } from '../renderer/core/memory-pools'; const _v3_tmp = new Vec3(); const _offset = new Vec3(); @@ -181,9 +180,10 @@ export class Sphere { set center (val:Vec3) { this._center = val; - SpherePool.setVec3(this._poolHandle, SphereView.CENTER, this._center); } + private _radius = 0; + /** * @en * The radius of this sphere. @@ -191,16 +191,11 @@ export class Sphere { * 半径。 */ get radius () : number { - return SpherePool.get(this._poolHandle, SphereView.RADIUS); + return this._radius; } set radius (val: number) { - SpherePool.set(this._poolHandle, SphereView.RADIUS, val); - } - - protected _poolHandle: SphereHandle = NULL_HANDLE; - get handle () { - return this._poolHandle; + this._radius = val; } /** @@ -228,16 +223,10 @@ export class Sphere { constructor (cx = 0, cy = 0, cz = 0, r = 1) { this._type = enums.SHAPE_SPHERE; this._center = new Vec3(cx, cy, cz); - this._poolHandle = SpherePool.alloc(); - SpherePool.setVec3(this._poolHandle, SphereView.CENTER, this._center); - SpherePool.set(this._poolHandle, SphereView.RADIUS, r); + this._radius = r; } public destroy () { - if (this._poolHandle) { - SpherePool.free(this._poolHandle); - this._poolHandle = NULL_HANDLE; - } } /** diff --git a/cocos/core/gfx/base/command-buffer.ts b/cocos/core/gfx/base/command-buffer.ts index 3762d7da441..e402e55e929 100644 --- a/cocos/core/gfx/base/command-buffer.ts +++ b/cocos/core/gfx/base/command-buffer.ts @@ -157,11 +157,14 @@ export abstract class CommandBuffer extends Obj { public abstract bindPipelineState (pipelineState: PipelineState): void; /** - * @en Bind descriptor set. - * @zh 绑定 GFX 描述符集。 + * @en Bind a descriptor set. Note that the corresponding PiplieneState has to be bound first + * before calling this function, or the dynamic offset specified may be invalidated. + * @zh 绑定 GFX 描述符集。注意在调用此函数前,必须先绑定对应的 PipelineState,否则 dynamic offset 可能无效。 + * @param set The target descriptor set index. * @param descriptorSet The descriptor set to be bound. + * @param dynamicOffsets The offset numbers for dynamic bindings. */ - public abstract bindDescriptorSet (set: number, descriptorSets: DescriptorSet, dynamicOffsets?: number[]): void; + public abstract bindDescriptorSet (set: number, descriptorSet: DescriptorSet, dynamicOffsets?: number[]): void; /** * @en Bind input assembler. @@ -205,7 +208,7 @@ export abstract class CommandBuffer extends Obj { * @zh 设置混合因子。 * @param blendConstants The new blend constants. */ - public abstract setBlendConstants (blendConstants: number[]): void; + public abstract setBlendConstants (blendConstants: Color): void; /** * @en Set depth bound. diff --git a/cocos/core/gfx/base/define.ts b/cocos/core/gfx/base/define.ts index 866d82d09c5..fbc04d5fb4a 100644 --- a/cocos/core/gfx/base/define.ts +++ b/cocos/core/gfx/base/define.ts @@ -601,9 +601,9 @@ export enum DynamicStateFlagBit { } export enum StencilFace { - FRONT, - BACK, - ALL, + FRONT = 0x1, + BACK = 0x2, + ALL = 0x3, } export enum DescriptorType { @@ -1646,6 +1646,56 @@ export class MemoryStatus { } } +export class DynamicStencilStates { + declare private _token: never; // to make sure all usages must be an instance of this exact class, not assembled from plain object + + constructor ( + public writeMask: number = 0, + public compareMask: number = 0, + public reference: number = 0, + ) {} + + public copy (info: DynamicStencilStates) { + this.writeMask = info.writeMask; + this.compareMask = info.compareMask; + this.reference = info.reference; + return this; + } +} + +export class DynamicStates { + declare private _token: never; // to make sure all usages must be an instance of this exact class, not assembled from plain object + + constructor ( + public viewport: Viewport = new Viewport(), + public scissor: Rect = new Rect(), + public blendConstant: Color = new Color(), + public lineWidth: number = 1, + public depthBiasConstant: number = 0, + public depthBiasClamp: number = 0, + public depthBiasSlope: number = 0, + public depthMinBounds: number = 0, + public depthMaxBounds: number = 0, + public stencilStatesFront: DynamicStencilStates = new DynamicStencilStates(), + public stencilStatesBack: DynamicStencilStates = new DynamicStencilStates(), + ) {} + + public copy (info: DynamicStates) { + this.viewport.copy(info.viewport); + this.scissor.copy(info.scissor); + this.blendConstant.copy(info.blendConstant); + this.lineWidth = info.lineWidth; + this.depthBiasConstant = info.depthBiasConstant; + this.depthBiasClamp = info.depthBiasClamp; + this.depthBiasSlope = info.depthBiasSlope; + this.depthMinBounds = info.depthMinBounds; + this.depthMaxBounds = info.depthMaxBounds; + this.stencilStatesFront.copy(info.stencilStatesFront); + this.stencilStatesBack.copy(info.stencilStatesBack); + return this; + } +} + /** * ========================= !DO NOT CHANGE THE ABOVE SECTION MANUALLY! ========================= * The above section is auto-generated from engine-native/cocos/renderer/core/gfx/GFXDef-common.h @@ -1678,8 +1728,8 @@ export class DeviceInfo { public isAntialias: boolean = true, public isPremultipliedAlpha: boolean = true, public devicePixelRatio: number = 1, - public nativeWidth: number = 1, - public nativeHeight: number = 1, + public width: number = 1, + public height: number = 1, /** * For non-vulkan backends, to maintain compatibility and maximize * descriptor cache-locality, descriptor-set-based binding numbers need diff --git a/cocos/core/gfx/base/descriptor-set.ts b/cocos/core/gfx/base/descriptor-set.ts index 2e40c97e816..c5012f27395 100644 --- a/cocos/core/gfx/base/descriptor-set.ts +++ b/cocos/core/gfx/base/descriptor-set.ts @@ -79,8 +79,6 @@ export abstract class DescriptorSet extends Obj { this._buffers[descriptorIndex + index] = buffer; this._isDirty = true; } - } else { - console.warn('Setting binding is not DescriptorType.UNIFORM_BUFFER.'); } } @@ -99,8 +97,6 @@ export abstract class DescriptorSet extends Obj { this._samplers[descriptorIndex + index] = sampler; this._isDirty = true; } - } else { - console.warn('Setting binding is not DescriptorType.SAMPLER.'); } } @@ -119,8 +115,6 @@ export abstract class DescriptorSet extends Obj { this._textures[descriptorIndex + index] = texture; this._isDirty = true; } - } else { - console.warn('Setting binding is not DescriptorType.SAMPLER.'); } } diff --git a/cocos/core/gfx/base/device.ts b/cocos/core/gfx/base/device.ts index 46045bcf876..ebd1edb5a06 100644 --- a/cocos/core/gfx/base/device.ts +++ b/cocos/core/gfx/base/device.ts @@ -122,22 +122,6 @@ export abstract class Device { return this._height; } - /** - * @en Device native width. - * @zh 设备原生的像素宽度。 - */ - get nativeWidth (): number { - return this._nativeWidth; - } - - /** - * @en Device native height. - * @zh 设备原生的像素高度。 - */ - get nativeHeight (): number { - return this._nativeHeight; - } - /** * @en Renderer description. * @zh 渲染器描述。 @@ -232,8 +216,6 @@ export abstract class Device { protected _devicePixelRatio = 1.0; protected _width = 0; protected _height = 0; - protected _nativeWidth = 0; - protected _nativeHeight = 0; protected _colorFmt = Format.UNKNOWN; protected _depthStencilFmt = Format.UNKNOWN; protected _numDrawCalls = 0; diff --git a/cocos/core/gfx/base/pipeline-state.ts b/cocos/core/gfx/base/pipeline-state.ts index 23de067d952..66d62763f10 100644 --- a/cocos/core/gfx/base/pipeline-state.ts +++ b/cocos/core/gfx/base/pipeline-state.ts @@ -50,7 +50,6 @@ import { Color, PipelineBindPoint, } from './define'; -import { NULL_HANDLE, RawBufferHandle } from '../../renderer/core/memory-pools'; /** * @en GFX rasterizer state. @@ -59,6 +58,10 @@ import { NULL_HANDLE, RawBufferHandle } from '../../renderer/core/memory-pools'; export class RasterizerState { declare private _token: never; // to make sure all usages must be an instance of this exact class, not assembled from plain object + get native () { + return this; + } + constructor ( public isDiscard: boolean = false, public polygonMode: PolygonMode = PolygonMode.FILL, @@ -93,8 +96,6 @@ export class RasterizerState { Object.assign(this, rs); } - get handle (): RawBufferHandle { return NULL_HANDLE; } - public destroy () {} } @@ -105,6 +106,9 @@ export class RasterizerState { export class DepthStencilState { declare private _token: never; // to make sure all usages must be an instance of this exact class, not assembled from plain object + get native () { + return this; + } constructor ( public depthTest: boolean = true, public depthWrite: boolean = true, @@ -153,8 +157,6 @@ export class DepthStencilState { Object.assign(this, dss); } - get handle (): RawBufferHandle { return NULL_HANDLE; } - public destroy () {} } @@ -191,8 +193,6 @@ export class BlendTarget { Object.assign(this, target); } - get handle (): RawBufferHandle { return NULL_HANDLE; } - public destroy () {} } @@ -203,6 +203,10 @@ export class BlendTarget { export class BlendState { declare private _token: never; // to make sure all usages must be an instance of this exact class, not assembled from plain object + get native () { + return this; + } + constructor ( public isA2C: boolean = false, public isIndepend: boolean = false, @@ -237,8 +241,6 @@ export class BlendState { this.targets[0].reset(); } - get handle (): RawBufferHandle { return NULL_HANDLE; } - public destroy () {} } diff --git a/cocos/core/gfx/index.jsb.ts b/cocos/core/gfx/index.jsb.ts index 755a84c0635..52deb7df2e3 100644 --- a/cocos/core/gfx/index.jsb.ts +++ b/cocos/core/gfx/index.jsb.ts @@ -68,7 +68,6 @@ polyfillCC.CommandBuffer = gfx.CommandBuffer; polyfillCC.Queue = gfx.Queue; legacyCC.gfx = polyfillCC; -export const Attribute = gfx.Attribute; // TODO: remove these after state info refactor export const BlendTarget = pso.BlendTarget; export const BlendState = pso.BlendState; diff --git a/cocos/core/gfx/pipeline-state.jsb.ts b/cocos/core/gfx/pipeline-state.jsb.ts index f06388cc72a..616f9624688 100644 --- a/cocos/core/gfx/pipeline-state.jsb.ts +++ b/cocos/core/gfx/pipeline-state.jsb.ts @@ -33,8 +33,8 @@ declare const gfx: any; declare type RecursivePartial = { [P in keyof T]?: - T[P] extends Array ? Array> : - T[P] extends ReadonlyArray ? ReadonlyArray> : RecursivePartial; + T[P] extends Array ? Array> : + T[P] extends ReadonlyArray ? ReadonlyArray> : RecursivePartial; }; import { @@ -48,13 +48,20 @@ import { StencilOp, Color, } from './base/define'; -import { BlendTargetArrayPool, NULL_HANDLE, BlendTargetArrayHandle, RasterizerStateHandle, RasterizerStatePool, RasterizerStateView, - DepthStencilStateHandle, DepthStencilStatePool, DepthStencilStateView, BlendTargetHandle, BlendTargetPool, BlendTargetView, - BlendStateHandle, BlendStatePool, BlendStateView } from '../renderer/core/memory-pools'; - export class RasterizerState { - private h: RasterizerStateHandle; - + protected _nativeObj; + protected _isDiscard: boolean = false; + protected _polygonMode: PolygonMode = PolygonMode.FILL; + protected _shadeModel: ShadeModel = ShadeModel.GOURAND; + protected _cullMode: CullMode = CullMode.BACK; + protected _isFrontFaceCCW: boolean = true; + protected _depthBiasEnabled: boolean = false; + protected _depthBias: number = 0; + protected _depthBiasClamp: number = 0.0; + protected _depthBiasSlop: number = 0.0; + protected _isDepthClip: boolean = true; + protected _isMultisample: boolean = false; + protected _lineWidth: number = 1.0; constructor ( isDiscard: boolean = false, polygonMode: PolygonMode = PolygonMode.FILL, @@ -69,51 +76,85 @@ export class RasterizerState { isMultisample: boolean = false, lineWidth: number = 1.0, ) { - this.h = RasterizerStatePool.alloc(); + this._nativeObj = new gfx.RasterizerState(); this.assignProperties(isDiscard, polygonMode, shadeModel, cullMode, isFrontFaceCCW, depthBiasEnabled, depthBias, depthBiasClamp, depthBiasSlop, isDepthClip, isMultisample, lineWidth); } + get native () { + return this._nativeObj; + } + get isDiscard (): boolean { - if (RasterizerStatePool.get(this.h, RasterizerStateView.IS_DISCARD)) return true; - else return false; - } - set isDiscard (val: boolean) { RasterizerStatePool.set(this.h, RasterizerStateView.IS_DISCARD, val ? 1 : 0) } - get polygonMode (): PolygonMode { return RasterizerStatePool.get(this.h, RasterizerStateView.POLYGO_MODEL); } - set polygonMode (val: PolygonMode) { RasterizerStatePool.set(this.h, RasterizerStateView.POLYGO_MODEL, val); } - get shadeModel (): ShadeModel { return RasterizerStatePool.get(this.h, RasterizerStateView.SHADE_MODEL); } - set shadeModel (val: ShadeModel) { RasterizerStatePool.set(this.h, RasterizerStateView.SHADE_MODEL, val); } - get cullMode (): CullMode { return RasterizerStatePool.get(this.h, RasterizerStateView.CULL_MODE); } - set cullMode (val: CullMode) { RasterizerStatePool.set(this.h, RasterizerStateView.CULL_MODE, val); } + return this._isDiscard; + } + set isDiscard (val: boolean) { + this._isDiscard = val; + this._nativeObj.isDiscard = val; + } + get polygonMode (): PolygonMode { return this._polygonMode; } + set polygonMode (val: PolygonMode) { + this._polygonMode = val; + this._nativeObj.polygonMode = val; + } + get shadeModel (): ShadeModel { return this._shadeModel; } + set shadeModel (val: ShadeModel) { + this._shadeModel = val; + this._nativeObj.shadeModel = val; + } + get cullMode (): CullMode { return this._cullMode; } + set cullMode (val: CullMode) { + this._cullMode = val; + this._nativeObj.cullMode = val; + } get isFrontFaceCCW (): boolean { - if (RasterizerStatePool.get(this.h, RasterizerStateView.IS_FRONT_FACE_CCW)) return true; - else return false; + return this._isFrontFaceCCW; + } + set isFrontFaceCCW (val: boolean) { + this._isFrontFaceCCW = val; + this._nativeObj.isFrontFaceCCW = val; } - set isFrontFaceCCW (val: boolean) { RasterizerStatePool.set(this.h, RasterizerStateView.IS_FRONT_FACE_CCW, val ? 1 : 0); } get depthBiasEnabled (): boolean { - if (RasterizerStatePool.get(this.h, RasterizerStateView.DEPTH_BIAS_ENABLED)) return true; - else return false; - } - set depthBiasEnabled (val: boolean) { RasterizerStatePool.set(this.h, RasterizerStateView.DEPTH_BIAS_ENABLED, val ? 1 : 0); } - get depthBias (): number { return RasterizerStatePool.get(this.h, RasterizerStateView.DEPTH_BIAS); } - set depthBias (val: number) { RasterizerStatePool.set(this.h, RasterizerStateView.DEPTH_BIAS, val); } - get depthBiasClamp (): number { return RasterizerStatePool.get(this.h, RasterizerStateView.DEPTH_BIAS_CLAMP); } - set depthBiasClamp (val: number) { RasterizerStatePool.set(this.h, RasterizerStateView.DEPTH_BIAS_CLAMP, val); } - get depthBiasSlop (): number { return RasterizerStatePool.get(this.h, RasterizerStateView.DEPTH_BIAS_SLOP); } - set depthBiasSlop (val: number) { RasterizerStatePool.set(this.h, RasterizerStateView.DEPTH_BIAS_SLOP, val); } + return this._depthBiasEnabled; + } + set depthBiasEnabled (val: boolean) { + this._depthBiasEnabled = val; + this._nativeObj.depthBiasEnabled = val; + } + get depthBias (): number { return this._depthBias; } + set depthBias (val: number) { + this._depthBias = val; + this._nativeObj.depthBias = val; + } + get depthBiasClamp (): number { return this._depthBiasClamp; } + set depthBiasClamp (val: number) { + this._depthBiasClamp = val; + this._nativeObj.depthBiasClamp = val; + } + get depthBiasSlop (): number { return this._depthBiasSlop; } + set depthBiasSlop (val: number) { + this._depthBiasSlop = val; + this._nativeObj.depthBiasSlop = val; + } get isDepthClip (): boolean { - if (RasterizerStatePool.get(this.h, RasterizerStateView.IS_DEPTH_CLIP)) return true; - else return false; + return this._isDepthClip; + } + set isDepthClip (val: boolean) { + this._isDepthClip = val; + this._nativeObj.isDepthClip = val; } - set isDepthClip (val: boolean) { RasterizerStatePool.set(this.h, RasterizerStateView.IS_DEPTH_CLIP, val ? 1 : 0); } get isMultisample (): boolean { - if (RasterizerStatePool.get(this.h, RasterizerStateView.IS_MULTI_SAMPLE)) return true; - else return false; + return this._isMultisample; + } + set isMultisample (val: boolean) { + this._isMultisample = val; + this._nativeObj.isMultisample = val; + } + get lineWidth (): number { return this._lineWidth; } + set lineWidth (val: number) { + this._lineWidth = val; + this._nativeObj.lineWidth = val; } - set isMultisample (val: boolean) { RasterizerStatePool.set(this.h, RasterizerStateView.IS_MULTI_SAMPLE, val ? 1 : 0); } - get lineWidth (): number { return RasterizerStatePool.get(this.h, RasterizerStateView.LINE_WIDTH); } - set lineWidth (val: number) { RasterizerStatePool.set(this.h, RasterizerStateView.LINE_WIDTH, val); } - get handle (): RasterizerStateHandle { return this.h; } public reset () { this.assignProperties(false, PolygonMode.FILL, ShadeModel.GOURAND, CullMode.BACK, true, false, 0, @@ -127,10 +168,7 @@ export class RasterizerState { } public destroy () { - if (this.h) { - RasterizerStatePool.free(this.h); - this.h = NULL_HANDLE; - } + this._nativeObj = null; } private assignProperties ( @@ -167,8 +205,26 @@ export class RasterizerState { * @zh GFX 深度模板状态。 */ export class DepthStencilState { - private h: DepthStencilStateHandle; - + protected _nativeObj; + protected _depthTest: boolean = true; + protected _depthWrite: boolean = true; + protected _depthFunc: ComparisonFunc = ComparisonFunc.LESS; + protected _stencilTestFront: boolean = false; + protected _stencilFuncFront: ComparisonFunc = ComparisonFunc.ALWAYS; + protected _stencilReadMaskFront: number = 0xffff; + protected _stencilWriteMaskFront: number = 0xffff; + protected _stencilFailOpFront: StencilOp = StencilOp.KEEP; + protected _stencilZFailOpFront: StencilOp = StencilOp.KEEP; + protected _stencilPassOpFront: StencilOp = StencilOp.KEEP; + protected _stencilRefFront: number = 1; + protected _stencilTestBack: boolean = false; + protected _stencilFuncBack: ComparisonFunc = ComparisonFunc.ALWAYS; + protected _stencilReadMaskBack: number = 0xffff; + protected _stencilWriteMaskBack: number = 0xffff; + protected _stencilFailOpBack: StencilOp = StencilOp.KEEP; + protected _stencilZFailOpBack: StencilOp = StencilOp.KEEP; + protected _stencilPassOpBack: StencilOp = StencilOp.KEEP; + protected _stencilRefBack: number = 1; constructor ( depthTest: boolean = true, depthWrite: boolean = true, @@ -190,67 +246,123 @@ export class DepthStencilState { stencilPassOpBack: StencilOp = StencilOp.KEEP, stencilRefBack: number = 1, ) { - this.h = DepthStencilStatePool.alloc(); + this._nativeObj = new gfx.DepthStencilState(); this.assignProperties(depthTest, depthWrite, depthFunc, stencilTestFront, stencilFuncFront, stencilReadMaskFront, stencilWriteMaskFront, stencilFailOpFront, stencilZFailOpFront, stencilPassOpFront, stencilRefFront, stencilTestBack, stencilFuncBack, stencilReadMaskBack, stencilWriteMaskBack, stencilFailOpBack, stencilZFailOpBack, stencilPassOpBack, stencilRefBack); } + get native () { + return this._nativeObj; + } + get depthTest (): boolean { - if (DepthStencilStatePool.get(this.h, DepthStencilStateView.DEPTH_TEST)) return true; - else return false; + return this._depthTest; + } + set depthTest (val: boolean) { + this._depthTest = val; + this._nativeObj.depthTest = val; } - set depthTest (val: boolean) { DepthStencilStatePool.set(this.h, DepthStencilStateView.DEPTH_TEST, val ? 1 : 0); } get depthWrite (): boolean { - if (DepthStencilStatePool.get(this.h, DepthStencilStateView.DEPTH_WRITE)) return true; - else return false; + return this._depthWrite; + } + set depthWrite (val: boolean) { + this._depthWrite = val; + this._nativeObj.depthWrite = val; + } + get depthFunc (): ComparisonFunc { return this._depthFunc; } + set depthFunc (val: ComparisonFunc) { + this._depthFunc = val; + this._nativeObj.depthFunc = val; } - set depthWrite (val: boolean) { DepthStencilStatePool.set(this.h, DepthStencilStateView.DEPTH_WRITE, val ? 1 : 0); } - get depthFunc (): ComparisonFunc { return DepthStencilStatePool.get(this.h, DepthStencilStateView.DEPTH_FUNC); } - set depthFunc (val: ComparisonFunc) { DepthStencilStatePool.set(this.h, DepthStencilStateView.DEPTH_FUNC, val); } get stencilTestFront (): boolean { - if (DepthStencilStatePool.get(this.h, DepthStencilStateView.STENCIL_TEST_FRONT)) return true; - else return false; - } - set stencilTestFront (val: boolean) { DepthStencilStatePool.set(this.h, DepthStencilStateView.STENCIL_TEST_FRONT, val ? 1 : 0); } - get stencilFuncFront (): ComparisonFunc { return DepthStencilStatePool.get(this.h, DepthStencilStateView.STENCIL_FUNC_FRONT); } - set stencilFuncFront (val: ComparisonFunc) { DepthStencilStatePool.set(this.h, DepthStencilStateView.STENCIL_FUNC_FRONT, val); } - get stencilReadMaskFront (): number { return DepthStencilStatePool.get(this.h, DepthStencilStateView.STENCIL_READ_MASK_FRONT); } - set stencilReadMaskFront (val: number) { DepthStencilStatePool.set(this.h, DepthStencilStateView.STENCIL_READ_MASK_FRONT, val);} - get stencilWriteMaskFront (): number { return DepthStencilStatePool.get(this.h, DepthStencilStateView.STENCIL_WRITE_MASK_FRONT); } - set stencilWriteMaskFront (val: number) { DepthStencilStatePool.set(this.h, DepthStencilStateView.STENCIL_WRITE_MASK_FRONT, val); } - get stencilFailOpFront (): StencilOp { return DepthStencilStatePool.get(this.h, DepthStencilStateView.STENCIL_FAIL_OP_FRONT); } - set stencilFailOpFront (val: StencilOp) { DepthStencilStatePool.set(this.h, DepthStencilStateView.STENCIL_FAIL_OP_FRONT, val); } - get stencilZFailOpFront (): StencilOp { return DepthStencilStatePool.get(this.h, DepthStencilStateView.STENCIL_Z_FAIL_OP_FRONT); } - set stencilZFailOpFront (val: StencilOp) { DepthStencilStatePool.set(this.h, DepthStencilStateView.STENCIL_Z_FAIL_OP_FRONT, val); } - get stencilPassOpFront (): StencilOp { return DepthStencilStatePool.get(this.h, DepthStencilStateView.STENCIL_PASS_OP_FRONT); } - set stencilPassOpFront (val: StencilOp) { DepthStencilStatePool.set(this.h, DepthStencilStateView.STENCIL_PASS_OP_FRONT, val); } - get stencilRefFront (): number { return DepthStencilStatePool.get(this.h, DepthStencilStateView.STENCIL_REF_FRONT); } - set stencilRefFront (val: number) { DepthStencilStatePool.set(this.h, DepthStencilStateView.STENCIL_REF_FRONT, val); } + return this._stencilTestFront; + } + set stencilTestFront (val: boolean) { + this._stencilTestFront = val; + this._nativeObj.stencilTestFront = val; + } + get stencilFuncFront (): ComparisonFunc { return this._stencilFuncFront; } + set stencilFuncFront (val: ComparisonFunc) { + this._stencilFuncFront = val; + this._nativeObj.stencilFuncFront = val; + } + get stencilReadMaskFront (): number { return this._stencilReadMaskFront; } + set stencilReadMaskFront (val: number) { + this._stencilReadMaskFront = val; + this._nativeObj.stencilReadMaskFront = val; + } + get stencilWriteMaskFront (): number { return this._stencilWriteMaskFront; } + set stencilWriteMaskFront (val: number) { + this._stencilWriteMaskFront = val; + this._nativeObj.stencilWriteMaskFront = val; + } + get stencilFailOpFront (): StencilOp { return this._stencilFailOpFront; } + set stencilFailOpFront (val: StencilOp) { + this._stencilFailOpFront = val; + this._nativeObj.stencilFailOpFront = val; + } + get stencilZFailOpFront (): StencilOp { return this._stencilZFailOpFront; } + set stencilZFailOpFront (val: StencilOp) { + this._stencilZFailOpFront = val; + this._nativeObj.stencilZFailOpFront = val; + } + get stencilPassOpFront (): StencilOp { return this._stencilPassOpFront; } + set stencilPassOpFront (val: StencilOp) { + this._stencilPassOpFront = val; + this._nativeObj.stencilPassOpFront = val; + } + get stencilRefFront (): number { return this._stencilRefFront; } + set stencilRefFront (val: number) { + this._stencilRefFront = val; + this._nativeObj.stencilRefFront = val; + } get stencilTestBack (): boolean { - if (DepthStencilStatePool.get(this.h, DepthStencilStateView.STENCIL_TEST_BACK)) return true; - else return false; - } - set stencilTestBack (val: boolean) { DepthStencilStatePool.set(this.h, DepthStencilStateView.STENCIL_TEST_BACK, val ? 1 : 0); } - get stencilFuncBack (): ComparisonFunc { return DepthStencilStatePool.get(this.h, DepthStencilStateView.STENCIL_FUNC_BACK); } - set stencilFuncBack (val: ComparisonFunc) { DepthStencilStatePool.set(this.h, DepthStencilStateView.STENCIL_FUNC_BACK, val); } - get stencilReadMaskBack (): number { return DepthStencilStatePool.get(this.h, DepthStencilStateView.STENCIL_READ_MADK_BACK); } - set stencilReadMaskBack (val: number) { DepthStencilStatePool.set(this.h, DepthStencilStateView.STENCIL_READ_MADK_BACK, val); } - get stencilWriteMaskBack (): number { return DepthStencilStatePool.get(this.h, DepthStencilStateView.STENCIL_WRITE_MASK_BACK); } - set stencilWriteMaskBack (val: number) { DepthStencilStatePool.set(this.h, DepthStencilStateView.STENCIL_WRITE_MASK_BACK, val); } - get stencilFailOpBack (): StencilOp { return DepthStencilStatePool.get(this.h, DepthStencilStateView.STENCIL_FAIL_OP_BACK); } - set stencilFailOpBack (val: StencilOp) { DepthStencilStatePool.set(this.h, DepthStencilStateView.STENCIL_FAIL_OP_BACK, val); } - get stencilZFailOpBack (): StencilOp { return DepthStencilStatePool.get(this.h, DepthStencilStateView.STENCIL_Z_FAIL_OP_BACK); } - set stencilZFailOpBack (val: StencilOp) { DepthStencilStatePool.set(this.h, DepthStencilStateView.STENCIL_Z_FAIL_OP_BACK, val); } - get stencilPassOpBack (): StencilOp { return DepthStencilStatePool.get(this.h, DepthStencilStateView.STENCIL_PASS_OP_BACK); } - set stencilPassOpBack (val: StencilOp) { DepthStencilStatePool.set(this.h, DepthStencilStateView.STENCIL_PASS_OP_BACK, val); } - get stencilRefBack (): number { return DepthStencilStatePool.get(this.h, DepthStencilStateView.STENCIL_REF_BACK); } - set stencilRefBack (val: number) { DepthStencilStatePool.set(this.h, DepthStencilStateView.STENCIL_REF_BACK, val); } - get handle (): DepthStencilStateHandle { return this.h; } + return this._stencilTestBack; + } + set stencilTestBack (val: boolean) { + this._stencilTestBack = val; + this._nativeObj.stencilTestBack = val; + } + get stencilFuncBack (): ComparisonFunc { return this._stencilFuncBack; } + set stencilFuncBack (val: ComparisonFunc) { + this._stencilFuncBack = val; + this._nativeObj.stencilFuncBack = val; + } + get stencilReadMaskBack (): number { return this._stencilReadMaskBack; } + set stencilReadMaskBack (val: number) { + this._stencilReadMaskBack = val; + this._nativeObj.stencilReadMaskBack = val; + } + get stencilWriteMaskBack (): number { return this._stencilWriteMaskBack; } + set stencilWriteMaskBack (val: number) { + this._stencilWriteMaskBack = val; + this._nativeObj.stencilWriteMaskBack = val; + } + get stencilFailOpBack (): StencilOp { return this._stencilFailOpBack; } + set stencilFailOpBack (val: StencilOp) { + this._stencilFailOpBack = val; + this._nativeObj.stencilFailOpBack = val; + } + get stencilZFailOpBack (): StencilOp { return this._stencilZFailOpBack; } + set stencilZFailOpBack (val: StencilOp) { + this._stencilZFailOpBack = val; + this._nativeObj.stencilZFailOpBack = val; + } + get stencilPassOpBack (): StencilOp { return this._stencilPassOpBack; } + set stencilPassOpBack (val: StencilOp) { + this._stencilPassOpBack = val; + this._nativeObj.stencilPassOpBack = val; + } + get stencilRefBack (): number { return this._stencilRefBack; } + set stencilRefBack (val: number) { + this._stencilRefBack = val; + this._nativeObj.stencilRefBack = val; + } public reset () { - this.assignProperties(true, true, ComparisonFunc.LESS, false, ComparisonFunc.ALWAYS, 0xffff, 0xffff,StencilOp.KEEP, + this.assignProperties(true, true, ComparisonFunc.LESS, false, ComparisonFunc.ALWAYS, 0xffff, 0xffff, StencilOp.KEEP, StencilOp.KEEP, StencilOp.KEEP, 1, false, ComparisonFunc.ALWAYS, 0xffff, 0xffff, StencilOp.KEEP, StencilOp.KEEP, StencilOp.KEEP, 1); } @@ -263,8 +375,7 @@ export class DepthStencilState { } public destroy () { - DepthStencilStatePool.free(this.h); - this.h = NULL_HANDLE; + this._nativeObj = null; } private assignProperties ( @@ -315,7 +426,18 @@ export class DepthStencilState { * @zh GFX 混合目标。 */ export class BlendTarget { - private h: BlendTargetHandle; + protected _nativeObj; + protected _blend: boolean = false; + protected _blendSrc: BlendFactor = BlendFactor.ONE; + protected _blendDst: BlendFactor = BlendFactor.ZERO; + protected _blendEq: BlendOp = BlendOp.ADD; + protected _blendSrcAlpha: BlendFactor = BlendFactor.ONE; + protected _blendDstAlpha: BlendFactor = BlendFactor.ZERO; + protected _blendAlphaEq: BlendOp = BlendOp.ADD; + protected _blendColorMask: ColorMask = ColorMask.ALL; + get native () { + return this._nativeObj; + } constructor ( blend: boolean = false, @@ -327,31 +449,53 @@ export class BlendTarget { blendAlphaEq: BlendOp = BlendOp.ADD, blendColorMask: ColorMask = ColorMask.ALL, ) { - this.h = BlendTargetPool.alloc(); + this._nativeObj = new gfx.BlendTarget(); this.assignProperties(blend, blendSrc, blendDst, blendEq, blendSrcAlpha, blendDstAlpha, blendAlphaEq, blendColorMask); } get blend (): boolean { - if (BlendTargetPool.get(this.h, BlendTargetView.BLEND)) return true; - else return false; - } - set blend (val: boolean) { BlendTargetPool.set(this.h, BlendTargetView.BLEND, val ? 1 : 0); } - get blendSrc (): BlendFactor { return BlendTargetPool.get(this.h, BlendTargetView.BLEND_SRC); } - set blendSrc (val: BlendFactor) { BlendTargetPool.set(this.h, BlendTargetView.BLEND_SRC, val); } - get blendDst () { return BlendTargetPool.get(this.h, BlendTargetView.BLEND_DST); } - set blendDst (val: BlendFactor) { BlendTargetPool.set(this.h, BlendTargetView.BLEND_DST, val); } - get blendEq (): BlendOp { return BlendTargetPool.get(this.h, BlendTargetView.BLEND_EQ); } - set blendEq (val: BlendOp) { BlendTargetPool.set(this.h, BlendTargetView.BLEND_EQ, val); } - get blendSrcAlpha (): BlendFactor { return BlendTargetPool.get(this.h, BlendTargetView.BLEND_SRC_ALPHA); } - set blendSrcAlpha (val: BlendFactor) { BlendTargetPool.set(this.h, BlendTargetView.BLEND_SRC_ALPHA, val); } - get blendDstAlpha (): BlendFactor { return BlendTargetPool.get(this.h, BlendTargetView.BLEND_DST_ALPHA); } - set blendDstAlpha (val: BlendFactor) { BlendTargetPool.set(this.h, BlendTargetView.BLEND_DST_ALPHA, val); } - get blendAlphaEq (): BlendOp { return BlendTargetPool.get(this.h, BlendTargetView.BLEND_ALPHA_EQ); } - set blendAlphaEq (val: BlendOp) { BlendTargetPool.set(this.h, BlendTargetView.BLEND_ALPHA_EQ, val); } - get blendColorMask (): ColorMask { return BlendTargetPool.get(this.h, BlendTargetView.BLEND_COLOR_MASK); } - set blendColorMask (val: ColorMask) { BlendTargetPool.set(this.h, BlendTargetView.BLEND_COLOR_MASK, val); } - get handle (): BlendTargetHandle { return this.h; } + return this._blend; + } + set blend (val: boolean) { + this._blend = val; + this._nativeObj.blend = val; + } + get blendSrc (): BlendFactor { return this._blendSrc; } + set blendSrc (val: BlendFactor) { + this._blendSrc = val; + this._nativeObj.blendSrc = val; + } + get blendDst () { return this._blendDst; } + set blendDst (val: BlendFactor) { + this._blendDst = val; + this._nativeObj.blendDst = val; + } + get blendEq (): BlendOp { return this._blendEq; } + set blendEq (val: BlendOp) { + this._blendEq = val; + this._nativeObj.blendEq = val; + } + get blendSrcAlpha (): BlendFactor { return this._blendSrcAlpha; } + set blendSrcAlpha (val: BlendFactor) { + this._blendSrcAlpha = val; + this._nativeObj.blendSrcAlpha = val; + } + get blendDstAlpha (): BlendFactor { return this._blendDstAlpha; } + set blendDstAlpha (val: BlendFactor) { + this._blendDstAlpha = val; + this._nativeObj.blendDstAlpha = val; + } + get blendAlphaEq (): BlendOp { return this._blendAlphaEq; } + set blendAlphaEq (val: BlendOp) { + this._blendAlphaEq = val; + this._nativeObj.blendAlphaEq = val; + } + get blendColorMask (): ColorMask { return this._blendColorMask; } + set blendColorMask (val: ColorMask) { + this._blendColorMask = val; + this._nativeObj.blendColorMask = val; + } public reset () { this.assignProperties(false, BlendFactor.ONE, BlendFactor.ZERO, BlendOp.ADD, @@ -359,8 +503,7 @@ export class BlendTarget { } public destroy () { - BlendTargetPool.free(this.h); - this.h = NULL_HANDLE; + this._nativeObj = null; } public assign (target: RecursivePartial) { @@ -390,11 +533,55 @@ export class BlendTarget { } } +function watchArrayElementsField (self: S, list: T[], eleField: string, cachedFieldName: string, callback: (self: S, idx: number, originTarget: T, prop: symbol | string, value: any) => void) { + for (let i = 0, l = list.length; i < l; i++) { + let ele = list[i] as any; + let originField = ele[eleField][cachedFieldName] || ele[eleField]; + // replace with Proxy + ele[eleField] = new Proxy(originField, { + get: (originTarget, key: string | symbol) => { + if (key === cachedFieldName) { + return originTarget; + } + return Reflect.get(originTarget, key); + }, + set: (originTarget, prop, value) => { + Reflect.set(originTarget, prop, value); + callback(self, i, originTarget, prop, value); + return true; + } + }); + } +} + + export class BlendState { - private h: BlendStateHandle; - private hBt: BlendTargetArrayHandle; private targets: BlendTarget[]; private _blendColor: Color; + protected _nativeObj; + protected _isA2C: boolean = false; + protected _isIndepend: boolean = false; + + private _setTargets (targets: BlendTarget[]) { + this.targets = targets; + + const CACHED_FIELD_NAME = `$__nativeObj`; + this._syncTargetsToNativeObj(CACHED_FIELD_NAME); + + // watch target[i]._nativeObj fields update + watchArrayElementsField(this, this.targets, "_nativeObj", CACHED_FIELD_NAME, (self, _idx, _originTarget, _prop, _value) => { + self._syncTargetsToNativeObj(CACHED_FIELD_NAME); + }); + } + + private _syncTargetsToNativeObj (cachedFieldName: string) { + const nativeTars = this.targets.map(target => { return target.native[cachedFieldName] || target.native; }); + this._nativeObj.targets = nativeTars; + } + + get native () { + return this._nativeObj; + } constructor ( isA2C: boolean = false, @@ -402,36 +589,32 @@ export class BlendState { blendColor: Color = new Color(), targets: BlendTarget[] = [new BlendTarget()], ) { - this.h = BlendStatePool.alloc(); - this.targets = targets; + this._nativeObj = new gfx.BlendState(); + this._setTargets(targets); this.blendColor = blendColor; this.isA2c = isA2C; this.isIndepend = isIndepend; - this.blendColor = blendColor - - this.hBt = BlendTargetArrayPool.alloc(); - BlendStatePool.set(this.h, BlendStateView.BLEND_TARGET, this.hBt); - for (let i = 0, len = targets.length; i < len; ++i) { - BlendTargetArrayPool.push(this.hBt, targets[i].handle); - } } get isA2c (): boolean { - if (BlendStatePool.get(this.h, BlendStateView.IS_A2C)) return true; - else return false; + return this._isA2C; + } + set isA2c (val: boolean) { + this._isA2C = val; + this._nativeObj.isA2C = val; } - set isA2c (val: boolean) { BlendStatePool.set(this.h, BlendStateView.IS_A2C, val ? 1 : 0); } get isIndepend (): boolean { - if (BlendStatePool.get(this.h, BlendStateView.IS_INDEPEND)) return true; - else return false; + return this._isIndepend; + } + set isIndepend (val: boolean) { + this._isIndepend = val; + this._nativeObj.isIndepend = val; } - set isIndepend (val: boolean) { BlendStatePool.set(this.h, BlendStateView.IS_INDEPEND, val ? 1 : 0); } get blendColor (): Color { return this._blendColor; } set blendColor (color: Color) { this._blendColor = color; - BlendStatePool.setVec4(this.h, BlendStateView.BLEND_COLOR, color); + this._nativeObj.blendColor = color; } - get handle (): BlendStateHandle { return this.h; } /** * @en Should use this function to set target, or it will not work @@ -445,15 +628,16 @@ export class BlendState { let tg = this.targets[index]; if (!tg) { tg = this.targets[index] = new BlendTarget(); - BlendTargetArrayPool.assign(this.hBt, index, tg.handle) } tg.assign(target); + // TODO: define setTarget function + this._setTargets(this.targets); } public reset () { this.isA2c = false; this.isIndepend = false; - BlendStatePool.setVec4(this.h, BlendStateView.BLEND_COLOR, new Color(0, 0, 0, 0)); + this.blendColor = new Color(0, 0, 0, 0); const targets = this.targets; for (let i = 1, len = targets.length; i < len; ++i) { @@ -461,21 +645,15 @@ export class BlendState { } targets.length = 1; targets[0].reset(); - BlendTargetArrayPool.clear(this.hBt); - BlendTargetArrayPool.push(this.hBt, targets[0].handle); + this._setTargets(targets); } public destroy () { - BlendStatePool.free(this.h); - this.h = NULL_HANDLE; - - BlendTargetArrayPool.free(this.hBt); - this.hBt = NULL_HANDLE; - for (let i = 0, len = this.targets.length; i < len; ++i) { this.targets[i].destroy(); } this.targets = null; + this._nativeObj = null; } } diff --git a/cocos/core/gfx/webgl/webgl-command-buffer.ts b/cocos/core/gfx/webgl/webgl-command-buffer.ts index 99be7eac347..4017ad20078 100644 --- a/cocos/core/gfx/webgl/webgl-command-buffer.ts +++ b/cocos/core/gfx/webgl/webgl-command-buffer.ts @@ -42,34 +42,12 @@ import { WebGLTexture } from './webgl-texture'; import { RenderPass } from '../base/render-pass'; import { WebGLRenderPass } from './webgl-render-pass'; import { BufferUsageBit, CommandBufferType, StencilFace, BufferSource, - CommandBufferInfo, BufferTextureCopy, Color, Rect, Viewport, DrawInfo } from '../base/define'; + CommandBufferInfo, BufferTextureCopy, Color, Rect, Viewport, DrawInfo, DynamicStates } from '../base/define'; import { WebGLCmd, WebGLCmdBeginRenderPass, WebGLCmdBindStates, WebGLCmdCopyBufferToTexture, WebGLCmdDraw, WebGLCmdPackage, WebGLCmdUpdateBuffer } from './webgl-commands'; import { GlobalBarrier } from '../base/global-barrier'; import { TextureBarrier } from '../base/texture-barrier'; -export interface IWebGLDepthBias { - constantFactor: number; - clamp: number; - slopeFactor: number; -} - -export interface IWebGLDepthBounds { - minBounds: number; - maxBounds: number; -} - -export interface IWebGLStencilWriteMask { - face: StencilFace; - writeMask: number; -} - -export interface IWebGLStencilCompareMask { - face: StencilFace; - reference: number; - compareMask: number; -} - export class WebGLCommandBuffer extends CommandBuffer { public cmdPackage: WebGLCmdPackage = new WebGLCmdPackage(); protected _webGLAllocator: WebGLCommandAllocator | null = null; @@ -77,15 +55,8 @@ export class WebGLCommandBuffer extends CommandBuffer { protected _curGPUPipelineState: IWebGLGPUPipelineState | null = null; protected _curGPUInputAssembler: IWebGLGPUInputAssembler | null = null; protected _curGPUDescriptorSets: IWebGLGPUDescriptorSet[] = []; - protected _curDynamicOffsets: number[][] = []; - protected _curViewport: Viewport | null = null; - protected _curScissor: Rect | null = null; - protected _curLineWidth: number | null = null; - protected _curDepthBias: IWebGLDepthBias | null = null; - protected _curBlendConstants: number[] = []; - protected _curDepthBounds: IWebGLDepthBounds | null = null; - protected _curStencilWriteMask: IWebGLStencilWriteMask | null = null; - protected _curStencilCompareMask: IWebGLStencilCompareMask | null = null; + protected _curDynamicOffsets: number[] = Array(8).fill(0); + protected _curDynamicStates: DynamicStates = new DynamicStates(); protected _isStateInvalied = false; public initialize (info: CommandBufferInfo): boolean { @@ -97,7 +68,6 @@ export class WebGLCommandBuffer extends CommandBuffer { const setCount = (this._device as WebGLDevice).bindingMappingInfo.bufferOffsets.length; for (let i = 0; i < setCount; i++) { this._curGPUDescriptorSets.push(null!); - this._curDynamicOffsets.push([]); } return true; @@ -115,17 +85,6 @@ export class WebGLCommandBuffer extends CommandBuffer { this._curGPUPipelineState = null; this._curGPUInputAssembler = null; this._curGPUDescriptorSets.length = 0; - for (let i = 0; i < this._curDynamicOffsets.length; i++) { - this._curDynamicOffsets[i].length = 0; - } - this._curViewport = null; - this._curScissor = null; - this._curLineWidth = null; - this._curDepthBias = null; - this._curBlendConstants.length = 0; - this._curDepthBounds = null; - this._curStencilWriteMask = null; - this._curStencilCompareMask = null; this._numDrawCalls = 0; this._numInstances = 0; this._numTris = 0; @@ -145,7 +104,7 @@ export class WebGLCommandBuffer extends CommandBuffer { renderArea: Rect, clearColors: Color[], clearDepth: number, - clearStencil: number + clearStencil: number, ) { const cmd = this._webGLAllocator!.beginRenderPassCmdPool.alloc(WebGLCmdBeginRenderPass); cmd.gpuRenderPass = (renderPass as WebGLRenderPass).gpuRenderPass; @@ -183,10 +142,13 @@ export class WebGLCommandBuffer extends CommandBuffer { this._isStateInvalied = true; } if (dynamicOffsets) { - const offsets = this._curDynamicOffsets[set]; - for (let i = 0; i < dynamicOffsets.length; i++) offsets[i] = dynamicOffsets[i]; - offsets.length = dynamicOffsets.length; - this._isStateInvalied = true; + const gpuPipelineLayout = this._curGPUPipelineState?.gpuPipelineLayout; + if (gpuPipelineLayout) { + const offsets = this._curDynamicOffsets; + const idx = gpuPipelineLayout.dynamicOffsetOffsets[set]; + for (let i = 0; i < dynamicOffsets.length; i++) offsets[idx + i] = dynamicOffsets[i]; + this._isStateInvalied = true; + } } } @@ -197,123 +159,112 @@ export class WebGLCommandBuffer extends CommandBuffer { } public setViewport (viewport: Viewport) { - if (!this._curViewport) { - this._curViewport = new Viewport(viewport.left, viewport.top, viewport.width, viewport.height, viewport.minDepth, viewport.maxDepth); - } else if (this._curViewport.left !== viewport.left - || this._curViewport.top !== viewport.top - || this._curViewport.width !== viewport.width - || this._curViewport.height !== viewport.height - || this._curViewport.minDepth !== viewport.minDepth - || this._curViewport.maxDepth !== viewport.maxDepth) { - this._curViewport.left = viewport.left; - this._curViewport.top = viewport.top; - this._curViewport.width = viewport.width; - this._curViewport.height = viewport.height; - this._curViewport.minDepth = viewport.minDepth; - this._curViewport.maxDepth = viewport.maxDepth; + const cache = this._curDynamicStates.viewport; + if (cache.left !== viewport.left + || cache.top !== viewport.top + || cache.width !== viewport.width + || cache.height !== viewport.height + || cache.minDepth !== viewport.minDepth + || cache.maxDepth !== viewport.maxDepth) { + cache.left = viewport.left; + cache.top = viewport.top; + cache.width = viewport.width; + cache.height = viewport.height; + cache.minDepth = viewport.minDepth; + cache.maxDepth = viewport.maxDepth; this._isStateInvalied = true; } } public setScissor (scissor: Rect) { - if (!this._curScissor) { - this._curScissor = new Rect(scissor.x, scissor.y, scissor.width, scissor.height); - } else if (this._curScissor.x !== scissor.x - || this._curScissor.y !== scissor.y - || this._curScissor.width !== scissor.width - || this._curScissor.height !== scissor.height) { - this._curScissor.x = scissor.x; - this._curScissor.y = scissor.y; - this._curScissor.width = scissor.width; - this._curScissor.height = scissor.height; + const cache = this._curDynamicStates.scissor; + if (cache.x !== scissor.x + || cache.y !== scissor.y + || cache.width !== scissor.width + || cache.height !== scissor.height) { + cache.x = scissor.x; + cache.y = scissor.y; + cache.width = scissor.width; + cache.height = scissor.height; this._isStateInvalied = true; } } public setLineWidth (lineWidth: number) { - if (this._curLineWidth !== lineWidth) { - this._curLineWidth = lineWidth; + if (this._curDynamicStates.lineWidth !== lineWidth) { + this._curDynamicStates.lineWidth = lineWidth; this._isStateInvalied = true; } } public setDepthBias (depthBiasConstantFactor: number, depthBiasClamp: number, depthBiasSlopeFactor: number) { - if (!this._curDepthBias) { - this._curDepthBias = { - constantFactor: depthBiasConstantFactor, - clamp: depthBiasClamp, - slopeFactor: depthBiasSlopeFactor, - }; - this._isStateInvalied = true; - } else if (this._curDepthBias.constantFactor !== depthBiasConstantFactor - || this._curDepthBias.clamp !== depthBiasClamp - || this._curDepthBias.slopeFactor !== depthBiasSlopeFactor) { - this._curDepthBias.constantFactor = depthBiasConstantFactor; - this._curDepthBias.clamp = depthBiasClamp; - this._curDepthBias.slopeFactor = depthBiasSlopeFactor; + const cache = this._curDynamicStates; + if (cache.depthBiasConstant !== depthBiasConstantFactor + || cache.depthBiasClamp !== depthBiasClamp + || cache.depthBiasSlope !== depthBiasSlopeFactor) { + cache.depthBiasConstant = depthBiasConstantFactor; + cache.depthBiasClamp = depthBiasClamp; + cache.depthBiasSlope = depthBiasSlopeFactor; this._isStateInvalied = true; } } - public setBlendConstants (blendConstants: number[]) { - if (blendConstants.length === 4 && ( - this._curBlendConstants[0] !== blendConstants[0] - || this._curBlendConstants[1] !== blendConstants[1] - || this._curBlendConstants[2] !== blendConstants[2] - || this._curBlendConstants[3] !== blendConstants[3])) { - this._curBlendConstants.length = 0; - Array.prototype.push.apply(this._curBlendConstants, blendConstants); + public setBlendConstants (blendConstants: Color) { + const cache = this._curDynamicStates.blendConstant; + if (cache.x !== blendConstants.x + || cache.y !== blendConstants.y + || cache.z !== blendConstants.z + || cache.w !== blendConstants.w) { + cache.copy(blendConstants); this._isStateInvalied = true; } } public setDepthBound (minDepthBounds: number, maxDepthBounds: number) { - if (!this._curDepthBounds) { - this._curDepthBounds = { - minBounds: minDepthBounds, - maxBounds: maxDepthBounds, - }; - this._isStateInvalied = true; - } else if (this._curDepthBounds.minBounds !== minDepthBounds - || this._curDepthBounds.maxBounds !== maxDepthBounds) { - this._curDepthBounds = { - minBounds: minDepthBounds, - maxBounds: maxDepthBounds, - }; + const cache = this._curDynamicStates; + if (cache.depthMinBounds !== minDepthBounds + || cache.depthMaxBounds !== maxDepthBounds) { + cache.depthMinBounds = minDepthBounds; + cache.depthMaxBounds = maxDepthBounds; this._isStateInvalied = true; } } public setStencilWriteMask (face: StencilFace, writeMask: number) { - if (!this._curStencilWriteMask) { - this._curStencilWriteMask = { - face, - writeMask, - }; - this._isStateInvalied = true; - } else if (this._curStencilWriteMask.face !== face - || this._curStencilWriteMask.writeMask !== writeMask) { - this._curStencilWriteMask.face = face; - this._curStencilWriteMask.writeMask = writeMask; - this._isStateInvalied = true; + const front = this._curDynamicStates.stencilStatesFront; + const back = this._curDynamicStates.stencilStatesBack; + if (face & StencilFace.FRONT) { + if (front.writeMask !== writeMask) { + front.writeMask = writeMask; + this._isStateInvalied = true; + } + } + if (face & StencilFace.BACK) { + if (back.writeMask !== writeMask) { + back.writeMask = writeMask; + this._isStateInvalied = true; + } } } public setStencilCompareMask (face: StencilFace, reference: number, compareMask: number) { - if (!this._curStencilCompareMask) { - this._curStencilCompareMask = { - face, - reference, - compareMask, - }; - this._isStateInvalied = true; - } else if (this._curStencilCompareMask.face !== face - || this._curStencilCompareMask.reference !== reference - || this._curStencilCompareMask.compareMask !== compareMask) { - this._curStencilCompareMask.face = face; - this._curStencilCompareMask.reference = reference; - this._curStencilCompareMask.compareMask = compareMask; - this._isStateInvalied = true; + const front = this._curDynamicStates.stencilStatesFront; + const back = this._curDynamicStates.stencilStatesBack; + if (face & StencilFace.FRONT) { + if (front.compareMask !== compareMask + || front.reference !== reference) { + front.reference = reference; + front.compareMask = compareMask; + this._isStateInvalied = true; + } + } + if (face & StencilFace.BACK) { + if (back.compareMask !== compareMask + || back.reference !== reference) { + back.reference = reference; + back.compareMask = compareMask; + this._isStateInvalied = true; + } } } @@ -473,18 +424,9 @@ export class WebGLCommandBuffer extends CommandBuffer { if (bindStatesCmd) { bindStatesCmd.gpuPipelineState = this._curGPUPipelineState; Array.prototype.push.apply(bindStatesCmd.gpuDescriptorSets, this._curGPUDescriptorSets); - for (let i = 0; i < this._curDynamicOffsets.length; i++) { - Array.prototype.push.apply(bindStatesCmd.dynamicOffsets, this._curDynamicOffsets[i]); - } + Array.prototype.push.apply(bindStatesCmd.dynamicOffsets, this._curDynamicOffsets); bindStatesCmd.gpuInputAssembler = this._curGPUInputAssembler; - bindStatesCmd.viewport = this._curViewport; - bindStatesCmd.scissor = this._curScissor; - bindStatesCmd.lineWidth = this._curLineWidth; - bindStatesCmd.depthBias = this._curDepthBias; - Array.prototype.push.apply(bindStatesCmd.blendConstants, this._curBlendConstants); - bindStatesCmd.depthBounds = this._curDepthBounds; - bindStatesCmd.stencilWriteMask = this._curStencilWriteMask; - bindStatesCmd.stencilCompareMask = this._curStencilCompareMask; + bindStatesCmd.dynamicStates.copy(this._curDynamicStates); this.cmdPackage.bindStatesCmds.push(bindStatesCmd); this.cmdPackage.cmds.push(WebGLCmd.BIND_STATES); diff --git a/cocos/core/gfx/webgl/webgl-commands.ts b/cocos/core/gfx/webgl/webgl-commands.ts index dbc0fc5e75c..a293e16d198 100644 --- a/cocos/core/gfx/webgl/webgl-commands.ts +++ b/cocos/core/gfx/webgl/webgl-commands.ts @@ -26,9 +26,6 @@ import { CachedArray } from '../../memop/cached-array'; import { error, errorID } from '../../platform/debug'; import { WebGLCommandAllocator } from './webgl-command-allocator'; -import { - IWebGLDepthBias, IWebGLDepthBounds, IWebGLStencilCompareMask, IWebGLStencilWriteMask, -} from './webgl-command-buffer'; import { WebGLEXT } from './webgl-define'; import { WebGLDevice } from './webgl-device'; import { @@ -36,9 +33,9 @@ import { IWebGLGPUPipelineState, IWebGLGPUShader, IWebGLGPUTexture, IWebGLGPUUniformBlock, IWebGLGPUUniformSamplerTexture, IWebGLGPURenderPass, } from './webgl-gpu-objects'; import { - BufferUsageBit, ClearFlagBit, ClearFlags, ColorMask, CullMode, Format, BufferTextureCopy, Color, Rect, Viewport, - FormatInfos, FormatSize, LoadOp, MemoryUsageBit, SampleCount, ShaderStageFlagBit, StencilFace, - TextureFlagBit, TextureType, Type, FormatInfo, DynamicStateFlagBit, BufferSource, DrawInfo, IndirectBuffer, + BufferUsageBit, ClearFlagBit, ClearFlags, ColorMask, CullMode, Format, BufferTextureCopy, Color, Rect, + FormatInfos, FormatSize, LoadOp, MemoryUsageBit, SampleCount, ShaderStageFlagBit, + TextureFlagBit, TextureType, Type, FormatInfo, DynamicStateFlagBit, BufferSource, DrawInfo, IndirectBuffer, DynamicStates, } from '../base/define'; export function GFXFormatToWebGLType (format: Format, gl: WebGLRenderingContext): GLenum { @@ -522,7 +519,6 @@ export enum WebGLCmd { export abstract class WebGLCmdObject { public cmdType: WebGLCmd; - public refCount = 0; constructor (type: WebGLCmd) { @@ -534,17 +530,11 @@ export abstract class WebGLCmdObject { export class WebGLCmdBeginRenderPass extends WebGLCmdObject { public gpuRenderPass: IWebGLGPURenderPass | null = null; - public gpuFramebuffer: IWebGLGPUFramebuffer | null = null; - public renderArea = new Rect(); - public clearFlag: ClearFlags = ClearFlagBit.NONE; - public clearColors: Color[] = []; - public clearDepth = 1.0; - public clearStencil = 0; constructor () { @@ -559,28 +549,10 @@ export class WebGLCmdBeginRenderPass extends WebGLCmdObject { export class WebGLCmdBindStates extends WebGLCmdObject { public gpuPipelineState: IWebGLGPUPipelineState | null = null; - public gpuInputAssembler: IWebGLGPUInputAssembler | null = null; - public gpuDescriptorSets: IWebGLGPUDescriptorSet[] = []; - public dynamicOffsets: number[] = []; - - public viewport: Viewport | null = null; - - public scissor: Rect | null = null; - - public lineWidth: number | null = null; - - public depthBias: IWebGLDepthBias | null = null; - - public blendConstants: number[] = []; - - public depthBounds: IWebGLDepthBounds | null = null; - - public stencilWriteMask: IWebGLStencilWriteMask | null = null; - - public stencilCompareMask: IWebGLStencilCompareMask | null = null; + public dynamicStates: DynamicStates = new DynamicStates(); constructor () { super(WebGLCmd.BIND_STATES); @@ -591,14 +563,6 @@ export class WebGLCmdBindStates extends WebGLCmdObject { this.gpuDescriptorSets.length = 0; this.gpuInputAssembler = null; this.dynamicOffsets.length = 0; - this.viewport = null; - this.scissor = null; - this.lineWidth = null; - this.depthBias = null; - this.blendConstants.length = 0; - this.depthBounds = null; - this.stencilWriteMask = null; - this.stencilCompareMask = null; } } @@ -615,11 +579,8 @@ export class WebGLCmdDraw extends WebGLCmdObject { export class WebGLCmdUpdateBuffer extends WebGLCmdObject { public gpuBuffer: IWebGLGPUBuffer | null = null; - public buffer: BufferSource | null = null; - public offset = 0; - public size = 0; constructor () { @@ -634,9 +595,7 @@ export class WebGLCmdUpdateBuffer extends WebGLCmdObject { export class WebGLCmdCopyBufferToTexture extends WebGLCmdObject { public gpuTexture: IWebGLGPUTexture | null = null; - public buffers: ArrayBufferView[] = []; - public regions: BufferTextureCopy[] = []; constructor () { @@ -652,15 +611,10 @@ export class WebGLCmdCopyBufferToTexture extends WebGLCmdObject { export class WebGLCmdPackage { public cmds: CachedArray = new CachedArray(1); - public beginRenderPassCmds: CachedArray = new CachedArray(1); - public bindStatesCmds: CachedArray = new CachedArray(1); - public drawCmds: CachedArray = new CachedArray(1); - public updateBufferCmds: CachedArray = new CachedArray(1); - public copyBufferToTextureCmds: CachedArray = new CachedArray(1); public clearCmds (allocator: WebGLCommandAllocator) { @@ -1854,14 +1808,7 @@ export function WebGLCmdFuncBindStates ( gpuInputAssembler: IWebGLGPUInputAssembler | null, gpuDescriptorSets: IWebGLGPUDescriptorSet[], dynamicOffsets: number[], - viewport: Viewport | null, - scissor: Rect | null, - lineWidth: number | null, - depthBias: IWebGLDepthBias | null, - blendConstants: number[], - depthBounds: IWebGLDepthBounds | null, - stencilWriteMask: IWebGLStencilWriteMask | null, - stencilCompareMask: IWebGLStencilCompareMask | null, + dynamicStates: DynamicStates, ) { const { gl } = device; const cache = device.stateCache; @@ -2535,148 +2482,89 @@ export function WebGLCmdFuncBindStates ( const dynamicState = gpuPipelineState.dynamicStates[j]; switch (dynamicState) { case DynamicStateFlagBit.VIEWPORT: { - if (viewport) { - if (cache.viewport.left !== viewport.left - || cache.viewport.top !== viewport.top - || cache.viewport.width !== viewport.width - || cache.viewport.height !== viewport.height) { - gl.viewport(viewport.left, viewport.top, viewport.width, viewport.height); - - cache.viewport.left = viewport.left; - cache.viewport.top = viewport.top; - cache.viewport.width = viewport.width; - cache.viewport.height = viewport.height; - } + const viewport = dynamicStates.viewport; + if (cache.viewport.left !== viewport.left + || cache.viewport.top !== viewport.top + || cache.viewport.width !== viewport.width + || cache.viewport.height !== viewport.height) { + gl.viewport(viewport.left, viewport.top, viewport.width, viewport.height); + + cache.viewport.left = viewport.left; + cache.viewport.top = viewport.top; + cache.viewport.width = viewport.width; + cache.viewport.height = viewport.height; } break; } case DynamicStateFlagBit.SCISSOR: { - if (scissor) { - if (cache.scissorRect.x !== scissor.x - || cache.scissorRect.y !== scissor.y - || cache.scissorRect.width !== scissor.width - || cache.scissorRect.height !== scissor.height) { - gl.scissor(scissor.x, scissor.y, scissor.width, scissor.height); - - cache.scissorRect.x = scissor.x; - cache.scissorRect.y = scissor.y; - cache.scissorRect.width = scissor.width; - cache.scissorRect.height = scissor.height; - } + const scissor = dynamicStates.scissor; + if (cache.scissorRect.x !== scissor.x + || cache.scissorRect.y !== scissor.y + || cache.scissorRect.width !== scissor.width + || cache.scissorRect.height !== scissor.height) { + gl.scissor(scissor.x, scissor.y, scissor.width, scissor.height); + + cache.scissorRect.x = scissor.x; + cache.scissorRect.y = scissor.y; + cache.scissorRect.width = scissor.width; + cache.scissorRect.height = scissor.height; } break; } case DynamicStateFlagBit.LINE_WIDTH: { - if (lineWidth) { - if (cache.rs.lineWidth !== lineWidth) { - gl.lineWidth(lineWidth); - cache.rs.lineWidth = lineWidth; - } + if (cache.rs.lineWidth !== dynamicStates.lineWidth) { + gl.lineWidth(dynamicStates.lineWidth); + cache.rs.lineWidth = dynamicStates.lineWidth; } break; } case DynamicStateFlagBit.DEPTH_BIAS: { - if (depthBias) { - if ((cache.rs.depthBias !== depthBias.constantFactor) - || (cache.rs.depthBiasSlop !== depthBias.slopeFactor)) { - gl.polygonOffset(depthBias.constantFactor, depthBias.slopeFactor); - cache.rs.depthBias = depthBias.constantFactor; - cache.rs.depthBiasSlop = depthBias.slopeFactor; - } + if (cache.rs.depthBias !== dynamicStates.depthBiasConstant + || cache.rs.depthBiasSlop !== dynamicStates.depthBiasSlope) { + gl.polygonOffset(dynamicStates.depthBiasConstant, dynamicStates.depthBiasSlope); + cache.rs.depthBias = dynamicStates.depthBiasConstant; + cache.rs.depthBiasSlop = dynamicStates.depthBiasSlope; } break; } case DynamicStateFlagBit.BLEND_CONSTANTS: { - if ((cache.bs.blendColor.x !== blendConstants[0]) - || (cache.bs.blendColor.y !== blendConstants[1]) - || (cache.bs.blendColor.z !== blendConstants[2]) - || (cache.bs.blendColor.w !== blendConstants[3])) { - gl.blendColor(blendConstants[0], blendConstants[1], blendConstants[2], blendConstants[3]); - [cache.bs.blendColor.x, cache.bs.blendColor.y, cache.bs.blendColor.z, cache.bs.blendColor.w] = blendConstants; + const blendConstant = dynamicStates.blendConstant; + if ((cache.bs.blendColor.x !== blendConstant.x) + || (cache.bs.blendColor.y !== blendConstant.y) + || (cache.bs.blendColor.z !== blendConstant.z) + || (cache.bs.blendColor.w !== blendConstant.w)) { + gl.blendColor(blendConstant.x, blendConstant.y, blendConstant.z, blendConstant.w); + cache.bs.blendColor.copy(blendConstant); } break; } case DynamicStateFlagBit.STENCIL_WRITE_MASK: { - if (stencilWriteMask) { - switch (stencilWriteMask.face) { - case StencilFace.FRONT: { - if (cache.dss.stencilWriteMaskFront !== stencilWriteMask.writeMask) { - gl.stencilMaskSeparate(gl.FRONT, stencilWriteMask.writeMask); - cache.dss.stencilWriteMaskFront = stencilWriteMask.writeMask; - } - break; - } - case StencilFace.BACK: { - if (cache.dss.stencilWriteMaskBack !== stencilWriteMask.writeMask) { - gl.stencilMaskSeparate(gl.BACK, stencilWriteMask.writeMask); - cache.dss.stencilWriteMaskBack = stencilWriteMask.writeMask; - } - break; - } - case StencilFace.ALL: { - if (cache.dss.stencilWriteMaskFront !== stencilWriteMask.writeMask - || cache.dss.stencilWriteMaskBack !== stencilWriteMask.writeMask) { - gl.stencilMask(stencilWriteMask.writeMask); - cache.dss.stencilWriteMaskFront = stencilWriteMask.writeMask; - cache.dss.stencilWriteMaskBack = stencilWriteMask.writeMask; - } - break; - } - default: - } + const front = dynamicStates.stencilStatesFront; + const back = dynamicStates.stencilStatesBack; + if (cache.dss.stencilWriteMaskFront !== front.writeMask) { + gl.stencilMaskSeparate(gl.FRONT, front.writeMask); + cache.dss.stencilWriteMaskFront = front.writeMask; + } + if (cache.dss.stencilWriteMaskBack !== back.writeMask) { + gl.stencilMaskSeparate(gl.BACK, back.writeMask); + cache.dss.stencilWriteMaskBack = back.writeMask; } break; } case DynamicStateFlagBit.STENCIL_COMPARE_MASK: { - if (stencilCompareMask) { - switch (stencilCompareMask.face) { - case StencilFace.FRONT: { - if (cache.dss.stencilRefFront !== stencilCompareMask.reference - || cache.dss.stencilReadMaskFront !== stencilCompareMask.compareMask) { - gl.stencilFuncSeparate( - gl.FRONT, - WebGLCmpFuncs[cache.dss.stencilFuncFront], - stencilCompareMask.reference, - stencilCompareMask.compareMask, - ); - cache.dss.stencilRefFront = stencilCompareMask.reference; - cache.dss.stencilReadMaskFront = stencilCompareMask.compareMask; - } - break; - } - case StencilFace.BACK: { - if (cache.dss.stencilRefBack !== stencilCompareMask.reference - || cache.dss.stencilReadMaskBack !== stencilCompareMask.compareMask) { - gl.stencilFuncSeparate( - gl.BACK, - WebGLCmpFuncs[cache.dss.stencilFuncBack], - stencilCompareMask.reference, - stencilCompareMask.compareMask, - ); - cache.dss.stencilRefBack = stencilCompareMask.reference; - cache.dss.stencilReadMaskBack = stencilCompareMask.compareMask; - } - break; - } - case StencilFace.ALL: { - if (cache.dss.stencilRefFront !== stencilCompareMask.reference - || cache.dss.stencilReadMaskFront !== stencilCompareMask.compareMask - || cache.dss.stencilRefBack !== stencilCompareMask.reference - || cache.dss.stencilReadMaskBack !== stencilCompareMask.compareMask) { - gl.stencilFunc( - WebGLCmpFuncs[cache.dss.stencilFuncBack], - stencilCompareMask.reference, - stencilCompareMask.compareMask, - ); - cache.dss.stencilRefFront = stencilCompareMask.reference; - cache.dss.stencilReadMaskFront = stencilCompareMask.compareMask; - cache.dss.stencilRefBack = stencilCompareMask.reference; - cache.dss.stencilReadMaskBack = stencilCompareMask.compareMask; - } - break; - } - default: - } + const front = dynamicStates.stencilStatesFront; + const back = dynamicStates.stencilStatesBack; + if (cache.dss.stencilRefFront !== front.reference + || cache.dss.stencilReadMaskFront !== front.compareMask) { + gl.stencilFuncSeparate(gl.FRONT, WebGLCmpFuncs[cache.dss.stencilFuncFront], front.reference, front.compareMask); + cache.dss.stencilRefFront = front.reference; + cache.dss.stencilReadMaskFront = front.compareMask; + } + if (cache.dss.stencilRefBack !== back.reference + || cache.dss.stencilReadMaskBack !== back.compareMask) { + gl.stencilFuncSeparate(gl.BACK, WebGLCmpFuncs[cache.dss.stencilFuncBack], back.reference, back.compareMask); + cache.dss.stencilRefBack = back.reference; + cache.dss.stencilReadMaskBack = back.compareMask; } break; } @@ -2764,9 +2652,8 @@ export function WebGLCmdFuncExecuteCmds (device: WebGLDevice, cmdPackage: WebGLC */ case WebGLCmd.BIND_STATES: { const cmd2 = cmdPackage.bindStatesCmds.array[cmdId]; - WebGLCmdFuncBindStates(device, cmd2.gpuPipelineState, cmd2.gpuInputAssembler, cmd2.gpuDescriptorSets, cmd2.dynamicOffsets, - cmd2.viewport, cmd2.scissor, cmd2.lineWidth, cmd2.depthBias, cmd2.blendConstants, - cmd2.depthBounds, cmd2.stencilWriteMask, cmd2.stencilCompareMask); + WebGLCmdFuncBindStates(device, cmd2.gpuPipelineState, cmd2.gpuInputAssembler, + cmd2.gpuDescriptorSets, cmd2.dynamicOffsets, cmd2.dynamicStates); break; } case WebGLCmd.DRAW: { diff --git a/cocos/core/gfx/webgl/webgl-device.ts b/cocos/core/gfx/webgl/webgl-device.ts index bb03cc71ed2..046d321e7bb 100644 --- a/cocos/core/gfx/webgl/webgl-device.ts +++ b/cocos/core/gfx/webgl/webgl-device.ts @@ -57,12 +57,16 @@ import { WebGLSampler } from './webgl-sampler'; import { WebGLShader } from './webgl-shader'; import { WebGLStateCache } from './webgl-state-cache'; import { WebGLTexture } from './webgl-texture'; -import { getTypedArrayConstructor, CommandBufferType, Filter, Format, FormatInfos, BindingMappingInfo, ShaderInfo, +import { + getTypedArrayConstructor, CommandBufferType, Filter, Format, FormatInfos, BindingMappingInfo, ShaderInfo, QueueInfo, CommandBufferInfo, DescriptorSetInfo, DescriptorSetLayoutInfo, FramebufferInfo, InputAssemblerInfo, PipelineLayoutInfo, RenderPassInfo, SamplerInfo, TextureInfo, TextureViewInfo, BufferInfo, BufferViewInfo, DeviceInfo, TextureBarrierInfo, GlobalBarrierInfo, - QueueType, TextureFlagBit, TextureType, TextureUsageBit, API, Feature, BufferTextureCopy, Rect } from '../base/define'; -import { GFXFormatToWebGLFormat, GFXFormatToWebGLType, WebGLCmdFuncCopyBuffersToTexture, - WebGLCmdFuncCopyTexImagesToTexture } from './webgl-commands'; + QueueType, TextureFlagBit, TextureType, TextureUsageBit, API, Feature, BufferTextureCopy, Rect, +} from '../base/define'; +import { + GFXFormatToWebGLFormat, GFXFormatToWebGLType, WebGLCmdFuncCopyBuffersToTexture, + WebGLCmdFuncCopyTexImagesToTexture, +} from './webgl-commands'; import { GlobalBarrier } from '../base/global-barrier'; import { TextureBarrier } from '../base/texture-barrier'; import { BrowserType, OS } from '../../../../pal/system/enum-type'; @@ -310,10 +314,8 @@ export class WebGLDevice extends Device { } this._devicePixelRatio = info.devicePixelRatio || 1.0; - this._width = this._canvas.width; - this._height = this._canvas.height; - this._nativeWidth = Math.max(info.nativeWidth || this._width, 0); - this._nativeHeight = Math.max(info.nativeHeight || this._height, 0); + this._width = info.width; + this._height = info.height; this._colorFmt = Format.RGBA8; @@ -487,7 +489,6 @@ export class WebGLDevice extends Device { console.info(`VERSION: ${this._version}`); console.info(`DPR: ${this._devicePixelRatio}`); console.info(`SCREEN_SIZE: ${this._width} x ${this._height}`); - console.info(`NATIVE_SIZE: ${this._nativeWidth} x ${this._nativeHeight}`); // console.info('COLOR_FORMAT: ' + FormatInfos[this._colorFmt].name); // console.info('DEPTH_STENCIL_FORMAT: ' + FormatInfos[this._depthStencilFmt].name); // console.info('MAX_VERTEX_ATTRIBS: ' + this._maxVertexAttributes); diff --git a/cocos/core/gfx/webgl/webgl-gpu-objects.ts b/cocos/core/gfx/webgl/webgl-gpu-objects.ts index d06fea10494..4799b0db09c 100644 --- a/cocos/core/gfx/webgl/webgl-gpu-objects.ts +++ b/cocos/core/gfx/webgl/webgl-gpu-objects.ts @@ -185,6 +185,7 @@ export interface IWebGLGPUDescriptorSetLayout { export interface IWebGLGPUPipelineLayout { gpuSetLayouts: IWebGLGPUDescriptorSetLayout[]; dynamicOffsetCount: number; + dynamicOffsetOffsets: number[]; dynamicOffsetIndices: number[][]; } diff --git a/cocos/core/gfx/webgl/webgl-pipeline-layout.ts b/cocos/core/gfx/webgl/webgl-pipeline-layout.ts index 14b38b269a3..4e1ca9c2303 100644 --- a/cocos/core/gfx/webgl/webgl-pipeline-layout.ts +++ b/cocos/core/gfx/webgl/webgl-pipeline-layout.ts @@ -40,6 +40,7 @@ export class WebGLPipelineLayout extends PipelineLayout { const gpuSetLayouts: IWebGLGPUDescriptorSetLayout[] = []; let dynamicOffsetCount = 0; + const dynamicOffsetOffsets: number[] = []; for (let i = 0; i < this._setLayouts.length; i++) { const setLayout = this._setLayouts[i] as WebGLDescriptorSetLayout; const dynamicBindings = setLayout.gpuDescriptorSetLayout.dynamicBindings; @@ -51,6 +52,7 @@ export class WebGLPipelineLayout extends PipelineLayout { gpuSetLayouts.push(setLayout.gpuDescriptorSetLayout); dynamicOffsetIndices.push(indices); + dynamicOffsetOffsets.push(dynamicOffsetCount); dynamicOffsetCount += dynamicBindings.length; } @@ -58,6 +60,7 @@ export class WebGLPipelineLayout extends PipelineLayout { gpuSetLayouts, dynamicOffsetIndices, dynamicOffsetCount, + dynamicOffsetOffsets, }; return true; diff --git a/cocos/core/gfx/webgl/webgl-primary-command-buffer.ts b/cocos/core/gfx/webgl/webgl-primary-command-buffer.ts index 15820c3b923..fc829655f55 100644 --- a/cocos/core/gfx/webgl/webgl-primary-command-buffer.ts +++ b/cocos/core/gfx/webgl/webgl-primary-command-buffer.ts @@ -40,8 +40,6 @@ import { WebGLTexture } from './webgl-texture'; import { RenderPass } from '../base/render-pass'; import { WebGLRenderPass } from './webgl-render-pass'; -const _dynamicOffsets: number[] = []; - export class WebGLPrimaryCommandBuffer extends WebGLCommandBuffer { public beginRenderPass ( renderPass: RenderPass, @@ -134,14 +132,8 @@ export class WebGLPrimaryCommandBuffer extends WebGLCommandBuffer { } protected bindStates () { - _dynamicOffsets.length = 0; - for (let i = 0; i < this._curDynamicOffsets.length; i++) { - Array.prototype.push.apply(_dynamicOffsets, this._curDynamicOffsets[i]); - } - WebGLCmdFuncBindStates(this._device as WebGLDevice, - this._curGPUPipelineState, this._curGPUInputAssembler, this._curGPUDescriptorSets, _dynamicOffsets, - this._curViewport, this._curScissor, this._curLineWidth, this._curDepthBias, this._curBlendConstants, - this._curDepthBounds, this._curStencilWriteMask, this._curStencilCompareMask); + WebGLCmdFuncBindStates(this._device as WebGLDevice, this._curGPUPipelineState, this._curGPUInputAssembler, + this._curGPUDescriptorSets, this._curDynamicOffsets, this._curDynamicStates); this._isStateInvalied = false; } } diff --git a/cocos/core/gfx/webgl2/webgl2-command-buffer.ts b/cocos/core/gfx/webgl2/webgl2-command-buffer.ts index 5d9e9c1fc5b..ecf1d005519 100644 --- a/cocos/core/gfx/webgl2/webgl2-command-buffer.ts +++ b/cocos/core/gfx/webgl2/webgl2-command-buffer.ts @@ -31,7 +31,7 @@ import { CommandBufferType, StencilFace, BufferSource, CommandBufferInfo, - BufferTextureCopy, Color, Rect, Viewport, DrawInfo, + BufferTextureCopy, Color, Rect, Viewport, DrawInfo, DynamicStates, } from '../base/define'; import { Framebuffer } from '../base/framebuffer'; import { InputAssembler } from '../base/input-assembler'; @@ -60,28 +60,6 @@ import { WebGL2RenderPass } from './webgl2-render-pass'; import { GlobalBarrier } from '../base/global-barrier'; import { TextureBarrier } from '../base/texture-barrier'; -export interface IWebGL2DepthBias { - constantFactor: number; - clamp: number; - slopeFactor: number; -} - -export interface IWebGL2DepthBounds { - minBounds: number; - maxBounds: number; -} - -export interface IWebGL2StencilWriteMask { - face: StencilFace; - writeMask: number; -} - -export interface IWebGL2StencilCompareMask { - face: StencilFace; - reference: number; - compareMask: number; -} - export class WebGL2CommandBuffer extends CommandBuffer { public cmdPackage: WebGL2CmdPackage = new WebGL2CmdPackage(); protected _webGLAllocator: WebGL2CommandAllocator | null = null; @@ -89,15 +67,8 @@ export class WebGL2CommandBuffer extends CommandBuffer { protected _curGPUPipelineState: IWebGL2GPUPipelineState | null = null; protected _curGPUDescriptorSets: IWebGL2GPUDescriptorSet[] = []; protected _curGPUInputAssembler: IWebGL2GPUInputAssembler | null = null; - protected _curDynamicOffsets: number[][] = []; - protected _curViewport: Viewport | null = null; - protected _curScissor: Rect | null = null; - protected _curLineWidth: number | null = null; - protected _curDepthBias: IWebGL2DepthBias | null = null; - protected _curBlendConstants: number[] = []; - protected _curDepthBounds: IWebGL2DepthBounds | null = null; - protected _curStencilWriteMask: IWebGL2StencilWriteMask | null = null; - protected _curStencilCompareMask: IWebGL2StencilCompareMask | null = null; + protected _curDynamicOffsets: number[] = Array(8).fill(0); + protected _curDynamicStates: DynamicStates = new DynamicStates(); protected _isStateInvalied = false; public initialize (info: CommandBufferInfo): boolean { @@ -109,7 +80,6 @@ export class WebGL2CommandBuffer extends CommandBuffer { const setCount = (this._device as WebGL2Device).bindingMappingInfo.bufferOffsets.length; for (let i = 0; i < setCount; i++) { this._curGPUDescriptorSets.push(null!); - this._curDynamicOffsets.push([]); } return true; @@ -127,17 +97,6 @@ export class WebGL2CommandBuffer extends CommandBuffer { this._curGPUPipelineState = null; this._curGPUInputAssembler = null; this._curGPUDescriptorSets.length = 0; - for (let i = 0; i < this._curDynamicOffsets.length; i++) { - this._curDynamicOffsets[i].length = 0; - } - this._curViewport = null; - this._curScissor = null; - this._curLineWidth = null; - this._curDepthBias = null; - this._curBlendConstants.length = 0; - this._curDepthBounds = null; - this._curStencilWriteMask = null; - this._curStencilCompareMask = null; this._numDrawCalls = 0; this._numInstances = 0; this._numTris = 0; @@ -194,10 +153,13 @@ export class WebGL2CommandBuffer extends CommandBuffer { this._isStateInvalied = true; } if (dynamicOffsets) { - const offsets = this._curDynamicOffsets[set]; - for (let i = 0; i < dynamicOffsets.length; i++) offsets[i] = dynamicOffsets[i]; - offsets.length = dynamicOffsets.length; - this._isStateInvalied = true; + const gpuPipelineLayout = this._curGPUPipelineState?.gpuPipelineLayout; + if (gpuPipelineLayout) { + const offsets = this._curDynamicOffsets; + const idx = gpuPipelineLayout.dynamicOffsetOffsets[set]; + for (let i = 0; i < dynamicOffsets.length; i++) offsets[idx + i] = dynamicOffsets[i]; + this._isStateInvalied = true; + } } } @@ -208,123 +170,112 @@ export class WebGL2CommandBuffer extends CommandBuffer { } public setViewport (viewport: Viewport) { - if (!this._curViewport) { - this._curViewport = new Viewport(viewport.left, viewport.top, viewport.width, viewport.height, viewport.minDepth, viewport.maxDepth); - } else if (this._curViewport.left !== viewport.left - || this._curViewport.top !== viewport.top - || this._curViewport.width !== viewport.width - || this._curViewport.height !== viewport.height - || this._curViewport.minDepth !== viewport.minDepth - || this._curViewport.maxDepth !== viewport.maxDepth) { - this._curViewport.left = viewport.left; - this._curViewport.top = viewport.top; - this._curViewport.width = viewport.width; - this._curViewport.height = viewport.height; - this._curViewport.minDepth = viewport.minDepth; - this._curViewport.maxDepth = viewport.maxDepth; + const cache = this._curDynamicStates.viewport; + if (cache.left !== viewport.left + || cache.top !== viewport.top + || cache.width !== viewport.width + || cache.height !== viewport.height + || cache.minDepth !== viewport.minDepth + || cache.maxDepth !== viewport.maxDepth) { + cache.left = viewport.left; + cache.top = viewport.top; + cache.width = viewport.width; + cache.height = viewport.height; + cache.minDepth = viewport.minDepth; + cache.maxDepth = viewport.maxDepth; this._isStateInvalied = true; } } public setScissor (scissor: Rect) { - if (!this._curScissor) { - this._curScissor = new Rect(scissor.x, scissor.y, scissor.width, scissor.height); - } else if (this._curScissor.x !== scissor.x - || this._curScissor.y !== scissor.y - || this._curScissor.width !== scissor.width - || this._curScissor.height !== scissor.height) { - this._curScissor.x = scissor.x; - this._curScissor.y = scissor.y; - this._curScissor.width = scissor.width; - this._curScissor.height = scissor.height; + const cache = this._curDynamicStates.scissor; + if (cache.x !== scissor.x + || cache.y !== scissor.y + || cache.width !== scissor.width + || cache.height !== scissor.height) { + cache.x = scissor.x; + cache.y = scissor.y; + cache.width = scissor.width; + cache.height = scissor.height; this._isStateInvalied = true; } } public setLineWidth (lineWidth: number) { - if (this._curLineWidth !== lineWidth) { - this._curLineWidth = lineWidth; + if (this._curDynamicStates.lineWidth !== lineWidth) { + this._curDynamicStates.lineWidth = lineWidth; this._isStateInvalied = true; } } public setDepthBias (depthBiasConstantFactor: number, depthBiasClamp: number, depthBiasSlopeFactor: number) { - if (!this._curDepthBias) { - this._curDepthBias = { - constantFactor: depthBiasConstantFactor, - clamp: depthBiasClamp, - slopeFactor: depthBiasSlopeFactor, - }; - this._isStateInvalied = true; - } else if (this._curDepthBias.constantFactor !== depthBiasConstantFactor - || this._curDepthBias.clamp !== depthBiasClamp - || this._curDepthBias.slopeFactor !== depthBiasSlopeFactor) { - this._curDepthBias.constantFactor = depthBiasConstantFactor; - this._curDepthBias.clamp = depthBiasClamp; - this._curDepthBias.slopeFactor = depthBiasSlopeFactor; + const cache = this._curDynamicStates; + if (cache.depthBiasConstant !== depthBiasConstantFactor + || cache.depthBiasClamp !== depthBiasClamp + || cache.depthBiasSlope !== depthBiasSlopeFactor) { + cache.depthBiasConstant = depthBiasConstantFactor; + cache.depthBiasClamp = depthBiasClamp; + cache.depthBiasSlope = depthBiasSlopeFactor; this._isStateInvalied = true; } } - public setBlendConstants (blendConstants: number[]) { - if (blendConstants.length === 4 && ( - this._curBlendConstants[0] !== blendConstants[0] - || this._curBlendConstants[1] !== blendConstants[1] - || this._curBlendConstants[2] !== blendConstants[2] - || this._curBlendConstants[3] !== blendConstants[3])) { - this._curBlendConstants.length = 0; - Array.prototype.push.apply(this._curBlendConstants, blendConstants); + public setBlendConstants (blendConstants: Color) { + const cache = this._curDynamicStates.blendConstant; + if (cache.x !== blendConstants.x + || cache.y !== blendConstants.y + || cache.z !== blendConstants.z + || cache.w !== blendConstants.w) { + cache.copy(blendConstants); this._isStateInvalied = true; } } public setDepthBound (minDepthBounds: number, maxDepthBounds: number) { - if (!this._curDepthBounds) { - this._curDepthBounds = { - minBounds: minDepthBounds, - maxBounds: maxDepthBounds, - }; - this._isStateInvalied = true; - } else if (this._curDepthBounds.minBounds !== minDepthBounds - || this._curDepthBounds.maxBounds !== maxDepthBounds) { - this._curDepthBounds = { - minBounds: minDepthBounds, - maxBounds: maxDepthBounds, - }; + const cache = this._curDynamicStates; + if (cache.depthMinBounds !== minDepthBounds + || cache.depthMaxBounds !== maxDepthBounds) { + cache.depthMinBounds = minDepthBounds; + cache.depthMaxBounds = maxDepthBounds; this._isStateInvalied = true; } } public setStencilWriteMask (face: StencilFace, writeMask: number) { - if (!this._curStencilWriteMask) { - this._curStencilWriteMask = { - face, - writeMask, - }; - this._isStateInvalied = true; - } else if (this._curStencilWriteMask.face !== face - || this._curStencilWriteMask.writeMask !== writeMask) { - this._curStencilWriteMask.face = face; - this._curStencilWriteMask.writeMask = writeMask; - this._isStateInvalied = true; + const front = this._curDynamicStates.stencilStatesFront; + const back = this._curDynamicStates.stencilStatesBack; + if (face & StencilFace.FRONT) { + if (front.writeMask !== writeMask) { + front.writeMask = writeMask; + this._isStateInvalied = true; + } + } + if (face & StencilFace.BACK) { + if (back.writeMask !== writeMask) { + back.writeMask = writeMask; + this._isStateInvalied = true; + } } } public setStencilCompareMask (face: StencilFace, reference: number, compareMask: number) { - if (!this._curStencilCompareMask) { - this._curStencilCompareMask = { - face, - reference, - compareMask, - }; - this._isStateInvalied = true; - } else if (this._curStencilCompareMask.face !== face - || this._curStencilCompareMask.reference !== reference - || this._curStencilCompareMask.compareMask !== compareMask) { - this._curStencilCompareMask.face = face; - this._curStencilCompareMask.reference = reference; - this._curStencilCompareMask.compareMask = compareMask; - this._isStateInvalied = true; + const front = this._curDynamicStates.stencilStatesFront; + const back = this._curDynamicStates.stencilStatesBack; + if (face & StencilFace.FRONT) { + if (front.compareMask !== compareMask + || front.reference !== reference) { + front.reference = reference; + front.compareMask = compareMask; + this._isStateInvalied = true; + } + } + if (face & StencilFace.BACK) { + if (back.compareMask !== compareMask + || back.reference !== reference) { + back.reference = reference; + back.compareMask = compareMask; + this._isStateInvalied = true; + } } } @@ -479,18 +430,9 @@ export class WebGL2CommandBuffer extends CommandBuffer { const bindStatesCmd = this._webGLAllocator!.bindStatesCmdPool.alloc(WebGL2CmdBindStates); bindStatesCmd.gpuPipelineState = this._curGPUPipelineState; Array.prototype.push.apply(bindStatesCmd.gpuDescriptorSets, this._curGPUDescriptorSets); - for (let i = 0; i < this._curDynamicOffsets.length; i++) { - Array.prototype.push.apply(bindStatesCmd.dynamicOffsets, this._curDynamicOffsets[i]); - } + Array.prototype.push.apply(bindStatesCmd.dynamicOffsets, this._curDynamicOffsets); bindStatesCmd.gpuInputAssembler = this._curGPUInputAssembler; - bindStatesCmd.viewport = this._curViewport; - bindStatesCmd.scissor = this._curScissor; - bindStatesCmd.lineWidth = this._curLineWidth; - bindStatesCmd.depthBias = this._curDepthBias; - Array.prototype.push.apply(bindStatesCmd.blendConstants, this._curBlendConstants); - bindStatesCmd.depthBounds = this._curDepthBounds; - bindStatesCmd.stencilWriteMask = this._curStencilWriteMask; - bindStatesCmd.stencilCompareMask = this._curStencilCompareMask; + bindStatesCmd.dynamicStates = this._curDynamicStates; this.cmdPackage.bindStatesCmds.push(bindStatesCmd); this.cmdPackage.cmds.push(WebGL2Cmd.BIND_STATES); diff --git a/cocos/core/gfx/webgl2/webgl2-commands.ts b/cocos/core/gfx/webgl2/webgl2-commands.ts index bda8ba6c3f2..8f1f376c9e8 100644 --- a/cocos/core/gfx/webgl2/webgl2-commands.ts +++ b/cocos/core/gfx/webgl2/webgl2-commands.ts @@ -27,17 +27,11 @@ import { CachedArray } from '../../memop/cached-array'; import { error, errorID } from '../../platform'; import { BufferUsageBit, ColorMask, CullMode, DynamicStateFlagBit, Filter, Format, TextureType, Type, FormatInfo, - FormatInfos, FormatSize, LoadOp, MemoryUsageBit, SampleCount, ShaderStageFlagBit, StencilFace, TextureFlagBit, - Color, Rect, Viewport, BufferTextureCopy, BufferSource, DrawInfo, IndirectBuffer, UniformBlock, + FormatInfos, FormatSize, LoadOp, MemoryUsageBit, SampleCount, ShaderStageFlagBit, TextureFlagBit, + Color, Rect, BufferTextureCopy, BufferSource, DrawInfo, IndirectBuffer, UniformBlock, DynamicStates, } from '../base/define'; import { WebGLEXT } from '../webgl/webgl-define'; import { WebGL2CommandAllocator } from './webgl2-command-allocator'; -import { - IWebGL2DepthBias, - IWebGL2DepthBounds, - IWebGL2StencilCompareMask, - IWebGL2StencilWriteMask, -} from './webgl2-command-buffer'; import { WebGL2Device } from './webgl2-device'; import { IWebGL2GPUInputAssembler, @@ -651,7 +645,6 @@ export enum WebGL2Cmd { export abstract class WebGL2CmdObject { public cmdType: WebGL2Cmd; - public refCount = 0; constructor (type: WebGL2Cmd) { @@ -663,15 +656,10 @@ export abstract class WebGL2CmdObject { export class WebGL2CmdBeginRenderPass extends WebGL2CmdObject { public gpuRenderPass: IWebGL2GPURenderPass | null = null; - public gpuFramebuffer: IWebGL2GPUFramebuffer | null = null; - public renderArea = new Rect(); - public clearColors: Color[] = []; - public clearDepth = 1.0; - public clearStencil = 0; constructor () { @@ -686,28 +674,10 @@ export class WebGL2CmdBeginRenderPass extends WebGL2CmdObject { export class WebGL2CmdBindStates extends WebGL2CmdObject { public gpuPipelineState: IWebGL2GPUPipelineState | null = null; - public gpuInputAssembler: IWebGL2GPUInputAssembler | null = null; - public gpuDescriptorSets: IWebGL2GPUDescriptorSet[] = []; - public dynamicOffsets: number[] = []; - - public viewport: Viewport | null = null; - - public scissor: Rect | null = null; - - public lineWidth: number | null = null; - - public depthBias: IWebGL2DepthBias | null = null; - - public blendConstants: number[] = []; - - public depthBounds: IWebGL2DepthBounds | null = null; - - public stencilWriteMask: IWebGL2StencilWriteMask | null = null; - - public stencilCompareMask: IWebGL2StencilCompareMask | null = null; + public dynamicStates: DynamicStates = new DynamicStates(); constructor () { super(WebGL2Cmd.BIND_STATES); @@ -718,14 +688,6 @@ export class WebGL2CmdBindStates extends WebGL2CmdObject { this.gpuInputAssembler = null; this.gpuDescriptorSets.length = 0; this.dynamicOffsets.length = 0; - this.viewport = null; - this.scissor = null; - this.lineWidth = null; - this.depthBias = null; - this.blendConstants.length = 0; - this.depthBounds = null; - this.stencilWriteMask = null; - this.stencilCompareMask = null; } } @@ -742,11 +704,8 @@ export class WebGL2CmdDraw extends WebGL2CmdObject { export class WebGL2CmdUpdateBuffer extends WebGL2CmdObject { public gpuBuffer: IWebGL2GPUBuffer | null = null; - public buffer: BufferSource | null = null; - public offset = 0; - public size = 0; constructor () { @@ -761,9 +720,7 @@ export class WebGL2CmdUpdateBuffer extends WebGL2CmdObject { export class WebGL2CmdCopyBufferToTexture extends WebGL2CmdObject { public gpuTexture: IWebGL2GPUTexture | null = null; - public buffers: ArrayBufferView[] = []; - public regions: BufferTextureCopy[] = []; constructor () { @@ -779,15 +736,10 @@ export class WebGL2CmdCopyBufferToTexture extends WebGL2CmdObject { export class WebGL2CmdPackage { public cmds: CachedArray = new CachedArray(1); - public beginRenderPassCmds: CachedArray = new CachedArray(1); - public bindStatesCmds: CachedArray = new CachedArray(1); - public drawCmds: CachedArray = new CachedArray(1); - public updateBufferCmds: CachedArray = new CachedArray(1); - public copyBufferToTextureCmds: CachedArray = new CachedArray(1); public clearCmds (allocator: WebGL2CommandAllocator) { @@ -1959,14 +1911,7 @@ export function WebGL2CmdFuncBindStates ( gpuInputAssembler: IWebGL2GPUInputAssembler | null, gpuDescriptorSets: IWebGL2GPUDescriptorSet[], dynamicOffsets: number[], - viewport: Viewport | null, - scissor: Rect | null, - lineWidth: number | null, - depthBias: IWebGL2DepthBias | null, - blendConstants: number[], - depthBounds: IWebGL2DepthBounds | null, - stencilWriteMask: IWebGL2StencilWriteMask | null, - stencilCompareMask: IWebGL2StencilCompareMask | null, + dynamicStates: DynamicStates, ) { const { gl } = device; const cache = device.stateCache; @@ -2419,149 +2364,89 @@ export function WebGL2CmdFuncBindStates ( const dynamicState = gpuPipelineState.dynamicStates[k]; switch (dynamicState) { case DynamicStateFlagBit.VIEWPORT: { - if (viewport) { - if (cache.viewport.left !== viewport.left - || cache.viewport.top !== viewport.top - || cache.viewport.width !== viewport.width - || cache.viewport.height !== viewport.height) { - gl.viewport(viewport.left, viewport.top, viewport.width, viewport.height); - - cache.viewport.left = viewport.left; - cache.viewport.top = viewport.top; - cache.viewport.width = viewport.width; - cache.viewport.height = viewport.height; - } + const viewport = dynamicStates.viewport; + if (cache.viewport.left !== viewport.left + || cache.viewport.top !== viewport.top + || cache.viewport.width !== viewport.width + || cache.viewport.height !== viewport.height) { + gl.viewport(viewport.left, viewport.top, viewport.width, viewport.height); + + cache.viewport.left = viewport.left; + cache.viewport.top = viewport.top; + cache.viewport.width = viewport.width; + cache.viewport.height = viewport.height; } break; } case DynamicStateFlagBit.SCISSOR: { - if (scissor) { - if (cache.scissorRect.x !== scissor.x - || cache.scissorRect.y !== scissor.y - || cache.scissorRect.width !== scissor.width - || cache.scissorRect.height !== scissor.height) { - gl.scissor(scissor.x, scissor.y, scissor.width, scissor.height); - - cache.scissorRect.x = scissor.x; - cache.scissorRect.y = scissor.y; - cache.scissorRect.width = scissor.width; - cache.scissorRect.height = scissor.height; - } + const scissor = dynamicStates.scissor; + if (cache.scissorRect.x !== scissor.x + || cache.scissorRect.y !== scissor.y + || cache.scissorRect.width !== scissor.width + || cache.scissorRect.height !== scissor.height) { + gl.scissor(scissor.x, scissor.y, scissor.width, scissor.height); + + cache.scissorRect.x = scissor.x; + cache.scissorRect.y = scissor.y; + cache.scissorRect.width = scissor.width; + cache.scissorRect.height = scissor.height; } break; } case DynamicStateFlagBit.LINE_WIDTH: { - if (lineWidth) { - if (cache.rs.lineWidth !== lineWidth) { - gl.lineWidth(lineWidth); - cache.rs.lineWidth = lineWidth; - } + if (cache.rs.lineWidth !== dynamicStates.lineWidth) { + gl.lineWidth(dynamicStates.lineWidth); + cache.rs.lineWidth = dynamicStates.lineWidth; } break; } case DynamicStateFlagBit.DEPTH_BIAS: { - if (depthBias) { - if ((cache.rs.depthBias !== depthBias.constantFactor) - || (cache.rs.depthBiasSlop !== depthBias.slopeFactor)) { - gl.polygonOffset(depthBias.constantFactor, depthBias.slopeFactor); - cache.rs.depthBias = depthBias.constantFactor; - cache.rs.depthBiasSlop = depthBias.slopeFactor; - } + if (cache.rs.depthBias !== dynamicStates.depthBiasConstant + || cache.rs.depthBiasSlop !== dynamicStates.depthBiasSlope) { + gl.polygonOffset(dynamicStates.depthBiasConstant, dynamicStates.depthBiasSlope); + cache.rs.depthBias = dynamicStates.depthBiasConstant; + cache.rs.depthBiasSlop = dynamicStates.depthBiasSlope; } break; } case DynamicStateFlagBit.BLEND_CONSTANTS: { - if ((cache.bs.blendColor.x !== blendConstants[0]) - || (cache.bs.blendColor.y !== blendConstants[1]) - || (cache.bs.blendColor.z !== blendConstants[2]) - || (cache.bs.blendColor.w !== blendConstants[3])) { - gl.blendColor(blendConstants[0], blendConstants[1], blendConstants[2], blendConstants[3]); - - [cache.bs.blendColor.x, cache.bs.blendColor.y, cache.bs.blendColor.z, cache.bs.blendColor.w] = blendConstants; + const blendConstant = dynamicStates.blendConstant; + if ((cache.bs.blendColor.x !== blendConstant.x) + || (cache.bs.blendColor.y !== blendConstant.y) + || (cache.bs.blendColor.z !== blendConstant.z) + || (cache.bs.blendColor.w !== blendConstant.w)) { + gl.blendColor(blendConstant.x, blendConstant.y, blendConstant.z, blendConstant.w); + cache.bs.blendColor.copy(blendConstant); } break; } case DynamicStateFlagBit.STENCIL_WRITE_MASK: { - if (stencilWriteMask) { - switch (stencilWriteMask.face) { - case StencilFace.FRONT: { - if (cache.dss.stencilWriteMaskFront !== stencilWriteMask.writeMask) { - gl.stencilMaskSeparate(gl.FRONT, stencilWriteMask.writeMask); - cache.dss.stencilWriteMaskFront = stencilWriteMask.writeMask; - } - break; - } - case StencilFace.BACK: { - if (cache.dss.stencilWriteMaskBack !== stencilWriteMask.writeMask) { - gl.stencilMaskSeparate(gl.BACK, stencilWriteMask.writeMask); - cache.dss.stencilWriteMaskBack = stencilWriteMask.writeMask; - } - break; - } - case StencilFace.ALL: { - if (cache.dss.stencilWriteMaskFront !== stencilWriteMask.writeMask - || cache.dss.stencilWriteMaskBack !== stencilWriteMask.writeMask) { - gl.stencilMask(stencilWriteMask.writeMask); - cache.dss.stencilWriteMaskFront = stencilWriteMask.writeMask; - cache.dss.stencilWriteMaskBack = stencilWriteMask.writeMask; - } - break; - } - default: - } + const front = dynamicStates.stencilStatesFront; + const back = dynamicStates.stencilStatesBack; + if (cache.dss.stencilWriteMaskFront !== front.writeMask) { + gl.stencilMaskSeparate(gl.FRONT, front.writeMask); + cache.dss.stencilWriteMaskFront = front.writeMask; + } + if (cache.dss.stencilWriteMaskBack !== back.writeMask) { + gl.stencilMaskSeparate(gl.BACK, back.writeMask); + cache.dss.stencilWriteMaskBack = back.writeMask; } break; } case DynamicStateFlagBit.STENCIL_COMPARE_MASK: { - if (stencilCompareMask) { - switch (stencilCompareMask.face) { - case StencilFace.FRONT: { - if (cache.dss.stencilRefFront !== stencilCompareMask.reference - || cache.dss.stencilReadMaskFront !== stencilCompareMask.compareMask) { - gl.stencilFuncSeparate( - gl.FRONT, - WebGLCmpFuncs[cache.dss.stencilFuncFront], - stencilCompareMask.reference, - stencilCompareMask.compareMask, - ); - cache.dss.stencilRefFront = stencilCompareMask.reference; - cache.dss.stencilReadMaskFront = stencilCompareMask.compareMask; - } - break; - } - case StencilFace.BACK: { - if (cache.dss.stencilRefBack !== stencilCompareMask.reference - || cache.dss.stencilReadMaskBack !== stencilCompareMask.compareMask) { - gl.stencilFuncSeparate( - gl.BACK, - WebGLCmpFuncs[cache.dss.stencilFuncBack], - stencilCompareMask.reference, - stencilCompareMask.compareMask, - ); - cache.dss.stencilRefBack = stencilCompareMask.reference; - cache.dss.stencilReadMaskBack = stencilCompareMask.compareMask; - } - break; - } - case StencilFace.ALL: { - if (cache.dss.stencilRefFront !== stencilCompareMask.reference - || cache.dss.stencilReadMaskFront !== stencilCompareMask.compareMask - || cache.dss.stencilRefBack !== stencilCompareMask.reference - || cache.dss.stencilReadMaskBack !== stencilCompareMask.compareMask) { - gl.stencilFunc( - WebGLCmpFuncs[cache.dss.stencilFuncBack], - stencilCompareMask.reference, - stencilCompareMask.compareMask, - ); - cache.dss.stencilRefFront = stencilCompareMask.reference; - cache.dss.stencilReadMaskFront = stencilCompareMask.compareMask; - cache.dss.stencilRefBack = stencilCompareMask.reference; - cache.dss.stencilReadMaskBack = stencilCompareMask.compareMask; - } - break; - } - default: - } + const front = dynamicStates.stencilStatesFront; + const back = dynamicStates.stencilStatesBack; + if (cache.dss.stencilRefFront !== front.reference + || cache.dss.stencilReadMaskFront !== front.compareMask) { + gl.stencilFuncSeparate(gl.FRONT, WebGLCmpFuncs[cache.dss.stencilFuncFront], front.reference, front.compareMask); + cache.dss.stencilRefFront = front.reference; + cache.dss.stencilReadMaskFront = front.compareMask; + } + if (cache.dss.stencilRefBack !== back.reference + || cache.dss.stencilReadMaskBack !== back.compareMask) { + gl.stencilFuncSeparate(gl.BACK, WebGLCmpFuncs[cache.dss.stencilFuncBack], back.reference, back.compareMask); + cache.dss.stencilRefBack = back.reference; + cache.dss.stencilReadMaskBack = back.compareMask; } break; } @@ -2645,9 +2530,8 @@ export function WebGL2CmdFuncExecuteCmds (device: WebGL2Device, cmdPackage: WebG */ case WebGL2Cmd.BIND_STATES: { const cmd2 = cmdPackage.bindStatesCmds.array[cmdId]; - WebGL2CmdFuncBindStates(device, cmd2.gpuPipelineState, cmd2.gpuInputAssembler, cmd2.gpuDescriptorSets, cmd2.dynamicOffsets, - cmd2.viewport, cmd2.scissor, cmd2.lineWidth, cmd2.depthBias, cmd2.blendConstants, - cmd2.depthBounds, cmd2.stencilWriteMask, cmd2.stencilCompareMask); + WebGL2CmdFuncBindStates(device, cmd2.gpuPipelineState, cmd2.gpuInputAssembler, + cmd2.gpuDescriptorSets, cmd2.dynamicOffsets, cmd2.dynamicStates); break; } case WebGL2Cmd.DRAW: { diff --git a/cocos/core/gfx/webgl2/webgl2-device.ts b/cocos/core/gfx/webgl2/webgl2-device.ts index f6d5bd2070d..dfdac74f837 100644 --- a/cocos/core/gfx/webgl2/webgl2-device.ts +++ b/cocos/core/gfx/webgl2/webgl2-device.ts @@ -54,12 +54,16 @@ import { WebGL2Sampler } from './webgl2-sampler'; import { WebGL2Shader } from './webgl2-shader'; import { WebGL2StateCache } from './webgl2-state-cache'; import { WebGL2Texture } from './webgl2-texture'; -import { getTypedArrayConstructor, CommandBufferType, Filter, Format, FormatInfos, DescriptorSetLayoutInfo, DescriptorSetInfo, +import { + getTypedArrayConstructor, CommandBufferType, Filter, Format, FormatInfos, DescriptorSetLayoutInfo, DescriptorSetInfo, PipelineLayoutInfo, BufferViewInfo, CommandBufferInfo, BufferInfo, BindingMappingInfo, FramebufferInfo, InputAssemblerInfo, QueueInfo, RenderPassInfo, SamplerInfo, ShaderInfo, TextureInfo, TextureViewInfo, DeviceInfo, Rect, GlobalBarrierInfo, TextureBarrierInfo, - QueueType, TextureFlagBit, TextureType, TextureUsageBit, API, Feature, BufferTextureCopy } from '../base/define'; -import { GFXFormatToWebGLFormat, GFXFormatToWebGLType, WebGL2CmdFuncBlitFramebuffer, - WebGL2CmdFuncCopyBuffersToTexture, WebGL2CmdFuncCopyTexImagesToTexture } from './webgl2-commands'; + QueueType, TextureFlagBit, TextureType, TextureUsageBit, API, Feature, BufferTextureCopy, +} from '../base/define'; +import { + GFXFormatToWebGLFormat, GFXFormatToWebGLType, WebGL2CmdFuncBlitFramebuffer, + WebGL2CmdFuncCopyBuffersToTexture, WebGL2CmdFuncCopyTexImagesToTexture, +} from './webgl2-commands'; import { GlobalBarrier } from '../base/global-barrier'; import { TextureBarrier } from '../base/texture-barrier'; @@ -233,10 +237,8 @@ export class WebGL2Device extends Device { this.stateCache.initialize(this._caps.maxTextureUnits, this._caps.maxUniformBufferBindings, this._caps.maxVertexAttributes); this._devicePixelRatio = info.devicePixelRatio || 1.0; - this._width = this._canvas.width; - this._height = this._canvas.height; - this._nativeWidth = Math.max(info.nativeWidth || this._width, 0); - this._nativeHeight = Math.max(info.nativeHeight || this._height, 0); + this._width = info.width; + this._height = info.height; this._colorFmt = Format.RGBA8; @@ -344,7 +346,6 @@ export class WebGL2Device extends Device { console.info(`VERSION: ${this._version}`); console.info(`DPR: ${this._devicePixelRatio}`); console.info(`SCREEN_SIZE: ${this._width} x ${this._height}`); - console.info(`NATIVE_SIZE: ${this._nativeWidth} x ${this._nativeHeight}`); console.info(`MAX_VERTEX_ATTRIBS: ${this._caps.maxVertexAttributes}`); console.info(`MAX_VERTEX_UNIFORM_VECTORS: ${this._caps.maxVertexUniformVectors}`); console.info(`MAX_FRAGMENT_UNIFORM_VECTORS: ${this._caps.maxFragmentUniformVectors}`); diff --git a/cocos/core/gfx/webgl2/webgl2-gpu-objects.ts b/cocos/core/gfx/webgl2/webgl2-gpu-objects.ts index f49d86b4667..1c35014c106 100644 --- a/cocos/core/gfx/webgl2/webgl2-gpu-objects.ts +++ b/cocos/core/gfx/webgl2/webgl2-gpu-objects.ts @@ -187,6 +187,7 @@ export interface IWebGL2GPUDescriptorSetLayout { export interface IWebGL2GPUPipelineLayout { gpuSetLayouts: IWebGL2GPUDescriptorSetLayout[]; dynamicOffsetCount: number; + dynamicOffsetOffsets: number[]; dynamicOffsetIndices: number[][]; } diff --git a/cocos/core/gfx/webgl2/webgl2-pipeline-layout.ts b/cocos/core/gfx/webgl2/webgl2-pipeline-layout.ts index 4176905b2c8..73fa325cf76 100644 --- a/cocos/core/gfx/webgl2/webgl2-pipeline-layout.ts +++ b/cocos/core/gfx/webgl2/webgl2-pipeline-layout.ts @@ -40,6 +40,7 @@ export class WebGL2PipelineLayout extends PipelineLayout { const gpuSetLayouts: IWebGL2GPUDescriptorSetLayout[] = []; let dynamicOffsetCount = 0; + const dynamicOffsetOffsets: number[] = []; for (let i = 0; i < this._setLayouts.length; i++) { const setLayout = this._setLayouts[i] as WebGL2DescriptorSetLayout; const dynamicBindings = setLayout.gpuDescriptorSetLayout.dynamicBindings; @@ -51,6 +52,7 @@ export class WebGL2PipelineLayout extends PipelineLayout { gpuSetLayouts.push(setLayout.gpuDescriptorSetLayout); dynamicOffsetIndices.push(indices); + dynamicOffsetOffsets.push(dynamicOffsetCount); dynamicOffsetCount += dynamicBindings.length; } @@ -58,6 +60,7 @@ export class WebGL2PipelineLayout extends PipelineLayout { gpuSetLayouts, dynamicOffsetIndices, dynamicOffsetCount, + dynamicOffsetOffsets, }; return true; diff --git a/cocos/core/gfx/webgl2/webgl2-primary-command-buffer.ts b/cocos/core/gfx/webgl2/webgl2-primary-command-buffer.ts index 8e190bbf928..084f9370001 100644 --- a/cocos/core/gfx/webgl2/webgl2-primary-command-buffer.ts +++ b/cocos/core/gfx/webgl2/webgl2-primary-command-buffer.ts @@ -40,8 +40,6 @@ import { WebGL2Texture } from './webgl2-texture'; import { RenderPass } from '../base/render-pass'; import { WebGL2RenderPass } from './webgl2-render-pass'; -const _dynamicOffsets: number[] = []; - export class WebGL2PrimaryCommandBuffer extends WebGL2CommandBuffer { public beginRenderPass ( renderPass: RenderPass, @@ -134,14 +132,8 @@ export class WebGL2PrimaryCommandBuffer extends WebGL2CommandBuffer { } protected bindStates () { - _dynamicOffsets.length = 0; - for (let i = 0; i < this._curDynamicOffsets.length; i++) { - Array.prototype.push.apply(_dynamicOffsets, this._curDynamicOffsets[i]); - } - WebGL2CmdFuncBindStates(this._device as WebGL2Device, - this._curGPUPipelineState, this._curGPUInputAssembler, this._curGPUDescriptorSets, _dynamicOffsets, - this._curViewport, this._curScissor, this._curLineWidth, this._curDepthBias, this._curBlendConstants, - this._curDepthBounds, this._curStencilWriteMask, this._curStencilCompareMask); + WebGL2CmdFuncBindStates(this._device as WebGL2Device, this._curGPUPipelineState, this._curGPUInputAssembler, + this._curGPUDescriptorSets, this._curDynamicOffsets, this._curDynamicStates); this._isStateInvalied = false; } } diff --git a/cocos/core/math/color.ts b/cocos/core/math/color.ts index 06606f7d42c..ca02a7cad1a 100644 --- a/cocos/core/math/color.ts +++ b/cocos/core/math/color.ts @@ -59,7 +59,7 @@ export class Color extends ValueType { * @en Copy content of a color into another and save the results to out color. * @zh 获得指定颜色的拷贝 */ - public static clone (a: Out) { + public static clone (a: Readonly) { const out = new Color(); if (a._val) { out._val = a._val; @@ -73,7 +73,7 @@ export class Color extends ValueType { * @en Clone a color and save the results to out color. * @zh 复制目标颜色 */ - public static copy (out: Out, a: Out) { + public static copy (out: Out, a: Readonly) { out.r = a.r; out.g = a.g; out.b = a.b; @@ -111,7 +111,7 @@ export class Color extends ValueType { * @en Add two colors by components. And save the results to out color. * @zh 逐通道颜色加法 */ - public static add (out: Out, a: Out, b: Out) { + public static add (out: Out, a: Readonly, b: Readonly) { out.r = a.r + b.r; out.g = a.g + b.g; out.b = a.b + b.b; @@ -123,7 +123,7 @@ export class Color extends ValueType { * @en Subtract each components of color b from each components of color a. And save the results to out color. * @zh 逐通道颜色减法 */ - public static subtract (out: Out, a: Out, b: Out) { + public static subtract (out: Out, a: Readonly, b: Readonly) { out.r = a.r - b.r; out.g = a.g - b.g; out.b = a.b - b.b; @@ -135,7 +135,7 @@ export class Color extends ValueType { * @en Multiply each components of two colors. And save the results to out color. * @zh 逐通道颜色乘法 */ - public static multiply (out: Out, a: Out, b: Out) { + public static multiply (out: Out, a: Readonly, b: Readonly) { out.r = a.r * b.r; out.g = a.g * b.g; out.b = a.b * b.b; @@ -147,7 +147,7 @@ export class Color extends ValueType { * @en Divide each components of color a by each components of color b. And save the results to out color. * @zh 逐通道颜色除法 */ - public static divide (out: Out, a: Out, b: Out) { + public static divide (out: Out, a: Readonly, b: Readonly) { out.r = a.r / b.r; out.g = a.g / b.g; out.b = a.b / b.b; @@ -159,7 +159,7 @@ export class Color extends ValueType { * @en Multiply all channels in a color with the given scale factor, and save the results to out color. * @zh 全通道统一缩放颜色 */ - public static scale (out: Out, a: Out, b: number) { + public static scale (out: Out, a: Readonly, b: number) { out.r = a.r * b; out.g = a.g * b; out.b = a.b * b; @@ -215,7 +215,7 @@ export class Color extends ValueType { * @en Check whether the two given colors are identical * @zh 颜色等价判断 */ - public static strictEquals (a: Out, b: Out) { + public static strictEquals (a: Readonly, b: Readonly) { return a.r === b.r && a.g === b.g && a.b === b.b && a.a === b.a; } @@ -223,7 +223,7 @@ export class Color extends ValueType { * @en Check whether the two given colors are approximately equivalent. Difference of each channel is smaller that the epsilon. * @zh 排除浮点数误差的颜色近似等价判断 */ - public static equals (a: Out, b: Out, epsilon = EPSILON) { + public static equals (a: Readonly, b: Readonly, epsilon = EPSILON) { return (Math.abs(a.r - b.r) <= epsilon * Math.max(1.0, Math.abs(a.r), Math.abs(b.r)) && Math.abs(a.g - b.g) <= epsilon * Math.max(1.0, Math.abs(a.g), Math.abs(b.g)) && Math.abs(a.b - b.b) <= epsilon * Math.max(1.0, Math.abs(a.b), Math.abs(b.b)) @@ -234,7 +234,7 @@ export class Color extends ValueType { * @en Convert the given color to a hex color value. And save the results to out color. * @zh 获取指定颜色的整型数据表示 */ - public static hex (a: Out) { + public static hex (a: Readonly) { return ((a.r * 255) << 24 | (a.g * 255) << 16 | (a.b * 255) << 8 | a.a * 255) >>> 0; } @@ -306,7 +306,7 @@ export class Color extends ValueType { * @zh 构造与指定颜色相等的颜色。 * @param other Specified color */ - constructor (other: Color); + constructor (other: Readonly); /** * @en Construct a color form the hex color string @@ -326,7 +326,7 @@ export class Color extends ValueType { */ constructor (r?: number, g?: number, b?: number, a?: number); - constructor (r?: number | Color | string, g?: number, b?: number, a?: number) { + constructor (r?: number | Readonly | string, g?: number, b?: number, a?: number) { super(); if (typeof r === 'string') { this.fromHEX(r); @@ -353,7 +353,7 @@ export class Color extends ValueType { * @param other Specified color * @returns Returns `true` when all channels of both colours are equal; otherwise returns `false`. */ - public equals (other: Color) { + public equals (other: Readonly) { return other && this._val === other._val; } @@ -553,6 +553,9 @@ export class Color extends ValueType { g = p; b = q; break; + + default: + break; } } r *= 255; @@ -609,7 +612,7 @@ export class Color extends ValueType { * @param [a=255] alpha component of the color * @returns Current color. */ - public set(other: Color): Color; + public set(other: Readonly): Color; public set(r?: number, g?: number, b?: number, a?: number): Color; public set (r?: number | Color, g?: number, b?: number, a?: number): Color { if (typeof r === 'object') { @@ -637,7 +640,7 @@ export class Color extends ValueType { * @zh 将当前颜色乘以与指定颜色 * @param other The specified color. */ - public multiply (other: Color) { + public multiply (other: Readonly) { const r = ((this._val & 0x000000ff) * other.r) >> 8; const g = ((this._val & 0x0000ff00) * other.g) >> 8; const b = ((this._val & 0x00ff0000) * other.b) >> 8; diff --git a/cocos/core/math/index.ts b/cocos/core/math/index.ts index fe2fd7cca3d..adaf0b78b90 100644 --- a/cocos/core/math/index.ts +++ b/cocos/core/math/index.ts @@ -49,3 +49,4 @@ export { Rect, rect } from './rect'; export { Color, color } from './color'; export * from './utils'; export * from './type-define'; +export * from './math-base'; diff --git a/cocos/core/math/mat3.ts b/cocos/core/math/mat3.ts index 0ea3cde6bce..03c2a0fa72d 100644 --- a/cocos/core/math/mat3.ts +++ b/cocos/core/math/mat3.ts @@ -29,26 +29,26 @@ */ import { CCClass } from '../data/class'; -import { ValueType } from '../value-types/value-type'; import { Quat } from './quat'; -import { IMat3Like, IMat4Like, IQuatLike, IVec2Like, IVec3Like } from './type-define'; +import { IMat3Like, IMat4Like, IQuatLike, IVec2Like, IVec3Like, FloatArray } from './type-define'; import { EPSILON } from './utils'; import { Vec3 } from './vec3'; import { legacyCC } from '../global-exports'; +import { MathBase } from './math-base'; /** * @en Mathematical 3x3 matrix. * @zh 表示三维(3x3)矩阵。 */ -export class Mat3 extends ValueType { +export class Mat3 extends MathBase { public static IDENTITY = Object.freeze(new Mat3()); /** * @en Clone a matrix and save the results to out matrix * @zh 获得指定矩阵的拷贝 */ - public static clone (a: Out) { + public static clone (a: Readonly) { return new Mat3( a.m00, a.m01, a.m02, a.m03, a.m04, a.m05, @@ -60,7 +60,7 @@ export class Mat3 extends ValueType { * @en Copy content of a matrix into another and save the results to out matrix * @zh 复制目标矩阵 */ - public static copy (out: Out, a: Out) { + public static copy (out: Out, a: Readonly) { out.m00 = a.m00; out.m01 = a.m01; out.m02 = a.m02; @@ -110,7 +110,7 @@ export class Mat3 extends ValueType { * @en Transposes a matrix and save the results to out matrix * @zh 转置矩阵 */ - public static transpose (out: Out, a: Out) { + public static transpose (out: Out, a: Readonly) { // If we are transposing ourselves we can skip a few steps but have to cache some values if (out === a) { const a01 = a.m01; @@ -141,7 +141,7 @@ export class Mat3 extends ValueType { * @en Inverts a matrix. When matrix is not invertible the matrix will be set to zeros. * @zh 矩阵求逆,注意,在矩阵不可逆时,会返回一个全为 0 的矩阵。 */ - public static invert (out: Out, a: Out) { + public static invert (out: Out, a: Readonly) { const a00 = a.m00; const a01 = a.m01; const a02 = a.m02; const a10 = a.m03; const a11 = a.m04; const a12 = a.m05; const a20 = a.m06; const a21 = a.m07; const a22 = a.m08; @@ -177,7 +177,7 @@ export class Mat3 extends ValueType { * @en Calculates the determinant of a matrix * @zh 矩阵行列式 */ - public static determinant (a: Out) { + public static determinant (a: Readonly) { const a00 = a.m00; const a01 = a.m01; const a02 = a.m02; const a10 = a.m03; const a11 = a.m04; const a12 = a.m05; const a20 = a.m06; const a21 = a.m07; const a22 = a.m08; @@ -189,7 +189,7 @@ export class Mat3 extends ValueType { * @en Multiply two matrices explicitly and save the results to out matrix * @zh 矩阵乘法 */ - public static multiply (out: Out, a: Out, b: Out) { + public static multiply (out: Out, a: Readonly, b: Readonly) { const a00 = a.m00; const a01 = a.m01; const a02 = a.m02; const a10 = a.m03; const a11 = a.m04; const a12 = a.m05; const a20 = a.m06; const a21 = a.m07; const a22 = a.m08; @@ -216,7 +216,7 @@ export class Mat3 extends ValueType { * @en Take the first third order of the fourth order matrix and multiply by the third order matrix * @zh 取四阶矩阵的前三阶,与三阶矩阵相乘 */ - public static multiplyMat4 (out: Out, a: Out, b: IMat4Like) { + public static multiplyMat4 (out: Out, a: Readonly, b: IMat4Like) { const a00 = a.m00; const a01 = a.m01; const a02 = a.m02; const a10 = a.m03; const a11 = a.m04; const a12 = a.m05; const a20 = a.m06; const a21 = a.m07; const a22 = a.m08; @@ -243,7 +243,7 @@ export class Mat3 extends ValueType { * @en Multiply a matrix with a translation vector given by a translation offset. * @zh 在给定矩阵变换基础上加入变换 */ - public static transform (out: Out, a: Out, v: VecLike) { + public static transform (out: Out, a: Readonly, v: Readonly) { const a00 = a.m00; const a01 = a.m01; const a02 = a.m02; const a10 = a.m03; const a11 = a.m04; const a12 = a.m05; const a20 = a.m06; const a21 = a.m07; const a22 = a.m08; @@ -267,7 +267,7 @@ export class Mat3 extends ValueType { * @en Multiply a matrix with a scale matrix given by a scale vector and save the results to out matrix * @zh 在给定矩阵变换基础上加入新缩放变换 */ - public static scale (out: Out, a: Out, v: VecLike) { + public static scale (out: Out, a: Readonly, v: Readonly) { const x = v.x; const y = v.y; out.m00 = x * a.m00; @@ -289,7 +289,7 @@ export class Mat3 extends ValueType { * @zh 在给定矩阵变换基础上加入新旋转变换 * @param rad radius of rotation */ - public static rotate (out: Out, a: Out, rad: number) { + public static rotate (out: Out, a: Readonly, rad: number) { const a00 = a.m00; const a01 = a.m01; const a02 = a.m02; const a10 = a.m03; const a11 = a.m04; const a12 = a.m05; const a20 = a.m06; const a21 = a.m07; const a22 = a.m08; @@ -334,14 +334,13 @@ export class Mat3 extends ValueType { * @param view The view direction, it`s must be normalized. * @param up The view up direction, it`s must be normalized, default value is (0, 1, 0). */ - public static fromViewUp (out: Out, view: VecLike, up?: Vec3) { + public static fromViewUp (out: Out, view: Readonly, up?: Readonly) { if (Vec3.lengthSqr(view) < EPSILON * EPSILON) { Mat3.identity(out); return out; } - up = up || Vec3.UNIT_Y; - Vec3.normalize(v3_1, Vec3.cross(v3_1, up, view)); + Vec3.normalize(v3_1, Vec3.cross(v3_1, up || Vec3.UNIT_Y, view)); if (Vec3.lengthSqr(v3_1) < EPSILON * EPSILON) { Mat3.identity(out); @@ -363,7 +362,7 @@ export class Mat3 extends ValueType { * @en Sets the given matrix with a translation vector and save the results to out matrix * @zh 计算位移矩阵 */ - public static fromTranslation (out: Out, v: VecLike) { + public static fromTranslation (out: Out, v: Readonly) { out.m00 = 1; out.m01 = 0; out.m02 = 0; @@ -380,7 +379,7 @@ export class Mat3 extends ValueType { * @en Sets the given matrix with a scale vector and save the results to out matrix * @zh 计算缩放矩阵 */ - public static fromScaling (out: Out, v: VecLike) { + public static fromScaling (out: Out, v: Readonly) { out.m00 = v.x; out.m01 = 0; out.m02 = 0; @@ -537,7 +536,7 @@ export class Mat3 extends ValueType { * @en Adds two matrices and save the results to out matrix * @zh 逐元素矩阵加法 */ - public static add (out: Out, a: Out, b: Out) { + public static add (out: Out, a: Readonly, b: Readonly) { out.m00 = a.m00 + b.m00; out.m01 = a.m01 + b.m01; out.m02 = a.m02 + b.m02; @@ -554,7 +553,7 @@ export class Mat3 extends ValueType { * @en Subtracts matrix b from matrix a and save the results to out matrix * @zh 逐元素矩阵减法 */ - public static subtract (out: Out, a: Out, b: Out) { + public static subtract (out: Out, a: Readonly, b: Readonly) { out.m00 = a.m00 - b.m00; out.m01 = a.m01 - b.m01; out.m02 = a.m02 - b.m02; @@ -571,7 +570,7 @@ export class Mat3 extends ValueType { * @en Multiply each element of a matrix by a scalar number and save the results to out matrix * @zh 矩阵标量乘法 */ - public static multiplyScalar (out: Out, a: Out, b: number) { + public static multiplyScalar (out: Out, a: Readonly, b: number) { out.m00 = a.m00 * b; out.m01 = a.m01 * b; out.m02 = a.m02 * b; @@ -588,7 +587,7 @@ export class Mat3 extends ValueType { * @en Adds two matrices after multiplying each element of the second operand by a scalar number. And save the results to out matrix. * @zh 逐元素矩阵标量乘加: A + B * scale */ - public static multiplyScalarAndAdd (out: Out, a: Out, b: Out, scale: number) { + public static multiplyScalarAndAdd (out: Out, a: Readonly, b: Readonly, scale: number) { out.m00 = b.m00 * scale + a.m00; out.m01 = b.m01 * scale + a.m01; out.m02 = b.m02 * scale + a.m02; @@ -605,7 +604,7 @@ export class Mat3 extends ValueType { * @en Returns whether the specified matrices are equal. * @zh 矩阵等价判断 */ - public static strictEquals (a: Out, b: Out) { + public static strictEquals (a: Readonly, b: Readonly) { return a.m00 === b.m00 && a.m01 === b.m01 && a.m02 === b.m02 && a.m03 === b.m03 && a.m04 === b.m04 && a.m05 === b.m05 && a.m06 === b.m06 && a.m07 === b.m07 && a.m08 === b.m08; @@ -615,7 +614,7 @@ export class Mat3 extends ValueType { * @en Returns whether the specified matrices are approximately equal. * @zh 排除浮点数误差的矩阵近似等价判断 */ - public static equals (a: Out, b: Out, epsilon = EPSILON) { + public static equals (a: Readonly, b: Readonly, epsilon = EPSILON) { return ( Math.abs(a.m00 - b.m00) <= epsilon * Math.max(1.0, Math.abs(a.m00), Math.abs(b.m00)) && Math.abs(a.m01 - b.m01) <= epsilon * Math.max(1.0, Math.abs(a.m01), Math.abs(b.m01)) @@ -633,57 +632,102 @@ export class Mat3 extends ValueType { * @en Value at column 0 row 0 of the matrix. * @zh 矩阵第 0 列第 0 行的元素。 */ - public declare m00: number; + public get m00 (): number { + return this._array[0]; + } + public set m00 (m: number) { + this._array[0] = m; + } /** * @en Value at column 0 row 1 of the matrix. * @zh 矩阵第 0 列第 1 行的元素。 */ - public declare m01: number; + public get m01 (): number { + return this._array[1]; + } + public set m01 (m: number) { + this._array[1] = m; + } /** * @en Value at column 0 row 2 of the matrix. * @zh 矩阵第 0 列第 2 行的元素。 */ - public declare m02: number; + public get m02 (): number { + return this._array[2]; + } + public set m02 (m: number) { + this._array[2] = m; + } /** * @en Value at column 1 row 0 of the matrix. * @zh 矩阵第 1 列第 0 行的元素。 */ - public declare m03: number; + public get m03 (): number { + return this._array[3]; + } + public set m03 (m: number) { + this._array[3] = m; + } /** * @en Value at column 1 row 1 of the matrix. * @zh 矩阵第 1 列第 1 行的元素。 */ - public declare m04: number; + public get m04 (): number { + return this._array[4]; + } + public set m04 (m: number) { + this._array[4] = m; + } /** * @en Value at column 1 row 2 of the matrix. * @zh 矩阵第 1 列第 2 行的元素。 */ - public declare m05: number; + public get m05 (): number { + return this._array[5]; + } + public set m05 (m: number) { + this._array[5] = m; + } /** * @en Value at column 2 row 0 of the matrix. * @zh 矩阵第 2 列第 0 行的元素。 */ - public declare m06: number; + public get m06 (): number { + return this._array[6]; + } + public set m06 (m: number) { + this._array[6] = m; + } /** * @en Value at column 2 row 1 of the matrix. * @zh 矩阵第 2 列第 1 行的元素。 */ - public declare m07: number; + public get m07 (): number { + return this._array[7]; + } + public set m07 (m: number) { + this._array[7] = m; + } /** * @en Value at column 2 row 2 of the matrix. * @zh 矩阵第 2 列第 2 行的元素。 */ - public declare m08: number; + public get m08 (): number { + return this._array[8]; + } + public set m08 (m: number) { + this._array[8] = m; + } - constructor (other: Mat3); + constructor (m00: Mat3 | FloatArray); constructor ( m00?: number, m01?: number, m02?: number, @@ -691,19 +735,27 @@ export class Mat3 extends ValueType { m06?: number, m07?: number, m08?: number); constructor ( - m00: number | Mat3 = 1, m01 = 0, m02 = 0, + m00: number | Mat3 | FloatArray = 1, m01 = 0, m02 = 0, m03 = 0, m04 = 1, m05 = 0, m06 = 0, m07 = 0, m08 = 1, ) { super(); - if (typeof m00 === 'object') { - this.m00 = m00.m00; this.m01 = m00.m01; this.m02 = m00.m02; - this.m03 = m00.m03; this.m04 = m00.m04; this.m05 = m00.m05; - this.m06 = m00.m06; this.m07 = m00.m07; this.m08 = m00.m08; + if (m00 && typeof m00 === 'object') { + if (ArrayBuffer.isView(m00)) { + this._array = m00; + this._array.set([1, 0, 0, 0, 1, 0, 0, 0, 1]); + } else { + const v = m00.array; + this._array = MathBase.createFloatArray(9); + this._array[0] = v[0]; this._array[1] = v[1]; this._array[2] = v[2]; + this._array[3] = v[3]; this._array[4] = v[4]; this._array[5] = v[5]; + this._array[6] = v[6]; this._array[7] = v[7]; this._array[8] = v[8]; + } } else { - this.m00 = m00; this.m01 = m01; this.m02 = m02; - this.m03 = m03; this.m04 = m04; this.m05 = m05; - this.m06 = m06; this.m07 = m07; this.m08 = m08; + this._array = MathBase.createFloatArray(9); + this._array[0] = m00; this._array[1] = m01; this._array[2] = m02; + this._array[3] = m03; this._array[4] = m04; this._array[5] = m05; + this._array[6] = m06; this._array[7] = m07; this._array[8] = m08; } } @@ -712,11 +764,11 @@ export class Mat3 extends ValueType { * @zh 克隆当前矩阵。 */ public clone () { - const t = this; + const m = this._array; return new Mat3( - t.m00, t.m01, t.m02, - t.m03, t.m04, t.m05, - t.m06, t.m07, t.m08, + m[0], m[1], m[2], + m[3], m[4], m[5], + m[6], m[7], m[8], ); } @@ -726,7 +778,7 @@ export class Mat3 extends ValueType { * @param other Specified matrix * @return this */ - public set (other: Mat3); + public set (other: Readonly); /** * @en Set the matrix with values of all elements @@ -736,18 +788,18 @@ export class Mat3 extends ValueType { public set (m00?: number, m01?: number, m02?: number, m03?: number, m04?: number, m05?: number, m06?: number, m07?: number, m08?: number); - - public set (m00: number | Mat3 = 1, m01 = 0, m02 = 0, + public set (m00: number | Readonly = 1, m01 = 0, m02 = 0, m03 = 0, m04 = 1, m05 = 0, m06 = 0, m07 = 0, m08 = 1) { - if (typeof m00 === 'object') { - this.m00 = m00.m00; this.m01 = m00.m01; this.m02 = m00.m02; - this.m03 = m00.m03; this.m04 = m00.m04; this.m05 = m00.m05; - this.m06 = m00.m06; this.m07 = m00.m07; this.m08 = m00.m08; + if (m00 && typeof m00 === 'object') { + const v = m00.array; + this._array[0] = v[0]; this._array[1] = v[1]; this._array[2] = v[2]; + this._array[3] = v[3]; this._array[4] = v[4]; this._array[5] = v[5]; + this._array[6] = v[6]; this._array[7] = v[7]; this._array[8] = v[8]; } else { - this.m00 = m00; this.m01 = m01; this.m02 = m02; - this.m03 = m03; this.m04 = m04; this.m05 = m05; - this.m06 = m06; this.m07 = m07; this.m08 = m08; + this._array[0] = m00; this._array[1] = m01; this._array[2] = m02; + this._array[3] = m03; this._array[4] = m04; this._array[5] = m05; + this._array[6] = m06; this._array[7] = m07; this._array[8] = m08; } return this; } @@ -759,17 +811,18 @@ export class Mat3 extends ValueType { * @param epsilon The error allowed. It`s should be a non-negative number. * @return Returns `true' when the elements of both matrices are equal; otherwise returns `false'. */ - public equals (other: Mat3, epsilon = EPSILON): boolean { + public equals (other: Readonly, epsilon = EPSILON): boolean { + const v = other.array; return ( - Math.abs(this.m00 - other.m00) <= epsilon * Math.max(1.0, Math.abs(this.m00), Math.abs(other.m00)) - && Math.abs(this.m01 - other.m01) <= epsilon * Math.max(1.0, Math.abs(this.m01), Math.abs(other.m01)) - && Math.abs(this.m02 - other.m02) <= epsilon * Math.max(1.0, Math.abs(this.m02), Math.abs(other.m02)) - && Math.abs(this.m03 - other.m03) <= epsilon * Math.max(1.0, Math.abs(this.m03), Math.abs(other.m03)) - && Math.abs(this.m04 - other.m04) <= epsilon * Math.max(1.0, Math.abs(this.m04), Math.abs(other.m04)) - && Math.abs(this.m05 - other.m05) <= epsilon * Math.max(1.0, Math.abs(this.m05), Math.abs(other.m05)) - && Math.abs(this.m06 - other.m06) <= epsilon * Math.max(1.0, Math.abs(this.m06), Math.abs(other.m06)) - && Math.abs(this.m07 - other.m07) <= epsilon * Math.max(1.0, Math.abs(this.m07), Math.abs(other.m07)) - && Math.abs(this.m08 - other.m08) <= epsilon * Math.max(1.0, Math.abs(this.m08), Math.abs(other.m08)) + Math.abs(this._array[0] - v[0]) <= epsilon * Math.max(1.0, Math.abs(this._array[0]), Math.abs(v[0])) + && Math.abs(this._array[1] - v[1]) <= epsilon * Math.max(1.0, Math.abs(this._array[1]), Math.abs(v[1])) + && Math.abs(this._array[2] - v[2]) <= epsilon * Math.max(1.0, Math.abs(this._array[2]), Math.abs(v[2])) + && Math.abs(this._array[3] - v[3]) <= epsilon * Math.max(1.0, Math.abs(this._array[3]), Math.abs(v[3])) + && Math.abs(this._array[4] - v[4]) <= epsilon * Math.max(1.0, Math.abs(this._array[4]), Math.abs(v[4])) + && Math.abs(this._array[5] - v[5]) <= epsilon * Math.max(1.0, Math.abs(this._array[5]), Math.abs(v[5])) + && Math.abs(this._array[6] - v[6]) <= epsilon * Math.max(1.0, Math.abs(this._array[6]), Math.abs(v[6])) + && Math.abs(this._array[7] - v[7]) <= epsilon * Math.max(1.0, Math.abs(this._array[7]), Math.abs(v[7])) + && Math.abs(this._array[8] - v[8]) <= epsilon * Math.max(1.0, Math.abs(this._array[8]), Math.abs(v[8])) ); } @@ -779,10 +832,11 @@ export class Mat3 extends ValueType { * @param other Comparative matrix * @return Returns `true' when the elements of both matrices are equal; otherwise returns `false'. */ - public strictEquals (other: Mat3): boolean { - return this.m00 === other.m00 && this.m01 === other.m01 && this.m02 === other.m02 - && this.m03 === other.m03 && this.m04 === other.m04 && this.m05 === other.m05 - && this.m06 === other.m06 && this.m07 === other.m07 && this.m08 === other.m08; + public strictEquals (other: Readonly): boolean { + const v = other.array; + return this._array[0] === v[0] && this._array[1] === v[1] && this._array[2] === v[2] + && this._array[3] === v[3] && this._array[4] === v[4] && this._array[5] === v[5] + && this._array[6] === v[6] && this._array[7] === v[7] && this._array[8] === v[8]; } /** @@ -791,11 +845,10 @@ export class Mat3 extends ValueType { * @return The string representation of this matrix */ public toString () { - const t = this; return `[\n${ - t.m00}, ${t.m01}, ${t.m02},\n${ - t.m03},\n${t.m04}, ${t.m05},\n${ - t.m06}, ${t.m07},\n${t.m08}\n` + this._array[0]}, ${this._array[1]}, ${this._array[2]},\n${ + this._array[3]},\n${this._array[4]}, ${this._array[5]},\n${ + this._array[6]}, ${this._array[7]},\n${this._array[8]}\n` + `]`; } @@ -805,15 +858,15 @@ export class Mat3 extends ValueType { * @return `this` */ public identity () { - this.m00 = 1; - this.m01 = 0; - this.m02 = 0; - this.m03 = 0; - this.m04 = 1; - this.m05 = 0; - this.m06 = 0; - this.m07 = 0; - this.m08 = 1; + this._array[0] = 1; + this._array[1] = 0; + this._array[2] = 0; + this._array[3] = 0; + this._array[4] = 1; + this._array[5] = 0; + this._array[6] = 0; + this._array[7] = 0; + this._array[8] = 1; return this; } @@ -822,13 +875,13 @@ export class Mat3 extends ValueType { * @zh 计算当前矩阵的转置矩阵。 */ public transpose () { - const a01 = this.m01; const a02 = this.m02; const a12 = this.m05; - this.m01 = this.m03; - this.m02 = this.m06; - this.m03 = a01; - this.m05 = this.m07; - this.m06 = a02; - this.m07 = a12; + const a01 = this._array[1]; const a02 = this._array[2]; const a12 = this._array[5]; + this._array[1] = this._array[3]; + this._array[2] = this._array[6]; + this._array[3] = a01; + this._array[5] = this._array[7]; + this._array[6] = a02; + this._array[7] = a12; return this; } @@ -837,9 +890,9 @@ export class Mat3 extends ValueType { * @zh 计算当前矩阵的逆矩阵。注意,在矩阵不可逆时,会返回一个全为 0 的矩阵。 */ public invert () { - const a00 = this.m00; const a01 = this.m01; const a02 = this.m02; - const a10 = this.m03; const a11 = this.m04; const a12 = this.m05; - const a20 = this.m06; const a21 = this.m07; const a22 = this.m08; + const a00 = this._array[0]; const a01 = this._array[1]; const a02 = this._array[2]; + const a10 = this._array[3]; const a11 = this._array[4]; const a12 = this._array[5]; + const a20 = this._array[6]; const a21 = this._array[7]; const a22 = this._array[8]; const b01 = a22 * a11 - a12 * a21; const b11 = -a22 * a10 + a12 * a20; @@ -854,15 +907,15 @@ export class Mat3 extends ValueType { } det = 1.0 / det; - this.m00 = b01 * det; - this.m01 = (-a22 * a01 + a02 * a21) * det; - this.m02 = (a12 * a01 - a02 * a11) * det; - this.m03 = b11 * det; - this.m04 = (a22 * a00 - a02 * a20) * det; - this.m05 = (-a12 * a00 + a02 * a10) * det; - this.m06 = b21 * det; - this.m07 = (-a21 * a00 + a01 * a20) * det; - this.m08 = (a11 * a00 - a01 * a10) * det; + this._array[0] = b01 * det; + this._array[1] = (-a22 * a01 + a02 * a21) * det; + this._array[2] = (a12 * a01 - a02 * a11) * det; + this._array[3] = b11 * det; + this._array[4] = (a22 * a00 - a02 * a20) * det; + this._array[5] = (-a12 * a00 + a02 * a10) * det; + this._array[6] = b21 * det; + this._array[7] = (-a21 * a00 + a01 * a20) * det; + this._array[8] = (a11 * a00 - a01 * a10) * det; return this; } @@ -872,9 +925,9 @@ export class Mat3 extends ValueType { * @return 当前矩阵的行列式。 */ public determinant (): number { - const a00 = this.m00; const a01 = this.m01; const a02 = this.m02; - const a10 = this.m03; const a11 = this.m04; const a12 = this.m05; - const a20 = this.m06; const a21 = this.m07; const a22 = this.m08; + const a00 = this._array[0]; const a01 = this._array[1]; const a02 = this._array[2]; + const a10 = this._array[3]; const a11 = this._array[4]; const a12 = this._array[5]; + const a20 = this._array[6]; const a21 = this._array[7]; const a22 = this._array[8]; return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20); } @@ -885,15 +938,16 @@ export class Mat3 extends ValueType { * @param mat the second operand */ public add (mat: Mat3) { - this.m00 += mat.m00; - this.m01 += mat.m01; - this.m02 += mat.m02; - this.m03 += mat.m03; - this.m04 += mat.m04; - this.m05 += mat.m05; - this.m06 += mat.m06; - this.m07 += mat.m07; - this.m08 += mat.m08; + const v = mat.array; + this._array[0] += v[0]; + this._array[1] += v[1]; + this._array[2] += v[2]; + this._array[3] += v[3]; + this._array[4] += v[4]; + this._array[5] += v[5]; + this._array[6] += v[6]; + this._array[7] += v[7]; + this._array[8] += v[8]; return this; } @@ -903,15 +957,16 @@ export class Mat3 extends ValueType { * @param mat the second operand */ public subtract (mat: Mat3) { - this.m00 -= mat.m00; - this.m01 -= mat.m01; - this.m02 -= mat.m02; - this.m03 -= mat.m03; - this.m04 -= mat.m04; - this.m05 -= mat.m05; - this.m06 -= mat.m06; - this.m07 -= mat.m07; - this.m08 -= mat.m08; + const v = mat.array; + this._array[0] -= v[0]; + this._array[1] -= v[1]; + this._array[2] -= v[2]; + this._array[3] -= v[3]; + this._array[4] -= v[4]; + this._array[5] -= v[5]; + this._array[6] -= v[6]; + this._array[7] -= v[7]; + this._array[8] -= v[8]; return this; } @@ -921,25 +976,26 @@ export class Mat3 extends ValueType { * @param mat the second operand */ public multiply (mat: Mat3) { - const a00 = this.m00; const a01 = this.m01; const a02 = this.m02; - const a10 = this.m03; const a11 = this.m04; const a12 = this.m05; - const a20 = this.m06; const a21 = this.m07; const a22 = this.m08; - - const b00 = mat.m00; const b01 = mat.m01; const b02 = mat.m02; - const b10 = mat.m03; const b11 = mat.m04; const b12 = mat.m05; - const b20 = mat.m06; const b21 = mat.m07; const b22 = mat.m08; - - this.m00 = b00 * a00 + b01 * a10 + b02 * a20; - this.m01 = b00 * a01 + b01 * a11 + b02 * a21; - this.m02 = b00 * a02 + b01 * a12 + b02 * a22; - - this.m03 = b10 * a00 + b11 * a10 + b12 * a20; - this.m04 = b10 * a01 + b11 * a11 + b12 * a21; - this.m05 = b10 * a02 + b11 * a12 + b12 * a22; - - this.m06 = b20 * a00 + b21 * a10 + b22 * a20; - this.m07 = b20 * a01 + b21 * a11 + b22 * a21; - this.m08 = b20 * a02 + b21 * a12 + b22 * a22; + const a00 = this._array[0]; const a01 = this._array[1]; const a02 = this._array[2]; + const a10 = this._array[3]; const a11 = this._array[4]; const a12 = this._array[5]; + const a20 = this._array[6]; const a21 = this._array[7]; const a22 = this._array[8]; + + const v = mat.array; + const b00 = v[0]; const b01 = v[1]; const b02 = v[2]; + const b10 = v[3]; const b11 = v[4]; const b12 = v[5]; + const b20 = v[6]; const b21 = v[7]; const b22 = v[8]; + + this._array[0] = b00 * a00 + b01 * a10 + b02 * a20; + this._array[1] = b00 * a01 + b01 * a11 + b02 * a21; + this._array[2] = b00 * a02 + b01 * a12 + b02 * a22; + + this._array[3] = b10 * a00 + b11 * a10 + b12 * a20; + this._array[4] = b10 * a01 + b11 * a11 + b12 * a21; + this._array[5] = b10 * a02 + b11 * a12 + b12 * a22; + + this._array[6] = b20 * a00 + b21 * a10 + b22 * a20; + this._array[7] = b20 * a01 + b21 * a11 + b22 * a21; + this._array[8] = b20 * a02 + b21 * a12 + b22 * a22; return this; } @@ -949,15 +1005,15 @@ export class Mat3 extends ValueType { * @param scalar amount to scale the matrix's elements by */ public multiplyScalar (scalar: number) { - this.m00 *= scalar; - this.m01 *= scalar; - this.m02 *= scalar; - this.m03 *= scalar; - this.m04 *= scalar; - this.m05 *= scalar; - this.m06 *= scalar; - this.m07 *= scalar; - this.m08 *= scalar; + this._array[0] *= scalar; + this._array[1] *= scalar; + this._array[2] *= scalar; + this._array[3] *= scalar; + this._array[4] *= scalar; + this._array[5] *= scalar; + this._array[6] *= scalar; + this._array[7] *= scalar; + this._array[8] *= scalar; return this; } @@ -967,19 +1023,14 @@ export class Mat3 extends ValueType { * @param vec vector to scale by */ public scale (vec: Vec3) { - const x = vec.x; const y = vec.y; - - this.m00 = x * this.m00; - this.m01 = x * this.m01; - this.m02 = x * this.m02; - - this.m03 = y * this.m03; - this.m04 = y * this.m04; - this.m05 = y * this.m05; - - this.m06 = this.m06; - this.m07 = this.m07; - this.m08 = this.m08; + const x = vec.array[0]; const y = vec.array[1]; + this._array[0] *= x; + this._array[1] *= x; + this._array[2] *= x; + + this._array[3] *= y; + this._array[4] *= y; + this._array[5] *= y; return this; } @@ -989,24 +1040,24 @@ export class Mat3 extends ValueType { * @param rad radius of rotation */ public rotate (rad: number) { - const a00 = this.m00; const a01 = this.m01; const a02 = this.m02; - const a10 = this.m03; const a11 = this.m04; const a12 = this.m05; - const a20 = this.m06; const a21 = this.m07; const a22 = this.m08; + const a00 = this._array[0]; const a01 = this._array[1]; const a02 = this._array[2]; + const a10 = this._array[3]; const a11 = this._array[4]; const a12 = this._array[5]; + const a20 = this._array[6]; const a21 = this._array[7]; const a22 = this._array[8]; const s = Math.sin(rad); const c = Math.cos(rad); - this.m00 = c * a00 + s * a10; - this.m01 = c * a01 + s * a11; - this.m02 = c * a02 + s * a12; + this._array[0] = c * a00 + s * a10; + this._array[1] = c * a01 + s * a11; + this._array[2] = c * a02 + s * a12; - this.m03 = c * a10 - s * a00; - this.m04 = c * a11 - s * a01; - this.m05 = c * a12 - s * a02; + this._array[3] = c * a10 - s * a00; + this._array[4] = c * a11 - s * a01; + this._array[5] = c * a12 - s * a02; - this.m06 = a20; - this.m07 = a21; - this.m08 = a22; + this._array[6] = a20; + this._array[7] = a21; + this._array[8] = a22; return this; } @@ -1032,17 +1083,17 @@ export class Mat3 extends ValueType { const wy = w * y2; const wz = w * z2; - this.m00 = 1 - yy - zz; - this.m03 = yx - wz; - this.m06 = zx + wy; + this._array[0] = 1 - yy - zz; + this._array[3] = yx - wz; + this._array[6] = zx + wy; - this.m01 = yx + wz; - this.m04 = 1 - xx - zz; - this.m07 = zy - wx; + this._array[1] = yx + wz; + this._array[4] = 1 - xx - zz; + this._array[7] = zy - wx; - this.m02 = zx - wy; - this.m05 = zy + wx; - this.m08 = 1 - xx - yy; + this._array[2] = zx - wy; + this._array[5] = zy + wx; + this._array[8] = 1 - xx - yy; return this; } } diff --git a/cocos/core/math/mat4.ts b/cocos/core/math/mat4.ts index 5daf57fb61e..1c26b949e5b 100644 --- a/cocos/core/math/mat4.ts +++ b/cocos/core/math/mat4.ts @@ -29,13 +29,13 @@ */ import { CCClass } from '../data/class'; -import { ValueType } from '../value-types/value-type'; import { Mat3 } from './mat3'; import { Quat } from './quat'; -import { IMat4Like, IVec3Like } from './type-define'; +import { IMat4Like, IVec3Like, FloatArray } from './type-define'; import { EPSILON } from './utils'; import { Vec3 } from './vec3'; import { legacyCC } from '../global-exports'; +import { MathBase } from './math-base'; export const preTransforms = Object.freeze([ Object.freeze([1, 0, 0, 1]), // SurfaceTransform.IDENTITY @@ -49,14 +49,14 @@ export const preTransforms = Object.freeze([ * @zh 表示四维(4x4)矩阵。 */ -export class Mat4 extends ValueType { +export class Mat4 extends MathBase { public static IDENTITY = Object.freeze(new Mat4()); /** * @en Clone a matrix and save the results to out matrix * @zh 获得指定矩阵的拷贝 */ - public static clone (a: Out) { + public static clone (a: Readonly) { return new Mat4( a.m00, a.m01, a.m02, a.m03, a.m04, a.m05, a.m06, a.m07, @@ -69,7 +69,7 @@ export class Mat4 extends ValueType { * @en Copy a matrix into the out matrix * @zh 复制目标矩阵 */ - public static copy (out: Out, a: Out) { + public static copy (out: Out, a: Readonly) { out.m00 = a.m00; out.m01 = a.m01; out.m02 = a.m02; @@ -135,7 +135,7 @@ export class Mat4 extends ValueType { * @en Transposes a matrix and save the results to out matrix * @zh 转置矩阵 */ - public static transpose (out: Out, a: Out) { + public static transpose (out: Out, a: Readonly) { // If we are transposing ourselves we can skip a few steps but have to cache some values if (out === a) { const a01 = a.m01; const a02 = a.m02; const a03 = a.m03; const a12 = a.m06; const a13 = a.m07; const a23 = a.m11; @@ -176,7 +176,7 @@ export class Mat4 extends ValueType { * @en Inverts a matrix. When matrix is not invertible the matrix will be set to zeros. * @zh 矩阵求逆,注意,在矩阵不可逆时,会返回一个全为 0 的矩阵。 */ - public static invert (out: Out, a: Out) { + public static invert (out: Out, a: Readonly) { const a00 = a.m00; const a01 = a.m01; const a02 = a.m02; const a03 = a.m03; const a10 = a.m04; const a11 = a.m05; const a12 = a.m06; const a13 = a.m07; const a20 = a.m08; const a21 = a.m09; const a22 = a.m10; const a23 = a.m11; @@ -231,7 +231,7 @@ export class Mat4 extends ValueType { * @en Calculates the determinant of a matrix * @zh 矩阵行列式 */ - public static determinant (a: Out): number { + public static determinant (a: Readonly): number { const a00 = a.m00; const a01 = a.m01; const a02 = a.m02; const a03 = a.m03; const a10 = a.m04; const a11 = a.m05; const a12 = a.m06; const a13 = a.m07; const a20 = a.m08; const a21 = a.m09; const a22 = a.m10; const a23 = a.m11; @@ -258,7 +258,7 @@ export class Mat4 extends ValueType { * @en Multiply two matrices and save the results to out matrix * @zh 矩阵乘法 */ - public static multiply (out: Out, a: Out, b: Out) { + public static multiply (out: Out, a: Readonly, b: Readonly) { const a00 = a.m00; const a01 = a.m01; const a02 = a.m02; const a03 = a.m03; const a10 = a.m04; const a11 = a.m05; const a12 = a.m06; const a13 = a.m07; const a20 = a.m08; const a21 = a.m09; const a22 = a.m10; const a23 = a.m11; @@ -295,7 +295,7 @@ export class Mat4 extends ValueType { * @en Transform a matrix with the given vector and save results to the out matrix * @zh 在给定矩阵变换基础上加入变换 */ - public static transform (out: Out, a: Out, v: VecLike) { + public static transform (out: Out, a: Readonly, v: Readonly) { const x = v.x; const y = v.y; const z = v.z; if (a === out) { out.m12 = a.m00 * x + a.m04 * y + a.m08 * z + a.m12; @@ -324,7 +324,7 @@ export class Mat4 extends ValueType { * @en Transform a matrix with the given translation vector and save results to the out matrix * @zh 在给定矩阵变换基础上加入新位移变换 */ - public static translate (out: Out, a: Out, v: VecLike) { + public static translate (out: Out, a: Readonly, v: Readonly) { console.warn('function changed'); if (a === out) { out.m12 += v.x; @@ -346,7 +346,7 @@ export class Mat4 extends ValueType { * @en Multiply a matrix with a scale matrix given by a scale vector and save the results into the out matrix * @zh 在给定矩阵变换基础上加入新缩放变换 */ - public static scale (out: Out, a: Out, v: VecLike) { + public static scale (out: Out, a: Readonly, v: Readonly) { const x = v.x; const y = v.y; const z = v.z; out.m00 = a.m00 * x; out.m01 = a.m01 * x; @@ -373,7 +373,7 @@ export class Mat4 extends ValueType { * @param rad Angle of rotation (in radians) * @param axis axis of rotation */ - public static rotate (out: Out, a: Out, rad: number, axis: VecLike) { + public static rotate (out: Out, a: Readonly, rad: number, axis: IVec3Like) { let x = axis.x; let y = axis.y; let z = axis.z; let len = Math.sqrt(x * x + y * y + z * z); @@ -430,7 +430,7 @@ export class Mat4 extends ValueType { * @zh 在给定矩阵变换基础上加入绕 X 轴的旋转变换 * @param rad Angle of rotation (in radians) */ - public static rotateX (out: Out, a: Out, rad: number) { + public static rotateX (out: Out, a: Readonly, rad: number) { const s = Math.sin(rad); const c = Math.cos(rad); const a10 = a.m04; @@ -471,7 +471,7 @@ export class Mat4 extends ValueType { * @zh 在给定矩阵变换基础上加入绕 Y 轴的旋转变换 * @param rad Angle of rotation (in radians) */ - public static rotateY (out: Out, a: Out, rad: number) { + public static rotateY (out: Out, a: Readonly, rad: number) { const s = Math.sin(rad); const c = Math.cos(rad); const a00 = a.m00; @@ -512,7 +512,7 @@ export class Mat4 extends ValueType { * @zh 在给定矩阵变换基础上加入绕 Z 轴的旋转变换 * @param rad Angle of rotation (in radians) */ - public static rotateZ (out: Out, a: Out, rad: number) { + public static rotateZ (out: Out, a: Readonly, rad: number) { const s = Math.sin(rad); const c = Math.cos(rad); const a00 = a.m00; @@ -553,7 +553,7 @@ export class Mat4 extends ValueType { * @en Sets the out matrix with a translation vector * @zh 计算位移矩阵 */ - public static fromTranslation (out: Out, v: VecLike) { + public static fromTranslation (out: Out, v: Readonly) { out.m00 = 1; out.m01 = 0; out.m02 = 0; @@ -577,7 +577,7 @@ export class Mat4 extends ValueType { * @en Sets the out matrix with a scale vector * @zh 计算缩放矩阵 */ - public static fromScaling (out: Out, v: VecLike) { + public static fromScaling (out: Out, v: Readonly) { out.m00 = v.x; out.m01 = 0; out.m02 = 0; @@ -601,7 +601,7 @@ export class Mat4 extends ValueType { * @en Sets the out matrix with rotation angle * @zh 计算旋转矩阵 */ - public static fromRotation (out: Out, rad: number, axis: VecLike) { + public static fromRotation (out: Out, rad: number, axis: IVec3Like) { let x = axis.x; let y = axis.y; let z = axis.z; let len = Math.sqrt(x * x + y * y + z * z); @@ -723,7 +723,7 @@ export class Mat4 extends ValueType { * @en Calculates the transform representing the combination of a rotation and a translation * @zh 根据旋转和位移信息计算矩阵 */ - public static fromRT (out: Out, q: Quat, v: VecLike) { + public static fromRT (out: Out, q: Quat, v: Readonly) { const x = q.x; const y = q.y; const z = q.z; const w = q.w; const x2 = x + x; const y2 = y + y; @@ -763,7 +763,7 @@ export class Mat4 extends ValueType { * @en Extracts the translation from the matrix, assuming it's composed in order of scale, rotation, translation * @zh 提取矩阵的位移信息, 默认矩阵中的变换以 S->R->T 的顺序应用 */ - public static getTranslation (out: VecLike, mat: Out) { + public static getTranslation (out: IVec3Like, mat: Out) { out.x = mat.m12; out.y = mat.m13; out.z = mat.m14; @@ -775,7 +775,7 @@ export class Mat4 extends ValueType { * @en Extracts the scale vector from the matrix, assuming it's composed in order of scale, rotation, translation * @zh 提取矩阵的缩放信息, 默认矩阵中的变换以 S->R->T 的顺序应用 */ - public static getScaling (out: VecLike, mat: Out) { + public static getScaling (out: IVec3Like, mat: Out) { const m00 = m3_1.m00 = mat.m00; const m01 = m3_1.m01 = mat.m01; const m02 = m3_1.m02 = mat.m02; @@ -834,7 +834,7 @@ export class Mat4 extends ValueType { * @en Extracts the scale, rotation and translation from the matrix, assuming it's composed in order of scale, rotation, translation * @zh 提取旋转、位移、缩放信息, 默认矩阵中的变换以 S->R->T 的顺序应用 */ - public static toRTS (m: Out, q: Quat, v: VecLike, s: VecLike) { + public static toRTS (m: Out, q: Quat, v: Readonly, s: IVec3Like) { s.x = Vec3.set(v3_1, m.m00, m.m01, m.m02).length(); m3_1.m00 = m.m00 / s.x; m3_1.m01 = m.m01 / s.x; @@ -857,7 +857,7 @@ export class Mat4 extends ValueType { * @en Compose a matrix from scale, rotation and translation, applied in order. * @zh 根据旋转、位移、缩放信息计算矩阵,以 S->R->T 的顺序应用 */ - public static fromRTS (out: Out, q: Quat, v: VecLike, s: VecLike) { + public static fromRTS (out: Out, q: Readonly, v: Readonly, s: Readonly) { const x = q.x; const y = q.y; const z = q.z; const w = q.w; const x2 = x + x; const y2 = y + y; @@ -904,7 +904,7 @@ export class Mat4 extends ValueType { * @param s Scaling vector * @param o transformation Center */ - public static fromRTSOrigin (out: Out, q: Quat, v: VecLike, s: VecLike, o: VecLike) { + public static fromRTSOrigin (out: Out, q: Quat, v: Readonly, s: Readonly, o: Readonly) { const x = q.x; const y = q.y; const z = q.z; const w = q.w; const x2 = x + x; const y2 = y + y; @@ -1116,7 +1116,7 @@ export class Mat4 extends ValueType { * @param center The target point. * @param up The vector describing the up direction. */ - public static lookAt (out: Out, eye: VecLike, center: VecLike, up: VecLike) { + public static lookAt (out: Out, eye: IVec3Like, center: IVec3Like, up: IVec3Like) { const eyex = eye.x; const eyey = eye.y; const eyez = eye.z; @@ -1172,7 +1172,7 @@ export class Mat4 extends ValueType { * @en Calculates the inverse transpose of a matrix and save the results to out matrix * @zh 计算逆转置矩阵 */ - public static inverseTranspose (out: Out, a: Out) { + public static inverseTranspose (out: Out, a: Readonly) { const a00 = a.m00; const a01 = a.m01; const a02 = a.m02; const a03 = a.m03; const a10 = a.m04; const a11 = a.m05; const a12 = a.m06; const a13 = a.m07; const a20 = a.m08; const a21 = a.m09; const a22 = a.m10; const a23 = a.m11; @@ -1276,7 +1276,7 @@ export class Mat4 extends ValueType { * @en Adds two matrices and save the results to out matrix * @zh 逐元素矩阵加法 */ - public static add (out: Out, a: Out, b: Out) { + public static add (out: Out, a: Readonly, b: Readonly) { out.m00 = a.m00 + b.m00; out.m01 = a.m01 + b.m01; out.m02 = a.m02 + b.m02; @@ -1300,7 +1300,7 @@ export class Mat4 extends ValueType { * @en Subtracts matrix b from matrix a and save the results to out matrix * @zh 逐元素矩阵减法 */ - public static subtract (out: Out, a: Out, b: Out) { + public static subtract (out: Out, a: Readonly, b: Readonly) { out.m00 = a.m00 - b.m00; out.m01 = a.m01 - b.m01; out.m02 = a.m02 - b.m02; @@ -1324,7 +1324,7 @@ export class Mat4 extends ValueType { * @en Multiply each element of a matrix by a scalar number and save the results to out matrix * @zh 矩阵标量乘法 */ - public static multiplyScalar (out: Out, a: Out, b: number) { + public static multiplyScalar (out: Out, a: Readonly, b: number) { out.m00 = a.m00 * b; out.m01 = a.m01 * b; out.m02 = a.m02 * b; @@ -1348,7 +1348,7 @@ export class Mat4 extends ValueType { * @en Adds two matrices after multiplying each element of the second operand by a scalar number. And save the results to out matrix. * @zh 逐元素矩阵标量乘加: A + B * scale */ - public static multiplyScalarAndAdd (out: Out, a: Out, b: Out, scale: number) { + public static multiplyScalarAndAdd (out: Out, a: Readonly, b: Readonly, scale: number) { out.m00 = a.m00 + (b.m00 * scale); out.m01 = a.m01 + (b.m01 * scale); out.m02 = a.m02 + (b.m02 * scale); @@ -1372,7 +1372,7 @@ export class Mat4 extends ValueType { * @en Returns whether the specified matrices are equal. * @zh 矩阵等价判断 */ - public static strictEquals (a: Out, b: Out) { + public static strictEquals (a: Readonly, b: Readonly) { return a.m00 === b.m00 && a.m01 === b.m01 && a.m02 === b.m02 && a.m03 === b.m03 && a.m04 === b.m04 && a.m05 === b.m05 && a.m06 === b.m06 && a.m07 === b.m07 && a.m08 === b.m08 && a.m09 === b.m09 && a.m10 === b.m10 && a.m11 === b.m11 @@ -1383,7 +1383,7 @@ export class Mat4 extends ValueType { * @en Returns whether the specified matrices are approximately equal. * @zh 排除浮点数误差的矩阵近似等价判断 */ - public static equals (a: Out, b: Out, epsilon = EPSILON) { + public static equals (a: Readonly, b: Readonly, epsilon = EPSILON) { // TAOCP vol.2, 3rd ed., s.4.2.4, p.213-225 // defines a 'close enough' relationship between u and v that scales for magnitude return ( @@ -1410,99 +1410,179 @@ export class Mat4 extends ValueType { * @en Value at column 0 row 0 of the matrix. * @zh 矩阵第 0 列第 0 行的元素。 */ - public m00: number; + public get m00 (): number { + return this._array[0]; + } + public set m00 (m: number) { + this._array[0] = m; + } /** * @en Value at column 0 row 1 of the matrix. * @zh 矩阵第 0 列第 1 行的元素。 */ - public m01: number; + public get m01 (): number { + return this._array[1]; + } + public set m01 (m: number) { + this._array[1] = m; + } /** * @en Value at column 0 row 2 of the matrix. * @zh 矩阵第 0 列第 2 行的元素。 */ - public m02: number; + public get m02 (): number { + return this._array[2]; + } + public set m02 (m: number) { + this._array[2] = m; + } /** * @en Value at column 0 row 3 of the matrix. * @zh 矩阵第 0 列第 3 行的元素。 */ - public m03: number; + public get m03 (): number { + return this._array[3]; + } + public set m03 (m: number) { + this._array[3] = m; + } /** * @en Value at column 1 row 0 of the matrix. * @zh 矩阵第 1 列第 0 行的元素。 */ - public m04: number; + public get m04 (): number { + return this._array[4]; + } + public set m04 (m: number) { + this._array[4] = m; + } /** * @en Value at column 1 row 1 of the matrix. * @zh 矩阵第 1 列第 1 行的元素。 */ - public m05: number; + public get m05 (): number { + return this._array[5]; + } + public set m05 (m: number) { + this._array[5] = m; + } /** * @en Value at column 1 row 2 of the matrix. * @zh 矩阵第 1 列第 2 行的元素。 */ - public m06: number; + public get m06 (): number { + return this._array[6]; + } + public set m06 (m: number) { + this._array[6] = m; + } /** * @en Value at column 1 row 3 of the matrix. * @zh 矩阵第 1 列第 3 行的元素。 */ - public m07: number; + public get m07 (): number { + return this._array[7]; + } + public set m07 (m: number) { + this._array[7] = m; + } /** * @en Value at column 2 row 0 of the matrix. * @zh 矩阵第 2 列第 0 行的元素。 */ - public m08: number; + public get m08 (): number { + return this._array[8]; + } + public set m08 (m: number) { + this._array[8] = m; + } /** * @en Value at column 2 row 1 of the matrix. * @zh 矩阵第 2 列第 1 行的元素。 */ - public m09: number; + public get m09 (): number { + return this._array[9]; + } + public set m09 (m: number) { + this._array[9] = m; + } /** * @en Value at column 2 row 2 of the matrix. * @zh 矩阵第 2 列第 2 行的元素。 */ - public m10: number; + public get m10 (): number { + return this._array[10]; + } + public set m10 (m: number) { + this._array[10] = m; + } /** * @en Value at column 2 row 3 of the matrix. * @zh 矩阵第 2 列第 3 行的元素。 */ - public m11: number; + public get m11 (): number { + return this._array[11]; + } + public set m11 (m: number) { + this._array[11] = m; + } /** * @en Value at column 3 row 0 of the matrix. * @zh 矩阵第 3 列第 0 行的元素。 */ - public m12: number; + public get m12 (): number { + return this._array[12]; + } + public set m12 (m: number) { + this._array[12] = m; + } /** * @en Value at column 3 row 1 of the matrix. * @zh 矩阵第 3 列第 1 行的元素。 */ - public m13: number; + public get m13 (): number { + return this._array[13]; + } + public set m13 (m: number) { + this._array[13] = m; + } /** * @en Value at column 3 row 2 of the matrix. * @zh 矩阵第 3 列第 2 行的元素。 */ - public m14: number; + public get m14 (): number { + return this._array[14]; + } + public set m14 (m: number) { + this._array[14] = m; + } /** * @en Value at column 3 row 3 of the matrix. * @zh 矩阵第 3 列第 3 行的元素。 */ - public m15: number; + public get m15 (): number { + return this._array[15]; + } + public set m15 (m: number) { + this._array[15] = m; + } - constructor (other: Mat4); + constructor (m00: Mat4 | FloatArray); constructor ( m00?: number, m01?: number, m02?: number, m03?: number, @@ -1511,22 +1591,30 @@ export class Mat4 extends ValueType { m12?: number, m13?: number, m14?: number, m15?: number); constructor ( - m00: Mat4 | number = 1, m01 = 0, m02 = 0, m03 = 0, + m00: Mat4 | number | FloatArray = 1, m01 = 0, m02 = 0, m03 = 0, m04 = 0, m05 = 1, m06 = 0, m07 = 0, m08 = 0, m09 = 0, m10 = 1, m11 = 0, m12 = 0, m13 = 0, m14 = 0, m15 = 1, ) { super(); - if (typeof m00 === 'object') { - this.m00 = m00.m00; this.m01 = m00.m01; this.m02 = m00.m02; this.m03 = m00.m03; - this.m04 = m00.m04; this.m05 = m00.m05; this.m06 = m00.m06; this.m07 = m00.m07; - this.m08 = m00.m08; this.m09 = m00.m09; this.m10 = m00.m10; this.m11 = m00.m11; - this.m12 = m00.m12; this.m13 = m00.m13; this.m14 = m00.m14; this.m15 = m00.m15; + if (m00 && typeof m00 === 'object') { + if (ArrayBuffer.isView(m00)) { + this._array = m00; + this._array.set([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]); + } else { + const v = m00.array; + this._array = MathBase.createFloatArray(16); + this._array[0] = v[0]; this._array[1] = v[1]; this._array[2] = v[2]; this._array[3] = v[3]; + this._array[4] = v[4]; this._array[5] = v[5]; this._array[6] = v[6]; this._array[7] = v[7]; + this._array[8] = v[8]; this._array[9] = v[9]; this._array[10] = v[10]; this._array[11] = v[11]; + this._array[12] = v[12]; this._array[13] = v[13]; this._array[14] = v[14]; this._array[15] = v[15]; + } } else { - this.m00 = m00; this.m01 = m01; this.m02 = m02; this.m03 = m03; - this.m04 = m04; this.m05 = m05; this.m06 = m06; this.m07 = m07; - this.m08 = m08; this.m09 = m09; this.m10 = m10; this.m11 = m11; - this.m12 = m12; this.m13 = m13; this.m14 = m14; this.m15 = m15; + this._array = MathBase.createFloatArray(16); + this._array[0] = m00; this._array[1] = m01; this._array[2] = m02; this._array[3] = m03; + this._array[4] = m04; this._array[5] = m05; this._array[6] = m06; this._array[7] = m07; + this._array[8] = m08; this._array[9] = m09; this._array[10] = m10; this._array[11] = m11; + this._array[12] = m12; this._array[13] = m13; this._array[14] = m14; this._array[15] = m15; } } @@ -1535,11 +1623,12 @@ export class Mat4 extends ValueType { * @zh 克隆当前矩阵。 */ public clone () { + const v = this._array; return new Mat4( - this.m00, this.m01, this.m02, this.m03, - this.m04, this.m05, this.m06, this.m07, - this.m08, this.m09, this.m10, this.m11, - this.m12, this.m13, this.m14, this.m15, + v[0], v[1], v[2], v[3], + v[4], v[5], v[6], v[7], + v[8], v[9], v[10], v[11], + v[12], v[13], v[14], v[15], ); } @@ -1549,7 +1638,7 @@ export class Mat4 extends ValueType { * @param other Specified matrix. * @return this */ - public set (other: Mat4); + public set (other: Readonly); /** * @en Set the matrix with values of all elements @@ -1562,20 +1651,21 @@ export class Mat4 extends ValueType { m08?: number, m09?: number, m10?: number, m11?: number, m12?: number, m13?: number, m14?: number, m15?: number); - public set (m00: Mat4 | number = 1, m01 = 0, m02 = 0, m03 = 0, + public set (m00: Readonly | number = 1, m01 = 0, m02 = 0, m03 = 0, m04 = 0, m05 = 1, m06 = 0, m07 = 0, m08 = 0, m09 = 0, m10 = 1, m11 = 0, m12 = 0, m13 = 0, m14 = 0, m15 = 1) { - if (typeof m00 === 'object') { - this.m01 = m00.m01; this.m02 = m00.m02; this.m03 = m00.m03; this.m04 = m00.m04; - this.m05 = m00.m05; this.m06 = m00.m06; this.m07 = m00.m07; this.m08 = m00.m08; - this.m09 = m00.m09; this.m10 = m00.m10; this.m11 = m00.m11; this.m12 = m00.m12; - this.m13 = m00.m13; this.m14 = m00.m14; this.m15 = m00.m15; this.m00 = m00.m00; + if (m00 && typeof m00 === 'object') { + const v = m00.array; + this._array[1] = v[1]; this._array[2] = v[2]; this._array[3] = v[3]; this._array[4] = v[4]; + this._array[5] = v[5]; this._array[6] = v[6]; this._array[7] = v[7]; this._array[8] = v[8]; + this._array[9] = v[9]; this._array[10] = v[10]; this._array[11] = v[11]; this._array[12] = v[12]; + this._array[13] = v[13]; this._array[14] = v[14]; this._array[15] = v[15]; this._array[0] = v[0]; } else { - this.m01 = m01; this.m02 = m02; this.m03 = m03; this.m04 = m04; - this.m05 = m05; this.m06 = m06; this.m07 = m07; this.m08 = m08; - this.m09 = m09; this.m10 = m10; this.m11 = m11; this.m12 = m12; - this.m13 = m13; this.m14 = m14; this.m15 = m15; this.m00 = m00; + this._array[1] = m01; this._array[2] = m02; this._array[3] = m03; this._array[4] = m04; + this._array[5] = m05; this._array[6] = m06; this._array[7] = m07; this._array[8] = m08; + this._array[9] = m09; this._array[10] = m10; this._array[11] = m11; this._array[12] = m12; + this._array[13] = m13; this._array[14] = m14; this._array[15] = m15; this._array[0] = m00; } return this; } @@ -1587,24 +1677,25 @@ export class Mat4 extends ValueType { * @param epsilon The error allowed. It`s should be a non-negative number. * @return Returns `true' when the elements of both matrices are equal; otherwise returns `false'. */ - public equals (other: Mat4, epsilon = EPSILON): boolean { + public equals (other: Readonly, epsilon = EPSILON): boolean { + const v = other.array; return ( - Math.abs(this.m00 - other.m00) <= epsilon * Math.max(1.0, Math.abs(this.m00), Math.abs(other.m00)) - && Math.abs(this.m01 - other.m01) <= epsilon * Math.max(1.0, Math.abs(this.m01), Math.abs(other.m01)) - && Math.abs(this.m02 - other.m02) <= epsilon * Math.max(1.0, Math.abs(this.m02), Math.abs(other.m02)) - && Math.abs(this.m03 - other.m03) <= epsilon * Math.max(1.0, Math.abs(this.m03), Math.abs(other.m03)) - && Math.abs(this.m04 - other.m04) <= epsilon * Math.max(1.0, Math.abs(this.m04), Math.abs(other.m04)) - && Math.abs(this.m05 - other.m05) <= epsilon * Math.max(1.0, Math.abs(this.m05), Math.abs(other.m05)) - && Math.abs(this.m06 - other.m06) <= epsilon * Math.max(1.0, Math.abs(this.m06), Math.abs(other.m06)) - && Math.abs(this.m07 - other.m07) <= epsilon * Math.max(1.0, Math.abs(this.m07), Math.abs(other.m07)) - && Math.abs(this.m08 - other.m08) <= epsilon * Math.max(1.0, Math.abs(this.m08), Math.abs(other.m08)) - && Math.abs(this.m09 - other.m09) <= epsilon * Math.max(1.0, Math.abs(this.m09), Math.abs(other.m09)) - && Math.abs(this.m10 - other.m10) <= epsilon * Math.max(1.0, Math.abs(this.m10), Math.abs(other.m10)) - && Math.abs(this.m11 - other.m11) <= epsilon * Math.max(1.0, Math.abs(this.m11), Math.abs(other.m11)) - && Math.abs(this.m12 - other.m12) <= epsilon * Math.max(1.0, Math.abs(this.m12), Math.abs(other.m12)) - && Math.abs(this.m13 - other.m13) <= epsilon * Math.max(1.0, Math.abs(this.m13), Math.abs(other.m13)) - && Math.abs(this.m14 - other.m14) <= epsilon * Math.max(1.0, Math.abs(this.m14), Math.abs(other.m14)) - && Math.abs(this.m15 - other.m15) <= epsilon * Math.max(1.0, Math.abs(this.m15), Math.abs(other.m15)) + Math.abs(this._array[0] - v[0]) <= epsilon * Math.max(1.0, Math.abs(this._array[0]), Math.abs(v[0])) + && Math.abs(this._array[1] - v[1]) <= epsilon * Math.max(1.0, Math.abs(this._array[1]), Math.abs(v[1])) + && Math.abs(this._array[2] - v[2]) <= epsilon * Math.max(1.0, Math.abs(this._array[2]), Math.abs(v[2])) + && Math.abs(this._array[3] - v[3]) <= epsilon * Math.max(1.0, Math.abs(this._array[3]), Math.abs(v[3])) + && Math.abs(this._array[4] - v[4]) <= epsilon * Math.max(1.0, Math.abs(this._array[4]), Math.abs(v[4])) + && Math.abs(this._array[5] - v[5]) <= epsilon * Math.max(1.0, Math.abs(this._array[5]), Math.abs(v[5])) + && Math.abs(this._array[6] - v[6]) <= epsilon * Math.max(1.0, Math.abs(this._array[6]), Math.abs(v[6])) + && Math.abs(this._array[7] - v[7]) <= epsilon * Math.max(1.0, Math.abs(this._array[7]), Math.abs(v[7])) + && Math.abs(this._array[8] - v[8]) <= epsilon * Math.max(1.0, Math.abs(this._array[8]), Math.abs(v[8])) + && Math.abs(this._array[9] - v[9]) <= epsilon * Math.max(1.0, Math.abs(this._array[9]), Math.abs(v[9])) + && Math.abs(this._array[10] - v[10]) <= epsilon * Math.max(1.0, Math.abs(this._array[10]), Math.abs(v[10])) + && Math.abs(this._array[11] - v[11]) <= epsilon * Math.max(1.0, Math.abs(this._array[11]), Math.abs(v[11])) + && Math.abs(this._array[12] - v[12]) <= epsilon * Math.max(1.0, Math.abs(this._array[12]), Math.abs(v[12])) + && Math.abs(this._array[13] - v[13]) <= epsilon * Math.max(1.0, Math.abs(this._array[13]), Math.abs(v[13])) + && Math.abs(this._array[14] - v[14]) <= epsilon * Math.max(1.0, Math.abs(this._array[14]), Math.abs(v[14])) + && Math.abs(this._array[15] - v[15]) <= epsilon * Math.max(1.0, Math.abs(this._array[15]), Math.abs(v[15])) ); } @@ -1614,11 +1705,12 @@ export class Mat4 extends ValueType { * @param other Comparative matrix * @return Returns `true' when the elements of both matrices are equal; otherwise returns `false'. */ - public strictEquals (other: Mat4): boolean { - return this.m00 === other.m00 && this.m01 === other.m01 && this.m02 === other.m02 && this.m03 === other.m03 - && this.m04 === other.m04 && this.m05 === other.m05 && this.m06 === other.m06 && this.m07 === other.m07 - && this.m08 === other.m08 && this.m09 === other.m09 && this.m10 === other.m10 && this.m11 === other.m11 - && this.m12 === other.m12 && this.m13 === other.m13 && this.m14 === other.m14 && this.m15 === other.m15; + public strictEquals (other: Readonly): boolean { + const v = other.array; + return this._array[0] === other.m00 && this._array[1] === v[1] && this._array[2] === v[2] && this._array[3] === v[3] + && this._array[4] === v[4] && this._array[5] === v[5] && this._array[6] === v[6] && this._array[7] === v[7] + && this._array[8] === v[8] && this._array[9] === v[9] && this._array[10] === v[10] && this._array[11] === v[11] + && this._array[12] === v[12] && this._array[13] === v[13] && this._array[14] === v[14] && this._array[15] === v[15]; } /** @@ -1628,11 +1720,11 @@ export class Mat4 extends ValueType { */ public toString () { return `[\n${ - this.m00}, ${this.m01}, ${this.m02}, ${this.m03},\n${ - this.m04}, ${this.m05}, ${this.m06}, ${this.m07},\n${ - this.m08}, ${this.m09}, ${this.m10}, ${this.m11},\n${ - this.m12}, ${this.m13}, ${this.m14}, ${this.m15}\n` - + ']'; + this._array[0]}, ${this._array[1]}, ${this._array[2]}, ${this._array[3]},\n${ + this._array[4]}, ${this._array[5]}, ${this._array[6]}, ${this._array[7]},\n${ + this._array[8]}, ${this._array[9]}, ${this._array[10]}, ${this._array[11]},\n${ + this._array[12]}, ${this._array[13]}, ${this._array[14]}, ${this._array[15]}\n` + + `]`; } /** @@ -1641,22 +1733,22 @@ export class Mat4 extends ValueType { * @return `this` */ public identity () { - this.m00 = 1; - this.m01 = 0; - this.m02 = 0; - this.m03 = 0; - this.m04 = 0; - this.m05 = 1; - this.m06 = 0; - this.m07 = 0; - this.m08 = 0; - this.m09 = 0; - this.m10 = 1; - this.m11 = 0; - this.m12 = 0; - this.m13 = 0; - this.m14 = 0; - this.m15 = 1; + this._array[0] = 1; + this._array[1] = 0; + this._array[2] = 0; + this._array[3] = 0; + this._array[4] = 0; + this._array[5] = 1; + this._array[6] = 0; + this._array[7] = 0; + this._array[8] = 0; + this._array[9] = 0; + this._array[10] = 1; + this._array[11] = 0; + this._array[12] = 0; + this._array[13] = 0; + this._array[14] = 0; + this._array[15] = 1; return this; } @@ -1690,19 +1782,19 @@ export class Mat4 extends ValueType { * @zh 计算当前矩阵的转置矩阵。 */ public transpose () { - const a01 = this.m01; const a02 = this.m02; const a03 = this.m03; const a12 = this.m06; const a13 = this.m07; const a23 = this.m11; - this.m01 = this.m04; - this.m02 = this.m08; - this.m03 = this.m12; - this.m04 = a01; - this.m06 = this.m09; - this.m07 = this.m13; - this.m08 = a02; - this.m09 = a12; - this.m11 = this.m14; - this.m12 = a03; - this.m13 = a13; - this.m14 = a23; + const a01 = this._array[1]; const a02 = this._array[2]; const a03 = this._array[3]; const a12 = this._array[6]; const a13 = this._array[7]; const a23 = this._array[11]; + this._array[1] = this._array[4]; + this._array[2] = this._array[8]; + this._array[3] = this._array[12]; + this._array[4] = a01; + this._array[6] = this._array[9]; + this._array[7] = this._array[13]; + this._array[8] = a02; + this._array[9] = a12; + this._array[11] = this._array[14]; + this._array[12] = a03; + this._array[13] = a13; + this._array[14] = a23; return this; } @@ -1711,10 +1803,10 @@ export class Mat4 extends ValueType { * @zh 计算当前矩阵的逆矩阵。注意,在矩阵不可逆时,会返回一个全为 0 的矩阵。 */ public invert () { - const a00 = this.m00; const a01 = this.m01; const a02 = this.m02; const a03 = this.m03; - const a10 = this.m04; const a11 = this.m05; const a12 = this.m06; const a13 = this.m07; - const a20 = this.m08; const a21 = this.m09; const a22 = this.m10; const a23 = this.m11; - const a30 = this.m12; const a31 = this.m13; const a32 = this.m14; const a33 = this.m15; + const a00 = this._array[0]; const a01 = this._array[1]; const a02 = this._array[2]; const a03 = this._array[3]; + const a10 = this._array[4]; const a11 = this._array[5]; const a12 = this._array[6]; const a13 = this._array[7]; + const a20 = this._array[8]; const a21 = this._array[9]; const a22 = this._array[10]; const a23 = this._array[11]; + const a30 = this._array[12]; const a31 = this._array[13]; const a32 = this._array[14]; const a33 = this._array[15]; const b00 = a00 * a11 - a01 * a10; const b01 = a00 * a12 - a02 * a10; @@ -1738,22 +1830,22 @@ export class Mat4 extends ValueType { } det = 1.0 / det; - this.m00 = (a11 * b11 - a12 * b10 + a13 * b09) * det; - this.m01 = (a02 * b10 - a01 * b11 - a03 * b09) * det; - this.m02 = (a31 * b05 - a32 * b04 + a33 * b03) * det; - this.m03 = (a22 * b04 - a21 * b05 - a23 * b03) * det; - this.m04 = (a12 * b08 - a10 * b11 - a13 * b07) * det; - this.m05 = (a00 * b11 - a02 * b08 + a03 * b07) * det; - this.m06 = (a32 * b02 - a30 * b05 - a33 * b01) * det; - this.m07 = (a20 * b05 - a22 * b02 + a23 * b01) * det; - this.m08 = (a10 * b10 - a11 * b08 + a13 * b06) * det; - this.m09 = (a01 * b08 - a00 * b10 - a03 * b06) * det; - this.m10 = (a30 * b04 - a31 * b02 + a33 * b00) * det; - this.m11 = (a21 * b02 - a20 * b04 - a23 * b00) * det; - this.m12 = (a11 * b07 - a10 * b09 - a12 * b06) * det; - this.m13 = (a00 * b09 - a01 * b07 + a02 * b06) * det; - this.m14 = (a31 * b01 - a30 * b03 - a32 * b00) * det; - this.m15 = (a20 * b03 - a21 * b01 + a22 * b00) * det; + this._array[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; + this._array[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det; + this._array[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det; + this._array[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det; + this._array[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det; + this._array[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det; + this._array[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det; + this._array[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det; + this._array[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det; + this._array[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det; + this._array[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det; + this._array[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det; + this._array[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det; + this._array[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det; + this._array[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det; + this._array[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det; return this; } @@ -1764,10 +1856,10 @@ export class Mat4 extends ValueType { * @return 当前矩阵的行列式。 */ public determinant (): number { - const a00 = this.m00; const a01 = this.m01; const a02 = this.m02; const a03 = this.m03; - const a10 = this.m04; const a11 = this.m05; const a12 = this.m06; const a13 = this.m07; - const a20 = this.m08; const a21 = this.m09; const a22 = this.m10; const a23 = this.m11; - const a30 = this.m12; const a31 = this.m13; const a32 = this.m14; const a33 = this.m15; + const a00 = this._array[0]; const a01 = this._array[1]; const a02 = this._array[2]; const a03 = this._array[3]; + const a10 = this._array[4]; const a11 = this._array[5]; const a12 = this._array[6]; const a13 = this._array[7]; + const a20 = this._array[8]; const a21 = this._array[9]; const a22 = this._array[10]; const a23 = this._array[11]; + const a30 = this._array[12]; const a31 = this._array[13]; const a32 = this._array[14]; const a33 = this._array[15]; const b00 = a00 * a11 - a01 * a10; const b01 = a00 * a12 - a02 * a10; @@ -1792,22 +1884,23 @@ export class Mat4 extends ValueType { * @param mat the second operand */ public add (mat: Mat4) { - this.m00 += mat.m00; - this.m01 += mat.m01; - this.m02 += mat.m02; - this.m03 += mat.m03; - this.m04 += mat.m04; - this.m05 += mat.m05; - this.m06 += mat.m06; - this.m07 += mat.m07; - this.m08 += mat.m08; - this.m09 += mat.m09; - this.m10 += mat.m10; - this.m11 += mat.m11; - this.m12 += mat.m12; - this.m13 += mat.m13; - this.m14 += mat.m14; - this.m15 += mat.m15; + const v = mat.array; + this._array[0] += v[0]; + this._array[1] += v[1]; + this._array[2] += v[2]; + this._array[3] += v[3]; + this._array[4] += v[4]; + this._array[5] += v[5]; + this._array[6] += v[6]; + this._array[7] += v[7]; + this._array[8] += v[8]; + this._array[9] += v[9]; + this._array[10] += v[10]; + this._array[11] += v[11]; + this._array[12] += v[12]; + this._array[13] += v[13]; + this._array[14] += v[14]; + this._array[15] += v[15]; return this; } @@ -1817,22 +1910,23 @@ export class Mat4 extends ValueType { * @param mat the second operand */ public subtract (mat: Mat4) { - this.m00 -= mat.m00; - this.m01 -= mat.m01; - this.m02 -= mat.m02; - this.m03 -= mat.m03; - this.m04 -= mat.m04; - this.m05 -= mat.m05; - this.m06 -= mat.m06; - this.m07 -= mat.m07; - this.m08 -= mat.m08; - this.m09 -= mat.m09; - this.m10 -= mat.m10; - this.m11 -= mat.m11; - this.m12 -= mat.m12; - this.m13 -= mat.m13; - this.m14 -= mat.m14; - this.m15 -= mat.m15; + const v = mat.array; + this._array[0] -= v[0]; + this._array[1] -= v[1]; + this._array[2] -= v[2]; + this._array[3] -= v[3]; + this._array[4] -= v[4]; + this._array[5] -= v[5]; + this._array[6] -= v[6]; + this._array[7] -= v[7]; + this._array[8] -= v[8]; + this._array[9] -= v[9]; + this._array[10] -= v[10]; + this._array[11] -= v[11]; + this._array[12] -= v[12]; + this._array[13] -= v[13]; + this._array[14] -= v[14]; + this._array[15] -= v[15]; return this; } @@ -1842,35 +1936,35 @@ export class Mat4 extends ValueType { * @param mat the second operand */ public multiply (mat: Mat4) { - const a00 = this.m00; const a01 = this.m01; const a02 = this.m02; const a03 = this.m03; - const a10 = this.m04; const a11 = this.m05; const a12 = this.m06; const a13 = this.m07; - const a20 = this.m08; const a21 = this.m09; const a22 = this.m10; const a23 = this.m11; - const a30 = this.m12; const a31 = this.m13; const a32 = this.m14; const a33 = this.m15; - + const a00 = this._array[0]; const a01 = this._array[1]; const a02 = this._array[2]; const a03 = this._array[3]; + const a10 = this._array[4]; const a11 = this._array[5]; const a12 = this._array[6]; const a13 = this._array[7]; + const a20 = this._array[8]; const a21 = this._array[9]; const a22 = this._array[10]; const a23 = this._array[11]; + const a30 = this._array[12]; const a31 = this._array[13]; const a32 = this._array[14]; const a33 = this._array[15]; + const v = mat.array; // Cache only the current line of the second matrix - let b0 = mat.m00; let b1 = mat.m01; let b2 = mat.m02; let b3 = mat.m03; - this.m00 = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; - this.m01 = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; - this.m02 = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; - this.m03 = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; - - b0 = mat.m04; b1 = mat.m05; b2 = mat.m06; b3 = mat.m07; - this.m04 = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; - this.m05 = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; - this.m06 = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; - this.m07 = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; - - b0 = mat.m08; b1 = mat.m09; b2 = mat.m10; b3 = mat.m11; - this.m08 = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; - this.m09 = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; - this.m10 = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; - this.m11 = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; - - b0 = mat.m12; b1 = mat.m13; b2 = mat.m14; b3 = mat.m15; - this.m12 = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; - this.m13 = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; - this.m14 = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; - this.m15 = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + let b0 = v[0]; let b1 = v[1]; let b2 = v[2]; let b3 = v[3]; + this._array[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + this._array[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + this._array[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + this._array[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + + b0 = v[4]; b1 = v[5]; b2 = v[6]; b3 = v[7]; + this._array[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + this._array[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + this._array[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + this._array[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + + b0 = v[8]; b1 = v[9]; b2 = v[10]; b3 = v[11]; + this._array[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + this._array[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + this._array[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + this._array[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + + b0 = v[12]; b1 = v[13]; b2 = v[14]; b3 = v[15]; + this._array[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + this._array[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + this._array[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + this._array[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; return this; } @@ -1880,22 +1974,22 @@ export class Mat4 extends ValueType { * @param scalar amount to scale the matrix's elements by */ public multiplyScalar (scalar: number) { - this.m00 *= scalar; - this.m01 *= scalar; - this.m02 *= scalar; - this.m03 *= scalar; - this.m04 *= scalar; - this.m05 *= scalar; - this.m06 *= scalar; - this.m07 *= scalar; - this.m08 *= scalar; - this.m09 *= scalar; - this.m10 *= scalar; - this.m11 *= scalar; - this.m12 *= scalar; - this.m13 *= scalar; - this.m14 *= scalar; - this.m15 *= scalar; + this._array[0] *= scalar; + this._array[1] *= scalar; + this._array[2] *= scalar; + this._array[3] *= scalar; + this._array[4] *= scalar; + this._array[5] *= scalar; + this._array[6] *= scalar; + this._array[7] *= scalar; + this._array[8] *= scalar; + this._array[9] *= scalar; + this._array[10] *= scalar; + this._array[11] *= scalar; + this._array[12] *= scalar; + this._array[13] *= scalar; + this._array[14] *= scalar; + this._array[15] *= scalar; return this; } @@ -1906,9 +2000,10 @@ export class Mat4 extends ValueType { */ public translate (vec: Vec3) { console.warn('function changed'); - this.m12 += vec.x; - this.m13 += vec.y; - this.m14 += vec.z; + const v = vec.array; + this._array[12] += v[0]; + this._array[13] += v[1]; + this._array[14] += v[2]; return this; } @@ -1918,19 +2013,20 @@ export class Mat4 extends ValueType { * @param vec vector to scale by */ public scale (vec: Vec3) { - const x = vec.x; const y = vec.y; const z = vec.z; - this.m00 *= x; - this.m01 *= x; - this.m02 *= x; - this.m03 *= x; - this.m04 *= y; - this.m05 *= y; - this.m06 *= y; - this.m07 *= y; - this.m08 *= z; - this.m09 *= z; - this.m10 *= z; - this.m11 *= z; + const v = vec.array; + const x = v[0]; const y = v[1]; const z = v[2]; + this._array[0] *= x; + this._array[1] *= x; + this._array[2] *= x; + this._array[3] *= x; + this._array[4] *= y; + this._array[5] *= y; + this._array[6] *= y; + this._array[7] *= y; + this._array[8] *= z; + this._array[9] *= z; + this._array[10] *= z; + this._array[11] *= z; return this; } @@ -1958,9 +2054,9 @@ export class Mat4 extends ValueType { const c = Math.cos(rad); const t = 1 - c; - const a00 = this.m00; const a01 = this.m01; const a02 = this.m02; const a03 = this.m03; - const a10 = this.m04; const a11 = this.m05; const a12 = this.m06; const a13 = this.m07; - const a20 = this.m08; const a21 = this.m09; const a22 = this.m10; const a23 = this.m11; + const a00 = this._array[0]; const a01 = this._array[1]; const a02 = this._array[2]; const a03 = this._array[3]; + const a10 = this._array[4]; const a11 = this._array[5]; const a12 = this._array[6]; const a13 = this._array[7]; + const a20 = this._array[8]; const a21 = this._array[9]; const a22 = this._array[10]; const a23 = this._array[11]; // Construct the elements of the rotation matrix const b00 = x * x * t + c; const b01 = y * x * t + z * s; const b02 = z * x * t - y * s; @@ -1968,18 +2064,18 @@ export class Mat4 extends ValueType { const b20 = x * z * t + y * s; const b21 = y * z * t - x * s; const b22 = z * z * t + c; // Perform rotation-specific matrix multiplication - this.m00 = a00 * b00 + a10 * b01 + a20 * b02; - this.m01 = a01 * b00 + a11 * b01 + a21 * b02; - this.m02 = a02 * b00 + a12 * b01 + a22 * b02; - this.m03 = a03 * b00 + a13 * b01 + a23 * b02; - this.m04 = a00 * b10 + a10 * b11 + a20 * b12; - this.m05 = a01 * b10 + a11 * b11 + a21 * b12; - this.m06 = a02 * b10 + a12 * b11 + a22 * b12; - this.m07 = a03 * b10 + a13 * b11 + a23 * b12; - this.m08 = a00 * b20 + a10 * b21 + a20 * b22; - this.m09 = a01 * b20 + a11 * b21 + a21 * b22; - this.m10 = a02 * b20 + a12 * b21 + a22 * b22; - this.m11 = a03 * b20 + a13 * b21 + a23 * b22; + this._array[0] = a00 * b00 + a10 * b01 + a20 * b02; + this._array[1] = a01 * b00 + a11 * b01 + a21 * b02; + this._array[2] = a02 * b00 + a12 * b01 + a22 * b02; + this._array[3] = a03 * b00 + a13 * b01 + a23 * b02; + this._array[4] = a00 * b10 + a10 * b11 + a20 * b12; + this._array[5] = a01 * b10 + a11 * b11 + a21 * b12; + this._array[6] = a02 * b10 + a12 * b11 + a22 * b12; + this._array[7] = a03 * b10 + a13 * b11 + a23 * b12; + this._array[8] = a00 * b20 + a10 * b21 + a20 * b22; + this._array[9] = a01 * b20 + a11 * b21 + a21 * b22; + this._array[10] = a02 * b20 + a12 * b21 + a22 * b22; + this._array[11] = a03 * b20 + a13 * b21 + a23 * b22; return this; } @@ -1990,9 +2086,9 @@ export class Mat4 extends ValueType { * @param out Vector to receive translation component. */ public getTranslation (out: Vec3) { - out.x = this.m12; - out.y = this.m13; - out.z = this.m14; + out.x = this._array[12]; + out.y = this._array[13]; + out.z = this._array[14]; return out; } @@ -2003,18 +2099,20 @@ export class Mat4 extends ValueType { * @param out Vector to receive scale component */ public getScale (out: Vec3) { - const m00 = m3_1.m00 = this.m00; - const m01 = m3_1.m01 = this.m01; - const m02 = m3_1.m02 = this.m02; - const m04 = m3_1.m03 = this.m04; - const m05 = m3_1.m04 = this.m05; - const m06 = m3_1.m05 = this.m06; - const m08 = m3_1.m06 = this.m08; - const m09 = m3_1.m07 = this.m09; - const m10 = m3_1.m08 = this.m10; - out.x = Math.sqrt(m00 * m00 + m01 * m01 + m02 * m02); - out.y = Math.sqrt(m04 * m04 + m05 * m05 + m06 * m06); - out.z = Math.sqrt(m08 * m08 + m09 * m09 + m10 * m10); + const o = out.array; + const t = m3_1.array; + const m00 = t[0] = this._array[0]; + const m01 = t[1] = this._array[1]; + const m02 = t[2] = this._array[2]; + const m04 = t[3] = this._array[4]; + const m05 = t[4] = this._array[5]; + const m06 = t[5] = this._array[6]; + const m08 = t[6] = this._array[8]; + const m09 = t[7] = this._array[9]; + const m10 = t[8] = this._array[10]; + o[0] = Math.sqrt(m00 * m00 + m01 * m01 + m02 * m02); + o[1] = Math.sqrt(m04 * m04 + m05 * m05 + m06 * m06); + o[2] = Math.sqrt(m08 * m08 + m09 * m09 + m10 * m10); // account for refections if (Mat3.determinant(m3_1) < 0) { out.x *= -1; } return out; @@ -2026,32 +2124,32 @@ export class Mat4 extends ValueType { * @param out Vector to receive rotation component */ public getRotation (out: Quat) { - const trace = this.m00 + this.m05 + this.m10; + const trace = this._array[0] + this._array[5] + this._array[10]; let S = 0; if (trace > 0) { S = Math.sqrt(trace + 1.0) * 2; out.w = 0.25 * S; - out.x = (this.m06 - this.m09) / S; - out.y = (this.m08 - this.m02) / S; - out.z = (this.m01 - this.m04) / S; - } else if ((this.m00 > this.m05) && (this.m00 > this.m10)) { - S = Math.sqrt(1.0 + this.m00 - this.m05 - this.m10) * 2; - out.w = (this.m06 - this.m09) / S; + out.x = (this._array[6] - this._array[9]) / S; + out.y = (this._array[8] - this._array[2]) / S; + out.z = (this._array[1] - this._array[4]) / S; + } else if ((this._array[0] > this._array[5]) && (this._array[0] > this._array[10])) { + S = Math.sqrt(1.0 + this._array[0] - this._array[5] - this._array[10]) * 2; + out.w = (this._array[6] - this._array[9]) / S; out.x = 0.25 * S; - out.y = (this.m01 + this.m04) / S; - out.z = (this.m08 + this.m02) / S; - } else if (this.m05 > this.m10) { - S = Math.sqrt(1.0 + this.m05 - this.m00 - this.m10) * 2; - out.w = (this.m08 - this.m02) / S; - out.x = (this.m01 + this.m04) / S; + out.y = (this._array[1] + this._array[4]) / S; + out.z = (this._array[8] + this._array[2]) / S; + } else if (this._array[5] > this._array[10]) { + S = Math.sqrt(1.0 + this._array[5] - this._array[0] - this._array[10]) * 2; + out.w = (this._array[8] - this._array[2]) / S; + out.x = (this._array[1] + this._array[4]) / S; out.y = 0.25 * S; - out.z = (this.m06 + this.m09) / S; + out.z = (this._array[6] + this._array[9]) / S; } else { - S = Math.sqrt(1.0 + this.m10 - this.m00 - this.m05) * 2; - out.w = (this.m01 - this.m04) / S; - out.x = (this.m08 + this.m02) / S; - out.y = (this.m06 + this.m09) / S; + S = Math.sqrt(1.0 + this._array[10] - this._array[0] - this._array[5]) * 2; + out.w = (this._array[1] - this._array[4]) / S; + out.x = (this._array[8] + this._array[2]) / S; + out.y = (this._array[6] + this._array[9]) / S; out.z = 0.25 * S; } @@ -2085,22 +2183,22 @@ export class Mat4 extends ValueType { const sy = s.y; const sz = s.z; - this.m00 = (1 - (yy + zz)) * sx; - this.m01 = (xy + wz) * sx; - this.m02 = (xz - wy) * sx; - this.m03 = 0; - this.m04 = (xy - wz) * sy; - this.m05 = (1 - (xx + zz)) * sy; - this.m06 = (yz + wx) * sy; - this.m07 = 0; - this.m08 = (xz + wy) * sz; - this.m09 = (yz - wx) * sz; - this.m10 = (1 - (xx + yy)) * sz; - this.m11 = 0; - this.m12 = v.x; - this.m13 = v.y; - this.m14 = v.z; - this.m15 = 1; + this._array[0] = (1 - (yy + zz)) * sx; + this._array[1] = (xy + wz) * sx; + this._array[2] = (xz - wy) * sx; + this._array[3] = 0; + this._array[4] = (xy - wz) * sy; + this._array[5] = (1 - (xx + zz)) * sy; + this._array[6] = (yz + wx) * sy; + this._array[7] = 0; + this._array[8] = (xz + wy) * sz; + this._array[9] = (yz - wx) * sz; + this._array[10] = (1 - (xx + yy)) * sz; + this._array[11] = 0; + this._array[12] = v.x; + this._array[13] = v.y; + this._array[14] = v.z; + this._array[15] = 1; return this; } @@ -2127,25 +2225,25 @@ export class Mat4 extends ValueType { const wy = w * y2; const wz = w * z2; - this.m00 = 1 - yy - zz; - this.m01 = yx + wz; - this.m02 = zx - wy; - this.m03 = 0; - - this.m04 = yx - wz; - this.m05 = 1 - xx - zz; - this.m06 = zy + wx; - this.m07 = 0; - - this.m08 = zx + wy; - this.m09 = zy - wx; - this.m10 = 1 - xx - yy; - this.m11 = 0; - - this.m12 = 0; - this.m13 = 0; - this.m14 = 0; - this.m15 = 1; + this._array[0] = 1 - yy - zz; + this._array[1] = yx + wz; + this._array[2] = zx - wy; + this._array[3] = 0; + + this._array[4] = yx - wz; + this._array[5] = 1 - xx - zz; + this._array[6] = zy + wx; + this._array[7] = 0; + + this._array[8] = zx + wy; + this._array[9] = zy - wx; + this._array[10] = 1 - xx - yy; + this._array[11] = 0; + + this._array[12] = 0; + this._array[13] = 0; + this._array[14] = 0; + this._array[15] = 1; return this; } diff --git a/cocos/core/math/math-base.ts b/cocos/core/math/math-base.ts new file mode 100644 index 00000000000..61eeaff2e2b --- /dev/null +++ b/cocos/core/math/math-base.ts @@ -0,0 +1,20 @@ +import { ValueType } from '../value-types/value-type'; +import { FloatArray } from './type-define'; + +export const MATH_FLOAT_ARRAY = Float32Array; + +export class MathBase extends ValueType { + public static createFloatArray (size: number) { + return new MATH_FLOAT_ARRAY(size); + } + + /** + * @en Get the internal array data. + * @zh 获取内部 array 数据。 + */ + public get array (): FloatArray { + return this._array; + } + + protected declare _array: FloatArray; +} diff --git a/cocos/core/math/quat.ts b/cocos/core/math/quat.ts index d6965d89d36..8b15dd96e3e 100644 --- a/cocos/core/math/quat.ts +++ b/cocos/core/math/quat.ts @@ -29,25 +29,25 @@ */ import { CCClass } from '../data/class'; -import { ValueType } from '../value-types/value-type'; import { Mat3 } from './mat3'; -import { IQuatLike, IVec3Like } from './type-define'; +import { IQuatLike, IVec3Like, FloatArray } from './type-define'; import { EPSILON, toDegree } from './utils'; import { Vec3 } from './vec3'; import { legacyCC } from '../global-exports'; +import { MathBase } from './math-base'; /** * @en quaternion * @zh 四元数 */ -export class Quat extends ValueType { +export class Quat extends MathBase { public static IDENTITY = Object.freeze(new Quat()); /** * @en Obtain a copy of the given quaternion * @zh 获得指定四元数的拷贝 */ - public static clone (a: Out) { + public static clone (a: Readonly) { return new Quat(a.x, a.y, a.z, a.w); } @@ -55,7 +55,7 @@ export class Quat extends ValueType { * @en Copy the given quaternion to the out quaternion * @zh 复制目标四元数 */ - public static copy (out: Out, a: QuatLike) { + public static copy (out: Out, a: Readonly) { out.x = a.x; out.y = a.y; out.z = a.z; @@ -91,7 +91,7 @@ export class Quat extends ValueType { * @en Sets the out quaternion with the shortest path orientation between two vectors, considering both vectors normalized * @zh 设置四元数为两向量间的最短路径旋转,默认两向量都已归一化 */ - public static rotationTo (out: Out, a: VecLike, b: VecLike) { + public static rotationTo (out: Out, a: Readonly, b: Readonly) { const dot = Vec3.dot(a, b); if (dot < -0.999999) { Vec3.cross(v3_1, Vec3.UNIT_X, a); @@ -124,7 +124,7 @@ export class Quat extends ValueType { * @param q input quaternion * @return radius of rotation */ - public static getAxisAngle (outAxis: VecLike, q: Out) { + public static getAxisAngle (outAxis: IVec3Like, q: Out) { const rad = Math.acos(q.w) * 2.0; const s = Math.sin(rad / 2.0); if (s !== 0.0) { @@ -160,7 +160,7 @@ export class Quat extends ValueType { * @en Quaternion scalar multiplication and save the results to out quaternion * @zh 四元数标量乘法 */ - public static multiplyScalar (out: Out, a: Out, b: number) { + public static multiplyScalar (out: Out, a: Readonly, b: number) { out.x = a.x * b; out.y = a.y * b; out.z = a.z * b; @@ -172,7 +172,7 @@ export class Quat extends ValueType { * @en Quaternion multiplication and addition: A + B * scale * @zh 四元数乘加:A + B * scale */ - public static scaleAndAdd (out: Out, a: Out, b: Out, scale: number) { + public static scaleAndAdd (out: Out, a: Readonly, b: Readonly, scale: number) { out.x = a.x + b.x * scale; out.y = a.y + b.y * scale; out.z = a.z + b.z * scale; @@ -185,7 +185,7 @@ export class Quat extends ValueType { * @zh 绕 X 轴旋转指定四元数 * @param rad radius of rotation */ - public static rotateX (out: Out, a: Out, rad: number) { + public static rotateX (out: Out, a: Readonly, rad: number) { rad *= 0.5; const bx = Math.sin(rad); @@ -204,7 +204,7 @@ export class Quat extends ValueType { * @zh 绕 Y 轴旋转指定四元数 * @param rad radius of rotation */ - public static rotateY (out: Out, a: Out, rad: number) { + public static rotateY (out: Out, a: Readonly, rad: number) { rad *= 0.5; const by = Math.sin(rad); @@ -223,7 +223,7 @@ export class Quat extends ValueType { * @zh 绕 Z 轴旋转指定四元数 * @param rad radius of rotation */ - public static rotateZ (out: Out, a: Out, rad: number) { + public static rotateZ (out: Out, a: Readonly, rad: number) { rad *= 0.5; const bz = Math.sin(rad); @@ -243,7 +243,7 @@ export class Quat extends ValueType { * @param axis axis of rotation, normalized by default * @param rad radius of rotation */ - public static rotateAround (out: Out, rot: Out, axis: VecLike, rad: number) { + public static rotateAround (out: Out, rot: Out, axis: Readonly, rad: number) { // get inv-axis (local to rot) Quat.invert(qt_1, rot); Vec3.transformQuat(v3_1, axis, qt_1); @@ -259,7 +259,7 @@ export class Quat extends ValueType { * @param axis axis of rotation * @param rad radius of rotation */ - public static rotateAroundLocal (out: Out, rot: Out, axis: VecLike, rad: number) { + public static rotateAroundLocal (out: Out, rot: Out, axis: Readonly, rad: number) { Quat.fromAxisAngle(qt_1, axis, rad); Quat.multiply(out, rot, qt_1); return out; @@ -269,7 +269,7 @@ export class Quat extends ValueType { * @en Calculates the w component with xyz components, considering the given quaternion normalized * @zh 根据 xyz 分量计算 w 分量,默认已归一化 */ - public static calculateW (out: Out, a: Out) { + public static calculateW (out: Out, a: Readonly) { out.x = a.x; out.y = a.y; out.z = a.z; @@ -281,7 +281,7 @@ export class Quat extends ValueType { * @en Quaternion dot product (scalar product) * @zh 四元数点积(数量积) */ - public static dot (a: Out, b: Out) { + public static dot (a: Readonly, b: Readonly) { return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; } @@ -289,7 +289,7 @@ export class Quat extends ValueType { * @en Element by element linear interpolation: A + t * (B - A) * @zh 逐元素线性插值: A + t * (B - A) */ - public static lerp (out: Out, a: Out, b: Out, t: number) { + public static lerp (out: Out, a: Readonly, b: Readonly, t: number) { out.x = a.x + t * (b.x - a.x); out.y = a.y + t * (b.y - a.y); out.z = a.z + t * (b.z - a.z); @@ -349,7 +349,7 @@ export class Quat extends ValueType { * @en Spherical quaternion interpolation with two control points * @zh 带两个控制点的四元数球面插值 */ - public static sqlerp (out: Out, a: Out, b: Out, c: Out, d: Out, t: number) { + public static sqlerp (out: Out, a: Readonly, b: Readonly, c: Out, d: Out, t: number) { Quat.slerp(qt_1, a, d, t); Quat.slerp(qt_2, b, c, t); Quat.slerp(out, qt_1, qt_2, 2 * t * (1 - t)); @@ -360,7 +360,7 @@ export class Quat extends ValueType { * @en Sets the inverse of the given quaternion to out quaternion * @zh 四元数求逆 */ - public static invert (out: Out, a: QuatLike) { + public static invert (out: Out, a: Readonly) { const dot = a.x * a.x + a.y * a.y + a.z * a.z + a.w * a.w; const invDot = dot ? 1.0 / dot : 0; @@ -377,7 +377,7 @@ export class Quat extends ValueType { * @en Conjugating a quaternion, it's equivalent to the inverse of the unit quaternion, but more efficient * @zh 求共轭四元数,对单位四元数与求逆等价,但更高效 */ - public static conjugate (out: Out, a: Out) { + public static conjugate (out: Out, a: Readonly) { out.x = -a.x; out.y = -a.y; out.z = -a.z; @@ -389,7 +389,7 @@ export class Quat extends ValueType { * @en Calculates the length of the quaternion * @zh 求四元数长度 */ - public static len (a: Out) { + public static len (a: Readonly) { return Math.sqrt(a.x * a.x + a.y * a.y + a.z * a.z + a.w * a.w); } @@ -397,7 +397,7 @@ export class Quat extends ValueType { * @en Calculates the squared length of the quaternion * @zh 求四元数长度平方 */ - public static lengthSqr (a: Out) { + public static lengthSqr (a: Readonly) { return a.x * a.x + a.y * a.y + a.z * a.z + a.w * a.w; } @@ -405,7 +405,7 @@ export class Quat extends ValueType { * @en Normalize the given quaternion * @zh 归一化四元数 */ - public static normalize (out: Out, a: Out) { + public static normalize (out: Out, a: Readonly) { let len = a.x * a.x + a.y * a.y + a.z * a.z + a.w * a.w; if (len > 0) { len = 1 / Math.sqrt(len); @@ -421,7 +421,7 @@ export class Quat extends ValueType { * @en Calculated the quaternion represents the given coordinates, considering all given vectors are normalized and mutually perpendicular * @zh 根据本地坐标轴朝向计算四元数,默认三向量都已归一化且相互垂直 */ - public static fromAxes (out: Out, xAxis: VecLike, yAxis: VecLike, zAxis: VecLike) { + public static fromAxes (out: Out, xAxis: Readonly, yAxis: Readonly, zAxis: Readonly) { Mat3.set(m3_1, xAxis.x, xAxis.y, xAxis.z, yAxis.x, yAxis.y, yAxis.z, @@ -435,7 +435,7 @@ export class Quat extends ValueType { * @param view The view direction, it`s must be normalized. * @param up The view up direction, it`s must be normalized, default value is (0, 1, 0). */ - public static fromViewUp (out: Out, view: VecLike, up?: Vec3) { + public static fromViewUp (out: Out, view: Readonly, up?: Readonly) { Mat3.fromViewUp(m3_1, view, up); return Quat.normalize(out, Quat.fromMat3(out, m3_1)); } @@ -444,7 +444,7 @@ export class Quat extends ValueType { * @en Calculates the quaternion from a given rotary shaft and a radian rotation around it. * @zh 根据旋转轴和旋转弧度计算四元数 */ - public static fromAxisAngle (out: Out, axis: VecLike, rad: number) { + public static fromAxisAngle (out: Out, axis: Readonly, rad: number) { rad *= 0.5; const s = Math.sin(rad); out.x = s * axis.x; @@ -668,42 +668,70 @@ export class Quat extends ValueType { * @en x component. * @zh x 分量。 */ - public declare x: number; + public get x (): number { + return this._array[0]; + } + public set x (x: number) { + this._array[0] = x; + } /** * @en y component. * @zh y 分量。 */ - public declare y: number; + public get y (): number { + return this._array[1]; + } + public set y (y: number) { + this._array[1] = y; + } /** * @en z component. * @zh z 分量。 */ - public declare z: number; + public get z (): number { + return this._array[2]; + } + public set z (z: number) { + this._array[2] = z; + } /** * @en w component. * @zh w 分量。 */ - public declare w: number; + public get w (): number { + return this._array[3]; + } + public set w (w: number) { + this._array[3] = w; + } - constructor (other: Quat); + constructor (x: Quat | FloatArray); constructor (x?: number, y?: number, z?: number, w?: number); - constructor (x?: number | IQuatLike, y?: number, z?: number, w?: number) { + constructor (x?: number | Quat | FloatArray, y?: number, z?: number, w?: number) { super(); if (x && typeof x === 'object') { - this.x = x.x; - this.y = x.y; - this.z = x.z; - this.w = x.w; + if (ArrayBuffer.isView(x)) { + this._array = x; + this._array.fill(0); + } else { + const v = x.array; + this._array = MathBase.createFloatArray(4); + this._array[0] = v[0]; + this._array[1] = v[1]; + this._array[2] = v[2]; + this._array[3] = v[3]; + } } else { - this.x = x || 0; - this.y = y || 0; - this.z = z || 0; - this.w = w ?? 1; + this._array = MathBase.createFloatArray(4); + this._array[0] = x || 0; + this._array[1] = y || 0; + this._array[2] = z || 0; + this._array[3] = w ?? 1; } } @@ -712,7 +740,7 @@ export class Quat extends ValueType { * @zh 克隆当前四元数。 */ public clone () { - return new Quat(this.x, this.y, this.z, this.w); + return new Quat(this._array[0], this._array[1], this._array[2], this._array[3]); } /** @@ -721,7 +749,7 @@ export class Quat extends ValueType { * @param other Specified quaternion * @returns `this` */ - public set (other: Quat): Quat; + public set (other: Readonly): Quat; /** * @en Set the value of each component of the current quaternion @@ -730,17 +758,18 @@ export class Quat extends ValueType { */ public set (x?: number, y?: number, z?: number, w?: number): Quat; - public set (x?: number | Quat, y?: number, z?: number, w?: number) { + public set (x?: number | Readonly, y?: number, z?: number, w?: number) { if (x && typeof x === 'object') { - this.x = x.x; - this.y = x.y; - this.z = x.z; - this.w = x.w; + const v = x.array; + this._array[0] = v[0]; + this._array[1] = v[1]; + this._array[2] = v[2]; + this._array[3] = v[3]; } else { - this.x = x || 0; - this.y = y || 0; - this.z = z || 0; - this.w = w ?? 1; + this._array[0] = x || 0; + this._array[1] = y || 0; + this._array[2] = z || 0; + this._array[3] = w ?? 1; } return this; } @@ -752,11 +781,12 @@ export class Quat extends ValueType { * @param epsilon The error allowed. It`s should be a non-negative number. * @returns Returns `true' when the components of the two quaternions are equal within the specified error range; otherwise, returns `false'. */ - public equals (other: Quat, epsilon = EPSILON) { - return (Math.abs(this.x - other.x) <= epsilon * Math.max(1.0, Math.abs(this.x), Math.abs(other.x)) - && Math.abs(this.y - other.y) <= epsilon * Math.max(1.0, Math.abs(this.y), Math.abs(other.y)) - && Math.abs(this.z - other.z) <= epsilon * Math.max(1.0, Math.abs(this.z), Math.abs(other.z)) - && Math.abs(this.w - other.w) <= epsilon * Math.max(1.0, Math.abs(this.w), Math.abs(other.w))); + public equals (other: Readonly, epsilon = EPSILON) { + const v = other.array; + return (Math.abs(this._array[0] - v[0]) <= epsilon * Math.max(1.0, Math.abs(this._array[0]), Math.abs(v[0])) + && Math.abs(this._array[1] - v[1]) <= epsilon * Math.max(1.0, Math.abs(this._array[1]), Math.abs(v[1])) + && Math.abs(this._array[2] - v[2]) <= epsilon * Math.max(1.0, Math.abs(this._array[2]), Math.abs(v[2])) + && Math.abs(this._array[3] - v[3]) <= epsilon * Math.max(1.0, Math.abs(this._array[3]), Math.abs(v[3]))); } /** @@ -765,8 +795,9 @@ export class Quat extends ValueType { * @param other Comparative quaternion * @returns Returns `true' when the components of the two quaternions are equal within the specified error range; otherwise, returns `false'. */ - public strictEquals (other: Quat) { - return other && this.x === other.x && this.y === other.y && this.z === other.z && this.w === other.w; + public strictEquals (other: Readonly) { + const v = other.array; + return other && this._array[0] === v[0] && this._array[1] === v[1] && this._array[2] === v[2] && this._array[3] === v[3]; } /** @@ -785,10 +816,11 @@ export class Quat extends ValueType { * @param ratio The interpolation coefficient. The range is [0,1]. */ public lerp (to: Quat, ratio: number) { - this.x += ratio * (to.x - this.x); - this.y += ratio * (to.y - this.y); - this.z += ratio * (to.z - this.z); - this.w += ratio * (to.w - this.w); + const tq = to.array; + this._array[0] += ratio * (tq[0] - this._array[0]); + this._array[1] += ratio * (tq[1] - this._array[1]); + this._array[2] += ratio * (tq[2] - this._array[2]); + this._array[3] += ratio * (tq[3] - this._array[3]); return this; } @@ -807,7 +839,8 @@ export class Quat extends ValueType { * @zh 求四元数长度 */ public length () { - return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w); + const v = this._array; + return Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]); } /** @@ -815,7 +848,8 @@ export class Quat extends ValueType { * @zh 求四元数长度平方 */ public lengthSqr () { - return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; + const v = this._array; + return v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]; } } diff --git a/cocos/core/math/rect.ts b/cocos/core/math/rect.ts index bc57640aa4d..f78c557a910 100644 --- a/cocos/core/math/rect.ts +++ b/cocos/core/math/rect.ts @@ -30,12 +30,12 @@ */ import { CCClass } from '../data/class'; -import { ValueType } from '../value-types/value-type'; import { Mat4 } from './mat4'; import { Size } from './size'; -import { IRectLike, IVec2Like } from './type-define'; +import { IRectLike, IVec2Like, FloatArray } from './type-define'; import { Vec2 } from './vec2'; import { legacyCC } from '../global-exports'; +import { MathBase } from './math-base'; /** * @en @@ -45,7 +45,7 @@ import { legacyCC } from '../global-exports'; * 矩形内的所有点都大于等于矩形的最小点 (xMin, yMin) 并且小于等于矩形的最大点 (xMax, yMax)。 * 矩形的宽度定义为 xMax - xMin;高度定义为 yMax - yMin。 */ -export class Rect extends ValueType { +export class Rect extends MathBase { /** * @en Creates a rectangle from two coordinate values. * @zh 由任意两个点创建一个矩形,目标矩形即是这两个点各向 x、y 轴作线所得到的矩形。 @@ -53,7 +53,7 @@ export class Rect extends ValueType { * @param v2 Specified point 2. * @returns Target rectangle. */ - public static fromMinMax (out: Out, v1: VecLike, v2: VecLike) { + public static fromMinMax (out: Out, v1: Readonly, v2: Readonly) { const minX = Math.min(v1.x, v2.x); const minY = Math.min(v1.y, v2.y); const maxX = Math.max(v1.x, v2.x); @@ -74,7 +74,7 @@ export class Rect extends ValueType { * @param to Target rect. * @param ratio The interpolation coefficient.The range is [0,1]. */ - public static lerp (out: Out, from: Out, to: Out, ratio: number) { + public static lerp (out: Out, from: Readonly, to: Readonly, ratio: number) { const x = from.x; const y = from.y; const w = from.width; @@ -94,7 +94,7 @@ export class Rect extends ValueType { * @param one One of the specify Rect. * @param other Another of the specify Rect. */ - public static intersection (out: Out, one: Out, other: Out) { + public static intersection (out: Out, one: Readonly, other: Readonly) { const axMin = one.x; const ayMin = one.y; const axMax = one.x + one.width; @@ -118,7 +118,7 @@ export class Rect extends ValueType { * @param one One of the specify Rect. * @param other Another of the specify Rect. */ - public static union (out: Out, one: Out, other: Out) { + public static union (out: Out, one: Readonly, other: Readonly) { const x = one.x; const y = one.y; const w = one.width; @@ -140,12 +140,12 @@ export class Rect extends ValueType { * @zh 获取或设置矩形在 x 轴上的最小值。 */ get xMin () { - return this.x; + return this._array[0]; } set xMin (value) { - this.width += this.x - value; - this.x = value; + this._array[2] += this._array[0] - value; + this._array[0] = value; } /** @@ -153,12 +153,12 @@ export class Rect extends ValueType { * @zh 获取或设置矩形在 y 轴上的最小值。 */ get yMin () { - return this.y; + return this._array[1]; } set yMin (value) { - this.height += this.y - value; - this.y = value; + this._array[3] += this._array[1] - value; + this._array[1] = value; } /** @@ -166,11 +166,11 @@ export class Rect extends ValueType { * @zh 获取或设置矩形在 x 轴上的最大值。 */ get xMax () { - return this.x + this.width; + return this._array[0] + this._array[2]; } set xMax (value) { - this.width = value - this.x; + this._array[2] = value - this._array[0]; } /** @@ -178,11 +178,11 @@ export class Rect extends ValueType { * @zh 获取或设置矩形在 y 轴上的最大值。 */ get yMax () { - return this.y + this.height; + return this._array[1] + this._array[3]; } set yMax (value) { - this.height = value - this.y; + this._array[3] = value - this._array[1]; } /** @@ -190,13 +190,13 @@ export class Rect extends ValueType { * @zh 获取或设置矩形中心点的坐标。 */ get center () { - return new Vec2(this.x + this.width * 0.5, - this.y + this.height * 0.5); + return new Vec2(this._array[0] + this._array[2] * 0.5, + this._array[1] + this._array[3] * 0.5); } set center (value) { - this.x = value.x - this.width * 0.5; - this.y = value.y - this.height * 0.5; + this._array[0] = value.x - this._array[2] * 0.5; + this._array[1] = value.y - this._array[3] * 0.5; } /** @@ -204,12 +204,12 @@ export class Rect extends ValueType { * @zh 获取或设置矩形的 x 和 y 坐标。 */ get origin () { - return new Vec2(this.x, this.y); + return new Vec2(this._array[0], this._array[1]); } set origin (value) { - this.x = value.x; - this.y = value.y; + this._array[0] = value.x; + this._array[1] = value.y; } /** @@ -217,50 +217,70 @@ export class Rect extends ValueType { * @zh 获取或设置矩形的尺寸。 */ get size () { - return new Size(this.width, this.height); + return new Size(this._array[2], this._array[3]); } set size (value) { - this.width = value.width; - this.height = value.height; + this._array[2] = value.width; + this._array[3] = value.height; } - // compatibility with vector interfaces - set z (val) { this.width = val; } - get z () { return this.width; } - set w (val) { this.height = val; } - get w () { return this.height; } - /** * @en The minimum x value. * @zh 矩形最小点的 x 坐标。 */ - public declare x: number; + public get x (): number { + return this._array[0]; + } + public set x (val: number) { + this._array[0] = val; + } /** * @en The minimum y value. * @zh 矩形最小点的 y 坐标。 */ - public declare y: number; + public get y (): number { + return this._array[1]; + } + public set y (val: number) { + this._array[1] = val; + } /** * @en The width of the Rect. * @zh 矩形的宽度。 */ - public declare width: number; + public get width (): number { + return this._array[2]; + } + public set width (val: number) { + this._array[2] = val; + } + // compatibility with vector interfaces + public get z (): number { return this._array[2]; } + public set z (val: number) { this._array[2] = val; } /** * @en The height of the Rect. * @zh 矩形的高度。 */ - public declare height: number; + public get height (): number { + return this._array[3]; + } + public set height (val: number) { + this._array[3] = val; + } + // compatibility with vector interfaces + public get w (): number { return this._array[3]; } + public set w (val: number) { this._array[3] = val; } /** * @en Constructs a Rect from another one. * @zh 构造与指定矩形相等的矩形。 * @param other Specified Rect. */ - constructor (other: Rect); + constructor (x: Readonly | FloatArray); /** * @en Constructs a Rect with specified values. @@ -272,18 +292,26 @@ export class Rect extends ValueType { */ constructor (x?: number, y?: number, width?: number, height?: number); - constructor (x?: Rect | number, y?: number, width?: number, height?: number) { + constructor (x?: Readonly | number | FloatArray, y?: number, width?: number, height?: number) { super(); if (x && typeof x === 'object') { - this.y = x.y; - this.width = x.width; - this.height = x.height; - this.x = x.x; + if (ArrayBuffer.isView(x)) { + this._array = x; + this._array.fill(0); + } else { + const v = x.array; + this._array = MathBase.createFloatArray(4); + this._array[0] = v[0]; + this._array[1] = v[1]; + this._array[2] = v[2]; + this._array[3] = v[3]; + } } else { - this.x = x || 0; - this.y = y || 0; - this.width = width || 0; - this.height = height || 0; + this._array = MathBase.createFloatArray(4); + this._array[0] = x || 0; + this._array[1] = y || 0; + this._array[2] = width || 0; + this._array[3] = height || 0; } } @@ -292,7 +320,7 @@ export class Rect extends ValueType { * @zh 克隆当前矩形。 */ public clone () { - return new Rect(this.x, this.y, this.width, this.height); + return new Rect(this._array[0], this._array[1], this._array[2], this._array[3]); } /** @@ -301,7 +329,7 @@ export class Rect extends ValueType { * @param other Specified Rect. * @returns `this` */ - public set (other: Rect); + public set (other: Readonly); /** * @en Set the value of each component of the current Rect. @@ -314,17 +342,18 @@ export class Rect extends ValueType { */ public set (x?: number, y?: number, width?: number, height?: number); - public set (x?: Rect | number, y?: number, width?: number, height?: number) { + public set (x?: Readonly | number, y?: number, width?: number, height?: number) { if (x && typeof x === 'object') { - this.y = x.y; - this.width = x.width; - this.height = x.height; - this.x = x.x; + const v = x.array; + this._array[0] = v[0]; + this._array[1] = v[1]; + this._array[2] = v[2]; + this._array[3] = v[3]; } else { - this.x = x || 0; - this.y = y || 0; - this.width = width || 0; - this.height = height || 0; + this._array[0] = x || 0; + this._array[1] = y || 0; + this._array[2] = width || 0; + this._array[3] = height || 0; } return this; } @@ -335,11 +364,12 @@ export class Rect extends ValueType { * @param other Specified rectangles. * @returns Returns `true' when the minimum and maximum values of both rectangles are equal, respectively; otherwise, returns `false'. */ - public equals (other: Rect) { - return this.x === other.x - && this.y === other.y - && this.width === other.width - && this.height === other.height; + public equals (other: Readonly) { + const v = other.array; + return this._array[0] === v[0] + && this._array[1] === v[1] + && this._array[2] === v[2] + && this._array[3] === v[3]; } /** @@ -348,15 +378,16 @@ export class Rect extends ValueType { * @param to Target Rect. * @param ratio The interpolation coefficient.The range is [0,1]. */ - public lerp (to: Rect, ratio: number) { - const x = this.x; - const y = this.y; - const w = this.width; - const h = this.height; - this.x = x + (to.x - x) * ratio; - this.y = y + (to.y - y) * ratio; - this.width = w + (to.width - w) * ratio; - this.height = h + (to.height - h) * ratio; + public lerp (to: Readonly, ratio: number) { + const x = this._array[0]; + const y = this._array[1]; + const w = this._array[2]; + const h = this._array[3]; + const v = to.array; + this._array[0] = x + (v[0] - x) * ratio; + this._array[1] = y + (v[1] - y) * ratio; + this._array[2] = w + (v[2] - w) * ratio; + this._array[3] = h + (v[3] - h) * ratio; return this; } @@ -367,7 +398,7 @@ export class Rect extends ValueType { * @returns The information of the current rect in string */ public toString () { - return `(${this.x.toFixed(2)}, ${this.y.toFixed(2)}, ${this.width.toFixed(2)}, ${this.height.toFixed(2)})`; + return `(${this._array[0].toFixed(2)}, ${this._array[1].toFixed(2)}, ${this._array[2].toFixed(2)}, ${this._array[3].toFixed(2)})`; } /** @@ -376,12 +407,13 @@ export class Rect extends ValueType { * @param other Specified rectangles. * @returns If intersected, return `true', otherwise return `false'. */ - public intersects (other: Rect) { - const maxax = this.x + this.width; - const maxay = this.y + this.height; - const maxbx = other.x + other.width; - const maxby = other.y + other.height; - return !(maxax < other.x || maxbx < this.x || maxay < other.y || maxby < this.y); + public intersects (other: Readonly) { + const maxax = this._array[0] + this._array[2]; + const maxay = this._array[1] + this._array[3]; + const v = other.array; + const maxbx = v[0] + v[2]; + const maxby = v[1] + v[3]; + return !(maxax < v[0] || maxbx < this._array[0] || maxay < v[1] || maxby < this._array[1]); } /** @@ -390,11 +422,12 @@ export class Rect extends ValueType { * @param point Specified point. * @returns The specified point is included in the rectangle and returns `true', otherwise it returns `false'. */ - public contains (point: Vec2) { - return (this.x <= point.x - && this.x + this.width >= point.x - && this.y <= point.y - && this.y + this.height >= point.y); + public contains (point: Readonly) { + const v = point.array; + return (this._array[0] <= v[0] + && this._array[0] + this._array[2] >= v[0] + && this._array[1] <= v[1] + && this._array[1] + this._array[3] >= v[1]); } /** @@ -403,11 +436,12 @@ export class Rect extends ValueType { * @param other Specified rectangles. * @returns Returns `true' if all the points of the specified rectangle are included in the current rectangle, `false' otherwise. */ - public containsRect (other: Rect) { - return (this.x <= other.x - && this.x + this.width >= other.x + other.width - && this.y <= other.y - && this.y + this.height >= other.y + other.height); + public containsRect (other: Readonly) { + const v = other.array; + return (this._array[0] <= v[0] + && this._array[0] + this._array[2] >= v[0] + v[2] + && this._array[1] <= v[1] + && this._array[1] + this._array[3] >= v[1] + v[3]); } /** @@ -419,29 +453,30 @@ export class Rect extends ValueType { * 并将如此构成的新矩形。 * @param matrix The matrix4 */ - public transformMat4 (mat: Mat4) { - const ol = this.x; - const ob = this.y; - const or = ol + this.width; - const ot = ob + this.height; - const lbx = mat.m00 * ol + mat.m04 * ob + mat.m12; - const lby = mat.m01 * ol + mat.m05 * ob + mat.m13; - const rbx = mat.m00 * or + mat.m04 * ob + mat.m12; - const rby = mat.m01 * or + mat.m05 * ob + mat.m13; - const ltx = mat.m00 * ol + mat.m04 * ot + mat.m12; - const lty = mat.m01 * ol + mat.m05 * ot + mat.m13; - const rtx = mat.m00 * or + mat.m04 * ot + mat.m12; - const rty = mat.m01 * or + mat.m05 * ot + mat.m13; + public transformMat4 (mat: Readonly) { + const ol = this._array[0]; + const ob = this._array[1]; + const or = ol + this._array[2]; + const ot = ob + this._array[3]; + const v = mat.array; + const lbx = v[0] * ol + v[4] * ob + v[12]; + const lby = v[1] * ol + v[5] * ob + v[13]; + const rbx = v[0] * or + v[4] * ob + v[12]; + const rby = v[1] * or + v[5] * ob + v[13]; + const ltx = v[0] * ol + v[4] * ot + v[12]; + const lty = v[1] * ol + v[5] * ot + v[13]; + const rtx = v[0] * or + v[4] * ot + v[12]; + const rty = v[1] * or + v[5] * ot + v[13]; const minX = Math.min(lbx, rbx, ltx, rtx); const maxX = Math.max(lbx, rbx, ltx, rtx); const minY = Math.min(lby, rby, lty, rty); const maxY = Math.max(lby, rby, lty, rty); - this.x = minX; - this.y = minY; - this.width = maxX - minX; - this.height = maxY - minY; + this._array[0] = minX; + this._array[1] = minY; + this._array[2] = maxX - minX; + this._array[3] = maxY - minY; return this; } @@ -449,7 +484,7 @@ export class Rect extends ValueType { /** * 应用矩阵变换到当前矩形,并将结果输出到四个顶点上。 */ - public transformMat4ToPoints (mat: Mat4, out_lb: Vec2, out_lt: Vec2, out_rt: Vec2, out_rb: Vec2) { + public transformMat4ToPoints (mat: Readonly, out_lb: Vec2, out_lt: Vec2, out_rt: Vec2, out_rb: Vec2) { const ol = this.x; const ob = this.y; const or = ol + this.width; diff --git a/cocos/core/math/size.ts b/cocos/core/math/size.ts index 96252a29cf1..5d6a1be1d14 100644 --- a/cocos/core/math/size.ts +++ b/cocos/core/math/size.ts @@ -51,7 +51,7 @@ export class Size extends ValueType { * @param ratio The interpolation coefficient.The range is [0,1]. * @returns A vector consisting of linear interpolation of the width and height of the current size to the width and height of the target size at a specified interpolation ratio, respectively. */ - public static lerp (out: Out, from: Out, to: Out, ratio: number) { + public static lerp (out: Out, from: Readonly, to: Readonly, ratio: number) { out.width = from.width + (to.width - from.width) * ratio; out.height = from.height + (to.height - from.height) * ratio; return out; @@ -72,7 +72,7 @@ export class Size extends ValueType { * @zh 构造与指定尺寸相等的尺寸。 * @param other Specified Size. */ - constructor (other: Size); + constructor (other: Readonly); /** * @en Constructor a size with specified values. @@ -82,7 +82,7 @@ export class Size extends ValueType { */ constructor (width?: number, height?: number); - constructor (width?: Size | number, height?: number) { + constructor (width?: Readonly | number, height?: number) { super(); if (width && typeof width === 'object') { this.width = width.width; @@ -107,7 +107,7 @@ export class Size extends ValueType { * @param other Specified Size. * @returns `this` */ - public set (other: Size); + public set (other: Readonly); /** * @en Set the value of each component of the current `Size`. @@ -135,7 +135,7 @@ export class Size extends ValueType { * @param other Specified Size * @returns Returns `true' when both dimensions are equal in width and height; otherwise returns `false'. */ - public equals (other: Size) { + public equals (other: Readonly) { return this.width === other.width && this.height === other.height; } diff --git a/cocos/core/math/type-define.ts b/cocos/core/math/type-define.ts index 3aff0ec55ec..168f14de5b8 100644 --- a/cocos/core/math/type-define.ts +++ b/cocos/core/math/type-define.ts @@ -1,28 +1,28 @@ -/* - Copyright (c) 2020 Xiamen Yaji Software Co., Ltd. - - https://www.cocos.com/ - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated engine source code (the "Software"), a limited, - worldwide, royalty-free, non-assignable, revocable and non-exclusive license - to use Cocos Creator solely to develop games on your target platforms. You shall - not use Cocos Creator software for developing other software or tools that's - used for developing games. You are not granted to publish, distribute, - sublicense, and/or sell copies of Cocos Creator. - - The software or tools in this License Agreement are licensed, not sold. - Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - */ - +/* + Copyright (c) 2020 Xiamen Yaji Software Co., Ltd. + + https://www.cocos.com/ + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated engine source code (the "Software"), a limited, + worldwide, royalty-free, non-assignable, revocable and non-exclusive license + to use Cocos Creator solely to develop games on your target platforms. You shall + not use Cocos Creator software for developing other software or tools that's + used for developing games. You are not granted to publish, distribute, + sublicense, and/or sell copies of Cocos Creator. + + The software or tools in this License Agreement are licensed, not sold. + Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + */ + /** * @packageDocumentation * @module core/math @@ -89,3 +89,5 @@ export interface IVec4Like { z: number; w: number; } + +export type FloatArray = Float64Array | Float32Array; diff --git a/cocos/core/math/utils.ts b/cocos/core/math/utils.ts index 01e39075842..b4e468e3a2a 100644 --- a/cocos/core/math/utils.ts +++ b/cocos/core/math/utils.ts @@ -187,11 +187,11 @@ export function pseudoRandomRangeInt (seed: number, min: number, max: number) { */ export function nextPow2 (val: number) { --val; - val = (val >> 1) | val; - val = (val >> 2) | val; - val = (val >> 4) | val; - val = (val >> 8) | val; - val = (val >> 16) | val; + val |= (val >> 1); + val |= (val >> 2); + val |= (val >> 4); + val |= (val >> 8); + val |= (val >> 16); ++val; return val; } diff --git a/cocos/core/math/vec2.ts b/cocos/core/math/vec2.ts index 46917d45855..8b1780dc05b 100644 --- a/cocos/core/math/vec2.ts +++ b/cocos/core/math/vec2.ts @@ -30,19 +30,18 @@ */ import { CCClass } from '../data/class'; -import { ValueType } from '../value-types/value-type'; import { Mat4 } from './mat4'; -import { IMat3Like, IMat4Like, IVec2Like } from './type-define'; +import { IMat3Like, IMat4Like, IVec2Like, FloatArray } from './type-define'; import { clamp, EPSILON, random } from './utils'; - import { Vec3 } from './vec3'; import { legacyCC } from '../global-exports'; +import { MathBase } from './math-base'; /** * @en Representation of 2D vectors and points. * @zh 二维向量。 */ -export class Vec2 extends ValueType { +export class Vec2 extends MathBase { public static ZERO = Object.freeze(new Vec2(0, 0)); public static ONE = Object.freeze(new Vec2(1, 1)); public static NEG_ONE = Object.freeze(new Vec2(-1, -1)); @@ -53,7 +52,7 @@ export class Vec2 extends ValueType { * @en Obtains a clone of the given vector object * @zh 获得指定向量的拷贝 */ - public static clone (a: Out) { + public static clone (a: Readonly) { return new Vec2(a.x, a.y); } @@ -61,7 +60,7 @@ export class Vec2 extends ValueType { * @en Copy the target vector and save the results to out vector object * @zh 复制目标向量 */ - public static copy (out: Out, a: Out) { + public static copy (out: Out, a: Readonly) { out.x = a.x; out.y = a.y; return out; @@ -81,7 +80,7 @@ export class Vec2 extends ValueType { * @en Element-wise vector addition and save the results to out vector object * @zh 逐元素向量加法 */ - public static add (out: Out, a: Out, b: Out) { + public static add (out: Out, a: Readonly, b: Readonly) { out.x = a.x + b.x; out.y = a.y + b.y; return out; @@ -91,7 +90,7 @@ export class Vec2 extends ValueType { * @en Element-wise vector subtraction and save the results to out vector object * @zh 逐元素向量减法 */ - public static subtract (out: Out, a: Out, b: Out) { + public static subtract (out: Out, a: Readonly, b: Readonly) { out.x = a.x - b.x; out.y = a.y - b.y; return out; @@ -101,7 +100,7 @@ export class Vec2 extends ValueType { * @en Element-wise vector multiplication and save the results to out vector object * @zh 逐元素向量乘法 */ - public static multiply (out: Out, a: Out, b: Out) { + public static multiply (out: Out, a: Readonly, b: Readonly) { out.x = a.x * b.x; out.y = a.y * b.y; return out; @@ -111,7 +110,7 @@ export class Vec2 extends ValueType { * @en Element-wise vector division and save the results to out vector object * @zh 逐元素向量除法 */ - public static divide (out: Out, a: Out, b: Out) { + public static divide (out: Out, a: Readonly, b: Readonly) { out.x = a.x / b.x; out.y = a.y / b.y; return out; @@ -121,7 +120,7 @@ export class Vec2 extends ValueType { * @en Rounds up by elements of the vector and save the results to out vector object * @zh 逐元素向量向上取整 */ - public static ceil (out: Out, a: Out) { + public static ceil (out: Out, a: Readonly) { out.x = Math.ceil(a.x); out.y = Math.ceil(a.y); return out; @@ -131,7 +130,7 @@ export class Vec2 extends ValueType { * @en Element-wise rounds down of the current vector and save the results to the out vector * @zh 逐元素向量向下取整 */ - public static floor (out: Out, a: Out) { + public static floor (out: Out, a: Readonly) { out.x = Math.floor(a.x); out.y = Math.floor(a.y); return out; @@ -141,7 +140,7 @@ export class Vec2 extends ValueType { * @en Calculates element-wise minimum values and save to the out vector * @zh 逐元素向量最小值 */ - public static min (out: Out, a: Out, b: Out) { + public static min (out: Out, a: Readonly, b: Readonly) { out.x = Math.min(a.x, b.x); out.y = Math.min(a.y, b.y); return out; @@ -151,7 +150,7 @@ export class Vec2 extends ValueType { * @en Calculates element-wise maximum values and save to the out vector * @zh 逐元素向量最大值 */ - public static max (out: Out, a: Out, b: Out) { + public static max (out: Out, a: Readonly, b: Readonly) { out.x = Math.max(a.x, b.x); out.y = Math.max(a.y, b.y); return out; @@ -161,7 +160,7 @@ export class Vec2 extends ValueType { * @en Calculates element-wise round results and save to the out vector * @zh 逐元素向量四舍五入取整 */ - public static round (out: Out, a: Out) { + public static round (out: Out, a: Readonly) { out.x = Math.round(a.x); out.y = Math.round(a.y); return out; @@ -171,7 +170,7 @@ export class Vec2 extends ValueType { * @en Vector scalar multiplication and save the results to out vector object * @zh 向量标量乘法 */ - public static multiplyScalar (out: Out, a: Out, b: number) { + public static multiplyScalar (out: Out, a: Readonly, b: number) { out.x = a.x * b; out.y = a.y * b; return out; @@ -181,7 +180,7 @@ export class Vec2 extends ValueType { * @en Element-wise multiplication and addition with the equation: a + b * scale * @zh 逐元素向量乘加: A + B * scale */ - public static scaleAndAdd (out: Out, a: Out, b: Out, scale: number) { + public static scaleAndAdd (out: Out, a: Readonly, b: Readonly, scale: number) { out.x = a.x + (b.x * scale); out.y = a.y + (b.y * scale); return out; @@ -191,7 +190,7 @@ export class Vec2 extends ValueType { * @en Calculates the euclidean distance of two vectors * @zh 求两向量的欧氏距离 */ - public static distance (a: Out, b: Out) { + public static distance (a: Readonly, b: Readonly) { const x = b.x - a.x; const y = b.y - a.y; return Math.sqrt(x * x + y * y); @@ -201,7 +200,7 @@ export class Vec2 extends ValueType { * @en Calculates the squared euclidean distance of two vectors * @zh 求两向量的欧氏距离平方 */ - public static squaredDistance (a: Out, b: Out) { + public static squaredDistance (a: Readonly, b: Readonly) { const x = b.x - a.x; const y = b.y - a.y; return x * x + y * y; @@ -211,7 +210,7 @@ export class Vec2 extends ValueType { * @en Calculates the length of the vector * @zh 求向量长度 */ - public static len (a: Out) { + public static len (a: Readonly) { const x = a.x; const y = a.y; return Math.sqrt(x * x + y * y); @@ -221,7 +220,7 @@ export class Vec2 extends ValueType { * @en Calculates the squared length of the vector * @zh 求向量长度平方 */ - public static lengthSqr (a: Out) { + public static lengthSqr (a: Readonly) { const x = a.x; const y = a.y; return x * x + y * y; @@ -231,7 +230,7 @@ export class Vec2 extends ValueType { * @en Sets each element to its negative value * @zh 逐元素向量取负 */ - public static negate (out: Out, a: Out) { + public static negate (out: Out, a: Readonly) { out.x = -a.x; out.y = -a.y; return out; @@ -241,7 +240,7 @@ export class Vec2 extends ValueType { * @en Sets each element to its inverse value, zero value will become Infinity * @zh 逐元素向量取倒数,接近 0 时返回 Infinity */ - public static inverse (out: Out, a: Out) { + public static inverse (out: Out, a: Readonly) { out.x = 1.0 / a.x; out.y = 1.0 / a.y; return out; @@ -251,7 +250,7 @@ export class Vec2 extends ValueType { * @en Sets each element to its inverse value, zero value will remain zero * @zh 逐元素向量取倒数,接近 0 时返回 0 */ - public static inverseSafe (out: Out, a: Out) { + public static inverseSafe (out: Out, a: Readonly) { const x = a.x; const y = a.y; @@ -274,7 +273,7 @@ export class Vec2 extends ValueType { * @en Sets the normalized vector to the out vector * @zh 归一化向量 */ - public static normalize (out: Out, a: Vec2Like) { + public static normalize (out: Out, a: IVec2Like) { const x = a.x; const y = a.y; let len = x * x + y * y; @@ -290,7 +289,7 @@ export class Vec2 extends ValueType { * @en Calculates the dot product of the vector * @zh 向量点积(数量积) */ - public static dot (a: Out, b: Out) { + public static dot (a: Readonly, b: Readonly) { return a.x * b.x + a.y * b.y; } @@ -298,7 +297,7 @@ export class Vec2 extends ValueType { * @en Calculates the cross product of the vector * @zh 向量叉积(向量积),注意二维向量的叉积为与 Z 轴平行的三维向量 */ - public static cross (out: Vec3, a: Out, b: Out) { + public static cross (out: Vec3, a: Readonly, b: Readonly) { out.x = out.y = 0; out.z = a.x * b.y - a.y * b.x; return out; @@ -308,7 +307,7 @@ export class Vec2 extends ValueType { * @en Calculates the linear interpolation between two vectors with a given ratio * @zh 逐元素向量线性插值: A + t * (B - A) */ - public static lerp (out: Out, a: Out, b: Out, t: number) { + public static lerp (out: Out, a: Readonly, b: Readonly, t: number) { const x = a.x; const y = a.y; out.x = x + t * (b.x - x); @@ -333,7 +332,7 @@ export class Vec2 extends ValueType { * @en Vector and third order matrix multiplication, will complete the vector with a third value as one * @zh 向量与三维矩阵乘法,默认向量第三位为 1。 */ - public static transformMat3 (out: Out, a: Out, m: IMat3Like) { + public static transformMat3 (out: Out, a: Readonly, m: Readonly) { const x = a.x; const y = a.y; out.x = m.m00 * x + m.m03 * y + m.m06; @@ -345,7 +344,7 @@ export class Vec2 extends ValueType { * @en Vector and third order matrix multiplication, will complete the vector with a third and a fourth element as one * @zh 向量与四维矩阵乘法,默认向量第三位为 0,第四位为 1。 */ - public static transformMat4 (out: Out, a: Out, m: IMat4Like) { + public static transformMat4 (out: Out, a: Readonly, m: Readonly) { const x = a.x; const y = a.y; out.x = m.m00 * x + m.m04 * y + m.m12; @@ -357,7 +356,7 @@ export class Vec2 extends ValueType { * @en Gets the string representation of the given vector * @zh 返回向量的字符串表示 */ - public static str (a: Out) { + public static str (a: Readonly) { return `Vec2(${a.x}, ${a.y})`; } @@ -387,7 +386,7 @@ export class Vec2 extends ValueType { * @en Check the equality of the two given vectors * @zh 向量等价判断 */ - public static strictEquals (a: Out, b: Out) { + public static strictEquals (a: Readonly, b: Readonly) { return a.x === b.x && a.y === b.y; } @@ -395,7 +394,7 @@ export class Vec2 extends ValueType { * @en Check whether the two given vectors are approximately equivalent * @zh 排除浮点数误差的向量近似等价判断 */ - public static equals (a: Out, b: Out, epsilon = EPSILON) { + public static equals (a: Readonly, b: Readonly, epsilon = EPSILON) { return ( Math.abs(a.x - b.x) <= epsilon * Math.max(1.0, Math.abs(a.x), Math.abs(b.x)) @@ -408,7 +407,7 @@ export class Vec2 extends ValueType { * @en Calculates the radian angle between two vectors * @zh 求两向量夹角弧度 */ - public static angle (a: Out, b: Out) { + public static angle (a: Readonly, b: Readonly) { Vec2.normalize(v2_1, a); Vec2.normalize(v2_2, b); const cosine = Vec2.dot(v2_1, v2_2); @@ -425,26 +424,43 @@ export class Vec2 extends ValueType { * @en x component. * @zh x 分量。 */ - public declare x: number; + public get x (): number { + return this._array[0]; + } + public set x (x: number) { + this._array[0] = x; + } /** - * @en y component. + * @en The y value of the vector. * @zh y 分量。 */ - public declare y: number; + public get y (): number { + return this._array[1]; + } + public set y (y: number) { + this._array[1] = y; + } - constructor (other: Vec2); + constructor (x: Vec2 | FloatArray); constructor (x?: number, y?: number); - constructor (x?: number | Vec2, y?: number) { + constructor (x?: number | Vec2 | FloatArray, y?: number) { super(); if (x && typeof x === 'object') { - this.x = x.x; - this.y = x.y; + if (ArrayBuffer.isView(x)) { + this._array = x; + } else { + const v = x.array; + this._array = MathBase.createFloatArray(2); + this._array[0] = v[0]; + this._array[1] = v[1]; + } } else { - this.x = x || 0; - this.y = y || 0; + this._array = MathBase.createFloatArray(2); + this._array[0] = x || 0; + this._array[1] = y || 0; } } @@ -453,7 +469,7 @@ export class Vec2 extends ValueType { * @zh 克隆当前向量。 */ public clone () { - return new Vec2(this.x, this.y); + return new Vec2(this._array[0], this._array[1]); } /** @@ -462,7 +478,7 @@ export class Vec2 extends ValueType { * @param other Specified vector * @return `this` */ - public set (other: Vec2); + public set (other: Readonly); /** * @en Set the value of each component of the current vector. @@ -473,13 +489,14 @@ export class Vec2 extends ValueType { */ public set (x?: number, y?: number); - public set (x?: number | Vec2, y?: number) { + public set (x?: number | Readonly, y?: number) { if (x && typeof x === 'object') { - this.x = x.x; - this.y = x.y; + const v = x.array; + this._array[0] = v[0]; + this._array[1] = v[1]; } else { - this.x = x || 0; - this.y = y || 0; + this._array[0] = x || 0; + this._array[1] = y || 0; } return this; } @@ -491,12 +508,13 @@ export class Vec2 extends ValueType { * @param epsilon The error allowed. It`s should be a non-negative number. * @return Returns `true` when the components of both vectors are equal within the specified range of error; otherwise it returns `false`. */ - public equals (other: Vec2, epsilon = EPSILON) { + public equals (other: Readonly, epsilon = EPSILON) { + const v = other.array; return ( - Math.abs(this.x - other.x) - <= epsilon * Math.max(1.0, Math.abs(this.x), Math.abs(other.x)) - && Math.abs(this.y - other.y) - <= epsilon * Math.max(1.0, Math.abs(this.y), Math.abs(other.y)) + Math.abs(this._array[0] - v[0]) + <= epsilon * Math.max(1.0, Math.abs(this._array[0]), Math.abs(v[0])) + && Math.abs(this._array[1] - v[1]) + <= epsilon * Math.max(1.0, Math.abs(this._array[1]), Math.abs(v[1])) ); } @@ -510,10 +528,10 @@ export class Vec2 extends ValueType { */ public equals2f (x: number, y: number, epsilon = EPSILON) { return ( - Math.abs(this.x - x) - <= epsilon * Math.max(1.0, Math.abs(this.x), Math.abs(x)) - && Math.abs(this.y - y) - <= epsilon * Math.max(1.0, Math.abs(this.y), Math.abs(y)) + Math.abs(this._array[0] - x) + <= epsilon * Math.max(1.0, Math.abs(this._array[0]), Math.abs(x)) + && Math.abs(this._array[1] - y) + <= epsilon * Math.max(1.0, Math.abs(this._array[1]), Math.abs(y)) ); } @@ -523,8 +541,9 @@ export class Vec2 extends ValueType { * @param other specified vector * @return Returns `true` when the components of both vectors are equal within the specified range of error; otherwise it returns `false`. */ - public strictEquals (other: Vec2) { - return other && this.x === other.x && this.y === other.y; + public strictEquals (other: Readonly) { + const v = other.array; + return other && this._array[0] === v[0] && this._array[1] === v[1]; } /** @@ -535,7 +554,7 @@ export class Vec2 extends ValueType { * @return Returns `true` when the components of both vectors are equal within the specified range of error; otherwise it returns `false`. */ public strictEquals2f (x: number, y: number) { - return this.x === x && this.y === y; + return this._array[0] === x && this._array[1] === y; } /** @@ -544,7 +563,7 @@ export class Vec2 extends ValueType { * @returns The string with vector information */ public toString () { - return `(${this.x.toFixed(2)}, ${this.y.toFixed(2)})`; + return `(${this._array[0].toFixed(2)}, ${this._array[1].toFixed(2)})`; } /** @@ -554,10 +573,11 @@ export class Vec2 extends ValueType { * @param ratio The interpolation coefficient.The range is [0,1]. */ public lerp (to: Vec2, ratio: number) { - const x = this.x; - const y = this.y; - this.x = x + ratio * (to.x - x); - this.y = y + ratio * (to.y - y); + const x = this._array[0]; + const y = this._array[1]; + const v = to.array; + this._array[0] = x + ratio * (v[0] - x); + this._array[1] = y + ratio * (v[1] - y); return this; } @@ -569,8 +589,10 @@ export class Vec2 extends ValueType { * @return `this` */ public clampf (minInclusive: Vec2, maxInclusive: Vec2) { - this.x = clamp(this.x, minInclusive.x, maxInclusive.x); - this.y = clamp(this.y, minInclusive.y, maxInclusive.y); + const min = minInclusive.array; + const max = maxInclusive.array; + this._array[0] = clamp(this._array[0], min[0], max[0]); + this._array[1] = clamp(this._array[1], min[1], max[1]); return this; } @@ -579,9 +601,10 @@ export class Vec2 extends ValueType { * @zh 向量加法。将当前向量与指定向量的相加 * @param other specified vector */ - public add (other: Vec2) { - this.x += other.x; - this.y += other.y; + public add (other: Readonly) { + const v = other.array; + this._array[0] += v[0]; + this._array[1] += v[1]; return this; } @@ -592,8 +615,8 @@ export class Vec2 extends ValueType { * @param y The y value of specified vector */ public add2f (x: number, y: number) { - this.x += x; - this.y += y; + this._array[0] += x; + this._array[1] += y; return this; } @@ -602,9 +625,10 @@ export class Vec2 extends ValueType { * @zh 向量减法。将当前向量减去指定向量 * @param other specified vector */ - public subtract (other: Vec2) { - this.x -= other.x; - this.y -= other.y; + public subtract (other: Readonly) { + const v = other.array; + this._array[0] -= v[0]; + this._array[1] -= v[1]; return this; } @@ -615,8 +639,8 @@ export class Vec2 extends ValueType { * @param y The y value of specified vector */ public subtract2f (x: number, y: number) { - this.x -= x; - this.y -= y; + this._array[0] -= x; + this._array[1] -= y; return this; } @@ -627,8 +651,8 @@ export class Vec2 extends ValueType { */ public multiplyScalar (scalar: number) { if (typeof scalar === 'object') { console.warn('should use Vec2.multiply for vector * vector operation'); } - this.x *= scalar; - this.y *= scalar; + this._array[0] *= scalar; + this._array[1] *= scalar; return this; } @@ -637,10 +661,11 @@ export class Vec2 extends ValueType { * @zh 向量乘法。将当前向量乘以与指定向量的结果赋值给当前向量。 * @param other specified vector */ - public multiply (other: Vec2) { + public multiply (other: Readonly) { if (typeof other !== 'object') { console.warn('should use Vec2.scale for vector * scalar operation'); } - this.x *= other.x; - this.y *= other.y; + const v = other.array; + this._array[0] *= v[0]; + this._array[1] *= v[1]; return this; } @@ -651,8 +676,8 @@ export class Vec2 extends ValueType { * @param y The y value of specified vector */ public multiply2f (x: number, y: number) { - this.x *= x; - this.y *= y; + this._array[0] *= x; + this._array[1] *= y; return this; } @@ -661,9 +686,10 @@ export class Vec2 extends ValueType { * @zh 向量逐元素相除。将当前向量与指定分量的向量相除的结果赋值给当前向量。 * @param other specified vector */ - public divide (other: Vec2) { - this.x /= other.x; - this.y /= other.y; + public divide (other: Readonly) { + const v = other.array; + this._array[0] /= v[0]; + this._array[1] /= v[1]; return this; } @@ -674,8 +700,8 @@ export class Vec2 extends ValueType { * @param y The y value of specified vector */ public divide2f (x: number, y: number) { - this.x /= x; - this.y /= y; + this._array[0] /= x; + this._array[1] /= y; return this; } @@ -684,8 +710,8 @@ export class Vec2 extends ValueType { * @zh 将当前向量的各个分量取反 */ public negative () { - this.x = -this.x; - this.y = -this.y; + this._array[0] = -this._array[0]; + this._array[1] = -this._array[1]; return this; } @@ -695,8 +721,9 @@ export class Vec2 extends ValueType { * @param other specified vector * @return The result of calculates the dot product with another vector */ - public dot (other: Vec2) { - return this.x * other.x + this.y * other.y; + public dot (other: Readonly) { + const v = other.array; + return this._array[0] * v[0] + this._array[1] * v[1]; } /** @@ -705,8 +732,9 @@ export class Vec2 extends ValueType { * @param other specified vector * @return `out` */ - public cross (other: Vec2) { - return this.x * other.y - this.y * other.x; + public cross (other: Readonly) { + const v = other.array; + return this._array[0] * v[1] - this._array[1] * v[0]; } /** @@ -715,7 +743,7 @@ export class Vec2 extends ValueType { * @return Length of vector */ public length () { - return Math.sqrt(this.x * this.x + this.y * this.y); + return Math.sqrt(this._array[0] * this._array[0] + this._array[1] * this._array[1]); } /** @@ -724,7 +752,7 @@ export class Vec2 extends ValueType { * @return the squared length of this vector */ public lengthSqr () { - return this.x * this.x + this.y * this.y; + return this._array[0] * this._array[0] + this._array[1] * this._array[1]; } /** @@ -732,13 +760,13 @@ export class Vec2 extends ValueType { * @zh 将当前向量归一化。 */ public normalize () { - const x = this.x; - const y = this.y; + const x = this._array[0]; + const y = this._array[1]; let len = x * x + y * y; if (len > 0) { len = 1 / Math.sqrt(len); - this.x *= len; - this.y *= len; + this._array[0] *= len; + this._array[1] *= len; } return this; } @@ -749,7 +777,7 @@ export class Vec2 extends ValueType { * @param other specified vector * @return The angle between the current vector and the specified vector (in radians); if there are zero vectors in the current vector and the specified vector, 0 is returned. */ - public angle (other: Vec2) { + public angle (other: Readonly) { const magSqr1 = this.lengthSqr(); const magSqr2 = other.lengthSqr(); @@ -771,7 +799,7 @@ export class Vec2 extends ValueType { * @param other specified vector * @return The signed angle between the current vector and the specified vector (in radians); if there is a zero vector in the current vector and the specified vector, 0 is returned. */ - public signAngle (other: Vec2) { + public signAngle (other: Readonly) { const angle = this.angle(other); return this.cross(other) < 0 ? -angle : angle; } @@ -782,13 +810,13 @@ export class Vec2 extends ValueType { * @param radians radius of rotation */ public rotate (radians: number) { - const x = this.x; - const y = this.y; + const x = this._array[0]; + const y = this._array[1]; const sin = Math.sin(radians); const cos = Math.cos(radians); - this.x = cos * x - sin * y; - this.y = sin * x + cos * y; + this._array[0] = cos * x - sin * y; + this._array[1] = sin * x + cos * y; return this; } @@ -797,10 +825,11 @@ export class Vec2 extends ValueType { * @zh 计算当前向量在指定向量上的投影向量。 * @param other specified vector */ - public project (other: Vec2) { + public project (other: Readonly) { + const v = other.array; const scalar = this.dot(other) / other.dot(other); - this.x = other.x * scalar; - this.y = other.y * scalar; + this._array[0] = v[0] * scalar; + this._array[1] = v[1] * scalar; return this; } @@ -811,10 +840,11 @@ export class Vec2 extends ValueType { * @param matrix matrix to transform with */ public transformMat4 (matrix: Mat4) { - const x = this.x; - const y = this.y; - this.x = matrix.m00 * x + matrix.m04 * y + matrix.m12; - this.y = matrix.m01 * x + matrix.m05 * y + matrix.m13; + const x = this._array[0]; + const y = this._array[1]; + const v = matrix.array; + this._array[0] = v[0] * x + v[4] * y + v[12]; + this._array[1] = v[1] * x + v[5] * y + v[13]; return this; } } diff --git a/cocos/core/math/vec3.ts b/cocos/core/math/vec3.ts index e9c12055741..78b7f06b508 100644 --- a/cocos/core/math/vec3.ts +++ b/cocos/core/math/vec3.ts @@ -30,17 +30,17 @@ */ import { CCClass } from '../data/class'; -import { ValueType } from '../value-types/value-type'; import { Mat4 } from './mat4'; -import { IMat3Like, IMat4Like, IQuatLike, IVec3Like } from './type-define'; +import { IMat3Like, IMat4Like, IQuatLike, IVec3Like, FloatArray } from './type-define'; import { clamp, EPSILON, random } from './utils'; import { legacyCC } from '../global-exports'; +import { MathBase } from './math-base'; /** * @en Representation of 3D vectors and points. * @zh 三维向量。 */ -export class Vec3 extends ValueType { +export class Vec3 extends MathBase { public static UNIT_X = Object.freeze(new Vec3(1, 0, 0)); public static UNIT_Y = Object.freeze(new Vec3(0, 1, 0)); public static UNIT_Z = Object.freeze(new Vec3(0, 0, 1)); @@ -66,7 +66,7 @@ export class Vec3 extends ValueType { * @en Obtains a clone of the given vector object * @zh 获得指定向量的拷贝 */ - public static clone (a: Out) { + public static clone (a: Readonly) { return new Vec3(a.x, a.y, a.z); } @@ -74,7 +74,7 @@ export class Vec3 extends ValueType { * @en Copy the target vector and save the results to out vector object * @zh 复制目标向量 */ - public static copy (out: Out, a: Vec3Like) { + public static copy (out: Out, a: Readonly) { out.x = a.x; out.y = a.y; out.z = a.z; @@ -96,7 +96,7 @@ export class Vec3 extends ValueType { * @en Element-wise vector addition and save the results to out vector object * @zh 逐元素向量加法 */ - public static add (out: Out, a: IVec3Like, b: IVec3Like) { + public static add (out: Out, a: Readonly, b: Readonly) { out.x = a.x + b.x; out.y = a.y + b.y; out.z = a.z + b.z; @@ -107,7 +107,7 @@ export class Vec3 extends ValueType { * @en Element-wise vector subtraction and save the results to out vector object * @zh 逐元素向量减法 */ - public static subtract (out: Out, a: IVec3Like, b: IVec3Like) { + public static subtract (out: Out, a: Readonly, b: Readonly) { out.x = a.x - b.x; out.y = a.y - b.y; out.z = a.z - b.z; @@ -118,7 +118,7 @@ export class Vec3 extends ValueType { * @en Element-wise vector multiplication and save the results to out vector object * @zh 逐元素向量乘法 (分量积) */ - public static multiply (out: Out, a: IVec3Like, b: IVec3Like) { + public static multiply (out: Out, a: Readonly, b: Readonly) { out.x = a.x * b.x; out.y = a.y * b.y; out.z = a.z * b.z; @@ -129,7 +129,7 @@ export class Vec3 extends ValueType { * @en Element-wise vector division and save the results to out vector object * @zh 逐元素向量除法 */ - public static divide (out: Out, a: IVec3Like, b: IVec3Like) { + public static divide (out: Out, a: Readonly, b: Readonly) { out.x = a.x / b.x; out.y = a.y / b.y; out.z = a.z / b.z; @@ -140,7 +140,7 @@ export class Vec3 extends ValueType { * @en Rounds up by elements of the vector and save the results to out vector object * @zh 逐元素向量向上取整 */ - public static ceil (out: Out, a: IVec3Like) { + public static ceil (out: Out, a: Readonly) { out.x = Math.ceil(a.x); out.y = Math.ceil(a.y); out.z = Math.ceil(a.z); @@ -151,7 +151,7 @@ export class Vec3 extends ValueType { * @en Element-wise rounds down of the current vector and save the results to the out vector * @zh 逐元素向量向下取整 */ - public static floor (out: Out, a: IVec3Like) { + public static floor (out: Out, a: Readonly) { out.x = Math.floor(a.x); out.y = Math.floor(a.y); out.z = Math.floor(a.z); @@ -162,7 +162,7 @@ export class Vec3 extends ValueType { * @en Calculates element-wise minimum values and save to the out vector * @zh 逐元素向量最小值 */ - public static min (out: Out, a: IVec3Like, b: IVec3Like) { + public static min (out: Out, a: Readonly, b: Readonly) { out.x = Math.min(a.x, b.x); out.y = Math.min(a.y, b.y); out.z = Math.min(a.z, b.z); @@ -173,7 +173,7 @@ export class Vec3 extends ValueType { * @en Calculates element-wise maximum values and save to the out vector * @zh 逐元素向量最大值 */ - public static max (out: Out, a: IVec3Like, b: IVec3Like) { + public static max (out: Out, a: Readonly, b: Readonly) { out.x = Math.max(a.x, b.x); out.y = Math.max(a.y, b.y); out.z = Math.max(a.z, b.z); @@ -184,7 +184,7 @@ export class Vec3 extends ValueType { * @en Calculates element-wise round results and save to the out vector * @zh 逐元素向量四舍五入取整 */ - public static round (out: Out, a: IVec3Like) { + public static round (out: Out, a: Readonly) { out.x = Math.round(a.x); out.y = Math.round(a.y); out.z = Math.round(a.z); @@ -195,7 +195,7 @@ export class Vec3 extends ValueType { * @en Vector scalar multiplication and save the results to out vector object * @zh 向量标量乘法 */ - public static multiplyScalar (out: Out, a: Vec3Like, b: number) { + public static multiplyScalar (out: Out, a: Readonly, b: number) { out.x = a.x * b; out.y = a.y * b; out.z = a.z * b; @@ -206,7 +206,7 @@ export class Vec3 extends ValueType { * @en Element-wise multiplication and addition with the equation: a + b * scale * @zh 逐元素向量乘加: A + B * scale */ - public static scaleAndAdd (out: Out, a: IVec3Like, b: IVec3Like, scale: number) { + public static scaleAndAdd (out: Out, a: Readonly, b: Readonly, scale: number) { out.x = a.x + b.x * scale; out.y = a.y + b.y * scale; out.z = a.z + b.z * scale; @@ -217,7 +217,7 @@ export class Vec3 extends ValueType { * @en Calculates the euclidean distance of two vectors * @zh 求两向量的欧氏距离 */ - public static distance (a: IVec3Like, b: IVec3Like) { + public static distance (a: Readonly, b: Readonly) { const x = b.x - a.x; const y = b.y - a.y; const z = b.z - a.z; @@ -228,7 +228,7 @@ export class Vec3 extends ValueType { * @en Calculates the squared euclidean distance of two vectors * @zh 求两向量的欧氏距离平方 */ - public static squaredDistance (a: IVec3Like, b: IVec3Like) { + public static squaredDistance (a: Readonly, b: Readonly) { const x = b.x - a.x; const y = b.y - a.y; const z = b.z - a.z; @@ -239,7 +239,7 @@ export class Vec3 extends ValueType { * @en Calculates the length of the vector * @zh 求向量长度 */ - public static len (a: IVec3Like) { + public static len (a: Readonly) { const x = a.x; const y = a.y; const z = a.z; @@ -250,7 +250,7 @@ export class Vec3 extends ValueType { * @en Calculates the squared length of the vector * @zh 求向量长度平方 */ - public static lengthSqr (a: IVec3Like) { + public static lengthSqr (a: Readonly) { const x = a.x; const y = a.y; const z = a.z; @@ -261,7 +261,7 @@ export class Vec3 extends ValueType { * @en Sets each element to its negative value * @zh 逐元素向量取负 */ - public static negate (out: Out, a: IVec3Like) { + public static negate (out: Out, a: Readonly) { out.x = -a.x; out.y = -a.y; out.z = -a.z; @@ -272,7 +272,7 @@ export class Vec3 extends ValueType { * @en Sets each element to its inverse value, zero value will become Infinity * @zh 逐元素向量取倒数,接近 0 时返回 Infinity */ - public static invert (out: Out, a: IVec3Like) { + public static invert (out: Out, a: Readonly) { out.x = 1.0 / a.x; out.y = 1.0 / a.y; out.z = 1.0 / a.z; @@ -283,7 +283,7 @@ export class Vec3 extends ValueType { * @en Sets each element to its inverse value, zero value will remain zero * @zh 逐元素向量取倒数,接近 0 时返回 0 */ - public static invertSafe (out: Out, a: IVec3Like) { + public static invertSafe (out: Out, a: Readonly) { const x = a.x; const y = a.y; const z = a.z; @@ -313,7 +313,7 @@ export class Vec3 extends ValueType { * @en Sets the normalized vector to the out vector * @zh 归一化向量 */ - public static normalize (out: Out, a: IVec3Like) { + public static normalize (out: Out, a: Readonly) { const x = a.x; const y = a.y; const z = a.z; @@ -332,7 +332,7 @@ export class Vec3 extends ValueType { * @en Calculates the dot product of the vector * @zh 向量点积(数量积) */ - public static dot (a: Out, b: IVec3Like) { + public static dot (a: Readonly, b: Readonly) { return a.x * b.x + a.y * b.y + a.z * b.z; } @@ -340,7 +340,7 @@ export class Vec3 extends ValueType { * @en Calculates the cross product of the vector * @zh 向量叉积(向量积) */ - public static cross (out: Out, a: IVec3Like, b: IVec3Like) { + public static cross (out: Out, a: Readonly, b: Readonly) { const { x: ax, y: ay, z: az } = a; const { x: bx, y: by, z: bz } = b; out.x = ay * bz - az * by; @@ -353,7 +353,7 @@ export class Vec3 extends ValueType { * @en Calculates the linear interpolation between two vectors with a given ratio * @zh 逐元素向量线性插值: A + t * (B - A) */ - public static lerp (out: Out, a: IVec3Like, b: IVec3Like, t: number) { + public static lerp (out: Out, a: Readonly, b: Readonly, t: number) { out.x = a.x + t * (b.x - a.x); out.y = a.y + t * (b.y - a.y); out.z = a.z + t * (b.z - a.z); @@ -382,7 +382,7 @@ export class Vec3 extends ValueType { * @en Vector and fourth order matrix multiplication, will complete the vector with a fourth value as one * @zh 向量与四维矩阵乘法,默认向量第四位为 1。 */ - public static transformMat4 (out: Out, a: IVec3Like, m: IMat4Like) { + public static transformMat4 (out: Out, a: Readonly, m: IMat4Like) { const x = a.x; const y = a.y; const z = a.z; @@ -398,7 +398,7 @@ export class Vec3 extends ValueType { * @en Vector and fourth order matrix multiplication, will complete the vector with a fourth element as one * @zh 向量与四维矩阵乘法,默认向量第四位为 0。 */ - public static transformMat4Normal (out: Out, a: IVec3Like, m: IMat4Like) { + public static transformMat4Normal (out: Out, a: Readonly, m: IMat4Like) { const x = a.x; const y = a.y; const z = a.z; @@ -414,7 +414,7 @@ export class Vec3 extends ValueType { * @en Vector and third order matrix multiplication * @zh 向量与三维矩阵乘法 */ - public static transformMat3 (out: Out, a: IVec3Like, m: IMat3Like) { + public static transformMat3 (out: Out, a: Readonly, m: IMat3Like) { const x = a.x; const y = a.y; const z = a.z; @@ -442,7 +442,7 @@ export class Vec3 extends ValueType { * @en Vector quaternion multiplication * @zh 向量四元数乘法 */ - public static transformQuat (out: Out, a: IVec3Like, q: IQuatLike) { + public static transformQuat (out: Out, a: Readonly, q: IQuatLike) { // benchmarks: http://jsperf.com/quaternion-transform-Vec3-implementations // calculate quat * vec @@ -462,7 +462,7 @@ export class Vec3 extends ValueType { * @en Transforms the current vector with given scale, rotation and translation in order * @zh 以缩放 -> 旋转 -> 平移顺序变换向量 */ - public static transformRTS (out: Out, a: IVec3Like, r: IQuatLike, t: IVec3Like, s: IVec3Like) { + public static transformRTS (out: Out, a: Readonly, r: IQuatLike, t: IVec3Like, s: IVec3Like) { const x = a.x * s.x; const y = a.y * s.y; const z = a.z * s.z; @@ -480,7 +480,7 @@ export class Vec3 extends ValueType { * @en Transforms the current vector with given scale, rotation and translation in reverse order * @zh 以平移 -> 旋转 -> 缩放顺序逆变换向量 */ - public static transformInverseRTS (out: Out, a: IVec3Like, r: IQuatLike, t: IVec3Like, s: IVec3Like) { + public static transformInverseRTS (out: Out, a: Readonly, r: IQuatLike, t: IVec3Like, s: IVec3Like) { const x = a.x - t.x; const y = a.y - t.y; const z = a.z - t.z; @@ -607,7 +607,7 @@ export class Vec3 extends ValueType { * @en Check the equality of the two given vectors * @zh 向量等价判断 */ - public static strictEquals (a: IVec3Like, b: IVec3Like) { + public static strictEquals (a: Readonly, b: Readonly) { return a.x === b.x && a.y === b.y && a.z === b.z; } @@ -615,7 +615,7 @@ export class Vec3 extends ValueType { * @en Check whether the two given vectors are approximately equivalent * @zh 排除浮点数误差的向量近似等价判断 */ - public static equals (a: IVec3Like, b: IVec3Like, epsilon = EPSILON) { + public static equals (a: Readonly, b: Readonly, epsilon = EPSILON) { const { x: a0, y: a1, z: a2 } = a; const { x: b0, y: b1, z: b2 } = b; return ( @@ -632,7 +632,7 @@ export class Vec3 extends ValueType { * @en Calculates the radian angle between two vectors * @zh 求两向量夹角弧度 */ - public static angle (a: IVec3Like, b: IVec3Like) { + public static angle (a: Readonly, b: Readonly) { Vec3.normalize(v3_1, a); Vec3.normalize(v3_2, b); const cosine = Vec3.dot(v3_1, v3_2); @@ -651,7 +651,7 @@ export class Vec3 extends ValueType { * @param a projection vector * @param n the normal line of specified plane */ - public static projectOnPlane (out: Out, a: IVec3Like, n: IVec3Like) { + public static projectOnPlane (out: Out, a: Readonly, n: IVec3Like) { return Vec3.subtract(out, a, Vec3.project(out, a, n)); } @@ -661,7 +661,7 @@ export class Vec3 extends ValueType { * @param a projection vector * @param n target vector */ - public static project (out: Out, a: IVec3Like, b: IVec3Like) { + public static project (out: Out, a: Readonly, b: Readonly) { const sqrLen = Vec3.lengthSqr(b); if (sqrLen < 0.000001) { return Vec3.set(out, 0, 0, 0); @@ -674,34 +674,57 @@ export class Vec3 extends ValueType { * @en x component. * @zh x 分量。 */ - public declare x: number; + public get x (): number { + return this._array[0]; + } + public set x (x: number) { + this._array[0] = x; + } /** * @en y component. * @zh y 分量。 */ - public declare y: number; + public get y (): number { + return this._array[1]; + } + public set y (y: number) { + this._array[1] = y; + } /** * @en z component. * @zh z 分量。 */ - public declare z: number; + public get z (): number { + return this._array[2]; + } + public set z (z: number) { + this._array[2] = z; + } - constructor (v: Vec3); + constructor (x: Vec3 | FloatArray); constructor (x?: number, y?: number, z?: number); - constructor (x?: number | Vec3, y?: number, z?: number) { + constructor (x?: number | Vec3 | FloatArray, y?: number, z?: number) { super(); if (x && typeof x === 'object') { - this.x = x.x; - this.y = x.y; - this.z = x.z; + if (ArrayBuffer.isView(x)) { + this._array = x; + this._array.fill(0); + } else { + const v = x.array; + this._array = MathBase.createFloatArray(3); + this._array[0] = v[0]; + this._array[1] = v[1]; + this._array[2] = v[2]; + } } else { - this.x = x || 0; - this.y = y || 0; - this.z = z || 0; + this._array = MathBase.createFloatArray(3); + this._array[0] = x || 0; + this._array[1] = y || 0; + this._array[2] = z || 0; } } @@ -710,7 +733,7 @@ export class Vec3 extends ValueType { * @zh 克隆当前向量。 */ public clone () { - return new Vec3(this.x, this.y, this.z); + return new Vec3(this._array[0], this._array[1], this._array[2]); } /** @@ -719,7 +742,7 @@ export class Vec3 extends ValueType { * @param other Specified vector * @returns `this` */ - public set (other: Vec3); + public set (other: Readonly); /** * @en Set the value of each component of the current vector. @@ -731,15 +754,16 @@ export class Vec3 extends ValueType { */ public set (x?: number, y?: number, z?: number); - public set (x?: number | Vec3, y?: number, z?: number) { + public set (x?: number | Readonly, y?: number, z?: number) { if (x && typeof x === 'object') { - this.x = x.x; - this.y = x.y; - this.z = x.z; + const v = x.array; + this._array[0] = v[0]; + this._array[1] = v[1]; + this._array[2] = v[2]; } else { - this.x = x || 0; - this.y = y || 0; - this.z = z || 0; + this._array[0] = x || 0; + this._array[1] = y || 0; + this._array[2] = z || 0; } return this; } @@ -751,14 +775,15 @@ export class Vec3 extends ValueType { * @param epsilon The error allowed. It`s should be a non-negative number. * @returns Returns `true` when the components of both vectors are equal within the specified range of error; otherwise it returns `false`. */ - public equals (other: Vec3, epsilon = EPSILON) { + public equals (other: Readonly, epsilon = EPSILON) { + const v = other.array; return ( - Math.abs(this.x - other.x) - <= epsilon * Math.max(1.0, Math.abs(this.x), Math.abs(other.x)) - && Math.abs(this.y - other.y) - <= epsilon * Math.max(1.0, Math.abs(this.y), Math.abs(other.y)) - && Math.abs(this.z - other.z) - <= epsilon * Math.max(1.0, Math.abs(this.z), Math.abs(other.z)) + Math.abs(this._array[0] - v[0]) + <= epsilon * Math.max(1.0, Math.abs(this._array[0]), Math.abs(v[0])) + && Math.abs(this._array[1] - v[1]) + <= epsilon * Math.max(1.0, Math.abs(this._array[1]), Math.abs(v[1])) + && Math.abs(this._array[2] - v[2]) + <= epsilon * Math.max(1.0, Math.abs(this._array[2]), Math.abs(v[2])) ); } @@ -773,12 +798,12 @@ export class Vec3 extends ValueType { */ public equals3f (x: number, y: number, z: number, epsilon = EPSILON) { return ( - Math.abs(this.x - x) - <= epsilon * Math.max(1.0, Math.abs(this.x), Math.abs(x)) - && Math.abs(this.y - y) - <= epsilon * Math.max(1.0, Math.abs(this.y), Math.abs(y)) - && Math.abs(this.z - z) - <= epsilon * Math.max(1.0, Math.abs(this.z), Math.abs(z)) + Math.abs(this._array[0] - x) + <= epsilon * Math.max(1.0, Math.abs(this._array[0]), Math.abs(x)) + && Math.abs(this._array[1] - y) + <= epsilon * Math.max(1.0, Math.abs(this._array[1]), Math.abs(y)) + && Math.abs(this._array[2] - z) + <= epsilon * Math.max(1.0, Math.abs(this._array[2]), Math.abs(z)) ); } @@ -788,8 +813,9 @@ export class Vec3 extends ValueType { * @param other specified vector * @returns Returns `true` when the components of both vectors are equal within the specified range of error; otherwise it returns `false`. */ - public strictEquals (other: Vec3) { - return this.x === other.x && this.y === other.y && this.z === other.z; + public strictEquals (other: Readonly) { + const v = other.array; + return this._array[0] === v[0] && this._array[1] === v[1] && this._array[2] === v[2]; } /** @@ -801,7 +827,7 @@ export class Vec3 extends ValueType { * @returns Returns `true` when the components of both vectors are equal within the specified range of error; otherwise it returns `false`. */ public strictEquals3f (x: number, y: number, z: number) { - return this.x === x && this.y === y && this.z === z; + return this._array[0] === x && this._array[1] === y && this._array[2] === z; } /** @@ -810,7 +836,7 @@ export class Vec3 extends ValueType { * @returns The string with vector information */ public toString () { - return `(${this.x.toFixed(2)}, ${this.y.toFixed(2)}, ${this.z.toFixed(2)})`; + return `(${this._array[0].toFixed(2)}, ${this._array[1].toFixed(2)}, ${this._array[2].toFixed(2)})`; } /** @@ -820,9 +846,9 @@ export class Vec3 extends ValueType { * @param ratio The interpolation coefficient.The range is [0,1]. */ public lerp (to: Vec3, ratio: number) { - this.x += ratio * (to.x - this.x); - this.y += ratio * (to.y - this.y); - this.z += ratio * (to.z - this.z); + this._array[0] += ratio * (to.x - this._array[0]); + this._array[1] += ratio * (to.y - this._array[1]); + this._array[2] += ratio * (to.z - this._array[2]); return this; } @@ -831,10 +857,11 @@ export class Vec3 extends ValueType { * @zh 向量加法。将当前向量与指定向量的相加 * @param other specified vector */ - public add (other: Vec3) { - this.x += other.x; - this.y += other.y; - this.z += other.z; + public add (other: Readonly) { + const v = other.array; + this._array[0] += v[0]; + this._array[1] += v[1]; + this._array[2] += v[2]; return this; } @@ -846,9 +873,9 @@ export class Vec3 extends ValueType { * @param z The z value of specified vector */ public add3f (x: number, y: number, z: number) { - this.x += x; - this.y += y; - this.z += z; + this._array[0] += x; + this._array[1] += y; + this._array[2] += z; return this; } @@ -857,10 +884,11 @@ export class Vec3 extends ValueType { * @zh 向量减法。将当前向量减去指定向量的结果。 * @param other specified vector */ - public subtract (other: Vec3) { - this.x -= other.x; - this.y -= other.y; - this.z -= other.z; + public subtract (other: Readonly) { + const v = other.array; + this._array[0] -= v[0]; + this._array[1] -= v[1]; + this._array[2] -= v[2]; return this; } @@ -872,9 +900,9 @@ export class Vec3 extends ValueType { * @param z The z value of specified vector */ public subtract3f (x: number, y: number, z: number) { - this.x -= x; - this.y -= y; - this.z -= z; + this._array[0] -= x; + this._array[1] -= y; + this._array[2] -= z; return this; } @@ -885,9 +913,9 @@ export class Vec3 extends ValueType { */ public multiplyScalar (scalar: number) { if (typeof scalar === 'object') { console.warn('should use Vec3.multiply for vector * vector operation'); } - this.x *= scalar; - this.y *= scalar; - this.z *= scalar; + this._array[0] *= scalar; + this._array[1] *= scalar; + this._array[2] *= scalar; return this; } @@ -896,11 +924,12 @@ export class Vec3 extends ValueType { * @zh 向量乘法。将当前向量乘以与指定向量的结果赋值给当前向量。 * @param other specified vector */ - public multiply (other: Vec3) { + public multiply (other: Readonly) { if (typeof other !== 'object') { console.warn('should use Vec3.scale for vector * scalar operation'); } - this.x *= other.x; - this.y *= other.y; - this.z *= other.z; + const v = other.array; + this._array[0] *= v[0]; + this._array[1] *= v[1]; + this._array[2] *= v[2]; return this; } @@ -912,9 +941,9 @@ export class Vec3 extends ValueType { * @param z The z value of specified vector */ public multiply3f (x: number, y: number, z: number) { - this.x *= x; - this.y *= y; - this.z *= z; + this._array[0] *= x; + this._array[1] *= y; + this._array[2] *= z; return this; } @@ -923,10 +952,11 @@ export class Vec3 extends ValueType { * @zh 向量逐元素相除。将当前向量与指定分量的向量相除的结果赋值给当前向量。 * @param other specified vector */ - public divide (other: Vec3) { - this.x /= other.x; - this.y /= other.y; - this.z /= other.z; + public divide (other: Readonly) { + const v = other.array; + this._array[0] /= v[0]; + this._array[1] /= v[1]; + this._array[2] /= v[2]; return this; } @@ -938,9 +968,9 @@ export class Vec3 extends ValueType { * @param z The z value of specified vector */ public divide3f (x: number, y: number, z: number) { - this.x /= x; - this.y /= y; - this.z /= z; + this._array[0] /= x; + this._array[1] /= y; + this._array[2] /= z; return this; } @@ -949,9 +979,9 @@ export class Vec3 extends ValueType { * @zh 将当前向量的各个分量取反 */ public negative () { - this.x = -this.x; - this.y = -this.y; - this.z = -this.z; + this._array[0] = -this._array[0]; + this._array[1] = -this._array[1]; + this._array[2] = -this._array[2]; return this; } @@ -962,10 +992,12 @@ export class Vec3 extends ValueType { * @param maxInclusive Maximum value allowed * @returns `this` */ - public clampf (minInclusive: Vec3, maxInclusive: Vec3) { - this.x = clamp(this.x, minInclusive.x, maxInclusive.x); - this.y = clamp(this.y, minInclusive.y, maxInclusive.y); - this.z = clamp(this.z, minInclusive.z, maxInclusive.z); + public clampf (minInclusive: Readonly, maxInclusive: Readonly) { + const min = minInclusive.array; + const max = maxInclusive.array; + this._array[0] = clamp(this._array[0], min[0], max[0]); + this._array[1] = clamp(this._array[1], min[1], max[1]); + this._array[2] = clamp(this._array[2], min[2], max[2]); return this; } @@ -975,8 +1007,9 @@ export class Vec3 extends ValueType { * @param other specified vector * @returns The result of calculates the dot product with another vector */ - public dot (other: Vec3) { - return this.x * other.x + this.y * other.y + this.z * other.z; + public dot (other: Readonly) { + const v = other.array; + return this._array[0] * v[0] + this._array[1] * v[1] + this._array[2] * v[2]; } /** @@ -984,13 +1017,17 @@ export class Vec3 extends ValueType { * @zh 向量叉乘。将当前向量左叉乘指定向量 * @param other specified vector */ - public cross (other: Vec3) { - const { x: ax, y: ay, z: az } = this; - const { x: bx, y: by, z: bz } = other; - - this.x = ay * bz - az * by; - this.y = az * bx - ax * bz; - this.z = ax * by - ay * bx; + public cross (other: Readonly) { + const ax = this._array[0]; + const ay = this._array[1]; + const az = this._array[2]; + const bx = other.array[0]; + const by = other.array[1]; + const bz = other.array[2]; + + this._array[0] = ay * bz - az * by; + this._array[1] = az * bx - ax * bz; + this._array[2] = ax * by - ay * bx; return this; } @@ -1000,7 +1037,7 @@ export class Vec3 extends ValueType { * @returns Length of vector */ public length () { - return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z); + return Math.sqrt(this._array[0] * this._array[0] + this._array[1] * this._array[1] + this._array[2] * this._array[2]); } /** @@ -1009,7 +1046,7 @@ export class Vec3 extends ValueType { * @returns the squared length of this vector */ public lengthSqr () { - return this.x * this.x + this.y * this.y + this.z * this.z; + return this._array[0] * this._array[0] + this._array[1] * this._array[1] + this._array[2] * this._array[2]; } /** @@ -1017,16 +1054,16 @@ export class Vec3 extends ValueType { * @zh 将当前向量归一化 */ public normalize () { - const x = this.x; - const y = this.y; - const z = this.z; + const x = this._array[0]; + const y = this._array[1]; + const z = this._array[2]; let len = x * x + y * y + z * z; if (len > 0) { len = 1 / Math.sqrt(len); - this.x = x * len; - this.y = y * len; - this.z = z * len; + this._array[0] = x * len; + this._array[1] = y * len; + this._array[2] = z * len; } return this; } @@ -1036,15 +1073,16 @@ export class Vec3 extends ValueType { * @zh 将当前向量视为 w 分量为 1 的四维向量,应用四维矩阵变换到当前矩阵 * @param matrix matrix to transform with */ - public transformMat4 (matrix: Mat4) { - const x = this.x; - const y = this.y; - const z = this.z; - let rhw = matrix.m03 * x + matrix.m07 * y + matrix.m11 * z + matrix.m15; + public transformMat4 (matrix: Readonly) { + const x = this._array[0]; + const y = this._array[1]; + const z = this._array[2]; + const v = matrix.array; + let rhw = v[3] * x + v[7] * y + v[11] * z + v[15]; rhw = rhw ? 1 / rhw : 1; - this.x = (matrix.m00 * x + matrix.m04 * y + matrix.m08 * z + matrix.m12) * rhw; - this.y = (matrix.m01 * x + matrix.m05 * y + matrix.m09 * z + matrix.m13) * rhw; - this.z = (matrix.m02 * x + matrix.m06 * y + matrix.m10 * z + matrix.m14) * rhw; + this._array[0] = (v[0] * x + v[4] * y + v[8] * z + v[12]) * rhw; + this._array[1] = (v[1] * x + v[5] * y + v[9] * z + v[13]) * rhw; + this._array[2] = (v[2] * x + v[6] * y + v[10] * z + v[14]) * rhw; return this; } } diff --git a/cocos/core/math/vec4.ts b/cocos/core/math/vec4.ts index e21cfb6554c..5df5af6609e 100644 --- a/cocos/core/math/vec4.ts +++ b/cocos/core/math/vec4.ts @@ -30,17 +30,17 @@ */ import { CCClass } from '../data/class'; -import { ValueType } from '../value-types/value-type'; import { Mat4 } from './mat4'; -import { IMat4Like, IQuatLike, IVec4Like } from './type-define'; +import { IMat4Like, IQuatLike, IVec4Like, FloatArray } from './type-define'; import { clamp, EPSILON, random } from './utils'; import { legacyCC } from '../global-exports'; +import { MathBase } from './math-base'; /** * @en Representation of four-dimensional vectors. * @zh 四维向量。 */ -export class Vec4 extends ValueType { +export class Vec4 extends MathBase { public static ZERO = Object.freeze(new Vec4(0, 0, 0, 0)); public static ONE = Object.freeze(new Vec4(1, 1, 1, 1)); public static NEG_ONE = Object.freeze(new Vec4(-1, -1, -1, -1)); @@ -49,7 +49,7 @@ export class Vec4 extends ValueType { * @en Obtains a clone of the given vector object * @zh 获得指定向量的拷贝 */ - public static clone (a: Out) { + public static clone (a: Readonly) { return new Vec4(a.x, a.y, a.z, a.w); } @@ -57,7 +57,7 @@ export class Vec4 extends ValueType { * @en Copy the target vector and save the results to out vector object * @zh 复制目标向量 */ - public static copy (out: Out, a: Out) { + public static copy (out: Out, a: Readonly) { out.x = a.x; out.y = a.y; out.z = a.z; @@ -81,7 +81,7 @@ export class Vec4 extends ValueType { * @en Element-wise vector addition and save the results to out vector object * @zh 逐元素向量加法 */ - public static add (out: Out, a: Out, b: Out) { + public static add (out: Out, a: Readonly, b: Readonly) { out.x = a.x + b.x; out.y = a.y + b.y; out.z = a.z + b.z; @@ -93,7 +93,7 @@ export class Vec4 extends ValueType { * @en Element-wise vector subtraction and save the results to out vector object * @zh 逐元素向量减法 */ - public static subtract (out: Out, a: Out, b: Out) { + public static subtract (out: Out, a: Readonly, b: Readonly) { out.x = a.x - b.x; out.y = a.y - b.y; out.z = a.z - b.z; @@ -105,7 +105,7 @@ export class Vec4 extends ValueType { * @en Element-wise vector multiplication and save the results to out vector object * @zh 逐元素向量乘法 */ - public static multiply (out: Out, a: Out, b: Out) { + public static multiply (out: Out, a: Readonly, b: Readonly) { out.x = a.x * b.x; out.y = a.y * b.y; out.z = a.z * b.z; @@ -117,7 +117,7 @@ export class Vec4 extends ValueType { * @en Element-wise vector division and save the results to out vector object * @zh 逐元素向量除法 */ - public static divide (out: Out, a: Out, b: Out) { + public static divide (out: Out, a: Readonly, b: Readonly) { out.x = a.x / b.x; out.y = a.y / b.y; out.z = a.z / b.z; @@ -129,7 +129,7 @@ export class Vec4 extends ValueType { * @en Rounds up by elements of the vector and save the results to out vector object * @zh 逐元素向量向上取整 */ - public static ceil (out: Out, a: Out) { + public static ceil (out: Out, a: Readonly) { out.x = Math.ceil(a.x); out.y = Math.ceil(a.y); out.z = Math.ceil(a.z); @@ -141,7 +141,7 @@ export class Vec4 extends ValueType { * @en Element-wise rounds down of the current vector and save the results to the out vector * @zh 逐元素向量向下取整 */ - public static floor (out: Out, a: Out) { + public static floor (out: Out, a: Readonly) { out.x = Math.floor(a.x); out.y = Math.floor(a.y); out.z = Math.floor(a.z); @@ -153,7 +153,7 @@ export class Vec4 extends ValueType { * @en Calculates the minimum values by elements of the vector and save the results to the out vector * @zh 逐元素向量最小值 */ - public static min (out: Out, a: Out, b: Out) { + public static min (out: Out, a: Readonly, b: Readonly) { out.x = Math.min(a.x, b.x); out.y = Math.min(a.y, b.y); out.z = Math.min(a.z, b.z); @@ -165,7 +165,7 @@ export class Vec4 extends ValueType { * @en Calculates the maximum values by elements of the vector and save the results to the out vector * @zh 逐元素向量最大值 */ - public static max (out: Out, a: Out, b: Out) { + public static max (out: Out, a: Readonly, b: Readonly) { out.x = Math.max(a.x, b.x); out.y = Math.max(a.y, b.y); out.z = Math.max(a.z, b.z); @@ -177,7 +177,7 @@ export class Vec4 extends ValueType { * @en Calculates element-wise round results and save to the out vector * @zh 逐元素向量四舍五入取整 */ - public static round (out: Out, a: Out) { + public static round (out: Out, a: Readonly) { out.x = Math.round(a.x); out.y = Math.round(a.y); out.z = Math.round(a.z); @@ -189,7 +189,7 @@ export class Vec4 extends ValueType { * @en Vector scalar multiplication and save the results to out vector object * @zh 向量标量乘法 */ - public static multiplyScalar (out: Out, a: Out, b: number) { + public static multiplyScalar (out: Out, a: Readonly, b: number) { out.x = a.x * b; out.y = a.y * b; out.z = a.z * b; @@ -201,7 +201,7 @@ export class Vec4 extends ValueType { * @en Element-wise multiplication and addition with the equation: a + b * scale * @zh 逐元素向量乘加: A + B * scale */ - public static scaleAndAdd (out: Out, a: Out, b: Out, scale: number) { + public static scaleAndAdd (out: Out, a: Readonly, b: Readonly, scale: number) { out.x = a.x + (b.x * scale); out.y = a.y + (b.y * scale); out.z = a.z + (b.z * scale); @@ -213,7 +213,7 @@ export class Vec4 extends ValueType { * @en Calculates the euclidean distance of two vectors * @zh 求两向量的欧氏距离 */ - public static distance (a: Out, b: Out) { + public static distance (a: Readonly, b: Readonly) { const x = b.x - a.x; const y = b.y - a.y; const z = b.z - a.z; @@ -225,7 +225,7 @@ export class Vec4 extends ValueType { * @en Calculates the squared euclidean distance of two vectors * @zh 求两向量的欧氏距离平方 */ - public static squaredDistance (a: Out, b: Out) { + public static squaredDistance (a: Readonly, b: Readonly) { const x = b.x - a.x; const y = b.y - a.y; const z = b.z - a.z; @@ -237,7 +237,7 @@ export class Vec4 extends ValueType { * @en Calculates the length of the vector * @zh 求向量长度 */ - public static len (a: Out) { + public static len (a: Readonly) { const x = a.x; const y = a.y; const z = a.z; @@ -249,7 +249,7 @@ export class Vec4 extends ValueType { * @en Calculates the squared length of the vector * @zh 求向量长度平方 */ - public static lengthSqr (a: Out) { + public static lengthSqr (a: Readonly) { const x = a.x; const y = a.y; const z = a.z; @@ -261,7 +261,7 @@ export class Vec4 extends ValueType { * @en Sets each element to its negative value * @zh 逐元素向量取负 */ - public static negate (out: Out, a: Out) { + public static negate (out: Out, a: Readonly) { out.x = -a.x; out.y = -a.y; out.z = -a.z; @@ -273,7 +273,7 @@ export class Vec4 extends ValueType { * @en Sets each element to its inverse value, zero value will become Infinity * @zh 逐元素向量取倒数,接近 0 时返回 Infinity */ - public static inverse (out: Out, a: Out) { + public static inverse (out: Out, a: Readonly) { out.x = 1.0 / a.x; out.y = 1.0 / a.y; out.z = 1.0 / a.z; @@ -285,7 +285,7 @@ export class Vec4 extends ValueType { * @en Sets each element to its inverse value, zero value will remain zero * @zh 逐元素向量取倒数,接近 0 时返回 0 */ - public static inverseSafe (out: Out, a: Out) { + public static inverseSafe (out: Out, a: Readonly) { const x = a.x; const y = a.y; const z = a.z; @@ -322,7 +322,7 @@ export class Vec4 extends ValueType { * @en Sets the normalized vector to the out vector * @zh 归一化向量 */ - public static normalize (out: Out, a: Out) { + public static normalize (out: Out, a: Readonly) { const x = a.x; const y = a.y; const z = a.z; @@ -342,7 +342,7 @@ export class Vec4 extends ValueType { * @en Calculates the dot product of the vector * @zh 向量点积(数量积) */ - public static dot (a: Out, b: Out) { + public static dot (a: Readonly, b: Readonly) { return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; } @@ -350,7 +350,7 @@ export class Vec4 extends ValueType { * @en Calculates the linear interpolation between two vectors with a given ratio * @zh 逐元素向量线性插值: A + t * (B - A) */ - public static lerp (out: Out, a: Out, b: Out, t: number) { + public static lerp (out: Out, a: Readonly, b: Readonly, t: number) { out.x = a.x + t * (b.x - a.x); out.y = a.y + t * (b.y - a.y); out.z = a.z + t * (b.z - a.z); @@ -381,7 +381,7 @@ export class Vec4 extends ValueType { * @en Vector and fourth order matrix multiplication * @zh 向量与四维矩阵乘法 */ - public static transformMat4 (out: Out, a: Out, m: MatLike) { + public static transformMat4 (out: Out, a: Readonly, m: Readonly) { const x = a.x; const y = a.y; const z = a.z; @@ -397,8 +397,7 @@ export class Vec4 extends ValueType { * @en Transform the vector with the given affine transformation * @zh 向量仿射变换 */ - public static transformAffine - (out: Out, v: VecLike, m: MatLike) { + public static transformAffine (out: Out, v: Readonly, m: Readonly) { const x = v.x; const y = v.y; const z = v.z; @@ -414,7 +413,7 @@ export class Vec4 extends ValueType { * @en Vector quaternion multiplication * @zh 向量四元数乘法 */ - public static transformQuat (out: Out, a: Out, q: QuatLike) { + public static transformQuat (out: Out, a: Readonly, q: Readonly) { const { x, y, z } = a; const _x = q.x; @@ -466,7 +465,7 @@ export class Vec4 extends ValueType { * @en Check the equality of the two given vectors * @zh 向量等价判断 */ - public static strictEquals (a: Out, b: Out) { + public static strictEquals (a: Readonly, b: Readonly) { return a.x === b.x && a.y === b.y && a.z === b.z && a.w === b.w; } @@ -474,7 +473,7 @@ export class Vec4 extends ValueType { * @en Check whether the two given vectors are approximately equivalent * @zh 排除浮点数误差的向量近似等价判断 */ - public static equals (a: Out, b: Out, epsilon = EPSILON) { + public static equals (a: Readonly, b: Readonly, epsilon = EPSILON) { return (Math.abs(a.x - b.x) <= epsilon * Math.max(1.0, Math.abs(a.x), Math.abs(b.x)) && Math.abs(a.y - b.y) <= epsilon * Math.max(1.0, Math.abs(a.y), Math.abs(b.y)) && Math.abs(a.z - b.z) <= epsilon * Math.max(1.0, Math.abs(a.z), Math.abs(b.z)) @@ -485,42 +484,70 @@ export class Vec4 extends ValueType { * @en x component. * @zh x 分量。 */ - public declare x: number; + public get x (): number { + return this._array[0]; + } + public set x (x: number) { + this._array[0] = x; + } /** * @en y component. * @zh y 分量。 */ - public declare y: number; + public get y (): number { + return this._array[1]; + } + public set y (y: number) { + this._array[1] = y; + } /** * @en z component. * @zh z 分量。 */ - public declare z: number; + public get z (): number { + return this._array[2]; + } + public set z (z: number) { + this._array[2] = z; + } /** - * @en w component. + * @en The w value of the vector. * @zh w 分量。 */ - public declare w: number; + public get w (): number { + return this._array[3]; + } + public set w (w: number) { + this._array[3] = w; + } - constructor (other: Vec4); + constructor (x: Vec4 | FloatArray); constructor (x?: number, y?: number, z?: number, w?: number); - constructor (x?: number | Vec4, y?: number, z?: number, w?: number) { + constructor (x?: number | Vec4 | FloatArray, y?: number, z?: number, w?: number) { super(); if (x && typeof x === 'object') { - this.x = x.x; - this.y = x.y; - this.z = x.z; - this.w = x.w; + if (ArrayBuffer.isView(x)) { + this._array = x; + this._array.fill(0); + } else { + const v = x.array; + this._array = MathBase.createFloatArray(4); + this._array[0] = v[0]; + this._array[1] = v[1]; + this._array[2] = v[2]; + this._array[3] = v[3]; + } } else { - this.x = x || 0; - this.y = y || 0; - this.z = z || 0; - this.w = w || 0; + this._array = MathBase.createFloatArray(4); + this._array[0] = x || 0; + this._array[1] = y || 0; + this._array[2] = z || 0; + this._array[3] = w || 0; } } @@ -529,7 +556,7 @@ export class Vec4 extends ValueType { * @zh 克隆当前向量。 */ public clone () { - return new Vec4(this.x, this.y, this.z, this.w); + return new Vec4(this._array[0], this._array[1], this._array[2], this._array[3]); } /** @@ -538,7 +565,7 @@ export class Vec4 extends ValueType { * @param other Specified vector * @returns `this` */ - public set (other: Vec4); + public set (other: Readonly); /** * @en Set the value of each component of the current vector. @@ -551,17 +578,18 @@ export class Vec4 extends ValueType { */ public set (x?: number, y?: number, z?: number, w?: number); - public set (x?: number | Vec4, y?: number, z?: number, w?: number) { + public set (x?: number | Readonly, y?: number, z?: number, w?: number) { if (x && typeof x === 'object') { - this.x = x.x; - this.y = x.y; - this.z = x.z; - this.w = x.w; + const v = x.array; + this._array[0] = v[0]; + this._array[1] = v[1]; + this._array[2] = v[2]; + this._array[3] = v[3]; } else { - this.x = x || 0; - this.y = y || 0; - this.z = z || 0; - this.w = w || 0; + this._array[0] = x || 0; + this._array[1] = y || 0; + this._array[2] = z || 0; + this._array[3] = w || 0; } return this; } @@ -573,11 +601,12 @@ export class Vec4 extends ValueType { * @param epsilon The error allowed. It`s should be a non-negative number. * @returns Returns `true` when the components of both vectors are equal within the specified range of error; otherwise it returns `false`. */ - public equals (other: Vec4, epsilon = EPSILON) { - return (Math.abs(this.x - other.x) <= epsilon * Math.max(1.0, Math.abs(this.x), Math.abs(other.x)) - && Math.abs(this.y - other.y) <= epsilon * Math.max(1.0, Math.abs(this.y), Math.abs(other.y)) - && Math.abs(this.z - other.z) <= epsilon * Math.max(1.0, Math.abs(this.z), Math.abs(other.z)) - && Math.abs(this.w - other.w) <= epsilon * Math.max(1.0, Math.abs(this.w), Math.abs(other.w))); + public equals (other: Readonly, epsilon = EPSILON) { + const v = other.array; + return (Math.abs(this._array[0] - v[0]) <= epsilon * Math.max(1.0, Math.abs(this._array[0]), Math.abs(v[0])) + && Math.abs(this._array[1] - v[1]) <= epsilon * Math.max(1.0, Math.abs(this._array[1]), Math.abs(v[1])) + && Math.abs(this._array[2] - v[2]) <= epsilon * Math.max(1.0, Math.abs(this._array[2]), Math.abs(v[2])) + && Math.abs(this._array[3] - v[3]) <= epsilon * Math.max(1.0, Math.abs(this._array[3]), Math.abs(v[3]))); } /** @@ -591,10 +620,10 @@ export class Vec4 extends ValueType { * @returns Returns `true` when the components of both vectors are equal within the specified range of error; otherwise it returns `false`. */ public equals4f (x: number, y: number, z: number, w: number, epsilon = EPSILON) { - return (Math.abs(this.x - x) <= epsilon * Math.max(1.0, Math.abs(this.x), Math.abs(x)) - && Math.abs(this.y - y) <= epsilon * Math.max(1.0, Math.abs(this.y), Math.abs(y)) - && Math.abs(this.z - z) <= epsilon * Math.max(1.0, Math.abs(this.z), Math.abs(z)) - && Math.abs(this.w - w) <= epsilon * Math.max(1.0, Math.abs(this.w), Math.abs(w))); + return (Math.abs(this._array[0] - x) <= epsilon * Math.max(1.0, Math.abs(this._array[0]), Math.abs(x)) + && Math.abs(this._array[1] - y) <= epsilon * Math.max(1.0, Math.abs(this._array[1]), Math.abs(y)) + && Math.abs(this._array[2] - z) <= epsilon * Math.max(1.0, Math.abs(this._array[2]), Math.abs(z)) + && Math.abs(this._array[3] - w) <= epsilon * Math.max(1.0, Math.abs(this._array[3]), Math.abs(w))); } /** @@ -603,8 +632,9 @@ export class Vec4 extends ValueType { * @param other specified vector * @returns Returns `true` when the components of both vectors are equal within the specified range of error; otherwise it returns `false`. */ - public strictEquals (other: Vec4) { - return this.x === other.x && this.y === other.y && this.z === other.z && this.w === other.w; + public strictEquals (other: Readonly) { + const v = other.array; + return this._array[0] === v[0] && this._array[1] === v[1] && this._array[2] === v[2] && this._array[3] === v[3]; } /** @@ -617,7 +647,7 @@ export class Vec4 extends ValueType { * @returns Returns `true` when the components of both vectors are equal within the specified range of error; otherwise it returns `false`. */ public strictEquals4f (x: number, y: number, z: number, w: number) { - return this.x === x && this.y === y && this.z === z && this.w === w; + return this._array[0] === x && this._array[1] === y && this._array[2] === z && this._array[3] === w; } /** @@ -627,14 +657,15 @@ export class Vec4 extends ValueType { * @param ratio The interpolation coefficient.The range is [0,1]. */ public lerp (to: Vec4, ratio: number) { - const x = this.x; - const y = this.y; - const z = this.z; - const w = this.w; - this.x = x + ratio * (to.x - x); - this.y = y + ratio * (to.y - y); - this.z = z + ratio * (to.z - z); - this.w = w + ratio * (to.w - w); + const x = this._array[0]; + const y = this._array[1]; + const z = this._array[2]; + const w = this._array[3]; + const v = to.array; + this._array[0] = x + ratio * (v[0] - x); + this._array[1] = y + ratio * (v[1] - y); + this._array[2] = z + ratio * (v[2] - z); + this._array[3] = w + ratio * (v[3] - w); return this; } @@ -644,7 +675,7 @@ export class Vec4 extends ValueType { * @returns The string with vector information */ public toString () { - return `(${this.x.toFixed(2)}, ${this.y.toFixed(2)}, ${this.z.toFixed(2)}, ${this.w.toFixed(2)})`; + return `(${this._array[0].toFixed(2)}, ${this._array[1].toFixed(2)}, ${this._array[2].toFixed(2)}, ${this._array[3].toFixed(2)})`; } /** @@ -655,10 +686,12 @@ export class Vec4 extends ValueType { * @returns `this` */ public clampf (minInclusive: Vec4, maxInclusive: Vec4) { - this.x = clamp(this.x, minInclusive.x, maxInclusive.x); - this.y = clamp(this.y, minInclusive.y, maxInclusive.y); - this.z = clamp(this.z, minInclusive.z, maxInclusive.z); - this.w = clamp(this.w, minInclusive.w, maxInclusive.w); + const min = minInclusive.array; + const max = maxInclusive.array; + this._array[0] = clamp(this._array[0], min[0], max[0]); + this._array[1] = clamp(this._array[1], min[1], max[1]); + this._array[2] = clamp(this._array[2], min[2], max[2]); + this._array[3] = clamp(this._array[3], min[3], max[3]); return this; } @@ -667,11 +700,12 @@ export class Vec4 extends ValueType { * @zh 向量加法。将当前向量与指定向量的相加 * @param other specified vector */ - public add (other: Vec4) { - this.x += other.x; - this.y += other.y; - this.z += other.z; - this.w += other.w; + public add (other: Readonly) { + const v = other.array; + this._array[0] += v[0]; + this._array[1] += v[1]; + this._array[2] += v[2]; + this._array[3] += v[3]; return this; } @@ -684,10 +718,10 @@ export class Vec4 extends ValueType { * @param w The w value of specified vector */ public add4f (x: number, y: number, z: number, w: number) { - this.x += x; - this.y += y; - this.z += z; - this.w += w; + this._array[0] += x; + this._array[1] += y; + this._array[2] += z; + this._array[3] += w; return this; } @@ -696,11 +730,12 @@ export class Vec4 extends ValueType { * @zh 向量减法。将当前向量减去指定向量 * @param other specified vector */ - public subtract (other: Vec4) { - this.x -= other.x; - this.y -= other.y; - this.z -= other.z; - this.w -= other.w; + public subtract (other: Readonly) { + const v = other.array; + this._array[0] -= v[0]; + this._array[1] -= v[1]; + this._array[2] -= -v[2]; + this._array[3] -= v[3]; return this; } @@ -713,10 +748,10 @@ export class Vec4 extends ValueType { * @param w The w value of specified vector */ public subtract4f (x: number, y: number, z: number, w: number) { - this.x -= x; - this.y -= y; - this.z -= z; - this.w -= w; + this._array[0] -= x; + this._array[1] -= y; + this._array[2] -= z; + this._array[3] -= w; return this; } @@ -727,10 +762,10 @@ export class Vec4 extends ValueType { */ public multiplyScalar (scalar: number) { if (typeof scalar === 'object') { console.warn('should use Vec4.multiply for vector * vector operation'); } - this.x *= scalar; - this.y *= scalar; - this.z *= scalar; - this.w *= scalar; + this._array[0] *= scalar; + this._array[1] *= scalar; + this._array[2] *= scalar; + this._array[3] *= scalar; return this; } @@ -739,12 +774,13 @@ export class Vec4 extends ValueType { * @zh 向量乘法。将当前向量乘以指定向量 * @param other specified vector */ - public multiply (other: Vec4) { + public multiply (other: Readonly) { if (typeof other !== 'object') { console.warn('should use Vec4.scale for vector * scalar operation'); } - this.x *= other.x; - this.y *= other.y; - this.z *= other.z; - this.w *= other.w; + const v = other.array; + this._array[0] *= v[0]; + this._array[1] *= v[1]; + this._array[2] *= v[2]; + this._array[3] *= v[3]; return this; } @@ -757,10 +793,10 @@ export class Vec4 extends ValueType { * @param w The w value of specified vector */ public multiply4f (x: number, y: number, z: number, w: number) { - this.x *= x; - this.y *= y; - this.z *= z; - this.w *= w; + this._array[0] *= x; + this._array[1] *= y; + this._array[2] *= z; + this._array[3] *= w; return this; } @@ -769,11 +805,12 @@ export class Vec4 extends ValueType { * @zh 向量逐元素相除。将当前向量与指定分量的向量相除的结果赋值给当前向量。 * @param other specified vector */ - public divide (other: Vec4) { - this.x /= other.x; - this.y /= other.y; - this.z /= other.z; - this.w /= other.w; + public divide (other: Readonly) { + const v = other.array; + this._array[0] /= v[0]; + this._array[1] /= v[1]; + this._array[2] /= v[2]; + this._array[3] /= v[3]; return this; } @@ -786,10 +823,10 @@ export class Vec4 extends ValueType { * @param w The w value of specified vector */ public divide4f (x: number, y: number, z: number, w: number) { - this.x /= x; - this.y /= y; - this.z /= z; - this.w /= w; + this._array[0] /= x; + this._array[1] /= y; + this._array[2] /= z; + this._array[3] /= w; return this; } @@ -798,10 +835,10 @@ export class Vec4 extends ValueType { * @zh 将当前向量的各个分量取反 */ public negative () { - this.x = -this.x; - this.y = -this.y; - this.z = -this.z; - this.w = -this.w; + this._array[0] = -this._array[0]; + this._array[1] = -this._array[1]; + this._array[2] = -this._array[2]; + this._array[3] = -this._array[3]; return this; } @@ -811,8 +848,9 @@ export class Vec4 extends ValueType { * @param other specified vector * @returns 当前向量与指定向量点乘的结果。 */ - public dot (vector: Vec4) { - return this.x * vector.x + this.y * vector.y + this.z * vector.z + this.w * vector.w; + public dot (other: Readonly) { + const v = other.array; + return this._array[0] * v[0] + this._array[1] * v[1] + this._array[2] * v[2] + this._array[3] * v[3]; } /** @@ -820,13 +858,18 @@ export class Vec4 extends ValueType { * @zh 向量叉乘。视当前向量和指定向量为三维向量(舍弃 w 分量),将当前向量左叉乘指定向量 * @param other specified vector */ - public cross (vector: Vec4) { - const { x: ax, y: ay, z: az } = this; - const { x: bx, y: by, z: bz } = vector; - - this.x = ay * bz - az * by; - this.y = az * bx - ax * bz; - this.z = ax * by - ay * bx; + public cross (other: Readonly) { + const ax = this._array[0]; + const ay = this._array[1]; + const az = this._array[2]; + const v = other.array; + const bx = v[0]; + const by = v[1]; + const bz = v[2]; + + this._array[0] = ay * bz - az * by; + this._array[1] = az * bx - ax * bz; + this._array[2] = ax * by - ay * bx; return this; } @@ -836,10 +879,10 @@ export class Vec4 extends ValueType { * @returns Length of vector */ public length () { - const x = this.x; - const y = this.y; - const z = this.z; - const w = this.w; + const x = this._array[0]; + const y = this._array[1]; + const z = this._array[2]; + const w = this._array[3]; return Math.sqrt(x * x + y * y + z * z + w * w); } @@ -849,10 +892,10 @@ export class Vec4 extends ValueType { * @returns the squared length of this vector */ public lengthSqr () { - const x = this.x; - const y = this.y; - const z = this.z; - const w = this.w; + const x = this._array[0]; + const y = this._array[1]; + const z = this._array[2]; + const w = this._array[3]; return x * x + y * y + z * z + w * w; } @@ -861,17 +904,17 @@ export class Vec4 extends ValueType { * @zh 将当前向量归一化 */ public normalize () { - const x = this.x; - const y = this.y; - const z = this.z; - const w = this.w; + const x = this._array[0]; + const y = this._array[1]; + const z = this._array[2]; + const w = this._array[3]; let len = x * x + y * y + z * z + w * w; if (len > 0) { len = 1 / Math.sqrt(len); - this.x = x * len; - this.y = y * len; - this.z = z * len; - this.w = w * len; + this._array[0] = x * len; + this._array[1] = y * len; + this._array[2] = z * len; + this._array[3] = w * len; } return this; } @@ -881,15 +924,16 @@ export class Vec4 extends ValueType { * @zh 应用四维矩阵变换到当前矩阵 * @param matrix matrix to transform with */ - public transformMat4 (matrix: Mat4) { - const x = this.x; - const y = this.y; - const z = this.z; - const w = this.w; - this.x = matrix.m00 * x + matrix.m04 * y + matrix.m08 * z + matrix.m12 * w; - this.y = matrix.m01 * x + matrix.m05 * y + matrix.m09 * z + matrix.m13 * w; - this.z = matrix.m02 * x + matrix.m06 * y + matrix.m10 * z + matrix.m14 * w; - this.w = matrix.m03 * x + matrix.m07 * y + matrix.m11 * z + matrix.m15 * w; + public transformMat4 (matrix: Readonly) { + const x = this._array[0]; + const y = this._array[1]; + const z = this._array[2]; + const w = this._array[3]; + const v = matrix.array; + this._array[0] = v[0] * x + v[4] * y + v[8] * z + v[12] * w; + this._array[1] = v[1] * x + v[5] * y + v[9] * z + v[13] * w; + this._array[2] = v[2] * x + v[6] * y + v[10] * z + v[14] * w; + this._array[3] = v[3] * x + v[7] * y + v[11] * z + v[15] * w; return this; } } diff --git a/cocos/core/pipeline/batched-buffer.ts b/cocos/core/pipeline/batched-buffer.ts index 584eb16fc62..05b245d2dc3 100644 --- a/cocos/core/pipeline/batched-buffer.ts +++ b/cocos/core/pipeline/batched-buffer.ts @@ -29,13 +29,12 @@ */ import { BufferUsageBit, Format, MemoryUsageBit, Device, DescriptorSet, InputAssembler, - InputAssemblerInfo, Attribute, Buffer, BufferInfo } from '../gfx'; + InputAssemblerInfo, Attribute, Buffer, BufferInfo, Shader } from '../gfx'; import { Mat4 } from '../math'; import { SubModel } from '../renderer/scene/submodel'; import { UBOLocalBatched } from './define'; import { Pass } from '../renderer'; import { Model } from '../renderer/scene'; -import { SubModelPool, SubModelView, ShaderHandle } from '../renderer/core/memory-pools'; export interface IBatchedItem { vbs: Buffer[]; @@ -49,7 +48,7 @@ export interface IBatchedItem { uboData: Float32Array; descriptorSet: DescriptorSet; pass: Pass; - hShader: ShaderHandle; + shader: Shader | null; } export class BatchedBuffer { @@ -90,7 +89,7 @@ export class BatchedBuffer { let vbIdxSize = 0; const vbCount = flatBuffers[0].count; const pass = subModel.passes[passIdx]; - const hShader = SubModelPool.get(subModel.handle, SubModelView.SHADER_0 + passIdx) as ShaderHandle; + const shader = pass.getShaderVariant(); const descriptorSet = subModel.descriptorSet; let isBatchExist = false; for (let i = 0; i < this.batches.length; ++i) { @@ -143,7 +142,7 @@ export class BatchedBuffer { descriptorSet.bindBuffer(UBOLocalBatched.BINDING, batch.ubo); descriptorSet.update(); batch.pass = pass; - batch.hShader = hShader; + batch.shader = shader; batch.descriptorSet = descriptorSet; } @@ -219,7 +218,7 @@ export class BatchedBuffer { ubo, uboData, pass, - hShader, + shader, descriptorSet, }); } diff --git a/cocos/core/pipeline/deferred/deferred-pipeline.ts b/cocos/core/pipeline/deferred/deferred-pipeline.ts index 20c8e7543ce..aa802a07e56 100644 --- a/cocos/core/pipeline/deferred/deferred-pipeline.ts +++ b/cocos/core/pipeline/deferred/deferred-pipeline.ts @@ -274,7 +274,7 @@ export class DeferredPipeline extends RenderPipeline { if (!this._lightingRenderPass) { const colorAttachment = new ColorAttachment(); - colorAttachment.format = Format.RGBA16F; + colorAttachment.format = Format.RGBA8; colorAttachment.loadOp = LoadOp.CLEAR; // should clear color attachment colorAttachment.storeOp = StoreOp.STORE; colorAttachment.endAccesses = [AccessType.COLOR_ATTACHMENT_WRITE]; @@ -296,15 +296,6 @@ export class DeferredPipeline extends RenderPipeline { this._height = device.height; this._generateDeferredRenderData(); - if (device.surfaceTransform === SurfaceTransform.IDENTITY - || device.surfaceTransform === SurfaceTransform.ROTATE_180) { - this._width = device.width; - this._height = device.height; - } else { - this._width = device.height; - this._height = device.width; - } - return true; } @@ -575,7 +566,7 @@ export class DeferredPipeline extends RenderPipeline { data.lightingRenderTargets.push(device.createTexture(new TextureInfo( TextureType.TEX2D, TextureUsageBit.COLOR_ATTACHMENT | TextureUsageBit.SAMPLED, - Format.RGBA16F, + Format.RGBA8, this._width, this._height, ))); diff --git a/cocos/core/pipeline/deferred/gbuffer-flow.ts b/cocos/core/pipeline/deferred/gbuffer-flow.ts index cf5358492cd..f1aaf3e8223 100644 --- a/cocos/core/pipeline/deferred/gbuffer-flow.ts +++ b/cocos/core/pipeline/deferred/gbuffer-flow.ts @@ -33,9 +33,7 @@ import { PIPELINE_FLOW_GBUFFER } from '../define'; import { IRenderFlowInfo, RenderFlow } from '../render-flow'; import { DeferredFlowPriority } from './enum'; import { GbufferStage } from './gbuffer-stage'; -import { DeferredPipeline } from './deferred-pipeline'; import { RenderPipeline } from '../render-pipeline'; -import { sceneCulling } from '../scene-culling'; /** * @en The gbuffer flow in deferred render pipeline diff --git a/cocos/core/pipeline/deferred/lighting-stage.ts b/cocos/core/pipeline/deferred/lighting-stage.ts index d70c4cdbdb1..c75eccc002e 100644 --- a/cocos/core/pipeline/deferred/lighting-stage.ts +++ b/cocos/core/pipeline/deferred/lighting-stage.ts @@ -33,14 +33,13 @@ import { Camera } from '../../renderer/scene'; import { localDescriptorSetLayout, UBODeferredLight, SetIndex, UBOForwardLight } from '../define'; import { getPhaseID } from '../pass-phase'; import { Color, Rect, Shader, Buffer, BufferUsageBit, MemoryUsageBit, BufferInfo, BufferViewInfo, DescriptorSet, DescriptorSetLayoutInfo, - DescriptorSetLayout, DescriptorSetInfo, PipelineState, ClearFlags, ClearFlagBit } from '../../gfx'; + DescriptorSetLayout, DescriptorSetInfo, PipelineState, ClearFlagBit } from '../../gfx'; import { IRenderStageInfo, RenderStage } from '../render-stage'; import { DeferredStagePriority } from './enum'; import { LightingFlow } from './lighting-flow'; import { DeferredPipeline } from './deferred-pipeline'; import { PlanarShadowQueue } from '../planar-shadow-queue'; import { Material } from '../../assets/material'; -import { ShaderPool } from '../../renderer/core/memory-pools'; import { PipelineStateManager } from '../pipeline-state-manager'; import { intersect, Sphere } from '../../geometry'; import { Vec3, Vec4 } from '../../math'; @@ -278,10 +277,10 @@ export class LightingStage extends RenderStage { const builinDeferred = builtinResMgr.get('builtin-deferred-material'); if (builinDeferred) { pass = builinDeferred.passes[0]; - shader = ShaderPool.get(pass.getShaderVariant()); + shader = pass.getShaderVariant()!; } else { pass = this._deferredMaterial!.passes[LIGHTINGPASS_INDEX]; - shader = ShaderPool.get(this._deferredMaterial!.passes[LIGHTINGPASS_INDEX].getShaderVariant()); + shader = this._deferredMaterial!.passes[LIGHTINGPASS_INDEX].getShaderVariant()!; } const inputAssembler = pipeline.quadIAOffscreen; diff --git a/cocos/core/pipeline/deferred/postprocess-stage.ts b/cocos/core/pipeline/deferred/postprocess-stage.ts index b0aaa2ef9df..7bae771ff9d 100644 --- a/cocos/core/pipeline/deferred/postprocess-stage.ts +++ b/cocos/core/pipeline/deferred/postprocess-stage.ts @@ -30,21 +30,16 @@ import { ccclass, displayOrder, type, serializable } from 'cc.decorator'; import { builtinResMgr } from '../../builtin'; import { Camera } from '../../renderer/scene'; -import { SetIndex, IRenderPass } from '../define'; -import { Color, Rect, Shader, PipelineState, ClearFlagBit, BlendFactor } from '../../gfx'; +import { SetIndex } from '../define'; +import { Color, Rect, Shader, PipelineState, ClearFlagBit } from '../../gfx'; import { IRenderStageInfo, RenderStage } from '../render-stage'; import { DeferredStagePriority } from './enum'; import { LightingFlow } from './lighting-flow'; import { DeferredPipeline } from './deferred-pipeline'; import { Material } from '../../assets/material'; -import { ShaderPool } from '../../renderer/core/memory-pools'; import { PipelineStateManager } from '../pipeline-state-manager'; import { Pass } from '../../renderer'; import { UIPhase } from '../forward/ui-phase'; -import { opaqueCompareFn, RenderQueue, transparentCompareFn } from '../render-queue'; -import { RenderQueueDesc, RenderQueueSortMode } from '../pipeline-serialization'; - -import { getPhaseID } from '../pass-phase'; const colors: Color[] = [new Color(0, 0, 0, 1)]; const POSTPROCESSPASS_INDEX = 0; @@ -130,10 +125,10 @@ export class PostprocessStage extends RenderStage { const builtinPostProcess = builtinResMgr.get('builtin-post-process-material'); if (builtinPostProcess) { pass = builtinPostProcess.passes[0]; - shader = ShaderPool.get(pass.getShaderVariant()); + shader = pass.getShaderVariant()!; } else { pass = this._postprocessMaterial!.passes[POSTPROCESSPASS_INDEX]; - shader = ShaderPool.get(this._postprocessMaterial!.passes[POSTPROCESSPASS_INDEX].getShaderVariant()); + shader = this._postprocessMaterial!.passes[POSTPROCESSPASS_INDEX].getShaderVariant()!; } const inputAssembler = camera.window!.hasOffScreenAttachments ? pipeline.quadIAOffscreen : pipeline.quadIAOnscreen; diff --git a/cocos/core/pipeline/define.ts b/cocos/core/pipeline/define.ts index 32e20d8d395..d36723c9aae 100644 --- a/cocos/core/pipeline/define.ts +++ b/cocos/core/pipeline/define.ts @@ -34,7 +34,7 @@ import { SubModel } from '../renderer/scene/submodel'; import { Layers } from '../scene-graph/layers'; import { legacyCC } from '../global-exports'; import { BindingMappingInfo, DescriptorType, Type, ShaderStageFlagBit, - DescriptorSetLayoutBinding, Uniform, UniformBlock, UniformSamplerTexture, Device, Feature } from '../gfx'; + DescriptorSetLayoutBinding, Uniform, UniformBlock, UniformSamplerTexture, UniformStorageImage, Device, Feature } from '../gfx'; export const PIPELINE_FLOW_GBUFFER = 'GbufferFlow'; export const PIPELINE_FLOW_LIGHTING = 'LightingFlow'; @@ -104,7 +104,7 @@ export interface IRenderQueueDesc { export interface IDescriptorSetLayoutInfo { bindings: DescriptorSetLayoutBinding[]; - layouts: Record; + layouts: Record; } export const globalDescriptorSetLayout: IDescriptorSetLayoutInfo = { bindings: [], layouts: {} }; @@ -146,6 +146,8 @@ export enum ModelLocalBindings { SAMPLER_MORPH_TANGENT, SAMPLER_LIGHTMAP, SAMPLER_SPRITE, + SAMPLER_REFLECTION, + STORAGE_REFLECTION, COUNT, } @@ -344,7 +346,7 @@ export class UBOLocal { public static readonly NAME = 'CCLocal'; public static readonly BINDING = ModelLocalBindings.UBO_LOCAL; - public static readonly DESCRIPTOR = new DescriptorSetLayoutBinding(UBOLocal.BINDING, DescriptorType.UNIFORM_BUFFER, 1, ShaderStageFlagBit.VERTEX); + public static readonly DESCRIPTOR = new DescriptorSetLayoutBinding(UBOLocal.BINDING, DescriptorType.UNIFORM_BUFFER, 1, ShaderStageFlagBit.VERTEX | ShaderStageFlagBit.COMPUTE); public static readonly LAYOUT = new UniformBlock(SetIndex.LOCAL, UBOLocal.BINDING, UBOLocal.NAME, [ new Uniform('cc_matWorld', Type.MAT4, 1), new Uniform('cc_matWorldIT', Type.MAT4, 1), @@ -364,7 +366,7 @@ export class UBOLocalBatched { public static readonly NAME = 'CCLocalBatched'; public static readonly BINDING = ModelLocalBindings.UBO_LOCAL; - public static readonly DESCRIPTOR = new DescriptorSetLayoutBinding(UBOLocalBatched.BINDING, DescriptorType.UNIFORM_BUFFER, 1, ShaderStageFlagBit.VERTEX); + public static readonly DESCRIPTOR = new DescriptorSetLayoutBinding(UBOLocalBatched.BINDING, DescriptorType.UNIFORM_BUFFER, 1, ShaderStageFlagBit.VERTEX | ShaderStageFlagBit.COMPUTE); public static readonly LAYOUT = new UniformBlock(SetIndex.LOCAL, UBOLocalBatched.BINDING, UBOLocalBatched.NAME, [ new Uniform('cc_matWorlds', Type.MAT4, UBOLocalBatched.BATCHING_COUNT), ], 1); @@ -548,6 +550,28 @@ const UNIFORM_SPRITE_TEXTURE_LAYOUT = new UniformSamplerTexture(SetIndex.LOCAL, localDescriptorSetLayout.layouts[UNIFORM_SPRITE_TEXTURE_NAME] = UNIFORM_SPRITE_TEXTURE_LAYOUT; localDescriptorSetLayout.bindings[UNIFORM_SPRITE_TEXTURE_BINDING] = UNIFORM_SPRITE_TEXTURE_DESCRIPTOR; +/** + * @en The sampler for reflection + * @zh 反射纹理采样器。 + */ +const UNIFORM_REFLECTION_TEXTURE_NAME = 'cc_reflectionTexture'; +export const UNIFORM_REFLECTION_TEXTURE_BINDING = ModelLocalBindings.SAMPLER_REFLECTION; +const UNIFORM_REFLECTION_TEXTURE_DESCRIPTOR = new DescriptorSetLayoutBinding(UNIFORM_REFLECTION_TEXTURE_BINDING, DescriptorType.SAMPLER_TEXTURE, 1, ShaderStageFlagBit.FRAGMENT); +const UNIFORM_REFLECTION_TEXTURE_LAYOUT = new UniformSamplerTexture(SetIndex.LOCAL, UNIFORM_REFLECTION_TEXTURE_BINDING, UNIFORM_REFLECTION_TEXTURE_NAME, Type.SAMPLER2D, 1); +localDescriptorSetLayout.layouts[UNIFORM_REFLECTION_TEXTURE_NAME] = UNIFORM_REFLECTION_TEXTURE_LAYOUT; +localDescriptorSetLayout.bindings[UNIFORM_REFLECTION_TEXTURE_BINDING] = UNIFORM_REFLECTION_TEXTURE_DESCRIPTOR; + +/** + * @en The storage image for reflection + * @zh 反射纹理存储。 + */ +const UNIFORM_REFLECTION_STORAGE_NAME = 'cc_reflectionStorage'; +export const UNIFORM_REFLECTION_STORAGE_BINDING = ModelLocalBindings.STORAGE_REFLECTION; +const UNIFORM_REFLECTION_STORAGE_DESCRIPTOR = new DescriptorSetLayoutBinding(UNIFORM_REFLECTION_STORAGE_BINDING, DescriptorType.STORAGE_IMAGE, 1, ShaderStageFlagBit.COMPUTE); +const UNIFORM_REFLECTION_STORAGE_LAYOUT = new UniformStorageImage(SetIndex.LOCAL, UNIFORM_REFLECTION_STORAGE_BINDING, UNIFORM_REFLECTION_STORAGE_NAME, Type.IMAGE2D, 1); +localDescriptorSetLayout.layouts[UNIFORM_REFLECTION_STORAGE_NAME] = UNIFORM_REFLECTION_STORAGE_LAYOUT; +localDescriptorSetLayout.bindings[UNIFORM_REFLECTION_STORAGE_BINDING] = UNIFORM_REFLECTION_STORAGE_DESCRIPTOR; + export const CAMERA_DEFAULT_MASK = Layers.makeMaskExclude([Layers.BitMask.UI_2D, Layers.BitMask.GIZMOS, Layers.BitMask.EDITOR, Layers.BitMask.SCENE_GIZMO, Layers.BitMask.PROFILER]); diff --git a/cocos/core/pipeline/forward/forward-flow.ts b/cocos/core/pipeline/forward/forward-flow.ts index 7bf1000ec72..04e2f10e062 100644 --- a/cocos/core/pipeline/forward/forward-flow.ts +++ b/cocos/core/pipeline/forward/forward-flow.ts @@ -33,10 +33,8 @@ import { PIPELINE_FLOW_FORWARD } from '../define'; import { IRenderFlowInfo, RenderFlow } from '../render-flow'; import { ForwardFlowPriority } from './enum'; import { ForwardStage } from './forward-stage'; -import { ForwardPipeline } from './forward-pipeline'; import { RenderPipeline } from '../render-pipeline'; import { Camera } from '../../renderer/scene'; -import { sceneCulling } from '../scene-culling'; /** * @en The forward flow in forward render pipeline diff --git a/cocos/core/pipeline/forward/ui-phase.ts b/cocos/core/pipeline/forward/ui-phase.ts index 194b1805a22..79065a4f60a 100644 --- a/cocos/core/pipeline/forward/ui-phase.ts +++ b/cocos/core/pipeline/forward/ui-phase.ts @@ -26,7 +26,6 @@ import { RenderPass } from '../../gfx'; import { PipelineStateManager } from '../pipeline-state-manager'; import { SetIndex } from '../define'; -import { IAPool, DSPool, ShaderPool, BatchPool2D, BatchView2D } from '../../renderer/core/memory-pools'; import { Camera } from '../../renderer/scene/camera'; import { ForwardPipeline } from './forward-pipeline'; import { RenderPipeline } from '../render-pipeline'; @@ -54,21 +53,19 @@ export class UIPhase { } if (!visible) continue; - const handle = batch.handle; - const count = BatchPool2D.get(handle, BatchView2D.PASS_COUNT); + const count = batch.passes.length; for (let j = 0; j < count; j++) { const pass = batch.passes[j]; if (pass.phase !== this._phaseID) continue; - const shaderHandle = BatchPool2D.get(handle, BatchView2D.SHADER_0 + j); - const shader = ShaderPool.get(shaderHandle); - const inputAssembler = IAPool.get(batch.hInputAssembler); - const ds = DSPool.get(batch.hDescriptorSet); - const pso = PipelineStateManager.getOrCreatePipelineState(device, pass, shader, renderPass, inputAssembler); + const shader = pass.getShaderVariant(); + const inputAssembler = batch.inputAssembler; + const ds = batch.descriptorSet; + const pso = PipelineStateManager.getOrCreatePipelineState(device, pass, shader!, renderPass, inputAssembler!); cmdBuff.bindPipelineState(pso); cmdBuff.bindDescriptorSet(SetIndex.MATERIAL, pass.descriptorSet); - cmdBuff.bindDescriptorSet(SetIndex.LOCAL, ds); - cmdBuff.bindInputAssembler(inputAssembler); - cmdBuff.draw(inputAssembler); + cmdBuff.bindDescriptorSet(SetIndex.LOCAL, ds!); + cmdBuff.bindInputAssembler(inputAssembler!); + cmdBuff.draw(inputAssembler!); } } } diff --git a/cocos/core/pipeline/global-descriptor-set-manager.ts b/cocos/core/pipeline/global-descriptor-set-manager.ts new file mode 100644 index 00000000000..a8d94bdb2df --- /dev/null +++ b/cocos/core/pipeline/global-descriptor-set-manager.ts @@ -0,0 +1,187 @@ +/* + Copyright (c) 2020 Xiamen Yaji Software Co., Ltd. + + https://www.cocos.com/ + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated engine source code (the "Software"), a limited, + worldwide, royalty-free, non-assignable, revocable and non-exclusive license + to use Cocos Creator solely to develop games on your target platforms. You shall + not use Cocos Creator software for developing other software or tools that's + used for developing games. You are not granted to publish, distribute, + sublicense, and/or sell copies of Cocos Creator. + + The software or tools in this License Agreement are licensed, not sold. + Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + */ + +/** + * @packageDocumentation + * @module pipeline + */ + +import { RenderPipeline } from './render-pipeline'; +import { Device, BufferUsageBit, MemoryUsageBit, BufferInfo, Filter, Address, Sampler, DescriptorSet, + DescriptorSetInfo, Buffer, Texture, DescriptorSetLayoutInfo, DescriptorSetLayout } from '../gfx'; +import { UBOShadow, globalDescriptorSetLayout, PipelineGlobalBindings } from './define'; +import { genSamplerHash, samplerLib } from '../renderer/core/sampler-lib'; + +const _samplerInfo = [ + Filter.LINEAR, + Filter.LINEAR, + Filter.NONE, + Address.CLAMP, + Address.CLAMP, + Address.CLAMP, +]; + +export class GlobalDSManager { + private _device: Device; + private _descriptorSetMap: Map = new Map(); + private _globalDescriptorSet: DescriptorSet; + private _descriptorSetLayout: DescriptorSetLayout; + private _sampler: Sampler; + + get descriptorSetMap () { + return this._descriptorSetMap; + } + + get shadowMapSampler () { + return this._sampler; + } + + get descriptorSetLayout () { + return this._descriptorSetLayout; + } + + get globalDescriptorSet () { + return this._globalDescriptorSet; + } + + constructor (pipeline: RenderPipeline) { + this._device = pipeline.device; + + const shadowMapSamplerHash = genSamplerHash(_samplerInfo); + this._sampler = samplerLib.getSampler(this._device, shadowMapSamplerHash); + + const layoutInfo = new DescriptorSetLayoutInfo(globalDescriptorSetLayout.bindings); + this._descriptorSetLayout = this._device.createDescriptorSetLayout(layoutInfo); + + this._globalDescriptorSet = this._device.createDescriptorSet(new DescriptorSetInfo(this._descriptorSetLayout)); + } + + /** + * @en Bind buffer for all descriptorSets, so that all created descriptorSet buffer are consistent + * @zh 为所有的 descriptorSet 绑定 buffer,使得所有已创建的 descriptorSet buffer 保持一致 + * @param binding The target binding. + * @param buffer The buffer to be bound. + */ + public bindBuffer (binding: number, buffer: Buffer) { + this._globalDescriptorSet.bindBuffer(binding, buffer); + const it = this._descriptorSetMap.values(); + let res = it.next(); + while (!res.done) { + const descriptorSet = res.value; + descriptorSet.bindBuffer(binding, buffer); + res = it.next(); + } + } + + /** + * @en Bind sampler for all descriptorSets, so that all created descriptorSet sampler are consistent + * @zh 为所有的 descriptorSet 绑定 sampler,使得所有已创建的 descriptorSet sampler 保持一致 + * @param binding The target binding. + * @param sampler The sampler to be bound. + */ + public bindSampler (binding: number, sampler: Sampler) { + this._globalDescriptorSet.bindSampler(binding, sampler); + const it = this._descriptorSetMap.values(); + let res = it.next(); + while (!res.done) { + const descriptorSet = res.value; + descriptorSet.bindSampler(binding, sampler); + res = it.next(); + } + } + + /** + * @en Bind texture for all descriptorSets, so that all created descriptorSet texture are consistent + * @zh 为所有的 descriptorSet 绑定 texture,使得所有已创建的 descriptorSet texture 保持一致 + * @param binding The target binding. + * @param texture The texture to be bound. + */ + public bindTexture (binding: number, texture: Texture) { + this._globalDescriptorSet.bindTexture(binding, texture); + const it = this._descriptorSetMap.values(); + let res = it.next(); + while (!res.done) { + const descriptorSet = res.value; + descriptorSet.bindTexture(binding, texture); + res = it.next(); + } + } + + /** + * @en Update all descriptorSet + * @zh 更新所有的 descriptorSet + */ + public update () { + this._globalDescriptorSet.update(); + const it = this._descriptorSetMap.values(); + let res = it.next(); + while (!res.done) { + const descriptorSet = res.value; + descriptorSet.update(); + res = it.next(); + } + } + + /** + * @en The layout of all created descriptorSets in buffer, sampler, and texture (except shadow) is consistent with the globalDescriptorSet + * @zh 所有创建出来的 descriptorSet 在 buffer、 sampler、 texture(shadow 除外)的布局与 globalDescriptorSet 保持一致 + * @param idx Specify index creation + * @return descriptorSet + */ + public getOrCreateDescriptorSet (idx: number) { + const device = this._device; + + // The global descriptorSet is managed by the pipeline and binds the buffer + if (!this._descriptorSetMap.has(idx)) { + const globalDescriptorSet = this._globalDescriptorSet; + const descriptorSet = device.createDescriptorSet(new DescriptorSetInfo(this._descriptorSetLayout)); + this._descriptorSetMap.set(idx, descriptorSet); + + // Create & Sync ALL UBO Buffer, Texture, Sampler + for (let i = PipelineGlobalBindings.UBO_GLOBAL; i < PipelineGlobalBindings.COUNT; i++) { + descriptorSet.bindBuffer(i, globalDescriptorSet.getBuffer(i)); + descriptorSet.bindSampler(i, globalDescriptorSet.getSampler(i)); + descriptorSet.bindTexture(i, globalDescriptorSet.getTexture(i)); + } + + const shadowBUO = device.createBuffer(new BufferInfo( + BufferUsageBit.UNIFORM | BufferUsageBit.TRANSFER_DST, + MemoryUsageBit.HOST | MemoryUsageBit.DEVICE, + UBOShadow.SIZE, + UBOShadow.SIZE, + )); + descriptorSet.bindBuffer(UBOShadow.BINDING, shadowBUO); + + descriptorSet.update(); + } + + return this._descriptorSetMap.get(idx); + } + + public destroy () { + this._descriptorSetLayout.destroy(); + this._sampler.destroy(); + } +} diff --git a/cocos/core/pipeline/index.jsb.ts b/cocos/core/pipeline/index.jsb.ts index 1322d2a9c41..65d49bf4e1e 100644 --- a/cocos/core/pipeline/index.jsb.ts +++ b/cocos/core/pipeline/index.jsb.ts @@ -41,15 +41,12 @@ export const PipelineStateManager = nr.PipelineStateManager; let instancedBufferProto = nr.InstancedBuffer; let oldGetFunc = instancedBufferProto.get; -instancedBufferProto.get = function(pass) { - return oldGetFunc.call(this, pass.handle); -}; let getOrCreatePipelineState = nr.PipelineStateManager.getOrCreatePipelineState; nr.PipelineStateManager.getOrCreatePipelineState = function(device, pass, shader, renderPass, ia) { - return getOrCreatePipelineState.call(this, pass.handle, shader, renderPass, ia); + return getOrCreatePipelineState.call(device, pass.native, shader, renderPass, ia); } - + export function createDefaultPipeline () { const pipeline = new ForwardPipeline(); pipeline.init(); @@ -69,7 +66,7 @@ export class ForwardPipeline extends nr.ForwardPipeline { } public init () { - this.setPipelineSharedSceneData(this.pipelineSceneData.handle); + this.setPipelineSharedSceneData(this.pipelineSceneData.native); for (let i = 0; i < this._flows.length; i++) { this._flows[i].init(); } @@ -82,11 +79,11 @@ export class ForwardPipeline extends nr.ForwardPipeline { } public render (cameras) { - let handles = []; + let nativeObjs = []; for (let i = 0, len = cameras.length; i < len; ++i) { - handles.push(cameras[i].handle); + nativeObjs.push(cameras[i].native) } - super.render(handles); + super.render(nativeObjs); } public destroy () { @@ -189,7 +186,7 @@ export class DeferredPipeline extends nr.DeferredPipeline { } init() { - this.setPipelineSharedSceneData(this.pipelineSceneData.handle); + this.setPipelineSharedSceneData(this.pipelineSceneData.native); for (let i = 0; i < this._flows.length; i++) { this._flows[i].init(); } @@ -202,11 +199,11 @@ export class DeferredPipeline extends nr.DeferredPipeline { } public render (cameras) { - let handles = []; + let nativeObjs = []; for (let i = 0, len = cameras.length; i < len; ++i) { - handles.push(cameras[i].handle); + nativeObjs.push(cameras[i].native) } - super.render(handles); + super.render(nativeObjs); } destroy () { diff --git a/cocos/core/pipeline/instanced-buffer.ts b/cocos/core/pipeline/instanced-buffer.ts index 19375ff6460..9812743d66e 100644 --- a/cocos/core/pipeline/instanced-buffer.ts +++ b/cocos/core/pipeline/instanced-buffer.ts @@ -30,10 +30,9 @@ import { Pass } from '../renderer'; import { IInstancedAttributeBlock, SubModel } from '../renderer/scene'; -import { SubModelView, SubModelPool, ShaderHandle, DescriptorSetHandle } from '../renderer/core/memory-pools'; import { UNIFORM_LIGHTMAP_TEXTURE_BINDING } from './define'; import { BufferUsageBit, MemoryUsageBit, Device, Texture, InputAssembler, InputAssemblerInfo, - Attribute, Buffer, BufferInfo, CommandBuffer } from '../gfx'; + Attribute, Buffer, BufferInfo, CommandBuffer, Shader, DescriptorSet } from '../gfx'; export interface IInstancedItem { count: number; @@ -42,8 +41,8 @@ export interface IInstancedItem { data: Uint8Array; ia: InputAssembler; stride: number; - hShader: ShaderHandle; - hDescriptorSet: DescriptorSetHandle; + shader: Shader | null; + descriptorSet: DescriptorSet; lightingMap: Texture; } @@ -80,16 +79,16 @@ export class InstancedBuffer { this.instances.length = 0; } - public merge (subModel: SubModel, attrs: IInstancedAttributeBlock, passIdx: number, hShaderImplant: ShaderHandle | null = null) { + public merge (subModel: SubModel, attrs: IInstancedAttributeBlock, passIdx: number, shaderImplant: Shader | null = null) { const stride = attrs.buffer.length; if (!stride) { return; } // we assume per-instance attributes are always present const sourceIA = subModel.inputAssembler; const lightingMap = subModel.descriptorSet.getTexture(UNIFORM_LIGHTMAP_TEXTURE_BINDING); - let hShader = hShaderImplant; - if (!hShader) { - hShader = SubModelPool.get(subModel.handle, SubModelView.SHADER_0 + passIdx) as ShaderHandle; + let shader = shaderImplant; + if (!shader) { + shader = subModel.passes[passIdx].getShaderVariant(); } - const hDescriptorSet = SubModelPool.get(subModel.handle, SubModelView.DESCRIPTOR_SET); + const descriptorSet = subModel.descriptorSet; for (let i = 0; i < this.instances.length; ++i) { const instance = this.instances[i]; if (instance.ia.indexBuffer !== sourceIA.indexBuffer || instance.count >= MAX_CAPACITY) { continue; } @@ -111,8 +110,8 @@ export class InstancedBuffer { instance.data.set(oldData); instance.vb.resize(newSize); } - if (instance.hShader !== hShader) { instance.hShader = hShader; } - if (instance.hDescriptorSet !== hDescriptorSet) { instance.hDescriptorSet = hDescriptorSet; } + if (instance.shader !== shader) { instance.shader = shader; } + if (instance.descriptorSet !== descriptorSet) { instance.descriptorSet = descriptorSet; } instance.data.set(attrs.buffer, instance.stride * instance.count++); this.hasPendingModels = true; return; @@ -140,7 +139,7 @@ export class InstancedBuffer { vertexBuffers.push(vb); const iaInfo = new InputAssemblerInfo(attributes, vertexBuffers, indexBuffer); const ia = this._device.createInputAssembler(iaInfo); - this.instances.push({ count: 1, capacity: INITIAL_CAPACITY, vb, data, ia, stride, hShader, hDescriptorSet, lightingMap }); + this.instances.push({ count: 1, capacity: INITIAL_CAPACITY, vb, data, ia, stride, shader, descriptorSet, lightingMap }); this.hasPendingModels = true; } diff --git a/cocos/core/pipeline/pipeline-scene-data.ts b/cocos/core/pipeline/pipeline-scene-data.ts index 2b4ee626c6a..365d2bea844 100644 --- a/cocos/core/pipeline/pipeline-scene-data.ts +++ b/cocos/core/pipeline/pipeline-scene-data.ts @@ -23,6 +23,7 @@ THE SOFTWARE. */ +import { JSB } from 'internal:constants'; import { Fog } from '../renderer/scene/fog'; import { Ambient } from '../renderer/scene/ambient'; import { Skybox } from '../renderer/scene/skybox'; @@ -31,39 +32,59 @@ import { IRenderObject } from './define'; import { Device, Framebuffer } from '../gfx'; import { RenderPipeline } from './render-pipeline'; import { Light } from '../renderer/scene/light'; -import { PipelineSceneDataPool, PipelineSceneDataHandle, PipelineSceneDataView, PassHandle, ShaderHandle } from '../renderer/core/memory-pools'; import { builtinResMgr } from '../builtin/builtin-res-mgr'; import { Material } from '../assets'; +import { NativePipelineSharedSceneData } from '../renderer/scene'; export class PipelineSceneData { - public get handle () { - return this._handle; + private _init (): void { + if (JSB) { + this._nativeObj = new NativePipelineSharedSceneData(); + this._nativeObj.fog = this.fog.native; + this._nativeObj.ambient = this.ambient.native; + this._nativeObj.skybox = this.skybox.native; + this._nativeObj.shadow = this.shadows.native; + } + } + + public get native (): NativePipelineSharedSceneData { + return this._nativeObj!; } + /** * @en Is open HDR. * @zh 是否开启 HDR。 * @readonly */ public get isHDR () { - return PipelineSceneDataPool.get(this._handle, PipelineSceneDataView.IS_HDR) as unknown as boolean; + return this._isHDR; } public set isHDR (val: boolean) { - PipelineSceneDataPool.set(this._handle, PipelineSceneDataView.IS_HDR, val ? 1 : 0); + this._isHDR = val; + if (JSB) { + this._nativeObj!.isHDR = val; + } } public get shadingScale () { - return PipelineSceneDataPool.get(this._handle, PipelineSceneDataView.SHADING_SCALE); + return this._shadingScale; } public set shadingScale (val: number) { - PipelineSceneDataPool.set(this._handle, PipelineSceneDataView.SHADING_SCALE, val); + this._shadingScale = val; + if (JSB) { + this._nativeObj!.shadingScale = val; + } } public get fpScale () { - return PipelineSceneDataPool.get(this._handle, PipelineSceneDataView.FP_SCALE); + return this._fpScale; } public set fpScale (val: number) { - PipelineSceneDataPool.set(this._handle, PipelineSceneDataView.FP_SCALE, val); + this._fpScale = val; + if (JSB) { + this._fpScale = val; + } } public fog: Fog = new Fog(); public ambient: Ambient = new Ambient(); @@ -78,33 +99,15 @@ export class PipelineSceneData { public shadowFrameBufferMap: Map = new Map(); protected declare _device: Device; protected declare _pipeline: RenderPipeline; - protected declare _handle: PipelineSceneDataHandle; + protected declare _nativeObj: NativePipelineSharedSceneData | null; + protected _isHDR = false; + protected _shadingScale = 1.0; + protected _fpScale = 1.0 / 1024.0; constructor () { - this._handle = PipelineSceneDataPool.alloc(); - PipelineSceneDataPool.set(this._handle, PipelineSceneDataView.AMBIENT, this.ambient.handle); - PipelineSceneDataPool.set(this._handle, PipelineSceneDataView.SKYBOX, this.skybox.handle); - PipelineSceneDataPool.set(this._handle, PipelineSceneDataView.FOG, this.fog.handle); - PipelineSceneDataPool.set(this._handle, PipelineSceneDataView.SHADOW, this.shadows.handle); - PipelineSceneDataPool.set(this._handle, PipelineSceneDataView.IS_HDR, 0); - PipelineSceneDataPool.set(this._handle, PipelineSceneDataView.SHADING_SCALE, 1.0); - PipelineSceneDataPool.set(this._handle, PipelineSceneDataView.FP_SCALE, 1.0 / 1024.0); - } - - public get deferredLightPassHandle (): PassHandle { - return PipelineSceneDataPool.get(this._handle, PipelineSceneDataView.DEFERRED_LIGHT_PASS); - } - - public get deferredLightPassShaderHandle (): ShaderHandle { - return PipelineSceneDataPool.get(this._handle, PipelineSceneDataView.DEFERRED_LIGHT_PASS_SHADER); - } - - public get deferredPostPassHandle (): PassHandle { - return PipelineSceneDataPool.get(this._handle, PipelineSceneDataView.DEFERRED_POST_PASS); - } - - public get deferredPostPassShaderHandle (): ShaderHandle { - return PipelineSceneDataPool.get(this._handle, PipelineSceneDataView.DEFERRED_POST_PASS_SHADER); + this._init(); + this.shadingScale = 1.0; + this.fpScale = 1.0 / 1024.0; } public initDeferredPassInfo () { @@ -124,16 +127,17 @@ export class PipelineSceneData { passPost.endChangeStatesSilently(); } - if (builinDeferred) { + if (builinDeferred && JSB) { const passLit = builinDeferred.passes[0]; - PipelineSceneDataPool.set(this._handle, PipelineSceneDataView.DEFERRED_LIGHT_PASS, passLit.handle); - PipelineSceneDataPool.set(this._handle, PipelineSceneDataView.DEFERRED_LIGHT_PASS_SHADER, passLit.getShaderVariant()); + this._nativeObj!.deferredLightPassShader = passLit.getShaderVariant(); + this._nativeObj!.deferredLightPass = passLit.native; } - if (builtinPostProcess) { + if (builtinPostProcess && JSB) { const passPost = builtinPostProcess.passes[0]; - PipelineSceneDataPool.set(this._handle, PipelineSceneDataView.DEFERRED_POST_PASS, passPost.handle); - PipelineSceneDataPool.set(this._handle, PipelineSceneDataView.DEFERRED_POST_PASS_SHADER, passPost.getShaderVariant()); + const shaderHandle = passPost.getShaderVariant(); + this._nativeObj!.deferredPostPassShader = passPost.getShaderVariant(); + this._nativeObj!.deferredPostPass = passPost.native; } } @@ -149,8 +153,8 @@ export class PipelineSceneData { this.skybox.destroy(); this.fog.destroy(); this.shadows.destroy(); - if (this._handle) { - PipelineSceneDataPool.free(this._handle); + if (JSB) { + this._nativeObj = null; } } } diff --git a/cocos/core/pipeline/pipeline-state-manager.ts b/cocos/core/pipeline/pipeline-state-manager.ts index d5b6d732dd6..d3b624e647a 100644 --- a/cocos/core/pipeline/pipeline-state-manager.ts +++ b/cocos/core/pipeline/pipeline-state-manager.ts @@ -29,7 +29,6 @@ */ import { Shader, RenderPass, InputAssembler, Device, PipelineState, InputState, PipelineStateInfo } from '../gfx'; -import { PassPool, PassView, PassHandle, PipelineLayoutPool } from '../renderer/core/memory-pools'; import { Pass } from '../renderer/core/pass'; export class PipelineStateManager { @@ -37,8 +36,7 @@ export class PipelineStateManager { // pass is only needed on TS. static getOrCreatePipelineState (device: Device, pass: Pass, shader: Shader, renderPass: RenderPass, ia: InputAssembler) { - const hPass = pass.handle; - const hash1 = PassPool.get(hPass, PassView.HASH); + const hash1 = pass.hash; const hash2 = renderPass.hash; const hash3 = ia.attributesHash; const hash4 = shader.id; @@ -46,15 +44,15 @@ export class PipelineStateManager { const newHash = hash1 ^ hash2 ^ hash3 ^ hash4; let pso = this._PSOHashMap.get(newHash); if (!pso) { - const pipelineLayout = PipelineLayoutPool.get(PassPool.get(hPass, PassView.PIPELINE_LAYOUT)); + const pipelineLayout = pass.pipelineLayout; const inputState = new InputState(ia.attributes); const psoInfo = new PipelineStateInfo( - shader, pipelineLayout, renderPass, inputState, + shader, pass.pipelineLayout, renderPass, inputState, pass.rasterizerState, pass.depthStencilState, pass.blendState, - PassPool.get(hPass, PassView.PRIMITIVE), - PassPool.get(hPass, PassView.DYNAMIC_STATES), + pass.primitive, + pass.dynamicStates, ); pso = device.createPipelineState(psoInfo); this._PSOHashMap.set(newHash, pso); diff --git a/cocos/core/pipeline/pipeline-ubo.ts b/cocos/core/pipeline/pipeline-ubo.ts index 78d23f25b2c..a3912ccd268 100644 --- a/cocos/core/pipeline/pipeline-ubo.ts +++ b/cocos/core/pipeline/pipeline-ubo.ts @@ -342,18 +342,26 @@ export class PipelineUBO { * @zh 更新全部 UBO。 */ public updateGlobalUBO () { + const globalDSManager = this._pipeline.globalDSManager; const ds = this._pipeline.descriptorSet; const cmdBuffer = this._pipeline.commandBuffers; ds.update(); PipelineUBO.updateGlobalUBOView(this._pipeline, this._globalUBO); cmdBuffer[0].updateBuffer(ds.getBuffer(UBOGlobal.BINDING), this._globalUBO); + + globalDSManager.bindBuffer(UBOGlobal.BINDING, ds.getBuffer(UBOGlobal.BINDING)); + globalDSManager.update(); } public updateCameraUBO (camera: Camera) { + const globalDSManager = this._pipeline.globalDSManager; const ds = this._pipeline.descriptorSet; const cmdBuffer = this._pipeline.commandBuffers; PipelineUBO.updateCameraUBOView(this._pipeline, this._cameraUBO, camera); cmdBuffer[0].updateBuffer(ds.getBuffer(UBOCamera.BINDING), this._cameraUBO); + + globalDSManager.bindBuffer(UBOCamera.BINDING, ds.getBuffer(UBOCamera.BINDING)); + globalDSManager.update(); } public updateShadowUBO (camera: Camera) { diff --git a/cocos/core/pipeline/planar-shadow-queue.ts b/cocos/core/pipeline/planar-shadow-queue.ts index e82a14f56e9..d71aa64a1fd 100644 --- a/cocos/core/pipeline/planar-shadow-queue.ts +++ b/cocos/core/pipeline/planar-shadow-queue.ts @@ -29,7 +29,6 @@ import { CommandBuffer, Device, RenderPass } from '../gfx'; import { InstancedBuffer } from './instanced-buffer'; import { PipelineStateManager } from './pipeline-state-manager'; import { Model, Camera } from '../renderer/scene'; -import { DSPool, ShaderPool, PassPool, PassView } from '../renderer/core/memory-pools'; import { RenderInstancedQueue } from './render-instanced-queue'; import { ShadowType } from '../renderer/scene/shadows'; import { Layers } from '../scene-graph/layers'; @@ -76,7 +75,7 @@ export class PlanarShadowQueue { const subModels = model.subModels; for (let m = 0; m < subModels.length; m++) { const subModel = subModels[m]; - instancedBuffer.merge(subModel, model.instancedAttributes, 0, subModel.planarInstanceShaderHandle); + instancedBuffer.merge(subModel, model.instancedAttributes, 0, subModel.planarInstanceShader); } } else { this._pendingModels.push(model); @@ -93,7 +92,7 @@ export class PlanarShadowQueue { if (!this._pendingModels.length) { return; } const pass = shadows.material.passes[0]; - const descriptorSet = DSPool.get(PassPool.get(pass.handle, PassView.DESCRIPTOR_SET)); + const descriptorSet = pass.descriptorSet; cmdBuff.bindDescriptorSet(SetIndex.MATERIAL, descriptorSet); const modelCount = this._pendingModels.length; @@ -103,9 +102,9 @@ export class PlanarShadowQueue { const subModel = model.subModels[j]; // This is a temporary solution // It should not be written in a fixed way, or modified by the user - const shader = ShaderPool.get(subModel.planarShaderHandle); + const shader = subModel.planarShader; const ia = subModel.inputAssembler; - const pso = PipelineStateManager.getOrCreatePipelineState(device, pass, shader, renderPass, ia); + const pso = PipelineStateManager.getOrCreatePipelineState(device, pass, shader!, renderPass, ia); cmdBuff.bindPipelineState(pso); cmdBuff.bindDescriptorSet(SetIndex.LOCAL, subModel.descriptorSet); cmdBuff.bindInputAssembler(ia); diff --git a/cocos/core/pipeline/render-additive-light-queue.ts b/cocos/core/pipeline/render-additive-light-queue.ts index fb9d8f87fc8..56d558b773d 100644 --- a/cocos/core/pipeline/render-additive-light-queue.ts +++ b/cocos/core/pipeline/render-additive-light-queue.ts @@ -33,12 +33,10 @@ import { RenderPipeline } from './render-pipeline'; import { InstancedBuffer } from './instanced-buffer'; import { Model } from '../renderer/scene/model'; import { PipelineStateManager } from './pipeline-state-manager'; -import { DSPool, ShaderPool, PassView, PassPool, SubModelPool, SubModelView, - ShaderHandle } from '../renderer/core/memory-pools'; import { Vec3, nextPow2, Mat4, Color } from '../math'; import { Sphere, intersect } from '../geometry'; import { Device, RenderPass, Buffer, BufferUsageBit, MemoryUsageBit, - BufferInfo, BufferViewInfo, CommandBuffer, Filter, Address, Sampler, DescriptorSet, DescriptorSetInfo, Feature } from '../gfx'; + BufferInfo, BufferViewInfo, CommandBuffer } from '../gfx'; import { Pool } from '../memop'; import { RenderBatchedQueue } from './render-batched-queue'; import { RenderInstancedQueue } from './render-instanced-queue'; @@ -47,29 +45,18 @@ import { SpotLight } from '../renderer/scene/spot-light'; import { SubModel } from '../renderer/scene/submodel'; import { getPhaseID } from './pass-phase'; import { Light, LightType } from '../renderer/scene/light'; -import { SetIndex, UBOForwardLight, UBOGlobal, UBOShadow, UBOCamera, UNIFORM_SHADOWMAP_BINDING, +import { SetIndex, UBOForwardLight, UBOGlobal, UBOShadow, UNIFORM_SHADOWMAP_BINDING, UNIFORM_SPOT_LIGHTING_MAP_TEXTURE_BINDING, supportsHalfFloatTexture } from './define'; -import { genSamplerHash, samplerLib } from '../renderer/core/sampler-lib'; -import { builtinResMgr } from '../builtin/builtin-res-mgr'; -import { Texture2D } from '../assets/texture-2d'; import { updatePlanarPROJ } from './scene-culling'; import { Camera } from '../renderer/scene'; - -const _samplerInfo = [ - Filter.LINEAR, - Filter.LINEAR, - Filter.NONE, - Address.CLAMP, - Address.CLAMP, - Address.CLAMP, -]; +import { GlobalDSManager } from './global-descriptor-set-manager'; interface IAdditiveLightPass { subModel: SubModel; passIdx: number; dynamicOffsets: number[]; - lights: Light[]; + lights: number[]; } const _lightPassPool = new Pool(() => ({ subModel: null!, passIdx: -1, dynamicOffsets: [], lights: [] }), 16); @@ -118,7 +105,6 @@ export class RenderAdditiveLightQueue { private _device: Device; private _validLights: Light[] = []; private _lightPasses: IAdditiveLightPass[] = []; - private _descriptorSetMap: Map = new Map(); private _shadowUBO = new Float32Array(UBOShadow.COUNT); private _lightBufferCount = 16; private _lightBufferStride: number; @@ -130,8 +116,6 @@ export class RenderAdditiveLightQueue { private _batchedQueue: RenderBatchedQueue; private _lightMeterScale = 10000.0; - private _sampler: Sampler | null = null; - constructor (pipeline: RenderPipeline) { this._pipeline = pipeline; this._device = pipeline.device; @@ -152,9 +136,6 @@ export class RenderAdditiveLightQueue { this._firstLightBufferView = this._device.createBuffer(new BufferViewInfo(this._lightBuffer, 0, UBOForwardLight.SIZE)); this._lightBufferData = new Float32Array(this._lightBufferElementCount * this._lightBufferCount); - - const shadowMapSamplerHash = genSamplerHash(_samplerInfo); - this._sampler = samplerLib.getSampler(this._device, shadowMapSamplerHash); } public clear () { @@ -173,11 +154,13 @@ export class RenderAdditiveLightQueue { } public destroy () { - const descriptorSets = Array.from(this._descriptorSetMap.values()); - for (let i = 0; i < descriptorSets.length; ++i) { - const descriptorSet = descriptorSets[i]; + const descriptorSetMap = this._pipeline.globalDSManager.descriptorSetMap; + const keys = descriptorSetMap.keys; + + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + const descriptorSet = descriptorSetMap.get(key)!; if (descriptorSet) { - descriptorSet.getBuffer(UBOGlobal.BINDING).destroy(); descriptorSet.getBuffer(UBOShadow.BINDING).destroy(); descriptorSet.getSampler(UNIFORM_SHADOWMAP_BINDING).destroy(); descriptorSet.getSampler(UNIFORM_SPOT_LIGHTING_MAP_TEXTURE_BINDING).destroy(); @@ -185,8 +168,8 @@ export class RenderAdditiveLightQueue { descriptorSet.getTexture(UNIFORM_SPOT_LIGHTING_MAP_TEXTURE_BINDING).destroy(); descriptorSet.destroy(); } + descriptorSetMap.delete(key); } - this._descriptorSetMap.clear(); } public gatherLightPasses (camera: Camera, cmdBuff: CommandBuffer) { @@ -232,13 +215,14 @@ export class RenderAdditiveLightQueue { this._instancedQueue.recordCommandBuffer(device, renderPass, cmdBuff); this._batchedQueue.recordCommandBuffer(device, renderPass, cmdBuff); + const globalDSManager: GlobalDSManager = this._pipeline.globalDSManager; for (let i = 0; i < this._lightPasses.length; i++) { const { subModel, passIdx, dynamicOffsets, lights } = this._lightPasses[i]; - const shader = ShaderPool.get(SubModelPool.get(subModel.handle, SubModelView.SHADER_0 + passIdx) as ShaderHandle); const pass = subModel.passes[passIdx]; + const shader = pass.getShaderVariant(); const ia = subModel.inputAssembler; - const pso = PipelineStateManager.getOrCreatePipelineState(device, pass, shader, renderPass, ia); - const matDS = DSPool.get(PassPool.get(pass.handle, PassView.DESCRIPTOR_SET)); + const pso = PipelineStateManager.getOrCreatePipelineState(device, pass, shader!, renderPass, ia); + const matDS = pass.descriptorSet; const localDS = subModel.descriptorSet; cmdBuff.bindPipelineState(pso); @@ -247,9 +231,9 @@ export class RenderAdditiveLightQueue { for (let j = 0; j < dynamicOffsets.length; ++j) { const light = lights[j]; - const descriptorSet = this._getOrCreateDescriptorSet(light); + const descriptorSet = globalDSManager.getOrCreateDescriptorSet(light)!; _dynamicOffsets[0] = dynamicOffsets[j]; - cmdBuff.bindDescriptorSet(SetIndex.GLOBAL, descriptorSet!); + cmdBuff.bindDescriptorSet(SetIndex.GLOBAL, descriptorSet); cmdBuff.bindDescriptorSet(SetIndex.LOCAL, localDS, _dynamicOffsets); cmdBuff.draw(ia); } @@ -268,7 +252,6 @@ export class RenderAdditiveLightQueue { Sphere.set(_sphere, light.position.x, light.position.y, light.position.z, light.range); if (intersect.sphereFrustum(_sphere, camera.frustum)) { validLights.push(light); - this._getOrCreateDescriptorSet(light); } } const { spotLights } = camera.scene!; @@ -281,7 +264,6 @@ export class RenderAdditiveLightQueue { Sphere.set(_sphere, light.position.x, light.position.y, light.position.z, light.range); if (intersect.sphereFrustum(_sphere, camera.frustum)) { validLights.push(light); - this._getOrCreateDescriptorSet(light); } } } @@ -331,7 +313,7 @@ export class RenderAdditiveLightQueue { lp.passIdx = lightPassIdx; for (let l = 0; l < _lightIndices.length; l++) { const idx = _lightIndices[l]; - lp.lights.push(validLights[idx]); + lp.lights.push(idx); lp.dynamicOffsets.push(this._lightBufferStride * idx); } @@ -349,10 +331,11 @@ export class RenderAdditiveLightQueue { const isSupportHalfFloat = supportsHalfFloatTexture(device); const linear = (shadowInfo.linear && isSupportHalfFloat) ? 1.0 : 0.0; const packing = shadowInfo.packing ? 1.0 : (isSupportHalfFloat ? 0.0 : 1.0); + const globalDSManager: GlobalDSManager = this._pipeline.globalDSManager; for (let i = 0; i < this._validLights.length; i++) { const light = this._validLights[i]; - const descriptorSet = this._getOrCreateDescriptorSet(light); + const descriptorSet = globalDSManager.getOrCreateDescriptorSet(i); if (!descriptorSet) { continue; } switch (light.type) { case LightType.SPHERE: @@ -408,11 +391,9 @@ export class RenderAdditiveLightQueue { // Spot light sampler binding if (shadowFrameBufferMap.has(light)) { - if (shadowFrameBufferMap.has(light)) { - const texture = shadowFrameBufferMap.get(light)?.colorTextures[0]; - if (texture) { - descriptorSet.bindTexture(UNIFORM_SPOT_LIGHTING_MAP_TEXTURE_BINDING, texture); - } + const texture = shadowFrameBufferMap.get(light)?.colorTextures[0]; + if (texture) { + descriptorSet.bindTexture(UNIFORM_SPOT_LIGHTING_MAP_TEXTURE_BINDING, texture); } } break; @@ -503,36 +484,4 @@ export class RenderAdditiveLightQueue { cmdBuff.updateBuffer(this._lightBuffer, this._lightBufferData); } - - protected _getOrCreateDescriptorSet (light: Light) { - if (!this._descriptorSetMap.has(light)) { - const device = this._device; - const descriptorSet = device.createDescriptorSet(new DescriptorSetInfo(this._pipeline.descriptorSetLayout)); - - descriptorSet.bindBuffer(UBOGlobal.BINDING, this._pipeline.descriptorSet.getBuffer(UBOGlobal.BINDING)); - - descriptorSet.bindBuffer(UBOCamera.BINDING, this._pipeline.descriptorSet.getBuffer(UBOCamera.BINDING)); - - const shadowBUO = device.createBuffer(new BufferInfo( - BufferUsageBit.UNIFORM | BufferUsageBit.TRANSFER_DST, - MemoryUsageBit.HOST | MemoryUsageBit.DEVICE, - UBOShadow.SIZE, - UBOShadow.SIZE, - )); - descriptorSet.bindBuffer(UBOShadow.BINDING, shadowBUO); - - descriptorSet.bindSampler(UNIFORM_SHADOWMAP_BINDING, this._sampler!); - descriptorSet.bindTexture(UNIFORM_SHADOWMAP_BINDING, builtinResMgr.get('default-texture').getGFXTexture()!); - descriptorSet.bindSampler(UNIFORM_SPOT_LIGHTING_MAP_TEXTURE_BINDING, this._sampler!); - descriptorSet.bindTexture(UNIFORM_SPOT_LIGHTING_MAP_TEXTURE_BINDING, builtinResMgr.get('default-texture').getGFXTexture()!); - - descriptorSet.update(); - - this._descriptorSetMap.set(light, descriptorSet); - - return descriptorSet; - } - - return this._descriptorSetMap.get(light); - } } diff --git a/cocos/core/pipeline/render-batched-queue.ts b/cocos/core/pipeline/render-batched-queue.ts index 34e8ae4e0af..ec74f25ee63 100644 --- a/cocos/core/pipeline/render-batched-queue.ts +++ b/cocos/core/pipeline/render-batched-queue.ts @@ -31,7 +31,6 @@ import { BatchedBuffer } from './batched-buffer'; import { PipelineStateManager } from './pipeline-state-manager'; import { RenderPass, Device, CommandBuffer } from '../gfx'; -import { DSPool, ShaderPool, PassPool, PassView } from '../renderer/core/memory-pools'; import { SetIndex } from './define'; /** @@ -87,8 +86,8 @@ export class RenderBatchedQueue { const batch = res.value.batches[b]; if (!batch.mergeCount) { continue; } if (!boundPSO) { - const shader = ShaderPool.get(batch.hShader); - const pso = PipelineStateManager.getOrCreatePipelineState(device, batch.pass, shader, renderPass, batch.ia); + const shader = batch.shader; + const pso = PipelineStateManager.getOrCreatePipelineState(device, batch.pass, shader!, renderPass, batch.ia); cmdBuff.bindPipelineState(pso); cmdBuff.bindDescriptorSet(SetIndex.MATERIAL, batch.pass.descriptorSet); boundPSO = true; diff --git a/cocos/core/pipeline/render-instanced-queue.ts b/cocos/core/pipeline/render-instanced-queue.ts index 1ff24e7a8c9..1beae719dec 100644 --- a/cocos/core/pipeline/render-instanced-queue.ts +++ b/cocos/core/pipeline/render-instanced-queue.ts @@ -31,7 +31,6 @@ import { InstancedBuffer } from './instanced-buffer'; import { Device, RenderPass, PipelineState, CommandBuffer } from '../gfx'; import { PipelineStateManager } from './pipeline-state-manager'; -import { DSPool, ShaderPool, PassPool, PassView } from '../renderer/core/memory-pools'; import { SetIndex } from './define'; /** @@ -81,13 +80,13 @@ export class RenderInstancedQueue { for (let b = 0; b < instances.length; ++b) { const instance = instances[b]; if (!instance.count) { continue; } - const shader = ShaderPool.get(instance.hShader); - const pso = PipelineStateManager.getOrCreatePipelineState(device, pass, shader, renderPass, instance.ia); + const shader = instance.shader; + const pso = PipelineStateManager.getOrCreatePipelineState(device, pass, shader!, renderPass, instance.ia); if (lastPSO !== pso) { cmdBuff.bindPipelineState(pso); lastPSO = pso; } - cmdBuff.bindDescriptorSet(SetIndex.LOCAL, DSPool.get(instance.hDescriptorSet), res.value.dynamicOffsets); + cmdBuff.bindDescriptorSet(SetIndex.LOCAL, instance.descriptorSet, res.value.dynamicOffsets); cmdBuff.bindInputAssembler(instance.ia); cmdBuff.draw(instance.ia); } diff --git a/cocos/core/pipeline/render-pipeline.ts b/cocos/core/pipeline/render-pipeline.ts index d6dd16ebb08..d298cb3c3bd 100644 --- a/cocos/core/pipeline/render-pipeline.ts +++ b/cocos/core/pipeline/render-pipeline.ts @@ -33,11 +33,11 @@ import { legacyCC } from '../global-exports'; import { Asset } from '../assets/asset'; import { RenderFlow } from './render-flow'; import { MacroRecord } from '../renderer/core/pass-utils'; -import { Device, DescriptorSet, CommandBuffer, DescriptorSetLayout, DescriptorSetLayoutInfo, DescriptorSetInfo, Feature, Rect } from '../gfx'; -import { globalDescriptorSetLayout } from './define'; +import { Device, DescriptorSet, CommandBuffer, Feature, Rect } from '../gfx'; import { Camera } from '../renderer/scene/camera'; import { PipelineUBO } from './pipeline-ubo'; import { PipelineSceneData } from './pipeline-scene-data'; +import { GlobalDSManager } from './global-descriptor-set-manager'; /** * @en Render pipeline information descriptor @@ -121,8 +121,12 @@ export abstract class RenderPipeline extends Asset { return this._device; } + get globalDSManager () { + return this._globalDSManager; + } + get descriptorSetLayout () { - return this._descriptorSetLayout; + return this._globalDSManager.descriptorSetLayout; } get descriptorSet () { @@ -142,7 +146,7 @@ export abstract class RenderPipeline extends Asset { } protected _device!: Device; - protected _descriptorSetLayout!: DescriptorSetLayout; + protected _globalDSManager!: GlobalDSManager; protected _descriptorSet!: DescriptorSet; protected _commandBuffers: CommandBuffer[] = []; protected _pipelineUBO = new PipelineUBO(); @@ -187,9 +191,8 @@ export abstract class RenderPipeline extends Asset { */ public activate (): boolean { this._device = legacyCC.director.root.device; - const layoutInfo = new DescriptorSetLayoutInfo(globalDescriptorSetLayout.bindings); - this._descriptorSetLayout = this._device.createDescriptorSetLayout(layoutInfo); - this._descriptorSet = this._device.createDescriptorSet(new DescriptorSetInfo(this._descriptorSetLayout)); + this._globalDSManager = new GlobalDSManager(this); + this._descriptorSet = this._globalDSManager.globalDescriptorSet; this._pipelineUBO.activate(this._device, this); this._pipelineSceneData.activate(this._device, this); @@ -230,9 +233,10 @@ export abstract class RenderPipeline extends Asset { if (this._descriptorSet) { this._descriptorSet.destroy(); - this._descriptorSet = null!; } + this._globalDSManager.destroy(); + for (let i = 0; i < this._commandBuffers.length; i++) { this._commandBuffers[i].destroy(); } diff --git a/cocos/core/pipeline/render-queue.ts b/cocos/core/pipeline/render-queue.ts index 721e8ba64f6..1395a1b36e0 100644 --- a/cocos/core/pipeline/render-queue.ts +++ b/cocos/core/pipeline/render-queue.ts @@ -33,7 +33,6 @@ import { CachedArray } from '../memop/cached-array'; import { IRenderObject, IRenderPass, IRenderQueueDesc, SetIndex } from './define'; import { PipelineStateManager } from './pipeline-state-manager'; import { RenderPass, Device, CommandBuffer } from '../gfx'; -import { PassPool, PassView, DSPool, SubModelView, SubModelPool, ShaderPool, PassHandle, ShaderHandle } from '../renderer/core/memory-pools'; import { RenderQueueDesc, RenderQueueSortMode } from './pipeline-serialization'; import { getPhaseID } from './pass-phase'; @@ -103,16 +102,16 @@ export class RenderQueue { */ public insertRenderPass (renderObj: IRenderObject, subModelIdx: number, passIdx: number): boolean { const subModel = renderObj.model.subModels[subModelIdx]; - const hPass = SubModelPool.get(subModel.handle, SubModelView.PASS_0 + passIdx) as PassHandle; - const isTransparent = subModel.passes[passIdx].blendState.targets[0].blend; - if (isTransparent !== this._passDesc.isTransparent || !(PassPool.get(hPass, PassView.PHASE) & this._passDesc.phases)) { + const pass = subModel.passes[passIdx]; + const isTransparent = pass.blendState.targets[0].blend; + if (isTransparent !== this._passDesc.isTransparent || !(pass.phase & this._passDesc.phases)) { return false; } - const hash = (0 << 30) | PassPool.get(hPass, PassView.PRIORITY) << 16 | subModel.priority << 8 | passIdx; + const hash = (0 << 30) | pass.priority << 16 | subModel.priority << 8 | passIdx; const rp = this._passPool.add(); rp.hash = hash; rp.depth = renderObj.depth || 0; - rp.shaderId = SubModelPool.get(subModel.handle, SubModelView.SHADER_0 + passIdx) as number; + rp.shaderId = pass.getShaderVariant()!.id; rp.subModel = subModel; rp.passIdx = passIdx; this.queue.push(rp); @@ -130,10 +129,10 @@ export class RenderQueue { public recordCommandBuffer (device: Device, renderPass: RenderPass, cmdBuff: CommandBuffer) { for (let i = 0; i < this.queue.length; ++i) { const { subModel, passIdx } = this.queue.array[i]; - const { inputAssembler, handle: hSubModel } = subModel; + const { inputAssembler } = subModel; const pass = subModel.passes[passIdx]; - const shader = ShaderPool.get(SubModelPool.get(hSubModel, SubModelView.SHADER_0 + passIdx) as ShaderHandle); - const pso = PipelineStateManager.getOrCreatePipelineState(device, pass, shader, renderPass, inputAssembler); + const shader = pass.getShaderVariant(); + const pso = PipelineStateManager.getOrCreatePipelineState(device, pass, shader!, renderPass, inputAssembler); cmdBuff.bindPipelineState(pso); cmdBuff.bindDescriptorSet(SetIndex.MATERIAL, pass.descriptorSet); cmdBuff.bindDescriptorSet(SetIndex.LOCAL, subModel.descriptorSet); diff --git a/cocos/core/pipeline/render-shadow-map-batched-queue.ts b/cocos/core/pipeline/render-shadow-map-batched-queue.ts index 2a4ba3ab582..4538ca3aa74 100644 --- a/cocos/core/pipeline/render-shadow-map-batched-queue.ts +++ b/cocos/core/pipeline/render-shadow-map-batched-queue.ts @@ -33,7 +33,6 @@ import { SetIndex, UBOShadow } from './define'; import { Device, RenderPass, Buffer, Shader, CommandBuffer } from '../gfx'; import { getPhaseID } from './pass-phase'; import { PipelineStateManager } from './pipeline-state-manager'; -import { ShaderPool, SubModelPool, SubModelView, ShaderHandle } from '../renderer/core/memory-pools'; import { Pass, BatchingSchemes } from '../renderer/core/pass'; import { RenderInstancedQueue } from './render-instanced-queue'; import { InstancedBuffer } from './instanced-buffer'; @@ -126,14 +125,11 @@ export class RenderShadowMapBatchedQueue { public add (model: Model, cmdBuff: CommandBuffer, _shadowPassIndices: number[]) { const subModels = model.subModels; - const shadowMapBuffer = this._pipeline.descriptorSet.getBuffer(UBOShadow.BINDING); for (let j = 0; j < subModels.length; j++) { const subModel = subModels[j]; const shadowPassIdx = _shadowPassIndices[j]; const pass = subModel.passes[shadowPassIdx]; const batchingScheme = pass.batchingScheme; - subModel.descriptorSet.bindBuffer(UBOShadow.BINDING, shadowMapBuffer); - subModel.descriptorSet.update(); if (batchingScheme === BatchingSchemes.INSTANCING) { // instancing const buffer = InstancedBuffer.get(pass); @@ -144,9 +140,9 @@ export class RenderShadowMapBatchedQueue { buffer.merge(subModel, shadowPassIdx, model); this._batchedQueue.queue.add(buffer); } else { - const shader = ShaderPool.get(SubModelPool.get(subModel.handle, SubModelView.SHADER_0 + shadowPassIdx) as ShaderHandle); + const shader = pass.getShaderVariant(); this._subModelsArray.push(subModel); - this._shaderArray.push(shader); + if (shader) this._shaderArray.push(shader); this._passArray.push(pass); } } diff --git a/cocos/core/pipeline/scene-culling.ts b/cocos/core/pipeline/scene-culling.ts index 154a7206002..9e6d644377c 100644 --- a/cocos/core/pipeline/scene-culling.ts +++ b/cocos/core/pipeline/scene-culling.ts @@ -222,14 +222,15 @@ export function sceneCulling (pipeline: RenderPipeline, camera: Camera) { } const models = scene.models; + const visibility = camera.visibility; for (let i = 0; i < models.length; i++) { const model = models[i]; // filter model by view visibility if (model.enabled) { - if (model.node && ((camera.visibility & model.node.layer) === model.node.layer) - || (camera.visibility & model.visFlags)) { + if (model.node && ((visibility & model.node.layer) === model.node.layer) + || (visibility & model.visFlags)) { // shadow render Object if (shadowObjects != null && model.castShadow && model.worldBounds) { if (!_castBoundsInited) { diff --git a/cocos/core/platform/deprecated.ts b/cocos/core/platform/deprecated.ts index df75eb03d0d..6b204b997c6 100644 --- a/cocos/core/platform/deprecated.ts +++ b/cocos/core/platform/deprecated.ts @@ -23,10 +23,13 @@ THE SOFTWARE. */ -import { removeProperty, replaceProperty } from '../utils'; -import { EventMouse, EventTouch, SystemEvent } from './event-manager'; +import { markAsWarning, removeProperty, replaceProperty } from '../utils'; +import { Event } from '../event'; +import { EventKeyboard, EventMouse, EventTouch, SystemEvent, SystemEventType } from './event-manager'; import { sys } from './sys'; import { View } from './view'; +import { Node } from '../scene-graph'; +import { macro } from './macro'; removeProperty(View.prototype, 'View.prototype', [ { @@ -39,54 +42,104 @@ removeProperty(View.prototype, 'View.prototype', [ }, ]); -// depracate EventMouse static property +// deprecate Event property +replaceProperty(Event, 'Event', [ + { + name: 'NO_TYPE', + target: SystemEventType, + targetName: 'SystemEventType', + }, + { + name: 'ACCELERATION', + newName: 'DEVICEMOTION', + target: SystemEvent.DeviceEvent, + targetName: 'SystemEvent.DeviceEvent', + }, +]); + +markAsWarning(Event, 'Event', [ + { + name: 'TOUCH', + suggest: 'please use SystemEvent.TouchEvent.TOUCH_START, SystemEvent.TouchEvent.TOUCH_MOVE, SystemEvent.TouchEvent.TOUCH_END and SystemEvent.TouchEvent.TOUCH_CANCEL instead', + }, + { + name: 'MOUSE', + suggest: 'please use SystemEvent.MouseEvent.MOUSE_DOWN, SystemEvent.MouseEvent.MOUSE_MOVE, SystemEvent.MouseEvent.MOUSE_UP, SystemEvent.MouseEvent.MOUSE_WHEEL, Node.EventType.MOUSE_ENTER and Node.EventType.MOUSE_LEAVE instead', + }, + { + name: 'KEYBOARD', + suggest: 'please use SystemEvent.KeyboardEvent.KEY_DOWN and SystemEvent.KeyboardEvent.KEY_UP instead', + }, +]); + +// depracate EventMouse property replaceProperty(EventMouse, 'EventMouse', ['DOWN', 'UP', 'MOVE'].map((item) => ({ name: item, newName: `MOUSE_${item}`, - target: SystemEvent.EventType, - targetName: 'SystemEvent.EventType', + target: SystemEvent.MouseEvent, + targetName: 'SystemEvent.MouseEvent', }))); replaceProperty(EventMouse, 'EventMouse', [ { name: 'SCROLL', newName: 'MOUSE_WHEEL', - target: SystemEvent.EventType, - targetName: 'SystemEvent.EventType', + target: SystemEvent.MouseEvent, + targetName: 'SystemEvent.MouseEvent', + }, +]); +markAsWarning(EventMouse.prototype, 'EventMouse.prototype', [ + { + name: 'eventType', + suggest: 'please use EventMouse.prototype.type instead', }, ]); -// depracate EventTouch static property +// depracate EventTouch property replaceProperty(EventTouch, 'EventTouch', [ { name: 'BEGAN', newName: 'TOUCH_START', - target: SystemEvent.EventType, - targetName: 'SystemEvent.EventType', + target: SystemEvent.TouchEvent, + targetName: 'SystemEvent.TouchEvent', }, ]); replaceProperty(EventTouch, 'EventTouch', [ { name: 'MOVED', newName: 'TOUCH_MOVE', - target: SystemEvent.EventType, - targetName: 'SystemEvent.EventType', + target: SystemEvent.TouchEvent, + targetName: 'SystemEvent.TouchEvent', }, ]); replaceProperty(EventTouch, 'EventTouch', [ { name: 'ENDED', newName: 'TOUCH_END', - target: SystemEvent.EventType, - targetName: 'SystemEvent.EventType', + target: SystemEvent.TouchEvent, + targetName: 'SystemEvent.TouchEvent', }, ]); replaceProperty(EventTouch, 'EventTouch', [ { name: 'CANCELLED', newName: 'TOUCH_CANCEL', - target: SystemEvent.EventType, - targetName: 'SystemEvent.EventType', + target: SystemEvent.TouchEvent, + targetName: 'SystemEvent.TouchEvent', + }, +]); +markAsWarning(EventTouch.prototype, 'EventTouch.prototype', [ + { + name: 'getEventCode', + suggest: 'please use EventTouch.prototype.type instead', + }, +]); + +// deprecated EventKeyboard property +markAsWarning(EventKeyboard.prototype, 'EventKeyboard.prototype', [ + { + name: 'isPressed', + suggest: 'use EventKeyboard.prototype.type !== SystemEvent.KeyboardEvent.KEY_UP instead', }, ]); @@ -161,3 +214,92 @@ removeProperty(sys, 'sys', 'WINRT', 'WP8', 'QQ_PLAY', 'FB_PLAYABLE_ADS'].map((item) => ({ name: item, }))); + +// deprecate KEY event +markAsWarning(SystemEventType, 'SystemEventType', [ + { + name: 'KEY_DOWN', + suggest: 'please use SystemEvent.KeyboardEvent.KEY_DOWN instead. The SystemEventType.KEY_DOWN event will be continuously dispatched in the key pressed state, it\'s not a good API design for developers.', + }, + { + name: 'KEY_UP', + suggest: 'please use SystemEvent.KeyboardEvent.KEY_UP instead.', + }, +]); + +replaceProperty(SystemEventType, 'SystemEventType', [ + 'MOUSE_ENTER', + 'MOUSE_LEAVE', + 'TRANSFORM_CHANGED', + 'SCENE_CHANGED_FOR_PERSISTS', + 'SIZE_CHANGED', + 'ANCHOR_CHANGED', + 'COLOR_CHANGED', + 'CHILD_ADDED', + 'CHILD_REMOVED', + 'PARENT_CHANGED', + 'NODE_DESTROYED', + 'LAYER_CHANGED', + 'SIBLING_ORDER_CHANGED', +].map((name: string) => ({ + name, + target: Node.EventType, + targetName: 'Node.EventType', +}))); + +replaceProperty(Node.EventType, 'Node.EventType', [ + { + name: 'DEVICEMOTION', + target: SystemEventType, + targetName: 'SystemEventType', + }, + { + name: 'KEY_DOWN', + target: SystemEventType, + targetName: 'SystemEventType', + }, + { + name: 'KEY_UP', + target: SystemEventType, + targetName: 'SystemEventType', + }, +]); + +markAsWarning(macro.KEY, 'macro.KEY', + [ + 'back', + 'menu', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', + '*', '+', '-', '/', ';', '=', ',', '.', '[', ']', + 'dpadLeft', 'dpadRight', 'dpadUp', 'dpadDown', 'dpadCenter', + ].map((item) => ({ + name: item, + }))); + +markAsWarning(macro.KEY, 'macro.KEY', [ + { + name: 'shift', + suggest: 'please use SystemEvent.KeyCode.SHIFT_LEFT instead', + }, +]); + +markAsWarning(macro.KEY, 'macro.KEY', [ + { + name: 'ctrl', + suggest: 'please use SystemEvent.KeyCode.CTRL_LEFT instead', + }, +]); + +markAsWarning(macro.KEY, 'macro.KEY', [ + { + name: 'alt', + suggest: 'please use SystemEvent.KeyCode.ALT_LEFT instead', + }, +]); + +markAsWarning(macro, 'macro', [ + { + name: 'KEY', + suggest: 'please use SystemEvent.KeyCode instead', + }, +]); diff --git a/cocos/core/platform/event-manager/event-enum.ts b/cocos/core/platform/event-manager/event-enum.ts index 7693c1a5767..f0e9ac36474 100644 --- a/cocos/core/platform/event-manager/event-enum.ts +++ b/cocos/core/platform/event-manager/event-enum.ts @@ -29,15 +29,129 @@ */ import { ccenum } from '../../value-types/enum'; import { legacyCC } from '../../global-exports'; +import { NodeEventType } from '../../scene-graph/node-event'; + +export enum TouchEvent { + /** + * @en + * The event type for touch start event + * + * @zh + * 手指开始触摸事件。 + */ + TOUCH_START = 'touch-start', + + /** + * @en + * The event type for touch move event + * + * @zh + * 当手指在屏幕上移动时。 + */ + TOUCH_MOVE = 'touch-move', + + /** + * @en + * The event type for touch end event + * + * @zh + * 手指结束触摸事件。 + */ + TOUCH_END = 'touch-end', + + /** + * @en + * The event type for touch end event + * + * @zh + * 当手指在目标节点区域外离开屏幕时。 + */ + TOUCH_CANCEL = 'touch-cancel', +} + +export enum MouseEvent { + /** + * @en + * The event type for mouse down events + * + * @zh + * 当鼠标按下时触发一次。 + */ + MOUSE_DOWN = 'mouse-down', + + /** + * @en + * The event type for mouse move events + * + * @zh + * 当鼠标在目标节点在目标节点区域中移动时,不论是否按下。 + */ + MOUSE_MOVE = 'mouse-move', + + /** + * @en + * The event type for mouse up events + * + * @zh + * 当鼠标从按下状态松开时触发一次。 + */ + MOUSE_UP = 'mouse-up', + + /** + * @en + * The event type for mouse wheel events + * + * @zh 手指开始触摸事件 + */ + MOUSE_WHEEL = 'mouse-wheel', +} + +export enum KeyboardEvent { + /** + * @en The event type for press the key down event + * @zh 当按下按键时触发的事件 + */ + KEY_DOWN = 'keyboarddown', // NOTE: different value with SystemEventType.KEY_DOWN + + /** + * @en The event type for press the key up event + * @zh 当松开按键时触发的事件 + */ + KEY_UP = 'keyup', // NOTE: same value with SystemEventType.KEY_UP +} + +export enum DeviceEvent { + /** + * @en + * The event type for press the devicemotion event + * + * @zh + * 重力感应 + */ + DEVICEMOTION = 'devicemotion', + + // TODO: add resize, orientation changed event +} /** * @en The event type supported by SystemEvent and Node events * @zh SystemEvent 支持的事件类型以及节点事件类型 + * + * @deprecated since v3.3, please use SystemEvent.TouchEvent, SystemEvent.MouseEvent, SystemEvent.KeyboardEvent, SystemEvent.DeviceEvent and Node.EventType instead */ export enum SystemEventType { /** * @en - * The event type for touch start event, you can use its value directly: 'touchstart'. + * Code for event without type. + * + * @zh + * 没有类型的事件。 + */ + NO_TYPE = 'no_type', + + /** + * @en + * The event type for touch start event * * @zh * 手指开始触摸事件。 @@ -46,7 +160,7 @@ export enum SystemEventType { /** * @en - * The event type for touch move event, you can use its value directly: 'touchmove'. + * The event type for touch move event * * @zh * 当手指在屏幕上移动时。 @@ -55,7 +169,7 @@ export enum SystemEventType { /** * @en - * The event type for touch end event, you can use its value directly: 'touchend'. + * The event type for touch end event * * @zh * 手指结束触摸事件。 @@ -64,7 +178,7 @@ export enum SystemEventType { /** * @en - * The event type for touch end event, you can use its value directly: 'touchcancel'. + * The event type for touch end event * * @zh * 当手指在目标节点区域外离开屏幕时。 @@ -73,7 +187,7 @@ export enum SystemEventType { /** * @en - * The event type for mouse down events, you can use its value directly: 'mousedown'. + * The event type for mouse down events * * @zh * 当鼠标按下时触发一次。 @@ -82,7 +196,7 @@ export enum SystemEventType { /** * @en - * The event type for mouse move events, you can use its value directly: 'mousemove'. + * The event type for mouse move events * * @zh * 当鼠标在目标节点在目标节点区域中移动时,不论是否按下。 @@ -91,7 +205,7 @@ export enum SystemEventType { /** * @en - * The event type for mouse up events, you can use its value directly: 'mouseup'. + * The event type for mouse up events * * @zh * 当鼠标从按下状态松开时触发一次。 @@ -100,7 +214,7 @@ export enum SystemEventType { /** * @en - * The event type for mouse wheel events, you can use its value directly: 'mousewheel'. + * The event type for mouse wheel events * * @zh 手指开始触摸事件 */ @@ -108,37 +222,43 @@ export enum SystemEventType { /** * @en - * The event type for mouse leave target events, you can use its value directly: 'mouseleave'. + * The event type for mouse leave target events * * @zh * 当鼠标移入目标节点区域时,不论是否按下. + * + * @deprecated since v3.3, please use Node.EventType.MOUSE_ENTER instead. */ MOUSE_ENTER = 'mouse-enter', /** * @en - * The event type for mouse leave target events, you can use its value directly: 'mouseleave'. + * The event type for mouse leave target events * * @zh * 当鼠标移出目标节点区域时,不论是否按下。 + * + * @deprecated since v3.3, please use Node.EventType.MOUSE_LEAVE instead. */ MOUSE_LEAVE = 'mouse-leave', /** - * @en The event type for press the key down event, you can use its value directly: 'keydown' - * @zh 当按下按键时触发的事件 + * @en The event type for press the key down event, the event will be continuously dispatched in the key pressed state + * @zh 当按下按键时触发的事件, 该事件在按下状态会持续派发 + * @deprecated since v3.3, please use SystemEvent.KeyboardEvent.KEY_DOWN instead. The SystemEventType.KEY_DOWN event will be continuously dispatched in the key pressed state, it's not a good API design for developers. */ KEY_DOWN = 'keydown', /** - * @en The event type for press the key up event, you can use its value directly: 'keyup' + * @en The event type for press the key up event * @zh 当松开按键时触发的事件 + * @deprecated since v3.3, please use SystemEvent.KeyboardEvent.KEY_UP instead */ KEY_UP = 'keyup', /** * @en - * The event type for press the devicemotion event, you can use its value directly: 'devicemotion' + * The event type for press the devicemotion event * * @zh * 重力感应 @@ -159,12 +279,16 @@ export enum SystemEventType { * } * }, this); * ``` + * + * @deprecated since v3.3, please use Node.EventType.TRANSFORM_CHANGED instead */ TRANSFORM_CHANGED = 'transform-changed', /** * @en The event type for notifying the host scene has been changed for a persist node. * @zh 当场景常驻节点的场景发生改变时触发的事件,一般在切换场景过程中触发。 + * + * @deprecated since v3.3, please use Node.EventType.SCENE_CHANGED_FOR_PERSISTS instead */ SCENE_CHANGED_FOR_PERSISTS = 'scene-changed-for-persists', @@ -177,6 +301,8 @@ export enum SystemEventType { * @zh * 当节点尺寸改变时触发的事件。 * 性能警告:这个事件会在每次对应的属性被修改时触发,如果事件回调损耗较高,有可能对性能有很大的负面影响,请尽量避免这种情况。 + * + * @deprecated since v3.3, please use Node.EventType.SIZE_CHANGED instead */ SIZE_CHANGED = 'size-changed', @@ -189,7 +315,8 @@ export enum SystemEventType { * @zh * 当节点的 UITransform 锚点改变时触发的事件。 * 性能警告:这个事件会在每次对应的属性被修改时触发,如果事件回调损耗较高,有可能对性能有很大的负面影响,请尽量避免这种情况。 - * @deprecated + * + * @deprecated since v3.3, please use Node.EventType.ANCHOR_CHANGED instead */ ANCHOR_CHANGED = 'anchor-changed', @@ -202,6 +329,8 @@ export enum SystemEventType { * @zh * 当节点的 UI 渲染组件颜色属性改变时触发的事件。 * 性能警告:这个事件会在每次对应的属性被修改时触发,如果事件回调损耗较高,有可能对性能有很大的负面影响,请尽量避免这种情况。 + * + * @deprecated since v3.3, please use Node.EventType.COLOR_CHANGED instead */ COLOR_CHANGED = 'color-changed', @@ -211,6 +340,8 @@ export enum SystemEventType { * * @zh * 给目标节点添加子节点时触发的事件。 + * + * @deprecated since v3.3, please use Node.EventType.CHILD_ADDED instead */ CHILD_ADDED = 'child-added', @@ -220,34 +351,46 @@ export enum SystemEventType { * * @zh * 给目标节点移除子节点时触发的事件。 + * + * @deprecated since v3.3, please use Node.EventType.CHILD_REMOVED instead */ CHILD_REMOVED = 'child-removed', /** * @en The event type for changing the parent of the target node * @zh 目标节点的父节点改变时触发的事件。 + * + * @deprecated since v3.3, please use Node.EventType.PARENT_CHANGED instead */ PARENT_CHANGED = 'parent-changed', /** * @en The event type for destroying the target node * @zh 目标节点被销毁时触发的事件。 + * + * @deprecated since v3.3, please use Node.EventType.NODE_DESTROYED instead */ NODE_DESTROYED = 'node-destroyed', /** * @en The event type for node layer change events. * @zh 节点 layer 改变时触发的事件。 + * + * @deprecated since v3.3, please use Node.EventType.LAYER_CHANGED instead */ LAYER_CHANGED = 'layer-changed', /** * @en The event type for node's sibling order changed. * @zh 当节点在兄弟节点中的顺序发生变化时触发的事件。 + * + * @deprecated since v3.3, please use Node.EventType.SIBLING_ORDER_CHANGED instead */ SIBLING_ORDER_CHANGED = 'sibling-order-changed', } ccenum(SystemEventType); +export type SystemEventTypeUnion = SystemEventType.NO_TYPE | TouchEvent | MouseEvent | KeyboardEvent | DeviceEvent | 'keydown' | NodeEventType; + legacyCC.SystemEventType = SystemEventType; diff --git a/cocos/core/platform/event-manager/event-listener.ts b/cocos/core/platform/event-manager/event-listener.ts index 36028fa47e1..ec9cb258ca4 100644 --- a/cocos/core/platform/event-manager/event-listener.ts +++ b/cocos/core/platform/event-manager/event-listener.ts @@ -34,7 +34,8 @@ import { EventKeyboard, EventAcceleration, EventMouse } from './events'; import { Component } from '../../components'; import { legacyCC } from '../../global-exports'; import { logID, assertID } from '../debug'; -import { SystemEventType } from './event-enum'; +import { SystemEvent } from './system-event'; +import { KeyboardEvent, MouseEvent } from './event-enum'; export interface IEventListenerCreateInfo { event?: number; @@ -360,23 +361,23 @@ export class MouseEventListener extends EventListener { } public _callback (event: EventMouse) { - switch (event.eventType) { - case SystemEventType.MOUSE_DOWN: + switch (event.type) { + case MouseEvent.MOUSE_DOWN: if (this.onMouseDown) { this.onMouseDown(event); } break; - case SystemEventType.MOUSE_UP: + case MouseEvent.MOUSE_UP: if (this.onMouseUp) { this.onMouseUp(event); } break; - case SystemEventType.MOUSE_MOVE: + case MouseEvent.MOUSE_MOVE: if (this.onMouseMove) { this.onMouseMove(event); } break; - case SystemEventType.MOUSE_WHEEL: + case MouseEvent.MOUSE_WHEEL: if (this.onMouseScroll) { this.onMouseScroll(event); } @@ -497,8 +498,9 @@ export class AccelerationEventListener extends EventListener { // Keyboard export class KeyboardEventListener extends EventListener { - public onKeyPressed: Function | null = null; - public onKeyReleased: Function | null = null; + public onKeyDown?: Function = undefined; + public onKeyPressed?: Function = undefined; // deprecated + public onKeyReleased?: Function = undefined; constructor () { super(EventListener.KEYBOARD, ListenerID.KEYBOARD, null); @@ -506,24 +508,31 @@ export class KeyboardEventListener extends EventListener { } public _callback (event: EventKeyboard) { - if (event.isPressed) { - if (this.onKeyPressed) { - this.onKeyPressed(event.keyCode, event); - } - } else if (this.onKeyReleased) { - this.onKeyReleased(event.keyCode, event); + switch (event.type) { + case KeyboardEvent.KEY_DOWN: + this.onKeyDown?.(event.keyCode, event); + break; + case 'keydown': // SystemEventType.KEY_DOWN + this.onKeyPressed?.(event.keyCode, event); + break; + case KeyboardEvent.KEY_UP: + this.onKeyReleased?.(event.keyCode, event); + break; + default: + break; } } public clone () { const eventListener = new KeyboardEventListener(); + eventListener.onKeyDown = this.onKeyDown; eventListener.onKeyPressed = this.onKeyPressed; eventListener.onKeyReleased = this.onKeyReleased; return eventListener; } public checkAvailable () { - if (this.onKeyPressed === null && this.onKeyReleased === null) { + if (this.onKeyDown === null && this.onKeyPressed === null && this.onKeyReleased === null) { logID(1800); return false; } diff --git a/cocos/core/platform/event-manager/event-manager.ts b/cocos/core/platform/event-manager/event-manager.ts index e4ae87f2865..538a91bf061 100644 --- a/cocos/core/platform/event-manager/event-manager.ts +++ b/cocos/core/platform/event-manager/event-manager.ts @@ -36,7 +36,7 @@ import { Node } from '../../scene-graph'; import { macro } from '../macro'; import { legacyCC } from '../../global-exports'; import { errorID, warnID, logID, assertID } from '../debug'; -import { SystemEventType } from './event-enum'; +import { DeviceEvent, KeyboardEvent, MouseEvent, TouchEvent } from './event-enum'; const ListenerID = EventListener.ListenerID; @@ -47,6 +47,10 @@ function checkUINode (node) { return false; } +const touchEvents: string[] = [TouchEvent.TOUCH_START, TouchEvent.TOUCH_MOVE, TouchEvent.TOUCH_END, TouchEvent.TOUCH_CANCEL]; +const mouseEvents: string[] = [MouseEvent.MOUSE_DOWN, MouseEvent.MOUSE_MOVE, MouseEvent.MOUSE_DOWN, MouseEvent.MOUSE_WHEEL]; +const keyboardEvents: string[] = [KeyboardEvent.KEY_DOWN, KeyboardEvent.KEY_UP, 'keydown']; + class _EventListenerVector { public gt0Index = 0; private _fixedListeners: EventListener[] = []; @@ -91,18 +95,17 @@ class _EventListenerVector { } function __getListenerID (event: Event) { - const eventType = Event; const type = event.type; - if (type === eventType.ACCELERATION) { + if (type === DeviceEvent.DEVICEMOTION) { return ListenerID.ACCELERATION; } - if (type === eventType.KEYBOARD) { + if (keyboardEvents.includes(type)) { return ListenerID.KEYBOARD; } - if (type.startsWith(eventType.MOUSE)) { + if (mouseEvents.includes(type)) { return ListenerID.MOUSE; } - if (type.startsWith(eventType.TOUCH)) { + if (touchEvents.includes(type)) { // Touch listener is very special, it contains two kinds of listeners: // EventListenerTouchOneByOne and EventListenerTouchAllAtOnce. // return UNKNOWN instead. @@ -569,7 +572,7 @@ class EventManager { errorID(3511); return; } - if (event.getType().startsWith(legacyCC.Event.TOUCH)) { + if (touchEvents.includes(event.getType())) { this._dispatchTouchEvent(event as EventTouch); this._inDispatch--; return; @@ -949,8 +952,8 @@ class EventManager { let isClaimed = false; let removedIdx = -1; - const eventCode = event.getEventCode(); - if (eventCode === SystemEventType.TOUCH_START) { + const eventType = event.type; + if (eventType === TouchEvent.TOUCH_START) { if (!macro.ENABLE_MULTI_TOUCH && eventManager._currentTouch) { const node = eventManager._currentTouchListener._node; if (!node || node.activeInHierarchy) { @@ -975,9 +978,9 @@ class EventManager { if (!macro.ENABLE_MULTI_TOUCH && eventManager._currentTouch && eventManager._currentTouch !== selTouch) { return false; } - if (eventCode === SystemEventType.TOUCH_MOVE && listener.onTouchMoved) { + if (eventType === TouchEvent.TOUCH_MOVE && listener.onTouchMoved) { listener.onTouchMoved(selTouch, event); - } else if (eventCode === SystemEventType.TOUCH_END) { + } else if (eventType === TouchEvent.TOUCH_END) { if (listener.onTouchEnded) { listener.onTouchEnded(selTouch, event); } @@ -990,7 +993,7 @@ class EventManager { } eventManager._currentTouchListener = null; - } else if (eventCode === SystemEventType.TOUCH_CANCEL) { + } else if (eventType === TouchEvent.TOUCH_CANCEL) { if (listener.onTouchCancelled) { listener.onTouchCancelled(selTouch, event); } @@ -1070,15 +1073,15 @@ class EventManager { const event = callbackParams.event; const touches = callbackParams.touches; - const eventCode = event.getEventCode(); + const eventType = event.type; event.currentTarget = listener._getSceneGraphPriority(); - if (eventCode === SystemEventType.TOUCH_START && listener.onTouchesBegan) { + if (eventType === TouchEvent.TOUCH_START && listener.onTouchesBegan) { listener.onTouchesBegan(touches, event); - } else if (eventCode === SystemEventType.TOUCH_MOVE && listener.onTouchesMoved) { + } else if (eventType === TouchEvent.TOUCH_MOVE && listener.onTouchesMoved) { listener.onTouchesMoved(touches, event); - } else if (eventCode === SystemEventType.TOUCH_END && listener.onTouchesEnded) { + } else if (eventType === TouchEvent.TOUCH_END && listener.onTouchesEnded) { listener.onTouchesEnded(touches, event); - } else if (eventCode === SystemEventType.TOUCH_CANCEL && listener.onTouchesCancelled) { + } else if (eventType === TouchEvent.TOUCH_CANCEL && listener.onTouchesCancelled) { listener.onTouchesCancelled(touches, event); } diff --git a/cocos/core/platform/event-manager/events.ts b/cocos/core/platform/event-manager/events.ts index 5dfc4f57b34..05fe96d9c4e 100644 --- a/cocos/core/platform/event-manager/events.ts +++ b/cocos/core/platform/event-manager/events.ts @@ -34,6 +34,7 @@ import { Vec2 } from '../../math/vec2'; import { Touch } from './touch'; import { Acceleration } from './acceleration'; import { legacyCC } from '../../global-exports'; +import { DeviceEvent, KeyboardEvent, SystemEventTypeUnion } from './event-enum'; const _vec2 = new Vec2(); @@ -108,11 +109,16 @@ export class EventMouse extends Event { */ public movementY = 0; + private _eventType: SystemEventTypeUnion; /** - * @en The type of the event, possible values are UP, DOWN, MOVE, SCROLL - * @zh 鼠标事件类型,可以是 UP, DOWN, MOVE, CANCELED。 + * @en The type of the event + * @zh 鼠标事件类型 + * + * @deprecated since v3.3, please use EventMouse.prototype.type instead. */ - public eventType: string; + public get eventType () { + return this._eventType; + } private _button: number = EventMouse.BUTTON_MISSING; @@ -129,12 +135,12 @@ export class EventMouse extends Event { private _scrollY = 0; /** - * @param eventType - The type of the event, possible values are UP, DOWN, MOVE, SCROLL + * @param eventType - The type of the event * @param bubbles - Indicate whether the event bubbles up through the hierarchy or not. */ - constructor (eventType: string, bubbles?: boolean, prevLoc?: Vec2) { - super(Event.MOUSE, bubbles); - this.eventType = eventType; + constructor (eventType: SystemEventTypeUnion, bubbles?: boolean, prevLoc?: Vec2) { + super(eventType, bubbles); + this._eventType = eventType; if (prevLoc) { this._prevX = prevLoc.x; this._prevY = prevLoc.y; @@ -388,7 +394,7 @@ export class EventTouch extends Event { */ public simulate = false; - private _eventCode: string; + private _eventCode: SystemEventTypeUnion; // deprecated since v3.3 private _touches: Touch[]; @@ -397,18 +403,20 @@ export class EventTouch extends Event { /** * @param touches - An array of current touches * @param bubbles - Indicate whether the event bubbles up through the hierarchy or not. - * @param eventCode - The type code of the touch event + * @param eventType - The type of the event */ - constructor (changedTouches?: Touch[], bubbles?: boolean, eventCode?: string, touches?: Touch[]) { - super(Event.TOUCH, bubbles); - this._eventCode = eventCode || ''; + constructor (changedTouches: Touch[], bubbles: boolean, eventType: SystemEventTypeUnion, touches: Touch[] = []) { + super(eventType, bubbles); + this._eventCode = eventType; this._touches = changedTouches || []; - this._allTouches = touches || []; + this._allTouches = touches; } /** * @en Returns event type code. * @zh 获取触摸事件类型。 + * + * @deprecated since v3.3, please use EventTouch.prototype.type instead. */ public getEventCode () { return this._eventCode; @@ -576,7 +584,7 @@ export class EventAcceleration extends Event { * @param bubbles - Indicate whether the event bubbles up through the hierarchy or not. */ constructor (acc: Acceleration, bubbles?: boolean) { - super(Event.ACCELERATION, bubbles); + super(DeviceEvent.DEVICEMOTION, bubbles); this.acc = acc; } } @@ -602,29 +610,48 @@ export class EventKeyboard extends Event { /** * @en Raw DOM KeyboardEvent. * @zh 原始 DOM KeyboardEvent 事件对象 + * + * @deprecated since v3.3, can't access rawEvent anymore */ public rawEvent?: KeyboardEvent; + private _isPressed: boolean; /** * @en Indicates whether the current key is being pressed * @zh 表示当前按键是否正在被按下 + * + * @deprecated since v3.3, please use Event.prototype.type !== SystemEvent.KeyboardEvent.KEY_UP instead */ - public isPressed: boolean; + public get isPressed () { + return this._isPressed; + } /** * @param keyCode - The key code of the current key or the DOM KeyboardEvent - * @param isPressed - Indicates whether the current key is being pressed + * @param isPressed - Indicates whether the current key is being pressed, this is the DEPRECATED parameter. + * @param bubbles - Indicates whether the event bubbles up through the hierarchy or not. + */ + constructor (keyCode: number | KeyboardEvent, isPressed: boolean, bubbles?: boolean); + /** + * @param keyCode - The key code of the current key or the DOM KeyboardEvent + * @param eventType - The type of the event * @param bubbles - Indicates whether the event bubbles up through the hierarchy or not. */ - constructor (keyCode: number | KeyboardEvent, isPressed: boolean, bubbles?: boolean) { - super(Event.KEYBOARD, bubbles); + constructor (keyCode: number | KeyboardEvent, eventType: SystemEventTypeUnion, bubbles?: boolean); + constructor (keyCode: any, eventType: SystemEventTypeUnion | boolean, bubbles?: boolean) { + if (typeof eventType === 'boolean') { + const isPressed = eventType; + eventType = isPressed ? 'keydown' : KeyboardEvent.KEY_UP; + } + super(eventType, bubbles); + this._isPressed = eventType !== KeyboardEvent.KEY_UP; + if (typeof keyCode === 'number') { this.keyCode = keyCode; } else { this.keyCode = keyCode.keyCode; this.rawEvent = keyCode; } - this.isPressed = isPressed; } } diff --git a/cocos/core/platform/event-manager/index.ts b/cocos/core/platform/event-manager/index.ts index 9baffcbbf2e..7d0b7fd4838 100644 --- a/cocos/core/platform/event-manager/index.ts +++ b/cocos/core/platform/event-manager/index.ts @@ -36,4 +36,4 @@ export * from './input-manager'; export * from './system-event'; export * from './events'; export * from './touch'; -export * from './event-enum'; +export { SystemEventType } from './event-enum'; diff --git a/cocos/core/platform/event-manager/input-manager.ts b/cocos/core/platform/event-manager/input-manager.ts index 9b928ad7407..44e304bf8a6 100644 --- a/cocos/core/platform/event-manager/input-manager.ts +++ b/cocos/core/platform/event-manager/input-manager.ts @@ -38,7 +38,8 @@ import { Touch } from './touch'; import { legacyCC } from '../../global-exports'; import { logID } from '../debug'; import { Acceleration } from './acceleration'; -import { SystemEventType } from './event-enum'; +import { SystemEvent } from './system-event'; +import { KeyboardEvent, TouchEvent } from './event-enum'; const TOUCH_TIMEOUT = macro.TOUCH_TIMEOUT; @@ -99,7 +100,7 @@ class InputManager { } if (handleTouches.length > 0) { // this._glView!._convertTouchesWithScale(handleTouches); - const touchEvent = new EventTouch(handleTouches, false, SystemEventType.TOUCH_START, macro.ENABLE_MULTI_TOUCH ? this._getUsefulTouches() : handleTouches); + const touchEvent = new EventTouch(handleTouches, false, TouchEvent.TOUCH_START, macro.ENABLE_MULTI_TOUCH ? this._getUsefulTouches() : handleTouches); eventManager.dispatchEvent(touchEvent); } } @@ -127,7 +128,7 @@ class InputManager { } } if (handleTouches.length > 0) { - const touchEvent = new EventTouch(handleTouches, false, SystemEventType.TOUCH_MOVE, macro.ENABLE_MULTI_TOUCH ? this._getUsefulTouches() : handleTouches); + const touchEvent = new EventTouch(handleTouches, false, TouchEvent.TOUCH_MOVE, macro.ENABLE_MULTI_TOUCH ? this._getUsefulTouches() : handleTouches); eventManager.dispatchEvent(touchEvent); } } @@ -135,7 +136,7 @@ class InputManager { public handleTouchesEnd (touches: Touch[]) { const handleTouches = this.getSetOfTouchesEndOrCancel(touches); if (handleTouches.length > 0) { - const touchEvent = new EventTouch(handleTouches, false, SystemEventType.TOUCH_END, macro.ENABLE_MULTI_TOUCH ? this._getUsefulTouches() : handleTouches); + const touchEvent = new EventTouch(handleTouches, false, TouchEvent.TOUCH_END, macro.ENABLE_MULTI_TOUCH ? this._getUsefulTouches() : handleTouches); eventManager.dispatchEvent(touchEvent); } this._preTouchPool.length = 0; @@ -144,7 +145,7 @@ class InputManager { public handleTouchesCancel (touches: Touch[]) { const handleTouches = this.getSetOfTouchesEndOrCancel(touches); if (handleTouches.length > 0) { - const touchEvent = new EventTouch(handleTouches, false, SystemEventType.TOUCH_CANCEL, macro.ENABLE_MULTI_TOUCH ? this._getUsefulTouches() : handleTouches); + const touchEvent = new EventTouch(handleTouches, false, TouchEvent.TOUCH_CANCEL, macro.ENABLE_MULTI_TOUCH ? this._getUsefulTouches() : handleTouches); eventManager.dispatchEvent(touchEvent); } this._preTouchPool.length = 0; @@ -433,11 +434,14 @@ class InputManager { } private _registerKeyboardEvent () { - input._keyboard.onDown((inputEvent) => { - eventManager.dispatchEvent(new EventKeyboard(inputEvent.code, true)); + input._keyboard.onDown((inputEvent) => { + eventManager.dispatchEvent(new EventKeyboard(inputEvent.code, KeyboardEvent.KEY_DOWN)); + }); + input._keyboard.onPressing((inputEvent) => { + eventManager.dispatchEvent(new EventKeyboard(inputEvent.code, 'keydown')); }); input._keyboard.onUp((inputEvent) => { - eventManager.dispatchEvent(new EventKeyboard(inputEvent.code, false)); + eventManager.dispatchEvent(new EventKeyboard(inputEvent.code, KeyboardEvent.KEY_UP)); }); } diff --git a/cocos/core/platform/event-manager/key-code.ts b/cocos/core/platform/event-manager/key-code.ts new file mode 100644 index 00000000000..bf2c10df1ef --- /dev/null +++ b/cocos/core/platform/event-manager/key-code.ts @@ -0,0 +1,611 @@ +export enum KeyCode { + /** + * @en None + * @zh 没有分配 + */ + NONE = 0, + + /** + * @en The backspace key + * @zh 退格键 + */ + BACKSPACE = 8, + + /** + * @en The tab key + * @zh Tab 键 + */ + TAB = 9, + + /** + * @en The enter key + * @zh 回车键 + */ + ENTER = 13, + + /** + * @en The left shift key + * @zh 左 Shift 键 + */ + SHIFT_LEFT = 16, + + /** + * @en The left ctrl key + * @zh 左 Ctrl 键 + */ + CTRL_LEFT = 17, + + /** + * @en The left alt key + * @zh 左 Alt 键 + */ + ALT_LEFT = 18, + + /** + * @en The pause key + * @zh 暂停键 + */ + PAUSE = 19, + + /** + * @en The caps lock key + * @zh 大写锁定键 + */ + CAPSLOCK = 20, + + /** + * @en The esc key + * @zh ESC 键 + */ + ESCAPE = 27, + + /** + * @en The space key + * @zh 空格键 + */ + SPACE = 32, + + /** + * @en The page up key + * @zh 向上翻页键 + */ + PAGEUP = 33, + + /** + * @en The page down key + * @zh 向下翻页键 + */ + PAGEDOWN = 34, + + /** + * @en The end key + * @zh 结束键 + */ + END = 35, + + /** + * @en The home key + * @zh 主菜单键 + */ + HOME = 36, + + /** + * @en The left key + * @zh 向左箭头键 + */ + ARROW_LEFT = 37, + + /** + * @en The up key + * @zh 向上箭头键 + */ + ARROW_UP = 38, + + /** + * @en The right key + * @zh 向右箭头键 + */ + ARROW_RIGHT = 39, + + /** + * @en The down key + * @zh 向下箭头键 + */ + ARROW_DOWN = 40, + + /** + * @en The insert key + * @zh 插入键 + */ + INSERT = 45, + + /** + * @en The Delete key + * @zh 删除键 + */ + DELETE = 46, + + /** + * @en The '0' key on the top of the alphanumeric keyboard. + * @zh 字母键盘上的 0 键 + */ + DIGIT_0 = 48, + + /** + * @en The '1' key on the top of the alphanumeric keyboard. + * @zh 字母键盘上的 1 键 + */ + DIGIT_1 = 49, + + /** + * @en The '2' key on the top of the alphanumeric keyboard. + * @zh 字母键盘上的 2 键 + */ + DIGIT_2 = 50, + + /** + * @en The '3' key on the top of the alphanumeric keyboard. + * @zh 字母键盘上的 3 键 + */ + DIGIT_3 = 51, + + /** + * @en The '4' key on the top of the alphanumeric keyboard. + * @zh 字母键盘上的 4 键 + */ + DIGIT_4 = 52, + + /** + * @en The '5' key on the top of the alphanumeric keyboard. + * @zh 字母键盘上的 5 键 + */ + DIGIT_5 = 53, + + /** + * @en The '6' key on the top of the alphanumeric keyboard. + * @zh 字母键盘上的 6 键 + */ + DIGIT_6 = 54, + + /** + * @en The '7' key on the top of the alphanumeric keyboard. + * @zh 字母键盘上的 7 键 + */ + DIGIT_7 = 55, + + /** + * @en The '8' key on the top of the alphanumeric keyboard. + * @zh 字母键盘上的 8 键 + */ + DIGIT_8 = 56, + + /** + * @en The '9' key on the top of the alphanumeric keyboard. + * @zh 字母键盘上的 9 键 + */ + DIGIT_9 = 57, + + /** + * @en The a key + * @zh A 键 + */ + KEY_A = 65, + + /** + * @en The b key + * @zh B 键 + */ + KEY_B = 66, + + /** + * @en The c key + * @zh C 键 + */ + KEY_C = 67, + + /** + * @en The d key + * @zh D 键 + */ + KEY_D = 68, + + /** + * @en The e key + * @zh E 键 + */ + KEY_E = 69, + + /** + * @en The f key + * @zh F 键 + */ + KEY_F = 70, + + /** + * @en The g key + * @zh G 键 + */ + KEY_G = 71, + + /** + * @en The h key + * @zh H 键 + */ + KEY_H = 72, + + /** + * @en The i key + * @zh I 键 + */ + KEY_I = 73, + + /** + * @en The j key + * @zh J 键 + */ + KEY_J = 74, + + /** + * @en The k key + * @zh K 键 + */ + KEY_K = 75, + + /** + * @en The l key + * @zh L 键 + */ + KEY_L = 76, + + /** + * @en The m key + * @zh M 键 + */ + KEY_M = 77, + + /** + * @en The n key + * @zh N 键 + */ + KEY_N = 78, + + /** + * @en The o key + * @zh O 键 + */ + KEY_O = 79, + + /** + * @en The p key + * @zh P 键 + */ + KEY_P = 80, + + /** + * @en The q key + * @zh Q 键 + */ + KEY_Q = 81, + + /** + * @en The r key + * @zh R 键 + */ + KEY_R = 82, + + /** + * @en The s key + * @zh S 键 + */ + KEY_S = 83, + + /** + * @en The t key + * @zh T 键 + */ + KEY_T = 84, + + /** + * @en The u key + * @zh U 键 + */ + KEY_U = 85, + + /** + * @en The v key + * @zh V 键 + */ + KEY_V = 86, + + /** + * @en The w key + * @zh W 键 + */ + KEY_W = 87, + + /** + * @en The x key + * @zh X 键 + */ + KEY_X = 88, + + /** + * @en The y key + * @zh Y 键 + */ + KEY_Y = 89, + + /** + * @en The z key + * @zh Z 键 + */ + KEY_Z = 90, + + /** + * @en The numeric keypad 0 + * @zh 数字键盘 0 + */ + NUM_0 = 96, + + /** + * @en The numeric keypad 1 + * @zh 数字键盘 1 + */ + NUM_1 = 97, + + /** + * @en The numeric keypad 2 + * @zh 数字键盘 2 + */ + NUM_2 = 98, + + /** + * @en The numeric keypad 3 + * @zh 数字键盘 3 + */ + NUM_3 = 99, + + /** + * @en The numeric keypad 4 + * @zh 数字键盘 4 + */ + NUM_4 = 100, + + /** + * @en The numeric keypad 5 + * @zh 数字键盘 5 + */ + NUM_5 = 101, + + /** + * @en The numeric keypad 6 + * @zh 数字键盘 6 + */ + NUM_6 = 102, + + /** + * @en The numeric keypad 7 + * @zh 数字键盘 7 + */ + NUM_7 = 103, + + /** + * @en The numeric keypad 8 + * @zh 数字键盘 8 + */ + NUM_8 = 104, + + /** + * @en The numeric keypad 9 + * @zh 数字键盘 9 + */ + NUM_9 = 105, + + /** + * @en The numeric keypad '*' + * @zh 数字键盘 * + */ + NUM_MUTIPLY = 106, + + /** + * @en The numeric keypad '+' + * @zh 数字键盘 + + */ + NUM_PLUS = 107, + + /** + * @en The numeric keypad '-' + * @zh 数字键盘 - + */ + NUM_SUBTRACT = 109, + + /** + * @en The numeric keypad '.' + * @zh 数字键盘小数点 '.' + */ + NUM_DECIMAL = 110, + + /** + * @en The numeric keypad '/' + * @zh 数字键盘 / + */ + NUM_DIVIDE = 111, + + /** + * @en The F1 function key + * @zh F1 功能键 + */ + F1 = 112, + + /** + * @en The F2 function key + * @zh F2 功能键 + */ + F2 = 113, + + /** + * @en The F3 function key + * @zh F3 功能键 + */ + F3 = 114, + + /** + * @en The F4 function key + * @zh F4 功能键 + */ + F4 = 115, + + /** + * @en The F5 function key + * @zh F5 功能键 + */ + F5 = 116, + + /** + * @en The F6 function key + * @zh F6 功能键 + */ + F6 = 117, + + /** + * @en The F7 function key + * @zh F7 功能键 + */ + F7 = 118, + + /** + * @en The F8 function key + * @zh F8 功能键 + */ + F8 = 119, + + /** + * @en The F9 function key + * @zh F9 功能键 + */ + F9 = 120, + + /** + * @en The F10 function key + * @zh F10 功能键 + */ + F10 = 121, + + /** + * @en The F11 function key + * @zh F11 功能键 + */ + F11 = 122, + + /** + * @en The F12 function key + * @zh F12 功能键 + */ + F12 = 123, + + /** + * @en The numlock key + * @zh 数字锁定键 + */ + NUM_LOCK = 144, + + /** + * @en The scroll lock key + * @zh 滚动锁定键 + */ + SCROLLLOCK = 145, + + /** + * @en The ';' key. + * @zh 分号键 + */ + SEMICOLON = 186, + + /** + * @en The '=' key. + * @zh 等于号键 + */ + EQUAL = 187, + + /** + * @en The ',' key. + * @zh 逗号键 + */ + COMMA = 188, + + /** + * @en The dash '-' key. + * @zh 中划线键 + */ + DASH = 189, + + /** + * @en The '.' key + * @zh 句号键 + */ + PERIOD = 190, + + /** + * @en The slash key '/' + * @zh 正斜杠键 '/' + */ + SLASH = 191, + + /** + * @en The back quote key ` + * @zh 按键 ` + */ + BACKQUOTE = 192, + + /** + * @en The '[' key + * @zh 按键 [ + */ + BRACKET_LEFT = 219, + + /** + * @en The back slash key '\' + * @zh 反斜杠键 '\' + */ + BACKSLASH = 220, + + /** + * @en The ']' key + * @zh 按键 ] + */ + BRACKET_RIGHT = 221, + + /** + * @en The quote key + * @zh 单引号键 + */ + QUOTE = 222, + +// #region The new allocated key enum since v3.3 + + /** + * @en The right shift key + * @zh 右 Shift 键 + */ + SHIFT_RIGHT = 2000, + + /** + * @en The right ctrl key + * @zh 右 Ctrl 键 + */ + CTRL_RIGHT = 2001, + + /** + * @en The right alt key + * @zh 右 Alt 键 + */ + ALT_RIGHT = 2002, + + /** + * @en The numeric keypad enter + * @zh 数字键盘 enter + */ + NUM_ENTER = 2003, + +// #endregion The new allocated key enum since v3.3 +} diff --git a/cocos/core/platform/event-manager/system-event.ts b/cocos/core/platform/event-manager/system-event.ts index 7854e369372..f5fc1f2c278 100644 --- a/cocos/core/platform/event-manager/system-event.ts +++ b/cocos/core/platform/event-manager/system-event.ts @@ -32,13 +32,14 @@ import { EDITOR } from 'internal:constants'; import { EventTarget } from '../../event/event-target'; import { EventAcceleration, EventKeyboard, EventMouse, EventTouch } from './events'; -import { SystemEventType } from './event-enum'; +import { DeviceEvent, KeyboardEvent, MouseEvent, SystemEventType, TouchEvent } from './event-enum'; import { EventListener } from './event-listener'; import eventManager from './event-manager'; import inputManager from './input-manager'; import { Touch } from './touch'; import { legacyCC } from '../../global-exports'; import { logID, warnID } from '../debug'; +import { KeyCode } from './key-code'; let keyboardListener: EventListener | null = null; let accelerationListener: EventListener | null = null; @@ -55,13 +56,31 @@ let mouseListener: EventListener | null = null; * @example * ``` * import { systemEvent, SystemEvent } from 'cc'; -* systemEvent.on(SystemEvent.EventType.DEVICEMOTION, this.onDeviceMotionEvent, this); -* systemEvent.off(SystemEvent.EventType.DEVICEMOTION, this.onDeviceMotionEvent, this); +* systemEvent.on(SystemEvent.DeviceEvent.DEVICEMOTION, this.onDeviceMotionEvent, this); +* systemEvent.off(SystemEvent.DeviceEvent.DEVICEMOTION, this.onDeviceMotionEvent, this); * ``` */ export class SystemEvent extends EventTarget { + /** + * @en The event type supported by SystemEvent and Node events + * @zh SystemEvent 支持的事件类型以及节点事件类型 + * + * @deprecated since v3.3, please use SystemEvent.TouchEvent, SystemEvent.MouseEvent, SystemEvent.KeyboardEvent, SystemEvent.DeviceEvent and Node.EventType instead + */ public static EventType = SystemEventType; + + public static TouchEvent = TouchEvent; + public static MouseEvent = MouseEvent; + public static KeyboardEvent = KeyboardEvent; + public static DeviceEvent = DeviceEvent; + + /** + * @en Enum type of keycode for key event + * @zh 按键事件的按键码 + */ + public static KeyCode = KeyCode; + constructor () { super(); } @@ -105,13 +124,12 @@ export class SystemEvent extends EventTarget { inputManager.setAccelerometerInterval(interval); } - public on (type: SystemEventType.KEY_DOWN | SystemEventType.KEY_UP, callback: (event: EventKeyboard) => void, target?: unknown): typeof callback; - public on (type: SystemEventType.MOUSE_DOWN | SystemEventType.MOUSE_ENTER | SystemEventType.MOUSE_LEAVE | - SystemEventType.MOUSE_MOVE | SystemEventType.MOUSE_UP | SystemEventType.MOUSE_WHEEL, + public on (type: SystemEventType.KEY_DOWN | SystemEventType.KEY_UP | KeyboardEvent.KEY_DOWN | KeyboardEvent.KEY_UP, callback: (event: EventKeyboard) => void, target?: unknown): typeof callback; + public on (type: MouseEvent.MOUSE_DOWN | MouseEvent.MOUSE_MOVE | MouseEvent.MOUSE_UP | MouseEvent.MOUSE_WHEEL, callback: (event: EventMouse) => void, target?: unknown): typeof callback; - public on (type: SystemEventType.TOUCH_START | SystemEventType.TOUCH_MOVE | SystemEventType.TOUCH_END | SystemEventType.TOUCH_CANCEL, + public on (type: TouchEvent.TOUCH_START | TouchEvent.TOUCH_MOVE | TouchEvent.TOUCH_END | TouchEvent.TOUCH_CANCEL, callback: (touch: Touch, event: EventTouch) => void, target?: unknown): typeof callback; - public on (type: SystemEventType.DEVICEMOTION, callback: (event: EventAcceleration) => void, target?: unknown): typeof callback; + public on (type: DeviceEvent.DEVICEMOTION, callback: (event: EventAcceleration) => void, target?: unknown): typeof callback; /** * @en * Register an callback of a specific system event type. @@ -129,16 +147,18 @@ export class SystemEvent extends EventTarget { super.on(type, callback, target, once); // Keyboard - if (type === SystemEventType.KEY_DOWN || type === SystemEventType.KEY_UP) { + if (type === KeyboardEvent.KEY_DOWN || type === 'keydown' || type === KeyboardEvent.KEY_UP) { if (!keyboardListener) { keyboardListener = EventListener.create({ event: EventListener.KEYBOARD, + onKeyDown (keyCode: number, event: EventKeyboard) { + systemEvent.emit(event.type, event); + }, + // deprecated onKeyPressed (keyCode: number, event: EventKeyboard) { - event.type = SystemEventType.KEY_DOWN; systemEvent.emit(event.type, event); }, onKeyReleased (keyCode: number, event: EventKeyboard) { - event.type = SystemEventType.KEY_UP; systemEvent.emit(event.type, event); }, }); @@ -147,12 +167,11 @@ export class SystemEvent extends EventTarget { } // Acceleration - if (type === SystemEventType.DEVICEMOTION) { + if (type === DeviceEvent.DEVICEMOTION) { if (!accelerationListener) { accelerationListener = EventListener.create({ event: EventListener.ACCELERATION, callback (acc: any, event: EventAcceleration) { - event.type = SystemEventType.DEVICEMOTION; legacyCC.systemEvent.emit(event.type, event); }, }); @@ -161,29 +180,25 @@ export class SystemEvent extends EventTarget { } // touch - if (type === SystemEventType.TOUCH_START - || type === SystemEventType.TOUCH_MOVE - || type === SystemEventType.TOUCH_END - || type === SystemEventType.TOUCH_CANCEL + if (type === TouchEvent.TOUCH_START + || type === TouchEvent.TOUCH_MOVE + || type === TouchEvent.TOUCH_END + || type === TouchEvent.TOUCH_CANCEL ) { if (!touchListener) { touchListener = EventListener.create({ event: EventListener.TOUCH_ONE_BY_ONE, onTouchBegan (touch: Touch, event: EventTouch) { - event.type = SystemEventType.TOUCH_START; legacyCC.systemEvent.emit(event.type, touch, event); return true; }, onTouchMoved (touch: Touch, event: EventTouch) { - event.type = SystemEventType.TOUCH_MOVE; legacyCC.systemEvent.emit(event.type, touch, event); }, onTouchEnded (touch: Touch, event: EventTouch) { - event.type = SystemEventType.TOUCH_END; legacyCC.systemEvent.emit(event.type, touch, event); }, onTouchCancelled (touch: Touch, event: EventTouch) { - event.type = SystemEventType.TOUCH_CANCEL; legacyCC.systemEvent.emit(event.type, touch, event); }, }); @@ -192,28 +207,24 @@ export class SystemEvent extends EventTarget { } // mouse - if (type === SystemEventType.MOUSE_DOWN - || type === SystemEventType.MOUSE_MOVE - || type === SystemEventType.MOUSE_UP - || type === SystemEventType.MOUSE_WHEEL + if (type === MouseEvent.MOUSE_DOWN + || type === MouseEvent.MOUSE_MOVE + || type === MouseEvent.MOUSE_UP + || type === MouseEvent.MOUSE_WHEEL ) { if (!mouseListener) { mouseListener = EventListener.create({ event: EventListener.MOUSE, onMouseDown (event: EventMouse) { - event.type = SystemEventType.MOUSE_DOWN; legacyCC.systemEvent.emit(event.type, event); }, onMouseMove (event:EventMouse) { - event.type = SystemEventType.MOUSE_MOVE; legacyCC.systemEvent.emit(event.type, event); }, onMouseUp (event: EventMouse) { - event.type = SystemEventType.MOUSE_UP; legacyCC.systemEvent.emit(event.type, event); }, onMouseScroll (event: EventMouse) { - event.type = SystemEventType.MOUSE_WHEEL; legacyCC.systemEvent.emit(event.type, event); }, }); @@ -242,41 +253,42 @@ export class SystemEvent extends EventTarget { super.off(type, callback, target); // Keyboard - if (keyboardListener && (type === SystemEventType.KEY_DOWN || type === SystemEventType.KEY_UP)) { - const hasKeyDownEventListener = this.hasEventListener(SystemEventType.KEY_DOWN); - const hasKeyUpEventListener = this.hasEventListener(SystemEventType.KEY_UP); - if (!hasKeyDownEventListener && !hasKeyUpEventListener) { + if (keyboardListener && (type === KeyboardEvent.KEY_DOWN || type === 'keydown' || type === KeyboardEvent.KEY_UP)) { + const hasKeyDownEventListener = this.hasEventListener(KeyboardEvent.KEY_DOWN); + const hasKeyPressingEventListener = this.hasEventListener('keydown'); // SystemEventType.KEY_DOWN + const hasKeyUpEventListener = this.hasEventListener(KeyboardEvent.KEY_UP); + if (!hasKeyDownEventListener && !hasKeyPressingEventListener && !hasKeyUpEventListener) { eventManager.removeListener(keyboardListener); keyboardListener = null; } } // Acceleration - if (accelerationListener && type === SystemEventType.DEVICEMOTION) { + if (accelerationListener && type === DeviceEvent.DEVICEMOTION) { eventManager.removeListener(accelerationListener); accelerationListener = null; } - if (touchListener && (type === SystemEventType.TOUCH_START || type === SystemEventType.TOUCH_MOVE - || type === SystemEventType.TOUCH_END || type === SystemEventType.TOUCH_CANCEL) + if (touchListener && (type === TouchEvent.TOUCH_START || type === TouchEvent.TOUCH_MOVE + || type === TouchEvent.TOUCH_END || type === TouchEvent.TOUCH_CANCEL) ) { - const hasTouchStart = this.hasEventListener(SystemEventType.TOUCH_START); - const hasTouchMove = this.hasEventListener(SystemEventType.TOUCH_MOVE); - const hasTouchEnd = this.hasEventListener(SystemEventType.TOUCH_END); - const hasTouchCancel = this.hasEventListener(SystemEventType.TOUCH_CANCEL); + const hasTouchStart = this.hasEventListener(TouchEvent.TOUCH_START); + const hasTouchMove = this.hasEventListener(TouchEvent.TOUCH_MOVE); + const hasTouchEnd = this.hasEventListener(TouchEvent.TOUCH_END); + const hasTouchCancel = this.hasEventListener(TouchEvent.TOUCH_CANCEL); if (!hasTouchStart && !hasTouchMove && !hasTouchEnd && !hasTouchCancel) { eventManager.removeListener(touchListener); touchListener = null; } } - if (mouseListener && (type === SystemEventType.MOUSE_DOWN || type === SystemEventType.MOUSE_MOVE - || type === SystemEventType.MOUSE_UP || type === SystemEventType.MOUSE_WHEEL) + if (mouseListener && (type === MouseEvent.MOUSE_DOWN || type === MouseEvent.MOUSE_MOVE + || type === MouseEvent.MOUSE_UP || type === MouseEvent.MOUSE_WHEEL) ) { - const hasMouseDown = this.hasEventListener(SystemEventType.MOUSE_DOWN); - const hasMouseMove = this.hasEventListener(SystemEventType.MOUSE_MOVE); - const hasMouseUp = this.hasEventListener(SystemEventType.MOUSE_UP); - const hasMouseWheel = this.hasEventListener(SystemEventType.MOUSE_WHEEL); + const hasMouseDown = this.hasEventListener(MouseEvent.MOUSE_DOWN); + const hasMouseMove = this.hasEventListener(MouseEvent.MOUSE_MOVE); + const hasMouseUp = this.hasEventListener(MouseEvent.MOUSE_UP); + const hasMouseWheel = this.hasEventListener(MouseEvent.MOUSE_WHEEL); if (!hasMouseDown && !hasMouseMove && !hasMouseUp && !hasMouseWheel) { eventManager.removeListener(mouseListener); mouseListener = null; diff --git a/cocos/core/platform/macro.ts b/cocos/core/platform/macro.ts index 644c31d330e..e2980d379f1 100644 --- a/cocos/core/platform/macro.ts +++ b/cocos/core/platform/macro.ts @@ -44,15 +44,17 @@ const KEY = { // android /** - * @en The back key - * @zh 返回键 + * @en The back key on mobile phone + * @zh 移动端返回键 * @readonly + * @deprecated since v3.3 */ back: 6, /** - * @en The menu key - * @zh 菜单键 + * @en The menu key on mobile phone + * @zh 移动端菜单键 * @readonly + * @deprecated since v3.3 */ menu: 18, @@ -81,6 +83,7 @@ const KEY = { * @en The shift key * @zh Shift 键 * @readonly + * @deprecated since v3.3, please use SystemEvent.KeyCode.SHIFT_LEFT instead. */ shift: 16, // should use shiftkey instead @@ -88,6 +91,7 @@ const KEY = { * @en The ctrl key * @zh Ctrl 键 * @readonly + * @deprecated since v3.3, please use SystemEvent.KeyCode.CTRL_LEFT instead. */ ctrl: 17, // should use ctrlkey @@ -95,6 +99,7 @@ const KEY = { * @en The alt key * @zh Alt 键 * @readonly + * @deprecated since v3.3, please use SystemEvent.KeyCode.ALT_LEFT instead. */ alt: 18, // should use altkey @@ -186,6 +191,7 @@ const KEY = { * @en The select key * @zh Select 键 * @readonly + * @deprecated since v3.3 */ select: 41, @@ -207,6 +213,7 @@ const KEY = { * @en The '0' key on the top of the alphanumeric keyboard. * @zh 字母键盘上的 0 键 * @readonly + * @deprecated since v3.3 */ 0: 48, @@ -214,6 +221,7 @@ const KEY = { * @en The '1' key on the top of the alphanumeric keyboard. * @zh 字母键盘上的 1 键 * @readonly + * @deprecated since v3.3 */ 1: 49, @@ -221,6 +229,7 @@ const KEY = { * @en The '2' key on the top of the alphanumeric keyboard. * @zh 字母键盘上的 2 键 * @readonly + * @deprecated since v3.3 */ 2: 50, @@ -228,6 +237,7 @@ const KEY = { * @en The '3' key on the top of the alphanumeric keyboard. * @zh 字母键盘上的 3 键 * @readonly + * @deprecated since v3.3 */ 3: 51, @@ -235,6 +245,7 @@ const KEY = { * @en The '4' key on the top of the alphanumeric keyboard. * @zh 字母键盘上的 4 键 * @readonly + * @deprecated since v3.3 */ 4: 52, @@ -242,6 +253,7 @@ const KEY = { * @en The '5' key on the top of the alphanumeric keyboard. * @zh 字母键盘上的 5 键 * @readonly + * @deprecated since v3.3 */ 5: 53, @@ -249,6 +261,7 @@ const KEY = { * @en The '6' key on the top of the alphanumeric keyboard. * @zh 字母键盘上的 6 键 * @readonly + * @deprecated since v3.3 */ 6: 54, @@ -256,6 +269,7 @@ const KEY = { * @en The '7' key on the top of the alphanumeric keyboard. * @zh 字母键盘上的 7 键 * @readonly + * @deprecated since v3.3 */ 7: 55, @@ -263,6 +277,7 @@ const KEY = { * @en The '8' key on the top of the alphanumeric keyboard. * @zh 字母键盘上的 8 键 * @readonly + * @deprecated since v3.3 */ 8: 56, @@ -270,6 +285,7 @@ const KEY = { * @en The '9' key on the top of the alphanumeric keyboard. * @zh 字母键盘上的 9 键 * @readonly + * @deprecated since v3.3 */ 9: 57, @@ -529,6 +545,7 @@ const KEY = { * @en The numeric keypad '*' * @zh 数字键盘 * * @readonly + * @deprecated since v3.3 */ '*': 106, @@ -536,6 +553,7 @@ const KEY = { * @en The numeric keypad '+' * @zh 数字键盘 + * @readonly + * @deprecated since v3.3 */ '+': 107, @@ -543,6 +561,7 @@ const KEY = { * @en The numeric keypad '-' * @zh 数字键盘 - * @readonly + * @deprecated since v3.3 */ '-': 109, @@ -557,6 +576,7 @@ const KEY = { * @en The numeric keypad '/' * @zh 数字键盘 / * @readonly + * @deprecated since v3.3 */ '/': 111, @@ -662,6 +682,7 @@ const KEY = { * @en The ';' key. * @zh 分号键 * @readonly + * @deprecated since v3.3 */ ';': 186, @@ -683,6 +704,7 @@ const KEY = { * @en The '=' key. * @zh 等于号键 * @readonly + * @deprecated since v3.3 */ '=': 187, @@ -690,6 +712,7 @@ const KEY = { * @en The ',' key. * @zh 逗号键 * @readonly + * @deprecated since v3.3 */ ',': 188, @@ -711,6 +734,7 @@ const KEY = { * @en The '.' key. * @zh 句号键 * @readonly + * @deprecated since v3.3 */ '.': 190, @@ -739,6 +763,7 @@ const KEY = { * @en The '[' key * @zh 按键 [ * @readonly + * @deprecated since v3.3 */ '[': 219, @@ -760,6 +785,7 @@ const KEY = { * @en The ']' key * @zh 按键 ] * @readonly + * @deprecated since v3.3 */ ']': 221, @@ -783,6 +809,7 @@ const KEY = { * @en The dpad left key * @zh 导航键 向左 * @readonly + * @deprecated since v3.3 */ dpadLeft: 1000, @@ -790,6 +817,7 @@ const KEY = { * @en The dpad right key * @zh 导航键 向右 * @readonly + * @deprecated since v3.3 */ dpadRight: 1001, @@ -797,6 +825,7 @@ const KEY = { * @en The dpad up key * @zh 导航键 向上 * @readonly + * @deprecated since v3.3 */ dpadUp: 1003, @@ -804,6 +833,7 @@ const KEY = { * @en The dpad down key * @zh 导航键 向下 * @readonly + * @deprecated since v3.3 */ dpadDown: 1004, @@ -811,6 +841,7 @@ const KEY = { * @en The dpad center key * @zh 导航键 确定键 * @readonly + * @deprecated since v3.3 */ dpadCenter: 1005, }; @@ -836,6 +867,7 @@ const macro = { * @en Key map for keyboard event * @zh 键盘事件的按键值。 * @example {@link cocos/core/platform/CCCommon/KEY.js} + * @deprecated since v3.3 please use SystemEvent.KeyCode instead */ KEY, diff --git a/cocos/core/renderer/core/memory-pools.ts b/cocos/core/renderer/core/memory-pools.ts index 099d8244726..92c3f22cdff 100644 --- a/cocos/core/renderer/core/memory-pools.ts +++ b/cocos/core/renderer/core/memory-pools.ts @@ -29,19 +29,7 @@ */ import { DEBUG, JSB } from 'internal:constants'; -import { NativeBufferPool, NativeObjectPool, NativeBufferAllocator } from './native-pools'; -import { - DescriptorSetInfo, - Device, DescriptorSet, ShaderInfo, Shader, InputAssemblerInfo, InputAssembler, - PipelineLayoutInfo, PipelineLayout, Framebuffer, FramebufferInfo, PrimitiveMode, - DynamicStateFlags, Color as GFXColor, ClearFlags, -} from '../../gfx'; -import { RenderPassStage } from '../../pipeline/define'; -import { BatchingSchemes } from './pass'; -import { - Vec2, Vec3, Quat, Color, Rect, Mat4, IVec2Like, IVec3Like, IVec4Like, IMat4Like, -} from '../../math'; -import { Plane } from '../../geometry'; +import { NativeBufferPool } from './native-pools'; const contains = (a: number[], t: number) => { for (let i = 0; i < a.length; ++i) { @@ -69,997 +57,148 @@ enum BufferDataType { } type BufferManifest = { [key: string]: number | string; COUNT: number }; -type StandardBufferElement = number | IHandle; -type GeneralBufferElement = StandardBufferElement | IVec2Like | IVec3Like | IVec4Like | IMat4Like; -type BufferTypeManifest = { [key in E[keyof E]]: GeneralBufferElement }; type BufferDataTypeManifest = { [key in E[keyof E]]: BufferDataType }; +type BufferDataMembersManifest = { [key in E[keyof E]]: number }; +type BufferArrayType = Float32Array | Uint32Array; -class BufferPool

> implements IMemoryPool

{ +class BufferPool

implements IMemoryPool

{ // naming convension: // this._bufferViews[chunk][entry][element] - private _dataType: BufferDataTypeManifest; - private _elementCount: number; - private _entryBits: number; - private _stride: number; - private _entriesPerChunk: number; - private _entryMask: number; - private _chunkMask: number; - private _poolFlag: number; - private _arrayBuffers: ArrayBuffer[] = []; - private _freelists: number[][] = []; - private _uint32BufferViews: Uint32Array[][] = []; - private _float32BufferViews: Float32Array[][] = []; - private _hasUint32 = false; - private _hasFloat32 = false; - private _nativePool: NativeBufferPool; - - constructor (poolType: P, dataType: BufferDataTypeManifest, enumType: E, entryBits = 8) { - this._elementCount = enumType.COUNT; - this._entryBits = entryBits; - this._dataType = dataType; - - const bytesPerElement = 4; - this._stride = bytesPerElement * this._elementCount; - this._entriesPerChunk = 1 << entryBits; - this._entryMask = this._entriesPerChunk - 1; - this._poolFlag = 1 << 30; - this._chunkMask = ~(this._entryMask | this._poolFlag); - this._nativePool = new NativeBufferPool(poolType, entryBits, this._stride); - - let type: BufferDataType = BufferDataType.NEVER; - let hasFloat32 = false; let hasUint32 = false; - for (const e in dataType) { - hasFloat32 = this._hasFloat32; - hasUint32 = this._hasUint32; - if (hasUint32 && hasFloat32) { - break; - } - - type = dataType[e as E[keyof E]]; - if (!hasFloat32 && type === BufferDataType.FLOAT32) { - this._hasFloat32 = true; - } else if (!hasUint32 && type === BufferDataType.UINT32) { - this._hasUint32 = true; - } - } - } - - public alloc (): IHandle

{ - let i = 0; - for (; i < this._freelists.length; i++) { - const list = this._freelists[i]; - if (list.length) { - const j = list[list.length - 1]; list.length--; - return (i << this._entryBits) + j + this._poolFlag as unknown as IHandle

; - } - } - // add a new chunk - const buffer = this._nativePool.allocateNewChunk(); - const float32BufferViews: Float32Array[] = []; - const uint32BufferViews: Uint32Array[] = []; - const freelist: number[] = []; - const hasFloat32 = this._hasFloat32; - const hasUint32 = this._hasUint32; - for (let j = 0; j < this._entriesPerChunk; j++) { - if (hasFloat32) { float32BufferViews.push(new Float32Array(buffer, this._stride * j, this._elementCount)); } - if (hasUint32) { uint32BufferViews.push(new Uint32Array(buffer, this._stride * j, this._elementCount)); } - if (j) { freelist.push(j); } - } - this._arrayBuffers.push(buffer); - if (hasUint32) { this._uint32BufferViews.push(uint32BufferViews); } - if (hasFloat32) { this._float32BufferViews.push(float32BufferViews); } - this._freelists.push(freelist); - return (i << this._entryBits) + this._poolFlag as unknown as IHandle

; // guarantees the handle is always not zero - } - - /** - * Get the specified element out from buffer pool. - * - * Note the type inference does not work when `element` is not directly - * an pre-declared enum value: (e.g. when doing arithmetic operations) - * ```ts - * SubModelPool.get(handle, SubModelView.SHADER_0 + passIndex); // the return value will have type GeneralBufferElement - * ``` - * - * To properly declare the variable type, you have two options: - * ```ts - * const hShader = SubModelPool.get(handle, SubModelView.SHADER_0 + passIndex) as ShaderHandle; // option #1 - * const hShader = SubModelPool.get(handle, SubModelView.SHADER_0 + passIndex); // option #2 - * ``` - */ - public get (handle: IHandle

, element: K): Extract { - const chunk = (this._chunkMask & handle as unknown as number) >> this._entryBits; - const entry = this._entryMask & handle as unknown as number; - const bufferViews = this._dataType[element] === BufferDataType.UINT32 ? this._uint32BufferViews : this._float32BufferViews; - if (DEBUG && (!handle || chunk < 0 || chunk >= bufferViews.length - || entry < 0 || entry >= this._entriesPerChunk || contains(this._freelists[chunk], entry))) { - console.warn('invalid buffer pool handle'); - return 0 as Extract; - } - return bufferViews[chunk][entry][element as number] as Extract; - } - - public set (handle: IHandle

, element: K, value: Extract) { - const chunk = (this._chunkMask & handle as unknown as number) >> this._entryBits; - const entry = this._entryMask & handle as unknown as number; - const bufferViews = this._dataType[element] === BufferDataType.UINT32 ? this._uint32BufferViews : this._float32BufferViews; - if (DEBUG && (!handle || chunk < 0 || chunk >= bufferViews.length - || entry < 0 || entry >= this._entriesPerChunk || contains(this._freelists[chunk], entry))) { - console.warn('invalid buffer pool handle'); - return; - } - bufferViews[chunk][entry][element as number] = value as number; - } - - public setVec2 (handle: IHandle

, element: K, vec2: Extract) { - // Web engine has Vec2 property, don't record it in shared memory. - if (!JSB) { return; } - - const chunk = (this._chunkMask & handle as unknown as number) >> this._entryBits; - const entry = this._entryMask & handle as unknown as number; - const bufferViews = this._dataType[element] === BufferDataType.UINT32 ? this._uint32BufferViews : this._float32BufferViews; - if (DEBUG && (!handle || chunk < 0 || chunk >= bufferViews.length - || entry < 0 || entry >= this._entriesPerChunk || contains(this._freelists[chunk], entry))) { - console.warn('invalid buffer pool handle'); - return; - } - let index = element as unknown as number; - const view = bufferViews[chunk][entry]; - view[index++] = vec2.x; view[index++] = vec2.y; - } - - public setVec3 (handle: IHandle

, element: K, vec3: Extract) { - // Web engine has Vec3 property, don't record it in shared memory. - if (!JSB) { return; } - - const chunk = (this._chunkMask & handle as unknown as number) >> this._entryBits; - const entry = this._entryMask & handle as unknown as number; - const bufferViews = this._dataType[element] === BufferDataType.UINT32 ? this._uint32BufferViews : this._float32BufferViews; - if (DEBUG && (!handle || chunk < 0 || chunk >= bufferViews.length - || entry < 0 || entry >= this._entriesPerChunk || contains(this._freelists[chunk], entry))) { - console.warn('invalid buffer pool handle'); - return; - } - let index = element as unknown as number; - const view = bufferViews[chunk][entry]; - view[index++] = vec3.x; view[index++] = vec3.y; view[index] = vec3.z; - } - - public getVec3 (handle: IHandle

, element: K, vec3: Extract) { - // Web engine has Vec3 property, don't record it in shared memory. - if (!JSB) { return; } - - const chunk = (this._chunkMask & handle as unknown as number) >> this._entryBits; - const entry = this._entryMask & handle as unknown as number; - const bufferViews = this._dataType[element] === BufferDataType.UINT32 ? this._uint32BufferViews : this._float32BufferViews; - if (DEBUG && (!handle || chunk < 0 || chunk >= bufferViews.length - || entry < 0 || entry >= this._entriesPerChunk || contains(this._freelists[chunk], entry))) { - console.warn('invalid buffer pool handle'); - return; - } - let index = element as unknown as number; - const view = bufferViews[chunk][entry]; - vec3.x = view[index++]; vec3.y = view[index++]; vec3.z = view[index]; - } - - public setVec4 (handle: IHandle

, element: K, vec4: Extract) { - // Web engine has Vec4 property, don't record it in shared memory. - if (!JSB) { return; } - - const chunk = (this._chunkMask & handle as unknown as number) >> this._entryBits; - const entry = this._entryMask & handle as unknown as number; - const bufferViews = this._dataType[element] === BufferDataType.UINT32 ? this._uint32BufferViews : this._float32BufferViews; - if (DEBUG && (!handle || chunk < 0 || chunk >= bufferViews.length - || entry < 0 || entry >= this._entriesPerChunk || contains(this._freelists[chunk], entry))) { - console.warn('invalid buffer pool handle'); - return; - } - let index = element as unknown as number; - const view = bufferViews[chunk][entry]; - view[index++] = vec4.x; view[index++] = vec4.y; - view[index++] = vec4.z; view[index] = vec4.w; - } - - public getVec4 (handle: IHandle

, element: K, vec4: Extract) { - // Web engine has Vec4 property, don't record it in shared memory. - if (!JSB) { return; } - - const chunk = (this._chunkMask & handle as unknown as number) >> this._entryBits; - const entry = this._entryMask & handle as unknown as number; - const bufferViews = this._dataType[element] === BufferDataType.UINT32 ? this._uint32BufferViews : this._float32BufferViews; - if (DEBUG && (!handle || chunk < 0 || chunk >= bufferViews.length - || entry < 0 || entry >= this._entriesPerChunk || contains(this._freelists[chunk], entry))) { - console.warn('invalid buffer pool handle'); - return; - } - let index = element as unknown as number; - const view = bufferViews[chunk][entry]; - vec4.x = view[index++]; vec4.y = view[index++]; - vec4.z = view[index++]; vec4.w = view[index]; - } - - public setMat4 (handle: IHandle

, element: K, mat4: Extract) { - // Web engine has mat4 property, don't record it in shared memory. - if (!JSB) { return; } - - const chunk = (this._chunkMask & handle as unknown as number) >> this._entryBits; - const entry = this._entryMask & handle as unknown as number; - const bufferViews = this._dataType[element] === BufferDataType.UINT32 ? this._uint32BufferViews : this._float32BufferViews; - if (DEBUG && (!handle || chunk < 0 || chunk >= bufferViews.length - || entry < 0 || entry >= this._entriesPerChunk || contains(this._freelists[chunk], entry))) { - console.warn('invalid buffer pool handle'); - return; - } - let index = element as unknown as number; - const view = bufferViews[chunk][entry]; - view[index++] = mat4.m00; view[index++] = mat4.m01; view[index++] = mat4.m02; view[index++] = mat4.m03; - view[index++] = mat4.m04; view[index++] = mat4.m05; view[index++] = mat4.m06; view[index++] = mat4.m07; - view[index++] = mat4.m08; view[index++] = mat4.m09; view[index++] = mat4.m10; view[index++] = mat4.m11; - view[index++] = mat4.m12; view[index++] = mat4.m13; view[index++] = mat4.m14; view[index] = mat4.m15; - } - - public free (handle: IHandle

) { - const chunk = (this._chunkMask & handle as unknown as number) >> this._entryBits; - const entry = this._entryMask & handle as unknown as number; - if (DEBUG && (!handle || chunk < 0 || chunk >= this._freelists.length - || entry < 0 || entry >= this._entriesPerChunk || contains(this._freelists[chunk], entry))) { - console.warn('invalid buffer pool handle'); - return; - } - const bufferViews = this._hasUint32 ? this._uint32BufferViews : this._float32BufferViews; - bufferViews[chunk][entry].fill(0); - this._freelists[chunk].push(entry); - } -} - -export class ObjectPool implements IMemoryPool

{ - private _ctor: (args: A, obj?: T) => T; - - private _dtor?: (obj: T) => T | undefined; - - private _indexMask: number; - - private _poolFlag: number; - - private _array: (T | undefined)[] = []; - - private _freelist: number[] = []; - - private _nativePool: NativeObjectPool; - - constructor (poolType: P, ctor: (args: A, obj?: T) => T, dtor?: (obj: T) => T | undefined) { - this._ctor = ctor; - if (dtor) { this._dtor = dtor; } - this._poolFlag = 1 << 29; - this._indexMask = ~this._poolFlag; - this._nativePool = new NativeObjectPool(poolType, this._array); - } - - public alloc (...args: A): IHandle

{ - const freelist = this._freelist; - let i = -1; - if (freelist.length) { - i = freelist[freelist.length - 1]; - freelist.length--; - this._array[i] = this._ctor(arguments as unknown as A, this._array[i]); - } else { - i = this._array.length; - const obj = this._ctor(arguments as unknown as A); - if (!obj) { return 0 as unknown as IHandle

; } - this._array.push(obj); - } - if (JSB) this._nativePool.bind(i, this._array[i] as T); - return i + this._poolFlag as unknown as IHandle

; // guarantees the handle is always not zero - } - - public get (handle: IHandle

): R { - const index = this._indexMask & handle as unknown as number; - if (DEBUG && (!handle || index < 0 || index >= this._array.length || contains(this._freelist, index))) { - console.warn('invalid object pool handle'); - return null!; - } - return this._array[index] as R; - } - - public free (handle: IHandle

): void { - const index = this._indexMask & handle as unknown as number; - if (DEBUG && (!handle || index < 0 || index >= this._array.length || contains(this._freelist, index))) { - console.warn('invalid object pool handle'); - return; - } - if (this._dtor) { this._array[index] = this._dtor(this._array[index]!); } - this._freelist.push(index); - } -} - -class BufferAllocator

implements IMemoryPool

{ - protected _nativeBufferAllocator: NativeBufferAllocator; - - protected _buffers = new Map(); - - protected _nextBufferIdx = 0; - - protected _poolFlag: number; - - protected _bufferIdxMask: number; - protected _freelist: number[] = []; - - constructor (poolType: P) { - this._poolFlag = 1 << 30; - this._bufferIdxMask = ~this._poolFlag; - this._nativeBufferAllocator = new NativeBufferAllocator(poolType); - } - - public alloc (size: number): IHandle

{ - const freelist = this._freelist; - let bufferIdx = -1; - if (freelist.length) { - bufferIdx = freelist[freelist.length - 1]; - freelist.length--; - } else { - bufferIdx = this._nextBufferIdx++; - } - - const buffer = this._nativeBufferAllocator.alloc(bufferIdx, size); - this._buffers.set(bufferIdx, buffer); - return (bufferIdx | this._poolFlag) as unknown as IHandle

; - } - - public free (handle: IHandle

) { - const bufferIdx = this._bufferIdxMask & handle as unknown as number; - if (!this._buffers.get(bufferIdx)) { - if (DEBUG) { console.warn('invalid buffer allocator handle'); } - return; - } - this._nativeBufferAllocator.free(bufferIdx); - this._buffers.delete(bufferIdx); - this._freelist.push(bufferIdx); - } - - public getBuffer (handle: IHandle

): ArrayBuffer { - const bufferIdx = this._bufferIdxMask & handle as unknown as number; - const buffer = this._buffers.get(bufferIdx); - if (!buffer) { - if (DEBUG) { console.warn('invalid array pool index or invalid array handle'); } - return null!; - } - return buffer; - } -} - -class TypedArrayPool

- extends BufferAllocator

implements IMemoryPool

{ - declare protected _buffers: Map>; - - protected _viewCtor: T; - - protected _size: number; - - protected _step: number; - - constructor (poolType: P, viewCtor: T, size: number, step?: number) { - super(poolType); - this._viewCtor = viewCtor; - this._size = size * viewCtor.BYTES_PER_ELEMENT; - this._step = step || size; - } - - public alloc (): IHandle

{ - const bufferIdx = this._nextBufferIdx++; - const buffer = this._nativeBufferAllocator.alloc(bufferIdx, this._size); - this._buffers.set(bufferIdx, new this._viewCtor(buffer) as InstanceType); - return (bufferIdx | this._poolFlag) as unknown as IHandle

; - } - - // no direct buffer accesses for array pools - public getBuffer (handle: IHandle

): never { return null!; } - - public assign (handle: IHandle

, targetIdx: number, value: D) { - const bufferIdx = this._bufferIdxMask & handle as unknown as number; - let array = this._buffers.get(bufferIdx); - if (!array) { - if (DEBUG) { console.warn('invalid array pool handle'); } - return; - } - - // First element is the length of array. - const index = targetIdx + 1; - if (index >= array.length) { - let newSize = array.length; - while (index >= newSize) { newSize += this._step; } - newSize *= this._viewCtor.BYTES_PER_ELEMENT; - const newArray = new this._viewCtor(this._nativeBufferAllocator.alloc(bufferIdx, newSize)) as InstanceType; - newArray.set(array); array = newArray; - this._buffers.set(bufferIdx, array); - } - array[index] = value as unknown as number; - - // There may be holes in the array. - const len = array[0]; - array[0] = index > len ? index : len; - } - - public erase (handle: IHandle

, index: number) { - const bufferIdx = this._bufferIdxMask & handle as unknown as number; - const array = this._buffers.get(bufferIdx); - if (!array || index >= array[0]) { - if (DEBUG) { console.warn('invalid array pool index or invalid array handle'); } - return; - } - for (let i = index + 1; i < array[0]; ++i) { - array[i] = array[i + 1]; - } - --array[0]; - } - - public push (handle: IHandle

, value: D) { - const bufferIdx = this._bufferIdxMask & handle as unknown as number; - const array = this._buffers.get(bufferIdx); - if (!array) { - if (DEBUG) { console.warn('invalid array pool handle'); } - return; - } - - this.assign(handle, array[0], value); - } - - public pop (handle: IHandle

) { - const bufferIdx = this._bufferIdxMask & handle as unknown as number; - const array = this._buffers.get(bufferIdx); - if (!array) { - if (DEBUG) { console.warn('invalid array pool handle'); } - return; - } - - if (array[0] !== 0) --array[0]; - } - - public clear (handle: IHandle

) { - const bufferIdx = this._bufferIdxMask & handle as unknown as number; - const array = this._buffers.get(bufferIdx); - if (!array) { - if (DEBUG) { console.warn('invalid array pool handle'); } - return; - } - array[0] = 0; - } - - public get (handle: IHandle

, index: number): D { - const bufferIdx = this._bufferIdxMask & handle as unknown as number; - const array = this._buffers.get(bufferIdx); - if (!array || index >= array[0]) { - if (DEBUG) { console.warn('invalid array pool handle'); } - return 0 as D; - } - return array[index + 1] as D; - } - - public length (handle: IHandle

) { - const bufferIdx = this._bufferIdxMask & handle as unknown as number; - const array = this._buffers.get(bufferIdx); - if (!array) { - if (DEBUG) { console.warn('invalid array pool handle'); } - return 0; - } - return array[0]; - } -} - -export function freeHandleArray

> ( - arrayHandle: IHandle

, - arrayPool: TypedArrayPool, - elementPool: IMemoryPool, - freeArrayItself = true, -): void { - const count = arrayPool.length(arrayHandle); - for (let i = 0; i < count; i++) { - const element = arrayPool.get(arrayHandle, i); - if (element) { elementPool.free(element); } - } - if (freeArrayItself) { arrayPool.free(arrayHandle); } else { arrayPool.clear(arrayHandle); } + private _dataType: BufferDataTypeManifest; + private _dataMembers: BufferDataMembersManifest; + private _elementCount: number; + private _entryBits: number; + private _stride: number; + private _entriesPerChunk: number; + private _entryMask: number; + private _chunkMask: number; + private _poolFlag: number; + private _arrayBuffers: ArrayBuffer[] = []; + private _freeLists: number[][] = []; + private _uint32BufferViews: Uint32Array[][] = []; + private _float32BufferViews: Float32Array[][] = []; + private _hasUint32 = false; + private _hasFloat32 = false; + private _nativePool: NativeBufferPool; + + constructor (poolType: P, dataType: BufferDataTypeManifest, dataMembers: BufferDataMembersManifest, enumType: E, entryBits = 8) { + this._elementCount = enumType.COUNT; + this._entryBits = entryBits; + this._dataType = dataType; + this._dataMembers = dataMembers; + + const bytesPerElement = 4; + this._stride = bytesPerElement * this._elementCount; + this._entriesPerChunk = 1 << entryBits; + this._entryMask = this._entriesPerChunk - 1; + this._poolFlag = 1 << 30; + this._chunkMask = ~(this._entryMask | this._poolFlag); + this._nativePool = new NativeBufferPool(poolType, entryBits, this._stride); + + let type: BufferDataType = BufferDataType.NEVER; + let hasFloat32 = false; let hasUint32 = false; + for (const e in dataType) { + hasFloat32 = this._hasFloat32; + hasUint32 = this._hasUint32; + if (hasUint32 && hasFloat32) { + break; + } + + type = dataType[e as E[keyof E]]; + if (!hasFloat32 && type === BufferDataType.FLOAT32) { + this._hasFloat32 = true; + } else if (!hasUint32 && type === BufferDataType.UINT32) { + this._hasUint32 = true; + } + } + } + + public alloc (): IHandle

{ + let i = 0; + for (; i < this._freeLists.length; i++) { + const list = this._freeLists[i]; + if (list.length) { + const j = list[list.length - 1]; list.length--; + return (i << this._entryBits) + j + this._poolFlag as unknown as IHandle

; + } + } + // add a new chunk + const buffer = this._nativePool.allocateNewChunk(); + const float32BufferViews: Float32Array[] = []; + const uint32BufferViews: Uint32Array[] = []; + const freeList: number[] = []; + const hasFloat32 = this._hasFloat32; + const hasUint32 = this._hasUint32; + for (let j = 0; j < this._entriesPerChunk; j++) { + if (hasFloat32) { float32BufferViews.push(new Float32Array(buffer, this._stride * j, this._elementCount)); } + if (hasUint32) { uint32BufferViews.push(new Uint32Array(buffer, this._stride * j, this._elementCount)); } + if (j) { freeList.push(j); } + } + if (hasUint32) { this._uint32BufferViews.push(uint32BufferViews); } + if (hasFloat32) { this._float32BufferViews.push(float32BufferViews); } + this._freeLists.push(freeList); + this._arrayBuffers.push(buffer); + const handle = (i << this._entryBits) + this._poolFlag as unknown as IHandle

; + return handle; // guarantees the handle is always not zero + } + + public getBuffer (handle: IHandle

): BufferArrayType { + const chunk = (this._chunkMask & handle as unknown as number) >> this._entryBits; + const entry = this._entryMask & handle as unknown as number; + const bufferViews = this._float32BufferViews; + if (DEBUG && (!handle || chunk < 0 || chunk >= bufferViews.length + || entry < 0 || entry >= this._entriesPerChunk || contains(this._freeLists[chunk], entry))) { + console.warn('invalid buffer pool handle'); + return [] as unknown as BufferArrayType; + } + + return bufferViews[chunk][entry]; + } + + public getTypedArray (handle: IHandle

, element: K): BufferArrayType { + const chunk = (this._chunkMask & handle as unknown as number) >> this._entryBits; + const entry = this._entryMask & handle as unknown as number; + const bufferViews = this._dataType[element] === BufferDataType.UINT32 ? this._uint32BufferViews : this._float32BufferViews; + if (DEBUG && (!handle || chunk < 0 || chunk >= bufferViews.length + || entry < 0 || entry >= this._entriesPerChunk || contains(this._freeLists[chunk], entry))) { + console.warn('invalid buffer pool handle'); + return [] as unknown as BufferArrayType; + } + const index = element as unknown as number; + const view = bufferViews[chunk][entry]; + const count = this._dataMembers[element]; + + return view.subarray(index, index + count); + } + + public free (handle: IHandle

) { + const chunk = (this._chunkMask & handle as unknown as number) >> this._entryBits; + const entry = this._entryMask & handle as unknown as number; + if (DEBUG && (!handle || chunk < 0 || chunk >= this._freeLists.length + || entry < 0 || entry >= this._entriesPerChunk || contains(this._freeLists[chunk], entry))) { + console.warn('invalid buffer pool handle'); + return; + } + const bufferViews = this._hasUint32 ? this._uint32BufferViews : this._float32BufferViews; + bufferViews[chunk][entry].fill(0); + this._freeLists[chunk].push(entry); + // free + if (this._freeLists[chunk].length === this._entriesPerChunk && this._freeLists.length > 1) { + this._freeLists.splice(chunk, 1); + this._arrayBuffers.splice(chunk, 1); + } + } } export enum PoolType { - // objects - ATTRIBUTE, - DESCRIPTOR_SETS, - SHADER, - INPUT_ASSEMBLER, - PIPELINE_LAYOUT, - FRAMEBUFFER, // buffers - PASS = 100, - SUB_MODEL, - MODEL, - SCENE, - CAMERA, - NODE, - ROOT, - AABB, - RENDER_WINDOW, - FRUSTUM, - AMBIENT, - FOG, - SKYBOX, - SHADOW, - LIGHT, - SPHERE, - INSTANCED_ATTRIBUTE, - FLAT_BUFFER, - SUB_MESH, - RASTERIZER_STATE, - DEPTH_STENCIL_STATE, - BLEND_TARGET, - BLEND_STATE, - BATCH_2D, - PIPELINE_SCENE_DATA, - // arrays - SUB_MODEL_ARRAY = 200, - MODEL_ARRAY, - ATTRIBUTE_ARRAY, - FLAT_BUFFER_ARRAY, - INSTANCED_BUFFER_ARRAY, - LIGHT_ARRAY, - BLEND_TARGET_ARRAY, - BATCH_ARRAY_2D, - // raw resources - RAW_BUFFER = 300, - RAW_OBJECT = 400, + NODE = 100, } export const NULL_HANDLE = 0 as unknown as IHandle; -export type AttributeHandle = IHandle; -export type DescriptorSetHandle = IHandle; -export type ShaderHandle = IHandle; -export type InputAssemblerHandle = IHandle; -export type PipelineLayoutHandle = IHandle; -export type FramebufferHandle = IHandle; -export type PassHandle = IHandle; -export type SubModelHandle = IHandle; -export type ModelHandle = IHandle; -export type SceneHandle = IHandle; -export type CameraHandle = IHandle; export type NodeHandle = IHandle; -export type RootHandle = IHandle; -export type AABBHandle = IHandle; -export type FrustumHandle = IHandle; -export type RenderWindowHandle = IHandle; -export type SubModelArrayHandle = IHandle; -export type AttributeArrayHandle = IHandle; -export type ModelArrayHandle = IHandle; -export type RawBufferHandle = IHandle; -export type RawObjectHandle = IHandle; -export type AmbientHandle = IHandle; -export type FogHandle = IHandle; -export type SkyboxHandle = IHandle; -export type ShadowsHandle = IHandle; -export type LightHandle = IHandle; -export type SphereHandle = IHandle; -export type SubMeshHandle = IHandle; -export type FlatBufferHandle = IHandle; -export type FlatBufferArrayHandle = IHandle; -export type LightArrayHandle = IHandle; -export type BlendTargetArrayHandle = IHandle; -export type RasterizerStateHandle = IHandle; -export type DepthStencilStateHandle = IHandle; -export type BlendTargetHandle = IHandle; -export type BlendStateHandle = IHandle; -export type BatchHandle2D = IHandle; -export type UIBatchArrayHandle = IHandle; -export type PipelineSceneDataHandle = IHandle; - -export const ShaderPool = new ObjectPool(PoolType.SHADER, - (args: [device: Device, info: ShaderInfo], obj?: Shader) => ( - obj ? (obj.initialize(args[1]), obj) : args[0].createShader(args[1])), - (obj: Shader) => (obj && obj.destroy(), obj)); -export const DSPool = new ObjectPool(PoolType.DESCRIPTOR_SETS, - (args: [device: Device, info: DescriptorSetInfo], obj?: DescriptorSet) => ( - obj ? (obj.initialize(args[1]), obj) : args[0].createDescriptorSet(args[1])), - (obj: DescriptorSet) => (obj && obj.destroy(), obj)); -export const IAPool = new ObjectPool(PoolType.INPUT_ASSEMBLER, - (args: [device: Device, info: InputAssemblerInfo], obj?: InputAssembler) => ( - obj ? (obj.initialize(args[1]), obj) : args[0].createInputAssembler(args[1])), - (obj: InputAssembler) => (obj && obj.destroy(), obj)); -export const PipelineLayoutPool = new ObjectPool(PoolType.PIPELINE_LAYOUT, - (args: [device: Device, info: PipelineLayoutInfo], obj?: PipelineLayout) => ( - obj ? (obj.initialize(args[1]), obj) : args[0].createPipelineLayout(args[1])), - (obj: PipelineLayout) => (obj && obj.destroy(), obj)); -export const FramebufferPool = new ObjectPool(PoolType.FRAMEBUFFER, - (args: [device: Device, info: FramebufferInfo], obj?: Framebuffer) => ( - obj ? (obj.initialize(args[1]), obj) : args[0].createFramebuffer(args[1])), - (obj: Framebuffer) => (obj && obj.destroy(), obj)); - -export const SubModelArrayPool = new TypedArrayPool( - PoolType.SUB_MODEL_ARRAY, Uint32Array, 8, 4, -); -export const ModelArrayPool = new TypedArrayPool( - PoolType.MODEL_ARRAY, Uint32Array, 32, 16, -); -export const AttributeArrayPool = new TypedArrayPool( - PoolType.ATTRIBUTE_ARRAY, Uint32Array, 8, 4, -); -export const FlatBufferArrayPool = new TypedArrayPool( - PoolType.FLAT_BUFFER_ARRAY, Uint32Array, 8, 4, -); -export const LightArrayPool = new TypedArrayPool( - PoolType.LIGHT_ARRAY, Uint32Array, 8, 4, -); -export const BlendTargetArrayPool = new TypedArrayPool( - PoolType.BLEND_TARGET_ARRAY, Uint32Array, 8, 4, -); -export const UIBatchArrayPool = new TypedArrayPool( - PoolType.BATCH_ARRAY_2D, Uint32Array, 32, 16, -); - -export const RawBufferPool = new BufferAllocator(PoolType.RAW_BUFFER); -export const RawObjectPool = new ObjectPool(PoolType.RAW_OBJECT, - (args: [obj?: Record]) => args[0] || {}, (_: Record) => undefined); - -export enum PassView { - PRIORITY, - STAGE, - PHASE, - BATCHING_SCHEME, - PRIMITIVE, - DYNAMIC_STATES, - HASH, - RASTERIZER_STATE, // handle - DEPTH_STENCIL_STATE, // handle - BLEND_STATE, // handle - DESCRIPTOR_SET, // handle - PIPELINE_LAYOUT, // handle - COUNT, -} -interface IPassViewType extends BufferTypeManifest { - [PassView.PRIORITY]: number; - [PassView.STAGE]: RenderPassStage; - [PassView.PHASE]: number; - [PassView.BATCHING_SCHEME]: BatchingSchemes; - [PassView.PRIMITIVE]: PrimitiveMode; - [PassView.DYNAMIC_STATES]: DynamicStateFlags; - [PassView.HASH]: number; - [PassView.RASTERIZER_STATE]: RawBufferHandle; - [PassView.DEPTH_STENCIL_STATE]: RawBufferHandle; - [PassView.BLEND_STATE]: RawBufferHandle; - [PassView.DESCRIPTOR_SET]: DescriptorSetHandle; - [PassView.PIPELINE_LAYOUT]: PipelineLayoutHandle; - [PassView.COUNT]: never; -} -const passViewDataType: BufferDataTypeManifest = { - [PassView.PRIORITY]: BufferDataType.UINT32, - [PassView.STAGE]: BufferDataType.UINT32, - [PassView.PHASE]: BufferDataType.UINT32, - [PassView.BATCHING_SCHEME]: BufferDataType.UINT32, - [PassView.PRIMITIVE]: BufferDataType.UINT32, - [PassView.DYNAMIC_STATES]: BufferDataType.UINT32, - [PassView.HASH]: BufferDataType.UINT32, - [PassView.RASTERIZER_STATE]: BufferDataType.UINT32, - [PassView.DEPTH_STENCIL_STATE]: BufferDataType.UINT32, - [PassView.BLEND_STATE]: BufferDataType.UINT32, - [PassView.DESCRIPTOR_SET]: BufferDataType.UINT32, - [PassView.PIPELINE_LAYOUT]: BufferDataType.UINT32, - [PassView.COUNT]: BufferDataType.NEVER, -}; -// Theoretically we only have to declare the type view here while all the other arguments can be inferred. -// but before the official support of Partial Type Argument Inference releases, (microsoft/TypeScript#26349) -// we'll have to explicitly declare all these types. -export const PassPool = new BufferPool(PoolType.PASS, passViewDataType, PassView); - -export enum SubModelView { - PRIORITY, - PASS_COUNT, - PASS_0, // handle - PASS_1, // handle - PASS_2, // handle - PASS_3, // handle - PASS_4, // handle - PASS_5, // handle - PASS_6, // handle - PASS_7, // handle - SHADER_0, // handle - SHADER_1, // handle - SHADER_2, // handle - SHADER_3, // handle - SHADER_4, // handle - SHADER_5, // handle - SHADER_6, // handle - SHADER_7, // handle - PLANAR_SHADER, // handle - PLANAR_INSTANCE_SHADER, // handle - DESCRIPTOR_SET, // handle - INPUT_ASSEMBLER, // handle - SUB_MESH, // handle - COUNT, -} -interface ISubModelViewType extends BufferTypeManifest { - [SubModelView.PRIORITY]: number; - [SubModelView.PASS_COUNT]: number; - [SubModelView.PASS_0]: PassHandle; - [SubModelView.PASS_1]: PassHandle; - [SubModelView.PASS_2]: PassHandle; - [SubModelView.PASS_3]: PassHandle; - [SubModelView.PASS_4]: PassHandle; - [SubModelView.PASS_5]: PassHandle; - [SubModelView.PASS_6]: PassHandle; - [SubModelView.PASS_7]: PassHandle; - [SubModelView.SHADER_0]: ShaderHandle; - [SubModelView.SHADER_1]: ShaderHandle; - [SubModelView.SHADER_2]: ShaderHandle; - [SubModelView.SHADER_3]: ShaderHandle; - [SubModelView.SHADER_4]: ShaderHandle; - [SubModelView.SHADER_5]: ShaderHandle; - [SubModelView.SHADER_6]: ShaderHandle; - [SubModelView.SHADER_7]: ShaderHandle; - [SubModelView.PLANAR_SHADER]: ShaderHandle; - [SubModelView.PLANAR_INSTANCE_SHADER]: ShaderHandle; - [SubModelView.DESCRIPTOR_SET]: DescriptorSetHandle; - [SubModelView.INPUT_ASSEMBLER]: InputAssemblerHandle; - [SubModelView.SUB_MESH]: SubMeshHandle; - [SubModelView.COUNT]: never; -} -const subModelViewDataType: BufferDataTypeManifest = { - [SubModelView.PRIORITY]: BufferDataType.UINT32, - [SubModelView.PASS_COUNT]: BufferDataType.UINT32, - [SubModelView.PASS_0]: BufferDataType.UINT32, - [SubModelView.PASS_1]: BufferDataType.UINT32, - [SubModelView.PASS_2]: BufferDataType.UINT32, - [SubModelView.PASS_3]: BufferDataType.UINT32, - [SubModelView.PASS_4]: BufferDataType.UINT32, - [SubModelView.PASS_5]: BufferDataType.UINT32, - [SubModelView.PASS_6]: BufferDataType.UINT32, - [SubModelView.PASS_7]: BufferDataType.UINT32, - [SubModelView.SHADER_0]: BufferDataType.UINT32, - [SubModelView.SHADER_1]: BufferDataType.UINT32, - [SubModelView.SHADER_2]: BufferDataType.UINT32, - [SubModelView.SHADER_3]: BufferDataType.UINT32, - [SubModelView.SHADER_4]: BufferDataType.UINT32, - [SubModelView.SHADER_5]: BufferDataType.UINT32, - [SubModelView.SHADER_6]: BufferDataType.UINT32, - [SubModelView.SHADER_7]: BufferDataType.UINT32, - [SubModelView.PLANAR_SHADER]: BufferDataType.UINT32, - [SubModelView.PLANAR_INSTANCE_SHADER]: BufferDataType.UINT32, - [SubModelView.DESCRIPTOR_SET]: BufferDataType.UINT32, - [SubModelView.INPUT_ASSEMBLER]: BufferDataType.UINT32, - [SubModelView.SUB_MESH]: BufferDataType.UINT32, - [SubModelView.COUNT]: BufferDataType.NEVER, -}; -// Theoretically we only have to declare the type view here while all the other arguments can be inferred. -// but before the official support of Partial Type Argument Inference releases, (microsoft/TypeScript#26349) -// we'll have to explicitly declare all these types. -export const SubModelPool = new BufferPool( - PoolType.SUB_MODEL, subModelViewDataType, SubModelView, -); - -export enum ModelView { - ENABLED, - VIS_FLAGS, - CAST_SHADOW, - RECEIVE_SHADOW, - WORLD_BOUNDS, // handle - NODE, // handle - TRANSFORM, // handle - SUB_MODEL_ARRAY, // array handle - INSTANCED_BUFFER, // raw buffer handle - INSTANCED_ATTR_ARRAY, // array handle - COUNT, -} -interface IModelViewType extends BufferTypeManifest { - [ModelView.ENABLED]: number; - [ModelView.VIS_FLAGS]: number; - [ModelView.CAST_SHADOW]: number; - [ModelView.RECEIVE_SHADOW]: number; - [ModelView.WORLD_BOUNDS]: AABBHandle; - [ModelView.NODE]: NodeHandle; - [ModelView.TRANSFORM]: NodeHandle; - [ModelView.SUB_MODEL_ARRAY]: SubModelArrayHandle; - [ModelView.INSTANCED_BUFFER]: RawBufferHandle; - [ModelView.INSTANCED_ATTR_ARRAY]: AttributeArrayHandle; - [ModelView.COUNT]: never; -} -const modelViewDataType: BufferDataTypeManifest = { - [ModelView.ENABLED]: BufferDataType.UINT32, - [ModelView.VIS_FLAGS]: BufferDataType.UINT32, - [ModelView.CAST_SHADOW]: BufferDataType.UINT32, - [ModelView.RECEIVE_SHADOW]: BufferDataType.UINT32, - [ModelView.WORLD_BOUNDS]: BufferDataType.UINT32, - [ModelView.NODE]: BufferDataType.UINT32, - [ModelView.TRANSFORM]: BufferDataType.UINT32, - [ModelView.SUB_MODEL_ARRAY]: BufferDataType.UINT32, - [ModelView.INSTANCED_BUFFER]: BufferDataType.UINT32, - [ModelView.INSTANCED_ATTR_ARRAY]: BufferDataType.UINT32, - [ModelView.COUNT]: BufferDataType.NEVER, -}; -// Theoretically we only have to declare the type view here while all the other arguments can be inferred. -// but before the official support of Partial Type Argument Inference releases, (microsoft/TypeScript#26349) -// we'll have to explicitly declare all these types. -export const ModelPool = new BufferPool(PoolType.MODEL, modelViewDataType, ModelView); - -export enum BatchView2D { - VIS_FLAGS, - PASS_COUNT, - PASS_0, // handle - PASS_1, // handle - PASS_2, // handle - PASS_3, // handle - SHADER_0, // handle - SHADER_1, // handle - SHADER_2, // handle - SHADER_3, // handle - DESCRIPTOR_SET, // handle - INPUT_ASSEMBLER, // handle - COUNT, -} -interface IBatchView2DType extends BufferTypeManifest { - [BatchView2D.VIS_FLAGS]: number; - [BatchView2D.PASS_COUNT]: number; - [BatchView2D.PASS_0]: PassHandle; - [BatchView2D.PASS_1]: PassHandle; - [BatchView2D.PASS_2]: PassHandle; - [BatchView2D.PASS_3]: PassHandle; - [BatchView2D.SHADER_0]: ShaderHandle; - [BatchView2D.SHADER_1]: ShaderHandle; - [BatchView2D.SHADER_2]: ShaderHandle; - [BatchView2D.SHADER_3]: ShaderHandle; - [BatchView2D.DESCRIPTOR_SET]: DescriptorSetHandle; - [BatchView2D.INPUT_ASSEMBLER]: InputAssemblerHandle; - [BatchView2D.COUNT]: never; -} -const batchView2DDataType: BufferDataTypeManifest = { - [BatchView2D.VIS_FLAGS]: BufferDataType.UINT32, - [BatchView2D.PASS_COUNT]: BufferDataType.UINT32, - [BatchView2D.PASS_0]: BufferDataType.UINT32, - [BatchView2D.PASS_1]: BufferDataType.UINT32, - [BatchView2D.PASS_2]: BufferDataType.UINT32, - [BatchView2D.PASS_3]: BufferDataType.UINT32, - [BatchView2D.SHADER_0]: BufferDataType.UINT32, - [BatchView2D.SHADER_1]: BufferDataType.UINT32, - [BatchView2D.SHADER_2]: BufferDataType.UINT32, - [BatchView2D.SHADER_3]: BufferDataType.UINT32, - [BatchView2D.DESCRIPTOR_SET]: BufferDataType.UINT32, - [BatchView2D.INPUT_ASSEMBLER]: BufferDataType.UINT32, - [BatchView2D.COUNT]: BufferDataType.NEVER, -}; - -export const BatchPool2D = new BufferPool( - PoolType.BATCH_2D, batchView2DDataType, BatchView2D, -); - -export enum AABBView { - CENTER, // Vec3 - HALF_EXTENSION = 3, // Vec3 - COUNT = 6, -} -interface IAABBViewType extends BufferTypeManifest { - [AABBView.CENTER]: Vec3; - [AABBView.HALF_EXTENSION]: Vec3; - [AABBView.COUNT]: never; -} -const aabbViewDataType: BufferDataTypeManifest = { - [AABBView.CENTER]: BufferDataType.FLOAT32, - [AABBView.HALF_EXTENSION]: BufferDataType.FLOAT32, - [AABBView.COUNT]: BufferDataType.NEVER, -}; -// Theoretically we only have to declare the type view here while all the other arguments can be inferred. -// but before the official support of Partial Type Argument Inference releases, (microsoft/TypeScript#26349) -// we'll have to explicitly declare all these types. -export const AABBPool = new BufferPool(PoolType.AABB, aabbViewDataType, AABBView); - -export enum SceneView { - MAIN_LIGHT, // handle - MODEL_ARRAY, // array handle - SPHERE_LIGHT_ARRAY, // array handle - SPOT_LIGHT_ARRAY, // array handle - BATCH_ARRAY_2D, // array handle - COUNT, -} -interface ISceneViewType extends BufferTypeManifest { - [SceneView.MAIN_LIGHT]: LightHandle; - [SceneView.MODEL_ARRAY]: ModelArrayHandle; - [SceneView.SPHERE_LIGHT_ARRAY]: LightArrayHandle; - [SceneView.SPOT_LIGHT_ARRAY]: LightArrayHandle; - [SceneView.BATCH_ARRAY_2D]: UIBatchArrayHandle; - [SceneView.COUNT]: never; -} -const sceneViewDataType: BufferDataTypeManifest = { - [SceneView.MAIN_LIGHT]: BufferDataType.UINT32, - [SceneView.MODEL_ARRAY]: BufferDataType.UINT32, - [SceneView.SPHERE_LIGHT_ARRAY]: BufferDataType.UINT32, - [SceneView.SPOT_LIGHT_ARRAY]: BufferDataType.UINT32, - [SceneView.BATCH_ARRAY_2D]: BufferDataType.UINT32, - [SceneView.COUNT]: BufferDataType.NEVER, -}; -// Theoretically we only have to declare the type view here while all the other arguments can be inferred. -// but before the official support of Partial Type Argument Inference releases, (microsoft/TypeScript#26349) -// we'll have to explicitly declare all these types. -export const ScenePool = new BufferPool(PoolType.SCENE, sceneViewDataType, SceneView); - -export enum CameraView { - WIDTH, - HEIGHT, - EXPOSURE, - CLEAR_FLAGS, - CLEAR_DEPTH, - CLEAR_STENCIL, - VISIBILITY, - NODE, // handle - SCENE, // handle - FRUSTUM, // handle - WINDOW, // handle - FORWARD, // Vec3 - POSITION = 14, // Vec3 - VIEW_PORT = 17, // Rect - CLEAR_COLOR = 21, // Color - MAT_VIEW = 25, // Mat4 - MAT_VIEW_PROJ = 41, // Mat4 - MAT_VIEW_PROJ_INV = 57, // Mat4 - MAT_PROJ = 73, // Mat4 - MAT_PROJ_INV = 89, // Mat4 - MAT_VIEW_PROJ_OFFSCREEN = 105, // Mat4 - MAT_VIEW_PROJ_INV_OFFSCREEN = 121, // Mat4 - MAT_PROJ_OFFSCREEN = 137, // Mat4 - MAT_PROJ_INV_OFFSCREEN = 153, // Mat4 - COUNT = 169 -} -interface ICameraViewType extends BufferTypeManifest { - [CameraView.WIDTH]: number; - [CameraView.HEIGHT]: number; - [CameraView.EXPOSURE]: number; - [CameraView.CLEAR_FLAGS]: ClearFlags; - [CameraView.CLEAR_DEPTH]: number; - [CameraView.CLEAR_STENCIL]: number; - [CameraView.VISIBILITY]: number, - [CameraView.NODE]: NodeHandle; - [CameraView.SCENE]: SceneHandle; - [CameraView.FRUSTUM]: FrustumHandle; - [CameraView.WINDOW]: RenderWindowHandle; - [CameraView.FORWARD]: Vec3; - [CameraView.POSITION]: Vec3; - [CameraView.VIEW_PORT]: Rect; - [CameraView.CLEAR_COLOR]: IVec4Like; - [CameraView.MAT_VIEW]: Mat4; - [CameraView.MAT_VIEW_PROJ]: Mat4; - [CameraView.MAT_VIEW_PROJ_INV]: Mat4; - [CameraView.MAT_PROJ]: Mat4; - [CameraView.MAT_PROJ_INV]: Mat4; - [CameraView.MAT_VIEW_PROJ_OFFSCREEN]: Mat4; - [CameraView.MAT_VIEW_PROJ_INV_OFFSCREEN]: Mat4; - [CameraView.MAT_PROJ_OFFSCREEN]: Mat4; - [CameraView.MAT_PROJ_INV_OFFSCREEN]: Mat4; - [CameraView.COUNT]: never; -} -const cameraViewDataType: BufferDataTypeManifest = { - [CameraView.WIDTH]: BufferDataType.UINT32, - [CameraView.HEIGHT]: BufferDataType.UINT32, - [CameraView.EXPOSURE]: BufferDataType.FLOAT32, - [CameraView.CLEAR_FLAGS]: BufferDataType.UINT32, - [CameraView.CLEAR_DEPTH]: BufferDataType.FLOAT32, - [CameraView.CLEAR_STENCIL]: BufferDataType.UINT32, - [CameraView.VISIBILITY]: BufferDataType.UINT32, - [CameraView.NODE]: BufferDataType.UINT32, - [CameraView.SCENE]: BufferDataType.UINT32, - [CameraView.FRUSTUM]: BufferDataType.UINT32, - [CameraView.WINDOW]: BufferDataType.UINT32, - [CameraView.FORWARD]: BufferDataType.FLOAT32, - [CameraView.POSITION]: BufferDataType.FLOAT32, - [CameraView.VIEW_PORT]: BufferDataType.FLOAT32, - [CameraView.CLEAR_COLOR]: BufferDataType.FLOAT32, - [CameraView.MAT_VIEW]: BufferDataType.FLOAT32, - [CameraView.MAT_VIEW_PROJ]: BufferDataType.FLOAT32, - [CameraView.MAT_VIEW_PROJ_INV]: BufferDataType.FLOAT32, - [CameraView.MAT_PROJ]: BufferDataType.FLOAT32, - [CameraView.MAT_PROJ_INV]: BufferDataType.FLOAT32, - [CameraView.MAT_VIEW_PROJ_OFFSCREEN]: BufferDataType.FLOAT32, - [CameraView.MAT_VIEW_PROJ_INV_OFFSCREEN]: BufferDataType.FLOAT32, - [CameraView.MAT_PROJ_OFFSCREEN]: BufferDataType.FLOAT32, - [CameraView.MAT_PROJ_INV_OFFSCREEN]: BufferDataType.FLOAT32, - [CameraView.COUNT]: BufferDataType.NEVER, -}; -// Theoretically we only have to declare the type view here while all the other arguments can be inferred. -// but before the official support of Partial Type Argument Inference releases, (microsoft/TypeScript#26349) -// we'll have to explicitly declare all these types. -export const CameraPool = new BufferPool(PoolType.CAMERA, cameraViewDataType, CameraView); export enum NodeView { FLAGS_CHANGED, @@ -1070,16 +209,8 @@ export enum NodeView { WORLD_MATRIX = 12, // Mat4 COUNT = 28 } -interface INodeViewType extends BufferTypeManifest { - [NodeView.FLAGS_CHANGED]: number; - [NodeView.LAYER]: number; - [NodeView.WORLD_SCALE]: Vec3; - [NodeView.WORLD_POSITION]: Vec3; - [NodeView.WORLD_ROTATION]: Quat; - [NodeView.WORLD_MATRIX]: Mat4; - [NodeView.COUNT]: never; -} -const nodeViewDataType: BufferDataTypeManifest = { + +const NodeViewDataType: BufferDataTypeManifest = { [NodeView.FLAGS_CHANGED]: BufferDataType.UINT32, [NodeView.LAYER]: BufferDataType.UINT32, [NodeView.WORLD_SCALE]: BufferDataType.FLOAT32, @@ -1088,618 +219,15 @@ const nodeViewDataType: BufferDataTypeManifest = { [NodeView.WORLD_MATRIX]: BufferDataType.FLOAT32, [NodeView.COUNT]: BufferDataType.NEVER, }; -// @ts-expect-error Don't alloc memory for Vec3, Quat, Mat4 on web, as they are accessed by class member variable. -if (!JSB) { delete NodeView[NodeView.COUNT]; NodeView[NodeView.COUNT = NodeView.LAYER + 1] = 'COUNT'; } -// Theoretically we only have to declare the type view here while all the other arguments can be inferred. -// but before the official support of Partial Type Argument Inference releases, (microsoft/TypeScript#26349) -// we'll have to explicitly declare all these types. -export const NodePool = new BufferPool(PoolType.NODE, nodeViewDataType, NodeView); - -export enum RootView { - CUMULATIVE_TIME, - FRAME_TIME, - COUNT -} -interface IRootViewType extends BufferTypeManifest { - [RootView.CUMULATIVE_TIME]: number; - [RootView.FRAME_TIME]: number; - [RootView.COUNT]: never; -} -const rootViewDataType: BufferDataTypeManifest = { - [RootView.CUMULATIVE_TIME]: BufferDataType.FLOAT32, - [RootView.FRAME_TIME]: BufferDataType.FLOAT32, - [RootView.COUNT]: BufferDataType.NEVER, -}; -// Theoretically we only have to declare the type view here while all the other arguments can be inferred. -// but before the official support of Partial Type Argument Inference releases, (microsoft/TypeScript#26349) -// we'll have to explicitly declare all these types. -export const RootPool = new BufferPool(PoolType.ROOT, rootViewDataType, RootView, 1); - -export enum RenderWindowView { - HAS_ON_SCREEN_ATTACHMENTS, - HAS_OFF_SCREEN_ATTACHMENTS, - FRAMEBUFFER, // handle - COUNT -} -interface IRenderWindowViewType extends BufferTypeManifest { - [RenderWindowView.HAS_ON_SCREEN_ATTACHMENTS]: number; - [RenderWindowView.HAS_OFF_SCREEN_ATTACHMENTS]: number; - [RenderWindowView.FRAMEBUFFER]: FramebufferHandle; - [RenderWindowView.COUNT]: never; -} -const renderWindowDataType: BufferDataTypeManifest = { - [RenderWindowView.HAS_ON_SCREEN_ATTACHMENTS]: BufferDataType.UINT32, - [RenderWindowView.HAS_OFF_SCREEN_ATTACHMENTS]: BufferDataType.UINT32, - [RenderWindowView.FRAMEBUFFER]: BufferDataType.UINT32, - [RenderWindowView.COUNT]: BufferDataType.NEVER, -}; -// Theoretically we only have to declare the type view here while all the other arguments can be inferred. -// but before the official support of Partial Type Argument Inference releases, (microsoft/TypeScript#26349) -// we'll have to explicitly declare all these types. -export const RenderWindowPool = new BufferPool( - PoolType.RENDER_WINDOW, renderWindowDataType, RenderWindowView, 2, -); - -export enum FrustumView { - VERTICES, // Vec3[8] - PLANES = 24, // plane[6] - COUNT = 48 -} -interface IFrustumViewType extends BufferTypeManifest { - [FrustumView.VERTICES]: Vec3; - [FrustumView.PLANES]: Plane; - [FrustumView.COUNT]: never; -} -const frustumViewDataType: BufferDataTypeManifest = { - [FrustumView.VERTICES]: BufferDataType.FLOAT32, - [FrustumView.PLANES]: BufferDataType.FLOAT32, - [FrustumView.COUNT]: BufferDataType.NEVER, -}; -// Theoretically we only have to declare the type view here while all the other arguments can be inferred. -// but before the official support of Partial Type Argument Inference releases, (microsoft/TypeScript#26349) -// we'll have to explicitly declare all these types. -export const FrustumPool = new BufferPool(PoolType.FRUSTUM, frustumViewDataType, FrustumView); - -export enum AmbientView { - ENABLE, - ILLUM, - SKY_COLOR, // Vec4 - GROUND_ALBEDO = 6, // Vec4 - COUNT = 10 -} -interface IAmbientViewType extends BufferTypeManifest { - [AmbientView.ENABLE]: number; - [AmbientView.ILLUM]: number; - [AmbientView.SKY_COLOR]: Color; - [AmbientView.GROUND_ALBEDO]: Color; - [AmbientView.COUNT]: never; -} -const ambientViewDataType: BufferDataTypeManifest = { - [AmbientView.ENABLE]: BufferDataType.UINT32, - [AmbientView.ILLUM]: BufferDataType.FLOAT32, - [AmbientView.SKY_COLOR]: BufferDataType.FLOAT32, - [AmbientView.GROUND_ALBEDO]: BufferDataType.FLOAT32, - [AmbientView.COUNT]: BufferDataType.NEVER, -}; -// @ts-expect-error Don't alloc memory for Vec3, Quat, Mat4 on web, as they are accessed by class member variable. -if (!JSB) { delete AmbientView[AmbientView.COUNT]; AmbientView[AmbientView.COUNT = AmbientView.ILLUM + 1] = 'COUNT'; } -// Theoretically we only have to declare the type view here while all the other arguments can be inferred. -// but before the official support of Partial Type Argument Inference releases, (microsoft/TypeScript#26349) -// we'll have to explicitly declare all these types. -export const AmbientPool = new BufferPool( - PoolType.AMBIENT, ambientViewDataType, AmbientView, 1, -); - -export enum SkyboxView { - ENABLE, - IS_RGBE, - USE_IBL, - MODEL, - COUNT -} -interface ISkyboxViewType extends BufferTypeManifest { - [SkyboxView.ENABLE]: number; - [SkyboxView.IS_RGBE]: number; - [SkyboxView.USE_IBL]: number; - [SkyboxView.MODEL]: ModelHandle; - [SkyboxView.COUNT]: never; -} -const skyboxDataType: BufferDataTypeManifest = { - [SkyboxView.ENABLE]: BufferDataType.UINT32, - [SkyboxView.IS_RGBE]: BufferDataType.UINT32, - [SkyboxView.USE_IBL]: BufferDataType.UINT32, - [SkyboxView.MODEL]: BufferDataType.UINT32, - [SkyboxView.COUNT]: BufferDataType.NEVER, -}; -// Theoretically we only have to declare the type view here while all the other arguments can be inferred. -// but before the official support of Partial Type Argument Inference releases, (microsoft/TypeScript#26349) -// we'll have to explicitly declare all these types. -export const SkyboxPool = new BufferPool(PoolType.SKYBOX, skyboxDataType, SkyboxView, 1); - -export enum FogView { - ENABLE, - TYPE, - DENSITY, - START, - END, - ATTEN, - TOP, - RANGE, - COLOR, - COUNT = 12 -} -interface IFogViewType extends BufferTypeManifest { - [FogView.ENABLE]: number; - [FogView.TYPE]: number; - [FogView.DENSITY]: number; - [FogView.START]: number; - [FogView.END]: number; - [FogView.ATTEN]: number; - [FogView.TOP]: number; - [FogView.RANGE]: number; - [FogView.COLOR]: Color; - [FogView.COUNT]: never; -} -const fogViewDataType: BufferDataTypeManifest = { - [FogView.ENABLE]: BufferDataType.UINT32, - [FogView.TYPE]: BufferDataType.UINT32, - [FogView.DENSITY]: BufferDataType.FLOAT32, - [FogView.START]: BufferDataType.FLOAT32, - [FogView.END]: BufferDataType.FLOAT32, - [FogView.ATTEN]: BufferDataType.FLOAT32, - [FogView.TOP]: BufferDataType.FLOAT32, - [FogView.RANGE]: BufferDataType.FLOAT32, - [FogView.COLOR]: BufferDataType.FLOAT32, - [FogView.COUNT]: BufferDataType.NEVER, -}; -// @ts-expect-error Don't alloc memory for Vec3, Quat, Mat4 on web, as they are accessed by class member variable. -if (!JSB) { delete FogView[FogView.COUNT]; FogView[FogView.COUNT = FogView.RANGE + 1] = 'COUNT'; } -// Theoretically we only have to declare the type view here while all the other arguments can be inferred. -// but before the official support of Partial Type Argument Inference releases, (microsoft/TypeScript#26349) -// we'll have to explicitly declare all these types. -export const FogPool = new BufferPool(PoolType.FOG, fogViewDataType, FogView); - -export enum ShadowsView { - ENABLE, - DIRTY, - TYPE, - DISTANCE, - INSTANCE_PASS, - PLANAR_PASS, - NEAR, - FAR, - ASPECT, - PCF_TYPE, - SHADOW_MAP_DIRTY, // boolean - BIAS, - PACKING, // boolean - LINEAR, // boolean - SELF_SHADOW, // boolean - NORMAL_BIAS, - ORTHO_SIZE, - AUTO_ADAPT, // boolean - COLOR = 18, // Vec4 - SIZE = 22, // Vec2 - NORMAL = 24, // Vec3 - MAT_LIGHT = 27, // Mat4 - COUNT = 43 -} -interface IShadowsViewType extends BufferTypeManifest { - [ShadowsView.ENABLE]: number; - [ShadowsView.DIRTY]: number; - [ShadowsView.TYPE]: number; - [ShadowsView.DISTANCE]: number; - [ShadowsView.INSTANCE_PASS]: PassHandle; - [ShadowsView.PLANAR_PASS]: PassHandle; - [ShadowsView.NEAR]: number; - [ShadowsView.FAR]: number; - [ShadowsView.ASPECT]: number; - [ShadowsView.PCF_TYPE]: number; - [ShadowsView.SHADOW_MAP_DIRTY]: number; - [ShadowsView.BIAS]: number; - [ShadowsView.PACKING]: number; - [ShadowsView.LINEAR]: number; - [ShadowsView.SELF_SHADOW]: number; - [ShadowsView.NORMAL_BIAS]: number; - [ShadowsView.ORTHO_SIZE]: number; - [ShadowsView.AUTO_ADAPT]: number; - [ShadowsView.COLOR]: Color; - [ShadowsView.SIZE]: Vec2; - [ShadowsView.NORMAL]: Vec3; - [ShadowsView.MAT_LIGHT]: Mat4; - [ShadowsView.COUNT]: never; -} -const shadowsViewDataType: BufferDataTypeManifest = { - [ShadowsView.ENABLE]: BufferDataType.UINT32, - [ShadowsView.DIRTY]: BufferDataType.UINT32, - [ShadowsView.TYPE]: BufferDataType.UINT32, - [ShadowsView.DISTANCE]: BufferDataType.FLOAT32, - [ShadowsView.INSTANCE_PASS]: BufferDataType.UINT32, - [ShadowsView.PLANAR_PASS]: BufferDataType.UINT32, - [ShadowsView.NEAR]: BufferDataType.FLOAT32, - [ShadowsView.FAR]: BufferDataType.FLOAT32, - [ShadowsView.ASPECT]: BufferDataType.FLOAT32, - [ShadowsView.PCF_TYPE]: BufferDataType.UINT32, - [ShadowsView.SHADOW_MAP_DIRTY]: BufferDataType.UINT32, - [ShadowsView.BIAS]: BufferDataType.FLOAT32, - [ShadowsView.PACKING]: BufferDataType.UINT32, - [ShadowsView.LINEAR]: BufferDataType.UINT32, - [ShadowsView.SELF_SHADOW]: BufferDataType.UINT32, - [ShadowsView.NORMAL_BIAS]: BufferDataType.FLOAT32, - [ShadowsView.ORTHO_SIZE]: BufferDataType.FLOAT32, - [ShadowsView.AUTO_ADAPT]: BufferDataType.UINT32, - [ShadowsView.COLOR]: BufferDataType.FLOAT32, - [ShadowsView.SIZE]: BufferDataType.FLOAT32, - [ShadowsView.NORMAL]: BufferDataType.FLOAT32, - [ShadowsView.MAT_LIGHT]: BufferDataType.FLOAT32, - [ShadowsView.COUNT]: BufferDataType.NEVER, -}; -// @ts-expect-error Don't alloc memory for Vec3, Quat, Mat4 on web, as they are accessed by class member variable. -if (!JSB) { delete ShadowsView[ShadowsView.COUNT]; ShadowsView[ShadowsView.COUNT = ShadowsView.AUTO_ADAPT + 1] = 'COUNT'; } -// Theoretically we only have to declare the type view here while all the other arguments can be inferred. -// but before the official support of Partial Type Argument Inference releases, (microsoft/TypeScript#26349) -// we'll have to explicitly declare all these types. -export const ShadowsPool = new BufferPool( - PoolType.SHADOW, shadowsViewDataType, ShadowsView, 1, -); - -export enum PipelineSceneDataView { - SHADOW, // handle - SKYBOX, // handle - AMBIENT, // handle - FOG, // handle - IS_HDR, - SHADING_SCALE, - FP_SCALE, - DEFERRED_LIGHT_PASS, - DEFERRED_LIGHT_PASS_SHADER, - DEFERRED_POST_PASS, - DEFERRED_POST_PASS_SHADER, - COUNT = 11 -} -interface IPipelineSceneDataViewType extends BufferTypeManifest { - [PipelineSceneDataView.SHADOW]: ShadowsHandle; - [PipelineSceneDataView.SKYBOX]: SkyboxHandle; - [PipelineSceneDataView.AMBIENT]: AmbientHandle; - [PipelineSceneDataView.FOG]: FogHandle; - [PipelineSceneDataView.IS_HDR]: number; - [PipelineSceneDataView.SHADING_SCALE]: number; - [PipelineSceneDataView.FP_SCALE]: number; - [PipelineSceneDataView.DEFERRED_LIGHT_PASS]: PassHandle; - [PipelineSceneDataView.DEFERRED_LIGHT_PASS_SHADER]: ShaderHandle; - [PipelineSceneDataView.DEFERRED_POST_PASS]: PassHandle; - [PipelineSceneDataView.DEFERRED_POST_PASS_SHADER]: ShaderHandle; - [PipelineSceneDataView.COUNT]: never; -} -const pipelineSceneDataType: BufferDataTypeManifest = { - [PipelineSceneDataView.SHADOW]: BufferDataType.UINT32, - [PipelineSceneDataView.SKYBOX]: BufferDataType.UINT32, - [PipelineSceneDataView.AMBIENT]: BufferDataType.UINT32, - [PipelineSceneDataView.FOG]: BufferDataType.UINT32, - [PipelineSceneDataView.IS_HDR]: BufferDataType.UINT32, - [PipelineSceneDataView.SHADING_SCALE]: BufferDataType.UINT32, - [PipelineSceneDataView.FP_SCALE]: BufferDataType.UINT32, - [PipelineSceneDataView.DEFERRED_LIGHT_PASS]: BufferDataType.UINT32, - [PipelineSceneDataView.DEFERRED_LIGHT_PASS_SHADER]: BufferDataType.UINT32, - [PipelineSceneDataView.DEFERRED_POST_PASS]: BufferDataType.UINT32, - [PipelineSceneDataView.DEFERRED_POST_PASS_SHADER]: BufferDataType.UINT32, - [PipelineSceneDataView.COUNT]: BufferDataType.NEVER, -}; -// Theoretically we only have to declare the type view here while all the other arguments can be inferred. -// but before the official support of Partial Type Argument Inference releases, (microsoft/TypeScript#26349) -// we'll have to explicitly declare all these types. -export const PipelineSceneDataPool = new BufferPool( - PoolType.PIPELINE_SCENE_DATA, pipelineSceneDataType, PipelineSceneDataView, 1, -); -export enum LightView { - USE_COLOR_TEMPERATURE, - ILLUMINANCE, - NODE, // handle - RANGE, - TYPE, - AABB, // handle - FRUSTUM, // handle - SIZE, - SPOT_ANGLE, - ASPECT, - DIRECTION, // Vec3 - COLOR = 13, // Vec3 - COLOR_TEMPERATURE_RGB = 16, // Vec3 - POSITION = 19, // Vec3 - COUNT = 22 -} -interface ILightViewType extends BufferTypeManifest { - [LightView.USE_COLOR_TEMPERATURE]: number; - [LightView.ILLUMINANCE]: number; - [LightView.NODE]: NodeHandle; - [LightView.RANGE]: number; - [LightView.TYPE]: number; - [LightView.AABB]: AABBHandle; - [LightView.FRUSTUM]: FrustumHandle; - [LightView.SIZE]: number; - [LightView.SPOT_ANGLE]: number; - [LightView.ASPECT]: number; - [LightView.DIRECTION]: Vec3; - [LightView.COLOR]: Vec3; - [LightView.COLOR_TEMPERATURE_RGB]: Vec3; - [LightView.POSITION]: Vec3; - [LightView.COUNT]: never; -} -const lightViewDataType: BufferDataTypeManifest = { - [LightView.USE_COLOR_TEMPERATURE]: BufferDataType.UINT32, - [LightView.ILLUMINANCE]: BufferDataType.FLOAT32, - [LightView.NODE]: BufferDataType.UINT32, - [LightView.RANGE]: BufferDataType.FLOAT32, - [LightView.TYPE]: BufferDataType.UINT32, - [LightView.AABB]: BufferDataType.UINT32, - [LightView.FRUSTUM]: BufferDataType.UINT32, - [LightView.SIZE]: BufferDataType.FLOAT32, - [LightView.SPOT_ANGLE]: BufferDataType.FLOAT32, - [LightView.ASPECT]: BufferDataType.FLOAT32, - [LightView.DIRECTION]: BufferDataType.FLOAT32, - [LightView.COLOR]: BufferDataType.FLOAT32, - [LightView.COLOR_TEMPERATURE_RGB]: BufferDataType.FLOAT32, - [LightView.POSITION]: BufferDataType.FLOAT32, - [LightView.COUNT]: BufferDataType.NEVER, -}; -// Theoretically we only have to declare the type view here while all the other arguments can be inferred. -// but before the official support of Partial Type Argument Inference releases, (microsoft/TypeScript#26349) -// we'll have to explicitly declare all these types. -export const LightPool = new BufferPool(PoolType.LIGHT, lightViewDataType, LightView, 3); - -export enum SphereView { - RADIUS, - CENTER, // Vec3 - COUNT = 4 -} -interface ISphereViewType extends BufferTypeManifest { - [SphereView.RADIUS]: number; - [SphereView.CENTER]: Vec3; - [SphereView.COUNT]: never; -} -const sphereViewDataType: BufferDataTypeManifest = { - [SphereView.RADIUS]: BufferDataType.FLOAT32, - [SphereView.CENTER]: BufferDataType.FLOAT32, - [SphereView.COUNT]: BufferDataType.NEVER, +const NodeViewDataMembers: BufferDataMembersManifest = { + [NodeView.FLAGS_CHANGED]: NodeView.LAYER - NodeView.FLAGS_CHANGED, + [NodeView.LAYER]: NodeView.WORLD_SCALE - NodeView.LAYER, + [NodeView.WORLD_SCALE]: NodeView.WORLD_POSITION - NodeView.WORLD_SCALE, + [NodeView.WORLD_POSITION]: NodeView.WORLD_ROTATION - NodeView.WORLD_POSITION, + [NodeView.WORLD_ROTATION]: NodeView.WORLD_MATRIX - NodeView.WORLD_ROTATION, + [NodeView.WORLD_MATRIX]: NodeView.COUNT - NodeView.WORLD_MATRIX, + [NodeView.COUNT]: 1, }; -// @ts-expect-error Don't alloc memory for Vec3, Quat, Mat4 on web, as they are accessed by class member variable. -if (!JSB) { delete SphereView[SphereView.COUNT]; SphereView[SphereView.COUNT = SphereView.RADIUS + 1] = 'COUNT'; } -export const SpherePool = new BufferPool(PoolType.SPHERE, sphereViewDataType, SphereView, 3); -export enum FlatBufferView { - STRIDE, - AMOUNT, - BUFFER, // raw buffer handle - COUNT, -} -interface IFlatBufferViewType extends BufferTypeManifest { - [FlatBufferView.STRIDE]: number; - [FlatBufferView.AMOUNT]: number; - [FlatBufferView.BUFFER]: RawBufferHandle; - [FlatBufferView.COUNT]: never; -} -const flatBufferViewDataType: BufferDataTypeManifest = { - [FlatBufferView.STRIDE]: BufferDataType.UINT32, - [FlatBufferView.AMOUNT]: BufferDataType.UINT32, - [FlatBufferView.BUFFER]: BufferDataType.UINT32, - [FlatBufferView.COUNT]: BufferDataType.NEVER, -}; -// Theoretically we only have to declare the type view here while all the other arguments can be inferred. -// but before the official support of Partial Type Argument Inference releases, (microsoft/TypeScript#26349) -// we'll have to explicitly declare all these types. -export const FlatBufferPool = new BufferPool( - PoolType.FLAT_BUFFER, flatBufferViewDataType, FlatBufferView, 3, -); - -export enum SubMeshView { - FLAT_BUFFER_ARRAY, // array handle - COUNT, -} -interface ISubMeshViewType extends BufferTypeManifest { - [SubMeshView.FLAT_BUFFER_ARRAY]: FlatBufferArrayHandle; - [SubMeshView.COUNT]: never; -} -const subMeshViewDataType: BufferDataTypeManifest = { - [SubMeshView.FLAT_BUFFER_ARRAY]: BufferDataType.UINT32, - [SubMeshView.COUNT]: BufferDataType.NEVER, -}; -// Theoretically we only have to declare the type view here while all the other arguments can be inferred. -// but before the official support of Partial Type Argument Inference releases, (microsoft/TypeScript#26349) -// we'll have to explicitly declare all these types. -export const SubMeshPool = new BufferPool( - PoolType.SUB_MESH, subMeshViewDataType, SubMeshView, 3, -); - -export enum RasterizerStateView { - IS_DISCARD, - POLYGO_MODEL, - SHADE_MODEL, - CULL_MODE, - IS_FRONT_FACE_CCW, - DEPTH_BIAS_ENABLED, - DEPTH_BIAS, - DEPTH_BIAS_CLAMP, - DEPTH_BIAS_SLOP, - IS_DEPTH_CLIP, - IS_MULTI_SAMPLE, - LINE_WIDTH, - COUNT -} -interface IRasterizerStateViewType extends BufferTypeManifest { - [RasterizerStateView.IS_DISCARD]: number; - [RasterizerStateView.POLYGO_MODEL]: number; - [RasterizerStateView.SHADE_MODEL]: number; - [RasterizerStateView.CULL_MODE]: number; - [RasterizerStateView.IS_FRONT_FACE_CCW]: number; - [RasterizerStateView.DEPTH_BIAS_ENABLED]: number; - [RasterizerStateView.DEPTH_BIAS]: number; - [RasterizerStateView.DEPTH_BIAS_CLAMP]: number; - [RasterizerStateView.DEPTH_BIAS_SLOP]: number; - [RasterizerStateView.IS_DEPTH_CLIP]: number; - [RasterizerStateView.IS_MULTI_SAMPLE]: number; - [RasterizerStateView.LINE_WIDTH]: number; - [RasterizerStateView.COUNT]: never; -} -const rasterizerStateViewDataType: BufferDataTypeManifest = { - [RasterizerStateView.IS_DISCARD]: BufferDataType.UINT32, - [RasterizerStateView.POLYGO_MODEL]: BufferDataType.UINT32, - [RasterizerStateView.SHADE_MODEL]: BufferDataType.UINT32, - [RasterizerStateView.CULL_MODE]: BufferDataType.UINT32, - [RasterizerStateView.IS_FRONT_FACE_CCW]: BufferDataType.UINT32, - [RasterizerStateView.DEPTH_BIAS_ENABLED]: BufferDataType.UINT32, - [RasterizerStateView.DEPTH_BIAS]: BufferDataType.FLOAT32, - [RasterizerStateView.DEPTH_BIAS_CLAMP]: BufferDataType.FLOAT32, - [RasterizerStateView.DEPTH_BIAS_SLOP]: BufferDataType.FLOAT32, - [RasterizerStateView.IS_DEPTH_CLIP]: BufferDataType.UINT32, - [RasterizerStateView.IS_MULTI_SAMPLE]: BufferDataType.UINT32, - [RasterizerStateView.LINE_WIDTH]: BufferDataType.FLOAT32, - [RasterizerStateView.COUNT]: BufferDataType.NEVER, -}; -// Theoretically we only have to declare the type view here while all the other arguments can be inferred. -// but before the official support of Partial Type Argument Inference releases, (microsoft/TypeScript#26349) -// we'll have to explicitly declare all these types. -export const RasterizerStatePool = new BufferPool( - PoolType.RASTERIZER_STATE, rasterizerStateViewDataType, RasterizerStateView, 9, -); - -export enum DepthStencilStateView { - DEPTH_TEST, - DEPTH_WRITE, - DEPTH_FUNC, - STENCIL_TEST_FRONT, - STENCIL_FUNC_FRONT, - STENCIL_READ_MASK_FRONT, - STENCIL_WRITE_MASK_FRONT, - STENCIL_FAIL_OP_FRONT, - STENCIL_Z_FAIL_OP_FRONT, - STENCIL_PASS_OP_FRONT, - STENCIL_REF_FRONT, - STENCIL_TEST_BACK, - STENCIL_FUNC_BACK, - STENCIL_READ_MADK_BACK, - STENCIL_WRITE_MASK_BACK, - STENCIL_FAIL_OP_BACK, - STENCIL_Z_FAIL_OP_BACK, - STENCIL_PASS_OP_BACK, - STENCIL_REF_BACK, - COUNT, -} -interface IDepthStencilStateViewType extends BufferTypeManifest { - [DepthStencilStateView.DEPTH_TEST]: number; - [DepthStencilStateView.DEPTH_WRITE]: number; - [DepthStencilStateView.DEPTH_FUNC]: number; - [DepthStencilStateView.STENCIL_TEST_FRONT]: number; - [DepthStencilStateView.STENCIL_FUNC_FRONT]: number; - [DepthStencilStateView.STENCIL_READ_MASK_FRONT]: number; - [DepthStencilStateView.STENCIL_WRITE_MASK_FRONT]: number; - [DepthStencilStateView.STENCIL_FAIL_OP_FRONT]: number; - [DepthStencilStateView.STENCIL_Z_FAIL_OP_FRONT]: number; - [DepthStencilStateView.STENCIL_PASS_OP_FRONT]: number; - [DepthStencilStateView.STENCIL_REF_FRONT]: number; - [DepthStencilStateView.STENCIL_TEST_BACK]: number; - [DepthStencilStateView.STENCIL_FUNC_BACK]: number; - [DepthStencilStateView.STENCIL_READ_MADK_BACK]: number; - [DepthStencilStateView.STENCIL_WRITE_MASK_BACK]: number; - [DepthStencilStateView.STENCIL_FAIL_OP_BACK]: number; - [DepthStencilStateView.STENCIL_Z_FAIL_OP_BACK]: number; - [DepthStencilStateView.STENCIL_PASS_OP_BACK]: number; - [DepthStencilStateView.STENCIL_REF_BACK]: number; - [DepthStencilStateView.COUNT]: never; -} -const depthStencilStateViewDataType: BufferDataTypeManifest = { - [DepthStencilStateView.DEPTH_TEST]: BufferDataType.UINT32, - [DepthStencilStateView.DEPTH_WRITE]: BufferDataType.UINT32, - [DepthStencilStateView.DEPTH_FUNC]: BufferDataType.UINT32, - [DepthStencilStateView.STENCIL_TEST_FRONT]: BufferDataType.UINT32, - [DepthStencilStateView.STENCIL_FUNC_FRONT]: BufferDataType.UINT32, - [DepthStencilStateView.STENCIL_READ_MASK_FRONT]: BufferDataType.UINT32, - [DepthStencilStateView.STENCIL_WRITE_MASK_FRONT]: BufferDataType.UINT32, - [DepthStencilStateView.STENCIL_FAIL_OP_FRONT]: BufferDataType.UINT32, - [DepthStencilStateView.STENCIL_Z_FAIL_OP_FRONT]: BufferDataType.UINT32, - [DepthStencilStateView.STENCIL_PASS_OP_FRONT]: BufferDataType.UINT32, - [DepthStencilStateView.STENCIL_REF_FRONT]: BufferDataType.UINT32, - [DepthStencilStateView.STENCIL_TEST_BACK]: BufferDataType.UINT32, - [DepthStencilStateView.STENCIL_FUNC_BACK]: BufferDataType.UINT32, - [DepthStencilStateView.STENCIL_READ_MADK_BACK]: BufferDataType.UINT32, - [DepthStencilStateView.STENCIL_WRITE_MASK_BACK]: BufferDataType.UINT32, - [DepthStencilStateView.STENCIL_FAIL_OP_BACK]: BufferDataType.UINT32, - [DepthStencilStateView.STENCIL_Z_FAIL_OP_BACK]: BufferDataType.UINT32, - [DepthStencilStateView.STENCIL_PASS_OP_BACK]: BufferDataType.UINT32, - [DepthStencilStateView.STENCIL_REF_BACK]: BufferDataType.UINT32, - [DepthStencilStateView.COUNT]: BufferDataType.NEVER, -}; -// Theoretically we only have to declare the type view here while all the other arguments can be inferred. -// but before the official support of Partial Type Argument Inference releases, (microsoft/TypeScript#26349) -// we'll have to explicitly declare all these types. -export const DepthStencilStatePool = new BufferPool( - PoolType.DEPTH_STENCIL_STATE, depthStencilStateViewDataType, DepthStencilStateView, 9, -); - -export enum BlendTargetView { - BLEND, - BLEND_SRC, - BLEND_DST, - BLEND_EQ, - BLEND_SRC_ALPHA, - BLEND_DST_ALPHA, - BLEND_ALPHA_EQ, - BLEND_COLOR_MASK, - COUNT, -} -interface IBlendTargetViewType extends BufferTypeManifest { - [BlendTargetView.BLEND]: number; - [BlendTargetView.BLEND_SRC]: number; - [BlendTargetView.BLEND_DST]: number; - [BlendTargetView.BLEND_EQ]: number; - [BlendTargetView.BLEND_SRC_ALPHA]: number; - [BlendTargetView.BLEND_DST_ALPHA]: number; - [BlendTargetView.BLEND_ALPHA_EQ]: number; - [BlendTargetView.BLEND_COLOR_MASK]: number; - [BlendTargetView.COUNT]: never; -} -const blendTargetViewDataType: BufferDataTypeManifest = { - [BlendTargetView.BLEND]: BufferDataType.UINT32, - [BlendTargetView.BLEND_SRC]: BufferDataType.UINT32, - [BlendTargetView.BLEND_DST]: BufferDataType.UINT32, - [BlendTargetView.BLEND_EQ]: BufferDataType.UINT32, - [BlendTargetView.BLEND_SRC_ALPHA]: BufferDataType.UINT32, - [BlendTargetView.BLEND_DST_ALPHA]: BufferDataType.UINT32, - [BlendTargetView.BLEND_ALPHA_EQ]: BufferDataType.UINT32, - [BlendTargetView.BLEND_COLOR_MASK]: BufferDataType.UINT32, - [BlendTargetView.COUNT]: BufferDataType.NEVER, -}; -// Theoretically we only have to declare the type view here while all the other arguments can be inferred. -// but before the official support of Partial Type Argument Inference releases, (microsoft/TypeScript#26349) -// we'll have to explicitly declare all these types. -export const BlendTargetPool = new BufferPool( - PoolType.BLEND_TARGET, depthStencilStateViewDataType, BlendTargetView, 9, -); - -export enum BlendStateView { - IS_A2C, - IS_INDEPEND, - BLEND_COLOR, // vec4 - BLEND_TARGET = 6, // array handle - COUNT = 7, -} -interface IBlendStateViewType extends BufferTypeManifest { - [BlendStateView.IS_A2C]: number; - [BlendStateView.IS_INDEPEND]: number; - [BlendStateView.BLEND_COLOR]: GFXColor; - [BlendStateView.BLEND_TARGET]: BlendTargetArrayHandle; - [BlendStateView.COUNT]: never; -} -const blendStateViewDataType: BufferDataTypeManifest = { - [BlendStateView.IS_A2C]: BufferDataType.UINT32, - [BlendStateView.IS_INDEPEND]: BufferDataType.UINT32, - [BlendStateView.BLEND_COLOR]: BufferDataType.FLOAT32, - [BlendStateView.BLEND_TARGET]: BufferDataType.UINT32, - [BlendStateView.COUNT]: BufferDataType.NEVER, -}; -// Theoretically we only have to declare the type view here while all the other arguments can be inferred. -// but before the official support of Partial Type Argument Inference releases, (microsoft/TypeScript#26349) -// we'll have to explicitly declare all these types. -export const BlendStatePool = new BufferPool( - PoolType.BLEND_STATE, blendStateViewDataType, BlendStateView, 9, -); +export const NodePool = new BufferPool(PoolType.NODE, NodeViewDataType, NodeViewDataMembers, NodeView); diff --git a/cocos/core/renderer/core/pass-instance.ts b/cocos/core/renderer/core/pass-instance.ts index e22a9a74cbd..a7fa47bdea4 100644 --- a/cocos/core/renderer/core/pass-instance.ts +++ b/cocos/core/renderer/core/pass-instance.ts @@ -30,9 +30,8 @@ import { IPassInfo } from '../../assets/effect-asset'; import { MaterialInstance } from './material-instance'; -import { Pass, PassOverrides } from './pass'; +import { BatchingSchemes, Pass, PassOverrides } from './pass'; import { overrideMacros, MacroRecord } from './pass-utils'; -import { PassView, PassPool } from './memory-pools'; /** * @en A pass instance defines an variant version of the [[Pass]] @@ -122,11 +121,11 @@ export class PassInstance extends Pass { protected _syncBatchingScheme () { this._defines.USE_BATCHING = this._defines.USE_INSTANCING = false; - PassPool.set(this._handle, PassView.BATCHING_SCHEME, 0); + this._setBatchingScheme(BatchingSchemes.NONE); } protected _onStateChange () { - PassPool.set(this._handle, PassView.HASH, Pass.getPassHash(this, this._hShaderDefault)); + this._setHash(Pass.getPassHash(this)); this._owner.onPassStateChange(this._dontNotify); } } diff --git a/cocos/core/renderer/core/pass.ts b/cocos/core/renderer/core/pass.ts index 504abcafd21..891a2655b1a 100644 --- a/cocos/core/renderer/core/pass.ts +++ b/cocos/core/renderer/core/pass.ts @@ -28,7 +28,7 @@ * @module material */ -import { EDITOR } from 'internal:constants'; +import { EDITOR, JSB } from 'internal:constants'; import { Root } from '../../root'; import { TextureBase } from '../../assets/texture-base'; import { builtinResMgr } from '../../builtin/builtin-res-mgr'; @@ -38,11 +38,8 @@ import { samplerLib } from './sampler-lib'; import { BufferUsageBit, DynamicStateFlagBit, DynamicStateFlags, Feature, GetTypeSize, MemoryUsageBit, PrimitiveMode, Type, Color, BlendState, BlendTarget, Buffer, BufferInfo, BufferViewInfo, DepthStencilState, DescriptorSet, - DescriptorSetInfo, DescriptorSetLayout, Device, RasterizerState, Sampler, Texture, + DescriptorSetInfo, DescriptorSetLayout, Device, RasterizerState, Sampler, Texture, Shader, PipelineLayout, } from '../../gfx'; -import { - DSPool, NULL_HANDLE, PassHandle, PassPool, PassView, ShaderHandle, -} from './memory-pools'; import { IPassInfo, IPassStates, IPropertyInfo } from '../../assets/effect-asset'; import { IProgramInfo, programLib } from './program-lib'; import { @@ -50,6 +47,8 @@ import { getBindingFromHandle, getDefaultFromType, getOffsetFromHandle, getPropertyTypeFromHandle, getTypeFromHandle, type2reader, type2writer, } from './pass-utils'; import { RenderPassStage, RenderPriority } from '../../pipeline/define'; +import { NativePass } from '../scene/native-scene'; +import { errorID } from '../../platform/debug'; export interface IPassInfoFull extends IPassInfo { // generated part @@ -81,6 +80,7 @@ const _bufferViewInfo = new BufferViewInfo(null!); const _dsInfo = new DescriptorSetInfo(null!); export enum BatchingSchemes { + NONE = 0, INSTANCING = 1, VB_MERGING = 2, } @@ -132,12 +132,11 @@ export class Pass { * @param info The pass override info */ public static fillPipelineInfo (pass: Pass, info: PassOverrides): void { - const hPass = pass.handle; - if (info.priority !== undefined) { PassPool.set(hPass, PassView.PRIORITY, info.priority); } - if (info.primitive !== undefined) { PassPool.set(hPass, PassView.PRIMITIVE, info.primitive); } - if (info.stage !== undefined) { PassPool.set(hPass, PassView.STAGE, info.stage); } - if (info.dynamicStates !== undefined) { PassPool.set(hPass, PassView.DYNAMIC_STATES, info.dynamicStates); } - if (info.phase !== undefined) { PassPool.set(hPass, PassView.PHASE, getPhaseID(info.phase)); } + if (info.priority !== undefined) { pass._setPriority(info.priority); } + if (info.primitive !== undefined) { pass._setPrimitive(info.primitive); } + if (info.stage !== undefined) { pass._setStage(info.stage); } + if (info.dynamicStates !== undefined) { pass._setDynamicState(info.dynamicStates); } + if (info.phase !== undefined) { pass._setPhase(getPhaseID(info.phase)); } const bs = pass._bs; if (info.blendState) { @@ -163,9 +162,9 @@ export class Pass { * * @param hPass Handle of the pass info used to compute hash value. */ - public static getPassHash (pass: Pass, hShader: ShaderHandle): number { - const hPass = pass.handle; - let res = `${hShader as unknown as number},${PassPool.get(hPass, PassView.PRIMITIVE)},${PassPool.get(hPass, PassView.DYNAMIC_STATES)}`; + public static getPassHash (pass: Pass): number { + const shaderKey = programLib.getKey(pass.program, pass.defines); + let res = `${shaderKey},${pass._primitive},${pass._dynamicStates}`; res += serializeBlendState(pass._bs); res += serializeDepthStencilState(pass._dss); res += serializeRasterizerState(pass._rs); @@ -175,49 +174,42 @@ export class Pass { // internal resources protected _rootBuffer: Buffer | null = null; - protected _rootBufferDirty = false; - protected _buffers: Buffer[] = []; - protected _descriptorSet: DescriptorSet = null!; - + protected _pipelineLayout: PipelineLayout = null!; // internal data protected _passIndex = 0; - protected _propertyIndex = 0; - protected _programName = ''; - protected _dynamics: IPassDynamics = {}; - protected _propertyHandleMap: Record = {}; - protected _rootBlock: ArrayBuffer | null = null; - protected _blocks: Float32Array[] = []; - protected _shaderInfo: IProgramInfo = null!; - protected _defines: MacroRecord = {}; - protected _properties: Record = {}; + protected _shader: Shader | null = null + protected _bs: BlendState = new BlendState(); + protected _dss: DepthStencilState = new DepthStencilState(); + protected _rs: RasterizerState = new RasterizerState(); + protected _priority: RenderPriority = RenderPriority.DEFAULT; + protected _stage: RenderPassStage = RenderPassStage.DEFAULT; + protected _phase = getPhaseID('default'); + protected _primitive: PrimitiveMode = PrimitiveMode.TRIANGLE_LIST; + protected _batchingScheme: BatchingSchemes = BatchingSchemes.NONE; + protected _dynamicStates: DynamicStateFlagBit = DynamicStateFlagBit.NONE; + protected _hash = 0; // external references protected _root: Root; - protected _device: Device; - // native data - protected _hShaderDefault: ShaderHandle = NULL_HANDLE; + protected declare _nativeObj: NativePass | null; - protected _handle: PassHandle = NULL_HANDLE; - - protected _bs: BlendState = new BlendState(); - - protected _dss: DepthStencilState = new DepthStencilState(); - - protected _rs: RasterizerState = new RasterizerState(); + get native (): NativePass { + return this._nativeObj!; + } constructor (root: Root) { this._root = root; @@ -369,11 +361,25 @@ export class Pass { * @zh 更新当前 Uniform 数据。 */ public update (): void { - if (this._rootBufferDirty && this._rootBuffer) { + if (!this._descriptorSet) { + errorID(12006); + return; + } + + if (this._rootBuffer && this._rootBufferDirty) { this._rootBuffer.update(this._rootBlock!); this._rootBufferDirty = false; } this._descriptorSet.update(); + if (JSB) { + this._nativeObj!.update(); + } + } + + private _destroy () { + if (JSB) { + this._nativeObj = null; + } } /** @@ -389,7 +395,7 @@ export class Pass { if (this._rootBuffer) { this._rootBuffer.destroy(); - this._rootBlock = null; + this._rootBuffer = null; } // textures are reused @@ -399,10 +405,7 @@ export class Pass { this._dss.destroy(); this._bs.destroy(); - if (this._handle) { - DSPool.free(PassPool.get(this._handle, PassView.DESCRIPTOR_SET)); - PassPool.free(this._handle); this._handle = NULL_HANDLE; - } + this._destroy(); } /** @@ -486,10 +489,11 @@ export class Pass { const { pipeline } = this._root; if (!pipeline) { return false; } this._syncBatchingScheme(); - this._hShaderDefault = programLib.getGFXShader(this._device, this._programName, this._defines, pipeline); - if (!this._hShaderDefault) { console.warn(`create shader ${this._programName} failed`); return false; } - PassPool.set(this._handle, PassView.PIPELINE_LAYOUT, programLib.getTemplateInfo(this._programName).hPipelineLayout); - PassPool.set(this._handle, PassView.HASH, Pass.getPassHash(this, this._hShaderDefault)); + const shader = programLib.getGFXShader(this._device, this._programName, this._defines, pipeline); + if (!shader) { console.warn(`create shader ${this._programName} failed`); return false; } + this._shader = shader; + this._setPipelineLayout(programLib.getTemplateInfo(this._programName).pipelineLayout); + this._setHash(Pass.getPassHash(this)); return true; } @@ -498,21 +502,21 @@ export class Pass { * @zh 结合指定的编译宏组合获取当前 Pass 的 Shader Variant * @param patches The macro patches */ - public getShaderVariant (patches: IMacroPatch[] | null = null): ShaderHandle { - if (!this._hShaderDefault && !this.tryCompile()) { + public getShaderVariant (patches: IMacroPatch[] | null = null): Shader | null { + if (!this._shader && !this.tryCompile()) { console.warn('pass resources incomplete'); - return NULL_HANDLE as ShaderHandle; + return null; } if (!patches) { - return this._hShaderDefault; + return this._shader; } if (EDITOR) { for (let i = 0; i < patches.length; i++) { if (!patches[i].name.startsWith('CC_')) { console.warn('cannot patch non-builtin macros'); - return NULL_HANDLE as ShaderHandle; + return null; } } } @@ -523,13 +527,13 @@ export class Pass { this._defines[patch.name] = patch.value; } - const hShader = programLib.getGFXShader(this._device, this._programName, this._defines, pipeline); + const shader = programLib.getGFXShader(this._device, this._programName, this._defines, pipeline); for (let i = 0; i < patches.length; i++) { const patch = patches[i]; delete this._defines[patch.name]; } - return hShader; + return shader; } // internal use @@ -543,15 +547,72 @@ export class Pass { */ public endChangeStatesSilently (): void {} + private _setPriority (val:RenderPriority) { + this._priority = val; + if (JSB) { + this._nativeObj!.setPriority(val); + } + } + + private _setStage (val: RenderPassStage) { + this._stage = val; + if (JSB) { + this._nativeObj!.setStage(val); + } + } + + private _setPhase (val: number) { + this._phase = val; + if (JSB) { + this._nativeObj!.setPhase(val); + } + } + + private _setPrimitive (val: PrimitiveMode) { + this._primitive = val; + if (JSB) { + this._nativeObj!.setPrimitive(val); + } + } + + private _setRasterizerState (val: RasterizerState) { + this._rs = val; + if (JSB) { + this._nativeObj!.setRasterizerState(val.native); + } + } + + private _setDepthStencilState (val: DepthStencilState) { + this._dss = val; + if (JSB) { + this._nativeObj!.setDepthStencilState(val.native); + } + } + + private _setBlendState (val: BlendState) { + this._bs = val; + if (JSB) { + this._nativeObj!.setBlendState(val.native); + } + } + + private _setNativeDescriptorSet (val: DescriptorSet) { + if (JSB) { + this._nativeObj!.setDescriptorSet(val); + } + } + protected _doInit (info: IPassInfoFull, copyDefines = false): void { - const handle = this._handle = PassPool.alloc(); - PassPool.set(handle, PassView.PRIORITY, RenderPriority.DEFAULT); - PassPool.set(handle, PassView.STAGE, RenderPassStage.DEFAULT); - PassPool.set(handle, PassView.PHASE, getPhaseID('default')); - PassPool.set(handle, PassView.PRIMITIVE, PrimitiveMode.TRIANGLE_LIST); - PassPool.set(handle, PassView.RASTERIZER_STATE, this._rs.handle); - PassPool.set(handle, PassView.DEPTH_STENCIL_STATE, this._dss.handle); - PassPool.set(handle, PassView.BLEND_STATE, this._bs.handle); + if (JSB) { + this._nativeObj = new NativePass(); + } + this._setPriority(RenderPriority.DEFAULT); + this._setStage(RenderPassStage.DEFAULT); + this._setPhase(getPhaseID('default')); + this._setPrimitive(PrimitiveMode.TRIANGLE_LIST); + this._setRasterizerState(this._rs); + this._setDepthStencilState(this._dss); + this._setBlendState(this._bs); this._passIndex = info.passIndex; this._propertyIndex = info.propertyIndex !== undefined ? info.propertyIndex : info.passIndex; @@ -566,10 +627,8 @@ export class Pass { // init descriptor set _dsInfo.layout = programLib.getDescriptorSetLayout(this._device, info.program); - const dsHandle = DSPool.alloc(this._device, _dsInfo); - PassPool.set(this._handle, PassView.DESCRIPTOR_SET, dsHandle); - this._descriptorSet = DSPool.get(dsHandle); - + this._descriptorSet = this._device.createDescriptorSet(_dsInfo); + this._setNativeDescriptorSet(this._descriptorSet); // calculate total size required const blocks = this._shaderInfo.blocks; const tmplInfo = programLib.getTemplateInfo(info.program); @@ -619,43 +678,65 @@ export class Pass { protected _syncBatchingScheme (): void { if (this._defines.USE_INSTANCING) { if (this._device.hasFeature(Feature.INSTANCED_ARRAYS)) { - PassPool.set(this._handle, PassView.BATCHING_SCHEME, BatchingSchemes.INSTANCING); + this._setBatchingScheme(BatchingSchemes.INSTANCING); } else { this._defines.USE_INSTANCING = false; - PassPool.set(this._handle, PassView.BATCHING_SCHEME, 0); + this._setBatchingScheme(BatchingSchemes.NONE); } } else if (this._defines.USE_BATCHING) { - PassPool.set(this._handle, PassView.BATCHING_SCHEME, BatchingSchemes.VB_MERGING); + this._setBatchingScheme(BatchingSchemes.VB_MERGING); } else { - PassPool.set(this._handle, PassView.BATCHING_SCHEME, 0); + this._setBatchingScheme(BatchingSchemes.NONE); } } // Only for UI - private _destroyHandle () { - if (this._handle) { - PassPool.free(this._handle); this._handle = NULL_HANDLE; + protected _setBatchingScheme (val: BatchingSchemes) { + this._batchingScheme = val; + if (JSB) { + this._nativeObj!.setBatchingScheme(val); } } - // Only for UI - private _initPassFromTarget (target: Pass, dss: DepthStencilState, bs: BlendState, hashFactor: number) { - PassPool.set(this.handle, PassView.PRIORITY, target.priority); - PassPool.set(this.handle, PassView.STAGE, target.stage); - PassPool.set(this.handle, PassView.PHASE, target.phase); - PassPool.set(this.handle, PassView.BATCHING_SCHEME, target.batchingScheme); - PassPool.set(this.handle, PassView.PRIMITIVE, target.primitive); - PassPool.set(this.handle, PassView.DYNAMIC_STATES, target.dynamicStates); + private _setDynamicState (val: DynamicStateFlagBit) { + this._dynamicStates = val; + if (JSB) { + this._nativeObj!.setDynamicState(val); + } + } + + private _setDescriptorSet (target: Pass, val: DescriptorSet) { this._descriptorSet = target.descriptorSet; - PassPool.set(this.handle, PassView.DESCRIPTOR_SET, PassPool.get(target.handle, PassView.DESCRIPTOR_SET)); + this._setNativeDescriptorSet(this._descriptorSet); + } - this._bs = bs; - PassPool.set(this.handle, PassView.BLEND_STATE, bs.handle); - this._rs = target.rasterizerState; - PassPool.set(this.handle, PassView.RASTERIZER_STATE, PassPool.get(target.handle, PassView.RASTERIZER_STATE)); - this._dss = dss; - PassPool.set(this.handle, PassView.DEPTH_STENCIL_STATE, dss.handle); + protected _setHash (val: number) { + this._hash = val; + if (JSB) { + this._nativeObj!.setHash(val); + } + } + private _setPipelineLayout (pipelineLayout: PipelineLayout) { + this._pipelineLayout = pipelineLayout; + if (JSB) { + this._nativeObj!.setPipelineLayout(pipelineLayout); + } + } + + // Only for UI + private _initPassFromTarget (target: Pass, dss: DepthStencilState, bs: BlendState, hashFactor: number) { + this._setPriority(target.priority); + this._setStage(target.stage); + this._setPhase(target.phase); + this._setBatchingScheme(target.batchingScheme); + this._setPrimitive(target.primitive); + this._setDynamicState(target.dynamicStates); + this._setDescriptorSet(target, target.descriptorSet); + + this._setBlendState(bs); + this._setRasterizerState(target.rasterizerState); + this._setDepthStencilState(dss); this._passIndex = target.passIndex; this._propertyIndex = target.propertyIndex; this._programName = target.program; @@ -666,14 +747,14 @@ export class Pass { this._blocks = target._blocks; this._dynamics = target._dynamics; - this._hShaderDefault = target._hShaderDefault; + this._shader = target._shader; - PassPool.set(this._handle, PassView.PIPELINE_LAYOUT, programLib.getTemplateInfo(this._programName).hPipelineLayout); - - const hash = PassPool.get(target.handle, PassView.HASH); - PassPool.set(this._handle, PassView.HASH, hash ^ hashFactor); + this._setPipelineLayout(programLib.getTemplateInfo(this._programName).pipelineLayout); + this._setHash(target._hash ^ hashFactor); } + /* eslint-disable max-len */ + // infos get root (): Root { return this._root; } get device (): Device { return this._device; } @@ -687,20 +768,20 @@ export class Pass { // data get dynamics (): IPassDynamics { return this._dynamics; } get blocks (): Float32Array[] { return this._blocks; } + get rootBufferDirty (): boolean { return this._rootBufferDirty; } // states - get handle (): PassHandle { return this._handle; } - get priority (): RenderPriority { return PassPool.get(this._handle, PassView.PRIORITY); } - get primitive (): PrimitiveMode { return PassPool.get(this._handle, PassView.PRIMITIVE); } - get stage (): RenderPassStage { return PassPool.get(this._handle, PassView.STAGE); } - get phase (): number { return PassPool.get(this._handle, PassView.PHASE); } + get priority (): RenderPriority { return this._priority; } + get primitive (): PrimitiveMode { return this._primitive; } + get stage (): RenderPassStage { return this._stage; } + get phase (): number { return this._phase; } get rasterizerState (): RasterizerState { return this._rs; } get depthStencilState (): DepthStencilState { return this._dss; } get blendState (): BlendState { return this._bs; } - get dynamicStates (): DynamicStateFlags { return PassPool.get(this._handle, PassView.DYNAMIC_STATES); } - get batchingScheme (): BatchingSchemes { return PassPool.get(this._handle, PassView.BATCHING_SCHEME); } + get dynamicStates (): DynamicStateFlags { return this._dynamicStates; } + get batchingScheme (): BatchingSchemes { return this._batchingScheme; } get descriptorSet (): DescriptorSet { return this._descriptorSet; } - get hash (): number { return PassPool.get(this._handle, PassView.HASH); } - get rootBufferDirty (): boolean { return this._rootBufferDirty; } + get hash (): number { return this._hash; } + get pipelineLayout (): PipelineLayout { return this._pipelineLayout; } } function serializeBlendState (bs: BlendState): string { diff --git a/cocos/core/renderer/core/program-lib.ts b/cocos/core/renderer/core/program-lib.ts index 5eee9f03a3e..a9e7f79eb17 100644 --- a/cocos/core/renderer/core/program-lib.ts +++ b/cocos/core/renderer/core/program-lib.ts @@ -33,11 +33,10 @@ import { SetIndex, IDescriptorSetLayoutInfo, globalDescriptorSetLayout, localDes import { RenderPipeline } from '../../pipeline/render-pipeline'; import { genHandle, MacroRecord, PropertyType } from './pass-utils'; import { legacyCC } from '../../global-exports'; -import { ShaderPool, ShaderHandle, PipelineLayoutHandle, PipelineLayoutPool, NULL_HANDLE } from './memory-pools'; import { PipelineLayoutInfo, Device, Attribute, UniformBlock, ShaderInfo, Uniform, ShaderStage, DESCRIPTOR_SAMPLER_TYPE, DESCRIPTOR_BUFFER_TYPE, DescriptorSetLayout, DescriptorSetLayoutBinding, DescriptorSetLayoutInfo, - DescriptorType, GetTypeSize, ShaderStageFlagBit, API, UniformSamplerTexture } from '../../gfx'; + DescriptorType, GetTypeSize, ShaderStageFlagBit, API, UniformSamplerTexture, PipelineLayout, Shader } from '../../gfx'; const _dsLayoutInfo = new DescriptorSetLayoutInfo(); @@ -53,7 +52,7 @@ export interface ITemplateInfo { blockSizes: number[]; gfxStages: ShaderStage[]; setLayouts: DescriptorSetLayout[]; - hPipelineLayout: PipelineLayoutHandle; + pipelineLayout: PipelineLayout; handleMap: Record; bindings: DescriptorSetLayoutBinding[]; samplerStartBinding: number; @@ -191,7 +190,7 @@ function getActiveAttributes (tmpl: IProgramInfo, tmplInfo: ITemplateInfo, defin */ class ProgramLib { protected _templates: Record = {}; // per shader - protected _cache: Record = {}; + protected _cache: Record = {}; protected _templateInfos: Record = {}; public register (effect: EffectAsset) { @@ -268,7 +267,6 @@ class ProgramLib { tmplInfo.gfxStages.push(new ShaderStage(ShaderStageFlagBit.VERTEX, '')); tmplInfo.gfxStages.push(new ShaderStage(ShaderStageFlagBit.FRAGMENT, '')); tmplInfo.handleMap = genHandles(tmpl); - tmplInfo.hPipelineLayout = NULL_HANDLE; tmplInfo.setLayouts = []; this._templateInfos[tmpl.hash] = tmplInfo; @@ -373,10 +371,10 @@ class ProgramLib { if (typeof val === 'boolean') { val = val ? '1' : '0'; } return new RegExp(`${cur}${val}`); }); - const keys = Object.keys(this._cache).filter((k) => regexes.every((re) => re.test(ShaderPool.get(this._cache[k]).name))); + const keys = Object.keys(this._cache).filter((k) => regexes.every((re) => re.test(this._cache[k].name))); for (let i = 0; i < keys.length; i++) { const k = keys[i]; - const prog = ShaderPool.get(this._cache[k]); + const prog = this._cache[k]; console.log(`destroyed shader ${prog.name}`); prog.destroy(); delete this._cache[k]; @@ -399,11 +397,11 @@ class ProgramLib { const tmpl = this._templates[name]; const tmplInfo = this._templateInfos[tmpl.hash]; - if (!tmplInfo.hPipelineLayout) { + if (!tmplInfo.pipelineLayout) { this.getDescriptorSetLayout(device, name); // ensure set layouts have been created insertBuiltinBindings(tmpl, tmplInfo, globalDescriptorSetLayout, 'globals'); tmplInfo.setLayouts[SetIndex.GLOBAL] = pipeline.descriptorSetLayout; - tmplInfo.hPipelineLayout = PipelineLayoutPool.alloc(device, new PipelineLayoutInfo(tmplInfo.setLayouts)); + tmplInfo.pipelineLayout = device.createPipelineLayout(new PipelineLayoutInfo(tmplInfo.setLayouts)); } const macroArray = prepareDefines(defines, tmpl.defines); @@ -426,7 +424,7 @@ class ProgramLib { const instanceName = getShaderInstanceName(name, macroArray); const shaderInfo = new ShaderInfo(instanceName, tmplInfo.gfxStages, attributes, tmplInfo.gfxBlocks); shaderInfo.samplerTextures = tmplInfo.gfxSamplerTextures; - return this._cache[key] = ShaderPool.alloc(device, shaderInfo); + return this._cache[key] = device.createShader(shaderInfo); } } diff --git a/cocos/core/renderer/core/render-window.ts b/cocos/core/renderer/core/render-window.ts index 339f97e3a1a..5164faf93ff 100644 --- a/cocos/core/renderer/core/render-window.ts +++ b/cocos/core/renderer/core/render-window.ts @@ -25,10 +25,10 @@ import { JSB } from 'internal:constants'; import { TextureType, TextureUsageBit, Format, RenderPass, Texture, Framebuffer, - RenderPassInfo, Device, TextureInfo, FramebufferInfo } from '../../gfx'; + RenderPassInfo, Device, TextureInfo, FramebufferInfo, +} from '../../gfx'; import { Root } from '../../root'; -import { RenderWindowHandle, RenderWindowPool, RenderWindowView, FramebufferPool, NULL_HANDLE } from './memory-pools'; -import { Camera } from '../scene'; +import { Camera, NativeRenderWindow } from '../scene'; export interface IRenderWindowInfo { title?: string; @@ -65,9 +65,6 @@ export class RenderWindow { * @zh 帧缓冲对象。 */ get framebuffer (): Framebuffer { - if (JSB) { - return FramebufferPool.get(RenderWindowPool.get(this._poolHandle, RenderWindowView.FRAMEBUFFER)); - } return this._framebuffer!; } @@ -91,10 +88,6 @@ export class RenderWindow { return this._hasOffScreenAttachments; } - get handle () : RenderWindowHandle { - return this._poolHandle; - } - get cameras () { return this._cameras; } @@ -109,55 +102,52 @@ export class RenderWindow { protected _title = ''; protected _width = 1; protected _height = 1; - protected _nativeWidth = 1; - protected _nativeHeight = 1; protected _renderPass: RenderPass | null = null; protected _colorTextures: (Texture | null)[] = []; protected _depthStencilTexture: Texture | null = null; protected _swapchainBufferIndices = 0; protected _shouldSyncSizeWithSwapchain = false; - protected _poolHandle: RenderWindowHandle = NULL_HANDLE; protected _cameras: Camera[] = []; protected _hasOnScreenAttachments = false; protected _hasOffScreenAttachments = false; protected _framebuffer: Framebuffer | null = null; + private declare _nativeObj: NativeRenderWindow | null; + + get native () { + return this._nativeObj; + } + private constructor (root: Root) { } private _setHasOffScreenAttachments (val) { this._hasOffScreenAttachments = val; if (JSB) { - RenderWindowPool.set(this._poolHandle, RenderWindowView.HAS_OFF_SCREEN_ATTACHMENTS, val ? 1 : 0); + this._nativeObj!.hasOffScreenAttachments = val; } } private _setHasOnScreenAttachments (val) { this._hasOnScreenAttachments = val; if (JSB) { - RenderWindowPool.set(this._poolHandle, RenderWindowView.HAS_ON_SCREEN_ATTACHMENTS, val ? 1 : 0); + this._nativeObj!.hasOnScreenAttachments = val; } } private _createFrameBuffer (device: Device, renderPass) { - if (JSB) { - const hFBO = FramebufferPool.alloc(device, new FramebufferInfo( - renderPass, - this._colorTextures, - this._depthStencilTexture, - )); - RenderWindowPool.set(this._poolHandle, RenderWindowView.FRAMEBUFFER, hFBO); - return; - } this._framebuffer = device.createFramebuffer(new FramebufferInfo( renderPass, this._colorTextures, this._depthStencilTexture, )); + if (JSB) { + this._nativeObj!.frameBuffer = this._framebuffer; + } } protected _init () { if (JSB) { - this._poolHandle = RenderWindowPool.alloc(); + this._nativeObj = new NativeRenderWindow(); } } @@ -177,8 +167,6 @@ export class RenderWindow { this._width = info.width; this._height = info.height; - this._nativeWidth = this._width; - this._nativeHeight = this._height; const { colorAttachments, depthStencilAttachment } = info.renderPassInfo; for (let i = 0; i < colorAttachments.length; i++) { @@ -230,8 +218,8 @@ export class RenderWindow { protected _destroy () { this.framebuffer.destroy(); - if (this._poolHandle) { - this._poolHandle = NULL_HANDLE; + if (JSB) { + this._nativeObj = null; } } @@ -262,35 +250,29 @@ export class RenderWindow { this._width = width; this._height = height; - if (width > this._nativeWidth - || height > this._nativeHeight) { - this._nativeWidth = width; - this._nativeHeight = height; + let needRebuild = false; - let needRebuild = false; + if (this._depthStencilTexture) { + this._depthStencilTexture.resize(width, height); + needRebuild = true; + } - if (this._depthStencilTexture) { - this._depthStencilTexture.resize(width, height); + for (let i = 0; i < this._colorTextures.length; i++) { + const colorTex = this._colorTextures[i]; + if (colorTex) { + colorTex.resize(width, height); needRebuild = true; } + } - for (let i = 0; i < this._colorTextures.length; i++) { - const colorTex = this._colorTextures[i]; - if (colorTex) { - colorTex.resize(width, height); - needRebuild = true; - } - } - - const framebuffer = this.framebuffer; - if (needRebuild && framebuffer) { - framebuffer.destroy(); - framebuffer.initialize(new FramebufferInfo( - this._renderPass!, - this._colorTextures, - this._depthStencilTexture, - )); - } + const framebuffer = this.framebuffer; + if (needRebuild && framebuffer) { + framebuffer.destroy(); + framebuffer.initialize(new FramebufferInfo( + this._renderPass!, + this._colorTextures, + this._depthStencilTexture, + )); } for (const camera of this._cameras) { diff --git a/cocos/core/renderer/scene/ambient.ts b/cocos/core/renderer/scene/ambient.ts index c9521642573..3ac52fc1f09 100644 --- a/cocos/core/renderer/scene/ambient.ts +++ b/cocos/core/renderer/scene/ambient.ts @@ -25,9 +25,9 @@ import { JSB } from 'internal:constants'; import { Color, Vec3 } from '../../math'; -import { AmbientPool, NULL_HANDLE, AmbientView, AmbientHandle } from '../core/memory-pools'; import { legacyCC } from '../../global-exports'; import { AmbientInfo } from '../../scene-graph/scene-globals'; +import { NativeAmbient } from './native-scene'; export class Ambient { public static SUN_ILLUM = 65000.0; @@ -48,7 +48,7 @@ export class Ambient { set enabled (val: boolean) { this._enabled = val; if (JSB) { - AmbientPool.set(this._handle, AmbientView.ENABLE, val ? 1 : 0); + this._nativeObj!.enabled = val; } } get enabled (): boolean { @@ -66,7 +66,7 @@ export class Ambient { this._skyColor.set(color); Color.toArray(this._colorArray, this._skyColor); if (JSB) { - AmbientPool.setVec4(this._handle, AmbientView.SKY_COLOR, this._skyColor); + this._nativeObj!.skyColor = this._skyColor; } } @@ -81,7 +81,7 @@ export class Ambient { set skyIllum (illum: number) { this._skyIllum = illum; if (JSB) { - AmbientPool.set(this._handle, AmbientView.ILLUM, illum); + this._nativeObj!.skyIllum = illum; } } /** @@ -96,22 +96,25 @@ export class Ambient { this._groundAlbedo.set(color); Vec3.toArray(this._albedoArray, this._groundAlbedo); if (JSB) { - AmbientPool.setVec4(this._handle, AmbientView.GROUND_ALBEDO, this._groundAlbedo); + this._nativeObj!.groundAlbedo = this._groundAlbedo; } } protected _skyColor = new Color(51, 128, 204, 1.0); protected _groundAlbedo = new Color(51, 51, 51, 255); protected _albedoArray = Float32Array.from([0.2, 0.2, 0.2, 1.0]); protected _colorArray = Float32Array.from([0.2, 0.5, 0.8, 1.0]); - protected _handle: AmbientHandle = NULL_HANDLE; protected _enabled = false; protected _skyIllum = 0; - get handle () : AmbientHandle { - return this._handle; + protected declare _nativeObj: NativeAmbient | null; + + get native (): NativeAmbient { + return this._nativeObj!; } constructor () { - this._handle = AmbientPool.alloc(); + if (JSB) { + this._nativeObj = new NativeAmbient(); + } } public initialize (ambientInfo: AmbientInfo) { @@ -121,9 +124,8 @@ export class Ambient { } protected _destroy () { - if (JSB && this._handle) { - AmbientPool.free(this._handle); - this._handle = NULL_HANDLE; + if (JSB) { + this._nativeObj = null; } } diff --git a/cocos/core/renderer/scene/camera.ts b/cocos/core/renderer/scene/camera.ts index d7123e45ede..1feda6631bb 100644 --- a/cocos/core/renderer/scene/camera.ts +++ b/cocos/core/renderer/scene/camera.ts @@ -34,13 +34,8 @@ import { Node } from '../../scene-graph'; import { RenderScene } from './render-scene'; import { legacyCC } from '../../global-exports'; import { RenderWindow } from '../core/render-window'; -import { - CameraHandle, CameraPool, CameraView, FrustumHandle, FrustumPool, NULL_HANDLE, SceneHandle, -} from '../core/memory-pools'; -import { recordFrustumToSharedMemory } from '../../geometry/frustum'; import { preTransforms } from '../../math/mat4'; -import { director } from '../../director'; -import { ClearFlag } from '../../components/camera-component'; +import { NativeCamera } from './native-scene'; export enum CameraFOVAxis { VERTICAL, @@ -161,8 +156,7 @@ export class Camera { private _iso: CameraISO = CameraISO.ISO100; private _isoValue = 0.0; private _ec = 0.0; - private _poolHandle: CameraHandle = NULL_HANDLE; - private _frustumHandle: FrustumHandle = NULL_HANDLE; + private declare _nativeObj: NativeCamera | null; private _window: RenderWindow | null = null; private _width = 1; private _height = 1; @@ -191,31 +185,29 @@ export class Camera { private _setWidth (val: number) { this._width = val; if (JSB) { - CameraPool.set(this._poolHandle, CameraView.WIDTH, val); + this._nativeObj!.width = val; } } private _setHeight (val: number) { this._height = val; if (JSB) { - CameraPool.set(this._poolHandle, CameraView.HEIGHT, val); + this._nativeObj!.height = val; } } - private _setScene (val) { + private _setScene (scene: RenderScene | null) { + this._scene = scene; if (JSB) { - CameraPool.set(this._poolHandle, CameraView.SCENE, val); + this._nativeObj!.scene = scene ? scene.native : null; } } protected _init (info: ICameraInfo) { if (JSB) { - const handle = this._poolHandle = CameraPool.alloc(); - if (this._scene) this._setScene(this._scene.handle); - this._frustumHandle = FrustumPool.alloc(); - CameraPool.set(handle, CameraView.FRUSTUM, this._frustumHandle); - console.log(`Created Camera: ${this._name} ${CameraPool.get(this._poolHandle, - CameraView.WIDTH)}x${CameraPool.get(this._poolHandle, CameraView.HEIGHT)}`); + this._nativeObj = new NativeCamera(); + if (this._scene) this._nativeObj.scene = this._scene.native; + this._nativeObj.frustum = this._frustum; } } @@ -236,14 +228,7 @@ export class Camera { } protected _destroy () { - if (JSB && this._poolHandle) { - CameraPool.free(this._poolHandle); - this._poolHandle = NULL_HANDLE; - if (this._frustumHandle) { - FrustumPool.free(this._frustumHandle); - this._frustumHandle = NULL_HANDLE; - } - } + if (JSB) this._nativeObj = null; } public destroy () { @@ -256,15 +241,13 @@ export class Camera { } public attachToScene (scene: RenderScene) { - this._scene = scene; this._enabled = true; - this._setScene(scene.handle); + this._setScene(scene); } public detachFromScene () { - this._scene = null; this._enabled = false; - this._setScene(0 as unknown as SceneHandle); + this._setScene(null); } public resize (width: number, height: number) { @@ -291,15 +274,15 @@ export class Camera { if (this._node.hasChangedFlags || forceUpdate) { Mat4.invert(this._matView, this._node.worldMatrix); if (JSB) { - CameraPool.setMat4(this._poolHandle, CameraView.MAT_VIEW, this._matView); + this._nativeObj!.matView = this._matView; } this._forward.x = -this._matView.m02; this._forward.y = -this._matView.m06; this._forward.z = -this._matView.m10; this._node.getWorldPosition(this._position); if (JSB) { - CameraPool.setVec3(this._poolHandle, CameraView.POSITION, this._position); - CameraPool.setVec3(this._poolHandle, CameraView.FORWARD, this._forward); + this._nativeObj!.position = this._position; + this._nativeObj!.forward = this._forward; } viewProjDirty = true; } @@ -324,8 +307,8 @@ export class Camera { } Mat4.invert(this._matProjInv, this._matProj); if (JSB) { - CameraPool.setMat4(this._poolHandle, CameraView.MAT_PROJ, this._matProj); - CameraPool.setMat4(this._poolHandle, CameraView.MAT_PROJ_INV, this._matProjInv); + this._nativeObj!.matProj = this._matProj; + this._nativeObj!.matProjInv = this._matProjInv; } viewProjDirty = true; this._isProjDirty = false; @@ -337,17 +320,17 @@ export class Camera { Mat4.invert(this._matViewProjInv, this._matViewProj); this._frustum.update(this._matViewProj, this._matViewProjInv); if (JSB) { - CameraPool.setMat4(this._poolHandle, CameraView.MAT_VIEW_PROJ, this._matViewProj); - CameraPool.setMat4(this._poolHandle, CameraView.MAT_VIEW_PROJ_INV, this._matViewProjInv); + this._nativeObj!.matViewProj = this._matViewProj; + this._nativeObj!.matViewProjInv = this._matViewProjInv; + this._nativeObj!.frustum = this._frustum; } - recordFrustumToSharedMemory(this._frustumHandle, this._frustum); } } set node (val: Node) { this._node = val; if (JSB) { - CameraPool.set(this._poolHandle, CameraView.NODE, this._node.handle); + this._nativeObj!.node = this._node.native; } } @@ -423,7 +406,7 @@ export class Camera { this._clearColor.z = val.z; this._clearColor.w = val.w; if (JSB) { - CameraPool.setVec4(this._poolHandle, CameraView.CLEAR_COLOR, val); + this._nativeObj!.clearColor = this._clearColor; } } @@ -467,7 +450,7 @@ export class Camera { default: } if (JSB) { - CameraPool.setVec4(this._poolHandle, CameraView.VIEW_PORT, this._viewport); + this._nativeObj!.viewPort = this._viewport; } this.resize(this.width, this.height); } @@ -495,7 +478,7 @@ export class Camera { set matView (val) { this._matView = val; if (JSB) { - CameraPool.setMat4(this._poolHandle, CameraView.MAT_VIEW, this._matView); + this._nativeObj!.matView = this._matView; } } @@ -508,13 +491,13 @@ export class Camera { } get matViewInv () { - return this._matViewInv || this._node!.worldMatrix; + return this._matViewInv || this._node!.worldMatrix as Mat4; } set matProj (val) { this._matProj = val; if (JSB) { - CameraPool.setMat4(this._poolHandle, CameraView.MAT_PROJ, this._matProj); + this._nativeObj!.matProj = this._matProj; } } @@ -525,7 +508,7 @@ export class Camera { set matProjInv (val) { this._matProjInv = val; if (JSB) { - CameraPool.setMat4(this._poolHandle, CameraView.MAT_PROJ_INV, this._matProjInv); + this._nativeObj!.matProjInv = this._matProjInv; } } @@ -536,7 +519,7 @@ export class Camera { set matViewProj (val) { this._matViewProj = val; if (JSB) { - CameraPool.setMat4(this._poolHandle, CameraView.MAT_VIEW_PROJ, this._matViewProj); + this._nativeObj!.matViewProj = this._matViewProj; } } @@ -547,7 +530,7 @@ export class Camera { set matViewProjInv (val) { this._matViewProjInv = val; if (JSB) { - CameraPool.setMat4(this._poolHandle, CameraView.MAT_VIEW_PROJ_INV, this._matViewProjInv); + this._nativeObj!.matViewProjInv = this._matViewProjInv; } } @@ -557,7 +540,9 @@ export class Camera { set frustum (val) { this._frustum = val; - recordFrustumToSharedMemory(this._frustumHandle, val); + if (JSB) { + this._nativeObj!.frustum = this._frustum; + } } get frustum () { @@ -566,7 +551,9 @@ export class Camera { set window (val) { this._window = val; - if (JSB && val) CameraPool.set(this._poolHandle, CameraView.WINDOW, val.handle); + if (JSB && val) { + this._nativeObj!.window = this._window!.native; + } } get window () { @@ -576,7 +563,7 @@ export class Camera { set forward (val) { this._forward = val; if (JSB) { - CameraPool.setVec3(this._poolHandle, CameraView.FORWARD, this._forward); + this._nativeObj!.forward = this._forward; } } @@ -587,7 +574,7 @@ export class Camera { set position (val) { this._position = val; if (JSB) { - CameraPool.setVec3(this._poolHandle, CameraView.POSITION, this._position); + this._nativeObj!.position = this._position; } } @@ -598,7 +585,7 @@ export class Camera { set visibility (vis: number) { this._visibility = vis; if (JSB) { - CameraPool.set(this._poolHandle, CameraView.VISIBILITY, vis); + this._nativeObj!.visibility = this._visibility; } } get visibility (): number { @@ -674,7 +661,7 @@ export class Camera { set clearFlag (flag: ClearFlags) { this._clearFlag = flag; if (JSB) { - CameraPool.set(this._poolHandle, CameraView.CLEAR_FLAGS, flag); + this._nativeObj!.clearFlag = flag; } } @@ -685,7 +672,7 @@ export class Camera { set clearDepth (depth: number) { this._clearDepth = depth; if (JSB) { - CameraPool.set(this._poolHandle, CameraView.CLEAR_DEPTH, depth); + this._nativeObj!.clearDepth = depth; } } @@ -696,12 +683,12 @@ export class Camera { set clearStencil (stencil: number) { this._clearStencil = stencil; if (JSB) { - CameraPool.set(this._poolHandle, CameraView.CLEAR_STENCIL, stencil); + this._nativeObj!.clearStencil = stencil; } } - get handle () : CameraHandle { - return this._poolHandle; + get native (): any { + return this._nativeObj; } public changeTargetWindow (window: RenderWindow | null = null) { @@ -806,7 +793,7 @@ export class Camera { /** * transform a world space position to screen space */ - public worldToScreen (out: Vec3, worldPos: Vec3): Vec3 { + public worldToScreen (out: Vec3, worldPos: Readonly): Vec3 { const width = this.width; const height = this.height; const cx = this._viewport.x * width; @@ -855,7 +842,7 @@ export class Camera { protected setExposure (ev100) { this._exposure = 0.833333 / (2.0 ** ev100); if (JSB) { - CameraPool.set(this._poolHandle, CameraView.EXPOSURE, this._exposure); + this._nativeObj!.exposure = this._exposure; } } diff --git a/cocos/core/renderer/scene/directional-light.ts b/cocos/core/renderer/scene/directional-light.ts index e3fdc68fbd8..8b3a93c01ec 100644 --- a/cocos/core/renderer/scene/directional-light.ts +++ b/cocos/core/renderer/scene/directional-light.ts @@ -24,10 +24,10 @@ */ import { JSB } from 'internal:constants'; -import { Vec3, Vec4 } from '../../math'; +import { Vec3 } from '../../math'; import { Ambient } from './ambient'; import { Light, LightType } from './light'; -import { LightPool, LightView } from '../core/memory-pools'; +import { NativeDirectionalLight } from './native-scene'; const _forward = new Vec3(0, 0, -1); const _v3 = new Vec3(); @@ -39,7 +39,7 @@ export class DirectionalLight extends Light { set direction (dir: Vec3) { Vec3.normalize(this._dir, dir); if (JSB) { - LightPool.setVec3(this._handle, LightView.DIRECTION, this._dir); + (this._nativeObj as NativeDirectionalLight).setDirection(dir); } } @@ -51,7 +51,7 @@ export class DirectionalLight extends Light { set illuminance (illum: number) { this._illuminance = illum; if (JSB) { - LightPool.set(this._handle, LightView.ILLUMINANCE, illum); + (this._nativeObj as NativeDirectionalLight).setIlluminance(illum); } } diff --git a/cocos/core/renderer/scene/fog.ts b/cocos/core/renderer/scene/fog.ts index ec7a6e7f123..e64ef3b50d2 100644 --- a/cocos/core/renderer/scene/fog.ts +++ b/cocos/core/renderer/scene/fog.ts @@ -27,8 +27,8 @@ import { JSB } from 'internal:constants'; import { Enum } from '../../value-types'; import { Color } from '../../math'; import { legacyCC } from '../../global-exports'; -import { FogPool, NULL_HANDLE, FogView, FogHandle } from '../core/memory-pools'; import { FogInfo } from '../../scene-graph/scene-globals'; +import { NativeFog } from './native-scene'; /** * @zh @@ -98,7 +98,7 @@ export class Fog { this._fogColor.set(val); Color.toArray(this._colorArray, this._fogColor); if (JSB) { - FogPool.setVec4(this._handle, FogView.COLOR, this._fogColor); + this._nativeObj!.color = this._fogColor; } } @@ -136,7 +136,7 @@ export class Fog { set fogDensity (val: number) { this._fogDensity = val; if (JSB) { - FogPool.set(this._handle, FogView.DENSITY, val); + this._nativeObj!.density = val; } } /** @@ -150,7 +150,7 @@ export class Fog { set fogStart (val: number) { this._fogStart = val; if (JSB) { - FogPool.set(this._handle, FogView.START, val); + this._nativeObj!.start = val; } } @@ -165,7 +165,7 @@ export class Fog { set fogEnd (val: number) { this._fogEnd = val; if (JSB) { - FogPool.set(this._handle, FogView.END, val); + this._nativeObj!.end = val; } } @@ -180,7 +180,7 @@ export class Fog { set fogAtten (val: number) { this._fogAtten = val; if (JSB) { - FogPool.set(this._handle, FogView.ATTEN, val); + this._nativeObj!.atten = val; } } @@ -195,7 +195,7 @@ export class Fog { set fogTop (val: number) { this._fogTop = val; if (JSB) { - FogPool.set(this._handle, FogView.TOP, val); + this._nativeObj!.top = val; } } @@ -210,7 +210,7 @@ export class Fog { set fogRange (val: number) { this._fogRange = val; if (JSB) { - FogPool.set(this._handle, FogView.RANGE, val); + this._nativeObj!.range = val; } } get colorArray (): Float32Array { @@ -218,7 +218,6 @@ export class Fog { } protected _fogColor = new Color('#C8C8C8'); protected _colorArray: Float32Array = new Float32Array([0.2, 0.2, 0.2, 1.0]); - protected _handle: FogHandle = NULL_HANDLE; protected _enabled = false; protected _type = 0; protected _fogDensity = 0.3; @@ -227,29 +226,30 @@ export class Fog { protected _fogAtten = 5; protected _fogTop = 1.5; protected _fogRange = 1.2; - get handle () : FogHandle { - return this._handle; + protected declare _nativeObj: NativeFog | null; + + get native (): NativeFog { + return this._nativeObj!; } constructor () { if (JSB) { - this._handle = FogPool.alloc(); + this._nativeObj = new NativeFog(); } } protected _setType (val) { this._type = this.enabled ? val : FOG_TYPE_NONE; if (JSB) { - FogPool.set(this._handle, FogView.TYPE, this._type); + this._nativeObj!.type = this._type; } } protected _setEnable (val) { + this._enabled = val; if (JSB) { - FogPool.set(this._handle, FogView.ENABLE, val ? 1 : 0); - if (!val) FogPool.set(this._handle, FogView.TYPE, FOG_TYPE_NONE); + this._nativeObj!.enabled = val; } - this._enabled = val; } public initialize (fogInfo : FogInfo) { @@ -278,9 +278,8 @@ export class Fog { } protected _destroy () { - if (JSB && this._handle) { - FogPool.free(this._handle); - this._handle = NULL_HANDLE; + if (JSB) { + this._nativeObj = null; } } diff --git a/cocos/core/renderer/scene/index.ts b/cocos/core/renderer/scene/index.ts index 369a1df1191..e04470ce1b4 100644 --- a/cocos/core/renderer/scene/index.ts +++ b/cocos/core/renderer/scene/index.ts @@ -35,3 +35,4 @@ export * from './skybox'; export * from './sphere-light'; export * from './spot-light'; export * from './submodel'; +export * from './native-scene'; diff --git a/cocos/core/renderer/scene/light.ts b/cocos/core/renderer/scene/light.ts index e2074622469..57a1dd580f8 100644 --- a/cocos/core/renderer/scene/light.ts +++ b/cocos/core/renderer/scene/light.ts @@ -28,9 +28,7 @@ import { Vec3 } from '../../math'; import { TransformBit } from '../../scene-graph/node-enum'; import { RenderScene } from './render-scene'; import { Node } from '../../scene-graph'; -import { - LightHandle, NULL_HANDLE, LightPool, LightView, -} from '../core/memory-pools'; +import { NativeDirectionalLight, NativeLight, NativeSphereLight, NativeSpotLight } from './native-scene'; // Color temperature (in Kelvin) to RGB export function ColorTemperatureToRGB (rgb: Vec3, kelvin: number) { @@ -69,17 +67,28 @@ export enum LightType { export const nt2lm = (size: number) => 4 * Math.PI * Math.PI * size * size; export class Light { - declare protected _handle: LightHandle; + protected declare _nativeObj: NativeLight | null; protected _init (): void { if (JSB) { - this._handle = LightPool.alloc(); - LightPool.set(this._handle, LightView.TYPE, this._type); + switch (this._type) { + case LightType.DIRECTIONAL: + this._nativeObj = new NativeDirectionalLight(); + break; + case LightType.SPHERE: + this._nativeObj = new NativeSphereLight(); + break; + case LightType.SPOT: + this._nativeObj = new NativeSpotLight(); + break; + default: + break; + } + this._nativeObj!.setType(this._type); } } protected _destroy (): void { - if (this._handle) { - LightPool.free(this._handle); - this._handle = NULL_HANDLE; + if (JSB) { + this._nativeObj = null; } } @@ -94,7 +103,7 @@ export class Light { set color (color: Vec3) { this._color.set(color); if (JSB) { - LightPool.setVec3(this._handle, LightView.COLOR, color); + this._nativeObj!.setColor(color); } } @@ -105,7 +114,7 @@ export class Light { set useColorTemperature (enable: boolean) { this._useColorTemperature = enable; if (JSB) { - LightPool.set(this._handle, LightView.USE_COLOR_TEMPERATURE, enable ? 1 : 0); + this._nativeObj!.setUseColorTemperature(enable); } } @@ -117,7 +126,7 @@ export class Light { this._colorTemp = val; ColorTemperatureToRGB(this._colorTempRGB, this._colorTemp); if (JSB) { - LightPool.setVec3(this._handle, LightView.COLOR_TEMPERATURE_RGB, this._colorTempRGB); + this._nativeObj!.setColorTemperatureRGB(this._colorTempRGB); } } @@ -134,7 +143,7 @@ export class Light { if (this._node) { this._node.hasChangedFlags |= TransformBit.ROTATION; if (JSB) { - LightPool.set(this._handle, LightView.NODE, this._node.handle); + this._nativeObj!.setNode(n ? n.native : null); } } } @@ -159,8 +168,8 @@ export class Light { return this._scene; } - get handle () { - return this._handle; + get native (): NativeLight { + return this._nativeObj!; } protected _baked = false; diff --git a/cocos/core/renderer/scene/model.ts b/cocos/core/renderer/scene/model.ts index 3f194c87048..5673e1fbe75 100644 --- a/cocos/core/renderer/scene/model.ts +++ b/cocos/core/renderer/scene/model.ts @@ -29,7 +29,6 @@ import { builtinResMgr } from '../../builtin/builtin-res-mgr'; import { Material } from '../../assets/material'; import { RenderingSubMesh } from '../../assets/rendering-sub-mesh'; import { AABB } from '../../geometry'; -import { Pool } from '../../memop'; import { Node } from '../../scene-graph'; import { Layers } from '../../scene-graph/layers'; import { RenderScene } from './render-scene'; @@ -41,14 +40,11 @@ import { InstancedBuffer } from '../../pipeline/instanced-buffer'; import { Mat4, Vec3, Vec4 } from '../../math'; import { genSamplerHash, samplerLib } from '../core/sampler-lib'; -import { ShaderPool, SubModelPool, SubModelView, ModelHandle, SubModelArrayPool, ModelPool, - ModelView, AABBHandle, AABBPool, AABBView, NULL_HANDLE, AttributeArrayPool, - RawBufferPool, freeHandleArray, ObjectPool, PoolType } from '../core/memory-pools'; import { Attribute, DescriptorSet, Device, Buffer, BufferInfo, getTypedArrayConstructor, BufferUsageBit, FormatInfos, MemoryUsageBit, Filter, Address, Feature } from '../../gfx'; import { INST_MAT_WORLD, UBOLocal, UNIFORM_LIGHTMAP_TEXTURE_BINDING } from '../../pipeline/define'; - -const AttrPool = new ObjectPool(PoolType.ATTRIBUTE, (_: never[], obj?: Attribute) => obj || new Attribute()); +import { NativeModel } from './native-scene'; +import { Pool } from '../../memop/pool'; const m4_1 = new Mat4(); @@ -145,21 +141,19 @@ export class Model { set castShadow (val) { this._castShadow = val; if (JSB) { - ModelPool.set(this._handle, ModelView.CAST_SHADOW, val ? 1 : 0); + this._nativeObj!.setCastShadow(val); } } - get handle () { - return this._handle; - } - get node () : Node { return this._node; } set node (n: Node) { this._node = n; - ModelPool.set(this._handle, ModelView.NODE, n.handle); + if (JSB) { + this._nativeObj!.setNode(n.native); + } } get transform () : Node { @@ -168,7 +162,9 @@ export class Model { set transform (n: Node) { this._transform = n; - ModelPool.set(this._handle, ModelView.TRANSFORM, n.handle); + if (JSB) { + this._nativeObj!.setTransform(n.native); + } } get visFlags () : number { @@ -178,7 +174,7 @@ export class Model { set visFlags (val: number) { this._visFlags = val; if (JSB) { - ModelPool.set(this._handle, ModelView.VIS_FLAGS, val); + this._nativeObj!.seVisFlag(val); } } @@ -189,7 +185,7 @@ export class Model { set enabled (val: boolean) { this._enabled = val; if (JSB) { - ModelPool.set(this._handle, ModelView.ENABLED, val ? 1 : 0); + this._nativeObj!.setEnabled(val); } } @@ -209,8 +205,6 @@ export class Model { protected _descriptorSetCount = 1; protected _updateStamp = -1; protected _transformUpdated = true; - protected _handle: ModelHandle = NULL_HANDLE; - protected _hWorldBounds: AABBHandle = NULL_HANDLE; protected _localData = new Float32Array(UBOLocal.COUNT); protected _localBuffer: Buffer | null = null; @@ -222,6 +216,11 @@ export class Model { protected _castShadow = false; protected _enabled = true; protected _visFlags = Layers.Enum.NONE; + protected declare _nativeObj: NativeModel | null; + + get native (): NativeModel { + return this._nativeObj!; + } /** * Setup a default empty model @@ -233,16 +232,14 @@ export class Model { private _setReceiveShadow (val: boolean) { this._receiveShadow = val; if (JSB) { - ModelPool.set(this._handle, ModelView.RECEIVE_SHADOW, val ? 1 : 0); + this._nativeObj!.setReceiveShadow(val); } } private _init () { - this._handle = ModelPool.alloc(); - const hSubModelArray = SubModelArrayPool.alloc(); - const hInstancedAttrArray = AttributeArrayPool.alloc(); - ModelPool.set(this._handle, ModelView.INSTANCED_ATTR_ARRAY, hInstancedAttrArray); - ModelPool.set(this._handle, ModelView.SUB_MODEL_ARRAY, hSubModelArray); + if (JSB) { + this._nativeObj = new NativeModel(); + } } public initialize () { @@ -259,31 +256,11 @@ export class Model { private _destroySubmodel (subModel: SubModel) { subModel.destroy(); - if (JSB) { - _subModelPool.free(subModel); - } } private _destroy () { if (JSB) { - if (this._handle) { - const hSubModelArray = ModelPool.get(this._handle, ModelView.SUB_MODEL_ARRAY); - // don't free submodel handles here since they are just references - if (hSubModelArray) SubModelArrayPool.free(hSubModelArray); - - const hOldBuffer = ModelPool.get(this._handle, ModelView.INSTANCED_BUFFER); - if (hOldBuffer) RawBufferPool.free(hOldBuffer); - const hAttrArray = ModelPool.get(this._handle, ModelView.INSTANCED_ATTR_ARRAY); - if (hAttrArray) freeHandleArray(hAttrArray, AttributeArrayPool, AttrPool); - - ModelPool.free(this._handle); - this._handle = NULL_HANDLE; - } - - if (this._hWorldBounds) { - AABBPool.free(this._hWorldBounds); - this._hWorldBounds = NULL_HANDLE; - } + this._nativeObj = null; } } @@ -346,6 +323,18 @@ export class Model { } } + private _applyLocalData () { + if (JSB) { + // this._nativeObj!.setLocalData(this._localData); + } + } + + private _applyLocalBuffer () { + if (JSB) { + this._nativeObj!.setLocalBuffer(this._localBuffer); + } + } + public updateUBOs (stamp: number) { const subModels = this._subModels; for (let i = 0; i < subModels.length; i++) { @@ -374,17 +363,14 @@ export class Model { } Mat4.toArray(this._localData, m4_1, UBOLocal.MAT_WORLD_IT_OFFSET); this._localBuffer.update(this._localData); + this._applyLocalData(); + this._applyLocalBuffer(); } } - private _updateNativeWorldBounds () { + protected _updateNativeWorldBounds () { if (JSB) { - if (this._hWorldBounds === NULL_HANDLE) { - this._hWorldBounds = AABBPool.alloc(); - ModelPool.set(this._handle, ModelView.WORLD_BOUNDS, this._hWorldBounds); - } - AABBPool.setVec3(this._hWorldBounds, AABBView.CENTER, this._worldBounds!.center); - AABBPool.setVec3(this._hWorldBounds, AABBView.HALF_EXTENSION, this._worldBounds!.halfExtents); + this._nativeObj!.setWolrdBounds(this._worldBounds); } } @@ -401,9 +387,6 @@ export class Model { } private _createSubModel () { - if (JSB) { - return _subModelPool.alloc(); - } return new SubModel(); } @@ -426,8 +409,7 @@ export class Model { this._updateAttributesAndBinding(idx); if (isNewSubModel && JSB) { - const hSubModelArray = ModelPool.get(this._handle, ModelView.SUB_MODEL_ARRAY); - SubModelArrayPool.assign(hSubModelArray, idx, this._subModels[idx].handle); + this._nativeObj!.addSubModel(this._subModels[idx].native); } } @@ -458,7 +440,7 @@ export class Model { public updateLightingmap (texture: Texture2D | null, uvParam: Vec4) { Vec4.toArray(this._localData, uvParam, UBOLocal.LIGHTINGMAP_UVPARAM); - + this._applyLocalData(); this._lightmap = texture; this._lightmapUVParam = uvParam; @@ -492,7 +474,7 @@ export class Model { this._initLocalDescriptors(subModelIndex); this._updateLocalDescriptors(subModelIndex, subModel.descriptorSet); - const shader = ShaderPool.get(SubModelPool.get(subModel.handle, SubModelView.SHADER_0)); + const shader = subModel.passes[0].getShaderVariant(subModel.patches)!; this._updateInstancedAttributes(shader.attributes, subModel.passes[0]); } @@ -504,16 +486,19 @@ export class Model { return -1; } + private _setInstMatWorldIdx (idx: number) { + this._instMatWorldIdx = idx; + if (JSB) { + this._nativeObj!.setInstmatWorldIdx(idx); + } + } + // sub-classes can override the following functions if needed // for now no submodel level instancing attributes protected _updateInstancedAttributes (attributes: Attribute[], pass: Pass) { if (!pass.device.hasFeature(Feature.INSTANCED_ARRAYS)) { return; } // free old data - const hOldBuffer = ModelPool.get(this._handle, ModelView.INSTANCED_BUFFER); - if (hOldBuffer) RawBufferPool.free(hOldBuffer); - const hAttrArray = ModelPool.get(this._handle, ModelView.INSTANCED_ATTR_ARRAY); - if (hAttrArray) freeHandleArray(hAttrArray, AttributeArrayPool, AttrPool, false); let size = 0; for (let j = 0; j < attributes.length; j++) { @@ -521,33 +506,35 @@ export class Model { if (!attribute.isInstanced) { continue; } size += FormatInfos[attribute.format].size; } - const hBuffer = RawBufferPool.alloc(size); - const buffer = RawBufferPool.getBuffer(hBuffer); - ModelPool.set(this._handle, ModelView.INSTANCED_BUFFER, hBuffer); const attrs = this.instancedAttributes; - attrs.buffer = new Uint8Array(buffer); + attrs.buffer = new Uint8Array(size); + if (JSB) { + this._nativeObj!.setInstancedBuffer(attrs.buffer.buffer); + } attrs.views.length = attrs.attributes.length = 0; let offset = 0; for (let j = 0; j < attributes.length; j++) { const attribute = attributes[j]; if (!attribute.isInstanced) { continue; } - const hAttr = AttrPool.alloc(); - const attr = AttrPool.get(hAttr); + const attr = attrs.attributes[j]; attr.format = attribute.format; attr.name = attribute.name; attr.isNormalized = attribute.isNormalized; attr.location = attribute.location; attrs.attributes.push(attr); - AttributeArrayPool.push(hAttrArray, hAttr); const info = FormatInfos[attribute.format]; - attrs.views.push(new (getTypedArrayConstructor(info))(buffer, offset, info.count)); + attrs.views.push(new (getTypedArrayConstructor(info))(attrs.buffer, offset, info.count)); offset += info.size; } if (pass.batchingScheme === BatchingSchemes.INSTANCING) { InstancedBuffer.get(pass).destroy(); } // instancing IA changed - this._instMatWorldIdx = this._getInstancedAttributeIndex(INST_MAT_WORLD); + this._setInstMatWorldIdx(this._getInstancedAttributeIndex(INST_MAT_WORLD)); this._transformUpdated = true; + + if (JSB) { + this._nativeObj!.setInstanceAttributes(attrs.attributes); + } } protected _initLocalDescriptors (subModelIndex: number) { @@ -558,6 +545,7 @@ export class Model { UBOLocal.SIZE, UBOLocal.SIZE, )); + this._applyLocalBuffer(); } } diff --git a/cocos/core/renderer/scene/native-scene.jsb.ts b/cocos/core/renderer/scene/native-scene.jsb.ts new file mode 100644 index 00000000000..53e5cc04359 --- /dev/null +++ b/cocos/core/renderer/scene/native-scene.jsb.ts @@ -0,0 +1,21 @@ +// scene +declare const ns: any; + +export const NativeNode = ns.Node; +export const NativeModel = ns.Model; +export const NativeLight = ns.light; +export const NativeDirectionalLight = ns.DirectionalLight; +export const NativeSpotLight = ns.SpotLight; +export const NativeSphereLight = ns.SphereLight; +export const NaitveSkybox = ns.Skybox; +export const NativeFog = ns.Fog; +export const NativeAmbient = ns.Ambient; +export const NativeShadow = ns.Shadow; +export const NativeCamera = ns.Camera; +export const NativeRenderWindow = ns.RenderWindow; +export const NativeRenderScene = ns.RenderScene; +export const NativeDrawBatch2D = ns.DrawBatch2D; +export const NativePass = ns.Pass; +export const NativeSubModel = ns.SubModel; +export const NativeRoot = ns.Root; +export const NativePipelineSharedSceneData = ns.PipelineSharedSceneData; diff --git a/cocos/core/renderer/scene/native-scene.ts b/cocos/core/renderer/scene/native-scene.ts new file mode 100644 index 00000000000..0a048fd7b97 --- /dev/null +++ b/cocos/core/renderer/scene/native-scene.ts @@ -0,0 +1,224 @@ +import { IFlatBuffer } from '../../assets/rendering-sub-mesh'; +import { AABB, Frustum } from '../../geometry'; +import { Attribute, Buffer, ClearFlags, Color as GFXColor, DescriptorSet, Framebuffer, InputAssembler, Shader } from '../../gfx'; +import { Color, Mat4, Rect, Vec2 } from '../../math'; +import { RenderPriority } from '../../pipeline/define'; +import { LightType } from './light'; + +export const NativeNode: Constructor<{ + initWithData (data: TypedArray): void; +}> = null!; +export type NativeNode = InstanceType; + +export const NativeModel: Constructor<{ + setReceiveShadow (val: boolean): void; + setEnabled (val: boolean): void; + seVisFlag (val: number): void; + setTransform (n: Node): void; + setNode (n: Node): void; + setCastShadow (val: boolean): void; + setLocalBuffer (buf: Buffer | null): void; + setWolrdBounds (val: AABB | null): void; + addSubModel (val: NativeSubModel): void; + setInstmatWorldIdx (idx: number): void; + setInstancedBuffer (buffer: ArrayBuffer): void; + setInstanceAttributes (attrs: Attribute[]): void; +}> = null!; +export type NativeModel = InstanceType; + +export const NativeLight: Constructor<{ + setType (type: LightType): void; + setColor (color: Vec3): void; + setUseColorTemperature (enable: boolean): void; + setColorTemperatureRGB (color: Vec3): void; + setNode (n: Node): void; +}> = null!; +export type NativeLight = InstanceType; + +export const NativeDirectionalLight: Constructor<{ + setDirection (dir: Vec3): void; + setIlluminance (lum: number): void; +} & NativeLight> = null!; +export type NativeDirectionalLight = InstanceType; + +export const NativeSphereLight: Constructor<{ + setPosition (pos: Vec3): void; + setAABB (aabb: AABB): void; + setSize (size: number): void; + setRange (range: number): void; + setIlluminance (lum: number): void; +} & NativeLight> = null!; +export type NativeSphereLight = InstanceType; + +export const NativeSpotLight: Constructor<{ + setDirection (dir: Vec3): void; + setFrustum (frs: Frustum): void; + setAABB (aabb: AABB): void; + setPosition (pos: Vec3): void; + setSize (size: number): void; + setRange (range: number): void; + setAspect (aspect: number): void; + setAngle (angle: number): void; + setIlluminance (lum: number): void; +} & NativeLight> = null!; +export type NativeSpotLight = InstanceType; + +export const NaitveSkybox: Constructor<{ + enabled: boolean; + useIBL: boolean; + isRGBE: boolean; + model: NativeModel | null; +}> = null!; +export type NaitveSkybox = InstanceType; + +export const NativeFog: Constructor<{ + type: number; + enabled: boolean; + color: Color; + density: number; + start: number; + end: number; + atten: number; + top: number; + range: number; +}> = null!; +export type NativeFog = InstanceType; + +export const NativeRenderWindow: Constructor<{ + hasOffScreenAttachments: boolean; + hasOnScreenAttachments: boolean; + frameBuffer: Framebuffer; +}> = null!; +export type NativeRenderWindow = InstanceType; + +export const NativeCamera: Constructor<{ + width: number; + height: number; + scene: NativeRenderScene | null; + frustum: Frustum; + matView: Mat4; + matViewProj: Mat4; + matViewProjInv: Mat4; + matProj: Mat4; + matProjInv: Mat4; + position: Vec3; + forward: Vec3; + node: NativeNode | null; + clearColor: GFXColor; + viewPort: Rect; + window: NativeRenderWindow | null; + visibility: number; + clearFlag: ClearFlags; + clearDepth: number; + clearStencil: number; + exposure: number; +}> = null!; +export type NativeCamera = InstanceType; + +export const NativePass: Constructor<{ + update(): void; + setPriority(val: number): void; + setStage(val: number): void; + setPhase(val: number): void; + setPrimitive(val: number): void; + setRasterizerState(val): void; + setDepthStencilState(val): void; + setBlendState(val): void; + setDescriptorSet(val): void; + setBatchingScheme(val: number): void; + setDynamicState(val: number): void; + setHash(val: number): void; + setPipelineLayout(val): void; +}> = null!; +export type NativePass = InstanceType; + +export const NativeSubModel: Constructor<{ + setDescriptorSet(val: DescriptorSet | null): void; + setInputAssembler(val: InputAssembler | null): void; + setRenderingSubMesh(val: IFlatBuffer[]): void; + setPlanarShader(val: Shader | null): void; + setPlanarInstanceShader(val: Shader | null): void; + setPasses(val: NativePass[]): void; + setShaders(val: (Shader | null)[]): void; + setPriority(val: RenderPriority): void; +}> = null!; +export type NativeSubModel = InstanceType; + +export const NativeDrawBatch2D: Constructor<{ + visFlags: number; + inputAssembler: InputAssembler | null; + descriptorSet: DescriptorSet | null; + passes: NativePass[]; + shaders: Shader[]; +}> = null!; +export type NativeDrawBatch2D = InstanceType; + +export const NativeRenderScene: Constructor<{ + setMainLight (l: NativeLight | null): void; + addSphereLight (l: NativeLight | null): void; + removeSphereLight (l: NativeLight | null): void; + addSpotLight (l: NativeLight | null): void; + removeSpotLight (l: NativeLight | null): void; + removeSphereLights (): void; + removeSpotLights (): void; + addModel (m: NativeModel): void; + removeModel (m: NativeModel): void; + removeModels (): void; + addBatch (batch: NativeDrawBatch2D): void; + removeBatch (index: number): void; + removeBatches (): void; +}> = null!; +export type NativeRenderScene = InstanceType; + +export const NativeAmbient: Constructor<{ + enabled: boolean; + skyColor: Color; + skyIllum: number; + groundAlbedo: Color; +}> = null!; +export type NativeAmbient = InstanceType; + +export const NativeShadow: Constructor<{ + normal: Vec3; + distance: number; + color: Color; + nearValue: number; + farValue: number; + aspect: number; + orthoSize: number; + size: Vec2; + pcfType: number; + shadowMapDirty: boolean; + bias: number; + packing: boolean; + linear: boolean; + selfShadow: boolean; + normalBias: number; + autoAdapt: boolean; + planarPass: NativePass; + instancePass: NativePass; + enabled: boolean; + shadowType: number; +}> = null!; +export type NativeShadow = InstanceType; + +export const NativeRoot: Constructor<{ + cumulativeTime: number; + frameTime: number; +}> = null!; +export type NativeRoot = InstanceType; + +export const NativePipelineSharedSceneData: Constructor<{ + isHDR: boolean; + shadingScale: number; + fpScale: number; + fog: NativeFog; + ambient: NativeAmbient; + skybox: NaitveSkybox; + shadow: NativeShadow; + deferredLightPassShader: Shader | null; + deferredLightPass: NativePass; + deferredPostPassShader: Shader | null; + deferredPostPass: NativePass; +}> = null!; +export type NativePipelineSharedSceneData = InstanceType; diff --git a/cocos/core/renderer/scene/render-scene.ts b/cocos/core/renderer/scene/render-scene.ts index 75f711f46cd..62cb99c8999 100644 --- a/cocos/core/renderer/scene/render-scene.ts +++ b/cocos/core/renderer/scene/render-scene.ts @@ -31,9 +31,8 @@ import { Model } from './model'; import { SphereLight } from './sphere-light'; import { SpotLight } from './spot-light'; import { TransformBit } from '../../scene-graph/node-enum'; -import { ScenePool, SceneView, ModelArrayPool, ModelArrayHandle, SceneHandle, NULL_HANDLE, - UIBatchArrayHandle, UIBatchArrayPool, LightArrayHandle, LightArrayPool } from '../core/memory-pools'; import { DrawBatch2D } from '../../../2d/renderer/draw-batch'; +import { NativeRenderScene } from './native-scene'; export interface IRenderSceneInfo { name: string; @@ -79,8 +78,8 @@ export class RenderScene { return this._models; } - get handle () : SceneHandle { - return this._scenePoolHandle; + get native (): NativeRenderScene { + return this._nativeObj!; } get batches () { @@ -101,20 +100,16 @@ export class RenderScene { private _spotLights: SpotLight[] = []; private _mainLight: DirectionalLight | null = null; private _modelId = 0; - private _scenePoolHandle: SceneHandle = NULL_HANDLE; - private _modelArrayHandle: ModelArrayHandle = NULL_HANDLE; - private _batchArrayHandle: UIBatchArrayHandle = NULL_HANDLE; - private _sphereLightsHandle: LightArrayHandle = NULL_HANDLE; - private _spotLightsHandle: LightArrayHandle = NULL_HANDLE; + private declare _nativeObj: NativeRenderScene | null; constructor (root: Root) { this._root = root; - this._createHandles(); + this._createNativeObject(); } public initialize (info: IRenderSceneInfo): boolean { this._name = info.name; - this._createHandles(); + this._createNativeObject(); return true; } @@ -149,26 +144,7 @@ export class RenderScene { protected _destroy () { if (JSB) { - if (this._modelArrayHandle) { - ModelArrayPool.free(this._modelArrayHandle); - this._modelArrayHandle = NULL_HANDLE; - } - if (this._scenePoolHandle) { - ScenePool.free(this._scenePoolHandle); - this._scenePoolHandle = NULL_HANDLE; - } - if (this._sphereLightsHandle) { - LightArrayPool.free(this._sphereLightsHandle); - this._sphereLightsHandle = NULL_HANDLE; - } - if (this._spotLightsHandle) { - LightArrayPool.free(this._spotLightsHandle); - this._spotLightsHandle = NULL_HANDLE; - } - if (this._batchArrayHandle) { - UIBatchArrayPool.free(this._batchArrayHandle); - this._batchArrayHandle = NULL_HANDLE; - } + this._nativeObj = null; } } @@ -205,7 +181,7 @@ export class RenderScene { public setMainLight (dl: DirectionalLight) { this._mainLight = dl; if (JSB) { - ScenePool.set(this._scenePoolHandle, SceneView.MAIN_LIGHT, dl.handle); + this._nativeObj!.setMainLight(dl.native); } } @@ -213,12 +189,10 @@ export class RenderScene { if (this._mainLight === dl) { const dlList = this._directionalLights; if (dlList.length) { - this._mainLight = dlList[dlList.length - 1]; + this.setMainLight(dlList[dlList.length - 1]); if (this._mainLight.node) { // trigger update this._mainLight.node.hasChangedFlags |= TransformBit.ROTATION; } - } else { - this._mainLight = null; } } } @@ -242,7 +216,7 @@ export class RenderScene { pl.attachToScene(this); this._sphereLights.push(pl); if (JSB) { - LightArrayPool.push(this._sphereLightsHandle, pl.handle); + this._nativeObj!.addSphereLight(pl.native); } } @@ -252,7 +226,7 @@ export class RenderScene { pl.detachFromScene(); this._sphereLights.splice(i, 1); if (JSB) { - LightArrayPool.erase(this._sphereLightsHandle, i); + this._nativeObj!.removeSphereLight(pl.native); } return; } @@ -263,7 +237,7 @@ export class RenderScene { sl.attachToScene(this); this._spotLights.push(sl); if (JSB) { - LightArrayPool.push(this._spotLightsHandle, sl.handle); + this._nativeObj!.addSpotLight(sl.native); } } @@ -273,7 +247,7 @@ export class RenderScene { sl.detachFromScene(); this._spotLights.splice(i, 1); if (JSB) { - LightArrayPool.erase(this._spotLightsHandle, i); + this._nativeObj!.removeSpotLight(sl.native); } return; } @@ -286,7 +260,7 @@ export class RenderScene { } this._sphereLights.length = 0; if (JSB) { - LightArrayPool.clear(this._sphereLightsHandle); + this._nativeObj!.removeSphereLights(); } } @@ -296,7 +270,7 @@ export class RenderScene { } this._spotLights = []; if (JSB) { - LightArrayPool.clear(this._spotLightsHandle); + this._nativeObj!.removeSpotLights(); } } @@ -304,7 +278,7 @@ export class RenderScene { m.attachToScene(this); this._models.push(m); if (JSB) { - ModelArrayPool.push(this._modelArrayHandle, m.handle); + this._nativeObj!.addModel(m.native); } } @@ -314,7 +288,7 @@ export class RenderScene { model.detachFromScene(); this._models.splice(i, 1); if (JSB) { - ModelArrayPool.erase(this._modelArrayHandle, i); + this._nativeObj!.removeModel(model.native); } return; } @@ -328,14 +302,14 @@ export class RenderScene { } this._models.length = 0; if (JSB) { - ModelArrayPool.clear(this._modelArrayHandle); + this._nativeObj!.removeModels(); } } public addBatch (batch: DrawBatch2D) { this._batches.push(batch); if (JSB) { - UIBatchArrayPool.push(this._batchArrayHandle, batch.handle); + this._nativeObj!.addBatch(batch.native); } } @@ -344,7 +318,7 @@ export class RenderScene { if (this._batches[i] === batch) { this._batches.splice(i, 1); if (JSB) { - UIBatchArrayPool.erase(this._batchArrayHandle, i); + this._nativeObj!.removeBatch(i); } return; } @@ -354,7 +328,7 @@ export class RenderScene { public removeBatches () { this._batches.length = 0; if (JSB) { - UIBatchArrayPool.clear(this._batchArrayHandle); + this._nativeObj!.removeBatches(); } } @@ -368,24 +342,9 @@ export class RenderScene { return this._modelId++; } - private _createHandles () { + private _createNativeObject () { if (JSB) { - if (!this._modelArrayHandle) { - this._modelArrayHandle = ModelArrayPool.alloc(); - this._scenePoolHandle = ScenePool.alloc(); - ScenePool.set(this._scenePoolHandle, SceneView.MODEL_ARRAY, this._modelArrayHandle); - - this._spotLightsHandle = LightArrayPool.alloc(); - ScenePool.set(this._scenePoolHandle, SceneView.SPOT_LIGHT_ARRAY, this._spotLightsHandle); - - this._sphereLightsHandle = LightArrayPool.alloc(); - ScenePool.set(this._scenePoolHandle, SceneView.SPHERE_LIGHT_ARRAY, this._sphereLightsHandle); - } - - if (!this._batchArrayHandle) { - this._batchArrayHandle = UIBatchArrayPool.alloc(); - ScenePool.set(this._scenePoolHandle, SceneView.BATCH_ARRAY_2D, this._batchArrayHandle); - } + this._nativeObj = new NativeRenderScene(); } } } diff --git a/cocos/core/renderer/scene/shadows.ts b/cocos/core/renderer/scene/shadows.ts index 63ce7e63605..eb34c67a52c 100644 --- a/cocos/core/renderer/scene/shadows.ts +++ b/cocos/core/renderer/scene/shadows.ts @@ -29,9 +29,10 @@ import { Sphere } from '../../geometry'; import { Color, Mat4, Vec3, Vec2 } from '../../math'; import { legacyCC } from '../../global-exports'; import { Enum } from '../../value-types'; -import { ShadowsPool, NULL_HANDLE, ShadowsView, ShadowsHandle, ShaderHandle } from '../core/memory-pools'; import { ShadowsInfo } from '../../scene-graph/scene-globals'; import { IMacroPatch } from '../core/pass'; +import { NativeShadow } from './native-scene'; +import { Shader } from '../../gfx'; /** * @zh 阴影类型。 @@ -131,7 +132,7 @@ export class Shadows { set normal (val: Vec3) { Vec3.copy(this._normal, val); if (JSB) { - ShadowsPool.setVec3(this._handle, ShadowsView.NORMAL, this._normal); + this._nativeObj!.normal = this._normal; } } @@ -146,7 +147,7 @@ export class Shadows { set distance (val: number) { this._distance = val; if (JSB) { - ShadowsPool.set(this._handle, ShadowsView.DISTANCE, val); + this._nativeObj!.distance = val; } } @@ -161,7 +162,7 @@ export class Shadows { set shadowColor (color: Color) { this._shadowColor = color; if (JSB) { - ShadowsPool.setVec4(this._handle, ShadowsView.COLOR, color); + this._nativeObj!.color = color; } } @@ -187,7 +188,7 @@ export class Shadows { public set near (val: number) { this._near = val; if (JSB) { - ShadowsPool.set(this._handle, ShadowsView.NEAR, val); + this._nativeObj!.nearValue = val; } } @@ -201,7 +202,7 @@ export class Shadows { public set far (val: number) { this._far = val; if (JSB) { - ShadowsPool.set(this._handle, ShadowsView.FAR, val); + this._nativeObj!.farValue = val; } } @@ -215,7 +216,7 @@ export class Shadows { public set aspect (val: number) { this._aspect = val; if (JSB) { - ShadowsPool.set(this._handle, ShadowsView.ASPECT, val); + this._nativeObj!.aspect = val; } } @@ -229,7 +230,7 @@ export class Shadows { public set orthoSize (val: number) { this._orthoSize = val; if (JSB) { - ShadowsPool.set(this._handle, ShadowsView.ORTHO_SIZE, val); + this._nativeObj!.orthoSize = val; } } @@ -243,7 +244,7 @@ export class Shadows { public set size (val: Vec2) { this._size = val; if (JSB) { - ShadowsPool.setVec2(this._handle, ShadowsView.SIZE, this._size); + this._nativeObj!.size = val; } } @@ -257,7 +258,7 @@ export class Shadows { public set pcf (val: number) { this._pcf = val; if (JSB) { - ShadowsPool.set(this._handle, ShadowsView.PCF_TYPE, val); + this._nativeObj!.pcfType = val; } } @@ -271,7 +272,7 @@ export class Shadows { public set shadowMapDirty (val: boolean) { this._shadowMapDirty = val; if (JSB) { - ShadowsPool.set(this._handle, ShadowsView.SHADOW_MAP_DIRTY, val ? 1 : 0); + this._nativeObj!.shadowMapDirty = val; } } @@ -285,7 +286,7 @@ export class Shadows { public set bias (val: number) { this._bias = val; if (JSB) { - ShadowsPool.set(this._handle, ShadowsView.BIAS, val); + this._nativeObj!.bias = val; } } @@ -299,7 +300,7 @@ export class Shadows { public set packing (val: boolean) { this._packing = val; if (JSB) { - ShadowsPool.set(this._handle, ShadowsView.PACKING, val ? 1 : 0); + this._nativeObj!.packing = val; } } @@ -313,7 +314,7 @@ export class Shadows { public set linear (val: boolean) { this._linear = val; if (JSB) { - ShadowsPool.set(this._handle, ShadowsView.LINEAR, val ? 1 : 0); + this._nativeObj!.linear = val; } } @@ -327,7 +328,7 @@ export class Shadows { public set selfShadow (val: boolean) { this._selfShadow = val; if (JSB) { - ShadowsPool.set(this._handle, ShadowsView.SELF_SHADOW, val ? 1 : 0); + this._nativeObj!.selfShadow = val; } } @@ -341,7 +342,7 @@ export class Shadows { public set normalBias (val: number) { this._normalBias = val; if (JSB) { - ShadowsPool.set(this._handle, ShadowsView.NORMAL_BIAS, val); + this._nativeObj!.normalBias = val; } } @@ -355,7 +356,7 @@ export class Shadows { public set autoAdapt (val: boolean) { this._autoAdapt = val; if (JSB) { - ShadowsPool.set(this._handle, ShadowsView.AUTO_ADAPT, val ? 1 : 0); + this._nativeObj!.autoAdapt = val; } } @@ -371,10 +372,6 @@ export class Shadows { return this._instancingMaterial!; } - public get handle () : ShadowsHandle { - return this._handle; - } - /** * @en The bounding sphere of the shadow map. * @zh 用于计算阴影 Shadow map 的场景包围球. @@ -393,7 +390,6 @@ export class Shadows { protected _material: Material | null = null; protected _instancingMaterial: Material | null = null; protected _size: Vec2 = new Vec2(512, 512); - protected _handle: ShadowsHandle = NULL_HANDLE; protected _enabled = false; protected _distance = 0; protected _type = SHADOW_TYPE_NONE; @@ -409,41 +405,46 @@ export class Shadows { protected _selfShadow = false; protected _normalBias = 0; protected _autoAdapt = false; + protected declare _nativeObj: NativeShadow | null; + + get native (): NativeShadow { + return this._nativeObj!; + } constructor () { if (JSB) { - this._handle = ShadowsPool.alloc(); + this._nativeObj = new NativeShadow(); } } - public getPlanarShader (patches: IMacroPatch[] | null): ShaderHandle { + public getPlanarShader (patches: IMacroPatch[] | null): Shader | null { if (!this._material) { this._material = new Material(); this._material.initialize({ effectName: 'planar-shadow' }); if (JSB) { - ShadowsPool.set(this._handle, ShadowsView.PLANAR_PASS, this._material.passes[0].handle); + this._nativeObj!.planarPass = this._material.passes[0].native; } } return this._material.passes[0].getShaderVariant(patches); } - public getPlanarInstanceShader (patches: IMacroPatch[] | null): ShaderHandle { + public getPlanarInstanceShader (patches: IMacroPatch[] | null): Shader | null { if (!this._instancingMaterial) { this._instancingMaterial = new Material(); this._instancingMaterial.initialize({ effectName: 'planar-shadow', defines: { USE_INSTANCING: true } }); if (JSB) { - ShadowsPool.set(this._handle, ShadowsView.INSTANCE_PASS, this._instancingMaterial.passes[0].handle); + this._nativeObj!.instancePass = this._instancingMaterial.passes[0].native; } } return this._instancingMaterial.passes[0].getShaderVariant(patches); } - private _setEnable (val) { + private _setEnable (val: boolean) { this._enabled = val; if (JSB) { - ShadowsPool.set(this._handle, ShadowsView.ENABLE, val ? 1 : 0); + this._nativeObj!.enabled = val; if (!val) this._setType(SHADOW_TYPE_NONE); } } @@ -451,7 +452,7 @@ export class Shadows { private _setType (val) { this._type = this.enabled ? val : SHADOW_TYPE_NONE; if (JSB) { - ShadowsPool.set(this._handle, ShadowsView.TYPE, this._type); + this._nativeObj!.shadowType = this._type; } } @@ -496,14 +497,14 @@ export class Shadows { this._material = new Material(); this._material.initialize({ effectName: 'planar-shadow' }); if (JSB) { - ShadowsPool.set(this._handle, ShadowsView.PLANAR_PASS, this._material.passes[0].handle); + this._nativeObj!.planarPass = this._material.passes[0].native; } } if (!this._instancingMaterial) { this._instancingMaterial = new Material(); this._instancingMaterial.initialize({ effectName: 'planar-shadow', defines: { USE_INSTANCING: true } }); if (JSB) { - ShadowsPool.set(this._handle, ShadowsView.INSTANCE_PASS, this._instancingMaterial.passes[0].handle); + this._nativeObj!.instancePass = this._instancingMaterial.passes[0].native; } } @@ -521,9 +522,8 @@ export class Shadows { } protected _destroy () { - if (JSB && this._handle) { - ShadowsPool.free(this._handle); - this._handle = NULL_HANDLE; + if (JSB) { + this._nativeObj = null; } } diff --git a/cocos/core/renderer/scene/skybox.ts b/cocos/core/renderer/scene/skybox.ts index 19e586bdbde..0869ca46cf0 100644 --- a/cocos/core/renderer/scene/skybox.ts +++ b/cocos/core/renderer/scene/skybox.ts @@ -34,9 +34,10 @@ import { samplerLib } from '../core/sampler-lib'; import { Model } from './model'; import { legacyCC } from '../../global-exports'; import { DescriptorSet } from '../../gfx'; -import { SkyboxPool, NULL_HANDLE, SkyboxView, SkyboxHandle } from '../core/memory-pools'; import { SkyboxInfo } from '../../scene-graph/scene-globals'; import { Root } from '../../root'; +import { NaitveSkybox } from './native-scene'; +import { GlobalDSManager } from '../../pipeline/global-descriptor-set-manager'; let skybox_mesh: Mesh | null = null; let skybox_material: Material | null = null; @@ -110,39 +111,42 @@ export class Skybox { } protected _envmap: TextureCube | null = null; - protected _globalDescriptorSet: DescriptorSet | null = null; + protected _globalDSManager: GlobalDSManager | null = null; protected _model: Model | null = null; protected _default: TextureCube | null = null; - protected _handle: SkyboxHandle = NULL_HANDLE; protected _enabled = false; protected _useIBL = false; protected _isRGBE = false; - get handle () : SkyboxHandle { - return this._handle; + protected declare _nativeObj: NaitveSkybox | null; + + get native (): NaitveSkybox { + return this._nativeObj!; } constructor () { - this._handle = SkyboxPool.alloc(); + if (JSB) { + this._nativeObj = new NaitveSkybox(); + } } private _setEnabled (val) { this._enabled = val; if (JSB) { - SkyboxPool.set(this._handle, SkyboxView.ENABLE, val ? 1 : 0); + this._nativeObj!.enabled = val; } } private _setUseIBL (val) { this._useIBL = val; if (JSB) { - SkyboxPool.set(this._handle, SkyboxView.USE_IBL, val ? 1 : 0); + this._nativeObj!.useIBL = val; } } private _setIsRGBE (val) { this._isRGBE = val; if (JSB) { - SkyboxPool.set(this._handle, SkyboxView.IS_RGBE, val ? 1 : 0); + this._nativeObj!.isRGBE = val; } } @@ -156,7 +160,7 @@ export class Skybox { public activate () { const pipeline = legacyCC.director.root.pipeline; const ambient = pipeline.pipelineSceneData.ambient; - this._globalDescriptorSet = pipeline.descriptorSet; + this._globalDSManager = pipeline.globalDSManager; this._default = builtinResMgr.get('default-cube-texture'); if (!this._model) { @@ -165,7 +169,7 @@ export class Skybox { this._model._initLocalDescriptors = () => {}; } if (JSB) { - SkyboxPool.set(this._handle, SkyboxView.MODEL, this._model.handle); + this._nativeObj!.model = this._model.native; } if (!this._envmap) { this._envmap = this._default; @@ -201,14 +205,14 @@ export class Skybox { protected _updateGlobalBinding () { const texture = this.envmap!.getGFXTexture()!; const sampler = samplerLib.getSampler(legacyCC.director._device, this.envmap!.getSamplerHash()); - this._globalDescriptorSet!.bindSampler(UNIFORM_ENVIRONMENT_BINDING, sampler); - this._globalDescriptorSet!.bindTexture(UNIFORM_ENVIRONMENT_BINDING, texture); + this._globalDSManager!.bindSampler(UNIFORM_ENVIRONMENT_BINDING, sampler); + this._globalDSManager!.bindTexture(UNIFORM_ENVIRONMENT_BINDING, texture); + this._globalDSManager!.update(); } protected _destroy () { - if (JSB && this._handle) { - SkyboxPool.free(this._handle); - this._handle = NULL_HANDLE; + if (JSB) { + this._nativeObj = null; } } diff --git a/cocos/core/renderer/scene/sphere-light.ts b/cocos/core/renderer/scene/sphere-light.ts index e717f325a3a..95b2698cb9f 100644 --- a/cocos/core/renderer/scene/sphere-light.ts +++ b/cocos/core/renderer/scene/sphere-light.ts @@ -27,31 +27,21 @@ import { JSB } from 'internal:constants'; import { AABB } from '../../geometry'; import { Vec3 } from '../../math'; import { Light, LightType, nt2lm } from './light'; -import { AABBHandle, AABBPool, AABBView, LightPool, LightView, NULL_HANDLE } from '../core/memory-pools'; +import { NativeSphereLight } from './native-scene'; export class SphereLight extends Light { - declare protected _hAABB: AABBHandle; protected _init (): void { super._init(); - if (JSB) { - this._hAABB = AABBPool.alloc(); - LightPool.set(this._handle, LightView.AABB, this._hAABB); - } } protected _destroy (): void { - if (this._hAABB) { - AABBPool.free(this._hAABB); - this._hAABB = NULL_HANDLE; - } super._destroy(); } protected _update (): void { if (JSB) { - LightPool.setVec3(this._handle, LightView.POSITION, this._pos); - AABBPool.setVec3(this._hAABB, AABBView.CENTER, this._aabb.center); - AABBPool.setVec3(this._hAABB, AABBView.HALF_EXTENSION, this._aabb.halfExtents); + (this._nativeObj! as NativeSphereLight).setPosition(this._pos); + (this._nativeObj! as NativeSphereLight).setAABB(this._aabb); } } @@ -62,7 +52,7 @@ export class SphereLight extends Light { set size (size: number) { this._size = size; if (JSB) { - LightPool.set(this._handle, LightView.SIZE, size); + (this._nativeObj! as NativeSphereLight).setSize(size); } } @@ -73,7 +63,7 @@ export class SphereLight extends Light { set range (range: number) { this._range = range; if (JSB) { - LightPool.set(this._handle, LightView.RANGE, range); + (this._nativeObj! as NativeSphereLight).setRange(range); } this._needUpdate = true; @@ -86,7 +76,7 @@ export class SphereLight extends Light { set luminance (lum: number) { this._luminance = lum; if (JSB) { - LightPool.set(this._handle, LightView.ILLUMINANCE, lum); + (this._nativeObj! as NativeSphereLight).setIlluminance(lum); } } diff --git a/cocos/core/renderer/scene/spot-light.ts b/cocos/core/renderer/scene/spot-light.ts index 53b8ec9a485..7f32f474628 100644 --- a/cocos/core/renderer/scene/spot-light.ts +++ b/cocos/core/renderer/scene/spot-light.ts @@ -27,10 +27,7 @@ import { JSB } from 'internal:constants'; import { AABB, Frustum } from '../../geometry'; import { Mat4, Quat, Vec3 } from '../../math'; import { Light, LightType, nt2lm } from './light'; -import { - AABBHandle, AABBPool, AABBView, FrustumHandle, FrustumPool, LightPool, LightView, NULL_HANDLE, -} from '../core/memory-pools'; -import { recordFrustumToSharedMemory } from '../../geometry/frustum'; +import { NativeSpotLight } from './native-scene'; const _forward = new Vec3(0, 0, -1); const _qt = new Quat(); @@ -62,46 +59,28 @@ export class SpotLight extends Light { protected _aspect = 0; - declare protected _hAABB: AABBHandle; - declare protected _hFrustum: FrustumHandle; - protected _init (): void { super._init(); - if (JSB) { - this._hAABB = AABBPool.alloc(); - this._hFrustum = FrustumPool.alloc(); - LightPool.set(this._handle, LightView.AABB, this._hAABB); - } } protected _destroy (): void { - if (JSB) { - if (this._hAABB) { - AABBPool.free(this._hAABB); - this._hAABB = NULL_HANDLE; - } - if (this._hFrustum) { - FrustumPool.free(this._hFrustum); - this._hFrustum = NULL_HANDLE; - } - } super._destroy(); } protected _setDirection (dir: Vec3): void { this._dir.set(dir); if (JSB) { - LightPool.setVec3(this._handle, LightView.DIRECTION, this._dir); + (this._nativeObj! as NativeSpotLight).setDirection(dir); } } protected _update (): void { if (JSB) { - LightPool.setVec3(this._handle, LightView.DIRECTION, this._dir); - LightPool.setVec3(this._handle, LightView.POSITION, this._pos); - AABBPool.setVec3(this._hAABB, AABBView.CENTER, this._aabb.center); - AABBPool.setVec3(this._hAABB, AABBView.HALF_EXTENSION, this._aabb.halfExtents); - recordFrustumToSharedMemory(this._hFrustum, this._frustum); + const nativeSpotLight = this._nativeObj! as NativeSpotLight; + nativeSpotLight.setFrustum(this._frustum); + nativeSpotLight.setAABB(this._aabb); + nativeSpotLight.setDirection(this._dir); + nativeSpotLight.setPosition(this._pos); } } @@ -112,7 +91,7 @@ export class SpotLight extends Light { set size (size: number) { this._size = size; if (JSB) { - LightPool.set(this._handle, LightView.SIZE, size); + (this._nativeObj! as NativeSpotLight).setSize(size); } } @@ -123,7 +102,7 @@ export class SpotLight extends Light { set range (range: number) { this._range = range; if (JSB) { - LightPool.set(this._handle, LightView.RANGE, range); + (this._nativeObj! as NativeSpotLight).setRange(range); } this._needUpdate = true; @@ -136,7 +115,7 @@ export class SpotLight extends Light { set luminance (lum: number) { this._luminance = lum; if (JSB) { - LightPool.set(this._handle, LightView.ILLUMINANCE, lum); + (this._nativeObj! as NativeSpotLight).setIlluminance(lum); } } @@ -156,7 +135,7 @@ export class SpotLight extends Light { this._angle = val; this._spotAngle = Math.cos(val * 0.5); if (JSB) { - LightPool.set(this._handle, LightView.SPOT_ANGLE, this._spotAngle); + (this._nativeObj! as NativeSpotLight).setAngle(this._spotAngle); } this._needUpdate = true; @@ -165,7 +144,7 @@ export class SpotLight extends Light { set aspect (val: number) { this._aspect = val; if (JSB) { - LightPool.set(this._handle, LightView.ASPECT, val); + (this._nativeObj! as NativeSpotLight).setAspect(val); } this._needUpdate = true; @@ -221,6 +200,7 @@ export class SpotLight extends Light { // Mat4.invert(_matViewProjInv, _matViewProj); this._frustum.update(_matViewProj, _matViewProjInv); + this._needUpdate = false; this._update(); diff --git a/cocos/core/renderer/scene/submodel.ts b/cocos/core/renderer/scene/submodel.ts index 2f3c391d881..0b439efe6b0 100644 --- a/cocos/core/renderer/scene/submodel.ts +++ b/cocos/core/renderer/scene/submodel.ts @@ -25,13 +25,17 @@ import { JSB } from 'internal:constants'; import { RenderingSubMesh } from '../../assets/rendering-sub-mesh'; -import { RenderPriority } from '../../pipeline/define'; +import { RenderPriority, UNIFORM_REFLECTION_TEXTURE_BINDING, UNIFORM_REFLECTION_STORAGE_BINDING } from '../../pipeline/define'; import { BatchingSchemes, IMacroPatch, Pass } from '../core/pass'; -import { DSPool, IAPool, SubModelPool, SubModelView, SubModelHandle, NULL_HANDLE, ShaderHandle } from '../core/memory-pools'; -import { DescriptorSet, DescriptorSetInfo, Device, InputAssembler, InputAssemblerInfo } from '../../gfx'; +import { DescriptorSet, DescriptorSetInfo, Device, InputAssembler, InputAssemblerInfo, Texture, TextureType, TextureUsageBit, TextureInfo, + Format, Sampler, Filter, Address, TextureFlagBit, Shader } from '../../gfx'; import { legacyCC } from '../../global-exports'; import { ForwardPipeline } from '../../pipeline'; -import { errorID } from '../../platform'; +import { errorID } from '../../platform/debug'; +import { Shadows } from './shadows'; +import { NativePass, NativeSubModel } from './native-scene'; +import { getPhaseID } from '../../pipeline/pass-phase'; +import { genSamplerHash, samplerLib } from '../core/sampler-lib'; const _dsInfo = new DescriptorSetInfo(null!); const MAX_PASS_COUNT = 8; @@ -40,16 +44,19 @@ export class SubModel { protected _passes: Pass[] | null = null; protected _subMesh: RenderingSubMesh | null = null; protected _patches: IMacroPatch[] | null = null; - protected _handle: SubModelHandle = NULL_HANDLE; protected _priority: RenderPriority = RenderPriority.DEFAULT; protected _inputAssembler: InputAssembler | null = null; protected _descriptorSet: DescriptorSet | null = null; - protected _passCount = 0; + protected _planarInstanceShader: Shader | null = null; + protected _planarShader: Shader | null = null; + protected _reflectionTex: Texture | null = null; + protected _reflectionSampler: Sampler | null = null; + protected declare _nativeObj: NativeSubModel | null; private _destroyDescriptorSet () { this._descriptorSet!.destroy(); if (JSB) { - DSPool.free(SubModelPool.get(this._handle, SubModelView.DESCRIPTOR_SET)); + this._nativeObj!.setDescriptorSet(null); } this._descriptorSet = null; } @@ -57,21 +64,15 @@ export class SubModel { private _destroyInputAssembler () { this._inputAssembler!.destroy(); if (JSB) { - IAPool.free(SubModelPool.get(this._handle, SubModelView.INPUT_ASSEMBLER)); + this._nativeObj!.setInputAssembler(null); } this._inputAssembler = null; } private _createDescriptorSet (descInfo: DescriptorSetInfo) { - const dsHandle = DSPool.alloc(this._device!, descInfo); - SubModelPool.set(this._handle, SubModelView.DESCRIPTOR_SET, dsHandle); - this._descriptorSet = DSPool.get(dsHandle); - } - - private _setPassCount (val: number) { - this._passCount = val; + this._descriptorSet = this._device!.createDescriptorSet(descInfo); if (JSB) { - SubModelPool.set(this._handle, SubModelView.PASS_COUNT, val); + this._nativeObj!.setDescriptorSet(this._descriptorSet); } } @@ -110,7 +111,7 @@ export class SubModel { set priority (val) { this._priority = val; if (JSB) { - SubModelPool.set(this._handle, SubModelView.PRIORITY, val); + this._nativeObj!.setPriority(val); } } @@ -118,10 +119,6 @@ export class SubModel { return this._priority; } - get handle (): SubModelHandle { - return this._handle; - } - get inputAssembler (): InputAssembler { return this._inputAssembler!; } @@ -134,33 +131,36 @@ export class SubModel { return this._patches; } - // This is a temporary solution - // It should not be written in a fixed way, or modified by the user - get planarShaderHandle (): ShaderHandle { - return SubModelPool.get(this._handle, SubModelView.PLANAR_SHADER); + get planarInstanceShader (): Shader | null { + return this._planarInstanceShader; } - // This is a temporary solution - // It should not be written in a fixed way, or modified by the user - get planarInstanceShaderHandle (): ShaderHandle { - return SubModelPool.get(this._handle, SubModelView.PLANAR_INSTANCE_SHADER); + get planarShader (): Shader | null { + return this._planarShader; } private _setInputAssembler (iaInfo: InputAssemblerInfo) { - const iaHandle = IAPool.alloc(this._device!, iaInfo); - SubModelPool.set(this._handle, SubModelView.INPUT_ASSEMBLER, iaHandle); - this._inputAssembler = IAPool.get(iaHandle); + this._inputAssembler = this._device!.createInputAssembler(iaInfo); + if (JSB) { + this._nativeObj!.setInputAssembler(this._inputAssembler); + } } private _setSubMesh (subMesh: RenderingSubMesh) { this._subMesh = subMesh; if (JSB) { - SubModelPool.set(this._handle, SubModelView.SUB_MESH, subMesh.handle); + this._nativeObj!.setRenderingSubMesh(subMesh.flatBuffers); } } + get native (): NativeSubModel { + return this._nativeObj!; + } + private _init () { - this._handle = SubModelPool.alloc(); + if (JSB) { + this._nativeObj = new NativeSubModel(); + } } public initialize (subMesh: RenderingSubMesh, passes: Pass[], patches: IMacroPatch[] | null = null): void { @@ -177,6 +177,53 @@ export class SubModel { if (passes[0].batchingScheme === BatchingSchemes.VB_MERGING) { this.subMesh.genFlatBuffers(); } this.priority = RenderPriority.DEFAULT; + + // initialize resources for reflection material + if (passes[0].phase === getPhaseID('reflection')) { + let texWidth = this._device.width; + let texHeight = this._device.height; + const minSize = 512; + + if (texHeight < texWidth) { + texWidth = minSize * texWidth / texHeight; + texHeight = minSize; + } else { + texWidth = minSize; + texHeight = minSize * texHeight / texWidth; + } + + this._reflectionTex = this._device.createTexture(new TextureInfo( + TextureType.TEX2D, + TextureUsageBit.STORAGE | TextureUsageBit.TRANSFER_SRC | TextureUsageBit.SAMPLED, + Format.RGBA8, + texWidth, + texHeight, + TextureFlagBit.IMMUTABLE, + )); + + this.descriptorSet.bindTexture(UNIFORM_REFLECTION_TEXTURE_BINDING, this._reflectionTex); + + const samplerInfo = [ + Filter.LINEAR, + Filter.LINEAR, + Filter.NONE, + Address.CLAMP, + Address.CLAMP, + Address.CLAMP, + ]; + + const samplerHash = genSamplerHash(samplerInfo); + this._reflectionSampler = samplerLib.getSampler(this._device, samplerHash); + this.descriptorSet.bindSampler(UNIFORM_REFLECTION_TEXTURE_BINDING, this._reflectionSampler); + this.descriptorSet.bindTexture(UNIFORM_REFLECTION_STORAGE_BINDING, this._reflectionTex); + } + } + + private _initNativePlanarShadowShader (shadowInfo: Shadows) { + this._planarShader = shadowInfo.getPlanarShader(this._patches); + if (JSB) { + this._nativeObj!.setPlanarShader(this._planarShader); + } } // This is a temporary solution @@ -184,8 +231,14 @@ export class SubModel { public initPlanarShadowShader () { const pipeline = legacyCC.director.root.pipeline as ForwardPipeline; const shadowInfo = pipeline.pipelineSceneData.shadows; - const shaderHandle = shadowInfo.getPlanarShader(this._patches); - SubModelPool.set(this._handle, SubModelView.PLANAR_SHADER, shaderHandle); + this._initNativePlanarShadowShader(shadowInfo); + } + + private _initNativePlanarShadowInstanceShader (shadowInfo: Shadows) { + this._planarInstanceShader = shadowInfo.getPlanarInstanceShader(this._patches); + if (JSB) { + this._nativeObj!.setPlanarInstanceShader(this._planarInstanceShader); + } } // This is a temporary solution @@ -193,19 +246,16 @@ export class SubModel { public initPlanarShadowInstanceShader () { const pipeline = legacyCC.director.root.pipeline as ForwardPipeline; const shadowInfo = pipeline.pipelineSceneData.shadows; - const shaderHandle = shadowInfo.getPlanarInstanceShader(this._patches); - SubModelPool.set(this._handle, SubModelView.PLANAR_INSTANCE_SHADER, shaderHandle); + this._initNativePlanarShadowInstanceShader(shadowInfo); } private _destroy () { if (JSB) { - SubModelPool.free(this._handle); + this._nativeObj = null; } - this._handle = NULL_HANDLE; } public destroy (): void { - this._destroy(); this._destroyDescriptorSet(); this._destroyInputAssembler(); this.priority = RenderPriority.DEFAULT; @@ -213,6 +263,13 @@ export class SubModel { this._patches = null; this._subMesh = null; this._passes = null; + + if (this._reflectionTex) this._reflectionTex.destroy(); + this._reflectionTex = null; + if (this._reflectionSampler) this._reflectionSampler.destroy(); + this._reflectionSampler = null; + + this._destroy(); } public update (): void { @@ -257,12 +314,17 @@ export class SubModel { const passes = this._passes; if (!passes) { return; } - this._setPassCount(passes.length); - let passOffset = SubModelView.PASS_0 as const; - let shaderOffset = SubModelView.SHADER_0 as const; - for (let i = 0; i < this._passCount; i++, passOffset++, shaderOffset++) { - SubModelPool.set(this._handle, passOffset, passes[i].handle); - SubModelPool.set(this._handle, shaderOffset, passes[i].getShaderVariant(this._patches)); + if (JSB) { + const nativeShaders: (Shader | null)[] = []; + for (let i = 0, len = passes.length; i < len; i++) { + if (JSB) { + nativeShaders.push(passes[i].getShaderVariant(this.patches)); + } + } + + const passesNative = passes.map((_pass: Pass): NativePass => _pass.native); + this._nativeObj!.setPasses(passesNative); + this._nativeObj!.setShaders(nativeShaders); } } } diff --git a/cocos/core/root.ts b/cocos/core/root.ts index 2fb28386f8f..72f1f78c30c 100644 --- a/cocos/core/root.ts +++ b/cocos/core/root.ts @@ -32,7 +32,7 @@ import { JSB } from 'internal:constants'; import { builtinResMgr } from './builtin'; import { Pool } from './memop'; import { RenderPipeline, createDefaultPipeline, DeferredPipeline } from './pipeline'; -import { Camera, Light, Model } from './renderer/scene'; +import { Camera, Light, Model, NativeRoot } from './renderer/scene'; import { DataPoolManager } from '../3d/skeletal-animation/data-pool-manager'; import { LightType } from './renderer/scene/light'; import { IRenderSceneInfo, RenderScene } from './renderer/scene/render-scene'; @@ -42,7 +42,6 @@ import { Batcher2D } from '../2d/renderer/batcher-2d'; import { legacyCC } from './global-exports'; import { RenderWindow, IRenderWindowInfo } from './renderer/core/render-window'; import { ColorAttachment, DepthStencilAttachment, RenderPassInfo, StoreOp, Device } from './gfx'; -import { RootHandle, RootPool, RootView, NULL_HANDLE } from './renderer/core/memory-pools'; import { warnID } from './platform/debug'; /** @@ -68,30 +67,27 @@ export interface ISceneInfo { export class Root { private _init (): void { if (JSB) { - this._poolHandle = RootPool.alloc(); + this._naitveObj = new NativeRoot(); } } private _destroy (): void { if (JSB) { - if (this._poolHandle) { - RootPool.free(this._poolHandle); - this._poolHandle = NULL_HANDLE; - } + this._naitveObj = null; } } private _setCumulativeTime (deltaTime: number): void { this._cumulativeTime += deltaTime; if (JSB) { - RootPool.set(this._poolHandle, RootView.CUMULATIVE_TIME, this._cumulativeTime); + this._naitveObj.cumulativeTime = this._cumulativeTime; } } private _setFrameTime (deltaTime: number): void { this._frameTime = deltaTime; if (JSB) { - RootPool.set(this._poolHandle, RootView.FRAME_TIME, deltaTime); + this._naitveObj.frameTime = deltaTime; } } @@ -221,10 +217,6 @@ export class Root { return this._dataPoolMgr; } - get handle () : RootHandle { - return this._poolHandle; - } - get useDeferredPipeline () : boolean { return this._useDeferredPipeline; } @@ -248,11 +240,11 @@ export class Root { private _frameCount = 0; private _fps = 0; private _fixedFPS = 0; - private _poolHandle: RootHandle = NULL_HANDLE; private _useDeferredPipeline = false; private _fixedFPSFrameTime = 0; private _cumulativeTime = 0; private _frameTime = 0; + private declare _naitveObj: any; /** * 构造函数 @@ -397,7 +389,7 @@ export class Root { * 重置累计时间 */ public resetCumulativeTime () { - RootPool.set(this._poolHandle, RootView.CUMULATIVE_TIME, 0); + this._setCumulativeTime(0); } /** diff --git a/cocos/core/scene-graph/base-node-dev.ts b/cocos/core/scene-graph/base-node-dev.ts index 9efa214566f..fc7cd9d50ee 100644 --- a/cocos/core/scene-graph/base-node-dev.ts +++ b/cocos/core/scene-graph/base-node-dev.ts @@ -91,8 +91,11 @@ export function baseNodePolyfill (BaseNode) { comp.node = this; this._components.splice(index, 0, comp); - if ((EDITOR || TEST) && legacyCC.engine && (this._id in legacyCC.engine.attachedObjsForEditor)) { - legacyCC.engine.attachedObjsForEditor[comp._id] = comp; + if (EDITOR && EditorExtends.Node && EditorExtends.Component) { + const node = EditorExtends.Node.getNode(this._id); + if (node) { + EditorExtends.Component.add(comp._id, comp); + } } if (this._activeInHierarchy) { legacyCC.director._nodeActivator.activateComp(comp); diff --git a/cocos/core/scene-graph/base-node.ts b/cocos/core/scene-graph/base-node.ts index 75286888526..62c98448485 100644 --- a/cocos/core/scene-graph/base-node.ts +++ b/cocos/core/scene-graph/base-node.ts @@ -35,7 +35,6 @@ import { property } from '../data/decorators/property'; import { CCObject } from '../data/object'; import { Event } from '../event'; import { errorID, warnID, error, log, getError } from '../platform/debug'; -import { SystemEventType } from '../platform/event-manager/event-enum'; import { ISchedulable } from '../scheduler'; import IdGenerator from '../utils/id-generator'; import * as js from '../utils/js'; @@ -44,6 +43,7 @@ import { legacyCC } from '../global-exports'; import { Node } from './node'; import type { Scene } from './scene'; import { PrefabInfo } from '../utils/prefab/prefab-info'; +import { NodeEventType } from './node-event'; const Destroying = CCObject.Flags.Destroying; const DontDestroy = CCObject.Flags.DontDestroy; @@ -72,12 +72,12 @@ function getConstructor (typeOrClassName: string | Constructor): Construct * @en The base class for [[Node]], it: * - maintains scene hierarchy and life cycle logic * - provides EventTarget ability - * - emits events if some properties changed, ref: [[SystemEventType]] + * - emits events if some properties changed, ref: [[Node.EventType]] * - manages components * @zh [[Node]] 的基类,他会负责: * - 维护场景树以及节点生命周期管理 * - 提供 EventTarget 的事件管理和注册能力 - * - 派发节点状态相关的事件,参考:[[SystemEventType]] + * - 派发节点状态相关的事件,参考:[[Node.EventType]] * - 管理组件 */ @ccclass('cc.BaseNode') @@ -425,7 +425,7 @@ export class BaseNode extends CCObject implements ISchedulable { this._onSetParent(oldParent, keepWorldTransform); if (this.emit) { - this.emit(SystemEventType.PARENT_CHANGED, oldParent); + this.emit(NodeEventType.PARENT_CHANGED, oldParent); } if (oldParent) { @@ -438,7 +438,7 @@ export class BaseNode extends CCObject implements ISchedulable { oldParent._children.splice(removeAt, 1); oldParent._updateSiblingIndex(); if (oldParent.emit) { - oldParent.emit(SystemEventType.CHILD_REMOVED, this); + oldParent.emit(NodeEventType.CHILD_REMOVED, this); } } } @@ -450,7 +450,7 @@ export class BaseNode extends CCObject implements ISchedulable { newParent._children.push(this); this._siblingIndex = newParent._children.length - 1; if (newParent.emit) { - newParent.emit(SystemEventType.CHILD_ADDED, this); + newParent.emit(NodeEventType.CHILD_ADDED, this); } } @@ -1062,15 +1062,15 @@ export class BaseNode extends CCObject implements ISchedulable { * @return - Just returns the incoming callback so you can save the anonymous function easier. * @example * ```ts - * this.node.on(SystemEventType.TOUCH_START, this.memberFunction, this); // if "this" is component and the "memberFunction" declared in CCClass. - * node.on(SystemEventType.TOUCH_START, callback, this); - * node.on(SystemEventType.TOUCH_MOVE, callback, this); - * node.on(SystemEventType.TOUCH_END, callback, this); + * this.node.on(NodeEventType.TOUCH_START, this.memberFunction, this); // if "this" is component and the "memberFunction" declared in CCClass. + * node.on(NodeEventType.TOUCH_START, callback, this); + * node.on(NodeEventType.TOUCH_MOVE, callback, this); + * node.on(NodeEventType.TOUCH_END, callback, this); * ``` */ - public on (type: string | SystemEventType, callback: AnyFunction, target?: unknown, useCapture: any = false) { + public on (type: string | NodeEventType, callback: AnyFunction, target?: unknown, useCapture: any = false) { switch (type) { - case SystemEventType.TRANSFORM_CHANGED: + case NodeEventType.TRANSFORM_CHANGED: this._eventMask |= TRANSFORM_ON; break; default: @@ -1090,8 +1090,8 @@ export class BaseNode extends CCObject implements ISchedulable { * @param useCapture - When set to true, the listener will be triggered at capturing phase which is ahead of the final target emit, otherwise it will be triggered during bubbling phase. * @example * ```ts - * this.node.off(SystemEventType.TOUCH_START, this.memberFunction, this); - * node.off(SystemEventType.TOUCH_START, callback, this.node); + * this.node.off(NodeEventType.TOUCH_START, this.memberFunction, this); + * node.off(NodeEventType.TOUCH_START, callback, this.node); * ``` */ public off (type: string, callback?: AnyFunction, target?: unknown, useCapture: any = false) { @@ -1101,7 +1101,7 @@ export class BaseNode extends CCObject implements ISchedulable { // All listener removed if (!hasListeners) { switch (type) { - case SystemEventType.TRANSFORM_CHANGED: + case NodeEventType.TRANSFORM_CHANGED: this._eventMask &= ~TRANSFORM_ON; break; default: @@ -1179,7 +1179,7 @@ export class BaseNode extends CCObject implements ISchedulable { public targetOff (target: string | unknown) { this._eventProcessor.targetOff(target); // Check for event mask reset - if ((this._eventMask & TRANSFORM_ON) && !this._eventProcessor.hasEventListener(SystemEventType.TRANSFORM_CHANGED)) { + if ((this._eventMask & TRANSFORM_ON) && !this._eventProcessor.hasEventListener(NodeEventType.TRANSFORM_CHANGED)) { this._eventMask &= ~TRANSFORM_ON; } } @@ -1233,7 +1233,7 @@ export class BaseNode extends CCObject implements ISchedulable { this._children[i]._siblingIndex = i; } - this.emit(SystemEventType.SIBLING_ORDER_CHANGED); + this.emit(NodeEventType.SIBLING_ORDER_CHANGED); } protected _onSetParent (oldParent: this | null, keepWorldTransform = false) { @@ -1343,20 +1343,20 @@ export class BaseNode extends CCObject implements ISchedulable { if (!destroyByParent) { // remove from parent if (parent) { - this.emit(SystemEventType.PARENT_CHANGED, this); + this.emit(NodeEventType.PARENT_CHANGED, this); // During destroy process, sibling index is not reliable const childIndex = parent._children.indexOf(this); parent._children.splice(childIndex, 1); this._siblingIndex = 0; parent._updateSiblingIndex(); if (parent.emit) { - parent.emit(SystemEventType.CHILD_REMOVED, this); + parent.emit(NodeEventType.CHILD_REMOVED, this); } } } // emit node destroy event (this should before event processor destroy) - this.emit(SystemEventType.NODE_DESTROYED, this); + this.emit(NodeEventType.NODE_DESTROYED, this); // Destroy node event processor this._eventProcessor.destroy(); diff --git a/cocos/core/scene-graph/node-event-processor.ts b/cocos/core/scene-graph/node-event-processor.ts index 9ce301874a6..c70b2a2fbf8 100644 --- a/cocos/core/scene-graph/node-event-processor.ts +++ b/cocos/core/scene-graph/node-event-processor.ts @@ -30,7 +30,6 @@ import Event from '../event/event'; import { Vec2 } from '../math/vec2'; -import { SystemEventType } from '../platform/event-manager/event-enum'; import { EventListener } from '../platform/event-manager/event-listener'; import { eventManager } from '../platform/event-manager/event-manager'; import { EventMouse, EventTouch } from '../platform/event-manager/events'; @@ -41,25 +40,26 @@ import { CallbacksInvoker } from '../event/callbacks-invoker'; import { errorID } from '../platform/debug'; import { legacyCC } from '../global-exports'; import { Component } from '../components/component'; +import { NodeEventType } from './node-event'; const _cachedArray = new Array(16); let _currentHovered: BaseNode | null = null; let pos = new Vec2(); const _touchEvents = [ - SystemEventType.TOUCH_START.toString(), - SystemEventType.TOUCH_MOVE.toString(), - SystemEventType.TOUCH_END.toString(), - SystemEventType.TOUCH_CANCEL.toString(), + NodeEventType.TOUCH_START, + NodeEventType.TOUCH_MOVE, + NodeEventType.TOUCH_END, + NodeEventType.TOUCH_CANCEL, ]; const _mouseEvents = [ - SystemEventType.MOUSE_DOWN.toString(), - SystemEventType.MOUSE_ENTER.toString(), - SystemEventType.MOUSE_MOVE.toString(), - SystemEventType.MOUSE_LEAVE.toString(), - SystemEventType.MOUSE_UP.toString(), - SystemEventType.MOUSE_WHEEL.toString(), + NodeEventType.MOUSE_DOWN, + NodeEventType.MOUSE_ENTER, + NodeEventType.MOUSE_MOVE, + NodeEventType.MOUSE_LEAVE, + NodeEventType.MOUSE_UP, + NodeEventType.MOUSE_WHEEL, ]; // TODO: rearrange event @@ -72,7 +72,7 @@ function _touchStartHandler (this: EventListener, touch: Touch, event: EventTouc touch.getUILocation(pos); if (node._uiProps.uiTransformComp.isHit(pos, this)) { - event.type = SystemEventType.TOUCH_START.toString(); + event.type = NodeEventType.TOUCH_START; event.touch = touch; event.bubbles = true; node.dispatchEvent(event); @@ -88,7 +88,7 @@ function _touchMoveHandler (this: EventListener, touch: Touch, event: EventTouch return false; } - event.type = SystemEventType.TOUCH_MOVE.toString(); + event.type = NodeEventType.TOUCH_MOVE; event.touch = touch; event.bubbles = true; node.dispatchEvent(event); @@ -104,9 +104,9 @@ function _touchEndHandler (this: EventListener, touch: Touch, event: EventTouch) touch.getUILocation(pos); if (node._uiProps.uiTransformComp.isHit(pos, this)) { - event.type = SystemEventType.TOUCH_END.toString(); + event.type = NodeEventType.TOUCH_END; } else { - event.type = SystemEventType.TOUCH_CANCEL.toString(); + event.type = NodeEventType.TOUCH_CANCEL; } event.touch = touch; event.bubbles = true; @@ -119,7 +119,7 @@ function _touchCancelHandler (this: EventListener, touch: Touch, event: EventTou return; } - event.type = SystemEventType.TOUCH_CANCEL.toString(); + event.type = NodeEventType.TOUCH_CANCEL; event.touch = touch; event.bubbles = true; node.dispatchEvent(event); @@ -134,7 +134,7 @@ function _mouseDownHandler (this: EventListener, event: EventMouse) { pos = event.getUILocation(); if (node._uiProps.uiTransformComp.isHit(pos, this)) { - event.type = SystemEventType.MOUSE_DOWN.toString(); + event.type = NodeEventType.MOUSE_DOWN; event.bubbles = true; node.dispatchEvent(event); } @@ -153,22 +153,22 @@ function _mouseMoveHandler (this: EventListener, event: EventMouse) { if (!this._previousIn) { // Fix issue when hover node switched, previous hovered node won't get MOUSE_LEAVE notification if (_currentHovered && _currentHovered.eventProcessor.mouseListener) { - event.type = SystemEventType.MOUSE_LEAVE; + event.type = NodeEventType.MOUSE_LEAVE; _currentHovered.dispatchEvent(event); if (_currentHovered.eventProcessor.mouseListener) { _currentHovered.eventProcessor.mouseListener._previousIn = false; } } _currentHovered = node; - event.type = SystemEventType.MOUSE_ENTER.toString(); + event.type = NodeEventType.MOUSE_ENTER; node.dispatchEvent(event); this._previousIn = true; } - event.type = SystemEventType.MOUSE_MOVE.toString(); + event.type = NodeEventType.MOUSE_MOVE; event.bubbles = true; node.dispatchEvent(event); } else if (this._previousIn) { - event.type = SystemEventType.MOUSE_LEAVE.toString(); + event.type = NodeEventType.MOUSE_LEAVE; node.dispatchEvent(event); this._previousIn = false; _currentHovered = null; @@ -191,7 +191,7 @@ function _mouseUpHandler (this: EventListener, event: EventMouse) { pos = event.getUILocation(); if (node._uiProps.uiTransformComp.isHit(pos, this)) { - event.type = SystemEventType.MOUSE_UP.toString(); + event.type = NodeEventType.MOUSE_UP; event.bubbles = true; node.dispatchEvent(event); // event.propagationStopped = true; @@ -208,7 +208,7 @@ function _mouseWheelHandler (this: EventListener, event: EventMouse) { pos = event.getUILocation(); if (node._uiProps.uiTransformComp.isHit(pos, this)) { - event.type = SystemEventType.MOUSE_WHEEL.toString(); + event.type = NodeEventType.MOUSE_WHEEL; event.bubbles = true; node.dispatchEvent(event); // event.propagationStopped = true; @@ -430,7 +430,7 @@ export class NodeEventProcessor { * this.node.on(Node.EventType.ANCHOR_CHANGED, callback); * ``` */ - public on (type: string, callback: AnyFunction, target?: unknown, useCapture?: boolean) { + public on (type: NodeEventType, callback: AnyFunction, target?: unknown, useCapture?: boolean) { const forDispatch = this._checknSetupSysEvent(type); if (forDispatch) { return this._onDispatch(type, callback, target, useCapture); @@ -479,7 +479,7 @@ export class NodeEventProcessor { * node.once(Node.EventType.ANCHOR_CHANGED, callback); * ``` */ - public once (type: string, callback: AnyFunction, target?: unknown, useCapture?: boolean) { + public once (type: NodeEventType, callback: AnyFunction, target?: unknown, useCapture?: boolean) { const forDispatch = this._checknSetupSysEvent(type); let listeners: CallbacksInvoker; @@ -512,7 +512,7 @@ export class NodeEventProcessor { * node.off(Node.EventType.ANCHOR_CHANGED, callback, this); * ``` */ - public off (type: string, callback?: AnyFunction, target?: unknown, useCapture?: boolean) { + public off (type: NodeEventType, callback?: AnyFunction, target?: unknown, useCapture?: boolean) { const touchEvent = _touchEvents.indexOf(type) !== -1; const mouseEvent = !touchEvent && _mouseEvents.indexOf(type) !== -1; if (touchEvent || mouseEvent) { @@ -673,7 +673,7 @@ export class NodeEventProcessor { // EVENT TARGET - private _checknSetupSysEvent (type: string) { + private _checknSetupSysEvent (type: NodeEventType) { let newAdded = false; let forDispatch = false; // just for ui diff --git a/cocos/core/scene-graph/node-event.ts b/cocos/core/scene-graph/node-event.ts new file mode 100644 index 00000000000..2ac29786981 --- /dev/null +++ b/cocos/core/scene-graph/node-event.ts @@ -0,0 +1,216 @@ +export enum NodeEventType { + /** + * @en + * The event type for touch start event + * + * @zh + * 手指开始触摸事件。 + */ + TOUCH_START = 'touch-start', + + /** + * @en + * The event type for touch move event + * + * @zh + * 当手指在屏幕上移动时。 + */ + TOUCH_MOVE = 'touch-move', + + /** + * @en + * The event type for touch end event + * + * @zh + * 手指结束触摸事件。 + */ + TOUCH_END = 'touch-end', + + /** + * @en + * The event type for touch end event + * + * @zh + * 当手指在目标节点区域外离开屏幕时。 + */ + TOUCH_CANCEL = 'touch-cancel', + + /** + * @en + * The event type for mouse down events + * + * @zh + * 当鼠标按下时触发一次。 + */ + MOUSE_DOWN = 'mouse-down', + + /** + * @en + * The event type for mouse move events + * + * @zh + * 当鼠标在目标节点在目标节点区域中移动时,不论是否按下。 + */ + MOUSE_MOVE = 'mouse-move', + + /** + * @en + * The event type for mouse up events + * + * @zh + * 当鼠标从按下状态松开时触发一次。 + */ + MOUSE_UP = 'mouse-up', + + /** + * @en + * The event type for mouse wheel events + * + * @zh 手指开始触摸事件 + */ + MOUSE_WHEEL = 'mouse-wheel', + + /** + * @en + * The event type for mouse leave target events + * + * @zh + * 当鼠标移入目标节点区域时,不论是否按下. + */ + MOUSE_ENTER = 'mouse-enter', + + /** + * @en + * The event type for mouse leave target events + * + * @zh + * 当鼠标移出目标节点区域时,不论是否按下。 + */ + MOUSE_LEAVE = 'mouse-leave', + + /** + * @en The event type for press the key down event, the event will be continuously dispatched in the key pressed state + * @zh 当按下按键时触发的事件, 该事件在按下状态会持续派发 + * @deprecated since v3.3, please use SystemEventType.KEY_DOWN instead + */ + KEY_DOWN = 'keydown', + + /** + * @en The event type for press the key up event + * @zh 当松开按键时触发的事件 + * @deprecated since v3.3, please use SystemEventType.KEY_UP instead + */ + KEY_UP = 'keyup', + + /** + * @en + * The event type for press the devicemotion event + * + * @zh + * 重力感应 + * + * @deprecated since v3.3, please use SystemEventType.DEVICEMOTION instead + */ + DEVICEMOTION = 'devicemotion', + + /** + * @en + * The event type for position, rotation, scale changed.Use the type parameter as [[Node.TransformBit]] to check which part is changed + * + * @zh + * 节点改变位置、旋转或缩放事件。如果具体需要判断是哪一个事件,可通过判断回调的第一个参数类型是 [[Node.TransformBit]] 中的哪一个来获取 + * @example + * ``` + * this.node.on(Node.EventType.TRANSFORM_CHANGED, (type)=>{ + * if (type & Node.TransformBit.POSITION) { + * //... + * } + * }, this); + * ``` + */ + TRANSFORM_CHANGED = 'transform-changed', + + /** + * @en The event type for notifying the host scene has been changed for a persist node. + * @zh 当场景常驻节点的场景发生改变时触发的事件,一般在切换场景过程中触发。 + */ + SCENE_CHANGED_FOR_PERSISTS = 'scene-changed-for-persists', + + /** + * @en + * The event type for size change events. + * Performance note, this event will be triggered every time corresponding properties being changed, + * if the event callback have heavy logic it may have great performance impact, try to avoid such scenario. + * + * @zh + * 当节点尺寸改变时触发的事件。 + * 性能警告:这个事件会在每次对应的属性被修改时触发,如果事件回调损耗较高,有可能对性能有很大的负面影响,请尽量避免这种情况。 + */ + SIZE_CHANGED = 'size-changed', + + /** + * @en + * The event type for anchor point change events. + * Performance note, this event will be triggered every time corresponding properties being changed, + * if the event callback have heavy logic it may have great performance impact, try to avoid such scenario. + * + * @zh + * 当节点的 UITransform 锚点改变时触发的事件。 + * 性能警告:这个事件会在每次对应的属性被修改时触发,如果事件回调损耗较高,有可能对性能有很大的负面影响,请尽量避免这种情况。 + */ + ANCHOR_CHANGED = 'anchor-changed', + + /** + * @en + * The event type for color change events. + * Performance note, this event will be triggered every time corresponding properties being changed, + * if the event callback have heavy logic it may have great performance impact, try to avoid such scenario. + * + * @zh + * 当节点的 UI 渲染组件颜色属性改变时触发的事件。 + * 性能警告:这个事件会在每次对应的属性被修改时触发,如果事件回调损耗较高,有可能对性能有很大的负面影响,请尽量避免这种情况。 + */ + COLOR_CHANGED = 'color-changed', + + /** + * @en + * The event type for adding a new child node to the target node. + * + * @zh + * 给目标节点添加子节点时触发的事件。 + */ + CHILD_ADDED = 'child-added', + + /** + * @en + * The event type for removing a child node from the target node. + * + * @zh + * 给目标节点移除子节点时触发的事件。 + */ + CHILD_REMOVED = 'child-removed', + + /** + * @en The event type for changing the parent of the target node + * @zh 目标节点的父节点改变时触发的事件。 + */ + PARENT_CHANGED = 'parent-changed', + + /** + * @en The event type for destroying the target node + * @zh 目标节点被销毁时触发的事件。 + */ + NODE_DESTROYED = 'node-destroyed', + + /** + * @en The event type for node layer change events. + * @zh 节点 layer 改变时触发的事件。 + */ + LAYER_CHANGED = 'layer-changed', + + /** + * @en The event type for node's sibling order changed. + * @zh 当节点在兄弟节点中的顺序发生变化时触发的事件。 + */ + SIBLING_ORDER_CHANGED = 'sibling-order-changed', +} diff --git a/cocos/core/scene-graph/node.ts b/cocos/core/scene-graph/node.ts index f69a8d2f65c..3f9beb7a799 100644 --- a/cocos/core/scene-graph/node.ts +++ b/cocos/core/scene-graph/node.ts @@ -34,30 +34,80 @@ import { import { JSB } from 'internal:constants'; import { Layers } from './layers'; import { NodeUIProperties } from './node-ui-properties'; -import { SystemEventType } from '../platform/event-manager/event-enum'; import { eventManager } from '../platform/event-manager/event-manager'; import { legacyCC } from '../global-exports'; import { BaseNode, TRANSFORM_ON } from './base-node'; -import { - Mat3, Mat4, Quat, Vec3, -} from '../math'; -import { - NULL_HANDLE, NodeHandle, NodePool, NodeView, -} from '../renderer/core/memory-pools'; +import { Mat3, Mat4, Quat, Vec3 } from '../math'; +import { NULL_HANDLE, NodePool, NodeView, NodeHandle } from '../renderer/core/memory-pools'; import { NodeSpace, TransformBit } from './node-enum'; import { applyMountedChildren, applyMountedComponents, applyRemovedComponents, applyPropertyOverrides, applyTargetOverrides, createNodeWithPrefab, generateTargetMap } from '../utils/prefab/utils'; import { Component } from '../components'; +import { NativeNode } from '../renderer/scene/native-scene'; +import { FloatArray } from '../math/type-define'; +import { NodeEventType } from './node-event'; const v3_a = new Vec3(); const q_a = new Quat(); const q_b = new Quat(); -const array_a = new Array(10); const qt_1 = new Quat(); const m3_1 = new Mat3(); const m3_scaling = new Mat3(); const m4_1 = new Mat4(); -const bookOfChange = new Map(); +const array_a: any[] = []; + +class BookOfChange { + private _chunks: Uint32Array[] = []; + private _freelists: number[][] = []; + + // these should match with native: cocos/renderer/pipeline/helper/SharedMemory.h Node.getHasChangedFlags + private static CAPACITY_PER_CHUNK = 256; + + constructor () { + this._createChunk(); + } + + public alloc () { + const chunkCount = this._freelists.length; + for (let i = 0; i < chunkCount; ++i) { + if (!this._freelists[i].length) continue; + return this._createView(i); + } + this._createChunk(); + return this._createView(chunkCount); + } + + public free (view: Uint32Array, idx: number) { + const chunkCount = this._freelists.length; + for (let i = 0; i < chunkCount; ++i) { + if (this._chunks[i] !== view) continue; + this._freelists[i].push(idx); + return; + } + } + + public clear () { + const chunkCount = this._chunks.length; + for (let i = 0; i < chunkCount; ++i) { + this._chunks[i].fill(0); + } + } + + private _createChunk () { + this._chunks.push(new Uint32Array(BookOfChange.CAPACITY_PER_CHUNK)); + const freelist: number[] = []; + for (let i = 0; i < BookOfChange.CAPACITY_PER_CHUNK; ++i) freelist.push(i); + this._freelists.push(freelist); + } + + private _createView (chunkIdx: number): [Uint32Array, number] { + const chunk = this._chunks[chunkIdx]; + const offset = this._freelists[chunkIdx].pop()!; + return [chunk, offset]; + } +} + +const bookOfChange = new BookOfChange(); /** * @zh @@ -83,13 +133,11 @@ const bookOfChange = new Map(); */ @ccclass('cc.Node') export class Node extends BaseNode { - public static bookOfChange = bookOfChange; - /** * @en Event types emitted by Node * @zh 节点可能发出的事件类型 */ - public static EventType = SystemEventType; + public static EventType = NodeEventType; /** * @en Coordinates space @@ -105,24 +153,31 @@ export class Node extends BaseNode { public static TransformDirtyBit = TransformBit; /** - * @en Bit masks for Node transformation parts, can be used to determine which part changed in [[SystemEventType.TRANSFORM_CHANGED]] event - * @zh 节点变换更新的具体部分,可用于判断 [[SystemEventType.TRANSFORM_CHANGED]] 事件的具体类型 + * @en Bit masks for Node transformation parts, can be used to determine which part changed in [[NodeEventType.TRANSFORM_CHANGED]] event + * @zh 节点变换更新的具体部分,可用于判断 [[NodeEventType.TRANSFORM_CHANGED]] 事件的具体类型 */ public static TransformBit = TransformBit; // UI 部分的脏数据 public _uiProps = new NodeUIProperties(this); + /** + * @en Counter to clear node array + * @zh 清除节点数组计时器 + */ + private static ClearFrame = 0; + private static ClearRound = 1000; + public _static = false; // world transform, don't access this directly - protected _pos = new Vec3(); + protected declare _pos: Vec3; - protected _rot = new Quat(); + protected declare _rot: Quat; - protected _scale = new Vec3(1, 1, 1); + protected declare _scale: Vec3; - protected _mat = new Mat4(); + protected declare _mat: Mat4; // local transform @serializable @@ -144,15 +199,39 @@ export class Node extends BaseNode { protected _dirtyFlags = TransformBit.NONE; // does the world transform need to update? protected _eulerDirty = false; - - protected _poolHandle: NodeHandle = NULL_HANDLE; + protected _nodeHandle: NodeHandle = NULL_HANDLE; + protected declare _hasChangedFlagsChunk: Uint32Array; // has the transform been updated in this frame? + protected declare _hasChangedFlagsOffset: number; + protected declare _nativeObj: NativeNode | null; + protected declare _nativeLayer: Uint32Array; + protected declare _nativeFlag: Uint32Array; protected _init () { if (JSB) { - this._poolHandle = NodePool.alloc(); - NodePool.set(this._poolHandle, NodeView.LAYER, this._layer); + // new node + this._nodeHandle = NodePool.alloc(); + this._pos = new Vec3(NodePool.getTypedArray(this._nodeHandle, NodeView.WORLD_POSITION) as FloatArray); + this._rot = new Quat(NodePool.getTypedArray(this._nodeHandle, NodeView.WORLD_ROTATION) as FloatArray); + this._scale = new Vec3(NodePool.getTypedArray(this._nodeHandle, NodeView.WORLD_SCALE) as FloatArray); + this._mat = new Mat4(NodePool.getTypedArray(this._nodeHandle, NodeView.WORLD_MATRIX) as FloatArray); + this._nativeLayer = NodePool.getTypedArray(this._nodeHandle, NodeView.LAYER) as Uint32Array; + this._nativeFlag = NodePool.getTypedArray(this._nodeHandle, NodeView.FLAGS_CHANGED) as Uint32Array; + this._scale.set(1, 1, 1); + this._nativeLayer[0] = this._layer; + this._nativeObj = new NativeNode(); + this._nativeObj.initWithData(NodePool.getBuffer(this._nodeHandle)); + } else { + this._pos = new Vec3(); + this._rot = new Quat(); + this._scale = new Vec3(1, 1, 1); + this._mat = new Mat4(); } + + const [chunk, offset] = bookOfChange.alloc(); + this._hasChangedFlagsChunk = chunk; + this._hasChangedFlagsOffset = offset; } + constructor (name?: string) { super(name); this._init(); @@ -167,10 +246,16 @@ export class Node extends BaseNode { } protected _destroy () { - if (JSB && this._poolHandle) { - NodePool.free(this._poolHandle); - this._poolHandle = NULL_HANDLE; + if (JSB) { + if (this._nodeHandle) { + NodePool.free(this._nodeHandle); + this._nodeHandle = NULL_HANDLE; + } + + this._nativeObj = null; } + + bookOfChange.free(this._hasChangedFlagsChunk, this._hasChangedFlagsOffset); } public destroy () { @@ -178,8 +263,8 @@ export class Node extends BaseNode { return super.destroy(); } - get handle (): NodeHandle { - return this._poolHandle; + get native (): any { + return this._nativeObj; } /** @@ -192,7 +277,7 @@ export class Node extends BaseNode { } public set position (val: Readonly) { - this.setPosition(val); + this.setPosition(val as Vec3); } /** @@ -206,7 +291,7 @@ export class Node extends BaseNode { } public set worldPosition (val: Readonly) { - this.setWorldPosition(val); + this.setWorldPosition(val as Vec3); } /** @@ -219,7 +304,7 @@ export class Node extends BaseNode { } public set rotation (val: Readonly) { - this.setRotation(val); + this.setRotation(val as Quat); } /** @@ -255,7 +340,7 @@ export class Node extends BaseNode { this.invalidateChildren(TransformBit.ROTATION); if (this._eventMask & TRANSFORM_ON) { - this.emit(SystemEventType.TRANSFORM_CHANGED, TransformBit.ROTATION); + this.emit(NodeEventType.TRANSFORM_CHANGED, TransformBit.ROTATION); } } @@ -270,7 +355,7 @@ export class Node extends BaseNode { } public set worldRotation (val: Readonly) { - this.setWorldRotation(val); + this.setWorldRotation(val as Quat); } /** @@ -283,7 +368,7 @@ export class Node extends BaseNode { } public set scale (val: Readonly) { - this.setScale(val); + this.setScale(val as Vec3); } /** @@ -297,7 +382,7 @@ export class Node extends BaseNode { } public set worldScale (val: Readonly) { - this.setWorldScale(val); + this.setWorldScale(val as Vec3); } /** @@ -309,7 +394,7 @@ export class Node extends BaseNode { this.invalidateChildren(TransformBit.TRS); this._eulerDirty = true; if (this._eventMask & TRANSFORM_ON) { - this.emit(SystemEventType.TRANSFORM_CHANGED, TransformBit.TRS); + this.emit(NodeEventType.TRANSFORM_CHANGED, TransformBit.TRS); } } @@ -338,6 +423,22 @@ export class Node extends BaseNode { this.setWorldRotation(q_a); } + /** + * @en Return the up direction vertor of this node in world space. + * @zh 返回当前节点在世界空间中朝上的方向向量 + */ + get up (): Vec3 { + return Vec3.transformQuat(new Vec3(), Vec3.UP, this.worldRotation); + } + + /** + * @en Return the right direction vector of this node in world space. + * @zh 返回当前节点在世界空间中朝右的方向向量 + */ + get right (): Vec3 { + return Vec3.transformQuat(new Vec3(), Vec3.RIGHT, this.worldRotation); + } + /** * @en Layer of the current Node, it affects raycast, physics etc, refer to [[Layers]] * @zh 节点所属层,主要影响射线检测、物理碰撞等,参考 [[Layers]] @@ -346,9 +447,9 @@ export class Node extends BaseNode { set layer (l) { this._layer = l; if (JSB) { - NodePool.set(this._poolHandle, NodeView.LAYER, this._layer); + this._nativeLayer[0] = this._layer; } - this.emit(SystemEventType.LAYER_CHANGED, this._layer); + this.emit(NodeEventType.LAYER_CHANGED, this._layer); } get layer () { @@ -360,13 +461,13 @@ export class Node extends BaseNode { * @zh 这个节点的空间变换信息在当前帧内是否有变过? */ get hasChangedFlags () { - return bookOfChange.get(this) || 0; + return this._hasChangedFlagsChunk[this._hasChangedFlagsOffset] as TransformBit; } set hasChangedFlags (val: number) { - bookOfChange.set(this, val); + this._hasChangedFlagsChunk[this._hasChangedFlagsOffset] = val; if (JSB) { - NodePool.set(this._poolHandle, NodeView.FLAGS_CHANGED, val); + this._nativeFlag[0] = val; } } @@ -411,8 +512,7 @@ export class Node extends BaseNode { public _onBatchCreated (dontSyncChildPrefab: boolean) { if (JSB) { - NodePool.set(this._poolHandle, NodeView.LAYER, this._layer); - NodePool.setVec3(this._poolHandle, NodeView.WORLD_SCALE, this._scale); + this._nativeLayer[0] = this._layer; } const prefabInstance = this._prefab?.instance; if (!dontSyncChildPrefab && prefabInstance) { @@ -490,10 +590,7 @@ export class Node extends BaseNode { } this.invalidateChildren(TransformBit.POSITION); if (this._eventMask & TRANSFORM_ON) { - this.emit(SystemEventType.TRANSFORM_CHANGED, TransformBit.POSITION); - } - if (JSB) { - NodePool.setVec3(this._poolHandle, NodeView.WORLD_POSITION, this.worldPosition); + this.emit(NodeEventType.TRANSFORM_CHANGED, TransformBit.POSITION); } } @@ -519,10 +616,7 @@ export class Node extends BaseNode { this._eulerDirty = true; this.invalidateChildren(TransformBit.ROTATION); if (this._eventMask & TRANSFORM_ON) { - this.emit(SystemEventType.TRANSFORM_CHANGED, TransformBit.ROTATION); - } - if (JSB) { - NodePool.setVec4(this._poolHandle, NodeView.WORLD_ROTATION, this.worldRotation); + this.emit(NodeEventType.TRANSFORM_CHANGED, TransformBit.ROTATION); } } @@ -532,7 +626,7 @@ export class Node extends BaseNode { * @param pos Target position * @param up Up direction */ - public lookAt (pos: Vec3, up?: Vec3): void { + public lookAt (pos: Readonly, up?: Readonly): void { this.getWorldPosition(v3_a); Vec3.subtract(v3_a, v3_a, pos); Vec3.normalize(v3_a, v3_a); @@ -551,15 +645,21 @@ export class Node extends BaseNode { * @param dirtyBit The dirty bits to setup to children, can be composed with multiple dirty bits */ public invalidateChildren (dirtyBit: TransformBit) { - const hasChanegdFlags = this.hasChangedFlags; - if ((this._dirtyFlags & hasChanegdFlags & dirtyBit) === dirtyBit) { return; } - this._dirtyFlags |= dirtyBit; - this.hasChangedFlags = hasChanegdFlags | dirtyBit; - const newDirtyBit = dirtyBit | TransformBit.POSITION; - const len = this._children.length; - for (let i = 0; i < len; ++i) { - const child = this._children[i]; - if (child.isValid) { child.invalidateChildren(newDirtyBit); } + const childDirtyBit = dirtyBit | TransformBit.POSITION; + array_a[0] = this; + + let i = 0; + while (i >= 0) { + const cur: this = array_a[i--]; + const hasChangedFlags = cur.hasChangedFlags; + if (cur.isValid && (cur._dirtyFlags & hasChangedFlags & dirtyBit) !== dirtyBit) { + cur._dirtyFlags |= dirtyBit; + cur.hasChangedFlags = hasChangedFlags | dirtyBit; + const children = cur._children; + const len = children.length; + for (let j = 0; j < len; ++j) array_a[++i] = children[j]; + } + dirtyBit = childDirtyBit; } } @@ -589,27 +689,18 @@ export class Node extends BaseNode { child._mat.m12 = child._pos.x; child._mat.m13 = child._pos.y; child._mat.m14 = child._pos.z; - if (JSB) { - NodePool.setVec3(child._poolHandle, NodeView.WORLD_POSITION, child._pos); - } } if (dirtyBits & TransformBit.RS) { Mat4.fromRTS(child._mat, child._lrot, child._lpos, child._lscale); Mat4.multiply(child._mat, cur._mat, child._mat); if (dirtyBits & TransformBit.ROTATION) { Quat.multiply(child._rot, cur._rot, child._lrot); - if (JSB) { - NodePool.setVec4(child._poolHandle, NodeView.WORLD_ROTATION, child._rot); - } } Mat3.fromQuat(m3_1, Quat.conjugate(qt_1, child._rot)); Mat3.multiplyMat4(m3_1, m3_1, child._mat); child._scale.x = m3_1.m00; child._scale.y = m3_1.m04; child._scale.z = m3_1.m08; - if (JSB) { - NodePool.setVec3(child._poolHandle, NodeView.WORLD_SCALE, child._scale); - } } } else { if (dirtyBits & TransformBit.POSITION) { @@ -617,31 +708,18 @@ export class Node extends BaseNode { child._mat.m12 = child._pos.x; child._mat.m13 = child._pos.y; child._mat.m14 = child._pos.z; - if (JSB) { - NodePool.setVec3(child._poolHandle, NodeView.WORLD_POSITION, child._pos); - } } if (dirtyBits & TransformBit.RS) { if (dirtyBits & TransformBit.ROTATION) { Quat.copy(child._rot, child._lrot); - if (JSB) { - NodePool.setVec4(child._poolHandle, NodeView.WORLD_ROTATION, child._rot); - } } if (dirtyBits & TransformBit.SCALE) { Vec3.copy(child._scale, child._lscale); - if (JSB) { - NodePool.setVec3(child._poolHandle, NodeView.WORLD_SCALE, child._scale); - } Mat4.fromRTS(child._mat, child._rot, child._pos, child._scale); } } } - if (dirtyBits !== TransformBit.NONE && JSB) { - NodePool.setMat4(child._poolHandle, NodeView.WORLD_MATRIX, child._mat); - } - child._dirtyFlags = TransformBit.NONE; cur = child; } @@ -656,7 +734,7 @@ export class Node extends BaseNode { * @zh 设置本地坐标 * @param position Target position */ - public setPosition (position: Vec3): void; + public setPosition (position: Readonly): void; /** * @en Set position in local coordinate system @@ -667,7 +745,7 @@ export class Node extends BaseNode { */ public setPosition (x: number, y: number, z?: number): void; - public setPosition (val: Vec3 | number, y?: number, z?: number): void { + public setPosition (val: Readonly | number, y?: number, z?: number): void { if (y === undefined && z === undefined) { Vec3.copy(this._lpos, val as Vec3); } else if (z === undefined) { @@ -678,7 +756,7 @@ export class Node extends BaseNode { this.invalidateChildren(TransformBit.POSITION); if (this._eventMask & TRANSFORM_ON) { - this.emit(SystemEventType.TRANSFORM_CHANGED, TransformBit.POSITION); + this.emit(NodeEventType.TRANSFORM_CHANGED, TransformBit.POSITION); } } @@ -700,7 +778,7 @@ export class Node extends BaseNode { * @zh 用四元数设置本地旋转 * @param rotation Rotation in quaternion */ - public setRotation (rotation: Quat): void; + public setRotation (rotation: Readonly): void; /** * @en Set rotation in local coordinate system with a quaternion representing the rotation @@ -712,9 +790,9 @@ export class Node extends BaseNode { */ public setRotation (x: number, y: number, z: number, w: number): void; - public setRotation (val: Quat | number, y?: number, z?: number, w?: number) { + public setRotation (val: Readonly | number, y?: number, z?: number, w?: number) { if (y === undefined || z === undefined || w === undefined) { - Quat.copy(this._lrot, val as Quat); + Quat.copy(this._lrot, val as Readonly); } else { Quat.set(this._lrot, val as number, y, z, w); } @@ -722,7 +800,7 @@ export class Node extends BaseNode { this.invalidateChildren(TransformBit.ROTATION); if (this._eventMask & TRANSFORM_ON) { - this.emit(SystemEventType.TRANSFORM_CHANGED, TransformBit.ROTATION); + this.emit(NodeEventType.TRANSFORM_CHANGED, TransformBit.ROTATION); } } @@ -757,7 +835,7 @@ export class Node extends BaseNode { this.invalidateChildren(TransformBit.ROTATION); if (this._eventMask & TRANSFORM_ON) { - this.emit(SystemEventType.TRANSFORM_CHANGED, TransformBit.ROTATION); + this.emit(NodeEventType.TRANSFORM_CHANGED, TransformBit.ROTATION); } } @@ -779,7 +857,7 @@ export class Node extends BaseNode { * @zh 设置本地缩放 * @param scale Target scale */ - public setScale (scale: Vec3): void; + public setScale (scale: Readonly): void; /** * @en Set scale in local coordinate system @@ -790,7 +868,7 @@ export class Node extends BaseNode { */ public setScale (x: number, y: number, z?: number): void; - public setScale (val: Vec3 | number, y?: number, z?: number) { + public setScale (val: Readonly | number, y?: number, z?: number) { if (y === undefined && z === undefined) { Vec3.copy(this._lscale, val as Vec3); } else if (z === undefined) { @@ -801,7 +879,7 @@ export class Node extends BaseNode { this.invalidateChildren(TransformBit.SCALE); if (this._eventMask & TRANSFORM_ON) { - this.emit(SystemEventType.TRANSFORM_CHANGED, TransformBit.SCALE); + this.emit(NodeEventType.TRANSFORM_CHANGED, TransformBit.SCALE); } } @@ -863,9 +941,6 @@ export class Node extends BaseNode { } else { Vec3.set(this._pos, val as number, y, z); } - if (JSB) { - NodePool.setVec3(this._poolHandle, NodeView.WORLD_POSITION, this._pos); - } const parent = this._parent; const local = this._lpos; if (parent) { @@ -882,7 +957,7 @@ export class Node extends BaseNode { this.invalidateChildren(TransformBit.POSITION); if (this._eventMask & TRANSFORM_ON) { - this.emit(SystemEventType.TRANSFORM_CHANGED, TransformBit.POSITION); + this.emit(NodeEventType.TRANSFORM_CHANGED, TransformBit.POSITION); } } @@ -923,9 +998,6 @@ export class Node extends BaseNode { } else { Quat.set(this._rot, val as number, y, z, w); } - if (JSB) { - NodePool.setVec4(this._poolHandle, NodeView.WORLD_ROTATION, this._rot); - } if (this._parent) { this._parent.updateWorldTransform(); Quat.multiply(this._lrot, Quat.conjugate(this._lrot, this._parent._rot), this._rot); @@ -936,7 +1008,7 @@ export class Node extends BaseNode { this.invalidateChildren(TransformBit.ROTATION); if (this._eventMask & TRANSFORM_ON) { - this.emit(SystemEventType.TRANSFORM_CHANGED, TransformBit.ROTATION); + this.emit(NodeEventType.TRANSFORM_CHANGED, TransformBit.ROTATION); } } @@ -959,7 +1031,7 @@ export class Node extends BaseNode { this.invalidateChildren(TransformBit.ROTATION); if (this._eventMask & TRANSFORM_ON) { - this.emit(SystemEventType.TRANSFORM_CHANGED, TransformBit.ROTATION); + this.emit(NodeEventType.TRANSFORM_CHANGED, TransformBit.ROTATION); } } @@ -999,9 +1071,6 @@ export class Node extends BaseNode { } else { Vec3.set(this._scale, val as number, y, z); } - if (JSB) { - NodePool.setVec3(this._poolHandle, NodeView.WORLD_SCALE, this._scale); - } const parent = this._parent; if (parent) { parent.updateWorldTransform(); @@ -1020,7 +1089,7 @@ export class Node extends BaseNode { this.invalidateChildren(TransformBit.SCALE); if (this._eventMask & TRANSFORM_ON) { - this.emit(SystemEventType.TRANSFORM_CHANGED, TransformBit.SCALE); + this.emit(NodeEventType.TRANSFORM_CHANGED, TransformBit.SCALE); } } @@ -1107,7 +1176,7 @@ export class Node extends BaseNode { if (dirtyBit) { this.invalidateChildren(dirtyBit); if (this._eventMask & TRANSFORM_ON) { - this.emit(SystemEventType.TRANSFORM_CHANGED, dirtyBit); + this.emit(NodeEventType.TRANSFORM_CHANGED, dirtyBit); } } } @@ -1147,47 +1216,22 @@ export class Node extends BaseNode { * @zh * 清除所有节点的脏标记。 */ - public static clearBooks () { - if (JSB) bookOfChange.forEach((v, k, m) => { if (k.isValid) k.hasChangedFlags = TransformBit.NONE; }); + public static resetHasChangedFlags () { bookOfChange.clear(); } /** * @en - * Synchronize the js transform to the native layer. - * @zh - * js 变换信息同步到原生层。 - */ - public syncToNativeTransform () { - const v = this.hasChangedFlags; - if (v && JSB) { - if (v & TransformBit.POSITION) { NodePool.setVec3(this._poolHandle, NodeView.WORLD_POSITION, this.worldPosition); } - if (v & TransformBit.ROTATION) { NodePool.setVec3(this._poolHandle, NodeView.WORLD_ROTATION, this.worldRotation); } - if (v & TransformBit.SCALE) { NodePool.setVec3(this._poolHandle, NodeView.WORLD_SCALE, this.worldScale); } - } - } - - /** - * @en - * Synchronize the native transform to the js layer. + * clear node array * @zh - * 原生变换信息同步到 js 层。 + * 清除节点数组 */ - public syncFromNativeTransform () { - const v = NodePool.get(this._poolHandle, NodeView.FLAGS_CHANGED); - if (v) { - if (v & TransformBit.POSITION) { - NodePool.getVec3(this._poolHandle, NodeView.WORLD_POSITION, v3_a); - this.setWorldPosition(v3_a); - } - if (v & TransformBit.ROTATION) { - NodePool.getVec4(this._poolHandle, NodeView.WORLD_ROTATION, q_a); - this.setWorldRotation(q_a); - } - if (v & TransformBit.SCALE) { - NodePool.getVec3(this._poolHandle, NodeView.WORLD_SCALE, v3_a); - this.setWorldScale(v3_a); - } + public static clearNodeArray () { + if (Node.ClearFrame < Node.ClearRound) { + Node.ClearFrame++; + } else { + Node.ClearFrame = 0; + array_a.length = 0; } } } diff --git a/cocos/core/splash-screen.ts b/cocos/core/splash-screen.ts index c27d1cebcf7..ce701c16fce 100644 --- a/cocos/core/splash-screen.ts +++ b/cocos/core/splash-screen.ts @@ -41,7 +41,6 @@ import { import { PipelineStateManager } from './pipeline'; import { legacyCC } from './global-exports'; import { Root } from './root'; -import { DSPool, ShaderPool, PassPool, PassView } from './renderer/core/memory-pools'; import { SetIndex } from './pipeline/define'; import { error } from './platform'; import { Mat4, Vec2 } from './math'; @@ -239,7 +238,7 @@ export class SplashScreen { let scaleX = logoW * logoTW / logoTH; let scaleY = logoW; if (device.surfaceTransform === SurfaceTransform.ROTATE_90 - || device.surfaceTransform === SurfaceTransform.ROTATE_270) { + || device.surfaceTransform === SurfaceTransform.ROTATE_270) { scaleX = logoW * dw / dh; scaleY = logoW * logoTH / logoTW * dh / dw; } @@ -257,7 +256,7 @@ export class SplashScreen { let scaleX = wartermarkW; let scaleY = wartermarkW * wartermarkTH / wartermarkTW; if (device.surfaceTransform === SurfaceTransform.ROTATE_90 - || device.surfaceTransform === SurfaceTransform.ROTATE_270) { + || device.surfaceTransform === SurfaceTransform.ROTATE_270) { scaleX = wartermarkW * 0.5; scaleY = wartermarkW * dw / dh * 0.5; } @@ -307,8 +306,8 @@ export class SplashScreen { const pass = this.logoMat.passes[0]; const binding = pass.getBinding('mainTexture'); pass.bindTexture(binding, this.logoTexture); - this.shader = ShaderPool.get(pass.getShaderVariant()); - const descriptorSet = DSPool.get(PassPool.get(pass.handle, PassView.DESCRIPTOR_SET)); + this.shader = pass.getShaderVariant()!; + const descriptorSet = pass.descriptorSet; descriptorSet.bindSampler(binding, this.sampler); descriptorSet.update(); @@ -345,7 +344,7 @@ export class SplashScreen { const pass = this.watermarkMat.passes[0]; const binding = pass.getBinding('mainTexture'); pass.bindTexture(binding, this.watermarkTexture); - DSPool.get(PassPool.get(pass.handle, PassView.DESCRIPTOR_SET)).update(); + pass.descriptorSet.update(); } private frame () { @@ -356,15 +355,8 @@ export class SplashScreen { const framebuffer = this.framebuffer; const renderArea = this.renderArea; - // here we gonna render to fullscreen, but device.width/height represents logic size, - // renderArea assigned to viewport directly, so physical size is needed. - if (JSB) { - renderArea.width = device.nativeWidth; - renderArea.height = device.nativeHeight; - } else { - renderArea.width = device.width; - renderArea.height = device.height; - } + renderArea.width = device.width; + renderArea.height = device.height; cmdBuff.begin(); cmdBuff.beginRenderPass(framebuffer.renderPass, framebuffer, renderArea, this.clearColors, 1.0, 0); diff --git a/cocos/core/utils/x-deprecated.ts b/cocos/core/utils/x-deprecated.ts index 299ca5016c5..b03bb27b593 100644 --- a/cocos/core/utils/x-deprecated.ts +++ b/cocos/core/utils/x-deprecated.ts @@ -246,7 +246,7 @@ markAsWarning = (owner: object, ownerName: string, properties: IMarkItem[]) => { const id = messageID++; messageMap.set(id, { id, count: 0, logTimes: item.logTimes !== undefined ? item.logTimes : defaultLogTimes }); const suggest = item.suggest ? `(${item.suggest})` : ''; - if (descriptor.value != null) { + if (typeof descriptor.value !== 'undefined') { if (typeof descriptor.value === 'function') { const oldValue = descriptor.value as Function; owner[deprecatedProp] = function (this) { @@ -254,7 +254,22 @@ markAsWarning = (owner: object, ownerName: string, properties: IMarkItem[]) => { return oldValue.call(this, ...arguments); }; } else { - _defaultGetSet(descriptor, ownerName, deprecatedProp, warn, id, suggest); + let oldValue = descriptor.value; + Object.defineProperty(owner, deprecatedProp, { + configurable: true, + get () { + markAsWarningLog(ownerName, deprecatedProp, warn, id, suggest); + return oldValue; + }, + }); + if (descriptor.writable) { + Object.defineProperty(owner, deprecatedProp, { + set (value) { + markAsWarningLog(ownerName, deprecatedProp, warn, id, suggest); + oldValue = value; + }, + }); + } } } else { _defaultGetSet(descriptor, ownerName, deprecatedProp, warn, id, suggest); diff --git a/cocos/dragon-bones/CCFactory.ts b/cocos/dragon-bones/CCFactory.ts index aef5920cc80..c22a6b18b33 100644 --- a/cocos/dragon-bones/CCFactory.ts +++ b/cocos/dragon-bones/CCFactory.ts @@ -5,7 +5,7 @@ import { EDITOR } from 'internal:constants'; import { Armature, BaseObject, Animation, BaseFactory, DragonBones } from '@cocos/dragonbones-js'; -import { Component, director, Game, game, ISchedulable, Node, RenderTexture, Scheduler, systemEvent, SystemEventType } from '../core'; +import { Component, director, Game, game, ISchedulable, Node, RenderTexture, Scheduler } from '../core'; import { ccclass } from '../core/data/class-decorator'; import { CCTextureAtlasData } from './CCTextureData'; import { TextureBase } from '../core/assets/texture-base'; diff --git a/cocos/dragon-bones/assembler/simple.ts b/cocos/dragon-bones/assembler/simple.ts index fa8937b026f..3ad832dbb41 100644 --- a/cocos/dragon-bones/assembler/simple.ts +++ b/cocos/dragon-bones/assembler/simple.ts @@ -408,9 +408,9 @@ function updateComponentRenderData (comp: ArmatureDisplay, batcher: Batcher2D) { _handleVal |= NEED_COLOR; } - let worldMat:Mat4|undefined; + let worldMat: Mat4 | undefined; if (_comp._enableBatch) { - worldMat = _node.worldMatrix; + worldMat = _node.worldMatrix as Mat4; _mustFlush = false; _handleVal |= NEED_BATCH; } diff --git a/cocos/particle/emitter/shape-module.ts b/cocos/particle/emitter/shape-module.ts index 0b5bfd8fd15..58ea3a34988 100644 --- a/cocos/particle/emitter/shape-module.ts +++ b/cocos/particle/emitter/shape-module.ts @@ -156,6 +156,8 @@ export default class ShapeModule { this.emitFrom = EmitLocation.Volume; } break; + default: + break; } } @@ -350,6 +352,8 @@ export default class ShapeModule { return repeat(angle, this._arc); case ArcMode.PingPong: return pingPong(angle, this._arc); + default: + return repeat(angle, this._arc); } } } diff --git a/cocos/particle/particle-system.ts b/cocos/particle/particle-system.ts index a7c81786ed4..44399024676 100644 --- a/cocos/particle/particle-system.ts +++ b/cocos/particle/particle-system.ts @@ -608,6 +608,10 @@ export class ParticleSystem extends RenderableComponent { this._subEmitters = []; // array of { emitter: ParticleSystem, type: 'birth', 'collision' or 'death'} } + public onFocusInEditor () { + this.renderer.create(this); + } + public onLoad () { // HACK, TODO this.renderer.onInit(this); @@ -620,7 +624,9 @@ export class ParticleSystem extends RenderableComponent { } public _onMaterialModified (index: number, material: Material) { - this.processor.onMaterialModified(index, material); + if (this.processor !== null) { + this.processor.onMaterialModified(index, material); + } } public _onRebuildPSO (index: number, material: Material) { diff --git a/cocos/particle/renderer/particle-system-renderer-data.ts b/cocos/particle/renderer/particle-system-renderer-data.ts index 31fb6dcdf61..118a0730f35 100644 --- a/cocos/particle/renderer/particle-system-renderer-data.ts +++ b/cocos/particle/renderer/particle-system-renderer-data.ts @@ -32,6 +32,7 @@ import ParticleSystemRendererGPU from './particle-system-renderer-gpu'; import { director } from '../../core/director'; import { Device, Feature } from '../../core/gfx'; import { legacyCC } from '../../core/global-exports'; +import { errorID } from '../../core'; function isSupportGPUParticle () { const device: Device = director.root!.device; @@ -203,11 +204,25 @@ export default class ParticleSystemRenderer { private _particleSystem: any = null!; // ParticleSystem - onInit (ps: any) { - this._particleSystem = ps; - const useGPU = this._useGPU && isSupportGPUParticle(); - this._particleSystem.processor = useGPU ? new ParticleSystemRendererGPU(this) : new ParticleSystemRendererCPU(this); - this._particleSystem.processor.onInit(ps); + create (ps) { + // if particle system is null we run the old routine + // else if particle system is not null we do nothing + if (this._particleSystem === null) { + this._particleSystem = ps; + } else if (this._particleSystem !== ps) { + errorID(6033); + } + } + + onInit (ps) { + this.create(ps); + if (!this._particleSystem.processor) { + const useGPU = this._useGPU && isSupportGPUParticle(); + this._particleSystem.processor = useGPU ? new ParticleSystemRendererGPU(this) : new ParticleSystemRendererCPU(this); + this._particleSystem.processor.onInit(ps); + } else { + errorID(6034); + } } private _switchProcessor () { diff --git a/cocos/physics-2d/box2d/joints/mouse-joint.ts b/cocos/physics-2d/box2d/joints/mouse-joint.ts index 0d9efe08692..061b0a93239 100644 --- a/cocos/physics-2d/box2d/joints/mouse-joint.ts +++ b/cocos/physics-2d/box2d/joints/mouse-joint.ts @@ -7,8 +7,9 @@ import { IMouseJoint } from '../../spec/i-physics-joint'; import { b2Joint } from './joint-2d'; import { MouseJoint2D, PhysicsSystem2D, Joint2D } from '../../framework'; import { PHYSICS_2D_PTM_RATIO } from '../../framework/physics-types'; -import { IVec2Like, systemEvent, SystemEventType, Touch, Vec2, find } from '../../../core'; +import { IVec2Like, Touch, Vec2, find } from '../../../core'; import { b2PhysicsWorld } from '../physics-world'; +import { NodeEventType } from '../../../core/scene-graph/node-event'; const tempB2Vec2 = new b2.Vec2(); @@ -54,10 +55,10 @@ export class b2MouseJoint extends b2Joint implements IMouseJoint { const canvas = find('Canvas'); if (canvas) { - canvas.on(SystemEventType.TOUCH_START, this.onTouchBegan, this); - canvas.on(SystemEventType.TOUCH_MOVE, this.onTouchMove, this); - canvas.on(SystemEventType.TOUCH_END, this.onTouchEnd, this); - canvas.on(SystemEventType.TOUCH_CANCEL, this.onTouchEnd, this); + canvas.on(NodeEventType.TOUCH_START, this.onTouchBegan, this); + canvas.on(NodeEventType.TOUCH_MOVE, this.onTouchMove, this); + canvas.on(NodeEventType.TOUCH_END, this.onTouchEnd, this); + canvas.on(NodeEventType.TOUCH_CANCEL, this.onTouchEnd, this); } } diff --git a/cocos/physics-2d/box2d/rigid-body.ts b/cocos/physics-2d/box2d/rigid-body.ts index 35ed7527ab6..b5159f90d50 100644 --- a/cocos/physics-2d/box2d/rigid-body.ts +++ b/cocos/physics-2d/box2d/rigid-body.ts @@ -13,6 +13,7 @@ import { PHYSICS_2D_PTM_RATIO, ERigidBody2DType } from '../framework/physics-typ import { Node } from '../../core/scene-graph/node'; import { Collider2D } from '../framework'; +import { NodeEventType } from '../../core/scene-graph/node-event'; const tempVec3 = new Vec3(); @@ -64,12 +65,12 @@ export class b2RigidBody2D implements IRigidBody2D { _registerNodeEvents () { const node = this.rigidBody.node; - node.on(Node.EventType.TRANSFORM_CHANGED, this._onNodeTransformChanged, this); + node.on(NodeEventType.TRANSFORM_CHANGED, this._onNodeTransformChanged, this); } _unregisterNodeEvents () { const node = this.rigidBody.node; - node.off(Node.EventType.TRANSFORM_CHANGED, this._onNodeTransformChanged, this); + node.off(NodeEventType.TRANSFORM_CHANGED, this._onNodeTransformChanged, this); } _onNodeTransformChanged (type) { diff --git a/cocos/physics/ammo/ammo-rigid-body.ts b/cocos/physics/ammo/ammo-rigid-body.ts index 6ae16aacd34..dedfd59444a 100644 --- a/cocos/physics/ammo/ammo-rigid-body.ts +++ b/cocos/physics/ammo/ammo-rigid-body.ts @@ -80,47 +80,7 @@ export class AmmoRigidBody implements IRigidBody { } setType (v: ERigidBodyType) { - let m_bcf = this.impl.getCollisionFlags(); - let m_gcf = this._sharedBody.ghost.getCollisionFlags(); - const localInertia = AmmoConstant.instance.VECTOR3_0; - switch (v) { - case ERigidBodyType.DYNAMIC: - m_bcf &= (~AmmoCollisionFlags.CF_KINEMATIC_OBJECT); - m_bcf &= (~AmmoCollisionFlags.CF_STATIC_OBJECT); - this.impl.setCollisionFlags(m_bcf); - this.setMass(this._rigidBody.mass); - this.useGravity(this._rigidBody.useGravity); - this.setAllowSleep(this._rigidBody.allowSleep); - m_gcf &= (~AmmoCollisionFlags.CF_STATIC_OBJECT); - m_gcf |= AmmoCollisionFlags.CF_KINEMATIC_OBJECT; - this._sharedBody.ghost.setCollisionFlags(m_gcf); - break; - case ERigidBodyType.KINEMATIC: - localInertia.setValue(0, 0, 0); - this.impl.setMassProps(0, localInertia); - m_bcf |= AmmoCollisionFlags.CF_KINEMATIC_OBJECT; - m_bcf &= (~AmmoCollisionFlags.CF_STATIC_OBJECT); - this.impl.setCollisionFlags(m_bcf); - this.impl.forceActivationState(AmmoCollisionObjectStates.DISABLE_DEACTIVATION); - m_gcf |= AmmoCollisionFlags.CF_KINEMATIC_OBJECT; - m_gcf &= (~AmmoCollisionFlags.CF_STATIC_OBJECT); - this._sharedBody.ghost.setCollisionFlags(m_gcf); - break; - case ERigidBodyType.STATIC: - default: - localInertia.setValue(0, 0, 0); - this.impl.setMassProps(0, localInertia); - m_bcf |= AmmoCollisionFlags.CF_STATIC_OBJECT; - m_bcf &= (~AmmoCollisionFlags.CF_KINEMATIC_OBJECT); - this.impl.setCollisionFlags(m_bcf); - this.impl.forceActivationState(AmmoCollisionObjectStates.DISABLE_DEACTIVATION); - m_gcf &= (~AmmoCollisionFlags.CF_KINEMATIC_OBJECT); - m_gcf |= AmmoCollisionFlags.CF_STATIC_OBJECT; - this._sharedBody.ghost.setCollisionFlags(m_gcf); - break; - } - this._sharedBody.dirty |= EAmmoSharedBodyDirty.BODY_RE_ADD; - this._sharedBody.dirty |= EAmmoSharedBodyDirty.GHOST_RE_ADD; + this._sharedBody.setType(v); } setLinearDamping (value: number) { @@ -205,7 +165,6 @@ export class AmmoRigidBody implements IRigidBody { onEnable () { this._isEnabled = true; this.setMass(this._rigidBody.mass); - this.setType(this._rigidBody.type); this.setAllowSleep(this._rigidBody.allowSleep); this.setLinearDamping(this._rigidBody.linearDamping); this.setAngularDamping(this._rigidBody.angularDamping); @@ -249,7 +208,7 @@ export class AmmoRigidBody implements IRigidBody { return ammo2CocosVec3(out, this.impl.getLinearVelocity()); } - setLinearVelocity (value: Vec3): void { + setLinearVelocity (value: Readonly): void { this._wakeUpIfSleep(); cocos2AmmoVec3(this.impl.getLinearVelocity(), value); } @@ -258,7 +217,7 @@ export class AmmoRigidBody implements IRigidBody { return ammo2CocosVec3(out, this.impl.getAngularVelocity()); } - setAngularVelocity (value: Vec3): void { + setAngularVelocity (value: Readonly): void { this._wakeUpIfSleep(); cocos2AmmoVec3(this.impl.getAngularVelocity(), value); } diff --git a/cocos/physics/ammo/ammo-shared-body.ts b/cocos/physics/ammo/ammo-shared-body.ts index d4addc64ca5..d4deb181841 100644 --- a/cocos/physics/ammo/ammo-shared-body.ts +++ b/cocos/physics/ammo/ammo-shared-body.ts @@ -37,7 +37,7 @@ import { IAmmoBodyStruct, IAmmoGhostStruct } from './ammo-interface'; import { CC_V3_0, CC_QUAT_0, AmmoConstant } from './ammo-const'; import { PhysicsSystem } from '../framework'; import { AmmoConstraint } from './constraints/ammo-constraint'; -import { PhysicsGroup } from '../framework/physics-enum'; +import { ERigidBodyType, PhysicsGroup } from '../framework/physics-enum'; import { fastRemoveAt } from '../../core/utils/array'; /** @@ -154,8 +154,12 @@ export class AmmoSharedBody { set bodyEnabled (v: boolean) { if (v) { if (this.bodyIndex < 0) { + // add to world only if it is a dynamic body or having shapes. + if (this.bodyStruct.wrappedShapes.length === 0) { + if (!this.wrappedBody) return; + if (!this.wrappedBody.rigidBody.isDynamic) return; + } this.bodyIndex = this.wrappedWorld.bodies.length; - this.body.clearState(); this.wrappedWorld.addSharedBody(this); this.syncInitialBody(); } @@ -235,11 +239,11 @@ export class AmmoSharedBody { wrappedShapes: [], useCompound: false, }; - AmmoInstance.bodyStructs[`KEY${this._bodyStruct.id}`] = this._bodyStruct; + AmmoInstance.bodyStructs[this._bodyStruct.id] = this._bodyStruct; this.body.setUserIndex2(2); this.body.setUserIndex(this._bodyStruct.id); - if (mass === 0) this.body.setActivationState(AmmoCollisionObjectStates.DISABLE_DEACTIVATION); if ((Ammo as any).CC_CONFIG.ignoreSelfBody && this._ghostStruct) this.ghost.setIgnoreCollisionCheck(this.body, true); + if (this.wrappedBody) this.setBodyType(this.wrappedBody.rigidBody.type); } private _instantiateGhostStruct () { @@ -256,11 +260,78 @@ export class AmmoSharedBody { worldQuat: new Ammo.btQuaternion(), wrappedShapes: [], }; - AmmoInstance.ghostStructs[`KEY${this._ghostStruct.id}`] = this._ghostStruct; + AmmoInstance.ghostStructs[this._ghostStruct.id] = this._ghostStruct; this.ghost.setUserIndex2(2); this.ghost.setUserIndex(this._ghostStruct.id); - this.ghost.setActivationState(AmmoCollisionObjectStates.DISABLE_DEACTIVATION); if ((Ammo as any).CC_CONFIG.ignoreSelfBody && this._bodyStruct) this.ghost.setIgnoreCollisionCheck(this.body, true); + if (this.wrappedBody) this.setGhostType(this.wrappedBody.rigidBody.type); + } + + setType (v:ERigidBodyType) { + this.setBodyType(v); + this.setGhostType(v); + } + + setBodyType (v:ERigidBodyType) { + if (this._bodyStruct && this._wrappedBody) { + const body = this._bodyStruct.body; + const wrap = this._wrappedBody; + const com = wrap.rigidBody; + let m_bcf = body.getCollisionFlags(); + const localInertia = AmmoConstant.instance.VECTOR3_0; + switch (v) { + case ERigidBodyType.DYNAMIC: + m_bcf &= (~AmmoCollisionFlags.CF_KINEMATIC_OBJECT); + m_bcf &= (~AmmoCollisionFlags.CF_STATIC_OBJECT); + body.setCollisionFlags(m_bcf); + wrap.setMass(com.mass); + wrap.useGravity(com.useGravity); + wrap.setAllowSleep(com.allowSleep); + break; + case ERigidBodyType.KINEMATIC: + localInertia.setValue(0, 0, 0); + body.setMassProps(0, localInertia); + m_bcf |= AmmoCollisionFlags.CF_KINEMATIC_OBJECT; + m_bcf &= (~AmmoCollisionFlags.CF_STATIC_OBJECT); + body.setCollisionFlags(m_bcf); + body.forceActivationState(AmmoCollisionObjectStates.DISABLE_DEACTIVATION); + break; + case ERigidBodyType.STATIC: + default: + localInertia.setValue(0, 0, 0); + body.setMassProps(0, localInertia); + m_bcf |= AmmoCollisionFlags.CF_STATIC_OBJECT; + m_bcf &= (~AmmoCollisionFlags.CF_KINEMATIC_OBJECT); + body.setCollisionFlags(m_bcf); + body.forceActivationState(AmmoCollisionObjectStates.ISLAND_SLEEPING); + break; + } + this.dirty |= EAmmoSharedBodyDirty.BODY_RE_ADD; + } + } + + setGhostType (v:ERigidBodyType) { + if (this._ghostStruct) { + const ghost = this._ghostStruct.ghost; + let m_gcf = ghost.getCollisionFlags(); + switch (v) { + case ERigidBodyType.DYNAMIC: + case ERigidBodyType.KINEMATIC: + m_gcf &= (~AmmoCollisionFlags.CF_STATIC_OBJECT); + m_gcf |= AmmoCollisionFlags.CF_KINEMATIC_OBJECT; + ghost.setCollisionFlags(m_gcf); + ghost.forceActivationState(AmmoCollisionObjectStates.DISABLE_DEACTIVATION); + break; + case ERigidBodyType.STATIC: + default: + m_gcf &= (~AmmoCollisionFlags.CF_KINEMATIC_OBJECT); + m_gcf |= AmmoCollisionFlags.CF_STATIC_OBJECT; + ghost.setCollisionFlags(m_gcf); + ghost.forceActivationState(AmmoCollisionObjectStates.ISLAND_SLEEPING); + break; + } + this.dirty |= EAmmoSharedBodyDirty.GHOST_RE_ADD; + } } addShape (v: AmmoShape, isTrigger: boolean) { @@ -388,10 +459,13 @@ export class AmmoSharedBody { wt0.getBasis().getRotation(this.bodyStruct.worldQuat); this.node.worldRotation = ammo2CocosQuat(quat_0, this.bodyStruct.worldQuat); - const wt1 = this.ghost.getWorldTransform(); - cocos2AmmoVec3(wt1.getOrigin(), this.node.worldPosition); - cocos2AmmoQuat(this.ghostStruct.worldQuat, this.node.worldRotation); - wt1.setRotation(this.ghostStruct.worldQuat); + // sync node to ghost + if (this._ghostStruct) { + const wt1 = this.ghost.getWorldTransform(); + cocos2AmmoVec3(wt1.getOrigin(), this.node.worldPosition); + cocos2AmmoQuat(this.ghostStruct.worldQuat, this.node.worldRotation); + wt1.setRotation(this.ghostStruct.worldQuat); + } } syncSceneToGhost () { @@ -478,8 +552,7 @@ export class AmmoSharedBody { // Ammo.destroy(bodyStruct.body); ammoDeletePtr(bodyStruct.body, Ammo.btRigidBody); ammoDeletePtr(bodyStruct.body, Ammo.btCollisionObject); - const key0 = `KEY${bodyStruct.id}`; - delete AmmoInstance.bodyStructs[key0]; + delete AmmoInstance.bodyStructs[bodyStruct.id]; (this._bodyStruct as any) = null; } @@ -489,8 +562,7 @@ export class AmmoSharedBody { Ammo.destroy(ghostStruct.shape); ammoDeletePtr(ghostStruct.shape, Ammo.btCollisionShape); Ammo.destroy(ghostStruct.ghost); - const key1 = `KEY${ghostStruct.id}`; - delete AmmoInstance.bodyStructs[key1]; + delete AmmoInstance.bodyStructs[ghostStruct.id]; (this._ghostStruct as any) = null; } } diff --git a/cocos/physics/ammo/ammo-world.ts b/cocos/physics/ammo/ammo-world.ts index 63e62184891..7d01e083700 100644 --- a/cocos/physics/ammo/ammo-world.ts +++ b/cocos/physics/ammo/ammo-world.ts @@ -90,15 +90,15 @@ export class AmmoWorld implements IPhysicsWorld { this._btBroadphase = new Ammo.btDbvtBroadphase(); this._btSolver = new Ammo.btSequentialImpulseConstraintSolver(); this._btWorld = new Ammo.btDiscreteDynamicsWorld(this._btDispatcher, this._btBroadphase, this._btSolver, this._btCollisionConfiguration); - (this._btWorld.getPairCache() as any).setOverlapFilterCallback(new (Ammo as any).ccOverlapFilterCallback()); + this._btWorld.getPairCache().setOverlapFilterCallback(new Ammo.ccOverlapFilterCallback()); // this._btWorld.setContactBreakingThreshold(0.04); const TMP = AmmoConstant.instance.VECTOR3_0; TMP.setValue(0, -10, 0); this._btWorld.setGravity(TMP); if (!AmmoWorld.closeHitCB) AmmoWorld.closeHitCB = new Ammo.ClosestRayResultCallback(TMP, TMP); if (!AmmoWorld.allHitsCB) AmmoWorld.allHitsCB = new Ammo.AllHitsRayResultCallback(TMP, TMP); - (AmmoWorld.closeHitCB as any).setUseCC(true); - (AmmoWorld.allHitsCB as any).setUseCC(true); + AmmoWorld.closeHitCB.setUseCC(true); + AmmoWorld.allHitsCB.setUseCC(true); } destroy (): void { @@ -175,7 +175,7 @@ export class AmmoWorld implements IPhysicsWorld { if (btCs.isCompound()) { const shapeIndex = allHitsCB.m_shapeParts.at(i); const index = btObj.getUserIndex(); - const shared = AmmoInstance.bodyAndGhosts[`KEY${index}`]; + const shared = AmmoInstance.bodyAndGhosts[index]; shape = shared.wrappedShapes[shapeIndex]; } else { shape = (btCs as any).wrapped; @@ -214,7 +214,7 @@ export class AmmoWorld implements IPhysicsWorld { let shape: AmmoShape; if (btCs.isCompound()) { const index = btObj.getUserIndex(); - const shared = AmmoInstance.bodyAndGhosts[`KEY${index}`]; + const shared = AmmoInstance.bodyAndGhosts[index]; const shapeIndex = closeHitCB.m_shapePart; shape = shared.wrappedShapes[shapeIndex]; } else { diff --git a/cocos/physics/cannon/cannon-rigid-body.ts b/cocos/physics/cannon/cannon-rigid-body.ts index 62040143b4f..8f63a3ebacc 100644 --- a/cocos/physics/cannon/cannon-rigid-body.ts +++ b/cocos/physics/cannon/cannon-rigid-body.ts @@ -236,28 +236,28 @@ export class CannonRigidBody implements IRigidBody { applyForce (force: Vec3, worldPoint?: Vec3) { this._sharedBody.syncSceneToPhysics(); this._wakeUpIfSleep(); - if (worldPoint == null) worldPoint = Vec3.ZERO; + if (worldPoint == null) worldPoint = Vec3.ZERO as Vec3; this.impl.applyForce(Vec3.copy(v3_cannon0, force), Vec3.copy(v3_cannon1, worldPoint)); } applyImpulse (impulse: Vec3, worldPoint?: Vec3) { this._sharedBody.syncSceneToPhysics(); this._wakeUpIfSleep(); - if (worldPoint == null) worldPoint = Vec3.ZERO; + if (worldPoint == null) worldPoint = Vec3.ZERO as Vec3; this.impl.applyImpulse(Vec3.copy(v3_cannon0, impulse), Vec3.copy(v3_cannon1, worldPoint)); } applyLocalForce (force: Vec3, localPoint?: Vec3): void { this._sharedBody.syncSceneToPhysics(); this._wakeUpIfSleep(); - if (localPoint == null) localPoint = Vec3.ZERO; + if (localPoint == null) localPoint = Vec3.ZERO as Vec3; this.impl.applyLocalForce(Vec3.copy(v3_cannon0, force), Vec3.copy(v3_cannon1, localPoint)); } applyLocalImpulse (impulse: Vec3, localPoint?: Vec3): void { this._sharedBody.syncSceneToPhysics(); this._wakeUpIfSleep(); - if (localPoint == null) localPoint = Vec3.ZERO; + if (localPoint == null) localPoint = Vec3.ZERO as Vec3; this.impl.applyLocalImpulse(Vec3.copy(v3_cannon0, impulse), Vec3.copy(v3_cannon1, localPoint)); } diff --git a/cocos/physics/cocos/builtin-interface.ts b/cocos/physics/cocos/builtin-interface.ts index 9ae2aacbbd0..9ad232058f5 100644 --- a/cocos/physics/cocos/builtin-interface.ts +++ b/cocos/physics/cocos/builtin-interface.ts @@ -36,5 +36,5 @@ import { IVec3Like, IQuatLike } from '../../core/math/type-define'; */ export interface IBuiltinShape { center: Vec3; - transform (m: Mat4, pos: IVec3Like, rot: IQuatLike, scale: IVec3Like, out: IBuiltinShape): any; + transform (m: Readonly, pos: IVec3Like, rot: IQuatLike, scale: IVec3Like, out: IBuiltinShape): any; } diff --git a/cocos/physics/cocos/shapes/builtin-shape.ts b/cocos/physics/cocos/shapes/builtin-shape.ts index b2b1338652b..843345cedd4 100644 --- a/cocos/physics/cocos/shapes/builtin-shape.ts +++ b/cocos/physics/cocos/shapes/builtin-shape.ts @@ -100,7 +100,7 @@ export class BuiltinShape implements IBaseShape { (this._worldShape as any) = null; } - transform (m: Mat4, pos: Vec3, rot: Quat, scale: Vec3) { + transform (m: Readonly, pos: Readonly, rot: Readonly, scale: Readonly) { this._localShape.transform(m, pos, rot, scale, this._worldShape); } diff --git a/cocos/profiler/profiler.ts b/cocos/profiler/profiler.ts index fd1da36658b..3da2dd404bc 100644 --- a/cocos/profiler/profiler.ts +++ b/cocos/profiler/profiler.ts @@ -40,6 +40,8 @@ import { preTransforms } from '../core/math/mat4'; const _characters = '0123456789. '; +const _average = 500; + const _string2offset = { 0: 0, 1: 1, @@ -68,14 +70,14 @@ interface IProfilerState { } const _profileInfo = { - fps: { desc: 'Framerate (FPS)', below: 30, average: 500, isInteger: true }, + fps: { desc: 'Framerate (FPS)', below: 30, average: _average, isInteger: true }, draws: { desc: 'Draw call', isInteger: true }, - frame: { desc: 'Frame time (ms)', min: 0, max: 50, average: 500 }, + frame: { desc: 'Frame time (ms)', min: 0, max: 50, average: _average }, instances: { desc: 'Instance Count', isInteger: true }, tricount: { desc: 'Triangle', isInteger: true }, - logic: { desc: 'Game Logic (ms)', min: 0, max: 50, average: 500, color: '#080' }, - physics: { desc: 'Physics (ms)', min: 0, max: 50, average: 500 }, - render: { desc: 'Renderer (ms)', min: 0, max: 50, average: 500, color: '#f90' }, + logic: { desc: 'Game Logic (ms)', min: 0, max: 50, average: _average, color: '#080' }, + physics: { desc: 'Physics (ms)', min: 0, max: 50, average: _average }, + render: { desc: 'Renderer (ms)', min: 0, max: 50, average: _average, color: '#f90' }, textureMemory: { desc: 'GFX Texture Mem(M)' }, bufferMemory: { desc: 'GFX Buffer Mem(M)' }, }; @@ -143,6 +145,7 @@ export class Profiler { legacyCC.director.off(legacyCC.Director.EVENT_BEFORE_DRAW, this.beforeDraw, this); legacyCC.director.off(legacyCC.Director.EVENT_AFTER_DRAW, this.afterDraw, this); this._showFPS = false; + legacyCC.game.config.showFPS = false; } } @@ -173,6 +176,7 @@ export class Profiler { this._showFPS = true; this._canvasDone = true; this._statsDone = true; + legacyCC.game.config.showFPS = true; } } @@ -405,7 +409,7 @@ export class Profiler { (this._stats.fps.counter as PerfCounter).frame(now); (this._stats.render.counter as PerfCounter).end(now); - if (now - this.lastTime < 500) { + if (now - this.lastTime < _average) { return; } this.lastTime = now; diff --git a/cocos/spine/assembler/simple.ts b/cocos/spine/assembler/simple.ts index 0bd8ea59243..fbf4bc23527 100644 --- a/cocos/spine/assembler/simple.ts +++ b/cocos/spine/assembler/simple.ts @@ -264,7 +264,7 @@ function updateComponentRenderData (comp: Skeleton, ui: Batcher2D) { let worldMat: Mat4 | undefined; if (_comp.enableBatch) { - worldMat = _node.worldMatrix; + worldMat = _node.worldMatrix as Mat4; _mustFlush = false; _handleVal |= FLAG_BATCH; } diff --git a/cocos/spine/attach-util.ts b/cocos/spine/attach-util.ts index f5187bc3fe9..e139e924dd0 100644 --- a/cocos/spine/attach-util.ts +++ b/cocos/spine/attach-util.ts @@ -3,12 +3,13 @@ * @module spine */ -import { Mat4, Node } from '../core'; +import { Mat4, Vec3, Node } from '../core'; import { Skeleton } from './skeleton'; import spine from './lib/spine-core.js'; import { FrameBoneInfo } from './skeleton-cache'; -const _tempMat4 = new Mat4(); +const tempMat4 = new Mat4(); +const nodeScale = new Vec3(); /** * @en Attach node tool @@ -59,15 +60,16 @@ export class AttachUtil { if (!boneInfos) return; const matrixHandle = (node:Node, bone:FrameBoneInfo) => { - const tm = _tempMat4; + nodeScale.set(node.scale); + const tm = tempMat4; tm.m00 = bone.a; tm.m01 = bone.c; tm.m04 = bone.b; tm.m05 = bone.d; tm.m12 = bone.worldX; tm.m13 = bone.worldY; - node.matrix = _tempMat4; - node.scale = this._skeletonNode!.scale; + node.matrix = tempMat4; + node.scale = nodeScale; }; for (const boneIdx of socketNodes.keys()) { diff --git a/cocos/terrain/terrain-asset.ts b/cocos/terrain/terrain-asset.ts index 8add0a21bd5..cae412cfd67 100644 --- a/cocos/terrain/terrain-asset.ts +++ b/cocos/terrain/terrain-asset.ts @@ -413,6 +413,10 @@ export class TerrainAsset extends Asset { } public _loadNativeData (_nativeData: Uint8Array) { + if (!_nativeData || _nativeData.length === 0) { + return false; + } + const stream = new TerrainBuffer(); stream.assign(_nativeData); diff --git a/cocos/tiledmap/assembler/simple.ts b/cocos/tiledmap/assembler/simple.ts index 76fc5bcdb32..e9a5bcb0e0d 100644 --- a/cocos/tiledmap/assembler/simple.ts +++ b/cocos/tiledmap/assembler/simple.ts @@ -538,8 +538,7 @@ function fillByTiledNode (tiledNode: Node, color: Float32Array, vbuf: Float32Arr const vertStep3 = vertStep * 3; tiledNode.updateWorldTransform(); - - Mat4.copy(_mat4_temp, tiledNode.matrix); + Mat4.fromRTS(_mat4_temp, tiledNode.getRotation(), tiledNode.getPosition(), tiledNode.getScale()); Vec3.set(_vec3u_temp, -(left + _moveX), -(bottom + _moveY), 0); Mat4.transform(_mat4_temp, _mat4_temp, _vec3u_temp); const m = _mat4_temp; diff --git a/cocos/tiledmap/tiled-layer.ts b/cocos/tiledmap/tiled-layer.ts index def8e31f889..13f2972c740 100644 --- a/cocos/tiledmap/tiled-layer.ts +++ b/cocos/tiledmap/tiled-layer.ts @@ -37,7 +37,7 @@ import { Renderable2D } from '../2d/framework/renderable-2d'; import { SpriteFrame } from '../2d/assets/sprite-frame'; import { Component } from '../core/components'; import { TMXMapInfo } from './tmx-xml-parser'; -import { Color, IVec2Like, Mat4, Size, SystemEventType, Texture2D, Vec2, Vec3, Node, warn, logID, CCBoolean, director } from '../core'; +import { Color, IVec2Like, Mat4, Size, Texture2D, Vec2, Vec3, Node, warn, logID, CCBoolean, director } from '../core'; import { TiledTile } from './tiled-tile'; import { MeshRenderData } from '../2d/renderer/render-data'; import { Batcher2D } from '../2d/renderer/batcher-2d'; @@ -46,6 +46,7 @@ import { GIDFlags, TiledGrid, TiledAnimationType, PropertiesInfo, TMXLayerInfo, } from './tiled-types'; import { fillTextureGrids, loadAllTextures } from './tiled-utils'; +import { NodeEventType } from '../core/scene-graph/node-event'; const _mat4_temp = new Mat4(); const _vec2_temp = new Vec2(); @@ -229,8 +230,8 @@ export class TiledLayer extends Renderable2D { this._positionToRowCol(_vec2_temp.x, _vec2_temp.y, _tempRowCol); this._addUserNodeToGrid(dataComp, _tempRowCol); this._updateCullingOffsetByUserNode(node); - node.on(SystemEventType.TRANSFORM_CHANGED, this._userNodePosChange, dataComp); - node.on(SystemEventType.SIZE_CHANGED, this._userNodeSizeChange, dataComp); + node.on(NodeEventType.TRANSFORM_CHANGED, this._userNodePosChange, dataComp); + node.on(NodeEventType.SIZE_CHANGED, this._userNodeSizeChange, dataComp); return true; } @@ -247,8 +248,8 @@ export class TiledLayer extends Renderable2D { warn('CCTiledLayer:removeUserNode node is not exist'); return false; } - node.off(SystemEventType.TRANSFORM_CHANGED, this._userNodePosChange, dataComp); - node.off(SystemEventType.SIZE_CHANGED, this._userNodeSizeChange, dataComp); + node.off(NodeEventType.TRANSFORM_CHANGED, this._userNodePosChange, dataComp); + node.off(NodeEventType.SIZE_CHANGED, this._userNodeSizeChange, dataComp); this._removeUserNodeFromGrid(dataComp); delete this._userNodeMap[node.uuid]; node._removeComponent(dataComp); @@ -394,11 +395,11 @@ export class TiledLayer extends Renderable2D { onEnable () { super.onEnable(); - this.node.on(SystemEventType.ANCHOR_CHANGED, this._syncAnchorPoint, this); - this.node.on(SystemEventType.TRANSFORM_CHANGED, this.updateCulling, this); - this.node.on(SystemEventType.SIZE_CHANGED, this.updateCulling, this); - this.node.parent!.on(SystemEventType.TRANSFORM_CHANGED, this.updateCulling, this); - this.node.parent!.on(SystemEventType.SIZE_CHANGED, this.updateCulling, this); + this.node.on(NodeEventType.ANCHOR_CHANGED, this._syncAnchorPoint, this); + this.node.on(NodeEventType.TRANSFORM_CHANGED, this.updateCulling, this); + this.node.on(NodeEventType.SIZE_CHANGED, this.updateCulling, this); + this.node.parent!.on(NodeEventType.TRANSFORM_CHANGED, this.updateCulling, this); + this.node.parent!.on(NodeEventType.SIZE_CHANGED, this.updateCulling, this); this.markForUpdateRenderData(); // delay 1 frame, since camera's matrix data is dirty this.scheduleOnce(this.updateCulling.bind(this)); @@ -406,11 +407,11 @@ export class TiledLayer extends Renderable2D { onDisable () { super.onDisable(); - this.node.parent!.off(SystemEventType.SIZE_CHANGED, this.updateCulling, this); - this.node.parent!.off(SystemEventType.TRANSFORM_CHANGED, this.updateCulling, this); - this.node.off(SystemEventType.SIZE_CHANGED, this.updateCulling, this); - this.node.off(SystemEventType.TRANSFORM_CHANGED, this.updateCulling, this); - this.node.off(SystemEventType.ANCHOR_CHANGED, this._syncAnchorPoint, this); + this.node.parent!.off(NodeEventType.SIZE_CHANGED, this.updateCulling, this); + this.node.parent!.off(NodeEventType.TRANSFORM_CHANGED, this.updateCulling, this); + this.node.off(NodeEventType.SIZE_CHANGED, this.updateCulling, this); + this.node.off(NodeEventType.TRANSFORM_CHANGED, this.updateCulling, this); + this.node.off(NodeEventType.ANCHOR_CHANGED, this._syncAnchorPoint, this); } protected _syncAnchorPoint () { diff --git a/cocos/tiledmap/tiled-map.ts b/cocos/tiledmap/tiled-map.ts index 28caec91d29..26d884b8990 100644 --- a/cocos/tiledmap/tiled-map.ts +++ b/cocos/tiledmap/tiled-map.ts @@ -40,8 +40,9 @@ import { TiledObjectGroup } from './tiled-object-group'; import { TiledMapAsset } from './tiled-map-asset'; import { Sprite } from '../2d/components/sprite'; import { fillTextureGrids, loadAllTextures } from './tiled-utils'; -import { Size, SystemEventType, Vec2, Node, logID, Color, sys } from '../core'; +import { Size, Vec2, Node, logID, Color, sys } from '../core'; import { SpriteFrame } from '../2d/assets'; +import { NodeEventType } from '../core/scene-graph/node-event'; interface ImageExtendedNode extends Node { layerInfo: TMXImageLayerInfo; @@ -315,11 +316,11 @@ export class TiledMap extends Component { } onEnable () { - this.node.on(SystemEventType.ANCHOR_CHANGED, this._syncAnchorPoint, this); + this.node.on(NodeEventType.ANCHOR_CHANGED, this._syncAnchorPoint, this); } onDisable () { - this.node.off(SystemEventType.ANCHOR_CHANGED, this._syncAnchorPoint, this); + this.node.off(NodeEventType.ANCHOR_CHANGED, this._syncAnchorPoint, this); } _applyFile () { diff --git a/cocos/tiledmap/tiled-tile.ts b/cocos/tiledmap/tiled-tile.ts index e866b194b00..97ee5001818 100644 --- a/cocos/tiledmap/tiled-tile.ts +++ b/cocos/tiledmap/tiled-tile.ts @@ -39,14 +39,17 @@ * @extends Component */ -import { ccclass, help, menu, type } from 'cc.decorator'; +import { ccclass, executeInEditMode, help, menu, requireComponent, type } from 'cc.decorator'; import { Component } from '../core/components'; import { TiledLayer } from './tiled-layer'; import { CCInteger, warn } from '../core'; +import { UITransform } from '../2d/framework'; @ccclass('cc.TiledTile') @help('i18n:cc.TiledTile') @menu('TiledMap/TiledTile') +@requireComponent(UITransform) +@executeInEditMode export class TiledTile extends Component { _layer: TiledLayer | null = null; diff --git a/cocos/tiledmap/tmx-xml-parser.ts b/cocos/tiledmap/tmx-xml-parser.ts index a69a58775bf..8b54daa8acd 100644 --- a/cocos/tiledmap/tmx-xml-parser.ts +++ b/cocos/tiledmap/tmx-xml-parser.ts @@ -614,46 +614,46 @@ export class TMXMapInfo { } for (i = 0; i < tilesets.length; i++) { - const selTileset = tilesets[i]; + const curTileset = tilesets[i]; // If this is an external tileset then start parsing that - const tsxName = selTileset.getAttribute('source'); + const tsxName = curTileset.getAttribute('source'); if (tsxName) { - const currentFirstGID = parseInt(selTileset.getAttribute('firstgid')!); + const currentFirstGID = parseInt(curTileset.getAttribute('firstgid')!); const tsxXmlString = this._tsxContentMap![tsxName]; if (tsxXmlString) { this.parseXMLString(tsxXmlString, currentFirstGID); } } else { - const images = selTileset.getElementsByTagName('image'); - const collection = images.length > 1; - const firstImage = images[0]; - let firstImageName: string = firstImage.getAttribute('source')!; - firstImageName = firstImageName.replace(/\\/g, '/'); - - const tiles = selTileset.getElementsByTagName('tile'); + const tiles = curTileset.getElementsByTagName('tile'); const tileCount = tiles && tiles.length || 1; let tile: Element | null = null; - const tilesetName = selTileset.getAttribute('name') || ''; - const tilesetSpacing = parseInt(selTileset.getAttribute('spacing')!) || 0; - const tilesetMargin = parseInt(selTileset.getAttribute('margin')!) || 0; - const fgid = tilesetFirstGid || (parseInt(selTileset.getAttribute('firstgid')!) || 0); + const tilesetName = curTileset.getAttribute('name') || ''; + const tilesetSpacing = parseInt(curTileset.getAttribute('spacing')!) || 0; + const tilesetMargin = parseInt(curTileset.getAttribute('margin')!) || 0; + const fgid = tilesetFirstGid || (parseInt(curTileset.getAttribute('firstgid')!) || 0); const tilesetSize = new Size(0, 0); - tilesetSize.width = parseFloat(selTileset.getAttribute('tilewidth')!); - tilesetSize.height = parseFloat(selTileset.getAttribute('tileheight')!); + tilesetSize.width = parseFloat(curTileset.getAttribute('tilewidth')!); + tilesetSize.height = parseFloat(curTileset.getAttribute('tileheight')!); // parse tile offset - const firstTileOffset = selTileset.getElementsByTagName('tileoffset')[0]; + const curTileOffset = curTileset.getElementsByTagName('tileoffset')[0]; let tileOffsetX = 0; let tileOffsetY = 0; - if (firstTileOffset) { - tileOffsetX = parseFloat(firstTileOffset.getAttribute('x')!) || 0; - tileOffsetY = parseFloat(firstTileOffset.getAttribute('y')!) || 0; + if (curTileOffset) { + tileOffsetX = parseFloat(curTileOffset.getAttribute('x')!) || 0; + tileOffsetY = parseFloat(curTileOffset.getAttribute('y')!) || 0; } + const images = curTileset.getElementsByTagName('image'); + const collection = images.length > 1; let tileset: TMXTilesetInfo | null = null; for (let tileIdx = 0; tileIdx < tileCount; tileIdx++) { + const curImage = images[tileIdx]; + let curImageName: string = curImage.getAttribute('source')!; + curImageName = curImageName.replace(/\\/g, '/'); + if (!tileset || collection) { tileset = new TMXTilesetInfo(); tileset.name = tilesetName; @@ -662,33 +662,31 @@ export class TMXMapInfo { tileset.tileOffset.y = tileOffsetY; tileset.collection = collection; - if (!collection) { - tileset.imageName = firstImageName; - tileset.imageSize.width = parseFloat(firstImage.getAttribute('width')!) || 0; - tileset.imageSize.height = parseFloat(firstImage.getAttribute('height')!) || 0; - tileset.sourceImage = this._spriteFrameMap![firstImageName]; + + // set multi-sprite frame for tilesets + tileset.spacing = tilesetSpacing; + tileset.margin = tilesetMargin; + tileset.imageName = curImageName; + tileset.sourceImage = this._spriteFrameMap![curImageName]; + if (!tileset.sourceImage) { + const nameWithPostfix = TMXMapInfo.getNameWithPostfix(curImageName); + tileset.imageName = nameWithPostfix; + tileset.sourceImage = this._spriteFrameMap![nameWithPostfix]; if (!tileset.sourceImage) { - const nameWithPostfix = TMXMapInfo.getNameWithPostfix(firstImageName); - tileset.imageName = nameWithPostfix; - tileset.sourceImage = this._spriteFrameMap![nameWithPostfix]; + const shortName = TMXMapInfo.getShortName(curImageName); + tileset.imageName = shortName; + tileset.sourceImage = this._spriteFrameMap![shortName]; if (!tileset.sourceImage) { - const shortName = TMXMapInfo.getShortName(firstImageName); - tileset.imageName = shortName; - tileset.sourceImage = this._spriteFrameMap![shortName]; - if (!tileset.sourceImage) { - console.error(`[error]: ${shortName} not find in [${Object.keys(this._spriteFrameMap!).join(', ')}]`); - errorID(7221, firstImageName); - console.warn(`Please try asset type of ${firstImageName} to 'sprite-frame'`); - } + console.error(`[error]: ${shortName} not find in [${Object.keys(this._spriteFrameMap!).join(', ')}]`); + errorID(7221, curImageName); + console.warn(`Please try asset type of ${curImageName} to 'sprite-frame'`); } } } - - tileset.spacing = tilesetSpacing; - tileset.margin = tilesetMargin; + tileset.imageSize.width = parseFloat(curImage.getAttribute('width')!) || 0; + tileset.imageSize.height = parseFloat(curImage.getAttribute('height')!) || 0; tileset._tileSize.width = tilesetSize.width; tileset._tileSize.height = tilesetSize.height; - this.setTilesets(tileset); } @@ -713,7 +711,7 @@ export class TMXMapInfo { tileset.sourceImage = this._spriteFrameMap![imageName]; if (!tileset.sourceImage) { - const nameWithPostfix = TMXMapInfo.getNameWithPostfix(firstImageName); + const nameWithPostfix = TMXMapInfo.getNameWithPostfix(curImageName); tileset.imageName = nameWithPostfix; tileset.sourceImage = this._spriteFrameMap![nameWithPostfix]; if (!tileset.sourceImage) { diff --git a/cocos/ui/block-input-events.ts b/cocos/ui/block-input-events.ts index c4cb900d1fd..09e891a3f90 100644 --- a/cocos/ui/block-input-events.ts +++ b/cocos/ui/block-input-events.ts @@ -32,11 +32,11 @@ import { ccclass, help, menu } from 'cc.decorator'; import { Component } from '../core/components/component'; import { Event } from '../core/event'; -import { SystemEventType } from '../core/platform/event-manager/event-enum'; +import { NodeEventType } from '../core/scene-graph/node-event'; -const BlockEvents = [SystemEventType.TOUCH_START, SystemEventType.TOUCH_END, SystemEventType.TOUCH_MOVE, - SystemEventType.MOUSE_DOWN, SystemEventType.MOUSE_MOVE, SystemEventType.MOUSE_UP, - SystemEventType.MOUSE_ENTER, SystemEventType.MOUSE_LEAVE, SystemEventType.MOUSE_WHEEL]; +const BlockEvents = [NodeEventType.TOUCH_START, NodeEventType.TOUCH_END, NodeEventType.TOUCH_MOVE, + NodeEventType.MOUSE_DOWN, NodeEventType.MOUSE_MOVE, NodeEventType.MOUSE_UP, + NodeEventType.MOUSE_ENTER, NodeEventType.MOUSE_LEAVE, NodeEventType.MOUSE_WHEEL]; function stopPropagation (event: Event) { event.propagationStopped = true; diff --git a/cocos/ui/button.ts b/cocos/ui/button.ts index ea92491e30b..16e4fab3ef1 100644 --- a/cocos/ui/button.ts +++ b/cocos/ui/button.ts @@ -34,7 +34,7 @@ import { EDITOR } from 'internal:constants'; import { SpriteFrame } from '../2d/assets'; import { Component, EventHandler as ComponentEventHandler } from '../core/components'; import { UITransform, Renderable2D } from '../2d/framework'; -import { EventMouse, EventTouch, SystemEventType } from '../core/platform'; +import { EventMouse, EventTouch } from '../core/platform'; import { Color, Vec3 } from '../core/math'; import { ccenum } from '../core/value-types/enum'; import { lerp } from '../core/math/utils'; @@ -42,6 +42,7 @@ import { Node } from '../core/scene-graph/node'; import { Sprite } from '../2d/components/sprite'; import { legacyCC } from '../core/global-exports'; import { TransformBit } from '../core/scene-graph/node-enum'; +import { NodeEventType } from '../core/scene-graph/node-event'; const _tempColor = new Color(); @@ -672,39 +673,39 @@ export class Button extends Component { } protected _registerNodeEvent () { - this.node.on(SystemEventType.TOUCH_START, this._onTouchBegan, this); - this.node.on(SystemEventType.TOUCH_MOVE, this._onTouchMove, this); - this.node.on(SystemEventType.TOUCH_END, this._onTouchEnded, this); - this.node.on(SystemEventType.TOUCH_CANCEL, this._onTouchCancel, this); + this.node.on(NodeEventType.TOUCH_START, this._onTouchBegan, this); + this.node.on(NodeEventType.TOUCH_MOVE, this._onTouchMove, this); + this.node.on(NodeEventType.TOUCH_END, this._onTouchEnded, this); + this.node.on(NodeEventType.TOUCH_CANCEL, this._onTouchCancel, this); - this.node.on(SystemEventType.MOUSE_ENTER, this._onMouseMoveIn, this); - this.node.on(SystemEventType.MOUSE_LEAVE, this._onMouseMoveOut, this); + this.node.on(NodeEventType.MOUSE_ENTER, this._onMouseMoveIn, this); + this.node.on(NodeEventType.MOUSE_LEAVE, this._onMouseMoveOut, this); } protected _registerTargetEvent (target) { if (EDITOR && !legacyCC.GAME_VIEW) { target.on(Sprite.EventType.SPRITE_FRAME_CHANGED, this._onTargetSpriteFrameChanged, this); - target.on(SystemEventType.COLOR_CHANGED, this._onTargetColorChanged, this); + target.on(NodeEventType.COLOR_CHANGED, this._onTargetColorChanged, this); } - target.on(SystemEventType.TRANSFORM_CHANGED, this._onTargetTransformChanged, this); + target.on(NodeEventType.TRANSFORM_CHANGED, this._onTargetTransformChanged, this); } protected _unregisterNodeEvent () { - this.node.off(SystemEventType.TOUCH_START, this._onTouchBegan, this); - this.node.off(SystemEventType.TOUCH_MOVE, this._onTouchMove, this); - this.node.off(SystemEventType.TOUCH_END, this._onTouchEnded, this); - this.node.off(SystemEventType.TOUCH_CANCEL, this._onTouchCancel, this); + this.node.off(NodeEventType.TOUCH_START, this._onTouchBegan, this); + this.node.off(NodeEventType.TOUCH_MOVE, this._onTouchMove, this); + this.node.off(NodeEventType.TOUCH_END, this._onTouchEnded, this); + this.node.off(NodeEventType.TOUCH_CANCEL, this._onTouchCancel, this); - this.node.off(SystemEventType.MOUSE_ENTER, this._onMouseMoveIn, this); - this.node.off(SystemEventType.MOUSE_LEAVE, this._onMouseMoveOut, this); + this.node.off(NodeEventType.MOUSE_ENTER, this._onMouseMoveIn, this); + this.node.off(NodeEventType.MOUSE_LEAVE, this._onMouseMoveOut, this); } protected _unregisterTargetEvent (target) { if (EDITOR && !legacyCC.GAME_VIEW) { target.off(Sprite.EventType.SPRITE_FRAME_CHANGED); - target.off(SystemEventType.COLOR_CHANGED); + target.off(NodeEventType.COLOR_CHANGED); } - target.off(SystemEventType.TRANSFORM_CHANGED); + target.off(NodeEventType.TRANSFORM_CHANGED); } protected _getTargetSprite (target: Node | null) { diff --git a/cocos/ui/editbox/edit-box.ts b/cocos/ui/editbox/edit-box.ts index 067859c058e..d43739a1108 100644 --- a/cocos/ui/editbox/edit-box.ts +++ b/cocos/ui/editbox/edit-box.ts @@ -37,7 +37,6 @@ import { Component } from '../../core/components/component'; import { EventHandler as ComponentEventHandler } from '../../core/components/component-event-handler'; import { Color, Size, Vec3 } from '../../core/math'; import { EventTouch } from '../../core/platform'; -import { SystemEventType } from '../../core/platform/event-manager/event-enum'; import { Node } from '../../core/scene-graph/node'; import { Label, VerticalTextAlignment } from '../../2d/components/label'; import { Sprite } from '../../2d/components/sprite'; @@ -46,6 +45,7 @@ import { EditBoxImplBase } from './edit-box-impl-base'; import { InputFlag, InputMode, KeyboardReturnType } from './types'; import { sys } from '../../core/platform/sys'; import { legacyCC } from '../../core/global-exports'; +import { NodeEventType } from '../../core/scene-graph/node-event'; const LEFT_PADDING = 2; @@ -511,7 +511,7 @@ export class EditBox extends Component { this._updatePlaceholderLabel(); this._updateTextLabel(); this._isLabelVisible = true; - this.node.on(SystemEventType.SIZE_CHANGED, this._resizeChildNodes, this); + this.node.on(NodeEventType.SIZE_CHANGED, this._resizeChildNodes, this); const impl = this._impl = new EditBox._EditBoxImpl(); impl.init(this); @@ -657,13 +657,13 @@ export class EditBox extends Component { } protected _registerEvent () { - this.node.on(SystemEventType.TOUCH_START, this._onTouchBegan, this); - this.node.on(SystemEventType.TOUCH_END, this._onTouchEnded, this); + this.node.on(NodeEventType.TOUCH_START, this._onTouchBegan, this); + this.node.on(NodeEventType.TOUCH_END, this._onTouchEnded, this); } protected _unregisterEvent () { - this.node.off(SystemEventType.TOUCH_START, this._onTouchBegan, this); - this.node.off(SystemEventType.TOUCH_END, this._onTouchEnded, this); + this.node.off(NodeEventType.TOUCH_START, this._onTouchBegan, this); + this.node.off(NodeEventType.TOUCH_END, this._onTouchEnded, this); } protected _updateLabelPosition (size: Size) { diff --git a/cocos/ui/layout.ts b/cocos/ui/layout.ts index fe66fa3fe86..d990c071391 100644 --- a/cocos/ui/layout.ts +++ b/cocos/ui/layout.ts @@ -34,12 +34,11 @@ import { Component } from '../core/components/component'; import { Rect, Size, Vec2, Vec3 } from '../core/math'; import { ccenum } from '../core/value-types/enum'; import { UITransform } from '../2d/framework/ui-transform'; -import { SystemEventType } from '../core/platform/event-manager/event-enum'; import { director, Director } from '../core/director'; import { TransformBit } from '../core/scene-graph/node-enum'; import { Node, warn } from '../core'; +import { NodeEventType } from '../core/scene-graph/node-event'; -const NodeEvent = SystemEventType; /** * @en Layout type. * @@ -712,22 +711,22 @@ export class Layout extends Component { protected _addEventListeners () { director.on(Director.EVENT_AFTER_UPDATE, this.updateLayout, this); - this.node.on(NodeEvent.SIZE_CHANGED, this._resized, this); - this.node.on(NodeEvent.ANCHOR_CHANGED, this._doLayoutDirty, this); - this.node.on(NodeEvent.CHILD_ADDED, this._childAdded, this); - this.node.on(NodeEvent.CHILD_REMOVED, this._childRemoved, this); - this.node.on(NodeEvent.SIBLING_ORDER_CHANGED, this._childrenChanged, this); + this.node.on(NodeEventType.SIZE_CHANGED, this._resized, this); + this.node.on(NodeEventType.ANCHOR_CHANGED, this._doLayoutDirty, this); + this.node.on(NodeEventType.CHILD_ADDED, this._childAdded, this); + this.node.on(NodeEventType.CHILD_REMOVED, this._childRemoved, this); + this.node.on(NodeEventType.SIBLING_ORDER_CHANGED, this._childrenChanged, this); this.node.on('childrenSiblingOrderChanged', this.updateLayout, this); this._addChildrenEventListeners(); } protected _removeEventListeners () { director.off(Director.EVENT_AFTER_UPDATE, this.updateLayout, this); - this.node.off(NodeEvent.SIZE_CHANGED, this._resized, this); - this.node.off(NodeEvent.ANCHOR_CHANGED, this._doLayoutDirty, this); - this.node.off(NodeEvent.CHILD_ADDED, this._childAdded, this); - this.node.off(NodeEvent.CHILD_REMOVED, this._childRemoved, this); - this.node.off(NodeEvent.SIBLING_ORDER_CHANGED, this._childrenChanged, this); + this.node.off(NodeEventType.SIZE_CHANGED, this._resized, this); + this.node.off(NodeEventType.ANCHOR_CHANGED, this._doLayoutDirty, this); + this.node.off(NodeEventType.CHILD_ADDED, this._childAdded, this); + this.node.off(NodeEventType.CHILD_REMOVED, this._childRemoved, this); + this.node.off(NodeEventType.SIBLING_ORDER_CHANGED, this._childrenChanged, this); this.node.off('childrenSiblingOrderChanged', this.updateLayout, this); this._removeChildrenEventListeners(); } @@ -736,9 +735,9 @@ export class Layout extends Component { const children = this.node.children; for (let i = 0; i < children.length; ++i) { const child = children[i]; - child.on(NodeEvent.SIZE_CHANGED, this._doLayoutDirty, this); - child.on(NodeEvent.TRANSFORM_CHANGED, this._transformDirty, this); - child.on(NodeEvent.ANCHOR_CHANGED, this._doLayoutDirty, this); + child.on(NodeEventType.SIZE_CHANGED, this._doLayoutDirty, this); + child.on(NodeEventType.TRANSFORM_CHANGED, this._transformDirty, this); + child.on(NodeEventType.ANCHOR_CHANGED, this._doLayoutDirty, this); child.on('active-in-hierarchy-changed', this._childrenChanged, this); } } @@ -747,25 +746,25 @@ export class Layout extends Component { const children = this.node.children; for (let i = 0; i < children.length; ++i) { const child = children[i]; - child.off(NodeEvent.SIZE_CHANGED, this._doLayoutDirty, this); - child.off(NodeEvent.TRANSFORM_CHANGED, this._transformDirty, this); - child.off(NodeEvent.ANCHOR_CHANGED, this._doLayoutDirty, this); + child.off(NodeEventType.SIZE_CHANGED, this._doLayoutDirty, this); + child.off(NodeEventType.TRANSFORM_CHANGED, this._transformDirty, this); + child.off(NodeEventType.ANCHOR_CHANGED, this._doLayoutDirty, this); child.off('active-in-hierarchy-changed', this._childrenChanged, this); } } protected _childAdded (child: Node) { - child.on(NodeEvent.SIZE_CHANGED, this._doLayoutDirty, this); - child.on(NodeEvent.TRANSFORM_CHANGED, this._transformDirty, this); - child.on(NodeEvent.ANCHOR_CHANGED, this._doLayoutDirty, this); + child.on(NodeEventType.SIZE_CHANGED, this._doLayoutDirty, this); + child.on(NodeEventType.TRANSFORM_CHANGED, this._transformDirty, this); + child.on(NodeEventType.ANCHOR_CHANGED, this._doLayoutDirty, this); child.on('active-in-hierarchy-changed', this._childrenChanged, this); this._childrenChanged(); } protected _childRemoved (child: Node) { - child.off(NodeEvent.SIZE_CHANGED, this._doLayoutDirty, this); - child.off(NodeEvent.TRANSFORM_CHANGED, this._transformDirty, this); - child.off(NodeEvent.ANCHOR_CHANGED, this._doLayoutDirty, this); + child.off(NodeEventType.SIZE_CHANGED, this._doLayoutDirty, this); + child.off(NodeEventType.TRANSFORM_CHANGED, this._transformDirty, this); + child.off(NodeEventType.ANCHOR_CHANGED, this._doLayoutDirty, this); child.off('active-in-hierarchy-changed', this._childrenChanged, this); this._childrenChanged(); } @@ -965,7 +964,7 @@ export class Layout extends Component { return containerResizeBoundary; } - protected _doLayoutGridAxisHorizontal (layoutAnchor: Vec2, layoutSize: Size) { + protected _doLayoutGridAxisHorizontal (layoutAnchor: Readonly, layoutSize: Size) { const baseWidth = layoutSize.width; let sign = 1; @@ -998,7 +997,7 @@ export class Layout extends Component { } } - protected _doLayoutGridAxisVertical (layoutAnchor: Vec2, layoutSize: Size) { + protected _doLayoutGridAxisVertical (layoutAnchor: Readonly, layoutSize: Size) { const baseHeight = layoutSize.height; let sign = 1; diff --git a/cocos/ui/page-view.ts b/cocos/ui/page-view.ts index 41118d16ab0..8bb220932e9 100644 --- a/cocos/ui/page-view.ts +++ b/cocos/ui/page-view.ts @@ -31,7 +31,7 @@ import { ccclass, help, executionOrder, menu, tooltip, type, slide, range, visible, override, serializable, editable } from 'cc.decorator'; import { EDITOR } from 'internal:constants'; import { EventHandler as ComponentEventHandler } from '../core/components'; -import { EventTouch, SystemEventType } from '../core/platform'; +import { EventTouch } from '../core/platform'; import { Vec2, Vec3 } from '../core/math'; import { ccenum } from '../core/value-types/enum'; import { Layout } from './layout'; @@ -42,6 +42,7 @@ import { warnID, logID } from '../core/platform/debug'; import { extendsEnum } from '../core/data/utils/extends-enum'; import { Node } from '../core/scene-graph'; import { legacyCC } from '../core/global-exports'; +import { NodeEventType } from '../core/scene-graph/node-event'; const _tempVec2 = new Vec2(); @@ -324,7 +325,7 @@ export class PageView extends ScrollView { public onEnable () { super.onEnable(); - this.node.on(SystemEventType.SIZE_CHANGED, this._updateAllPagesSize, this); + this.node.on(NodeEventType.SIZE_CHANGED, this._updateAllPagesSize, this); if (!EDITOR || legacyCC.GAME_VIEW) { this.node.on(PageView.EventType.SCROLL_ENG_WITH_THRESHOLD, this._dispatchPageTurningEvent, this); } @@ -332,7 +333,7 @@ export class PageView extends ScrollView { public onDisable () { super.onDisable(); - this.node.off(SystemEventType.SIZE_CHANGED, this._updateAllPagesSize, this); + this.node.off(NodeEventType.SIZE_CHANGED, this._updateAllPagesSize, this); if (!EDITOR || legacyCC.GAME_VIEW) { this.node.off(PageView.EventType.SCROLL_ENG_WITH_THRESHOLD, this._dispatchPageTurningEvent, this); } @@ -629,7 +630,7 @@ export class PageView extends ScrollView { // 初始化页面 protected _initPages () { if (!this.content) { return; } - this._initContentPos = this.content.position; + this._initContentPos = this.content.position as Vec3; const children = this.content.children; for (let i = 0; i < children.length; ++i) { const page = children[i]; diff --git a/cocos/ui/scroll-bar.ts b/cocos/ui/scroll-bar.ts index 82140ce5440..6ffbd4978f0 100644 --- a/cocos/ui/scroll-bar.ts +++ b/cocos/ui/scroll-bar.ts @@ -231,7 +231,7 @@ export class ScrollBar extends Component { * * @param outOfBoundary - 滚动位移。 */ - public onScroll (outOfBoundary: Vec2) { + public onScroll (outOfBoundary: Readonly) { if (!this._scrollView) { return; } diff --git a/cocos/ui/scroll-view.ts b/cocos/ui/scroll-view.ts index 9c40b2a40cc..694bf2b3bed 100644 --- a/cocos/ui/scroll-view.ts +++ b/cocos/ui/scroll-view.ts @@ -43,6 +43,8 @@ import { Node } from '../core/scene-graph/node'; import { director, Director } from '../core/director'; import { TransformBit } from '../core/scene-graph/node-enum'; import { legacyCC } from '../core/global-exports'; +import { NodeEventType } from '../core/scene-graph/node-event'; +import { TouchEvent } from '../core/platform/event-manager/event-enum'; const NUMBER_OF_GATHERED_TOUCHES_FOR_MOVE_SPEED = 5; const OUT_OF_BOUNDARY_BREAKING_FACTOR = 0.05; @@ -891,9 +893,9 @@ export class ScrollView extends ViewGroup { return this._getContentPosition(); } - private _getContentPosition () { + private _getContentPosition (): Vec3 { if (!this._content) { - return Vec3.ZERO; + return Vec3.ZERO.clone(); } this._contentPos.set(this._content.position); @@ -943,11 +945,11 @@ export class ScrollView extends ViewGroup { if (!EDITOR || legacyCC.GAME_VIEW) { this._registerEvent(); if (this._content) { - this._content.on(Node.EventType.SIZE_CHANGED, this._calculateBoundary, this); - this._content.on(Node.EventType.TRANSFORM_CHANGED, this._scaleChanged, this); + this._content.on(NodeEventType.SIZE_CHANGED, this._calculateBoundary, this); + this._content.on(NodeEventType.TRANSFORM_CHANGED, this._scaleChanged, this); if (this.view) { - this.view.node.on(Node.EventType.TRANSFORM_CHANGED, this._scaleChanged, this); - this.view.node.on(Node.EventType.SIZE_CHANGED, this._calculateBoundary, this); + this.view.node.on(NodeEventType.TRANSFORM_CHANGED, this._scaleChanged, this); + this.view.node.on(NodeEventType.SIZE_CHANGED, this._calculateBoundary, this); } } @@ -966,11 +968,11 @@ export class ScrollView extends ViewGroup { if (!EDITOR || legacyCC.GAME_VIEW) { this._unregisterEvent(); if (this._content) { - this._content.off(Node.EventType.SIZE_CHANGED, this._calculateBoundary, this); - this._content.off(Node.EventType.TRANSFORM_CHANGED, this._scaleChanged, this); + this._content.off(NodeEventType.SIZE_CHANGED, this._calculateBoundary, this); + this._content.off(NodeEventType.TRANSFORM_CHANGED, this._scaleChanged, this); if (this.view) { - this.view.node.off(Node.EventType.TRANSFORM_CHANGED, this._scaleChanged, this); - this.view.node.off(Node.EventType.SIZE_CHANGED, this._calculateBoundary, this); + this.view.node.off(NodeEventType.TRANSFORM_CHANGED, this._scaleChanged, this); + this.view.node.off(NodeEventType.SIZE_CHANGED, this._calculateBoundary, this); } } } @@ -980,19 +982,19 @@ export class ScrollView extends ViewGroup { // private methods protected _registerEvent () { - this.node.on(Node.EventType.TOUCH_START, this._onTouchBegan, this, true); - this.node.on(Node.EventType.TOUCH_MOVE, this._onTouchMoved, this, true); - this.node.on(Node.EventType.TOUCH_END, this._onTouchEnded, this, true); - this.node.on(Node.EventType.TOUCH_CANCEL, this._onTouchCancelled, this, true); - this.node.on(Node.EventType.MOUSE_WHEEL, this._onMouseWheel, this, true); + this.node.on(NodeEventType.TOUCH_START, this._onTouchBegan, this, true); + this.node.on(NodeEventType.TOUCH_MOVE, this._onTouchMoved, this, true); + this.node.on(NodeEventType.TOUCH_END, this._onTouchEnded, this, true); + this.node.on(NodeEventType.TOUCH_CANCEL, this._onTouchCancelled, this, true); + this.node.on(NodeEventType.MOUSE_WHEEL, this._onMouseWheel, this, true); } protected _unregisterEvent () { - this.node.off(Node.EventType.TOUCH_START, this._onTouchBegan, this, true); - this.node.off(Node.EventType.TOUCH_MOVE, this._onTouchMoved, this, true); - this.node.off(Node.EventType.TOUCH_END, this._onTouchEnded, this, true); - this.node.off(Node.EventType.TOUCH_CANCEL, this._onTouchCancelled, this, true); - this.node.off(Node.EventType.MOUSE_WHEEL, this._onMouseWheel, this, true); + this.node.off(NodeEventType.TOUCH_START, this._onTouchBegan, this, true); + this.node.off(NodeEventType.TOUCH_MOVE, this._onTouchMoved, this, true); + this.node.off(NodeEventType.TOUCH_END, this._onTouchEnded, this, true); + this.node.off(NodeEventType.TOUCH_CANCEL, this._onTouchCancelled, this, true); + this.node.off(NodeEventType.MOUSE_WHEEL, this._onMouseWheel, this, true); } protected _onMouseWheel (event: EventMouse, captureListeners?: Node[]) { @@ -1053,8 +1055,7 @@ export class ScrollView extends ViewGroup { if (deltaMove.length() > 7) { if (!this._touchMoved && event.target !== this.node) { // Simulate touch cancel for target node - const cancelEvent = new EventTouch(event.getTouches(), event.bubbles); - cancelEvent.type = Node.EventType.TOUCH_CANCEL; + const cancelEvent = new EventTouch(event.getTouches(), event.bubbles, TouchEvent.TOUCH_CANCEL); cancelEvent.touch = event.touch; cancelEvent.simulate = true; (event.target as Node).dispatchEvent(cancelEvent); @@ -1324,7 +1325,7 @@ export class ScrollView extends ViewGroup { return outOfBoundaryAmount; } - protected _updateScrollBar (outOfBoundary: Vec2) { + protected _updateScrollBar (outOfBoundary: Readonly) { if (this._horizontalScrollBar) { this._horizontalScrollBar.onScroll(outOfBoundary); } diff --git a/cocos/ui/slider.ts b/cocos/ui/slider.ts index 4f0de2c7ca0..8662ecd9cd4 100644 --- a/cocos/ui/slider.ts +++ b/cocos/ui/slider.ts @@ -33,12 +33,13 @@ import { ccclass, help, executionOrder, menu, requireComponent, tooltip, type, s import { EDITOR } from 'internal:constants'; import { Component, EventHandler } from '../core/components'; import { UITransform } from '../2d/framework'; -import { EventTouch, SystemEventType, Touch } from '../core/platform'; +import { EventTouch, Touch } from '../core/platform'; import { Vec3 } from '../core/math'; import { ccenum } from '../core/value-types/enum'; import { clamp01 } from '../core/math/utils'; import { Sprite } from '../2d/components/sprite'; import { legacyCC } from '../core/global-exports'; +import { NodeEventType } from '../core/scene-graph/node-event'; const _tempPos = new Vec3(); /** @@ -186,26 +187,26 @@ export class Slider extends Component { public onEnable () { this._updateHandlePosition(); - this.node.on(SystemEventType.TOUCH_START, this._onTouchBegan, this); - this.node.on(SystemEventType.TOUCH_MOVE, this._onTouchMoved, this); - this.node.on(SystemEventType.TOUCH_END, this._onTouchEnded, this); - this.node.on(SystemEventType.TOUCH_CANCEL, this._onTouchCancelled, this); + this.node.on(NodeEventType.TOUCH_START, this._onTouchBegan, this); + this.node.on(NodeEventType.TOUCH_MOVE, this._onTouchMoved, this); + this.node.on(NodeEventType.TOUCH_END, this._onTouchEnded, this); + this.node.on(NodeEventType.TOUCH_CANCEL, this._onTouchCancelled, this); if (this._handle && this._handle.isValid) { - this._handle.node.on(SystemEventType.TOUCH_START, this._onHandleDragStart, this); - this._handle.node.on(SystemEventType.TOUCH_MOVE, this._onTouchMoved, this); - this._handle.node.on(SystemEventType.TOUCH_END, this._onTouchEnded, this); + this._handle.node.on(NodeEventType.TOUCH_START, this._onHandleDragStart, this); + this._handle.node.on(NodeEventType.TOUCH_MOVE, this._onTouchMoved, this); + this._handle.node.on(NodeEventType.TOUCH_END, this._onTouchEnded, this); } } public onDisable () { - this.node.off(SystemEventType.TOUCH_START, this._onTouchBegan, this); - this.node.off(SystemEventType.TOUCH_MOVE, this._onTouchMoved, this); - this.node.off(SystemEventType.TOUCH_END, this._onTouchEnded, this); - this.node.off(SystemEventType.TOUCH_CANCEL, this._onTouchCancelled, this); + this.node.off(NodeEventType.TOUCH_START, this._onTouchBegan, this); + this.node.off(NodeEventType.TOUCH_MOVE, this._onTouchMoved, this); + this.node.off(NodeEventType.TOUCH_END, this._onTouchEnded, this); + this.node.off(NodeEventType.TOUCH_CANCEL, this._onTouchCancelled, this); if (this._handle && this._handle.isValid) { - this._handle.node.off(SystemEventType.TOUCH_START, this._onHandleDragStart, this); - this._handle.node.off(SystemEventType.TOUCH_MOVE, this._onTouchMoved, this); - this._handle.node.off(SystemEventType.TOUCH_END, this._onTouchEnded, this); + this._handle.node.off(NodeEventType.TOUCH_START, this._onHandleDragStart, this); + this._handle.node.off(NodeEventType.TOUCH_MOVE, this._onTouchMoved, this); + this._handle.node.off(NodeEventType.TOUCH_END, this._onTouchEnded, this); } } diff --git a/cocos/ui/sub-context-view.ts b/cocos/ui/sub-context-view.ts index 3235aa7bc35..5ebadb91f29 100644 --- a/cocos/ui/sub-context-view.ts +++ b/cocos/ui/sub-context-view.ts @@ -39,10 +39,11 @@ import { UITransform } from '../2d/framework/ui-transform'; import { SpriteFrame } from '../2d/assets'; import { ImageAsset } from '../core/assets/image-asset'; -import { Rect, Size } from '../core/math'; +import { Size } from '../core/math'; import { legacyCC } from '../core/global-exports'; -import { CCObject, SystemEventType } from '../core'; +import { NodeEventType } from '../core/scene-graph/node-event'; +import { CCObject, Texture2D } from '../core'; /** * @en SubContextView is a view component which controls open data context viewport in WeChat game platform.
@@ -99,6 +100,7 @@ export class SubContextView extends Component { private _fps = 60; private _sprite: Sprite | null; private _imageAsset: ImageAsset; + private _texture: Texture2D; private _updatedTime = 0; private _updateInterval = 0; private _openDataContext: any; @@ -114,6 +116,7 @@ export class SubContextView extends Component { this._imageAsset = new ImageAsset(); this._openDataContext = null; this._updatedTime = performance.now(); + this._texture = new Texture2D(); } public onLoad () { @@ -151,7 +154,8 @@ export class SubContextView extends Component { const image = this._imageAsset; image.reset(sharedCanvas); - image._texture.create(sharedCanvas.width, sharedCanvas.height); + this._texture.image = image; + this._texture.create(sharedCanvas.width, sharedCanvas.height); this._sprite = this._content.getComponent(Sprite); if (!this._sprite) { @@ -159,10 +163,10 @@ export class SubContextView extends Component { } if (this._sprite.spriteFrame) { - this._sprite.spriteFrame.texture = this._imageAsset._texture; + this._sprite.spriteFrame.texture = this._texture; } else { const sp = new SpriteFrame(); - sp.texture = this._imageAsset._texture; + sp.texture = this._texture; this._sprite.spriteFrame = sp; } @@ -220,22 +224,22 @@ export class SubContextView extends Component { const sharedCanvas = this._openDataContext.canvas; img.reset(sharedCanvas); if (sharedCanvas.width > img.width || sharedCanvas.height > img.height) { - this._imageAsset._texture.create(sharedCanvas.width, sharedCanvas.height); + this._texture.create(sharedCanvas.width, sharedCanvas.height); } - this._imageAsset._texture.uploadData(sharedCanvas); + this._texture.uploadData(sharedCanvas); } private _registerNodeEvent () { - this.node.on(Node.EventType.TRANSFORM_CHANGED, this._updateSubContextView, this); - this.node.on(Node.EventType.SIZE_CHANGED, this._updateSubContextView, this); - this.node.on(SystemEventType.LAYER_CHANGED, this._updateContentLayer, this); + this.node.on(NodeEventType.TRANSFORM_CHANGED, this._updateSubContextView, this); + this.node.on(NodeEventType.SIZE_CHANGED, this._updateSubContextView, this); + this.node.on(NodeEventType.LAYER_CHANGED, this._updateContentLayer, this); } private _unregisterNodeEvent () { - this.node.off(Node.EventType.TRANSFORM_CHANGED, this._updateSubContextView, this); - this.node.off(Node.EventType.SIZE_CHANGED, this._updateSubContextView, this); - this.node.off(SystemEventType.LAYER_CHANGED, this._updateContentLayer, this); + this.node.off(NodeEventType.TRANSFORM_CHANGED, this._updateSubContextView, this); + this.node.off(NodeEventType.SIZE_CHANGED, this._updateSubContextView, this); + this.node.off(NodeEventType.LAYER_CHANGED, this._updateContentLayer, this); } private _updateContentLayer () { @@ -255,5 +259,13 @@ export class SubContextView extends Component { this._updateSubContextTexture(); } } + + public onDestroy () { + this._content.destroy(); + this._texture.destroy(); + if (this._sprite) { this._sprite.destroy(); } + this._imageAsset.destroy(); + this._openDataContext = null; + } } legacyCC.SubContextView = SubContextView; diff --git a/cocos/ui/toggle-container.ts b/cocos/ui/toggle-container.ts index 333e252fac5..082326fc619 100644 --- a/cocos/ui/toggle-container.ts +++ b/cocos/ui/toggle-container.ts @@ -33,7 +33,7 @@ import { ccclass, help, executeInEditMode, executionOrder, menu, tooltip, type, import { Component, EventHandler as ComponentEventHandler } from '../core/components'; import { Toggle } from './toggle'; import { legacyCC } from '../core/global-exports'; -import { SystemEventType } from '../core/platform/event-manager'; +import { NodeEventType } from '../core/scene-graph/node-event'; /** * @en @@ -103,13 +103,13 @@ export class ToggleContainer extends Component { public onEnable () { this.ensureValidState(); - this.node.on(SystemEventType.CHILD_ADDED, this.ensureValidState, this); - this.node.on(SystemEventType.CHILD_REMOVED, this.ensureValidState, this); + this.node.on(NodeEventType.CHILD_ADDED, this.ensureValidState, this); + this.node.on(NodeEventType.CHILD_REMOVED, this.ensureValidState, this); } public onDisable () { - this.node.off(SystemEventType.CHILD_ADDED, this.ensureValidState, this); - this.node.off(SystemEventType.CHILD_REMOVED, this.ensureValidState, this); + this.node.off(NodeEventType.CHILD_ADDED, this.ensureValidState, this); + this.node.off(NodeEventType.CHILD_REMOVED, this.ensureValidState, this); } public activeToggles () { diff --git a/cocos/ui/widget.ts b/cocos/ui/widget.ts index 6b86f549732..9570ecd43cd 100644 --- a/cocos/ui/widget.ts +++ b/cocos/ui/widget.ts @@ -35,7 +35,6 @@ import { Component } from '../core/components'; import { UITransform } from '../2d/framework/ui-transform'; import { Size, Vec2, Vec3 } from '../core/math'; import { errorID, warnID } from '../core/platform/debug'; -import { SystemEventType } from '../core/platform/event-manager/event-enum'; import { View } from '../core/platform/view'; import visibleRect from '../core/platform/visible-rect'; import { Scene } from '../core/scene-graph'; @@ -43,6 +42,7 @@ import { Node } from '../core/scene-graph/node'; import { ccenum } from '../core/value-types/enum'; import { TransformBit } from '../core/scene-graph/node-enum'; import { legacyCC } from '../core/global-exports'; +import { NodeEventType } from '../core/scene-graph/node-event'; const _tempScale = new Vec2(); @@ -845,29 +845,29 @@ export class Widget extends Component { protected _registerEvent () { if (EDITOR && !legacyCC.GAME_VIEW) { - this.node.on(SystemEventType.TRANSFORM_CHANGED, this._adjustWidgetToAllowMovingInEditor, this); - this.node.on(SystemEventType.SIZE_CHANGED, this._adjustWidgetToAllowResizingInEditor, this); + this.node.on(NodeEventType.TRANSFORM_CHANGED, this._adjustWidgetToAllowMovingInEditor, this); + this.node.on(NodeEventType.SIZE_CHANGED, this._adjustWidgetToAllowResizingInEditor, this); } else { - this.node.on(SystemEventType.TRANSFORM_CHANGED, this._setDirtyByMode, this); - this.node.on(SystemEventType.SIZE_CHANGED, this._setDirtyByMode, this); + this.node.on(NodeEventType.TRANSFORM_CHANGED, this._setDirtyByMode, this); + this.node.on(NodeEventType.SIZE_CHANGED, this._setDirtyByMode, this); } - this.node.on(SystemEventType.ANCHOR_CHANGED, this._adjustWidgetToAnchorChanged, this); - this.node.on(SystemEventType.PARENT_CHANGED, this._adjustTargetToParentChanged, this); + this.node.on(NodeEventType.ANCHOR_CHANGED, this._adjustWidgetToAnchorChanged, this); + this.node.on(NodeEventType.PARENT_CHANGED, this._adjustTargetToParentChanged, this); } protected _unregisterEvent () { if (EDITOR && !legacyCC.GAME_VIEW) { - this.node.off(SystemEventType.TRANSFORM_CHANGED, this._adjustWidgetToAllowMovingInEditor, this); - this.node.off(SystemEventType.SIZE_CHANGED, this._adjustWidgetToAllowResizingInEditor, this); + this.node.off(NodeEventType.TRANSFORM_CHANGED, this._adjustWidgetToAllowMovingInEditor, this); + this.node.off(NodeEventType.SIZE_CHANGED, this._adjustWidgetToAllowResizingInEditor, this); } else { - this.node.off(SystemEventType.TRANSFORM_CHANGED, this._setDirtyByMode, this); - this.node.off(SystemEventType.SIZE_CHANGED, this._setDirtyByMode, this); + this.node.off(NodeEventType.TRANSFORM_CHANGED, this._setDirtyByMode, this); + this.node.off(NodeEventType.SIZE_CHANGED, this._setDirtyByMode, this); } - this.node.off(SystemEventType.ANCHOR_CHANGED, this._adjustWidgetToAnchorChanged, this); + this.node.off(NodeEventType.ANCHOR_CHANGED, this._adjustWidgetToAnchorChanged, this); } protected _removeParentEvent () { - this.node.off(SystemEventType.PARENT_CHANGED, this._adjustTargetToParentChanged, this); + this.node.off(NodeEventType.PARENT_CHANGED, this._adjustTargetToParentChanged, this); } protected _autoChangedValue (flag: AlignFlags, isAbs: boolean) { @@ -900,8 +900,8 @@ export class Widget extends Component { const target = this._target || this.node.parent; if (target) { if (target.getComponent(UITransform)) { - target.on(SystemEventType.TRANSFORM_CHANGED, this._setDirtyByMode, this); - target.on(SystemEventType.SIZE_CHANGED, this._setDirtyByMode, this); + target.on(NodeEventType.TRANSFORM_CHANGED, this._setDirtyByMode, this); + target.on(NodeEventType.SIZE_CHANGED, this._setDirtyByMode, this); } } } @@ -909,16 +909,16 @@ export class Widget extends Component { protected _unregisterTargetEvents () { const target = this._target || this.node.parent; if (target) { - target.off(SystemEventType.TRANSFORM_CHANGED, this._setDirtyByMode, this); - target.off(SystemEventType.SIZE_CHANGED, this._setDirtyByMode, this); + target.off(NodeEventType.TRANSFORM_CHANGED, this._setDirtyByMode, this); + target.off(NodeEventType.SIZE_CHANGED, this._setDirtyByMode, this); } } protected _unregisterOldParentEvents (oldParent: Node) { const target = this._target || oldParent; if (target) { - target.off(SystemEventType.TRANSFORM_CHANGED, this._setDirtyByMode, this); - target.off(SystemEventType.SIZE_CHANGED, this._setDirtyByMode, this); + target.off(NodeEventType.TRANSFORM_CHANGED, this._setDirtyByMode, this); + target.off(NodeEventType.SIZE_CHANGED, this._setDirtyByMode, this); } } diff --git a/editor/assets/default_ui/atom.plist.meta b/editor/assets/default_ui/atom.plist.meta index a680e02621f..28244b8ef60 100644 --- a/editor/assets/default_ui/atom.plist.meta +++ b/editor/assets/default_ui/atom.plist.meta @@ -50,12 +50,16 @@ "endSizeVar": 0, "positionType": 0, "sourcePos": { - "x": 0, - "y": 0 + "_array": { + "0": 0, + "1": 0 + } }, "posVar": { - "x": 7, - "y": 7 + "_array": { + "0": 7, + "1": 7 + } }, "angle": 360, "angleVar": 360, @@ -65,8 +69,10 @@ "endSpinVar": -142.11000061035156, "emitterMode": 0, "gravity": { - "x": 0.25, - "y": 0.8600000143051147 + "_array": { + "0": 0.25, + "1": 0.8600000143051147 + } }, "speed": 0, "speedVar": 190.7899932861328, diff --git a/editor/assets/effects/builtin-reflection-deferred.effect b/editor/assets/effects/builtin-reflection-deferred.effect new file mode 100644 index 00000000000..f60f42b0494 --- /dev/null +++ b/editor/assets/effects/builtin-reflection-deferred.effect @@ -0,0 +1,248 @@ +// Copyright (c) 2017-2020 Xiamen Yaji Software Co., Ltd. + +CCEffect %{ + techniques: + - passes: + - vert: standard-vs + frag: standard-fs + phase: reflection + depthStencilState: + depthTest: true + depthWrite: false + blendState: + targets: + - blend: true + blendSrc: src_alpha + blendDst: one_minus_src_alpha + blendDstAlpha: one_minus_src_alpha + properties: &props + tilingOffset: { value: [1.0, 1.0, 0.0, 0.0] } + mainColor: { value: [1.0, 1.0, 1.0, 1.0], target: albedo, editor: { displayName: Albedo, type: color } } + albedoScale: { value: [1.0, 1.0, 1.0], target: albedoScaleAndCutoff.xyz } + alphaThreshold: { value: 0.5, target: albedoScaleAndCutoff.w, editor: { parent: USE_ALPHA_TEST } } + occlusion: { value: 1.0, target: pbrParams.x } + roughness: { value: 0.8, target: pbrParams.y } + metallic: { value: 0.6, target: pbrParams.z } + normalStrenth: { value: 1.0, target: pbrParams.w, editor: { parent: USE_NORMAL_MAP } } + emissive: { value: [0.0, 0.0, 0.0, 1.0], editor: { type: color } } + emissiveScale: { value: [1.0, 1.0, 1.0], target: emissiveScaleParam.xyz } + mainTexture: { value: grey, target: albedoMap, editor: { displayName: AlbedoMap } } + normalMap: { value: normal } + pbrMap: { value: grey } + metallicRoughnessMap: { value: grey } + occlusionMap: { value: white } + emissiveMap: { value: grey } +}% + +CCProgram shared-ubos %{ + uniform Constants { + vec4 tilingOffset; + vec4 albedo; + vec4 albedoScaleAndCutoff; + vec4 pbrParams; + vec4 emissive; + vec4 emissiveScaleParam; + }; +}% + +CCProgram standard-vs %{ + precision highp float; + #include + #include + #include + #include + #include + #include + + #if USE_VERTEX_COLOR + in vec4 a_color; + out vec4 v_color; + #endif + + out vec3 v_position; + out vec3 v_normal; + out vec2 v_uv; + out vec2 v_uv1; + + #if USE_NORMAL_MAP + out vec3 v_tangent; + out vec3 v_bitangent; + #endif + + #if HAS_SECOND_UV || USE_LIGHTMAP + in vec2 a_texCoord1; + #endif + + #if USE_LIGHTMAP && !USE_BATCHING && !CC_FORWARD_ADD + #include + #endif + + void main () { + StandardVertInput In; + CCVertInput(In); + + mat4 matWorld, matWorldIT; + CCGetWorldMatrixFull(matWorld, matWorldIT); + + vec4 pos = matWorld * In.position; + + v_position = pos.xyz; + v_normal = normalize((matWorldIT * vec4(In.normal, 0.0)).xyz); + #if USE_NORMAL_MAP + v_tangent = normalize((matWorld * vec4(In.tangent.xyz, 0.0)).xyz); + v_bitangent = cross(v_normal, v_tangent) * In.tangent.w; // note the cross order + #endif + + v_uv = a_texCoord * tilingOffset.xy + tilingOffset.zw; + #if HAS_SECOND_UV + v_uv1 = a_texCoord1 * tilingOffset.xy + tilingOffset.zw; + #endif + + #if USE_VERTEX_COLOR + v_color = a_color; + #endif + + CC_TRANSFER_FOG(pos); + CC_TRANSFER_SHADOW(pos); + + #if USE_LIGHTMAP && !USE_BATCHING && !CC_FORWARD_ADD + CCLightingMapCaclUV(); + #endif + + + gl_Position = cc_matProj * (cc_matView * matWorld) * In.position; + } +}% + +CCProgram standard-fs %{ + precision highp float; + #include + #include + #include + #include + #if USE_LIGHTMAP && !USE_BATCHING && !CC_FORWARD_ADD + #include + #endif + + in vec3 v_position; + in vec2 v_uv; + in vec2 v_uv1; + in vec3 v_normal; + + #if USE_VERTEX_COLOR + in vec4 v_color; + #endif + + #if USE_ALBEDO_MAP + uniform sampler2D albedoMap; + #pragma define ALBEDO_UV options([v_uv, v_uv1]) + #endif + #if USE_NORMAL_MAP + in vec3 v_tangent; + in vec3 v_bitangent; + uniform sampler2D normalMap; + #pragma define NORMAL_UV options([v_uv, v_uv1]) + #endif + #pragma define PBR_UV options([v_uv, v_uv1]) + #if USE_PBR_MAP + uniform sampler2D pbrMap; + #endif + #if USE_METALLIC_ROUGHNESS_MAP + uniform sampler2D metallicRoughnessMap; + #endif + #if USE_OCCLUSION_MAP + uniform sampler2D occlusionMap; + #endif + #if USE_EMISSIVE_MAP + uniform sampler2D emissiveMap; + #pragma define EMISSIVE_UV options([v_uv, v_uv1]) + #endif + + #define OCCLUSION_CHANNEL r + #define ROUGHNESS_CHANNEL g + #define METALLIC_CHANNEL b + + #if USE_ALPHA_TEST + #pragma define ALPHA_TEST_CHANNEL options([a, r]) + #endif + + void surf (out StandardSurface s) { + vec4 baseColor = albedo; + #if USE_VERTEX_COLOR + baseColor *= v_color; + #endif + #if USE_ALBEDO_MAP + vec4 texColor = texture(albedoMap, ALBEDO_UV); + texColor.rgb = SRGBToLinear(texColor.rgb); + baseColor *= texColor; + #endif + s.albedo = baseColor; + s.albedo.rgb *= albedoScaleAndCutoff.xyz; + + #if USE_ALPHA_TEST + if (s.albedo.ALPHA_TEST_CHANNEL < albedoScaleAndCutoff.w) discard; + #endif + + #if USE_LIGHTMAP && !USE_BATCHING && !CC_FORWARD_ADD + s.lightmap = texture(cc_lightingMap, v_luv); + #endif + + s.normal = v_normal; + #if USE_NORMAL_MAP + vec3 nmmp = texture(normalMap, NORMAL_UV).xyz - vec3(0.5); + s.normal = + (nmmp.x * pbrParams.w) * normalize(v_tangent) + + (nmmp.y * pbrParams.w) * normalize(v_bitangent) + + nmmp.z * normalize(s.normal); + #endif + + s.position = v_position; + + vec4 pbr = pbrParams; + #if USE_PBR_MAP + vec4 res = texture(pbrMap, PBR_UV); + pbr.x *= res.OCCLUSION_CHANNEL; + pbr.y *= res.ROUGHNESS_CHANNEL; + pbr.z *= res.METALLIC_CHANNEL; + #endif + #if USE_METALLIC_ROUGHNESS_MAP + vec4 metallicRoughness = texture(metallicRoughnessMap, PBR_UV); + pbr.z *= metallicRoughness.METALLIC_CHANNEL; + pbr.y *= metallicRoughness.ROUGHNESS_CHANNEL; + #endif + #if USE_OCCLUSION_MAP + pbr.x *= texture(occlusionMap, PBR_UV).OCCLUSION_CHANNEL; + #endif + s.occlusion = clamp(pbr.x, 0.0, 0.96); + s.roughness = clamp(pbr.y, 0.04, 1.0); + s.metallic = pbr.z; + + s.emissive = emissive.rgb * emissiveScaleParam.xyz; + #if USE_EMISSIVE_MAP + s.emissive *= SRGBToLinear(texture(emissiveMap, EMISSIVE_UV).rgb); + #endif + } + + #pragma builtin(local) + layout(set = 2, binding = 11) uniform sampler2D cc_reflectionTexture; + + layout(location = 0) out vec4 fragColorX; + + void main () { + StandardSurface s; surf(s); + vec4 color = CCStandardShadingBase(s, CC_SHADOW_POSITION); + CC_APPLY_FOG(color); + vec4 baseColor = CCFragOutput(color); + + vec2 noise = v_normal.xy * 0.02; + #if USE_NORMAL_MAP + noise = texture(normalMap, ALBEDO_UV).xy * 0.02; + #endif + + vec2 resolution = cc_screenSize.xy; + vec2 uv = (gl_FragCoord.xy / resolution) + noise; + vec4 reflectionColor = texture(cc_reflectionTexture, uv); + fragColorX = mix(baseColor, reflectionColor, 0.5); + fragColorX.w = 1.0; + } +}% \ No newline at end of file diff --git a/editor/assets/effects/builtin-reflection-deferred.effect.meta b/editor/assets/effects/builtin-reflection-deferred.effect.meta new file mode 100644 index 00000000000..6acebc99e41 --- /dev/null +++ b/editor/assets/effects/builtin-reflection-deferred.effect.meta @@ -0,0 +1,11 @@ +{ + "ver": "1.4.6", + "importer": "effect", + "imported": true, + "uuid": "99498f84-efe6-43a6-a9a7-e6e93eb845c1", + "files": [ + ".json" + ], + "subMetas": {}, + "userData": {} +} diff --git a/editor/i18n/en/assets.js b/editor/i18n/en/assets.js index 54f779b06e2..7dba122b4ef 100644 --- a/editor/i18n/en/assets.js +++ b/editor/i18n/en/assets.js @@ -13,8 +13,8 @@ module.exports = { FontSize: 'Font Size', }, particle: { - spriteFrame:'Sprite Frame', - spriteFrameTip:'Sprite Frame', + spriteFrame: 'Sprite Frame', + spriteFrameTip: 'Sprite Frame', }, erpTextureCube: { anisotropy: 'Anisotropy', @@ -31,7 +31,8 @@ module.exports = { wrapModeTTip: 'Wrap Mode T', faceSize: { name: 'Face Size', - title: 'Size of each cube face. If not specified, or specified as 0, the default size, which is the nearest power of two to (image.width)/4, is used.', + title: + 'Size of each cube face. If not specified, or specified as 0, the default size, which is the nearest power of two to (image.width)/4, is used.', }, }, javascript: { @@ -121,7 +122,8 @@ module.exports = { wrapModeSTip: 'Wrap Mode S', wrapModeT: 'Wrap Mode T', wrapModeTTip: 'Wrap Mode T', - modeWarn: 'Warning: WebGL 1.0 platform doesn\'t support \'repeat\' filter for non-power-of-two textures(runtime fallback to \'clamp-to-edge\'), effectively disabling features like the \'tilingOffset\' property in many materials.', + modeWarn: + "Warning: WebGL 1.0 platform doesn't support 'repeat' filter for non-power-of-two textures(runtime fallback to 'clamp-to-edge'), effectively disabling features like the 'tilingOffset' property in many materials.", }, fbx: { browse: 'Change Target', @@ -171,13 +173,34 @@ module.exports = { title: 'Recalculate tangents and import, ingoring whether if the model file contain tangents.', }, }, + morphNormals: { + name: 'Morph normals', + title: 'Morph normals import setting.', + optional: { + name: 'Optional', + title: 'Import morph normals only if the model file contains morph normals.', + }, + exclude: { + name: 'Exclude', + title: 'Do not import morph normals.', + }, + require: { + name: 'Required', + title: 'Import morph normals that are contained in the model file, or calculated if not contained.', + }, + recalculate: { + name: 'Recalculate', + title: 'Recalculate morph normals and import, ingoring whether if the model file contain morph normals.', + }, + }, dumpMaterials: { name: 'Dump materials', title: 'Whether to extract material assets out of embedded (sub)assets, so that the assets become editable.', }, materialDumpDir: { name: 'Material dump directory', - title: 'The directory to dump the materials.\nDefault to a direct sub-folder named `Materials_${model-file-base-name}` under current path.', + title: + 'The directory to dump the materials.\nDefault to a direct sub-folder named `Materials_${model-file-base-name}` under current path.', }, useVertexColors: { name: 'Use vertex colors', @@ -258,6 +281,13 @@ module.exports = { name: 'Animation Bake Rate', title: 'Specify the animation bake rate in frames per second (fps).', }, + promoteSingleRootNode: { + name: 'Promote single root node', + title: + 'If enabled and there is only one single root node in a FBX scene,
' + + 'the single root node is used as the root of prefab when converting the FBX scene to Cocos Creator prefab.
' + + "Otherwise, the FBX scene become prefab's root.", + }, }, textureCube: { anisotropy: 'Anisotropy', @@ -272,7 +302,8 @@ module.exports = { wrapModeSTip: 'Wrap Mode S', wrapModeT: 'Wrap Mode T', wrapModeTTip: 'Wrap Mode T', - modeWarn: 'Warning: WebGL 1.0 platform doesn\'t support \'repeat\' filter for non-power-of-two textures(runtime fallback to \'clamp-to-edge\'), effectively disabling features like the \'tilingOffset\' property in many materials.', + modeWarn: + "Warning: WebGL 1.0 platform doesn't support 'repeat' filter for non-power-of-two textures(runtime fallback to 'clamp-to-edge'), effectively disabling features like the 'tilingOffset' property in many materials.", }, }, }; diff --git a/editor/i18n/zh/assets.js b/editor/i18n/zh/assets.js index d4f31e6878b..5b586079338 100644 --- a/editor/i18n/zh/assets.js +++ b/editor/i18n/zh/assets.js @@ -172,6 +172,26 @@ module.exports = { title: '不管模型文件中是否包含切线都直接重新计算并导入。', }, }, + morphNormals: { + name: '形变法线', + title: '形变法线导入设置。', + optional: { + name: '可选', + title: '仅当模型文件中包含形变法线时导入形变法线。', + }, + exclude: { + name: '排除', + title: '不导入形变法线。', + }, + require: { + name: '仅在必要时重新计算', + title: '导入形变法线。优先使用模型文件中的形变法线,若模型文件中不包含形变法线则计算形变法线。', + }, + recalculate: { + name: '重新计算', + title: '不管模型文件中是否包含形变法线都直接重新计算并导入。', + }, + }, dumpMaterials: { name: '提取材质', title: '开启后,模型文件中的材质将被提取成为可编辑的材质文件,而非作为模型文件资源的只读子资源。', @@ -257,6 +277,10 @@ module.exports = { name: '动画烘焙速率', title: '指定动画烘焙速率,单位为帧每秒(FPS)', }, + promoteSingleRootNode: { + name: '提升单一根结点', + title: '若开启并且 FBX 场景仅有一个根节点,那么当转换该 FBX 场景为 Cocos Creator 预制体时,
以该根节点作为预制体的根节点,否则以该 FBX 场景的根节点作为预制体的根节点。', + }, }, textureCube: { anisotropy: 'Anisotropy', diff --git a/editor/inspector/assets/effect.js b/editor/inspector/assets/effect.js index dd19bb0e29a..2a816699b8d 100644 --- a/editor/inspector/assets/effect.js +++ b/editor/inspector/assets/effect.js @@ -9,7 +9,7 @@ exports.template = ` - +

@@ -196,6 +196,7 @@ const Elements = { panel.$.codes.appendChild(section); section.setAttribute('class', 'config'); section.setAttribute('expand', ''); + section.setAttribute('cache-expand', `effect-${glslKey}`); const glslName = panel.glslNames[glslKey]; diff --git a/editor/inspector/assets/fbx/fbx.js b/editor/inspector/assets/fbx/fbx.js index 90596e234db..25ddc9b7b0b 100644 --- a/editor/inspector/assets/fbx/fbx.js +++ b/editor/inspector/assets/fbx/fbx.js @@ -18,6 +18,10 @@ exports.template = ` + + + +
`; @@ -38,6 +42,7 @@ exports.$ = { container: '.container', legacyFbxImporterCheckbox: '.legacyFbxImporter-checkbox', animationBakeRateSelect: '.animationBakeRate-select', + promoteSingleRootNodeCheckbox: '.promoteSingleRootNode-checkbox', }; /** @@ -74,6 +79,21 @@ const Elements = { panel.updateReadonly(panel.$.animationBakeRateSelect); }, }, + promoteSingleRootNode: { + ready() { + const panel = this; + + panel.$.promoteSingleRootNodeCheckbox.addEventListener('change', panel.setProp.bind(panel, 'promoteSingleRootNode')); + }, + update() { + const panel = this; + + panel.$.promoteSingleRootNodeCheckbox.value = panel.getDefault(panel.meta.userData.promoteSingleRootNode, false); + + panel.updateInvalid(panel.$.promoteSingleRootNodeCheckbox, 'promoteSingleRootNode'); + panel.updateReadonly(panel.$.promoteSingleRootNodeCheckbox); + }, + }, }; exports.update = function(assetList, metaList) { diff --git a/editor/inspector/assets/fbx/model.js b/editor/inspector/assets/fbx/model.js index eafd3076b31..d10fbcf38a3 100644 --- a/editor/inspector/assets/fbx/model.js +++ b/editor/inspector/assets/fbx/model.js @@ -10,6 +10,10 @@ exports.template = ` + + + + @@ -18,13 +22,13 @@ exports.template = ` - +
- + @@ -35,7 +39,7 @@ exports.template = ` - + @@ -46,7 +50,7 @@ exports.template = ` - + @@ -88,6 +92,7 @@ exports.$ = { container: '.container', normalsSelect: '.normals-select', tangentsSelect: '.tangents-select', + morphNormalsSelect: '.morphNormals-select', skipValidationCheckbox: '.skipValidation-checkbox', disableMeshSplitCheckbox: '.disableMeshSplit-checkbox', meshOptimizerCheckbox: '.meshOptimizer-checkbox', @@ -151,6 +156,30 @@ const Elements = { panel.updateReadonly(panel.$.tangentsSelect); }, }, + morphNormals: { + ready() { + const panel = this; + + panel.$.morphNormalsSelect.addEventListener('change', panel.setProp.bind(panel, 'morphNormals')); + }, + update() { + const panel = this; + + let optionsHtml = ''; + const types = ['optional', 'exclude']; + types.forEach((type, index) => { + optionsHtml += ``; + }); + panel.$.morphNormalsSelect.innerHTML = optionsHtml; + + panel.$.morphNormalsSelect.value = panel.getDefault(panel.meta.userData.morphNormals, 1); + + panel.updateInvalid(panel.$.morphNormalsSelect, 'morphNormals'); + panel.updateReadonly(panel.$.morphNormalsSelect); + }, + }, skipValidation: { ready() { const panel = this; @@ -324,8 +353,10 @@ exports.methods = { setProp(prop, event) { this.metaList.forEach((meta) => { let value = event.target.value; - if (prop === 'normals' || prop === 'tangents') { - value = Number(value); + switch (prop) { + case 'normals': case 'tangents': case 'morphNormals': + value = Number(value); + break; } meta.userData[prop] = value; diff --git a/editor/inspector/assets/image.js b/editor/inspector/assets/image.js index 73a71b8208a..c7693d45730 100644 --- a/editor/inspector/assets/image.js +++ b/editor/inspector/assets/image.js @@ -18,7 +18,7 @@ exports.template = ` - + diff --git a/editor/inspector/assets/render-pipeline.js b/editor/inspector/assets/render-pipeline.js index b1ef00f07bb..543541efcff 100644 --- a/editor/inspector/assets/render-pipeline.js +++ b/editor/inspector/assets/render-pipeline.js @@ -63,7 +63,7 @@ const Elements = { async update() { const panel = this; - const $content = panel.$.content + const $content = panel.$.content; const oldPropList = Object.keys(panel.$propList); const newPropList = []; @@ -92,7 +92,7 @@ const Elements = { $prop = document.createElement('ui-prop'); $prop.setAttribute('type', 'dump'); $prop.addEventListener('change-dump', this.dataChange.bind(this)); - + $content.appendChild($prop); panel.$propList[id] = $prop; } @@ -141,6 +141,7 @@ exports.update = async function(assetList, metaList) { } this.setDirtyData(); + await this.preview(); }; exports.ready = function() { @@ -173,6 +174,13 @@ exports.close = function() { }; exports.methods = { + async preview() { + if (!this.pipeline) { + return; + } + await Editor.Message.request('scene', 'preview-render-pipeline', this.asset.uuid, this.pipeline); + }, + async query(uuid) { return await Editor.Message.request('scene', 'query-render-pipeline', uuid); }, @@ -180,6 +188,7 @@ exports.methods = { async apply() { this.reset(); await Editor.Message.request('scene', 'apply-render-pipeline', this.asset.uuid, this.pipeline); + await this.preview(); }, reset() { this.dirtyData.origin = this.dirtyData.realtime; @@ -193,6 +202,8 @@ exports.methods = { this.setDirtyData(); this.dispatch('change'); + + await this.preview(); }, /** diff --git a/editor/inspector/assets/texture-cube.js b/editor/inspector/assets/texture-cube.js index 45e44009730..f1b075e5191 100644 --- a/editor/inspector/assets/texture-cube.js +++ b/editor/inspector/assets/texture-cube.js @@ -8,7 +8,7 @@ const Direction = { top: 'top ( +Y )', bottom: 'bottom ( -Y )', front: 'front ( +Z )', - back: 'left ( -X )', + back: 'back ( -Z )', }; exports.template = ` diff --git a/editor/inspector/components/particle-system.js b/editor/inspector/components/particle-system.js index 0cdee44862a..dbd35746092 100644 --- a/editor/inspector/components/particle-system.js +++ b/editor/inspector/components/particle-system.js @@ -35,7 +35,7 @@ exports.template = ` - + @@ -90,10 +90,10 @@ exports.template = ` - - + + - + @@ -114,7 +114,7 @@ exports.template = ` - + @@ -130,9 +130,9 @@ exports.template = ` - - - + + + @@ -146,7 +146,7 @@ exports.template = ` - + diff --git a/pal/input/minigame/accelerometer.ts b/pal/input/minigame/accelerometer.ts index 180b6b1be1c..d2bbfceee67 100644 --- a/pal/input/minigame/accelerometer.ts +++ b/pal/input/minigame/accelerometer.ts @@ -1,6 +1,6 @@ import { AccelerometerCallback, AccelerometerInputEvent } from 'pal/input'; import { minigame, AccelerometerIntervalMode } from 'pal/minigame'; -import { SystemEventType } from '../../../cocos/core/platform/event-manager/event-enum'; +import { DeviceEvent } from '../../../cocos/core/platform/event-manager/event-enum'; import { EventTarget } from '../../../cocos/core/event/event-target'; export class AccelerometerInputSource { @@ -26,13 +26,13 @@ export class AccelerometerInputSource { private _didAccelerate (event: AccelerometerData) { const accelerometer: AccelerometerInputEvent = { - type: SystemEventType.DEVICEMOTION, + type: DeviceEvent.DEVICEMOTION, x: event.x, y: event.y, z: event.z, timestamp: performance.now(), }; - this._eventTarget.emit(SystemEventType.DEVICEMOTION, accelerometer); + this._eventTarget.emit(DeviceEvent.DEVICEMOTION, accelerometer); } public start () { @@ -71,6 +71,6 @@ export class AccelerometerInputSource { } } public onChange (cb: AccelerometerCallback) { - this._eventTarget.on(SystemEventType.DEVICEMOTION, cb); + this._eventTarget.on(DeviceEvent.DEVICEMOTION, cb); } } diff --git a/pal/input/minigame/keyboard.ts b/pal/input/minigame/keyboard.ts index 2807e26b92c..5e039b41d01 100644 --- a/pal/input/minigame/keyboard.ts +++ b/pal/input/minigame/keyboard.ts @@ -1,5 +1,5 @@ import { KeyboardCallback, KeyboardInputEvent } from 'pal/input'; -import { SystemEventType } from '../../../cocos/core/platform/event-manager/event-enum'; +import { KeyboardEvent } from '../../../cocos/core/platform/event-manager/event-enum'; import { EventTarget } from '../../../cocos/core/event/event-target'; export class KeyboardInputSource { @@ -11,10 +11,14 @@ export class KeyboardInputSource { } public onDown (cb: KeyboardCallback) { - this._eventTarget.on(SystemEventType.KEY_DOWN, cb); + this._eventTarget.on(KeyboardEvent.KEY_DOWN, cb); + } + + public onPressing (cb: KeyboardCallback) { + this._eventTarget.on('keydown', cb); } public onUp (cb: KeyboardCallback) { - this._eventTarget.on(SystemEventType.KEY_UP, cb); + this._eventTarget.on(KeyboardEvent.KEY_UP, cb); } } diff --git a/pal/input/minigame/mouse.ts b/pal/input/minigame/mouse.ts index 56cfec20692..c2210dc14f7 100644 --- a/pal/input/minigame/mouse.ts +++ b/pal/input/minigame/mouse.ts @@ -1,7 +1,7 @@ import { MouseCallback, MouseInputEvent, MouseWheelCallback, MouseWheelInputEvent } from 'pal/input'; import { EventMouse } from '../../../cocos/core/platform/event-manager/events'; import { EventTarget } from '../../../cocos/core/event/event-target'; -import { SystemEventType } from '../../../cocos/core/platform/event-manager/event-enum'; +import { MouseEvent } from '../../../cocos/core/platform/event-manager/event-enum'; export class MouseInputSource { public support: boolean; @@ -12,15 +12,15 @@ export class MouseInputSource { } onDown (cb: MouseCallback) { - this._eventTarget.on(SystemEventType.MOUSE_DOWN, cb); + this._eventTarget.on(MouseEvent.MOUSE_DOWN, cb); } onMove (cb: MouseCallback) { - this._eventTarget.on(SystemEventType.MOUSE_MOVE, cb); + this._eventTarget.on(MouseEvent.MOUSE_MOVE, cb); } onUp (cb: MouseCallback) { - this._eventTarget.on(SystemEventType.MOUSE_UP, cb); + this._eventTarget.on(MouseEvent.MOUSE_UP, cb); } onWheel (cb: MouseWheelCallback) { - this._eventTarget.on(SystemEventType.MOUSE_WHEEL, cb); + this._eventTarget.on(MouseEvent.MOUSE_WHEEL, cb); } } diff --git a/pal/input/minigame/touch.ts b/pal/input/minigame/touch.ts index 77e866946b6..bb1e0483b7a 100644 --- a/pal/input/minigame/touch.ts +++ b/pal/input/minigame/touch.ts @@ -2,8 +2,7 @@ import { TouchCallback, TouchData, TouchInputEvent } from 'pal/input'; import { minigame } from 'pal/minigame'; import { Vec2 } from '../../../cocos/core/math'; import { EventTarget } from '../../../cocos/core/event/event-target'; -import { EventTouch } from '../../../cocos/core/platform/event-manager/events'; -import { SystemEventType } from '../../../cocos/core/platform/event-manager/event-enum'; +import { TouchEvent } from '../../../cocos/core/platform/event-manager/event-enum'; export class TouchInputSource { public support: boolean; @@ -15,14 +14,14 @@ export class TouchInputSource { } private _registerEvent () { - minigame.onTouchStart(this._createCallback(SystemEventType.TOUCH_START)); - minigame.onTouchMove(this._createCallback(SystemEventType.TOUCH_MOVE)); - minigame.onTouchEnd(this._createCallback(SystemEventType.TOUCH_END)); - minigame.onTouchCancel(this._createCallback(SystemEventType.TOUCH_CANCEL)); + minigame.onTouchStart(this._createCallback(TouchEvent.TOUCH_START)); + minigame.onTouchMove(this._createCallback(TouchEvent.TOUCH_MOVE)); + minigame.onTouchEnd(this._createCallback(TouchEvent.TOUCH_END)); + minigame.onTouchCancel(this._createCallback(TouchEvent.TOUCH_CANCEL)); } - private _createCallback (eventType: string) { - return (event: TouchEvent) => { + private _createCallback (eventType: TouchEvent) { + return (event: any) => { const sysInfo = minigame.getSystemInfoSync(); const touchDataList: TouchData[] = []; const length = event.changedTouches.length; @@ -51,15 +50,15 @@ export class TouchInputSource { } public onStart (cb: TouchCallback) { - this._eventTarget.on(SystemEventType.TOUCH_START, cb); + this._eventTarget.on(TouchEvent.TOUCH_START, cb); } public onMove (cb: TouchCallback) { - this._eventTarget.on(SystemEventType.TOUCH_MOVE, cb); + this._eventTarget.on(TouchEvent.TOUCH_MOVE, cb); } public onEnd (cb: TouchCallback) { - this._eventTarget.on(SystemEventType.TOUCH_END, cb); + this._eventTarget.on(TouchEvent.TOUCH_END, cb); } public onCancel (cb: TouchCallback) { - this._eventTarget.on(SystemEventType.TOUCH_CANCEL, cb); + this._eventTarget.on(TouchEvent.TOUCH_CANCEL, cb); } } diff --git a/pal/input/native/accelerometer.ts b/pal/input/native/accelerometer.ts index 911313b0f53..5d86bbfda17 100644 --- a/pal/input/native/accelerometer.ts +++ b/pal/input/native/accelerometer.ts @@ -1,6 +1,6 @@ import { AccelerometerCallback, AccelerometerInputEvent } from 'pal/input'; import { system } from 'pal/system'; -import { SystemEventType } from '../../../cocos/core/platform/event-manager/event-enum'; +import { DeviceEvent } from '../../../cocos/core/platform/event-manager/event-enum'; import { EventTarget } from '../../../cocos/core/event/event-target'; import { Orientation, OS } from '../../system/enum-type'; @@ -44,14 +44,14 @@ export class AccelerometerInputSource { y = -y; } const accelerometer: AccelerometerInputEvent = { - type: SystemEventType.DEVICEMOTION, + type: DeviceEvent.DEVICEMOTION, x, y, z, timestamp: performance.now(), }; - this._eventTarget.emit(SystemEventType.DEVICEMOTION, accelerometer); + this._eventTarget.emit(DeviceEvent.DEVICEMOTION, accelerometer); } public start () { @@ -81,6 +81,6 @@ export class AccelerometerInputSource { } } public onChange (cb: AccelerometerCallback) { - this._eventTarget.on(SystemEventType.DEVICEMOTION, cb); + this._eventTarget.on(DeviceEvent.DEVICEMOTION, cb); } } diff --git a/pal/input/native/keyboard.ts b/pal/input/native/keyboard.ts index e8070f043f2..882f394b18a 100644 --- a/pal/input/native/keyboard.ts +++ b/pal/input/native/keyboard.ts @@ -1,38 +1,86 @@ import { KeyboardCallback, KeyboardInputEvent } from 'pal/input'; import { system } from 'pal/system'; -import { SystemEventType } from '../../../cocos/core/platform/event-manager/event-enum'; +import { KeyboardEvent } from '../../../cocos/core/platform/event-manager/event-enum'; import { EventTarget } from '../../../cocos/core/event/event-target'; +import { KeyCode } from '../../../cocos/core/platform/event-manager/key-code'; + +const nativeKeyCode2Keycode: Record = { + 12: KeyCode.NUM_LOCK, + 10048: KeyCode.NUM_0, + 10049: KeyCode.NUM_1, + 10050: KeyCode.NUM_2, + 10051: KeyCode.NUM_3, + 10052: KeyCode.NUM_4, + 10053: KeyCode.NUM_5, + 10054: KeyCode.NUM_6, + 10055: KeyCode.NUM_7, + 10056: KeyCode.NUM_8, + 10057: KeyCode.NUM_9, + 20013: KeyCode.NUM_ENTER, + 20016: KeyCode.SHIFT_RIGHT, + 20017: KeyCode.CTRL_RIGHT, + 20018: KeyCode.ALT_RIGHT, +}; + +function getKeyCode (keyCode: number): KeyCode { + return nativeKeyCode2Keycode[keyCode] || keyCode; +} export class KeyboardInputSource { public support: boolean; private _eventTarget: EventTarget = new EventTarget(); + // On native platform, KeyboardEvent.repeat is always false, so we need a map to manage the key state. + private _keyStateMap: Record = {}; + constructor () { this.support = !system.isMobile; this._registerEvent(); } private _registerEvent () { - jsb.onKeyDown = this._createCallback(SystemEventType.KEY_DOWN); - jsb.onKeyUp = this._createCallback(SystemEventType.KEY_UP); - } - - private _createCallback (eventType: string) { - return (event: jsb.KeyboardEvent) => { + jsb.onKeyDown = (event: jsb.KeyboardEvent) => { + const keycode = getKeyCode(event.keyCode); + if (!this._keyStateMap[keycode]) { + const keyDownInputEvent = this._getInputEvent(event, KeyboardEvent.KEY_DOWN); + this._eventTarget.emit(KeyboardEvent.KEY_DOWN, keyDownInputEvent); + } + // @ts-expect-error Compability for key pressing callback + const keyPressingInputEvent = this._getInputEvent(event, 'keydown'); + this._eventTarget.emit('keydown', keyPressingInputEvent); + this._keyStateMap[keycode] = true; + }; + jsb.onKeyUp = (event: jsb.KeyboardEvent) => { + const keycode = getKeyCode(event.keyCode); const inputEvent: KeyboardInputEvent = { - type: eventType, - code: event.keyCode, + type: KeyboardEvent.KEY_UP, + code: keycode, timestamp: performance.now(), }; - this._eventTarget.emit(eventType, inputEvent); + this._keyStateMap[keycode] = false; + this._eventTarget.emit(KeyboardEvent.KEY_UP, inputEvent); + }; + } + + private _getInputEvent (event: jsb.KeyboardEvent, eventType: KeyboardEvent) { + const keycode = getKeyCode(event.keyCode); + const inputEvent: KeyboardInputEvent = { + type: eventType, + code: keycode, + timestamp: performance.now(), }; + return inputEvent; } public onDown (cb: KeyboardCallback) { - this._eventTarget.on(SystemEventType.KEY_DOWN, cb); + this._eventTarget.on(KeyboardEvent.KEY_DOWN, cb); + } + + public onPressing (cb: KeyboardCallback) { + this._eventTarget.on('keydown', cb); } public onUp (cb: KeyboardCallback) { - this._eventTarget.on(SystemEventType.KEY_UP, cb); + this._eventTarget.on(KeyboardEvent.KEY_UP, cb); } } diff --git a/pal/input/native/mouse.ts b/pal/input/native/mouse.ts index 7946a408689..98c610d150c 100644 --- a/pal/input/native/mouse.ts +++ b/pal/input/native/mouse.ts @@ -3,7 +3,7 @@ import { system } from 'pal/system'; import { EventMouse } from '../../../cocos/core/platform/event-manager/events'; import { EventTarget } from '../../../cocos/core/event/event-target'; import { Vec2 } from '../../../cocos/core/math'; -import { SystemEventType } from '../../../cocos/core/platform/event-manager/event-enum'; +import { MouseEvent } from '../../../cocos/core/platform/event-manager/event-enum'; export class MouseInputSource { public support: boolean; @@ -19,15 +19,15 @@ export class MouseInputSource { } private _registerEvent () { - jsb.onMouseDown = this._createCallback(SystemEventType.MOUSE_DOWN); - jsb.onMouseMove = this._createCallback(SystemEventType.MOUSE_MOVE); - jsb.onMouseUp = this._createCallback(SystemEventType.MOUSE_UP); + jsb.onMouseDown = this._createCallback(MouseEvent.MOUSE_DOWN); + jsb.onMouseMove = this._createCallback(MouseEvent.MOUSE_MOVE); + jsb.onMouseUp = this._createCallback(MouseEvent.MOUSE_UP); jsb.onMouseWheel = (event: jsb.MouseWheelEvent) => { const location = this._getLocation(event); const viewSize = system.getViewSize(); const matchStandardFactor = 120; const inputEvent: MouseWheelInputEvent = { - type: SystemEventType.MOUSE_WHEEL, + type: MouseEvent.MOUSE_WHEEL, x: location.x, y: viewSize.height - location.y, button: event.button, @@ -35,11 +35,11 @@ export class MouseInputSource { deltaY: event.wheelDeltaY * matchStandardFactor, timestamp: performance.now(), }; - this._eventTarget.emit(SystemEventType.MOUSE_WHEEL, inputEvent); + this._eventTarget.emit(MouseEvent.MOUSE_WHEEL, inputEvent); }; } - private _createCallback (eventType: string) { + private _createCallback (eventType: MouseEvent) { return (event: jsb.MouseEvent) => { const location = this._getLocation(event); const viewSize = system.getViewSize(); @@ -56,15 +56,15 @@ export class MouseInputSource { } onDown (cb: MouseCallback) { - this._eventTarget.on(SystemEventType.MOUSE_DOWN, cb); + this._eventTarget.on(MouseEvent.MOUSE_DOWN, cb); } onMove (cb: MouseCallback) { - this._eventTarget.on(SystemEventType.MOUSE_MOVE, cb); + this._eventTarget.on(MouseEvent.MOUSE_MOVE, cb); } onUp (cb: MouseCallback) { - this._eventTarget.on(SystemEventType.MOUSE_UP, cb); + this._eventTarget.on(MouseEvent.MOUSE_UP, cb); } onWheel (cb: MouseWheelCallback) { - this._eventTarget.on(SystemEventType.MOUSE_WHEEL, cb); + this._eventTarget.on(MouseEvent.MOUSE_WHEEL, cb); } } diff --git a/pal/input/native/touch.ts b/pal/input/native/touch.ts index 1761c131665..d4a7c08a438 100644 --- a/pal/input/native/touch.ts +++ b/pal/input/native/touch.ts @@ -4,7 +4,7 @@ import { Rect, Vec2 } from '../../../cocos/core/math'; import { EventTarget } from '../../../cocos/core/event/event-target'; import { EventTouch } from '../../../cocos/core/platform/event-manager/events'; import { legacyCC } from '../../../cocos/core/global-exports'; -import { SystemEventType } from '../../../cocos/core/platform/event-manager/event-enum'; +import { TouchEvent } from '../../../cocos/core/platform/event-manager/event-enum'; export class TouchInputSource { public support: boolean; @@ -16,13 +16,13 @@ export class TouchInputSource { } private _registerEvent () { - jsb.onTouchStart = this._createCallback(SystemEventType.TOUCH_START); - jsb.onTouchMove = this._createCallback(SystemEventType.TOUCH_MOVE); - jsb.onTouchEnd = this._createCallback(SystemEventType.TOUCH_END); - jsb.onTouchCancel = this._createCallback(SystemEventType.TOUCH_CANCEL); + jsb.onTouchStart = this._createCallback(TouchEvent.TOUCH_START); + jsb.onTouchMove = this._createCallback(TouchEvent.TOUCH_MOVE); + jsb.onTouchEnd = this._createCallback(TouchEvent.TOUCH_END); + jsb.onTouchCancel = this._createCallback(TouchEvent.TOUCH_CANCEL); } - private _createCallback (eventType: string) { + private _createCallback (eventType: TouchEvent) { return (touchList: TouchList) => { const touchDataList: TouchData[] = []; const length = touchList.length; @@ -54,15 +54,15 @@ export class TouchInputSource { } public onStart (cb: TouchCallback) { - this._eventTarget.on(SystemEventType.TOUCH_START, cb); + this._eventTarget.on(TouchEvent.TOUCH_START, cb); } public onMove (cb: TouchCallback) { - this._eventTarget.on(SystemEventType.TOUCH_MOVE, cb); + this._eventTarget.on(TouchEvent.TOUCH_MOVE, cb); } public onEnd (cb: TouchCallback) { - this._eventTarget.on(SystemEventType.TOUCH_END, cb); + this._eventTarget.on(TouchEvent.TOUCH_END, cb); } public onCancel (cb: TouchCallback) { - this._eventTarget.on(SystemEventType.TOUCH_CANCEL, cb); + this._eventTarget.on(TouchEvent.TOUCH_CANCEL, cb); } } diff --git a/pal/input/web/accelerometer.ts b/pal/input/web/accelerometer.ts index 79ae8a67afd..f704a18ad0b 100644 --- a/pal/input/web/accelerometer.ts +++ b/pal/input/web/accelerometer.ts @@ -1,9 +1,9 @@ import { AccelerometerCallback, AccelerometerInputEvent } from 'pal/input'; import { system } from 'pal/system'; -import { SystemEventType } from '../../../cocos/core/platform/event-manager/event-enum'; import { EventTarget } from '../../../cocos/core/event/event-target'; import { BrowserType, OS } from '../../system/enum-type'; import { legacyCC } from '../../../cocos/core/global-exports'; +import { DeviceEvent } from '../../../cocos/core/platform/event-manager/event-enum'; export class AccelerometerInputSource { public support: boolean; @@ -93,14 +93,14 @@ export class AccelerometerInputSource { y = -y; } const accelerometer: AccelerometerInputEvent = { - type: SystemEventType.DEVICEMOTION, + type: DeviceEvent.DEVICEMOTION, x, y, z, timestamp: performance.now(), }; - this._eventTarget.emit(SystemEventType.DEVICEMOTION, accelerometer); + this._eventTarget.emit(DeviceEvent.DEVICEMOTION, accelerometer); } public start () { @@ -113,6 +113,6 @@ export class AccelerometerInputSource { this._intervalInMileseconds = intervalInMileseconds; } public onChange (cb: AccelerometerCallback) { - this._eventTarget.on(SystemEventType.DEVICEMOTION, cb); + this._eventTarget.on(DeviceEvent.DEVICEMOTION, cb); } } diff --git a/pal/input/web/keyboard.ts b/pal/input/web/keyboard.ts index 1a30a1fa93d..f62b4f501b5 100644 --- a/pal/input/web/keyboard.ts +++ b/pal/input/web/keyboard.ts @@ -1,7 +1,114 @@ import { KeyboardCallback, KeyboardInputEvent } from 'pal/input'; -import { system } from 'pal/system'; -import { SystemEventType } from '../../../cocos/core/platform/event-manager/event-enum'; +import { KeyboardEvent } from '../../../cocos/core/platform/event-manager/event-enum'; import { EventTarget } from '../../../cocos/core/event/event-target'; +import { KeyCode } from '../../../cocos/core/platform/event-manager/key-code'; + +const code2KeyCode: Record = { + Backspace: KeyCode.BACKSPACE, + Tab: KeyCode.TAB, + Enter: KeyCode.ENTER, + ShiftLeft: KeyCode.SHIFT_LEFT, + ControlLeft: KeyCode.CTRL_LEFT, + AltLeft: KeyCode.ALT_LEFT, + ShiftRight: KeyCode.SHIFT_RIGHT, + ControlRight: KeyCode.CTRL_RIGHT, + AltRight: KeyCode.ALT_RIGHT, + Pause: KeyCode.PAUSE, + CapsLock: KeyCode.CAPSLOCK, + Escape: KeyCode.ESCAPE, + Space: KeyCode.SPACE, + PageUp: KeyCode.PAGEUP, + PageDown: KeyCode.PAGEDOWN, + End: KeyCode.END, + Home: KeyCode.HOME, + ArrowLeft: KeyCode.ARROW_LEFT, + ArrowUp: KeyCode.ARROW_UP, + ArrowRight: KeyCode.ARROW_RIGHT, + ArrowDown: KeyCode.ARROW_DOWN, + Insert: KeyCode.INSERT, + Delete: KeyCode.DELETE, + Digit0: KeyCode.DIGIT_0, + Digit1: KeyCode.DIGIT_1, + Digit2: KeyCode.DIGIT_2, + Digit3: KeyCode.DIGIT_3, + Digit4: KeyCode.DIGIT_4, + Digit5: KeyCode.DIGIT_5, + Digit6: KeyCode.DIGIT_6, + Digit7: KeyCode.DIGIT_7, + Digit8: KeyCode.DIGIT_8, + Digit9: KeyCode.DIGIT_9, + KeyA: KeyCode.KEY_A, + KeyB: KeyCode.KEY_B, + KeyC: KeyCode.KEY_C, + KeyD: KeyCode.KEY_D, + KeyE: KeyCode.KEY_E, + KeyF: KeyCode.KEY_F, + KeyG: KeyCode.KEY_G, + KeyH: KeyCode.KEY_H, + KeyI: KeyCode.KEY_I, + KeyJ: KeyCode.KEY_J, + KeyK: KeyCode.KEY_K, + KeyL: KeyCode.KEY_L, + KeyM: KeyCode.KEY_M, + KeyN: KeyCode.KEY_N, + KeyO: KeyCode.KEY_O, + KeyP: KeyCode.KEY_P, + KeyQ: KeyCode.KEY_Q, + KeyR: KeyCode.KEY_R, + KeyS: KeyCode.KEY_S, + KeyT: KeyCode.KEY_T, + KeyU: KeyCode.KEY_U, + KeyV: KeyCode.KEY_V, + KeyW: KeyCode.KEY_W, + KeyX: KeyCode.KEY_X, + KeyY: KeyCode.KEY_Y, + KeyZ: KeyCode.KEY_Z, + Numpad0: KeyCode.NUM_0, + Numpad1: KeyCode.NUM_1, + Numpad2: KeyCode.NUM_2, + Numpad3: KeyCode.NUM_3, + Numpad4: KeyCode.NUM_4, + Numpad5: KeyCode.NUM_5, + Numpad6: KeyCode.NUM_6, + Numpad7: KeyCode.NUM_7, + Numpad8: KeyCode.NUM_8, + Numpad9: KeyCode.NUM_9, + NumpadMultiply: KeyCode.NUM_MUTIPLY, + NumpadAdd: KeyCode.NUM_PLUS, + NumpadSubtract: KeyCode.NUM_SUBTRACT, + NumpadDecimal: KeyCode.NUM_DECIMAL, + NumpadDivide: KeyCode.NUM_DIVIDE, + NumpadEnter: KeyCode.NUM_ENTER, + F1: KeyCode.F1, + F2: KeyCode.F2, + F3: KeyCode.F3, + F4: KeyCode.F4, + F5: KeyCode.F5, + F6: KeyCode.F6, + F7: KeyCode.F7, + F8: KeyCode.F8, + F9: KeyCode.F9, + F10: KeyCode.F10, + F11: KeyCode.F11, + F12: KeyCode.F12, + NumLock: KeyCode.NUM_LOCK, + ScrollLock: KeyCode.SCROLLLOCK, + Semicolon: KeyCode.SEMICOLON, + Equal: KeyCode.EQUAL, + Comma: KeyCode.COMMA, + Minus: KeyCode.DASH, + Period: KeyCode.PERIOD, + Slash: KeyCode.SLASH, + Backquote: KeyCode.BACKQUOTE, + BracketLeft: KeyCode.BRACKET_LEFT, + Backslash: KeyCode.BACKSLASH, + BracketRight: KeyCode.BRACKET_RIGHT, + Quote: KeyCode.QUOTE, +}; + +function getKeyCode (code: string): KeyCode { + return code2KeyCode[code] || KeyCode.NONE; +} export class KeyboardInputSource { public support: boolean; @@ -14,28 +121,44 @@ export class KeyboardInputSource { private _registerEvent () { const canvas = document.getElementById('GameCanvas') as HTMLCanvasElement; - canvas?.addEventListener('keydown', this._createCallback(SystemEventType.KEY_DOWN)); - canvas?.addEventListener('keyup', this._createCallback(SystemEventType.KEY_UP)); - } - - private _createCallback (eventType: string) { - return (event: KeyboardEvent) => { - const inputEvent: KeyboardInputEvent = { - type: eventType, - code: event.keyCode, // TODO: keyCode is deprecated on Web standard - timestamp: performance.now(), - }; + canvas?.addEventListener('keydown', (event: any) => { event.stopPropagation(); event.preventDefault(); - this._eventTarget.emit(eventType, inputEvent); + if (!event.repeat) { + const keyDownInputEvent = this._getInputEvent(event, KeyboardEvent.KEY_DOWN); + this._eventTarget.emit(KeyboardEvent.KEY_DOWN, keyDownInputEvent); + } + // @ts-expect-error Compability for key pressing callback + const keyPressingInputEvent = this._getInputEvent(event, 'keydown'); + this._eventTarget.emit('keydown', keyPressingInputEvent); + }); + canvas?.addEventListener('keyup', (event: any) => { + const inputEvent = this._getInputEvent(event, KeyboardEvent.KEY_UP); + event.stopPropagation(); + event.preventDefault(); + this._eventTarget.emit(KeyboardEvent.KEY_UP, inputEvent); + }); + } + + private _getInputEvent (event: any, eventType: KeyboardEvent) { + const keyCode = getKeyCode(event.code); + const inputEvent: KeyboardInputEvent = { + type: eventType, + code: keyCode, + timestamp: performance.now(), }; + return inputEvent; } public onDown (cb: KeyboardCallback) { - this._eventTarget.on(SystemEventType.KEY_DOWN, cb); + this._eventTarget.on(KeyboardEvent.KEY_DOWN, cb); + } + + public onPressing (cb: KeyboardCallback) { + this._eventTarget.on('keydown', cb); } public onUp (cb: KeyboardCallback) { - this._eventTarget.on(SystemEventType.KEY_UP, cb); + this._eventTarget.on(KeyboardEvent.KEY_UP, cb); } } diff --git a/pal/input/web/mouse.ts b/pal/input/web/mouse.ts index 0ebfb9afb82..54985889dac 100644 --- a/pal/input/web/mouse.ts +++ b/pal/input/web/mouse.ts @@ -1,11 +1,8 @@ import { EDITOR, TEST } from 'internal:constants'; import { MouseCallback, MouseInputEvent, MouseWheelCallback, MouseWheelInputEvent } from 'pal/input'; -import { system } from 'pal/system'; +import { MouseEvent } from '../../../cocos/core/platform/event-manager/event-enum'; import { EventTarget } from '../../../cocos/core/event/event-target'; import { Rect, Vec2 } from '../../../cocos/core/math'; -import { SystemEventType } from '../../../cocos/core/platform/event-manager/event-enum'; - -type MouseEventNames = 'mousedown' | 'mouseup' | 'mousemove' | 'wheel'; export class MouseInputSource { public support: boolean; @@ -35,7 +32,7 @@ export class MouseInputSource { return new Rect(0, 0, 0, 0); } - private _getLocation (event: MouseEvent): Vec2 { + private _getLocation (event: any): Vec2 { return new Vec2(event.clientX, event.clientY); } @@ -44,14 +41,14 @@ export class MouseInputSource { window.addEventListener('mousedown', () => { this._isPressed = true; }); - this._canvas?.addEventListener('mousedown', this._createCallback(SystemEventType.MOUSE_DOWN)); + this._canvas?.addEventListener('mousedown', this._createCallback(MouseEvent.MOUSE_DOWN)); // register mouse move event - this._canvas?.addEventListener('mousemove', this._createCallback(SystemEventType.MOUSE_MOVE)); + this._canvas?.addEventListener('mousemove', this._createCallback(MouseEvent.MOUSE_MOVE)); // register mouse up event - window.addEventListener('mouseup', this._createCallback(SystemEventType.MOUSE_UP)); - this._canvas?.addEventListener('mouseup', this._createCallback(SystemEventType.MOUSE_UP)); + window.addEventListener('mouseup', this._createCallback(MouseEvent.MOUSE_UP)); + this._canvas?.addEventListener('mouseup', this._createCallback(MouseEvent.MOUSE_UP)); // register wheel event this._canvas?.addEventListener('wheel', (event: WheelEvent) => { @@ -59,7 +56,7 @@ export class MouseInputSource { const location = this._getLocation(event); const wheelSensitivityFactor = 5; const inputEvent: MouseWheelInputEvent = { - type: SystemEventType.MOUSE_WHEEL, + type: MouseEvent.MOUSE_WHEEL, x: location.x - canvasRect.x, y: canvasRect.y + canvasRect.height - location.y, button: event.button, // TODO: what is the button when tracking mouse move ? @@ -71,7 +68,7 @@ export class MouseInputSource { }; event.stopPropagation(); event.preventDefault(); - this._eventTarget.emit(SystemEventType.MOUSE_WHEEL, inputEvent); + this._eventTarget.emit(MouseEvent.MOUSE_WHEEL, inputEvent); }); this._registerPointerLockEvent(); } @@ -95,8 +92,8 @@ export class MouseInputSource { } } - private _createCallback (eventType: string) { - return (event: MouseEvent) => { + private _createCallback (eventType: MouseEvent) { + return (event: any) => { const canvasRect = this._getCanvasRect(); const location = this._getLocation(event); let button = event.button; @@ -118,8 +115,8 @@ export class MouseInputSource { } const inputEvent: MouseInputEvent = { type: eventType, - x: this._pointLocked ? (this._preMousePos.x + event.movementX) : (location.x - canvasRect.x), - y: this._pointLocked ? (this._preMousePos.y - event.movementY) : (canvasRect.y + canvasRect.height - location.y), + x: this._pointLocked ? (this._preMousePos.x + event.movementX) : (location.x - canvasRect.x), + y: this._pointLocked ? (this._preMousePos.y - event.movementY) : (canvasRect.y + canvasRect.height - location.y), button, timestamp: performance.now(), // this is web only property @@ -138,15 +135,15 @@ export class MouseInputSource { } onDown (cb: MouseCallback) { - this._eventTarget.on(SystemEventType.MOUSE_DOWN, cb); + this._eventTarget.on(MouseEvent.MOUSE_DOWN, cb); } onMove (cb: MouseCallback) { - this._eventTarget.on(SystemEventType.MOUSE_MOVE, cb); + this._eventTarget.on(MouseEvent.MOUSE_MOVE, cb); } onUp (cb: MouseCallback) { - this._eventTarget.on(SystemEventType.MOUSE_UP, cb); + this._eventTarget.on(MouseEvent.MOUSE_UP, cb); } onWheel (cb: MouseWheelCallback) { - this._eventTarget.on(SystemEventType.MOUSE_WHEEL, cb); + this._eventTarget.on(MouseEvent.MOUSE_WHEEL, cb); } } diff --git a/pal/input/web/touch.ts b/pal/input/web/touch.ts index f337d8be4b3..8fbfe53d58e 100644 --- a/pal/input/web/touch.ts +++ b/pal/input/web/touch.ts @@ -4,7 +4,7 @@ import { TEST } from 'internal:constants'; import { Rect, Vec2 } from '../../../cocos/core/math'; import { EventTarget } from '../../../cocos/core/event/event-target'; import { legacyCC } from '../../../cocos/core/global-exports'; -import { SystemEventType } from '../../../cocos/core/platform/event-manager/event-enum'; +import { TouchEvent } from '../../../cocos/core/platform/event-manager/event-enum'; export class TouchInputSource { public support: boolean; @@ -24,14 +24,14 @@ export class TouchInputSource { private _registerEvent () { // IDEA: need to register on window ? - this._canvas?.addEventListener('touchstart', this._createCallback(SystemEventType.TOUCH_START)); - this._canvas?.addEventListener('touchmove', this._createCallback(SystemEventType.TOUCH_MOVE)); - this._canvas?.addEventListener('touchend', this._createCallback(SystemEventType.TOUCH_END)); - this._canvas?.addEventListener('touchcancel', this._createCallback(SystemEventType.TOUCH_CANCEL)); + this._canvas?.addEventListener('touchstart', this._createCallback(TouchEvent.TOUCH_START)); + this._canvas?.addEventListener('touchmove', this._createCallback(TouchEvent.TOUCH_MOVE)); + this._canvas?.addEventListener('touchend', this._createCallback(TouchEvent.TOUCH_END)); + this._canvas?.addEventListener('touchcancel', this._createCallback(TouchEvent.TOUCH_CANCEL)); } - private _createCallback (eventType: string) { - return (event: TouchEvent) => { + private _createCallback (eventType: TouchEvent) { + return (event: any) => { const canvasRect = this._getCanvasRect(); const touchDataList: TouchData[] = []; const length = event.changedTouches.length; @@ -85,15 +85,15 @@ export class TouchInputSource { } public onStart (cb: TouchCallback) { - this._eventTarget.on(SystemEventType.TOUCH_START, cb); + this._eventTarget.on(TouchEvent.TOUCH_START, cb); } public onMove (cb: TouchCallback) { - this._eventTarget.on(SystemEventType.TOUCH_MOVE, cb); + this._eventTarget.on(TouchEvent.TOUCH_MOVE, cb); } public onEnd (cb: TouchCallback) { - this._eventTarget.on(SystemEventType.TOUCH_END, cb); + this._eventTarget.on(TouchEvent.TOUCH_END, cb); } public onCancel (cb: TouchCallback) { - this._eventTarget.on(SystemEventType.TOUCH_CANCEL, cb); + this._eventTarget.on(TouchEvent.TOUCH_CANCEL, cb); } } diff --git a/pal/system/enum-type/event.ts b/pal/system/enum-type/event.ts index 2e2dc51726d..026249a5b4d 100644 --- a/pal/system/enum-type/event.ts +++ b/pal/system/enum-type/event.ts @@ -1,6 +1,7 @@ export enum AppEvent { HIDE = 'hide', SHOW = 'show', + CLOSE = 'close', RESIZE = 'resize', ORIENTATION_CHANGE = 'orientation_change', } diff --git a/pal/system/minigame/system.ts b/pal/system/minigame/system.ts index b968f57dfc8..3cc1bdd72d9 100644 --- a/pal/system/minigame/system.ts +++ b/pal/system/minigame/system.ts @@ -183,12 +183,19 @@ class System { } } + public close () { + // TODO: minigame.exitMiniProgram() not implemented. + } + public onHide (cb: () => void) { this._eventTarget.on(AppEvent.HIDE, cb); } public onShow (cb: () => void) { this._eventTarget.on(AppEvent.SHOW, cb); } + public onClose (cb: () => void) { + this._eventTarget.on(AppEvent.CLOSE, cb); + } public onViewResize (cb: () => void) { this._eventTarget.on(AppEvent.RESIZE, cb); } @@ -202,6 +209,9 @@ class System { public offShow (cb?: () => void) { this._eventTarget.off(AppEvent.SHOW, cb); } + public offClose (cb?: () => void) { + this._eventTarget.off(AppEvent.CLOSE, cb); + } public offViewResize (cb?: () => void) { this._eventTarget.off(AppEvent.RESIZE, cb); } diff --git a/pal/system/native/system.ts b/pal/system/native/system.ts index 20f8fcaeba9..8585af48e6e 100644 --- a/pal/system/native/system.ts +++ b/pal/system/native/system.ts @@ -112,6 +112,9 @@ class System { jsb.onResume = () => { this._eventTarget.emit(AppEvent.SHOW); }; + jsb.onClose = () => { + this._eventTarget.emit(AppEvent.CLOSE); + }; } public getViewSize (): Size { @@ -167,12 +170,20 @@ class System { __restartVM(); } + public close () { + // @ts-expect-error __close() is defined in JSB + __close(); + } + public onHide (cb: () => void) { this._eventTarget.on(AppEvent.HIDE, cb); } public onShow (cb: () => void) { this._eventTarget.on(AppEvent.SHOW, cb); } + public onClose (cb: () => void) { + this._eventTarget.on(AppEvent.CLOSE, cb); + } public onViewResize (cb: () => void) { this._eventTarget.on(AppEvent.RESIZE, cb); } @@ -186,6 +197,9 @@ class System { public offShow (cb?: () => void) { this._eventTarget.off(AppEvent.SHOW, cb); } + public offClose (cb?: () => void) { + this._eventTarget.off(AppEvent.CLOSE, cb); + } public offViewResize (cb?: () => void) { this._eventTarget.off(AppEvent.RESIZE, cb); } diff --git a/pal/system/web/system.ts b/pal/system/web/system.ts index 13c1461b02d..3c4102b5543 100644 --- a/pal/system/web/system.ts +++ b/pal/system/web/system.ts @@ -309,12 +309,20 @@ class System { } } + public close () { + this._eventTarget.emit(AppEvent.CLOSE); + window.close(); + } + public onHide (cb: () => void) { this._eventTarget.on(AppEvent.HIDE, cb); } public onShow (cb: () => void) { this._eventTarget.on(AppEvent.SHOW, cb); } + public onClose (cb: () => void) { + this._eventTarget.on(AppEvent.CLOSE, cb); + } public onViewResize (cb: () => void) { this._eventTarget.on(AppEvent.RESIZE, cb); } @@ -328,6 +336,9 @@ class System { public offShow (cb?: () => void) { this._eventTarget.off(AppEvent.SHOW, cb); } + public offClose (cb?: () => void) { + this._eventTarget.off(AppEvent.CLOSE, cb); + } public offViewResize (cb?: () => void) { this._eventTarget.off(AppEvent.RESIZE, cb); } diff --git a/platforms/native/engine/jsb-gfx.js b/platforms/native/engine/jsb-gfx.js index 45d00abadb3..730ec24649c 100644 --- a/platforms/native/engine/jsb-gfx.js +++ b/platforms/native/engine/jsb-gfx.js @@ -47,10 +47,8 @@ let _converters = { } }, DeviceInfo: function (info) { - let width = cc.game.canvas.width, - height = cc.game.canvas.height, - handler = window.windowHandler; - return new gfx.DeviceInfo(info.isAntiAlias, handler, width, height, info.nativeWidth, info.nativeHeight, null, info.bindingMappingInfo); + let handler = window.windowHandler; + return new gfx.DeviceInfo(info.isAntialias, handler, info.width, info.height, info.devicePixelRatio, info.bindingMappingInfo); } }; @@ -116,35 +114,36 @@ function replace (proto, replacements) { // Cache dirty to avoid invoking gfx.DescriptorSet.update(). let descriptorSetProto = gfx.DescriptorSet.prototype; -descriptorSetProto.bindBuffer = function(binding, buffer, index) { +descriptorSetProto.bindBuffer = function (binding, buffer, index) { this.dirtyJSB = descriptorSetProto.bindBufferJSB.call(this, binding, buffer, index || 0); } -descriptorSetProto.bindSampler = function(binding, sampler, index) { +descriptorSetProto.bindSampler = function (binding, sampler, index) { this.dirtyJSB = descriptorSetProto.bindSamplerJSB.call(this, binding, sampler, index || 0); } -descriptorSetProto.bindTexture = function(bindding, texture, index) { +descriptorSetProto.bindTexture = function (bindding, texture, index) { this.dirtyJSB = descriptorSetProto.bindTextureJSB.call(this, bindding, texture, index || 0); } let oldDSUpdate = descriptorSetProto.update; -descriptorSetProto.update = function() { +descriptorSetProto.update = function () { if (!this.dirtyJSB) return; oldDSUpdate.call(this); this.dirtyJSB = false; } -let deviceProto = gfx.deviceInstance.__proto__; -replace(deviceProto, { - initialize: replaceFunction('_initialize', _converters.DeviceInfo), +replace(gfx.DeviceManager, { + create: replaceFunction('_create', _converters.DeviceInfo), }); +let deviceProto = gfx.Device.prototype; + let oldCopyTexImagesToTextureFunc = deviceProto.copyTexImagesToTexture; -deviceProto.copyTexImagesToTexture = function(texImages, texture, regions) { +deviceProto.copyTexImagesToTexture = function (texImages, texture, regions) { let images = _converters.texImagesToBuffers(texImages); oldCopyTexImagesToTextureFunc.call(this, images, texture, regions); } let oldDeviceCreatBufferFun = deviceProto.createBuffer; -deviceProto.createBuffer = function(info) { +deviceProto.createBuffer = function (info) { let buffer; if (info.buffer) { buffer = oldDeviceCreatBufferFun.call(this, info, true); @@ -156,7 +155,7 @@ deviceProto.createBuffer = function(info) { } let oldDeviceCreatTextureFun = deviceProto.createTexture; -deviceProto.createTexture = function(info) { +deviceProto.createTexture = function (info) { if (info.texture) { return oldDeviceCreatTextureFun.call(this, info, true); } else { @@ -181,8 +180,8 @@ cc.js.get(shaderProto, 'id', function () { let bufferProto = gfx.Buffer.prototype; let oldUpdate = bufferProto.update; -bufferProto.update = function(buffer, size) { - if(buffer.byteLength === 0) return; +bufferProto.update = function (buffer, size) { + if (buffer.byteLength === 0) return; let buffSize; if (this.cachedUsage & 0x40) { // BufferUsageBit.INDIRECT @@ -204,7 +203,7 @@ bufferProto.update = function(buffer, size) { } buffSize = buffer.byteLength; - } else if (size !== undefined ) { + } else if (size !== undefined) { buffSize = size; } else { buffSize = buffer.byteLength; @@ -214,7 +213,7 @@ bufferProto.update = function(buffer, size) { } let oldBufferInitializeFunc = bufferProto.initialize; -bufferProto.initialize = function(info) { +bufferProto.initialize = function (info) { if (info.buffer) { oldBufferInitializeFunc.call(this, info, true); } else { @@ -224,7 +223,7 @@ bufferProto.initialize = function(info) { let textureProto = gfx.Texture.prototype; let oldTextureInitializeFunc = textureProto.initialize; -textureProto.initialize = function(info) { +textureProto.initialize = function (info) { if (info.texture) { oldTextureInitializeFunc.call(this, info, true); } else { diff --git a/platforms/native/engine/jsb-physics.js b/platforms/native/engine/jsb-physics.js index cdb4033ce2e..4b05d049d03 100644 --- a/platforms/native/engine/jsb-physics.js +++ b/platforms/native/engine/jsb-physics.js @@ -189,12 +189,10 @@ class PhysicsWorld { } syncSceneToPhysics () { - books.forEach((v) => { v.updateWorldTransform(); }); this._impl.syncSceneToPhysics(); } syncAfterEvents () { - books.forEach((v) => { v.syncFromNativeTransform(); }); // this._impl.syncSceneToPhysics() } @@ -290,7 +288,7 @@ class RigidBody { initialize (v) { v.node.updateWorldTransform(); this._com = v; - this._impl.initialize(v.node.handle, v.type, v._group); + this._impl.initialize(v.node.native, v.type, v._group); bookNode(v.node); } @@ -367,7 +365,7 @@ class Shape { initialize (v) { v.node.updateWorldTransform(); this._com = v; - this._impl.initialize(v.node.handle); + this._impl.initialize(v.node.native); ptrToObj[this._impl.getImpl()] = this; bookNode(v.node); } @@ -580,7 +578,7 @@ class Joint { setConnectedBody (v) { this._impl.setConnectedBody(v ? v.body.impl.getNodeHandle() : 0); } initialize (v) { this._com = v; - this._impl.initialize(v.node.handle); + this._impl.initialize(v.node.native); ptrToObj[this._impl.getImpl()] = this; this.onLoad(); } diff --git a/platforms/runtime/platforms/cocos-runtime/engine/index.js b/platforms/runtime/platforms/cocos-runtime/engine/index.js deleted file mode 100644 index 15d34b77a68..00000000000 --- a/platforms/runtime/platforms/cocos-runtime/engine/index.js +++ /dev/null @@ -1 +0,0 @@ -require('../../../common/engine/index'); \ No newline at end of file diff --git a/platforms/runtime/platforms/cocos-runtime/ral.js b/platforms/runtime/platforms/cocos-runtime/ral.js deleted file mode 100644 index 04760cb310c..00000000000 --- a/platforms/runtime/platforms/cocos-runtime/ral.js +++ /dev/null @@ -1,1297 +0,0 @@ -(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i= 0) { - _copyObject(touch, _touches[index]); - } else { - var tmp = {}; - - _copyObject(touch, tmp); - - _touches.push(tmp); - } - }); - } else if (type === "touchmove") { - changedTouches.forEach(function (element) { - index = _getTouchIndex(element); - - if (index >= 0) { - _copyObject(element, _touches[index]); - } - }); - } else if (type === "touchend" || type === "touchcancel") { - changedTouches.forEach(function (element) { - index = _getTouchIndex(element); - - if (index >= 0) { - _touches.splice(index, 1); - } - }); - } - - var touches = [].concat(_touches); - var _changedTouches = []; - changedTouches.forEach(function (touch) { - var length = touches.length; - - for (var _index = 0; _index < length; ++_index) { - var _touch = touches[_index]; - - if (touch.identifier === _touch.identifier) { - _changedTouches.push(_touch); - - return; - } - } - - _changedTouches.push(touch); - }); - touchEvent.touches = touches; - touchEvent.targetTouches = touches; - touchEvent.changedTouches = _changedTouches; - - if (_hasDellWith) { - touches.forEach(function (touch) { - touch.clientX /= window.devicePixelRatio; - touch.clientY /= window.devicePixelRatio; - touch.pageX /= window.devicePixelRatio; - touch.pageY /= window.devicePixelRatio; - }); - - if (type === "touchcancel" || type === "touchend") { - _changedTouches.forEach(function (touch) { - touch.clientX /= window.devicePixelRatio; - touch.clientY /= window.devicePixelRatio; - touch.pageX /= window.devicePixelRatio; - touch.pageY /= window.devicePixelRatio; - }); - } - } - - var listenerArr = _listenerMap[type]; - var length = listenerArr.length; - - for (var _index2 = 0; _index2 < length; _index2++) { - listenerArr[_index2](touchEvent); - } - }; -}; - -if (_rt.onTouchStart) { - ral.onTouchStart = _rt.onTouchStart; - ral.offTouchStart = _rt.offTouchStart; -} else { - _jsb.onTouchStart = _touchEventHandlerFactory('touchstart'); - - _jsb.offTouchStart = function (callback) { - _removeListener("touchstart", callback); - }; - - ral.onTouchStart = _jsb.onTouchStart.bind(_jsb); - ral.offTouchStart = _jsb.offTouchStart.bind(_jsb); -} - -if (_rt.onTouchMove) { - ral.onTouchMove = _rt.onTouchMove; - ral.offTouchMove = _rt.offTouchMove; -} else { - _jsb.onTouchMove = _touchEventHandlerFactory('touchmove'); - - _jsb.offTouchMove = function (callback) { - _removeListener("touchmove", callback); - }; - - ral.onTouchMove = _jsb.onTouchMove.bind(_jsb); - ral.offTouchMove = _jsb.offTouchMove.bind(_jsb); -} - -if (_rt.onTouchCancel) { - ral.onTouchCancel = _rt.onTouchCancel; - ral.offTouchCancel = _rt.offTouchCancel; -} else { - _jsb.onTouchCancel = _touchEventHandlerFactory('touchcancel'); - - _jsb.offTouchCancel = function (callback) { - _removeListener("touchcancel", callback); - }; - - ral.onTouchCancel = _jsb.onTouchCancel.bind(_jsb); - ral.offTouchCancel = _jsb.offTouchCancel.bind(_jsb); -} - -if (_rt.onTouchEnd) { - ral.onTouchEnd = _rt.onTouchEnd; - ral.offTouchEnd = _rt.offTouchEnd; -} else { - _jsb.onTouchEnd = _touchEventHandlerFactory('touchend'); - - _jsb.offTouchEnd = function (callback) { - _removeListener("touchend", callback); - }; - - ral.onTouchEnd = _jsb.onTouchEnd.bind(_jsb); - ral.offTouchEnd = _jsb.offTouchEnd.bind(_jsb); -} - -},{}],5:[function(require,module,exports){ -"use strict"; - -var _util = _interopRequireDefault(require("../../util")); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } - -var _rt = loadRuntime(); - -var _listeners = []; -ral.device = ral.device || {}; - -if (_rt.offAccelerometerChange) { - ral.onAccelerometerChange = _rt.onAccelerometerChange.bind(_rt); - ral.offAccelerometerChange = _rt.offAccelerometerChange.bind(_rt); - ral.stopAccelerometer = _rt.stopAccelerometer.bind(_rt); - - var _startAccelerometer = _rt.startAccelerometer.bind(_rt); - - ral.startAccelerometer = function (obj) { - return _startAccelerometer(Object.assign({ - type: "accelerationIncludingGravity" - }, obj)); - }; -} else { - ral.onAccelerometerChange = function (listener) { - if (typeof listener === "function") { - var length = _listeners.length; - - for (var index = 0; index < length; ++index) { - if (listener === _listeners[index]) { - return; - } - } - - _listeners.push(listener); - } - }; - - ral.offAccelerometerChange = function (listener) { - var length = _listeners.length; - - for (var index = 0; index < length; ++index) { - if (listener === _listeners[index]) { - _listeners.splice(index, 1); - - return; - } - } - }; - - var _systemInfo = _rt.getSystemInfoSync(); - - var _isAndroid = _systemInfo.platform.toLowerCase() === "android"; - - jsb.device.dispatchDeviceMotionEvent = function (event) { - var acceleration = Object.assign({}, event._accelerationIncludingGravity); - - if (_isAndroid) { - acceleration.x /= -10; - acceleration.y /= -10; - acceleration.z /= -10; - } else { - acceleration.x /= 10; - acceleration.y /= 10; - acceleration.z /= 10; - } - - _listeners.forEach(function (listener) { - listener({ - x: acceleration.x, - y: acceleration.y, - z: acceleration.z - }); - }); - }; - - ral.stopAccelerometer = function () { - jsb.device.setMotionEnabled(false); - }; - - ral.startAccelerometer = function () { - jsb.device.setMotionEnabled(true); - }; -} - -},{"../../util":21}],6:[function(require,module,exports){ -"use strict"; - -var _util = _interopRequireDefault(require("../../util")); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } - -var _rt = loadRuntime(); - -_util["default"].exportTo("getBatteryInfo", _rt, ral); - -_util["default"].exportTo("getBatteryInfoSync", _rt, ral); - -},{"../../util":21}],7:[function(require,module,exports){ -"use strict"; - -var _util = _interopRequireDefault(require("../../util")); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } - -var _rt = loadRuntime(); - -_util["default"].exportTo("getFileSystemManager", _rt, ral); - -},{"../../util":21}],8:[function(require,module,exports){ -"use strict"; - -var _util = _interopRequireDefault(require("../util")); - -var _feature = _interopRequireDefault(require("../feature")); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } - -if (window.jsb) { - window.ral = Object.assign({}, window.jsb); -} else { - window.ral = {}; -} - -require("./base/lifecycle"); - -require("./base/subpackage"); - -require("./base/system-info"); - -require("./base/touch-event"); - -require("./device/accelerometer"); - -require("./device/battery"); - -require("./file/file-system-manager"); - -require("./interface/keyboard"); - -require("./interface/window"); - -require("./media/audio"); - -require("./media/video"); - -require("./network/download"); - -require("./rendering/canvas"); - -require("./rendering/webgl"); - -require("./rendering/font"); - -require("./rendering/frame"); - -require("./rendering/image"); - -_util["default"].exportTo("getFeatureProperty", _feature["default"], ral); - -},{"../feature":19,"../util":21,"./base/lifecycle":1,"./base/subpackage":2,"./base/system-info":3,"./base/touch-event":4,"./device/accelerometer":5,"./device/battery":6,"./file/file-system-manager":7,"./interface/keyboard":9,"./interface/window":10,"./media/audio":11,"./media/video":12,"./network/download":13,"./rendering/canvas":14,"./rendering/font":15,"./rendering/frame":16,"./rendering/image":17,"./rendering/webgl":18}],9:[function(require,module,exports){ -"use strict"; - -var _util = _interopRequireDefault(require("../../util")); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } - -var _rt = loadRuntime(); - -_util["default"].exportTo("onKeyboardInput", _rt, ral); - -_util["default"].exportTo("onKeyboardConfirm", _rt, ral); - -_util["default"].exportTo("onKeyboardComplete", _rt, ral); - -_util["default"].exportTo("offKeyboardInput", _rt, ral); - -_util["default"].exportTo("offKeyboardConfirm", _rt, ral); - -_util["default"].exportTo("offKeyboardComplete", _rt, ral); - -_util["default"].exportTo("hideKeyboard", _rt, ral); - -_util["default"].exportTo("showKeyboard", _rt, ral); - -_util["default"].exportTo("updateKeyboard", _rt, ral); - -},{"../../util":21}],10:[function(require,module,exports){ -"use strict"; - -var _rt = loadRuntime(); - -var _onWindowResize = _rt.onWindowResize; - -ral.onWindowResize = function (callBack) { - _onWindowResize(function (size) { - callBack(size.width || size.windowWidth, size.height || size.windowHeight); - }); -}; - -},{}],11:[function(require,module,exports){ -"use strict"; - -var _innerContext = _interopRequireDefault(require("../../inner-context")); - -var _util = _interopRequireDefault(require("../../util")); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } - -var _rt = loadRuntime(); - -_util["default"].exportTo("AudioEngine", _rt, ral); - -_util["default"].exportTo("createInnerAudioContext", _rt, ral, function () { - if (_rt.AudioEngine) { - ral.createInnerAudioContext = function () { - return (0, _innerContext["default"])(_rt.AudioEngine); - }; - } -}); - -},{"../../inner-context":20,"../../util":21}],12:[function(require,module,exports){ -"use strict"; - -var _util = _interopRequireDefault(require("../../util")); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } - -var _rt = loadRuntime(); - -_util["default"].exportTo("createVideo", _rt, ral); - -},{"../../util":21}],13:[function(require,module,exports){ -"use strict"; - -var _util = _interopRequireDefault(require("../../util")); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } - -var _rt = loadRuntime(); - -_util["default"].exportTo("downloadFile", _rt, ral); - -},{"../../util":21}],14:[function(require,module,exports){ -"use strict"; - -var _util = _interopRequireDefault(require("../../util")); - -var _feature = _interopRequireDefault(require("../../feature")); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } - -var _rt = loadRuntime(); - -_util["default"].exportTo("createCanvas", _rt, ral, function () { - var featureValue = "unsupported"; - - if (document && typeof document.createElement === "function") { - featureValue = "wrapper"; - - ral.createCanvas = function () { - return document.createElement("canvas"); - }; - } - - _feature["default"].setFeature("ral.createCanvas", "spec", featureValue); -}); - -},{"../../feature":19,"../../util":21}],15:[function(require,module,exports){ -"use strict"; - -var _util = _interopRequireDefault(require("../../util")); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } - -var _rt = loadRuntime(); - -_util["default"].exportTo("loadFont", _rt, ral); - -},{"../../util":21}],16:[function(require,module,exports){ -"use strict"; - -var _rt = loadRuntime(); - -if (window.jsb && jsb.setPreferredFramesPerSecond) { - ral.setPreferredFramesPerSecond = jsb.setPreferredFramesPerSecond.bind(jsb); -} else if (_rt.setPreferredFramesPerSecond) { - ral.setPreferredFramesPerSecond = _rt.setPreferredFramesPerSecond.bind(_rt); -} else { - ral.setPreferredFramesPerSecond = function () { - console.error("The setPreferredFramesPerSecond is not define!"); - }; -} - -},{}],17:[function(require,module,exports){ -"use strict"; - -var _util = _interopRequireDefault(require("../../util")); - -var _feature = _interopRequireDefault(require("../../feature")); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } - -var _rt = loadRuntime(); - -_util["default"].exportTo("loadImageData", _rt, ral); - -_util["default"].exportTo("createImage", _rt, ral, function () { - var featureValue = "unsupported"; - - if (document && typeof document.createElement === "function") { - featureValue = "wrapper"; - - ral.createImage = function () { - return document.createElement("image"); - }; - } - - _feature["default"].setFeature("ral.createImage", "spec", featureValue); -}); - -},{"../../feature":19,"../../util":21}],18:[function(require,module,exports){ -"use strict"; - -if (window.__gl) { - var gl = window.__gl; - var _glTexImage2D = gl.texImage2D; - - gl.texImage2D = function (target, level, internalformat, width, height, border, format, type, pixels) { - var argc = arguments.length; - - if (argc === 6) { - var image = border; - type = height; - format = width; - - if (image instanceof HTMLImageElement) { - var error = console.error; - - console.error = function () {}; - - _glTexImage2D.apply(void 0, arguments); - - console.error = error; - gl.texImage2D_image(target, level, image._imageMeta); - } else if (image instanceof HTMLCanvasElement) { - var _error = console.error; - - console.error = function () {}; - - _glTexImage2D.apply(void 0, arguments); - - console.error = _error; - var context2D = image.getContext('2d'); - gl.texImage2D_canvas(target, level, internalformat, format, type, context2D); - } else if (image instanceof ImageData) { - var _error2 = console.error; - - console.error = function () {}; - - _glTexImage2D(target, level, internalformat, image.width, image.height, 0, format, type, image.data); - - console.error = _error2; - } else { - console.error("Invalid pixel argument passed to gl.texImage2D!"); - } - } else if (argc === 9) { - _glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); - } else { - console.error("gl.texImage2D: invalid argument count!"); - } - }; - - var _glTexSubImage2D = gl.texSubImage2D; - - gl.texSubImage2D = function (target, level, xoffset, yoffset, width, height, format, type, pixels) { - var argc = arguments.length; - - if (argc === 7) { - var image = format; - type = height; - format = width; - - if (image instanceof HTMLImageElement) { - var error = console.error; - - console.error = function () {}; - - _glTexSubImage2D.apply(void 0, arguments); - - console.error = error; - gl.texSubImage2D_image(target, level, xoffset, yoffset, image._imageMeta); - } else if (image instanceof HTMLCanvasElement) { - var _error3 = console.error; - - console.error = function () {}; - - _glTexSubImage2D.apply(void 0, arguments); - - console.error = _error3; - var context2D = image.getContext('2d'); - gl.texSubImage2D_canvas(target, level, xoffset, yoffset, format, type, context2D); - } else if (image instanceof ImageData) { - var _error4 = console.error; - - console.error = function () {}; - - _glTexSubImage2D(target, level, xoffset, yoffset, image.width, image.height, format, type, image.data); - - console.error = _error4; - } else { - console.error("Invalid pixel argument passed to gl.texImage2D!"); - } - } else if (argc === 9) { - _glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); - } else { - console.error(new Error("gl.texImage2D: invalid argument count!").stack); - } - }; -} - -},{}],19:[function(require,module,exports){ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports["default"] = void 0; -var _features = {}; -var _default = { - setFeature: function setFeature(featureName, property, value) { - var feature = _features[featureName]; - - if (!feature) { - feature = _features[featureName] = {}; - } - - feature[property] = value; - }, - getFeatureProperty: function getFeatureProperty(featureName, property) { - var feature = _features[featureName]; - return feature ? feature[property] : undefined; - } -}; -exports["default"] = _default; - -},{}],20:[function(require,module,exports){ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports["default"] = _default; -var _CANPLAY_CALLBACK = "canplayCallbacks"; -var _ENDED_CALLBACK = "endedCallbacks"; -var _ERROR_CALLBACK = "errorCallbacks"; -var _PAUSE_CALLBACK = "pauseCallbacks"; -var _PLAY_CALLBACK = "playCallbacks"; -var _SEEKED_CALLBACK = "seekedCallbacks"; -var _SEEKING_CALLBACK = "seekingCallbacks"; -var _STOP_CALLBACK = "stopCallbacks"; -var _TIME_UPDATE_CALLBACK = "timeUpdateCallbacks"; -var _WAITING_CALLBACK = "waitingCallbacks"; -var _ERROR_CODE = { - ERROR_SYSTEM: 10001, - ERROR_NET: 10002, - ERROR_FILE: 10003, - ERROR_FORMAT: 10004, - ERROR_UNKNOWN: -1 -}; -var _STATE = { - ERROR: -1, - INITIALIZING: 0, - PLAYING: 1, - PAUSED: 2 -}; -var _audioEngine = undefined; - -var _weakMap = new WeakMap(); - -var _offCallback = function _offCallback(target, type, callback) { - var privateThis = _weakMap.get(target); - - if (typeof callback !== "function" || !privateThis) { - return -1; - } - - var callbacks = privateThis[type] || []; - - for (var i = 0, len = callbacks.length; i < len; ++i) { - if (callback === callbacks[i]) { - callbacks.splice(i, 1); - return callback.length + 1; - } - } - - return 0; -}; - -var _onCallback = function _onCallback(target, type, callback) { - var privateThis = _weakMap.get(target); - - if (typeof callback !== "function" || !privateThis) { - return -1; - } - - var callbacks = privateThis[type]; - - if (!callbacks) { - callbacks = privateThis[type] = [callback]; - } else { - for (var i = 0, len = callbacks.length; i < len; ++i) { - if (callback === callbacks[i]) { - return 0; - } - } - - callbacks.push(callback); - } - - return callbacks.length; -}; - -var _dispatchCallback = function _dispatchCallback(target, type) { - var args = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : []; - - var privateThis = _weakMap.get(target); - - if (privateThis) { - var callbacks = privateThis[type] || []; - - for (var i = 0, len = callbacks.length; i < len; ++i) { - callbacks[i].apply(target, args); - } - } -}; - -function InnerAudioContext() { - this.startTime = 0; - this.autoplay = false; - - _weakMap.set(this, { - src: "", - volume: 1, - loop: false - }); - - Object.defineProperty(this, "loop", { - set: function set(value) { - value = !!value; - - var privateThis = _weakMap.get(this); - - if (privateThis) { - var audioID = privateThis.audioID; - - if (typeof audioID === "number" && audioID >= 0) { - _audioEngine.setLoop(audioID, value); - } - - privateThis.loop = value; - } - }, - get: function get() { - var privateThis = _weakMap.get(this); - - return privateThis ? privateThis.loop : false; - } - }); - Object.defineProperty(this, "volume", { - set: function set(value) { - if (typeof value === "number") { - if (value < 0) { - value = 0; - } else if (value > 1) { - value = 1; - } - } else { - value = 1; - } - - var privateThis = _weakMap.get(this); - - if (privateThis) { - var audioID = privateThis.audioID; - - if (typeof audioID === "number" && audioID >= 0) { - _audioEngine.setVolume(audioID, value); - } - - privateThis.volume = value; - } - }, - get: function get() { - var privateThis = _weakMap.get(this); - - return privateThis ? privateThis.volume : 1; - } - }); - Object.defineProperty(this, "src", { - set: function set(value) { - var privateThis = _weakMap.get(this); - - if (!privateThis) { - return; - } - - var oldSrc = privateThis.src; - privateThis.src = value; - - if (typeof value === "string") { - var audioID = privateThis.audioID; - - if (typeof audioID === "number" && audioID >= 0 && _audioEngine.getState(audioID) === _STATE.PAUSED && oldSrc !== value) { - _audioEngine.stop(audioID); - - privateThis.audioID = -1; - } - - var self = this; - - _audioEngine.preload(value, function () { - setTimeout(function () { - if (self.src === value) { - _dispatchCallback(self, _CANPLAY_CALLBACK); - - if (self.autoplay) { - self.play(); - } - } - }); - }); - } - }, - get: function get() { - var privateThis = _weakMap.get(this); - - return privateThis ? privateThis.src : ""; - } - }); - Object.defineProperty(this, "duration", { - get: function get() { - var privateThis = _weakMap.get(this); - - if (privateThis) { - var audioID = privateThis.audioID; - - if (typeof audioID === "number" && audioID >= 0) { - return _audioEngine.getDuration(audioID); - } - } - - return NaN; - }, - set: function set() {} - }); - Object.defineProperty(this, "currentTime", { - get: function get() { - var privateThis = _weakMap.get(this); - - if (privateThis) { - var audioID = privateThis.audioID; - - if (typeof audioID === "number" && audioID >= 0) { - return _audioEngine.getCurrentTime(audioID); - } - } - - return 0; - }, - set: function set() {} - }); - Object.defineProperty(this, "paused", { - get: function get() { - var privateThis = _weakMap.get(this); - - if (privateThis) { - var audioID = privateThis.audioID; - - if (typeof audioID === "number" && audioID >= 0) { - return _audioEngine.getState(audioID) === _STATE.PAUSED; - } - } - - return true; - }, - set: function set() {} - }); - Object.defineProperty(this, "buffered", { - get: function get() { - var privateThis = _weakMap.get(this); - - if (privateThis) { - var audioID = privateThis.audioID; - - if (typeof audioID === "number" && audioID >= 0) { - return _audioEngine.getBuffered(audioID); - } - } - - return 0; - }, - set: function set() {} - }); -} - -var _prototype = InnerAudioContext.prototype; - -_prototype.destroy = function () { - var privateThis = _weakMap.get(this); - - if (privateThis) { - var audioID = privateThis.audioID; - - if (typeof audioID === "number" && audioID >= 0) { - _audioEngine.stop(audioID); - - privateThis.audioID = -1; - - _dispatchCallback(this, _STOP_CALLBACK); - } - - privateThis[_CANPLAY_CALLBACK] = []; - privateThis[_ENDED_CALLBACK] = []; - privateThis[_ERROR_CALLBACK] = []; - privateThis[_PAUSE_CALLBACK] = []; - privateThis[_PLAY_CALLBACK] = []; - privateThis[_SEEKED_CALLBACK] = []; - privateThis[_SEEKING_CALLBACK] = []; - privateThis[_STOP_CALLBACK] = []; - privateThis[_TIME_UPDATE_CALLBACK] = []; - privateThis[_WAITING_CALLBACK] = []; - clearInterval(privateThis.intervalID); - } -}; - -_prototype.play = function () { - var privateThis = _weakMap.get(this); - - if (!privateThis) { - return; - } - - var src = privateThis.src; - var audioID = privateThis.audioID; - - if (typeof src !== "string" || src === "") { - _dispatchCallback(this, _ERROR_CALLBACK, [{ - errMsg: "invalid src", - errCode: _ERROR_CODE.ERROR_FILE - }]); - - return; - } - - if (typeof audioID === "number" && audioID >= 0) { - if (_audioEngine.getState(audioID) === _STATE.PAUSED) { - _audioEngine.resume(audioID); - - _dispatchCallback(this, _PLAY_CALLBACK); - - return; - } else { - _audioEngine.stop(audioID); - - privateThis.audioID = -1; - } - } - - audioID = _audioEngine.play(src, this.loop, this.volume); - - if (audioID === -1) { - _dispatchCallback(this, _ERROR_CALLBACK, [{ - errMsg: "unknown", - errCode: _ERROR_CODE.ERROR_UNKNOWN - }]); - - return; - } - - privateThis.audioID = audioID; - - if (typeof this.startTime === "number" && this.startTime > 0) { - _audioEngine.setCurrentTime(audioID, this.startTime); - } - - _dispatchCallback(this, _WAITING_CALLBACK); - - var self = this; - - _audioEngine.setCanPlayCallback(audioID, function () { - if (src === self.src) { - _dispatchCallback(self, _CANPLAY_CALLBACK); - - _dispatchCallback(self, _PLAY_CALLBACK); - } - }); - - _audioEngine.setWaitingCallback(audioID, function () { - if (src === self.src) { - _dispatchCallback(self, _WAITING_CALLBACK); - } - }); - - _audioEngine.setErrorCallback(audioID, function () { - if (src === self.src) { - privateThis.audioID = -1; - - _dispatchCallback(self, _ERROR_CALLBACK); - } - }); - - _audioEngine.setFinishCallback(audioID, function () { - if (src === self.src) { - privateThis.audioID = -1; - - _dispatchCallback(self, _ENDED_CALLBACK); - } - }); -}; - -_prototype.pause = function () { - var privateThis = _weakMap.get(this); - - if (privateThis) { - var audioID = privateThis.audioID; - - if (typeof audioID === "number" && audioID >= 0) { - _audioEngine.pause(audioID); - - _dispatchCallback(this, _PAUSE_CALLBACK); - } - } -}; - -_prototype.seek = function (position) { - var privateThis = _weakMap.get(this); - - if (privateThis && typeof position === "number" && position >= 0) { - var audioID = privateThis.audioID; - - if (typeof audioID === "number" && audioID >= 0) { - _audioEngine.setCurrentTime(audioID, position); - - _dispatchCallback(this, _SEEKING_CALLBACK); - - _dispatchCallback(this, _SEEKED_CALLBACK); - } - } -}; - -_prototype.stop = function () { - var privateThis = _weakMap.get(this); - - if (privateThis) { - var audioID = privateThis.audioID; - - if (typeof audioID === "number" && audioID >= 0) { - _audioEngine.stop(audioID); - - privateThis.audioID = -1; - - _dispatchCallback(this, _STOP_CALLBACK); - } - } -}; - -_prototype.offCanplay = function (callback) { - _offCallback(this, _CANPLAY_CALLBACK, callback); -}; - -_prototype.offEnded = function (callback) { - _offCallback(this, _ENDED_CALLBACK, callback); -}; - -_prototype.offError = function (callback) { - _offCallback(this, _ERROR_CALLBACK, callback); -}; - -_prototype.offPause = function (callback) { - _offCallback(this, _PAUSE_CALLBACK, callback); -}; - -_prototype.offPlay = function (callback) { - _offCallback(this, _PLAY_CALLBACK, callback); -}; - -_prototype.offSeeked = function (callback) { - _offCallback(this, _SEEKED_CALLBACK, callback); -}; - -_prototype.offSeeking = function (callback) { - _offCallback(this, _SEEKING_CALLBACK, callback); -}; - -_prototype.offStop = function (callback) { - _offCallback(this, _STOP_CALLBACK, callback); -}; - -_prototype.offTimeUpdate = function (callback) { - var result = _offCallback(this, _TIME_UPDATE_CALLBACK, callback); - - if (result === 1) { - clearInterval(_weakMap.get(this).intervalID); - } -}; - -_prototype.offWaiting = function (callback) { - _offCallback(this, _WAITING_CALLBACK, callback); -}; - -_prototype.onCanplay = function (callback) { - _onCallback(this, _CANPLAY_CALLBACK, callback); -}; - -_prototype.onEnded = function (callback) { - _onCallback(this, _ENDED_CALLBACK, callback); -}; - -_prototype.onError = function (callback) { - _onCallback(this, _ERROR_CALLBACK, callback); -}; - -_prototype.onPause = function (callback) { - _onCallback(this, _PAUSE_CALLBACK, callback); -}; - -_prototype.onPlay = function (callback) { - _onCallback(this, _PLAY_CALLBACK, callback); -}; - -_prototype.onSeeked = function (callback) { - _onCallback(this, _SEEKED_CALLBACK, callback); -}; - -_prototype.onSeeking = function (callback) { - _onCallback(this, "seekingCallbacks", callback); -}; - -_prototype.onStop = function (callback) { - _onCallback(this, _STOP_CALLBACK, callback); -}; - -_prototype.onTimeUpdate = function (callback) { - var result = _onCallback(this, _TIME_UPDATE_CALLBACK, callback); - - if (result === 1) { - var privateThis = _weakMap.get(this); - - var self = this; - var intervalID = setInterval(function () { - var privateThis = _weakMap.get(self); - - if (privateThis) { - var audioID = privateThis.audioID; - - if (typeof audioID === "number" && audioID >= 0 && _audioEngine.getState(audioID) === _STATE.PLAYING) { - _dispatchCallback(self, _TIME_UPDATE_CALLBACK); - } - } else { - clearInterval(intervalID); - } - }, 500); - privateThis.intervalID = intervalID; - } -}; - -_prototype.onWaiting = function (callback) { - _onCallback(this, _WAITING_CALLBACK, callback); -}; - -function _default(AudioEngine) { - if (_audioEngine === undefined) { - _audioEngine = Object.assign({}, AudioEngine); - Object.keys(AudioEngine).forEach(function (name) { - if (typeof AudioEngine[name] === "function") { - AudioEngine[name] = function () { - console.warn("AudioEngine." + name + " is deprecated"); - return _audioEngine[name].apply(AudioEngine, arguments); - }; - } - }); - } - - return new InnerAudioContext(); -} - -; - -},{}],21:[function(require,module,exports){ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports["default"] = void 0; - -function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } - -var _default = { - exportTo: function exportTo(name, from, to, errCallback) { - if (_typeof(from) !== "object" || _typeof(to) !== "object") { - console.warn("invalid exportTo: ", name); - return; - } - - var fromProperty = from[name]; - - if (typeof fromProperty !== "undefined") { - if (typeof fromProperty === "function") { - to[name] = fromProperty.bind(from); - Object.assign(to[name], fromProperty); - } else { - to[name] = fromProperty; - } - } else { - to[name] = function () { - console.error(name + " is not support!"); - return {}; - }; - - if (typeof errCallback === "function") { - errCallback(); - } - } - } -}; -exports["default"] = _default; - -},{}]},{},[8]); - -//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIiwic291cmNlcyI6WyJyYWwuanMiXSwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uKCl7ZnVuY3Rpb24gcihlLG4sdCl7ZnVuY3Rpb24gbyhpLGYpe2lmKCFuW2ldKXtpZighZVtpXSl7dmFyIGM9XCJmdW5jdGlvblwiPT10eXBlb2YgcmVxdWlyZSYmcmVxdWlyZTtpZighZiYmYylyZXR1cm4gYyhpLCEwKTtpZih1KXJldHVybiB1KGksITApO3ZhciBhPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIraStcIidcIik7dGhyb3cgYS5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGF9dmFyIHA9bltpXT17ZXhwb3J0czp7fX07ZVtpXVswXS5jYWxsKHAuZXhwb3J0cyxmdW5jdGlvbihyKXt2YXIgbj1lW2ldWzFdW3JdO3JldHVybiBvKG58fHIpfSxwLHAuZXhwb3J0cyxyLGUsbix0KX1yZXR1cm4gbltpXS5leHBvcnRzfWZvcih2YXIgdT1cImZ1bmN0aW9uXCI9PXR5cGVvZiByZXF1aXJlJiZyZXF1aXJlLGk9MDtpPHQubGVuZ3RoO2krKylvKHRbaV0pO3JldHVybiBvfXJldHVybiByfSkoKSh7MTpbZnVuY3Rpb24ocmVxdWlyZSxtb2R1bGUsZXhwb3J0cyl7XG5cInVzZSBzdHJpY3RcIjtcblxudmFyIF91dGlsID0gX2ludGVyb3BSZXF1aXJlRGVmYXVsdChyZXF1aXJlKFwiLi4vLi4vdXRpbFwiKSk7XG5cbmZ1bmN0aW9uIF9pbnRlcm9wUmVxdWlyZURlZmF1bHQob2JqKSB7IHJldHVybiBvYmogJiYgb2JqLl9fZXNNb2R1bGUgPyBvYmogOiB7IFwiZGVmYXVsdFwiOiBvYmogfTsgfVxuXG52YXIgX3J0ID0gbG9hZFJ1bnRpbWUoKTtcblxuX3V0aWxbXCJkZWZhdWx0XCJdLmV4cG9ydFRvKFwib25TaG93XCIsIF9ydCwgcmFsKTtcblxuX3V0aWxbXCJkZWZhdWx0XCJdLmV4cG9ydFRvKFwib25IaWRlXCIsIF9ydCwgcmFsKTtcblxuX3V0aWxbXCJkZWZhdWx0XCJdLmV4cG9ydFRvKFwib2ZmU2hvd1wiLCBfcnQsIHJhbCk7XG5cbl91dGlsW1wiZGVmYXVsdFwiXS5leHBvcnRUbyhcIm9mZkhpZGVcIiwgX3J0LCByYWwpO1xuXG59LHtcIi4uLy4uL3V0aWxcIjoyMX1dLDI6W2Z1bmN0aW9uKHJlcXVpcmUsbW9kdWxlLGV4cG9ydHMpe1xuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBfdXRpbCA9IF9pbnRlcm9wUmVxdWlyZURlZmF1bHQocmVxdWlyZShcIi4uLy4uL3V0aWxcIikpO1xuXG5mdW5jdGlvbiBfaW50ZXJvcFJlcXVpcmVEZWZhdWx0KG9iaikgeyByZXR1cm4gb2JqICYmIG9iai5fX2VzTW9kdWxlID8gb2JqIDogeyBcImRlZmF1bHRcIjogb2JqIH07IH1cblxudmFyIF9ydCA9IGxvYWRSdW50aW1lKCk7XG5cbl91dGlsW1wiZGVmYXVsdFwiXS5leHBvcnRUbyhcImxvYWRTdWJwYWNrYWdlXCIsIF9ydCwgcmFsKTtcblxufSx7XCIuLi8uLi91dGlsXCI6MjF9XSwzOltmdW5jdGlvbihyZXF1aXJlLG1vZHVsZSxleHBvcnRzKXtcblwidXNlIHN0cmljdFwiO1xuXG52YXIgX3V0aWwgPSBfaW50ZXJvcFJlcXVpcmVEZWZhdWx0KHJlcXVpcmUoXCIuLi8uLi91dGlsXCIpKTtcblxuZnVuY3Rpb24gX2ludGVyb3BSZXF1aXJlRGVmYXVsdChvYmopIHsgcmV0dXJuIG9iaiAmJiBvYmouX19lc01vZHVsZSA/IG9iaiA6IHsgXCJkZWZhdWx0XCI6IG9iaiB9OyB9XG5cbnZhciBfcnQgPSBsb2FkUnVudGltZSgpO1xuXG5fdXRpbFtcImRlZmF1bHRcIl0uZXhwb3J0VG8oXCJlbnZcIiwgX3J0LCByYWwpO1xuXG5fdXRpbFtcImRlZmF1bHRcIl0uZXhwb3J0VG8oXCJnZXRTeXN0ZW1JbmZvXCIsIF9ydCwgcmFsKTtcblxuX3V0aWxbXCJkZWZhdWx0XCJdLmV4cG9ydFRvKFwiZ2V0U3lzdGVtSW5mb1N5bmNcIiwgX3J0LCByYWwpO1xuXG59LHtcIi4uLy4uL3V0aWxcIjoyMX1dLDQ6W2Z1bmN0aW9uKHJlcXVpcmUsbW9kdWxlLGV4cG9ydHMpe1xuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBfanNiID0gd2luZG93LmpzYjtcblxuaWYgKCFfanNiKSB7XG4gIF9qc2IgPSB7fTtcbn1cblxudmFyIF9ydCA9IGxvYWRSdW50aW1lKCk7XG5cbnZhciBfdG91Y2hlcyA9IFtdO1xuXG52YXIgX2dldFRvdWNoSW5kZXggPSBmdW5jdGlvbiBfZ2V0VG91Y2hJbmRleCh0b3VjaCkge1xuICB2YXIgZWxlbWVudDtcblxuICBmb3IgKHZhciBpbmRleCA9IDA7IGluZGV4IDwgX3RvdWNoZXMubGVuZ3RoOyBpbmRleCsrKSB7XG4gICAgZWxlbWVudCA9IF90b3VjaGVzW2luZGV4XTtcblxuICAgIGlmICh0b3VjaC5pZGVudGlmaWVyID09PSBlbGVtZW50LmlkZW50aWZpZXIpIHtcbiAgICAgIHJldHVybiBpbmRleDtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gLTE7XG59O1xuXG52YXIgX2NvcHlPYmplY3QgPSBmdW5jdGlvbiBfY29weU9iamVjdChmcm9tT2JqLCB0b09iamVjdCkge1xuICBmb3IgKHZhciBrZXkgaW4gZnJvbU9iaikge1xuICAgIGlmIChmcm9tT2JqLmhhc093blByb3BlcnR5KGtleSkpIHtcbiAgICAgIHRvT2JqZWN0W2tleV0gPSBmcm9tT2JqW2tleV07XG4gICAgfVxuICB9XG59O1xuXG52YXIgX2xpc3RlbmVyTWFwID0ge1xuICBcInRvdWNoc3RhcnRcIjogW10sXG4gIFwidG91Y2htb3ZlXCI6IFtdLFxuICBcInRvdWNoZW5kXCI6IFtdLFxuICBcInRvdWNoY2FuY2VsXCI6IFtdXG59O1xuXG5mdW5jdGlvbiBfYWRkTGlzdGVuZXIoa2V5LCB2YWx1ZSkge1xuICB2YXIgbGlzdGVuZXJBcnIgPSBfbGlzdGVuZXJNYXBba2V5XTtcblxuICBmb3IgKHZhciBpbmRleCA9IDAsIGxlbmd0aCA9IGxpc3RlbmVyQXJyLmxlbmd0aDsgaW5kZXggPCBsZW5ndGg7IGluZGV4KyspIHtcbiAgICBpZiAodmFsdWUgPT09IGxpc3RlbmVyQXJyW2luZGV4XSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgfVxuXG4gIGxpc3RlbmVyQXJyLnB1c2godmFsdWUpO1xufVxuXG5mdW5jdGlvbiBfcmVtb3ZlTGlzdGVuZXIoa2V5LCB2YWx1ZSkge1xuICB2YXIgbGlzdGVuZXJBcnIgPSBfbGlzdGVuZXJNYXBba2V5XSB8fCBbXTtcbiAgdmFyIGxlbmd0aCA9IGxpc3RlbmVyQXJyLmxlbmd0aDtcblxuICBmb3IgKHZhciBpbmRleCA9IDA7IGluZGV4IDwgbGVuZ3RoOyArK2luZGV4KSB7XG4gICAgaWYgKHZhbHVlID09PSBsaXN0ZW5lckFycltpbmRleF0pIHtcbiAgICAgIGxpc3RlbmVyQXJyLnNwbGljZShpbmRleCwgMSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICB9XG59XG5cbnZhciBfaGFzRGVsbFdpdGggPSBmYWxzZTtcblxudmFyIF9zeXN0ZW1JbmZvID0gX3J0LmdldFN5c3RlbUluZm9TeW5jKCk7XG5cbmlmICh3aW5kb3cuaW5uZXJXaWR0aCAmJiBfc3lzdGVtSW5mby53aW5kb3dXaWR0aCAhPT0gd2luZG93LmlubmVyV2lkdGgpIHtcbiAgX2hhc0RlbGxXaXRoID0gdHJ1ZTtcbn1cblxudmFyIF90b3VjaEV2ZW50SGFuZGxlckZhY3RvcnkgPSBmdW5jdGlvbiBfdG91Y2hFdmVudEhhbmRsZXJGYWN0b3J5KHR5cGUpIHtcbiAgcmV0dXJuIGZ1bmN0aW9uIChjaGFuZ2VkVG91Y2hlcykge1xuICAgIGlmICh0eXBlb2YgY2hhbmdlZFRvdWNoZXMgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgX2FkZExpc3RlbmVyKHR5cGUsIGNoYW5nZWRUb3VjaGVzKTtcblxuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHZhciB0b3VjaEV2ZW50ID0gbmV3IFRvdWNoRXZlbnQodHlwZSk7XG4gICAgdmFyIGluZGV4O1xuXG4gICAgaWYgKHR5cGUgPT09IFwidG91Y2hzdGFydFwiKSB7XG4gICAgICBjaGFuZ2VkVG91Y2hlcy5mb3JFYWNoKGZ1bmN0aW9uICh0b3VjaCkge1xuICAgICAgICBpbmRleCA9IF9nZXRUb3VjaEluZGV4KHRvdWNoKTtcblxuICAgICAgICBpZiAoaW5kZXggPj0gMCkge1xuICAgICAgICAgIF9jb3B5T2JqZWN0KHRvdWNoLCBfdG91Y2hlc1tpbmRleF0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHZhciB0bXAgPSB7fTtcblxuICAgICAgICAgIF9jb3B5T2JqZWN0KHRvdWNoLCB0bXApO1xuXG4gICAgICAgICAgX3RvdWNoZXMucHVzaCh0bXApO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9IGVsc2UgaWYgKHR5cGUgPT09IFwidG91Y2htb3ZlXCIpIHtcbiAgICAgIGNoYW5nZWRUb3VjaGVzLmZvckVhY2goZnVuY3Rpb24gKGVsZW1lbnQpIHtcbiAgICAgICAgaW5kZXggPSBfZ2V0VG91Y2hJbmRleChlbGVtZW50KTtcblxuICAgICAgICBpZiAoaW5kZXggPj0gMCkge1xuICAgICAgICAgIF9jb3B5T2JqZWN0KGVsZW1lbnQsIF90b3VjaGVzW2luZGV4XSk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH0gZWxzZSBpZiAodHlwZSA9PT0gXCJ0b3VjaGVuZFwiIHx8IHR5cGUgPT09IFwidG91Y2hjYW5jZWxcIikge1xuICAgICAgY2hhbmdlZFRvdWNoZXMuZm9yRWFjaChmdW5jdGlvbiAoZWxlbWVudCkge1xuICAgICAgICBpbmRleCA9IF9nZXRUb3VjaEluZGV4KGVsZW1lbnQpO1xuXG4gICAgICAgIGlmIChpbmRleCA+PSAwKSB7XG4gICAgICAgICAgX3RvdWNoZXMuc3BsaWNlKGluZGV4LCAxKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgdmFyIHRvdWNoZXMgPSBbXS5jb25jYXQoX3RvdWNoZXMpO1xuICAgIHZhciBfY2hhbmdlZFRvdWNoZXMgPSBbXTtcbiAgICBjaGFuZ2VkVG91Y2hlcy5mb3JFYWNoKGZ1bmN0aW9uICh0b3VjaCkge1xuICAgICAgdmFyIGxlbmd0aCA9IHRvdWNoZXMubGVuZ3RoO1xuXG4gICAgICBmb3IgKHZhciBfaW5kZXggPSAwOyBfaW5kZXggPCBsZW5ndGg7ICsrX2luZGV4KSB7XG4gICAgICAgIHZhciBfdG91Y2ggPSB0b3VjaGVzW19pbmRleF07XG5cbiAgICAgICAgaWYgKHRvdWNoLmlkZW50aWZpZXIgPT09IF90b3VjaC5pZGVudGlmaWVyKSB7XG4gICAgICAgICAgX2NoYW5nZWRUb3VjaGVzLnB1c2goX3RvdWNoKTtcblxuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBfY2hhbmdlZFRvdWNoZXMucHVzaCh0b3VjaCk7XG4gICAgfSk7XG4gICAgdG91Y2hFdmVudC50b3VjaGVzID0gdG91Y2hlcztcbiAgICB0b3VjaEV2ZW50LnRhcmdldFRvdWNoZXMgPSB0b3VjaGVzO1xuICAgIHRvdWNoRXZlbnQuY2hhbmdlZFRvdWNoZXMgPSBfY2hhbmdlZFRvdWNoZXM7XG5cbiAgICBpZiAoX2hhc0RlbGxXaXRoKSB7XG4gICAgICB0b3VjaGVzLmZvckVhY2goZnVuY3Rpb24gKHRvdWNoKSB7XG4gICAgICAgIHRvdWNoLmNsaWVudFggLz0gd2luZG93LmRldmljZVBpeGVsUmF0aW87XG4gICAgICAgIHRvdWNoLmNsaWVudFkgLz0gd2luZG93LmRldmljZVBpeGVsUmF0aW87XG4gICAgICAgIHRvdWNoLnBhZ2VYIC89IHdpbmRvdy5kZXZpY2VQaXhlbFJhdGlvO1xuICAgICAgICB0b3VjaC5wYWdlWSAvPSB3aW5kb3cuZGV2aWNlUGl4ZWxSYXRpbztcbiAgICAgIH0pO1xuXG4gICAgICBpZiAodHlwZSA9PT0gXCJ0b3VjaGNhbmNlbFwiIHx8IHR5cGUgPT09IFwidG91Y2hlbmRcIikge1xuICAgICAgICBfY2hhbmdlZFRvdWNoZXMuZm9yRWFjaChmdW5jdGlvbiAodG91Y2gpIHtcbiAgICAgICAgICB0b3VjaC5jbGllbnRYIC89IHdpbmRvdy5kZXZpY2VQaXhlbFJhdGlvO1xuICAgICAgICAgIHRvdWNoLmNsaWVudFkgLz0gd2luZG93LmRldmljZVBpeGVsUmF0aW87XG4gICAgICAgICAgdG91Y2gucGFnZVggLz0gd2luZG93LmRldmljZVBpeGVsUmF0aW87XG4gICAgICAgICAgdG91Y2gucGFnZVkgLz0gd2luZG93LmRldmljZVBpeGVsUmF0aW87XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIHZhciBsaXN0ZW5lckFyciA9IF9saXN0ZW5lck1hcFt0eXBlXTtcbiAgICB2YXIgbGVuZ3RoID0gbGlzdGVuZXJBcnIubGVuZ3RoO1xuXG4gICAgZm9yICh2YXIgX2luZGV4MiA9IDA7IF9pbmRleDIgPCBsZW5ndGg7IF9pbmRleDIrKykge1xuICAgICAgbGlzdGVuZXJBcnJbX2luZGV4Ml0odG91Y2hFdmVudCk7XG4gICAgfVxuICB9O1xufTtcblxuaWYgKF9ydC5vblRvdWNoU3RhcnQpIHtcbiAgcmFsLm9uVG91Y2hTdGFydCA9IF9ydC5vblRvdWNoU3RhcnQ7XG4gIHJhbC5vZmZUb3VjaFN0YXJ0ID0gX3J0Lm9mZlRvdWNoU3RhcnQ7XG59IGVsc2Uge1xuICBfanNiLm9uVG91Y2hTdGFydCA9IF90b3VjaEV2ZW50SGFuZGxlckZhY3RvcnkoJ3RvdWNoc3RhcnQnKTtcblxuICBfanNiLm9mZlRvdWNoU3RhcnQgPSBmdW5jdGlvbiAoY2FsbGJhY2spIHtcbiAgICBfcmVtb3ZlTGlzdGVuZXIoXCJ0b3VjaHN0YXJ0XCIsIGNhbGxiYWNrKTtcbiAgfTtcblxuICByYWwub25Ub3VjaFN0YXJ0ID0gX2pzYi5vblRvdWNoU3RhcnQuYmluZChfanNiKTtcbiAgcmFsLm9mZlRvdWNoU3RhcnQgPSBfanNiLm9mZlRvdWNoU3RhcnQuYmluZChfanNiKTtcbn1cblxuaWYgKF9ydC5vblRvdWNoTW92ZSkge1xuICByYWwub25Ub3VjaE1vdmUgPSBfcnQub25Ub3VjaE1vdmU7XG4gIHJhbC5vZmZUb3VjaE1vdmUgPSBfcnQub2ZmVG91Y2hNb3ZlO1xufSBlbHNlIHtcbiAgX2pzYi5vblRvdWNoTW92ZSA9IF90b3VjaEV2ZW50SGFuZGxlckZhY3RvcnkoJ3RvdWNobW92ZScpO1xuXG4gIF9qc2Iub2ZmVG91Y2hNb3ZlID0gZnVuY3Rpb24gKGNhbGxiYWNrKSB7XG4gICAgX3JlbW92ZUxpc3RlbmVyKFwidG91Y2htb3ZlXCIsIGNhbGxiYWNrKTtcbiAgfTtcblxuICByYWwub25Ub3VjaE1vdmUgPSBfanNiLm9uVG91Y2hNb3ZlLmJpbmQoX2pzYik7XG4gIHJhbC5vZmZUb3VjaE1vdmUgPSBfanNiLm9mZlRvdWNoTW92ZS5iaW5kKF9qc2IpO1xufVxuXG5pZiAoX3J0Lm9uVG91Y2hDYW5jZWwpIHtcbiAgcmFsLm9uVG91Y2hDYW5jZWwgPSBfcnQub25Ub3VjaENhbmNlbDtcbiAgcmFsLm9mZlRvdWNoQ2FuY2VsID0gX3J0Lm9mZlRvdWNoQ2FuY2VsO1xufSBlbHNlIHtcbiAgX2pzYi5vblRvdWNoQ2FuY2VsID0gX3RvdWNoRXZlbnRIYW5kbGVyRmFjdG9yeSgndG91Y2hjYW5jZWwnKTtcblxuICBfanNiLm9mZlRvdWNoQ2FuY2VsID0gZnVuY3Rpb24gKGNhbGxiYWNrKSB7XG4gICAgX3JlbW92ZUxpc3RlbmVyKFwidG91Y2hjYW5jZWxcIiwgY2FsbGJhY2spO1xuICB9O1xuXG4gIHJhbC5vblRvdWNoQ2FuY2VsID0gX2pzYi5vblRvdWNoQ2FuY2VsLmJpbmQoX2pzYik7XG4gIHJhbC5vZmZUb3VjaENhbmNlbCA9IF9qc2Iub2ZmVG91Y2hDYW5jZWwuYmluZChfanNiKTtcbn1cblxuaWYgKF9ydC5vblRvdWNoRW5kKSB7XG4gIHJhbC5vblRvdWNoRW5kID0gX3J0Lm9uVG91Y2hFbmQ7XG4gIHJhbC5vZmZUb3VjaEVuZCA9IF9ydC5vZmZUb3VjaEVuZDtcbn0gZWxzZSB7XG4gIF9qc2Iub25Ub3VjaEVuZCA9IF90b3VjaEV2ZW50SGFuZGxlckZhY3RvcnkoJ3RvdWNoZW5kJyk7XG5cbiAgX2pzYi5vZmZUb3VjaEVuZCA9IGZ1bmN0aW9uIChjYWxsYmFjaykge1xuICAgIF9yZW1vdmVMaXN0ZW5lcihcInRvdWNoZW5kXCIsIGNhbGxiYWNrKTtcbiAgfTtcblxuICByYWwub25Ub3VjaEVuZCA9IF9qc2Iub25Ub3VjaEVuZC5iaW5kKF9qc2IpO1xuICByYWwub2ZmVG91Y2hFbmQgPSBfanNiLm9mZlRvdWNoRW5kLmJpbmQoX2pzYik7XG59XG5cbn0se31dLDU6W2Z1bmN0aW9uKHJlcXVpcmUsbW9kdWxlLGV4cG9ydHMpe1xuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBfdXRpbCA9IF9pbnRlcm9wUmVxdWlyZURlZmF1bHQocmVxdWlyZShcIi4uLy4uL3V0aWxcIikpO1xuXG5mdW5jdGlvbiBfaW50ZXJvcFJlcXVpcmVEZWZhdWx0KG9iaikgeyByZXR1cm4gb2JqICYmIG9iai5fX2VzTW9kdWxlID8gb2JqIDogeyBcImRlZmF1bHRcIjogb2JqIH07IH1cblxudmFyIF9ydCA9IGxvYWRSdW50aW1lKCk7XG5cbnZhciBfbGlzdGVuZXJzID0gW107XG5yYWwuZGV2aWNlID0gcmFsLmRldmljZSB8fCB7fTtcblxuaWYgKF9ydC5vZmZBY2NlbGVyb21ldGVyQ2hhbmdlKSB7XG4gIHJhbC5vbkFjY2VsZXJvbWV0ZXJDaGFuZ2UgPSBfcnQub25BY2NlbGVyb21ldGVyQ2hhbmdlLmJpbmQoX3J0KTtcbiAgcmFsLm9mZkFjY2VsZXJvbWV0ZXJDaGFuZ2UgPSBfcnQub2ZmQWNjZWxlcm9tZXRlckNoYW5nZS5iaW5kKF9ydCk7XG4gIHJhbC5zdG9wQWNjZWxlcm9tZXRlciA9IF9ydC5zdG9wQWNjZWxlcm9tZXRlci5iaW5kKF9ydCk7XG5cbiAgdmFyIF9zdGFydEFjY2VsZXJvbWV0ZXIgPSBfcnQuc3RhcnRBY2NlbGVyb21ldGVyLmJpbmQoX3J0KTtcblxuICByYWwuc3RhcnRBY2NlbGVyb21ldGVyID0gZnVuY3Rpb24gKG9iaikge1xuICAgIHJldHVybiBfc3RhcnRBY2NlbGVyb21ldGVyKE9iamVjdC5hc3NpZ24oe1xuICAgICAgdHlwZTogXCJhY2NlbGVyYXRpb25JbmNsdWRpbmdHcmF2aXR5XCJcbiAgICB9LCBvYmopKTtcbiAgfTtcbn0gZWxzZSB7XG4gIHJhbC5vbkFjY2VsZXJvbWV0ZXJDaGFuZ2UgPSBmdW5jdGlvbiAobGlzdGVuZXIpIHtcbiAgICBpZiAodHlwZW9mIGxpc3RlbmVyID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgIHZhciBsZW5ndGggPSBfbGlzdGVuZXJzLmxlbmd0aDtcblxuICAgICAgZm9yICh2YXIgaW5kZXggPSAwOyBpbmRleCA8IGxlbmd0aDsgKytpbmRleCkge1xuICAgICAgICBpZiAobGlzdGVuZXIgPT09IF9saXN0ZW5lcnNbaW5kZXhdKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIF9saXN0ZW5lcnMucHVzaChsaXN0ZW5lcik7XG4gICAgfVxuICB9O1xuXG4gIHJhbC5vZmZBY2NlbGVyb21ldGVyQ2hhbmdlID0gZnVuY3Rpb24gKGxpc3RlbmVyKSB7XG4gICAgdmFyIGxlbmd0aCA9IF9saXN0ZW5lcnMubGVuZ3RoO1xuXG4gICAgZm9yICh2YXIgaW5kZXggPSAwOyBpbmRleCA8IGxlbmd0aDsgKytpbmRleCkge1xuICAgICAgaWYgKGxpc3RlbmVyID09PSBfbGlzdGVuZXJzW2luZGV4XSkge1xuICAgICAgICBfbGlzdGVuZXJzLnNwbGljZShpbmRleCwgMSk7XG5cbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgIH1cbiAgfTtcblxuICB2YXIgX3N5c3RlbUluZm8gPSBfcnQuZ2V0U3lzdGVtSW5mb1N5bmMoKTtcblxuICB2YXIgX2lzQW5kcm9pZCA9IF9zeXN0ZW1JbmZvLnBsYXRmb3JtLnRvTG93ZXJDYXNlKCkgPT09IFwiYW5kcm9pZFwiO1xuXG4gIGpzYi5kZXZpY2UuZGlzcGF0Y2hEZXZpY2VNb3Rpb25FdmVudCA9IGZ1bmN0aW9uIChldmVudCkge1xuICAgIHZhciBhY2NlbGVyYXRpb24gPSBPYmplY3QuYXNzaWduKHt9LCBldmVudC5fYWNjZWxlcmF0aW9uSW5jbHVkaW5nR3Jhdml0eSk7XG5cbiAgICBpZiAoX2lzQW5kcm9pZCkge1xuICAgICAgYWNjZWxlcmF0aW9uLnggLz0gLTEwO1xuICAgICAgYWNjZWxlcmF0aW9uLnkgLz0gLTEwO1xuICAgICAgYWNjZWxlcmF0aW9uLnogLz0gLTEwO1xuICAgIH0gZWxzZSB7XG4gICAgICBhY2NlbGVyYXRpb24ueCAvPSAxMDtcbiAgICAgIGFjY2VsZXJhdGlvbi55IC89IDEwO1xuICAgICAgYWNjZWxlcmF0aW9uLnogLz0gMTA7XG4gICAgfVxuXG4gICAgX2xpc3RlbmVycy5mb3JFYWNoKGZ1bmN0aW9uIChsaXN0ZW5lcikge1xuICAgICAgbGlzdGVuZXIoe1xuICAgICAgICB4OiBhY2NlbGVyYXRpb24ueCxcbiAgICAgICAgeTogYWNjZWxlcmF0aW9uLnksXG4gICAgICAgIHo6IGFjY2VsZXJhdGlvbi56XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfTtcblxuICByYWwuc3RvcEFjY2VsZXJvbWV0ZXIgPSBmdW5jdGlvbiAoKSB7XG4gICAganNiLmRldmljZS5zZXRNb3Rpb25FbmFibGVkKGZhbHNlKTtcbiAgfTtcblxuICByYWwuc3RhcnRBY2NlbGVyb21ldGVyID0gZnVuY3Rpb24gKCkge1xuICAgIGpzYi5kZXZpY2Uuc2V0TW90aW9uRW5hYmxlZCh0cnVlKTtcbiAgfTtcbn1cblxufSx7XCIuLi8uLi91dGlsXCI6MjF9XSw2OltmdW5jdGlvbihyZXF1aXJlLG1vZHVsZSxleHBvcnRzKXtcblwidXNlIHN0cmljdFwiO1xuXG52YXIgX3V0aWwgPSBfaW50ZXJvcFJlcXVpcmVEZWZhdWx0KHJlcXVpcmUoXCIuLi8uLi91dGlsXCIpKTtcblxuZnVuY3Rpb24gX2ludGVyb3BSZXF1aXJlRGVmYXVsdChvYmopIHsgcmV0dXJuIG9iaiAmJiBvYmouX19lc01vZHVsZSA/IG9iaiA6IHsgXCJkZWZhdWx0XCI6IG9iaiB9OyB9XG5cbnZhciBfcnQgPSBsb2FkUnVudGltZSgpO1xuXG5fdXRpbFtcImRlZmF1bHRcIl0uZXhwb3J0VG8oXCJnZXRCYXR0ZXJ5SW5mb1wiLCBfcnQsIHJhbCk7XG5cbl91dGlsW1wiZGVmYXVsdFwiXS5leHBvcnRUbyhcImdldEJhdHRlcnlJbmZvU3luY1wiLCBfcnQsIHJhbCk7XG5cbn0se1wiLi4vLi4vdXRpbFwiOjIxfV0sNzpbZnVuY3Rpb24ocmVxdWlyZSxtb2R1bGUsZXhwb3J0cyl7XG5cInVzZSBzdHJpY3RcIjtcblxudmFyIF91dGlsID0gX2ludGVyb3BSZXF1aXJlRGVmYXVsdChyZXF1aXJlKFwiLi4vLi4vdXRpbFwiKSk7XG5cbmZ1bmN0aW9uIF9pbnRlcm9wUmVxdWlyZURlZmF1bHQob2JqKSB7IHJldHVybiBvYmogJiYgb2JqLl9fZXNNb2R1bGUgPyBvYmogOiB7IFwiZGVmYXVsdFwiOiBvYmogfTsgfVxuXG52YXIgX3J0ID0gbG9hZFJ1bnRpbWUoKTtcblxuX3V0aWxbXCJkZWZhdWx0XCJdLmV4cG9ydFRvKFwiZ2V0RmlsZVN5c3RlbU1hbmFnZXJcIiwgX3J0LCByYWwpO1xuXG59LHtcIi4uLy4uL3V0aWxcIjoyMX1dLDg6W2Z1bmN0aW9uKHJlcXVpcmUsbW9kdWxlLGV4cG9ydHMpe1xuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBfdXRpbCA9IF9pbnRlcm9wUmVxdWlyZURlZmF1bHQocmVxdWlyZShcIi4uL3V0aWxcIikpO1xuXG52YXIgX2ZlYXR1cmUgPSBfaW50ZXJvcFJlcXVpcmVEZWZhdWx0KHJlcXVpcmUoXCIuLi9mZWF0dXJlXCIpKTtcblxuZnVuY3Rpb24gX2ludGVyb3BSZXF1aXJlRGVmYXVsdChvYmopIHsgcmV0dXJuIG9iaiAmJiBvYmouX19lc01vZHVsZSA/IG9iaiA6IHsgXCJkZWZhdWx0XCI6IG9iaiB9OyB9XG5cbmlmICh3aW5kb3cuanNiKSB7XG4gIHdpbmRvdy5yYWwgPSBPYmplY3QuYXNzaWduKHt9LCB3aW5kb3cuanNiKTtcbn0gZWxzZSB7XG4gIHdpbmRvdy5yYWwgPSB7fTtcbn1cblxucmVxdWlyZShcIi4vYmFzZS9saWZlY3ljbGVcIik7XG5cbnJlcXVpcmUoXCIuL2Jhc2Uvc3VicGFja2FnZVwiKTtcblxucmVxdWlyZShcIi4vYmFzZS9zeXN0ZW0taW5mb1wiKTtcblxucmVxdWlyZShcIi4vYmFzZS90b3VjaC1ldmVudFwiKTtcblxucmVxdWlyZShcIi4vZGV2aWNlL2FjY2VsZXJvbWV0ZXJcIik7XG5cbnJlcXVpcmUoXCIuL2RldmljZS9iYXR0ZXJ5XCIpO1xuXG5yZXF1aXJlKFwiLi9maWxlL2ZpbGUtc3lzdGVtLW1hbmFnZXJcIik7XG5cbnJlcXVpcmUoXCIuL2ludGVyZmFjZS9rZXlib2FyZFwiKTtcblxucmVxdWlyZShcIi4vaW50ZXJmYWNlL3dpbmRvd1wiKTtcblxucmVxdWlyZShcIi4vbWVkaWEvYXVkaW9cIik7XG5cbnJlcXVpcmUoXCIuL21lZGlhL3ZpZGVvXCIpO1xuXG5yZXF1aXJlKFwiLi9uZXR3b3JrL2Rvd25sb2FkXCIpO1xuXG5yZXF1aXJlKFwiLi9yZW5kZXJpbmcvY2FudmFzXCIpO1xuXG5yZXF1aXJlKFwiLi9yZW5kZXJpbmcvd2ViZ2xcIik7XG5cbnJlcXVpcmUoXCIuL3JlbmRlcmluZy9mb250XCIpO1xuXG5yZXF1aXJlKFwiLi9yZW5kZXJpbmcvZnJhbWVcIik7XG5cbnJlcXVpcmUoXCIuL3JlbmRlcmluZy9pbWFnZVwiKTtcblxuX3V0aWxbXCJkZWZhdWx0XCJdLmV4cG9ydFRvKFwiZ2V0RmVhdHVyZVByb3BlcnR5XCIsIF9mZWF0dXJlW1wiZGVmYXVsdFwiXSwgcmFsKTtcblxufSx7XCIuLi9mZWF0dXJlXCI6MTksXCIuLi91dGlsXCI6MjEsXCIuL2Jhc2UvbGlmZWN5Y2xlXCI6MSxcIi4vYmFzZS9zdWJwYWNrYWdlXCI6MixcIi4vYmFzZS9zeXN0ZW0taW5mb1wiOjMsXCIuL2Jhc2UvdG91Y2gtZXZlbnRcIjo0LFwiLi9kZXZpY2UvYWNjZWxlcm9tZXRlclwiOjUsXCIuL2RldmljZS9iYXR0ZXJ5XCI6NixcIi4vZmlsZS9maWxlLXN5c3RlbS1tYW5hZ2VyXCI6NyxcIi4vaW50ZXJmYWNlL2tleWJvYXJkXCI6OSxcIi4vaW50ZXJmYWNlL3dpbmRvd1wiOjEwLFwiLi9tZWRpYS9hdWRpb1wiOjExLFwiLi9tZWRpYS92aWRlb1wiOjEyLFwiLi9uZXR3b3JrL2Rvd25sb2FkXCI6MTMsXCIuL3JlbmRlcmluZy9jYW52YXNcIjoxNCxcIi4vcmVuZGVyaW5nL2ZvbnRcIjoxNSxcIi4vcmVuZGVyaW5nL2ZyYW1lXCI6MTYsXCIuL3JlbmRlcmluZy9pbWFnZVwiOjE3LFwiLi9yZW5kZXJpbmcvd2ViZ2xcIjoxOH1dLDk6W2Z1bmN0aW9uKHJlcXVpcmUsbW9kdWxlLGV4cG9ydHMpe1xuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBfdXRpbCA9IF9pbnRlcm9wUmVxdWlyZURlZmF1bHQocmVxdWlyZShcIi4uLy4uL3V0aWxcIikpO1xuXG5mdW5jdGlvbiBfaW50ZXJvcFJlcXVpcmVEZWZhdWx0KG9iaikgeyByZXR1cm4gb2JqICYmIG9iai5fX2VzTW9kdWxlID8gb2JqIDogeyBcImRlZmF1bHRcIjogb2JqIH07IH1cblxudmFyIF9ydCA9IGxvYWRSdW50aW1lKCk7XG5cbl91dGlsW1wiZGVmYXVsdFwiXS5leHBvcnRUbyhcIm9uS2V5Ym9hcmRJbnB1dFwiLCBfcnQsIHJhbCk7XG5cbl91dGlsW1wiZGVmYXVsdFwiXS5leHBvcnRUbyhcIm9uS2V5Ym9hcmRDb25maXJtXCIsIF9ydCwgcmFsKTtcblxuX3V0aWxbXCJkZWZhdWx0XCJdLmV4cG9ydFRvKFwib25LZXlib2FyZENvbXBsZXRlXCIsIF9ydCwgcmFsKTtcblxuX3V0aWxbXCJkZWZhdWx0XCJdLmV4cG9ydFRvKFwib2ZmS2V5Ym9hcmRJbnB1dFwiLCBfcnQsIHJhbCk7XG5cbl91dGlsW1wiZGVmYXVsdFwiXS5leHBvcnRUbyhcIm9mZktleWJvYXJkQ29uZmlybVwiLCBfcnQsIHJhbCk7XG5cbl91dGlsW1wiZGVmYXVsdFwiXS5leHBvcnRUbyhcIm9mZktleWJvYXJkQ29tcGxldGVcIiwgX3J0LCByYWwpO1xuXG5fdXRpbFtcImRlZmF1bHRcIl0uZXhwb3J0VG8oXCJoaWRlS2V5Ym9hcmRcIiwgX3J0LCByYWwpO1xuXG5fdXRpbFtcImRlZmF1bHRcIl0uZXhwb3J0VG8oXCJzaG93S2V5Ym9hcmRcIiwgX3J0LCByYWwpO1xuXG5fdXRpbFtcImRlZmF1bHRcIl0uZXhwb3J0VG8oXCJ1cGRhdGVLZXlib2FyZFwiLCBfcnQsIHJhbCk7XG5cbn0se1wiLi4vLi4vdXRpbFwiOjIxfV0sMTA6W2Z1bmN0aW9uKHJlcXVpcmUsbW9kdWxlLGV4cG9ydHMpe1xuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBfcnQgPSBsb2FkUnVudGltZSgpO1xuXG52YXIgX29uV2luZG93UmVzaXplID0gX3J0Lm9uV2luZG93UmVzaXplO1xuXG5yYWwub25XaW5kb3dSZXNpemUgPSBmdW5jdGlvbiAoY2FsbEJhY2spIHtcbiAgX29uV2luZG93UmVzaXplKGZ1bmN0aW9uIChzaXplKSB7XG4gICAgY2FsbEJhY2soc2l6ZS53aWR0aCB8fCBzaXplLndpbmRvd1dpZHRoLCBzaXplLmhlaWdodCB8fCBzaXplLndpbmRvd0hlaWdodCk7XG4gIH0pO1xufTtcblxufSx7fV0sMTE6W2Z1bmN0aW9uKHJlcXVpcmUsbW9kdWxlLGV4cG9ydHMpe1xuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBfaW5uZXJDb250ZXh0ID0gX2ludGVyb3BSZXF1aXJlRGVmYXVsdChyZXF1aXJlKFwiLi4vLi4vaW5uZXItY29udGV4dFwiKSk7XG5cbnZhciBfdXRpbCA9IF9pbnRlcm9wUmVxdWlyZURlZmF1bHQocmVxdWlyZShcIi4uLy4uL3V0aWxcIikpO1xuXG5mdW5jdGlvbiBfaW50ZXJvcFJlcXVpcmVEZWZhdWx0KG9iaikgeyByZXR1cm4gb2JqICYmIG9iai5fX2VzTW9kdWxlID8gb2JqIDogeyBcImRlZmF1bHRcIjogb2JqIH07IH1cblxudmFyIF9ydCA9IGxvYWRSdW50aW1lKCk7XG5cbl91dGlsW1wiZGVmYXVsdFwiXS5leHBvcnRUbyhcIkF1ZGlvRW5naW5lXCIsIF9ydCwgcmFsKTtcblxuX3V0aWxbXCJkZWZhdWx0XCJdLmV4cG9ydFRvKFwiY3JlYXRlSW5uZXJBdWRpb0NvbnRleHRcIiwgX3J0LCByYWwsIGZ1bmN0aW9uICgpIHtcbiAgaWYgKF9ydC5BdWRpb0VuZ2luZSkge1xuICAgIHJhbC5jcmVhdGVJbm5lckF1ZGlvQ29udGV4dCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiAoMCwgX2lubmVyQ29udGV4dFtcImRlZmF1bHRcIl0pKF9ydC5BdWRpb0VuZ2luZSk7XG4gICAgfTtcbiAgfVxufSk7XG5cbn0se1wiLi4vLi4vaW5uZXItY29udGV4dFwiOjIwLFwiLi4vLi4vdXRpbFwiOjIxfV0sMTI6W2Z1bmN0aW9uKHJlcXVpcmUsbW9kdWxlLGV4cG9ydHMpe1xuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBfdXRpbCA9IF9pbnRlcm9wUmVxdWlyZURlZmF1bHQocmVxdWlyZShcIi4uLy4uL3V0aWxcIikpO1xuXG5mdW5jdGlvbiBfaW50ZXJvcFJlcXVpcmVEZWZhdWx0KG9iaikgeyByZXR1cm4gb2JqICYmIG9iai5fX2VzTW9kdWxlID8gb2JqIDogeyBcImRlZmF1bHRcIjogb2JqIH07IH1cblxudmFyIF9ydCA9IGxvYWRSdW50aW1lKCk7XG5cbl91dGlsW1wiZGVmYXVsdFwiXS5leHBvcnRUbyhcImNyZWF0ZVZpZGVvXCIsIF9ydCwgcmFsKTtcblxufSx7XCIuLi8uLi91dGlsXCI6MjF9XSwxMzpbZnVuY3Rpb24ocmVxdWlyZSxtb2R1bGUsZXhwb3J0cyl7XG5cInVzZSBzdHJpY3RcIjtcblxudmFyIF91dGlsID0gX2ludGVyb3BSZXF1aXJlRGVmYXVsdChyZXF1aXJlKFwiLi4vLi4vdXRpbFwiKSk7XG5cbmZ1bmN0aW9uIF9pbnRlcm9wUmVxdWlyZURlZmF1bHQob2JqKSB7IHJldHVybiBvYmogJiYgb2JqLl9fZXNNb2R1bGUgPyBvYmogOiB7IFwiZGVmYXVsdFwiOiBvYmogfTsgfVxuXG52YXIgX3J0ID0gbG9hZFJ1bnRpbWUoKTtcblxuX3V0aWxbXCJkZWZhdWx0XCJdLmV4cG9ydFRvKFwiZG93bmxvYWRGaWxlXCIsIF9ydCwgcmFsKTtcblxufSx7XCIuLi8uLi91dGlsXCI6MjF9XSwxNDpbZnVuY3Rpb24ocmVxdWlyZSxtb2R1bGUsZXhwb3J0cyl7XG5cInVzZSBzdHJpY3RcIjtcblxudmFyIF91dGlsID0gX2ludGVyb3BSZXF1aXJlRGVmYXVsdChyZXF1aXJlKFwiLi4vLi4vdXRpbFwiKSk7XG5cbnZhciBfZmVhdHVyZSA9IF9pbnRlcm9wUmVxdWlyZURlZmF1bHQocmVxdWlyZShcIi4uLy4uL2ZlYXR1cmVcIikpO1xuXG5mdW5jdGlvbiBfaW50ZXJvcFJlcXVpcmVEZWZhdWx0KG9iaikgeyByZXR1cm4gb2JqICYmIG9iai5fX2VzTW9kdWxlID8gb2JqIDogeyBcImRlZmF1bHRcIjogb2JqIH07IH1cblxudmFyIF9ydCA9IGxvYWRSdW50aW1lKCk7XG5cbl91dGlsW1wiZGVmYXVsdFwiXS5leHBvcnRUbyhcImNyZWF0ZUNhbnZhc1wiLCBfcnQsIHJhbCwgZnVuY3Rpb24gKCkge1xuICB2YXIgZmVhdHVyZVZhbHVlID0gXCJ1bnN1cHBvcnRlZFwiO1xuXG4gIGlmIChkb2N1bWVudCAmJiB0eXBlb2YgZG9jdW1lbnQuY3JlYXRlRWxlbWVudCA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgZmVhdHVyZVZhbHVlID0gXCJ3cmFwcGVyXCI7XG5cbiAgICByYWwuY3JlYXRlQ2FudmFzID0gZnVuY3Rpb24gKCkge1xuICAgICAgcmV0dXJuIGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJjYW52YXNcIik7XG4gICAgfTtcbiAgfVxuXG4gIF9mZWF0dXJlW1wiZGVmYXVsdFwiXS5zZXRGZWF0dXJlKFwicmFsLmNyZWF0ZUNhbnZhc1wiLCBcInNwZWNcIiwgZmVhdHVyZVZhbHVlKTtcbn0pO1xuXG59LHtcIi4uLy4uL2ZlYXR1cmVcIjoxOSxcIi4uLy4uL3V0aWxcIjoyMX1dLDE1OltmdW5jdGlvbihyZXF1aXJlLG1vZHVsZSxleHBvcnRzKXtcblwidXNlIHN0cmljdFwiO1xuXG52YXIgX3V0aWwgPSBfaW50ZXJvcFJlcXVpcmVEZWZhdWx0KHJlcXVpcmUoXCIuLi8uLi91dGlsXCIpKTtcblxuZnVuY3Rpb24gX2ludGVyb3BSZXF1aXJlRGVmYXVsdChvYmopIHsgcmV0dXJuIG9iaiAmJiBvYmouX19lc01vZHVsZSA/IG9iaiA6IHsgXCJkZWZhdWx0XCI6IG9iaiB9OyB9XG5cbnZhciBfcnQgPSBsb2FkUnVudGltZSgpO1xuXG5fdXRpbFtcImRlZmF1bHRcIl0uZXhwb3J0VG8oXCJsb2FkRm9udFwiLCBfcnQsIHJhbCk7XG5cbn0se1wiLi4vLi4vdXRpbFwiOjIxfV0sMTY6W2Z1bmN0aW9uKHJlcXVpcmUsbW9kdWxlLGV4cG9ydHMpe1xuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBfcnQgPSBsb2FkUnVudGltZSgpO1xuXG5pZiAod2luZG93LmpzYiAmJiBqc2Iuc2V0UHJlZmVycmVkRnJhbWVzUGVyU2Vjb25kKSB7XG4gIHJhbC5zZXRQcmVmZXJyZWRGcmFtZXNQZXJTZWNvbmQgPSBqc2Iuc2V0UHJlZmVycmVkRnJhbWVzUGVyU2Vjb25kLmJpbmQoanNiKTtcbn0gZWxzZSBpZiAoX3J0LnNldFByZWZlcnJlZEZyYW1lc1BlclNlY29uZCkge1xuICByYWwuc2V0UHJlZmVycmVkRnJhbWVzUGVyU2Vjb25kID0gX3J0LnNldFByZWZlcnJlZEZyYW1lc1BlclNlY29uZC5iaW5kKF9ydCk7XG59IGVsc2Uge1xuICByYWwuc2V0UHJlZmVycmVkRnJhbWVzUGVyU2Vjb25kID0gZnVuY3Rpb24gKCkge1xuICAgIGNvbnNvbGUuZXJyb3IoXCJUaGUgc2V0UHJlZmVycmVkRnJhbWVzUGVyU2Vjb25kIGlzIG5vdCBkZWZpbmUhXCIpO1xuICB9O1xufVxuXG59LHt9XSwxNzpbZnVuY3Rpb24ocmVxdWlyZSxtb2R1bGUsZXhwb3J0cyl7XG5cInVzZSBzdHJpY3RcIjtcblxudmFyIF91dGlsID0gX2ludGVyb3BSZXF1aXJlRGVmYXVsdChyZXF1aXJlKFwiLi4vLi4vdXRpbFwiKSk7XG5cbnZhciBfZmVhdHVyZSA9IF9pbnRlcm9wUmVxdWlyZURlZmF1bHQocmVxdWlyZShcIi4uLy4uL2ZlYXR1cmVcIikpO1xuXG5mdW5jdGlvbiBfaW50ZXJvcFJlcXVpcmVEZWZhdWx0KG9iaikgeyByZXR1cm4gb2JqICYmIG9iai5fX2VzTW9kdWxlID8gb2JqIDogeyBcImRlZmF1bHRcIjogb2JqIH07IH1cblxudmFyIF9ydCA9IGxvYWRSdW50aW1lKCk7XG5cbl91dGlsW1wiZGVmYXVsdFwiXS5leHBvcnRUbyhcImxvYWRJbWFnZURhdGFcIiwgX3J0LCByYWwpO1xuXG5fdXRpbFtcImRlZmF1bHRcIl0uZXhwb3J0VG8oXCJjcmVhdGVJbWFnZVwiLCBfcnQsIHJhbCwgZnVuY3Rpb24gKCkge1xuICB2YXIgZmVhdHVyZVZhbHVlID0gXCJ1bnN1cHBvcnRlZFwiO1xuXG4gIGlmIChkb2N1bWVudCAmJiB0eXBlb2YgZG9jdW1lbnQuY3JlYXRlRWxlbWVudCA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgZmVhdHVyZVZhbHVlID0gXCJ3cmFwcGVyXCI7XG5cbiAgICByYWwuY3JlYXRlSW1hZ2UgPSBmdW5jdGlvbiAoKSB7XG4gICAgICByZXR1cm4gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImltYWdlXCIpO1xuICAgIH07XG4gIH1cblxuICBfZmVhdHVyZVtcImRlZmF1bHRcIl0uc2V0RmVhdHVyZShcInJhbC5jcmVhdGVJbWFnZVwiLCBcInNwZWNcIiwgZmVhdHVyZVZhbHVlKTtcbn0pO1xuXG59LHtcIi4uLy4uL2ZlYXR1cmVcIjoxOSxcIi4uLy4uL3V0aWxcIjoyMX1dLDE4OltmdW5jdGlvbihyZXF1aXJlLG1vZHVsZSxleHBvcnRzKXtcblwidXNlIHN0cmljdFwiO1xuXG5pZiAod2luZG93Ll9fZ2wpIHtcbiAgdmFyIGdsID0gd2luZG93Ll9fZ2w7XG4gIHZhciBfZ2xUZXhJbWFnZTJEID0gZ2wudGV4SW1hZ2UyRDtcblxuICBnbC50ZXhJbWFnZTJEID0gZnVuY3Rpb24gKHRhcmdldCwgbGV2ZWwsIGludGVybmFsZm9ybWF0LCB3aWR0aCwgaGVpZ2h0LCBib3JkZXIsIGZvcm1hdCwgdHlwZSwgcGl4ZWxzKSB7XG4gICAgdmFyIGFyZ2MgPSBhcmd1bWVudHMubGVuZ3RoO1xuXG4gICAgaWYgKGFyZ2MgPT09IDYpIHtcbiAgICAgIHZhciBpbWFnZSA9IGJvcmRlcjtcbiAgICAgIHR5cGUgPSBoZWlnaHQ7XG4gICAgICBmb3JtYXQgPSB3aWR0aDtcblxuICAgICAgaWYgKGltYWdlIGluc3RhbmNlb2YgSFRNTEltYWdlRWxlbWVudCkge1xuICAgICAgICB2YXIgZXJyb3IgPSBjb25zb2xlLmVycm9yO1xuXG4gICAgICAgIGNvbnNvbGUuZXJyb3IgPSBmdW5jdGlvbiAoKSB7fTtcblxuICAgICAgICBfZ2xUZXhJbWFnZTJELmFwcGx5KHZvaWQgMCwgYXJndW1lbnRzKTtcblxuICAgICAgICBjb25zb2xlLmVycm9yID0gZXJyb3I7XG4gICAgICAgIGdsLnRleEltYWdlMkRfaW1hZ2UodGFyZ2V0LCBsZXZlbCwgaW1hZ2UuX2ltYWdlTWV0YSk7XG4gICAgICB9IGVsc2UgaWYgKGltYWdlIGluc3RhbmNlb2YgSFRNTENhbnZhc0VsZW1lbnQpIHtcbiAgICAgICAgdmFyIF9lcnJvciA9IGNvbnNvbGUuZXJyb3I7XG5cbiAgICAgICAgY29uc29sZS5lcnJvciA9IGZ1bmN0aW9uICgpIHt9O1xuXG4gICAgICAgIF9nbFRleEltYWdlMkQuYXBwbHkodm9pZCAwLCBhcmd1bWVudHMpO1xuXG4gICAgICAgIGNvbnNvbGUuZXJyb3IgPSBfZXJyb3I7XG4gICAgICAgIHZhciBjb250ZXh0MkQgPSBpbWFnZS5nZXRDb250ZXh0KCcyZCcpO1xuICAgICAgICBnbC50ZXhJbWFnZTJEX2NhbnZhcyh0YXJnZXQsIGxldmVsLCBpbnRlcm5hbGZvcm1hdCwgZm9ybWF0LCB0eXBlLCBjb250ZXh0MkQpO1xuICAgICAgfSBlbHNlIGlmIChpbWFnZSBpbnN0YW5jZW9mIEltYWdlRGF0YSkge1xuICAgICAgICB2YXIgX2Vycm9yMiA9IGNvbnNvbGUuZXJyb3I7XG5cbiAgICAgICAgY29uc29sZS5lcnJvciA9IGZ1bmN0aW9uICgpIHt9O1xuXG4gICAgICAgIF9nbFRleEltYWdlMkQodGFyZ2V0LCBsZXZlbCwgaW50ZXJuYWxmb3JtYXQsIGltYWdlLndpZHRoLCBpbWFnZS5oZWlnaHQsIDAsIGZvcm1hdCwgdHlwZSwgaW1hZ2UuZGF0YSk7XG5cbiAgICAgICAgY29uc29sZS5lcnJvciA9IF9lcnJvcjI7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zb2xlLmVycm9yKFwiSW52YWxpZCBwaXhlbCBhcmd1bWVudCBwYXNzZWQgdG8gZ2wudGV4SW1hZ2UyRCFcIik7XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChhcmdjID09PSA5KSB7XG4gICAgICBfZ2xUZXhJbWFnZTJEKHRhcmdldCwgbGV2ZWwsIGludGVybmFsZm9ybWF0LCB3aWR0aCwgaGVpZ2h0LCBib3JkZXIsIGZvcm1hdCwgdHlwZSwgcGl4ZWxzKTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc29sZS5lcnJvcihcImdsLnRleEltYWdlMkQ6IGludmFsaWQgYXJndW1lbnQgY291bnQhXCIpO1xuICAgIH1cbiAgfTtcblxuICB2YXIgX2dsVGV4U3ViSW1hZ2UyRCA9IGdsLnRleFN1YkltYWdlMkQ7XG5cbiAgZ2wudGV4U3ViSW1hZ2UyRCA9IGZ1bmN0aW9uICh0YXJnZXQsIGxldmVsLCB4b2Zmc2V0LCB5b2Zmc2V0LCB3aWR0aCwgaGVpZ2h0LCBmb3JtYXQsIHR5cGUsIHBpeGVscykge1xuICAgIHZhciBhcmdjID0gYXJndW1lbnRzLmxlbmd0aDtcblxuICAgIGlmIChhcmdjID09PSA3KSB7XG4gICAgICB2YXIgaW1hZ2UgPSBmb3JtYXQ7XG4gICAgICB0eXBlID0gaGVpZ2h0O1xuICAgICAgZm9ybWF0ID0gd2lkdGg7XG5cbiAgICAgIGlmIChpbWFnZSBpbnN0YW5jZW9mIEhUTUxJbWFnZUVsZW1lbnQpIHtcbiAgICAgICAgdmFyIGVycm9yID0gY29uc29sZS5lcnJvcjtcblxuICAgICAgICBjb25zb2xlLmVycm9yID0gZnVuY3Rpb24gKCkge307XG5cbiAgICAgICAgX2dsVGV4U3ViSW1hZ2UyRC5hcHBseSh2b2lkIDAsIGFyZ3VtZW50cyk7XG5cbiAgICAgICAgY29uc29sZS5lcnJvciA9IGVycm9yO1xuICAgICAgICBnbC50ZXhTdWJJbWFnZTJEX2ltYWdlKHRhcmdldCwgbGV2ZWwsIHhvZmZzZXQsIHlvZmZzZXQsIGltYWdlLl9pbWFnZU1ldGEpO1xuICAgICAgfSBlbHNlIGlmIChpbWFnZSBpbnN0YW5jZW9mIEhUTUxDYW52YXNFbGVtZW50KSB7XG4gICAgICAgIHZhciBfZXJyb3IzID0gY29uc29sZS5lcnJvcjtcblxuICAgICAgICBjb25zb2xlLmVycm9yID0gZnVuY3Rpb24gKCkge307XG5cbiAgICAgICAgX2dsVGV4U3ViSW1hZ2UyRC5hcHBseSh2b2lkIDAsIGFyZ3VtZW50cyk7XG5cbiAgICAgICAgY29uc29sZS5lcnJvciA9IF9lcnJvcjM7XG4gICAgICAgIHZhciBjb250ZXh0MkQgPSBpbWFnZS5nZXRDb250ZXh0KCcyZCcpO1xuICAgICAgICBnbC50ZXhTdWJJbWFnZTJEX2NhbnZhcyh0YXJnZXQsIGxldmVsLCB4b2Zmc2V0LCB5b2Zmc2V0LCBmb3JtYXQsIHR5cGUsIGNvbnRleHQyRCk7XG4gICAgICB9IGVsc2UgaWYgKGltYWdlIGluc3RhbmNlb2YgSW1hZ2VEYXRhKSB7XG4gICAgICAgIHZhciBfZXJyb3I0ID0gY29uc29sZS5lcnJvcjtcblxuICAgICAgICBjb25zb2xlLmVycm9yID0gZnVuY3Rpb24gKCkge307XG5cbiAgICAgICAgX2dsVGV4U3ViSW1hZ2UyRCh0YXJnZXQsIGxldmVsLCB4b2Zmc2V0LCB5b2Zmc2V0LCBpbWFnZS53aWR0aCwgaW1hZ2UuaGVpZ2h0LCBmb3JtYXQsIHR5cGUsIGltYWdlLmRhdGEpO1xuXG4gICAgICAgIGNvbnNvbGUuZXJyb3IgPSBfZXJyb3I0O1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihcIkludmFsaWQgcGl4ZWwgYXJndW1lbnQgcGFzc2VkIHRvIGdsLnRleEltYWdlMkQhXCIpO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoYXJnYyA9PT0gOSkge1xuICAgICAgX2dsVGV4U3ViSW1hZ2UyRCh0YXJnZXQsIGxldmVsLCB4b2Zmc2V0LCB5b2Zmc2V0LCB3aWR0aCwgaGVpZ2h0LCBmb3JtYXQsIHR5cGUsIHBpeGVscyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IobmV3IEVycm9yKFwiZ2wudGV4SW1hZ2UyRDogaW52YWxpZCBhcmd1bWVudCBjb3VudCFcIikuc3RhY2spO1xuICAgIH1cbiAgfTtcbn1cblxufSx7fV0sMTk6W2Z1bmN0aW9uKHJlcXVpcmUsbW9kdWxlLGV4cG9ydHMpe1xuXCJ1c2Ugc3RyaWN0XCI7XG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIl9fZXNNb2R1bGVcIiwge1xuICB2YWx1ZTogdHJ1ZVxufSk7XG5leHBvcnRzW1wiZGVmYXVsdFwiXSA9IHZvaWQgMDtcbnZhciBfZmVhdHVyZXMgPSB7fTtcbnZhciBfZGVmYXVsdCA9IHtcbiAgc2V0RmVhdHVyZTogZnVuY3Rpb24gc2V0RmVhdHVyZShmZWF0dXJlTmFtZSwgcHJvcGVydHksIHZhbHVlKSB7XG4gICAgdmFyIGZlYXR1cmUgPSBfZmVhdHVyZXNbZmVhdHVyZU5hbWVdO1xuXG4gICAgaWYgKCFmZWF0dXJlKSB7XG4gICAgICBmZWF0dXJlID0gX2ZlYXR1cmVzW2ZlYXR1cmVOYW1lXSA9IHt9O1xuICAgIH1cblxuICAgIGZlYXR1cmVbcHJvcGVydHldID0gdmFsdWU7XG4gIH0sXG4gIGdldEZlYXR1cmVQcm9wZXJ0eTogZnVuY3Rpb24gZ2V0RmVhdHVyZVByb3BlcnR5KGZlYXR1cmVOYW1lLCBwcm9wZXJ0eSkge1xuICAgIHZhciBmZWF0dXJlID0gX2ZlYXR1cmVzW2ZlYXR1cmVOYW1lXTtcbiAgICByZXR1cm4gZmVhdHVyZSA/IGZlYXR1cmVbcHJvcGVydHldIDogdW5kZWZpbmVkO1xuICB9XG59O1xuZXhwb3J0c1tcImRlZmF1bHRcIl0gPSBfZGVmYXVsdDtcblxufSx7fV0sMjA6W2Z1bmN0aW9uKHJlcXVpcmUsbW9kdWxlLGV4cG9ydHMpe1xuXCJ1c2Ugc3RyaWN0XCI7XG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIl9fZXNNb2R1bGVcIiwge1xuICB2YWx1ZTogdHJ1ZVxufSk7XG5leHBvcnRzW1wiZGVmYXVsdFwiXSA9IF9kZWZhdWx0O1xudmFyIF9DQU5QTEFZX0NBTExCQUNLID0gXCJjYW5wbGF5Q2FsbGJhY2tzXCI7XG52YXIgX0VOREVEX0NBTExCQUNLID0gXCJlbmRlZENhbGxiYWNrc1wiO1xudmFyIF9FUlJPUl9DQUxMQkFDSyA9IFwiZXJyb3JDYWxsYmFja3NcIjtcbnZhciBfUEFVU0VfQ0FMTEJBQ0sgPSBcInBhdXNlQ2FsbGJhY2tzXCI7XG52YXIgX1BMQVlfQ0FMTEJBQ0sgPSBcInBsYXlDYWxsYmFja3NcIjtcbnZhciBfU0VFS0VEX0NBTExCQUNLID0gXCJzZWVrZWRDYWxsYmFja3NcIjtcbnZhciBfU0VFS0lOR19DQUxMQkFDSyA9IFwic2Vla2luZ0NhbGxiYWNrc1wiO1xudmFyIF9TVE9QX0NBTExCQUNLID0gXCJzdG9wQ2FsbGJhY2tzXCI7XG52YXIgX1RJTUVfVVBEQVRFX0NBTExCQUNLID0gXCJ0aW1lVXBkYXRlQ2FsbGJhY2tzXCI7XG52YXIgX1dBSVRJTkdfQ0FMTEJBQ0sgPSBcIndhaXRpbmdDYWxsYmFja3NcIjtcbnZhciBfRVJST1JfQ09ERSA9IHtcbiAgRVJST1JfU1lTVEVNOiAxMDAwMSxcbiAgRVJST1JfTkVUOiAxMDAwMixcbiAgRVJST1JfRklMRTogMTAwMDMsXG4gIEVSUk9SX0ZPUk1BVDogMTAwMDQsXG4gIEVSUk9SX1VOS05PV046IC0xXG59O1xudmFyIF9TVEFURSA9IHtcbiAgRVJST1I6IC0xLFxuICBJTklUSUFMSVpJTkc6IDAsXG4gIFBMQVlJTkc6IDEsXG4gIFBBVVNFRDogMlxufTtcbnZhciBfYXVkaW9FbmdpbmUgPSB1bmRlZmluZWQ7XG5cbnZhciBfd2Vha01hcCA9IG5ldyBXZWFrTWFwKCk7XG5cbnZhciBfb2ZmQ2FsbGJhY2sgPSBmdW5jdGlvbiBfb2ZmQ2FsbGJhY2sodGFyZ2V0LCB0eXBlLCBjYWxsYmFjaykge1xuICB2YXIgcHJpdmF0ZVRoaXMgPSBfd2Vha01hcC5nZXQodGFyZ2V0KTtcblxuICBpZiAodHlwZW9mIGNhbGxiYWNrICE9PSBcImZ1bmN0aW9uXCIgfHwgIXByaXZhdGVUaGlzKSB7XG4gICAgcmV0dXJuIC0xO1xuICB9XG5cbiAgdmFyIGNhbGxiYWNrcyA9IHByaXZhdGVUaGlzW3R5cGVdIHx8IFtdO1xuXG4gIGZvciAodmFyIGkgPSAwLCBsZW4gPSBjYWxsYmFja3MubGVuZ3RoOyBpIDwgbGVuOyArK2kpIHtcbiAgICBpZiAoY2FsbGJhY2sgPT09IGNhbGxiYWNrc1tpXSkge1xuICAgICAgY2FsbGJhY2tzLnNwbGljZShpLCAxKTtcbiAgICAgIHJldHVybiBjYWxsYmFjay5sZW5ndGggKyAxO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiAwO1xufTtcblxudmFyIF9vbkNhbGxiYWNrID0gZnVuY3Rpb24gX29uQ2FsbGJhY2sodGFyZ2V0LCB0eXBlLCBjYWxsYmFjaykge1xuICB2YXIgcHJpdmF0ZVRoaXMgPSBfd2Vha01hcC5nZXQodGFyZ2V0KTtcblxuICBpZiAodHlwZW9mIGNhbGxiYWNrICE9PSBcImZ1bmN0aW9uXCIgfHwgIXByaXZhdGVUaGlzKSB7XG4gICAgcmV0dXJuIC0xO1xuICB9XG5cbiAgdmFyIGNhbGxiYWNrcyA9IHByaXZhdGVUaGlzW3R5cGVdO1xuXG4gIGlmICghY2FsbGJhY2tzKSB7XG4gICAgY2FsbGJhY2tzID0gcHJpdmF0ZVRoaXNbdHlwZV0gPSBbY2FsbGJhY2tdO1xuICB9IGVsc2Uge1xuICAgIGZvciAodmFyIGkgPSAwLCBsZW4gPSBjYWxsYmFja3MubGVuZ3RoOyBpIDwgbGVuOyArK2kpIHtcbiAgICAgIGlmIChjYWxsYmFjayA9PT0gY2FsbGJhY2tzW2ldKSB7XG4gICAgICAgIHJldHVybiAwO1xuICAgICAgfVxuICAgIH1cblxuICAgIGNhbGxiYWNrcy5wdXNoKGNhbGxiYWNrKTtcbiAgfVxuXG4gIHJldHVybiBjYWxsYmFja3MubGVuZ3RoO1xufTtcblxudmFyIF9kaXNwYXRjaENhbGxiYWNrID0gZnVuY3Rpb24gX2Rpc3BhdGNoQ2FsbGJhY2sodGFyZ2V0LCB0eXBlKSB7XG4gIHZhciBhcmdzID0gYXJndW1lbnRzLmxlbmd0aCA+IDIgJiYgYXJndW1lbnRzWzJdICE9PSB1bmRlZmluZWQgPyBhcmd1bWVudHNbMl0gOiBbXTtcblxuICB2YXIgcHJpdmF0ZVRoaXMgPSBfd2Vha01hcC5nZXQodGFyZ2V0KTtcblxuICBpZiAocHJpdmF0ZVRoaXMpIHtcbiAgICB2YXIgY2FsbGJhY2tzID0gcHJpdmF0ZVRoaXNbdHlwZV0gfHwgW107XG5cbiAgICBmb3IgKHZhciBpID0gMCwgbGVuID0gY2FsbGJhY2tzLmxlbmd0aDsgaSA8IGxlbjsgKytpKSB7XG4gICAgICBjYWxsYmFja3NbaV0uYXBwbHkodGFyZ2V0LCBhcmdzKTtcbiAgICB9XG4gIH1cbn07XG5cbmZ1bmN0aW9uIElubmVyQXVkaW9Db250ZXh0KCkge1xuICB0aGlzLnN0YXJ0VGltZSA9IDA7XG4gIHRoaXMuYXV0b3BsYXkgPSBmYWxzZTtcblxuICBfd2Vha01hcC5zZXQodGhpcywge1xuICAgIHNyYzogXCJcIixcbiAgICB2b2x1bWU6IDEsXG4gICAgbG9vcDogZmFsc2VcbiAgfSk7XG5cbiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRoaXMsIFwibG9vcFwiLCB7XG4gICAgc2V0OiBmdW5jdGlvbiBzZXQodmFsdWUpIHtcbiAgICAgIHZhbHVlID0gISF2YWx1ZTtcblxuICAgICAgdmFyIHByaXZhdGVUaGlzID0gX3dlYWtNYXAuZ2V0KHRoaXMpO1xuXG4gICAgICBpZiAocHJpdmF0ZVRoaXMpIHtcbiAgICAgICAgdmFyIGF1ZGlvSUQgPSBwcml2YXRlVGhpcy5hdWRpb0lEO1xuXG4gICAgICAgIGlmICh0eXBlb2YgYXVkaW9JRCA9PT0gXCJudW1iZXJcIiAmJiBhdWRpb0lEID49IDApIHtcbiAgICAgICAgICBfYXVkaW9FbmdpbmUuc2V0TG9vcChhdWRpb0lELCB2YWx1ZSk7XG4gICAgICAgIH1cblxuICAgICAgICBwcml2YXRlVGhpcy5sb29wID0gdmFsdWU7XG4gICAgICB9XG4gICAgfSxcbiAgICBnZXQ6IGZ1bmN0aW9uIGdldCgpIHtcbiAgICAgIHZhciBwcml2YXRlVGhpcyA9IF93ZWFrTWFwLmdldCh0aGlzKTtcblxuICAgICAgcmV0dXJuIHByaXZhdGVUaGlzID8gcHJpdmF0ZVRoaXMubG9vcCA6IGZhbHNlO1xuICAgIH1cbiAgfSk7XG4gIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0aGlzLCBcInZvbHVtZVwiLCB7XG4gICAgc2V0OiBmdW5jdGlvbiBzZXQodmFsdWUpIHtcbiAgICAgIGlmICh0eXBlb2YgdmFsdWUgPT09IFwibnVtYmVyXCIpIHtcbiAgICAgICAgaWYgKHZhbHVlIDwgMCkge1xuICAgICAgICAgIHZhbHVlID0gMDtcbiAgICAgICAgfSBlbHNlIGlmICh2YWx1ZSA+IDEpIHtcbiAgICAgICAgICB2YWx1ZSA9IDE7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHZhbHVlID0gMTtcbiAgICAgIH1cblxuICAgICAgdmFyIHByaXZhdGVUaGlzID0gX3dlYWtNYXAuZ2V0KHRoaXMpO1xuXG4gICAgICBpZiAocHJpdmF0ZVRoaXMpIHtcbiAgICAgICAgdmFyIGF1ZGlvSUQgPSBwcml2YXRlVGhpcy5hdWRpb0lEO1xuXG4gICAgICAgIGlmICh0eXBlb2YgYXVkaW9JRCA9PT0gXCJudW1iZXJcIiAmJiBhdWRpb0lEID49IDApIHtcbiAgICAgICAgICBfYXVkaW9FbmdpbmUuc2V0Vm9sdW1lKGF1ZGlvSUQsIHZhbHVlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHByaXZhdGVUaGlzLnZvbHVtZSA9IHZhbHVlO1xuICAgICAgfVxuICAgIH0sXG4gICAgZ2V0OiBmdW5jdGlvbiBnZXQoKSB7XG4gICAgICB2YXIgcHJpdmF0ZVRoaXMgPSBfd2Vha01hcC5nZXQodGhpcyk7XG5cbiAgICAgIHJldHVybiBwcml2YXRlVGhpcyA/IHByaXZhdGVUaGlzLnZvbHVtZSA6IDE7XG4gICAgfVxuICB9KTtcbiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRoaXMsIFwic3JjXCIsIHtcbiAgICBzZXQ6IGZ1bmN0aW9uIHNldCh2YWx1ZSkge1xuICAgICAgdmFyIHByaXZhdGVUaGlzID0gX3dlYWtNYXAuZ2V0KHRoaXMpO1xuXG4gICAgICBpZiAoIXByaXZhdGVUaGlzKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdmFyIG9sZFNyYyA9IHByaXZhdGVUaGlzLnNyYztcbiAgICAgIHByaXZhdGVUaGlzLnNyYyA9IHZhbHVlO1xuXG4gICAgICBpZiAodHlwZW9mIHZhbHVlID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgIHZhciBhdWRpb0lEID0gcHJpdmF0ZVRoaXMuYXVkaW9JRDtcblxuICAgICAgICBpZiAodHlwZW9mIGF1ZGlvSUQgPT09IFwibnVtYmVyXCIgJiYgYXVkaW9JRCA+PSAwICYmIF9hdWRpb0VuZ2luZS5nZXRTdGF0ZShhdWRpb0lEKSA9PT0gX1NUQVRFLlBBVVNFRCAmJiBvbGRTcmMgIT09IHZhbHVlKSB7XG4gICAgICAgICAgX2F1ZGlvRW5naW5lLnN0b3AoYXVkaW9JRCk7XG5cbiAgICAgICAgICBwcml2YXRlVGhpcy5hdWRpb0lEID0gLTE7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgc2VsZiA9IHRoaXM7XG5cbiAgICAgICAgX2F1ZGlvRW5naW5lLnByZWxvYWQodmFsdWUsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGlmIChzZWxmLnNyYyA9PT0gdmFsdWUpIHtcbiAgICAgICAgICAgICAgX2Rpc3BhdGNoQ2FsbGJhY2soc2VsZiwgX0NBTlBMQVlfQ0FMTEJBQ0spO1xuXG4gICAgICAgICAgICAgIGlmIChzZWxmLmF1dG9wbGF5KSB7XG4gICAgICAgICAgICAgICAgc2VsZi5wbGF5KCk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSxcbiAgICBnZXQ6IGZ1bmN0aW9uIGdldCgpIHtcbiAgICAgIHZhciBwcml2YXRlVGhpcyA9IF93ZWFrTWFwLmdldCh0aGlzKTtcblxuICAgICAgcmV0dXJuIHByaXZhdGVUaGlzID8gcHJpdmF0ZVRoaXMuc3JjIDogXCJcIjtcbiAgICB9XG4gIH0pO1xuICBPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywgXCJkdXJhdGlvblwiLCB7XG4gICAgZ2V0OiBmdW5jdGlvbiBnZXQoKSB7XG4gICAgICB2YXIgcHJpdmF0ZVRoaXMgPSBfd2Vha01hcC5nZXQodGhpcyk7XG5cbiAgICAgIGlmIChwcml2YXRlVGhpcykge1xuICAgICAgICB2YXIgYXVkaW9JRCA9IHByaXZhdGVUaGlzLmF1ZGlvSUQ7XG5cbiAgICAgICAgaWYgKHR5cGVvZiBhdWRpb0lEID09PSBcIm51bWJlclwiICYmIGF1ZGlvSUQgPj0gMCkge1xuICAgICAgICAgIHJldHVybiBfYXVkaW9FbmdpbmUuZ2V0RHVyYXRpb24oYXVkaW9JRCk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIE5hTjtcbiAgICB9LFxuICAgIHNldDogZnVuY3Rpb24gc2V0KCkge31cbiAgfSk7XG4gIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0aGlzLCBcImN1cnJlbnRUaW1lXCIsIHtcbiAgICBnZXQ6IGZ1bmN0aW9uIGdldCgpIHtcbiAgICAgIHZhciBwcml2YXRlVGhpcyA9IF93ZWFrTWFwLmdldCh0aGlzKTtcblxuICAgICAgaWYgKHByaXZhdGVUaGlzKSB7XG4gICAgICAgIHZhciBhdWRpb0lEID0gcHJpdmF0ZVRoaXMuYXVkaW9JRDtcblxuICAgICAgICBpZiAodHlwZW9mIGF1ZGlvSUQgPT09IFwibnVtYmVyXCIgJiYgYXVkaW9JRCA+PSAwKSB7XG4gICAgICAgICAgcmV0dXJuIF9hdWRpb0VuZ2luZS5nZXRDdXJyZW50VGltZShhdWRpb0lEKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gMDtcbiAgICB9LFxuICAgIHNldDogZnVuY3Rpb24gc2V0KCkge31cbiAgfSk7XG4gIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0aGlzLCBcInBhdXNlZFwiLCB7XG4gICAgZ2V0OiBmdW5jdGlvbiBnZXQoKSB7XG4gICAgICB2YXIgcHJpdmF0ZVRoaXMgPSBfd2Vha01hcC5nZXQodGhpcyk7XG5cbiAgICAgIGlmIChwcml2YXRlVGhpcykge1xuICAgICAgICB2YXIgYXVkaW9JRCA9IHByaXZhdGVUaGlzLmF1ZGlvSUQ7XG5cbiAgICAgICAgaWYgKHR5cGVvZiBhdWRpb0lEID09PSBcIm51bWJlclwiICYmIGF1ZGlvSUQgPj0gMCkge1xuICAgICAgICAgIHJldHVybiBfYXVkaW9FbmdpbmUuZ2V0U3RhdGUoYXVkaW9JRCkgPT09IF9TVEFURS5QQVVTRUQ7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSxcbiAgICBzZXQ6IGZ1bmN0aW9uIHNldCgpIHt9XG4gIH0pO1xuICBPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywgXCJidWZmZXJlZFwiLCB7XG4gICAgZ2V0OiBmdW5jdGlvbiBnZXQoKSB7XG4gICAgICB2YXIgcHJpdmF0ZVRoaXMgPSBfd2Vha01hcC5nZXQodGhpcyk7XG5cbiAgICAgIGlmIChwcml2YXRlVGhpcykge1xuICAgICAgICB2YXIgYXVkaW9JRCA9IHByaXZhdGVUaGlzLmF1ZGlvSUQ7XG5cbiAgICAgICAgaWYgKHR5cGVvZiBhdWRpb0lEID09PSBcIm51bWJlclwiICYmIGF1ZGlvSUQgPj0gMCkge1xuICAgICAgICAgIHJldHVybiBfYXVkaW9FbmdpbmUuZ2V0QnVmZmVyZWQoYXVkaW9JRCk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIDA7XG4gICAgfSxcbiAgICBzZXQ6IGZ1bmN0aW9uIHNldCgpIHt9XG4gIH0pO1xufVxuXG52YXIgX3Byb3RvdHlwZSA9IElubmVyQXVkaW9Db250ZXh0LnByb3RvdHlwZTtcblxuX3Byb3RvdHlwZS5kZXN0cm95ID0gZnVuY3Rpb24gKCkge1xuICB2YXIgcHJpdmF0ZVRoaXMgPSBfd2Vha01hcC5nZXQodGhpcyk7XG5cbiAgaWYgKHByaXZhdGVUaGlzKSB7XG4gICAgdmFyIGF1ZGlvSUQgPSBwcml2YXRlVGhpcy5hdWRpb0lEO1xuXG4gICAgaWYgKHR5cGVvZiBhdWRpb0lEID09PSBcIm51bWJlclwiICYmIGF1ZGlvSUQgPj0gMCkge1xuICAgICAgX2F1ZGlvRW5naW5lLnN0b3AoYXVkaW9JRCk7XG5cbiAgICAgIHByaXZhdGVUaGlzLmF1ZGlvSUQgPSAtMTtcblxuICAgICAgX2Rpc3BhdGNoQ2FsbGJhY2sodGhpcywgX1NUT1BfQ0FMTEJBQ0spO1xuICAgIH1cblxuICAgIHByaXZhdGVUaGlzW19DQU5QTEFZX0NBTExCQUNLXSA9IFtdO1xuICAgIHByaXZhdGVUaGlzW19FTkRFRF9DQUxMQkFDS10gPSBbXTtcbiAgICBwcml2YXRlVGhpc1tfRVJST1JfQ0FMTEJBQ0tdID0gW107XG4gICAgcHJpdmF0ZVRoaXNbX1BBVVNFX0NBTExCQUNLXSA9IFtdO1xuICAgIHByaXZhdGVUaGlzW19QTEFZX0NBTExCQUNLXSA9IFtdO1xuICAgIHByaXZhdGVUaGlzW19TRUVLRURfQ0FMTEJBQ0tdID0gW107XG4gICAgcHJpdmF0ZVRoaXNbX1NFRUtJTkdfQ0FMTEJBQ0tdID0gW107XG4gICAgcHJpdmF0ZVRoaXNbX1NUT1BfQ0FMTEJBQ0tdID0gW107XG4gICAgcHJpdmF0ZVRoaXNbX1RJTUVfVVBEQVRFX0NBTExCQUNLXSA9IFtdO1xuICAgIHByaXZhdGVUaGlzW19XQUlUSU5HX0NBTExCQUNLXSA9IFtdO1xuICAgIGNsZWFySW50ZXJ2YWwocHJpdmF0ZVRoaXMuaW50ZXJ2YWxJRCk7XG4gIH1cbn07XG5cbl9wcm90b3R5cGUucGxheSA9IGZ1bmN0aW9uICgpIHtcbiAgdmFyIHByaXZhdGVUaGlzID0gX3dlYWtNYXAuZ2V0KHRoaXMpO1xuXG4gIGlmICghcHJpdmF0ZVRoaXMpIHtcbiAgICByZXR1cm47XG4gIH1cblxuICB2YXIgc3JjID0gcHJpdmF0ZVRoaXMuc3JjO1xuICB2YXIgYXVkaW9JRCA9IHByaXZhdGVUaGlzLmF1ZGlvSUQ7XG5cbiAgaWYgKHR5cGVvZiBzcmMgIT09IFwic3RyaW5nXCIgfHwgc3JjID09PSBcIlwiKSB7XG4gICAgX2Rpc3BhdGNoQ2FsbGJhY2sodGhpcywgX0VSUk9SX0NBTExCQUNLLCBbe1xuICAgICAgZXJyTXNnOiBcImludmFsaWQgc3JjXCIsXG4gICAgICBlcnJDb2RlOiBfRVJST1JfQ09ERS5FUlJPUl9GSUxFXG4gICAgfV0pO1xuXG4gICAgcmV0dXJuO1xuICB9XG5cbiAgaWYgKHR5cGVvZiBhdWRpb0lEID09PSBcIm51bWJlclwiICYmIGF1ZGlvSUQgPj0gMCkge1xuICAgIGlmIChfYXVkaW9FbmdpbmUuZ2V0U3RhdGUoYXVkaW9JRCkgPT09IF9TVEFURS5QQVVTRUQpIHtcbiAgICAgIF9hdWRpb0VuZ2luZS5yZXN1bWUoYXVkaW9JRCk7XG5cbiAgICAgIF9kaXNwYXRjaENhbGxiYWNrKHRoaXMsIF9QTEFZX0NBTExCQUNLKTtcblxuICAgICAgcmV0dXJuO1xuICAgIH0gZWxzZSB7XG4gICAgICBfYXVkaW9FbmdpbmUuc3RvcChhdWRpb0lEKTtcblxuICAgICAgcHJpdmF0ZVRoaXMuYXVkaW9JRCA9IC0xO1xuICAgIH1cbiAgfVxuXG4gIGF1ZGlvSUQgPSBfYXVkaW9FbmdpbmUucGxheShzcmMsIHRoaXMubG9vcCwgdGhpcy52b2x1bWUpO1xuXG4gIGlmIChhdWRpb0lEID09PSAtMSkge1xuICAgIF9kaXNwYXRjaENhbGxiYWNrKHRoaXMsIF9FUlJPUl9DQUxMQkFDSywgW3tcbiAgICAgIGVyck1zZzogXCJ1bmtub3duXCIsXG4gICAgICBlcnJDb2RlOiBfRVJST1JfQ09ERS5FUlJPUl9VTktOT1dOXG4gICAgfV0pO1xuXG4gICAgcmV0dXJuO1xuICB9XG5cbiAgcHJpdmF0ZVRoaXMuYXVkaW9JRCA9IGF1ZGlvSUQ7XG5cbiAgaWYgKHR5cGVvZiB0aGlzLnN0YXJ0VGltZSA9PT0gXCJudW1iZXJcIiAmJiB0aGlzLnN0YXJ0VGltZSA+IDApIHtcbiAgICBfYXVkaW9FbmdpbmUuc2V0Q3VycmVudFRpbWUoYXVkaW9JRCwgdGhpcy5zdGFydFRpbWUpO1xuICB9XG5cbiAgX2Rpc3BhdGNoQ2FsbGJhY2sodGhpcywgX1dBSVRJTkdfQ0FMTEJBQ0spO1xuXG4gIHZhciBzZWxmID0gdGhpcztcblxuICBfYXVkaW9FbmdpbmUuc2V0Q2FuUGxheUNhbGxiYWNrKGF1ZGlvSUQsIGZ1bmN0aW9uICgpIHtcbiAgICBpZiAoc3JjID09PSBzZWxmLnNyYykge1xuICAgICAgX2Rpc3BhdGNoQ2FsbGJhY2soc2VsZiwgX0NBTlBMQVlfQ0FMTEJBQ0spO1xuXG4gICAgICBfZGlzcGF0Y2hDYWxsYmFjayhzZWxmLCBfUExBWV9DQUxMQkFDSyk7XG4gICAgfVxuICB9KTtcblxuICBfYXVkaW9FbmdpbmUuc2V0V2FpdGluZ0NhbGxiYWNrKGF1ZGlvSUQsIGZ1bmN0aW9uICgpIHtcbiAgICBpZiAoc3JjID09PSBzZWxmLnNyYykge1xuICAgICAgX2Rpc3BhdGNoQ2FsbGJhY2soc2VsZiwgX1dBSVRJTkdfQ0FMTEJBQ0spO1xuICAgIH1cbiAgfSk7XG5cbiAgX2F1ZGlvRW5naW5lLnNldEVycm9yQ2FsbGJhY2soYXVkaW9JRCwgZnVuY3Rpb24gKCkge1xuICAgIGlmIChzcmMgPT09IHNlbGYuc3JjKSB7XG4gICAgICBwcml2YXRlVGhpcy5hdWRpb0lEID0gLTE7XG5cbiAgICAgIF9kaXNwYXRjaENhbGxiYWNrKHNlbGYsIF9FUlJPUl9DQUxMQkFDSyk7XG4gICAgfVxuICB9KTtcblxuICBfYXVkaW9FbmdpbmUuc2V0RmluaXNoQ2FsbGJhY2soYXVkaW9JRCwgZnVuY3Rpb24gKCkge1xuICAgIGlmIChzcmMgPT09IHNlbGYuc3JjKSB7XG4gICAgICBwcml2YXRlVGhpcy5hdWRpb0lEID0gLTE7XG5cbiAgICAgIF9kaXNwYXRjaENhbGxiYWNrKHNlbGYsIF9FTkRFRF9DQUxMQkFDSyk7XG4gICAgfVxuICB9KTtcbn07XG5cbl9wcm90b3R5cGUucGF1c2UgPSBmdW5jdGlvbiAoKSB7XG4gIHZhciBwcml2YXRlVGhpcyA9IF93ZWFrTWFwLmdldCh0aGlzKTtcblxuICBpZiAocHJpdmF0ZVRoaXMpIHtcbiAgICB2YXIgYXVkaW9JRCA9IHByaXZhdGVUaGlzLmF1ZGlvSUQ7XG5cbiAgICBpZiAodHlwZW9mIGF1ZGlvSUQgPT09IFwibnVtYmVyXCIgJiYgYXVkaW9JRCA+PSAwKSB7XG4gICAgICBfYXVkaW9FbmdpbmUucGF1c2UoYXVkaW9JRCk7XG5cbiAgICAgIF9kaXNwYXRjaENhbGxiYWNrKHRoaXMsIF9QQVVTRV9DQUxMQkFDSyk7XG4gICAgfVxuICB9XG59O1xuXG5fcHJvdG90eXBlLnNlZWsgPSBmdW5jdGlvbiAocG9zaXRpb24pIHtcbiAgdmFyIHByaXZhdGVUaGlzID0gX3dlYWtNYXAuZ2V0KHRoaXMpO1xuXG4gIGlmIChwcml2YXRlVGhpcyAmJiB0eXBlb2YgcG9zaXRpb24gPT09IFwibnVtYmVyXCIgJiYgcG9zaXRpb24gPj0gMCkge1xuICAgIHZhciBhdWRpb0lEID0gcHJpdmF0ZVRoaXMuYXVkaW9JRDtcblxuICAgIGlmICh0eXBlb2YgYXVkaW9JRCA9PT0gXCJudW1iZXJcIiAmJiBhdWRpb0lEID49IDApIHtcbiAgICAgIF9hdWRpb0VuZ2luZS5zZXRDdXJyZW50VGltZShhdWRpb0lELCBwb3NpdGlvbik7XG5cbiAgICAgIF9kaXNwYXRjaENhbGxiYWNrKHRoaXMsIF9TRUVLSU5HX0NBTExCQUNLKTtcblxuICAgICAgX2Rpc3BhdGNoQ2FsbGJhY2sodGhpcywgX1NFRUtFRF9DQUxMQkFDSyk7XG4gICAgfVxuICB9XG59O1xuXG5fcHJvdG90eXBlLnN0b3AgPSBmdW5jdGlvbiAoKSB7XG4gIHZhciBwcml2YXRlVGhpcyA9IF93ZWFrTWFwLmdldCh0aGlzKTtcblxuICBpZiAocHJpdmF0ZVRoaXMpIHtcbiAgICB2YXIgYXVkaW9JRCA9IHByaXZhdGVUaGlzLmF1ZGlvSUQ7XG5cbiAgICBpZiAodHlwZW9mIGF1ZGlvSUQgPT09IFwibnVtYmVyXCIgJiYgYXVkaW9JRCA+PSAwKSB7XG4gICAgICBfYXVkaW9FbmdpbmUuc3RvcChhdWRpb0lEKTtcblxuICAgICAgcHJpdmF0ZVRoaXMuYXVkaW9JRCA9IC0xO1xuXG4gICAgICBfZGlzcGF0Y2hDYWxsYmFjayh0aGlzLCBfU1RPUF9DQUxMQkFDSyk7XG4gICAgfVxuICB9XG59O1xuXG5fcHJvdG90eXBlLm9mZkNhbnBsYXkgPSBmdW5jdGlvbiAoY2FsbGJhY2spIHtcbiAgX29mZkNhbGxiYWNrKHRoaXMsIF9DQU5QTEFZX0NBTExCQUNLLCBjYWxsYmFjayk7XG59O1xuXG5fcHJvdG90eXBlLm9mZkVuZGVkID0gZnVuY3Rpb24gKGNhbGxiYWNrKSB7XG4gIF9vZmZDYWxsYmFjayh0aGlzLCBfRU5ERURfQ0FMTEJBQ0ssIGNhbGxiYWNrKTtcbn07XG5cbl9wcm90b3R5cGUub2ZmRXJyb3IgPSBmdW5jdGlvbiAoY2FsbGJhY2spIHtcbiAgX29mZkNhbGxiYWNrKHRoaXMsIF9FUlJPUl9DQUxMQkFDSywgY2FsbGJhY2spO1xufTtcblxuX3Byb3RvdHlwZS5vZmZQYXVzZSA9IGZ1bmN0aW9uIChjYWxsYmFjaykge1xuICBfb2ZmQ2FsbGJhY2sodGhpcywgX1BBVVNFX0NBTExCQUNLLCBjYWxsYmFjayk7XG59O1xuXG5fcHJvdG90eXBlLm9mZlBsYXkgPSBmdW5jdGlvbiAoY2FsbGJhY2spIHtcbiAgX29mZkNhbGxiYWNrKHRoaXMsIF9QTEFZX0NBTExCQUNLLCBjYWxsYmFjayk7XG59O1xuXG5fcHJvdG90eXBlLm9mZlNlZWtlZCA9IGZ1bmN0aW9uIChjYWxsYmFjaykge1xuICBfb2ZmQ2FsbGJhY2sodGhpcywgX1NFRUtFRF9DQUxMQkFDSywgY2FsbGJhY2spO1xufTtcblxuX3Byb3RvdHlwZS5vZmZTZWVraW5nID0gZnVuY3Rpb24gKGNhbGxiYWNrKSB7XG4gIF9vZmZDYWxsYmFjayh0aGlzLCBfU0VFS0lOR19DQUxMQkFDSywgY2FsbGJhY2spO1xufTtcblxuX3Byb3RvdHlwZS5vZmZTdG9wID0gZnVuY3Rpb24gKGNhbGxiYWNrKSB7XG4gIF9vZmZDYWxsYmFjayh0aGlzLCBfU1RPUF9DQUxMQkFDSywgY2FsbGJhY2spO1xufTtcblxuX3Byb3RvdHlwZS5vZmZUaW1lVXBkYXRlID0gZnVuY3Rpb24gKGNhbGxiYWNrKSB7XG4gIHZhciByZXN1bHQgPSBfb2ZmQ2FsbGJhY2sodGhpcywgX1RJTUVfVVBEQVRFX0NBTExCQUNLLCBjYWxsYmFjayk7XG5cbiAgaWYgKHJlc3VsdCA9PT0gMSkge1xuICAgIGNsZWFySW50ZXJ2YWwoX3dlYWtNYXAuZ2V0KHRoaXMpLmludGVydmFsSUQpO1xuICB9XG59O1xuXG5fcHJvdG90eXBlLm9mZldhaXRpbmcgPSBmdW5jdGlvbiAoY2FsbGJhY2spIHtcbiAgX29mZkNhbGxiYWNrKHRoaXMsIF9XQUlUSU5HX0NBTExCQUNLLCBjYWxsYmFjayk7XG59O1xuXG5fcHJvdG90eXBlLm9uQ2FucGxheSA9IGZ1bmN0aW9uIChjYWxsYmFjaykge1xuICBfb25DYWxsYmFjayh0aGlzLCBfQ0FOUExBWV9DQUxMQkFDSywgY2FsbGJhY2spO1xufTtcblxuX3Byb3RvdHlwZS5vbkVuZGVkID0gZnVuY3Rpb24gKGNhbGxiYWNrKSB7XG4gIF9vbkNhbGxiYWNrKHRoaXMsIF9FTkRFRF9DQUxMQkFDSywgY2FsbGJhY2spO1xufTtcblxuX3Byb3RvdHlwZS5vbkVycm9yID0gZnVuY3Rpb24gKGNhbGxiYWNrKSB7XG4gIF9vbkNhbGxiYWNrKHRoaXMsIF9FUlJPUl9DQUxMQkFDSywgY2FsbGJhY2spO1xufTtcblxuX3Byb3RvdHlwZS5vblBhdXNlID0gZnVuY3Rpb24gKGNhbGxiYWNrKSB7XG4gIF9vbkNhbGxiYWNrKHRoaXMsIF9QQVVTRV9DQUxMQkFDSywgY2FsbGJhY2spO1xufTtcblxuX3Byb3RvdHlwZS5vblBsYXkgPSBmdW5jdGlvbiAoY2FsbGJhY2spIHtcbiAgX29uQ2FsbGJhY2sodGhpcywgX1BMQVlfQ0FMTEJBQ0ssIGNhbGxiYWNrKTtcbn07XG5cbl9wcm90b3R5cGUub25TZWVrZWQgPSBmdW5jdGlvbiAoY2FsbGJhY2spIHtcbiAgX29uQ2FsbGJhY2sodGhpcywgX1NFRUtFRF9DQUxMQkFDSywgY2FsbGJhY2spO1xufTtcblxuX3Byb3RvdHlwZS5vblNlZWtpbmcgPSBmdW5jdGlvbiAoY2FsbGJhY2spIHtcbiAgX29uQ2FsbGJhY2sodGhpcywgXCJzZWVraW5nQ2FsbGJhY2tzXCIsIGNhbGxiYWNrKTtcbn07XG5cbl9wcm90b3R5cGUub25TdG9wID0gZnVuY3Rpb24gKGNhbGxiYWNrKSB7XG4gIF9vbkNhbGxiYWNrKHRoaXMsIF9TVE9QX0NBTExCQUNLLCBjYWxsYmFjayk7XG59O1xuXG5fcHJvdG90eXBlLm9uVGltZVVwZGF0ZSA9IGZ1bmN0aW9uIChjYWxsYmFjaykge1xuICB2YXIgcmVzdWx0ID0gX29uQ2FsbGJhY2sodGhpcywgX1RJTUVfVVBEQVRFX0NBTExCQUNLLCBjYWxsYmFjayk7XG5cbiAgaWYgKHJlc3VsdCA9PT0gMSkge1xuICAgIHZhciBwcml2YXRlVGhpcyA9IF93ZWFrTWFwLmdldCh0aGlzKTtcblxuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB2YXIgaW50ZXJ2YWxJRCA9IHNldEludGVydmFsKGZ1bmN0aW9uICgpIHtcbiAgICAgIHZhciBwcml2YXRlVGhpcyA9IF93ZWFrTWFwLmdldChzZWxmKTtcblxuICAgICAgaWYgKHByaXZhdGVUaGlzKSB7XG4gICAgICAgIHZhciBhdWRpb0lEID0gcHJpdmF0ZVRoaXMuYXVkaW9JRDtcblxuICAgICAgICBpZiAodHlwZW9mIGF1ZGlvSUQgPT09IFwibnVtYmVyXCIgJiYgYXVkaW9JRCA+PSAwICYmIF9hdWRpb0VuZ2luZS5nZXRTdGF0ZShhdWRpb0lEKSA9PT0gX1NUQVRFLlBMQVlJTkcpIHtcbiAgICAgICAgICBfZGlzcGF0Y2hDYWxsYmFjayhzZWxmLCBfVElNRV9VUERBVEVfQ0FMTEJBQ0spO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjbGVhckludGVydmFsKGludGVydmFsSUQpO1xuICAgICAgfVxuICAgIH0sIDUwMCk7XG4gICAgcHJpdmF0ZVRoaXMuaW50ZXJ2YWxJRCA9IGludGVydmFsSUQ7XG4gIH1cbn07XG5cbl9wcm90b3R5cGUub25XYWl0aW5nID0gZnVuY3Rpb24gKGNhbGxiYWNrKSB7XG4gIF9vbkNhbGxiYWNrKHRoaXMsIF9XQUlUSU5HX0NBTExCQUNLLCBjYWxsYmFjayk7XG59O1xuXG5mdW5jdGlvbiBfZGVmYXVsdChBdWRpb0VuZ2luZSkge1xuICBpZiAoX2F1ZGlvRW5naW5lID09PSB1bmRlZmluZWQpIHtcbiAgICBfYXVkaW9FbmdpbmUgPSBPYmplY3QuYXNzaWduKHt9LCBBdWRpb0VuZ2luZSk7XG4gICAgT2JqZWN0LmtleXMoQXVkaW9FbmdpbmUpLmZvckVhY2goZnVuY3Rpb24gKG5hbWUpIHtcbiAgICAgIGlmICh0eXBlb2YgQXVkaW9FbmdpbmVbbmFtZV0gPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICBBdWRpb0VuZ2luZVtuYW1lXSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBjb25zb2xlLndhcm4oXCJBdWRpb0VuZ2luZS5cIiArIG5hbWUgKyBcIiBpcyBkZXByZWNhdGVkXCIpO1xuICAgICAgICAgIHJldHVybiBfYXVkaW9FbmdpbmVbbmFtZV0uYXBwbHkoQXVkaW9FbmdpbmUsIGFyZ3VtZW50cyk7XG4gICAgICAgIH07XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICByZXR1cm4gbmV3IElubmVyQXVkaW9Db250ZXh0KCk7XG59XG5cbjtcblxufSx7fV0sMjE6W2Z1bmN0aW9uKHJlcXVpcmUsbW9kdWxlLGV4cG9ydHMpe1xuXCJ1c2Ugc3RyaWN0XCI7XG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIl9fZXNNb2R1bGVcIiwge1xuICB2YWx1ZTogdHJ1ZVxufSk7XG5leHBvcnRzW1wiZGVmYXVsdFwiXSA9IHZvaWQgMDtcblxuZnVuY3Rpb24gX3R5cGVvZihvYmopIHsgXCJAYmFiZWwvaGVscGVycyAtIHR5cGVvZlwiOyBpZiAodHlwZW9mIFN5bWJvbCA9PT0gXCJmdW5jdGlvblwiICYmIHR5cGVvZiBTeW1ib2wuaXRlcmF0b3IgPT09IFwic3ltYm9sXCIpIHsgX3R5cGVvZiA9IGZ1bmN0aW9uIF90eXBlb2Yob2JqKSB7IHJldHVybiB0eXBlb2Ygb2JqOyB9OyB9IGVsc2UgeyBfdHlwZW9mID0gZnVuY3Rpb24gX3R5cGVvZihvYmopIHsgcmV0dXJuIG9iaiAmJiB0eXBlb2YgU3ltYm9sID09PSBcImZ1bmN0aW9uXCIgJiYgb2JqLmNvbnN0cnVjdG9yID09PSBTeW1ib2wgJiYgb2JqICE9PSBTeW1ib2wucHJvdG90eXBlID8gXCJzeW1ib2xcIiA6IHR5cGVvZiBvYmo7IH07IH0gcmV0dXJuIF90eXBlb2Yob2JqKTsgfVxuXG52YXIgX2RlZmF1bHQgPSB7XG4gIGV4cG9ydFRvOiBmdW5jdGlvbiBleHBvcnRUbyhuYW1lLCBmcm9tLCB0bywgZXJyQ2FsbGJhY2spIHtcbiAgICBpZiAoX3R5cGVvZihmcm9tKSAhPT0gXCJvYmplY3RcIiB8fCBfdHlwZW9mKHRvKSAhPT0gXCJvYmplY3RcIikge1xuICAgICAgY29uc29sZS53YXJuKFwiaW52YWxpZCBleHBvcnRUbzogXCIsIG5hbWUpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHZhciBmcm9tUHJvcGVydHkgPSBmcm9tW25hbWVdO1xuXG4gICAgaWYgKHR5cGVvZiBmcm9tUHJvcGVydHkgIT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgIGlmICh0eXBlb2YgZnJvbVByb3BlcnR5ID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgdG9bbmFtZV0gPSBmcm9tUHJvcGVydHkuYmluZChmcm9tKTtcbiAgICAgICAgT2JqZWN0LmFzc2lnbih0b1tuYW1lXSwgZnJvbVByb3BlcnR5KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRvW25hbWVdID0gZnJvbVByb3BlcnR5O1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICB0b1tuYW1lXSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihuYW1lICsgXCIgaXMgbm90IHN1cHBvcnQhXCIpO1xuICAgICAgICByZXR1cm4ge307XG4gICAgICB9O1xuXG4gICAgICBpZiAodHlwZW9mIGVyckNhbGxiYWNrID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgZXJyQ2FsbGJhY2soKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn07XG5leHBvcnRzW1wiZGVmYXVsdFwiXSA9IF9kZWZhdWx0O1xuXG59LHt9XX0se30sWzhdKTtcbiJdLCJmaWxlIjoicmFsLmpzIn0= diff --git a/platforms/runtime/platforms/cocos-runtime/ral.min.js b/platforms/runtime/platforms/cocos-runtime/ral.min.js deleted file mode 100644 index e50ab1265e4..00000000000 --- a/platforms/runtime/platforms/cocos-runtime/ral.min.js +++ /dev/null @@ -1 +0,0 @@ -!function n(r,i,a){function u(t,e){if(!i[t]){if(!r[t]){var o="function"==typeof require&&require;if(!e&&o)return o(t,!0);if(c)return c(t,!0);throw(o=new Error("Cannot find module '"+t+"'")).code="MODULE_NOT_FOUND",o}o=i[t]={exports:{}},r[t][0].call(o.exports,function(e){return u(r[t][1][e]||e)},o,o.exports,n,r,i,a)}return i[t].exports}for(var c="function"==typeof require&&require,e=0;e { + describe('Blending', () => { + const nodes = [ + new Node('Node position affected by all nodes'), + new Node('Node rotation affected by all nodes'), + new Node('Node eulerAngles affected by all nodes'), + new Node('Node scale affected by all nodes'), + new Node('Node Scale affected by 1'), + new Node('Node Scale affected by 1 2'), + ]; + const [ + nodePosition_all, + nodeRotation_all, + nodeEulerAngles_all, + nodeScale_all, + nodeScale_1, + nodeScale_1_2, + ] = nodes; + + function revertNodesTransforms () { + for (const node of nodes) { + node.setPosition(0.0, 0.0, 0.0); + node.setScale(1.0, 1.0, 1.0); + node.setRotation(Quat.IDENTITY); + } + } + + const blendBuffer = new BlendStateBuffer(); + + const host1 = { weight: 0.0 }; + const writers1 = { + nodePosition_all: blendBuffer.createWriter(nodePosition_all, 'position', host1, false), + nodeRotation_all: blendBuffer.createWriter(nodeRotation_all, 'rotation', host1, false), + nodeEulerAngles_all: blendBuffer.createWriter(nodeEulerAngles_all, 'eulerAngles', host1, false), + nodeScale_all: blendBuffer.createWriter(nodeScale_all, 'scale', host1, false), + nodeScale_1: blendBuffer.createWriter(nodeScale_1, 'scale', host1, false), + nodeScale_1_2: blendBuffer.createWriter(nodeScale_1_2, 'scale', host1, false), + }; + + const host2 = { weight: 0.0 }; + const writers2 = { + nodePosition_all: blendBuffer.createWriter(nodePosition_all, 'position', host2, false), + nodeRotation_all: blendBuffer.createWriter(nodeRotation_all, 'rotation', host2, false), + nodeEulerAngles_all: blendBuffer.createWriter(nodeEulerAngles_all, 'eulerAngles', host2, false), + nodeScale_all: blendBuffer.createWriter(nodeScale_all, 'scale', host2, false), + nodeScale_1_2: blendBuffer.createWriter(nodeScale_1_2, 'scale', host2, false), + }; + + const host3 = { weight: 0.0 }; + const writers3 = { + nodePosition_all: blendBuffer.createWriter(nodePosition_all, 'position', host3, false), + nodeRotation_all: blendBuffer.createWriter(nodeRotation_all, 'rotation', host3, false), + nodeEulerAngles_all: blendBuffer.createWriter(nodeEulerAngles_all, 'eulerAngles', host3, false), + nodeScale_all: blendBuffer.createWriter(nodeScale_all, 'scale', host3, false), + }; + + beforeEach(() => { + revertNodesTransforms(); + }); + + test('Normalized blending ', () => { + host1.weight = 0.3; + host2.weight = 0.5; + host3.weight = 0.2; + + writers1.nodePosition_all.setValue(new Vec3(0.2, 0.4, 0.6)); + writers2.nodePosition_all.setValue(new Vec3(1.2, 1.4, 1.6)); + writers3.nodePosition_all.setValue(new Vec3(7.0, 8.0, 9.0)); + + writers1.nodeRotation_all.setValue(Quat.fromEuler(new Quat(), toRadian(20.0), 0.0, 0.0)); + writers2.nodeRotation_all.setValue(Quat.fromEuler(new Quat(), toRadian(30.0), 0.0, 0.0)); + writers3.nodeRotation_all.setValue(Quat.fromEuler(new Quat(), toRadian(40.0), 0.0, 0.0)); + + writers1.nodeEulerAngles_all.setValue(new Vec3(toRadian(20.0), 0.0, 0.0)); + writers2.nodeEulerAngles_all.setValue(new Vec3(toRadian(30.0), 0.0, 0.0)); + writers3.nodeEulerAngles_all.setValue(new Vec3(toRadian(40.0), 0.0, 0.0)); + + writers1.nodeScale_all.setValue(new Vec3(0.2, 0.4, 0.6)); + writers2.nodeScale_all.setValue(new Vec3(1.2, 1.4, 1.6)); + writers3.nodeScale_all.setValue(new Vec3(7.0, 8.0, 9.0)); + + blendBuffer.apply(); + + expect(Vec3.equals(nodePosition_all.position, new Vec3( + 0.2 * 0.3 + 1.2 * 0.5 + 7.0 * 0.2, + 0.4 * 0.3 + 1.4 * 0.5 + 8.0 * 0.2, + 0.6 * 0.3 + 1.6 * 0.5 + 9.0 * 0.2, + ))).toBe(true); + + expect(Vec3.equals(nodeRotation_all.rotation, Quat.fromEuler( + new Quat(), + toRadian(20.0 * 0.3 + 30.0 * 0.5 + 40.0 * 0.2), + 0.0, + 0.0, + ))).toBe(true); + + expect(Vec3.equals(nodeEulerAngles_all.eulerAngles, new Vec3( + toRadian(20.0 * 0.3 + 30.0 * 0.5 + 40.0 * 0.2), + 0.0, + 0.0, + ))).toBe(true); + + expect(Vec3.equals(nodeScale_all.scale, new Vec3( + 0.2 * 0.3 + 1.2 * 0.5 + 7.0 * 0.2, + 0.4 * 0.3 + 1.4 * 0.5 + 8.0 * 0.2, + 0.6 * 0.3 + 1.6 * 0.5 + 9.0 * 0.2, + ))).toBe(true); + }); + + test('If sum less than 1, current pose with be blended, with remain weight', () => { + host1.weight = 0.3; + host2.weight = 0.5; + host3.weight = 0.2; + + writers1.nodeScale_1.setValue(new Vec3(1.2, 1.4, 1.6)); + writers1.nodeScale_1_2.setValue(new Vec3(1.2, 1.4, 1.6)); + + writers2.nodeScale_1_2.setValue(new Vec3(3.0, 4.0, 5.0)); + + blendBuffer.apply(); + + // nodeScale_1.scale is only effect by host1 + expect(Vec3.equals(nodeScale_1.scale, new Vec3( + 1.2 * 0.3 + 1.0 * 0.7, + 1.4 * 0.3 + 1.0 * 0.7, + 1.6 * 0.3 + 1.0 * 0.7, + ))).toBe(true); + + // nodeScale_1.scale is effect by both host1 and host2, even if their weights are not sum to 1 + expect(Vec3.equals(nodeScale_1_2.scale, new Vec3( + 1.2 * 0.3 + 3.0 * 0.5 + 1.0 * 0.2, + 1.4 * 0.3 + 4.0 * 0.5 + 1.0 * 0.2, + 1.6 * 0.3 + 5.0 * 0.5 + 1.0 * 0.2, + ))).toBe(true); + }); + }); +}); diff --git a/tests/core/algorithm/move.ts b/tests/core/algorithm/move.ts new file mode 100644 index 00000000000..288242925a9 --- /dev/null +++ b/tests/core/algorithm/move.ts @@ -0,0 +1,23 @@ +import { move } from '../../../cocos/core/algorithm/move'; + +describe('Array utils', () => { + describe('Move', () => { + test('Location does not alters', () => { + expect(move([1, 2, 3], 0, 0)).toStrictEqual([1, 2, 3]); + }); + + test('Move right', () => { + expect(move([1, 2, 3], 0, 1)).toStrictEqual([2, 1, 3]); + expect(move([1, 2, 3], 0, 2)).toStrictEqual([2, 3, 1]); + expect(move([1, 2, 3, 4], 0, 2)).toStrictEqual([2, 3, 1, 4]); + expect(move([1, 2, 3, 4], 1, 2)).toStrictEqual([1, 3, 2, 4]); + }); + + test('Move left', () => { + expect(move([1, 2, 3], 1, 0)).toStrictEqual([2, 1, 3]); + expect(move([1, 2, 3], 2, 0)).toStrictEqual([3, 1, 2]); + expect(move([1, 2, 3, 4], 2, 0)).toStrictEqual([3, 1, 2, 4]); + expect(move([1, 2, 3, 4], 2, 1)).toStrictEqual([1, 3, 2, 4]); + }); + }); +}); \ No newline at end of file diff --git a/tests/core/editor-extendable.test.ts b/tests/core/editor-extendable.test.ts new file mode 100644 index 00000000000..201037c8c5a --- /dev/null +++ b/tests/core/editor-extendable.test.ts @@ -0,0 +1,15 @@ +import { EditorExtendable, editorExtrasTag } from "../../cocos/core/data/editor-extendable"; + +describe('Editor extendable', () => { + test('Serialize', () => { + class Foo extends EditorExtendable { + + } + + const foo = new Foo(); + + foo[editorExtrasTag] = {}; + + const extras = foo[editorExtrasTag]; + }); +}); \ No newline at end of file diff --git a/tests/general/sealed-global-variables.json b/tests/general/sealed-global-variables.json index 78246769517..dc5d90699c4 100644 --- a/tests/general/sealed-global-variables.json +++ b/tests/general/sealed-global-variables.json @@ -1,6 +1,6 @@ { "thisFile": { - "stamp": "2021-02-08T03:18:26.527Z" + "stamp": "2021-05-25T04:22:39.074Z" }, "variables": [ "cc.AffineTransform", @@ -100,6 +100,8 @@ "cc.GFXDispatchInfo", "cc.GFXDrawInfo", "cc.GFXDynamicStateFlagBit", + "cc.GFXDynamicStates", + "cc.GFXDynamicStencilStates", "cc.GFXExtent", "cc.GFXFeature", "cc.GFXFilter",