From 42ff3021c1f7ef475db1920ec1ad3874fbd9d8c5 Mon Sep 17 00:00:00 2001 From: Frank Weindel <6070611+frank-weindel@users.noreply.github.com> Date: Tue, 7 Nov 2023 16:56:03 -0500 Subject: [PATCH] Fix up issues with Text / Texture loaded/failed event refactor --- examples/common/utils.ts | 14 ++-- examples/tests/alpha-blending.ts | 13 ++-- examples/tests/text-events.ts | 17 ++--- examples/tests/textures.ts | 19 ++++-- src/common/CommonTypes.ts | 68 +++++++------------ src/core/CoreNode.ts | 16 ++++- src/core/CoreTextNode.ts | 26 ++++--- .../text-rendering/renderers/TextRenderer.ts | 16 +++++ src/core/textures/SubTexture.ts | 11 +-- src/core/textures/Texture.ts | 25 +++++-- src/render-drivers/main/MainOnlyNode.ts | 29 +++----- src/render-drivers/main/MainOnlyTextNode.ts | 32 +-------- .../threadx/worker/ThreadXRendererNode.ts | 33 ++++----- .../threadx/worker/ThreadXRendererTextNode.ts | 22 ------ 14 files changed, 159 insertions(+), 182 deletions(-) diff --git a/examples/common/utils.ts b/examples/common/utils.ts index 602a6ef2..8b50a187 100644 --- a/examples/common/utils.ts +++ b/examples/common/utils.ts @@ -17,16 +17,22 @@ * limitations under the License. */ -import type { Dimensions, ITextNode, INode } from '@lightningjs/renderer'; +import type { + Dimensions, + ITextNode, + INode, + NodeTextLoadedPayload, +} from '@lightningjs/renderer'; export async function waitForTextDimensions( node: ITextNode, ): Promise { return new Promise((resolve) => { - node.once('textLoaded', (_node: INode, dimensions: Dimensions) => { + node.once('loaded', (_node: INode, payload: NodeTextLoadedPayload) => { + const { width, height } = payload.dimensions; resolve({ - width: dimensions.width, - height: dimensions.height, + width, + height, }); }); }); diff --git a/examples/tests/alpha-blending.ts b/examples/tests/alpha-blending.ts index 1cb89b66..14999886 100644 --- a/examples/tests/alpha-blending.ts +++ b/examples/tests/alpha-blending.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import type { INode, TextureLoadedEventHandler } from '@lightningjs/renderer'; +import type { INode, NodeLoadedEventHandler } from '@lightningjs/renderer'; import { mergeColorAlpha } from '@lightningjs/renderer/utils'; import type { ExampleSettings } from '../common/ExampleSettings.js'; import red25 from '../assets/red-25.png'; @@ -445,9 +445,10 @@ export default async function ({ curY += 30 + PADDING; - const sizeToTexture: TextureLoadedEventHandler = (target, dimensions) => { - target.width = dimensions.width; - target.height = dimensions.height; + const sizeToTexture: NodeLoadedEventHandler = (target, payload) => { + const { width, height } = payload.dimensions; + target.width = width; + target.height = height; }; renderer @@ -460,7 +461,7 @@ export default async function ({ alpha: 1, parent: sideContainer, }) - .once('txLoaded', sizeToTexture); + .once('loaded', sizeToTexture); curX += RECT_SIZE + PADDING; @@ -472,7 +473,7 @@ export default async function ({ alpha: 1.0, parent: sideContainer, }) - .once('txLoaded', sizeToTexture); + .once('loaded', sizeToTexture); curX += RECT_SIZE + PADDING; diff --git a/examples/tests/text-events.ts b/examples/tests/text-events.ts index 678ee921..ad37ecc0 100644 --- a/examples/tests/text-events.ts +++ b/examples/tests/text-events.ts @@ -22,7 +22,8 @@ import { type ITextNode, type RendererMain, type Dimensions, - type TextLoadedEventHandler, + type NodeLoadedEventHandler, + type NodeFailedEventHandler, } from '@lightningjs/renderer'; import { EventEmitter } from '@lightningjs/renderer/utils'; import type { ExampleSettings } from '../common/ExampleSettings.js'; @@ -96,7 +97,7 @@ export default async function ({ renderer, driverName }: ExampleSettings) { (renderer.settings.appHeight * 3) / 4 - marqueeCanvas.node.height / 2; }); - const marqueeText = `The following is a test of the textLoaded event... + const marqueeText = `The following is a test of the text loaded event... From Philly's streets to Dutch canal's grace, A code symphony spanned time and space. Lightning 3 emerged, open and free, @@ -214,11 +215,11 @@ class BoxedText extends EventEmitter implements BoxedTextProps { parent: this.node, }); - this.textNode.on('textLoaded', this.onTextLoaded); + this.textNode.on('loaded', this.onTextLoaded); } - private onTextLoaded: TextLoadedEventHandler = (target, dimensions) => { - this.layout(dimensions); + private onTextLoaded: NodeLoadedEventHandler = (target, payload) => { + this.layout(payload.dimensions); }; private layout(textDimensions: Dimensions) { @@ -300,8 +301,8 @@ function waitForTextFailed(textNode: ITextNode) { setTimeout(() => { reject(new Error('TIMEOUT')); }, 1000); - textNode.once('textFailed', (target, error: Error) => { - resolve(error); - }); + textNode.once('failed', ((target, payload) => { + resolve(payload.error); + }) satisfies NodeFailedEventHandler); }); } diff --git a/examples/tests/textures.ts b/examples/tests/textures.ts index 0e0cdea7..a7489afb 100644 --- a/examples/tests/textures.ts +++ b/examples/tests/textures.ts @@ -17,7 +17,12 @@ * limitations under the License. */ -import { type INode, type Dimensions } from '@lightningjs/renderer'; +import { + type INode, + type Dimensions, + type NodeLoadedEventHandler, + type NodeFailedEventHandler, +} from '@lightningjs/renderer'; import rockoImg from '../assets/rocko.png'; import elevatorImg from '../assets/elevator.png'; import spritemap from '../assets/spritemap.png'; @@ -191,13 +196,13 @@ export default async function ({ renderer, driverName }: ExampleSettings) { await execFailureTest(subTxFailure2); function waitForTxLoaded(imgNode: INode) { - return new Promise<{ width: number; height: number }>((resolve, reject) => { + return new Promise((resolve, reject) => { setTimeout(() => { reject(new Error('TIMEOUT')); }, 1000); - imgNode.once('txLoaded', (target, dimensions) => { - resolve(dimensions); - }); + imgNode.once('loaded', ((target, payload) => { + resolve(payload.dimensions); + }) satisfies NodeLoadedEventHandler); }); } @@ -206,9 +211,9 @@ export default async function ({ renderer, driverName }: ExampleSettings) { setTimeout(() => { reject(new Error('TIMEOUT')); }, 1000); - imgNode.once('txFailed', () => { + imgNode.once('failed', (() => { resolve(true); - }); + }) satisfies NodeFailedEventHandler); }); } diff --git a/src/common/CommonTypes.ts b/src/common/CommonTypes.ts index 7e565179..da5fd791 100644 --- a/src/common/CommonTypes.ts +++ b/src/common/CommonTypes.ts @@ -33,46 +33,10 @@ export interface Dimensions { height: number; } -/** - * Event handler for when a texture is loading - */ -export type TextureLoadingEventHandler = (target: any) => void; - -/** - * Event handler for when a texture is loaded - */ -export type TextureLoadedEventHandler = ( - target: any, - dimensions: Readonly, -) => void; - -/** - * Event handler for when a texture fails to load - */ -export type TextureFailedEventHandler = (target: any, error: Error) => void; - -/** - * Event handler for when text is loading - */ -export type TextLoadingEventHandler = (target: any) => void; - -/** - * Event handler for when text is loaded - */ -export type TextLoadedEventHandler = ( - target: any, - dimensions: Dimensions, -) => void; - -/** - * Event handler for when text fails to load - */ -export type TextFailedEventHandler = (target: any, error: Error) => void; - /** * Payload for when text is loaded */ -type TextLoadedPayload = { +export type NodeTextLoadedPayload = { type: 'text'; dimensions: Dimensions; }; @@ -80,7 +44,7 @@ type TextLoadedPayload = { /** * Payload for when texture is loaded */ -type TextureLoadedPayload = { +export type NodeTextureLoadedPayload = { type: 'texture'; dimensions: Dimensions; }; @@ -88,12 +52,14 @@ type TextureLoadedPayload = { /** * Combined type for all loaded payloads */ -export type LoadedPayload = TextLoadedPayload | TextureLoadedPayload; +export type NodeLoadedPayload = + | NodeTextLoadedPayload + | NodeTextureLoadedPayload; /** * Payload for when text failed to load */ -type TextFailedPayload = { +export type NodeTextFailedPayload = { type: 'text'; error: Error; }; @@ -101,7 +67,7 @@ type TextFailedPayload = { /** * Payload for when texture failed to load */ -type TextureFailedPayload = { +export type NodeTextureFailedPayload = { type: 'texture'; error: Error; }; @@ -109,4 +75,22 @@ type TextureFailedPayload = { /** * Combined type for all failed payloads */ -export type FailedPayload = TextFailedPayload | TextureFailedPayload; +export type NodeFailedPayload = + | NodeTextFailedPayload + | NodeTextureFailedPayload; + +/** + * Event handler for when the texture/text of a node has loaded + */ +export type NodeLoadedEventHandler = ( + target: any, + payload: NodeLoadedPayload, +) => void; + +/** + * Event handler for when the texture/text of a node has failed to load + */ +export type NodeFailedEventHandler = ( + target: any, + payload: NodeFailedPayload, +) => void; diff --git a/src/core/CoreNode.ts b/src/core/CoreNode.ts index e1e7fd07..38b53f40 100644 --- a/src/core/CoreNode.ts +++ b/src/core/CoreNode.ts @@ -27,10 +27,14 @@ import type { import type { CoreRenderer } from './renderers/CoreRenderer.js'; import type { CoreShader } from './renderers/CoreShader.js'; import type { Stage } from './Stage.js'; -import type { Texture } from './textures/Texture.js'; import type { + Texture, TextureFailedEventHandler, TextureLoadedEventHandler, +} from './textures/Texture.js'; +import type { + NodeTextureFailedPayload, + NodeTextureLoadedPayload, } from '../common/CommonTypes.js'; import { EventEmitter } from '../common/EventEmitter.js'; import type { Rect } from './lib/utils.js'; @@ -149,11 +153,17 @@ export class CoreNode extends EventEmitter implements ICoreNode { } private onTextureLoaded: TextureLoadedEventHandler = (target, dimensions) => { - this.emit('txLoaded', dimensions); + this.emit('loaded', { + type: 'texture', + dimensions, + } satisfies NodeTextureLoadedPayload); }; private onTextureFailed: TextureFailedEventHandler = (target, error) => { - this.emit('txFailed', error); + this.emit('failed', { + type: 'texture', + error, + } satisfies NodeTextureFailedPayload); }; //#endregion Textures diff --git a/src/core/CoreTextNode.ts b/src/core/CoreTextNode.ts index 2d058f85..5262d73b 100644 --- a/src/core/CoreTextNode.ts +++ b/src/core/CoreTextNode.ts @@ -22,13 +22,15 @@ import type { TextRendererMap, TrProps, TextRendererState, + TrFailedEventHandler, + TrLoadedEventHandler, } from './text-rendering/renderers/TextRenderer.js'; import { CoreNode, type CoreNodeProps } from './CoreNode.js'; import type { Stage } from './Stage.js'; import type { CoreRenderer } from './renderers/CoreRenderer.js'; import type { - TextFailedEventHandler, - TextLoadedEventHandler, + NodeTextFailedPayload, + NodeTextLoadedPayload, } from '../common/CommonTypes.js'; import type { Rect } from './lib/utils.js'; import { assertTruthy } from '../utils.js'; @@ -86,7 +88,7 @@ export class CoreTextNode extends CoreNode implements ICoreTextNode { this.trState = textRendererState; } - private onTextLoaded: TextLoadedEventHandler = () => { + private onTextLoaded: TrLoadedEventHandler = () => { const { contain } = this; const setWidth = this.trState.props.width; const setHeight = this.trState.props.height; @@ -105,14 +107,20 @@ export class CoreTextNode extends CoreNode implements ICoreTextNode { } this.updateLocalTransform(); - this.emit('textLoaded', { - width: this.trState.textW, - height: this.trState.textH, - }); + this.emit('loaded', { + type: 'text', + dimensions: { + width: this.trState.textW || 0, + height: this.trState.textH || 0, + }, + } satisfies NodeTextLoadedPayload); }; - private onTextFailed: TextFailedEventHandler = (target, error) => { - this.emit('textFailed', error); + private onTextFailed: TrFailedEventHandler = (target, error) => { + this.emit('failed', { + type: 'text', + error, + } satisfies NodeTextFailedPayload); }; override get width(): number { diff --git a/src/core/text-rendering/renderers/TextRenderer.ts b/src/core/text-rendering/renderers/TextRenderer.ts index 83ddc06a..2c5c9b22 100644 --- a/src/core/text-rendering/renderers/TextRenderer.ts +++ b/src/core/text-rendering/renderers/TextRenderer.ts @@ -325,6 +325,22 @@ const trPropSetterDefaults: TrPropSetters = { }, }; +/** + * Event handler for when text is loaded + * + * @remarks + * Emitted by state.emitter + */ +export type TrLoadedEventHandler = (target: any) => void; + +/** + * Event handler for when text failed to load + * + * @remarks + * Emitted by state.emitter + */ +export type TrFailedEventHandler = (target: any, error: Error) => void; + export abstract class TextRenderer< StateT extends TextRendererState = TextRendererState, > { diff --git a/src/core/textures/SubTexture.ts b/src/core/textures/SubTexture.ts index aceaf91a..4fc322d0 100644 --- a/src/core/textures/SubTexture.ts +++ b/src/core/textures/SubTexture.ts @@ -17,13 +17,14 @@ * limitations under the License. */ -import type { - TextureFailedEventHandler, - TextureLoadedEventHandler, -} from '../../common/CommonTypes.js'; import type { TextureRef } from '../../main-api/RendererMain.js'; import type { CoreTextureManager } from '../CoreTextureManager.js'; -import { Texture, type TextureData } from './Texture.js'; +import { + Texture, + type TextureData, + type TextureFailedEventHandler, + type TextureLoadedEventHandler, +} from './Texture.js'; /** * Properties of the {@link SubTexture} diff --git a/src/core/textures/Texture.ts b/src/core/textures/Texture.ts index eb876266..580ca713 100644 --- a/src/core/textures/Texture.ts +++ b/src/core/textures/Texture.ts @@ -19,14 +19,27 @@ import type { CoreTextureManager } from '../CoreTextureManager.js'; import type { SubTextureProps } from './SubTexture.js'; -import type { - Dimensions, - TextureFailedEventHandler, - TextureLoadedEventHandler, - TextureLoadingEventHandler, -} from '../../common/CommonTypes.js'; +import type { Dimensions } from '../../common/CommonTypes.js'; import { EventEmitter } from '../../common/EventEmitter.js'; +/** + * Event handler for when a Texture is loading + */ +export type TextureLoadingEventHandler = (target: any) => void; + +/** + * Event handler for when a Texture is loaded + */ +export type TextureLoadedEventHandler = ( + target: any, + dimensions: Readonly, +) => void; + +/** + * Event handler for when a Texture fails to load + */ +export type TextureFailedEventHandler = (target: any, error: Error) => void; + /** * TextureData that is used to populate a CoreContextTexture */ diff --git a/src/render-drivers/main/MainOnlyNode.ts b/src/render-drivers/main/MainOnlyNode.ts index aade2521..f06914bf 100644 --- a/src/render-drivers/main/MainOnlyNode.ts +++ b/src/render-drivers/main/MainOnlyNode.ts @@ -36,10 +36,8 @@ import type { import type { AnimationSettings } from '../../core/animations/CoreAnimation.js'; import { EventEmitter } from '../../common/EventEmitter.js'; import type { - TextureFailedEventHandler, - TextureLoadedEventHandler, - LoadedPayload, - FailedPayload, + NodeLoadedEventHandler, + NodeFailedEventHandler, } from '../../common/CommonTypes.js'; let nextId = 1; @@ -103,9 +101,9 @@ export class MainOnlyNode extends EventEmitter implements INode { texture: null, textureOptions: null, }); - // Forward texture events - this.coreNode.on('txLoaded', this.onTextureLoaded); - this.coreNode.on('txFailed', this.onTextureFailed); + // Forward loaded/failed events + this.coreNode.on('loaded', this.onTextureLoaded); + this.coreNode.on('failed', this.onTextureFailed); // Assign properties to this object this.parent = props.parent as MainOnlyNode; @@ -404,21 +402,12 @@ export class MainOnlyNode extends EventEmitter implements INode { } } - private onTextureLoaded: TextureLoadedEventHandler = (target, dimensions) => { - const texturePayload: LoadedPayload = { - type: 'texture', - dimensions, - }; - - this.emit('loaded', texturePayload); + private onTextureLoaded: NodeLoadedEventHandler = (target, payload) => { + this.emit('loaded', payload); }; - private onTextureFailed: TextureFailedEventHandler = (target, error) => { - const textureFailedPayload: FailedPayload = { - type: 'texture', - error, - }; - this.emit('failed', textureFailedPayload); + private onTextureFailed: NodeFailedEventHandler = (target, payload) => { + this.emit('failed', payload); }; //#endregion Texture diff --git a/src/render-drivers/main/MainOnlyTextNode.ts b/src/render-drivers/main/MainOnlyTextNode.ts index 7e060165..00e59722 100644 --- a/src/render-drivers/main/MainOnlyTextNode.ts +++ b/src/render-drivers/main/MainOnlyTextNode.ts @@ -25,13 +25,6 @@ import type { Stage } from '../../core/Stage.js'; import type { RendererMain } from '../../main-api/RendererMain.js'; import { MainOnlyNode, getNewId } from './MainOnlyNode.js'; import { CoreTextNode } from '../../core/CoreTextNode.js'; -import type { - TextFailedEventHandler, - TextLoadedEventHandler, - LoadedPayload, - FailedPayload, - Dimensions, -} from '../../common/CommonTypes.js'; export class MainOnlyTextNode extends MainOnlyNode implements ITextNode { protected declare coreNode: CoreTextNode; @@ -98,30 +91,7 @@ export class MainOnlyTextNode extends MainOnlyNode implements ITextNode { shaderProps: null, }), ); - this.coreNode.on('textLoaded', this.onTextLoaded); - this.coreNode.on('textFailed', this.onTextFailed); - } - - private onTextLoaded: TextLoadedEventHandler = ( - target, - dimensions: Dimensions, - ) => { - const textPayload: LoadedPayload = { - type: 'text', - dimensions, - }; - - this.emit('loaded', textPayload); - }; - - private onTextFailed: TextFailedEventHandler = (target, error) => { - const textFailedPayload: FailedPayload = { - type: 'text', - error, - }; - - this.emit('failed', textFailedPayload); - }; + } get text(): string { return this.coreNode.text; diff --git a/src/render-drivers/threadx/worker/ThreadXRendererNode.ts b/src/render-drivers/threadx/worker/ThreadXRendererNode.ts index 9894923d..c370212f 100644 --- a/src/render-drivers/threadx/worker/ThreadXRendererNode.ts +++ b/src/render-drivers/threadx/worker/ThreadXRendererNode.ts @@ -31,9 +31,8 @@ import { CoreNode } from '../../../core/CoreNode.js'; import type { ShaderRef, TextureRef } from '../../../main-api/RendererMain.js'; import type { AnimationSettings } from '../../../core/animations/CoreAnimation.js'; import type { - Dimensions, - LoadedPayload, - FailedPayload, + NodeLoadedPayload, + NodeFailedPayload, } from '../../../common/CommonTypes.js'; export class ThreadXRendererNode extends SharedNode { @@ -132,22 +131,18 @@ export class ThreadXRendererNode extends SharedNode { this.coreNode.unloadTexture(); }); // Forward on CoreNode events - this.coreNode.on('txLoaded', (target: CoreNode, dimensions: Dimensions) => { - const texturePayload: LoadedPayload = { - type: 'texture', - dimensions, - }; - - this.emit('loaded', texturePayload); - }); - this.coreNode.on('txFailed', (target: CoreNode, error: Error) => { - const textureFailedPayload: FailedPayload = { - type: 'texture', - error, - }; - - this.emit('failed', textureFailedPayload); - }); + this.coreNode.on( + 'loaded', + (target: CoreNode, payload: NodeLoadedPayload) => { + this.emit('loaded', payload); + }, + ); + this.coreNode.on( + 'failed', + (target: CoreNode, payload: NodeFailedPayload) => { + this.emit('failed', payload); + }, + ); } override onPropertyChange( diff --git a/src/render-drivers/threadx/worker/ThreadXRendererTextNode.ts b/src/render-drivers/threadx/worker/ThreadXRendererTextNode.ts index b0fa98c6..65ae4cea 100644 --- a/src/render-drivers/threadx/worker/ThreadXRendererTextNode.ts +++ b/src/render-drivers/threadx/worker/ThreadXRendererTextNode.ts @@ -17,11 +17,6 @@ * limitations under the License. */ -import type { - Dimensions, - LoadedPayload, - FailedPayload, -} from '../../../common/CommonTypes.js'; import { CoreTextNode } from '../../../core/CoreTextNode.js'; import type { Stage } from '../../../core/Stage.js'; import type { TrProps } from '../../../core/text-rendering/renderers/TextRenderer.js'; @@ -118,23 +113,6 @@ export class ThreadXRendererTextNode extends ThreadXRendererNode { >, ); // Forward on CoreNode events - this.coreNode.on( - 'textLoaded', - (target: CoreTextNode, dimensions: Dimensions) => { - const textPayload: LoadedPayload = { - type: 'text', - dimensions, - }; - this.emit('loaded', textPayload); - }, - ); - this.coreNode.on('textFailed', (target: CoreTextNode, error: Error) => { - const textFailedPayload: FailedPayload = { - type: 'text', - error, - }; - this.emit('failed', textFailedPayload); - }); this.on('debug', (target: ThreadXRendererNode, debug: TrProps['debug']) => { this.coreNode.debug = debug; });