@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
package/src/core/utils.ts CHANGED
@@ -23,8 +23,6 @@
23
23
  * @module
24
24
  */
25
25
 
26
- import memo from 'memize';
27
-
28
26
  export const EPSILON = 0.000001;
29
27
  export let ARRAY_TYPE =
30
28
  typeof Float32Array !== 'undefined' ? Float32Array : Array;
@@ -121,97 +119,107 @@ const getTimingBezier = (
121
119
  };
122
120
  };
123
121
 
124
- export const getTimingFunction = memo(
125
- (str: string): ((time: number) => number | undefined) => {
126
- switch (str) {
127
- case 'linear':
128
- return function (time: number) {
129
- return time;
130
- };
131
- case 'ease':
132
- return getTimingBezier(0.25, 0.1, 0.25, 1.0);
133
-
134
- case 'ease-in':
135
- return getTimingBezier(0.42, 0, 1.0, 1.0);
136
- case 'ease-out':
137
- return getTimingBezier(0, 0, 0.58, 1.0);
138
- case 'ease-in-out':
139
- return getTimingBezier(0.42, 0, 0.58, 1.0);
140
-
141
- case 'ease-in-sine':
142
- return getTimingBezier(0.12, 0, 0.39, 0);
143
- case 'ease-out-sine':
144
- return getTimingBezier(0.12, 0, 0.39, 0);
145
- case 'ease-in-out-sine':
146
- return getTimingBezier(0.37, 0, 0.63, 1);
147
-
148
- case 'ease-in-cubic':
149
- return getTimingBezier(0.32, 0, 0.67, 0);
150
- case 'ease-out-cubic':
151
- return getTimingBezier(0.33, 1, 0.68, 1);
152
- case 'ease-in-out-cubic':
153
- return getTimingBezier(0.65, 0, 0.35, 1);
154
-
155
- case 'ease-in-circ':
156
- return getTimingBezier(0.55, 0, 1, 0.45);
157
- case 'ease-out-circ':
158
- return getTimingBezier(0, 0.55, 0.45, 1);
159
- case 'ease-in-out-circ':
160
- return getTimingBezier(0.85, 0, 0.15, 1);
161
-
162
- case 'ease-in-back':
163
- return getTimingBezier(0.36, 0, 0.66, -0.56);
164
- case 'ease-out-back':
165
- return getTimingBezier(0.34, 1.56, 0.64, 1);
166
- case 'ease-in-out-back':
167
- return getTimingBezier(0.68, -0.6, 0.32, 1.6);
168
-
169
- case 'step-start':
170
- return function () {
171
- return 1;
172
- };
173
- case 'step-end':
174
- return function (time: number) {
175
- return time === 1 ? 1 : 0;
176
- };
177
- default:
178
- // eslint-disable-next-line no-case-declarations
179
- const s = 'cubic-bezier(';
180
- if (str && str.indexOf(s) === 0) {
181
- const parts = str
182
- .substr(s.length, str.length - s.length - 1)
183
- .split(',');
184
- if (parts.length !== 4) {
185
- console.warn('Unknown timing function: ' + str);
186
- // Fallback: use linear.
187
- return function (time) {
188
- return time;
189
- };
190
- }
191
- const a = parseFloat(parts[0] || '0.42');
192
- const b = parseFloat(parts[1] || '0');
193
- const c = parseFloat(parts[2] || '1');
194
- const d = parseFloat(parts[3] || '1');
195
-
196
- if (isNaN(a) || isNaN(b) || isNaN(c) || isNaN(d)) {
197
- console.warn(' Unknown timing function: ' + str);
198
- // Fallback: use linear.
199
- return function (time) {
200
- return time;
201
- };
202
- }
203
-
204
- return getTimingBezier(a, b, c, d);
205
- } else {
206
- console.warn('Unknown timing function: ' + str);
207
- // Fallback: use linear.
208
- return function (time) {
209
- return time;
210
- };
211
- }
212
- }
213
- },
214
- );
122
+ interface TimingFunctionMap {
123
+ [key: string]: (time: number) => number | undefined;
124
+ }
125
+
126
+ type TimingLookupArray = number[];
127
+ interface TimingLookup {
128
+ [key: string]: TimingLookupArray;
129
+ }
130
+
131
+ const timingMapping: TimingFunctionMap = {};
132
+
133
+ const timingLookup: TimingLookup = {
134
+ ease: [0.25, 0.1, 0.25, 1.0],
135
+ 'ease-in': [0.42, 0, 1.0, 1.0],
136
+ 'ease-out': [0, 0, 0.58, 1.0],
137
+ 'ease-in-out': [0.42, 0, 0.58, 1.0],
138
+ 'ease-in-sine': [0.12, 0, 0.39, 0],
139
+ 'ease-out-sine': [0.12, 0, 0.39, 0],
140
+ 'ease-in-out-sine': [0.37, 0, 0.63, 1],
141
+ 'ease-in-cubic': [0.32, 0, 0.67, 0],
142
+ 'ease-out-cubic': [0.33, 1, 0.68, 1],
143
+ 'ease-in-out-cubic': [0.65, 0, 0.35, 1],
144
+ 'ease-in-circ': [0.55, 0, 1, 0.45],
145
+ 'ease-out-circ': [0, 0.55, 0.45, 1],
146
+ 'ease-in-out-circ': [0.85, 0, 0.15, 1],
147
+ 'ease-in-back': [0.36, 0, 0.66, -0.56],
148
+ 'ease-out-back': [0.34, 1.56, 0.64, 1],
149
+ 'ease-in-out-back': [0.68, -0.6, 0.32, 1.6],
150
+ };
151
+
152
+ const defaultTiming = (t: number): number => t;
153
+
154
+ const parseCubicBezier = (str: string) => {
155
+ //cubic-bezier(0.84, 0.52, 0.56, 0.6)
156
+ const regex = /-?\d*\.?\d+/g;
157
+ const match = str.match(regex);
158
+
159
+ if (match) {
160
+ const [num1, num2, num3, num4] = match;
161
+ const a = parseFloat(num1 || '0.42');
162
+ const b = parseFloat(num2 || '0');
163
+ const c = parseFloat(num3 || '1');
164
+ const d = parseFloat(num4 || '1');
165
+
166
+ const timing = getTimingBezier(a, b, c, d);
167
+ timingMapping[str] = timing;
168
+
169
+ return timing;
170
+ }
171
+
172
+ // parse failed, return linear
173
+ console.warn('Unknown cubic-bezier timing: ' + str);
174
+ return defaultTiming;
175
+ };
176
+
177
+ export const getTimingFunction = (
178
+ str: string,
179
+ ): ((time: number) => number | undefined) => {
180
+ if (str === '') {
181
+ return defaultTiming;
182
+ }
183
+
184
+ if (timingMapping[str] !== undefined) {
185
+ return timingMapping[str] || defaultTiming;
186
+ }
187
+
188
+ if (str === 'linear') {
189
+ return (time: number) => {
190
+ return time;
191
+ };
192
+ }
193
+
194
+ if (str === 'step-start') {
195
+ return () => {
196
+ return 1;
197
+ };
198
+ }
199
+
200
+ if (str === 'step-end') {
201
+ return (time: number) => {
202
+ return time === 1 ? 1 : 0;
203
+ };
204
+ }
205
+
206
+ if (timingLookup[str] !== undefined) {
207
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
208
+ // @ts-ignore - TS doesn't understand that we've checked for undefined
209
+ const [a, b, c, d] = timingLookup[str];
210
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
211
+ const timing = getTimingBezier(a, b, c, d);
212
+ timingMapping[str] = timing;
213
+ return timing;
214
+ }
215
+
216
+ if (str.startsWith('cubic-bezier')) {
217
+ return parseCubicBezier(str);
218
+ }
219
+
220
+ console.warn('Unknown timing function: ' + str);
221
+ return defaultTiming;
222
+ };
215
223
 
