@babylonjs/loaders 9.25.0 → 9.26.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) 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 +31 -0
  66. package/SPLAT/gaussianSplattingStream.js +49 -0
  67. package/SPLAT/gaussianSplattingStream.js.map +1 -1
  68. package/USD/index.d.ts +2 -0
  69. package/USD/index.js +4 -0
  70. package/USD/index.js.map +1 -0
  71. package/USD/pure.d.ts +3 -0
  72. package/USD/pure.js +5 -0
  73. package/USD/pure.js.map +1 -0
  74. package/USD/usdCommandProtocol.d.ts +83 -0
  75. package/USD/usdCommandProtocol.js +173 -0
  76. package/USD/usdCommandProtocol.js.map +1 -0
  77. package/USD/usdFileLoader.d.ts +6 -0
  78. package/USD/usdFileLoader.js +9 -0
  79. package/USD/usdFileLoader.js.map +1 -0
  80. package/USD/usdFileLoader.metadata.d.ts +20 -0
  81. package/USD/usdFileLoader.metadata.js +18 -0
  82. package/USD/usdFileLoader.metadata.js.map +1 -0
  83. package/USD/usdFileLoader.pure.d.ts +102 -0
  84. package/USD/usdFileLoader.pure.js +341 -0
  85. package/USD/usdFileLoader.pure.js.map +1 -0
  86. package/USD/usdFileLoader.types.d.ts +11 -0
  87. package/USD/usdFileLoader.types.js +2 -0
  88. package/USD/usdFileLoader.types.js.map +1 -0
  89. package/USD/usdLoadingOptions.d.ts +123 -0
  90. package/USD/usdLoadingOptions.js +3 -0
  91. package/USD/usdLoadingOptions.js.map +1 -0
  92. package/USD/usdSceneMaterializer.d.ts +9 -0
  93. package/USD/usdSceneMaterializer.js +982 -0
  94. package/USD/usdSceneMaterializer.js.map +1 -0
  95. package/USD/usdWorkerMessages.d.ts +57 -0
  96. package/USD/usdWorkerMessages.js +3 -0
  97. package/USD/usdWorkerMessages.js.map +1 -0
  98. package/dynamic.js +10 -0
  99. package/dynamic.js.map +1 -1
  100. package/index.d.ts +1 -0
  101. package/index.js +1 -0
  102. package/index.js.map +1 -1
  103. package/package.json +4 -3
  104. package/pure.d.ts +1 -0
  105. package/pure.js +1 -0
  106. package/pure.js.map +1 -1
@@ -1,3 +1,5 @@
1
+ import { type FBXNodeTransformData } from "./nodeTransform.js";
2
+ import { type FBXPropertyTemplate, type FBXPropertyTemplateMap } from "./propertyTemplates.js";
1
3
  import { type FBXNode } from "../types/fbxTypes.js";
2
4
  import { type FBXObjectMap } from "./connections.js";
3
5
  export type FBXClusterMode = "Normalize" | "Additive" | "TotalOne" | "Unknown";
@@ -72,22 +74,6 @@ export interface FBXSkinData {
72
74
  /** Recoverable skinning/bind diagnostics */
73
75
  diagnostics: FBXSkinDiagnostic[];
74
76
  }
75
- /**
76
- * Extract all skin deformers from the FBX scene.
77
- * Returns skin data including bone hierarchy and vertex weights.
78
- */
79
- export declare function extractSkins(objectMap: FBXObjectMap): FBXSkinData[];
77
+ export declare function extractSkins(objectMap: FBXObjectMap, propertyTemplates?: FBXPropertyTemplateMap): FBXSkinData[];
80
78
  export declare function isSkeletonModel(modelNode: FBXNode): boolean;
81
- export declare function extractBoneTransform(modelNode: FBXNode): {
82
- translation: [number, number, number];
83
- rotation: [number, number, number];
84
- preRotation: [number, number, number];
85
- postRotation: [number, number, number];
86
- rotationPivot: [number, number, number];
87
- scalingPivot: [number, number, number];
88
- rotationOffset: [number, number, number];
89
- scalingOffset: [number, number, number];
90
- scale: [number, number, number];
91
- rotationOrder: number;
92
- inheritType: number;
93
- };
79
+ export declare function extractBoneTransform(modelNode: FBXNode, template?: FBXPropertyTemplate): FBXNodeTransformData;
@@ -1,12 +1,17 @@
1
1
  /* eslint-disable @typescript-eslint/naming-convention, jsdoc/require-param, jsdoc/require-returns */
2
- import { findChildByName, getPropertyValue, cleanFBXName } from "../types/fbxTypes.js";
2
+ import { extractNodeTransform } from "./nodeTransform.js";
3
+ import { getPropertyTemplate } from "./propertyTemplates.js";
4
+ import { findChildByName, getPropertyValue, cleanFBXName, getNodeArray } from "../types/fbxTypes.js";
3
5
  import { getChildren } from "./connections.js";
4
6
  const MAX_BONE_INFLUENCES = 8;
5
7
  /**
6
8
  * Extract all skin deformers from the FBX scene.
7
9
  * Returns skin data including bone hierarchy and vertex weights.
8
10
  */
