@lightningjs/renderer 0.8.2 → 0.8.4

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 (153) hide show
  1. package/dist/src/core/CoreNode.d.ts +27 -1
  2. package/dist/src/core/CoreNode.js +130 -5
  3. package/dist/src/core/CoreNode.js.map +1 -1
  4. package/dist/src/core/CoreShaderManager.d.ts +2 -0
  5. package/dist/src/core/CoreShaderManager.js +9 -0
  6. package/dist/src/core/CoreShaderManager.js.map +1 -1
  7. package/dist/src/core/CoreTextNode.js +20 -1
  8. package/dist/src/core/CoreTextNode.js.map +1 -1
  9. package/dist/src/core/CoreTextureManager.d.ts +2 -0
  10. package/dist/src/core/CoreTextureManager.js +2 -0
  11. package/dist/src/core/CoreTextureManager.js.map +1 -1
  12. package/dist/src/core/Stage.d.ts +3 -2
  13. package/dist/src/core/Stage.js +36 -10
  14. package/dist/src/core/Stage.js.map +1 -1
  15. package/dist/src/core/TextureMemoryManager.d.ts +1 -0
  16. package/dist/src/core/TextureMemoryManager.js +3 -1
  17. package/dist/src/core/TextureMemoryManager.js.map +1 -1
  18. package/dist/src/core/lib/ImageWorker.d.ts +2 -1
  19. package/dist/src/core/lib/ImageWorker.js +11 -7
  20. package/dist/src/core/lib/ImageWorker.js.map +1 -1
  21. package/dist/src/core/lib/WebGlContextWrapper.d.ts +26 -1
  22. package/dist/src/core/lib/WebGlContextWrapper.js +37 -1
  23. package/dist/src/core/lib/WebGlContextWrapper.js.map +1 -1
  24. package/dist/src/core/renderers/CoreRenderer.d.ts +32 -3
  25. package/dist/src/core/renderers/CoreRenderer.js +14 -2
  26. package/dist/src/core/renderers/CoreRenderer.js.map +1 -1
  27. package/dist/src/core/renderers/canvas/CanvasCoreRenderer.d.ts +22 -0
  28. package/dist/src/core/renderers/canvas/CanvasCoreRenderer.js +166 -0
  29. package/dist/src/core/renderers/canvas/CanvasCoreRenderer.js.map +1 -0
  30. package/dist/src/core/renderers/canvas/CanvasCoreTexture.d.ts +17 -0
  31. package/dist/src/core/renderers/canvas/CanvasCoreTexture.js +124 -0
  32. package/dist/src/core/renderers/canvas/CanvasCoreTexture.js.map +1 -0
  33. package/dist/src/core/renderers/canvas/internal/C2DShaderUtils.d.ts +5 -0
  34. package/dist/src/core/renderers/canvas/internal/C2DShaderUtils.js +32 -0
  35. package/dist/src/core/renderers/canvas/internal/C2DShaderUtils.js.map +1 -0
  36. package/dist/src/core/renderers/canvas/internal/ColorUtils.d.ts +15 -0
  37. package/dist/src/core/renderers/canvas/internal/ColorUtils.js +45 -0
  38. package/dist/src/core/renderers/canvas/internal/ColorUtils.js.map +1 -0
  39. package/dist/src/core/renderers/canvas/shaders/UnsupportedShader.d.ts +10 -0
  40. package/dist/src/core/renderers/canvas/shaders/UnsupportedShader.js +43 -0
  41. package/dist/src/core/renderers/canvas/shaders/UnsupportedShader.js.map +1 -0
  42. package/dist/src/core/renderers/webgl/WebGlCoreCtxRenderTexture.d.ts +11 -0
  43. package/dist/src/core/renderers/webgl/WebGlCoreCtxRenderTexture.js +51 -0
  44. package/dist/src/core/renderers/webgl/WebGlCoreCtxRenderTexture.js.map +1 -0
  45. package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.d.ts +11 -1
  46. package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.js +22 -11
  47. package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.js.map +1 -1
  48. package/dist/src/core/renderers/webgl/WebGlCoreRenderOp.d.ts +4 -1
  49. package/dist/src/core/renderers/webgl/WebGlCoreRenderOp.js +7 -2
  50. package/dist/src/core/renderers/webgl/WebGlCoreRenderOp.js.map +1 -1
  51. package/dist/src/core/renderers/webgl/WebGlCoreRenderer.d.ts +18 -21
  52. package/dist/src/core/renderers/webgl/WebGlCoreRenderer.js +121 -41
  53. package/dist/src/core/renderers/webgl/WebGlCoreRenderer.js.map +1 -1
  54. package/dist/src/core/renderers/webgl/WebGlCoreShader.js +19 -4
  55. package/dist/src/core/renderers/webgl/WebGlCoreShader.js.map +1 -1
  56. package/dist/src/core/renderers/webgl/shaders/DefaultShader.js +4 -6
  57. package/dist/src/core/renderers/webgl/shaders/DefaultShader.js.map +1 -1
  58. package/dist/src/core/renderers/webgl/shaders/SdfShader.js +6 -1
  59. package/dist/src/core/renderers/webgl/shaders/SdfShader.js.map +1 -1
  60. package/dist/src/core/text-rendering/TextRenderingUtils.d.ts +12 -0
  61. package/dist/src/core/text-rendering/TextRenderingUtils.js +14 -0
  62. package/dist/src/core/text-rendering/TextRenderingUtils.js.map +1 -0
  63. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.d.ts +2 -1
  64. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js +6 -3
  65. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js.map +1 -1
  66. package/dist/src/core/text-rendering/renderers/TextRenderer.d.ts +2 -1
  67. package/dist/src/core/text-rendering/renderers/TextRenderer.js.map +1 -1
  68. package/dist/src/core/textures/ImageTexture.js +3 -0
  69. package/dist/src/core/textures/ImageTexture.js.map +1 -1
  70. package/dist/src/core/textures/RenderTexture.d.ts +28 -0
  71. package/dist/src/core/textures/RenderTexture.js +52 -0
  72. package/dist/src/core/textures/RenderTexture.js.map +1 -0
  73. package/dist/src/core/utils.d.ts +6 -1
  74. package/dist/src/core/utils.js +74 -82
  75. package/dist/src/core/utils.js.map +1 -1
  76. package/dist/src/main-api/INode.d.ts +9 -0
  77. package/dist/src/main-api/Inspector.js +7 -1
  78. package/dist/src/main-api/Inspector.js.map +1 -1
  79. package/dist/src/main-api/RendererMain.d.ts +4 -0
  80. package/dist/src/main-api/RendererMain.js +2 -0
  81. package/dist/src/main-api/RendererMain.js.map +1 -1
  82. package/dist/src/render-drivers/main/MainCoreDriver.js +1 -0
  83. package/dist/src/render-drivers/main/MainCoreDriver.js.map +1 -1
  84. package/dist/src/render-drivers/main/MainOnlyNode.d.ts +3 -0
  85. package/dist/src/render-drivers/main/MainOnlyNode.js +29 -0
  86. package/dist/src/render-drivers/main/MainOnlyNode.js.map +1 -1
  87. package/dist/src/render-drivers/main/MainOnlyTextNode.js +1 -0
  88. package/dist/src/render-drivers/main/MainOnlyTextNode.js.map +1 -1
  89. package/dist/src/render-drivers/threadx/NodeStruct.d.ts +3 -0
  90. package/dist/src/render-drivers/threadx/NodeStruct.js +9 -0
  91. package/dist/src/render-drivers/threadx/NodeStruct.js.map +1 -1
  92. package/dist/src/render-drivers/threadx/SharedNode.d.ts +1 -0
  93. package/dist/src/render-drivers/threadx/SharedNode.js +1 -0
  94. package/dist/src/render-drivers/threadx/SharedNode.js.map +1 -1
  95. package/dist/src/render-drivers/threadx/ThreadXCoreDriver.js +2 -0
  96. package/dist/src/render-drivers/threadx/ThreadXCoreDriver.js.map +1 -1
  97. package/dist/src/render-drivers/threadx/ThreadXMainNode.d.ts +3 -0
  98. package/dist/src/render-drivers/threadx/ThreadXMainNode.js +7 -0
  99. package/dist/src/render-drivers/threadx/ThreadXMainNode.js.map +1 -1
  100. package/dist/src/render-drivers/threadx/worker/ThreadXRendererNode.js +1 -0
  101. package/dist/src/render-drivers/threadx/worker/ThreadXRendererNode.js.map +1 -1
  102. package/dist/src/render-drivers/threadx/worker/ThreadXRendererTextNode.js +1 -0
  103. package/dist/src/render-drivers/threadx/worker/ThreadXRendererTextNode.js.map +1 -1
  104. package/dist/src/render-drivers/threadx/worker/renderer.js +2 -0
  105. package/dist/src/render-drivers/threadx/worker/renderer.js.map +1 -1
  106. package/dist/src/render-drivers/utils.js +1 -1
  107. package/dist/src/render-drivers/utils.js.map +1 -1
  108. package/dist/src/utils.d.ts +12 -6
  109. package/dist/src/utils.js +19 -9
  110. package/dist/src/utils.js.map +1 -1
  111. package/dist/tsconfig.dist.tsbuildinfo +1 -1
  112. package/package.json +1 -1
  113. package/src/core/CoreNode.ts +164 -8
  114. package/src/core/CoreShaderManager.ts +13 -0
  115. package/src/core/CoreTextNode.ts +25 -0
  116. package/src/core/CoreTextureManager.ts +3 -0
  117. package/src/core/Stage.ts +44 -10
  118. package/src/core/TextureMemoryManager.ts +3 -1
  119. package/src/core/lib/ImageWorker.ts +13 -8
  120. package/src/core/lib/WebGlContextWrapper.ts +51 -1
  121. package/src/core/renderers/CoreRenderer.ts +46 -6
  122. package/src/core/renderers/canvas/CanvasCoreRenderer.ts +223 -0
  123. package/src/core/renderers/canvas/CanvasCoreTexture.ts +144 -0
  124. package/src/core/renderers/canvas/internal/C2DShaderUtils.ts +37 -0
  125. package/src/core/renderers/canvas/internal/ColorUtils.ts +55 -0
  126. package/src/core/renderers/canvas/shaders/UnsupportedShader.ts +48 -0
  127. package/src/core/renderers/webgl/WebGlCoreCtxRenderTexture.ts +79 -0
  128. package/src/core/renderers/webgl/WebGlCoreCtxTexture.ts +26 -24
  129. package/src/core/renderers/webgl/WebGlCoreRenderOp.ts +4 -2
  130. package/src/core/renderers/webgl/WebGlCoreRenderer.ts +173 -70
  131. package/src/core/renderers/webgl/WebGlCoreShader.ts +29 -4
  132. package/src/core/renderers/webgl/shaders/DefaultShader.ts +4 -6
  133. package/src/core/renderers/webgl/shaders/SdfShader.ts +6 -1
  134. package/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.ts +10 -1
  135. package/src/core/text-rendering/renderers/TextRenderer.ts +3 -0
  136. package/src/core/textures/ImageTexture.ts +3 -0
  137. package/src/core/textures/RenderTexture.ts +81 -0
  138. package/src/core/utils.ts +101 -93
  139. package/src/main-api/INode.ts +11 -0
  140. package/src/main-api/Inspector.ts +6 -1
  141. package/src/main-api/RendererMain.ts +8 -0
  142. package/src/render-drivers/main/MainCoreDriver.ts +1 -0
  143. package/src/render-drivers/main/MainOnlyNode.ts +44 -0
  144. package/src/render-drivers/main/MainOnlyTextNode.ts +1 -0
  145. package/src/render-drivers/threadx/NodeStruct.ts +10 -0
  146. package/src/render-drivers/threadx/SharedNode.ts +2 -0
  147. package/src/render-drivers/threadx/ThreadXCoreDriver.ts +2 -0
  148. package/src/render-drivers/threadx/ThreadXMainNode.ts +9 -0
  149. package/src/render-drivers/threadx/worker/ThreadXRendererNode.ts +1 -0
  150. package/src/render-drivers/threadx/worker/ThreadXRendererTextNode.ts +1 -0
  151. package/src/render-drivers/threadx/worker/renderer.ts +2 -0
  152. package/src/render-drivers/utils.ts +1 -1
  153. package/src/utils.ts +21 -9
