glre 0.28.0 → 0.30.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,67 +1,92 @@
1
1
  import { is } from '../utils/helpers'
2
2
  import { infer } from './infer'
3
- import { joins, getOperator, formatConversions } from './utils'
3
+ import { getBluiltin, getOperator, generateDefine, formatConversions, joins } from './utils'
4
4
  import type { NodeConfig, X } from './types'
5
5
 
6
6
  export const code = (target: X, c?: NodeConfig | null): string => {
7
7
  if (!c) c = {}
8
- if (!c.uniforms) c.uniforms = new Set()
9
- if (!c.functions) c.functions = new Set()
10
- if (is.num(target)) return target.toFixed(1)
8
+ if (!c.headers) c.headers = new Map()
11
9
  if (is.str(target)) return target
12
- if (is.bol(target)) return target.toString()
10
+ if (is.num(target)) {
11
+ const ret = `${target}`
12
+ if (ret.includes('.')) return ret
13
+ return ret + '.0'
14
+ }
15
+ if (is.bol(target)) return target ? 'true' : 'false'
13
16
  if (!target) return '' // ignore if no target
14
17
  const { type, props } = target
15
18
  const { id = '', children = [] } = props
16
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
+ }
17
28
  if (type === 'uniform') {
29
+ if (c.headers.has(id)) return id
30
+ if (!c.binding) c.binding = 0
18
31
  const varType = infer(target, c)
19
- c.uniforms.add(`${varType} ${id}`)
20
- c.onUniform?.(id, props.value)
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)
21
51
  return id
22
52
  }
23
- if (type === 'variable' || type === 'varying' || type === 'constant' || type === 'attribute') return id
24
- if (type === 'vertex_stage') return code(x, c)
53
+ /**
54
+ * variables
55
+ */
56
+ if (type === 'variable') return id
25
57
  if (type === 'swizzle') return `${code(y, c)}.${code(x, c)}`
58
+ if (type === 'ternary') return `(${code(x, c)} ? ${code(y, c)} : ${code(z, c)})`
59
+ if (type === 'builtin') return c?.isWebGL ? getBluiltin(id) : id
60
+ if (type === 'conversion') return `${formatConversions(x, c)}(${joins(children.slice(1), c)})`
26
61
  if (type === 'operator') {
27
62
  if (x === 'not' || x === 'bitNot') return `!${code(y, c)}`
28
63
  return `(${code(y, c)} ${getOperator(x)} ${code(z, c)})`
29
64
  }
30
- if (type === 'math_fun') return `${x}(${joins(children.slice(1), c)})`
31
- if (type === 'conversions') return `${formatConversions(x, c)}(${joins(children.slice(1), c)})`
65
+ if (type === 'function') {
66
+ if (x === 'negate') return `(-${joins(children.slice(1), c)})`
67
+ return `${x}(${joins(children.slice(1), c)})`
68
+ }
69
+ /**
70
+ * scopes
71
+ */
32
72
  if (type === 'scope') return children.map((child: any) => code(child, c)).join('\n')
33
73
  if (type === 'assign') return `${code(x, c)} = ${code(y, c)};`
