glre 0.45.0 → 0.47.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 +35 -50
- package/dist/index.cjs +6 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +37 -90
- 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 +45 -93
- 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 +35 -50
- package/dist/node.js +15 -15
- 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 +37 -91
- 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 +37 -91
- 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 +3 -19
- package/src/node/create.ts +2 -4
- package/src/node/index.ts +8 -20
- package/src/node/types.ts +2 -0
- package/src/node/utils/index.ts +5 -2
- package/src/node/utils/infer.ts +5 -13
- package/src/node/utils/parse.ts +18 -34
- package/src/node/utils/utils.ts +15 -10
- 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)
|
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
|
package/src/node/utils/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { infer } from './infer'
|
|
2
2
|
import { parseArray, parseAttribHead, parseConstantHead, parseDeclare, parseDefine, parseGather, parseIf, parseLoop, parseScatter, parseStorageHead, parseStruct, parseStructHead, parseSwitch, parseTexture, parseUniformHead, parseVaryingHead } from './parse'
|
|
3
3
|
import { getBluiltin, getConversions, getOperator, initNodeContext, isX, setupEvent } from './utils'
|
|
4
|
-
import { is } from '../../
|
|
4
|
+
import { is } from '../../helpers'
|
|
5
5
|
import { mod } from '..'
|
|
6
6
|
import type { Constants as C, NodeContext, Y } from '../types'
|
|
7
7
|
|
|
@@ -114,7 +114,10 @@ export const code = <T extends C>(target: Y<T>, c?: NodeContext | null): string
|
|
|
114
114
|
setupEvent(c, id, varType, target, x)
|
|
115
115
|
head = parseUniformHead(c, id, varType)
|
|
116
116
|
}
|
|
117
|
-
if (type === 'storage')
|
|
117
|
+
if (type === 'storage') {
|
|
118
|
+
setupEvent(c, id, type, target, x)
|
|
119
|
+
head = parseStorageHead(c, id, infer(target, c))
|
|
120
|
+
}
|
|
118
121
|
if (type === 'constant') head = parseConstantHead(c, id, infer(target, c), code(x, c))
|
|
119
122
|
if (head) {
|
|
120
123
|
c.code?.headers.set(id, head)
|
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, isFloat32 } 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
|
|
|
@@ -23,15 +16,14 @@ export const inferPrimitiveType = <T extends C>(x: Y<T>) => {
|
|
|
23
16
|
if (is.bol(x)) return 'bool' as T
|
|
24
17
|
if (is.str(x)) return 'texture' as T
|
|
25
18
|
if (is.num(x)) return 'float' as T // @TODO FIX: Number.isInteger(x) ? 'int' : 'float'
|
|
26
|
-
if (is.arr(x)) return COMPONENT_COUNT_TO_TYPE[x.length as keyof typeof COMPONENT_COUNT_TO_TYPE] as T
|
|
19
|
+
if (is.arr(x) || isFloat32(x)) return COMPONENT_COUNT_TO_TYPE[x.length as keyof typeof COMPONENT_COUNT_TO_TYPE] as T
|
|
27
20
|
if (isElement(x)) return 'texture' as T
|
|
28
21
|
return 'void' as T
|
|
29
22
|
}
|
|
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,7 +1,7 @@
|
|
|
1
1
|
import { CONSTANTS, CONVERSIONS, FUNCTIONS, OPERATOR_KEYS, OPERATORS, TYPE_MAPPING, WGSL_TO_GLSL_BUILTIN } from './const'
|
|
2
|
-
import { is } from '../../
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
2
|
+
import { is, isFloat32 } from '../../helpers'
|
|
3
|
+
import { storageSize } from '../../webgl/utils'
|
|
4
|
+
import type { Constants as C, Conversions, Functions, NodeContext, Operators, Swizzles, X, Y } from '../types'
|
|
5
5
|
|
|
6
6
|
export const isSwizzle = (key: unknown): key is Swizzles => {
|
|
7
7
|
return is.str(key) && /^[xyzwrgbastpq]{1,4}$/.test(key)
|
|
@@ -103,28 +103,33 @@ export const addDependency = (c: NodeContext, id = '', type: string) => {
|
|
|
103
103
|
*/
|
|
104
104
|
const getEventFun = (c: NodeContext, id: string, type: string) => {
|
|
105
105
|
if (c.isWebGL) {
|
|
106
|
-
if (type === 'attribute') return
|
|
107
|
-
if (type === 'instance') return
|
|
108
|
-
if (type === 'texture') return
|
|
106
|
+
if (type === 'attribute') return c.gl?.attribute?.bind(null, id as any)
|
|
107
|
+
if (type === 'instance') return c.gl?.instance?.bind(null, id as any)
|
|
108
|
+
if (type === 'texture') return c.gl?.texture?.bind(null, id as any)
|
|
109
|
+
if (type === 'storage') return c.gl?.storage?.bind(null, id as any)
|
|
109
110
|
return (value: any) => c.gl?.uniform?.(id, value)
|
|
110
111
|
}
|
|
111
|
-
if (type === 'attribute') return
|
|
112
|
-
if (type === 'instance') return
|
|
113
|
-
if (type === 'texture') return
|
|
112
|
+
if (type === 'attribute') return c.gl?._attribute?.bind(null, id)
|
|
113
|
+
if (type === 'instance') return c.gl?._instance?.bind(null, id)
|
|
114
|
+
if (type === 'texture') return c.gl?._texture?.bind(null, id)
|
|
115
|
+
if (type === 'storage') return c.gl?._storage?.bind(null, id)
|
|
114
116
|
return (value: any) => c.gl?._uniform?.(id, value)
|
|
115
117
|
}
|
|
116
118
|
|
|
117
|
-
const safeEventCall = <T extends C>(x: X<T>, fun: (value:
|
|
119
|
+
const safeEventCall = <T extends C>(x: X<T>, fun: (value: any) => void) => {
|
|
118
120
|
if (is.und(x)) return
|
|
119
121
|
if (!isX(x)) return fun(x) // for uniform(0) or uniform([0, 1])
|
|
120
122
|
if (x.type !== 'conversion') return
|
|
121
123
|
const args = x.props.children?.slice(1)
|
|
122
124
|
if (is.und(args?.[0])) return // ignore if uniform(vec2())
|
|
125
|
+
if (is.arr(args[0])) return fun(args[0]) // for attribute(vec2([0, 0.73, -1, -1, 1, -1]))
|
|
126
|
+
if (isFloat32(args[0])) return fun(args[0]) // for storage(float(new Float32Array(1024)))
|
|
123
127
|
fun(args.map((x) => x ?? args[0])) // for uniform(vec2(1)) or uniform(vec2(1, 1))
|
|
124
128
|
}
|
|
125
129
|
|
|
126
130
|
export const setupEvent = (c: NodeContext, id: string, type: string, target: X, child: X) => {
|
|
127
131
|
const fun = getEventFun(c, id, type)
|
|
132
|
+
if (!fun) return
|
|
128
133
|
safeEventCall(child, fun)
|
|
129
134
|
target.listeners.add(fun)
|
|
130
135
|
return fun
|
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
|
}
|