@shaderfrog/core 2.0.0-beta.3 → 3.0.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.
Files changed (49) hide show
  1. package/README.md +2 -2
  2. package/engine.d.ts +39 -3
  3. package/engine.js +5 -0
  4. package/graph/code-nodes.d.ts +8 -2
  5. package/graph/code-nodes.js +5 -1
  6. package/graph/context.d.ts +8 -6
  7. package/graph/context.js +53 -50
  8. package/graph/data-nodes.d.ts +15 -6
  9. package/graph/data-nodes.js +1 -1
  10. package/graph/evaluate.js +7 -0
  11. package/graph/graph-types.d.ts +26 -6
  12. package/graph/graph-types.js +69 -0
  13. package/graph/graph.d.ts +35 -4
  14. package/graph/graph.js +187 -143
  15. package/graph/graph.test.js +244 -54
  16. package/graph/parsers.d.ts +4 -12
  17. package/graph/parsers.js +32 -18
  18. package/graph/shader-sections.d.ts +31 -14
  19. package/graph/shader-sections.js +93 -19
  20. package/package.json +4 -4
  21. package/plugins/babylon/bablyengine.js +9 -10
  22. package/plugins/playcanvas/playengine.js +9 -10
  23. package/plugins/three/importers.d.ts +1 -0
  24. package/plugins/three/importers.js +49 -1
  25. package/plugins/three/threngine.d.ts +6 -4
  26. package/plugins/three/threngine.js +59 -39
  27. package/plugins/three/threngine.test.js +51 -4
  28. package/strategy/assignmentTo.d.ts +10 -0
  29. package/strategy/assignmentTo.js +35 -0
  30. package/strategy/declarationOf.js +2 -2
  31. package/strategy/hardCode.js +1 -4
  32. package/strategy/index.d.ts +1 -1
  33. package/strategy/index.js +1 -1
  34. package/strategy/inject.js +3 -4
  35. package/strategy/namedAttribute.js +2 -2
  36. package/strategy/strategy.d.ts +30 -5
  37. package/strategy/strategy.js +1 -1
  38. package/strategy/stratgies.test.js +59 -31
  39. package/strategy/texture2D.js +20 -22
  40. package/strategy/uniform.js +54 -56
  41. package/strategy/variable.js +5 -5
  42. package/util/ast.d.ts +9 -4
  43. package/util/ast.js +37 -8
  44. package/util/ast.test.d.ts +1 -0
  45. package/util/ast.test.js +14 -0
  46. package/util/indexByid.d.ts +4 -0
  47. package/util/indexByid.js +18 -0
  48. package/util/whitespace.d.ts +2 -0
  49. package/util/whitespace.js +22 -3
package/graph/graph.js CHANGED
@@ -72,13 +72,13 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
72
72
  };
73
73
  import { renameBindings, renameFunctions, } from '@shaderfrog/glsl-parser/parser/utils';
74
74
  import { computeGraphContext, isError, } from './context';
75
- import { emptyShaderSections, findShaderSections, mergeShaderSections, shaderSectionsToProgram, } from './shader-sections';
76
- import { makeExpression } from '../util/ast';
75
+ import { shaderSectionsCons, findShaderSections, mergeShaderSections, shaderSectionsToProgram, } from './shader-sections';
76
+ import { backfillAst, makeExpression } from '../util/ast';
77
77
  import { ensure } from '../util/ensure';
78
78
  import { SourceType } from './code-nodes';
79
79
  import { nodeInput } from './base-node';
80
80
  import { makeId } from '../util/id';
81
- import { coreParsers } from './parsers';
81
+ import { alphabet, coreParsers } from './parsers';
82
82
  import { toGlsl } from './evaluate';
83
83
  import { EdgeLink, MAGIC_OUTPUT_STMTS, NodeType, } from './graph-types';
84
84
  import { generate } from '@shaderfrog/glsl-parser';
