glre 0.33.0 → 0.35.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/src/node/types.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { GL } from '../types'
2
+
2
3
  import { CONSTANTS, CONVERSIONS, FUNCTIONS, OPERATOR_KEYS } from './const'
3
4
 
4
5
  export type Constants = (typeof CONSTANTS)[number] | 'void'
@@ -47,17 +48,17 @@ export type NodeTypes =
47
48
  | 'declare'
48
49
  | 'return'
49
50
 
50
- export interface NodeProps {
51
+ export interface NodeProps<T extends Record<string, NodeProxy> = {}> {
51
52
  id?: string
52
- args?: X[]
53
+ args?: any[]
53
54
  type?: string
54
- children?: X[]
55
- inferFrom?: X[]
55
+ children?: any[]
56
+ inferFrom?: any[]
56
57
  layout?: FnLayout
57
58
  parent?: NodeProxy
58
59
  // for struct
59
- fields?: Record<string, NodeProxy>
60
- initialValues?: Record<string, NodeProxy>
60
+ fields?: T
61
+ initialValues?: T
61
62
  }
62
63
 
63
64
  export interface NodeContext {
@@ -78,7 +79,48 @@ export interface NodeContext {
78
79
  }
79
80
 
80
81
  /**
81
- * NodeProxy
82
+ * infer
83
+ */
84
+ // Unified logic with infer.ts inferOperator function
85
+ // prettier-ignore
86
+ type InferOperator<L extends Constants, R extends Constants> =
87
+ L extends R ? L :
88
+ // broadcast
89
+ L extends 'float' | 'int' ? R :
90
+ R extends 'float' | 'int' ? L :
91
+ // mat * vec → vec
92
+ L extends 'mat4' ? R extends 'vec4' ? R /* default */ : L :
93
+ L extends 'mat3' ? R extends 'vec3' ? R /* default */ : L :
94
+ L extends 'mat2' ? R extends 'vec2' ? R /* default */ : L :
95
+ // vec * mat → vec
96
+ L extends 'vec4' ? R extends 'mat4' ? L /* default */ : L :
97
+ L extends 'vec3' ? R extends 'mat3' ? L /* default */ : L :
98
+ L extends 'vec2' ? R extends 'mat2' ? L /* default */ : L : L
99
+
100
+ type _StringLength<S extends string> = S extends `${infer _}${infer Rest}`
101
+ ? Rest extends ''
102
+ ? 1
103
+ : Rest extends `${infer _}${infer Rest2}`
104
+ ? Rest2 extends ''
105
+ ? 2
106
+ : Rest2 extends `${infer _}${infer Rest3}`
107
+ ? Rest3 extends ''
108
+ ? 3
109
+ : 4
110
+ : never
111
+ : never
112
+ : 0
113
+
114
+ type InferSwizzleType<S extends string> = _StringLength<S> extends 4
115
+ ? 'vec4'
116
+ : _StringLength<S> extends 3
117
+ ? 'vec3'
118
+ : _StringLength<S> extends 2
119
+ ? 'vec2'
120
+ : 'float'
121
+
122
+ /**
123
+ * Swizzles
82
124
  */
83
125
  type _Swizzles<T extends string> = T | `${T}${T}` | `${T}${T}${T}` | `${T}${T}${T}${T}`
84
126
 
@@ -101,14 +143,10 @@ type NodeProxyMethods =
101
143
  | 'toVar'
102
144
  | 'toString'
103
145
 
104
- export type ReadNodeProxy = {
105
- [K in string as K extends NodeProxyMethods ? never : K]: X
106
- }
107
-
108
- export interface BaseNodeProxy extends Record<Swizzles, NodeProxy> {
146
+ export interface BaseNodeProxy<T extends Constants> {
109
147
  // System properties
110
- assign(n: X): NodeProxy
111
- toVar(name?: string): NodeProxy
148
+ assign(x: any): NodeProxy<T>
149
+ toVar(name?: string): NodeProxy<T>
112
150
  toString(c?: NodeContext): string
113
151
  type: NodeTypes
114
152
  props: NodeProps
@@ -116,90 +154,176 @@ export interface BaseNodeProxy extends Record<Swizzles, NodeProxy> {
116
154
  listeners: Set<(value: any) => void>
117
155
 
118
156
  // Operators methods
119
- add(n: X): NodeProxy
120
- sub(n: X): NodeProxy
121
- mul(n: X): NodeProxy
122
- div(n: X): NodeProxy
123
- mod(n: X): NodeProxy
124
- equal(n: X): NodeProxy
125
- notEqual(n: X): NodeProxy
126
- lessThan(n: X): NodeProxy
127
- lessThanEqual(n: X): NodeProxy
128
- greaterThan(n: X): NodeProxy
129
- greaterThanEqual(n: X): NodeProxy
130
- and(n: X): NodeProxy
131
- or(n: X): NodeProxy
132
- not(): NodeProxy
133
-
134
- // Conversations methods
135
- toBool(): NodeProxy
136
- toUint(): NodeProxy
137
- toInt(): NodeProxy
138
- toFloat(): NodeProxy
139
- toBvec2(): NodeProxy
140
- toIvec2(): NodeProxy
141
- toUvec2(): NodeProxy
142
- toVec2(): NodeProxy
143
- toBvec3(): NodeProxy
144
- toIvec3(): NodeProxy
145
- toUvec3(): NodeProxy
146
- toVec3(): NodeProxy
147
- toBvec4(): NodeProxy
148
- toIvec4(): NodeProxy
149
- toUvec4(): NodeProxy
150
- toVec4(): NodeProxy
151
- toColor(): NodeProxy
152
- toMat2(): NodeProxy
153
- toMat3(): NodeProxy
154
- toMat4(): NodeProxy
155
-
156
- // Function methods
157
- abs(): NodeProxy
158
- sin(): NodeProxy
159
- cos(): NodeProxy
160
- tan(): NodeProxy
161
- asin(): NodeProxy
162
- acos(): NodeProxy
163
- atan(): NodeProxy
164
- atan2(x: X): NodeProxy
165
- pow(y: X): NodeProxy
166
- pow2(): NodeProxy
167
- pow3(): NodeProxy
168
- pow4(): NodeProxy
169
- sqrt(): NodeProxy
170
- inverseSqrt(): NodeProxy
171
- exp(): NodeProxy
172
- exp2(): NodeProxy
173
- log(): NodeProxy
174
- log2(): NodeProxy
175
- floor(): NodeProxy
176
- ceil(): NodeProxy
177
- round(): NodeProxy
178
- fract(): NodeProxy
179
- trunc(): NodeProxy
180
- min(y: X): NodeProxy
181
- max(y: X): NodeProxy
182
- clamp(min: X, max: X): NodeProxy
183
- saturate(): NodeProxy
184
- mix(y: X, a: X): NodeProxy
185
- step(edge: X): NodeProxy
186
- smoothstep(edge0: X, edge1: X): NodeProxy
187
- length(): NodeProxy
188
- distance(y: X): NodeProxy
189
- dot(y: X): NodeProxy
190
- cross(y: X): NodeProxy
191
- normalize(): NodeProxy
192
- reflect(N: X): NodeProxy
193
- refract(N: X, eta: X): NodeProxy
194
- sign(): NodeProxy
195
- oneMinus(): NodeProxy
196
- reciprocal(): NodeProxy
197
- negate(): NodeProxy
198
- dFdx(): NodeProxy
199
- dFdy(): NodeProxy
200
- fwidth(): NodeProxy
157
+ add<U extends Constants>(x: X<U>): NodeProxy<InferOperator<T, U>>
158
+ sub<U extends Constants>(x: X<U>): NodeProxy<InferOperator<T, U>>
159
+ mul<U extends Constants>(x: X<U>): NodeProxy<InferOperator<T, U>>
160
+ div<U extends Constants>(x: X<U>): NodeProxy<InferOperator<T, U>>
161
+ mod<U extends Constants>(x: X<U>): NodeProxy<InferOperator<T, U>>
162
+ equal<U extends Constants>(x: X<U>): Bool
163
+ notEqual<U extends Constants>(x: X<U>): Bool
164
+ lessThan<U extends Constants>(x: X<U>): Bool
165
+ lessThanEqual<U extends Constants>(x: X<U>): Bool
166
+ greaterThan<U extends Constants>(x: X<U>): Bool
167
+ greaterThanEqual<U extends Constants>(x: X<U>): Bool
168
+ and(x: X<'bool'>): Bool
169
+ or(x: X<'bool'>): Bool
170
+ not(): Bool
171
+
172
+ // Bitwise operators
173
+ bitAnd(x: X<T>): NodeProxy<T>
174
+ bitOr(x: X<T>): NodeProxy<T>
175
+ bitXor(x: X<T>): NodeProxy<T>
176
+ bitNot(): NodeProxy<T>
177
+ shiftLeft<U extends Constants>(x: X<U>): NodeProxy<InferOperator<T, U>>
178
+ shiftRight<U extends Constants>(x: X<U>): NodeProxy<InferOperator<T, U>>
179
+
180
+ // Conversion methods
181
+ toBool(): Bool
182
+ toUint(): UInt
183
+ toInt(): Int
184
+ toFloat(): Float
185
+ toBvec2(): BVec2
186
+ toIvec2(): IVec2
187
+ toUvec2(): UVec2
188
+ toVec2(): Vec2
189
+ toBvec3(): BVec3
190
+ toIvec3(): IVec3
191
+ toUvec3(): UVec3
192
+ toVec3(): Vec3
193
+ toBvec4(): BVec4
194
+ toIvec4(): IVec4
195
+ toUvec4(): UVec4
196
+ toVec4(): Vec4
197
+ toColor(): Color
198
+ toMat2(): Mat2
199
+ toMat3(): Mat3
200
+ toMat4(): Mat4
201
+
202
+ // Mathematical function methods (preserve type functions)
203
+ abs(): NodeProxy<T>
204
+ sign(): NodeProxy<T>
205
+ floor(): NodeProxy<T>
206
+ ceil(): NodeProxy<T>
207
+ round(): NodeProxy<T>
208
+ fract(): NodeProxy<T>
209
+ trunc(): NodeProxy<T>
210
+ sin(): NodeProxy<T>
211
+ cos(): NodeProxy<T>
212
+ tan(): NodeProxy<T>
213
+ asin(): NodeProxy<T>
214
+ acos(): NodeProxy<T>
215
+ atan(): NodeProxy<T>
216
+ exp(): NodeProxy<T>
217
+ exp2(): NodeProxy<T>
218
+ log(): NodeProxy<T>
219
+ log2(): NodeProxy<T>
220
+ sqrt(): NodeProxy<T>
221
+ inverseSqrt(): NodeProxy<T>
222
+ normalize(): NodeProxy<T>
223
+ oneMinus(): NodeProxy<T>
224
+ saturate(): NodeProxy<T>
225
+ negate(): NodeProxy<T>
226
+ reciprocal(): NodeProxy<T>
227
+ dFdx(): NodeProxy<T>
228
+ dFdy(): NodeProxy<T>
229
+ fwidth(): NodeProxy<T>
230
+
231
+ // Scalar return functions
232
+ length(): Float
233
+ lengthSq(): Float
234
+ determinant(): Float
235
+ luminance(): Float
236
+
237
+ // Bool return functions
238
+ all(): Bool
239
+ any(): Bool
240
+
241
+ // Specific return type functions
242
+ cross<U extends Constants>(y: X<U>): Vec3
243
+
244
+ // Two argument functions with variable return types
245
+ atan2<U extends Constants>(x: X<U>): NodeProxy<T>
246
+ pow<U extends Constants>(y: X<U>): NodeProxy<T>
247
+ distance<U extends Constants>(y: X<U>): Float
248
+ dot<U extends Constants>(y: X<U>): Float
249
+ reflect<U extends Constants>(N: X<U>): NodeProxy<T>
250
+ refract<U extends Constants>(N: X<U>, eta: any): NodeProxy<T>
251
+
252
+ // Multi-argument functions that return highest priority type
253
+ min<U extends Constants>(y: X<U>): NodeProxy<InferOperator<T, U>>
254
+ max<U extends Constants>(y: X<U>): NodeProxy<InferOperator<T, U>>
255
+ mix<U extends Constants, V>(y: X<U>, a: V): NodeProxy<InferOperator<T, U>>
256
+ clamp<U extends Constants, V>(mix: X<U>, max: V): NodeProxy<InferOperator<T, U>>
257
+ step<U extends Constants>(edge: X<U>): NodeProxy<InferOperator<T, U>>
258
+ smoothstep<U extends Constants, V>(edge0: X<U>, edge1: V): NodeProxy<InferOperator<T, U>>
259
+
260
+ // Power functions
261
+ pow2(): NodeProxy<T>
262
+ pow3(): NodeProxy<T>
263
+ pow4(): NodeProxy<T>
264
+ }
265
+
266
+ type ReadNodeProxy = {
267
+ [K in string as K extends NodeProxyMethods ? never : K]: any
268
+ } & {
269
+ [K in Swizzles]: NodeProxy<InferSwizzleType<K>>
270
+ }
271
+
272
+ // Internal NodeProxy implementation (renamed from original)
273
+ type NodeProxyImpl<T extends Constants = string> = BaseNodeProxy<T> & ReadNodeProxy
274
+
275
+ export type Bool = NodeProxyImpl<'bool'>
276
+ export type UInt = NodeProxyImpl<'uint'>
277
+ export type Int = NodeProxyImpl<'int'>
278
+ export type Float = NodeProxyImpl<'float'>
279
+ export type BVec2 = NodeProxyImpl<'bvec2'>
280
+ export type IVec2 = NodeProxyImpl<'ivec2'>
281
+ export type UVec2 = NodeProxyImpl<'uvec2'>
282
+ export type Vec2 = NodeProxyImpl<'vec2'>
283
+ export type BVec3 = NodeProxyImpl<'bvec3'>
284
+ export type IVec3 = NodeProxyImpl<'ivec3'>
285
+ export type UVec3 = NodeProxyImpl<'uvec3'>
286
+ export type Vec3 = NodeProxyImpl<'vec3'>
287
+ export type BVec4 = NodeProxyImpl<'bvec4'>
288
+ export type IVec4 = NodeProxyImpl<'ivec4'>
289
+ export type UVec4 = NodeProxyImpl<'uvec4'>
290
+ export type Vec4 = NodeProxyImpl<'vec4'>
291
+ export type Color = NodeProxyImpl<'color'>
292
+ export type Mat2 = NodeProxyImpl<'mat2'>
293
+ export type Mat3 = NodeProxyImpl<'mat3'>
294
+ export type Mat4 = NodeProxyImpl<'mat4'>
295
+ export type Texture = NodeProxyImpl<'texture'>
296
+ export type Sampler2D = NodeProxyImpl<'sampler2D'>
297
+ export type Struct = NodeProxyImpl<'struct'>
298
+
299
+ export interface ConstantsToType {
300
+ bool: Bool
301
+ uint: UInt
302
+ int: Int
303
+ float: Float
304
+ bvec2: BVec2
305
+ ivec2: IVec2
306
+ uvec2: UVec2
307
+ vec2: Vec2
308
+ bvec3: BVec3
309
+ ivec3: IVec3
310
+ uvec3: UVec3
311
+ vec3: Vec3
312
+ bvec4: BVec4
313
+ ivec4: IVec4
314
+ uvec4: UVec4
315
+ vec4: Vec4
316
+ color: Color
317
+ mat2: Mat2
318
+ mat3: Mat3
319
+ mat4: Mat4
320
+ texture: Texture
321
+ sampler2D: Sampler2D
322
+ struct: Struct
201
323
  }
202
324
 
203
- export type NodeProxy = BaseNodeProxy & ReadNodeProxy
325
+ export type NodeProxy<T extends Constants = string> = T extends keyof ConstantsToType
326
+ ? ConstantsToType[T]
327
+ : NodeProxyImpl<T>
204
328
 
205
- export type X = X[] | (NodeProxy | number | string | boolean | undefined)
329
+ export type X<T extends Constants = string> = number | string | boolean | undefined | NodeProxy<T> | X[]
package/src/node/utils.ts CHANGED
@@ -26,7 +26,7 @@ export const isConversion = (key: unknown): key is Conversions => {
26
26
  return CONVERSIONS.includes(key as Conversions)
27
27
  }
28
28
 
29
- export const isNodeProxy = (x: unknown): x is NodeProxy => {
29
+ export const isNodeProxy = <T extends Constants>(x: unknown): x is NodeProxy<T> => {
30
30
  if (!x) return false
31
31
  if (typeof x !== 'object') return false // @ts-ignore
32
32
  return x.isProxy
@@ -46,15 +46,15 @@ export const hex2rgb = (hex: number) => {
46
46
 
47
47
  let count = 0
48
48
 
49
- export const getId = () => `i${count++}`
49
+ export const getId = () => `x${count++}`
50
50
 
51
- export const formatConversions = (x: X, c?: NodeContext) => {
51
+ export const formatConversions = <T extends Constants>(x: X<T>, c?: NodeContext) => {
52
52
  if (!is.str(x)) return ''
53
53
  if (c?.isWebGL) return x
54
54
  return TYPE_MAPPING[x as keyof typeof TYPE_MAPPING] || x // for struct type
55
55
  }
56
56
 
57
- export const getOperator = (op: X) => {
57
+ export const getOperator = (op: X<string>) => {
58
58
  return OPERATORS[op as keyof typeof OPERATORS] || op
59
59
  }
60
60
 
@@ -78,8 +78,8 @@ export const getEventFun = (c: NodeContext, id: string, isAttribute = false, isT
78
78
  return (value: any) => c.gl?._uniform?.(id, value)
79
79
  }
80
80
 
81
- export const safeEventCall = (x: X, fun: (value: unknown) => void) => {
82
- if (!x) return
81
+ export const safeEventCall = <T extends Constants>(x: X<T>, fun: (value: unknown) => void) => {
82
+ if (is.und(x)) return
83
83
  if (!isNodeProxy(x)) return fun(x) // for uniform(1)
84
84
  if (x.type !== 'conversion') return
85
85
  const value = x.props.children?.slice(1).filter(Boolean)
package/src/types.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { EventState, Nested } from 'reev'
2
2
  import type { Fun, Queue, Frame } from 'refr'
3
- import type { NodeProxy } from './node'
3
+ import type { NodeProxy, Vec4 } from './node'
4
4
  export type { Fun, Queue, Frame }
5
5
  export type PrecisionMode = 'highp' | 'mediump' | 'lowp'
6
6
  export type GLClearMode = 'COLOR_BUFFER_BIT' | 'DEPTH_BUFFER_BIT' | 'STENCIL_BUFFER_BIT'
@@ -59,20 +59,22 @@ export type GL = EventState<{
59
59
  */
60
60
  isNative: boolean
61
61
  isWebGL: boolean
62
+ isError: boolean
62
63
  isLoop: boolean
63
64
  isGL: true
64
- width: number
65
- height: number
65
+ width?: number
66
+ height?: number
66
67
  size: [number, number]
67
68
  mouse: [number, number]
68
69
  count: number
70
+ loading: number
69
71
  el: HTMLCanvasElement
70
- vs: string | NodeProxy
71
- fs: string | NodeProxy
72
- vert: string | NodeProxy
73
- frag: string | NodeProxy
74
- vertex: string | NodeProxy
75
- fragment: string | NodeProxy
72
+ vs?: string | Vec4
73
+ fs?: string | Vec4
74
+ vert?: string | Vec4
75
+ frag?: string | Vec4
76
+ vertex?: string | Vec4
77
+ fragment?: string | Vec4
76
78
 
77
79
  /**
78
80
  * core state
@@ -86,13 +88,13 @@ export type GL = EventState<{
86
88
  * events
87
89
  */
88
90
  ref?: any
89
- init(): void
90
- loop(): void
91
91
  mount(): void
92
92
  clean(): void
93
+ error(e?: string): void
93
94
  render(): void
94
95
  resize(e?: Event): void
95
96
  mousemove(e: Event): void
97
+ loop(): void
96
98
 
97
99
  /**
98
100
  * setter
@@ -1,27 +1,26 @@
1
- const createShader = (c: WebGLRenderingContext, source: string, type: number) => {
1
+ const createShader = (c: WebGLRenderingContext, source: string, type: number, onError = console.warn) => {
2
2
  const shader = c.createShader(type)
3
- if (!shader) throw new Error('Failed to create shader')
3
+ if (!shader) return onError('Failed to create shader')
4
4
  c.shaderSource(shader, source.trim())
5
5
  c.compileShader(shader)
6
6
  if (c.getShaderParameter(shader, c.COMPILE_STATUS)) return shader
7
7
  const error = c.getShaderInfoLog(shader)
8
8
  c.deleteShader(shader)
9
- console.warn(`Could not compile shader: ${error}`)
9
+ onError(`Could not compile shader: ${error}`)
10
10
  }
11
11
 
12
- export const createProgram = (c: WebGLRenderingContext, vert: string, frag: string, onError = () => {}) => {
12
+ export const createProgram = (c: WebGLRenderingContext, vert: string, frag: string, onError = console.warn) => {
13
13
  const pg = c.createProgram()
14
- const fs = createShader(c, frag, c.FRAGMENT_SHADER)
15
- const vs = createShader(c, vert, c.VERTEX_SHADER)
16
- if (!fs || !vs) return onError()
17
- c.attachShader(pg, vs)
18
- c.attachShader(pg, fs)
14
+ const fs = createShader(c, frag, c.FRAGMENT_SHADER, onError)
15
+ const vs = createShader(c, vert, c.VERTEX_SHADER, onError)
16
+ if (!fs || !vs) return
17
+ c.attachShader(pg, vs!)
18
+ c.attachShader(pg, fs!)
19
19
  c.linkProgram(pg)
20
20
  if (c.getProgramParameter(pg, c.LINK_STATUS)) return pg
21
21
  const error = c.getProgramInfoLog(pg)
22
22
  c.deleteProgram(pg)
23
- onError()
24
- console.warn(`Could not link program: ${error}`)
23
+ onError(`Could not link program: ${error}`)
25
24
  }
26
25
 
27
26
  export const createVbo = (c: WebGLRenderingContext, data: number[]) => {
package/src/webgl.ts CHANGED
@@ -4,24 +4,29 @@ import { is } from './utils/helpers'
4
4
  import { createAttrib, createIbo, createProgram, createTexture, createVbo, getStride } from './utils/program'
5
5
  import type { GL, WebGLState } from './types'
6
6
 
7
- export const webgl = async (gl: Partial<GL>) => {
7
+ export const webgl = async (gl: GL) => {
8
8
  const c = gl.el!.getContext('webgl2')!
9
9
  const config = { isWebGL: true, gl }
10
10
  const fs = fragment(gl.fs, config)
11
11
  const vs = vertex(gl.vs, config)
12
- const pg = createProgram(c, vs, fs, () => void (gl.isLoop = false))!
12
+ const pg = createProgram(c, vs, fs, gl.error)!
13
13
  c.useProgram(pg)
14
14
 
15
- let _activeUnit = 0
15
+ let activeUnit = 0
16
16
  const uniforms = cached((key) => c.getUniformLocation(pg, key))
17
17
  const attribs = cached((key) => c.getAttribLocation(pg, key))
18
- const units = cached(() => _activeUnit++)
18
+ const units = cached(() => activeUnit++)
19
19
 
20
- const clean = () => c.deleteProgram(pg)
20
+ const clean = () => {
21
+ c.deleteProgram(pg)
22
+ c.getExtension('WEBGL_lose_context')?.loseContext()
23
+ gl.el.width = 1
24
+ gl.el.height = 1
25
+ }
21
26
 
22
27
  const render = () => {
23
28
  c.clear(c.COLOR_BUFFER_BIT)
24
- c.viewport(0, 0, ...gl.size!)
29
+ c.viewport(0, 0, ...gl.size)
25
30
  c.drawArrays(c.TRIANGLES, 0, 3)
26
31
  }
27
32
 
@@ -29,7 +34,7 @@ export const webgl = async (gl: Partial<GL>) => {
29
34
  const loc = attribs(key, true)
30
35
  const vbo = createVbo(c, value)
31
36
  const ibo = createIbo(c, iboValue)
32
- const str = getStride(gl.count!, value, iboValue)
37
+ const str = getStride(gl.count, value, iboValue)
33
38
  createAttrib(c, str, loc, vbo, ibo)
34
39
  }
35
40
 
@@ -43,14 +48,18 @@ export const webgl = async (gl: Partial<GL>) => {
43
48
  }
44
49
 
45
50
  const _texture = (key: string, src: string) => {
51
+ gl.loading++
46
52
  const image = new Image()
47
53
  Object.assign(image, { src, crossOrigin: 'anonymous' })
48
54
  image.decode().then(() => {
49
55
  const loc = uniforms(key)
50
56
  const unit = units(key)
51
57
  createTexture(c, image, loc, unit)
58
+ gl.loading--
52
59
  })
53
60
  }
54
61
 
55
- return { render, clean, _attribute, _uniform, _texture, webgl: { context: c, program: pg } as WebGLState }
62
+ const webgl: WebGLState = { context: c, program: pg }
63
+
64
+ return { webgl, render, clean, _attribute, _uniform, _texture }
56
65
  }
package/src/webgpu.ts CHANGED
@@ -15,14 +15,14 @@ import {
15
15
  import type { GL, WebGPUState } from './types'
16
16
  import { fragment, vertex } from './node'
17
17
 
18
- export const webgpu = async (gl: Partial<GL>) => {
18
+ export const webgpu = async (gl: GL) => {
19
19
  const context = gl.el!.getContext('webgpu') as GPUCanvasContext
20
20
  const { device, format } = await createDevice(context)
21
+ device.onuncapturederror = (e) => gl.error(e.error.message)
21
22
  const bindings = createBindings()
22
23
  let frag: string
23
24
  let vert: string
24
25
  let flush = (_pass: GPURenderPassEncoder) => {}
25
- let imageLoading = 0
26
26
  let needsUpdate = true
27
27
  let depthTexture: GPUTexture
28
28
 
@@ -42,7 +42,7 @@ export const webgpu = async (gl: Partial<GL>) => {
42
42
 
43
43
  const attribs = cached((_key, value: number[]) => {
44
44
  needsUpdate = true
45
- const stride = value.length / gl.count!
45
+ const stride = value.length / gl.count
46
46
  const { location } = bindings.attrib()
47
47
  const { array, buffer } = createAttribBuffer(device, value)
48
48
  return { array, buffer, location, stride }
@@ -60,7 +60,7 @@ export const webgpu = async (gl: Partial<GL>) => {
60
60
  pass.setPipeline(pipeline)
61
61
  bindGroups.forEach((v, i) => pass.setBindGroup(i, v))
62
62
  vertexBuffers.forEach((v, i) => pass.setVertexBuffer(i, v))
63
- pass.draw(gl.count!, 1, 0, 0)
63
+ pass.draw(gl.count, 1, 0, 0)
64
64
  pass.end()
65
65
  }
66
66
  }
@@ -71,7 +71,7 @@ export const webgpu = async (gl: Partial<GL>) => {
71
71
  frag = fragment(gl.fs, config)
72
72
  vert = vertex(gl.vs, config)
73
73
  }
74
- if (imageLoading) return // MEMO: loading after build node
74
+ if (gl.loading) return // MEMO: loading after build node
75
75
  if (needsUpdate) update()
76
76
  needsUpdate = false
77
77
  const encoder = device.createCommandEncoder()
@@ -86,7 +86,11 @@ export const webgpu = async (gl: Partial<GL>) => {
86
86
  }
87
87
 
88
88
  const clean = () => {
89
+ device.destroy()
89
90
  depthTexture?.destroy()
91
+ for (const { texture } of textures.map.values()) texture.destroy()
92
+ for (const { buffer } of uniforms.map.values()) buffer.destroy()
93
+ for (const { buffer } of attribs.map.values()) buffer.destroy()
90
94
  }
91
95
 
92
96
  const _attribute = (key = '', value: number[]) => {
@@ -103,13 +107,13 @@ export const webgpu = async (gl: Partial<GL>) => {
103
107
  }
104
108
 
105
109
  const _texture = (key: string, src: string) => {
106
- imageLoading++
110
+ gl.loading++
107
111
  const source = Object.assign(new Image(), { src, crossOrigin: 'anonymous' })
108
112
  source.decode().then(() => {
109
113
  const { width, height } = source
110
114
  const { texture } = textures(key, width, height)
111
115
  device.queue.copyExternalImageToTexture({ source }, { texture }, { width, height })
112
- imageLoading--
116
+ gl.loading--
113
117
  })
114
118
  }
115
119