@lightningjs/renderer 2.9.2 → 2.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (329) hide show
  1. package/LICENSE +202 -202
  2. package/NOTICE +3 -3
  3. package/README.md +147 -147
  4. package/dist/exports/core-api.d.ts +74 -0
  5. package/dist/exports/core-api.js +96 -0
  6. package/dist/exports/core-api.js.map +1 -0
  7. package/dist/exports/main-api.d.ts +30 -0
  8. package/dist/exports/main-api.js +45 -0
  9. package/dist/exports/main-api.js.map +1 -0
  10. package/dist/src/core/CoreExtension.d.ts +12 -0
  11. package/dist/src/core/CoreExtension.js +29 -0
  12. package/dist/src/core/CoreExtension.js.map +1 -0
  13. package/dist/src/core/CoreStuff.d.ts +1 -0
  14. package/dist/src/core/CoreStuff.js +138 -0
  15. package/dist/src/core/CoreStuff.js.map +1 -0
  16. package/dist/src/core/CoreTextureManager.d.ts +5 -2
  17. package/dist/src/core/CoreTextureManager.js +20 -11
  18. package/dist/src/core/CoreTextureManager.js.map +1 -1
  19. package/dist/src/core/LngNode.d.ts +736 -0
  20. package/dist/src/core/LngNode.js +1174 -0
  21. package/dist/src/core/LngNode.js.map +1 -0
  22. package/dist/src/core/Matrix2DContext.d.ts +15 -0
  23. package/dist/src/core/Matrix2DContext.js +45 -0
  24. package/dist/src/core/Matrix2DContext.js.map +1 -0
  25. package/dist/src/core/ShaderNode.d.ts +10 -0
  26. package/dist/src/core/ShaderNode.js +30 -0
  27. package/dist/src/core/ShaderNode.js.map +1 -0
  28. package/dist/src/core/Stage.d.ts +1 -1
  29. package/dist/src/core/Stage.js +2 -2
  30. package/dist/src/core/Stage.js.map +1 -1
  31. package/dist/src/core/TextNode.d.ts +103 -0
  32. package/dist/src/core/TextNode.js +331 -0
  33. package/dist/src/core/TextNode.js.map +1 -0
  34. package/dist/src/core/TextureMemoryManager.d.ts +30 -0
  35. package/dist/src/core/TextureMemoryManager.js +58 -38
  36. package/dist/src/core/TextureMemoryManager.js.map +1 -1
  37. package/dist/src/core/lib/Coords.d.ts +14 -0
  38. package/dist/src/core/lib/Coords.js +55 -0
  39. package/dist/src/core/lib/Coords.js.map +1 -0
  40. package/dist/src/core/lib/glm/common.d.ts +162 -0
  41. package/dist/src/core/lib/glm/common.js +81 -0
  42. package/dist/src/core/lib/glm/common.js.map +1 -0
  43. package/dist/src/core/lib/glm/index.d.ts +11 -0
  44. package/dist/src/core/lib/glm/index.js +30 -0
  45. package/dist/src/core/lib/glm/index.js.map +1 -0
  46. package/dist/src/core/lib/glm/mat2.d.ts +219 -0
  47. package/dist/src/core/lib/glm/mat2.js +396 -0
  48. package/dist/src/core/lib/glm/mat2.js.map +1 -0
  49. package/dist/src/core/lib/glm/mat2d.d.ts +237 -0
  50. package/dist/src/core/lib/glm/mat2d.js +442 -0
  51. package/dist/src/core/lib/glm/mat2d.js.map +1 -0
  52. package/dist/src/core/lib/glm/mat3.d.ts +283 -0
  53. package/dist/src/core/lib/glm/mat3.js +680 -0
  54. package/dist/src/core/lib/glm/mat3.js.map +1 -0
  55. package/dist/src/core/lib/glm/mat4.d.ts +550 -0
  56. package/dist/src/core/lib/glm/mat4.js +1802 -0
  57. package/dist/src/core/lib/glm/mat4.js.map +1 -0
  58. package/dist/src/core/lib/glm/quat.d.ts +363 -0
  59. package/dist/src/core/lib/glm/quat.js +693 -0
  60. package/dist/src/core/lib/glm/quat.js.map +1 -0
  61. package/dist/src/core/lib/glm/quat2.d.ts +356 -0
  62. package/dist/src/core/lib/glm/quat2.js +754 -0
  63. package/dist/src/core/lib/glm/quat2.js.map +1 -0
  64. package/dist/src/core/lib/glm/vec2.d.ts +365 -0
  65. package/dist/src/core/lib/glm/vec2.js +569 -0
  66. package/dist/src/core/lib/glm/vec2.js.map +1 -0
  67. package/dist/src/core/lib/glm/vec3.d.ts +406 -0
  68. package/dist/src/core/lib/glm/vec3.js +720 -0
  69. package/dist/src/core/lib/glm/vec3.js.map +1 -0
  70. package/dist/src/core/lib/glm/vec4.d.ts +330 -0
  71. package/dist/src/core/lib/glm/vec4.js +608 -0
  72. package/dist/src/core/lib/glm/vec4.js.map +1 -0
  73. package/dist/src/core/lib/textureSvg.js +1 -1
  74. package/dist/src/core/lib/textureSvg.js.map +1 -1
  75. package/dist/src/core/renderers/CoreShaderManager.d.ts +19 -0
  76. package/dist/src/core/renderers/CoreShaderManager.js +33 -0
  77. package/dist/src/core/renderers/CoreShaderManager.js.map +1 -0
  78. package/dist/src/core/renderers/canvas/CanvasCoreRenderer.js +4 -2
  79. package/dist/src/core/renderers/canvas/CanvasCoreRenderer.js.map +1 -1
  80. package/dist/src/core/renderers/canvas/CanvasCoreTexture.js +4 -4
  81. package/dist/src/core/renderers/canvas/CanvasCoreTexture.js.map +1 -1
  82. package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.js +9 -12
  83. package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.js.map +1 -1
  84. package/dist/src/core/renderers/webgl/WebGlCoreShaderManager.d.ts +27 -0
  85. package/dist/src/core/renderers/webgl/WebGlCoreShaderManager.js +82 -0
  86. package/dist/src/core/renderers/webgl/WebGlCoreShaderManager.js.map +1 -0
  87. package/dist/src/core/renderers/webgl/WebGlCoreShaderProgram.d.ts +11 -0
  88. package/dist/src/core/renderers/webgl/WebGlCoreShaderProgram.js +34 -0
  89. package/dist/src/core/renderers/webgl/WebGlCoreShaderProgram.js.map +1 -0
  90. package/dist/src/core/renderers/webgl/shaders/DefaultShader.js +45 -45
  91. package/dist/src/core/renderers/webgl/shaders/DefaultShaderBatched.js +61 -61
  92. package/dist/src/core/renderers/webgl/shaders/DynamicShader.js +93 -93
  93. package/dist/src/core/renderers/webgl/shaders/RoundedRectangle.js +63 -63
  94. package/dist/src/core/renderers/webgl/shaders/SdfShader.js +62 -62
  95. package/dist/src/core/renderers/webgl/shaders/effects/BorderBottomEffect.js +15 -15
  96. package/dist/src/core/renderers/webgl/shaders/effects/BorderEffect.js +6 -6
  97. package/dist/src/core/renderers/webgl/shaders/effects/BorderLeftEffect.js +15 -15
  98. package/dist/src/core/renderers/webgl/shaders/effects/BorderRightEffect.js +15 -15
  99. package/dist/src/core/renderers/webgl/shaders/effects/BorderTopEffect.js +15 -15
  100. package/dist/src/core/renderers/webgl/shaders/effects/FadeOutEffect.js +42 -42
  101. package/dist/src/core/renderers/webgl/shaders/effects/GlitchEffect.js +44 -44
  102. package/dist/src/core/renderers/webgl/shaders/effects/GrayscaleEffect.js +3 -3
  103. package/dist/src/core/renderers/webgl/shaders/effects/HolePunchEffect.js +22 -22
  104. package/dist/src/core/renderers/webgl/shaders/effects/LinearGradientEffect.js +28 -28
  105. package/dist/src/core/renderers/webgl/shaders/effects/RadialGradientEffect.js +10 -10
  106. package/dist/src/core/renderers/webgl/shaders/effects/RadialProgressEffect.js +37 -37
  107. package/dist/src/core/renderers/webgl/shaders/effects/RadiusEffect.js +19 -19
  108. package/dist/src/core/scene/Scene.d.ts +59 -0
  109. package/dist/src/core/scene/Scene.js +106 -0
  110. package/dist/src/core/scene/Scene.js.map +1 -0
  111. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/makeRenderWindow.d.ts +20 -0
  112. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/makeRenderWindow.js +55 -0
  113. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/makeRenderWindow.js.map +1 -0
  114. package/dist/src/core/textures/ColorTexture.js +1 -1
  115. package/dist/src/core/textures/ColorTexture.js.map +1 -1
  116. package/dist/src/core/textures/ImageTexture.js +3 -3
  117. package/dist/src/core/textures/ImageTexture.js.map +1 -1
  118. package/dist/src/core/textures/NoiseTexture.js +1 -1
  119. package/dist/src/core/textures/NoiseTexture.js.map +1 -1
  120. package/dist/src/core/textures/RenderTexture.js +1 -1
  121. package/dist/src/core/textures/RenderTexture.js.map +1 -1
  122. package/dist/src/core/textures/SubTexture.d.ts +4 -0
  123. package/dist/src/core/textures/SubTexture.js +54 -16
  124. package/dist/src/core/textures/SubTexture.js.map +1 -1
  125. package/dist/src/core/textures/Texture.d.ts +2 -34
  126. package/dist/src/core/textures/Texture.js +13 -69
  127. package/dist/src/core/textures/Texture.js.map +1 -1
  128. package/dist/src/main-api/ICoreDriver.d.ts +27 -0
  129. package/dist/src/main-api/ICoreDriver.js +20 -0
  130. package/dist/src/main-api/ICoreDriver.js.map +1 -0
  131. package/dist/src/main-api/IRenderDriver.d.ts +20 -0
  132. package/dist/src/main-api/IRenderDriver.js +20 -0
  133. package/dist/src/main-api/IRenderDriver.js.map +1 -0
  134. package/dist/src/main-api/IShaderController.d.ts +14 -0
  135. package/dist/src/main-api/IShaderController.js +30 -0
  136. package/dist/src/main-api/IShaderController.js.map +1 -0
  137. package/dist/src/main-api/IShaderNode.d.ts +17 -0
  138. package/dist/src/main-api/IShaderNode.js +19 -0
  139. package/dist/src/main-api/IShaderNode.js.map +1 -0
  140. package/dist/src/main-api/Renderer.d.ts +6 -5
  141. package/dist/src/main-api/Renderer.js +3 -2
  142. package/dist/src/main-api/Renderer.js.map +1 -1
  143. package/dist/src/main-api/RendererMain.d.ts +375 -0
  144. package/dist/src/main-api/RendererMain.js +365 -0
  145. package/dist/src/main-api/RendererMain.js.map +1 -0
  146. package/dist/src/main-api/texture-usage-trackers/FinalizationRegistryTextureUsageTracker.d.ts +9 -0
  147. package/dist/src/main-api/texture-usage-trackers/FinalizationRegistryTextureUsageTracker.js +38 -0
  148. package/dist/src/main-api/texture-usage-trackers/FinalizationRegistryTextureUsageTracker.js.map +1 -0
  149. package/dist/src/main-api/texture-usage-trackers/ManualCountTextureUsageTracker.d.ts +56 -0
  150. package/dist/src/main-api/texture-usage-trackers/ManualCountTextureUsageTracker.js +101 -0
  151. package/dist/src/main-api/texture-usage-trackers/ManualCountTextureUsageTracker.js.map +1 -0
  152. package/dist/src/main-api/texture-usage-trackers/TextureUsageTracker.d.ts +32 -0
  153. package/dist/src/main-api/texture-usage-trackers/TextureUsageTracker.js +28 -0
  154. package/dist/src/main-api/texture-usage-trackers/TextureUsageTracker.js.map +1 -0
  155. package/dist/src/render-drivers/main/MainCoreDriver.d.ts +24 -0
  156. package/dist/src/render-drivers/main/MainCoreDriver.js +118 -0
  157. package/dist/src/render-drivers/main/MainCoreDriver.js.map +1 -0
  158. package/dist/src/render-drivers/main/MainOnlyNode.d.ts +99 -0
  159. package/dist/src/render-drivers/main/MainOnlyNode.js +396 -0
  160. package/dist/src/render-drivers/main/MainOnlyNode.js.map +1 -0
  161. package/dist/src/render-drivers/main/MainOnlyShaderController.d.ts +6 -0
  162. package/dist/src/render-drivers/main/MainOnlyShaderController.js +15 -0
  163. package/dist/src/render-drivers/main/MainOnlyShaderController.js.map +1 -0
  164. package/dist/src/render-drivers/main/MainOnlyShaderNode.d.ts +7 -0
  165. package/dist/src/render-drivers/main/MainOnlyShaderNode.js +34 -0
  166. package/dist/src/render-drivers/main/MainOnlyShaderNode.js.map +1 -0
  167. package/dist/src/render-drivers/main/MainOnlyTextNode.d.ts +47 -0
  168. package/dist/src/render-drivers/main/MainOnlyTextNode.js +205 -0
  169. package/dist/src/render-drivers/main/MainOnlyTextNode.js.map +1 -0
  170. package/dist/src/render-drivers/main/MainRenderDriver.d.ts +17 -0
  171. package/dist/src/render-drivers/main/MainRenderDriver.js +88 -0
  172. package/dist/src/render-drivers/main/MainRenderDriver.js.map +1 -0
  173. package/dist/src/render-drivers/threadx/NodeStruct.d.ts +90 -0
  174. package/dist/src/render-drivers/threadx/NodeStruct.js +281 -0
  175. package/dist/src/render-drivers/threadx/NodeStruct.js.map +1 -0
  176. package/dist/src/render-drivers/threadx/SharedNode.d.ts +39 -0
  177. package/dist/src/render-drivers/threadx/SharedNode.js +60 -0
  178. package/dist/src/render-drivers/threadx/SharedNode.js.map +1 -0
  179. package/dist/src/render-drivers/threadx/TextNodeStruct.d.ts +44 -0
  180. package/dist/src/render-drivers/threadx/TextNodeStruct.js +201 -0
  181. package/dist/src/render-drivers/threadx/TextNodeStruct.js.map +1 -0
  182. package/dist/src/render-drivers/threadx/ThreadXCoreDriver.d.ts +28 -0
  183. package/dist/src/render-drivers/threadx/ThreadXCoreDriver.js +234 -0
  184. package/dist/src/render-drivers/threadx/ThreadXCoreDriver.js.map +1 -0
  185. package/dist/src/render-drivers/threadx/ThreadXMainAnimationController.d.ts +20 -0
  186. package/dist/src/render-drivers/threadx/ThreadXMainAnimationController.js +84 -0
  187. package/dist/src/render-drivers/threadx/ThreadXMainAnimationController.js.map +1 -0
  188. package/dist/src/render-drivers/threadx/ThreadXMainNode.d.ts +44 -0
  189. package/dist/src/render-drivers/threadx/ThreadXMainNode.js +154 -0
  190. package/dist/src/render-drivers/threadx/ThreadXMainNode.js.map +1 -0
  191. package/dist/src/render-drivers/threadx/ThreadXMainShaderController.d.ts +6 -0
  192. package/dist/src/render-drivers/threadx/ThreadXMainShaderController.js +16 -0
  193. package/dist/src/render-drivers/threadx/ThreadXMainShaderController.js.map +1 -0
  194. package/dist/src/render-drivers/threadx/ThreadXMainShaderNode.d.ts +7 -0
  195. package/dist/src/render-drivers/threadx/ThreadXMainShaderNode.js +15 -0
  196. package/dist/src/render-drivers/threadx/ThreadXMainShaderNode.js.map +1 -0
  197. package/dist/src/render-drivers/threadx/ThreadXMainTextNode.d.ts +28 -0
  198. package/dist/src/render-drivers/threadx/ThreadXMainTextNode.js +55 -0
  199. package/dist/src/render-drivers/threadx/ThreadXMainTextNode.js.map +1 -0
  200. package/dist/src/render-drivers/threadx/ThreadXRenderDriver.d.ts +21 -0
  201. package/dist/src/render-drivers/threadx/ThreadXRenderDriver.js +198 -0
  202. package/dist/src/render-drivers/threadx/ThreadXRenderDriver.js.map +1 -0
  203. package/dist/src/render-drivers/threadx/ThreadXRendererMessage.d.ts +70 -0
  204. package/dist/src/render-drivers/threadx/ThreadXRendererMessage.js +32 -0
  205. package/dist/src/render-drivers/threadx/ThreadXRendererMessage.js.map +1 -0
  206. package/dist/src/render-drivers/threadx/worker/ThreadXRendererNode.d.ts +19 -0
  207. package/dist/src/render-drivers/threadx/worker/ThreadXRendererNode.js +177 -0
  208. package/dist/src/render-drivers/threadx/worker/ThreadXRendererNode.js.map +1 -0
  209. package/dist/src/render-drivers/threadx/worker/ThreadXRendererTextNode.d.ts +27 -0
  210. package/dist/src/render-drivers/threadx/worker/ThreadXRendererTextNode.js +108 -0
  211. package/dist/src/render-drivers/threadx/worker/ThreadXRendererTextNode.js.map +1 -0
  212. package/dist/src/render-drivers/threadx/worker/renderer.d.ts +1 -0
  213. package/dist/src/render-drivers/threadx/worker/renderer.js +145 -0
  214. package/dist/src/render-drivers/threadx/worker/renderer.js.map +1 -0
  215. package/dist/src/render-drivers/utils.d.ts +12 -0
  216. package/dist/src/render-drivers/utils.js +69 -0
  217. package/dist/src/render-drivers/utils.js.map +1 -0
  218. package/dist/tsconfig.dist.tsbuildinfo +1 -1
  219. package/exports/canvas.ts +39 -39
  220. package/exports/index.ts +89 -89
  221. package/exports/inspector.ts +24 -24
  222. package/exports/utils.ts +44 -44
  223. package/exports/webgl.ts +38 -38
  224. package/package.json +2 -1
  225. package/scripts/please-use-pnpm.js +13 -13
  226. package/src/common/CommonTypes.ts +139 -139
  227. package/src/common/EventEmitter.ts +77 -77
  228. package/src/common/IAnimationController.ts +92 -92
  229. package/src/common/IEventEmitter.ts +28 -28
  230. package/src/core/CoreNode.test.ts +199 -199
  231. package/src/core/CoreNode.ts +2335 -2335
  232. package/src/core/CoreShaderManager.ts +292 -292
  233. package/src/core/CoreTextNode.ts +455 -455
  234. package/src/core/CoreTextureManager.ts +561 -548
  235. package/src/core/Stage.ts +700 -700
  236. package/src/core/TextureMemoryManager.ts +292 -277
  237. package/src/core/animations/AnimationManager.ts +38 -38
  238. package/src/core/animations/CoreAnimation.ts +340 -340
  239. package/src/core/animations/CoreAnimationController.ts +157 -157
  240. package/src/core/lib/ContextSpy.ts +41 -41
  241. package/src/core/lib/ImageWorker.ts +270 -270
  242. package/src/core/lib/Matrix3d.ts +244 -244
  243. package/src/core/lib/RenderCoords.ts +86 -86
  244. package/src/core/lib/WebGlContextWrapper.ts +1322 -1322
  245. package/src/core/lib/textureCompression.ts +152 -152
  246. package/src/core/lib/textureSvg.ts +78 -78
  247. package/src/core/lib/utils.ts +310 -310
  248. package/src/core/platform.ts +61 -61
  249. package/src/core/renderers/CoreContextTexture.ts +43 -43
  250. package/src/core/renderers/CoreRenderOp.ts +22 -22
  251. package/src/core/renderers/CoreRenderer.ts +114 -114
  252. package/src/core/renderers/CoreShader.ts +41 -41
  253. package/src/core/renderers/canvas/CanvasCoreRenderer.ts +371 -369
  254. package/src/core/renderers/canvas/CanvasCoreTexture.ts +150 -150
  255. package/src/core/renderers/canvas/internal/C2DShaderUtils.ts +231 -231
  256. package/src/core/renderers/canvas/internal/ColorUtils.ts +69 -69
  257. package/src/core/renderers/canvas/shaders/UnsupportedShader.ts +48 -48
  258. package/src/core/renderers/webgl/WebGlCoreCtxRenderTexture.ts +79 -79
  259. package/src/core/renderers/webgl/WebGlCoreCtxSubTexture.ts +50 -50
  260. package/src/core/renderers/webgl/WebGlCoreCtxTexture.ts +295 -298
  261. package/src/core/renderers/webgl/WebGlCoreRenderOp.ts +125 -125
  262. package/src/core/renderers/webgl/WebGlCoreRenderer.ts +805 -805
  263. package/src/core/renderers/webgl/WebGlCoreShader.ts +362 -362
  264. package/src/core/renderers/webgl/internal/BufferCollection.ts +54 -54
  265. package/src/core/renderers/webgl/internal/RendererUtils.ts +155 -155
  266. package/src/core/renderers/webgl/internal/ShaderUtils.ts +143 -143
  267. package/src/core/renderers/webgl/internal/WebGlUtils.ts +35 -35
  268. package/src/core/renderers/webgl/shaders/DefaultShader.ts +93 -93
  269. package/src/core/renderers/webgl/shaders/DefaultShaderBatched.ts +132 -132
  270. package/src/core/renderers/webgl/shaders/DynamicShader.ts +580 -580
  271. package/src/core/renderers/webgl/shaders/RoundedRectangle.ts +167 -167
  272. package/src/core/renderers/webgl/shaders/SdfShader.ts +204 -204
  273. package/src/core/renderers/webgl/shaders/effects/BorderBottomEffect.ts +101 -101
  274. package/src/core/renderers/webgl/shaders/effects/BorderEffect.ts +87 -87
  275. package/src/core/renderers/webgl/shaders/effects/BorderLeftEffect.ts +101 -101
  276. package/src/core/renderers/webgl/shaders/effects/BorderRightEffect.ts +101 -101
  277. package/src/core/renderers/webgl/shaders/effects/BorderTopEffect.ts +101 -101
  278. package/src/core/renderers/webgl/shaders/effects/EffectUtils.ts +159 -159
  279. package/src/core/renderers/webgl/shaders/effects/FadeOutEffect.ts +127 -127
  280. package/src/core/renderers/webgl/shaders/effects/GlitchEffect.ts +148 -148
  281. package/src/core/renderers/webgl/shaders/effects/GrayscaleEffect.ts +67 -67
  282. package/src/core/renderers/webgl/shaders/effects/HolePunchEffect.ts +157 -157
  283. package/src/core/renderers/webgl/shaders/effects/LinearGradientEffect.ts +171 -171
  284. package/src/core/renderers/webgl/shaders/effects/RadialGradientEffect.ts +168 -168
  285. package/src/core/renderers/webgl/shaders/effects/RadialProgressEffect.ts +187 -187
  286. package/src/core/renderers/webgl/shaders/effects/RadiusEffect.ts +110 -110
  287. package/src/core/renderers/webgl/shaders/effects/ShaderEffect.ts +196 -196
  288. package/src/core/text-rendering/TextRenderingUtils.ts +36 -36
  289. package/src/core/text-rendering/TextTextureRendererUtils.ts +263 -263
  290. package/src/core/text-rendering/TrFontManager.ts +183 -183
  291. package/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.ts +176 -176
  292. package/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/FontShaper.ts +139 -139
  293. package/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.test.ts +173 -173
  294. package/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.ts +171 -171
  295. package/src/core/text-rendering/font-face-types/TrFontFace.ts +187 -187
  296. package/src/core/text-rendering/font-face-types/WebTrFontFace.ts +94 -94
  297. package/src/core/text-rendering/renderers/CanvasTextRenderer.ts +509 -509
  298. package/src/core/text-rendering/renderers/LightningTextTextureRenderer.ts +808 -808
  299. package/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.ts +853 -853
  300. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/PeekableGenerator.test.ts +48 -48
  301. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/PeekableGenerator.ts +66 -66
  302. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/SpecialCodepoints.ts +52 -52
  303. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/constants.ts +32 -32
  304. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/getStartConditions.ts +117 -117
  305. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/getUnicodeCodepoints.test.ts +133 -133
  306. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/getUnicodeCodepoints.ts +38 -38
  307. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.ts +408 -408
  308. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/measureText.test.ts +49 -49
  309. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/measureText.ts +52 -52
  310. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.test.ts +205 -205
  311. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.ts +93 -93
  312. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/util.ts +40 -40
  313. package/src/core/text-rendering/renderers/TextRenderer.ts +557 -557
  314. package/src/core/textures/ColorTexture.ts +102 -102
  315. package/src/core/textures/ImageTexture.ts +379 -379
  316. package/src/core/textures/NoiseTexture.ts +104 -104
  317. package/src/core/textures/RenderTexture.ts +85 -85
  318. package/src/core/textures/SubTexture.ts +225 -179
  319. package/src/core/textures/Texture.ts +347 -435
  320. package/src/core/utils.ts +227 -227
  321. package/src/env.d.ts +7 -7
  322. package/src/main-api/DynamicShaderController.ts +104 -104
  323. package/src/main-api/INode.ts +101 -101
  324. package/src/main-api/Inspector.ts +505 -505
  325. package/src/main-api/Renderer.ts +698 -693
  326. package/src/main-api/ShaderController.ts +80 -80
  327. package/src/main-api/utils.ts +45 -45
  328. package/src/utils.ts +248 -248
  329. package/COPYING +0 -1