9
- export function extractSkins(objectMap) {
11
+ // Template used to resolve bone transform defaults while extractSkins runs (bones are Models).
12
+ let currentModelTemplate;
13
+ export function extractSkins(objectMap, propertyTemplates) {
14
+ currentModelTemplate = propertyTemplates ? (getPropertyTemplate(propertyTemplates, "Model", "FbxNode") ?? getPropertyTemplate(propertyTemplates, "Model")) : undefined;
10
15
  const skins = [];
11
16
  for (const [id, node] of Array.from(objectMap.objects)) {
12
17
  if (node.name === "Deformer" && getPropertyValue(node, 2) === "Skin") {
@@ -158,7 +163,7 @@ function extractBindPoseMatrices(geometryId, objectMap) {
158
163
  const nodeChild = findChildByName(poseChild, "Node");
159
164
  const matrixChild = findChildByName(poseChild, "Matrix");
160
165
  const nodeId = nodeChild?.properties[0]?.value;
161
- const matrixValue = matrixChild?.properties[0]?.value;
166
+ const matrixValue = getNodeArray(matrixChild);
162
167
  if (typeof nodeId !== "number") {
163
168
  continue;
164
169
  }
@@ -224,85 +229,8 @@ export function isSkeletonModel(modelNode) {
224
229
  const subType = getPropertyValue(modelNode, 2);
225
230
  return subType === "Root" || subType === "LimbNode";
226
231
  }
227
- export function extractBoneTransform(modelNode) {
228
- const translation = [0, 0, 0];
229
- const rotation = [0, 0, 0];
230
- const preRotation = [0, 0, 0];
231
- const postRotation = [0, 0, 0];
232
- const rotationPivot = [0, 0, 0];
233
- const scalingPivot = [0, 0, 0];
234
- const rotationOffset = [0, 0, 0];
235
- const scalingOffset = [0, 0, 0];
236
- const scale = [1, 1, 1];
237
- let rotationOrder = 0;
238
- let inheritType = 1;
239
- const props70 = findChildByName(modelNode, "Properties70");
240
- if (!props70) {
241
- return { translation, rotation, preRotation, postRotation, rotationPivot, scalingPivot, rotationOffset, scalingOffset, scale, rotationOrder, inheritType };
242
- }
243
- for (const p of props70.children) {
244
- if (p.name !== "P") {
245
- continue;
246
- }
247
- const propName = getPropertyValue(p, 0);
248
- if (!propName) {
249
- continue;
250
- }
251
- switch (propName) {
252
- case "Lcl Translation":
253
- translation[0] = toNumber(p.properties[4]?.value) ?? 0;
254
- translation[1] = toNumber(p.properties[5]?.value) ?? 0;
255
- translation[2] = toNumber(p.properties[6]?.value) ?? 0;
256
- break;
257
- case "Lcl Rotation":
258
- rotation[0] = toNumber(p.properties[4]?.value) ?? 0;
259
- rotation[1] = toNumber(p.properties[5]?.value) ?? 0;
260
- rotation[2] = toNumber(p.properties[6]?.value) ?? 0;
261
- break;
262
- case "PreRotation":
263
- preRotation[0] = toNumber(p.properties[4]?.value) ?? 0;
264
- preRotation[1] = toNumber(p.properties[5]?.value) ?? 0;
265
- preRotation[2] = toNumber(p.properties[6]?.value) ?? 0;
266
- break;
267
- case "PostRotation":
268
- postRotation[0] = toNumber(p.properties[4]?.value) ?? 0;
269
- postRotation[1] = toNumber(p.properties[5]?.value) ?? 0;
270
- postRotation[2] = toNumber(p.properties[6]?.value) ?? 0;
271
- break;
272
- case "RotationPivot":
273
- rotationPivot[0] = toNumber(p.properties[4]?.value) ?? 0;
274
- rotationPivot[1] = toNumber(p.properties[5]?.value) ?? 0;
275
- rotationPivot[2] = toNumber(p.properties[6]?.value) ?? 0;
276
- break;
277
- case "ScalingPivot":
278
- scalingPivot[0] = toNumber(p.properties[4]?.value) ?? 0;
279
- scalingPivot[1] = toNumber(p.properties[5]?.value) ?? 0;
280
- scalingPivot[2] = toNumber(p.properties[6]?.value) ?? 0;
281
- break;
282
- case "RotationOffset":
283
- rotationOffset[0] = toNumber(p.properties[4]?.value) ?? 0;
284
- rotationOffset[1] = toNumber(p.properties[5]?.value) ?? 0;
285
- rotationOffset[2] = toNumber(p.properties[6]?.value) ?? 0;
286
- break;
287
- case "ScalingOffset":
288
- scalingOffset[0] = toNumber(p.properties[4]?.value) ?? 0;
289
- scalingOffset[1] = toNumber(p.properties[5]?.value) ?? 0;
290
- scalingOffset[2] = toNumber(p.properties[6]?.value) ?? 0;
291
- break;
292
- case "Lcl Scaling":
293
- scale[0] = toNumber(p.properties[4]?.value) ?? 1;
294
- scale[1] = toNumber(p.properties[5]?.value) ?? 1;
295
- scale[2] = toNumber(p.properties[6]?.value) ?? 1;
296
- break;
297
- case "RotationOrder":
298
- rotationOrder = toNumber(p.properties[4]?.value) ?? 0;
299
- break;
300
- case "InheritType":
301
- inheritType = toNumber(p.properties[4]?.value) ?? 1;
302
- break;
303
- }
304
- }
305
- return { translation, rotation, preRotation, postRotation, rotationPivot, scalingPivot, rotationOffset, scalingOffset, scale, rotationOrder, inheritType };
232
+ export function extractBoneTransform(modelNode, template) {
233
+ return extractNodeTransform(modelNode, template ?? currentModelTemplate);
306
234
  }
307
235
  function extractClusterMatrices(clusterNode) {
308
236
  let bindPoseMatrix = null;
@@ -311,7 +239,7 @@ function extractClusterMatrices(clusterNode) {
311
239
  let clusterMode = "Normalize";
312
240
  const transformNode = findChildByName(clusterNode, "Transform");
313
241
  if (transformNode && transformNode.properties[0]) {
314
- const val = transformNode.properties[0].value;
242
+ const val = getNodeArray(transformNode);
315
243
  if (val instanceof Float64Array && val.length === 16) {
316
244
  bindPoseMatrix = val;
317
245
  }
@@ -321,7 +249,7 @@ function extractClusterMatrices(clusterNode) {
321
249
  }
322
250
  const transformLinkNode = findChildByName(clusterNode, "TransformLink");
323
251
  if (transformLinkNode && transformLinkNode.properties[0]) {
324
- const val = transformLinkNode.properties[0].value;
252
+ const val = getNodeArray(transformLinkNode);
325
253
  if (val instanceof Float64Array && val.length === 16) {
326
254
  transformLinkMatrix = val;
327
255
  }
@@ -331,7 +259,7 @@ function extractClusterMatrices(clusterNode) {
331
259
  }
332
260
  const transformAssociateModelNode = findChildByName(clusterNode, "TransformAssociateModel");
333
261
  if (transformAssociateModelNode && transformAssociateModelNode.properties[0]) {
334
- const val = transformAssociateModelNode.properties[0].value;
262
+ const val = getNodeArray(transformAssociateModelNode);
335
263
  if (val instanceof Float64Array && val.length === 16) {
336
264
  transformAssociateModelMatrix = val;
337
265
  }
@@ -418,7 +346,7 @@ function extractVertexWeights(bones, boneModelMap, objectMap) {
418
346
  if (!indexesNode) {
419
347
  continue;
420
348
  }
421
- const indexes = toInt32Array(indexesNode.properties[0]?.value);
349
+ const indexes = toInt32Array(getNodeArray(indexesNode));
422
350
  if (!indexes) {
423
351
  continue;
424
352
  }
@@ -447,8 +375,8 @@ function extractVertexWeights(bones, boneModelMap, objectMap) {
447
375
  if (!indexesNode || !weightsNode) {
448
376
  continue;
449
377
  }
450
- const indexes = toInt32Array(indexesNode.properties[0]?.value);
451
- const weights = toFloat64Array(weightsNode.properties[0]?.value);
378
+ const indexes = toInt32Array(getNodeArray(indexesNode));
379
+ const weights = toFloat64Array(getNodeArray(weightsNode));
452
380
  if (!indexes || !weights) {
453
381
  continue;
454
382
  }
@@ -484,12 +412,6 @@ function extractVertexWeights(bones, boneModelMap, objectMap) {
484
412
  return { boneIndices, boneWeights };
485
413
  }
486
414
  // ── Utilities ──────────────────────────────────────────────────────────────────
487
- function toNumber(value) {
488
- if (typeof value === "number") {
489
- return value;
490
- }
491
- return undefined;
492
- }
493
415
  function toInt32Array(value) {
494
416
  if (value instanceof Int32Array) {
495
417
  return value;
@@ -1 +1 @@
1
- {"version":3,"file":"skeleton.js","sourceRoot":"","sources":["../../../../../dev/loaders/src/FBX/interpreter/skeleton.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/naming-convention, jsdoc/require-param, jsdoc/require-returns */\r\nimport { type FBXNode, findChildByName, getPropertyValue, cleanFBXName } from \"../types/fbxTypes\";\r\n\r\nimport { type FBXObjectMap, getChildren } from \"./connections\";\r\n\r\nconst MAX_BONE_INFLUENCES = 8;\r\n\r\nexport type FBXClusterMode = \"Normalize\" | \"Additive\" | \"TotalOne\" | \"Unknown\";\r\n\r\nexport interface FBXSkinDiagnostic {\r\n type: \"cluster-mode-runtime-unsupported\" | \"missing-cluster-transform\" | \"missing-cluster-transform-link\" | \"missing-bind-pose-matrix\" | \"associate-model-present\";\r\n message: string;\r\n boneModelId?: number;\r\n boneName?: string;\r\n clusterMode?: FBXClusterMode;\r\n}\r\n\r\n/** Represents a single bone (cluster) in the FBX skeleton */\r\nexport interface FBXBoneData {\r\n /** The Model node ID for this bone */\r\n modelId: number;\r\n /** Bone name (from the Model node) */\r\n name: string;\r\n /** Index of this bone in the skeleton */\r\n index: number;\r\n /** Index of the parent bone (-1 for root) */\r\n parentIndex: number;\r\n /** Whether this bone corresponds to an FBX Cluster with vertex weights */\r\n isCluster: boolean;\r\n /** Local translation from parent (Lcl Translation) */\r\n translation: [number, number, number];\r\n /** Local rotation in degrees (Lcl Rotation) */\r\n rotation: [number, number, number];\r\n /** Pre-rotation in degrees (applied before Lcl Rotation) */\r\n preRotation: [number, number, number];\r\n /** Post-rotation in degrees (applied after Lcl Rotation, inverted) */\r\n postRotation: [number, number, number];\r\n /** Rotation pivot point */\r\n rotationPivot: [number, number, number];\r\n /** Scaling pivot point */\r\n scalingPivot: [number, number, number];\r\n /** Rotation offset */\r\n rotationOffset: [number, number, number];\r\n /** Scaling offset */\r\n scalingOffset: [number, number, number];\r\n /** Local scale (Lcl Scaling) */\r\n scale: [number, number, number];\r\n /** Rotation order: 0=XYZ, 1=XZY, 2=YZX, 3=YXZ, 4=ZXY, 5=ZYX */\r\n rotationOrder: number;\r\n /** FBX transform inheritance mode. 0=RrSs, 1=RSrs, 2=Rrs */\r\n inheritType: number;\r\n /** Cluster skinning mode */\r\n clusterMode: FBXClusterMode;\r\n /** Bind pose transform matrix (cluster Transform, 4x4) */\r\n bindPoseMatrix: Float64Array | null;\r\n /** Bone's world transform at bind time (cluster TransformLink, 4x4) */\r\n transformLinkMatrix: Float64Array | null;\r\n /** Associate model world transform at bind time (cluster TransformAssociateModel, 4x4) */\r\n transformAssociateModelMatrix: Float64Array | null;\r\n /** Model's absolute matrix from the FBX BindPose, when present */\r\n modelBindPoseMatrix: Float64Array | null;\r\n /** Recoverable bind/skinning diagnostics for this bone */\r\n diagnostics: FBXSkinDiagnostic[];\r\n}\r\n\r\n/** Represents a skin deformer with its clusters */\r\nexport interface FBXSkinData {\r\n /** Skin deformer ID */\r\n id: number;\r\n /** Geometry ID this skin is attached to */\r\n geometryId: number;\r\n /** Mesh model world matrix from the FBX BindPose, when present */\r\n meshBindPoseMatrix: Float64Array | null;\r\n /** Bones in this skeleton */\r\n bones: FBXBoneData[];\r\n /** Per-vertex bone indices, sorted by descending weight and capped for Babylon skinning */\r\n boneIndices: number[][];\r\n /** Per-vertex bone weights, matching boneIndices */\r\n boneWeights: number[][];\r\n /** Recoverable skinning/bind diagnostics */\r\n diagnostics: FBXSkinDiagnostic[];\r\n}\r\n\r\n/**\r\n * Extract all skin deformers from the FBX scene.\r\n * Returns skin data including bone hierarchy and vertex weights.\r\n */\r\nexport function extractSkins(objectMap: FBXObjectMap): FBXSkinData[] {\r\n const skins: FBXSkinData[] = [];\r\n\r\n for (const [id, node] of Array.from(objectMap.objects)) {\r\n if (node.name === \"Deformer\" && getPropertyValue<string>(node, 2) === \"Skin\") {\r\n const skin = extractSkin(id, node, objectMap);\r\n if (skin) {\r\n skins.push(skin);\r\n }\r\n }\r\n }\r\n\r\n return skins;\r\n}\r\n\r\nfunction extractSkin(skinId: number, _skinNode: FBXNode, objectMap: FBXObjectMap): FBXSkinData | null {\r\n // Find the geometry this skin is attached to\r\n // Skin is a child of the geometry in FBX connection graph\r\n const skinParent = objectMap.parentOf.get(skinId);\r\n if (!skinParent) {\r\n return null;\r\n }\r\n\r\n const geometryId = skinParent.id;\r\n const geometryNode = objectMap.objects.get(geometryId);\r\n if (!geometryNode || geometryNode.name !== \"Geometry\") {\r\n return null;\r\n }\r\n const modelParent = objectMap.parentOf.get(geometryId);\r\n const modelParentNode = modelParent ? objectMap.objects.get(modelParent.id) : undefined;\r\n const meshModelId = modelParentNode?.name === \"Model\" ? modelParent!.id : undefined;\r\n\r\n // Find all clusters (children of this skin)\r\n const clusterEntries = getChildren(objectMap, skinId, \"Deformer\");\r\n if (clusterEntries.length === 0) {\r\n return null;\r\n }\r\n\r\n // For each cluster, find the connected bone Model\r\n // Connection graph: BoneModel → Cluster (bone is child of cluster)\r\n const boneModelMap = new Map<number, { clusterId: number; clusterNode: FBXNode }>();\r\n for (const { id: clusterId, node: clusterNode } of clusterEntries) {\r\n const subType = getPropertyValue<string>(clusterNode, 2);\r\n if (subType !== \"Cluster\") {\r\n continue;\r\n }\r\n\r\n // The bone Model is a child of the Cluster\r\n const boneChildren = getChildren(objectMap, clusterId, \"Model\");\r\n if (boneChildren.length > 0) {\r\n boneModelMap.set(boneChildren[0].id, { clusterId, clusterNode });\r\n }\r\n }\r\n\r\n // Build bone hierarchy from Model parent-child relationships. Include\r\n // skeleton-like ancestors even when they are not weighted clusters; some\r\n // rigs (for example 3ds Max Biped) animate a non-cluster root above the\r\n // clustered bones.\r\n const bindPoseMatrices = extractBindPoseMatrices(geometryId, objectMap);\r\n const skinDiagnostics: FBXSkinDiagnostic[] = [];\r\n const bones = buildBoneHierarchy(boneModelMap, bindPoseMatrices, objectMap, skinDiagnostics);\r\n if (bones.length === 0) {\r\n return null;\r\n }\r\n\r\n // Extract per-vertex weights from clusters\r\n const { boneIndices, boneWeights } = extractVertexWeights(bones, boneModelMap, objectMap);\r\n\r\n return {\r\n id: skinId,\r\n geometryId,\r\n meshBindPoseMatrix: meshModelId !== undefined ? (bindPoseMatrices.get(meshModelId) ?? null) : null,\r\n bones,\r\n boneIndices,\r\n boneWeights,\r\n diagnostics: skinDiagnostics,\r\n };\r\n}\r\n\r\n/**\r\n * Build a flat ordered bone list with parent indices from the FBX Model hierarchy.\r\n */\r\nfunction buildBoneHierarchy(\r\n boneModelMap: Map<number, { clusterId: number; clusterNode: FBXNode }>,\r\n bindPoseMatrices: Map<number, Float64Array>,\r\n objectMap: FBXObjectMap,\r\n skinDiagnostics: FBXSkinDiagnostic[]\r\n): FBXBoneData[] {\r\n const bones: FBXBoneData[] = [];\r\n const visited = new Set<number>();\r\n const skeletonModelIds = collectSkeletonModelIds(boneModelMap, objectMap);\r\n const parentByModelId = buildSkeletonParentMap(skeletonModelIds, objectMap);\r\n const childrenByModelId = buildSkeletonChildrenMap(skeletonModelIds, parentByModelId);\r\n\r\n const rootBoneIds = Array.from(skeletonModelIds).filter((modelId) => !parentByModelId.has(modelId));\r\n\r\n // BFS to build ordered list\r\n const queue: { modelId: number; parentIndex: number }[] = rootBoneIds.map((id) => ({\r\n modelId: id,\r\n parentIndex: -1,\r\n }));\r\n\r\n while (queue.length > 0) {\r\n const { modelId, parentIndex } = queue.shift()!;\r\n if (visited.has(modelId)) {\r\n continue;\r\n }\r\n visited.add(modelId);\r\n\r\n const modelNode = objectMap.objects.get(modelId);\r\n if (!modelNode) {\r\n continue;\r\n }\r\n\r\n const boneIndex = bones.length;\r\n\r\n const clusterInfo = boneModelMap.get(modelId);\r\n const transform = extractBoneTransform(modelNode);\r\n const { bindPoseMatrix, transformLinkMatrix, transformAssociateModelMatrix, clusterMode } = clusterInfo\r\n ? extractClusterMatrices(clusterInfo.clusterNode)\r\n : { bindPoseMatrix: null, transformLinkMatrix: null, transformAssociateModelMatrix: null, clusterMode: \"Unknown\" as const };\r\n const diagnostics = createBoneDiagnostics(\r\n modelId,\r\n cleanFBXName(getPropertyValue<string>(modelNode, 1) ?? `Bone${boneIndex}`),\r\n clusterInfo !== undefined,\r\n clusterMode,\r\n bindPoseMatrix,\r\n transformLinkMatrix,\r\n transformAssociateModelMatrix,\r\n bindPoseMatrices.get(modelId) ?? null\r\n );\r\n skinDiagnostics.push(...diagnostics);\r\n\r\n bones.push({\r\n modelId,\r\n name: cleanFBXName(getPropertyValue<string>(modelNode, 1) ?? `Bone${boneIndex}`),\r\n index: boneIndex,\r\n parentIndex,\r\n isCluster: clusterInfo !== undefined,\r\n translation: transform.translation,\r\n rotation: transform.rotation,\r\n preRotation: transform.preRotation,\r\n postRotation: transform.postRotation,\r\n rotationPivot: transform.rotationPivot,\r\n scalingPivot: transform.scalingPivot,\r\n rotationOffset: transform.rotationOffset,\r\n scalingOffset: transform.scalingOffset,\r\n scale: transform.scale,\r\n rotationOrder: transform.rotationOrder,\r\n inheritType: transform.inheritType,\r\n clusterMode,\r\n bindPoseMatrix,\r\n transformLinkMatrix,\r\n transformAssociateModelMatrix,\r\n modelBindPoseMatrix: bindPoseMatrices.get(modelId) ?? null,\r\n diagnostics,\r\n });\r\n\r\n for (const childId of childrenByModelId.get(modelId) ?? []) {\r\n if (!visited.has(childId)) {\r\n queue.push({ modelId: childId, parentIndex: boneIndex });\r\n }\r\n }\r\n }\r\n\r\n return bones;\r\n}\r\n\r\nfunction extractBindPoseMatrices(geometryId: number, objectMap: FBXObjectMap): Map<number, Float64Array> {\r\n const modelParent = objectMap.parentOf.get(geometryId);\r\n const modelParentNode = modelParent ? objectMap.objects.get(modelParent.id) : undefined;\r\n const modelId = modelParentNode?.name === \"Model\" ? modelParent!.id : undefined;\r\n if (modelId === undefined) {\r\n return new Map();\r\n }\r\n\r\n for (const [, poseNode] of Array.from(objectMap.objects)) {\r\n if (poseNode.name !== \"Pose\" || getPropertyValue<string>(poseNode, 2) !== \"BindPose\") {\r\n continue;\r\n }\r\n\r\n const matrices = new Map<number, Float64Array>();\r\n for (const poseChild of poseNode.children) {\r\n if (poseChild.name !== \"PoseNode\") {\r\n continue;\r\n }\r\n\r\n const nodeChild = findChildByName(poseChild, \"Node\");\r\n const matrixChild = findChildByName(poseChild, \"Matrix\");\r\n const nodeId = nodeChild?.properties[0]?.value;\r\n const matrixValue = matrixChild?.properties[0]?.value;\r\n if (typeof nodeId !== \"number\") {\r\n continue;\r\n }\r\n\r\n const matrix = toFloat64Array(matrixValue);\r\n if (matrix?.length === 16) {\r\n matrices.set(nodeId, matrix);\r\n }\r\n }\r\n\r\n if (matrices.has(modelId)) {\r\n return matrices;\r\n }\r\n }\r\n\r\n return new Map();\r\n}\r\n\r\nfunction buildSkeletonChildrenMap(skeletonModelIds: Set<number>, parentByModelId: Map<number, number>): Map<number, number[]> {\r\n const childrenByModelId = new Map<number, number[]>();\r\n\r\n for (const modelId of Array.from(skeletonModelIds)) {\r\n const parentId = parentByModelId.get(modelId);\r\n if (parentId === undefined) {\r\n continue;\r\n }\r\n\r\n if (!childrenByModelId.has(parentId)) {\r\n childrenByModelId.set(parentId, []);\r\n }\r\n childrenByModelId.get(parentId)!.push(modelId);\r\n }\r\n\r\n return childrenByModelId;\r\n}\r\n\r\nfunction collectSkeletonModelIds(boneModelMap: Map<number, { clusterId: number; clusterNode: FBXNode }>, objectMap: FBXObjectMap): Set<number> {\r\n const skeletonModelIds = new Set<number>(Array.from(boneModelMap.keys()));\r\n\r\n for (const modelId of Array.from(boneModelMap.keys())) {\r\n let parentId = findModelParentId(modelId, objectMap);\r\n while (parentId !== undefined) {\r\n const parentNode = objectMap.objects.get(parentId);\r\n if (!parentNode || parentNode.name !== \"Model\") {\r\n break;\r\n }\r\n\r\n skeletonModelIds.add(parentId);\r\n parentId = findModelParentId(parentId, objectMap);\r\n }\r\n }\r\n\r\n return skeletonModelIds;\r\n}\r\n\r\nfunction buildSkeletonParentMap(skeletonModelIds: Set<number>, objectMap: FBXObjectMap): Map<number, number> {\r\n const parentByModelId = new Map<number, number>();\r\n\r\n for (const modelId of Array.from(skeletonModelIds)) {\r\n let parentId = findModelParentId(modelId, objectMap);\r\n while (parentId !== undefined) {\r\n if (skeletonModelIds.has(parentId)) {\r\n parentByModelId.set(modelId, parentId);\r\n break;\r\n }\r\n parentId = findModelParentId(parentId, objectMap);\r\n }\r\n }\r\n\r\n return parentByModelId;\r\n}\r\n\r\nfunction findModelParentId(modelId: number, objectMap: FBXObjectMap): number | undefined {\r\n const parentConnection = objectMap.connections.find((conn) => conn.type === \"OO\" && conn.childId === modelId && objectMap.objects.get(conn.parentId)?.name === \"Model\");\r\n return parentConnection?.parentId;\r\n}\r\n\r\nexport function isSkeletonModel(modelNode: FBXNode): boolean {\r\n const subType = getPropertyValue<string>(modelNode, 2);\r\n return subType === \"Root\" || subType === \"LimbNode\";\r\n}\r\n\r\nexport function extractBoneTransform(modelNode: FBXNode): {\r\n translation: [number, number, number];\r\n rotation: [number, number, number];\r\n preRotation: [number, number, number];\r\n postRotation: [number, number, number];\r\n rotationPivot: [number, number, number];\r\n scalingPivot: [number, number, number];\r\n rotationOffset: [number, number, number];\r\n scalingOffset: [number, number, number];\r\n scale: [number, number, number];\r\n rotationOrder: number;\r\n inheritType: number;\r\n} {\r\n const translation: [number, number, number] = [0, 0, 0];\r\n const rotation: [number, number, number] = [0, 0, 0];\r\n const preRotation: [number, number, number] = [0, 0, 0];\r\n const postRotation: [number, number, number] = [0, 0, 0];\r\n const rotationPivot: [number, number, number] = [0, 0, 0];\r\n const scalingPivot: [number, number, number] = [0, 0, 0];\r\n const rotationOffset: [number, number, number] = [0, 0, 0];\r\n const scalingOffset: [number, number, number] = [0, 0, 0];\r\n const scale: [number, number, number] = [1, 1, 1];\r\n let rotationOrder = 0;\r\n let inheritType = 1;\r\n\r\n const props70 = findChildByName(modelNode, \"Properties70\");\r\n if (!props70) {\r\n return { translation, rotation, preRotation, postRotation, rotationPivot, scalingPivot, rotationOffset, scalingOffset, scale, rotationOrder, inheritType };\r\n }\r\n\r\n for (const p of props70.children) {\r\n if (p.name !== \"P\") {\r\n continue;\r\n }\r\n const propName = getPropertyValue<string>(p, 0);\r\n if (!propName) {\r\n continue;\r\n }\r\n\r\n switch (propName) {\r\n case \"Lcl Translation\":\r\n translation[0] = toNumber(p.properties[4]?.value) ?? 0;\r\n translation[1] = toNumber(p.properties[5]?.value) ?? 0;\r\n translation[2] = toNumber(p.properties[6]?.value) ?? 0;\r\n break;\r\n case \"Lcl Rotation\":\r\n rotation[0] = toNumber(p.properties[4]?.value) ?? 0;\r\n rotation[1] = toNumber(p.properties[5]?.value) ?? 0;\r\n rotation[2] = toNumber(p.properties[6]?.value) ?? 0;\r\n break;\r\n case \"PreRotation\":\r\n preRotation[0] = toNumber(p.properties[4]?.value) ?? 0;\r\n preRotation[1] = toNumber(p.properties[5]?.value) ?? 0;\r\n preRotation[2] = toNumber(p.properties[6]?.value) ?? 0;\r\n break;\r\n case \"PostRotation\":\r\n postRotation[0] = toNumber(p.properties[4]?.value) ?? 0;\r\n postRotation[1] = toNumber(p.properties[5]?.value) ?? 0;\r\n postRotation[2] = toNumber(p.properties[6]?.value) ?? 0;\r\n break;\r\n case \"RotationPivot\":\r\n rotationPivot[0] = toNumber(p.properties[4]?.value) ?? 0;\r\n rotationPivot[1] = toNumber(p.properties[5]?.value) ?? 0;\r\n rotationPivot[2] = toNumber(p.properties[6]?.value) ?? 0;\r\n break;\r\n case \"ScalingPivot\":\r\n scalingPivot[0] = toNumber(p.properties[4]?.value) ?? 0;\r\n scalingPivot[1] = toNumber(p.properties[5]?.value) ?? 0;\r\n scalingPivot[2] = toNumber(p.properties[6]?.value) ?? 0;\r\n break;\r\n case \"RotationOffset\":\r\n rotationOffset[0] = toNumber(p.properties[4]?.value) ?? 0;\r\n rotationOffset[1] = toNumber(p.properties[5]?.value) ?? 0;\r\n rotationOffset[2] = toNumber(p.properties[6]?.value) ?? 0;\r\n break;\r\n case \"ScalingOffset\":\r\n scalingOffset[0] = toNumber(p.properties[4]?.value) ?? 0;\r\n scalingOffset[1] = toNumber(p.properties[5]?.value) ?? 0;\r\n scalingOffset[2] = toNumber(p.properties[6]?.value) ?? 0;\r\n break;\r\n case \"Lcl Scaling\":\r\n scale[0] = toNumber(p.properties[4]?.value) ?? 1;\r\n scale[1] = toNumber(p.properties[5]?.value) ?? 1;\r\n scale[2] = toNumber(p.properties[6]?.value) ?? 1;\r\n break;\r\n case \"RotationOrder\":\r\n rotationOrder = toNumber(p.properties[4]?.value) ?? 0;\r\n break;\r\n case \"InheritType\":\r\n inheritType = toNumber(p.properties[4]?.value) ?? 1;\r\n break;\r\n }\r\n }\r\n\r\n return { translation, rotation, preRotation, postRotation, rotationPivot, scalingPivot, rotationOffset, scalingOffset, scale, rotationOrder, inheritType };\r\n}\r\n\r\nfunction extractClusterMatrices(clusterNode: FBXNode): {\r\n bindPoseMatrix: Float64Array | null;\r\n transformLinkMatrix: Float64Array | null;\r\n transformAssociateModelMatrix: Float64Array | null;\r\n clusterMode: FBXClusterMode;\r\n} {\r\n let bindPoseMatrix: Float64Array | null = null;\r\n let transformLinkMatrix: Float64Array | null = null;\r\n let transformAssociateModelMatrix: Float64Array | null = null;\r\n let clusterMode: FBXClusterMode = \"Normalize\";\r\n\r\n const transformNode = findChildByName(clusterNode, \"Transform\");\r\n if (transformNode && transformNode.properties[0]) {\r\n const val = transformNode.properties[0].value;\r\n if (val instanceof Float64Array && val.length === 16) {\r\n bindPoseMatrix = val;\r\n } else if (val instanceof Float32Array && val.length === 16) {\r\n bindPoseMatrix = new Float64Array(val);\r\n }\r\n }\r\n\r\n const transformLinkNode = findChildByName(clusterNode, \"TransformLink\");\r\n if (transformLinkNode && transformLinkNode.properties[0]) {\r\n const val = transformLinkNode.properties[0].value;\r\n if (val instanceof Float64Array && val.length === 16) {\r\n transformLinkMatrix = val;\r\n } else if (val instanceof Float32Array && val.length === 16) {\r\n transformLinkMatrix = new Float64Array(val);\r\n }\r\n }\r\n\r\n const transformAssociateModelNode = findChildByName(clusterNode, \"TransformAssociateModel\");\r\n if (transformAssociateModelNode && transformAssociateModelNode.properties[0]) {\r\n const val = transformAssociateModelNode.properties[0].value;\r\n if (val instanceof Float64Array && val.length === 16) {\r\n transformAssociateModelMatrix = val;\r\n } else if (val instanceof Float32Array && val.length === 16) {\r\n transformAssociateModelMatrix = new Float64Array(val);\r\n }\r\n }\r\n\r\n const modeNode = findChildByName(clusterNode, \"Mode\");\r\n const mode = modeNode ? getPropertyValue<string>(modeNode, 0) : undefined;\r\n if (mode === \"Normalize\" || mode === \"Additive\" || mode === \"TotalOne\") {\r\n clusterMode = mode;\r\n } else if (mode) {\r\n clusterMode = \"Unknown\";\r\n }\r\n\r\n return { bindPoseMatrix, transformLinkMatrix, transformAssociateModelMatrix, clusterMode };\r\n}\r\n\r\nfunction createBoneDiagnostics(\r\n modelId: number,\r\n boneName: string,\r\n isCluster: boolean,\r\n clusterMode: FBXClusterMode,\r\n bindPoseMatrix: Float64Array | null,\r\n transformLinkMatrix: Float64Array | null,\r\n transformAssociateModelMatrix: Float64Array | null,\r\n modelBindPoseMatrix: Float64Array | null\r\n): FBXSkinDiagnostic[] {\r\n if (!isCluster) {\r\n return [];\r\n }\r\n\r\n const diagnostics: FBXSkinDiagnostic[] = [];\r\n if (clusterMode === \"Additive\" || clusterMode === \"TotalOne\") {\r\n diagnostics.push({\r\n type: \"cluster-mode-runtime-unsupported\",\r\n message: `Cluster mode '${clusterMode}' is preserved but not applied by Babylon linear blend skinning.`,\r\n boneModelId: modelId,\r\n boneName,\r\n clusterMode,\r\n });\r\n }\r\n if (!bindPoseMatrix) {\r\n diagnostics.push({\r\n type: \"missing-cluster-transform\",\r\n message: \"Cluster is missing Transform matrix; falling back to rest/bind-pose data.\",\r\n boneModelId: modelId,\r\n boneName,\r\n clusterMode,\r\n });\r\n }\r\n if (!transformLinkMatrix) {\r\n diagnostics.push({\r\n type: \"missing-cluster-transform-link\",\r\n message: \"Cluster is missing TransformLink matrix; falling back to model bind pose or rest transform.\",\r\n boneModelId: modelId,\r\n boneName,\r\n clusterMode,\r\n });\r\n }\r\n if (!modelBindPoseMatrix) {\r\n diagnostics.push({\r\n type: \"missing-bind-pose-matrix\",\r\n message: \"No BindPose matrix was found for this bone model.\",\r\n boneModelId: modelId,\r\n boneName,\r\n clusterMode,\r\n });\r\n }\r\n if (transformAssociateModelMatrix) {\r\n diagnostics.push({\r\n type: \"associate-model-present\",\r\n message: \"TransformAssociateModel is preserved for future associate-model skinning semantics.\",\r\n boneModelId: modelId,\r\n boneName,\r\n clusterMode,\r\n });\r\n }\r\n\r\n return diagnostics;\r\n}\r\n\r\n/**\r\n * Extract per-vertex bone indices and weights from cluster data.\r\n * Returns arrays indexed by control point index.\r\n */\r\nfunction extractVertexWeights(\r\n bones: FBXBoneData[],\r\n boneModelMap: Map<number, { clusterId: number; clusterNode: FBXNode }>,\r\n objectMap: FBXObjectMap\r\n): { boneIndices: number[][]; boneWeights: number[][] } {\r\n // We need to find the max vertex index to size our arrays\r\n let maxVertexIndex = 0;\r\n\r\n // First pass: find max vertex index\r\n for (const bone of bones) {\r\n const clusterInfo = boneModelMap.get(bone.modelId);\r\n if (!clusterInfo) {\r\n continue;\r\n }\r\n\r\n const indexesNode = findChildByName(clusterInfo.clusterNode, \"Indexes\");\r\n if (!indexesNode) {\r\n continue;\r\n }\r\n\r\n const indexes = toInt32Array(indexesNode.properties[0]?.value);\r\n if (!indexes) {\r\n continue;\r\n }\r\n\r\n for (let i = 0; i < indexes.length; i++) {\r\n if (indexes[i] > maxVertexIndex) {\r\n maxVertexIndex = indexes[i];\r\n }\r\n }\r\n }\r\n\r\n // Initialize arrays\r\n const vertexCount = maxVertexIndex + 1;\r\n const boneIndices: number[][] = new Array(vertexCount);\r\n const boneWeights: number[][] = new Array(vertexCount);\r\n for (let i = 0; i < vertexCount; i++) {\r\n boneIndices[i] = [];\r\n boneWeights[i] = [];\r\n }\r\n\r\n // Second pass: collect influences\r\n for (const bone of bones) {\r\n const clusterInfo = boneModelMap.get(bone.modelId);\r\n if (!clusterInfo) {\r\n continue;\r\n }\r\n\r\n const indexesNode = findChildByName(clusterInfo.clusterNode, \"Indexes\");\r\n const weightsNode = findChildByName(clusterInfo.clusterNode, \"Weights\");\r\n if (!indexesNode || !weightsNode) {\r\n continue;\r\n }\r\n\r\n const indexes = toInt32Array(indexesNode.properties[0]?.value);\r\n const weights = toFloat64Array(weightsNode.properties[0]?.value);\r\n if (!indexes || !weights) {\r\n continue;\r\n }\r\n\r\n for (let i = 0; i < indexes.length; i++) {\r\n const vertIdx = indexes[i];\r\n boneIndices[vertIdx].push(bone.index);\r\n boneWeights[vertIdx].push(weights[i]);\r\n }\r\n }\r\n\r\n // Sort by weight descending and cap to Babylon's primary + extra influence buffers.\r\n for (let i = 0; i < vertexCount; i++) {\r\n if (boneIndices[i].length === 0) {\r\n continue;\r\n }\r\n\r\n const pairs = boneIndices[i].map((bi, idx) => ({\r\n index: bi,\r\n weight: boneWeights[i][idx],\r\n }));\r\n pairs.sort((a, b) => b.weight - a.weight);\r\n const cappedPairs = pairs.slice(0, MAX_BONE_INFLUENCES);\r\n boneIndices[i] = cappedPairs.map((p) => p.index);\r\n boneWeights[i] = cappedPairs.map((p) => p.weight);\r\n }\r\n\r\n // Normalize weights to sum to 1.0\r\n for (let i = 0; i < vertexCount; i++) {\r\n const sum = boneWeights[i].reduce((a, b) => a + b, 0);\r\n if (sum > 0) {\r\n for (let j = 0; j < boneWeights[i].length; j++) {\r\n boneWeights[i][j] /= sum;\r\n }\r\n }\r\n }\r\n\r\n return { boneIndices, boneWeights };\r\n}\r\n\r\n// ── Utilities ──────────────────────────────────────────────────────────────────\r\n\r\nfunction toNumber(value: unknown): number | undefined {\r\n if (typeof value === \"number\") {\r\n return value;\r\n }\r\n return undefined;\r\n}\r\n\r\nfunction toInt32Array(value: unknown): Int32Array | null {\r\n if (value instanceof Int32Array) {\r\n return value;\r\n }\r\n if (value instanceof Float64Array) {\r\n const result = new Int32Array(value.length);\r\n for (let i = 0; i < value.length; i++) {\r\n result[i] = Math.round(value[i]);\r\n }\r\n return result;\r\n }\r\n return null;\r\n}\r\n\r\nfunction toFloat64Array(value: unknown): Float64Array | null {\r\n if (value instanceof Float64Array) {\r\n return value;\r\n }\r\n if (value instanceof Float32Array) {\r\n return new Float64Array(value);\r\n }\r\n return null;\r\n}\r\n"]}
1
+ {"version":3,"file":"skeleton.js","sourceRoot":"","sources":["../../../../../dev/loaders/src/FBX/interpreter/skeleton.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/naming-convention, jsdoc/require-param, jsdoc/require-returns */\nimport { extractNodeTransform, type FBXNodeTransformData } from \"./nodeTransform\";\nimport { getPropertyTemplate, type FBXPropertyTemplate, type FBXPropertyTemplateMap } from \"./propertyTemplates\";\nimport { type FBXNode, findChildByName, getPropertyValue, cleanFBXName, getNodeArray } from \"../types/fbxTypes\";\n\nimport { type FBXObjectMap, getChildren } from \"./connections\";\n\nconst MAX_BONE_INFLUENCES = 8;\n\nexport type FBXClusterMode = \"Normalize\" | \"Additive\" | \"TotalOne\" | \"Unknown\";\n\nexport interface FBXSkinDiagnostic {\n type: \"cluster-mode-runtime-unsupported\" | \"missing-cluster-transform\" | \"missing-cluster-transform-link\" | \"missing-bind-pose-matrix\" | \"associate-model-present\";\n message: string;\n boneModelId?: number;\n boneName?: string;\n clusterMode?: FBXClusterMode;\n}\n\n/** Represents a single bone (cluster) in the FBX skeleton */\nexport interface FBXBoneData {\n /** The Model node ID for this bone */\n modelId: number;\n /** Bone name (from the Model node) */\n name: string;\n /** Index of this bone in the skeleton */\n index: number;\n /** Index of the parent bone (-1 for root) */\n parentIndex: number;\n /** Whether this bone corresponds to an FBX Cluster with vertex weights */\n isCluster: boolean;\n /** Local translation from parent (Lcl Translation) */\n translation: [number, number, number];\n /** Local rotation in degrees (Lcl Rotation) */\n rotation: [number, number, number];\n /** Pre-rotation in degrees (applied before Lcl Rotation) */\n preRotation: [number, number, number];\n /** Post-rotation in degrees (applied after Lcl Rotation, inverted) */\n postRotation: [number, number, number];\n /** Rotation pivot point */\n rotationPivot: [number, number, number];\n /** Scaling pivot point */\n scalingPivot: [number, number, number];\n /** Rotation offset */\n rotationOffset: [number, number, number];\n /** Scaling offset */\n scalingOffset: [number, number, number];\n /** Local scale (Lcl Scaling) */\n scale: [number, number, number];\n /** Rotation order: 0=XYZ, 1=XZY, 2=YZX, 3=YXZ, 4=ZXY, 5=ZYX */\n rotationOrder: number;\n /** FBX transform inheritance mode. 0=RrSs, 1=RSrs, 2=Rrs */\n inheritType: number;\n /** Cluster skinning mode */\n clusterMode: FBXClusterMode;\n /** Bind pose transform matrix (cluster Transform, 4x4) */\n bindPoseMatrix: Float64Array | null;\n /** Bone's world transform at bind time (cluster TransformLink, 4x4) */\n transformLinkMatrix: Float64Array | null;\n /** Associate model world transform at bind time (cluster TransformAssociateModel, 4x4) */\n transformAssociateModelMatrix: Float64Array | null;\n /** Model's absolute matrix from the FBX BindPose, when present */\n modelBindPoseMatrix: Float64Array | null;\n /** Recoverable bind/skinning diagnostics for this bone */\n diagnostics: FBXSkinDiagnostic[];\n}\n\n/** Represents a skin deformer with its clusters */\nexport interface FBXSkinData {\n /** Skin deformer ID */\n id: number;\n /** Geometry ID this skin is attached to */\n geometryId: number;\n /** Mesh model world matrix from the FBX BindPose, when present */\n meshBindPoseMatrix: Float64Array | null;\n /** Bones in this skeleton */\n bones: FBXBoneData[];\n /** Per-vertex bone indices, sorted by descending weight and capped for Babylon skinning */\n boneIndices: number[][];\n /** Per-vertex bone weights, matching boneIndices */\n boneWeights: number[][];\n /** Recoverable skinning/bind diagnostics */\n diagnostics: FBXSkinDiagnostic[];\n}\n\n/**\n * Extract all skin deformers from the FBX scene.\n * Returns skin data including bone hierarchy and vertex weights.\n */\n// Template used to resolve bone transform defaults while extractSkins runs (bones are Models).\nlet currentModelTemplate: FBXPropertyTemplate | undefined;\n\nexport function extractSkins(objectMap: FBXObjectMap, propertyTemplates?: FBXPropertyTemplateMap): FBXSkinData[] {\n currentModelTemplate = propertyTemplates ? (getPropertyTemplate(propertyTemplates, \"Model\", \"FbxNode\") ?? getPropertyTemplate(propertyTemplates, \"Model\")) : undefined;\n const skins: FBXSkinData[] = [];\n\n for (const [id, node] of Array.from(objectMap.objects)) {\n if (node.name === \"Deformer\" && getPropertyValue<string>(node, 2) === \"Skin\") {\n const skin = extractSkin(id, node, objectMap);\n if (skin) {\n skins.push(skin);\n }\n }\n }\n\n return skins;\n}\n\nfunction extractSkin(skinId: number, _skinNode: FBXNode, objectMap: FBXObjectMap): FBXSkinData | null {\n // Find the geometry this skin is attached to\n // Skin is a child of the geometry in FBX connection graph\n const skinParent = objectMap.parentOf.get(skinId);\n if (!skinParent) {\n return null;\n }\n\n const geometryId = skinParent.id;\n const geometryNode = objectMap.objects.get(geometryId);\n if (!geometryNode || geometryNode.name !== \"Geometry\") {\n return null;\n }\n const modelParent = objectMap.parentOf.get(geometryId);\n const modelParentNode = modelParent ? objectMap.objects.get(modelParent.id) : undefined;\n const meshModelId = modelParentNode?.name === \"Model\" ? modelParent!.id : undefined;\n\n // Find all clusters (children of this skin)\n const clusterEntries = getChildren(objectMap, skinId, \"Deformer\");\n if (clusterEntries.length === 0) {\n return null;\n }\n\n // For each cluster, find the connected bone Model\n // Connection graph: BoneModel → Cluster (bone is child of cluster)\n const boneModelMap = new Map<number, { clusterId: number; clusterNode: FBXNode }>();\n for (const { id: clusterId, node: clusterNode } of clusterEntries) {\n const subType = getPropertyValue<string>(clusterNode, 2);\n if (subType !== \"Cluster\") {\n continue;\n }\n\n // The bone Model is a child of the Cluster\n const boneChildren = getChildren(objectMap, clusterId, \"Model\");\n if (boneChildren.length > 0) {\n boneModelMap.set(boneChildren[0].id, { clusterId, clusterNode });\n }\n }\n\n // Build bone hierarchy from Model parent-child relationships. Include\n // skeleton-like ancestors even when they are not weighted clusters; some\n // rigs (for example 3ds Max Biped) animate a non-cluster root above the\n // clustered bones.\n const bindPoseMatrices = extractBindPoseMatrices(geometryId, objectMap);\n const skinDiagnostics: FBXSkinDiagnostic[] = [];\n const bones = buildBoneHierarchy(boneModelMap, bindPoseMatrices, objectMap, skinDiagnostics);\n if (bones.length === 0) {\n return null;\n }\n\n // Extract per-vertex weights from clusters\n const { boneIndices, boneWeights } = extractVertexWeights(bones, boneModelMap, objectMap);\n\n return {\n id: skinId,\n geometryId,\n meshBindPoseMatrix: meshModelId !== undefined ? (bindPoseMatrices.get(meshModelId) ?? null) : null,\n bones,\n boneIndices,\n boneWeights,\n diagnostics: skinDiagnostics,\n };\n}\n\n/**\n * Build a flat ordered bone list with parent indices from the FBX Model hierarchy.\n */\nfunction buildBoneHierarchy(\n boneModelMap: Map<number, { clusterId: number; clusterNode: FBXNode }>,\n bindPoseMatrices: Map<number, Float64Array>,\n objectMap: FBXObjectMap,\n skinDiagnostics: FBXSkinDiagnostic[]\n): FBXBoneData[] {\n const bones: FBXBoneData[] = [];\n const visited = new Set<number>();\n const skeletonModelIds = collectSkeletonModelIds(boneModelMap, objectMap);\n const parentByModelId = buildSkeletonParentMap(skeletonModelIds, objectMap);\n const childrenByModelId = buildSkeletonChildrenMap(skeletonModelIds, parentByModelId);\n\n const rootBoneIds = Array.from(skeletonModelIds).filter((modelId) => !parentByModelId.has(modelId));\n\n // BFS to build ordered list\n const queue: { modelId: number; parentIndex: number }[] = rootBoneIds.map((id) => ({\n modelId: id,\n parentIndex: -1,\n }));\n\n while (queue.length > 0) {\n const { modelId, parentIndex } = queue.shift()!;\n if (visited.has(modelId)) {\n continue;\n }\n visited.add(modelId);\n\n const modelNode = objectMap.objects.get(modelId);\n if (!modelNode) {\n continue;\n }\n\n const boneIndex = bones.length;\n\n const clusterInfo = boneModelMap.get(modelId);\n const transform = extractBoneTransform(modelNode);\n const { bindPoseMatrix, transformLinkMatrix, transformAssociateModelMatrix, clusterMode } = clusterInfo\n ? extractClusterMatrices(clusterInfo.clusterNode)\n : { bindPoseMatrix: null, transformLinkMatrix: null, transformAssociateModelMatrix: null, clusterMode: \"Unknown\" as const };\n const diagnostics = createBoneDiagnostics(\n modelId,\n cleanFBXName(getPropertyValue<string>(modelNode, 1) ?? `Bone${boneIndex}`),\n clusterInfo !== undefined,\n clusterMode,\n bindPoseMatrix,\n transformLinkMatrix,\n transformAssociateModelMatrix,\n bindPoseMatrices.get(modelId) ?? null\n );\n skinDiagnostics.push(...diagnostics);\n\n bones.push({\n modelId,\n name: cleanFBXName(getPropertyValue<string>(modelNode, 1) ?? `Bone${boneIndex}`),\n index: boneIndex,\n parentIndex,\n isCluster: clusterInfo !== undefined,\n translation: transform.translation,\n rotation: transform.rotation,\n preRotation: transform.preRotation,\n postRotation: transform.postRotation,\n rotationPivot: transform.rotationPivot,\n scalingPivot: transform.scalingPivot,\n rotationOffset: transform.rotationOffset,\n scalingOffset: transform.scalingOffset,\n scale: transform.scale,\n rotationOrder: transform.rotationOrder,\n inheritType: transform.inheritType,\n clusterMode,\n bindPoseMatrix,\n transformLinkMatrix,\n transformAssociateModelMatrix,\n modelBindPoseMatrix: bindPoseMatrices.get(modelId) ?? null,\n diagnostics,\n });\n\n for (const childId of childrenByModelId.get(modelId) ?? []) {\n if (!visited.has(childId)) {\n queue.push({ modelId: childId, parentIndex: boneIndex });\n }\n }\n }\n\n return bones;\n}\n\nfunction extractBindPoseMatrices(geometryId: number, objectMap: FBXObjectMap): Map<number, Float64Array> {\n const modelParent = objectMap.parentOf.get(geometryId);\n const modelParentNode = modelParent ? objectMap.objects.get(modelParent.id) : undefined;\n const modelId = modelParentNode?.name === \"Model\" ? modelParent!.id : undefined;\n if (modelId === undefined) {\n return new Map();\n }\n\n for (const [, poseNode] of Array.from(objectMap.objects)) {\n if (poseNode.name !== \"Pose\" || getPropertyValue<string>(poseNode, 2) !== \"BindPose\") {\n continue;\n }\n\n const matrices = new Map<number, Float64Array>();\n for (const poseChild of poseNode.children) {\n if (poseChild.name !== \"PoseNode\") {\n continue;\n }\n\n const nodeChild = findChildByName(poseChild, \"Node\");\n const matrixChild = findChildByName(poseChild, \"Matrix\");\n const nodeId = nodeChild?.properties[0]?.value;\n const matrixValue = getNodeArray(matrixChild);\n if (typeof nodeId !== \"number\") {\n continue;\n }\n\n const matrix = toFloat64Array(matrixValue);\n if (matrix?.length === 16) {\n matrices.set(nodeId, matrix);\n }\n }\n\n if (matrices.has(modelId)) {\n return matrices;\n }\n }\n\n return new Map();\n}\n\nfunction buildSkeletonChildrenMap(skeletonModelIds: Set<number>, parentByModelId: Map<number, number>): Map<number, number[]> {\n const childrenByModelId = new Map<number, number[]>();\n\n for (const modelId of Array.from(skeletonModelIds)) {\n const parentId = parentByModelId.get(modelId);\n if (parentId === undefined) {\n continue;\n }\n\n if (!childrenByModelId.has(parentId)) {\n childrenByModelId.set(parentId, []);\n }\n childrenByModelId.get(parentId)!.push(modelId);\n }\n\n return childrenByModelId;\n}\n\nfunction collectSkeletonModelIds(boneModelMap: Map<number, { clusterId: number; clusterNode: FBXNode }>, objectMap: FBXObjectMap): Set<number> {\n const skeletonModelIds = new Set<number>(Array.from(boneModelMap.keys()));\n\n for (const modelId of Array.from(boneModelMap.keys())) {\n let parentId = findModelParentId(modelId, objectMap);\n while (parentId !== undefined) {\n const parentNode = objectMap.objects.get(parentId);\n if (!parentNode || parentNode.name !== \"Model\") {\n break;\n }\n\n skeletonModelIds.add(parentId);\n parentId = findModelParentId(parentId, objectMap);\n }\n }\n\n return skeletonModelIds;\n}\n\nfunction buildSkeletonParentMap(skeletonModelIds: Set<number>, objectMap: FBXObjectMap): Map<number, number> {\n const parentByModelId = new Map<number, number>();\n\n for (const modelId of Array.from(skeletonModelIds)) {\n let parentId = findModelParentId(modelId, objectMap);\n while (parentId !== undefined) {\n if (skeletonModelIds.has(parentId)) {\n parentByModelId.set(modelId, parentId);\n break;\n }\n parentId = findModelParentId(parentId, objectMap);\n }\n }\n\n return parentByModelId;\n}\n\nfunction findModelParentId(modelId: number, objectMap: FBXObjectMap): number | undefined {\n const parentConnection = objectMap.connections.find((conn) => conn.type === \"OO\" && conn.childId === modelId && objectMap.objects.get(conn.parentId)?.name === \"Model\");\n return parentConnection?.parentId;\n}\n\nexport function isSkeletonModel(modelNode: FBXNode): boolean {\n const subType = getPropertyValue<string>(modelNode, 2);\n return subType === \"Root\" || subType === \"LimbNode\";\n}\n\nexport function extractBoneTransform(modelNode: FBXNode, template?: FBXPropertyTemplate): FBXNodeTransformData {\n return extractNodeTransform(modelNode, template ?? currentModelTemplate);\n}\n\nfunction extractClusterMatrices(clusterNode: FBXNode): {\n bindPoseMatrix: Float64Array | null;\n transformLinkMatrix: Float64Array | null;\n transformAssociateModelMatrix: Float64Array | null;\n clusterMode: FBXClusterMode;\n} {\n let bindPoseMatrix: Float64Array | null = null;\n let transformLinkMatrix: Float64Array | null = null;\n let transformAssociateModelMatrix: Float64Array | null = null;\n let clusterMode: FBXClusterMode = \"Normalize\";\n\n const transformNode = findChildByName(clusterNode, \"Transform\");\n if (transformNode && transformNode.properties[0]) {\n const val = getNodeArray(transformNode);\n if (val instanceof Float64Array && val.length === 16) {\n bindPoseMatrix = val;\n } else if (val instanceof Float32Array && val.length === 16) {\n bindPoseMatrix = new Float64Array(val);\n }\n }\n\n const transformLinkNode = findChildByName(clusterNode, \"TransformLink\");\n if (transformLinkNode && transformLinkNode.properties[0]) {\n const val = getNodeArray(transformLinkNode);\n if (val instanceof Float64Array && val.length === 16) {\n transformLinkMatrix = val;\n } else if (val instanceof Float32Array && val.length === 16) {\n transformLinkMatrix = new Float64Array(val);\n }\n }\n\n const transformAssociateModelNode = findChildByName(clusterNode, \"TransformAssociateModel\");\n if (transformAssociateModelNode && transformAssociateModelNode.properties[0]) {\n const val = getNodeArray(transformAssociateModelNode);\n if (val instanceof Float64Array && val.length === 16) {\n transformAssociateModelMatrix = val;\n } else if (val instanceof Float32Array && val.length === 16) {\n transformAssociateModelMatrix = new Float64Array(val);\n }\n }\n\n const modeNode = findChildByName(clusterNode, \"Mode\");\n const mode = modeNode ? getPropertyValue<string>(modeNode, 0) : undefined;\n if (mode === \"Normalize\" || mode === \"Additive\" || mode === \"TotalOne\") {\n clusterMode = mode;\n } else if (mode) {\n clusterMode = \"Unknown\";\n }\n\n return { bindPoseMatrix, transformLinkMatrix, transformAssociateModelMatrix, clusterMode };\n}\n\nfunction createBoneDiagnostics(\n modelId: number,\n boneName: string,\n isCluster: boolean,\n clusterMode: FBXClusterMode,\n bindPoseMatrix: Float64Array | null,\n transformLinkMatrix: Float64Array | null,\n transformAssociateModelMatrix: Float64Array | null,\n modelBindPoseMatrix: Float64Array | null\n): FBXSkinDiagnostic[] {\n if (!isCluster) {\n return [];\n }\n\n const diagnostics: FBXSkinDiagnostic[] = [];\n if (clusterMode === \"Additive\" || clusterMode === \"TotalOne\") {\n diagnostics.push({\n type: \"cluster-mode-runtime-unsupported\",\n message: `Cluster mode '${clusterMode}' is preserved but not applied by Babylon linear blend skinning.`,\n boneModelId: modelId,\n boneName,\n clusterMode,\n });\n }\n if (!bindPoseMatrix) {\n diagnostics.push({\n type: \"missing-cluster-transform\",\n message: \"Cluster is missing Transform matrix; falling back to rest/bind-pose data.\",\n boneModelId: modelId,\n boneName,\n clusterMode,\n });\n }\n if (!transformLinkMatrix) {\n diagnostics.push({\n type: \"missing-cluster-transform-link\",\n message: \"Cluster is missing TransformLink matrix; falling back to model bind pose or rest transform.\",\n boneModelId: modelId,\n boneName,\n clusterMode,\n });\n }\n if (!modelBindPoseMatrix) {\n diagnostics.push({\n type: \"missing-bind-pose-matrix\",\n message: \"No BindPose matrix was found for this bone model.\",\n boneModelId: modelId,\n boneName,\n clusterMode,\n });\n }\n if (transformAssociateModelMatrix) {\n diagnostics.push({\n type: \"associate-model-present\",\n message: \"TransformAssociateModel is preserved for future associate-model skinning semantics.\",\n boneModelId: modelId,\n boneName,\n clusterMode,\n });\n }\n\n return diagnostics;\n}\n\n/**\n * Extract per-vertex bone indices and weights from cluster data.\n * Returns arrays indexed by control point index.\n */\nfunction extractVertexWeights(\n bones: FBXBoneData[],\n boneModelMap: Map<number, { clusterId: number; clusterNode: FBXNode }>,\n objectMap: FBXObjectMap\n): { boneIndices: number[][]; boneWeights: number[][] } {\n // We need to find the max vertex index to size our arrays\n let maxVertexIndex = 0;\n\n // First pass: find max vertex index\n for (const bone of bones) {\n const clusterInfo = boneModelMap.get(bone.modelId);\n if (!clusterInfo) {\n continue;\n }\n\n const indexesNode = findChildByName(clusterInfo.clusterNode, \"Indexes\");\n if (!indexesNode) {\n continue;\n }\n\n const indexes = toInt32Array(getNodeArray(indexesNode));\n if (!indexes) {\n continue;\n }\n\n for (let i = 0; i < indexes.length; i++) {\n if (indexes[i] > maxVertexIndex) {\n maxVertexIndex = indexes[i];\n }\n }\n }\n\n // Initialize arrays\n const vertexCount = maxVertexIndex + 1;\n const boneIndices: number[][] = new Array(vertexCount);\n const boneWeights: number[][] = new Array(vertexCount);\n for (let i = 0; i < vertexCount; i++) {\n boneIndices[i] = [];\n boneWeights[i] = [];\n }\n\n // Second pass: collect influences\n for (const bone of bones) {\n const clusterInfo = boneModelMap.get(bone.modelId);\n if (!clusterInfo) {\n continue;\n }\n\n const indexesNode = findChildByName(clusterInfo.clusterNode, \"Indexes\");\n const weightsNode = findChildByName(clusterInfo.clusterNode, \"Weights\");\n if (!indexesNode || !weightsNode) {\n continue;\n }\n\n const indexes = toInt32Array(getNodeArray(indexesNode));\n const weights = toFloat64Array(getNodeArray(weightsNode));\n if (!indexes || !weights) {\n continue;\n }\n\n for (let i = 0; i < indexes.length; i++) {\n const vertIdx = indexes[i];\n boneIndices[vertIdx].push(bone.index);\n boneWeights[vertIdx].push(weights[i]);\n }\n }\n\n // Sort by weight descending and cap to Babylon's primary + extra influence buffers.\n for (let i = 0; i < vertexCount; i++) {\n if (boneIndices[i].length === 0) {\n continue;\n }\n\n const pairs = boneIndices[i].map((bi, idx) => ({\n index: bi,\n weight: boneWeights[i][idx],\n }));\n pairs.sort((a, b) => b.weight - a.weight);\n const cappedPairs = pairs.slice(0, MAX_BONE_INFLUENCES);\n boneIndices[i] = cappedPairs.map((p) => p.index);\n boneWeights[i] = cappedPairs.map((p) => p.weight);\n }\n\n // Normalize weights to sum to 1.0\n for (let i = 0; i < vertexCount; i++) {\n const sum = boneWeights[i].reduce((a, b) => a + b, 0);\n if (sum > 0) {\n for (let j = 0; j < boneWeights[i].length; j++) {\n boneWeights[i][j] /= sum;\n }\n }\n }\n\n return { boneIndices, boneWeights };\n}\n\n// ── Utilities ──────────────────────────────────────────────────────────────────\n\nfunction toInt32Array(value: unknown): Int32Array | null {\n if (value instanceof Int32Array) {\n return value;\n }\n if (value instanceof Float64Array) {\n const result = new Int32Array(value.length);\n for (let i = 0; i < value.length; i++) {\n result[i] = Math.round(value[i]);\n }\n return result;\n }\n return null;\n}\n\nfunction toFloat64Array(value: unknown): Float64Array | null {\n if (value instanceof Float64Array) {\n return value;\n }\n if (value instanceof Float32Array) {\n return new Float64Array(value);\n }\n return null;\n}\n"]}
@@ -15,15 +15,43 @@ export function parseAsciiFBX(text) {
15
15
  nodes.push(node);
16
16
  }
17
17
  }
18
+ if (version >= 7200) {
19
+ reinterpretKeyAttrDataFloat(nodes);
20
+ }
18
21
  return { version, nodes };
19
22
  }
23
+ /**
24
+ * In ASCII files of version 7.2+, `KeyAttrDataFloat` holds the raw 32-bit float bit patterns written as integers
25
+ * (some elements are genuinely integers). Reinterpret them so tangent data reads like the binary format.
26
+ */
27
+ function reinterpretKeyAttrDataFloat(nodes) {
28
+ for (const node of nodes) {
29
+ if (node.name === "KeyAttrDataFloat" && node.properties.length === 1 && node.properties[0].value instanceof Float64Array) {
30
+ const raw = node.properties[0].value;
31
+ const bits = new Int32Array(raw.length);
32
+ for (let i = 0; i < raw.length; i++) {
33
+ bits[i] = raw[i] | 0;
34
+ }
35
+ node.properties[0] = { type: "float32[]", value: new Float32Array(bits.buffer) };
36
+ }
37
+ if (node.children.length > 0) {
38
+ reinterpretKeyAttrDataFloat(node.children);
39
+ }
40
+ }
41
+ }
20
42
  /** Extract FBX version from the header comment (e.g. "; FBX 7.7.0 project file") */
21
43
  function parseVersion(text) {
22
44
  const match = text.match(/;\s*FBX\s+(\d+)\.(\d+)\.(\d+)/);
23
- if (!match) {
24
- throw new Error("Cannot determine FBX version from ASCII header");
45
+ if (match) {
46
+ return parseInt(match[1]) * 1000 + parseInt(match[2]) * 100 + parseInt(match[3]);
47
+ }
48
+ // Some files lack the header comment. The FBXHeaderExtension block carries the version too.
49
+ const ext = text.match(/FBXVersion:\s*(\d+)/);
50
+ if (ext) {
51
+ return parseInt(ext[1]);
25
52
  }
26
- return parseInt(match[1]) * 1000 + parseInt(match[2]) * 100 + parseInt(match[3]);
53
+ // Fall back to the layout heuristic: Properties70 blocks only exist in 7.x files.
54
+ return text.includes("Properties70") ? 7000 : 6000;
27
55
  }
28
56
  // ── Tokenizer ──────────────────────────────────────────────────────────────────
29
57
  var TokenType;
@@ -150,6 +178,10 @@ class Tokenizer {
150
178
  if (this.pos < this.len) {
151
179
  this.pos++; // skip closing quote
152
180
  }
181
+ // The SDK writes double quotes inside strings as &quot;
182
+ if (value.includes("&quot;")) {
183
+ value = value.split("&quot;").join('"');
184
+ }
153
185
  return { type: 2 /* TokenType.String */, value, pos: startPos };
154
186
  }
155
187
  readNumber() {
@@ -158,6 +190,15 @@ class Tokenizer {
158
190
  if (this.text[this.pos] === "-" || this.text[this.pos] === "+") {
159
191
  this.pos++;
160
192
  }
193
+ // Word-form specials: inf, infinity, nan, ind (any case), optionally signed, optionally with a
194
+ // parenthesised payload such as nan(ind) or nan(12345).
195
+ if (this.pos < this.len && this.isIdentStart(this.text[this.pos])) {
196
+ while (this.pos < this.len && this.isIdentStart(this.text[this.pos])) {
197
+ this.pos++;
198
+ }
199
+ this.skipSpecialNumberSuffix();
200
+ return { type: 1 /* TokenType.Number */, value: this.text.substring(startPos, this.pos), pos: startPos };
201
+ }
161
202
  while (this.pos < this.len && this.isDigit(this.text[this.pos])) {
162
203
  this.pos++;
163
204
  }
@@ -177,6 +218,14 @@ class Tokenizer {
177
218
  this.pos++;
178
219
  }
179
220
  }
221
+ // MSVC-style specials: 1.#INF, -1.#IND, 1.#QNAN, 1.#SNAN, 2.#IND12345678
222
+ if (this.pos < this.len && this.text[this.pos] === "#") {
223
+ this.pos++;
224
+ while (this.pos < this.len && (this.isIdentStart(this.text[this.pos]) || this.isDigit(this.text[this.pos]))) {
225
+ this.pos++;
226
+ }
227
+ this.skipSpecialNumberSuffix();
228
+ }
180
229
  return { type: 1 /* TokenType.Number */, value: this.text.substring(startPos, this.pos), pos: startPos };
181
230
  }
182
231
  readIdentifier() {
@@ -184,25 +233,57 @@ class Tokenizer {
184
233
  while (this.pos < this.len && this.isIdentChar(this.text[this.pos])) {
185
234
  this.pos++;
186
235
  }
236
+ // Malformed special numbers such as "snan(" or "Nan((" lex as identifiers; swallow their parenthesised tail.
237
+ this.skipSpecialNumberSuffix();
187
238
  return { type: 0 /* TokenType.Identifier */, value: this.text.substring(startPos, this.pos), pos: startPos };
188
239
  }
240
+ /** Consumes a run of parentheses and alphanumerics that some writers append to nan/inf tokens. */
241
+ skipSpecialNumberSuffix() {
242
+ if (this.pos < this.len && this.text[this.pos] === "(") {
243
+ while (this.pos < this.len) {
244
+ const ch = this.text[this.pos];
245
+ if (ch === "(" || ch === ")" || this.isIdentChar(ch)) {
246
+ this.pos++;
247
+ }
248
+ else {
249
+ break;
250
+ }
251
+ }
252
+ }
253
+ }
189
254
  isDigit(ch) {
190
255
  return ch >= "0" && ch <= "9";
191
256
  }
192
257
  isNumberStart(ch) {
193
- if (this.isDigit(ch)) {
258
+ if (this.isDigit(ch) || ch === ".") {
194
259
  return true;
195
260
  }
196
261
  if ((ch === "-" || ch === "+") && this.pos + 1 < this.len) {
197
- return this.isDigit(this.text[this.pos + 1]) || this.text[this.pos + 1] === ".";
262
+ const next = this.text[this.pos + 1];
263
+ return this.isDigit(next) || next === "." || isSpecialNumberWord(this.text.substring(this.pos + 1, this.pos + 10));
264
+ }
265
+ if (isSpecialNumberWord(this.text.substring(this.pos, this.pos + 9))) {
266
+ // Bare inf/nan words in value position; identifiers followed by ':' are node names and never match.
267
+ return !this.isFollowedByColon(this.pos);
198
268
  }
199
269
  return false;
200
270
  }
271
+ isFollowedByColon(from) {
272
+ let p = from;
273
+ while (p < this.len && this.isIdentChar(this.text[p])) {
274
+ p++;
275
+ }
276
+ while (p < this.len && (this.text[p] === " " || this.text[p] === "\t")) {
277
+ p++;
278
+ }
279
+ return p < this.len && this.text[p] === ":";
280
+ }
201
281
  isIdentStart(ch) {
202
282
  return (ch >= "a" && ch <= "z") || (ch >= "A" && ch <= "Z") || ch === "_";
203
283
  }
204
284
  isIdentChar(ch) {
205
- return this.isIdentStart(ch) || this.isDigit(ch) || ch === "|";
285
+ // '-' appears inside node names such as "Pre-Extrapolation" / "Post-Extrapolation".
286
+ return this.isIdentStart(ch) || this.isDigit(ch) || ch === "|" || ch === "-";
206
287
  }
207
288
  }
208
289
  // ── Node Parsing ───────────────────────────────────────────────────────────────
@@ -247,7 +328,11 @@ function parseNodeFromTokens(tokenizer) {
247
328
  const tok = tokenizer.next();
248
329
  const numVal = parseNumericValue(tok.value);
249
330
  if (Number.isInteger(numVal) && !tok.value.includes(".") && !tok.value.includes("e") && !tok.value.includes("E")) {
250
- properties.push({ type: isInt32(numVal) ? "int32" : "int64", value: numVal });
331
+ const property = { type: isInt32(numVal) ? "int32" : "int64", value: numVal };
332
+ if (!Number.isSafeInteger(numVal)) {
333
+ property.raw = canonicalIntegerText(tok.value);
334
+ }
335
+ properties.push(property);
251
336
  }
252
337
  else {
253
338
  properties.push({ type: "float64", value: numVal });
@@ -310,7 +395,12 @@ function parseArrayValues(tokenizer, count) {
310
395
  }
311
396
  if (peek.type === 1 /* TokenType.Number */) {
312
397
  const tok = tokenizer.next();
313
- values.push(Number(tok.value));
398
+ values.push(parseNumericValue(tok.value));
399
+ }
400
+ else if (peek.type === 0 /* TokenType.Identifier */ && !tokenizer.isNextNodeStart()) {
401
+ // Unrecognised nan/inf spellings ("snan", "infty", "ind") still count as values.
402
+ const tok = tokenizer.next();
403
+ values.push(parseNumericValue(tok.value));
314
404
  }
315
405
  else {
316
406
  break;
@@ -321,8 +411,28 @@ function parseArrayValues(tokenizer, count) {
321
411
  }
322
412
  return values;
323
413
  }
414
+ /** Matches a leading inf/infinity/nan/ind word (case-insensitive) at the start of the string. */
415
+ function isSpecialNumberWord(str) {
416
+ return /^(?:inf(?:inity)?|nan|ind)(?![A-Za-z0-9_|])/i.test(str);
417
+ }
324
418
  function parseNumericValue(str) {
325
- return Number(str);
419
+ const n = Number(str);
420
+ if (!Number.isNaN(n)) {
421
+ return n;
422
+ }
423
+ // "1.#INF", "-1.#IND", "1.#QNAN", "inf", "-Infinity", "nan", "nan(ind)", "infty"
424
+ const sign = str.startsWith("-") ? -1 : 1;
425
+ const body = str.replace(/^[+-]/, "").replace(/\(.*$/, "");
426
+ if (/#INF/i.test(body) || /^inf/i.test(body)) {
427
+ return sign * Infinity;
428
+ }
429
+ return NaN;
430
+ }
431
+ /** Integer text without sign prefix noise or leading zeros, so equal values produce equal keys. */
432
+ function canonicalIntegerText(text) {
433
+ const negative = text.startsWith("-");
434
+ const digits = text.replace(/^[+-]/, "").replace(/^0+(?=\d)/, "");
435
+ return negative && digits !== "0" ? `-${digits}` : digits;
326
436
  }
327
437
  function isInt32(value) {
328
438
  return value >= -2147483648 && value <= 2147483647;