@lightningjs/renderer 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (204) hide show
  1. package/README.md +1 -1
  2. package/dist/src/common/CommonTypes.d.ts +8 -0
  3. package/dist/src/core/CoreNode.d.ts +63 -15
  4. package/dist/src/core/CoreNode.js +266 -117
  5. package/dist/src/core/CoreNode.js.map +1 -1
  6. package/dist/src/core/CoreTextNode.d.ts +11 -0
  7. package/dist/src/core/CoreTextNode.js +58 -0
  8. package/dist/src/core/CoreTextNode.js.map +1 -1
  9. package/dist/src/core/CoreTextureManager.d.ts +3 -1
  10. package/dist/src/core/CoreTextureManager.js +4 -1
  11. package/dist/src/core/CoreTextureManager.js.map +1 -1
  12. package/dist/src/core/Stage.d.ts +12 -2
  13. package/dist/src/core/Stage.js +36 -24
  14. package/dist/src/core/Stage.js.map +1 -1
  15. package/dist/src/core/animations/CoreAnimation.js +11 -2
  16. package/dist/src/core/animations/CoreAnimation.js.map +1 -1
  17. package/dist/src/core/lib/ContextSpy.d.ts +12 -0
  18. package/dist/src/core/lib/ContextSpy.js +38 -0
  19. package/dist/src/core/lib/ContextSpy.js.map +1 -0
  20. package/dist/src/core/lib/ImageWorker.d.ts +16 -0
  21. package/dist/src/core/lib/ImageWorker.js +111 -0
  22. package/dist/src/core/lib/ImageWorker.js.map +1 -0
  23. package/dist/src/core/lib/WebGlContext.d.ts +414 -0
  24. package/dist/src/core/lib/WebGlContext.js +640 -0
  25. package/dist/src/core/lib/WebGlContext.js.map +1 -0
  26. package/dist/src/core/lib/WebGlContextWrapper.d.ts +500 -0
  27. package/dist/src/core/lib/WebGlContextWrapper.js +784 -0
  28. package/dist/src/core/lib/WebGlContextWrapper.js.map +1 -0
  29. package/dist/src/core/platform.js +4 -0
  30. package/dist/src/core/platform.js.map +1 -1
  31. package/dist/src/core/renderers/webgl/WebGlCoreCtxSubTexture.d.ts +2 -1
  32. package/dist/src/core/renderers/webgl/WebGlCoreCtxSubTexture.js +2 -2
  33. package/dist/src/core/renderers/webgl/WebGlCoreCtxSubTexture.js.map +1 -1
  34. package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.d.ts +3 -2
  35. package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.js +23 -21
  36. package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.js.map +1 -1
  37. package/dist/src/core/renderers/webgl/WebGlCoreRenderOp.d.ts +3 -2
  38. package/dist/src/core/renderers/webgl/WebGlCoreRenderOp.js +9 -13
  39. package/dist/src/core/renderers/webgl/WebGlCoreRenderOp.js.map +1 -1
  40. package/dist/src/core/renderers/webgl/WebGlCoreRenderer.d.ts +4 -1
  41. package/dist/src/core/renderers/webgl/WebGlCoreRenderer.js +33 -31
  42. package/dist/src/core/renderers/webgl/WebGlCoreRenderer.js.map +1 -1
  43. package/dist/src/core/renderers/webgl/WebGlCoreShader.d.ts +2 -1
  44. package/dist/src/core/renderers/webgl/WebGlCoreShader.js +24 -24
  45. package/dist/src/core/renderers/webgl/WebGlCoreShader.js.map +1 -1
  46. package/dist/src/core/renderers/webgl/internal/RendererUtils.d.ts +8 -5
  47. package/dist/src/core/renderers/webgl/internal/RendererUtils.js +11 -13
  48. package/dist/src/core/renderers/webgl/internal/RendererUtils.js.map +1 -1
  49. package/dist/src/core/renderers/webgl/internal/ShaderUtils.d.ts +3 -2
  50. package/dist/src/core/renderers/webgl/internal/ShaderUtils.js +15 -15
  51. package/dist/src/core/renderers/webgl/internal/ShaderUtils.js.map +1 -1
  52. package/dist/src/core/renderers/webgl/shaders/DefaultShader.js +3 -6
  53. package/dist/src/core/renderers/webgl/shaders/DefaultShader.js.map +1 -1
  54. package/dist/src/core/renderers/webgl/shaders/DefaultShaderBatched.js +3 -3
  55. package/dist/src/core/renderers/webgl/shaders/DefaultShaderBatched.js.map +1 -1
  56. package/dist/src/core/renderers/webgl/shaders/DynamicShader.d.ts +1 -0
  57. package/dist/src/core/renderers/webgl/shaders/DynamicShader.js +32 -12
  58. package/dist/src/core/renderers/webgl/shaders/DynamicShader.js.map +1 -1
  59. package/dist/src/core/renderers/webgl/shaders/RoundedRectangle.js +3 -3
  60. package/dist/src/core/renderers/webgl/shaders/RoundedRectangle.js.map +1 -1
  61. package/dist/src/core/renderers/webgl/shaders/SdfShader.js +3 -3
  62. package/dist/src/core/renderers/webgl/shaders/SdfShader.js.map +1 -1
  63. package/dist/src/core/renderers/webgl/shaders/effects/BorderEffect.js +1 -1
  64. package/dist/src/core/renderers/webgl/shaders/effects/GrayscaleEffect.d.ts +14 -1
  65. package/dist/src/core/renderers/webgl/shaders/effects/GrayscaleEffect.js +15 -5
  66. package/dist/src/core/renderers/webgl/shaders/effects/GrayscaleEffect.js.map +1 -1
  67. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.js +7 -8
  68. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.js.map +1 -1
  69. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.d.ts +2 -1
  70. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.js +4 -2
  71. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.js.map +1 -1
  72. package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.js +40 -13
  73. package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.js.map +1 -1
  74. package/dist/src/core/text-rendering/renderers/LightningTextTextureRenderer.d.ts +1 -1
  75. package/dist/src/core/text-rendering/renderers/LightningTextTextureRenderer.js +6 -6
  76. package/dist/src/core/text-rendering/renderers/LightningTextTextureRenderer.js.map +1 -1
  77. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.d.ts +3 -2
  78. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js +82 -50
  79. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js.map +1 -1
  80. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/findNearestMultiple.d.ts +8 -0
  81. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/findNearestMultiple.js +29 -0
  82. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/findNearestMultiple.js.map +1 -0
  83. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/getStartConditions.d.ts +4 -3
  84. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/getStartConditions.js +15 -11
  85. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/getStartConditions.js.map +1 -1
  86. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.d.ts +3 -2
  87. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.js +30 -26
  88. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.js.map +1 -1
  89. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/SdfBufferHelper.d.ts +19 -0
  90. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/SdfBufferHelper.js +84 -0
  91. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/SdfBufferHelper.js.map +1 -0
  92. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutLine.d.ts +8 -0
  93. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutLine.js +40 -0
  94. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutLine.js.map +1 -0
  95. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutText2.d.ts +2 -0
  96. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutText2.js +41 -0
  97. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutText2.js.map +1 -0
  98. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/utils.d.ts +1 -0
  99. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/utils.js +4 -0
  100. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/utils.js.map +1 -0
  101. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2.d.ts +1 -0
  102. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2.js +2 -0
  103. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2.js.map +1 -0
  104. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/roundUpToMultiple.d.ts +9 -0
  105. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/roundUpToMultiple.js +32 -0
  106. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/roundUpToMultiple.js.map +1 -0
  107. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.d.ts +26 -0
  108. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.js +70 -0
  109. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.js.map +1 -0
  110. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/util.d.ts +16 -0
  111. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/util.js +39 -0
  112. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/util.js.map +1 -0
  113. package/dist/src/core/text-rendering/renderers/TextRenderer.d.ts +50 -0
  114. package/dist/src/core/text-rendering/renderers/TextRenderer.js +19 -0
  115. package/dist/src/core/text-rendering/renderers/TextRenderer.js.map +1 -1
  116. package/dist/src/core/textures/ImageTexture.js +14 -9
  117. package/dist/src/core/textures/ImageTexture.js.map +1 -1
  118. package/dist/src/core/utils.d.ts +1 -6
  119. package/dist/src/core/utils.js +3 -2
  120. package/dist/src/core/utils.js.map +1 -1
  121. package/dist/src/main-api/ICoreDriver.d.ts +2 -1
  122. package/dist/src/main-api/RendererMain.d.ts +25 -0
  123. package/dist/src/main-api/RendererMain.js +14 -5
  124. package/dist/src/main-api/RendererMain.js.map +1 -1
  125. package/dist/src/render-drivers/main/MainCoreDriver.d.ts +2 -1
  126. package/dist/src/render-drivers/main/MainCoreDriver.js +6 -4
  127. package/dist/src/render-drivers/main/MainCoreDriver.js.map +1 -1
  128. package/dist/src/render-drivers/main/MainOnlyTextNode.d.ts +10 -0
  129. package/dist/src/render-drivers/main/MainOnlyTextNode.js +45 -0
  130. package/dist/src/render-drivers/main/MainOnlyTextNode.js.map +1 -1
  131. package/dist/src/render-drivers/threadx/TextNodeStruct.d.ts +10 -0
  132. package/dist/src/render-drivers/threadx/TextNodeStruct.js +45 -0
  133. package/dist/src/render-drivers/threadx/TextNodeStruct.js.map +1 -1
  134. package/dist/src/render-drivers/threadx/ThreadXCoreDriver.d.ts +2 -1
  135. package/dist/src/render-drivers/threadx/ThreadXCoreDriver.js +8 -1
  136. package/dist/src/render-drivers/threadx/ThreadXCoreDriver.js.map +1 -1
  137. package/dist/src/render-drivers/threadx/ThreadXMainTextNode.d.ts +5 -0
  138. package/dist/src/render-drivers/threadx/ThreadXMainTextNode.js +5 -0
  139. package/dist/src/render-drivers/threadx/ThreadXMainTextNode.js.map +1 -1
  140. package/dist/src/render-drivers/threadx/ThreadXRendererMessage.d.ts +4 -1
  141. package/dist/src/render-drivers/threadx/ThreadXRendererMessage.js.map +1 -1
  142. package/dist/src/render-drivers/threadx/worker/ThreadXRendererTextNode.d.ts +5 -0
  143. package/dist/src/render-drivers/threadx/worker/ThreadXRendererTextNode.js +10 -0
  144. package/dist/src/render-drivers/threadx/worker/ThreadXRendererTextNode.js.map +1 -1
  145. package/dist/src/render-drivers/threadx/worker/renderer.js +5 -3
  146. package/dist/src/render-drivers/threadx/worker/renderer.js.map +1 -1
  147. package/dist/src/utils.d.ts +2 -1
  148. package/dist/src/utils.js +22 -3
  149. package/dist/src/utils.js.map +1 -1
  150. package/dist/tsconfig.dist.tsbuildinfo +1 -1
  151. package/package.json +3 -2
  152. package/src/common/CommonTypes.ts +9 -0
  153. package/src/core/CoreNode.ts +325 -148
  154. package/src/core/CoreTextNode.ts +72 -0
  155. package/src/core/CoreTextureManager.ts +4 -2
  156. package/src/core/Stage.ts +60 -34
  157. package/src/core/animations/CoreAnimation.ts +11 -2
  158. package/src/core/lib/ContextSpy.ts +41 -0
  159. package/src/core/lib/ImageWorker.ts +124 -0
  160. package/src/core/lib/WebGlContextWrapper.ts +965 -0
  161. package/src/core/platform.ts +5 -0
  162. package/src/core/renderers/webgl/WebGlCoreCtxSubTexture.ts +3 -2
  163. package/src/core/renderers/webgl/WebGlCoreCtxTexture.ts +29 -28
  164. package/src/core/renderers/webgl/WebGlCoreRenderOp.ts +10 -14
  165. package/src/core/renderers/webgl/WebGlCoreRenderer.ts +34 -63
  166. package/src/core/renderers/webgl/WebGlCoreShader.ts +34 -25
  167. package/src/core/renderers/webgl/internal/RendererUtils.ts +13 -16
  168. package/src/core/renderers/webgl/internal/ShaderUtils.ts +16 -15
  169. package/src/core/renderers/webgl/shaders/DefaultShader.ts +3 -7
  170. package/src/core/renderers/webgl/shaders/DefaultShaderBatched.ts +3 -3
  171. package/src/core/renderers/webgl/shaders/DynamicShader.ts +42 -14
  172. package/src/core/renderers/webgl/shaders/RoundedRectangle.ts +3 -3
  173. package/src/core/renderers/webgl/shaders/SdfShader.ts +3 -3
  174. package/src/core/renderers/webgl/shaders/effects/BorderEffect.ts +1 -1
  175. package/src/core/renderers/webgl/shaders/effects/GrayscaleEffect.ts +35 -5
  176. package/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.ts +7 -8
  177. package/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.test.ts +9 -3
  178. package/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.ts +4 -2
  179. package/src/core/text-rendering/renderers/CanvasTextRenderer.ts +44 -15
  180. package/src/core/text-rendering/renderers/LightningTextTextureRenderer.ts +7 -7
  181. package/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.ts +115 -63
  182. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/getStartConditions.ts +26 -18
  183. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.ts +40 -28
  184. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/measureText.test.ts +6 -1
  185. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.test.ts +205 -0
  186. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/{makeRenderWindow.ts → setRenderWindow.ts} +50 -21
  187. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/util.ts +40 -0
  188. package/src/core/text-rendering/renderers/TextRenderer.ts +73 -0
  189. package/src/core/textures/ImageTexture.ts +17 -9
  190. package/src/core/utils.ts +87 -85
  191. package/src/env.d.ts +7 -0
  192. package/src/main-api/ICoreDriver.ts +2 -1
  193. package/src/main-api/RendererMain.ts +43 -5
  194. package/src/render-drivers/main/MainCoreDriver.ts +8 -5
  195. package/src/render-drivers/main/MainOnlyTextNode.ts +55 -1
  196. package/src/render-drivers/threadx/TextNodeStruct.ts +45 -0
  197. package/src/render-drivers/threadx/ThreadXCoreDriver.ts +10 -2
  198. package/src/render-drivers/threadx/ThreadXMainTextNode.ts +10 -0
  199. package/src/render-drivers/threadx/ThreadXRendererMessage.ts +5 -1
  200. package/src/render-drivers/threadx/worker/ThreadXRendererTextNode.ts +15 -0
  201. package/src/render-drivers/threadx/worker/renderer.ts +6 -4
  202. package/src/utils.ts +25 -4
  203. package/src/core/scene/Scene.ts +0 -120
  204. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/makeRenderWindow.test.ts +0 -136