34
- if (type === 'fn_run') {
35
- c.functions.add(code(x, c))
36
- return `${id}(${children
37
- .slice(1)
38
- .map((child) => code(child, c))
39
- .join(', ')})`
40
- }
41
- if (type === 'fn_def') {
42
- const { paramInfo = [], returnType } = props
43
- const scopeCode = code(x, c)
44
- const returnCode = y ? `return ${code(y, c)};` : ''
45
- if (c?.isWebGL) {
46
- const params = paramInfo.map(({ name, type }) => `${type} ${name}`).join(', ')
47
- return `${returnType} ${id}(${params}) {\n${scopeCode}\n${returnCode}\n}`
48
- } else {
49
- const wgslReturnType = formatConversions(returnType, c)
50
- const wgslParams = paramInfo
51
- .map(({ name, type }) => {
52
- const wgslParamType = formatConversions(type, c)
53
- return `${name}: ${wgslParamType}`
54
- })
55
- .join(', ')
56
- return `fn ${id}(${wgslParams}) -> ${wgslReturnType} {\n${scopeCode}\n${returnCode}\n}`
57
- }
74
+ if (type === 'loop')
75
+ return c.isWebGL
76
+ ? `for (int i = 0; i < ${x}; i += 1) {\n${code(y, c)}\n}`
77
+ : `for (var i: i32 = 0; i < ${x}; i++) {\n${code(y, c)}\n}`
78
+ if (type === 'define') {
79
+ const args = children.slice(2)
80
+ const ret = `${id}(${args.map((arg) => code(arg, c))})`
81
+ if (c.headers.has(id)) return ret
82
+ c.headers.set(id, generateDefine(props, c))
83
+ return ret
58
84
  }
59
- if (type === 'loop') return `for (int i = 0; i < ${x}; i++) {\n${code(y, c)}\n}`
60
85
  if (type === 'if') {
61
86
  let ret = `if (${code(x, c)}) {\n${code(y, c)}\n}`
62
87
  for (let i = 2; i < children.length; i += 2) {
63
- const isLast = i >= children.length - 1
64
- ret += !isLast
88
+ const isElseIf = i >= children.length - 1
89
+ ret += !isElseIf
65
90
  ? ` else if (${code(children[i], c)}) {\n${code(children[i + 1], c)}\n}`
66
91
  : ` else {\n${code(children[i], c)}\n}`
67
92
  }
@@ -69,35 +94,22 @@ export const code = (target: X, c?: NodeConfig | null): string => {
69
94
  }
70
95
  if (type === 'switch') {
71
96
  let ret = `switch (${code(x, c)}) {\n`
72
- for (const child of children.slice(1)) ret += code(child, c) + '\n'
73
- ret += '}'
74
- return ret
75
- }
76
- if (type === 'case') {
77
- const values = children.slice(0, -1)
78
- const scope = children[children.length - 1]
79
- let ret = ''
80
- for (const value of values) {
81
- ret += `case ${code(value, c)}:\n`
97
+ for (let i = 1; i < children.length; i += 2) {
98
+ const isDefault = i >= children.length - 1
99
+ if (isDefault && children.length % 2 === 0) {
100
+ ret += `default:\n${code(children[i], c)}\nbreak;\n`
101
+ } else if (i + 1 < children.length)
102
+ ret += `case ${code(children[i], c)}:\n${code(children[i + 1], c)}\nbreak;\n`
82
103
  }
83
- ret += `${code(scope, c)}\nbreak;\n`
104
+ ret += '}'
84
105
  return ret
85
106
  }
86
- if (type === 'default') `default:\n${code(x, c)}\nbreak;\n`
87
- if (type === 'ternary') return `(${code(x, c)} ? ${code(y, c)} : ${code(z, c)})`
88
107
  if (type === 'declare') {
89
- const varType = infer(y, c)
90
- const varName = (x as any)?.props?.id
91
- if (c.isWebGL) return `${varType} ${varName} = ${code(y, c)};`
108
+ const varType = infer(x, c)
109
+ const varName = (y as any)?.props?.id
110
+ if (c.isWebGL) return `${varType} ${varName} = ${code(x, c)};`
92
111
  const wgslType = formatConversions(varType)
93
- return `var ${varName}: ${wgslType} = ${code(y, c)};`
94
- }
95
- if (type === 'builtin') {
96
- if (c?.isWebGL) {
97
- if (id === 'position') return 'gl_FragCoord'
98
- if (id === 'uv') return 'gl_FragCoord.xy'
99
- }
100
- return id
112
+ return `var ${varName}: ${wgslType} = ${code(x, c)};`
101
113
  }
102
114
  return code(x, c)
103
115
  }
package/src/node/const.ts CHANGED
@@ -6,16 +6,16 @@ export const CONSTANTS = [
6
6
  'int',
7
7
  'float',
8
8
  'bvec2',
9
- 'bvec3',
10
- 'bvec4',
11
9
  'ivec2',
12
- 'ivec3',
13
- 'ivec4',
14
10
  'uvec2',
15
- 'uvec3',
16
- 'uvec4',
17
11
  'vec2',
12
+ 'bvec3',
13
+ 'ivec3',
14
+ 'uvec3',
18
15
  'vec3',
16
+ 'bvec4',
17
+ 'ivec4',
18
+ 'uvec4',
19
19
  'vec4',
20
20
  'color',
21
21
  'mat2',
@@ -24,26 +24,26 @@ export const CONSTANTS = [
24
24
  ] as const
25
25
 
26
26
  export const CONVERSIONS = [
27
- 'toFloat',
28
- 'toInt',
29
- 'toUint',
30
27
  'toBool',
31
- 'toVec2',
32
- 'toVec3',
33
- 'toVec4',
28
+ 'toUint',
29
+ 'toInt',
30
+ 'toFloat',
31
+ 'toBvec2',
34
32
  'toIvec2',
35
- 'toIvec3',
36
- 'toIvec4',
37
33
  'toUvec2',
38
- 'toUvec3',
39
- 'toUvec4',
40
- 'toBvec2',
34
+ 'toVec2',
41
35
  'toBvec3',
36
+ 'toIvec3',
37
+ 'toUvec3',
38
+ 'toVec3',
42
39
  'toBvec4',
40
+ 'toIvec4',
41
+ 'toUvec4',
42
+ 'toVec4',
43
+ 'toColor',
43
44
  'toMat2',
44
45
  'toMat3',
45
46
  'toMat4',
46
- 'toColor',
47
47
  ] as const
48
48
 
49
49
  export const OPERATORS = {
@@ -69,7 +69,6 @@ export const OPERATORS = {
69
69
 
70
70
  export const OPERATOR_KEYS = Object.keys(OPERATORS) as (keyof typeof OPERATORS)[]
71
71
 
72
- // Function return type classification
73
72
  export const SCALAR_RETURN_FUNCTIONS = ['dot', 'distance', 'length', 'lengthSq', 'determinant', 'luminance'] as const
74
73
 
75
74
  export const BOOL_RETURN_FUNCTIONS = ['all', 'any'] as const
@@ -171,8 +170,37 @@ export const COMPONENT_COUNT_TO_TYPE = {
171
170
  } as const
172
171
 
173
172
  export const BUILTIN_TYPES = {
173
+ // WGSL builtin variables
174
+ position: 'vec4',
175
+ vertex_index: 'uint',
176
+ instance_index: 'uint',
177
+ front_facing: 'bool',
178
+ frag_depth: 'float',
179
+ sample_index: 'uint',
180
+ sample_mask: 'uint',
181
+ point_coord: 'vec2',
182
+
183
+ // TSL compatible variables
184
+ positionLocal: 'vec3',
185
+ positionWorld: 'vec3',
186
+ positionView: 'vec3',
187
+ normalLocal: 'vec3',
188
+ normalWorld: 'vec3',
189
+ normalView: 'vec3',
190
+ screenCoordinate: 'vec2',
191
+ screenUV: 'vec2',
192
+
193
+ // Legacy GLSL variables (for backward compatibility)
174
194
  gl_FragCoord: 'vec4',
175
- position: 'vec3',
195
+ gl_VertexID: 'uint',
196
+ gl_InstanceID: 'uint',
197
+ gl_FrontFacing: 'bool',
198
+ gl_FragDepth: 'float',
199
+ gl_SampleID: 'uint',
200
+ gl_SampleMask: 'uint',
201
+ gl_PointCoord: 'vec2',
202
+
203
+ // Common variables
176
204
  normal: 'vec3',
177
205
  uv: 'vec2',
178
206
  color: 'vec4',
@@ -188,3 +216,15 @@ export const COMPARISON_OPERATORS = [
188
216
  ] as const
189
217
 
190
218
  export const LOGICAL_OPERATORS = ['and', 'or'] as const
219
+
220
+ export const WGSL_TO_GLSL_BUILTIN = {
221
+ position: 'gl_FragCoord',
222
+ vertex_index: 'gl_VertexID',
223
+ instance_index: 'gl_InstanceID',
224
+ front_facing: 'gl_FrontFacing',
225
+ frag_depth: 'gl_FragDepth',
226
+ sample_index: 'gl_SampleID',
227
+ sample_mask: 'gl_SampleMask',
228
+ point_coord: 'gl_PointCoord',
229
+ uv: 'gl_FragCoord.xy',
230
+ } as const
package/src/node/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { f, n, node, u } from './node'
1
+ import { builtin, conversion as c, function_ as f, uniform } from './node'
2
2
  import { hex2rgb } from './utils'
3
3
  import { is } from '../utils/helpers'
4
4
  import type { X } from './types'
@@ -10,53 +10,56 @@ export * from './scope'
10
10
  export * from './types'
11
11
  export * from './utils'
12
12
 
13
- // Default uniforms
14
- export const iResolution = u('iResolution', [1280, 800])
15
- export const iMouse = u('iMouse', [0, 0])
16
- export const iTime = u('iTime', 0)
17
- export const position = node('variable', { id: 'gl_FragCoord' })
18
-
19
- // Default attributes
20
- export const uv = (index = 0) => node('attribute', { id: `uv${index || ''}` })
21
- export const vertexColor = (index = 0) => node('attribute', { id: `color${index || ''}` })
22
- export const attribute = (id: string, type?: string) => node('attribute', { id, type })
23
- export const vertexStage = (value: X) => node('vertex_stage', null, value)
13
+ // Builtin Variables
14
+ export const position = builtin('position')
15
+ export const vertexIndex = builtin('vertex_index')
16
+ export const instanceIndex = builtin('instance_index')
17
+ export const frontFacing = builtin('front_facing')
18
+ export const fragDepth = builtin('frag_depth')
19
+ export const sampleIndex = builtin('sample_index')
20
+ export const sampleMask = builtin('sample_mask')
21
+ export const pointCoord = builtin('point_coord')
24
22
 
25
- // Buildin Variables
26
- export const positionLocal = node('builtin', { id: 'positionLocal' })
27
- export const positionWorld = node('builtin', { id: 'positionWorld' })
28
- export const positionView = node('builtin', { id: 'positionView' })
29
- export const normalLocal = node('builtin', { id: 'normalLocal' })
30
- export const normalWorld = node('builtin', { id: 'normalWorld' })
31
- export const normalView = node('builtin', { id: 'normalView' })
32
- export const screenCoordinate = node('builtin', { id: 'screenCoordinate' })
33
- export const screenUV = node('builtin', { id: 'screenUV' })
23
+ // TSL Compatible Builtin Variables
24
+ export const normalLocal = builtin('normalLocal')
25
+ export const normalWorld = builtin('normalWorld')
26
+ export const normalView = builtin('normalView')
27
+ export const positionLocal = builtin('position')
28
+ export const positionWorld = builtin('positionWorld')
29
+ export const positionView = builtin('positionView')
30
+ export const screenCoordinate = builtin('screenCoordinate')
31
+ export const screenUV = builtin('screenUV')
34
32
 
35
33
  // Type constructors
36
- export const float = (x: X) => n('float', x)
37
- export const int = (x: X) => n('int', x)
38
- export const uint = (x: X) => n('uint', x)
39
- export const bool = (x: X) => n('bool', x)
40
- export const vec2 = (x?: X, y?: X) => n('vec2', x, y)
41
- export const vec3 = (x?: X, y?: X, z?: X) => n('vec3', x, y, z)
42
- export const vec4 = (x?: X, y?: X, z?: X, w?: X) => n('vec4', x, y, z, w)
43
- export const mat2 = (...args: X[]) => n('mat2', ...args)
44
- export const mat3 = (...args: X[]) => n('mat3', ...args)
45
- export const mat4 = (...args: X[]) => n('mat4', ...args)
46
- export const ivec2 = (x?: X, y?: X) => n('ivec2', x, y)
47
- export const ivec3 = (x?: X, y?: X, z?: X) => n('ivec3', x, y, z)
48
- export const ivec4 = (x?: X, y?: X, z?: X, w?: X) => n('ivec4', x, y, z, w)
49
- export const uvec2 = (x?: X, y?: X) => n('uvec2', x, y)
50
- export const uvec3 = (x?: X, y?: X, z?: X) => n('uvec3', x, y, z)
51
- export const uvec4 = (x?: X, y?: X, z?: X, w?: X) => n('uvec4', x, y, z, w)
52
- export const bvec2 = (x?: X, y?: X) => n('bvec2', x, y)
53
- export const bvec3 = (x?: X, y?: X, z?: X) => n('bvec3', x, y, z)
54
- export const bvec4 = (x?: X, y?: X, z?: X, w?: X) => n('bvec4', x, y, z, w)
34
+ export const float = (x: X) => c('float', x)
35
+ export const int = (x: X) => c('int', x)
36
+ export const uint = (x: X) => c('uint', x)
37
+ export const bool = (x: X) => c('bool', x)
38
+ export const vec2 = (x?: X, y?: X) => c('vec2', x, y)
39
+ export const vec3 = (x?: X, y?: X, z?: X) => c('vec3', x, y, z)
40
+ export const vec4 = (x?: X, y?: X, z?: X, w?: X) => c('vec4', x, y, z, w)
41
+ export const mat2 = (...args: X[]) => c('mat2', ...args)
42
+ export const mat3 = (...args: X[]) => c('mat3', ...args)
43
+ export const mat4 = (...args: X[]) => c('mat4', ...args)
44
+ export const ivec2 = (x?: X, y?: X) => c('ivec2', x, y)
45
+ export const ivec3 = (x?: X, y?: X, z?: X) => c('ivec3', x, y, z)
46
+ export const ivec4 = (x?: X, y?: X, z?: X, w?: X) => c('ivec4', x, y, z, w)
47
+ export const uvec2 = (x?: X, y?: X) => c('uvec2', x, y)
48
+ export const uvec3 = (x?: X, y?: X, z?: X) => c('uvec3', x, y, z)
49
+ export const uvec4 = (x?: X, y?: X, z?: X, w?: X) => c('uvec4', x, y, z, w)
50
+ export const bvec2 = (x?: X, y?: X) => c('bvec2', x, y)
51
+ export const bvec3 = (x?: X, y?: X, z?: X) => c('bvec3', x, y, z)
52
+ export const bvec4 = (x?: X, y?: X, z?: X, w?: X) => c('bvec4', x, y, z, w)
55
53
  export const color = (r?: X, g?: X, b?: X) => {
56
54
  if (is.num(r) && is.und(g) && is.und(b)) return vec3(...hex2rgb(r))
57
55
  return vec3(r, g, b)
58
56
  }
59
57
 
58
+ // Default uniforms
59
+ export const iResolution = uniform(vec2(1280, 800), 'iResolution')
60
+ export const iMouse = uniform(vec2(0, 0), 'iMouse')
61
+ export const iTime = uniform(float(0), 'iTime')
62
+
60
63
  // Texture Functions
61
64
  export const texture = (x: X, y: X, z?: X) => f('texture', x, y, z)
62
65
  export const cubeTexture = (x: X, y: X, z?: X) => f('cubeTexture', x, y, z)
package/src/node/infer.ts CHANGED
@@ -1,29 +1,47 @@
1
1
  import { is } from '../utils/helpers'
2
- import { isNodeProxy } from './utils'
3
2
  import {
4
- CONSTANTS,
5
- SCALAR_RETURN_FUNCTIONS,
6
3
  BOOL_RETURN_FUNCTIONS,
7
- PRESERVE_TYPE_FUNCTIONS,
8
- VEC3_RETURN_FUNCTIONS,
4
+ BUILTIN_TYPES,
5
+ COMPARISON_OPERATORS,
6
+ COMPONENT_COUNT_TO_TYPE,
7
+ CONSTANTS,
9
8
  FIRST_ARG_TYPE_FUNCTIONS,
10
9
  HIGHEST_TYPE_FUNCTIONS,
11
- VEC4_RETURN_FUNCTIONS,
12
- COMPARISON_OPERATORS,
13
10
  LOGICAL_OPERATORS,
14
- COMPONENT_COUNT_TO_TYPE,
15
- BUILTIN_TYPES,
11
+ PRESERVE_TYPE_FUNCTIONS,
12
+ SCALAR_RETURN_FUNCTIONS,
13
+ VEC3_RETURN_FUNCTIONS,
14
+ VEC4_RETURN_FUNCTIONS,
16
15
  } from './const'
17
- import type { Constants, NodeConfig, X } from './types'
16
+ import { isNodeProxy } from './utils'
17
+ import type { Constants, NodeConfig, NodeProxy, X } from './types'
18
18
 
19
- const inferPrimitiveType = (x: any): Constants => {
20
- if (is.bol(x)) return 'bool'
21
- if (is.num(x)) return Number.isInteger(x) ? 'int' : 'float'
22
- if (is.arr(x)) return COMPONENT_COUNT_TO_TYPE[x.length as keyof typeof COMPONENT_COUNT_TO_TYPE] || 'float'
23
- return 'float'
19
+ const getHighestPriorityType = (args: X[], c: NodeConfig) => {
20
+ return args.reduce((highest, current) => {
21
+ const currentType = infer(current, c)
22
+ const highestPriority = CONSTANTS.indexOf(highest as any)
23
+ const currentPriority = CONSTANTS.indexOf(currentType as any)
24
+ return currentPriority > highestPriority ? currentType : highest
25
+ }, 'float') as Constants
26
+ }
27
+
28
+ const inferBuiltin = (id: string | undefined): Constants => {
29
+ return BUILTIN_TYPES[id as keyof typeof BUILTIN_TYPES]!
30
+ }
31
+
32
+ const inferFunction = (funcName: string, args: X[], c: NodeConfig): Constants => {
33
+ const firstArgType = args.length > 0 ? infer(args[0], c) : 'float'
34
+ if (FIRST_ARG_TYPE_FUNCTIONS.includes(funcName as any)) return firstArgType
35
+ if (SCALAR_RETURN_FUNCTIONS.includes(funcName as any)) return 'float'
36
+ if (BOOL_RETURN_FUNCTIONS.includes(funcName as any)) return 'bool'
37
+ if (PRESERVE_TYPE_FUNCTIONS.includes(funcName as any)) return firstArgType
38
+ if (VEC3_RETURN_FUNCTIONS.includes(funcName as any)) return 'vec3'
39
+ if (VEC4_RETURN_FUNCTIONS.includes(funcName as any)) return 'vec4'
40
+ if (HIGHEST_TYPE_FUNCTIONS.includes(funcName as any)) return getHighestPriorityType(args, c)
41
+ return firstArgType
24
42
  }
25
43
 
26
- const inferBinaryOpType = (leftType: string, rightType: string, op: string): Constants => {
44
+ const inferOperator = (leftType: string, rightType: string, op: string): Constants => {
27
45
  if (COMPARISON_OPERATORS.includes(op as any)) return 'bool'
28
46
  if (LOGICAL_OPERATORS.includes(op as any)) return 'bool'
29
47
  if (leftType === rightType) return leftType as Constants
@@ -34,60 +52,41 @@ const inferBinaryOpType = (leftType: string, rightType: string, op: string): Con
34
52
  return (leftPriority >= rightPriority ? leftType : rightType) as Constants
35
53
  }
36
54
 
37
- const getHighestPriorityType = (args: X[]) => {
38
- return args.reduce((highest, current) => {
39
- const currentType = infer(current)
40
- const highestPriority = CONSTANTS.indexOf(highest as any)
41
- const currentPriority = CONSTANTS.indexOf(currentType as any)
42
- return currentPriority > highestPriority ? currentType : highest
43
- }, 'float')
44
- }
45
- const inferSwizzleType = (count: number): Constants => {
46
- return COMPONENT_COUNT_TO_TYPE[count as keyof typeof COMPONENT_COUNT_TO_TYPE] || 'vec4'
47
- }
48
-
49
- const inferBuiltinType = (id: string | undefined): Constants => {
50
- if (!id) return 'vec3'
51
- return BUILTIN_TYPES[id as keyof typeof BUILTIN_TYPES]!
55
+ const inferPrimitiveType = (x: any): Constants => {
56
+ if (is.bol(x)) return 'bool'
57
+ if (is.num(x)) return 'float' // Number.isInteger(x) ? 'int' : 'float' // @TODO FIX
58
+ if (is.arr(x)) return COMPONENT_COUNT_TO_TYPE[x.length as keyof typeof COMPONENT_COUNT_TO_TYPE] || 'float'
59
+ return 'float'
52
60
  }
53
61
 
54
- const inferMathType = (funcName: string, args: X[]): Constants => {
55
- const firstArgType = args.length > 0 ? infer(args[0]) : 'float'
56
- if (FIRST_ARG_TYPE_FUNCTIONS.includes(funcName as any)) return firstArgType as Constants
57
- if (SCALAR_RETURN_FUNCTIONS.includes(funcName as any)) return 'float'
58
- if (BOOL_RETURN_FUNCTIONS.includes(funcName as any)) return 'bool'
59
- if (PRESERVE_TYPE_FUNCTIONS.includes(funcName as any)) return firstArgType as Constants
60
- if (VEC3_RETURN_FUNCTIONS.includes(funcName as any)) return 'vec3'
61
- if (VEC4_RETURN_FUNCTIONS.includes(funcName as any)) return 'vec4'
62
- if (HIGHEST_TYPE_FUNCTIONS.includes(funcName as any)) return getHighestPriorityType(args) as Constants
63
- return firstArgType as Constants
62
+ const inferSwizzle = (count: number): Constants => {
63
+ return COMPONENT_COUNT_TO_TYPE[count as keyof typeof COMPONENT_COUNT_TO_TYPE]!
64
64
  }
65
65
 
66
- export const infer = (target: X, c?: NodeConfig): Constants => {
67
- if (!target) throw ``
68
- if (!isNodeProxy(target)) return inferPrimitiveType(target)
66
+ export const inferImpl = (target: NodeProxy, c: NodeConfig): Constants => {
69
67
  const { type, props } = target
70
- const { id, children = [], value, returnType } = props
68
+ const { id, children = [], inferFrom } = props
71
69
  const [x, y, z] = children
72
- if (
73
- type === 'uniform' ||
74
- type === 'variable' ||
75
- type === 'constant' ||
76
- type === 'attribute' ||
77
- type === 'varying'
78
- )
79
- return inferPrimitiveType(value)
80
- if (type === 'conversions') return x as Constants
81
- if (type === 'operator') return inferBinaryOpType(infer(y, c), infer(z, c), x as string)
82
- if (type === 'math_fun') return inferMathType(x as string, children.slice(1))
83
- if (type === 'swizzle') return inferSwizzleType((x as string).length)
84
- if (type === 'ternary') return inferBinaryOpType(infer(y, c), infer(z, c), 'add')
85
- if (type === 'fn_run') return returnType!
86
- if (type === 'fn_def') return returnType!
87
- if (type === 'builtin') return inferBuiltinType(id)
88
- return 'float'
70
+ if (inferFrom) return infer(inferFrom, c)
71
+ if (type === 'conversion') return x as Constants
72
+ if (type === 'operator') return inferOperator(infer(y, c), infer(z, c), x as string)
73
+ if (type === 'function') return inferFunction(x as string, children.slice(1), c)
74
+ if (type === 'swizzle') return inferSwizzle((x as string).length)
75
+ if (type === 'ternary') return inferOperator(infer(y, c), infer(z, c), 'add')
76
+ if (type === 'builtin') return inferBuiltin(id)
77
+ if (type === 'define') {
78
+ if (props.layout?.type && props.layout?.type !== 'auto') return props.layout.type as Constants
79
+ return y ? infer(y, c) : 'void'
80
+ }
81
+ return infer(x, c)
89
82
  }
90
83
 
91
- export const inferParameterTypes = (args: X[], c?: NodeConfig): Constants[] => {
92
- return args.map((arg) => infer(arg, c))
84
+ export const infer = (target: X, c?: NodeConfig | null): Constants => {
85
+ if (!c) c = {}
86
+ if (!isNodeProxy(target)) return inferPrimitiveType(target)
87
+ if (!c.infers) c.infers = new WeakMap<NodeProxy, Constants>()
88
+ if (c.infers.has(target)) return c.infers.get(target)!
89
+ const ret = inferImpl(target, c)
90
+ c.infers.set(target, ret)
91
+ return ret
93
92
  }