@babylonjs/core 6.20.0 → 6.20.2

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 (128) hide show
  1. package/Animations/animation.d.ts +51 -3
  2. package/Animations/animation.js +92 -106
  3. package/Animations/animation.js.map +1 -1
  4. package/Animations/animationGroup.d.ts +60 -8
  5. package/Animations/animationGroup.js +132 -29
  6. package/Animations/animationGroup.js.map +1 -1
  7. package/Engines/Extensions/engine.query.js +1 -1
  8. package/Engines/Extensions/engine.query.js.map +1 -1
  9. package/Engines/WebGPU/Extensions/engine.query.js +1 -1
  10. package/Engines/WebGPU/Extensions/engine.query.js.map +1 -1
  11. package/Engines/WebGPU/Extensions/engine.renderTarget.js +3 -2
  12. package/Engines/WebGPU/Extensions/engine.renderTarget.js.map +1 -1
  13. package/Engines/WebGPU/Extensions/engine.renderTargetCube.js +2 -0
  14. package/Engines/WebGPU/Extensions/engine.renderTargetCube.js.map +1 -1
  15. package/Engines/WebGPU/webgpuOcclusionQuery.d.ts +3 -1
  16. package/Engines/WebGPU/webgpuOcclusionQuery.js +18 -6
  17. package/Engines/WebGPU/webgpuOcclusionQuery.js.map +1 -1
  18. package/Engines/WebGPU/webgpuQuerySet.d.ts +1 -1
  19. package/Engines/WebGPU/webgpuQuerySet.js +2 -1
  20. package/Engines/WebGPU/webgpuQuerySet.js.map +1 -1
  21. package/Engines/nativeEngine.js +1 -1
  22. package/Engines/nativeEngine.js.map +1 -1
  23. package/Engines/renderTargetWrapper.d.ts +6 -1
  24. package/Engines/renderTargetWrapper.js +3 -1
  25. package/Engines/renderTargetWrapper.js.map +1 -1
  26. package/Engines/thinEngine.js +2 -2
  27. package/Engines/thinEngine.js.map +1 -1
  28. package/Engines/webgpuEngine.js +5 -3
  29. package/Engines/webgpuEngine.js.map +1 -1
  30. package/Materials/Node/Blocks/PBR/pbrMetallicRoughnessBlock.js +1 -0
  31. package/Materials/Node/Blocks/PBR/pbrMetallicRoughnessBlock.js.map +1 -1
  32. package/Materials/Node/nodeMaterial.d.ts +4 -0
  33. package/Materials/Node/nodeMaterial.js +30 -20
  34. package/Materials/Node/nodeMaterial.js.map +1 -1
  35. package/Materials/effect.js +4 -4
  36. package/Materials/effect.js.map +1 -1
  37. package/Maths/math.vector.d.ts +2 -1
  38. package/Maths/math.vector.js +5 -4
  39. package/Maths/math.vector.js.map +1 -1
  40. package/Meshes/Node/Blocks/Instances/instantiateBlock.js +5 -2
  41. package/Meshes/Node/Blocks/Instances/instantiateBlock.js.map +1 -1
  42. package/Meshes/Node/Blocks/Instances/instantiateOnFacesBlock.js +10 -6
  43. package/Meshes/Node/Blocks/Instances/instantiateOnFacesBlock.js.map +1 -1
  44. package/Meshes/Node/Blocks/Instances/instantiateOnVerticesBlock.js +10 -6
  45. package/Meshes/Node/Blocks/Instances/instantiateOnVerticesBlock.js.map +1 -1
  46. package/Meshes/Node/Blocks/Instances/instantiateOnVolumeBlock.js +10 -6
  47. package/Meshes/Node/Blocks/Instances/instantiateOnVolumeBlock.js.map +1 -1
  48. package/Meshes/Node/Blocks/Matrices/alignBlock.js +1 -1
  49. package/Meshes/Node/Blocks/Matrices/alignBlock.js.map +1 -1
  50. package/Meshes/Node/Blocks/Set/setColorsBlock.js +9 -6
  51. package/Meshes/Node/Blocks/Set/setColorsBlock.js.map +1 -1
  52. package/Meshes/Node/Blocks/Set/setMaterialIDBlock.js +1 -0
  53. package/Meshes/Node/Blocks/Set/setMaterialIDBlock.js.map +1 -1
  54. package/Meshes/Node/Blocks/Set/setNormalsBlock.js +9 -6
  55. package/Meshes/Node/Blocks/Set/setNormalsBlock.js.map +1 -1
  56. package/Meshes/Node/Blocks/Set/setPositionsBlock.js +7 -4
  57. package/Meshes/Node/Blocks/Set/setPositionsBlock.js.map +1 -1
  58. package/Meshes/Node/Blocks/Set/setTangentsBlock.js +9 -6
  59. package/Meshes/Node/Blocks/Set/setTangentsBlock.js.map +1 -1
  60. package/Meshes/Node/Blocks/Set/setUVsBlock.js +9 -6
  61. package/Meshes/Node/Blocks/Set/setUVsBlock.js.map +1 -1
  62. package/Meshes/Node/Blocks/Sources/boxBlock.js +3 -1
  63. package/Meshes/Node/Blocks/Sources/boxBlock.js.map +1 -1
  64. package/Meshes/Node/Blocks/Sources/capsuleBlock.js +3 -1
  65. package/Meshes/Node/Blocks/Sources/capsuleBlock.js.map +1 -1
  66. package/Meshes/Node/Blocks/Sources/cylinderBlock.js +3 -1
  67. package/Meshes/Node/Blocks/Sources/cylinderBlock.js.map +1 -1
  68. package/Meshes/Node/Blocks/Sources/discBlock.js +3 -1
  69. package/Meshes/Node/Blocks/Sources/discBlock.js.map +1 -1
  70. package/Meshes/Node/Blocks/Sources/gridBlock.js +3 -1
  71. package/Meshes/Node/Blocks/Sources/gridBlock.js.map +1 -1
  72. package/Meshes/Node/Blocks/Sources/icoSphereBlock.js +3 -1
  73. package/Meshes/Node/Blocks/Sources/icoSphereBlock.js.map +1 -1
  74. package/Meshes/Node/Blocks/Sources/meshBlock.js +4 -1
  75. package/Meshes/Node/Blocks/Sources/meshBlock.js.map +1 -1
  76. package/Meshes/Node/Blocks/Sources/planeBlock.js +3 -1
  77. package/Meshes/Node/Blocks/Sources/planeBlock.js.map +1 -1
  78. package/Meshes/Node/Blocks/Sources/sphereBlock.js +3 -1
  79. package/Meshes/Node/Blocks/Sources/sphereBlock.js.map +1 -1
  80. package/Meshes/Node/Blocks/Sources/torusBlock.js +3 -1
  81. package/Meshes/Node/Blocks/Sources/torusBlock.js.map +1 -1
  82. package/Meshes/Node/Blocks/Teleport/teleportInBlock.js +1 -0
  83. package/Meshes/Node/Blocks/Teleport/teleportInBlock.js.map +1 -1
  84. package/Meshes/Node/Blocks/Teleport/teleportOutBlock.js +1 -0
  85. package/Meshes/Node/Blocks/Teleport/teleportOutBlock.js.map +1 -1
  86. package/Meshes/Node/Blocks/debugBlock.js +1 -0
  87. package/Meshes/Node/Blocks/debugBlock.js.map +1 -1
  88. package/Meshes/Node/Blocks/geometryCollectionBlock.js +1 -0
  89. package/Meshes/Node/Blocks/geometryCollectionBlock.js.map +1 -1
  90. package/Meshes/Node/Blocks/geometryInputBlock.js +1 -0
  91. package/Meshes/Node/Blocks/geometryInputBlock.js.map +1 -1
  92. package/Meshes/Node/Blocks/geometryOptimizeBlock.js +2 -1
  93. package/Meshes/Node/Blocks/geometryOptimizeBlock.js.map +1 -1
  94. package/Meshes/Node/Blocks/geometryTransformBlock.js +1 -0
  95. package/Meshes/Node/Blocks/geometryTransformBlock.js.map +1 -1
  96. package/Meshes/Node/Blocks/matrixComposeBlock.js +4 -1
  97. package/Meshes/Node/Blocks/matrixComposeBlock.js.map +1 -1
  98. package/Meshes/Node/Blocks/mergeGeometryBlock.js +1 -0
  99. package/Meshes/Node/Blocks/mergeGeometryBlock.js.map +1 -1
  100. package/Meshes/Node/Blocks/noiseBlock.js +1 -1
  101. package/Meshes/Node/Blocks/noiseBlock.js.map +1 -1
  102. package/Meshes/Node/Blocks/randomBlock.d.ts +12 -0
  103. package/Meshes/Node/Blocks/randomBlock.js +42 -1
  104. package/Meshes/Node/Blocks/randomBlock.js.map +1 -1
  105. package/Meshes/Node/nodeGeometry.js +5 -0
  106. package/Meshes/Node/nodeGeometry.js.map +1 -1
  107. package/Meshes/Node/nodeGeometryBlock.d.ts +8 -3
  108. package/Meshes/Node/nodeGeometryBlock.js +18 -10
  109. package/Meshes/Node/nodeGeometryBlock.js.map +1 -1
  110. package/Meshes/Node/nodeGeometryBuildState.d.ts +37 -3
  111. package/Meshes/Node/nodeGeometryBuildState.js +64 -6
  112. package/Meshes/Node/nodeGeometryBuildState.js.map +1 -1
  113. package/Meshes/linesMesh.js +2 -2
  114. package/Meshes/linesMesh.js.map +1 -1
  115. package/Meshes/mesh.vertexData.js +28 -26
  116. package/Meshes/mesh.vertexData.js.map +1 -1
  117. package/Physics/v2/physicsBody.d.ts +1 -0
  118. package/Physics/v2/physicsBody.js +5 -0
  119. package/Physics/v2/physicsBody.js.map +1 -1
  120. package/Physics/v2/physicsShape.d.ts +1 -0
  121. package/Physics/v2/physicsShape.js +5 -0
  122. package/Physics/v2/physicsShape.js.map +1 -1
  123. package/Probes/reflectionProbe.d.ts +2 -1
  124. package/Probes/reflectionProbe.js +4 -1
  125. package/Probes/reflectionProbe.js.map +1 -1
  126. package/Shaders/ShadersInclude/pbrDebug.js +3 -0
  127. package/Shaders/ShadersInclude/pbrDebug.js.map +1 -1
  128. package/package.json +1 -1
