@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.
- package/README.md +2 -2
- package/engine.d.ts +39 -3
- package/engine.js +5 -0
- package/graph/code-nodes.d.ts +8 -2
- package/graph/code-nodes.js +5 -1
- package/graph/context.d.ts +8 -6
- package/graph/context.js +53 -50
- package/graph/data-nodes.d.ts +15 -6
- package/graph/data-nodes.js +1 -1
- package/graph/evaluate.js +7 -0
- package/graph/graph-types.d.ts +26 -6
- package/graph/graph-types.js +69 -0
- package/graph/graph.d.ts +35 -4
- package/graph/graph.js +187 -143
- package/graph/graph.test.js +244 -54
- package/graph/parsers.d.ts +4 -12
- package/graph/parsers.js +32 -18
- package/graph/shader-sections.d.ts +31 -14
- package/graph/shader-sections.js +93 -19
- package/package.json +4 -4
- package/plugins/babylon/bablyengine.js +9 -10
- package/plugins/playcanvas/playengine.js +9 -10
- package/plugins/three/importers.d.ts +1 -0
- package/plugins/three/importers.js +49 -1
- package/plugins/three/threngine.d.ts +6 -4
- package/plugins/three/threngine.js +59 -39
- package/plugins/three/threngine.test.js +51 -4
- package/strategy/assignmentTo.d.ts +10 -0
- package/strategy/assignmentTo.js +35 -0
- package/strategy/declarationOf.js +2 -2
- package/strategy/hardCode.js +1 -4
- package/strategy/index.d.ts +1 -1
- package/strategy/index.js +1 -1
- package/strategy/inject.js +3 -4
- package/strategy/namedAttribute.js +2 -2
- package/strategy/strategy.d.ts +30 -5
- package/strategy/strategy.js +1 -1
- package/strategy/stratgies.test.js +59 -31
- package/strategy/texture2D.js +20 -22
- package/strategy/uniform.js +54 -56
- package/strategy/variable.js +5 -5
- package/util/ast.d.ts +9 -4
- package/util/ast.js +37 -8
- package/util/ast.test.d.ts +1 -0
- package/util/ast.test.js +14 -0
- package/util/indexByid.d.ts +4 -0
- package/util/indexByid.js +18 -0
- package/util/whitespace.d.ts +2 -0
- package/util/whitespace.js +22 -3
package/README.md
CHANGED
|
@@ -119,9 +119,9 @@ export interface Engine {
|
|
|
119
119
|
|
|
120
120
|
Shaderfrog works by searching each node's AST for certain patterns, like
|
|
121
121
|
`uniform` variables, and creating an interface where you can replace each
|
|
122
|
-
`uniform` variable with the output of another node.
|
|
122
|
+
`uniform` variable with the output of another node.
|
|
123
123
|
|
|
124
|
-
Each fillable part of the AST is called a
|
|
124
|
+
Each fillable part of the AST is called a **hole**. Holes are found by executing
|
|
125
125
|
user defined _strategies_ against an AST. With a program such as:
|
|
126
126
|
|
|
127
127
|
```glsl
|
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;
|
|
@@ -47,6 +82,7 @@ export type EngineImporter = {
|
|
|
47
82
|
edgeMap: {
|
|
48
83
|
[oldInput: string]: string;
|
|
49
84
|
};
|
|
85
|
+
code?: Record<string, string>;
|
|
50
86
|
};
|
|
51
87
|
export type EngineImporters = {
|
|
52
88
|
[engine: string]: EngineImporter;
|
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, ")"));
|
package/graph/code-nodes.d.ts
CHANGED
|
@@ -26,17 +26,23 @@ export interface NodeProperty {
|
|
|
26
26
|
export declare const property: (displayName: string, property: string, type: GraphDataType, fillerName?: string, defaultValue?: any) => NodeProperty;
|
|
27
27
|
export declare enum SourceType {
|
|
28
28
|
SHADER_PROGRAM = "Shader Program",
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
FN_BODY_FRAGMENT = "Function Body Fragment",
|
|
30
|
+
EXPRESSION = "Expression"
|
|
31
31
|
}
|
|
32
|
+
export type Backfillers = Record<string, {
|
|
33
|
+
argType: string;
|
|
34
|
+
targetVariable: string;
|
|
35
|
+
}[]>;
|
|
32
36
|
export interface CodeNode extends BaseNode {
|
|
33
37
|
config: NodeConfig;
|
|
38
|
+
type: string;
|
|
34
39
|
engine: boolean;
|
|
35
40
|
source: string;
|
|
36
41
|
sourceType?: SourceType;
|
|
37
42
|
stage?: ShaderStage;
|
|
38
43
|
biStage?: boolean;
|
|
39
44
|
originalEngine?: string;
|
|
45
|
+
backfillers?: Backfillers;
|
|
40
46
|
}
|
|
41
47
|
export interface BinaryNode extends CodeNode {
|
|
42
48
|
operator: string;
|
package/graph/code-nodes.js
CHANGED
|
@@ -13,6 +13,10 @@ export var property = function (displayName, property, type, fillerName, default
|
|
|
13
13
|
export var SourceType;
|
|
14
14
|
(function (SourceType) {
|
|
15
15
|
SourceType["SHADER_PROGRAM"] = "Shader Program";
|
|
16
|
-
|
|
16
|
+
// Function body fragments are parsed, and parsed differently than shader
|
|
17
|
+
// programs. This confuses me all the time. TODO: Remove fn_body_framgent
|
|
18
|
+
// and just try/catch parsing a program, then try fn body fragment?
|
|
17
19
|
SourceType["FN_BODY_FRAGMENT"] = "Function Body Fragment";
|
|
20
|
+
// Expressions are inlined as is
|
|
21
|
+
SourceType["EXPRESSION"] = "Expression";
|
|
18
22
|
})(SourceType || (SourceType = {}));
|
package/graph/context.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { type GlslSyntaxError } from '@shaderfrog/glsl-parser';
|
|
2
|
-
import { AstNode, Program } from '@shaderfrog/glsl-parser/ast';
|
|
2
|
+
import { AstNode, FunctionNode, Program } from '@shaderfrog/glsl-parser/ast';
|
|
3
3
|
import { Engine, EngineContext } from '../engine';
|
|
4
4
|
import { NodeInput } from './base-node';
|
|
5
5
|
import { Graph, GraphNode } from './graph-types';
|
|
6
|
-
import { InputFillers } from '
|
|
6
|
+
import { InputFillers } from '../strategy';
|
|
7
7
|
/**
|
|
8
8
|
* A node's context is the runtime / in-memory computed data associated with a
|
|
9
9
|
* graph node. It includes the parsed AST representation of the node, as well as
|
|
@@ -12,26 +12,28 @@ import { InputFillers } from './parsers';
|
|
|
12
12
|
export type NodeContext = {
|
|
13
13
|
id?: string;
|
|
14
14
|
name?: string;
|
|
15
|
-
|
|
15
|
+
computedSource?: string;
|
|
16
16
|
ast: AstNode | Program;
|
|
17
17
|
inputs?: NodeInput[];
|
|
18
18
|
inputFillers: InputFillers;
|
|
19
19
|
errors?: NodeErrors;
|
|
20
|
+
mainFn?: FunctionNode;
|
|
20
21
|
};
|
|
22
|
+
export type NodeContexts = Record<string, NodeContext>;
|
|
21
23
|
export type NodeErrors = {
|
|
22
24
|
type: 'errors';
|
|
23
25
|
nodeId: string;
|
|
24
26
|
errors: (GlslSyntaxError | string)[];
|
|
25
27
|
};
|
|
26
28
|
export declare const isError: (test: any) => test is NodeErrors;
|
|
27
|
-
export declare const computeContextForNodes: (engineContext: EngineContext, engine: Engine, graph: Graph, nodes: GraphNode[]) => Promise<NodeErrors |
|
|
29
|
+
export declare const computeContextForNodes: (engineContext: EngineContext, engine: Engine, graph: Graph, nodes: GraphNode[]) => Promise<NodeErrors | NodeContexts>;
|
|
28
30
|
/**
|
|
29
31
|
* Compute the context for every node in the graph, done on initial graph load
|
|
30
32
|
* to compute the inputs/outputs for every node
|
|
31
33
|
*/
|
|
32
|
-
export declare const computeAllContexts: (engineContext: EngineContext, engine: Engine, graph: Graph) => Promise<NodeErrors |
|
|
34
|
+
export declare const computeAllContexts: (engineContext: EngineContext, engine: Engine, graph: Graph) => Promise<NodeErrors | NodeContexts>;
|
|
33
35
|
/**
|
|
34
36
|
* Compute the contexts for nodes starting from the outputs, working backwards.
|
|
35
37
|
* Used to only (re)-compute context for any actively used nodes
|
|
36
38
|
*/
|
|
37
|
-
export declare const computeGraphContext: (engineContext: EngineContext, engine: Engine, graph: Graph) => Promise<NodeErrors |
|
|
39
|
+
export declare const computeGraphContext: (engineContext: EngineContext, engine: Engine, graph: Graph) => Promise<NodeErrors | NodeContexts>;
|
package/graph/context.js
CHANGED
|
@@ -71,10 +71,12 @@ 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
|
-
import { collectConnectedNodes, filterGraphFromNode, findLinkedNode, findLinkedVertexNodes, isSourceNode, mangleEntireProgram, } from './graph';
|
|
77
|
+
import { collectConnectedNodes, filterGraphFromNode, findLinkedNode, findLinkedVertexNodes, isSourceNode, mangleEntireProgram, shouldNodeHaveMainFn, } from './graph';
|
|
77
78
|
import { coreParsers } from './parsers';
|
|
79
|
+
import { findMain } from '../util/ast';
|
|
78
80
|
var makeError = function (nodeId) {
|
|
79
81
|
var errors = [];
|
|
80
82
|
for (var _i = 1; _i < arguments.length; _i++) {
|
|
@@ -97,24 +99,32 @@ var collapseNodeInputs = function (node, updatedInputs) {
|
|
|
97
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)); }); });
|
|
98
100
|
};
|
|
99
101
|
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;
|
|
102
|
+
var parser, sibling, onBeforeCompile, manipulateAst, updatedNodeContext, updatedContext, inputEdges, mainFn, ast, dataInputs, computedInputs, nodeContext;
|
|
101
103
|
return __generator(this, function (_a) {
|
|
102
104
|
switch (_a.label) {
|
|
103
105
|
case 0:
|
|
104
106
|
parser = __assign(__assign({}, (coreParsers[node.type] || coreParsers[NodeType.SOURCE])), (engine.parsers[node.type] || {}));
|
|
105
107
|
sibling = findLinkedNode(graph, node.id);
|
|
106
108
|
onBeforeCompile = parser.onBeforeCompile, manipulateAst = parser.manipulateAst;
|
|
109
|
+
updatedContext = engineContext;
|
|
107
110
|
if (!onBeforeCompile) return [3 /*break*/, 2];
|
|
108
111
|
return [4 /*yield*/, onBeforeCompile(graph, engineContext, node, sibling)];
|
|
109
112
|
case 1:
|
|
110
|
-
_a.sent();
|
|
113
|
+
updatedNodeContext = _a.sent();
|
|
114
|
+
if (updatedNodeContext) {
|
|
115
|
+
updatedContext = extendNodeContext(engineContext, node.id, updatedNodeContext);
|
|
116
|
+
}
|
|
111
117
|
_a.label = 2;
|
|
112
118
|
case 2:
|
|
113
119
|
inputEdges = graph.edges.filter(function (edge) { return edge.to === node.id; });
|
|
114
120
|
try {
|
|
115
|
-
ast = parser.produceAst(
|
|
121
|
+
ast = parser.produceAst(updatedContext, engine, graph, node, inputEdges);
|
|
122
|
+
// Find the main function before mangling
|
|
123
|
+
if (shouldNodeHaveMainFn(node)) {
|
|
124
|
+
mainFn = findMain(ast);
|
|
125
|
+
}
|
|
116
126
|
if (manipulateAst) {
|
|
117
|
-
ast = manipulateAst(
|
|
127
|
+
ast = manipulateAst(updatedContext, engine, graph, ast, inputEdges, node, sibling);
|
|
118
128
|
}
|
|
119
129
|
}
|
|
120
130
|
catch (error) {
|
|
@@ -126,23 +136,11 @@ var computeNodeContext = function (engineContext, engine, graph, node) { return
|
|
|
126
136
|
return input.bakeable && (fromNode === null || fromNode === void 0 ? void 0 : fromNode.type) === 'source';
|
|
127
137
|
},
|
|
128
138
|
}, 1).inputs[node.id] || [], 'id');
|
|
129
|
-
computedInputs = parser.findInputs(
|
|
139
|
+
computedInputs = parser.findInputs(updatedContext, ast, inputEdges, node, sibling);
|
|
130
140
|
node.inputs = collapseNodeInputs(node, computedInputs.map(function (_a) {
|
|
131
141
|
var _b = __read(_a, 1), i = _b[0];
|
|
132
142
|
return (__assign(__assign({}, i), { displayName: mapInputName(node, i) }));
|
|
133
143
|
})).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
144
|
// Skip mangling if the node tells us to, which probably means it's an engine
|
|
147
145
|
// node where we don't care about renaming all the variables, or if it's
|
|
148
146
|
// an expression, where we want to be in the context of other variables
|
|
@@ -152,6 +150,20 @@ var computeNodeContext = function (engineContext, engine, graph, node) { return
|
|
|
152
150
|
node.sourceType !== SourceType.FN_BODY_FRAGMENT) {
|
|
153
151
|
mangleEntireProgram(engine, ast, node, findLinkedNode(graph, node.id));
|
|
154
152
|
}
|
|
153
|
+
nodeContext = __assign(__assign({}, (updatedNodeContext || {})), { ast: ast, id: node.id, mainFn: mainFn, inputFillers: computedInputs.reduce(function (acc, _a) {
|
|
154
|
+
var _b;
|
|
155
|
+
var _c = __read(_a, 4), input = _c[0], filler = _c[1], fillerArgs = _c[2], fillerStmt = _c[3];
|
|
156
|
+
// This is intentionally broken out into an explicit return to force
|
|
157
|
+
// this type declaration. Inlining the object in [input.id]: {...}
|
|
158
|
+
// doesn't force it to be an InputFillerGroup, and it can contain extra
|
|
159
|
+
// arguments by accident
|
|
160
|
+
var fillerGroup = {
|
|
161
|
+
filler: filler,
|
|
162
|
+
fillerArgs: fillerArgs,
|
|
163
|
+
fillerStmt: fillerStmt,
|
|
164
|
+
};
|
|
165
|
+
return __assign(__assign({}, acc), (_b = {}, _b[input.id] = fillerGroup, _b));
|
|
166
|
+
}, {}) });
|
|
155
167
|
return [2 /*return*/, nodeContext];
|
|
156
168
|
}
|
|
157
169
|
});
|
|
@@ -162,22 +174,22 @@ export var computeContextForNodes = function (engineContext, engine, graph, node
|
|
|
162
174
|
.filter(isSourceNode)
|
|
163
175
|
.reduce(function (ctx, node) { return __awaiter(void 0, void 0, void 0, function () {
|
|
164
176
|
var context, nodeContextOrError;
|
|
165
|
-
|
|
166
|
-
|
|
177
|
+
var _a;
|
|
178
|
+
return __generator(this, function (_b) {
|
|
179
|
+
switch (_b.label) {
|
|
167
180
|
case 0: return [4 /*yield*/, ctx];
|
|
168
181
|
case 1:
|
|
169
|
-
context =
|
|
182
|
+
context = _b.sent();
|
|
170
183
|
if (isError(context)) {
|
|
171
184
|
return [2 /*return*/, context];
|
|
172
185
|
}
|
|
173
186
|
return [4 /*yield*/, computeNodeContext(engineContext, engine, graph, node)];
|
|
174
187
|
case 2:
|
|
175
|
-
nodeContextOrError =
|
|
188
|
+
nodeContextOrError = _b.sent();
|
|
176
189
|
if (isError(nodeContextOrError)) {
|
|
177
190
|
return [2 /*return*/, nodeContextOrError];
|
|
178
191
|
}
|
|
179
|
-
context[node.id] = __assign(__assign({}, (context[node.id] || {})), nodeContextOrError);
|
|
180
|
-
return [2 /*return*/, context];
|
|
192
|
+
return [2 /*return*/, __assign(__assign({}, context), (_a = {}, _a[node.id] = __assign(__assign({}, (context[node.id] || {})), nodeContextOrError), _a))];
|
|
181
193
|
}
|
|
182
194
|
});
|
|
183
195
|
}); }, Promise.resolve(engineContext.nodes))];
|
|
@@ -187,26 +199,18 @@ export var computeContextForNodes = function (engineContext, engine, graph, node
|
|
|
187
199
|
* Compute the context for every node in the graph, done on initial graph load
|
|
188
200
|
* to compute the inputs/outputs for every node
|
|
189
201
|
*/
|
|
190
|
-
export var computeAllContexts = function (engineContext, engine, graph) { return __awaiter(void 0, void 0, void 0, function () {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
result = _a.sent();
|
|
197
|
-
if (isError(result)) {
|
|
198
|
-
return [2 /*return*/, result];
|
|
199
|
-
}
|
|
200
|
-
return [2 /*return*/];
|
|
201
|
-
}
|
|
202
|
-
});
|
|
203
|
-
}); };
|
|
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
|
+
}); }); };
|
|
204
208
|
/**
|
|
205
209
|
* Compute the contexts for nodes starting from the outputs, working backwards.
|
|
206
210
|
* Used to only (re)-compute context for any actively used nodes
|
|
207
211
|
*/
|
|
208
212
|
export var computeGraphContext = function (engineContext, engine, graph) { return __awaiter(void 0, void 0, void 0, function () {
|
|
209
|
-
var outputFrag, outputVert,
|
|
213
|
+
var outputFrag, outputVert, vertexes, fragments, vertexIds, unlinkedNodes, vertNodesOrError, updatedContext, finalNodeContextOrError;
|
|
210
214
|
return __generator(this, function (_a) {
|
|
211
215
|
switch (_a.label) {
|
|
212
216
|
case 0:
|
|
@@ -218,26 +222,25 @@ export var computeGraphContext = function (engineContext, engine, graph) { retur
|
|
|
218
222
|
if (!outputVert) {
|
|
219
223
|
throw new Error('No vertex output in graph');
|
|
220
224
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
225
|
+
vertexes = collectConnectedNodes(graph, outputVert);
|
|
226
|
+
fragments = collectConnectedNodes(graph, outputFrag);
|
|
227
|
+
vertexIds = new Set(Object.keys(vertexes));
|
|
228
|
+
unlinkedNodes = findLinkedVertexNodes(graph, vertexes);
|
|
224
229
|
return [4 /*yield*/, computeContextForNodes(engineContext, engine, graph, __spreadArray(__spreadArray([
|
|
225
230
|
outputVert
|
|
226
|
-
], __read(Object.values(
|
|
231
|
+
], __read(Object.values(vertexes).filter(function (node) { return node.id !== outputVert.id; })), false), __read(unlinkedNodes), false))];
|
|
227
232
|
case 1:
|
|
228
233
|
vertNodesOrError = _a.sent();
|
|
229
234
|
if (isError(vertNodesOrError)) {
|
|
230
235
|
return [2 /*return*/, vertNodesOrError];
|
|
231
236
|
}
|
|
232
|
-
|
|
237
|
+
updatedContext = extendNodesContext(engineContext, vertNodesOrError);
|
|
238
|
+
return [4 /*yield*/, computeContextForNodes(updatedContext, engine, graph, __spreadArray([
|
|
233
239
|
outputFrag
|
|
234
|
-
], __read(Object.values(
|
|
240
|
+
], __read(Object.values(fragments).filter(function (node) { return node.id !== outputFrag.id && !vertexIds.has(node.id); })), false))];
|
|
235
241
|
case 2:
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
return [2 /*return*/, fragNodesOrError];
|
|
239
|
-
}
|
|
240
|
-
return [2 /*return*/];
|
|
242
|
+
finalNodeContextOrError = _a.sent();
|
|
243
|
+
return [2 /*return*/, finalNodeContextOrError];
|
|
241
244
|
}
|
|
242
245
|
});
|
|
243
246
|
}); };
|
package/graph/data-nodes.d.ts
CHANGED
|
@@ -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
|
|
24
|
-
assetId
|
|
25
|
-
versionId
|
|
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?:
|
|
38
|
+
value?: TextureNodeValueData;
|
|
30
39
|
}
|
|
31
|
-
export declare const textureNode: (id: string, name: string, position: NodePosition, value
|
|
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:
|
|
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;
|
package/graph/data-nodes.js
CHANGED
|
@@ -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
|
{
|
package/graph/evaluate.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { coreParsers } from './parsers';
|
|
2
2
|
export var toGlsl = function (node) {
|
|
3
3
|
var type = node.type, value = node.value;
|
|
4
|
+
if (type === 'number') {
|
|
5
|
+
return value;
|
|
6
|
+
}
|
|
4
7
|
if (type === 'vector2') {
|
|
5
8
|
return "vec2(".concat(value[0], ", ").concat(value[1], ")");
|
|
6
9
|
}
|
|
@@ -10,6 +13,10 @@ export var toGlsl = function (node) {
|
|
|
10
13
|
if (type === 'vector4' || type === 'rgba') {
|
|
11
14
|
return "vec4(".concat(value[0], ", ").concat(value[1], ", ").concat(value[2], ", ").concat(value[3], ")");
|
|
12
15
|
}
|
|
16
|
+
// Right now hard coding that an array is floats. Need type from node later.
|
|
17
|
+
if (type === 'array') {
|
|
18
|
+
return "float[".concat(value.length, "](").concat(value.join(', '), ")");
|
|
19
|
+
}
|
|
13
20
|
throw new Error("Unknown GLSL inline type: \"".concat(node.type, "\""));
|
|
14
21
|
};
|
|
15
22
|
export var evaluateNode = function (engine, graph, node) {
|
package/graph/graph-types.d.ts
CHANGED
|
@@ -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
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
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";
|
package/graph/graph-types.js
CHANGED
|
@@ -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';
|
|
@@ -11,16 +11,45 @@ import { ProduceNodeFiller } from './parsers';
|
|
|
11
11
|
import { Graph, GraphNode } from './graph-types';
|
|
12
12
|
export declare const isDataNode: (node: GraphNode) => node is DataNode;
|
|
13
13
|
export declare const isSourceNode: (node: GraphNode) => node is SourceNode;
|
|
14
|
+
/**
|
|
15
|
+
* Determine if a node's source code / AST should have a main function. Essentially
|
|
16
|
+
* check if the source code is a full program or not.
|
|
17
|
+
*/
|
|
18
|
+
export declare const shouldNodeHaveMainFn: (node: GraphNode) => node is SourceNode;
|
|
14
19
|
export declare const findNode: (graph: Graph, id: string) => GraphNode;
|
|
15
20
|
export declare const doesLinkThruShader: (graph: Graph, node: GraphNode) => boolean;
|
|
16
21
|
export declare const nodeName: (node: GraphNode) => string;
|
|
22
|
+
export declare const resultName: (node: GraphNode) => string;
|
|
17
23
|
export declare const mangleName: (name: string, node: GraphNode, nextSibling?: GraphNode) => string;
|
|
18
24
|
export declare const mangleVar: (name: string, engine: Engine, node: GraphNode, sibling?: GraphNode) => string;
|
|
19
25
|
export declare const mangleEntireProgram: (engine: Engine, ast: FrogProgram, node: GraphNode, sibling?: GraphNode) => void;
|
|
20
26
|
export declare const mangleMainFn: (ast: Program, node: GraphNode, sibling?: GraphNode) => void;
|
|
21
|
-
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 |
|
|
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;
|
|
22
28
|
export declare const resetGraphIds: (graph: Graph) => Graph;
|
|
23
|
-
|
|
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;
|
|
24
53
|
/**
|
|
25
54
|
* Find any unconnected vertex nodes linked to collected fragment nodes
|
|
26
55
|
*/
|
|
@@ -33,7 +62,7 @@ export type Predicates = {
|
|
|
33
62
|
export type SearchResult = {
|
|
34
63
|
nodes: Record<string, GraphNode>;
|
|
35
64
|
inputs: Record<string, NodeInput[]>;
|
|
36
|
-
edges: Edge
|
|
65
|
+
edges: Record<string, Edge>;
|
|
37
66
|
};
|
|
38
67
|
export declare const consSearchResult: () => SearchResult;
|
|
39
68
|
export declare const mergeSearchResults: (a: SearchResult, b: SearchResult) => SearchResult;
|
|
@@ -80,11 +109,13 @@ export declare const compileGraph: (engineContext: EngineContext, engine: Engine
|
|
|
80
109
|
export declare const collectNodeProperties: (graph: Graph) => SearchResult;
|
|
81
110
|
export type IndexedDataInputs = Record<string, NodeInput[]>;
|
|
82
111
|
export type CompileResult = {
|
|
112
|
+
updatedNodeContext: NodeContexts;
|
|
83
113
|
fragmentResult: string;
|
|
84
114
|
vertexResult: string;
|
|
85
115
|
compileResult: CompileGraphResult;
|
|
86
116
|
dataNodes: Record<string, GraphNode>;
|
|
87
117
|
dataInputs: IndexedDataInputs;
|
|
118
|
+
compileMs: string;
|
|
88
119
|
};
|
|
89
120
|
export declare const compileSource: (graph: Graph, engine: Engine, ctx: EngineContext) => Promise<CompileResult | NodeErrors>;
|
|
90
121
|
export {};
|