@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
|
@@ -20,6 +20,8 @@ import { generate } from '@shaderfrog/glsl-parser';
|
|
|
20
20
|
import { applyStrategy, StrategyType } from '.';
|
|
21
21
|
import { makeExpression } from '../util/ast';
|
|
22
22
|
import preprocess from '@shaderfrog/glsl-parser/preprocessor';
|
|
23
|
+
import { NodeType } from '../graph/graph-types';
|
|
24
|
+
import { mangleEntireProgram } from '../graph';
|
|
23
25
|
it('named attribute strategy`', function () {
|
|
24
26
|
var source = "\nin vec3 replaceThisAtrribute;\nvoid main() {\n vec2 y = replaceThisAtrribute;\n}\n";
|
|
25
27
|
var ast = parser.parse(source, { quiet: true });
|
|
@@ -30,11 +32,11 @@ it('named attribute strategy`', function () {
|
|
|
30
32
|
},
|
|
31
33
|
}, ast, { source: source }, {});
|
|
32
34
|
expect(fillers.length).toBe(1);
|
|
33
|
-
fillers[0][1]({
|
|
35
|
+
fillers[0][1](function () { return ({
|
|
34
36
|
type: 'literal',
|
|
35
37
|
literal: "myFiller()",
|
|
36
38
|
whitespace: '',
|
|
37
|
-
});
|
|
39
|
+
}); });
|
|
38
40
|
var result = generate(ast);
|
|
39
41
|
// Should replace the use of the filler, but not the declaration
|
|
40
42
|
expect(result).toBe("\nin vec3 replaceThisAtrribute;\nvoid main() {\n vec2 y = myFiller();\n}\n");
|
|
@@ -51,11 +53,11 @@ it('inject strategy after', function () {
|
|
|
51
53
|
},
|
|
52
54
|
}, ast, { source: source }, {});
|
|
53
55
|
expect(fillers.length).toBe(1);
|
|
54
|
-
fillers[0][1]({
|
|
56
|
+
fillers[0][1](function () { return ({
|
|
55
57
|
type: 'literal',
|
|
56
58
|
literal: "someOtherCall(x, y, z);\nsomeOtherCall(x, y, z);",
|
|
57
59
|
whitespace: '',
|
|
58
|
-
});
|
|
60
|
+
}); });
|
|
59
61
|
var result = generate(ast);
|
|
60
62
|
// Should fill references
|
|
61
63
|
expect(result).toBe("\nuniform float x;\n// Some comment\nvoid main() {\n/* some comment */\nre(x, y, z);\nsomeOtherCall(x, y, z);\nsomeOtherCall(x, y, z);\n// Middle comment\nre(x, y, z);\nsomeOtherCall(x, y, z);\nsomeOtherCall(x, y, z);\n// Final comment\n}");
|
|
@@ -72,11 +74,11 @@ it('inject strategy before', function () {
|
|
|
72
74
|
},
|
|
73
75
|
}, ast, { source: source }, {});
|
|
74
76
|
expect(fillers.length).toBe(1);
|
|
75
|
-
fillers[0][1]({
|
|
77
|
+
fillers[0][1](function () { return ({
|
|
76
78
|
type: 'literal',
|
|
77
79
|
literal: "someOtherCall(x, y, z);\nsomeOtherCall(x, y, z);",
|
|
78
80
|
whitespace: '\n',
|
|
79
|
-
});
|
|
81
|
+
}); });
|
|
80
82
|
var result = generate(ast);
|
|
81
83
|
// Should fill references
|
|
82
84
|
expect(result).toBe("\nuniform float x;\n// Some comment\nvoid main() {\n/* some comment */\nsomeOtherCall(x, y, z);\nsomeOtherCall(x, y, z);\nre(x, y, z);\n// Middle comment\nsomeOtherCall(x, y, z);\nsomeOtherCall(x, y, z);\nre(x, y, z);\n// Final comment\n}");
|
|
@@ -91,7 +93,7 @@ var constructor = function () { return ({
|
|
|
91
93
|
id: '1',
|
|
92
94
|
name: '1',
|
|
93
95
|
engine: true,
|
|
94
|
-
type:
|
|
96
|
+
type: NodeType.SOURCE,
|
|
95
97
|
inputs: [],
|
|
96
98
|
outputs: [],
|
|
97
99
|
position: { x: 0, y: 0 },
|
|
@@ -122,25 +124,7 @@ var engine = {
|
|
|
122
124
|
it('correctly fills with uniform strategy', function () {
|
|
123
125
|
var _a, _b, _c;
|
|
124
126
|
var ast = parser.parse("\nlayout(std140,column_major) uniform;\nuniform sampler2D image;\nuniform vec4 input, output, other;\nuniform vec4 zenput;\nuniform Light0 { vec4 y; } x;\nvec3 topLevel = vec3(0.0);\nvoid other(in vec3 param) {}\nvoid main() {\n vec4 computed = texture2D(image, uvPow * 1.0);\n vec4 x = input;\n vec4 y = output;\n vec4 z = zenput;\n}", { quiet: true });
|
|
125
|
-
|
|
126
|
-
// avoid having to mangle in the strategy, in service of maybe mangling the
|
|
127
|
-
// AST as part of producing context. But as the test shows -
|
|
128
|
-
// mangleEntireProgram does NOT modify binding names
|
|
129
|
-
//
|
|
130
|
-
// You started updating binding names in the parser but realized that
|
|
131
|
-
// technically a mangler can produce different results for different nodes
|
|
132
|
-
// during the rename, since the parser takes in the node to mangle.
|
|
133
|
-
//
|
|
134
|
-
// which raised the question about why pass in the node at all to the mangler?
|
|
135
|
-
// looks like it's for "doNotDescope" hack to avoid renaming a specific
|
|
136
|
-
// varaible.
|
|
137
|
-
//
|
|
138
|
-
// But maybe that could be done here instead? And mangleEntireProgram could be
|
|
139
|
-
// aware of the output varaibles to ignore? Which means we need to track the
|
|
140
|
-
// output varialbe names somewhere... do we alredy?
|
|
141
|
-
var node = { name: 'fake', id: '1' };
|
|
142
|
-
// mangleEntireProgram(engine, ast, node);
|
|
143
|
-
var fillers = applyStrategy({ type: StrategyType.UNIFORM, config: {} }, ast, {}, {});
|
|
127
|
+
var fillers = applyStrategy({ type: StrategyType.UNIFORM, config: {} }, ast, {});
|
|
144
128
|
// It should find uniforms with simple types, excluding sampler2D
|
|
145
129
|
expect(fillers.map(function (_a) {
|
|
146
130
|
var _b = __read(_a, 1), name = _b[0].displayName;
|
|
@@ -155,15 +139,21 @@ it('correctly fills with uniform strategy', function () {
|
|
|
155
139
|
(_a = fillers.find(function (_a) {
|
|
156
140
|
var _b = __read(_a, 1), name = _b[0].displayName;
|
|
157
141
|
return name === 'input';
|
|
158
|
-
})) === null || _a === void 0 ? void 0 : _a[1](
|
|
142
|
+
})) === null || _a === void 0 ? void 0 : _a[1](function () {
|
|
143
|
+
return makeExpression('a');
|
|
144
|
+
});
|
|
159
145
|
(_b = fillers.find(function (_a) {
|
|
160
146
|
var _b = __read(_a, 1), name = _b[0].displayName;
|
|
161
147
|
return name === 'output';
|
|
162
|
-
})) === null || _b === void 0 ? void 0 : _b[1](
|
|
148
|
+
})) === null || _b === void 0 ? void 0 : _b[1](function () {
|
|
149
|
+
return makeExpression('b');
|
|
150
|
+
});
|
|
163
151
|
(_c = fillers.find(function (_a) {
|
|
164
152
|
var _b = __read(_a, 1), name = _b[0].displayName;
|
|
165
153
|
return name === 'zenput';
|
|
166
|
-
})) === null || _c === void 0 ? void 0 : _c[1](
|
|
154
|
+
})) === null || _c === void 0 ? void 0 : _c[1](function () {
|
|
155
|
+
return makeExpression('c');
|
|
156
|
+
});
|
|
167
157
|
var result = generate(ast);
|
|
168
158
|
// Should fill references
|
|
169
159
|
expect(result).toContain('vec4 x = a;');
|
|
@@ -178,6 +168,44 @@ it('correctly fills with uniform strategy', function () {
|
|
|
178
168
|
// Should remove uniform lines
|
|
179
169
|
expect(result).not.toContain('uniform vec4 zenput');
|
|
180
170
|
});
|
|
171
|
+
it('correctly fills with uniform strategy through mangling', function () {
|
|
172
|
+
var _a, _b, _c;
|
|
173
|
+
var ast = parser.parse("\nuniform sampler2D image;\nuniform vec4 input, output;\nvoid main() {\n vec4 computed = texture2D(image, uvPow * 1.0);\n vec4 x = input;\n vec4 y = output;\n}", { quiet: true });
|
|
174
|
+
var node = { id: '1', name: 'fake' };
|
|
175
|
+
var fillers = applyStrategy({ type: StrategyType.UNIFORM, config: {} }, ast, node);
|
|
176
|
+
mangleEntireProgram(engine, ast, node);
|
|
177
|
+
// It should find uniforms with simple types, excluding sampler2D
|
|
178
|
+
expect(fillers.map(function (_a) {
|
|
179
|
+
var _b = __read(_a, 1), name = _b[0].displayName;
|
|
180
|
+
return name;
|
|
181
|
+
})).toEqual([
|
|
182
|
+
'image',
|
|
183
|
+
'input',
|
|
184
|
+
'output',
|
|
185
|
+
]);
|
|
186
|
+
var a = (_a = fillers.find(function (_a) {
|
|
187
|
+
var _b = __read(_a, 1), name = _b[0].displayName;
|
|
188
|
+
return name === 'input';
|
|
189
|
+
})) === null || _a === void 0 ? void 0 : _a[1];
|
|
190
|
+
(_b = fillers.find(function (_a) {
|
|
191
|
+
var _b = __read(_a, 1), name = _b[0].displayName;
|
|
192
|
+
return name === 'input';
|
|
193
|
+
})) === null || _b === void 0 ? void 0 : _b[1](function () {
|
|
194
|
+
return makeExpression('a');
|
|
195
|
+
});
|
|
196
|
+
(_c = fillers.find(function (_a) {
|
|
197
|
+
var _b = __read(_a, 1), name = _b[0].displayName;
|
|
198
|
+
return name === 'output';
|
|
199
|
+
})) === null || _c === void 0 ? void 0 : _c[1](function () {
|
|
200
|
+
return makeExpression('b');
|
|
201
|
+
});
|
|
202
|
+
var result = generate(ast);
|
|
203
|
+
// Should fill references
|
|
204
|
+
expect(result).toContain('vec4 x = a;');
|
|
205
|
+
expect(result).toContain('vec4 y = b;');
|
|
206
|
+
// Should preserve things it shouldn't touch
|
|
207
|
+
expect(result).toContain("uniform sampler2D image_".concat(node.id, ";"));
|
|
208
|
+
});
|
|
181
209
|
it('uses name without suffix for single call', function () {
|
|
182
210
|
var ast = parser.parse("\nvoid main() {\n vec4 computed = texture2D(noiseImage, uvPow * 1.0);\n}", { quiet: true });
|
|
183
211
|
expect(applyStrategy({ type: StrategyType.TEXTURE_2D, config: {} }, ast, {}, {}).map(function (_a) {
|
|
@@ -185,12 +213,12 @@ it('uses name without suffix for single call', function () {
|
|
|
185
213
|
return name;
|
|
186
214
|
})).toEqual(['noiseImage']);
|
|
187
215
|
});
|
|
188
|
-
it('finds
|
|
216
|
+
it('finds one texture2D input for one texture2D() call', function () {
|
|
189
217
|
var ast = parser.parse("\nvoid main() {\n vec4 computed = texture2D(noiseImage, uvPow * 1.0);\n computed += texture2D(noiseImage, uvPow * 2.0);\n}", { quiet: true });
|
|
190
218
|
expect(applyStrategy({ type: StrategyType.TEXTURE_2D, config: {} }, ast, {}, {}).map(function (_a) {
|
|
191
219
|
var _b = __read(_a, 1), name = _b[0].displayName;
|
|
192
220
|
return name;
|
|
193
|
-
})).toEqual(['
|
|
221
|
+
})).toEqual(['noiseImage']);
|
|
194
222
|
});
|
|
195
223
|
it('Make sure texture2D finds preprocessed texture() call', function () {
|
|
196
224
|
// I thought this was a regression, but it wasn't a real bug, but tests seems
|
package/strategy/texture2D.js
CHANGED
|
@@ -33,7 +33,7 @@ export var texture2DStrategy = function () { return ({
|
|
|
33
33
|
}); };
|
|
34
34
|
export var applyTexture2DStrategy = function (strategy, ast, graphNode, siblingNode) {
|
|
35
35
|
var texture2Dcalls = [];
|
|
36
|
-
var
|
|
36
|
+
var references = {};
|
|
37
37
|
var visitors = {
|
|
38
38
|
function_call: {
|
|
39
39
|
enter: function (path) {
|
|
@@ -47,36 +47,34 @@ export var applyTexture2DStrategy = function (strategy, ast, graphNode, siblingN
|
|
|
47
47
|
throw new Error('This error is impossible. A function call always has a parent.');
|
|
48
48
|
}
|
|
49
49
|
var name = generate(path.node.args[0]);
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
name
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
path.
|
|
57
|
-
|
|
50
|
+
if (!(name in references)) {
|
|
51
|
+
references[name] = [];
|
|
52
|
+
texture2Dcalls.push(name);
|
|
53
|
+
}
|
|
54
|
+
references[name].push({
|
|
55
|
+
parent: path.parent,
|
|
56
|
+
key: path.key,
|
|
57
|
+
args: path.node.args.slice(2),
|
|
58
|
+
});
|
|
58
59
|
}
|
|
59
60
|
},
|
|
60
61
|
},
|
|
61
62
|
};
|
|
62
63
|
visit(ast, visitors);
|
|
63
|
-
var
|
|
64
|
-
var _b = __read(_a, 2), name = _b[0], count = _b[1];
|
|
65
|
-
return __spreadArray(__spreadArray([], __read(arr), false), __read((count > 1 ? [name] : [])), false);
|
|
66
|
-
}, []));
|
|
67
|
-
var inputs = texture2Dcalls.map(function (_a, index) {
|
|
68
|
-
var _b = __read(_a, 4), name = _b[0], parent = _b[1], key = _b[2], texture2dArgs = _b[3];
|
|
69
|
-
// Suffix input name if it's used more than once
|
|
70
|
-
var iName = names.has(name) ? "".concat(name, "_").concat(index) : name;
|
|
64
|
+
var inputs = texture2Dcalls.map(function (name) {
|
|
71
65
|
return [
|
|
72
|
-
nodeInput(
|
|
66
|
+
nodeInput(name, "filler_".concat(name), 'filler', 'vector4', // Data type for what plugs into this filler
|
|
73
67
|
['code', 'data'], false),
|
|
74
|
-
function (
|
|
75
|
-
|
|
76
|
-
|
|
68
|
+
function (filler) {
|
|
69
|
+
references[name].forEach(function (_a) {
|
|
70
|
+
var parent = _a.parent, key = _a.key, args = _a.args;
|
|
71
|
+
// Backfilling into the filler! Similar to parsers.ts filler
|
|
72
|
+
var f = filler.apply(void 0, __spreadArray([], __read(args.map(generate)), false));
|
|
73
|
+
// @ts-ignore
|
|
74
|
+
parent[key] = f;
|
|
75
|
+
});
|
|
77
76
|
return ast;
|
|
78
77
|
},
|
|
79
|
-
texture2dArgs,
|
|
80
78
|
];
|
|
81
79
|
});
|
|
82
80
|
return inputs;
|
package/strategy/uniform.js
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
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
|
+
};
|
|
1
12
|
var __read = (this && this.__read) || function (o, n) {
|
|
2
13
|
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
3
14
|
if (!m) return o;
|
|
@@ -17,6 +28,7 @@ var __read = (this && this.__read) || function (o, n) {
|
|
|
17
28
|
import { nodeInput } from '../graph/base-node';
|
|
18
29
|
import { StrategyType } from '.';
|
|
19
30
|
import { generateFiller } from '../util/ast';
|
|
31
|
+
import { renameBinding } from '@shaderfrog/glsl-parser/parser/utils';
|
|
20
32
|
export var uniformStrategy = function () { return ({
|
|
21
33
|
type: StrategyType.UNIFORM,
|
|
22
34
|
config: {},
|
|
@@ -127,64 +139,50 @@ var mapUniformType = function (type) {
|
|
|
127
139
|
}
|
|
128
140
|
// console.log(`Unknown uniform type, can't map to graph: ${type}`);
|
|
129
141
|
};
|
|
130
|
-
|
|
142
|
+
var isUniformDeclaration = function (node) {
|
|
143
|
+
var _a, _b, _c;
|
|
144
|
+
return node.type === 'declaration_statement' &&
|
|
145
|
+
node.declaration.type === 'declarator_list' &&
|
|
146
|
+
!!((_c = (_b = (_a = node.declaration) === null || _a === void 0 ? void 0 : _a.specified_type) === null || _b === void 0 ? void 0 : _b.qualifiers) === null || _c === void 0 ? void 0 : _c.find(function (n) { return n.token === 'uniform'; }));
|
|
147
|
+
};
|
|
148
|
+
// commented this out to allow for sampler2D uniforms to appear as inputs
|
|
149
|
+
// && uniformType !== 'sampler2D'
|
|
150
|
+
export var applyUniformStrategy = function (strategy, ast, graphNode) {
|
|
131
151
|
var program = ast;
|
|
132
|
-
return (program.program || [])
|
|
133
|
-
|
|
152
|
+
return (program.program || [])
|
|
153
|
+
.filter(isUniformDeclaration)
|
|
154
|
+
.flatMap(function (node) {
|
|
155
|
+
var _a, _b, _c;
|
|
156
|
+
var declaration = node.declaration;
|
|
134
157
|
// The uniform declaration type, like vec4
|
|
135
|
-
|
|
158
|
+
// TODO: File VSCode bug, this is highlighted like a function
|
|
159
|
+
var uniformType = (_c = (_b = (_a = declaration === null || declaration === void 0 ? void 0 : declaration.specified_type) === null || _a === void 0 ? void 0 : _a.specifier) === null || _b === void 0 ? void 0 : _b.specifier) === null || _c === void 0 ? void 0 : _c.token;
|
|
136
160
|
var graphDataType = mapUniformType(uniformType);
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
//
|
|
142
|
-
|
|
143
|
-
) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
else {
|
|
164
|
-
var decl = node.declaration;
|
|
165
|
-
decl.declarations = decl.declarations.filter(function (d) { return d.identifier.identifier !== mangledName; });
|
|
166
|
-
}
|
|
167
|
-
// And rename all the references to said uniform
|
|
168
|
-
program.scopes[0].bindings[name].references.forEach(function (ref) {
|
|
169
|
-
if (ref.type === 'identifier' && ref.identifier === mangledName) {
|
|
170
|
-
ref.identifier = generateFiller(filler);
|
|
171
|
-
}
|
|
172
|
-
else if (ref.type === 'parameter_declaration' &&
|
|
173
|
-
'identifier' in ref &&
|
|
174
|
-
ref.identifier.identifier === mangledName) {
|
|
175
|
-
ref.identifier.identifier = generateFiller(filler);
|
|
176
|
-
}
|
|
177
|
-
else if ('identifier' in ref) {
|
|
178
|
-
ref.identifier = generateFiller(filler);
|
|
179
|
-
}
|
|
180
|
-
else {
|
|
181
|
-
console.warn('Unknown uniform reference for', graphNode.name, 'ref');
|
|
182
|
-
}
|
|
183
|
-
});
|
|
184
|
-
return ast;
|
|
185
|
-
},
|
|
186
|
-
]; });
|
|
187
|
-
}
|
|
188
|
-
return [];
|
|
161
|
+
var declarations = declaration.declarations;
|
|
162
|
+
// Capture the uniform names, and then capture their references in the
|
|
163
|
+
// closure. This allows the scope binding to be renamed when the AST is
|
|
164
|
+
// mangled, but this strategy can still find the original named variables
|
|
165
|
+
// to work with
|
|
166
|
+
var names = declarations.map(function (d) { return d.identifier.identifier; });
|
|
167
|
+
var references = names.reduce(function (acc, name) {
|
|
168
|
+
var _a;
|
|
169
|
+
return (__assign(__assign({}, acc), (_a = {}, _a[name] = program.scopes[0].bindings[name], _a)));
|
|
170
|
+
}, {});
|
|
171
|
+
return names.map(function (name) { return [
|
|
172
|
+
nodeInput(name, "uniform_".concat(name), 'uniform', graphDataType, ['code', 'data'], true),
|
|
173
|
+
function (filler) {
|
|
174
|
+
// Remove the declaration line, or the declared uniform
|
|
175
|
+
if (declarations.length === 1) {
|
|
176
|
+
program.program.splice(program.program.indexOf(node), 1);
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
var decl = node.declaration;
|
|
180
|
+
decl.declarations = decl.declarations.filter(function (d) { return d.identifier.identifier !== name; });
|
|
181
|
+
}
|
|
182
|
+
// Rename all the references to said uniform
|
|
183
|
+
renameBinding(references[name], generateFiller(filler()));
|
|
184
|
+
return ast;
|
|
185
|
+
},
|
|
186
|
+
]; });
|
|
189
187
|
});
|
|
190
188
|
};
|
package/strategy/variable.js
CHANGED
|
@@ -35,7 +35,7 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
|
35
35
|
return to.concat(ar || Array.prototype.slice.call(from));
|
|
36
36
|
};
|
|
37
37
|
import { nodeInput } from '../graph/base-node';
|
|
38
|
-
import { StrategyType } from '.';
|
|
38
|
+
import { StrategyType, } from '.';
|
|
39
39
|
import { generateFiller } from '../util/ast';
|
|
40
40
|
export var variableStrategy = function () { return ({
|
|
41
41
|
type: StrategyType.VARIABLE,
|
|
@@ -48,15 +48,15 @@ export var applyVariableStrategy = function (strategy, ast, graphNode, siblingNo
|
|
|
48
48
|
var identifier, replacer;
|
|
49
49
|
if (ref.type === 'declaration') {
|
|
50
50
|
identifier = ref.identifier.identifier;
|
|
51
|
-
replacer = function (
|
|
52
|
-
ref.identifier.identifier = generateFiller(
|
|
51
|
+
replacer = function (filler) {
|
|
52
|
+
ref.identifier.identifier = generateFiller(filler());
|
|
53
53
|
return ast;
|
|
54
54
|
};
|
|
55
55
|
}
|
|
56
56
|
else if (ref.type === 'identifier') {
|
|
57
57
|
identifier = ref.identifier;
|
|
58
|
-
replacer = function (
|
|
59
|
-
ref.identifier = generateFiller(
|
|
58
|
+
replacer = function (filler) {
|
|
59
|
+
ref.identifier = generateFiller(filler());
|
|
60
60
|
return ast;
|
|
61
61
|
};
|
|
62
62
|
// } else if (ref.type === 'parameter_declaration') {
|
package/util/ast.d.ts
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions to work with ASTs
|
|
3
|
+
*/
|
|
4
|
+
import { AstNode, ExpressionStatementNode, FunctionNode, DeclarationStatementNode, DeclarationNode, LiteralNode } from '@shaderfrog/glsl-parser/ast';
|
|
2
5
|
import { Program } from '@shaderfrog/glsl-parser/ast';
|
|
3
6
|
import { ShaderStage } from '../graph/graph-types';
|
|
4
7
|
import { Scope } from '@shaderfrog/glsl-parser/parser/scope';
|
|
5
|
-
import { Filler } from '../graph/parsers';
|
|
6
8
|
export interface FrogProgram extends Program {
|
|
7
9
|
outVar?: string;
|
|
8
10
|
}
|
|
11
|
+
export declare const makeLiteral: (literal: string, whitespace?: string) => LiteralNode;
|
|
9
12
|
export declare const findVec4Constructor: (ast: AstNode) => AstNode | undefined;
|
|
10
13
|
export declare const findAssignmentTo: (ast: AstNode | Program, assignTo: string, nth?: number) => DeclarationNode | ExpressionStatementNode | undefined;
|
|
11
14
|
export declare const findDeclarationOf: (ast: AstNode | Program, declarationOf: string) => DeclarationNode | undefined;
|
|
12
15
|
export declare const from2To3: (ast: Program, stage: ShaderStage) => void;
|
|
13
|
-
export declare const makeStatement: (stmt: string) => readonly [
|
|
16
|
+
export declare const makeStatement: (stmt: string, ws?: string) => readonly [import("@shaderfrog/glsl-parser/ast").ProgramStatement, Scope];
|
|
14
17
|
export declare const makeFnStatement: (fnStmt: string) => readonly [AstNode, Scope];
|
|
15
18
|
/**
|
|
16
19
|
* Add a new scope into an existing one. Meant to be used for adding net new
|
|
@@ -46,4 +49,6 @@ export declare const returnGlPositionVec3Right: (fnName: string, ast: Program) =
|
|
|
46
49
|
* returns a vec4.
|
|
47
50
|
*/
|
|
48
51
|
export declare const convert300MainToReturn: (ast: FrogProgram) => void;
|
|
49
|
-
export declare const generateFiller: (
|
|
52
|
+
export declare const generateFiller: (ast: AstNode | AstNode[] | void) => string;
|
|
53
|
+
export declare const isDeclarationStatement: (node: Program["program"][0]) => node is DeclarationStatementNode;
|
|
54
|
+
export declare const backfillAst: (ast: Program, fromType: string, targetVariable: string, mainFn?: FunctionNode) => Program;
|
package/util/ast.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions to work with ASTs
|
|
3
|
+
*/
|
|
1
4
|
var __assign = (this && this.__assign) || function () {
|
|
2
5
|
__assign = Object.assign || function(t) {
|
|
3
6
|
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
@@ -37,7 +40,7 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
|
37
40
|
import { parser, generate } from '@shaderfrog/glsl-parser';
|
|
38
41
|
import { visit, } from '@shaderfrog/glsl-parser/ast';
|
|
39
42
|
import { addFnStmtWithIndent } from './whitespace';
|
|
40
|
-
import { renameBinding
|
|
43
|
+
import { renameBinding } from '@shaderfrog/glsl-parser/parser/utils';
|
|
41
44
|
var log = function () {
|
|
42
45
|
var _a;
|
|
43
46
|
var args = [];
|
|
@@ -46,6 +49,14 @@ var log = function () {
|
|
|
46
49
|
}
|
|
47
50
|
return (_a = console.log).call.apply(_a, __spreadArray([console, '\x1b[31m(core.manipulate)\x1b[0m'], __read(args), false));
|
|
48
51
|
};
|
|
52
|
+
export var makeLiteral = function (literal, whitespace) {
|
|
53
|
+
if (whitespace === void 0) { whitespace = ''; }
|
|
54
|
+
return ({
|
|
55
|
+
type: 'literal',
|
|
56
|
+
literal: literal,
|
|
57
|
+
whitespace: whitespace,
|
|
58
|
+
});
|
|
59
|
+
};
|
|
49
60
|
export var findVec4Constructor = function (ast) {
|
|
50
61
|
var parent;
|
|
51
62
|
var visitors = {
|
|
@@ -159,11 +170,12 @@ export var from2To3 = function (ast, stage) {
|
|
|
159
170
|
},
|
|
160
171
|
});
|
|
161
172
|
};
|
|
162
|
-
export var makeStatement = function (stmt) {
|
|
173
|
+
export var makeStatement = function (stmt, ws) {
|
|
174
|
+
if (ws === void 0) { ws = ''; }
|
|
163
175
|
// log(`Parsing "${stmt}"`);
|
|
164
176
|
var ast;
|
|
165
177
|
try {
|
|
166
|
-
ast = parser.parse("".concat(stmt, "
|
|
178
|
+
ast = parser.parse("".concat(stmt, ";").concat(ws, "\n"), { quiet: true });
|
|
167
179
|
}
|
|
168
180
|
catch (error) {
|
|
169
181
|
console.error({ stmt: stmt, error: error });
|
|
@@ -366,11 +378,28 @@ export var convert300MainToReturn = function (ast) {
|
|
|
366
378
|
main.body.statements = addFnStmtWithIndent(main, rtn);
|
|
367
379
|
ast.scopes[0].bindings[replacedReturn].references.push(rtn.expression);
|
|
368
380
|
};
|
|
369
|
-
export var generateFiller = function (
|
|
370
|
-
if (!
|
|
381
|
+
export var generateFiller = function (ast) {
|
|
382
|
+
if (!ast) {
|
|
371
383
|
throw new Error('Cannot generate void filler!');
|
|
372
384
|
}
|
|
373
|
-
return Array.isArray(
|
|
374
|
-
|
|
375
|
-
|
|
385
|
+
return Array.isArray(ast) ? ast.map(generate).join('') : generate(ast);
|
|
386
|
+
};
|
|
387
|
+
export var isDeclarationStatement = function (node) {
|
|
388
|
+
return node.type === 'declaration_statement' &&
|
|
389
|
+
node.declaration.type === 'declarator_list';
|
|
390
|
+
};
|
|
391
|
+
export var backfillAst = function (ast, fromType, targetVariable, mainFn) {
|
|
392
|
+
if (!ast.scopes[0].bindings[targetVariable]) {
|
|
393
|
+
console.warn("Variable \"".concat(targetVariable, "\" not found in global program scope to backfill! Variables: ").concat(Object.keys(ast.scopes[0].bindings)));
|
|
394
|
+
}
|
|
395
|
+
// Inject the backfill param as the arg
|
|
396
|
+
if (mainFn) {
|
|
397
|
+
mainFn.prototype.parameters = (mainFn.prototype.parameters || [])
|
|
398
|
+
.filter(
|
|
399
|
+
// Watch out for the main(void){} case!
|
|
400
|
+
function (arg) { return arg.specifier.specifier.token !== 'void'; })
|
|
401
|
+
.concat(parser.parse("void x(".concat(fromType, " ").concat(targetVariable, ") {}"))
|
|
402
|
+
.program[0].prototype.parameters);
|
|
403
|
+
}
|
|
404
|
+
return ast;
|
|
376
405
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/util/ast.test.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { expect, it } from 'vitest';
|
|
2
|
+
import { parser } from '@shaderfrog/glsl-parser';
|
|
3
|
+
import { generate } from '@shaderfrog/glsl-parser';
|
|
4
|
+
import { backfillAst, findMain } from '../util/ast';
|
|
5
|
+
it('backfillAst', function () {
|
|
6
|
+
var source = parser.parse("\nattribute vec2 vUv, xx;\nvoid main() {\n gl_FragColor = vec4(vUv, xx);\n}");
|
|
7
|
+
var result = backfillAst(source, 'vec2', 'vUv', findMain(source));
|
|
8
|
+
expect(generate(result)).toBe("\nattribute vec2 vUv, xx;\nvoid main(vec2 vUv) {\n gl_FragColor = vec4(vUv, xx);\n}");
|
|
9
|
+
});
|
|
10
|
+
it('backfillAst with void main fn', function () {
|
|
11
|
+
var source = parser.parse("\nattribute vec2 vUv;\nvoid main(void) {\n gl_FragColor = vec4(vUv, 1.0, 1.0);\n}");
|
|
12
|
+
var result = backfillAst(source, 'vec2', 'vUv', findMain(source));
|
|
13
|
+
expect(generate(result)).toBe("\nattribute vec2 vUv;\nvoid main(vec2 vUv) {\n gl_FragColor = vec4(vUv, 1.0, 1.0);\n}");
|
|
14
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
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 indexById = function (records) {
|
|
13
|
+
return records.reduce(function (acc, record) {
|
|
14
|
+
var _a;
|
|
15
|
+
return (__assign(__assign({}, acc), (_a = {}, _a[record.id] = record, _a)));
|
|
16
|
+
}, {});
|
|
17
|
+
};
|
|
18
|
+
export default indexById;
|
package/util/whitespace.d.ts
CHANGED
|
@@ -16,3 +16,5 @@ export declare const getLiteralIndent: (node: {
|
|
|
16
16
|
export declare const tryAddTrailingWhitespace: <T extends AstNode>(node: T, ws: string) => T;
|
|
17
17
|
export declare const guessFnIndent: (fnBody: FunctionNode) => string;
|
|
18
18
|
export declare const addFnStmtWithIndent: (fnBody: FunctionNode, newNode: string | AstNode) => AstNode[];
|
|
19
|
+
export declare const unshiftFnStmtWithIndent: (fnBody: FunctionNode, newNode: string | AstNode) => AstNode[];
|
|
20
|
+
export declare const spliceFnStmtWithIndent: (fnBody: FunctionNode, index: number, ...newNodes: (string | AstNode)[]) => AstNode[];
|
package/util/whitespace.js
CHANGED
|
@@ -34,7 +34,7 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
|
34
34
|
}
|
|
35
35
|
return to.concat(ar || Array.prototype.slice.call(from));
|
|
36
36
|
};
|
|
37
|
-
import { makeFnStatement } from './ast';
|
|
37
|
+
import { makeFnStatement, makeLiteral } from './ast';
|
|
38
38
|
var log = function () {
|
|
39
39
|
var _a;
|
|
40
40
|
var args = [];
|
|
@@ -79,13 +79,32 @@ export var guessFnIndent = function (fnBody) {
|
|
|
79
79
|
return ws || getLiteralIndent(n.semi) || '';
|
|
80
80
|
}, '');
|
|
81
81
|
};
|
|
82
|
+
var addWs = function (node, ws) {
|
|
83
|
+
return tryAddTrailingWhitespace(typeof node === 'string' ? makeFnStatement(node)[0] : node, ws);
|
|
84
|
+
};
|
|
82
85
|
export var addFnStmtWithIndent = function (fnBody, newNode) {
|
|
83
86
|
var statements = fnBody.body.statements;
|
|
84
87
|
var indent = guessFnIndent(fnBody);
|
|
85
88
|
return __spreadArray(__spreadArray([], __read(statements), false), [
|
|
86
89
|
// This simple hack is way easier than trying to modify the function body
|
|
87
90
|
// opening brace and/or the previous statement
|
|
88
|
-
|
|
89
|
-
|
|
91
|
+
makeLiteral('', indent),
|
|
92
|
+
addWs(newNode, "\n"),
|
|
90
93
|
], false);
|
|
91
94
|
};
|
|
95
|
+
export var unshiftFnStmtWithIndent = function (fnBody, newNode) {
|
|
96
|
+
var statements = fnBody.body.statements;
|
|
97
|
+
var indent = guessFnIndent(fnBody);
|
|
98
|
+
return __spreadArray([addWs(newNode, "\n"), makeLiteral('', indent)], __read(statements), false);
|
|
99
|
+
};
|
|
100
|
+
export var spliceFnStmtWithIndent = function (fnBody, index) {
|
|
101
|
+
var newNodes = [];
|
|
102
|
+
for (var _i = 2; _i < arguments.length; _i++) {
|
|
103
|
+
newNodes[_i - 2] = arguments[_i];
|
|
104
|
+
}
|
|
105
|
+
var statements = fnBody.body.statements;
|
|
106
|
+
var indent = guessFnIndent(fnBody);
|
|
107
|
+
return __spreadArray(__spreadArray(__spreadArray(__spreadArray([], __read(statements.slice(0, index)), false), __read(newNodes.map(function (n) { return addWs(n, "\n"); })), false), [
|
|
108
|
+
makeLiteral('', indent)
|
|
109
|
+
], false), __read(statements.slice(index)), false);
|
|
110
|
+
};
|