glre 0.34.0 → 0.36.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/README.md +96 -98
- package/dist/index.cjs +34 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +104 -178
- package/dist/index.js +35 -31
- package/dist/index.js.map +1 -1
- package/dist/native.cjs +34 -30
- package/dist/native.cjs.map +1 -1
- package/dist/native.d.ts +29 -19
- package/dist/native.js +35 -31
- package/dist/native.js.map +1 -1
- package/dist/react.cjs +34 -30
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +35 -31
- package/dist/react.js.map +1 -1
- package/dist/solid.cjs +34 -30
- package/dist/solid.cjs.map +1 -1
- package/dist/solid.d.ts +1 -1
- package/dist/solid.js +35 -31
- package/dist/solid.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +13 -6
- package/src/node/core.ts +100 -0
- package/src/node/index.ts +22 -97
- package/src/node/node.ts +28 -20
- package/src/node/scope.ts +7 -13
- package/src/node/types.ts +28 -20
- package/src/node/{code.ts → utils/index.ts} +16 -11
- package/src/node/{infer.ts → utils/infer.ts} +15 -6
- package/src/node/{parse.ts → utils/parse.ts} +44 -41
- package/src/node/{utils.ts → utils/utils.ts} +25 -41
- package/src/types.ts +70 -60
- package/src/utils/helpers.ts +16 -0
- package/src/utils/pipeline.ts +41 -12
- package/src/utils/program.ts +56 -19
- package/src/webgl.ts +91 -37
- package/src/webgpu.ts +77 -47
- /package/src/node/{const.ts → utils/const.ts} +0 -0
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -8,9 +8,6 @@ import type { GL } from './types'
|
|
|
8
8
|
import { float, fract, int, iResolution, position, vec4, vertexIndex } from './node'
|
|
9
9
|
export * from './node'
|
|
10
10
|
export * from './types'
|
|
11
|
-
export * from './utils/helpers'
|
|
12
|
-
export * from './utils/pipeline'
|
|
13
|
-
export * from './utils/program'
|
|
14
11
|
export * from './webgl'
|
|
15
12
|
export * from './webgpu'
|
|
16
13
|
|
|
@@ -45,9 +42,10 @@ const defaultVertex = () =>
|
|
|
45
42
|
)
|
|
46
43
|
|
|
47
44
|
export const createGL = (props?: Partial<GL>) => {
|
|
48
|
-
const gl = event
|
|
45
|
+
const gl = event({
|
|
49
46
|
isNative: false,
|
|
50
47
|
isWebGL: true,
|
|
48
|
+
isError: false,
|
|
51
49
|
isLoop: true,
|
|
52
50
|
isGL: true,
|
|
53
51
|
size: [0, 0],
|
|
@@ -55,27 +53,37 @@ export const createGL = (props?: Partial<GL>) => {
|
|
|
55
53
|
count: 6,
|
|
56
54
|
webgl: {},
|
|
57
55
|
webgpu: {},
|
|
56
|
+
loading: 0,
|
|
57
|
+
error() {
|
|
58
|
+
gl.isError = true
|
|
59
|
+
gl.isLoop = false
|
|
60
|
+
gl.clean()
|
|
61
|
+
},
|
|
58
62
|
}) as EventState<GL>
|
|
59
63
|
|
|
60
64
|
gl.queue = createQueue()
|
|
61
65
|
gl.frame = createFrame()
|
|
62
66
|
|
|
63
67
|
gl.attribute = durable((k, v, i) => gl.queue(() => gl._attribute?.(k, v, i)), gl)
|
|
64
|
-
gl.
|
|
68
|
+
gl.storage = durable((k, v) => gl.queue(() => gl._storage?.(k, v)), gl)
|
|
69
|
+
gl.uniform = durable((k, v) => gl.queue(() => gl._uniform?.(k, v)), gl)
|
|
65
70
|
gl.texture = durable((k, v) => gl.queue(() => gl._texture?.(k, v)), gl)
|
|
66
71
|
gl.uniform({ iResolution: gl.size, iMouse: [0, 0], iTime })
|
|
67
72
|
|
|
68
73
|
gl('mount', async () => {
|
|
69
74
|
gl.vs = gl.vs || gl.vert || gl.vertex || defaultVertex()
|
|
70
75
|
gl.fs = gl.fs || gl.frag || gl.fragment || defaultFragment()
|
|
76
|
+
gl.cs = gl.cs || gl.comp || gl.compute
|
|
71
77
|
if (!isWebGPUSupported()) gl.isWebGL = true
|
|
72
78
|
if (gl.isWebGL) {
|
|
73
79
|
gl((await webgl(gl)) as GL)
|
|
74
80
|
} else gl((await webgpu(gl)) as GL)
|
|
81
|
+
if (gl.isError) return // stop if error
|
|
75
82
|
gl.resize()
|
|
76
83
|
gl.frame(() => {
|
|
77
84
|
gl.loop()
|
|
78
85
|
gl.queue.flush()
|
|
86
|
+
if (gl.loading) return true // wait for textures @TODO FIX
|
|
79
87
|
gl.render()
|
|
80
88
|
return gl.isLoop
|
|
81
89
|
})
|
|
@@ -86,7 +94,6 @@ export const createGL = (props?: Partial<GL>) => {
|
|
|
86
94
|
|
|
87
95
|
gl('clean', () => {
|
|
88
96
|
gl.frame.stop()
|
|
89
|
-
gl.frame.clean(gl.render)
|
|
90
97
|
if (gl.isNative) return
|
|
91
98
|
window.removeEventListener('resize', gl.resize)
|
|
92
99
|
gl.el.removeEventListener('mousemove', gl.mousemove)
|
package/src/node/core.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { code } from './utils'
|
|
2
|
+
import { is } from '../utils/helpers'
|
|
3
|
+
import type { NodeContext, X } from './types'
|
|
4
|
+
|
|
5
|
+
const GLSL_FRAGMENT_HEAD = `
|
|
6
|
+
#version 300 es
|
|
7
|
+
precision mediump float;
|
|
8
|
+
out vec4 fragColor;
|
|
9
|
+
`.trim()
|
|
10
|
+
|
|
11
|
+
const topological = (headers: Map<string, string>, dependencies: Map<string, Set<string>>) => {
|
|
12
|
+
const sorted: [string, string][] = []
|
|
13
|
+
const visited = new Set<string>()
|
|
14
|
+
const visiting = new Set<string>()
|
|
15
|
+
const visit = (id: string) => {
|
|
16
|
+
if (visiting.has(id)) return
|
|
17
|
+
if (visited.has(id)) return
|
|
18
|
+
visiting.add(id)
|
|
19
|
+
const deps = dependencies.get(id) || new Set()
|
|
20
|
+
for (const dep of deps) if (headers.has(dep)) visit(dep)
|
|
21
|
+
visiting.delete(id)
|
|
22
|
+
visited.add(id)
|
|
23
|
+
if (headers.has(id)) sorted.push([id, headers.get(id)!])
|
|
24
|
+
}
|
|
25
|
+
for (const [id] of headers) visit(id)
|
|
26
|
+
return sorted
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const generateHead = (x: X, c: NodeContext) => {
|
|
30
|
+
const body = code(x, c)
|
|
31
|
+
let head = ''
|
|
32
|
+
if (c.isWebGL && c.code?.dependencies) {
|
|
33
|
+
const sorted = topological(c.code.headers, c.code.dependencies)
|
|
34
|
+
head = sorted.map(([, value]) => value).join('\n')
|
|
35
|
+
} else head = Array.from(c.code?.headers?.values() || []).join('\n')
|
|
36
|
+
return [head, body]
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const generateStruct = (id: string, map: Map<string, string>) => {
|
|
40
|
+
return `struct ${id} {\n ${Array.from(map.values()).join(',\n ')}\n}`
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export const fragment = (x: X, c: NodeContext) => {
|
|
44
|
+
if (is.str(x)) return x.trim()
|
|
45
|
+
c.code?.headers?.clear()
|
|
46
|
+
c.isFrag = true // for varying inputs or outputs
|
|
47
|
+
const [head, body] = generateHead(x, c)
|
|
48
|
+
const ret = []
|
|
49
|
+
if (c.isWebGL) {
|
|
50
|
+
ret.push(GLSL_FRAGMENT_HEAD)
|
|
51
|
+
for (const code of c.code?.fragInputs?.values() || []) ret.push(`in ${code}`)
|
|
52
|
+
ret.push(head)
|
|
53
|
+
ret.push(`void main() {\n fragColor = ${body};`)
|
|
54
|
+
} else {
|
|
55
|
+
if (c.code?.fragInputs?.size) ret.push(generateStruct('Out', c.code.fragInputs))
|
|
56
|
+
ret.push(head)
|
|
57
|
+
ret.push(`@fragment\nfn main(out: Out) -> @location(0) vec4f {`)
|
|
58
|
+
ret.push(` return ${body};`)
|
|
59
|
+
}
|
|
60
|
+
ret.push('}')
|
|
61
|
+
const main = ret.filter(Boolean).join('\n').trim()
|
|
62
|
+
// console.log(`↓↓↓generated↓↓↓\n${main}`)
|
|
63
|
+
return main
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export const vertex = (x: X, c: NodeContext) => {
|
|
67
|
+
if (is.str(x)) return x.trim()
|
|
68
|
+
c.code?.headers?.clear()
|
|
69
|
+
c.isFrag = false // for varying inputs or outputs
|
|
70
|
+
const [head, body] = generateHead(x, c)
|
|
71
|
+
const ret = []
|
|
72
|
+
if (c.isWebGL) {
|
|
73
|
+
ret.push('#version 300 es')
|
|
74
|
+
for (const code of c.code?.vertInputs?.values() || []) ret.push(`in ${code}`)
|
|
75
|
+
for (const code of c.code?.vertOutputs?.values() || []) ret.push(`out ${code}`)
|
|
76
|
+
ret.push(head)
|
|
77
|
+
ret.push('void main() {')
|
|
78
|
+
ret.push(` gl_Position = ${body};`)
|
|
79
|
+
for (const [id, code] of c.code?.vertVaryings?.entries() || []) ret.push(` ${id} = ${code};`)
|
|
80
|
+
} else {
|
|
81
|
+
if (c.code?.vertInputs?.size) ret.push(generateStruct('In', c.code.vertInputs))
|
|
82
|
+
if (c.code?.vertOutputs?.size) ret.push(generateStruct('Out', c.code.vertOutputs))
|
|
83
|
+
ret.push(head)
|
|
84
|
+
ret.push('@vertex')
|
|
85
|
+
ret.push(`fn main(${c.code?.vertInputs?.size ? 'in: In' : ''}) -> Out {`)
|
|
86
|
+
ret.push(' var out: Out;')
|
|
87
|
+
ret.push(` out.position = ${body};`)
|
|
88
|
+
for (const [id, code] of c.code?.vertVaryings?.entries() || []) ret.push(` out.${id} = ${code};`)
|
|
89
|
+
ret.push(' return out;')
|
|
90
|
+
}
|
|
91
|
+
ret.push('}')
|
|
92
|
+
const main = ret.filter(Boolean).join('\n').trim()
|
|
93
|
+
// console.log(`↓↓↓generated↓↓↓\n${main}`)
|
|
94
|
+
return main
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export const compute = (x: X, _c: NodeContext) => {
|
|
98
|
+
if (is.str(x)) return x.trim()
|
|
99
|
+
return ''
|
|
100
|
+
}
|
package/src/node/index.ts
CHANGED
|
@@ -1,107 +1,31 @@
|
|
|
1
|
+
import { hex2rgb } from './utils'
|
|
2
|
+
import { builtin as b, conversion as c, function_ as f, uniform as u } from './node'
|
|
1
3
|
import { is } from '../utils/helpers'
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
import { hex2rgb, sortHeadersByDependencies } from './utils'
|
|
5
|
-
import type { Constants as C, NodeContext, X, Vec2, Float } from './types'
|
|
6
|
-
export * from './code'
|
|
4
|
+
import type { Constants as C, X, Vec2, Float, NodeProxy } from './types'
|
|
5
|
+
export * from './core'
|
|
7
6
|
export * from './node'
|
|
8
7
|
export * from './scope'
|
|
9
8
|
export * from './types'
|
|
10
|
-
export * from './utils'
|
|
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
9
|
|
|
86
10
|
// Builtin Variables
|
|
87
|
-
export const position =
|
|
88
|
-
export const vertexIndex =
|
|
89
|
-
export const instanceIndex =
|
|
90
|
-
export const frontFacing =
|
|
91
|
-
export const fragDepth =
|
|
92
|
-
export const sampleIndex =
|
|
93
|
-
export const sampleMask =
|
|
94
|
-
export const pointCoord =
|
|
11
|
+
export const position = b<'vec4'>('position')
|
|
12
|
+
export const vertexIndex = b<'uint'>('vertex_index')
|
|
13
|
+
export const instanceIndex = b<'uint'>('instance_index')
|
|
14
|
+
export const frontFacing = b<'bool'>('front_facing')
|
|
15
|
+
export const fragDepth = b<'float'>('frag_depth')
|
|
16
|
+
export const sampleIndex = b<'uint'>('sample_index')
|
|
17
|
+
export const sampleMask = b<'uint'>('sample_mask')
|
|
18
|
+
export const pointCoord = b<'vec2'>('point_coord')
|
|
95
19
|
|
|
96
20
|
// TSL Compatible Builtin Variables
|
|
97
|
-
export const positionLocal =
|
|
98
|
-
export const positionWorld =
|
|
99
|
-
export const positionView =
|
|
100
|
-
export const normalLocal =
|
|
101
|
-
export const normalWorld =
|
|
102
|
-
export const normalView =
|
|
103
|
-
export const screenCoordinate =
|
|
104
|
-
export const screenUV =
|
|
21
|
+
export const positionLocal = b<'vec3'>('position')
|
|
22
|
+
export const positionWorld = b<'vec3'>('positionWorld')
|
|
23
|
+
export const positionView = b<'vec3'>('positionView')
|
|
24
|
+
export const normalLocal = b<'vec3'>('normalLocal')
|
|
25
|
+
export const normalWorld = b<'vec3'>('normalWorld')
|
|
26
|
+
export const normalView = b<'vec3'>('normalView')
|
|
27
|
+
export const screenCoordinate = b<'vec2'>('screenCoordinate')
|
|
28
|
+
export const screenUV = b<'vec2'>('screenUV')
|
|
105
29
|
|
|
106
30
|
// Type constructors with proper type inference
|
|
107
31
|
export const float = (x?: X) => c('float', x)
|
|
@@ -204,7 +128,7 @@ export const step = <T extends C>(edge: X, x: X<T>) => f<T>('step', edge, x)
|
|
|
204
128
|
export const smoothstep = <T extends C>(e0: X, e1: X, x: X<T>) => f<T>('smoothstep', e0, e1, x)
|
|
205
129
|
|
|
206
130
|
// Two-argument functions with highest priority type
|
|
207
|
-
export const atan2 = <T extends C>(
|
|
131
|
+
export const atan2 = <T extends C>(x: X<T>, y: X) => f<T>('atan2', x, y)
|
|
208
132
|
export const pow = <T extends C>(x: X<T>, y: X) => f<T>('pow', x, y)
|
|
209
133
|
|
|
210
134
|
// Component-wise power functions
|
|
@@ -219,3 +143,4 @@ export const difference = <T extends C>(x: X<T>, y: X) => f<T>('difference', x,
|
|
|
219
143
|
export const equals = (x: X, y: X) => f<'bool'>('equals', x, y)
|
|
220
144
|
export const faceforward = <T extends C>(N: X<T>, I: X, Nref: X) => f<T>('faceforward', N, I, Nref)
|
|
221
145
|
export const transformDirection = <T extends C>(dir: X<T>, matrix: X) => f<T>('transformDirection', dir, matrix)
|
|
146
|
+
export const mod = <T extends C>(x: NodeProxy<T>, y: X<T>) => x.sub(x.div(y).floor().mul(y))
|
package/src/node/node.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { code } from './code'
|
|
1
|
+
import { code, getConstant, isConversion, isFunction, isOperator, getId, isArrayAccess } from './utils'
|
|
3
2
|
import { assign, toVar } from './scope'
|
|
4
|
-
import {
|
|
3
|
+
import { is } from '../utils/helpers'
|
|
5
4
|
import type { Functions, NodeProps, NodeProxy, NodeTypes, Operators, X, Constants as C } from './types'
|
|
6
5
|
|
|
7
6
|
const toPrimitive = (x: X, hint: string) => {
|
|
@@ -12,23 +11,31 @@ export const node = <T extends C>(type: NodeTypes, props?: NodeProps | null, ...
|
|
|
12
11
|
if (!props) props = {}
|
|
13
12
|
if (args.length) props.children = args
|
|
14
13
|
const listeners = new Set<(value: any) => void>()
|
|
15
|
-
const get = (_: unknown,
|
|
16
|
-
if (
|
|
17
|
-
if (
|
|
18
|
-
if (
|
|
19
|
-
if (
|
|
20
|
-
if (
|
|
21
|
-
if (
|
|
22
|
-
if (
|
|
23
|
-
if (
|
|
24
|
-
if (
|
|
25
|
-
if (
|
|
26
|
-
if (
|
|
27
|
-
if (
|
|
14
|
+
const get = (_: unknown, y: string | Symbol) => {
|
|
15
|
+
if (y === 'type') return type
|
|
16
|
+
if (y === 'props') return props
|
|
17
|
+
if (y === 'toVar') return toVar.bind(null, x)
|
|
18
|
+
if (y === 'assign') return assign.bind(null, x)
|
|
19
|
+
if (y === 'isProxy') return true
|
|
20
|
+
if (y === 'toString') return code.bind(null, x)
|
|
21
|
+
if (y === Symbol.toPrimitive) return toPrimitive.bind(null, x)
|
|
22
|
+
if (y === 'listeners') return listeners
|
|
23
|
+
if (y === 'attribute') return (id = getId()) => attribute(x, id)
|
|
24
|
+
if (y === 'constant') return (id = getId()) => constant(x, id)
|
|
25
|
+
if (y === 'uniform') return (id = getId()) => uniform(x, id)
|
|
26
|
+
if (y === 'variable') return (id = getId()) => variable(id)
|
|
27
|
+
if (y === 'builtin') return (id = getId()) => builtin(id)
|
|
28
|
+
if (y === 'vertexStage') return (id = getId()) => vertexStage(x, id)
|
|
29
|
+
if (y === 'element') return (z: X) => element(x, z)
|
|
30
|
+
if (y === 'member') return (z: X) => member(x, z)
|
|
31
|
+
if (isOperator(y)) return (...z: X[]) => operator(y, x, ...z)
|
|
32
|
+
if (isFunction(y)) return (...z: X[]) => function_(y, x, ...z)
|
|
33
|
+
if (isConversion(y)) return () => conversion(getConstant(y), x)
|
|
34
|
+
if (is.str(y)) return isArrayAccess(y) ? element(x, y) : member(x, y)
|
|
28
35
|
}
|
|
29
|
-
const set = (_: unknown,
|
|
30
|
-
if (
|
|
31
|
-
if (is.str(
|
|
36
|
+
const set = (_: unknown, y: string, z: X) => {
|
|
37
|
+
if (y === 'value') listeners.forEach((fun) => fun(z))
|
|
38
|
+
if (is.str(y)) member(x, y).assign(z)
|
|
32
39
|
return true
|
|
33
40
|
}
|
|
34
41
|
const x = new Proxy({}, { get, set }) as unknown as NodeProxy<T>
|
|
@@ -46,7 +53,8 @@ export const vertexStage = <T extends C>(x: X<T>, id = getId()) => {
|
|
|
46
53
|
}
|
|
47
54
|
|
|
48
55
|
// Node shorthands with proper typing
|
|
49
|
-
export const member = <T extends C>(
|
|
56
|
+
export const member = <T extends C>(x: X, index: X) => node<T>('member', null, x, index)
|
|
57
|
+
export const element = <T extends C>(x: X, index: X) => node<T>('element', null, x, index)
|
|
50
58
|
export const select = <T extends C>(x: X<T>, y: X<T>, z: X) => node<T>('ternary', null, x, y, z) // z ? x : y @TODO REMOVE
|
|
51
59
|
export const operator = <T extends C>(key: Operators, ...x: X[]) => node<T>('operator', null, key, ...x)
|
|
52
60
|
export const function_ = <T extends C>(key: Functions, ...x: X[]) => node<T>('function', null, key, ...x)
|
package/src/node/scope.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { conversion, node } from './node'
|
|
2
1
|
import { getId } from './utils'
|
|
2
|
+
import { conversion, node } from './node'
|
|
3
3
|
import type { FnLayout, NodeProps, NodeProxy, X, Constants, Int } from './types'
|
|
4
4
|
|
|
5
5
|
let scope: NodeProxy | null = null
|
|
@@ -45,18 +45,11 @@ export const struct = <T extends Record<string, NodeProxy>>(fields: T, id = getI
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
const scoped = (x: NodeProxy, fun: () => NodeProxy | void, y = define) => {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const _define = define
|
|
51
|
-
// update
|
|
52
|
-
scope = x
|
|
53
|
-
define = y
|
|
54
|
-
if (_scope) x.props.parent = _scope
|
|
48
|
+
const [_scope, _define] = [scope, define]
|
|
49
|
+
;[scope, define] = [x, y]
|
|
55
50
|
const z = fun()
|
|
56
51
|
if (z) Return(z)
|
|
57
|
-
|
|
58
|
-
scope = _scope
|
|
59
|
-
define = _define
|
|
52
|
+
;[scope, define] = [_scope, _define]
|
|
60
53
|
}
|
|
61
54
|
|
|
62
55
|
export const If = (x: NodeProxy, fun: () => void) => {
|
|
@@ -82,8 +75,9 @@ export const If = (x: NodeProxy, fun: () => void) => {
|
|
|
82
75
|
|
|
83
76
|
export const Loop = (x: NodeProxy, fun: (params: { i: Int }) => void) => {
|
|
84
77
|
const y = node('scope')
|
|
85
|
-
|
|
86
|
-
|
|
78
|
+
const id = getId()
|
|
79
|
+
scoped(y, () => fun({ i: node<'int'>('variable', { id, inferFrom: [conversion('int', 0)] }) }))
|
|
80
|
+
const ret = node('loop', { id }, x, y)
|
|
87
81
|
addToScope(ret)
|
|
88
82
|
return ret
|
|
89
83
|
}
|
package/src/node/types.ts
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import { CONSTANTS, CONVERSIONS, FUNCTIONS, OPERATOR_KEYS } from './const'
|
|
1
|
+
import { CONSTANTS, CONVERSIONS, FUNCTIONS, OPERATOR_KEYS } from './utils/const'
|
|
2
|
+
import type { GL } from '../types'
|
|
4
3
|
|
|
5
4
|
export type Constants = (typeof CONSTANTS)[number] | 'void'
|
|
6
|
-
|
|
7
5
|
export type Conversions = (typeof CONVERSIONS)[number]
|
|
8
|
-
|
|
9
6
|
export type Functions = (typeof FUNCTIONS)[number]
|
|
10
|
-
|
|
11
7
|
export type Operators = (typeof OPERATOR_KEYS)[number]
|
|
12
8
|
|
|
13
9
|
export interface FnLayout {
|
|
@@ -38,6 +34,7 @@ export type NodeTypes =
|
|
|
38
34
|
// struct
|
|
39
35
|
| 'struct'
|
|
40
36
|
| 'member'
|
|
37
|
+
| 'element'
|
|
41
38
|
// scopes
|
|
42
39
|
| 'scope'
|
|
43
40
|
| 'assign'
|
|
@@ -55,7 +52,6 @@ export interface NodeProps<T extends Record<string, NodeProxy> = {}> {
|
|
|
55
52
|
children?: any[]
|
|
56
53
|
inferFrom?: any[]
|
|
57
54
|
layout?: FnLayout
|
|
58
|
-
parent?: NodeProxy
|
|
59
55
|
// for struct
|
|
60
56
|
fields?: T
|
|
61
57
|
initialValues?: T
|
|
@@ -81,6 +77,20 @@ export interface NodeContext {
|
|
|
81
77
|
/**
|
|
82
78
|
* infer
|
|
83
79
|
*/
|
|
80
|
+
type _StringLength<S extends string> = S extends `${infer _}${infer Rest}`
|
|
81
|
+
? Rest extends ''
|
|
82
|
+
? 1
|
|
83
|
+
: Rest extends `${infer _}${infer Rest2}`
|
|
84
|
+
? Rest2 extends ''
|
|
85
|
+
? 2
|
|
86
|
+
: Rest2 extends `${infer _}${infer Rest3}`
|
|
87
|
+
? Rest3 extends ''
|
|
88
|
+
? 3
|
|
89
|
+
: 4
|
|
90
|
+
: never
|
|
91
|
+
: never
|
|
92
|
+
: 0
|
|
93
|
+
|
|
84
94
|
// Unified logic with infer.ts inferOperator function
|
|
85
95
|
// prettier-ignore
|
|
86
96
|
type InferOperator<L extends Constants, R extends Constants> =
|
|
@@ -97,19 +107,13 @@ type InferOperator<L extends Constants, R extends Constants> =
|
|
|
97
107
|
L extends 'vec3' ? R extends 'mat3' ? L /* default */ : L :
|
|
98
108
|
L extends 'vec2' ? R extends 'mat2' ? L /* default */ : L : L
|
|
99
109
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
? Rest3 extends ''
|
|
108
|
-
? 3
|
|
109
|
-
: 4
|
|
110
|
-
: never
|
|
111
|
-
: never
|
|
112
|
-
: 0
|
|
110
|
+
// Unified logic with infer.ts inferArrayElement function
|
|
111
|
+
// prettier-ignore
|
|
112
|
+
type InferArrayElement<T extends Constants> =
|
|
113
|
+
T extends 'mat4' ? 'vec4' :
|
|
114
|
+
T extends 'mat3' ? 'vec3' :
|
|
115
|
+
T extends 'mat2' ? 'vec2' :
|
|
116
|
+
'float'
|
|
113
117
|
|
|
114
118
|
type InferSwizzleType<S extends string> = _StringLength<S> extends 4
|
|
115
119
|
? 'vec4'
|
|
@@ -142,6 +146,7 @@ type NodeProxyMethods =
|
|
|
142
146
|
| 'assign'
|
|
143
147
|
| 'toVar'
|
|
144
148
|
| 'toString'
|
|
149
|
+
| 'element'
|
|
145
150
|
|
|
146
151
|
export interface BaseNodeProxy<T extends Constants> {
|
|
147
152
|
// System properties
|
|
@@ -261,6 +266,9 @@ export interface BaseNodeProxy<T extends Constants> {
|
|
|
261
266
|
pow2(): NodeProxy<T>
|
|
262
267
|
pow3(): NodeProxy<T>
|
|
263
268
|
pow4(): NodeProxy<T>
|
|
269
|
+
|
|
270
|
+
// Element access for array/matrix types
|
|
271
|
+
element<Index extends X>(index: Index): NodeProxy<InferArrayElement<T>>
|
|
264
272
|
}
|
|
265
273
|
|
|
266
274
|
type ReadNodeProxy = {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { is } from '../utils/helpers'
|
|
2
1
|
import { infer } from './infer'
|
|
3
2
|
import {
|
|
4
3
|
parseArray,
|
|
@@ -14,8 +13,11 @@ import {
|
|
|
14
13
|
parseVaryingHead,
|
|
15
14
|
parseUniformHead,
|
|
16
15
|
} from './parse'
|
|
17
|
-
import { getBluiltin, getOperator,
|
|
18
|
-
import
|
|
16
|
+
import { getBluiltin, getOperator, getConversions, safeEventCall, getEventFun, initNodeContext } from './utils'
|
|
17
|
+
import { is } from '../../utils/helpers'
|
|
18
|
+
import type { Constants, NodeContext, X } from '../types'
|
|
19
|
+
|
|
20
|
+
export * from './utils'
|
|
19
21
|
|
|
20
22
|
export const code = <T extends Constants>(target: X<T>, c?: NodeContext | null): string => {
|
|
21
23
|
if (!c) c = {}
|
|
@@ -31,26 +33,29 @@ export const code = <T extends Constants>(target: X<T>, c?: NodeContext | null):
|
|
|
31
33
|
}
|
|
32
34
|
if (is.bol(target)) return target ? 'true' : 'false'
|
|
33
35
|
if (!target) return ''
|
|
34
|
-
const { type, props } = target
|
|
35
|
-
const { id = '', children = [], fields, initialValues } = props
|
|
36
|
+
const { type, props = {} } = target
|
|
37
|
+
const { id = 'i', children = [], fields, initialValues } = props
|
|
36
38
|
const [x, y, z, w] = children
|
|
37
39
|
/**
|
|
38
40
|
* variables
|
|
39
41
|
*/
|
|
40
42
|
if (type === 'variable') return id
|
|
41
|
-
if (type === 'member') return `${code(
|
|
43
|
+
if (type === 'member') return `${code(x, c)}.${code(y, c)}`
|
|
44
|
+
if (type === 'element') return `${code(x, c)}[${code(y, c)}]`
|
|
42
45
|
if (type === 'ternary')
|
|
43
46
|
return c.isWebGL
|
|
44
47
|
? `(${code(z, c)} ? ${code(x, c)} : ${code(y, c)})`
|
|
45
48
|
: `select(${code(x, c)}, ${code(y, c)}, ${code(z, c)})`
|
|
46
|
-
if (type === 'conversion') return `${
|
|
49
|
+
if (type === 'conversion') return `${getConversions(x, c)}(${parseArray(children.slice(1), c)})`
|
|
47
50
|
if (type === 'operator') {
|
|
48
51
|
if (x === 'not' || x === 'bitNot') return `!${code(y, c)}`
|
|
49
52
|
return `(${code(y, c)} ${getOperator(x)} ${code(z, c)})`
|
|
50
53
|
}
|
|
51
54
|
if (type === 'function') {
|
|
52
|
-
if (x === 'negate') return `(-${
|
|
55
|
+
if (x === 'negate') return `(-${code(y, c)})`
|
|
56
|
+
if (x === 'oneMinus') return `(1.0-${code(y, c)})`
|
|
53
57
|
if (x === 'texture') return parseTexture(c, y, z, w)
|
|
58
|
+
if (x === 'atan2' && c.isWebGL) return `atan(${code(y, c)}, ${code(z, c)})`
|
|
54
59
|
return `${x}(${parseArray(children.slice(1), c)})`
|
|
55
60
|
}
|
|
56
61
|
/**
|
|
@@ -61,8 +66,8 @@ export const code = <T extends Constants>(target: X<T>, c?: NodeContext | null):
|
|
|
61
66
|
if (type === 'return') return `return ${code(x, c)};`
|
|
62
67
|
if (type === 'loop')
|
|
63
68
|
return c.isWebGL
|
|
64
|
-
? `for (int
|
|
65
|
-
: `for (var
|
|
69
|
+
? `for (int ${id} = 0; ${id} < ${code(x, c)}; ${id} += 1) {\n${code(y, c)}\n}`
|
|
70
|
+
: `for (var ${id}: i32 = 0; ${id} < ${code(x, c)}; ${id}++) {\n${code(y, c)}\n}`
|
|
66
71
|
if (type === 'if') return parseIf(c, x, y, children)
|
|
67
72
|
if (type === 'switch') return parseSwitch(c, x, children)
|
|
68
73
|
if (type === 'declare') return parseDeclare(c, x, y)
|
|
@@ -88,7 +93,7 @@ export const code = <T extends Constants>(target: X<T>, c?: NodeContext | null):
|
|
|
88
93
|
if (type === 'builtin') {
|
|
89
94
|
if (c.isWebGL) return getBluiltin(id)
|
|
90
95
|
if (id === 'position') return 'out.position'
|
|
91
|
-
const field = `@builtin(${id}) ${id}: ${
|
|
96
|
+
const field = `@builtin(${id}) ${id}: ${getConversions(infer(target, c), c)}`
|
|
92
97
|
if (c.isFrag) {
|
|
93
98
|
c.code?.fragInputs.set(id, field)
|
|
94
99
|
} else c.code?.vertInputs.set(id, field)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isConstants, isNodeProxy, isSwizzle } from './utils'
|
|
2
2
|
import {
|
|
3
3
|
BUILTIN_TYPES,
|
|
4
4
|
COMPARISON_OPERATORS,
|
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
FUNCTION_RETURN_TYPES,
|
|
7
7
|
LOGICAL_OPERATORS,
|
|
8
8
|
} from './const'
|
|
9
|
-
import {
|
|
10
|
-
import type { Constants as C, NodeContext, NodeProxy, X } from '
|
|
9
|
+
import { is } from '../../utils/helpers'
|
|
10
|
+
import type { Constants as C, NodeContext, NodeProxy, X } from '../types'
|
|
11
11
|
|
|
12
12
|
const inferBuiltin = <T extends C>(id: string | undefined) => {
|
|
13
13
|
return BUILTIN_TYPES[id as keyof typeof BUILTIN_TYPES] as T
|
|
@@ -31,6 +31,14 @@ const inferOperator = <T extends C>(L: T, R: T, op: string): T => {
|
|
|
31
31
|
return L
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
// Unified logic with infer.ts InferArrayElement type
|
|
35
|
+
const inferArrayElement = <T extends C>(arrayType: T): T => {
|
|
36
|
+
if (arrayType === 'mat4') return 'vec4' as T
|
|
37
|
+
if (arrayType === 'mat3') return 'vec3' as T
|
|
38
|
+
if (arrayType === 'mat2') return 'vec2' as T
|
|
39
|
+
return 'float' as T
|
|
40
|
+
}
|
|
41
|
+
|
|
34
42
|
export const inferPrimitiveType = <T extends C>(x: X) => {
|
|
35
43
|
if (is.bol(x)) return 'bool' as T
|
|
36
44
|
if (is.str(x)) return 'texture' as T
|
|
@@ -68,10 +76,11 @@ export const inferImpl = <T extends C>(target: NodeProxy<T>, c: NodeContext): T
|
|
|
68
76
|
if (type === 'function') return inferFunction(x) || infer(y, c)
|
|
69
77
|
if (type === 'define' && isConstants(layout?.type)) return layout?.type as T
|
|
70
78
|
if (type === 'attribute' && is.arr(x) && c.gl?.count) return inferFromCount(x.length / c.gl.count)
|
|
79
|
+
if (type === 'element') return inferArrayElement(infer(x, c) as T)
|
|
71
80
|
if (type === 'member') {
|
|
72
|
-
if (isSwizzle(
|
|
73
|
-
if (isNodeProxy(
|
|
74
|
-
const field = (
|
|
81
|
+
if (isSwizzle(y)) return inferFromCount(y.length)
|
|
82
|
+
if (isNodeProxy(x)) {
|
|
83
|
+
const field = (x as any).props.fields[y] // for variable node of struct member
|
|
75
84
|
if (field) return infer(field, c)
|
|
76
85
|
}
|
|
77
86
|
return 'float' as T // fallback @TODO FIX
|