@lightningjs/renderer 0.7.4 → 0.7.6

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