@lightningjs/renderer 0.6.0 → 0.6.1

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 (40) hide show
  1. package/README.md +1 -1
  2. package/dist/src/core/CoreNode.d.ts +63 -15
  3. package/dist/src/core/CoreNode.js +238 -118
  4. package/dist/src/core/CoreNode.js.map +1 -1
  5. package/dist/src/core/CoreTextNode.d.ts +1 -0
  6. package/dist/src/core/CoreTextNode.js +13 -0
  7. package/dist/src/core/CoreTextNode.js.map +1 -1
  8. package/dist/src/core/Stage.d.ts +6 -2
  9. package/dist/src/core/Stage.js +24 -21
  10. package/dist/src/core/Stage.js.map +1 -1
  11. package/dist/src/core/animations/CoreAnimation.js +11 -2
  12. package/dist/src/core/animations/CoreAnimation.js.map +1 -1
  13. package/dist/src/core/lib/ContextSpy.d.ts +12 -0
  14. package/dist/src/core/lib/ContextSpy.js +38 -0
  15. package/dist/src/core/lib/ContextSpy.js.map +1 -0
  16. package/dist/src/core/lib/WebGlContext.d.ts +414 -0
  17. package/dist/src/core/lib/WebGlContext.js +640 -0
  18. package/dist/src/core/lib/WebGlContext.js.map +1 -0
  19. package/dist/src/core/lib/WebGlContextWrapper.d.ts +496 -0
  20. package/dist/src/core/lib/WebGlContextWrapper.js +779 -0
  21. package/dist/src/core/lib/WebGlContextWrapper.js.map +1 -0
  22. package/dist/src/core/platform.js +4 -0
  23. package/dist/src/core/platform.js.map +1 -1
  24. package/dist/src/core/renderers/webgl/WebGlCoreRenderer.js +9 -8
  25. package/dist/src/core/renderers/webgl/WebGlCoreRenderer.js.map +1 -1
  26. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.js +4 -5
  27. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.js.map +1 -1
  28. package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.js +15 -13
  29. package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.js.map +1 -1
  30. package/dist/tsconfig.dist.tsbuildinfo +1 -1
  31. package/package.json +1 -1
  32. package/src/core/CoreNode.ts +293 -149
  33. package/src/core/CoreTextNode.ts +16 -0
  34. package/src/core/Stage.ts +28 -31
  35. package/src/core/animations/CoreAnimation.ts +11 -2
  36. package/src/core/platform.ts +5 -0
  37. package/src/core/renderers/webgl/WebGlCoreRenderer.ts +9 -40
  38. package/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.ts +4 -5
  39. package/src/core/text-rendering/renderers/CanvasTextRenderer.ts +19 -15
  40. package/src/core/scene/Scene.ts +0 -120
@@ -16,21 +16,77 @@
16
16
  * See the License for the specific language governing permissions and
17
17
  * limitations under the License.
18
18
  */
19
- import { assertTruthy } from '../utils.js';
19
+ import { assertTruthy, mergeColorAlphaPremultiplied } from '../utils.js';
20
20
  import { EventEmitter } from '../common/EventEmitter.js';
21
- import { intersectRect } from './lib/utils.js';
21
+ import { getNormalizedAlphaComponent, intersectRect, } from './lib/utils.js';
22
22
  import { Matrix3d } from './lib/Matrix3d.js';
