@lightningjs/renderer 0.7.5 → 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 (218) 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 +21 -4
  6. package/dist/src/core/CoreNode.js +145 -34
  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 +30 -25
  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.js +8 -2
  59. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js.map +1 -1
  60. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/findNearestMultiple.d.ts +8 -0
  61. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/findNearestMultiple.js +29 -0
  62. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/findNearestMultiple.js.map +1 -0
  63. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/SdfBufferHelper.d.ts +19 -0
  64. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/SdfBufferHelper.js +84 -0
  65. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/SdfBufferHelper.js.map +1 -0
  66. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutLine.d.ts +8 -0
  67. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutLine.js +40 -0
  68. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutLine.js.map +1 -0
  69. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutText2.d.ts +2 -0
  70. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutText2.js +41 -0
  71. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutText2.js.map +1 -0
  72. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/utils.d.ts +1 -0
  73. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/utils.js +4 -0
  74. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/utils.js.map +1 -0
  75. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2.d.ts +1 -0
  76. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2.js +2 -0
  77. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2.js.map +1 -0
  78. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/makeRenderWindow.d.ts +20 -0
  79. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/makeRenderWindow.js +55 -0
  80. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/makeRenderWindow.js.map +1 -0
  81. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/roundUpToMultiple.d.ts +9 -0
  82. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/roundUpToMultiple.js +32 -0
  83. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/roundUpToMultiple.js.map +1 -0
  84. package/dist/src/core/text-rendering/renderers/TextRenderer.d.ts +12 -0
  85. package/dist/src/core/text-rendering/renderers/TextRenderer.js.map +1 -1
  86. package/dist/src/core/textures/ImageTexture.js +16 -2
  87. package/dist/src/core/textures/ImageTexture.js.map +1 -1
  88. package/dist/src/core/textures/Texture.d.ts +1 -1
  89. package/dist/src/core/textures/Texture.js.map +1 -1
  90. package/dist/src/core/utils.d.ts +1 -1
  91. package/dist/src/main-api/RendererMain.d.ts +6 -0
  92. package/dist/src/main-api/RendererMain.js +1 -0
  93. package/dist/src/main-api/RendererMain.js.map +1 -1
  94. package/dist/src/render-drivers/main/MainCoreDriver.js +1 -0
  95. package/dist/src/render-drivers/main/MainCoreDriver.js.map +1 -1
  96. package/dist/src/render-drivers/main/MainOnlyNode.d.ts +4 -0
  97. package/dist/src/render-drivers/main/MainOnlyNode.js +22 -0
  98. package/dist/src/render-drivers/main/MainOnlyNode.js.map +1 -1
  99. package/dist/src/render-drivers/threadx/ThreadXCoreDriver.js +1 -0
  100. package/dist/src/render-drivers/threadx/ThreadXCoreDriver.js.map +1 -1
  101. package/dist/src/render-drivers/threadx/ThreadXRendererMessage.d.ts +1 -0
  102. package/dist/src/render-drivers/threadx/ThreadXRendererMessage.js.map +1 -1
  103. package/dist/src/render-drivers/threadx/worker/renderer.js +1 -0
  104. package/dist/src/render-drivers/threadx/worker/renderer.js.map +1 -1
  105. package/dist/tsconfig.dist.tsbuildinfo +1 -1
  106. package/exports/core-api.ts +102 -102
  107. package/exports/main-api.ts +60 -60
  108. package/exports/utils.ts +41 -41
  109. package/package.json +1 -1
  110. package/scripts/please-use-pnpm.js +13 -13
  111. package/src/common/CommonTypes.ts +125 -113
  112. package/src/common/EventEmitter.ts +77 -77
  113. package/src/common/IAnimationController.ts +29 -29
  114. package/src/core/CoreExtension.ts +32 -32
  115. package/src/core/CoreNode.ts +1114 -955
  116. package/src/core/CoreShaderManager.ts +243 -243
  117. package/src/core/CoreTextNode.ts +399 -391
  118. package/src/core/CoreTextureManager.ts +337 -326
  119. package/src/core/Stage.ts +365 -354
  120. package/src/core/animations/AnimationManager.ts +38 -38
  121. package/src/core/animations/CoreAnimation.ts +181 -181
  122. package/src/core/animations/CoreAnimationController.ts +148 -148
  123. package/src/core/lib/ContextSpy.ts +41 -41
  124. package/src/core/lib/ImageWorker.ts +149 -135
  125. package/src/core/lib/Matrix3d.ts +290 -290
  126. package/src/core/lib/RenderCoords.ts +86 -0
  127. package/src/core/lib/WebGlContextWrapper.ts +992 -992
  128. package/src/core/lib/textureCompression.ts +152 -152
  129. package/src/core/lib/utils.ts +250 -241
  130. package/src/core/platform.ts +46 -46
  131. package/src/core/renderers/CoreContextTexture.ts +30 -30
  132. package/src/core/renderers/CoreRenderOp.ts +22 -22
  133. package/src/core/renderers/CoreRenderer.ts +63 -63
  134. package/src/core/renderers/CoreShader.ts +41 -41
  135. package/src/core/renderers/webgl/WebGlCoreCtxSubTexture.ts +37 -37
  136. package/src/core/renderers/webgl/WebGlCoreCtxTexture.ts +233 -230
  137. package/src/core/renderers/webgl/WebGlCoreRenderOp.ts +107 -107
  138. package/src/core/renderers/webgl/WebGlCoreRenderer.ts +520 -520
  139. package/src/core/renderers/webgl/WebGlCoreShader.ts +337 -337
  140. package/src/core/renderers/webgl/internal/BufferCollection.ts +54 -54
  141. package/src/core/renderers/webgl/internal/RendererUtils.ts +148 -131
  142. package/src/core/renderers/webgl/internal/ShaderUtils.ts +136 -136
  143. package/src/core/renderers/webgl/internal/WebGlUtils.ts +35 -35
  144. package/src/core/renderers/webgl/shaders/DefaultShader.ts +95 -95
  145. package/src/core/renderers/webgl/shaders/DefaultShaderBatched.ts +132 -132
  146. package/src/core/renderers/webgl/shaders/DynamicShader.ts +474 -474
  147. package/src/core/renderers/webgl/shaders/RoundedRectangle.ts +161 -161
  148. package/src/core/renderers/webgl/shaders/SdfShader.ts +174 -174
  149. package/src/core/renderers/webgl/shaders/effects/BorderBottomEffect.ts +101 -101
  150. package/src/core/renderers/webgl/shaders/effects/BorderEffect.ts +86 -86
  151. package/src/core/renderers/webgl/shaders/effects/BorderLeftEffect.ts +101 -101
  152. package/src/core/renderers/webgl/shaders/effects/BorderRightEffect.ts +101 -101
  153. package/src/core/renderers/webgl/shaders/effects/BorderTopEffect.ts +101 -101
  154. package/src/core/renderers/webgl/shaders/effects/EffectUtils.ts +33 -33
  155. package/src/core/renderers/webgl/shaders/effects/FadeOutEffect.ts +135 -135
  156. package/src/core/renderers/webgl/shaders/effects/GlitchEffect.ts +145 -145
  157. package/src/core/renderers/webgl/shaders/effects/GrayscaleEffect.ts +67 -67
  158. package/src/core/renderers/webgl/shaders/effects/LinearGradientEffect.ts +176 -176
  159. package/src/core/renderers/webgl/shaders/effects/RadialGradientEffect.ts +159 -159
  160. package/src/core/renderers/webgl/shaders/effects/RadialProgressEffect.ts +186 -186
  161. package/src/core/renderers/webgl/shaders/effects/RadiusEffect.ts +121 -121
  162. package/src/core/renderers/webgl/shaders/effects/ShaderEffect.ts +114 -114
  163. package/src/core/text-rendering/TextTextureRendererUtils.ts +189 -189
  164. package/src/core/text-rendering/TrFontManager.ts +170 -166
  165. package/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.ts +141 -141
  166. package/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/FontShaper.ts +139 -139
  167. package/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.test.ts +173 -173
  168. package/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.ts +169 -169
  169. package/src/core/text-rendering/font-face-types/TrFontFace.ts +105 -105
  170. package/src/core/text-rendering/font-face-types/WebTrFontFace.ts +77 -77
  171. package/src/core/text-rendering/renderers/CanvasTextRenderer.ts +757 -751
  172. package/src/core/text-rendering/renderers/LightningTextTextureRenderer.ts +741 -741
  173. package/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.ts +784 -778
  174. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/PeekableGenerator.test.ts +48 -48
  175. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/PeekableGenerator.ts +66 -66
  176. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/SpecialCodepoints.ts +52 -52
  177. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/constants.ts +32 -32
  178. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/getStartConditions.ts +84 -84
  179. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/getUnicodeCodepoints.test.ts +133 -133
  180. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/getUnicodeCodepoints.ts +38 -38
  181. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.ts +393 -393
  182. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/measureText.test.ts +49 -49
  183. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/measureText.ts +51 -51
  184. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.test.ts +205 -205
  185. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.ts +93 -93
  186. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/util.ts +40 -40
  187. package/src/core/text-rendering/renderers/TextRenderer.ts +516 -504
  188. package/src/core/textures/ColorTexture.ts +86 -86
  189. package/src/core/textures/ImageTexture.ts +154 -140
  190. package/src/core/textures/NoiseTexture.ts +96 -96
  191. package/src/core/textures/SubTexture.ts +143 -143
  192. package/src/core/textures/Texture.ts +224 -218
  193. package/src/core/utils.ts +224 -224
  194. package/src/env.d.ts +7 -7
  195. package/src/main-api/ICoreDriver.ts +66 -66
  196. package/src/main-api/INode.ts +499 -499
  197. package/src/main-api/Inspector.ts +439 -439
  198. package/src/main-api/RendererMain.ts +659 -652
  199. package/src/main-api/texture-usage-trackers/FinalizationRegistryTextureUsageTracker.ts +45 -45
  200. package/src/main-api/texture-usage-trackers/ManualCountTextureUsageTracker.ts +154 -154
  201. package/src/main-api/texture-usage-trackers/TextureUsageTracker.ts +54 -54
  202. package/src/render-drivers/main/MainCoreDriver.ts +149 -148
  203. package/src/render-drivers/main/MainOnlyNode.ts +494 -466
  204. package/src/render-drivers/main/MainOnlyTextNode.ts +261 -261
  205. package/src/render-drivers/threadx/NodeStruct.ts +300 -300
  206. package/src/render-drivers/threadx/SharedNode.ts +97 -97
  207. package/src/render-drivers/threadx/TextNodeStruct.ts +211 -211
  208. package/src/render-drivers/threadx/ThreadXCoreDriver.ts +286 -285
  209. package/src/render-drivers/threadx/ThreadXMainAnimationController.ts +99 -99
  210. package/src/render-drivers/threadx/ThreadXMainNode.ts +192 -192
  211. package/src/render-drivers/threadx/ThreadXMainTextNode.ts +85 -85
  212. package/src/render-drivers/threadx/ThreadXRendererMessage.ts +111 -110
  213. package/src/render-drivers/threadx/worker/ThreadXRendererNode.ts +238 -238
  214. package/src/render-drivers/threadx/worker/ThreadXRendererTextNode.ts +149 -149
  215. package/src/render-drivers/threadx/worker/renderer.ts +152 -151
  216. package/src/render-drivers/utils.ts +97 -97
  217. package/src/utils.ts +207 -207
  218. package/COPYING +0 -1
@@ -1,652 +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
- 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
+
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
+ }