@@ -17,7 +17,7 @@
17
17
  * limitations under the License.
18
18
  */
19
19
 
20
- import { assertTruthy } from '../utils.js';
20
+ import { assertTruthy, mergeColorAlphaPremultiplied } from '../utils.js';
21
21
  import type { ShaderMap } from './CoreShaderManager.js';
22
22
  import type {
23
23
  ExtractProps,
@@ -82,17 +82,83 @@ type ICoreNode = Omit<
82
82
  'texture' | 'textureOptions' | 'shader' | 'shaderProps'
83
83
  >;
84
84
 
85
+ enum UpdateType {
86
+ /**
87
+ * Child updates
88
+ */
89
+ Children = 1,
90
+
91
+ /**
92
+ * Scale/Rotate transform update
93
+ */
94
+ ScaleRotate = 2,
95
+
96
+ /**
97
+ * Translate transform update (x/y/width/height/pivot/mount)
98
+ */
99
+ Local = 4,
100
+
101
+ /**
102
+ * Global transform update
103
+ */
104
+ Global = 8,
105
+
106
+ /**
107
+ * Clipping rect update
108
+ */
109
+ Clipping = 16,
110
+
111
+ /**
112
+ * Calculated ZIndex update
113
+ */
114
+ CalculatedZIndex = 32,
115
+
116
+ /**
117
+ * Z-Index Sorted Children update
118
+ */
119
+ ZIndexSortedChildren = 64,
120
+
121
+ /**
122
+ * Premultiplied Colors
123
+ */
124
+ PremultipliedColors = 128,
125
+
126
+ /**
127
+ * World Alpha
128
+ *
129
+ * @remarks
130
+ * World Alpha = Parent World Alpha * Alpha
131
+ */
132
+ WorldAlpha = 256,
133
+
134
+ /**
135
+ * None
136
+ */
137
+ None = 0,
138
+
139
+ /**
140
+ * All
141
+ */
142
+ All = 511,
143
+ }
144
+
85
145
  export class CoreNode extends EventEmitter implements ICoreNode {
86
146
  readonly children: CoreNode[] = [];
87
147
  protected props: Required<CoreNodeProps>;
88
148
 
89
- public recalculationType = 0;
90
- public hasUpdates = true;
149
+ public updateType = UpdateType.All;
91
150
  public globalTransform?: Matrix3d;
92
151
  public scaleRotateTransform?: Matrix3d;
93
152
  public localTransform?: Matrix3d;
94
153
  public clippingRect: Rect | null = null;
154
+ public isRenderable = false;
95
155
  private parentClippingRect: Rect | null = null;
156
+ public worldAlpha = 1;
157
+ public premultipliedColorTl = 0;
158
+ public premultipliedColorTr = 0;
159
+ public premultipliedColorBl = 0;
160
+ public premultipliedColorBr = 0;
161
+ public calcZIndex = 0;
96
162
 
97
163
  private isComplex = false;
98
164
 
@@ -122,6 +188,7 @@ export class CoreNode extends EventEmitter implements ICoreNode {
122
188
 
123
189
  this.props.texture = texture;
124
190
  this.props.textureOptions = options;
191
+ this.checkIsRenderable();
125
192
 
126
193
  // If texture is already loaded / failed, trigger loaded event manually
127
194
  // so that users get a consistent event experience.
@@ -145,9 +212,13 @@ export class CoreNode extends EventEmitter implements ICoreNode {
145
212
  }
146
213
  this.props.texture = null;
147
214
  this.props.textureOptions = null;
215
+ this.checkIsRenderable();
148
216
  }
149
217
 
150
218
  private onTextureLoaded: TextureLoadedEventHandler = (target, dimensions) => {
219
+ // Texture was loaded. In case the RAF loop has already stopped, we request
220
+ // a render to ensure the texture is rendered.
221
+ this.stage.requestRender();
151
222
  this.emit('loaded', {
152
223
  type: 'texture',
153
224
  dimensions,
@@ -171,66 +242,41 @@ export class CoreNode extends EventEmitter implements ICoreNode {
171
242
  const { shader, props: p } = shManager.loadShader(shaderType, props);
172
243
  this.props.shader = shader;
173
244
  this.props.shaderProps = p;
174
- }
175
-
176
- setHasUpdates(): void {
177
- this.hasUpdates = true;
178
- }
179
-
180
- setChildrenHasUpdates(): void {
181
- this.children.forEach((child) => {
182
- child.setRecalculationType(2);
183
- });
184
- }
185
-
186
- setParentHasUpdates(): void {
187
- if (!this.props.parent) {
188
- return;
189
- }
190
-
191
- this.props.parent.setRecalculationType(1);
245
+ this.checkIsRenderable();
192
246
  }
193
247
 
194
248
  /**
195
249
  * Change types types is used to determine the scope of the changes being applied
196
- * 1 - alpha recalculation
197
- * 2 - translate recalculation
198
- * 4 - transform recalculation
199
- * 8 - z-index recalculation
250
+ *
251
+ * @remarks
252
+ * See {@link UpdateType} for more information on each type
200
253
  *
201
254
  * @param type
202
255
  */
203
- setRecalculationType(type: number): void {
204
- this.recalculationType |= type;
205
- this.setHasUpdates();
206
-
207
- // always forcing parent updates so the root will have an hasUpdates flag
208
- this.setParentHasUpdates();
209
-
210
- if (type & 4) {
211
- this.setChildrenHasUpdates();
256
+ setUpdateType(type: UpdateType): void {
257
+ this.updateType |= type;
258
+
259
+ // If we're updating this node at all, we need to inform the parent
260
+ // (and all ancestors) that their children need updating as well
261
+ const parent = this.props.parent;
262
+ if (parent && !(parent.updateType & UpdateType.Children)) {
263
+ parent.setUpdateType(UpdateType.Children);
212
264
  }
213
265
  }
214
266
 
215
267
  sortChildren() {
216
- this.children.sort((a, b) => a.zIndex - b.zIndex);
268
+ this.children.sort((a, b) => a.calcZIndex - b.calcZIndex);
217
269
  }
218
270
 
219
271
  updateScaleRotateTransform() {
220
- this.setRecalculationType(4);
221
-
222
272
  this.scaleRotateTransform = Matrix3d.rotate(
223
273
  this.props.rotation,
224
274
  this.scaleRotateTransform,
225
275
  ).scale(this.props.scaleX, this.props.scaleY);
226
-
227
- // do transformations when matrix is implemented
228
- this.updateLocalTransform();
229
276
  }
230
277
 
231
278
  updateLocalTransform() {
232
279
  assertTruthy(this.scaleRotateTransform);
233
- this.setRecalculationType(2);
234
280
  const pivotTranslateX = this.props.pivotX * this.props.width;
235
281
  const pivotTranslateY = this.props.pivotY * this.props.height;
236
282
  const mountTranslateX = this.props.mountX * this.props.width;
@@ -243,6 +289,7 @@ export class CoreNode extends EventEmitter implements ICoreNode {
243
289
  )
244
290
  .multiply(this.scaleRotateTransform)
245
291
  .translate(-pivotTranslateX, -pivotTranslateY);
292
+ this.setUpdateType(UpdateType.Global);
246
293
  }
247
294
 
248
295
  /**
@@ -250,45 +297,182 @@ export class CoreNode extends EventEmitter implements ICoreNode {
250
297
  * @param delta
251
298
  */
252
299
  update(delta: number, parentClippingRect: Rect | null = null): void {
253
- assertTruthy(this.localTransform);
254
- const parentGlobalTransform = this.parent?.globalTransform;
255
- if (parentGlobalTransform) {
256
- this.globalTransform = Matrix3d.copy(
257
- parentGlobalTransform,
258
- this.globalTransform,
259
- ).multiply(this.localTransform);
260
- } else {
300
+ if (this.updateType & UpdateType.ScaleRotate) {
301
+ this.updateScaleRotateTransform();
302
+ this.setUpdateType(UpdateType.Local);
303
+ }
304
+
305
+ if (this.updateType & UpdateType.Local) {
306
+ this.updateLocalTransform();
307
+ this.setUpdateType(UpdateType.Global);
308
+ }
309
+
310
+ const parent = this.props.parent;
311
+ let childUpdateType = UpdateType.None;
312
+ if (this.updateType & UpdateType.Global) {
313
+ assertTruthy(this.localTransform);
261
314
  this.globalTransform = Matrix3d.copy(
262
- this.localTransform,
315
+ parent?.globalTransform || this.localTransform,
263
316
  this.globalTransform,
264
317
  );
318
+
319
+ if (parent) {
320
+ this.globalTransform.multiply(this.localTransform);
321
+ }
322
+
323
+ this.setUpdateType(UpdateType.Clipping | UpdateType.Children);
324
+ childUpdateType |= UpdateType.Global;
325
+ }
326
+
327
+ if (this.updateType & UpdateType.Clipping) {
328
+ this.calculateClippingRect(parentClippingRect);
329
+ this.checkIsRenderable();
330
+ this.setUpdateType(UpdateType.Children);
331
+ childUpdateType |= UpdateType.Clipping;
332
+ }
333
+
334
+ if (this.updateType & UpdateType.WorldAlpha) {
335
+ if (parent) {
336
+ this.worldAlpha = parent.worldAlpha * this.props.alpha;
337
+ } else {
338
+ this.worldAlpha = this.props.alpha;
339
+ }
340
+ this.setUpdateType(UpdateType.Children | UpdateType.PremultipliedColors);
341
+ childUpdateType |= UpdateType.WorldAlpha;
342
+ }
343
+
344
+ if (this.updateType & UpdateType.PremultipliedColors) {
345
+ this.premultipliedColorTl = mergeColorAlphaPremultiplied(
346
+ this.props.colorTl,
347
+ this.worldAlpha,
348
+ true,
349
+ );
350
+
351
+ // If all the colors are the same just sent them all to the same value
352
+ if (
353
+ this.props.colorTl === this.props.colorTr &&
354
+ this.props.colorBl === this.props.colorBr &&
355
+ this.props.colorTl === this.props.colorBl
356
+ ) {
357
+ this.premultipliedColorTr =
358
+ this.premultipliedColorBl =
359
+ this.premultipliedColorBr =
360
+ this.premultipliedColorTl;
361
+ } else {
362
+ this.premultipliedColorTr = mergeColorAlphaPremultiplied(
363
+ this.props.colorTr,
364
+ this.worldAlpha,
365
+ true,
366
+ );
367
+ this.premultipliedColorBl = mergeColorAlphaPremultiplied(
368
+ this.props.colorBl,
369
+ this.worldAlpha,
370
+ true,
371
+ );
372
+ this.premultipliedColorBr = mergeColorAlphaPremultiplied(
373
+ this.props.colorBr,
374
+ this.worldAlpha,
375
+ true,
376
+ );
377
+ }
378
+ this.checkIsRenderable();
379
+ this.setUpdateType(UpdateType.Children);
380
+ childUpdateType |= UpdateType.PremultipliedColors;
265
381
  }
266
382
 
267
- this.calculateClippingRect(parentClippingRect);
383
+ // No need to update zIndex if there is no parent
384
+ if (parent && this.updateType & UpdateType.CalculatedZIndex) {
385
+ this.calculateZIndex();
386
+ // Tell parent to re-sort children
387
+ parent.setUpdateType(UpdateType.ZIndexSortedChildren);
388
+ }
268
389
 
269
- if (this.children.length) {
390
+ if (this.updateType & UpdateType.Children && this.children.length) {
270
391
  this.children.forEach((child) => {
392
+ // Trigger the depenedent update types on the child
393
+ child.setUpdateType(childUpdateType);
394
+ // If child has no updates, skip
395
+ if (child.updateType === 0) {
396
+ return;
397
+ }
271
398
  child.update(delta, this.clippingRect);
272
399
  });
273
400
  }
274
401
 
275
- if (this.recalculationType & 8) {
402
+ // Sorting children MUST happen after children have been updated so
403
+ // that they have the oppotunity to update their calculated zIndex.
404
+ if (this.updateType & UpdateType.ZIndexSortedChildren) {
276
405
  // reorder z-index
277
406
  this.sortChildren();
278
407
  }
279
408
 
280
- // reset update flag
281
- this.hasUpdates = false;
409
+ // reset update type
410
+ this.updateType = 0;
411
+ }
412
+
413
+ // This function checks if the current node is renderable based on certain properties.
414
+ // It returns true if any of the specified properties are truthy or if any color property is not 0, otherwise it returns false.
415
+ checkIsRenderable(): boolean {
416
+ if (this.props.texture) {
417
+ return (this.isRenderable = true);
418
+ }
419
+
420
+ if (!this.props.width || !this.props.height) {
421
+ return (this.isRenderable = false);
422
+ }
282
423
 
283
- // reset recalculation type
284
- this.recalculationType = 0;
424
+ if (this.props.shader) {
425
+ return (this.isRenderable = true);
426
+ }
427
+
428
+ if (this.props.clipping) {
429
+ return (this.isRenderable = true);
430
+ }
431
+
432
+ if (this.props.color !== 0) {
433
+ return (this.isRenderable = true);
434
+ }
435
+
436
+ // Consider removing these checks and just using the color property check above.
437
+ // Maybe add a forceRender prop for nodes that should always render.
438
+ if (this.props.colorTop !== 0) {
439
+ return (this.isRenderable = true);
440
+ }
441
+
442
+ if (this.props.colorBottom !== 0) {
443
+ return (this.isRenderable = true);
444
+ }
445
+
446
+ if (this.props.colorLeft !== 0) {
447
+ return (this.isRenderable = true);
448
+ }
449
+
450
+ if (this.props.colorRight !== 0) {
451
+ return (this.isRenderable = true);
452
+ }
453
+
454
+ if (this.props.colorTl !== 0) {
455
+ return (this.isRenderable = true);
456
+ }
457
+
458
+ if (this.props.colorTr !== 0) {
459
+ return (this.isRenderable = true);
460
+ }
461
+
462
+ if (this.props.colorBl !== 0) {
463
+ return (this.isRenderable = true);
464
+ }
465
+
466
+ if (this.props.colorBr !== 0) {
467
+ return (this.isRenderable = true);
468
+ }
469
+
470
+ return (this.isRenderable = false);
285
471
  }
286
472
 
287
473
  /**
288
474
  * This function calculates the clipping rectangle for a node.
289
475
  *
290
- * If the node's globalTransform is not set, the function returns immediately.
291
- * If the node's props do not require clipping and there is no parent clipping rectangle, the node's clipping rectangle is set to null.
292
476
  * If the parent clipping rectangle has not changed and the node's clipping rectangle is already set, the function returns immediately.
293
477
  *
294
478
  * The function then checks if the node is rotated. If the node requires clipping and is not rotated, a new clipping rectangle is created based on the node's global transform and dimensions.
@@ -297,14 +481,7 @@ export class CoreNode extends EventEmitter implements ICoreNode {
297
481
  * Finally, the node's parentClippingRect and clippingRect properties are updated.
298
482
  */
299
483
  calculateClippingRect(parentClippingRect: Rect | null = null) {
300
- if (!this.globalTransform) {
301
- return;
302
- }
303
-
304
- if (!this.props.clipping && !parentClippingRect) {
305
- this.clippingRect = null;
306
- return;
307
- }
484
+ assertTruthy(this.globalTransform);
308
485
 
309
486
  if (this.parentClippingRect === parentClippingRect && this.clippingRect) {
310
487
  return;
@@ -332,19 +509,28 @@ export class CoreNode extends EventEmitter implements ICoreNode {
332
509
  this.clippingRect = clippingRect;
333
510
  }
334
511
 
512
+ calculateZIndex(): void {
513
+ const props = this.props;
514
+ const z = props.zIndex || 0;
515
+ const p = props.parent?.zIndex || 0;
516
+
517
+ let zIndex = z;
518
+ if (props.parent?.zIndexLocked) {
519
+ zIndex = z < p ? z : p;
520
+ }
521
+ this.calcZIndex = zIndex;
522
+ }
523
+
335
524
  renderQuads(renderer: CoreRenderer): void {
525
+ const { width, height, texture, textureOptions, shader, shaderProps } =
526
+ this.props;
336
527
  const {
337
- width,
338
- height,
339
- colorTl,
340
- colorTr,
341
- colorBl,
342
- colorBr,
343
- texture,
344
- textureOptions,
345
- shader,
346
- shaderProps,
347
- } = this.props;
528
+ premultipliedColorTl,
529
+ premultipliedColorTr,
530
+ premultipliedColorBl,
531
+ premultipliedColorBr,
532
+ } = this;
533
+
348
534
  const { zIndex, worldAlpha, globalTransform: gt, clippingRect } = this;
349
535
 
350
536
  assertTruthy(gt);
@@ -353,10 +539,10 @@ export class CoreNode extends EventEmitter implements ICoreNode {
353
539
  renderer.addQuad({
354
540
  width,
355
541
  height,
356
- colorTl,
357
- colorTr,
358
- colorBl,
359
- colorBr,
542
+ colorTl: premultipliedColorTl,
543
+ colorTr: premultipliedColorTr,
544
+ colorBl: premultipliedColorBl,
545
+ colorBr: premultipliedColorBr,
360
546
  texture,
361
547
  textureOptions,
362
548
  zIndex,
@@ -388,7 +574,7 @@ export class CoreNode extends EventEmitter implements ICoreNode {
388
574
  set x(value: number) {
389
575
  if (this.props.x !== value) {
390
576
  this.props.x = value;
391
- this.updateLocalTransform();
577
+ this.setUpdateType(UpdateType.Local);
392
578
  }
393
579
  }
394
580
 
@@ -410,7 +596,7 @@ export class CoreNode extends EventEmitter implements ICoreNode {
410
596
  set y(value: number) {
411
597
  if (this.props.y !== value) {
412
598
  this.props.y = value;
413
- this.updateLocalTransform();
599
+ this.setUpdateType(UpdateType.Local);
414
600
  }
415
601
  }
416
602
 
@@ -421,7 +607,7 @@ export class CoreNode extends EventEmitter implements ICoreNode {
421
607
  set width(value: number) {
422
608
  if (this.props.width !== value) {
423
609
  this.props.width = value;
424
- this.updateLocalTransform();
610
+ this.setUpdateType(UpdateType.Local);
425
611
  }
426
612
  }
427
613
 
@@ -432,7 +618,7 @@ export class CoreNode extends EventEmitter implements ICoreNode {
432
618
  set height(value: number) {
433
619
  if (this.props.height !== value) {
434
620
  this.props.height = value;
435
- this.updateLocalTransform();
621
+ this.setUpdateType(UpdateType.Local);
436
622
  }
437
623
  }
438
624
 
@@ -456,7 +642,7 @@ export class CoreNode extends EventEmitter implements ICoreNode {
456
642
  set scaleX(value: number) {
457
643
  if (this.props.scaleX !== value) {
458
644
  this.props.scaleX = value;
459
- this.updateScaleRotateTransform();
645
+ this.setUpdateType(UpdateType.ScaleRotate);
460
646
  }
461
647
  }
462
648
 
@@ -467,35 +653,21 @@ export class CoreNode extends EventEmitter implements ICoreNode {
467
653
  set scaleY(value: number) {
468
654
  if (this.props.scaleY !== value) {
469
655
  this.props.scaleY = value;
470
- this.updateScaleRotateTransform();
656
+ this.setUpdateType(UpdateType.ScaleRotate);
471
657
  }
472
658
  }
473
659
 
474
- get worldScaleX(): number {
475
- return (
476
- this.props.scaleX * (this.props.parent?.worldScaleX ?? 1) ||
477
- this.props.scaleX
478
- );
479
- }
480
-
481
- get worldScaleY(): number {
482
- return (
483
- this.props.scaleY * (this.props.parent?.worldScaleY ?? 1) ||
484
- this.props.scaleY
485
- );
486
- }
487
-
488
660
  get mount(): number {
489
661
  return this.props.mount;
490
662
  }
491
663
 
492
664
  set mount(value: number) {
493
- // if (this.props.mountX !== value || this.props.mountY !== value) {
494
- this.props.mountX = value;
495
- this.props.mountY = value;
496
- this.props.mount = value;
497
- this.updateLocalTransform();
498
- // }
665
+ if (this.props.mountX !== value || this.props.mountY !== value) {
666
+ this.props.mountX = value;
667
+ this.props.mountY = value;
668
+ this.props.mount = value;
669
+ this.setUpdateType(UpdateType.Local);
670
+ }
499
671
  }
500
672
 
501
673
  get mountX(): number {
@@ -503,8 +675,10 @@ export class CoreNode extends EventEmitter implements ICoreNode {
503
675
  }
504
676
 
505
677
  set mountX(value: number) {
506
- this.props.mountX = value;
507
- this.updateLocalTransform();
678
+ if (this.props.mountX !== value) {
679
+ this.props.mountX = value;
680
+ this.setUpdateType(UpdateType.Local);
681
+ }
508
682
  }
509
683
 
510
684
  get mountY(): number {
@@ -512,8 +686,10 @@ export class CoreNode extends EventEmitter implements ICoreNode {
512
686
  }
513
687
 
514
688
  set mountY(value: number) {
515
- this.props.mountY = value;
516
- this.updateLocalTransform();
689
+ if (this.props.mountY !== value) {
690
+ this.props.mountY = value;
691
+ this.setUpdateType(UpdateType.Local);
692
+ }
517
693
  }
518
694
 
519
695
  get pivot(): number {
@@ -524,7 +700,8 @@ export class CoreNode extends EventEmitter implements ICoreNode {
524
700
  if (this.props.pivotX !== value || this.props.pivotY !== value) {
525
701
  this.props.pivotX = value;
526
702
  this.props.pivotY = value;
527
- this.updateLocalTransform();
703
+ this.props.pivot = value;
704
+ this.setUpdateType(UpdateType.Local);
528
705
  }
529
706
  }
530
707
 
@@ -533,8 +710,10 @@ export class CoreNode extends EventEmitter implements ICoreNode {
533
710
  }
534
711
 
535
712
  set pivotX(value: number) {
536
- this.props.pivotX = value;
537
- this.updateLocalTransform();
713
+ if (this.props.pivotX !== value) {
714
+ this.props.pivotX = value;
715
+ this.setUpdateType(UpdateType.Local);
716
+ }
538
717
  }
539
718
 
540
719
  get pivotY(): number {
@@ -542,8 +721,10 @@ export class CoreNode extends EventEmitter implements ICoreNode {
542
721
  }
543
722
 
544
723
  set pivotY(value: number) {
545
- this.props.pivotY = value;
546
- this.updateLocalTransform();
724
+ if (this.props.pivotY !== value) {
725
+ this.props.pivotY = value;
726
+ this.setUpdateType(UpdateType.Local);
727
+ }
547
728
  }
548
729
 
549
730
  get rotation(): number {
@@ -553,7 +734,7 @@ export class CoreNode extends EventEmitter implements ICoreNode {
553
734
  set rotation(value: number) {
554
735
  if (this.props.rotation !== value) {
555
736
  this.props.rotation = value;
556
- this.updateScaleRotateTransform();
737
+ this.setUpdateType(UpdateType.ScaleRotate);
557
738
  }
558
739
  }
559
740
 
@@ -563,14 +744,7 @@ export class CoreNode extends EventEmitter implements ICoreNode {
563
744
 
564
745
  set alpha(value: number) {
565
746
  this.props.alpha = value;
566
- this.setRecalculationType(1);
567
- }
568
-
569
- get worldAlpha(): number {
570
- const props = this.props;
571
- const parent = props.parent;
572
-
573
- return props.alpha * (parent?.worldAlpha || 1);
747
+ this.setUpdateType(UpdateType.PremultipliedColors | UpdateType.WorldAlpha);
574
748
  }
575
749
 
576
750
  get clipping(): boolean {
@@ -579,8 +753,7 @@ export class CoreNode extends EventEmitter implements ICoreNode {
579
753
 
580
754
  set clipping(value: boolean) {
581
755
  this.props.clipping = value;
582
- this.clippingRect = null;
583
- this.setRecalculationType(4);
756
+ this.setUpdateType(UpdateType.Clipping);
584
757
  }
585
758
 
586
759
  get color(): number {
@@ -601,7 +774,7 @@ export class CoreNode extends EventEmitter implements ICoreNode {
601
774
  }
602
775
  this.props.color = value;
603
776
 
604
- this.setRecalculationType(2);
777
+ this.setUpdateType(UpdateType.PremultipliedColors);
605
778
  }
606
779
 
607
780
  get colorTop(): number {
@@ -614,7 +787,7 @@ export class CoreNode extends EventEmitter implements ICoreNode {
614
787
  this.colorTr = value;
615
788
  }
616
789
  this.props.colorTop = value;
617
- this.setRecalculationType(2);
790
+ this.setUpdateType(UpdateType.PremultipliedColors);
618
791
  }
619
792
 
620
793
  get colorBottom(): number {
@@ -627,7 +800,7 @@ export class CoreNode extends EventEmitter implements ICoreNode {
627
800
  this.colorBr = value;
628
801
  }
629
802
  this.props.colorBottom = value;
630
- this.setRecalculationType(2);
803
+ this.setUpdateType(UpdateType.PremultipliedColors);
631
804
  }
632
805
 
633
806
  get colorLeft(): number {
@@ -640,7 +813,7 @@ export class CoreNode extends EventEmitter implements ICoreNode {
640
813
  this.colorBl = value;
641
814
  }
642
815
  this.props.colorLeft = value;
643
- this.setRecalculationType(2);
816
+ this.setUpdateType(UpdateType.PremultipliedColors);
644
817
  }
645
818
 
646
819
  get colorRight(): number {
@@ -653,7 +826,7 @@ export class CoreNode extends EventEmitter implements ICoreNode {
653
826
  this.colorBr = value;
654
827
  }
655
828
  this.props.colorRight = value;
656
- this.setRecalculationType(2);
829
+ this.setUpdateType(UpdateType.PremultipliedColors);
657
830
  }
658
831
 
659
832
  get colorTl(): number {
@@ -662,7 +835,7 @@ export class CoreNode extends EventEmitter implements ICoreNode {
662
835
 
663
836
  set colorTl(value: number) {
664
837
  this.props.colorTl = value;
665
- this.setRecalculationType(2);
838
+ this.setUpdateType(UpdateType.PremultipliedColors);
666
839
  }
667
840
 
668
841
  get colorTr(): number {
@@ -671,7 +844,7 @@ export class CoreNode extends EventEmitter implements ICoreNode {
671
844
 
672
845
  set colorTr(value: number) {
673
846
  this.props.colorTr = value;
674
- this.setRecalculationType(2);
847
+ this.setUpdateType(UpdateType.PremultipliedColors);
675
848
  }
676
849
 
677
850
  get colorBl(): number {
@@ -680,7 +853,7 @@ export class CoreNode extends EventEmitter implements ICoreNode {
680
853
 
681
854
  set colorBl(value: number) {
682
855
  this.props.colorBl = value;
683
- this.setRecalculationType(2);
856
+ this.setUpdateType(UpdateType.PremultipliedColors);
684
857
  }
685
858
 
686
859
  get colorBr(): number {
@@ -689,7 +862,7 @@ export class CoreNode extends EventEmitter implements ICoreNode {
689
862
 
690
863
  set colorBr(value: number) {
691
864
  this.props.colorBr = value;
692
- this.setRecalculationType(2);
865
+ this.setUpdateType(UpdateType.PremultipliedColors);
693
866
  }
694
867
 
695
868
  // we're only interested in parent zIndex to test
@@ -700,22 +873,22 @@ export class CoreNode extends EventEmitter implements ICoreNode {
700
873
 
701
874
  set zIndexLocked(value: number) {
702
875
  this.props.zIndexLocked = value;
876
+ this.setUpdateType(UpdateType.CalculatedZIndex | UpdateType.Children);
877
+ this.children.forEach((child) => {
878
+ child.setUpdateType(UpdateType.CalculatedZIndex);
879
+ });
703
880
  }
704
881
 
705
882
  get zIndex(): number {
706
- const props = this.props;
707
- const z = props.zIndex || 0;
708
- const p = props.parent?.zIndex || 0;
709
-
710
- if (props.parent?.zIndexLocked) {
711
- return z < p ? z : p;
712
- }
713
- return z;
883
+ return this.props.zIndex;
714
884
  }
715
885
 
716
886
  set zIndex(value: number) {
717
887
  this.props.zIndex = value;
718
- this.props.parent?.setRecalculationType(8);
888
+ this.setUpdateType(UpdateType.CalculatedZIndex | UpdateType.Children);
889
+ this.children.forEach((child) => {
890
+ child.setUpdateType(UpdateType.CalculatedZIndex);
891
+ });
719
892
  }
720
893
 
721
894
  get parent(): CoreNode | null {
@@ -738,8 +911,12 @@ export class CoreNode extends EventEmitter implements ICoreNode {
738
911
  }
739
912
  if (newParent) {
740
913
  newParent.children.push(this);
741
- // force parent to recalculate z-index for its children
742
- newParent.setRecalculationType(8);
914
+ // Since this node has a new parent, to be safe, have it do a full update.
915
+ this.setUpdateType(UpdateType.All);
916
+ // Tell parent that it's children need to be updated and sorted.
917
+ newParent.setUpdateType(
918
+ UpdateType.Children | UpdateType.ZIndexSortedChildren,
919
+ );
743
920
  }
744
921
 
745
922
  this.updateScaleRotateTransform();