@lightningtv/renderer 3.0.0-beta1 → 3.2.3

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 (497) hide show
  1. package/NOTICE +4 -0
  2. package/README.md +22 -28
  3. package/dist/exports/canvas-shaders.js +0 -16
  4. package/dist/exports/canvas-shaders.js.map +1 -1
  5. package/dist/exports/canvas.d.ts +1 -1
  6. package/dist/exports/canvas.js +1 -19
  7. package/dist/exports/canvas.js.map +1 -1
  8. package/dist/exports/index.d.ts +2 -5
  9. package/dist/exports/index.js +1 -23
  10. package/dist/exports/index.js.map +1 -1
  11. package/dist/exports/inspector.js +0 -18
  12. package/dist/exports/inspector.js.map +1 -1
  13. package/dist/exports/utils.d.ts +2 -1
  14. package/dist/exports/utils.js +2 -19
  15. package/dist/exports/utils.js.map +1 -1
  16. package/dist/exports/webgl-shaders.js +0 -16
  17. package/dist/exports/webgl-shaders.js.map +1 -1
  18. package/dist/exports/webgl.d.ts +2 -1
  19. package/dist/exports/webgl.js +2 -19
  20. package/dist/exports/webgl.js.map +1 -1
  21. package/dist/src/common/CommonTypes.d.ts +15 -3
  22. package/dist/src/common/CommonTypes.js +0 -18
  23. package/dist/src/common/CommonTypes.js.map +1 -1
  24. package/dist/src/common/EventEmitter.js +0 -18
  25. package/dist/src/common/EventEmitter.js.map +1 -1
  26. package/dist/src/common/IEventEmitter.js +0 -16
  27. package/dist/src/common/IEventEmitter.js.map +1 -1
  28. package/dist/src/core/Autosizer.d.ts +35 -0
  29. package/dist/src/core/Autosizer.js +178 -0
  30. package/dist/src/core/Autosizer.js.map +1 -0
  31. package/dist/src/core/CoreNode.d.ts +140 -102
  32. package/dist/src/core/CoreNode.js +812 -528
  33. package/dist/src/core/CoreNode.js.map +1 -1
  34. package/dist/src/core/CoreShaderManager.d.ts +3 -3
  35. package/dist/src/core/CoreShaderManager.js +0 -18
  36. package/dist/src/core/CoreShaderManager.js.map +1 -1
  37. package/dist/src/core/CoreTextNode.d.ts +75 -87
  38. package/dist/src/core/CoreTextNode.js +380 -258
  39. package/dist/src/core/CoreTextNode.js.map +1 -1
  40. package/dist/src/core/CoreTextureManager.d.ts +25 -14
  41. package/dist/src/core/CoreTextureManager.js +82 -139
  42. package/dist/src/core/CoreTextureManager.js.map +1 -1
  43. package/dist/src/core/Stage.d.ts +102 -36
  44. package/dist/src/core/Stage.js +424 -191
  45. package/dist/src/core/Stage.js.map +1 -1
  46. package/dist/src/core/TextureError.d.ts +11 -0
  47. package/dist/src/core/TextureError.js +37 -0
  48. package/dist/src/core/TextureError.js.map +1 -0
  49. package/dist/src/core/TextureMemoryManager.d.ts +11 -4
  50. package/dist/src/core/TextureMemoryManager.js +114 -134
  51. package/dist/src/core/TextureMemoryManager.js.map +1 -1
  52. package/dist/src/core/animations/AnimationManager.js +0 -18
  53. package/dist/src/core/animations/AnimationManager.js.map +1 -1
  54. package/dist/src/core/animations/CoreAnimation.d.ts +3 -3
  55. package/dist/src/core/animations/CoreAnimation.js +8 -24
  56. package/dist/src/core/animations/CoreAnimation.js.map +1 -1
  57. package/dist/src/core/animations/CoreAnimationController.d.ts +1 -0
  58. package/dist/src/core/animations/CoreAnimationController.js +11 -22
  59. package/dist/src/core/animations/CoreAnimationController.js.map +1 -1
  60. package/dist/src/core/lib/ContextSpy.js +0 -18
  61. package/dist/src/core/lib/ContextSpy.js.map +1 -1
  62. package/dist/src/core/lib/ImageWorker.d.ts +2 -2
  63. package/dist/src/core/lib/ImageWorker.js +33 -31
  64. package/dist/src/core/lib/ImageWorker.js.map +1 -1
  65. package/dist/src/core/lib/Matrix3d.d.ts +1 -0
  66. package/dist/src/core/lib/Matrix3d.js +7 -19
  67. package/dist/src/core/lib/Matrix3d.js.map +1 -1
  68. package/dist/src/core/lib/RenderCoords.d.ts +9 -10
  69. package/dist/src/core/lib/RenderCoords.js +27 -55
  70. package/dist/src/core/lib/RenderCoords.js.map +1 -1
  71. package/dist/src/core/lib/WebGlContextWrapper.d.ts +83 -8
  72. package/dist/src/core/lib/WebGlContextWrapper.js +150 -25
  73. package/dist/src/core/lib/WebGlContextWrapper.js.map +1 -1
  74. package/dist/src/core/lib/collectionUtils.d.ts +5 -0
  75. package/dist/src/core/lib/collectionUtils.js +82 -0
  76. package/dist/src/core/lib/collectionUtils.js.map +1 -0
  77. package/dist/src/core/lib/colorCache.d.ts +1 -0
  78. package/dist/src/core/lib/colorCache.js +19 -0
  79. package/dist/src/core/lib/colorCache.js.map +1 -0
  80. package/dist/src/core/{renderers/canvas/internal/ColorUtils.js → lib/colorParser.js} +1 -19
  81. package/dist/src/core/lib/colorParser.js.map +1 -0
  82. package/dist/src/core/lib/textureCompression.d.ts +14 -2
  83. package/dist/src/core/lib/textureCompression.js +320 -85
  84. package/dist/src/core/lib/textureCompression.js.map +1 -1
  85. package/dist/src/core/lib/textureSvg.js +0 -18
  86. package/dist/src/core/lib/textureSvg.js.map +1 -1
  87. package/dist/src/core/lib/utils.d.ts +8 -1
  88. package/dist/src/core/lib/utils.js +44 -20
  89. package/dist/src/core/lib/utils.js.map +1 -1
  90. package/dist/src/core/lib/validateImageBitmap.d.ts +2 -1
  91. package/dist/src/core/lib/validateImageBitmap.js +4 -4
  92. package/dist/src/core/lib/validateImageBitmap.js.map +1 -1
  93. package/dist/src/core/platforms/Platform.d.ts +42 -0
  94. package/dist/src/core/platforms/Platform.js +4 -0
  95. package/dist/src/core/platforms/Platform.js.map +1 -0
  96. package/dist/src/core/platforms/web/WebPlatform.d.ts +10 -0
  97. package/dist/src/core/platforms/web/WebPlatform.js +90 -0
  98. package/dist/src/core/platforms/web/WebPlatform.js.map +1 -0
  99. package/dist/src/core/renderers/CoreContextTexture.d.ts +2 -1
  100. package/dist/src/core/renderers/CoreContextTexture.js +0 -18
  101. package/dist/src/core/renderers/CoreContextTexture.js.map +1 -1
  102. package/dist/src/core/renderers/CoreRenderOp.js +0 -18
  103. package/dist/src/core/renderers/CoreRenderOp.js.map +1 -1
  104. package/dist/src/core/renderers/CoreRenderer.d.ts +15 -3
  105. package/dist/src/core/renderers/CoreRenderer.js +1 -18
  106. package/dist/src/core/renderers/CoreRenderer.js.map +1 -1
  107. package/dist/src/core/renderers/CoreShaderNode.d.ts +13 -3
  108. package/dist/src/core/renderers/CoreShaderNode.js +25 -2
  109. package/dist/src/core/renderers/CoreShaderNode.js.map +1 -1
  110. package/dist/src/core/renderers/CoreShaderProgram.js +0 -18
  111. package/dist/src/core/renderers/CoreShaderProgram.js.map +1 -1
  112. package/dist/src/core/renderers/canvas/CanvasRenderer.d.ts +4 -5
  113. package/dist/src/core/renderers/canvas/CanvasRenderer.js +89 -83
  114. package/dist/src/core/renderers/canvas/CanvasRenderer.js.map +1 -1
  115. package/dist/src/core/renderers/canvas/CanvasShaderNode.js +3 -21
  116. package/dist/src/core/renderers/canvas/CanvasShaderNode.js.map +1 -1
  117. package/dist/src/core/renderers/canvas/CanvasTexture.d.ts +3 -2
  118. package/dist/src/core/renderers/canvas/CanvasTexture.js +18 -31
  119. package/dist/src/core/renderers/canvas/CanvasTexture.js.map +1 -1
  120. package/dist/src/core/renderers/webgl/SdfRenderOp.d.ts +33 -0
  121. package/dist/src/core/renderers/webgl/SdfRenderOp.js +80 -0
  122. package/dist/src/core/renderers/webgl/SdfRenderOp.js.map +1 -0
  123. package/dist/src/core/renderers/webgl/WebGlCtxRenderTexture.d.ts +2 -0
  124. package/dist/src/core/renderers/webgl/WebGlCtxRenderTexture.js +14 -24
  125. package/dist/src/core/renderers/webgl/WebGlCtxRenderTexture.js.map +1 -1
  126. package/dist/src/core/renderers/webgl/WebGlCtxSubTexture.d.ts +13 -0
  127. package/dist/src/core/renderers/webgl/WebGlCtxSubTexture.js +34 -23
  128. package/dist/src/core/renderers/webgl/WebGlCtxSubTexture.js.map +1 -1
  129. package/dist/src/core/renderers/webgl/WebGlCtxTexture.d.ts +16 -6
  130. package/dist/src/core/renderers/webgl/WebGlCtxTexture.js +102 -70
  131. package/dist/src/core/renderers/webgl/WebGlCtxTexture.js.map +1 -1
  132. package/dist/src/core/renderers/webgl/WebGlRenderer.d.ts +34 -20
  133. package/dist/src/core/renderers/webgl/WebGlRenderer.js +319 -195
  134. package/dist/src/core/renderers/webgl/WebGlRenderer.js.map +1 -1
  135. package/dist/src/core/renderers/webgl/WebGlShaderNode.d.ts +2 -3
  136. package/dist/src/core/renderers/webgl/WebGlShaderNode.js +1 -4
  137. package/dist/src/core/renderers/webgl/WebGlShaderNode.js.map +1 -1
  138. package/dist/src/core/renderers/webgl/WebGlShaderProgram.d.ts +9 -7
  139. package/dist/src/core/renderers/webgl/WebGlShaderProgram.js +99 -48
  140. package/dist/src/core/renderers/webgl/WebGlShaderProgram.js.map +1 -1
  141. package/dist/src/core/renderers/webgl/internal/BufferCollection.d.ts +1 -0
  142. package/dist/src/core/renderers/webgl/internal/BufferCollection.js +12 -21
  143. package/dist/src/core/renderers/webgl/internal/BufferCollection.js.map +1 -1
  144. package/dist/src/core/renderers/webgl/internal/RendererUtils.js +0 -18
  145. package/dist/src/core/renderers/webgl/internal/RendererUtils.js.map +1 -1
  146. package/dist/src/core/renderers/webgl/internal/ShaderUtils.js +0 -18
  147. package/dist/src/core/renderers/webgl/internal/ShaderUtils.js.map +1 -1
  148. package/dist/src/core/renderers/webgl/internal/WebGlUtils.js +0 -18
  149. package/dist/src/core/renderers/webgl/internal/WebGlUtils.js.map +1 -1
  150. package/dist/src/core/shaders/canvas/Border.d.ts +8 -2
  151. package/dist/src/core/shaders/canvas/Border.js +67 -41
  152. package/dist/src/core/shaders/canvas/Border.js.map +1 -1
  153. package/dist/src/core/shaders/canvas/HolePunch.js +3 -19
  154. package/dist/src/core/shaders/canvas/HolePunch.js.map +1 -1
  155. package/dist/src/core/shaders/canvas/LinearGradient.js +7 -21
  156. package/dist/src/core/shaders/canvas/LinearGradient.js.map +1 -1
  157. package/dist/src/core/shaders/canvas/RadialGradient.js +14 -28
  158. package/dist/src/core/shaders/canvas/RadialGradient.js.map +1 -1
  159. package/dist/src/core/shaders/canvas/Rounded.js +1 -17
  160. package/dist/src/core/shaders/canvas/Rounded.js.map +1 -1
  161. package/dist/src/core/shaders/canvas/RoundedWithBorder.d.ts +6 -3
  162. package/dist/src/core/shaders/canvas/RoundedWithBorder.js +44 -22
  163. package/dist/src/core/shaders/canvas/RoundedWithBorder.js.map +1 -1
  164. package/dist/src/core/shaders/canvas/RoundedWithBorderAndShadow.d.ts +2 -3
  165. package/dist/src/core/shaders/canvas/RoundedWithBorderAndShadow.js +47 -25
  166. package/dist/src/core/shaders/canvas/RoundedWithBorderAndShadow.js.map +1 -1
  167. package/dist/src/core/shaders/canvas/RoundedWithShadow.js +9 -21
  168. package/dist/src/core/shaders/canvas/RoundedWithShadow.js.map +1 -1
  169. package/dist/src/core/shaders/canvas/Shadow.js +0 -16
  170. package/dist/src/core/shaders/canvas/Shadow.js.map +1 -1
  171. package/dist/src/core/shaders/canvas/utils/render.d.ts +1 -1
  172. package/dist/src/core/shaders/canvas/utils/render.js +31 -34
  173. package/dist/src/core/shaders/canvas/utils/render.js.map +1 -1
  174. package/dist/src/core/shaders/templates/BorderTemplate.d.ts +12 -2
  175. package/dist/src/core/shaders/templates/BorderTemplate.js +31 -27
  176. package/dist/src/core/shaders/templates/BorderTemplate.js.map +1 -1
  177. package/dist/src/core/shaders/templates/HolePunchTemplate.d.ts +2 -2
  178. package/dist/src/core/shaders/templates/HolePunchTemplate.js +3 -19
  179. package/dist/src/core/shaders/templates/HolePunchTemplate.js.map +1 -1
  180. package/dist/src/core/shaders/templates/LinearGradientTemplate.js +0 -16
  181. package/dist/src/core/shaders/templates/LinearGradientTemplate.js.map +1 -1
  182. package/dist/src/core/shaders/templates/RadialGradientTemplate.d.ts +8 -6
  183. package/dist/src/core/shaders/templates/RadialGradientTemplate.js +2 -18
  184. package/dist/src/core/shaders/templates/RadialGradientTemplate.js.map +1 -1
  185. package/dist/src/core/shaders/templates/RoundedTemplate.js +1 -17
  186. package/dist/src/core/shaders/templates/RoundedTemplate.js.map +1 -1
  187. package/dist/src/core/shaders/templates/RoundedWithBorderAndShadowTemplate.d.ts +1 -1
  188. package/dist/src/core/shaders/templates/RoundedWithBorderAndShadowTemplate.js +0 -16
  189. package/dist/src/core/shaders/templates/RoundedWithBorderAndShadowTemplate.js.map +1 -1
  190. package/dist/src/core/shaders/templates/RoundedWithBorderTemplate.d.ts +4 -2
  191. package/dist/src/core/shaders/templates/RoundedWithBorderTemplate.js +3 -17
  192. package/dist/src/core/shaders/templates/RoundedWithBorderTemplate.js.map +1 -1
  193. package/dist/src/core/shaders/templates/RoundedWithShadowTemplate.d.ts +1 -1
  194. package/dist/src/core/shaders/templates/RoundedWithShadowTemplate.js +0 -16
  195. package/dist/src/core/shaders/templates/RoundedWithShadowTemplate.js.map +1 -1
  196. package/dist/src/core/shaders/templates/ShadowTemplate.d.ts +1 -1
  197. package/dist/src/core/shaders/templates/ShadowTemplate.js +0 -16
  198. package/dist/src/core/shaders/templates/ShadowTemplate.js.map +1 -1
  199. package/dist/src/core/shaders/{templates/shaderUtils.d.ts → utils.d.ts} +1 -1
  200. package/dist/src/core/shaders/utils.js +25 -0
  201. package/dist/src/core/shaders/utils.js.map +1 -0
  202. package/dist/src/core/shaders/webgl/Border.js +118 -51
  203. package/dist/src/core/shaders/webgl/Border.js.map +1 -1
  204. package/dist/src/core/shaders/webgl/Default.js +6 -41
  205. package/dist/src/core/shaders/webgl/Default.js.map +1 -1
  206. package/dist/src/core/shaders/webgl/HolePunch.js +4 -19
  207. package/dist/src/core/shaders/webgl/HolePunch.js.map +1 -1
  208. package/dist/src/core/shaders/webgl/LinearGradient.js +73 -34
  209. package/dist/src/core/shaders/webgl/LinearGradient.js.map +1 -1
  210. package/dist/src/core/shaders/webgl/RadialGradient.js +56 -48
  211. package/dist/src/core/shaders/webgl/RadialGradient.js.map +1 -1
  212. package/dist/src/core/shaders/webgl/Rounded.js +25 -23
  213. package/dist/src/core/shaders/webgl/Rounded.js.map +1 -1
  214. package/dist/src/core/shaders/webgl/RoundedWithBorder.js +160 -55
  215. package/dist/src/core/shaders/webgl/RoundedWithBorder.js.map +1 -1
  216. package/dist/src/core/shaders/webgl/RoundedWithBorderAndShadow.js +168 -58
  217. package/dist/src/core/shaders/webgl/RoundedWithBorderAndShadow.js.map +1 -1
  218. package/dist/src/core/shaders/webgl/RoundedWithShadow.js +73 -34
  219. package/dist/src/core/shaders/webgl/RoundedWithShadow.js.map +1 -1
  220. package/dist/src/core/shaders/webgl/SdfShader.d.ts +0 -2
  221. package/dist/src/core/shaders/webgl/SdfShader.js +8 -36
  222. package/dist/src/core/shaders/webgl/SdfShader.js.map +1 -1
  223. package/dist/src/core/shaders/webgl/Shadow.js +39 -34
  224. package/dist/src/core/shaders/webgl/Shadow.js.map +1 -1
  225. package/dist/src/core/text-rendering/CanvasFontHandler.d.ts +59 -0
  226. package/dist/src/core/text-rendering/CanvasFontHandler.js +206 -0
  227. package/dist/src/core/text-rendering/CanvasFontHandler.js.map +1 -0
  228. package/dist/src/core/text-rendering/CanvasTextRenderer.d.ts +17 -0
  229. package/dist/src/core/text-rendering/CanvasTextRenderer.js +139 -0
  230. package/dist/src/core/text-rendering/CanvasTextRenderer.js.map +1 -0
  231. package/dist/src/core/text-rendering/SdfFontHandler.d.ts +167 -0
  232. package/dist/src/core/text-rendering/SdfFontHandler.js +371 -0
  233. package/dist/src/core/text-rendering/SdfFontHandler.js.map +1 -0
  234. package/dist/src/core/text-rendering/SdfTextRenderer.d.ts +18 -0
  235. package/dist/src/core/text-rendering/SdfTextRenderer.js +301 -0
  236. package/dist/src/core/text-rendering/SdfTextRenderer.js.map +1 -0
  237. package/dist/src/core/text-rendering/TextLayoutEngine.d.ts +18 -0
  238. package/dist/src/core/text-rendering/TextLayoutEngine.js +380 -0
  239. package/dist/src/core/text-rendering/TextLayoutEngine.js.map +1 -0
  240. package/dist/src/core/text-rendering/TextRenderer.d.ts +384 -0
  241. package/dist/src/core/text-rendering/TextRenderer.js +2 -0
  242. package/dist/src/core/text-rendering/TextRenderer.js.map +1 -0
  243. package/dist/src/core/text-rendering/Utils.d.ts +30 -0
  244. package/dist/src/core/text-rendering/Utils.js +66 -0
  245. package/dist/src/core/text-rendering/Utils.js.map +1 -0
  246. package/dist/src/core/textures/ColorTexture.d.ts +1 -1
  247. package/dist/src/core/textures/ColorTexture.js +3 -22
  248. package/dist/src/core/textures/ColorTexture.js.map +1 -1
  249. package/dist/src/core/textures/ImageTexture.d.ts +13 -6
  250. package/dist/src/core/textures/ImageTexture.js +57 -66
  251. package/dist/src/core/textures/ImageTexture.js.map +1 -1
  252. package/dist/src/core/textures/NoiseTexture.d.ts +3 -3
  253. package/dist/src/core/textures/NoiseTexture.js +8 -26
  254. package/dist/src/core/textures/NoiseTexture.js.map +1 -1
  255. package/dist/src/core/textures/RenderTexture.d.ts +7 -7
  256. package/dist/src/core/textures/RenderTexture.js +12 -30
  257. package/dist/src/core/textures/RenderTexture.js.map +1 -1
  258. package/dist/src/core/textures/SubTexture.d.ts +6 -8
  259. package/dist/src/core/textures/SubTexture.js +19 -55
  260. package/dist/src/core/textures/SubTexture.js.map +1 -1
  261. package/dist/src/core/textures/Texture.d.ts +90 -12
  262. package/dist/src/core/textures/Texture.js +160 -35
  263. package/dist/src/core/textures/Texture.js.map +1 -1
  264. package/dist/src/core/utils.d.ts +2 -1
  265. package/dist/src/core/utils.js +1 -19
  266. package/dist/src/core/utils.js.map +1 -1
  267. package/dist/src/main-api/INode.js.map +1 -1
  268. package/dist/src/main-api/Inspector.d.ts +135 -2
  269. package/dist/src/main-api/Inspector.js +507 -30
  270. package/dist/src/main-api/Inspector.js.map +1 -1
  271. package/dist/src/main-api/Renderer.d.ts +294 -81
  272. package/dist/src/main-api/Renderer.js +225 -96
  273. package/dist/src/main-api/Renderer.js.map +1 -1
  274. package/dist/src/utils.d.ts +19 -6
  275. package/dist/src/utils.js +32 -27
  276. package/dist/src/utils.js.map +1 -1
  277. package/dist/tsconfig.dist.tsbuildinfo +1 -1
  278. package/dist/tsconfig.tsbuildinfo +1 -0
  279. package/exports/canvas-shaders.ts +0 -17
  280. package/exports/canvas.ts +1 -19
  281. package/exports/index.ts +6 -27
  282. package/exports/inspector.ts +0 -19
  283. package/exports/utils.ts +7 -19
  284. package/exports/webgl-shaders.ts +0 -16
  285. package/exports/webgl.ts +3 -20
  286. package/package.json +23 -22
  287. package/src/common/CommonTypes.ts +20 -22
  288. package/src/common/EventEmitter.ts +0 -19
  289. package/src/common/IAnimationController.ts +0 -18
  290. package/src/common/IEventEmitter.ts +0 -17
  291. package/src/core/Autosizer.ts +205 -0
  292. package/src/core/CoreNode.test.ts +376 -45
  293. package/src/core/CoreNode.ts +1015 -656
  294. package/src/core/CoreShaderManager.ts +3 -21
  295. package/src/core/CoreTextNode.ts +457 -314
  296. package/src/core/CoreTextureManager.ts +110 -167
  297. package/src/core/Stage.ts +526 -236
  298. package/src/core/TextureError.ts +46 -0
  299. package/src/core/TextureMemoryManager.ts +150 -167
  300. package/src/core/animations/AnimationManager.ts +0 -19
  301. package/src/core/animations/CoreAnimation.ts +15 -32
  302. package/src/core/animations/CoreAnimationController.ts +13 -23
  303. package/src/core/lib/ContextSpy.ts +0 -19
  304. package/src/core/lib/ImageWorker.ts +45 -32
  305. package/src/core/lib/Matrix3d.ts +7 -20
  306. package/src/core/lib/RenderCoords.ts +36 -67
  307. package/src/core/lib/WebGlContextWrapper.ts +196 -72
  308. package/src/core/lib/collectionUtils.ts +99 -0
  309. package/src/core/lib/colorCache.ts +20 -0
  310. package/src/core/{renderers/canvas/internal/ColorUtils.ts → lib/colorParser.ts} +2 -21
  311. package/src/core/lib/textureCompression.ts +433 -93
  312. package/src/core/lib/textureSvg.ts +0 -19
  313. package/src/core/lib/utils.ts +58 -19
  314. package/src/core/lib/validateImageBitmap.ts +17 -6
  315. package/src/core/platforms/Platform.ts +64 -0
  316. package/src/core/platforms/web/WebPlatform.ts +132 -0
  317. package/src/core/renderers/CoreContextTexture.ts +2 -20
  318. package/src/core/renderers/CoreRenderOp.ts +0 -19
  319. package/src/core/renderers/CoreRenderer.ts +16 -23
  320. package/src/core/renderers/CoreShaderNode.ts +37 -6
  321. package/src/core/renderers/CoreShaderProgram.ts +0 -19
  322. package/src/core/renderers/canvas/CanvasRenderer.ts +108 -137
  323. package/src/core/renderers/canvas/CanvasShaderNode.ts +3 -23
  324. package/src/core/renderers/canvas/CanvasTexture.ts +25 -37
  325. package/src/core/renderers/webgl/SdfRenderOp.ts +88 -0
  326. package/src/core/renderers/webgl/WebGlCtxRenderTexture.ts +18 -34
  327. package/src/core/renderers/webgl/WebGlCtxSubTexture.ts +50 -24
  328. package/src/core/renderers/webgl/WebGlCtxTexture.ts +134 -103
  329. package/src/core/renderers/webgl/WebGlRenderer.ts +368 -233
  330. package/src/core/renderers/webgl/WebGlShaderNode.ts +4 -7
  331. package/src/core/renderers/webgl/WebGlShaderProgram.ts +122 -76
  332. package/src/core/renderers/webgl/internal/BufferCollection.ts +15 -23
  333. package/src/core/renderers/webgl/internal/RendererUtils.ts +0 -19
  334. package/src/core/renderers/webgl/internal/ShaderUtils.ts +0 -19
  335. package/src/core/renderers/webgl/internal/WebGlUtils.ts +0 -19
  336. package/src/core/shaders/canvas/Border.ts +91 -50
  337. package/src/core/shaders/canvas/HolePunch.ts +4 -28
  338. package/src/core/shaders/canvas/LinearGradient.ts +10 -25
  339. package/src/core/shaders/canvas/RadialGradient.ts +23 -54
  340. package/src/core/shaders/canvas/Rounded.ts +2 -19
  341. package/src/core/shaders/canvas/RoundedWithBorder.ts +72 -35
  342. package/src/core/shaders/canvas/RoundedWithBorderAndShadow.ts +77 -47
  343. package/src/core/shaders/canvas/RoundedWithShadow.ts +21 -34
  344. package/src/core/shaders/canvas/Shadow.ts +0 -17
  345. package/src/core/shaders/canvas/utils/render.ts +45 -53
  346. package/src/core/shaders/templates/BorderTemplate.ts +42 -29
  347. package/src/core/shaders/templates/HolePunchTemplate.ts +5 -22
  348. package/src/core/shaders/templates/LinearGradientTemplate.ts +0 -17
  349. package/src/core/shaders/templates/RadialGradientTemplate.ts +10 -25
  350. package/src/core/shaders/templates/RoundedTemplate.ts +1 -18
  351. package/src/core/shaders/templates/RoundedWithBorderAndShadowTemplate.ts +1 -18
  352. package/src/core/shaders/templates/RoundedWithBorderTemplate.ts +7 -19
  353. package/src/core/shaders/templates/RoundedWithShadowTemplate.ts +1 -18
  354. package/src/core/shaders/templates/ShadowTemplate.ts +1 -18
  355. package/src/core/shaders/utils.ts +30 -0
  356. package/src/core/shaders/webgl/Border.ts +118 -55
  357. package/src/core/shaders/webgl/Default.ts +6 -43
  358. package/src/core/shaders/webgl/HolePunch.ts +4 -24
  359. package/src/core/shaders/webgl/LinearGradient.ts +73 -35
  360. package/src/core/shaders/webgl/RadialGradient.ts +58 -51
  361. package/src/core/shaders/webgl/Rounded.ts +25 -45
  362. package/src/core/shaders/webgl/RoundedWithBorder.ts +161 -63
  363. package/src/core/shaders/webgl/RoundedWithBorderAndShadow.ts +169 -68
  364. package/src/core/shaders/webgl/RoundedWithShadow.ts +73 -39
  365. package/src/core/shaders/webgl/SdfShader.ts +8 -41
  366. package/src/core/shaders/webgl/Shadow.ts +39 -35
  367. package/src/core/text-rendering/CanvasFontHandler.ts +285 -0
  368. package/src/core/text-rendering/CanvasTextRenderer.ts +236 -0
  369. package/src/core/text-rendering/SdfFontHandler.ts +566 -0
  370. package/src/core/text-rendering/SdfTextRenderer.ts +406 -0
  371. package/src/core/text-rendering/TextLayoutEngine.ts +672 -0
  372. package/src/core/text-rendering/TextRenderer.ts +426 -0
  373. package/src/core/text-rendering/Utils.ts +80 -0
  374. package/src/core/text-rendering/tests/TextLayoutEngine.test.ts +434 -0
  375. package/src/core/textures/ColorTexture.ts +7 -24
  376. package/src/core/textures/ImageTexture.ts +110 -92
  377. package/src/core/textures/NoiseTexture.ts +14 -31
  378. package/src/core/textures/RenderTexture.ts +18 -35
  379. package/src/core/textures/SubTexture.ts +25 -65
  380. package/src/core/textures/Texture.ts +214 -46
  381. package/src/core/utils.ts +9 -26
  382. package/src/main-api/INode.ts +0 -18
  383. package/src/main-api/Inspector.ts +794 -38
  384. package/src/main-api/Renderer.ts +519 -159
  385. package/src/utils.ts +64 -29
  386. package/dist/src/core/platform.d.ts +0 -10
  387. package/dist/src/core/platform.js +0 -56
  388. package/dist/src/core/platform.js.map +0 -1
  389. package/dist/src/core/renderers/canvas/internal/C2DShaderUtils.d.ts +0 -1
  390. package/dist/src/core/renderers/canvas/internal/C2DShaderUtils.js +0 -217
  391. package/dist/src/core/renderers/canvas/internal/C2DShaderUtils.js.map +0 -1
  392. package/dist/src/core/renderers/canvas/internal/ColorUtils.js.map +0 -1
  393. package/dist/src/core/renderers/webgl/WebGlRenderOp.d.ts +0 -36
  394. package/dist/src/core/renderers/webgl/WebGlRenderOp.js +0 -107
  395. package/dist/src/core/renderers/webgl/WebGlRenderOp.js.map +0 -1
  396. package/dist/src/core/shaders/templates/shaderUtils.js +0 -41
  397. package/dist/src/core/shaders/templates/shaderUtils.js.map +0 -1
  398. package/dist/src/core/text-rendering/TextRenderingUtils.d.ts +0 -12
  399. package/dist/src/core/text-rendering/TextRenderingUtils.js +0 -14
  400. package/dist/src/core/text-rendering/TextRenderingUtils.js.map +0 -1
  401. package/dist/src/core/text-rendering/TextTextureRendererUtils.d.ts +0 -72
  402. package/dist/src/core/text-rendering/TextTextureRendererUtils.js +0 -217
  403. package/dist/src/core/text-rendering/TextTextureRendererUtils.js.map +0 -1
  404. package/dist/src/core/text-rendering/TrFontManager.d.ts +0 -26
  405. package/dist/src/core/text-rendering/TrFontManager.js +0 -131
  406. package/dist/src/core/text-rendering/TrFontManager.js.map +0 -1
  407. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.d.ts +0 -39
  408. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.js +0 -125
  409. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.js.map +0 -1
  410. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/FontShaper.d.ts +0 -103
  411. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/FontShaper.js +0 -21
  412. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/FontShaper.js.map +0 -1
  413. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.d.ts +0 -62
  414. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.js +0 -88
  415. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.js.map +0 -1
  416. package/dist/src/core/text-rendering/font-face-types/TrFontFace.d.ts +0 -118
  417. package/dist/src/core/text-rendering/font-face-types/TrFontFace.js +0 -63
  418. package/dist/src/core/text-rendering/font-face-types/TrFontFace.js.map +0 -1
  419. package/dist/src/core/text-rendering/font-face-types/WebTrFontFace.d.ts +0 -14
  420. package/dist/src/core/text-rendering/font-face-types/WebTrFontFace.js +0 -66
  421. package/dist/src/core/text-rendering/font-face-types/WebTrFontFace.js.map +0 -1
  422. package/dist/src/core/text-rendering/font-face-types/utils.d.ts +0 -1
  423. package/dist/src/core/text-rendering/font-face-types/utils.js +0 -38
  424. package/dist/src/core/text-rendering/font-face-types/utils.js.map +0 -1
  425. package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.d.ts +0 -59
  426. package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.js +0 -397
  427. package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.js.map +0 -1
  428. package/dist/src/core/text-rendering/renderers/LightningTextTextureRenderer.d.ts +0 -126
  429. package/dist/src/core/text-rendering/renderers/LightningTextTextureRenderer.js +0 -551
  430. package/dist/src/core/text-rendering/renderers/LightningTextTextureRenderer.js.map +0 -1
  431. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.d.ts +0 -91
  432. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js +0 -611
  433. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js.map +0 -1
  434. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/PeekableGenerator.d.ts +0 -12
  435. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/PeekableGenerator.js +0 -61
  436. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/PeekableGenerator.js.map +0 -1
  437. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/SpecialCodepoints.d.ts +0 -33
  438. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/SpecialCodepoints.js +0 -52
  439. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/SpecialCodepoints.js.map +0 -1
  440. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/constants.d.ts +0 -13
  441. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/constants.js +0 -32
  442. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/constants.js.map +0 -1
  443. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/getStartConditions.d.ts +0 -23
  444. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/getStartConditions.js +0 -84
  445. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/getStartConditions.js.map +0 -1
  446. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/getUnicodeCodepoints.d.ts +0 -4
  447. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/getUnicodeCodepoints.js +0 -34
  448. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/getUnicodeCodepoints.js.map +0 -1
  449. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.d.ts +0 -20
  450. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.js +0 -308
  451. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.js.map +0 -1
  452. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/measureText.d.ts +0 -10
  453. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/measureText.js +0 -40
  454. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/measureText.js.map +0 -1
  455. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.d.ts +0 -26
  456. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.js +0 -70
  457. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.js.map +0 -1
  458. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/util.d.ts +0 -16
  459. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/util.js +0 -39
  460. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/util.js.map +0 -1
  461. package/dist/src/core/text-rendering/renderers/TextRenderer.d.ts +0 -370
  462. package/dist/src/core/text-rendering/renderers/TextRenderer.js +0 -178
  463. package/dist/src/core/text-rendering/renderers/TextRenderer.js.map +0 -1
  464. package/scripts/please-use-pnpm.js +0 -13
  465. package/src/core/platform.ts +0 -64
  466. package/src/core/renderers/canvas/internal/C2DShaderUtils.ts +0 -220
  467. package/src/core/renderers/webgl/WebGlRenderOp.ts +0 -145
  468. package/src/core/shaders/templates/shaderUtils.ts +0 -47
  469. package/src/core/shaders/webgl/DefaultBatched.ts +0 -129
  470. package/src/core/text-rendering/TextRenderingUtils.ts +0 -36
  471. package/src/core/text-rendering/TextTextureRendererUtils.ts +0 -263
  472. package/src/core/text-rendering/TrFontManager.ts +0 -183
  473. package/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.ts +0 -176
  474. package/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/FontShaper.ts +0 -139
  475. package/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.test.ts +0 -173
  476. package/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.ts +0 -171
  477. package/src/core/text-rendering/font-face-types/TrFontFace.ts +0 -187
  478. package/src/core/text-rendering/font-face-types/WebTrFontFace.ts +0 -94
  479. package/src/core/text-rendering/font-face-types/utils.ts +0 -39
  480. package/src/core/text-rendering/renderers/CanvasTextRenderer.ts +0 -509
  481. package/src/core/text-rendering/renderers/LightningTextTextureRenderer.ts +0 -815
  482. package/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.ts +0 -841
  483. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/PeekableGenerator.test.ts +0 -48
  484. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/PeekableGenerator.ts +0 -66
  485. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/SpecialCodepoints.ts +0 -52
  486. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/constants.ts +0 -32
  487. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/getStartConditions.ts +0 -117
  488. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/getUnicodeCodepoints.test.ts +0 -133
  489. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/getUnicodeCodepoints.ts +0 -38
  490. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.ts +0 -408
  491. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/measureText.test.ts +0 -49
  492. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/measureText.ts +0 -52
  493. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.test.ts +0 -205
  494. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.ts +0 -93
  495. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/util.ts +0 -40
  496. package/src/core/text-rendering/renderers/TextRenderer.ts +0 -550
  497. /package/dist/src/core/{renderers/canvas/internal/ColorUtils.d.ts → lib/colorParser.d.ts} +0 -0
