@lightningjs/renderer 3.0.2 → 3.0.3
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 +56 -196
- package/dist/src/core/CoreNode.js +25 -4
- package/dist/src/core/CoreNode.js.map +1 -1
- package/dist/src/core/CoreTextNode.d.ts +9 -2
- package/dist/src/core/CoreTextNode.js +32 -11
- package/dist/src/core/CoreTextNode.js.map +1 -1
- package/dist/src/core/CoreTextureManager.d.ts +8 -0
- package/dist/src/core/CoreTextureManager.js +13 -1
- package/dist/src/core/CoreTextureManager.js.map +1 -1
- package/dist/src/core/Stage.d.ts +8 -0
- package/dist/src/core/Stage.js +23 -0
- package/dist/src/core/Stage.js.map +1 -1
- package/dist/src/core/TextureMemoryManager.d.ts +8 -13
- package/dist/src/core/TextureMemoryManager.js +22 -27
- package/dist/src/core/TextureMemoryManager.js.map +1 -1
- package/dist/src/core/lib/ImageWorker.d.ts +2 -2
- package/dist/src/core/lib/ImageWorker.js +31 -12
- package/dist/src/core/lib/ImageWorker.js.map +1 -1
- package/dist/src/core/lib/WebGlContextWrapper.d.ts +105 -56
- package/dist/src/core/lib/WebGlContextWrapper.js +164 -158
- package/dist/src/core/lib/WebGlContextWrapper.js.map +1 -1
- package/dist/src/core/lib/textureCompression.js +19 -10
- package/dist/src/core/lib/textureCompression.js.map +1 -1
- package/dist/src/core/lib/validateImageBitmap.d.ts +2 -1
- package/dist/src/core/lib/validateImageBitmap.js +4 -4
- package/dist/src/core/lib/validateImageBitmap.js.map +1 -1
- package/dist/src/core/platform.js +2 -2
- package/dist/src/core/platform.js.map +1 -1
- package/dist/src/core/platforms/Platform.d.ts +4 -0
- package/dist/src/core/platforms/Platform.js.map +1 -1
- package/dist/src/core/platforms/web/WebPlatform.d.ts +2 -0
- package/dist/src/core/platforms/web/WebPlatform.js +13 -0
- package/dist/src/core/platforms/web/WebPlatform.js.map +1 -1
- package/dist/src/core/renderers/CoreRenderer.d.ts +6 -0
- package/dist/src/core/renderers/CoreRenderer.js +8 -0
- package/dist/src/core/renderers/CoreRenderer.js.map +1 -1
- package/dist/src/core/renderers/canvas/CanvasRenderer.d.ts +1 -0
- package/dist/src/core/renderers/canvas/CanvasRenderer.js +5 -0
- package/dist/src/core/renderers/canvas/CanvasRenderer.js.map +1 -1
- package/dist/src/core/renderers/webgl/WebGlRenderOp.d.ts +45 -0
- package/dist/src/core/renderers/webgl/WebGlRenderOp.js +127 -0
- package/dist/src/core/renderers/webgl/WebGlRenderOp.js.map +1 -0
- package/dist/src/core/renderers/webgl/WebGlRenderer.d.ts +2 -0
- package/dist/src/core/renderers/webgl/WebGlRenderer.js +30 -22
- package/dist/src/core/renderers/webgl/WebGlRenderer.js.map +1 -1
- package/dist/src/core/text-rendering/CanvasFont.d.ts +14 -0
- package/dist/src/core/text-rendering/CanvasFont.js +120 -0
- package/dist/src/core/text-rendering/CanvasFont.js.map +1 -0
- package/dist/src/core/text-rendering/CanvasTextRenderer.d.ts +1 -2
- package/dist/src/core/text-rendering/CanvasTextRenderer.js +11 -19
- package/dist/src/core/text-rendering/CanvasTextRenderer.js.map +1 -1
- package/dist/src/core/text-rendering/CoreFont.d.ts +33 -0
- package/dist/src/core/text-rendering/CoreFont.js +48 -0
- package/dist/src/core/text-rendering/CoreFont.js.map +1 -0
- package/dist/src/core/text-rendering/FontManager.d.ts +11 -0
- package/dist/src/core/text-rendering/FontManager.js +41 -0
- package/dist/src/core/text-rendering/FontManager.js.map +1 -0
- package/dist/src/core/text-rendering/SdfFont.d.ts +29 -0
- package/dist/src/core/text-rendering/SdfFont.js +142 -0
- package/dist/src/core/text-rendering/SdfFont.js.map +1 -0
- package/dist/src/core/text-rendering/SdfTextRenderer.d.ts +2 -2
- package/dist/src/core/text-rendering/SdfTextRenderer.js +141 -132
- package/dist/src/core/text-rendering/SdfTextRenderer.js.map +1 -1
- package/dist/src/core/text-rendering/TextGenerator.d.ts +10 -0
- package/dist/src/core/text-rendering/TextGenerator.js +36 -0
- package/dist/src/core/text-rendering/TextGenerator.js.map +1 -0
- package/dist/src/core/text-rendering/TextRenderer.d.ts +26 -20
- package/dist/src/core/text-rendering/Utils.d.ts +2 -0
- package/dist/src/core/text-rendering/Utils.js +3 -0
- package/dist/src/core/text-rendering/Utils.js.map +1 -1
- package/dist/src/main-api/Renderer.d.ts +14 -0
- package/dist/src/main-api/Renderer.js +29 -3
- package/dist/src/main-api/Renderer.js.map +1 -1
- package/dist/tsconfig.dist.tsbuildinfo +1 -1
- package/package.json +2 -1
- package/src/core/CoreNode.ts +29 -4
- package/src/core/CoreTextNode.test.ts +237 -0
- package/src/core/CoreTextNode.ts +53 -33
- package/src/core/CoreTextureManager.ts +14 -2
- package/src/core/Stage.ts +29 -0
- package/src/core/TextureMemoryManager.test.ts +134 -0
- package/src/core/TextureMemoryManager.ts +23 -30
- package/src/core/platforms/Platform.ts +5 -0
- package/src/core/platforms/web/WebPlatform.ts +13 -0
- package/src/core/renderers/CoreRenderer.ts +10 -0
- package/src/core/renderers/canvas/CanvasRenderer.ts +6 -0
- package/src/core/renderers/webgl/WebGlRenderer.rtt.test.ts +551 -0
- package/src/core/renderers/webgl/WebGlRenderer.ts +38 -28
- package/src/core/text-rendering/CanvasTextRenderer.ts +13 -41
- package/src/core/text-rendering/SdfTextRenderer.ts +166 -163
- package/src/core/text-rendering/TextRenderer.ts +23 -21
- package/src/core/text-rendering/Utils.ts +5 -1
- package/src/main-api/Renderer.test.ts +153 -0
- package/src/main-api/Renderer.ts +33 -3
- package/dist/src/core/renderers/webgl/WebGlCoreShader.destroy.d.ts +0 -1
- package/dist/src/core/renderers/webgl/WebGlCoreShader.destroy.js +0 -2
- package/dist/src/core/renderers/webgl/WebGlCoreShader.destroy.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CoreFont.js","sourceRoot":"","sources":["../../../../src/core/text-rendering/CoreFont.ts"],"names":[],"mappings":"AAwBA,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAE5D,MAAM,CAAN,IAAY,SAKX;AALD,WAAY,SAAS;IACnB,+CAAO,CAAA;IACP,+CAAO,CAAA;IACP,6CAAM,CAAA;IACN,6CAAM,CAAA;AACR,CAAC,EALW,SAAS,KAAT,SAAS,QAKpB;AAOD;;GAEG;AACH,MAAM,OAAgB,QAAS,SAAQ,YAAY;IACvC,YAAY,GAAkC,MAAM,CAAC,MAAM,CACnE,IAAI,CAC2B,CAAC;IACxB,iBAAiB,GACzB,MAAM,CAAC,MAAM,CAAC,IAAI,CAA0C,CAAC;IAExD,YAAY,CAAe;IAC3B,KAAK,CAAY;IACjB,MAAM,CAAS;IACf,OAAO,CAAe;IAE7B,YAAY,YAA0B,EAAE,KAAoB;QAC1D,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,UAAU,CAAC;QAC/B,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC;QAC/B,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;IACnC,CAAC;IAES,QAAQ;QAChB,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC;QACvC,KAAK,IAAI,GAAG,IAAI,YAAY,EAAE,CAAC;YAC7B,YAAY,CAAC,GAAG,CAAE,CAAC,aAAa,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;YACnD,OAAO,YAAY,CAAC,GAAG,CAAC,CAAC;QAC3B,CAAC;QACD,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC,MAAM,CAAC;IAChC,CAAC;IAEM,OAAO,CAAC,IAAkB;QAC/B,IAAI,CAAC,YAAa,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC;IACrC,CAAC;IAEM,WAAW,CAAC,IAAkB;QACnC,IAAI,IAAI,CAAC,YAAa,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;YAChC,OAAO,IAAI,CAAC,YAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IAEM,OAAO;QACZ,OAAO,IAAI,CAAC,YAAY,CAAC;QACzB,OAAO,IAAI,CAAC,iBAAiB,CAAC;QAC9B,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;CAMF"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Stage } from '../Stage.js';
|
|
2
|
+
import type { CoreFont } from './CoreFont.js';
|
|
3
|
+
import type { FontLoadOptions, TextRenderer, TextRenderers } from './TextRenderer.js';
|
|
4
|
+
export declare class CoreFontManager {
|
|
5
|
+
private fonts;
|
|
6
|
+
private renderers;
|
|
7
|
+
constructor(stage: Stage, textRenderers: TextRenderer[]);
|
|
8
|
+
loadFont(type: TextRenderers, options: FontLoadOptions): void;
|
|
9
|
+
unloadFont(fontFamily: string): void;
|
|
10
|
+
getFont(fontFamily: string): CoreFont | undefined;
|
|
11
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export class CoreFontManager {
|
|
2
|
+
fonts = Object.create(null);
|
|
3
|
+
renderers = Object.create(null);
|
|
4
|
+
constructor(stage, textRenderers) {
|
|
5
|
+
for (let i = 0; i < textRenderers.length; i++) {
|
|
6
|
+
const renderer = textRenderers[i];
|
|
7
|
+
this.renderers[renderer.type] = renderer;
|
|
8
|
+
renderer.init(stage, this);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
loadFont(type, options) {
|
|
12
|
+
const targetRenderer = this.renderers[type];
|
|
13
|
+
if (targetRenderer === undefined) {
|
|
14
|
+
console.error('renderer type for this font does not exist');
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const font = targetRenderer.createFont(options);
|
|
18
|
+
if (font === undefined) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
font.load();
|
|
22
|
+
this.fonts[options.fontFamily] = font;
|
|
23
|
+
}
|
|
24
|
+
unloadFont(fontFamily) {
|
|
25
|
+
const targetFont = this.fonts[fontFamily];
|
|
26
|
+
if (targetFont === undefined) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
targetFont.destroy();
|
|
30
|
+
delete this.fonts[fontFamily];
|
|
31
|
+
}
|
|
32
|
+
getFont(fontFamily) {
|
|
33
|
+
const font = this.fonts[fontFamily];
|
|
34
|
+
if (font === undefined) {
|
|
35
|
+
console.warn('fontFamily not registered');
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
return font;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=FontManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FontManager.js","sourceRoot":"","sources":["../../../../src/core/text-rendering/FontManager.ts"],"names":[],"mappings":"AAQA,MAAM,OAAO,eAAe;IAClB,KAAK,GAA6B,MAAM,CAAC,MAAM,CAAC,IAAI,CAG3D,CAAC;IACM,SAAS,GAAiC,MAAM,CAAC,MAAM,CAC7D,IAAI,CAC2B,CAAC;IAElC,YAAY,KAAY,EAAE,aAA6B;QACrD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9C,MAAM,QAAQ,GAAG,aAAa,CAAC,CAAC,CAAE,CAAC;YACnC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC;YACzC,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,QAAQ,CAAC,IAAmB,EAAE,OAAwB;QACpD,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAC5C,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;YACjC,OAAO,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;YAC5D,OAAO;QACT,CAAC;QACD,MAAM,IAAI,GAAG,cAAc,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAChD,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,OAAO;QACT,CAAC;QACD,IAAI,CAAC,IAAI,EAAE,CAAC;QACZ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;IACxC,CAAC;IAED,UAAU,CAAC,UAAkB;QAC3B,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC1C,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YAC7B,OAAO;QACT,CAAC;QACD,UAAU,CAAC,OAAO,EAAE,CAAC;QACrB,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAChC,CAAC;IAED,OAAO,CAAC,UAAkB;QACxB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QACpC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,OAAO,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;YAC1C,OAAO;QACT,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Stage } from '../Stage.js';
|
|
2
|
+
import type { ImageTexture } from '../textures/ImageTexture.js';
|
|
3
|
+
import { CoreFont, type CoreFontProps } from './CoreFont.js';
|
|
4
|
+
import { type SdfFontData } from './SdfFontHandler.js';
|
|
5
|
+
import type { NormalizedFontMetrics, TextRenderer } from './TextRenderer.js';
|
|
6
|
+
export type SdfFontProps = CoreFontProps & {
|
|
7
|
+
atlasUrl: string;
|
|
8
|
+
atlasDataUrl: string;
|
|
9
|
+
};
|
|
10
|
+
export declare class SdfFont extends CoreFont {
|
|
11
|
+
private stage;
|
|
12
|
+
type: string;
|
|
13
|
+
atlasUrl: string;
|
|
14
|
+
atlasDataUrl: string;
|
|
15
|
+
atlasTexture?: ImageTexture;
|
|
16
|
+
private glyphMap?;
|
|
17
|
+
private kerningTable?;
|
|
18
|
+
private data?;
|
|
19
|
+
constructor(textRenderer: TextRenderer, props: SdfFontProps, stage: Stage);
|
|
20
|
+
load(): void;
|
|
21
|
+
private hardFail;
|
|
22
|
+
private processFontData;
|
|
23
|
+
measureText(text: string, letterSpacing: number): number;
|
|
24
|
+
getMetrics(fontSize: number): NormalizedFontMetrics;
|
|
25
|
+
getGlyph(codepoint: number): import("./SdfFontHandler.js").SdfGlyph | null;
|
|
26
|
+
getKerning(firstGlyph: number, secondGlyph: number): number;
|
|
27
|
+
getAtlas(): ImageTexture;
|
|
28
|
+
getData(): SdfFontData;
|
|
29
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* If not stated otherwise in this file or this component's LICENSE file the
|
|
3
|
+
* following copyright and licenses apply:
|
|
4
|
+
*
|
|
5
|
+
* Copyright 2025 Comcast Cable Communications Management, LLC.
|
|
6
|
+
*
|
|
7
|
+
* Licensed under the Apache License, Version 2.0 (the License);
|
|
8
|
+
* you may not use this file except in compliance with the License.
|
|
9
|
+
* You may obtain a copy of the License at
|
|
10
|
+
*
|
|
11
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
* See the License for the specific language governing permissions and
|
|
17
|
+
* limitations under the License.
|
|
18
|
+
*/
|
|
19
|
+
import { CoreFont, FontState } from './CoreFont.js';
|
|
20
|
+
import { buildGlyphMap, buildKerningTable, } from './SdfFontHandler.js';
|
|
21
|
+
import { normalizeFontMetrics } from './TextLayoutEngine.js';
|
|
22
|
+
import { hasZeroWidthSpace } from './Utils.js';
|
|
23
|
+
export class SdfFont extends CoreFont {
|
|
24
|
+
stage;
|
|
25
|
+
type = 'sdf';
|
|
26
|
+
atlasUrl;
|
|
27
|
+
atlasDataUrl;
|
|
28
|
+
atlasTexture;
|
|
29
|
+
glyphMap;
|
|
30
|
+
kerningTable;
|
|
31
|
+
data;
|
|
32
|
+
constructor(textRenderer, props, stage) {
|
|
33
|
+
super(textRenderer, props);
|
|
34
|
+
this.stage = stage;
|
|
35
|
+
this.atlasUrl = props.atlasUrl;
|
|
36
|
+
this.atlasDataUrl = props.atlasDataUrl;
|
|
37
|
+
}
|
|
38
|
+
load() {
|
|
39
|
+
new Promise(async () => {
|
|
40
|
+
const atlasData = await fetch(this.atlasDataUrl);
|
|
41
|
+
if (atlasData.ok === false) {
|
|
42
|
+
this.hardFail(`Failed to load font data: ${atlasData.statusText}`);
|
|
43
|
+
}
|
|
44
|
+
const fontData = (await atlasData.json());
|
|
45
|
+
if (fontData.chars === undefined) {
|
|
46
|
+
this.hardFail('Invalid SDF font data format');
|
|
47
|
+
}
|
|
48
|
+
const atlasTexture = this.stage.txManager.createTexture('ImageTexture', {
|
|
49
|
+
src: this.atlasUrl,
|
|
50
|
+
premultiplyAlpha: false,
|
|
51
|
+
});
|
|
52
|
+
atlasTexture.setRenderableOwner(this.family, true);
|
|
53
|
+
atlasTexture.preventCleanup = true;
|
|
54
|
+
atlasTexture.on('loaded', () => {
|
|
55
|
+
this.onLoaded();
|
|
56
|
+
});
|
|
57
|
+
atlasTexture.on('failed', (error) => {
|
|
58
|
+
console.error(`Failed to load SDF font: ${this.family}`, error);
|
|
59
|
+
this.emit('failed');
|
|
60
|
+
});
|
|
61
|
+
this.atlasTexture = atlasTexture;
|
|
62
|
+
this.processFontData(fontData);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
hardFail(message) {
|
|
66
|
+
this.state = FontState.Failed;
|
|
67
|
+
throw new Error(message);
|
|
68
|
+
}
|
|
69
|
+
processFontData(fontData) {
|
|
70
|
+
this.glyphMap = buildGlyphMap(fontData.chars);
|
|
71
|
+
this.kerningTable = buildKerningTable(fontData.kernings);
|
|
72
|
+
this.metrics = this.metrics ||
|
|
73
|
+
fontData.lightningMetrics || {
|
|
74
|
+
ascender: 800,
|
|
75
|
+
descender: -200,
|
|
76
|
+
lineGap: 200,
|
|
77
|
+
unitsPerEm: 1000,
|
|
78
|
+
};
|
|
79
|
+
this.data = fontData;
|
|
80
|
+
}
|
|
81
|
+
measureText(text, letterSpacing) {
|
|
82
|
+
if (text.length === 1) {
|
|
83
|
+
const char = text.charAt(0);
|
|
84
|
+
const codepoint = text.codePointAt(0);
|
|
85
|
+
if (codepoint === undefined)
|
|
86
|
+
return 0;
|
|
87
|
+
if (hasZeroWidthSpace(char) === true)
|
|
88
|
+
return 0;
|
|
89
|
+
const glyph = this.getGlyph(codepoint);
|
|
90
|
+
if (glyph === null)
|
|
91
|
+
return 0;
|
|
92
|
+
return glyph.xadvance + letterSpacing;
|
|
93
|
+
}
|
|
94
|
+
let width = 0;
|
|
95
|
+
let prevCodepoint = 0;
|
|
96
|
+
for (let i = 0; i < text.length; i++) {
|
|
97
|
+
const char = text.charAt(i);
|
|
98
|
+
const codepoint = text.codePointAt(i);
|
|
99
|
+
if (codepoint === undefined)
|
|
100
|
+
continue;
|
|
101
|
+
// Skip zero-width spaces in width calculations
|
|
102
|
+
if (hasZeroWidthSpace(char)) {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
const glyph = this.getGlyph(codepoint);
|
|
106
|
+
if (glyph === null)
|
|
107
|
+
continue;
|
|
108
|
+
let advance = glyph.xadvance;
|
|
109
|
+
// Add kerning if there's a previous character
|
|
110
|
+
if (prevCodepoint !== 0) {
|
|
111
|
+
const kerning = this.getKerning(prevCodepoint, codepoint);
|
|
112
|
+
advance += kerning;
|
|
113
|
+
}
|
|
114
|
+
width += advance + letterSpacing;
|
|
115
|
+
prevCodepoint = codepoint;
|
|
116
|
+
}
|
|
117
|
+
return width;
|
|
118
|
+
}
|
|
119
|
+
getMetrics(fontSize) {
|
|
120
|
+
let m = this.normalizedMetrics[fontSize];
|
|
121
|
+
if (m !== undefined) {
|
|
122
|
+
return m;
|
|
123
|
+
}
|
|
124
|
+
m = this.normalizedMetrics[fontSize] = normalizeFontMetrics(this.metrics, fontSize);
|
|
125
|
+
return m;
|
|
126
|
+
}
|
|
127
|
+
getGlyph(codepoint) {
|
|
128
|
+
const gm = this.glyphMap;
|
|
129
|
+
return gm[codepoint] || gm[63] || null;
|
|
130
|
+
}
|
|
131
|
+
getKerning(firstGlyph, secondGlyph) {
|
|
132
|
+
const seconds = this.kerningTable[secondGlyph];
|
|
133
|
+
return (seconds !== undefined && seconds[firstGlyph]) || 0;
|
|
134
|
+
}
|
|
135
|
+
getAtlas() {
|
|
136
|
+
return this.atlasTexture;
|
|
137
|
+
}
|
|
138
|
+
getData() {
|
|
139
|
+
return this.data;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=SdfFont.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SdfFont.js","sourceRoot":"","sources":["../../../../src/core/text-rendering/SdfFont.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,8 +10,8 @@ declare const SdfTextRenderer: {
|
|
|
10
10
|
type: "sdf";
|
|
11
11
|
font: FontHandler;
|
|
12
12
|
renderText: (props: CoreTextNodeProps) => TextRenderInfo;
|
|
13
|
-
|
|
14
|
-
renderQuads: (renderer: CoreRenderer, layout: TextLayout, vertexBuffer: Float32Array, renderProps: TextRenderProps) => void;
|
|
13
|
+
renderQuads: (renderer: CoreRenderer, layout: TextLayout, renderProps: TextRenderProps) => void;
|
|
15
14
|
init: (stage: Stage) => void;
|
|
15
|
+
clearCache: () => void;
|
|
16
16
|
};
|
|
17
17
|
export default SdfTextRenderer;
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* See the License for the specific language governing permissions and
|
|
17
17
|
* limitations under the License.
|
|
18
18
|
*/
|
|
19
|
-
import { hasZeroWidthSpace } from './Utils.js';
|
|
19
|
+
import { getLayoutCacheKey, hasZeroWidthSpace } from './Utils.js';
|
|
20
20
|
import * as SdfFontHandler from './SdfFontHandler.js';
|
|
21
21
|
import { WebGlRenderer } from '../renderers/webgl/WebGlRenderer.js';
|
|
22
22
|
import { SdfRenderOp } from '../renderers/webgl/SdfRenderOp.js';
|
|
@@ -38,6 +38,7 @@ const init = (stage) => {
|
|
|
38
38
|
sdfShader = stage.shManager.createShader('Sdf');
|
|
39
39
|
};
|
|
40
40
|
const font = SdfFontHandler;
|
|
41
|
+
const layoutCache = new Map();
|
|
41
42
|
/**
|
|
42
43
|
* SDF text renderer using MSDF/SDF fonts with WebGL
|
|
43
44
|
*
|
|
@@ -53,6 +54,17 @@ const renderText = (props) => {
|
|
|
53
54
|
height: 0,
|
|
54
55
|
};
|
|
55
56
|
}
|
|
57
|
+
const cacheKey = getLayoutCacheKey(props);
|
|
58
|
+
let layout = layoutCache.get(cacheKey);
|
|
59
|
+
if (layout !== undefined) {
|
|
60
|
+
return {
|
|
61
|
+
width: layout.width,
|
|
62
|
+
height: layout.height,
|
|
63
|
+
remainingLines: layout.remainingLines,
|
|
64
|
+
hasRemainingText: layout.hasRemainingText,
|
|
65
|
+
layout, // Cache layout for addQuads
|
|
66
|
+
};
|
|
67
|
+
}
|
|
56
68
|
// Get font cache for this font family
|
|
57
69
|
const fontData = SdfFontHandler.getFontData(props.fontFamily);
|
|
58
70
|
if (fontData === undefined) {
|
|
@@ -63,89 +75,27 @@ const renderText = (props) => {
|
|
|
63
75
|
};
|
|
64
76
|
}
|
|
65
77
|
// Calculate text layout and generate glyph data for caching
|
|
66
|
-
|
|
78
|
+
layout = generateTextLayout(props, fontData);
|
|
79
|
+
layoutCache.set(cacheKey, layout);
|
|
67
80
|
// For SDF renderer, ImageData is null since we render via WebGL
|
|
68
81
|
return {
|
|
69
|
-
remainingLines: 0,
|
|
70
|
-
hasRemainingText: false,
|
|
71
82
|
width: layout.width,
|
|
72
83
|
height: layout.height,
|
|
84
|
+
remainingLines: layout.remainingLines,
|
|
85
|
+
hasRemainingText: layout.hasRemainingText,
|
|
73
86
|
layout, // Cache layout for addQuads
|
|
74
87
|
};
|
|
75
88
|
};
|
|
76
|
-
/**
|
|
77
|
-
* Add quads for rendering using cached layout data
|
|
78
|
-
*/
|
|
79
|
-
const addQuads = (layout) => {
|
|
80
|
-
if (layout === undefined) {
|
|
81
|
-
return null; // No layout data available
|
|
82
|
-
}
|
|
83
|
-
const glyphs = layout.glyphs;
|
|
84
|
-
const glyphsLength = glyphs.length;
|
|
85
|
-
if (glyphsLength === 0) {
|
|
86
|
-
return null;
|
|
87
|
-
}
|
|
88
|
-
const vertexBuffer = new Float32Array(glyphsLength * VERTICES_PER_GLYPH * FLOATS_PER_VERTEX);
|
|
89
|
-
let bufferIndex = 0;
|
|
90
|
-
let glyphIndex = 0;
|
|
91
|
-
while (glyphIndex < glyphsLength) {
|
|
92
|
-
const glyph = glyphs[glyphIndex];
|
|
93
|
-
glyphIndex++;
|
|
94
|
-
if (glyph === undefined) {
|
|
95
|
-
continue;
|
|
96
|
-
}
|
|
97
|
-
const x1 = glyph.x;
|
|
98
|
-
const y1 = glyph.y;
|
|
99
|
-
const x2 = x1 + glyph.width;
|
|
100
|
-
const y2 = y1 + glyph.height;
|
|
101
|
-
const u1 = glyph.atlasX;
|
|
102
|
-
const v1 = glyph.atlasY;
|
|
103
|
-
const u2 = u1 + glyph.atlasWidth;
|
|
104
|
-
const v2 = v1 + glyph.atlasHeight;
|
|
105
|
-
// Triangle 1: Top-left, top-right, bottom-left
|
|
106
|
-
// Vertex 1: Top-left
|
|
107
|
-
vertexBuffer[bufferIndex++] = x1;
|
|
108
|
-
vertexBuffer[bufferIndex++] = y1;
|
|
109
|
-
vertexBuffer[bufferIndex++] = u1;
|
|
110
|
-
vertexBuffer[bufferIndex++] = v1;
|
|
111
|
-
// Vertex 2: Top-right
|
|
112
|
-
vertexBuffer[bufferIndex++] = x2;
|
|
113
|
-
vertexBuffer[bufferIndex++] = y1;
|
|
114
|
-
vertexBuffer[bufferIndex++] = u2;
|
|
115
|
-
vertexBuffer[bufferIndex++] = v1;
|
|
116
|
-
// Vertex 3: Bottom-left
|
|
117
|
-
vertexBuffer[bufferIndex++] = x1;
|
|
118
|
-
vertexBuffer[bufferIndex++] = y2;
|
|
119
|
-
vertexBuffer[bufferIndex++] = u1;
|
|
120
|
-
vertexBuffer[bufferIndex++] = v2;
|
|
121
|
-
// Triangle 2: Top-right, bottom-right, bottom-left
|
|
122
|
-
// Vertex 4: Top-right (duplicate)
|
|
123
|
-
vertexBuffer[bufferIndex++] = x2;
|
|
124
|
-
vertexBuffer[bufferIndex++] = y1;
|
|
125
|
-
vertexBuffer[bufferIndex++] = u2;
|
|
126
|
-
vertexBuffer[bufferIndex++] = v1;
|
|
127
|
-
// Vertex 5: Bottom-right
|
|
128
|
-
vertexBuffer[bufferIndex++] = x2;
|
|
129
|
-
vertexBuffer[bufferIndex++] = y2;
|
|
130
|
-
vertexBuffer[bufferIndex++] = u2;
|
|
131
|
-
vertexBuffer[bufferIndex++] = v2;
|
|
132
|
-
// Vertex 6: Bottom-left (duplicate)
|
|
133
|
-
vertexBuffer[bufferIndex++] = x1;
|
|
134
|
-
vertexBuffer[bufferIndex++] = y2;
|
|
135
|
-
vertexBuffer[bufferIndex++] = u1;
|
|
136
|
-
vertexBuffer[bufferIndex++] = v2;
|
|
137
|
-
}
|
|
138
|
-
return vertexBuffer;
|
|
139
|
-
};
|
|
140
89
|
/**
|
|
141
90
|
* Create and submit WebGL render operations for SDF text
|
|
142
91
|
* This is called from CoreTextNode during rendering to add SDF text to the render pipeline
|
|
143
92
|
*/
|
|
144
|
-
const renderQuads = (renderer, layout,
|
|
93
|
+
const renderQuads = (renderer, layout, renderProps) => {
|
|
145
94
|
const fontFamily = renderProps.fontFamily;
|
|
146
95
|
const color = renderProps.color;
|
|
147
96
|
const worldAlpha = renderProps.worldAlpha;
|
|
148
97
|
const globalTransform = renderProps.globalTransform;
|
|
98
|
+
const vertexBuffer = layout.vertexBuffer;
|
|
149
99
|
const atlasTexture = SdfFontHandler.getAtlas(fontFamily);
|
|
150
100
|
if (atlasTexture === null) {
|
|
151
101
|
console.warn(`SDF atlas texture not found for font: ${fontFamily}`);
|
|
@@ -154,53 +104,66 @@ const renderQuads = (renderer, layout, vertexBuffer, renderProps) => {
|
|
|
154
104
|
// We can safely assume this is a WebGL renderer else this wouldn't be called
|
|
155
105
|
const glw = renderer.glw;
|
|
156
106
|
const stride = 4 * Float32Array.BYTES_PER_ELEMENT;
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
107
|
+
/**
|
|
108
|
+
* Wraps a WebGLBuffer in a BufferCollection with the standard SDF vertex
|
|
109
|
+
* layout, creates and submits an SdfRenderOp. Called by both the cache-miss
|
|
110
|
+
* and cache-hit paths so attribute/op setup only exists in one place.
|
|
111
|
+
*/
|
|
112
|
+
const buildAndSubmitRenderOp = (gpuBuffer) => {
|
|
113
|
+
const webGlBuffers = new BufferCollection([
|
|
114
|
+
{
|
|
115
|
+
buffer: gpuBuffer,
|
|
116
|
+
attributes: {
|
|
117
|
+
a_position: {
|
|
118
|
+
name: 'a_position',
|
|
119
|
+
size: 2,
|
|
120
|
+
type: glw.FLOAT,
|
|
121
|
+
normalized: false,
|
|
122
|
+
stride,
|
|
123
|
+
offset: 0,
|
|
124
|
+
},
|
|
125
|
+
a_textureCoords: {
|
|
126
|
+
name: 'a_textureCoords',
|
|
127
|
+
size: 2,
|
|
128
|
+
type: glw.FLOAT,
|
|
129
|
+
normalized: false,
|
|
130
|
+
stride,
|
|
131
|
+
offset: 2 * Float32Array.BYTES_PER_ELEMENT,
|
|
132
|
+
},
|
|
181
133
|
},
|
|
182
134
|
},
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
135
|
+
]);
|
|
136
|
+
const renderOp = new SdfRenderOp(renderer, sdfShader, {
|
|
137
|
+
transform: globalTransform,
|
|
138
|
+
color: mergeColorAlpha(color, worldAlpha),
|
|
139
|
+
size: layout.fontScale,
|
|
140
|
+
distanceRange: layout.distanceRange,
|
|
141
|
+
}, webGlBuffers, worldAlpha,
|
|
142
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
143
|
+
renderProps.clippingRect, layout.width, layout.height, false, renderProps.parentHasRenderTexture,
|
|
144
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
145
|
+
renderProps.framebufferDimensions);
|
|
146
|
+
renderOp.addTexture(atlasTexture.ctxTexture);
|
|
147
|
+
renderOp.numQuads = layout.glyphCount;
|
|
148
|
+
renderer.addRenderOp(renderOp);
|
|
149
|
+
};
|
|
150
|
+
// Reuse the cached WebGLBuffer if one was provided — avoids a createBuffer
|
|
151
|
+
// call every frame on nodes whose text has not changed.
|
|
152
|
+
const glBufferRefBox = renderProps.glBufferRef;
|
|
153
|
+
if (glBufferRefBox.current === null) {
|
|
154
|
+
// Cache miss: allocate a new buffer, upload vertex data, then cache it.
|
|
155
|
+
const newBuffer = glw.createBuffer();
|
|
156
|
+
if (newBuffer === null) {
|
|
157
|
+
console.warn('Failed to create WebGL buffer for SDF text');
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
// Upload vertex data directly into the new buffer.
|
|
161
|
+
glw.arrayBufferData(newBuffer, vertexBuffer, glw.STATIC_DRAW);
|
|
162
|
+
// Write back into the ref box so the owning node can reuse it next frame.
|
|
163
|
+
glBufferRefBox.current = newBuffer;
|
|
188
164
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
transform: globalTransform,
|
|
192
|
-
color: mergeColorAlpha(color, worldAlpha),
|
|
193
|
-
size: layout.fontScale, // Use proper font scaling in shader
|
|
194
|
-
distanceRange: layout.distanceRange,
|
|
195
|
-
}, webGlBuffers, worldAlpha,
|
|
196
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
197
|
-
renderProps.clippingRect, layout.width, layout.height, false, renderProps.parentHasRenderTexture,
|
|
198
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
199
|
-
renderProps.framebufferDimensions);
|
|
200
|
-
// Add atlas texture and set quad count
|
|
201
|
-
renderOp.addTexture(atlasTexture.ctxTexture);
|
|
202
|
-
renderOp.numQuads = layout.glyphs.length;
|
|
203
|
-
renderer.addRenderOp(renderOp);
|
|
165
|
+
// Cache hit (or freshly allocated): build the render op and submit.
|
|
166
|
+
buildAndSubmitRenderOp(glBufferRefBox.current);
|
|
204
167
|
};
|
|
205
168
|
/**
|
|
206
169
|
* Generate complete text layout with glyph positioning for caching
|
|
@@ -222,7 +185,23 @@ const generateTextLayout = (props, fontCache) => {
|
|
|
222
185
|
const maxHeight = props.maxHeight;
|
|
223
186
|
const [lines, remainingLines, hasRemainingText, bareLineHeight, lineHeightPx, effectiveWidth, effectiveHeight,] = mapTextLayout(SdfFontHandler.measureText, metrics, props.text, props.textAlign, fontFamily, lineHeight, props.overflowSuffix, props.wordBreak, letterSpacing, props.maxLines, maxWidth, maxHeight);
|
|
224
187
|
const lineAmount = lines.length;
|
|
225
|
-
|
|
188
|
+
let bufferIndex = 0;
|
|
189
|
+
let glyphCount = 0;
|
|
190
|
+
// Count total glyphs (excluding spaces) for buffer allocation
|
|
191
|
+
for (let i = 0; i < lineAmount; i++) {
|
|
192
|
+
const textLine = lines[i][0];
|
|
193
|
+
for (const char of textLine) {
|
|
194
|
+
if (hasZeroWidthSpace(char) === true) {
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
const codepoint = char.codePointAt(0);
|
|
198
|
+
if (codepoint === undefined) {
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
glyphCount++;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
const vertexBuffer = new Float32Array(glyphCount * VERTICES_PER_GLYPH * FLOATS_PER_VERTEX);
|
|
226
205
|
let currentX = 0;
|
|
227
206
|
let currentY = 0;
|
|
228
207
|
for (let i = 0; i < lineAmount; i++) {
|
|
@@ -253,22 +232,46 @@ const generateTextLayout = (props, fontCache) => {
|
|
|
253
232
|
}
|
|
254
233
|
// Apply pair kerning before placing this glyph.
|
|
255
234
|
currentX += kerning;
|
|
256
|
-
|
|
257
|
-
const
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
235
|
+
const x1 = currentX + glyph.xoffset;
|
|
236
|
+
const y1 = currentY + glyph.yoffset;
|
|
237
|
+
const x2 = x1 + glyph.width;
|
|
238
|
+
const y2 = y1 + glyph.height;
|
|
239
|
+
const u1 = glyph.x / atlasWidth;
|
|
240
|
+
const v1 = glyph.y / atlasHeight;
|
|
241
|
+
const u2 = u1 + glyph.width / atlasWidth;
|
|
242
|
+
const v2 = v1 + glyph.height / atlasHeight;
|
|
243
|
+
// Triangle 1: Top-left, top-right, bottom-left
|
|
244
|
+
// Vertex 1: Top-left
|
|
245
|
+
vertexBuffer[bufferIndex++] = x1;
|
|
246
|
+
vertexBuffer[bufferIndex++] = y1;
|
|
247
|
+
vertexBuffer[bufferIndex++] = u1;
|
|
248
|
+
vertexBuffer[bufferIndex++] = v1;
|
|
249
|
+
// Vertex 2: Top-right
|
|
250
|
+
vertexBuffer[bufferIndex++] = x2;
|
|
251
|
+
vertexBuffer[bufferIndex++] = y1;
|
|
252
|
+
vertexBuffer[bufferIndex++] = u2;
|
|
253
|
+
vertexBuffer[bufferIndex++] = v1;
|
|
254
|
+
// Vertex 3: Bottom-left
|
|
255
|
+
vertexBuffer[bufferIndex++] = x1;
|
|
256
|
+
vertexBuffer[bufferIndex++] = y2;
|
|
257
|
+
vertexBuffer[bufferIndex++] = u1;
|
|
258
|
+
vertexBuffer[bufferIndex++] = v2;
|
|
259
|
+
// Triangle 2: Top-right, bottom-right, bottom-left
|
|
260
|
+
// Vertex 4: Top-right (duplicate)
|
|
261
|
+
vertexBuffer[bufferIndex++] = x2;
|
|
262
|
+
vertexBuffer[bufferIndex++] = y1;
|
|
263
|
+
vertexBuffer[bufferIndex++] = u2;
|
|
264
|
+
vertexBuffer[bufferIndex++] = v1;
|
|
265
|
+
// Vertex 5: Bottom-right
|
|
266
|
+
vertexBuffer[bufferIndex++] = x2;
|
|
267
|
+
vertexBuffer[bufferIndex++] = y2;
|
|
268
|
+
vertexBuffer[bufferIndex++] = u2;
|
|
269
|
+
vertexBuffer[bufferIndex++] = v2;
|
|
270
|
+
// Vertex 6: Bottom-left (duplicate)
|
|
271
|
+
vertexBuffer[bufferIndex++] = x1;
|
|
272
|
+
vertexBuffer[bufferIndex++] = y2;
|
|
273
|
+
vertexBuffer[bufferIndex++] = u1;
|
|
274
|
+
vertexBuffer[bufferIndex++] = v2;
|
|
272
275
|
// Advance position with letter spacing (in design units)
|
|
273
276
|
currentX += glyph.xadvance + letterSpacing;
|
|
274
277
|
prevGlyphId = glyph.id;
|
|
@@ -277,15 +280,21 @@ const generateTextLayout = (props, fontCache) => {
|
|
|
277
280
|
}
|
|
278
281
|
// Convert final dimensions to pixel space for the layout
|
|
279
282
|
return {
|
|
280
|
-
|
|
283
|
+
vertexBuffer,
|
|
284
|
+
glyphCount,
|
|
281
285
|
distanceRange: fontScale * fontData.distanceField.distanceRange,
|
|
282
286
|
width: effectiveWidth * fontScale,
|
|
283
287
|
height: effectiveHeight,
|
|
284
288
|
fontScale: fontScale,
|
|
285
289
|
lineHeight: lineHeightPx,
|
|
286
290
|
fontFamily,
|
|
291
|
+
remainingLines,
|
|
292
|
+
hasRemainingText,
|
|
287
293
|
};
|
|
288
294
|
};
|
|
295
|
+
const clearCache = () => {
|
|
296
|
+
layoutCache.clear();
|
|
297
|
+
};
|
|
289
298
|
/**
|
|
290
299
|
* SDF Text Renderer - implements TextRenderer interface
|
|
291
300
|
*/
|
|
@@ -293,9 +302,9 @@ const SdfTextRenderer = {
|
|
|
293
302
|
type,
|
|
294
303
|
font,
|
|
295
304
|
renderText,
|
|
296
|
-
addQuads,
|
|
297
305
|
renderQuads,
|
|
298
306
|
init,
|
|
307
|
+
clearCache,
|
|
299
308
|
};
|
|
300
309
|
export default SdfTextRenderer;
|
|
301
310
|
//# sourceMappingURL=SdfTextRenderer.js.map
|