@shaderfrog/core 2.0.0-beta.3 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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) {
@@ -41,12 +52,14 @@ import { generate } from '@shaderfrog/glsl-parser';
41
52
  import { addNode, outputNode, sourceNode } from './graph-node';
42
53
  import { shaderSectionsToProgram, mergeShaderSections, findShaderSections, } 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
  };
@@ -65,9 +78,7 @@ var dedupe = function (code) {
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(id(), 'Output v', p, 'vertex');
146
- outF = outputNode(id(), 'Output f', p, 'fragment');
147
- imageReplacemMe = makeSourceNode(id(), "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');
148
- input1 = makeSourceNode(id(), "float a = 1.0;\nvoid main() {\n gl_FragColor = vec4(0.0);\n}\n", 'fragment');
149
- input2 = makeSourceNode(id(), "float a = 2.0;\nvoid main() {\n gl_FragColor = vec4(1.0);\n}\n", 'fragment');
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(id(), imageReplacemMe.id, outF.id, 'out', 'filler_frogFragOut', 'fragment'),
154
- makeEdge(id(), input1.id, imageReplacemMe.id, 'out', 'filler_image1', 'fragment'),
155
- makeEdge(id(), input2.id, imageReplacemMe.id, 'out', 'filler_image2', 'fragment'),
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(id(), 'Output v', p, 'vertex');
187
- outF = outputNode(id(), 'Output f', p, 'fragment');
188
- imageReplacemMe = makeSourceNode(id(), "float a = 1.0;\nvoid main() {\n gl_FragColor = vec4(1.0);\n}\n", 'fragment');
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(id(), imageReplacemMe.id, outF.id, 'out', 'filler_frogFragOut', 'fragment'),
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(id(), p);
218
- var add2 = addNode(id(), p);
219
- var num1 = numberNode(id(), 'number', p, '3');
220
- var num2 = numberNode(id(), 'number', p, '5');
221
- var num3 = numberNode(id(), 'number', p, '7');
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(id(), num1.id, finalAdd.id, 'out', 'a'),
226
- makeEdge(id(), add2.id, finalAdd.id, 'out', 'b'),
227
- makeEdge(id(), num2.id, add2.id, 'out', 'a'),
228
- makeEdge(id(), num3.id, add2.id, 'out', 'b'),
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);
@@ -1,20 +1,11 @@
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
8
  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
9
  export type ProduceAst = (engineContext: EngineContext, engine: Engine, graph: Graph, node: SourceNode, inputEdges: Edge[]) => AstNode | Program;
19
10
  export type OnBeforeCompile = (graph: Graph, engineContext: EngineContext, node: SourceNode, sibling?: SourceNode) => Promise<void>;
20
11
  export type ManipulateAst = (engineContext: EngineContext, engine: Engine, graph: Graph, ast: AstNode | Program, inputEdges: Edge[], node: SourceNode, sibling: SourceNode) => AstNode | Program;
@@ -24,7 +15,7 @@ export type NodeParser = {
24
15
  findInputs?: FindInputs;
25
16
  produceFiller?: ProduceNodeFiller;
26
17
  };
27
- export type FindInputs = (engineContext: EngineContext, ast: Program | AstNode, inputEdges: Edge[], node: SourceNode, sibling: SourceNode) => ComputedInput[];
18
+ export type FindInputs = (engineContext: EngineContext, ast: Program | AstNode, inputEdges: Edge[], node: SourceNode, sibling?: SourceNode) => ComputedInput[];
28
19
  export type ProduceNodeFiller = (node: SourceNode, ast: Program | AstNode) => Filler;
29
20
  type CoreNodeParser = {
30
21
  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, makeFnStatement, } from '../util/ast';
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.
@@ -109,11 +110,20 @@ export var coreParsers = (_a = {},
109
110
  });
110
111
  },
