glre 0.27.0 → 0.28.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/const.ts CHANGED
@@ -1,26 +1,49 @@
1
1
  export const SWIZZLES = ['x', 'y', 'z', 'w', 'r', 'g', 'b', 'a', 's', 't', 'p', 'q'] as const
2
2
 
3
- export const NODE_TYPES = [
4
- 'float',
5
- 'int',
6
- 'uint',
3
+ export const CONSTANTS = [
7
4
  'bool',
8
- 'color',
9
- 'vec2',
10
- 'vec3',
11
- 'vec4',
12
- 'mat2',
13
- 'mat3',
14
- 'mat4',
5
+ 'uint',
6
+ 'int',
7
+ 'float',
8
+ 'bvec2',
9
+ 'bvec3',
10
+ 'bvec4',
15
11
  'ivec2',
16
12
  'ivec3',
17
13
  'ivec4',
18
14
  'uvec2',
19
15
  'uvec3',
20
16
  'uvec4',
21
- 'bvec2',
22
- 'bvec3',
23
- 'bvec4',
17
+ 'vec2',
18
+ 'vec3',
19
+ 'vec4',
20
+ 'color',
21
+ 'mat2',
22
+ 'mat3',
23
+ 'mat4',
24
+ ] as const
25
+
26
+ export const CONVERSIONS = [
27
+ 'toFloat',
28
+ 'toInt',
29
+ 'toUint',
30
+ 'toBool',
31
+ 'toVec2',
32
+ 'toVec3',
33
+ 'toVec4',
34
+ 'toIvec2',
35
+ 'toIvec3',
36
+ 'toIvec4',
37
+ 'toUvec2',
38
+ 'toUvec3',
39
+ 'toUvec4',
40
+ 'toBvec2',
41
+ 'toBvec3',
42
+ 'toBvec4',
43
+ 'toMat2',
44
+ 'toMat3',
45
+ 'toMat4',
46
+ 'toColor',
24
47
  ] as const
25
48
 
26
49
  export const OPERATORS = {
@@ -46,62 +69,74 @@ export const OPERATORS = {
46
69
 
47
70
  export const OPERATOR_KEYS = Object.keys(OPERATORS) as (keyof typeof OPERATORS)[]
48
71
 
49
- export const FUNCTIONS = [
72
+ // Function return type classification
73
+ export const SCALAR_RETURN_FUNCTIONS = ['dot', 'distance', 'length', 'lengthSq', 'determinant', 'luminance'] as const
74
+
75
+ export const BOOL_RETURN_FUNCTIONS = ['all', 'any'] as const
76
+
77
+ export const PRESERVE_TYPE_FUNCTIONS = [
50
78
  'abs',
51
- 'acos',
52
- 'asin',
53
- 'atan',
54
- 'atan2',
79
+ 'sign',
80
+ 'floor',
55
81
  'ceil',
56
- 'clamp',
82
+ 'round',
83
+ 'fract',
84
+ 'trunc',
85
+ 'sin',
57
86
  'cos',
58
- 'cross',
59
- 'degrees',
60
- 'distance',
61
- 'dot',
87
+ 'tan',
88
+ 'asin',
89
+ 'acos',
90
+ 'atan',
62
91
  'exp',
63
92
  'exp2',
93
+ 'log',
94
+ 'log2',
95
+ 'sqrt',
96
+ 'inverseSqrt',
97
+ 'normalize',
98
+ 'oneMinus',
99
+ 'saturate',
100
+ 'negate',
101
+ 'reciprocal',
102
+ 'dFdx',
103
+ 'dFdy',
104
+ 'fwidth',
105
+ ] as const
106
+
107
+ export const VEC3_RETURN_FUNCTIONS = ['cross'] as const
108
+
109
+ export const FIRST_ARG_TYPE_FUNCTIONS = ['reflect', 'refract'] as const
110
+
111
+ export const HIGHEST_TYPE_FUNCTIONS = ['min', 'max', 'mix', 'clamp', 'step', 'smoothstep'] as const
112
+
113
+ export const VEC4_RETURN_FUNCTIONS = ['texture', 'textureLod', 'textureSize', 'cubeTexture'] as const
114
+
115
+ export const ADDITIONAL_FUNCTIONS = [
116
+ 'atan2',
117
+ 'degrees',
64
118
  'faceforward',
65
- 'floor',
66
- 'fract',
67
- 'length',
68
- 'all',
69
- 'any',
70
119
  'bitcast',
71
120
  'cbrt',
72
- 'dFdx',
73
- 'dFdy',
74
121
  'difference',
75
122
  'equals',
76
- 'fwidth',
77
- 'inverseSqrt',
78
- 'lengthSq',
79
- 'log',
80
- 'log2',
81
- 'max',
82
- 'min',
83
- 'mix',
84
- 'negate',
85
- 'normalize',
86
- 'oneMinus',
87
123
  'pow',
88
124
  'pow2',
89
125
  'pow3',
90
126
  'pow4',
91
127
  'radians',
92
- 'reciprocal',
93
- 'reflect',
94
- 'refract',
95
- 'round',
96
- 'saturate',
97
- 'sign',
98
- 'sin',
99
- 'smoothstep',
100
- 'sqrt',
101
- 'step',
102
- 'tan',
103
128
  'transformDirection',
104
- 'trunc',
129
+ ] as const
130
+
131
+ export const FUNCTIONS = [
132
+ ...SCALAR_RETURN_FUNCTIONS,
133
+ ...BOOL_RETURN_FUNCTIONS,
134
+ ...PRESERVE_TYPE_FUNCTIONS,
135
+ ...VEC3_RETURN_FUNCTIONS,
136
+ ...FIRST_ARG_TYPE_FUNCTIONS,
137
+ ...HIGHEST_TYPE_FUNCTIONS,
138
+ ...VEC4_RETURN_FUNCTIONS,
139
+ ...ADDITIONAL_FUNCTIONS,
105
140
  ] as const
106
141
 
107
142
  export const TYPE_MAPPING = {
@@ -125,3 +160,31 @@ export const TYPE_MAPPING = {
125
160
  bvec3: 'vec3<bool>',
126
161
  bvec4: 'vec4<bool>',
127
162
  } as const
163
+
164
+ export const COMPONENT_COUNT_TO_TYPE = {
165
+ 1: 'float',
166
+ 2: 'vec2',
167
+ 3: 'vec3',
168
+ 4: 'vec4',
169
+ 9: 'mat3',
170
+ 16: 'mat4',
171
+ } as const
172
+
173
+ export const BUILTIN_TYPES = {
174
+ gl_FragCoord: 'vec4',
175
+ position: 'vec3',
176
+ normal: 'vec3',
177
+ uv: 'vec2',
178
+ color: 'vec4',
179
+ } as const
180
+
181
+ export const COMPARISON_OPERATORS = [
182
+ 'equal',
183
+ 'notEqual',
184
+ 'lessThan',
185
+ 'lessThanEqual',
186
+ 'greaterThan',
187
+ 'greaterThanEqual',
188
+ ] as const
189
+
190
+ export const LOGICAL_OPERATORS = ['and', 'or'] as const
package/src/node/index.ts CHANGED
@@ -1,7 +1,10 @@
1
1
  import { f, n, node, u } from './node'
2
+ import { hex2rgb } from './utils'
3
+ import { is } from '../utils/helpers'
2
4
  import type { X } from './types'
3
5
  export * from './code'
4
6
  export * from './const'
7
+ export * from './infer'
5
8
  export * from './node'
6
9
  export * from './scope'
7
10
  export * from './types'
@@ -11,7 +14,23 @@ export * from './utils'
11
14
  export const iResolution = u('iResolution', [1280, 800])
12
15
  export const iMouse = u('iMouse', [0, 0])
13
16
  export const iTime = u('iTime', 0)
14
- export const fragCoord = node('variable', { id: 'fragCoord' })
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)
24
+
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' })
15
34
 
16
35
  // Type constructors
17
36
  export const float = (x: X) => n('float', x)
@@ -33,59 +52,69 @@ export const uvec4 = (x?: X, y?: X, z?: X, w?: X) => n('uvec4', x, y, z, w)
33
52
  export const bvec2 = (x?: X, y?: X) => n('bvec2', x, y)
34
53
  export const bvec3 = (x?: X, y?: X, z?: X) => n('bvec3', x, y, z)
35
54
  export const bvec4 = (x?: X, y?: X, z?: X, w?: X) => n('bvec4', x, y, z, w)
55
+ export const color = (r?: X, g?: X, b?: X) => {
56
+ if (is.num(r) && is.und(g) && is.und(b)) return vec3(...hex2rgb(r))
57
+ return vec3(r, g, b)
58
+ }
59
+
60
+ // Texture Functions
61
+ export const texture = (x: X, y: X, z?: X) => f('texture', x, y, z)
62
+ export const cubeTexture = (x: X, y: X, z?: X) => f('cubeTexture', x, y, z)
63
+ export const textureSize = (x: X, y?: X) => f('textureSize', x, y)
36
64
 
37
65
  // Math Functions
38
- export const abs = (x: X) => f('abs', x) // Return the absolute value of the parameter.
39
- export const acos = (x: X) => f('acos', x) // Return the arccosine of the parameter.
40
- export const all = (x: X) => f('all', x) // Return true if all components of x are true.
41
- export const any = (x: X) => f('any', x) // Return true if any component of x is true.
42
- export const asin = (x: X) => f('asin', x) // Return the arcsine of the parameter.
43
- export const atan = (y: X, x: X) => f('atan', y, x) // Return the arc-tangent of the parameters.
44
- export const bitcast = (x: X, y: X) => f('bitcast', x, y) // Reinterpret the bits of a value as a different type.
45
- export const cbrt = (x: X) => f('cbrt', x) // Return the cube root of the parameter.
46
- export const ceil = (x: X) => f('ceil', x) // Find the nearest integer that is greater than or equal to the parameter.
47
- export const clamp = (x: X, min: X, max: X) => f('clamp', x, min, max) // Constrain a value to lie between two further values.
48
- export const cos = (x: X) => f('cos', x) // Return the cosine of the parameter.
49
- export const cross = (x: X, y: X) => f('cross', x, y) // Calculate the cross product of two vectors.
50
- export const dFdx = (p: X) => f('dFdx', p) // Return the partial derivative of an argument with respect to x.
51
- export const dFdy = (p: X) => f('dFdy', p) // Return the partial derivative of an argument with respect to y.
52
- export const degrees = (radians: X) => f('degrees', radians) // Convert a quantity in radians to degrees.
53
- export const difference = (x: X, y: X) => f('difference', x, y) // Calculate the absolute difference between two values.
54
- export const distance = (x: X, y: X) => f('distance', x, y) // Calculate the distance between two points.
55
- export const dot = (x: X, y: X) => f('dot', x, y) // Calculate the dot product of two vectors.
56
- export const equals = (x: X, y: X) => f('equals', x, y) // Return true if x equals y.
57
- export const exp = (x: X) => f('exp', x) // Return the natural exponentiation of the parameter.
58
- export const exp2 = (x: X) => f('exp2', x) // Return 2 raised to the power of the parameter.
59
- export const faceforward = (N: X, I: X, Nref: X) => f('faceforward', N, I, Nref) // Return a vector pointing in the same direction as another.
60
- export const floor = (x: X) => f('floor', x) // Find the nearest integer less than or equal to the parameter.
61
- export const fract = (x: X) => f('fract', x) // Compute the fractional part of the argument.
62
- export const fwidth = (x: X) => f('fwidth', x) // Return the sum of the absolute derivatives in x and y.
63
- export const inverseSqrt = (x: X) => f('inverseSqrt', x) // Return the inverse of the square root of the parameter.
64
- export const length = (x: X) => f('length', x) // Calculate the length of a vector.
65
- export const lengthSq = (x: X) => f('lengthSq', x) // Calculate the squared length of a vector.
66
- export const log = (x: X) => f('log', x) // Return the natural logarithm of the parameter.
67
- export const log2 = (x: X) => f('log2', x) // Return the base 2 logarithm of the parameter.
68
- export const max = (x: X, y: X) => f('max', x, y) // Return the greater of two values.
69
- export const min = (x: X, y: X) => f('min', x, y) // Return the lesser of two values.
70
- export const mix = (x: X, y: X, a: X) => f('mix', x, y, a) // Linearly interpolate between two values.
71
- export const negate = (x: X) => f('negate', x) // Negate the value of the parameter ( -x ).
72
- export const normalize = (x: X) => f('normalize', x) // Calculate the unit vector in the same direction as the original vector.
73
- export const oneMinus = (x: X) => f('oneMinus', x) // Return 1 minus the parameter.
74
- export const pow = (x: X, y: X) => f('pow', x, y) // Return the value of the first parameter raised to the power of the second.
75
- export const pow2 = (x: X) => f('pow2', x) // Return the square of the parameter.
76
- export const pow3 = (x: X) => f('pow3', x) // Return the cube of the parameter.
77
- export const pow4 = (x: X) => f('pow4', x) // Return the fourth power of the parameter.
78
- export const radians = (degrees: X) => f('radians', degrees) // Convert a quantity in degrees to radians.
79
- export const reciprocal = (x: X) => f('reciprocal', x) // Return the reciprocal of the parameter (1/x).
80
- export const reflect = (I: X, N: X) => f('reflect', I, N) // Calculate the reflection direction for an incident vector.
81
- export const refract = (I: X, N: X, eta: X) => f('refract', I, N, eta) // Calculate the refraction direction for an incident vector.
82
- export const round = (x: X) => f('round', x) // Round the parameter to the nearest integer.
83
- export const saturate = (x: X) => f('saturate', x) // Constrain a value between 0 and 1.
84
- export const sign = (x: X) => f('sign', x) // Extract the sign of the parameter.
85
- export const sin = (x: X) => f('sin', x) // Return the sine of the parameter.
86
- export const smoothstep = (e0: X, e1: X, x: X) => f('smoothstep', e0, e1, x) // Perform Hermite interpolation between two values.
87
- export const sqrt = (x: X) => f('sqrt', x) // Return the square root of the parameter.
88
- export const step = (edge: X, x: X) => f('step', edge, x) // Generate a step function by comparing two values.
89
- export const tan = (x: X) => f('tan', x) // Return the tangent of the parameter.
90
- export const transformDirection = (dir: X, matrix: X) => f('transformDirection', dir, matrix) // Transform the direction of a vector by a matrix and then normalize the result.
91
- export const trunc = (x: X) => f('trunc', x) // Truncate the parameter, removing the fractional part.
66
+ export const abs = (x: X) => f('abs', x)
67
+ export const acos = (x: X) => f('acos', x)
68
+ export const all = (x: X) => f('all', x)
69
+ export const any = (x: X) => f('any', x)
70
+ export const asin = (x: X) => f('asin', x)
71
+ export const atan = (y: X, x?: X) => (x !== undefined ? f('atan', y, x) : f('atan', y))
72
+ export const atan2 = (y: X, x: X) => f('atan', y, x)
73
+ export const bitcast = (x: X, y: X) => f('bitcast', x, y)
74
+ export const cbrt = (x: X) => f('cbrt', x)
75
+ export const ceil = (x: X) => f('ceil', x)
76
+ export const clamp = (x: X, min: X, max: X) => f('clamp', x, min, max)
77
+ export const cos = (x: X) => f('cos', x)
78
+ export const cross = (x: X, y: X) => f('cross', x, y)
79
+ export const dFdx = (p: X) => f('dFdx', p)
80
+ export const dFdy = (p: X) => f('dFdy', p)
81
+ export const degrees = (radians: X) => f('degrees', radians)
82
+ export const difference = (x: X, y: X) => f('difference', x, y)
83
+ export const distance = (x: X, y: X) => f('distance', x, y)
84
+ export const dot = (x: X, y: X) => f('dot', x, y)
85
+ export const equals = (x: X, y: X) => f('equals', x, y)
86
+ export const exp = (x: X) => f('exp', x)
87
+ export const exp2 = (x: X) => f('exp2', x)
88
+ export const faceforward = (N: X, I: X, Nref: X) => f('faceforward', N, I, Nref)
89
+ export const floor = (x: X) => f('floor', x)
90
+ export const fract = (x: X) => f('fract', x)
91
+ export const fwidth = (x: X) => f('fwidth', x)
92
+ export const inverseSqrt = (x: X) => f('inverseSqrt', x)
93
+ export const length = (x: X) => f('length', x)
94
+ export const lengthSq = (x: X) => f('lengthSq', x)
95
+ export const log = (x: X) => f('log', x)
96
+ export const log2 = (x: X) => f('log2', x)
97
+ export const max = (x: X, y: X) => f('max', x, y)
98
+ export const min = (x: X, y: X) => f('min', x, y)
99
+ export const mix = (x: X, y: X, a: X) => f('mix', x, y, a)
100
+ export const negate = (x: X) => f('negate', x)
101
+ export const normalize = (x: X) => f('normalize', x)
102
+ export const oneMinus = (x: X) => f('oneMinus', x)
103
+ export const pow = (x: X, y: X) => f('pow', x, y)
104
+ export const pow2 = (x: X) => f('pow2', x)
105
+ export const pow3 = (x: X) => f('pow3', x)
106
+ export const pow4 = (x: X) => f('pow4', x)
107
+ export const radians = (degrees: X) => f('radians', degrees)
108
+ export const reciprocal = (x: X) => f('reciprocal', x)
109
+ export const reflect = (I: X, N: X) => f('reflect', I, N)
110
+ export const refract = (I: X, N: X, eta: X) => f('refract', I, N, eta)
111
+ export const round = (x: X) => f('round', x)
112
+ export const saturate = (x: X) => f('saturate', x)
113
+ export const sign = (x: X) => f('sign', x)
114
+ export const sin = (x: X) => f('sin', x)
115
+ export const smoothstep = (e0: X, e1: X, x: X) => f('smoothstep', e0, e1, x)
116
+ export const sqrt = (x: X) => f('sqrt', x)
117
+ export const step = (edge: X, x: X) => f('step', edge, x)
118
+ export const tan = (x: X) => f('tan', x)
119
+ export const transformDirection = (dir: X, matrix: X) => f('transformDirection', dir, matrix)
120
+ export const trunc = (x: X) => f('trunc', x)
@@ -0,0 +1,93 @@
1
+ import { is } from '../utils/helpers'
2
+ import { isNodeProxy } from './utils'
3
+ import {
4
+ CONSTANTS,
5
+ SCALAR_RETURN_FUNCTIONS,
6
+ BOOL_RETURN_FUNCTIONS,
7
+ PRESERVE_TYPE_FUNCTIONS,
8
+ VEC3_RETURN_FUNCTIONS,
9
+ FIRST_ARG_TYPE_FUNCTIONS,
10
+ HIGHEST_TYPE_FUNCTIONS,
11
+ VEC4_RETURN_FUNCTIONS,
12
+ COMPARISON_OPERATORS,
13
+ LOGICAL_OPERATORS,
14
+ COMPONENT_COUNT_TO_TYPE,
15
+ BUILTIN_TYPES,
16
+ } from './const'
17
+ import type { Constants, NodeConfig, X } from './types'
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'
24
+ }
25
+
26
+ const inferBinaryOpType = (leftType: string, rightType: string, op: string): Constants => {
27
+ if (COMPARISON_OPERATORS.includes(op as any)) return 'bool'
28
+ if (LOGICAL_OPERATORS.includes(op as any)) return 'bool'
29
+ if (leftType === rightType) return leftType as Constants
30
+ if (leftType.includes('vec') && !rightType.includes('vec')) return leftType as Constants
31
+ if (rightType.includes('vec') && !leftType.includes('vec')) return rightType as Constants
32
+ const leftPriority = CONSTANTS.indexOf(leftType as any)
33
+ const rightPriority = CONSTANTS.indexOf(rightType as any)
34
+ return (leftPriority >= rightPriority ? leftType : rightType) as Constants
35
+ }
36
+
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]!
52
+ }
53
+
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
64
+ }
65
+
66
+ export const infer = (target: X, c?: NodeConfig): Constants => {
67
+ if (!target) throw ``
68
+ if (!isNodeProxy(target)) return inferPrimitiveType(target)
69
+ const { type, props } = target
70
+ const { id, children = [], value, returnType } = props
71
+ 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'
89
+ }
90
+
91
+ export const inferParameterTypes = (args: X[], c?: NodeConfig): Constants[] => {
92
+ return args.map((arg) => infer(arg, c))
93
+ }
package/src/node/node.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { code } from './code'
2
- import { assign, toVar } from './scope'
3
- import { getId, isFunction, isOperator, isSwizzle } from './utils'
2
+ import { assign, toVar, toConst } from './scope'
3
+ import { getId, isConversion, isFunction, isOperator, isSwizzle } from './utils'
4
4
  import type { Functions, NodeProps, NodeProxy, NodeTypes, Operators, Swizzles, X } from './types'
