@shaderfrog/core 2.0.1 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/engine.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import { Program } from '@shaderfrog/glsl-parser/ast';
2
2
  import { MergeOptions } from './graph/shader-sections';
3
3
  import { Graph, ShaderStage } from './graph/graph-types';
4
- import { NodePosition } from './graph/base-node';
4
+ import { NodeInput, NodePosition } from './graph/base-node';
5
5
  import { DataNode, UniformDataType } from './graph/data-nodes';
6
6
  import { CodeNode, NodeProperty, SourceNode } from './graph/code-nodes';
7
- import { NodeContext } from './graph/context';
7
+ import { NodeContext, NodeContexts } from './graph/context';
8
8
  import { NodeParser } from './graph/parsers';
9
9
  export declare enum EngineNodeType {
10
10
  toon = "toon",
@@ -30,9 +30,44 @@ export interface Engine {
30
30
  [EngineNodeType.toon]?: ToonNodeConstructor;
31
31
  };
32
32
  }
33
- export type EngineContext = {
33
+ export type EngineContext<T = any> = {
34
34
  engine: string;
35
35
  nodes: Record<string, NodeContext>;
36
+ runtime: T;
37
+ debuggingNonsense: {
38
+ vertexSource?: string;
39
+ vertexPreprocessed?: string;
40
+ fragmentPreprocessed?: string;
41
+ fragmentSource?: string;
42
+ };
43
+ };
44
+ export declare const extendNodeContext: (context: EngineContext, nodeId: string, nodeContext: Partial<NodeContext>) => {
45
+ nodes: {
46
+ [x: string]: NodeContext | {
47
+ id?: string;
48
+ name?: string;
49
+ computedSource?: string;
50
+ ast: import("@shaderfrog/glsl-parser/ast").AstNode | Program;
51
+ inputs?: NodeInput[];
52
+ inputFillers: import("./strategy").InputFillers;
53
+ errors?: import("./graph/context").NodeErrors;
54
+ mainFn?: import("@shaderfrog/glsl-parser/ast").FunctionNode;
55
+ };
56
+ };
57
+ engine: string;
58
+ runtime: any;
59
+ debuggingNonsense: {
60
+ vertexSource?: string;
61
+ vertexPreprocessed?: string;
62
+ fragmentPreprocessed?: string;
63
+ fragmentSource?: string;
64
+ };
65
+ };
66
+ export declare const extendNodesContext: (context: EngineContext, nodesContext: NodeContexts) => {
67
+ nodes: {
68
+ [x: string]: NodeContext;
69
+ };
70
+ engine: string;
36
71
  runtime: any;
37
72
  debuggingNonsense: {
38
73
  vertexSource?: string;
@@ -42,7 +77,9 @@ export type EngineContext = {
42
77
  };
43
78
  };
44
79
  export type EngineImporter = {
45
- convertAst(ast: Program, type?: ShaderStage): void;
80
+ convertAst(ast: Program, options?: Record<string, unknown> & {
81
+ type?: ShaderStage;
82
+ }): void;
46
83
  nodeInputMap: Partial<Record<EngineNodeType, Record<string, string | null>>>;
47
84
  edgeMap: {
48
85
  [oldInput: string]: string;
package/engine.js CHANGED
@@ -56,6 +56,11 @@ export var EngineNodeType;
56
56
  EngineNodeType["shader"] = "shader";
57
57
  EngineNodeType["binary"] = "binary";
58
58
  })(EngineNodeType || (EngineNodeType = {}));
59
+ export var extendNodeContext = function (context, nodeId, nodeContext) {
60
+ var _a;
61
+ return (__assign(__assign({}, context), { nodes: __assign(__assign({}, context.nodes), (_a = {}, _a[nodeId] = __assign(__assign({}, (context.nodes[nodeId] || {})), nodeContext), _a)) }));
62
+ };
63
+ export var extendNodesContext = function (context, nodesContext) { return (__assign(__assign({}, context), { nodes: __assign(__assign({}, context.nodes), nodesContext) })); };
59
64
  // type EdgeUpdates = { [edgeId: string]: { oldInput: string; newInput: string } };
60
65
  export var convertNode = function (node, converter) {
61
66
  log("Converting ".concat(node.name, " (").concat(node.id, ")"));
@@ -66,8 +71,8 @@ export var convertNode = function (node, converter) {
66
71
  define: function () { return true; },
67
72
  },
68
73
  });
69
- var ast = parser.parse(preprocessed);
70
- converter.convertAst(ast, node.stage);
74
+ var ast = parser.parse(preprocessed, { stage: node.stage });
75
+ converter.convertAst(ast, { type: node.stage });
71
76
  var source = generate(ast);
72
77
  return __assign(__assign({}, node), { source: source });
73
78
  };
