@bigmistqke/view.gl 0.1.18 → 0.2.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
@@ -204,6 +204,18 @@ attributes.instanceOffset.set(instanceData).bind()
204
204
  gl.drawArraysInstanced(gl.TRIANGLES, 0, 3, 100)
205
205
  ```
206
206
 
207
+ `bind()` returns a disposer that restores the state it changed — here the
208
+ instancing divisor, which belongs to the attribute location rather than to the
209
+ program, and so is inherited by whatever binds there next. Ignore it when the
210
+ view owns its locations for the lifetime of the program; call it when they are
211
+ shared:
212
+
213
+ ```typescript
214
+ const unbind = attributes.instanceOffset.set(instanceData).bind()
215
+ gl.drawArraysInstanced(gl.TRIANGLES, 0, 3, 100)
216
+ unbind()
217
+ ```
218
+
207
219
  ##### 📋 AttributeSchema
208
220
 
209
221
  A mapping of attribute names to their configuration.
@@ -258,6 +270,16 @@ const interleavedAttributes = interleavedAttributeView(gl, program, {
258
270
  interleavedAttributes.vertexData.set(interleavedVertexData).bind()
259
271
  ```
260
272
 
273
+ Where vertex array objects are available this binds one, and it stays selected
274
+ for every later draw — which would then write its own attributes into it. The
275
+ disposer returned by `bind()` selects the previous array again:
276
+
277
+ ```typescript
278
+ const unbind = interleavedAttributes.vertexData.bind()
279
+ gl.drawElements(gl.TRIANGLES, count, gl.UNSIGNED_SHORT, 0)
280
+ unbind()
281
+ ```
282
+
261
283
  ##### 📋 InterleavedAttributeSchema
262
284
 
263
285
  A mapping of interleaved buffer names to their layout configuration. Each layout defines multiple attributes packed into a single buffer.