5
5
 
6
6
  const toPrimitive = (x: X) => {
@@ -17,6 +17,7 @@ export const node = (type: NodeTypes, props?: NodeProps | null, ...args: X[]) =>
17
17
  if (key === 'type') return type
18
18
  if (key === 'props') return props
19
19
  if (key === 'toVar') return toVar(x)
20
+ if (key === 'toConst') return toConst(x)
20
21
  if (key === 'assign') return assign(x)
21
22
  if (key === 'isProxy') return true
22
23
  if (key === 'toString') return code.bind(null, x)
@@ -24,7 +25,7 @@ export const node = (type: NodeTypes, props?: NodeProps | null, ...args: X[]) =>
24
25
  if (isSwizzle(key)) return s(key, x)
25
26
  if (isOperator(key)) return (...y: X[]) => o(key, x, ...y)
26
27
  if (isFunction(key)) return (...y: X[]) => f(key, x, ...y)
27
- return toVar(x)('')
28
+ if (isConversion(key)) return n(key, x)
28
29
  },
29
30
  set(_, key, value) {
30
31
  if (isSwizzle(key)) {
@@ -39,8 +40,12 @@ export const node = (type: NodeTypes, props?: NodeProps | null, ...args: X[]) =>
39
40
 
40
41
  // Node shorthands
41
42
  export const v = (...args: X[]) => node('variable', { id: getId() }, ...args)
42
- export const u = (key: string, defaultValue?: number | number[]) => node('uniform', { defaultValue }, key)
43
43
  export const s = (key: Swizzles, arg: X) => node('swizzle', null, key, arg)
44
- export const n = (key: string, ...args: X[]) => node('node_type', null, key, ...args)
44
+ export const n = (key: string, ...args: X[]) => node('conversions', null, key, ...args)
45
45
  export const o = (key: Operators, ...args: X[]) => node('operator', null, key, ...args)
46
46
  export const f = (key: Functions, ...args: X[]) => node('math_fun', null, key, ...args)
47
+
48
+ // uniform and attribute
49
+ export const u = (id: string, value?: number | number[] | boolean) => node('uniform', { id, value })
50
+
51
+ export const select = (x: X, y: X, z: X) => node('ternary', null, x, y, z)
package/src/node/scope.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { infer } from './infer'
1
2
  import { node } from './node'
2
3
  import { getId } from './utils'
3
4
  import type { NodeProxy, X } from './types'
@@ -17,23 +18,25 @@ const addToScope = (x: NodeProxy) => {
17
18
  _scope.props.children.push(x)
18
19
  }
19
20
 
20
- export const If = (x: X, callback: () => void) => {
21
- const y = node('scope')
22
- scoped(y, callback)
23
- const ifNode = node('if', null, x, y)
21
+ export const If = (condition: X, callback: () => void) => {
22
+ const scope = node('scope')
23
+ scoped(scope, callback)
24
+ const ifNode = node('if', null, condition, scope)
24
25
  addToScope(ifNode)
25
- return {
26
- ElseIf: (y: X, elseCallback: () => void) => {
27
- const z = node('scope')
28
- scoped(z, elseCallback)
29
- ifNode.props.children!.push(y, z)
26
+ const createChain = () => ({
27
+ ElseIf: (newCondition: X, elseIfCallback: () => void) => {
28
+ const elseIfScope = node('scope')
29
+ scoped(elseIfScope, elseIfCallback)
30
+ ifNode.props.children!.push(newCondition, elseIfScope)
31
+ return createChain()
30
32
  },
31
33
  Else: (elseCallback: () => void) => {
32
- const z = node('scope')
33
- scoped(z, elseCallback)
34
- ifNode.props.children!.push(z)
34
+ const elseScope = node('scope')
35
+ scoped(elseScope, elseCallback)
36
+ ifNode.props.children!.push(elseScope)
35
37
  },
36
- }
38
+ })
39
+ return createChain()
37
40
  }
38
41
 
39
42
  export const Loop = (x: X, callback?: (params: { i: NodeProxy }) => void) => {
@@ -44,16 +47,50 @@ export const Loop = (x: X, callback?: (params: { i: NodeProxy }) => void) => {
44
47
  return ret
45
48
  }
46
49
 
47
- export const Fn = (callback: (args: X[]) => NodeProxy) => {
48
- return (...args: X[]) => {
49
- let result
50
- const fnScope = node('scope')
51
- scoped(fnScope, () => (result = callback(args)))
52
- return node('fn', null, fnScope, result)
50
+ export const Switch = (value: X) => {
51
+ const switchNode = node('switch', null, value)
52
+ addToScope(switchNode)
53
+ const createChain = () => ({
54
+ Case: (...values: X[]) => {
55
+ return (callback: () => void) => {
56
+ const caseScope = node('scope')
57
+ scoped(caseScope, callback)
58
+ const caseNode = node('case', null, ...values, caseScope)
59
+ switchNode.props.children!.push(caseNode)
60
+ return createChain()
61
+ }
62
+ },
63
+ Default: (callback: () => void) => {
64
+ const defaultScope = node('scope')
65
+ scoped(defaultScope, callback)
66
+ const defaultNode = node('default', null, defaultScope)
67
+ switchNode.props.children!.push(defaultNode)
68
+ },
69
+ })
70
+
71
+ return createChain()
72
+ }
73
+
74
+ export const Fn = (callback: (args: NodeProxy[]) => NodeProxy) => {
75
+ const id = getId()
76
+ return (...args: NodeProxy[]) => {
77
+ const x = node('scope')
78
+ let y: NodeProxy | undefined
79
+ const paramVars: NodeProxy[] = []
80
+ for (let i = 0; i < args.length; i++) {
81
+ const paramId = `p${i}`
82
+ const paramVar = node('variable', { id: paramId })
83
+ paramVars.push(paramVar)
84
+ }
85
+ scoped(x, () => (y = callback(paramVars)))
86
+ const returnType = y ? infer(y) : 'void'
87
+ const paramInfo = args.map((arg, i) => ({ name: `p${i}`, type: infer(arg) }))
88
+ const def = node('fn_def', { id, returnType, paramInfo, args }, x, y)
89
+ return node('fn_run', { id, returnType }, def, ...paramVars)
53
90
  }
54
91
  }
55
92
 
56
- export const toVar = (x: X) => (id: string) => {
93
+ export const toVar = (x: X) => (id?: string) => {
57
94
  if (!id) id = getId()
58
95
  const y = node('variable', { id })
59
96
  const z = node('declare', null, y, x)
@@ -61,8 +98,24 @@ export const toVar = (x: X) => (id: string) => {
61
98
  return y
62
99
  }
63
100
 
101
+ export const toConst = (x: X) => (id?: string) => {
102
+ if (!id) id = getId()
103
+ const y = node('constant', { id })
104
+ const z = node('declare', null, y, x)
105
+ addToScope(z)
106
+ return y
107
+ }
108
+
64
109
  export const assign = (x: X) => (y: X) => {
65
110
  const assignNode = node('assign', null, x, y)
66
111
  addToScope(assignNode)
67
112
  return x
68
113
  }
114
+
115
+ export const varying = (value: X, name?: string) => {
116
+ if (!name) name = getId()
117
+ const varyingVar = node('varying', { id: name })
118
+ const declaration = node('declare', null, varyingVar, value)
119
+ addToScope(declaration)
120
+ return varyingVar
121
+ }