glre 0.36.0 → 0.37.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.
@@ -1,5 +1,30 @@
1
1
  export const SWIZZLES = ['x', 'y', 'z', 'w', 'r', 'g', 'b', 'a', 's', 't', 'p', 'q'] as const
2
2
 
3
+ // Unified order with TYPE_MAPPING array
4
+ export const CONVERSIONS = [
5
+ 'toBool',
6
+ 'toUint',
7
+ 'toInt',
8
+ 'toFloat',
9
+ 'toBvec2',
10
+ 'toIvec2',
11
+ 'toUvec2',
12
+ 'toVec2',
13
+ 'toBvec3',
14
+ 'toIvec3',
15
+ 'toUvec3',
16
+ 'toVec3',
17
+ 'toBvec4',
18
+ 'toIvec4',
19
+ 'toUvec4',
20
+ 'toVec4',
21
+ 'toColor',
22
+ 'toMat2',
23
+ 'toMat3',
24
+ 'toMat4',
25
+ ] as const
26
+
27
+ // Unified order with CONVERSIONS array
3
28
  export const TYPE_MAPPING = {
4
29
  bool: 'bool',
5
30
  uint: 'u32',
@@ -28,29 +53,6 @@ export const TYPE_MAPPING = {
28
53
 
29
54
  export const CONSTANTS = Object.keys(TYPE_MAPPING) as unknown as keyof typeof TYPE_MAPPING
30
55
 
31
- export const CONVERSIONS = [
32
- 'toBool',
33
- 'toUint',
34
- 'toInt',
35
- 'toFloat',
36
- 'toBvec2',
37
- 'toIvec2',
38
- 'toUvec2',
39
- 'toVec2',
40
- 'toBvec3',
41
- 'toIvec3',
42
- 'toUvec3',
43
- 'toVec3',
44
- 'toBvec4',
45
- 'toIvec4',
46
- 'toUvec4',
47
- 'toVec4',
48
- 'toColor',
49
- 'toMat2',
50
- 'toMat3',
51
- 'toMat4',
52
- ] as const
53
-
54
56
  export const OPERATORS = {
55
57
  add: '+',
56
58
  sub: '-',
@@ -74,84 +76,6 @@ export const OPERATORS = {
74
76
 
75
77
  export const OPERATOR_KEYS = Object.keys(OPERATORS) as (keyof typeof OPERATORS)[]
76
78
 
77
- // All shader functions (type inference now handled by inferFrom)
78
- export const FUNCTIONS = [
79
- // Float return functions
80
- 'dot',
81
- 'distance',
82
- 'length',
83
- 'lengthSq',
84
- 'determinant',
85
- 'luminance',
86
- // Bool return functions
87
- 'all',
88
- 'any',
89
- // Component-wise functions (preserve input type)
90
- 'abs',
91
- 'sign',
92
- 'floor',
93
- 'ceil',
94
- 'round',
95
- 'fract',
96
- 'trunc',
97
- 'sin',
98
- 'cos',
99
- 'tan',
100
- 'asin',
101
- 'acos',
102
- 'atan',
103
- 'sinh',
104
- 'cosh',
105
- 'tanh',
106
- 'asinh',
107
- 'acosh',
108
- 'atanh',
109
- 'exp',
110
- 'exp2',
111
- 'log',
112
- 'log2',
113
- 'sqrt',
114
- 'inverseSqrt',
115
- 'normalize',
116
- 'oneMinus',
117
- 'saturate',
118
- 'negate',
119
- 'reciprocal',
120
- 'dFdx',
121
- 'dFdy',
122
- 'fwidth',
123
- 'degrees',
124
- 'radians',
125
- // Vector functions
126
- 'cross',
127
- 'reflect',
128
- 'refract',
129
- // Multi-argument functions
130
- 'min',
131
- 'max',
132
- 'mix',
133
- 'clamp',
134
- 'step',
135
- 'smoothstep',
136
- 'pow',
137
- 'atan2',
138
- // Texture functions
139
- 'texture',
140
- 'textureLod',
141
- 'textureSize',
142
- 'cubeTexture',
143
- // Utility functions
144
- 'faceforward',
145
- 'bitcast',
146
- 'cbrt',
147
- 'difference',
148
- 'equals',
149
- 'pow2',
150
- 'pow3',
151
- 'pow4',
152
- 'transformDirection',
153
- ] as const
154
-
155
79
  export const COMPONENT_COUNT_TO_TYPE = {
156
80
  1: 'float',
157
81
  2: 'vec2',
@@ -161,24 +85,6 @@ export const COMPONENT_COUNT_TO_TYPE = {
161
85
  16: 'mat4',
162
86
  } as const
163
87
 
164
- // Function return type mapping for method chaining
165
- export const FUNCTION_RETURN_TYPES = {
166
- // Always return vec4
167
- texture: 'vec4',
168
- cubeTexture: 'vec4',
169
- textureSize: 'vec4',
170
- // Always return float
171
- length: 'float',
172
- lengthSq: 'float',
173
- distance: 'float',
174
- dot: 'float',
175
- // Always return bool
176
- all: 'bool',
177
- any: 'bool',
178
- // Always return vec3
179
- cross: 'vec3',
180
- } as const
181
-
182
88
  export const BUILTIN_TYPES = {
183
89
  // WGSL builtin variables
184
90
  position: 'vec4',
@@ -189,6 +95,7 @@ export const BUILTIN_TYPES = {
189
95
  sample_index: 'uint',
190
96
  sample_mask: 'uint',
191
97
  point_coord: 'vec2',
98
+ global_invocation_id: 'uvec3',
192
99
 
193
100
  // TSL compatible variables
194
101
  positionLocal: 'vec3',
@@ -238,3 +145,88 @@ export const WGSL_TO_GLSL_BUILTIN = {
238
145
  point_coord: 'gl_PointCoord',
239
146
  uv: 'gl_FragCoord.xy',
240
147
  } as const
148
+
149
+ /**
150
+ * 2.1. unified with:
151
+ * 1.1. index.ts functions and
152
+ * 3.1. types.ts BaseNodeProxy
153
+ */
154
+ // Function return type mapping for method chaining
155
+ export const FUNCTION_RETURN_TYPES = {
156
+ // 0. Always return bool
157
+ all: 'bool',
158
+ any: 'bool',
159
+ // 2. Always return float
160
+ determinant: 'float',
161
+ distance: 'float',
162
+ dot: 'float',
163
+ length: 'float',
164
+ lengthSq: 'float',
165
+ luminance: 'float',
166
+ // 3. Always return vec3
167
+ cross: 'vec3',
168
+ // 4. Always return vec4
169
+ cubeTexture: 'vec4',
170
+ texture: 'vec4',
171
+ texelFetch: 'vec4',
172
+ textureLod: 'vec4',
173
+ } as const
174
+
175
+ /**
176
+ * 2.2. unified with:
177
+ * 1.2. index.ts functions and
178
+ * 3.2. types.ts BaseNodeProxy
179
+ */
180
+ // All shader functions (type inference now handled by inferFrom)
181
+ export const FUNCTIONS = [
182
+ ...(Object.keys(FUNCTION_RETURN_TYPES) as (keyof typeof FUNCTION_RETURN_TYPES)[]),
183
+ // 0. Component-wise functions
184
+ 'abs',
185
+ 'acos',
186
+ 'acosh',
187
+ 'asin',
188
+ 'asinh',
189
+ 'atan',
190
+ 'atanh',
191
+ 'ceil',
192
+ 'cos',
193
+ 'cosh',
194
+ 'dFdx',
195
+ 'dFdy',
196
+ 'degrees',
197
+ 'exp',
198
+ 'exp2',
199
+ 'floor',
200
+ 'fract',
201
+ 'fwidth',
202
+ 'inverseSqrt',
203
+ 'log',
204
+ 'log2',
205
+ 'negate',
206
+ 'normalize',
207
+ 'oneMinus',
208
+ 'radians',
209
+ 'reciprocal',
210
+ 'round',
211
+ 'saturate',
212
+ 'sign',
213
+ 'sin',
214
+ 'sinh',
215
+ 'sqrt',
216
+ 'tan',
217
+ 'tanh',
218
+ 'trunc',
219
+ // 1. Functions where first argument determines return type
220
+ 'atan2',
221
+ 'clamp',
222
+ 'max',
223
+ 'min',
224
+ 'mix',
225
+ 'pow',
226
+ 'reflect',
227
+ 'refract',
228
+ // 2. Functions where not first argument determines return type
229
+ 'smoothstep',
230
+ 'step',
231
+ // @NOTE: mod is operator
232
+ ] as const
@@ -5,13 +5,16 @@ import {
5
5
  parseConstantHead,
6
6
  parseDeclare,
7
7
  parseDefine,
8
+ parseGather,
8
9
  parseIf,
10
+ parseScatter,
11
+ parseStorageHead,
9
12
  parseStruct,
10
13
  parseStructHead,
11
14
  parseSwitch,
12
15
  parseTexture,
13
- parseVaryingHead,
14
16
  parseUniformHead,
17
+ parseVaryingHead,
15
18
  } from './parse'
16
19
  import { getBluiltin, getOperator, getConversions, safeEventCall, getEventFun, initNodeContext } from './utils'
17
20
  import { is } from '../../utils/helpers'
@@ -42,6 +45,16 @@ export const code = <T extends Constants>(target: X<T>, c?: NodeContext | null):
42
45
  if (type === 'variable') return id
43
46
  if (type === 'member') return `${code(x, c)}.${code(y, c)}`
44
47
  if (type === 'element') return `${code(x, c)}[${code(y, c)}]`
48
+ if (type === 'gather')
49
+ return c.isWebGL //
50
+ ? parseGather(c, x, y, target)
51
+ : `${code(x, c)}[${code(y, c)}]`
52
+ if (type === 'scatter') {
53
+ const [storageNode, indexNode] = x.props.children ?? [] // x is gather node
54
+ return c.isWebGL
55
+ ? parseScatter(c, storageNode, y) // indexNode is not using
56
+ : `${code(storageNode, c)}[${code(indexNode, c)}] = ${code(y, c)};`
57
+ }
45
58
  if (type === 'ternary')
46
59
  return c.isWebGL
47
60
  ? `(${code(z, c)} ? ${code(x, c)} : ${code(y, c)})`
@@ -91,12 +104,12 @@ export const code = <T extends Constants>(target: X<T>, c?: NodeContext | null):
91
104
  return c.isWebGL ? `${id}` : `out.${id}`
92
105
  }
93
106
  if (type === 'builtin') {
94
- if (c.isWebGL) return getBluiltin(id)
107
+ if (c.isWebGL) return getBluiltin(c, id)
95
108
  if (id === 'position') return 'out.position'
96
109
  const field = `@builtin(${id}) ${id}: ${getConversions(infer(target, c), c)}`
97
- if (c.isFrag) {
98
- c.code?.fragInputs.set(id, field)
99
- } else c.code?.vertInputs.set(id, field)
110
+ if (c.label === 'compute') c.code?.computeInputs.set(id, field)
111
+ else if (c.label === 'frag') c.code?.fragInputs.set(id, field)
112
+ else if (c.label === 'vert') c.code?.vertInputs.set(id, field)
100
113
  return `in.${id}`
101
114
  }
102
115
  if (type === 'attribute') {
@@ -115,6 +128,7 @@ export const code = <T extends Constants>(target: X<T>, c?: NodeContext | null):
115
128
  target.listeners.add(fun)
116
129
  head = parseUniformHead(c, id, varType)
117
130
  }
131
+ if (type === 'storage') head = parseStorageHead(c, id, infer(target, c))
118
132
  if (type === 'constant') head = parseConstantHead(c, id, infer(target, c), code(x, c))
119
133
  if (head) {
120
134
  c.code?.headers.set(id, head)
@@ -31,14 +31,6 @@ const inferOperator = <T extends C>(L: T, R: T, op: string): T => {
31
31
  return L
32
32
  }
33
33
 
34
- // Unified logic with infer.ts InferArrayElement type
35
- const inferArrayElement = <T extends C>(arrayType: T): T => {
36
- if (arrayType === 'mat4') return 'vec4' as T
37
- if (arrayType === 'mat3') return 'vec3' as T
38
- if (arrayType === 'mat2') return 'vec2' as T
39
- return 'float' as T
40
- }
41
-
42
34
  export const inferPrimitiveType = <T extends C>(x: X) => {
43
35
  if (is.bol(x)) return 'bool' as T
44
36
  if (is.str(x)) return 'texture' as T
@@ -74,9 +66,12 @@ export const inferImpl = <T extends C>(target: NodeProxy<T>, c: NodeContext): T
74
66
  if (type === 'ternary') return inferOperator(infer(y, c), infer(z, c), 'add')
75
67
  if (type === 'builtin') return inferBuiltin(id)
76
68
  if (type === 'function') return inferFunction(x) || infer(y, c)
77
- if (type === 'define' && isConstants(layout?.type)) return layout?.type as T
69
+ if (type === 'define') {
70
+ if (isConstants(layout?.type)) return layout?.type as T
71
+ if (!inferFrom || inferFrom.length === 0) return 'void' as T
72
+ return inferFromArray(inferFrom, c)
73
+ }
78
74
  if (type === 'attribute' && is.arr(x) && c.gl?.count) return inferFromCount(x.length / c.gl.count)
79
- if (type === 'element') return inferArrayElement(infer(x, c) as T)
80
75
  if (type === 'member') {
81
76
  if (isSwizzle(y)) return inferFromCount(y.length)
82
77
  if (isNodeProxy(x)) {
@@ -86,7 +81,7 @@ export const inferImpl = <T extends C>(target: NodeProxy<T>, c: NodeContext): T
86
81
  return 'float' as T // fallback @TODO FIX
87
82
  }
88
83
  if (inferFrom) return inferFromArray(inferFrom, c)
89
- return infer(x, c) // for uniform
84
+ return infer(x, c) // for uniform and storage gather and scatter
90
85
  }
91
86
 
92
87
  export const infer = <T extends C>(target: X<T>, c?: NodeContext | null): T => {
@@ -11,6 +11,35 @@ export const parseArray = (children: X[], c: NodeContext) => {
11
11
  .join(', ')
12
12
  }
13
13
 
14
+ // only for webgl
15
+ export const parseGather = (c: NodeContext, x: X, y: X, target: X) => {
16
+ const parseSwizzle = () => {
17
+ const valueType = infer(target, c)
18
+ if (valueType === 'float') return '.x'
19
+ if (valueType === 'vec2') return '.xy'
20
+ if (valueType === 'vec3') return '.xyz'
21
+ if (valueType === 'vec4') return ''
22
+ throw new Error(`Unsupported storage scatter type: ${valueType}`)
23
+ }
24
+ const indexVar = code(y, c)
25
+ const texSize = Math.floor(Math.sqrt(c.gl?.particles || 1024))
26
+ const coordX = `int(${indexVar}) % ${texSize}`
27
+ const coordY = `int(${indexVar}) / ${texSize}`
28
+ return `texelFetch(${code(x, c)}, ivec2(${coordX}, ${coordY}), 0)${parseSwizzle()}`
29
+ }
30
+
31
+ // only for webgl
32
+ export const parseScatter = (c: NodeContext, storageNode: X, valueNode: X) => {
33
+ const storageId = code(storageNode, c)
34
+ const valueCode = code(valueNode, c)
35
+ const valueType = infer(valueNode, c)
36
+ if (valueType === 'float') return `_${storageId} = vec4(${valueCode}, 0.0, 0.0, 1.0);`
37
+ if (valueType === 'vec2') return `_${storageId} = vec4(${valueCode}, 0.0, 1.0);`
38
+ if (valueType === 'vec3') return `_${storageId} = vec4(${valueCode}, 1.0);`
39
+ if (valueType === 'vec4') return `_${storageId} = ${valueCode};`
40
+ throw new Error(`Unsupported storage scatter type: ${valueType}`)
41
+ }
42
+
14
43
  export const parseTexture = (c: NodeContext, y: X, z: X, w: X) => {
15
44
  if (c.isWebGL) {
16
45
  const args = w ? [y, z, w] : [y, z]
@@ -118,7 +147,10 @@ export const parseDefine = (c: NodeContext, props: NodeProps, returnType: Consta
118
147
  ret.push(`${returnType} ${id}(${params}) {`)
119
148
  } else {
120
149
  for (const [paramId, type] of argParams) params.push(`${paramId}: ${getConversions(type, c)}`)
121
- ret.push(`fn ${id}(${params}) -> ${getConversions(returnType, c)} {`)
150
+ const isVoid = returnType === 'void'
151
+ if (isVoid) {
152
+ ret.push(`fn ${id}(${params}) {`)
153
+ } else ret.push(`fn ${id}(${params}) -> ${getConversions(returnType, c)} {`)
122
154
  }
123
155
  const scopeCode = code(x, c)
124
156
  if (scopeCode) ret.push(scopeCode)
@@ -135,6 +167,13 @@ export const parseVaryingHead = (c: NodeContext, id: string, type: string) => {
135
167
  : `@location(${c.code?.vertVaryings?.size || 0}) ${id}: ${getConversions(type, c)}`
136
168
  }
137
169
 
170
+ export const parseAttribHead = (c: NodeContext, id: string, type: Constants) => {
171
+ if (c.isWebGL) return `${type} ${id};`
172
+ const { location = 0 } = c.gl?.webgpu?.attribs.map.get(id) || {}
173
+ const wgslType = getConversions(type, c)
174
+ return `@location(${location}) ${id}: ${wgslType}`
175
+ }
176
+
138
177
  export const parseUniformHead = (c: NodeContext, id: string, type: Constants) => {
139
178
  const isTexture = type === 'sampler2D' || type === 'texture'
140
179
  if (c.isWebGL)
@@ -153,11 +192,16 @@ export const parseUniformHead = (c: NodeContext, id: string, type: Constants) =>
153
192
  return `@group(${group}) @binding(${binding}) var<uniform> ${id}: ${wgslType};`
154
193
  }
155
194
 
156
- export const parseAttribHead = (c: NodeContext, id: string, type: Constants) => {
157
- if (c.isWebGL) return `${type} ${id};`
158
- const { location = 0 } = c.gl?.webgpu?.attribs.map.get(id) || {}
195
+ export const parseStorageHead = (c: NodeContext, id: string, type: Constants) => {
196
+ if (c.isWebGL) {
197
+ const ret = `uniform sampler2D ${id};`
198
+ if (c.label !== 'compute') return ret
199
+ const location = c.units?.(id)
200
+ return `${ret}\nlayout(location = ${location}) out vec4 _${id};` // out texture buffer
201
+ }
202
+ const { group = 0, binding = 0 } = c.gl?.webgpu?.storages.map.get(id) || {}
159
203
  const wgslType = getConversions(type, c)
160
- return `@location(${location}) ${id}: ${wgslType}`
204
+ return `@group(${group}) @binding(${binding}) var<storage, read_write> ${id}: array<${wgslType}>;`
161
205
  }
162
206
 
163
207
  export const parseConstantHead = (c: NodeContext, id: string, type: Constants, value: string) => {
@@ -48,8 +48,14 @@ let count = 0
48
48
 
49
49
  export const getId = () => `x${count++}`
50
50
 
51
- export const getBluiltin = (id: string) => {
52
- return WGSL_TO_GLSL_BUILTIN[id as keyof typeof WGSL_TO_GLSL_BUILTIN]
51
+ export const getBluiltin = (c: NodeContext, id: string) => {
52
+ if (id === 'global_invocation_id') {
53
+ const size = Math.floor(Math.sqrt(c.gl?.particles || 1024))
54
+ return `uvec3(uint(gl_FragCoord.y) * uint(${size}) + uint(gl_FragCoord.x), 0u, 0u)`
55
+ }
56
+ const ret = WGSL_TO_GLSL_BUILTIN[id as keyof typeof WGSL_TO_GLSL_BUILTIN]
57
+ if (!ret) throw new Error(`Error: unknown builtin variable ${id}`)
58
+ return ret
53
59
  }
54
60
 
55
61
  export const getConversions = <T extends Constants>(x: X<T>, c?: NodeContext) => {
@@ -95,6 +101,7 @@ export const initNodeContext = (c: NodeContext) => {
95
101
  vertInputs: new Map(),
96
102
  vertOutputs: new Map(),
97
103
  vertVaryings: new Map(),
104
+ computeInputs: new Map(),
98
105
  dependencies: new Map(),
99
106
  }
100
107
  if (c.isWebGL) return c
package/src/types.ts CHANGED
@@ -18,6 +18,7 @@ export type GL = EventState<{
18
18
  mouse: [number, number]
19
19
  count: number
20
20
  loading: number
21
+ particles: 64 | 256 | 576 | 1024 | 1600 | 2304 | 3136 | 4096 | 4096 | 5184 | 6400 // (8k)^2
21
22
  el: HTMLCanvasElement
22
23
  vs?: string | Vec4
23
24
  cs?: string | Vec4
@@ -117,4 +118,5 @@ export interface WebGPUState {
117
118
  export interface WebGLState {
118
119
  context: WebGLRenderingContext
119
120
  program: WebGLProgram
121
+ storages: any
120
122
  }
@@ -1,6 +1,4 @@
1
- import { fragment, vertex } from '../node'
2
1
  import { is } from './helpers'
3
- import type { X } from '../node'
4
2
  import type { GL } from '../types'
5
3
 
6
4
  const createShader = (c: WebGLRenderingContext, source: string, type: number, onError = console.warn) => {
@@ -14,17 +12,13 @@ const createShader = (c: WebGLRenderingContext, source: string, type: number, on
14
12
  onError(`Could not compile shader: ${error}`)
15
13
  }
16
14
 
17
- export const createProgram = (c: WebGLRenderingContext, vert: X, frag: X, gl: GL) => {
18
- if (!vert || !frag) return
19
- const config = { isWebGL: true, gl }
20
- frag = fragment(frag, config) // needs to be before vertex
21
- vert = vertex(vert, config)
15
+ export const createProgram = (c: WebGLRenderingContext, frag: string, vert: string, gl: GL) => {
22
16
  const pg = c.createProgram()
23
- const vs = createShader(c, vert, c.VERTEX_SHADER, gl.error)
24
17
  const fs = createShader(c, frag, c.FRAGMENT_SHADER, gl.error)
18
+ const vs = createShader(c, vert, c.VERTEX_SHADER, gl.error)
25
19
  if (!fs || !vs) return
26
- c.attachShader(pg, vs!)
27
20
  c.attachShader(pg, fs!)
21
+ c.attachShader(pg, vs!)
28
22
  c.linkProgram(pg)
29
23
  if (c.getProgramParameter(pg, c.LINK_STATUS)) return pg
30
24
  const error = c.getProgramInfoLog(pg)
@@ -93,20 +87,70 @@ export const createTexture = (c: WebGLRenderingContext, img: HTMLImageElement, l
93
87
  c.bindTexture(c.TEXTURE_2D, texture)
94
88
  }
95
89
 
96
- export const createStorage = (c: WebGL2RenderingContext, size: number, storage: any, array: any) => {
97
- const data = new Float32Array(size * size * 4)
98
- for (let i = 0; i < array.length; i++) data[i * 4] = array[i]
99
- c.activeTexture(c.TEXTURE0 + storage.unit)
100
- c.bindTexture(c.TEXTURE_2D, storage.a.texture)
101
- c.texImage2D(c.TEXTURE_2D, 0, c.RGBA32F, size, size, 0, c.RGBA, c.FLOAT, data)
90
+ /**
91
+ * for gpgpu
92
+ */
93
+ interface TextureBuffer {
94
+ texture: WebGLTexture
95
+ buffer: WebGLFramebuffer
96
+ }
97
+
98
+ export const createStorage = (
99
+ c: WebGL2RenderingContext,
100
+ value: number[],
101
+ size: number,
102
+ ping: TextureBuffer,
103
+ pong: TextureBuffer,
104
+ unit: number,
105
+ array: Float32Array
106
+ ) => {
107
+ const particles = size * size
108
+ const vectorSize = value.length / particles
109
+ for (let i = 0; i < particles; i++) {
110
+ for (let j = 0; j < Math.min(vectorSize, 4); j++) {
111
+ array[4 * i + j] = value[i * vectorSize + j] || 0
112
+ }
113
+ }
114
+ c.activeTexture(c.TEXTURE0 + unit)
115
+ c.bindTexture(c.TEXTURE_2D, ping.texture)
116
+ c.texImage2D(c.TEXTURE_2D, 0, c.RGBA32F, size, size, 0, c.RGBA, c.FLOAT, array)
102
117
  c.texParameteri(c.TEXTURE_2D, c.TEXTURE_MIN_FILTER, c.NEAREST)
103
118
  c.texParameteri(c.TEXTURE_2D, c.TEXTURE_MAG_FILTER, c.NEAREST)
104
119
  c.texParameteri(c.TEXTURE_2D, c.TEXTURE_WRAP_S, c.CLAMP_TO_EDGE)
105
120
  c.texParameteri(c.TEXTURE_2D, c.TEXTURE_WRAP_T, c.CLAMP_TO_EDGE)
106
- c.bindTexture(c.TEXTURE_2D, storage.b.texture)
107
- c.texImage2D(c.TEXTURE_2D, 0, c.RGBA32F, size, size, 0, c.RGBA, c.FLOAT, null)
121
+ c.bindTexture(c.TEXTURE_2D, pong.texture)
122
+ c.texImage2D(c.TEXTURE_2D, 0, c.RGBA32F, size, size, 0, c.RGBA, c.FLOAT, array)
108
123
  c.texParameteri(c.TEXTURE_2D, c.TEXTURE_MIN_FILTER, c.NEAREST)
109
124
  c.texParameteri(c.TEXTURE_2D, c.TEXTURE_MAG_FILTER, c.NEAREST)
110
125
  c.texParameteri(c.TEXTURE_2D, c.TEXTURE_WRAP_S, c.CLAMP_TO_EDGE)
111
126
  c.texParameteri(c.TEXTURE_2D, c.TEXTURE_WRAP_T, c.CLAMP_TO_EDGE)
112
127
  }
128
+
129
+ export const cleanStorage = (
130
+ c: WebGL2RenderingContext,
131
+ map: Iterable<{ ping: TextureBuffer; pong: TextureBuffer }>
132
+ ) => {
133
+ for (const { ping, pong } of map) {
134
+ c.deleteTexture(ping.texture)
135
+ c.deleteTexture(pong.texture)
136
+ c.deleteFramebuffer(ping.buffer)
137
+ c.deleteFramebuffer(pong.buffer)
138
+ }
139
+ }
140
+
141
+ export const createAttachment = (
142
+ c: WebGL2RenderingContext,
143
+ i: TextureBuffer,
144
+ o: TextureBuffer,
145
+ loc: WebGLUniformLocation,
146
+ unit: number,
147
+ index: number
148
+ ) => {
149
+ c.activeTexture(c.TEXTURE0 + unit)
150
+ c.bindTexture(c.TEXTURE_2D, i.texture)
151
+ c.uniform1i(loc, unit)
152
+ if (index === 0) c.bindFramebuffer(c.FRAMEBUFFER, o.buffer)
153
+ const attachment = c.COLOR_ATTACHMENT0 + index
154
+ c.framebufferTexture2D(c.FRAMEBUFFER, attachment, c.TEXTURE_2D, o.texture, 0)
155
+ return attachment
156
+ }