@bigmistqke/view.gl 0.1.19 → 0.3.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/README.md +82 -27
- package/dev/dist/404.html +19 -0
- package/dev/dist/assets/bezier-DrA4cU_H.js +292 -0
- package/dev/dist/assets/game-of-life-BYlzWhEL.js +186 -0
- package/dev/dist/assets/glsl-composition-D_BaFFij.js +97 -0
- package/dev/dist/assets/grid-DfXHNLBm.js +181 -0
- package/dev/dist/assets/index-C2N3u8wj.css +12 -0
- package/dev/dist/assets/index-D-N0FDYs.js +110 -0
- package/dev/dist/assets/main-CSE2fki3.js +32 -0
- package/dev/dist/assets/overview-IeUhUflE.js +80 -0
- package/dev/dist/assets/pix-sim-DMJJA_WO.js +500 -0
- package/dev/dist/assets/ray-casting-DTQetDPd.js +411 -0
- package/dev/dist/assets/ray-casting-modules-Dkfw4tdc.js +765 -0
- package/dev/dist/assets/sdf-CS0uBonx.js +66 -0
- package/dev/dist/assets/symbol-BL_7GJ0M.js +67 -0
- package/dev/dist/assets/tag-C0Vskpp8.js +833 -0
- package/dev/dist/assets/tetris-D8mokodr.js +344 -0
- package/dev/dist/assets/utils-2dzuv_bW.js +62 -0
- package/dev/dist/index.html +51 -0
- package/dist/chunk-BZDGEIOT.mjs +278 -0
- package/dist/chunk-BZDGEIOT.mjs.map +1 -0
- package/dist/chunk-X4M3LV4R.mjs +433 -0
- package/dist/chunk-X4M3LV4R.mjs.map +1 -0
- package/dist/gl.d.mts +2 -2
- package/dist/gl.mjs +1 -1
- package/dist/index.d.mts +23 -6
- package/dist/index.mjs +9 -2
- package/dist/tag.d.mts +6 -1
- package/dist/tag.mjs +13 -5
- package/dist/tag.mjs.map +1 -1
- package/dist/{types-DTSPQclW.d.mts → types-CNdqh7tB.d.mts} +121 -8
- package/package.json +1 -1
- package/src/gl.ts +13 -2
- package/src/index.ts +294 -122
- package/src/tag.ts +18 -2
- package/src/types.ts +127 -7
- package/src/utils.ts +45 -10
- package/test/index.test.ts +339 -84
- package/test/mocks/webgl.ts +20 -0
- package/test/tag.test.ts +41 -0
- package/dist/chunk-CJTT7WPV.mjs +0 -75
- package/dist/chunk-CJTT7WPV.mjs.map +0 -1
- package/dist/chunk-ZP4HP5H7.mjs +0 -405
- package/dist/chunk-ZP4HP5H7.mjs.map +0 -1
package/src/types.ts
CHANGED
|
@@ -322,11 +322,58 @@ type FormatToArray = {
|
|
|
322
322
|
uint8: Uint8Array
|
|
323
323
|
}
|
|
324
324
|
|
|
325
|
-
|
|
325
|
+
/**
|
|
326
|
+
* What a participant contributes to a vertex array.
|
|
327
|
+
*
|
|
328
|
+
* `enableVertexAttribArray`, `vertexAttribPointer`, `vertexAttribDivisor` and
|
|
329
|
+
* the `ELEMENT_ARRAY_BUFFER` binding all write into whichever vertex array is
|
|
330
|
+
* bound when they run — they name no destination of their own. That is what
|
|
331
|
+
* makes them a participant in something rather than a property of themselves,
|
|
332
|
+
* and why `vao()` exists: it binds the array first, then asks each participant
|
|
333
|
+
* to write itself in.
|
|
334
|
+
*
|
|
335
|
+
* The returned function undoes the write. It is only used where there is no
|
|
336
|
+
* vertex array to hold the state — a WebGL1 context without
|
|
337
|
+
* `OES_vertex_array_object` — since a real vertex array is thrown away whole.
|
|
338
|
+
*/
|
|
339
|
+
export interface VertexArrayParticipant {
|
|
340
|
+
applyToVertexArray(): () => void
|
|
341
|
+
/**
|
|
342
|
+
* State the CONTEXT holds rather than the vertex array, re-applied on every
|
|
343
|
+
* bind because no array can keep it.
|
|
344
|
+
*
|
|
345
|
+
* There is exactly one such thing: the current generic vertex attribute
|
|
346
|
+
* values, which an attribute reads when its array is disabled. The enable
|
|
347
|
+
* flag saying to read them is vertex-array state; the values themselves are
|
|
348
|
+
* not. So a constant source splits across the two hooks — and the tempting
|
|
349
|
+
* optimisation of skipping this when nothing changed would let one draw's
|
|
350
|
+
* constants leak into the next.
|
|
351
|
+
*/
|
|
352
|
+
applyToContext?(): void
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
export interface AttributeMethods<T extends AttributeDefinition = AttributeDefinition>
|
|
356
|
+
extends VertexArrayParticipant {
|
|
326
357
|
buffer: WebGLBuffer
|
|
327
|
-
/**
|
|
358
|
+
/**
|
|
359
|
+
* Apply this attribute to the DEFAULT vertex array, returning a disposer.
|
|
360
|
+
*
|
|
361
|
+
* Explicitly the default one: these calls have no destination of their own,
|
|
362
|
+
* so without binding first this would edit whichever array happened to be
|
|
363
|
+
* bound — and a vertex array keeps what it is given, so the damage would
|
|
364
|
+
* outlive the call. Use `vao()` to build an array of your own.
|
|
365
|
+
*/
|
|
328
366
|
bind(): () => void
|
|
329
367
|
set(data: FormatToArray[ResolvedFormat<T>], usage?: GLUsage): { bind(): () => void }
|
|
368
|
+
/**
|
|
369
|
+
* Delete the buffer, if this attribute is the one that made it.
|
|
370
|
+
*
|
|
371
|
+
* A buffer named by the schema came from somewhere else and is deleted by
|
|
372
|
+
* whoever made it — a shared buffer is the point of passing one in, and one
|
|
373
|
+
* view cannot know whether the others are done. So this is safe to call
|
|
374
|
+
* twice and safe to call on a borrowed buffer, and it is not a way to free
|
|
375
|
+
* one: dispose the view that created it.
|
|
376
|
+
*/
|
|
330
377
|
dispose(): void
|
|
331
378
|
}
|
|
332
379
|
|
|
@@ -354,13 +401,55 @@ export interface InterleavedAttributeDefinition {
|
|
|
354
401
|
|
|
355
402
|
export type InterleavedAttributeSchema = Record<string | symbol, InterleavedAttributeDefinition>
|
|
356
403
|
|
|
404
|
+
/**
|
|
405
|
+
* A source is where one draw's values for a layout come from. Both kinds are
|
|
406
|
+
* participants, so either can go into a `vao()`.
|
|
407
|
+
*/
|
|
408
|
+
export interface Source extends VertexArrayParticipant {
|
|
409
|
+
/**
|
|
410
|
+
* Apply this source to the DEFAULT vertex array, returning a disposer. See
|
|
411
|
+
* `AttributeMethods.bind` — and prefer `vao()`, which is the only way to get
|
|
412
|
+
* a source and its fellow participants into an array of their own.
|
|
413
|
+
*/
|
|
414
|
+
bind(): () => void
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
export interface BufferSource extends Source {
|
|
418
|
+
/**
|
|
419
|
+
* The same buffer, stepped once per instance rather than once per vertex.
|
|
420
|
+
*
|
|
421
|
+
* A divisor is a property of the draw, not of the data — the same markers
|
|
422
|
+
* are an instanced fleet in one draw and a single mesh in the next — so it
|
|
423
|
+
* is chosen here rather than declared in the schema.
|
|
424
|
+
*/
|
|
425
|
+
perInstance: Source
|
|
426
|
+
set(data: Float32Array, usage?: GLUsage): void
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
export interface ConstantAttributeMethods {
|
|
430
|
+
set(...values: number[]): void
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Per-key setters over the same layout the buffer source uses — a constant
|
|
435
|
+
* attribute is a uniform in all but name, so it is written like one.
|
|
436
|
+
*/
|
|
437
|
+
export type ConstantSource<T extends InterleavedAttributeLayout[]> = Source & {
|
|
438
|
+
[K in T[number] as K['key'] extends string ? K['key'] : never]: ConstantAttributeMethods
|
|
439
|
+
}
|
|
440
|
+
|
|
357
441
|
export interface InterleavedAttributeMethods<
|
|
358
442
|
T extends InterleavedAttributeLayout[] = InterleavedAttributeLayout[],
|
|
359
443
|
> {
|
|
444
|
+
buffer: BufferSource
|
|
445
|
+
constant: ConstantSource<T>
|
|
446
|
+
dispose(): void
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
export interface VertexArrayMethods {
|
|
360
450
|
/** Binds the vertex array, returning a disposer that restores the previous one */
|
|
361
451
|
bind(): () => void
|
|
362
452
|
unbind(): void
|
|
363
|
-
set(data: Float32Array, usage?: GLUsage): void
|
|
364
453
|
dispose(): void
|
|
365
454
|
}
|
|
366
455
|
|
|
@@ -381,7 +470,7 @@ export interface BufferDefinition {
|
|
|
381
470
|
|
|
382
471
|
export type BufferSchema = Record<string | symbol, BufferDefinition>
|
|
383
472
|
|
|
384
|
-
export interface BufferMethods {
|
|
473
|
+
export interface BufferMethods extends VertexArrayParticipant {
|
|
385
474
|
set(data: Float32Array | Uint16Array | Uint32Array): void
|
|
386
475
|
/** Binds the buffer, returning a disposer that restores the previous binding */
|
|
387
476
|
bind(): () => void
|
|
@@ -422,6 +511,12 @@ export interface TextureDefinition {
|
|
|
422
511
|
export interface Framebuffer {
|
|
423
512
|
texture: WebGLTexture
|
|
424
513
|
framebuffer: WebGLFramebuffer
|
|
514
|
+
/**
|
|
515
|
+
* Delete the framebuffer, and the texture only if `createFramebuffer` made
|
|
516
|
+
* it. A texture handed in belongs to whoever made it. Idempotent, and exactly
|
|
517
|
+
* what aborting the signal does.
|
|
518
|
+
*/
|
|
519
|
+
dispose(): void
|
|
425
520
|
}
|
|
426
521
|
|
|
427
522
|
/**********************************************************************************/
|
|
@@ -537,11 +632,16 @@ export interface ViewOptions {
|
|
|
537
632
|
signal?: AbortSignal
|
|
538
633
|
}
|
|
539
634
|
|
|
635
|
+
/**
|
|
636
|
+
* What a program has names for. Buffers are absent on purpose: a buffer has no
|
|
637
|
+
* name in the source, so it cannot be resolved against a program the way a
|
|
638
|
+
* uniform or an attribute is, and its lifetime is rarely a program's. Build one
|
|
639
|
+
* with `bufferView` and pass it to `vao()` alongside the attributes.
|
|
640
|
+
*/
|
|
540
641
|
export interface ViewSchema {
|
|
541
642
|
uniforms?: UniformSchema
|
|
542
643
|
attributes?: AttributeSchema
|
|
543
644
|
interleavedAttributes?: InterleavedAttributeSchema
|
|
544
|
-
buffers?: BufferSchema
|
|
545
645
|
}
|
|
546
646
|
|
|
547
647
|
type PartialSchema<T> =
|
|
@@ -551,7 +651,6 @@ export interface ViewSchemaPartial {
|
|
|
551
651
|
uniforms?: PartialSchema<UniformSchema>
|
|
552
652
|
attributes?: PartialSchema<AttributeSchema>
|
|
553
653
|
interleavedAttributes?: PartialSchema<InterleavedAttributeSchema>
|
|
554
|
-
buffers?: PartialSchema<BufferSchema>
|
|
555
654
|
}
|
|
556
655
|
|
|
557
656
|
export type View<T extends ViewSchema = ViewSchema> = {
|
|
@@ -561,8 +660,24 @@ export type View<T extends ViewSchema = ViewSchema> = {
|
|
|
561
660
|
interleavedAttributes: T['interleavedAttributes'] extends InterleavedAttributeSchema
|
|
562
661
|
? Prettify<InterleavedAttributeView<T['interleavedAttributes']>>
|
|
563
662
|
: {}
|
|
564
|
-
buffers: T['buffers'] extends BufferSchema ? Prettify<BufferView<T['buffers']>> : {}
|
|
565
663
|
uniforms: T['uniforms'] extends UniformSchema ? Prettify<UniformView<T['uniforms']>> : {}
|
|
664
|
+
/**
|
|
665
|
+
* Build a vertex array from the participants one draw needs — its attributes,
|
|
666
|
+
* its interleaved layouts, its element buffer.
|
|
667
|
+
*
|
|
668
|
+
* This is the one member the schema cannot declare, because its input is the
|
|
669
|
+
* schema's own output. It is also the only place a vertex array is created:
|
|
670
|
+
* the participants no longer make one each, so which array they end up in is
|
|
671
|
+
* something you say rather than something you inherit from call order.
|
|
672
|
+
*/
|
|
673
|
+
vao(participants: VertexArrayParticipant[]): VertexArrayMethods
|
|
674
|
+
/**
|
|
675
|
+
* Delete everything the view made: the buffers behind its attributes and
|
|
676
|
+
* layouts, and any vertex array still held from `vao()`. Buffers named by the
|
|
677
|
+
* schema are left alone — those belong to whoever made them. Idempotent, and
|
|
678
|
+
* exactly what aborting the signal does.
|
|
679
|
+
*/
|
|
680
|
+
dispose(): void
|
|
566
681
|
}
|
|
567
682
|
|
|
568
683
|
/**********************************************************************************/
|
|
@@ -791,5 +906,10 @@ export type CompileResult<
|
|
|
791
906
|
view: Prettify<View<TSchema>>
|
|
792
907
|
vertex: string
|
|
793
908
|
fragment: string
|
|
909
|
+
/**
|
|
910
|
+
* Delete the program and everything its view made. Idempotent, and
|
|
911
|
+
* exactly what aborting the signal does.
|
|
912
|
+
*/
|
|
913
|
+
dispose(): void
|
|
794
914
|
}
|
|
795
915
|
: never
|
package/src/utils.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
KIND_TO_UNIFORM_FN_NAME_MAP,
|
|
7
7
|
TextureDefinition,
|
|
8
8
|
UniformKind,
|
|
9
|
+
ViewOptions,
|
|
9
10
|
} from './types'
|
|
10
11
|
|
|
11
12
|
export function assertedNotNullish<T>(value: T, message?: string): NonNullable<T> {
|
|
@@ -13,6 +14,24 @@ export function assertedNotNullish<T>(value: T, message?: string): NonNullable<T
|
|
|
13
14
|
return value
|
|
14
15
|
}
|
|
15
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Wraps a teardown so it runs once.
|
|
19
|
+
*
|
|
20
|
+
* Two reasons, and both bite. A disposer is per `bind()`, and undoing twice
|
|
21
|
+
* would put back state a later `bind()` is relying on. And a `dispose()` that
|
|
22
|
+
* deletes twice invalidates a handle someone else may still be holding — the
|
|
23
|
+
* object survives while it is bound, so the fault surfaces later, somewhere
|
|
24
|
+
* else. Idempotent is the only safe shape for either.
|
|
25
|
+
*/
|
|
26
|
+
export function once(teardown: () => void): () => void {
|
|
27
|
+
let done = false
|
|
28
|
+
return () => {
|
|
29
|
+
if (done) return
|
|
30
|
+
done = true
|
|
31
|
+
teardown()
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
16
35
|
/**********************************************************************************/
|
|
17
36
|
/* */
|
|
18
37
|
/* Kind To Uniform Name */
|
|
@@ -114,8 +133,9 @@ export function createTexture(
|
|
|
114
133
|
height,
|
|
115
134
|
}: TextureDefinition,
|
|
116
135
|
data?: ArrayBufferView | null,
|
|
136
|
+
{ signal }: ViewOptions = {},
|
|
117
137
|
): WebGLTexture {
|
|
118
|
-
const texture = gl.createTexture()
|
|
138
|
+
const texture = assertedNotNullish(gl.createTexture(), 'Failed to create texture')
|
|
119
139
|
|
|
120
140
|
function getTextureConstant(name: string) {
|
|
121
141
|
if (!(name in gl)) {
|
|
@@ -137,13 +157,17 @@ export function createTexture(
|
|
|
137
157
|
data ?? null,
|
|
138
158
|
)
|
|
139
159
|
|
|
140
|
-
console.log(minFilter)
|
|
141
160
|
// Set texture parameters
|
|
142
161
|
gl.texParameteri(gl[target], gl.TEXTURE_MIN_FILTER, gl[minFilter])
|
|
143
162
|
gl.texParameteri(gl[target], gl.TEXTURE_MAG_FILTER, gl[magFilter])
|
|
144
163
|
gl.texParameteri(gl[target], gl.TEXTURE_WRAP_S, gl[wrapS])
|
|
145
164
|
gl.texParameteri(gl[target], gl.TEXTURE_WRAP_T, gl[wrapT])
|
|
146
165
|
|
|
166
|
+
signal?.addEventListener(
|
|
167
|
+
'abort',
|
|
168
|
+
once(() => gl.deleteTexture(texture)),
|
|
169
|
+
)
|
|
170
|
+
|
|
147
171
|
return texture
|
|
148
172
|
}
|
|
149
173
|
|
|
@@ -162,7 +186,7 @@ const FRAMEBUFFER_ATTACHMENT_MAP = {
|
|
|
162
186
|
|
|
163
187
|
class FramebufferError extends Error {
|
|
164
188
|
constructor(gl: GL, status: number) {
|
|
165
|
-
let errorMessage =
|
|
189
|
+
let errorMessage = 'Framebuffer not complete. Status: '
|
|
166
190
|
switch (status) {
|
|
167
191
|
case gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
|
|
168
192
|
errorMessage += 'FRAMEBUFFER_INCOMPLETE_ATTACHMENT'
|
|
@@ -185,16 +209,15 @@ class FramebufferError extends Error {
|
|
|
185
209
|
|
|
186
210
|
export function createFramebuffer(
|
|
187
211
|
gl: GL,
|
|
188
|
-
{ attachment, texture, ...
|
|
212
|
+
{ attachment, texture: providedTexture, ...definition }: FramebufferDefinition,
|
|
213
|
+
{ signal }: ViewOptions = {},
|
|
189
214
|
) {
|
|
190
|
-
// Create texture for the framebuffer
|
|
191
|
-
|
|
215
|
+
// Create texture for the framebuffer, unless one was handed in. Which one it
|
|
216
|
+
// is decides who deletes it below — the same rule the attribute buffers follow.
|
|
217
|
+
const texture = providedTexture ?? createTexture(gl, definition)
|
|
192
218
|
|
|
193
219
|
// Create framebuffer
|
|
194
|
-
const framebuffer = assertedNotNullish(
|
|
195
|
-
gl.createFramebuffer(),
|
|
196
|
-
`Failed to create framebuffer: ${name}`,
|
|
197
|
-
)
|
|
220
|
+
const framebuffer = assertedNotNullish(gl.createFramebuffer(), 'Failed to create framebuffer')
|
|
198
221
|
|
|
199
222
|
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer)
|
|
200
223
|
|
|
@@ -213,9 +236,21 @@ export function createFramebuffer(
|
|
|
213
236
|
throw new FramebufferError(gl, status)
|
|
214
237
|
}
|
|
215
238
|
|
|
239
|
+
const dispose = once(() => {
|
|
240
|
+
gl.deleteFramebuffer(framebuffer)
|
|
241
|
+
// A texture handed in belongs to whoever made it — it commonly outlives the
|
|
242
|
+
// framebuffer, ping-ponged between two of them.
|
|
243
|
+
if (!providedTexture) {
|
|
244
|
+
gl.deleteTexture(texture)
|
|
245
|
+
}
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
signal?.addEventListener('abort', dispose)
|
|
249
|
+
|
|
216
250
|
return {
|
|
217
251
|
texture,
|
|
218
252
|
framebuffer,
|
|
253
|
+
dispose,
|
|
219
254
|
}
|
|
220
255
|
}
|
|
221
256
|
|