@@ -1,4 +1,4 @@
1
- import { type GlslSyntaxError } from '@shaderfrog/glsl-parser';
1
+ import { GlslSyntaxError } from '@shaderfrog/glsl-parser';
2
2
  import { AstNode, FunctionNode, Program } from '@shaderfrog/glsl-parser/ast';
3
3
  import { Engine, EngineContext } from '../engine';
4
4
  import { NodeInput } from './base-node';
@@ -12,27 +12,28 @@ import { InputFillers } from '../strategy';
12
12
  export type NodeContext = {
13
13
  id?: string;
14
14
  name?: string;
15
- source?: string;
15
+ computedSource?: string;
16
16
  ast: AstNode | Program;
17
17
  inputs?: NodeInput[];
18
18
  inputFillers: InputFillers;
19
19
  errors?: NodeErrors;
20
20
  mainFn?: FunctionNode;
21
21
  };
22
+ export type NodeContexts = Record<string, NodeContext>;
22
23
  export type NodeErrors = {
23
24
  type: 'errors';
24
25
  nodeId: string;
25
26
  errors: (GlslSyntaxError | string)[];
26
27
  };
27
28
  export declare const isError: (test: any) => test is NodeErrors;
28
- export declare const computeContextForNodes: (engineContext: EngineContext, engine: Engine, graph: Graph, nodes: GraphNode[]) => Promise<NodeErrors | Record<string, NodeContext>>;
29
+ export declare const computeContextForNodes: (engineContext: EngineContext, engine: Engine, graph: Graph, nodes: GraphNode[]) => Promise<NodeErrors | NodeContexts>;
29
30
  /**
30
31
  * Compute the context for every node in the graph, done on initial graph load
31
32
  * to compute the inputs/outputs for every node
32
33
  */
33
- export declare const computeAllContexts: (engineContext: EngineContext, engine: Engine, graph: Graph) => Promise<NodeErrors | undefined>;
34
+ export declare const computeAllContexts: (engineContext: EngineContext, engine: Engine, graph: Graph) => Promise<NodeErrors | NodeContexts>;
34
35
  /**
35
36
  * Compute the contexts for nodes starting from the outputs, working backwards.
36
37
  * Used to only (re)-compute context for any actively used nodes
37
38
  */
38
- export declare const computeGraphContext: (engineContext: EngineContext, engine: Engine, graph: Graph) => Promise<NodeErrors | undefined>;
39
+ export declare const computeGraphContext: (engineContext: EngineContext, engine: Engine, graph: Graph) => Promise<NodeErrors | NodeContexts>;
package/graph/context.js CHANGED
@@ -71,6 +71,7 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
71
71
  return to.concat(ar || Array.prototype.slice.call(from));
72
72
  };
73
73
  import groupBy from 'lodash.groupby';
74
+ import { extendNodeContext, extendNodesContext, } from '../engine';
74
75
  import { mapInputName, SourceType } from './code-nodes';
75
76
  import { NodeType } from './graph-types';
76
77
  import { collectConnectedNodes, filterGraphFromNode, findLinkedNode, findLinkedVertexNodes, isSourceNode, mangleEntireProgram, shouldNodeHaveMainFn, } from './graph';
@@ -98,28 +99,32 @@ var collapseNodeInputs = function (node, updatedInputs) {
98
99
  return Object.values(groupBy(__spreadArray(__spreadArray([], __read(updatedInputs), false), __read(node.inputs), false), function (i) { return i.id; })).map(function (dupes) { return dupes.reduce(function (node, dupe) { return (__assign(__assign({}, node), dupe)); }); });
99
100
  };
