@lightningjs/renderer 0.6.1 → 0.7.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.
Files changed (189) hide show
  1. package/dist/src/common/CommonTypes.d.ts +8 -0
  2. package/dist/src/core/CoreNode.js +45 -16
  3. package/dist/src/core/CoreNode.js.map +1 -1
  4. package/dist/src/core/CoreTextNode.d.ts +10 -0
  5. package/dist/src/core/CoreTextNode.js +45 -0
  6. package/dist/src/core/CoreTextNode.js.map +1 -1
  7. package/dist/src/core/CoreTextureManager.d.ts +3 -1
  8. package/dist/src/core/CoreTextureManager.js +4 -1
  9. package/dist/src/core/CoreTextureManager.js.map +1 -1
  10. package/dist/src/core/Stage.d.ts +6 -0
  11. package/dist/src/core/Stage.js +12 -3
  12. package/dist/src/core/Stage.js.map +1 -1
  13. package/dist/src/core/lib/ImageWorker.d.ts +16 -0
  14. package/dist/src/core/lib/ImageWorker.js +111 -0
  15. package/dist/src/core/lib/ImageWorker.js.map +1 -0
  16. package/dist/src/core/lib/WebGlContextWrapper.d.ts +4 -0
  17. package/dist/src/core/lib/WebGlContextWrapper.js +7 -2
  18. package/dist/src/core/lib/WebGlContextWrapper.js.map +1 -1
  19. package/dist/src/core/renderers/webgl/WebGlCoreCtxSubTexture.d.ts +2 -1
  20. package/dist/src/core/renderers/webgl/WebGlCoreCtxSubTexture.js +2 -2
  21. package/dist/src/core/renderers/webgl/WebGlCoreCtxSubTexture.js.map +1 -1
  22. package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.d.ts +3 -2
  23. package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.js +23 -21
  24. package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.js.map +1 -1
  25. package/dist/src/core/renderers/webgl/WebGlCoreRenderOp.d.ts +3 -2
  26. package/dist/src/core/renderers/webgl/WebGlCoreRenderOp.js +9 -13
  27. package/dist/src/core/renderers/webgl/WebGlCoreRenderOp.js.map +1 -1
  28. package/dist/src/core/renderers/webgl/WebGlCoreRenderer.d.ts +4 -1
  29. package/dist/src/core/renderers/webgl/WebGlCoreRenderer.js +25 -24
  30. package/dist/src/core/renderers/webgl/WebGlCoreRenderer.js.map +1 -1
  31. package/dist/src/core/renderers/webgl/WebGlCoreShader.d.ts +2 -1
  32. package/dist/src/core/renderers/webgl/WebGlCoreShader.js +24 -24
  33. package/dist/src/core/renderers/webgl/WebGlCoreShader.js.map +1 -1
  34. package/dist/src/core/renderers/webgl/internal/RendererUtils.d.ts +8 -5
  35. package/dist/src/core/renderers/webgl/internal/RendererUtils.js +11 -13
  36. package/dist/src/core/renderers/webgl/internal/RendererUtils.js.map +1 -1
  37. package/dist/src/core/renderers/webgl/internal/ShaderUtils.d.ts +3 -2
  38. package/dist/src/core/renderers/webgl/internal/ShaderUtils.js +15 -15
  39. package/dist/src/core/renderers/webgl/internal/ShaderUtils.js.map +1 -1
  40. package/dist/src/core/renderers/webgl/shaders/DefaultShader.js +3 -6
  41. package/dist/src/core/renderers/webgl/shaders/DefaultShader.js.map +1 -1
  42. package/dist/src/core/renderers/webgl/shaders/DefaultShaderBatched.js +3 -3
  43. package/dist/src/core/renderers/webgl/shaders/DefaultShaderBatched.js.map +1 -1
  44. package/dist/src/core/renderers/webgl/shaders/DynamicShader.d.ts +1 -0
  45. package/dist/src/core/renderers/webgl/shaders/DynamicShader.js +32 -12
  46. package/dist/src/core/renderers/webgl/shaders/DynamicShader.js.map +1 -1
  47. package/dist/src/core/renderers/webgl/shaders/RoundedRectangle.js +3 -3
  48. package/dist/src/core/renderers/webgl/shaders/RoundedRectangle.js.map +1 -1
  49. package/dist/src/core/renderers/webgl/shaders/SdfShader.js +3 -3
  50. package/dist/src/core/renderers/webgl/shaders/SdfShader.js.map +1 -1
  51. package/dist/src/core/renderers/webgl/shaders/effects/BorderEffect.js +1 -1
  52. package/dist/src/core/renderers/webgl/shaders/effects/GrayscaleEffect.d.ts +14 -1
  53. package/dist/src/core/renderers/webgl/shaders/effects/GrayscaleEffect.js +15 -5
  54. package/dist/src/core/renderers/webgl/shaders/effects/GrayscaleEffect.js.map +1 -1
  55. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.js +3 -3
  56. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.js.map +1 -1
  57. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.d.ts +2 -1
  58. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.js +4 -2
  59. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.js.map +1 -1
  60. package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.js +25 -0
  61. package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.js.map +1 -1
  62. package/dist/src/core/text-rendering/renderers/LightningTextTextureRenderer.d.ts +1 -1
  63. package/dist/src/core/text-rendering/renderers/LightningTextTextureRenderer.js +6 -6
  64. package/dist/src/core/text-rendering/renderers/LightningTextTextureRenderer.js.map +1 -1
  65. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.d.ts +3 -2
  66. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js +82 -50
  67. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js.map +1 -1
  68. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/findNearestMultiple.d.ts +8 -0
  69. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/findNearestMultiple.js +29 -0
  70. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/findNearestMultiple.js.map +1 -0
  71. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/getStartConditions.d.ts +4 -3
  72. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/getStartConditions.js +15 -11
  73. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/getStartConditions.js.map +1 -1
  74. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.d.ts +3 -2
  75. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.js +30 -26
  76. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.js.map +1 -1
  77. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/SdfBufferHelper.d.ts +19 -0
  78. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/SdfBufferHelper.js +84 -0
  79. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/SdfBufferHelper.js.map +1 -0
  80. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutLine.d.ts +8 -0
  81. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutLine.js +40 -0
  82. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutLine.js.map +1 -0
  83. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutText2.d.ts +2 -0
  84. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutText2.js +41 -0
  85. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutText2.js.map +1 -0
  86. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/utils.d.ts +1 -0
  87. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/utils.js +4 -0
  88. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/utils.js.map +1 -0
  89. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2.d.ts +1 -0
  90. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2.js +2 -0
  91. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2.js.map +1 -0
  92. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/roundUpToMultiple.d.ts +9 -0
  93. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/roundUpToMultiple.js +32 -0
  94. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/roundUpToMultiple.js.map +1 -0
  95. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.d.ts +26 -0
  96. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.js +70 -0
  97. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.js.map +1 -0
  98. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/util.d.ts +16 -0
  99. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/util.js +39 -0
  100. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/util.js.map +1 -0
  101. package/dist/src/core/text-rendering/renderers/TextRenderer.d.ts +50 -0
  102. package/dist/src/core/text-rendering/renderers/TextRenderer.js +19 -0
  103. package/dist/src/core/text-rendering/renderers/TextRenderer.js.map +1 -1
  104. package/dist/src/core/textures/ImageTexture.js +14 -9
  105. package/dist/src/core/textures/ImageTexture.js.map +1 -1
  106. package/dist/src/core/utils.d.ts +1 -6
  107. package/dist/src/core/utils.js +3 -2
  108. package/dist/src/core/utils.js.map +1 -1
  109. package/dist/src/main-api/ICoreDriver.d.ts +2 -1
  110. package/dist/src/main-api/RendererMain.d.ts +25 -0
  111. package/dist/src/main-api/RendererMain.js +14 -5
  112. package/dist/src/main-api/RendererMain.js.map +1 -1
  113. package/dist/src/render-drivers/main/MainCoreDriver.d.ts +2 -1
  114. package/dist/src/render-drivers/main/MainCoreDriver.js +6 -4
  115. package/dist/src/render-drivers/main/MainCoreDriver.js.map +1 -1
  116. package/dist/src/render-drivers/main/MainOnlyTextNode.d.ts +10 -0
  117. package/dist/src/render-drivers/main/MainOnlyTextNode.js +45 -0
  118. package/dist/src/render-drivers/main/MainOnlyTextNode.js.map +1 -1
  119. package/dist/src/render-drivers/threadx/TextNodeStruct.d.ts +10 -0
  120. package/dist/src/render-drivers/threadx/TextNodeStruct.js +45 -0
  121. package/dist/src/render-drivers/threadx/TextNodeStruct.js.map +1 -1
  122. package/dist/src/render-drivers/threadx/ThreadXCoreDriver.d.ts +2 -1
  123. package/dist/src/render-drivers/threadx/ThreadXCoreDriver.js +8 -1
  124. package/dist/src/render-drivers/threadx/ThreadXCoreDriver.js.map +1 -1
  125. package/dist/src/render-drivers/threadx/ThreadXMainTextNode.d.ts +5 -0
  126. package/dist/src/render-drivers/threadx/ThreadXMainTextNode.js +5 -0
  127. package/dist/src/render-drivers/threadx/ThreadXMainTextNode.js.map +1 -1
  128. package/dist/src/render-drivers/threadx/ThreadXRendererMessage.d.ts +4 -1
  129. package/dist/src/render-drivers/threadx/ThreadXRendererMessage.js.map +1 -1
  130. package/dist/src/render-drivers/threadx/worker/ThreadXRendererTextNode.d.ts +5 -0
  131. package/dist/src/render-drivers/threadx/worker/ThreadXRendererTextNode.js +10 -0
  132. package/dist/src/render-drivers/threadx/worker/ThreadXRendererTextNode.js.map +1 -1
  133. package/dist/src/render-drivers/threadx/worker/renderer.js +5 -3
  134. package/dist/src/render-drivers/threadx/worker/renderer.js.map +1 -1
  135. package/dist/src/utils.d.ts +2 -1
  136. package/dist/src/utils.js +22 -3
  137. package/dist/src/utils.js.map +1 -1
  138. package/dist/tsconfig.dist.tsbuildinfo +1 -1
  139. package/package.json +3 -2
  140. package/src/common/CommonTypes.ts +9 -0
  141. package/src/core/CoreNode.ts +67 -34
  142. package/src/core/CoreTextNode.ts +56 -0
  143. package/src/core/CoreTextureManager.ts +4 -2
  144. package/src/core/Stage.ts +32 -3
  145. package/src/core/lib/ContextSpy.ts +41 -0
  146. package/src/core/lib/ImageWorker.ts +124 -0
  147. package/src/core/lib/WebGlContextWrapper.ts +965 -0
  148. package/src/core/renderers/webgl/WebGlCoreCtxSubTexture.ts +3 -2
  149. package/src/core/renderers/webgl/WebGlCoreCtxTexture.ts +29 -28
  150. package/src/core/renderers/webgl/WebGlCoreRenderOp.ts +10 -14
  151. package/src/core/renderers/webgl/WebGlCoreRenderer.ts +26 -24
  152. package/src/core/renderers/webgl/WebGlCoreShader.ts +34 -25
  153. package/src/core/renderers/webgl/internal/RendererUtils.ts +13 -16
  154. package/src/core/renderers/webgl/internal/ShaderUtils.ts +16 -15
  155. package/src/core/renderers/webgl/shaders/DefaultShader.ts +3 -7
  156. package/src/core/renderers/webgl/shaders/DefaultShaderBatched.ts +3 -3
  157. package/src/core/renderers/webgl/shaders/DynamicShader.ts +42 -14
  158. package/src/core/renderers/webgl/shaders/RoundedRectangle.ts +3 -3
  159. package/src/core/renderers/webgl/shaders/SdfShader.ts +3 -3
  160. package/src/core/renderers/webgl/shaders/effects/BorderEffect.ts +1 -1
  161. package/src/core/renderers/webgl/shaders/effects/GrayscaleEffect.ts +35 -5
  162. package/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.ts +3 -3
  163. package/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.test.ts +9 -3
  164. package/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.ts +4 -2
  165. package/src/core/text-rendering/renderers/CanvasTextRenderer.ts +25 -0
  166. package/src/core/text-rendering/renderers/LightningTextTextureRenderer.ts +7 -7
  167. package/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.ts +115 -63
  168. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/getStartConditions.ts +26 -18
  169. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.ts +40 -28
  170. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/measureText.test.ts +6 -1
  171. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.test.ts +205 -0
  172. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/{makeRenderWindow.ts → setRenderWindow.ts} +50 -21
  173. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/util.ts +40 -0
  174. package/src/core/text-rendering/renderers/TextRenderer.ts +73 -0
  175. package/src/core/textures/ImageTexture.ts +17 -9
  176. package/src/core/utils.ts +87 -85
  177. package/src/env.d.ts +7 -0
  178. package/src/main-api/ICoreDriver.ts +2 -1
  179. package/src/main-api/RendererMain.ts +43 -5
  180. package/src/render-drivers/main/MainCoreDriver.ts +8 -5
  181. package/src/render-drivers/main/MainOnlyTextNode.ts +55 -1
  182. package/src/render-drivers/threadx/TextNodeStruct.ts +45 -0
  183. package/src/render-drivers/threadx/ThreadXCoreDriver.ts +10 -2
  184. package/src/render-drivers/threadx/ThreadXMainTextNode.ts +10 -0
  185. package/src/render-drivers/threadx/ThreadXRendererMessage.ts +5 -1
  186. package/src/render-drivers/threadx/worker/ThreadXRendererTextNode.ts +15 -0
  187. package/src/render-drivers/threadx/worker/renderer.ts +6 -4
  188. package/src/utils.ts +25 -4
  189. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/makeRenderWindow.test.ts +0 -136
