@lightningjs/renderer 0.7.6 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/dist/src/common/CommonTypes.d.ts +6 -0
- package/dist/src/core/CoreNode.d.ts +63 -6
- package/dist/src/core/CoreNode.js +97 -20
- package/dist/src/core/CoreNode.js.map +1 -1
- package/dist/src/core/CoreTextNode.d.ts +5 -0
- package/dist/src/core/CoreTextNode.js +15 -10
- package/dist/src/core/CoreTextNode.js.map +1 -1
- package/dist/src/core/CoreTextureManager.js +2 -0
- package/dist/src/core/CoreTextureManager.js.map +1 -1
- package/dist/src/core/Stage.d.ts +4 -0
- package/dist/src/core/Stage.js +8 -1
- package/dist/src/core/Stage.js.map +1 -1
- package/dist/src/core/TextureMemoryManager.d.ts +12 -0
- package/dist/src/core/TextureMemoryManager.js +42 -0
- package/dist/src/core/TextureMemoryManager.js.map +1 -0
- package/dist/src/core/platform.js +8 -0
- package/dist/src/core/platform.js.map +1 -1
- package/dist/src/core/renderers/CoreContextTexture.d.ts +5 -1
- package/dist/src/core/renderers/CoreContextTexture.js +3 -1
- package/dist/src/core/renderers/CoreContextTexture.js.map +1 -1
- package/dist/src/core/renderers/webgl/WebGlCoreCtxSubTexture.d.ts +2 -1
- package/dist/src/core/renderers/webgl/WebGlCoreCtxSubTexture.js +2 -2
- package/dist/src/core/renderers/webgl/WebGlCoreCtxSubTexture.js.map +1 -1
- package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.d.ts +3 -1
- package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.js +22 -5
- package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.js.map +1 -1
- package/dist/src/core/renderers/webgl/WebGlCoreRenderer.d.ts +3 -0
- package/dist/src/core/renderers/webgl/WebGlCoreRenderer.js +4 -2
- package/dist/src/core/renderers/webgl/WebGlCoreRenderer.js.map +1 -1
- package/dist/src/core/renderers/webgl/shaders/effects/LinearGradientEffect.js +17 -30
- package/dist/src/core/renderers/webgl/shaders/effects/LinearGradientEffect.js.map +1 -1
- package/dist/src/core/renderers/webgl/shaders/effects/RadialGradientEffect.d.ts +1 -0
- package/dist/src/core/renderers/webgl/shaders/effects/RadialGradientEffect.js +24 -30
- package/dist/src/core/renderers/webgl/shaders/effects/RadialGradientEffect.js.map +1 -1
- package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.d.ts +2 -0
- package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.js +18 -0
- package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.js.map +1 -1
- package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.d.ts +8 -0
- package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js +26 -4
- package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js.map +1 -1
- package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.js +1 -3
- package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.js.map +1 -1
- package/dist/src/core/text-rendering/renderers/TextRenderer.d.ts +19 -0
- package/dist/src/core/text-rendering/renderers/TextRenderer.js +26 -0
- package/dist/src/core/text-rendering/renderers/TextRenderer.js.map +1 -1
- package/dist/src/core/textures/Texture.d.ts +26 -1
- package/dist/src/core/textures/Texture.js +30 -1
- package/dist/src/core/textures/Texture.js.map +1 -1
- package/dist/src/main-api/ICoreDriver.d.ts +1 -0
- package/dist/src/main-api/Inspector.js +2 -1
- package/dist/src/main-api/Inspector.js.map +1 -1
- package/dist/src/main-api/RendererMain.d.ts +10 -1
- package/dist/src/main-api/RendererMain.js +6 -1
- package/dist/src/main-api/RendererMain.js.map +1 -1
- package/dist/src/render-drivers/main/MainCoreDriver.d.ts +1 -0
- package/dist/src/render-drivers/main/MainCoreDriver.js +7 -0
- package/dist/src/render-drivers/main/MainCoreDriver.js.map +1 -1
- package/dist/src/render-drivers/main/MainOnlyNode.d.ts +1 -0
- package/dist/src/render-drivers/main/MainOnlyNode.js +10 -6
- package/dist/src/render-drivers/main/MainOnlyNode.js.map +1 -1
- package/dist/src/render-drivers/threadx/ThreadXCoreDriver.js +1 -0
- package/dist/src/render-drivers/threadx/ThreadXCoreDriver.js.map +1 -1
- package/dist/src/render-drivers/threadx/ThreadXRendererMessage.d.ts +1 -0
- package/dist/src/render-drivers/threadx/ThreadXRendererMessage.js.map +1 -1
- package/dist/src/render-drivers/threadx/worker/ThreadXRendererNode.js +3 -0
- package/dist/src/render-drivers/threadx/worker/ThreadXRendererNode.js.map +1 -1
- package/dist/src/render-drivers/threadx/worker/renderer.js +1 -0
- package/dist/src/render-drivers/threadx/worker/renderer.js.map +1 -1
- package/dist/src/utils.d.ts +6 -0
- package/dist/src/utils.js +9 -1
- package/dist/src/utils.js.map +1 -1
- package/dist/tsconfig.dist.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/common/CommonTypes.ts +7 -0
- package/src/core/CoreNode.ts +105 -20
- package/src/core/CoreTextNode.ts +44 -43
- package/src/core/CoreTextureManager.ts +2 -0
- package/src/core/Stage.ts +10 -0
- package/src/core/TextureMemoryManager.ts +66 -0
- package/src/core/platform.ts +8 -0
- package/src/core/renderers/CoreContextTexture.ts +6 -1
- package/src/core/renderers/webgl/WebGlCoreCtxSubTexture.ts +7 -2
- package/src/core/renderers/webgl/WebGlCoreCtxTexture.ts +34 -6
- package/src/core/renderers/webgl/WebGlCoreRenderer.ts +10 -2
- package/src/core/renderers/webgl/shaders/effects/LinearGradientEffect.ts +16 -32
- package/src/core/renderers/webgl/shaders/effects/RadialGradientEffect.ts +26 -32
- package/src/core/text-rendering/renderers/CanvasTextRenderer.ts +23 -0
- package/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.ts +32 -4
- package/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.ts +1 -3
- package/src/core/text-rendering/renderers/TextRenderer.ts +32 -0
- package/src/core/textures/Texture.ts +39 -2
- package/src/main-api/ICoreDriver.ts +2 -0
- package/src/main-api/Inspector.ts +2 -1
- package/src/main-api/RendererMain.ts +19 -2
- package/src/render-drivers/main/MainCoreDriver.ts +9 -0
- package/src/render-drivers/main/MainOnlyNode.ts +12 -6
- package/src/render-drivers/threadx/ThreadXCoreDriver.ts +1 -0
- package/src/render-drivers/threadx/ThreadXRendererMessage.ts +1 -0
- package/src/render-drivers/threadx/worker/ThreadXRendererNode.ts +7 -0
- package/src/render-drivers/threadx/worker/renderer.ts +1 -0
- package/src/utils.ts +10 -1
|
@@ -290,6 +290,7 @@ export class CanvasTextRenderer extends TextRenderer<CanvasTextRendererState> {
|
|
|
290
290
|
textH: 0,
|
|
291
291
|
fontInfo: undefined,
|
|
292
292
|
fontFaceLoadedHandler: undefined,
|
|
293
|
+
isRenderable: false,
|
|
293
294
|
debugData: {
|
|
294
295
|
updateCount: 0,
|
|
295
296
|
layoutCount: 0,
|
|
@@ -500,9 +501,11 @@ export class CanvasTextRenderer extends TextRenderer<CanvasTextRendererState> {
|
|
|
500
501
|
for (const pageInfo of canvasPages) {
|
|
501
502
|
if (pageInfo.valid) continue;
|
|
502
503
|
if (pageInfo.lineNumStart < 0) {
|
|
504
|
+
pageInfo.texture?.setRenderableOwner(state, false);
|
|
503
505
|
pageInfo.texture = this.stage.txManager.loadTexture('ImageTexture', {
|
|
504
506
|
src: '',
|
|
505
507
|
});
|
|
508
|
+
pageInfo.texture.setRenderableOwner(state, state.isRenderable);
|
|
506
509
|
pageInfo.valid = true;
|
|
507
510
|
continue;
|
|
508
511
|
}
|
|
@@ -517,6 +520,7 @@ export class CanvasTextRenderer extends TextRenderer<CanvasTextRendererState> {
|
|
|
517
520
|
),
|
|
518
521
|
});
|
|
519
522
|
if (!(this.canvas.width === 0 || this.canvas.height === 0)) {
|
|
523
|
+
pageInfo.texture?.setRenderableOwner(state, false);
|
|
520
524
|
pageInfo.texture = this.stage.txManager.loadTexture(
|
|
521
525
|
'ImageTexture',
|
|
522
526
|
{
|
|
@@ -531,6 +535,7 @@ export class CanvasTextRenderer extends TextRenderer<CanvasTextRendererState> {
|
|
|
531
535
|
preload: true,
|
|
532
536
|
},
|
|
533
537
|
);
|
|
538
|
+
pageInfo.texture.setRenderableOwner(state, state.isRenderable);
|
|
534
539
|
}
|
|
535
540
|
pageInfo.valid = true;
|
|
536
541
|
}
|
|
@@ -694,6 +699,24 @@ export class CanvasTextRenderer extends TextRenderer<CanvasTextRendererState> {
|
|
|
694
699
|
// );
|
|
695
700
|
// }
|
|
696
701
|
}
|
|
702
|
+
|
|
703
|
+
override setIsRenderable(
|
|
704
|
+
state: CanvasTextRendererState,
|
|
705
|
+
renderable: boolean,
|
|
706
|
+
): void {
|
|
707
|
+
super.setIsRenderable(state, renderable);
|
|
708
|
+
// Set state object owner from any canvas page textures
|
|
709
|
+
state.canvasPages?.forEach((pageInfo) => {
|
|
710
|
+
pageInfo.texture?.setRenderableOwner(state, renderable);
|
|
711
|
+
});
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
override destroyState(state: CanvasTextRendererState): void {
|
|
715
|
+
// Remove state object owner from any canvas page textures
|
|
716
|
+
state.canvasPages?.forEach((pageInfo) => {
|
|
717
|
+
pageInfo.texture?.setRenderableOwner(state, false);
|
|
718
|
+
});
|
|
719
|
+
}
|
|
697
720
|
//#endregion Overrides
|
|
698
721
|
|
|
699
722
|
/**
|
|
@@ -150,22 +150,22 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
|
|
|
150
150
|
return {
|
|
151
151
|
fontFamily: (state, value) => {
|
|
152
152
|
state.props.fontFamily = value;
|
|
153
|
-
state
|
|
153
|
+
this.releaseFontFace(state);
|
|
154
154
|
this.invalidateLayoutCache(state);
|
|
155
155
|
},
|
|
156
156
|
fontWeight: (state, value) => {
|
|
157
157
|
state.props.fontWeight = value;
|
|
158
|
-
state
|
|
158
|
+
this.releaseFontFace(state);
|
|
159
159
|
this.invalidateLayoutCache(state);
|
|
160
160
|
},
|
|
161
161
|
fontStyle: (state, value) => {
|
|
162
162
|
state.props.fontStyle = value;
|
|
163
|
-
state
|
|
163
|
+
this.releaseFontFace(state);
|
|
164
164
|
this.invalidateLayoutCache(state);
|
|
165
165
|
},
|
|
166
166
|
fontStretch: (state, value) => {
|
|
167
167
|
state.props.fontStretch = value;
|
|
168
|
-
state
|
|
168
|
+
this.releaseFontFace(state);
|
|
169
169
|
this.invalidateLayoutCache(state);
|
|
170
170
|
},
|
|
171
171
|
fontSize: (state, value) => {
|
|
@@ -360,6 +360,7 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
|
|
|
360
360
|
textW: undefined,
|
|
361
361
|
distanceRange: 0,
|
|
362
362
|
trFontFace: undefined,
|
|
363
|
+
isRenderable: false,
|
|
363
364
|
debugData: {
|
|
364
365
|
updateCount: 0,
|
|
365
366
|
layoutCount: 0,
|
|
@@ -392,6 +393,7 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
|
|
|
392
393
|
this.setStatus(state, 'failed', new Error(msg));
|
|
393
394
|
return;
|
|
394
395
|
}
|
|
396
|
+
trFontFace.texture.setRenderableOwner(state, state.isRenderable);
|
|
395
397
|
}
|
|
396
398
|
|
|
397
399
|
// If the font hasn't been loaded yet, stop here.
|
|
@@ -741,6 +743,20 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
|
|
|
741
743
|
// debugData.drawCount++;
|
|
742
744
|
// }
|
|
743
745
|
}
|
|
746
|
+
|
|
747
|
+
override setIsRenderable(
|
|
748
|
+
state: SdfTextRendererState,
|
|
749
|
+
renderable: boolean,
|
|
750
|
+
): void {
|
|
751
|
+
super.setIsRenderable(state, renderable);
|
|
752
|
+
state.trFontFace?.texture.setRenderableOwner(state, renderable);
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
override destroyState(state: SdfTextRendererState): void {
|
|
756
|
+
super.destroyState(state);
|
|
757
|
+
// If there's a Font Face assigned we must free the owner relation to its texture
|
|
758
|
+
state.trFontFace?.texture.setRenderableOwner(state, false);
|
|
759
|
+
}
|
|
744
760
|
//#endregion Overrides
|
|
745
761
|
|
|
746
762
|
public resolveFontFace(props: TrFontProps): SdfTrFontFace | undefined {
|
|
@@ -749,6 +765,18 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
|
|
|
749
765
|
| undefined;
|
|
750
766
|
}
|
|
751
767
|
|
|
768
|
+
/**
|
|
769
|
+
* Release the loaded SDF font face
|
|
770
|
+
*
|
|
771
|
+
* @param state
|
|
772
|
+
*/
|
|
773
|
+
protected releaseFontFace(state: SdfTextRendererState) {
|
|
774
|
+
if (state.trFontFace) {
|
|
775
|
+
state.trFontFace.texture.setRenderableOwner(state, false);
|
|
776
|
+
state.trFontFace = undefined;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
|
|
752
780
|
/**
|
|
753
781
|
* Invalidate the layout cache stored in the state. This will cause the text
|
|
754
782
|
* to be re-layed out on the next update.
|
|
@@ -212,8 +212,6 @@ export function layoutText(
|
|
|
212
212
|
charEndX >= lineVertexW &&
|
|
213
213
|
// There is a last word that we can break to the next line
|
|
214
214
|
lastWord.codepointIndex !== -1 &&
|
|
215
|
-
// We have advanced at least one character since the last word started
|
|
216
|
-
lastWord.codepointIndex < glyph.cluster &&
|
|
217
215
|
// Prevents infinite loop when a single word is longer than the width
|
|
218
216
|
lastWord.xStart > 0
|
|
219
217
|
) {
|
|
@@ -286,8 +284,8 @@ export function layoutText(
|
|
|
286
284
|
}
|
|
287
285
|
|
|
288
286
|
maxY = Math.max(maxY, quadY + glyph.height);
|
|
287
|
+
maxX = Math.max(maxX, quadX + glyph.width);
|
|
289
288
|
curX += glyph.xAdvance;
|
|
290
|
-
maxX = Math.max(maxX, curX);
|
|
291
289
|
}
|
|
292
290
|
} else {
|
|
293
291
|
// Unmapped character
|
|
@@ -66,6 +66,8 @@ export interface TextRendererState {
|
|
|
66
66
|
textW: number | undefined;
|
|
67
67
|
textH: number | undefined;
|
|
68
68
|
|
|
69
|
+
isRenderable: boolean;
|
|
70
|
+
|
|
69
71
|
debugData: {
|
|
70
72
|
updateCount: number;
|
|
71
73
|
layoutCount: number;
|
|
@@ -311,6 +313,7 @@ export interface TrProps extends TrFontProps {
|
|
|
311
313
|
overflowSuffix: string;
|
|
312
314
|
|
|
313
315
|
zIndex: number;
|
|
316
|
+
|
|
314
317
|
debug: Partial<TextRendererDebugProps>;
|
|
315
318
|
}
|
|
316
319
|
|
|
@@ -450,6 +453,17 @@ export abstract class TextRenderer<
|
|
|
450
453
|
state.emitter.emit(status, error);
|
|
451
454
|
}
|
|
452
455
|
|
|
456
|
+
/**
|
|
457
|
+
* Allows the CoreTextNode to communicate changes to the isRenderable state of
|
|
458
|
+
* the itself.
|
|
459
|
+
*
|
|
460
|
+
* @param state
|
|
461
|
+
* @param renderable
|
|
462
|
+
*/
|
|
463
|
+
setIsRenderable(state: StateT, renderable: boolean) {
|
|
464
|
+
state.isRenderable = renderable;
|
|
465
|
+
}
|
|
466
|
+
|
|
453
467
|
/**
|
|
454
468
|
* Called by constructor to get a map of property setter functions for this renderer.
|
|
455
469
|
*/
|
|
@@ -484,6 +498,24 @@ export abstract class TextRenderer<
|
|
|
484
498
|
|
|
485
499
|
abstract createState(props: TrProps): StateT;
|
|
486
500
|
|
|
501
|
+
/**
|
|
502
|
+
* Destroy/Clean up the state object
|
|
503
|
+
*
|
|
504
|
+
* @remarks
|
|
505
|
+
* Opposite of createState(). Frees any event listeners / resources held by
|
|
506
|
+
* the state that may not reliably get garbage collected.
|
|
507
|
+
*
|
|
508
|
+
* @param state
|
|
509
|
+
*/
|
|
510
|
+
destroyState(state: StateT) {
|
|
511
|
+
const stateEvents = ['loading', 'loaded', 'failed'];
|
|
512
|
+
|
|
513
|
+
// Remove the old event listeners from previous state obj there was one
|
|
514
|
+
stateEvents.forEach((eventName) => {
|
|
515
|
+
state.emitter.off(eventName);
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
|
|
487
519
|
/**
|
|
488
520
|
* Schedule a state update via queueMicrotask
|
|
489
521
|
*
|
|
@@ -22,6 +22,11 @@ import type { SubTextureProps } from './SubTexture.js';
|
|
|
22
22
|
import type { Dimensions } from '../../common/CommonTypes.js';
|
|
23
23
|
import { EventEmitter } from '../../common/EventEmitter.js';
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Event handler for when a Texture is freed
|
|
27
|
+
*/
|
|
28
|
+
export type TextureFreedEventHandler = (target: any) => void;
|
|
29
|
+
|
|
25
30
|
/**
|
|
26
31
|
* Event handler for when a Texture is loading
|
|
27
32
|
*/
|
|
@@ -94,9 +99,10 @@ export interface TextureData {
|
|
|
94
99
|
premultiplyAlpha?: boolean | null;
|
|
95
100
|
}
|
|
96
101
|
|
|
97
|
-
export type TextureState = 'loading' | 'loaded' | 'failed';
|
|
102
|
+
export type TextureState = 'freed' | 'loading' | 'loaded' | 'failed';
|
|
98
103
|
|
|
99
104
|
export interface TextureStateEventMap {
|
|
105
|
+
freed: TextureFreedEventHandler;
|
|
100
106
|
loading: TextureLoadingEventHandler;
|
|
101
107
|
loaded: TextureLoadedEventHandler;
|
|
102
108
|
failed: TextureFailedEventHandler;
|
|
@@ -135,12 +141,43 @@ export abstract class Texture extends EventEmitter {
|
|
|
135
141
|
|
|
136
142
|
readonly error: Error | null = null;
|
|
137
143
|
|
|
138
|
-
readonly state: TextureState = '
|
|
144
|
+
readonly state: TextureState = 'freed';
|
|
145
|
+
|
|
146
|
+
readonly renderableOwners = new Set<unknown>();
|
|
139
147
|
|
|
140
148
|
constructor(protected txManager: CoreTextureManager) {
|
|
141
149
|
super();
|
|
142
150
|
}
|
|
143
151
|
|
|
152
|
+
/**
|
|
153
|
+
* Add/remove an owner to/from the Texture based on its renderability.
|
|
154
|
+
*
|
|
155
|
+
* @remarks
|
|
156
|
+
* Any object can own a texture, be it a CoreNode or even the state object
|
|
157
|
+
* from a Text Renderer.
|
|
158
|
+
*
|
|
159
|
+
* When the reference to the texture that an owner object holds is replaced
|
|
160
|
+
* or cleared it must call this with `renderable=false` to release the owner
|
|
161
|
+
* association.
|
|
162
|
+
*
|
|
163
|
+
* @param owner
|
|
164
|
+
* @param renderable
|
|
165
|
+
*/
|
|
166
|
+
setRenderableOwner(owner: unknown, renderable: boolean): void {
|
|
167
|
+
if (renderable) {
|
|
168
|
+
this.renderableOwners.add(owner);
|
|
169
|
+
} else {
|
|
170
|
+
this.renderableOwners.delete(owner);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Returns true if the texture is assigned to any Nodes that are renderable.
|
|
176
|
+
*/
|
|
177
|
+
get renderable(): boolean {
|
|
178
|
+
return this.renderableOwners.size > 0;
|
|
179
|
+
}
|
|
180
|
+
|
|
144
181
|
/**
|
|
145
182
|
* Set the state of the texture
|
|
146
183
|
*
|
|
@@ -9,6 +9,7 @@ import type { ICoreDriver } from './ICoreDriver.js';
|
|
|
9
9
|
import { type RendererMainSettings } from './RendererMain.js';
|
|
10
10
|
import type { AnimationSettings } from '../core/animations/CoreAnimation.js';
|
|
11
11
|
import type { IAnimationController } from '../common/IAnimationController.js';
|
|
12
|
+
import { isProductionEnvironment } from '../utils.js';
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* Inspector
|
|
@@ -152,7 +153,7 @@ export class Inspector {
|
|
|
152
153
|
private scaleY = 1;
|
|
153
154
|
|
|
154
155
|
constructor(canvas: HTMLCanvasElement, settings: RendererMainSettings) {
|
|
155
|
-
if (
|
|
156
|
+
if (isProductionEnvironment()) return;
|
|
156
157
|
|
|
157
158
|
if (!settings) {
|
|
158
159
|
throw new Error('settings is required');
|
|
@@ -40,6 +40,7 @@ import type { TextureUsageTracker } from './texture-usage-trackers/TextureUsageT
|
|
|
40
40
|
import { EventEmitter } from '../common/EventEmitter.js';
|
|
41
41
|
import { Inspector } from './Inspector.js';
|
|
42
42
|
import { santizeCustomDataMap } from '../render-drivers/utils.js';
|
|
43
|
+
import { isProductionEnvironment } from '../utils.js';
|
|
43
44
|
|
|
44
45
|
/**
|
|
45
46
|
* An immutable reference to a specific Texture type
|
|
@@ -127,11 +128,22 @@ export interface RendererMainSettings {
|
|
|
127
128
|
appHeight?: number;
|
|
128
129
|
|
|
129
130
|
/**
|
|
130
|
-
*
|
|
131
|
+
* Texture Memory Byte Threshold
|
|
131
132
|
*
|
|
133
|
+
* @remarks
|
|
134
|
+
* When the amount of GPU VRAM used by textures exceeds this threshold,
|
|
135
|
+
* the Renderer will free up all the textures that are current not visible
|
|
136
|
+
* within the configured `boundsMargin`.
|
|
132
137
|
*
|
|
138
|
+
* When set to `0`, the threshold-based texture memory manager is disabled.
|
|
139
|
+
*/
|
|
140
|
+
txMemByteThreshold?: number;
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Bounds margin to extend the boundary in which a CoreNode is added as Quad.
|
|
133
144
|
*/
|
|
134
145
|
boundsMargin?: number | [number, number, number, number];
|
|
146
|
+
|
|
135
147
|
/**
|
|
136
148
|
* Factor to convert app-authored logical coorindates to device logical coordinates
|
|
137
149
|
*
|
|
@@ -317,6 +329,7 @@ export class RendererMain extends EventEmitter {
|
|
|
317
329
|
const resolvedSettings: Required<RendererMainSettings> = {
|
|
318
330
|
appWidth: settings.appWidth || 1920,
|
|
319
331
|
appHeight: settings.appHeight || 1080,
|
|
332
|
+
txMemByteThreshold: settings.txMemByteThreshold || 124e6,
|
|
320
333
|
boundsMargin: settings.boundsMargin || 0,
|
|
321
334
|
deviceLogicalPixelRatio: settings.deviceLogicalPixelRatio || 1,
|
|
322
335
|
devicePhysicalPixelRatio:
|
|
@@ -397,9 +410,13 @@ export class RendererMain extends EventEmitter {
|
|
|
397
410
|
this.emit('frameTick', frameTickData);
|
|
398
411
|
};
|
|
399
412
|
|
|
413
|
+
driver.onIdle = () => {
|
|
414
|
+
this.emit('idle');
|
|
415
|
+
};
|
|
416
|
+
|
|
400
417
|
targetEl.appendChild(canvas);
|
|
401
418
|
|
|
402
|
-
if (enableInspector && !
|
|
419
|
+
if (enableInspector && !isProductionEnvironment()) {
|
|
403
420
|
this.inspector = new Inspector(canvas, resolvedSettings);
|
|
404
421
|
}
|
|
405
422
|
}
|
|
@@ -55,6 +55,7 @@ export class MainCoreDriver implements ICoreDriver {
|
|
|
55
55
|
rootId: getNewId(),
|
|
56
56
|
appWidth: rendererSettings.appWidth,
|
|
57
57
|
appHeight: rendererSettings.appHeight,
|
|
58
|
+
txMemByteThreshold: rendererSettings.txMemByteThreshold,
|
|
58
59
|
boundsMargin: rendererSettings.boundsMargin,
|
|
59
60
|
deviceLogicalPixelRatio: rendererSettings.deviceLogicalPixelRatio,
|
|
60
61
|
devicePhysicalPixelRatio: rendererSettings.devicePhysicalPixelRatio,
|
|
@@ -92,6 +93,10 @@ export class MainCoreDriver implements ICoreDriver {
|
|
|
92
93
|
this.stage.on('frameTick', ((stage, frameTickData) => {
|
|
93
94
|
this.onFrameTick(frameTickData);
|
|
94
95
|
}) satisfies StageFrameTickHandler);
|
|
96
|
+
|
|
97
|
+
this.stage.on('idle', () => {
|
|
98
|
+
this.onIdle();
|
|
99
|
+
});
|
|
95
100
|
}
|
|
96
101
|
|
|
97
102
|
createNode(props: INodeWritableProps): INode {
|
|
@@ -145,5 +150,9 @@ export class MainCoreDriver implements ICoreDriver {
|
|
|
145
150
|
onFrameTick(frameTickData: FrameTickPayload) {
|
|
146
151
|
throw new Error('Method not implemented.');
|
|
147
152
|
}
|
|
153
|
+
|
|
154
|
+
onIdle() {
|
|
155
|
+
throw new Error('Method not implemented.');
|
|
156
|
+
}
|
|
148
157
|
//#endregion
|
|
149
158
|
}
|
|
@@ -108,6 +108,7 @@ export class MainOnlyNode extends EventEmitter implements INode {
|
|
|
108
108
|
// Forward loaded/failed events
|
|
109
109
|
this.coreNode.on('loaded', this.onTextureLoaded);
|
|
110
110
|
this.coreNode.on('failed', this.onTextureFailed);
|
|
111
|
+
this.coreNode.on('freed', this.onTextureFreed);
|
|
111
112
|
|
|
112
113
|
this.coreNode.on('outOfBounds', this.onOutOfBounds);
|
|
113
114
|
this.coreNode.on('inBounds', this.onInBounds);
|
|
@@ -420,6 +421,10 @@ export class MainOnlyNode extends EventEmitter implements INode {
|
|
|
420
421
|
this.emit('failed', payload);
|
|
421
422
|
};
|
|
422
423
|
|
|
424
|
+
private onTextureFreed: NodeLoadedEventHandler = (target, payload) => {
|
|
425
|
+
this.emit('freed', payload);
|
|
426
|
+
};
|
|
427
|
+
|
|
423
428
|
private onOutOfBounds: NodeRenderStateEventHandler = (target, payload) => {
|
|
424
429
|
this.emit('outOfBounds', payload);
|
|
425
430
|
};
|
|
@@ -461,13 +466,14 @@ export class MainOnlyNode extends EventEmitter implements INode {
|
|
|
461
466
|
|
|
462
467
|
destroy(): void {
|
|
463
468
|
this.emit('beforeDestroy', {});
|
|
464
|
-
|
|
465
|
-
//
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
+
|
|
470
|
+
//use while loop since setting parent to null removes it from array
|
|
471
|
+
let child = this.children[0];
|
|
472
|
+
while (child) {
|
|
473
|
+
child.destroy();
|
|
474
|
+
child = this.children[0];
|
|
469
475
|
}
|
|
470
|
-
this.
|
|
476
|
+
this.coreNode.destroy();
|
|
471
477
|
this.parent = null;
|
|
472
478
|
this.texture = null;
|
|
473
479
|
this.emit('afterDestroy', {});
|
|
@@ -112,6 +112,7 @@ export class ThreadXCoreDriver implements ICoreDriver {
|
|
|
112
112
|
canvas: offscreenCanvas,
|
|
113
113
|
appWidth: rendererSettings.appWidth,
|
|
114
114
|
appHeight: rendererSettings.appHeight,
|
|
115
|
+
txMemByteThreshold: rendererSettings.txMemByteThreshold,
|
|
115
116
|
boundsMargin: rendererSettings.boundsMargin,
|
|
116
117
|
deviceLogicalPixelRatio: rendererSettings.deviceLogicalPixelRatio,
|
|
117
118
|
devicePhysicalPixelRatio: rendererSettings.devicePhysicalPixelRatio,
|
|
@@ -44,6 +44,7 @@ export interface ThreadXRendererInitMessage extends ThreadXRendererMessage {
|
|
|
44
44
|
canvas: OffscreenCanvas;
|
|
45
45
|
appWidth: number;
|
|
46
46
|
appHeight: number;
|
|
47
|
+
txMemByteThreshold: number;
|
|
47
48
|
boundsMargin: number | [number, number, number, number];
|
|
48
49
|
deviceLogicalPixelRatio: number;
|
|
49
50
|
devicePhysicalPixelRatio: number;
|
|
@@ -33,6 +33,7 @@ import type { AnimationSettings } from '../../../core/animations/CoreAnimation.j
|
|
|
33
33
|
import type {
|
|
34
34
|
NodeLoadedPayload,
|
|
35
35
|
NodeFailedPayload,
|
|
36
|
+
NodeTextureFreedPayload,
|
|
36
37
|
} from '../../../common/CommonTypes.js';
|
|
37
38
|
|
|
38
39
|
export class ThreadXRendererNode extends SharedNode {
|
|
@@ -143,6 +144,12 @@ export class ThreadXRendererNode extends SharedNode {
|
|
|
143
144
|
this.emit('failed', payload);
|
|
144
145
|
},
|
|
145
146
|
);
|
|
147
|
+
this.coreNode.on(
|
|
148
|
+
'freed',
|
|
149
|
+
(target: CoreNode, payload: NodeTextureFreedPayload) => {
|
|
150
|
+
this.emit('freed', payload);
|
|
151
|
+
},
|
|
152
|
+
);
|
|
146
153
|
}
|
|
147
154
|
|
|
148
155
|
override onPropertyChange<Key extends keyof this['z$__type__Props']>(
|
|
@@ -66,6 +66,7 @@ const threadx = ThreadX.init({
|
|
|
66
66
|
rootId: nodeStruct.id,
|
|
67
67
|
appWidth: message.appWidth,
|
|
68
68
|
appHeight: message.appHeight,
|
|
69
|
+
txMemByteThreshold: message.txMemByteThreshold,
|
|
69
70
|
boundsMargin: message.boundsMargin,
|
|
70
71
|
deviceLogicalPixelRatio: message.deviceLogicalPixelRatio,
|
|
71
72
|
devicePhysicalPixelRatio: message.devicePhysicalPixelRatio,
|
package/src/utils.ts
CHANGED
|
@@ -79,7 +79,7 @@ export function assertTruthy(
|
|
|
79
79
|
condition: unknown,
|
|
80
80
|
message?: string,
|
|
81
81
|
): asserts condition {
|
|
82
|
-
if (
|
|
82
|
+
if (isProductionEnvironment()) return;
|
|
83
83
|
if (!condition) {
|
|
84
84
|
throw new Error(message || 'Assertion failed');
|
|
85
85
|
}
|
|
@@ -205,3 +205,12 @@ export function hasOwn(obj: object, prop: string | number | symbol): boolean {
|
|
|
205
205
|
export function deg2Rad(degrees: number): number {
|
|
206
206
|
return (degrees * Math.PI) / 180;
|
|
207
207
|
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Checks import.meta if env is production
|
|
211
|
+
*
|
|
212
|
+
* @returns
|
|
213
|
+
*/
|
|
214
|
+
export function isProductionEnvironment(): boolean {
|
|
215
|
+
return import.meta.env && import.meta.env.PROD;
|
|
216
|
+
}
|