@@ -296,6 +318,10 @@ const buffers = bufferView(gl, {
296
318
 
297
319
  buffers.indices.set(indexData).bind()
298
320
  buffers.data.set(dynamicData).bind()
321
+
322
+ // bind() returns a disposer restoring the previous binding for that target.
323
+ // Worth calling for ELEMENT_ARRAY_BUFFER, whose binding is recorded in the
324
+ // bound vertex array object.
299
325
  ```
300
326
 
301
327
  ##### 📋 BufferSchema
@@ -72,4 +72,4 @@ export {
72
72
  getInstancedArrays,
73
73
  getVertexArrayObject
74
74
  };
75
- //# sourceMappingURL=chunk-WSNE4JVQ.mjs.map
75
+ //# sourceMappingURL=chunk-CJTT7WPV.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/gl.ts"],"sourcesContent":["import { RemoveSuffix } from './type-utils'\nimport type { GL } from './types'\n\nfunction isWebGL2RenderingContext(\n gl: WebGLRenderingContext | WebGL2RenderingContext,\n): gl is WebGL2RenderingContext {\n return typeof WebGL2RenderingContext !== 'undefined' && gl instanceof WebGL2RenderingContext\n}\n\n/**********************************************************************************/\n/* */\n/* Create Shader */\n/* */\n/**********************************************************************************/\n\nexport function createShader(gl: GL, type: number, source: string): WebGLShader {\n const shader = gl.createShader(type)\n if (!shader) throw new Error('Failed to create shader')\n\n gl.shaderSource(shader, source)\n gl.compileShader(shader)\n\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n const info = gl.getShaderInfoLog(shader)\n gl.deleteShader(shader)\n throw new Error(\n `Failed to compile ${type === gl.VERTEX_SHADER ? 'vertex' : 'fragment'} shader: ${info}`,\n )\n }\n\n return shader\n}\n\n/**********************************************************************************/\n/* */\n/* Create Program */\n/* */\n/**********************************************************************************/\n\nexport function createProgram(gl: GL, vertexSource: string, fragmentSource: string): WebGLProgram {\n const program = gl.createProgram()\n if (!program) throw new Error('Failed to create WebGL program')\n\n const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexSource)\n const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentSource)\n\n gl.attachShader(program, vertexShader)\n gl.attachShader(program, fragmentShader)\n gl.linkProgram(program)\n\n if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n const info = gl.getProgramInfoLog(program)\n gl.deleteProgram(program)\n gl.deleteShader(vertexShader)\n gl.deleteShader(fragmentShader)\n throw new Error(`Failed to link program: ${info}`)\n }\n\n // Clean up shaders after linking\n gl.deleteShader(vertexShader)\n gl.deleteShader(fragmentShader)\n\n return program\n}\n\n/**********************************************************************************/\n/* */\n/* Get Instanced Arrays */\n/* */\n/**********************************************************************************/\n\nconst INSTANCED_ARRAYS_WRAPPER_MAP = new WeakMap<\n GL,\n RemoveSuffix<\n Pick<\n ANGLE_instanced_arrays,\n 'drawArraysInstancedANGLE' | 'drawElementsInstancedANGLE' | 'vertexAttribDivisorANGLE'\n >,\n 'ANGLE'\n > | null\n>()\nexport function getInstancedArrays(gl: GL) {\n if (isWebGL2RenderingContext(gl)) return gl\n\n const cached = INSTANCED_ARRAYS_WRAPPER_MAP.get(gl)\n if (cached) return cached\n\n const ext = gl.getExtension('ANGLE_instanced_arrays')\n if (!ext) return undefined\n\n const wrapper = {\n drawArraysInstanced: ext.drawArraysInstancedANGLE.bind(ext),\n drawElementsInstanced: ext.drawElementsInstancedANGLE.bind(ext),\n vertexAttribDivisor: ext.vertexAttribDivisorANGLE.bind(ext),\n }\n INSTANCED_ARRAYS_WRAPPER_MAP.set(gl, wrapper)\n\n return wrapper\n}\n\n/**********************************************************************************/\n/* */\n/* Get Vertex Array Object */\n/* */\n/**********************************************************************************/\n\nconst VERTEX_ARRAY_OBJECT_WRAPPER_MAP = new WeakMap<\n GL,\n RemoveSuffix<\n Pick<\n OES_vertex_array_object,\n 'bindVertexArrayOES' | 'createVertexArrayOES' | 'deleteVertexArrayOES'\n >,\n 'OES'\n > | null\n>()\nexport function getVertexArrayObject(gl: GL) {\n if (isWebGL2RenderingContext(gl)) return gl\n\n const cached = VERTEX_ARRAY_OBJECT_WRAPPER_MAP.get(gl)\n if (cached) return cached\n\n const ext = gl.getExtension('OES_vertex_array_object')\n if (!ext) return null\n\n const wrapper = {\n bindVertexArray: ext.bindVertexArrayOES.bind(ext),\n createVertexArray: ext.createVertexArrayOES.bind(ext),\n deleteVertexArray: ext.deleteVertexArrayOES.bind(ext),\n }\n VERTEX_ARRAY_OBJECT_WRAPPER_MAP.set(gl, wrapper)\n\n return wrapper\n}\n"],"mappings":";AAGA,SAAS,yBACP,IAC8B;AAC9B,SAAO,OAAO,2BAA2B,eAAe,cAAc;AACxE;AAQO,SAAS,aAAa,IAAQ,MAAc,QAA6B;AAC9E,QAAM,SAAS,GAAG,aAAa,IAAI;AACnC,MAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,yBAAyB;AAEtD,KAAG,aAAa,QAAQ,MAAM;AAC9B,KAAG,cAAc,MAAM;AAEvB,MAAI,CAAC,GAAG,mBAAmB,QAAQ,GAAG,cAAc,GAAG;AACrD,UAAM,OAAO,GAAG,iBAAiB,MAAM;AACvC,OAAG,aAAa,MAAM;AACtB,UAAM,IAAI;AAAA,MACR,qBAAqB,SAAS,GAAG,gBAAgB,WAAW,UAAU,YAAY,IAAI;AAAA,IACxF;AAAA,EACF;AAEA,SAAO;AACT;AAQO,SAAS,cAAc,IAAQ,cAAsB,gBAAsC;AAChG,QAAM,UAAU,GAAG,cAAc;AACjC,MAAI,CAAC,QAAS,OAAM,IAAI,MAAM,gCAAgC;AAE9D,QAAM,eAAe,aAAa,IAAI,GAAG,eAAe,YAAY;AACpE,QAAM,iBAAiB,aAAa,IAAI,GAAG,iBAAiB,cAAc;AAE1E,KAAG,aAAa,SAAS,YAAY;AACrC,KAAG,aAAa,SAAS,cAAc;AACvC,KAAG,YAAY,OAAO;AAEtB,MAAI,CAAC,GAAG,oBAAoB,SAAS,GAAG,WAAW,GAAG;AACpD,UAAM,OAAO,GAAG,kBAAkB,OAAO;AACzC,OAAG,cAAc,OAAO;AACxB,OAAG,aAAa,YAAY;AAC5B,OAAG,aAAa,cAAc;AAC9B,UAAM,IAAI,MAAM,2BAA2B,IAAI,EAAE;AAAA,EACnD;AAGA,KAAG,aAAa,YAAY;AAC5B,KAAG,aAAa,cAAc;AAE9B,SAAO;AACT;AAQA,IAAM,+BAA+B,oBAAI,QASvC;AACK,SAAS,mBAAmB,IAAQ;AACzC,MAAI,yBAAyB,EAAE,EAAG,QAAO;AAEzC,QAAM,SAAS,6BAA6B,IAAI,EAAE;AAClD,MAAI,OAAQ,QAAO;AAEnB,QAAM,MAAM,GAAG,aAAa,wBAAwB;AACpD,MAAI,CAAC,IAAK,QAAO;AAEjB,QAAM,UAAU;AAAA,IACd,qBAAqB,IAAI,yBAAyB,KAAK,GAAG;AAAA,IAC1D,uBAAuB,IAAI,2BAA2B,KAAK,GAAG;AAAA,IAC9D,qBAAqB,IAAI,yBAAyB,KAAK,GAAG;AAAA,EAC5D;AACA,+BAA6B,IAAI,IAAI,OAAO;AAE5C,SAAO;AACT;AAQA,IAAM,kCAAkC,oBAAI,QAS1C;AACK,SAAS,qBAAqB,IAAQ;AAC3C,MAAI,yBAAyB,EAAE,EAAG,QAAO;AAEzC,QAAM,SAAS,gCAAgC,IAAI,EAAE;AACrD,MAAI,OAAQ,QAAO;AAEnB,QAAM,MAAM,GAAG,aAAa,yBAAyB;AACrD,MAAI,CAAC,IAAK,QAAO;AAEjB,QAAM,UAAU;AAAA,IACd,iBAAiB,IAAI,mBAAmB,KAAK,GAAG;AAAA,IAChD,mBAAmB,IAAI,qBAAqB,KAAK,GAAG;AAAA,IACpD,mBAAmB,IAAI,qBAAqB,KAAK,GAAG;AAAA,EACtD;AACA,kCAAgC,IAAI,IAAI,OAAO;AAE/C,SAAO;AACT;","names":[]}
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getInstancedArrays,
3
3
  getVertexArrayObject
4
- } from "./chunk-WSNE4JVQ.mjs";
4
+ } from "./chunk-CJTT7WPV.mjs";
5
5
 
6
6
  // src/utils.ts
7
7
  function assertedNotNullish(value, message) {
@@ -112,9 +112,62 @@ function view(gl, program, schema, options) {
112
112
  uniforms: !schema.uniforms ? void 0 : uniformView(gl, program, schema.uniforms),
113
113
  attributes: !schema.attributes ? void 0 : attributeView(gl, program, schema.attributes, options),
114
114
  interleavedAttributes: !schema.interleavedAttributes ? void 0 : interleavedAttributeView(gl, program, schema.interleavedAttributes, options),
115
- buffers: !schema.buffers ? void 0 : bufferView(gl, schema.buffers)
115
+ buffers: !schema.buffers ? void 0 : bufferView(gl, schema.buffers),
116
+ vao(participants) {
117
+ return vaoView(gl, participants, options);
118
+ }
116
119
  };
117
120
  }
121
+ function bindDefaultVertexArray(gl) {
122
+ const feature = getVertexArrayObject(gl);
123
+ if (!feature) {
124
+ return () => {
125
+ };
126
+ }
127
+ const previous = gl.getParameter(VERTEX_ARRAY_BINDING);
128
+ feature.bindVertexArray(null);
129
+ return () => feature.bindVertexArray(previous);
130
+ }
131
+ function vaoView(gl, participants, { signal } = {}) {
132
+ const feature = getVertexArrayObject(gl);
133
+ const methods = !feature ? {
134
+ bind() {
135
+ const restores = participants.map((participant) => participant.applyToVertexArray());
136
+ participants.forEach((participant) => participant.applyToContext?.());
137
+ return once(() => restores.forEach((restore) => restore()));
138
+ },
139
+ unbind() {
140
+ },
141
+ dispose() {
142
+ }
143
+ } : (() => {
144
+ const vertexArray = assertedNotNullish(feature.createVertexArray());
145
+ const previous = gl.getParameter(VERTEX_ARRAY_BINDING);
146
+ feature.bindVertexArray(vertexArray);
147
+ for (const participant of participants) {
148
+ participant.applyToVertexArray();
149
+ }
150
+ feature.bindVertexArray(previous);
151
+ return {
152
+ bind() {
153
+ const previousVertexArray = gl.getParameter(
154
+ VERTEX_ARRAY_BINDING
155
+ );
156
+ feature.bindVertexArray(vertexArray);
157
+ participants.forEach((participant) => participant.applyToContext?.());
158
+ return once(() => feature.bindVertexArray(previousVertexArray));
159
+ },
160
+ unbind() {
161
+ feature.bindVertexArray(null);
162
+ },
163
+ dispose() {
164
+ feature.deleteVertexArray(vertexArray);
165
+ }
166
+ };
167
+ })();
168
+ signal?.addEventListener("abort", () => methods.dispose());
169
+ return methods;
170
+ }
118
171
  function uniformView(gl, program, schema) {
119
172
  return mapObject(schema, ({ kind, size }, key) => {
120
173
  const name2 = toID(key);
@@ -195,14 +248,36 @@ function handleAttribute(gl, location, size, stride, offset, glType, isIntegerKi
195
248
  } else {
196
249
  gl.vertexAttribPointer(location, size, gl[glType], normalized, stride, offset);
197
250
  }
251
+ const instancedArrays = getInstancedArrays(gl);
198
252
  if (instanced) {
199
- assertedNotNullish(getInstancedArrays(gl)).vertexAttribDivisor(location, 1);
253
+ assertedNotNullish(instancedArrays).vertexAttribDivisor(location, 1);
254
+ } else if (instancedArrays) {
255
+ instancedArrays.vertexAttribDivisor(location, 0);
200
256
  }
201
257
  }
258
+ var VERTEX_ATTRIB_ARRAY_DIVISOR = 35070;
259
+ var VERTEX_ARRAY_BINDING = 34229;
260
+ function readDivisor(gl, location) {
261
+ return getInstancedArrays(gl) ? gl.getVertexAttrib(location, VERTEX_ATTRIB_ARRAY_DIVISOR) : 0;
262
+ }
263
+ function once(restore) {
264
+ let done = false;
265
+ return () => {
266
+ if (done) return;
267
+ done = true;
268
+ restore();
269
+ };
270
+ }
202
271
  function attributeView(gl, program, schema, { signal } = {}) {
203
272
  const attributes = mapObject(
204
273
  schema,
205
- ({ kind, format, normalized = false, instanced, buffer = assertedNotNullish(gl.createBuffer()) }, key) => {
274
+ ({
275
+ kind,
276
+ format,
277
+ normalized = false,
278
+ instanced,
279
+ buffer = assertedNotNullish(gl.createBuffer())
280
+ }, key) => {
206
281
  const name2 = toID(key);
207
282
  const location = gl.getAttribLocation(program, name2);
208
283
  if (location < 0) {
@@ -212,11 +287,24 @@ function attributeView(gl, program, schema, { signal } = {}) {
212
287
  const resolvedFormat = format ?? defaultFormat(kind);
213
288
  const glType = FORMAT_TO_GL_TYPE[resolvedFormat];
214
289
  const isIntKind = kind.startsWith("i") || kind.startsWith("u");
290
+ function applyToVertexArray() {
291
+ const previousDivisor = readDivisor(gl, location);
292
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
293
+ handleAttribute(gl, location, size, 0, 0, glType, isIntKind, normalized, instanced);
294
+ return once(() => {
295
+ getInstancedArrays(gl)?.vertexAttribDivisor(location, previousDivisor);
296
+ });
297
+ }
215
298
  return {
216
299
  buffer,
300
+ applyToVertexArray,
217
301
  bind() {
218
- gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
219
- handleAttribute(gl, location, size, 0, 0, glType, isIntKind, normalized, instanced);
302
+ const restoreVertexArray = bindDefaultVertexArray(gl);
303
+ const restore = applyToVertexArray();
304
+ return once(() => {
305
+ restore();
306
+ restoreVertexArray();
307
+ });
220
308
  },
221
309
  dispose() {
222
310
  gl.deleteBuffer(buffer);
@@ -234,15 +322,67 @@ function attributeView(gl, program, schema, { signal } = {}) {
234
322
  });
235
323
  return attributes;
236
324
  }
325
+ function constantSource(gl, layout, locations) {
326
+ const setters = layout.map((entry, index2) => {
327
+ const size = kindToSize(entry.kind);
328
+ const name2 = toID(entry.key);
329
+ if (isMatKind(entry.kind) || size > 4) {
330
+ throw new Error(
331
+ `'${name2}' 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.`
332
+ );
333
+ }
334
+ let values = [];
335
+ const fn = gl[`vertexAttrib${size}f`].bind(gl);
336
+ return {
337
+ name: name2,
338
+ location: locations[index2],
339
+ write: () => {
340
+ if (values.length) {
341
+ ;
342
+ fn(locations[index2], ...values);
343
+ }
344
+ },
345
+ methods: {
346
+ set(...args) {
347
+ values = args;
348
+ }
349
+ }
350
+ };
351
+ });
352
+ return Object.assign(Object.fromEntries(setters.map((setter) => [setter.name, setter.methods])), {
353
+ applyToVertexArray() {
354
+ const restores = setters.map(({ location }) => {
355
+ const wasEnabled = gl.getVertexAttrib(location, gl.VERTEX_ATTRIB_ARRAY_ENABLED);
356
+ gl.disableVertexAttribArray(location);
357
+ return () => wasEnabled ? gl.enableVertexAttribArray(location) : void 0;
358
+ });
359
+ return once(() => restores.forEach((restore) => restore()));
360
+ },
361
+ applyToContext() {
362
+ setters.forEach((setter) => setter.write());
363
+ },
364
+ bind() {
365
+ const restoreVertexArray = bindDefaultVertexArray(gl);
366
+ const restore = this.applyToVertexArray();
367
+ this.applyToContext();
368
+ return once(() => {
369
+ restore();
370
+ restoreVertexArray();
371
+ });
372
+ }
373
+ });
374
+ }
237
375
  function interleavedAttributeView(gl, program, schema, { signal } = {}) {
238
- const interleavedAttributes = mapObject(schema, ({ layout, instanced }) => {
376
+ const interleavedAttributes = mapObject(schema, ({ layout }) => {
239
377
  let index2 = 0;
378
+ const locations = [];
240
379
  const handles = layout.map((layout2) => {
241
380
  const name2 = toID(layout2.key);
242
381
  const location = gl.getAttribLocation(program, name2);
243
382
  if (location < 0) {
244
383
  throw new Error(`Attribute '${name2}' not found`);
245
384
  }
385
+ locations.push(location);
246
386
  const size = kindToSize(layout2.kind);
247
387
  const offset = index2;
248
388
  const resolvedFormat = layout2.format ?? defaultFormat(layout2.kind);
@@ -250,63 +390,66 @@ function interleavedAttributeView(gl, program, schema, { signal } = {}) {
250
390
  const isIntKind = layout2.kind.startsWith("i") || layout2.kind.startsWith("u");
251
391
  const normalized = layout2.normalized ?? false;
252
392
  index2 += size * FORMAT_BYTE_SIZE[resolvedFormat];
253
- return () => handleAttribute(gl, location, size, stride, offset, glType, isIntKind, normalized, instanced);
393
+ return (divisor) => handleAttribute(
394
+ gl,
395
+ location,
396
+ size,
397
+ stride,
398
+ offset,
399
+ glType,
400
+ isIntKind,
401
+ normalized,
402
+ divisor === 1
403
+ );
254
404
  });
255
405
  const stride = index2;
256
406
  const buffer = assertedNotNullish(gl.createBuffer());
257
- let vao = void 0;
258
- const feature = getVertexArrayObject(gl);
259
- if (feature) {
260
- const vertexArray = feature.createVertexArray();
261
- feature.bindVertexArray(vertexArray);
407
+ function applyToVertexArray(divisor) {
408
+ const previousDivisors = locations.map(
409
+ (location) => [location, readDivisor(gl, location)]
410
+ );
262
411
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
263
412
  for (const handle of handles) {
264
- handle();
413
+ handle(divisor);
265
414
  }
266
- feature.bindVertexArray(null);
267
- vao = {
268
- unbind() {
269
- feature.bindVertexArray(null);
270
- },
415
+ return once(() => {
416
+ const instancedArrays = getInstancedArrays(gl);
417
+ previousDivisors.forEach(([location, previous]) => {
418
+ instancedArrays?.vertexAttribDivisor(location, previous);
419
+ });
420
+ });
421
+ }
422
+ let constant;
423
+ function bufferSource(divisor) {
424
+ const apply = () => applyToVertexArray(divisor);
425
+ return {
426
+ applyToVertexArray: apply,
271
427
  bind() {
272
- feature.bindVertexArray(vertexArray);
273
- },
274
- dispose() {
275
- feature.deleteVertexArray(vertexArray);
428
+ const restoreVertexArray = bindDefaultVertexArray(gl);
429
+ const restore = apply();
430
+ return once(() => {
431
+ restore();
432
+ restoreVertexArray();
433
+ });
276
434
  }
277
435
  };
278
436
  }
279
437
  return {
280
- bind() {
281
- gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
282
- if (vao) {
283
- vao.bind();
284
- } else {
285
- for (const handle of handles) {
286
- handle();
287
- }
288
- }
289
- },
290
- unbind() {
291
- if (vao) {
292
- vao.unbind();
438
+ buffer: Object.assign(bufferSource(0), {
439
+ /** The same buffer, stepped once per instance instead of once per vertex. */
440
+ perInstance: bufferSource(1),
441
+ set(value, usage = "STATIC_DRAW") {
442
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
443
+ gl.bufferData(gl.ARRAY_BUFFER, value, gl[usage]);
293
444
  }
445
+ }),
446
+ // Lazy: a layout key can be perfectly good in a buffer and impossible as
447
+ // a constant, and finding that out should wait until someone asks for one.
448
+ get constant() {
449
+ return constant ??= constantSource(gl, layout, locations);
294
450
  },
295
451
  dispose() {
296
452
  gl.deleteBuffer(buffer);
297
- if (vao) {
298
- vao.dispose();
299
- }
300
- },
301
- set(value, usage = "STATIC_DRAW") {
302
- if (vao) {
303
- vao.bind();
304
- }
305
- gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
306
- gl.bufferData(gl.ARRAY_BUFFER, value, gl[usage]);
307
- if (vao) {
308
- vao.unbind();
309
- }
310
453
  }
311
454
  };
312
455
  });
@@ -318,9 +461,22 @@ function interleavedAttributeView(gl, program, schema, { signal } = {}) {
318
461
  function bufferView(gl, schema, { signal } = {}) {
319
462
  const buffers = mapObject(schema, ({ target = "ARRAY_BUFFER", usage = "STATIC_DRAW" }) => {
320
463
  const buffer = assertedNotNullish(gl.createBuffer());
464
+ function applyToVertexArray() {
465
+ const previousBuffer = gl.getParameter(gl[`${target}_BINDING`]);
466
+ gl.bindBuffer(gl[target], buffer);
467
+ return once(() => {
468
+ gl.bindBuffer(gl[target], previousBuffer);
469
+ });
470
+ }
321
471
  return {
472
+ applyToVertexArray,
322
473
  bind() {
323
- gl.bindBuffer(gl[target], buffer);
474
+ const restoreVertexArray = bindDefaultVertexArray(gl);
475
+ const restore = applyToVertexArray();
476
+ return once(() => {
477
+ restore();
478
+ restoreVertexArray();
479
+ });
324
480
  },
325
481
  dispose() {
326
482
  gl.deleteBuffer(buffer);
@@ -341,9 +497,10 @@ export {
341
497
  createUpsertMap,
342
498
  toID,
343
499
  view,
500
+ vaoView,
344
501
  uniformView,
345
502
  attributeView,
346
503
  interleavedAttributeView,
347
504
  bufferView
348
505
  };
349
- //# sourceMappingURL=chunk-CLMGHUTT.mjs.map
506
+ //# sourceMappingURL=chunk-EYXOSM7B.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils.ts","../src/index.ts"],"sourcesContent":["import type {\n AttributeKind,\n FramebufferDefinition,\n GL,\n KIND_TO_SIZE_MAP,\n KIND_TO_UNIFORM_FN_NAME_MAP,\n TextureDefinition,\n UniformKind,\n} from './types'\n\nexport function assertedNotNullish<T>(value: T, message?: string): NonNullable<T> {\n if (value === undefined || value === null) throw new Error(message)\n return value\n}\n\n/**********************************************************************************/\n/* */\n/* Kind To Uniform Name */\n/* */\n/**********************************************************************************/\n\nexport const kindToUniformFnName = <T extends UniformKind>(\n kind: T,\n): KIND_TO_UNIFORM_FN_NAME_MAP[T] => {\n switch (kind[0]) {\n // mat\n case 'm':\n return ('Matrix' + kind.slice(3) + 'fv') as KIND_TO_UNIFORM_FN_NAME_MAP[T]\n // sampler/booleans/integer\n case 's':\n case 'b':\n case 'i':\n return ((kind.match(/\\d/)?.[0] ?? '1') + 'i') as KIND_TO_UNIFORM_FN_NAME_MAP[T]\n // unsigned integers\n case 'u':\n return ((kind[4] || '1') + 'ui') as KIND_TO_UNIFORM_FN_NAME_MAP[T]\n // vec\n case 'v':\n return (kind[3] + 'f') as KIND_TO_UNIFORM_FN_NAME_MAP[T]\n default:\n switch (kind) {\n case 'float':\n return '1f' as KIND_TO_UNIFORM_FN_NAME_MAP[T]\n case 'uint':\n return '1ui' as KIND_TO_UNIFORM_FN_NAME_MAP[T]\n default:\n return '1i' as KIND_TO_UNIFORM_FN_NAME_MAP[T]\n }\n }\n}\n\n/**********************************************************************************/\n/* */\n/* Kind To Size */\n/* */\n/**********************************************************************************/\n\nexport const kindToSize = <T extends UniformKind>(kind: T): KIND_TO_SIZE_MAP[T] => {\n switch (kind[0]) {\n case 'm':\n const [a, b] = kind.match(/\\d+/g)!.map(Number) as [number, number?]\n return (a * (b ?? a)) as KIND_TO_SIZE_MAP[T]\n case 'v':\n case 'i':\n case 'b':\n case 'u':\n const match = kind.match(/\\d/) as [string] | undefined\n return (match ? +match[0] : 1) as KIND_TO_SIZE_MAP[T]\n default:\n return 1 as KIND_TO_SIZE_MAP[T]\n }\n}\n\n/**********************************************************************************/\n/* */\n/* Guards */\n/* */\n/**********************************************************************************/\n\nexport const isMatKind = <\n T extends UniformKind | AttributeKind,\n TPrefix extends string,\n TPostfix extends string,\n>(\n kind: T,\n): kind is T & `${TPrefix}mat${TPostfix}` => kind.includes('mat')\n\nexport const isSamplerKind = <TPrefix extends string, TPostfix extends string>(\n kind: UniformKind,\n): kind is UniformKind & `${TPrefix}sampler${TPostfix}` => kind.includes('sampler')\n\nexport const isVecKind = <TPrefix extends string, TPostfix extends string>(\n kind: UniformKind,\n): kind is UniformKind & `${TPrefix}vec${TPostfix}` => kind.includes('vec')\n\n/**********************************************************************************/\n/* */\n/* Create Texture */\n/* */\n/**********************************************************************************/\n\nexport function createTexture(\n gl: GL,\n {\n target = 'TEXTURE_2D',\n internalFormat = 'RGBA',\n format = 'RGBA',\n type = 'UNSIGNED_BYTE',\n minFilter = 'NEAREST',\n magFilter = 'NEAREST',\n wrapS = 'CLAMP_TO_EDGE',\n wrapT = 'CLAMP_TO_EDGE',\n width,\n height,\n }: TextureDefinition,\n data?: ArrayBufferView | null,\n): WebGLTexture {\n const texture = gl.createTexture()\n\n function getTextureConstant(name: string) {\n if (!(name in gl)) {\n throw new Error(`Attempted to create webgl2-only texture (${name}) in webgl1`)\n }\n return gl[name as keyof typeof gl] as any\n }\n\n gl.bindTexture(gl[target], texture)\n gl.texImage2D(\n gl[target],\n 0,\n getTextureConstant(internalFormat),\n width,\n height,\n 0,\n getTextureConstant(format),\n getTextureConstant(type),\n data ?? null,\n )\n\n console.log(minFilter)\n // Set texture parameters\n gl.texParameteri(gl[target], gl.TEXTURE_MIN_FILTER, gl[minFilter])\n gl.texParameteri(gl[target], gl.TEXTURE_MAG_FILTER, gl[magFilter])\n gl.texParameteri(gl[target], gl.TEXTURE_WRAP_S, gl[wrapS])\n gl.texParameteri(gl[target], gl.TEXTURE_WRAP_T, gl[wrapT])\n\n return texture\n}\n\n/**********************************************************************************/\n/* */\n/* Create Framebuffer */\n/* */\n/**********************************************************************************/\n\nconst FRAMEBUFFER_ATTACHMENT_MAP = {\n color: 'COLOR_ATTACHMENT0',\n depth: 'DEPTH_ATTACHMENT',\n stencil: 'STENCIL_ATTACHMENT',\n depthStencil: 'DEPTH_STENCIL_ATTACHMENT',\n} as const\n\nclass FramebufferError extends Error {\n constructor(gl: GL, status: number) {\n let errorMessage = `Framebuffer '${name}' not complete. Status: `\n switch (status) {\n case gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:\n errorMessage += 'FRAMEBUFFER_INCOMPLETE_ATTACHMENT'\n break\n case gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:\n errorMessage += 'FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT'\n break\n case gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:\n errorMessage += 'FRAMEBUFFER_INCOMPLETE_DIMENSIONS'\n break\n case gl.FRAMEBUFFER_UNSUPPORTED:\n errorMessage += 'FRAMEBUFFER_UNSUPPORTED'\n break\n default:\n errorMessage += `Unknown (${status})`\n }\n super(errorMessage)\n }\n}\n\nexport function createFramebuffer(\n gl: GL,\n { attachment, texture, ...options }: FramebufferDefinition,\n) {\n // Create texture for the framebuffer\n texture ??= createTexture(gl, options)\n\n // Create framebuffer\n const framebuffer = assertedNotNullish(\n gl.createFramebuffer(),\n `Failed to create framebuffer: ${name}`,\n )\n\n gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer)\n\n gl.framebufferTexture2D(\n gl.FRAMEBUFFER,\n // Determine attachment point based on attachment kind\n gl[FRAMEBUFFER_ATTACHMENT_MAP[attachment]],\n gl.TEXTURE_2D,\n texture,\n 0,\n )\n\n // Check framebuffer completeness\n const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER)\n if (status !== gl.FRAMEBUFFER_COMPLETE) {\n throw new FramebufferError(gl, status)\n }\n\n return {\n texture,\n framebuffer,\n }\n}\n\n/**********************************************************************************/\n/* */\n/* Create Upsert */\n/* */\n/**********************************************************************************/\n\ntype UpsertMapKind<T, U> = Map<T, U> | (T extends WeakKey ? WeakMap<T, U> : never)\n\nexport function createUpsertMap<T extends UpsertMapKind<any, any> = Map<any, any>>(\n constructor?: new () => T,\n) {\n const map = new (constructor ?? Map)() as T\n return Object.assign(map, {\n getOrInsert(\n key: T extends UpsertMapKind<infer U, any> ? U : never,\n value: T extends UpsertMapKind<any, infer U> ? () => U : never,\n ) {\n let result = map.get(key)\n if (result) {\n return result\n }\n result = value()\n map.set(key, result)\n return result\n },\n })\n}\n\nexport function forEachObject<T extends Record<string, any>>(\n value: T,\n callback: (value: T[keyof T], key: keyof T, index: number) => void,\n) {\n let index = 0\n for (const key in value) {\n callback(value[key], key, index)\n index++\n }\n for (const key of Object.getOwnPropertySymbols(value)) {\n callback(value[key as keyof T], key as keyof T, index)\n index++\n }\n}\n\nexport function mapObject<T extends Record<string, any>, TReturn>(\n value: T,\n callback: (value: T[keyof T], key: keyof T, index: number) => TReturn,\n): { [TKey in keyof T]: TReturn } {\n const result = {} as { [TKey in keyof T]: TReturn }\n\n forEachObject(value, (value, key, index) => {\n result[key] = callback(value, key, index)\n })\n\n return result\n}\n","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} from './utils'\nimport { createUpsertMap, mapObject } from './utils'\nexport * from './types'\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 options?: ViewOptions,\n): View<TSchema> {\n return {\n uniforms: !schema.uniforms ? undefined : uniformView(gl, program, schema.uniforms),\n attributes: !schema.attributes\n ? undefined\n : attributeView(gl, program, schema.attributes, options),\n interleavedAttributes: !schema.interleavedAttributes\n ? undefined\n : interleavedAttributeView(gl, program, schema.interleavedAttributes, options),\n buffers: !schema.buffers ? undefined : bufferView(gl, schema.buffers),\n vao(participants: VertexArrayParticipant[]) {\n return vaoView(gl, participants, options)\n },\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() {\n feature.deleteVertexArray(vertexArray)\n },\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\n// Wraps a restore so it runs once: a disposer is per bind() and undoing twice\n// would put back state a later bind() is relying on\nfunction once(restore: () => void): () => void {\n let done = false\n return () => {\n if (done) return\n done = true\n restore()\n }\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 {\n kind,\n format,\n normalized = false,\n instanced,\n buffer = assertedNotNullish(gl.createBuffer()),\n },\n key,\n ): AttributeMethods => {\n const name = toID(key)\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() {\n gl.deleteBuffer(buffer)\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() {\n gl.deleteBuffer(buffer)\n },\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() {\n gl.deleteBuffer(buffer)\n },\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":["index","value","name","location","index","layout"]}
package/dist/gl.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { G as GL, R as RemoveSuffix } from './types-CXqYX05f.mjs';
1
+ import { G as GL, R as RemoveSuffix } from './types-CyGyGi18.mjs';
2
2
 
3
3
  /**********************************************************************************/
4
4
  /**********************************************************************************/
package/dist/gl.mjs CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  createShader,
4
4
  getInstancedArrays,
5
5
  getVertexArrayObject
6
- } from "./chunk-WSNE4JVQ.mjs";
6
+ } from "./chunk-CJTT7WPV.mjs";
7
7
  export {
8
8
  createProgram,
9
9
  createShader,
package/dist/index.d.mts CHANGED
@@ -1,19 +1,27 @@
1
- import { V as ViewSchema, G as GL, a as ViewOptions, b as View, U as UniformSchema, c as UniformView, A as AttributeSchema, d as AttributeView, I as InterleavedAttributeSchema, e as InterleavedAttributeView, B as BufferSchema, f as BufferView } from './types-CXqYX05f.mjs';
2
- export { z as AttributeDefinition, y as AttributeFormat, x as AttributeKind, C as AttributeMethods, w as AttributeShortHand, a6 as AttributeToken, a7 as AttributeTokenFn, H as BufferDefinition, J as BufferMethods, ae as CompileResult, ac as FlattenSlots, Z as Format, M as Framebuffer, L as FramebufferDefinition, a3 as GLSL, a1 as GLSLResult, a2 as GLSLSlot, ab as GLSLSlotsToSchema, a9 as GLSLToSchema, aa as GLSLToView, g as GLTarget, l as GLTextureFilter, j as GLTextureFormat, i as GLTextureTarget, k as GLTextureType, m as GLTextureWrap, h as GLUsage, a8 as InterleaveToken, E as InterleavedAttributeDefinition, D as InterleavedAttributeLayout, F as InterleavedAttributeMethods, Y as InternalFormat, n as KIND_TO_SIZE_MAP, K as KIND_TO_UNIFORM_FN_NAME_MAP, ad as MergeGLSLSchema, _ as PixelType, $ as TexImage2DOptions, T as TextureDefinition, P as TextureMethods, S as TextureParameterName, W as TextureParameterValue, X as TextureParameters, O as TextureSchema, N as TextureTarget, Q as TextureView, t as UniformArrayMethods, r as UniformDefinition, s as UniformElementMethods, o as UniformFnName, p as UniformKind, q as UniformKindMap, u as UniformMethods, a4 as UniformToken, a5 as UniformTokenFn, v as UniformValue, a0 as ViewSchemaPartial } from './types-CXqYX05f.mjs';
1
+ import { V as ViewSchema, G as GL, a as ViewOptions, 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-CyGyGi18.mjs';
2
+ export { D as AttributeDefinition, C as AttributeFormat, z as AttributeKind, E as AttributeMethods, y as AttributeShortHand, ac as AttributeToken, ad as AttributeTokenFn, O as BufferDefinition, P as BufferMethods, J as BufferSource, ak as CompileResult, L as ConstantAttributeMethods, M as ConstantSource, ai as FlattenSlots, a3 as Format, W as Framebuffer, Q as FramebufferDefinition, 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, H as InterleavedAttributeDefinition, F as InterleavedAttributeLayout, N 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, T as TextureDefinition, 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-CyGyGi18.mjs';
3
3
 
4
4
  declare function toID(key: string | number | symbol): any;
5
5
  /**********************************************************************************/
6
6
  /**********************************************************************************/
7
7
  declare function view<TSchema extends ViewSchema>(gl: GL, program: WebGLProgram, schema: TSchema, options?: ViewOptions): View<TSchema>;
8
+ /**
9
+ * A vertex array over the participants one draw needs.
10
+ *
11
+ * Where the context has vertex arrays, each participant writes itself in once,
12
+ * here, and `bind()` is a single `bindVertexArray`. Where it does not — WebGL1
13
+ * without `OES_vertex_array_object` — there is nowhere to keep the state, so
14
+ * `bind()` re-applies every participant and the disposer puts back what they
15
+ * displaced. Same contract, and the emulation is why the name still fits.
16
+ */
17
+ declare function vaoView(gl: GL, participants: VertexArrayParticipant[], { signal }?: ViewOptions): VertexArrayMethods;
8
18
  /**********************************************************************************/
9
19
  /**********************************************************************************/
10
20
  declare function uniformView<T extends UniformSchema>(gl: GL, program: WebGLProgram, schema: T): UniformView<T>;
11
21
  declare function attributeView<T extends AttributeSchema>(gl: GL, program: WebGLProgram, schema: T, { signal }?: ViewOptions): AttributeView<T>;
12
- /**********************************************************************************/
13
- /**********************************************************************************/
14
22
  declare function interleavedAttributeView<T extends InterleavedAttributeSchema>(gl: GL, program: WebGLProgram, schema: T, { signal }?: ViewOptions): InterleavedAttributeView<T>;
15
23
  /**********************************************************************************/
16
24
  /**********************************************************************************/
17
25
  declare function bufferView<T extends BufferSchema>(gl: GL, schema: T, { signal }?: ViewOptions): BufferView<T>;
18
26
 
19
- export { AttributeSchema, AttributeView, BufferSchema, BufferView, GL, InterleavedAttributeSchema, InterleavedAttributeView, UniformSchema, UniformView, View, ViewOptions, ViewSchema, attributeView, bufferView, interleavedAttributeView, toID, uniformView, view };
27
+ export { AttributeSchema, AttributeView, BufferSchema, BufferView, GL, InterleavedAttributeSchema, InterleavedAttributeView, UniformSchema, UniformView, VertexArrayMethods, VertexArrayParticipant, View, ViewOptions, ViewSchema, attributeView, bufferView, interleavedAttributeView, toID, uniformView, vaoView, view };
package/dist/index.mjs CHANGED
@@ -4,15 +4,17 @@ import {
4
4
  interleavedAttributeView,
5
5
  toID,
6
6
  uniformView,
7
+ vaoView,
7
8
  view
8
- } from "./chunk-CLMGHUTT.mjs";
9
- import "./chunk-WSNE4JVQ.mjs";
9
+ } from "./chunk-EYXOSM7B.mjs";
10
+ import "./chunk-CJTT7WPV.mjs";
10
11
  export {
11
12
  attributeView,
12
13
  bufferView,
13
14
  interleavedAttributeView,
14
15
  toID,
15
16
  uniformView,
17
+ vaoView,
16
18
  view
17
19
  };
18
20
  //# sourceMappingURL=index.mjs.map
package/dist/tag.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { a2 as GLSLSlot, a3 as GLSL, a5 as UniformTokenFn, a7 as AttributeTokenFn, a6 as AttributeToken, x as AttributeKind, z as AttributeDefinition, a8 as InterleaveToken, a0 as ViewSchemaPartial, ae as CompileResult, af as Prettify, a9 as GLSLToSchema, G as GL } from './types-CXqYX05f.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-CyGyGi18.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
@@ -2,10 +2,10 @@ import {
2
2
  createUpsertMap,
3
3
  toID,
4
4
  view
5
- } from "./chunk-CLMGHUTT.mjs";
5
+ } from "./chunk-EYXOSM7B.mjs";
6
6
  import {
7
7
  createProgram
8
- } from "./chunk-WSNE4JVQ.mjs";
8
+ } from "./chunk-CJTT7WPV.mjs";
9
9
 
10
10
  // src/tag.ts
11
11
  function glsl(template, ...slots) {