@@ -211,6 +211,33 @@ export interface RendererMainSettings {
211
211
  * @defaultValue `0` (disabled)
212
212
  */
213
213
  fpsUpdateInterval?: number;
214
+
215
+ /**
216
+ * Include context call (i.e. WebGL) information in FPS updates
217
+ *
218
+ * @remarks
219
+ * When enabled the number of calls to each context method over the
220
+ * `fpsUpdateInterval` will be included in the FPS update payload's
221
+ * `contextSpyData` property.
222
+ *
223
+ * Enabling the context spy has a serious impact on performance so only use it
224
+ * when you need to extract context call information.
225
+ *
226
+ * @defaultValue `false` (disabled)
227
+ */
228
+ enableContextSpy?: boolean;
229
+
230
+ /**
231
+ * Number or Image Workers to use
232
+ *
233
+ * @remarks
234
+ * On devices with multiple cores, this can be used to improve image loading
235
+ * as well as reduce the impact of image loading on the main thread.
236
+ * Set to 0 to disable image workers.
237
+ *
238
+ * @defaultValue `2`
239
+ */
240
+ numImageWorkers?: number;
214
241
  }
215
242
 
216
243
  /**
@@ -278,6 +305,9 @@ export class RendererMain extends EventEmitter {
278
305
  settings.experimental_FinalizationRegistryTextureUsageTracker ?? false,
279
306
  textureCleanupOptions: settings.textureCleanupOptions || {},
280
307
  fpsUpdateInterval: settings.fpsUpdateInterval || 0,
308
+ numImageWorkers:
309
+ settings.numImageWorkers !== undefined ? settings.numImageWorkers : 2,
310
+ enableContextSpy: settings.enableContextSpy ?? false,
281
311
  };
282
312
  this.settings = resolvedSettings;
283
313
 
@@ -335,8 +365,8 @@ export class RendererMain extends EventEmitter {
335
365
  this.nodes.delete(node.id);
336
366
  };
337
367
 
338
- driver.onFpsUpdate = (fps) => {
339
- this.emit('fpsUpdate', fps);
368
+ driver.onFpsUpdate = (fpsData) => {
369
+ this.emit('fpsUpdate', fpsData);
340
370
  };
341
371
 
342
372
  targetEl.appendChild(canvas);
@@ -389,11 +419,12 @@ export class RendererMain extends EventEmitter {
389
419
  * @returns
390
420
  */
