@lightningjs/renderer 0.6.0 → 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 (204) hide show
  1. package/README.md +1 -1
  2. package/dist/src/common/CommonTypes.d.ts +8 -0
  3. package/dist/src/core/CoreNode.d.ts +63 -15
  4. package/dist/src/core/CoreNode.js +266 -117
  5. package/dist/src/core/CoreNode.js.map +1 -1
  6. package/dist/src/core/CoreTextNode.d.ts +11 -0
  7. package/dist/src/core/CoreTextNode.js +58 -0
  8. package/dist/src/core/CoreTextNode.js.map +1 -1
  9. package/dist/src/core/CoreTextureManager.d.ts +3 -1
  10. package/dist/src/core/CoreTextureManager.js +4 -1
  11. package/dist/src/core/CoreTextureManager.js.map +1 -1
  12. package/dist/src/core/Stage.d.ts +12 -2
  13. package/dist/src/core/Stage.js +36 -24
  14. package/dist/src/core/Stage.js.map +1 -1
  15. package/dist/src/core/animations/CoreAnimation.js +11 -2
  16. package/dist/src/core/animations/CoreAnimation.js.map +1 -1
  17. package/dist/src/core/lib/ContextSpy.d.ts +12 -0
  18. package/dist/src/core/lib/ContextSpy.js +38 -0
  19. package/dist/src/core/lib/ContextSpy.js.map +1 -0
  20. package/dist/src/core/lib/ImageWorker.d.ts +16 -0
  21. package/dist/src/core/lib/ImageWorker.js +111 -0
  22. package/dist/src/core/lib/ImageWorker.js.map +1 -0
  23. package/dist/src/core/lib/WebGlContext.d.ts +414 -0
  24. package/dist/src/core/lib/WebGlContext.js +640 -0
  25. package/dist/src/core/lib/WebGlContext.js.map +1 -0
  26. package/dist/src/core/lib/WebGlContextWrapper.d.ts +500 -0
  27. package/dist/src/core/lib/WebGlContextWrapper.js +784 -0
  28. package/dist/src/core/lib/WebGlContextWrapper.js.map +1 -0
  29. package/dist/src/core/platform.js +4 -0
  30. package/dist/src/core/platform.js.map +1 -1
  31. package/dist/src/core/renderers/webgl/WebGlCoreCtxSubTexture.d.ts +2 -1
  32. package/dist/src/core/renderers/webgl/WebGlCoreCtxSubTexture.js +2 -2
  33. package/dist/src/core/renderers/webgl/WebGlCoreCtxSubTexture.js.map +1 -1
  34. package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.d.ts +3 -2
  35. package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.js +23 -21
  36. package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.js.map +1 -1
  37. package/dist/src/core/renderers/webgl/WebGlCoreRenderOp.d.ts +3 -2
  38. package/dist/src/core/renderers/webgl/WebGlCoreRenderOp.js +9 -13
  39. package/dist/src/core/renderers/webgl/WebGlCoreRenderOp.js.map +1 -1
  40. package/dist/src/core/renderers/webgl/WebGlCoreRenderer.d.ts +4 -1
  41. package/dist/src/core/renderers/webgl/WebGlCoreRenderer.js +33 -31
  42. package/dist/src/core/renderers/webgl/WebGlCoreRenderer.js.map +1 -1
  43. package/dist/src/core/renderers/webgl/WebGlCoreShader.d.ts +2 -1
  44. package/dist/src/core/renderers/webgl/WebGlCoreShader.js +24 -24
  45. package/dist/src/core/renderers/webgl/WebGlCoreShader.js.map +1 -1
  46. package/dist/src/core/renderers/webgl/internal/RendererUtils.d.ts +8 -5
  47. package/dist/src/core/renderers/webgl/internal/RendererUtils.js +11 -13
  48. package/dist/src/core/renderers/webgl/internal/RendererUtils.js.map +1 -1
  49. package/dist/src/core/renderers/webgl/internal/ShaderUtils.d.ts +3 -2
  50. package/dist/src/core/renderers/webgl/internal/ShaderUtils.js +15 -15
  51. package/dist/src/core/renderers/webgl/internal/ShaderUtils.js.map +1 -1
  52. package/dist/src/core/renderers/webgl/shaders/DefaultShader.js +3 -6
  53. package/dist/src/core/renderers/webgl/shaders/DefaultShader.js.map +1 -1
  54. package/dist/src/core/renderers/webgl/shaders/DefaultShaderBatched.js +3 -3
  55. package/dist/src/core/renderers/webgl/shaders/DefaultShaderBatched.js.map +1 -1
  56. package/dist/src/core/renderers/webgl/shaders/DynamicShader.d.ts +1 -0
  57. package/dist/src/core/renderers/webgl/shaders/DynamicShader.js +32 -12
  58. package/dist/src/core/renderers/webgl/shaders/DynamicShader.js.map +1 -1
  59. package/dist/src/core/renderers/webgl/shaders/RoundedRectangle.js +3 -3
  60. package/dist/src/core/renderers/webgl/shaders/RoundedRectangle.js.map +1 -1
  61. package/dist/src/core/renderers/webgl/shaders/SdfShader.js +3 -3
  62. package/dist/src/core/renderers/webgl/shaders/SdfShader.js.map +1 -1
  63. package/dist/src/core/renderers/webgl/shaders/effects/BorderEffect.js +1 -1
  64. package/dist/src/core/renderers/webgl/shaders/effects/GrayscaleEffect.d.ts +14 -1
  65. package/dist/src/core/renderers/webgl/shaders/effects/GrayscaleEffect.js +15 -5
  66. package/dist/src/core/renderers/webgl/shaders/effects/GrayscaleEffect.js.map +1 -1
  67. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.js +7 -8
  68. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.js.map +1 -1
  69. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.d.ts +2 -1
  70. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.js +4 -2
  71. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.js.map +1 -1
  72. package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.js +40 -13
  73. package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.js.map +1 -1
  74. package/dist/src/core/text-rendering/renderers/LightningTextTextureRenderer.d.ts +1 -1
  75. package/dist/src/core/text-rendering/renderers/LightningTextTextureRenderer.js +6 -6
  76. package/dist/src/core/text-rendering/renderers/LightningTextTextureRenderer.js.map +1 -1
  77. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.d.ts +3 -2
  78. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js +82 -50
  79. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js.map +1 -1
  80. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/findNearestMultiple.d.ts +8 -0
  81. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/findNearestMultiple.js +29 -0
  82. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/findNearestMultiple.js.map +1 -0
  83. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/getStartConditions.d.ts +4 -3
  84. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/getStartConditions.js +15 -11
  85. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/getStartConditions.js.map +1 -1
  86. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.d.ts +3 -2
  87. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.js +30 -26
  88. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.js.map +1 -1
  89. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/SdfBufferHelper.d.ts +19 -0
  90. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/SdfBufferHelper.js +84 -0
  91. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/SdfBufferHelper.js.map +1 -0
  92. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutLine.d.ts +8 -0
  93. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutLine.js +40 -0
  94. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutLine.js.map +1 -0
  95. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutText2.d.ts +2 -0
  96. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutText2.js +41 -0
  97. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutText2.js.map +1 -0
  98. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/utils.d.ts +1 -0
  99. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/utils.js +4 -0
  100. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/utils.js.map +1 -0
  101. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2.d.ts +1 -0
  102. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2.js +2 -0
  103. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2.js.map +1 -0
  104. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/roundUpToMultiple.d.ts +9 -0
  105. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/roundUpToMultiple.js +32 -0
  106. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/roundUpToMultiple.js.map +1 -0
  107. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.d.ts +26 -0
  108. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.js +70 -0
  109. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.js.map +1 -0
  110. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/util.d.ts +16 -0
  111. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/util.js +39 -0
  112. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/util.js.map +1 -0
  113. package/dist/src/core/text-rendering/renderers/TextRenderer.d.ts +50 -0
  114. package/dist/src/core/text-rendering/renderers/TextRenderer.js +19 -0
  115. package/dist/src/core/text-rendering/renderers/TextRenderer.js.map +1 -1
  116. package/dist/src/core/textures/ImageTexture.js +14 -9
  117. package/dist/src/core/textures/ImageTexture.js.map +1 -1
  118. package/dist/src/core/utils.d.ts +1 -6
  119. package/dist/src/core/utils.js +3 -2
  120. package/dist/src/core/utils.js.map +1 -1
  121. package/dist/src/main-api/ICoreDriver.d.ts +2 -1
  122. package/dist/src/main-api/RendererMain.d.ts +25 -0
  123. package/dist/src/main-api/RendererMain.js +14 -5
  124. package/dist/src/main-api/RendererMain.js.map +1 -1
  125. package/dist/src/render-drivers/main/MainCoreDriver.d.ts +2 -1
  126. package/dist/src/render-drivers/main/MainCoreDriver.js +6 -4
  127. package/dist/src/render-drivers/main/MainCoreDriver.js.map +1 -1
  128. package/dist/src/render-drivers/main/MainOnlyTextNode.d.ts +10 -0
  129. package/dist/src/render-drivers/main/MainOnlyTextNode.js +45 -0
  130. package/dist/src/render-drivers/main/MainOnlyTextNode.js.map +1 -1
  131. package/dist/src/render-drivers/threadx/TextNodeStruct.d.ts +10 -0
  132. package/dist/src/render-drivers/threadx/TextNodeStruct.js +45 -0
  133. package/dist/src/render-drivers/threadx/TextNodeStruct.js.map +1 -1
  134. package/dist/src/render-drivers/threadx/ThreadXCoreDriver.d.ts +2 -1
  135. package/dist/src/render-drivers/threadx/ThreadXCoreDriver.js +8 -1
  136. package/dist/src/render-drivers/threadx/ThreadXCoreDriver.js.map +1 -1
  137. package/dist/src/render-drivers/threadx/ThreadXMainTextNode.d.ts +5 -0
  138. package/dist/src/render-drivers/threadx/ThreadXMainTextNode.js +5 -0
  139. package/dist/src/render-drivers/threadx/ThreadXMainTextNode.js.map +1 -1
  140. package/dist/src/render-drivers/threadx/ThreadXRendererMessage.d.ts +4 -1
  141. package/dist/src/render-drivers/threadx/ThreadXRendererMessage.js.map +1 -1
  142. package/dist/src/render-drivers/threadx/worker/ThreadXRendererTextNode.d.ts +5 -0
  143. package/dist/src/render-drivers/threadx/worker/ThreadXRendererTextNode.js +10 -0
  144. package/dist/src/render-drivers/threadx/worker/ThreadXRendererTextNode.js.map +1 -1
  145. package/dist/src/render-drivers/threadx/worker/renderer.js +5 -3
  146. package/dist/src/render-drivers/threadx/worker/renderer.js.map +1 -1
  147. package/dist/src/utils.d.ts +2 -1
  148. package/dist/src/utils.js +22 -3
  149. package/dist/src/utils.js.map +1 -1
  150. package/dist/tsconfig.dist.tsbuildinfo +1 -1
  151. package/package.json +3 -2
  152. package/src/common/CommonTypes.ts +9 -0
  153. package/src/core/CoreNode.ts +325 -148
  154. package/src/core/CoreTextNode.ts +72 -0
  155. package/src/core/CoreTextureManager.ts +4 -2
  156. package/src/core/Stage.ts +60 -34
  157. package/src/core/animations/CoreAnimation.ts +11 -2
  158. package/src/core/lib/ContextSpy.ts +41 -0
  159. package/src/core/lib/ImageWorker.ts +124 -0
  160. package/src/core/lib/WebGlContextWrapper.ts +965 -0
  161. package/src/core/platform.ts +5 -0
  162. package/src/core/renderers/webgl/WebGlCoreCtxSubTexture.ts +3 -2
  163. package/src/core/renderers/webgl/WebGlCoreCtxTexture.ts +29 -28
  164. package/src/core/renderers/webgl/WebGlCoreRenderOp.ts +10 -14
  165. package/src/core/renderers/webgl/WebGlCoreRenderer.ts +34 -63
  166. package/src/core/renderers/webgl/WebGlCoreShader.ts +34 -25
  167. package/src/core/renderers/webgl/internal/RendererUtils.ts +13 -16
  168. package/src/core/renderers/webgl/internal/ShaderUtils.ts +16 -15
  169. package/src/core/renderers/webgl/shaders/DefaultShader.ts +3 -7
  170. package/src/core/renderers/webgl/shaders/DefaultShaderBatched.ts +3 -3
  171. package/src/core/renderers/webgl/shaders/DynamicShader.ts +42 -14
  172. package/src/core/renderers/webgl/shaders/RoundedRectangle.ts +3 -3
  173. package/src/core/renderers/webgl/shaders/SdfShader.ts +3 -3
  174. package/src/core/renderers/webgl/shaders/effects/BorderEffect.ts +1 -1
  175. package/src/core/renderers/webgl/shaders/effects/GrayscaleEffect.ts +35 -5
  176. package/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.ts +7 -8
  177. package/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.test.ts +9 -3
  178. package/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.ts +4 -2
  179. package/src/core/text-rendering/renderers/CanvasTextRenderer.ts +44 -15
  180. package/src/core/text-rendering/renderers/LightningTextTextureRenderer.ts +7 -7
  181. package/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.ts +115 -63
  182. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/getStartConditions.ts +26 -18
  183. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.ts +40 -28
  184. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/measureText.test.ts +6 -1
  185. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.test.ts +205 -0
  186. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/{makeRenderWindow.ts → setRenderWindow.ts} +50 -21
  187. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/util.ts +40 -0
  188. package/src/core/text-rendering/renderers/TextRenderer.ts +73 -0
  189. package/src/core/textures/ImageTexture.ts +17 -9
  190. package/src/core/utils.ts +87 -85
  191. package/src/env.d.ts +7 -0
  192. package/src/main-api/ICoreDriver.ts +2 -1
  193. package/src/main-api/RendererMain.ts +43 -5
  194. package/src/render-drivers/main/MainCoreDriver.ts +8 -5
  195. package/src/render-drivers/main/MainOnlyTextNode.ts +55 -1
  196. package/src/render-drivers/threadx/TextNodeStruct.ts +45 -0
  197. package/src/render-drivers/threadx/ThreadXCoreDriver.ts +10 -2
  198. package/src/render-drivers/threadx/ThreadXMainTextNode.ts +10 -0
  199. package/src/render-drivers/threadx/ThreadXRendererMessage.ts +5 -1
  200. package/src/render-drivers/threadx/worker/ThreadXRendererTextNode.ts +15 -0
  201. package/src/render-drivers/threadx/worker/renderer.ts +6 -4
  202. package/src/utils.ts +25 -4
  203. package/src/core/scene/Scene.ts +0 -120
  204. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/makeRenderWindow.test.ts +0 -136
