@lightningjs/renderer 3.0.0-beta22 → 3.0.0-beta23

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 (166) hide show
  1. package/README.md +93 -0
  2. package/dist/exports/platform.d.ts +7 -0
  3. package/dist/exports/platform.js +27 -0
  4. package/dist/exports/platform.js.map +1 -0
  5. package/dist/src/core/AutosizeManager.d.ts +29 -0
  6. package/dist/src/core/AutosizeManager.js +169 -0
  7. package/dist/src/core/AutosizeManager.js.map +1 -0
  8. package/dist/src/core/CoreNode.js +10 -14
  9. package/dist/src/core/CoreNode.js.map +1 -1
  10. package/dist/src/core/CoreTextureManager.d.ts +0 -13
  11. package/dist/src/core/CoreTextureManager.js +4 -78
  12. package/dist/src/core/CoreTextureManager.js.map +1 -1
  13. package/dist/src/core/Stage.js +2 -12
  14. package/dist/src/core/Stage.js.map +1 -1
  15. package/dist/src/core/animations/Animation.d.ts +21 -0
  16. package/dist/src/core/animations/Animation.js +194 -0
  17. package/dist/src/core/animations/Animation.js.map +1 -0
  18. package/dist/src/core/animations/CoreAnimationController.d.ts +1 -1
  19. package/dist/src/core/animations/CoreAnimationController.js +4 -2
  20. package/dist/src/core/animations/CoreAnimationController.js.map +1 -1
  21. package/dist/src/core/animations/Playback.d.ts +64 -0
  22. package/dist/src/core/animations/Playback.js +169 -0
  23. package/dist/src/core/animations/Playback.js.map +1 -0
  24. package/dist/src/core/animations/Transition.d.ts +27 -0
  25. package/dist/src/core/animations/Transition.js +52 -0
  26. package/dist/src/core/animations/Transition.js.map +1 -0
  27. package/dist/src/core/animations/utils.d.ts +2 -0
  28. package/dist/src/core/animations/utils.js +136 -0
  29. package/dist/src/core/animations/utils.js.map +1 -0
  30. package/dist/src/core/lib/collectionUtils.js +3 -2
  31. package/dist/src/core/lib/collectionUtils.js.map +1 -1
  32. package/dist/src/core/lib/utils.d.ts +0 -5
  33. package/dist/src/core/lib/utils.js +0 -63
  34. package/dist/src/core/lib/utils.js.map +1 -1
  35. package/dist/src/core/platforms/GlContextWrapper.d.ts +136 -0
  36. package/dist/src/core/platforms/GlContextWrapper.js +32 -0
  37. package/dist/src/core/platforms/GlContextWrapper.js.map +1 -0
  38. package/dist/src/core/platforms/Platform.d.ts +74 -13
  39. package/dist/src/core/platforms/Platform.js +18 -0
  40. package/dist/src/core/platforms/Platform.js.map +1 -1
  41. package/dist/src/core/platforms/web/WebGlContextWrapper.d.ts +776 -0
  42. package/dist/src/core/platforms/web/WebGlContextWrapper.js +1208 -0
  43. package/dist/src/core/platforms/web/WebGlContextWrapper.js.map +1 -0
  44. package/dist/src/core/platforms/web/WebPlatform.d.ts +13 -2
  45. package/dist/src/core/platforms/web/WebPlatform.js +109 -8
  46. package/dist/src/core/platforms/web/WebPlatform.js.map +1 -1
  47. package/dist/src/core/platforms/web/WebPlatformChrome50.d.ts +17 -0
  48. package/dist/src/core/platforms/web/WebPlatformChrome50.js +50 -0
  49. package/dist/src/core/platforms/web/WebPlatformChrome50.js.map +1 -0
  50. package/dist/src/core/platforms/web/WebPlatformLegacy.d.ts +18 -0
  51. package/dist/src/core/platforms/web/WebPlatformLegacy.js +99 -0
  52. package/dist/src/core/platforms/web/WebPlatformLegacy.js.map +1 -0
  53. package/dist/src/core/platforms/web/WebPlatformNext.d.ts +21 -0
  54. package/dist/src/core/platforms/web/WebPlatformNext.js +52 -0
  55. package/dist/src/core/platforms/web/WebPlatformNext.js.map +1 -0
  56. package/dist/src/core/platforms/web/lib/ImageWorker.d.ts +15 -0
  57. package/dist/src/core/platforms/web/lib/ImageWorker.js +189 -0
  58. package/dist/src/core/platforms/web/lib/ImageWorker.js.map +1 -0
  59. package/dist/src/core/platforms/web/lib/createImageBitmap.d.ts +1 -0
  60. package/dist/src/core/platforms/web/lib/createImageBitmap.js +27 -0
  61. package/dist/src/core/platforms/web/lib/createImageBitmap.js.map +1 -0
  62. package/dist/src/core/platforms/web/lib/textureCompression.d.ts +26 -0
  63. package/dist/src/core/platforms/web/lib/textureCompression.js +301 -0
  64. package/dist/src/core/platforms/web/lib/textureCompression.js.map +1 -0
  65. package/dist/src/core/platforms/web/lib/textureSvg.d.ts +7 -0
  66. package/dist/src/core/platforms/web/lib/textureSvg.js +51 -0
  67. package/dist/src/core/platforms/web/lib/textureSvg.js.map +1 -0
  68. package/dist/src/core/platforms/web/lib/utils.d.ts +5 -0
  69. package/dist/src/core/platforms/web/lib/utils.js +86 -0
  70. package/dist/src/core/platforms/web/lib/utils.js.map +1 -0
  71. package/dist/src/core/renderers/CoreRenderer.d.ts +1 -9
  72. package/dist/src/core/renderers/CoreRenderer.js +2 -4
  73. package/dist/src/core/renderers/CoreRenderer.js.map +1 -1
  74. package/dist/src/core/renderers/canvas/CanvasRenderer.d.ts +3 -2
  75. package/dist/src/core/renderers/canvas/CanvasRenderer.js +4 -3
  76. package/dist/src/core/renderers/canvas/CanvasRenderer.js.map +1 -1
  77. package/dist/src/core/renderers/webgl/SdfRenderOp.js +3 -2
  78. package/dist/src/core/renderers/webgl/SdfRenderOp.js.map +1 -1
  79. package/dist/src/core/renderers/webgl/WebGlCtxRenderTexture.d.ts +2 -2
  80. package/dist/src/core/renderers/webgl/WebGlCtxRenderTexture.js.map +1 -1
  81. package/dist/src/core/renderers/webgl/WebGlCtxSubTexture.d.ts +2 -2
  82. package/dist/src/core/renderers/webgl/WebGlCtxSubTexture.js.map +1 -1
  83. package/dist/src/core/renderers/webgl/WebGlCtxTexture.d.ts +3 -3
  84. package/dist/src/core/renderers/webgl/WebGlCtxTexture.js +1 -2
  85. package/dist/src/core/renderers/webgl/WebGlCtxTexture.js.map +1 -1
  86. package/dist/src/core/renderers/webgl/WebGlRenderer.d.ts +5 -5
  87. package/dist/src/core/renderers/webgl/WebGlRenderer.js +7 -8
  88. package/dist/src/core/renderers/webgl/WebGlRenderer.js.map +1 -1
  89. package/dist/src/core/renderers/webgl/WebGlShaderNode.d.ts +2 -2
  90. package/dist/src/core/renderers/webgl/WebGlShaderProgram.d.ts +2 -2
  91. package/dist/src/core/renderers/webgl/WebGlShaderProgram.js.map +1 -1
  92. package/dist/src/core/renderers/webgl/internal/RendererUtils.d.ts +4 -4
  93. package/dist/src/core/renderers/webgl/internal/RendererUtils.js.map +1 -1
  94. package/dist/src/core/renderers/webgl/internal/ShaderUtils.d.ts +3 -3
  95. package/dist/src/core/renderers/webgl/internal/ShaderUtils.js.map +1 -1
  96. package/dist/src/core/renderers/webgl/shaders/effects/LinearGradientEffect.js +24 -8
  97. package/dist/src/core/renderers/webgl/shaders/effects/LinearGradientEffect.js.map +1 -1
  98. package/dist/src/core/renderers/webgl/shaders/effects/RadialGradientEffect.js +25 -8
  99. package/dist/src/core/renderers/webgl/shaders/effects/RadialGradientEffect.js.map +1 -1
  100. package/dist/src/core/shaders/webgl/Border.js +6 -4
  101. package/dist/src/core/shaders/webgl/Border.js.map +1 -1
  102. package/dist/src/core/shaders/webgl/RoundedWithBorder.js +6 -4
  103. package/dist/src/core/shaders/webgl/RoundedWithBorder.js.map +1 -1
  104. package/dist/src/core/shaders/webgl/RoundedWithBorderAndShadow.js +6 -4
  105. package/dist/src/core/shaders/webgl/RoundedWithBorderAndShadow.js.map +1 -1
  106. package/dist/src/core/shaders/webgl/SdfShadowShader.d.ts +9 -0
  107. package/dist/src/core/shaders/webgl/SdfShadowShader.js +100 -0
  108. package/dist/src/core/shaders/webgl/SdfShadowShader.js.map +1 -0
  109. package/dist/src/core/text-rendering/CanvasFont.d.ts +1 -1
  110. package/dist/src/core/text-rendering/CanvasFont.js +2 -6
  111. package/dist/src/core/text-rendering/CanvasFont.js.map +1 -1
  112. package/dist/src/core/text-rendering/CoreFont.d.ts +1 -1
  113. package/dist/src/core/text-rendering/CoreFont.js +1 -1
  114. package/dist/src/core/text-rendering/CoreFont.js.map +1 -1
  115. package/dist/src/core/text-rendering/FontManager.js +2 -1
  116. package/dist/src/core/text-rendering/FontManager.js.map +1 -1
  117. package/dist/src/core/textures/ImageTexture.d.ts +24 -11
  118. package/dist/src/core/textures/ImageTexture.js +32 -95
  119. package/dist/src/core/textures/ImageTexture.js.map +1 -1
  120. package/dist/src/core/textures/Texture.d.ts +1 -1
  121. package/dist/src/main-api/Renderer.js +18 -21
  122. package/dist/src/main-api/Renderer.js.map +1 -1
  123. package/dist/src/utils.d.ts +0 -2
  124. package/dist/src/utils.js +0 -36
  125. package/dist/src/utils.js.map +1 -1
  126. package/dist/tsconfig.dist.tsbuildinfo +1 -1
  127. package/dist/tsconfig.tsbuildinfo +1 -0
  128. package/exports/platform.ts +31 -0
  129. package/package.json +3 -2
  130. package/src/core/CoreNode.ts +11 -15
  131. package/src/core/CoreTextureManager.ts +10 -103
  132. package/src/core/Stage.ts +1 -14
  133. package/src/core/animations/CoreAnimationController.ts +5 -2
  134. package/src/core/lib/collectionUtils.ts +3 -2
  135. package/src/core/lib/utils.ts +0 -78
  136. package/src/core/platforms/GlContextWrapper.ts +291 -0
  137. package/src/core/platforms/Platform.ts +121 -28
  138. package/src/core/{lib → platforms/web}/WebGlContextWrapper.ts +129 -4
  139. package/src/core/platforms/web/WebPlatform.ts +171 -22
  140. package/src/core/platforms/web/WebPlatformChrome50.ts +57 -0
  141. package/src/core/platforms/web/WebPlatformLegacy.ts +140 -0
  142. package/src/core/platforms/web/WebPlatformNext.ts +57 -0
  143. package/src/core/{lib → platforms/web/lib}/ImageWorker.ts +10 -74
  144. package/src/core/platforms/web/lib/createImageBitmap.ts +40 -0
  145. package/src/core/{lib → platforms/web/lib}/textureCompression.ts +19 -138
  146. package/src/core/{lib → platforms/web/lib}/textureSvg.ts +3 -15
  147. package/src/core/platforms/web/lib/utils.ts +105 -0
  148. package/src/core/renderers/CoreRenderer.ts +2 -11
  149. package/src/core/renderers/canvas/CanvasRenderer.ts +6 -4
  150. package/src/core/renderers/webgl/SdfRenderOp.ts +3 -2
  151. package/src/core/renderers/webgl/WebGlCtxRenderTexture.ts +2 -2
  152. package/src/core/renderers/webgl/WebGlCtxSubTexture.ts +2 -2
  153. package/src/core/renderers/webgl/WebGlCtxTexture.ts +3 -4
  154. package/src/core/renderers/webgl/WebGlRenderer.ts +12 -19
  155. package/src/core/renderers/webgl/WebGlShaderNode.ts +2 -2
  156. package/src/core/renderers/webgl/WebGlShaderProgram.ts +2 -2
  157. package/src/core/renderers/webgl/internal/RendererUtils.ts +4 -8
  158. package/src/core/renderers/webgl/internal/ShaderUtils.ts +3 -3
  159. package/src/core/shaders/webgl/Border.ts +6 -4
  160. package/src/core/shaders/webgl/RoundedWithBorder.ts +6 -4
  161. package/src/core/shaders/webgl/RoundedWithBorderAndShadow.ts +6 -4
  162. package/src/core/textures/ImageTexture.ts +42 -161
  163. package/src/core/textures/Texture.ts +1 -1
  164. package/src/main-api/Renderer.ts +24 -22
  165. package/src/utils.ts +0 -47
  166. package/src/core/lib/validateImageBitmap.ts +0 -87