391
421
  createTextNode(props: Partial<ITextNodeWritableProps>): ITextNode {
392
- return this.driver.createTextNode({
422
+ const fontSize = props.fontSize ?? 16;
423
+ const data = {
393
424
  ...this.resolveNodeDefaults(props),
394
425
  text: props.text ?? '',
395
426
  textRendererOverride: props.textRendererOverride ?? null,
396
- fontSize: props.fontSize ?? 16,
427
+ fontSize,
397
428
  fontFamily: props.fontFamily ?? 'sans-serif',
398
429
  fontStyle: props.fontStyle ?? 'normal',
399
430
  fontWeight: props.fontWeight ?? 'normal',
@@ -404,8 +435,15 @@ export class RendererMain extends EventEmitter {
404
435
  scrollY: props.scrollY ?? 0,
405
436
  offsetY: props.offsetY ?? 0,
406
437
  letterSpacing: props.letterSpacing ?? 0,
438
+ lineHeight: props.lineHeight ?? fontSize,
439
+ maxLines: props.maxLines ?? 0,
440
+ textBaseline: props.textBaseline ?? 'alphabetic',
441
+ verticalAlign: props.verticalAlign ?? 'top',
442
+ overflowSuffix: props.overflowSuffix ?? '...',
407
443
  debug: props.debug ?? {},
408
- });
444
+ };
445
+
446
+ return this.driver.createTextNode(data);
409
447
  }
410
448
 
411
449
  /**
@@ -25,13 +25,14 @@ import type {
25
25
  ITextNodeWritableProps,
26
26
  } from '../../main-api/INode.js';
27
27
  import { MainOnlyNode, getNewId } from './MainOnlyNode.js';
28
- import { Stage } from '../../core/Stage.js';
28
+ import { Stage, type StageFpsUpdateHandler } from '../../core/Stage.js';
29
29
  import type {
30
30
  RendererMain,
31
31
  RendererMainSettings,
32
32
  } from '../../main-api/RendererMain.js';
33
33
  import { MainOnlyTextNode } from './MainOnlyTextNode.js';
34
34
  import { loadCoreExtension } from '../utils.js';
35
+ import type { FpsUpdatePayload } from '../../common/CommonTypes.js';
35
36
 
36
37
  export class MainCoreDriver implements ICoreDriver {
37
38
  private root: MainOnlyNode | null = null;
@@ -52,6 +53,8 @@ export class MainCoreDriver implements ICoreDriver {
52
53
  clearColor: rendererSettings.clearColor,
53
54
  canvas,
54
55
  fpsUpdateInterval: rendererSettings.fpsUpdateInterval,
56
+ enableContextSpy: rendererSettings.enableContextSpy,
57
+ numImageWorkers: rendererSettings.numImageWorkers,
55
58
  debug: {
56
59
  monitorTextureCache: false,
57
60
  },
@@ -74,9 +77,9 @@ export class MainCoreDriver implements ICoreDriver {
74
77
  }
75
78
 
76
79
  // Forward fpsUpdate events from the stage to RendererMain
77
- this.stage.on('fpsUpdate', (stage: Stage, fps: number) => {
78
- this.onFpsUpdate(fps);
79
- });
80
+ this.stage.on('fpsUpdate', ((stage, fpsData) => {
81
+ this.onFpsUpdate(fpsData);
82
+ }) satisfies StageFpsUpdateHandler);
80
83
  }
81
84
 
82
85
  createNode(props: INodeWritableProps): INode {
@@ -123,7 +126,7 @@ export class MainCoreDriver implements ICoreDriver {
123
126
  throw new Error('Method not implemented.');
124
127
  }
125
128
 
126
- onFpsUpdate(fps: number) {
129
+ onFpsUpdate(fpsData: FpsUpdatePayload) {
127
130
  throw new Error('Method not implemented.');
128
131
  }
129
132
  //#endregion
@@ -81,8 +81,12 @@ export class MainOnlyTextNode extends MainOnlyNode implements ITextNode {
81
81
  scrollY: props.scrollY,
82
82
  offsetY: props.offsetY,
83
83
  textRendererOverride: props.textRendererOverride,
84
+ lineHeight: props.lineHeight,
85
+ maxLines: props.maxLines,
86
+ textBaseline: props.textBaseline,
87
+ verticalAlign: props.verticalAlign,
88
+ overflowSuffix: props.overflowSuffix,
84
89
  debug: props.debug,
85
-
86
90
  // These properties will get set appropriately in the base MainOnlyNode class
87
91
  parent: null,
88
92
  texture: null,
@@ -197,6 +201,56 @@ export class MainOnlyTextNode extends MainOnlyNode implements ITextNode {
197
201
  this.coreNode.letterSpacing = value;
198
202
  }
199
203
 
204
+ get lineHeight(): ITextNode['lineHeight'] {
205
+ return this.coreNode.lineHeight;
206
+ }
207
+
208
+ set lineHeight(value: ITextNode['lineHeight']) {
209
+ if (value) {
210
+ this.coreNode.lineHeight = value;
211
+ }
212
+ }
213
+
214
+ get maxLines(): ITextNode['maxLines'] {
215
+ return this.coreNode.maxLines;
216
+ }
217
+
218
+ set maxLines(value: ITextNode['maxLines']) {
219
+ if (value) {
220
+ this.coreNode.maxLines = value;
221
+ }
222
+ }
223
+
224
+ get textBaseline(): ITextNode['textBaseline'] {
225
+ return this.coreNode.textBaseline;
226
+ }
227
+
228
+ set textBaseline(value: ITextNode['textBaseline']) {
229
+ if (value) {
230
+ this.coreNode.textBaseline = value;
231
+ }
232
+ }
233
+
234
+ get verticalAlign(): ITextNode['verticalAlign'] {
235
+ return this.coreNode.verticalAlign;
236
+ }
237
+
238
+ set verticalAlign(value: ITextNode['verticalAlign']) {
239
+ if (value) {
240
+ this.coreNode.verticalAlign = value;
241
+ }
242
+ }
243
+
244
+ get overflowSuffix(): ITextNode['overflowSuffix'] {
245
+ return this.coreNode.overflowSuffix;
246
+ }
247
+
248
+ set overflowSuffix(value: ITextNode['overflowSuffix']) {
249
+ if (value) {
250
+ this.coreNode.overflowSuffix = value;
251
+ }
252
+ }
253
+
200
254
  get debug(): ITextNode['debug'] {
201
255
  return this.coreNode.debug;
202
256
  }
@@ -163,4 +163,49 @@ export class TextNodeStruct
163
163
  set letterSpacing(value: TextNodeStructWritableProps['letterSpacing']) {
164
164
  // Decorator will handle this
165
165
  }
166
+
167
+ @structProp('number')
168
+ get lineHeight(): TextNodeStructWritableProps['lineHeight'] {
169
+ return 0;
170
+ }
171
+
172
+ set lineHeight(value: TextNodeStructWritableProps['lineHeight']) {
173
+ // Decorator will handle this
174
+ }
175
+
176
+ @structProp('number')
177
+ get maxLines(): TextNodeStructWritableProps['maxLines'] {
178
+ return 0;
179
+ }
180
+
181
+ set maxLines(value: TextNodeStructWritableProps['maxLines']) {
182
+ // Decorator will handle this
183
+ }
184
+
185
+ @structProp('string')
186
+ get textBaseline(): TextNodeStructWritableProps['textBaseline'] {
187
+ return 'alphabetic';
188
+ }
189
+
190
+ set textBaseline(value: TextNodeStructWritableProps['textBaseline']) {
191
+ // Decorator will handle this
192
+ }
193
+
194
+ @structProp('string')
195
+ get verticalAlign(): TextNodeStructWritableProps['verticalAlign'] {
196
+ return 'middle';
197
+ }
198
+
199
+ set verticalAlign(value: TextNodeStructWritableProps['verticalAlign']) {
200
+ // Decorator will handle this
201
+ }
202
+
203
+ @structProp('string')
204
+ get overflowSuffix(): TextNodeStructWritableProps['overflowSuffix'] {
205
+ return '...';
206
+ }
207
+
208
+ set overflowSuffix(value: TextNodeStructWritableProps['overflowSuffix']) {
209
+ // Decorator will handle this
210
+ }
166
211
  }
@@ -42,6 +42,7 @@ import {
42
42
  type TextNodeStructWritableProps,
43
43
  } from './TextNodeStruct.js';
44
44
  import { ThreadXMainTextNode } from './ThreadXMainTextNode.js';
45
+ import type { FpsUpdatePayload } from '../../common/CommonTypes.js';
45
46
 
46
47
  export interface ThreadXRendererSettings {
47
48
  coreWorkerUrl: string;
@@ -79,7 +80,7 @@ export class ThreadXCoreDriver implements ICoreDriver {
79
80
  onMessage: async (message) => {
80
81
  // Forward fpsUpdate events from the renderer worker's Stage to RendererMain
81
82
  if (isThreadXRendererMessage('fpsUpdate', message)) {
82
- this.onFpsUpdate(message.fps);
83
+ this.onFpsUpdate(message.fpsData);
83
84
  }
84
85
  },
85
86
  });
@@ -108,6 +109,8 @@ export class ThreadXCoreDriver implements ICoreDriver {
108
109
  clearColor: rendererSettings.clearColor,
109
110
  coreExtensionModule: rendererSettings.coreExtensionModule,
110
111
  fpsUpdateInterval: rendererSettings.fpsUpdateInterval,
112
+ enableContextSpy: rendererSettings.enableContextSpy,
113
+ numImageWorkers: rendererSettings.numImageWorkers,
111
114
  } satisfies ThreadXRendererInitMessage,
112
115
  [offscreenCanvas],
113
116
  )) as number;
@@ -215,8 +218,13 @@ export class ThreadXCoreDriver implements ICoreDriver {
215
218
  fontWeight: props.fontWeight,
216
219
  fontStretch: props.fontStretch,
217
220
  fontStyle: props.fontStyle,
221
+ lineHeight: props.lineHeight,
222
+ maxLines: props.maxLines,
223
+ textBaseline: props.textBaseline,
224
+ verticalAlign: props.verticalAlign,
218
225
  contain: props.contain,
219
226
  letterSpacing: props.letterSpacing,
227
+ overflowSuffix: props.overflowSuffix,
220
228
  offsetY: props.offsetY,
221
229
  textAlign: props.textAlign,
222
230
  scrollable: props.scrollable,
@@ -258,7 +266,7 @@ export class ThreadXCoreDriver implements ICoreDriver {
258
266
  throw new Error('Method not implemented.');
259
267
  }
260
268
 
261
- onFpsUpdate(fps: number): void {
269
+ onFpsUpdate(fps: FpsUpdatePayload): void {
262
270
  throw new Error('Method not implemented.');
263
271
  }
264
272
  //#endregion
@@ -38,12 +38,17 @@ export class ThreadXMainTextNode extends ThreadXMainNode implements ITextNode {
38
38
  fontStretch: sharedNodeStruct.fontStretch,
39
39
  fontStyle: sharedNodeStruct.fontStyle,
40
40
  fontWeight: sharedNodeStruct.fontWeight,
41
+ lineHeight: sharedNodeStruct.lineHeight,
42
+ maxLines: sharedNodeStruct.maxLines,
43
+ textBaseline: sharedNodeStruct.textBaseline,
44
+ verticalAlign: sharedNodeStruct.verticalAlign,
41
45
  contain: sharedNodeStruct.contain,
42
46
  letterSpacing: sharedNodeStruct.letterSpacing,
43
47
  offsetY: sharedNodeStruct.offsetY,
44
48
  scrollable: sharedNodeStruct.scrollable,
45
49
  scrollY: sharedNodeStruct.scrollY,
46
50
  textAlign: sharedNodeStruct.textAlign,
51
+ overflowSuffix: sharedNodeStruct.overflowSuffix,
47
52
  } satisfies Omit<TextNodeStructWritableProps, keyof NodeStructWritableProps>);
48
53
  }
49
54
 
@@ -54,12 +59,17 @@ export class ThreadXMainTextNode extends ThreadXMainNode implements ITextNode {
54
59
  declare fontStretch: ITextNode['fontStretch'];
55
60
  declare fontStyle: ITextNode['fontStyle'];
56
61
  declare fontWeight: ITextNode['fontWeight'];
62
+ declare lineHeight: ITextNode['lineHeight'];
63
+ declare maxLines: ITextNode['maxLines'];
64
+ declare textBaseline: ITextNode['textBaseline'];
65
+ declare verticalAlign: ITextNode['verticalAlign'];
57
66
  declare textAlign: ITextNode['textAlign'];
58
67
  declare contain: ITextNode['contain'];
59
68
  declare scrollable: ITextNode['scrollable'];
60
69
  declare scrollY: ITextNode['scrollY'];
61
70
  declare offsetY: ITextNode['offsetY'];
62
71
  declare letterSpacing: ITextNode['letterSpacing'];
72
+ declare overflowSuffix: ITextNode['overflowSuffix'];
63
73
 
64
74
  get debug(): ITextNode['debug'] {
65
75
  return this._debug;
@@ -17,6 +17,8 @@
17
17
  * limitations under the License.
18
18
  */
19
19
 
20
+ import type { FpsUpdatePayload } from '../../common/CommonTypes.js';
21
+
20
22
  /**
21
23
  * @module
22
24
  * @description
@@ -43,6 +45,8 @@ export interface ThreadXRendererInitMessage extends ThreadXRendererMessage {
43
45
  devicePhysicalPixelRatio: number;
44
46
  clearColor: number;
45
47
  fpsUpdateInterval: number;
48
+ enableContextSpy: boolean;
49
+ numImageWorkers: number;
46
50
  coreExtensionModule: string | null;
47
51
  }
48
52
 
@@ -62,7 +66,7 @@ export interface ThreadXRendererReleaseTextureMessage
62
66
  export interface ThreadXRendererFpsUpdateMessage
63
67
  extends ThreadXRendererMessage {
64
68
  type: 'fpsUpdate';
65
- fps: number;
69
+ fpsData: FpsUpdatePayload;
66
70
  }
67
71
 
68
72
  /**
@@ -85,6 +85,11 @@ export class ThreadXRendererTextNode extends ThreadXRendererNode {
85
85
  fontWeight: sharedNodeStruct.fontWeight,
86
86
  fontStretch: sharedNodeStruct.fontStretch,
87
87
  fontStyle: sharedNodeStruct.fontStyle,
88
+ lineHeight: sharedNodeStruct.lineHeight,
89
+ maxLines: sharedNodeStruct.maxLines,
90
+ textBaseline: sharedNodeStruct.textBaseline,
91
+ verticalAlign: sharedNodeStruct.verticalAlign,
92
+ overflowSuffix: sharedNodeStruct.overflowSuffix,
88
93
  contain: sharedNodeStruct.contain,
89
94
  letterSpacing: sharedNodeStruct.letterSpacing,
90
95
  offsetY: sharedNodeStruct.offsetY,
@@ -101,6 +106,11 @@ export class ThreadXRendererTextNode extends ThreadXRendererNode {
101
106
  fontWeight: sharedNodeStruct.fontWeight,
102
107
  fontStretch: sharedNodeStruct.fontStretch,
103
108
  fontStyle: sharedNodeStruct.fontStyle,
109
+ lineHeight: sharedNodeStruct.lineHeight,
110
+ maxLines: sharedNodeStruct.maxLines,
111
+ textBaseline: sharedNodeStruct.textBaseline,
112
+ verticalAlign: sharedNodeStruct.verticalAlign,
113
+ overflowSuffix: sharedNodeStruct.overflowSuffix,
104
114
  contain: sharedNodeStruct.contain,
105
115
  letterSpacing: sharedNodeStruct.letterSpacing,
106
116
  offsetY: sharedNodeStruct.offsetY,
@@ -125,6 +135,11 @@ export class ThreadXRendererTextNode extends ThreadXRendererNode {
125
135
  declare fontWeight: TextNodeStructWritableProps['fontWeight'];
126
136
  declare fontStretch: TextNodeStructWritableProps['fontStretch'];
127
137
  declare fontStyle: TextNodeStructWritableProps['fontStyle'];
138
+ declare lineHeight: TextNodeStructWritableProps['lineHeight'];
139
+ declare maxLines: TextNodeStructWritableProps['maxLines'];
140
+ declare textBaseline: TextNodeStructWritableProps['textBaseline'];
141
+ declare verticalAlign: TextNodeStructWritableProps['verticalAlign'];
142
+ declare overflowSuffix: TextNodeStructWritableProps['overflowSuffix'];
128
143
  declare contain: TextNodeStructWritableProps['contain'];
129
144
  declare letterSpacing: TextNodeStructWritableProps['letterSpacing'];
130
145
  declare offsetY: TextNodeStructWritableProps['offsetY'];
@@ -20,7 +20,7 @@
20
20
  import { ThreadX, BufferStruct } from '@lightningjs/threadx';
21
21
  import { NodeStruct, type NodeStructWritableProps } from '../NodeStruct.js';
22
22
  import { ThreadXRendererNode } from './ThreadXRendererNode.js';
23
- import { Stage } from '../../../core/Stage.js';
23
+ import { Stage, type StageFpsUpdateHandler } from '../../../core/Stage.js';
24
24
  import { assertTruthy } from '../../../utils.js';
25
25
  import {
26
26
  isThreadXRendererMessage,
@@ -71,6 +71,8 @@ const threadx = ThreadX.init({
71
71
  clearColor: message.clearColor,
72
72
  canvas,
73
73
  fpsUpdateInterval: message.fpsUpdateInterval,
74
+ enableContextSpy: message.enableContextSpy,
75
+ numImageWorkers: message.numImageWorkers,
74
76
  debug: {
75
77
  monitorTextureCache: false,
76
78
  },
@@ -120,12 +122,12 @@ const threadx = ThreadX.init({
120
122
  }
121
123
 
122
124
  // Forward FPS updates to the main worker.
123
- stage.on('fpsUpdate', (stage: Stage, fps: number) => {
125
+ stage.on('fpsUpdate', ((stage, fpsData) => {
124
126
  threadx.sendMessage('parent', {
125
127
  type: 'fpsUpdate',
126
- fps,
128
+ fpsData: fpsData,
127
129
  } satisfies ThreadXRendererFpsUpdateMessage);
128
- });
130
+ }) satisfies StageFpsUpdateHandler);
129
131
 
130
132
  // Return its ID so the main worker can retrieve it from the shared object
131
133
  // store.
package/src/utils.ts CHANGED
@@ -17,9 +17,12 @@
17
17
  * limitations under the License.
18
18
  */
19
19
 
20
+ import type { ContextSpy } from './core/lib/ContextSpy.js';
21
+
20
22
  export function createWebGLContext(
21
23
  canvas: HTMLCanvasElement | OffscreenCanvas,
22
- ): WebGLRenderingContext | null {
24
+ contextSpy: ContextSpy | null,
25
+ ): WebGLRenderingContext {
23
26
  const config: WebGLContextAttributes = {
24
27
  alpha: true,
25
28
  antialias: false,
@@ -32,15 +35,32 @@ export function createWebGLContext(
32
35
  premultipliedAlpha: true,
33
36
  preserveDrawingBuffer: false,
34
37
  };
35
- return (
38
+ const gl =
36
39
  // TODO: Remove this assertion once this issue is fixed in TypeScript
37
40
  // https://github.com/microsoft/TypeScript/issues/53614
38
41
  (canvas.getContext('webgl', config) ||
39
42
  canvas.getContext(
40
43
  'experimental-webgl' as 'webgl',
41
44
  config,
42
- )) as unknown as WebGLRenderingContext | null
43
- );
45
+ )) as unknown as WebGLRenderingContext | null;
46
+ if (!gl) {
47
+ throw new Error('Unable to create WebGL context');
48
+ }
49
+ if (contextSpy) {
50
+ // Proxy the GL context to log all GL calls
51
+ return new Proxy(gl, {
52
+ get(target, prop) {
53
+ const value = target[prop as never] as unknown;
54
+ if (typeof value === 'function') {
55
+ contextSpy.increment(String(prop));
56
+ return value.bind(target);
57
+ }
58
+ return value;
59
+ },
60
+ });
61
+ }
62
+
63
+ return gl;
44
64
  }
