glre 0.38.0 → 0.39.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 (49) hide show
  1. package/dist/addons.cjs +2 -0
  2. package/dist/addons.cjs.map +1 -0
  3. package/dist/addons.d.ts +457 -0
  4. package/dist/addons.js +2 -0
  5. package/dist/addons.js.map +1 -0
  6. package/dist/index.cjs +29 -41
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.d.ts +153 -307
  9. package/dist/index.js +29 -41
  10. package/dist/index.js.map +1 -1
  11. package/dist/native.cjs +1 -48
  12. package/dist/native.cjs.map +1 -1
  13. package/dist/native.d.ts +508 -8
  14. package/dist/native.js +1 -48
  15. package/dist/native.js.map +1 -1
  16. package/dist/node.cjs +40 -0
  17. package/dist/node.cjs.map +1 -0
  18. package/dist/node.d.ts +614 -0
  19. package/dist/node.js +40 -0
  20. package/dist/node.js.map +1 -0
  21. package/dist/react.cjs +1 -48
  22. package/dist/react.cjs.map +1 -1
  23. package/dist/react.d.ts +506 -4
  24. package/dist/react.js +1 -48
  25. package/dist/react.js.map +1 -1
  26. package/dist/solid.cjs +1 -48
  27. package/dist/solid.cjs.map +1 -1
  28. package/dist/solid.d.ts +506 -4
  29. package/dist/solid.js +1 -48
  30. package/dist/solid.js.map +1 -1
  31. package/package.json +56 -3
  32. package/src/addons/index.ts +6 -0
  33. package/src/index.ts +6 -22
  34. package/src/node/{core.ts → build.ts} +3 -7
  35. package/src/node/create.ts +73 -0
  36. package/src/node/index.ts +63 -47
  37. package/src/node/scope.ts +50 -47
  38. package/src/node/types.ts +207 -177
  39. package/src/node/utils/const.ts +62 -2
  40. package/src/node/utils/index.ts +6 -3
  41. package/src/node/utils/infer.ts +17 -29
  42. package/src/node/utils/parse.ts +11 -11
  43. package/src/node/utils/utils.ts +9 -9
  44. package/src/types.ts +2 -4
  45. package/src/utils/pipeline.ts +3 -3
  46. package/src/utils/program.ts +6 -1
  47. package/src/{webgl.ts → utils/webgl.ts} +24 -14
  48. package/src/{webgpu.ts → utils/webgpu.ts} +28 -7
  49. package/src/node/node.ts +0 -65
@@ -1,37 +1,25 @@
1
- import { isConstants, isNodeProxy, isSwizzle } from './utils'
1
+ import { isConstants, isX, isSwizzle } from './utils'
2
2
  import {
3
3
  BUILTIN_TYPES,
4
- COMPARISON_OPERATORS,
5
4
  COMPONENT_COUNT_TO_TYPE,
6
5
  FUNCTION_RETURN_TYPES,
7
- LOGICAL_OPERATORS,
6
+ getOperatorResultType,
7
+ validateOperatorTypes,
8
8
  } from './const'
9
9
  import { is } from '../../utils/helpers'
10
- import type { Constants as C, NodeContext, NodeProxy, X } from '../types'
10
+ import type { Constants as C, NodeContext, X, Y } from '../types'
11
11
 
12
12
  const inferBuiltin = <T extends C>(id: string | undefined) => {
13
13
  return BUILTIN_TYPES[id as keyof typeof BUILTIN_TYPES] as T
14
14
  }
15
15
 
