@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
|
@@ -254,14 +254,6 @@ export interface TrProps extends TrFontProps {
|
|
|
254
254
|
* Glyph layout information for WebGL rendering
|
|
255
255
|
*/
|
|
256
256
|
export interface GlyphLayout {
|
|
257
|
-
/**
|
|
258
|
-
* Unicode codepoint
|
|
259
|
-
*/
|
|
260
|
-
codepoint: number;
|
|
261
|
-
/**
|
|
262
|
-
* Glyph ID in the font atlas
|
|
263
|
-
*/
|
|
264
|
-
glyphId: number;
|
|
265
257
|
/**
|
|
266
258
|
* X position relative to text origin
|
|
267
259
|
*/
|
|
@@ -278,14 +270,6 @@ export interface GlyphLayout {
|
|
|
278
270
|
* Height of glyph in font units
|
|
279
271
|
*/
|
|
280
272
|
height: number;
|
|
281
|
-
/**
|
|
282
|
-
* X offset for glyph positioning
|
|
283
|
-
*/
|
|
284
|
-
xOffset: number;
|
|
285
|
-
/**
|
|
286
|
-
* Y offset for glyph positioning
|
|
287
|
-
*/
|
|
288
|
-
yOffset: number;
|
|
289
273
|
/**
|
|
290
274
|
* Atlas texture coordinates (normalized 0-1)
|
|
291
275
|
*/
|
|
@@ -300,9 +284,13 @@ export interface GlyphLayout {
|
|
|
300
284
|
*/
|
|
301
285
|
export interface TextLayout {
|
|
302
286
|
/**
|
|
303
|
-
*
|
|
287
|
+
* vertices for rendering quads in WebGL
|
|
304
288
|
*/
|
|
305
|
-
|
|
289
|
+
vertexBuffer: Float32Array;
|
|
290
|
+
/**
|
|
291
|
+
* glyph count in layout
|
|
292
|
+
*/
|
|
293
|
+
glyphCount: number;
|
|
306
294
|
/**
|
|
307
295
|
* Total text width
|
|
308
296
|
*/
|
|
@@ -327,6 +315,14 @@ export interface TextLayout {
|
|
|
327
315
|
* distanceRange used
|
|
328
316
|
*/
|
|
329
317
|
distanceRange: number;
|
|
318
|
+
/**
|
|
319
|
+
* number of lines that exceeded maxHeight and were truncated
|
|
320
|
+
*/
|
|
321
|
+
remainingLines: number;
|
|
322
|
+
/**
|
|
323
|
+
* Whether there is remaining text that exceeded maxHeight and was truncated
|
|
324
|
+
*/
|
|
325
|
+
hasRemainingText: boolean;
|
|
330
326
|
}
|
|
331
327
|
|
|
332
328
|
export interface FontLoadOptions {
|
|
@@ -379,6 +375,14 @@ export interface TextRenderProps {
|
|
|
379
375
|
parentHasRenderTexture: boolean;
|
|
380
376
|
framebufferDimensions: unknown;
|
|
381
377
|
stage: Stage;
|
|
378
|
+
/**
|
|
379
|
+
* Mutable wrapper ref used by the SDF renderer to cache the underlying
|
|
380
|
+
* WebGLBuffer across frames. The SDF renderer reads and writes the
|
|
381
|
+
* `.current` property so the node's ref box is updated in-place.
|
|
382
|
+
* CoreTextNode owns the ref and is responsible for calling
|
|
383
|
+
* deleteBuffer when the buffer is no longer needed.
|
|
384
|
+
*/
|
|
385
|
+
glBufferRef: { current: WebGLBuffer | null };
|
|
382
386
|
}
|
|
383
387
|
|
|
384
388
|
export interface TextRenderInfo {
|
|
@@ -394,15 +398,13 @@ export interface TextRenderer {
|
|
|
394
398
|
type: 'canvas' | 'sdf';
|
|
395
399
|
font: FontHandler;
|
|
396
400
|
renderText: (props: CoreTextNodeProps) => TextRenderInfo;
|
|
397
|
-
// Updated to accept layout data and return vertex buffer for performance
|
|
398
|
-
addQuads: (layout?: TextLayout) => Float32Array | null;
|
|
399
401
|
renderQuads: (
|
|
400
402
|
renderer: CoreRenderer,
|
|
401
403
|
layout: TextLayout,
|
|
402
|
-
vertexBuffer: Float32Array,
|
|
403
404
|
renderProps: TextRenderProps,
|
|
404
405
|
) => void;
|
|
405
406
|
init: (stage: Stage) => void;
|
|
407
|
+
clearCache: () => void;
|
|
406
408
|
}
|
|
407
409
|
|
|
408
410
|
/**
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* limitations under the License.
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import type {
|
|
20
|
+
import type { CoreTextNodeProps } from '../CoreTextNode.js';
|
|
21
21
|
|
|
22
22
|
const invisibleChars = /[\u200B\u200C\u200D\uFEFF\u00AD\u2060]/g;
|
|
23
23
|
|
|
@@ -97,3 +97,7 @@ export function tokenizeString(tokenRegex: RegExp, text: string): string[] {
|
|
|
97
97
|
final.pop();
|
|
98
98
|
return final.filter((word) => word != '');
|
|
99
99
|
}
|
|
100
|
+
|
|
101
|
+
export function getLayoutCacheKey(props: CoreTextNodeProps): string {
|
|
102
|
+
return `${props.text}-${props.fontFamily}-${props.fontSize}-${props.letterSpacing}-${props.lineHeight}-${props.maxHeight}-${props.maxWidth}-${props.textAlign}-${props.wordBreak}-${props.maxLines}-${props.overflowSuffix}`;
|
|
103
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
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 2023 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
|
+
|
|
20
|
+
// @vitest-environment happy-dom
|
|
21
|
+
|
|
22
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
23
|
+
import { RendererMain } from './Renderer.js';
|
|
24
|
+
import type { Platform } from '../core/platforms/Platform.js';
|
|
25
|
+
import type { Inspector } from './Inspector.js';
|
|
26
|
+
import type { CanvasRenderer } from '../core/renderers/canvas/CanvasRenderer.js';
|
|
27
|
+
import type { WebGlRenderer } from '../core/renderers/webgl/WebGlRenderer.js';
|
|
28
|
+
|
|
29
|
+
// Mock isProductionEnvironment so the Inspector gets initialized
|
|
30
|
+
vi.mock('../utils.js', async (importOriginal) => {
|
|
31
|
+
const actual = (await importOriginal()) as typeof import('../utils.js');
|
|
32
|
+
return {
|
|
33
|
+
...actual,
|
|
34
|
+
isProductionEnvironment: false,
|
|
35
|
+
};
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Mock Stage to avoid real WebGL/Canvas renderer setup
|
|
39
|
+
vi.mock('../core/Stage.js', () => {
|
|
40
|
+
const mockStage = {
|
|
41
|
+
root: {
|
|
42
|
+
id: 1,
|
|
43
|
+
children: [],
|
|
44
|
+
props: {},
|
|
45
|
+
on: vi.fn(),
|
|
46
|
+
off: vi.fn(),
|
|
47
|
+
emit: vi.fn(),
|
|
48
|
+
},
|
|
49
|
+
destroy: vi.fn(),
|
|
50
|
+
on: vi.fn(),
|
|
51
|
+
off: vi.fn(),
|
|
52
|
+
emit: vi.fn(),
|
|
53
|
+
txManager: { destroy: vi.fn() },
|
|
54
|
+
};
|
|
55
|
+
return {
|
|
56
|
+
Stage: vi.fn(() => mockStage),
|
|
57
|
+
};
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Minimal platform mock: returns a real <canvas> element so the Renderer
|
|
62
|
+
* can set its width/height and append it to the target.
|
|
63
|
+
*/
|
|
64
|
+
function makeMockPlatform() {
|
|
65
|
+
const canvas = document.createElement('canvas');
|
|
66
|
+
return vi.fn().mockReturnValue({ canvas, settings: {}, glw: null });
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Convenience: construct RendererMain with the minimum required settings. */
|
|
70
|
+
function makeRenderer(
|
|
71
|
+
target: HTMLElement,
|
|
72
|
+
extra: Partial<{
|
|
73
|
+
inspector: typeof Inspector | false;
|
|
74
|
+
}> = {},
|
|
75
|
+
) {
|
|
76
|
+
const MockPlatform = makeMockPlatform();
|
|
77
|
+
return new RendererMain(
|
|
78
|
+
{
|
|
79
|
+
appWidth: 1920,
|
|
80
|
+
appHeight: 1080,
|
|
81
|
+
inspector: extra.inspector ?? false,
|
|
82
|
+
platform: MockPlatform as unknown as typeof Platform,
|
|
83
|
+
renderEngine: {} as unknown as
|
|
84
|
+
| typeof CanvasRenderer
|
|
85
|
+
| typeof WebGlRenderer,
|
|
86
|
+
},
|
|
87
|
+
target,
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
describe('RendererMain.close()', () => {
|
|
92
|
+
let target: HTMLDivElement;
|
|
93
|
+
|
|
94
|
+
beforeEach(() => {
|
|
95
|
+
target = document.createElement('div');
|
|
96
|
+
document.body.appendChild(target);
|
|
97
|
+
vi.clearAllMocks();
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
afterEach(() => {
|
|
101
|
+
target.remove();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('should call inspector.destroy() when close() is called', () => {
|
|
105
|
+
const inspectorDestroy = vi.fn();
|
|
106
|
+
const MockInspector = vi.fn(() => ({ destroy: inspectorDestroy }));
|
|
107
|
+
|
|
108
|
+
const renderer = makeRenderer(target, {
|
|
109
|
+
inspector: MockInspector as unknown as typeof Inspector,
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
renderer.close();
|
|
113
|
+
|
|
114
|
+
expect(inspectorDestroy).toHaveBeenCalledOnce();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('should call stage.destroy() when close() is called', async () => {
|
|
118
|
+
const { Stage } = await import('../core/Stage.js');
|
|
119
|
+
const renderer = makeRenderer(target);
|
|
120
|
+
|
|
121
|
+
const mockStageInstance = vi.mocked(Stage).mock.results[0]?.value as {
|
|
122
|
+
destroy: ReturnType<typeof vi.fn>;
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
renderer.close();
|
|
126
|
+
|
|
127
|
+
expect(mockStageInstance?.destroy).toHaveBeenCalledOnce();
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('should remove the canvas from the DOM when close() is called', () => {
|
|
131
|
+
const renderer = makeRenderer(target);
|
|
132
|
+
const canvas = renderer.canvas;
|
|
133
|
+
|
|
134
|
+
expect(target.contains(canvas)).toBe(true);
|
|
135
|
+
|
|
136
|
+
renderer.close();
|
|
137
|
+
|
|
138
|
+
expect(document.contains(canvas)).toBe(false);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('should not throw when close() is called a second time', () => {
|
|
142
|
+
const MockInspector = vi.fn(() => ({ destroy: vi.fn() }));
|
|
143
|
+
|
|
144
|
+
const renderer = makeRenderer(target, {
|
|
145
|
+
inspector: MockInspector as unknown as typeof Inspector,
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
renderer.close();
|
|
149
|
+
|
|
150
|
+
// inspector is set to null after close(); the ?. guard must handle it
|
|
151
|
+
expect(() => renderer.close()).not.toThrow();
|
|
152
|
+
});
|
|
153
|
+
});
|
package/src/main-api/Renderer.ts
CHANGED
|
@@ -533,7 +533,7 @@ export class RendererMain extends EventEmitter {
|
|
|
533
533
|
boundsMargin: settings.boundsMargin || 0,
|
|
534
534
|
deviceLogicalPixelRatio: settings.deviceLogicalPixelRatio || 1,
|
|
535
535
|
devicePhysicalPixelRatio:
|
|
536
|
-
settings.devicePhysicalPixelRatio ||
|
|
536
|
+
settings.devicePhysicalPixelRatio || this.windowDevicePixelRatio() || 1,
|
|
537
537
|
clearColor: settings.clearColor ?? 0x00000000,
|
|
538
538
|
fpsUpdateInterval: settings.fpsUpdateInterval || 0,
|
|
539
539
|
enableClear: settings.enableClear ?? true,
|
|
@@ -582,8 +582,10 @@ export class RendererMain extends EventEmitter {
|
|
|
582
582
|
this.canvas.width = deviceLogicalWidth * devicePhysicalPixelRatio;
|
|
583
583
|
this.canvas.height = deviceLogicalHeight * devicePhysicalPixelRatio;
|
|
584
584
|
|
|
585
|
-
this.canvas.style
|
|
586
|
-
|
|
585
|
+
if (this.canvas.style) {
|
|
586
|
+
this.canvas.style.width = `${deviceLogicalWidth}px`;
|
|
587
|
+
this.canvas.style.height = `${deviceLogicalHeight}px`;
|
|
588
|
+
}
|
|
587
589
|
|
|
588
590
|
// Initialize the stage
|
|
589
591
|
this.stage = new Stage({
|
|
@@ -1027,4 +1029,32 @@ export class RendererMain extends EventEmitter {
|
|
|
1027
1029
|
this.stage.options.targetFPS = fps > 0 ? fps : 0;
|
|
1028
1030
|
this.stage.updateTargetFrameTime();
|
|
1029
1031
|
}
|
|
1032
|
+
|
|
1033
|
+
private windowDevicePixelRatio() {
|
|
1034
|
+
return typeof window !== 'undefined' ? window.devicePixelRatio : undefined;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
/**
|
|
1038
|
+
* Close and destroy the renderer, releasing all resources.
|
|
1039
|
+
*
|
|
1040
|
+
* @remarks
|
|
1041
|
+
* This method performs a full teardown of the renderer:
|
|
1042
|
+
* - Stops the platform render loop
|
|
1043
|
+
* - Destroys all scene nodes (including text node font resources)
|
|
1044
|
+
* - Releases all texture memory and GPU resources
|
|
1045
|
+
* - Terminates image worker threads
|
|
1046
|
+
* - Removes the canvas element from the target div
|
|
1047
|
+
* - Destroys the inspector if active
|
|
1048
|
+
*/
|
|
1049
|
+
close(): void {
|
|
1050
|
+
// Destroy the inspector first
|
|
1051
|
+
this.inspector?.destroy();
|
|
1052
|
+
this.inspector = null;
|
|
1053
|
+
|
|
1054
|
+
// Destroy the stage (stops loop, destroys nodes, releases textures/GPU)
|
|
1055
|
+
this.stage.destroy();
|
|
1056
|
+
|
|
1057
|
+
// Remove the canvas from the DOM
|
|
1058
|
+
this.canvas.remove();
|
|
1059
|
+
}
|
|
1030
1060
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"WebGlCoreShader.destroy.js","sourceRoot":"","sources":["../../../../../src/core/renderers/webgl/WebGlCoreShader.destroy.ts"],"names":[],"mappings":""}
|