45
65
 
46
66
  /**
@@ -59,6 +79,7 @@ export function assertTruthy(
59
79
  condition: unknown,
60
80
  message?: string,
61
81
  ): asserts condition {
82
+ if (import.meta.env.PROD) return;
62
83
  if (!condition) {
63
84
  throw new Error(message || 'Assertion failed');
64
85
  }
@@ -1,136 +0,0 @@
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
- import { expect, describe, it } from 'vitest';
21
- import { makeRenderWindow } from './makeRenderWindow.js';
22
-
23
- describe('makeRenderWindow', () => {
24
- it('should return a empty window when all inputs are zero / empty', () => {
25
- expect(
26
- makeRenderWindow(0, 0, 0, 0, 0, { x1: 0, y1: 0, x2: 0, y2: 0 }),
27
- ).toEqual({
28
- x1: 0,
29
- y1: 0,
30
- x2: 0,
31
- y2: 0,
32
- });
33
- // Visible window is empty
34
- expect(
35
- makeRenderWindow(0, 0, 0, 0, 0, { x1: 100, y1: 100, x2: 100, y2: 100 }),
36
- ).toEqual({
37
- x1: 0,
38
- y1: 0,
39
- x2: 0,
40
- y2: 0,
41
- });
42
- });
43
-
44
- it('should return an empty window when the visible window is empty regardless of other inputs', () => {
45
- expect(
46
- makeRenderWindow(100, 200, 300, 10, 3, { x1: 0, y1: 0, x2: 0, y2: 0 }),
47
- ).toEqual({
48
- x1: 0,
49
- y1: 0,
50
- x2: 0,
51
- y2: 0,
52
- });
53
- expect(
54
- makeRenderWindow(400, 500, 100, 20, 2, {
55
- x1: 100,
56
- y1: 100,
57
- x2: 100,
58
- y2: 100,
59
- }),
60
- ).toEqual({
61
- x1: 0,
62
- y1: 0,
63
- x2: 0,
64
- y2: 0,
65
- });
66
- });
67
-
68
- it('should return a window with no margin around the visible area if lineHeight and/or numExtraLines set are zero', () => {
69
- expect(
70
- makeRenderWindow(0, 0, 0, 0, 0, { x1: 0, y1: 0, x2: 100, y2: 100 }),
71
- ).toEqual({
72
- x1: 0,
73
- y1: 0,
74
- x2: 100,
75
- y2: 100,
76
- });
77
-
78
- expect(
79
- makeRenderWindow(0, 0, 0, 10, 0, { x1: 0, y1: 0, x2: 100, y2: 100 }),
80
- ).toEqual({
81
- x1: 0,
82
- y1: 0,
83
- x2: 100,
84
- y2: 100,
85
- });
86
-
87
- expect(
88
- makeRenderWindow(0, 0, 0, 0, 2, { x1: 0, y1: 0, x2: 100, y2: 100 }),
89
- ).toEqual({
90
- x1: 0,
91
- y1: 0,
92
- x2: 100,
93
- y2: 100,
94
- });
95
- });
96
-
97
- it('should return a window with a margin around the visible area (if lineHeight/numExtraLines set)', () => {
98
- expect(
99
- makeRenderWindow(0, 0, 0, 10, 1, { x1: 0, y1: 0, x2: 100, y2: 100 }),
100
- ).toEqual({
101
- x1: 0,
102
- y1: -10,
103
- x2: 100,
104
- y2: 110,
105
- });
106
-
107
- expect(
108
- makeRenderWindow(0, 0, 0, 5, 3, { x1: 0, y1: 0, x2: 100, y2: 100 }),
109
- ).toEqual({
110
- x1: 0,
111
- y1: -15,
112
- x2: 100,
113
- y2: 115,
114
- });
115
- });
116
-
117
- it('should return a window scrolled to scrollY when set', () => {
118
- expect(
119
- makeRenderWindow(0, 0, 100, 10, 1, { x1: 0, y1: 0, x2: 100, y2: 100 }),
120
- ).toEqual({
121
- x1: 0,
122
- y1: 90,
123
- x2: 100,
124
- y2: 210,
125
- });
126
-
127
- expect(
128
- makeRenderWindow(0, 0, 200, 10, 1, { x1: 0, y1: 0, x2: 100, y2: 100 }),
129
- ).toEqual({
130
- x1: 0,
131
- y1: 190,
132
- x2: 100,
133
- y2: 310,
134
- });
135
- });
136
- });