@babylonjs/loaders 9.26.0 → 9.26.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 (129) hide show
  1. package/FBX/fbxConstraintBehavior.d.ts +188 -0
  2. package/FBX/fbxConstraintBehavior.js +532 -0
  3. package/FBX/fbxConstraintBehavior.js.map +1 -0
  4. package/FBX/fbxFileLoader.pure.d.ts +175 -6
  5. package/FBX/fbxFileLoader.pure.js +1521 -286
  6. package/FBX/fbxFileLoader.pure.js.map +1 -1
  7. package/FBX/index.d.ts +4 -1
  8. package/FBX/index.js +1 -0
  9. package/FBX/index.js.map +1 -1
  10. package/FBX/interpreter/animation.d.ts +73 -33
  11. package/FBX/interpreter/animation.js +620 -223
  12. package/FBX/interpreter/animation.js.map +1 -1
  13. package/FBX/interpreter/animationCurve.d.ts +91 -0
  14. package/FBX/interpreter/animationCurve.js +623 -0
  15. package/FBX/interpreter/animationCurve.js.map +1 -0
  16. package/FBX/interpreter/blendShapes.js +9 -18
  17. package/FBX/interpreter/blendShapes.js.map +1 -1
  18. package/FBX/interpreter/connections.d.ts +1 -1
  19. package/FBX/interpreter/connections.js +173 -34
  20. package/FBX/interpreter/connections.js.map +1 -1
  21. package/FBX/interpreter/constraints.d.ts +68 -0
  22. package/FBX/interpreter/constraints.js +143 -0
  23. package/FBX/interpreter/constraints.js.map +1 -0
  24. package/FBX/interpreter/fbxInterpreter.d.ts +89 -4
  25. package/FBX/interpreter/fbxInterpreter.js +474 -122
  26. package/FBX/interpreter/fbxInterpreter.js.map +1 -1
  27. package/FBX/interpreter/geometry.d.ts +1 -1
  28. package/FBX/interpreter/geometry.js +150 -92
  29. package/FBX/interpreter/geometry.js.map +1 -1
  30. package/FBX/interpreter/legacyDocument.d.ts +11 -0
  31. package/FBX/interpreter/legacyDocument.js +425 -0
  32. package/FBX/interpreter/legacyDocument.js.map +1 -0
  33. package/FBX/interpreter/materialModel.d.ts +71 -0
  34. package/FBX/interpreter/materialModel.js +622 -0
  35. package/FBX/interpreter/materialModel.js.map +1 -0
  36. package/FBX/interpreter/materials.d.ts +13 -1
  37. package/FBX/interpreter/materials.js +88 -5
  38. package/FBX/interpreter/materials.js.map +1 -1
  39. package/FBX/interpreter/nodeTransform.d.ts +32 -0
  40. package/FBX/interpreter/nodeTransform.js +54 -0
  41. package/FBX/interpreter/nodeTransform.js.map +1 -0
  42. package/FBX/interpreter/nurbs.d.ts +99 -0
  43. package/FBX/interpreter/nurbs.js +627 -0
  44. package/FBX/interpreter/nurbs.js.map +1 -0
  45. package/FBX/interpreter/propertyTemplates.d.ts +23 -0
  46. package/FBX/interpreter/propertyTemplates.js +109 -2
  47. package/FBX/interpreter/propertyTemplates.js.map +1 -1
  48. package/FBX/interpreter/rig.js +16 -0
  49. package/FBX/interpreter/rig.js.map +1 -1
  50. package/FBX/interpreter/sceneDiagnostics.js +28 -3
  51. package/FBX/interpreter/sceneDiagnostics.js.map +1 -1
  52. package/FBX/interpreter/skeleton.d.ts +4 -18
  53. package/FBX/interpreter/skeleton.js +16 -94
  54. package/FBX/interpreter/skeleton.js.map +1 -1
  55. package/FBX/parsers/fbxAsciiParser.js +119 -9
  56. package/FBX/parsers/fbxAsciiParser.js.map +1 -1
  57. package/FBX/parsers/fbxBinaryParser.js +74 -22
  58. package/FBX/parsers/fbxBinaryParser.js.map +1 -1
  59. package/FBX/pure.d.ts +1 -0
  60. package/FBX/pure.js +1 -0
  61. package/FBX/pure.js.map +1 -1
  62. package/FBX/types/fbxTypes.d.ts +18 -2
  63. package/FBX/types/fbxTypes.js +40 -12
  64. package/FBX/types/fbxTypes.js.map +1 -1
  65. package/SPLAT/gaussianSplattingStream.d.ts +79 -25
  66. package/SPLAT/gaussianSplattingStream.js +320 -95
  67. package/SPLAT/gaussianSplattingStream.js.map +1 -1
  68. package/USD/usdCommandProtocol.d.ts +20 -4
  69. package/USD/usdCommandProtocol.js +25 -3
  70. package/USD/usdCommandProtocol.js.map +1 -1
  71. package/USD/usdFileLoader.pure.js +2 -0
  72. package/USD/usdFileLoader.pure.js.map +1 -1
  73. package/USD/usdSceneMaterializer.js +430 -92
  74. package/USD/usdSceneMaterializer.js.map +1 -1
  75. package/glTF/2.0/Extensions/KHR_interactivity/declarationMapper.d.ts +110 -3
  76. package/glTF/2.0/Extensions/KHR_interactivity/declarationMapper.js +468 -74
  77. package/glTF/2.0/Extensions/KHR_interactivity/declarationMapper.js.map +1 -1
  78. package/glTF/2.0/Extensions/KHR_interactivity/flowGraphEventReferenceBlock.d.ts +47 -0
  79. package/glTF/2.0/Extensions/KHR_interactivity/flowGraphEventReferenceBlock.js +68 -0
  80. package/glTF/2.0/Extensions/KHR_interactivity/flowGraphEventReferenceBlock.js.map +1 -0
  81. package/glTF/2.0/Extensions/KHR_interactivity/flowGraphGLTFDataProvider.d.ts +2 -2
  82. package/glTF/2.0/Extensions/KHR_interactivity/flowGraphGLTFDataProvider.js +1 -1
  83. package/glTF/2.0/Extensions/KHR_interactivity/flowGraphGLTFDataProvider.js.map +1 -1
  84. package/glTF/2.0/Extensions/KHR_interactivity/flowGraphObjectReferenceBlock.d.ts +24 -0
  85. package/glTF/2.0/Extensions/KHR_interactivity/flowGraphObjectReferenceBlock.js +38 -0
  86. package/glTF/2.0/Extensions/KHR_interactivity/flowGraphObjectReferenceBlock.js.map +1 -0
  87. package/glTF/2.0/Extensions/KHR_interactivity/flowGraphUnsupportedInteractivityBlock.d.ts +41 -0
  88. package/glTF/2.0/Extensions/KHR_interactivity/flowGraphUnsupportedInteractivityBlock.js +63 -0
  89. package/glTF/2.0/Extensions/KHR_interactivity/flowGraphUnsupportedInteractivityBlock.js.map +1 -0
  90. package/glTF/2.0/Extensions/KHR_interactivity/index.d.ts +5 -0
  91. package/glTF/2.0/Extensions/KHR_interactivity/index.js +5 -0
  92. package/glTF/2.0/Extensions/KHR_interactivity/index.js.map +1 -1
  93. package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphModel.d.ts +112 -0
  94. package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphModel.js +773 -0
  95. package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphModel.js.map +1 -0
  96. package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphParser.d.ts +18 -10
  97. package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphParser.js +299 -54
  98. package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphParser.js.map +1 -1
  99. package/glTF/2.0/Extensions/KHR_interactivity/interactivityHostResolver.d.ts +2 -1
  100. package/glTF/2.0/Extensions/KHR_interactivity/interactivityHostResolver.js +7 -2
  101. package/glTF/2.0/Extensions/KHR_interactivity/interactivityHostResolver.js.map +1 -1
  102. package/glTF/2.0/Extensions/KHR_interactivity/interactivityNodeState.d.ts +24 -0
  103. package/glTF/2.0/Extensions/KHR_interactivity/interactivityNodeState.js +89 -0
  104. package/glTF/2.0/Extensions/KHR_interactivity/interactivityNodeState.js.map +1 -0
  105. package/glTF/2.0/Extensions/KHR_interactivity/pure.d.ts +5 -0
  106. package/glTF/2.0/Extensions/KHR_interactivity/pure.js +5 -0
  107. package/glTF/2.0/Extensions/KHR_interactivity/pure.js.map +1 -1
  108. package/glTF/2.0/Extensions/KHR_interactivity.pure.d.ts +55 -1
  109. package/glTF/2.0/Extensions/KHR_interactivity.pure.js +124 -76
  110. package/glTF/2.0/Extensions/KHR_interactivity.pure.js.map +1 -1
  111. package/glTF/2.0/Extensions/KHR_interactivity.types.d.ts +18 -1
  112. package/glTF/2.0/Extensions/KHR_interactivity.types.js.map +1 -1
  113. package/glTF/2.0/Extensions/KHR_node_hoverability.pure.d.ts +2 -0
  114. package/glTF/2.0/Extensions/KHR_node_hoverability.pure.js +114 -56
  115. package/glTF/2.0/Extensions/KHR_node_hoverability.pure.js.map +1 -1
  116. package/glTF/2.0/Extensions/KHR_node_selectability.pure.d.ts +2 -0
  117. package/glTF/2.0/Extensions/KHR_node_selectability.pure.js +80 -35
  118. package/glTF/2.0/Extensions/KHR_node_selectability.pure.js.map +1 -1
  119. package/glTF/2.0/Extensions/interactivityRefPathToObjectConverter.js +3 -2
  120. package/glTF/2.0/Extensions/interactivityRefPathToObjectConverter.js.map +1 -1
  121. package/glTF/2.0/Extensions/objectModelMapping.d.ts +4 -2
  122. package/glTF/2.0/Extensions/objectModelMapping.js +33 -4
  123. package/glTF/2.0/Extensions/objectModelMapping.js.map +1 -1
  124. package/glTF/2.0/glTFLoader.pure.d.ts +1 -1
  125. package/glTF/2.0/glTFLoader.pure.js +9 -4
  126. package/glTF/2.0/glTFLoader.pure.js.map +1 -1
  127. package/glTF/2.0/glTFLoaderExtension.d.ts +2 -1
  128. package/glTF/2.0/glTFLoaderExtension.js.map +1 -1
  129. package/package.json +3 -3