@@ -1,14 +1,34 @@
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 2026 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
+
1
20
  /* eslint-disable @typescript-eslint/no-unsafe-return */
2
21
  /* eslint-disable @typescript-eslint/no-explicit-any */
3
22
  /* eslint-disable @typescript-eslint/no-unsafe-argument */
4
23
 
5
- import { assertTruthy, isProductionEnvironment } from '../../utils.js';
6
24
  import type {
7
25
  Vec2,
8
26
  Vec3,
9
27
  Vec4,
10
- } from '../renderers/webgl/internal/ShaderUtils.js';
11
- import { isWebGl2 } from '../renderers/webgl/internal/WebGlUtils.js';
28
+ } from '../../renderers/webgl/internal/ShaderUtils.js';
29
+ import { isWebGl2 } from '../../renderers/webgl/internal/WebGlUtils.js';
30
+ import { GlContextWrapper } from '../GlContextWrapper.js';
31
+ import type { CompressedData } from '../../textures/Texture.js';
12
32
 
13
33
  /**
14
34
  * Optimized WebGL Context Wrapper
@@ -29,7 +49,7 @@ import { isWebGl2 } from '../renderers/webgl/internal/WebGlUtils.js';
29
49
  * A subset of GLenum constants are also exposed as properties on this class
30
50
  * for convenience.
31
51
  */