16
- // Unified logic with types.ts InferOperator type
17
16
  const inferOperator = <T extends C>(L: T, R: T, op: string): T => {
18
- if (COMPARISON_OPERATORS.includes(op as any) || LOGICAL_OPERATORS.includes(op as any)) return 'bool' as T
19
- if (L === R) return L
20
- // broadcast
21
- if (L === 'float' || L === 'int') return R
22
- if (R === 'float' || R === 'int') return L
23
- // mat * vec → vec
24
- if (L === 'mat4' && R === 'vec4') return R
25
- if (L === 'mat3' && R === 'vec3') return R
26
- if (L === 'mat2' && R === 'vec2') return R
27
- // vec * mat → vec
28
- if (L === 'vec4' && R === 'mat4') return L
29
- if (L === 'vec3' && R === 'mat3') return L
30
- if (L === 'vec2' && R === 'mat2') return L
31
- return L
17
+ if (!validateOperatorTypes(L, R, op))
18
+ console.warn(`GLRE Type Warning: Invalid operator '${op}' between types '${L}' and '${R}'`)
19
+ return getOperatorResultType(L, R, op) as T
32
20
  }
33
21
 
34
- export const inferPrimitiveType = <T extends C>(x: X) => {
22
+ export const inferPrimitiveType = <T extends C>(x: Y<T>) => {
35
23
  if (is.bol(x)) return 'bool' as T
36
24
  if (is.str(x)) return 'texture' as T
37
25
  if (is.num(x)) return 'float' as T // @TODO FIX: Number.isInteger(x) ? 'int' : 'float'
@@ -43,7 +31,7 @@ const inferFromCount = <T extends C>(count: number) => {
43
31
  return COMPONENT_COUNT_TO_TYPE[count as keyof typeof COMPONENT_COUNT_TO_TYPE] as T
44
32
  }
45
33
 
46
- const inferFromArray = <T extends C>(arr: X<T>[], c: NodeContext) => {
34
+ const inferFromArray = <T extends C>(arr: Y<T>[], c: NodeContext) => {
47
35
  if (arr.length === 0) return 'void' as T
48
36
  const [x] = arr
49
37
  if (is.str(x)) return x as T // for struct
@@ -53,11 +41,11 @@ const inferFromArray = <T extends C>(arr: X<T>[], c: NodeContext) => {
53
41
  return ret
54
42
  }
55
43
 
56
- export const inferFunction = <T extends C>(x: X) => {
44
+ export const inferFunction = <T extends C>(x: Y) => {
57
45
  return FUNCTION_RETURN_TYPES[x as keyof typeof FUNCTION_RETURN_TYPES] as T
58
46
  }
59
47
 
60
- export const inferImpl = <T extends C>(target: NodeProxy<T>, c: NodeContext): T => {
48
+ export const inferImpl = <T extends C>(target: X<T>, c: NodeContext): T => {
61
49
  const { type, props } = target
62
50
  const { id, children = [], inferFrom, layout } = props
63
51
  const [x, y, z] = children
@@ -73,22 +61,22 @@ export const inferImpl = <T extends C>(target: NodeProxy<T>, c: NodeContext): T
73
61
  if (type === 'attribute' && is.arr(x) && c.gl?.count) return inferFromCount(x.length / c.gl.count)
74
62
  if (type === 'member') {
75
63
  if (isSwizzle(y)) return inferFromCount(y.length)
76
- if (isNodeProxy(x)) {
64
+ if (isX(x)) {
77
65
  const structType = infer(x, c)
78
- const fields = c.code?.structFields?.get(structType)
66
+ const fields = c.code?.structStructFields?.get(structType)
79
67
  if (fields && fields[y]) return infer(fields[y], c) as T
80
68
  }
81
69
  return 'float' as T
82
70
  }
83
71
  if (inferFrom) return inferFromArray(inferFrom, c)
84
- return infer(x, c) // for uniform and storage gather and scatter
72
+ return x ? infer(x, c) : ('void' as T) // for uniform and storage gather and scatter
85
73
  }
86
74
 
87
- export const infer = <T extends C>(target: X<T>, c?: NodeContext | null): T => {
75
+ export const infer = <T extends C>(target: Y<T>, c?: NodeContext | null): T => {
88
76
  if (!c) c = {}
89
- if (!isNodeProxy(target)) return inferPrimitiveType(target)
77
+ if (!isX(target)) return inferPrimitiveType(target)
90
78
  if (is.arr(target)) return inferFromCount(target.length)
91
- if (!c.infers) c.infers = new WeakMap<NodeProxy<T>, C>()
79
+ if (!c.infers) c.infers = new WeakMap<X<T>, C>()
92
80
  if (c.infers.has(target)) return c.infers.get(target) as T
93
81
  const ret = inferImpl(target, c)
94
82
  c.infers.set(target, ret)
@@ -2,9 +2,9 @@ import { code } from '.'
2
2
  import { infer } from './infer'
3
3
  import { getConversions, addDependency } from './utils'
4
4
  import { is } from '../../utils/helpers'
5
- import type { Constants, NodeContext, NodeProps, NodeProxy, StructFields, X } from '../types'
5
+ import type { Constants, NodeContext, NodeProps, StructFields, Y } from '../types'
6
6
 
7
- export const parseArray = (children: X[], c: NodeContext) => {
7
+ export const parseArray = (children: Y[], c: NodeContext) => {
8
8
  return children
9
9
  .filter((x) => !is.und(x) && !is.nul(x))
10
10
  .map((x) => code(x, c))
@@ -12,7 +12,7 @@ export const parseArray = (children: X[], c: NodeContext) => {
12
12
  }
13
13
 
14
14
  // only for webgl
15
- export const parseGather = (c: NodeContext, x: X, y: X, target: X) => {
15
+ export const parseGather = (c: NodeContext, x: Y, y: Y, target: Y) => {
16
16
  const parseSwizzle = () => {
17
17
  const valueType = infer(target, c)
18
18
  if (valueType === 'float') return '.x'
@@ -29,7 +29,7 @@ export const parseGather = (c: NodeContext, x: X, y: X, target: X) => {
29
29
  }
30
30
 
31
31
  // only for webgl
32
- export const parseScatter = (c: NodeContext, storageNode: X, valueNode: X) => {
32
+ export const parseScatter = (c: NodeContext, storageNode: Y, valueNode: Y) => {
33
33
  const storageId = code(storageNode, c)
34
34
  const valueCode = code(valueNode, c)
35
35
  const valueType = infer(valueNode, c)
@@ -40,7 +40,7 @@ export const parseScatter = (c: NodeContext, storageNode: X, valueNode: X) => {
40
40
  throw new Error(`Unsupported storage scatter type: ${valueType}`)
41
41
  }
42
42
 
43
- export const parseTexture = (c: NodeContext, y: X, z: X, w: X) => {
43
+ export const parseTexture = (c: NodeContext, y: Y, z: Y, w: Y) => {
44
44
  if (c.isWebGL) {
45
45
  const args = w ? [y, z, w] : [y, z]
46
46
  return `texture(${parseArray(args, c)})`
@@ -55,7 +55,7 @@ export const parseTexture = (c: NodeContext, y: X, z: X, w: X) => {
55
55
  /**
56
56
  * scopes
57
57
  */
58
- export const parseIf = (c: NodeContext, x: X, y: X, children: X[]) => {
58
+ export const parseIf = (c: NodeContext, x: Y, y: Y, children: Y[]) => {
59
59
  let ret = `if (${code(x, c)}) {\n${code(y, c)}\n}`
60
60
  for (let i = 2; i < children.length; i += 2) {
61
61
  const isElse = i >= children.length - 1
@@ -66,7 +66,7 @@ export const parseIf = (c: NodeContext, x: X, y: X, children: X[]) => {
66
66
  return ret
67
67
  }
68
68
 
69
- export const parseSwitch = (c: NodeContext, x: X, children: X[]) => {
69
+ export const parseSwitch = (c: NodeContext, x: Y, children: Y[]) => {
70
70
  let ret = `switch (${code(x, c)}) {\n`
71
71
  for (let i = 1; i < children.length; i += 2) {
72
72
  const isDefault = i >= children.length - 1
@@ -79,7 +79,7 @@ export const parseSwitch = (c: NodeContext, x: X, children: X[]) => {
79
79
  return ret
80
80
  }
81
81
 
82
- export const parseDeclare = (c: NodeContext, x: X, y: X) => {
82
+ export const parseDeclare = (c: NodeContext, x: Y, y: Y) => {
83
83
  const type = infer(x, c)
84
84
  const varName = (y as any)?.props?.id
85
85
  if (c.isWebGL) return `${type} ${varName} = ${code(x, c)};`
@@ -88,7 +88,7 @@ export const parseDeclare = (c: NodeContext, x: X, y: X) => {
88
88
  }
89
89
 
90
90
  export const parseStructHead = (c: NodeContext, id: string, fields: StructFields = {}) => {
91
- c.code?.structFields?.set(id, fields)
91
+ c.code?.structStructFields?.set(id, fields)
92
92
  const lines: string[] = []
93
93
  for (const key in fields) {
94
94
  const fieldType = fields[key]
@@ -101,7 +101,7 @@ export const parseStructHead = (c: NodeContext, id: string, fields: StructFields
101
101
  }
102
102
 
103
103
  export const parseStruct = (c: NodeContext, id: string, instanceId = '', initialValues?: StructFields) => {
104
- const fields = c.code?.structFields?.get(id) || {}
104
+ const fields = c.code?.structStructFields?.get(id) || {}
105
105
  if (c.isWebGL) {
106
106
  if (initialValues) {
107
107
  const ordered = []
@@ -120,7 +120,7 @@ export const parseStruct = (c: NodeContext, id: string, instanceId = '', initial
120
120
  /**
121
121
  * define
122
122
  */
123
- export const parseDefine = (c: NodeContext, props: NodeProps, target: NodeProxy) => {
123
+ export const parseDefine = (c: NodeContext, props: NodeProps, target: Y) => {
124
124
  const { id, children = [], layout } = props
125
125
  const [x, ...args] = children
126
126
  const argParams: [name: string, type: string][] = []
@@ -8,7 +8,7 @@ import {
8
8
  WGSL_TO_GLSL_BUILTIN,
9
9
  } from './const'
10
10
  import { is } from '../../utils/helpers'
11
- import type { Constants, Conversions, Functions, NodeContext, NodeProxy, Operators, Swizzles, X } from '../types'
11
+ import type { Constants as C, Conversions, Functions, NodeContext, Operators, Swizzles, X, Y } from '../types'
12
12
 
13
13
  export const isSwizzle = (key: unknown): key is Swizzles => {
14
14
  return is.str(key) && /^[xyzwrgbastpq]{1,4}$/.test(key)
@@ -26,13 +26,13 @@ export const isConversion = (key: unknown): key is Conversions => {
26
26
  return CONVERSIONS.includes(key as Conversions)
27
27
  }
28
28
 
29
- export const isNodeProxy = <T extends Constants>(x: unknown): x is NodeProxy<T> => {
29
+ export const isX = (x: unknown): x is X => {
30
30
  if (!x) return false
31
31
  if (typeof x !== 'object') return false // @ts-ignore
32
32
  return x.isProxy
33
33
  }
34
34
 
35
- export const isConstants = (type?: unknown): type is Constants => {
35
+ export const isConstants = (type?: unknown): type is C => {
36
36
  if (!is.str(type)) return false
37
37
  return CONSTANTS.includes(type as any)
38
38
  }
@@ -58,17 +58,17 @@ export const getBluiltin = (c: NodeContext, id: string) => {
58
58
  return ret
59
59
  }
60
60
 
61
- export const getConversions = <T extends Constants>(x: X<T>, c?: NodeContext) => {
61
+ export const getConversions = <T extends C>(x: T, c?: NodeContext) => {
62
62
  if (!is.str(x)) return ''
63
63
  if (c?.isWebGL) return x
64
64
  return TYPE_MAPPING[x as keyof typeof TYPE_MAPPING] || x // for struct type
65
65
  }
66
66
 
67
- export const getOperator = (op: X) => {
67
+ export const getOperator = (op: Y) => {
68
68
  return OPERATORS[op as keyof typeof OPERATORS] || op
69
69
  }
70
70
 
71
- export const getConstant = (conversionKey: string): Constants => {
71
+ export const getConstant = (conversionKey: string): C => {
72
72
  const index = CONVERSIONS.indexOf(conversionKey as Conversions)
73
73
  return index !== -1 ? CONSTANTS[index] : 'float'
74
74
  }
@@ -84,9 +84,9 @@ export const getEventFun = (c: NodeContext, id: string, isAttribute = false, isT
84
84
  return (value: any) => c.gl?._uniform?.(id, value)
85
85
  }
86
86
 
87
- export const safeEventCall = <T extends Constants>(x: X<T>, fun: (value: unknown) => void) => {
87
+ export const safeEventCall = <T extends C>(x: X<T>, fun: (value: unknown) => void) => {
88
88
  if (is.und(x)) return
89
- if (!isNodeProxy(x)) return fun(x) // for uniform(0) or uniform([0, 1])
89
+ if (!isX(x)) return fun(x) // for uniform(0) or uniform([0, 1])
90
90
  if (x.type !== 'conversion') return
91
91
  const args = x.props.children?.slice(1)
92
92
  if (is.und(args?.[0])) return // ignore if uniform(vec2())
@@ -103,7 +103,7 @@ export const initNodeContext = (c: NodeContext) => {
103
103
  vertVaryings: new Map(),
104
104
  computeInputs: new Map(),
105
105
  dependencies: new Map(),
106
- structFields: new Map(),
106
+ structStructFields: new Map(),
107
107
  }
108
108
  if (c.isWebGL) return c
109
109
  c.code.fragInputs.set('position', '@builtin(position) position: vec4f')
package/src/types.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import type { EventState, Nested } from 'reev'
2
- import type { Fun, Queue, Frame } from 'refr'
3
- import type { NodeProxy, Vec4, Void } from './node'
4
- export type { Fun, Queue, Frame }
2
+ import type { Queue, Frame } from 'refr'
3
+ import type { Vec4, Void } from './node'
5
4
 
6
5
  export type GL = EventState<{
7
6
  /**
@@ -55,7 +54,6 @@ export type GL = EventState<{
55
54
  */
56
55
  _uniform?(key: string, value: Uniform, isMatrix?: boolean): GL
57
56
  uniform(key: string, value: Uniform, isMatrix?: boolean): GL
58
- uniform(node: NodeProxy): GL
59
57
  uniform(target: { [key: string]: Uniform }): GL
60
58
  _texture?(key: string, value: string): GL
61
59
  texture(key: string, value: string): GL
@@ -118,12 +118,12 @@ export const createPipeline = (
118
118
  ) => {
119
119
  return device.createRenderPipeline({
120
120
  vertex: {
121
- module: device.createShaderModule({ label: 'vert', code: vs }),
121
+ module: device.createShaderModule({ label: 'vert', code: vs.trim() }),
122
122
  entryPoint: 'main',
123
123
  buffers: bufferLayouts,
124
124
  },
125
125
  fragment: {
126
- module: device.createShaderModule({ label: 'frag', code: fs }),
126
+ module: device.createShaderModule({ label: 'frag', code: fs.trim() }),
127
127
  entryPoint: 'main',
128
128
  targets: [{ format }],
129
129
  },
@@ -140,7 +140,7 @@ export const createPipeline = (
140
140
  export const createComputePipeline = (device: GPUDevice, bindGroupLayouts: GPUBindGroupLayout[], cs: string) => {
141
141
  return device.createComputePipeline({
142
142
  compute: {
143
- module: device.createShaderModule({ label: 'compute', code: cs }),
143
+ module: device.createShaderModule({ label: 'compute', code: cs.trim() }),
144
144
  entryPoint: 'main',
145
145
  },
146
146
  layout: device.createPipelineLayout({ bindGroupLayouts }),
@@ -72,7 +72,12 @@ export const createUniform = (c: WebGLRenderingContext, loc: WebGLUniformLocatio
72
72
  c[`uniformMatrix${l as 2}fv`](loc, false, value)
73
73
  }
74
74
 
75
- export const createTexture = (c: WebGLRenderingContext, img: HTMLImageElement, loc: any, unit: number) => {
75
+ export const createTexture = (
76
+ c: WebGLRenderingContext,
77
+ img: HTMLImageElement,
78
+ loc: WebGLUniformLocation,
79
+ unit: number
80
+ ) => {
76
81
  const texture = c.createTexture()
77
82
  c.bindTexture(c.TEXTURE_2D, texture)
78
83
  c.texImage2D(c.TEXTURE_2D, 0, c.RGBA, c.RGBA, c.UNSIGNED_BYTE, img)
@@ -1,5 +1,5 @@
1
1
  import { nested as cached } from 'reev'
2
- import { loadingImage } from './utils/helpers'
2
+ import { is, loadingImage } from './helpers'
3
3
  import {
4
4
  cleanStorage,
5
5
  createAttachment,
@@ -8,17 +8,26 @@ import {
8
8
  createStorage,
9
9
  createTexture,
10
10
  createUniform,
11
- } from './utils/program'
12
- import { compute, fragment, vertex } from './node'
13
- import type { GL, WebGLState } from './types'
11
+ } from './program'
12
+ import type { GL, WebGLState } from '../types'
14
13
 
15
- const vert = /* cpp */ `
14
+ const DEFAULT_FRAGMENT = /* cpp */ `
16
15
  #version 300 es
16
+ precision mediump float;
17
+ out vec4 fragColor;
18
+ uniform vec2 iResolution;
17
19
  void main() {
18
- float x = float(gl_VertexID % 2) * 4.0 - 1.0;
19
- float y = float(gl_VertexID / 2) * 4.0 - 1.0;
20
- gl_Position = vec4(x, y, 0.0, 1.0);
21
- }`.trim()
20
+ fragColor = vec4(fract((gl_FragCoord.xy / iResolution)), 0.0, 1.0);
21
+ }
22
+ `
23
+
24
+ const DEFAULT_VERTEX = /* cpp */ `
25
+ #version 300 es
26
+ void main() {
27
+ float x = float(gl_VertexID % 2) * 4.0 - 1.0;
28
+ float y = float(gl_VertexID / 2) * 4.0 - 1.0;
29
+ gl_Position = vec4(x, y, 0.0, 1.0);
30
+ }`
22
31
 
23
32
  const computeProgram = (gl: GL, c: WebGL2RenderingContext) => {
24
33
  if (!gl.cs) return null // ignore if no compute shader
@@ -28,9 +37,8 @@ const computeProgram = (gl: GL, c: WebGL2RenderingContext) => {
28
37
  let currentNum = 0 // for storage buffers
29
38
 
30
39
  const units = cached(() => activeUnit++)
31
- const config = { isWebGL: true, gl, units }
32
-
33
- const pg = createProgram(c, compute(gl.cs, config), vert, gl)!
40
+ const cs = is.str(gl.cs) ? gl.cs : gl.cs!.compute({ isWebGL: true, gl, units })
41
+ const pg = createProgram(c, cs, DEFAULT_VERTEX, gl)!
34
42
  const size = Math.ceil(Math.sqrt(gl.particles))
35
43
 
36
44
  const uniforms = cached((key) => c.getUniformLocation(pg, key)!)
@@ -75,7 +83,9 @@ export const webgl = async (gl: GL) => {
75
83
  const config = { isWebGL: true, gl }
76
84
  const c = gl.el!.getContext('webgl2')!
77
85
  const cp = computeProgram(gl, c)
78
- const pg = createProgram(c, fragment(gl.fs, config), vertex(gl.vs, config), gl)!
86
+ const fs = gl.fs ? (is.str(gl.fs) ? gl.fs : gl.fs!.fragment(config)) : DEFAULT_FRAGMENT
87
+ const vs = gl.vs ? (is.str(gl.vs) ? gl.vs : gl.vs!.vertex(config)) : DEFAULT_VERTEX
88
+ const pg = createProgram(c, fs, vs, gl)!
79
89
  c.useProgram(pg)
80
90
 
81
91
  let activeUnit = 0 // for texture units
@@ -98,7 +108,7 @@ export const webgl = async (gl: GL) => {
98
108
  const _texture = (key: string, src: string) => {
99
109
  c.useProgram(pg)
100
110
  loadingImage(gl, src, (source) => {
101
- createTexture(c, source, uniforms(key), units(key))
111
+ createTexture(c, source, uniforms(key)!, units(key))
102
112
  })
103
113
  }
104
114
 
@@ -1,5 +1,5 @@
1
1
  import { nested as cached } from 'reev'
2
- import { is, loadingImage } from './utils/helpers'
2
+ import { is, loadingImage } from './helpers'
3
3
  import {
4
4
  createArrayBuffer,
5
5
  createBindGroup,
@@ -11,12 +11,33 @@ import {
11
11
  createPipeline,
12
12
  createTextureSampler,
13
13
  createVertexBuffers,
14
- } from './utils/pipeline'
15
- import type { GL, WebGPUState } from './types'
16
- import { compute, fragment, vertex } from './node'
14
+ } from './pipeline'
15
+ import type { GL, WebGPUState } from '../types'
17
16
 
18
17
  const WORKING_GROUP_SIZE = 32
19
18
 
19
+ const DEFAULT_VERTEX = /* rust */ `
20
+ struct In { @builtin(vertex_index) vertex_index: u32 }
21
+ struct Out { @builtin(position) position: vec4f }
22
+ @vertex
23
+ fn main(in: In) -> Out {
24
+ var out: Out;
25
+ var x = f32(in.vertex_index % 2) * 4.0 - 1.0;
26
+ var y = f32(in.vertex_index / 2) * 4.0 - 1.0;
27
+ out.position = vec4f(x, y, 0.0, 1.0);
28
+ return out;
29
+ }
30
+ `.trim()
31
+
32
+ const DEFAULT_FRAGMENT = /* rust */ `
33
+ struct Out { @builtin(position) position: vec4f }
34
+ @group(0) @binding(0) var<uniform> iResolution: vec2f;
35
+ @fragment
36
+ fn main(out: Out) -> @location(0) vec4f {
37
+ return vec4f(fract((out.position.xy / iResolution)), 0.0, 1.0);
38
+ }
39
+ `
40
+
20
41
  const computeProgram = (gl: GL, device: GPUDevice, bindings: any) => {
21
42
  let flush = (_pass: GPUComputePassEncoder) => {}
22
43
 
@@ -129,9 +150,9 @@ export const webgpu = async (gl: GL) => {
129
150
  const render = () => {
130
151
  if (!frag || !vert) {
131
152
  const config = { isWebGL: false, gl }
132
- frag = fragment(gl.fs, config) // needs to be before vertex
133
- vert = vertex(gl.vs, config)
134
- comp = compute(gl.cs, config)
153
+ frag = gl.fs ? (is.str(gl.fs) ? gl.fs : gl.fs.fragment(config)) : DEFAULT_FRAGMENT
154
+ vert = gl.vs ? (is.str(gl.vs) ? gl.vs : gl.vs.vertex(config)) : DEFAULT_VERTEX
155
+ comp = gl.cs ? (is.str(gl.cs) ? gl.cs : gl.cs.compute(config)) : ''
135
156
  }
136
157
  if (gl.loading) return // MEMO: loading after build node
137
158
  if (needsUpdate) update()
package/src/node/node.ts DELETED
@@ -1,65 +0,0 @@
1
- import { code, getConstant, isConversion, isFunction, isOperator, getId, isArrayAccess } from './utils'
2
- import { assign, toVar } from './scope'
3
- import { is } from '../utils/helpers'
4
- import type { Functions, NodeProps, NodeProxy, NodeTypes, Operators, X, Constants as C } from './types'
5
-
6
- const toPrimitive = (x: X, hint: string) => {
7
- if (hint === 'string') return code(x, null)
8
- }
9
-
10
- export const node = <T extends C>(type: NodeTypes, props?: NodeProps | null, ...args: X[]) => {
11
- if (!props) props = {}
12
- if (args.length) props.children = args
13
- const listeners = new Set<(value: any) => void>()
14
- const get = (_: unknown, y: string | Symbol) => {
15
- if (y === 'type') return type
16
- if (y === 'props') return props
17
- if (y === '__nodeType') return undefined // Will be inferred by TypeScript
18
- if (y === 'toVar') return toVar.bind(null, x as any)
19
- if (y === 'isProxy') return true
20
- if (y === 'toString') return code.bind(null, x)
21
- if (y === Symbol.toPrimitive) return toPrimitive.bind(null, x)
22
- if (y === 'listeners') return listeners
23
- if (y === 'attribute') return (id = getId()) => attribute(x, id)
24
- if (y === 'constant') return (id = getId()) => constant(x, id)
25
- if (y === 'uniform') return (id = getId()) => uniform(x, id)
26
- if (y === 'variable') return (id = getId()) => variable(id)
27
- if (y === 'builtin') return (id = getId()) => builtin(id)
28
- if (y === 'vertexStage') return (id = getId()) => vertexStage(x, id)
29
- if (y === 'element') return (z: X) => (type === 'storage' ? gather(x, z) : element(x, z))
30
- if (y === 'member') return (z: X) => member(x, z)
31
- if (y === 'assign') return assign.bind(null, x, x.type === 'gather')
32
- if (isOperator(y)) return (...z: X[]) => operator(y, x, ...z)
33
- if (isFunction(y)) return (...z: X[]) => function_(y, x, ...z)
34
- if (isConversion(y)) return () => conversion(getConstant(y), x)
35
- if (is.str(y)) return isArrayAccess(y) ? element(x, y) : member(x, y)
36
- }
37
- const set = (_: unknown, y: string, z: X) => {
38
- if (y === 'value') listeners.forEach((fun) => fun(z))
39
- if (is.str(y)) member(x, y).assign(z)
40
- return true
41
- }
42
- const x = new Proxy({}, { get, set }) as unknown as NodeProxy<T>
43
- return x
44
- }
45
-
46
- // headers with proper type inference
47
- export const attribute = <T extends C>(x: X<T>, id = getId()) => node<T>('attribute', { id }, x)
48
- export const constant = <T extends C>(x: X<T>, id = getId()) => node<T>('constant', { id }, x)
49
- export const uniform = <T extends C>(x: X<T>, id = getId()) => node<T>('uniform', { id }, x)
50
- export const storage = <T extends C>(x: X<T>, id = getId()) => node<T>('storage', { id }, x)
51
- export const variable = <T extends C>(id = getId()) => node<T>('variable', { id })
52
- export const builtin = <T extends C>(id = getId()) => node<T>('builtin', { id })
53
- export const vertexStage = <T extends C>(x: X<T>, id = getId()) => {
54
- return node<T>('varying', { id, inferFrom: [x] }, x)
55
- }
56
-
57
- // Node shorthands with proper typing
58
- export const member = <T extends C>(x: X, index: X) => node<T>('member', null, x, index)
59
- export const element = <T extends C>(x: X, index: X) => node<T>('element', null, x, index)
60
- export const gather = <T extends C>(x: X, index: X) => node<T>('gather', null, x, index)
61
- export const scatter = <T extends C>(x: X, index: X) => node<T>('scatter', null, x, index)
62
- export const select = <T extends C>(x: X<T>, y: X<T>, z: X) => node<T>('ternary', null, x, y, z) // z ? x : y @TODO REMOVE
63
- export const operator = <T extends C>(key: Operators, ...x: X[]) => node<T>('operator', null, key, ...x)
64
- export const function_ = <T extends C>(key: Functions, ...x: X[]) => node<T>('function', null, key, ...x)
65
- export const conversion = <T extends C>(key: T, ...x: X[]) => node<T>('conversion', null, key, ...x)