@shaderfrog/core 0.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.
- package/.eslintrc.json +3 -0
- package/.prettierrc.js +3 -0
- package/README.md +3 -0
- package/babel.config.js +6 -0
- package/package.json +47 -0
- package/src/ast/manipulate.ts +392 -0
- package/src/ast/shader-sections.ts +323 -0
- package/src/core/engine.ts +214 -0
- package/src/core/file.js +53 -0
- package/src/core/graph.ts +1007 -0
- package/src/core/nodes/code-nodes.ts +66 -0
- package/src/core/nodes/core-node.ts +48 -0
- package/src/core/nodes/data-nodes.ts +344 -0
- package/src/core/nodes/edge.ts +23 -0
- package/src/core/nodes/engine-node.ts +266 -0
- package/src/core/strategy.ts +520 -0
- package/src/core.test.ts +312 -0
- package/src/plugins/babylon/bablyengine.ts +670 -0
- package/src/plugins/babylon/examples.ts +512 -0
- package/src/plugins/babylon/importers.ts +69 -0
- package/src/plugins/babylon/index.ts +6 -0
- package/src/plugins/three/examples.ts +680 -0
- package/src/plugins/three/importers.ts +18 -0
- package/src/plugins/three/index.ts +6 -0
- package/src/plugins/three/threngine.tsx +571 -0
- package/src/util/ensure.ts +10 -0
- package/src/util/id.ts +2 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { ShaderStage } from '../graph';
|
|
2
|
+
import { Strategy } from '../strategy';
|
|
3
|
+
import { GraphDataType, UniformDataType } from './data-nodes';
|
|
4
|
+
import { CoreNode, NodeInput } from './core-node';
|
|
5
|
+
|
|
6
|
+
export const mapInputName = (
|
|
7
|
+
node: CodeNode,
|
|
8
|
+
{ id, displayName }: NodeInput
|
|
9
|
+
): string => node.config?.inputMapping?.[id] || displayName;
|
|
10
|
+
|
|
11
|
+
export type InputMapping = { [original: string]: string };
|
|
12
|
+
export type NodeConfig = {
|
|
13
|
+
version: 2 | 3;
|
|
14
|
+
mangle?: boolean;
|
|
15
|
+
preprocess: boolean;
|
|
16
|
+
inputMapping?: InputMapping;
|
|
17
|
+
strategies: Strategy[];
|
|
18
|
+
uniforms: UniformDataType[];
|
|
19
|
+
properties?: NodeProperty[];
|
|
20
|
+
hardCodedProperties?: Record<string, any>;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export interface NodeProperty {
|
|
24
|
+
// Display name, like "albedo"
|
|
25
|
+
displayName: string;
|
|
26
|
+
// Type in the engine, like "texture"
|
|
27
|
+
type: GraphDataType;
|
|
28
|
+
// Property name to apply to the material, like "map"
|
|
29
|
+
property: string;
|
|
30
|
+
// The name of the filler this property introduces, aka the GLSL source code
|
|
31
|
+
// to be replaced, if this property is present.
|
|
32
|
+
fillerName?: string;
|
|
33
|
+
defaultValue?: any;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const property = (
|
|
37
|
+
displayName: string,
|
|
38
|
+
property: string,
|
|
39
|
+
type: GraphDataType,
|
|
40
|
+
fillerName?: string,
|
|
41
|
+
defaultValue?: any
|
|
42
|
+
): NodeProperty => ({
|
|
43
|
+
displayName,
|
|
44
|
+
type,
|
|
45
|
+
property,
|
|
46
|
+
fillerName,
|
|
47
|
+
defaultValue,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
export interface CodeNode extends CoreNode {
|
|
51
|
+
config: NodeConfig;
|
|
52
|
+
source: string;
|
|
53
|
+
expressionOnly?: boolean;
|
|
54
|
+
stage: ShaderStage | undefined;
|
|
55
|
+
biStage?: boolean;
|
|
56
|
+
groupId: string | null | undefined;
|
|
57
|
+
nextStageNodeId?: string;
|
|
58
|
+
prevStageNodeId?: string;
|
|
59
|
+
originalEngine?: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface BinaryNode extends CodeNode {
|
|
63
|
+
operator: string;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export type SourceNode = BinaryNode | CodeNode;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { GraphDataType } from './data-nodes';
|
|
2
|
+
|
|
3
|
+
export type InputCategory = 'data' | 'code';
|
|
4
|
+
export type InputType = 'uniform' | 'property' | 'filler';
|
|
5
|
+
|
|
6
|
+
export interface NodeInput {
|
|
7
|
+
displayName: string;
|
|
8
|
+
id: string;
|
|
9
|
+
type: InputType;
|
|
10
|
+
dataType?: GraphDataType;
|
|
11
|
+
accepts: Set<InputCategory>;
|
|
12
|
+
baked?: boolean;
|
|
13
|
+
bakeable: boolean;
|
|
14
|
+
property?: string;
|
|
15
|
+
}
|
|
16
|
+
export const nodeInput = (
|
|
17
|
+
displayName: string,
|
|
18
|
+
id: string,
|
|
19
|
+
type: InputType,
|
|
20
|
+
dataType: GraphDataType | undefined,
|
|
21
|
+
accepts: Set<InputCategory>,
|
|
22
|
+
bakeable: boolean,
|
|
23
|
+
property?: string
|
|
24
|
+
): NodeInput => ({
|
|
25
|
+
displayName,
|
|
26
|
+
id,
|
|
27
|
+
type,
|
|
28
|
+
dataType,
|
|
29
|
+
accepts,
|
|
30
|
+
bakeable,
|
|
31
|
+
property,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
export interface NodeOutput {
|
|
35
|
+
name: string;
|
|
36
|
+
id: string;
|
|
37
|
+
category: InputCategory;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type NodePosition = { x: number; y: number };
|
|
41
|
+
export interface CoreNode {
|
|
42
|
+
id: string;
|
|
43
|
+
name: string;
|
|
44
|
+
type: string;
|
|
45
|
+
inputs: NodeInput[];
|
|
46
|
+
outputs: NodeOutput[];
|
|
47
|
+
position: NodePosition;
|
|
48
|
+
}
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import { CoreNode, NodeInput, NodeOutput, NodePosition } from './core-node';
|
|
2
|
+
|
|
3
|
+
type ArrayType = 'array';
|
|
4
|
+
type Vector = 'vector2' | 'vector3' | 'vector4';
|
|
5
|
+
type Color = 'rgb' | 'rgba';
|
|
6
|
+
type Mat =
|
|
7
|
+
| 'mat2'
|
|
8
|
+
| 'mat3'
|
|
9
|
+
| 'mat4'
|
|
10
|
+
| 'mat2x2'
|
|
11
|
+
| 'mat2x3'
|
|
12
|
+
| 'mat2x4'
|
|
13
|
+
| 'mat3x2'
|
|
14
|
+
| 'mat3x3'
|
|
15
|
+
| 'mat3x4'
|
|
16
|
+
| 'mat4x2'
|
|
17
|
+
| 'mat4x3'
|
|
18
|
+
| 'mat4x4';
|
|
19
|
+
|
|
20
|
+
export type GraphDataType =
|
|
21
|
+
| Vector
|
|
22
|
+
| Color
|
|
23
|
+
| Mat
|
|
24
|
+
| 'texture'
|
|
25
|
+
| 'samplerCube'
|
|
26
|
+
| 'number'
|
|
27
|
+
| ArrayType;
|
|
28
|
+
|
|
29
|
+
export interface NumberNode extends CoreNode {
|
|
30
|
+
type: 'number';
|
|
31
|
+
value: string;
|
|
32
|
+
range?: [number, number];
|
|
33
|
+
stepper?: number;
|
|
34
|
+
}
|
|
35
|
+
export const numberNode = (
|
|
36
|
+
id: string,
|
|
37
|
+
name: string,
|
|
38
|
+
position: NodePosition,
|
|
39
|
+
value: string,
|
|
40
|
+
optionals?: {
|
|
41
|
+
range?: [number, number];
|
|
42
|
+
stepper?: number;
|
|
43
|
+
inputs?: NodeInput[];
|
|
44
|
+
outputs?: NodeOutput[];
|
|
45
|
+
}
|
|
46
|
+
): NumberNode => ({
|
|
47
|
+
type: 'number',
|
|
48
|
+
id,
|
|
49
|
+
name,
|
|
50
|
+
position,
|
|
51
|
+
value,
|
|
52
|
+
inputs: optionals?.inputs || [],
|
|
53
|
+
outputs: optionals?.outputs || [
|
|
54
|
+
{
|
|
55
|
+
name: 'float',
|
|
56
|
+
id: '1',
|
|
57
|
+
category: 'data',
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
range: optionals?.range,
|
|
61
|
+
stepper: optionals?.stepper,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
export type NumberDataUniform = Omit<
|
|
65
|
+
NumberNode,
|
|
66
|
+
'id' | 'inputs' | 'outputs' | 'position'
|
|
67
|
+
>;
|
|
68
|
+
|
|
69
|
+
export const numberUniformData = (
|
|
70
|
+
name: string,
|
|
71
|
+
value: string,
|
|
72
|
+
range?: [number, number],
|
|
73
|
+
stepper?: number
|
|
74
|
+
): NumberDataUniform => ({
|
|
75
|
+
type: 'number',
|
|
76
|
+
name,
|
|
77
|
+
value,
|
|
78
|
+
range,
|
|
79
|
+
stepper,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
export interface TextureNode extends CoreNode {
|
|
83
|
+
type: 'texture';
|
|
84
|
+
value: string;
|
|
85
|
+
}
|
|
86
|
+
export const textureNode = (
|
|
87
|
+
id: string,
|
|
88
|
+
name: string,
|
|
89
|
+
position: NodePosition,
|
|
90
|
+
value: string
|
|
91
|
+
): TextureNode => ({
|
|
92
|
+
type: 'texture',
|
|
93
|
+
id,
|
|
94
|
+
name,
|
|
95
|
+
position,
|
|
96
|
+
value,
|
|
97
|
+
inputs: [],
|
|
98
|
+
outputs: [
|
|
99
|
+
{
|
|
100
|
+
name: 'texture',
|
|
101
|
+
id: '1',
|
|
102
|
+
category: 'data',
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
export type TextureDataUniform = Omit<
|
|
108
|
+
TextureNode,
|
|
109
|
+
'id' | 'inputs' | 'outputs' | 'position'
|
|
110
|
+
>;
|
|
111
|
+
|
|
112
|
+
export const textureUniformData = (
|
|
113
|
+
name: string,
|
|
114
|
+
value: string
|
|
115
|
+
): TextureDataUniform => ({ type: 'texture', name, value });
|
|
116
|
+
|
|
117
|
+
export interface SamplerCubeNode extends CoreNode {
|
|
118
|
+
type: 'samplerCube';
|
|
119
|
+
value: string;
|
|
120
|
+
}
|
|
121
|
+
export const samplerCubeNode = (
|
|
122
|
+
id: string,
|
|
123
|
+
name: string,
|
|
124
|
+
position: NodePosition,
|
|
125
|
+
value: string
|
|
126
|
+
): SamplerCubeNode => ({
|
|
127
|
+
type: 'samplerCube',
|
|
128
|
+
id,
|
|
129
|
+
name,
|
|
130
|
+
position,
|
|
131
|
+
value,
|
|
132
|
+
inputs: [],
|
|
133
|
+
outputs: [
|
|
134
|
+
{
|
|
135
|
+
name: 'samplerCube',
|
|
136
|
+
id: '1',
|
|
137
|
+
category: 'data',
|
|
138
|
+
},
|
|
139
|
+
],
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
export type SamplerCubeDataUniform = Omit<
|
|
143
|
+
SamplerCubeNode,
|
|
144
|
+
'id' | 'inputs' | 'outputs' | 'position'
|
|
145
|
+
>;
|
|
146
|
+
|
|
147
|
+
export const samplerCubeUniformData = (
|
|
148
|
+
name: string,
|
|
149
|
+
value: string
|
|
150
|
+
): SamplerCubeDataUniform => ({ type: 'samplerCube', name, value });
|
|
151
|
+
|
|
152
|
+
export type ArrayValue = string[];
|
|
153
|
+
|
|
154
|
+
export interface ArrayNode extends CoreNode {
|
|
155
|
+
type: 'array';
|
|
156
|
+
dimensions: number;
|
|
157
|
+
value: ArrayValue;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function arrayNode(
|
|
161
|
+
id: string,
|
|
162
|
+
name: string,
|
|
163
|
+
position: NodePosition,
|
|
164
|
+
value: ArrayValue
|
|
165
|
+
): ArrayNode {
|
|
166
|
+
return {
|
|
167
|
+
id,
|
|
168
|
+
name,
|
|
169
|
+
position,
|
|
170
|
+
inputs: [],
|
|
171
|
+
outputs: [
|
|
172
|
+
{
|
|
173
|
+
name: 'array',
|
|
174
|
+
id: '1',
|
|
175
|
+
category: 'data',
|
|
176
|
+
},
|
|
177
|
+
],
|
|
178
|
+
value,
|
|
179
|
+
dimensions: value.length,
|
|
180
|
+
type: 'array',
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export type Vector2 = [string, string];
|
|
185
|
+
export type Vector3 = [string, string, string];
|
|
186
|
+
export type Vector4 = [string, string, string, string];
|
|
187
|
+
|
|
188
|
+
export interface Vector2Node extends CoreNode {
|
|
189
|
+
type: 'vector2';
|
|
190
|
+
dimensions: 2;
|
|
191
|
+
value: Vector2;
|
|
192
|
+
}
|
|
193
|
+
export interface Vector3Node extends CoreNode {
|
|
194
|
+
type: 'vector3';
|
|
195
|
+
dimensions: 3;
|
|
196
|
+
value: Vector3;
|
|
197
|
+
}
|
|
198
|
+
export interface Vector4Node extends CoreNode {
|
|
199
|
+
type: 'vector4';
|
|
200
|
+
dimensions: 4;
|
|
201
|
+
value: Vector4;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export function vectorNode(
|
|
205
|
+
id: string,
|
|
206
|
+
name: string,
|
|
207
|
+
position: NodePosition,
|
|
208
|
+
value: Vector2 | Vector3 | Vector4
|
|
209
|
+
): Vector2Node | Vector3Node | Vector4Node {
|
|
210
|
+
return {
|
|
211
|
+
id,
|
|
212
|
+
name,
|
|
213
|
+
position,
|
|
214
|
+
inputs: [],
|
|
215
|
+
outputs: [
|
|
216
|
+
{
|
|
217
|
+
name: `vector${value.length}`,
|
|
218
|
+
id: '1',
|
|
219
|
+
category: 'data',
|
|
220
|
+
},
|
|
221
|
+
],
|
|
222
|
+
...(value.length === 2
|
|
223
|
+
? { value, dimensions: 2, type: 'vector2' }
|
|
224
|
+
: value.length === 3
|
|
225
|
+
? { value, dimensions: 3, type: 'vector3' }
|
|
226
|
+
: { value, dimensions: 4, type: 'vector4' }),
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export type ArrayDataUniform = Omit<
|
|
231
|
+
ArrayNode,
|
|
232
|
+
'id' | 'inputs' | 'outputs' | 'position'
|
|
233
|
+
>;
|
|
234
|
+
|
|
235
|
+
export const arrayUniformData = (
|
|
236
|
+
name: string,
|
|
237
|
+
value: ArrayValue
|
|
238
|
+
): ArrayDataUniform => ({
|
|
239
|
+
name,
|
|
240
|
+
value,
|
|
241
|
+
dimensions: value.length,
|
|
242
|
+
type: 'array',
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
export type Vector2DataUniform = Omit<
|
|
246
|
+
Vector2Node,
|
|
247
|
+
'id' | 'inputs' | 'outputs' | 'position'
|
|
248
|
+
>;
|
|
249
|
+
export type Vector3DataUniform = Omit<
|
|
250
|
+
Vector3Node,
|
|
251
|
+
'id' | 'inputs' | 'outputs' | 'position'
|
|
252
|
+
>;
|
|
253
|
+
export type Vector4DataUniform = Omit<
|
|
254
|
+
Vector4Node,
|
|
255
|
+
'id' | 'inputs' | 'outputs' | 'position'
|
|
256
|
+
>;
|
|
257
|
+
|
|
258
|
+
export const vectorUniformData = (
|
|
259
|
+
name: string,
|
|
260
|
+
value: Vector2 | Vector3 | Vector4
|
|
261
|
+
): Vector2DataUniform | Vector3DataUniform | Vector4DataUniform => ({
|
|
262
|
+
name,
|
|
263
|
+
...(value.length === 2
|
|
264
|
+
? { value, dimensions: 2, type: 'vector2' }
|
|
265
|
+
: value.length === 3
|
|
266
|
+
? { value, dimensions: 3, type: 'vector3' }
|
|
267
|
+
: { value, dimensions: 4, type: 'vector4' }),
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
export interface RgbNode extends CoreNode {
|
|
271
|
+
type: 'rgb';
|
|
272
|
+
dimensions: 3;
|
|
273
|
+
value: Vector3;
|
|
274
|
+
}
|
|
275
|
+
export interface RgbaNode extends CoreNode {
|
|
276
|
+
type: 'rgba';
|
|
277
|
+
dimensions: 4;
|
|
278
|
+
value: Vector4;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export function colorNode(
|
|
282
|
+
id: string,
|
|
283
|
+
name: string,
|
|
284
|
+
position: NodePosition,
|
|
285
|
+
value: Vector3 | Vector4
|
|
286
|
+
): RgbNode | RgbaNode {
|
|
287
|
+
return {
|
|
288
|
+
id,
|
|
289
|
+
name,
|
|
290
|
+
position,
|
|
291
|
+
inputs: [],
|
|
292
|
+
outputs: [
|
|
293
|
+
{
|
|
294
|
+
name: value.length === 3 ? 'rgb' : 'rgba',
|
|
295
|
+
id: '1',
|
|
296
|
+
category: 'data',
|
|
297
|
+
},
|
|
298
|
+
],
|
|
299
|
+
...(value.length === 3
|
|
300
|
+
? { value, dimensions: 3, type: 'rgb' }
|
|
301
|
+
: { value, dimensions: 4, type: 'rgba' }),
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
export type RgbDataUniform = Omit<
|
|
306
|
+
RgbNode,
|
|
307
|
+
'id' | 'inputs' | 'outputs' | 'position'
|
|
308
|
+
>;
|
|
309
|
+
export type RgbaDataUniform = Omit<
|
|
310
|
+
RgbaNode,
|
|
311
|
+
'id' | 'inputs' | 'outputs' | 'position'
|
|
312
|
+
>;
|
|
313
|
+
|
|
314
|
+
export const colorUniformData = (
|
|
315
|
+
name: string,
|
|
316
|
+
value: Vector3 | Vector4
|
|
317
|
+
): RgbDataUniform | RgbaDataUniform => ({
|
|
318
|
+
name,
|
|
319
|
+
...(value.length === 3
|
|
320
|
+
? { value, dimensions: 3, type: 'rgb' }
|
|
321
|
+
: { value, dimensions: 4, type: 'rgba' }),
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
// When defining nodes, these are the types allowed in uniforms
|
|
325
|
+
export type UniformDataType =
|
|
326
|
+
| TextureDataUniform
|
|
327
|
+
| SamplerCubeDataUniform
|
|
328
|
+
| NumberDataUniform
|
|
329
|
+
| Vector2DataUniform
|
|
330
|
+
| Vector3DataUniform
|
|
331
|
+
| Vector4DataUniform
|
|
332
|
+
| RgbDataUniform
|
|
333
|
+
| RgbaDataUniform;
|
|
334
|
+
|
|
335
|
+
export type DataNode =
|
|
336
|
+
| TextureNode
|
|
337
|
+
| SamplerCubeNode
|
|
338
|
+
| NumberNode
|
|
339
|
+
| Vector2Node
|
|
340
|
+
| Vector3Node
|
|
341
|
+
| Vector4Node
|
|
342
|
+
| ArrayNode
|
|
343
|
+
| RgbNode
|
|
344
|
+
| RgbaNode;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ShaderStage } from '../graph';
|
|
2
|
+
import { GraphDataType } from './data-nodes';
|
|
3
|
+
|
|
4
|
+
export type EdgeType = ShaderStage | GraphDataType;
|
|
5
|
+
export type Edge = {
|
|
6
|
+
id: string;
|
|
7
|
+
from: string;
|
|
8
|
+
to: string;
|
|
9
|
+
output: string;
|
|
10
|
+
// The ID of the input of the node this edge connects to
|
|
11
|
+
input: string;
|
|
12
|
+
// Fragment, vertex, or any of the data types
|
|
13
|
+
type?: EdgeType;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const makeEdge = (
|
|
17
|
+
id: string,
|
|
18
|
+
from: string,
|
|
19
|
+
to: string,
|
|
20
|
+
output: string,
|
|
21
|
+
input: string,
|
|
22
|
+
type?: EdgeType
|
|
23
|
+
): Edge => ({ id, from, to, output, input, type });
|