23
+ var UpdateType;
24
+ (function (UpdateType) {
25
+ /**
26
+ * Child updates
27
+ */
28
+ UpdateType[UpdateType["Children"] = 1] = "Children";
29
+ /**
30
+ * Scale/Rotate transform update
31
+ */
32
+ UpdateType[UpdateType["ScaleRotate"] = 2] = "ScaleRotate";
33
+ /**
34
+ * Translate transform update (x/y/width/height/pivot/mount)
35
+ */
36
+ UpdateType[UpdateType["Local"] = 4] = "Local";
37
+ /**
38
+ * Global transform update
39
+ */
40
+ UpdateType[UpdateType["Global"] = 8] = "Global";
41
+ /**
42
+ * Clipping rect update
43
+ */
44
+ UpdateType[UpdateType["Clipping"] = 16] = "Clipping";
45
+ /**
46
+ * Calculated ZIndex update
47
+ */
48
+ UpdateType[UpdateType["CalculatedZIndex"] = 32] = "CalculatedZIndex";
49
+ /**
50
+ * Z-Index Sorted Children update
51
+ */
52
+ UpdateType[UpdateType["ZIndexSortedChildren"] = 64] = "ZIndexSortedChildren";
53
+ /**
54
+ * Premultiplied Colors
55
+ */
56
+ UpdateType[UpdateType["PremultipliedColors"] = 128] = "PremultipliedColors";
57
+ /**
58
+ * World Alpha
59
+ *
60
+ * @remarks
61
+ * World Alpha = Parent World Alpha * Alpha
62
+ */
63
+ UpdateType[UpdateType["WorldAlpha"] = 256] = "WorldAlpha";
64
+ /**
65
+ * None
66
+ */
67
+ UpdateType[UpdateType["None"] = 0] = "None";
68
+ /**
69
+ * All
70
+ */
71
+ UpdateType[UpdateType["All"] = 511] = "All";
72
+ })(UpdateType || (UpdateType = {}));
23
73
  export class CoreNode extends EventEmitter {
24
74
  stage;
25
75
  children = [];
26
76
  props;
27
- recalculationType = 0;
28
- hasUpdates = true;
77
+ updateType = UpdateType.All;
29
78
  globalTransform;
30
79
  scaleRotateTransform;
31
80
  localTransform;
32
81
  clippingRect = null;
82
+ isRenderable = false;
33
83
  parentClippingRect = null;
84
+ worldAlpha = 1;
85
+ premultipliedColorTl = 0;
86
+ premultipliedColorTr = 0;
87
+ premultipliedColorBl = 0;
88
+ premultipliedColorBr = 0;
89
+ calcZIndex = 0;
34
90
  isComplex = false;
35
91
  constructor(stage, props) {
36
92
  super();
@@ -53,6 +109,7 @@ export class CoreNode extends EventEmitter {
53
109
  const texture = txManager.loadTexture(textureType, props, options);
54
110
  this.props.texture = texture;
55
111
  this.props.textureOptions = options;
112
+ this.checkIsRenderable();
56
113
  // If texture is already loaded / failed, trigger loaded event manually
57
114
  // so that users get a consistent event experience.
58
115
  // We do this in a microtask to allow listeners to be attached in the same
@@ -75,8 +132,12 @@ export class CoreNode extends EventEmitter {
75
132
  }
76
133
  this.props.texture = null;
77
134
  this.props.textureOptions = null;
135
+ this.checkIsRenderable();
78
136
  }
79
137
  onTextureLoaded = (target, dimensions) => {
138
+ // Texture was loaded. In case the RAF loop has already stopped, we request
139
+ // a render to ensure the texture is rendered.
140
+ this.stage.requestRender();
80
141
  this.emit('loaded', {
81
142
  type: 'texture',
82
143
  dimensions,
@@ -95,51 +156,33 @@ export class CoreNode extends EventEmitter {
95
156
  const { shader, props: p } = shManager.loadShader(shaderType, props);
96
157
  this.props.shader = shader;
97
158
  this.props.shaderProps = p;
98
- }
99
- setHasUpdates() {
100
- this.hasUpdates = true;
101
- }
102
- setChildrenHasUpdates() {
103
- this.children.forEach((child) => {
104
- child.setRecalculationType(2);
105
- });
106
- }
107
- setParentHasUpdates() {
108
- if (!this.props.parent) {
109
- return;
110
- }
111
- this.props.parent.setRecalculationType(1);
159
+ this.checkIsRenderable();
112
160
  }
113
161
  /**
114
162
  * Change types types is used to determine the scope of the changes being applied
115
- * 1 - alpha recalculation
116
- * 2 - translate recalculation
117
- * 4 - transform recalculation
118
- * 8 - z-index recalculation
163
+ *
164
+ * @remarks
165
+ * See {@link UpdateType} for more information on each type
119
166
  *
120
167
  * @param type
121
168
  */
122
- setRecalculationType(type) {
123
- this.recalculationType |= type;
124
- this.setHasUpdates();
125
- // always forcing parent updates so the root will have an hasUpdates flag
126
- this.setParentHasUpdates();
127
- if (type & 4) {
128
- this.setChildrenHasUpdates();
169
+ setUpdateType(type) {
170
+ this.updateType |= type;
171
+ // If we're updating this node at all, we need to inform the parent
172
+ // (and all ancestors) that their children need updating as well
173
+ const parent = this.props.parent;
174
+ if (parent && !(parent.updateType & UpdateType.Children)) {
175
+ parent.setUpdateType(UpdateType.Children);
129
176
  }
130
177
  }
131
178
  sortChildren() {
132
- this.children.sort((a, b) => a.zIndex - b.zIndex);
179
+ this.children.sort((a, b) => a.calcZIndex - b.calcZIndex);
133
180
  }
134
181
  updateScaleRotateTransform() {
135
- this.setRecalculationType(4);
136
182
  this.scaleRotateTransform = Matrix3d.rotate(this.props.rotation, this.scaleRotateTransform).scale(this.props.scaleX, this.props.scaleY);
137
- // do transformations when matrix is implemented
138
- this.updateLocalTransform();
139
183
  }
140
184
  updateLocalTransform() {
141
185
  assertTruthy(this.scaleRotateTransform);
142
- this.setRecalculationType(2);
143
186
  const pivotTranslateX = this.props.pivotX * this.props.width;
144
187
  const pivotTranslateY = this.props.pivotY * this.props.height;
145
188
  const mountTranslateX = this.props.mountX * this.props.width;
@@ -147,40 +190,114 @@ export class CoreNode extends EventEmitter {
147
190
  this.localTransform = Matrix3d.translate(pivotTranslateX - mountTranslateX + this.props.x, pivotTranslateY - mountTranslateY + this.props.y, this.localTransform)
148
191
  .multiply(this.scaleRotateTransform)
149
192
  .translate(-pivotTranslateX, -pivotTranslateY);
193
+ this.setUpdateType(UpdateType.Global);
150
194
  }
151
195
  /**
152
196
  * @todo: test for correct calculation flag
153
197
  * @param delta
154
198
  */
155
199
  update(delta, parentClippingRect = null) {
156
- assertTruthy(this.localTransform);
157
- const parentGlobalTransform = this.parent?.globalTransform;
158
- if (parentGlobalTransform) {
159
- this.globalTransform = Matrix3d.copy(parentGlobalTransform, this.globalTransform).multiply(this.localTransform);
200
+ if (this.updateType & UpdateType.ScaleRotate) {
201
+ this.updateScaleRotateTransform();
202
+ this.setUpdateType(UpdateType.Local);
160
203
  }
161
- else {
162
- this.globalTransform = Matrix3d.copy(this.localTransform, this.globalTransform);
204
+ if (this.updateType & UpdateType.Local) {
205
+ this.updateLocalTransform();
206
+ this.setUpdateType(UpdateType.Global);
163
207
  }
164
- this.calculateClippingRect(parentClippingRect);
165
- if (this.children.length) {
208
+ const parent = this.props.parent;
209
+ let childUpdateType = UpdateType.None;
210
+ if (this.updateType & UpdateType.Global) {
211
+ assertTruthy(this.localTransform);
212
+ this.globalTransform = Matrix3d.copy(parent?.globalTransform || this.localTransform, this.globalTransform);
213
+ if (parent) {
214
+ this.globalTransform.multiply(this.localTransform);
215
+ }
216
+ this.setUpdateType(UpdateType.Clipping | UpdateType.Children);
217
+ childUpdateType |= UpdateType.Global;
218
+ }
219
+ if (this.updateType & UpdateType.Clipping) {
220
+ this.calculateClippingRect(parentClippingRect);
221
+ this.checkIsRenderable();
222
+ this.setUpdateType(UpdateType.Children);
223
+ childUpdateType |= UpdateType.Clipping;
224
+ }
225
+ if (this.updateType & UpdateType.WorldAlpha) {
226
+ if (parent) {
227
+ this.worldAlpha = parent.worldAlpha * this.props.alpha;
228
+ }
229
+ else {
230
+ this.worldAlpha = this.props.alpha;
231
+ }
232
+ this.setUpdateType(UpdateType.Children | UpdateType.PremultipliedColors);
233
+ childUpdateType |= UpdateType.WorldAlpha;
234
+ }
235
+ if (this.updateType & UpdateType.PremultipliedColors) {
236
+ this.premultipliedColorTl = mergeColorAlphaPremultiplied(this.props.colorTl, this.worldAlpha, true);
237
+ this.premultipliedColorTr = mergeColorAlphaPremultiplied(this.props.colorTr, this.worldAlpha, true);
238
+ this.premultipliedColorBl = mergeColorAlphaPremultiplied(this.props.colorBl, this.worldAlpha, true);
239
+ this.premultipliedColorBr = mergeColorAlphaPremultiplied(this.props.colorBr, this.worldAlpha, true);
240
+ this.checkIsRenderable();
241
+ this.setUpdateType(UpdateType.Children);
242
+ childUpdateType |= UpdateType.PremultipliedColors;
243
+ }
244
+ // No need to update zIndex if there is no parent
245
+ if (parent && this.updateType & UpdateType.CalculatedZIndex) {
246
+ this.calculateZIndex();
247
+ // Tell parent to re-sort children
248
+ parent.setUpdateType(UpdateType.ZIndexSortedChildren);
249
+ }
250
+ if (this.updateType & UpdateType.Children && this.children.length) {
166
251
  this.children.forEach((child) => {
252
+ // Trigger the depenedent update types on the child
253
+ child.setUpdateType(childUpdateType);
254
+ // If child has no updates, skip
255
+ if (child.updateType === 0) {
256
+ return;
257
+ }
167
258
  child.update(delta, this.clippingRect);
168
259
  });
169
260
  }
170
- if (this.recalculationType & 8) {
261
+ // Sorting children MUST happen after children have been updated so
262
+ // that they have the oppotunity to update their calculated zIndex.
263
+ if (this.updateType & UpdateType.ZIndexSortedChildren) {
171
264
  // reorder z-index
172
265
  this.sortChildren();
173
266
  }
174
- // reset update flag
175
- this.hasUpdates = false;
176
- // reset recalculation type
177
- this.recalculationType = 0;
267
+ // reset update type
268
+ this.updateType = 0;
269
+ }
270
+ // This function checks if the current node is renderable based on certain properties.
271
+ // It returns true if any of the specified properties are truthy or if any color property is not 0, otherwise it returns false.
272
+ checkIsRenderable() {
273
+ if (this.props.texture) {
274
+ return (this.isRenderable = true);
275
+ }
276
+ if (this.props.shader) {
277
+ return (this.isRenderable = true);
278
+ }
279
+ if (this.props.clipping) {
280
+ return (this.isRenderable = true);
281
+ }
282
+ const colors = [
283
+ 'color',
284
+ 'colorTop',
285
+ 'colorBottom',
286
+ 'colorLeft',
287
+ 'colorRight',
288
+ 'colorTl',
289
+ 'colorTr',
290
+ 'colorBl',
291
+ 'colorBr',
292
+ ];
293
+ if (colors.some((color) => this.props[color] !== 0)) {
294
+ return (this.isRenderable = true);
295
+ }
296
+ return (this.isRenderable = false);
178
297
  }
179
298
  /**
180
299
  * This function calculates the clipping rectangle for a node.
181
300
  *
182
- * If the node's globalTransform is not set, the function returns immediately.
183
- * 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.
184
301
  * If the parent clipping rectangle has not changed and the node's clipping rectangle is already set, the function returns immediately.
185
302
  *
186
303
  * 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.
@@ -189,13 +306,7 @@ export class CoreNode extends EventEmitter {
189
306
  * Finally, the node's parentClippingRect and clippingRect properties are updated.
190
307
  */
191
308
  calculateClippingRect(parentClippingRect = null) {
192
- if (!this.globalTransform) {
193
- return;
194
- }
195
- if (!this.props.clipping && !parentClippingRect) {
196
- this.clippingRect = null;
197
- return;
198
- }
309
+ assertTruthy(this.globalTransform);
199
310
  if (this.parentClippingRect === parentClippingRect && this.clippingRect) {
200
311
  return;
201
312
  }
@@ -218,18 +329,29 @@ export class CoreNode extends EventEmitter {
218
329
  this.parentClippingRect = parentClippingRect;
219
330
  this.clippingRect = clippingRect;
220
331
  }
332
+ calculateZIndex() {
333
+ const props = this.props;
334
+ const z = props.zIndex || 0;
335
+ const p = props.parent?.zIndex || 0;
336
+ let zIndex = z;
337
+ if (props.parent?.zIndexLocked) {
338
+ zIndex = z < p ? z : p;
339
+ }
340
+ this.calcZIndex = zIndex;
341
+ }
221
342
  renderQuads(renderer) {
222
- const { width, height, colorTl, colorTr, colorBl, colorBr, texture, textureOptions, shader, shaderProps, } = this.props;
343
+ const { width, height, texture, textureOptions, shader, shaderProps } = this.props;
344
+ const { premultipliedColorTl, premultipliedColorTr, premultipliedColorBl, premultipliedColorBr, } = this;
223
345
  const { zIndex, worldAlpha, globalTransform: gt, clippingRect } = this;
224
346
  assertTruthy(gt);
225
347
  // add to list of renderables to be sorted before rendering
226
348
  renderer.addQuad({
227
349
  width,
228
350
  height,
229
- colorTl,
230
- colorTr,
231
- colorBl,
232
- colorBr,
351
+ colorTl: premultipliedColorTl,
352
+ colorTr: premultipliedColorTr,
353
+ colorBl: premultipliedColorBl,
354
+ colorBr: premultipliedColorBr,
233
355
  texture,
234
356
  textureOptions,
235
357
  zIndex,
@@ -257,7 +379,7 @@ export class CoreNode extends EventEmitter {
257
379
  set x(value) {
258
380
  if (this.props.x !== value) {
259
381
  this.props.x = value;
260
- this.updateLocalTransform();
382
+ this.setUpdateType(UpdateType.Local);
261
383
  }
262
384
  }
263
385
  get absX() {
@@ -273,7 +395,7 @@ export class CoreNode extends EventEmitter {
273
395
  set y(value) {
274
396
  if (this.props.y !== value) {
275
397
  this.props.y = value;
276
- this.updateLocalTransform();
398
+ this.setUpdateType(UpdateType.Local);
277
399
  }
278
400
  }
279
401
  get width() {
@@ -282,7 +404,7 @@ export class CoreNode extends EventEmitter {
282
404
  set width(value) {
283
405
  if (this.props.width !== value) {
284
406
  this.props.width = value;
285
- this.updateLocalTransform();
407
+ this.setUpdateType(UpdateType.Local);
286
408
  }
287
409
  }
288
410
  get height() {
@@ -291,7 +413,7 @@ export class CoreNode extends EventEmitter {
291
413
  set height(value) {
292
414
  if (this.props.height !== value) {
293
415
  this.props.height = value;
294
- this.updateLocalTransform();
416
+ this.setUpdateType(UpdateType.Local);
295
417
  }
296
418
  }
297
419
  get scale() {
@@ -311,7 +433,7 @@ export class CoreNode extends EventEmitter {
311
433
  set scaleX(value) {
312
434
  if (this.props.scaleX !== value) {
313
435
  this.props.scaleX = value;
314
- this.updateScaleRotateTransform();
436
+ this.setUpdateType(UpdateType.ScaleRotate);
315
437
  }
316
438
  }
317
439
  get scaleY() {
@@ -320,41 +442,37 @@ export class CoreNode extends EventEmitter {
320
442
  set scaleY(value) {
321
443
  if (this.props.scaleY !== value) {
322
444
  this.props.scaleY = value;
323
- this.updateScaleRotateTransform();
445
+ this.setUpdateType(UpdateType.ScaleRotate);
324
446
  }
325
447
  }
326
- get worldScaleX() {
327
- return (this.props.scaleX * (this.props.parent?.worldScaleX ?? 1) ||
328
- this.props.scaleX);
329
- }
330
- get worldScaleY() {
331
- return (this.props.scaleY * (this.props.parent?.worldScaleY ?? 1) ||
332
- this.props.scaleY);
333
- }
334
448
  get mount() {
335
449
  return this.props.mount;
336
450
  }
337
451
  set mount(value) {
338
- // if (this.props.mountX !== value || this.props.mountY !== value) {
339
- this.props.mountX = value;
340
- this.props.mountY = value;
341
- this.props.mount = value;
342
- this.updateLocalTransform();
343
- // }
452
+ if (this.props.mountX !== value || this.props.mountY !== value) {
453
+ this.props.mountX = value;
454
+ this.props.mountY = value;
455
+ this.props.mount = value;
456
+ this.setUpdateType(UpdateType.Local);
457
+ }
344
458
  }
345
459
  get mountX() {
346
460
  return this.props.mountX;
347
461
  }
348
462
  set mountX(value) {
349
- this.props.mountX = value;
350
- this.updateLocalTransform();
463
+ if (this.props.mountX !== value) {
464
+ this.props.mountX = value;
465
+ this.setUpdateType(UpdateType.Local);
466
+ }
351
467
  }
352
468
  get mountY() {
353
469
  return this.props.mountY;
354
470
  }
355
471
  set mountY(value) {
356
- this.props.mountY = value;
357
- this.updateLocalTransform();
472
+ if (this.props.mountY !== value) {
473
+ this.props.mountY = value;
474
+ this.setUpdateType(UpdateType.Local);
475
+ }
358
476
  }
359
477
  get pivot() {
360
478
  return this.props.pivot;
@@ -363,22 +481,27 @@ export class CoreNode extends EventEmitter {
363
481
  if (this.props.pivotX !== value || this.props.pivotY !== value) {
364
482
  this.props.pivotX = value;
365
483
  this.props.pivotY = value;
366
- this.updateLocalTransform();
484
+ this.props.pivot = value;
485
+ this.setUpdateType(UpdateType.Local);
367
486
  }
368
487
  }
369
488
  get pivotX() {
370
489
  return this.props.pivotX;
371
490
  }
372
491
  set pivotX(value) {
373
- this.props.pivotX = value;
374
- this.updateLocalTransform();
492
+ if (this.props.pivotX !== value) {
493
+ this.props.pivotX = value;
494
+ this.setUpdateType(UpdateType.Local);
495
+ }
375
496
  }
376
497
  get pivotY() {
377
498
  return this.props.pivotY;
378
499
  }
379
500
  set pivotY(value) {
380
- this.props.pivotY = value;
381
- this.updateLocalTransform();
501
+ if (this.props.pivotY !== value) {
502
+ this.props.pivotY = value;
503
+ this.setUpdateType(UpdateType.Local);
504
+ }
382
505
  }
383
506
  get rotation() {
384
507
  return this.props.rotation;
@@ -386,7 +509,7 @@ export class CoreNode extends EventEmitter {
386
509
  set rotation(value) {
387
510
  if (this.props.rotation !== value) {
388
511
  this.props.rotation = value;
389
- this.updateScaleRotateTransform();
512
+ this.setUpdateType(UpdateType.ScaleRotate);
390
513
  }
391
514
  }
392
515
  get alpha() {
@@ -394,20 +517,14 @@ export class CoreNode extends EventEmitter {
394
517
  }
395
518
  set alpha(value) {
396
519
  this.props.alpha = value;
397
- this.setRecalculationType(1);
398
- }
399
- get worldAlpha() {
400
- const props = this.props;
401
- const parent = props.parent;
402
- return props.alpha * (parent?.worldAlpha || 1);
520
+ this.setUpdateType(UpdateType.PremultipliedColors | UpdateType.WorldAlpha);
403
521
  }
404
522
  get clipping() {
405
523
  return this.props.clipping;
406
524
  }
407
525
  set clipping(value) {
408
526
  this.props.clipping = value;
409
- this.clippingRect = null;
410
- this.setRecalculationType(4);
527
+ this.setUpdateType(UpdateType.Clipping);
411
528
  }
412
529
  get color() {
413
530
  return this.props.color;
@@ -423,7 +540,7 @@ export class CoreNode extends EventEmitter {
423
540
  this.colorBr = value;
424
541
  }
425
542
  this.props.color = value;
426
- this.setRecalculationType(2);
543
+ this.setUpdateType(UpdateType.PremultipliedColors);
427
544
  }
428
545
  get colorTop() {
429
546
  return this.props.colorTop;
@@ -434,7 +551,7 @@ export class CoreNode extends EventEmitter {
434
551
  this.colorTr = value;
435
552
  }
436
553
  this.props.colorTop = value;
437
- this.setRecalculationType(2);
554
+ this.setUpdateType(UpdateType.PremultipliedColors);
438
555
  }
439
556
  get colorBottom() {
440
557
  return this.props.colorBottom;
@@ -445,7 +562,7 @@ export class CoreNode extends EventEmitter {
445
562
  this.colorBr = value;
446
563
  }
447
564
  this.props.colorBottom = value;
448
- this.setRecalculationType(2);
565
+ this.setUpdateType(UpdateType.PremultipliedColors);
449
566
  }
450
567
  get colorLeft() {
451
568
  return this.props.colorLeft;
@@ -456,7 +573,7 @@ export class CoreNode extends EventEmitter {
456
573
  this.colorBl = value;
457
574
  }
458
575
  this.props.colorLeft = value;
459
- this.setRecalculationType(2);
576
+ this.setUpdateType(UpdateType.PremultipliedColors);
460
577
  }
461
578
  get colorRight() {
462
579
  return this.props.colorRight;
@@ -467,35 +584,35 @@ export class CoreNode extends EventEmitter {
467
584
  this.colorBr = value;
468
585
  }
469
586
  this.props.colorRight = value;
470
- this.setRecalculationType(2);
587
+ this.setUpdateType(UpdateType.PremultipliedColors);
471
588
  }
472
589
  get colorTl() {
473
590
  return this.props.colorTl;
474
591
  }
475
592
  set colorTl(value) {
476
593
  this.props.colorTl = value;
477
- this.setRecalculationType(2);
594
+ this.setUpdateType(UpdateType.PremultipliedColors);
478
595
  }
479
596
  get colorTr() {
480
597
  return this.props.colorTr;
481
598
  }
482
599
  set colorTr(value) {
483
600
  this.props.colorTr = value;
484
- this.setRecalculationType(2);
601
+ this.setUpdateType(UpdateType.PremultipliedColors);
485
602
  }
486
603
  get colorBl() {
487
604
  return this.props.colorBl;
488
605
  }
489
606
  set colorBl(value) {
490
607
  this.props.colorBl = value;
491
- this.setRecalculationType(2);
608
+ this.setUpdateType(UpdateType.PremultipliedColors);
492
609
  }
493
610
  get colorBr() {
494
611
  return this.props.colorBr;
495
612
  }
496
613
  set colorBr(value) {
497
614
  this.props.colorBr = value;
498
- this.setRecalculationType(2);
615
+ this.setUpdateType(UpdateType.PremultipliedColors);
499
616
  }
500
617
  // we're only interested in parent zIndex to test
501
618
  // if we should use node zIndex is higher then parent zIndex
@@ -504,19 +621,20 @@ export class CoreNode extends EventEmitter {
504
621
  }
505
622
  set zIndexLocked(value) {
506
623
  this.props.zIndexLocked = value;
624
+ this.setUpdateType(UpdateType.CalculatedZIndex | UpdateType.Children);
625
+ this.children.forEach((child) => {
626
+ child.setUpdateType(UpdateType.CalculatedZIndex);
627
+ });
507
628
  }
508
629
  get zIndex() {
509
- const props = this.props;
510
- const z = props.zIndex || 0;
511
- const p = props.parent?.zIndex || 0;
512
- if (props.parent?.zIndexLocked) {
513
- return z < p ? z : p;
514
- }
515
- return z;
630
+ return this.props.zIndex;
516
631
  }
517
632
  set zIndex(value) {
518
633
  this.props.zIndex = value;
519
- this.props.parent?.setRecalculationType(8);
634
+ this.setUpdateType(UpdateType.CalculatedZIndex | UpdateType.Children);
635
+ this.children.forEach((child) => {
636
+ child.setUpdateType(UpdateType.CalculatedZIndex);
637
+ });
520
638
  }
521
639
  get parent() {
522
640
  return this.props.parent;
@@ -534,8 +652,10 @@ export class CoreNode extends EventEmitter {
534
652
  }
535
653
  if (newParent) {
536
654
  newParent.children.push(this);
537
- // force parent to recalculate z-index for its children
538
- newParent.setRecalculationType(8);
655
+ // Since this node has a new parent, to be safe, have it do a full update.
656
+ this.setUpdateType(UpdateType.All);
657
+ // Tell parent that it's children need to be updated and sorted.
658
+ newParent.setUpdateType(UpdateType.Children | UpdateType.ZIndexSortedChildren);
539
659
  }
540
660
  this.updateScaleRotateTransform();
541
661
  }