@@ -1,408 +1,408 @@
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
- import { assertTruthy } from '../../../../../utils.js';
21
- import type { Bound } from '../../../../lib/utils.js';
22
- import type {
23
- FontShaperProps,
24
- MappedGlyphInfo,
25
- UnmappedCharacterInfo,
26
- } from '../../../font-face-types/SdfTrFontFace/internal/FontShaper.js';
27
- import type { TrProps, TextRendererState } from '../../TextRenderer.js';
28
- import type { SdfTextRendererState } from '../SdfTextRenderer.js';
29
- import { PeekableIterator } from './PeekableGenerator.js';
30
- import { getUnicodeCodepoints } from './getUnicodeCodepoints.js';
31
- import { measureText } from './measureText.js';
32
-
33
- export function layoutText(
34
- curLineIndex: number,
35
- startX: number,
36
- startY: number,
37
- text: TrProps['text'],
38
- textAlign: TrProps['textAlign'],
39
- width: TrProps['width'],
40
- height: TrProps['height'],
41
- fontSize: TrProps['fontSize'],
42
- lineHeight: number,
43
- letterSpacing: TrProps['letterSpacing'],
44
- /**
45
- * Mutated
46
- */
47
- vertexBuffer: NonNullable<SdfTextRendererState['vertexBuffer']>,
48
- contain: TrProps['contain'],
49
- /**
50
- * Mutated
51
- */
52
- lineCache: SdfTextRendererState['lineCache'],
53
- rwSdf: Bound,
54
- trFontFace: SdfTextRendererState['trFontFace'],
55
- forceFullLayoutCalc: TextRendererState['forceFullLayoutCalc'],
56
- scrollable: TrProps['scrollable'],
57
- overflowSuffix: TrProps['overflowSuffix'],
58
- maxLines: TrProps['maxLines'],
59
- ): {
60
- bufferNumFloats: number;
61
- bufferNumQuads: number;
62
- layoutNumCharacters: number;
63
- fullyProcessed: boolean;
64
- maxX: number;
65
- maxY: number;
66
- numLines: number;
67
- } {
68
- assertTruthy(trFontFace, 'Font face must be loaded');
69
- assertTruthy(trFontFace.loaded, 'Font face must be loaded');
70
- assertTruthy(trFontFace.data, 'Font face must be loaded');
71
- assertTruthy(trFontFace.shaper, 'Font face must be loaded');
72
-
73
- // Regardless of fontSize (or other scaling properties), we layout the vertices of each glyph
74
- // using the fixed coordinate space determined by font size used to produce the atlas.
75
- // Scaling for display is handled by shader uniforms inexpensively.
76
- // So we have:
77
- // - vertex space: the space in which the vertices of each glyph are laid out
78
- // - screen space: the screen pixel space
79
- // Input properties such as x, y, w, fontSize, letterSpacing, etc. are all expressed in screen space.
80
- // We convert these to the vertex space by dividing them the `fontSizeRatio` factor.
81
-
82
- /**
83
- * See above
84
- */
85
- const fontSizeRatio = fontSize / trFontFace.data.info.size;
86
-
87
- /**
88
- * `lineHeight` in vertex coordinates
89
- */
90
- const vertexLineHeight = lineHeight / fontSizeRatio;
91
- /**
92
- * `w` in vertex coordinates
93
- */
94
- const vertexW = width / fontSizeRatio;
95
- /**
96
- * `letterSpacing` in vertex coordinates
97
- */
98
- const vertexLSpacing = letterSpacing / fontSizeRatio;
99
-
100
- const startingLineCacheEntry = lineCache[curLineIndex];
101
- const startingCodepointIndex = startingLineCacheEntry?.codepointIndex || 0;
102
- const startingMaxX = startingLineCacheEntry?.maxX || 0;
103
- const startingMaxY = startingLineCacheEntry?.maxY || 0;
104
-
105
- let maxX = startingMaxX;
106
- let maxY = startingMaxY;
107
- let curX = startX;
108
- let curY = startY;
109
-
110
- let bufferOffset = 0;
111
- /**
112
- * Buffer offset to last word boundry. This is -1 when we aren't in a word boundry.
113
- */
114
- const lastWord: {
115
- codepointIndex: number;
116
- bufferOffset: number;
117
- xStart: number;
118
- } = {
119
- codepointIndex: -1,
120
- bufferOffset: -1,
121
- xStart: -1,
122
- };
123
-
124
- const shaper = trFontFace.shaper;
125
-
126
- const shaperProps: FontShaperProps = {
127
- letterSpacing: vertexLSpacing,
128
- };
129
-
130
- // HACK: The space is used as a word boundary. When a text ends with a space, we need to
131
- // add an extra space to ensure the space is included in the line width calculation.
132
- if (text.endsWith(' ')) {
133
- text += ' ';
134
- }
135
-
136
- // Get glyphs
137
- let glyphs = shaper.shapeText(
138
- shaperProps,
139
- new PeekableIterator(
140
- getUnicodeCodepoints(text, startingCodepointIndex),
141
- startingCodepointIndex,
142
- ),
143
- );
144
-
145
- let glyphResult:
146
- | IteratorResult<MappedGlyphInfo | UnmappedCharacterInfo, void>
147
- | undefined;
148
-
149
- let curLineBufferStart = -1;
150
-
151
- const bufferLineInfos: {
152
- bufferStart: number;
153
- bufferEnd: number;
154
- }[] = [];
155
-
156
- const vertexTruncateHeight = height / fontSizeRatio;
157
- const overflowSuffVertexWidth = measureText(
158
- overflowSuffix,
159
- shaperProps,
160
- shaper,
161
- );
162
-
163
- // Line-by-line layout
164
- let moreLines = true;
165
- while (moreLines) {
166
- const nextLineWillFit =
167
- (maxLines === 0 || curLineIndex + 1 < maxLines) &&
168
- (contain !== 'both' ||
169
- scrollable ||
170
- curY + vertexLineHeight + trFontFace.maxCharHeight <=
171
- vertexTruncateHeight);
172
- const lineVertexW = nextLineWillFit
173
- ? vertexW
174
- : vertexW - overflowSuffVertexWidth;
175
- /**
176
- * Vertex X position to the beginning of the last word boundary. This becomes -1 when we start traversing a word.
177
- */
178
- let xStartLastWordBoundary = 0;
179
-
180
- const lineIsBelowWindowTop = curY + trFontFace.maxCharHeight >= rwSdf.y1;
181
- const lineIsAboveWindowBottom = curY <= rwSdf.y2;
182
- const lineIsWithinWindow = lineIsBelowWindowTop && lineIsAboveWindowBottom;
183
- // Layout glyphs in this line
184
- // Any break statements in this while loop will trigger a line break
185
- while ((glyphResult = glyphs.next()) && !glyphResult.done) {
186
- const glyph = glyphResult.value;
187
-
188
- if (curLineIndex === lineCache.length) {
189
- lineCache.push({
190
- codepointIndex: glyph.cluster,
191
- maxY,
192
- maxX,
193
- });
194
- } else if (curLineIndex > lineCache.length) {
195
- throw new Error('Unexpected lineCache length');
196
- }
197
-
198
- // If we encounter a word boundary (white space or newline) we invalidate
199
- // the lastWord and set the xStartLastWordBoundary if we haven't already.
200
- if (
201
- glyph.codepoint === 32 ||
202
- glyph.codepoint === 10 ||
203
- glyph.codepoint === 8203
204
- ) {
205
- if (lastWord.codepointIndex !== -1) {
206
- lastWord.codepointIndex = -1;
207
- xStartLastWordBoundary = curX;
208
- }
209
- } else if (lastWord.codepointIndex === -1) {
210
- lastWord.codepointIndex = glyph.cluster;
211
- lastWord.bufferOffset = bufferOffset;
212
- lastWord.xStart = xStartLastWordBoundary;
213
- }
214
-
215
- if (glyph.mapped) {
216
- // Mapped glyph
217
- const charEndX = curX + glyph.xOffset + glyph.width;
218
- // Word wrap check
219
- if (
220
- // We are containing the text
221
- contain !== 'none' &&
222
- // The current glyph reaches outside the contained width
223
- charEndX >= lineVertexW &&
224
- // There is a last word that we can break to the next line
225
- lastWord.codepointIndex !== -1 &&
226
- // Prevents infinite loop when a single word is longer than the width
227
- lastWord.xStart > 0
228
- ) {
229
- // The current word is about to go off the edge of the container width
230
- // Reinitialize the iterator starting at the last word
231
- // and proceeding to the next line
232
- if (nextLineWillFit) {
233
- glyphs = shaper.shapeText(
234
- shaperProps,
235
- new PeekableIterator(
236
- getUnicodeCodepoints(text, lastWord.codepointIndex),
237
- lastWord.codepointIndex,
238
- ),
239
- );
240
- bufferOffset = lastWord.bufferOffset;
241
- break;
242
- } else {
243
- glyphs = shaper.shapeText(
244
- shaperProps,
245
- new PeekableIterator(getUnicodeCodepoints(overflowSuffix, 0), 0),
246
- );
247
- curX = lastWord.xStart;
248
- bufferOffset = lastWord.bufferOffset;
249
- // HACK: For the rest of the line when inserting the overflow suffix,
250
- // set contain = 'none' to prevent an infinite loop.
251
- contain = 'none';
252
- }
253
- } else {
254
- // This glyph fits, so we can add it to the buffer
255
- const quadX = curX + glyph.xOffset;
256
- const quadY = curY + glyph.yOffset;
257
-
258
- // Only add to buffer for rendering if the line is within the render window
259
- if (lineIsWithinWindow) {
260
- if (curLineBufferStart === -1) {
261
- curLineBufferStart = bufferOffset;
262
- }
263
-
264
- const atlasEntry = trFontFace.getAtlasEntry(glyph.glyphId);
265
-
266
- // Add texture coordinates
267
- const u = atlasEntry.x / trFontFace.data.common.scaleW;
268
- const v = atlasEntry.y / trFontFace.data.common.scaleH;
269
- const uvWidth = atlasEntry.width / trFontFace.data.common.scaleW;
270
- const uvHeight = atlasEntry.height / trFontFace.data.common.scaleH;
271
-
272
- // TODO: (Performance) We can optimize this by using ELEMENT_ARRAY_BUFFER
273
- // eliminating the need to duplicate vertices
274
-
275
- // Top-left
276
- vertexBuffer[bufferOffset++] = quadX;
277
- vertexBuffer[bufferOffset++] = quadY;
278
- vertexBuffer[bufferOffset++] = u;
279
- vertexBuffer[bufferOffset++] = v;
280
-
281
- // Top-right
282
- vertexBuffer[bufferOffset++] = quadX + glyph.width;
283
- vertexBuffer[bufferOffset++] = quadY;
284
- vertexBuffer[bufferOffset++] = u + uvWidth;
285
- vertexBuffer[bufferOffset++] = v;
286
-
287
- // Bottom-left
288
- vertexBuffer[bufferOffset++] = quadX;
289
- vertexBuffer[bufferOffset++] = quadY + glyph.height;
290
- vertexBuffer[bufferOffset++] = u;
291
- vertexBuffer[bufferOffset++] = v + uvHeight;
292
-
293
- // Bottom-right
294
- vertexBuffer[bufferOffset++] = quadX + glyph.width;
295
- vertexBuffer[bufferOffset++] = quadY + glyph.height;
296
- vertexBuffer[bufferOffset++] = u + uvWidth;
297
- vertexBuffer[bufferOffset++] = v + uvHeight;
298
- }
299
-
300
- maxY = Math.max(maxY, quadY + glyph.height);
301
- maxX = Math.max(maxX, quadX + glyph.width);
302
- curX += glyph.xAdvance;
303
- }
304
- } else {
305
- // Unmapped character
306
-
307
- // Handle newlines
308
- if (glyph.codepoint === 10) {
309
- if (nextLineWillFit) {
310
- // The whole line fit, so we can break to the next line
311
- break;
312
- } else {
313
- // The whole line won't fit, so we need to add the overflow suffix
314
- glyphs = shaper.shapeText(
315
- shaperProps,
316
- new PeekableIterator(getUnicodeCodepoints(overflowSuffix, 0), 0),
317
- );
318
- // HACK: For the rest of the line when inserting the overflow suffix,
319
- // set contain = 'none' to prevent an infinite loop.
320
- contain = 'none';
321
- }
322
- }
323
- }
324
- }
325
-
326
- // Prepare for the next line...
327
- if (curLineBufferStart !== -1) {
328
- bufferLineInfos.push({
329
- bufferStart: curLineBufferStart,
330
- bufferEnd: bufferOffset,
331
- });
332
- curLineBufferStart = -1;
333
- }
334
- curX = 0;
335
- curY += vertexLineHeight;
336
- curLineIndex++;
337
- lastWord.codepointIndex = -1;
338
- xStartLastWordBoundary = 0;
339
-
340
- // Figure out if there are any more lines to render...
341
- if (!forceFullLayoutCalc && contain === 'both' && curY > rwSdf.y2) {
342
- // Stop layout calculation early (for performance purposes) if:
343
- // - We're not forcing a full layout calculation (for width/height calculation)
344
- // - ...and we're containing the text vertically+horizontally (contain === 'both')
345
- // - ...and we have a render window
346
- // - ...and the next line is below the bottom of the render window
347
- moreLines = false;
348
- } else if (glyphResult && glyphResult.done) {
349
- // If we've reached the end of the text, we know we're done
350
- moreLines = false;
351
- } else if (!nextLineWillFit) {
352
- // If we're contained vertically+horizontally (contain === 'both')
353
- // but not scrollable and the next line won't fit, we're done.
354
- moreLines = false;
355
- }
356
- }
357
-
358
- // Use textAlign to determine if we need to adjust the x position of the text
359
- // in the buffer line by line
360
- if (textAlign === 'center') {
361
- const vertexTextW = contain === 'none' ? maxX : vertexW;
362
-
363
- for (let i = 0; i < bufferLineInfos.length; i++) {
364
- const line = bufferLineInfos[i]!;
365
- // - 4 = the x position of a rightmost vertex
366
- const lineWidth =
367
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
368
- vertexBuffer[line.bufferEnd - 4]! - vertexBuffer[line.bufferStart]!;
369
-
370
- const xOffset = (vertexTextW - lineWidth) / 2;
371
- for (let j = line.bufferStart; j < line.bufferEnd; j += 4) {
372
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
373
- vertexBuffer[j]! += xOffset;
374
- }
375
- }
376
- } else if (textAlign === 'right') {
377
- const vertexTextW = contain === 'none' ? maxX : vertexW;
378
-
379
- for (let i = 0; i < bufferLineInfos.length; i++) {
380
- const line = bufferLineInfos[i]!;
381
- const lineWidth =
382
- line.bufferEnd === line.bufferStart
383
- ? 0
384
- : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
385
- vertexBuffer[line.bufferEnd - 4]! - vertexBuffer[line.bufferStart]!;
386
-
387
- const xOffset = vertexTextW - lineWidth;
388
- for (let j = line.bufferStart; j < line.bufferEnd; j += 4) {
389
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
390
- vertexBuffer[j]! += xOffset;
391
- }
392
- }
393
- }
394
-
395
- assertTruthy(glyphResult);
396
-
397
- return {
398
- bufferNumFloats: bufferOffset,
399
- bufferNumQuads: bufferOffset / 16,
400
- layoutNumCharacters: glyphResult.done
401
- ? text.length - startingCodepointIndex
402
- : glyphResult.value.cluster - startingCodepointIndex + 1,
403
- fullyProcessed: !!glyphResult.done,
404
- maxX,
405
- maxY,
406
- numLines: lineCache.length,
407
- };
408
- }
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
+ import { assertTruthy } from '../../../../../utils.js';
21
+ import type { Bound } from '../../../../lib/utils.js';
22
+ import type {
23
+ FontShaperProps,
24
+ MappedGlyphInfo,
25
+ UnmappedCharacterInfo,
26
+ } from '../../../font-face-types/SdfTrFontFace/internal/FontShaper.js';
27
+ import type { TrProps, TextRendererState } from '../../TextRenderer.js';
28
+ import type { SdfTextRendererState } from '../SdfTextRenderer.js';
29
+ import { PeekableIterator } from './PeekableGenerator.js';
30
+ import { getUnicodeCodepoints } from './getUnicodeCodepoints.js';
31
+ import { measureText } from './measureText.js';
32
+
33
+ export function layoutText(
34
+ curLineIndex: number,
35
+ startX: number,
36
+ startY: number,
37
+ text: TrProps['text'],
38
+ textAlign: TrProps['textAlign'],
39
+ width: TrProps['width'],
40
+ height: TrProps['height'],
41
+ fontSize: TrProps['fontSize'],
42
+ lineHeight: number,
43
+ letterSpacing: TrProps['letterSpacing'],
44
+ /**
45
+ * Mutated
46
+ */
47
+ vertexBuffer: NonNullable<SdfTextRendererState['vertexBuffer']>,
48
+ contain: TrProps['contain'],
49
+ /**
50
+ * Mutated
51
+ */
52
+ lineCache: SdfTextRendererState['lineCache'],
53
+ rwSdf: Bound,
54
+ trFontFace: SdfTextRendererState['trFontFace'],
55
+ forceFullLayoutCalc: TextRendererState['forceFullLayoutCalc'],
56
+ scrollable: TrProps['scrollable'],
57
+ overflowSuffix: TrProps['overflowSuffix'],
58
+ maxLines: TrProps['maxLines'],
59
+ ): {
60
+ bufferNumFloats: number;
61
+ bufferNumQuads: number;
62
+ layoutNumCharacters: number;
63
+ fullyProcessed: boolean;
64
+ maxX: number;
65
+ maxY: number;
66
+ numLines: number;
67
+ } {
68
+ assertTruthy(trFontFace, 'Font face must be loaded');
69
+ assertTruthy(trFontFace.loaded, 'Font face must be loaded');
70
+ assertTruthy(trFontFace.data, 'Font face must be loaded');
71
+ assertTruthy(trFontFace.shaper, 'Font face must be loaded');
72
+
73
+ // Regardless of fontSize (or other scaling properties), we layout the vertices of each glyph
74
+ // using the fixed coordinate space determined by font size used to produce the atlas.
75
+ // Scaling for display is handled by shader uniforms inexpensively.
76
+ // So we have:
77
+ // - vertex space: the space in which the vertices of each glyph are laid out
78
+ // - screen space: the screen pixel space
79
+ // Input properties such as x, y, w, fontSize, letterSpacing, etc. are all expressed in screen space.
80
+ // We convert these to the vertex space by dividing them the `fontSizeRatio` factor.
81
+
82
+ /**
83
+ * See above
84
+ */
85
+ const fontSizeRatio = fontSize / trFontFace.data.info.size;
86
+
87
+ /**
88
+ * `lineHeight` in vertex coordinates
89
+ */
90
+ const vertexLineHeight = lineHeight / fontSizeRatio;
91
+ /**
92
+ * `w` in vertex coordinates
93
+ */
94
+ const vertexW = width / fontSizeRatio;
95
+ /**
96
+ * `letterSpacing` in vertex coordinates
97
+ */
98
+ const vertexLSpacing = letterSpacing / fontSizeRatio;
99
+
100
+ const startingLineCacheEntry = lineCache[curLineIndex];
101
+ const startingCodepointIndex = startingLineCacheEntry?.codepointIndex || 0;
102
+ const startingMaxX = startingLineCacheEntry?.maxX || 0;
103
+ const startingMaxY = startingLineCacheEntry?.maxY || 0;
104
+
105
+ let maxX = startingMaxX;
106
+ let maxY = startingMaxY;
107
+ let curX = startX;
108
+ let curY = startY;
109
+
110
+ let bufferOffset = 0;
111
+ /**
112
+ * Buffer offset to last word boundry. This is -1 when we aren't in a word boundry.
113
+ */
114
+ const lastWord: {
115
+ codepointIndex: number;
116
+ bufferOffset: number;
117
+ xStart: number;
118
+ } = {
119
+ codepointIndex: -1,
120
+ bufferOffset: -1,
121
+ xStart: -1,
122
+ };
123
+
124
+ const shaper = trFontFace.shaper;
125
+
126
+ const shaperProps: FontShaperProps = {
127
+ letterSpacing: vertexLSpacing,
128
+ };
129
+
130
+ // HACK: The space is used as a word boundary. When a text ends with a space, we need to
131
+ // add an extra space to ensure the space is included in the line width calculation.
132
+ if (text.endsWith(' ')) {
133
+ text += ' ';
134
+ }
135
+
136
+ // Get glyphs
137
+ let glyphs = shaper.shapeText(
138
+ shaperProps,
139
+ new PeekableIterator(
140
+ getUnicodeCodepoints(text, startingCodepointIndex),
141
+ startingCodepointIndex,
142
+ ),
143
+ );
144
+
145
+ let glyphResult:
146
+ | IteratorResult<MappedGlyphInfo | UnmappedCharacterInfo, void>
147
+ | undefined;
148
+
149
+ let curLineBufferStart = -1;
150
+
151
+ const bufferLineInfos: {
152
+ bufferStart: number;
153
+ bufferEnd: number;
154
+ }[] = [];
155
+
156
+ const vertexTruncateHeight = height / fontSizeRatio;
157
+ const overflowSuffVertexWidth = measureText(
158
+ overflowSuffix,
159
+ shaperProps,
160
+ shaper,
161
+ );
162
+
163
+ // Line-by-line layout
164
+ let moreLines = true;
165
+ while (moreLines) {
166
+ const nextLineWillFit =
167
+ (maxLines === 0 || curLineIndex + 1 < maxLines) &&
168
+ (contain !== 'both' ||
169
+ scrollable ||
170
+ curY + vertexLineHeight + trFontFace.maxCharHeight <=
171
+ vertexTruncateHeight);
172
+ const lineVertexW = nextLineWillFit
173
+ ? vertexW
174
+ : vertexW - overflowSuffVertexWidth;
175
+ /**
176
+ * Vertex X position to the beginning of the last word boundary. This becomes -1 when we start traversing a word.
177
+ */
178
+ let xStartLastWordBoundary = 0;
179
+
180
+ const lineIsBelowWindowTop = curY + trFontFace.maxCharHeight >= rwSdf.y1;
181
+ const lineIsAboveWindowBottom = curY <= rwSdf.y2;
182
+ const lineIsWithinWindow = lineIsBelowWindowTop && lineIsAboveWindowBottom;
183
+ // Layout glyphs in this line
184
+ // Any break statements in this while loop will trigger a line break
185
+ while ((glyphResult = glyphs.next()) && !glyphResult.done) {
186
+ const glyph = glyphResult.value;
187
+
188
+ if (curLineIndex === lineCache.length) {
189
+ lineCache.push({
190
+ codepointIndex: glyph.cluster,
191
+ maxY,
192
+ maxX,
193
+ });
194
+ } else if (curLineIndex > lineCache.length) {
195
+ throw new Error('Unexpected lineCache length');
196
+ }
197
+
198
+ // If we encounter a word boundary (white space or newline) we invalidate
199
+ // the lastWord and set the xStartLastWordBoundary if we haven't already.
200
+ if (
201
+ glyph.codepoint === 32 ||
202
+ glyph.codepoint === 10 ||
203
+ glyph.codepoint === 8203
204
+ ) {
205
+ if (lastWord.codepointIndex !== -1) {
206
+ lastWord.codepointIndex = -1;
207
+ xStartLastWordBoundary = curX;
208
+ }
209
+ } else if (lastWord.codepointIndex === -1) {
210
+ lastWord.codepointIndex = glyph.cluster;
211
+ lastWord.bufferOffset = bufferOffset;
212
+ lastWord.xStart = xStartLastWordBoundary;
213
+ }
214
+
215
+ if (glyph.mapped) {
216
+ // Mapped glyph
217
+ const charEndX = curX + glyph.xOffset + glyph.width;
218
+ // Word wrap check
219
+ if (
220
+ // We are containing the text
221
+ contain !== 'none' &&
222
+ // The current glyph reaches outside the contained width
223
+ charEndX >= lineVertexW &&
224
+ // There is a last word that we can break to the next line
225
+ lastWord.codepointIndex !== -1 &&
226
+ // Prevents infinite loop when a single word is longer than the width
227
+ lastWord.xStart > 0
228
+ ) {
229
+ // The current word is about to go off the edge of the container width
230
+ // Reinitialize the iterator starting at the last word
231
+ // and proceeding to the next line
232
+ if (nextLineWillFit) {
233
+ glyphs = shaper.shapeText(
234
+ shaperProps,
235
+ new PeekableIterator(
236
+ getUnicodeCodepoints(text, lastWord.codepointIndex),
237
+ lastWord.codepointIndex,
238
+ ),
239
+ );
240
+ bufferOffset = lastWord.bufferOffset;
241
+ break;
242
+ } else {
243
+ glyphs = shaper.shapeText(
244
+ shaperProps,
245
+ new PeekableIterator(getUnicodeCodepoints(overflowSuffix, 0), 0),
246
+ );
247
+ curX = lastWord.xStart;
248
+ bufferOffset = lastWord.bufferOffset;
249
+ // HACK: For the rest of the line when inserting the overflow suffix,
250
+ // set contain = 'none' to prevent an infinite loop.
251
+ contain = 'none';
252
+ }
253
+ } else {
254
+ // This glyph fits, so we can add it to the buffer
255
+ const quadX = curX + glyph.xOffset;
256
+ const quadY = curY + glyph.yOffset;
257
+
258
+ // Only add to buffer for rendering if the line is within the render window
259
+ if (lineIsWithinWindow) {
260
+ if (curLineBufferStart === -1) {
261
+ curLineBufferStart = bufferOffset;
262
+ }
263
+
264
+ const atlasEntry = trFontFace.getAtlasEntry(glyph.glyphId);
265
+
266
+ // Add texture coordinates
267
+ const u = atlasEntry.x / trFontFace.data.common.scaleW;
268
+ const v = atlasEntry.y / trFontFace.data.common.scaleH;
269
+ const uvWidth = atlasEntry.width / trFontFace.data.common.scaleW;
270
+ const uvHeight = atlasEntry.height / trFontFace.data.common.scaleH;
271
+
272
+ // TODO: (Performance) We can optimize this by using ELEMENT_ARRAY_BUFFER
273
+ // eliminating the need to duplicate vertices
274
+
275
+ // Top-left
276
+ vertexBuffer[bufferOffset++] = quadX;
277
+ vertexBuffer[bufferOffset++] = quadY;
278
+ vertexBuffer[bufferOffset++] = u;
279
+ vertexBuffer[bufferOffset++] = v;
280
+
281
+ // Top-right
282
+ vertexBuffer[bufferOffset++] = quadX + glyph.width;
283
+ vertexBuffer[bufferOffset++] = quadY;
284
+ vertexBuffer[bufferOffset++] = u + uvWidth;
285
+ vertexBuffer[bufferOffset++] = v;
286
+
287
+ // Bottom-left
288
+ vertexBuffer[bufferOffset++] = quadX;
289
+ vertexBuffer[bufferOffset++] = quadY + glyph.height;
290
+ vertexBuffer[bufferOffset++] = u;
291
+ vertexBuffer[bufferOffset++] = v + uvHeight;
292
+
293
+ // Bottom-right
294
+ vertexBuffer[bufferOffset++] = quadX + glyph.width;
295
+ vertexBuffer[bufferOffset++] = quadY + glyph.height;
296
+ vertexBuffer[bufferOffset++] = u + uvWidth;
297
+ vertexBuffer[bufferOffset++] = v + uvHeight;
298
+ }
299
+
300
+ maxY = Math.max(maxY, quadY + glyph.height);
301
+ maxX = Math.max(maxX, quadX + glyph.width);
302
+ curX += glyph.xAdvance;
303
+ }
304
+ } else {
305
+ // Unmapped character
306
+
307
+ // Handle newlines
308
+ if (glyph.codepoint === 10) {
309
+ if (nextLineWillFit) {
310
+ // The whole line fit, so we can break to the next line
311
+ break;
312
+ } else {
313
+ // The whole line won't fit, so we need to add the overflow suffix
314
+ glyphs = shaper.shapeText(
315
+ shaperProps,
316
+ new PeekableIterator(getUnicodeCodepoints(overflowSuffix, 0), 0),
317
+ );
318
+ // HACK: For the rest of the line when inserting the overflow suffix,
319
+ // set contain = 'none' to prevent an infinite loop.
320
+ contain = 'none';
321
+ }
322
+ }
323
+ }
324
+ }
325
+
326
+ // Prepare for the next line...
327
+ if (curLineBufferStart !== -1) {
328
+ bufferLineInfos.push({
329
+ bufferStart: curLineBufferStart,
330
+ bufferEnd: bufferOffset,
331
+ });
332
+ curLineBufferStart = -1;
333
+ }
334
+ curX = 0;
335
+ curY += vertexLineHeight;
336
+ curLineIndex++;
337
+ lastWord.codepointIndex = -1;
338
+ xStartLastWordBoundary = 0;
339
+
340
+ // Figure out if there are any more lines to render...
341
+ if (!forceFullLayoutCalc && contain === 'both' && curY > rwSdf.y2) {
342
+ // Stop layout calculation early (for performance purposes) if:
343
+ // - We're not forcing a full layout calculation (for width/height calculation)
344
+ // - ...and we're containing the text vertically+horizontally (contain === 'both')
345
+ // - ...and we have a render window
346
+ // - ...and the next line is below the bottom of the render window
347
+ moreLines = false;
348
+ } else if (glyphResult && glyphResult.done) {
349
+ // If we've reached the end of the text, we know we're done
350
+ moreLines = false;
351
+ } else if (!nextLineWillFit) {
352
+ // If we're contained vertically+horizontally (contain === 'both')
353
+ // but not scrollable and the next line won't fit, we're done.
354
+ moreLines = false;
355
+ }
356
+ }
357
+
358
+ // Use textAlign to determine if we need to adjust the x position of the text
359
+ // in the buffer line by line
360
+ if (textAlign === 'center') {
361
+ const vertexTextW = contain === 'none' ? maxX : vertexW;
362
+
363
+ for (let i = 0; i < bufferLineInfos.length; i++) {
364
+ const line = bufferLineInfos[i]!;
365
+ // - 4 = the x position of a rightmost vertex
366
+ const lineWidth =
367
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
368
+ vertexBuffer[line.bufferEnd - 4]! - vertexBuffer[line.bufferStart]!;
369
+
370
+ const xOffset = (vertexTextW - lineWidth) / 2;
371
+ for (let j = line.bufferStart; j < line.bufferEnd; j += 4) {
372
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
373
+ vertexBuffer[j]! += xOffset;
374
+ }
375
+ }
376
+ } else if (textAlign === 'right') {
377
+ const vertexTextW = contain === 'none' ? maxX : vertexW;
378
+
379
+ for (let i = 0; i < bufferLineInfos.length; i++) {
380
+ const line = bufferLineInfos[i]!;
381
+ const lineWidth =
382
+ line.bufferEnd === line.bufferStart
383
+ ? 0
384
+ : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
385
+ vertexBuffer[line.bufferEnd - 4]! - vertexBuffer[line.bufferStart]!;
386
+
387
+ const xOffset = vertexTextW - lineWidth;
388
+ for (let j = line.bufferStart; j < line.bufferEnd; j += 4) {
389
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
390
+ vertexBuffer[j]! += xOffset;
391
+ }
392
+ }
393
+ }
394
+
395
+ assertTruthy(glyphResult);
396
+
397
+ return {
398
+ bufferNumFloats: bufferOffset,
399
+ bufferNumQuads: bufferOffset / 16,
400
+ layoutNumCharacters: glyphResult.done
401
+ ? text.length - startingCodepointIndex
402
+ : glyphResult.value.cluster - startingCodepointIndex + 1,
403
+ fullyProcessed: !!glyphResult.done,
404
+ maxX,
405
+ maxY,
406
+ numLines: lineCache.length,
407
+ };
408
+ }