@shaderfrog/core 0.0.2 → 0.1.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.
- package/README.md +184 -1
- package/dist/ast/manipulate.js +328 -0
- package/dist/ast/shader-sections.js +256 -0
- package/dist/context.js +230 -0
- package/dist/engine.js +209 -0
- package/dist/evaluate.js +27 -0
- package/dist/graph-types.js +7 -0
- package/dist/graph.js +381 -0
- package/dist/graph.test.js +168 -0
- package/dist/nodes/code-nodes.js +18 -0
- package/dist/nodes/core-node.js +9 -0
- package/dist/nodes/data-nodes.js +123 -0
- package/dist/nodes/edge.js +1 -0
- package/dist/nodes/engine-node.js +189 -0
- package/dist/parsers.js +213 -0
- package/dist/plugins/babylon/bablyengine.js +582 -0
- package/dist/plugins/babylon/importers.js +64 -0
- package/{src/plugins/babylon/index.ts → dist/plugins/babylon/index.js} +0 -1
- package/dist/plugins/playcanvas/importers.js +28 -0
- package/dist/plugins/playcanvas/index.js +2 -0
- package/dist/plugins/playcanvas/playengine.js +510 -0
- package/dist/plugins/three/importers.js +15 -0
- package/{src/plugins/three/index.ts → dist/plugins/three/index.js} +0 -1
- package/dist/plugins/three/threngine.js +495 -0
- package/dist/strategy/assignemntTo.js +26 -0
- package/dist/strategy/declarationOf.js +23 -0
- package/dist/strategy/hardCode.js +23 -0
- package/dist/strategy/index.js +38 -0
- package/dist/strategy/inject.js +122 -0
- package/dist/strategy/namedAttribute.js +48 -0
- package/dist/strategy/texture2D.js +83 -0
- package/dist/strategy/uniform.js +190 -0
- package/dist/strategy/variable.js +80 -0
- package/dist/stratgies.test.js +164 -0
- package/dist/util/ast.js +9 -0
- package/dist/util/ensure.js +7 -0
- package/dist/util/id.js +2 -0
- package/package.json +12 -4
- package/src/ast/manipulate.ts +0 -392
- package/src/ast/shader-sections.ts +0 -323
- package/src/core/engine.ts +0 -214
- package/src/core/file.js +0 -53
- package/src/core/graph.ts +0 -1007
- package/src/core/nodes/code-nodes.ts +0 -66
- package/src/core/nodes/core-node.ts +0 -48
- package/src/core/nodes/data-nodes.ts +0 -344
- package/src/core/nodes/edge.ts +0 -23
- package/src/core/nodes/engine-node.ts +0 -266
- package/src/core/strategy.ts +0 -520
- package/src/core.test.ts +0 -312
- package/src/plugins/babylon/bablyengine.ts +0 -670
- package/src/plugins/babylon/importers.ts +0 -69
- package/src/plugins/three/importers.ts +0 -18
- package/src/plugins/three/threngine.tsx +0 -571
- package/src/util/ensure.ts +0 -10
- package/src/util/id.ts +0 -2
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
var __read = (this && this.__read) || function (o, n) {
|
|
2
|
+
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
3
|
+
if (!m) return o;
|
|
4
|
+
var i = m.call(o), r, ar = [], e;
|
|
5
|
+
try {
|
|
6
|
+
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
7
|
+
}
|
|
8
|
+
catch (error) { e = { error: error }; }
|
|
9
|
+
finally {
|
|
10
|
+
try {
|
|
11
|
+
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
12
|
+
}
|
|
13
|
+
finally { if (e) throw e.error; }
|
|
14
|
+
}
|
|
15
|
+
return ar;
|
|
16
|
+
};
|
|
17
|
+
import { parser } from '@shaderfrog/glsl-parser';
|
|
18
|
+
import { generate } from '@shaderfrog/glsl-parser';
|
|
19
|
+
import { applyStrategy, StrategyType } from './strategy';
|
|
20
|
+
import * as graphModule from './graph';
|
|
21
|
+
import { makeExpression } from './ast/manipulate';
|
|
22
|
+
import preprocess from '@shaderfrog/glsl-parser/preprocessor';
|
|
23
|
+
var orig;
|
|
24
|
+
beforeEach(function () {
|
|
25
|
+
orig = graphModule.mangleName;
|
|
26
|
+
// Terrible hack. in the real world, strategies are applied after mangling
|
|
27
|
+
// @ts-ignore
|
|
28
|
+
graphModule.mangleName = function (name) { return name; };
|
|
29
|
+
});
|
|
30
|
+
afterEach(function () {
|
|
31
|
+
// @ts-ignore
|
|
32
|
+
graphModule.mangleName = orig;
|
|
33
|
+
});
|
|
34
|
+
it('named attribute strategy`', function () {
|
|
35
|
+
var source = "\nin vec3 replaceThisAtrribute;\nvoid main() {\n vec2 y = replaceThisAtrribute;\n}\n";
|
|
36
|
+
var ast = parser.parse(source, { quiet: true });
|
|
37
|
+
var fillers = applyStrategy({
|
|
38
|
+
type: StrategyType.NAMED_ATTRIBUTE,
|
|
39
|
+
config: {
|
|
40
|
+
attributeName: 'replaceThisAtrribute',
|
|
41
|
+
},
|
|
42
|
+
}, { source: source }, ast);
|
|
43
|
+
expect(fillers.length).toBe(1);
|
|
44
|
+
fillers[0][1]({
|
|
45
|
+
type: 'literal',
|
|
46
|
+
literal: "myFiller()",
|
|
47
|
+
whitespace: '',
|
|
48
|
+
});
|
|
49
|
+
var result = generate(ast);
|
|
50
|
+
// Should replace the use of the filler, but not the declaration
|
|
51
|
+
expect(result).toBe("\nin vec3 replaceThisAtrribute;\nvoid main() {\n vec2 y = myFiller();\n}\n");
|
|
52
|
+
});
|
|
53
|
+
it('inject strategy after', function () {
|
|
54
|
+
var source = "\nuniform float x;\n// Some comment\nvoid main() {\n/* some comment */\nre(x, y, z);\n// Middle comment\nre(x, y, z);\n// Final comment\n}";
|
|
55
|
+
var ast = parser.parse(source, { quiet: true });
|
|
56
|
+
var fillers = applyStrategy({
|
|
57
|
+
type: StrategyType.INJECT,
|
|
58
|
+
config: {
|
|
59
|
+
find: 're(x, y, z);',
|
|
60
|
+
insert: 'after',
|
|
61
|
+
count: Infinity,
|
|
62
|
+
},
|
|
63
|
+
}, { source: source }, ast);
|
|
64
|
+
expect(fillers.length).toBe(1);
|
|
65
|
+
fillers[0][1]({
|
|
66
|
+
type: 'literal',
|
|
67
|
+
literal: "someOtherCall(x, y, z);\nsomeOtherCall(x, y, z);",
|
|
68
|
+
whitespace: '',
|
|
69
|
+
});
|
|
70
|
+
var result = generate(ast);
|
|
71
|
+
// Should fill references
|
|
72
|
+
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}");
|
|
73
|
+
});
|
|
74
|
+
it('inject strategy before', function () {
|
|
75
|
+
var source = "\nuniform float x;\n// Some comment\nvoid main() {\n/* some comment */\nre(x, y, z);\n// Middle comment\nre(x, y, z);\n// Final comment\n}";
|
|
76
|
+
var ast = parser.parse(source, { quiet: true });
|
|
77
|
+
var fillers = applyStrategy({
|
|
78
|
+
type: StrategyType.INJECT,
|
|
79
|
+
config: {
|
|
80
|
+
find: 're(x, y, z);',
|
|
81
|
+
insert: 'before',
|
|
82
|
+
count: Infinity,
|
|
83
|
+
},
|
|
84
|
+
}, { source: source }, ast);
|
|
85
|
+
expect(fillers.length).toBe(1);
|
|
86
|
+
fillers[0][1]({
|
|
87
|
+
type: 'literal',
|
|
88
|
+
literal: "someOtherCall(x, y, z);\nsomeOtherCall(x, y, z);",
|
|
89
|
+
whitespace: '\n',
|
|
90
|
+
});
|
|
91
|
+
var result = generate(ast);
|
|
92
|
+
// Should fill references
|
|
93
|
+
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}");
|
|
94
|
+
});
|
|
95
|
+
it('correctly fills with uniform strategy', function () {
|
|
96
|
+
var _a, _b, _c;
|
|
97
|
+
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 });
|
|
98
|
+
var fillers = applyStrategy({ type: StrategyType.UNIFORM, config: {} }, {}, ast);
|
|
99
|
+
// It should find uniforms with simple types, excluding sampler2D
|
|
100
|
+
expect(fillers.map(function (_a) {
|
|
101
|
+
var _b = __read(_a, 1), name = _b[0].displayName;
|
|
102
|
+
return name;
|
|
103
|
+
})).toEqual([
|
|
104
|
+
'image',
|
|
105
|
+
'input',
|
|
106
|
+
'output',
|
|
107
|
+
'other',
|
|
108
|
+
'zenput',
|
|
109
|
+
]);
|
|
110
|
+
(_a = fillers.find(function (_a) {
|
|
111
|
+
var _b = __read(_a, 1), name = _b[0].displayName;
|
|
112
|
+
return name === 'input';
|
|
113
|
+
})) === null || _a === void 0 ? void 0 : _a[1](makeExpression('a'));
|
|
114
|
+
(_b = fillers.find(function (_a) {
|
|
115
|
+
var _b = __read(_a, 1), name = _b[0].displayName;
|
|
116
|
+
return name === 'output';
|
|
117
|
+
})) === null || _b === void 0 ? void 0 : _b[1](makeExpression('b'));
|
|
118
|
+
(_c = fillers.find(function (_a) {
|
|
119
|
+
var _b = __read(_a, 1), name = _b[0].displayName;
|
|
120
|
+
return name === 'zenput';
|
|
121
|
+
})) === null || _c === void 0 ? void 0 : _c[1](makeExpression('c'));
|
|
122
|
+
var result = generate(ast);
|
|
123
|
+
// Should fill references
|
|
124
|
+
expect(result).toContain('vec4 x = a;');
|
|
125
|
+
expect(result).toContain('vec4 y = b;');
|
|
126
|
+
expect(result).toContain('vec4 z = c;');
|
|
127
|
+
// Should preserve things it shouldn't touch
|
|
128
|
+
expect(result).toContain('layout(std140,column_major) uniform;');
|
|
129
|
+
expect(result).toContain('uniform sampler2D image;');
|
|
130
|
+
expect(result).toContain('uniform Light0 { vec4 y; } x;');
|
|
131
|
+
// Should remove uniforms from declarator list
|
|
132
|
+
expect(result).toContain('uniform vec4 other;');
|
|
133
|
+
// Should remove uniform lines
|
|
134
|
+
expect(result).not.toContain('uniform vec4 zenput');
|
|
135
|
+
});
|
|
136
|
+
it('uses name without suffix for single call', function () {
|
|
137
|
+
var ast = parser.parse("\nvoid main() {\n vec4 computed = texture2D(noiseImage, uvPow * 1.0);\n}", { quiet: true });
|
|
138
|
+
expect(applyStrategy({ type: StrategyType.TEXTURE_2D, config: {} }, {}, ast).map(function (_a) {
|
|
139
|
+
var _b = __read(_a, 1), name = _b[0].displayName;
|
|
140
|
+
return name;
|
|
141
|
+
})).toEqual(['noiseImage']);
|
|
142
|
+
});
|
|
143
|
+
it('finds multiple texture2D inputs for one uniform', function () {
|
|
144
|
+
var ast = parser.parse("\nvoid main() {\n vec4 computed = texture2D(noiseImage, uvPow * 1.0);\n computed += texture2D(noiseImage, uvPow * 2.0);\n}", { quiet: true });
|
|
145
|
+
expect(applyStrategy({ type: StrategyType.TEXTURE_2D, config: {} }, {}, ast).map(function (_a) {
|
|
146
|
+
var _b = __read(_a, 1), name = _b[0].displayName;
|
|
147
|
+
return name;
|
|
148
|
+
})).toEqual(['noiseImage_0', 'noiseImage_1']);
|
|
149
|
+
});
|
|
150
|
+
it('Make sure texture2D finds preprocessed texture() call', function () {
|
|
151
|
+
// I thought this was a regression, but it wasn't a real bug, but tests seems
|
|
152
|
+
// benign to keep anyway
|
|
153
|
+
var program = "\n#define texture2DBias texture\n\nuniform sampler2D normalMap;\n\nvoid getNormal() {\n vec3 normalMap = unpackNormal(texture2DBias(normalMap, vUv0, textureBias));\n}";
|
|
154
|
+
var pp = preprocess(program, {
|
|
155
|
+
preserve: {
|
|
156
|
+
version: function () { return true; },
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
var ast = parser.parse(pp, { quiet: true });
|
|
160
|
+
expect(applyStrategy({ type: StrategyType.TEXTURE_2D, config: {} }, {}, ast).map(function (_a) {
|
|
161
|
+
var _b = __read(_a, 1), name = _b[0].displayName;
|
|
162
|
+
return name;
|
|
163
|
+
})).toEqual(['normalMapx']);
|
|
164
|
+
});
|
package/dist/util/ast.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { generate } from '@shaderfrog/glsl-parser';
|
|
2
|
+
export var generateFiller = function (filler) {
|
|
3
|
+
if (!filler) {
|
|
4
|
+
throw new Error('Cannot generate void filler!');
|
|
5
|
+
}
|
|
6
|
+
return Array.isArray(filler)
|
|
7
|
+
? filler.map(generate).join('')
|
|
8
|
+
: generate(filler);
|
|
9
|
+
};
|
package/dist/util/id.js
ADDED
package/package.json
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shaderfrog/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Shaderfrog core",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"
|
|
7
|
+
"prepare": "npm run build",
|
|
8
|
+
"build": "./build.sh",
|
|
9
|
+
"watch-test": "jest --watch",
|
|
10
|
+
"test": "jest --colors"
|
|
8
11
|
},
|
|
9
12
|
"repository": {
|
|
10
13
|
"type": "git",
|
|
@@ -13,7 +16,7 @@
|
|
|
13
16
|
"author": "Andrew Ray",
|
|
14
17
|
"license": "ISC",
|
|
15
18
|
"files": [
|
|
16
|
-
"
|
|
19
|
+
"dist"
|
|
17
20
|
],
|
|
18
21
|
"bugs": {
|
|
19
22
|
"url": "https://github.com/ShaderFrog/core/issues"
|
|
@@ -37,8 +40,10 @@
|
|
|
37
40
|
"lodash.groupby": "^4.6.0"
|
|
38
41
|
},
|
|
39
42
|
"peerDependencies": {
|
|
43
|
+
"@shaderfrog/glsl-parser": "^2.0.0-beta.5",
|
|
40
44
|
"babylonjs": ">=4",
|
|
41
|
-
"three": ">=0.50"
|
|
45
|
+
"three": ">=0.50",
|
|
46
|
+
"playcanvas": "^1.65.3"
|
|
42
47
|
},
|
|
43
48
|
"peerDependenciesMeta": {
|
|
44
49
|
"babylonjs": {
|
|
@@ -46,6 +51,9 @@
|
|
|
46
51
|
},
|
|
47
52
|
"three": {
|
|
48
53
|
"optional": true
|
|
54
|
+
},
|
|
55
|
+
"playcanvas": {
|
|
56
|
+
"optional": true
|
|
49
57
|
}
|
|
50
58
|
}
|
|
51
59
|
}
|
package/src/ast/manipulate.ts
DELETED
|
@@ -1,392 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Utility functions to work with ASTs
|
|
3
|
-
*/
|
|
4
|
-
import { parser, generate } from '@shaderfrog/glsl-parser';
|
|
5
|
-
import {
|
|
6
|
-
visit,
|
|
7
|
-
AstNode,
|
|
8
|
-
NodeVisitors,
|
|
9
|
-
ExpressionStatementNode,
|
|
10
|
-
FunctionNode,
|
|
11
|
-
AssignmentNode,
|
|
12
|
-
DeclarationStatementNode,
|
|
13
|
-
KeywordNode,
|
|
14
|
-
DeclarationNode,
|
|
15
|
-
} from '@shaderfrog/glsl-parser/ast';
|
|
16
|
-
import { Program } from '@shaderfrog/glsl-parser/ast';
|
|
17
|
-
import { ShaderStage } from '../core/graph';
|
|
18
|
-
|
|
19
|
-
export const findVec4Constructor = (ast: AstNode): AstNode | undefined => {
|
|
20
|
-
let parent: AstNode | undefined;
|
|
21
|
-
const visitors: NodeVisitors = {
|
|
22
|
-
function_call: {
|
|
23
|
-
enter: (path) => {
|
|
24
|
-
if (
|
|
25
|
-
'specifier' in path.node.identifier &&
|
|
26
|
-
path.node.identifier?.specifier?.token === 'vec4'
|
|
27
|
-
) {
|
|
28
|
-
parent = path.findParent((p) => 'right' in p.node)?.node;
|
|
29
|
-
path.skip();
|
|
30
|
-
}
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
};
|
|
34
|
-
visit(ast, visitors);
|
|
35
|
-
return parent;
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
export const findAssignmentTo = (
|
|
39
|
-
ast: AstNode | Program,
|
|
40
|
-
assignTo: string
|
|
41
|
-
): ExpressionStatementNode | undefined => {
|
|
42
|
-
let assign: ExpressionStatementNode | undefined;
|
|
43
|
-
const visitors: NodeVisitors = {
|
|
44
|
-
expression_statement: {
|
|
45
|
-
enter: (path) => {
|
|
46
|
-
if (path.node.expression?.left?.identifier === assignTo) {
|
|
47
|
-
assign = path.node;
|
|
48
|
-
}
|
|
49
|
-
path.skip();
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
};
|
|
53
|
-
visit(ast, visitors);
|
|
54
|
-
return assign;
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
export const findDeclarationOf = (
|
|
58
|
-
ast: AstNode | Program,
|
|
59
|
-
declarationOf: string
|
|
60
|
-
): DeclarationNode | undefined => {
|
|
61
|
-
let declaration: DeclarationNode | undefined;
|
|
62
|
-
const visitors: NodeVisitors = {
|
|
63
|
-
declaration_statement: {
|
|
64
|
-
enter: (path) => {
|
|
65
|
-
const foundDecl = path.node.declaration?.declarations?.find(
|
|
66
|
-
(decl: any) => decl?.identifier?.identifier === declarationOf
|
|
67
|
-
);
|
|
68
|
-
if (foundDecl) {
|
|
69
|
-
declaration = foundDecl;
|
|
70
|
-
}
|
|
71
|
-
path.skip();
|
|
72
|
-
},
|
|
73
|
-
},
|
|
74
|
-
};
|
|
75
|
-
visit(ast, visitors);
|
|
76
|
-
return declaration;
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
export const from2To3 = (ast: Program, stage: ShaderStage) => {
|
|
80
|
-
const glOut = 'fragmentColor';
|
|
81
|
-
// TODO: add this back in when there's only one after the merge
|
|
82
|
-
// ast.program.unshift({
|
|
83
|
-
// type: 'preprocessor',
|
|
84
|
-
// line: '#version 300 es',
|
|
85
|
-
// _: '\n',
|
|
86
|
-
// });
|
|
87
|
-
if (stage === 'fragment') {
|
|
88
|
-
ast.program.unshift({
|
|
89
|
-
type: 'declaration_statement',
|
|
90
|
-
declaration: {
|
|
91
|
-
type: 'declarator_list',
|
|
92
|
-
specified_type: {
|
|
93
|
-
type: 'fully_specified_type',
|
|
94
|
-
qualifiers: [{ type: 'keyword', token: 'out', whitespace: ' ' }],
|
|
95
|
-
specifier: {
|
|
96
|
-
type: 'type_specifier',
|
|
97
|
-
specifier: { type: 'keyword', token: 'vec4', whitespace: ' ' },
|
|
98
|
-
quantifier: null,
|
|
99
|
-
},
|
|
100
|
-
},
|
|
101
|
-
declarations: [
|
|
102
|
-
{
|
|
103
|
-
type: 'declaration',
|
|
104
|
-
identifier: {
|
|
105
|
-
type: 'identifier',
|
|
106
|
-
identifier: glOut,
|
|
107
|
-
whitespace: undefined,
|
|
108
|
-
},
|
|
109
|
-
quantifier: null,
|
|
110
|
-
operator: undefined,
|
|
111
|
-
initializer: undefined,
|
|
112
|
-
},
|
|
113
|
-
],
|
|
114
|
-
commas: [],
|
|
115
|
-
},
|
|
116
|
-
semi: { type: 'literal', literal: ';', whitespace: '\n ' },
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
visit(ast, {
|
|
120
|
-
function_call: {
|
|
121
|
-
enter: (path) => {
|
|
122
|
-
const identifier = path.node.identifier;
|
|
123
|
-
if (
|
|
124
|
-
'specifier' in identifier &&
|
|
125
|
-
identifier.specifier?.identifier === 'texture2D'
|
|
126
|
-
) {
|
|
127
|
-
identifier.specifier.identifier = 'texture';
|
|
128
|
-
}
|
|
129
|
-
},
|
|
130
|
-
},
|
|
131
|
-
identifier: {
|
|
132
|
-
enter: (path) => {
|
|
133
|
-
if (path.node.identifier === 'gl_FragColor') {
|
|
134
|
-
path.node.identifier = glOut;
|
|
135
|
-
}
|
|
136
|
-
},
|
|
137
|
-
},
|
|
138
|
-
keyword: {
|
|
139
|
-
enter: (path) => {
|
|
140
|
-
if (
|
|
141
|
-
(path.node.token === 'attribute' || path.node.token === 'varying') &&
|
|
142
|
-
path.findParent((path) => path.node.type === 'declaration_statement')
|
|
143
|
-
) {
|
|
144
|
-
path.node.token =
|
|
145
|
-
stage === 'vertex' && path.node.token === 'varying' ? 'out' : 'in';
|
|
146
|
-
}
|
|
147
|
-
},
|
|
148
|
-
},
|
|
149
|
-
});
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
export const outDeclaration = (name: string): Object => ({
|
|
153
|
-
type: 'declaration_statement',
|
|
154
|
-
declaration: {
|
|
155
|
-
type: 'declarator_list',
|
|
156
|
-
specified_type: {
|
|
157
|
-
type: 'fully_specified_type',
|
|
158
|
-
qualifiers: [{ type: 'keyword', token: 'out', whitespace: ' ' }],
|
|
159
|
-
specifier: {
|
|
160
|
-
type: 'type_specifier',
|
|
161
|
-
specifier: { type: 'keyword', token: 'vec4', whitespace: ' ' },
|
|
162
|
-
quantifier: null,
|
|
163
|
-
},
|
|
164
|
-
},
|
|
165
|
-
declarations: [
|
|
166
|
-
{
|
|
167
|
-
type: 'declaration',
|
|
168
|
-
identifier: {
|
|
169
|
-
type: 'identifier',
|
|
170
|
-
identifier: name,
|
|
171
|
-
whitespace: undefined,
|
|
172
|
-
},
|
|
173
|
-
quantifier: null,
|
|
174
|
-
operator: undefined,
|
|
175
|
-
initializer: undefined,
|
|
176
|
-
},
|
|
177
|
-
],
|
|
178
|
-
commas: [],
|
|
179
|
-
},
|
|
180
|
-
semi: { type: 'literal', literal: ';', whitespace: '\n ' },
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
export const makeStatement = (stmt: string): AstNode => {
|
|
184
|
-
// console.log(stmt);
|
|
185
|
-
let ast;
|
|
186
|
-
try {
|
|
187
|
-
ast = parser.parse(
|
|
188
|
-
`${stmt};
|
|
189
|
-
`,
|
|
190
|
-
{ quiet: true }
|
|
191
|
-
);
|
|
192
|
-
} catch (error: any) {
|
|
193
|
-
console.error({ stmt, error });
|
|
194
|
-
throw new Error(`Error parsing stmt "${stmt}": ${error?.message}`);
|
|
195
|
-
}
|
|
196
|
-
// console.log(util.inspect(ast, false, null, true));
|
|
197
|
-
return ast.program[0];
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
export const makeFnStatement = (fnStmt: string): AstNode => {
|
|
201
|
-
let ast;
|
|
202
|
-
try {
|
|
203
|
-
ast = parser.parse(
|
|
204
|
-
`
|
|
205
|
-
void main() {
|
|
206
|
-
${fnStmt};
|
|
207
|
-
}`,
|
|
208
|
-
{ quiet: true }
|
|
209
|
-
);
|
|
210
|
-
} catch (error: any) {
|
|
211
|
-
console.error({ fnStmt, error });
|
|
212
|
-
throw new Error(`Error parsing fnStmt "${fnStmt}": ${error?.message}`);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// console.log(util.inspect(ast, false, null, true));
|
|
216
|
-
return (ast.program[0] as FunctionNode).body.statements[0];
|
|
217
|
-
};
|
|
218
|
-
|
|
219
|
-
export const makeExpression = (expr: string): AstNode => {
|
|
220
|
-
let ast;
|
|
221
|
-
try {
|
|
222
|
-
ast = parser.parse(
|
|
223
|
-
`void main() {
|
|
224
|
-
a = ${expr};
|
|
225
|
-
}`,
|
|
226
|
-
{ quiet: true }
|
|
227
|
-
);
|
|
228
|
-
} catch (error: any) {
|
|
229
|
-
console.error({ expr, error });
|
|
230
|
-
throw new Error(`Error parsing expr "${expr}": ${error?.message}`);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
// console.log(util.inspect(ast, false, null, true));
|
|
234
|
-
return (ast.program[0] as FunctionNode).body.statements[0].expression.right;
|
|
235
|
-
};
|
|
236
|
-
|
|
237
|
-
export const makeExpressionWithScopes = (expr: string): Program => {
|
|
238
|
-
let ast: Program;
|
|
239
|
-
try {
|
|
240
|
-
ast = parser.parse(
|
|
241
|
-
`void main() {
|
|
242
|
-
${expr};
|
|
243
|
-
}`,
|
|
244
|
-
{ quiet: true }
|
|
245
|
-
);
|
|
246
|
-
} catch (error: any) {
|
|
247
|
-
console.error({ expr, error });
|
|
248
|
-
throw new Error(`Error parsing expr "${expr}": ${error?.message}`);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
// console.log(util.inspect(ast, false, null, true));
|
|
252
|
-
return {
|
|
253
|
-
type: 'program',
|
|
254
|
-
// Set the main() fn body scope as the global one
|
|
255
|
-
scopes: [ast.scopes[1]],
|
|
256
|
-
program: [(ast.program[0] as FunctionNode).body.statements[0].expression],
|
|
257
|
-
};
|
|
258
|
-
};
|
|
259
|
-
|
|
260
|
-
export const findFn = (ast: Program, name: string): FunctionNode | undefined =>
|
|
261
|
-
ast.program.find(
|
|
262
|
-
(stmt): stmt is FunctionNode =>
|
|
263
|
-
stmt.type === 'function' && stmt.prototype.header.name.identifier === name
|
|
264
|
-
);
|
|
265
|
-
|
|
266
|
-
export const returnGlPosition = (fnName: string, ast: Program): void =>
|
|
267
|
-
convertVertexMain(fnName, ast, 'vec4', (assign) => assign.expression.right);
|
|
268
|
-
|
|
269
|
-
export const returnGlPositionHardCoded = (
|
|
270
|
-
fnName: string,
|
|
271
|
-
ast: Program,
|
|
272
|
-
returnType: string,
|
|
273
|
-
hardCodedReturn: string
|
|
274
|
-
): void =>
|
|
275
|
-
convertVertexMain(fnName, ast, returnType, () =>
|
|
276
|
-
makeExpression(hardCodedReturn)
|
|
277
|
-
);
|
|
278
|
-
|
|
279
|
-
export const returnGlPositionVec3Right = (fnName: string, ast: Program): void =>
|
|
280
|
-
convertVertexMain(fnName, ast, 'vec3', (assign) => {
|
|
281
|
-
let found: AstNode | undefined;
|
|
282
|
-
visit(assign, {
|
|
283
|
-
function_call: {
|
|
284
|
-
enter: (path) => {
|
|
285
|
-
const { node } = path;
|
|
286
|
-
if (
|
|
287
|
-
// @ts-ignore
|
|
288
|
-
node?.identifier?.specifier?.token === 'vec4' &&
|
|
289
|
-
node?.args?.[2]?.token?.includes('1.')
|
|
290
|
-
) {
|
|
291
|
-
found = node.args[0];
|
|
292
|
-
}
|
|
293
|
-
},
|
|
294
|
-
},
|
|
295
|
-
});
|
|
296
|
-
if (!found) {
|
|
297
|
-
console.error(generate(ast));
|
|
298
|
-
throw new Error(
|
|
299
|
-
'Could not find position assignment to convert to return!'
|
|
300
|
-
);
|
|
301
|
-
}
|
|
302
|
-
return found;
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
const convertVertexMain = (
|
|
306
|
-
fnName: string,
|
|
307
|
-
ast: Program,
|
|
308
|
-
returnType: string,
|
|
309
|
-
generateRight: (positionAssign: ExpressionStatementNode) => AstNode
|
|
310
|
-
) => {
|
|
311
|
-
const mainReturnVar = `frogOut`;
|
|
312
|
-
|
|
313
|
-
const main = findFn(ast, fnName);
|
|
314
|
-
if (!main) {
|
|
315
|
-
throw new Error(`No ${fnName} fn found!`);
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
// Convert the main function to one that returns
|
|
319
|
-
(main.prototype.header.returnType.specifier.specifier as KeywordNode).token =
|
|
320
|
-
returnType;
|
|
321
|
-
|
|
322
|
-
// Find the gl_position assignment line
|
|
323
|
-
const assign = main.body.statements.find(
|
|
324
|
-
(stmt: AstNode) =>
|
|
325
|
-
stmt.type === 'expression_statement' &&
|
|
326
|
-
stmt.expression.left?.identifier === 'gl_Position'
|
|
327
|
-
);
|
|
328
|
-
if (!assign) {
|
|
329
|
-
throw new Error(`No gl position assign found in main fn!`);
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
const rtnStmt = makeFnStatement(
|
|
333
|
-
`${returnType} ${mainReturnVar} = 1.0`
|
|
334
|
-
) as DeclarationStatementNode;
|
|
335
|
-
rtnStmt.declaration.declarations[0].initializer = generateRight(assign);
|
|
336
|
-
|
|
337
|
-
main.body.statements.splice(main.body.statements.indexOf(assign), 1, rtnStmt);
|
|
338
|
-
main.body.statements.push(makeFnStatement(`return ${mainReturnVar}`));
|
|
339
|
-
};
|
|
340
|
-
|
|
341
|
-
export const convert300MainToReturn = (fnName: string, ast: Program): void => {
|
|
342
|
-
const mainReturnVar = `frogOut`;
|
|
343
|
-
|
|
344
|
-
// Find the output variable, as in "pc_fragColor" from "out highp vec4 pc_fragColor;"
|
|
345
|
-
let outName: string | undefined;
|
|
346
|
-
ast.program.find((line, index) => {
|
|
347
|
-
if (
|
|
348
|
-
line.type === 'declaration_statement' &&
|
|
349
|
-
line.declaration?.specified_type?.qualifiers?.find(
|
|
350
|
-
(n: KeywordNode) => n.token === 'out'
|
|
351
|
-
) &&
|
|
352
|
-
line.declaration.specified_type.specifier.specifier.token === 'vec4'
|
|
353
|
-
) {
|
|
354
|
-
// Remove the out declaration
|
|
355
|
-
ast.program.splice(index, 1);
|
|
356
|
-
outName = line.declaration.declarations[0].identifier.identifier;
|
|
357
|
-
return true;
|
|
358
|
-
}
|
|
359
|
-
});
|
|
360
|
-
if (!outName) {
|
|
361
|
-
console.error(generate(ast));
|
|
362
|
-
throw new Error('No "out vec4" line found in the fragment shader');
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
visit(ast, {
|
|
366
|
-
identifier: {
|
|
367
|
-
enter: (path) => {
|
|
368
|
-
if (path.node.identifier === outName) {
|
|
369
|
-
path.node.identifier = mainReturnVar;
|
|
370
|
-
// @ts-ignore
|
|
371
|
-
path.node.doNotDescope = true; // hack because this var is in the scope which gets renamed later
|
|
372
|
-
}
|
|
373
|
-
},
|
|
374
|
-
},
|
|
375
|
-
function: {
|
|
376
|
-
enter: (path) => {
|
|
377
|
-
if (path.node.prototype.header.name.identifier === fnName) {
|
|
378
|
-
(
|
|
379
|
-
path.node.prototype.header.returnType.specifier
|
|
380
|
-
.specifier as KeywordNode
|
|
381
|
-
).token = 'vec4';
|
|
382
|
-
path.node.body.statements.unshift(
|
|
383
|
-
makeFnStatement(`vec4 ${mainReturnVar}`)
|
|
384
|
-
);
|
|
385
|
-
path.node.body.statements.push(
|
|
386
|
-
makeFnStatement(`return ${mainReturnVar}`)
|
|
387
|
-
);
|
|
388
|
-
}
|
|
389
|
-
},
|
|
390
|
-
},
|
|
391
|
-
});
|
|
392
|
-
};
|