roavatar-renderer 1.5.15 → 1.5.16

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.
package/dist/index.js CHANGED
@@ -1117,6 +1117,11 @@ const RED_GREEN_RGTC2_Format = 36285;
1117
1117
  const SIGNED_RED_GREEN_RGTC2_Format = 36286;
1118
1118
  const InterpolateDiscrete = 2300;
1119
1119
  const InterpolateLinear = 2301;
1120
+ const InterpolateSmooth = 2302;
1121
+ const ZeroCurvatureEnding = 2400;
1122
+ const ZeroSlopeEnding = 2401;
1123
+ const WrapAroundEnding = 2402;
1124
+ const NormalAnimationBlendMode = 2500;
1120
1125
  const BasicDepthPacking = 3200;
1121
1126
  const RGBADepthPacking = 3201;
1122
1127
  const TangentSpaceNormalMap = 0;
@@ -15538,6 +15543,1128 @@ class MeshDistanceMaterial extends Material {
15538
15543
  return this;
15539
15544
  }
15540
15545
  }
15546
+ function convertArray(array, type) {
15547
+ if (!array || array.constructor === type) return array;
15548
+ if (typeof type.BYTES_PER_ELEMENT === "number") {
15549
+ return new type(array);
15550
+ }
15551
+ return Array.prototype.slice.call(array);
15552
+ }
15553
+ function isTypedArray(object) {
15554
+ return ArrayBuffer.isView(object) && !(object instanceof DataView);
15555
+ }
15556
+ function getKeyframeOrder(times) {
15557
+ function compareTime(i, j) {
15558
+ return times[i] - times[j];
15559
+ }
15560
+ const n = times.length;
15561
+ const result = new Array(n);
15562
+ for (let i = 0; i !== n; ++i) result[i] = i;
15563
+ result.sort(compareTime);
15564
+ return result;
15565
+ }
15566
+ function sortedArray(values, stride, order) {
15567
+ const nValues = values.length;
15568
+ const result = new values.constructor(nValues);
15569
+ for (let i = 0, dstOffset = 0; dstOffset !== nValues; ++i) {
15570
+ const srcOffset = order[i] * stride;
15571
+ for (let j = 0; j !== stride; ++j) {
15572
+ result[dstOffset++] = values[srcOffset + j];
15573
+ }
15574
+ }
15575
+ return result;
15576
+ }
15577
+ function flattenJSON(jsonKeys, times, values, valuePropertyName) {
15578
+ let i = 1, key = jsonKeys[0];
15579
+ while (key !== void 0 && key[valuePropertyName] === void 0) {
15580
+ key = jsonKeys[i++];
15581
+ }
15582
+ if (key === void 0) return;
15583
+ let value = key[valuePropertyName];
15584
+ if (value === void 0) return;
15585
+ if (Array.isArray(value)) {
15586
+ do {
15587
+ value = key[valuePropertyName];
15588
+ if (value !== void 0) {
15589
+ times.push(key.time);
15590
+ values.push(...value);
15591
+ }
15592
+ key = jsonKeys[i++];
15593
+ } while (key !== void 0);
15594
+ } else if (value.toArray !== void 0) {
15595
+ do {
15596
+ value = key[valuePropertyName];
15597
+ if (value !== void 0) {
15598
+ times.push(key.time);
15599
+ value.toArray(values, values.length);
15600
+ }
15601
+ key = jsonKeys[i++];
15602
+ } while (key !== void 0);
15603
+ } else {
15604
+ do {
15605
+ value = key[valuePropertyName];
15606
+ if (value !== void 0) {
15607
+ times.push(key.time);
15608
+ values.push(value);
15609
+ }
15610
+ key = jsonKeys[i++];
15611
+ } while (key !== void 0);
15612
+ }
15613
+ }
15614
+ class Interpolant {
15615
+ /**
15616
+ * Constructs a new interpolant.
15617
+ *
15618
+ * @param {TypedArray} parameterPositions - The parameter positions hold the interpolation factors.
15619
+ * @param {TypedArray} sampleValues - The sample values.
15620
+ * @param {number} sampleSize - The sample size
15621
+ * @param {TypedArray} [resultBuffer] - The result buffer.
15622
+ */
15623
+ constructor(parameterPositions, sampleValues, sampleSize, resultBuffer) {
15624
+ this.parameterPositions = parameterPositions;
15625
+ this._cachedIndex = 0;
15626
+ this.resultBuffer = resultBuffer !== void 0 ? resultBuffer : new sampleValues.constructor(sampleSize);
15627
+ this.sampleValues = sampleValues;
15628
+ this.valueSize = sampleSize;
15629
+ this.settings = null;
15630
+ this.DefaultSettings_ = {};
15631
+ }
15632
+ /**
15633
+ * Evaluate the interpolant at position `t`.
15634
+ *
15635
+ * @param {number} t - The interpolation factor.
15636
+ * @return {TypedArray} The result buffer.
15637
+ */
15638
+ evaluate(t) {
15639
+ const pp = this.parameterPositions;
15640
+ let i1 = this._cachedIndex, t1 = pp[i1], t0 = pp[i1 - 1];
15641
+ validate_interval: {
15642
+ seek: {
15643
+ let right;
15644
+ linear_scan: {
15645
+ forward_scan: if (!(t < t1)) {
15646
+ for (let giveUpAt = i1 + 2; ; ) {
15647
+ if (t1 === void 0) {
15648
+ if (t < t0) break forward_scan;
15649
+ i1 = pp.length;
15650
+ this._cachedIndex = i1;
15651
+ return this.copySampleValue_(i1 - 1);
15652
+ }
15653
+ if (i1 === giveUpAt) break;
15654
+ t0 = t1;
15655
+ t1 = pp[++i1];
15656
+ if (t < t1) {
15657
+ break seek;
15658
+ }
15659
+ }
15660
+ right = pp.length;
15661
+ break linear_scan;
15662
+ }
15663
+ if (!(t >= t0)) {
15664
+ const t1global = pp[1];
15665
+ if (t < t1global) {
15666
+ i1 = 2;
15667
+ t0 = t1global;
15668
+ }
15669
+ for (let giveUpAt = i1 - 2; ; ) {
15670
+ if (t0 === void 0) {
15671
+ this._cachedIndex = 0;
15672
+ return this.copySampleValue_(0);
15673
+ }
15674
+ if (i1 === giveUpAt) break;
15675
+ t1 = t0;
15676
+ t0 = pp[--i1 - 1];
15677
+ if (t >= t0) {
15678
+ break seek;
15679
+ }
15680
+ }
15681
+ right = i1;
15682
+ i1 = 0;
15683
+ break linear_scan;
15684
+ }
15685
+ break validate_interval;
15686
+ }
15687
+ while (i1 < right) {
15688
+ const mid = i1 + right >>> 1;
15689
+ if (t < pp[mid]) {
15690
+ right = mid;
15691
+ } else {
15692
+ i1 = mid + 1;
15693
+ }
15694
+ }
15695
+ t1 = pp[i1];
15696
+ t0 = pp[i1 - 1];
15697
+ if (t0 === void 0) {
15698
+ this._cachedIndex = 0;
15699
+ return this.copySampleValue_(0);
15700
+ }
15701
+ if (t1 === void 0) {
15702
+ i1 = pp.length;
15703
+ this._cachedIndex = i1;
15704
+ return this.copySampleValue_(i1 - 1);
15705
+ }
15706
+ }
15707
+ this._cachedIndex = i1;
15708
+ this.intervalChanged_(i1, t0, t1);
15709
+ }
15710
+ return this.interpolate_(i1, t0, t, t1);
15711
+ }
15712
+ /**
15713
+ * Returns the interpolation settings.
15714
+ *
15715
+ * @return {Object} The interpolation settings.
15716
+ */
15717
+ getSettings_() {
15718
+ return this.settings || this.DefaultSettings_;
15719
+ }
15720
+ /**
15721
+ * Copies a sample value to the result buffer.
15722
+ *
15723
+ * @param {number} index - An index into the sample value buffer.
15724
+ * @return {TypedArray} The result buffer.
15725
+ */
15726
+ copySampleValue_(index) {
15727
+ const result = this.resultBuffer, values = this.sampleValues, stride = this.valueSize, offset = index * stride;
15728
+ for (let i = 0; i !== stride; ++i) {
15729
+ result[i] = values[offset + i];
15730
+ }
15731
+ return result;
15732
+ }
15733
+ /**
15734
+ * Copies a sample value to the result buffer.
15735
+ *
15736
+ * @abstract
15737
+ * @param {number} i1 - An index into the sample value buffer.
15738
+ * @param {number} t0 - The previous interpolation factor.
15739
+ * @param {number} t - The current interpolation factor.
15740
+ * @param {number} t1 - The next interpolation factor.
15741
+ * @return {TypedArray} The result buffer.
15742
+ */
15743
+ interpolate_() {
15744
+ throw new Error("call to abstract method");
15745
+ }
15746
+ /**
15747
+ * Optional method that is executed when the interval has changed.
15748
+ *
15749
+ * @param {number} i1 - An index into the sample value buffer.
15750
+ * @param {number} t0 - The previous interpolation factor.
15751
+ * @param {number} t - The current interpolation factor.
15752
+ */
15753
+ intervalChanged_() {
15754
+ }
15755
+ }
15756
+ class CubicInterpolant extends Interpolant {
15757
+ /**
15758
+ * Constructs a new cubic interpolant.
15759
+ *
15760
+ * @param {TypedArray} parameterPositions - The parameter positions hold the interpolation factors.
15761
+ * @param {TypedArray} sampleValues - The sample values.
15762
+ * @param {number} sampleSize - The sample size
15763
+ * @param {TypedArray} [resultBuffer] - The result buffer.
15764
+ */
15765
+ constructor(parameterPositions, sampleValues, sampleSize, resultBuffer) {
15766
+ super(parameterPositions, sampleValues, sampleSize, resultBuffer);
15767
+ this._weightPrev = -0;
15768
+ this._offsetPrev = -0;
15769
+ this._weightNext = -0;
15770
+ this._offsetNext = -0;
15771
+ this.DefaultSettings_ = {
15772
+ endingStart: ZeroCurvatureEnding,
15773
+ endingEnd: ZeroCurvatureEnding
15774
+ };
15775
+ }
15776
+ intervalChanged_(i1, t0, t1) {
15777
+ const pp = this.parameterPositions;
15778
+ let iPrev = i1 - 2, iNext = i1 + 1, tPrev = pp[iPrev], tNext = pp[iNext];
15779
+ if (tPrev === void 0) {
15780
+ switch (this.getSettings_().endingStart) {
15781
+ case ZeroSlopeEnding:
15782
+ iPrev = i1;
15783
+ tPrev = 2 * t0 - t1;
15784
+ break;
15785
+ case WrapAroundEnding:
15786
+ iPrev = pp.length - 2;
15787
+ tPrev = t0 + pp[iPrev] - pp[iPrev + 1];
15788
+ break;
15789
+ default:
15790
+ iPrev = i1;
15791
+ tPrev = t1;
15792
+ }
15793
+ }
15794
+ if (tNext === void 0) {
15795
+ switch (this.getSettings_().endingEnd) {
15796
+ case ZeroSlopeEnding:
15797
+ iNext = i1;
15798
+ tNext = 2 * t1 - t0;
15799
+ break;
15800
+ case WrapAroundEnding:
15801
+ iNext = 1;
15802
+ tNext = t1 + pp[1] - pp[0];
15803
+ break;
15804
+ default:
15805
+ iNext = i1 - 1;
15806
+ tNext = t0;
15807
+ }
15808
+ }
15809
+ const halfDt = (t1 - t0) * 0.5, stride = this.valueSize;
15810
+ this._weightPrev = halfDt / (t0 - tPrev);
15811
+ this._weightNext = halfDt / (tNext - t1);
15812
+ this._offsetPrev = iPrev * stride;
15813
+ this._offsetNext = iNext * stride;
15814
+ }
15815
+ interpolate_(i1, t0, t, t1) {
15816
+ const result = this.resultBuffer, values = this.sampleValues, stride = this.valueSize, o1 = i1 * stride, o0 = o1 - stride, oP = this._offsetPrev, oN = this._offsetNext, wP = this._weightPrev, wN = this._weightNext, p2 = (t - t0) / (t1 - t0), pp = p2 * p2, ppp = pp * p2;
15817
+ const sP = -wP * ppp + 2 * wP * pp - wP * p2;
15818
+ const s0 = (1 + wP) * ppp + (-1.5 - 2 * wP) * pp + (-0.5 + wP) * p2 + 1;
15819
+ const s1 = (-1 - wN) * ppp + (1.5 + wN) * pp + 0.5 * p2;
15820
+ const sN = wN * ppp - wN * pp;
15821
+ for (let i = 0; i !== stride; ++i) {
15822
+ result[i] = sP * values[oP + i] + s0 * values[o0 + i] + s1 * values[o1 + i] + sN * values[oN + i];
15823
+ }
15824
+ return result;
15825
+ }
15826
+ }
15827
+ class LinearInterpolant extends Interpolant {
15828
+ /**
15829
+ * Constructs a new linear interpolant.
15830
+ *
15831
+ * @param {TypedArray} parameterPositions - The parameter positions hold the interpolation factors.
15832
+ * @param {TypedArray} sampleValues - The sample values.
15833
+ * @param {number} sampleSize - The sample size
15834
+ * @param {TypedArray} [resultBuffer] - The result buffer.
15835
+ */
15836
+ constructor(parameterPositions, sampleValues, sampleSize, resultBuffer) {
15837
+ super(parameterPositions, sampleValues, sampleSize, resultBuffer);
15838
+ }
15839
+ interpolate_(i1, t0, t, t1) {
15840
+ const result = this.resultBuffer, values = this.sampleValues, stride = this.valueSize, offset1 = i1 * stride, offset0 = offset1 - stride, weight1 = (t - t0) / (t1 - t0), weight0 = 1 - weight1;
15841
+ for (let i = 0; i !== stride; ++i) {
15842
+ result[i] = values[offset0 + i] * weight0 + values[offset1 + i] * weight1;
15843
+ }
15844
+ return result;
15845
+ }
15846
+ }
15847
+ class DiscreteInterpolant extends Interpolant {
15848
+ /**
15849
+ * Constructs a new discrete interpolant.
15850
+ *
15851
+ * @param {TypedArray} parameterPositions - The parameter positions hold the interpolation factors.
15852
+ * @param {TypedArray} sampleValues - The sample values.
15853
+ * @param {number} sampleSize - The sample size
15854
+ * @param {TypedArray} [resultBuffer] - The result buffer.
15855
+ */
15856
+ constructor(parameterPositions, sampleValues, sampleSize, resultBuffer) {
15857
+ super(parameterPositions, sampleValues, sampleSize, resultBuffer);
15858
+ }
15859
+ interpolate_(i1) {
15860
+ return this.copySampleValue_(i1 - 1);
15861
+ }
15862
+ }
15863
+ class KeyframeTrack {
15864
+ /**
15865
+ * Constructs a new keyframe track.
15866
+ *
15867
+ * @param {string} name - The keyframe track's name.
15868
+ * @param {Array<number>} times - A list of keyframe times.
15869
+ * @param {Array<number|string|boolean>} values - A list of keyframe values.
15870
+ * @param {(InterpolateLinear|InterpolateDiscrete|InterpolateSmooth)} [interpolation] - The interpolation type.
15871
+ */
15872
+ constructor(name, times, values, interpolation) {
15873
+ if (name === void 0) throw new Error("THREE.KeyframeTrack: track name is undefined");
15874
+ if (times === void 0 || times.length === 0) throw new Error("THREE.KeyframeTrack: no keyframes in track named " + name);
15875
+ this.name = name;
15876
+ this.times = convertArray(times, this.TimeBufferType);
15877
+ this.values = convertArray(values, this.ValueBufferType);
15878
+ this.setInterpolation(interpolation || this.DefaultInterpolation);
15879
+ }
15880
+ /**
15881
+ * Converts the keyframe track to JSON.
15882
+ *
15883
+ * @static
15884
+ * @param {KeyframeTrack} track - The keyframe track to serialize.
15885
+ * @return {Object} The serialized keyframe track as JSON.
15886
+ */
15887
+ static toJSON(track) {
15888
+ const trackType = track.constructor;
15889
+ let json;
15890
+ if (trackType.toJSON !== this.toJSON) {
15891
+ json = trackType.toJSON(track);
15892
+ } else {
15893
+ json = {
15894
+ "name": track.name,
15895
+ "times": convertArray(track.times, Array),
15896
+ "values": convertArray(track.values, Array)
15897
+ };
15898
+ const interpolation = track.getInterpolation();
15899
+ if (interpolation !== track.DefaultInterpolation) {
15900
+ json.interpolation = interpolation;
15901
+ }
15902
+ }
15903
+ json.type = track.ValueTypeName;
15904
+ return json;
15905
+ }
15906
+ /**
15907
+ * Factory method for creating a new discrete interpolant.
15908
+ *
15909
+ * @static
15910
+ * @param {TypedArray} [result] - The result buffer.
15911
+ * @return {DiscreteInterpolant} The new interpolant.
15912
+ */
15913
+ InterpolantFactoryMethodDiscrete(result) {
15914
+ return new DiscreteInterpolant(this.times, this.values, this.getValueSize(), result);
15915
+ }
15916
+ /**
15917
+ * Factory method for creating a new linear interpolant.
15918
+ *
15919
+ * @static
15920
+ * @param {TypedArray} [result] - The result buffer.
15921
+ * @return {LinearInterpolant} The new interpolant.
15922
+ */
15923
+ InterpolantFactoryMethodLinear(result) {
15924
+ return new LinearInterpolant(this.times, this.values, this.getValueSize(), result);
15925
+ }
15926
+ /**
15927
+ * Factory method for creating a new smooth interpolant.
15928
+ *
15929
+ * @static
15930
+ * @param {TypedArray} [result] - The result buffer.
15931
+ * @return {CubicInterpolant} The new interpolant.
15932
+ */
15933
+ InterpolantFactoryMethodSmooth(result) {
15934
+ return new CubicInterpolant(this.times, this.values, this.getValueSize(), result);
15935
+ }
15936
+ /**
15937
+ * Defines the interpolation factor method for this keyframe track.
15938
+ *
15939
+ * @param {(InterpolateLinear|InterpolateDiscrete|InterpolateSmooth)} interpolation - The interpolation type.
15940
+ * @return {KeyframeTrack} A reference to this keyframe track.
15941
+ */
15942
+ setInterpolation(interpolation) {
15943
+ let factoryMethod;
15944
+ switch (interpolation) {
15945
+ case InterpolateDiscrete:
15946
+ factoryMethod = this.InterpolantFactoryMethodDiscrete;
15947
+ break;
15948
+ case InterpolateLinear:
15949
+ factoryMethod = this.InterpolantFactoryMethodLinear;
15950
+ break;
15951
+ case InterpolateSmooth:
15952
+ factoryMethod = this.InterpolantFactoryMethodSmooth;
15953
+ break;
15954
+ }
15955
+ if (factoryMethod === void 0) {
15956
+ const message = "unsupported interpolation for " + this.ValueTypeName + " keyframe track named " + this.name;
15957
+ if (this.createInterpolant === void 0) {
15958
+ if (interpolation !== this.DefaultInterpolation) {
15959
+ this.setInterpolation(this.DefaultInterpolation);
15960
+ } else {
15961
+ throw new Error(message);
15962
+ }
15963
+ }
15964
+ console.warn("THREE.KeyframeTrack:", message);
15965
+ return this;
15966
+ }
15967
+ this.createInterpolant = factoryMethod;
15968
+ return this;
15969
+ }
15970
+ /**
15971
+ * Returns the current interpolation type.
15972
+ *
15973
+ * @return {(InterpolateLinear|InterpolateDiscrete|InterpolateSmooth)} The interpolation type.
15974
+ */
15975
+ getInterpolation() {
15976
+ switch (this.createInterpolant) {
15977
+ case this.InterpolantFactoryMethodDiscrete:
15978
+ return InterpolateDiscrete;
15979
+ case this.InterpolantFactoryMethodLinear:
15980
+ return InterpolateLinear;
15981
+ case this.InterpolantFactoryMethodSmooth:
15982
+ return InterpolateSmooth;
15983
+ }
15984
+ }
15985
+ /**
15986
+ * Returns the value size.
15987
+ *
15988
+ * @return {number} The value size.
15989
+ */
15990
+ getValueSize() {
15991
+ return this.values.length / this.times.length;
15992
+ }
15993
+ /**
15994
+ * Moves all keyframes either forward or backward in time.
15995
+ *
15996
+ * @param {number} timeOffset - The offset to move the time values.
15997
+ * @return {KeyframeTrack} A reference to this keyframe track.
15998
+ */
15999
+ shift(timeOffset) {
16000
+ if (timeOffset !== 0) {
16001
+ const times = this.times;
16002
+ for (let i = 0, n = times.length; i !== n; ++i) {
16003
+ times[i] += timeOffset;
16004
+ }
16005
+ }
16006
+ return this;
16007
+ }
16008
+ /**
16009
+ * Scale all keyframe times by a factor (useful for frame - seconds conversions).
16010
+ *
16011
+ * @param {number} timeScale - The time scale.
16012
+ * @return {KeyframeTrack} A reference to this keyframe track.
16013
+ */
16014
+ scale(timeScale) {
16015
+ if (timeScale !== 1) {
16016
+ const times = this.times;
16017
+ for (let i = 0, n = times.length; i !== n; ++i) {
16018
+ times[i] *= timeScale;
16019
+ }
16020
+ }
16021
+ return this;
16022
+ }
16023
+ /**
16024
+ * Removes keyframes before and after animation without changing any values within the defined time range.
16025
+ *
16026
+ * Note: The method does not shift around keys to the start of the track time, because for interpolated
16027
+ * keys this will change their values
16028
+ *
16029
+ * @param {number} startTime - The start time.
16030
+ * @param {number} endTime - The end time.
16031
+ * @return {KeyframeTrack} A reference to this keyframe track.
16032
+ */
16033
+ trim(startTime, endTime) {
16034
+ const times = this.times, nKeys = times.length;
16035
+ let from = 0, to = nKeys - 1;
16036
+ while (from !== nKeys && times[from] < startTime) {
16037
+ ++from;
16038
+ }
16039
+ while (to !== -1 && times[to] > endTime) {
16040
+ --to;
16041
+ }
16042
+ ++to;
16043
+ if (from !== 0 || to !== nKeys) {
16044
+ if (from >= to) {
16045
+ to = Math.max(to, 1);
16046
+ from = to - 1;
16047
+ }
16048
+ const stride = this.getValueSize();
16049
+ this.times = times.slice(from, to);
16050
+ this.values = this.values.slice(from * stride, to * stride);
16051
+ }
16052
+ return this;
16053
+ }
16054
+ /**
16055
+ * Performs minimal validation on the keyframe track. Returns `true` if the values
16056
+ * are valid.
16057
+ *
16058
+ * @return {boolean} Whether the keyframes are valid or not.
16059
+ */
16060
+ validate() {
16061
+ let valid = true;
16062
+ const valueSize = this.getValueSize();
16063
+ if (valueSize - Math.floor(valueSize) !== 0) {
16064
+ console.error("THREE.KeyframeTrack: Invalid value size in track.", this);
16065
+ valid = false;
16066
+ }
16067
+ const times = this.times, values = this.values, nKeys = times.length;
16068
+ if (nKeys === 0) {
16069
+ console.error("THREE.KeyframeTrack: Track is empty.", this);
16070
+ valid = false;
16071
+ }
16072
+ let prevTime = null;
16073
+ for (let i = 0; i !== nKeys; i++) {
16074
+ const currTime = times[i];
16075
+ if (typeof currTime === "number" && isNaN(currTime)) {
16076
+ console.error("THREE.KeyframeTrack: Time is not a valid number.", this, i, currTime);
16077
+ valid = false;
16078
+ break;
16079
+ }
16080
+ if (prevTime !== null && prevTime > currTime) {
16081
+ console.error("THREE.KeyframeTrack: Out of order keys.", this, i, currTime, prevTime);
16082
+ valid = false;
16083
+ break;
16084
+ }
16085
+ prevTime = currTime;
16086
+ }
16087
+ if (values !== void 0) {
16088
+ if (isTypedArray(values)) {
16089
+ for (let i = 0, n = values.length; i !== n; ++i) {
16090
+ const value = values[i];
16091
+ if (isNaN(value)) {
16092
+ console.error("THREE.KeyframeTrack: Value is not a valid number.", this, i, value);
16093
+ valid = false;
16094
+ break;
16095
+ }
16096
+ }
16097
+ }
16098
+ }
16099
+ return valid;
16100
+ }
16101
+ /**
16102
+ * Optimizes this keyframe track by removing equivalent sequential keys (which are
16103
+ * common in morph target sequences).
16104
+ *
16105
+ * @return {AnimationClip} A reference to this animation clip.
16106
+ */
16107
+ optimize() {
16108
+ const times = this.times.slice(), values = this.values.slice(), stride = this.getValueSize(), smoothInterpolation = this.getInterpolation() === InterpolateSmooth, lastIndex = times.length - 1;
16109
+ let writeIndex = 1;
16110
+ for (let i = 1; i < lastIndex; ++i) {
16111
+ let keep = false;
16112
+ const time2 = times[i];
16113
+ const timeNext = times[i + 1];
16114
+ if (time2 !== timeNext && (i !== 1 || time2 !== times[0])) {
16115
+ if (!smoothInterpolation) {
16116
+ const offset = i * stride, offsetP = offset - stride, offsetN = offset + stride;
16117
+ for (let j = 0; j !== stride; ++j) {
16118
+ const value = values[offset + j];
16119
+ if (value !== values[offsetP + j] || value !== values[offsetN + j]) {
16120
+ keep = true;
16121
+ break;
16122
+ }
16123
+ }
16124
+ } else {
16125
+ keep = true;
16126
+ }
16127
+ }
16128
+ if (keep) {
16129
+ if (i !== writeIndex) {
16130
+ times[writeIndex] = times[i];
16131
+ const readOffset = i * stride, writeOffset = writeIndex * stride;
16132
+ for (let j = 0; j !== stride; ++j) {
16133
+ values[writeOffset + j] = values[readOffset + j];
16134
+ }
16135
+ }
16136
+ ++writeIndex;
16137
+ }
16138
+ }
16139
+ if (lastIndex > 0) {
16140
+ times[writeIndex] = times[lastIndex];
16141
+ for (let readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++j) {
16142
+ values[writeOffset + j] = values[readOffset + j];
16143
+ }
16144
+ ++writeIndex;
16145
+ }
16146
+ if (writeIndex !== times.length) {
16147
+ this.times = times.slice(0, writeIndex);
16148
+ this.values = values.slice(0, writeIndex * stride);
16149
+ } else {
16150
+ this.times = times;
16151
+ this.values = values;
16152
+ }
16153
+ return this;
16154
+ }
16155
+ /**
16156
+ * Returns a new keyframe track with copied values from this instance.
16157
+ *
16158
+ * @return {KeyframeTrack} A clone of this instance.
16159
+ */
16160
+ clone() {
16161
+ const times = this.times.slice();
16162
+ const values = this.values.slice();
16163
+ const TypedKeyframeTrack = this.constructor;
16164
+ const track = new TypedKeyframeTrack(this.name, times, values);
16165
+ track.createInterpolant = this.createInterpolant;
16166
+ return track;
16167
+ }
16168
+ }
16169
+ KeyframeTrack.prototype.ValueTypeName = "";
16170
+ KeyframeTrack.prototype.TimeBufferType = Float32Array;
16171
+ KeyframeTrack.prototype.ValueBufferType = Float32Array;
16172
+ KeyframeTrack.prototype.DefaultInterpolation = InterpolateLinear;
16173
+ class BooleanKeyframeTrack extends KeyframeTrack {
16174
+ /**
16175
+ * Constructs a new boolean keyframe track.
16176
+ *
16177
+ * This keyframe track type has no `interpolation` parameter because the
16178
+ * interpolation is always discrete.
16179
+ *
16180
+ * @param {string} name - The keyframe track's name.
16181
+ * @param {Array<number>} times - A list of keyframe times.
16182
+ * @param {Array<boolean>} values - A list of keyframe values.
16183
+ */
16184
+ constructor(name, times, values) {
16185
+ super(name, times, values);
16186
+ }
16187
+ }
16188
+ BooleanKeyframeTrack.prototype.ValueTypeName = "bool";
16189
+ BooleanKeyframeTrack.prototype.ValueBufferType = Array;
16190
+ BooleanKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete;
16191
+ BooleanKeyframeTrack.prototype.InterpolantFactoryMethodLinear = void 0;
16192
+ BooleanKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = void 0;
16193
+ class ColorKeyframeTrack extends KeyframeTrack {
16194
+ /**
16195
+ * Constructs a new color keyframe track.
16196
+ *
16197
+ * @param {string} name - The keyframe track's name.
16198
+ * @param {Array<number>} times - A list of keyframe times.
16199
+ * @param {Array<number>} values - A list of keyframe values.
16200
+ * @param {(InterpolateLinear|InterpolateDiscrete|InterpolateSmooth)} [interpolation] - The interpolation type.
16201
+ */
16202
+ constructor(name, times, values, interpolation) {
16203
+ super(name, times, values, interpolation);
16204
+ }
16205
+ }
16206
+ ColorKeyframeTrack.prototype.ValueTypeName = "color";
16207
+ class NumberKeyframeTrack extends KeyframeTrack {
16208
+ /**
16209
+ * Constructs a new number keyframe track.
16210
+ *
16211
+ * @param {string} name - The keyframe track's name.
16212
+ * @param {Array<number>} times - A list of keyframe times.
16213
+ * @param {Array<number>} values - A list of keyframe values.
16214
+ * @param {(InterpolateLinear|InterpolateDiscrete|InterpolateSmooth)} [interpolation] - The interpolation type.
16215
+ */
16216
+ constructor(name, times, values, interpolation) {
16217
+ super(name, times, values, interpolation);
16218
+ }
16219
+ }
16220
+ NumberKeyframeTrack.prototype.ValueTypeName = "number";
16221
+ class QuaternionLinearInterpolant extends Interpolant {
16222
+ /**
16223
+ * Constructs a new SLERP interpolant.
16224
+ *
16225
+ * @param {TypedArray} parameterPositions - The parameter positions hold the interpolation factors.
16226
+ * @param {TypedArray} sampleValues - The sample values.
16227
+ * @param {number} sampleSize - The sample size
16228
+ * @param {TypedArray} [resultBuffer] - The result buffer.
16229
+ */
16230
+ constructor(parameterPositions, sampleValues, sampleSize, resultBuffer) {
16231
+ super(parameterPositions, sampleValues, sampleSize, resultBuffer);
16232
+ }
16233
+ interpolate_(i1, t0, t, t1) {
16234
+ const result = this.resultBuffer, values = this.sampleValues, stride = this.valueSize, alpha = (t - t0) / (t1 - t0);
16235
+ let offset = i1 * stride;
16236
+ for (let end = offset + stride; offset !== end; offset += 4) {
16237
+ Quaternion.slerpFlat(result, 0, values, offset - stride, values, offset, alpha);
16238
+ }
16239
+ return result;
16240
+ }
16241
+ }
16242
+ class QuaternionKeyframeTrack extends KeyframeTrack {
16243
+ /**
16244
+ * Constructs a new Quaternion keyframe track.
16245
+ *
16246
+ * @param {string} name - The keyframe track's name.
16247
+ * @param {Array<number>} times - A list of keyframe times.
16248
+ * @param {Array<number>} values - A list of keyframe values.
16249
+ * @param {(InterpolateLinear|InterpolateDiscrete|InterpolateSmooth)} [interpolation] - The interpolation type.
16250
+ */
16251
+ constructor(name, times, values, interpolation) {
16252
+ super(name, times, values, interpolation);
16253
+ }
16254
+ /**
16255
+ * Overwritten so the method returns Quaternion based interpolant.
16256
+ *
16257
+ * @static
16258
+ * @param {TypedArray} [result] - The result buffer.
16259
+ * @return {QuaternionLinearInterpolant} The new interpolant.
16260
+ */
16261
+ InterpolantFactoryMethodLinear(result) {
16262
+ return new QuaternionLinearInterpolant(this.times, this.values, this.getValueSize(), result);
16263
+ }
16264
+ }
16265
+ QuaternionKeyframeTrack.prototype.ValueTypeName = "quaternion";
16266
+ QuaternionKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = void 0;
16267
+ class StringKeyframeTrack extends KeyframeTrack {
16268
+ /**
16269
+ * Constructs a new string keyframe track.
16270
+ *
16271
+ * This keyframe track type has no `interpolation` parameter because the
16272
+ * interpolation is always discrete.
16273
+ *
16274
+ * @param {string} name - The keyframe track's name.
16275
+ * @param {Array<number>} times - A list of keyframe times.
16276
+ * @param {Array<string>} values - A list of keyframe values.
16277
+ */
16278
+ constructor(name, times, values) {
16279
+ super(name, times, values);
16280
+ }
16281
+ }
16282
+ StringKeyframeTrack.prototype.ValueTypeName = "string";
16283
+ StringKeyframeTrack.prototype.ValueBufferType = Array;
16284
+ StringKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete;
16285
+ StringKeyframeTrack.prototype.InterpolantFactoryMethodLinear = void 0;
16286
+ StringKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = void 0;
16287
+ class VectorKeyframeTrack extends KeyframeTrack {
16288
+ /**
16289
+ * Constructs a new vector keyframe track.
16290
+ *
16291
+ * @param {string} name - The keyframe track's name.
16292
+ * @param {Array<number>} times - A list of keyframe times.
16293
+ * @param {Array<number>} values - A list of keyframe values.
16294
+ * @param {(InterpolateLinear|InterpolateDiscrete|InterpolateSmooth)} [interpolation] - The interpolation type.
16295
+ */
16296
+ constructor(name, times, values, interpolation) {
16297
+ super(name, times, values, interpolation);
16298
+ }
16299
+ }
16300
+ VectorKeyframeTrack.prototype.ValueTypeName = "vector";
16301
+ class AnimationClip {
16302
+ /**
16303
+ * Constructs a new animation clip.
16304
+ *
16305
+ * Note: Instead of instantiating an AnimationClip directly with the constructor, you can
16306
+ * use the static interface of this class for creating clips. In most cases though, animation clips
16307
+ * will automatically be created by loaders when importing animated 3D assets.
16308
+ *
16309
+ * @param {string} [name=''] - The clip's name.
16310
+ * @param {number} [duration=-1] - The clip's duration in seconds. If a negative value is passed,
16311
+ * the duration will be calculated from the passed keyframes.
16312
+ * @param {Array<KeyframeTrack>} tracks - An array of keyframe tracks.
16313
+ * @param {(NormalAnimationBlendMode|AdditiveAnimationBlendMode)} [blendMode=NormalAnimationBlendMode] - Defines how the animation
16314
+ * is blended/combined when two or more animations are simultaneously played.
16315
+ */
16316
+ constructor(name = "", duration = -1, tracks = [], blendMode = NormalAnimationBlendMode) {
16317
+ this.name = name;
16318
+ this.tracks = tracks;
16319
+ this.duration = duration;
16320
+ this.blendMode = blendMode;
16321
+ this.uuid = generateUUID();
16322
+ this.userData = {};
16323
+ if (this.duration < 0) {
16324
+ this.resetDuration();
16325
+ }
16326
+ }
16327
+ /**
16328
+ * Factory method for creating an animation clip from the given JSON.
16329
+ *
16330
+ * @static
16331
+ * @param {Object} json - The serialized animation clip.
16332
+ * @return {AnimationClip} The new animation clip.
16333
+ */
16334
+ static parse(json) {
16335
+ const tracks = [], jsonTracks = json.tracks, frameTime = 1 / (json.fps || 1);
16336
+ for (let i = 0, n = jsonTracks.length; i !== n; ++i) {
16337
+ tracks.push(parseKeyframeTrack(jsonTracks[i]).scale(frameTime));
16338
+ }
16339
+ const clip = new this(json.name, json.duration, tracks, json.blendMode);
16340
+ clip.uuid = json.uuid;
16341
+ clip.userData = JSON.parse(json.userData || "{}");
16342
+ return clip;
16343
+ }
16344
+ /**
16345
+ * Serializes the given animation clip into JSON.
16346
+ *
16347
+ * @static
16348
+ * @param {AnimationClip} clip - The animation clip to serialize.
16349
+ * @return {Object} The JSON object.
16350
+ */
16351
+ static toJSON(clip) {
16352
+ const tracks = [], clipTracks = clip.tracks;
16353
+ const json = {
16354
+ "name": clip.name,
16355
+ "duration": clip.duration,
16356
+ "tracks": tracks,
16357
+ "uuid": clip.uuid,
16358
+ "blendMode": clip.blendMode,
16359
+ "userData": JSON.stringify(clip.userData)
16360
+ };
16361
+ for (let i = 0, n = clipTracks.length; i !== n; ++i) {
16362
+ tracks.push(KeyframeTrack.toJSON(clipTracks[i]));
16363
+ }
16364
+ return json;
16365
+ }
16366
+ /**
16367
+ * Returns a new animation clip from the passed morph targets array of a
16368
+ * geometry, taking a name and the number of frames per second.
16369
+ *
16370
+ * Note: The fps parameter is required, but the animation speed can be
16371
+ * overridden via {@link AnimationAction#setDuration}.
16372
+ *
16373
+ * @static
16374
+ * @param {string} name - The name of the animation clip.
16375
+ * @param {Array<Object>} morphTargetSequence - A sequence of morph targets.
16376
+ * @param {number} fps - The Frames-Per-Second value.
16377
+ * @param {boolean} noLoop - Whether the clip should be no loop or not.
16378
+ * @return {AnimationClip} The new animation clip.
16379
+ */
16380
+ static CreateFromMorphTargetSequence(name, morphTargetSequence, fps, noLoop) {
16381
+ const numMorphTargets = morphTargetSequence.length;
16382
+ const tracks = [];
16383
+ for (let i = 0; i < numMorphTargets; i++) {
16384
+ let times = [];
16385
+ let values = [];
16386
+ times.push(
16387
+ (i + numMorphTargets - 1) % numMorphTargets,
16388
+ i,
16389
+ (i + 1) % numMorphTargets
16390
+ );
16391
+ values.push(0, 1, 0);
16392
+ const order = getKeyframeOrder(times);
16393
+ times = sortedArray(times, 1, order);
16394
+ values = sortedArray(values, 1, order);
16395
+ if (!noLoop && times[0] === 0) {
16396
+ times.push(numMorphTargets);
16397
+ values.push(values[0]);
16398
+ }
16399
+ tracks.push(
16400
+ new NumberKeyframeTrack(
16401
+ ".morphTargetInfluences[" + morphTargetSequence[i].name + "]",
16402
+ times,
16403
+ values
16404
+ ).scale(1 / fps)
16405
+ );
16406
+ }
16407
+ return new this(name, -1, tracks);
16408
+ }
16409
+ /**
16410
+ * Searches for an animation clip by name, taking as its first parameter
16411
+ * either an array of clips, or a mesh or geometry that contains an
16412
+ * array named "animations" property.
16413
+ *
16414
+ * @static
16415
+ * @param {(Array<AnimationClip>|Object3D)} objectOrClipArray - The array or object to search through.
16416
+ * @param {string} name - The name to search for.
16417
+ * @return {?AnimationClip} The found animation clip. Returns `null` if no clip has been found.
16418
+ */
16419
+ static findByName(objectOrClipArray, name) {
16420
+ let clipArray = objectOrClipArray;
16421
+ if (!Array.isArray(objectOrClipArray)) {
16422
+ const o = objectOrClipArray;
16423
+ clipArray = o.geometry && o.geometry.animations || o.animations;
16424
+ }
16425
+ for (let i = 0; i < clipArray.length; i++) {
16426
+ if (clipArray[i].name === name) {
16427
+ return clipArray[i];
16428
+ }
16429
+ }
16430
+ return null;
16431
+ }
16432
+ /**
16433
+ * Returns an array of new AnimationClips created from the morph target
16434
+ * sequences of a geometry, trying to sort morph target names into
16435
+ * animation-group-based patterns like "Walk_001, Walk_002, Run_001, Run_002...".
16436
+ *
16437
+ * See {@link MD2Loader#parse} as an example for how the method should be used.
16438
+ *
16439
+ * @static
16440
+ * @param {Array<Object>} morphTargets - A sequence of morph targets.
16441
+ * @param {number} fps - The Frames-Per-Second value.
16442
+ * @param {boolean} noLoop - Whether the clip should be no loop or not.
16443
+ * @return {Array<AnimationClip>} An array of new animation clips.
16444
+ */
16445
+ static CreateClipsFromMorphTargetSequences(morphTargets, fps, noLoop) {
16446
+ const animationToMorphTargets = {};
16447
+ const pattern = /^([\w-]*?)([\d]+)$/;
16448
+ for (let i = 0, il = morphTargets.length; i < il; i++) {
16449
+ const morphTarget = morphTargets[i];
16450
+ const parts = morphTarget.name.match(pattern);
16451
+ if (parts && parts.length > 1) {
16452
+ const name = parts[1];
16453
+ let animationMorphTargets = animationToMorphTargets[name];
16454
+ if (!animationMorphTargets) {
16455
+ animationToMorphTargets[name] = animationMorphTargets = [];
16456
+ }
16457
+ animationMorphTargets.push(morphTarget);
16458
+ }
16459
+ }
16460
+ const clips = [];
16461
+ for (const name in animationToMorphTargets) {
16462
+ clips.push(this.CreateFromMorphTargetSequence(name, animationToMorphTargets[name], fps, noLoop));
16463
+ }
16464
+ return clips;
16465
+ }
16466
+ /**
16467
+ * Parses the `animation.hierarchy` format and returns a new animation clip.
16468
+ *
16469
+ * @static
16470
+ * @deprecated since r175.
16471
+ * @param {Object} animation - A serialized animation clip as JSON.
16472
+ * @param {Array<Bones>} bones - An array of bones.
16473
+ * @return {?AnimationClip} The new animation clip.
16474
+ */
16475
+ static parseAnimation(animation, bones) {
16476
+ console.warn("THREE.AnimationClip: parseAnimation() is deprecated and will be removed with r185");
16477
+ if (!animation) {
16478
+ console.error("THREE.AnimationClip: No animation in JSONLoader data.");
16479
+ return null;
16480
+ }
16481
+ const addNonemptyTrack = function(trackType, trackName, animationKeys, propertyName, destTracks) {
16482
+ if (animationKeys.length !== 0) {
16483
+ const times = [];
16484
+ const values = [];
16485
+ flattenJSON(animationKeys, times, values, propertyName);
16486
+ if (times.length !== 0) {
16487
+ destTracks.push(new trackType(trackName, times, values));
16488
+ }
16489
+ }
16490
+ };
16491
+ const tracks = [];
16492
+ const clipName = animation.name || "default";
16493
+ const fps = animation.fps || 30;
16494
+ const blendMode = animation.blendMode;
16495
+ let duration = animation.length || -1;
16496
+ const hierarchyTracks = animation.hierarchy || [];
16497
+ for (let h = 0; h < hierarchyTracks.length; h++) {
16498
+ const animationKeys = hierarchyTracks[h].keys;
16499
+ if (!animationKeys || animationKeys.length === 0) continue;
16500
+ if (animationKeys[0].morphTargets) {
16501
+ const morphTargetNames = {};
16502
+ let k;
16503
+ for (k = 0; k < animationKeys.length; k++) {
16504
+ if (animationKeys[k].morphTargets) {
16505
+ for (let m = 0; m < animationKeys[k].morphTargets.length; m++) {
16506
+ morphTargetNames[animationKeys[k].morphTargets[m]] = -1;
16507
+ }
16508
+ }
16509
+ }
16510
+ for (const morphTargetName in morphTargetNames) {
16511
+ const times = [];
16512
+ const values = [];
16513
+ for (let m = 0; m !== animationKeys[k].morphTargets.length; ++m) {
16514
+ const animationKey = animationKeys[k];
16515
+ times.push(animationKey.time);
16516
+ values.push(animationKey.morphTarget === morphTargetName ? 1 : 0);
16517
+ }
16518
+ tracks.push(new NumberKeyframeTrack(".morphTargetInfluence[" + morphTargetName + "]", times, values));
16519
+ }
16520
+ duration = morphTargetNames.length * fps;
16521
+ } else {
16522
+ const boneName = ".bones[" + bones[h].name + "]";
16523
+ addNonemptyTrack(
16524
+ VectorKeyframeTrack,
16525
+ boneName + ".position",
16526
+ animationKeys,
16527
+ "pos",
16528
+ tracks
16529
+ );
16530
+ addNonemptyTrack(
16531
+ QuaternionKeyframeTrack,
16532
+ boneName + ".quaternion",
16533
+ animationKeys,
16534
+ "rot",
16535
+ tracks
16536
+ );
16537
+ addNonemptyTrack(
16538
+ VectorKeyframeTrack,
16539
+ boneName + ".scale",
16540
+ animationKeys,
16541
+ "scl",
16542
+ tracks
16543
+ );
16544
+ }
16545
+ }
16546
+ if (tracks.length === 0) {
16547
+ return null;
16548
+ }
16549
+ const clip = new this(clipName, duration, tracks, blendMode);
16550
+ return clip;
16551
+ }
16552
+ /**
16553
+ * Sets the duration of this clip to the duration of its longest keyframe track.
16554
+ *
16555
+ * @return {AnimationClip} A reference to this animation clip.
16556
+ */
16557
+ resetDuration() {
16558
+ const tracks = this.tracks;
16559
+ let duration = 0;
16560
+ for (let i = 0, n = tracks.length; i !== n; ++i) {
16561
+ const track = this.tracks[i];
16562
+ duration = Math.max(duration, track.times[track.times.length - 1]);
16563
+ }
16564
+ this.duration = duration;
16565
+ return this;
16566
+ }
16567
+ /**
16568
+ * Trims all tracks to the clip's duration.
16569
+ *
16570
+ * @return {AnimationClip} A reference to this animation clip.
16571
+ */
16572
+ trim() {
16573
+ for (let i = 0; i < this.tracks.length; i++) {
16574
+ this.tracks[i].trim(0, this.duration);
16575
+ }
16576
+ return this;
16577
+ }
16578
+ /**
16579
+ * Performs minimal validation on each track in the clip. Returns `true` if all
16580
+ * tracks are valid.
16581
+ *
16582
+ * @return {boolean} Whether the clip's keyframes are valid or not.
16583
+ */
16584
+ validate() {
16585
+ let valid = true;
16586
+ for (let i = 0; i < this.tracks.length; i++) {
16587
+ valid = valid && this.tracks[i].validate();
16588
+ }
16589
+ return valid;
16590
+ }
16591
+ /**
16592
+ * Optimizes each track by removing equivalent sequential keys (which are
16593
+ * common in morph target sequences).
16594
+ *
16595
+ * @return {AnimationClip} A reference to this animation clip.
16596
+ */
16597
+ optimize() {
16598
+ for (let i = 0; i < this.tracks.length; i++) {
16599
+ this.tracks[i].optimize();
16600
+ }
16601
+ return this;
16602
+ }
16603
+ /**
16604
+ * Returns a new animation clip with copied values from this instance.
16605
+ *
16606
+ * @return {AnimationClip} A clone of this instance.
16607
+ */
16608
+ clone() {
16609
+ const tracks = [];
16610
+ for (let i = 0; i < this.tracks.length; i++) {
16611
+ tracks.push(this.tracks[i].clone());
16612
+ }
16613
+ const clip = new this.constructor(this.name, this.duration, tracks, this.blendMode);
16614
+ clip.userData = JSON.parse(JSON.stringify(this.userData));
16615
+ return clip;
16616
+ }
16617
+ /**
16618
+ * Serializes this animation clip into JSON.
16619
+ *
16620
+ * @return {Object} The JSON object.
16621
+ */
16622
+ toJSON() {
16623
+ return this.constructor.toJSON(this);
16624
+ }
16625
+ }
16626
+ function getTrackTypeForValueTypeName(typeName) {
16627
+ switch (typeName.toLowerCase()) {
16628
+ case "scalar":
16629
+ case "double":
16630
+ case "float":
16631
+ case "number":
16632
+ case "integer":
16633
+ return NumberKeyframeTrack;
16634
+ case "vector":
16635
+ case "vector2":
16636
+ case "vector3":
16637
+ case "vector4":
16638
+ return VectorKeyframeTrack;
16639
+ case "color":
16640
+ return ColorKeyframeTrack;
16641
+ case "quaternion":
16642
+ return QuaternionKeyframeTrack;
16643
+ case "bool":
16644
+ case "boolean":
16645
+ return BooleanKeyframeTrack;
16646
+ case "string":
16647
+ return StringKeyframeTrack;
16648
+ }
16649
+ throw new Error("THREE.KeyframeTrack: Unsupported typeName: " + typeName);
16650
+ }
16651
+ function parseKeyframeTrack(json) {
16652
+ if (json.type === void 0) {
16653
+ throw new Error("THREE.KeyframeTrack: track type undefined, can not parse");
16654
+ }
16655
+ const trackType = getTrackTypeForValueTypeName(json.type);
16656
+ if (json.times === void 0) {
16657
+ const times = [], values = [];
16658
+ flattenJSON(json.keys, times, values, "value");
16659
+ json.times = times;
16660
+ json.values = values;
16661
+ }
16662
+ if (trackType.parse !== void 0) {
16663
+ return trackType.parse(json);
16664
+ } else {
16665
+ return new trackType(json.name, json.times, json.values, json.interpolation);
16666
+ }
16667
+ }
15541
16668
  class Light extends Object3D {
15542
16669
  /**
15543
16670
  * Constructs a new light.
@@ -30421,7 +31548,9 @@ class Event {
30421
31548
  return new Connection(callback, this);
30422
31549
  }
30423
31550
  Fire(...args) {
30424
- for (const callback of this._callbacks) {
31551
+ for (let i = this._callbacks.length - 1; i >= 0; i--) {
31552
+ const callback = this._callbacks[i];
31553
+ if (!callback) return;
30425
31554
  callback(...args);
30426
31555
  }
30427
31556
  }
@@ -30432,7 +31561,9 @@ class Event {
30432
31561
  }
30433
31562
  }
30434
31563
  Clear() {
30435
- for (const callback of this._callbacks) {
31564
+ for (let i = this._callbacks.length - 1; i >= 0; i--) {
31565
+ const callback = this._callbacks[i];
31566
+ if (!callback) return;
30436
31567
  this.Disconnect(callback);
30437
31568
  }
30438
31569
  this._callbacks = [];
@@ -42738,6 +43869,7 @@ class ModelLayersDesc {
42738
43869
  targetDeformers;
42739
43870
  targetParents;
42740
43871
  layers;
43872
+ destroyConnection;
42741
43873
  //requires compilation
42742
43874
  _targetMeshes;
42743
43875
  uvToHits;
@@ -43017,16 +44149,23 @@ function getModelLayersDesc(model) {
43017
44149
  if (oldLayerDesc && newLayerDesc.isSame(oldLayerDesc)) {
43018
44150
  return oldLayerDesc;
43019
44151
  } else {
44152
+ oldLayerDesc?.destroyConnection?.Disconnect();
43020
44153
  modelLayers.set(model, newLayerDesc);
44154
+ newLayerDesc.destroyConnection = model.Destroying.Connect(() => {
44155
+ modelLayers.delete(model);
44156
+ newLayerDesc.destroyConnection?.Disconnect();
44157
+ newLayerDesc.destroyConnection = void 0;
44158
+ });
43021
44159
  return newLayerDesc;
43022
44160
  }
43023
44161
  }
43024
44162
  const modelHSRDescs = /* @__PURE__ */ new Map();
43025
- const CACHE_uvToHits = /* @__PURE__ */ new Map();
44163
+ const CACHE_uvToHits = new Cache();
43026
44164
  class HSRDesc {
43027
44165
  layers;
43028
44166
  layerTransparent;
43029
44167
  uvsToHits;
44168
+ destroyConnection;
43030
44169
  isSame(other) {
43031
44170
  if (!this.layers && other.layers || this.layers && !other.layers) {
43032
44171
  return false;
@@ -43212,7 +44351,13 @@ function getModelHSRDesc(model) {
43212
44351
  if (oldLayerDesc && newHSRDesc.isSame(oldLayerDesc)) {
43213
44352
  return oldLayerDesc;
43214
44353
  } else {
44354
+ oldLayerDesc?.destroyConnection?.Disconnect();
43215
44355
  modelHSRDescs.set(model, newHSRDesc);
44356
+ newHSRDesc.destroyConnection = model.Destroying.Connect(() => {
44357
+ modelHSRDescs.delete(model);
44358
+ newHSRDesc.destroyConnection?.Disconnect();
44359
+ newHSRDesc.destroyConnection = void 0;
44360
+ });
43216
44361
  return newHSRDesc;
43217
44362
  }
43218
44363
  }
@@ -43266,7 +44411,7 @@ function buildWedge(x, y, z) {
43266
44411
  mesh.coreMesh.increaseFaces(2 * 5);
43267
44412
  let totalVerts = 0;
43268
44413
  let totalFaces = 0;
43269
- totalVerts = addQuad(mesh, totalVerts, totalFaces, [-x, -y, -z], [x, -y, -z], [x, y, z], [-x, y, z], [0, 1, 0], void 0, void 0, void 0, [0, 0], [1, 0], [1, 1], [0, 1]);
44414
+ totalVerts = addQuad(mesh, totalVerts, totalFaces, [-x, -y, -z], [x, -y, -z], [x, y, z], [-x, y, z], normalize([0, 1, -1]), void 0, void 0, void 0, [0, 0], [1, 0], [1, 1], [0, 1]);
43270
44415
  totalFaces += 2;
43271
44416
  totalVerts = addQuad(mesh, totalVerts, totalFaces, [-x, -y, z], [x, -y, z], [x, -y, -z], [-x, -y, -z], [0, -1, 0], void 0, void 0, void 0, [0, 0], [1, 0], [1, 1], [0, 1]);
43272
44417
  totalFaces += 2;
@@ -43277,7 +44422,7 @@ function buildWedge(x, y, z) {
43277
44422
  addQuad(mesh, totalVerts, totalFaces, [x, y, z], [x, -y, -z], [x, -y, -z], [x, -y, z], [1, 0, 0], void 0, void 0, void 0, [0, 0], [1, 0], [1, 1], [0, 1]);
43278
44423
  return mesh;
43279
44424
  }
43280
- const HSR_CACHE = /* @__PURE__ */ new Map();
44425
+ const HSR_CACHE = new Cache();
43281
44426
  function doHSR(totalUvToHits, targetCage, mesh, moveVerts = true, cacheStr) {
43282
44427
  let closestVertIndexArr = void 0;
43283
44428
  if (cacheStr) {
@@ -43785,7 +44930,7 @@ class MeshDesc {
43785
44930
  }
43786
44931
  threeMesh.castShadow = true;
43787
44932
  threeMesh.geometry = geometry;
43788
- threeMesh.name = this.instance?.PropOrDefault("Name", "Mesh");
44933
+ threeMesh.name = this.instance?.PropOrDefault("Name", "Mesh") + "_" + this.instance?.id;
43789
44934
  threeMesh.scale.set(mesh.size[0], mesh.size[1], mesh.size[2]);
43790
44935
  this.compilationTimestamp = Date.now() / 1e3;
43791
44936
  return threeMesh;
@@ -43818,6 +44963,11 @@ class MeshDesc {
43818
44963
  fromPart(child) {
43819
44964
  this.canHaveSkinning = false;
43820
44965
  if (child.className === "WedgePart") this.shape = "wedge";
44966
+ switch (child.PropOrDefault("Shape", PartType.Block)) {
44967
+ case PartType.Wedge:
44968
+ this.shape = "wedge";
44969
+ break;
44970
+ }
43821
44971
  const specialMesh = child.FindFirstChildOfClass("SpecialMesh");
43822
44972
  if (specialMesh) {
43823
44973
  switch (specialMesh.Property("MeshType")) {
@@ -45324,10 +46474,13 @@ const __vite_glob_0_11 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.de
45324
46474
  function diffCFrame(parent, child) {
45325
46475
  return parent.inverse().multiply(child);
45326
46476
  }
46477
+ function getBoneName(bone) {
46478
+ return bone.userData.name || bone.name.split("_").pop();
46479
+ }
45327
46480
  function boneIsChildOf(bone, parentName) {
45328
46481
  let nextParent = bone.parent;
45329
46482
  while (nextParent) {
45330
- if (nextParent.name === parentName) {
46483
+ if (getBoneName(nextParent) === parentName) {
45331
46484
  return true;
45332
46485
  }
45333
46486
  nextParent = nextParent.parent;
@@ -45355,13 +46508,15 @@ class SkeletonDesc {
45355
46508
  const boneArr = [];
45356
46509
  for (let i = 0; i < skinning.bones.length; i++) {
45357
46510
  const threeBone = new Bone();
45358
- threeBone.name = skinning.bones[i].name || "";
45359
- if (threeBone.name === "HumanoidRootNode") {
45360
- threeBone.name = "HumanoidRootPart";
46511
+ let boneName = skinning.bones[i].name || "";
46512
+ if (boneName === "HumanoidRootNode") {
46513
+ boneName = "HumanoidRootPart";
45361
46514
  }
45362
- if (threeBone.name === "root") {
45363
- threeBone.name = "Root";
46515
+ if (boneName === "root") {
46516
+ boneName = "Root";
45364
46517
  }
46518
+ threeBone.name = "Skeleton_" + this.meshDesc.instance?.id + "_" + boneName;
46519
+ threeBone.userData.name = boneName;
45365
46520
  boneArr.push(threeBone);
45366
46521
  }
45367
46522
  this.bones = boneArr;
@@ -45396,9 +46551,10 @@ class SkeletonDesc {
45396
46551
  throw new Error("FileMesh has no root bone");
45397
46552
  } else {
45398
46553
  log(false, rootBone);
45399
- if (rootBone && rootBone.name !== "Root") {
46554
+ if (rootBone && getBoneName(rootBone) !== "Root") {
45400
46555
  const trueRootBone = new Bone();
45401
- trueRootBone.name = "Root";
46556
+ trueRootBone.name = "Skeleton_" + this.meshDesc.instance?.id + "_Root";
46557
+ trueRootBone.userData.name = "Root";
45402
46558
  trueRootBone.position.set(0, 0, 0);
45403
46559
  trueRootBone.rotation.set(0, 0, 0, "YXZ");
45404
46560
  this.boneSourceParts.unshift(void 0);
@@ -45426,7 +46582,7 @@ class SkeletonDesc {
45426
46582
  }
45427
46583
  getBoneWithName(name) {
45428
46584
  for (const bone of this.bones) {
45429
- if (bone.name === name) {
46585
+ if (getBoneName(bone) === name) {
45430
46586
  return bone;
45431
46587
  }
45432
46588
  }
@@ -45475,13 +46631,13 @@ class SkeletonDesc {
45475
46631
  return sourceNode;
45476
46632
  }
45477
46633
  getBoneWorldCFrame(bone, assembly, selfInstance, includeTransform) {
45478
- const node = assembly.getNode(bone.name);
46634
+ const node = assembly.getNode(getBoneName(bone));
45479
46635
  const selfNode = selfInstance.w.GetAssemblyNode();
45480
46636
  const sourceNode = this.getSourceNode(selfNode, bone, assembly);
45481
- if (bone.name === "Root") {
46637
+ if (getBoneName(bone) === "Root") {
45482
46638
  return assembly.traverseCFrame(selfNode, includeTransform, true);
45483
46639
  } else if (node) {
45484
- if (this.meshDesc.wasDeformed && !this.meshDesc.wasAutoSkinned && bone.name === "Head") {
46640
+ if (this.meshDesc.wasDeformed && !this.meshDesc.wasAutoSkinned && getBoneName(bone) === "Head") {
45485
46641
  const ogCF = assembly.traverseCFrame(node, includeTransform, true);
45486
46642
  const connectorOffset = node.getConnectorOffset(includeTransform).inverse();
45487
46643
  connectorOffset.Orientation = [0, 0, 0];
@@ -45498,7 +46654,7 @@ class SkeletonDesc {
45498
46654
  return this.meshDesc.fileMesh?.facs?.faceBoneNames.includes(boneName);
45499
46655
  }
45500
46656
  addFACS(restCF, bone, assembly) {
45501
- const isFACS = this.isFACS(bone.name);
46657
+ const isFACS = this.isFACS(getBoneName(bone));
45502
46658
  if (!isFACS) return restCF;
45503
46659
  const facsMesh = this.meshDesc.fileMesh;
45504
46660
  const facs = this.meshDesc.fileMesh?.facs;
@@ -45513,7 +46669,7 @@ class SkeletonDesc {
45513
46669
  new FaceControlsWrapper(faceControls);
45514
46670
  for (let j = 0; j < facs.faceBoneNames.length; j++) {
45515
46671
  const boneName = facs.faceBoneNames[j];
45516
- if (boneName === bone.name) {
46672
+ if (boneName === getBoneName(bone)) {
45517
46673
  let totalPosition = new Vector32();
45518
46674
  let totalRotation = new Vector32();
45519
46675
  for (let i = 0; i < facs.faceControlNames.length; i++) {
@@ -45576,7 +46732,7 @@ class SkeletonDesc {
45576
46732
  let parentBone = bone.parent;
45577
46733
  if (!(parentBone instanceof Bone)) parentBone = null;
45578
46734
  if (bone && parentBone) {
45579
- if ((boneIsChildOf(bone, "DynamicHead") || bone.name === "DynamicHead") && this.meshDesc.wasDeformed && !this.meshDesc.wasAutoSkinned) {
46735
+ if ((boneIsChildOf(bone, "DynamicHead") || getBoneName(bone) === "DynamicHead") && this.meshDesc.wasDeformed && !this.meshDesc.wasAutoSkinned) {
45580
46736
  const parentBoneWorldCFrame = this.getOriginalWorldCFrameNoChange(parentBone);
45581
46737
  const boneWorldCFrameNoChange = this.getOriginalWorldCFrameNoChange(bone);
45582
46738
  let diffCF = diffCFrame(parentBoneWorldCFrame, boneWorldCFrameNoChange);
@@ -50589,7 +51745,125 @@ class RBXRendererScene {
50589
51745
  * @param autoDownload If resulting file should be auto downloaded
50590
51746
  * @returns The GLB (buffer) or GLTF (object)
50591
51747
  */
50592
- async exportGLTF(name = "scene", autoDownload = true) {
51748
+ async exportGLTF(name = "scene", autoDownload = true, options) {
51749
+ const actualOptions = {
51750
+ includeAnimations: false,
51751
+ binary: false
51752
+ };
51753
+ if (options) Object.assign(actualOptions, options);
51754
+ const clips = [];
51755
+ let animator = void 0;
51756
+ let allInstances = [];
51757
+ let rootInstance = void 0;
51758
+ const allRenderedInstances = Array.from(this.renderDescs.keys());
51759
+ let parent = allRenderedInstances[0].parent;
51760
+ while (parent !== void 0) {
51761
+ if (parent.parent === void 0) {
51762
+ rootInstance = parent;
51763
+ allInstances = [parent, ...parent.GetDescendants()];
51764
+ break;
51765
+ }
51766
+ parent = parent.parent;
51767
+ }
51768
+ for (const instance of allInstances) {
51769
+ if (instance.className === "Animator") {
51770
+ animator = instance;
51771
+ break;
51772
+ }
51773
+ }
51774
+ const GLTF_FPS = 30;
51775
+ if (animator && actualOptions.includeAnimations && rootInstance) {
51776
+ const w = animator.w;
51777
+ for (const animationEntryKey of Object.keys(w.data.animationSet)) {
51778
+ let trackIndex = 0;
51779
+ for (const animationEntry of w.data.animationSet[animationEntryKey]) {
51780
+ const track = w._getTrack(animationEntry.id);
51781
+ if (track) {
51782
+ const objectPositions = /* @__PURE__ */ new Map();
51783
+ const objectRotations = /* @__PURE__ */ new Map();
51784
+ const bonePositions = /* @__PURE__ */ new Map();
51785
+ const boneQuaternions = /* @__PURE__ */ new Map();
51786
+ track.weight = 1;
51787
+ const times = [];
51788
+ for (let i = 0; i < Math.max(1, Math.ceil(track.length * GLTF_FPS)); i++) {
51789
+ w.restPose();
51790
+ track.setTime(i / GLTF_FPS);
51791
+ if (w.data.currentMoodAnimationTrack) w.data.currentMoodAnimationTrack.setTime(0);
51792
+ times.push(i / GLTF_FPS);
51793
+ rootInstance.preRender();
51794
+ RBXRenderer.addInstance(rootInstance, new Authentication(), this);
51795
+ for (const instance of allRenderedInstances) {
51796
+ if (instance.className === "Attachment") continue;
51797
+ let isSkinned = false;
51798
+ const renderDesc = this.renderDescs.get(instance);
51799
+ if (renderDesc && renderDesc instanceof ObjectDesc && renderDesc.skeletonDesc) {
51800
+ isSkinned = true;
51801
+ const bones = renderDesc.skeletonDesc.bones;
51802
+ for (const bone of bones) {
51803
+ if (!bonePositions.has(bone)) bonePositions.set(bone, []);
51804
+ if (!boneQuaternions.has(bone)) boneQuaternions.set(bone, []);
51805
+ bonePositions.get(bone).push(bone.position.toArray());
51806
+ boneQuaternions.get(bone).push(bone.quaternion.toArray());
51807
+ }
51808
+ }
51809
+ let partToUse = instance;
51810
+ if (partToUse.className === "Decal" && partToUse.parent) {
51811
+ partToUse = partToUse.parent;
51812
+ }
51813
+ let cf = partToUse.PropOrDefault("CFrame", new CFrame());
51814
+ if (isSkinned) {
51815
+ cf = new CFrame();
51816
+ }
51817
+ if (!objectPositions.has(instance)) objectPositions.set(instance, []);
51818
+ if (!objectRotations.has(instance)) objectRotations.set(instance, []);
51819
+ objectPositions.get(instance).push(cf.Position);
51820
+ objectRotations.get(instance).push([rad(cf.Orientation[0]), rad(cf.Orientation[1]), rad(cf.Orientation[2])]);
51821
+ }
51822
+ }
51823
+ const keyframeTracks = [];
51824
+ for (const instance of allRenderedInstances) {
51825
+ if (instance.className === "Attachment") continue;
51826
+ const thisPositions = objectPositions.get(instance);
51827
+ const thisRotations = objectRotations.get(instance);
51828
+ if (thisPositions && thisRotations) {
51829
+ const instanceName = instance.PropOrDefault("Name", "Mesh") + "_" + instance.id;
51830
+ keyframeTracks.push(new VectorKeyframeTrack(instanceName + ".position", times, thisPositions.flat()));
51831
+ const quaternionValues = [];
51832
+ for (const rotationValue of thisRotations) {
51833
+ const quat = new Quaternion().setFromEuler(new Euler(...rotationValue, "YXZ"));
51834
+ quaternionValues.push(quat.x, quat.y, quat.z, quat.w);
51835
+ }
51836
+ keyframeTracks.push(new QuaternionKeyframeTrack(instanceName + ".quaternion", times, quaternionValues));
51837
+ }
51838
+ const renderDesc = this.renderDescs.get(instance);
51839
+ if (renderDesc && renderDesc instanceof ObjectDesc && renderDesc.skeletonDesc) {
51840
+ const bones = renderDesc.skeletonDesc.bones;
51841
+ for (const bone of bones) {
51842
+ const thisBonePositions = bonePositions.get(bone);
51843
+ const thisBoneQuaternions = boneQuaternions.get(bone);
51844
+ if (thisBonePositions && thisBoneQuaternions) {
51845
+ keyframeTracks.push(new VectorKeyframeTrack(bone.name + ".position", times, thisBonePositions.flat()));
51846
+ keyframeTracks.push(new QuaternionKeyframeTrack(bone.name + ".quaternion", times, thisBoneQuaternions.flat()));
51847
+ }
51848
+ }
51849
+ }
51850
+ }
51851
+ const clip = new AnimationClip(animationEntryKey + "_" + trackIndex, track.length, keyframeTracks);
51852
+ clips.push(clip);
51853
+ console.log(`Generated clip (${clip.name}) with ${clip.tracks.length} tracks and length of ${track.length}`);
51854
+ }
51855
+ trackIndex += 1;
51856
+ }
51857
+ }
51858
+ w.restPose();
51859
+ rootInstance.preRender();
51860
+ RBXRenderer.addInstance(rootInstance, new Authentication(), this);
51861
+ }
51862
+ for (const renderedInstance of allRenderedInstances) {
51863
+ if (this.renderDescs.get(renderedInstance) instanceof EmitterGroupDesc) {
51864
+ RBXRenderer.removeInstance(renderedInstance, this);
51865
+ }
51866
+ }
50593
51867
  return new Promise((resolve, reject) => {
50594
51868
  const exporter = new GLTFExporter();
50595
51869
  exporter.parse(this.scene, (gltf) => {
@@ -50603,6 +51877,9 @@ class RBXRendererScene {
50603
51877
  resolve(gltf);
50604
51878
  }, (error2) => {
50605
51879
  reject(error2);
51880
+ }, {
51881
+ animations: clips,
51882
+ binary: actualOptions.binary
50606
51883
  });
50607
51884
  });
50608
51885
  }
@@ -51772,7 +53049,7 @@ async function renderTargetToCanvas(renderTarget) {
51772
53049
  await rbxRenderer.readRenderTargetPixelsAsync(renderTarget, 0, 0, width, height, data);
51773
53050
  return imageDataToCanvas(data, width, height);
51774
53051
  }
51775
- async function generateModelThumbnail(auth, renderScene, model, size = [150, 150], type = "png", quality = 1, gltfAutoDownload = false) {
53052
+ async function generateModelThumbnail(auth, renderScene, model, size = [150, 150], type = "png", quality = 1, gltfAutoDownload = false, includeAnimations = false) {
51776
53053
  return new Promise((resolve) => {
51777
53054
  const cameraCFrame = getThumbnailCameraCFrame(model);
51778
53055
  if (cameraCFrame) {
@@ -51791,11 +53068,14 @@ async function generateModelThumbnail(auth, renderScene, model, size = [150, 150
51791
53068
  });
51792
53069
  async function doExport() {
51793
53070
  onLoadingConnection.Disconnect();
51794
- if (type === "gltf") {
53071
+ if (type === "gltf" || type === "glb") {
51795
53072
  if (!FLAGS.RENDERTARGET_TO_CANVASTEXTURE && FLAGS.USE_RENDERTARGET) {
51796
53073
  warn(true, "FLAGS.RENDERTARGET_TO_CANVASTEXTURE is false, GLTF export cannot export render target textures, consider setting this flag to true");
51797
53074
  }
51798
- resolve(await renderScene.exportGLTF(`result`, gltfAutoDownload));
53075
+ resolve(await renderScene.exportGLTF(`result`, gltfAutoDownload, {
53076
+ includeAnimations,
53077
+ binary: type === "glb"
53078
+ }));
51799
53079
  } else {
51800
53080
  const renderTarget = renderToRenderTarget(...size, renderScene);
51801
53081
  const canvasTarget = await renderTargetToCanvas(renderTarget);
@@ -51809,7 +53089,7 @@ async function generateModelThumbnail(auth, renderScene, model, size = [150, 150
51809
53089
  }
51810
53090
  });
51811
53091
  }
51812
- async function generateOutfitThumbnail(auth, outfit, size = [150, 150], type = "png", quality = 1, gltfAutoDownload = false) {
53092
+ async function generateOutfitThumbnail(auth, outfit, size = [150, 150], type = "png", quality = 1, gltfAutoDownload = false, includeAnimations = false) {
51813
53093
  return new Promise((resolve) => {
51814
53094
  const startTime = performance.now();
51815
53095
  const renderScene = RBXRenderer.addScene();
@@ -51849,7 +53129,7 @@ async function generateOutfitThumbnail(auth, outfit, size = [150, 150], type = "
51849
53129
  onLoadingConnection.Disconnect();
51850
53130
  if (outfitRenderer.currentRig) {
51851
53131
  outfitRenderer.animateOnce(!outfit.containsAssetType("Gear") && outfit.playerAvatarType === AvatarType.R6 ? 0 : 1);
51852
- const thumbnailResult = await generateModelThumbnail(auth, renderScene, outfitRenderer.currentRig, size, type, quality, gltfAutoDownload);
53132
+ const thumbnailResult = await generateModelThumbnail(auth, renderScene, outfitRenderer.currentRig, size, type, quality, gltfAutoDownload, includeAnimations);
51853
53133
  console.log("Generated outfit thumbnail after seconds:", (performance.now() - startTime) / 1e3);
51854
53134
  resolve(thumbnailResult);
51855
53135
  if (outfitRenderer.currentRig) outfitRenderer.currentRig.Destroy();
@@ -51934,6 +53214,7 @@ export {
51934
53214
  CACHE,
51935
53215
  CFrame,
51936
53216
  COREMESH,
53217
+ Cache,
51937
53218
  CatalogBundleTypes,
51938
53219
  CategoryDictionary,
51939
53220
  Color3,