@lightningjs/renderer 0.5.0 → 0.6.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 +40 -8
- package/dist/exports/main-api.d.ts +3 -3
- package/dist/exports/main-api.js +3 -3
- package/dist/exports/main-api.js.map +1 -1
- package/dist/src/core/CoreNode.d.ts +24 -10
- package/dist/src/core/CoreNode.js +92 -20
- package/dist/src/core/CoreNode.js.map +1 -1
- package/dist/src/core/CoreShaderManager.d.ts +4 -0
- package/dist/src/core/CoreShaderManager.js +8 -0
- package/dist/src/core/CoreShaderManager.js.map +1 -1
- package/dist/src/core/CoreTextNode.d.ts +2 -4
- package/dist/src/core/CoreTextNode.js +5 -53
- package/dist/src/core/CoreTextNode.js.map +1 -1
- package/dist/src/core/Stage.d.ts +14 -3
- package/dist/src/core/Stage.js +52 -32
- package/dist/src/core/Stage.js.map +1 -1
- package/dist/src/core/animations/CoreAnimation.d.ts +1 -0
- package/dist/src/core/animations/CoreAnimation.js +25 -15
- package/dist/src/core/animations/CoreAnimation.js.map +1 -1
- package/dist/src/core/lib/utils.d.ts +5 -1
- package/dist/src/core/lib/utils.js +17 -12
- package/dist/src/core/lib/utils.js.map +1 -1
- package/dist/src/core/platform.js +4 -4
- package/dist/src/core/platform.js.map +1 -1
- package/dist/src/core/renderers/CoreRenderer.d.ts +1 -3
- package/dist/src/core/renderers/CoreRenderer.js.map +1 -1
- package/dist/src/core/renderers/webgl/WebGlCoreRenderer.d.ts +11 -17
- package/dist/src/core/renderers/webgl/WebGlCoreRenderer.js +13 -30
- package/dist/src/core/renderers/webgl/WebGlCoreRenderer.js.map +1 -1
- package/dist/src/core/renderers/webgl/shaders/DefaultShader.js +3 -0
- package/dist/src/core/renderers/webgl/shaders/DefaultShader.js.map +1 -1
- package/dist/src/core/renderers/webgl/shaders/DynamicShader.js +5 -28
- package/dist/src/core/renderers/webgl/shaders/DynamicShader.js.map +1 -1
- package/dist/src/core/renderers/webgl/shaders/effects/RadialProgressEffect.d.ts +61 -0
- package/dist/src/core/renderers/webgl/shaders/effects/RadialProgressEffect.js +126 -0
- package/dist/src/core/renderers/webgl/shaders/effects/RadialProgressEffect.js.map +1 -0
- package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.d.ts +20 -2
- package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.js +98 -45
- package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.js.map +1 -1
- package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.d.ts +16 -4
- package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js +80 -42
- package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js.map +1 -1
- package/dist/src/core/text-rendering/renderers/TextRenderer.d.ts +16 -8
- package/dist/src/core/text-rendering/renderers/TextRenderer.js +34 -8
- package/dist/src/core/text-rendering/renderers/TextRenderer.js.map +1 -1
- package/dist/src/main-api/{IRenderDriver.d.ts → ICoreDriver.d.ts} +3 -2
- package/dist/src/main-api/{IRenderDriver.js → ICoreDriver.js} +1 -1
- package/dist/src/main-api/ICoreDriver.js.map +1 -0
- package/dist/src/main-api/INode.d.ts +2 -2
- package/dist/src/main-api/RendererMain.d.ts +16 -6
- package/dist/src/main-api/RendererMain.js +9 -3
- package/dist/src/main-api/RendererMain.js.map +1 -1
- package/dist/src/render-drivers/main/{MainRenderDriver.d.ts → MainCoreDriver.d.ts} +3 -2
- package/dist/src/render-drivers/main/{MainRenderDriver.js → MainCoreDriver.js} +14 -4
- package/dist/src/render-drivers/main/MainCoreDriver.js.map +1 -0
- package/dist/src/render-drivers/threadx/{ThreadXRenderDriver.d.ts → ThreadXCoreDriver.d.ts} +4 -2
- package/dist/src/render-drivers/threadx/{ThreadXRenderDriver.js → ThreadXCoreDriver.js} +18 -4
- package/dist/src/render-drivers/threadx/ThreadXCoreDriver.js.map +1 -0
- package/dist/src/render-drivers/threadx/ThreadXRendererMessage.d.ts +9 -0
- package/dist/src/render-drivers/threadx/ThreadXRendererMessage.js.map +1 -1
- package/dist/src/render-drivers/threadx/worker/renderer.js +8 -0
- package/dist/src/render-drivers/threadx/worker/renderer.js.map +1 -1
- package/dist/src/utils.js +2 -1
- package/dist/src/utils.js.map +1 -1
- package/dist/tsconfig.dist.tsbuildinfo +1 -1
- package/exports/main-api.ts +3 -3
- package/package.json +8 -3
- package/src/core/CoreNode.ts +107 -21
- package/src/core/CoreShaderManager.ts +11 -0
- package/src/core/CoreTextNode.ts +5 -58
- package/src/core/Stage.ts +65 -34
- package/src/core/animations/CoreAnimation.ts +47 -27
- package/src/core/lib/utils.ts +39 -13
- package/src/core/platform.ts +5 -4
- package/src/core/renderers/CoreRenderer.ts +1 -2
- package/src/core/renderers/webgl/WebGlCoreRenderer.ts +14 -35
- package/src/core/renderers/webgl/shaders/DefaultShader.ts +4 -0
- package/src/core/renderers/webgl/shaders/DynamicShader.ts +5 -29
- package/src/core/renderers/webgl/shaders/effects/RadialProgressEffect.ts +186 -0
- package/src/core/text-rendering/renderers/CanvasTextRenderer.ts +107 -50
- package/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.ts +95 -44
- package/src/core/text-rendering/renderers/TextRenderer.ts +44 -16
- package/src/main-api/{IRenderDriver.ts → ICoreDriver.ts} +4 -2
- package/src/main-api/INode.ts +2 -2
- package/src/main-api/RendererMain.ts +23 -6
- package/src/render-drivers/main/{MainRenderDriver.ts → MainCoreDriver.ts} +17 -4
- package/src/render-drivers/threadx/{ThreadXRenderDriver.ts → ThreadXCoreDriver.ts} +23 -7
- package/src/render-drivers/threadx/ThreadXRendererMessage.ts +11 -0
- package/src/render-drivers/threadx/worker/renderer.ts +10 -0
- package/src/utils.ts +2 -1
- package/dist/src/main-api/IRenderDriver.js.map +0 -1
- package/dist/src/render-drivers/main/MainRenderDriver.js.map +0 -1
- package/dist/src/render-drivers/threadx/ThreadXRenderDriver.js.map +0 -1
package/src/core/CoreNode.ts
CHANGED
|
@@ -37,7 +37,7 @@ import type {
|
|
|
37
37
|
NodeTextureLoadedPayload,
|
|
38
38
|
} from '../common/CommonTypes.js';
|
|
39
39
|
import { EventEmitter } from '../common/EventEmitter.js';
|
|
40
|
-
import type
|
|
40
|
+
import { intersectRect, type Rect } from './lib/utils.js';
|
|
41
41
|
import { Matrix3d } from './lib/Matrix3d.js';
|
|
42
42
|
|
|
43
43
|
export interface CoreNodeProps {
|
|
@@ -86,18 +86,13 @@ export class CoreNode extends EventEmitter implements ICoreNode {
|
|
|
86
86
|
readonly children: CoreNode[] = [];
|
|
87
87
|
protected props: Required<CoreNodeProps>;
|
|
88
88
|
|
|
89
|
-
|
|
90
|
-
* Recalculation type
|
|
91
|
-
* 0 - no recalculation
|
|
92
|
-
* 1 - alpha recalculation
|
|
93
|
-
* 2 - translate recalculation
|
|
94
|
-
* 4 - transform recalculation
|
|
95
|
-
*/
|
|
96
|
-
public recalculationType = 6;
|
|
89
|
+
public recalculationType = 0;
|
|
97
90
|
public hasUpdates = true;
|
|
98
91
|
public globalTransform?: Matrix3d;
|
|
99
92
|
public scaleRotateTransform?: Matrix3d;
|
|
100
93
|
public localTransform?: Matrix3d;
|
|
94
|
+
public clippingRect: Rect | null = null;
|
|
95
|
+
private parentClippingRect: Rect | null = null;
|
|
101
96
|
|
|
102
97
|
private isComplex = false;
|
|
103
98
|
|
|
@@ -179,27 +174,46 @@ export class CoreNode extends EventEmitter implements ICoreNode {
|
|
|
179
174
|
}
|
|
180
175
|
|
|
181
176
|
setHasUpdates(): void {
|
|
182
|
-
if (!this.props.alpha) {
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
177
|
this.hasUpdates = true;
|
|
186
|
-
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
setChildrenHasUpdates(): void {
|
|
181
|
+
this.children.forEach((child) => {
|
|
182
|
+
child.setRecalculationType(2);
|
|
183
|
+
});
|
|
184
|
+
}
|
|
187
185
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
186
|
+
setParentHasUpdates(): void {
|
|
187
|
+
if (!this.props.parent) {
|
|
188
|
+
return;
|
|
191
189
|
}
|
|
190
|
+
|
|
191
|
+
this.props.parent.setRecalculationType(1);
|
|
192
192
|
}
|
|
193
193
|
|
|
194
194
|
/**
|
|
195
|
+
* Change types types is used to determine the scope of the changes being applied
|
|
195
196
|
* 1 - alpha recalculation
|
|
196
197
|
* 2 - translate recalculation
|
|
197
198
|
* 4 - transform recalculation
|
|
199
|
+
* 8 - z-index recalculation
|
|
200
|
+
*
|
|
198
201
|
* @param type
|
|
199
202
|
*/
|
|
200
203
|
setRecalculationType(type: number): void {
|
|
201
204
|
this.recalculationType |= type;
|
|
202
205
|
this.setHasUpdates();
|
|
206
|
+
|
|
207
|
+
// always forcing parent updates so the root will have an hasUpdates flag
|
|
208
|
+
this.setParentHasUpdates();
|
|
209
|
+
|
|
210
|
+
if (type & 4) {
|
|
211
|
+
this.setChildrenHasUpdates();
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
sortChildren() {
|
|
216
|
+
this.children.sort((a, b) => a.zIndex - b.zIndex);
|
|
203
217
|
}
|
|
204
218
|
|
|
205
219
|
updateScaleRotateTransform() {
|
|
@@ -235,7 +249,7 @@ export class CoreNode extends EventEmitter implements ICoreNode {
|
|
|
235
249
|
* @todo: test for correct calculation flag
|
|
236
250
|
* @param delta
|
|
237
251
|
*/
|
|
238
|
-
update(delta: number): void {
|
|
252
|
+
update(delta: number, parentClippingRect: Rect | null = null): void {
|
|
239
253
|
assertTruthy(this.localTransform);
|
|
240
254
|
const parentGlobalTransform = this.parent?.globalTransform;
|
|
241
255
|
if (parentGlobalTransform) {
|
|
@@ -250,12 +264,19 @@ export class CoreNode extends EventEmitter implements ICoreNode {
|
|
|
250
264
|
);
|
|
251
265
|
}
|
|
252
266
|
|
|
267
|
+
this.calculateClippingRect(parentClippingRect);
|
|
268
|
+
|
|
253
269
|
if (this.children.length) {
|
|
254
270
|
this.children.forEach((child) => {
|
|
255
|
-
child.update(delta);
|
|
271
|
+
child.update(delta, this.clippingRect);
|
|
256
272
|
});
|
|
257
273
|
}
|
|
258
274
|
|
|
275
|
+
if (this.recalculationType & 8) {
|
|
276
|
+
// reorder z-index
|
|
277
|
+
this.sortChildren();
|
|
278
|
+
}
|
|
279
|
+
|
|
259
280
|
// reset update flag
|
|
260
281
|
this.hasUpdates = false;
|
|
261
282
|
|
|
@@ -263,7 +284,55 @@ export class CoreNode extends EventEmitter implements ICoreNode {
|
|
|
263
284
|
this.recalculationType = 0;
|
|
264
285
|
}
|
|
265
286
|
|
|
266
|
-
|
|
287
|
+
/**
|
|
288
|
+
* This function calculates the clipping rectangle for a node.
|
|
289
|
+
*
|
|
290
|
+
* If the node's globalTransform is not set, the function returns immediately.
|
|
291
|
+
* If the node's props do not require clipping and there is no parent clipping rectangle, the node's clipping rectangle is set to null.
|
|
292
|
+
* If the parent clipping rectangle has not changed and the node's clipping rectangle is already set, the function returns immediately.
|
|
293
|
+
*
|
|
294
|
+
* The function then checks if the node is rotated. If the node requires clipping and is not rotated, a new clipping rectangle is created based on the node's global transform and dimensions.
|
|
295
|
+
* If a parent clipping rectangle exists, it is intersected with the node's clipping rectangle (if it exists), or replaces the node's clipping rectangle.
|
|
296
|
+
*
|
|
297
|
+
* Finally, the node's parentClippingRect and clippingRect properties are updated.
|
|
298
|
+
*/
|
|
299
|
+
calculateClippingRect(parentClippingRect: Rect | null = null) {
|
|
300
|
+
if (!this.globalTransform) {
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
if (!this.props.clipping && !parentClippingRect) {
|
|
305
|
+
this.clippingRect = null;
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if (this.parentClippingRect === parentClippingRect && this.clippingRect) {
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const gt = this.globalTransform;
|
|
314
|
+
const isRotated = gt.tb !== 0 || gt.tc !== 0;
|
|
315
|
+
|
|
316
|
+
let clippingRect: Rect | null =
|
|
317
|
+
this.props.clipping && !isRotated
|
|
318
|
+
? {
|
|
319
|
+
x: gt.tx,
|
|
320
|
+
y: gt.ty,
|
|
321
|
+
width: this.width * gt.ta,
|
|
322
|
+
height: this.height * gt.td,
|
|
323
|
+
}
|
|
324
|
+
: null;
|
|
325
|
+
if (parentClippingRect && clippingRect) {
|
|
326
|
+
clippingRect = intersectRect(parentClippingRect, clippingRect);
|
|
327
|
+
} else if (parentClippingRect) {
|
|
328
|
+
clippingRect = parentClippingRect;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
this.parentClippingRect = parentClippingRect;
|
|
332
|
+
this.clippingRect = clippingRect;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
renderQuads(renderer: CoreRenderer): void {
|
|
267
336
|
const {
|
|
268
337
|
width,
|
|
269
338
|
height,
|
|
@@ -276,12 +345,12 @@ export class CoreNode extends EventEmitter implements ICoreNode {
|
|
|
276
345
|
shader,
|
|
277
346
|
shaderProps,
|
|
278
347
|
} = this.props;
|
|
279
|
-
const { zIndex, worldAlpha, globalTransform: gt } = this;
|
|
348
|
+
const { zIndex, worldAlpha, globalTransform: gt, clippingRect } = this;
|
|
280
349
|
|
|
281
350
|
assertTruthy(gt);
|
|
282
351
|
|
|
283
352
|
// add to list of renderables to be sorted before rendering
|
|
284
|
-
renderer.
|
|
353
|
+
renderer.addQuad({
|
|
285
354
|
width,
|
|
286
355
|
height,
|
|
287
356
|
colorTl,
|
|
@@ -494,6 +563,7 @@ export class CoreNode extends EventEmitter implements ICoreNode {
|
|
|
494
563
|
|
|
495
564
|
set alpha(value: number) {
|
|
496
565
|
this.props.alpha = value;
|
|
566
|
+
this.setRecalculationType(1);
|
|
497
567
|
}
|
|
498
568
|
|
|
499
569
|
get worldAlpha(): number {
|
|
@@ -509,6 +579,8 @@ export class CoreNode extends EventEmitter implements ICoreNode {
|
|
|
509
579
|
|
|
510
580
|
set clipping(value: boolean) {
|
|
511
581
|
this.props.clipping = value;
|
|
582
|
+
this.clippingRect = null;
|
|
583
|
+
this.setRecalculationType(4);
|
|
512
584
|
}
|
|
513
585
|
|
|
514
586
|
get color(): number {
|
|
@@ -528,6 +600,8 @@ export class CoreNode extends EventEmitter implements ICoreNode {
|
|
|
528
600
|
this.colorBr = value;
|
|
529
601
|
}
|
|
530
602
|
this.props.color = value;
|
|
603
|
+
|
|
604
|
+
this.setRecalculationType(2);
|
|
531
605
|
}
|
|
532
606
|
|
|
533
607
|
get colorTop(): number {
|
|
@@ -540,6 +614,7 @@ export class CoreNode extends EventEmitter implements ICoreNode {
|
|
|
540
614
|
this.colorTr = value;
|
|
541
615
|
}
|
|
542
616
|
this.props.colorTop = value;
|
|
617
|
+
this.setRecalculationType(2);
|
|
543
618
|
}
|
|
544
619
|
|
|
545
620
|
get colorBottom(): number {
|
|
@@ -552,6 +627,7 @@ export class CoreNode extends EventEmitter implements ICoreNode {
|
|
|
552
627
|
this.colorBr = value;
|
|
553
628
|
}
|
|
554
629
|
this.props.colorBottom = value;
|
|
630
|
+
this.setRecalculationType(2);
|
|
555
631
|
}
|
|
556
632
|
|
|
557
633
|
get colorLeft(): number {
|
|
@@ -564,6 +640,7 @@ export class CoreNode extends EventEmitter implements ICoreNode {
|
|
|
564
640
|
this.colorBl = value;
|
|
565
641
|
}
|
|
566
642
|
this.props.colorLeft = value;
|
|
643
|
+
this.setRecalculationType(2);
|
|
567
644
|
}
|
|
568
645
|
|
|
569
646
|
get colorRight(): number {
|
|
@@ -576,6 +653,7 @@ export class CoreNode extends EventEmitter implements ICoreNode {
|
|
|
576
653
|
this.colorBr = value;
|
|
577
654
|
}
|
|
578
655
|
this.props.colorRight = value;
|
|
656
|
+
this.setRecalculationType(2);
|
|
579
657
|
}
|
|
580
658
|
|
|
581
659
|
get colorTl(): number {
|
|
@@ -584,6 +662,7 @@ export class CoreNode extends EventEmitter implements ICoreNode {
|
|
|
584
662
|
|
|
585
663
|
set colorTl(value: number) {
|
|
586
664
|
this.props.colorTl = value;
|
|
665
|
+
this.setRecalculationType(2);
|
|
587
666
|
}
|
|
588
667
|
|
|
589
668
|
get colorTr(): number {
|
|
@@ -592,6 +671,7 @@ export class CoreNode extends EventEmitter implements ICoreNode {
|
|
|
592
671
|
|
|
593
672
|
set colorTr(value: number) {
|
|
594
673
|
this.props.colorTr = value;
|
|
674
|
+
this.setRecalculationType(2);
|
|
595
675
|
}
|
|
596
676
|
|
|
597
677
|
get colorBl(): number {
|
|
@@ -600,6 +680,7 @@ export class CoreNode extends EventEmitter implements ICoreNode {
|
|
|
600
680
|
|
|
601
681
|
set colorBl(value: number) {
|
|
602
682
|
this.props.colorBl = value;
|
|
683
|
+
this.setRecalculationType(2);
|
|
603
684
|
}
|
|
604
685
|
|
|
605
686
|
get colorBr(): number {
|
|
@@ -608,6 +689,7 @@ export class CoreNode extends EventEmitter implements ICoreNode {
|
|
|
608
689
|
|
|
609
690
|
set colorBr(value: number) {
|
|
610
691
|
this.props.colorBr = value;
|
|
692
|
+
this.setRecalculationType(2);
|
|
611
693
|
}
|
|
612
694
|
|
|
613
695
|
// we're only interested in parent zIndex to test
|
|
@@ -633,6 +715,7 @@ export class CoreNode extends EventEmitter implements ICoreNode {
|
|
|
633
715
|
|
|
634
716
|
set zIndex(value: number) {
|
|
635
717
|
this.props.zIndex = value;
|
|
718
|
+
this.props.parent?.setRecalculationType(8);
|
|
636
719
|
}
|
|
637
720
|
|
|
638
721
|
get parent(): CoreNode | null {
|
|
@@ -655,7 +738,10 @@ export class CoreNode extends EventEmitter implements ICoreNode {
|
|
|
655
738
|
}
|
|
656
739
|
if (newParent) {
|
|
657
740
|
newParent.children.push(this);
|
|
741
|
+
// force parent to recalculate z-index for its children
|
|
742
|
+
newParent.setRecalculationType(8);
|
|
658
743
|
}
|
|
744
|
+
|
|
659
745
|
this.updateScaleRotateTransform();
|
|
660
746
|
}
|
|
661
747
|
//#endregion Properties
|
|
@@ -41,6 +41,7 @@ import { GlitchEffect } from './renderers/webgl/shaders/effects/GlitchEffect.js'
|
|
|
41
41
|
import { FadeOutEffect } from './renderers/webgl/shaders/effects/FadeOutEffect.js';
|
|
42
42
|
import { RadialGradientEffect } from './renderers/webgl/shaders/effects/RadialGradientEffect.js';
|
|
43
43
|
import type { WebGlCoreRenderer } from './renderers/webgl/WebGlCoreRenderer.js';
|
|
44
|
+
import { RadialProgressEffect } from './renderers/webgl/shaders/effects/RadialProgressEffect.js';
|
|
44
45
|
|
|
45
46
|
export interface ShaderMap {
|
|
46
47
|
DefaultShader: typeof DefaultShader;
|
|
@@ -67,6 +68,7 @@ export interface EffectMap {
|
|
|
67
68
|
radialGradient: typeof RadialGradientEffect;
|
|
68
69
|
grayscale: typeof GrayscaleEffect;
|
|
69
70
|
glitch: typeof GlitchEffect;
|
|
71
|
+
radialProgress: typeof RadialProgressEffect;
|
|
70
72
|
}
|
|
71
73
|
|
|
72
74
|
export class CoreShaderManager {
|
|
@@ -95,6 +97,7 @@ export class CoreShaderManager {
|
|
|
95
97
|
this.registerEffectType('grayscale', GrayscaleEffect);
|
|
96
98
|
this.registerEffectType('glitch', GlitchEffect);
|
|
97
99
|
this.registerEffectType('radius', RadiusEffect);
|
|
100
|
+
this.registerEffectType('radialProgress', RadialProgressEffect);
|
|
98
101
|
}
|
|
99
102
|
|
|
100
103
|
registerShaderType<Type extends keyof ShaderMap>(
|
|
@@ -111,6 +114,14 @@ export class CoreShaderManager {
|
|
|
111
114
|
this.effectConstructors[effectType] = effectClass;
|
|
112
115
|
}
|
|
113
116
|
|
|
117
|
+
getRegisteredEffects(): Partial<EffectMap> {
|
|
118
|
+
return this.effectConstructors;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
getRegisteredShaders(): Partial<ShaderMap> {
|
|
122
|
+
return this.shConstructors;
|
|
123
|
+
}
|
|
124
|
+
|
|
114
125
|
loadShader<Type extends keyof ShaderMap>(
|
|
115
126
|
shType: Type,
|
|
116
127
|
props?: ExtractProps<ShaderMap[Type]>,
|
package/src/core/CoreTextNode.ts
CHANGED
|
@@ -48,13 +48,11 @@ type ICoreTextNode = Omit<
|
|
|
48
48
|
export class CoreTextNode extends CoreNode implements ICoreTextNode {
|
|
49
49
|
textRenderer: TextRenderer;
|
|
50
50
|
trState: TextRendererState;
|
|
51
|
-
updateScheduled: boolean;
|
|
52
51
|
private _textRendererOverride: CoreTextNodeProps['textRendererOverride'] =
|
|
53
52
|
null;
|
|
54
53
|
|
|
55
54
|
constructor(stage: Stage, props: CoreTextNodeProps) {
|
|
56
55
|
super(stage, props);
|
|
57
|
-
this.updateScheduled = false;
|
|
58
56
|
this._textRendererOverride = props.textRendererOverride;
|
|
59
57
|
const { resolvedTextRenderer, textRendererState } =
|
|
60
58
|
this.resolveTextRendererAndState(
|
|
@@ -67,8 +65,6 @@ export class CoreTextNode extends CoreNode implements ICoreTextNode {
|
|
|
67
65
|
color: props.color,
|
|
68
66
|
zIndex: props.zIndex,
|
|
69
67
|
contain: props.contain,
|
|
70
|
-
scaleX: props.scaleX,
|
|
71
|
-
scaleY: props.scaleY,
|
|
72
68
|
scrollable: props.scrollable,
|
|
73
69
|
scrollY: props.scrollY,
|
|
74
70
|
offsetY: props.offsetY,
|
|
@@ -128,7 +124,6 @@ export class CoreTextNode extends CoreNode implements ICoreTextNode {
|
|
|
128
124
|
|
|
129
125
|
override set width(value: number) {
|
|
130
126
|
this.textRenderer.set.width(this.trState, value);
|
|
131
|
-
this.updateText();
|
|
132
127
|
}
|
|
133
128
|
|
|
134
129
|
override get height(): number {
|
|
@@ -137,7 +132,6 @@ export class CoreTextNode extends CoreNode implements ICoreTextNode {
|
|
|
137
132
|
|
|
138
133
|
override set height(value: number) {
|
|
139
134
|
this.textRenderer.set.height(this.trState, value);
|
|
140
|
-
this.updateText();
|
|
141
135
|
}
|
|
142
136
|
|
|
143
137
|
override get color(): number {
|
|
@@ -146,7 +140,6 @@ export class CoreTextNode extends CoreNode implements ICoreTextNode {
|
|
|
146
140
|
|
|
147
141
|
override set color(value: number) {
|
|
148
142
|
this.textRenderer.set.color(this.trState, value);
|
|
149
|
-
this.updateText();
|
|
150
143
|
}
|
|
151
144
|
|
|
152
145
|
get text(): string {
|
|
@@ -155,7 +148,6 @@ export class CoreTextNode extends CoreNode implements ICoreTextNode {
|
|
|
155
148
|
|
|
156
149
|
set text(value: string) {
|
|
157
150
|
this.textRenderer.set.text(this.trState, value);
|
|
158
|
-
this.updateText();
|
|
159
151
|
}
|
|
160
152
|
|
|
161
153
|
get textRendererOverride(): CoreTextNodeProps['textRendererOverride'] {
|
|
@@ -177,7 +169,6 @@ export class CoreTextNode extends CoreNode implements ICoreTextNode {
|
|
|
177
169
|
|
|
178
170
|
set fontSize(value: CoreTextNodeProps['fontSize']) {
|
|
179
171
|
this.textRenderer.set.fontSize(this.trState, value);
|
|
180
|
-
this.updateText();
|
|
181
172
|
}
|
|
182
173
|
|
|
183
174
|
get fontFamily(): CoreTextNodeProps['fontFamily'] {
|
|
@@ -186,7 +177,6 @@ export class CoreTextNode extends CoreNode implements ICoreTextNode {
|
|
|
186
177
|
|
|
187
178
|
set fontFamily(value: CoreTextNodeProps['fontFamily']) {
|
|
188
179
|
this.textRenderer.set.fontFamily(this.trState, value);
|
|
189
|
-
this.updateText();
|
|
190
180
|
}
|
|
191
181
|
|
|
192
182
|
get fontStretch(): CoreTextNodeProps['fontStretch'] {
|
|
@@ -195,7 +185,6 @@ export class CoreTextNode extends CoreNode implements ICoreTextNode {
|
|
|
195
185
|
|
|
196
186
|
set fontStretch(value: CoreTextNodeProps['fontStretch']) {
|
|
197
187
|
this.textRenderer.set.fontStretch(this.trState, value);
|
|
198
|
-
this.updateText();
|
|
199
188
|
}
|
|
200
189
|
|
|
201
190
|
get fontStyle(): CoreTextNodeProps['fontStyle'] {
|
|
@@ -204,7 +193,6 @@ export class CoreTextNode extends CoreNode implements ICoreTextNode {
|
|
|
204
193
|
|
|
205
194
|
set fontStyle(value: CoreTextNodeProps['fontStyle']) {
|
|
206
195
|
this.textRenderer.set.fontStyle(this.trState, value);
|
|
207
|
-
this.updateText();
|
|
208
196
|
}
|
|
209
197
|
|
|
210
198
|
get fontWeight(): CoreTextNodeProps['fontWeight'] {
|
|
@@ -213,7 +201,6 @@ export class CoreTextNode extends CoreNode implements ICoreTextNode {
|
|
|
213
201
|
|
|
214
202
|
set fontWeight(value: CoreTextNodeProps['fontWeight']) {
|
|
215
203
|
this.textRenderer.set.fontWeight(this.trState, value);
|
|
216
|
-
this.updateText();
|
|
217
204
|
}
|
|
218
205
|
|
|
219
206
|
get textAlign(): CoreTextNodeProps['textAlign'] {
|
|
@@ -222,7 +209,6 @@ export class CoreTextNode extends CoreNode implements ICoreTextNode {
|
|
|
222
209
|
|
|
223
210
|
set textAlign(value: CoreTextNodeProps['textAlign']) {
|
|
224
211
|
this.textRenderer.set.textAlign(this.trState, value);
|
|
225
|
-
this.updateText();
|
|
226
212
|
}
|
|
227
213
|
|
|
228
214
|
get contain(): CoreTextNodeProps['contain'] {
|
|
@@ -231,7 +217,6 @@ export class CoreTextNode extends CoreNode implements ICoreTextNode {
|
|
|
231
217
|
|
|
232
218
|
set contain(value: CoreTextNodeProps['contain']) {
|
|
233
219
|
this.textRenderer.set.contain(this.trState, value);
|
|
234
|
-
this.updateText();
|
|
235
220
|
}
|
|
236
221
|
|
|
237
222
|
get scrollable(): CoreTextNodeProps['scrollable'] {
|
|
@@ -240,7 +225,6 @@ export class CoreTextNode extends CoreNode implements ICoreTextNode {
|
|
|
240
225
|
|
|
241
226
|
set scrollable(value: CoreTextNodeProps['scrollable']) {
|
|
242
227
|
this.textRenderer.set.scrollable(this.trState, value);
|
|
243
|
-
this.updateText();
|
|
244
228
|
}
|
|
245
229
|
|
|
246
230
|
get scrollY(): CoreTextNodeProps['scrollY'] {
|
|
@@ -249,7 +233,6 @@ export class CoreTextNode extends CoreNode implements ICoreTextNode {
|
|
|
249
233
|
|
|
250
234
|
set scrollY(value: CoreTextNodeProps['scrollY']) {
|
|
251
235
|
this.textRenderer.set.scrollY(this.trState, value);
|
|
252
|
-
this.updateText();
|
|
253
236
|
}
|
|
254
237
|
|
|
255
238
|
get offsetY(): CoreTextNodeProps['offsetY'] {
|
|
@@ -258,7 +241,6 @@ export class CoreTextNode extends CoreNode implements ICoreTextNode {
|
|
|
258
241
|
|
|
259
242
|
set offsetY(value: CoreTextNodeProps['offsetY']) {
|
|
260
243
|
this.textRenderer.set.offsetY(this.trState, value);
|
|
261
|
-
this.updateText();
|
|
262
244
|
}
|
|
263
245
|
|
|
264
246
|
get letterSpacing(): CoreTextNodeProps['letterSpacing'] {
|
|
@@ -267,7 +249,6 @@ export class CoreTextNode extends CoreNode implements ICoreTextNode {
|
|
|
267
249
|
|
|
268
250
|
set letterSpacing(value: CoreTextNodeProps['letterSpacing']) {
|
|
269
251
|
this.textRenderer.set.letterSpacing(this.trState, value);
|
|
270
|
-
this.updateText();
|
|
271
252
|
}
|
|
272
253
|
|
|
273
254
|
get debug(): CoreTextNodeProps['debug'] {
|
|
@@ -276,41 +257,24 @@ export class CoreTextNode extends CoreNode implements ICoreTextNode {
|
|
|
276
257
|
|
|
277
258
|
set debug(value: CoreTextNodeProps['debug']) {
|
|
278
259
|
this.textRenderer.set.debug(this.trState, value);
|
|
279
|
-
this.updateText();
|
|
280
260
|
}
|
|
281
261
|
|
|
282
|
-
override update(delta: number) {
|
|
283
|
-
super.update(delta);
|
|
262
|
+
override update(delta: number, parentClippingRect: Rect | null = null) {
|
|
263
|
+
super.update(delta, parentClippingRect);
|
|
284
264
|
|
|
285
265
|
assertTruthy(this.globalTransform);
|
|
286
266
|
|
|
287
267
|
// globalTransform is updated in super.update(delta)
|
|
288
268
|
this.textRenderer.set.x(this.trState, this.globalTransform.tx);
|
|
289
269
|
this.textRenderer.set.y(this.trState, this.globalTransform.ty);
|
|
290
|
-
|
|
291
|
-
if (this.trState.status === 'loading') {
|
|
292
|
-
// Update the text state now
|
|
293
|
-
this.textRenderer.updateState(this.trState);
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
private updateText() {
|
|
298
|
-
if (this.updateScheduled) {
|
|
299
|
-
return;
|
|
300
|
-
}
|
|
301
|
-
this.updateScheduled = true;
|
|
302
|
-
queueMicrotask(() => {
|
|
303
|
-
this.updateScheduled = false;
|
|
304
|
-
this.textRenderer.updateState(this.trState);
|
|
305
|
-
});
|
|
306
270
|
}
|
|
307
271
|
|
|
308
|
-
override renderQuads(renderer: CoreRenderer
|
|
272
|
+
override renderQuads(renderer: CoreRenderer) {
|
|
309
273
|
assertTruthy(this.globalTransform);
|
|
310
274
|
this.textRenderer.renderQuads(
|
|
311
275
|
this.trState,
|
|
312
276
|
this.globalTransform,
|
|
313
|
-
clippingRect,
|
|
277
|
+
this.clippingRect,
|
|
314
278
|
this.worldAlpha,
|
|
315
279
|
);
|
|
316
280
|
}
|
|
@@ -343,26 +307,9 @@ export class CoreTextNode extends CoreNode implements ICoreTextNode {
|
|
|
343
307
|
});
|
|
344
308
|
}
|
|
345
309
|
|
|
346
|
-
// Forward basic status events from the text renderer state
|
|
347
|
-
textRendererState.emitter.on('loading', () => {
|
|
348
|
-
// This event will be fired only once between the `loading` and `loaded`
|
|
349
|
-
// event ONLY if the font is not already loaded
|
|
350
|
-
textRendererState.emitter.once('fontLoaded', () => {
|
|
351
|
-
// When it's fired we must run update to make sure the text renders
|
|
352
|
-
this.updateText();
|
|
353
|
-
});
|
|
354
|
-
|
|
355
|
-
textRendererState.emitter.once('loaded', () => {
|
|
356
|
-
// Make sure we stop listening for fontLoaded events
|
|
357
|
-
textRendererState.emitter.off('fontLoaded');
|
|
358
|
-
});
|
|
359
|
-
});
|
|
360
|
-
|
|
361
310
|
textRendererState.emitter.on('loaded', this.onTextLoaded);
|
|
362
311
|
textRendererState.emitter.on('failed', this.onTextFailed);
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
// TODO: Handle text renderer errors
|
|
312
|
+
resolvedTextRenderer.scheduleUpdateState(textRendererState);
|
|
366
313
|
|
|
367
314
|
return {
|
|
368
315
|
resolvedTextRenderer,
|
package/src/core/Stage.ts
CHANGED
|
@@ -35,7 +35,7 @@ import type {
|
|
|
35
35
|
} from './text-rendering/renderers/TextRenderer.js';
|
|
36
36
|
import { SdfTextRenderer } from './text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js';
|
|
37
37
|
import { CanvasTextRenderer } from './text-rendering/renderers/CanvasTextRenderer.js';
|
|
38
|
-
import {
|
|
38
|
+
import { EventEmitter } from '../common/EventEmitter.js';
|
|
39
39
|
|
|
40
40
|
export interface StageOptions {
|
|
41
41
|
rootId: number;
|
|
@@ -45,6 +45,7 @@ export interface StageOptions {
|
|
|
45
45
|
devicePhysicalPixelRatio: number;
|
|
46
46
|
canvas: HTMLCanvasElement | OffscreenCanvas;
|
|
47
47
|
clearColor: number;
|
|
48
|
+
fpsUpdateInterval: number;
|
|
48
49
|
debug?: {
|
|
49
50
|
monitorTextureCache?: boolean;
|
|
50
51
|
};
|
|
@@ -53,7 +54,7 @@ export interface StageOptions {
|
|
|
53
54
|
const bufferMemory = 2e6;
|
|
54
55
|
const autoStart = true;
|
|
55
56
|
|
|
56
|
-
export class Stage {
|
|
57
|
+
export class Stage extends EventEmitter {
|
|
57
58
|
/// Module Instances
|
|
58
59
|
public readonly animationManager: AnimationManager;
|
|
59
60
|
public readonly txManager: CoreTextureManager;
|
|
@@ -67,11 +68,14 @@ export class Stage {
|
|
|
67
68
|
deltaTime = 0;
|
|
68
69
|
lastFrameTime = 0;
|
|
69
70
|
currentFrameTime = 0;
|
|
71
|
+
private fpsNumFrames = 0;
|
|
72
|
+
private fpsElapsedTime = 0;
|
|
70
73
|
|
|
71
74
|
/**
|
|
72
75
|
* Stage constructor
|
|
73
76
|
*/
|
|
74
77
|
constructor(readonly options: StageOptions) {
|
|
78
|
+
super();
|
|
75
79
|
const { canvas, clearColor, rootId, debug, appWidth, appHeight } = options;
|
|
76
80
|
this.txManager = new CoreTextureManager();
|
|
77
81
|
this.shManager = new CoreShaderManager();
|
|
@@ -149,11 +153,12 @@ export class Stage {
|
|
|
149
153
|
startLoop(this);
|
|
150
154
|
}
|
|
151
155
|
}
|
|
156
|
+
|
|
152
157
|
/**
|
|
153
|
-
*
|
|
158
|
+
* Update animations
|
|
154
159
|
*/
|
|
155
|
-
|
|
156
|
-
const {
|
|
160
|
+
updateAnimations() {
|
|
161
|
+
const { scene, animationManager } = this;
|
|
157
162
|
if (!scene?.root) {
|
|
158
163
|
return;
|
|
159
164
|
}
|
|
@@ -166,48 +171,74 @@ export class Stage {
|
|
|
166
171
|
|
|
167
172
|
// step animation
|
|
168
173
|
animationManager.update(this.deltaTime);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Check if the scene has updates
|
|
178
|
+
*/
|
|
179
|
+
hasSceneUpdates() {
|
|
180
|
+
const { scene } = this;
|
|
181
|
+
|
|
182
|
+
if (!scene?.root) {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return scene?.root?.hasUpdates;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Start a new frame draw
|
|
191
|
+
*/
|
|
192
|
+
drawFrame() {
|
|
193
|
+
const { renderer, scene } = this;
|
|
194
|
+
if (!scene?.root) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
169
197
|
|
|
170
198
|
// reset and clear viewport
|
|
171
|
-
|
|
199
|
+
scene?.root?.update(this.deltaTime);
|
|
172
200
|
|
|
173
201
|
// test if we need to update the scene
|
|
174
|
-
|
|
175
|
-
scene?.root?.update(this.deltaTime);
|
|
176
|
-
}
|
|
202
|
+
renderer?.reset();
|
|
177
203
|
|
|
178
204
|
this.addQuads(scene.root);
|
|
179
205
|
|
|
180
|
-
renderer?.sortRenderables();
|
|
181
206
|
renderer?.render();
|
|
207
|
+
|
|
208
|
+
// If there's an FPS update interval, emit the FPS update event
|
|
209
|
+
// when the specified interval has elapsed.
|
|
210
|
+
const { fpsUpdateInterval } = this.options;
|
|
211
|
+
if (fpsUpdateInterval) {
|
|
212
|
+
this.fpsNumFrames++;
|
|
213
|
+
this.fpsElapsedTime += this.deltaTime;
|
|
214
|
+
if (this.fpsElapsedTime >= fpsUpdateInterval) {
|
|
215
|
+
const fps = Math.round(
|
|
216
|
+
(this.fpsNumFrames * 1000) / this.fpsElapsedTime,
|
|
217
|
+
);
|
|
218
|
+
this.fpsNumFrames = 0;
|
|
219
|
+
this.fpsElapsedTime = 0;
|
|
220
|
+
this.emit('fpsUpdate', fps);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
182
223
|
}
|
|
183
224
|
|
|
184
|
-
addQuads(node: CoreNode
|
|
225
|
+
addQuads(node: CoreNode) {
|
|
185
226
|
assertTruthy(this.renderer && node.globalTransform);
|
|
186
|
-
const gt = node.globalTransform;
|
|
187
|
-
const isRotated = gt.tb !== 0 || gt.tc !== 0;
|
|
188
|
-
|
|
189
|
-
let clippingRect: Rect | null =
|
|
190
|
-
node.clipping && !isRotated
|
|
191
|
-
? {
|
|
192
|
-
x: gt.tx,
|
|
193
|
-
y: gt.ty,
|
|
194
|
-
width: node.width * gt.ta,
|
|
195
|
-
height: node.height * gt.td,
|
|
196
|
-
}
|
|
197
|
-
: null;
|
|
198
|
-
if (parentClippingRect && clippingRect) {
|
|
199
|
-
clippingRect = intersectRect(parentClippingRect, clippingRect);
|
|
200
|
-
} else if (parentClippingRect) {
|
|
201
|
-
clippingRect = parentClippingRect;
|
|
202
|
-
}
|
|
203
227
|
|
|
204
|
-
node.renderQuads(this.renderer
|
|
205
|
-
node.children.
|
|
206
|
-
|
|
207
|
-
|
|
228
|
+
node.renderQuads(this.renderer);
|
|
229
|
+
for (let i = 0; i < node.children.length; i++) {
|
|
230
|
+
const child = node.children[i];
|
|
231
|
+
|
|
232
|
+
if (!child) {
|
|
233
|
+
continue;
|
|
208
234
|
}
|
|
209
|
-
|
|
210
|
-
|
|
235
|
+
|
|
236
|
+
if (child?.worldAlpha === 0) {
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
this.addQuads(child);
|
|
241
|
+
}
|
|
211
242
|
}
|
|
212
243
|
|
|
213
244
|
/**
|