100
101
  var computeNodeContext = function (engineContext, engine, graph, node) { return __awaiter(void 0, void 0, void 0, function () {
101
- var parser, sibling, onBeforeCompile, manipulateAst, inputEdges, mainFn, ast, dataInputs, computedInputs, nodeContext;
102
+ var parser, sibling, onBeforeCompile, manipulateAst, updatedNodeContext, updatedContext, inputEdges, mainFn, ast, dataInputs, computedInputs, nodeContext;
102
103
  return __generator(this, function (_a) {
103
104
  switch (_a.label) {
104
105
  case 0:
105
106
  parser = __assign(__assign({}, (coreParsers[node.type] || coreParsers[NodeType.SOURCE])), (engine.parsers[node.type] || {}));
106
107
  sibling = findLinkedNode(graph, node.id);
107
108
  onBeforeCompile = parser.onBeforeCompile, manipulateAst = parser.manipulateAst;
109
+ updatedContext = engineContext;
108
110
  if (!onBeforeCompile) return [3 /*break*/, 2];
109
111
  return [4 /*yield*/, onBeforeCompile(graph, engineContext, node, sibling)];
110
112
  case 1:
111
- _a.sent();
113
+ updatedNodeContext = _a.sent();
114
+ if (updatedNodeContext) {
115
+ updatedContext = extendNodeContext(engineContext, node.id, updatedNodeContext);
116
+ }
112
117
  _a.label = 2;
113
118
  case 2:
114
119
  inputEdges = graph.edges.filter(function (edge) { return edge.to === node.id; });
115
120
  try {
116
- ast = parser.produceAst(engineContext, engine, graph, node, inputEdges);
121
+ ast = parser.produceAst(updatedContext, engine, graph, node, inputEdges);
117
122
  // Find the main function before mangling
118
123
  if (shouldNodeHaveMainFn(node)) {
119
124
  mainFn = findMain(ast);
120
125
  }
121
126
  if (manipulateAst) {
122
- ast = manipulateAst(engineContext, engine, graph, ast, inputEdges, node, sibling);
127
+ ast = manipulateAst(updatedContext, engine, graph, ast, inputEdges, node, sibling);
123
128
  }
124
129
  }
125
130
  catch (error) {
@@ -131,16 +136,21 @@ var computeNodeContext = function (engineContext, engine, graph, node) { return
131
136
  return input.bakeable && (fromNode === null || fromNode === void 0 ? void 0 : fromNode.type) === 'source';
132
137
  },
133
138
  }, 1).inputs[node.id] || [], 'id');
134
- computedInputs = parser.findInputs(engineContext, ast, inputEdges, node, sibling);
139
+ computedInputs = parser.findInputs(updatedContext, ast, inputEdges, node, sibling);
135
140
  node.inputs = collapseNodeInputs(node, computedInputs.map(function (_a) {
136
141
  var _b = __read(_a, 1), i = _b[0];
137
142
  return (__assign(__assign({}, i), { displayName: mapInputName(node, i) }));
138
143
  })).map(function (input) { return (__assign(__assign({}, input), (input.id in dataInputs ? { baked: true } : {}))); });
139
- nodeContext = {
140
- ast: ast,
141
- id: node.id,
142
- mainFn: mainFn,
143
- inputFillers: computedInputs.reduce(function (acc, _a) {
144
+ // Skip mangling if the node tells us to, which probably means it's an engine
145
+ // node where we don't care about renaming all the variables, or if it's
146
+ // an expression, where we want to be in the context of other variables
147
+ // TODO: Use global undefined engine variables here?
148
+ if (node.config.mangle !== false &&
149
+ node.sourceType !== SourceType.EXPRESSION &&
150
+ node.sourceType !== SourceType.FN_BODY_FRAGMENT) {
151
+ mangleEntireProgram(engine, ast, node, findLinkedNode(graph, node.id));
152
+ }
153
+ nodeContext = __assign(__assign({}, (updatedNodeContext || {})), { ast: ast, id: node.id, mainFn: mainFn, inputFillers: computedInputs.reduce(function (acc, _a) {
144
154
  var _b;
145
155
  var _c = __read(_a, 4), input = _c[0], filler = _c[1], fillerArgs = _c[2], fillerStmt = _c[3];
146
156
  // This is intentionally broken out into an explicit return to force
@@ -153,17 +163,7 @@ var computeNodeContext = function (engineContext, engine, graph, node) { return
153
163
  fillerStmt: fillerStmt,
154
164
  };
155
165
  return __assign(__assign({}, acc), (_b = {}, _b[input.id] = fillerGroup, _b));
156
- }, {}),
157
- };
158
- // Skip mangling if the node tells us to, which probably means it's an engine
159
- // node where we don't care about renaming all the variables, or if it's
160
- // an expression, where we want to be in the context of other variables
161
- // TODO: Use global undefined engine variables here?
162
- if (node.config.mangle !== false &&
163
- node.sourceType !== SourceType.EXPRESSION &&
164
- node.sourceType !== SourceType.FN_BODY_FRAGMENT) {
165
- mangleEntireProgram(engine, ast, node, findLinkedNode(graph, node.id));
166
- }
166
+ }, {}) });
167
167
  return [2 /*return*/, nodeContext];
168
168
  }
169
169
  });
@@ -174,22 +174,22 @@ export var computeContextForNodes = function (engineContext, engine, graph, node
174
174
  .filter(isSourceNode)
175
175
  .reduce(function (ctx, node) { return __awaiter(void 0, void 0, void 0, function () {
176
176
  var context, nodeContextOrError;
177
- return __generator(this, function (_a) {
178
- switch (_a.label) {
177
+ var _a;
178
+ return __generator(this, function (_b) {
179
+ switch (_b.label) {
179
180
  case 0: return [4 /*yield*/, ctx];
180
181
  case 1:
181
- context = _a.sent();
182
+ context = _b.sent();
182
183
  if (isError(context)) {
183
184
  return [2 /*return*/, context];
184
185
  }
185
186
  return [4 /*yield*/, computeNodeContext(engineContext, engine, graph, node)];
186
187
  case 2:
187
- nodeContextOrError = _a.sent();
188
+ nodeContextOrError = _b.sent();
188
189
  if (isError(nodeContextOrError)) {
189
190
  return [2 /*return*/, nodeContextOrError];
190
191
  }
191
- context[node.id] = __assign(__assign({}, (context[node.id] || {})), nodeContextOrError);
192
- return [2 /*return*/, context];
192
+ return [2 /*return*/, __assign(__assign({}, context), (_a = {}, _a[node.id] = __assign(__assign({}, (context[node.id] || {})), nodeContextOrError), _a))];
193
193
  }
194
194
  });
195
195
  }); }, Promise.resolve(engineContext.nodes))];
@@ -199,26 +199,18 @@ export var computeContextForNodes = function (engineContext, engine, graph, node
199
199
  * Compute the context for every node in the graph, done on initial graph load
200
200
  * to compute the inputs/outputs for every node
201
201
  */
202
- export var computeAllContexts = function (engineContext, engine, graph) { return __awaiter(void 0, void 0, void 0, function () {
203
- var result;
204
- return __generator(this, function (_a) {
205
- switch (_a.label) {
206
- case 0: return [4 /*yield*/, computeContextForNodes(engineContext, engine, graph, graph.nodes)];
207
- case 1:
208
- result = _a.sent();
209
- if (isError(result)) {
210
- return [2 /*return*/, result];
211
- }
212
- return [2 /*return*/];
213
- }
214
- });
215
- }); };
202
+ export var computeAllContexts = function (engineContext, engine, graph) { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
203
+ switch (_a.label) {
204
+ case 0: return [4 /*yield*/, computeContextForNodes(engineContext, engine, graph, graph.nodes)];
205
+ case 1: return [2 /*return*/, _a.sent()];
206
+ }
207
+ }); }); };
216
208
  /**
217
209
  * Compute the contexts for nodes starting from the outputs, working backwards.
218
210
  * Used to only (re)-compute context for any actively used nodes
219
211
  */
220
212
  export var computeGraphContext = function (engineContext, engine, graph) { return __awaiter(void 0, void 0, void 0, function () {
221
- var outputFrag, outputVert, vertexes, fragments, vertexIds, unlinkedNodes, vertNodesOrError, fragNodesOrError;
213
+ var outputFrag, outputVert, vertexes, fragments, vertexIds, unlinkedNodes, vertNodesOrError, updatedContext, finalNodeContextOrError;
222
214
  return __generator(this, function (_a) {
223
215
  switch (_a.label) {
224
216
  case 0:
@@ -242,15 +234,13 @@ export var computeGraphContext = function (engineContext, engine, graph) { retur
242
234
  if (isError(vertNodesOrError)) {
243
235
  return [2 /*return*/, vertNodesOrError];
244
236
  }
245
- return [4 /*yield*/, computeContextForNodes(engineContext, engine, graph, __spreadArray([
237
+ updatedContext = extendNodesContext(engineContext, vertNodesOrError);
238
+ return [4 /*yield*/, computeContextForNodes(updatedContext, engine, graph, __spreadArray([
246
239
  outputFrag
247
240
  ], __read(Object.values(fragments).filter(function (node) { return node.id !== outputFrag.id && !vertexIds.has(node.id); })), false))];
248
241
  case 2:
249
- fragNodesOrError = _a.sent();
250
- if (isError(fragNodesOrError)) {
251
- return [2 /*return*/, fragNodesOrError];
252
- }
253
- return [2 /*return*/];
242
+ finalNodeContextOrError = _a.sent();
243
+ return [2 /*return*/, finalNodeContextOrError];
254
244
  }
255
245
  });
256
246
  }); };
@@ -20,17 +20,26 @@ export declare const numberNode: (id: string, name: string, position: NodePositi
20
20
  }) => NumberNode;
21
21
  export type NumberDataUniform = Pick<NumberNode, 'type' | 'value' | 'name' | 'range' | 'stepper'>;
22
22
  export declare const numberUniformData: (name: string, value: string, range?: [string | number, string | number], stepper?: string | number) => NumberDataUniform;
23
- export type AssetVersionNodeData = {
24
- assetId: number;
25
- versionId: number;
23
+ export type TextureNodeValueData = {
24
+ assetId?: number;
25
+ versionId?: number;
26
+ properties?: {
27
+ repeatTexure: boolean;
28
+ repeat?: {
29
+ x: number;
30
+ y: number;
31
+ };
32
+ anisotropy?: number;
33
+ encoding?: 'srgb';
34
+ };
26
35
  };
27
36
  export interface TextureNode extends BaseNode {
28
37
  type: 'texture';
29
- value?: AssetVersionNodeData;
38
+ value?: TextureNodeValueData;
30
39
  }
31
- export declare const textureNode: (id: string, name: string, position: NodePosition, value: AssetVersionNodeData) => TextureNode;
40
+ export declare const textureNode: (id: string, name: string, position: NodePosition, value?: TextureNodeValueData) => TextureNode;
32
41
  export type TextureDataUniform = Pick<TextureNode, 'type' | 'value' | 'name'>;
33
- export declare const textureUniformData: (name: string, value: AssetVersionNodeData) => TextureDataUniform;
42
+ export declare const textureUniformData: (name: string, value: TextureNodeValueData) => TextureDataUniform;
34
43
  export interface SamplerCubeNode extends BaseNode {
35
44
  type: 'samplerCube';
36
45
  value: string;
@@ -40,7 +40,7 @@ export var textureNode = function (id, name, position, value) { return ({
40
40
  id: id,
41
41
  name: name,
42
42
  position: position,
43
- value: value,
43
+ value: __assign(__assign({}, (value || { assetId: undefined, versionId: undefined })), { properties: (value === null || value === void 0 ? void 0 : value.properties) || { repeatTexure: true } }),
44
44
  inputs: [],
45
45
  outputs: [
46
46
  {
@@ -4,12 +4,11 @@ import { SourceNode } from './code-nodes';
4
4
  /**
5
5
  * Core graph types.
6
6
  *
7
- * Originally abstracted out of graph.ts to avoid a circular
8
- * dependency between graph.ts and parsers.ts. Both files need these types at
9
- * module initialization time, and without this third file, the types will be
10
- * undefined in either graph/parsers.ts at init time. If the types were only
11
- * used at runtime it would be fine, because the circular depenency is resolved
12
- * by then.
7
+ * Originally abstracted out of graph.ts to avoid a circular dependency between
8
+ * graph.ts and parsers.ts. Both files need these types at module initialization
9
+ * time, and without this third file, the types will be undefined in either
10
+ * graph/parsers.ts at init time. If the types were only used at runtime it
11
+ * would be fine, because the circular depenency is resolved by then.
13
12
  */
14
13
  export type ShaderStage = 'fragment' | 'vertex';
15
14
  /**
@@ -35,4 +34,25 @@ export interface Graph {
35
34
  nodes: GraphNode[];
36
35
  edges: Edge[];
37
36
  }
37
+ export type EdgesByNode = {
38
+ [nodeId: string]: {
39
+ from: Edge[];
40
+ to: {
41
+ edges: Edge[];
42
+ edgesByInput: {
43
+ [inputId: string]: Edge;
44
+ };
45
+ };
46
+ };
47
+ };
48
+ export type Grindex = {
49
+ nodes: {
50
+ [nodeId: string]: GraphNode;
51
+ };
52
+ edges: {
53
+ [edgeId: string]: Edge;
54
+ };
55
+ edgesByNode: EdgesByNode;
56
+ };
57
+ export declare const computeGrindex: (graph: Graph) => Grindex;
38
58
  export declare const MAGIC_OUTPUT_STMTS = "mainStmts";
@@ -1,3 +1,40 @@
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
11
+ };
12
+ var __read = (this && this.__read) || function (o, n) {
13
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
14
+ if (!m) return o;
15
+ var i = m.call(o), r, ar = [], e;
16
+ try {
17
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
18
+ }
19
+ catch (error) { e = { error: error }; }
20
+ finally {
21
+ try {
22
+ if (r && !r.done && (m = i["return"])) m.call(i);
23
+ }
24
+ finally { if (e) throw e.error; }
25
+ }
26
+ return ar;
27
+ };
28
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
29
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
30
+ if (ar || !(i in from)) {
31
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
32
+ ar[i] = from[i];
33
+ }
34
+ }
35
+ return to.concat(ar || Array.prototype.slice.call(from));
36
+ };
37
+ import indexById from '../util/indexByid';
1
38
  /**
2
39
  * The type applied to the edge representing a link between node stages
3
40
  */
@@ -19,4 +56,36 @@ export var NodeType;
19
56
  NodeType["BINARY"] = "binary";
20
57
  NodeType["SOURCE"] = "source";
21
58
  })(NodeType || (NodeType = {}));
59
+ var lastGraph;
60
+ var lastGrindex;
61
+ export var computeGrindex = function (graph) {
62
+ // Poor programmer's memoization
63
+ if (graph === lastGraph && lastGrindex) {
64
+ return lastGrindex;
65
+ }
66
+ lastGraph = graph;
67
+ lastGrindex = {
68
+ nodes: indexById(graph.nodes),
69
+ edges: indexById(graph.edges),
70
+ edgesByNode: graph.edges.reduce(function (acc, edge) {
71
+ var _a, _b, _c;
72
+ var _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
73
+ var to = edge.to, from = edge.from;
74
+ return __assign(__assign({}, acc), (_a = {}, _a[to] = {
75
+ to: {
76
+ edges: __spreadArray(__spreadArray([], __read((((_e = (_d = acc[to]) === null || _d === void 0 ? void 0 : _d.to) === null || _e === void 0 ? void 0 : _e.edges) || [])), false), [edge], false),
77
+ edgesByInput: __assign(__assign({}, (_g = (_f = acc[to]) === null || _f === void 0 ? void 0 : _f.to) === null || _g === void 0 ? void 0 : _g.edgesByInput), (_b = {}, _b[edge.input] = edge, _b)),
78
+ },
79
+ from: ((_h = acc[to]) === null || _h === void 0 ? void 0 : _h.from) || [],
80
+ }, _a[from] = {
81
+ to: {
82
+ edges: ((_k = (_j = acc[from]) === null || _j === void 0 ? void 0 : _j.to) === null || _k === void 0 ? void 0 : _k.edges) || [],
83
+ edgesByInput: __assign(__assign({}, (_m = (_l = acc[from]) === null || _l === void 0 ? void 0 : _l.to) === null || _m === void 0 ? void 0 : _m.edgesByInput), (_c = {}, _c[edge.input] = edge, _c)),
84
+ },
85
+ from: __spreadArray(__spreadArray([], __read((((_o = acc[from]) === null || _o === void 0 ? void 0 : _o.from) || [])), false), [edge], false),
86
+ }, _a));
87
+ }, {}),
88
+ };
89
+ return lastGrindex;
90
+ };
22
91
  export var MAGIC_OUTPUT_STMTS = 'mainStmts';
package/graph/graph.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Program } from '@shaderfrog/glsl-parser/ast';
2
2
  import { Engine, EngineContext } from '../engine';
3
- import { NodeErrors } from './context';
3
+ import { NodeContexts, NodeErrors } from './context';
4
4
  import { ShaderSections } from './shader-sections';
5
5
  import { FrogProgram } from '../util/ast';
6
6
  import { DataNode } from './data-nodes';
@@ -26,7 +26,30 @@ export declare const mangleEntireProgram: (engine: Engine, ast: FrogProgram, nod
26
26
  export declare const mangleMainFn: (ast: Program, node: GraphNode, sibling?: GraphNode) => void;
27
27
  export declare const ensureFromNode: (graph: Graph, inputEdge: Edge) => import("./data-nodes").NumberNode | import("./data-nodes").TextureNode | import("./data-nodes").SamplerCubeNode | import("./data-nodes").ArrayNode | import("./data-nodes").Vector2Node | import("./data-nodes").Vector3Node | import("./data-nodes").Vector4Node | import("./data-nodes").RgbNode | import("./data-nodes").RgbaNode | import("./code-nodes").BinaryNode | CodeNode;
28
28
  export declare const resetGraphIds: (graph: Graph) => Graph;
29
- export declare const findLinkedNode: (graph: Graph, id: string) => SourceNode | undefined;
29
+ /**
30
+ * A binary node automatically adds/removes inputs based on how many edges
31
+ * connect to it. If a binary node has edges to "a" and "b", removing the edge
32
+ * to "a" means the edge to "b" needs to be moved down to the "a" one. This
33
+ * function essentially groups edges by target node id, and resets the edge
34
+ * target to its index. This doesn't feel good to do here but I don't have a
35
+ * better idea at the moment. One reason the inputs to binary nodes are
36
+ * automatically updated after compile, but the edges are updated here
37
+ * at the editor layer, before compile. This also hard codes assumptions about
38
+ * (binary) node inputs into the graph, namely they can't have blank inputs.
39
+ */
40
+ export declare const collapseBinaryGraphEdges: (graph: Graph) => Graph;
41
+ /**
42
+ * Restrict edges so that an input handle can't have multiple edges going to it
43
+ */
44
+ export declare const addEdgeAndPruneRestrictions: (edges: Edge[], newEdge: Edge) => Edge[];
45
+ /**
46
+ * Adds an edge to the graph and enforces graph edge business logic rules:
47
+ * - Makes sure "binary" (add/multiply) nodes edges are collapsed
48
+ * - Makes sure two edges can't flow into the same input.
49
+ * See also editor/flow-helpers.ts
50
+ */
51
+ export declare const addGraphEdge: (graph: Graph, newEdge: Edge) => Graph;
52
+ export declare const findLinkedNode: (graph: Graph, nodeId: string) => SourceNode | undefined;
30
53
  /**
31
54
  * Find any unconnected vertex nodes linked to collected fragment nodes
32
55
  */
@@ -39,7 +62,7 @@ export type Predicates = {
39
62
  export type SearchResult = {
40
63
  nodes: Record<string, GraphNode>;
41
64
  inputs: Record<string, NodeInput[]>;
42
- edges: Edge[];
65
+ edges: Record<string, Edge>;
43
66
  };
44
67
  export declare const consSearchResult: () => SearchResult;
45
68
  export declare const mergeSearchResults: (a: SearchResult, b: SearchResult) => SearchResult;
@@ -86,11 +109,13 @@ export declare const compileGraph: (engineContext: EngineContext, engine: Engine
86
109
  export declare const collectNodeProperties: (graph: Graph) => SearchResult;
87
110
  export type IndexedDataInputs = Record<string, NodeInput[]>;
88
111
  export type CompileResult = {
112
+ updatedNodeContext: NodeContexts;
89
113
  fragmentResult: string;
90
114
  vertexResult: string;
91
115
  compileResult: CompileGraphResult;
92
116
  dataNodes: Record<string, GraphNode>;
93
117
  dataInputs: IndexedDataInputs;
118
+ compileMs: string;
94
119
  };
95
120
  export declare const compileSource: (graph: Graph, engine: Engine, ctx: EngineContext) => Promise<CompileResult | NodeErrors>;
96
121
  export {};