@babylonjs/loaders 9.26.1 → 9.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SPLAT/gaussianSplattingStream.d.ts +79 -25
- package/SPLAT/gaussianSplattingStream.js +320 -95
- package/SPLAT/gaussianSplattingStream.js.map +1 -1
- package/glTF/2.0/Extensions/EXT_texture_avif.pure.js +1 -1
- package/glTF/2.0/Extensions/EXT_texture_avif.pure.js.map +1 -1
- package/glTF/2.0/Extensions/EXT_texture_webp.pure.js +1 -1
- package/glTF/2.0/Extensions/EXT_texture_webp.pure.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_interactivity/declarationMapper.d.ts +143 -3
- package/glTF/2.0/Extensions/KHR_interactivity/declarationMapper.js +622 -99
- package/glTF/2.0/Extensions/KHR_interactivity/declarationMapper.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphEventReferenceBlock.d.ts +47 -0
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphEventReferenceBlock.js +68 -0
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphEventReferenceBlock.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphGLTFDataProvider.d.ts +2 -2
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphGLTFDataProvider.js +1 -1
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphGLTFDataProvider.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphObjectReferenceBlock.d.ts +24 -0
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphObjectReferenceBlock.js +38 -0
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphObjectReferenceBlock.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphUnsupportedInteractivityBlock.d.ts +41 -0
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphUnsupportedInteractivityBlock.js +63 -0
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphUnsupportedInteractivityBlock.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_interactivity/index.d.ts +6 -0
- package/glTF/2.0/Extensions/KHR_interactivity/index.js +6 -0
- package/glTF/2.0/Extensions/KHR_interactivity/index.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphExporter.d.ts +243 -0
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphExporter.js +2335 -0
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphExporter.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphModel.d.ts +193 -0
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphModel.js +919 -0
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphModel.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphParser.d.ts +30 -10
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphParser.js +485 -54
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphParser.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityHostResolver.d.ts +2 -1
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityHostResolver.js +7 -2
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityHostResolver.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityNodeState.d.ts +24 -0
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityNodeState.js +89 -0
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityNodeState.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_interactivity/pure.d.ts +6 -0
- package/glTF/2.0/Extensions/KHR_interactivity/pure.js +6 -0
- package/glTF/2.0/Extensions/KHR_interactivity/pure.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_interactivity.pure.d.ts +59 -1
- package/glTF/2.0/Extensions/KHR_interactivity.pure.js +129 -77
- package/glTF/2.0/Extensions/KHR_interactivity.pure.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_interactivity.types.d.ts +18 -1
- package/glTF/2.0/Extensions/KHR_interactivity.types.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_node_hoverability.pure.d.ts +2 -0
- package/glTF/2.0/Extensions/KHR_node_hoverability.pure.js +114 -56
- package/glTF/2.0/Extensions/KHR_node_hoverability.pure.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_node_selectability.pure.d.ts +2 -0
- package/glTF/2.0/Extensions/KHR_node_selectability.pure.js +80 -35
- package/glTF/2.0/Extensions/KHR_node_selectability.pure.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_texture_basisu.pure.js +1 -1
- package/glTF/2.0/Extensions/KHR_texture_basisu.pure.js.map +1 -1
- package/glTF/2.0/Extensions/interactivityRefPathToObjectConverter.js +3 -2
- package/glTF/2.0/Extensions/interactivityRefPathToObjectConverter.js.map +1 -1
- package/glTF/2.0/Extensions/objectModelMapping.d.ts +4 -2
- package/glTF/2.0/Extensions/objectModelMapping.js +33 -4
- package/glTF/2.0/Extensions/objectModelMapping.js.map +1 -1
- package/glTF/2.0/glTFLoader.pure.d.ts +3 -2
- package/glTF/2.0/glTFLoader.pure.js +50 -8
- package/glTF/2.0/glTFLoader.pure.js.map +1 -1
- package/glTF/2.0/glTFLoaderExtension.d.ts +2 -1
- package/glTF/2.0/glTFLoaderExtension.js.map +1 -1
- package/glTF/2.0/glTFLoaderInterfaces.d.ts +9 -0
- package/glTF/2.0/glTFLoaderInterfaces.js.map +1 -1
- package/package.json +3 -3
|
@@ -1,22 +1,81 @@
|
|
|
1
|
-
import { getMappingForDeclaration,
|
|
1
|
+
import { getMappingForDeclaration, getNoOpMappingForDeclaration, HasDefaultInteractivityFlowInput, NormalizeInteractivityEventDataConfiguration, 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
|
+
import { _CreateKHRInteractivityRuntimeValueSnapshot, CloneKHRInteractivityGraph, CreateEffectiveKHRInteractivityGraph, gltfTypeToBabylonType, KHR_INTERACTIVITY_SPECIFICATION_COMMIT, } 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
|
+
}
|
|
10
|
+
function _CloneMetadataValue(value) {
|
|
11
|
+
if (Array.isArray(value)) {
|
|
12
|
+
return value.map((entry) => _CloneMetadataValue(entry));
|
|
13
|
+
}
|
|
14
|
+
if (value !== null && typeof value === "object") {
|
|
15
|
+
const clone = {};
|
|
16
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
17
|
+
Object.defineProperty(clone, key, {
|
|
18
|
+
configurable: true,
|
|
19
|
+
enumerable: true,
|
|
20
|
+
value: _CloneMetadataValue(entry),
|
|
21
|
+
writable: true,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
return clone;
|
|
25
|
+
}
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
28
|
+
function _IsSerializableConfigurationValue(value) {
|
|
29
|
+
return (value === null ||
|
|
30
|
+
["string", "number", "boolean"].includes(typeof value) ||
|
|
31
|
+
(Array.isArray(value) && value.every(_IsSerializableConfigurationValue)) ||
|
|
32
|
+
(typeof value === "object" && Object.values(value).every(_IsSerializableConfigurationValue)));
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Captures import-time defaults for unconnected runtime inputs that have no authored KHR socket.
|
|
36
|
+
* @param flowGraph the fully parsed FlowGraph
|
|
37
|
+
* @internal
|
|
38
|
+
*/
|
|
4
39
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
};
|
|
40
|
+
export function _CaptureKHRInteractivityRuntimeInputDefaults(flowGraph) {
|
|
41
|
+
for (const block of flowGraph.getAllBlocks()) {
|
|
42
|
+
const provenance = block.metadata?.khrInteractivity;
|
|
43
|
+
if (!provenance) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (Object.prototype.hasOwnProperty.call(provenance.generatedConfiguration ?? {}, "eventData")) {
|
|
47
|
+
provenance.generatedConfigurationRuntime || (provenance.generatedConfigurationRuntime = {});
|
|
48
|
+
if (!Object.prototype.hasOwnProperty.call(provenance.generatedConfigurationRuntime, "eventData")) {
|
|
49
|
+
Object.defineProperty(provenance.generatedConfigurationRuntime, "eventData", {
|
|
50
|
+
configurable: true,
|
|
51
|
+
enumerable: true,
|
|
52
|
+
value: _CreateKHRInteractivityRuntimeValueSnapshot(NormalizeInteractivityEventDataConfiguration(block.config?.eventData)),
|
|
53
|
+
writable: true,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
for (const input of block.dataInputs) {
|
|
58
|
+
if (input.isConnected()) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
const socketProvenance = input.metadata?.khrInteractivity;
|
|
62
|
+
if (socketProvenance) {
|
|
63
|
+
socketProvenance.runtimeValueSnapshot ?? (socketProvenance.runtimeValueSnapshot = _CreateKHRInteractivityRuntimeValueSnapshot(input._defaultValue));
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (provenance.generatedInputDefaults && Object.prototype.hasOwnProperty.call(provenance.generatedInputDefaults, input.name)) {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
provenance.generatedInputDefaults || (provenance.generatedInputDefaults = {});
|
|
70
|
+
Object.defineProperty(provenance.generatedInputDefaults, input.name, {
|
|
71
|
+
configurable: true,
|
|
72
|
+
enumerable: true,
|
|
73
|
+
value: _CreateKHRInteractivityRuntimeValueSnapshot(input._defaultValue),
|
|
74
|
+
writable: true,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
20
79
|
/**
|
|
21
80
|
* Parses a KHR_interactivity graph definition (the raw glTF JSON object) into
|
|
22
81
|
* the serialized FlowGraph form consumed by {@link ParseFlowGraphAsync}.
|
|
@@ -26,10 +85,12 @@ export const gltfTypeToBabylonType = {
|
|
|
26
85
|
* {@link serializeToFlowGraph}.
|
|
27
86
|
*/
|
|
28
87
|
export class InteractivityGraphToFlowGraphParser {
|
|
29
|
-
constructor(
|
|
30
|
-
this._interactivityGraph = _interactivityGraph;
|
|
88
|
+
constructor(interactivityGraph, _gltf, _animationTargetFps = 60, _graphIndex = 0, _supportedExtensions, _declarationModels, canonicalGraph) {
|
|
31
89
|
this._gltf = _gltf;
|
|
32
90
|
this._animationTargetFps = _animationTargetFps;
|
|
91
|
+
this._graphIndex = _graphIndex;
|
|
92
|
+
this._supportedExtensions = _supportedExtensions;
|
|
93
|
+
this._declarationModels = _declarationModels;
|
|
33
94
|
/**
|
|
34
95
|
* Note - the graph should be rejected if the same type is defined twice.
|
|
35
96
|
* We currently don't validate that.
|
|
@@ -47,6 +108,10 @@ export class InteractivityGraphToFlowGraphParser {
|
|
|
47
108
|
* the last block) is not disturbed, then concatenated into the serialized graph.
|
|
48
109
|
*/
|
|
49
110
|
this._insertedBlocks = [];
|
|
111
|
+
this._canonicalGraph = CloneKHRInteractivityGraph(canonicalGraph ?? interactivityGraph);
|
|
112
|
+
this._interactivityGraph = this._declarationModels
|
|
113
|
+
? CreateEffectiveKHRInteractivityGraph(interactivityGraph, this._declarationModels, this._gltf.nodes?.length ?? 0)
|
|
114
|
+
: CloneKHRInteractivityGraph(interactivityGraph);
|
|
50
115
|
// start with types
|
|
51
116
|
this._parseTypes();
|
|
52
117
|
// continue with declarations
|
|
@@ -55,6 +120,60 @@ export class InteractivityGraphToFlowGraphParser {
|
|
|
55
120
|
this._parseEvents();
|
|
56
121
|
this._parseNodes();
|
|
57
122
|
}
|
|
123
|
+
get _strictValidation() {
|
|
124
|
+
return !!this._declarationModels;
|
|
125
|
+
}
|
|
126
|
+
_getAllowedDynamicValueSockets(operation, node, direction) {
|
|
127
|
+
if ((operation === "debug/log" || operation === "flow/log:BABYLON") && direction === "input") {
|
|
128
|
+
const message = node.configuration?.[operation === "debug/log" ? "message" : "messageTemplate"]?.value?.[0];
|
|
129
|
+
return new Set(typeof message === "string" ? ParseDebugLogTemplate(message).sockets : []);
|
|
130
|
+
}
|
|
131
|
+
if ((operation === "event/send" && direction === "input") || (operation === "event/receive" && direction === "output")) {
|
|
132
|
+
const eventIndex = node.configuration?.event?.value?.[0];
|
|
133
|
+
if (typeof eventIndex === "number") {
|
|
134
|
+
return new Set(Object.keys(this._interactivityGraph.events?.[eventIndex]?.values ?? {}));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (operation === "variable/set" && direction === "input") {
|
|
138
|
+
return new Set((node.configuration?.variables?.value ?? []).map(String));
|
|
139
|
+
}
|
|
140
|
+
if (operation === "math/switch" && direction === "input") {
|
|
141
|
+
return new Set((node.configuration?.cases?.value ?? []).map(String));
|
|
142
|
+
}
|
|
143
|
+
if ((operation === "pointer/get" || operation === "pointer/set" || operation === "pointer/interpolate") && direction === "input") {
|
|
144
|
+
const pointer = node.configuration?.pointer?.value?.[0];
|
|
145
|
+
if (typeof pointer === "string") {
|
|
146
|
+
return new Set(pointer
|
|
147
|
+
.split("/")
|
|
148
|
+
.filter((segment) => (segment.startsWith("[") && !segment.startsWith("[[")) || (segment.startsWith("{") && !segment.startsWith("{{")))
|
|
149
|
+
.map((segment) => segment
|
|
150
|
+
.substring(1, segment.length - 1)
|
|
151
|
+
.replace(/~1/g, "/")
|
|
152
|
+
.replace(/~0/g, "~")));
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
_getAllowedDynamicFlowSockets(node, mapping, direction) {
|
|
158
|
+
for (const [key, property] of Object.entries(mapping.configuration ?? {})) {
|
|
159
|
+
const generatesSockets = direction === "input" ? property.generatesInputFlowSockets : property.generatesOutputFlowSockets;
|
|
160
|
+
if (!generatesSockets) {
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
const configuredValues = node.configuration?.[key]?.value;
|
|
164
|
+
const validValues = configuredValues &&
|
|
165
|
+
configuredValues.length > 0 &&
|
|
166
|
+
(property.configurationType !== "int" || configuredValues.length === 1) &&
|
|
167
|
+
configuredValues.every((value) => typeof value === "number" && Number.isInteger(value) && value >= (property.minimum ?? -2147483648) && value <= (property.maximum ?? 2147483647));
|
|
168
|
+
const values = validValues ? configuredValues : property.defaultValue;
|
|
169
|
+
if (direction === "input") {
|
|
170
|
+
const count = Array.isArray(values) && typeof values[0] === "number" ? values[0] : 0;
|
|
171
|
+
return new Set(Array.from({ length: count }, (_, index) => String(index)));
|
|
172
|
+
}
|
|
173
|
+
return new Set(Array.isArray(values) ? values.map(String) : []);
|
|
174
|
+
}
|
|
175
|
+
return undefined;
|
|
176
|
+
}
|
|
58
177
|
get arrays() {
|
|
59
178
|
return {
|
|
60
179
|
types: this._types,
|
|
@@ -76,10 +195,15 @@ export class InteractivityGraphToFlowGraphParser {
|
|
|
76
195
|
if (!this._interactivityGraph.declarations) {
|
|
77
196
|
return;
|
|
78
197
|
}
|
|
79
|
-
for (
|
|
80
|
-
|
|
81
|
-
const
|
|
82
|
-
|
|
198
|
+
for (let index = 0; index < this._interactivityGraph.declarations.length; index++) {
|
|
199
|
+
const declaration = this._interactivityGraph.declarations[index];
|
|
200
|
+
const declarationModel = this._declarationModels?.[index];
|
|
201
|
+
const extensionEnabled = !declaration.extension || !this._supportedExtensions || this._supportedExtensions.has(declaration.extension);
|
|
202
|
+
const supportedMapping = declarationModel?.support === "unsupported-extension" ? undefined : extensionEnabled ? getMappingForDeclaration(declaration, false) : undefined;
|
|
203
|
+
if (!supportedMapping && !declaration.extension) {
|
|
204
|
+
throw new Error(`Unknown core KHR_interactivity operation "${declaration.op}".`);
|
|
205
|
+
}
|
|
206
|
+
const mapping = supportedMapping ?? (declaration.extension ? getNoOpMappingForDeclaration(declaration) : undefined);
|
|
83
207
|
if (!mapping) {
|
|
84
208
|
Logger.Error(["No mapping found for declaration", declaration]);
|
|
85
209
|
throw new Error("Error parsing declarations");
|
|
@@ -87,6 +211,13 @@ export class InteractivityGraphToFlowGraphParser {
|
|
|
87
211
|
this._mappings.push({
|
|
88
212
|
flowGraphMapping: mapping,
|
|
89
213
|
fullOperationName: declaration.extension ? declaration.op + ":" + declaration.extension : declaration.op,
|
|
214
|
+
declaration: declarationModel ??
|
|
215
|
+
{
|
|
216
|
+
index,
|
|
217
|
+
operation: declaration.extension ? `${declaration.op}:${declaration.extension}` : declaration.op,
|
|
218
|
+
support: supportedMapping ? (declaration.extension ? "extension" : "core") : "unsupported-extension",
|
|
219
|
+
source: declaration,
|
|
220
|
+
},
|
|
90
221
|
});
|
|
91
222
|
}
|
|
92
223
|
}
|
|
@@ -107,12 +238,12 @@ export class InteractivityGraphToFlowGraphParser {
|
|
|
107
238
|
throw new Error("Error parsing variables");
|
|
108
239
|
}
|
|
109
240
|
if (variable.value) {
|
|
110
|
-
if (variable.value.length !== type.length) {
|
|
241
|
+
if (this._interactivityGraph.types?.[variable.type]?.signature !== "custom" && variable.value.length !== type.length) {
|
|
111
242
|
Logger.Error(["Invalid value length for variable", variable, type]);
|
|
112
243
|
throw new Error("Error parsing variables");
|
|
113
244
|
}
|
|
114
245
|
}
|
|
115
|
-
const value = variable.value
|
|
246
|
+
const value = variable.value ? variable.value.slice() : [];
|
|
116
247
|
if (!value.length) {
|
|
117
248
|
switch (type.flowGraphType) {
|
|
118
249
|
case "boolean" /* FlowGraphTypes.Boolean */:
|
|
@@ -137,13 +268,17 @@ export class InteractivityGraphToFlowGraphParser {
|
|
|
137
268
|
case "Vector4" /* FlowGraphTypes.Vector4 */:
|
|
138
269
|
case "Matrix2D" /* FlowGraphTypes.Matrix2D */:
|
|
139
270
|
case "Quaternion" /* FlowGraphTypes.Quaternion */:
|
|
140
|
-
value.
|
|
271
|
+
value.push(NaN, NaN, NaN, NaN);
|
|
141
272
|
break;
|
|
142
273
|
case "Matrix" /* FlowGraphTypes.Matrix */:
|
|
143
|
-
|
|
274
|
+
for (let i = 0; i < 16; i++) {
|
|
275
|
+
value.push(NaN);
|
|
276
|
+
}
|
|
144
277
|
break;
|
|
145
278
|
case "Matrix3D" /* FlowGraphTypes.Matrix3D */:
|
|
146
|
-
|
|
279
|
+
for (let i = 0; i < 9; i++) {
|
|
280
|
+
value.push(NaN);
|
|
281
|
+
}
|
|
147
282
|
break;
|
|
148
283
|
default:
|
|
149
284
|
break;
|
|
@@ -153,15 +288,52 @@ export class InteractivityGraphToFlowGraphParser {
|
|
|
153
288
|
if (type.elementType === "number" && typeof value[0] === "string") {
|
|
154
289
|
value[0] = parseFloat(value[0]);
|
|
155
290
|
}
|
|
291
|
+
else if (type.flowGraphType === "string" /* FlowGraphTypes.String */ && typeof value[0] === "string") {
|
|
292
|
+
value[0] = this._normalizeStaticReference(value[0]);
|
|
293
|
+
}
|
|
156
294
|
return { type: type.flowGraphType, value: dataTransform ? dataTransform(value, this) : value };
|
|
157
295
|
}
|
|
296
|
+
_normalizeStaticReference(reference) {
|
|
297
|
+
if (!reference || reference.startsWith(EventReferencePrefix) || reference.startsWith(DelayReferencePrefix)) {
|
|
298
|
+
return "";
|
|
299
|
+
}
|
|
300
|
+
if (!reference.startsWith("/")) {
|
|
301
|
+
return "";
|
|
302
|
+
}
|
|
303
|
+
let current = this._gltf;
|
|
304
|
+
for (const rawSegment of reference.substring(1).split("/")) {
|
|
305
|
+
const segment = rawSegment.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
306
|
+
if (Array.isArray(current)) {
|
|
307
|
+
if (!/^(0|[1-9]\d*)$/.test(segment)) {
|
|
308
|
+
return "";
|
|
309
|
+
}
|
|
310
|
+
current = current[parseInt(segment, 10)];
|
|
311
|
+
}
|
|
312
|
+
else if (current !== null && typeof current === "object" && Object.prototype.hasOwnProperty.call(current, segment)) {
|
|
313
|
+
current = current[segment];
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
316
|
+
return "";
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return current !== null && typeof current === "object" ? reference : "";
|
|
320
|
+
}
|
|
158
321
|
_parseEvents() {
|
|
159
322
|
if (!this._interactivityGraph.events) {
|
|
160
323
|
return;
|
|
161
324
|
}
|
|
325
|
+
const eventIds = new Set(this._interactivityGraph.events.flatMap((event) => (event.id === undefined ? [] : [event.id])));
|
|
326
|
+
const internalPrefix = `__babylon_khr_internal_${this._graphIndex}_`;
|
|
162
327
|
for (const event of this._interactivityGraph.events) {
|
|
328
|
+
let generatedEventId;
|
|
329
|
+
if (event.id === undefined) {
|
|
330
|
+
do {
|
|
331
|
+
generatedEventId = internalPrefix + this._internalEventsCounter++;
|
|
332
|
+
} while (eventIds.has(generatedEventId));
|
|
333
|
+
eventIds.add(generatedEventId);
|
|
334
|
+
}
|
|
163
335
|
const converted = {
|
|
164
|
-
eventId: event.id
|
|
336
|
+
eventId: event.id ?? generatedEventId,
|
|
165
337
|
};
|
|
166
338
|
if (event.values) {
|
|
167
339
|
converted.eventData = Object.keys(event.values).map((key) => {
|
|
@@ -191,7 +363,8 @@ export class InteractivityGraphToFlowGraphParser {
|
|
|
191
363
|
if (!this._interactivityGraph.nodes) {
|
|
192
364
|
return;
|
|
193
365
|
}
|
|
194
|
-
for (
|
|
366
|
+
for (let nodeIndex = 0; nodeIndex < this._interactivityGraph.nodes.length; nodeIndex++) {
|
|
367
|
+
const node = this._interactivityGraph.nodes[nodeIndex];
|
|
195
368
|
// some validation
|
|
196
369
|
if (typeof node.declaration !== "number") {
|
|
197
370
|
Logger.Error(["No declaration found for node", node]);
|
|
@@ -209,16 +382,30 @@ export class InteractivityGraphToFlowGraphParser {
|
|
|
209
382
|
}
|
|
210
383
|
}
|
|
211
384
|
const blocks = [];
|
|
385
|
+
if (mapping.declaration.support === "unsupported-extension") {
|
|
386
|
+
blocks.push(this._createUnsupportedExtensionBlock(node, nodeIndex, mapping));
|
|
387
|
+
}
|
|
212
388
|
// create block(s) for this node using the mapping
|
|
213
|
-
for (
|
|
214
|
-
const
|
|
389
|
+
for (let role = 0; role < mapping.flowGraphMapping.blocks.length; role++) {
|
|
390
|
+
const blockType = mapping.flowGraphMapping.blocks[role];
|
|
391
|
+
const block = this._getEmptyBlock(blockType, mapping.fullOperationName, nodeIndex, node.declaration, role);
|
|
215
392
|
this._parseNodeConfiguration(node, block, mapping.flowGraphMapping, blockType);
|
|
216
393
|
blocks.push(block);
|
|
217
394
|
}
|
|
218
395
|
this._nodes.push({ blocks, fullOperationName: mapping.fullOperationName });
|
|
219
396
|
}
|
|
220
397
|
}
|
|
221
|
-
|
|
398
|
+
_createBlockProvenance(nodeIndex, declarationIndex, operation, role) {
|
|
399
|
+
return {
|
|
400
|
+
graphIndex: this._graphIndex,
|
|
401
|
+
nodeIndex,
|
|
402
|
+
declarationIndex,
|
|
403
|
+
operation,
|
|
404
|
+
role,
|
|
405
|
+
sourcePath: `/extensions/KHR_interactivity/graphs/${this._graphIndex}/nodes/${nodeIndex}`,
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
_getEmptyBlock(className, type, nodeIndex, declarationIndex, role) {
|
|
222
409
|
return {
|
|
223
410
|
uniqueId: RandomGUID(),
|
|
224
411
|
className,
|
|
@@ -228,9 +415,71 @@ export class InteractivityGraphToFlowGraphParser {
|
|
|
228
415
|
signalOutputs: [],
|
|
229
416
|
config: {},
|
|
230
417
|
type,
|
|
231
|
-
metadata:
|
|
418
|
+
metadata: nodeIndex === undefined
|
|
419
|
+
? {}
|
|
420
|
+
: {
|
|
421
|
+
khrInteractivity: this._createBlockProvenance(nodeIndex, declarationIndex, type, role ?? 0),
|
|
422
|
+
},
|
|
232
423
|
};
|
|
233
424
|
}
|
|
425
|
+
_setSocketProvenance(connection, nodeIndex, declarationIndex, operation, role, kind, direction, socket) {
|
|
426
|
+
connection.metadata = {
|
|
427
|
+
...(connection.metadata ?? {}),
|
|
428
|
+
khrInteractivity: {
|
|
429
|
+
...this._createBlockProvenance(nodeIndex, declarationIndex, operation, role),
|
|
430
|
+
kind,
|
|
431
|
+
direction,
|
|
432
|
+
socket,
|
|
433
|
+
},
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
_getBlockRole(blocks, block) {
|
|
437
|
+
return block.metadata?.khrInteractivity?.role ?? blocks.indexOf(block);
|
|
438
|
+
}
|
|
439
|
+
_createUnsupportedExtensionBlock(node, nodeIndex, mapping) {
|
|
440
|
+
const block = this._getEmptyBlock("KHR_interactivity/FlowGraphUnsupportedInteractivityBlock", mapping.fullOperationName, nodeIndex, node.declaration, 0);
|
|
441
|
+
const inputFlowSockets = new Set();
|
|
442
|
+
for (const sourceNode of this._interactivityGraph.nodes ?? []) {
|
|
443
|
+
for (const flow of Object.values(sourceNode.flows ?? {})) {
|
|
444
|
+
if (flow.node === nodeIndex) {
|
|
445
|
+
inputFlowSockets.add(flow.socket ?? "in");
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
const toSockets = (sockets) => Object.entries(sockets ?? {}).map(([name, definition]) => ({
|
|
450
|
+
name,
|
|
451
|
+
type: this._types[definition.type]?.flowGraphType,
|
|
452
|
+
signature: this._interactivityGraph.types?.[definition.type]?.signature,
|
|
453
|
+
}));
|
|
454
|
+
block.config = {
|
|
455
|
+
operation: mapping.fullOperationName,
|
|
456
|
+
inputValueSockets: toSockets(mapping.declaration.source.inputValueSockets),
|
|
457
|
+
outputValueSockets: toSockets(mapping.declaration.source.outputValueSockets),
|
|
458
|
+
inputFlowSockets: Array.from(inputFlowSockets).sort(),
|
|
459
|
+
outputFlowSockets: Object.keys(node.flows ?? {}).sort(),
|
|
460
|
+
};
|
|
461
|
+
for (const socket of block.config.inputValueSockets) {
|
|
462
|
+
const connection = this._createNewSocketConnection(socket.name);
|
|
463
|
+
this._setSocketProvenance(connection, nodeIndex, node.declaration, mapping.fullOperationName, 0, "value", "input", socket.name);
|
|
464
|
+
block.dataInputs.push(connection);
|
|
465
|
+
}
|
|
466
|
+
for (const socket of block.config.outputValueSockets) {
|
|
467
|
+
const connection = this._createNewSocketConnection(socket.name, true);
|
|
468
|
+
this._setSocketProvenance(connection, nodeIndex, node.declaration, mapping.fullOperationName, 0, "value", "output", socket.name);
|
|
469
|
+
block.dataOutputs.push(connection);
|
|
470
|
+
}
|
|
471
|
+
for (const socket of block.config.inputFlowSockets) {
|
|
472
|
+
const connection = this._createNewSocketConnection(socket);
|
|
473
|
+
this._setSocketProvenance(connection, nodeIndex, node.declaration, mapping.fullOperationName, 0, "flow", "input", socket);
|
|
474
|
+
block.signalInputs.push(connection);
|
|
475
|
+
}
|
|
476
|
+
for (const socket of block.config.outputFlowSockets) {
|
|
477
|
+
const connection = this._createNewSocketConnection(socket, true);
|
|
478
|
+
this._setSocketProvenance(connection, nodeIndex, node.declaration, mapping.fullOperationName, 0, "flow", "output", socket);
|
|
479
|
+
block.signalOutputs.push(connection);
|
|
480
|
+
}
|
|
481
|
+
return block;
|
|
482
|
+
}
|
|
234
483
|
_parseNodeConfiguration(node, block, nodeMapping, blockType) {
|
|
235
484
|
const gltfConfiguration = node.configuration;
|
|
236
485
|
if (gltfConfiguration) {
|
|
@@ -240,6 +489,12 @@ export class InteractivityGraphToFlowGraphParser {
|
|
|
240
489
|
throw new Error("Error parsing node configuration");
|
|
241
490
|
}
|
|
242
491
|
const propertyMapping = nodeMapping.configuration?.[key];
|
|
492
|
+
if (!propertyMapping && this._strictValidation) {
|
|
493
|
+
continue;
|
|
494
|
+
}
|
|
495
|
+
if (propertyMapping?.validationOnly) {
|
|
496
|
+
continue;
|
|
497
|
+
}
|
|
243
498
|
const belongsToBlock = propertyMapping && propertyMapping.toBlock ? propertyMapping.toBlock === blockType : nodeMapping.blocks.indexOf(blockType) === 0;
|
|
244
499
|
if (belongsToBlock) {
|
|
245
500
|
let value = propertyMapping?.defaultValue;
|
|
@@ -297,8 +552,31 @@ export class InteractivityGraphToFlowGraphParser {
|
|
|
297
552
|
// connect the flows
|
|
298
553
|
for (const flowKey of flowsKeys) {
|
|
299
554
|
const flow = flowsFromGLTF[flowKey];
|
|
300
|
-
|
|
301
|
-
|
|
555
|
+
let flowMapping = _GetOwnMapping(outputMapper.flowGraphMapping.outputs?.flows, flowKey);
|
|
556
|
+
if (this._strictValidation && flowMapping?.compatibilityOnly) {
|
|
557
|
+
flowMapping = undefined;
|
|
558
|
+
}
|
|
559
|
+
let outputArrayMapping = false;
|
|
560
|
+
if (!flowMapping) {
|
|
561
|
+
for (const key in outputMapper.flowGraphMapping.outputs?.flows) {
|
|
562
|
+
if (key.startsWith("[") && key.endsWith("]")) {
|
|
563
|
+
const wildcardMapping = outputMapper.flowGraphMapping.outputs?.flows?.[key];
|
|
564
|
+
if (!this._strictValidation || !wildcardMapping?.compatibilityOnly) {
|
|
565
|
+
outputArrayMapping = true;
|
|
566
|
+
flowMapping = wildcardMapping;
|
|
567
|
+
break;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
const allowedDynamicOutputs = outputArrayMapping ? this._getAllowedDynamicFlowSockets(gltfNode, outputMapper.flowGraphMapping, "output") : undefined;
|
|
573
|
+
if (this._strictValidation && allowedDynamicOutputs && !allowedDynamicOutputs.has(flowKey)) {
|
|
574
|
+
flowMapping = undefined;
|
|
575
|
+
}
|
|
576
|
+
if (!flowMapping && !this._isUnsupportedExtensionBlock(flowGraphBlocks.blocks[0])) {
|
|
577
|
+
continue;
|
|
578
|
+
}
|
|
579
|
+
const socketOutName = flowMapping ? (outputArrayMapping ? flowMapping.name.replace("$1", flowKey) : flowMapping.name) : flowKey;
|
|
302
580
|
// get the input node of this block
|
|
303
581
|
const inputNodeId = flow.node;
|
|
304
582
|
const nodeIn = this._nodes[inputNodeId];
|
|
@@ -314,24 +592,43 @@ export class InteractivityGraphToFlowGraphParser {
|
|
|
314
592
|
continue;
|
|
315
593
|
}
|
|
316
594
|
// create a serialized socket
|
|
317
|
-
const socketOut = this._createNewSocketConnection(socketOutName, true);
|
|
318
595
|
const block = (flowMapping && flowMapping.toBlock && flowGraphBlocks.blocks.find((b) => b.className === flowMapping.toBlock)) || flowGraphBlocks.blocks[0];
|
|
319
|
-
block.signalOutputs.
|
|
596
|
+
const socketOut = block.signalOutputs.find((socket) => socket.name === socketOutName) ?? this._createNewSocketConnection(socketOutName, true);
|
|
597
|
+
if (!block.signalOutputs.includes(socketOut)) {
|
|
598
|
+
block.signalOutputs.push(socketOut);
|
|
599
|
+
}
|
|
600
|
+
this._setSocketProvenance(socketOut, i, gltfNode.declaration, flowGraphBlocks.fullOperationName, this._getBlockRole(flowGraphBlocks.blocks, block), "flow", "output", flowKey);
|
|
320
601
|
// get the mapper for the input node - in case it mapped to multiple blocks
|
|
321
|
-
const inputMapper =
|
|
602
|
+
const inputMapper = this._mappings[this._interactivityGraph.nodes[inputNodeId].declaration]?.flowGraphMapping;
|
|
322
603
|
if (!inputMapper) {
|
|
323
604
|
Logger.Error(["No mapping found for input node", nodeIn]);
|
|
324
605
|
throw new Error("Error parsing node connections");
|
|
325
606
|
}
|
|
326
|
-
let flowInMapping = inputMapper.inputs?.flows
|
|
607
|
+
let flowInMapping = _GetOwnMapping(inputMapper.inputs?.flows, flow.socket || "in");
|
|
608
|
+
if (this._strictValidation && flowInMapping?.compatibilityOnly) {
|
|
609
|
+
flowInMapping = undefined;
|
|
610
|
+
}
|
|
327
611
|
let arrayMapping = false;
|
|
328
612
|
if (!flowInMapping) {
|
|
329
613
|
for (const key in inputMapper.inputs?.flows) {
|
|
330
614
|
if (key.startsWith("[") && key.endsWith("]")) {
|
|
331
|
-
|
|
332
|
-
|
|
615
|
+
const wildcardMapping = inputMapper.inputs?.flows?.[key];
|
|
616
|
+
if (!this._strictValidation || !wildcardMapping?.compatibilityOnly) {
|
|
617
|
+
arrayMapping = true;
|
|
618
|
+
flowInMapping = wildcardMapping;
|
|
619
|
+
}
|
|
333
620
|
}
|
|
334
621
|
}
|
|
622
|
+
const allowedDynamicInputs = arrayMapping ? this._getAllowedDynamicFlowSockets(this._interactivityGraph.nodes[inputNodeId], inputMapper, "input") : undefined;
|
|
623
|
+
if (this._strictValidation && allowedDynamicInputs && !allowedDynamicInputs.has(flow.socket ?? "in")) {
|
|
624
|
+
flowInMapping = undefined;
|
|
625
|
+
}
|
|
626
|
+
if (!flowInMapping && (flow.socket ?? "in") === "in" && HasDefaultInteractivityFlowInput(nodeIn.fullOperationName)) {
|
|
627
|
+
flowInMapping = { name: "in" };
|
|
628
|
+
}
|
|
629
|
+
if (!flowInMapping && !this._isUnsupportedExtensionBlock(nodeIn.blocks[0])) {
|
|
630
|
+
continue;
|
|
631
|
+
}
|
|
335
632
|
}
|
|
336
633
|
const nodeInSocketName = flowInMapping ? (arrayMapping ? flowInMapping.name.replace("$1", flow.socket || "") : flowInMapping.name) : flow.socket || "in";
|
|
337
634
|
const inputBlock = (flowInMapping && flowInMapping.toBlock && nodeIn.blocks.find((b) => b.className === flowInMapping.toBlock)) || nodeIn.blocks[0];
|
|
@@ -342,6 +639,7 @@ export class InteractivityGraphToFlowGraphParser {
|
|
|
342
639
|
socketIn = this._createNewSocketConnection(nodeInSocketName);
|
|
343
640
|
inputBlock.signalInputs.push(socketIn);
|
|
344
641
|
}
|
|
642
|
+
this._setSocketProvenance(socketIn, inputNodeId, this._interactivityGraph.nodes[inputNodeId].declaration, nodeIn.fullOperationName, this._getBlockRole(nodeIn.blocks, inputBlock), "flow", "input", flow.socket ?? "in");
|
|
345
643
|
// connect the sockets
|
|
346
644
|
socketIn.connectedPointIds.push(socketOut.uniqueId);
|
|
347
645
|
socketOut.connectedPointIds.push(socketIn.uniqueId);
|
|
@@ -351,21 +649,36 @@ export class InteractivityGraphToFlowGraphParser {
|
|
|
351
649
|
const valuesKeys = Object.keys(valuesFromGLTF);
|
|
352
650
|
for (const valueKey of valuesKeys) {
|
|
353
651
|
const value = valuesFromGLTF[valueKey];
|
|
354
|
-
let valueMapping = outputMapper.flowGraphMapping.inputs?.values
|
|
652
|
+
let valueMapping = _GetOwnMapping(outputMapper.flowGraphMapping.inputs?.values, valueKey);
|
|
653
|
+
if (this._strictValidation && valueMapping?.compatibilityOnly) {
|
|
654
|
+
valueMapping = undefined;
|
|
655
|
+
}
|
|
355
656
|
let arrayMapping = false;
|
|
356
657
|
if (!valueMapping) {
|
|
357
658
|
for (const key in outputMapper.flowGraphMapping.inputs?.values) {
|
|
358
659
|
if (key.startsWith("[") && key.endsWith("]")) {
|
|
359
|
-
|
|
360
|
-
|
|
660
|
+
const wildcardMapping = outputMapper.flowGraphMapping.inputs?.values?.[key];
|
|
661
|
+
if (!this._strictValidation || !wildcardMapping?.compatibilityOnly) {
|
|
662
|
+
arrayMapping = true;
|
|
663
|
+
valueMapping = wildcardMapping;
|
|
664
|
+
}
|
|
361
665
|
}
|
|
362
666
|
}
|
|
363
667
|
}
|
|
668
|
+
const allowedDynamicInputs = arrayMapping ? this._getAllowedDynamicValueSockets(outputMapper.fullOperationName, gltfNode, "input") : undefined;
|
|
669
|
+
if (!valueMapping || (allowedDynamicInputs && !allowedDynamicInputs.has(valueKey))) {
|
|
670
|
+
continue;
|
|
671
|
+
}
|
|
364
672
|
const socketInName = valueMapping ? (arrayMapping ? valueMapping.name.replace("$1", valueKey) : valueMapping.name) : valueKey;
|
|
365
673
|
// create a serialized socket
|
|
366
|
-
const socketIn = this._createNewSocketConnection(socketInName);
|
|
367
674
|
const block = (valueMapping && valueMapping.toBlock && flowGraphBlocks.blocks.find((b) => b.className === valueMapping.toBlock)) || flowGraphBlocks.blocks[0];
|
|
368
|
-
block.dataInputs.
|
|
675
|
+
const socketIn = block.dataInputs.find((socket) => socket.name === socketInName) ?? this._createNewSocketConnection(socketInName);
|
|
676
|
+
if (!block.dataInputs.includes(socketIn)) {
|
|
677
|
+
block.dataInputs.push(socketIn);
|
|
678
|
+
}
|
|
679
|
+
this._setSocketProvenance(socketIn, i, gltfNode.declaration, flowGraphBlocks.fullOperationName, this._getBlockRole(flowGraphBlocks.blocks, block), "value", "input", valueKey);
|
|
680
|
+
const socketProvenance = socketIn.metadata.khrInteractivity;
|
|
681
|
+
socketProvenance.sourceValue = _CloneMetadataValue(this._canonicalGraph.nodes?.[i]?.values?.[valueKey] ?? value);
|
|
369
682
|
// Captured before the connected branch below shadows `valueMapping`. When set and the
|
|
370
683
|
// value is supplied by a connection, the seconds→frames `dataTransformer` cannot run
|
|
371
684
|
// (it is parse-time only), so the raw connected value is scaled by a runtime multiply.
|
|
@@ -373,6 +686,8 @@ export class InteractivityGraphToFlowGraphParser {
|
|
|
373
686
|
if (value.value !== undefined) {
|
|
374
687
|
const convertedValue = this._parseVariable(value, valueMapping && valueMapping.dataTransformer);
|
|
375
688
|
context._connectionValues[socketIn.uniqueId] = convertedValue;
|
|
689
|
+
socketIn.defaultValue = convertedValue;
|
|
690
|
+
socketProvenance.runtimeValue = _CloneMetadataValue(convertedValue.value);
|
|
376
691
|
}
|
|
377
692
|
else if (typeof value.node !== "undefined") {
|
|
378
693
|
const nodeOutId = value.node;
|
|
@@ -390,22 +705,34 @@ export class InteractivityGraphToFlowGraphParser {
|
|
|
390
705
|
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
706
|
continue;
|
|
392
707
|
}
|
|
393
|
-
const outputMapper =
|
|
708
|
+
const outputMapper = this._mappings[this._interactivityGraph.nodes[nodeOutId].declaration]?.flowGraphMapping;
|
|
394
709
|
if (!outputMapper) {
|
|
395
710
|
Logger.Error(["No mapping found for output socket reference", value]);
|
|
396
711
|
throw new Error("Error parsing node connections");
|
|
397
712
|
}
|
|
398
|
-
let valueMapping = outputMapper.outputs?.values
|
|
713
|
+
let valueMapping = _GetOwnMapping(outputMapper.outputs?.values, nodeOutSocketName);
|
|
714
|
+
if (this._strictValidation && valueMapping?.compatibilityOnly) {
|
|
715
|
+
valueMapping = undefined;
|
|
716
|
+
}
|
|
399
717
|
let arrayMapping = false;
|
|
400
718
|
// check if there is an array mapping defined
|
|
401
719
|
if (!valueMapping) {
|
|
402
720
|
// search for a value mapping that has an array mapping
|
|
403
721
|
for (const key in outputMapper.outputs?.values) {
|
|
404
722
|
if (key.startsWith("[") && key.endsWith("]")) {
|
|
405
|
-
|
|
406
|
-
|
|
723
|
+
const wildcardMapping = outputMapper.outputs?.values?.[key];
|
|
724
|
+
if (!this._strictValidation || !wildcardMapping?.compatibilityOnly) {
|
|
725
|
+
arrayMapping = true;
|
|
726
|
+
valueMapping = wildcardMapping;
|
|
727
|
+
}
|
|
407
728
|
}
|
|
408
729
|
}
|
|
730
|
+
const allowedDynamicOutputs = arrayMapping
|
|
731
|
+
? this._getAllowedDynamicValueSockets(nodeOut.fullOperationName, this._interactivityGraph.nodes[nodeOutId], "output")
|
|
732
|
+
: undefined;
|
|
733
|
+
if (!valueMapping || (allowedDynamicOutputs && !allowedDynamicOutputs.has(nodeOutSocketName))) {
|
|
734
|
+
continue;
|
|
735
|
+
}
|
|
409
736
|
}
|
|
410
737
|
const socketOutName = valueMapping ? (arrayMapping ? valueMapping.name.replace("$1", nodeOutSocketName) : valueMapping?.name) : nodeOutSocketName;
|
|
411
738
|
const outBlock = (valueMapping && valueMapping.toBlock && nodeOut.blocks.find((b) => b.className === valueMapping.toBlock)) || nodeOut.blocks[0];
|
|
@@ -415,9 +742,10 @@ export class InteractivityGraphToFlowGraphParser {
|
|
|
415
742
|
socketOut = this._createNewSocketConnection(socketOutName, true);
|
|
416
743
|
outBlock.dataOutputs.push(socketOut);
|
|
417
744
|
}
|
|
745
|
+
this._setSocketProvenance(socketOut, nodeOutId, this._interactivityGraph.nodes[nodeOutId].declaration, nodeOut.fullOperationName, this._getBlockRole(nodeOut.blocks, outBlock), "value", "output", nodeOutSocketName);
|
|
418
746
|
// connect the sockets
|
|
419
747
|
if (convertConnectedTimeToFrames) {
|
|
420
|
-
this._connectWithSecondsToFramesConversion(context, socketOut, socketIn);
|
|
748
|
+
this._connectWithSecondsToFramesConversion(context, socketOut, socketIn, i, gltfNode.declaration, flowGraphBlocks.fullOperationName);
|
|
421
749
|
}
|
|
422
750
|
else {
|
|
423
751
|
socketIn.connectedPointIds.push(socketOut.uniqueId);
|
|
@@ -446,6 +774,93 @@ export class InteractivityGraphToFlowGraphParser {
|
|
|
446
774
|
}
|
|
447
775
|
flowGraphBlocks.blocks = outputMapper.flowGraphMapping.extraProcessor(gltfNode, declaration, outputMapper.flowGraphMapping, this, flowGraphBlocks.blocks, context, this._gltf);
|
|
448
776
|
}
|
|
777
|
+
this._ensureMappedSocketProvenance(i, gltfNode, flowGraphBlocks.blocks, outputMapper);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
_ensureMappedSocketProvenance(nodeIndex, node, blocks, mapping) {
|
|
781
|
+
const ensureConnections = (socketMappings, kind, direction) => {
|
|
782
|
+
for (const [sourceName, property] of Object.entries(socketMappings ?? {})) {
|
|
783
|
+
if ((sourceName.startsWith("[") && sourceName.endsWith("]")) || (this._strictValidation && property.compatibilityOnly)) {
|
|
784
|
+
continue;
|
|
785
|
+
}
|
|
786
|
+
const block = (property.toBlock && blocks.find((candidate) => candidate.className === property.toBlock)) || blocks[0];
|
|
787
|
+
if (!block) {
|
|
788
|
+
continue;
|
|
789
|
+
}
|
|
790
|
+
const connections = kind === "value" ? (direction === "input" ? block.dataInputs : block.dataOutputs) : direction === "input" ? block.signalInputs : block.signalOutputs;
|
|
791
|
+
let connection = connections.find((candidate) => candidate.name === property.name);
|
|
792
|
+
if (!connection) {
|
|
793
|
+
connection = this._createNewSocketConnection(property.name, direction === "output");
|
|
794
|
+
connections.push(connection);
|
|
795
|
+
}
|
|
796
|
+
this._setSocketProvenance(connection, nodeIndex, node.declaration, mapping.fullOperationName, this._getBlockRole(blocks, block), kind, direction, sourceName);
|
|
797
|
+
}
|
|
798
|
+
};
|
|
799
|
+
ensureConnections(mapping.flowGraphMapping.outputs?.values, "value", "output");
|
|
800
|
+
ensureConnections(mapping.flowGraphMapping.inputs?.flows, "flow", "input");
|
|
801
|
+
ensureConnections(mapping.flowGraphMapping.outputs?.flows, "flow", "output");
|
|
802
|
+
if (HasDefaultInteractivityFlowInput(mapping.fullOperationName)) {
|
|
803
|
+
const block = blocks[0];
|
|
804
|
+
if (block) {
|
|
805
|
+
let connection = block.signalInputs.find((candidate) => candidate.name === "in");
|
|
806
|
+
if (!connection) {
|
|
807
|
+
connection = this._createNewSocketConnection("in");
|
|
808
|
+
block.signalInputs.push(connection);
|
|
809
|
+
}
|
|
810
|
+
this._setSocketProvenance(connection, nodeIndex, node.declaration, mapping.fullOperationName, this._getBlockRole(blocks, block), "flow", "input", "in");
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
for (const [sourceKey, property] of Object.entries(mapping.flowGraphMapping.configuration ?? {})) {
|
|
814
|
+
const block = (property.toBlock && blocks.find((candidate) => candidate.className === property.toBlock)) || blocks[0];
|
|
815
|
+
const provenance = block?.metadata?.khrInteractivity;
|
|
816
|
+
if (!block || !provenance) {
|
|
817
|
+
continue;
|
|
818
|
+
}
|
|
819
|
+
const serializedRuntimeValue = block.config?.[property.name];
|
|
820
|
+
const runtimeValue = serializedRuntimeValue !== null && typeof serializedRuntimeValue === "object" && Object.prototype.hasOwnProperty.call(serializedRuntimeValue, "value")
|
|
821
|
+
? serializedRuntimeValue.value
|
|
822
|
+
: serializedRuntimeValue;
|
|
823
|
+
provenance.configuration || (provenance.configuration = {});
|
|
824
|
+
const configurationProvenance = {
|
|
825
|
+
sourceValue: _CloneMetadataValue(this._canonicalGraph.nodes?.[nodeIndex]?.configuration?.[sourceKey]?.value),
|
|
826
|
+
runtimeValue: _CloneMetadataValue(runtimeValue),
|
|
827
|
+
};
|
|
828
|
+
Object.defineProperty(provenance.configuration, sourceKey, {
|
|
829
|
+
configurable: true,
|
|
830
|
+
enumerable: true,
|
|
831
|
+
value: configurationProvenance,
|
|
832
|
+
writable: true,
|
|
833
|
+
});
|
|
834
|
+
}
|
|
835
|
+
for (const block of blocks) {
|
|
836
|
+
const provenance = block.metadata?.khrInteractivity;
|
|
837
|
+
if (!provenance) {
|
|
838
|
+
continue;
|
|
839
|
+
}
|
|
840
|
+
const mappedConfigurationNames = new Set(Object.values(mapping.flowGraphMapping.configuration ?? {})
|
|
841
|
+
.filter((property) => (property.toBlock ? block.className === property.toBlock : provenance.role === 0))
|
|
842
|
+
.map((property) => property.name));
|
|
843
|
+
const ignoredConfigurationNames = new Set(["glTF"]);
|
|
844
|
+
for (const [key, value] of Object.entries(block.config ?? {})) {
|
|
845
|
+
if (mappedConfigurationNames.has(key) || ignoredConfigurationNames.has(key)) {
|
|
846
|
+
continue;
|
|
847
|
+
}
|
|
848
|
+
const normalizedValue = key === "eventData"
|
|
849
|
+
? NormalizeInteractivityEventDataConfiguration(value)
|
|
850
|
+
: value !== null && typeof value === "object" && Object.prototype.hasOwnProperty.call(value, "value")
|
|
851
|
+
? value.value
|
|
852
|
+
: value;
|
|
853
|
+
if (!_IsSerializableConfigurationValue(normalizedValue)) {
|
|
854
|
+
continue;
|
|
855
|
+
}
|
|
856
|
+
provenance.generatedConfiguration || (provenance.generatedConfiguration = {});
|
|
857
|
+
Object.defineProperty(provenance.generatedConfiguration, key, {
|
|
858
|
+
configurable: true,
|
|
859
|
+
enumerable: true,
|
|
860
|
+
value: _CloneMetadataValue(normalizedValue),
|
|
861
|
+
writable: true,
|
|
862
|
+
});
|
|
863
|
+
}
|
|
449
864
|
}
|
|
450
865
|
}
|
|
451
866
|
_createNewSocketConnection(name, isOutput) {
|
|
@@ -456,6 +871,9 @@ export class InteractivityGraphToFlowGraphParser {
|
|
|
456
871
|
connectedPointIds: [],
|
|
457
872
|
};
|
|
458
873
|
}
|
|
874
|
+
_isUnsupportedExtensionBlock(block) {
|
|
875
|
+
return block?.className === "KHR_interactivity/FlowGraphUnsupportedInteractivityBlock";
|
|
876
|
+
}
|
|
459
877
|
/**
|
|
460
878
|
* Wires an upstream data output into a downstream data input through a runtime multiply block that
|
|
461
879
|
* scales the value by the animation target fps. This converts a KHR animation time (seconds),
|
|
@@ -465,9 +883,12 @@ export class InteractivityGraphToFlowGraphParser {
|
|
|
465
883
|
* @param context the serialized flow graph context that stores literal socket values
|
|
466
884
|
* @param upstreamOutput the data output socket providing the time value (in seconds)
|
|
467
885
|
* @param downstreamInput the data input socket that expects the time in frames
|
|
886
|
+
* @param nodeIndex source node receiving the converted value
|
|
887
|
+
* @param declarationIndex source declaration used by the receiving node
|
|
888
|
+
* @param operation owning KHR operation
|
|
468
889
|
*/
|
|
469
|
-
_connectWithSecondsToFramesConversion(context, upstreamOutput, downstreamInput) {
|
|
470
|
-
const multiplyBlock = this._getEmptyBlock("FlowGraphMultiplyBlock" /* FlowGraphBlockNames.Multiply */,
|
|
890
|
+
_connectWithSecondsToFramesConversion(context, upstreamOutput, downstreamInput, nodeIndex, declarationIndex, operation) {
|
|
891
|
+
const multiplyBlock = this._getEmptyBlock("FlowGraphMultiplyBlock" /* FlowGraphBlockNames.Multiply */, operation, nodeIndex, declarationIndex, -1);
|
|
471
892
|
// Scalar (float) multiply; matches how the `math/mul` mapping configures the block.
|
|
472
893
|
multiplyBlock.config = { type: "number" /* FlowGraphTypes.Number */ };
|
|
473
894
|
const inputA = this._createNewSocketConnection("a");
|
|
@@ -476,7 +897,9 @@ export class InteractivityGraphToFlowGraphParser {
|
|
|
476
897
|
multiplyBlock.dataInputs.push(inputA, inputB);
|
|
477
898
|
multiplyBlock.dataOutputs.push(output);
|
|
478
899
|
// The second factor is the constant animation target fps.
|
|
479
|
-
|
|
900
|
+
const frameRateValue = { type: "number" /* FlowGraphTypes.Number */, value: [this._animationTargetFps] };
|
|
901
|
+
context._connectionValues[inputB.uniqueId] = frameRateValue;
|
|
902
|
+
inputB.defaultValue = frameRateValue;
|
|
480
903
|
// upstream time output -> multiply.a
|
|
481
904
|
inputA.connectedPointIds.push(upstreamOutput.uniqueId);
|
|
482
905
|
upstreamOutput.connectedPointIds.push(inputA.uniqueId);
|
|
@@ -531,6 +954,14 @@ export class InteractivityGraphToFlowGraphParser {
|
|
|
531
954
|
}
|
|
532
955
|
const allBlocks = this._nodes.reduce((acc, val) => acc.concat(val.blocks), []).concat(this._insertedBlocks);
|
|
533
956
|
return {
|
|
957
|
+
name: this._interactivityGraph.name ?? `Graph ${this._graphIndex + 1}`,
|
|
958
|
+
metadata: {
|
|
959
|
+
khrInteractivity: {
|
|
960
|
+
graphIndex: this._graphIndex,
|
|
961
|
+
specificationCommit: KHR_INTERACTIVITY_SPECIFICATION_COMMIT,
|
|
962
|
+
source: CloneKHRInteractivityGraph(this._canonicalGraph),
|
|
963
|
+
},
|
|
964
|
+
},
|
|
534
965
|
rightHanded: true,
|
|
535
966
|
allBlocks,
|
|
536
967
|
executionContexts: [context],
|