glre 0.32.0 → 0.33.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 +31 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +71 -34
- package/dist/index.js +31 -27
- package/dist/index.js.map +1 -1
- package/dist/native.cjs +31 -27
- package/dist/native.cjs.map +1 -1
- package/dist/native.d.ts +1 -1
- package/dist/native.js +31 -27
- package/dist/native.js.map +1 -1
- package/dist/react.cjs +31 -27
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +31 -27
- package/dist/react.js.map +1 -1
- package/dist/solid.cjs +31 -27
- package/dist/solid.cjs.map +1 -1
- package/dist/solid.d.ts +1 -1
- package/dist/solid.js +31 -27
- package/dist/solid.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +1 -1
- package/src/node/code.ts +39 -34
- package/src/node/const.ts +27 -46
- package/src/node/index.ts +39 -23
- package/src/node/infer.ts +19 -7
- package/src/node/node.ts +11 -10
- package/src/node/parse.ts +70 -28
- package/src/node/scope.ts +11 -5
- package/src/node/types.ts +21 -12
- package/src/node/utils.ts +65 -13
- package/src/types.ts +1 -0
- package/src/utils/pipeline.ts +65 -76
- package/src/utils/program.ts +7 -14
- package/src/webgl.ts +6 -1
- package/src/webgpu.ts +39 -24
package/src/node/code.ts
CHANGED
|
@@ -1,32 +1,26 @@
|
|
|
1
1
|
import { is } from '../utils/helpers'
|
|
2
2
|
import { infer } from './infer'
|
|
3
|
-
import { getBluiltin, getOperator, formatConversions, joins } from './utils'
|
|
4
|
-
import type { NodeContext, X } from './types'
|
|
5
3
|
import {
|
|
4
|
+
parseArray,
|
|
6
5
|
parseAttribHead,
|
|
7
6
|
parseConstantHead,
|
|
8
|
-
parseUniformHead,
|
|
9
7
|
parseDeclare,
|
|
10
8
|
parseDefine,
|
|
11
9
|
parseIf,
|
|
10
|
+
parseStruct,
|
|
11
|
+
parseStructHead,
|
|
12
12
|
parseSwitch,
|
|
13
13
|
parseTexture,
|
|
14
14
|
parseVaryingHead,
|
|
15
|
+
parseUniformHead,
|
|
15
16
|
} from './parse'
|
|
17
|
+
import { getBluiltin, getOperator, formatConversions, safeEventCall, getEventFun, initNodeContext } from './utils'
|
|
18
|
+
import type { NodeContext, NodeProxy, X } from './types'
|
|
16
19
|
|
|
17
20
|
export const code = (target: X, c?: NodeContext | null): string => {
|
|
18
21
|
if (!c) c = {}
|
|
19
|
-
|
|
20
|
-
if (
|
|
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
|
-
}
|
|
22
|
+
initNodeContext(c)
|
|
23
|
+
if (is.arr(target)) return parseArray(target, c)
|
|
30
24
|
if (is.str(target)) return target
|
|
31
25
|
if (is.num(target)) {
|
|
32
26
|
const ret = `${target}`
|
|
@@ -36,26 +30,26 @@ export const code = (target: X, c?: NodeContext | null): string => {
|
|
|
36
30
|
if (is.bol(target)) return target ? 'true' : 'false'
|
|
37
31
|
if (!target) return ''
|
|
38
32
|
const { type, props } = target
|
|
39
|
-
const { id = '', children = [] } = props
|
|
33
|
+
const { id = '', children = [], fields, initialValues } = props
|
|
40
34
|
const [x, y, z, w] = children
|
|
41
35
|
/**
|
|
42
36
|
* variables
|
|
43
37
|
*/
|
|
44
38
|
if (type === 'variable') return id
|
|
45
|
-
if (type === '
|
|
39
|
+
if (type === 'member') return `${code(y, c)}.${code(x, c)}`
|
|
46
40
|
if (type === 'ternary')
|
|
47
41
|
return c.isWebGL
|
|
48
42
|
? `(${code(x, c)} ? ${code(y, c)} : ${code(z, c)})`
|
|
49
|
-
: `select(${code(
|
|
50
|
-
if (type === 'conversion') return `${formatConversions(x, c)}(${
|
|
43
|
+
: `select(${code(z, c)}, ${code(y, c)}, ${code(x, c)})`
|
|
44
|
+
if (type === 'conversion') return `${formatConversions(x, c)}(${parseArray(children.slice(1), c)})`
|
|
51
45
|
if (type === 'operator') {
|
|
52
46
|
if (x === 'not' || x === 'bitNot') return `!${code(y, c)}`
|
|
53
47
|
return `(${code(y, c)} ${getOperator(x)} ${code(z, c)})`
|
|
54
48
|
}
|
|
55
49
|
if (type === 'function') {
|
|
56
|
-
if (x === 'negate') return `(-${
|
|
50
|
+
if (x === 'negate') return `(-${parseArray(children.slice(1), c)})`
|
|
57
51
|
if (x === 'texture') return parseTexture(c, y, z, w)
|
|
58
|
-
return `${x}(${
|
|
52
|
+
return `${x}(${parseArray(children.slice(1), c)})`
|
|
59
53
|
}
|
|
60
54
|
/**
|
|
61
55
|
* scopes
|
|
@@ -71,20 +65,22 @@ export const code = (target: X, c?: NodeContext | null): string => {
|
|
|
71
65
|
if (type === 'switch') return parseSwitch(c, x, children)
|
|
72
66
|
if (type === 'declare') return parseDeclare(c, x, y)
|
|
73
67
|
if (type === 'define') {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
68
|
+
if (!c.code?.headers.has(id)) c.code?.headers.set(id, parseDefine(c, props, infer(target, c)))
|
|
69
|
+
return `${id}(${parseArray(children.slice(1), c)})`
|
|
70
|
+
}
|
|
71
|
+
if (type === 'struct') {
|
|
72
|
+
if (!c.code?.headers.has(id)) c.code?.headers.set(id, parseStructHead(c, id, fields))
|
|
73
|
+
return parseStruct(c, id, (x as NodeProxy).props.id, fields, initialValues)
|
|
78
74
|
}
|
|
79
75
|
/**
|
|
80
76
|
* headers
|
|
81
77
|
*/
|
|
82
78
|
if (type === 'varying') {
|
|
83
|
-
if (c.vertOutputs.has(id)) return c.isWebGL ? `${id}` : `out.${id}`
|
|
79
|
+
if (c.code?.vertOutputs.has(id)) return c.isWebGL ? `${id}` : `out.${id}`
|
|
84
80
|
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))
|
|
81
|
+
c.code?.fragInputs.set(id, field)
|
|
82
|
+
c.code?.vertOutputs.set(id, field)
|
|
83
|
+
c.code?.vertVaryings.set(id, code(x, c))
|
|
88
84
|
return c.isWebGL ? `${id}` : `out.${id}`
|
|
89
85
|
}
|
|
90
86
|
if (type === 'builtin') {
|
|
@@ -92,20 +88,29 @@ export const code = (target: X, c?: NodeContext | null): string => {
|
|
|
92
88
|
if (id === 'position') return 'out.position'
|
|
93
89
|
const field = `@builtin(${id}) ${id}: ${formatConversions(infer(target, c), c)}`
|
|
94
90
|
if (c.isFrag) {
|
|
95
|
-
c.fragInputs.set(id, field)
|
|
96
|
-
} else c.vertInputs.set(id, field)
|
|
91
|
+
c.code?.fragInputs.set(id, field)
|
|
92
|
+
} else c.code?.vertInputs.set(id, field)
|
|
97
93
|
return `in.${id}`
|
|
98
94
|
}
|
|
99
95
|
if (type === 'attribute') {
|
|
100
|
-
|
|
96
|
+
const fun = getEventFun(c, id, true)
|
|
97
|
+
safeEventCall(x, fun)
|
|
98
|
+
target.listeners.add(fun)
|
|
99
|
+
c.code?.vertInputs.set(id, parseAttribHead(c, id, infer(target, c)))
|
|
101
100
|
return c.isWebGL ? `${id}` : `in.${id}`
|
|
102
101
|
}
|
|
103
|
-
if (c.headers.has(id)) return id // must last
|
|
102
|
+
if (c.code?.headers.has(id)) return id // must last
|
|
104
103
|
let head = ''
|
|
105
|
-
if (type === 'uniform')
|
|
104
|
+
if (type === 'uniform') {
|
|
105
|
+
const varType = infer(target, c)
|
|
106
|
+
const fun = getEventFun(c, id, false, varType === 'texture')
|
|
107
|
+
safeEventCall(x, fun)
|
|
108
|
+
target.listeners.add(fun)
|
|
109
|
+
head = parseUniformHead(c, id, varType)
|
|
110
|
+
}
|
|
106
111
|
if (type === 'constant') head = parseConstantHead(c, id, infer(target, c), code(x, c))
|
|
107
112
|
if (head) {
|
|
108
|
-
c.headers.set(id, head)
|
|
113
|
+
c.code?.headers.set(id, head)
|
|
109
114
|
return id
|
|
110
115
|
}
|
|
111
116
|
return code(x, c)
|
package/src/node/const.ts
CHANGED
|
@@ -1,29 +1,32 @@
|
|
|
1
1
|
export const SWIZZLES = ['x', 'y', 'z', 'w', 'r', 'g', 'b', 'a', 's', 't', 'p', 'q'] as const
|
|
2
2
|
|
|
3
|
-
export const
|
|
4
|
-
'bool',
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
'color',
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
3
|
+
export const TYPE_MAPPING = {
|
|
4
|
+
bool: 'bool',
|
|
5
|
+
uint: 'u32',
|
|
6
|
+
int: 'i32',
|
|
7
|
+
float: 'f32',
|
|
8
|
+
bvec2: 'vec2<bool>',
|
|
9
|
+
ivec2: 'vec2i',
|
|
10
|
+
uvec2: 'vec2u',
|
|
11
|
+
vec2: 'vec2f',
|
|
12
|
+
bvec3: 'vec3<bool>',
|
|
13
|
+
ivec3: 'vec3i',
|
|
14
|
+
uvec3: 'vec3u',
|
|
15
|
+
vec3: 'vec3f',
|
|
16
|
+
bvec4: 'vec4<bool>',
|
|
17
|
+
ivec4: 'vec4i',
|
|
18
|
+
uvec4: 'vec4u',
|
|
19
|
+
vec4: 'vec4f',
|
|
20
|
+
color: 'color',
|
|
21
|
+
mat2: 'mat2x2f',
|
|
22
|
+
mat3: 'mat3x3f',
|
|
23
|
+
mat4: 'mat4x4f',
|
|
24
|
+
texture: 'texture_2d<f32>',
|
|
25
|
+
sampler2D: 'sampler',
|
|
26
|
+
struct: 'struct',
|
|
27
|
+
} as const
|
|
28
|
+
|
|
29
|
+
export const CONSTANTS = Object.keys(TYPE_MAPPING) as unknown as keyof typeof TYPE_MAPPING
|
|
27
30
|
|
|
28
31
|
export const CONVERSIONS = [
|
|
29
32
|
'toBool',
|
|
@@ -140,28 +143,6 @@ export const FUNCTIONS = [
|
|
|
140
143
|
...ADDITIONAL_FUNCTIONS,
|
|
141
144
|
] as const
|
|
142
145
|
|
|
143
|
-
export const TYPE_MAPPING = {
|
|
144
|
-
float: 'f32',
|
|
145
|
-
int: 'i32',
|
|
146
|
-
uint: 'u32',
|
|
147
|
-
bool: 'bool',
|
|
148
|
-
vec2: 'vec2f',
|
|
149
|
-
vec3: 'vec3f',
|
|
150
|
-
vec4: 'vec4f',
|
|
151
|
-
mat2: 'mat2x2f',
|
|
152
|
-
mat3: 'mat3x3f',
|
|
153
|
-
mat4: 'mat4x4f',
|
|
154
|
-
ivec2: 'vec2i',
|
|
155
|
-
ivec3: 'vec3i',
|
|
156
|
-
ivec4: 'vec4i',
|
|
157
|
-
uvec2: 'vec2u',
|
|
158
|
-
uvec3: 'vec3u',
|
|
159
|
-
uvec4: 'vec4u',
|
|
160
|
-
bvec2: 'vec2<bool>',
|
|
161
|
-
bvec3: 'vec3<bool>',
|
|
162
|
-
bvec4: 'vec4<bool>',
|
|
163
|
-
} as const
|
|
164
|
-
|
|
165
146
|
export const COMPONENT_COUNT_TO_TYPE = {
|
|
166
147
|
1: 'float',
|
|
167
148
|
2: 'vec2',
|
package/src/node/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { is } from '../utils/helpers'
|
|
2
2
|
import { code } from './code'
|
|
3
3
|
import { builtin, conversion as c, function_ as f, uniform as u } from './node'
|
|
4
|
-
import { hex2rgb } from './utils'
|
|
4
|
+
import { hex2rgb, sortHeadersByDependencies } from './utils'
|
|
5
5
|
import type { NodeContext, X } from './types'
|
|
6
6
|
export * from './code'
|
|
7
7
|
export * from './node'
|
|
@@ -17,7 +17,11 @@ out vec4 fragColor;
|
|
|
17
17
|
|
|
18
18
|
const generateHead = (x: X, c: NodeContext) => {
|
|
19
19
|
const body = code(x, c)
|
|
20
|
-
|
|
20
|
+
let head = ''
|
|
21
|
+
if (c.isWebGL && c.code?.dependencies) {
|
|
22
|
+
const sorted = sortHeadersByDependencies(c.code.headers, c.code.dependencies)
|
|
23
|
+
head = sorted.map(([, value]) => value).join('\n')
|
|
24
|
+
} else head = Array.from(c.code?.headers?.values() || []).join('\n')
|
|
21
25
|
return [head, body]
|
|
22
26
|
}
|
|
23
27
|
|
|
@@ -26,53 +30,55 @@ const generateStruct = (id: string, map: Map<string, string>) => {
|
|
|
26
30
|
}
|
|
27
31
|
|
|
28
32
|
export const vertex = (x: X, c: NodeContext) => {
|
|
29
|
-
|
|
33
|
+
if (is.str(x)) return x.trim()
|
|
34
|
+
c.code?.headers?.clear()
|
|
30
35
|
c.isFrag = false // for varying inputs or outputs
|
|
31
36
|
const [head, body] = generateHead(x, c)
|
|
32
37
|
const ret = []
|
|
33
38
|
if (c.isWebGL) {
|
|
34
39
|
ret.push('#version 300 es')
|
|
35
|
-
for (const code of c.vertInputs
|
|
36
|
-
for (const code of c.vertOutputs
|
|
40
|
+
for (const code of c.code?.vertInputs?.values() || []) ret.push(`in ${code}`)
|
|
41
|
+
for (const code of c.code?.vertOutputs?.values() || []) ret.push(`out ${code}`)
|
|
37
42
|
ret.push(head)
|
|
38
43
|
ret.push('void main() {')
|
|
39
44
|
ret.push(` gl_Position = ${body};`)
|
|
40
|
-
for (const [id, code] of c.vertVaryings
|
|
45
|
+
for (const [id, code] of c.code?.vertVaryings?.entries() || []) ret.push(` ${id} = ${code};`)
|
|
41
46
|
} else {
|
|
42
|
-
if (c.vertInputs?.size) ret.push(generateStruct('In', c.vertInputs))
|
|
43
|
-
if (c.vertOutputs?.size) ret.push(generateStruct('Out', c.vertOutputs))
|
|
47
|
+
if (c.code?.vertInputs?.size) ret.push(generateStruct('In', c.code.vertInputs))
|
|
48
|
+
if (c.code?.vertOutputs?.size) ret.push(generateStruct('Out', c.code.vertOutputs))
|
|
44
49
|
ret.push(head)
|
|
45
50
|
ret.push('@vertex')
|
|
46
|
-
ret.push(`fn main(${c.vertInputs?.size ? 'in: In' : ''}) -> Out {`)
|
|
51
|
+
ret.push(`fn main(${c.code?.vertInputs?.size ? 'in: In' : ''}) -> Out {`)
|
|
47
52
|
ret.push(' var out: Out;')
|
|
48
53
|
ret.push(` out.position = ${body};`)
|
|
49
|
-
for (const [id, code] of c.vertVaryings
|
|
54
|
+
for (const [id, code] of c.code?.vertVaryings?.entries() || []) ret.push(` out.${id} = ${code};`)
|
|
50
55
|
ret.push(' return out;')
|
|
51
56
|
}
|
|
52
57
|
ret.push('}')
|
|
53
|
-
const main = ret.filter(Boolean).join('\n')
|
|
58
|
+
const main = ret.filter(Boolean).join('\n').trim()
|
|
54
59
|
console.log(`↓↓↓generated↓↓↓\n${main}`)
|
|
55
60
|
return main
|
|
56
61
|
}
|
|
57
62
|
|
|
58
63
|
export const fragment = (x: X, c: NodeContext) => {
|
|
59
|
-
|
|
64
|
+
if (is.str(x)) return x.trim()
|
|
65
|
+
c.code?.headers?.clear()
|
|
60
66
|
c.isFrag = true // for varying inputs or outputs
|
|
61
67
|
const [head, body] = generateHead(x, c)
|
|
62
68
|
const ret = []
|
|
63
69
|
if (c.isWebGL) {
|
|
64
70
|
ret.push(GLSL_FRAGMENT_HEAD)
|
|
65
|
-
for (const code of c.fragInputs
|
|
71
|
+
for (const code of c.code?.fragInputs?.values() || []) ret.push(`in ${code}`)
|
|
66
72
|
ret.push(head)
|
|
67
73
|
ret.push(`void main() {\n fragColor = ${body};`)
|
|
68
74
|
} else {
|
|
69
|
-
if (c.fragInputs?.size) ret.push(generateStruct('Out', c.fragInputs))
|
|
75
|
+
if (c.code?.fragInputs?.size) ret.push(generateStruct('Out', c.code.fragInputs))
|
|
70
76
|
ret.push(head)
|
|
71
77
|
ret.push(`@fragment\nfn main(out: Out) -> @location(0) vec4f {`)
|
|
72
78
|
ret.push(` return ${body};`)
|
|
73
79
|
}
|
|
74
80
|
ret.push('}')
|
|
75
|
-
const main = ret.filter(Boolean).join('\n')
|
|
81
|
+
const main = ret.filter(Boolean).join('\n').trim()
|
|
76
82
|
console.log(`↓↓↓generated↓↓↓\n${main}`)
|
|
77
83
|
return main
|
|
78
84
|
}
|
|
@@ -98,10 +104,10 @@ export const screenCoordinate = builtin('screenCoordinate')
|
|
|
98
104
|
export const screenUV = builtin('screenUV')
|
|
99
105
|
|
|
100
106
|
// Type constructors
|
|
101
|
-
export const float = (x
|
|
102
|
-
export const int = (x
|
|
103
|
-
export const uint = (x
|
|
104
|
-
export const bool = (x
|
|
107
|
+
export const float = (x?: X) => c('float', x)
|
|
108
|
+
export const int = (x?: X) => c('int', x)
|
|
109
|
+
export const uint = (x?: X) => c('uint', x)
|
|
110
|
+
export const bool = (x?: X) => c('bool', x)
|
|
105
111
|
export const vec2 = (x?: X, y?: X) => c('vec2', x, y)
|
|
106
112
|
export const vec3 = (x?: X, y?: X, z?: X) => c('vec3', x, y, z)
|
|
107
113
|
export const vec4 = (x?: X, y?: X, z?: X, w?: X) => c('vec4', x, y, z, w)
|
|
@@ -117,7 +123,7 @@ export const uvec4 = (x?: X, y?: X, z?: X, w?: X) => c('uvec4', x, y, z, w)
|
|
|
117
123
|
export const bvec2 = (x?: X, y?: X) => c('bvec2', x, y)
|
|
118
124
|
export const bvec3 = (x?: X, y?: X, z?: X) => c('bvec3', x, y, z)
|
|
119
125
|
export const bvec4 = (x?: X, y?: X, z?: X, w?: X) => c('bvec4', x, y, z, w)
|
|
120
|
-
export const texture2D = () => c('texture')
|
|
126
|
+
export const texture2D = (x?: X) => c('texture', x)
|
|
121
127
|
export const sampler2D = () => c('sampler2D')
|
|
122
128
|
export const color = (r?: X, g?: X, b?: X) => {
|
|
123
129
|
if (is.num(r) && is.und(g) && is.und(b)) return vec3(...hex2rgb(r))
|
|
@@ -125,9 +131,9 @@ export const color = (r?: X, g?: X, b?: X) => {
|
|
|
125
131
|
}
|
|
126
132
|
|
|
127
133
|
// Default uniforms
|
|
128
|
-
export const iResolution = u(vec2(
|
|
129
|
-
export const iMouse = u(vec2(
|
|
130
|
-
export const iTime = u(float(
|
|
134
|
+
export const iResolution = u(vec2(), 'iResolution')
|
|
135
|
+
export const iMouse = u(vec2(), 'iMouse')
|
|
136
|
+
export const iTime = u(float(), 'iTime')
|
|
131
137
|
export const uv = () => position.xy.div(iResolution)
|
|
132
138
|
|
|
133
139
|
// Texture Functions
|
|
@@ -191,3 +197,13 @@ export const step = (edge: X, x: X) => f('step', edge, x)
|
|
|
191
197
|
export const tan = (x: X) => f('tan', x)
|
|
192
198
|
export const transformDirection = (dir: X, matrix: X) => f('transformDirection', dir, matrix)
|
|
193
199
|
export const trunc = (x: X) => f('trunc', x)
|
|
200
|
+
|
|
201
|
+
// // Struct functions
|
|
202
|
+
// export const struct = (fields: Record<string, X>) => {
|
|
203
|
+
// const id = getId()
|
|
204
|
+
// const structNode = node('struct', { id, fields })
|
|
205
|
+
// // Create constructor function
|
|
206
|
+
// const constructor = () => node('struct', { id: getId(), type: id })
|
|
207
|
+
// Object.assign(constructor, structNode)
|
|
208
|
+
// return constructor as any
|
|
209
|
+
// }
|
package/src/node/infer.ts
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
VEC3_RETURN_FUNCTIONS,
|
|
14
14
|
VEC4_RETURN_FUNCTIONS,
|
|
15
15
|
} from './const'
|
|
16
|
-
import {
|
|
16
|
+
import { isConstants, isNodeProxy, isSwizzle } from './utils'
|
|
17
17
|
import type { Constants, NodeContext, NodeProxy, X } from './types'
|
|
18
18
|
|
|
19
19
|
const getHighestPriorityType = (args: X[], c: NodeContext) => {
|
|
@@ -54,20 +54,23 @@ const inferOperator = (leftType: string, rightType: string, op: string): Constan
|
|
|
54
54
|
|
|
55
55
|
export const inferPrimitiveType = (x: any): Constants => {
|
|
56
56
|
if (is.bol(x)) return 'bool'
|
|
57
|
-
if (is.
|
|
57
|
+
if (is.str(x)) return 'texture'
|
|
58
|
+
if (is.num(x)) return Number.isInteger(x) ? 'int' : 'float'
|
|
58
59
|
if (is.arr(x)) return COMPONENT_COUNT_TO_TYPE[x.length as keyof typeof COMPONENT_COUNT_TO_TYPE] || 'float'
|
|
59
60
|
return 'float'
|
|
60
61
|
}
|
|
61
62
|
|
|
62
|
-
const
|
|
63
|
+
const inferFromCount = (count: number): Constants => {
|
|
63
64
|
return COMPONENT_COUNT_TO_TYPE[count as keyof typeof COMPONENT_COUNT_TO_TYPE]!
|
|
64
65
|
}
|
|
65
66
|
|
|
66
67
|
const inferFromArray = (arr: X[], c: NodeContext): Constants => {
|
|
67
68
|
if (arr.length === 0) return 'void'
|
|
68
|
-
const
|
|
69
|
+
const [x] = arr
|
|
70
|
+
if (is.str(x)) return x as Constants // for struct
|
|
71
|
+
const ret = infer(x, c)
|
|
69
72
|
for (const x of arr.slice(1))
|
|
70
|
-
if (ret !== infer(x)) throw new Error(`glre node system error: defined scope return mismatch`)
|
|
73
|
+
if (ret !== infer(x, c)) throw new Error(`glre node system error: defined scope return mismatch`)
|
|
71
74
|
return ret
|
|
72
75
|
}
|
|
73
76
|
|
|
@@ -78,10 +81,18 @@ export const inferImpl = (target: NodeProxy, c: NodeContext): Constants => {
|
|
|
78
81
|
if (type === 'conversion') return x as Constants
|
|
79
82
|
if (type === 'operator') return inferOperator(infer(y, c), infer(z, c), x as string)
|
|
80
83
|
if (type === 'function') return inferFunction(x as string, children.slice(1), c)
|
|
81
|
-
if (type === 'swizzle') return inferSwizzle((x as string).length)
|
|
82
84
|
if (type === 'ternary') return inferOperator(infer(y, c), infer(z, c), 'add')
|
|
83
85
|
if (type === 'builtin') return inferBuiltin(id)
|
|
84
|
-
if (type === 'define' &&
|
|
86
|
+
if (type === 'define' && isConstants(layout?.type)) return layout?.type
|
|
87
|
+
if (type === 'attribute' && is.arr(x) && c.gl?.count) return inferFromCount(x.length / c.gl.count)
|
|
88
|
+
if (type === 'member') {
|
|
89
|
+
if (isSwizzle(x)) return inferFromCount(x.length)
|
|
90
|
+
if (isNodeProxy(y) && is.str(x)) {
|
|
91
|
+
const field = y.props.fields?.[x] // for variable node of struct member
|
|
92
|
+
if (field) return infer(field, c)
|
|
93
|
+
}
|
|
94
|
+
return 'float' // fallback @TODO FIX
|
|
95
|
+
}
|
|
85
96
|
if (inferFrom) return inferFromArray(inferFrom, c)
|
|
86
97
|
return infer(x, c)
|
|
87
98
|
}
|
|
@@ -89,6 +100,7 @@ export const inferImpl = (target: NodeProxy, c: NodeContext): Constants => {
|
|
|
89
100
|
export const infer = (target: X, c?: NodeContext | null): Constants => {
|
|
90
101
|
if (!c) c = {}
|
|
91
102
|
if (!isNodeProxy(target)) return inferPrimitiveType(target)
|
|
103
|
+
if (is.arr(target)) return inferFromCount(target.length)
|
|
92
104
|
if (!c.infers) c.infers = new WeakMap<NodeProxy, Constants>()
|
|
93
105
|
if (c.infers.has(target)) return c.infers.get(target)!
|
|
94
106
|
const ret = inferImpl(target, c)
|
package/src/node/node.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { is } from '../utils/helpers'
|
|
1
2
|
import { code } from './code'
|
|
2
3
|
import { assign, toVar } from './scope'
|
|
3
|
-
import { conversionToConstant, isConversion, isFunction, isOperator,
|
|
4
|
-
import type { Functions, NodeProps, NodeProxy, NodeTypes, Operators,
|
|
4
|
+
import { conversionToConstant, isConversion, isFunction, isOperator, getId } from './utils'
|
|
5
|
+
import type { Functions, NodeProps, NodeProxy, NodeTypes, Operators, X } from './types'
|
|
5
6
|
|
|
6
7
|
const toPrimitive = (x: X, hint: string) => {
|
|
7
8
|
if (hint === 'string') return code(x)
|
|
@@ -10,6 +11,7 @@ const toPrimitive = (x: X, hint: string) => {
|
|
|
10
11
|
export const node = (type: NodeTypes, props?: NodeProps | null, ...args: X[]) => {
|
|
11
12
|
if (!props) props = {}
|
|
12
13
|
if (args.length) props.children = args
|
|
14
|
+
const listeners = new Set<(value: any) => void>()
|
|
13
15
|
const get = (_: unknown, key: string | Symbol) => {
|
|
14
16
|
if (key === 'type') return type
|
|
15
17
|
if (key === 'props') return props
|
|
@@ -18,17 +20,16 @@ export const node = (type: NodeTypes, props?: NodeProps | null, ...args: X[]) =>
|
|
|
18
20
|
if (key === 'isProxy') return true
|
|
19
21
|
if (key === 'toString') return code.bind(null, x)
|
|
20
22
|
if (key === Symbol.toPrimitive) return toPrimitive.bind(null, x)
|
|
21
|
-
if (
|
|
23
|
+
if (key === 'listeners') return listeners
|
|
22
24
|
if (isOperator(key)) return (...y: X[]) => operator(key, x, ...y)
|
|
23
25
|
if (isFunction(key)) return (...y: X[]) => function_(key, x, ...y)
|
|
24
26
|
if (isConversion(key)) return () => conversion(conversionToConstant(key), x)
|
|
27
|
+
if (is.str(key)) return member(key, x) // for struct
|
|
25
28
|
}
|
|
26
29
|
const set = (_: unknown, key: string, y: X) => {
|
|
27
|
-
if (
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
return false
|
|
30
|
+
if (key === 'value') listeners.forEach((fun) => fun(y))
|
|
31
|
+
if (is.str(key)) member(key, x).assign(y)
|
|
32
|
+
return true
|
|
32
33
|
}
|
|
33
34
|
const x = new Proxy({}, { get, set }) as unknown as NodeProxy
|
|
34
35
|
return x
|
|
@@ -43,8 +44,8 @@ export const builtin = (id = getId()) => node('builtin', { id })
|
|
|
43
44
|
export const vertexStage = (x: X, id = getId()) => node('varying', { id, inferFrom: [x] }, x)
|
|
44
45
|
|
|
45
46
|
// Node shorthands
|
|
46
|
-
export const swizzle = (key: Swizzles, x: X) => node('swizzle', null, key, x)
|
|
47
47
|
export const operator = (key: Operators, ...x: X[]) => node('operator', null, key, ...x)
|
|
48
48
|
export const function_ = (key: Functions, ...x: X[]) => node('function', null, key, ...x)
|
|
49
49
|
export const conversion = (key: string, ...x: X[]) => node('conversion', null, key, ...x)
|
|
50
|
-
export const
|
|
50
|
+
export const member = (key: string, x: X) => node('member', null, key, x)
|
|
51
|
+
export const select = (x: X, y: X, z: X) => node('ternary', null, x, y, z) // x ? y : z @TODO REMOVE
|
package/src/node/parse.ts
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { formatConversions, joins } from './utils'
|
|
1
|
+
import { is } from '../utils/helpers'
|
|
3
2
|
import { code } from './code'
|
|
4
|
-
import
|
|
3
|
+
import { infer } from './infer'
|
|
4
|
+
import { formatConversions, isConstants, addDependency } from './utils'
|
|
5
|
+
import type { Constants, NodeContext, NodeProps, NodeProxy, X } from './types'
|
|
6
|
+
|
|
7
|
+
export const parseArray = (children: X[], c: NodeContext) => {
|
|
8
|
+
return children
|
|
9
|
+
.filter((x) => !is.und(x) && !is.nul(x))
|
|
10
|
+
.map((x) => code(x, c))
|
|
11
|
+
.join(', ')
|
|
12
|
+
}
|
|
5
13
|
|
|
6
14
|
export const parseTexture = (c: NodeContext, y: X, z: X, w: X) => {
|
|
7
15
|
if (c.isWebGL) {
|
|
8
16
|
const args = w ? [y, z, w] : [y, z]
|
|
9
|
-
return `texture(${
|
|
17
|
+
return `texture(${parseArray(args, c)})`
|
|
10
18
|
}
|
|
11
19
|
const _y = code(y, c)
|
|
12
20
|
const args = [_y, _y + 'Sampler', code(z, c)]
|
|
@@ -43,14 +51,14 @@ export const parseSwitch = (c: NodeContext, x: X, children: X[]) => {
|
|
|
43
51
|
}
|
|
44
52
|
|
|
45
53
|
export const parseDeclare = (c: NodeContext, x: X, y: X) => {
|
|
46
|
-
const
|
|
54
|
+
const type = infer(x, c)
|
|
47
55
|
const varName = (y as any)?.props?.id
|
|
48
|
-
if (c.isWebGL) return `${
|
|
49
|
-
const wgslType = formatConversions(
|
|
56
|
+
if (c.isWebGL) return `${type} ${varName} = ${code(x, c)};`
|
|
57
|
+
const wgslType = formatConversions(type)
|
|
50
58
|
return `var ${varName}: ${wgslType} = ${code(x, c)};`
|
|
51
59
|
}
|
|
52
60
|
|
|
53
|
-
export const parseDefine = (c: NodeContext, props: NodeProps, returnType: Constants) => {
|
|
61
|
+
export const parseDefine = (c: NodeContext, props: NodeProps, returnType: Constants | string) => {
|
|
54
62
|
const { id, children = [], layout } = props
|
|
55
63
|
const [x, ...args] = children
|
|
56
64
|
const argParams: [name: string, type: string][] = []
|
|
@@ -65,10 +73,14 @@ export const parseDefine = (c: NodeContext, props: NodeProps, returnType: Consta
|
|
|
65
73
|
}
|
|
66
74
|
const ret = []
|
|
67
75
|
if (c?.isWebGL) {
|
|
68
|
-
for (const [
|
|
76
|
+
for (const [paramId, type] of argParams) {
|
|
77
|
+
addDependency(c, id!, type)
|
|
78
|
+
params.push(`${type} ${paramId}`)
|
|
79
|
+
}
|
|
80
|
+
addDependency(c, id!, returnType)
|
|
69
81
|
ret.push(`${returnType} ${id}(${params}) {`)
|
|
70
82
|
} else {
|
|
71
|
-
for (const [
|
|
83
|
+
for (const [paramId, type] of argParams) params.push(`${paramId}: ${formatConversions(type, c)}`)
|
|
72
84
|
ret.push(`fn ${id}(${params}) -> ${formatConversions(returnType, c)} {`)
|
|
73
85
|
}
|
|
74
86
|
const scopeCode = code(x, c)
|
|
@@ -77,42 +89,72 @@ export const parseDefine = (c: NodeContext, props: NodeProps, returnType: Consta
|
|
|
77
89
|
return ret.join('\n')
|
|
78
90
|
}
|
|
79
91
|
|
|
92
|
+
export const parseStructHead = (c: NodeContext, id: string, fields: Record<string, NodeProxy> = {}) => {
|
|
93
|
+
const lines: string[] = []
|
|
94
|
+
for (const key in fields) {
|
|
95
|
+
const fieldType = fields[key]
|
|
96
|
+
const type = infer(fieldType, c)
|
|
97
|
+
if (c.isWebGL) addDependency(c, id, type)
|
|
98
|
+
lines.push(c.isWebGL ? `${type} ${key};` : `${key}: ${formatConversions(type, c)},`)
|
|
99
|
+
}
|
|
100
|
+
const ret = lines.join('\n ')
|
|
101
|
+
return `struct ${id} {\n ${ret}\n};`
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export const parseStruct = (
|
|
105
|
+
c: NodeContext,
|
|
106
|
+
id: string,
|
|
107
|
+
instanceId = '',
|
|
108
|
+
fields?: Record<string, NodeProxy>,
|
|
109
|
+
initialValues?: Record<string, NodeProxy>
|
|
110
|
+
) => {
|
|
111
|
+
if (c.isWebGL) {
|
|
112
|
+
if (initialValues) {
|
|
113
|
+
const ordered = []
|
|
114
|
+
for (const key in fields) ordered.push(initialValues[key])
|
|
115
|
+
return `${id} ${instanceId} = ${id}(${parseArray(ordered, c)});`
|
|
116
|
+
} else return `${id} ${instanceId};`
|
|
117
|
+
} else {
|
|
118
|
+
if (initialValues) {
|
|
119
|
+
const ordered = []
|
|
120
|
+
for (const key in fields) ordered.push(initialValues[key])
|
|
121
|
+
return `var ${instanceId}: ${id} = ${id}(${parseArray(ordered, c)});`
|
|
122
|
+
} else return `var ${instanceId}: ${id};`
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
80
126
|
/**
|
|
81
127
|
* headers
|
|
82
128
|
*/
|
|
83
|
-
export const parseVaryingHead = (c: NodeContext, id: string,
|
|
84
|
-
return c.isWebGL
|
|
85
|
-
? `${varType} ${id};`
|
|
86
|
-
: `@location(${c.vertVaryings!.size}) ${id}: ${formatConversions(varType, c)}`
|
|
129
|
+
export const parseVaryingHead = (c: NodeContext, id: string, type: string) => {
|
|
130
|
+
return c.isWebGL ? `${type} ${id};` : `@location(${c.code?.vertVaryings?.size || 0}) ${id}: ${formatConversions(type, c)}`
|
|
87
131
|
}
|
|
88
132
|
|
|
89
|
-
export const parseUniformHead = (c: NodeContext, id: string,
|
|
90
|
-
const isTexture =
|
|
133
|
+
export const parseUniformHead = (c: NodeContext, id: string, type: Constants) => {
|
|
134
|
+
const isTexture = type === 'sampler2D' || type === 'texture'
|
|
91
135
|
if (c.isWebGL)
|
|
92
136
|
return isTexture //
|
|
93
137
|
? `uniform sampler2D ${id};`
|
|
94
|
-
: `uniform ${
|
|
138
|
+
: `uniform ${type} ${id};`
|
|
95
139
|
if (isTexture) {
|
|
96
|
-
const { group = 1, binding = 0 } = c.webgpu?.textures.map.get(id) || {}
|
|
140
|
+
const { group = 1, binding = 0 } = c.gl?.webgpu?.textures.map.get(id) || {}
|
|
97
141
|
return (
|
|
98
142
|
`@group(${group}) @binding(${binding}) var ${id}Sampler: sampler;\n` +
|
|
99
143
|
`@group(${group}) @binding(${binding + 1}) var ${id}: texture_2d<f32>;`
|
|
100
144
|
)
|
|
101
145
|
}
|
|
102
|
-
const { group = 0, binding = 0 } = c.webgpu?.uniforms.map.get(id) || {}
|
|
103
|
-
const wgslType = formatConversions(
|
|
146
|
+
const { group = 0, binding = 0 } = c.gl?.webgpu?.uniforms.map.get(id) || {}
|
|
147
|
+
const wgslType = formatConversions(type, c)
|
|
104
148
|
return `@group(${group}) @binding(${binding}) var<uniform> ${id}: ${wgslType};`
|
|
105
149
|
}
|
|
106
150
|
|
|
107
|
-
export const parseAttribHead = (c: NodeContext, id: string,
|
|
108
|
-
if (c.isWebGL) return `${
|
|
109
|
-
const { location = 0 } = c.webgpu?.attribs.map.get(id) || {}
|
|
110
|
-
const wgslType = formatConversions(
|
|
151
|
+
export const parseAttribHead = (c: NodeContext, id: string, type: Constants) => {
|
|
152
|
+
if (c.isWebGL) return `${type} ${id};`
|
|
153
|
+
const { location = 0 } = c.gl?.webgpu?.attribs.map.get(id) || {}
|
|
154
|
+
const wgslType = formatConversions(type, c)
|
|
111
155
|
return `@location(${location}) ${id}: ${wgslType}`
|
|
112
156
|
}
|
|
113
157
|
|
|
114
|
-
export const parseConstantHead = (c: NodeContext, id: string,
|
|
115
|
-
return c.isWebGL
|
|
116
|
-
? `const ${varType} ${id} = ${value};`
|
|
117
|
-
: `const ${id}: ${formatConversions(varType, c)} = ${value};`
|
|
158
|
+
export const parseConstantHead = (c: NodeContext, id: string, type: Constants, value: string) => {
|
|
159
|
+
return c.isWebGL ? `const ${type} ${id} = ${value};` : `const ${id}: ${formatConversions(type, c)} = ${value};`
|
|
118
160
|
}
|