@@ -96,6 +96,21 @@ export var isDataNode = function (node) {
96
96
  export var isSourceNode = function (node) {
97
97
  return !isDataNode(node);
98
98
  };
99
+ /**
100
+ * Determine if a node's source code / AST should have a main function. Essentially
101
+ * check if the source code is a full program or not.
102
+ */
103
+ export var shouldNodeHaveMainFn = function (node) {
104
+ // Some legacy shaders have an output node that does not have a sourceType,
105
+ // otherwise the sourceType second check would always work
106
+ return node.type === NodeType.OUTPUT ||
107
+ // Same for code nodes :(
108
+ (isSourceNode(node) && !node.sourceType) ||
109
+ node.sourceType === SourceType.SHADER_PROGRAM ||
110
+ // Engine nodes can have rando types like "physical", so if they are engine
111
+ // nodes, assume they have a main fn.
112
+ node.engine;
113
+ };
99
114
  export var findNode = function (graph, id) {
100
115
  return ensure(graph.nodes.find(function (node) { return node.id === id; }));
101
116
  };
@@ -120,6 +135,7 @@ export var doesLinkThruShader = function (graph, node) {
120
135
  export var nodeName = function (node) {
121
136
  return 'main_' + node.name.replace(/[^a-zA-Z0-9]/g, ' ').replace(/ +/g, '_');
122
137
  };
138
+ export var resultName = function (node) { return nodeName(node) + '_out'; };
123
139
  export var mangleName = function (name, node, nextSibling) {
124
140
  // Mangle a name to its next stage node, so the vertex suffix becomes the
125
141
  // fragment id, but not the other way around.
@@ -157,9 +173,59 @@ export var resetGraphIds = function (graph) {
157
173
  edges: graph.edges.map(function (e) { return (__assign(__assign({}, e), { id: map(e.id), from: map(e.from), to: map(e.to) })); }),
158
174
  };
159
175
  };
160
- export var findLinkedNode = function (graph, id) {
161
- var edgeLink = graph.edges.find(function (e) { return e.type === EdgeLink.NEXT_STAGE && (e.from === id || e.to === id); });
162
- var otherId = (edgeLink === null || edgeLink === void 0 ? void 0 : edgeLink.from) === id ? edgeLink === null || edgeLink === void 0 ? void 0 : edgeLink.to : edgeLink === null || edgeLink === void 0 ? void 0 : edgeLink.from;
176
+ /**
177
+ * A binary node automatically adds/removes inputs based on how many edges
178
+ * connect to it. If a binary node has edges to "a" and "b", removing the edge
179
+ * to "a" means the edge to "b" needs to be moved down to the "a" one. This
180
+ * function essentially groups edges by target node id, and resets the edge
181
+ * target to its index. This doesn't feel good to do here but I don't have a
182
+ * better idea at the moment. One reason the inputs to binary nodes are
183
+ * automatically updated after compile, but the edges are updated here
184
+ * at the editor layer, before compile. This also hard codes assumptions about
185
+ * (binary) node inputs into the graph, namely they can't have blank inputs.
186
+ */
187
+ export var collapseBinaryGraphEdges = function (graph) {
188
+ // Find all edges that flow into a binary node, grouped by the target node's
189
+ // id, since we need to know the total number of edges per node first
190
+ var binaryEdges = graph.edges.reduce(function (acc, edge) {
191
+ var _a;
192
+ var toNode = findNode(graph, edge.to);
193
+ return toNode.type === NodeType.BINARY
194
+ ? __assign(__assign({}, acc), (_a = {}, _a[toNode.id] = __spreadArray(__spreadArray([], __read((acc[toNode.id] || [])), false), [edge], false), _a)) : acc;
195
+ }, {});
196
+ // Then collapse them
197
+ var updatedEdges = graph.edges.map(function (edge) {
198
+ return edge.to in binaryEdges
199
+ ? __assign(__assign({}, edge), { input: alphabet.charAt(binaryEdges[edge.to].indexOf(edge)) }) : edge;
200
+ });
201
+ return __assign(__assign({}, graph), { edges: updatedEdges });
202
+ };
203
+ /**
204
+ * Restrict edges so that an input handle can't have multiple edges going to it
205
+ */
206
+ export var addEdgeAndPruneRestrictions = function (edges, newEdge) {
207
+ return edges
208
+ .filter(function (edge) {
209
+ // Prevent one input handle from having multiple inputs
210
+ return !(edge.to === newEdge.to && edge.input === newEdge.input);
211
+ })
212
+ .concat(newEdge);
213
+ };
214
+ /**
215
+ * Adds an edge to the graph and enforces graph edge business logic rules:
216
+ * - Makes sure "binary" (add/multiply) nodes edges are collapsed
217
+ * - Makes sure two edges can't flow into the same input.
218
+ * See also editor/flow-helpers.ts
219
+ */
220
+ export var addGraphEdge = function (graph, newEdge) {
221
+ return collapseBinaryGraphEdges(__assign(__assign({}, graph), { edges: addEdgeAndPruneRestrictions(graph.edges, newEdge) }));
222
+ };
223
+ export var findLinkedNode = function (graph, nodeId) {
224
+ var edgeLink = graph.edges.find(function (e) {
225
+ return e.type === EdgeLink.NEXT_STAGE && (e.from === nodeId || e.to === nodeId);
226
+ });
227
+ var otherId = (edgeLink === null || edgeLink === void 0 ? void 0 : edgeLink.from) === nodeId ? edgeLink === null || edgeLink === void 0 ? void 0 : edgeLink.to : edgeLink === null || edgeLink === void 0 ? void 0 : edgeLink.from;
228
+ // Only source nodes can be linked, so cast it
163
229
  return graph.nodes.find(function (node) { return node.id === otherId; });
164
230
  };
165
231
  /**
@@ -187,12 +253,12 @@ export var findLinkedVertexNodes = function (graph, existingIds) {
187
253
  export var consSearchResult = function () { return ({
188
254
  nodes: {},
189
255
  inputs: {},
190
- edges: [],
256
+ edges: {},
191
257
  }); };
192
258
  export var mergeSearchResults = function (a, b) { return ({
193
259
  nodes: __assign(__assign({}, a.nodes), b.nodes),
194
260
  inputs: __assign(__assign({}, a.inputs), b.inputs),
195
- edges: __spreadArray(__spreadArray([], __read(a.edges), false), __read(b.edges), false),
261
+ edges: __assign(__assign({}, a.edges), b.edges),
196
262
  }); };
197
263
  /**
198
264
  * Create the inputs on a node from the properties. This used to be done at
@@ -220,23 +286,24 @@ export var filterGraphFromNode = function (graph, node, predicates, depth, lastR
220
286
  ? (_a = {}, _a[node.id] = node, _a) : {}));
221
287
  var accumulatedResult = __assign(__assign({}, lastResult), { nodes: __assign(__assign({}, lastResult.nodes), nodeAcc) });
222
288
  return inputEdges.reduce(function (acc, inputEdge) {
223
- var _a;
289
+ var _a, _b;
224
290
  var input = inputs.find(function (i) { return i.id === inputEdge.input; });
225
291
  var fromNode = inputEdge ? ensureFromNode(graph, inputEdge) : undefined;
226
292
  var inputAcc = __assign(__assign({}, acc.inputs), (input &&
227
293
  predicates.input &&
228
294
  predicates.input(input, node, inputEdge, fromNode, lastResult)
229
295
  ? (_a = {}, _a[node.id] = __spreadArray(__spreadArray([], __read((acc.inputs[node.id] || [])), false), [input], false), _a) : {}));
230
- var edgeAcc = __spreadArray(__spreadArray([], __read(acc.edges), false), __read((predicates.edge &&
296
+ var edgeAcc = __assign(__assign({}, acc.edges), (predicates.edge &&
231
297
  predicates.edge(input, node, inputEdge, fromNode, lastResult)
232
- ? [inputEdge]
233
- : [])), false);
298
+ ? (_b = {}, _b[inputEdge.id] = inputEdge, _b) : {}));
234
299
  // Add in the latest result of edges and inputs so that when we recurse into
235
300
  // the next node, it has the latest accumulator
236
301
  var intermediateAcc = __assign(__assign({}, acc), { inputs: inputAcc, edges: edgeAcc });
237
302
  if (inputEdge && fromNode && depth > 1) {
238
303
  var result = filterGraphFromNode(graph, fromNode, predicates, depth - 1, intermediateAcc);
239
- return mergeSearchResults(intermediateAcc, result);
304
+ // The result is automatically the combination of the currenet acc and the
305
+ // result of the recursed data
306
+ return result;
240
307
  }
241
308
  else {
242
309
  return intermediateAcc;
@@ -246,13 +313,20 @@ export var filterGraphFromNode = function (graph, node, predicates, depth, lastR
246
313
  export var collectConnectedNodes = function (graph, node) {
247
314
  return filterGraphFromNode(graph, node, { node: function () { return true; } }).nodes;
248
315
  };
316
+ var merge = function (a, b) {
317
+ var keys = new Set(__spreadArray(__spreadArray([], __read(Object.keys(a)), false), __read(Object.keys(b)), false));
318
+ return Array.from(keys).reduce(function (acc, key) {
319
+ var _a;
320
+ return (__assign(__assign({}, acc), (_a = {}, _a[key] = __spreadArray(__spreadArray([], __read((a[key] || [])), false), __read((b[key] || [])), false), _a)));
321
+ }, {});
322
+ };
249
323
  export var filterGraphNodes = function (graph, nodes, filter, depth) {
250
324
  if (depth === void 0) { depth = Infinity; }
251
325
  return nodes.reduce(function (acc, node) {
252
326
  var result = filterGraphFromNode(graph, node, filter, depth);
253
327
  return {
254
328
  nodes: __assign(__assign({}, acc.nodes), result.nodes),
255
- inputs: __assign(__assign({}, acc.inputs), result.inputs),
329
+ inputs: merge(acc.inputs, result.inputs),
256
330
  edges: __assign(__assign({}, acc.edges), result.edges),
257
331
  };
258
332
  }, consSearchResult());
@@ -264,10 +338,11 @@ export var isDataInput = function (input) {
264
338
  return (input.type === 'uniform' || input.type === 'property') && !input.baked;
265
339
  };
266
340
  export var compileNode = function (engine, graph, edges, engineContext, node, activeIds) {
267
- var _a, _b;
341
+ var _a;
268
342
  if (activeIds === void 0) { activeIds = {}; }
269
343
  // THIS DUPLICATES OTHER LINE
270
344
  var parser = __assign(__assign({}, (coreParsers[node.type] || coreParsers[NodeType.SOURCE])), (engine.parsers[node.type] || {}));
345
+ var codeNode = node;
271
346
  var inputs = node.inputs;
272
347
  if (!parser) {
273
348
  console.error(node);
@@ -276,135 +351,101 @@ export var compileNode = function (engine, graph, edges, engineContext, node, ac
276
351
  var nodeContext = isDataNode(node)
277
352
  ? null
278
353
  : ensure(engineContext.nodes[node.id], "No node context found for \"".concat(node.name, "\" (id ").concat(node.id, ")!"));
279
- var _c = (nodeContext || {}), ast = _c.ast, inputFillers = _c.inputFillers;
280
- if (!inputs) {
281
- throw new Error("I'm drunk and I think this case should be impossible");
354
+ var _b = nodeContext || {}, ast = _b.ast, inputFillers = _b.inputFillers;
355
+ if (!ast || !inputFillers) {
356
+ throw new Error("I'm drunk while writing this code, and I think this case should be impossible, so I'm going to throw an error and ignore it");
282
357
  }
283
358
  var compiledIds = activeIds;
284
359
  var inputEdges = edges.filter(function (edge) { return edge.to === node.id; });
285
- if (inputEdges.length) {
286
- var continuation_1 = emptyShaderSections();
287
- inputEdges
288
- .filter(function (edge) { return edge.type !== EdgeLink.NEXT_STAGE; })
289
- .map(function (edge) { return ({
290
- edge: edge,
291
- fromNode: ensure(graph.nodes.find(function (node) { return edge.from === node.id; }), "GraphNode for edge ".concat(edge.from, " not found")),
292
- input: ensure(inputs.find(function (_a) {
293
- var id = _a.id;
294
- return id == edge.input;
295
- }), "GraphNode \"".concat(node.name, "\"").concat(node.stage ? " (".concat(node.stage, ")") : '', " has no input ").concat(edge.input, "!\nAvailable:").concat(inputs
296
- .map(function (_a) {
297
- var id = _a.id;
298
- return id;
299
- })
300
- .join(', '))),
301
- }); })
302
- .filter(function (_a) {
303
- var input = _a.input;
304
- return !isDataInput(input);
360
+ var continuation = shaderSectionsCons();
361
+ // Compile children recursively
362
+ inputEdges
363
+ .filter(function (edge) { return edge.type !== EdgeLink.NEXT_STAGE; })
364
+ .map(function (edge) { return ({
365
+ edge: edge,
366
+ fromNode: ensure(graph.nodes.find(function (node) { return edge.from === node.id; }), "GraphNode for edge ".concat(edge.from, " not found")),
367
+ input: ensure(inputs.find(function (_a) {
368
+ var id = _a.id;
369
+ return id == edge.input;
370
+ }), "GraphNode \"".concat(node.name, "\"").concat(node.stage ? " (".concat(node.stage, ")") : '', " has no input ").concat(edge.input, "!\nAvailable:").concat(inputs
371
+ .map(function (_a) {
372
+ var id = _a.id;
373
+ return id;
305
374
  })
306
- .forEach(function (_a) {
307
- var _b;
308
- var fromNode = _a.fromNode, edge = _a.edge, input = _a.input;
309
- var _c = __read(compileNode(engine, graph, edges, engineContext, fromNode, activeIds), 3), inputSections = _c[0], fillerAst = _c[1], childIds = _c[2];
310
- if (!fillerAst) {
311
- throw new TypeError("Expected a filler ast from node ID ".concat(fromNode.id, " (").concat(fromNode.type, ") but none was returned"));
312
- }
313
- continuation_1 = mergeShaderSections(continuation_1, inputSections);
314
- compiledIds = __assign(__assign({}, compiledIds), childIds);
315
- var filler;
316
- var fillerName;
317
- if (nodeContext) {
318
- if (input.property) {
319
- fillerName = ensure((_b = (node.config.properties || []).find(function (p) { return p.property === input.property; })) === null || _b === void 0 ? void 0 : _b.fillerName, "Node \"".concat(node.name, "\" has no property named \"").concat(input.property, "\" to find the filler for"));
320
- filler = inputFillers[fillerName];
321
- }
322
- else {
323
- filler = inputFillers[input.id];
324
- }
325
- if (!filler) {
326
- console.error('No filler for property', {
327
- input: input,
328
- node: node,
329
- inputFillers: inputFillers,
330
- fillerName: fillerName,
331
- });
332
- throw new Error("Node \"".concat(node.name, "\"").concat(node.stage
333
- ? " (".concat(node.stage, ")")
334
- : '', " has no filler for input \"").concat(input.displayName, "\" named ").concat(fillerName));
335
- }
336
- /**
337
- * +------+ +------+
338
- * a -- o add o -- o tex |
339
- * b -- o | +------+
340
- * +------+
341
- *
342
- * This could produce:
343
- * main_a(v1) + main_b(v2)
344
- * I guess it has to? or it could produce
345
- * function add(v1) { return main_a(v1) + main_b(v2); }
346
- * It can't replace the arg _expression_ in the from shaders, because
347
- * the expression isn't available there.
348
- */
349
- // TODO: This is a hard coded hack for vUv backfilling. It works in
350
- // the simple case. Doesn't work for hell (based on world position).
351
- if (filler.backfillArgs &&
352
- !Array.isArray(fillerAst) &&
353
- fillerAst.type === 'function_call') {
354
- // Object.values(filterGraphFromNode(graph, node, {
355
- // node: (n) => n.type === 'source'
356
- // }).nodes).forEach(sourceNode => {
357
- if (fromNode.type === 'source') {
358
- // @ts-ignore
359
- fillerAst.args = filler.backfillArgs;
360
- // const fc = engineContext.nodes[sourceNode.id];
361
- var fc = engineContext.nodes[fromNode.id];
362
- var main = Object.values(fc.ast.scopes[0].functions.main)[0].declaration;
363
- main.prototype.parameters = [
364
- 'vec2 vv',
365
- ];
366
- // @ts-ignore
367
- var scope = fc.ast.scopes[0];
368
- // renameBindings(scope, (name, node) => {
369
- // return node.type !== 'declaration' && name === 'vUv'
370
- // ? 'vv'
371
- // : name;
372
- // });
373
- }
374
- // })
375
- }
376
- // Fill in the input! The return value is the new AST of the filled in
377
- // fromNode.
378
- nodeContext.ast = filler.filler(fillerAst);
375
+ .join(', '))),
376
+ }); })
377
+ .filter(function (_a) {
378
+ var input = _a.input;
379
+ return !isDataInput(input);
380
+ })
381
+ .forEach(function (_a) {
382
+ var _b, _c;
383
+ var fromNode = _a.fromNode, input = _a.input;
384
+ var _d = __read(compileNode(engine, graph, edges, engineContext, fromNode, activeIds), 3), inputSections = _d[0], fillerFn = _d[1], childIds = _d[2];
385
+ if (!fillerFn) {
386
+ throw new TypeError("Expected a filler ast from node ID ".concat(fromNode.id, " (").concat(fromNode.type, ") but none was returned"));
387
+ }
388
+ continuation = mergeShaderSections(continuation, inputSections);
389
+ compiledIds = __assign(__assign({}, compiledIds), childIds);
390
+ // Continue on if there's no context I don't know what case causes this
391
+ if (!nodeContext) {
392
+ return;
393
+ }
394
+ // Produce the input filler
395
+ var filler;
396
+ var fillerName;
397
+ if (input.property) {
398
+ fillerName = ensure((_b = (codeNode.config.properties || []).find(function (p) { return p.property === input.property; })) === null || _b === void 0 ? void 0 : _b.fillerName, "Node \"".concat(node.name, "\" has no property named \"").concat(input.property, "\" to find the filler for"));
399
+ filler = inputFillers[fillerName];
400
+ }
401
+ else {
402
+ filler = inputFillers[input.id];
403
+ }
404
+ if (!filler) {
405
+ console.error('No filler for property', {
406
+ input: input,
407
+ node: node,
408
+ inputFillers: inputFillers,
409
+ fillerName: fillerName,
410
+ });
411
+ return;
412
+ // throw new Error(
413
+ // `Node "${node.name}"${
414
+ // (node as SourceNode).stage ? ` (${(node as SourceNode).stage})` : ''
415
+ // } has no filler for input "${input.displayName}" named ${fillerName}`,
416
+ // );
417
+ }
418
+ // Test if it needs to be backfilled - this only goes one level deep
419
+ // because we're only backfilling fromNode
420
+ var backfillers = (_c = codeNode.backfillers) === null || _c === void 0 ? void 0 : _c[input.id];
421
+ if (backfillers && shouldNodeHaveMainFn(fromNode)) {
422
+ var childAst_1 = engineContext.nodes[fromNode.id].ast;
423
+ // For now we can only backfill programs
424
+ if (childAst_1.type === 'program') {
425
+ backfillers.forEach(function (backfiller) {
426
+ // This is where the variable name gets injected into the main
427
+ // function parameter of the backfilled child
428
+ backfillAst(childAst_1, backfiller.argType, backfiller.targetVariable, engineContext.nodes[fromNode.id].mainFn);
429
+ });
379
430
  }
380
- // log(generate(ast.program));
381
- });
382
- // Order matters here! *Prepend* the input nodes to this one, because
383
- // you have to declare functions in order of use in GLSL
384
- var sections = mergeShaderSections(continuation_1, isDataNode(node) ||
385
- node.sourceType === SourceType.EXPRESSION ||
386
- node.sourceType === SourceType.FN_BODY_FRAGMENT
387
- ? emptyShaderSections()
388
- : findShaderSections(ast));
389
- var filler = isDataNode(node)
390
- ? makeExpression(toGlsl(node))
391
- : parser.produceFiller(node, ast);
392
- return [sections, filler, __assign(__assign({}, compiledIds), (_a = {}, _a[node.id] = node, _a))];
393
- }
394
- else {
395
- // TODO: This duplicates the above branch, and also does this mean we
396
- // recalculate the shader sections and filler for every edge? Can I move
397
- // these lines above the loop?
398
- var sections = isDataNode(node) ||
399
- node.sourceType === SourceType.EXPRESSION ||
400
- node.sourceType === SourceType.FN_BODY_FRAGMENT
401
- ? emptyShaderSections()
402
- : findShaderSections(ast);
403
- var filler = isDataNode(node)
404
- ? makeExpression(toGlsl(node))
405
- : parser.produceFiller(node, ast);
406
- return [sections, filler, __assign(__assign({}, compiledIds), (_b = {}, _b[node.id] = node, _b))];
407
- }
431
+ nodeContext.ast = filler.filler(fillerFn);
432
+ }
433
+ else {
434
+ // Don't backfill by discarding the backfiller args
435
+ nodeContext.ast = filler.filler(function () { return fillerFn(); });
436
+ }
437
+ });
438
+ // Order matters here! *Prepend* the input nodes to this one, because
439
+ // you have to declare functions in order of use in GLSL
440
+ var sections = mergeShaderSections(continuation, isDataNode(node) ||
441
+ codeNode.sourceType === SourceType.EXPRESSION ||
442
+ codeNode.sourceType === SourceType.FN_BODY_FRAGMENT
443
+ ? shaderSectionsCons()
444
+ : findShaderSections(node.id, ast));
445
+ var filler = isDataNode(node)
446
+ ? function () { return makeExpression(toGlsl(node)); }
447
+ : parser.produceFiller(node, ast);
448
+ return [sections, filler, __assign(__assign({}, compiledIds), (_a = {}, _a[node.id] = node, _a))];
408
449
  };
