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.
- package/dist/addons.cjs +2 -0
- package/dist/addons.cjs.map +1 -0
- package/dist/addons.d.ts +457 -0
- package/dist/addons.js +2 -0
- package/dist/addons.js.map +1 -0
- package/dist/index.cjs +31 -40
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +170 -1791
- package/dist/index.js +31 -40
- package/dist/index.js.map +1 -1
- package/dist/native.cjs +1 -45
- package/dist/native.cjs.map +1 -1
- package/dist/native.d.ts +511 -11
- package/dist/native.js +1 -45
- package/dist/native.js.map +1 -1
- package/dist/node.cjs +40 -0
- package/dist/node.cjs.map +1 -0
- package/dist/node.d.ts +614 -0
- package/dist/node.js +40 -0
- package/dist/node.js.map +1 -0
- package/dist/react.cjs +1 -45
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.ts +506 -4
- package/dist/react.js +1 -45
- package/dist/react.js.map +1 -1
- package/dist/solid.cjs +1 -45
- package/dist/solid.cjs.map +1 -1
- package/dist/solid.d.ts +506 -4
- package/dist/solid.js +1 -45
- package/dist/solid.js.map +1 -1
- package/package.json +56 -3
- package/src/addons/index.ts +6 -0
- package/src/index.ts +6 -22
- package/src/node/{core.ts → build.ts} +3 -7
- package/src/node/create.ts +73 -0
- package/src/node/index.ts +63 -47
- package/src/node/scope.ts +65 -50
- package/src/node/types.ts +222 -164
- package/src/node/utils/const.ts +64 -3
- package/src/node/utils/index.ts +8 -5
- package/src/node/utils/infer.ts +23 -35
- package/src/node/utils/parse.ts +15 -18
- package/src/node/utils/utils.ts +13 -12
- package/src/types.ts +5 -7
- package/src/utils/pipeline.ts +3 -3
- package/src/utils/program.ts +7 -2
- package/src/{webgl.ts → utils/webgl.ts} +24 -14
- package/src/{webgpu.ts → utils/webgpu.ts} +28 -7
- package/src/node/node.ts +0 -64
package/src/node/utils/infer.ts
CHANGED
|
@@ -1,37 +1,25 @@
|
|
|
1
|
-
import { isConstants,
|
|
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
|
-
|
|
6
|
+
getOperatorResultType,
|
|
7
|
+
validateOperatorTypes,
|
|
8
8
|
} from './const'
|
|
9
9
|
import { is } from '../../utils/helpers'
|
|
10
|
-
import type { Constants as C, NodeContext,
|
|
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 (
|
|
19
|
-
|
|
20
|
-
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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 (
|
|
78
|
-
const
|
|
79
|
-
|
|
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
|
|
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:
|
|
75
|
+
export const infer = <T extends C>(target: Y<T>, c?: NodeContext | null): T => {
|
|
88
76
|
if (!c) c = {}
|
|
89
|
-
if (!
|
|
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<
|
|
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
|
}
|
package/src/node/utils/parse.ts
CHANGED
|
@@ -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,
|
|
5
|
+
import type { Constants, NodeContext, NodeProps, StructFields, Y } from '../types'
|
|
6
6
|
|
|
7
|
-
export const parseArray = (children:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
|
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,
|
|
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')
|
package/src/node/utils/utils.ts
CHANGED
|
@@ -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,
|
|
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
|
|
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
|
|
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
|
|
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:
|
|
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):
|
|
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
|
|
87
|
+
export const safeEventCall = <T extends C>(x: X<T>, fun: (value: unknown) => void) => {
|
|
88
88
|
if (is.und(x)) return
|
|
89
|
-
if (!
|
|
89
|
+
if (!isX(x)) return fun(x) // for uniform(0) or uniform([0, 1])
|
|
90
90
|
if (x.type !== 'conversion') return
|
|
91
|
-
const
|
|
92
|
-
if (
|
|
93
|
-
fun(
|
|
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 {
|
|
3
|
-
import type {
|
|
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 |
|
|
23
|
+
cs?: string | Void
|
|
25
24
|
fs?: string | Vec4
|
|
26
25
|
vert?: string | Vec4
|
|
27
|
-
comp?: string |
|
|
26
|
+
comp?: string | Void
|
|
28
27
|
frag?: string | Vec4
|
|
29
28
|
vertex?: string | Vec4
|
|
30
|
-
compute?: string |
|
|
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
|
package/src/utils/pipeline.ts
CHANGED
|
@@ -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 }),
|
package/src/utils/program.ts
CHANGED
|
@@ -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 = (
|
|
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 './
|
|
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 './
|
|
12
|
-
import {
|
|
13
|
-
import type { GL, WebGLState } from './types'
|
|
11
|
+
} from './program'
|
|
12
|
+
import type { GL, WebGLState } from '../types'
|
|
14
13
|
|
|
15
|
-
const
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
|
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
|
|
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)
|
|
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 './
|
|
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 './
|
|
15
|
-
import type { GL, WebGPUState } from '
|
|
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 =
|
|
133
|
-
vert =
|
|
134
|
-
comp =
|
|
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)
|