glre 0.37.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 +31 -40
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.d.ts +170 -1791
  9. package/dist/index.js +31 -40
  10. package/dist/index.js.map +1 -1
  11. package/dist/native.cjs +1 -45
  12. package/dist/native.cjs.map +1 -1
  13. package/dist/native.d.ts +511 -11
  14. package/dist/native.js +1 -45
  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 -45
  22. package/dist/react.cjs.map +1 -1
  23. package/dist/react.d.ts +506 -4
  24. package/dist/react.js +1 -45
  25. package/dist/react.js.map +1 -1
  26. package/dist/solid.cjs +1 -45
  27. package/dist/solid.cjs.map +1 -1
  28. package/dist/solid.d.ts +506 -4
  29. package/dist/solid.js +1 -45
  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 +65 -50
  38. package/src/node/types.ts +222 -164
  39. package/src/node/utils/const.ts +64 -3
  40. package/src/node/utils/index.ts +8 -5
  41. package/src/node/utils/infer.ts +23 -35
  42. package/src/node/utils/parse.ts +15 -18
  43. package/src/node/utils/utils.ts +13 -12
  44. package/src/types.ts +5 -7
  45. package/src/utils/pipeline.ts +3 -3
  46. package/src/utils/program.ts +7 -2
  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 -64
@@ -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,27 +31,26 @@ 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
50
38
  const ret = infer(x, c)
51
- for (const x of arr.slice(1))
52
- if (ret !== infer(x, c)) throw new Error(`glre node system error: defined scope return mismatch`)
39
+ // for (const x of arr.slice(1))
40
+ // if (ret !== infer(x, c)) throw new Error(`glre node system error: defined scope return mismatch`)
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
64
52
  if (type === 'conversion') return x
65
53
  if (type === 'operator') return inferOperator(infer(y, c), infer(z, c), x)
66
- if (type === 'ternary') return inferOperator(infer(y, c), infer(z, c), 'add')
67
54
  if (type === 'builtin') return inferBuiltin(id)
68
55
  if (type === 'function') return inferFunction(x) || infer(y, c)