409
450
  export var compileGraph = function (engineContext, engine, graph) {
410
451
  // computeGraphContext(engineContext, engine, graph);
@@ -472,7 +513,7 @@ export var collectNodeProperties = function (graph) {
472
513
  };
473
514
  };
474
515
  export var compileSource = function (graph, engine, ctx) { return __awaiter(void 0, void 0, void 0, function () {
475
- var result, compileResult, fragmentResult, vertexResult, dataInputs, dataNodes;
516
+ var result, updatedNodeContext, updatedContext, compileResult, fragmentResult, vertexResult, dataInputs, dataNodes;
476
517
  return __generator(this, function (_a) {
477
518
  switch (_a.label) {
478
519
  case 0: return [4 /*yield*/, computeGraphContext(ctx, engine, graph)];
@@ -481,9 +522,10 @@ export var compileSource = function (graph, engine, ctx) { return __awaiter(void
481
522
  if (isError(result)) {
482
523
  return [2 /*return*/, result];
483
524
  }
484
- compileResult = compileGraph(ctx, engine, graph);
485
- fragmentResult = generate(shaderSectionsToProgram(compileResult.fragment, engine.mergeOptions)
486
- .program);
525
+ updatedNodeContext = __assign(__assign({}, ctx.nodes), result);
526
+ updatedContext = __assign(__assign({}, ctx), { nodes: updatedNodeContext });
527
+ compileResult = compileGraph(updatedContext, engine, graph);
528
+ fragmentResult = generate(shaderSectionsToProgram(compileResult.fragment, engine.mergeOptions).program);
487
529
  vertexResult = generate(shaderSectionsToProgram(compileResult.vertex, engine.mergeOptions).program);
488
530
  dataInputs = filterGraphNodes(graph, [compileResult.outputFrag, compileResult.outputVert], { input: isDataInput }).inputs;
489
531
  dataNodes = Object.entries(dataInputs).reduce(function (acc, _a) {
@@ -496,11 +538,13 @@ export var compileSource = function (graph, engine, ctx) { return __awaiter(void
496
538
  }, acc);
497
539
  }, {});
498
540
  return [2 /*return*/, {
541
+ updatedNodeContext: updatedNodeContext,
499
542
  compileResult: compileResult,
500
543
  fragmentResult: fragmentResult,
501
544
  vertexResult: vertexResult,
502
545
  dataNodes: dataNodes,
503
546
  dataInputs: dataInputs,
547
+ compileMs: '',
504
548
  }];
505
549
  }
506
550
  });