@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
@@ -1,22 +1,12 @@
1
- import { getMappingForDeclaration, getMappingForFullOperationName } from "./declarationMapper.js";
1
+ import { getMappingForDeclaration, getNoOpMappingForDeclaration, ParseDebugLogTemplate } from "./declarationMapper.js";
2
2
  import { Logger } from "@babylonjs/core/Misc/logger.js";
3
3
  import { RandomGUID } from "@babylonjs/core/Misc/guid.js";
4
- // eslint-disable-next-line @typescript-eslint/naming-convention
5
- export const gltfTypeToBabylonType = {
6
- float: { length: 1, flowGraphType: "number" /* FlowGraphTypes.Number */, elementType: "number" },
7
- bool: { length: 1, flowGraphType: "boolean" /* FlowGraphTypes.Boolean */, elementType: "boolean" },
8
- float2: { length: 2, flowGraphType: "Vector2" /* FlowGraphTypes.Vector2 */, elementType: "number" },
9
- float3: { length: 3, flowGraphType: "Vector3" /* FlowGraphTypes.Vector3 */, elementType: "number" },
10
- float4: { length: 4, flowGraphType: "Vector4" /* FlowGraphTypes.Vector4 */, elementType: "number" },
11
- float4x4: { length: 16, flowGraphType: "Matrix" /* FlowGraphTypes.Matrix */, elementType: "number" },
12
- float2x2: { length: 4, flowGraphType: "Matrix2D" /* FlowGraphTypes.Matrix2D */, elementType: "number" },
13
- float3x3: { length: 9, flowGraphType: "Matrix3D" /* FlowGraphTypes.Matrix3D */, elementType: "number" },
14
- int: { length: 1, flowGraphType: "FlowGraphInteger" /* FlowGraphTypes.Integer */, elementType: "number" },
15
- // KHR_interactivity opaque reference type. Represented as a JSON Pointer string
16
- // (e.g. "/nodes/17/") that addresses a glTF object. The empty string is the
17
- // canonical "null reference" sentinel used by the parser.
18
- ref: { length: 1, flowGraphType: "string" /* FlowGraphTypes.String */, elementType: "string" },
19
- };
4
+ import { CloneKHRInteractivityGraph, CreateEffectiveKHRInteractivityGraph, gltfTypeToBabylonType } from "./interactivityGraphModel.js";
5
+ import { DelayReferencePrefix, EventReferencePrefix } from "./interactivityReferences.js";
6
+ export { gltfTypeToBabylonType } from "./interactivityGraphModel.js";
7
+ function _GetOwnMapping(mapping, key) {
8
+ return mapping && Object.prototype.hasOwnProperty.call(mapping, key) ? mapping[key] : undefined;
9
+ }
20
10
  /**
21
11
  * Parses a KHR_interactivity graph definition (the raw glTF JSON object) into
22
12
  * the serialized FlowGraph form consumed by {@link ParseFlowGraphAsync}.
@@ -26,10 +16,12 @@ export const gltfTypeToBabylonType = {
26
16
  * {@link serializeToFlowGraph}.
27
17
  */
