@lightningjs/renderer 0.7.5 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (252) hide show
  1. package/LICENSE +202 -202
  2. package/NOTICE +3 -3
  3. package/README.md +233 -221
  4. package/dist/src/common/CommonTypes.d.ts +12 -0
  5. package/dist/src/core/CoreNode.d.ts +83 -9
  6. package/dist/src/core/CoreNode.js +232 -44
  7. package/dist/src/core/CoreNode.js.map +1 -1
  8. package/dist/src/core/CoreTextNode.d.ts +6 -1
  9. package/dist/src/core/CoreTextNode.js +33 -20
  10. package/dist/src/core/CoreTextNode.js.map +1 -1
  11. package/dist/src/core/CoreTextureManager.d.ts +3 -1
  12. package/dist/src/core/CoreTextureManager.js +11 -2
  13. package/dist/src/core/CoreTextureManager.js.map +1 -1
  14. package/dist/src/core/Stage.d.ts +6 -0
  15. package/dist/src/core/Stage.js +16 -1
  16. package/dist/src/core/Stage.js.map +1 -1
  17. package/dist/src/core/TextureMemoryManager.d.ts +12 -0
  18. package/dist/src/core/TextureMemoryManager.js +42 -0
  19. package/dist/src/core/TextureMemoryManager.js.map +1 -0
  20. package/dist/src/core/lib/ImageWorker.d.ts +0 -1
  21. package/dist/src/core/lib/ImageWorker.js +55 -40
  22. package/dist/src/core/lib/ImageWorker.js.map +1 -1
  23. package/dist/src/core/lib/RenderCoords.d.ts +13 -0
  24. package/dist/src/core/lib/RenderCoords.js +63 -0
  25. package/dist/src/core/lib/RenderCoords.js.map +1 -0
  26. package/dist/src/core/lib/WebGlContext.d.ts +414 -0
  27. package/dist/src/core/lib/WebGlContext.js +640 -0
  28. package/dist/src/core/lib/WebGlContext.js.map +1 -0
  29. package/dist/src/core/lib/utils.d.ts +1 -0
  30. package/dist/src/core/lib/utils.js +6 -0
  31. package/dist/src/core/lib/utils.js.map +1 -1
  32. package/dist/src/core/platform.js +8 -0
  33. package/dist/src/core/platform.js.map +1 -1
  34. package/dist/src/core/renderers/CoreContextTexture.d.ts +5 -1
  35. package/dist/src/core/renderers/CoreContextTexture.js +3 -1
  36. package/dist/src/core/renderers/CoreContextTexture.js.map +1 -1
  37. package/dist/src/core/renderers/webgl/WebGlCoreCtxSubTexture.d.ts +2 -1
  38. package/dist/src/core/renderers/webgl/WebGlCoreCtxSubTexture.js +2 -2
  39. package/dist/src/core/renderers/webgl/WebGlCoreCtxSubTexture.js.map +1 -1
  40. package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.d.ts +3 -1
  41. package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.js +26 -6
  42. package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.js.map +1 -1
  43. package/dist/src/core/renderers/webgl/WebGlCoreRenderer.d.ts +3 -0
  44. package/dist/src/core/renderers/webgl/WebGlCoreRenderer.js +4 -2
  45. package/dist/src/core/renderers/webgl/WebGlCoreRenderer.js.map +1 -1
  46. package/dist/src/core/renderers/webgl/internal/RendererUtils.d.ts +9 -0
  47. package/dist/src/core/renderers/webgl/internal/RendererUtils.js +14 -0
  48. package/dist/src/core/renderers/webgl/internal/RendererUtils.js.map +1 -1
  49. package/dist/src/core/renderers/webgl/shaders/DefaultShader.js +47 -47
  50. package/dist/src/core/renderers/webgl/shaders/DefaultShaderBatched.js +61 -61
  51. package/dist/src/core/renderers/webgl/shaders/DynamicShader.js +93 -93
  52. package/dist/src/core/renderers/webgl/shaders/RoundedRectangle.js +63 -63
  53. package/dist/src/core/renderers/webgl/shaders/SdfShader.js +49 -49
  54. package/dist/src/core/renderers/webgl/shaders/effects/BorderBottomEffect.js +15 -15
  55. package/dist/src/core/renderers/webgl/shaders/effects/BorderEffect.js +5 -5
  56. package/dist/src/core/renderers/webgl/shaders/effects/BorderLeftEffect.js +15 -15
  57. package/dist/src/core/renderers/webgl/shaders/effects/BorderRightEffect.js +15 -15
  58. package/dist/src/core/renderers/webgl/shaders/effects/BorderTopEffect.js +15 -15
  59. package/dist/src/core/renderers/webgl/shaders/effects/FadeOutEffect.js +42 -42
  60. package/dist/src/core/renderers/webgl/shaders/effects/GlitchEffect.js +44 -44
  61. package/dist/src/core/renderers/webgl/shaders/effects/GrayscaleEffect.js +3 -3
  62. package/dist/src/core/renderers/webgl/shaders/effects/LinearGradientEffect.js +44 -57
  63. package/dist/src/core/renderers/webgl/shaders/effects/LinearGradientEffect.js.map +1 -1
  64. package/dist/src/core/renderers/webgl/shaders/effects/RadialGradientEffect.d.ts +1 -0
  65. package/dist/src/core/renderers/webgl/shaders/effects/RadialGradientEffect.js +33 -39
  66. package/dist/src/core/renderers/webgl/shaders/effects/RadialGradientEffect.js.map +1 -1
  67. package/dist/src/core/renderers/webgl/shaders/effects/RadialProgressEffect.js +37 -37
  68. package/dist/src/core/renderers/webgl/shaders/effects/RadiusEffect.js +19 -19
  69. package/dist/src/core/scene/Scene.d.ts +59 -0
  70. package/dist/src/core/scene/Scene.js +106 -0
  71. package/dist/src/core/scene/Scene.js.map +1 -0
  72. package/dist/src/core/text-rendering/TrFontManager.js +30 -25
  73. package/dist/src/core/text-rendering/TrFontManager.js.map +1 -1
  74. package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.d.ts +2 -0
  75. package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.js +26 -2
  76. package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.js.map +1 -1
  77. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.d.ts +8 -0
  78. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js +34 -6
  79. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js.map +1 -1
  80. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/findNearestMultiple.d.ts +8 -0
  81. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/findNearestMultiple.js +29 -0
  82. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/findNearestMultiple.js.map +1 -0
  83. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.js +1 -3
  84. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.js.map +1 -1
  85. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/SdfBufferHelper.d.ts +19 -0
  86. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/SdfBufferHelper.js +84 -0
  87. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/SdfBufferHelper.js.map +1 -0
  88. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutLine.d.ts +8 -0
  89. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutLine.js +40 -0
  90. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutLine.js.map +1 -0
  91. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutText2.d.ts +2 -0
  92. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutText2.js +41 -0
  93. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutText2.js.map +1 -0
  94. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/utils.d.ts +1 -0
  95. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/utils.js +4 -0
  96. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/utils.js.map +1 -0
  97. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2.d.ts +1 -0
  98. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2.js +2 -0
  99. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2.js.map +1 -0
  100. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/makeRenderWindow.d.ts +20 -0
  101. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/makeRenderWindow.js +55 -0
  102. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/makeRenderWindow.js.map +1 -0
  103. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/roundUpToMultiple.d.ts +9 -0
  104. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/roundUpToMultiple.js +32 -0
  105. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/roundUpToMultiple.js.map +1 -0
  106. package/dist/src/core/text-rendering/renderers/TextRenderer.d.ts +31 -0
  107. package/dist/src/core/text-rendering/renderers/TextRenderer.js +26 -0
  108. package/dist/src/core/text-rendering/renderers/TextRenderer.js.map +1 -1
  109. package/dist/src/core/textures/ImageTexture.js +16 -2
  110. package/dist/src/core/textures/ImageTexture.js.map +1 -1
  111. package/dist/src/core/textures/Texture.d.ts +27 -2
  112. package/dist/src/core/textures/Texture.js +30 -1
  113. package/dist/src/core/textures/Texture.js.map +1 -1
  114. package/dist/src/core/utils.d.ts +1 -1
  115. package/dist/src/main-api/ICoreDriver.d.ts +1 -0
  116. package/dist/src/main-api/Inspector.js +2 -1
  117. package/dist/src/main-api/Inspector.js.map +1 -1
  118. package/dist/src/main-api/RendererMain.d.ts +15 -0
  119. package/dist/src/main-api/RendererMain.js +7 -1
  120. package/dist/src/main-api/RendererMain.js.map +1 -1
  121. package/dist/src/render-drivers/main/MainCoreDriver.d.ts +1 -0
  122. package/dist/src/render-drivers/main/MainCoreDriver.js +8 -0
  123. package/dist/src/render-drivers/main/MainCoreDriver.js.map +1 -1
  124. package/dist/src/render-drivers/main/MainOnlyNode.d.ts +5 -0
  125. package/dist/src/render-drivers/main/MainOnlyNode.js +26 -0
  126. package/dist/src/render-drivers/main/MainOnlyNode.js.map +1 -1
  127. package/dist/src/render-drivers/threadx/ThreadXCoreDriver.js +2 -0
  128. package/dist/src/render-drivers/threadx/ThreadXCoreDriver.js.map +1 -1
  129. package/dist/src/render-drivers/threadx/ThreadXRendererMessage.d.ts +2 -0
  130. package/dist/src/render-drivers/threadx/ThreadXRendererMessage.js.map +1 -1
  131. package/dist/src/render-drivers/threadx/worker/ThreadXRendererNode.js +3 -0
  132. package/dist/src/render-drivers/threadx/worker/ThreadXRendererNode.js.map +1 -1
  133. package/dist/src/render-drivers/threadx/worker/renderer.js +2 -0
  134. package/dist/src/render-drivers/threadx/worker/renderer.js.map +1 -1
  135. package/dist/src/utils.d.ts +6 -0
  136. package/dist/src/utils.js +9 -1
  137. package/dist/src/utils.js.map +1 -1
  138. package/dist/tsconfig.dist.tsbuildinfo +1 -1
  139. package/exports/core-api.ts +102 -102
  140. package/exports/main-api.ts +60 -60
  141. package/exports/utils.ts +41 -41
  142. package/package.json +1 -1
  143. package/scripts/please-use-pnpm.js +13 -13
  144. package/src/common/CommonTypes.ts +132 -113
  145. package/src/common/EventEmitter.ts +77 -77
  146. package/src/common/IAnimationController.ts +29 -29
  147. package/src/core/CoreExtension.ts +32 -32
  148. package/src/core/CoreNode.ts +1199 -955
  149. package/src/core/CoreShaderManager.ts +243 -243
  150. package/src/core/CoreTextNode.ts +400 -391
  151. package/src/core/CoreTextureManager.ts +339 -326
  152. package/src/core/Stage.ts +375 -354
  153. package/src/core/TextureMemoryManager.ts +66 -0
  154. package/src/core/animations/AnimationManager.ts +38 -38
  155. package/src/core/animations/CoreAnimation.ts +181 -181
  156. package/src/core/animations/CoreAnimationController.ts +148 -148
  157. package/src/core/lib/ContextSpy.ts +41 -41
  158. package/src/core/lib/ImageWorker.ts +149 -135
  159. package/src/core/lib/Matrix3d.ts +290 -290
  160. package/src/core/lib/RenderCoords.ts +86 -0
  161. package/src/core/lib/WebGlContextWrapper.ts +992 -992
  162. package/src/core/lib/textureCompression.ts +152 -152
  163. package/src/core/lib/utils.ts +250 -241
  164. package/src/core/platform.ts +54 -46
  165. package/src/core/renderers/CoreContextTexture.ts +35 -30
  166. package/src/core/renderers/CoreRenderOp.ts +22 -22
  167. package/src/core/renderers/CoreRenderer.ts +63 -63
  168. package/src/core/renderers/CoreShader.ts +41 -41
  169. package/src/core/renderers/webgl/WebGlCoreCtxSubTexture.ts +42 -37
  170. package/src/core/renderers/webgl/WebGlCoreCtxTexture.ts +261 -230
  171. package/src/core/renderers/webgl/WebGlCoreRenderOp.ts +107 -107
  172. package/src/core/renderers/webgl/WebGlCoreRenderer.ts +528 -520
  173. package/src/core/renderers/webgl/WebGlCoreShader.ts +337 -337
  174. package/src/core/renderers/webgl/internal/BufferCollection.ts +54 -54
  175. package/src/core/renderers/webgl/internal/RendererUtils.ts +148 -131
  176. package/src/core/renderers/webgl/internal/ShaderUtils.ts +136 -136
  177. package/src/core/renderers/webgl/internal/WebGlUtils.ts +35 -35
  178. package/src/core/renderers/webgl/shaders/DefaultShader.ts +95 -95
  179. package/src/core/renderers/webgl/shaders/DefaultShaderBatched.ts +132 -132
  180. package/src/core/renderers/webgl/shaders/DynamicShader.ts +474 -474
  181. package/src/core/renderers/webgl/shaders/RoundedRectangle.ts +161 -161
  182. package/src/core/renderers/webgl/shaders/SdfShader.ts +174 -174
  183. package/src/core/renderers/webgl/shaders/effects/BorderBottomEffect.ts +101 -101
  184. package/src/core/renderers/webgl/shaders/effects/BorderEffect.ts +86 -86
  185. package/src/core/renderers/webgl/shaders/effects/BorderLeftEffect.ts +101 -101
  186. package/src/core/renderers/webgl/shaders/effects/BorderRightEffect.ts +101 -101
  187. package/src/core/renderers/webgl/shaders/effects/BorderTopEffect.ts +101 -101
  188. package/src/core/renderers/webgl/shaders/effects/EffectUtils.ts +33 -33
  189. package/src/core/renderers/webgl/shaders/effects/FadeOutEffect.ts +135 -135
  190. package/src/core/renderers/webgl/shaders/effects/GlitchEffect.ts +145 -145
  191. package/src/core/renderers/webgl/shaders/effects/GrayscaleEffect.ts +67 -67
  192. package/src/core/renderers/webgl/shaders/effects/LinearGradientEffect.ts +160 -176
  193. package/src/core/renderers/webgl/shaders/effects/RadialGradientEffect.ts +153 -159
  194. package/src/core/renderers/webgl/shaders/effects/RadialProgressEffect.ts +186 -186
  195. package/src/core/renderers/webgl/shaders/effects/RadiusEffect.ts +121 -121
  196. package/src/core/renderers/webgl/shaders/effects/ShaderEffect.ts +114 -114
  197. package/src/core/text-rendering/TextTextureRendererUtils.ts +189 -189
  198. package/src/core/text-rendering/TrFontManager.ts +170 -166
  199. package/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.ts +141 -141
  200. package/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/FontShaper.ts +139 -139
  201. package/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.test.ts +173 -173
  202. package/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.ts +169 -169
  203. package/src/core/text-rendering/font-face-types/TrFontFace.ts +105 -105
  204. package/src/core/text-rendering/font-face-types/WebTrFontFace.ts +77 -77
  205. package/src/core/text-rendering/renderers/CanvasTextRenderer.ts +780 -751
  206. package/src/core/text-rendering/renderers/LightningTextTextureRenderer.ts +741 -741
  207. package/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.ts +812 -778
  208. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/PeekableGenerator.test.ts +48 -48
  209. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/PeekableGenerator.ts +66 -66
  210. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/SpecialCodepoints.ts +52 -52
  211. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/constants.ts +32 -32
  212. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/getStartConditions.ts +84 -84
  213. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/getUnicodeCodepoints.test.ts +133 -133
  214. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/getUnicodeCodepoints.ts +38 -38
  215. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.ts +391 -393
  216. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/measureText.test.ts +49 -49
  217. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/measureText.ts +51 -51
  218. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.test.ts +205 -205
  219. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.ts +93 -93
  220. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/util.ts +40 -40
  221. package/src/core/text-rendering/renderers/TextRenderer.ts +548 -504
  222. package/src/core/textures/ColorTexture.ts +86 -86
  223. package/src/core/textures/ImageTexture.ts +154 -140
  224. package/src/core/textures/NoiseTexture.ts +96 -96
  225. package/src/core/textures/SubTexture.ts +143 -143
  226. package/src/core/textures/Texture.ts +261 -218
  227. package/src/core/utils.ts +224 -224
  228. package/src/env.d.ts +7 -7
  229. package/src/main-api/ICoreDriver.ts +68 -66
  230. package/src/main-api/INode.ts +499 -499
  231. package/src/main-api/Inspector.ts +440 -439
  232. package/src/main-api/RendererMain.ts +676 -652
  233. package/src/main-api/texture-usage-trackers/FinalizationRegistryTextureUsageTracker.ts +45 -45
  234. package/src/main-api/texture-usage-trackers/ManualCountTextureUsageTracker.ts +154 -154
  235. package/src/main-api/texture-usage-trackers/TextureUsageTracker.ts +54 -54
  236. package/src/render-drivers/main/MainCoreDriver.ts +158 -148
  237. package/src/render-drivers/main/MainOnlyNode.ts +500 -466
  238. package/src/render-drivers/main/MainOnlyTextNode.ts +261 -261
  239. package/src/render-drivers/threadx/NodeStruct.ts +300 -300
  240. package/src/render-drivers/threadx/SharedNode.ts +97 -97
  241. package/src/render-drivers/threadx/TextNodeStruct.ts +211 -211
  242. package/src/render-drivers/threadx/ThreadXCoreDriver.ts +287 -285
  243. package/src/render-drivers/threadx/ThreadXMainAnimationController.ts +99 -99
  244. package/src/render-drivers/threadx/ThreadXMainNode.ts +192 -192
  245. package/src/render-drivers/threadx/ThreadXMainTextNode.ts +85 -85
  246. package/src/render-drivers/threadx/ThreadXRendererMessage.ts +112 -110
  247. package/src/render-drivers/threadx/worker/ThreadXRendererNode.ts +245 -238
  248. package/src/render-drivers/threadx/worker/ThreadXRendererTextNode.ts +149 -149
  249. package/src/render-drivers/threadx/worker/renderer.ts +153 -151
  250. package/src/render-drivers/utils.ts +97 -97
  251. package/src/utils.ts +216 -207
  252. package/COPYING +0 -1