69
56
  if (type === 'define') {
@@ -74,23 +61,24 @@ export const inferImpl = <T extends C>(target: NodeProxy<T>, c: NodeContext): T
74
61
  if (type === 'attribute' && is.arr(x) && c.gl?.count) return inferFromCount(x.length / c.gl.count)
75
62
  if (type === 'member') {
76
63
  if (isSwizzle(y)) return inferFromCount(y.length)
77
- if (isNodeProxy(x)) {
78
- const field = (x as any).props.fields[y] // for variable node of struct member
79
- if (field) return infer(field, c)
64
+ if (isX(x)) {
65
+ const structType = infer(x, c)
66
+ const fields = c.code?.structStructFields?.get(structType)
67
+ if (fields && fields[y]) return infer(fields[y], c) as T
80
68
  }
81
- return 'float' as T // fallback @TODO FIX
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)
95
- return ret
83
+ return ret as T
96
84
  }
@@ -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, 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)};`
@@ -87,7 +87,8 @@ export const parseDeclare = (c: NodeContext, x: X, y: X) => {
87
87
  return `var ${varName}: ${wgslType} = ${code(x, c)};`
88
88
  }
89
89
 
90
- export const parseStructHead = (c: NodeContext, id: string, fields: Record<string, NodeProxy> = {}) => {
90
+ export const parseStructHead = (c: NodeContext, id: string, fields: StructFields = {}) => {
91
+ c.code?.structStructFields?.set(id, fields)
91
92
  const lines: string[] = []
92
93
  for (const key in fields) {
93
94
  const fieldType = fields[key]
@@ -99,13 +100,8 @@ export const parseStructHead = (c: NodeContext, id: string, fields: Record<strin
99
100
  return `struct ${id} {\n ${ret}\n};`
100
101
  }
101
102
 
102
- export const parseStruct = (
103
- c: NodeContext,
104
- id: string,
105
- instanceId = '',
106
- fields?: Record<string, NodeProxy>,
107
- initialValues?: Record<string, NodeProxy>
108
- ) => {
103
+ export const parseStruct = (c: NodeContext, id: string, instanceId = '', initialValues?: StructFields) => {
104
+ const fields = c.code?.structStructFields?.get(id) || {}
109
105
  if (c.isWebGL) {
110
106
  if (initialValues) {
111
107
  const ordered = []
@@ -124,7 +120,7 @@ export const parseStruct = (
124
120
  /**
125
121
  * define
126
122
  */
127
- export const parseDefine = (c: NodeContext, props: NodeProps, returnType: Constants) => {
123
+ export const parseDefine = (c: NodeContext, props: NodeProps, target: Y) => {
128
124
  const { id, children = [], layout } = props
129
125
  const [x, ...args] = children
130
126
  const argParams: [name: string, type: string][] = []
@@ -137,6 +133,8 @@ export const parseDefine = (c: NodeContext, props: NodeProps, returnType: Consta
137
133
  for (let i = 0; i < args.length; i++) {
138
134
  argParams.push([`p${i}`, infer(args[i], c)])
139
135
  }
136
+ const scopeCode = code(x, c) // build struct headers before inferring returnType
137
+ const returnType = infer(target, c)
140
138
  const ret = []
141
139
  if (c?.isWebGL) {
142
140
  for (const [paramId, type] of argParams) {
@@ -152,7 +150,6 @@ export const parseDefine = (c: NodeContext, props: NodeProps, returnType: Consta
152
150
  ret.push(`fn ${id}(${params}) {`)
153
151
  } else ret.push(`fn ${id}(${params}) -> ${getConversions(returnType, c)} {`)
154
152
  }
155
- const scopeCode = code(x, c)
156
153
  if (scopeCode) ret.push(scopeCode)
157
154
  ret.push('}')
158
155
  return ret.join('\n')
@@ -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,15 +26,15 @@ 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
- return CONSTANTS.includes(type)
37
+ return CONSTANTS.includes(type as any)
38
38
  }
39
39
 
40
40
  export const hex2rgb = (hex: number) => {
@@ -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<string>) => {
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,13 +84,13 @@ 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(1)
89
+ if (!isX(x)) return fun(x) // for uniform(0) or uniform([0, 1])
90
90
  if (x.type !== 'conversion') return
91
- const value = x.props.children?.slice(1).filter(Boolean)
92
- if (!value?.length) return // for uniform(vec2())
93
- fun(value)
91
+ const args = x.props.children?.slice(1)
92
+ if (is.und(args?.[0])) return // ignore if uniform(vec2())
93
+ fun(args.map((x) => x ?? args[0])) // for uniform(vec2(1)) or uniform(vec2(1, 1))
94
94
  }
95
95
 
96
96
  export const initNodeContext = (c: NodeContext) => {
@@ -103,6 +103,7 @@ export const initNodeContext = (c: NodeContext) => {
103
103
  vertVaryings: new Map(),
104
104
  computeInputs: new Map(),
105
105
  dependencies: new Map(),
106
+ structStructFields: new Map(),
106
107
  }
107
108
  if (c.isWebGL) return c
108
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 } 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
  /**
@@ -21,13 +20,13 @@ export type GL = EventState<{
21
20
  particles: 64 | 256 | 576 | 1024 | 1600 | 2304 | 3136 | 4096 | 4096 | 5184 | 6400 // (8k)^2
22
21
  el: HTMLCanvasElement
23
22
  vs?: string | Vec4
24
- cs?: string | Vec4
23
+ cs?: string | Void
25
24
  fs?: string | Vec4
26
25
  vert?: string | Vec4
27
- comp?: string | Vec4
26
+ comp?: string | Void
28
27
  frag?: string | Vec4
29
28
  vertex?: string | Vec4
30
- compute?: string | Vec4
29
+ compute?: string | Void
31
30
  fragment?: string | Vec4
32
31
 
33
32
  /**
@@ -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 }),
@@ -9,7 +9,7 @@ const createShader = (c: WebGLRenderingContext, source: string, type: number, on
9
9
  if (c.getShaderParameter(shader, c.COMPILE_STATUS)) return shader
10
10
  const error = c.getShaderInfoLog(shader)
11
11
  c.deleteShader(shader)
12
- onError(`Could not compile shader: ${error}`)
12
+ onError(`Could not compile shader: ${error}\n\n↓↓↓generated↓↓↓\n${source}`)
13
13
  }
14
14
 
15
15
  export const createProgram = (c: WebGLRenderingContext, frag: string, vert: string, gl: GL) => {
@@ -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,64 +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 === 'toVar') return toVar.bind(null, x)
18
- if (y === 'isProxy') return true
19
- if (y === 'toString') return code.bind(null, x)
20
- if (y === Symbol.toPrimitive) return toPrimitive.bind(null, x)
21
- if (y === 'listeners') return listeners
22
- if (y === 'attribute') return (id = getId()) => attribute(x, id)
23
- if (y === 'constant') return (id = getId()) => constant(x, id)
24
- if (y === 'uniform') return (id = getId()) => uniform(x, id)
25
- if (y === 'variable') return (id = getId()) => variable(id)
26
- if (y === 'builtin') return (id = getId()) => builtin(id)
27
- if (y === 'vertexStage') return (id = getId()) => vertexStage(x, id)
28
- if (y === 'element') return (z: X) => (type === 'storage' ? gather(x, z) : element(x, z))
29
- if (y === 'member') return (z: X) => member(x, z)
30
- if (y === 'assign') return assign.bind(null, x, x.type === 'gather')
31
- if (isOperator(y)) return (...z: X[]) => operator(y, x, ...z)
32
- if (isFunction(y)) return (...z: X[]) => function_(y, x, ...z)
33
- if (isConversion(y)) return () => conversion(getConstant(y), x)
34
- if (is.str(y)) return isArrayAccess(y) ? element(x, y) : member(x, y)
35
- }
36
- const set = (_: unknown, y: string, z: X) => {
37
- if (y === 'value') listeners.forEach((fun) => fun(z))
38
- if (is.str(y)) member(x, y).assign(z)
39
- return true
40
- }
41
- const x = new Proxy({}, { get, set }) as unknown as NodeProxy<T>
42
- return x
43
- }
44
-
45
- // headers with proper type inference
46
- export const attribute = <T extends C>(x: X, id = getId()) => node<T>('attribute', { id }, x)
47
- export const constant = <T extends C>(x: X<T>, id = getId()) => node<T>('constant', { id }, x)
48
- export const uniform = <T extends C>(x: X<T>, id = getId()) => node<T>('uniform', { id }, x)
49
- export const storage = <T extends C>(x: X<T>, id = getId()) => node<T>('storage', { id }, x)
50
- export const variable = <T extends C>(id = getId()) => node<T>('variable', { id })
51
- export const builtin = <T extends C>(id = getId()) => node<T>('builtin', { id })
52
- export const vertexStage = <T extends C>(x: X<T>, id = getId()) => {
53
- return node<T>('varying', { id, inferFrom: [x] }, x)
54
- }
55
-
56
- // Node shorthands with proper typing
57
- export const member = <T extends C>(x: X, index: X) => node<T>('member', null, x, index)
58
- export const element = <T extends C>(x: X, index: X) => node<T>('element', null, x, index)
59
- export const gather = <T extends C>(x: X, index: X) => node<T>('gather', null, x, index)
60
- export const scatter = <T extends C>(x: X, index: X) => node<T>('scatter', null, x, index)
61
- 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
62
- export const operator = <T extends C>(key: Operators, ...x: X[]) => node<T>('operator', null, key, ...x)
63
- export const function_ = <T extends C>(key: Functions, ...x: X[]) => node<T>('function', null, key, ...x)
64
- export const conversion = <T extends C>(key: T, ...x: X[]) => node<T>('conversion', null, key, ...x)