@@ -37,6 +37,7 @@ import type {
37
37
  TextureFreedEventHandler,
38
38
  TextureLoadedEventHandler,
39
39
  } from './textures/Texture.js';
40
+ import { RenderTexture } from './textures/RenderTexture.js';
40
41
  import type {
41
42
  Dimensions,
42
43
  NodeTextureFailedPayload,
@@ -104,6 +105,7 @@ export interface CoreNodeProps {
104
105
  pivotX: number;
105
106
  pivotY: number;
106
107
  rotation: number;
108
+ rtt: boolean;
107
109
  }
108
110
 
109
111
  type ICoreNode = Omit<
@@ -212,6 +214,16 @@ export enum UpdateType {
212
214
  */
213
215
  IsRenderable = 1024,
214
216
 
217
+ /**
218
+ * Render Texture update
219
+ */
220
+ RenderTexture = 2048,
221
+
222
+ /**
223
+ * Track if parent has render texture
224
+ */
225
+ ParentRenderTexture = 4096,
226
+
215
227
  /**
216
228
  * None
217
229
  */
@@ -220,7 +232,7 @@ export enum UpdateType {
220
232
  /**
221
233
  * All
222
234
  */
223
- All = 2047,
235
+ All = 8191,
224
236
  }
225
237
 
226
238
  export class CoreNode extends EventEmitter implements ICoreNode {
@@ -252,6 +264,8 @@ export class CoreNode extends EventEmitter implements ICoreNode {
252
264
  public premultipliedColorBl = 0;
253
265
  public premultipliedColorBr = 0;
254
266
  public calcZIndex = 0;
267
+ public hasRTTupdates = false;
268
+ public parentHasRenderTexture = false;
255
269
 
256
270
  constructor(protected stage: Stage, props: CoreNodeProps) {
257
271
  super();
@@ -261,6 +275,10 @@ export class CoreNode extends EventEmitter implements ICoreNode {
261
275
  };
262
276
  // Allow for parent to be processed appropriately
263
277
  this.parent = props.parent;
278
+
279
+ // Allow for Render Texture to be processed appropriately
280
+ this.rtt = props.rtt;
281
+
264
282
  this.updateScaleRotateTransform();
265
283
  }
266
284
 
@@ -324,6 +342,13 @@ export class CoreNode extends EventEmitter implements ICoreNode {
324
342
  // Texture was loaded. In case the RAF loop has already stopped, we request
325
343
  // a render to ensure the texture is rendered.
326
344
  this.stage.requestRender();
345
+
346
+ // If parent has a render texture, flag that we need to update
347
+ // @todo: Reserve type for RTT updates
348
+ if (this.parentHasRenderTexture) {
349
+ this.setRTTUpdates(1);
350
+ }
351
+
327
352
  this.emit('loaded', {
328
353
  type: 'texture',
329
354
  dimensions,
@@ -373,6 +398,11 @@ export class CoreNode extends EventEmitter implements ICoreNode {
373
398
  if (parent && !(parent.updateType & UpdateType.Children)) {
374
399
  parent.setUpdateType(UpdateType.Children);
375
400
  }
401
+ // If node is part of RTT texture
402
+ // Flag that we need to update
403
+ if (this.parentHasRenderTexture) {
404
+ this.setRTTUpdates(type);
405
+ }
376
406
  }
377
407
 
378
408
  sortChildren() {
@@ -421,16 +451,43 @@ export class CoreNode extends EventEmitter implements ICoreNode {
421
451
 
422
452
  const parent = this.props.parent;
423
453
  let childUpdateType = UpdateType.None;
454
+
455
+ if (this.updateType & UpdateType.ParentRenderTexture) {
456
+ let p = this.parent;
457
+ while (p) {
458
+ if (p.rtt) {
459
+ this.parentHasRenderTexture = true;
460
+ }
461
+ p = p.parent;
462
+ }
463
+ }
464
+
465
+ // If we have render texture updates and not already running a full update
466
+ if (
467
+ this.updateType ^ UpdateType.All &&
468
+ this.updateType & UpdateType.RenderTexture
469
+ ) {
470
+ this.children.forEach((child) => {
471
+ child.setUpdateType(UpdateType.All);
472
+ });
473
+ }
474
+
424
475
  if (this.updateType & UpdateType.Global) {
425
476
  assertTruthy(this.localTransform);
477
+
426
478
  this.globalTransform = Matrix3d.copy(
427
479
  parent?.globalTransform || this.localTransform,
428
480
  this.globalTransform,
429
481
  );
430
482
 
483
+ if (this.parentHasRenderTexture && this.props.parent?.rtt) {
484
+ this.globalTransform = Matrix3d.identity();
485
+ }
486
+
431
487
  if (parent) {
432
488
  this.globalTransform.multiply(this.localTransform);
433
489
  }
490
+
434
491
  this.calculateRenderCoords();
435
492
  this.updateBoundingRect();
436
493
  this.setUpdateType(
@@ -511,7 +568,11 @@ export class CoreNode extends EventEmitter implements ICoreNode {
511
568
  parent.setUpdateType(UpdateType.ZIndexSortedChildren);
512
569
  }
513
570
 
514
- if (this.updateType & UpdateType.Children && this.children.length) {
571
+ if (
572
+ this.updateType & UpdateType.Children &&
573
+ this.children.length &&
574
+ !this.rtt
575
+ ) {
515
576
  this.children.forEach((child) => {
516
577
  // Trigger the depenedent update types on the child
517
578
  child.setUpdateType(childUpdateType);
@@ -755,7 +816,6 @@ export class CoreNode extends EventEmitter implements ICoreNode {
755
816
  );
756
817
  }
757
818
  }
758
-
759
819
  /**
760
820
  * This function calculates the clipping rectangle for a node.
761
821
  *
@@ -824,13 +884,30 @@ export class CoreNode extends EventEmitter implements ICoreNode {
824
884
  this.props.texture = null;
825
885
  this.props.shader = null;
826
886
 
887
+ if (this.rtt) {
888
+ this.stage.renderer.removeRTTNode(this);
889
+ }
890
+
827
891
  this.removeAllListeners();
828
892
  this.parent = null;
829
893
  }
830
894
 
831
895
  renderQuads(renderer: CoreRenderer): void {
832
- const { width, height, texture, textureOptions, shader, shaderProps } =
896
+ const { width, height, texture, textureOptions, shader, shaderProps, rtt } =
833
897
  this.props;
898
+
899
+ // Prevent quad rendering if parent has a render texture
900
+ // and renderer is not currently rendering to a texture
901
+ if (this.parentHasRenderTexture) {
902
+ if (!renderer.renderToTextureActive) {
903
+ return;
904
+ }
905
+ // Prevent quad rendering if parent render texture is not the active render texture
906
+ if (this.parentRenderTexture !== renderer.activeRttNode) {
907
+ return;
908
+ }
909
+ }
910
+
834
911
  const {
835
912
  premultipliedColorTl,
836
913
  premultipliedColorTr,
@@ -863,10 +940,10 @@ export class CoreNode extends EventEmitter implements ICoreNode {
863
940
  tb: gt.tb,
864
941
  tc: gt.tc,
865
942
  td: gt.td,
943
+ rtt,
944
+ parentHasRenderTexture: this.parentHasRenderTexture,
945
+ framebufferDimensions: this.framebufferDimensions,
866
946
  });
867
-
868
- // Calculate absolute X and Y based on all ancestors
869
- // renderer.addQuad(absX, absY, w, h, color, texture, textureOptions, zIndex);
870
947
  }
871
948
 
872
949
  //#region Properties
@@ -915,6 +992,10 @@ export class CoreNode extends EventEmitter implements ICoreNode {
915
992
  if (this.props.width !== value) {
916
993
  this.props.width = value;
917
994
  this.setUpdateType(UpdateType.Local);
995
+
996
+ if (this.props.rtt) {
997
+ this.setUpdateType(UpdateType.RenderTexture);
998
+ }
918
999
  }
919
1000
  }
920
1001
 
@@ -926,6 +1007,10 @@ export class CoreNode extends EventEmitter implements ICoreNode {
926
1007
  if (this.props.height !== value) {
927
1008
  this.props.height = value;
928
1009
  this.setUpdateType(UpdateType.Local);
1010
+
1011
+ if (this.props.rtt) {
1012
+ this.setUpdateType(UpdateType.RenderTexture);
1013
+ }
929
1014
  }
930
1015
  }
931
1016
 
@@ -1235,9 +1320,80 @@ export class CoreNode extends EventEmitter implements ICoreNode {
1235
1320
  newParent.setUpdateType(
1236
1321
  UpdateType.Children | UpdateType.ZIndexSortedChildren,
1237
1322
  );
1238
- }
1239
1323
 
1324
+ if (newParent.rtt || newParent.parentHasRenderTexture) {
1325
+ this.setRTTUpdates(UpdateType.All);
1326
+ }
1327
+ }
1240
1328
  this.updateScaleRotateTransform();
1241
1329
  }
1330
+
1331
+ get rtt(): boolean {
1332
+ return this.props.rtt;
1333
+ }
1334
+
1335
+ set rtt(value: boolean) {
1336
+ if (!value) {
1337
+ if (this.props.rtt) {
1338
+ this.props.rtt = false;
1339
+ this.unloadTexture();
1340
+ this.setUpdateType(UpdateType.All);
1341
+
1342
+ this.children.forEach((child) => {
1343
+ child.parentHasRenderTexture = false;
1344
+ });
1345
+
1346
+ this.stage.renderer?.removeRTTNode(this);
1347
+ }
1348
+ return;
1349
+ }
1350
+
1351
+ this.props.rtt = true;
1352
+ this.hasRTTupdates = true;
1353
+ this.setUpdateType(UpdateType.All);
1354
+
1355
+ this.children.forEach((child) => {
1356
+ child.setUpdateType(UpdateType.All);
1357
+ });
1358
+
1359
+ // Store RTT nodes in a separate list
1360
+ this.stage.renderer?.renderToTexture(this);
1361
+ }
1362
+
1363
+ /**
1364
+ * Returns the framebuffer dimensions of the node.
1365
+ * If the node has a render texture, the dimensions are the same as the node's dimensions.
1366
+ * If the node does not have a render texture, the dimensions are inherited from the parent.
1367
+ * If the node parent has a render texture and the node is a render texture, the nodes dimensions are used.
1368
+ */
1369
+ get framebufferDimensions(): Dimensions {
1370
+ if (this.parentHasRenderTexture && !this.rtt && this.parent) {
1371
+ return this.parent.framebufferDimensions;
1372
+ }
1373
+ return { width: this.width, height: this.height };
1374
+ }
1375
+
1376
+ /**
1377
+ * Returns the parent render texture node if it exists.
1378
+ */
1379
+ get parentRenderTexture(): CoreNode | null {
1380
+ let parent = this.parent;
1381
+ while (parent) {
1382
+ if (parent.rtt) {
1383
+ return parent;
1384
+ }
1385
+ parent = parent.parent;
1386
+ }
1387
+ return null;
1388
+ }
1389
+
1390
+ get texture(): Texture | null {
1391
+ return this.props.texture;
1392
+ }
1393
+
1394
+ setRTTUpdates(type: number) {
1395
+ this.hasRTTupdates = true;
1396
+ this.parent?.setRTTUpdates(type);
1397
+ }
1242
1398
  //#endregion Properties
1243
1399
  }
@@ -61,6 +61,8 @@ import {
61
61
  type RadialProgressEffectProps,
62
62
  } from './renderers/webgl/shaders/effects/RadialProgressEffect.js';
63
63
  import { HolePunchEffect } from './renderers/webgl/shaders/effects/HolePunchEffect.js';
64
+ import { WebGlCoreShader } from './renderers/webgl/WebGlCoreShader.js';
65
+ import { UnsupportedShader } from './renderers/canvas/shaders/UnsupportedShader.js';
64
66
 
65
67
  export type { FadeOutEffectProps };
66
68
  export type { LinearGradientEffectProps };
@@ -75,6 +77,7 @@ export interface ShaderMap {
75
77
  RoundedRectangle: typeof RoundedRectangle;
76
78
  DynamicShader: typeof DynamicShader;
77
79
  SdfShader: typeof SdfShader;
80
+ UnsupportedShader: typeof UnsupportedShader;
78
81
  }
79
82
 
80
83
  export type ShaderNode<Type extends keyof ShaderMap> = {
@@ -170,6 +173,16 @@ export class CoreShaderManager {
170
173
  throw new Error(`Shader type "${shType as string}" is not registered`);
171
174
  }
172
175
 
176
+ if (
177
+ this.renderer.mode === 'canvas' &&
178
+ ShaderClass.prototype instanceof WebGlCoreShader
179
+ ) {
180
+ return {
181
+ shader: new UnsupportedShader(shType) as InstanceType<ShaderMap[Type]>,
182
+ props: props as Record<string, unknown>,
183
+ };
184
+ }
185
+
173
186
  if (shType === 'DynamicShader') {
174
187
  return this.loadDynamicShader(props!);
175
188
  }
@@ -34,6 +34,7 @@ import type {
34
34
  } from '../common/CommonTypes.js';
35
35
  import type { Rect, RectWithValid } from './lib/utils.js';
36
36
  import { assertTruthy } from '../utils.js';
37
+ import { Matrix3d } from './lib/Matrix3d.js';
37
38
 
38
39
  export interface CoreTextNodeProps extends CoreNodeProps, TrProps {
39
40
  text: string;
@@ -354,11 +355,35 @@ export class CoreTextNode extends CoreNode implements ICoreTextNode {
354
355
 
355
356
  override renderQuads(renderer: CoreRenderer) {
356
357
  assertTruthy(this.globalTransform);
358
+
359
+ // Prevent quad rendering if parent has a render texture
360
+ // and this node is not the render texture
361
+ if (this.parentHasRenderTexture) {
362
+ if (!renderer.renderToTextureActive) {
363
+ return;
364
+ }
365
+ // Prevent quad rendering if parent render texture is not the active render texture
366
+ if (this.parentRenderTexture !== renderer.activeRttNode) {
367
+ return;
368
+ }
369
+ }
370
+
371
+ if (this.parentHasRenderTexture && this.props.parent?.rtt) {
372
+ this.globalTransform = Matrix3d.identity();
373
+ if (this.localTransform) {
374
+ this.globalTransform.multiply(this.localTransform);
375
+ }
376
+ }
377
+
378
+ assertTruthy(this.globalTransform);
379
+
357
380
  this.textRenderer.renderQuads(
358
381
  this.trState,
359
382
  this.globalTransform,
360
383
  this.clippingRect,
361
384
  this.worldAlpha,
385
+ this.parentHasRenderTexture,
386
+ this.framebufferDimensions,
362
387
  );
363
388
  }
364
389
 
@@ -25,6 +25,7 @@ import { ColorTexture } from './textures/ColorTexture.js';
25
25
  import { ImageTexture } from './textures/ImageTexture.js';
26
26
  import { NoiseTexture } from './textures/NoiseTexture.js';
27
27
  import { SubTexture } from './textures/SubTexture.js';
28
+ import { RenderTexture } from './textures/RenderTexture.js';
28
29
  import type { Texture } from './textures/Texture.js';
29
30
 
30
31
  /**
@@ -40,6 +41,7 @@ export interface TextureMap {
40
41
  ImageTexture: typeof ImageTexture;
41
42
  NoiseTexture: typeof NoiseTexture;
42
43
  SubTexture: typeof SubTexture;
44
+ RenderTexture: typeof RenderTexture;
43
45
  }
44
46
 
45
47
  export type ExtractProps<Type> = Type extends { z$__type__Props: infer Props }
@@ -173,6 +175,7 @@ export class CoreTextureManager {
173
175
  this.registerTextureType('ColorTexture', ColorTexture);
174
176
  this.registerTextureType('NoiseTexture', NoiseTexture);
175
177
  this.registerTextureType('SubTexture', SubTexture);
178
+ this.registerTextureType('RenderTexture', RenderTexture);
176
179
  }
177
180
 
178
181
  registerTextureType<Type extends keyof TextureMap>(
package/src/core/Stage.ts CHANGED
@@ -18,7 +18,7 @@
18
18
  */
19
19
  import { startLoop, getTimeStamp } from './platform.js';
20
20
  import { WebGlCoreRenderer } from './renderers/webgl/WebGlCoreRenderer.js';
21
- import { assertTruthy } from '../utils.js';
21
+ import { assertTruthy, setPremultiplyMode } from '../utils.js';
22
22
  import { AnimationManager } from './animations/AnimationManager.js';
23
23
  import { CoreNode } from './CoreNode.js';
24
24
  import { CoreTextureManager } from './CoreTextureManager.js';
@@ -38,6 +38,11 @@ import type {
38
38
  FrameTickPayload,
39
39
  } from '../common/CommonTypes.js';
40
40
  import { TextureMemoryManager } from './TextureMemoryManager.js';
41
+ import type {
42
+ CoreRenderer,
43
+ CoreRendererOptions,
44
+ } from './renderers/CoreRenderer.js';
45
+ import { CanvasCoreRenderer } from './renderers/canvas/CanvasCoreRenderer.js';
41
46
 
42
47
  export interface StageOptions {
43
48
  rootId: number;
@@ -52,6 +57,7 @@ export interface StageOptions {
52
57
  fpsUpdateInterval: number;
53
58
  enableContextSpy: boolean;
54
59
  numImageWorkers: number;
60
+ renderMode: 'webgl' | 'canvas';
55
61
 
56
62
  debug?: {
57
63
  monitorTextureCache?: boolean;
@@ -79,7 +85,7 @@ export class Stage extends EventEmitter {
79
85
  public readonly fontManager: TrFontManager;
80
86
  public readonly textRenderers: Partial<TextRendererMap>;
81
87
  public readonly shManager: CoreShaderManager;
82
- public readonly renderer: WebGlCoreRenderer;
88
+ public readonly renderer: CoreRenderer;
83
89
  public readonly root: CoreNode;
84
90
  public readonly boundsMargin: [number, number, number, number];
85
91
 
@@ -110,6 +116,7 @@ export class Stage extends EventEmitter {
110
116
  enableContextSpy,
111
117
  numImageWorkers,
112
118
  txMemByteThreshold,
119
+ renderMode,
113
120
  } = options;
114
121
 
115
122
  this.txManager = new CoreTextureManager(numImageWorkers);
@@ -135,7 +142,7 @@ export class Stage extends EventEmitter {
135
142
  }, 1000);
136
143
  }
137
144
 
138
- this.renderer = new WebGlCoreRenderer({
145
+ const rendererOptions: CoreRendererOptions = {
139
146
  stage: this,
140
147
  canvas,
141
148
  pixelRatio:
@@ -146,15 +153,27 @@ export class Stage extends EventEmitter {
146
153
  txMemManager: this.txMemManager,
147
154
  shManager: this.shManager,
148
155
  contextSpy: this.contextSpy,
149
- });
156
+ };
157
+
158
+ if (renderMode === 'canvas') {
159
+ this.renderer = new CanvasCoreRenderer(rendererOptions);
160
+ } else {
161
+ this.renderer = new WebGlCoreRenderer(rendererOptions);
162
+ }
163
+ setPremultiplyMode(renderMode);
150
164
 
151
165
  // Must do this after renderer is created
152
166
  this.txManager.renderer = this.renderer;
153
167
 
154
- this.textRenderers = {
155
- canvas: new CanvasTextRenderer(this),
156
- sdf: new SdfTextRenderer(this),
157
- };
168
+ this.textRenderers =
169
+ renderMode === 'webgl'
170
+ ? {
171
+ canvas: new CanvasTextRenderer(this),
172
+ sdf: new SdfTextRenderer(this),
173
+ }
174
+ : {
175
+ canvas: new CanvasTextRenderer(this),
176
+ };
158
177
  this.fontManager = new TrFontManager(this.textRenderers);
159
178
 
160
179
  // create root node
@@ -192,6 +211,7 @@ export class Stage extends EventEmitter {
192
211
  textureOptions: null,
193
212
  shader: null,
194
213
  shaderProps: null,
214
+ rtt: false,
195
215
  });
196
216
 
197
217
  this.root = rootNode;
@@ -237,17 +257,31 @@ export class Stage extends EventEmitter {
237
257
  */
238
258
  drawFrame() {
239
259
  const { renderer, renderRequested } = this;
260
+ assertTruthy(renderer);
240
261
 
241
262
  // Update tree if needed
242
263
  if (this.root.updateType !== 0) {
243
264
  this.root.update(this.deltaTime, this.root.clippingRect);
244
265
  }
245
266
 
246
- // test if we need to update the scene
247
- renderer?.reset();
267
+ // Reset render operations and clear the canvas
268
+ renderer.reset();
269
+
270
+ // Check if we need to garbage collect
271
+ if (renderer.txMemManager.gcRequested) {
272
+ renderer.txMemManager.gc();
273
+ }
274
+
275
+ // If we have RTT nodes draw them first
276
+ // So we can use them as textures in the main scene
277
+ if (renderer.rttNodes.length > 0) {
278
+ renderer.renderRTTNodes();
279
+ }
248
280
 
281
+ // Fill quads buffer
249
282
  this.addQuads(this.root);
250
283
 
284
+ // Perform render pass
251
285
  renderer?.render();
252
286
 
253
287
  this.calculateFps();
@@ -22,6 +22,7 @@ export class TextureMemoryManager {
22
22
  private memUsed = 0;
23
23
  private textures: Map<CoreContextTexture, number> = new Map();
24
24
  private threshold: number;
25
+ public gcRequested = false;
25
26
 
26
27
  /**
27
28
  * @param byteThreshold Number of texture bytes to trigger garbage collection
@@ -52,11 +53,12 @@ export class TextureMemoryManager {
52
53
  }
53
54
 
54
55
  if (this.memUsed > this.threshold) {
55
- this.gc();
56
+ this.gcRequested = true;
56
57
  }
57
58
  }
58
59
 
59
60
  gc() {
61
+ this.gcRequested = false;
60
62
  this.textures.forEach((byteSize, ctxTexture) => {
61
63
  if (!ctxTexture.renderable) {
62
64
  ctxTexture.free();
@@ -23,9 +23,10 @@ type MessageCallback = [(value: any) => void, (reason: any) => void];
23
23
 
24
24
  export class ImageWorkerManager {
25
25
  imageWorkersEnabled = true;
26
- messageManager: Record<string, MessageCallback> = {};
26
+ messageManager: Record<number, MessageCallback> = {};
27
27
  workers: Worker[] = [];
28
28
  workerIndex = 0;
29
+ nextId = 0;
29
30
 
30
31
  constructor(numImageWorkers: number) {
31
32
  this.workers = this.createWorkers(numImageWorkers);
@@ -35,15 +36,16 @@ export class ImageWorkerManager {
35
36
  }
36
37
 
37
38
  private handleMessage(event: MessageEvent) {
38
- const { src, data, error } = event.data as {
39
+ const { id, data, error } = event.data as {
40
+ id: number;
39
41
  src: string;
40
42
  data?: any;
41
43
  error?: string;
42
44
  };
43
- const msg = this.messageManager[src];
45
+ const msg = this.messageManager[id];
44
46
  if (msg) {
45
47
  const [resolve, reject] = msg;
46
- delete this.messageManager[src];
48
+ delete this.messageManager[id];
47
49
  if (error) {
48
50
  reject(new Error(error));
49
51
  } else {
@@ -91,16 +93,17 @@ export class ImageWorkerManager {
91
93
  });
92
94
  }
93
95
 
94
- self.onmessage = async (event) => {
96
+ self.onmessage = (event) => {
97
+ var id = event.data.id;
95
98
  var src = event.data.src;
96
99
  var premultiplyAlpha = event.data.premultiplyAlpha;
97
100
 
98
101
  getImage(src, premultiplyAlpha)
99
102
  .then(function(data) {
100
- self.postMessage({ src: src, data: data }, [data.data]);
103
+ self.postMessage({ id: id, data: data }, [data.data]);
101
104
  })
102
105
  .catch(function(error) {
103
- self.postMessage({ src: src, error: error.message });
106
+ self.postMessage({ id: id, error: error.message });
104
107
  });
105
108
  };
106
109
  `;
@@ -135,8 +138,10 @@ export class ImageWorkerManager {
135
138
  try {
136
139
  if (this.workers) {
137
140
  const absoluteSrcUrl = this.convertUrlToAbsolute(src);
138
- this.messageManager[absoluteSrcUrl] = [resolve, reject];
141
+ const id = this.nextId++;
142
+ this.messageManager[id] = [resolve, reject];
139
143
  this.getNextWorker().postMessage({
144
+ id,
140
145
  src: absoluteSrcUrl,
141
146
  premultiplyAlpha,
142
147
  });
@@ -75,6 +75,7 @@ export class WebGlContextWrapper {
75
75
  public readonly RGBA;
76
76
  public readonly UNSIGNED_BYTE;
77
77
  public readonly UNPACK_PREMULTIPLY_ALPHA_WEBGL;
78
+ public readonly UNPACK_FLIP_Y_WEBGL;
78
79
  public readonly FLOAT;
79
80
  public readonly TRIANGLES;
80
81
  public readonly UNSIGNED_SHORT;
@@ -86,6 +87,7 @@ export class WebGlContextWrapper {
86
87
  public readonly COMPILE_STATUS;
87
88
  public readonly LINK_STATUS;
88
89
  public readonly DYNAMIC_DRAW;
90
+ public readonly COLOR_ATTACHMENT0;
89
91
  //#endregion WebGL Enums
90
92
 
91
93
  constructor(private gl: WebGLRenderingContext | WebGL2RenderingContext) {
@@ -161,6 +163,7 @@ export class WebGlContextWrapper {
161
163
  this.RGBA = gl.RGBA;
162
164
  this.UNSIGNED_BYTE = gl.UNSIGNED_BYTE;
163
165
  this.UNPACK_PREMULTIPLY_ALPHA_WEBGL = gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL;
166
+ this.UNPACK_FLIP_Y_WEBGL = gl.UNPACK_FLIP_Y_WEBGL;
164
167
  this.FLOAT = gl.FLOAT;
165
168
  this.TRIANGLES = gl.TRIANGLES;
166
169
  this.UNSIGNED_SHORT = gl.UNSIGNED_SHORT;
@@ -175,6 +178,7 @@ export class WebGlContextWrapper {
175
178
  this.COMPILE_STATUS = gl.COMPILE_STATUS;
176
179
  this.LINK_STATUS = gl.LINK_STATUS;
177
180
  this.DYNAMIC_DRAW = gl.DYNAMIC_DRAW;
181
+ this.COLOR_ATTACHMENT0 = gl.COLOR_ATTACHMENT0;
178
182
  }
179
183
  /**
180
184
  * Returns true if the WebGL context is WebGL2
@@ -533,7 +537,7 @@ export class WebGlContextWrapper {
533
537
 
534
538
  /**
535
539
  * ```
536
- * createBuffer();
540
+ * gl.createBuffer();
537
541
  * ```
538
542
  *
539
543
  * @returns
@@ -543,6 +547,52 @@ export class WebGlContextWrapper {
543
547
  return gl.createBuffer();
544
548
  }
545
549
 
550
+ /**
551
+ * ```
552
+ * gl.createFramebuffer();
553
+ * ```
554
+ * @returns
555
+ */
556
+ createFramebuffer() {
557
+ const { gl } = this;
558
+ return gl.createFramebuffer();
559
+ }
560
+
561
+ /**
562
+ * ```
563
+ * gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
564
+ * ```
565
+ *
566
+ * @param framebuffer
567
+ */
568
+ bindFramebuffer(framebuffer: WebGLFramebuffer | null) {
569
+ const { gl } = this;
570
+ gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
571
+ }
572
+
573
+ /**
574
+ * ```
575
+ * gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
576
+ * ```
577
+ * @remarks
578
+ * **WebGL Difference**: Bind target is always `gl.FRAMEBUFFER` and textarget is always `gl.TEXTURE_2D`
579
+ */
580
+
581
+ framebufferTexture2D(
582
+ attachment: GLenum,
583
+ texture: WebGLTexture | null,
584
+ level: GLint,
585
+ ) {
586
+ const { gl } = this;
587
+ gl.framebufferTexture2D(
588
+ gl.FRAMEBUFFER,
589
+ attachment,
590
+ gl.TEXTURE_2D,
591
+ texture,
592
+ level,
593
+ );
594
+ }
595
+
546
596
  /**
547
597
  * ```
548
598
  * gl.clear(gl.COLOR_BUFFER_BIT);