@lightningjs/renderer 0.7.0 → 0.7.1
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/dist/src/core/CoreNode.d.ts +4 -7
- package/dist/src/core/CoreNode.js +29 -25
- package/dist/src/core/CoreNode.js.map +1 -1
- package/dist/src/core/CoreTextNode.d.ts +2 -2
- package/dist/src/core/CoreTextNode.js +1 -1
- package/dist/src/core/CoreTextNode.js.map +1 -1
- package/dist/src/core/Stage.js +1 -1
- 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 +7 -0
- package/dist/src/core/animations/CoreAnimation.js.map +1 -1
- package/dist/src/core/lib/utils.d.ts +9 -0
- package/dist/src/core/lib/utils.js +48 -1
- package/dist/src/core/lib/utils.js.map +1 -1
- package/dist/src/core/renderers/CoreRenderer.d.ts +2 -2
- package/dist/src/core/renderers/webgl/WebGlCoreRenderOp.d.ts +3 -3
- package/dist/src/core/renderers/webgl/WebGlCoreRenderOp.js +1 -1
- package/dist/src/core/renderers/webgl/WebGlCoreRenderOp.js.map +1 -1
- package/dist/src/core/renderers/webgl/WebGlCoreRenderer.js +5 -0
- package/dist/src/core/renderers/webgl/WebGlCoreRenderer.js.map +1 -1
- package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.d.ts +2 -2
- package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.js.map +1 -1
- package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.d.ts +6 -10
- package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js +73 -46
- package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js.map +1 -1
- package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.js +1 -1
- package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.js.map +1 -1
- package/dist/src/core/text-rendering/renderers/TextRenderer.d.ts +2 -2
- package/dist/tsconfig.dist.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/core/CoreNode.ts +30 -29
- package/src/core/CoreTextNode.ts +2 -2
- package/src/core/Stage.ts +1 -1
- package/src/core/animations/CoreAnimation.ts +8 -0
- package/src/core/lib/utils.ts +68 -1
- package/src/core/renderers/CoreRenderer.ts +2 -2
- package/src/core/renderers/webgl/WebGlCoreRenderOp.ts +3 -3
- package/src/core/renderers/webgl/WebGlCoreRenderer.ts +7 -1
- package/src/core/text-rendering/renderers/CanvasTextRenderer.ts +2 -1
- package/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.ts +96 -58
- package/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.ts +1 -1
- package/src/core/text-rendering/renderers/TextRenderer.ts +2 -2
|
@@ -18,13 +18,15 @@
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
import {
|
|
21
|
-
intersectBound,
|
|
22
21
|
type Bound,
|
|
23
22
|
type Rect,
|
|
24
23
|
createBound,
|
|
25
24
|
type BoundWithValid,
|
|
26
25
|
intersectRect,
|
|
27
|
-
|
|
26
|
+
type RectWithValid,
|
|
27
|
+
copyRect,
|
|
28
|
+
boundsOverlap,
|
|
29
|
+
convertBoundToRect,
|
|
28
30
|
} from '../../../lib/utils.js';
|
|
29
31
|
import {
|
|
30
32
|
TextRenderer,
|
|
@@ -84,7 +86,9 @@ export interface SdfTextRendererState extends TextRendererState {
|
|
|
84
86
|
|
|
85
87
|
renderWindow: SdfRenderWindow;
|
|
86
88
|
|
|
87
|
-
|
|
89
|
+
elementBounds: BoundWithValid;
|
|
90
|
+
|
|
91
|
+
clippingRect: RectWithValid;
|
|
88
92
|
|
|
89
93
|
bufferNumFloats: number;
|
|
90
94
|
|
|
@@ -104,13 +108,14 @@ export interface SdfTextRendererState extends TextRendererState {
|
|
|
104
108
|
}
|
|
105
109
|
|
|
106
110
|
/**
|
|
107
|
-
* Ephemeral
|
|
108
|
-
*
|
|
109
|
-
* @remarks
|
|
110
|
-
* Used to avoid creating a new object every time we need to intersect
|
|
111
|
-
* element bounds.
|
|
111
|
+
* Ephemeral rect object used for calculations
|
|
112
112
|
*/
|
|
113
|
-
const
|
|
113
|
+
const tmpRect: Rect = {
|
|
114
|
+
x: 0,
|
|
115
|
+
y: 0,
|
|
116
|
+
width: 0,
|
|
117
|
+
height: 0,
|
|
118
|
+
};
|
|
114
119
|
|
|
115
120
|
/**
|
|
116
121
|
* Singleton class for rendering text using signed distance fields.
|
|
@@ -178,11 +183,31 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
|
|
|
178
183
|
},
|
|
179
184
|
x: (state, value) => {
|
|
180
185
|
state.props.x = value;
|
|
181
|
-
|
|
186
|
+
if (state.elementBounds.valid) {
|
|
187
|
+
this.setElementBoundsX(state);
|
|
188
|
+
// Only schedule an update if the text is not already rendered
|
|
189
|
+
// (renderWindow is invalid) and the element possibly overlaps the screen
|
|
190
|
+
// This is to avoid unnecessary updates when we know text is off-screen
|
|
191
|
+
if (
|
|
192
|
+
!state.renderWindow.valid &&
|
|
193
|
+
boundsOverlap(state.elementBounds, this.rendererBounds)
|
|
194
|
+
) {
|
|
195
|
+
this.scheduleUpdateState(state);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
182
198
|
},
|
|
183
199
|
y: (state, value) => {
|
|
184
200
|
state.props.y = value;
|
|
185
|
-
|
|
201
|
+
if (state.elementBounds.valid) {
|
|
202
|
+
this.setElementBoundsY(state);
|
|
203
|
+
// See x() for explanation
|
|
204
|
+
if (
|
|
205
|
+
!state.renderWindow.valid &&
|
|
206
|
+
boundsOverlap(state.elementBounds, this.rendererBounds)
|
|
207
|
+
) {
|
|
208
|
+
this.scheduleUpdateState(state);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
186
211
|
},
|
|
187
212
|
contain: (state, value) => {
|
|
188
213
|
state.props.contain = value;
|
|
@@ -304,13 +329,20 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
|
|
|
304
329
|
numLines: 0,
|
|
305
330
|
valid: false,
|
|
306
331
|
},
|
|
307
|
-
|
|
332
|
+
elementBounds: {
|
|
308
333
|
x1: 0,
|
|
309
334
|
y1: 0,
|
|
310
335
|
x2: 0,
|
|
311
336
|
y2: 0,
|
|
312
337
|
valid: false,
|
|
313
338
|
},
|
|
339
|
+
clippingRect: {
|
|
340
|
+
x: 0,
|
|
341
|
+
y: 0,
|
|
342
|
+
width: 0,
|
|
343
|
+
height: 0,
|
|
344
|
+
valid: false,
|
|
345
|
+
},
|
|
314
346
|
bufferNumFloats: 0,
|
|
315
347
|
bufferNumQuads: 0,
|
|
316
348
|
vertexBuffer: undefined,
|
|
@@ -410,22 +442,11 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
|
|
|
410
442
|
vertexBuffer = new Float32Array(neededLength * 2);
|
|
411
443
|
}
|
|
412
444
|
|
|
413
|
-
const
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
x,
|
|
419
|
-
y,
|
|
420
|
-
contain !== 'none' ? x + width : Infinity,
|
|
421
|
-
contain === 'both' ? y + height : Infinity,
|
|
422
|
-
tmpElementBounds, // Prevent allocation by using this temp object
|
|
423
|
-
);
|
|
424
|
-
/**
|
|
425
|
-
* Area that is visible on the screen.
|
|
426
|
-
*/
|
|
427
|
-
intersectBound(this.rendererBounds, elementBounds, state.visibleWindow);
|
|
428
|
-
visibleWindow.valid = true;
|
|
445
|
+
const elementBounds = state.elementBounds;
|
|
446
|
+
if (!elementBounds.valid) {
|
|
447
|
+
this.setElementBoundsX(state);
|
|
448
|
+
this.setElementBoundsY(state);
|
|
449
|
+
elementBounds.valid = true;
|
|
429
450
|
}
|
|
430
451
|
|
|
431
452
|
// Return early if we're still viewing inside the established render window
|
|
@@ -434,10 +455,10 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
|
|
|
434
455
|
if (!forceFullLayoutCalc && renderWindow.valid) {
|
|
435
456
|
const rwScreen = renderWindow.screen;
|
|
436
457
|
if (
|
|
437
|
-
x + rwScreen.x1 <=
|
|
438
|
-
x + rwScreen.x2 >=
|
|
439
|
-
y - scrollY + rwScreen.y1 <=
|
|
440
|
-
y - scrollY + rwScreen.y2 >=
|
|
458
|
+
x + rwScreen.x1 <= elementBounds.x1 &&
|
|
459
|
+
x + rwScreen.x2 >= elementBounds.x2 &&
|
|
460
|
+
y - scrollY + rwScreen.y1 <= elementBounds.y1 &&
|
|
461
|
+
y - scrollY + rwScreen.y2 >= elementBounds.y2
|
|
441
462
|
) {
|
|
442
463
|
this.setStatus(state, 'loaded');
|
|
443
464
|
return;
|
|
@@ -451,14 +472,24 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
|
|
|
451
472
|
|
|
452
473
|
// Create a new renderWindow if needed
|
|
453
474
|
if (!renderWindow.valid) {
|
|
475
|
+
const isPossiblyOnScreen = boundsOverlap(
|
|
476
|
+
elementBounds,
|
|
477
|
+
this.rendererBounds,
|
|
478
|
+
);
|
|
479
|
+
|
|
480
|
+
if (!isPossiblyOnScreen) {
|
|
481
|
+
// If the element is not possibly on screen, we can skip the layout and rendering completely
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
|
|
454
485
|
setRenderWindow(
|
|
455
486
|
renderWindow,
|
|
456
487
|
x,
|
|
457
488
|
y,
|
|
458
489
|
scrollY,
|
|
459
490
|
lineHeight,
|
|
460
|
-
|
|
461
|
-
|
|
491
|
+
contain === 'both' ? elementBounds.y2 - elementBounds.y1 : 0,
|
|
492
|
+
elementBounds,
|
|
462
493
|
fontSizeRatio,
|
|
463
494
|
);
|
|
464
495
|
// console.log('newRenderWindow', renderWindow);
|
|
@@ -531,7 +562,7 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
|
|
|
531
562
|
override renderQuads(
|
|
532
563
|
state: SdfTextRendererState,
|
|
533
564
|
transform: Matrix3d,
|
|
534
|
-
clippingRect:
|
|
565
|
+
clippingRect: Readonly<RectWithValid>,
|
|
535
566
|
alpha: number,
|
|
536
567
|
): void {
|
|
537
568
|
if (!state.vertexBuffer) {
|
|
@@ -553,6 +584,7 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
|
|
|
553
584
|
vertexBuffer,
|
|
554
585
|
bufferUploaded,
|
|
555
586
|
trFontFace,
|
|
587
|
+
elementBounds,
|
|
556
588
|
} = state;
|
|
557
589
|
|
|
558
590
|
let { webGlBuffers } = state;
|
|
@@ -599,18 +631,21 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
|
|
|
599
631
|
}
|
|
600
632
|
|
|
601
633
|
assertTruthy(trFontFace);
|
|
602
|
-
|
|
603
634
|
if (scrollable && contain === 'both') {
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
635
|
+
assertTruthy(elementBounds.valid);
|
|
636
|
+
const elementRect = convertBoundToRect(elementBounds, tmpRect);
|
|
637
|
+
|
|
638
|
+
if (clippingRect.valid) {
|
|
639
|
+
state.clippingRect.valid = true;
|
|
640
|
+
clippingRect = intersectRect(
|
|
641
|
+
clippingRect,
|
|
642
|
+
elementRect,
|
|
643
|
+
state.clippingRect,
|
|
644
|
+
);
|
|
645
|
+
} else {
|
|
646
|
+
state.clippingRect.valid = true;
|
|
647
|
+
clippingRect = copyRect(elementRect, state.clippingRect);
|
|
648
|
+
}
|
|
614
649
|
}
|
|
615
650
|
|
|
616
651
|
const renderOp = new WebGlCoreRenderOp(
|
|
@@ -707,17 +742,6 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
|
|
|
707
742
|
) as SdfTrFontFace | undefined;
|
|
708
743
|
}
|
|
709
744
|
|
|
710
|
-
/**
|
|
711
|
-
* Invalidate the visible window stored in the state. This will cause a new
|
|
712
|
-
* visible window to be calculated on the next update.
|
|
713
|
-
*
|
|
714
|
-
* @param state
|
|
715
|
-
*/
|
|
716
|
-
protected invalidateVisibleWindowCache(state: SdfTextRendererState): void {
|
|
717
|
-
state.visibleWindow.valid = false;
|
|
718
|
-
this.scheduleUpdateState(state);
|
|
719
|
-
}
|
|
720
|
-
|
|
721
745
|
/**
|
|
722
746
|
* Invalidate the layout cache stored in the state. This will cause the text
|
|
723
747
|
* to be re-layed out on the next update.
|
|
@@ -728,12 +752,26 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
|
|
|
728
752
|
* @param state
|
|
729
753
|
*/
|
|
730
754
|
protected invalidateLayoutCache(state: SdfTextRendererState): void {
|
|
731
|
-
state.visibleWindow.valid = false;
|
|
732
755
|
state.renderWindow.valid = false;
|
|
756
|
+
state.elementBounds.valid = false;
|
|
733
757
|
state.textH = undefined;
|
|
734
758
|
state.textW = undefined;
|
|
735
759
|
state.lineCache = [];
|
|
736
760
|
this.setStatus(state, 'loading');
|
|
737
761
|
this.scheduleUpdateState(state);
|
|
738
762
|
}
|
|
763
|
+
|
|
764
|
+
protected setElementBoundsX(state: SdfTextRendererState): void {
|
|
765
|
+
const { x, contain, width } = state.props;
|
|
766
|
+
const { elementBounds } = state;
|
|
767
|
+
elementBounds.x1 = x;
|
|
768
|
+
elementBounds.x2 = contain !== 'none' ? x + width : Infinity;
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
protected setElementBoundsY(state: SdfTextRendererState): void {
|
|
772
|
+
const { y, contain, height } = state.props;
|
|
773
|
+
const { elementBounds } = state;
|
|
774
|
+
elementBounds.y1 = y;
|
|
775
|
+
elementBounds.y2 = contain === 'both' ? y + height : Infinity;
|
|
776
|
+
}
|
|
739
777
|
}
|
|
@@ -87,7 +87,7 @@ export function setRenderWindow(
|
|
|
87
87
|
sdf.y2 = y2 / fontSizeRatio;
|
|
88
88
|
|
|
89
89
|
outRenderWindow.numLines = Math.ceil((y2 - y1) / lineHeight);
|
|
90
|
-
outRenderWindow.firstLineIdx = Math.floor(y1 / lineHeight);
|
|
90
|
+
outRenderWindow.firstLineIdx = lineHeight ? Math.floor(y1 / lineHeight) : 0;
|
|
91
91
|
}
|
|
92
92
|
outRenderWindow.valid = true;
|
|
93
93
|
}
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
import type { EventEmitter } from '../../../common/EventEmitter.js';
|
|
21
21
|
import type { Stage } from '../../Stage.js';
|
|
22
22
|
import type { Matrix3d } from '../../lib/Matrix3d.js';
|
|
23
|
-
import type { Rect } from '../../lib/utils.js';
|
|
23
|
+
import type { Rect, RectWithValid } from '../../lib/utils.js';
|
|
24
24
|
import type {
|
|
25
25
|
TrFontFace,
|
|
26
26
|
TrFontFaceDescriptors,
|
|
@@ -498,7 +498,7 @@ export abstract class TextRenderer<
|
|
|
498
498
|
abstract renderQuads(
|
|
499
499
|
state: StateT,
|
|
500
500
|
transform: Matrix3d,
|
|
501
|
-
clippingRect:
|
|
501
|
+
clippingRect: RectWithValid,
|
|
502
502
|
alpha: number,
|
|
503
503
|
): void;
|
|
504
504
|
}
|