@shaderfrog/core 1.2.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/cjs/package.json +1 -0
  2. package/esm/engine.d.ts +69 -0
  3. package/esm/engine.js +209 -0
  4. package/esm/graph/base-node.d.ts +36 -0
  5. package/esm/graph/base-node.js +9 -0
  6. package/esm/graph/code-nodes.d.ts +44 -0
  7. package/esm/graph/code-nodes.js +18 -0
  8. package/esm/graph/context.d.ts +37 -0
  9. package/esm/graph/context.js +243 -0
  10. package/esm/graph/data-nodes.d.ts +83 -0
  11. package/esm/graph/data-nodes.js +131 -0
  12. package/esm/graph/edge.d.ts +13 -0
  13. package/esm/graph/edge.js +7 -0
  14. package/esm/graph/evaluate.d.ts +9 -0
  15. package/esm/graph/evaluate.js +27 -0
  16. package/esm/graph/graph-node.d.ts +8 -0
  17. package/esm/graph/graph-node.js +135 -0
  18. package/esm/graph/graph-types.d.ts +38 -0
  19. package/esm/graph/graph-types.js +22 -0
  20. package/esm/graph/graph.d.ts +89 -0
  21. package/esm/graph/graph.js +506 -0
  22. package/esm/graph/graph.test.d.ts +1 -0
  23. package/esm/graph/graph.test.js +168 -0
  24. package/esm/graph/index.d.ts +11 -0
  25. package/esm/graph/index.js +11 -0
  26. package/esm/graph/parsers.d.ts +39 -0
  27. package/esm/graph/parsers.js +213 -0
  28. package/esm/graph/shader-sections.d.ts +47 -0
  29. package/esm/graph/shader-sections.js +256 -0
  30. package/esm/index.d.ts +3 -0
  31. package/esm/index.js +3 -0
  32. package/esm/package.json +1 -0
  33. package/esm/plugins/babylon/bablyengine.d.ts +28 -0
  34. package/esm/plugins/babylon/bablyengine.js +589 -0
  35. package/esm/plugins/babylon/importers.d.ts +3 -0
  36. package/esm/plugins/babylon/importers.js +64 -0
  37. package/esm/plugins/babylon/index.d.ts +2 -0
  38. package/esm/plugins/babylon/index.js +2 -0
  39. package/esm/plugins/playcanvas/importers.d.ts +3 -0
  40. package/esm/plugins/playcanvas/importers.js +28 -0
  41. package/esm/plugins/playcanvas/index.d.ts +2 -0
  42. package/esm/plugins/playcanvas/index.js +2 -0
  43. package/esm/plugins/playcanvas/playengine.d.ts +39 -0
  44. package/esm/plugins/playcanvas/playengine.js +517 -0
  45. package/esm/plugins/three/importers.d.ts +3 -0
  46. package/esm/plugins/three/importers.js +15 -0
  47. package/esm/plugins/three/index.d.ts +2 -0
  48. package/esm/plugins/three/index.js +2 -0
  49. package/esm/plugins/three/threngine.d.ts +34 -0
  50. package/esm/plugins/three/threngine.js +608 -0
  51. package/esm/strategy/assignemntTo.d.ts +9 -0
  52. package/esm/strategy/assignemntTo.js +26 -0
  53. package/esm/strategy/declarationOf.d.ts +9 -0
  54. package/esm/strategy/declarationOf.js +23 -0
  55. package/esm/strategy/hardCode.d.ts +15 -0
  56. package/esm/strategy/hardCode.js +23 -0
  57. package/esm/strategy/index.d.ts +9 -0
  58. package/esm/strategy/index.js +9 -0
  59. package/esm/strategy/inject.d.ts +15 -0
  60. package/esm/strategy/inject.js +122 -0
  61. package/esm/strategy/namedAttribute.d.ts +9 -0
  62. package/esm/strategy/namedAttribute.js +48 -0
  63. package/esm/strategy/strategy.d.ts +28 -0
  64. package/esm/strategy/strategy.js +31 -0
  65. package/esm/strategy/stratgies.test.d.ts +1 -0
  66. package/esm/strategy/stratgies.test.js +164 -0
  67. package/esm/strategy/texture2D.d.ts +6 -0
  68. package/esm/strategy/texture2D.js +83 -0
  69. package/esm/strategy/uniform.d.ts +6 -0
  70. package/esm/strategy/uniform.js +190 -0
  71. package/esm/strategy/variable.d.ts +6 -0
  72. package/esm/strategy/variable.js +80 -0
  73. package/esm/util/ast.d.ts +30 -0
  74. package/esm/util/ast.js +332 -0
  75. package/esm/util/ensure.d.ts +1 -0
  76. package/esm/util/ensure.js +7 -0
  77. package/esm/util/id.d.ts +1 -0
  78. package/esm/util/id.js +2 -0
  79. package/package.json +10 -11
  80. /package/{engine.d.ts → cjs/engine.d.ts} +0 -0
  81. /package/{engine.js → cjs/engine.js} +0 -0
  82. /package/{graph → cjs/graph}/base-node.d.ts +0 -0
  83. /package/{graph → cjs/graph}/base-node.js +0 -0
  84. /package/{graph → cjs/graph}/code-nodes.d.ts +0 -0
  85. /package/{graph → cjs/graph}/code-nodes.js +0 -0
  86. /package/{graph → cjs/graph}/context.d.ts +0 -0
  87. /package/{graph → cjs/graph}/context.js +0 -0
  88. /package/{graph → cjs/graph}/data-nodes.d.ts +0 -0
  89. /package/{graph → cjs/graph}/data-nodes.js +0 -0
  90. /package/{graph → cjs/graph}/edge.d.ts +0 -0
  91. /package/{graph → cjs/graph}/edge.js +0 -0
  92. /package/{graph → cjs/graph}/evaluate.d.ts +0 -0
  93. /package/{graph → cjs/graph}/evaluate.js +0 -0
  94. /package/{graph → cjs/graph}/graph-node.d.ts +0 -0
  95. /package/{graph → cjs/graph}/graph-node.js +0 -0
  96. /package/{graph → cjs/graph}/graph-types.d.ts +0 -0
  97. /package/{graph → cjs/graph}/graph-types.js +0 -0
  98. /package/{graph → cjs/graph}/graph.d.ts +0 -0
  99. /package/{graph → cjs/graph}/graph.js +0 -0
  100. /package/{graph → cjs/graph}/graph.test.d.ts +0 -0
  101. /package/{graph → cjs/graph}/graph.test.js +0 -0
  102. /package/{graph → cjs/graph}/index.d.ts +0 -0
  103. /package/{graph → cjs/graph}/index.js +0 -0
  104. /package/{graph → cjs/graph}/parsers.d.ts +0 -0
  105. /package/{graph → cjs/graph}/parsers.js +0 -0
  106. /package/{graph → cjs/graph}/shader-sections.d.ts +0 -0
  107. /package/{graph → cjs/graph}/shader-sections.js +0 -0
  108. /package/{index.d.ts → cjs/index.d.ts} +0 -0
  109. /package/{index.js → cjs/index.js} +0 -0
  110. /package/{plugins → cjs/plugins}/babylon/bablyengine.d.ts +0 -0
  111. /package/{plugins → cjs/plugins}/babylon/bablyengine.js +0 -0
  112. /package/{plugins → cjs/plugins}/babylon/importers.d.ts +0 -0
  113. /package/{plugins → cjs/plugins}/babylon/importers.js +0 -0
  114. /package/{plugins → cjs/plugins}/babylon/index.d.ts +0 -0
  115. /package/{plugins → cjs/plugins}/babylon/index.js +0 -0
  116. /package/{plugins → cjs/plugins}/playcanvas/importers.d.ts +0 -0
  117. /package/{plugins → cjs/plugins}/playcanvas/importers.js +0 -0
  118. /package/{plugins → cjs/plugins}/playcanvas/index.d.ts +0 -0
  119. /package/{plugins → cjs/plugins}/playcanvas/index.js +0 -0
  120. /package/{plugins → cjs/plugins}/playcanvas/playengine.d.ts +0 -0
  121. /package/{plugins → cjs/plugins}/playcanvas/playengine.js +0 -0
  122. /package/{plugins → cjs/plugins}/three/importers.d.ts +0 -0
  123. /package/{plugins → cjs/plugins}/three/importers.js +0 -0
  124. /package/{plugins → cjs/plugins}/three/index.d.ts +0 -0
  125. /package/{plugins → cjs/plugins}/three/index.js +0 -0
  126. /package/{plugins → cjs/plugins}/three/threngine.d.ts +0 -0
  127. /package/{plugins → cjs/plugins}/three/threngine.js +0 -0
  128. /package/{strategy → cjs/strategy}/assignemntTo.d.ts +0 -0
  129. /package/{strategy → cjs/strategy}/assignemntTo.js +0 -0
  130. /package/{strategy → cjs/strategy}/declarationOf.d.ts +0 -0
  131. /package/{strategy → cjs/strategy}/declarationOf.js +0 -0
  132. /package/{strategy → cjs/strategy}/hardCode.d.ts +0 -0
  133. /package/{strategy → cjs/strategy}/hardCode.js +0 -0
  134. /package/{strategy → cjs/strategy}/index.d.ts +0 -0
  135. /package/{strategy → cjs/strategy}/index.js +0 -0
  136. /package/{strategy → cjs/strategy}/inject.d.ts +0 -0
  137. /package/{strategy → cjs/strategy}/inject.js +0 -0
  138. /package/{strategy → cjs/strategy}/namedAttribute.d.ts +0 -0
  139. /package/{strategy → cjs/strategy}/namedAttribute.js +0 -0
  140. /package/{strategy → cjs/strategy}/strategy.d.ts +0 -0
  141. /package/{strategy → cjs/strategy}/strategy.js +0 -0
  142. /package/{strategy → cjs/strategy}/stratgies.test.d.ts +0 -0
  143. /package/{strategy → cjs/strategy}/stratgies.test.js +0 -0
  144. /package/{strategy → cjs/strategy}/texture2D.d.ts +0 -0
  145. /package/{strategy → cjs/strategy}/texture2D.js +0 -0
  146. /package/{strategy → cjs/strategy}/uniform.d.ts +0 -0
  147. /package/{strategy → cjs/strategy}/uniform.js +0 -0
  148. /package/{strategy → cjs/strategy}/variable.d.ts +0 -0
  149. /package/{strategy → cjs/strategy}/variable.js +0 -0
  150. /package/{util → cjs/util}/ast.d.ts +0 -0
  151. /package/{util → cjs/util}/ast.js +0 -0
  152. /package/{util → cjs/util}/ensure.d.ts +0 -0
  153. /package/{util → cjs/util}/ensure.js +0 -0
  154. /package/{util → cjs/util}/id.d.ts +0 -0
  155. /package/{util → cjs/util}/id.js +0 -0