@@ -0,0 +1,623 @@
1
+ /* eslint-disable @typescript-eslint/naming-convention, jsdoc/require-param, jsdoc/require-returns */
2
+ /**
3
+ * FBX animation curve model and evaluator.
4
+ *
5
+ * Keys carry cubic Bezier tangents expressed the way the FBX SDK stores them: a left and right tangent with a time
6
+ * extent (dx, as a fraction of the segment scaled by the tangent weight) and a value extent (dy). Linear and constant
7
+ * segments are represented the same way so that a single evaluator handles every case, including the weighted
8
+ * tangents Maya and MotionBuilder write, TCB keys, and the pre/post extrapolation modes.
9
+ */
10
+ /** FBX time units: 46186158000 ticks per second */
11
+ export const FBX_TIME_UNIT = 46186158000;
12
+ // Key attribute flags (KeyAttrFlags), as written by the FBX SDK.
13
+ const KEY_INTERPOLATION_CONSTANT = 0x2;
14
+ const KEY_INTERPOLATION_CUBIC = 0x8;
15
+ const KEY_TANGENT_TCB = 0x200;
16
+ const KEY_TANGENT_USER = 0x400;
17
+ const KEY_TANGENT_BROKEN = 0x800;
18
+ const KEY_CONSTANT_NEXT = 0x100;
19
+ const KEY_CLAMP = 0x1000;
20
+ const KEY_TIME_INDEPENDENT = 0x2000;
21
+ const KEY_CLAMP_PROGRESSIVE = 0x4000;
22
+ const KEY_WEIGHTED_RIGHT = 0x1000000;
23
+ const KEY_WEIGHTED_NEXT_LEFT = 0x2000000;
24
+ const DEFAULT_WEIGHT = 0.333333;
25
+ const KEY_CLAMP_THRESHOLD = 0.00001;
26
+ /**
27
+ * Builds keyframes from parallel time/value arrays and their (run-length encoded) attributes, resolving every
28
+ * tangent mode the FBX SDK writes: user, broken, auto (with clamp / progressive clamp / time-independent flags and
29
+ * auto bias), TCB, weighted, linear and constant.
30
+ */
31
+ export function buildKeyframes(times, values, attributes) {
32
+ const numKeys = Math.min(times.length, values.length);
33
+ const keys = [];
34
+ if (numKeys === 0) {
35
+ return keys;
36
+ }
37
+ let slopeLeft = 0;
38
+ let weightLeft = DEFAULT_WEIGHT;
39
+ let prevTime = 0;
40
+ let nextTime = Number(times[0]) / FBX_TIME_UNIT;
41
+ for (let i = 0; i < numKeys; i++) {
42
+ const time = nextTime;
43
+ const value = values[i];
44
+ if (i + 1 < numKeys) {
45
+ nextTime = Number(times[i + 1]) / FBX_TIME_UNIT;
46
+ }
47
+ const prevValue = i > 0 ? values[i - 1] : value;
48
+ const nextValue = i + 1 < numKeys ? values[i + 1] : value;
49
+ const attr = attributes(i);
50
+ const flags = attr.flags;
51
+ let slopeRight = attr.data[0];
52
+ let weightRight = DEFAULT_WEIGHT;
53
+ let nextSlopeLeft = attr.data[1];
54
+ let nextWeightLeft = DEFAULT_WEIGHT;
55
+ if ((flags & (KEY_WEIGHTED_RIGHT | KEY_WEIGHTED_NEXT_LEFT)) !== 0) {
56
+ // Two 0.4 decimal fixed point weights packed into the bit pattern of the third float.
57
+ const packed = floatToUint32Bits(attr.data[2]);
58
+ if (flags & KEY_WEIGHTED_RIGHT) {
59
+ weightRight = (packed & 0xffff) * 0.0001;
60
+ }
61
+ if (flags & KEY_WEIGHTED_NEXT_LEFT) {
62
+ nextWeightLeft = (packed >>> 16) * 0.0001;
63
+ }
64
+ }
65
+ let interpolation;
66
+ let constantMode = "standard";
67
+ if (flags & KEY_INTERPOLATION_CONSTANT) {
68
+ interpolation = "constant";
69
+ constantMode = flags & KEY_CONSTANT_NEXT ? "next" : "standard";
70
+ weightRight = nextWeightLeft = DEFAULT_WEIGHT;
71
+ slopeRight = nextSlopeLeft = 0;
72
+ }
73
+ else if (flags & KEY_INTERPOLATION_CUBIC) {
74
+ interpolation = "cubic";
75
+ if (flags & KEY_TANGENT_TCB) {
76
+ let tcbSlopeLeft = 0;
77
+ let tcbSlopeRight = 0;
78
+ let edge = false;
79
+ if (i > 0 && time > prevTime) {
80
+ tcbSlopeLeft = (value - prevValue) / (time - prevTime);
81
+ }
82
+ else {
83
+ edge = true;
84
+ }
85
+ if (i + 1 < numKeys && nextTime > time) {
86
+ tcbSlopeRight = (nextValue - value) / (nextTime - time);
87
+ }
88
+ else {
89
+ edge = true;
90
+ }
91
+ const tcb = solveTcb(attr.data[0], attr.data[1], attr.data[2], tcbSlopeLeft, tcbSlopeRight, edge);
92
+ slopeLeft = tcb.left;
93
+ slopeRight = tcb.right;
94
+ nextSlopeLeft = 0;
95
+ nextWeightLeft = DEFAULT_WEIGHT;
96
+ }
97
+ else if (flags & KEY_TANGENT_USER) {
98
+ // User tangents: slopes are stored explicitly. Unified vs broken makes no difference to evaluation.
99
+ void KEY_TANGENT_BROKEN;
100
+ }
101
+ else {
102
+ // Auto tangents
103
+ if (i > 0 && i + 1 < numKeys && time > prevTime && nextTime > time) {
104
+ if (Math.abs(slopeLeft + slopeRight) <= 0.0001) {
105
+ slopeLeft = slopeRight = solveAutoTangent(prevTime, time, nextTime, prevValue, value, nextValue, weightLeft, weightRight, slopeRight, flags);
106
+ }
107
+ else {
108
+ slopeLeft = solveAutoTangent(prevTime, time, nextTime, prevValue, value, nextValue, weightLeft, weightRight, -slopeLeft, flags);
109
+ slopeRight = solveAutoTangent(prevTime, time, nextTime, prevValue, value, nextValue, weightLeft, weightRight, slopeRight, flags);
110
+ }
111
+ }
112
+ else if (i > 0 && time > prevTime) {
113
+ slopeLeft = slopeRight = solveAutoTangentOneSided(prevTime, time, prevValue, value, -slopeLeft, flags);
114
+ }
115
+ else if (i + 1 < numKeys && nextTime > time) {
116
+ slopeLeft = slopeRight = solveAutoTangentOneSided(time, nextTime, value, nextValue, slopeRight, flags);
117
+ }
118
+ else {
119
+ slopeLeft = slopeRight = 0;
120
+ }
121
+ }
122
+ }
123
+ else {
124
+ // Linear or unknown interpolation: tangents match the linear segment with 1/3 weights.
125
+ interpolation = "linear";
126
+ weightRight = DEFAULT_WEIGHT;
127
+ nextWeightLeft = DEFAULT_WEIGHT;
128
+ const deltaTime = nextTime - time;
129
+ slopeRight = nextSlopeLeft = deltaTime > 0 ? (nextValue - value) / deltaTime : 0;
130
+ }
131
+ const key = { time, value, interpolation, constantMode, leftDx: 0, leftDy: 0, rightDx: 0, rightDy: 0 };
132
+ if (time > prevTime) {
133
+ key.leftDx = weightLeft * (time - prevTime);
134
+ key.leftDy = key.leftDx * slopeLeft;
135
+ }
136
+ if (nextTime > time) {
137
+ key.rightDx = weightRight * (nextTime - time);
138
+ key.rightDy = key.rightDx * slopeRight;
139
+ }
140
+ key.rightSlope = slopeRight;
141
+ keys.push(key);
142
+ slopeLeft = nextSlopeLeft;
143
+ weightLeft = nextWeightLeft;
144
+ prevTime = time;
145
+ }
146
+ for (let i = 0; i + 1 < keys.length; i++) {
147
+ const next = keys[i + 1];
148
+ keys[i].nextLeftSlope = next.leftDx > 0 ? next.leftDy / next.leftDx : 0;
149
+ }
150
+ return keys;
151
+ }
152
+ const f32 = new Float32Array(1);
153
+ const u32 = new Uint32Array(f32.buffer);
154
+ function floatToUint32Bits(v) {
155
+ f32[0] = v;
156
+ return u32[0];
157
+ }
158
+ function solveTcb(tension, continuity, bias, slopeLeft, slopeRight, edge) {
159
+ const factor = edge ? 1 : 0.5;
160
+ const d00 = factor * (1 - tension) * (1 + bias) * (1 - continuity);
161
+ const d01 = factor * (1 - tension) * (1 - bias) * (1 + continuity);
162
+ const d10 = factor * (1 - tension) * (1 + bias) * (1 + continuity);
163
+ const d11 = factor * (1 - tension) * (1 - bias) * (1 - continuity);
164
+ return { left: d00 * slopeLeft + d01 * slopeRight, right: d10 * slopeLeft + d11 * slopeRight };
165
+ }
166
+ /** Auto tangent as the FBX SDK computes it, including clamping and auto bias. */
167
+ export function solveAutoTangent(prevTime, time, nextTime, prevValue, value, nextValue, weightLeft, weightRight, autoBias, flags) {
168
+ if (flags & KEY_CLAMP) {
169
+ if (Math.min(Math.abs(prevValue - value), Math.abs(nextValue - value)) <= KEY_CLAMP_THRESHOLD) {
170
+ return 0;
171
+ }
172
+ }
173
+ let slope = (nextValue - prevValue) / (nextTime - prevTime);
174
+ if ((flags & KEY_TIME_INDEPENDENT) === 0) {
175
+ const slopeLeft = (value - prevValue) / (time - prevTime);
176
+ const slopeRight = (nextValue - value) / (nextTime - time);
177
+ const delta = (time - prevTime) / (nextTime - prevTime);
178
+ slope = slope * 0.5 + (slopeLeft * (1 - delta) + slopeRight * delta) * 0.5;
179
+ const biasWeight = Math.abs(autoBias) / 100;
180
+ if (biasWeight > 0.0001) {
181
+ const biasTarget = autoBias > 0 ? slopeRight : slopeLeft;
182
+ const biasDelta = biasTarget - slope;
183
+ slope = slope * (1 - biasWeight) + biasTarget * biasWeight;
184
+ const absBiasWeight = biasWeight - 5;
185
+ if (absBiasWeight > 0) {
186
+ let biasSign = Math.abs(biasDelta) > 0.00001 ? biasDelta : autoBias;
187
+ biasSign = biasSign > 0 ? 1 : -1;
188
+ slope += absBiasWeight * absBiasWeight * biasSign * 40;
189
+ }
190
+ }
191
+ }
192
+ if (flags & KEY_CLAMP_PROGRESSIVE) {
193
+ const slopeSign = slope >= 0 ? 1 : -1;
194
+ let absSlope = slopeSign * slope;
195
+ const rangeLeft = weightLeft * (time - prevTime);
196
+ const rangeRight = weightRight * (nextTime - time);
197
+ let maxLeft = rangeLeft > 0 ? (slopeSign * (value - prevValue)) / rangeLeft : 0;
198
+ let maxRight = rangeRight > 0 ? (slopeSign * (nextValue - value)) / rangeRight : 0;
199
+ if (!(maxLeft > 0)) {
200
+ maxLeft = 0;
201
+ }
202
+ if (!(maxRight > 0)) {
203
+ maxRight = 0;
204
+ }
205
+ absSlope = Math.min(absSlope, maxLeft, maxRight);
206
+ slope = slopeSign * absSlope;
207
+ }
208
+ return slope;
209
+ }
210
+ function solveAutoTangentOneSided(t0, t1, v0, v1, autoBias, flags) {
211
+ if (flags & KEY_CLAMP_PROGRESSIVE) {
212
+ return 0;
213
+ }
214
+ if (flags & KEY_CLAMP) {
215
+ if (Math.abs(v1 - v0) <= KEY_CLAMP_THRESHOLD) {
216
+ return 0;
217
+ }
218
+ }
219
+ let slope = (v1 - v0) / (t1 - t0);
220
+ if ((flags & KEY_TIME_INDEPENDENT) === 0) {
221
+ const absBiasWeight = Math.abs(autoBias) / 100 - 5;
222
+ if (absBiasWeight > 0) {
223
+ slope += absBiasWeight * absBiasWeight * (autoBias > 0 ? 1 : -1) * 40;
224
+ }
225
+ }
226
+ return slope;
227
+ }
228
+ /** Builds a keyframe list from explicit per-key slopes (legacy Takes and synthetic curves). */
229
+ export function keyframesFromSlopes(times, values, interpolation, constantNext, leftSlope, rightSlope, leftWeight, rightWeight) {
230
+ const keys = [];
231
+ for (let i = 0; i < times.length; i++) {
232
+ const key = {
233
+ time: times[i],
234
+ value: values[i],
235
+ interpolation: interpolation[i],
236
+ constantMode: constantNext[i] ? "next" : "standard",
237
+ leftDx: 0,
238
+ leftDy: 0,
239
+ rightDx: 0,
240
+ rightDy: 0,
241
+ rightSlope: rightSlope[i],
242
+ nextLeftSlope: i + 1 < times.length ? leftSlope[i + 1] : undefined,
243
+ };
244
+ if (i > 0 && times[i] > times[i - 1]) {
245
+ key.leftDx = (leftWeight?.[i] ?? DEFAULT_WEIGHT) * (times[i] - times[i - 1]);
246
+ key.leftDy = key.leftDx * leftSlope[i];
247
+ }
248
+ if (i + 1 < times.length && times[i + 1] > times[i]) {
249
+ key.rightDx = (rightWeight?.[i] ?? DEFAULT_WEIGHT) * (times[i + 1] - times[i]);
250
+ key.rightDy = key.rightDx * rightSlope[i];
251
+ }
252
+ keys.push(key);
253
+ }
254
+ return keys;
255
+ }
256
+ /** Reads a `Pre-Extrapolation` / `Post-Extrapolation` block: `Type` is a character code, `Repetition` a count. */
257
+ export function parseExtrapolation(typeValue, repetitionValue) {
258
+ const code = typeof typeValue === "string" ? typeValue.charCodeAt(0) : typeof typeValue === "number" ? typeValue : 0;
259
+ let mode;
260
+ switch (String.fromCharCode(code)) {
261
+ case "A":
262
+ mode = "repeatRelative";
263
+ break;
264
+ case "K":
265
+ mode = "slope";
266
+ break;
267
+ case "M":
268
+ mode = "mirror";
269
+ break;
270
+ case "R":
271
+ mode = "repeat";
272
+ break;
273
+ default:
274
+ mode = "constant";
275
+ }
276
+ let repeatCount = typeof repetitionValue === "number" ? repetitionValue : -1;
277
+ if (repeatCount < 0) {
278
+ repeatCount = -1;
279
+ }
280
+ return { mode, repeatCount };
281
+ }
282
+ function findCubicBezierT(p1, p2, x0) {
283
+ const p1_3 = p1 * 3;
284
+ const p2_3 = p2 * 3;
285
+ const a = p1_3 - p2_3 + 1;
286
+ const b = p2_3 - p1_3 - p1_3;
287
+ const c = p1_3;
288
+ const a_3 = 3 * a;
289
+ const b_2 = 2 * b;
290
+ let t = x0;
291
+ let x1;
292
+ const eps = 8.881784197001252e-16;
293
+ for (let i = 0; i < 11; i++) {
294
+ const t2 = t * t;
295
+ const t3 = t2 * t;
296
+ x1 = a * t3 + b * t2 + c * t - x0;
297
+ const d = a_3 * t2 + b_2 * t + c;
298
+ if (d === 0) {
299
+ break;
300
+ }
301
+ t -= x1 / d;
302
+ if (i >= 2 && Math.abs(x1) <= eps) {
303
+ break;
304
+ }
305
+ }
306
+ return t;
307
+ }
308
+ /**
309
+ * Evaluates a curve at a time in seconds, following the FBX SDK: constant/linear/cubic Bezier segments inside the
310
+ * key range and the curve's pre/post extrapolation outside it.
311
+ */
312
+ /**
313
+ * Tangent handles of the segment between two keys. Keys built by the parsers carry explicit handles; keys that
314
+ * only carry slopes (`rightSlope` / `nextLeftSlope`) get the SDK's default one-third weighting.
315
+ */
316
+ function segmentTangents(prev, next) {
317
+ const dt = next.time - prev.time;
318
+ const hasHandles = Number.isFinite(prev.rightDx) && Number.isFinite(prev.rightDy) && Number.isFinite(next.leftDx) && Number.isFinite(next.leftDy) && (prev.rightDx > 0 || next.leftDx > 0);
319
+ if (hasHandles) {
320
+ return { rightDx: prev.rightDx, rightDy: prev.rightDy, leftDx: next.leftDx, leftDy: next.leftDy };
321
+ }
322
+ const rightSlope = prev.rightSlope ?? 0;
323
+ const leftSlope = prev.nextLeftSlope ?? (next.leftDx > 0 ? next.leftDy / next.leftDx : rightSlope);
324
+ return { rightDx: dt / 3, rightDy: (dt / 3) * rightSlope, leftDx: dt / 3, leftDy: (dt / 3) * leftSlope };
325
+ }
326
+ export function evaluateCurve(curve, time, defaultValue, noExtrapolation = false) {
327
+ if (!curve || curve.keys.length === 0) {
328
+ return defaultValue;
329
+ }
330
+ const keys = curve.keys;
331
+ if (keys.length === 1) {
332
+ return keys[0].value;
333
+ }
334
+ const minTime = keys[0].time;
335
+ const maxTime = keys[keys.length - 1].time;
336
+ if (!noExtrapolation && (time < minTime || time > maxTime)) {
337
+ return extrapolateCurve(curve, time);
338
+ }
339
+ // Binary search for the first key with time > `time`.
340
+ let begin = 0;
341
+ let end = keys.length;
342
+ while (end - begin >= 8) {
343
+ const mid = (begin + end) >> 1;
344
+ if (keys[mid].time <= time) {
345
+ begin = mid + 1;
346
+ }
347
+ else {
348
+ end = mid;
349
+ }
350
+ }
351
+ end = keys.length;
352
+ for (; begin < end; begin++) {
353
+ const next = keys[begin];
354
+ if (next.time <= time) {
355
+ continue;
356
+ }
357
+ if (begin === 0) {
358
+ return next.value;
359
+ }
360
+ const prev = keys[begin - 1];
361
+ if (prev.time === time) {
362
+ return prev.value;
363
+ }
364
+ const rcpDelta = 1 / (next.time - prev.time);
365
+ let t = (time - prev.time) * rcpDelta;
366
+ switch (prev.interpolation) {
367
+ case "constant":
368
+ return prev.constantMode === "next" ? next.value : prev.value;
369
+ case "linear":
370
+ return prev.value * (1 - t) + next.value * t;
371
+ default: {
372
+ const tangents = segmentTangents(prev, next);
373
+ const x1 = tangents.rightDx * rcpDelta;
374
+ const x2 = 1 - tangents.leftDx * rcpDelta;
375
+ t = findCubicBezierT(x1, x2, t);
376
+ const t2 = t * t;
377
+ const t3 = t2 * t;
378
+ const u = 1 - t;
379
+ const u2 = u * u;
380
+ const u3 = u2 * u;
381
+ const y0 = prev.value;
382
+ const y3 = next.value;
383
+ const y1 = y0 + tangents.rightDy;
384
+ const y2 = y3 - tangents.leftDy;
385
+ return u3 * y0 + 3 * (u2 * t * y1 + u * t2 * y2) + t3 * y3;
386
+ }
387
+ }
388
+ }
389
+ return keys[keys.length - 1].value;
390
+ }
391
+ function extrapolateCurve(curve, realTime) {
392
+ const keys = curve.keys;
393
+ const minTime = keys[0].time;
394
+ const maxTime = keys[keys.length - 1].time;
395
+ const pre = realTime < minTime;
396
+ const key = pre ? keys[0] : keys[keys.length - 1];
397
+ const ext = (pre ? curve.preExtrapolation : curve.postExtrapolation) ?? { mode: "constant", repeatCount: -1 };
398
+ if (ext.mode === "constant") {
399
+ return key.value;
400
+ }
401
+ if (ext.mode === "slope") {
402
+ const dx = pre ? key.rightDx : key.leftDx;
403
+ const dy = pre ? key.rightDy : key.leftDy;
404
+ return dx !== 0 ? key.value + dy * ((realTime - key.time) / dx) : key.value;
405
+ }
406
+ if (ext.repeatCount === 0) {
407
+ return key.value;
408
+ }
409
+ // Work in KTime ticks to stay frame exact.
410
+ const scale = FBX_TIME_UNIT;
411
+ const min = Math.round(minTime * scale);
412
+ const max = Math.round(maxTime * scale);
413
+ const time = realTime * scale;
414
+ const delta = pre ? min - time : time - max;
415
+ const duration = max - min;
416
+ if (!(duration >= 1)) {
417
+ return key.value;
418
+ }
419
+ const rep = delta / duration;
420
+ let repN = Math.floor(rep);
421
+ let repD = delta - repN * duration;
422
+ if (ext.repeatCount > 0 && repN >= ext.repeatCount) {
423
+ repN = ext.repeatCount - 1;
424
+ repD = duration;
425
+ }
426
+ if (ext.mode === "mirror") {
427
+ const parity = repN * 0.5 - Math.floor(repN * 0.5);
428
+ if (parity <= 0.25) {
429
+ repD = duration - repD;
430
+ }
431
+ }
432
+ if (pre) {
433
+ repD = duration - repD;
434
+ }
435
+ const newTime = (min + repD) / scale;
436
+ let value = evaluateCurve(curve, newTime, key.value, true);
437
+ if (ext.mode === "repeatRelative") {
438
+ let valueDelta = keys[keys.length - 1].value - keys[0].value;
439
+ if (pre) {
440
+ valueDelta = -valueDelta;
441
+ }
442
+ value += valueDelta * (repN + 1);
443
+ }
444
+ return value;
445
+ }
446
+ const DEG2RAD = Math.PI / 180;
447
+ const RAD2DEG = 180 / Math.PI;
448
+ /** Euler angles in degrees with an FBX rotation order (0=XYZ ... 5=ZYX; spheric falls back to XYZ) to a quaternion. */
449
+ export function eulerToQuat(v, order) {
450
+ const vx = v[0] * (DEG2RAD * 0.5);
451
+ const vy = v[1] * (DEG2RAD * 0.5);
452
+ const vz = v[2] * (DEG2RAD * 0.5);
453
+ const cx = Math.cos(vx), sx = Math.sin(vx);
454
+ const cy = Math.cos(vy), sy = Math.sin(vy);
455
+ const cz = Math.cos(vz), sz = Math.sin(vz);
456
+ switch (order) {
457
+ case 1: // XZY
458
+ return [cx * sy * sz + cy * cz * sx, cx * cz * sy + cy * sx * sz, cx * cy * sz - cz * sx * sy, cx * cy * cz - sx * sy * sz];
459
+ case 2: // YZX
460
+ return [-cx * sy * sz + cy * cz * sx, cx * cz * sy - cy * sx * sz, cx * cy * sz + cz * sx * sy, cx * cy * cz + sx * sy * sz];
461
+ case 3: // YXZ
462
+ return [-cx * sy * sz + cy * cz * sx, cx * cz * sy + cy * sx * sz, cx * cy * sz + cz * sx * sy, cx * cy * cz - sx * sy * sz];
463
+ case 4: // ZXY
464
+ return [cx * sy * sz + cy * cz * sx, cx * cz * sy - cy * sx * sz, cx * cy * sz - cz * sx * sy, cx * cy * cz + sx * sy * sz];
465
+ case 5: // ZYX
466
+ return [cx * sy * sz + cy * cz * sx, cx * cz * sy - cy * sx * sz, cx * cy * sz + cz * sx * sy, cx * cy * cz - sx * sy * sz];
467
+ default: // XYZ
468
+ return [-cx * sy * sz + cy * cz * sx, cx * cz * sy + cy * sx * sz, cx * cy * sz - cz * sx * sy, cx * cy * cz + sx * sy * sz];
469
+ }
470
+ }
471
+ /** Quaternion to Euler angles in degrees for an FBX rotation order (inverse of eulerToQuat). */
472
+ export function quatToEuler(q, order) {
473
+ const eps = 0.999999999;
474
+ const [qx, qy, qz, qw] = q;
475
+ let vx = 0, vy = 0, vz = 0;
476
+ let t;
477
+ const halfPi = Math.PI * 0.5;
478
+ switch (order) {
479
+ case 1: // XZY
480
+ t = 2 * (qw * qz + qx * qy);
481
+ if (Math.abs(t) < eps) {
482
+ vz = Math.asin(t);
483
+ vy = Math.atan2(2 * (qw * qy - qx * qz), 2 * (qw * qw + qx * qx) - 1);
484
+ vx = -Math.atan2(-2 * (qw * qx - qy * qz), 2 * (qw * qw + qy * qy) - 1);
485
+ }
486
+ else {
487
+ vz = Math.sign(t) * halfPi;
488
+ vy = Math.atan2(2 * t * (qw * qx + qy * qz), -t * (2 * qx * qy - 2 * qw * qz));
489
+ }
490
+ break;
491
+ case 2: // YZX
492
+ t = 2 * (qw * qz - qx * qy);
493
+ if (Math.abs(t) < eps) {
494
+ vz = Math.asin(t);
495
+ vx = Math.atan2(2 * (qw * qx + qy * qz), 2 * (qw * qw + qy * qy) - 1);
496
+ vy = -Math.atan2(-2 * (qw * qy + qx * qz), 2 * (qw * qw + qx * qx) - 1);
497
+ }
498
+ else {
499
+ vz = Math.sign(t) * halfPi;
500
+ vx = Math.atan2(-2 * t * (qw * qy - qx * qz), t * (2 * qw * qz + 2 * qx * qy));
501
+ }
502
+ break;
503
+ case 3: // YXZ
504
+ t = 2 * (qw * qx + qy * qz);
505
+ if (Math.abs(t) < eps) {
506
+ vx = Math.asin(t);
507
+ vz = Math.atan2(2 * (qw * qz - qx * qy), 2 * (qw * qw + qy * qy) - 1);
508
+ vy = -Math.atan2(-2 * (qw * qy - qx * qz), 2 * (qw * qw + qz * qz) - 1);
509
+ }
510
+ else {
511
+ vx = Math.sign(t) * halfPi;
512
+ vz = Math.atan2(2 * t * (qw * qy + qx * qz), -t * (2 * qy * qz - 2 * qw * qx));
513
+ }
514
+ break;
515
+ case 4: // ZXY
516
+ t = 2 * (qw * qx - qy * qz);
517
+ if (Math.abs(t) < eps) {
518
+ vx = Math.asin(t);
519
+ vy = Math.atan2(2 * (qw * qy + qx * qz), 2 * (qw * qw + qz * qz) - 1);
520
+ vz = -Math.atan2(-2 * (qw * qz + qx * qy), 2 * (qw * qw + qy * qy) - 1);
521
+ }
522
+ else {
523
+ vx = Math.sign(t) * halfPi;
524
+ vy = Math.atan2(-2 * t * (qw * qz - qx * qy), t * (2 * qw * qx + 2 * qy * qz));
525
+ }
526
+ break;
527
+ case 5: // ZYX
528
+ t = 2 * (qw * qy + qx * qz);
529
+ if (Math.abs(t) < eps) {
530
+ vy = Math.asin(t);
531
+ vx = Math.atan2(2 * (qw * qx - qy * qz), 2 * (qw * qw + qz * qz) - 1);
532
+ vz = -Math.atan2(-2 * (qw * qz - qx * qy), 2 * (qw * qw + qx * qx) - 1);
533
+ }
534
+ else {
535
+ vy = Math.sign(t) * halfPi;
536
+ vx = Math.atan2(2 * t * (qw * qz + qx * qy), -t * (2 * qx * qz - 2 * qw * qy));
537
+ }
538
+ break;
539
+ default: // XYZ
540
+ t = 2 * (qw * qy - qx * qz);
541
+ if (Math.abs(t) < eps) {
542
+ vy = Math.asin(t);
543
+ vz = Math.atan2(2 * (qw * qz + qx * qy), 2 * (qw * qw + qx * qx) - 1);
544
+ vx = -Math.atan2(-2 * (qw * qx + qy * qz), 2 * (qw * qw + qz * qz) - 1);
545
+ }
546
+ else {
547
+ vy = Math.sign(t) * halfPi;
548
+ vz = Math.atan2(-2 * t * (qw * qx - qy * qz), t * (2 * qw * qy + 2 * qx * qz));
549
+ }
550
+ break;
551
+ }
552
+ return [vx * RAD2DEG, vy * RAD2DEG, vz * RAD2DEG];
553
+ }
554
+ function quatMul(a, b) {
555
+ return [
556
+ a[3] * b[0] + a[0] * b[3] + a[1] * b[2] - a[2] * b[1],
557
+ a[3] * b[1] - a[0] * b[2] + a[1] * b[3] + a[2] * b[0],
558
+ a[3] * b[2] + a[0] * b[1] - a[1] * b[0] + a[2] * b[3],
559
+ a[3] * b[3] - a[0] * b[0] - a[1] * b[1] - a[2] * b[2],
560
+ ];
561
+ }
562
+ function quatSlerp(a, b, t) {
563
+ let dot = a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
564
+ let bx = b[0], by = b[1], bz = b[2], bw = b[3];
565
+ if (dot < 0) {
566
+ dot = -dot;
567
+ bx = -bx;
568
+ by = -by;
569
+ bz = -bz;
570
+ bw = -bw;
571
+ }
572
+ let wa;
573
+ let wb;
574
+ if (dot > 0.9995) {
575
+ wa = 1 - t;
576
+ wb = t;
577
+ }
578
+ else {
579
+ const omega = Math.acos(Math.min(1, dot));
580
+ const rcpSin = 1 / Math.sin(omega);
581
+ wa = Math.sin((1 - t) * omega) * rcpSin;
582
+ wb = Math.sin(t * omega) * rcpSin;
583
+ }
584
+ const x = a[0] * wa + bx * wb;
585
+ const y = a[1] * wa + by * wb;
586
+ const z = a[2] * wa + bz * wb;
587
+ const w = a[3] * wa + bw * wb;
588
+ const len = Math.hypot(x, y, z, w) || 1;
589
+ return [x / len, y / len, z / len, w / len];
590
+ }
591
+ function powAbs(v, e) {
592
+ return v >= 0 ? Math.pow(v, e) : -Math.pow(-v, e);
593
+ }
594
+ /**
595
+ * Combines one animation layer's value into the running result, exactly as the FBX SDK evaluator does.
596
+ * `kind` selects the accumulation rule: "R" rotations (degrees, rotation order given), "S" scales, anything else linear.
597
+ */
598
+ export function combineLayerValue(result, value, layer, kind, rotationOrder) {
599
+ const w = layer.weight;
600
+ if (layer.additive) {
601
+ if (layer.composeScale && kind === "S") {
602
+ return [result[0] * powAbs(value[0], w), result[1] * powAbs(value[1], w), result[2] * powAbs(value[2], w)];
603
+ }
604
+ if (layer.composeRotation && kind === "R") {
605
+ const a = eulerToQuat(result, rotationOrder);
606
+ const b = quatSlerp([0, 0, 0, 1], eulerToQuat(value, rotationOrder), w);
607
+ return quatToEuler(quatMul(a, b), rotationOrder);
608
+ }
609
+ return [result[0] + value[0] * w, result[1] + value[1] * w, result[2] + value[2] * w];
610
+ }
611
+ if (layer.blended) {
612
+ const rw = 1 - w;
613
+ if (layer.composeScale && kind === "S") {
614
+ return [powAbs(result[0], rw) * powAbs(value[0], w), powAbs(result[1], rw) * powAbs(value[1], w), powAbs(result[2], rw) * powAbs(value[2], w)];
615
+ }
616
+ if (layer.composeRotation && kind === "R") {
617
+ return quatToEuler(quatSlerp(eulerToQuat(result, rotationOrder), eulerToQuat(value, rotationOrder), w), rotationOrder);
618
+ }
619
+ return [result[0] * rw + value[0] * w, result[1] * rw + value[1] * w, result[2] * rw + value[2] * w];
620
+ }
621
+ return [value[0], value[1], value[2]];
622
+ }
623
+ //# sourceMappingURL=animationCurve.js.map