@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/graph/graph.test.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 __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
13
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
14
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -39,20 +50,22 @@ import util from 'util';
|
|
|
39
50
|
import { parser } from '@shaderfrog/glsl-parser';
|
|
40
51
|
import { generate } from '@shaderfrog/glsl-parser';
|
|
41
52
|
import { addNode, outputNode, sourceNode } from './graph-node';
|
|
42
|
-
import { shaderSectionsToProgram, mergeShaderSections, findShaderSections, } from './shader-sections';
|
|
53
|
+
import { shaderSectionsToProgram, mergeShaderSections, findShaderSections, extractSource, filterUniformNames, filterQualifiedStatements, } from './shader-sections';
|
|
43
54
|
import { numberNode } from './data-nodes';
|
|
44
|
-
import { makeEdge } from './edge';
|
|
55
|
+
import { linkFromVertToFrag, makeEdge } from './edge';
|
|
45
56
|
import { evaluateNode } from './evaluate';
|
|
46
|
-
import { compileSource } from './graph';
|
|
57
|
+
import { compileSource, nodeName } from './graph';
|
|
47
58
|
import { texture2DStrategy } from '../strategy';
|
|
48
59
|
import { isError } from './context';
|
|
49
60
|
import { fail } from '../test-util';
|
|
61
|
+
import { SourceType } from './code-nodes';
|
|
62
|
+
import { makeId } from 'src/util/id';
|
|
50
63
|
var inspect = function (thing) {
|
|
51
64
|
return console.log(util.inspect(thing, false, null, true));
|
|
52
65
|
};
|
|
53
66
|
var mergeBlocks = function (ast1, ast2) {
|
|
54
|
-
var s1 = findShaderSections(ast1);
|
|
55
|
-
var s2 = findShaderSections(ast2);
|
|
67
|
+
var s1 = findShaderSections('', ast1);
|
|
68
|
+
var s2 = findShaderSections('', ast2);
|
|
56
69
|
var merged = mergeShaderSections(s1, s2);
|
|
57
70
|
return generate(shaderSectionsToProgram(merged, {
|
|
58
71
|
includePrecisions: true,
|
|
@@ -60,14 +73,12 @@ var mergeBlocks = function (ast1, ast2) {
|
|
|
60
73
|
}));
|
|
61
74
|
};
|
|
62
75
|
var dedupe = function (code) {
|
|
63
|
-
return generate(shaderSectionsToProgram(findShaderSections(parser.parse(code)), {
|
|
76
|
+
return generate(shaderSectionsToProgram(findShaderSections('', parser.parse(code)), {
|
|
64
77
|
includePrecisions: true,
|
|
65
78
|
includeVersion: true,
|
|
66
79
|
}));
|
|
67
80
|
};
|
|
68
|
-
var counter = 0;
|
|
69
81
|
var p = { x: 0, y: 0 };
|
|
70
|
-
var id = function () { return '' + counter++; };
|
|
71
82
|
var constructor = function () { return ({
|
|
72
83
|
config: {
|
|
73
84
|
version: 3,
|
|
@@ -103,7 +114,7 @@ var engine = {
|
|
|
103
114
|
includeVersion: true,
|
|
104
115
|
},
|
|
105
116
|
importers: {},
|
|
106
|
-
preserve: new Set(),
|
|
117
|
+
preserve: new Set('vUv'),
|
|
107
118
|
parsers: {},
|
|
108
119
|
};
|
|
109
120
|
var makeSourceNode = function (id, source, stage, strategies) {
|
|
@@ -115,45 +126,22 @@ var makeSourceNode = function (id, source, stage, strategies) {
|
|
|
115
126
|
uniforms: [],
|
|
116
127
|
}, source, stage);
|
|
117
128
|
};
|
|
118
|
-
|
|
119
|
-
* What exactly am I doing here?
|
|
120
|
-
*
|
|
121
|
-
* I opened shaderfrog to start looking at the backfilling case and inlining
|
|
122
|
-
* function calls at the top of functions
|
|
123
|
-
*
|
|
124
|
-
* WHie doing that I found jest not to work well anyore and switched to vitest,
|
|
125
|
-
* which is fine, but with esm by default I can't stub the mangleName() function
|
|
126
|
-
* call, which means mangling happens as-is in the tests.
|
|
127
|
-
*
|
|
128
|
-
* Without changing the mangling strategy, the strategies.test.ts file fails
|
|
129
|
-
* because the uniform strategy looks for a mangled variable name, but the
|
|
130
|
-
* program itself isn't mangled.
|
|
131
|
-
*
|
|
132
|
-
* One way to fix this is to make fillers not have to care about mangling names,
|
|
133
|
-
* which would be simpler on the surface.
|
|
134
|
-
*
|
|
135
|
-
* Then everything in the tests broke and you found out the reason why was
|
|
136
|
-
* trying to use scopes to rename things, and most of the ast manipulation steps
|
|
137
|
-
* don't modify scopes, so you made some of them modify scopes, and now things
|
|
138
|
-
* are fucked
|
|
139
|
-
*/
|
|
140
|
-
it('compileSource() fragment produces inlined output', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
129
|
+
it('compileSource() fragment produces inlined output without', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
141
130
|
var outV, outF, imageReplacemMe, input1, input2, graph, engineContext, result, imgOut;
|
|
142
131
|
return __generator(this, function (_a) {
|
|
143
132
|
switch (_a.label) {
|
|
144
133
|
case 0:
|
|
145
|
-
outV = outputNode(
|
|
146
|
-
outF = outputNode(
|
|
147
|
-
imageReplacemMe = makeSourceNode(
|
|
148
|
-
input1 = makeSourceNode(
|
|
149
|
-
input2 = makeSourceNode(
|
|
134
|
+
outV = outputNode(makeId(), 'Output v', p, 'vertex');
|
|
135
|
+
outF = outputNode(makeId(), 'Output f', p, 'fragment');
|
|
136
|
+
imageReplacemMe = makeSourceNode(makeId(), "uniform sampler2D image1;\nuniform sampler2D image2;\nvoid main() {\n vec3 col1 = texture2D(image1, posTurn - 0.4 * time).rgb + 1.0;\n vec3 col2 = texture2D(image2, negTurn - 0.4 * time).rgb + 2.0;\n gl_FragColor = vec4(col1 + col2, 1.0);\n}\n", 'fragment');
|
|
137
|
+
input1 = makeSourceNode(makeId(), "float a = 1.0;\nvoid main() {\n gl_FragColor = vec4(0.0);\n}\n", 'fragment');
|
|
138
|
+
input2 = makeSourceNode(makeId(), "float a = 2.0;\nvoid main() {\n gl_FragColor = vec4(1.0);\n}\n", 'fragment');
|
|
150
139
|
graph = {
|
|
151
140
|
nodes: [outV, outF, imageReplacemMe, input1, input2],
|
|
152
141
|
edges: [
|
|
153
|
-
makeEdge(
|
|
154
|
-
makeEdge(
|
|
155
|
-
makeEdge(
|
|
156
|
-
makeEdge(id(), input2.id, imageReplacemMe.id, 'out', 'filler_image2', 'fragment'),
|
|
142
|
+
makeEdge(makeId(), imageReplacemMe.id, outF.id, 'out', 'filler_frogFragOut', 'fragment'),
|
|
143
|
+
makeEdge(makeId(), input1.id, imageReplacemMe.id, 'out', 'filler_image1', 'fragment'),
|
|
144
|
+
makeEdge(makeId(), input2.id, imageReplacemMe.id, 'out', 'filler_image2', 'fragment'),
|
|
157
145
|
],
|
|
158
146
|
};
|
|
159
147
|
engineContext = {
|
|
@@ -178,18 +166,206 @@ it('compileSource() fragment produces inlined output', function () { return __aw
|
|
|
178
166
|
}
|
|
179
167
|
});
|
|
180
168
|
}); });
|
|
169
|
+
it('compileSource() vertex produces inlined output', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
170
|
+
var outV, outF, vert, graph, engineContext, result, iMainName;
|
|
171
|
+
return __generator(this, function (_a) {
|
|
172
|
+
switch (_a.label) {
|
|
173
|
+
case 0:
|
|
174
|
+
outV = outputNode(makeId(), 'Output v', p, 'vertex');
|
|
175
|
+
outF = outputNode(makeId(), 'Output f', p, 'fragment');
|
|
176
|
+
vert = makeSourceNode(makeId(), "uniform vec4 modelViewMatrix;\nattribute vec3 position;\nfloat a = 2.0;\nvoid main() {\n gl_Position = modelViewMatrix * vec4(position, 1.0);\n}\n", 'vertex');
|
|
177
|
+
graph = {
|
|
178
|
+
nodes: [outV, outF, vert],
|
|
179
|
+
edges: [
|
|
180
|
+
makeEdge(makeId(), vert.id, outV.id, 'out', 'filler_gl_Position', 'vertex'),
|
|
181
|
+
],
|
|
182
|
+
};
|
|
183
|
+
engineContext = {
|
|
184
|
+
engine: 'three',
|
|
185
|
+
nodes: {},
|
|
186
|
+
runtime: {},
|
|
187
|
+
debuggingNonsense: {},
|
|
188
|
+
};
|
|
189
|
+
return [4 /*yield*/, compileSource(graph, engine, engineContext)];
|
|
190
|
+
case 1:
|
|
191
|
+
result = _a.sent();
|
|
192
|
+
if (isError(result)) {
|
|
193
|
+
fail(result);
|
|
194
|
+
}
|
|
195
|
+
iMainName = nodeName(vert);
|
|
196
|
+
expect(result.vertexResult).toContain("\nvoid main() {\n gl_Position = ".concat(iMainName, "();\n}"));
|
|
197
|
+
return [2 /*return*/];
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
}); });
|
|
201
|
+
it('compileSource() fragment backfilling one level', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
202
|
+
var outV, outF, imageReplacemMe, input1, graph, engineContext, preserver, result, inputMain, imageMain;
|
|
203
|
+
return __generator(this, function (_a) {
|
|
204
|
+
switch (_a.label) {
|
|
205
|
+
case 0:
|
|
206
|
+
outV = outputNode(makeId(), 'Output v', p, 'vertex');
|
|
207
|
+
outF = outputNode(makeId(), 'Output f', p, 'fragment');
|
|
208
|
+
imageReplacemMe = makeSourceNode(makeId(), "attribute vec2 vUv;\nuniform sampler2D image1;\nuniform sampler2D image2;\nvoid main() {\n vec3 col1 = texture2D(image1, vUv - 0.4 * time).rgb + 1.0;\n vec3 other1 = texture2D(image1, vUv + 1.0).rgb;\n vec3 col2 = texture2D(image2, negTurn - 0.4 * time).rgb + 2.0;\n gl_FragColor = vec4(col1 + col2, 1.0);\n}\n", 'fragment');
|
|
209
|
+
imageReplacemMe.backfillers = {
|
|
210
|
+
filler_image1: [
|
|
211
|
+
{
|
|
212
|
+
argType: 'vec2',
|
|
213
|
+
targetVariable: 'vUv',
|
|
214
|
+
},
|
|
215
|
+
],
|
|
216
|
+
};
|
|
217
|
+
input1 = makeSourceNode(makeId(), "attribute vec2 vUv;\nvoid main() {\n gl_FragColor = vec4(vUv, 1.0, 1.0);\n}\n", 'fragment');
|
|
218
|
+
graph = {
|
|
219
|
+
nodes: [outV, outF, imageReplacemMe, input1],
|
|
220
|
+
edges: [
|
|
221
|
+
makeEdge(makeId(), imageReplacemMe.id, outF.id, 'out', 'filler_frogFragOut', 'fragment'),
|
|
222
|
+
makeEdge(makeId(), input1.id, imageReplacemMe.id, 'out', 'filler_image1', 'fragment'),
|
|
223
|
+
],
|
|
224
|
+
};
|
|
225
|
+
engineContext = {
|
|
226
|
+
engine: 'three',
|
|
227
|
+
nodes: {},
|
|
228
|
+
runtime: {},
|
|
229
|
+
debuggingNonsense: {},
|
|
230
|
+
};
|
|
231
|
+
preserver = __assign(__assign({}, engine), { preserve: new Set(['vUv']) });
|
|
232
|
+
return [4 /*yield*/, compileSource(graph, preserver, engineContext)];
|
|
233
|
+
case 1:
|
|
234
|
+
result = _a.sent();
|
|
235
|
+
if (isError(result)) {
|
|
236
|
+
fail(result);
|
|
237
|
+
}
|
|
238
|
+
inputMain = nodeName(input1);
|
|
239
|
+
imageMain = nodeName(imageReplacemMe);
|
|
240
|
+
// Should preserve global variable despite backfilling
|
|
241
|
+
expect(result.fragmentResult).toContain("in vec2 vUv;");
|
|
242
|
+
// Backfilled variable should be in the main fn parameters
|
|
243
|
+
// I don't think is inlined? I think this is expected by convertToMain
|
|
244
|
+
expect(result.fragmentResult).toContain("\nvec4 ".concat(inputMain, "(vec2 vUv) {\n frogOut_").concat(input1.id, " = vec4(vUv, 1.0, 1.0);\n return frogOut_").concat(input1.id, ";\n}"));
|
|
245
|
+
// The image function should pass its parameters to the child
|
|
246
|
+
expect(result.fragmentResult).toContain("\nvec4 ".concat(imageMain, "() {\n vec3 col1 = ").concat(inputMain, "(vUv - 0.4 * time).rgb + 1.0;\n vec3 other1 = ").concat(inputMain, "(vUv + 1.0).rgb;\n vec3 col2 = texture(image2"));
|
|
247
|
+
return [2 /*return*/];
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
}); });
|
|
251
|
+
it('compileSource() orphaned vertex nodes are called properly in output', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
252
|
+
var outV, outF, vert, frag, graph, engineContext, result, iMainName;
|
|
253
|
+
return __generator(this, function (_a) {
|
|
254
|
+
switch (_a.label) {
|
|
255
|
+
case 0:
|
|
256
|
+
outV = outputNode(makeId(), 'Output v', p, 'vertex');
|
|
257
|
+
outF = outputNode(makeId(), 'Output f', p, 'fragment');
|
|
258
|
+
vert = makeSourceNode(makeId(), "uniform vec4 modelViewMatrix;\nattribute vec3 position;\nfloat a = 2.0;\nvoid main() {\n gl_Position = modelViewMatrix * vec4(position, 1.0);\n}\n", 'vertex');
|
|
259
|
+
frag = makeSourceNode(makeId(), "attribute vec2 vUv;\nvoid main() {\n gl_FragColor = vec4(vUv, 0.0, 1.0);\n}\n", 'fragment');
|
|
260
|
+
graph = {
|
|
261
|
+
nodes: [outV, outF, frag, vert],
|
|
262
|
+
edges: [
|
|
263
|
+
makeEdge(makeId(), frag.id, outF.id, 'out', 'filler_frogFragOut', 'fragment'),
|
|
264
|
+
linkFromVertToFrag(makeId(), vert.id, frag.id),
|
|
265
|
+
],
|
|
266
|
+
};
|
|
267
|
+
engineContext = {
|
|
268
|
+
engine: 'three',
|
|
269
|
+
nodes: {},
|
|
270
|
+
runtime: {},
|
|
271
|
+
debuggingNonsense: {},
|
|
272
|
+
};
|
|
273
|
+
return [4 /*yield*/, compileSource(graph, engine, engineContext)];
|
|
274
|
+
case 1:
|
|
275
|
+
result = _a.sent();
|
|
276
|
+
if (isError(result)) {
|
|
277
|
+
fail(result);
|
|
278
|
+
}
|
|
279
|
+
iMainName = nodeName(vert);
|
|
280
|
+
expect(result.vertexResult).toContain("\nvoid main() {\n ".concat(iMainName, "();\n gl_Position = vec4(1.0);\n}"));
|
|
281
|
+
return [2 /*return*/];
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
}); });
|
|
285
|
+
it('compileSource() inlining a fragment expression', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
286
|
+
var outV, outF, imageReplacemMe, input, graph, engineContext, result;
|
|
287
|
+
return __generator(this, function (_a) {
|
|
288
|
+
switch (_a.label) {
|
|
289
|
+
case 0:
|
|
290
|
+
outV = outputNode(makeId(), 'Output v', p, 'vertex');
|
|
291
|
+
outF = outputNode(makeId(), 'Output f', p, 'fragment');
|
|
292
|
+
imageReplacemMe = makeSourceNode(makeId(), "uniform sampler2D image1;\nvoid main() {\n vec3 col1 = texture2D(image1, posTurn - 0.4 * time).rgb + 1.0;\n gl_FragColor = vec4(col1, 1.0);\n}\n", 'fragment');
|
|
293
|
+
input = makeSourceNode(makeId(), "vec4(1.0)", 'fragment');
|
|
294
|
+
input.sourceType = SourceType.EXPRESSION;
|
|
295
|
+
graph = {
|
|
296
|
+
nodes: [outV, outF, imageReplacemMe, input],
|
|
297
|
+
edges: [
|
|
298
|
+
makeEdge(makeId(), imageReplacemMe.id, outF.id, 'out', 'filler_frogFragOut', 'fragment'),
|
|
299
|
+
makeEdge(makeId(), input.id, imageReplacemMe.id, 'out', 'filler_image1', 'fragment'),
|
|
300
|
+
],
|
|
301
|
+
};
|
|
302
|
+
engineContext = {
|
|
303
|
+
engine: 'three',
|
|
304
|
+
nodes: {},
|
|
305
|
+
runtime: {},
|
|
306
|
+
debuggingNonsense: {},
|
|
307
|
+
};
|
|
308
|
+
return [4 /*yield*/, compileSource(graph, engine, engineContext)];
|
|
309
|
+
case 1:
|
|
310
|
+
result = _a.sent();
|
|
311
|
+
if (isError(result)) {
|
|
312
|
+
fail(result);
|
|
313
|
+
}
|
|
314
|
+
// Verify it inlined the expression and did not memoize the source into a
|
|
315
|
+
// varaible
|
|
316
|
+
expect(result.fragmentResult).toContain("vec4 ".concat(nodeName(imageReplacemMe), "() {\n vec3 col1 = vec4(1.0).rgb + 1.0;"));
|
|
317
|
+
return [2 /*return*/];
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
}); });
|
|
321
|
+
it('compileSource() binary properly inlines dependencies', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
322
|
+
var outV, outF, color, expr, add, graph, engineContext, result;
|
|
323
|
+
return __generator(this, function (_a) {
|
|
324
|
+
switch (_a.label) {
|
|
325
|
+
case 0:
|
|
326
|
+
outV = outputNode(makeId(), 'Output v', p, 'vertex');
|
|
327
|
+
outF = outputNode(makeId(), 'Output f', p, 'fragment');
|
|
328
|
+
color = makeSourceNode(makeId(), "uniform sampler2D image;\nvoid main() {\n vec3 col = texture2D(image, vec2(0.0)).rgb;\n gl_FragColor = vec4(col, 1.0);\n}\n", 'fragment');
|
|
329
|
+
expr = makeSourceNode(makeId(), "vec4(1.0)", 'fragment');
|
|
330
|
+
expr.sourceType = SourceType.EXPRESSION;
|
|
331
|
+
add = addNode(makeId(), p);
|
|
332
|
+
graph = {
|
|
333
|
+
nodes: [color, expr, add, outV, outF],
|
|
334
|
+
edges: [
|
|
335
|
+
makeEdge(makeId(), color.id, add.id, 'out', 'a'),
|
|
336
|
+
makeEdge(makeId(), expr.id, add.id, 'out', 'b'),
|
|
337
|
+
makeEdge(makeId(), add.id, outF.id, 'out', 'filler_frogFragOut', 'fragment'),
|
|
338
|
+
],
|
|
339
|
+
};
|
|
340
|
+
engineContext = {
|
|
341
|
+
engine: 'three',
|
|
342
|
+
nodes: {},
|
|
343
|
+
runtime: {},
|
|
344
|
+
debuggingNonsense: {},
|
|
345
|
+
};
|
|
346
|
+
return [4 /*yield*/, compileSource(graph, engine, engineContext)];
|
|
347
|
+
case 1:
|
|
348
|
+
result = _a.sent();
|
|
349
|
+
if (isError(result)) {
|
|
350
|
+
fail(result);
|
|
351
|
+
}
|
|
352
|
+
expect(result.fragmentResult).toContain("void main() {\n frogFragOut = (".concat(nodeName(color), "()+ vec4(1.0));\n}"));
|
|
353
|
+
return [2 /*return*/];
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
}); });
|
|
181
357
|
it('compileSource() base case', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
182
358
|
var outV, outF, imageReplacemMe, graph, engineContext, result, imgOut;
|
|
183
359
|
return __generator(this, function (_a) {
|
|
184
360
|
switch (_a.label) {
|
|
185
361
|
case 0:
|
|
186
|
-
outV = outputNode(
|
|
187
|
-
outF = outputNode(
|
|
188
|
-
imageReplacemMe = makeSourceNode(
|
|
362
|
+
outV = outputNode(makeId(), 'Output v', p, 'vertex');
|
|
363
|
+
outF = outputNode(makeId(), 'Output f', p, 'fragment');
|
|
364
|
+
imageReplacemMe = makeSourceNode(makeId(), "float a = 1.0;\nvoid main() {\n gl_FragColor = vec4(1.0);\n}\n", 'fragment');
|
|
189
365
|
graph = {
|
|
190
366
|
nodes: [outV, outF, imageReplacemMe],
|
|
191
367
|
edges: [
|
|
192
|
-
makeEdge(
|
|
368
|
+
makeEdge(makeId(), imageReplacemMe.id, outF.id, 'out', 'filler_frogFragOut', 'fragment'),
|
|
193
369
|
],
|
|
194
370
|
};
|
|
195
371
|
engineContext = {
|
|
@@ -214,18 +390,18 @@ it('compileSource() base case', function () { return __awaiter(void 0, void 0, v
|
|
|
214
390
|
}); });
|
|
215
391
|
describe('evaluateNode()', function () {
|
|
216
392
|
it('evaluates binary nodes', function () {
|
|
217
|
-
var finalAdd = addNode(
|
|
218
|
-
var add2 = addNode(
|
|
219
|
-
var num1 = numberNode(
|
|
220
|
-
var num2 = numberNode(
|
|
221
|
-
var num3 = numberNode(
|
|
393
|
+
var finalAdd = addNode(makeId(), p);
|
|
394
|
+
var add2 = addNode(makeId(), p);
|
|
395
|
+
var num1 = numberNode(makeId(), 'number', p, '3');
|
|
396
|
+
var num2 = numberNode(makeId(), 'number', p, '5');
|
|
397
|
+
var num3 = numberNode(makeId(), 'number', p, '7');
|
|
222
398
|
var graph = {
|
|
223
399
|
nodes: [num1, num2, num3, finalAdd, add2],
|
|
224
400
|
edges: [
|
|
225
|
-
makeEdge(
|
|
226
|
-
makeEdge(
|
|
227
|
-
makeEdge(
|
|
228
|
-
makeEdge(
|
|
401
|
+
makeEdge(makeId(), num1.id, finalAdd.id, 'out', 'a'),
|
|
402
|
+
makeEdge(makeId(), add2.id, finalAdd.id, 'out', 'b'),
|
|
403
|
+
makeEdge(makeId(), num2.id, add2.id, 'out', 'a'),
|
|
404
|
+
makeEdge(makeId(), num3.id, add2.id, 'out', 'b'),
|
|
229
405
|
],
|
|
230
406
|
};
|
|
231
407
|
expect(evaluateNode(engine, graph, finalAdd)).toBe(15);
|
|
@@ -259,3 +435,17 @@ it('should merge uniforms with interface blocks', function () {
|
|
|
259
435
|
// Verify these lines are preserved (they go through dedupeUniforms)
|
|
260
436
|
expect(dedupe("layout(std140,column_major) uniform;")).toEqual("layout(std140,column_major) uniform;");
|
|
261
437
|
});
|
|
438
|
+
it('filterUniformNames', function () {
|
|
439
|
+
var stmts = parser
|
|
440
|
+
.parse("uniform vec4 x,y;\nuniform vec2 x, y[5];\nuniform Light0 { vec4 y; } x;\nuniform Light0 { vec4 x; } y;\n")
|
|
441
|
+
.program.filter(function (s) { return s.type === 'declaration_statement'; });
|
|
442
|
+
var filtered = filterUniformNames(stmts.map(function (x) { return ({ nodeId: '', source: x }); }), function (name) { return name !== 'x'; });
|
|
443
|
+
expect(generate(extractSource(filtered))).toEqual("uniform vec4 y;\nuniform vec2 y[5];\nuniform Light0 { vec4 x; } y;\n");
|
|
444
|
+
});
|
|
445
|
+
it('filterQualifiedStatements', function () {
|
|
446
|
+
var stmts = parser
|
|
447
|
+
.parse("in vec2 x, y;\nout vec2 x;\n")
|
|
448
|
+
.program.filter(function (s) { return s.type === 'declaration_statement'; });
|
|
449
|
+
var filtered = filterQualifiedStatements(stmts.map(function (x) { return ({ nodeId: '', source: x }); }), function (name) { return name !== 'x'; });
|
|
450
|
+
expect(generate(extractSource(filtered))).toEqual("in vec2 y;\n");
|
|
451
|
+
});
|
package/graph/parsers.d.ts
CHANGED
|
@@ -1,22 +1,14 @@
|
|
|
1
1
|
import { AstNode, Program } from '@shaderfrog/glsl-parser/ast';
|
|
2
2
|
import { Engine, EngineContext } from '../engine';
|
|
3
|
+
import { ComputedInput, Filler } from '../strategy';
|
|
3
4
|
import { Edge } from './edge';
|
|
4
5
|
import { SourceNode } from './code-nodes';
|
|
5
|
-
import { NodeInput } from './base-node';
|
|
6
6
|
import { Graph } from './graph-types';
|
|
7
7
|
import { Evaluate } from './evaluate';
|
|
8
|
+
import { NodeContext } from './context';
|
|
8
9
|
export declare const alphabet = "abcdefghijklmnopqrstuvwxyz";
|
|
9
|
-
export type Filler = AstNode | AstNode[] | void;
|
|
10
|
-
export type InputFiller = (filler: Filler) => AstNode | Program;
|
|
11
|
-
export type InputFillerGroup = {
|
|
12
|
-
filler: InputFiller;
|
|
13
|
-
backfillArgs?: AstNode[];
|
|
14
|
-
};
|
|
15
|
-
export type InputFillers = Record<string, InputFillerGroup>;
|
|
16
|
-
type FillerArguments = AstNode[];
|
|
17
|
-
export type ComputedInput = [NodeInput, InputFiller, FillerArguments?];
|
|
18
10
|
export type ProduceAst = (engineContext: EngineContext, engine: Engine, graph: Graph, node: SourceNode, inputEdges: Edge[]) => AstNode | Program;
|
|
19
|
-
export type OnBeforeCompile = (graph: Graph, engineContext: EngineContext, node: SourceNode, sibling?: SourceNode) => Promise<void>;
|
|
11
|
+
export type OnBeforeCompile = (graph: Graph, engineContext: EngineContext, node: SourceNode, sibling?: SourceNode) => Promise<Partial<NodeContext> | void>;
|
|
20
12
|
export type ManipulateAst = (engineContext: EngineContext, engine: Engine, graph: Graph, ast: AstNode | Program, inputEdges: Edge[], node: SourceNode, sibling: SourceNode) => AstNode | Program;
|
|
21
13
|
export type NodeParser = {
|
|
22
14
|
onBeforeCompile?: OnBeforeCompile;
|
|
@@ -24,7 +16,7 @@ export type NodeParser = {
|
|
|
24
16
|
findInputs?: FindInputs;
|
|
25
17
|
produceFiller?: ProduceNodeFiller;
|
|
26
18
|
};
|
|
27
|
-
export type FindInputs = (engineContext: EngineContext, ast: Program | AstNode, inputEdges: Edge[], node: SourceNode, sibling
|
|
19
|
+
export type FindInputs = (engineContext: EngineContext, ast: Program | AstNode, inputEdges: Edge[], node: SourceNode, sibling?: SourceNode) => ComputedInput[];
|
|
28
20
|
export type ProduceNodeFiller = (node: SourceNode, ast: Program | AstNode) => Filler;
|
|
29
21
|
type CoreNodeParser = {
|
|
30
22
|
produceAst: ProduceAst;
|
package/graph/parsers.js
CHANGED
|
@@ -27,13 +27,14 @@ var _a;
|
|
|
27
27
|
import { parser } from '@shaderfrog/glsl-parser';
|
|
28
28
|
import { visit, } from '@shaderfrog/glsl-parser/ast';
|
|
29
29
|
import preprocess from '@shaderfrog/glsl-parser/preprocessor';
|
|
30
|
-
import { convert300MainToReturn, from2To3, makeExpression, makeExpressionWithScopes, makeFnBodyStatementWithScopes,
|
|
30
|
+
import { convert300MainToReturn, findMainOrThrow, from2To3, makeExpression, makeExpressionWithScopes, makeFnBodyStatementWithScopes, } from '../util/ast';
|
|
31
31
|
import { applyStrategy } from '../strategy';
|
|
32
32
|
import { SourceType } from './code-nodes';
|
|
33
33
|
import { nodeInput } from './base-node';
|
|
34
34
|
import { MAGIC_OUTPUT_STMTS, NodeType } from './graph-types';
|
|
35
35
|
import { nodeName } from './graph';
|
|
36
36
|
import { generateFiller } from '../util/ast';
|
|
37
|
+
import { unshiftFnStmtWithIndent } from '../util/whitespace';
|
|
37
38
|
/*
|
|
38
39
|
* Core graph parsers, which is the plumbing/interface the graph and context
|
|
39
40
|
* calls into, to parse, find inputs, etc, and define this per-node type.
|
|
@@ -50,7 +51,11 @@ export var alphabet = 'abcdefghijklmnopqrstuvwxyz';
|
|
|
50
51
|
export var coreParsers = (_a = {},
|
|
51
52
|
_a[NodeType.SOURCE] = {
|
|
52
53
|
produceAst: function (engineContext, engine, graph, node, inputEdges) {
|
|
54
|
+
var _a;
|
|
53
55
|
var ast;
|
|
56
|
+
// Load the source either from the computed source at runtime, or the
|
|
57
|
+
// node's source code itself
|
|
58
|
+
var source = ((_a = engineContext.nodes[node.id]) === null || _a === void 0 ? void 0 : _a.computedSource) || node.source;
|
|
54
59
|
// @ts-ignore
|
|
55
60
|
if (node.expressionOnly) {
|
|
56
61
|
node.sourceType = SourceType.EXPRESSION;
|
|
@@ -58,7 +63,7 @@ export var coreParsers = (_a = {},
|
|
|
58
63
|
delete node.expressionOnly;
|
|
59
64
|
}
|
|
60
65
|
if (node.sourceType === SourceType.FN_BODY_FRAGMENT) {
|
|
61
|
-
var
|
|
66
|
+
var _b = makeFnBodyStatementWithScopes(source), statements = _b.statements, scope = _b.scope;
|
|
62
67
|
ast = {
|
|
63
68
|
type: 'program',
|
|
64
69
|
scopes: [scope],
|
|
@@ -67,7 +72,7 @@ export var coreParsers = (_a = {},
|
|
|
67
72
|
};
|
|
68
73
|
}
|
|
69
74
|
else if (node.sourceType === SourceType.EXPRESSION) {
|
|
70
|
-
var
|
|
75
|
+
var _c = makeExpressionWithScopes(source), expression = _c.expression, scope = _c.scope;
|
|
71
76
|
ast = {
|
|
72
77
|
type: 'program',
|
|
73
78
|
scopes: [scope],
|
|
@@ -77,8 +82,8 @@ export var coreParsers = (_a = {},
|
|
|
77
82
|
}
|
|
78
83
|
else {
|
|
79
84
|
var preprocessed = node.config.preprocess === false
|
|
80
|
-
?
|
|
81
|
-
: preprocess(
|
|
85
|
+
? source
|
|
86
|
+
: preprocess(source, {
|
|
82
87
|
preserve: {
|
|
83
88
|
version: function () { return true; },
|
|
84
89
|
},
|
|
@@ -109,11 +114,20 @@ export var coreParsers = (_a = {},
|
|
|
109
114
|
});
|
|
110
115
|
},
|
|
111
116
|
produceFiller: function (node, ast) {
|
|
112
|
-
return
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
+
return function () {
|
|
118
|
+
var args = [];
|
|
119
|
+
for (var _i = 0; _i < arguments.length; _i++) {
|
|
120
|
+
args[_i] = arguments[_i];
|
|
121
|
+
}
|
|
122
|
+
var fillerNode = node.sourceType === SourceType.EXPRESSION
|
|
123
|
+
? ast.program[0]
|
|
124
|
+
: node.sourceType === SourceType.FN_BODY_FRAGMENT
|
|
125
|
+
? ast.program
|
|
126
|
+
: // Backfilling into the call of this program's filler.
|
|
127
|
+
// Similar to texutre2D.ts filler
|
|
128
|
+
makeExpression("".concat(nodeName(node), "(").concat(args.join(', '), ")"));
|
|
129
|
+
return fillerNode;
|
|
130
|
+
};
|
|
117
131
|
},
|
|
118
132
|
},
|
|
119
133
|
// TODO: Output node assumes strategies are still passed in on node creation,
|
|
@@ -128,16 +142,16 @@ export var coreParsers = (_a = {},
|
|
|
128
142
|
})), false), [
|
|
129
143
|
[
|
|
130
144
|
nodeInput(MAGIC_OUTPUT_STMTS, "filler_".concat(MAGIC_OUTPUT_STMTS), 'filler', 'rgba', ['code'], false),
|
|
131
|
-
function (
|
|
132
|
-
var
|
|
133
|
-
|
|
145
|
+
function (filler) {
|
|
146
|
+
var main = findMainOrThrow(ast);
|
|
147
|
+
main.body.statements = unshiftFnStmtWithIndent(main, generateFiller(filler()));
|
|
134
148
|
return ast;
|
|
135
149
|
},
|
|
136
150
|
],
|
|
137
151
|
], false);
|
|
138
152
|
},
|
|
139
153
|
produceFiller: function (node, ast) {
|
|
140
|
-
return makeExpression('impossible_call()');
|
|
154
|
+
return function () { return makeExpression('impossible_call()'); };
|
|
141
155
|
},
|
|
142
156
|
},
|
|
143
157
|
_a[NodeType.BINARY] = {
|
|
@@ -158,7 +172,7 @@ export var coreParsers = (_a = {},
|
|
|
158
172
|
var letter = alphabet.charAt(index);
|
|
159
173
|
return [
|
|
160
174
|
nodeInput(letter, letter, 'filler', undefined, ['data', 'code'], false),
|
|
161
|
-
function (
|
|
175
|
+
function (filler) {
|
|
162
176
|
var foundPath;
|
|
163
177
|
var visitors = {
|
|
164
178
|
identifier: {
|
|
@@ -175,18 +189,18 @@ export var coreParsers = (_a = {},
|
|
|
175
189
|
}
|
|
176
190
|
if (foundPath.parent && foundPath.key) {
|
|
177
191
|
// @ts-ignore
|
|
178
|
-
foundPath.parent[foundPath.key] =
|
|
192
|
+
foundPath.parent[foundPath.key] = filler();
|
|
179
193
|
return ast;
|
|
180
194
|
}
|
|
181
195
|
else {
|
|
182
|
-
return
|
|
196
|
+
return filler();
|
|
183
197
|
}
|
|
184
198
|
},
|
|
185
199
|
];
|
|
186
200
|
});
|
|
187
201
|
},
|
|
188
202
|
produceFiller: function (node, ast) {
|
|
189
|
-
return ast;
|
|
203
|
+
return function () { return ast; };
|
|
190
204
|
},
|
|
191
205
|
evaluate: function (node, inputEdges, inputNodes, evaluateNode) {
|
|
192
206
|
var operator = node.operator;
|
|
@@ -1,28 +1,45 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Categorizing / deduping parts of shaders to help merge them together
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
4
|
+
import { DeclarationStatementNode, PreprocessorNode, ProgramStatement } from '@shaderfrog/glsl-parser/ast';
|
|
5
5
|
import { Program } from '@shaderfrog/glsl-parser/ast';
|
|
6
|
+
export type LineAndSource<T = any> = {
|
|
7
|
+
nodeId: string;
|
|
8
|
+
source: T;
|
|
9
|
+
};
|
|
10
|
+
export declare function extractSource<T>(lineAndSource: LineAndSource<T>): T;
|
|
11
|
+
export declare function extractSource<T>(lineAndSource: LineAndSource<T>[]): T[];
|
|
6
12
|
export interface ShaderSections {
|
|
7
|
-
precision: DeclarationStatementNode[];
|
|
8
|
-
version:
|
|
9
|
-
preprocessor: PreprocessorNode[];
|
|
10
|
-
structs:
|
|
11
|
-
inStatements: DeclarationStatementNode[];
|
|
12
|
-
outStatements: DeclarationStatementNode[];
|
|
13
|
-
uniforms: DeclarationStatementNode[];
|
|
14
|
-
program:
|
|
13
|
+
precision: LineAndSource<DeclarationStatementNode>[];
|
|
14
|
+
version: LineAndSource<PreprocessorNode>[];
|
|
15
|
+
preprocessor: LineAndSource<PreprocessorNode>[];
|
|
16
|
+
structs: LineAndSource<DeclarationStatementNode>[];
|
|
17
|
+
inStatements: LineAndSource<DeclarationStatementNode>[];
|
|
18
|
+
outStatements: LineAndSource<DeclarationStatementNode>[];
|
|
19
|
+
uniforms: LineAndSource<DeclarationStatementNode>[];
|
|
20
|
+
program: LineAndSource<ProgramStatement>[];
|
|
15
21
|
}
|
|
16
|
-
export declare const
|
|
22
|
+
export declare const filterSections: (filter: (s: LineAndSource) => boolean, sections: ShaderSections) => ShaderSections;
|
|
23
|
+
export declare const mapSections: (map: (s: LineAndSource) => LineAndSource, sections: ShaderSections) => ShaderSections;
|
|
24
|
+
export declare const shaderSectionsCons: () => ShaderSections;
|
|
17
25
|
declare enum Precision {
|
|
18
26
|
highp = 2,
|
|
19
27
|
mediump = 1,
|
|
20
28
|
lowp = 0
|
|
21
29
|
}
|
|
22
30
|
export declare const higherPrecision: (p1: Precision, p2: Precision) => Precision;
|
|
23
|
-
export declare const dedupeVersions: (nodes:
|
|
31
|
+
export declare const dedupeVersions: (nodes: PreprocessorNode[]) => PreprocessorNode;
|
|
24
32
|
export declare const highestPrecisions: (nodes: DeclarationStatementNode[]) => DeclarationStatementNode[];
|
|
25
|
-
export declare const
|
|
33
|
+
export declare const extractDeclarationNameAndType: (stmt: DeclarationStatementNode) => {
|
|
34
|
+
type: string;
|
|
35
|
+
names: string[];
|
|
36
|
+
};
|
|
37
|
+
export declare const filterQualifiedStatements: (statements: LineAndSource<DeclarationStatementNode>[], filter: (name: string) => boolean) => LineAndSource<DeclarationStatementNode>[];
|
|
38
|
+
export declare const dedupeQualifiedStatements: (statements: DeclarationStatementNode[], qualifier: string) => ProgramStatement[];
|
|
39
|
+
/**
|
|
40
|
+
* Remove uniform declarations by the variable names they declare
|
|
41
|
+
*/
|
|
42
|
+
export declare const filterUniformNames: (declarations: LineAndSource<DeclarationStatementNode>[], filter: (name: string) => boolean) => LineAndSource<DeclarationStatementNode>[];
|
|
26
43
|
/**
|
|
27
44
|
* Merge uniforms together into lists of identifiers under the same type.
|
|
28
45
|
* There's special case handling for mixing of uniforms with "interface blocks"
|
|
@@ -32,7 +49,7 @@ export declare const dedupeQualifiedStatements: (statements: DeclarationStatemen
|
|
|
32
49
|
* This function consumes uniforms as found by findShaderSections, so the
|
|
33
50
|
* definitions must line up
|
|
34
51
|
*/
|
|
35
|
-
export declare const dedupeUniforms: (statements: DeclarationStatementNode[]) =>
|
|
52
|
+
export declare const dedupeUniforms: (statements: DeclarationStatementNode[]) => DeclarationStatementNode[];
|
|
36
53
|
export declare const mergeShaderSections: (s1: ShaderSections, s2: ShaderSections) => ShaderSections;
|
|
37
54
|
export type MergeOptions = {
|
|
38
55
|
includePrecisions: boolean;
|
|
@@ -43,5 +60,5 @@ export declare const shaderSectionsToProgram: (sections: ShaderSections, mergeOp
|
|
|
43
60
|
* Group an AST into logical sections. The output of this funciton is consumed
|
|
44
61
|
* by the dedupe methods, namely dedupeUniforms, so the data shapes are coupled
|
|
45
62
|
*/
|
|
46
|
-
export declare const findShaderSections: (ast: Program) => ShaderSections;
|
|
63
|
+
export declare const findShaderSections: (nodeId: string, ast: Program) => ShaderSections;
|
|
47
64
|
export {};
|