glre 0.30.0 → 0.32.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/dist/index.cjs +30 -64
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +571 -0
- package/dist/index.js +30 -64
- package/dist/index.js.map +1 -1
- package/dist/native.cjs +30 -64
- package/dist/native.cjs.map +1 -1
- package/dist/native.d.ts +54 -0
- package/dist/native.js +30 -64
- package/dist/native.js.map +1 -1
- package/dist/react.cjs +30 -64
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.ts +8 -0
- package/dist/react.js +30 -64
- package/dist/react.js.map +1 -1
- package/dist/solid.cjs +30 -64
- package/dist/solid.cjs.map +1 -1
- package/dist/solid.d.ts +8 -0
- package/dist/solid.js +30 -64
- package/dist/solid.js.map +1 -1
- package/package.json +7 -6
- package/src/index.ts +20 -5
- package/src/node/code.ts +66 -69
- package/src/node/const.ts +2 -0
- package/src/node/index.ts +78 -8
- package/src/node/infer.ts +19 -14
- package/src/node/node.ts +12 -14
- package/src/node/parse.ts +118 -0
- package/src/node/scope.ts +37 -18
- package/src/node/types.ts +90 -56
- package/src/node/utils.ts +9 -92
- package/src/types.ts +31 -16
- package/src/utils/pipeline.ts +135 -83
- package/src/utils/program.ts +7 -29
- package/src/webgl.ts +2 -3
- package/src/webgpu.ts +67 -58
- package/dist/index-q8W5cl04.d.cts +0 -358
- package/dist/index.d.cts +0 -3
- package/dist/native.d.cts +0 -53
- package/dist/react.d.cts +0 -8
- package/dist/solid.d.cts +0 -8
package/src/node/code.ts
CHANGED
|
@@ -1,11 +1,32 @@
|
|
|
1
1
|
import { is } from '../utils/helpers'
|
|
2
2
|
import { infer } from './infer'
|
|
3
|
-
import { getBluiltin, getOperator,
|
|
4
|
-
import type {
|
|
3
|
+
import { getBluiltin, getOperator, formatConversions, joins } from './utils'
|
|
4
|
+
import type { NodeContext, X } from './types'
|
|
5
|
+
import {
|
|
6
|
+
parseAttribHead,
|
|
7
|
+
parseConstantHead,
|
|
8
|
+
parseUniformHead,
|
|
9
|
+
parseDeclare,
|
|
10
|
+
parseDefine,
|
|
11
|
+
parseIf,
|
|
12
|
+
parseSwitch,
|
|
13
|
+
parseTexture,
|
|
14
|
+
parseVaryingHead,
|
|
15
|
+
} from './parse'
|
|
5
16
|
|
|
6
|
-
export const code = (target: X, c?:
|
|
17
|
+
export const code = (target: X, c?: NodeContext | null): string => {
|
|
7
18
|
if (!c) c = {}
|
|
8
19
|
if (!c.headers) c.headers = new Map()
|
|
20
|
+
if (!c.vertVaryings) c.vertVaryings = new Map()
|
|
21
|
+
if (!c.fragInputs) c.fragInputs = new Map()
|
|
22
|
+
if (!c.vertInputs) c.vertInputs = new Map()
|
|
23
|
+
if (!c.vertOutputs) {
|
|
24
|
+
c.vertOutputs = new Map()
|
|
25
|
+
if (!c.isWebGL) {
|
|
26
|
+
c.fragInputs.set('position', '@builtin(position) position: vec4f')
|
|
27
|
+
c.vertOutputs.set('position', '@builtin(position) position: vec4f')
|
|
28
|
+
}
|
|
29
|
+
}
|
|
9
30
|
if (is.str(target)) return target
|
|
10
31
|
if (is.num(target)) {
|
|
11
32
|
const ret = `${target}`
|
|
@@ -13,50 +34,19 @@ export const code = (target: X, c?: NodeConfig | null): string => {
|
|
|
13
34
|
return ret + '.0'
|
|
14
35
|
}
|
|
15
36
|
if (is.bol(target)) return target ? 'true' : 'false'
|
|
16
|
-
if (!target) return ''
|
|
37
|
+
if (!target) return ''
|
|
17
38
|
const { type, props } = target
|
|
18
39
|
const { id = '', children = [] } = props
|
|
19
|
-
const [x, y, z] = children
|
|
20
|
-
/**
|
|
21
|
-
* headers
|
|
22
|
-
*/
|
|
23
|
-
let head = ''
|
|
24
|
-
if (type === 'attribute') {
|
|
25
|
-
if (c.headers.has(id)) return id
|
|
26
|
-
head = `${infer(target, c)} ${id}`
|
|
27
|
-
}
|
|
28
|
-
if (type === 'uniform') {
|
|
29
|
-
if (c.headers.has(id)) return id
|
|
30
|
-
if (!c.binding) c.binding = 0
|
|
31
|
-
const varType = infer(target, c)
|
|
32
|
-
head = c.isWebGL
|
|
33
|
-
? `uniform ${varType} ${id};`
|
|
34
|
-
: `@group(0) @binding(${c.binding++}) var<uniform> ${id}: ${formatConversions(varType, c)};`
|
|
35
|
-
}
|
|
36
|
-
if (type === 'constant') {
|
|
37
|
-
if (c.headers.has(id)) return id
|
|
38
|
-
const varType = infer(target, c)
|
|
39
|
-
const value = code(x, c)
|
|
40
|
-
head = c.isWebGL
|
|
41
|
-
? `const ${varType} ${id} = ${value};`
|
|
42
|
-
: `const ${id}: ${formatConversions(varType, c)} = ${value};`
|
|
43
|
-
}
|
|
44
|
-
if (type === 'varying') {
|
|
45
|
-
if (c.headers.has(id)) return id
|
|
46
|
-
head = `${infer(target, c)} ${id}`
|
|
47
|
-
}
|
|
48
|
-
if (head) {
|
|
49
|
-
c.headers.set(id, head)
|
|
50
|
-
c.onMount?.(id)
|
|
51
|
-
return id
|
|
52
|
-
}
|
|
40
|
+
const [x, y, z, w] = children
|
|
53
41
|
/**
|
|
54
42
|
* variables
|
|
55
43
|
*/
|
|
56
44
|
if (type === 'variable') return id
|
|
57
45
|
if (type === 'swizzle') return `${code(y, c)}.${code(x, c)}`
|
|
58
|
-
if (type === 'ternary')
|
|
59
|
-
|
|
46
|
+
if (type === 'ternary')
|
|
47
|
+
return c.isWebGL
|
|
48
|
+
? `(${code(x, c)} ? ${code(y, c)} : ${code(z, c)})`
|
|
49
|
+
: `select(${code(x, c)}, ${code(y, c)}, ${code(z, c)})`
|
|
60
50
|
if (type === 'conversion') return `${formatConversions(x, c)}(${joins(children.slice(1), c)})`
|
|
61
51
|
if (type === 'operator') {
|
|
62
52
|
if (x === 'not' || x === 'bitNot') return `!${code(y, c)}`
|
|
@@ -64,6 +54,7 @@ export const code = (target: X, c?: NodeConfig | null): string => {
|
|
|
64
54
|
}
|
|
65
55
|
if (type === 'function') {
|
|
66
56
|
if (x === 'negate') return `(-${joins(children.slice(1), c)})`
|
|
57
|
+
if (x === 'texture') return parseTexture(c, y, z, w)
|
|
67
58
|
return `${x}(${joins(children.slice(1), c)})`
|
|
68
59
|
}
|
|
69
60
|
/**
|
|
@@ -71,45 +62,51 @@ export const code = (target: X, c?: NodeConfig | null): string => {
|
|
|
71
62
|
*/
|
|
72
63
|
if (type === 'scope') return children.map((child: any) => code(child, c)).join('\n')
|
|
73
64
|
if (type === 'assign') return `${code(x, c)} = ${code(y, c)};`
|
|
65
|
+
if (type === 'return') return `return ${code(x, c)};`
|
|
74
66
|
if (type === 'loop')
|
|
75
67
|
return c.isWebGL
|
|
76
68
|
? `for (int i = 0; i < ${x}; i += 1) {\n${code(y, c)}\n}`
|
|
77
69
|
: `for (var i: i32 = 0; i < ${x}; i++) {\n${code(y, c)}\n}`
|
|
70
|
+
if (type === 'if') return parseIf(c, x, y, children)
|
|
71
|
+
if (type === 'switch') return parseSwitch(c, x, children)
|
|
72
|
+
if (type === 'declare') return parseDeclare(c, x, y)
|
|
78
73
|
if (type === 'define') {
|
|
79
|
-
const
|
|
80
|
-
const ret = `${id}(${args.map((arg) => code(arg, c))})`
|
|
74
|
+
const ret = `${id}(${joins(children.slice(1), c)})`
|
|
81
75
|
if (c.headers.has(id)) return ret
|
|
82
|
-
c.headers.set(id,
|
|
76
|
+
c.headers.set(id, parseDefine(c, props, infer(target, c)))
|
|
83
77
|
return ret
|
|
84
78
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
79
|
+
/**
|
|
80
|
+
* headers
|
|
81
|
+
*/
|
|
82
|
+
if (type === 'varying') {
|
|
83
|
+
if (c.vertOutputs.has(id)) return c.isWebGL ? `${id}` : `out.${id}`
|
|
84
|
+
const field = parseVaryingHead(c, id, infer(target, c))
|
|
85
|
+
c.fragInputs.set(id, field)
|
|
86
|
+
c.vertOutputs.set(id, field)
|
|
87
|
+
c.vertVaryings.set(id, code(x, c))
|
|
88
|
+
return c.isWebGL ? `${id}` : `out.${id}`
|
|
94
89
|
}
|
|
95
|
-
if (type === '
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
90
|
+
if (type === 'builtin') {
|
|
91
|
+
if (c.isWebGL) return getBluiltin(id)
|
|
92
|
+
if (id === 'position') return 'out.position'
|
|
93
|
+
const field = `@builtin(${id}) ${id}: ${formatConversions(infer(target, c), c)}`
|
|
94
|
+
if (c.isFrag) {
|
|
95
|
+
c.fragInputs.set(id, field)
|
|
96
|
+
} else c.vertInputs.set(id, field)
|
|
97
|
+
return `in.${id}`
|
|
98
|
+
}
|
|
99
|
+
if (type === 'attribute') {
|
|
100
|
+
c.vertInputs.set(id, parseAttribHead(c, id, infer(target, c)))
|
|
101
|
+
return c.isWebGL ? `${id}` : `in.${id}`
|
|
106
102
|
}
|
|
107
|
-
if (
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
103
|
+
if (c.headers.has(id)) return id // must last
|
|
104
|
+
let head = ''
|
|
105
|
+
if (type === 'uniform') head = parseUniformHead(c, id, infer(target, c))
|
|
106
|
+
if (type === 'constant') head = parseConstantHead(c, id, infer(target, c), code(x, c))
|
|
107
|
+
if (head) {
|
|
108
|
+
c.headers.set(id, head)
|
|
109
|
+
return id
|
|
113
110
|
}
|
|
114
111
|
return code(x, c)
|
|
115
112
|
}
|
package/src/node/const.ts
CHANGED
package/src/node/index.ts
CHANGED
|
@@ -1,15 +1,82 @@
|
|
|
1
|
-
import { builtin, conversion as c, function_ as f, uniform } from './node'
|
|
2
|
-
import { hex2rgb } from './utils'
|
|
3
1
|
import { is } from '../utils/helpers'
|
|
4
|
-
import
|
|
2
|
+
import { code } from './code'
|
|
3
|
+
import { builtin, conversion as c, function_ as f, uniform as u } from './node'
|
|
4
|
+
import { hex2rgb } from './utils'
|
|
5
|
+
import type { NodeContext, X } from './types'
|
|
5
6
|
export * from './code'
|
|
6
|
-
export * from './const'
|
|
7
|
-
export * from './infer'
|
|
8
7
|
export * from './node'
|
|
9
8
|
export * from './scope'
|
|
10
9
|
export * from './types'
|
|
11
10
|
export * from './utils'
|
|
12
11
|
|
|
12
|
+
const GLSL_FRAGMENT_HEAD = `
|
|
13
|
+
#version 300 es
|
|
14
|
+
precision mediump float;
|
|
15
|
+
out vec4 fragColor;
|
|
16
|
+
`.trim()
|
|
17
|
+
|
|
18
|
+
const generateHead = (x: X, c: NodeContext) => {
|
|
19
|
+
const body = code(x, c)
|
|
20
|
+
const head = Array.from(c.headers!.values()).join('\n')
|
|
21
|
+
return [head, body]
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const generateStruct = (id: string, map: Map<string, string>) => {
|
|
25
|
+
return `struct ${id} {\n ${Array.from(map.values()).join(',\n ')}\n}`
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const vertex = (x: X, c: NodeContext) => {
|
|
29
|
+
c.headers?.clear()
|
|
30
|
+
c.isFrag = false // for varying inputs or outputs
|
|
31
|
+
const [head, body] = generateHead(x, c)
|
|
32
|
+
const ret = []
|
|
33
|
+
if (c.isWebGL) {
|
|
34
|
+
ret.push('#version 300 es')
|
|
35
|
+
for (const code of c.vertInputs!.values()) ret.push(`in ${code}`)
|
|
36
|
+
for (const code of c.vertOutputs!.values()) ret.push(`out ${code}`)
|
|
37
|
+
ret.push(head)
|
|
38
|
+
ret.push('void main() {')
|
|
39
|
+
ret.push(` gl_Position = ${body};`)
|
|
40
|
+
for (const [id, code] of c.vertVaryings!.entries()) ret.push(` ${id} = ${code};`)
|
|
41
|
+
} else {
|
|
42
|
+
if (c.vertInputs?.size) ret.push(generateStruct('In', c.vertInputs))
|
|
43
|
+
if (c.vertOutputs?.size) ret.push(generateStruct('Out', c.vertOutputs))
|
|
44
|
+
ret.push(head)
|
|
45
|
+
ret.push('@vertex')
|
|
46
|
+
ret.push(`fn main(${c.vertInputs?.size ? 'in: In' : ''}) -> Out {`)
|
|
47
|
+
ret.push(' var out: Out;')
|
|
48
|
+
ret.push(` out.position = ${body};`)
|
|
49
|
+
for (const [id, code] of c.vertVaryings!.entries()) ret.push(` out.${id} = ${code};`)
|
|
50
|
+
ret.push(' return out;')
|
|
51
|
+
}
|
|
52
|
+
ret.push('}')
|
|
53
|
+
const main = ret.filter(Boolean).join('\n')
|
|
54
|
+
console.log(`↓↓↓generated↓↓↓\n${main}`)
|
|
55
|
+
return main
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export const fragment = (x: X, c: NodeContext) => {
|
|
59
|
+
c.headers?.clear()
|
|
60
|
+
c.isFrag = true // for varying inputs or outputs
|
|
61
|
+
const [head, body] = generateHead(x, c)
|
|
62
|
+
const ret = []
|
|
63
|
+
if (c.isWebGL) {
|
|
64
|
+
ret.push(GLSL_FRAGMENT_HEAD)
|
|
65
|
+
for (const code of c.fragInputs!.values()) ret.push(`in ${code}`)
|
|
66
|
+
ret.push(head)
|
|
67
|
+
ret.push(`void main() {\n fragColor = ${body};`)
|
|
68
|
+
} else {
|
|
69
|
+
if (c.fragInputs?.size) ret.push(generateStruct('Out', c.fragInputs))
|
|
70
|
+
ret.push(head)
|
|
71
|
+
ret.push(`@fragment\nfn main(out: Out) -> @location(0) vec4f {`)
|
|
72
|
+
ret.push(` return ${body};`)
|
|
73
|
+
}
|
|
74
|
+
ret.push('}')
|
|
75
|
+
const main = ret.filter(Boolean).join('\n')
|
|
76
|
+
console.log(`↓↓↓generated↓↓↓\n${main}`)
|
|
77
|
+
return main
|
|
78
|
+
}
|
|
79
|
+
|
|
13
80
|
// Builtin Variables
|
|
14
81
|
export const position = builtin('position')
|
|
15
82
|
export const vertexIndex = builtin('vertex_index')
|
|
@@ -50,15 +117,18 @@ export const uvec4 = (x?: X, y?: X, z?: X, w?: X) => c('uvec4', x, y, z, w)
|
|
|
50
117
|
export const bvec2 = (x?: X, y?: X) => c('bvec2', x, y)
|
|
51
118
|
export const bvec3 = (x?: X, y?: X, z?: X) => c('bvec3', x, y, z)
|
|
52
119
|
export const bvec4 = (x?: X, y?: X, z?: X, w?: X) => c('bvec4', x, y, z, w)
|
|
120
|
+
export const texture2D = () => c('texture')
|
|
121
|
+
export const sampler2D = () => c('sampler2D')
|
|
53
122
|
export const color = (r?: X, g?: X, b?: X) => {
|
|
54
123
|
if (is.num(r) && is.und(g) && is.und(b)) return vec3(...hex2rgb(r))
|
|
55
124
|
return vec3(r, g, b)
|
|
56
125
|
}
|
|
57
126
|
|
|
58
127
|
// Default uniforms
|
|
59
|
-
export const iResolution =
|
|
60
|
-
export const iMouse =
|
|
61
|
-
export const iTime =
|
|
128
|
+
export const iResolution = u(vec2(1280, 800), 'iResolution')
|
|
129
|
+
export const iMouse = u(vec2(0, 0), 'iMouse')
|
|
130
|
+
export const iTime = u(float(0), 'iTime')
|
|
131
|
+
export const uv = () => position.xy.div(iResolution)
|
|
62
132
|
|
|
63
133
|
// Texture Functions
|
|
64
134
|
export const texture = (x: X, y: X, z?: X) => f('texture', x, y, z)
|
package/src/node/infer.ts
CHANGED
|
@@ -13,10 +13,10 @@ import {
|
|
|
13
13
|
VEC3_RETURN_FUNCTIONS,
|
|
14
14
|
VEC4_RETURN_FUNCTIONS,
|
|
15
15
|
} from './const'
|
|
16
|
-
import { isNodeProxy } from './utils'
|
|
17
|
-
import type { Constants,
|
|
16
|
+
import { isConstantsType, isNodeProxy } from './utils'
|
|
17
|
+
import type { Constants, NodeContext, NodeProxy, X } from './types'
|
|
18
18
|
|
|
19
|
-
const getHighestPriorityType = (args: X[], c:
|
|
19
|
+
const getHighestPriorityType = (args: X[], c: NodeContext) => {
|
|
20
20
|
return args.reduce((highest, current) => {
|
|
21
21
|
const currentType = infer(current, c)
|
|
22
22
|
const highestPriority = CONSTANTS.indexOf(highest as any)
|
|
@@ -29,7 +29,7 @@ const inferBuiltin = (id: string | undefined): Constants => {
|
|
|
29
29
|
return BUILTIN_TYPES[id as keyof typeof BUILTIN_TYPES]!
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
const inferFunction = (funcName: string, args: X[], c:
|
|
32
|
+
const inferFunction = (funcName: string, args: X[], c: NodeContext): Constants => {
|
|
33
33
|
const firstArgType = args.length > 0 ? infer(args[0], c) : 'float'
|
|
34
34
|
if (FIRST_ARG_TYPE_FUNCTIONS.includes(funcName as any)) return firstArgType
|
|
35
35
|
if (SCALAR_RETURN_FUNCTIONS.includes(funcName as any)) return 'float'
|
|
@@ -52,9 +52,9 @@ const inferOperator = (leftType: string, rightType: string, op: string): Constan
|
|
|
52
52
|
return (leftPriority >= rightPriority ? leftType : rightType) as Constants
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
const inferPrimitiveType = (x: any): Constants => {
|
|
55
|
+
export const inferPrimitiveType = (x: any): Constants => {
|
|
56
56
|
if (is.bol(x)) return 'bool'
|
|
57
|
-
if (is.num(x)) return 'float'
|
|
57
|
+
if (is.num(x)) return 'float'
|
|
58
58
|
if (is.arr(x)) return COMPONENT_COUNT_TO_TYPE[x.length as keyof typeof COMPONENT_COUNT_TO_TYPE] || 'float'
|
|
59
59
|
return 'float'
|
|
60
60
|
}
|
|
@@ -63,25 +63,30 @@ const inferSwizzle = (count: number): Constants => {
|
|
|
63
63
|
return COMPONENT_COUNT_TO_TYPE[count as keyof typeof COMPONENT_COUNT_TO_TYPE]!
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
const inferFromArray = (arr: X[], c: NodeContext): Constants => {
|
|
67
|
+
if (arr.length === 0) return 'void'
|
|
68
|
+
const ret = infer(arr[0], c)
|
|
69
|
+
for (const x of arr.slice(1))
|
|
70
|
+
if (ret !== infer(x)) throw new Error(`glre node system error: defined scope return mismatch`)
|
|
71
|
+
return ret
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export const inferImpl = (target: NodeProxy, c: NodeContext): Constants => {
|
|
67
75
|
const { type, props } = target
|
|
68
|
-
const { id, children = [], inferFrom } = props
|
|
76
|
+
const { id, children = [], layout, inferFrom } = props
|
|
69
77
|
const [x, y, z] = children
|
|
70
|
-
if (inferFrom) return infer(inferFrom, c)
|
|
71
78
|
if (type === 'conversion') return x as Constants
|
|
72
79
|
if (type === 'operator') return inferOperator(infer(y, c), infer(z, c), x as string)
|
|
73
80
|
if (type === 'function') return inferFunction(x as string, children.slice(1), c)
|
|
74
81
|
if (type === 'swizzle') return inferSwizzle((x as string).length)
|
|
75
82
|
if (type === 'ternary') return inferOperator(infer(y, c), infer(z, c), 'add')
|
|
76
83
|
if (type === 'builtin') return inferBuiltin(id)
|
|
77
|
-
if (type === 'define')
|
|
78
|
-
|
|
79
|
-
return y ? infer(y, c) : 'void'
|
|
80
|
-
}
|
|
84
|
+
if (type === 'define' && isConstantsType(layout?.type)) return layout?.type
|
|
85
|
+
if (inferFrom) return inferFromArray(inferFrom, c)
|
|
81
86
|
return infer(x, c)
|
|
82
87
|
}
|
|
83
88
|
|
|
84
|
-
export const infer = (target: X, c?:
|
|
89
|
+
export const infer = (target: X, c?: NodeContext | null): Constants => {
|
|
85
90
|
if (!c) c = {}
|
|
86
91
|
if (!isNodeProxy(target)) return inferPrimitiveType(target)
|
|
87
92
|
if (!c.infers) c.infers = new WeakMap<NodeProxy, Constants>()
|
package/src/node/node.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { code } from './code'
|
|
2
2
|
import { assign, toVar } from './scope'
|
|
3
|
-
import { conversionToConstant, isConversion, isFunction, isOperator, isSwizzle } from './utils'
|
|
3
|
+
import { conversionToConstant, isConversion, isFunction, isOperator, isSwizzle, getId, isNodeProxy } from './utils'
|
|
4
4
|
import type { Functions, NodeProps, NodeProxy, NodeTypes, Operators, Swizzles, X } from './types'
|
|
5
5
|
|
|
6
6
|
const toPrimitive = (x: X, hint: string) => {
|
|
@@ -35,18 +35,16 @@ export const node = (type: NodeTypes, props?: NodeProps | null, ...args: X[]) =>
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
// headers
|
|
38
|
-
export const attribute = (x: X, id
|
|
39
|
-
export const
|
|
40
|
-
export const
|
|
41
|
-
export const
|
|
42
|
-
export const
|
|
43
|
-
export const
|
|
38
|
+
export const attribute = (x: X, id = getId()) => node('attribute', { id }, x)
|
|
39
|
+
export const constant = (x: X, id = getId()) => node('constant', { id }, x)
|
|
40
|
+
export const uniform = (x: X, id = getId()) => node('uniform', { id }, x)
|
|
41
|
+
export const variable = (id = getId()) => node('variable', { id })
|
|
42
|
+
export const builtin = (id = getId()) => node('builtin', { id })
|
|
43
|
+
export const vertexStage = (x: X, id = getId()) => node('varying', { id, inferFrom: [x] }, x)
|
|
44
44
|
|
|
45
45
|
// Node shorthands
|
|
46
|
-
export const swizzle = (key: Swizzles,
|
|
47
|
-
export const operator = (key: Operators, ...
|
|
48
|
-
export const function_ = (key: Functions, ...
|
|
49
|
-
export const conversion = (key: string, ...
|
|
50
|
-
|
|
51
|
-
// x ? y : z
|
|
52
|
-
export const select = (x: X, y: X, z: X) => node('ternary', null, x, y, z)
|
|
46
|
+
export const swizzle = (key: Swizzles, x: X) => node('swizzle', null, key, x)
|
|
47
|
+
export const operator = (key: Operators, ...x: X[]) => node('operator', null, key, ...x)
|
|
48
|
+
export const function_ = (key: Functions, ...x: X[]) => node('function', null, key, ...x)
|
|
49
|
+
export const conversion = (key: string, ...x: X[]) => node('conversion', null, key, ...x)
|
|
50
|
+
export const select = (x: X, y: X, z: X) => node('ternary', null, x, y, z) // x ? y : z
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { infer } from './infer'
|
|
2
|
+
import { formatConversions, joins } from './utils'
|
|
3
|
+
import { code } from './code'
|
|
4
|
+
import type { Constants, NodeContext, NodeProps, X } from './types'
|
|
5
|
+
|
|
6
|
+
export const parseTexture = (c: NodeContext, y: X, z: X, w: X) => {
|
|
7
|
+
if (c.isWebGL) {
|
|
8
|
+
const args = w ? [y, z, w] : [y, z]
|
|
9
|
+
return `texture(${joins(args, c)})`
|
|
10
|
+
}
|
|
11
|
+
const _y = code(y, c)
|
|
12
|
+
const args = [_y, _y + 'Sampler', code(z, c)]
|
|
13
|
+
if (!w) return `textureSample(${args})`
|
|
14
|
+
args.push(code(w, c))
|
|
15
|
+
return `textureSampleLevel(${args})`
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* scopes
|
|
20
|
+
*/
|
|
21
|
+
export const parseIf = (c: NodeContext, x: X, y: X, children: X[]) => {
|
|
22
|
+
let ret = `if (${code(x, c)}) {\n${code(y, c)}\n}`
|
|
23
|
+
for (let i = 2; i < children.length; i += 2) {
|
|
24
|
+
const isElse = i >= children.length - 1
|
|
25
|
+
ret += !isElse
|
|
26
|
+
? ` else if (${code(children[i], c)}) {\n${code(children[i + 1], c)}\n}`
|
|
27
|
+
: ` else {\n${code(children[i], c)}\n}`
|
|
28
|
+
}
|
|
29
|
+
return ret
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const parseSwitch = (c: NodeContext, x: X, children: X[]) => {
|
|
33
|
+
let ret = `switch (${code(x, c)}) {\n`
|
|
34
|
+
for (let i = 1; i < children.length; i += 2) {
|
|
35
|
+
const isDefault = i >= children.length - 1
|
|
36
|
+
if (isDefault && children.length % 2 === 0) {
|
|
37
|
+
ret += `default:\n${code(children[i], c)}\nbreak;\n`
|
|
38
|
+
} else if (i + 1 < children.length)
|
|
39
|
+
ret += `case ${code(children[i], c)}:\n${code(children[i + 1], c)}\nbreak;\n`
|
|
40
|
+
}
|
|
41
|
+
ret += '}'
|
|
42
|
+
return ret
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export const parseDeclare = (c: NodeContext, x: X, y: X) => {
|
|
46
|
+
const varType = infer(x, c)
|
|
47
|
+
const varName = (y as any)?.props?.id
|
|
48
|
+
if (c.isWebGL) return `${varType} ${varName} = ${code(x, c)};`
|
|
49
|
+
const wgslType = formatConversions(varType)
|
|
50
|
+
return `var ${varName}: ${wgslType} = ${code(x, c)};`
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const parseDefine = (c: NodeContext, props: NodeProps, returnType: Constants) => {
|
|
54
|
+
const { id, children = [], layout } = props
|
|
55
|
+
const [x, ...args] = children
|
|
56
|
+
const argParams: [name: string, type: string][] = []
|
|
57
|
+
const params: string[] = []
|
|
58
|
+
if (layout?.inputs)
|
|
59
|
+
for (const input of layout.inputs) {
|
|
60
|
+
argParams.push([input.name, input.type])
|
|
61
|
+
}
|
|
62
|
+
else
|
|
63
|
+
for (let i = 0; i < args.length; i++) {
|
|
64
|
+
argParams.push([`p${i}`, infer(args[i], c)])
|
|
65
|
+
}
|
|
66
|
+
const ret = []
|
|
67
|
+
if (c?.isWebGL) {
|
|
68
|
+
for (const [id, type] of argParams) params.push(`${type} ${id}`)
|
|
69
|
+
ret.push(`${returnType} ${id}(${params}) {`)
|
|
70
|
+
} else {
|
|
71
|
+
for (const [id, type] of argParams) params.push(`${id}: ${formatConversions(type, c)}`)
|
|
72
|
+
ret.push(`fn ${id}(${params}) -> ${formatConversions(returnType, c)} {`)
|
|
73
|
+
}
|
|
74
|
+
const scopeCode = code(x, c)
|
|
75
|
+
if (scopeCode) ret.push(scopeCode)
|
|
76
|
+
ret.push('}')
|
|
77
|
+
return ret.join('\n')
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* headers
|
|
82
|
+
*/
|
|
83
|
+
export const parseVaryingHead = (c: NodeContext, id: string, varType: string) => {
|
|
84
|
+
return c.isWebGL
|
|
85
|
+
? `${varType} ${id};`
|
|
86
|
+
: `@location(${c.vertVaryings!.size}) ${id}: ${formatConversions(varType, c)}`
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export const parseUniformHead = (c: NodeContext, id: string, varType: Constants) => {
|
|
90
|
+
const isTexture = varType === 'sampler2D' || varType === 'texture'
|
|
91
|
+
if (c.isWebGL)
|
|
92
|
+
return isTexture //
|
|
93
|
+
? `uniform sampler2D ${id};`
|
|
94
|
+
: `uniform ${varType} ${id};`
|
|
95
|
+
if (isTexture) {
|
|
96
|
+
const { group = 1, binding = 0 } = c.webgpu?.textures.map.get(id) || {}
|
|
97
|
+
return (
|
|
98
|
+
`@group(${group}) @binding(${binding}) var ${id}Sampler: sampler;\n` +
|
|
99
|
+
`@group(${group}) @binding(${binding + 1}) var ${id}: texture_2d<f32>;`
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
const { group = 0, binding = 0 } = c.webgpu?.uniforms.map.get(id) || {}
|
|
103
|
+
const wgslType = formatConversions(varType, c)
|
|
104
|
+
return `@group(${group}) @binding(${binding}) var<uniform> ${id}: ${wgslType};`
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export const parseAttribHead = (c: NodeContext, id: string, varType: Constants) => {
|
|
108
|
+
if (c.isWebGL) return `${varType} ${id};`
|
|
109
|
+
const { location = 0 } = c.webgpu?.attribs.map.get(id) || {}
|
|
110
|
+
const wgslType = formatConversions(varType, c)
|
|
111
|
+
return `@location(${location}) ${id}: ${wgslType}`
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export const parseConstantHead = (c: NodeContext, id: string, varType: Constants, value: string) => {
|
|
115
|
+
return c.isWebGL
|
|
116
|
+
? `const ${varType} ${id} = ${value};`
|
|
117
|
+
: `const ${id}: ${formatConversions(varType, c)} = ${value};`
|
|
118
|
+
}
|
package/src/node/scope.ts
CHANGED
|
@@ -3,24 +3,22 @@ import { conversion, node } from './node'
|
|
|
3
3
|
import { getId } from './utils'
|
|
4
4
|
import type { FnLayout, NodeProps, NodeProxy, X } from './types'
|
|
5
5
|
|
|
6
|
-
let
|
|
7
|
-
|
|
8
|
-
const scoped = (x: NodeProxy | null, fun = () => {}) => {
|
|
9
|
-
const prev = _scope
|
|
10
|
-
_scope = x
|
|
11
|
-
fun()
|
|
12
|
-
_scope = prev
|
|
13
|
-
}
|
|
6
|
+
let scope: NodeProxy | null = null
|
|
7
|
+
let define: NodeProxy | null = null
|
|
14
8
|
|
|
15
9
|
const addToScope = (x: NodeProxy) => {
|
|
16
|
-
if (!
|
|
17
|
-
if (!
|
|
18
|
-
|
|
10
|
+
if (!scope) return
|
|
11
|
+
if (!scope.props.children) scope.props.children = []
|
|
12
|
+
scope.props.children.push(x)
|
|
13
|
+
if (x.type !== 'return' || !define) return
|
|
14
|
+
const { props } = define
|
|
15
|
+
if (!props.inferFrom) props.inferFrom = []
|
|
16
|
+
props.inferFrom.push(x)
|
|
19
17
|
}
|
|
20
18
|
|
|
21
19
|
export const toVar = (x: X, id?: string) => {
|
|
22
20
|
if (!id) id = getId()
|
|
23
|
-
const y = node('variable', { id, inferFrom: x })
|
|
21
|
+
const y = node('variable', { id, inferFrom: [x] })
|
|
24
22
|
const z = node('declare', null, x, y)
|
|
25
23
|
addToScope(z)
|
|
26
24
|
return y
|
|
@@ -32,6 +30,27 @@ export const assign = (x: X, y: X) => {
|
|
|
32
30
|
return x
|
|
33
31
|
}
|
|
34
32
|
|
|
33
|
+
export const Return = (x: X) => {
|
|
34
|
+
const y = node('return', { inferFrom: [x] }, x)
|
|
35
|
+
addToScope(y)
|
|
36
|
+
return y
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const scoped = (x: NodeProxy, fun: () => NodeProxy | void, y = define) => {
|
|
40
|
+
// cache to revert
|
|
41
|
+
const _scope = scope
|
|
42
|
+
const _define = define
|
|
43
|
+
// update
|
|
44
|
+
scope = x
|
|
45
|
+
define = y
|
|
46
|
+
if (_scope) x.props.parent = _scope
|
|
47
|
+
const z = fun()
|
|
48
|
+
if (z) Return(z)
|
|
49
|
+
// revert
|
|
50
|
+
scope = _scope
|
|
51
|
+
define = _define
|
|
52
|
+
}
|
|
53
|
+
|
|
35
54
|
export const If = (x: X, fun: () => void) => {
|
|
36
55
|
const y = node('scope')
|
|
37
56
|
scoped(y, fun)
|
|
@@ -55,7 +74,7 @@ export const If = (x: X, fun: () => void) => {
|
|
|
55
74
|
|
|
56
75
|
export const Loop = (x: X, fun: (params: { i: NodeProxy }) => void) => {
|
|
57
76
|
const y = node('scope')
|
|
58
|
-
scoped(y, () => fun({ i: node('variable', { id: 'i', inferFrom: int(0) }) }))
|
|
77
|
+
scoped(y, () => fun({ i: node('variable', { id: 'i', inferFrom: [int(0)] }) }))
|
|
59
78
|
const ret = node('loop', null, x, y)
|
|
60
79
|
addToScope(ret)
|
|
61
80
|
return ret
|
|
@@ -88,20 +107,20 @@ export const Fn = (fun: (paramVars: NodeProxy[]) => NodeProxy) => {
|
|
|
88
107
|
const ret = (...args: X[]) => {
|
|
89
108
|
const id = layout?.name || getId()
|
|
90
109
|
const x = node('scope')
|
|
91
|
-
let y: NodeProxy | undefined
|
|
92
110
|
const paramVars: NodeProxy[] = []
|
|
93
111
|
const paramDefs: NodeProps[] = []
|
|
94
112
|
if (layout?.inputs)
|
|
95
113
|
for (const input of layout.inputs) {
|
|
96
|
-
paramDefs.push({ id: input.name, inferFrom: conversion(input.type) })
|
|
114
|
+
paramDefs.push({ id: input.name, inferFrom: [conversion(input.type)] })
|
|
97
115
|
}
|
|
98
116
|
else
|
|
99
117
|
for (let i = 0; i < args.length; i++) {
|
|
100
|
-
paramDefs.push({ id: `p${i}`, inferFrom: args[i] })
|
|
118
|
+
paramDefs.push({ id: `p${i}`, inferFrom: [args[i]] })
|
|
101
119
|
}
|
|
102
120
|
for (const props of paramDefs) paramVars.push(node('variable', props))
|
|
103
|
-
|
|
104
|
-
|
|
121
|
+
const y = node('define', { id, layout }, x, ...args)
|
|
122
|
+
scoped(x, () => fun(paramVars), y)
|
|
123
|
+
return y
|
|
105
124
|
}
|
|
106
125
|
ret.setLayout = (newLayout: FnLayout) => {
|
|
107
126
|
layout = newLayout
|