@bigmistqke/view.gl 0.5.0 → 0.7.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
@@ -268,6 +268,14 @@ gl.drawArraysInstanced(gl.TRIANGLES, 0, 3, 100)
268
268
  unbind()
269
269
  ```
270
270
 
271
+ A large buffer can be sized first and filled in parts, counting in elements of
272
+ the attribute's format:
273
+
274
+ ```typescript
275
+ attributes.position.allocate(totalElements) // sizes the buffer, contents undefined
276
+ attributes.position.write(chunk, offset) // overwrites a range with bufferSubData
277
+ ```
278
+
271
279
  ##### 📋 AttributeSchema
272
280
 
273
281
  A mapping of attribute names to their configuration.
@@ -388,6 +396,14 @@ const unbind = buffers.indices.bind()
388
396
  // bound vertex array object.
389
397
  ```
390
398
 
399
+ A large buffer can be sized first and filled in parts. A buffer has no element
400
+ type of its own, so these count in bytes:
401
+
402
+ ```typescript
403
+ buffers.data.allocate(byteLength) // sizes the buffer, contents undefined
404
+ buffers.data.write(chunk, byteOffset) // overwrites a range with bufferSubData
405
+ ```
406
+
391
407
  ##### 📋 BufferSchema
392
408
  A mapping of buffer names to their configuration. Each buffer has a target type and optional usage pattern.
393
409
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bigmistqke/view.gl",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "description": "👀 Utilities for managing WebGL resources.",
5
5
  "exports": {
6
6
  ".": {
package/src/index.ts CHANGED
@@ -438,6 +438,16 @@ export function attributeView<T extends AttributeSchema>(
438
438
  gl.bufferData(gl.ARRAY_BUFFER, data, gl[usage])
439
439
  return this
440
440
  },
441
+ allocate(length, usage = 'STATIC_DRAW') {
442
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer)
443
+ gl.bufferData(gl.ARRAY_BUFFER, length * FORMAT_BYTE_SIZE[resolvedFormat], gl[usage])
444
+ return this
445
+ },
446
+ write(data, offset) {
447
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer)
448
+ gl.bufferSubData(gl.ARRAY_BUFFER, offset * FORMAT_BYTE_SIZE[resolvedFormat], data)
449
+ return this
450
+ },
441
451
  }
442
452
  },
443
453
  )
@@ -692,6 +702,14 @@ export function bufferView<T extends BufferSchema>(
692
702
  gl.bindBuffer(gl[target], buffer)
693
703
  gl.bufferData(gl[target], data, gl[usage])
694
704
  },
705
+ allocate(byteLength: number) {
706
+ gl.bindBuffer(gl[target], buffer)
707
+ gl.bufferData(gl[target], byteLength, gl[usage])
708
+ },
709
+ write(data: Float32Array | Uint16Array | Uint32Array, byteOffset: number) {
710
+ gl.bindBuffer(gl[target], buffer)
711
+ gl.bufferSubData(gl[target], byteOffset, data)
712
+ },
695
713
  }
696
714
  })
697
715
 
package/src/types.ts CHANGED
@@ -365,6 +365,17 @@ export interface AttributeMethods<T extends AttributeDefinition = AttributeDefin
365
365
  */
366
366
  bind(): () => void
367
367
  set(data: FormatToArray[ResolvedFormat<T>], usage?: GLUsage): { bind(): () => void }
368
+ /**
369
+ * Sizes the buffer to `length` elements of the attribute's format, contents
370
+ * undefined, discarding what it held.
371
+ */
372
+ allocate(length: number, usage?: GLUsage): { bind(): () => void }
373
+ /**
374
+ * Overwrites the elements from `offset` on with `data`, leaving the rest as
375
+ * it is. Counts in elements of the attribute's format; the range must fit
376
+ * inside the buffer's current size.
377
+ */
378
+ write(data: FormatToArray[ResolvedFormat<T>], offset: number): { bind(): () => void }
368
379
  /**
369
380
  * Delete the buffer, if this attribute is the one that made it.
370
381
  *
@@ -479,6 +490,16 @@ export type BufferSchema = Record<string | symbol, BufferDefinition>
479
490
 
480
491
  export interface BufferMethods extends VertexArrayParticipant {
481
492
  set(data: Float32Array | Uint16Array | Uint32Array): void
493
+ /**
494
+ * Sizes the buffer to `byteLength` bytes, contents undefined, discarding what
495
+ * it held. In bytes: the buffer has no element type of its own.
496
+ */
497
+ allocate(byteLength: number): void
498
+ /**
499
+ * Overwrites the bytes from `byteOffset` on with `data`, leaving the rest as
500
+ * it is. The range must fit inside the buffer's current size.
501
+ */
502
+ write(data: Float32Array | Uint16Array | Uint32Array, byteOffset: number): void
482
503
  /** Binds the buffer, returning a disposer that restores the previous binding */