@@ -11,6 +11,41 @@ import type { IAnimatable } from "./animatable.interface";
11
11
  import { Size } from "../Maths/math.size";
12
12
  import type { Animatable } from "./animatable";
13
13
  import type { RuntimeAnimation } from "./runtimeAnimation";
14
+ /**
15
+ * Options to be used when creating an additive animation
16
+ */
17
+ export interface IMakeAnimationAdditiveOptions {
18
+ /**
19
+ * The frame that the animation should be relative to (if not provided, 0 will be used)
20
+ */
21
+ referenceFrame?: number;
22
+ /**
23
+ * The name of the animation range to convert to additive. If not provided, fromFrame / toFrame will be used
24
+ * If fromFrame / toFrame are not provided either, the whole animation will be converted to additive
25
+ */
26
+ range?: string;
27
+ /**
28
+ * If true, the original animation will be cloned and converted to additive. If false, the original animation will be converted to additive (default is false)
29
+ */
30
+ cloneOriginalAnimation?: boolean;
31
+ /**
32
+ * The name of the cloned animation if cloneOriginalAnimation is true. If not provided, use the original animation name
33
+ */
34
+ clonedAnimationName?: string;
35
+ /**
36
+ * Together with toFrame, defines the range of the animation to convert to additive. Will only be used if range is not provided
37
+ * If range and fromFrame / toFrame are not provided, the whole animation will be converted to additive
38
+ */
39
+ fromFrame?: number;
40
+ /**
41
+ * Together with fromFrame, defines the range of the animation to convert to additive.
42
+ */
43
+ toFrame?: number;
44
+ /**
45
+ * If true, the key frames will be clipped to the range specified by range or fromFrame / toFrame (default is false)
46
+ */
47
+ clipKeys?: boolean;
48
+ }
14
49
  /**
15
50
  * @internal
16
51
  */