32
- export class WebGlContextWrapper {
52
+ export class WebGlContextWrapper extends GlContextWrapper {
33
53
  //#region Cached WebGL State
34
54
  private activeTextureUnit = 0;
35
55
  private texture2dUnits: Array<WebGLTexture | null>;
@@ -97,6 +117,7 @@ export class WebGlContextWrapper {
97
117
  //#endregion WebGL Enums
98
118
 
99
119
  constructor(private gl: WebGLRenderingContext | WebGL2RenderingContext) {
120
+ super();
100
121
  // The following code extracts the current state of the WebGL context
101
122
  // to our local JavaScript cached version of it. This is so we can
102
123
  // avoid making WebGL calls if we don't need to.
@@ -1367,6 +1388,110 @@ export class WebGlContextWrapper {
1367
1388
  }
1368
1389
  return null;
1369
1390
  }
1391
+
1392
+ /**
1393
+ *
1394
+ * Compressed Textures support
1395
+ */
1396
+ uploadKTX(texture: WebGLTexture, data: CompressedData) {
1397
+ const { glInternalFormat, mipmaps, w: width, h: height, blockInfo } = data;
1398
+ if (mipmaps === undefined) {
1399
+ return;
1400
+ }
1401
+
1402
+ this.bindTexture(texture);
1403
+
1404
+ const blockWidth = blockInfo.width;
1405
+ const blockHeight = blockInfo.height;
1406
+ let w = width;
1407
+ let h = height;
1408
+
1409
+ for (let i = 0; i < mipmaps!.length; i++) {
1410
+ let view = new Uint8Array(mipmaps![i]!);
1411
+
1412
+ const uploadW = Math.ceil(w / blockWidth) * blockWidth;
1413
+ const uploadH = Math.ceil(h / blockHeight) * blockHeight;
1414
+
1415
+ const expectedBytes =
1416
+ Math.ceil(w / blockWidth) *
1417
+ Math.ceil(h / blockHeight) *
1418
+ blockInfo.bytes;
1419
+
1420
+ if (view.byteLength < expectedBytes) {
1421
+ const padded = new Uint8Array(expectedBytes);
1422
+ padded.set(view);
1423
+ view = padded;
1424
+ }
1425
+
1426
+ this.compressedTexImage2D(i, glInternalFormat, uploadW, uploadH, 0, view);
1427
+
1428
+ w = Math.max(1, w >> 1);
1429
+ h = Math.max(1, h >> 1);
1430
+ }
1431
+
1432
+ this.texParameteri(this.TEXTURE_WRAP_S, this.CLAMP_TO_EDGE);
1433
+ this.texParameteri(this.TEXTURE_WRAP_T, this.CLAMP_TO_EDGE);
1434
+ this.texParameteri(this.TEXTURE_MAG_FILTER, this.LINEAR);
1435
+ this.texParameteri(
1436
+ this.TEXTURE_MIN_FILTER,
1437
+ mipmaps!.length > 1 ? this.LINEAR_MIPMAP_LINEAR : this.LINEAR,
1438
+ );
1439
+ }
1440
+
1441
+ uploadPVR(texture: WebGLTexture, data: CompressedData) {
1442
+ const { glInternalFormat, mipmaps, w: width, h: height } = data;
1443
+ if (mipmaps === undefined) {
1444
+ return;
1445
+ }
1446
+ this.bindTexture(texture);
1447
+
1448
+ let w = width;
1449
+ let h = height;
1450
+
1451
+ for (let i = 0; i < mipmaps!.length; i++) {
1452
+ this.compressedTexImage2D(
1453
+ i,
1454
+ glInternalFormat,
1455
+ w,
1456
+ h,
1457
+ 0,
1458
+ new Uint8Array(mipmaps[i]!),
1459
+ );
1460
+
1461
+ w = Math.max(1, w >> 1);
1462
+ h = Math.max(1, h >> 1);
1463
+ }
1464
+
1465
+ this.texParameteri(this.TEXTURE_WRAP_S, this.CLAMP_TO_EDGE);
1466
+ this.texParameteri(this.TEXTURE_WRAP_T, this.CLAMP_TO_EDGE);
1467
+ this.texParameteri(this.TEXTURE_MAG_FILTER, this.LINEAR);
1468
+ this.texParameteri(
1469
+ this.TEXTURE_MIN_FILTER,
1470
+ mipmaps.length > 1 ? this.LINEAR_MIPMAP_LINEAR : this.LINEAR,
1471
+ );
1472
+ }
1473
+
1474
+ uploadASTC(texture: WebGLTexture, data: CompressedData) {
1475
+ if (this.getExtension('WEBGL_compressed_texture_astc') === null) {
1476
+ throw new Error('ASTC compressed textures not supported by this device');
1477
+ }
1478
+
1479
+ this.bindTexture(texture);
1480
+
1481
+ const { glInternalFormat, mipmaps, w, h } = data;
1482
+ if (mipmaps === undefined) {
1483
+ return;
1484
+ }
1485
+
1486
+ const view = new Uint8Array(mipmaps[0]!);
1487
+
1488
+ this.compressedTexImage2D(0, glInternalFormat, w, h, 0, view);
1489
+ // ASTC textures MUST use no mipmaps unless stored
1490
+ this.texParameteri(this.TEXTURE_WRAP_S, this.CLAMP_TO_EDGE);
1491
+ this.texParameteri(this.TEXTURE_WRAP_T, this.CLAMP_TO_EDGE);
1492
+ this.texParameteri(this.TEXTURE_MAG_FILTER, this.LINEAR);
1493
+ this.texParameteri(this.TEXTURE_MIN_FILTER, this.LINEAR);
1494
+ }
1370
1495
  }
1371
1496
 
1372
1497
  // prettier-ignore
@@ -1,5 +1,37 @@
1
- import { Platform } from '../Platform.js';
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 2026 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 { Platform, type PlatformSettings } from '../Platform.js';
21
+ import { ImageWorkerManager } from './lib/ImageWorker.js';
2
22
  import type { Stage } from '../../Stage.js';
23
+ import {
24
+ dataURIToBlob,
25
+ isBase64Image,
26
+ convertUrlToAbsolute,
27
+ createWebGLContext,
28
+ } from './lib/utils.js';
29
+
30
+ import type { ImageResponse } from '../../textures/ImageTexture.js';
31
+ import { loadSvg } from './lib/textureSvg.js';
32
+ import { loadCompressedTexture } from './lib/textureCompression.js';
33
+ import { WebGlContextWrapper } from './WebGlContextWrapper.js';
34
+ import type { GlContextWrapper } from '../GlContextWrapper.js';
3
35
 
4
36
  /**
5
37
  * make fontface add not show errors
@@ -9,13 +41,33 @@ interface FontFaceSetWithAdd extends FontFaceSet {
9
41
  }
10
42
 
11
43
  export class WebPlatform extends Platform {
44
+ private useImageWorker: boolean;
45
+ private imageWorkerManager: ImageWorkerManager | null = null;
46
+ private hasWorker = !!self.Worker;
47
+
48
+ constructor(settings: PlatformSettings = {}) {
49
+ super(settings);
50
+
51
+ const numImageWorkers = settings.numImageWorkers ?? 0;
52
+ this.useImageWorker = numImageWorkers > 0 && this.hasWorker;
53
+
54
+ if (this.useImageWorker === true) {
55
+ this.imageWorkerManager = new ImageWorkerManager(numImageWorkers);
56
+ }
57
+ }
58
+
12
59
  ////////////////////////
13
60
  // Platform-specific methods
14
61
  ////////////////////////
15
62
 
16
63
  override createCanvas(): HTMLCanvasElement {
17
- const canvas = document.createElement('canvas');
18
- return canvas;
64
+ return document.createElement('canvas');
65
+ }
66
+
67
+ override createContext(): GlContextWrapper {
68
+ const gl = createWebGLContext(this.canvas!, this.settings.forceWebGL2);
69
+ this.glw = new WebGlContextWrapper(gl);
70
+ return this.glw;
19
71
  }
20
72
 
21
73
  override getElementById(id: string): HTMLElement | null {
@@ -76,7 +128,11 @@ export class WebPlatform extends Platform {
76
128
  return;
77
129
  }
78
130
 
79
- isIdle = false;
131
+ if (isIdle === true) {
132
+ stage.eventBus.emit('active');
133
+ isIdle = false;
134
+ }
135
+
80
136
  stage.drawFrame();
81
137
  stage.flushFrameEvents();
82
138
 
@@ -97,31 +153,124 @@ export class WebPlatform extends Platform {
97
153
  }
98
154
 
99
155
  ////////////////////////
100
- // ImageBitmap
156
+ // Image handling
101
157
  ////////////////////////
102
158
 
103
- override createImageBitmap(
104
- blob: ImageBitmapSource,
105
- sxOrOptions?: number | ImageBitmapOptions,
106
- sy?: number,
107
- sw?: number,
108
- sh?: number,
109
- options?: ImageBitmapOptions,
110
- ): Promise<ImageBitmap> {
111
- if (typeof sxOrOptions === 'number') {
112
- return createImageBitmap(
113
- blob,
114
- sxOrOptions,
115
- sy ?? 0,
116
- sw ?? 0,
117
- sh ?? 0,
118
- options,
159
+ override fetch(url: string): Promise<Blob> {
160
+ return new Promise((resolve, reject) => {
161
+ const xhr = new XMLHttpRequest();
162
+ xhr.responseType = '';
163
+ xhr.onreadystatechange = function () {
164
+ if (xhr.readyState == XMLHttpRequest.DONE) {
165
+ // On most devices like WebOS and Tizen, the file protocol returns 0 while http(s) protocol returns 200
166
+ if (xhr.status === 0 || xhr.status === 200) {
167
+ resolve(xhr.response);
168
+ } else {
169
+ reject(xhr.statusText);
170
+ }
171
+ }
172
+ };
173
+ xhr.open('GET', url, true);
174
+ xhr.send(null);
175
+ });
176
+ }
177
+
178
+ override async createImage(
179
+ blob: Blob,
180
+ premultiplyAlpha: boolean | null,
181
+ sx: number | null,
182
+ sy: number | null,
183
+ sw: number | null,
184
+ sh: number | null,
185
+ ): Promise<ImageResponse> {
186
+ const hasAlphaChannel = premultiplyAlpha ?? blob.type.includes('image/png');
187
+
188
+ if (sw !== null && sh !== null) {
189
+ // createImageBitmap with crop
190
+ const bitmap = await createImageBitmap(blob, sx || 0, sy || 0, sw, sh, {
191
+ premultiplyAlpha: hasAlphaChannel ? 'premultiply' : 'none',
192
+ colorSpaceConversion: 'none',
193
+ imageOrientation: 'none',
194
+ });
195
+ return { data: bitmap, premultiplyAlpha: hasAlphaChannel };
196
+ }
197
+
198
+ // default createImageBitmap without crop but with options
199
+ const bitmap = await createImageBitmap(blob, {
200
+ premultiplyAlpha: hasAlphaChannel ? 'premultiply' : 'none',
201
+ colorSpaceConversion: 'none',
202
+ imageOrientation: 'none',
203
+ });
204
+
205
+ return { data: bitmap, premultiplyAlpha: hasAlphaChannel };
206
+ }
207
+
208
+ override async loadImage(
209
+ src: string,
210
+ premultiplyAlpha: boolean | null,
211
+ sx?: number | null,
212
+ sy?: number | null,
213
+ sw?: number | null,
214
+ sh?: number | null,
215
+ ): Promise<ImageResponse> {
216
+ const isBase64 = isBase64Image(src);
217
+ const absoluteSrc = convertUrlToAbsolute(src);
218
+ const x = sx ?? null;
219
+ const y = sy ?? null;
220
+ const width = sw ?? null;
221
+ const height = sh ?? null;
222
+
223
+ // check if image worker is enabled
224
+ if (this.imageWorkerManager !== null && isBase64 === false) {
225
+ return this.imageWorkerManager.getImage(
226
+ absoluteSrc,
227
+ premultiplyAlpha,
228
+ x,
229
+ y,
230
+ width,
231
+ height,
119
232
  );
233
+ }
234
+
235
+ // fallback to main thread loading
236
+ let blob: Blob;
237
+ if (isBase64Image(src) === true) {
238
+ blob = dataURIToBlob(src);
120
239
  } else {
121
- return createImageBitmap(blob, sxOrOptions);
240
+ blob = await this.fetch(absoluteSrc);
122
241
  }
242
+
243
+ return this.createImage(blob, premultiplyAlpha, x, y, width, height);
244
+ }
245
+
246
+ override async loadSvg(
247
+ src: string,
248
+ width: number | null,
249
+ height: number | null,
250
+ sx?: number | null,
251
+ sy?: number | null,
252
+ sw?: number | null,
253
+ sh?: number | null,
254
+ ): Promise<ImageResponse> {
255
+ return loadSvg(
256
+ convertUrlToAbsolute(src),
257
+ width,
258
+ height,
259
+ sx ?? null,
260
+ sy ?? null,
261
+ sw ?? null,
262
+ sh ?? null,
263
+ );
264
+ }
265
+
266
+ override async loadCompressedTexture(src: string): Promise<ImageResponse> {
267
+ return loadCompressedTexture(convertUrlToAbsolute(src));
123
268
  }
124
269
 
270
+ ////////////////////////
271
+ // Utilities
272
+ ////////////////////////
273
+
125
274
  getTimeStamp(): number {
126
275
  return performance ? performance.now() : Date.now();
127
276
  }
@@ -0,0 +1,57 @@
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 2026 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 { WebPlatform } from './WebPlatform.js';
21
+ import type { ImageResponse } from '../../textures/ImageTexture.js';
22
+
23
+ /**
24
+ * Chrome 50 Web Platform implementation with limited createImageBitmap support
25
+ *
26
+ * @remarks
27
+ * This platform is designed for Chrome 50 and similar browsers that support
28
+ * createImageBitmap but with a limited signature (no options or cropping parameters).
29
+ *
30
+ * Limitations:
31
+ * - createImageBitmap is called without options (premultiplyAlpha, colorSpaceConversion, imageOrientation)
32
+ * - Image cropping (sx, sy, sw, sh parameters) is not supported
33
+ * - Image workers can still be used if enabled via settings
34
+ */
35
+ export class WebPlatformChrome50 extends WebPlatform {
36
+ override async createImage(
37
+ blob: Blob,
38
+ premultiplyAlpha: boolean | null,
39
+ // Cropping parameters are not supported in Chrome 50
40
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
41
+ sx: number | null,
42
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
43
+ sy: number | null,
44
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
45
+ sw: number | null,
46
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
47
+ sh: number | null,
48
+ ): Promise<ImageResponse> {
49
+ const hasAlphaChannel = premultiplyAlpha ?? blob.type.includes('image/png');
50
+
51
+ // Chrome 50 createImageBitmap signature: createImageBitmap(blob)
52
+ // No options or cropping parameters supported
53
+ const bitmap = await createImageBitmap(blob);
54
+
55
+ return { data: bitmap, premultiplyAlpha: hasAlphaChannel };
56
+ }
57
+ }
@@ -0,0 +1,140 @@
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 2026 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 { WebPlatform } from './WebPlatform.js';
21
+ import type { PlatformSettings } from '../Platform.js';
22
+ import type { ImageResponse } from '../../textures/ImageTexture.js';
23
+ import {
24
+ isBase64Image,
25
+ dataURIToBlob,
26
+ convertUrlToAbsolute,
27
+ } from './lib/utils.js';
28
+
29
+ /**
30
+ * Legacy Web Platform implementation that uses Image() instead of createImageBitmap
31
+ *
32
+ * @remarks
33
+ * This platform is designed for environments that don't support createImageBitmap API,
34
+ * or for compatibility with older browsers. It uses the traditional HTMLImageElement
35
+ * approach for image loading.
36
+ *
37
+ */
38
+ export class WebPlatformLegacy extends WebPlatform {
39
+ constructor(settings: PlatformSettings = {}) {
40
+ // Force image workers to be disabled in legacy mode
41
+ super({ ...settings, numImageWorkers: 0 });
42
+ }
43
+
44
+ override async loadImage(
45
+ src: string,
46
+ premultiplyAlpha: boolean | null,
47
+ sx?: number | null,
48
+ sy?: number | null,
49
+ sw?: number | null,
50
+ sh?: number | null,
51
+ ): Promise<ImageResponse> {
52
+ const isBase64 = isBase64Image(src);
53
+ const absoluteSrc = convertUrlToAbsolute(src);
54
+
55
+ // For base64 images, use blob conversion
56
+ if (isBase64 === true) {
57
+ const blob = dataURIToBlob(src);
58
+ return this.createImage(
59
+ blob,
60
+ premultiplyAlpha,
61
+ sx ?? null,
62
+ sy ?? null,
63
+ sw ?? null,
64
+ sh ?? null,
65
+ );
66
+ }
67
+
68
+ // For regular URLs, load directly without blob conversion
69
+ const hasAlpha =
70
+ premultiplyAlpha ?? absoluteSrc.toLowerCase().endsWith('.png');
71
+ const img = new Image();
72
+ img.crossOrigin = 'anonymous';
73
+
74
+ return new Promise<ImageResponse>((resolve, reject) => {
75
+ img.onload = () => {
76
+ resolve({ data: img, premultiplyAlpha: hasAlpha });
77
+ };
78
+
79
+ img.onerror = (err) => {
80
+ const errorMessage =
81
+ err instanceof Error
82
+ ? err.message
83
+ : err instanceof Event
84
+ ? `Image loading failed for ${img.src}`
85
+ : 'Unknown image loading error';
86
+ reject(new Error(`Image loading failed: ${errorMessage}`));
87
+ };
88
+
89
+ img.src = absoluteSrc;
90
+ });
91
+ }
92
+
93
+ override async createImage(
94
+ blob: Blob,
95
+ premultiplyAlpha: boolean | null,
96
+ // Cropping parameters are not supported in legacy mode
97
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
98
+ sx: number | null,
99
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
100
+ sy: number | null,
101
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
102
+ sw: number | null,
103
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
104
+ sh: number | null,
105
+ ): Promise<ImageResponse> {
106
+ const hasAlpha = premultiplyAlpha ?? blob.type.includes('image/png');
107
+ const src = URL.createObjectURL(blob);
108
+ const img = new Image();
109
+
110
+ if (typeof src === 'string' && isBase64Image(src) === false) {
111
+ img.crossOrigin = 'anonymous';
112
+ }
113
+
114
+ return new Promise<ImageResponse>((resolve, reject) => {
115
+ img.onload = () => {
116
+ URL.revokeObjectURL(src);
117
+ resolve({ data: img, premultiplyAlpha: hasAlpha });
118
+ };
119
+
120
+ img.onerror = (err) => {
121
+ URL.revokeObjectURL(src);
122
+ const errorMessage =
123
+ err instanceof Error
124
+ ? err.message
125
+ : err instanceof Event
126
+ ? `Image loading failed for ${img.src}`
127
+ : 'Unknown image loading error';
128
+ reject(new Error(`Image loading failed: ${errorMessage}`));
129
+ };
130
+
131
+ img.src = src;
132
+ });
133
+ }
134
+
135
+ override async loadCompressedTexture(src: string): Promise<ImageResponse> {
136
+ throw new Error(
137
+ `Compressed textures are not supported in legacy mode. Attempted to load: ${src}`,
138
+ );
139
+ }
140
+ }
@@ -0,0 +1,57 @@
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 2026 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 { WebPlatform } from './WebPlatform.js';
21
+
22
+ /**
23
+ * Next-generation Web Platform implementation that uses Fetch API
24
+ *
25
+ * @remarks
26
+ * This platform uses the modern Fetch API instead of XMLHttpRequest for
27
+ * loading image resources. The Fetch API provides a more modern, promise-based
28
+ * interface for network requests and better streaming capabilities.
29
+ *
30
+ * Benefits over XMLHttpRequest:
31
+ * - Promise-based (no callback-based API)
32
+ * - Better error handling
33
+ * - More consistent across browsers
34
+ * - Better streaming support
35
+ * - Service Worker compatible
36
+ *
37
+ * All other platform features remain the same as WebPlatform.
38
+ */
39
+ export class WebPlatformNext extends WebPlatform {
40
+ override async fetch(url: string): Promise<Blob> {
41
+ try {
42
+ const response = await fetch(url);
43
+
44
+ if (!response.ok) {
45
+ throw new Error(
46
+ `Failed to fetch resource: ${response.status} ${response.statusText}`,
47
+ );
48
+ }
49
+
50
+ return await response.blob();
51
+ } catch (error) {
52
+ const errorMessage =
53
+ error instanceof Error ? error.message : 'Unknown fetch error';
54
+ throw new Error(`Fetch failed for ${url}: ${errorMessage}`);
55
+ }
56
+ }
57
+ }