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.
Files changed (52) hide show
  1. package/README.md +4 -26
  2. package/dist/addons.d.ts +41 -51
  3. package/dist/index.cjs +6 -6
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.ts +43 -91
  6. package/dist/index.js +6 -6
  7. package/dist/index.js.map +1 -1
  8. package/dist/native.cjs +1 -1
  9. package/dist/native.cjs.map +1 -1
  10. package/dist/native.d.ts +51 -94
  11. package/dist/native.js +1 -1
  12. package/dist/native.js.map +1 -1
  13. package/dist/node.cjs +15 -15
  14. package/dist/node.cjs.map +1 -1
  15. package/dist/node.d.ts +41 -52
  16. package/dist/node.js +14 -14
  17. package/dist/node.js.map +1 -1
  18. package/dist/react.cjs +1 -1
  19. package/dist/react.cjs.map +1 -1
  20. package/dist/react.d.ts +43 -92
  21. package/dist/react.js +1 -1
  22. package/dist/react.js.map +1 -1
  23. package/dist/solid.cjs +1 -1
  24. package/dist/solid.cjs.map +1 -1
  25. package/dist/solid.d.ts +43 -92
  26. package/dist/solid.js +1 -1
  27. package/dist/solid.js.map +1 -1
  28. package/package.json +1 -1
  29. package/src/{utils/helpers.ts → helpers.ts} +10 -32
  30. package/src/index.ts +45 -42
  31. package/src/native.ts +6 -7
  32. package/src/node/build.ts +6 -21
  33. package/src/node/create.ts +2 -4
  34. package/src/node/index.ts +8 -20
  35. package/src/node/types.ts +9 -1
  36. package/src/node/utils/index.ts +5 -25
  37. package/src/node/utils/infer.ts +4 -12
  38. package/src/node/utils/parse.ts +18 -34
  39. package/src/node/utils/utils.ts +3 -11
  40. package/src/react.ts +9 -12
  41. package/src/solid.ts +3 -10
  42. package/src/types.ts +30 -22
  43. package/src/webgl/compute.ts +56 -0
  44. package/src/webgl/graphic.ts +65 -0
  45. package/src/webgl/index.ts +21 -0
  46. package/src/{utils/program.ts → webgl/utils.ts} +30 -8
  47. package/src/webgpu/compute.ts +39 -0
  48. package/src/webgpu/graphic.ts +89 -0
  49. package/src/webgpu/index.ts +42 -0
  50. package/src/{utils/pipeline.ts → webgpu/utils.ts} +75 -78
  51. package/src/utils/webgl.ts +0 -135
  52. 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 './utils/helpers'
4
- import { webgl } from './utils/webgl'
5
- import { webgpu } from './utils/webgpu'
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
- let iTime = performance.now()
19
+ const findElement = (arg: Partial<GL>) => {
20
+ return arg.el || arg.elem || arg.element
21
+ }
26
22
 
27
- export const createGL = (props?: Partial<GL>) => {
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
- if (!isWebGPUSupported()) gl.isWebGL = true
66
- gl.vs = gl.vs || gl.vert || gl.vertex
67
- gl.fs = gl.fs || gl.frag || gl.fragment
68
- gl.cs = gl.cs || gl.comp || gl.compute
69
- if (gl.isWebGL) {
70
- gl((await webgl(gl)) as GL)
71
- } else gl((await webgpu(gl)) as GL)
72
- if (gl.isError) return // stop if error
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 w = gl.width || window.innerWidth
95
- const h = gl.height || window.innerHeight
96
- gl.size[0] = gl.el.width = w
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 [w, h] = gl.size
103
- const { top, left } = gl.el.getBoundingClientRect()
104
- gl.mouse[0] = (x - top - w / 2) / (w / 2)
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('loop', () => {
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(props)
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' // @ts-ignore
2
- // import { Dimensions } from 'react-native'
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 = (props: Partial<GL> = {}) => {
6
+ export const useGL = (...args: Partial<GL>[]) => {
8
7
  return useState(() => {
9
- const gl = isGL(props) ? props : createGL(props)
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({ isNative: true })
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} float;`)
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?.webgl?.context, c.gl?.precision))
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, code] of c.code?.vertVaryings?.entries() || []) result.push(` ${id} = ${code};`)
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, code] of c.code?.vertVaryings?.entries() || []) result.push(` out.${id} = ${code};`)
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('}')
@@ -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 '../utils/helpers'
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 '../utils/helpers'
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
- f<'float'>('distance', x, y)
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
- f<T>('reflect', I, N)
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, 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
  } & {
@@ -1,24 +1,7 @@
1
1
  import { infer } from './infer'
2
- import {
3
- parseArray,
4
- parseAttribHead,
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, code(x, c))
93
+ c.code?.vertVaryings.set(id, { node: x })
114
94
  return c.isWebGL ? `${id}` : `out.${id}`
115
95
  }
116
96
  if (type === 'builtin') {
@@ -1,12 +1,6 @@
1
1
  import { isConstants, isElement, isX, isSwizzle } from './utils'
2
- import {
3
- BUILTIN_TYPES,
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
 
@@ -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 '../../utils/helpers'
4
+ import { is } from '../../helpers'
5
5
  import type { Constants, NodeContext, NodeProps, StructFields, Y } from '../types'
6
- import { storageSize } from '../../utils/program'
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.gl?.webgpu?.attribs.map.get(id) || {}
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.gl?.webgpu?.textures.map.get(id) || {}
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.gl?.webgpu?.uniforms.map.get(id) || {}
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.gl?.webgpu?.storages.map.get(id) || {}
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
- return `for (int ${id} = 0; ${id} < ${conditionCode}; ${id} += 1) {\n${bodyCode}\n}`
209
- if (conditionType === 'float')
210
- return `for (float ${id} = 0.0; ${id} < ${conditionCode}; ${id} += 1.0) {\n${bodyCode}\n}`
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
- return `for (var ${id}: i32 = 0; ${id} < ${conditionCode}; ${id}++) {\n${bodyCode}\n}`
219
- if (conditionType === 'float')
220
- return `for (var ${id}: f32 = 0.0; ${id} < ${conditionCode}; ${id} += 1.0) {\n${bodyCode}\n}`
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
 
@@ -1,15 +1,7 @@
1
- import {
2
- CONSTANTS,
3
- CONVERSIONS,
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, isGL } from './index'
2
+ import { createGL } from './index'
3
3
  import type { GL } from './types'
4
4
  export * from './index'
5
5
 
6
- export const useGL = (props: Partial<GL> = {}) => {
7
- return useState(() => {
8
- const gl = isGL(props) ? props : createGL(props)
9
- gl.ref = (el: HTMLCanvasElement | null) => {
10
- if (el) {
11
- gl.el = el
12
- gl.mount()
13
- } else gl.clean()
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, isGL } from './index'
1
+ import { createGL } from './index'
2
2
  import type { GL } from './types'
3
3
  export * from './index'
4
4
 
5
- export const onGL = (props?: Partial<GL>) => {
6
- const gl = isGL(props) ? props : createGL(props)
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
  }