@bigmistqke/view.gl 0.1.4 → 0.1.5
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/.prettierignore +1 -0
- package/README.md +72 -109
- package/dev/src/examples/glsl-composition.ts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/tag.d.mts +1 -1
- package/dist/tag.mjs +11 -3
- package/dist/tag.mjs.map +1 -1
- package/dist/{types-CGTxl3Eq.d.mts → types-DIIqZ8e6.d.mts} +2 -1
- package/package.json +1 -1
- package/src/tag.ts +50 -4
- package/src/types.ts +3 -8
- package/test/tag.test.ts +269 -0
package/.prettierignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
README.md
|
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
- [🚀 Basic Usage](#-basic-usage-1)
|
|
21
21
|
- [📝 glsl](#-glsl)
|
|
22
22
|
- [🧩 GLSL Fragment](#-glsl-fragment)
|
|
23
|
-
- [🔒 Symbol
|
|
23
|
+
- [🔒 Symbol Variables](#-symbol-variables)
|
|
24
24
|
- [WebGL Version Support](#webgl-version-support)
|
|
25
25
|
- [⚙️ Resource Tags](#️-resource-tags)
|
|
26
26
|
- [🎯 uniform[kind](name, options?)](#-uniformkindname-options)
|
|
@@ -52,8 +52,6 @@ The view system provides type-safe WebGL resource management for uniforms, attri
|
|
|
52
52
|
### 🚀 Basic Usage
|
|
53
53
|
|
|
54
54
|
```typescript
|
|
55
|
-
import { view } from '@bigmistqke/view.gl'
|
|
56
|
-
|
|
57
55
|
const { uniforms, attributes } = view(gl, program, {
|
|
58
56
|
uniforms: {
|
|
59
57
|
time: { kind: 'float' },
|
|
@@ -158,14 +156,6 @@ uniforms.lights.set(lightData) // Takes Float32Array for array uniforms
|
|
|
158
156
|
**UniformSchema:**
|
|
159
157
|
A mapping of uniform names to their configuration. Each uniform has a GLSL type and optional array size.
|
|
160
158
|
|
|
161
|
-
```typescript
|
|
162
|
-
{
|
|
163
|
-
time: { kind: 'float' },
|
|
164
|
-
transform: { kind: 'mat4' },
|
|
165
|
-
lights: { kind: 'vec3', size: 8 }, // Array uniform
|
|
166
|
-
}
|
|
167
|
-
```
|
|
168
|
-
|
|
169
159
|
- `kind`: GLSL type (see [Uniform Types](#-uniform-types) for full list and WebGL compatibility)
|
|
170
160
|
- `size`: Array size (optional) - converts uniform to array type
|
|
171
161
|
|
|
@@ -194,7 +184,7 @@ type UniformKind =
|
|
|
194
184
|
|
|
195
185
|
interface UniformOptions {
|
|
196
186
|
kind: UniformKind
|
|
197
|
-
size?: number
|
|
187
|
+
size?: number // Creates array uniform with Float32Array setter
|
|
198
188
|
}
|
|
199
189
|
|
|
200
190
|
type UniformSchema = Record<string | symbol, UniformOptions>
|
|
@@ -221,13 +211,6 @@ gl.drawArraysInstanced(gl.TRIANGLES, 0, 3, 100)
|
|
|
221
211
|
**AttributeSchema:**
|
|
222
212
|
A mapping of attribute names to their configuration. Each attribute has a GLSL type, optional instancing, and optional custom buffer.
|
|
223
213
|
|
|
224
|
-
```typescript
|
|
225
|
-
{
|
|
226
|
-
position: { kind: 'vec3' },
|
|
227
|
-
instanceOffset: { kind: 'vec2', instanced: true },
|
|
228
|
-
}
|
|
229
|
-
```
|
|
230
|
-
|
|
231
214
|
- `kind`: GLSL type (see [Attribute Types](#-attribute-types) for full list and WebGL compatibility)
|
|
232
215
|
- `instanced`: Boolean - enables instanced rendering
|
|
233
216
|
- `buffer`: Custom WebGLBuffer (optional)
|
|
@@ -251,8 +234,8 @@ type AttributeKind =
|
|
|
251
234
|
|
|
252
235
|
interface AttributeOptions {
|
|
253
236
|
kind: AttributeKind
|
|
254
|
-
instanced?: boolean
|
|
255
|
-
buffer?: WebGLBuffer
|
|
237
|
+
instanced?: boolean // Enables vertexAttribDivisor
|
|
238
|
+
buffer?: WebGLBuffer // Custom buffer, auto-created if not provided
|
|
256
239
|
}
|
|
257
240
|
|
|
258
241
|
type AttributeSchema = Record<string | symbol, AttributeOptions>
|
|
@@ -281,19 +264,7 @@ interleavedAttributes.vertexData.set(interleavedVertexData).bind()
|
|
|
281
264
|
**InterleavedAttributeSchema:**
|
|
282
265
|
A mapping of interleaved buffer names to their layout configuration. Each layout defines multiple attributes packed into a single buffer.
|
|
283
266
|
|
|
284
|
-
|
|
285
|
-
{
|
|
286
|
-
vertexData: {
|
|
287
|
-
layout: [
|
|
288
|
-
{ key: 'position', kind: 'vec3' },
|
|
289
|
-
{ key: 'normal', kind: 'vec3' },
|
|
290
|
-
{ key: 'uv', kind: 'vec2' },
|
|
291
|
-
],
|
|
292
|
-
},
|
|
293
|
-
}
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
- `layout`: Array of attribute definitions with `key` and `kind` (see [Attribute Types](#-attribute-types) for WebGL compatibility)
|
|
267
|
+
- `layout`: Array of attribute definitions with `key` and `kind` (see [Attribute Types](#-attribute-types))
|
|
297
268
|
- `instanced`: Boolean - applies to all attributes in layout
|
|
298
269
|
|
|
299
270
|
<details>
|
|
@@ -305,8 +276,8 @@ interface InterleavedAttributeOptions {
|
|
|
305
276
|
key: string | symbol
|
|
306
277
|
kind: AttributeKind
|
|
307
278
|
}>
|
|
308
|
-
instanced?: boolean
|
|
309
|
-
buffer?: WebGLBuffer
|
|
279
|
+
instanced?: boolean // Applies vertexAttribDivisor to all attributes
|
|
280
|
+
buffer?: WebGLBuffer // Custom buffer for interleaved data
|
|
310
281
|
}
|
|
311
282
|
|
|
312
283
|
type InterleavedAttributeSchema = Record<string | symbol, InterleavedAttributeOptions>
|
|
@@ -331,13 +302,6 @@ buffers.data.set(dynamicData).bind()
|
|
|
331
302
|
**BufferSchema:**
|
|
332
303
|
A mapping of buffer names to their configuration. Each buffer has a target type and optional usage pattern.
|
|
333
304
|
|
|
334
|
-
```typescript
|
|
335
|
-
{
|
|
336
|
-
indices: { target: 'ELEMENT_ARRAY_BUFFER' },
|
|
337
|
-
data: { target: 'ARRAY_BUFFER', usage: 'DYNAMIC_DRAW' },
|
|
338
|
-
}
|
|
339
|
-
```
|
|
340
|
-
|
|
341
305
|
- `target`: Buffer target (`'ARRAY_BUFFER'`, `'ELEMENT_ARRAY_BUFFER'`)
|
|
342
306
|
- `usage`: Usage pattern (`'STATIC_DRAW'`, `'DYNAMIC_DRAW'`, `'STREAM_DRAW'`)
|
|
343
307
|
|
|
@@ -361,25 +325,21 @@ Type-safe GLSL template literals with automatic schema extraction.
|
|
|
361
325
|
|
|
362
326
|
- **Embedded Resources**: Define uniforms, attributes, and interleaved layouts directly in GLSL
|
|
363
327
|
- **Type Inference**: Automatically infers schema types and creates type-safe view
|
|
364
|
-
- **
|
|
328
|
+
- **Unique Variables**: Prevent naming collisions using symbols for unique shader variables
|
|
365
329
|
- **GLSL Composition**: Compose reusable GLSL fragments with automatic dependency resolution
|
|
366
330
|
|
|
367
331
|
### 🚀 Basic Usage
|
|
368
332
|
|
|
369
333
|
```typescript
|
|
370
|
-
import { glsl, uniform, attribute, compile } from '@bigmistqke/view.gl/tag'
|
|
371
|
-
|
|
372
334
|
const vertexShader = glsl`
|
|
373
335
|
${attribute.vec3('position')}
|
|
374
|
-
${attribute.vec2('uv')}
|
|
375
|
-
${uniform.mat4('projection')}
|
|
376
336
|
${uniform.mat4('model')}
|
|
377
337
|
|
|
378
338
|
varying vec2 vUv;
|
|
379
339
|
|
|
380
340
|
void main() {
|
|
381
341
|
vUv = uv;
|
|
382
|
-
gl_Position =
|
|
342
|
+
gl_Position = model * vec4(position, 1.0);
|
|
383
343
|
}
|
|
384
344
|
`
|
|
385
345
|
|
|
@@ -401,15 +361,23 @@ const { program, schema } = compile(gl, vertexShader, fragmentShader)
|
|
|
401
361
|
Template literal processor that handles GLSL code and embedded resources. Supports interpolation of:
|
|
402
362
|
|
|
403
363
|
- **[Resource tags](#️-resource-tags)**: `uniform.*()`, `attribute.*()`, `interleave()`
|
|
404
|
-
- **[
|
|
405
|
-
- **[
|
|
364
|
+
- **[GLSL fragments](#-glsl-fragment)**: Reusable shader code snippets
|
|
365
|
+
- **[Symbol Variables](#-symbol-variables)**: Unique variable names to prevent collisions
|
|
366
|
+
- **Strings**: Interpolated as-is into the shader code
|
|
367
|
+
- **Arrays**: Arrays of any supported interpolation types
|
|
406
368
|
|
|
407
369
|
```typescript
|
|
408
|
-
|
|
370
|
+
const precision = 'precision mediump float;'
|
|
371
|
+
const functionName = Symbol('function')
|
|
409
372
|
|
|
410
373
|
const shader = glsl`
|
|
374
|
+
${precision} // String interpolated as-is
|
|
411
375
|
${uniform.vec2('resolution')}
|
|
412
|
-
${attribute.vec3('position')}
|
|
376
|
+
${[attribute.vec3('position'), attribute.vec2('uv')]} // Array interpolation
|
|
377
|
+
|
|
378
|
+
vec3 ${functionName}(vec2 uv) { // Symbol interpolated to unique identifier
|
|
379
|
+
return vec3(uv, 0.5);
|
|
380
|
+
}
|
|
413
381
|
|
|
414
382
|
void main() {
|
|
415
383
|
gl_Position = vec4(position, 1.0);
|
|
@@ -430,18 +398,19 @@ const lighting = glsl`
|
|
|
430
398
|
`
|
|
431
399
|
|
|
432
400
|
const vertexShader = glsl`
|
|
433
|
-
${attribute.vec3('
|
|
401
|
+
${attribute.vec3('direction')}
|
|
434
402
|
${attribute.vec3('normal')}
|
|
435
|
-
${lighting}
|
|
403
|
+
${lighting} // Include the lighting fragment
|
|
404
|
+
|
|
405
|
+
varying vec3 vLighting;
|
|
436
406
|
|
|
437
407
|
void main() {
|
|
438
|
-
|
|
439
|
-
// Use the composed function
|
|
408
|
+
vLighting = calculateLighting(normal, direction);
|
|
440
409
|
}
|
|
441
410
|
`
|
|
442
411
|
```
|
|
443
412
|
|
|
444
|
-
#### 🔒 Symbol
|
|
413
|
+
#### 🔒 Symbol Variables
|
|
445
414
|
|
|
446
415
|
Use JavaScript symbols to prevent naming collisions:
|
|
447
416
|
|
|
@@ -462,7 +431,7 @@ void main(){
|
|
|
462
431
|
`
|
|
463
432
|
```
|
|
464
433
|
|
|
465
|
-
Symbols are converted to unique identifiers
|
|
434
|
+
Symbols are converted to unique identifiers during the compilation of the shader.
|
|
466
435
|
|
|
467
436
|
#### WebGL Version Support
|
|
468
437
|
|
|
@@ -471,7 +440,7 @@ The glsl-function supports both WebGL1 and WebGL2 syntax, automatically using th
|
|
|
471
440
|
```typescript
|
|
472
441
|
// WebGL1 (default)
|
|
473
442
|
const shader = glsl`
|
|
474
|
-
${attribute.vec3('position')}
|
|
443
|
+
${attribute.vec3('position')} // → attribute vec3 position;
|
|
475
444
|
varying vec2 vUv;
|
|
476
445
|
`
|
|
477
446
|
```
|
|
@@ -481,7 +450,7 @@ If the shader starts with `#version 300 es`, resource tags generate WebGL2 synta
|
|
|
481
450
|
```typescript
|
|
482
451
|
// WebGL2
|
|
483
452
|
const shader = glsl`#version 300 es
|
|
484
|
-
${attribute.vec3('position')}
|
|
453
|
+
${attribute.vec3('position')} // → in vec3 position;
|
|
485
454
|
out vec2 vUv;
|
|
486
455
|
`
|
|
487
456
|
```
|
|
@@ -492,48 +461,43 @@ Functions for defining WebGL resources directly in GLSL templates. These tags ge
|
|
|
492
461
|
|
|
493
462
|
#### 🎯 uniform[kind](name, options?)
|
|
494
463
|
|
|
495
|
-
Define uniform variables in GLSL templates
|
|
464
|
+
Define uniform variables in GLSL templates (see [Uniform Types](#-uniform-types)).
|
|
496
465
|
|
|
497
466
|
```typescript
|
|
498
|
-
|
|
467
|
+
const uniqueTime = Symbol('time')
|
|
499
468
|
|
|
500
469
|
const shader = glsl`
|
|
501
|
-
${uniform.float('time')}
|
|
502
|
-
${uniform.
|
|
470
|
+
${uniform.float('time')} // String key
|
|
471
|
+
${uniform.float(uniqueTime)} // Symbol key
|
|
472
|
+
${uniform.vec3('lights', { size: 8 })} // Array uniform: vec3[8]
|
|
503
473
|
|
|
504
474
|
void main() {
|
|
505
|
-
|
|
475
|
+
float wave = sin(time * 2.0 + ${uniqueTime});
|
|
476
|
+
vec3 totalLight = vec3(0.0);
|
|
477
|
+
for(int i = 0; i < 8; i++) {
|
|
478
|
+
totalLight += lights[i] * wave;
|
|
479
|
+
}
|
|
480
|
+
gl_FragColor = vec4(totalLight, 1.0);
|
|
506
481
|
}
|
|
507
482
|
`
|
|
508
483
|
```
|
|
509
484
|
|
|
510
|
-
**
|
|
485
|
+
**Parameters**:
|
|
511
486
|
|
|
512
|
-
- `
|
|
487
|
+
- `name`: Uniform name (string or symbol for unique variables)
|
|
488
|
+
- `options`: Optional configuration object
|
|
489
|
+
- `size`: Array size (creates array uniform with Float32Array setter)
|
|
513
490
|
|
|
514
491
|
#### 📝 attribute[kind](name, options?)
|
|
515
492
|
|
|
516
|
-
Define vertex attributes in GLSL templates (see [Attribute Types](#-attribute-types)
|
|
517
|
-
|
|
518
|
-
**Regular rendering:**
|
|
493
|
+
Define vertex attributes in GLSL templates (see [Attribute Types](#-attribute-types)).
|
|
519
494
|
|
|
520
495
|
```typescript
|
|
521
|
-
|
|
496
|
+
const uniquePosition = Symbol('position')
|
|
522
497
|
|
|
523
498
|
const vertexShader = glsl`
|
|
524
|
-
${attribute.vec3('position')}
|
|
525
|
-
|
|
526
|
-
void main() {
|
|
527
|
-
gl_Position = vec4(position, 1.0);
|
|
528
|
-
}
|
|
529
|
-
`
|
|
530
|
-
```
|
|
531
|
-
|
|
532
|
-
**Instanced rendering:**
|
|
533
|
-
|
|
534
|
-
```typescript
|
|
535
|
-
const vertexShader = glsl`
|
|
536
|
-
${attribute.vec3('position')}
|
|
499
|
+
${attribute.vec3('position')} // String key
|
|
500
|
+
${attribute.vec3(uniquePosition)} // Symbol key
|
|
537
501
|
${attribute.vec2('offset', { instanced: true })}
|
|
538
502
|
|
|
539
503
|
void main() {
|
|
@@ -542,23 +506,32 @@ const vertexShader = glsl`
|
|
|
542
506
|
`
|
|
543
507
|
```
|
|
544
508
|
|
|
545
|
-
**
|
|
509
|
+
**Parameters**:
|
|
546
510
|
|
|
547
|
-
- `
|
|
548
|
-
- `
|
|
511
|
+
- `name`: Attribute name (string or symbol for unique variables)
|
|
512
|
+
- `options`: Optional configuration object
|
|
513
|
+
- `instanced`: Boolean - enables instanced rendering with `vertexAttribDivisor`
|
|
514
|
+
- `buffer`: Custom WebGLBuffer (optional)
|
|
549
515
|
|
|
550
516
|
#### 🔗 interleave(name, layout, options?)
|
|
551
517
|
|
|
552
518
|
Define interleaved attribute layouts for efficient vertex data.
|
|
553
519
|
|
|
554
520
|
```typescript
|
|
555
|
-
|
|
521
|
+
const uniqueVertexData = Symbol('vertexData')
|
|
522
|
+
const uniquePosition = Symbol('position')
|
|
556
523
|
|
|
557
524
|
const vertexShader = glsl`
|
|
558
525
|
${interleave('vertexData', [
|
|
526
|
+
// String key
|
|
559
527
|
{ key: 'position', kind: 'vec3' },
|
|
560
528
|
{ key: 'uv', kind: 'vec2' },
|
|
561
529
|
])}
|
|
530
|
+
${interleave(uniqueVertexData, [
|
|
531
|
+
// Symbol key
|
|
532
|
+
{ key: uniquePosition, kind: 'vec3' }, // Symbol keys in layout
|
|
533
|
+
{ key: 'uv', kind: 'vec2' },
|
|
534
|
+
])}
|
|
562
535
|
|
|
563
536
|
void main() {
|
|
564
537
|
gl_Position = vec4(position + vec3(uv, 0.0), 1.0);
|
|
@@ -566,22 +539,20 @@ const vertexShader = glsl`
|
|
|
566
539
|
`
|
|
567
540
|
```
|
|
568
541
|
|
|
569
|
-
**
|
|
542
|
+
**Parameters**:
|
|
570
543
|
|
|
571
|
-
- `
|
|
572
|
-
- `
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
- `instanced`: Boolean - applies `vertexAttribDivisor` to all attributes
|
|
544
|
+
- `name`: Buffer name (string or symbol for unique variables)
|
|
545
|
+
- `layout`: Array of attribute definitions
|
|
546
|
+
- `key`: Attribute name (string or symbol for unique variables)
|
|
547
|
+
- `kind`: GLSL type (see [Attribute Types](#-attribute-types))
|
|
548
|
+
- `options`: Optional configuration object
|
|
549
|
+
- `instanced`: Boolean - applies `vertexAttribDivisor` to all attributes
|
|
577
550
|
|
|
578
551
|
### ⚙️ compile(gl, vertex, fragment, overrideSchema?)
|
|
579
552
|
|
|
580
553
|
Compiles shaders and extracts schema from embedded resources. Returns both the compiled program and a ready-to-use view.
|
|
581
554
|
|
|
582
555
|
```typescript
|
|
583
|
-
import { compile } from '@bigmistqke/view.gl/tag'
|
|
584
|
-
|
|
585
556
|
const { program, schema, view } = compile(gl, vertexShader, fragmentShader)
|
|
586
557
|
|
|
587
558
|
// Use the view directly
|
|
@@ -589,8 +560,8 @@ view.uniforms.time.set(performance.now())
|
|
|
589
560
|
view.attributes.position.set(vertexData).bind()
|
|
590
561
|
|
|
591
562
|
// Or access the extracted schema
|
|
592
|
-
console.log(schema.uniforms)
|
|
593
|
-
console.log(schema.attributes)
|
|
563
|
+
console.log(schema.uniforms) // { time: { kind: 'float' }, ... }
|
|
564
|
+
console.log(schema.attributes) // { position: { kind: 'vec3' }, ... }
|
|
594
565
|
```
|
|
595
566
|
|
|
596
567
|
**Override Schema:**
|
|
@@ -623,11 +594,9 @@ view.buffers.indices.set(indexData).bind()
|
|
|
623
594
|
<details>
|
|
624
595
|
<summary>Usage with vanilla view.gl</summary>
|
|
625
596
|
|
|
626
|
-
When manually constructing GLSL strings, use `toID()` to convert symbols to valid identifiers:
|
|
597
|
+
When manually constructing GLSL strings, use `toID()` to convert symbols to valid, unique identifiers:
|
|
627
598
|
|
|
628
599
|
```typescript
|
|
629
|
-
import { createProgram, view, toID } from 'view.gl'
|
|
630
|
-
|
|
631
600
|
const u_time = Symbol('time')
|
|
632
601
|
const a_position = Symbol('position')
|
|
633
602
|
|
|
@@ -669,8 +638,6 @@ uniforms[u_time].set(performance.now())
|
|
|
669
638
|
Creates and links a WebGL program from vertex and fragment shader sources.
|
|
670
639
|
|
|
671
640
|
```typescript
|
|
672
|
-
import { createProgram } from '@bigmistqke/view.gl/utils'
|
|
673
|
-
|
|
674
641
|
const program = createProgram(gl, vertexShaderSource, fragmentShaderSource)
|
|
675
642
|
```
|
|
676
643
|
|
|
@@ -679,8 +646,6 @@ const program = createProgram(gl, vertexShaderSource, fragmentShaderSource)
|
|
|
679
646
|
Creates a WebGL texture with specified parameters.
|
|
680
647
|
|
|
681
648
|
```typescript
|
|
682
|
-
import { createTexture } from '@bigmistqke/view.gl/utils'
|
|
683
|
-
|
|
684
649
|
const texture = createTexture(
|
|
685
650
|
gl,
|
|
686
651
|
{
|
|
@@ -705,8 +670,6 @@ Automatically validates WebGL2-only formats and provides fallbacks for WebGL1.
|
|
|
705
670
|
Creates a framebuffer with attached texture for render-to-texture operations.
|
|
706
671
|
|
|
707
672
|
```typescript
|
|
708
|
-
import { createFramebuffer } from '@bigmistqke/view.gl/utils'
|
|
709
|
-
|
|
710
673
|
const { framebuffer, texture } = createFramebuffer(gl, {
|
|
711
674
|
width: 512,
|
|
712
675
|
height: 512,
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
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-
|
|
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-DIIqZ8e6.mjs';
|
|
2
2
|
|
|
3
3
|
declare function toID(key: string | number | symbol): any;
|
|
4
4
|
/**********************************************************************************/
|
package/dist/tag.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { g as GLSLSlot, h as GLSLTag, i as UniformTagFn, j as AttributeTagFn, k as AttributeTag, l as AttributeKind, m as AttributeOptions, n as InterleaveTag, o as ViewSchemaPartial, V as ViewSchema, D as DeepMerge, S as ShallowMerge, p as UniformTag, P as Prettify, b as View } from './types-
|
|
1
|
+
import { g as GLSLSlot, h as GLSLTag, i as UniformTagFn, j as AttributeTagFn, k as AttributeTag, l as AttributeKind, m as AttributeOptions, n as InterleaveTag, o as ViewSchemaPartial, V as ViewSchema, D as DeepMerge, S as ShallowMerge, p as UniformTag, P as Prettify, b as View } from './types-DIIqZ8e6.mjs';
|
|
2
2
|
|
|
3
3
|
declare function glsl<TSlot extends GLSLSlot, TSlots extends TSlot[]>(template: TemplateStringsArray, ...slots: [...TSlots]): GLSLTag<TSlots>;
|
|
4
4
|
declare const uniform: {
|
package/dist/tag.mjs
CHANGED
|
@@ -439,9 +439,13 @@ function glslTagToSchema(tag) {
|
|
|
439
439
|
attributes: {},
|
|
440
440
|
interleavedAttributes: {}
|
|
441
441
|
};
|
|
442
|
-
|
|
442
|
+
function handleSlot(slot) {
|
|
443
|
+
if (Array.isArray(slot)) {
|
|
444
|
+
slot.forEach(handleSlot);
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
443
447
|
if (typeof slot !== "object") {
|
|
444
|
-
|
|
448
|
+
return;
|
|
445
449
|
}
|
|
446
450
|
if (slot.type === "glsl") {
|
|
447
451
|
const { uniforms, attributes, interleavedAttributes } = glslTagToSchema(slot);
|
|
@@ -457,11 +461,12 @@ function glslTagToSchema(tag) {
|
|
|
457
461
|
...result.interleavedAttributes,
|
|
458
462
|
...interleavedAttributes
|
|
459
463
|
};
|
|
460
|
-
|
|
464
|
+
return;
|
|
461
465
|
}
|
|
462
466
|
const { key: name2, type, ...rest } = slot;
|
|
463
467
|
result[`${type}s`][name2] = rest;
|
|
464
468
|
}
|
|
469
|
+
tag.slots.forEach(handleSlot);
|
|
465
470
|
return result;
|
|
466
471
|
}
|
|
467
472
|
function glslTagToString({ template: [initial, ...rest], slots }) {
|
|
@@ -476,6 +481,9 @@ function glslSlotToString(slot, v300) {
|
|
|
476
481
|
if (typeof slot !== "object") {
|
|
477
482
|
return toID(slot);
|
|
478
483
|
}
|
|
484
|
+
if (Array.isArray(slot)) {
|
|
485
|
+
return slot.map((slot2) => glslSlotToString(slot2, v300)).join("");
|
|
486
|
+
}
|
|
479
487
|
if (slot.type === "glsl") {
|
|
480
488
|
return glslTagToString(slot);
|
|
481
489
|
}
|
package/dist/tag.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/features.ts","../src/utils/object.ts","../src/utils/index.ts","../src/index.ts","../src/tag.ts"],"sourcesContent":["import type { GL, RemoveSuffix } from './types'\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 (gl instanceof WebGL2RenderingContext) 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\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 (gl instanceof WebGL2RenderingContext) 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","export function forEach<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 map<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 forEach(value, (value, key, index) => {\n result[key] = callback(value, key, index)\n })\n\n return result\n}\n","import type {\n AttributeKind,\n FramebufferOptions,\n GL,\n KIND_TO_SIZE_MAP,\n KIND_TO_UNIFORM_FN_NAME_MAP,\n TextureOptions,\n UniformKind,\n} from '../types'\n\nexport * as ObjectUtils from './object'\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\nfunction createGLShader(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\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 = createGLShader(gl, gl.VERTEX_SHADER, vertexSource)\n const fragmentShader = createGLShader(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/* 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 }: TextureOptions,\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(gl: GL, { attachment, texture, ...options }: FramebufferOptions) {\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","import { getInstancedArrays, getVertexArrayObject } from './features'\nimport type {\n AttributeMethods,\n AttributeSchema,\n AttributeView,\n BufferSchema,\n BufferView,\n GL,\n UniformView as InferUniformView,\n InterleavedAttributeMethods,\n InterleavedAttributeSchema,\n InterleavedAttributeView,\n UniformSchema,\n View,\n ViewOptions,\n ViewSchema,\n} from './types'\nimport {\n assertedNotNullish,\n createUpsertMap,\n isMatKind,\n isSamplerKind,\n kindToSize,\n kindToUniformFnName,\n ObjectUtils,\n} from './utils'\n\n/**********************************************************************************/\n/* */\n/* To ID */\n/* */\n/**********************************************************************************/\n\nlet index = 0\nconst PREFIX = 'VIEW_GL_ALIAS'\n\nconst SYMBOL_MAP = createUpsertMap(WeakMap<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 } as View<TSchema>\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 return ObjectUtils.map(schema, ({ kind, size }, key) => {\n const name = toID(key)\n\n const location = gl.getUniformLocation(program, name)\n\n if (isSamplerKind(kind)) {\n return {\n set(arg: number) {\n gl.uniform1i(location, arg)\n },\n }\n }\n\n const fnName = `uniform${kindToUniformFnName(kind)}${size ? 'v' : ''}`\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\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 type: 'FLOAT' | 'INT',\n instanced?: boolean,\n) {\n gl.enableVertexAttribArray(location)\n gl.vertexAttribPointer(location, size, gl[type], false, stride, offset)\n\n if (instanced) {\n // Get instanced-arrays-feature: extension if webgl, gl if webgl2\n assertedNotNullish(getInstancedArrays(gl)).vertexAttribDivisor(location, 1)\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 = ObjectUtils.map(\n schema,\n (\n { kind, instanced, buffer = assertedNotNullish(gl.createBuffer()) },\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 type = kind.startsWith('i') ? 'INT' : 'FLOAT'\n\n return {\n buffer,\n bind() {\n gl.bindBuffer(gl.ARRAY_BUFFER, buffer)\n handleAttribute(gl, location, size, 0, 0, type, instanced)\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 ObjectUtils.forEach(attributes, value => value.dispose())\n })\n\n return attributes\n}\n\n/**********************************************************************************/\n/* */\n/* Interleaved Attribute View */\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 = ObjectUtils.map(schema, ({ layout, instanced }) => {\n // Increment number to keep track of offset\n let index = 0\n\n // Calculate layout information\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 const size = kindToSize(layout.kind)\n const offset = index\n const type = layout.kind.startsWith('i') ? 'INT' : 'FLOAT'\n index += size * 4\n\n return () => handleAttribute(gl, location, size, stride, offset, type, instanced)\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 // Create VAO to cache attribute state\n let vao: { unbind(): void; bind(): void; dispose(): void } | undefined = undefined\n\n // Get VAO-feature: extension if webgl1, gl if webgl2\n const feature = getVertexArrayObject(gl)\n if (feature) {\n const vertexArray = feature.createVertexArray()\n feature.bindVertexArray(vertexArray)\n gl.bindBuffer(gl.ARRAY_BUFFER, buffer)\n for (const handle of handles) {\n handle()\n }\n feature.bindVertexArray(null)\n vao = {\n unbind() {\n feature.bindVertexArray(null)\n },\n bind() {\n feature.bindVertexArray(vertexArray)\n },\n dispose() {\n feature.deleteVertexArray(vertexArray)\n },\n }\n }\n\n return {\n bind() {\n gl.bindBuffer(gl.ARRAY_BUFFER, buffer)\n if (vao) {\n vao.bind()\n } else {\n // Fallback: manual attribute setup\n for (const handle of handles) {\n handle()\n }\n }\n },\n unbind() {\n if (vao) {\n vao.unbind()\n }\n },\n dispose() {\n gl.deleteBuffer(buffer)\n if (vao) {\n vao.dispose()\n }\n },\n set(value, usage = 'STATIC_DRAW') {\n if (vao) {\n vao.bind()\n } else {\n gl.bindBuffer(gl.ARRAY_BUFFER, buffer)\n }\n gl.bufferData(gl.ARRAY_BUFFER, value, gl[usage])\n if (vao) {\n vao.unbind()\n }\n },\n } satisfies InterleavedAttributeMethods\n })\n\n signal?.addEventListener('abort', function dispose() {\n ObjectUtils.forEach(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 = ObjectUtils.map(schema, ({ target = 'ARRAY_BUFFER', usage = 'STATIC_DRAW' }) => {\n const buffer = assertedNotNullish(gl.createBuffer())\n return {\n bind() {\n gl.bindBuffer(gl[target], buffer)\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 ObjectUtils.forEach(buffers, value => value.dispose())\n })\n\n return buffers\n}\n","import { toID, view } from '.'\nimport type {\n AttributeKind,\n AttributeOptions,\n AttributeTag,\n AttributeTagFn as AttributeTagMethod,\n DeepMerge,\n GLSLSlot,\n GLSLTag,\n InterleaveTag,\n Prettify,\n ShallowMerge,\n UniformKind,\n UniformOptions,\n UniformTag,\n UniformTagFn as UniformTagMethod,\n View,\n ViewSchema,\n ViewSchemaPartial,\n} from './types'\nimport { createProgram } from './utils'\n\nexport function glsl<TSlot extends GLSLSlot, TSlots extends TSlot[]>(\n template: TemplateStringsArray,\n ...slots: [...TSlots]\n): GLSLTag<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<UniformOptions, '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<AttributeOptions, '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<AttributeTag<string | symbol, AttributeKind, undefined>>,\n const TOptions extends Omit<AttributeOptions, 'kind'>,\n>(key: TKey, layout: TLayout, instanced: TOptions): InterleaveTag<TKey, TLayout, TOptions>\nexport function interleave<\n const TKey extends string | symbol,\n const TLayout extends Array<AttributeTag<string | symbol, AttributeKind, undefined>>,\n>(key: TKey, layout: TLayout): InterleaveTag<TKey, TLayout, { instanced: false }>\nexport function interleave<\n const TKey extends string | symbol,\n const TLayout extends Array<AttributeTag<string | symbol, AttributeKind, undefined>>,\n const TOptions extends Omit<AttributeOptions, '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 InterleaveTag<TKey, TLayout, TOptions>\n}\n\n/**********************************************************************************/\n/* */\n/* Compile */\n/* */\n/**********************************************************************************/\n\ntype glslTagToSchema<TTag extends GLSLTag> =\n FlattenSlots<TTag> extends infer TSlots\n ? TSlots extends Array<any>\n ? GLSLSlotsToSchema<TSlots>\n : never\n : never\n\ntype GLSLSlotsToSchema<TSlots extends Array<GLSLSlot>> = {\n uniforms: {\n [K in Extract<TSlots[number], UniformTag> as K['key']]: Prettify<Omit<K, 'name' | 'type'>>\n }\n attributes: {\n [K in Extract<TSlots[number], AttributeTag> as K['key']]: Prettify<Omit<K, 'name' | 'type'>>\n }\n interleavedAttributes: {\n [K in Extract<TSlots[number], InterleaveTag> as K['key']]: Prettify<Omit<K, 'name' | 'type'>>\n }\n}\n\ntype FlattenSlots<T> =\n T extends GLSLTag<infer TSlots>\n ? _FlattenSlots<TSlots>\n : T extends Array<GLSLSlot>\n ? _FlattenSlots<T>\n : never\n\ntype _FlattenSlots<T extends Array<GLSLSlot>> = T extends [infer First, ...infer Rest]\n ? First extends GLSLTag\n ? [...FlattenSlots<First>, ...FlattenSlots<Rest>]\n : First extends unknown[]\n ? [...FlattenSlots<First>, ...FlattenSlots<Rest>]\n : [First, ...FlattenSlots<Rest>]\n : []\n\ntype MergeGLSLSchema<\n TVertex extends ViewSchema,\n TFragment extends ViewSchema,\n TOverrides extends ViewSchemaPartial,\n> = {\n uniforms: DeepMerge<\n [ShallowMerge<[TVertex['uniforms'], TFragment['uniforms']]>, TOverrides['uniforms']]\n >\n attributes: DeepMerge<\n [ShallowMerge<[TVertex['attributes'], TFragment['attributes']]>, TOverrides['attributes']]\n >\n interleavedAttributes: DeepMerge<\n [\n ShallowMerge<[TVertex['interleavedAttributes'], TFragment['interleavedAttributes']]>,\n TOverrides['interleavedAttributes'],\n ]\n >\n}\n\ntype CompileResult<\n TVertex extends GLSLTag,\n TFragment extends GLSLTag,\n TOverrides extends ViewSchemaPartial,\n> =\n MergeGLSLSchema<\n glslTagToSchema<TVertex>,\n glslTagToSchema<TFragment>,\n TOverrides\n > extends infer TSchema extends ViewSchema\n ? {\n program: WebGLProgram\n schema: TSchema\n view: View<TSchema>\n }\n : never\n\nexport function compile<\n TVertex extends GLSLTag,\n TFragment extends GLSLTag,\n TOverride extends ViewSchemaPartial,\n>(gl: WebGLRenderingContext, vertex: TVertex, fragment: TFragment, overrideSchema?: TOverride) {\n const _vertex = resolveGLSLTag(vertex)\n const _fragment = resolveGLSLTag(fragment)\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 for (const kind in overrideSchema) {\n const schemaKind = schema[kind as keyof typeof schema]\n const overrideSchemaKind = overrideSchema[kind]\n\n for (const key in overrideSchemaKind) {\n // @ts-expect-error\n schemaKind[key] = {\n // @ts-expect-error\n ...schemaKind[key],\n ...overrideSchemaKind[key],\n }\n }\n }\n\n const program = createProgram(gl, _vertex.template, _fragment.template)\n\n return {\n program,\n schema,\n view: view(gl, program, schema),\n } as CompileResult<TVertex, TFragment, TOverride>\n}\n\nfunction resolveGLSLTag<TTag extends GLSLTag>(tag: TTag) {\n return {\n template: glslTagToString(tag),\n schema: glslTagToSchema(tag),\n }\n}\n\nfunction glslTagToSchema<TTag extends GLSLTag>(tag: TTag) {\n const result = {\n uniforms: {},\n attributes: {},\n interleavedAttributes: {},\n }\n\n for (const slot of tag.slots) {\n if (typeof slot !== 'object') {\n continue\n }\n\n if (slot.type === 'glsl') {\n const { uniforms, attributes, interleavedAttributes } = glslTagToSchema(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 continue\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\n}\n\nfunction glslTagToString<TTag extends GLSLTag>({ template: [initial, ...rest], slots }: TTag) {\n const v300 = !!initial?.startsWith('#version 300 es')\n\n let template = initial ?? ''\n\n for (let i = 0; i < rest.length; i++) {\n template += `${glslSlotToString(slots[i]!, v300)}${rest[i]}`\n }\n\n return template\n}\n\nfunction glslSlotToString(slot: GLSLSlot, v300: boolean) {\n if (typeof slot !== 'object') {\n return toID(slot)\n }\n\n if (slot.type === 'glsl') {\n return glslTagToString(slot)\n }\n\n if (slot.type === '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 }\n\n if (slot.type === 'uniform' && 'size' in slot) {\n return `${slot.type} ${slot.kind} ${toID(slot.key)}[${slot.size}];`\n }\n\n return `${slot.type === 'attribute' && v300 ? 'in' : slot.type} ${slot.kind} ${toID(slot.key)};`\n}\n"],"mappings":"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","names":["index","value","map","name","index","layout","key","name"]}
|
|
1
|
+
{"version":3,"sources":["../src/features.ts","../src/utils/object.ts","../src/utils/index.ts","../src/index.ts","../src/tag.ts"],"sourcesContent":["import type { GL, RemoveSuffix } from './types'\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 (gl instanceof WebGL2RenderingContext) 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\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 (gl instanceof WebGL2RenderingContext) 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","export function forEach<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 map<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 forEach(value, (value, key, index) => {\n result[key] = callback(value, key, index)\n })\n\n return result\n}\n","import type {\n AttributeKind,\n FramebufferOptions,\n GL,\n KIND_TO_SIZE_MAP,\n KIND_TO_UNIFORM_FN_NAME_MAP,\n TextureOptions,\n UniformKind,\n} from '../types'\n\nexport * as ObjectUtils from './object'\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\nfunction createGLShader(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\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 = createGLShader(gl, gl.VERTEX_SHADER, vertexSource)\n const fragmentShader = createGLShader(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/* 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 }: TextureOptions,\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(gl: GL, { attachment, texture, ...options }: FramebufferOptions) {\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","import { getInstancedArrays, getVertexArrayObject } from './features'\nimport type {\n AttributeMethods,\n AttributeSchema,\n AttributeView,\n BufferSchema,\n BufferView,\n GL,\n UniformView as InferUniformView,\n InterleavedAttributeMethods,\n InterleavedAttributeSchema,\n InterleavedAttributeView,\n UniformSchema,\n View,\n ViewOptions,\n ViewSchema,\n} from './types'\nimport {\n assertedNotNullish,\n createUpsertMap,\n isMatKind,\n isSamplerKind,\n kindToSize,\n kindToUniformFnName,\n ObjectUtils,\n} from './utils'\n\n/**********************************************************************************/\n/* */\n/* To ID */\n/* */\n/**********************************************************************************/\n\nlet index = 0\nconst PREFIX = 'VIEW_GL_ALIAS'\n\nconst SYMBOL_MAP = createUpsertMap(WeakMap<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 } as View<TSchema>\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 return ObjectUtils.map(schema, ({ kind, size }, key) => {\n const name = toID(key)\n\n const location = gl.getUniformLocation(program, name)\n\n if (isSamplerKind(kind)) {\n return {\n set(arg: number) {\n gl.uniform1i(location, arg)\n },\n }\n }\n\n const fnName = `uniform${kindToUniformFnName(kind)}${size ? 'v' : ''}`\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\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 type: 'FLOAT' | 'INT',\n instanced?: boolean,\n) {\n gl.enableVertexAttribArray(location)\n gl.vertexAttribPointer(location, size, gl[type], false, stride, offset)\n\n if (instanced) {\n // Get instanced-arrays-feature: extension if webgl, gl if webgl2\n assertedNotNullish(getInstancedArrays(gl)).vertexAttribDivisor(location, 1)\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 = ObjectUtils.map(\n schema,\n (\n { kind, instanced, buffer = assertedNotNullish(gl.createBuffer()) },\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 type = kind.startsWith('i') ? 'INT' : 'FLOAT'\n\n return {\n buffer,\n bind() {\n gl.bindBuffer(gl.ARRAY_BUFFER, buffer)\n handleAttribute(gl, location, size, 0, 0, type, instanced)\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 ObjectUtils.forEach(attributes, value => value.dispose())\n })\n\n return attributes\n}\n\n/**********************************************************************************/\n/* */\n/* Interleaved Attribute View */\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 = ObjectUtils.map(schema, ({ layout, instanced }) => {\n // Increment number to keep track of offset\n let index = 0\n\n // Calculate layout information\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 const size = kindToSize(layout.kind)\n const offset = index\n const type = layout.kind.startsWith('i') ? 'INT' : 'FLOAT'\n index += size * 4\n\n return () => handleAttribute(gl, location, size, stride, offset, type, instanced)\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 // Create VAO to cache attribute state\n let vao: { unbind(): void; bind(): void; dispose(): void } | undefined = undefined\n\n // Get VAO-feature: extension if webgl1, gl if webgl2\n const feature = getVertexArrayObject(gl)\n if (feature) {\n const vertexArray = feature.createVertexArray()\n feature.bindVertexArray(vertexArray)\n gl.bindBuffer(gl.ARRAY_BUFFER, buffer)\n for (const handle of handles) {\n handle()\n }\n feature.bindVertexArray(null)\n vao = {\n unbind() {\n feature.bindVertexArray(null)\n },\n bind() {\n feature.bindVertexArray(vertexArray)\n },\n dispose() {\n feature.deleteVertexArray(vertexArray)\n },\n }\n }\n\n return {\n bind() {\n gl.bindBuffer(gl.ARRAY_BUFFER, buffer)\n if (vao) {\n vao.bind()\n } else {\n // Fallback: manual attribute setup\n for (const handle of handles) {\n handle()\n }\n }\n },\n unbind() {\n if (vao) {\n vao.unbind()\n }\n },\n dispose() {\n gl.deleteBuffer(buffer)\n if (vao) {\n vao.dispose()\n }\n },\n set(value, usage = 'STATIC_DRAW') {\n if (vao) {\n vao.bind()\n } else {\n gl.bindBuffer(gl.ARRAY_BUFFER, buffer)\n }\n gl.bufferData(gl.ARRAY_BUFFER, value, gl[usage])\n if (vao) {\n vao.unbind()\n }\n },\n } satisfies InterleavedAttributeMethods\n })\n\n signal?.addEventListener('abort', function dispose() {\n ObjectUtils.forEach(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 = ObjectUtils.map(schema, ({ target = 'ARRAY_BUFFER', usage = 'STATIC_DRAW' }) => {\n const buffer = assertedNotNullish(gl.createBuffer())\n return {\n bind() {\n gl.bindBuffer(gl[target], buffer)\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 ObjectUtils.forEach(buffers, value => value.dispose())\n })\n\n return buffers\n}\n","import { toID, view } from '.'\nimport type {\n AttributeKind,\n AttributeOptions,\n AttributeTag,\n AttributeTagFn as AttributeTagMethod,\n DeepMerge,\n GLSLSlot,\n GLSLTag,\n InterleaveTag,\n Prettify,\n ShallowMerge,\n UniformKind,\n UniformOptions,\n UniformTag,\n UniformTagFn as UniformTagMethod,\n View,\n ViewSchema,\n ViewSchemaPartial,\n} from './types'\nimport { createProgram } from './utils'\n\nexport function glsl<TSlot extends GLSLSlot, TSlots extends TSlot[]>(\n template: TemplateStringsArray,\n ...slots: [...TSlots]\n): GLSLTag<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<UniformOptions, '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<AttributeOptions, '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<AttributeTag<string | symbol, AttributeKind, undefined>>,\n const TOptions extends Omit<AttributeOptions, 'kind'>,\n>(key: TKey, layout: TLayout, instanced: TOptions): InterleaveTag<TKey, TLayout, TOptions>\nexport function interleave<\n const TKey extends string | symbol,\n const TLayout extends Array<AttributeTag<string | symbol, AttributeKind, undefined>>,\n>(key: TKey, layout: TLayout): InterleaveTag<TKey, TLayout, { instanced: false }>\nexport function interleave<\n const TKey extends string | symbol,\n const TLayout extends Array<AttributeTag<string | symbol, AttributeKind, undefined>>,\n const TOptions extends Omit<AttributeOptions, '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 InterleaveTag<TKey, TLayout, TOptions>\n}\n\n/**********************************************************************************/\n/* */\n/* Compile */\n/* */\n/**********************************************************************************/\n\ntype glslTagToSchema<TTag extends GLSLTag> =\n FlattenSlots<TTag> extends infer TSlots\n ? TSlots extends Array<any>\n ? GLSLSlotsToSchema<TSlots>\n : never\n : never\n\ntype GLSLSlotsToSchema<TSlots extends Array<GLSLSlot>> = {\n uniforms: {\n [K in Extract<TSlots[number], UniformTag> as K['key']]: Prettify<Omit<K, 'name' | 'type'>>\n }\n attributes: {\n [K in Extract<TSlots[number], AttributeTag> as K['key']]: Prettify<Omit<K, 'name' | 'type'>>\n }\n interleavedAttributes: {\n [K in Extract<TSlots[number], InterleaveTag> as K['key']]: Prettify<Omit<K, 'name' | 'type'>>\n }\n}\n\ntype FlattenSlots<T> =\n T extends GLSLTag<infer TSlots>\n ? _FlattenSlots<TSlots>\n : T extends Array<GLSLSlot>\n ? _FlattenSlots<T>\n : never\n\ntype _FlattenSlots<T extends Array<GLSLSlot>> = T extends [infer First, ...infer Rest]\n ? First extends GLSLTag\n ? [...FlattenSlots<First>, ...FlattenSlots<Rest>]\n : First extends unknown[]\n ? [...FlattenSlots<First>, ...FlattenSlots<Rest>]\n : [First, ...FlattenSlots<Rest>]\n : []\n\ntype MergeGLSLSchema<\n TVertex extends ViewSchema,\n TFragment extends ViewSchema,\n TOverrides extends ViewSchemaPartial,\n> = {\n uniforms: DeepMerge<\n [ShallowMerge<[TVertex['uniforms'], TFragment['uniforms']]>, TOverrides['uniforms']]\n >\n attributes: DeepMerge<\n [ShallowMerge<[TVertex['attributes'], TFragment['attributes']]>, TOverrides['attributes']]\n >\n interleavedAttributes: DeepMerge<\n [\n ShallowMerge<[TVertex['interleavedAttributes'], TFragment['interleavedAttributes']]>,\n TOverrides['interleavedAttributes'],\n ]\n >\n}\n\ntype CompileResult<\n TVertex extends GLSLTag,\n TFragment extends GLSLTag,\n TOverrides extends ViewSchemaPartial,\n> =\n MergeGLSLSchema<\n glslTagToSchema<TVertex>,\n glslTagToSchema<TFragment>,\n TOverrides\n > extends infer TSchema extends ViewSchema\n ? {\n program: WebGLProgram\n schema: TSchema\n view: View<TSchema>\n }\n : never\n\nexport function compile<\n TVertex extends GLSLTag,\n TFragment extends GLSLTag,\n TOverride extends ViewSchemaPartial,\n>(gl: WebGLRenderingContext, vertex: TVertex, fragment: TFragment, overrideSchema?: TOverride) {\n const _vertex = resolveGLSLTag(vertex)\n const _fragment = resolveGLSLTag(fragment)\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 for (const kind in overrideSchema) {\n const schemaKind = schema[kind as keyof typeof schema]\n const overrideSchemaKind = overrideSchema[kind]\n\n for (const key in overrideSchemaKind) {\n // @ts-expect-error\n schemaKind[key] = {\n // @ts-expect-error\n ...schemaKind[key],\n ...overrideSchemaKind[key],\n }\n }\n }\n\n const program = createProgram(gl, _vertex.template, _fragment.template)\n\n return {\n program,\n schema,\n view: view(gl, program, schema),\n } as CompileResult<TVertex, TFragment, TOverride>\n}\n\nfunction resolveGLSLTag<TTag extends GLSLTag>(tag: TTag) {\n return {\n template: glslTagToString(tag),\n schema: glslTagToSchema(tag),\n }\n}\n\nfunction glslTagToSchema<TTag extends GLSLTag>(tag: TTag) {\n const result = {\n uniforms: {},\n attributes: {},\n interleavedAttributes: {},\n }\n\n function handleSlot(slot: GLSLSlot) {\n if (Array.isArray(slot)) {\n slot.forEach(handleSlot)\n return\n }\n\n if (typeof slot !== 'object') {\n return\n }\n\n if (slot.type === 'glsl') {\n const { uniforms, attributes, interleavedAttributes } = glslTagToSchema(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 tag.slots.forEach(handleSlot)\n\n return result\n}\n\n// function glslSlotToSchema(slot: GLSLSlot){\n// if(Array.isArray(slot)){\n\n// return\n// }\n\n// if (typeof slot !== 'object') {\n// return\n// }\n\n// if (slot.type === 'glsl') {\n// return glslTagToSchema(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// // continue\n// }\n\n// const { key: name, type, ...rest } = slot\n\n// // @ts-expect-error\n// result[`${type}s`][name] = rest\n// }\n\nfunction glslTagToString<TTag extends GLSLTag>({ template: [initial, ...rest], slots }: TTag) {\n const v300 = !!initial?.startsWith('#version 300 es')\n\n let template = initial ?? ''\n\n for (let i = 0; i < rest.length; i++) {\n template += `${glslSlotToString(slots[i]!, v300)}${rest[i]}`\n }\n\n return template\n}\n\nfunction glslSlotToString(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 => glslSlotToString(slot, v300)).join('')\n }\n\n if (slot.type === 'glsl') {\n return glslTagToString(slot)\n }\n\n if (slot.type === '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 }\n\n if (slot.type === 'uniform' && 'size' in slot) {\n return `${slot.type} ${slot.kind} ${toID(slot.key)}[${slot.size}];`\n }\n\n return `${slot.type === 'attribute' && v300 ? 'in' : slot.type} ${slot.kind} ${toID(slot.key)};`\n}\n"],"mappings":";;;;;;;AAEA,IAAM,+BAA+B,oBAAI,QASvC;AACK,SAAS,mBAAmB,IAAQ;AACzC,MAAI,cAAc,uBAAwB,QAAO;AAEjD,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;AAEA,IAAM,kCAAkC,oBAAI,QAS1C;AACK,SAAS,qBAAqB,IAAQ;AAC3C,MAAI,cAAc,uBAAwB,QAAO;AAEjD,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;;;AC1DA;AAAA;AAAA;AAAA;AAAA;AAAO,SAAS,QACd,OACA,UACA;AACA,MAAIA,SAAQ;AACZ,aAAW,OAAO,OAAO;AACvB,aAAS,MAAM,GAAG,GAAG,KAAKA,MAAK;AAC/B,IAAAA;AAAA,EACF;AACA,aAAW,OAAO,OAAO,sBAAsB,KAAK,GAAG;AACrD,aAAS,MAAM,GAAc,GAAG,KAAgBA,MAAK;AACrD,IAAAA;AAAA,EACF;AACF;AAEO,SAAS,IACd,OACA,UACgC;AAChC,QAAM,SAAS,CAAC;AAEhB,UAAQ,OAAO,CAACC,QAAO,KAAKD,WAAU;AACpC,WAAO,GAAG,IAAI,SAASC,QAAO,KAAKD,MAAK;AAAA,EAC1C,CAAC;AAED,SAAO;AACT;;;ACdO,SAAS,mBAAsB,OAAU,SAAkC;AAChF,MAAI,UAAU,UAAa,UAAU,KAAM,OAAM,IAAI,MAAM,OAAO;AAClE,SAAO;AACT;AAEA,SAAS,eAAe,IAAQ,MAAc,QAA6B;AACzE,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;AAEO,SAAS,cAAc,IAAQ,cAAsB,gBAAsC;AAChG,QAAM,UAAU,GAAG,cAAc;AACjC,MAAI,CAAC,QAAS,OAAM,IAAI,MAAM,gCAAgC;AAE9D,QAAM,eAAe,eAAe,IAAI,GAAG,eAAe,YAAY;AACtE,QAAM,iBAAiB,eAAe,IAAI,GAAG,iBAAiB,cAAc;AAE5E,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;AAQO,IAAM,sBAAsB,CACjC,SACmC;AACnC,UAAQ,KAAK,CAAC,GAAG;AAAA;AAAA,IAEf,KAAK;AACH,aAAQ,WAAW,KAAK,MAAM,CAAC,IAAI;AAAA;AAAA,IAErC,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,cAAS,KAAK,MAAM,IAAI,IAAI,CAAC,KAAK,OAAO;AAAA;AAAA,IAE3C,KAAK;AACH,cAAS,KAAK,CAAC,KAAK,OAAO;AAAA;AAAA,IAE7B,KAAK;AACH,aAAQ,KAAK,CAAC,IAAI;AAAA,IACpB;AACE,cAAQ,MAAM;AAAA,QACZ,KAAK;AACH,iBAAO;AAAA,QACT,KAAK;AACH,iBAAO;AAAA,QACT;AACE,iBAAO;AAAA,MACX;AAAA,EACJ;AACF;AAQO,IAAM,aAAa,CAAwB,SAAiC;AACjF,UAAQ,KAAK,CAAC,GAAG;AAAA,IACf,KAAK;AACH,YAAM,CAAC,GAAG,CAAC,IAAI,KAAK,MAAM,MAAM,EAAG,IAAI,MAAM;AAC7C,aAAQ,KAAK,KAAK;AAAA,IACpB,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,YAAM,QAAQ,KAAK,MAAM,IAAI;AAC7B,aAAQ,QAAQ,CAAC,MAAM,CAAC,IAAI;AAAA,IAC9B;AACE,aAAO;AAAA,EACX;AACF;AAQO,IAAM,YAAY,CAKvB,SAC2C,KAAK,SAAS,KAAK;AAEzD,IAAM,gBAAgB,CAC3B,SACyD,KAAK,SAAS,SAAS;AAyI3E,SAAS,gBACd,aACA;AACA,QAAME,OAAM,KAAK,eAAe,KAAK;AACrC,SAAO,OAAO,OAAOA,MAAK;AAAA,IACxB,YACE,KACA,OACA;AACA,UAAI,SAASA,KAAI,IAAI,GAAG;AACxB,UAAI,QAAQ;AACV,eAAO;AAAA,MACT;AACA,eAAS,MAAM;AACf,MAAAA,KAAI,IAAI,KAAK,MAAM;AACnB,aAAO;AAAA,IACT;AAAA,EACF,CAAC;AACH;;;ACjQA,IAAI,QAAQ;AACZ,IAAM,SAAS;AAEf,IAAM,aAAa,gBAAgB,OAAuB;AAEnD,SAAS,KAAK,KAA+B;AAClD,MAAI,OAAO,QAAQ,UAAU;AAC3B,WAAO;AAAA,EACT;AACA,MAAI,OAAO,QAAQ,UAAU;AAC3B,WAAO,WAAW,YAAY,KAAK,MAAM,GAAG,MAAM,IAAI,OAAO,EAAE;AAAA,EACjE;AACA,SAAO,IAAI,SAAS;AACtB;AAQO,SAAS,KACd,IACA,SACA,QACA,SACe;AACf,SAAO;AAAA,IACL,UAAU,CAAC,OAAO,WAAW,SAAY,YAAY,IAAI,SAAS,OAAO,QAAQ;AAAA,IACjF,YAAY,CAAC,OAAO,aAChB,SACA,cAAc,IAAI,SAAS,OAAO,YAAY,OAAO;AAAA,IACzD,uBAAuB,CAAC,OAAO,wBAC3B,SACA,yBAAyB,IAAI,SAAS,OAAO,uBAAuB,OAAO;AAAA,IAC/E,SAAS,CAAC,OAAO,UAAU,SAAY,WAAW,IAAI,OAAO,OAAO;AAAA,EACtE;AACF;AAQO,SAAS,YACd,IACA,SACA,QACqB;AACrB,SAAO,eAAY,IAAI,QAAQ,CAAC,EAAE,MAAM,KAAK,GAAG,QAAQ;AACtD,UAAMC,QAAO,KAAK,GAAG;AAErB,UAAM,WAAW,GAAG,mBAAmB,SAASA,KAAI;AAEpD,QAAI,cAAc,IAAI,GAAG;AACvB,aAAO;AAAA,QACL,IAAI,KAAa;AACf,aAAG,UAAU,UAAU,GAAG;AAAA,QAC5B;AAAA,MACF;AAAA,IACF;AAEA,UAAM,SAAS,UAAU,oBAAoB,IAAI,CAAC,GAAG,OAAO,MAAM,EAAE;AAGpE,UAAM,KAAK,GAAG,MAAM,EAAE,KAAK,EAAE;AAE7B,QAAI,UAAU,IAAI,GAAG;AACnB,aAAO;AAAA,QACL,OAAO,MAAa;AAClB,aAAG,UAAU,OAAO,KAAK,CAAC,CAAC;AAAA,QAC7B;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL,OAAO,MAAa;AAClB,WAAG,UAAU,GAAG,IAAI;AAAA,MACtB;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAUA,SAAS,gBACP,IACA,UACA,MACA,QACA,QACA,MACA,WACA;AACA,KAAG,wBAAwB,QAAQ;AACnC,KAAG,oBAAoB,UAAU,MAAM,GAAG,IAAI,GAAG,OAAO,QAAQ,MAAM;AAEtE,MAAI,WAAW;AAEb,uBAAmB,mBAAmB,EAAE,CAAC,EAAE,oBAAoB,UAAU,CAAC;AAAA,EAC5E;AACF;AAEO,SAAS,cACd,IACA,SACA,QACA,EAAE,OAAO,IAAiB,CAAC,GACT;AAClB,QAAM,aAAa,eAAY;AAAA,IAC7B;AAAA,IACA,CACE,EAAE,MAAM,WAAW,SAAS,mBAAmB,GAAG,aAAa,CAAC,EAAE,GAClE,QACqB;AACrB,YAAMA,QAAO,KAAK,GAAG;AAErB,YAAM,WAAW,GAAG,kBAAkB,SAASA,KAAI;AACnD,UAAI,WAAW,GAAG;AAChB,cAAM,IAAI,MAAM,cAAcA,KAAI,aAAa;AAAA,MACjD;AAEA,YAAM,OAAO,WAAW,IAAI;AAC5B,YAAM,OAAO,KAAK,WAAW,GAAG,IAAI,QAAQ;AAE5C,aAAO;AAAA,QACL;AAAA,QACA,OAAO;AACL,aAAG,WAAW,GAAG,cAAc,MAAM;AACrC,0BAAgB,IAAI,UAAU,MAAM,GAAG,GAAG,MAAM,SAAS;AAAA,QAC3D;AAAA,QACA,UAAU;AACR,aAAG,aAAa,MAAM;AAAA,QACxB;AAAA,QACA,IAAI,MAAM,QAAQ,eAAe;AAC/B,aAAG,WAAW,GAAG,cAAc,MAAM;AACrC,aAAG,WAAW,GAAG,cAAc,MAAM,GAAG,KAAK,CAAC;AAC9C,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,UAAQ,iBAAiB,SAAS,SAAS,UAAU;AACnD,mBAAY,QAAQ,YAAY,WAAS,MAAM,QAAQ,CAAC;AAAA,EAC1D,CAAC;AAED,SAAO;AACT;AAQO,SAAS,yBACd,IACA,SACA,QACA,EAAE,OAAO,IAAiB,CAAC,GACE;AAE7B,QAAM,wBAAwB,eAAY,IAAI,QAAQ,CAAC,EAAE,QAAQ,UAAU,MAAM;AAE/E,QAAIC,SAAQ;AAGZ,UAAM,UAAU,OAAO,IAAI,CAAAC,YAAU;AACnC,YAAMF,QAAO,KAAKE,QAAO,GAAG;AAE5B,YAAM,WAAW,GAAG,kBAAkB,SAASF,KAAI;AAEnD,UAAI,WAAW,GAAG;AAChB,cAAM,IAAI,MAAM,cAAcA,KAAI,aAAa;AAAA,MACjD;AAEA,YAAM,OAAO,WAAWE,QAAO,IAAI;AACnC,YAAM,SAASD;AACf,YAAM,OAAOC,QAAO,KAAK,WAAW,GAAG,IAAI,QAAQ;AACnD,MAAAD,UAAS,OAAO;AAEhB,aAAO,MAAM,gBAAgB,IAAI,UAAU,MAAM,QAAQ,QAAQ,MAAM,SAAS;AAAA,IAClF,CAAC;AAGD,UAAM,SAASA;AAGf,UAAM,SAAS,mBAAmB,GAAG,aAAa,CAAC;AAGnD,QAAI,MAAqE;AAGzE,UAAM,UAAU,qBAAqB,EAAE;AACvC,QAAI,SAAS;AACX,YAAM,cAAc,QAAQ,kBAAkB;AAC9C,cAAQ,gBAAgB,WAAW;AACnC,SAAG,WAAW,GAAG,cAAc,MAAM;AACrC,iBAAW,UAAU,SAAS;AAC5B,eAAO;AAAA,MACT;AACA,cAAQ,gBAAgB,IAAI;AAC5B,YAAM;AAAA,QACJ,SAAS;AACP,kBAAQ,gBAAgB,IAAI;AAAA,QAC9B;AAAA,QACA,OAAO;AACL,kBAAQ,gBAAgB,WAAW;AAAA,QACrC;AAAA,QACA,UAAU;AACR,kBAAQ,kBAAkB,WAAW;AAAA,QACvC;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL,OAAO;AACL,WAAG,WAAW,GAAG,cAAc,MAAM;AACrC,YAAI,KAAK;AACP,cAAI,KAAK;AAAA,QACX,OAAO;AAEL,qBAAW,UAAU,SAAS;AAC5B,mBAAO;AAAA,UACT;AAAA,QACF;AAAA,MACF;AAAA,MACA,SAAS;AACP,YAAI,KAAK;AACP,cAAI,OAAO;AAAA,QACb;AAAA,MACF;AAAA,MACA,UAAU;AACR,WAAG,aAAa,MAAM;AACtB,YAAI,KAAK;AACP,cAAI,QAAQ;AAAA,QACd;AAAA,MACF;AAAA,MACA,IAAI,OAAO,QAAQ,eAAe;AAChC,YAAI,KAAK;AACP,cAAI,KAAK;AAAA,QACX,OAAO;AACL,aAAG,WAAW,GAAG,cAAc,MAAM;AAAA,QACvC;AACA,WAAG,WAAW,GAAG,cAAc,OAAO,GAAG,KAAK,CAAC;AAC/C,YAAI,KAAK;AACP,cAAI,OAAO;AAAA,QACb;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC;AAED,UAAQ,iBAAiB,SAAS,SAAS,UAAU;AACnD,mBAAY,QAAQ,uBAAuB,WAAS,MAAM,QAAQ,CAAC;AAAA,EACrE,CAAC;AAED,SAAO;AACT;AAQO,SAAS,WACd,IACA,QACA,EAAE,OAAO,IAAiB,CAAC,GACZ;AAEf,QAAM,UAAU,eAAY,IAAI,QAAQ,CAAC,EAAE,SAAS,gBAAgB,QAAQ,cAAc,MAAM;AAC9F,UAAM,SAAS,mBAAmB,GAAG,aAAa,CAAC;AACnD,WAAO;AAAA,MACL,OAAO;AACL,WAAG,WAAW,GAAG,MAAM,GAAG,MAAM;AAAA,MAClC;AAAA,MACA,UAAU;AACR,WAAG,aAAa,MAAM;AAAA,MACxB;AAAA,MACA,IAAI,MAAoB;AACtB,WAAG,WAAW,GAAG,MAAM,GAAG,MAAM;AAChC,WAAG,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;AAAA,MAC3C;AAAA,IACF;AAAA,EACF,CAAC;AAED,UAAQ,iBAAiB,SAAS,SAAS,UAAU;AACnD,mBAAY,QAAQ,SAAS,WAAS,MAAM,QAAQ,CAAC;AAAA,EACvD,CAAC;AAED,SAAO;AACT;;;ACxTO,SAAS,KACd,aACG,OACc;AACjB,SAAO,EAAE,UAAU,OAAO,MAAM,OAAO;AACzC;AAEO,IAAM,UAAU,IAAI;AAAA,EACzB,CAAC;AAAA,EAGD;AAAA,IACE,IAAI,QAAQ,UAAU;AAEpB,UAAI,OAAO,aAAa,SAAU,QAAO,OAAO,QAAQ;AACxD,aAAO,CAAC,KAAa,aAA4C;AAAA,QAC/D,MAAM;AAAA,QACN;AAAA,QACA,MAAM;AAAA,QACN,GAAG;AAAA,MACL;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,YAAY,IAAI;AAAA,EAC3B,CAAC;AAAA,EAGD;AAAA,IACE,IAAI,QAAQ,UAAU;AAEpB,UAAI,OAAO,aAAa,SAAU,QAAO,OAAO,QAAQ;AACxD,aAAO,CAAC,KAAa,aAA8C;AAAA,QACjE,MAAM;AAAA,QACN;AAAA,QACA,MAAM;AAAA,QACN,GAAG;AAAA,MACL;AAAA,IACF;AAAA,EACF;AACF;AAWO,SAAS,WAId,KAAW,QAAiB,EAAE,WAAW,OAAO,IAAuB,CAAC,GAAG;AAC3E,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA;AAAA,IAEA,QAAQ,OAAO,IAAI,CAAC,EAAE,KAAAE,MAAK,KAAK,OAAO;AAAA,MACrC,KAAAA;AAAA,MACA;AAAA,IACF,EAAE;AAAA,IACF,WAAW,CAAC,CAAC;AAAA,IACb;AAAA,EACF;AACF;AA8EO,SAAS,QAId,IAA2B,QAAiB,UAAqB,gBAA4B;AAC7F,QAAM,UAAU,eAAe,MAAM;AACrC,QAAM,YAAY,eAAe,QAAQ;AAEzC,QAAM,SAAS;AAAA,IACb,UAAU;AAAA,MACR,GAAG,QAAQ,OAAO;AAAA,MAClB,GAAG,UAAU,OAAO;AAAA,IACtB;AAAA,IACA,YAAY;AAAA,MACV,GAAG,QAAQ,OAAO;AAAA,MAClB,GAAG,UAAU,OAAO;AAAA,IACtB;AAAA,IACA,uBAAuB;AAAA,MACrB,GAAG,QAAQ,OAAO;AAAA,MAClB,GAAG,UAAU,OAAO;AAAA,IACtB;AAAA,EACF;AAEA,aAAW,QAAQ,gBAAgB;AACjC,UAAM,aAAa,OAAO,IAA2B;AACrD,UAAM,qBAAqB,eAAe,IAAI;AAE9C,eAAW,OAAO,oBAAoB;AAEpC,iBAAW,GAAG,IAAI;AAAA;AAAA,QAEhB,GAAG,WAAW,GAAG;AAAA,QACjB,GAAG,mBAAmB,GAAG;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AAEA,QAAM,UAAU,cAAc,IAAI,QAAQ,UAAU,UAAU,QAAQ;AAEtE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,MAAM,KAAK,IAAI,SAAS,MAAM;AAAA,EAChC;AACF;AAEA,SAAS,eAAqC,KAAW;AACvD,SAAO;AAAA,IACL,UAAU,gBAAgB,GAAG;AAAA,IAC7B,QAAQ,gBAAgB,GAAG;AAAA,EAC7B;AACF;AAEA,SAAS,gBAAsC,KAAW;AACxD,QAAM,SAAS;AAAA,IACb,UAAU,CAAC;AAAA,IACX,YAAY,CAAC;AAAA,IACb,uBAAuB,CAAC;AAAA,EAC1B;AAEA,WAAS,WAAW,MAAgB;AAClC,QAAI,MAAM,QAAQ,IAAI,GAAG;AACvB,WAAK,QAAQ,UAAU;AACvB;AAAA,IACF;AAEA,QAAI,OAAO,SAAS,UAAU;AAC5B;AAAA,IACF;AAEA,QAAI,KAAK,SAAS,QAAQ;AACxB,YAAM,EAAE,UAAU,YAAY,sBAAsB,IAAI,gBAAgB,IAAI;AAE5E,aAAO,WAAW;AAAA,QAChB,GAAG,OAAO;AAAA,QACV,GAAG;AAAA,MACL;AACA,aAAO,aAAa;AAAA,QAClB,GAAG,OAAO;AAAA,QACV,GAAG;AAAA,MACL;AACA,aAAO,wBAAwB;AAAA,QAC7B,GAAG,OAAO;AAAA,QACV,GAAG;AAAA,MACL;AAEA;AAAA,IACF;AAEA,UAAM,EAAE,KAAKC,OAAM,MAAM,GAAG,KAAK,IAAI;AAGrC,WAAO,GAAG,IAAI,GAAG,EAAEA,KAAI,IAAI;AAAA,EAC7B;AAEA,MAAI,MAAM,QAAQ,UAAU;AAE5B,SAAO;AACT;AAqCA,SAAS,gBAAsC,EAAE,UAAU,CAAC,SAAS,GAAG,IAAI,GAAG,MAAM,GAAS;AAC5F,QAAM,OAAO,CAAC,CAAC,SAAS,WAAW,iBAAiB;AAEpD,MAAI,WAAW,WAAW;AAE1B,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,gBAAY,GAAG,iBAAiB,MAAM,CAAC,GAAI,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;AAAA,EAC5D;AAEA,SAAO;AACT;AAEA,SAAS,iBAAiB,MAAgB,MAAuB;AAC/D,MAAI,OAAO,SAAS,UAAU;AAC5B,WAAO,KAAK,IAAI;AAAA,EAClB;AAEA,MAAI,MAAM,QAAQ,IAAI,GAAG;AACvB,WAAO,KAAK,IAAI,CAAAC,UAAQ,iBAAiBA,OAAM,IAAI,CAAC,EAAE,KAAK,EAAE;AAAA,EAC/D;AAEA,MAAI,KAAK,SAAS,QAAQ;AACxB,WAAO,gBAAgB,IAAI;AAAA,EAC7B;AAEA,MAAI,KAAK,SAAS,wBAAwB;AACxC,WAAO,KAAK,OAAO;AAAA,MACjB,CAAC,GAAG,MACF,OAAO,GAAG,CAAC,MAAM,EAAE,IAAI,IAAI,KAAK,EAAE,GAAG,CAAC;AAAA,IAAQ,GAAG,CAAC,aAAa,EAAE,IAAI,IAAI,KAAK,EAAE,GAAG,CAAC;AAAA;AAAA,MACtF;AAAA,IACF;AAAA,EACF;AAEA,MAAI,KAAK,SAAS,aAAa,UAAU,MAAM;AAC7C,WAAO,GAAG,KAAK,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,KAAK,GAAG,CAAC,IAAI,KAAK,IAAI;AAAA,EACjE;AAEA,SAAO,GAAG,KAAK,SAAS,eAAe,OAAO,OAAO,KAAK,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,KAAK,GAAG,CAAC;AAC/F;","names":["index","value","map","name","index","layout","key","name","slot"]}
|
|
@@ -245,7 +245,8 @@ type View<T extends ViewSchema = ViewSchema> = {
|
|
|
245
245
|
buffers: T['buffers'] extends BufferSchema ? BufferView<T['buffers']> : undefined;
|
|
246
246
|
uniforms: T['uniforms'] extends UniformSchema ? UniformView<T['uniforms']> : never;
|
|
247
247
|
};
|
|
248
|
-
type
|
|
248
|
+
type GLSLSlotItem = GLSLTag | UniformTag | AttributeTag | InterleaveTag | string | number | symbol;
|
|
249
|
+
type GLSLSlot = GLSLSlotItem | Array<GLSLSlotItem>;
|
|
249
250
|
interface GLSLTag<TSlots extends GLSLSlot[] = GLSLSlot[]> {
|
|
250
251
|
type: 'glsl';
|
|
251
252
|
template: TemplateStringsArray;
|
package/package.json
CHANGED
package/src/tag.ts
CHANGED
|
@@ -226,9 +226,14 @@ function glslTagToSchema<TTag extends GLSLTag>(tag: TTag) {
|
|
|
226
226
|
interleavedAttributes: {},
|
|
227
227
|
}
|
|
228
228
|
|
|
229
|
-
|
|
229
|
+
function handleSlot(slot: GLSLSlot) {
|
|
230
|
+
if (Array.isArray(slot)) {
|
|
231
|
+
slot.forEach(handleSlot)
|
|
232
|
+
return
|
|
233
|
+
}
|
|
234
|
+
|
|
230
235
|
if (typeof slot !== 'object') {
|
|
231
|
-
|
|
236
|
+
return
|
|
232
237
|
}
|
|
233
238
|
|
|
234
239
|
if (slot.type === 'glsl') {
|
|
@@ -247,7 +252,7 @@ function glslTagToSchema<TTag extends GLSLTag>(tag: TTag) {
|
|
|
247
252
|
...interleavedAttributes,
|
|
248
253
|
}
|
|
249
254
|
|
|
250
|
-
|
|
255
|
+
return
|
|
251
256
|
}
|
|
252
257
|
|
|
253
258
|
const { key: name, type, ...rest } = slot
|
|
@@ -256,9 +261,46 @@ function glslTagToSchema<TTag extends GLSLTag>(tag: TTag) {
|
|
|
256
261
|
result[`${type}s`][name] = rest
|
|
257
262
|
}
|
|
258
263
|
|
|
264
|
+
tag.slots.forEach(handleSlot)
|
|
265
|
+
|
|
259
266
|
return result
|
|
260
267
|
}
|
|
261
268
|
|
|
269
|
+
// function glslSlotToSchema(slot: GLSLSlot){
|
|
270
|
+
// if(Array.isArray(slot)){
|
|
271
|
+
|
|
272
|
+
// return
|
|
273
|
+
// }
|
|
274
|
+
|
|
275
|
+
// if (typeof slot !== 'object') {
|
|
276
|
+
// return
|
|
277
|
+
// }
|
|
278
|
+
|
|
279
|
+
// if (slot.type === 'glsl') {
|
|
280
|
+
// return glslTagToSchema(slot)
|
|
281
|
+
|
|
282
|
+
// // result.uniforms = {
|
|
283
|
+
// // ...result.uniforms,
|
|
284
|
+
// // ...uniforms,
|
|
285
|
+
// // }
|
|
286
|
+
// // result.attributes = {
|
|
287
|
+
// // ...result.attributes,
|
|
288
|
+
// // ...attributes,
|
|
289
|
+
// // }
|
|
290
|
+
// // result.interleavedAttributes = {
|
|
291
|
+
// // ...result.interleavedAttributes,
|
|
292
|
+
// // ...interleavedAttributes,
|
|
293
|
+
// // }
|
|
294
|
+
|
|
295
|
+
// // continue
|
|
296
|
+
// }
|
|
297
|
+
|
|
298
|
+
// const { key: name, type, ...rest } = slot
|
|
299
|
+
|
|
300
|
+
// // @ts-expect-error
|
|
301
|
+
// result[`${type}s`][name] = rest
|
|
302
|
+
// }
|
|
303
|
+
|
|
262
304
|
function glslTagToString<TTag extends GLSLTag>({ template: [initial, ...rest], slots }: TTag) {
|
|
263
305
|
const v300 = !!initial?.startsWith('#version 300 es')
|
|
264
306
|
|
|
@@ -271,11 +313,15 @@ function glslTagToString<TTag extends GLSLTag>({ template: [initial, ...rest], s
|
|
|
271
313
|
return template
|
|
272
314
|
}
|
|
273
315
|
|
|
274
|
-
function glslSlotToString(slot: GLSLSlot, v300: boolean) {
|
|
316
|
+
function glslSlotToString(slot: GLSLSlot, v300: boolean): string {
|
|
275
317
|
if (typeof slot !== 'object') {
|
|
276
318
|
return toID(slot)
|
|
277
319
|
}
|
|
278
320
|
|
|
321
|
+
if (Array.isArray(slot)) {
|
|
322
|
+
return slot.map(slot => glslSlotToString(slot, v300)).join('')
|
|
323
|
+
}
|
|
324
|
+
|
|
279
325
|
if (slot.type === 'glsl') {
|
|
280
326
|
return glslTagToString(slot)
|
|
281
327
|
}
|
package/src/types.ts
CHANGED
|
@@ -709,14 +709,9 @@ export interface GLSLResult {
|
|
|
709
709
|
schema: ViewSchema
|
|
710
710
|
}
|
|
711
711
|
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
| AttributeTag
|
|
716
|
-
| InterleaveTag
|
|
717
|
-
| string
|
|
718
|
-
| number
|
|
719
|
-
| symbol
|
|
712
|
+
type GLSLSlotItem = GLSLTag | UniformTag | AttributeTag | InterleaveTag | string | number | symbol
|
|
713
|
+
|
|
714
|
+
export type GLSLSlot = GLSLSlotItem | Array<GLSLSlotItem>
|
|
720
715
|
|
|
721
716
|
export interface GLSLTag<TSlots extends GLSLSlot[] = GLSLSlot[]> {
|
|
722
717
|
type: 'glsl'
|
package/test/tag.test.ts
CHANGED
|
@@ -992,6 +992,275 @@ describe('compile with symbols', () => {
|
|
|
992
992
|
})
|
|
993
993
|
})
|
|
994
994
|
|
|
995
|
+
describe('glsl array interpolation', () => {
|
|
996
|
+
let gl: GL
|
|
997
|
+
|
|
998
|
+
beforeEach(() => {
|
|
999
|
+
gl = createMockGL()
|
|
1000
|
+
})
|
|
1001
|
+
|
|
1002
|
+
it('should interpolate arrays of resource tags', () => {
|
|
1003
|
+
const shader = glsl`
|
|
1004
|
+
${[uniform.float('u_time'), uniform.vec2('u_resolution')]}
|
|
1005
|
+
${[attribute.vec3('a_position'), attribute.vec2('a_uv')]}
|
|
1006
|
+
|
|
1007
|
+
void main() {
|
|
1008
|
+
gl_Position = vec4(a_position, 1.0);
|
|
1009
|
+
}
|
|
1010
|
+
`
|
|
1011
|
+
|
|
1012
|
+
const { schema } = compile(gl, shader, glsl``)
|
|
1013
|
+
|
|
1014
|
+
expect(schema.uniforms).toEqual({
|
|
1015
|
+
u_time: { kind: 'float' },
|
|
1016
|
+
u_resolution: { kind: 'vec2' },
|
|
1017
|
+
})
|
|
1018
|
+
|
|
1019
|
+
expect(schema.attributes).toEqual({
|
|
1020
|
+
a_position: { kind: 'vec3' },
|
|
1021
|
+
a_uv: { kind: 'vec2' },
|
|
1022
|
+
})
|
|
1023
|
+
})
|
|
1024
|
+
|
|
1025
|
+
it('should interpolate arrays with mixed types', () => {
|
|
1026
|
+
const sharedUniforms = glsl`
|
|
1027
|
+
${uniform.float('u_time')}
|
|
1028
|
+
${uniform.vec2('u_resolution')}
|
|
1029
|
+
`
|
|
1030
|
+
|
|
1031
|
+
const shader = glsl`
|
|
1032
|
+
${[sharedUniforms, uniform.vec3('u_color')]}
|
|
1033
|
+
${[attribute.vec3('a_position'), 'precision mediump float;']}
|
|
1034
|
+
|
|
1035
|
+
void main() {
|
|
1036
|
+
gl_Position = vec4(a_position, 1.0);
|
|
1037
|
+
}
|
|
1038
|
+
`
|
|
1039
|
+
|
|
1040
|
+
const { schema } = compile(gl, shader, glsl``)
|
|
1041
|
+
|
|
1042
|
+
expect(schema.uniforms).toEqual({
|
|
1043
|
+
u_time: { kind: 'float' },
|
|
1044
|
+
u_resolution: { kind: 'vec2' },
|
|
1045
|
+
u_color: { kind: 'vec3' },
|
|
1046
|
+
})
|
|
1047
|
+
|
|
1048
|
+
expect(schema.attributes).toEqual({
|
|
1049
|
+
a_position: { kind: 'vec3' },
|
|
1050
|
+
})
|
|
1051
|
+
|
|
1052
|
+
// Check that the string was interpolated in the shader source
|
|
1053
|
+
const shaderSource = (gl.shaderSource as any).mock.calls.find(
|
|
1054
|
+
(call: any[]) => call[1].includes('precision mediump float;')
|
|
1055
|
+
)
|
|
1056
|
+
expect(shaderSource).toBeTruthy()
|
|
1057
|
+
})
|
|
1058
|
+
|
|
1059
|
+
it('should interpolate arrays with symbols', () => {
|
|
1060
|
+
const u_time_symbol = Symbol('u_time')
|
|
1061
|
+
const a_pos_symbol = Symbol('a_position')
|
|
1062
|
+
|
|
1063
|
+
const shader = glsl`
|
|
1064
|
+
${[uniform.float(u_time_symbol), uniform.vec3('u_color')]}
|
|
1065
|
+
${[attribute.vec3(a_pos_symbol), attribute.vec2('a_uv')]}
|
|
1066
|
+
|
|
1067
|
+
void main() {
|
|
1068
|
+
gl_Position = vec4(${a_pos_symbol}, 1.0);
|
|
1069
|
+
}
|
|
1070
|
+
`
|
|
1071
|
+
|
|
1072
|
+
const { schema } = compile(gl, shader, glsl``)
|
|
1073
|
+
|
|
1074
|
+
expect(schema.uniforms).toEqual({
|
|
1075
|
+
[u_time_symbol]: { kind: 'float' },
|
|
1076
|
+
u_color: { kind: 'vec3' },
|
|
1077
|
+
})
|
|
1078
|
+
|
|
1079
|
+
expect(schema.attributes).toEqual({
|
|
1080
|
+
[a_pos_symbol]: { kind: 'vec3' },
|
|
1081
|
+
a_uv: { kind: 'vec2' },
|
|
1082
|
+
})
|
|
1083
|
+
|
|
1084
|
+
// Check that symbol was interpolated in the shader source
|
|
1085
|
+
const shaderSource = (gl.shaderSource as any).mock.calls.find(
|
|
1086
|
+
(call: any[]) => call[1].includes('attribute vec3 VIEW_GL_ALIAS_') &&
|
|
1087
|
+
call[1].includes('uniform float VIEW_GL_ALIAS_')
|
|
1088
|
+
)
|
|
1089
|
+
expect(shaderSource).toBeTruthy()
|
|
1090
|
+
})
|
|
1091
|
+
|
|
1092
|
+
it('should interpolate nested arrays', () => {
|
|
1093
|
+
const shader = glsl`
|
|
1094
|
+
${[[uniform.float('u_time'), uniform.vec2('u_resolution')], uniform.vec3('u_color')]}
|
|
1095
|
+
${[[attribute.vec3('a_position')], [attribute.vec2('a_uv'), attribute.vec3('a_normal')]]}
|
|
1096
|
+
|
|
1097
|
+
void main() {
|
|
1098
|
+
gl_Position = vec4(a_position, 1.0);
|
|
1099
|
+
}
|
|
1100
|
+
`
|
|
1101
|
+
|
|
1102
|
+
const { schema } = compile(gl, shader, glsl``)
|
|
1103
|
+
|
|
1104
|
+
expect(schema.uniforms).toEqual({
|
|
1105
|
+
u_time: { kind: 'float' },
|
|
1106
|
+
u_resolution: { kind: 'vec2' },
|
|
1107
|
+
u_color: { kind: 'vec3' },
|
|
1108
|
+
})
|
|
1109
|
+
|
|
1110
|
+
expect(schema.attributes).toEqual({
|
|
1111
|
+
a_position: { kind: 'vec3' },
|
|
1112
|
+
a_uv: { kind: 'vec2' },
|
|
1113
|
+
a_normal: { kind: 'vec3' },
|
|
1114
|
+
})
|
|
1115
|
+
})
|
|
1116
|
+
|
|
1117
|
+
it('should interpolate arrays with interleaved attributes', () => {
|
|
1118
|
+
const vertexData = interleave('vertexData', [
|
|
1119
|
+
attribute.vec2('a_position'),
|
|
1120
|
+
attribute.vec2('a_uv'),
|
|
1121
|
+
])
|
|
1122
|
+
|
|
1123
|
+
const shader = glsl`
|
|
1124
|
+
${[vertexData, uniform.mat4('u_mvpMatrix')]}
|
|
1125
|
+
|
|
1126
|
+
void main() {
|
|
1127
|
+
gl_Position = u_mvpMatrix * vec4(a_position, 0.0, 1.0);
|
|
1128
|
+
}
|
|
1129
|
+
`
|
|
1130
|
+
|
|
1131
|
+
const { schema } = compile(gl, shader, glsl``)
|
|
1132
|
+
|
|
1133
|
+
expect(schema.uniforms).toEqual({
|
|
1134
|
+
u_mvpMatrix: { kind: 'mat4' },
|
|
1135
|
+
})
|
|
1136
|
+
|
|
1137
|
+
expect(schema.interleavedAttributes).toEqual({
|
|
1138
|
+
vertexData: {
|
|
1139
|
+
layout: [
|
|
1140
|
+
{ key: 'a_position', kind: 'vec2' },
|
|
1141
|
+
{ key: 'a_uv', kind: 'vec2' },
|
|
1142
|
+
],
|
|
1143
|
+
instanced: false,
|
|
1144
|
+
},
|
|
1145
|
+
})
|
|
1146
|
+
})
|
|
1147
|
+
|
|
1148
|
+
it('should interpolate arrays with composed glsl templates', () => {
|
|
1149
|
+
const sharedUniforms = glsl`
|
|
1150
|
+
${uniform.float('u_time')}
|
|
1151
|
+
${uniform.vec2('u_resolution')}
|
|
1152
|
+
`
|
|
1153
|
+
|
|
1154
|
+
const lightingCode = glsl`
|
|
1155
|
+
${uniform.vec3('u_lightPos')}
|
|
1156
|
+
|
|
1157
|
+
vec3 calculateLighting(vec3 pos) {
|
|
1158
|
+
return normalize(u_lightPos - pos);
|
|
1159
|
+
}
|
|
1160
|
+
`
|
|
1161
|
+
|
|
1162
|
+
const shader = glsl`
|
|
1163
|
+
${[sharedUniforms, lightingCode]}
|
|
1164
|
+
${[attribute.vec3('a_position'), attribute.vec3('a_normal')]}
|
|
1165
|
+
|
|
1166
|
+
void main() {
|
|
1167
|
+
vec3 lighting = calculateLighting(a_position);
|
|
1168
|
+
gl_Position = vec4(a_position, 1.0);
|
|
1169
|
+
}
|
|
1170
|
+
`
|
|
1171
|
+
|
|
1172
|
+
const { schema } = compile(gl, shader, glsl``)
|
|
1173
|
+
|
|
1174
|
+
expect(schema.uniforms).toEqual({
|
|
1175
|
+
u_time: { kind: 'float' },
|
|
1176
|
+
u_resolution: { kind: 'vec2' },
|
|
1177
|
+
u_lightPos: { kind: 'vec3' },
|
|
1178
|
+
})
|
|
1179
|
+
|
|
1180
|
+
expect(schema.attributes).toEqual({
|
|
1181
|
+
a_position: { kind: 'vec3' },
|
|
1182
|
+
a_normal: { kind: 'vec3' },
|
|
1183
|
+
})
|
|
1184
|
+
|
|
1185
|
+
// Check that both templates and the function were interpolated
|
|
1186
|
+
const shaderSource = (gl.shaderSource as any).mock.calls.find(
|
|
1187
|
+
(call: any[]) => call[1].includes('calculateLighting') &&
|
|
1188
|
+
call[1].includes('uniform float u_time') &&
|
|
1189
|
+
call[1].includes('uniform vec3 u_lightPos')
|
|
1190
|
+
)
|
|
1191
|
+
expect(shaderSource).toBeTruthy()
|
|
1192
|
+
})
|
|
1193
|
+
|
|
1194
|
+
it('should handle empty arrays', () => {
|
|
1195
|
+
const shader = glsl`
|
|
1196
|
+
${[]}
|
|
1197
|
+
${uniform.float('u_time')}
|
|
1198
|
+
${[]}
|
|
1199
|
+
|
|
1200
|
+
void main() {
|
|
1201
|
+
gl_Position = vec4(1.0);
|
|
1202
|
+
}
|
|
1203
|
+
`
|
|
1204
|
+
|
|
1205
|
+
const { schema } = compile(gl, shader, glsl``)
|
|
1206
|
+
|
|
1207
|
+
expect(schema.uniforms).toEqual({
|
|
1208
|
+
u_time: { kind: 'float' },
|
|
1209
|
+
})
|
|
1210
|
+
|
|
1211
|
+
expect(schema.attributes).toEqual({})
|
|
1212
|
+
expect(schema.interleavedAttributes).toEqual({})
|
|
1213
|
+
})
|
|
1214
|
+
|
|
1215
|
+
it('should interpolate arrays with WebGL2 syntax', () => {
|
|
1216
|
+
const shader = glsl`#version 300 es
|
|
1217
|
+
${[uniform.float('u_time'), attribute.vec3('a_position')]}
|
|
1218
|
+
|
|
1219
|
+
void main() {
|
|
1220
|
+
gl_Position = vec4(a_position, 1.0);
|
|
1221
|
+
}
|
|
1222
|
+
`
|
|
1223
|
+
|
|
1224
|
+
compile(gl, shader, glsl``)
|
|
1225
|
+
|
|
1226
|
+
// Check that shaderSource was called with WebGL2 syntax
|
|
1227
|
+
const shaderSource = (gl.shaderSource as any).mock.calls.find(
|
|
1228
|
+
(call: any[]) => call[1].includes('uniform float u_time') &&
|
|
1229
|
+
call[1].includes('in vec3 a_position')
|
|
1230
|
+
)
|
|
1231
|
+
expect(shaderSource).toBeTruthy()
|
|
1232
|
+
})
|
|
1233
|
+
|
|
1234
|
+
it('should preserve order when interpolating arrays', () => {
|
|
1235
|
+
const shader = glsl`
|
|
1236
|
+
${['// First comment', uniform.float('u_time'), '// Second comment']}
|
|
1237
|
+
|
|
1238
|
+
void main() {
|
|
1239
|
+
gl_Position = vec4(1.0);
|
|
1240
|
+
}
|
|
1241
|
+
`
|
|
1242
|
+
|
|
1243
|
+
compile(gl, shader, glsl``)
|
|
1244
|
+
|
|
1245
|
+
// Check that order is preserved in the shader source
|
|
1246
|
+
const shaderSource = (gl.shaderSource as any).mock.calls.find(
|
|
1247
|
+
(call: any[]) => call[1].includes('// First comment') &&
|
|
1248
|
+
call[1].includes('uniform float u_time') &&
|
|
1249
|
+
call[1].includes('// Second comment')
|
|
1250
|
+
)?.[1]
|
|
1251
|
+
|
|
1252
|
+
expect(shaderSource).toBeTruthy()
|
|
1253
|
+
|
|
1254
|
+
// Verify order
|
|
1255
|
+
const firstIndex = shaderSource.indexOf('// First comment')
|
|
1256
|
+
const uniformIndex = shaderSource.indexOf('uniform float u_time')
|
|
1257
|
+
const secondIndex = shaderSource.indexOf('// Second comment')
|
|
1258
|
+
|
|
1259
|
+
expect(firstIndex).toBeLessThan(uniformIndex)
|
|
1260
|
+
expect(uniformIndex).toBeLessThan(secondIndex)
|
|
1261
|
+
})
|
|
1262
|
+
})
|
|
1263
|
+
|
|
995
1264
|
describe('compile', () => {
|
|
996
1265
|
let gl: GL
|
|
997
1266
|
let mockProgram: WebGLProgram
|