483
504
  bind(): () => void
484
505
  dispose(): void
@@ -435,6 +435,31 @@ describe('attributeView', () => {
435
435
  program = gl.createProgram()!
436
436
  })
437
437
 
438
+ it('sizes the buffer without data, then fills it in parts, counting in its format', () => {
439
+ const schema = {
440
+ a_position: { kind: 'vec2' },
441
+ a_uv: { kind: 'vec2', format: 'int16' },
442
+ } satisfies AttributeSchema
443
+
444
+ const { a_position, a_uv } = attributeView(gl, program, schema)
445
+
446
+ a_position.allocate(12, 'DYNAMIC_DRAW')
447
+ expect(gl.bindBuffer).toHaveBeenLastCalledWith(gl.ARRAY_BUFFER, a_position.buffer)
448
+ expect(gl.bufferData).toHaveBeenLastCalledWith(gl.ARRAY_BUFFER, 48, gl.DYNAMIC_DRAW)
449
+
450
+ const floats = new Float32Array([1, 2])
451
+ a_position.write(floats, 6)
452
+ expect(gl.bufferSubData).toHaveBeenLastCalledWith(gl.ARRAY_BUFFER, 24, floats)
453
+
454
+ a_uv.allocate(12)
455
+ expect(gl.bindBuffer).toHaveBeenLastCalledWith(gl.ARRAY_BUFFER, a_uv.buffer)
456
+ expect(gl.bufferData).toHaveBeenLastCalledWith(gl.ARRAY_BUFFER, 24, gl.STATIC_DRAW)
457
+
458
+ const shorts = new Int16Array([1, 2])
459
+ a_uv.write(shorts, 6)
460
+ expect(gl.bufferSubData).toHaveBeenLastCalledWith(gl.ARRAY_BUFFER, 12, shorts)
461
+ })
462
+
438
463
  it('should create attribute methods for basic types', () => {
439
464
  const schema = {
440
465
  a_position: { kind: 'vec2' },
@@ -1231,6 +1256,21 @@ describe('bufferView', () => {
1231
1256
  expect(gl.createBuffer).toHaveBeenCalledTimes(2)
1232
1257
  })
1233
1258
 
1259
+ it('sizes the buffer without data, then fills it in parts, counting in bytes', () => {
1260
+ const { indices } = bufferView(gl, {
1261
+ indices: { target: 'ELEMENT_ARRAY_BUFFER', usage: 'DYNAMIC_DRAW' },
1262
+ })
1263
+ const target = vi.mocked(gl.createBuffer).mock.results.at(-1)!.value
1264
+
1265
+ indices.allocate(64)
1266
+ expect(gl.bindBuffer).toHaveBeenLastCalledWith(gl.ELEMENT_ARRAY_BUFFER, target)
1267
+ expect(gl.bufferData).toHaveBeenLastCalledWith(gl.ELEMENT_ARRAY_BUFFER, 64, gl.DYNAMIC_DRAW)
1268
+
1269
+ const part = new Uint16Array([0, 1, 2])
1270
+ indices.write(part, 12)
1271
+ expect(gl.bufferSubData).toHaveBeenLastCalledWith(gl.ELEMENT_ARRAY_BUFFER, 12, part)
1272
+ })
1273
+
1234
1274
  it('should create buffers with specified target', () => {
1235
1275
  const schema = {
1236
1276
  vertices: { target: 'ARRAY_BUFFER' },