glre 0.31.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 +34 -64
- package/dist/index.cjs.map +1 -1
- package/dist/{index.d.cts → index.d.ts} +184 -191
- package/dist/index.js +34 -64
- package/dist/index.js.map +1 -1
- package/dist/native.cjs +34 -64
- package/dist/native.cjs.map +1 -1
- package/dist/native.d.ts +54 -0
- package/dist/native.js +34 -64
- package/dist/native.js.map +1 -1
- package/dist/react.cjs +34 -64
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.ts +8 -0
- package/dist/react.js +34 -64
- package/dist/react.js.map +1 -1
- package/dist/solid.cjs +34 -64
- package/dist/solid.cjs.map +1 -1
- package/dist/solid.d.ts +8 -0
- package/dist/solid.js +34 -64
- package/dist/solid.js.map +1 -1
- package/package.json +7 -6
- package/src/index.ts +19 -5
- package/src/node/code.ts +79 -77
- package/src/node/const.ts +27 -44
- package/src/node/index.ts +98 -12
- package/src/node/infer.ts +32 -15
- package/src/node/node.ts +20 -21
- package/src/node/parse.ts +160 -0
- package/src/node/scope.ts +48 -23
- package/src/node/types.ts +100 -57
- package/src/node/utils.ts +63 -94
- package/src/types.ts +32 -16
- package/src/utils/pipeline.ts +136 -95
- package/src/utils/program.ts +7 -36
- package/src/webgl.ts +7 -3
- package/src/webgpu.ts +82 -58
- package/dist/native.d.cts +0 -53
- package/dist/react.d.cts +0 -8
- package/dist/solid.d.cts +0 -8
package/src/index.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { webgpu } from './webgpu'
|
|
|
5
5
|
import { is } from './utils/helpers'
|
|
6
6
|
import type { EventState } from 'reev'
|
|
7
7
|
import type { GL } from './types'
|
|
8
|
+
import { float, fract, int, iResolution, position, vec4, vertexIndex } from './node'
|
|
8
9
|
export * from './node'
|
|
9
10
|
export * from './types'
|
|
10
11
|
export * from './utils/helpers'
|
|
@@ -30,6 +31,19 @@ export const isWebGPUSupported = () => {
|
|
|
30
31
|
|
|
31
32
|
let iTime = performance.now()
|
|
32
33
|
|
|
34
|
+
const defaultFragment = () => vec4(fract(position.xy.div(iResolution)), 0, 1)
|
|
35
|
+
const defaultVertex = () =>
|
|
36
|
+
vec4(
|
|
37
|
+
float(int(vertexIndex).mod(int(2)))
|
|
38
|
+
.mul(4)
|
|
39
|
+
.sub(1),
|
|
40
|
+
float(int(vertexIndex).div(int(2)))
|
|
41
|
+
.mul(4)
|
|
42
|
+
.sub(1),
|
|
43
|
+
0,
|
|
44
|
+
1
|
|
45
|
+
)
|
|
46
|
+
|
|
33
47
|
export const createGL = (props?: Partial<GL>) => {
|
|
34
48
|
const gl = event<Partial<GL>>({
|
|
35
49
|
isNative: false,
|
|
@@ -46,14 +60,14 @@ export const createGL = (props?: Partial<GL>) => {
|
|
|
46
60
|
gl.queue = createQueue()
|
|
47
61
|
gl.frame = createFrame()
|
|
48
62
|
|
|
49
|
-
gl.attribute = durable((k, v, i) => gl.queue(() => gl._attribute?.(k, v, i)))
|
|
50
|
-
gl.
|
|
51
|
-
gl.
|
|
63
|
+
gl.attribute = durable((k, v, i) => gl.queue(() => gl._attribute?.(k, v, i)), gl)
|
|
64
|
+
gl.uniform = durable((k, v, i) => gl.queue(() => gl._uniform?.(k, v, i)), gl)
|
|
65
|
+
gl.texture = durable((k, v) => gl.queue(() => gl._texture?.(k, v)), gl)
|
|
52
66
|
gl.uniform({ iResolution: gl.size, iMouse: [0, 0], iTime })
|
|
53
67
|
|
|
54
68
|
gl('mount', async () => {
|
|
55
|
-
gl.vs = gl.vs || gl.vert || gl.vertex
|
|
56
|
-
gl.fs = gl.fs || gl.frag || gl.fragment
|
|
69
|
+
gl.vs = gl.vs || gl.vert || gl.vertex || defaultVertex()
|
|
70
|
+
gl.fs = gl.fs || gl.frag || gl.fragment || defaultFragment()
|
|
57
71
|
if (!isWebGPUSupported()) gl.isWebGL = true
|
|
58
72
|
if (gl.isWebGL) {
|
|
59
73
|
gl((await webgl(gl)) as GL)
|
package/src/node/code.ts
CHANGED
|
@@ -1,11 +1,26 @@
|
|
|
1
1
|
import { is } from '../utils/helpers'
|
|
2
2
|
import { infer } from './infer'
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import {
|
|
4
|
+
parseArray,
|
|
5
|
+
parseAttribHead,
|
|
6
|
+
parseConstantHead,
|
|
7
|
+
parseDeclare,
|
|
8
|
+
parseDefine,
|
|
9
|
+
parseIf,
|
|
10
|
+
parseStruct,
|
|
11
|
+
parseStructHead,
|
|
12
|
+
parseSwitch,
|
|
13
|
+
parseTexture,
|
|
14
|
+
parseVaryingHead,
|
|
15
|
+
parseUniformHead,
|
|
16
|
+
} from './parse'
|
|
17
|
+
import { getBluiltin, getOperator, formatConversions, safeEventCall, getEventFun, initNodeContext } from './utils'
|
|
18
|
+
import type { NodeContext, NodeProxy, X } from './types'
|
|
5
19
|
|
|
6
|
-
export const code = (target: X, c?:
|
|
20
|
+
export const code = (target: X, c?: NodeContext | null): string => {
|
|
7
21
|
if (!c) c = {}
|
|
8
|
-
|
|
22
|
+
initNodeContext(c)
|
|
23
|
+
if (is.arr(target)) return parseArray(target, c)
|
|
9
24
|
if (is.str(target)) return target
|
|
10
25
|
if (is.num(target)) {
|
|
11
26
|
const ret = `${target}`
|
|
@@ -13,103 +28,90 @@ export const code = (target: X, c?: NodeConfig | null): string => {
|
|
|
13
28
|
return ret + '.0'
|
|
14
29
|
}
|
|
15
30
|
if (is.bol(target)) return target ? 'true' : 'false'
|
|
16
|
-
if (!target) return ''
|
|
31
|
+
if (!target) return ''
|
|
17
32
|
const { type, props } = target
|
|
18
|
-
const { id = '', children = [] } = props
|
|
19
|
-
const [x, y, z] = children
|
|
20
|
-
/**
|
|
21
|
-
* headers
|
|
22
|
-
*/
|
|
23
|
-
let head = ''
|
|
24
|
-
if (type === 'attribute') {
|
|
25
|
-
if (c.headers.has(id)) return id
|
|
26
|
-
head = `${infer(target, c)} ${id}`
|
|
27
|
-
}
|
|
28
|
-
if (type === 'uniform') {
|
|
29
|
-
if (c.headers.has(id)) return id
|
|
30
|
-
if (!c.binding) c.binding = 0
|
|
31
|
-
const varType = infer(target, c)
|
|
32
|
-
head = c.isWebGL
|
|
33
|
-
? `uniform ${varType} ${id};`
|
|
34
|
-
: `@group(0) @binding(${c.binding++}) var<uniform> ${id}: ${formatConversions(varType, c)};`
|
|
35
|
-
}
|
|
36
|
-
if (type === 'constant') {
|
|
37
|
-
if (c.headers.has(id)) return id
|
|
38
|
-
const varType = infer(target, c)
|
|
39
|
-
const value = code(x, c)
|
|
40
|
-
head = c.isWebGL
|
|
41
|
-
? `const ${varType} ${id} = ${value};`
|
|
42
|
-
: `const ${id}: ${formatConversions(varType, c)} = ${value};`
|
|
43
|
-
}
|
|
44
|
-
if (type === 'varying') {
|
|
45
|
-
if (c.headers.has(id)) return id
|
|
46
|
-
head = `${infer(target, c)} ${id}`
|
|
47
|
-
}
|
|
48
|
-
if (head) {
|
|
49
|
-
c.headers.set(id, head)
|
|
50
|
-
c.onMount?.(id)
|
|
51
|
-
return id
|
|
52
|
-
}
|
|
33
|
+
const { id = '', children = [], fields, initialValues } = props
|
|
34
|
+
const [x, y, z, w] = children
|
|
53
35
|
/**
|
|
54
36
|
* variables
|
|
55
37
|
*/
|
|
56
38
|
if (type === 'variable') return id
|
|
57
|
-
if (type === '
|
|
58
|
-
if (type === 'ternary')
|
|
59
|
-
|
|
60
|
-
|
|
39
|
+
if (type === 'member') return `${code(y, c)}.${code(x, c)}`
|
|
40
|
+
if (type === 'ternary')
|
|
41
|
+
return c.isWebGL
|
|
42
|
+
? `(${code(x, c)} ? ${code(y, c)} : ${code(z, 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)})`
|
|
61
45
|
if (type === 'operator') {
|
|
62
46
|
if (x === 'not' || x === 'bitNot') return `!${code(y, c)}`
|
|
63
47
|
return `(${code(y, c)} ${getOperator(x)} ${code(z, c)})`
|
|
64
48
|
}
|
|
65
49
|
if (type === 'function') {
|
|
66
|
-
if (x === 'negate') return `(-${
|
|
67
|
-
return
|
|
50
|
+
if (x === 'negate') return `(-${parseArray(children.slice(1), c)})`
|
|
51
|
+
if (x === 'texture') return parseTexture(c, y, z, w)
|
|
52
|
+
return `${x}(${parseArray(children.slice(1), c)})`
|
|
68
53
|
}
|
|
69
54
|
/**
|
|
70
55
|
* scopes
|
|
71
56
|
*/
|
|
72
57
|
if (type === 'scope') return children.map((child: any) => code(child, c)).join('\n')
|
|
73
58
|
if (type === 'assign') return `${code(x, c)} = ${code(y, c)};`
|
|
59
|
+
if (type === 'return') return `return ${code(x, c)};`
|
|
74
60
|
if (type === 'loop')
|
|
75
61
|
return c.isWebGL
|
|
76
62
|
? `for (int i = 0; i < ${x}; i += 1) {\n${code(y, c)}\n}`
|
|
77
63
|
: `for (var i: i32 = 0; i < ${x}; i++) {\n${code(y, c)}\n}`
|
|
64
|
+
if (type === 'if') return parseIf(c, x, y, children)
|
|
65
|
+
if (type === 'switch') return parseSwitch(c, x, children)
|
|
66
|
+
if (type === 'declare') return parseDeclare(c, x, y)
|
|
78
67
|
if (type === 'define') {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
if (c.headers.has(id)) return ret
|
|
82
|
-
c.headers.set(id, generateDefine(props, c))
|
|
83
|
-
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)})`
|
|
84
70
|
}
|
|
85
|
-
if (type === '
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
return
|
|
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)
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* headers
|
|
77
|
+
*/
|
|
78
|
+
if (type === 'varying') {
|
|
79
|
+
if (c.code?.vertOutputs.has(id)) return c.isWebGL ? `${id}` : `out.${id}`
|
|
80
|
+
const field = parseVaryingHead(c, id, infer(target, c))
|
|
81
|
+
c.code?.fragInputs.set(id, field)
|
|
82
|
+
c.code?.vertOutputs.set(id, field)
|
|
83
|
+
c.code?.vertVaryings.set(id, code(x, c))
|
|
84
|
+
return c.isWebGL ? `${id}` : `out.${id}`
|
|
94
85
|
}
|
|
95
|
-
if (type === '
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
ret += '}'
|
|
105
|
-
return ret
|
|
86
|
+
if (type === 'builtin') {
|
|
87
|
+
if (c.isWebGL) return getBluiltin(id)
|
|
88
|
+
if (id === 'position') return 'out.position'
|
|
89
|
+
const field = `@builtin(${id}) ${id}: ${formatConversions(infer(target, c), c)}`
|
|
90
|
+
if (c.isFrag) {
|
|
91
|
+
c.code?.fragInputs.set(id, field)
|
|
92
|
+
} else c.code?.vertInputs.set(id, field)
|
|
93
|
+
return `in.${id}`
|
|
106
94
|
}
|
|
107
|
-
if (type === '
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
return
|
|
95
|
+
if (type === 'attribute') {
|
|
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)))
|
|
100
|
+
return c.isWebGL ? `${id}` : `in.${id}`
|
|
101
|
+
}
|
|
102
|
+
if (c.code?.headers.has(id)) return id // must last
|
|
103
|
+
let head = ''
|
|
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
|
+
}
|
|
111
|
+
if (type === 'constant') head = parseConstantHead(c, id, infer(target, c), code(x, c))
|
|
112
|
+
if (head) {
|
|
113
|
+
c.code?.headers.set(id, head)
|
|
114
|
+
return id
|
|
113
115
|
}
|
|
114
116
|
return code(x, c)
|
|
115
117
|
}
|
package/src/node/const.ts
CHANGED
|
@@ -1,27 +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
|
-
|
|
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
|
|
25
30
|
|
|
26
31
|
export const CONVERSIONS = [
|
|
27
32
|
'toBool',
|
|
@@ -138,28 +143,6 @@ export const FUNCTIONS = [
|
|
|
138
143
|
...ADDITIONAL_FUNCTIONS,
|
|
139
144
|
] as const
|
|
140
145
|
|
|
141
|
-
export const TYPE_MAPPING = {
|
|
142
|
-
float: 'f32',
|
|
143
|
-
int: 'i32',
|
|
144
|
-
uint: 'u32',
|
|
145
|
-
bool: 'bool',
|
|
146
|
-
vec2: 'vec2f',
|
|
147
|
-
vec3: 'vec3f',
|
|
148
|
-
vec4: 'vec4f',
|
|
149
|
-
mat2: 'mat2x2f',
|
|
150
|
-
mat3: 'mat3x3f',
|
|
151
|
-
mat4: 'mat4x4f',
|
|
152
|
-
ivec2: 'vec2i',
|
|
153
|
-
ivec3: 'vec3i',
|
|
154
|
-
ivec4: 'vec4i',
|
|
155
|
-
uvec2: 'vec2u',
|
|
156
|
-
uvec3: 'vec3u',
|
|
157
|
-
uvec4: 'vec4u',
|
|
158
|
-
bvec2: 'vec2<bool>',
|
|
159
|
-
bvec3: 'vec3<bool>',
|
|
160
|
-
bvec4: 'vec4<bool>',
|
|
161
|
-
} as const
|
|
162
|
-
|
|
163
146
|
export const COMPONENT_COUNT_TO_TYPE = {
|
|
164
147
|
1: 'float',
|
|
165
148
|
2: 'vec2',
|
package/src/node/index.ts
CHANGED
|
@@ -1,15 +1,88 @@
|
|
|
1
|
-
import { builtin, conversion as c, function_ as f, uniform } from './node'
|
|
2
|
-
import { hex2rgb } from './utils'
|
|
3
1
|
import { is } from '../utils/helpers'
|
|
4
|
-
import
|
|
2
|
+
import { code } from './code'
|
|
3
|
+
import { builtin, conversion as c, function_ as f, uniform as u } from './node'
|
|
4
|
+
import { hex2rgb, sortHeadersByDependencies } from './utils'
|
|
5
|
+
import type { NodeContext, X } from './types'
|
|
5
6
|
export * from './code'
|
|
6
|
-
export * from './const'
|
|
7
|
-
export * from './infer'
|
|
8
7
|
export * from './node'
|
|
9
8
|
export * from './scope'
|
|
10
9
|
export * from './types'
|
|
11
10
|
export * from './utils'
|
|
12
11
|
|
|
12
|
+
const GLSL_FRAGMENT_HEAD = `
|
|
13
|
+
#version 300 es
|
|
14
|
+
precision mediump float;
|
|
15
|
+
out vec4 fragColor;
|
|
16
|
+
`.trim()
|
|
17
|
+
|
|
18
|
+
const generateHead = (x: X, c: NodeContext) => {
|
|
19
|
+
const body = code(x, c)
|
|
20
|
+
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')
|
|
25
|
+
return [head, body]
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const generateStruct = (id: string, map: Map<string, string>) => {
|
|
29
|
+
return `struct ${id} {\n ${Array.from(map.values()).join(',\n ')}\n}`
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const vertex = (x: X, c: NodeContext) => {
|
|
33
|
+
if (is.str(x)) return x.trim()
|
|
34
|
+
c.code?.headers?.clear()
|
|
35
|
+
c.isFrag = false // for varying inputs or outputs
|
|
36
|
+
const [head, body] = generateHead(x, c)
|
|
37
|
+
const ret = []
|
|
38
|
+
if (c.isWebGL) {
|
|
39
|
+
ret.push('#version 300 es')
|
|
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}`)
|
|
42
|
+
ret.push(head)
|
|
43
|
+
ret.push('void main() {')
|
|
44
|
+
ret.push(` gl_Position = ${body};`)
|
|
45
|
+
for (const [id, code] of c.code?.vertVaryings?.entries() || []) ret.push(` ${id} = ${code};`)
|
|
46
|
+
} else {
|
|
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))
|
|
49
|
+
ret.push(head)
|
|
50
|
+
ret.push('@vertex')
|
|
51
|
+
ret.push(`fn main(${c.code?.vertInputs?.size ? 'in: In' : ''}) -> Out {`)
|
|
52
|
+
ret.push(' var out: Out;')
|
|
53
|
+
ret.push(` out.position = ${body};`)
|
|
54
|
+
for (const [id, code] of c.code?.vertVaryings?.entries() || []) ret.push(` out.${id} = ${code};`)
|
|
55
|
+
ret.push(' return out;')
|
|
56
|
+
}
|
|
57
|
+
ret.push('}')
|
|
58
|
+
const main = ret.filter(Boolean).join('\n').trim()
|
|
59
|
+
console.log(`↓↓↓generated↓↓↓\n${main}`)
|
|
60
|
+
return main
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export const fragment = (x: X, c: NodeContext) => {
|
|
64
|
+
if (is.str(x)) return x.trim()
|
|
65
|
+
c.code?.headers?.clear()
|
|
66
|
+
c.isFrag = true // for varying inputs or outputs
|
|
67
|
+
const [head, body] = generateHead(x, c)
|
|
68
|
+
const ret = []
|
|
69
|
+
if (c.isWebGL) {
|
|
70
|
+
ret.push(GLSL_FRAGMENT_HEAD)
|
|
71
|
+
for (const code of c.code?.fragInputs?.values() || []) ret.push(`in ${code}`)
|
|
72
|
+
ret.push(head)
|
|
73
|
+
ret.push(`void main() {\n fragColor = ${body};`)
|
|
74
|
+
} else {
|
|
75
|
+
if (c.code?.fragInputs?.size) ret.push(generateStruct('Out', c.code.fragInputs))
|
|
76
|
+
ret.push(head)
|
|
77
|
+
ret.push(`@fragment\nfn main(out: Out) -> @location(0) vec4f {`)
|
|
78
|
+
ret.push(` return ${body};`)
|
|
79
|
+
}
|
|
80
|
+
ret.push('}')
|
|
81
|
+
const main = ret.filter(Boolean).join('\n').trim()
|
|
82
|
+
console.log(`↓↓↓generated↓↓↓\n${main}`)
|
|
83
|
+
return main
|
|
84
|
+
}
|
|
85
|
+
|
|
13
86
|
// Builtin Variables
|
|
14
87
|
export const position = builtin('position')
|
|
15
88
|
export const vertexIndex = builtin('vertex_index')
|
|
@@ -31,10 +104,10 @@ export const screenCoordinate = builtin('screenCoordinate')
|
|
|
31
104
|
export const screenUV = builtin('screenUV')
|
|
32
105
|
|
|
33
106
|
// Type constructors
|
|
34
|
-
export const float = (x
|
|
35
|
-
export const int = (x
|
|
36
|
-
export const uint = (x
|
|
37
|
-
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)
|
|
38
111
|
export const vec2 = (x?: X, y?: X) => c('vec2', x, y)
|
|
39
112
|
export const vec3 = (x?: X, y?: X, z?: X) => c('vec3', x, y, z)
|
|
40
113
|
export const vec4 = (x?: X, y?: X, z?: X, w?: X) => c('vec4', x, y, z, w)
|
|
@@ -50,15 +123,18 @@ export const uvec4 = (x?: X, y?: X, z?: X, w?: X) => c('uvec4', x, y, z, w)
|
|
|
50
123
|
export const bvec2 = (x?: X, y?: X) => c('bvec2', x, y)
|
|
51
124
|
export const bvec3 = (x?: X, y?: X, z?: X) => c('bvec3', x, y, z)
|
|
52
125
|
export const bvec4 = (x?: X, y?: X, z?: X, w?: X) => c('bvec4', x, y, z, w)
|
|
126
|
+
export const texture2D = (x?: X) => c('texture', x)
|
|
127
|
+
export const sampler2D = () => c('sampler2D')
|
|
53
128
|
export const color = (r?: X, g?: X, b?: X) => {
|
|
54
129
|
if (is.num(r) && is.und(g) && is.und(b)) return vec3(...hex2rgb(r))
|
|
55
130
|
return vec3(r, g, b)
|
|
56
131
|
}
|
|
57
132
|
|
|
58
133
|
// Default uniforms
|
|
59
|
-
export const iResolution =
|
|
60
|
-
export const iMouse =
|
|
61
|
-
export const iTime =
|
|
134
|
+
export const iResolution = u(vec2(), 'iResolution')
|
|
135
|
+
export const iMouse = u(vec2(), 'iMouse')
|
|
136
|
+
export const iTime = u(float(), 'iTime')
|
|
137
|
+
export const uv = () => position.xy.div(iResolution)
|
|
62
138
|
|
|
63
139
|
// Texture Functions
|
|
64
140
|
export const texture = (x: X, y: X, z?: X) => f('texture', x, y, z)
|
|
@@ -121,3 +197,13 @@ export const step = (edge: X, x: X) => f('step', edge, x)
|
|
|
121
197
|
export const tan = (x: X) => f('tan', x)
|
|
122
198
|
export const transformDirection = (dir: X, matrix: X) => f('transformDirection', dir, matrix)
|
|
123
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,10 +13,10 @@ import {
|
|
|
13
13
|
VEC3_RETURN_FUNCTIONS,
|
|
14
14
|
VEC4_RETURN_FUNCTIONS,
|
|
15
15
|
} from './const'
|
|
16
|
-
import { isNodeProxy } from './utils'
|
|
17
|
-
import type { Constants,
|
|
16
|
+
import { isConstants, isNodeProxy, isSwizzle } from './utils'
|
|
17
|
+
import type { Constants, NodeContext, NodeProxy, X } from './types'
|
|
18
18
|
|
|
19
|
-
const getHighestPriorityType = (args: X[], c:
|
|
19
|
+
const getHighestPriorityType = (args: X[], c: NodeContext) => {
|
|
20
20
|
return args.reduce((highest, current) => {
|
|
21
21
|
const currentType = infer(current, c)
|
|
22
22
|
const highestPriority = CONSTANTS.indexOf(highest as any)
|
|
@@ -29,7 +29,7 @@ const inferBuiltin = (id: string | undefined): Constants => {
|
|
|
29
29
|
return BUILTIN_TYPES[id as keyof typeof BUILTIN_TYPES]!
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
const inferFunction = (funcName: string, args: X[], c:
|
|
32
|
+
const inferFunction = (funcName: string, args: X[], c: NodeContext): Constants => {
|
|
33
33
|
const firstArgType = args.length > 0 ? infer(args[0], c) : 'float'
|
|
34
34
|
if (FIRST_ARG_TYPE_FUNCTIONS.includes(funcName as any)) return firstArgType
|
|
35
35
|
if (SCALAR_RETURN_FUNCTIONS.includes(funcName as any)) return 'float'
|
|
@@ -52,38 +52,55 @@ const inferOperator = (leftType: string, rightType: string, op: string): Constan
|
|
|
52
52
|
return (leftPriority >= rightPriority ? leftType : rightType) as Constants
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
const inferPrimitiveType = (x: any): Constants => {
|
|
55
|
+
export const inferPrimitiveType = (x: any): Constants => {
|
|
56
56
|
if (is.bol(x)) return 'bool'
|
|
57
|
-
if (is.
|
|
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 => {
|
|
68
|
+
if (arr.length === 0) return 'void'
|
|
69
|
+
const [x] = arr
|
|
70
|
+
if (is.str(x)) return x as Constants // for struct
|
|
71
|
+
const ret = infer(x, c)
|
|
72
|
+
for (const x of arr.slice(1))
|
|
73
|
+
if (ret !== infer(x, c)) throw new Error(`glre node system error: defined scope return mismatch`)
|
|
74
|
+
return ret
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export const inferImpl = (target: NodeProxy, c: NodeContext): Constants => {
|
|
67
78
|
const { type, props } = target
|
|
68
|
-
const { id, children = [], inferFrom } = props
|
|
79
|
+
const { id, children = [], layout, inferFrom } = props
|
|
69
80
|
const [x, y, z] = children
|
|
70
|
-
if (inferFrom) return infer(inferFrom, c)
|
|
71
81
|
if (type === 'conversion') return x as Constants
|
|
72
82
|
if (type === 'operator') return inferOperator(infer(y, c), infer(z, c), x as string)
|
|
73
83
|
if (type === 'function') return inferFunction(x as string, children.slice(1), c)
|
|
74
|
-
if (type === 'swizzle') return inferSwizzle((x as string).length)
|
|
75
84
|
if (type === 'ternary') return inferOperator(infer(y, c), infer(z, c), 'add')
|
|
76
85
|
if (type === 'builtin') return inferBuiltin(id)
|
|
77
|
-
if (type === 'define')
|
|
78
|
-
|
|
79
|
-
|
|
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
|
|
80
95
|
}
|
|
96
|
+
if (inferFrom) return inferFromArray(inferFrom, c)
|
|
81
97
|
return infer(x, c)
|
|
82
98
|
}
|
|
83
99
|
|
|
84
|
-
export const infer = (target: X, c?:
|
|
100
|
+
export const infer = (target: X, c?: NodeContext | null): Constants => {
|
|
85
101
|
if (!c) c = {}
|
|
86
102
|
if (!isNodeProxy(target)) return inferPrimitiveType(target)
|
|
103
|
+
if (is.arr(target)) return inferFromCount(target.length)
|
|
87
104
|
if (!c.infers) c.infers = new WeakMap<NodeProxy, Constants>()
|
|
88
105
|
if (c.infers.has(target)) return c.infers.get(target)!
|
|
89
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,35 +20,32 @@ 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
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
// headers
|
|
38
|
-
export const attribute = (x: X, id
|
|
39
|
-
export const
|
|
40
|
-
export const
|
|
41
|
-
export const
|
|
42
|
-
export const
|
|
43
|
-
export const
|
|
39
|
+
export const attribute = (x: X, id = getId()) => node('attribute', { id }, x)
|
|
40
|
+
export const constant = (x: X, id = getId()) => node('constant', { id }, x)
|
|
41
|
+
export const uniform = (x: X, id = getId()) => node('uniform', { id }, x)
|
|
42
|
+
export const variable = (id = getId()) => node('variable', { id })
|
|
43
|
+
export const builtin = (id = getId()) => node('builtin', { id })
|
|
44
|
+
export const vertexStage = (x: X, id = getId()) => node('varying', { id, inferFrom: [x] }, x)
|
|
44
45
|
|
|
45
46
|
// Node shorthands
|
|
46
|
-
export const
|
|
47
|
-
export const
|
|
48
|
-
export const
|
|
49
|
-
export const
|
|
50
|
-
|
|
51
|
-
// x ? y : z
|
|
52
|
-
export const select = (x: X, y: X, z: X) => node('ternary', null, x, y, z)
|
|
47
|
+
export const operator = (key: Operators, ...x: X[]) => node('operator', null, key, ...x)
|
|
48
|
+
export const function_ = (key: Functions, ...x: X[]) => node('function', null, key, ...x)
|
|
49
|
+
export const conversion = (key: string, ...x: X[]) => node('conversion', null, key, ...x)
|
|
50
|
+
export const 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
|