@@ -0,0 +1 @@
1
+ {"type": "commonjs"}
@@ -0,0 +1,69 @@
1
+ import { Program } from '@shaderfrog/glsl-parser/ast';
2
+ import { MergeOptions } from './graph/shader-sections';
3
+ import { Graph, ShaderStage } from './graph/graph-types';
4
+ import { NodePosition } from './graph/base-node';
5
+ import { DataNode, UniformDataType } from './graph/data-nodes';
6
+ import { CodeNode, NodeProperty, SourceNode } from './graph/code-nodes';
7
+ import { NodeContext } from './graph/context';
8
+ import { NodeParser } from './graph/parsers';
9
+ export declare enum EngineNodeType {
10
+ toon = "toon",
11
+ phong = "phong",
12
+ physical = "physical",
13
+ shader = "shader",
14
+ binary = "binary"
15
+ }
16
+ export type PhongNodeConstructor = (id: string, name: string, position: NodePosition, uniforms: UniformDataType[], stage: ShaderStage | undefined) => CodeNode;
17
+ export type PhysicalNodeConstructor = (id: string, name: string, position: NodePosition, uniforms: UniformDataType[], stage: ShaderStage | undefined) => CodeNode;
18
+ export type ToonNodeConstructor = (id: string, name: string, position: NodePosition, uniforms: UniformDataType[], stage: ShaderStage | undefined) => CodeNode;
19
+ export interface Engine {
20
+ name: 'three' | 'babylon' | 'playcanvas';
21
+ displayName: string;
22
+ preserve: Set<string>;
23
+ mergeOptions: MergeOptions;
24
+ parsers: Record<string, NodeParser>;
25
+ importers: EngineImporters;
26
+ evaluateNode: (node: DataNode) => any;
27
+ constructors: {
28
+ [EngineNodeType.phong]?: PhongNodeConstructor;
29
+ [EngineNodeType.physical]?: PhysicalNodeConstructor;
30
+ [EngineNodeType.toon]?: ToonNodeConstructor;
31
+ };
32
+ }
33
+ export type EngineContext = {
34
+ engine: string;
35
+ nodes: Record<string, NodeContext>;
36
+ runtime: any;
37
+ debuggingNonsense: {
38
+ vertexSource?: string;
39
+ vertexPreprocessed?: string;
40
+ fragmentPreprocessed?: string;
41
+ fragmentSource?: string;
42
+ };
43
+ };
44
+ export type EngineImporter = {
45
+ convertAst(ast: Program, type?: ShaderStage): void;
46
+ nodeInputMap: Partial<Record<EngineNodeType, Record<string, string | null>>>;
47
+ edgeMap: {
48
+ [oldInput: string]: string;
49
+ };
50
+ };
51
+ export type EngineImporters = {
52
+ [engine: string]: EngineImporter;
53
+ };
54
+ export declare const convertNode: (node: SourceNode, converter: EngineImporter) => SourceNode;
55
+ export declare const convertToEngine: (oldEngine: Engine, newEngine: Engine, graph: Graph) => Graph;
56
+ export type DefaultPropertySetter = (p: NodeProperty) => any;
57
+ /**
58
+ * Create the initial engine node properties for a plugin to create its initial
59
+ * material with. This finds all engine nodes in the graph, finds all their
60
+ * properties, evalutes them, and returns an object with initial properties to
61
+ * set on the new plugin material, like a three.RawShaderMaterial().
62
+ *
63
+ * Currently only PlayCanvas uses this. It's at odds with the compileResult.dataInputs
64
+ * code path. That path uses isDataNode() to check for inputs, which excludes
65
+ * baked inputs. PlayCanvas requires (at least diffusesMap?) baked input properties
66
+ * to be set to a pc.Texture() at runtime, otherwise there's an error about
67
+ * vertex_texCoord0.
68
+ */
69
+ export declare const collectInitialEvaluatedGraphProperties: (engine: Engine, graph: Graph, defaultPropertySetting: DefaultPropertySetter) => Record<string, any>;
package/esm/engine.js ADDED
@@ -0,0 +1,209 @@
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 preprocess from '@shaderfrog/glsl-parser/preprocessor';
38
+ import { generate, parser } from '@shaderfrog/glsl-parser';
39
+ import { NodeType } from './graph/graph-types';
40
+ import groupBy from 'lodash.groupby';
41
+ import { collectNodeProperties } from './graph/graph';
42
+ import { evaluateNode } from './graph/evaluate';
43
+ var log = function () {
44
+ var _a;
45
+ var args = [];
46
+ for (var _i = 0; _i < arguments.length; _i++) {
47
+ args[_i] = arguments[_i];
48
+ }
49
+ return (_a = console.log).call.apply(_a, __spreadArray([console, '\x1b[32m(core)\x1b[0m'], __read(args), false));
50
+ };
51
+ export var EngineNodeType;
52
+ (function (EngineNodeType) {
53
+ EngineNodeType["toon"] = "toon";
54
+ EngineNodeType["phong"] = "phong";
55
+ EngineNodeType["physical"] = "physical";
56
+ EngineNodeType["shader"] = "shader";
57
+ EngineNodeType["binary"] = "binary";
58
+ })(EngineNodeType || (EngineNodeType = {}));
59
+ // type EdgeUpdates = { [edgeId: string]: { oldInput: string; newInput: string } };
60
+ export var convertNode = function (node, converter) {
61
+ log("Converting ".concat(node.name, " (").concat(node.id, ")"));
62
+ var preprocessed = preprocess(node.source, {
63
+ preserveComments: true,
64
+ preserve: {
65
+ version: function () { return true; },
66
+ define: function () { return true; },
67
+ },
68
+ });
69
+ var ast = parser.parse(preprocessed);
70
+ converter.convertAst(ast, node.stage);
71
+ var source = generate(ast);
72
+ return __assign(__assign({}, node), { source: source });
73
+ };
74
+ export var convertToEngine = function (oldEngine, newEngine, graph) {
75
+ var converter = newEngine.importers[oldEngine.name];
76
+ if (!converter) {
77
+ throw new Error("The engine ".concat(newEngine.name, " has no importer for ").concat(oldEngine.name));
78
+ }
79
+ log("Attempting to convert from ".concat(newEngine.name, " to ").concat(oldEngine.name));
80
+ // const edgeUpdates: EdgeUpdates = {};
81
+ var edgesByNodeId = groupBy(graph.edges, 'to');
82
+ var edgeUpdates = {};
83
+ var nodeUpdates = {};
84
+ graph.nodes.forEach(function (node) {
85
+ // Convert engine nodes
86
+ if (node.type in EngineNodeType) {
87
+ if (node.type in newEngine.constructors) {
88
+ var source = node;
89
+ nodeUpdates[source.id] = // @ts-ignore
90
+ newEngine.constructors[source.type](source.id, source.name, source.position, source.config.uniforms, source.stage);
91
+ // Bail if no conversion
92
+ }
93
+ else {
94
+ throw new Error("Can't convert ".concat(oldEngine.name, " to ").concat(newEngine.name, " because ").concat(newEngine.name, " does not have a \"").concat(node.type, "\" constructor"));
95
+ }
96
+ }
97
+ else if (NodeType.SOURCE === node.type) {
98
+ nodeUpdates[node.id] = convertNode(node, converter);
99
+ }
100
+ // Then update input edges. We only care about engine nodes
101
+ if (node.type in converter.nodeInputMap) {
102
+ var map_1 = converter.nodeInputMap[node.type];
103
+ (edgesByNodeId[node.id] || []).forEach(function (edge) {
104
+ if (edge.input in map_1) {
105
+ var mapped = map_1[edge.input];
106
+ log('Converting edge', edge.input, 'to', map_1[edge.input]);
107
+ edgeUpdates[edge.id] = __assign(__assign({}, edge), { input: mapped });
108
+ }
109
+ else {
110
+ log('Discarding', edge.input, 'as there is no edge mapping in the', newEngine.name, 'importer');
111
+ edgeUpdates[edge.id] = null;
112
+ }
113
+ });
114
+ }
115
+ });
116
+ graph.edges = graph.edges.reduce(function (edges, edge) {
117
+ if (edge.id in edgeUpdates) {
118
+ var res = edgeUpdates[edge.id];
119
+ if (res === null) {
120
+ return edges;
121
+ }
122
+ else {
123
+ return __spreadArray(__spreadArray([], __read(edges), false), [res], false);
124
+ }
125
+ }
126
+ return __spreadArray(__spreadArray([], __read(edges), false), [edge], false);
127
+ }, []);
128
+ graph.nodes = graph.nodes.reduce(function (nodes, node) {
129
+ if (node.id in nodeUpdates) {
130
+ var res = nodeUpdates[node.id];
131
+ if (res === null) {
132
+ return nodes;
133
+ }
134
+ else {
135
+ return __spreadArray(__spreadArray([], __read(nodes), false), [res], false);
136
+ }
137
+ }
138
+ return __spreadArray(__spreadArray([], __read(nodes), false), [node], false);
139
+ }, []);
140
+ log('Created converted graph', graph);
141
+ return graph;
142
+ };
143
+ /**
144
+ * Create the initial engine node properties for a plugin to create its initial
145
+ * material with. This finds all engine nodes in the graph, finds all their
146
+ * properties, evalutes them, and returns an object with initial properties to
147
+ * set on the new plugin material, like a three.RawShaderMaterial().
148
+ *
149
+ * Currently only PlayCanvas uses this. It's at odds with the compileResult.dataInputs
150
+ * code path. That path uses isDataNode() to check for inputs, which excludes
151
+ * baked inputs. PlayCanvas requires (at least diffusesMap?) baked input properties
152
+ * to be set to a pc.Texture() at runtime, otherwise there's an error about
153
+ * vertex_texCoord0.
154
+ */
155
+ export var collectInitialEvaluatedGraphProperties = function (engine, graph, defaultPropertySetting) {
156
+ var graphProperties = {};
157
+ // Get all the nodes with properties, meaning engine nodes, and the inputs
158
+ // for each property (property is like "diffuseMap").
159
+ var _a = collectNodeProperties(graph), nodes = _a.nodes, inputs = _a.inputs;
160
+ Object.entries(inputs).forEach(function (_a) {
161
+ var _b = __read(_a, 2), nodeId = _b[0], nodeInputs = _b[1];
162
+ // For every node with properties... There might be mulitple if there are
163
+ // uniforms plugged into both frag and vertex engine nodes, which
164
+ var node = nodes[nodeId];
165
+ nodeInputs.forEach(function (i) {
166
+ // Cast this to an input with a property specified on it, which the
167
+ // predicate search enforces
168
+ var input = i;
169
+ var edge = graph.edges.find(function (_a) {
170
+ var to = _a.to, i = _a.input;
171
+ return to === node.id && i === input.id;
172
+ });
173
+ // In the case where a node has been deleted from the graph,
174
+ // dataInputs won't have been udpated until a recompile completes
175
+ var fromNode = edge && graph.nodes.find(function (_a) {
176
+ var id = _a.id;
177
+ return id === edge.from;
178
+ });
179
+ if (fromNode) {
180
+ // If this is a baked input, we need to set the engine property to force
181
+ // whatever we're baking to generate.
182
+ if (input.baked) {
183
+ // Find the corresponding property on the node and get the default
184
+ // setting
185
+ var property = (node.config.properties || []).find(function (p) { return p.property === input.property; });
186
+ if (property) {
187
+ graphProperties[input.property] = defaultPropertySetting(property);
188
+ }
189
+ else {
190
+ console.error('Property not found on input node', node, input);
191
+ throw new Error('Property not found on input node');
192
+ }
193
+ // Other inputs should(?) be data if not baked
194
+ }
195
+ else {
196
+ try {
197
+ graphProperties[input.property] = evaluateNode(engine, graph, fromNode);
198
+ }
199
+ catch (err) {
200
+ console.error('Tried to evaluate a non-data node!', {
201
+ err: err,
202
+ });
203
+ }
204
+ }
205
+ }
206
+ });
207
+ });
208
+ return graphProperties;
209
+ };
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Base node stuff, used across all nodes
3
+ */
4
+ import { GraphDataType } from './data-nodes';
5
+ export type InputCategory = 'data' | 'code';
6
+ export type InputType = 'uniform' | 'property' | 'filler';
7
+ export interface NodeInput {
8
+ displayName: string;
9
+ id: string;
10
+ type: InputType;
11
+ dataType?: GraphDataType;
12
+ accepts: InputCategory[];
13
+ baked?: boolean;
14
+ bakeable: boolean;
15
+ property?: string;
16
+ }
17
+ export declare const nodeInput: (displayName: string, id: string, type: InputType, dataType: GraphDataType | undefined, accepts: InputCategory[], bakeable: boolean, property?: string) => NodeInput;
18
+ export interface NodeOutput {
19
+ name: string;
20
+ id: string;
21
+ dataType?: GraphDataType;
22
+ category: InputCategory;
23
+ }
24
+ export type NodePosition = {
25
+ x: number;
26
+ y: number;
27
+ };
28
+ export interface BaseNode {
29
+ id: string;
30
+ parentId?: string;
31
+ name: string;
32
+ type: string;
33
+ inputs: NodeInput[];
34
+ outputs: NodeOutput[];
35
+ position: NodePosition;
36
+ }
@@ -0,0 +1,9 @@
1
+ export var nodeInput = function (displayName, id, type, dataType, accepts, bakeable, property) { return ({
2
+ displayName: displayName,
3
+ id: id,
4
+ type: type,
5
+ dataType: dataType,
6
+ accepts: accepts,
7
+ bakeable: bakeable,
8
+ property: property,
9
+ }); };
@@ -0,0 +1,44 @@
1
+ import { ShaderStage } from './graph-types';
2
+ import { Strategy } from '../strategy';
3
+ import { GraphDataType, UniformDataType } from './data-nodes';
4
+ import { BaseNode, NodeInput } from './base-node';
5
+ export declare const mapInputName: (node: CodeNode, { id, displayName }: NodeInput) => string;
6
+ export type InputMapping = {
7
+ [original: string]: string;
8
+ };
9
+ export type NodeConfig = {
10
+ version: 2 | 3;
11
+ mangle?: boolean;
12
+ preprocess: boolean;
13
+ inputMapping?: InputMapping;
14
+ strategies: Strategy[];
15
+ uniforms: UniformDataType[];
16
+ properties?: NodeProperty[];
17
+ hardCodedProperties?: Record<string, any>;
18
+ };
19
+ export interface NodeProperty {
20
+ displayName: string;
21
+ type: GraphDataType;
22
+ property: string;
23
+ fillerName?: string;
24
+ defaultValue?: any;
25
+ }
26
+ export declare const property: (displayName: string, property: string, type: GraphDataType, fillerName?: string, defaultValue?: any) => NodeProperty;
27
+ export declare enum SourceType {
28
+ SHADER_PROGRAM = "Shader Program",
29
+ EXPRESSION = "Expression",
30
+ FN_BODY_FRAGMENT = "Function Body Fragment"
31
+ }
32
+ export interface CodeNode extends BaseNode {
33
+ config: NodeConfig;
34
+ engine: boolean;
35
+ source: string;
36
+ sourceType?: SourceType;
37
+ stage?: ShaderStage;
38
+ biStage?: boolean;
39
+ originalEngine?: string;
40
+ }
41
+ export interface BinaryNode extends CodeNode {
42
+ operator: string;
43
+ }
44
+ export type SourceNode = BinaryNode | CodeNode;
@@ -0,0 +1,18 @@
1
+ export var mapInputName = function (node, _a) {
2
+ var _b, _c;
3
+ var id = _a.id, displayName = _a.displayName;
4
+ return ((_c = (_b = node.config) === null || _b === void 0 ? void 0 : _b.inputMapping) === null || _c === void 0 ? void 0 : _c[id]) || displayName;
5
+ };
6
+ export var property = function (displayName, property, type, fillerName, defaultValue) { return ({
7
+ displayName: displayName,
8
+ type: type,
9
+ property: property,
10
+ fillerName: fillerName,
11
+ defaultValue: defaultValue,
12
+ }); };
13
+ export var SourceType;
14
+ (function (SourceType) {
15
+ SourceType["SHADER_PROGRAM"] = "Shader Program";
16
+ SourceType["EXPRESSION"] = "Expression";
17
+ SourceType["FN_BODY_FRAGMENT"] = "Function Body Fragment";
18
+ })(SourceType || (SourceType = {}));
@@ -0,0 +1,37 @@
1
+ import type { GlslSyntaxError } from '@shaderfrog/glsl-parser';
2
+ import { AstNode, Program } from '@shaderfrog/glsl-parser/ast';
3
+ import { Engine, EngineContext } from '../engine';
4
+ import { NodeInput } from './base-node';
5
+ import { Graph, GraphNode } from './graph-types';
6
+ import { InputFillers } from './parsers';
7
+ /**
8
+ * A node's context is the runtime / in-memory computed data associated with a
9
+ * graph node. It includes the parsed AST representation of the node, as well as
10
+ * the inputs found in that AST. It's not currently saved to the database.
11
+ */
12
+ export type NodeContext = {
13
+ id?: string;
14
+ name?: string;
15
+ source?: string;
16
+ ast: AstNode | Program;
17
+ inputs?: NodeInput[];
18
+ inputFillers: InputFillers;
19
+ errors?: NodeErrors;
20
+ };
21
+ export type NodeErrors = {
22
+ type: 'errors';
23
+ nodeId: string;
24
+ errors: (GlslSyntaxError | string)[];
25
+ };
26
+ export declare const isError: (test: any) => test is NodeErrors;
27
+ export declare const computeContextForNodes: (engineContext: EngineContext, engine: Engine, graph: Graph, nodes: GraphNode[]) => Promise<NodeErrors | Record<string, NodeContext>>;
28
+ /**
29
+ * Compute the context for every node in the graph, done on initial graph load
30
+ * to compute the inputs/outputs for every node
31
+ */
32
+ export declare const computeAllContexts: (engineContext: EngineContext, engine: Engine, graph: Graph) => Promise<NodeErrors>;
33
+ /**
34
+ * Compute the contexts for nodes starting from the outputs, working backwards.
35
+ * Used to only (re)-compute context for any actively used nodes
36
+ */
37
+ export declare const computeGraphContext: (engineContext: EngineContext, engine: Engine, graph: Graph) => Promise<NodeErrors>;
@@ -0,0 +1,243 @@
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 __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
13
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
14
+ return new (P || (P = Promise))(function (resolve, reject) {
15
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
16
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
17
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
18
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
19
+ });
20
+ };
21
+ var __generator = (this && this.__generator) || function (thisArg, body) {
22
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
23
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
24
+ function verb(n) { return function (v) { return step([n, v]); }; }
25
+ function step(op) {
26
+ if (f) throw new TypeError("Generator is already executing.");
27
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
28
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
29
+ if (y = 0, t) op = [op[0] & 2, t.value];
30
+ switch (op[0]) {
31
+ case 0: case 1: t = op; break;
32
+ case 4: _.label++; return { value: op[1], done: false };
33
+ case 5: _.label++; y = op[1]; op = [0]; continue;
34
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
35
+ default:
36
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
37
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
38
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
39
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
40
+ if (t[2]) _.ops.pop();
41
+ _.trys.pop(); continue;
42
+ }
43
+ op = body.call(thisArg, _);
44
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
45
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
46
+ }
47
+ };
48
+ var __read = (this && this.__read) || function (o, n) {
49
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
50
+ if (!m) return o;
51
+ var i = m.call(o), r, ar = [], e;
52
+ try {
53
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
54
+ }
55
+ catch (error) { e = { error: error }; }
56
+ finally {
57
+ try {
58
+ if (r && !r.done && (m = i["return"])) m.call(i);
59
+ }
60
+ finally { if (e) throw e.error; }
61
+ }
62
+ return ar;
63
+ };
64
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
65
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
66
+ if (ar || !(i in from)) {
67
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
68
+ ar[i] = from[i];
69
+ }
70
+ }
71
+ return to.concat(ar || Array.prototype.slice.call(from));
72
+ };
73
+ import groupBy from 'lodash.groupby';
74
+ import { mapInputName, SourceType } from './code-nodes';
75
+ import { NodeType } from './graph-types';
76
+ import { collectConnectedNodes, filterGraphFromNode, findLinkedNode, findLinkedVertexNodes, isSourceNode, mangleEntireProgram, } from './graph';
77
+ import { coreParsers } from './parsers';
78
+ var makeError = function (nodeId) {
79
+ var errors = [];
80
+ for (var _i = 1; _i < arguments.length; _i++) {
81
+ errors[_i - 1] = arguments[_i];
82
+ }
83
+ return ({
84
+ type: 'errors',
85
+ nodeId: nodeId,
86
+ errors: errors,
87
+ });
88
+ };
89
+ export var isError = function (test) {
90
+ return (test === null || test === void 0 ? void 0 : test.type) === 'errors';
91
+ };
92
+ // Merge existing node inputs, and inputs based on properties, with new ones
93
+ // found from the source code, using the *id* as the uniqueness key. Any filler input gets
94
+ // merged into property inputs with the same id. This preserves the
95
+ // "baked" property on node inputs which is toggle-able in the graph
96
+ var collapseNodeInputs = function (node, updatedInputs) {
97
+ 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)); }); });
98
+ };
99
+ var computeNodeContext = function (engineContext, engine, graph, node) { return __awaiter(void 0, void 0, void 0, function () {
100
+ var parser, sibling, onBeforeCompile, manipulateAst, inputEdges, ast, dataInputs, computedInputs, nodeContext;
101
+ return __generator(this, function (_a) {
102
+ switch (_a.label) {
103
+ case 0:
104
+ parser = __assign(__assign({}, (coreParsers[node.type] || coreParsers[NodeType.SOURCE])), (engine.parsers[node.type] || {}));
105
+ sibling = findLinkedNode(graph, node.id);
106
+ onBeforeCompile = parser.onBeforeCompile, manipulateAst = parser.manipulateAst;
107
+ if (!onBeforeCompile) return [3 /*break*/, 2];
108
+ return [4 /*yield*/, onBeforeCompile(graph, engineContext, node, sibling)];
109
+ case 1:
110
+ _a.sent();
111
+ _a.label = 2;
112
+ case 2:
113
+ inputEdges = graph.edges.filter(function (edge) { return edge.to === node.id; });
114
+ try {
115
+ ast = parser.produceAst(engineContext, engine, graph, node, inputEdges);
116
+ if (manipulateAst) {
117
+ ast = manipulateAst(engineContext, engine, graph, ast, inputEdges, node, sibling);
118
+ }
119
+ }
120
+ catch (error) {
121
+ console.error('Error parsing source code!', { error: error, node: node });
122
+ return [2 /*return*/, makeError(node.id, error)];
123
+ }
124
+ dataInputs = groupBy(filterGraphFromNode(graph, node, {
125
+ input: function (input, b, c, fromNode) {
126
+ return input.bakeable && (fromNode === null || fromNode === void 0 ? void 0 : fromNode.type) === 'source';
127
+ },
128
+ }, 1).inputs[node.id] || [], 'id');
129
+ computedInputs = parser.findInputs(engineContext, ast, inputEdges, node, sibling);
130
+ node.inputs = collapseNodeInputs(node, computedInputs.map(function (_a) {
131
+ var _b = __read(_a, 1), i = _b[0];
132
+ return (__assign(__assign({}, i), { displayName: mapInputName(node, i) }));
133
+ })).map(function (input) { return (__assign(__assign({}, input), (input.id in dataInputs ? { baked: true } : {}))); });
134
+ nodeContext = {
135
+ ast: ast,
136
+ id: node.id,
137
+ inputFillers: computedInputs.reduce(function (acc, _a) {
138
+ var _b;
139
+ var _c = __read(_a, 3), input = _c[0], filler = _c[1], args = _c[2];
140
+ return (__assign(__assign({}, acc), (_b = {}, _b[input.id] = {
141
+ filler: filler,
142
+ args: args,
143
+ }, _b)));
144
+ }, {}),
145
+ };
146
+ // Skip mangling if the node tells us to, which probably means it's an engine
147
+ // node where we don't care about renaming all the variables, or if it's
148
+ // an expression, where we want to be in the context of other variables
149
+ // TODO: Use global undefined engine variables here?
150
+ if (node.config.mangle !== false &&
151
+ node.sourceType !== SourceType.EXPRESSION &&
152
+ node.sourceType !== SourceType.FN_BODY_FRAGMENT) {
153
+ mangleEntireProgram(engine, ast, node, findLinkedNode(graph, node.id));
154
+ }
155
+ return [2 /*return*/, nodeContext];
156
+ }
157
+ });
158
+ }); };
159
+ export var computeContextForNodes = function (engineContext, engine, graph, nodes) { return __awaiter(void 0, void 0, void 0, function () {
160
+ return __generator(this, function (_a) {
161
+ return [2 /*return*/, nodes
162
+ .filter(isSourceNode)
163
+ .reduce(function (ctx, node) { return __awaiter(void 0, void 0, void 0, function () {
164
+ var context, nodeContextOrError;
165
+ return __generator(this, function (_a) {
166
+ switch (_a.label) {
167
+ case 0: return [4 /*yield*/, ctx];
168
+ case 1:
169
+ context = _a.sent();
170
+ if (isError(context)) {
171
+ return [2 /*return*/, context];
172
+ }
173
+ return [4 /*yield*/, computeNodeContext(engineContext, engine, graph, node)];
174
+ case 2:
175
+ nodeContextOrError = _a.sent();
176
+ if (isError(nodeContextOrError)) {
177
+ return [2 /*return*/, nodeContextOrError];
178
+ }
179
+ context[node.id] = __assign(__assign({}, (context[node.id] || {})), nodeContextOrError);
180
+ return [2 /*return*/, context];
181
+ }
182
+ });
183
+ }); }, Promise.resolve(engineContext.nodes))];
184
+ });
185
+ }); };
186
+ /**
187
+ * Compute the context for every node in the graph, done on initial graph load
188
+ * to compute the inputs/outputs for every node
189
+ */
190
+ export var computeAllContexts = function (engineContext, engine, graph) { return __awaiter(void 0, void 0, void 0, function () {
191
+ var result;
192
+ return __generator(this, function (_a) {
193
+ switch (_a.label) {
194
+ case 0: return [4 /*yield*/, computeContextForNodes(engineContext, engine, graph, graph.nodes)];
195
+ case 1:
196
+ result = _a.sent();
197
+ if (isError(result)) {
198
+ return [2 /*return*/, result];
199
+ }
200
+ return [2 /*return*/];
201
+ }
202
+ });
203
+ }); };
204
+ /**
205
+ * Compute the contexts for nodes starting from the outputs, working backwards.
206
+ * Used to only (re)-compute context for any actively used nodes
207
+ */
208
+ export var computeGraphContext = function (engineContext, engine, graph) { return __awaiter(void 0, void 0, void 0, function () {
209
+ var outputFrag, outputVert, vertexIds, fragmentIds, unlinkedNodes, vertNodesOrError, fragNodesOrError;
210
+ return __generator(this, function (_a) {
211
+ switch (_a.label) {
212
+ case 0:
213
+ outputFrag = graph.nodes.find(function (node) { return node.type === 'output' && node.stage === 'fragment'; });
214
+ if (!outputFrag) {
215
+ throw new Error('No fragment output in graph');
216
+ }
217
+ outputVert = graph.nodes.find(function (node) { return node.type === 'output' && node.stage === 'vertex'; });
218
+ if (!outputVert) {
219
+ throw new Error('No vertex output in graph');
220
+ }
221
+ vertexIds = collectConnectedNodes(graph, outputVert);
222
+ fragmentIds = collectConnectedNodes(graph, outputFrag);
223
+ unlinkedNodes = findLinkedVertexNodes(graph, vertexIds);
224
+ return [4 /*yield*/, computeContextForNodes(engineContext, engine, graph, __spreadArray(__spreadArray([
225
+ outputVert
226
+ ], __read(Object.values(vertexIds).filter(function (node) { return node.id !== outputVert.id; })), false), __read(unlinkedNodes), false))];
227
+ case 1:
228
+ vertNodesOrError = _a.sent();
229
+ if (isError(vertNodesOrError)) {
230
+ return [2 /*return*/, vertNodesOrError];
231
+ }
232
+ return [4 /*yield*/, computeContextForNodes(engineContext, engine, graph, __spreadArray([
233
+ outputFrag
234
+ ], __read(Object.values(fragmentIds).filter(function (node) { return node.id !== outputFrag.id; })), false))];
235
+ case 2:
236
+ fragNodesOrError = _a.sent();
237
+ if (isError(fragNodesOrError)) {
238
+ return [2 /*return*/, fragNodesOrError];
239
+ }
240
+ return [2 /*return*/];
241
+ }
242
+ });
243
+ }); };