@@ -145,15 +180,22 @@ export declare class Animation {
145
180
  */
146
181
  static CreateMergeAndStartAnimation(name: string, node: Node, targetProperty: string, framePerSecond: number, totalFrame: number, from: any, to: any, loopMode?: number, easingFunction?: EasingFunction, onAnimationEnd?: () => void): Nullable<Animatable>;
147
182
  /**
148
- * Convert the keyframes for all animations belonging to the group to be relative to a given reference frame.
183
+ * Convert the keyframes of an animation to be relative to a given reference frame.
149
184
  * @param sourceAnimation defines the Animation containing keyframes to convert
150
- * @param referenceFrame defines the frame that keyframes in the range will be relative to
185
+ * @param referenceFrame defines the frame that keyframes in the range will be relative to (default: 0)
151
186
  * @param range defines the name of the AnimationRange belonging to the Animation to convert
152
187
  * @param cloneOriginal defines whether or not to clone the animation and convert the clone or convert the original animation (default is false)
153
188
  * @param clonedName defines the name of the resulting cloned Animation if cloneOriginal is true
154
189
  * @returns a new Animation if cloneOriginal is true or the original Animation if cloneOriginal is false
155
190
  */
156
191
  static MakeAnimationAdditive(sourceAnimation: Animation, referenceFrame?: number, range?: string, cloneOriginal?: boolean, clonedName?: string): Animation;
192
+ /**
193
+ * Convert the keyframes of an animation to be relative to a given reference frame.
194
+ * @param sourceAnimation defines the Animation containing keyframes to convert
195
+ * @param options defines the options to use when converting ey keyframes
196
+ * @returns a new Animation if options.cloneOriginalAnimation is true or the original Animation if options.cloneOriginalAnimation is false
197
+ */
198
+ static MakeAnimationAdditive(sourceAnimation: Animation, options?: IMakeAnimationAdditiveOptions): Animation;
157
199
  /**
158
200
  * Transition property of an host to the target Value
159
201
  * @param property The property to transition
@@ -386,7 +428,7 @@ export declare class Animation {
386
428
  /**
387
429
  * @internal Internal use only
388
430
  */
389
- _interpolate(currentFrame: number, state: _IAnimationState): any;
431
+ _interpolate(currentFrame: number, state: _IAnimationState, searchClosestKeyOnly?: boolean): any;
390
432
  /**
391
433
  * Defines the function to use to interpolate matrices
392
434
  * @param startValue defines the start matrix
@@ -407,6 +449,12 @@ export declare class Animation {
407
449
  * @param dontClone Whether to clone the keys or not (default is false, so the array of keys is cloned)
408
450
  */
409
451
  setKeys(values: Array<IAnimationKey>, dontClone?: boolean): void;
452
+ /**
453
+ * Creates a key for the frame passed as a parameter and adds it to the animation IF a key doesn't already exist for that frame
454
+ * @param frame Frame number
455
+ * @returns The key index if the key was added or the index of the pre existing key if the frame passed as parameter already has a corresponding key
456
+ */
457
+ createKeyForFrame(frame: number): number;
410
458
  /**
411
459
  * Serializes the animation to an object
412
460
  * @returns Serialized object
@@ -15,6 +15,11 @@ import { WebRequest } from "../Misc/webRequest.js";
15
15
  // eslint-disable-next-line @typescript-eslint/naming-convention
16
16
  export class _IAnimationState {
17
17
  }
18
+ const evaluateAnimationState = {
19
+ key: 0,
20
+ repeatCount: 0,
21
+ loopMode: 2 /*Animation.ANIMATIONLOOPMODE_CONSTANT*/,
22
+ };
18
23
  /**
19
24
  * Class used to store any kind of animation
20
25
  */