28
18
  export class InteractivityGraphToFlowGraphParser {
29
- constructor(_interactivityGraph, _gltf, _animationTargetFps = 60) {
30
- this._interactivityGraph = _interactivityGraph;
19
+ constructor(interactivityGraph, _gltf, _animationTargetFps = 60, _graphIndex = 0, _supportedExtensions, _declarationModels) {
31
20
  this._gltf = _gltf;
32
21
  this._animationTargetFps = _animationTargetFps;
22
+ this._graphIndex = _graphIndex;
23
+ this._supportedExtensions = _supportedExtensions;
24
+ this._declarationModels = _declarationModels;
33
25
  /**
34
26
  * Note - the graph should be rejected if the same type is defined twice.
35
27
  * We currently don't validate that.
@@ -47,6 +39,9 @@ export class InteractivityGraphToFlowGraphParser {
47
39
  * the last block) is not disturbed, then concatenated into the serialized graph.
48
40
  */
49
41
  this._insertedBlocks = [];
42
+ this._interactivityGraph = this._declarationModels
43
+ ? CreateEffectiveKHRInteractivityGraph(interactivityGraph, this._declarationModels, this._gltf.nodes?.length ?? 0)
44
+ : CloneKHRInteractivityGraph(interactivityGraph);
50
45
  // start with types
51
46
  this._parseTypes();
52
47
  // continue with declarations
@@ -55,6 +50,74 @@ export class InteractivityGraphToFlowGraphParser {
55
50
  this._parseEvents();
56
51
  this._parseNodes();
57
52
  }
53
+ get _strictValidation() {
54
+ return !!this._declarationModels;
55
+ }
56
+ _hasDefaultFlowInput(operation) {
57
+ if (operation === "flow/waitAll") {
58
+ return false;
59
+ }
60
+ return (operation.startsWith("flow/") ||
61
+ operation.startsWith("animation/") ||
62
+ operation === "pointer/set" ||
63
+ operation === "pointer/interpolate" ||
64
+ operation === "variable/set" ||
65
+ operation === "variable/interpolate" ||
66
+ operation === "event/send" ||
67
+ operation === "event/stopPropagation" ||
68
+ operation === "flow/log:BABYLON");
69
+ }
70
+ _getAllowedDynamicValueSockets(operation, node, direction) {
71
+ if ((operation === "debug/log" || operation === "flow/log:BABYLON") && direction === "input") {
72
+ const message = node.configuration?.[operation === "debug/log" ? "message" : "messageTemplate"]?.value?.[0];
73
+ return new Set(typeof message === "string" ? ParseDebugLogTemplate(message).sockets : []);
74
+ }
75
+ if ((operation === "event/send" && direction === "input") || (operation === "event/receive" && direction === "output")) {
76
+ const eventIndex = node.configuration?.event?.value?.[0];
77
+ if (typeof eventIndex === "number") {
78
+ return new Set(Object.keys(this._interactivityGraph.events?.[eventIndex]?.values ?? {}));
79
+ }
80
+ }
81
+ if (operation === "variable/set" && direction === "input") {
82
+ return new Set((node.configuration?.variables?.value ?? []).map(String));
83
+ }
84
+ if (operation === "math/switch" && direction === "input") {
85
+ return new Set((node.configuration?.cases?.value ?? []).map(String));
86
+ }
87
+ if ((operation === "pointer/get" || operation === "pointer/set" || operation === "pointer/interpolate") && direction === "input") {
88
+ const pointer = node.configuration?.pointer?.value?.[0];
89
+ if (typeof pointer === "string") {
90
+ return new Set(pointer
91
+ .split("/")
92
+ .filter((segment) => (segment.startsWith("[") && !segment.startsWith("[[")) || (segment.startsWith("{") && !segment.startsWith("{{")))
93
+ .map((segment) => segment
94
+ .substring(1, segment.length - 1)
95
+ .replace(/~1/g, "/")
96
+ .replace(/~0/g, "~")));
97
+ }
98
+ }
99
+ return undefined;
100
+ }
101
+ _getAllowedDynamicFlowSockets(node, mapping, direction) {
102
+ for (const [key, property] of Object.entries(mapping.configuration ?? {})) {
103
+ const generatesSockets = direction === "input" ? property.generatesInputFlowSockets : property.generatesOutputFlowSockets;
104
+ if (!generatesSockets) {
105
+ continue;
106
+ }
107
+ const configuredValues = node.configuration?.[key]?.value;
108
+ const validValues = configuredValues &&
109
+ configuredValues.length > 0 &&
110
+ (property.configurationType !== "int" || configuredValues.length === 1) &&
111
+ configuredValues.every((value) => typeof value === "number" && Number.isInteger(value) && value >= (property.minimum ?? -2147483648) && value <= (property.maximum ?? 2147483647));
112
+ const values = validValues ? configuredValues : property.defaultValue;
113
+ if (direction === "input") {
114
+ const count = Array.isArray(values) && typeof values[0] === "number" ? values[0] : 0;
115
+ return new Set(Array.from({ length: count }, (_, index) => String(index)));
116
+ }
117
+ return new Set(Array.isArray(values) ? values.map(String) : []);
118
+ }
119
+ return undefined;
120
+ }
58
121
  get arrays() {
59
122
  return {
60
123
  types: this._types,
@@ -76,10 +139,15 @@ export class InteractivityGraphToFlowGraphParser {
76
139
  if (!this._interactivityGraph.declarations) {
77
140
  return;
78
141
  }
79
- for (const declaration of this._interactivityGraph.declarations) {
80
- // make sure we have the mapping for this operation
81
- const mapping = getMappingForDeclaration(declaration);
82
- // mapping is defined, because we generate an empty mapping if it's not found
142
+ for (let index = 0; index < this._interactivityGraph.declarations.length; index++) {
143
+ const declaration = this._interactivityGraph.declarations[index];
144
+ const declarationModel = this._declarationModels?.[index];
145
+ const extensionEnabled = !declaration.extension || !this._supportedExtensions || this._supportedExtensions.has(declaration.extension);
146
+ const supportedMapping = declarationModel?.support === "unsupported-extension" ? undefined : extensionEnabled ? getMappingForDeclaration(declaration, false) : undefined;
147
+ if (!supportedMapping && !declaration.extension) {
148
+ throw new Error(`Unknown core KHR_interactivity operation "${declaration.op}".`);
149
+ }
150
+ const mapping = supportedMapping ?? (declaration.extension ? getNoOpMappingForDeclaration(declaration) : undefined);
83
151
  if (!mapping) {
84
152
  Logger.Error(["No mapping found for declaration", declaration]);
85
153
  throw new Error("Error parsing declarations");
@@ -87,6 +155,13 @@ export class InteractivityGraphToFlowGraphParser {
87
155
  this._mappings.push({
88
156
  flowGraphMapping: mapping,
89
157
  fullOperationName: declaration.extension ? declaration.op + ":" + declaration.extension : declaration.op,
158
+ declaration: declarationModel ??
159
+ {
160
+ index,
161
+ operation: declaration.extension ? `${declaration.op}:${declaration.extension}` : declaration.op,
162
+ support: supportedMapping ? (declaration.extension ? "extension" : "core") : "unsupported-extension",
163
+ source: declaration,
164
+ },
90
165
  });
91
166
  }
92
167
  }
@@ -107,12 +182,12 @@ export class InteractivityGraphToFlowGraphParser {
107
182
  throw new Error("Error parsing variables");
108
183
  }
109
184
  if (variable.value) {
110
- if (variable.value.length !== type.length) {
185
+ if (this._interactivityGraph.types?.[variable.type]?.signature !== "custom" && variable.value.length !== type.length) {
111
186
  Logger.Error(["Invalid value length for variable", variable, type]);
112
187
  throw new Error("Error parsing variables");
113
188
  }
114
189
  }
115
- const value = variable.value || [];
190
+ const value = variable.value ? variable.value.slice() : [];
116
191
  if (!value.length) {
117
192
  switch (type.flowGraphType) {
118
193
  case "boolean" /* FlowGraphTypes.Boolean */:
@@ -137,13 +212,17 @@ export class InteractivityGraphToFlowGraphParser {
137
212
  case "Vector4" /* FlowGraphTypes.Vector4 */:
138
213
  case "Matrix2D" /* FlowGraphTypes.Matrix2D */:
139
214
  case "Quaternion" /* FlowGraphTypes.Quaternion */:
140
- value.fill(NaN, 0, 4);
215
+ value.push(NaN, NaN, NaN, NaN);
141
216
  break;
142
217
  case "Matrix" /* FlowGraphTypes.Matrix */:
143
- value.fill(NaN, 0, 16);
218
+ for (let i = 0; i < 16; i++) {
219
+ value.push(NaN);
220
+ }
144
221
  break;
145
222
  case "Matrix3D" /* FlowGraphTypes.Matrix3D */:
146
- value.fill(NaN, 0, 9);
223
+ for (let i = 0; i < 9; i++) {
224
+ value.push(NaN);
225
+ }
147
226
  break;
148
227
  default:
149
228
  break;
@@ -153,15 +232,52 @@ export class InteractivityGraphToFlowGraphParser {
153
232
  if (type.elementType === "number" && typeof value[0] === "string") {
154
233
  value[0] = parseFloat(value[0]);
155
234
  }
235
+ else if (type.flowGraphType === "string" /* FlowGraphTypes.String */ && typeof value[0] === "string") {
236
+ value[0] = this._normalizeStaticReference(value[0]);
237
+ }
156
238
  return { type: type.flowGraphType, value: dataTransform ? dataTransform(value, this) : value };
157
239
  }
240
+ _normalizeStaticReference(reference) {
241
+ if (!reference || reference.startsWith(EventReferencePrefix) || reference.startsWith(DelayReferencePrefix)) {
242
+ return "";
243
+ }
244
+ if (!reference.startsWith("/")) {
245
+ return "";
246
+ }
247
+ let current = this._gltf;
248
+ for (const rawSegment of reference.substring(1).split("/")) {
249
+ const segment = rawSegment.replace(/~1/g, "/").replace(/~0/g, "~");
250
+ if (Array.isArray(current)) {
251
+ if (!/^(0|[1-9]\d*)$/.test(segment)) {
252
+ return "";
253
+ }
254
+ current = current[parseInt(segment, 10)];
255
+ }
256
+ else if (current !== null && typeof current === "object" && Object.prototype.hasOwnProperty.call(current, segment)) {
257
+ current = current[segment];
258
+ }
259
+ else {
260
+ return "";
261
+ }
262
+ }
263
+ return current !== null && typeof current === "object" ? reference : "";
264
+ }
158
265
  _parseEvents() {
159
266
  if (!this._interactivityGraph.events) {
160
267
  return;
161
268
  }
269
+ const eventIds = new Set(this._interactivityGraph.events.flatMap((event) => (event.id === undefined ? [] : [event.id])));
270
+ const internalPrefix = `__babylon_khr_internal_${this._graphIndex}_`;
162
271
  for (const event of this._interactivityGraph.events) {
272
+ let generatedEventId;
273
+ if (event.id === undefined) {
274
+ do {
275
+ generatedEventId = internalPrefix + this._internalEventsCounter++;
276
+ } while (eventIds.has(generatedEventId));
277
+ eventIds.add(generatedEventId);
278
+ }
163
279
  const converted = {
164
- eventId: event.id || "internalEvent_" + this._internalEventsCounter++,
280
+ eventId: event.id ?? generatedEventId,
165
281
  };
166
282
  if (event.values) {
167
283
  converted.eventData = Object.keys(event.values).map((key) => {
@@ -191,7 +307,8 @@ export class InteractivityGraphToFlowGraphParser {
191
307
  if (!this._interactivityGraph.nodes) {
192
308
  return;
193
309
  }
194
- for (const node of this._interactivityGraph.nodes) {
310
+ for (let nodeIndex = 0; nodeIndex < this._interactivityGraph.nodes.length; nodeIndex++) {
311
+ const node = this._interactivityGraph.nodes[nodeIndex];
195
312
  // some validation
196
313
  if (typeof node.declaration !== "number") {
197
314
  Logger.Error(["No declaration found for node", node]);
@@ -209,16 +326,20 @@ export class InteractivityGraphToFlowGraphParser {
209
326
  }
210
327
  }
211
328
  const blocks = [];
329
+ if (mapping.declaration.support === "unsupported-extension") {
330
+ blocks.push(this._createUnsupportedExtensionBlock(node, nodeIndex, mapping));
331
+ }
212
332
  // create block(s) for this node using the mapping
213
- for (const blockType of mapping.flowGraphMapping.blocks) {
214
- const block = this._getEmptyBlock(blockType, mapping.fullOperationName);
333
+ for (let role = 0; role < mapping.flowGraphMapping.blocks.length; role++) {
334
+ const blockType = mapping.flowGraphMapping.blocks[role];
335
+ const block = this._getEmptyBlock(blockType, mapping.fullOperationName, nodeIndex, node.declaration, role);
215
336
  this._parseNodeConfiguration(node, block, mapping.flowGraphMapping, blockType);
216
337
  blocks.push(block);
217
338
  }
218
339
  this._nodes.push({ blocks, fullOperationName: mapping.fullOperationName });
219
340
  }
220
341
  }
221
- _getEmptyBlock(className, type) {
342
+ _getEmptyBlock(className, type, nodeIndex, declarationIndex, role) {
222
343
  return {
223
344
  uniqueId: RandomGUID(),
224
345
  className,
@@ -228,8 +349,55 @@ export class InteractivityGraphToFlowGraphParser {
228
349
  signalOutputs: [],
229
350
  config: {},
230
351
  type,
231
- metadata: {},
352
+ metadata: nodeIndex === undefined
353
+ ? {}
354
+ : {
355
+ khrInteractivity: {
356
+ graphIndex: this._graphIndex,
357
+ nodeIndex,
358
+ declarationIndex,
359
+ operation: type,
360
+ role: role ?? 0,
361
+ sourcePath: `/extensions/KHR_interactivity/graphs/${this._graphIndex}/nodes/${nodeIndex}`,
362
+ },
363
+ },
364
+ };
365
+ }
366
+ _createUnsupportedExtensionBlock(node, nodeIndex, mapping) {
367
+ const block = this._getEmptyBlock("KHR_interactivity/FlowGraphUnsupportedInteractivityBlock", mapping.fullOperationName, nodeIndex, node.declaration, 0);
368
+ const inputFlowSockets = new Set();
369
+ for (const sourceNode of this._interactivityGraph.nodes ?? []) {
370
+ for (const flow of Object.values(sourceNode.flows ?? {})) {
371
+ if (flow.node === nodeIndex) {
372
+ inputFlowSockets.add(flow.socket ?? "in");
373
+ }
374
+ }
375
+ }
376
+ const toSockets = (sockets) => Object.entries(sockets ?? {}).map(([name, definition]) => ({
377
+ name,
378
+ type: this._types[definition.type]?.flowGraphType,
379
+ signature: this._interactivityGraph.types?.[definition.type]?.signature,
380
+ }));
381
+ block.config = {
382
+ operation: mapping.fullOperationName,
383
+ inputValueSockets: toSockets(mapping.declaration.source.inputValueSockets),
384
+ outputValueSockets: toSockets(mapping.declaration.source.outputValueSockets),
385
+ inputFlowSockets: Array.from(inputFlowSockets).sort(),
386
+ outputFlowSockets: Object.keys(node.flows ?? {}).sort(),
232
387
  };
388
+ for (const socket of block.config.inputValueSockets) {
389
+ block.dataInputs.push(this._createNewSocketConnection(socket.name));
390
+ }
391
+ for (const socket of block.config.outputValueSockets) {
392
+ block.dataOutputs.push(this._createNewSocketConnection(socket.name, true));
393
+ }
394
+ for (const socket of block.config.inputFlowSockets) {
395
+ block.signalInputs.push(this._createNewSocketConnection(socket));
396
+ }
397
+ for (const socket of block.config.outputFlowSockets) {
398
+ block.signalOutputs.push(this._createNewSocketConnection(socket, true));
399
+ }
400
+ return block;
233
401
  }
234
402
  _parseNodeConfiguration(node, block, nodeMapping, blockType) {
235
403
  const gltfConfiguration = node.configuration;
@@ -240,6 +408,12 @@ export class InteractivityGraphToFlowGraphParser {
240
408
  throw new Error("Error parsing node configuration");
241
409
  }
242
410
  const propertyMapping = nodeMapping.configuration?.[key];
411
+ if (!propertyMapping && this._strictValidation) {
412
+ continue;
413
+ }
414
+ if (propertyMapping?.validationOnly) {
415
+ continue;
416
+ }
243
417
  const belongsToBlock = propertyMapping && propertyMapping.toBlock ? propertyMapping.toBlock === blockType : nodeMapping.blocks.indexOf(blockType) === 0;
244
418
  if (belongsToBlock) {
245
419
  let value = propertyMapping?.defaultValue;
@@ -297,8 +471,31 @@ export class InteractivityGraphToFlowGraphParser {
297
471
  // connect the flows
298
472
  for (const flowKey of flowsKeys) {
299
473
  const flow = flowsFromGLTF[flowKey];
300
- const flowMapping = outputMapper.flowGraphMapping.outputs?.flows?.[flowKey];
301
- const socketOutName = flowMapping?.name || flowKey;
474
+ let flowMapping = _GetOwnMapping(outputMapper.flowGraphMapping.outputs?.flows, flowKey);
475
+ if (this._strictValidation && flowMapping?.compatibilityOnly) {
476
+ flowMapping = undefined;
477
+ }
478
+ let outputArrayMapping = false;
479
+ if (!flowMapping) {
480
+ for (const key in outputMapper.flowGraphMapping.outputs?.flows) {
481
+ if (key.startsWith("[") && key.endsWith("]")) {
482
+ const wildcardMapping = outputMapper.flowGraphMapping.outputs?.flows?.[key];
483
+ if (!this._strictValidation || !wildcardMapping?.compatibilityOnly) {
484
+ outputArrayMapping = true;
485
+ flowMapping = wildcardMapping;
486
+ break;
487
+ }
488
+ }
489
+ }
490
+ }
491
+ const allowedDynamicOutputs = outputArrayMapping ? this._getAllowedDynamicFlowSockets(gltfNode, outputMapper.flowGraphMapping, "output") : undefined;
492
+ if (this._strictValidation && allowedDynamicOutputs && !allowedDynamicOutputs.has(flowKey)) {
493
+ flowMapping = undefined;
494
+ }
495
+ if (!flowMapping && !this._isUnsupportedExtensionBlock(flowGraphBlocks.blocks[0])) {
496
+ continue;
497
+ }
498
+ const socketOutName = flowMapping ? (outputArrayMapping ? flowMapping.name.replace("$1", flowKey) : flowMapping.name) : flowKey;
302
499
  // get the input node of this block
303
500
  const inputNodeId = flow.node;
304
501
  const nodeIn = this._nodes[inputNodeId];
@@ -314,24 +511,42 @@ export class InteractivityGraphToFlowGraphParser {
314
511
  continue;
315
512
  }
316
513
  // create a serialized socket
317
- const socketOut = this._createNewSocketConnection(socketOutName, true);
318
514
  const block = (flowMapping && flowMapping.toBlock && flowGraphBlocks.blocks.find((b) => b.className === flowMapping.toBlock)) || flowGraphBlocks.blocks[0];
319
- block.signalOutputs.push(socketOut);
515
+ const socketOut = block.signalOutputs.find((socket) => socket.name === socketOutName) ?? this._createNewSocketConnection(socketOutName, true);
516
+ if (!block.signalOutputs.includes(socketOut)) {
517
+ block.signalOutputs.push(socketOut);
518
+ }
320
519
  // get the mapper for the input node - in case it mapped to multiple blocks
321
- const inputMapper = getMappingForFullOperationName(nodeIn.fullOperationName);
520
+ const inputMapper = this._mappings[this._interactivityGraph.nodes[inputNodeId].declaration]?.flowGraphMapping;
322
521
  if (!inputMapper) {
323
522
  Logger.Error(["No mapping found for input node", nodeIn]);
324
523
  throw new Error("Error parsing node connections");
325
524
  }
326
- let flowInMapping = inputMapper.inputs?.flows?.[flow.socket || "in"];
525
+ let flowInMapping = _GetOwnMapping(inputMapper.inputs?.flows, flow.socket || "in");
526
+ if (this._strictValidation && flowInMapping?.compatibilityOnly) {
527
+ flowInMapping = undefined;
528
+ }
327
529
  let arrayMapping = false;
328
530
  if (!flowInMapping) {
329
531
  for (const key in inputMapper.inputs?.flows) {
330
532
  if (key.startsWith("[") && key.endsWith("]")) {
331
- arrayMapping = true;
332
- flowInMapping = inputMapper.inputs?.flows?.[key];
533
+ const wildcardMapping = inputMapper.inputs?.flows?.[key];
534
+ if (!this._strictValidation || !wildcardMapping?.compatibilityOnly) {
535
+ arrayMapping = true;
536
+ flowInMapping = wildcardMapping;
537
+ }
333
538
  }
334
539
  }
540
+ const allowedDynamicInputs = arrayMapping ? this._getAllowedDynamicFlowSockets(this._interactivityGraph.nodes[inputNodeId], inputMapper, "input") : undefined;
541
+ if (this._strictValidation && allowedDynamicInputs && !allowedDynamicInputs.has(flow.socket ?? "in")) {
542
+ flowInMapping = undefined;
543
+ }
544
+ if (!flowInMapping && (flow.socket ?? "in") === "in" && this._hasDefaultFlowInput(nodeIn.fullOperationName)) {
545
+ flowInMapping = { name: "in" };
546
+ }
547
+ if (!flowInMapping && !this._isUnsupportedExtensionBlock(nodeIn.blocks[0])) {
548
+ continue;
549
+ }
335
550
  }
336
551
  const nodeInSocketName = flowInMapping ? (arrayMapping ? flowInMapping.name.replace("$1", flow.socket || "") : flowInMapping.name) : flow.socket || "in";
337
552
  const inputBlock = (flowInMapping && flowInMapping.toBlock && nodeIn.blocks.find((b) => b.className === flowInMapping.toBlock)) || nodeIn.blocks[0];
@@ -351,21 +566,33 @@ export class InteractivityGraphToFlowGraphParser {
351
566
  const valuesKeys = Object.keys(valuesFromGLTF);
352
567
  for (const valueKey of valuesKeys) {
353
568
  const value = valuesFromGLTF[valueKey];
354
- let valueMapping = outputMapper.flowGraphMapping.inputs?.values?.[valueKey];
569
+ let valueMapping = _GetOwnMapping(outputMapper.flowGraphMapping.inputs?.values, valueKey);
570
+ if (this._strictValidation && valueMapping?.compatibilityOnly) {
571
+ valueMapping = undefined;
572
+ }
355
573
  let arrayMapping = false;
356
574
  if (!valueMapping) {
357
575
  for (const key in outputMapper.flowGraphMapping.inputs?.values) {
358
576
  if (key.startsWith("[") && key.endsWith("]")) {
359
- arrayMapping = true;
360
- valueMapping = outputMapper.flowGraphMapping.inputs?.values?.[key];
577
+ const wildcardMapping = outputMapper.flowGraphMapping.inputs?.values?.[key];
578
+ if (!this._strictValidation || !wildcardMapping?.compatibilityOnly) {
579
+ arrayMapping = true;
580
+ valueMapping = wildcardMapping;
581
+ }
361
582
  }
362
583
  }
363
584
  }
585
+ const allowedDynamicInputs = arrayMapping ? this._getAllowedDynamicValueSockets(outputMapper.fullOperationName, gltfNode, "input") : undefined;
586
+ if (!valueMapping || (allowedDynamicInputs && !allowedDynamicInputs.has(valueKey))) {
587
+ continue;
588
+ }
364
589
  const socketInName = valueMapping ? (arrayMapping ? valueMapping.name.replace("$1", valueKey) : valueMapping.name) : valueKey;
365
590
  // create a serialized socket
366
- const socketIn = this._createNewSocketConnection(socketInName);
367
591
  const block = (valueMapping && valueMapping.toBlock && flowGraphBlocks.blocks.find((b) => b.className === valueMapping.toBlock)) || flowGraphBlocks.blocks[0];
368
- block.dataInputs.push(socketIn);
592
+ const socketIn = block.dataInputs.find((socket) => socket.name === socketInName) ?? this._createNewSocketConnection(socketInName);
593
+ if (!block.dataInputs.includes(socketIn)) {
594
+ block.dataInputs.push(socketIn);
595
+ }
369
596
  // Captured before the connected branch below shadows `valueMapping`. When set and the
370
597
  // value is supplied by a connection, the seconds→frames `dataTransformer` cannot run
371
598
  // (it is parse-time only), so the raw connected value is scaled by a runtime multiply.
@@ -390,22 +617,34 @@ export class InteractivityGraphToFlowGraphParser {
390
617
  Logger.Warn(`Dropping value connection from no-op node #${nodeOutId} (unsupported operation: ${nodeOut.fullOperationName}) into node #${i} "${valueKey}"; consumer will use type-default value`);
391
618
  continue;
392
619
  }
393
- const outputMapper = getMappingForFullOperationName(nodeOut.fullOperationName);
620
+ const outputMapper = this._mappings[this._interactivityGraph.nodes[nodeOutId].declaration]?.flowGraphMapping;
394
621
  if (!outputMapper) {
395
622
  Logger.Error(["No mapping found for output socket reference", value]);
396
623
  throw new Error("Error parsing node connections");
397
624
  }
398
- let valueMapping = outputMapper.outputs?.values?.[nodeOutSocketName];
625
+ let valueMapping = _GetOwnMapping(outputMapper.outputs?.values, nodeOutSocketName);
626
+ if (this._strictValidation && valueMapping?.compatibilityOnly) {
627
+ valueMapping = undefined;
628
+ }
399
629
  let arrayMapping = false;
400
630
  // check if there is an array mapping defined
401
631
  if (!valueMapping) {
402
632
  // search for a value mapping that has an array mapping
403
633
  for (const key in outputMapper.outputs?.values) {
404
634
  if (key.startsWith("[") && key.endsWith("]")) {
405
- arrayMapping = true;
406
- valueMapping = outputMapper.outputs?.values?.[key];
635
+ const wildcardMapping = outputMapper.outputs?.values?.[key];
636
+ if (!this._strictValidation || !wildcardMapping?.compatibilityOnly) {
637
+ arrayMapping = true;
638
+ valueMapping = wildcardMapping;
639
+ }
407
640
  }
408
641
  }
642
+ const allowedDynamicOutputs = arrayMapping
643
+ ? this._getAllowedDynamicValueSockets(nodeOut.fullOperationName, this._interactivityGraph.nodes[nodeOutId], "output")
644
+ : undefined;
645
+ if (!valueMapping || (allowedDynamicOutputs && !allowedDynamicOutputs.has(nodeOutSocketName))) {
646
+ continue;
647
+ }
409
648
  }
410
649
  const socketOutName = valueMapping ? (arrayMapping ? valueMapping.name.replace("$1", nodeOutSocketName) : valueMapping?.name) : nodeOutSocketName;
411
650
  const outBlock = (valueMapping && valueMapping.toBlock && nodeOut.blocks.find((b) => b.className === valueMapping.toBlock)) || nodeOut.blocks[0];
@@ -417,7 +656,7 @@ export class InteractivityGraphToFlowGraphParser {
417
656
  }
418
657
  // connect the sockets
419
658
  if (convertConnectedTimeToFrames) {
420
- this._connectWithSecondsToFramesConversion(context, socketOut, socketIn);
659
+ this._connectWithSecondsToFramesConversion(context, socketOut, socketIn, i, gltfNode.declaration);
421
660
  }
422
661
  else {
423
662
  socketIn.connectedPointIds.push(socketOut.uniqueId);
@@ -456,6 +695,9 @@ export class InteractivityGraphToFlowGraphParser {
456
695
  connectedPointIds: [],
457
696
  };
458
697
  }
698
+ _isUnsupportedExtensionBlock(block) {
699
+ return block?.className === "KHR_interactivity/FlowGraphUnsupportedInteractivityBlock";
700
+ }
459
701
  /**
460
702
  * Wires an upstream data output into a downstream data input through a runtime multiply block that
461
703
  * scales the value by the animation target fps. This converts a KHR animation time (seconds),
@@ -465,9 +707,11 @@ export class InteractivityGraphToFlowGraphParser {
465
707
  * @param context the serialized flow graph context that stores literal socket values
466
708
  * @param upstreamOutput the data output socket providing the time value (in seconds)
467
709
  * @param downstreamInput the data input socket that expects the time in frames
710
+ * @param nodeIndex source node receiving the converted value
711
+ * @param declarationIndex source declaration used by the receiving node
468
712
  */
469
- _connectWithSecondsToFramesConversion(context, upstreamOutput, downstreamInput) {
470
- const multiplyBlock = this._getEmptyBlock("FlowGraphMultiplyBlock" /* FlowGraphBlockNames.Multiply */, "FlowGraphMultiplyBlock" /* FlowGraphBlockNames.Multiply */);
713
+ _connectWithSecondsToFramesConversion(context, upstreamOutput, downstreamInput, nodeIndex, declarationIndex) {
714
+ const multiplyBlock = this._getEmptyBlock("FlowGraphMultiplyBlock" /* FlowGraphBlockNames.Multiply */, "FlowGraphMultiplyBlock" /* FlowGraphBlockNames.Multiply */, nodeIndex, declarationIndex, -1);
471
715
  // Scalar (float) multiply; matches how the `math/mul` mapping configures the block.
472
716
  multiplyBlock.config = { type: "number" /* FlowGraphTypes.Number */ };
473
717
  const inputA = this._createNewSocketConnection("a");
@@ -531,6 +775,7 @@ export class InteractivityGraphToFlowGraphParser {
531
775
  }
532
776
  const allBlocks = this._nodes.reduce((acc, val) => acc.concat(val.blocks), []).concat(this._insertedBlocks);
533
777
  return {
778
+ name: this._interactivityGraph.name ?? `Graph ${this._graphIndex + 1}`,
534
779
  rightHanded: true,
535
780
  allBlocks,
536
781
  executionContexts: [context],