216
224
  if (!Math.hypot)
217
225
  Math.hypot = (...args: number[]) => {
@@ -405,6 +405,17 @@ export interface INodeWritableProps {
405
405
  * - `2 * Math.PI`: 360 rotation clockwise
406
406
  */
407
407
  rotation: number;
408
+
409
+ /**
410
+ * Whether the Node is rendered to a texture
411
+ *
412
+ * @remarks
413
+ * TBD
414
+ *
415
+ * @default false
416
+ */
417
+ rtt: boolean;
418
+
408
419
  /**
409
420
  * Node data element for custom data storage (optional)
410
421
  *
@@ -393,7 +393,12 @@ export class Inspector {
393
393
  if (property === 'data') {
394
394
  for (const key in value) {
395
395
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
396
- div.setAttribute(`data-${key}`, String(value[key]));
396
+ const keyValue: unknown = value[key];
397
+ if (keyValue === undefined) {
398
+ div.removeAttribute(`data-${key}`);
399
+ } else {
400
+ div.setAttribute(`data-${key}`, String(keyValue));
401
+ }
397
402
  }
398
403
  return;
399
404
  }
@@ -41,6 +41,7 @@ import { EventEmitter } from '../common/EventEmitter.js';
41
41
  import { Inspector } from './Inspector.js';
42
42
  import { santizeCustomDataMap } from '../render-drivers/utils.js';
43
43
  import { isProductionEnvironment } from '../utils.js';
44
+ import type { StageOptions } from '../core/Stage.js';
44
45
 
45
46
  /**
46
47
  * An immutable reference to a specific Texture type
@@ -270,6 +271,11 @@ export interface RendererMainSettings {
270
271
  * @defaultValue `false` (disabled)
271
272
  */
272
273
  enableInspector?: boolean;
274
+
275
+ /**
276
+ * Renderer mode
277
+ */
278
+ renderMode?: 'webgl' | 'canvas';
273
279
  }
274
280
 
275
281
  /**
@@ -344,6 +350,7 @@ export class RendererMain extends EventEmitter {
344
350
  settings.numImageWorkers !== undefined ? settings.numImageWorkers : 2,
345
351
  enableContextSpy: settings.enableContextSpy ?? false,
346
352
  enableInspector: settings.enableInspector ?? false,
353
+ renderMode: settings.renderMode ?? 'webgl',
347
354
  };
348
355
  this.settings = resolvedSettings;
349
356
 
@@ -563,6 +570,7 @@ export class RendererMain extends EventEmitter {
563
570
  pivotX: props.pivotX ?? props.pivot ?? 0.5,
564
571
  pivotY: props.pivotY ?? props.pivot ?? 0.5,
565
572
  rotation: props.rotation ?? 0,
573
+ rtt: props.rtt ?? false,
566
574
  data: data,
567
575
  };
568
576
  }
@@ -64,6 +64,7 @@ export class MainCoreDriver implements ICoreDriver {
64
64
  fpsUpdateInterval: rendererSettings.fpsUpdateInterval,
65
65
  enableContextSpy: rendererSettings.enableContextSpy,
66
66
  numImageWorkers: rendererSettings.numImageWorkers,
67
+ renderMode: rendererSettings.renderMode,
67
68
  debug: {
68
69
  monitorTextureCache: false,
69
70
  },
@@ -105,6 +105,7 @@ export class MainOnlyNode extends EventEmitter implements INode {
105
105
  shaderProps: null,
106
106
  texture: null,
107
107
  textureOptions: null,
108
+ rtt: props.rtt,
108
109
  });
109
110
  // Forward loaded/failed events
110
111
  this.coreNode.on('loaded', this.onTextureLoaded);
@@ -121,6 +122,7 @@ export class MainOnlyNode extends EventEmitter implements INode {
121
122
  this.shader = props.shader;
122
123
  this.texture = props.texture;
123
124
  this.src = props.src;
125
+ this.rtt = props.rtt;
124
126
  this._data = props.data;
125
127
  }
126
128
 
@@ -145,6 +147,16 @@ export class MainOnlyNode extends EventEmitter implements INode {
145
147
  }
146
148
 
147
149
  set width(value: number) {
150
+ if (value !== this.coreNode.width && this.coreNode.rtt) {
151
+ this.texture = this.rendererMain.createTexture(
152
+ 'RenderTexture',
153
+ {
154
+ width: this.width,
155
+ height: this.height,
156
+ },
157
+ { preload: true, flipY: true },
158
+ );
159
+ }
148
160
  this.coreNode.width = value;
149
161
  }
150
162
 
@@ -153,6 +165,16 @@ export class MainOnlyNode extends EventEmitter implements INode {
153
165
  }
154
166
 
155
167
  set height(value: number) {
168
+ if (value !== this.coreNode.height && this.coreNode.rtt) {
169
+ this.texture = this.rendererMain.createTexture(
170
+ 'RenderTexture',
171
+ {
172
+ width: this.width,
173
+ height: this.height,
174
+ },
175
+ { preload: true, flipY: true },
176
+ );
177
+ }
156
178
  this.coreNode.height = value;
157
179
  }
158
180
 
@@ -422,6 +444,28 @@ export class MainOnlyNode extends EventEmitter implements INode {
422
444
  }
423
445
  }
424
446
 
447
+ get rtt(): boolean {
448
+ return this.coreNode.rtt;
449
+ }
450
+
451
+ set rtt(value: boolean) {
452
+ if (value) {
453
+ this.texture = this.rendererMain.createTexture(
454
+ 'RenderTexture',
455
+ {
456
+ width: this.width,
457
+ height: this.height,
458
+ },
459
+ { preload: true, flipY: true },
460
+ );
461
+ }
462
+ this.coreNode.rtt = value;
463
+ }
464
+
465
+ get parentHasRenderTexture(): boolean {
466
+ return this.coreNode.parentHasRenderTexture;
467
+ }
468
+
425
469
  private onTextureLoaded: NodeLoadedEventHandler = (target, payload) => {
426
470
  this.emit('loaded', payload);
427
471
  };
@@ -94,6 +94,7 @@ export class MainOnlyTextNode extends MainOnlyNode implements ITextNode {
94
94
  textureOptions: null,
95
95
  shader: null,
96
96
  shaderProps: null,
97
+ rtt: false,
97
98
  }),
98
99
  );
99
100
  }
@@ -48,6 +48,7 @@ export interface NodeStructWritableProps {
48
48
  pivotX: number;
49
49
  pivotY: number;
50
50
  rotation: number;
51
+ rtt: boolean;
51
52
  }
52
53
 
53
54
  export class NodeStruct
@@ -307,4 +308,13 @@ export class NodeStruct
307
308
  set zIndexLocked(value: number) {
308
309
  // Decorator will handle this
309
310
  }
311
+
312
+ @structProp('boolean')
313
+ get rtt(): boolean {
314
+ return false;
315
+ }
316
+
317
+ set rtt(value: boolean) {
318
+ // Decorator will handle this
319
+ }
310
320
  }
@@ -63,6 +63,7 @@ export class SharedNode extends SharedObject {
63
63
  pivotX: sharedNodeStruct.pivotX,
64
64
  pivotY: sharedNodeStruct.pivotY,
65
65
  rotation: sharedNodeStruct.rotation,
66
+ rtt: sharedNodeStruct.rtt,
66
67
  } satisfies NodeStructWritableProps);
67
68
  }
68
69
 
@@ -96,4 +97,5 @@ export class SharedNode extends SharedObject {
96
97
  protected declare parentId: number;
97
98
  declare zIndex: number;
98
99
  declare zIndexLocked: number;
100
+ declare rtt: boolean;
99
101
  }
@@ -174,6 +174,7 @@ export class ThreadXCoreDriver implements ICoreDriver {
174
174
  pivotX: props.pivotX,
175
175
  pivotY: props.pivotY,
176
176
  rotation: props.rotation,
177
+ rtt: props.rtt,
177
178
  } satisfies NodeStructWritableProps);
178
179
 
179
180
  const node = new ThreadXMainNode(rendererMain, bufferStruct);
@@ -221,6 +222,7 @@ export class ThreadXCoreDriver implements ICoreDriver {
221
222
  pivotX: props.pivotX,
222
223
  pivotY: props.pivotY,
223
224
  rotation: props.rotation,
225
+ rtt: props.rtt,
224
226
 
225
227
  // Text specific properties
226
228
  text: props.text,
@@ -43,6 +43,7 @@ export class ThreadXMainNode extends SharedNode implements INode {
43
43
  protected _shader: ShaderRef | null = null;
44
44
  protected _data: CustomDataMap | undefined = {};
45
45
  private _src = '';
46
+ private _parentHasRenderTexture = false;
46
47
 
47
48
  /**
48
49
  * FinalizationRegistry for animation controllers. When an animation
@@ -168,6 +169,14 @@ export class ThreadXMainNode extends SharedNode implements INode {
168
169
  }
169
170
  }
170
171
 
172
+ set parentHasRenderTexture(hasRenderTexture: boolean) {
173
+ this._parentHasRenderTexture = hasRenderTexture;
174
+ }
175
+
176
+ get parentHasRenderTexture(): boolean {
177
+ return this._parentHasRenderTexture;
178
+ }
179
+
171
180
  get children(): ThreadXMainNode[] {
172
181
  return this._children;
173
182
  }
@@ -231,6 +231,7 @@ export class ThreadXRendererNode extends SharedNode {
231
231
  pivotX: sharedNodeStruct.pivotX,
232
232
  pivotY: sharedNodeStruct.pivotY,
233
233
  rotation: sharedNodeStruct.rotation,
234
+ rtt: sharedNodeStruct.rtt,
234
235
 
235
236
  // These are passed in via message handlers
236
237
  shader: null,
@@ -68,6 +68,7 @@ export class ThreadXRendererTextNode extends ThreadXRendererNode {
68
68
  scaleX: sharedNodeStruct.scaleX,
69
69
  scaleY: sharedNodeStruct.scaleY,
70
70
  rotation: sharedNodeStruct.rotation,
71
+ rtt: sharedNodeStruct.rtt,
71
72
 
72
73
  // These are passed in via message handlers
73
74
  shader: null,
@@ -75,6 +75,7 @@ const threadx = ThreadX.init({
75
75
  fpsUpdateInterval: message.fpsUpdateInterval,
76
76
  enableContextSpy: message.enableContextSpy,
77
77
  numImageWorkers: message.numImageWorkers,
78
+ renderMode: 'webgl',
78
79
  debug: {
79
80
  monitorTextureCache: false,
80
81
  },
@@ -113,6 +114,7 @@ const threadx = ThreadX.init({
113
114
  pivotX: coreRootNode.pivotX,
114
115
  pivotY: coreRootNode.pivotY,
115
116
  rotation: coreRootNode.rotation,
117
+ rtt: coreRootNode.rtt,
116
118
  } satisfies NodeStructWritableProps);
117
119
 
118
120
  // Share the root node that was created by the Stage with the main worker.
@@ -58,7 +58,7 @@ export async function loadCoreExtension(
58
58
  }
59
59
 
60
60
  export function santizeCustomDataMap(d: CustomDataMap): CustomDataMap {
61
- const validTypes = { boolean: true, string: true, number: true };
61
+ const validTypes = { boolean: true, string: true, number: true, undefined: true };
62
62
 
63
63
  const keys = Object.keys(d);
64
64
  for (let i = 0; i < keys.length; i++) {
package/src/utils.ts CHANGED
@@ -143,19 +143,30 @@ export function mergeColorAlpha(rgba: number, alpha: number): number {
143
143
  return ((r << 24) | (g << 16) | (b << 8) | a) >>> 0;
144
144
  }
145
145
 
146
+ let premultiplyRGB = true;
147
+
148
+ /**
149
+ * RGB components should not be premultiplied when using Canvas renderer
150
+ * @param mode Renderer mode
151
+ */
152
+ export function setPremultiplyMode(mode: 'webgl' | 'canvas'): void {
153
+ premultiplyRGB = mode === 'webgl';
154
+ }
155
+
146
156
  /**
147
157
  * Given an RGBA encoded number, returns back the RGBA number with it's alpha
148
- * component multiplied by the passed `alpha` parameter. Before returning, the
149
- * final alpha value is multiplied into the color channels.
158
+ * component multiplied by the passed `alpha` parameter.
159
+ *
160
+ * For the webGl renderer, each color channel is premultiplied by the final alpha value.
150
161
  *
151
162
  * @remarks
152
163
  * If `flipEndianess` is set to true, the function will returned an ABGR encoded number
153
164
  * which is useful when the color value needs to be passed into a shader attribute.
154
165
  *
155
- * NOTE: This method returns a PREMULTIPLIED alpha color which is generally only useful
156
- * in the context of the internal rendering process. Use {@link mergeColorAlpha} if you
157
- * need to blend an alpha value into a color in the context of the Renderer's
158
- * main API.
166
+ * NOTE: Depending on the mode set by {@link setPremultiplyMode}, this method returns
167
+ * a PREMULTIPLIED alpha color which is generally only useful in the context of the
168
+ * internal rendering process. Use {@link mergeColorAlpha} if you need to blend an alpha
169
+ * value into a color in the context of the Renderer's main API.
159
170
  *
160
171
  * @internalRemarks
161
172
  * Do not expose this method in the main API because Renderer users should instead use
@@ -173,9 +184,10 @@ export function mergeColorAlphaPremultiplied(
173
184
  flipEndianess = false,
174
185
  ): number {
175
186
  const newAlpha = ((rgba & 0xff) / 255) * alpha;
176
- const r = Math.trunc((rgba >>> 24) * newAlpha);
177
- const g = Math.trunc(((rgba >>> 16) & 0xff) * newAlpha);
178
- const b = Math.trunc(((rgba >>> 8) & 0xff) * newAlpha);
187
+ const rgbAlpha = premultiplyRGB ? newAlpha : 1;
188
+ const r = Math.trunc((rgba >>> 24) * rgbAlpha);
189
+ const g = Math.trunc(((rgba >>> 16) & 0xff) * rgbAlpha);
190
+ const b = Math.trunc(((rgba >>> 8) & 0xff) * rgbAlpha);
179
191
  const a = Math.trunc(newAlpha * 255);
180
192
 
181
193
  if (flipEndianess) {