@@ -1,652 +1,676 @@
1
- /*
2
- * If not stated otherwise in this file or this component's LICENSE file the
3
- * following copyright and licenses apply:
4
- *
5
- * Copyright 2023 Comcast Cable Communications Management, LLC.
6
- *
7
- * Licensed under the Apache License, Version 2.0 (the License);
8
- * you may not use this file except in compliance with the License.
9
- * You may obtain a copy of the License at
10
- *
11
- * http://www.apache.org/licenses/LICENSE-2.0
12
- *
13
- * Unless required by applicable law or agreed to in writing, software
14
- * distributed under the License is distributed on an "AS IS" BASIS,
15
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
- * See the License for the specific language governing permissions and
17
- * limitations under the License.
18
- */
19
-
20
- /* eslint-disable @typescript-eslint/no-unused-vars */
21
- import type { ShaderMap } from '../core/CoreShaderManager.js';
22
- import type {
23
- ExtractProps,
24
- TextureMap,
25
- TextureOptions,
26
- } from '../core/CoreTextureManager.js';
27
- import type {
28
- INode,
29
- INodeWritableProps,
30
- ITextNode,
31
- ITextNodeWritableProps,
32
- } from './INode.js';
33
- import type { ICoreDriver } from './ICoreDriver.js';
34
- import {
35
- ManualCountTextureUsageTracker,
36
- type ManualCountTextureUsageTrackerOptions,
37
- } from './texture-usage-trackers/ManualCountTextureUsageTracker.js';
38
- import { FinalizationRegistryTextureUsageTracker } from './texture-usage-trackers/FinalizationRegistryTextureUsageTracker.js';
39
- import type { TextureUsageTracker } from './texture-usage-trackers/TextureUsageTracker.js';
40
- import { EventEmitter } from '../common/EventEmitter.js';
41
- import { Inspector } from './Inspector.js';
42
- import { santizeCustomDataMap } from '../render-drivers/utils.js';
43
-
44
- /**
45
- * An immutable reference to a specific Texture type
46
- *
47
- * @remarks
48
- * See {@link TextureRef} for more details.
49
- */
50
- export interface SpecificTextureRef<TxType extends keyof TextureMap> {
51
- readonly descType: 'texture';
52
- readonly txType: TxType;
53
- readonly props: ExtractProps<TextureMap[TxType]>;
54
- readonly options?: Readonly<TextureOptions>;
55
- }
56
-
57
- type MapTextureRefs<TxType extends keyof TextureMap> =
58
- TxType extends keyof TextureMap ? SpecificTextureRef<TxType> : never;
59
-
60
- /**
61
- * An immutable reference to a Texture
62
- *
63
- * @remarks
64
- * This structure should only be created by the RendererMain's `createTexture`
65
- * method. The structure is immutable and should not be modified once created.
66
- *
67
- * A `TextureRef` exists in the Main API Space and is used to point to an actual
68
- * `Texture` instance in the Core API Space. The `TextureRef` is used to
69
- * communicate with the Core API Space to create, load, and destroy the
70
- * `Texture` instance.
71
- *
72
- * This type is technically a discriminated union of all possible texture types.
73
- * If you'd like to represent a specific texture type, you can use the
74
- * `SpecificTextureRef` generic type.
75
- */
76
- export type TextureRef = MapTextureRefs<keyof TextureMap>;
77
-
78
- /**
79
- * An immutable reference to a specific Shader type
80
- *
81
- * @remarks
82
- * See {@link ShaderRef} for more details.
83
- */
84
- export interface SpecificShaderRef<ShType extends keyof ShaderMap> {
85
- readonly descType: 'shader';
86
- readonly shType: ShType;
87
- readonly props: ExtractProps<ShaderMap[ShType]>;
88
- }
89
-
90
- type MapShaderRefs<ShType extends keyof ShaderMap> =
91
- ShType extends keyof ShaderMap ? SpecificShaderRef<ShType> : never;
92
-
93
- /**
94
- * An immutable reference to a Shader
95
- *
96
- * @remarks
97
- * This structure should only be created by the RendererMain's `createShader`
98
- * method. The structure is immutable and should not be modified once created.
99
- *
100
- * A `ShaderRef` exists in the Main API Space and is used to point to an actual
101
- * `Shader` instance in the Core API Space. The `ShaderRef` is used to
102
- * communicate with the Core API Space to create, load, and destroy the
103
- * `Shader` instance.
104
- *
105
- * This type is technically a discriminated union of all possible shader types.
106
- * If you'd like to represent a specific shader type, you can use the
107
- * `SpecificShaderRef` generic type.
108
- */
109
- export type ShaderRef = MapShaderRefs<keyof ShaderMap>;
110
-
111
- /**
112
- * Configuration settings for {@link RendererMain}
113
- */
114
- export interface RendererMainSettings {
115
- /**
116
- * Authored logical pixel width of the application
117
- *
118
- * @defaultValue `1920`
119
- */
120
- appWidth?: number;
121
-
122
- /**
123
- * Authored logical pixel height of the application
124
- *
125
- * @defaultValue `1080`
126
- */
127
- appHeight?: number;
128
-
129
- /**
130
- * Factor to convert app-authored logical coorindates to device logical coordinates
131
- *
132
- * @remarks
133
- * This value allows auto-scaling to support larger/small resolutions than the
134
- * app was authored for.
135
- *
136
- * If the app was authored for 1920x1080 and this value is 2, the app's canvas
137
- * will be rendered at 3840x2160 logical pixels.
138
- *
139
- * Likewise, if the app was authored for 1920x1080 and this value is 0.66667,
140
- * the app's canvas will be rendered at 1280x720 logical pixels.
141
- *
142
- * @defaultValue `1`
143
- */
144
- deviceLogicalPixelRatio?: number;
145
-
146
- /**
147
- * Factor to convert device logical coordinates to device physical coordinates
148
- *
149
- * @remarks
150
- * This value allows auto-scaling to support devices with different pixel densities.
151
- *
152
- * This controls the number of physical pixels that are used to render each logical
153
- * pixel. For example, if the device has a pixel density of 2, each logical pixel
154
- * will be rendered using 2x2 physical pixels.
155
- *
156
- * By default, it will be set to `window.devicePixelRatio` which is the pixel
157
- * density of the device the app is running on reported by the browser.
158
- *
159
- * @defaultValue `window.devicePixelRatio`
160
- */
161
- devicePhysicalPixelRatio?: number;
162
-
163
- /**
164
- * RGBA encoded number of the background to use
165
- *
166
- * @defaultValue `0x00000000`
167
- */
168
- clearColor?: number;
169
-
170
- /**
171
- * Path to a custom core module to use
172
- *
173
- * @defaultValue `null`
174
- */
175
- coreExtensionModule?: string | null;
176
-
177
- /**
178
- * Enable experimental FinalizationRegistry-based texture usage tracking
179
- * for texture garbage collection
180
- *
181
- * @remarks
182
- * By default, the Renderer uses a manual reference counting system to track
183
- * texture usage. Textures are eventually released from the Core Texture
184
- * Manager's Usage Cache when they are no longer referenced by any Nodes (or
185
- * SubTextures that are referenced by nodes). This works well enough, but has
186
- * the consequence of textures being removed from Usage Cache even if their
187
- * references are still alive in memory. This can require a texture to be
188
- * reloaded from the source when it is used again after being removed from
189
- * cache.
190
- *
191
- * This is an experimental feature that uses a FinalizationRegistry to track
192
- * texture usage. This causes textures to be removed from the Usage Cache only
193
- * when their references are no longer alive in memory. Meaning a loaded texture
194
- * will remain in the Usage Cache until it's reference is garbage collected.
195
- *
196
- * This feature is not enabled by default because browser support for the
197
- * FinalizationRegistry is limited. It should NOT be enabled in production apps
198
- * as this behavior is not guaranteed to be supported in the future. Developer
199
- * feedback on this feature, however, is welcome.
200
- *
201
- * @defaultValue `false`
202
- */
203
- experimental_FinalizationRegistryTextureUsageTracker?: boolean;
204
-
205
- textureCleanupOptions?: ManualCountTextureUsageTrackerOptions;
206
-
207
- /**
208
- * Interval in milliseconds to receive FPS updates
209
- *
210
- * @remarks
211
- * If set to `0`, FPS updates will be disabled.
212
- *
213
- * @defaultValue `0` (disabled)
214
- */
215
- fpsUpdateInterval?: number;
216
-
217
- /**
218
- * Include context call (i.e. WebGL) information in FPS updates
219
- *
220
- * @remarks
221
- * When enabled the number of calls to each context method over the
222
- * `fpsUpdateInterval` will be included in the FPS update payload's
223
- * `contextSpyData` property.
224
- *
225
- * Enabling the context spy has a serious impact on performance so only use it
226
- * when you need to extract context call information.
227
- *
228
- * @defaultValue `false` (disabled)
229
- */
230
- enableContextSpy?: boolean;
231
-
232
- /**
233
- * Number or Image Workers to use
234
- *
235
- * @remarks
236
- * On devices with multiple cores, this can be used to improve image loading
237
- * as well as reduce the impact of image loading on the main thread.
238
- * Set to 0 to disable image workers.
239
- *
240
- * @defaultValue `2`
241
- */
242
- numImageWorkers?: number;
243
-
244
- /**
245
- * Enable inspector
246
- *
247
- * @remarks
248
- * When enabled the renderer will spawn a inspector. The inspector will
249
- * replicate the state of the Nodes created in the renderer and allow
250
- * inspection of the state of the nodes.
251
- *
252
- * @defaultValue `false` (disabled)
253
- */
254
- enableInspector?: boolean;
255
- }
256
-
257
- /**
258
- * The Renderer Main API
259
- *
260
- * @remarks
261
- * This is the primary class used to configure and operate the Renderer.
262
- *
263
- * It is used to create and destroy Nodes, as well as Texture and Shader
264
- * references.
265
- *
266
- * Example:
267
- * ```ts
268
- * import { RendererMain, MainCoreDriver } from '@lightningjs/renderer';
269
- *
270
- * // Initialize the Renderer
271
- * const renderer = new RendererMain(
272
- * {
273
- * appWidth: 1920,
274
- * appHeight: 1080
275
- * },
276
- * 'app',
277
- * new MainCoreDriver(),
278
- * );
279
- * ```
280
- */
281
- export class RendererMain extends EventEmitter {
282
- readonly root: INode | null = null;
283
- readonly driver: ICoreDriver;
284
- readonly canvas: HTMLCanvasElement;
285
- readonly settings: Readonly<Required<RendererMainSettings>>;
286
- private inspector: Inspector | null = null;
287
- private nodes: Map<number, INode> = new Map();
288
- private nextTextureId = 1;
289
-
290
- /**
291
- * Texture Usage Tracker for Usage Based Texture Garbage Collection
292
- *
293
- * @remarks
294
- * For internal use only. DO NOT ACCESS.
295
- */
296
- public textureTracker: TextureUsageTracker;
297
-
298
- /**
299
- * Constructs a new Renderer instance
300
- *
301
- * @param settings Renderer settings
302
- * @param target Element ID or HTMLElement to insert the canvas into
303
- * @param driver Core Driver to use
304
- */
305
- constructor(
306
- settings: RendererMainSettings,
307
- target: string | HTMLElement,
308
- driver: ICoreDriver,
309
- ) {
310
- super();
311
- const resolvedSettings: Required<RendererMainSettings> = {
312
- appWidth: settings.appWidth || 1920,
313
- appHeight: settings.appHeight || 1080,
314
- deviceLogicalPixelRatio: settings.deviceLogicalPixelRatio || 1,
315
- devicePhysicalPixelRatio:
316
- settings.devicePhysicalPixelRatio || window.devicePixelRatio,
317
- clearColor: settings.clearColor ?? 0x00000000,
318
- coreExtensionModule: settings.coreExtensionModule || null,
319
- experimental_FinalizationRegistryTextureUsageTracker:
320
- settings.experimental_FinalizationRegistryTextureUsageTracker ?? false,
321
- textureCleanupOptions: settings.textureCleanupOptions || {},
322
- fpsUpdateInterval: settings.fpsUpdateInterval || 0,
323
- numImageWorkers:
324
- settings.numImageWorkers !== undefined ? settings.numImageWorkers : 2,
325
- enableContextSpy: settings.enableContextSpy ?? false,
326
- enableInspector: settings.enableInspector ?? false,
327
- };
328
- this.settings = resolvedSettings;
329
-
330
- const {
331
- appWidth,
332
- appHeight,
333
- deviceLogicalPixelRatio,
334
- devicePhysicalPixelRatio,
335
- enableInspector,
336
- } = resolvedSettings;
337
-
338
- const releaseCallback = (textureId: number) => {
339
- this.driver.releaseTexture(textureId);
340
- };
341
-
342
- const useFinalizationRegistryTracker =
343
- resolvedSettings.experimental_FinalizationRegistryTextureUsageTracker &&
344
- typeof FinalizationRegistry === 'function';
345
- this.textureTracker = useFinalizationRegistryTracker
346
- ? new FinalizationRegistryTextureUsageTracker(releaseCallback)
347
- : new ManualCountTextureUsageTracker(
348
- releaseCallback,
349
- this.settings.textureCleanupOptions,
350
- );
351
-
352
- const deviceLogicalWidth = appWidth * deviceLogicalPixelRatio;
353
- const deviceLogicalHeight = appHeight * deviceLogicalPixelRatio;
354
-
355
- this.driver = driver;
356
-
357
- const canvas = document.createElement('canvas');
358
- this.canvas = canvas;
359
- canvas.width = deviceLogicalWidth * devicePhysicalPixelRatio;
360
- canvas.height = deviceLogicalHeight * devicePhysicalPixelRatio;
361
-
362
- canvas.style.width = `${deviceLogicalWidth}px`;
363
- canvas.style.height = `${deviceLogicalHeight}px`;
364
-
365
- let targetEl: HTMLElement | null;
366
- if (typeof target === 'string') {
367
- targetEl = document.getElementById(target);
368
- } else {
369
- targetEl = target;
370
- }
371
-
372
- if (!targetEl) {
373
- throw new Error('Could not find target element');
374
- }
375
-
376
- // Hook up the driver's callbacks
377
- driver.onCreateNode = (node) => {
378
- this.nodes.set(node.id, node);
379
- };
380
-
381
- driver.onBeforeDestroyNode = (node) => {
382
- this.nodes.delete(node.id);
383
- };
384
-
385
- driver.onFpsUpdate = (fpsData) => {
386
- this.emit('fpsUpdate', fpsData);
387
- };
388
-
389
- driver.onFrameTick = (frameTickData) => {
390
- this.emit('frameTick', frameTickData);
391
- };
392
-
393
- targetEl.appendChild(canvas);
394
-
395
- if (enableInspector && !import.meta.env.PROD) {
396
- this.inspector = new Inspector(canvas, resolvedSettings);
397
- }
398
- }
399
-
400
- /**
401
- * Initialize the renderer
402
- *
403
- * @remarks
404
- * This method must be called and resolved asyncronously before any other
405
- * methods are called.
406
- */
407
- async init(): Promise<void> {
408
- await this.driver.init(this, this.settings, this.canvas);
409
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
410
- (this.root as INode) = this.driver.getRootNode();
411
- }
412
-
413
- /**
414
- * Create a new scene graph node
415
- *
416
- * @remarks
417
- * A node is the main graphical building block of the Renderer scene graph. It
418
- * can be a container for other nodes, or it can be a leaf node that renders a
419
- * solid color, gradient, image, or specific texture, using a specific shader.
420
- *
421
- * To create a text node, see {@link createTextNode}.
422
- *
423
- * See {@link INode} for more details.
424
- *
425
- * @param props
426
- * @returns
427
- */
428
- createNode(props: Partial<INodeWritableProps>): INode {
429
- if (this.inspector) {
430
- return this.inspector.createNode(
431
- this.driver,
432
- this.resolveNodeDefaults(props),
433
- );
434
- }
435
-
436
- return this.driver.createNode(this.resolveNodeDefaults(props));
437
- }
438
-
439
- /**
440
- * Create a new scene graph text node
441
- *
442
- * @remarks
443
- * A text node is the second graphical building block of the Renderer scene
444
- * graph. It renders text using a specific text renderer that is automatically
445
- * chosen based on the font requested and what type of fonts are installed
446
- * into an app via a CoreExtension.
447
- *
448
- * See {@link ITextNode} for more details.
449
- *
450
- * @param props
451
- * @returns
452
- */
453
- createTextNode(props: Partial<ITextNodeWritableProps>): ITextNode {
454
- const fontSize = props.fontSize ?? 16;
455
- const data = {
456
- ...this.resolveNodeDefaults(props),
457
- text: props.text ?? '',
458
- textRendererOverride: props.textRendererOverride ?? null,
459
- fontSize,
460
- fontFamily: props.fontFamily ?? 'sans-serif',
461
- fontStyle: props.fontStyle ?? 'normal',
462
- fontWeight: props.fontWeight ?? 'normal',
463
- fontStretch: props.fontStretch ?? 'normal',
464
- textAlign: props.textAlign ?? 'left',
465
- contain: props.contain ?? 'none',
466
- scrollable: props.scrollable ?? false,
467
- scrollY: props.scrollY ?? 0,
468
- offsetY: props.offsetY ?? 0,
469
- letterSpacing: props.letterSpacing ?? 0,
470
- lineHeight: props.lineHeight ?? fontSize,
471
- maxLines: props.maxLines ?? 0,
472
- textBaseline: props.textBaseline ?? 'alphabetic',
473
- verticalAlign: props.verticalAlign ?? 'top',
474
- overflowSuffix: props.overflowSuffix ?? '...',
475
- debug: props.debug ?? {},
476
- };
477
-
478
- if (this.inspector) {
479
- return this.inspector.createTextNode(this.driver, data);
480
- }
481
-
482
- return this.driver.createTextNode(data);
483
- }
484
-
485
- /**
486
- * Resolves the default property values for a Node
487
- *
488
- * @remarks
489
- * This method is used internally by the RendererMain to resolve the default
490
- * property values for a Node. It is exposed publicly so that it can be used
491
- * by Core Driver implementations.
492
- *
493
- * @param props
494
- * @returns
495
- */
496
- resolveNodeDefaults(props: Partial<INodeWritableProps>): INodeWritableProps {
497
- const color = props.color ?? 0xffffffff;
498
- const colorTl = props.colorTl ?? props.colorTop ?? props.colorLeft ?? color;
499
- const colorTr =
500
- props.colorTr ?? props.colorTop ?? props.colorRight ?? color;
501
- const colorBl =
502
- props.colorBl ?? props.colorBottom ?? props.colorLeft ?? color;
503
- const colorBr =
504
- props.colorBr ?? props.colorBottom ?? props.colorRight ?? color;
505
- const data = santizeCustomDataMap(props.data ?? {});
506
-
507
- return {
508
- x: props.x ?? 0,
509
- y: props.y ?? 0,
510
- width: props.width ?? 0,
511
- height: props.height ?? 0,
512
- alpha: props.alpha ?? 1,
513
- clipping: props.clipping ?? false,
514
- color,
515
- colorTop: props.colorTop ?? color,
516
- colorBottom: props.colorBottom ?? color,
517
- colorLeft: props.colorLeft ?? color,
518
- colorRight: props.colorRight ?? color,
519
- colorBl,
520
- colorBr,
521
- colorTl,
522
- colorTr,
523
- zIndex: props.zIndex ?? 0,
524
- zIndexLocked: props.zIndexLocked ?? 0,
525
- parent: props.parent ?? null,
526
- texture: props.texture ?? null,
527
- shader: props.shader ?? null,
528
- // Since setting the `src` will trigger a texture load, we need to set it after
529
- // we set the texture. Otherwise, problems happen.
530
- src: props.src ?? '',
531
- scale: props.scale ?? null,
532
- scaleX: props.scaleX ?? props.scale ?? 1,
533
- scaleY: props.scaleY ?? props.scale ?? 1,
534
- mount: props.mount ?? 0,
535
- mountX: props.mountX ?? props.mount ?? 0,
536
- mountY: props.mountY ?? props.mount ?? 0,
537
- pivot: props.pivot ?? 0.5,
538
- pivotX: props.pivotX ?? props.pivot ?? 0.5,
539
- pivotY: props.pivotY ?? props.pivot ?? 0.5,
540
- rotation: props.rotation ?? 0,
541
- data: data,
542
- };
543
- }
544
-
545
- /**
546
- * Destroy a node
547
- *
548
- * @remarks
549
- * This method destroys a node but does not destroy its children.
550
- *
551
- * @param node
552
- * @returns
553
- */
554
- destroyNode(node: INode) {
555
- if (this.inspector) {
556
- this.inspector.destroyNode(node);
557
- }
558
-
559
- return this.driver.destroyNode(node);
560
- }
561
-
562
- /**
563
- * Create a new texture reference
564
- *
565
- * @remarks
566
- * This method creates a new reference to a texture. The texture is not
567
- * loaded until it is used on a node.
568
- *
569
- * It can be assigned to a node's `texture` property, or it can be used
570
- * when creating a SubTexture.
571
- *
572
- * @param textureType
573
- * @param props
574
- * @param options
575
- * @returns
576
- */
577
- createTexture<TxType extends keyof TextureMap>(
578
- textureType: TxType,
579
- props: SpecificTextureRef<TxType>['props'],
580
- options?: TextureOptions,
581
- ): SpecificTextureRef<TxType> {
582
- const id = this.nextTextureId++;
583
- const desc = {
584
- descType: 'texture',
585
- txType: textureType,
586
- props,
587
- options: {
588
- ...options,
589
- // This ID is used to identify the texture in the CoreTextureManager's
590
- // ID Texture Map cache.
591
- id,
592
- },
593
- } satisfies SpecificTextureRef<TxType>;
594
- this.textureTracker.registerTexture(desc as TextureRef);
595
- return desc;
596
- }
597
-
598
- /**
599
- * Create a new shader reference
600
- *
601
- * @remarks
602
- * This method creates a new reference to a shader. The shader is not
603
- * loaded until it is used on a Node.
604
- *
605
- * It can be assigned to a Node's `shader` property.
606
- *
607
- * @param shaderType
608
- * @param props
609
- * @returns
610
- */
611
- createShader<ShType extends keyof ShaderMap>(
612
- shaderType: ShType,
613
- props?: SpecificShaderRef<ShType>['props'],
614
- ): SpecificShaderRef<ShType> {
615
- return {
616
- descType: 'shader',
617
- shType: shaderType,
618
- props: props as SpecificShaderRef<ShType>['props'],
619
- };
620
- }
621
-
622
- /**
623
- * Get a Node by its ID
624
- *
625
- * @param id
626
- * @returns
627
- */
628
- getNodeById(id: number): INode | null {
629
- return this.nodes.get(id) || null;
630
- }
631
-
632
- toggleFreeze() {
633
- throw new Error('Not implemented');
634
- }
635
-
636
- advanceFrame() {
637
- throw new Error('Not implemented');
638
- }
639
-
640
- /**
641
- * Re-render the current frame without advancing any running animations.
642
- *
643
- * @remarks
644
- * Any state changes will be reflected in the re-rendered frame. Useful for
645
- * debugging.
646
- *
647
- * May not do anything if the render loop is running on a separate worker.
648
- */
649
- rerender() {
650
- throw new Error('Not implemented');
651
- }
652
- }
1
+ /*
2
+ * If not stated otherwise in this file or this component's LICENSE file the
3
+ * following copyright and licenses apply:
4
+ *
5
+ * Copyright 2023 Comcast Cable Communications Management, LLC.
6
+ *
7
+ * Licensed under the Apache License, Version 2.0 (the License);
8
+ * you may not use this file except in compliance with the License.
9
+ * You may obtain a copy of the License at
10
+ *
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+ *
13
+ * Unless required by applicable law or agreed to in writing, software
14
+ * distributed under the License is distributed on an "AS IS" BASIS,
15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ * See the License for the specific language governing permissions and
17
+ * limitations under the License.
18
+ */
19
+
20
+ /* eslint-disable @typescript-eslint/no-unused-vars */
21
+ import type { ShaderMap } from '../core/CoreShaderManager.js';
22
+ import type {
23
+ ExtractProps,
24
+ TextureMap,
25
+ TextureOptions,
26
+ } from '../core/CoreTextureManager.js';
27
+ import type {
28
+ INode,
29
+ INodeWritableProps,
30
+ ITextNode,
31
+ ITextNodeWritableProps,
32
+ } from './INode.js';
33
+ import type { ICoreDriver } from './ICoreDriver.js';
34
+ import {
35
+ ManualCountTextureUsageTracker,
36
+ type ManualCountTextureUsageTrackerOptions,
37
+ } from './texture-usage-trackers/ManualCountTextureUsageTracker.js';
38
+ import { FinalizationRegistryTextureUsageTracker } from './texture-usage-trackers/FinalizationRegistryTextureUsageTracker.js';
39
+ import type { TextureUsageTracker } from './texture-usage-trackers/TextureUsageTracker.js';
40
+ import { EventEmitter } from '../common/EventEmitter.js';
41
+ import { Inspector } from './Inspector.js';
42
+ import { santizeCustomDataMap } from '../render-drivers/utils.js';
43
+ import { isProductionEnvironment } from '../utils.js';
44
+
45
+ /**
46
+ * An immutable reference to a specific Texture type
47
+ *
48
+ * @remarks
49
+ * See {@link TextureRef} for more details.
50
+ */
51
+ export interface SpecificTextureRef<TxType extends keyof TextureMap> {
52
+ readonly descType: 'texture';
53
+ readonly txType: TxType;
54
+ readonly props: ExtractProps<TextureMap[TxType]>;
55
+ readonly options?: Readonly<TextureOptions>;
56
+ }
57
+
58
+ type MapTextureRefs<TxType extends keyof TextureMap> =
59
+ TxType extends keyof TextureMap ? SpecificTextureRef<TxType> : never;
60
+
61
+ /**
62
+ * An immutable reference to a Texture
63
+ *
64
+ * @remarks
65
+ * This structure should only be created by the RendererMain's `createTexture`
66
+ * method. The structure is immutable and should not be modified once created.
67
+ *
68
+ * A `TextureRef` exists in the Main API Space and is used to point to an actual
69
+ * `Texture` instance in the Core API Space. The `TextureRef` is used to
70
+ * communicate with the Core API Space to create, load, and destroy the
71
+ * `Texture` instance.
72
+ *
73
+ * This type is technically a discriminated union of all possible texture types.
74
+ * If you'd like to represent a specific texture type, you can use the
75
+ * `SpecificTextureRef` generic type.
76
+ */
77
+ export type TextureRef = MapTextureRefs<keyof TextureMap>;
78
+
79
+ /**
80
+ * An immutable reference to a specific Shader type
81
+ *
82
+ * @remarks
83
+ * See {@link ShaderRef} for more details.
84
+ */
85
+ export interface SpecificShaderRef<ShType extends keyof ShaderMap> {
86
+ readonly descType: 'shader';
87
+ readonly shType: ShType;
88
+ readonly props: ExtractProps<ShaderMap[ShType]>;
89
+ }
90
+
91
+ type MapShaderRefs<ShType extends keyof ShaderMap> =
92
+ ShType extends keyof ShaderMap ? SpecificShaderRef<ShType> : never;
93
+
94
+ /**
95
+ * An immutable reference to a Shader
96
+ *
97
+ * @remarks
98
+ * This structure should only be created by the RendererMain's `createShader`
99
+ * method. The structure is immutable and should not be modified once created.
100
+ *
101
+ * A `ShaderRef` exists in the Main API Space and is used to point to an actual
102
+ * `Shader` instance in the Core API Space. The `ShaderRef` is used to
103
+ * communicate with the Core API Space to create, load, and destroy the
104
+ * `Shader` instance.
105
+ *
106
+ * This type is technically a discriminated union of all possible shader types.
107
+ * If you'd like to represent a specific shader type, you can use the
108
+ * `SpecificShaderRef` generic type.
109
+ */
110
+ export type ShaderRef = MapShaderRefs<keyof ShaderMap>;
111
+
112
+ /**
113
+ * Configuration settings for {@link RendererMain}
114
+ */
115
+ export interface RendererMainSettings {
116
+ /**
117
+ * Authored logical pixel width of the application
118
+ *
119
+ * @defaultValue `1920`
120
+ */
121
+ appWidth?: number;
122
+
123
+ /**
124
+ * Authored logical pixel height of the application
125
+ *
126
+ * @defaultValue `1080`
127
+ */
128
+ appHeight?: number;
129
+
130
+ /**
131
+ * Texture Memory Byte Threshold
132
+ *
133
+ * @remarks
134
+ * When the amount of GPU VRAM used by textures exceeds this threshold,
135
+ * the Renderer will free up all the textures that are current not visible
136
+ * within the configured `boundsMargin`.
137
+ *
138
+ * When set to `0`, the threshold-based texture memory manager is disabled.
139
+ */
140
+ txMemByteThreshold?: number;
141
+
142
+ /**
143
+ * Bounds margin to extend the boundary in which a CoreNode is added as Quad.
144
+ */
145
+ boundsMargin?: number | [number, number, number, number];
146
+
147
+ /**
148
+ * Factor to convert app-authored logical coorindates to device logical coordinates
149
+ *
150
+ * @remarks
151
+ * This value allows auto-scaling to support larger/small resolutions than the
152
+ * app was authored for.
153
+ *
154
+ * If the app was authored for 1920x1080 and this value is 2, the app's canvas
155
+ * will be rendered at 3840x2160 logical pixels.
156
+ *
157
+ * Likewise, if the app was authored for 1920x1080 and this value is 0.66667,
158
+ * the app's canvas will be rendered at 1280x720 logical pixels.
159
+ *
160
+ * @defaultValue `1`
161
+ */
162
+ deviceLogicalPixelRatio?: number;
163
+
164
+ /**
165
+ * Factor to convert device logical coordinates to device physical coordinates
166
+ *
167
+ * @remarks
168
+ * This value allows auto-scaling to support devices with different pixel densities.
169
+ *
170
+ * This controls the number of physical pixels that are used to render each logical
171
+ * pixel. For example, if the device has a pixel density of 2, each logical pixel
172
+ * will be rendered using 2x2 physical pixels.
173
+ *
174
+ * By default, it will be set to `window.devicePixelRatio` which is the pixel
175
+ * density of the device the app is running on reported by the browser.
176
+ *
177
+ * @defaultValue `window.devicePixelRatio`
178
+ */
179
+ devicePhysicalPixelRatio?: number;
180
+
181
+ /**
182
+ * RGBA encoded number of the background to use
183
+ *
184
+ * @defaultValue `0x00000000`
185
+ */
186
+ clearColor?: number;
187
+
188
+ /**
189
+ * Path to a custom core module to use
190
+ *
191
+ * @defaultValue `null`
192
+ */
193
+ coreExtensionModule?: string | null;
194
+
195
+ /**
196
+ * Enable experimental FinalizationRegistry-based texture usage tracking
197
+ * for texture garbage collection
198
+ *
199
+ * @remarks
200
+ * By default, the Renderer uses a manual reference counting system to track
201
+ * texture usage. Textures are eventually released from the Core Texture
202
+ * Manager's Usage Cache when they are no longer referenced by any Nodes (or
203
+ * SubTextures that are referenced by nodes). This works well enough, but has
204
+ * the consequence of textures being removed from Usage Cache even if their
205
+ * references are still alive in memory. This can require a texture to be
206
+ * reloaded from the source when it is used again after being removed from
207
+ * cache.
208
+ *
209
+ * This is an experimental feature that uses a FinalizationRegistry to track
210
+ * texture usage. This causes textures to be removed from the Usage Cache only
211
+ * when their references are no longer alive in memory. Meaning a loaded texture
212
+ * will remain in the Usage Cache until it's reference is garbage collected.
213
+ *
214
+ * This feature is not enabled by default because browser support for the
215
+ * FinalizationRegistry is limited. It should NOT be enabled in production apps
216
+ * as this behavior is not guaranteed to be supported in the future. Developer
217
+ * feedback on this feature, however, is welcome.
218
+ *
219
+ * @defaultValue `false`
220
+ */
221
+ experimental_FinalizationRegistryTextureUsageTracker?: boolean;
222
+
223
+ textureCleanupOptions?: ManualCountTextureUsageTrackerOptions;
224
+
225
+ /**
226
+ * Interval in milliseconds to receive FPS updates
227
+ *
228
+ * @remarks
229
+ * If set to `0`, FPS updates will be disabled.
230
+ *
231
+ * @defaultValue `0` (disabled)
232
+ */
233
+ fpsUpdateInterval?: number;
234
+
235
+ /**
236
+ * Include context call (i.e. WebGL) information in FPS updates
237
+ *
238
+ * @remarks
239
+ * When enabled the number of calls to each context method over the
240
+ * `fpsUpdateInterval` will be included in the FPS update payload's
241
+ * `contextSpyData` property.
242
+ *
243
+ * Enabling the context spy has a serious impact on performance so only use it
244
+ * when you need to extract context call information.
245
+ *
246
+ * @defaultValue `false` (disabled)
247
+ */
248
+ enableContextSpy?: boolean;
249
+
250
+ /**
251
+ * Number or Image Workers to use
252
+ *
253
+ * @remarks
254
+ * On devices with multiple cores, this can be used to improve image loading
255
+ * as well as reduce the impact of image loading on the main thread.
256
+ * Set to 0 to disable image workers.
257
+ *
258
+ * @defaultValue `2`
259
+ */
260
+ numImageWorkers?: number;
261
+
262
+ /**
263
+ * Enable inspector
264
+ *
265
+ * @remarks
266
+ * When enabled the renderer will spawn a inspector. The inspector will
267
+ * replicate the state of the Nodes created in the renderer and allow
268
+ * inspection of the state of the nodes.
269
+ *
270
+ * @defaultValue `false` (disabled)
271
+ */
272
+ enableInspector?: boolean;
273
+ }
274
+
275
+ /**
276
+ * The Renderer Main API
277
+ *
278
+ * @remarks
279
+ * This is the primary class used to configure and operate the Renderer.
280
+ *
281
+ * It is used to create and destroy Nodes, as well as Texture and Shader
282
+ * references.
283
+ *
284
+ * Example:
285
+ * ```ts
286
+ * import { RendererMain, MainCoreDriver } from '@lightningjs/renderer';
287
+ *
288
+ * // Initialize the Renderer
289
+ * const renderer = new RendererMain(
290
+ * {
291
+ * appWidth: 1920,
292
+ * appHeight: 1080
293
+ * },
294
+ * 'app',
295
+ * new MainCoreDriver(),
296
+ * );
297
+ * ```
298
+ */
299
+ export class RendererMain extends EventEmitter {
300
+ readonly root: INode | null = null;
301
+ readonly driver: ICoreDriver;
302
+ readonly canvas: HTMLCanvasElement;
303
+ readonly settings: Readonly<Required<RendererMainSettings>>;
304
+ private inspector: Inspector | null = null;
305
+ private nodes: Map<number, INode> = new Map();
306
+ private nextTextureId = 1;
307
+
308
+ /**
309
+ * Texture Usage Tracker for Usage Based Texture Garbage Collection
310
+ *
311
+ * @remarks
312
+ * For internal use only. DO NOT ACCESS.
313
+ */
314
+ public textureTracker: TextureUsageTracker;
315
+
316
+ /**
317
+ * Constructs a new Renderer instance
318
+ *
319
+ * @param settings Renderer settings
320
+ * @param target Element ID or HTMLElement to insert the canvas into
321
+ * @param driver Core Driver to use
322
+ */
323
+ constructor(
324
+ settings: RendererMainSettings,
325
+ target: string | HTMLElement,
326
+ driver: ICoreDriver,
327
+ ) {
328
+ super();
329
+ const resolvedSettings: Required<RendererMainSettings> = {
330
+ appWidth: settings.appWidth || 1920,
331
+ appHeight: settings.appHeight || 1080,
332
+ txMemByteThreshold: settings.txMemByteThreshold || 124e6,
333
+ boundsMargin: settings.boundsMargin || 0,
334
+ deviceLogicalPixelRatio: settings.deviceLogicalPixelRatio || 1,
335
+ devicePhysicalPixelRatio:
336
+ settings.devicePhysicalPixelRatio || window.devicePixelRatio,
337
+ clearColor: settings.clearColor ?? 0x00000000,
338
+ coreExtensionModule: settings.coreExtensionModule || null,
339
+ experimental_FinalizationRegistryTextureUsageTracker:
340
+ settings.experimental_FinalizationRegistryTextureUsageTracker ?? false,
341
+ textureCleanupOptions: settings.textureCleanupOptions || {},
342
+ fpsUpdateInterval: settings.fpsUpdateInterval || 0,
343
+ numImageWorkers:
344
+ settings.numImageWorkers !== undefined ? settings.numImageWorkers : 2,
345
+ enableContextSpy: settings.enableContextSpy ?? false,
346
+ enableInspector: settings.enableInspector ?? false,
347
+ };
348
+ this.settings = resolvedSettings;
349
+
350
+ const {
351
+ appWidth,
352
+ appHeight,
353
+ deviceLogicalPixelRatio,
354
+ devicePhysicalPixelRatio,
355
+ enableInspector,
356
+ } = resolvedSettings;
357
+
358
+ const releaseCallback = (textureId: number) => {
359
+ this.driver.releaseTexture(textureId);
360
+ };
361
+
362
+ const useFinalizationRegistryTracker =
363
+ resolvedSettings.experimental_FinalizationRegistryTextureUsageTracker &&
364
+ typeof FinalizationRegistry === 'function';
365
+ this.textureTracker = useFinalizationRegistryTracker
366
+ ? new FinalizationRegistryTextureUsageTracker(releaseCallback)
367
+ : new ManualCountTextureUsageTracker(
368
+ releaseCallback,
369
+ this.settings.textureCleanupOptions,
370
+ );
371
+
372
+ const deviceLogicalWidth = appWidth * deviceLogicalPixelRatio;
373
+ const deviceLogicalHeight = appHeight * deviceLogicalPixelRatio;
374
+
375
+ this.driver = driver;
376
+
377
+ const canvas = document.createElement('canvas');
378
+ this.canvas = canvas;
379
+ canvas.width = deviceLogicalWidth * devicePhysicalPixelRatio;
380
+ canvas.height = deviceLogicalHeight * devicePhysicalPixelRatio;
381
+
382
+ canvas.style.width = `${deviceLogicalWidth}px`;
383
+ canvas.style.height = `${deviceLogicalHeight}px`;
384
+
385
+ let targetEl: HTMLElement | null;
386
+ if (typeof target === 'string') {
387
+ targetEl = document.getElementById(target);
388
+ } else {
389
+ targetEl = target;
390
+ }
391
+
392
+ if (!targetEl) {
393
+ throw new Error('Could not find target element');
394
+ }
395
+
396
+ // Hook up the driver's callbacks
397
+ driver.onCreateNode = (node) => {
398
+ this.nodes.set(node.id, node);
399
+ };
400
+
401
+ driver.onBeforeDestroyNode = (node) => {
402
+ this.nodes.delete(node.id);
403
+ };
404
+
405
+ driver.onFpsUpdate = (fpsData) => {
406
+ this.emit('fpsUpdate', fpsData);
407
+ };
408
+
409
+ driver.onFrameTick = (frameTickData) => {
410
+ this.emit('frameTick', frameTickData);
411
+ };
412
+
413
+ driver.onIdle = () => {
414
+ this.emit('idle');
415
+ };
416
+
417
+ targetEl.appendChild(canvas);
418
+
419
+ if (enableInspector && !isProductionEnvironment()) {
420
+ this.inspector = new Inspector(canvas, resolvedSettings);
421
+ }
422
+ }
423
+
424
+ /**
425
+ * Initialize the renderer
426
+ *
427
+ * @remarks
428
+ * This method must be called and resolved asyncronously before any other
429
+ * methods are called.
430
+ */
431
+ async init(): Promise<void> {
432
+ await this.driver.init(this, this.settings, this.canvas);
433
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
434
+ (this.root as INode) = this.driver.getRootNode();
435
+ }
436
+
437
+ /**
438
+ * Create a new scene graph node
439
+ *
440
+ * @remarks
441
+ * A node is the main graphical building block of the Renderer scene graph. It
442
+ * can be a container for other nodes, or it can be a leaf node that renders a
443
+ * solid color, gradient, image, or specific texture, using a specific shader.
444
+ *
445
+ * To create a text node, see {@link createTextNode}.
446
+ *
447
+ * See {@link INode} for more details.
448
+ *
449
+ * @param props
450
+ * @returns
451
+ */
452
+ createNode(props: Partial<INodeWritableProps>): INode {
453
+ if (this.inspector) {
454
+ return this.inspector.createNode(
455
+ this.driver,
456
+ this.resolveNodeDefaults(props),
457
+ );
458
+ }
459
+
460
+ return this.driver.createNode(this.resolveNodeDefaults(props));
461
+ }
462
+
463
+ /**
464
+ * Create a new scene graph text node
465
+ *
466
+ * @remarks
467
+ * A text node is the second graphical building block of the Renderer scene
468
+ * graph. It renders text using a specific text renderer that is automatically
469
+ * chosen based on the font requested and what type of fonts are installed
470
+ * into an app via a CoreExtension.
471
+ *
472
+ * See {@link ITextNode} for more details.
473
+ *
474
+ * @param props
475
+ * @returns
476
+ */
477
+ createTextNode(props: Partial<ITextNodeWritableProps>): ITextNode {
478
+ const fontSize = props.fontSize ?? 16;
479
+ const data = {
480
+ ...this.resolveNodeDefaults(props),
481
+ text: props.text ?? '',
482
+ textRendererOverride: props.textRendererOverride ?? null,
483
+ fontSize,
484
+ fontFamily: props.fontFamily ?? 'sans-serif',
485
+ fontStyle: props.fontStyle ?? 'normal',
486
+ fontWeight: props.fontWeight ?? 'normal',
487
+ fontStretch: props.fontStretch ?? 'normal',
488
+ textAlign: props.textAlign ?? 'left',
489
+ contain: props.contain ?? 'none',
490
+ scrollable: props.scrollable ?? false,
491
+ scrollY: props.scrollY ?? 0,
492
+ offsetY: props.offsetY ?? 0,
493
+ letterSpacing: props.letterSpacing ?? 0,
494
+ lineHeight: props.lineHeight ?? fontSize,
495
+ maxLines: props.maxLines ?? 0,
496
+ textBaseline: props.textBaseline ?? 'alphabetic',
497
+ verticalAlign: props.verticalAlign ?? 'top',
498
+ overflowSuffix: props.overflowSuffix ?? '...',
499
+ debug: props.debug ?? {},
500
+ };
501
+
502
+ if (this.inspector) {
503
+ return this.inspector.createTextNode(this.driver, data);
504
+ }
505
+
506
+ return this.driver.createTextNode(data);
507
+ }
508
+
509
+ /**
510
+ * Resolves the default property values for a Node
511
+ *
512
+ * @remarks
513
+ * This method is used internally by the RendererMain to resolve the default
514
+ * property values for a Node. It is exposed publicly so that it can be used
515
+ * by Core Driver implementations.
516
+ *
517
+ * @param props
518
+ * @returns
519
+ */
520
+ resolveNodeDefaults(props: Partial<INodeWritableProps>): INodeWritableProps {
521
+ const color = props.color ?? 0xffffffff;
522
+ const colorTl = props.colorTl ?? props.colorTop ?? props.colorLeft ?? color;
523
+ const colorTr =
524
+ props.colorTr ?? props.colorTop ?? props.colorRight ?? color;
525
+ const colorBl =
526
+ props.colorBl ?? props.colorBottom ?? props.colorLeft ?? color;
527
+ const colorBr =
528
+ props.colorBr ?? props.colorBottom ?? props.colorRight ?? color;
529
+ const data = santizeCustomDataMap(props.data ?? {});
530
+
531
+ return {
532
+ x: props.x ?? 0,
533
+ y: props.y ?? 0,
534
+ width: props.width ?? 0,
535
+ height: props.height ?? 0,
536
+ alpha: props.alpha ?? 1,
537
+ clipping: props.clipping ?? false,
538
+ color,
539
+ colorTop: props.colorTop ?? color,
540
+ colorBottom: props.colorBottom ?? color,
541
+ colorLeft: props.colorLeft ?? color,
542
+ colorRight: props.colorRight ?? color,
543
+ colorBl,
544
+ colorBr,
545
+ colorTl,
546
+ colorTr,
547
+ zIndex: props.zIndex ?? 0,
548
+ zIndexLocked: props.zIndexLocked ?? 0,
549
+ parent: props.parent ?? null,
550
+ texture: props.texture ?? null,
551
+ shader: props.shader ?? null,
552
+ // Since setting the `src` will trigger a texture load, we need to set it after
553
+ // we set the texture. Otherwise, problems happen.
554
+ src: props.src ?? '',
555
+ scale: props.scale ?? null,
556
+ scaleX: props.scaleX ?? props.scale ?? 1,
557
+ scaleY: props.scaleY ?? props.scale ?? 1,
558
+ mount: props.mount ?? 0,
559
+ mountX: props.mountX ?? props.mount ?? 0,
560
+ mountY: props.mountY ?? props.mount ?? 0,
561
+ pivot: props.pivot ?? 0.5,
562
+ pivotX: props.pivotX ?? props.pivot ?? 0.5,
563
+ pivotY: props.pivotY ?? props.pivot ?? 0.5,
564
+ rotation: props.rotation ?? 0,
565
+ data: data,
566
+ };
567
+ }
568
+
569
+ /**
570
+ * Destroy a node
571
+ *
572
+ * @remarks
573
+ * This method destroys a node but does not destroy its children.
574
+ *
575
+ * @param node
576
+ * @returns
577
+ */
578
+ destroyNode(node: INode) {
579
+ if (this.inspector) {
580
+ this.inspector.destroyNode(node);
581
+ }
582
+
583
+ return this.driver.destroyNode(node);
584
+ }
585
+
586
+ /**
587
+ * Create a new texture reference
588
+ *
589
+ * @remarks
590
+ * This method creates a new reference to a texture. The texture is not
591
+ * loaded until it is used on a node.
592
+ *
593
+ * It can be assigned to a node's `texture` property, or it can be used
594
+ * when creating a SubTexture.
595
+ *
596
+ * @param textureType
597
+ * @param props
598
+ * @param options
599
+ * @returns
600
+ */
601
+ createTexture<TxType extends keyof TextureMap>(
602
+ textureType: TxType,
603
+ props: SpecificTextureRef<TxType>['props'],
604
+ options?: TextureOptions,
605
+ ): SpecificTextureRef<TxType> {
606
+ const id = this.nextTextureId++;
607
+ const desc = {
608
+ descType: 'texture',
609
+ txType: textureType,
610
+ props,
611
+ options: {
612
+ ...options,
613
+ // This ID is used to identify the texture in the CoreTextureManager's
614
+ // ID Texture Map cache.
615
+ id,
616
+ },
617
+ } satisfies SpecificTextureRef<TxType>;
618
+ this.textureTracker.registerTexture(desc as TextureRef);
619
+ return desc;
620
+ }
621
+
622
+ /**
623
+ * Create a new shader reference
624
+ *
625
+ * @remarks
626
+ * This method creates a new reference to a shader. The shader is not
627
+ * loaded until it is used on a Node.
628
+ *
629
+ * It can be assigned to a Node's `shader` property.
630
+ *
631
+ * @param shaderType
632
+ * @param props
633
+ * @returns
634
+ */
635
+ createShader<ShType extends keyof ShaderMap>(
636
+ shaderType: ShType,
637
+ props?: SpecificShaderRef<ShType>['props'],
638
+ ): SpecificShaderRef<ShType> {
639
+ return {
640
+ descType: 'shader',
641
+ shType: shaderType,
642
+ props: props as SpecificShaderRef<ShType>['props'],
643
+ };
644
+ }
645
+
646
+ /**
647
+ * Get a Node by its ID
648
+ *
649
+ * @param id
650
+ * @returns
651
+ */
652
+ getNodeById(id: number): INode | null {
653
+ return this.nodes.get(id) || null;
654
+ }
655
+
656
+ toggleFreeze() {
657
+ throw new Error('Not implemented');
658
+ }
659
+
660
+ advanceFrame() {
661
+ throw new Error('Not implemented');
662
+ }
663
+
664
+ /**
665
+ * Re-render the current frame without advancing any running animations.
666
+ *
667
+ * @remarks
668
+ * Any state changes will be reflected in the re-rendered frame. Useful for
669
+ * debugging.
670
+ *
671
+ * May not do anything if the render loop is running on a separate worker.
672
+ */
673
+ rerender() {
674
+ throw new Error('Not implemented');
675
+ }
676
+ }