@@ -76,6 +76,11 @@ export class CoreTextNode extends CoreNode implements ICoreTextNode {
76
76
  fontStyle: props.fontStyle,
77
77
  fontWeight: props.fontWeight,
78
78
  text: props.text,
79
+ lineHeight: props.lineHeight,
80
+ maxLines: props.maxLines,
81
+ textBaseline: props.textBaseline,
82
+ verticalAlign: props.verticalAlign,
83
+ overflowSuffix: props.overflowSuffix,
79
84
  },
80
85
  undefined,
81
86
  );
@@ -102,6 +107,9 @@ export class CoreTextNode extends CoreNode implements ICoreTextNode {
102
107
  }
103
108
  this.updateLocalTransform();
104
109
 
110
+ // Incase the RAF loop has been stopped already before text was loaded,
111
+ // we request a render so it can be drawn.
112
+ this.stage.requestRender();
105
113
  this.emit('loaded', {
106
114
  type: 'text',
107
115
  dimensions: {
@@ -148,6 +156,7 @@ export class CoreTextNode extends CoreNode implements ICoreTextNode {
148
156
 
149
157
  set text(value: string) {
150
158
  this.textRenderer.set.text(this.trState, value);
159
+ this.checkIsRenderable();
151
160
  }
152
161
 
153
162
  get textRendererOverride(): CoreTextNodeProps['textRendererOverride'] {
@@ -251,6 +260,56 @@ export class CoreTextNode extends CoreNode implements ICoreTextNode {
251
260
  this.textRenderer.set.letterSpacing(this.trState, value);
252
261
  }
253
262
 
263
+ get lineHeight(): CoreTextNodeProps['lineHeight'] {
264
+ return this.trState.props.lineHeight;
265
+ }
266
+
267
+ set lineHeight(value: CoreTextNodeProps['lineHeight']) {
268
+ if (this.textRenderer.set.lineHeight) {
269
+ this.textRenderer.set.lineHeight(this.trState, value);
270
+ }
271
+ }
272
+
273
+ get maxLines(): CoreTextNodeProps['maxLines'] {
274
+ return this.trState.props.maxLines;
275
+ }
276
+
277
+ set maxLines(value: CoreTextNodeProps['maxLines']) {
278
+ if (this.textRenderer.set.maxLines) {
279
+ this.textRenderer.set.maxLines(this.trState, value);
280
+ }
281
+ }
282
+
283
+ get textBaseline(): CoreTextNodeProps['textBaseline'] {
284
+ return this.trState.props.textBaseline;
285
+ }
286
+
287
+ set textBaseline(value: CoreTextNodeProps['textBaseline']) {
288
+ if (this.textRenderer.set.textBaseline) {
289
+ this.textRenderer.set.textBaseline(this.trState, value);
290
+ }
291
+ }
292
+
293
+ get verticalAlign(): CoreTextNodeProps['verticalAlign'] {
294
+ return this.trState.props.verticalAlign;
295
+ }
296
+
297
+ set verticalAlign(value: CoreTextNodeProps['verticalAlign']) {
298
+ if (this.textRenderer.set.verticalAlign) {
299
+ this.textRenderer.set.verticalAlign(this.trState, value);
300
+ }
301
+ }
302
+
303
+ get overflowSuffix(): CoreTextNodeProps['overflowSuffix'] {
304
+ return this.trState.props.overflowSuffix;
305
+ }
306
+
307
+ set overflowSuffix(value: CoreTextNodeProps['overflowSuffix']) {
308
+ if (this.textRenderer.set.overflowSuffix) {
309
+ this.textRenderer.set.overflowSuffix(this.trState, value);
310
+ }
311
+ }
312
+
254
313
  get debug(): CoreTextNodeProps['debug'] {
255
314
  return this.trState.props.debug;
256
315
  }
@@ -269,6 +328,18 @@ export class CoreTextNode extends CoreNode implements ICoreTextNode {
269
328
  this.textRenderer.set.y(this.trState, this.globalTransform.ty);
270
329
  }
271
330
 
331
+ override checkIsRenderable(): boolean {
332
+ if (super.checkIsRenderable()) {
333
+ return true;
334
+ }
335
+
336
+ if (this.trState.props.text !== '') {
337
+ return (this.isRenderable = true);
338
+ }
339
+
340
+ return (this.isRenderable = false);
341
+ }
342
+
272
343
  override renderQuads(renderer: CoreRenderer) {
273
344
  assertTruthy(this.globalTransform);
274
345
  this.textRenderer.renderQuads(
@@ -309,6 +380,7 @@ export class CoreTextNode extends CoreNode implements ICoreTextNode {
309
380
 
310
381
  textRendererState.emitter.on('loaded', this.onTextLoaded);
311
382
  textRendererState.emitter.on('failed', this.onTextFailed);
383
+
312
384
  resolvedTextRenderer.scheduleUpdateState(textRendererState);
313
385
 
314
386
  return {
@@ -18,6 +18,7 @@
18
18
  */
19
19
 
20
20
  import { assertTruthy } from '../utils.js';
21
+ import { ImageWorkerManager } from './lib/ImageWorker.js';
21
22
  import type { CoreContextTexture } from './renderers/CoreContextTexture.js';
22
23
  import type { CoreRenderer } from './renderers/CoreRenderer.js';
23
24
  import { ColorTexture } from './textures/ColorTexture.js';
@@ -144,7 +145,7 @@ export class CoreTextureManager {
144
145
  Texture,
145
146
  { cacheKey: string | false; count: number }
146
147
  > = new WeakMap();
147
-
148
+ imageWorkerManager: ImageWorkerManager;
148
149
  /**
149
150
  * Renderer that this texture manager is associated with
150
151
  *
@@ -154,8 +155,9 @@ export class CoreTextureManager {
154
155
  */
155
156
  renderer!: CoreRenderer;
156
157
 
157
- constructor() {
158
+ constructor(numImageWorkers: number) {
158
159
  // Register default known texture types
160
+ this.imageWorkerManager = new ImageWorkerManager(numImageWorkers);
159
161
  this.registerTextureType('ImageTexture', ImageTexture);
160
162
  this.registerTextureType('ColorTexture', ColorTexture);
161
163
  this.registerTextureType('NoiseTexture', NoiseTexture);
package/src/core/Stage.ts CHANGED
@@ -16,11 +16,7 @@
16
16
  * See the License for the specific language governing permissions and
17
17
  * limitations under the License.
18
18
  */
19
-
20
- import { Scene } from './scene/Scene.js';
21
-
22
19
  import { startLoop, getTimeStamp } from './platform.js';
23
-
24
20
  import { WebGlCoreRenderer } from './renderers/webgl/WebGlCoreRenderer.js';
25
21
  import { assertTruthy } from '../utils.js';
26
22
  import { AnimationManager } from './animations/AnimationManager.js';
@@ -36,6 +32,8 @@ import type {
36
32
  import { SdfTextRenderer } from './text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js';
37
33
  import { CanvasTextRenderer } from './text-rendering/renderers/CanvasTextRenderer.js';
38
34
  import { EventEmitter } from '../common/EventEmitter.js';
35
+ import { ContextSpy } from './lib/ContextSpy.js';
36
+ import type { FpsUpdatePayload } from '../common/CommonTypes.js';
39
37
 
40
38
  export interface StageOptions {
41
39
  rootId: number;
@@ -46,11 +44,19 @@ export interface StageOptions {
46
44
  canvas: HTMLCanvasElement | OffscreenCanvas;
47
45
  clearColor: number;
48
46
  fpsUpdateInterval: number;
47
+ enableContextSpy: boolean;
48
+ numImageWorkers: number;
49
+
49
50
  debug?: {
50
51
  monitorTextureCache?: boolean;
51
52
  };
52
53
  }
53
54
 
55
+ export type StageFpsUpdateHandler = (
56
+ stage: Stage,
57
+ fpsData: FpsUpdatePayload,
58
+ ) => void;
59
+
54
60
  const bufferMemory = 2e6;
55
61
  const autoStart = true;
56
62
 
@@ -62,7 +68,7 @@ export class Stage extends EventEmitter {
62
68
  public readonly textRenderers: Partial<TextRendererMap>;
63
69
  public readonly shManager: CoreShaderManager;
64
70
  public readonly renderer: WebGlCoreRenderer;
65
- private scene: Scene;
71
+ public readonly root: CoreNode;
66
72
 
67
73
  /// State
68
74
  deltaTime = 0;
@@ -70,16 +76,31 @@ export class Stage extends EventEmitter {
70
76
  currentFrameTime = 0;
71
77
  private fpsNumFrames = 0;
72
78
  private fpsElapsedTime = 0;
79
+ private renderRequested = false;
80
+
81
+ /// Debug data
82
+ contextSpy: ContextSpy | null = null;
73
83
 
74
84
  /**
75
85
  * Stage constructor
76
86
  */
77
87
  constructor(readonly options: StageOptions) {
78
88
  super();
79
- const { canvas, clearColor, rootId, debug, appWidth, appHeight } = options;
80
- this.txManager = new CoreTextureManager();
89
+ const {
90
+ canvas,
91
+ clearColor,
92
+ rootId,
93
+ debug,
94
+ appWidth,
95
+ appHeight,
96
+ enableContextSpy,
97
+ numImageWorkers,
98
+ } = options;
99
+
100
+ this.txManager = new CoreTextureManager(numImageWorkers);
81
101
  this.shManager = new CoreShaderManager();
82
102
  this.animationManager = new AnimationManager();
103
+ this.contextSpy = enableContextSpy ? new ContextSpy() : null;
83
104
 
84
105
  if (debug?.monitorTextureCache) {
85
106
  setInterval(() => {
@@ -99,6 +120,7 @@ export class Stage extends EventEmitter {
99
120
  bufferMemory,
100
121
  txManager: this.txManager,
101
122
  shManager: this.shManager,
123
+ contextSpy: this.contextSpy,
102
124
  });
103
125
 
104
126
  // Must do this after renderer is created
@@ -146,7 +168,7 @@ export class Stage extends EventEmitter {
146
168
  shaderProps: null,
147
169
  });
148
170
 
149
- this.scene = new Scene(rootNode);
171
+ this.root = rootNode;
150
172
 
151
173
  // execute platform start loop
152
174
  if (autoStart) {
@@ -158,8 +180,8 @@ export class Stage extends EventEmitter {
158
180
  * Update animations
159
181
  */
160
182
  updateAnimations() {
161
- const { scene, animationManager } = this;
162
- if (!scene?.root) {
183
+ const { animationManager } = this;
184
+ if (!this.root) {
163
185
  return;
164
186
  }
165
187
  this.lastFrameTime = this.currentFrameTime;
@@ -177,34 +199,32 @@ export class Stage extends EventEmitter {
177
199
  * Check if the scene has updates
178
200
  */
179
201
  hasSceneUpdates() {
180
- const { scene } = this;
181
-
182
- if (!scene?.root) {
183
- return false;
184
- }
185
-
186
- return scene?.root?.hasUpdates;
202
+ return !!this.root.updateType || this.renderRequested;
187
203
  }
188
204
 
189
205
  /**
190
206
  * Start a new frame draw
191
207
  */
192
208
  drawFrame() {
193
- const { renderer, scene } = this;
194
- if (!scene?.root) {
195
- return;
196
- }
209
+ const { renderer, renderRequested } = this;
197
210
 
198
- // reset and clear viewport
199
- scene?.root?.update(this.deltaTime);
211
+ // Update tree if needed
212
+ if (this.root.updateType !== 0) {
213
+ this.root.update(this.deltaTime);
214
+ }
200
215
 
201
216
  // test if we need to update the scene
202
217
  renderer?.reset();
203
218
 
204
- this.addQuads(scene.root);
219
+ this.addQuads(this.root);
205
220
 
206
221
  renderer?.render();
207
222
 
223
+ // Reset renderRequested flag if it was set
224
+ if (renderRequested) {
225
+ this.renderRequested = false;
226
+ }
227
+
208
228
  // If there's an FPS update interval, emit the FPS update event
209
229
  // when the specified interval has elapsed.
210
230
  const { fpsUpdateInterval } = this.options;
@@ -217,7 +237,11 @@ export class Stage extends EventEmitter {
217
237
  );
218
238
  this.fpsNumFrames = 0;
219
239
  this.fpsElapsedTime = 0;
220
- this.emit('fpsUpdate', fps);
240
+ this.emit('fpsUpdate', {
241
+ fps,
242
+ contextSpyData: this.contextSpy?.getData() ?? null,
243
+ } satisfies FpsUpdatePayload);
244
+ this.contextSpy?.reset();
221
245
  }
222
246
  }
223
247
  }
@@ -225,7 +249,10 @@ export class Stage extends EventEmitter {
225
249
  addQuads(node: CoreNode) {
226
250
  assertTruthy(this.renderer && node.globalTransform);
227
251
 
228
- node.renderQuads(this.renderer);
252
+ if (node.isRenderable) {
253
+ node.renderQuads(this.renderer);
254
+ }
255
+
229
256
  for (let i = 0; i < node.children.length; i++) {
230
257
  const child = node.children[i];
231
258
 
@@ -241,6 +268,13 @@ export class Stage extends EventEmitter {
241
268
  }
242
269
  }
243
270
 
271
+ /**
272
+ * Request a render pass without forcing an update
273
+ */
274
+ requestRender() {
275
+ this.renderRequested = true;
276
+ }
277
+
244
278
  /**
245
279
  * Given a font name, and possible renderer override, return the best compatible text renderer.
246
280
  *
@@ -305,12 +339,4 @@ export class Stage extends EventEmitter {
305
339
  // the covariant state argument in the setter method map
306
340
  return resolvedTextRenderer as unknown as TextRenderer;
307
341
  }
308
-
309
- //#region Properties
310
-
311
- get root() {
312
- return this.scene?.root || null;
313
- }
314
-
315
- //#endregion Properties
316
342
  }
@@ -98,7 +98,7 @@ export class CoreAnimation extends EventEmitter {
98
98
  }
99
99
 
100
100
  update(dt: number) {
101
- const { duration, loop, easing } = this.settings;
101
+ const { duration, loop, easing, stopMethod } = this.settings;
102
102
  if (!duration) {
103
103
  this.emit('finished', {});
104
104
  return;
@@ -108,7 +108,13 @@ export class CoreAnimation extends EventEmitter {
108
108
 
109
109
  if (this.progress > 1) {
110
110
  this.progress = loop ? 0 : 1;
111
- return this.emit('finished', {});
111
+ if (stopMethod) {
112
+ // If there's a stop method emit finished so the stop method can be applied.
113
+ // TODO: We should probably reevaluate how stopMethod is implemented as currently
114
+ // stop method 'reset' does not work when looping.
115
+ this.emit('finished', {});
116
+ return;
117
+ }
112
118
  }
113
119
 
114
120
  for (let i = 0; i < this.propsList.length; i++) {
@@ -156,5 +162,8 @@ export class CoreAnimation extends EventEmitter {
156
162
  this.node[propName] =
157
163
  startValue + (endValue - startValue) * this.progress;
158
164
  }
165
+ if (this.progress === 1) {
166
+ this.emit('finished', {});
167
+ }
159
168
  }
160
169
  }
@@ -0,0 +1,41 @@
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
+ /**
21
+ * Class that keeps track of the invocations of Context methods when
22
+ * the `enableContextSpy` renderer option is enabled.
23
+ */
24
+ export class ContextSpy {
25
+ private data: Record<string, number> = {};
26
+
27
+ reset() {
28
+ this.data = {};
29
+ }
30
+
31
+ increment(name: string) {
32
+ if (!this.data[name]) {
33
+ this.data[name] = 0;
34
+ }
35
+ this.data[name]++;
36
+ }
37
+
38
+ getData() {
39
+ return { ...this.data };
40
+ }
41
+ }
@@ -0,0 +1,124 @@
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 { type TextureData } from '../textures/Texture.js';
21
+
22
+ type MessageCallback = [(value: any) => void, (reason: any) => void];
23
+
24
+ export class ImageWorkerManager {
25
+ isWorkerSupported = !!self.Worker;
26
+ imageWorkersEnabled = true;
27
+ messageManager: Record<string, MessageCallback> = {};
28
+ workers: Worker[] = [];
29
+ workerIndex = 0;
30
+
31
+ constructor(numImageWorkers: number) {
32
+ if (this.isWorkerSupported && numImageWorkers > 0) {
33
+ this.workers = this.createWorkers(numImageWorkers);
34
+ this.workers.forEach((worker) => {
35
+ worker.onmessage = this.handleMessage.bind(this);
36
+ });
37
+ } else {
38
+ this.imageWorkersEnabled = false;
39
+ }
40
+ }
41
+
42
+ private handleMessage(event: MessageEvent) {
43
+ const { src, data, error } = event.data as {
44
+ src: string;
45
+ data?: any;
46
+ error?: string;
47
+ };
48
+ const msg = this.messageManager[src];
49
+ if (msg) {
50
+ const [resolve, reject] = msg;
51
+ delete this.messageManager[src];
52
+ if (error) {
53
+ reject(new Error(error));
54
+ } else {
55
+ resolve({ data: data as ImageBitmap });
56
+ }
57
+ }
58
+ }
59
+
60
+ private createWorkers(numWorkers = 1): Worker[] {
61
+ const workerCode = `
62
+ async function getImage(src, premultiplyAlpha) {
63
+ const response = await fetch(src);
64
+ const blob = await response.blob();
65
+ return await createImageBitmap(blob, {
66
+ premultiplyAlpha: premultiplyAlpha ? 'premultiply' : 'none',
67
+ colorSpaceConversion: 'none',
68
+ imageOrientation: 'none',
69
+ });
70
+ }
71
+
72
+ self.onmessage = async (event) => {
73
+ const { src, premultiplyAlpha } = event.data;
74
+
75
+ try {
76
+ const data = await getImage(src, premultiplyAlpha);
77
+ self.postMessage({ src, data }, [data]);
78
+ } catch (error) {
79
+ self.postMessage({ src, error: error.message });
80
+ }
81
+ };
82
+ `;
83
+
84
+ const blob: Blob = new Blob([workerCode.replace('"use strict";', '')], {
85
+ type: 'application/javascript',
86
+ });
87
+ const blobURL: string = (window.URL ? URL : webkitURL).createObjectURL(
88
+ blob,
89
+ );
90
+ const workers: Worker[] = [];
91
+ for (let i = 0; i < numWorkers; i++) {
92
+ workers.push(new Worker(blobURL));
93
+ }
94
+ return workers;
95
+ }
96
+
97
+ private getNextWorker(): Worker {
98
+ const worker = this.workers[this.workerIndex];
99
+ this.workerIndex = (this.workerIndex + 1) % this.workers.length;
100
+ return worker!;
101
+ }
102
+
103
+ private convertUrlToAbsolute(url: string): string {
104
+ const absoluteUrl = new URL(url, self.location.href);
105
+ return absoluteUrl.href;
106
+ }
107
+
108
+ getImage(src: string, premultiplyAlpha: boolean): Promise<TextureData> {
109
+ return new Promise((resolve, reject) => {
110
+ try {
111
+ if (this.workers) {
112
+ const absoluteSrcUrl = this.convertUrlToAbsolute(src);
113
+ this.messageManager[absoluteSrcUrl] = [resolve, reject];
114
+ this.getNextWorker().postMessage({
115
+ src: absoluteSrcUrl,
116
+ premultiplyAlpha,
117
+ });
118
+ }
119
+ } catch (error) {
120
+ reject(error);
121
+ }
122
+ });
123
+ }
124
+ }