glre 0.44.0 → 0.46.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 +4 -26
- package/dist/addons.d.ts +41 -51
- package/dist/index.cjs +6 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +43 -91
- package/dist/index.js +6 -6
- package/dist/index.js.map +1 -1
- package/dist/native.cjs +1 -1
- package/dist/native.cjs.map +1 -1
- package/dist/native.d.ts +51 -94
- package/dist/native.js +1 -1
- package/dist/native.js.map +1 -1
- package/dist/node.cjs +15 -15
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.ts +41 -52
- package/dist/node.js +14 -14
- package/dist/node.js.map +1 -1
- package/dist/react.cjs +1 -1
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.ts +43 -92
- package/dist/react.js +1 -1
- package/dist/react.js.map +1 -1
- package/dist/solid.cjs +1 -1
- package/dist/solid.cjs.map +1 -1
- package/dist/solid.d.ts +43 -92
- package/dist/solid.js +1 -1
- package/dist/solid.js.map +1 -1
- package/package.json +1 -1
- package/src/{utils/helpers.ts → helpers.ts} +10 -32
- package/src/index.ts +45 -42
- package/src/native.ts +6 -7
- package/src/node/build.ts +6 -21
- package/src/node/create.ts +2 -4
- package/src/node/index.ts +8 -20
- package/src/node/types.ts +9 -1
- package/src/node/utils/index.ts +5 -25
- package/src/node/utils/infer.ts +4 -12
- package/src/node/utils/parse.ts +18 -34
- package/src/node/utils/utils.ts +3 -11
- package/src/react.ts +9 -12
- package/src/solid.ts +3 -10
- package/src/types.ts +30 -22
- package/src/webgl/compute.ts +56 -0
- package/src/webgl/graphic.ts +65 -0
- package/src/webgl/index.ts +21 -0
- package/src/{utils/program.ts → webgl/utils.ts} +30 -8
- package/src/webgpu/compute.ts +39 -0
- package/src/webgpu/graphic.ts +89 -0
- package/src/webgpu/index.ts +42 -0
- package/src/{utils/pipeline.ts → webgpu/utils.ts} +75 -78
- package/src/utils/webgl.ts +0 -135
- package/src/utils/webgpu.ts +0 -178
package/src/index.ts
CHANGED
|
@@ -1,18 +1,12 @@
|
|
|
1
1
|
import { durable, event } from 'reev'
|
|
2
2
|
import { createFrame, createQueue } from 'refr'
|
|
3
|
-
import { is } from './
|
|
4
|
-
import { webgl } from './
|
|
5
|
-
import { webgpu } from './
|
|
3
|
+
import { is } from './helpers'
|
|
4
|
+
import { webgl } from './webgl'
|
|
5
|
+
import { webgpu } from './webgpu'
|
|
6
6
|
import type { EventState } from 'reev'
|
|
7
7
|
import type { GL } from './types'
|
|
8
8
|
export * from './types'
|
|
9
9
|
|
|
10
|
-
export const isGL = (a: unknown): a is EventState<GL> => {
|
|
11
|
-
if (!is.obj(a)) return false
|
|
12
|
-
if ('isGL' in a) return true
|
|
13
|
-
return false
|
|
14
|
-
}
|
|
15
|
-
|
|
16
10
|
export const isServer = () => {
|
|
17
11
|
return typeof window === 'undefined'
|
|
18
12
|
}
|
|
@@ -22,9 +16,11 @@ export const isWebGPUSupported = () => {
|
|
|
22
16
|
return 'gpu' in navigator
|
|
23
17
|
}
|
|
24
18
|
|
|
25
|
-
|
|
19
|
+
const findElement = (arg: Partial<GL>) => {
|
|
20
|
+
return arg.el || arg.elem || arg.element
|
|
21
|
+
}
|
|
26
22
|
|
|
27
|
-
export const createGL = (
|
|
23
|
+
export const createGL = (...args: Partial<GL>[]) => {
|
|
28
24
|
const gl = event({
|
|
29
25
|
isNative: false,
|
|
30
26
|
isWebGL: true,
|
|
@@ -33,16 +29,9 @@ export const createGL = (props?: Partial<GL>) => {
|
|
|
33
29
|
isDebug: false,
|
|
34
30
|
isDepth: false,
|
|
35
31
|
wireframe: false,
|
|
36
|
-
isGL: true,
|
|
37
32
|
size: [0, 0],
|
|
38
33
|
mouse: [0, 0],
|
|
39
|
-
count: 6,
|
|
40
|
-
instanceCount: 1,
|
|
41
|
-
particleCount: 1024,
|
|
42
34
|
precision: 'highp',
|
|
43
|
-
webgl: {},
|
|
44
|
-
webgpu: {},
|
|
45
|
-
loading: 0,
|
|
46
35
|
error() {
|
|
47
36
|
gl.isError = true
|
|
48
37
|
gl.isLoop = false
|
|
@@ -51,67 +40,81 @@ export const createGL = (props?: Partial<GL>) => {
|
|
|
51
40
|
},
|
|
52
41
|
}) as EventState<GL>
|
|
53
42
|
|
|
43
|
+
let iTime = performance.now()
|
|
54
44
|
gl.queue = createQueue()
|
|
55
45
|
gl.frame = createFrame()
|
|
56
46
|
|
|
57
47
|
gl.attribute = durable((k, v, i) => gl.queue(() => gl._attribute?.(k, v, i)), gl)
|
|
58
48
|
gl.instance = durable((k, v, at) => gl.queue(() => gl._instance?.(k, v, at)), gl)
|
|
59
49
|
gl.storage = durable((k, v) => gl.queue(() => gl._storage?.(k, v)), gl)
|
|
60
|
-
gl.uniform = durable((k, v) => gl.queue(() => gl._uniform?.(k, v)), gl)
|
|
61
50
|
gl.texture = durable((k, v) => gl.queue(() => gl._texture?.(k, v)), gl)
|
|
51
|
+
gl.uniform = durable((k, v) => gl.queue(() => gl._uniform?.(k, v)), gl)
|
|
62
52
|
gl.uniform({ iResolution: gl.size, iMouse: [0, 0], iTime })
|
|
63
53
|
|
|
64
|
-
gl('mount', async () => {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
gl
|
|
71
|
-
|
|
72
|
-
|
|
54
|
+
gl('mount', async (el: HTMLCanvasElement) => {
|
|
55
|
+
gl.el = findElement(gl) || el || args.map(findElement).find(Boolean)
|
|
56
|
+
const isAppend = !gl.el // Check first: canvas may unmount during WebGPU async processing
|
|
57
|
+
if (isAppend && !gl.isNative) gl.el = document.createElement('canvas')
|
|
58
|
+
for (const arg of args) {
|
|
59
|
+
gl.fs = arg.fs || arg.frag || arg.fragment || undefined
|
|
60
|
+
gl.cs = arg.cs || arg.comp || arg.compute || undefined
|
|
61
|
+
gl.vs = arg.vs || arg.vert || arg.vertex || undefined
|
|
62
|
+
gl.triangleCount = arg.triangleCount || arg.count || 6
|
|
63
|
+
gl.instanceCount = arg.instanceCount || 1
|
|
64
|
+
gl.particleCount = arg.particleCount || 1024
|
|
65
|
+
gl(arg)
|
|
66
|
+
if (is.bol(arg.isWebGL)) gl.isWebGL = arg.isWebGL || !isWebGPUSupported()
|
|
67
|
+
if (gl.isWebGL) webgl(gl)
|
|
68
|
+
else await webgpu(gl)
|
|
69
|
+
if (arg.mount) arg.mount() // events added in mount phase need explicit call to execute
|
|
70
|
+
}
|
|
71
|
+
if (!gl.el || gl.isError) return // stop if error or canvas was unmounted during async
|
|
73
72
|
gl.resize()
|
|
74
73
|
gl.frame(() => {
|
|
75
|
-
gl.loop()
|
|
76
|
-
gl.queue.flush()
|
|
77
|
-
if (gl.loading) return true // wait for textures @TODO FIX
|
|
78
74
|
gl.render()
|
|
79
75
|
return gl.isLoop
|
|
80
76
|
})
|
|
81
77
|
if (gl.isNative) return
|
|
78
|
+
if (isAppend) document.body.appendChild(gl.el)
|
|
82
79
|
window.addEventListener('resize', gl.resize)
|
|
83
80
|
gl.el.addEventListener('mousemove', gl.mousemove)
|
|
84
81
|
})
|
|
85
82
|
|
|
86
83
|
gl('clean', () => {
|
|
87
84
|
gl.frame.stop()
|
|
88
|
-
if (gl.isNative) return
|
|
85
|
+
if (!gl.el || gl.isNative) return
|
|
89
86
|
window.removeEventListener('resize', gl.resize)
|
|
90
87
|
gl.el.removeEventListener('mousemove', gl.mousemove)
|
|
91
88
|
})
|
|
92
89
|
|
|
90
|
+
gl('ref', (el: HTMLCanvasElement | null) => {
|
|
91
|
+
if (el) {
|
|
92
|
+
gl.el = el
|
|
93
|
+
gl.mount()
|
|
94
|
+
} else gl.clean()
|
|
95
|
+
})
|
|
96
|
+
|
|
93
97
|
gl('resize', () => {
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
gl.size[
|
|
97
|
-
gl.size[1] = gl.el.height = h
|
|
98
|
+
const rect = gl.el.parentElement?.getBoundingClientRect()
|
|
99
|
+
gl.size[0] = gl.el.width = gl.width || rect?.width || window.innerWidth
|
|
100
|
+
gl.size[1] = gl.el.height = gl.height || rect?.height || window.innerHeight
|
|
98
101
|
gl.uniform('iResolution', gl.size)
|
|
99
102
|
})
|
|
100
103
|
|
|
101
104
|
gl('mousemove', (_e: any, x = _e.clientX, y = _e.clientY) => {
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
gl.mouse[
|
|
105
|
-
gl.mouse[1] = -(y - left - h / 2) / (h / 2)
|
|
105
|
+
const rect = gl.el.getBoundingClientRect()
|
|
106
|
+
gl.mouse[0] = (x - rect.left) / rect.width
|
|
107
|
+
gl.mouse[1] = -(y - rect.top) / rect.height + 1
|
|
106
108
|
gl.uniform('iMouse', gl.mouse)
|
|
107
109
|
})
|
|
108
110
|
|
|
109
|
-
gl('
|
|
111
|
+
gl('render', () => {
|
|
110
112
|
iTime = performance.now() / 1000
|
|
111
113
|
gl.uniform('iTime', iTime)
|
|
114
|
+
gl.queue.flush()
|
|
112
115
|
})
|
|
113
116
|
|
|
114
|
-
return gl
|
|
117
|
+
return gl
|
|
115
118
|
}
|
|
116
119
|
|
|
117
120
|
export default createGL
|
package/src/native.ts
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import { useState } from 'react'
|
|
2
|
-
|
|
3
|
-
import { createGL, isGL } from './index'
|
|
1
|
+
import { useState } from 'react'
|
|
2
|
+
import { createGL } from './index'
|
|
4
3
|
import type { GL } from './types'
|
|
5
4
|
export * from './index'
|
|
6
5
|
|
|
7
|
-
export const useGL = (
|
|
6
|
+
export const useGL = (...args: Partial<GL>[]) => {
|
|
8
7
|
return useState(() => {
|
|
9
|
-
const gl =
|
|
8
|
+
const gl = createGL(...args)
|
|
9
|
+
gl.isNative = true
|
|
10
10
|
gl.ref = (ctx: any) => {
|
|
11
|
-
gl.el = {} as any
|
|
12
11
|
gl({
|
|
13
12
|
render() {
|
|
14
13
|
ctx.flush()
|
|
@@ -24,6 +23,6 @@ export const useGL = (props: Partial<GL> = {}) => {
|
|
|
24
23
|
resize()
|
|
25
24
|
// Dimensions.addEventListener('change', resize)
|
|
26
25
|
}
|
|
27
|
-
return gl(
|
|
26
|
+
return gl()
|
|
28
27
|
})[0]
|
|
29
28
|
}
|
package/src/node/build.ts
CHANGED
|
@@ -36,24 +36,9 @@ const generateStruct = (id: string, map: Map<string, string>) => {
|
|
|
36
36
|
return `struct ${id} {\n ${Array.from(map.values()).join(',\n ')}\n}`
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
const PRECISION = ['float', 'int', 'sampler2D', 'samplerCube', 'sampler3D', 'sampler2DArray', 'sampler2DShadow', 'samplerCubeShadow', 'sampler2DArrayShadow', 'isampler2D', 'isampler3D', 'isamplerCube', 'isampler2DArray', 'usampler2D', 'usampler3D', 'usamplerCube', 'usampler2DArray']
|
|
39
40
|
const precisionHead = (result: string[], precision = 'highp') => {
|
|
40
|
-
result.push(`precision ${precision}
|
|
41
|
-
result.push(`precision ${precision} int;`)
|
|
42
|
-
result.push(`precision ${precision} sampler2D;`)
|
|
43
|
-
result.push(`precision ${precision} samplerCube;`)
|
|
44
|
-
result.push(`precision ${precision} sampler3D;`)
|
|
45
|
-
result.push(`precision ${precision} sampler2DArray;`)
|
|
46
|
-
result.push(`precision ${precision} sampler2DShadow;`)
|
|
47
|
-
result.push(`precision ${precision} samplerCubeShadow;`)
|
|
48
|
-
result.push(`precision ${precision} sampler2DArrayShadow;`)
|
|
49
|
-
result.push(`precision ${precision} isampler2D;`)
|
|
50
|
-
result.push(`precision ${precision} isampler3D;`)
|
|
51
|
-
result.push(`precision ${precision} isamplerCube;`)
|
|
52
|
-
result.push(`precision ${precision} isampler2DArray;`)
|
|
53
|
-
result.push(`precision ${precision} usampler2D;`)
|
|
54
|
-
result.push(`precision ${precision} usampler3D;`)
|
|
55
|
-
result.push(`precision ${precision} usamplerCube;`)
|
|
56
|
-
result.push(`precision ${precision} usampler2DArray;`)
|
|
41
|
+
for (const key of PRECISION) result.push(`precision ${precision} ${key};`)
|
|
57
42
|
}
|
|
58
43
|
|
|
59
44
|
// ref: https://github.com/mrdoob/three.js/blob/master/src/renderers/webgl/WebGLCapabilities.js
|
|
@@ -69,7 +54,6 @@ const getMaxPrecision = (c?: WebGL2RenderingContext, precision = 'highp') => {
|
|
|
69
54
|
const p0 = c.getShaderPrecisionFormat(c.VERTEX_SHADER, c.MEDIUM_FLOAT)
|
|
70
55
|
const p1 = c.getShaderPrecisionFormat(c.FRAGMENT_SHADER, c.MEDIUM_FLOAT)
|
|
71
56
|
if (p0 && p0.precision > 0 && p1 && p1.precision > 0) return 'mediump'
|
|
72
|
-
precision = 'lowp'
|
|
73
57
|
}
|
|
74
58
|
return 'lowp'
|
|
75
59
|
}
|
|
@@ -81,7 +65,7 @@ export const fragment = (x: X, c: NodeContext = {}) => {
|
|
|
81
65
|
const result = []
|
|
82
66
|
if (c.isWebGL) {
|
|
83
67
|
result.push('#version 300 es')
|
|
84
|
-
precisionHead(result, getMaxPrecision(c.gl?.
|
|
68
|
+
precisionHead(result, getMaxPrecision(c.gl?.gl, c.gl?.precision))
|
|
85
69
|
result.push('out vec4 fragColor;')
|
|
86
70
|
for (const code of c.code?.fragInputs?.values() || []) result.push(`in ${code}`)
|
|
87
71
|
result.push(head)
|
|
@@ -104,6 +88,7 @@ export const fragment = (x: X, c: NodeContext = {}) => {
|
|
|
104
88
|
export const vertex = (x: X, c: NodeContext = {}) => {
|
|
105
89
|
c.code?.headers?.clear()
|
|
106
90
|
c.label = 'vert' // for varying inputs or outputs
|
|
91
|
+
if (c.code) for (const [id, { node }] of c.code.vertVaryings.entries()) c.code.vertVaryings.set(id, { node, code: code(node, c) }) // ① prebuild varying.code because the scope (e.g. output function definitions) is fixed to vertex.
|
|
107
92
|
const [head, lines, ret] = build(x, c)
|
|
108
93
|
const result = []
|
|
109
94
|
if (c.isWebGL) {
|
|
@@ -114,7 +99,7 @@ export const vertex = (x: X, c: NodeContext = {}) => {
|
|
|
114
99
|
result.push('void main() {')
|
|
115
100
|
result.push(` ${lines}`)
|
|
116
101
|
result.push(` gl_Position = ${ret};`)
|
|
117
|
-
for (const [id,
|
|
102
|
+
if (c.code) for (const [id, varying] of c.code.vertVaryings.entries()) result.push(` ${id} = ${varying.code!};`) // ② varying.code is already prebuilt
|
|
118
103
|
} else {
|
|
119
104
|
if (c.code?.vertInputs?.size) result.push(generateStruct('In', c.code.vertInputs))
|
|
120
105
|
if (c.code?.vertOutputs?.size) result.push(generateStruct('Out', c.code.vertOutputs))
|
|
@@ -124,7 +109,7 @@ export const vertex = (x: X, c: NodeContext = {}) => {
|
|
|
124
109
|
result.push(' var out: Out;')
|
|
125
110
|
result.push(` ${lines}`)
|
|
126
111
|
result.push(` out.position = ${ret};`)
|
|
127
|
-
for (const [id,
|
|
112
|
+
if (c.code) for (const [id, varying] of c.code.vertVaryings.entries()) result.push(` out.${id} = ${varying.code!};`)
|
|
128
113
|
result.push(' return out;')
|
|
129
114
|
}
|
|
130
115
|
result.push('}')
|
package/src/node/create.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { compute, fragment, vertex } from './build'
|
|
2
2
|
import { addToScope, assign, toVar } from './scope'
|
|
3
3
|
import { code, getConstant, isConversion, isFunction, isOperator, getId, isArrayAccess } from './utils'
|
|
4
|
-
import { is } from '../
|
|
4
|
+
import { is } from '../helpers'
|
|
5
5
|
import type { Bool, Constants as C, Functions, NodeProps, NodeTypes, Operators, X, Y } from './types'
|
|
6
6
|
|
|
7
7
|
const toPrimitive = (x: Y, hint: string) => {
|
|
@@ -35,9 +35,7 @@ export const create = <T extends C>(type: NodeTypes, props?: NodeProps | null, .
|
|
|
35
35
|
if (key === 'assign') return assign.bind(null, x, x.type === 'gather')
|
|
36
36
|
if (key === 'select') return select.bind(null, x)
|
|
37
37
|
if (isOperator(key)) {
|
|
38
|
-
return key.endsWith('Assign')
|
|
39
|
-
? (...args: Y[]) => addToScope(operator(key, x, ...args))
|
|
40
|
-
: (...args: Y[]) => operator(key, x, ...args)
|
|
38
|
+
return key.endsWith('Assign') ? (...args: Y[]) => addToScope(operator(key, x, ...args)) : (...args: Y[]) => operator(key, x, ...args)
|
|
41
39
|
}
|
|
42
40
|
if (isFunction(key)) return (...args: Y[]) => function_(key, x, ...args)
|
|
43
41
|
if (isConversion(key)) return () => conversion(getConstant(key), x)
|
package/src/node/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { hex2rgb } from './utils'
|
|
2
2
|
import { builtin as b, conversion as c, function_ as f, uniform as u } from './create'
|
|
3
|
-
import { is } from '../
|
|
3
|
+
import { is } from '../helpers'
|
|
4
4
|
import type { Constants as C, Float, X, Y } from './types'
|
|
5
5
|
export * from './build'
|
|
6
6
|
export * from './create'
|
|
@@ -72,12 +72,8 @@ export const any = <T extends C>(x: X<T>) => f<'bool'>('any', x)
|
|
|
72
72
|
|
|
73
73
|
// 2. Always return float with WGSL-compliant type constraints and unified parameter types
|
|
74
74
|
export const determinant = <T extends 'mat2' | 'mat3' | 'mat4'>(x: X<T>) => f<'float'>('determinant', x)
|
|
75
|
-
export const distance = <T extends 'vec2' | 'vec3' | 'vec4', U extends C>(x: X<T>, y: number | X<U>) =>
|
|
76
|
-
|
|
77
|
-
export const dot = <T extends 'vec2' | 'vec3' | 'vec4' | 'ivec2' | 'ivec3' | 'ivec4', U extends C>(
|
|
78
|
-
x: X<T>,
|
|
79
|
-
y: number | X<U>
|
|
80
|
-
) => f<T extends `ivec${string}` ? 'int' : 'float'>('dot', x, y)
|
|
75
|
+
export const distance = <T extends 'vec2' | 'vec3' | 'vec4', U extends C>(x: X<T>, y: number | X<U>) => f<'float'>('distance', x, y)
|
|
76
|
+
export const dot = <T extends 'vec2' | 'vec3' | 'vec4' | 'ivec2' | 'ivec3' | 'ivec4', U extends C>(x: X<T>, y: number | X<U>) => f<T extends `ivec${string}` ? 'int' : 'float'>('dot', x, y)
|
|
81
77
|
export const length = <T extends 'vec2' | 'vec3' | 'vec4'>(x: X<T>) => f<'float'>('length', x)
|
|
82
78
|
export const lengthSq = (x: X) => f<'float'>('lengthSq', x)
|
|
83
79
|
export const luminance = (x: X) => f<'float'>('luminance', x)
|
|
@@ -134,24 +130,16 @@ export const trunc = <T extends C>(x: X<T>) => f<T>('trunc', x)
|
|
|
134
130
|
|
|
135
131
|
// 1. Functions where first argument determines return type with unified parameter types
|
|
136
132
|
export const atan2 = <T extends C, U extends C>(x: X<T>, y: number | X<U>) => f<T>('atan2', x, y)
|
|
137
|
-
export const clamp = <T extends C, U extends C>(x: X<T>, min: number | X<U>, max: number | X<U>) =>
|
|
138
|
-
f<T>('clamp', x, min, max)
|
|
133
|
+
export const clamp = <T extends C, U extends C>(x: X<T>, min: number | X<U>, max: number | X<U>) => f<T>('clamp', x, min, max)
|
|
139
134
|
export const max = <T extends C, U extends C>(x: X<T>, y: number | X<U>) => f<T>('max', x, y)
|
|
140
135
|
export const min = <T extends C, U extends C>(x: X<T>, y: number | X<U>) => f<T>('min', x, y)
|
|
141
|
-
export const mix = <T extends C, U extends C>(x: X<T>, y: number | X<U>, a: number | Float | X<U>) =>
|
|
142
|
-
f<T>('mix', x, y, a)
|
|
136
|
+
export const mix = <T extends C, U extends C>(x: X<T>, y: number | X<U>, a: number | Float | X<U>) => f<T>('mix', x, y, a)
|
|
143
137
|
export const pow = <T extends C, U extends C>(x: X<T>, y: number | X<U>) => f<T>('pow', x, y)
|
|
144
|
-
export const reflect = <T extends 'vec2' | 'vec3' | 'vec4', U extends C>(I: X<T>, N: number | X<U>) =>
|
|
145
|
-
|
|
146
|
-
export const refract = <T extends 'vec2' | 'vec3' | 'vec4', U extends C>(
|
|
147
|
-
I: X<T>,
|
|
148
|
-
N: number | X<U>,
|
|
149
|
-
eta: number | Float
|
|
150
|
-
) => f<T>('refract', I, N, eta)
|
|
138
|
+
export const reflect = <T extends 'vec2' | 'vec3' | 'vec4', U extends C>(I: X<T>, N: number | X<U>) => f<T>('reflect', I, N)
|
|
139
|
+
export const refract = <T extends 'vec2' | 'vec3' | 'vec4', U extends C>(I: X<T>, N: number | X<U>, eta: number | Float) => f<T>('refract', I, N, eta)
|
|
151
140
|
|
|
152
141
|
// 2. Functions where not first argument determines return type with unified parameter types
|
|
153
|
-
export const smoothstep = <T extends C, U extends C>(e0: number | X<U>, e1: number | X<U>, x: X<T>) =>
|
|
154
|
-
f<T>('smoothstep', e0, e1, x)
|
|
142
|
+
export const smoothstep = <T extends C, U extends C>(e0: number | X<U>, e1: number | X<U>, x: X<T>) => f<T>('smoothstep', e0, e1, x)
|
|
155
143
|
export const step = <T extends C, U extends C>(edge: number | X<U>, x: X<T>) => f<T>('step', edge, x)
|
|
156
144
|
export const mod = <T extends C, U extends C>(x: X<T>, y: number | X<U>) => {
|
|
157
145
|
return (x as any).sub((x as any).div(y).floor().mul(y)) as X<T>
|
package/src/node/types.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CONSTANTS, CONVERSIONS, FUNCTIONS, OPERATOR_KEYS, OPERATOR_TYPE_RULES } from './utils/const'
|
|
2
2
|
import type { GL } from '../types'
|
|
3
|
+
import type { Binding } from '../webgpu/utils'
|
|
3
4
|
|
|
4
5
|
export type Constants = (typeof CONSTANTS)[number] | 'void'
|
|
5
6
|
export type Conversions = (typeof CONVERSIONS)[number]
|
|
@@ -80,6 +81,7 @@ export interface NodeProps {
|
|
|
80
81
|
|
|
81
82
|
export interface NodeContext {
|
|
82
83
|
gl?: Partial<GL>
|
|
84
|
+
binding?: Binding
|
|
83
85
|
label?: 'vert' | 'frag' | 'compute'
|
|
84
86
|
isWebGL?: boolean
|
|
85
87
|
units?: any // @TODO FIX
|
|
@@ -90,7 +92,7 @@ export interface NodeContext {
|
|
|
90
92
|
fragInputs: Map<string, string>
|
|
91
93
|
vertInputs: Map<string, string>
|
|
92
94
|
vertOutputs: Map<string, string>
|
|
93
|
-
vertVaryings: Map<string,
|
|
95
|
+
vertVaryings: Map<string, VaryingInfo>
|
|
94
96
|
computeInputs: Map<string, string>
|
|
95
97
|
dependencies: Map<string, Set<string>>
|
|
96
98
|
structStructFields: Map<string, StructFields>
|
|
@@ -202,6 +204,12 @@ export type Mat4 = XImpl<'mat4'>
|
|
|
202
204
|
export type Texture = XImpl<'texture'>
|
|
203
205
|
export type Sampler2D = XImpl<'sampler2D'>
|
|
204
206
|
export type StructBase = XImpl<'struct'>
|
|
207
|
+
|
|
208
|
+
export interface VaryingInfo {
|
|
209
|
+
node: Y
|
|
210
|
+
code?: string
|
|
211
|
+
}
|
|
212
|
+
|
|
205
213
|
export type Struct<T extends StructFields = any> = Omit<StructBase, keyof T> & {
|
|
206
214
|
[K in keyof T]: T[K] extends X<infer U> ? X<U> : never
|
|
207
215
|
} & {
|
package/src/node/utils/index.ts
CHANGED
|
@@ -1,24 +1,7 @@
|
|
|
1
1
|
import { infer } from './infer'
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
parseConstantHead,
|
|
6
|
-
parseDeclare,
|
|
7
|
-
parseDefine,
|
|
8
|
-
parseGather,
|
|
9
|
-
parseIf,
|
|
10
|
-
parseLoop,
|
|
11
|
-
parseScatter,
|
|
12
|
-
parseStorageHead,
|
|
13
|
-
parseStruct,
|
|
14
|
-
parseStructHead,
|
|
15
|
-
parseSwitch,
|
|
16
|
-
parseTexture,
|
|
17
|
-
parseUniformHead,
|
|
18
|
-
parseVaryingHead,
|
|
19
|
-
} from './parse'
|
|
20
|
-
import { getBluiltin, getConversions, getOperator, initNodeContext, isElement, isX, setupEvent } from './utils'
|
|
21
|
-
import { is } from '../../utils/helpers'
|
|
2
|
+
import { parseArray, parseAttribHead, parseConstantHead, parseDeclare, parseDefine, parseGather, parseIf, parseLoop, parseScatter, parseStorageHead, parseStruct, parseStructHead, parseSwitch, parseTexture, parseUniformHead, parseVaryingHead } from './parse'
|
|
3
|
+
import { getBluiltin, getConversions, getOperator, initNodeContext, isX, setupEvent } from './utils'
|
|
4
|
+
import { is } from '../../helpers'
|
|
22
5
|
import { mod } from '..'
|
|
23
6
|
import type { Constants as C, NodeContext, Y } from '../types'
|
|
24
7
|
|
|
@@ -58,10 +41,7 @@ export const code = <T extends C>(target: Y<T>, c?: NodeContext | null): string
|
|
|
58
41
|
? parseScatter(c, storageNode, y) // indexNode is not using
|
|
59
42
|
: `${code(storageNode, c)}[${code(indexNode, c)}] = ${code(y, c)};`
|
|
60
43
|
}
|
|
61
|
-
if (type === 'ternary')
|
|
62
|
-
return c.isWebGL
|
|
63
|
-
? `(${code(z, c)} ? ${code(x, c)} : ${code(y, c)})`
|
|
64
|
-
: `select(${code(x, c)}, ${code(y, c)}, ${code(z, c)})`
|
|
44
|
+
if (type === 'ternary') return c.isWebGL ? `(${code(z, c)} ? ${code(x, c)} : ${code(y, c)})` : `select(${code(x, c)}, ${code(y, c)}, ${code(z, c)})`
|
|
65
45
|
if (type === 'conversion') return `${getConversions(x, c)}(${parseArray(children.slice(1), c)})`
|
|
66
46
|
if (type === 'operator') {
|
|
67
47
|
if (x === 'not' || x === 'bitNot') return `!${code(y, c)}`
|
|
@@ -110,7 +90,7 @@ export const code = <T extends C>(target: Y<T>, c?: NodeContext | null): string
|
|
|
110
90
|
const field = parseVaryingHead(c, id, infer(target, c))
|
|
111
91
|
c.code?.fragInputs.set(id, field)
|
|
112
92
|
c.code?.vertOutputs.set(id, field)
|
|
113
|
-
c.code?.vertVaryings.set(id,
|
|
93
|
+
c.code?.vertVaryings.set(id, { node: x })
|
|
114
94
|
return c.isWebGL ? `${id}` : `out.${id}`
|
|
115
95
|
}
|
|
116
96
|
if (type === 'builtin') {
|
package/src/node/utils/infer.ts
CHANGED
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
import { isConstants, isElement, isX, isSwizzle } from './utils'
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
COMPONENT_COUNT_TO_TYPE,
|
|
5
|
-
FUNCTION_RETURN_TYPES,
|
|
6
|
-
getOperatorResultType,
|
|
7
|
-
validateOperatorTypes,
|
|
8
|
-
} from './const'
|
|
9
|
-
import { is, getStride } from '../../utils/helpers'
|
|
2
|
+
import { BUILTIN_TYPES, COMPONENT_COUNT_TO_TYPE, FUNCTION_RETURN_TYPES, getOperatorResultType, validateOperatorTypes } from './const'
|
|
3
|
+
import { is, getStride } from '../../helpers'
|
|
10
4
|
import type { Constants as C, NodeContext, X, Y } from '../types'
|
|
11
5
|
|
|
12
6
|
const inferBuiltin = <T extends C>(id: string | undefined) => {
|
|
@@ -14,8 +8,7 @@ const inferBuiltin = <T extends C>(id: string | undefined) => {
|
|
|
14
8
|
}
|
|
15
9
|
|
|
16
10
|
const inferOperator = <T extends C>(L: T, R: T, op: string): T => {
|
|
17
|
-
if (!validateOperatorTypes(L, R, op))
|
|
18
|
-
console.warn(`GLRE Type Warning: Invalid operator '${op}' between types '${L}' and '${R}'`)
|
|
11
|
+
if (!validateOperatorTypes(L, R, op)) console.warn(`GLRE Type Warning: Invalid operator '${op}' between types '${L}' and '${R}'`)
|
|
19
12
|
return getOperatorResultType(L, R, op) as T
|
|
20
13
|
}
|
|
21
14
|
|
|
@@ -30,8 +23,7 @@ export const inferPrimitiveType = <T extends C>(x: Y<T>) => {
|
|
|
30
23
|
|
|
31
24
|
const inferFromCount = <T extends C>(count: number) => {
|
|
32
25
|
const ret = COMPONENT_COUNT_TO_TYPE[count as keyof typeof COMPONENT_COUNT_TO_TYPE] as T
|
|
33
|
-
if (!ret)
|
|
34
|
-
throw `glre node system error: Cannot infer type from array length ${count}. Check your data size. Supported: 1(float), 2(vec2), 3(vec3), 4(vec4), 9(mat3), 16(mat4)`
|
|
26
|
+
if (!ret) throw `glre node system error: Cannot infer type from array length ${count}. Check your data size. Supported: 1(float), 2(vec2), 3(vec3), 4(vec4), 9(mat3), 16(mat4)`
|
|
35
27
|
return ret
|
|
36
28
|
}
|
|
37
29
|
|
package/src/node/utils/parse.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { code } from '.'
|
|
2
2
|
import { infer } from './infer'
|
|
3
3
|
import { getConversions, addDependency } from './utils'
|
|
4
|
-
import { is } from '../../
|
|
4
|
+
import { is } from '../../helpers'
|
|
5
5
|
import type { Constants, NodeContext, NodeProps, StructFields, Y } from '../types'
|
|
6
|
-
import { storageSize } from '../../utils
|
|
6
|
+
import { storageSize } from '../../webgl/utils'
|
|
7
7
|
|
|
8
8
|
export const parseArray = (children: Y[], c: NodeContext) => {
|
|
9
9
|
return children
|
|
@@ -60,9 +60,7 @@ export const parseIf = (c: NodeContext, x: Y, y: Y, children: Y[]) => {
|
|
|
60
60
|
let ret = `if (${code(x, c)}) {\n${code(y, c)}\n}`
|
|
61
61
|
for (let i = 2; i < children.length; i += 2) {
|
|
62
62
|
const isElse = i >= children.length - 1
|
|
63
|
-
ret += !isElse
|
|
64
|
-
? ` else if (${code(children[i], c)}) {\n${code(children[i + 1], c)}\n}`
|
|
65
|
-
: ` else {\n${code(children[i], c)}\n}`
|
|
63
|
+
ret += !isElse ? ` else if (${code(children[i], c)}) {\n${code(children[i + 1], c)}\n}` : ` else {\n${code(children[i], c)}\n}`
|
|
66
64
|
}
|
|
67
65
|
return ret
|
|
68
66
|
}
|
|
@@ -73,8 +71,7 @@ export const parseSwitch = (c: NodeContext, x: Y, children: Y[]) => {
|
|
|
73
71
|
const isDefault = i >= children.length - 1
|
|
74
72
|
if (isDefault && children.length % 2 === 0) {
|
|
75
73
|
ret += `default:\n${code(children[i], c)}\nbreak;\n`
|
|
76
|
-
} else if (i + 1 < children.length)
|
|
77
|
-
ret += `case ${code(children[i], c)}:\n${code(children[i + 1], c)}\nbreak;\n`
|
|
74
|
+
} else if (i + 1 < children.length) ret += `case ${code(children[i], c)}:\n${code(children[i + 1], c)}\nbreak;\n`
|
|
78
75
|
}
|
|
79
76
|
ret += '}'
|
|
80
77
|
return ret
|
|
@@ -157,14 +154,12 @@ export const parseDefine = (c: NodeContext, props: NodeProps, target: Y) => {
|
|
|
157
154
|
* headers
|
|
158
155
|
*/
|
|
159
156
|
export const parseVaryingHead = (c: NodeContext, id: string, type: Constants) => {
|
|
160
|
-
return c.isWebGL
|
|
161
|
-
? `${type} ${id};`
|
|
162
|
-
: `@location(${c.code?.vertVaryings?.size || 0}) ${id}: ${getConversions(type, c)}`
|
|
157
|
+
return c.isWebGL ? `${type} ${id};` : `@location(${c.code?.vertVaryings?.size || 0}) ${id}: ${getConversions(type, c)}`
|
|
163
158
|
}
|
|
164
159
|
|
|
165
160
|
export const parseAttribHead = (c: NodeContext, id: string, type: Constants) => {
|
|
166
161
|
if (c.isWebGL) return `${type} ${id};`
|
|
167
|
-
const { location = 0 } = c.
|
|
162
|
+
const { location = 0 } = c.binding?.attrib(id) || {}
|
|
168
163
|
const wgslType = getConversions(type, c)
|
|
169
164
|
return `@location(${location}) ${id}: ${wgslType}`
|
|
170
165
|
}
|
|
@@ -176,13 +171,10 @@ export const parseUniformHead = (c: NodeContext, id: string, type: Constants) =>
|
|
|
176
171
|
? `uniform sampler2D ${id};`
|
|
177
172
|
: `uniform ${type} ${id};`
|
|
178
173
|
if (isTexture) {
|
|
179
|
-
const { group = 1, binding = 0 } = c.
|
|
180
|
-
return (
|
|
181
|
-
`@group(${group}) @binding(${binding}) var ${id}Sampler: sampler;\n` +
|
|
182
|
-
`@group(${group}) @binding(${binding + 1}) var ${id}: texture_2d<f32>;`
|
|
183
|
-
)
|
|
174
|
+
const { group = 1, binding = 0 } = c.binding?.texture(id) || {}
|
|
175
|
+
return `@group(${group}) @binding(${binding}) var ${id}Sampler: sampler;\n` + `@group(${group}) @binding(${binding + 1}) var ${id}: texture_2d<f32>;`
|
|
184
176
|
}
|
|
185
|
-
const { group = 0, binding = 0 } = c.
|
|
177
|
+
const { group = 0, binding = 0 } = c.binding?.uniform(id) || {}
|
|
186
178
|
const wgslType = getConversions(type, c)
|
|
187
179
|
return `@group(${group}) @binding(${binding}) var<uniform> ${id}: ${wgslType};`
|
|
188
180
|
}
|
|
@@ -194,7 +186,7 @@ export const parseStorageHead = (c: NodeContext, id: string, type: Constants) =>
|
|
|
194
186
|
const location = c.units?.(id)
|
|
195
187
|
return `${ret}\nlayout(location = ${location}) out vec4 _${id};` // out texture buffer
|
|
196
188
|
}
|
|
197
|
-
const { group = 0, binding = 0 } = c.
|
|
189
|
+
const { group = 0, binding = 0 } = c.binding?.storage(id) || {}
|
|
198
190
|
const wgslType = getConversions(type, c)
|
|
199
191
|
return `@group(${group}) @binding(${binding}) var<storage, read_write> ${id}: array<${wgslType}>;`
|
|
200
192
|
}
|
|
@@ -204,24 +196,16 @@ export const parseLoop = (c: NodeContext, x: Y, y: Y, id: string) => {
|
|
|
204
196
|
const bodyCode = code(y, c)
|
|
205
197
|
const conditionCode = code(x, c)
|
|
206
198
|
if (c.isWebGL) {
|
|
207
|
-
if (conditionType === 'int')
|
|
208
|
-
|
|
209
|
-
if (conditionType === '
|
|
210
|
-
|
|
211
|
-
if (conditionType === 'vec2')
|
|
212
|
-
return `for (vec2 ${id} = vec2(0.0); ${id}.x < ${conditionCode}.x && ${id}.y < ${conditionCode}.y; ${id} += vec2(1.0)) {\n${bodyCode}\n}`
|
|
213
|
-
if (conditionType === 'vec3')
|
|
214
|
-
return `for (vec3 ${id} = vec3(0.0); ${id}.x < ${conditionCode}.x && ${id}.y < ${conditionCode}.y && ${id}.z < ${conditionCode}.z; ${id} += vec3(1.0)) {\n${bodyCode}\n}`
|
|
199
|
+
if (conditionType === 'int') return `for (int ${id} = 0; ${id} < ${conditionCode}; ${id} += 1) {\n${bodyCode}\n}`
|
|
200
|
+
if (conditionType === 'float') return `for (float ${id} = 0.0; ${id} < ${conditionCode}; ${id} += 1.0) {\n${bodyCode}\n}`
|
|
201
|
+
if (conditionType === 'vec2') return `for (vec2 ${id} = vec2(0.0); ${id}.x < ${conditionCode}.x && ${id}.y < ${conditionCode}.y; ${id} += vec2(1.0)) {\n${bodyCode}\n}`
|
|
202
|
+
if (conditionType === 'vec3') return `for (vec3 ${id} = vec3(0.0); ${id}.x < ${conditionCode}.x && ${id}.y < ${conditionCode}.y && ${id}.z < ${conditionCode}.z; ${id} += vec3(1.0)) {\n${bodyCode}\n}`
|
|
215
203
|
return `for (int ${id} = 0; ${id} < ${conditionCode}; ${id} += 1) {\n${bodyCode}\n}`
|
|
216
204
|
}
|
|
217
|
-
if (conditionType === 'int')
|
|
218
|
-
|
|
219
|
-
if (conditionType === '
|
|
220
|
-
|
|
221
|
-
if (conditionType === 'vec2')
|
|
222
|
-
return `for (var ${id}: vec2f = vec2f(0.0); ${id}.x < ${conditionCode}.x && ${id}.y < ${conditionCode}.y; ${id} += vec2f(1.0)) {\n${bodyCode}\n}`
|
|
223
|
-
if (conditionType === 'vec3')
|
|
224
|
-
return `for (var ${id}: vec3f = vec3f(0.0); ${id}.x < ${conditionCode}.x && ${id}.y < ${conditionCode}.y && ${id}.z < ${conditionCode}.z; ${id} += vec3f(1.0)) {\n${bodyCode}\n}`
|
|
205
|
+
if (conditionType === 'int') return `for (var ${id}: i32 = 0; ${id} < ${conditionCode}; ${id}++) {\n${bodyCode}\n}`
|
|
206
|
+
if (conditionType === 'float') return `for (var ${id}: f32 = 0.0; ${id} < ${conditionCode}; ${id} += 1.0) {\n${bodyCode}\n}`
|
|
207
|
+
if (conditionType === 'vec2') return `for (var ${id}: vec2f = vec2f(0.0); ${id}.x < ${conditionCode}.x && ${id}.y < ${conditionCode}.y; ${id} += vec2f(1.0)) {\n${bodyCode}\n}`
|
|
208
|
+
if (conditionType === 'vec3') return `for (var ${id}: vec3f = vec3f(0.0); ${id}.x < ${conditionCode}.x && ${id}.y < ${conditionCode}.y && ${id}.z < ${conditionCode}.z; ${id} += vec3f(1.0)) {\n${bodyCode}\n}`
|
|
225
209
|
return `for (var ${id}: i32 = 0; ${id} < ${conditionCode}; ${id}++) {\n${bodyCode}\n}`
|
|
226
210
|
}
|
|
227
211
|
|
package/src/node/utils/utils.ts
CHANGED
|
@@ -1,15 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
FUNCTIONS,
|
|
5
|
-
OPERATOR_KEYS,
|
|
6
|
-
OPERATORS,
|
|
7
|
-
TYPE_MAPPING,
|
|
8
|
-
WGSL_TO_GLSL_BUILTIN,
|
|
9
|
-
} from './const'
|
|
10
|
-
import { is } from '../../utils/helpers'
|
|
1
|
+
import { CONSTANTS, CONVERSIONS, FUNCTIONS, OPERATOR_KEYS, OPERATORS, TYPE_MAPPING, WGSL_TO_GLSL_BUILTIN } from './const'
|
|
2
|
+
import { is } from '../../helpers'
|
|
3
|
+
import { storageSize } from '../../webgl/utils'
|
|
11
4
|
import type { Constants as C, Conversions, Functions, NodeContext, Operators, Swizzles, X, Y } from '../types'
|
|
12
|
-
import { storageSize } from '../../utils/program'
|
|
13
5
|
|
|
14
6
|
export const isSwizzle = (key: unknown): key is Swizzles => {
|
|
15
7
|
return is.str(key) && /^[xyzwrgbastpq]{1,4}$/.test(key)
|
package/src/react.ts
CHANGED
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
import { useState } from 'react'
|
|
2
|
-
import { createGL
|
|
2
|
+
import { createGL } from './index'
|
|
3
3
|
import type { GL } from './types'
|
|
4
4
|
export * from './index'
|
|
5
5
|
|
|
6
|
-
export const useGL = (
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
return gl
|
|
16
|
-
})[0]
|
|
6
|
+
export const useGL = (...args: Partial<GL>[]) => {
|
|
7
|
+
const [, set] = useState(null) // for error boundary // ref: https://github.com/facebook/react/issues/14981
|
|
8
|
+
if (args[0] && !args[0].error)
|
|
9
|
+
args[0].error = (error = '') =>
|
|
10
|
+
set(() => {
|
|
11
|
+
throw new Error(error)
|
|
12
|
+
})
|
|
13
|
+
return useState(() => createGL(...args))[0]
|
|
17
14
|
}
|
package/src/solid.ts
CHANGED
|
@@ -1,14 +1,7 @@
|
|
|
1
|
-
import { createGL
|
|
1
|
+
import { createGL } from './index'
|
|
2
2
|
import type { GL } from './types'
|
|
3
3
|
export * from './index'
|
|
4
4
|
|
|
5
|
-
export const onGL = (
|
|
6
|
-
|
|
7
|
-
gl.ref = (el: HTMLCanvasElement | null) => {
|
|
8
|
-
if (el) {
|
|
9
|
-
gl.el = el
|
|
10
|
-
gl.mount()
|
|
11
|
-
} else gl.clean()
|
|
12
|
-
}
|
|
13
|
-
return gl
|
|
5
|
+
export const onGL = (...args: Partial<GL>[]) => {
|
|
6
|
+
return createGL(...args)
|
|
14
7
|
}
|