@bigmistqke/view.gl 0.3.0 → 0.4.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 CHANGED
@@ -110,11 +110,22 @@ The complete schema object that defines all WebGL resources. Contains mappings f
110
110
  - [`UniformSchema`](#-uniformschema) - uniform variable definitions
111
111
  - [`AttributeSchema`](#-attributeschema) - vertex attribute definitions
112
112
  - [`InterleavedAttributeSchema`](#-interleavedattributeschema) - interleaved vertex data definitions
113
+ - [`BufferSchema`](#-bufferschema) - buffers the view owns
113
114
 
114
- A schema names what the program has names for, so buffers are not part of it: a
115
- buffer has no name in the source to resolve against the program, and its lifetime
116
- is rarely a program's — the same buffer often feeds several. Build one with
117
- [`bufferView`](#-bufferview) and hand it to `vao()` alongside the attributes.
115
+ A buffer is the one schema member with no name in the source, so it is not
116
+ resolved against the program the way a uniform or an attribute is — a buffer key
117
+ is a label for the reader. What putting it in the schema decides is its
118
+ **lifetime**, and that is the question worth answering at the declaration:
119
+
120
+ | the buffer | declare it | disposed by |
121
+ | --- | --- | --- |
122
+ | lives and dies with the view | `buffers:` in the schema | the view |
123
+ | outlives the view, or is shared between views | a standalone [`bufferView`](#-bufferview) | you |
124
+ | belongs to somebody else | name it on an attribute | nobody — it is borrowed |
125
+
126
+ An index buffer whose lifetime is its program's belongs in the schema, beside
127
+ the attributes it is drawn with, on the one signal. A quad cached per context,
128
+ or a buffer handed from one program's view to another's, is its own thing.
118
129
 
119
130
  <details>
120
131
  <summary>TypeScript Types</summary>
@@ -158,7 +169,7 @@ or aborting twice, deletes each resource exactly once.
158
169
 
159
170
  | creates | disposed by |
160
171
  | --- | --- |
161
- | `view()` | its own attribute and layout buffers, and vertex arrays still held from `vao()` |
172
+ | `view()` | its own attribute, layout and schema buffers, and vertex arrays still held from `vao()` |
162
173
  | `compile()` | the program, and its view |
163
174
  | `attributeView` / `interleavedAttributeView` | the buffer, unless the schema named one |
164
175
  | `bufferView` | its buffers |
@@ -682,8 +693,9 @@ const { program, schema, view } = compile(gl, vertexShader, fragmentShader, {
682
693
  // The override schema is merged with the extracted schema
683
694
  view.uniforms.customTime.set(123.45)
684
695
 
685
- // An index buffer is its own thing — no program names it, and it outlives any
686
- // one of them. Build it with bufferView and pass it into the vertex array.
696
+ // An index buffer that outlives this program — shared between views, or cached
697
+ // per context — is its own thing. One that dies with the view goes in the
698
+ // schema instead, and is disposed with it.
687
699
  const buffers = bufferView(gl, { indices: { target: 'ELEMENT_ARRAY_BUFFER' } })
688
700
  buffers.indices.set(indexData)
689
701
  const vao = view.vao([view.attributes.position, buffers.indices])
@@ -37,10 +37,12 @@ function toID(key) {
37
37
  function view(gl, program, schema, { signal } = {}) {
38
38
  const attributes = !schema.attributes ? void 0 : attributeView(gl, program, schema.attributes);
39
39
  const interleavedAttributes = !schema.interleavedAttributes ? void 0 : interleavedAttributeView(gl, program, schema.interleavedAttributes);
40
+ const buffers = !schema.buffers ? void 0 : bufferView(gl, schema.buffers);
40
41
  const vertexArrays = /* @__PURE__ */ new Set();
41
42
  const dispose = once(() => {
42
43
  if (attributes) forEachObject(attributes, (value) => value.dispose());
43
44
  if (interleavedAttributes) forEachObject(interleavedAttributes, (value) => value.dispose());
45
+ if (buffers) forEachObject(buffers, (value) => value.dispose());
44
46
  vertexArrays.forEach((vertexArray) => vertexArray.dispose());
45
47
  vertexArrays.clear();
46
48
  });
@@ -49,6 +51,7 @@ function view(gl, program, schema, { signal } = {}) {
49
51
  uniforms: !schema.uniforms ? void 0 : uniformView(gl, program, schema.uniforms),
50
52
  attributes,
51
53
  interleavedAttributes,
54
+ buffers,
52
55
  vao(participants) {
53
56
  const vertexArray = vaoView(gl, participants);
54
57
  vertexArrays.add(vertexArray);
@@ -430,4 +433,4 @@ export {
430
433
  interleavedAttributeView,
431
434
  bufferView
432
435
  };
433
- //# sourceMappingURL=chunk-X4M3LV4R.mjs.map
436
+ //# sourceMappingURL=chunk-H56LJYS5.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { getInstancedArrays, getVertexArrayObject } from './gl'\nimport type {\n AttributeFormat,\n AttributeKind,\n AttributeMethods,\n AttributeSchema,\n AttributeView,\n BufferSchema,\n BufferView,\n GL,\n UniformView as InferUniformView,\n GLUsage,\n InterleavedAttributeLayout,\n InterleavedAttributeMethods,\n InterleavedAttributeSchema,\n InterleavedAttributeView,\n UniformSchema,\n VertexArrayMethods,\n VertexArrayParticipant,\n View,\n ViewOptions,\n ViewSchema,\n} from './types'\nimport {\n isSamplerKind,\n kindToUniformFnName,\n isMatKind,\n assertedNotNullish,\n kindToSize,\n forEachObject,\n once,\n} from './utils'\nimport { createUpsertMap, mapObject } from './utils'\nexport * from './types'\n// Documented under Utils but reachable from nowhere until now: utils is not a\n// build entry, and named rather than star so the internal helpers stay internal.\nexport { createFramebuffer, createTexture } from './utils'\n\n/**********************************************************************************/\n/* */\n/* To ID */\n/* */\n/**********************************************************************************/\n\nlet index = 0\nconst PREFIX = 'VIEW_GL_ALIAS'\n// Firefox has currently a bug where it can not handle symbol as WeakRef / key for WeakMap\n// see https://bugzilla.mozilla.org/show_bug.cgi?id=1710433\nconst HAS_WEAK_SYMBOL = (() => {\n try {\n const symbol = Symbol()\n new WeakMap().set(symbol, '')\n return true\n } catch {\n return false\n }\n})()\n// NOTE: fallback to Map will currently cause a minor memory leak.\nconst SYMBOL_MAP = createUpsertMap(HAS_WEAK_SYMBOL ? WeakMap<symbol, string> : Map<symbol, string>)\n\nexport function toID(key: string | number | symbol) {\n if (typeof key === 'string') {\n return key\n }\n if (typeof key === 'symbol') {\n return SYMBOL_MAP.getOrInsert(key, () => `${PREFIX}_${index++}`)\n }\n return key.toString()\n}\n\n/**********************************************************************************/\n/* */\n/* View */\n/* */\n/**********************************************************************************/\n\nexport function view<TSchema extends ViewSchema>(\n gl: GL,\n program: WebGLProgram,\n schema: TSchema,\n { signal }: ViewOptions = {},\n): View<TSchema> {\n // The sub-views are built without the signal and the view wires disposal\n // once, so that `dispose()` and aborting do the same thing rather than each\n // doing half of it.\n const attributes = !schema.attributes ? undefined : attributeView(gl, program, schema.attributes)\n const interleavedAttributes = !schema.interleavedAttributes\n ? undefined\n : interleavedAttributeView(gl, program, schema.interleavedAttributes)\n // Owned by the view, on the view's signal. This is the line the split was\n // really about: it used to read `bufferView(gl, schema.buffers)` with the\n // options dropped, so a view's buffers were the only resources that still\n // needed disposing by hand. That was a missing argument rather than a wrong\n // model — a buffer whose lifetime IS the view's belongs with it.\n const buffers = !schema.buffers ? undefined : bufferView(gl, schema.buffers)\n\n // Vertex arrays are made on demand rather than declared, so they are the one\n // thing the view cannot dispose from the schema alone. Held until disposed —\n // by the view or by the caller — and dropped either way, so a view that hands\n // out an array per frame does not accumulate them.\n const vertexArrays = new Set<VertexArrayMethods>()\n\n const dispose = once(() => {\n if (attributes) forEachObject(attributes, value => value.dispose())\n if (interleavedAttributes) forEachObject(interleavedAttributes, value => value.dispose())\n if (buffers) forEachObject(buffers, value => value.dispose())\n vertexArrays.forEach(vertexArray => vertexArray.dispose())\n vertexArrays.clear()\n })\n\n signal?.addEventListener('abort', dispose)\n\n return {\n uniforms: !schema.uniforms ? undefined : uniformView(gl, program, schema.uniforms),\n attributes,\n interleavedAttributes,\n buffers,\n vao(participants: VertexArrayParticipant[]) {\n const vertexArray = vaoView(gl, participants)\n vertexArrays.add(vertexArray)\n return {\n ...vertexArray,\n dispose: once(() => {\n vertexArrays.delete(vertexArray)\n vertexArray.dispose()\n }),\n }\n },\n dispose,\n } as View<TSchema>\n}\n\n/**********************************************************************************/\n/* */\n/* Vertex Array */\n/* */\n/**********************************************************************************/\n\n/**\n * Bind the default vertex array, returning a disposer that puts the previous\n * one back. The pointer calls name no destination, so anything applied without\n * a vertex array of its own has to say which one it means — and a vertex array\n * keeps what it is given, so writing into a caller's array by accident would\n * outlive the call that did it.\n */\nfunction bindDefaultVertexArray(gl: GL): () => void {\n const feature = getVertexArrayObject(gl)\n if (!feature) {\n return () => {}\n }\n const previous = gl.getParameter(VERTEX_ARRAY_BINDING) as WebGLVertexArrayObject | null\n feature.bindVertexArray(null)\n return () => feature.bindVertexArray(previous)\n}\n\n/**\n * A vertex array over the participants one draw needs.\n *\n * Where the context has vertex arrays, each participant writes itself in once,\n * here, and `bind()` is a single `bindVertexArray`. Where it does not — WebGL1\n * without `OES_vertex_array_object` — there is nowhere to keep the state, so\n * `bind()` re-applies every participant and the disposer puts back what they\n * displaced. Same contract, and the emulation is why the name still fits.\n */\nexport function vaoView(\n gl: GL,\n participants: VertexArrayParticipant[],\n { signal }: ViewOptions = {},\n): VertexArrayMethods {\n const feature = getVertexArrayObject(gl)\n\n const methods: VertexArrayMethods = !feature\n ? {\n bind() {\n const restores = participants.map(participant => participant.applyToVertexArray())\n participants.forEach(participant => participant.applyToContext?.())\n return once(() => restores.forEach(restore => restore()))\n },\n unbind() {},\n dispose() {},\n }\n : (() => {\n const vertexArray = assertedNotNullish(feature.createVertexArray())\n const previous = gl.getParameter(VERTEX_ARRAY_BINDING) as WebGLVertexArrayObject | null\n feature.bindVertexArray(vertexArray)\n // Discarding the restorers is the point: the state lives in this array\n // now, and the array is thrown away whole.\n for (const participant of participants) {\n participant.applyToVertexArray()\n }\n feature.bindVertexArray(previous)\n\n return {\n bind() {\n const previousVertexArray = gl.getParameter(\n VERTEX_ARRAY_BINDING,\n ) as WebGLVertexArrayObject | null\n feature.bindVertexArray(vertexArray)\n // Context state the array cannot hold — see applyToContext.\n participants.forEach(participant => participant.applyToContext?.())\n return once(() => feature.bindVertexArray(previousVertexArray))\n },\n unbind() {\n feature.bindVertexArray(null)\n },\n dispose: once(() => feature.deleteVertexArray(vertexArray)),\n }\n })()\n\n signal?.addEventListener('abort', () => methods.dispose())\n\n return methods\n}\n\n/**********************************************************************************/\n/* */\n/* Uniform View */\n/* */\n/**********************************************************************************/\n\nexport function uniformView<T extends UniformSchema>(\n gl: GL,\n program: WebGLProgram,\n schema: T,\n): InferUniformView<T> {\n // @ts-expect-error - conditional return type based on size is hard to infer\n return mapObject(schema, ({ kind, size }, key) => {\n const name = toID(key)\n\n if (isSamplerKind(kind)) {\n const location = gl.getUniformLocation(program, name)\n return {\n set(arg: number) {\n gl.uniform1i(location, arg)\n },\n }\n }\n\n // Array uniform - support both bulk set and indexed access\n if (size) {\n const bulkFnName = `uniform${kindToUniformFnName(kind)}v`\n // @ts-ignore FIX WEBGL/WEBGL2 TYPES\n const bulkFn = gl[bulkFnName].bind(gl)\n const bulkLocation = gl.getUniformLocation(program, name)\n\n const elementFnName = `uniform${kindToUniformFnName(kind)}`\n // @ts-ignore FIX WEBGL/WEBGL2 TYPES\n const elementFn = gl[elementFnName].bind(gl)\n\n // Build array of element setters\n const elements: Array<{ set(...args: any[]): void }> = []\n for (let i = 0; i < size; i++) {\n const location = gl.getUniformLocation(program, `${name}[${i}]`)\n elements[i] = {\n set(...args: any[]) {\n elementFn(location, ...args)\n },\n }\n }\n\n // Return array-like object with bulk set\n return Object.assign(elements, {\n set(arg: Float32Array) {\n bulkFn(bulkLocation, arg)\n },\n })\n }\n\n // Non-array uniform\n const location = gl.getUniformLocation(program, name)\n const fnName = `uniform${kindToUniformFnName(kind)}`\n\n // @ts-ignore FIX WEBGL/WEBGL2 TYPES\n const fn = gl[fnName].bind(gl)\n\n if (isMatKind(kind)) {\n return {\n set(...args: any[]) {\n fn(location, false, args[0])\n },\n }\n }\n\n return {\n set(...args: any[]) {\n fn(location, ...args)\n },\n }\n })\n}\n\n/**********************************************************************************/\n/* */\n/* Attribute View */\n/* */\n/**********************************************************************************/\n\ntype GLType =\n | 'FLOAT'\n | 'INT'\n | 'UNSIGNED_INT'\n | 'SHORT'\n | 'UNSIGNED_SHORT'\n | 'BYTE'\n | 'UNSIGNED_BYTE'\n\nconst FORMAT_TO_GL_TYPE: Record<AttributeFormat, GLType> = {\n float32: 'FLOAT',\n int32: 'INT',\n uint32: 'UNSIGNED_INT',\n int16: 'SHORT',\n uint16: 'UNSIGNED_SHORT',\n int8: 'BYTE',\n uint8: 'UNSIGNED_BYTE',\n}\n\nconst FORMAT_BYTE_SIZE: Record<AttributeFormat, number> = {\n float32: 4,\n int32: 4,\n uint32: 4,\n int16: 2,\n uint16: 2,\n int8: 1,\n uint8: 1,\n}\n\nfunction defaultFormat(kind: AttributeKind): AttributeFormat {\n if (kind.startsWith('u')) return 'uint32'\n if (kind.startsWith('i')) return 'int32'\n return 'float32'\n}\n\n// Shared attribute helper functions\n// between attributeView and interleavedAttributeView\nfunction handleAttribute(\n gl: GL,\n location: number,\n size: number,\n stride: number,\n offset: number,\n glType: GLType,\n isIntegerKind: boolean,\n normalized: boolean,\n instanced?: boolean,\n) {\n gl.enableVertexAttribArray(location)\n if (isIntegerKind) {\n ;(gl as WebGL2RenderingContext).vertexAttribIPointer(location, size, gl[glType], stride, offset)\n } else {\n gl.vertexAttribPointer(location, size, gl[glType], normalized, stride, offset)\n }\n\n // Always stated, never inherited: the divisor belongs to the location rather\n // than to the program, so a location left at 1 by an earlier instanced\n // attribute would feed one value to every vertex here.\n // Get instanced-arrays-feature: extension if webgl, gl if webgl2\n const instancedArrays = getInstancedArrays(gl)\n if (instanced) {\n assertedNotNullish(instancedArrays).vertexAttribDivisor(location, 1)\n } else if (instancedArrays) {\n instancedArrays.vertexAttribDivisor(location, 0)\n }\n}\n\n// Same enum in webgl2 and in the webgl1 extensions, which expose no constants\nconst VERTEX_ATTRIB_ARRAY_DIVISOR = 0x88fe\nconst VERTEX_ARRAY_BINDING = 0x85b5\n\n// Reads the divisor currently attached to a location, 0 where instancing is\n// unavailable and nothing can have set one\nfunction readDivisor(gl: GL, location: number): number {\n return getInstancedArrays(gl)\n ? (gl.getVertexAttrib(location, VERTEX_ATTRIB_ARRAY_DIVISOR) as number)\n : 0\n}\n\nexport function attributeView<T extends AttributeSchema>(\n gl: GL,\n program: WebGLProgram,\n schema: T,\n { signal }: ViewOptions = {},\n): AttributeView<T> {\n const attributes = mapObject(\n schema,\n (\n { kind, format, normalized = false, instanced, buffer: providedBuffer },\n key,\n ): AttributeMethods => {\n const name = toID(key)\n\n // Whoever made the buffer deletes it. A schema can name a buffer that\n // belongs to another view — the quad `compile.toQuad` shares across every\n // program on a context, an attribute two programs step over — and\n // deleting one of those would take it out from under its owner.\n const buffer = providedBuffer ?? assertedNotNullish(gl.createBuffer())\n\n const location = gl.getAttribLocation(program, name)\n if (location < 0) {\n throw new Error(`Attribute '${name}' not found`)\n }\n\n const size = kindToSize(kind)\n const resolvedFormat = format ?? defaultFormat(kind)\n const glType = FORMAT_TO_GL_TYPE[resolvedFormat]\n const isIntKind = kind.startsWith('i') || kind.startsWith('u')\n\n function applyToVertexArray() {\n // Snapshot before the change, restore in the disposer\n const previousDivisor = readDivisor(gl, location)\n // vertexAttribPointer captures whatever is bound to ARRAY_BUFFER when\n // it runs, so this binding is the setup for the pointer, not a lasting\n // part of the vertex array's state.\n gl.bindBuffer(gl.ARRAY_BUFFER, buffer)\n handleAttribute(gl, location, size, 0, 0, glType, isIntKind, normalized, instanced)\n return once(() => {\n getInstancedArrays(gl)?.vertexAttribDivisor(location, previousDivisor)\n })\n }\n\n return {\n buffer,\n applyToVertexArray,\n bind() {\n const restoreVertexArray = bindDefaultVertexArray(gl)\n const restore = applyToVertexArray()\n return once(() => {\n restore()\n restoreVertexArray()\n })\n },\n dispose: once(() => {\n if (!providedBuffer) {\n gl.deleteBuffer(buffer)\n }\n }),\n set(data, usage = 'STATIC_DRAW') {\n gl.bindBuffer(gl.ARRAY_BUFFER, buffer)\n gl.bufferData(gl.ARRAY_BUFFER, data, gl[usage])\n return this\n },\n }\n },\n )\n\n signal?.addEventListener('abort', function dispose() {\n forEachObject(attributes, value => value.dispose())\n })\n\n return attributes\n}\n\n/**********************************************************************************/\n/* */\n/* Interleaved Attribute View */\n/* */\n/**********************************************************************************/\n\n/**\n * The other place an attribute's value can come from: not a buffer, but the\n * context's current generic vertex attribute values, which an attribute reads\n * for every vertex when its array is disabled.\n *\n * A constant is a uniform in all but name — one value for the whole draw, set\n * by a function chosen from the kind — so it gets the setters a uniform gets,\n * off the same layout the buffer source uses.\n *\n * `vertexAttrib*` tops out at four floats and has no matrix form, so a layout\n * key that is fine in a buffer can be impossible as a constant. That is a hard\n * limit of the API rather than a choice, and it is worth saying so out loud at\n * the point someone reaches for it.\n */\nfunction constantSource(gl: GL, layout: InterleavedAttributeLayout[], locations: number[]) {\n const setters = layout.map((entry, index) => {\n const size = kindToSize(entry.kind)\n const name = toID(entry.key)\n if (isMatKind(entry.kind) || size > 4) {\n throw new Error(\n `'${name}' is a ${entry.kind}, which cannot be a constant attribute: vertexAttrib* takes at most 4 floats and has no matrix form. Use the buffer source for it.`,\n )\n }\n // The values are context state, not vertex-array state, so they are held\n // here and written again on every bind — see applyToContext.\n let values: number[] = []\n const fn = gl[`vertexAttrib${size as 1 | 2 | 3 | 4}f`].bind(gl)\n return {\n name,\n location: locations[index]!,\n write: () => {\n if (values.length) {\n ;(fn as (location: number, ...args: number[]) => void)(locations[index]!, ...values)\n }\n },\n methods: {\n set(...args: number[]) {\n values = args\n },\n },\n }\n })\n\n return Object.assign(Object.fromEntries(setters.map(setter => [setter.name, setter.methods])), {\n applyToVertexArray() {\n const restores = setters.map(({ location }) => {\n const wasEnabled = gl.getVertexAttrib(location, gl.VERTEX_ATTRIB_ARRAY_ENABLED) as boolean\n gl.disableVertexAttribArray(location)\n return () => (wasEnabled ? gl.enableVertexAttribArray(location) : undefined)\n })\n return once(() => restores.forEach(restore => restore()))\n },\n applyToContext() {\n setters.forEach(setter => setter.write())\n },\n bind() {\n const restoreVertexArray = bindDefaultVertexArray(gl)\n const restore = this.applyToVertexArray()\n this.applyToContext()\n return once(() => {\n restore()\n restoreVertexArray()\n })\n },\n })\n}\n\nexport function interleavedAttributeView<T extends InterleavedAttributeSchema>(\n gl: GL,\n program: WebGLProgram,\n schema: T,\n { signal }: ViewOptions = {},\n): InterleavedAttributeView<T> {\n // Initialize interleaved attributes\n const interleavedAttributes = mapObject(schema, ({ layout }) => {\n // Increment number to keep track of offset\n let index = 0\n\n // Calculate layout information\n const locations: number[] = []\n const handles = layout.map(layout => {\n const name = toID(layout.key)\n\n const location = gl.getAttribLocation(program, name)\n\n if (location < 0) {\n throw new Error(`Attribute '${name}' not found`)\n }\n\n locations.push(location)\n\n const size = kindToSize(layout.kind)\n const offset = index\n const resolvedFormat = layout.format ?? defaultFormat(layout.kind)\n const glType = FORMAT_TO_GL_TYPE[resolvedFormat]\n const isIntKind = layout.kind.startsWith('i') || layout.kind.startsWith('u')\n const normalized = layout.normalized ?? false\n index += size * FORMAT_BYTE_SIZE[resolvedFormat]\n\n return (divisor: 0 | 1) =>\n handleAttribute(\n gl,\n location,\n size,\n stride,\n offset,\n glType,\n isIntKind,\n normalized,\n divisor === 1,\n )\n })\n\n // Set stride to final index\n const stride = index\n\n // Create a buffer\n const buffer = assertedNotNullish(gl.createBuffer())\n\n // This layout used to create a vertex array of its own, here, which is why\n // the other participants in a draw had to be bound after it to be included\n // — the array they landed in was whichever one happened to be current.\n // Arrays are `vao()`'s job now; a layout is a layout and a buffer.\n function applyToVertexArray(divisor: 0 | 1) {\n const previousDivisors = locations.map(\n location => [location, readDivisor(gl, location)] as const,\n )\n gl.bindBuffer(gl.ARRAY_BUFFER, buffer)\n for (const handle of handles) {\n handle(divisor)\n }\n return once(() => {\n const instancedArrays = getInstancedArrays(gl)\n previousDivisors.forEach(([location, previous]) => {\n instancedArrays?.vertexAttribDivisor(location, previous)\n })\n })\n }\n\n let constant: ReturnType<typeof constantSource> | undefined\n\n /** One layout, one buffer, but a divisor per draw rather than per schema. */\n function bufferSource(divisor: 0 | 1) {\n const apply = () => applyToVertexArray(divisor)\n return {\n applyToVertexArray: apply,\n bind() {\n const restoreVertexArray = bindDefaultVertexArray(gl)\n const restore = apply()\n return once(() => {\n restore()\n restoreVertexArray()\n })\n },\n }\n }\n\n return {\n buffer: Object.assign(bufferSource(0), {\n /** The same buffer, stepped once per instance instead of once per vertex. */\n perInstance: bufferSource(1),\n set(value: Float32Array, usage: GLUsage = 'STATIC_DRAW') {\n // Uploading is storage, not binding: ARRAY_BUFFER is not vertex-array\n // state, so this touches no array, whichever one is bound.\n gl.bindBuffer(gl.ARRAY_BUFFER, buffer)\n gl.bufferData(gl.ARRAY_BUFFER, value, gl[usage])\n },\n }),\n // Lazy: a layout key can be perfectly good in a buffer and impossible as\n // a constant, and finding that out should wait until someone asks for one.\n get constant() {\n return (constant ??= constantSource(gl, layout, locations))\n },\n dispose: once(() => gl.deleteBuffer(buffer)),\n } satisfies InterleavedAttributeMethods\n })\n\n signal?.addEventListener('abort', function dispose() {\n forEachObject(interleavedAttributes, value => value.dispose())\n })\n\n return interleavedAttributes\n}\n\n/**********************************************************************************/\n/* */\n/* Buffer View */\n/* */\n/**********************************************************************************/\n\nexport function bufferView<T extends BufferSchema>(\n gl: GL,\n schema: T,\n { signal }: ViewOptions = {},\n): BufferView<T> {\n // Initialize buffers\n const buffers = mapObject(schema, ({ target = 'ARRAY_BUFFER', usage = 'STATIC_DRAW' }) => {\n const buffer = assertedNotNullish(gl.createBuffer())\n\n function applyToVertexArray() {\n // Snapshot before the change, restore in the disposer. Restoring the\n // previous buffer rather than null matters for ELEMENT_ARRAY_BUFFER,\n // whose binding is recorded in the bound vertex array: clearing it\n // would strip the index buffer from an array the caller may not own.\n const previousBuffer = gl.getParameter(gl[`${target}_BINDING`]) as WebGLBuffer | null\n gl.bindBuffer(gl[target], buffer)\n return once(() => {\n gl.bindBuffer(gl[target], previousBuffer)\n })\n }\n\n return {\n applyToVertexArray,\n bind() {\n // ELEMENT_ARRAY_BUFFER's binding belongs to the bound vertex array, so\n // like the attributes this has to say which array it means. ARRAY_BUFFER\n // is context state and unaffected either way.\n const restoreVertexArray = bindDefaultVertexArray(gl)\n const restore = applyToVertexArray()\n return once(() => {\n restore()\n restoreVertexArray()\n })\n },\n dispose: once(() => gl.deleteBuffer(buffer)),\n set(data: Float32Array) {\n gl.bindBuffer(gl[target], buffer)\n gl.bufferData(gl[target], data, gl[usage])\n },\n }\n })\n\n signal?.addEventListener('abort', function dispose() {\n forEachObject(buffers, value => value.dispose())\n })\n\n return buffers\n}\n"],"mappings":"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","names":["location","index","layout"]}
package/dist/gl.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { G as GL, V as ViewOptions, R as RemoveSuffix } from './types-CNdqh7tB.mjs';
1
+ import { G as GL, V as ViewOptions, R as RemoveSuffix } from './types-k1Xz1iO3.mjs';
2
2
 
3
3
  /**********************************************************************************/
4
4
  /**********************************************************************************/
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { G as GL, F as FramebufferDefinition, V as ViewOptions, T as TextureDefinition, a as ViewSchema, b as View, c as VertexArrayParticipant, d as VertexArrayMethods, U as UniformSchema, e as UniformView, A as AttributeSchema, f as AttributeView, I as InterleavedAttributeSchema, g as InterleavedAttributeView, B as BufferSchema, h as BufferView } from './types-CNdqh7tB.mjs';
2
- export { D as AttributeDefinition, C as AttributeFormat, z as AttributeKind, E as AttributeMethods, y as AttributeShortHand, ac as AttributeToken, ad as AttributeTokenFn, P as BufferDefinition, Q as BufferMethods, L as BufferSource, ak as CompileResult, M as ConstantAttributeMethods, N as ConstantSource, ai as FlattenSlots, a3 as Format, W as Framebuffer, a9 as GLSL, a7 as GLSLResult, a8 as GLSLSlot, ah as GLSLSlotsToSchema, af as GLSLToSchema, ag as GLSLToView, i as GLTarget, n as GLTextureFilter, l as GLTextureFormat, k as GLTextureTarget, m as GLTextureType, o as GLTextureWrap, j as GLUsage, ae as InterleaveToken, J as InterleavedAttributeDefinition, H as InterleavedAttributeLayout, O as InterleavedAttributeMethods, a2 as InternalFormat, p as KIND_TO_SIZE_MAP, K as KIND_TO_UNIFORM_FN_NAME_MAP, aj as MergeGLSLSchema, a4 as PixelType, S as Source, a5 as TexImage2DOptions, Z as TextureMethods, $ as TextureParameterName, a0 as TextureParameterValue, a1 as TextureParameters, Y as TextureSchema, X as TextureTarget, _ as TextureView, v as UniformArrayMethods, t as UniformDefinition, u as UniformElementMethods, q as UniformFnName, r as UniformKind, s as UniformKindMap, w as UniformMethods, aa as UniformToken, ab as UniformTokenFn, x as UniformValue, a6 as ViewSchemaPartial } from './types-CNdqh7tB.mjs';
1
+ import { G as GL, F as FramebufferDefinition, V as ViewOptions, T as TextureDefinition, a as ViewSchema, b as View, c as VertexArrayParticipant, d as VertexArrayMethods, U as UniformSchema, e as UniformView, A as AttributeSchema, f as AttributeView, I as InterleavedAttributeSchema, g as InterleavedAttributeView, B as BufferSchema, h as BufferView } from './types-k1Xz1iO3.mjs';
2
+ export { D as AttributeDefinition, C as AttributeFormat, z as AttributeKind, E as AttributeMethods, y as AttributeShortHand, ac as AttributeToken, ad as AttributeTokenFn, P as BufferDefinition, Q as BufferMethods, L as BufferSource, ak as CompileResult, M as ConstantAttributeMethods, N as ConstantSource, ai as FlattenSlots, a3 as Format, W as Framebuffer, a9 as GLSL, a7 as GLSLResult, a8 as GLSLSlot, ah as GLSLSlotsToSchema, af as GLSLToSchema, ag as GLSLToView, i as GLTarget, n as GLTextureFilter, l as GLTextureFormat, k as GLTextureTarget, m as GLTextureType, o as GLTextureWrap, j as GLUsage, ae as InterleaveToken, J as InterleavedAttributeDefinition, H as InterleavedAttributeLayout, O as InterleavedAttributeMethods, a2 as InternalFormat, p as KIND_TO_SIZE_MAP, K as KIND_TO_UNIFORM_FN_NAME_MAP, aj as MergeGLSLSchema, a4 as PixelType, S as Source, a5 as TexImage2DOptions, Z as TextureMethods, $ as TextureParameterName, a0 as TextureParameterValue, a1 as TextureParameters, Y as TextureSchema, X as TextureTarget, _ as TextureView, v as UniformArrayMethods, t as UniformDefinition, u as UniformElementMethods, q as UniformFnName, r as UniformKind, s as UniformKindMap, w as UniformMethods, aa as UniformToken, ab as UniformTokenFn, x as UniformValue, a6 as ViewSchemaPartial } from './types-k1Xz1iO3.mjs';
3
3
 
4
4
  /**********************************************************************************/
5
5
  /**********************************************************************************/
package/dist/index.mjs CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  uniformView,
7
7
  vaoView,
8
8
  view
9
- } from "./chunk-X4M3LV4R.mjs";
9
+ } from "./chunk-H56LJYS5.mjs";
10
10
  import {
11
11
  createFramebuffer,
12
12
  createTexture
package/dist/tag.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { a8 as GLSLSlot, a9 as GLSL, ab as UniformTokenFn, ad as AttributeTokenFn, ac as AttributeToken, z as AttributeKind, D as AttributeDefinition, ae as InterleaveToken, a6 as ViewSchemaPartial, ak as CompileResult, al as Prettify, af as GLSLToSchema, G as GL } from './types-CNdqh7tB.mjs';
1
+ import { a8 as GLSLSlot, a9 as GLSL, ab as UniformTokenFn, ad as AttributeTokenFn, ac as AttributeToken, z as AttributeKind, D as AttributeDefinition, ae as InterleaveToken, a6 as ViewSchemaPartial, ak as CompileResult, al as Prettify, af as GLSLToSchema, G as GL } from './types-k1Xz1iO3.mjs';
2
2
 
3
3
  declare function glsl<TSlot extends GLSLSlot, const TSlots extends TSlot[]>(template: TemplateStringsArray, ...slots: [...TSlots]): GLSL<TSlots>;
4
4
  declare const uniform: {
package/dist/tag.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  toID,
3
3
  view
4
- } from "./chunk-X4M3LV4R.mjs";
4
+ } from "./chunk-H56LJYS5.mjs";
5
5
  import {
6
6
  createProgram,
7
7
  createUpsertMap,
@@ -68,7 +68,12 @@ function compile(gl, vertex, fragment, options) {
68
68
  interleavedAttributes: {
69
69
  ..._vertex.schema.interleavedAttributes,
70
70
  ..._fragment.schema.interleavedAttributes
71
- }
71
+ },
72
+ // Never produced by a tag — a buffer has no name in the source to be
73
+ // parsed out of one — but `options.schema` may name buffers for the view to
74
+ // own, and the deep merge below indexes this object by every key it finds
75
+ // there. Missing, that threw.
76
+ buffers: {}
72
77
  };
73
78
  for (const kind in options?.schema) {
74
79
  const schemaKind = schema[kind];
package/dist/tag.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/tag.ts"],"sourcesContent":["import { toID, view } from '.'\nimport { createProgram } from './gl'\nimport type { Prettify } from './type-utils'\nimport type {\n AttributeDefinition,\n AttributeKind,\n AttributeTokenFn as AttributeTagMethod,\n AttributeToken,\n CompileResult,\n GL,\n GLSL,\n GLSLSlot,\n GLSLToSchema,\n InterleaveToken,\n UniformDefinition,\n UniformKind,\n UniformTokenFn as UniformTagMethod,\n ViewSchema,\n ViewSchemaPartial,\n} from './types'\nimport { createUpsertMap, once } from './utils'\n\nexport function glsl<TSlot extends GLSLSlot, const TSlots extends TSlot[]>(\n template: TemplateStringsArray,\n ...slots: [...TSlots]\n): GLSL<TSlots> {\n return { template, slots, type: 'glsl' }\n}\n\nexport const uniform = new Proxy(\n {} as {\n [TKey in UniformKind]: UniformTagMethod<TKey>\n },\n {\n get(target, property) {\n // @ts-expect-error\n if (typeof property === 'symbol') return target[property]\n return (key: string, options?: Omit<UniformDefinition, 'kind'>) => ({\n type: 'uniform',\n key,\n kind: property,\n ...options,\n })\n },\n },\n)\n\nexport const attribute = new Proxy(\n {} as {\n [TKey in AttributeKind]: AttributeTagMethod<TKey>\n },\n {\n get(target, property) {\n // @ts-expect-error\n if (typeof property === 'symbol') return target[property]\n return (key: string, options?: Omit<AttributeDefinition, 'kind'>) => ({\n type: 'attribute',\n key,\n kind: property,\n ...options,\n })\n },\n },\n)\n\nexport function interleave<\n const TKey extends string | symbol,\n const TLayout extends Array<AttributeToken<string | symbol, AttributeKind, undefined>>,\n const TOptions extends Omit<AttributeDefinition, 'kind'>,\n>(key: TKey, layout: TLayout, instanced: TOptions): InterleaveToken<TKey, TLayout, TOptions>\nexport function interleave<\n const TKey extends string | symbol,\n const TLayout extends Array<AttributeToken<string | symbol, AttributeKind, undefined>>,\n>(key: TKey, layout: TLayout): InterleaveToken<TKey, TLayout, { instanced: false }>\nexport function interleave<\n const TKey extends string | symbol,\n const TLayout extends Array<AttributeToken<string | symbol, AttributeKind, undefined>>,\n const TOptions extends Omit<AttributeDefinition, 'kind'>,\n>(key: TKey, layout: TLayout, { instanced, buffer }: Partial<TOptions> = {}) {\n return {\n type: 'interleavedAttribute',\n key,\n // remove instanced- and type-property\n layout: layout.map(({ key, kind }) => ({\n key,\n kind,\n })),\n instanced: !!instanced,\n buffer,\n } as unknown as InterleaveToken<TKey, TLayout, TOptions>\n}\n\n/**********************************************************************************/\n/* */\n/* Compile */\n/* */\n/**********************************************************************************/\n\nexport interface CompileOptions<TSchema extends ViewSchemaPartial> {\n schema?: TSchema\n webgl2?: boolean\n /**\n * Disposes what `compile` made: the program, and the buffers the view created\n * for itself. Buffers named by the schema belong to whoever made them.\n */\n signal?: AbortSignal\n}\n\nexport function compile<\n TVertex extends GLSL,\n TFragment extends GLSL,\n TSchema extends ViewSchemaPartial,\n>(\n gl: WebGLRenderingContext,\n vertex: TVertex,\n fragment: TFragment,\n options?: CompileOptions<TSchema> | undefined,\n) {\n const _vertex = resolveGLSLTag(vertex, options) as { template: string; schema: ViewSchema }\n const _fragment = resolveGLSLTag(fragment, options) as { template: string; schema: ViewSchema }\n\n const schema = {\n uniforms: {\n ..._vertex.schema.uniforms,\n ..._fragment.schema.uniforms,\n },\n attributes: {\n ..._vertex.schema.attributes,\n ..._fragment.schema.attributes,\n },\n interleavedAttributes: {\n ..._vertex.schema.interleavedAttributes,\n ..._fragment.schema.interleavedAttributes,\n },\n }\n\n // Deep merge options.schema with generated schema\n for (const kind in options?.schema) {\n const schemaKind = schema[kind as keyof typeof schema]\n const configSchemaKind = options?.schema[kind]\n\n for (const key in configSchemaKind) {\n schemaKind[key] = {\n ...schemaKind[key],\n ...configSchemaKind[key],\n }\n }\n }\n\n try {\n const program = createProgram(gl, _vertex.template, _fragment.template)\n\n // The same rule the views follow: `compile` made this program, so `compile`\n // is what deletes it. A program handed in from outside would not be ours to\n // delete, and there is no way to hand one in.\n const resolvedView = view(gl, program, schema)\n const dispose = once(() => {\n resolvedView.dispose()\n gl.deleteProgram(program)\n })\n options?.signal?.addEventListener('abort', dispose)\n\n return {\n program,\n schema,\n view: resolvedView,\n dispose,\n vertex: _vertex.template,\n fragment: _fragment.template,\n } as unknown as Prettify<CompileResult<TVertex, TFragment, TSchema>>\n } catch (error) {\n console.error('Error while creating WebGLProgram - vertex\\n\\n', _vertex.template)\n console.error('Error while creating WebGLProgram - fragment\\n\\n', _fragment.template)\n\n throw error\n }\n}\n\nfunction resolveGLSLTag<TTag extends GLSL>(tag: TTag, options?: { webgl2?: boolean }) {\n return {\n template: compile.toString(tag, options),\n schema: compile.toSchema(tag),\n }\n}\n\ncompile.toSchema = function <TTag extends GLSL>(tag: TTag) {\n const result = {\n uniforms: {},\n attributes: {},\n interleavedAttributes: {},\n }\n\n tag.slots.forEach(function handleSlot(slot: GLSLSlot) {\n if (typeof slot !== 'object') {\n return\n }\n\n if (Array.isArray(slot)) {\n slot.forEach(handleSlot)\n return\n }\n\n if (slot.type === 'glsl') {\n const { uniforms, attributes, interleavedAttributes } = compile.toSchema(slot)\n\n result.uniforms = {\n ...result.uniforms,\n ...uniforms,\n }\n result.attributes = {\n ...result.attributes,\n ...attributes,\n }\n result.interleavedAttributes = {\n ...result.interleavedAttributes,\n ...interleavedAttributes,\n }\n\n return\n }\n\n const { key: name, type, ...rest } = slot\n\n // @ts-expect-error\n result[`${type}s`][name] = rest\n })\n\n return result as unknown as Prettify<GLSLToSchema<TTag>>\n}\n\ncompile.toString = function <TTag extends GLSL>(\n { template: [initial, ...rest], slots }: TTag,\n config?: { webgl2?: boolean },\n) {\n const v300 = config?.webgl2 ?? !!initial?.startsWith('#version 300 es')\n\n let template = initial ?? ''\n\n for (let i = 0; i < rest.length; i++) {\n template += `${resolveGlslSlotToString(slots[i]!, v300)}${rest[i]}`\n }\n\n return template\n}\n\nfunction resolveGlslSlotToString(slot: GLSLSlot, v300: boolean): string {\n if (typeof slot !== 'object') {\n return toID(slot)\n }\n\n if (Array.isArray(slot)) {\n return slot.map(slot => resolveGlslSlotToString(slot, v300)).join('')\n }\n\n switch (slot.type) {\n case 'glsl':\n return compile.toString(slot)\n case 'interleavedAttribute':\n return slot.layout.reduce(\n (a, v) =>\n v300 ? `${a}in ${v.kind} ${toID(v.key)};\\n` : `${a}attribute ${v.kind} ${toID(v.key)};\\n`,\n '',\n )\n case 'uniform':\n if ('size' in slot) {\n return `${slot.type} ${slot.kind} ${toID(slot.key)}[${slot.size}];`\n }\n return `${slot.type} ${slot.kind} ${toID(slot.key)};`\n }\n\n if (slot.type === 'attribute') {\n return `${v300 ? 'in' : slot.type} ${slot.kind} ${toID(slot.key)};`\n }\n\n throw new Error(`Unexpected slot: ${JSON.stringify(slot)}`)\n}\n\nconst QUAD_FLOAT_ARRAY = new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1])\nconst QUAD_BUFFER_MAP = createUpsertMap(WeakMap<GL, WebGLBuffer>)\n\ncompile.toQuad = function <TFragment extends GLSL, TSchema extends ViewSchemaPartial>(\n gl: GL,\n fragment: TFragment,\n options?: CompileOptions<TSchema>,\n) {\n const buffer = QUAD_BUFFER_MAP.getOrInsert(gl, gl.createBuffer.bind(gl))\n\n const webgl2 = options?.webgl2 ?? fragment.template[0]?.startsWith('#version 300 es')\n\n const vertex = webgl2\n ? glsl`#version 300 es\nprecision mediump float;\n\n${attribute.vec2('a_quad', { buffer })}\n\nout vec2 v_uv;\n\nvoid main() {\n v_uv = a_quad;\n gl_Position = vec4(v_uv, 0.0, 1.0);\n}`\n : glsl`precision mediump float;\n\n${attribute.vec2('a_quad', { buffer })}\n\nvarying vec2 v_uv;\n\nvoid main() {\n v_uv = a_quad;\n gl_Position = vec4(v_uv, 0.0, 1.0);\n}`\n\n const result = compile(gl, vertex, fragment, options)\n\n // @ts-expect-error\n result.view.attributes.a_quad.set(QUAD_FLOAT_ARRAY)\n\n return result\n}\n"],"mappings":"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","names":["key","slot"]}
1
+ {"version":3,"sources":["../src/tag.ts"],"sourcesContent":["import { toID, view } from '.'\nimport { createProgram } from './gl'\nimport type { Prettify } from './type-utils'\nimport type {\n AttributeDefinition,\n AttributeKind,\n AttributeTokenFn as AttributeTagMethod,\n AttributeToken,\n CompileResult,\n GL,\n GLSL,\n GLSLSlot,\n GLSLToSchema,\n InterleaveToken,\n UniformDefinition,\n UniformKind,\n UniformTokenFn as UniformTagMethod,\n ViewSchema,\n ViewSchemaPartial,\n} from './types'\nimport { createUpsertMap, once } from './utils'\n\nexport function glsl<TSlot extends GLSLSlot, const TSlots extends TSlot[]>(\n template: TemplateStringsArray,\n ...slots: [...TSlots]\n): GLSL<TSlots> {\n return { template, slots, type: 'glsl' }\n}\n\nexport const uniform = new Proxy(\n {} as {\n [TKey in UniformKind]: UniformTagMethod<TKey>\n },\n {\n get(target, property) {\n // @ts-expect-error\n if (typeof property === 'symbol') return target[property]\n return (key: string, options?: Omit<UniformDefinition, 'kind'>) => ({\n type: 'uniform',\n key,\n kind: property,\n ...options,\n })\n },\n },\n)\n\nexport const attribute = new Proxy(\n {} as {\n [TKey in AttributeKind]: AttributeTagMethod<TKey>\n },\n {\n get(target, property) {\n // @ts-expect-error\n if (typeof property === 'symbol') return target[property]\n return (key: string, options?: Omit<AttributeDefinition, 'kind'>) => ({\n type: 'attribute',\n key,\n kind: property,\n ...options,\n })\n },\n },\n)\n\nexport function interleave<\n const TKey extends string | symbol,\n const TLayout extends Array<AttributeToken<string | symbol, AttributeKind, undefined>>,\n const TOptions extends Omit<AttributeDefinition, 'kind'>,\n>(key: TKey, layout: TLayout, instanced: TOptions): InterleaveToken<TKey, TLayout, TOptions>\nexport function interleave<\n const TKey extends string | symbol,\n const TLayout extends Array<AttributeToken<string | symbol, AttributeKind, undefined>>,\n>(key: TKey, layout: TLayout): InterleaveToken<TKey, TLayout, { instanced: false }>\nexport function interleave<\n const TKey extends string | symbol,\n const TLayout extends Array<AttributeToken<string | symbol, AttributeKind, undefined>>,\n const TOptions extends Omit<AttributeDefinition, 'kind'>,\n>(key: TKey, layout: TLayout, { instanced, buffer }: Partial<TOptions> = {}) {\n return {\n type: 'interleavedAttribute',\n key,\n // remove instanced- and type-property\n layout: layout.map(({ key, kind }) => ({\n key,\n kind,\n })),\n instanced: !!instanced,\n buffer,\n } as unknown as InterleaveToken<TKey, TLayout, TOptions>\n}\n\n/**********************************************************************************/\n/* */\n/* Compile */\n/* */\n/**********************************************************************************/\n\nexport interface CompileOptions<TSchema extends ViewSchemaPartial> {\n schema?: TSchema\n webgl2?: boolean\n /**\n * Disposes what `compile` made: the program, and the buffers the view created\n * for itself. Buffers named by the schema belong to whoever made them.\n */\n signal?: AbortSignal\n}\n\nexport function compile<\n TVertex extends GLSL,\n TFragment extends GLSL,\n TSchema extends ViewSchemaPartial,\n>(\n gl: WebGLRenderingContext,\n vertex: TVertex,\n fragment: TFragment,\n options?: CompileOptions<TSchema> | undefined,\n) {\n const _vertex = resolveGLSLTag(vertex, options) as { template: string; schema: ViewSchema }\n const _fragment = resolveGLSLTag(fragment, options) as { template: string; schema: ViewSchema }\n\n const schema = {\n uniforms: {\n ..._vertex.schema.uniforms,\n ..._fragment.schema.uniforms,\n },\n attributes: {\n ..._vertex.schema.attributes,\n ..._fragment.schema.attributes,\n },\n interleavedAttributes: {\n ..._vertex.schema.interleavedAttributes,\n ..._fragment.schema.interleavedAttributes,\n },\n // Never produced by a tag — a buffer has no name in the source to be\n // parsed out of one — but `options.schema` may name buffers for the view to\n // own, and the deep merge below indexes this object by every key it finds\n // there. Missing, that threw.\n buffers: {} as NonNullable<ViewSchema['buffers']>,\n }\n\n // Deep merge options.schema with generated schema\n for (const kind in options?.schema) {\n const schemaKind = schema[kind as keyof typeof schema]\n const configSchemaKind = options?.schema[kind]\n\n for (const key in configSchemaKind) {\n schemaKind[key] = {\n ...schemaKind[key],\n ...configSchemaKind[key],\n }\n }\n }\n\n try {\n const program = createProgram(gl, _vertex.template, _fragment.template)\n\n // The same rule the views follow: `compile` made this program, so `compile`\n // is what deletes it. A program handed in from outside would not be ours to\n // delete, and there is no way to hand one in.\n const resolvedView = view(gl, program, schema)\n const dispose = once(() => {\n resolvedView.dispose()\n gl.deleteProgram(program)\n })\n options?.signal?.addEventListener('abort', dispose)\n\n return {\n program,\n schema,\n view: resolvedView,\n dispose,\n vertex: _vertex.template,\n fragment: _fragment.template,\n } as unknown as Prettify<CompileResult<TVertex, TFragment, TSchema>>\n } catch (error) {\n console.error('Error while creating WebGLProgram - vertex\\n\\n', _vertex.template)\n console.error('Error while creating WebGLProgram - fragment\\n\\n', _fragment.template)\n\n throw error\n }\n}\n\nfunction resolveGLSLTag<TTag extends GLSL>(tag: TTag, options?: { webgl2?: boolean }) {\n return {\n template: compile.toString(tag, options),\n schema: compile.toSchema(tag),\n }\n}\n\ncompile.toSchema = function <TTag extends GLSL>(tag: TTag) {\n const result = {\n uniforms: {},\n attributes: {},\n interleavedAttributes: {},\n }\n\n tag.slots.forEach(function handleSlot(slot: GLSLSlot) {\n if (typeof slot !== 'object') {\n return\n }\n\n if (Array.isArray(slot)) {\n slot.forEach(handleSlot)\n return\n }\n\n if (slot.type === 'glsl') {\n const { uniforms, attributes, interleavedAttributes } = compile.toSchema(slot)\n\n result.uniforms = {\n ...result.uniforms,\n ...uniforms,\n }\n result.attributes = {\n ...result.attributes,\n ...attributes,\n }\n result.interleavedAttributes = {\n ...result.interleavedAttributes,\n ...interleavedAttributes,\n }\n\n return\n }\n\n const { key: name, type, ...rest } = slot\n\n // @ts-expect-error\n result[`${type}s`][name] = rest\n })\n\n return result as unknown as Prettify<GLSLToSchema<TTag>>\n}\n\ncompile.toString = function <TTag extends GLSL>(\n { template: [initial, ...rest], slots }: TTag,\n config?: { webgl2?: boolean },\n) {\n const v300 = config?.webgl2 ?? !!initial?.startsWith('#version 300 es')\n\n let template = initial ?? ''\n\n for (let i = 0; i < rest.length; i++) {\n template += `${resolveGlslSlotToString(slots[i]!, v300)}${rest[i]}`\n }\n\n return template\n}\n\nfunction resolveGlslSlotToString(slot: GLSLSlot, v300: boolean): string {\n if (typeof slot !== 'object') {\n return toID(slot)\n }\n\n if (Array.isArray(slot)) {\n return slot.map(slot => resolveGlslSlotToString(slot, v300)).join('')\n }\n\n switch (slot.type) {\n case 'glsl':\n return compile.toString(slot)\n case 'interleavedAttribute':\n return slot.layout.reduce(\n (a, v) =>\n v300 ? `${a}in ${v.kind} ${toID(v.key)};\\n` : `${a}attribute ${v.kind} ${toID(v.key)};\\n`,\n '',\n )\n case 'uniform':\n if ('size' in slot) {\n return `${slot.type} ${slot.kind} ${toID(slot.key)}[${slot.size}];`\n }\n return `${slot.type} ${slot.kind} ${toID(slot.key)};`\n }\n\n if (slot.type === 'attribute') {\n return `${v300 ? 'in' : slot.type} ${slot.kind} ${toID(slot.key)};`\n }\n\n throw new Error(`Unexpected slot: ${JSON.stringify(slot)}`)\n}\n\nconst QUAD_FLOAT_ARRAY = new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1])\nconst QUAD_BUFFER_MAP = createUpsertMap(WeakMap<GL, WebGLBuffer>)\n\ncompile.toQuad = function <TFragment extends GLSL, TSchema extends ViewSchemaPartial>(\n gl: GL,\n fragment: TFragment,\n options?: CompileOptions<TSchema>,\n) {\n const buffer = QUAD_BUFFER_MAP.getOrInsert(gl, gl.createBuffer.bind(gl))\n\n const webgl2 = options?.webgl2 ?? fragment.template[0]?.startsWith('#version 300 es')\n\n const vertex = webgl2\n ? glsl`#version 300 es\nprecision mediump float;\n\n${attribute.vec2('a_quad', { buffer })}\n\nout vec2 v_uv;\n\nvoid main() {\n v_uv = a_quad;\n gl_Position = vec4(v_uv, 0.0, 1.0);\n}`\n : glsl`precision mediump float;\n\n${attribute.vec2('a_quad', { buffer })}\n\nvarying vec2 v_uv;\n\nvoid main() {\n v_uv = a_quad;\n gl_Position = vec4(v_uv, 0.0, 1.0);\n}`\n\n const result = compile(gl, vertex, fragment, options)\n\n // @ts-expect-error\n result.view.attributes.a_quad.set(QUAD_FLOAT_ARRAY)\n\n return result\n}\n"],"mappings":"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","names":["key","slot"]}
@@ -409,26 +409,38 @@ interface ViewOptions {
409
409
  signal?: AbortSignal;
410
410
  }
411
411
  /**
412
- * What a program has names for. Buffers are absent on purpose: a buffer has no
413
- * name in the source, so it cannot be resolved against a program the way a
414
- * uniform or an attribute is, and its lifetime is rarely a program's. Build one
415
- * with `bufferView` and pass it to `vao()` alongside the attributes.
412
+ * What a view builds for one program.
413
+ *
414
+ * A buffer declared here is OWNED by the view: it lives and dies with it, on
415
+ * the one signal, which is the common case — an index buffer whose lifetime is
416
+ * its program's has no reason to be declared apart from the attributes it is
417
+ * drawn with.
418
+ *
419
+ * The other two lifetimes have their own spellings, and neither is this one. A
420
+ * buffer that outlives the view, or is shared between views, is a standalone
421
+ * `bufferView` — `compile.toQuad`'s per-context quad, a buffer handed from one
422
+ * program's view to another's. A buffer that belongs to somebody else is NAMED
423
+ * by an attribute schema, and is borrowed: the view uses it and never deletes
424
+ * it.
416
425
  */
417
426
  interface ViewSchema {
418
427
  uniforms?: UniformSchema;
419
428
  attributes?: AttributeSchema;
420
429
  interleavedAttributes?: InterleavedAttributeSchema;
430
+ buffers?: BufferSchema;
421
431
  }
422
432
  type PartialSchema<T> = T extends Record<string | symbol, infer V> ? Record<string | symbol, Partial<V>> : never;
423
433
  interface ViewSchemaPartial {
424
434
  uniforms?: PartialSchema<UniformSchema>;
425
435
  attributes?: PartialSchema<AttributeSchema>;
426
436
  interleavedAttributes?: PartialSchema<InterleavedAttributeSchema>;
437
+ buffers?: PartialSchema<BufferSchema>;
427
438
  }
428
439
  type View<T extends ViewSchema = ViewSchema> = {
429
440
  attributes: T['attributes'] extends AttributeSchema ? Prettify<AttributeView<T['attributes']>> : {};
430
441
  interleavedAttributes: T['interleavedAttributes'] extends InterleavedAttributeSchema ? Prettify<InterleavedAttributeView<T['interleavedAttributes']>> : {};
431
442
  uniforms: T['uniforms'] extends UniformSchema ? Prettify<UniformView<T['uniforms']>> : {};
443
+ buffers: T['buffers'] extends BufferSchema ? Prettify<BufferView<T['buffers']>> : {};
432
444
  /**
433
445
  * Build a vertex array from the participants one draw needs — its attributes,
434
446
  * its interleaved layouts, its element buffer.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bigmistqke/view.gl",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "👀 Utilities for managing WebGL resources.",
5
5
  "exports": {
6
6
  ".": {
package/src/index.ts CHANGED
@@ -87,6 +87,12 @@ export function view<TSchema extends ViewSchema>(
87
87
  const interleavedAttributes = !schema.interleavedAttributes
88
88
  ? undefined
89
89
  : interleavedAttributeView(gl, program, schema.interleavedAttributes)
90
+ // Owned by the view, on the view's signal. This is the line the split was
91
+ // really about: it used to read `bufferView(gl, schema.buffers)` with the
92
+ // options dropped, so a view's buffers were the only resources that still
93
+ // needed disposing by hand. That was a missing argument rather than a wrong
94
+ // model — a buffer whose lifetime IS the view's belongs with it.
95
+ const buffers = !schema.buffers ? undefined : bufferView(gl, schema.buffers)
90
96
 
91
97
  // Vertex arrays are made on demand rather than declared, so they are the one
92
98
  // thing the view cannot dispose from the schema alone. Held until disposed —
@@ -97,6 +103,7 @@ export function view<TSchema extends ViewSchema>(
97
103
  const dispose = once(() => {
98
104
  if (attributes) forEachObject(attributes, value => value.dispose())
99
105
  if (interleavedAttributes) forEachObject(interleavedAttributes, value => value.dispose())
106
+ if (buffers) forEachObject(buffers, value => value.dispose())
100
107
  vertexArrays.forEach(vertexArray => vertexArray.dispose())
101
108
  vertexArrays.clear()
102
109
  })
@@ -107,6 +114,7 @@ export function view<TSchema extends ViewSchema>(
107
114
  uniforms: !schema.uniforms ? undefined : uniformView(gl, program, schema.uniforms),
108
115
  attributes,
109
116
  interleavedAttributes,
117
+ buffers,
110
118
  vao(participants: VertexArrayParticipant[]) {
111
119
  const vertexArray = vaoView(gl, participants)
112
120
  vertexArrays.add(vertexArray)
package/src/tag.ts CHANGED
@@ -132,6 +132,11 @@ export function compile<
132
132
  ..._vertex.schema.interleavedAttributes,
133
133
  ..._fragment.schema.interleavedAttributes,
134
134
  },
135
+ // Never produced by a tag — a buffer has no name in the source to be
136
+ // parsed out of one — but `options.schema` may name buffers for the view to
137
+ // own, and the deep merge below indexes this object by every key it finds
138
+ // there. Missing, that threw.
139
+ buffers: {} as NonNullable<ViewSchema['buffers']>,
135
140
  }
136
141
 
137
142
  // Deep merge options.schema with generated schema
package/src/types.ts CHANGED
@@ -633,15 +633,25 @@ export interface ViewOptions {
633
633
  }
634
634
 
635
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.
636
+ * What a view builds for one program.
637
+ *
638
+ * A buffer declared here is OWNED by the view: it lives and dies with it, on
639
+ * the one signal, which is the common case — an index buffer whose lifetime is
640
+ * its program's has no reason to be declared apart from the attributes it is
641
+ * drawn with.
642
+ *
643
+ * The other two lifetimes have their own spellings, and neither is this one. A
644
+ * buffer that outlives the view, or is shared between views, is a standalone
645
+ * `bufferView` — `compile.toQuad`'s per-context quad, a buffer handed from one
646
+ * program's view to another's. A buffer that belongs to somebody else is NAMED
647
+ * by an attribute schema, and is borrowed: the view uses it and never deletes
648
+ * it.
640
649
  */
641
650
  export interface ViewSchema {
642
651
  uniforms?: UniformSchema
643
652
  attributes?: AttributeSchema
644
653
  interleavedAttributes?: InterleavedAttributeSchema
654
+ buffers?: BufferSchema
645
655
  }
646
656
 
647
657
  type PartialSchema<T> =
@@ -651,6 +661,7 @@ export interface ViewSchemaPartial {
651
661
  uniforms?: PartialSchema<UniformSchema>
652
662
  attributes?: PartialSchema<AttributeSchema>
653
663
  interleavedAttributes?: PartialSchema<InterleavedAttributeSchema>
664
+ buffers?: PartialSchema<BufferSchema>
654
665
  }
655
666
 
656
667
  export type View<T extends ViewSchema = ViewSchema> = {
@@ -661,6 +672,7 @@ export type View<T extends ViewSchema = ViewSchema> = {
661
672
  ? Prettify<InterleavedAttributeView<T['interleavedAttributes']>>
662
673
  : {}
663
674
  uniforms: T['uniforms'] extends UniformSchema ? Prettify<UniformView<T['uniforms']>> : {}
675
+ buffers: T['buffers'] extends BufferSchema ? Prettify<BufferView<T['buffers']>> : {}
664
676
  /**
665
677
  * Build a vertex array from the participants one draw needs — its attributes,
666
678
  * its interleaved layouts, its element buffer.
@@ -214,6 +214,40 @@ describe('disposing a view', () => {
214
214
  expect(gl.deleteVertexArray).toHaveBeenCalledTimes(1)
215
215
  })
216
216
 
217
+ it('deletes a buffer the schema declared, on its own signal', () => {
218
+ // The regression this key exists for. It used to be built with the options
219
+ // dropped — `bufferView(gl, schema.buffers)` — so a view's buffers were the
220
+ // only resources it did not dispose, and every caller had to remember one
221
+ // extra line beside an abort that covered everything else.
222
+ const controller = new AbortController()
223
+ const withBuffer = {
224
+ attributes: { a_position: { kind: 'vec2' } },
225
+ buffers: { b_index: { target: 'ELEMENT_ARRAY_BUFFER' } },
226
+ } satisfies ViewSchema
227
+ const result = view(gl, program, withBuffer, { signal: controller.signal })
228
+ void result.buffers.b_index
229
+
230
+ controller.abort()
231
+
232
+ // The attribute's buffer and the declared one.
233
+ expect(gl.deleteBuffer).toHaveBeenCalledTimes(2)
234
+ })
235
+
236
+ it('leaves a buffer the schema NAMED to whoever made it', () => {
237
+ // Borrowed, not owned — the other half of the rule. A named buffer is the
238
+ // point of sharing one, and one view cannot know whether the others are
239
+ // done with it.
240
+ const borrowed = bufferView(gl, { shared: { target: 'ARRAY_BUFFER' } })
241
+ ;(gl.deleteBuffer as any).mockClear()
242
+ const result = view(gl, program, {
243
+ attributes: { a_position: { kind: 'vec2', buffer: borrowed.shared } },
244
+ } satisfies ViewSchema)
245
+
246
+ result.dispose()
247
+
248
+ expect(gl.deleteBuffer).not.toHaveBeenCalled()
249
+ })
250
+
217
251
  it('forgets a vertex array the caller disposed itself', () => {
218
252
  const result = view(gl, program, schema)
219
253
  const vertexArray = result.vao([result.attributes.a_position])
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { getInstancedArrays, getVertexArrayObject } from './gl'\nimport type {\n AttributeFormat,\n AttributeKind,\n AttributeMethods,\n AttributeSchema,\n AttributeView,\n BufferSchema,\n BufferView,\n GL,\n UniformView as InferUniformView,\n GLUsage,\n InterleavedAttributeLayout,\n InterleavedAttributeMethods,\n InterleavedAttributeSchema,\n InterleavedAttributeView,\n UniformSchema,\n VertexArrayMethods,\n VertexArrayParticipant,\n View,\n ViewOptions,\n ViewSchema,\n} from './types'\nimport {\n isSamplerKind,\n kindToUniformFnName,\n isMatKind,\n assertedNotNullish,\n kindToSize,\n forEachObject,\n once,\n} from './utils'\nimport { createUpsertMap, mapObject } from './utils'\nexport * from './types'\n// Documented under Utils but reachable from nowhere until now: utils is not a\n// build entry, and named rather than star so the internal helpers stay internal.\nexport { createFramebuffer, createTexture } from './utils'\n\n/**********************************************************************************/\n/* */\n/* To ID */\n/* */\n/**********************************************************************************/\n\nlet index = 0\nconst PREFIX = 'VIEW_GL_ALIAS'\n// Firefox has currently a bug where it can not handle symbol as WeakRef / key for WeakMap\n// see https://bugzilla.mozilla.org/show_bug.cgi?id=1710433\nconst HAS_WEAK_SYMBOL = (() => {\n try {\n const symbol = Symbol()\n new WeakMap().set(symbol, '')\n return true\n } catch {\n return false\n }\n})()\n// NOTE: fallback to Map will currently cause a minor memory leak.\nconst SYMBOL_MAP = createUpsertMap(HAS_WEAK_SYMBOL ? WeakMap<symbol, string> : Map<symbol, string>)\n\nexport function toID(key: string | number | symbol) {\n if (typeof key === 'string') {\n return key\n }\n if (typeof key === 'symbol') {\n return SYMBOL_MAP.getOrInsert(key, () => `${PREFIX}_${index++}`)\n }\n return key.toString()\n}\n\n/**********************************************************************************/\n/* */\n/* View */\n/* */\n/**********************************************************************************/\n\nexport function view<TSchema extends ViewSchema>(\n gl: GL,\n program: WebGLProgram,\n schema: TSchema,\n { signal }: ViewOptions = {},\n): View<TSchema> {\n // The sub-views are built without the signal and the view wires disposal\n // once, so that `dispose()` and aborting do the same thing rather than each\n // doing half of it.\n const attributes = !schema.attributes ? undefined : attributeView(gl, program, schema.attributes)\n const interleavedAttributes = !schema.interleavedAttributes\n ? undefined\n : interleavedAttributeView(gl, program, schema.interleavedAttributes)\n\n // Vertex arrays are made on demand rather than declared, so they are the one\n // thing the view cannot dispose from the schema alone. Held until disposed —\n // by the view or by the caller — and dropped either way, so a view that hands\n // out an array per frame does not accumulate them.\n const vertexArrays = new Set<VertexArrayMethods>()\n\n const dispose = once(() => {\n if (attributes) forEachObject(attributes, value => value.dispose())\n if (interleavedAttributes) forEachObject(interleavedAttributes, value => value.dispose())\n vertexArrays.forEach(vertexArray => vertexArray.dispose())\n vertexArrays.clear()\n })\n\n signal?.addEventListener('abort', dispose)\n\n return {\n uniforms: !schema.uniforms ? undefined : uniformView(gl, program, schema.uniforms),\n attributes,\n interleavedAttributes,\n vao(participants: VertexArrayParticipant[]) {\n const vertexArray = vaoView(gl, participants)\n vertexArrays.add(vertexArray)\n return {\n ...vertexArray,\n dispose: once(() => {\n vertexArrays.delete(vertexArray)\n vertexArray.dispose()\n }),\n }\n },\n dispose,\n } as View<TSchema>\n}\n\n/**********************************************************************************/\n/* */\n/* Vertex Array */\n/* */\n/**********************************************************************************/\n\n/**\n * Bind the default vertex array, returning a disposer that puts the previous\n * one back. The pointer calls name no destination, so anything applied without\n * a vertex array of its own has to say which one it means — and a vertex array\n * keeps what it is given, so writing into a caller's array by accident would\n * outlive the call that did it.\n */\nfunction bindDefaultVertexArray(gl: GL): () => void {\n const feature = getVertexArrayObject(gl)\n if (!feature) {\n return () => {}\n }\n const previous = gl.getParameter(VERTEX_ARRAY_BINDING) as WebGLVertexArrayObject | null\n feature.bindVertexArray(null)\n return () => feature.bindVertexArray(previous)\n}\n\n/**\n * A vertex array over the participants one draw needs.\n *\n * Where the context has vertex arrays, each participant writes itself in once,\n * here, and `bind()` is a single `bindVertexArray`. Where it does not — WebGL1\n * without `OES_vertex_array_object` — there is nowhere to keep the state, so\n * `bind()` re-applies every participant and the disposer puts back what they\n * displaced. Same contract, and the emulation is why the name still fits.\n */\nexport function vaoView(\n gl: GL,\n participants: VertexArrayParticipant[],\n { signal }: ViewOptions = {},\n): VertexArrayMethods {\n const feature = getVertexArrayObject(gl)\n\n const methods: VertexArrayMethods = !feature\n ? {\n bind() {\n const restores = participants.map(participant => participant.applyToVertexArray())\n participants.forEach(participant => participant.applyToContext?.())\n return once(() => restores.forEach(restore => restore()))\n },\n unbind() {},\n dispose() {},\n }\n : (() => {\n const vertexArray = assertedNotNullish(feature.createVertexArray())\n const previous = gl.getParameter(VERTEX_ARRAY_BINDING) as WebGLVertexArrayObject | null\n feature.bindVertexArray(vertexArray)\n // Discarding the restorers is the point: the state lives in this array\n // now, and the array is thrown away whole.\n for (const participant of participants) {\n participant.applyToVertexArray()\n }\n feature.bindVertexArray(previous)\n\n return {\n bind() {\n const previousVertexArray = gl.getParameter(\n VERTEX_ARRAY_BINDING,\n ) as WebGLVertexArrayObject | null\n feature.bindVertexArray(vertexArray)\n // Context state the array cannot hold — see applyToContext.\n participants.forEach(participant => participant.applyToContext?.())\n return once(() => feature.bindVertexArray(previousVertexArray))\n },\n unbind() {\n feature.bindVertexArray(null)\n },\n dispose: once(() => feature.deleteVertexArray(vertexArray)),\n }\n })()\n\n signal?.addEventListener('abort', () => methods.dispose())\n\n return methods\n}\n\n/**********************************************************************************/\n/* */\n/* Uniform View */\n/* */\n/**********************************************************************************/\n\nexport function uniformView<T extends UniformSchema>(\n gl: GL,\n program: WebGLProgram,\n schema: T,\n): InferUniformView<T> {\n // @ts-expect-error - conditional return type based on size is hard to infer\n return mapObject(schema, ({ kind, size }, key) => {\n const name = toID(key)\n\n if (isSamplerKind(kind)) {\n const location = gl.getUniformLocation(program, name)\n return {\n set(arg: number) {\n gl.uniform1i(location, arg)\n },\n }\n }\n\n // Array uniform - support both bulk set and indexed access\n if (size) {\n const bulkFnName = `uniform${kindToUniformFnName(kind)}v`\n // @ts-ignore FIX WEBGL/WEBGL2 TYPES\n const bulkFn = gl[bulkFnName].bind(gl)\n const bulkLocation = gl.getUniformLocation(program, name)\n\n const elementFnName = `uniform${kindToUniformFnName(kind)}`\n // @ts-ignore FIX WEBGL/WEBGL2 TYPES\n const elementFn = gl[elementFnName].bind(gl)\n\n // Build array of element setters\n const elements: Array<{ set(...args: any[]): void }> = []\n for (let i = 0; i < size; i++) {\n const location = gl.getUniformLocation(program, `${name}[${i}]`)\n elements[i] = {\n set(...args: any[]) {\n elementFn(location, ...args)\n },\n }\n }\n\n // Return array-like object with bulk set\n return Object.assign(elements, {\n set(arg: Float32Array) {\n bulkFn(bulkLocation, arg)\n },\n })\n }\n\n // Non-array uniform\n const location = gl.getUniformLocation(program, name)\n const fnName = `uniform${kindToUniformFnName(kind)}`\n\n // @ts-ignore FIX WEBGL/WEBGL2 TYPES\n const fn = gl[fnName].bind(gl)\n\n if (isMatKind(kind)) {\n return {\n set(...args: any[]) {\n fn(location, false, args[0])\n },\n }\n }\n\n return {\n set(...args: any[]) {\n fn(location, ...args)\n },\n }\n })\n}\n\n/**********************************************************************************/\n/* */\n/* Attribute View */\n/* */\n/**********************************************************************************/\n\ntype GLType =\n | 'FLOAT'\n | 'INT'\n | 'UNSIGNED_INT'\n | 'SHORT'\n | 'UNSIGNED_SHORT'\n | 'BYTE'\n | 'UNSIGNED_BYTE'\n\nconst FORMAT_TO_GL_TYPE: Record<AttributeFormat, GLType> = {\n float32: 'FLOAT',\n int32: 'INT',\n uint32: 'UNSIGNED_INT',\n int16: 'SHORT',\n uint16: 'UNSIGNED_SHORT',\n int8: 'BYTE',\n uint8: 'UNSIGNED_BYTE',\n}\n\nconst FORMAT_BYTE_SIZE: Record<AttributeFormat, number> = {\n float32: 4,\n int32: 4,\n uint32: 4,\n int16: 2,\n uint16: 2,\n int8: 1,\n uint8: 1,\n}\n\nfunction defaultFormat(kind: AttributeKind): AttributeFormat {\n if (kind.startsWith('u')) return 'uint32'\n if (kind.startsWith('i')) return 'int32'\n return 'float32'\n}\n\n// Shared attribute helper functions\n// between attributeView and interleavedAttributeView\nfunction handleAttribute(\n gl: GL,\n location: number,\n size: number,\n stride: number,\n offset: number,\n glType: GLType,\n isIntegerKind: boolean,\n normalized: boolean,\n instanced?: boolean,\n) {\n gl.enableVertexAttribArray(location)\n if (isIntegerKind) {\n ;(gl as WebGL2RenderingContext).vertexAttribIPointer(location, size, gl[glType], stride, offset)\n } else {\n gl.vertexAttribPointer(location, size, gl[glType], normalized, stride, offset)\n }\n\n // Always stated, never inherited: the divisor belongs to the location rather\n // than to the program, so a location left at 1 by an earlier instanced\n // attribute would feed one value to every vertex here.\n // Get instanced-arrays-feature: extension if webgl, gl if webgl2\n const instancedArrays = getInstancedArrays(gl)\n if (instanced) {\n assertedNotNullish(instancedArrays).vertexAttribDivisor(location, 1)\n } else if (instancedArrays) {\n instancedArrays.vertexAttribDivisor(location, 0)\n }\n}\n\n// Same enum in webgl2 and in the webgl1 extensions, which expose no constants\nconst VERTEX_ATTRIB_ARRAY_DIVISOR = 0x88fe\nconst VERTEX_ARRAY_BINDING = 0x85b5\n\n// Reads the divisor currently attached to a location, 0 where instancing is\n// unavailable and nothing can have set one\nfunction readDivisor(gl: GL, location: number): number {\n return getInstancedArrays(gl)\n ? (gl.getVertexAttrib(location, VERTEX_ATTRIB_ARRAY_DIVISOR) as number)\n : 0\n}\n\nexport function attributeView<T extends AttributeSchema>(\n gl: GL,\n program: WebGLProgram,\n schema: T,\n { signal }: ViewOptions = {},\n): AttributeView<T> {\n const attributes = mapObject(\n schema,\n (\n { kind, format, normalized = false, instanced, buffer: providedBuffer },\n key,\n ): AttributeMethods => {\n const name = toID(key)\n\n // Whoever made the buffer deletes it. A schema can name a buffer that\n // belongs to another view — the quad `compile.toQuad` shares across every\n // program on a context, an attribute two programs step over — and\n // deleting one of those would take it out from under its owner.\n const buffer = providedBuffer ?? assertedNotNullish(gl.createBuffer())\n\n const location = gl.getAttribLocation(program, name)\n if (location < 0) {\n throw new Error(`Attribute '${name}' not found`)\n }\n\n const size = kindToSize(kind)\n const resolvedFormat = format ?? defaultFormat(kind)\n const glType = FORMAT_TO_GL_TYPE[resolvedFormat]\n const isIntKind = kind.startsWith('i') || kind.startsWith('u')\n\n function applyToVertexArray() {\n // Snapshot before the change, restore in the disposer\n const previousDivisor = readDivisor(gl, location)\n // vertexAttribPointer captures whatever is bound to ARRAY_BUFFER when\n // it runs, so this binding is the setup for the pointer, not a lasting\n // part of the vertex array's state.\n gl.bindBuffer(gl.ARRAY_BUFFER, buffer)\n handleAttribute(gl, location, size, 0, 0, glType, isIntKind, normalized, instanced)\n return once(() => {\n getInstancedArrays(gl)?.vertexAttribDivisor(location, previousDivisor)\n })\n }\n\n return {\n buffer,\n applyToVertexArray,\n bind() {\n const restoreVertexArray = bindDefaultVertexArray(gl)\n const restore = applyToVertexArray()\n return once(() => {\n restore()\n restoreVertexArray()\n })\n },\n dispose: once(() => {\n if (!providedBuffer) {\n gl.deleteBuffer(buffer)\n }\n }),\n set(data, usage = 'STATIC_DRAW') {\n gl.bindBuffer(gl.ARRAY_BUFFER, buffer)\n gl.bufferData(gl.ARRAY_BUFFER, data, gl[usage])\n return this\n },\n }\n },\n )\n\n signal?.addEventListener('abort', function dispose() {\n forEachObject(attributes, value => value.dispose())\n })\n\n return attributes\n}\n\n/**********************************************************************************/\n/* */\n/* Interleaved Attribute View */\n/* */\n/**********************************************************************************/\n\n/**\n * The other place an attribute's value can come from: not a buffer, but the\n * context's current generic vertex attribute values, which an attribute reads\n * for every vertex when its array is disabled.\n *\n * A constant is a uniform in all but name — one value for the whole draw, set\n * by a function chosen from the kind — so it gets the setters a uniform gets,\n * off the same layout the buffer source uses.\n *\n * `vertexAttrib*` tops out at four floats and has no matrix form, so a layout\n * key that is fine in a buffer can be impossible as a constant. That is a hard\n * limit of the API rather than a choice, and it is worth saying so out loud at\n * the point someone reaches for it.\n */\nfunction constantSource(gl: GL, layout: InterleavedAttributeLayout[], locations: number[]) {\n const setters = layout.map((entry, index) => {\n const size = kindToSize(entry.kind)\n const name = toID(entry.key)\n if (isMatKind(entry.kind) || size > 4) {\n throw new Error(\n `'${name}' is a ${entry.kind}, which cannot be a constant attribute: vertexAttrib* takes at most 4 floats and has no matrix form. Use the buffer source for it.`,\n )\n }\n // The values are context state, not vertex-array state, so they are held\n // here and written again on every bind — see applyToContext.\n let values: number[] = []\n const fn = gl[`vertexAttrib${size as 1 | 2 | 3 | 4}f`].bind(gl)\n return {\n name,\n location: locations[index]!,\n write: () => {\n if (values.length) {\n ;(fn as (location: number, ...args: number[]) => void)(locations[index]!, ...values)\n }\n },\n methods: {\n set(...args: number[]) {\n values = args\n },\n },\n }\n })\n\n return Object.assign(Object.fromEntries(setters.map(setter => [setter.name, setter.methods])), {\n applyToVertexArray() {\n const restores = setters.map(({ location }) => {\n const wasEnabled = gl.getVertexAttrib(location, gl.VERTEX_ATTRIB_ARRAY_ENABLED) as boolean\n gl.disableVertexAttribArray(location)\n return () => (wasEnabled ? gl.enableVertexAttribArray(location) : undefined)\n })\n return once(() => restores.forEach(restore => restore()))\n },\n applyToContext() {\n setters.forEach(setter => setter.write())\n },\n bind() {\n const restoreVertexArray = bindDefaultVertexArray(gl)\n const restore = this.applyToVertexArray()\n this.applyToContext()\n return once(() => {\n restore()\n restoreVertexArray()\n })\n },\n })\n}\n\nexport function interleavedAttributeView<T extends InterleavedAttributeSchema>(\n gl: GL,\n program: WebGLProgram,\n schema: T,\n { signal }: ViewOptions = {},\n): InterleavedAttributeView<T> {\n // Initialize interleaved attributes\n const interleavedAttributes = mapObject(schema, ({ layout }) => {\n // Increment number to keep track of offset\n let index = 0\n\n // Calculate layout information\n const locations: number[] = []\n const handles = layout.map(layout => {\n const name = toID(layout.key)\n\n const location = gl.getAttribLocation(program, name)\n\n if (location < 0) {\n throw new Error(`Attribute '${name}' not found`)\n }\n\n locations.push(location)\n\n const size = kindToSize(layout.kind)\n const offset = index\n const resolvedFormat = layout.format ?? defaultFormat(layout.kind)\n const glType = FORMAT_TO_GL_TYPE[resolvedFormat]\n const isIntKind = layout.kind.startsWith('i') || layout.kind.startsWith('u')\n const normalized = layout.normalized ?? false\n index += size * FORMAT_BYTE_SIZE[resolvedFormat]\n\n return (divisor: 0 | 1) =>\n handleAttribute(\n gl,\n location,\n size,\n stride,\n offset,\n glType,\n isIntKind,\n normalized,\n divisor === 1,\n )\n })\n\n // Set stride to final index\n const stride = index\n\n // Create a buffer\n const buffer = assertedNotNullish(gl.createBuffer())\n\n // This layout used to create a vertex array of its own, here, which is why\n // the other participants in a draw had to be bound after it to be included\n // — the array they landed in was whichever one happened to be current.\n // Arrays are `vao()`'s job now; a layout is a layout and a buffer.\n function applyToVertexArray(divisor: 0 | 1) {\n const previousDivisors = locations.map(\n location => [location, readDivisor(gl, location)] as const,\n )\n gl.bindBuffer(gl.ARRAY_BUFFER, buffer)\n for (const handle of handles) {\n handle(divisor)\n }\n return once(() => {\n const instancedArrays = getInstancedArrays(gl)\n previousDivisors.forEach(([location, previous]) => {\n instancedArrays?.vertexAttribDivisor(location, previous)\n })\n })\n }\n\n let constant: ReturnType<typeof constantSource> | undefined\n\n /** One layout, one buffer, but a divisor per draw rather than per schema. */\n function bufferSource(divisor: 0 | 1) {\n const apply = () => applyToVertexArray(divisor)\n return {\n applyToVertexArray: apply,\n bind() {\n const restoreVertexArray = bindDefaultVertexArray(gl)\n const restore = apply()\n return once(() => {\n restore()\n restoreVertexArray()\n })\n },\n }\n }\n\n return {\n buffer: Object.assign(bufferSource(0), {\n /** The same buffer, stepped once per instance instead of once per vertex. */\n perInstance: bufferSource(1),\n set(value: Float32Array, usage: GLUsage = 'STATIC_DRAW') {\n // Uploading is storage, not binding: ARRAY_BUFFER is not vertex-array\n // state, so this touches no array, whichever one is bound.\n gl.bindBuffer(gl.ARRAY_BUFFER, buffer)\n gl.bufferData(gl.ARRAY_BUFFER, value, gl[usage])\n },\n }),\n // Lazy: a layout key can be perfectly good in a buffer and impossible as\n // a constant, and finding that out should wait until someone asks for one.\n get constant() {\n return (constant ??= constantSource(gl, layout, locations))\n },\n dispose: once(() => gl.deleteBuffer(buffer)),\n } satisfies InterleavedAttributeMethods\n })\n\n signal?.addEventListener('abort', function dispose() {\n forEachObject(interleavedAttributes, value => value.dispose())\n })\n\n return interleavedAttributes\n}\n\n/**********************************************************************************/\n/* */\n/* Buffer View */\n/* */\n/**********************************************************************************/\n\nexport function bufferView<T extends BufferSchema>(\n gl: GL,\n schema: T,\n { signal }: ViewOptions = {},\n): BufferView<T> {\n // Initialize buffers\n const buffers = mapObject(schema, ({ target = 'ARRAY_BUFFER', usage = 'STATIC_DRAW' }) => {\n const buffer = assertedNotNullish(gl.createBuffer())\n\n function applyToVertexArray() {\n // Snapshot before the change, restore in the disposer. Restoring the\n // previous buffer rather than null matters for ELEMENT_ARRAY_BUFFER,\n // whose binding is recorded in the bound vertex array: clearing it\n // would strip the index buffer from an array the caller may not own.\n const previousBuffer = gl.getParameter(gl[`${target}_BINDING`]) as WebGLBuffer | null\n gl.bindBuffer(gl[target], buffer)\n return once(() => {\n gl.bindBuffer(gl[target], previousBuffer)\n })\n }\n\n return {\n applyToVertexArray,\n bind() {\n // ELEMENT_ARRAY_BUFFER's binding belongs to the bound vertex array, so\n // like the attributes this has to say which array it means. ARRAY_BUFFER\n // is context state and unaffected either way.\n const restoreVertexArray = bindDefaultVertexArray(gl)\n const restore = applyToVertexArray()\n return once(() => {\n restore()\n restoreVertexArray()\n })\n },\n dispose: once(() => gl.deleteBuffer(buffer)),\n set(data: Float32Array) {\n gl.bindBuffer(gl[target], buffer)\n gl.bufferData(gl[target], data, gl[usage])\n },\n }\n })\n\n signal?.addEventListener('abort', function dispose() {\n forEachObject(buffers, value => value.dispose())\n })\n\n return buffers\n}\n"],"mappings":"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","names":["location","index","layout"]}