@lightningjs/renderer 0.7.0 → 0.7.2
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/exports/main-api.d.ts +1 -0
- 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/CoreShaderManager.d.ts +13 -6
- package/dist/src/core/CoreShaderManager.js +6 -6
- package/dist/src/core/CoreShaderManager.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/WebGlContextWrapper.d.ts +9 -0
- package/dist/src/core/lib/WebGlContextWrapper.js +12 -0
- package/dist/src/core/lib/WebGlContextWrapper.js.map +1 -1
- package/dist/src/core/lib/textureCompression.d.ts +16 -0
- package/dist/src/core/lib/textureCompression.js +129 -0
- package/dist/src/core/lib/textureCompression.js.map +1 -0
- 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/WebGlCoreCtxTexture.js +12 -0
- package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.js.map +1 -1
- 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/font-face-types/SdfTrFontFace/SdfTrFontFace.d.ts +4 -0
- package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.js +11 -0
- package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.js.map +1 -1
- package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.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 +10 -1
- package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.js.map +1 -1
- package/dist/src/core/text-rendering/renderers/LightningTextTextureRenderer.js +21 -7
- package/dist/src/core/text-rendering/renderers/LightningTextTextureRenderer.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/layoutText.js +2 -1
- package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.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/src/core/textures/ImageTexture.js +5 -0
- package/dist/src/core/textures/ImageTexture.js.map +1 -1
- package/dist/src/core/textures/Texture.d.ts +28 -1
- package/dist/src/core/textures/Texture.js.map +1 -1
- package/dist/src/main-api/Inspector.d.ts +15 -0
- package/dist/src/main-api/Inspector.js +216 -0
- package/dist/src/main-api/Inspector.js.map +1 -0
- package/dist/tsconfig.dist.tsbuildinfo +1 -1
- package/exports/main-api.ts +9 -0
- package/package.json +1 -1
- package/src/core/CoreNode.ts +30 -29
- package/src/core/CoreShaderManager.ts +39 -6
- 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/WebGlContextWrapper.ts +27 -0
- package/src/core/lib/textureCompression.ts +152 -0
- package/src/core/lib/utils.ts +68 -1
- package/src/core/renderers/CoreRenderer.ts +2 -2
- package/src/core/renderers/webgl/WebGlCoreCtxTexture.ts +20 -0
- package/src/core/renderers/webgl/WebGlCoreRenderOp.ts +3 -3
- package/src/core/renderers/webgl/WebGlCoreRenderer.ts +7 -1
- package/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.ts +15 -1
- package/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.test.ts +12 -4
- package/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.ts +4 -1
- package/src/core/text-rendering/renderers/CanvasTextRenderer.ts +16 -2
- package/src/core/text-rendering/renderers/LightningTextTextureRenderer.ts +42 -8
- package/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.ts +96 -60
- package/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.ts +2 -1
- package/src/core/text-rendering/renderers/SdfTextRenderer/internal/measureText.test.ts +4 -1
- package/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.ts +1 -1
- package/src/core/text-rendering/renderers/TextRenderer.ts +2 -2
- package/src/core/textures/ImageTexture.ts +9 -0
- package/src/core/textures/Texture.ts +33 -1
package/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.test.ts
CHANGED
|
@@ -34,7 +34,10 @@ sdfData.chars.forEach((glyph) => {
|
|
|
34
34
|
|
|
35
35
|
describe('SdfFontShaper', () => {
|
|
36
36
|
it('should be able to shape text.', () => {
|
|
37
|
-
const shaper = new SdfFontShaper(
|
|
37
|
+
const shaper = new SdfFontShaper(
|
|
38
|
+
sdfData as unknown as SdfFontData,
|
|
39
|
+
glyphMap,
|
|
40
|
+
);
|
|
38
41
|
const peekableCodepoints = new PeekableIterator(
|
|
39
42
|
getUnicodeCodepoints('Hi!'),
|
|
40
43
|
);
|
|
@@ -88,7 +91,10 @@ describe('SdfFontShaper', () => {
|
|
|
88
91
|
});
|
|
89
92
|
|
|
90
93
|
it('should be able to shape text that we know have kerning pairs.', () => {
|
|
91
|
-
const shaper = new SdfFontShaper(
|
|
94
|
+
const shaper = new SdfFontShaper(
|
|
95
|
+
sdfData as unknown as SdfFontData,
|
|
96
|
+
glyphMap,
|
|
97
|
+
);
|
|
92
98
|
const peekableCodepoints = new PeekableIterator(
|
|
93
99
|
getUnicodeCodepoints('WeVo'),
|
|
94
100
|
);
|
|
@@ -130,8 +136,10 @@ describe('SdfFontShaper', () => {
|
|
|
130
136
|
});
|
|
131
137
|
|
|
132
138
|
it('should be able to shape text with letterSpacing.', () => {
|
|
133
|
-
|
|
134
|
-
|
|
139
|
+
const shaper = new SdfFontShaper(
|
|
140
|
+
sdfData as unknown as SdfFontData,
|
|
141
|
+
glyphMap,
|
|
142
|
+
);
|
|
135
143
|
const peekableCodepoints = new PeekableIterator(
|
|
136
144
|
getUnicodeCodepoints('We!'),
|
|
137
145
|
);
|
|
@@ -39,7 +39,10 @@ export class SdfFontShaper extends FontShaper {
|
|
|
39
39
|
private readonly glyphMap: Map<number, SdfFontData['chars'][0]>;
|
|
40
40
|
private readonly kernings: KerningTable;
|
|
41
41
|
|
|
42
|
-
constructor(
|
|
42
|
+
constructor(
|
|
43
|
+
data: SdfFontData,
|
|
44
|
+
glyphMap: Map<number, SdfFontData['chars'][0]>,
|
|
45
|
+
) {
|
|
43
46
|
super();
|
|
44
47
|
this.data = data;
|
|
45
48
|
this.glyphMap = glyphMap;
|
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
getNormalizedAlphaComponent,
|
|
31
31
|
type BoundWithValid,
|
|
32
32
|
createBound,
|
|
33
|
+
type RectWithValid,
|
|
33
34
|
} from '../../lib/utils.js';
|
|
34
35
|
import type { ImageTexture } from '../../textures/ImageTexture.js';
|
|
35
36
|
import type { TrFontFace } from '../font-face-types/TrFontFace.js';
|
|
@@ -325,6 +326,18 @@ export class CanvasTextRenderer extends TextRenderer<CanvasTextRendererState> {
|
|
|
325
326
|
}
|
|
326
327
|
|
|
327
328
|
if (!state.renderInfo) {
|
|
329
|
+
const maxLines = state.props.maxLines;
|
|
330
|
+
const containedMaxLines =
|
|
331
|
+
state.props.contain === 'both'
|
|
332
|
+
? Math.floor(
|
|
333
|
+
(state.props.height - state.props.offsetY) /
|
|
334
|
+
state.props.lineHeight,
|
|
335
|
+
)
|
|
336
|
+
: 0;
|
|
337
|
+
const calcMaxLines =
|
|
338
|
+
containedMaxLines > 0 && maxLines > 0
|
|
339
|
+
? Math.min(containedMaxLines, maxLines)
|
|
340
|
+
: Math.max(containedMaxLines, maxLines);
|
|
328
341
|
state.lightning2TextRenderer.settings = {
|
|
329
342
|
text: state.props.text,
|
|
330
343
|
textAlign: state.props.textAlign,
|
|
@@ -342,7 +355,7 @@ export class CanvasTextRenderer extends TextRenderer<CanvasTextRendererState> {
|
|
|
342
355
|
state.props.contain === 'none' ? undefined : state.props.width,
|
|
343
356
|
letterSpacing: state.props.letterSpacing,
|
|
344
357
|
lineHeight: state.props.lineHeight,
|
|
345
|
-
maxLines:
|
|
358
|
+
maxLines: calcMaxLines,
|
|
346
359
|
textBaseline: state.props.textBaseline,
|
|
347
360
|
verticalAlign: state.props.verticalAlign,
|
|
348
361
|
overflowSuffix: state.props.overflowSuffix,
|
|
@@ -524,7 +537,7 @@ export class CanvasTextRenderer extends TextRenderer<CanvasTextRendererState> {
|
|
|
524
537
|
override renderQuads(
|
|
525
538
|
state: CanvasTextRendererState,
|
|
526
539
|
transform: Matrix3d,
|
|
527
|
-
clippingRect:
|
|
540
|
+
clippingRect: RectWithValid,
|
|
528
541
|
alpha: number,
|
|
529
542
|
): void {
|
|
530
543
|
const { stage } = this;
|
|
@@ -700,6 +713,7 @@ export class CanvasTextRenderer extends TextRenderer<CanvasTextRendererState> {
|
|
|
700
713
|
*/
|
|
701
714
|
private invalidateLayoutCache(state: CanvasTextRendererState): void {
|
|
702
715
|
state.renderInfo = undefined;
|
|
716
|
+
state.visibleWindow.valid = false;
|
|
703
717
|
this.setStatus(state, 'loading');
|
|
704
718
|
this.scheduleUpdateState(state);
|
|
705
719
|
}
|
|
@@ -125,6 +125,32 @@ export interface RenderInfo {
|
|
|
125
125
|
textIndent: number;
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
+
/**
|
|
129
|
+
* Calculate height for the canvas
|
|
130
|
+
*
|
|
131
|
+
* @param textBaseline
|
|
132
|
+
* @param fontSize
|
|
133
|
+
* @param lineHeight
|
|
134
|
+
* @param numLines
|
|
135
|
+
* @param offsetY
|
|
136
|
+
* @returns
|
|
137
|
+
*/
|
|
138
|
+
function calcHeight(
|
|
139
|
+
textBaseline: TextBaseline,
|
|
140
|
+
fontSize: number,
|
|
141
|
+
lineHeight: number,
|
|
142
|
+
numLines: number,
|
|
143
|
+
offsetY: number | null,
|
|
144
|
+
) {
|
|
145
|
+
const baselineOffset = textBaseline !== 'bottom' ? 0.5 * fontSize : 0;
|
|
146
|
+
return (
|
|
147
|
+
lineHeight * (numLines - 1) +
|
|
148
|
+
baselineOffset +
|
|
149
|
+
Math.max(lineHeight, fontSize) +
|
|
150
|
+
(offsetY || 0)
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
128
154
|
export class LightningTextTextureRenderer {
|
|
129
155
|
private _canvas: OffscreenCanvas | HTMLCanvasElement;
|
|
130
156
|
private _context:
|
|
@@ -349,13 +375,13 @@ export class LightningTextTextureRenderer {
|
|
|
349
375
|
if (h) {
|
|
350
376
|
height = h;
|
|
351
377
|
} else {
|
|
352
|
-
|
|
353
|
-
this._settings.textBaseline
|
|
354
|
-
|
|
355
|
-
lineHeight
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
378
|
+
height = calcHeight(
|
|
379
|
+
this._settings.textBaseline,
|
|
380
|
+
fontSize,
|
|
381
|
+
lineHeight,
|
|
382
|
+
lines.length,
|
|
383
|
+
offsetY,
|
|
384
|
+
);
|
|
359
385
|
}
|
|
360
386
|
|
|
361
387
|
if (offsetY === null) {
|
|
@@ -414,7 +440,15 @@ export class LightningTextTextureRenderer {
|
|
|
414
440
|
const lines = linesOverride?.lines || renderInfo.lines;
|
|
415
441
|
const lineWidths = linesOverride?.lineWidths || renderInfo.lineWidths;
|
|
416
442
|
const height = linesOverride
|
|
417
|
-
?
|
|
443
|
+
? calcHeight(
|
|
444
|
+
this._settings.textBaseline,
|
|
445
|
+
renderInfo.fontSize,
|
|
446
|
+
renderInfo.lineHeight,
|
|
447
|
+
linesOverride.lines.length,
|
|
448
|
+
this._settings.offsetY === null
|
|
449
|
+
? null
|
|
450
|
+
: this._settings.offsetY * precision,
|
|
451
|
+
)
|
|
418
452
|
: renderInfo.height;
|
|
419
453
|
|
|
420
454
|
// Add extra margin to prevent issue with clipped text when scaling.
|
|
@@ -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,14 +86,14 @@ 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
|
|
|
91
95
|
bufferNumQuads: number;
|
|
92
96
|
|
|
93
|
-
// texCoordBuffer: Float32Array | undefined;
|
|
94
|
-
|
|
95
97
|
vertexBuffer: Float32Array | undefined;
|
|
96
98
|
|
|
97
99
|
webGlBuffers: BufferCollection | null;
|
|
@@ -104,13 +106,14 @@ export interface SdfTextRendererState extends TextRendererState {
|
|
|
104
106
|
}
|
|
105
107
|
|
|
106
108
|
/**
|
|
107
|
-
* Ephemeral
|
|
108
|
-
*
|
|
109
|
-
* @remarks
|
|
110
|
-
* Used to avoid creating a new object every time we need to intersect
|
|
111
|
-
* element bounds.
|
|
109
|
+
* Ephemeral rect object used for calculations
|
|
112
110
|
*/
|
|
113
|
-
const
|
|
111
|
+
const tmpRect: Rect = {
|
|
112
|
+
x: 0,
|
|
113
|
+
y: 0,
|
|
114
|
+
width: 0,
|
|
115
|
+
height: 0,
|
|
116
|
+
};
|
|
114
117
|
|
|
115
118
|
/**
|
|
116
119
|
* Singleton class for rendering text using signed distance fields.
|
|
@@ -178,11 +181,31 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
|
|
|
178
181
|
},
|
|
179
182
|
x: (state, value) => {
|
|
180
183
|
state.props.x = value;
|
|
181
|
-
|
|
184
|
+
if (state.elementBounds.valid) {
|
|
185
|
+
this.setElementBoundsX(state);
|
|
186
|
+
// Only schedule an update if the text is not already rendered
|
|
187
|
+
// (renderWindow is invalid) and the element possibly overlaps the screen
|
|
188
|
+
// This is to avoid unnecessary updates when we know text is off-screen
|
|
189
|
+
if (
|
|
190
|
+
!state.renderWindow.valid &&
|
|
191
|
+
boundsOverlap(state.elementBounds, this.rendererBounds)
|
|
192
|
+
) {
|
|
193
|
+
this.scheduleUpdateState(state);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
182
196
|
},
|
|
183
197
|
y: (state, value) => {
|
|
184
198
|
state.props.y = value;
|
|
185
|
-
|
|
199
|
+
if (state.elementBounds.valid) {
|
|
200
|
+
this.setElementBoundsY(state);
|
|
201
|
+
// See x() for explanation
|
|
202
|
+
if (
|
|
203
|
+
!state.renderWindow.valid &&
|
|
204
|
+
boundsOverlap(state.elementBounds, this.rendererBounds)
|
|
205
|
+
) {
|
|
206
|
+
this.scheduleUpdateState(state);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
186
209
|
},
|
|
187
210
|
contain: (state, value) => {
|
|
188
211
|
state.props.contain = value;
|
|
@@ -304,13 +327,20 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
|
|
|
304
327
|
numLines: 0,
|
|
305
328
|
valid: false,
|
|
306
329
|
},
|
|
307
|
-
|
|
330
|
+
elementBounds: {
|
|
308
331
|
x1: 0,
|
|
309
332
|
y1: 0,
|
|
310
333
|
x2: 0,
|
|
311
334
|
y2: 0,
|
|
312
335
|
valid: false,
|
|
313
336
|
},
|
|
337
|
+
clippingRect: {
|
|
338
|
+
x: 0,
|
|
339
|
+
y: 0,
|
|
340
|
+
width: 0,
|
|
341
|
+
height: 0,
|
|
342
|
+
valid: false,
|
|
343
|
+
},
|
|
314
344
|
bufferNumFloats: 0,
|
|
315
345
|
bufferNumQuads: 0,
|
|
316
346
|
vertexBuffer: undefined,
|
|
@@ -410,22 +440,11 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
|
|
|
410
440
|
vertexBuffer = new Float32Array(neededLength * 2);
|
|
411
441
|
}
|
|
412
442
|
|
|
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;
|
|
443
|
+
const elementBounds = state.elementBounds;
|
|
444
|
+
if (!elementBounds.valid) {
|
|
445
|
+
this.setElementBoundsX(state);
|
|
446
|
+
this.setElementBoundsY(state);
|
|
447
|
+
elementBounds.valid = true;
|
|
429
448
|
}
|
|
430
449
|
|
|
431
450
|
// Return early if we're still viewing inside the established render window
|
|
@@ -434,10 +453,10 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
|
|
|
434
453
|
if (!forceFullLayoutCalc && renderWindow.valid) {
|
|
435
454
|
const rwScreen = renderWindow.screen;
|
|
436
455
|
if (
|
|
437
|
-
x + rwScreen.x1 <=
|
|
438
|
-
x + rwScreen.x2 >=
|
|
439
|
-
y - scrollY + rwScreen.y1 <=
|
|
440
|
-
y - scrollY + rwScreen.y2 >=
|
|
456
|
+
x + rwScreen.x1 <= elementBounds.x1 &&
|
|
457
|
+
x + rwScreen.x2 >= elementBounds.x2 &&
|
|
458
|
+
y - scrollY + rwScreen.y1 <= elementBounds.y1 &&
|
|
459
|
+
y - scrollY + rwScreen.y2 >= elementBounds.y2
|
|
441
460
|
) {
|
|
442
461
|
this.setStatus(state, 'loaded');
|
|
443
462
|
return;
|
|
@@ -451,14 +470,24 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
|
|
|
451
470
|
|
|
452
471
|
// Create a new renderWindow if needed
|
|
453
472
|
if (!renderWindow.valid) {
|
|
473
|
+
const isPossiblyOnScreen = boundsOverlap(
|
|
474
|
+
elementBounds,
|
|
475
|
+
this.rendererBounds,
|
|
476
|
+
);
|
|
477
|
+
|
|
478
|
+
if (!isPossiblyOnScreen) {
|
|
479
|
+
// If the element is not possibly on screen, we can skip the layout and rendering completely
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
|
|
454
483
|
setRenderWindow(
|
|
455
484
|
renderWindow,
|
|
456
485
|
x,
|
|
457
486
|
y,
|
|
458
487
|
scrollY,
|
|
459
488
|
lineHeight,
|
|
460
|
-
|
|
461
|
-
|
|
489
|
+
contain === 'both' ? elementBounds.y2 - elementBounds.y1 : 0,
|
|
490
|
+
elementBounds,
|
|
462
491
|
fontSizeRatio,
|
|
463
492
|
);
|
|
464
493
|
// console.log('newRenderWindow', renderWindow);
|
|
@@ -531,7 +560,7 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
|
|
|
531
560
|
override renderQuads(
|
|
532
561
|
state: SdfTextRendererState,
|
|
533
562
|
transform: Matrix3d,
|
|
534
|
-
clippingRect:
|
|
563
|
+
clippingRect: Readonly<RectWithValid>,
|
|
535
564
|
alpha: number,
|
|
536
565
|
): void {
|
|
537
566
|
if (!state.vertexBuffer) {
|
|
@@ -553,6 +582,7 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
|
|
|
553
582
|
vertexBuffer,
|
|
554
583
|
bufferUploaded,
|
|
555
584
|
trFontFace,
|
|
585
|
+
elementBounds,
|
|
556
586
|
} = state;
|
|
557
587
|
|
|
558
588
|
let { webGlBuffers } = state;
|
|
@@ -599,18 +629,21 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
|
|
|
599
629
|
}
|
|
600
630
|
|
|
601
631
|
assertTruthy(trFontFace);
|
|
602
|
-
|
|
603
632
|
if (scrollable && contain === 'both') {
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
633
|
+
assertTruthy(elementBounds.valid);
|
|
634
|
+
const elementRect = convertBoundToRect(elementBounds, tmpRect);
|
|
635
|
+
|
|
636
|
+
if (clippingRect.valid) {
|
|
637
|
+
state.clippingRect.valid = true;
|
|
638
|
+
clippingRect = intersectRect(
|
|
639
|
+
clippingRect,
|
|
640
|
+
elementRect,
|
|
641
|
+
state.clippingRect,
|
|
642
|
+
);
|
|
643
|
+
} else {
|
|
644
|
+
state.clippingRect.valid = true;
|
|
645
|
+
clippingRect = copyRect(elementRect, state.clippingRect);
|
|
646
|
+
}
|
|
614
647
|
}
|
|
615
648
|
|
|
616
649
|
const renderOp = new WebGlCoreRenderOp(
|
|
@@ -707,17 +740,6 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
|
|
|
707
740
|
) as SdfTrFontFace | undefined;
|
|
708
741
|
}
|
|
709
742
|
|
|
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
743
|
/**
|
|
722
744
|
* Invalidate the layout cache stored in the state. This will cause the text
|
|
723
745
|
* to be re-layed out on the next update.
|
|
@@ -728,12 +750,26 @@ export class SdfTextRenderer extends TextRenderer<SdfTextRendererState> {
|
|
|
728
750
|
* @param state
|
|
729
751
|
*/
|
|
730
752
|
protected invalidateLayoutCache(state: SdfTextRendererState): void {
|
|
731
|
-
state.visibleWindow.valid = false;
|
|
732
753
|
state.renderWindow.valid = false;
|
|
754
|
+
state.elementBounds.valid = false;
|
|
733
755
|
state.textH = undefined;
|
|
734
756
|
state.textW = undefined;
|
|
735
757
|
state.lineCache = [];
|
|
736
758
|
this.setStatus(state, 'loading');
|
|
737
759
|
this.scheduleUpdateState(state);
|
|
738
760
|
}
|
|
761
|
+
|
|
762
|
+
protected setElementBoundsX(state: SdfTextRendererState): void {
|
|
763
|
+
const { x, contain, width } = state.props;
|
|
764
|
+
const { elementBounds } = state;
|
|
765
|
+
elementBounds.x1 = x;
|
|
766
|
+
elementBounds.x2 = contain !== 'none' ? x + width : Infinity;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
protected setElementBoundsY(state: SdfTextRendererState): void {
|
|
770
|
+
const { y, contain, height } = state.props;
|
|
771
|
+
const { elementBounds } = state;
|
|
772
|
+
elementBounds.y1 = y;
|
|
773
|
+
elementBounds.y2 = contain === 'both' ? y + height : Infinity;
|
|
774
|
+
}
|
|
739
775
|
}
|
|
@@ -160,7 +160,8 @@ export function layoutText(
|
|
|
160
160
|
(maxLines === 0 || curLineIndex + 1 < maxLines) &&
|
|
161
161
|
(contain !== 'both' ||
|
|
162
162
|
scrollable ||
|
|
163
|
-
curY + vertexLineHeight +
|
|
163
|
+
curY + vertexLineHeight + trFontFace.maxCharHeight <=
|
|
164
|
+
vertexTruncateHeight);
|
|
164
165
|
const lineVertexW = nextLineWillFit
|
|
165
166
|
? vertexW
|
|
166
167
|
: vertexW - overflowSuffVertexWidth;
|
|
@@ -33,7 +33,10 @@ sdfData.chars.forEach((glyph) => {
|
|
|
33
33
|
describe('measureText', () => {
|
|
34
34
|
it('should measure text width', () => {
|
|
35
35
|
const PERIOD_WIDTH = 10.332;
|
|
36
|
-
const shaper = new SdfFontShaper(
|
|
36
|
+
const shaper = new SdfFontShaper(
|
|
37
|
+
sdfData as unknown as SdfFontData,
|
|
38
|
+
glyphMap,
|
|
39
|
+
);
|
|
37
40
|
expect(measureText('', { letterSpacing: 0 }, shaper)).toBe(0);
|
|
38
41
|
expect(measureText('.', { letterSpacing: 0 }, shaper)).toBe(PERIOD_WIDTH);
|
|
39
42
|
expect(measureText('..', { letterSpacing: 0 }, shaper)).toBeCloseTo(
|
|
@@ -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
|
}
|
|
@@ -19,6 +19,10 @@
|
|
|
19
19
|
|
|
20
20
|
import type { CoreTextureManager } from '../CoreTextureManager.js';
|
|
21
21
|
import { Texture, type TextureData } from './Texture.js';
|
|
22
|
+
import {
|
|
23
|
+
isCompressedTextureContainer,
|
|
24
|
+
loadCompressedTexture,
|
|
25
|
+
} from '../lib/textureCompression.js';
|
|
22
26
|
|
|
23
27
|
/**
|
|
24
28
|
* Properties of the {@link ImageTexture}
|
|
@@ -84,6 +88,11 @@ export class ImageTexture extends Texture {
|
|
|
84
88
|
};
|
|
85
89
|
}
|
|
86
90
|
|
|
91
|
+
// Handle compressed textures
|
|
92
|
+
if (isCompressedTextureContainer(src)) {
|
|
93
|
+
return loadCompressedTexture(src);
|
|
94
|
+
}
|
|
95
|
+
|
|
87
96
|
if (this.txManager.imageWorkerManager.imageWorkersEnabled) {
|
|
88
97
|
return await this.txManager.imageWorkerManager.getImage(
|
|
89
98
|
src,
|
|
@@ -35,6 +35,38 @@ export type TextureLoadedEventHandler = (
|
|
|
35
35
|
dimensions: Readonly<Dimensions>,
|
|
36
36
|
) => void;
|
|
37
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Represents compressed texture data.
|
|
40
|
+
*/
|
|
41
|
+
interface CompressedData {
|
|
42
|
+
/**
|
|
43
|
+
* GLenum spcifying compression format
|
|
44
|
+
*/
|
|
45
|
+
glInternalFormat: number;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* All mipmap levels
|
|
49
|
+
*/
|
|
50
|
+
mipmaps?: ArrayBuffer[];
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Supported container types ('pvr' or 'ktx').
|
|
54
|
+
*/
|
|
55
|
+
type: 'pvr' | 'ktx';
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* The width of the compressed texture in pixels. Defaults to 0.
|
|
59
|
+
*
|
|
60
|
+
* @default 0
|
|
61
|
+
*/
|
|
62
|
+
width: number;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The height of the compressed texture in pixels.
|
|
66
|
+
**/
|
|
67
|
+
height: number;
|
|
68
|
+
}
|
|
69
|
+
|
|
38
70
|
/**
|
|
39
71
|
* Event handler for when a Texture fails to load
|
|
40
72
|
*/
|
|
@@ -47,7 +79,7 @@ export interface TextureData {
|
|
|
47
79
|
/**
|
|
48
80
|
* The texture data
|
|
49
81
|
*/
|
|
50
|
-
data: ImageBitmap | ImageData | SubTextureProps | null;
|
|
82
|
+
data: ImageBitmap | ImageData | SubTextureProps | CompressedData | null;
|
|
51
83
|
/**
|
|
52
84
|
* Premultiply alpha when uploading texture data to the GPU
|
|
53
85
|
*
|