111
112
  produceFiller: function (node, ast) {
112
- return node.sourceType === SourceType.EXPRESSION
113
- ? ast.program[0]
114
- : node.sourceType === SourceType.FN_BODY_FRAGMENT
115
- ? ast.program
116
- : makeExpression("".concat(nodeName(node), "()"));
113
+ return function () {
114
+ var args = [];
115
+ for (var _i = 0; _i < arguments.length; _i++) {
116
+ args[_i] = arguments[_i];
117
+ }
118
+ var fillerNode = node.sourceType === SourceType.EXPRESSION
119
+ ? ast.program[0]
120
+ : node.sourceType === SourceType.FN_BODY_FRAGMENT
121
+ ? ast.program
122
+ : // Backfilling into the call of this program's filler.
123
+ // Similar to texutre2D.ts filler
124
+ makeExpression("".concat(nodeName(node), "(").concat(args.join(', '), ")"));
125
+ return fillerNode;
126
+ };
117
127
  },
118
128
  },
119
129
  // TODO: Output node assumes strategies are still passed in on node creation,
@@ -128,16 +138,16 @@ export var coreParsers = (_a = {},
128
138
  })), false), [
129
139
  [
130
140
  nodeInput(MAGIC_OUTPUT_STMTS, "filler_".concat(MAGIC_OUTPUT_STMTS), 'filler', 'rgba', ['code'], false),
131
- function (fillerAst) {
132
- var fn = ast.program.find(function (stmt) { return stmt.type === 'function'; });
133
- fn === null || fn === void 0 ? void 0 : fn.body.statements.unshift(makeFnStatement(generateFiller(fillerAst))[0]);
141
+ function (filler) {
142
+ var main = findMainOrThrow(ast);
143
+ main.body.statements = unshiftFnStmtWithIndent(main, generateFiller(filler()));
134
144
  return ast;
135
145
  },
136
146
  ],
137
147
  ], false);
138
148
  },
139
149
  produceFiller: function (node, ast) {
140
- return makeExpression('impossible_call()');
150
+ return function () { return makeExpression('impossible_call()'); };
141
151
  },
142
152
  },