@@ -146,25 +151,30 @@ export class Animation {
146
151
  node.animations.push(animation);
147
152
  return node.getScene().beginAnimation(node, 0, totalFrame, animation.loopMode === 1, 1.0, onAnimationEnd);
148
153
  }
149
- /**
150
- * Convert the keyframes for all animations belonging to the group to be relative to a given reference frame.
151
- * @param sourceAnimation defines the Animation containing keyframes to convert
152
- * @param referenceFrame defines the frame that keyframes in the range will be relative to
153
- * @param range defines the name of the AnimationRange belonging to the Animation to convert
154
- * @param cloneOriginal defines whether or not to clone the animation and convert the clone or convert the original animation (default is false)
155
- * @param clonedName defines the name of the resulting cloned Animation if cloneOriginal is true
156
- * @returns a new Animation if cloneOriginal is true or the original Animation if cloneOriginal is false
157
- */
158
- static MakeAnimationAdditive(sourceAnimation, referenceFrame = 0, range, cloneOriginal = false, clonedName) {
154
+ /** @internal */
155
+ static MakeAnimationAdditive(sourceAnimation, referenceFrameOrOptions, range, cloneOriginal = false, clonedName) {
156
+ var _a, _b;
157
+ let options;
158
+ if (typeof referenceFrameOrOptions === "object") {
159
+ options = referenceFrameOrOptions;
160
+ }
161
+ else {
162
+ options = {
163
+ referenceFrame: referenceFrameOrOptions !== null && referenceFrameOrOptions !== void 0 ? referenceFrameOrOptions : 0,
164
+ range: range,
165
+ cloneOriginalAnimation: cloneOriginal,
166
+ clonedAnimationName: clonedName,
167
+ };
168
+ }
159
169
  let animation = sourceAnimation;
160
- if (cloneOriginal) {
170
+ if (options.cloneOriginalAnimation) {
161
171
  animation = sourceAnimation.clone();
162
- animation.name = clonedName || animation.name;
172
+ animation.name = options.clonedAnimationName || animation.name;
163
173
  }
164
174
  if (!animation._keys.length) {
165
175
  return animation;
166
176
  }
167
- referenceFrame = referenceFrame >= 0 ? referenceFrame : 0;
177
+ const referenceFrame = options.referenceFrame && options.referenceFrame >= 0 ? options.referenceFrame : 0;
168
178
  let startIndex = 0;
169
179
  const firstKey = animation._keys[0];
170
180
  let endIndex = animation._keys.length - 1;
@@ -178,110 +188,45 @@ export class Animation {
178
188
  keyQuaternion: TmpVectors.Quaternion[1],
179
189
  keyScaling: TmpVectors.Vector3[3],
180
190
  };
181
- let referenceFound = false;
182
191
  let from = firstKey.frame;
183
192
  let to = lastKey.frame;
184
- if (range) {
185
- const rangeValue = animation.getRange(range);
193
+ if (options.range) {
194
+ const rangeValue = animation.getRange(options.range);
186
195
  if (rangeValue) {
187
196
  from = rangeValue.from;
188
197
  to = rangeValue.to;
189
198
  }
190
199
  }
191
- let fromKeyFound = firstKey.frame === from;
192
- let toKeyFound = lastKey.frame === to;
200
+ else {
201
+ from = (_a = options.fromFrame) !== null && _a !== void 0 ? _a : from;
202
+ to = (_b = options.toFrame) !== null && _b !== void 0 ? _b : to;
203
+ }
204
+ if (from !== firstKey.frame) {
205
+ startIndex = animation.createKeyForFrame(from);
206
+ }
207
+ if (to !== lastKey.frame) {
208
+ endIndex = animation.createKeyForFrame(to);
209
+ }
193
210
  // There's only one key, so use it
194
211
  if (animation._keys.length === 1) {
195
212
  const value = animation._getKeyValue(animation._keys[0]);
196
213
  valueStore.referenceValue = value.clone ? value.clone() : value;
197
- referenceFound = true;
198
214
  }
199
215
  // Reference frame is before the first frame, so just use the first frame
200
216
  else if (referenceFrame <= firstKey.frame) {
201
217
  const value = animation._getKeyValue(firstKey.value);
202
218
  valueStore.referenceValue = value.clone ? value.clone() : value;
203
- referenceFound = true;
204
219
  }
205
220
  // Reference frame is after the last frame, so just use the last frame
206
221
  else if (referenceFrame >= lastKey.frame) {
207
222
  const value = animation._getKeyValue(lastKey.value);
208
223
  valueStore.referenceValue = value.clone ? value.clone() : value;
209
- referenceFound = true;
210
- }
211
- // Find key bookends, create them if they don't exist
212
- let index = 0;
213
- while (!referenceFound || !fromKeyFound || (!toKeyFound && index < animation._keys.length - 1)) {
214
- const currentKey = animation._keys[index];
215
- const nextKey = animation._keys[index + 1];
216
- // If reference frame wasn't found yet, check if we can interpolate to it
217
- if (!referenceFound && referenceFrame >= currentKey.frame && referenceFrame <= nextKey.frame) {
218
- let value;
219
- if (referenceFrame === currentKey.frame) {
220
- value = animation._getKeyValue(currentKey.value);
221
- }
222
- else if (referenceFrame === nextKey.frame) {
223
- value = animation._getKeyValue(nextKey.value);
224
- }
225
- else {
226
- const animationState = {
227
- key: index,
228
- repeatCount: 0,
229
- loopMode: this.ANIMATIONLOOPMODE_CONSTANT,
230
- };
231
- value = animation._interpolate(referenceFrame, animationState);
232
- }
233
- valueStore.referenceValue = value.clone ? value.clone() : value;
234
- referenceFound = true;
235
- }
236
- // If from key wasn't found yet, check if we can interpolate to it
237
- if (!fromKeyFound && from >= currentKey.frame && from <= nextKey.frame) {
238
- if (from === currentKey.frame) {
239
- startIndex = index;
240
- }
241
- else if (from === nextKey.frame) {
242
- startIndex = index + 1;
243
- }
244
- else {
245
- const animationState = {
246
- key: index,
247
- repeatCount: 0,
248
- loopMode: this.ANIMATIONLOOPMODE_CONSTANT,
249
- };
250
- const value = animation._interpolate(from, animationState);
251
- const key = {
252
- frame: from,
253
- value: value.clone ? value.clone() : value,
254
- };
255
- animation._keys.splice(index + 1, 0, key);
256
- startIndex = index + 1;
257
- }
258
- fromKeyFound = true;
259
- }
260
- // If to key wasn't found yet, check if we can interpolate to it
261
- if (!toKeyFound && to >= currentKey.frame && to <= nextKey.frame) {
262
- if (to === currentKey.frame) {
263
- endIndex = index;
264
- }
265
- else if (to === nextKey.frame) {
266
- endIndex = index + 1;
267
- }
268
- else {
269
- const animationState = {
270
- key: index,
271
- repeatCount: 0,
272
- loopMode: this.ANIMATIONLOOPMODE_CONSTANT,
273
- };
274
- const value = animation._interpolate(to, animationState);
275
- const key = {
276
- frame: to,
277
- value: value.clone ? value.clone() : value,
278
- };
279
- animation._keys.splice(index + 1, 0, key);
280
- endIndex = index + 1;
281
- }
282
- toKeyFound = true;
283
- }
284
- index++;
224
+ }
225
+ // Interpolate the reference value from the animation
226
+ else {
227
+ evaluateAnimationState.key = 0;
228
+ const value = animation._interpolate(referenceFrame, evaluateAnimationState);
229
+ valueStore.referenceValue = value.clone ? value.clone() : value;
285
230
  }
286
231
  // Conjugate the quaternion
287
232
  if (animation.dataType === Animation.ANIMATIONTYPE_QUATERNION) {
@@ -292,9 +237,26 @@ export class Animation {
292
237
  valueStore.referenceValue.decompose(valueStore.referenceScaling, valueStore.referenceQuaternion, valueStore.referencePosition);
293
238
  valueStore.referenceQuaternion.normalize().conjugateInPlace();
294
239
  }
240
+ let startFrame = Number.MAX_VALUE;
241
+ const clippedKeys = options.clipKeys ? [] : null;
295
242
  // Subtract the reference value from all of the key values
296
- for (index = startIndex; index <= endIndex; index++) {
297
- const key = animation._keys[index];
243
+ for (let index = startIndex; index <= endIndex; index++) {
244
+ let key = animation._keys[index];
245
+ if (clippedKeys) {
246
+ key = {
247
+ frame: key.frame,
248
+ value: key.value.clone ? key.value.clone() : key.value,
249
+ inTangent: key.inTangent,
250
+ outTangent: key.outTangent,
251
+ interpolation: key.interpolation,
252
+ lockedTangent: key.lockedTangent,
253
+ };
254
+ if (startFrame === Number.MAX_VALUE) {
255
+ startFrame = key.frame;
256
+ }
257
+ key.frame -= startFrame;
258
+ clippedKeys.push(key);
259
+ }
298
260
  // If this key was duplicated to create a frame 0 key, skip it because its value has already been updated
299
261
  if (index && animation.dataType !== Animation.ANIMATIONTYPE_FLOAT && key.value === firstKey.value) {
300
262
  continue;
@@ -324,6 +286,9 @@ export class Animation {
324
286
  key.value -= valueStore.referenceValue;
325
287
  }
326
288
  }
289
+ if (clippedKeys) {
290
+ animation.setKeys(clippedKeys, true);
291
+ }
327
292
  return animation;
328
293
  }
329
294
  /**
@@ -720,16 +685,13 @@ export class Animation {
720
685
  * @returns the animation value
721
686
  */
722
687
  evaluate(currentFrame) {
723
- return this._interpolate(currentFrame, {
724
- key: 0,
725
- repeatCount: 0,
726
- loopMode: Animation.ANIMATIONLOOPMODE_CONSTANT,
727
- });
688
+ evaluateAnimationState.key = 0;
689
+ return this._interpolate(currentFrame, evaluateAnimationState);
728
690
  }
729
691
  /**
730
692
  * @internal Internal use only
731
693
  */
732
- _interpolate(currentFrame, state) {
694
+ _interpolate(currentFrame, state, searchClosestKeyOnly = false) {
733
695
  if (state.loopMode === Animation.ANIMATIONLOOPMODE_CONSTANT && state.repeatCount > 0) {
734
696
  return state.highLimitValue.clone ? state.highLimitValue.clone() : state.highLimitValue;
735
697
  }
@@ -744,13 +706,16 @@ export class Animation {
744
706
  }
745
707
  state.key = key;
746
708
  if (key < 0) {
747
- return this._getKeyValue(keys[0].value);
709
+ return searchClosestKeyOnly ? undefined : this._getKeyValue(keys[0].value);
748
710
  }
749
711
  else if (key + 1 > keysLength - 1) {
750
- return this._getKeyValue(keys[keysLength - 1].value);
712
+ return searchClosestKeyOnly ? undefined : this._getKeyValue(keys[keysLength - 1].value);
751
713
  }
752
714
  const startKey = keys[key];
753
715
  const endKey = keys[key + 1];
716
+ if (searchClosestKeyOnly && (currentFrame === startKey.frame || currentFrame === endKey.frame)) {
717
+ return undefined;
718
+ }
754
719
  const startValue = this._getKeyValue(startKey.value);
755
720
  const endValue = this._getKeyValue(endKey.value);
756
721
  if (startKey.interpolation === AnimationKeyInterpolation.STEP) {
@@ -946,6 +911,27 @@ export class Animation {
946
911
  setKeys(values, dontClone = false) {
947
912
  this._keys = !dontClone ? values.slice(0) : values;
948
913
  }
914
+ /**
915
+ * Creates a key for the frame passed as a parameter and adds it to the animation IF a key doesn't already exist for that frame
916
+ * @param frame Frame number
917
+ * @returns The key index if the key was added or the index of the pre existing key if the frame passed as parameter already has a corresponding key
918
+ */
919
+ createKeyForFrame(frame) {
920
+ // Find the key corresponding to frame
921
+ evaluateAnimationState.key = 0;
922
+ const value = this._interpolate(frame, evaluateAnimationState, true);
923
+ if (!value) {
924
+ // A key corresponding to this frame already exists
925
+ return evaluateAnimationState.key === frame ? evaluateAnimationState.key : evaluateAnimationState.key + 1;
926
+ }
927
+ // The frame is between two keys, so create a new key
928
+ const newKey = {
929
+ frame,
930
+ value: value.clone ? value.clone() : value,
931
+ };
932
+ this._keys.splice(evaluateAnimationState.key + 1, 0, newKey);
933
+ return evaluateAnimationState.key + 1;
934
+ }
949
935
  /**
950
936
  * Serializes the animation to an object
951
937
  * @returns Serialized object