@@ -1,33 +1,20 @@
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
1
  import {
21
2
  assertTruthy,
22
3
  getNewId,
23
- isProductionEnvironment,
24
- mergeColorAlphaPremultiplied,
4
+ premultiplyColorABGR,
5
+ USE_RTT,
6
+ ENABLE_AUTOSIZE,
7
+ EMIT_BOUNDS_EVENTS,
25
8
  } from '../utils.js';
26
9
  import type { TextureOptions } from './CoreTextureManager.js';
10
+ import type { WebGlRenderer } from './renderers/webgl/WebGlRenderer.js';
11
+ import type { WebGlCtxTexture } from './renderers/webgl/WebGlCtxTexture.js';
12
+ import type { BufferCollection } from './renderers/webgl/internal/BufferCollection.js';
27
13
  import type { CoreRenderer } from './renderers/CoreRenderer.js';
28
14
  import type { Stage } from './Stage.js';
29
15
  import {
30
16
  type Texture,
17
+ type TextureCoords,
31
18
  type TextureFailedEventHandler,
32
19
  type TextureFreedEventHandler,
33
20
  type TextureLoadedEventHandler,
@@ -37,6 +24,7 @@ import type {
37
24
  NodeTextureFailedPayload,
38
25
  NodeTextureFreedPayload,
39
26
  NodeTextureLoadedPayload,
27
+ NodeRenderablePayload,
40
28
  } from '../common/CommonTypes.js';
41
29
  import { EventEmitter } from '../common/EventEmitter.js';
42
30
  import {
@@ -56,6 +44,8 @@ import type { IAnimationController } from '../common/IAnimationController.js';
56
44
  import { CoreAnimation } from './animations/CoreAnimation.js';
57
45
  import { CoreAnimationController } from './animations/CoreAnimationController.js';
58
46
  import type { CoreShaderNode } from './renderers/CoreShaderNode.js';
47
+ import { AutosizeMode, Autosizer } from './Autosizer.js';
48
+ import { removeChild } from './lib/collectionUtils.js';
59
49
 
60
50
  export enum CoreNodeRenderState {
61
51
  Init = 0,
@@ -64,6 +54,14 @@ export enum CoreNodeRenderState {
64
54
  InViewport = 8,
65
55
  }
66
56
 
57
+ const NO_CLIPPING_RECT: RectWithValid = {
58
+ x: 0,
59
+ y: 0,
60
+ width: 0,
61
+ height: 0,
62
+ valid: false,
63
+ };
64
+
67
65
  const CoreNodeRenderStateMap: Map<CoreNodeRenderState, string> = new Map();
68
66
  CoreNodeRenderStateMap.set(CoreNodeRenderState.Init, 'init');
69
67
  CoreNodeRenderStateMap.set(CoreNodeRenderState.OutOfBounds, 'outOfBounds');
@@ -77,33 +75,24 @@ export enum UpdateType {
77
75
  Children = 1,
78
76
 
79
77
  /**
80
- * Scale/Rotate transform update
81
- *
82
- * @remarks
83
- * CoreNode Properties Updated:
84
- * - `scaleRotateTransform`
85
- */
86
- ScaleRotate = 2,
87
-
88
- /**
89
- * Translate transform update (x/y/width/height/pivot/mount)
78
+ * localTransform
90
79
  *
91
80
  * @remarks
92
81
  * CoreNode Properties Updated:
93
82
  * - `localTransform`
94
83
  */
95
- Local = 4,
84
+ Local = 2,
96
85
 
97
86
  /**
98
- * Global Transform update
87
+ * globalTransform
99
88
  *
100
- * @remarks
89
+ * * @remarks
101
90
  * CoreNode Properties Updated:
102
91
  * - `globalTransform`
92
+ * - `renderBounds`
103
93
  * - `renderCoords`
104
- * - `renderBound`
105
94
  */
106
- Global = 8,
95
+ Global = 4,
107
96
 
108
97
  /**
109
98
  * Clipping rect update
@@ -112,25 +101,16 @@ export enum UpdateType {
112
101
  * CoreNode Properties Updated:
113
102
  * - `clippingRect`
114
103
  */
115
- Clipping = 16,
116
-
117
- /**
118
- * Calculated ZIndex update
119
- *
120
- * @remarks
121
- * CoreNode Properties Updated:
122
- * - `calcZIndex`
123
- */
124
- CalculatedZIndex = 32,
104
+ Clipping = 8,
125
105
 
126
106
  /**
127
- * Z-Index Sorted Children update
107
+ * Sort Z-Index Children update
128
108
  *
129
109
  * @remarks
130
110
  * CoreNode Properties Updated:
131
111
  * - `children` (sorts children by their `calcZIndex`)
132
112
  */
133
- ZIndexSortedChildren = 64,
113
+ SortZIndexChildren = 16,
134
114
 
135
115
  /**
136
116
  * Premultiplied Colors update
@@ -142,7 +122,7 @@ export enum UpdateType {
142
122
  * - `premultipliedColorBl`
143
123
  * - `premultipliedColorBr`
144
124
  */
145
- PremultipliedColors = 128,
125
+ PremultipliedColors = 32,
146
126
 
147
127
  /**
148
128
  * World Alpha update
@@ -151,7 +131,7 @@ export enum UpdateType {
151
131
  * CoreNode Properties Updated:
152
132
  * - `worldAlpha` = `parent.worldAlpha` * `alpha`
153
133
  */
154
- WorldAlpha = 256,
134
+ WorldAlpha = 64,
155
135
 
156
136
  /**
157
137
  * Render State update
@@ -160,7 +140,7 @@ export enum UpdateType {
160
140
  * CoreNode Properties Updated:
161
141
  * - `renderState`
162
142
  */
163
- RenderState = 512,
143
+ RenderState = 128,
164
144
 
165
145
  /**
166
146
  * Is Renderable update
@@ -169,37 +149,41 @@ export enum UpdateType {
169
149
  * CoreNode Properties Updated:
170
150
  * - `isRenderable`
171
151
  */
172
- IsRenderable = 1024,
152
+ IsRenderable = 256,
173
153
 
174
154
  /**
175
155
  * Render Texture update
176
156
  */
177
- RenderTexture = 2048,
157
+ RenderTexture = 512,
178
158
 
179
159
  /**
180
160
  * Track if parent has render texture
181
161
  */
182
- ParentRenderTexture = 4096,
162
+ ParentRenderTexture = 1024,
183
163
 
184
164
  /**
185
165
  * Render Bounds update
186
166
  */
187
- RenderBounds = 8192,
167
+ RenderBounds = 2048,
188
168
 
189
169
  /**
190
- * None
170
+ * RecalcUniforms
191
171
  */
192
- None = 0,
172
+ RecalcUniforms = 4096,
193
173
 
194
174
  /**
195
- * All
175
+ * Autosize update
176
+ */
177
+ Autosize = 8192,
178
+ /**
179
+ * None
196
180
  */
197
- All = 14335,
181
+ None = 0,
198
182
 
199
183
  /**
200
- * RecalcUniforms
184
+ * All
201
185
  */
202
- RecalcUniforms = 16384,
186
+ All = 16383,
203
187
  }
204
188
 
205
189
  /**
@@ -240,16 +224,18 @@ export interface CoreNodeProps {
240
224
  y: number;
241
225
  /**
242
226
  * The width of the Node.
227
+ * @warning This will be deprecated in favor of `w` and `h` properties in the future.
243
228
  *
244
229
  * @default `0`
245
230
  */
246
- width: number;
231
+ w: number;
247
232
  /**
248
233
  * The height of the Node.
234
+ * @warning This will be deprecated in favor of `w` and `h` properties in the future.
249
235
  *
250
236
  * @default `0`
251
237
  */
252
- height: number;
238
+ h: number;
253
239
  /**
254
240
  * The alpha opacity of the Node.
255
241
  *
@@ -261,14 +247,35 @@ export interface CoreNodeProps {
261
247
  */
262
248
  alpha: number;
263
249
  /**
264
- * Autosize mode
250
+ * Autosize
265
251
  *
266
252
  * @remarks
267
- * When enabled, when a texture is loaded into the Node, the Node will
268
- * automatically resize to the dimensions of the texture.
253
+ * When enabled, the Node automatically resizes based on its content
254
+ *
255
+ * **Texture Autosize Mode:**
256
+ * - When the Node has a texture, it automatically resizes to match the
257
+ * texture's dimensions when the texture loads
258
+ * - This ensures images display at their natural size without manual sizing
259
+ * - Text Nodes always use this mode regardless of this setting
260
+ *
261
+ * **Children Autosize Mode:**
262
+ * - When the Node has no texture but contains children, it automatically
263
+ * resizes to encompass all children's bounds
264
+ * - Calculates the bounding box that contains all child positions, dimensions,
265
+ * and transforms (scale, rotation, mount/pivot points)
266
+ * - Creates container behavior where the parent grows to fit its content
267
+ * - Updates dynamically as children are added, removed, or transformed
268
+ *
269
+ * **Mode Selection Logic:**
270
+ * - Texture mode takes precedence over children mode
271
+ * - Mode switches automatically when texture is added/removed
272
+ * - If no texture and no children, autosize has no effect
273
+ *
274
+ * **Performance:**
275
+ * - Children mode uses efficient transform caching and differential updates
276
+ * - Only recalculates when child transforms actually change
277
+ * - Minimal memory allocation with factory function patterns
269
278
  *
270
- * Text Nodes are always autosized based on their text content regardless
271
- * of this mode setting.
272
279
  *
273
280
  * @default `false`
274
281
  */
@@ -396,7 +403,11 @@ export interface CoreNodeProps {
396
403
  * The Node's z-index.
397
404
  *
398
405
  * @remarks
399
- * TBD
406
+ * Max z-index of children under the same parent determines which child
407
+ * is rendered on top. Higher z-index means the Node is rendered on top of
408
+ * children with lower z-index.
409
+ *
410
+ * Max value is 1000 and min value is -1000. Values outside of this range will be clamped.
400
411
  */
401
412
  zIndex: number;
402
413
  /**
@@ -424,15 +435,6 @@ export interface CoreNodeProps {
424
435
  */
425
436
  texture: Texture | null;
426
437
 
427
- /**
428
- * [Deprecated]: Prevents the texture from being cleaned up when the Node is removed
429
- *
430
- * @remarks
431
- * Please use the `preventCleanup` property on {@link TextureOptions} instead.
432
- *
433
- * @default false
434
- */
435
- preventCleanup: boolean;
436
438
  /**
437
439
  * Options to associate with the Node's Texture
438
440
  */
@@ -462,7 +464,6 @@ export interface CoreNodeProps {
462
464
  * settings being defaults)
463
465
  */
464
466
  src: string | null;
465
- zIndexLocked: number;
466
467
  /**
467
468
  * Scale to render the Node at
468
469
  *
@@ -683,20 +684,11 @@ export interface CoreNodeProps {
683
684
  */
684
685
  srcY?: number;
685
686
  /**
686
- * By enabling Strict bounds the renderer will not process & render child nodes of a node that is out of the visible area
687
- *
688
- * @remarks
689
- * When enabled out of bound nodes, i.e. nodes that are out of the visible area, will
690
- * **NOT** have their children processed and renderer anymore. This means the children of a out of bound
691
- * node will not receive update processing such as positioning updates and will not be drawn on screen.
692
- * As such the rest of the branch of the update tree that sits below this node will not be processed anymore
693
- *
694
- * This is a big performance gain but may be disabled in cases where the width of the parent node is
695
- * unknown and the render must process the child nodes regardless of the viewport status of the parent node
696
- *
687
+ * Mark the node as interactive so we can perform hit tests on it
688
+ * when pointer events are registered.
697
689
  * @default false
698
690
  */
699
- strictBounds: boolean;
691
+ interactive?: boolean;
700
692
  }
701
693
 
702
694
  /**
@@ -729,12 +721,34 @@ export class CoreNode extends EventEmitter {
729
721
  readonly children: CoreNode[] = [];
730
722
  protected _id: number = getNewId();
731
723
  readonly props: CoreNodeProps;
724
+ public readonly isCoreNode = true as const;
725
+
726
+ // WebGL Render Op State
727
+ public renderOpBufferIdx: number = 0;
728
+ public numQuads: number = 0;
729
+ public renderOpTextures: WebGlCtxTexture[] = [];
730
+
731
+ /**
732
+ * Permanent index (in float32 units) into the renderer's quad buffer.
733
+ * -1 means this node has not yet been assigned a slot.
734
+ */
735
+ public quadBufferIndex: number = -1;
736
+
737
+ /**
738
+ * True when renderCoords, premultiplied colors, or textureCoords changed
739
+ * since the node's quad was last written to the GPU.
740
+ */
741
+ public isQuadDirty: boolean = true;
742
+
743
+ private hasShaderUpdater = false;
744
+ public hasShaderTimeFn = false;
745
+ private hasColorProps = false;
746
+ public textureLoaded = false;
732
747
 
733
748
  public updateType = UpdateType.All;
734
749
  public childUpdateType = UpdateType.None;
735
750
 
736
751
  public globalTransform?: Matrix3d;
737
- public scaleRotateTransform?: Matrix3d;
738
752
  public localTransform?: Matrix3d;
739
753
  public sceneGlobalTransform?: Matrix3d;
740
754
  public renderCoords?: RenderCoords;
@@ -749,8 +763,11 @@ export class CoreNode extends EventEmitter {
749
763
  height: 0,
750
764
  valid: false,
751
765
  };
766
+ public textureCoords?: TextureCoords;
767
+ public updateShaderUniforms: boolean = false;
752
768
  public isRenderable = false;
753
769
  public renderState: CoreNodeRenderState = CoreNodeRenderState.Init;
770
+ public isSimple = true;
754
771
 
755
772
  public worldAlpha = 1;
756
773
  public premultipliedColorTl = 0;
@@ -761,121 +778,189 @@ export class CoreNode extends EventEmitter {
761
778
  public hasRTTupdates = false;
762
779
  public parentHasRenderTexture = false;
763
780
  public rttParent: CoreNode | null = null;
781
+ /**
782
+ * only used when rtt = true
783
+ */
784
+ public framebufferDimensions: Dimensions | null = null;
785
+
786
+ /**Autosize properties */
787
+ autosizer: Autosizer | null = null;
788
+ parentAutosizer: Autosizer | null = null;
789
+
790
+ public destroyed = false;
764
791
 
765
792
  constructor(readonly stage: Stage, props: CoreNodeProps) {
766
793
  super();
767
794
 
768
- this.props = Object.assign({}, props, {
769
- parent: null,
795
+ //inital update type
796
+ let initialUpdateType =
797
+ UpdateType.Local | UpdateType.RenderBounds | UpdateType.RenderState;
798
+
799
+ // Fast-path assign only known keys
800
+ const p = (this.props = {
801
+ x: props.x,
802
+ y: props.y,
803
+ w: props.w,
804
+ h: props.h,
805
+ alpha: props.alpha,
806
+ autosize: props.autosize,
807
+ clipping: props.clipping,
808
+ color: props.color,
809
+ colorTop: props.colorTop,
810
+ colorBottom: props.colorBottom,
811
+ colorLeft: props.colorLeft,
812
+ colorRight: props.colorRight,
813
+ colorTl: props.colorTl,
814
+ colorTr: props.colorTr,
815
+ colorBl: props.colorBl,
816
+ colorBr: props.colorBr,
817
+ scaleX: props.scaleX,
818
+ scaleY: props.scaleY,
819
+ rotation: props.rotation,
820
+ pivotX: props.pivotX,
821
+ pivotY: props.pivotY,
822
+ mountX: props.mountX,
823
+ mountY: props.mountY,
824
+ mount: props.mount,
825
+ pivot: props.pivot,
826
+ zIndex: props.zIndex,
827
+ textureOptions: props.textureOptions,
828
+ data: props.data,
829
+ imageType: props.imageType,
830
+ srcX: props.srcX,
831
+ srcY: props.srcY,
832
+ srcWidth: props.srcWidth,
833
+ srcHeight: props.srcHeight,
834
+ parent: props.parent,
770
835
  texture: null,
771
836
  shader: null,
772
837
  src: null,
773
838
  rtt: false,
839
+ boundsMargin: null,
840
+ scale: null,
841
+ interactive: props.interactive,
774
842
  });
775
843
 
776
- // Assign props to instance
777
- this.parent = props.parent;
844
+ //check if any color props are set for premultiplied color updates
845
+ if (
846
+ p.color > 0 ||
847
+ p.colorTop > 0 ||
848
+ p.colorBottom > 0 ||
849
+ p.colorLeft > 0 ||
850
+ p.colorRight > 0 ||
851
+ p.colorTl > 0 ||
852
+ p.colorTr > 0 ||
853
+ p.colorBl > 0 ||
854
+ p.colorBr > 0
855
+ ) {
856
+ this.hasColorProps = true;
857
+ initialUpdateType |= UpdateType.PremultipliedColors;
858
+ }
859
+
860
+ // Only set non-default values
861
+ if (p.zIndex !== 0) {
862
+ this.zIndex = p.zIndex;
863
+ }
864
+
865
+ if (props.parent !== null) {
866
+ props.parent.addChild(this);
867
+ }
868
+
869
+ // Assign props to instances
778
870
  this.texture = props.texture;
779
871
  this.shader = props.shader;
780
872
  this.src = props.src;
781
873
  this.rtt = props.rtt;
874
+ this.boundsMargin = props.boundsMargin;
875
+ this.interactive = props.interactive;
782
876
 
783
- if (props.boundsMargin) {
784
- this.boundsMargin = Array.isArray(props.boundsMargin)
785
- ? props.boundsMargin
786
- : [
787
- props.boundsMargin,
788
- props.boundsMargin,
789
- props.boundsMargin,
790
- props.boundsMargin,
791
- ];
877
+ // Initialize autosize if enabled
878
+ if (p.autosize === true) {
879
+ this.autosizer = new Autosizer(this);
792
880
  }
793
881
 
794
- this.setUpdateType(
795
- UpdateType.ScaleRotate |
796
- UpdateType.Local |
797
- UpdateType.RenderBounds |
798
- UpdateType.RenderState,
799
- );
800
-
801
- if (isProductionEnvironment() === false && props.preventCleanup === true) {
802
- console.warn(
803
- 'CoreNode.preventCleanup: Is deprecated and will be removed in upcoming release, please use textureOptions.preventCleanup instead',
804
- );
805
- }
882
+ this.setUpdateType(initialUpdateType);
806
883
 
807
884
  // if the default texture isn't loaded yet, wait for it to load
808
885
  // this only happens when the node is created before the stage is ready
809
- if (
810
- this.stage.defaultTexture &&
811
- this.stage.defaultTexture.state !== 'loaded'
812
- ) {
813
- this.stage.defaultTexture.once('loaded', () => {
814
- this.setUpdateType(UpdateType.IsRenderable);
815
- });
886
+ const dt = this.stage.defaultTexture;
887
+ if (dt !== null && dt.state !== 'loaded') {
888
+ dt.once('loaded', () => this.setUpdateType(UpdateType.IsRenderable));
816
889
  }
890
+ this.updateIsSimple();
817
891
  }
818
892
 
819
893
  //#region Textures
820
894
  loadTexture(): void {
821
- const { texture } = this.props;
822
- assertTruthy(texture);
895
+ if (this.props.texture === null) {
896
+ return;
897
+ }
823
898
 
824
899
  // If texture is already loaded / failed, trigger loaded event manually
825
900
  // so that users get a consistent event experience.
826
901
  // We do this in a microtask to allow listeners to be attached in the same
827
902
  // synchronous task after calling loadTexture()
828
- queueMicrotask(() => {
829
- if (this.textureOptions.preload === true) {
830
- this.stage.txManager.loadTexture(texture);
831
- }
903
+ queueMicrotask(this.loadTextureTask);
904
+ }
832
905
 
833
- texture.preventCleanup =
834
- this.props.textureOptions?.preventCleanup ?? false;
835
- texture.on('loaded', this.onTextureLoaded);
836
- texture.on('failed', this.onTextureFailed);
837
- texture.on('freed', this.onTextureFreed);
838
-
839
- // If the parent is a render texture, the initial texture status
840
- // will be set to freed until the texture is processed by the
841
- // Render RTT nodes. So we only need to listen fo changes and
842
- // no need to check the texture.state until we restructure how
843
- // textures are being processed.
844
- if (this.parentHasRenderTexture) {
845
- this.notifyParentRTTOfUpdate();
846
- return;
847
- }
906
+ /**
907
+ * Task for queueMicrotask to loadTexture
908
+ *
909
+ * @remarks
910
+ * This method is called in a microtask to release the texture.
911
+ */
912
+ private loadTextureTask = (): void => {
913
+ const texture = this.props.texture as Texture;
914
+ //it is possible that texture is null here if user sets the texture to null right after loadTexture call
915
+ if (texture === null) {
916
+ return;
917
+ }
918
+ if (this.textureOptions.preload === true) {
919
+ this.stage.txManager.loadTexture(texture);
920
+ }
848
921
 
849
- if (texture.state === 'loaded') {
850
- assertTruthy(texture.dimensions);
851
- this.onTextureLoaded(texture, texture.dimensions);
852
- } else if (texture.state === 'failed') {
853
- assertTruthy(texture.error);
854
- this.onTextureFailed(texture, texture.error);
855
- } else if (texture.state === 'freed') {
856
- this.onTextureFreed(texture);
857
- }
858
- });
859
- }
922
+ texture.preventCleanup = this.props.textureOptions?.preventCleanup ?? false;
923
+ texture.on('loaded', this.onTextureLoaded);
924
+ texture.on('failed', this.onTextureFailed);
925
+ texture.on('freed', this.onTextureFreed);
926
+
927
+ // If the parent is a render texture, the initial texture status
928
+ // will be set to freed until the texture is processed by the
929
+ // Render RTT nodes. So we only need to listen fo changes and
930
+ // no need to check the texture.state until we restructure how
931
+ // textures are being processed.
932
+ if (this.parentHasRenderTexture) {
933
+ this.notifyParentRTTOfUpdate();
934
+ return;
935
+ }
936
+
937
+ if (texture.state === 'loaded') {
938
+ this.onTextureLoaded(texture, texture.dimensions!);
939
+ } else if (texture.state === 'failed') {
940
+ this.onTextureFailed(texture, texture.error!);
941
+ } else if (texture.state === 'freed') {
942
+ this.onTextureFreed(texture);
943
+ }
944
+ };
860
945
 
861
946
  unloadTexture(): void {
862
- if (this.texture !== null) {
863
- this.texture.off('loaded', this.onTextureLoaded);
864
- this.texture.off('failed', this.onTextureFailed);
865
- this.texture.off('freed', this.onTextureFreed);
866
- this.texture.setRenderableOwner(this, false);
947
+ if (this.texture === null) {
948
+ return;
867
949
  }
950
+
951
+ const texture = this.texture;
952
+ texture.off('loaded', this.onTextureLoaded);
953
+ texture.off('failed', this.onTextureFailed);
954
+ texture.off('freed', this.onTextureFreed);
955
+ texture.setRenderableOwner(this._id, false);
868
956
  }
869
957
 
870
- autosizeNode(dimensions: Dimensions) {
871
- if (this.autosize) {
872
- this.width = dimensions.width;
873
- this.height = dimensions.height;
958
+ protected onTextureLoaded: TextureLoadedEventHandler = (_, dimensions) => {
959
+ if (this.autosizer !== null) {
960
+ this.autosizer.update();
874
961
  }
875
- }
876
962
 
877
- private onTextureLoaded: TextureLoadedEventHandler = (_, dimensions) => {
878
- this.autosizeNode(dimensions);
963
+ this.textureLoaded = true;
879
964
  this.setUpdateType(UpdateType.IsRenderable);
880
965
 
881
966
  // Texture was loaded. In case the RAF loop has already stopped, we request
@@ -888,13 +973,20 @@ export class CoreNode extends EventEmitter {
888
973
  }
889
974
 
890
975
  // ignore 1x1 pixel textures
891
- if (dimensions.width > 1 && dimensions.height > 1) {
976
+ if (dimensions.w > 1 && dimensions.h > 1) {
892
977
  this.emit('loaded', {
893
978
  type: 'texture',
894
979
  dimensions,
895
980
  } satisfies NodeTextureLoadedPayload);
896
981
  }
897
982
 
983
+ if (
984
+ this.stage.calculateTextureCoord === true &&
985
+ this.props.textureOptions !== null
986
+ ) {
987
+ this.textureCoords = this.stage.renderer.getTextureCoords!(this);
988
+ }
989
+
898
990
  // Trigger a local update if the texture is loaded and the resizeMode is 'contain'
899
991
  if (this.props.textureOptions?.resizeMode?.type === 'contain') {
900
992
  this.setUpdateType(UpdateType.Local);
@@ -902,6 +994,11 @@ export class CoreNode extends EventEmitter {
902
994
  };
903
995
 
904
996
  private onTextureFailed: TextureFailedEventHandler = (_, error) => {
997
+ // immediately set isRenderable to false, so that we handle the error
998
+ // without waiting for the next frame loop
999
+ this.textureLoaded = false;
1000
+ this.isRenderable = false;
1001
+ this.updateTextureOwnership(false);
905
1002
  this.setUpdateType(UpdateType.IsRenderable);
906
1003
 
907
1004
  // If parent has a render texture, flag that we need to update
@@ -909,13 +1006,23 @@ export class CoreNode extends EventEmitter {
909
1006
  this.notifyParentRTTOfUpdate();
910
1007
  }
911
1008
 
912
- this.emit('failed', {
913
- type: 'texture',
914
- error,
915
- } satisfies NodeTextureFailedPayload);
1009
+ if (
1010
+ this.texture !== null &&
1011
+ this.texture.retryCount > this.texture.maxRetryCount
1012
+ ) {
1013
+ this.emit('failed', {
1014
+ type: 'texture',
1015
+ error,
1016
+ } satisfies NodeTextureFailedPayload);
1017
+ }
916
1018
  };
917
1019
 
918
1020
  private onTextureFreed: TextureFreedEventHandler = () => {
1021
+ // immediately set isRenderable to false, so that we handle the error
1022
+ // without waiting for the next frame loop
1023
+ this.textureLoaded = false;
1024
+ this.isRenderable = false;
1025
+ this.updateTextureOwnership(false);
919
1026
  this.setUpdateType(UpdateType.IsRenderable);
920
1027
 
921
1028
  // If parent has a render texture, flag that we need to update
@@ -941,48 +1048,38 @@ export class CoreNode extends EventEmitter {
941
1048
  this.updateType |= type;
942
1049
 
943
1050
  const parent = this.props.parent;
944
- if (!parent) return;
945
-
946
- if ((parent.updateType & UpdateType.Children) === 0) {
947
- // Inform the parent if it doesn’t already have a child update
948
- parent.setUpdateType(UpdateType.Children);
949
- }
950
- }
1051
+ if (!parent || parent.updateType & UpdateType.Children) return;
951
1052
 
952
- sortChildren() {
953
- this.children.sort((a, b) => a.calcZIndex - b.calcZIndex);
1053
+ parent.setUpdateType(UpdateType.Children);
954
1054
  }
955
1055
 
956
- updateScaleRotateTransform() {
957
- const { rotation, scaleX, scaleY } = this.props;
1056
+ updateLocalTransform() {
1057
+ const p = this.props;
1058
+ const { x, y } = p;
958
1059
 
959
- // optimize simple translation cases
960
- if (rotation === 0 && scaleX === 1 && scaleY === 1) {
961
- this.scaleRotateTransform = undefined;
1060
+ if (this.isSimple) {
1061
+ this.localTransform = Matrix3d.translate(x, y, this.localTransform);
962
1062
  return;
963
1063
  }
964
1064
 
965
- this.scaleRotateTransform = Matrix3d.rotate(
966
- rotation,
967
- this.scaleRotateTransform,
968
- ).scale(scaleX, scaleY);
969
- }
1065
+ const { w, h } = p;
1066
+ const mountTranslateX = p.mountX * w;
1067
+ const mountTranslateY = p.mountY * h;
970
1068
 
971
- updateLocalTransform() {
972
- const { x, y, width, height } = this.props;
973
- const mountTranslateX = this.props.mountX * width;
974
- const mountTranslateY = this.props.mountY * height;
975
-
976
- if (this.scaleRotateTransform) {
977
- const pivotTranslateX = this.props.pivotX * width;
978
- const pivotTranslateY = this.props.pivotY * height;
1069
+ if (p.rotation !== 0 || p.scaleX !== 1 || p.scaleY !== 1) {
1070
+ const scaleRotate = Matrix3d.rotate(p.rotation, Matrix3d.temp).scale(
1071
+ p.scaleX,
1072
+ p.scaleY,
1073
+ );
1074
+ const pivotTranslateX = p.pivotX * w;
1075
+ const pivotTranslateY = p.pivotY * h;
979
1076
 
980
1077
  this.localTransform = Matrix3d.translate(
981
1078
  x - mountTranslateX + pivotTranslateX,
982
1079
  y - mountTranslateY + pivotTranslateY,
983
1080
  this.localTransform,
984
1081
  )
985
- .multiply(this.scaleRotateTransform)
1082
+ .multiply(scaleRotate)
986
1083
  .translate(-pivotTranslateX, -pivotTranslateY);
987
1084
  } else {
988
1085
  this.localTransform = Matrix3d.translate(
@@ -993,35 +1090,35 @@ export class CoreNode extends EventEmitter {
993
1090
  }
994
1091
 
995
1092
  // Handle 'contain' resize mode
996
- const texture = this.props.texture;
1093
+ const texture = p.texture;
997
1094
  if (
998
1095
  texture &&
999
1096
  texture.dimensions &&
1000
- this.props.textureOptions?.resizeMode?.type === 'contain'
1097
+ p.textureOptions.resizeMode?.type === 'contain'
1001
1098
  ) {
1002
1099
  let resizeModeScaleX = 1;
1003
1100
  let resizeModeScaleY = 1;
1004
1101
  let extraX = 0;
1005
1102
  let extraY = 0;
1006
- const { width: tw, height: th } = texture.dimensions;
1103
+ const { w: tw, h: th } = texture.dimensions;
1007
1104
  const txAspectRatio = tw / th;
1008
- const nodeAspectRatio = width / height;
1105
+ const nodeAspectRatio = w / h;
1009
1106
  if (txAspectRatio > nodeAspectRatio) {
1010
1107
  // Texture is wider than node
1011
1108
  // Center the node vertically (shift down by extraY)
1012
1109
  // Scale the node vertically to maintain original aspect ratio
1013
- const scaleX = width / tw;
1110
+ const scaleX = w / tw;
1014
1111
  const scaledTxHeight = th * scaleX;
1015
- extraY = (height - scaledTxHeight) / 2;
1016
- resizeModeScaleY = scaledTxHeight / height;
1112
+ extraY = (h - scaledTxHeight) / 2;
1113
+ resizeModeScaleY = scaledTxHeight / h;
1017
1114
  } else {
1018
1115
  // Texture is taller than node (or equal)
1019
1116
  // Center the node horizontally (shift right by extraX)
1020
1117
  // Scale the node horizontally to maintain original aspect ratio
1021
- const scaleY = height / th;
1118
+ const scaleY = h / th;
1022
1119
  const scaledTxWidth = tw * scaleY;
1023
- extraX = (width - scaledTxWidth) / 2;
1024
- resizeModeScaleX = scaledTxWidth / width;
1120
+ extraX = (w - scaledTxWidth) / 2;
1121
+ resizeModeScaleX = scaledTxWidth / w;
1025
1122
  }
1026
1123
 
1027
1124
  // Apply the extra translation and scale to the local transform
@@ -1029,8 +1126,17 @@ export class CoreNode extends EventEmitter {
1029
1126
  .translate(extraX, extraY)
1030
1127
  .scale(resizeModeScaleX, resizeModeScaleY);
1031
1128
  }
1129
+ }
1032
1130
 
1033
- this.setUpdateType(UpdateType.Global);
1131
+ updateIsSimple() {
1132
+ const p = this.props;
1133
+ this.isSimple =
1134
+ p.rotation === 0 &&
1135
+ p.scaleX === 1 &&
1136
+ p.scaleY === 1 &&
1137
+ p.mountX === 0 &&
1138
+ p.mountY === 0 &&
1139
+ !(p.texture && p.textureOptions.resizeMode?.type === 'contain');
1034
1140
  }
1035
1141
 
1036
1142
  /**
@@ -1038,217 +1144,235 @@ export class CoreNode extends EventEmitter {
1038
1144
  * @param delta
1039
1145
  */
1040
1146
  update(delta: number, parentClippingRect: RectWithValid): void {
1041
- if (this.updateType & UpdateType.ScaleRotate) {
1042
- this.updateScaleRotateTransform();
1043
- this.setUpdateType(UpdateType.Local);
1147
+ const props = this.props;
1148
+ //parent can be forced to ! because the root node update loop uses updateRoot which implies that
1149
+ //all other loops using this update method have a parent
1150
+ const parent = props.parent!;
1151
+ const parentHasRenderTexture = this.parentHasRenderTexture;
1152
+ let newRenderState: CoreNodeRenderState | null = null;
1153
+ let updateType = this.updateType;
1154
+ let childUpdateType = this.childUpdateType;
1155
+
1156
+ //this needs to be handled before setting updateTypes are reset
1157
+ if (
1158
+ ENABLE_AUTOSIZE &&
1159
+ updateType & UpdateType.Autosize &&
1160
+ this.autosizer !== null
1161
+ ) {
1162
+ this.autosizer.update();
1044
1163
  }
1045
1164
 
1046
- if (this.updateType & UpdateType.Local) {
1165
+ // reset update type
1166
+ this.updateType = 0;
1167
+ this.childUpdateType = 0;
1168
+
1169
+ if (updateType & UpdateType.Local) {
1047
1170
  this.updateLocalTransform();
1048
- this.setUpdateType(UpdateType.Global);
1049
- }
1050
1171
 
1051
- const parent = this.props.parent;
1052
- let renderState: CoreNodeRenderState | null = null;
1172
+ updateType |= UpdateType.Global;
1173
+ }
1053
1174
 
1054
1175
  // Handle specific RTT updates at this node level
1055
- if (this.updateType & UpdateType.RenderTexture && this.rtt) {
1176
+ if (USE_RTT && updateType & UpdateType.RenderTexture && this.rtt === true) {
1056
1177
  this.hasRTTupdates = true;
1057
1178
  }
1058
1179
 
1059
- if (this.updateType & UpdateType.Global) {
1060
- assertTruthy(this.localTransform);
1061
-
1062
- if (this.parentHasRenderTexture === true && parent?.rtt === true) {
1180
+ if (updateType & UpdateType.Global) {
1181
+ if (
1182
+ USE_RTT &&
1183
+ this.parentHasRenderTexture === true &&
1184
+ parent.rtt === true
1185
+ ) {
1063
1186
  // we are at the start of the RTT chain, so we need to reset the globalTransform
1064
1187
  // for correct RTT rendering
1065
- this.globalTransform = Matrix3d.identity();
1188
+ this.globalTransform = Matrix3d.identity(this.globalTransform);
1066
1189
 
1067
1190
  // Maintain a full scene global transform for bounds detection
1191
+ const parentTransform =
1192
+ parent.globalTransform || Matrix3d.identity(Matrix3d.temp);
1193
+
1068
1194
  this.sceneGlobalTransform = Matrix3d.copy(
1069
- parent?.globalTransform || Matrix3d.identity(),
1070
- ).multiply(this.localTransform);
1195
+ parentTransform,
1196
+ this.sceneGlobalTransform,
1197
+ ).translateOrMultiply(this.localTransform!);
1071
1198
  } else if (
1199
+ USE_RTT &&
1072
1200
  this.parentHasRenderTexture === true &&
1073
- parent?.rtt === false
1201
+ parent.rtt === false
1074
1202
  ) {
1075
1203
  // we're part of an RTT chain but our parent is not the main RTT node
1076
1204
  // so we need to propogate the sceneGlobalTransform of the parent
1077
1205
  // to maintain a full scene global transform for bounds detection
1206
+ const parentSceneTransform =
1207
+ parent.sceneGlobalTransform || this.localTransform!;
1208
+
1078
1209
  this.sceneGlobalTransform = Matrix3d.copy(
1079
- parent?.sceneGlobalTransform || this.localTransform,
1080
- ).multiply(this.localTransform);
1210
+ parentSceneTransform,
1211
+ this.sceneGlobalTransform,
1212
+ ).translateOrMultiply(this.localTransform!);
1081
1213
 
1082
1214
  this.globalTransform = Matrix3d.copy(
1083
- parent?.globalTransform || this.localTransform,
1215
+ parent.globalTransform || this.localTransform!,
1084
1216
  this.globalTransform,
1085
1217
  );
1086
1218
  } else {
1087
1219
  this.globalTransform = Matrix3d.copy(
1088
- parent?.globalTransform || this.localTransform,
1220
+ parent.globalTransform || this.localTransform!,
1089
1221
  this.globalTransform,
1090
1222
  );
1091
1223
  }
1092
1224
 
1093
- if (parent !== null) {
1094
- this.globalTransform.multiply(this.localTransform);
1225
+ if (this.isSimple) {
1226
+ this.globalTransform.translate(
1227
+ this.localTransform!.tx,
1228
+ this.localTransform!.ty,
1229
+ );
1230
+ } else {
1231
+ this.globalTransform.translateOrMultiply(this.localTransform!);
1095
1232
  }
1096
1233
  this.calculateRenderCoords();
1097
1234
  this.updateBoundingRect();
1098
1235
 
1099
- this.setUpdateType(
1100
- UpdateType.RenderState |
1101
- UpdateType.Children |
1102
- UpdateType.RecalcUniforms,
1103
- );
1104
- this.childUpdateType |= UpdateType.Global;
1236
+ updateType |= UpdateType.RenderState | UpdateType.RecalcUniforms;
1237
+
1238
+ //only propagate children updates if not autosizing
1239
+ if ((updateType & UpdateType.Autosize) === 0) {
1240
+ updateType |= UpdateType.Children;
1241
+ childUpdateType |= UpdateType.Global;
1242
+ }
1105
1243
 
1106
1244
  if (this.clipping === true) {
1107
- this.setUpdateType(UpdateType.Clipping | UpdateType.RenderBounds);
1108
- this.childUpdateType |= UpdateType.RenderBounds;
1245
+ updateType |= UpdateType.Clipping | UpdateType.RenderBounds;
1246
+ childUpdateType |= UpdateType.RenderBounds;
1109
1247
  }
1110
1248
  }
1111
1249
 
1112
- if (this.updateType & UpdateType.RenderBounds) {
1250
+ if (updateType & UpdateType.RenderBounds) {
1113
1251
  this.createRenderBounds();
1114
- this.setUpdateType(UpdateType.RenderState);
1115
- this.setUpdateType(UpdateType.Children);
1116
1252
 
1117
- this.childUpdateType |= UpdateType.RenderBounds;
1253
+ updateType |= UpdateType.RenderState | UpdateType.Children;
1254
+ childUpdateType |= UpdateType.RenderBounds;
1118
1255
  }
1119
1256
 
1120
- if (this.updateType & UpdateType.RenderState) {
1121
- renderState = this.checkRenderBounds();
1122
- this.setUpdateType(UpdateType.IsRenderable);
1257
+ if (updateType & UpdateType.RenderState) {
1258
+ newRenderState = this.checkRenderBounds();
1259
+ updateType |= UpdateType.IsRenderable;
1123
1260
 
1124
1261
  // if we're not going out of bounds, update the render state
1125
1262
  // this is done so the update loop can finish before we mark a node
1126
1263
  // as out of bounds
1127
- if (renderState !== CoreNodeRenderState.OutOfBounds) {
1128
- this.updateRenderState(renderState);
1264
+ if (newRenderState !== CoreNodeRenderState.OutOfBounds) {
1265
+ this.updateRenderState(newRenderState);
1129
1266
  }
1130
1267
  }
1131
1268
 
1132
- if (this.updateType & UpdateType.WorldAlpha) {
1133
- if (parent) {
1134
- this.worldAlpha = parent.worldAlpha * this.props.alpha;
1135
- } else {
1136
- this.worldAlpha = this.props.alpha;
1137
- }
1138
- this.setUpdateType(
1269
+ if (updateType & UpdateType.WorldAlpha) {
1270
+ this.worldAlpha = parent.worldAlpha * this.props.alpha;
1271
+ updateType |=
1272
+ UpdateType.PremultipliedColors |
1139
1273
  UpdateType.Children |
1140
- UpdateType.PremultipliedColors |
1141
- UpdateType.IsRenderable,
1142
- );
1143
- this.childUpdateType |= UpdateType.WorldAlpha;
1274
+ UpdateType.IsRenderable;
1275
+ childUpdateType |= UpdateType.WorldAlpha;
1144
1276
  }
1145
1277
 
1146
- if (this.updateType & UpdateType.IsRenderable) {
1278
+ if (updateType & UpdateType.IsRenderable) {
1147
1279
  this.updateIsRenderable();
1148
1280
  }
1149
1281
 
1150
- if (this.updateType & UpdateType.Clipping) {
1151
- this.calculateClippingRect(parentClippingRect);
1152
- this.setUpdateType(UpdateType.Children);
1282
+ // Handle autosize updates when children transforms change
1283
+ if (
1284
+ ENABLE_AUTOSIZE &&
1285
+ updateType & UpdateType.Global &&
1286
+ this.isRenderable === true &&
1287
+ this.parentAutosizer !== null
1288
+ ) {
1289
+ this.parentAutosizer.patch(this.id);
1290
+ }
1153
1291
 
1154
- this.childUpdateType |= UpdateType.Clipping;
1155
- this.childUpdateType |= UpdateType.RenderBounds;
1292
+ if (updateType & UpdateType.Clipping) {
1293
+ this.calculateClippingRect(parentClippingRect);
1294
+ updateType |= UpdateType.Children;
1295
+ childUpdateType |= UpdateType.Clipping | UpdateType.RenderBounds;
1156
1296
  }
1157
1297
 
1158
- if (this.updateType & UpdateType.PremultipliedColors) {
1159
- this.premultipliedColorTl = mergeColorAlphaPremultiplied(
1160
- this.props.colorTl,
1161
- this.worldAlpha,
1162
- true,
1163
- );
1298
+ if (updateType & UpdateType.PremultipliedColors) {
1299
+ const alpha = this.worldAlpha;
1164
1300
 
1165
- // If all the colors are the same just sent them all to the same value
1166
- if (
1167
- this.props.colorTl === this.props.colorTr &&
1168
- this.props.colorBl === this.props.colorBr &&
1169
- this.props.colorTl === this.props.colorBl
1170
- ) {
1301
+ const tl = props.colorTl;
1302
+ const tr = props.colorTr;
1303
+ const bl = props.colorBl;
1304
+ const br = props.colorBr;
1305
+
1306
+ // Fast equality check (covers all 4 corners)
1307
+ const same = tl === tr && tl === bl && tl === br;
1308
+
1309
+ const merged = premultiplyColorABGR(tl, alpha);
1310
+
1311
+ this.premultipliedColorTl = merged;
1312
+
1313
+ if (same === true) {
1171
1314
  this.premultipliedColorTr =
1172
1315
  this.premultipliedColorBl =
1173
1316
  this.premultipliedColorBr =
1174
- this.premultipliedColorTl;
1317
+ merged;
1175
1318
  } else {
1176
- this.premultipliedColorTr = mergeColorAlphaPremultiplied(
1177
- this.props.colorTr,
1178
- this.worldAlpha,
1179
- true,
1180
- );
1181
- this.premultipliedColorBl = mergeColorAlphaPremultiplied(
1182
- this.props.colorBl,
1183
- this.worldAlpha,
1184
- true,
1185
- );
1186
- this.premultipliedColorBr = mergeColorAlphaPremultiplied(
1187
- this.props.colorBr,
1188
- this.worldAlpha,
1189
- true,
1190
- );
1319
+ this.premultipliedColorTr = premultiplyColorABGR(tr, alpha);
1320
+ this.premultipliedColorBl = premultiplyColorABGR(bl, alpha);
1321
+ this.premultipliedColorBr = premultiplyColorABGR(br, alpha);
1191
1322
  }
1192
1323
  }
1193
1324
 
1194
- // No need to update zIndex if there is no parent
1195
- if (parent !== null && this.updateType & UpdateType.CalculatedZIndex) {
1196
- this.calculateZIndex();
1197
- // Tell parent to re-sort children
1198
- parent.setUpdateType(UpdateType.ZIndexSortedChildren);
1325
+ if (this.renderState === CoreNodeRenderState.OutOfBounds) {
1326
+ // Delay updating children until the node is in bounds
1327
+ this.updateType = updateType;
1328
+ this.childUpdateType = childUpdateType;
1329
+ return;
1199
1330
  }
1200
1331
 
1201
1332
  if (
1202
- this.props.strictBounds === true &&
1203
- this.renderState === CoreNodeRenderState.OutOfBounds
1333
+ updateType & UpdateType.RecalcUniforms &&
1334
+ this.hasShaderUpdater === true
1204
1335
  ) {
1205
- this.updateType &= ~UpdateType.RenderBounds; // remove render bounds update
1206
- return;
1336
+ this.updateShaderUniforms = true;
1207
1337
  }
1208
1338
 
1209
- if (
1210
- this.shader?.update !== undefined &&
1211
- (this.updateType & UpdateType.Local ||
1212
- this.updateType & UpdateType.RecalcUniforms)
1213
- ) {
1214
- this.shader.update();
1339
+ if (this.isRenderable === true && this.updateShaderUniforms === true) {
1340
+ this.updateShaderUniforms = false;
1341
+ //this exists because the boolean hasShaderUpdater === true
1342
+ this.shader!.update!();
1215
1343
  }
1216
1344
 
1217
- if (this.updateType & UpdateType.Children && this.children.length > 0) {
1345
+ if (updateType & UpdateType.Children && this.children.length > 0) {
1346
+ let childClippingRect = this.clippingRect;
1347
+
1348
+ if (USE_RTT && this.rtt === true) {
1349
+ childClippingRect = NO_CLIPPING_RECT;
1350
+ }
1351
+
1218
1352
  for (let i = 0, length = this.children.length; i < length; i++) {
1219
1353
  const child = this.children[i] as CoreNode;
1220
1354
 
1221
- child.setUpdateType(this.childUpdateType);
1355
+ if (childUpdateType !== 0) {
1356
+ child.setUpdateType(childUpdateType);
1357
+ }
1222
1358
 
1223
1359
  if (child.updateType === 0) {
1224
1360
  continue;
1225
1361
  }
1226
1362
 
1227
- let childClippingRect = this.clippingRect;
1228
- if (this.rtt === true) {
1229
- childClippingRect = {
1230
- x: 0,
1231
- y: 0,
1232
- width: 0,
1233
- height: 0,
1234
- valid: false,
1235
- };
1236
- }
1237
-
1238
1363
  child.update(delta, childClippingRect);
1239
1364
  }
1240
1365
  }
1241
1366
 
1242
1367
  // If the node has an RTT parent and requires a texture re-render, inform the RTT parent
1243
- // if (this.parentHasRenderTexture && this.updateType & UpdateType.RenderTexture) {
1368
+ // if (this.parentHasRenderTexture && updateType & UpdateType.RenderTexture) {
1244
1369
  // @TODO have a more scoped down updateType for RTT updates
1245
- if (this.parentHasRenderTexture && this.updateType > 0) {
1370
+ if (USE_RTT === true && parentHasRenderTexture === true) {
1246
1371
  this.notifyParentRTTOfUpdate();
1247
1372
  }
1248
1373
 
1249
- // Sorting children MUST happen after children have been updated so
1250
- // that they have the oppotunity to update their calculated zIndex.
1251
- if (this.updateType & UpdateType.ZIndexSortedChildren) {
1374
+ //Resort children if needed
1375
+ if (updateType & UpdateType.SortZIndexChildren) {
1252
1376
  // reorder z-index
1253
1377
  this.sortChildren();
1254
1378
  }
@@ -1256,24 +1380,31 @@ export class CoreNode extends EventEmitter {
1256
1380
  // If we're out of bounds, apply the render state now
1257
1381
  // this is done so nodes can finish their entire update loop before
1258
1382
  // being marked as out of bounds
1259
- if (renderState === CoreNodeRenderState.OutOfBounds) {
1260
- this.updateRenderState(renderState);
1383
+ if (newRenderState === CoreNodeRenderState.OutOfBounds) {
1384
+ this.updateRenderState(newRenderState);
1261
1385
  this.updateIsRenderable();
1262
1386
 
1263
1387
  if (
1388
+ USE_RTT === true &&
1264
1389
  this.rtt === true &&
1265
- renderState === CoreNodeRenderState.OutOfBounds
1390
+ newRenderState === CoreNodeRenderState.OutOfBounds
1266
1391
  ) {
1267
1392
  // notify children that we are going out of bounds
1268
1393
  // we have to do this now before we stop processing the render tree
1269
- this.notifyChildrenRTTOfUpdate(renderState);
1270
- // this.childUpdateType |= UpdateType.RenderState;
1394
+ this.notifyChildrenRTTOfUpdate(newRenderState);
1271
1395
  }
1272
1396
  }
1273
1397
 
1274
- // reset update type
1275
- this.updateType = 0;
1276
- this.childUpdateType = 0;
1398
+ // Mark quad dirty only when visual data (transforms, colors) actually
1399
+ // changed, so the WebGL renderer only re-uploads modified slots.
1400
+ if (
1401
+ updateType &
1402
+ (UpdateType.Global |
1403
+ UpdateType.PremultipliedColors |
1404
+ UpdateType.WorldAlpha)
1405
+ ) {
1406
+ this.isQuadDirty = true;
1407
+ }
1277
1408
  }
1278
1409
 
1279
1410
  private findParentRTTNode(): CoreNode | null {
@@ -1284,15 +1415,6 @@ export class CoreNode extends EventEmitter {
1284
1415
  return rttNode;
1285
1416
  }
1286
1417
 
1287
- private getRTTParentRenderState(): CoreNodeRenderState | null {
1288
- const rttNode = this.rttParent || this.findParentRTTNode();
1289
- if (!rttNode) {
1290
- return null;
1291
- }
1292
-
1293
- return rttNode.renderState;
1294
- }
1295
-
1296
1418
  private notifyChildrenRTTOfUpdate(renderState: CoreNodeRenderState) {
1297
1419
  for (const child of this.children) {
1298
1420
  // force child to update render state
@@ -1302,7 +1424,7 @@ export class CoreNode extends EventEmitter {
1302
1424
  }
1303
1425
  }
1304
1426
 
1305
- private notifyParentRTTOfUpdate() {
1427
+ protected notifyParentRTTOfUpdate() {
1306
1428
  if (this.parent === null) {
1307
1429
  return;
1308
1430
  }
@@ -1323,28 +1445,21 @@ export class CoreNode extends EventEmitter {
1323
1445
  }
1324
1446
 
1325
1447
  checkRenderBounds(): CoreNodeRenderState {
1326
- assertTruthy(this.renderBound);
1327
- assertTruthy(this.strictBound);
1328
- assertTruthy(this.preloadBound);
1329
-
1330
- if (boundInsideBound(this.renderBound, this.strictBound)) {
1448
+ if (boundInsideBound(this.renderBound!, this.strictBound!)) {
1331
1449
  return CoreNodeRenderState.InViewport;
1332
1450
  }
1333
1451
 
1334
- if (boundInsideBound(this.renderBound, this.preloadBound)) {
1452
+ if (boundInsideBound(this.renderBound!, this.preloadBound!)) {
1335
1453
  return CoreNodeRenderState.InBounds;
1336
1454
  }
1337
1455
 
1338
1456
  // check if we're larger then our parent, we're definitely in the viewport
1339
- if (boundLargeThanBound(this.renderBound, this.strictBound)) {
1457
+ if (boundLargeThanBound(this.renderBound!, this.strictBound!)) {
1340
1458
  return CoreNodeRenderState.InViewport;
1341
1459
  }
1342
1460
 
1343
1461
  // check if we dont have dimensions, take our parent's render state
1344
- if (
1345
- this.parent !== null &&
1346
- (this.props.width === 0 || this.props.height === 0)
1347
- ) {
1462
+ if (this.parent !== null && (this.props.w === 0 || this.props.h === 0)) {
1348
1463
  return this.parent.renderState;
1349
1464
  }
1350
1465
 
@@ -1352,18 +1467,21 @@ export class CoreNode extends EventEmitter {
1352
1467
  }
1353
1468
 
1354
1469
  updateBoundingRect() {
1355
- const transform = this.sceneGlobalTransform || this.globalTransform;
1356
- const renderCoords = this.sceneRenderCoords || this.renderCoords;
1470
+ const transform = (this.sceneGlobalTransform ||
1471
+ this.globalTransform) as Matrix3d;
1472
+ const renderCoords = (this.sceneRenderCoords ||
1473
+ this.renderCoords) as RenderCoords;
1357
1474
 
1358
- assertTruthy(transform);
1359
- assertTruthy(renderCoords);
1360
-
1361
- const { tb, tc } = transform;
1362
- const { x1, y1, x3, y3 } = renderCoords;
1363
- if (tb === 0 || tc === 0) {
1364
- this.renderBound = createBound(x1, y1, x3, y3, this.renderBound);
1475
+ if (transform.tb === 0 || transform.tc === 0) {
1476
+ this.renderBound = createBound(
1477
+ renderCoords.x1,
1478
+ renderCoords.y1,
1479
+ renderCoords.x3,
1480
+ renderCoords.y3,
1481
+ this.renderBound,
1482
+ );
1365
1483
  } else {
1366
- const { x2, x4, y2, y4 } = renderCoords;
1484
+ const { x1, y1, x2, y2, x3, y3, x4, y4 } = renderCoords;
1367
1485
  this.renderBound = createBound(
1368
1486
  Math.min(x1, x2, x3, x4),
1369
1487
  Math.min(y1, y2, y3, y4),
@@ -1375,8 +1493,6 @@ export class CoreNode extends EventEmitter {
1375
1493
  }
1376
1494
 
1377
1495
  createRenderBounds(): void {
1378
- assertTruthy(this.stage);
1379
-
1380
1496
  if (this.parent !== null && this.parent.strictBound !== undefined) {
1381
1497
  // we have a parent with a valid bound, copy it
1382
1498
  const parentBound = this.parent.strictBound;
@@ -1385,11 +1501,13 @@ export class CoreNode extends EventEmitter {
1385
1501
  parentBound.y1,
1386
1502
  parentBound.x2,
1387
1503
  parentBound.y2,
1504
+ this.strictBound,
1388
1505
  );
1389
1506
 
1390
1507
  this.preloadBound = createPreloadBounds(
1391
1508
  this.strictBound,
1392
1509
  this.boundsMargin as [number, number, number, number],
1510
+ this.preloadBound,
1393
1511
  );
1394
1512
  } else {
1395
1513
  // no parent or parent does not have a bound, take the stage boundaries
@@ -1414,24 +1532,19 @@ export class CoreNode extends EventEmitter {
1414
1532
  }
1415
1533
 
1416
1534
  // clipping is enabled and we are in bounds create our own bounds
1417
- const { x, y, width, height } = this.props;
1535
+ const { x, y, w, h } = this.props;
1418
1536
 
1419
1537
  // Pick the global transform if available, otherwise use the local transform
1420
1538
  // global transform is only available if the node in an RTT chain
1421
1539
  const { tx, ty } = this.sceneGlobalTransform || this.globalTransform || {};
1422
1540
  const _x = tx ?? x;
1423
1541
  const _y = ty ?? y;
1424
- this.strictBound = createBound(
1425
- _x,
1426
- _y,
1427
- _x + width,
1428
- _y + height,
1429
- this.strictBound,
1430
- );
1542
+ this.strictBound = createBound(_x, _y, _x + w, _y + h, this.strictBound);
1431
1543
 
1432
1544
  this.preloadBound = createPreloadBounds(
1433
1545
  this.strictBound,
1434
1546
  this.boundsMargin as [number, number, number, number],
1547
+ this.preloadBound,
1435
1548
  );
1436
1549
  }
1437
1550
 
@@ -1442,12 +1555,34 @@ export class CoreNode extends EventEmitter {
1442
1555
 
1443
1556
  const previous = this.renderState;
1444
1557
  this.renderState = renderState;
1445
- const event = CoreNodeRenderStateMap.get(renderState);
1446
- assertTruthy(event);
1447
- this.emit(event, {
1448
- previous,
1449
- current: renderState,
1450
- });
1558
+
1559
+ // If node visibility changes, dirty the render list cache
1560
+ if (
1561
+ renderState === CoreNodeRenderState.OutOfBounds ||
1562
+ previous === CoreNodeRenderState.OutOfBounds
1563
+ ) {
1564
+ this.stage.requestRenderListUpdate();
1565
+ }
1566
+
1567
+ if (EMIT_BOUNDS_EVENTS) {
1568
+ const event = CoreNodeRenderStateMap.get(renderState);
1569
+ assertTruthy(event);
1570
+ this.emit(event, {
1571
+ previous,
1572
+ current: renderState,
1573
+ });
1574
+ }
1575
+ }
1576
+
1577
+ /**
1578
+ * Checks if the node is renderable based on world alpha, dimensions and out of bounds status.
1579
+ */
1580
+ checkBasicRenderability(): boolean {
1581
+ if (this.worldAlpha === 0 || this.isOutOfBounds() === true) {
1582
+ return false;
1583
+ } else {
1584
+ return true;
1585
+ }
1451
1586
  }
1452
1587
 
1453
1588
  /**
@@ -1465,51 +1600,58 @@ export class CoreNode extends EventEmitter {
1465
1600
  }
1466
1601
 
1467
1602
  if (this.texture !== null) {
1468
- needsTextureOwnership = true;
1603
+ // preemptive check for failed textures this will mark the current node as non-renderable
1604
+ // and will prevent further checks until the texture is reloaded or retry is reset on the texture
1605
+ if (this.texture.retryCount > this.texture.maxRetryCount) {
1606
+ // texture has failed to load, we cannot render
1607
+ this.updateTextureOwnership(false);
1608
+ this.setRenderable(false);
1609
+ return;
1610
+ }
1469
1611
 
1470
- // we're only renderable if the texture state is loaded
1471
- newIsRenderable = this.texture.state === 'loaded';
1612
+ needsTextureOwnership = true;
1613
+ // Use cached boolean instead of string comparison
1614
+ newIsRenderable = this.textureLoaded;
1472
1615
  } else if (
1473
- (this.hasShader() || this.hasColorProperties() === true) &&
1616
+ // check shader
1617
+ (this.props.shader !== this.stage.renderer.getDefaultShaderNode() ||
1618
+ this.hasColorProps === true) &&
1619
+ // check dimensions
1474
1620
  this.hasDimensions() === true
1475
1621
  ) {
1476
1622
  // This mean we have dimensions and a color set, so we can render a ColorTexture
1477
- if (
1478
- this.stage.defaultTexture &&
1479
- this.stage.defaultTexture.state === 'loaded'
1480
- ) {
1481
- newIsRenderable = true;
1482
- }
1623
+ newIsRenderable = true;
1483
1624
  }
1484
1625
 
1485
1626
  this.updateTextureOwnership(needsTextureOwnership);
1486
1627
  this.setRenderable(newIsRenderable);
1487
1628
  }
1488
1629
 
1489
- /**
1490
- * Checks if the node is renderable based on world alpha, dimensions and out of bounds status.
1491
- */
1492
- checkBasicRenderability(): boolean {
1493
- if (this.worldAlpha === 0 || this.isOutOfBounds() === true) {
1494
- return false;
1495
- } else {
1496
- return true;
1497
- }
1498
- }
1499
-
1500
1630
  /**
1501
1631
  * Sets the renderable state and triggers changes if necessary.
1502
1632
  * @param isRenderable - The new renderable state
1503
1633
  */
1504
1634
  setRenderable(isRenderable: boolean) {
1635
+ const previousIsRenderable = this.isRenderable;
1505
1636
  this.isRenderable = isRenderable;
1637
+
1638
+ // Emit event if renderable status has changed
1639
+ if (previousIsRenderable !== isRenderable) {
1640
+ this.stage.requestRenderListUpdate();
1641
+ if (EMIT_BOUNDS_EVENTS) {
1642
+ this.emit('renderable', {
1643
+ type: 'renderable',
1644
+ isRenderable,
1645
+ } satisfies NodeRenderablePayload);
1646
+ }
1647
+ }
1506
1648
  }
1507
1649
 
1508
1650
  /**
1509
1651
  * Changes the renderable state of the node.
1510
1652
  */
1511
1653
  updateTextureOwnership(isRenderable: boolean) {
1512
- this.texture?.setRenderableOwner(this, isRenderable);
1654
+ this.texture?.setRenderableOwner(this._id, isRenderable);
1513
1655
  }
1514
1656
 
1515
1657
  /**
@@ -1523,38 +1665,24 @@ export class CoreNode extends EventEmitter {
1523
1665
  * Checks if the node has dimensions (width/height)
1524
1666
  */
1525
1667
  hasDimensions(): boolean {
1526
- return this.props.width !== 0 && this.props.height !== 0;
1527
- }
1528
-
1529
- /**
1530
- * Checks if the node has any color properties set.
1531
- */
1532
- hasColorProperties(): boolean {
1533
- return (
1534
- this.props.color !== 0 ||
1535
- this.props.colorTop !== 0 ||
1536
- this.props.colorBottom !== 0 ||
1537
- this.props.colorLeft !== 0 ||
1538
- this.props.colorRight !== 0 ||
1539
- this.props.colorTl !== 0 ||
1540
- this.props.colorTr !== 0 ||
1541
- this.props.colorBl !== 0 ||
1542
- this.props.colorBr !== 0
1543
- );
1544
- }
1545
-
1546
- hasShader(): boolean {
1547
- return this.props.shader !== null;
1668
+ return this.props.w !== 0 && this.props.h !== 0;
1548
1669
  }
1549
1670
 
1550
1671
  calculateRenderCoords() {
1551
- const { width, height } = this;
1552
- const { tx, ty, ta, tb, tc, td } = this.globalTransform!;
1672
+ const { w, h } = this.props;
1673
+
1674
+ const g = this.globalTransform!;
1675
+ const tx = g.tx,
1676
+ ty = g.ty,
1677
+ ta = g.ta,
1678
+ tb = g.tb,
1679
+ tc = g.tc,
1680
+ td = g.td;
1553
1681
  if (tb === 0 && tc === 0) {
1554
1682
  const minX = tx;
1555
- const maxX = tx + width * ta;
1683
+ const maxX = tx + w * ta;
1556
1684
  const minY = ty;
1557
- const maxY = ty + height * td;
1685
+ const maxY = ty + h * td;
1558
1686
  this.renderCoords = RenderCoords.translate(
1559
1687
  //top-left
1560
1688
  minX,
@@ -1576,18 +1704,18 @@ export class CoreNode extends EventEmitter {
1576
1704
  tx,
1577
1705
  ty,
1578
1706
  //top-right
1579
- tx + width * ta,
1580
- ty + width * tc,
1707
+ tx + w * ta,
1708
+ ty + w * tc,
1581
1709
  //bottom-right
1582
- tx + width * ta + height * tb,
1583
- ty + width * tc + height * td,
1710
+ tx + w * ta + h * tb,
1711
+ ty + w * tc + h * td,
1584
1712
  //bottom-left
1585
- tx + height * tb,
1586
- ty + height * td,
1713
+ tx + h * tb,
1714
+ ty + h * td,
1587
1715
  this.renderCoords,
1588
1716
  );
1589
1717
  }
1590
- if (this.sceneGlobalTransform === undefined) {
1718
+ if (!USE_RTT || this.sceneGlobalTransform === undefined) {
1591
1719
  return;
1592
1720
  }
1593
1721
 
@@ -1601,9 +1729,9 @@ export class CoreNode extends EventEmitter {
1601
1729
  } = this.sceneGlobalTransform;
1602
1730
  if (stb === 0 && stc === 0) {
1603
1731
  const minX = stx;
1604
- const maxX = stx + width * sta;
1732
+ const maxX = stx + w * sta;
1605
1733
  const minY = sty;
1606
- const maxY = sty + height * std;
1734
+ const maxY = sty + h * std;
1607
1735
  this.sceneRenderCoords = RenderCoords.translate(
1608
1736
  //top-left
1609
1737
  minX,
@@ -1625,14 +1753,14 @@ export class CoreNode extends EventEmitter {
1625
1753
  stx,
1626
1754
  sty,
1627
1755
  //top-right
1628
- stx + width * sta,
1629
- sty + width * stc,
1756
+ stx + w * sta,
1757
+ sty + w * stc,
1630
1758
  //bottom-right
1631
- stx + width * sta + height * stb,
1632
- sty + width * stc + height * std,
1759
+ stx + w * sta + h * stb,
1760
+ sty + w * stc + h * std,
1633
1761
  //bottom-left
1634
- stx + height * stb,
1635
- sty + height * std,
1762
+ stx + h * stb,
1763
+ sty + h * std,
1636
1764
  this.sceneRenderCoords,
1637
1765
  );
1638
1766
  }
@@ -1647,16 +1775,15 @@ export class CoreNode extends EventEmitter {
1647
1775
  * Finally, the node's parentClippingRect and clippingRect properties are updated.
1648
1776
  */
1649
1777
  calculateClippingRect(parentClippingRect: RectWithValid) {
1650
- assertTruthy(this.globalTransform);
1651
1778
  const { clippingRect, props, globalTransform: gt } = this;
1652
1779
  const { clipping } = props;
1653
- const isRotated = gt.tb !== 0 || gt.tc !== 0;
1780
+ const isRotated = gt!.tb !== 0 || gt!.tc !== 0;
1654
1781
 
1655
1782
  if (clipping === true && isRotated === false) {
1656
- clippingRect.x = gt.tx;
1657
- clippingRect.y = gt.ty;
1658
- clippingRect.width = this.width * gt.ta;
1659
- clippingRect.height = this.height * gt.td;
1783
+ clippingRect.x = gt!.tx;
1784
+ clippingRect.y = gt!.ty;
1785
+ clippingRect.width = this.props.w * gt!.ta;
1786
+ clippingRect.height = this.props.h * gt!.td;
1660
1787
  clippingRect.valid = true;
1661
1788
  } else {
1662
1789
  clippingRect.valid = false;
@@ -1672,95 +1799,185 @@ export class CoreNode extends EventEmitter {
1672
1799
  }
1673
1800
  }
1674
1801
 
1675
- calculateZIndex(): void {
1676
- const props = this.props;
1677
- const z = props.zIndex || 0;
1678
- const p = props.parent?.zIndex || 0;
1679
-
1680
- let zIndex = z;
1681
- if (props.parent?.zIndexLocked) {
1682
- zIndex = z < p ? z : p;
1683
- }
1684
- this.calcZIndex = zIndex;
1685
- }
1686
-
1687
1802
  /**
1688
1803
  * Destroy the node and cleanup all resources
1689
1804
  */
1690
- destroy(): void {
1691
- this.unloadTexture();
1805
+ destroy(isChild: boolean = false): void {
1806
+ if (this.destroyed === true) {
1807
+ return;
1808
+ }
1809
+ this.destroyed = true;
1810
+
1811
+ // Detach from parent first to stop propagation of updates
1812
+ if (isChild === false) {
1813
+ const parent = this.parent;
1814
+ if (parent !== null) {
1815
+ parent.removeChild(this);
1816
+ }
1817
+ this.props.parent = null;
1818
+ this.stage.requestRender();
1819
+ }
1692
1820
 
1693
- this.clippingRect.valid = false;
1821
+ this.removeAllListeners();
1822
+ this.unloadTexture();
1694
1823
  this.isRenderable = false;
1695
1824
 
1696
- this.renderCoords = undefined;
1697
- this.renderBound = undefined;
1698
- this.strictBound = undefined;
1699
- this.preloadBound = undefined;
1700
- this.globalTransform = undefined;
1701
- this.scaleRotateTransform = undefined;
1702
- this.localTransform = undefined;
1825
+ if (this.hasShaderTimeFn === true) {
1826
+ this.stage.untrackTimedNode(this);
1827
+ }
1828
+
1829
+ if (USE_RTT && this.rtt === true) {
1830
+ this.stage.renderer.removeRTTNode(this);
1831
+ }
1832
+
1833
+ // Kill children
1834
+ for (let i = 0, n = this.children.length; i < n; i++) {
1835
+ this.children[i]!.destroy(true);
1836
+ }
1837
+ this.children.length = 0;
1703
1838
 
1704
1839
  this.props.texture = null;
1705
- this.props.shader = this.stage.defShaderNode;
1840
+ }
1706
1841
 
1707
- while (this.children.length > 0) {
1708
- this.children[0]?.destroy();
1842
+ renderQuads(renderer: CoreRenderer): void {
1843
+ if (USE_RTT && this.parentHasRenderTexture === true) {
1844
+ const rtt = renderer.renderToTextureActive;
1845
+ if (rtt === false || this.parentRenderTexture !== renderer.activeRttNode)
1846
+ return;
1847
+ }
1848
+ // There is a race condition where the texture can be null
1849
+ // with RTT nodes. Adding this defensively to avoid errors.
1850
+ // Also check if we have a valid texture or default texture to render
1851
+ if (USE_RTT && this.renderTexture!.state !== 'loaded') {
1852
+ return;
1709
1853
  }
1710
1854
 
1711
- // This very action will also remove the node from the parent's children array
1712
- this.parent = null;
1855
+ renderer.addQuad(this);
1856
+ }
1713
1857
 
1714
- if (this.rtt) {
1715
- this.stage.renderer.removeRTTNode(this);
1858
+ get renderTexture(): Texture | null {
1859
+ return this.props.texture || this.stage.defaultTexture;
1860
+ }
1861
+
1862
+ get renderTextureCoords(): TextureCoords | undefined {
1863
+ return this.textureCoords || this.stage.renderer.defaultTextureCoords;
1864
+ }
1865
+
1866
+ get quadBufferCollection(): BufferCollection {
1867
+ return (this.stage.renderer as WebGlRenderer).quadBufferCollection;
1868
+ }
1869
+
1870
+ get width(): number {
1871
+ return this.props.w;
1872
+ }
1873
+
1874
+ get height(): number {
1875
+ return this.props.h;
1876
+ }
1877
+
1878
+ get time(): number {
1879
+ if (this.hasShaderTimeFn === true) {
1880
+ return this.getTimerValue();
1716
1881
  }
1882
+ return 0;
1883
+ }
1717
1884
 
1718
- this.removeAllListeners();
1885
+ getTimerValue(): number {
1886
+ if (typeof this.shader!.time === 'function') {
1887
+ return this.shader!.time(this.stage);
1888
+ }
1889
+ return this.stage.elapsedTime;
1719
1890
  }
1720
1891
 
1721
- renderQuads(renderer: CoreRenderer): void {
1722
- // Prevent quad rendering if parent has a render texture
1723
- // and renderer is not currently rendering to a texture
1724
- if (this.parentHasRenderTexture) {
1725
- if (!renderer.renderToTextureActive) {
1726
- return;
1892
+ sortChildren() {
1893
+ this.children.sort((a, b) => a.props.zIndex - b.props.zIndex);
1894
+ this.stage.requestRenderListUpdate();
1895
+ }
1896
+
1897
+ removeChild(node: CoreNode, targetParent: CoreNode | null = null) {
1898
+ if (targetParent === null) {
1899
+ if (
1900
+ USE_RTT &&
1901
+ this.props.rtt === true &&
1902
+ this.parentHasRenderTexture === true
1903
+ ) {
1904
+ node.clearRTTInheritance();
1727
1905
  }
1728
- // Prevent quad rendering if parent render texture is not the active render texture
1729
- if (this.parentRenderTexture !== renderer.activeRttNode) {
1730
- return;
1906
+
1907
+ if (ENABLE_AUTOSIZE) {
1908
+ const autosizeTarget = this.autosizer || this.parentAutosizer;
1909
+ if (autosizeTarget !== null) {
1910
+ autosizeTarget.detach(node);
1911
+ }
1731
1912
  }
1732
1913
  }
1914
+ removeChild(node, this.children);
1915
+ this.stage.requestRenderListUpdate();
1916
+ }
1917
+
1918
+ addChild(node: CoreNode, previousParent: CoreNode | null = null) {
1919
+ const inRttCluster =
1920
+ USE_RTT &&
1921
+ (this.props.rtt === true || this.parentHasRenderTexture === true);
1922
+ const children = this.children;
1923
+ let attachToAutosizer = false;
1924
+ let autosizeTarget: Autosizer | null = null;
1925
+ if (ENABLE_AUTOSIZE) {
1926
+ autosizeTarget = this.autosizer || this.parentAutosizer;
1927
+ attachToAutosizer = autosizeTarget !== null;
1928
+ }
1929
+
1930
+ node.parentHasRenderTexture = inRttCluster;
1931
+ if (previousParent !== null) {
1932
+ const previousParentInRttCluster =
1933
+ USE_RTT &&
1934
+ (previousParent.props.rtt === true ||
1935
+ previousParent.parentHasRenderTexture === true);
1936
+ if (inRttCluster === false && previousParentInRttCluster === true) {
1937
+ // update child RTT status
1938
+ node.clearRTTInheritance();
1939
+ }
1733
1940
 
1734
- assertTruthy(this.globalTransform);
1735
- assertTruthy(this.renderCoords);
1736
-
1737
- // add to list of renderables to be sorted before rendering
1738
- renderer.addQuad({
1739
- width: this.props.width,
1740
- height: this.props.height,
1741
- colorTl: this.premultipliedColorTl,
1742
- colorTr: this.premultipliedColorTr,
1743
- colorBl: this.premultipliedColorBl,
1744
- colorBr: this.premultipliedColorBr,
1745
- // if we do not have a texture, use the default texture
1746
- // this assumes any renderable node is either a distinct texture or a ColorTexture
1747
- texture: this.texture || this.stage.defaultTexture,
1748
- textureOptions: this.textureOptions,
1749
- zIndex: this.zIndex,
1750
- shader: this.props.shader as CoreShaderNode<any>,
1751
- alpha: this.worldAlpha,
1752
- clippingRect: this.clippingRect,
1753
- tx: this.globalTransform.tx,
1754
- ty: this.globalTransform.ty,
1755
- ta: this.globalTransform.ta,
1756
- tb: this.globalTransform.tb,
1757
- tc: this.globalTransform.tc,
1758
- td: this.globalTransform.td,
1759
- renderCoords: this.renderCoords,
1760
- rtt: this.rtt,
1761
- parentHasRenderTexture: this.parentHasRenderTexture,
1762
- framebufferDimensions: this.framebufferDimensions,
1763
- });
1941
+ if (ENABLE_AUTOSIZE) {
1942
+ const previousAutosizer = node.autosizer || node.parentAutosizer;
1943
+ if (previousAutosizer !== null) {
1944
+ if (!autosizeTarget || previousAutosizer.id !== autosizeTarget.id) {
1945
+ previousAutosizer.detach(node);
1946
+ }
1947
+ attachToAutosizer = false;
1948
+ }
1949
+ }
1950
+ }
1951
+
1952
+ if (ENABLE_AUTOSIZE && attachToAutosizer === true && autosizeTarget) {
1953
+ //if this is true, then the autosizer really exists
1954
+ autosizeTarget.attach(node);
1955
+ }
1956
+
1957
+ if (inRttCluster === true) {
1958
+ node.markChildrenWithRTT(this);
1959
+ }
1960
+
1961
+ children.push(node);
1962
+
1963
+ // check if we need to sort
1964
+ const lastIndex = children.length - 1;
1965
+ let shouldSort = node.zIndex !== 0;
1966
+
1967
+ if (shouldSort === false && lastIndex > 0) {
1968
+ // If the new node has zIndex 0, we check if any existing children have (had) non-zero zIndex.
1969
+ // Since children are sorted, we only need to check the first and the last (before the new one).
1970
+ // The new node is at `lastIndex`. The previous last node is at `lastIndex - 1`.
1971
+ const first = children[0]!;
1972
+ const last = children[lastIndex - 1]!;
1973
+ shouldSort = first.zIndex !== 0 || last.zIndex !== 0;
1974
+ }
1975
+
1976
+ if (shouldSort) {
1977
+ this.setUpdateType(UpdateType.SortZIndexChildren);
1978
+ }
1979
+ this.setUpdateType(UpdateType.Children);
1980
+ this.stage.requestRenderListUpdate();
1764
1981
  }
1765
1982
 
1766
1983
  //#region Properties
@@ -1790,7 +2007,7 @@ export class CoreNode extends EventEmitter {
1790
2007
  get absX(): number {
1791
2008
  return (
1792
2009
  this.props.x +
1793
- -this.props.width * this.props.mountX +
2010
+ -this.props.w * this.props.mountX +
1794
2011
  (this.props.parent?.absX || this.props.parent?.globalTransform?.tx || 0)
1795
2012
  );
1796
2013
  }
@@ -1798,7 +2015,7 @@ export class CoreNode extends EventEmitter {
1798
2015
  get absY(): number {
1799
2016
  return (
1800
2017
  this.props.y +
1801
- -this.props.height * this.props.mountY +
2018
+ -this.props.h * this.props.mountY +
1802
2019
  (this.props.parent?.absY ?? 0)
1803
2020
  );
1804
2021
  }
@@ -1814,43 +2031,63 @@ export class CoreNode extends EventEmitter {
1814
2031
  }
1815
2032
  }
1816
2033
 
1817
- get width(): number {
1818
- return this.props.width;
2034
+ get w(): number {
2035
+ return this.props.w;
1819
2036
  }
1820
2037
 
1821
- set width(value: number) {
1822
- if (this.props.width !== value) {
1823
- this.props.width = value;
1824
- this.setUpdateType(UpdateType.Local);
2038
+ set w(value: number) {
2039
+ const props = this.props;
2040
+ if (props.w !== value) {
2041
+ props.w = value;
2042
+ let updateType = UpdateType.Local;
1825
2043
 
1826
- if (this.props.rtt) {
1827
- this.texture = this.stage.txManager.createTexture('RenderTexture', {
1828
- width: this.width,
1829
- height: this.height,
1830
- });
2044
+ if (
2045
+ props.texture !== null &&
2046
+ this.stage.calculateTextureCoord === true &&
2047
+ props.textureOptions !== null
2048
+ ) {
2049
+ this.textureCoords = this.stage.renderer.getTextureCoords!(this);
2050
+ }
1831
2051
 
1832
- this.setUpdateType(UpdateType.RenderTexture);
2052
+ if (props.rtt === true) {
2053
+ this.framebufferDimensions!.w = value;
2054
+ this.texture = this.stage.txManager.createTexture(
2055
+ 'RenderTexture',
2056
+ this.framebufferDimensions!,
2057
+ );
2058
+ updateType |= UpdateType.RenderTexture;
1833
2059
  }
2060
+ this.setUpdateType(updateType);
1834
2061
  }
1835
2062
  }
1836
2063
 
1837
- get height(): number {
1838
- return this.props.height;
2064
+ get h(): number {
2065
+ return this.props.h;
1839
2066
  }
1840
2067
 
1841
- set height(value: number) {
1842
- if (this.props.height !== value) {
1843
- this.props.height = value;
1844
- this.setUpdateType(UpdateType.Local);
2068
+ set h(value: number) {
2069
+ const props = this.props;
2070
+ if (props.h !== value) {
2071
+ props.h = value;
2072
+ let updateType = UpdateType.Local;
1845
2073
 
1846
- if (this.props.rtt) {
1847
- this.texture = this.stage.txManager.createTexture('RenderTexture', {
1848
- width: this.width,
1849
- height: this.height,
1850
- });
2074
+ if (
2075
+ props.texture !== null &&
2076
+ this.stage.calculateTextureCoord === true &&
2077
+ props.textureOptions !== null
2078
+ ) {
2079
+ this.textureCoords = this.stage.renderer.getTextureCoords!(this);
2080
+ }
1851
2081
 
1852
- this.setUpdateType(UpdateType.RenderTexture);
2082
+ if (props.rtt === true) {
2083
+ this.framebufferDimensions!.h = value;
2084
+ this.texture = this.stage.txManager.createTexture(
2085
+ 'RenderTexture',
2086
+ this.framebufferDimensions!,
2087
+ );
2088
+ updateType |= UpdateType.RenderTexture;
1853
2089
  }
2090
+ this.setUpdateType(updateType);
1854
2091
  }
1855
2092
  }
1856
2093
 
@@ -1865,6 +2102,7 @@ export class CoreNode extends EventEmitter {
1865
2102
  // Unlike INode, `null` should never be possibility for Animations.
1866
2103
  this.scaleX = value;
1867
2104
  this.scaleY = value;
2105
+ this.updateIsSimple();
1868
2106
  }
1869
2107
 
1870
2108
  get scaleX(): number {
@@ -1874,7 +2112,8 @@ export class CoreNode extends EventEmitter {
1874
2112
  set scaleX(value: number) {
1875
2113
  if (this.props.scaleX !== value) {
1876
2114
  this.props.scaleX = value;
1877
- this.setUpdateType(UpdateType.ScaleRotate);
2115
+ this.setUpdateType(UpdateType.Local);
2116
+ this.updateIsSimple();
1878
2117
  }
1879
2118
  }
1880
2119
 
@@ -1885,7 +2124,8 @@ export class CoreNode extends EventEmitter {
1885
2124
  set scaleY(value: number) {
1886
2125
  if (this.props.scaleY !== value) {
1887
2126
  this.props.scaleY = value;
1888
- this.setUpdateType(UpdateType.ScaleRotate);
2127
+ this.setUpdateType(UpdateType.Local);
2128
+ this.updateIsSimple();
1889
2129
  }
1890
2130
  }
1891
2131
 
@@ -1899,6 +2139,7 @@ export class CoreNode extends EventEmitter {
1899
2139
  this.props.mountY = value;
1900
2140
  this.props.mount = value;
1901
2141
  this.setUpdateType(UpdateType.Local);
2142
+ this.updateIsSimple();
1902
2143
  }
1903
2144
  }
1904
2145
 
@@ -1910,6 +2151,7 @@ export class CoreNode extends EventEmitter {
1910
2151
  if (this.props.mountX !== value) {
1911
2152
  this.props.mountX = value;
1912
2153
  this.setUpdateType(UpdateType.Local);
2154
+ this.updateIsSimple();
1913
2155
  }
1914
2156
  }
1915
2157
 
@@ -1921,6 +2163,7 @@ export class CoreNode extends EventEmitter {
1921
2163
  if (this.props.mountY !== value) {
1922
2164
  this.props.mountY = value;
1923
2165
  this.setUpdateType(UpdateType.Local);
2166
+ this.updateIsSimple();
1924
2167
  }
1925
2168
  }
1926
2169
 
@@ -1966,7 +2209,8 @@ export class CoreNode extends EventEmitter {
1966
2209
  set rotation(value: number) {
1967
2210
  if (this.props.rotation !== value) {
1968
2211
  this.props.rotation = value;
1969
- this.setUpdateType(UpdateType.ScaleRotate);
2212
+ this.setUpdateType(UpdateType.Local);
2213
+ this.updateIsSimple();
1970
2214
  }
1971
2215
  }
1972
2216
 
@@ -1990,15 +2234,34 @@ export class CoreNode extends EventEmitter {
1990
2234
  }
1991
2235
 
1992
2236
  set autosize(value: boolean) {
2237
+ if (this.props.autosize === value) {
2238
+ return;
2239
+ }
2240
+
1993
2241
  this.props.autosize = value;
2242
+
2243
+ if (value === true && this.autosizer === null) {
2244
+ this.autosizer = new Autosizer(this);
2245
+ } else {
2246
+ this.autosizer = null;
2247
+ }
1994
2248
  }
1995
2249
 
1996
2250
  get boundsMargin(): number | [number, number, number, number] | null {
1997
- return (
1998
- this.props.boundsMargin ??
1999
- this.parent?.boundsMargin ??
2000
- this.stage.boundsMargin
2001
- );
2251
+ const props = this.props;
2252
+ if (props.boundsMargin !== null) {
2253
+ return props.boundsMargin;
2254
+ }
2255
+
2256
+ const parent = this.parent;
2257
+ if (parent !== null) {
2258
+ const margin = parent.boundsMargin;
2259
+ if (margin !== undefined) {
2260
+ return margin;
2261
+ }
2262
+ }
2263
+
2264
+ return this.stage.boundsMargin;
2002
2265
  }
2003
2266
 
2004
2267
  set boundsMargin(value: number | [number, number, number, number] | null) {
@@ -2035,11 +2298,22 @@ export class CoreNode extends EventEmitter {
2035
2298
  }
2036
2299
 
2037
2300
  set color(value: number) {
2038
- this.colorTop = value;
2039
- this.colorBottom = value;
2040
- this.colorLeft = value;
2041
- this.colorRight = value;
2042
- this.props.color = value;
2301
+ const p = this.props;
2302
+ if (p.color === value) return;
2303
+
2304
+ p.color = value;
2305
+
2306
+ const has = value > 0;
2307
+
2308
+ if (has !== this.hasColorProps) {
2309
+ this.setUpdateType(UpdateType.IsRenderable);
2310
+ }
2311
+ this.hasColorProps = has;
2312
+
2313
+ if (p.colorTop !== value) this.colorTop = value;
2314
+ if (p.colorBottom !== value) this.colorBottom = value;
2315
+ if (p.colorLeft !== value) this.colorLeft = value;
2316
+ if (p.colorRight !== value) this.colorRight = value;
2043
2317
 
2044
2318
  this.setUpdateType(UpdateType.PremultipliedColors);
2045
2319
  }
@@ -2054,7 +2328,10 @@ export class CoreNode extends EventEmitter {
2054
2328
  this.colorTr = value;
2055
2329
  }
2056
2330
  this.props.colorTop = value;
2057
- this.setUpdateType(UpdateType.PremultipliedColors);
2331
+ this.hasColorProps = value > 0;
2332
+ this.setUpdateType(
2333
+ UpdateType.PremultipliedColors | UpdateType.IsRenderable,
2334
+ );
2058
2335
  }
2059
2336
 
2060
2337
  get colorBottom(): number {
@@ -2067,7 +2344,10 @@ export class CoreNode extends EventEmitter {
2067
2344
  this.colorBr = value;
2068
2345
  }
2069
2346
  this.props.colorBottom = value;
2070
- this.setUpdateType(UpdateType.PremultipliedColors);
2347
+ this.hasColorProps = value > 0;
2348
+ this.setUpdateType(
2349
+ UpdateType.PremultipliedColors | UpdateType.IsRenderable,
2350
+ );
2071
2351
  }
2072
2352
 
2073
2353
  get colorLeft(): number {
@@ -2080,7 +2360,10 @@ export class CoreNode extends EventEmitter {
2080
2360
  this.colorBl = value;
2081
2361
  }
2082
2362
  this.props.colorLeft = value;
2083
- this.setUpdateType(UpdateType.PremultipliedColors);
2363
+ this.hasColorProps = value > 0;
2364
+ this.setUpdateType(
2365
+ UpdateType.PremultipliedColors | UpdateType.IsRenderable,
2366
+ );
2084
2367
  }
2085
2368
 
2086
2369
  get colorRight(): number {
@@ -2093,7 +2376,10 @@ export class CoreNode extends EventEmitter {
2093
2376
  this.colorBr = value;
2094
2377
  }
2095
2378
  this.props.colorRight = value;
2096
- this.setUpdateType(UpdateType.PremultipliedColors);
2379
+ this.hasColorProps = value > 0;
2380
+ this.setUpdateType(
2381
+ UpdateType.PremultipliedColors | UpdateType.IsRenderable,
2382
+ );
2097
2383
  }
2098
2384
 
2099
2385
  get colorTl(): number {
@@ -2102,7 +2388,10 @@ export class CoreNode extends EventEmitter {
2102
2388
 
2103
2389
  set colorTl(value: number) {
2104
2390
  this.props.colorTl = value;
2105
- this.setUpdateType(UpdateType.PremultipliedColors);
2391
+ this.hasColorProps = value > 0;
2392
+ this.setUpdateType(
2393
+ UpdateType.PremultipliedColors | UpdateType.IsRenderable,
2394
+ );
2106
2395
  }
2107
2396
 
2108
2397
  get colorTr(): number {
@@ -2111,7 +2400,10 @@ export class CoreNode extends EventEmitter {
2111
2400
 
2112
2401
  set colorTr(value: number) {
2113
2402
  this.props.colorTr = value;
2114
- this.setUpdateType(UpdateType.PremultipliedColors);
2403
+ this.hasColorProps = value > 0;
2404
+ this.setUpdateType(
2405
+ UpdateType.PremultipliedColors | UpdateType.IsRenderable,
2406
+ );
2115
2407
  }
2116
2408
 
2117
2409
  get colorBl(): number {
@@ -2120,7 +2412,10 @@ export class CoreNode extends EventEmitter {
2120
2412
 
2121
2413
  set colorBl(value: number) {
2122
2414
  this.props.colorBl = value;
2123
- this.setUpdateType(UpdateType.PremultipliedColors);
2415
+ this.hasColorProps = value > 0;
2416
+ this.setUpdateType(
2417
+ UpdateType.PremultipliedColors | UpdateType.IsRenderable,
2418
+ );
2124
2419
  }
2125
2420
 
2126
2421
  get colorBr(): number {
@@ -2129,21 +2424,10 @@ export class CoreNode extends EventEmitter {
2129
2424
 
2130
2425
  set colorBr(value: number) {
2131
2426
  this.props.colorBr = value;
2132
- this.setUpdateType(UpdateType.PremultipliedColors);
2133
- }
2134
-
2135
- // we're only interested in parent zIndex to test
2136
- // if we should use node zIndex is higher then parent zIndex
2137
- get zIndexLocked(): number {
2138
- return this.props.zIndexLocked || 0;
2139
- }
2140
-
2141
- set zIndexLocked(value: number) {
2142
- this.props.zIndexLocked = value;
2143
- this.setUpdateType(UpdateType.CalculatedZIndex | UpdateType.Children);
2144
- for (let i = 0, length = this.children.length; i < length; i++) {
2145
- this.children[i]!.setUpdateType(UpdateType.CalculatedZIndex);
2146
- }
2427
+ this.hasColorProps = value > 0;
2428
+ this.setUpdateType(
2429
+ UpdateType.PremultipliedColors | UpdateType.IsRenderable,
2430
+ );
2147
2431
  }
2148
2432
 
2149
2433
  get zIndex(): number {
@@ -2151,10 +2435,28 @@ export class CoreNode extends EventEmitter {
2151
2435
  }
2152
2436
 
2153
2437
  set zIndex(value: number) {
2154
- this.props.zIndex = value;
2155
- this.setUpdateType(UpdateType.CalculatedZIndex | UpdateType.Children);
2156
- for (let i = 0, length = this.children.length; i < length; i++) {
2157
- this.children[i]!.setUpdateType(UpdateType.CalculatedZIndex);
2438
+ let sanitizedValue = value;
2439
+ if (isNaN(sanitizedValue) || Number.isFinite(sanitizedValue) === false) {
2440
+ console.warn(
2441
+ `zIndex was set to an invalid value: ${value}, defaulting to 0`,
2442
+ );
2443
+ sanitizedValue = 0;
2444
+ }
2445
+
2446
+ //Clamp to safe integer range
2447
+ if (sanitizedValue > Number.MAX_SAFE_INTEGER) {
2448
+ sanitizedValue = 1000;
2449
+ } else if (sanitizedValue < Number.MIN_SAFE_INTEGER) {
2450
+ sanitizedValue = -1000;
2451
+ }
2452
+
2453
+ if (this.props.zIndex === sanitizedValue) {
2454
+ return;
2455
+ }
2456
+ this.props.zIndex = sanitizedValue;
2457
+ const parent = this.parent;
2458
+ if (parent !== null) {
2459
+ parent.setUpdateType(UpdateType.SortZIndexChildren);
2158
2460
  }
2159
2461
  }
2160
2462
 
@@ -2169,48 +2471,13 @@ export class CoreNode extends EventEmitter {
2169
2471
  }
2170
2472
  this.props.parent = newParent;
2171
2473
  if (oldParent) {
2172
- const index = oldParent.children.indexOf(this);
2173
- assertTruthy(
2174
- index !== -1,
2175
- "CoreNode.parent: Node not found in old parent's children!",
2176
- );
2177
- oldParent.children.splice(index, 1);
2178
- oldParent.setUpdateType(
2179
- UpdateType.Children | UpdateType.ZIndexSortedChildren,
2180
- );
2181
- }
2182
- if (newParent) {
2183
- newParent.children.push(this);
2184
- // Since this node has a new parent, to be safe, have it do a full update.
2185
- this.setUpdateType(UpdateType.All);
2186
- // Tell parent that it's children need to be updated and sorted.
2187
- newParent.setUpdateType(
2188
- UpdateType.Children | UpdateType.ZIndexSortedChildren,
2189
- );
2190
-
2191
- // If the new parent has an RTT enabled, apply RTT inheritance
2192
- if (newParent.rtt || newParent.parentHasRenderTexture) {
2193
- this.applyRTTInheritance(newParent);
2194
- }
2474
+ oldParent.removeChild(this, newParent);
2195
2475
  }
2196
- this.updateScaleRotateTransform();
2197
-
2198
- // fetch render bounds from parent
2199
- this.setUpdateType(UpdateType.RenderBounds | UpdateType.Children);
2200
- }
2201
-
2202
- get preventCleanup(): boolean {
2203
- return this.props.textureOptions.preventCleanup || false;
2204
- }
2205
-
2206
- set preventCleanup(value: boolean) {
2207
- if (isProductionEnvironment() === false) {
2208
- console.warn(
2209
- 'CoreNode.preventCleanup: Is deprecated and will be removed in upcoming release, please use textureOptions.preventCleanup instead',
2210
- );
2476
+ if (newParent !== null) {
2477
+ newParent.addChild(this, oldParent);
2211
2478
  }
2212
-
2213
- this.props.textureOptions.preventCleanup = value;
2479
+ //since this node has a new parent, recalc global and render bounds
2480
+ this.setUpdateType(UpdateType.Global | UpdateType.RenderBounds);
2214
2481
  }
2215
2482
 
2216
2483
  get rtt(): boolean {
@@ -2237,11 +2504,14 @@ export class CoreNode extends EventEmitter {
2237
2504
  }
2238
2505
  }
2239
2506
  private initRenderTexture() {
2240
- this.texture = this.stage.txManager.createTexture('RenderTexture', {
2241
- width: this.width,
2242
- height: this.height,
2243
- });
2244
-
2507
+ this.framebufferDimensions = {
2508
+ w: this.props.w,
2509
+ h: this.props.h,
2510
+ };
2511
+ this.texture = this.stage.txManager.createTexture(
2512
+ 'RenderTexture',
2513
+ this.framebufferDimensions,
2514
+ );
2245
2515
  this.stage.renderer.renderToTexture(this);
2246
2516
  }
2247
2517
 
@@ -2251,6 +2521,7 @@ export class CoreNode extends EventEmitter {
2251
2521
 
2252
2522
  this.hasRTTupdates = false;
2253
2523
  this.texture = null;
2524
+ this.framebufferDimensions = null;
2254
2525
  }
2255
2526
 
2256
2527
  private markChildrenWithRTT(node: CoreNode | null = null) {
@@ -2300,13 +2571,24 @@ export class CoreNode extends EventEmitter {
2300
2571
  return;
2301
2572
  }
2302
2573
  if (shader === null) {
2574
+ this.hasShaderUpdater = false;
2303
2575
  this.props.shader = this.stage.defShaderNode;
2304
2576
  this.setUpdateType(UpdateType.IsRenderable);
2305
2577
  return;
2306
2578
  }
2307
- shader.attachNode(this);
2579
+ if (shader.shaderKey !== 'default') {
2580
+ this.hasShaderUpdater = shader.update !== undefined;
2581
+ this.hasShaderTimeFn = shader.time !== undefined;
2582
+ shader.attachNode(this);
2583
+ }
2584
+
2585
+ if (this.hasShaderTimeFn === true) {
2586
+ this.stage.trackTimedNode(this);
2587
+ } else {
2588
+ this.stage.untrackTimedNode(this);
2589
+ }
2308
2590
  this.props.shader = shader;
2309
- this.setUpdateType(UpdateType.IsRenderable);
2591
+ this.setUpdateType(UpdateType.IsRenderable | UpdateType.RecalcUniforms);
2310
2592
  }
2311
2593
 
2312
2594
  get src(): string | null {
@@ -2327,8 +2609,8 @@ export class CoreNode extends EventEmitter {
2327
2609
 
2328
2610
  this.texture = this.stage.txManager.createTexture('ImageTexture', {
2329
2611
  src: imageUrl,
2330
- width: this.props.width,
2331
- height: this.props.height,
2612
+ w: this.props.w,
2613
+ h: this.props.h,
2332
2614
  type: this.props.imageType,
2333
2615
  sx: this.props.srcX,
2334
2616
  sy: this.props.srcY,
@@ -2382,16 +2664,14 @@ export class CoreNode extends EventEmitter {
2382
2664
  }
2383
2665
 
2384
2666
  /**
2385
- * Returns the framebuffer dimensions of the node.
2386
- * If the node has a render texture, the dimensions are the same as the node's dimensions.
2387
- * If the node does not have a render texture, the dimensions are inherited from the parent.
2388
- * If the node parent has a render texture and the node is a render texture, the nodes dimensions are used.
2667
+ * Returns the framebuffer dimensions of the RTT parent
2389
2668
  */
2390
- get framebufferDimensions(): Dimensions {
2391
- if (this.parentHasRenderTexture && !this.rtt && this.parent) {
2392
- return this.parent.framebufferDimensions;
2669
+ get parentFramebufferDimensions(): Dimensions | null {
2670
+ if (this.rttParent !== null) {
2671
+ return this.rttParent.framebufferDimensions;
2393
2672
  }
2394
- return { width: this.width, height: this.height };
2673
+ this.rttParent = this.findParentRTTNode();
2674
+ return this.rttParent ? this.rttParent.framebufferDimensions : null;
2395
2675
  }
2396
2676
 
2397
2677
  /**
@@ -2419,39 +2699,53 @@ export class CoreNode extends EventEmitter {
2419
2699
 
2420
2700
  const oldTexture = this.props.texture;
2421
2701
  if (oldTexture) {
2422
- oldTexture.setRenderableOwner(this, false);
2423
2702
  this.unloadTexture();
2703
+ if (this.autosizer !== null && value === null) {
2704
+ this.autosizer.setMode(AutosizeMode.Children); // Set to children size mode
2705
+ }
2424
2706
  }
2425
2707
 
2708
+ this.textureCoords = undefined;
2426
2709
  this.props.texture = value;
2427
2710
  if (value !== null) {
2428
- value.setRenderableOwner(this, this.isRenderable);
2711
+ if (this.autosizer !== null) {
2712
+ this.autosizer.setMode(AutosizeMode.Texture); // Set to texture size mode
2713
+ }
2714
+ value.setRenderableOwner(this._id, this.isRenderable);
2429
2715
  this.loadTexture();
2430
2716
  }
2431
2717
 
2432
2718
  this.setUpdateType(UpdateType.IsRenderable);
2719
+ this.updateIsSimple();
2433
2720
  }
2434
2721
 
2435
2722
  set textureOptions(value: TextureOptions) {
2436
2723
  this.props.textureOptions = value;
2724
+ if (this.stage.calculateTextureCoord === true && value !== null) {
2725
+ this.textureCoords = this.stage.renderer.getTextureCoords!(this);
2726
+ }
2727
+ this.updateIsSimple();
2437
2728
  }
2438
2729
 
2439
2730
  get textureOptions(): TextureOptions {
2440
2731
  return this.props.textureOptions;
2441
2732
  }
2442
2733
 
2443
- get strictBounds(): boolean {
2444
- return this.props.strictBounds;
2734
+ set interactive(value: boolean | undefined) {
2735
+ this.props.interactive = value;
2736
+ // Update Stage's interactive Set
2737
+ if (value === true) {
2738
+ this.stage.interactiveNodes.add(this);
2739
+ }
2445
2740
  }
2446
2741
 
2447
- set strictBounds(v) {
2448
- if (v === this.props.strictBounds) {
2449
- return;
2450
- }
2742
+ get interactive(): boolean | undefined {
2743
+ return this.props.interactive;
2744
+ }
2451
2745
 
2452
- this.props.strictBounds = v;
2453
- this.setUpdateType(UpdateType.RenderBounds | UpdateType.Children);
2454
- this.childUpdateType |= UpdateType.RenderBounds | UpdateType.Children;
2746
+ setRTTUpdates(type: number) {
2747
+ this.hasRTTupdates = true;
2748
+ this.parent?.setRTTUpdates(type);
2455
2749
  }
2456
2750
 
2457
2751
  animate(
@@ -2472,5 +2766,70 @@ export class CoreNode extends EventEmitter {
2472
2766
  // no-op
2473
2767
  }
2474
2768
 
2769
+ /**
2770
+ * Add a texture to the current RenderOp.
2771
+ *
2772
+ * @param texture
2773
+ * @returns Assigned Texture Index of the texture in the render op
2774
+ */
2775
+ addTexture(texture: WebGlCtxTexture): number {
2776
+ const textures = this.renderOpTextures;
2777
+ const length = textures.length;
2778
+
2779
+ for (let i = 0; i < length; i++) {
2780
+ if (textures[i] === texture) {
2781
+ return i;
2782
+ }
2783
+ }
2784
+
2785
+ if (length >= 1) {
2786
+ return 0xffffffff;
2787
+ }
2788
+
2789
+ textures.push(texture);
2790
+ return length;
2791
+ }
2792
+
2793
+ draw(renderer: WebGlRenderer) {
2794
+ const { glw, options, stage } = renderer;
2795
+ const shader = this.props.shader as any;
2796
+
2797
+ stage.shManager.useShader(shader.program);
2798
+ shader.program.bindRenderOp(this);
2799
+
2800
+ // Clipping
2801
+ if (this.clippingRect.valid === true) {
2802
+ const pixelRatio =
2803
+ USE_RTT && this.parentHasRenderTexture ? 1 : stage.pixelRatio;
2804
+
2805
+ const clipX = Math.round(this.clippingRect.x * pixelRatio);
2806
+ const clipWidth = Math.round(this.clippingRect.width * pixelRatio);
2807
+ const clipHeight = Math.round(this.clippingRect.height * pixelRatio);
2808
+ let clipY = Math.round(
2809
+ options.canvas.height - clipHeight - this.clippingRect.y * pixelRatio,
2810
+ );
2811
+ // if parent has render texture, we need to adjust the scissor rect
2812
+ // to be relative to the parent's framebuffer
2813
+ if (USE_RTT && this.parentHasRenderTexture) {
2814
+ clipY = this.parentFramebufferDimensions
2815
+ ? this.parentFramebufferDimensions.h - this.props.h
2816
+ : 0;
2817
+ }
2818
+
2819
+ glw.setScissorTest(true);
2820
+ glw.scissor(clipX, clipY, clipWidth, clipHeight);
2821
+ } else {
2822
+ glw.setScissorTest(false);
2823
+ }
2824
+
2825
+ const quadIdx = (this.renderOpBufferIdx / 20) * 6 * 2;
2826
+ glw.drawElements(
2827
+ glw.TRIANGLES,
2828
+ 6 * this.numQuads,
2829
+ glw.UNSIGNED_SHORT,
2830
+ quadIdx,
2831
+ );
2832
+ }
2833
+
2475
2834
  //#endregion Properties
2476
2835
  }