143
153
  _a[NodeType.BINARY] = {
@@ -158,7 +168,7 @@ export var coreParsers = (_a = {},
158
168
  var letter = alphabet.charAt(index);
159
169
  return [
160
170
  nodeInput(letter, letter, 'filler', undefined, ['data', 'code'], false),
161
- function (fillerAst) {
171
+ function (filler) {
162
172
  var foundPath;
163
173
  var visitors = {
164
174
  identifier: {
@@ -175,18 +185,18 @@ export var coreParsers = (_a = {},
175
185
  }
176
186
  if (foundPath.parent && foundPath.key) {
177
187
  // @ts-ignore
178
- foundPath.parent[foundPath.key] = fillerAst;
188
+ foundPath.parent[foundPath.key] = filler();
179
189
  return ast;
180
190
  }
181
191
  else {
182
- return fillerAst;
192
+ return filler();
183
193
  }
184
194
  },
185
195
  ];
186
196
  });
187
197
  },
188
198
  produceFiller: function (node, ast) {
189
- return ast;
199
+ return function () { return ast; };
190
200
  },
191
201
  evaluate: function (node, inputEdges, inputNodes, evaluateNode) {
192
202
  var operator = node.operator;
@@ -13,7 +13,7 @@ export interface ShaderSections {
13
13
  uniforms: DeclarationStatementNode[];
14
14
  program: AstNode[];
15
15
  }
16
- export declare const emptyShaderSections: () => ShaderSections;
16
+ export declare const shaderSectionsCons: () => ShaderSections;
17
17
  declare enum Precision {
18
18
  highp = 2,
19
19
  mediump = 1,
@@ -36,7 +36,7 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
36
36
  };
37
37
  import { generate } from '@shaderfrog/glsl-parser';
38
38
  import { makeStatement } from '../util/ast';
39
- export var emptyShaderSections = function () { return ({
39
+ export var shaderSectionsCons = function () { return ({
40
40
  precision: [],
41
41
  preprocessor: [],
42
42
  version: [],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shaderfrog/core",
3
- "version": "2.0.0-beta.3",
3
+ "version": "2.0.1",
4
4
  "description": "Shaderfrog core",
5
5
  "type": "module",
6
6
  "files": [
@@ -34,13 +34,13 @@
34
34
  "@babel/core": "^7.21.8",
35
35
  "@babel/preset-env": "^7.21.5",
36
36
  "@babel/preset-typescript": "^7.21.5",
37
- "@shaderfrog/glsl-parser": "^5.0.0-beta.4",
37
+ "@shaderfrog/glsl-parser": "^5.2.0",
38
38
  "@swc/core": "^1.6.7",
39
39
  "@types/lodash.groupby": "^4.6.7",
40
- "@types/three": "^0.156.0",
40
+ "@types/three": "^0.169.0",
41
41
  "babylonjs": "^6.2.0",
42
42
  "prettier": "^3.3.2",
43
- "three": "^0.156.1",
43
+ "three": "^0.169.0",
44
44
  "typescript": "^5.5.3",
45
45
  "vitest": "^1.6.0"
46
46
  },
@@ -531,7 +531,6 @@ export var babylengine = {
531
531
  'normal',
532
532
  'uv',
533
533
  'world',
534
- 'time',
535
534
  'Light0',
536
535
  'Light1',
537
536
  'Light2',
@@ -555,6 +554,10 @@ export var babylengine = {
555
554
  'vSphericalL22',
556
555
  'vAlbedoInfos',
557
556
  'reflectionSampler',
557
+ // passed by shaderfrog. maybe should have separate names? duplicated across
558
+ // all the engines.
559
+ 'time',
560
+ 'renderResolution',
558
561
  ]),
559
562
  parsers: (_b = {},
560
563
  _b[NodeType.SOURCE] = {
@@ -472,7 +472,6 @@ export var playengine = {
472
472
  'matrix_normal',
473
473
  'matrix_view',
474
474
  'matrix_viewProjection',
475
- 'time',
476
475
  'vertex_color',
477
476
  'vertex_normal',
478
477
  'vertex_position',
@@ -483,6 +482,10 @@ export var playengine = {
483
482
  'vNormalW',
484
483
  'vPositionW',
485
484
  'vUv0',
485
+ // passed by shaderfrog. maybe should have separate names? duplicated across
486
+ // all the engines.
487
+ 'time',
488
+ 'renderResolution',
486
489
  ]),
487
490
  parsers: (_b = {},
488
491
  _b[NodeType.SOURCE] = {
@@ -1,3 +1,4 @@
1
1
  import { EngineImporters } from '../../engine';
2
+ export declare const defaultShadertoyVertex = "\nprecision highp float;\nprecision highp int;\n\nattribute vec3 position;\nattribute vec2 uv;\nvarying vec2 vUv;\n\nvoid main() {\n vUv = uv;\n gl_Position = vec4(position * 2.0, 1.0);\n}\n";
2
3
  declare const importers: EngineImporters;
3
4
  export default importers;
@@ -1,5 +1,53 @@
1
- import { renameBindings } from '@shaderfrog/glsl-parser/parser/utils';
1
+ import { renameBindings, renameFunction, } from '@shaderfrog/glsl-parser/parser/utils';
2
+ import { findMainOrThrow, makeStatement } from '../../util/ast';
3
+ export var defaultShadertoyVertex = "\nprecision highp float;\nprecision highp int;\n\nattribute vec3 position;\nattribute vec2 uv;\nvarying vec2 vUv;\n\nvoid main() {\n vUv = uv;\n gl_Position = vec4(position * 2.0, 1.0);\n}\n";
2
4
  var importers = {
5
+ shadertoy: {
6
+ code: {
7
+ defaultShadertoyVertex: defaultShadertoyVertex,
8
+ },
9
+ convertAst: function (ast, type) {
10
+ ast.program.unshift(makeStatement('uniform vec2 renderResolution', '\n')[0]);
11
+ // These do not catch variables in preprocessor definitions! See "SAD HACK"
12
+ //if (ast.scopes.some((s) => 'iTime' in s.bindings)) {
13
+ ast.program.unshift(makeStatement('uniform float time')[0]);
14
+ //}
15
+ //if (ast.scopes.some((s) => 'iMouse' in s.bindings)) {
16
+ ast.program.unshift(makeStatement('uniform vec2 mouse')[0]);
17
+ //}
18
+ ast.program.unshift(makeStatement('precision highp int', '\n')[0]);
19
+ ast.program.unshift(makeStatement('precision highp float')[0]);
20
+ ast.scopes[0].functions.main = renameFunction(ast.scopes[0].functions.mainImage, 'main');
21
+ var main = findMainOrThrow(ast);
22
+ main.prototype.parameters = [];
23
+ main.prototype.header.lp.whitespace = '';
24
+ main.prototype.rp.whitespace = ' ';
25
+ // These renames do not catch variables in preprocessor definitions! See
26
+ // "SAD HACK" comment in Editor.tsx
27
+ for (var i = 0; i < ast.scopes.length; i++) {
28
+ ast.scopes[i].bindings = renameBindings(ast.scopes[i].bindings, function (name) {
29
+ if (name === 'iTime') {
30
+ return 'time';
31
+ }
32
+ if (name === 'iMouse') {
33
+ return 'mouse';
34
+ }
35
+ if (name === 'iResolution') {
36
+ return 'renderResolution';
37
+ }
38
+ if (name === 'fragColor') {
39
+ return 'gl_FragColor';
40
+ }
41
+ if (name === 'fragCoord') {
42
+ return 'gl_FragCoord.xy';
43
+ }
44
+ return name;
45
+ });
46
+ }
47
+ },
48
+ nodeInputMap: {},
49
+ edgeMap: {},
50
+ },
3
51
  babylon: {
4
52
  convertAst: function (ast, type) {
5
53
  ast.scopes[0].bindings = renameBindings(ast.scopes[0].bindings, function (name) {
@@ -460,7 +460,6 @@ export var threngine = {
460
460
  'opacity',
461
461
  'map',
462
462
  'specularTint',
463
- 'time',
464
463
  'normalScale',
465
464
  'normalMap',
466
465
  'envMap',
@@ -502,6 +501,10 @@ export var threngine = {
502
501
  'displacementMap',
503
502
  'displacementScale',
504
503
  'displacementBias',
504
+ // passed by shaderfrog. maybe should have separate names? duplicated across
505
+ // all the engines.
506
+ 'time',
507
+ 'renderResolution',
505
508
  ]),
506
509
  parsers: (_b = {},
507
510
  _b[NodeType.SOURCE] = {
@@ -561,7 +564,7 @@ export var threngine = {
561
564
  };
562
565
  export var createMaterial = function (compileResult, ctx) {
563
566
  var engineMaterial = ctx.runtime.engineMaterial;
564
- var finalUniforms = __assign(__assign(__assign(__assign({}, ShaderLib.phong.uniforms), ShaderLib.toon.uniforms), ShaderLib.physical.uniforms), { time: { value: 0 }, cameraPosition: { value: new Vector3(1.0) } });
567
+ var finalUniforms = __assign(__assign(__assign(__assign({}, ShaderLib.phong.uniforms), ShaderLib.toon.uniforms), ShaderLib.physical.uniforms), { time: { value: 0 }, cameraPosition: { value: new Vector3(1.0) }, renderResolution: { value: new Vector2(1.0) } });
565
568
  // Also the ThreeComponent's sceneConfig properties modify the material
566
569
  var initialProperties = {
567
570
  name: 'ShaderFrog Material',