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/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
- 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
- }
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 === 'swizzle') return `${code(y, c)}.${code(x, c)}`
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(x, c)}, ${code(y, c)}, ${code(z, c)})`
50
- if (type === 'conversion') return `${formatConversions(x, c)}(${joins(children.slice(1), 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 `(-${joins(children.slice(1), c)})`
50
+ if (x === 'negate') return `(-${parseArray(children.slice(1), c)})`
57
51
  if (x === 'texture') return parseTexture(c, y, z, w)
58
- return `${x}(${joins(children.slice(1), c)})`
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
- const ret = `${id}(${joins(children.slice(1), c)})`
75
- if (c.headers.has(id)) return ret
76
- c.headers.set(id, parseDefine(c, props, infer(target, c)))
77
- return ret
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
- c.vertInputs.set(id, parseAttribHead(c, id, infer(target, c)))
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') head = parseUniformHead(c, id, infer(target, c))
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 CONSTANTS = [
4
- 'bool',
5
- 'uint',
6
- 'int',
7
- 'float',
8
- 'bvec2',
9
- 'ivec2',
10
- 'uvec2',
11
- 'vec2',
12
- 'bvec3',
13
- 'ivec3',
14
- 'uvec3',
15
- 'vec3',
16
- 'bvec4',
17
- 'ivec4',
18
- 'uvec4',
19
- 'vec4',
20
- 'color',
21
- 'mat2',
22
- 'mat3',
23
- 'mat4',
24
- 'texture',
25
- 'sampler2D',
26
- ] as const
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
- const head = Array.from(c.headers!.values()).join('\n')
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
- c.headers?.clear()
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!.values()) ret.push(`in ${code}`)
36
- for (const code of c.vertOutputs!.values()) ret.push(`out ${code}`)
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!.entries()) ret.push(` ${id} = ${code};`)
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!.entries()) ret.push(` out.${id} = ${code};`)
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
- c.headers?.clear()
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!.values()) ret.push(`in ${code}`)
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: X) => c('float', x)
102
- export const int = (x: X) => c('int', x)
103
- export const uint = (x: X) => c('uint', x)
104
- export const bool = (x: X) => c('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(1280, 800), 'iResolution')
129
- export const iMouse = u(vec2(0, 0), 'iMouse')
130
- export const iTime = u(float(0), 'iTime')
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 { isConstantsType, isNodeProxy } from './utils'
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.num(x)) return 'float'
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 inferSwizzle = (count: number): Constants => {
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 ret = infer(arr[0], c)
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' && isConstantsType(layout?.type)) return layout?.type
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, isSwizzle, getId, isNodeProxy } from './utils'
4
- import type { Functions, NodeProps, NodeProxy, NodeTypes, Operators, Swizzles, X } from './types'
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 (isSwizzle(key)) return swizzle(key, x)
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 (isSwizzle(key)) {
28
- swizzle(key, x).assign(y)
29
- return true
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 select = (x: X, y: X, z: X) => node('ternary', null, x, y, z) // x ? y : z
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 { infer } from './infer'
2
- import { formatConversions, joins } from './utils'
1
+ import { is } from '../utils/helpers'
3
2
  import { code } from './code'
4
- import type { Constants, NodeContext, NodeProps, X } from './types'
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(${joins(args, c)})`
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 varType = infer(x, c)
54
+ const type = infer(x, c)
47
55
  const varName = (y as any)?.props?.id
48
- if (c.isWebGL) return `${varType} ${varName} = ${code(x, c)};`
49
- const wgslType = formatConversions(varType)
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 [id, type] of argParams) params.push(`${type} ${id}`)
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 [id, type] of argParams) params.push(`${id}: ${formatConversions(type, c)}`)
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, varType: 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, varType: Constants) => {
90
- const isTexture = varType === 'sampler2D' || varType === 'texture'
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 ${varType} ${id};`
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(varType, c)
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, 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)
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, varType: Constants, value: 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
  }