@bigmistqke/view.gl 0.1.7 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -42
- package/dist/index.d.mts +2 -2
- package/dist/tag.d.mts +68 -68
- package/dist/tag.mjs +3 -1
- package/dist/tag.mjs.map +1 -1
- package/dist/{types-C4TRuvYh.d.mts → types-Bp9VAVe3.d.mts} +27 -24
- package/package.json +1 -1
- package/src/tag.ts +22 -20
- package/src/types.ts +45 -32
- package/test/tag.test.ts +235 -6
package/README.md
CHANGED
|
@@ -1,56 +1,61 @@
|
|
|
1
1
|
# 👁️ @bigmistqke/view.gl
|
|
2
2
|
|
|
3
|
-
🔧
|
|
3
|
+
🔧 Utilities for managing WebGL resources: uniforms, (interleaved) attributes and buffers.
|
|
4
4
|
|
|
5
5
|
- schema-based resource management [`view-gl`](#️-viewgl)
|
|
6
|
-
-
|
|
6
|
+
- compose schema and shader simultaneously via a tag template literal [`view-gl/tag`](#️-viewgltag)
|
|
7
7
|
|
|
8
8
|
## Table of Contents
|
|
9
9
|
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
10
|
+
- 📦 [Install](#-install)
|
|
11
|
+
- 👁️ [view.gl](#️-viewgl)
|
|
12
|
+
- 🚀 [Basic Usage](#-basic-usage)
|
|
13
|
+
- 👁️ [view](#️-view)
|
|
14
|
+
- 📋 [ViewSchema](#-viewschema)
|
|
15
|
+
- 👀 [Resource Views](#-resource-views)
|
|
16
|
+
- 🎯 [uniformView](#-uniformview)
|
|
17
|
+
- 📋 [UniformSchema](#-uniformschema)
|
|
18
|
+
- 📝 [attributeView](#-attributeview)
|
|
19
|
+
- 📋 [AttributeSchema](#-attributeschema)
|
|
20
|
+
- 🔗 [interleavedAttributeView](#-interleavedattributeview)
|
|
21
|
+
- 📋 [InterleavedAttributeSchema](#-interleavedattributeschema)
|
|
22
|
+
- 🗂️ [bufferView](#-bufferview)
|
|
23
|
+
- 📋 [BufferSchema](#-bufferschema)
|
|
24
|
+
- 🏷️ [view.gl/tag](#️-viewgltag)
|
|
25
|
+
- 🚀 [Basic Usage](#-basic-usage-1)
|
|
26
|
+
- 📝 [glsl](#-glsl)
|
|
27
|
+
- 🧩 [GLSL Fragment](#-glsl-fragment)
|
|
28
|
+
- 🔒 [Symbol Variables](#-symbol-variables)
|
|
29
29
|
- [WebGL Version Support](#webgl-version-support)
|
|
30
|
-
- [
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
-
|
|
37
|
-
-
|
|
38
|
-
-
|
|
39
|
-
-
|
|
40
|
-
-
|
|
41
|
-
-
|
|
42
|
-
-
|
|
43
|
-
-
|
|
30
|
+
- 🏷️ [Resource Tokens](#️-resource-tokens)
|
|
31
|
+
- 🎯 [uniform[kind](name, options?)](#-uniformkindname-options)
|
|
32
|
+
- 📝 [attribute[kind](name, options?)](#-attributekindname-options)
|
|
33
|
+
- 🔗 [interleave(name, layout, options?)](#-interleavename-layout-options)
|
|
34
|
+
- ⚙️ [compile(gl, vertex, fragment)](#️-compilegl-vertex-fragment)
|
|
35
|
+
- 🔍 [compile.toString(shader)](#-compiletostringshader)
|
|
36
|
+
- 📋 [compile.toSchema(shader)](#-compiletoschemaschader)
|
|
37
|
+
- 🛠️ [Utils](#️-utils)
|
|
38
|
+
- 🏗️ [createProgram](#️-createprogram)
|
|
39
|
+
- 🖼️ [createTexture](#️-createtexture)
|
|
40
|
+
- 🖥️ [createFramebuffer](#️-createframebuffer)
|
|
41
|
+
- 🔍 [WebGL Type Compatibility](#-webgl-type-compatibility)
|
|
42
|
+
- 🎯 [Uniform Types](#-uniform-types)
|
|
43
|
+
- 📝 [Attribute Types](#-attribute-types)
|
|
44
44
|
|
|
45
45
|
## 📦 Install
|
|
46
46
|
|
|
47
47
|
```shell
|
|
48
48
|
npm install @bigmistqke/view.gl
|
|
49
|
-
|
|
49
|
+
```
|
|
50
|
+
```shell
|
|
50
51
|
pnpm add @bigmistqke/view.gl
|
|
51
|
-
|
|
52
|
+
```
|
|
53
|
+
```shell
|
|
52
54
|
yarn add @bigmistqke/view.gl
|
|
53
55
|
```
|
|
56
|
+
```shell
|
|
57
|
+
bun add @bigmistqke/view.gl
|
|
58
|
+
```
|
|
54
59
|
|
|
55
60
|
## 👁️ view.gl
|
|
56
61
|
|
|
@@ -314,7 +319,7 @@ type BufferSchema = Record<string | symbol, BufferDefinition>
|
|
|
314
319
|
|
|
315
320
|
## 🏷️ view.gl/tag
|
|
316
321
|
|
|
317
|
-
Type-safe GLSL template literals with automatic schema extraction.
|
|
322
|
+
Type-safe GLSL template literals with automatic schema extraction and view creation.
|
|
318
323
|
|
|
319
324
|
- **Embedded Resources**: Define uniforms, attributes, and interleaved layouts directly in GLSL
|
|
320
325
|
- **Type Inference**: Automatically infers schema types and creates type-safe view
|
|
@@ -448,9 +453,9 @@ const shader = glsl`#version 300 es
|
|
|
448
453
|
`
|
|
449
454
|
```
|
|
450
455
|
|
|
451
|
-
###
|
|
456
|
+
### 🏷️ Resource Tokens
|
|
452
457
|
|
|
453
|
-
|
|
458
|
+
Utilities for defining WebGL resources directly in GLSL templates. These create metadata that the [`compile`](#️-compilegl-vertex-fragment-overrideschema) consumes to generate the typesafe schema and view.
|
|
454
459
|
|
|
455
460
|
#### 🎯 uniform[kind](name, options?)
|
|
456
461
|
|
|
@@ -543,15 +548,19 @@ const vertexShader = glsl`
|
|
|
543
548
|
|
|
544
549
|
### ⚙️ compile(gl, vertex, fragment, overrideSchema?)
|
|
545
550
|
|
|
546
|
-
Compiles shaders
|
|
551
|
+
Compiles shaders to a `WebGLProgram` and extracts typesafe schema and view.
|
|
547
552
|
|
|
548
553
|
```typescript
|
|
549
|
-
const { program, schema, view } = compile(gl, vertexShader, fragmentShader)
|
|
554
|
+
const { program, schema, view, vertex, fragment } = compile(gl, vertexShader, fragmentShader)
|
|
550
555
|
|
|
551
556
|
// Use the view directly
|
|
552
557
|
view.uniforms.time.set(performance.now())
|
|
553
558
|
view.attributes.position.set(vertexData).bind()
|
|
554
559
|
|
|
560
|
+
// Access the compiled shader strings
|
|
561
|
+
console.log(vertex) // Compiled vertex shader GLSL
|
|
562
|
+
console.log(fragment) // Compiled fragment shader GLSL
|
|
563
|
+
|
|
555
564
|
// Or access the extracted schema
|
|
556
565
|
console.log(schema.uniforms) // { time: { kind: 'float' }, ... }
|
|
557
566
|
console.log(schema.attributes) // { position: { kind: 'vec3' }, ... }
|
|
@@ -583,6 +592,8 @@ view.buffers.indices.set(indexData).bind()
|
|
|
583
592
|
- `program`: Compiled WebGL program
|
|
584
593
|
- `schema`: Merged schema (extracted + override)
|
|
585
594
|
- `view`: Ready-to-use view with type-safe resource access
|
|
595
|
+
- `vertex`: Compiled vertex shader GLSL string
|
|
596
|
+
- `fragment`: Compiled fragment shader GLSL string
|
|
586
597
|
|
|
587
598
|
#### 🔍 compile.toString(shader)
|
|
588
599
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
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-
|
|
2
|
-
export { v as AttributeDefinition, u as AttributeKind, w as AttributeMethods, t as AttributeShortHand, a1 as
|
|
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-Bp9VAVe3.mjs';
|
|
2
|
+
export { v as AttributeDefinition, u as AttributeKind, w as AttributeMethods, t as AttributeShortHand, a1 as AttributeToken, a2 as AttributeTokenFn, C as BufferDefinition, D as BufferMethods, a8 as CompileResult, R as Format, E as Framebuffer, F as FramebufferDefinition, _ as GLSL, Y as GLSLResult, Z as GLSLSlot, a6 as GLSLSlotsToSchema, a4 as GLSLToSchema, a5 as GLSLToView, g as GLTarget, l as GLTextureFilter, j as GLTextureFormat, i as GLTextureTarget, k as GLTextureType, m as GLTextureWrap, h as GLUsage, a3 as InterleaveToken, y as InterleavedAttributeDefinition, x as InterleavedAttributeLayout, z as InterleavedAttributeMethods, Q as InternalFormat, n as KIND_TO_SIZE_MAP, K as KIND_TO_UNIFORM_FN_NAME_MAP, a7 as MergeGLSLSchema, S as PixelType, W as TexImage2DOptions, T as TextureDefinition, L as TextureMethods, N as TextureParameterName, O as TextureParameterValue, P as TextureParameters, J as TextureSchema, H as TextureTarget, M as TextureView, q as UniformDefinition, o as UniformFnName, p as UniformKind, s as UniformMethods, r as UniformSchemaPartial, $ as UniformToken, a0 as UniformTokenFn, X as ViewSchemaPartial } from './types-Bp9VAVe3.mjs';
|
|
3
3
|
|
|
4
4
|
declare function toID(key: string | number | symbol): any;
|
|
5
5
|
/**********************************************************************************/
|
package/dist/tag.d.mts
CHANGED
|
@@ -1,81 +1,81 @@
|
|
|
1
|
-
import { Z as GLSLSlot, _ as
|
|
1
|
+
import { Z as GLSLSlot, _ as GLSL, a0 as UniformTokenFn, a2 as AttributeTokenFn, a1 as AttributeToken, u as AttributeKind, v as AttributeDefinition, a3 as InterleaveToken, X as ViewSchemaPartial, a9 as Prettify, a8 as CompileResult, a4 as GLSLToSchema } from './types-Bp9VAVe3.mjs';
|
|
2
2
|
|
|
3
|
-
declare function glsl<TSlot extends GLSLSlot, TSlots extends TSlot[]>(template: TemplateStringsArray, ...slots: [...TSlots]):
|
|
3
|
+
declare function glsl<TSlot extends GLSLSlot, TSlots extends TSlot[]>(template: TemplateStringsArray, ...slots: [...TSlots]): GLSL<TSlots>;
|
|
4
4
|
declare const uniform: {
|
|
5
|
-
float:
|
|
6
|
-
vec2:
|
|
7
|
-
vec3:
|
|
8
|
-
vec4:
|
|
9
|
-
int:
|
|
10
|
-
ivec2:
|
|
11
|
-
ivec3:
|
|
12
|
-
ivec4:
|
|
13
|
-
bool:
|
|
14
|
-
bvec2:
|
|
15
|
-
bvec3:
|
|
16
|
-
bvec4:
|
|
17
|
-
mat2:
|
|
18
|
-
mat3:
|
|
19
|
-
mat4:
|
|
20
|
-
sampler2D:
|
|
21
|
-
samplerCube:
|
|
22
|
-
uint:
|
|
23
|
-
uvec2:
|
|
24
|
-
uvec3:
|
|
25
|
-
uvec4:
|
|
26
|
-
mat2x3:
|
|
27
|
-
mat2x4:
|
|
28
|
-
mat3x2:
|
|
29
|
-
mat3x4:
|
|
30
|
-
mat4x2:
|
|
31
|
-
mat4x3:
|
|
32
|
-
sampler3D:
|
|
33
|
-
sampler2DArray:
|
|
34
|
-
sampler2DShadow:
|
|
35
|
-
samplerCubeShadow:
|
|
36
|
-
sampler2DArrayShadow:
|
|
37
|
-
isampler2D:
|
|
38
|
-
isampler3D:
|
|
39
|
-
isamplerCube:
|
|
40
|
-
isampler2DArray:
|
|
41
|
-
usampler2D:
|
|
42
|
-
usampler3D:
|
|
43
|
-
usamplerCube:
|
|
44
|
-
usampler2DArray:
|
|
5
|
+
float: UniformTokenFn<"float">;
|
|
6
|
+
vec2: UniformTokenFn<"vec2">;
|
|
7
|
+
vec3: UniformTokenFn<"vec3">;
|
|
8
|
+
vec4: UniformTokenFn<"vec4">;
|
|
9
|
+
int: UniformTokenFn<"int">;
|
|
10
|
+
ivec2: UniformTokenFn<"ivec2">;
|
|
11
|
+
ivec3: UniformTokenFn<"ivec3">;
|
|
12
|
+
ivec4: UniformTokenFn<"ivec4">;
|
|
13
|
+
bool: UniformTokenFn<"bool">;
|
|
14
|
+
bvec2: UniformTokenFn<"bvec2">;
|
|
15
|
+
bvec3: UniformTokenFn<"bvec3">;
|
|
16
|
+
bvec4: UniformTokenFn<"bvec4">;
|
|
17
|
+
mat2: UniformTokenFn<"mat2">;
|
|
18
|
+
mat3: UniformTokenFn<"mat3">;
|
|
19
|
+
mat4: UniformTokenFn<"mat4">;
|
|
20
|
+
sampler2D: UniformTokenFn<"sampler2D">;
|
|
21
|
+
samplerCube: UniformTokenFn<"samplerCube">;
|
|
22
|
+
uint: UniformTokenFn<"uint">;
|
|
23
|
+
uvec2: UniformTokenFn<"uvec2">;
|
|
24
|
+
uvec3: UniformTokenFn<"uvec3">;
|
|
25
|
+
uvec4: UniformTokenFn<"uvec4">;
|
|
26
|
+
mat2x3: UniformTokenFn<"mat2x3">;
|
|
27
|
+
mat2x4: UniformTokenFn<"mat2x4">;
|
|
28
|
+
mat3x2: UniformTokenFn<"mat3x2">;
|
|
29
|
+
mat3x4: UniformTokenFn<"mat3x4">;
|
|
30
|
+
mat4x2: UniformTokenFn<"mat4x2">;
|
|
31
|
+
mat4x3: UniformTokenFn<"mat4x3">;
|
|
32
|
+
sampler3D: UniformTokenFn<"sampler3D">;
|
|
33
|
+
sampler2DArray: UniformTokenFn<"sampler2DArray">;
|
|
34
|
+
sampler2DShadow: UniformTokenFn<"sampler2DShadow">;
|
|
35
|
+
samplerCubeShadow: UniformTokenFn<"samplerCubeShadow">;
|
|
36
|
+
sampler2DArrayShadow: UniformTokenFn<"sampler2DArrayShadow">;
|
|
37
|
+
isampler2D: UniformTokenFn<"isampler2D">;
|
|
38
|
+
isampler3D: UniformTokenFn<"isampler3D">;
|
|
39
|
+
isamplerCube: UniformTokenFn<"isamplerCube">;
|
|
40
|
+
isampler2DArray: UniformTokenFn<"isampler2DArray">;
|
|
41
|
+
usampler2D: UniformTokenFn<"usampler2D">;
|
|
42
|
+
usampler3D: UniformTokenFn<"usampler3D">;
|
|
43
|
+
usamplerCube: UniformTokenFn<"usamplerCube">;
|
|
44
|
+
usampler2DArray: UniformTokenFn<"usampler2DArray">;
|
|
45
45
|
};
|
|
46
46
|
declare const attribute: {
|
|
47
|
-
float:
|
|
48
|
-
vec2:
|
|
49
|
-
vec3:
|
|
50
|
-
vec4:
|
|
51
|
-
int:
|
|
52
|
-
ivec2:
|
|
53
|
-
ivec3:
|
|
54
|
-
ivec4:
|
|
55
|
-
mat2:
|
|
56
|
-
mat3:
|
|
57
|
-
mat4:
|
|
58
|
-
uint:
|
|
59
|
-
uvec2:
|
|
60
|
-
uvec3:
|
|
61
|
-
uvec4:
|
|
62
|
-
mat2x3:
|
|
63
|
-
mat2x4:
|
|
64
|
-
mat3x2:
|
|
65
|
-
mat3x4:
|
|
66
|
-
mat4x2:
|
|
67
|
-
mat4x3:
|
|
47
|
+
float: AttributeTokenFn<"float">;
|
|
48
|
+
vec2: AttributeTokenFn<"vec2">;
|
|
49
|
+
vec3: AttributeTokenFn<"vec3">;
|
|
50
|
+
vec4: AttributeTokenFn<"vec4">;
|
|
51
|
+
int: AttributeTokenFn<"int">;
|
|
52
|
+
ivec2: AttributeTokenFn<"ivec2">;
|
|
53
|
+
ivec3: AttributeTokenFn<"ivec3">;
|
|
54
|
+
ivec4: AttributeTokenFn<"ivec4">;
|
|
55
|
+
mat2: AttributeTokenFn<"mat2">;
|
|
56
|
+
mat3: AttributeTokenFn<"mat3">;
|
|
57
|
+
mat4: AttributeTokenFn<"mat4">;
|
|
58
|
+
uint: AttributeTokenFn<"uint">;
|
|
59
|
+
uvec2: AttributeTokenFn<"uvec2">;
|
|
60
|
+
uvec3: AttributeTokenFn<"uvec3">;
|
|
61
|
+
uvec4: AttributeTokenFn<"uvec4">;
|
|
62
|
+
mat2x3: AttributeTokenFn<"mat2x3">;
|
|
63
|
+
mat2x4: AttributeTokenFn<"mat2x4">;
|
|
64
|
+
mat3x2: AttributeTokenFn<"mat3x2">;
|
|
65
|
+
mat3x4: AttributeTokenFn<"mat3x4">;
|
|
66
|
+
mat4x2: AttributeTokenFn<"mat4x2">;
|
|
67
|
+
mat4x3: AttributeTokenFn<"mat4x3">;
|
|
68
68
|
};
|
|
69
|
-
declare function interleave<const TKey extends string | symbol, const TLayout extends Array<
|
|
70
|
-
declare function interleave<const TKey extends string | symbol, const TLayout extends Array<
|
|
69
|
+
declare function interleave<const TKey extends string | symbol, const TLayout extends Array<AttributeToken<string | symbol, AttributeKind, undefined>>, const TOptions extends Omit<AttributeDefinition, 'kind'>>(key: TKey, layout: TLayout, instanced: TOptions): InterleaveToken<TKey, TLayout, TOptions>;
|
|
70
|
+
declare function interleave<const TKey extends string | symbol, const TLayout extends Array<AttributeToken<string | symbol, AttributeKind, undefined>>>(key: TKey, layout: TLayout): InterleaveToken<TKey, TLayout, {
|
|
71
71
|
instanced: false;
|
|
72
72
|
}>;
|
|
73
73
|
/**********************************************************************************/
|
|
74
74
|
/**********************************************************************************/
|
|
75
|
-
declare function compile<TVertex extends
|
|
75
|
+
declare function compile<TVertex extends GLSL, TFragment extends GLSL, TOverride extends ViewSchemaPartial>(gl: WebGLRenderingContext, vertex: TVertex, fragment: TFragment, overrideSchema?: TOverride): Prettify<CompileResult<TVertex, TFragment, TOverride>>;
|
|
76
76
|
declare namespace compile {
|
|
77
|
-
var toSchema: <TTag extends
|
|
78
|
-
var toString: <TTag extends
|
|
77
|
+
var toSchema: <TTag extends GLSL>(tag: TTag) => Prettify<GLSLToSchema<TTag>>;
|
|
78
|
+
var toString: <TTag extends GLSL>({ template: [initial, ...rest], slots }: TTag) => string;
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
export { attribute, compile, glsl, interleave, uniform };
|
package/dist/tag.mjs
CHANGED
|
@@ -424,7 +424,9 @@ function compile(gl, vertex, fragment, overrideSchema) {
|
|
|
424
424
|
return {
|
|
425
425
|
program,
|
|
426
426
|
schema,
|
|
427
|
-
view: view(gl, program, schema)
|
|
427
|
+
view: view(gl, program, schema),
|
|
428
|
+
vertex: _vertex.template,
|
|
429
|
+
fragment: _fragment.template
|
|
428
430
|
};
|
|
429
431
|
}
|
|
430
432
|
function resolveGLSLTag(tag) {
|
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 { RemoveSuffix } from './type-utils'\nimport type { GL } 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 FramebufferDefinition,\n GL,\n KIND_TO_SIZE_MAP,\n KIND_TO_UNIFORM_FN_NAME_MAP,\n TextureDefinition,\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 }: TextureDefinition,\n data?: ArrayBufferView | null,\n): WebGLTexture {\n const texture = gl.createTexture()\n\n function getTextureConstant(name: string) {\n if (!(name in gl)) {\n throw new Error(`Attempted to create webgl2-only texture (${name}) in webgl1`)\n }\n return gl[name as keyof typeof gl] as any\n }\n\n gl.bindTexture(gl[target], texture)\n gl.texImage2D(\n gl[target],\n 0,\n getTextureConstant(internalFormat),\n width,\n height,\n 0,\n getTextureConstant(format),\n getTextureConstant(type),\n data ?? null,\n )\n\n console.log(minFilter)\n // Set texture parameters\n gl.texParameteri(gl[target], gl.TEXTURE_MIN_FILTER, gl[minFilter])\n gl.texParameteri(gl[target], gl.TEXTURE_MAG_FILTER, gl[magFilter])\n gl.texParameteri(gl[target], gl.TEXTURE_WRAP_S, gl[wrapS])\n gl.texParameteri(gl[target], gl.TEXTURE_WRAP_T, gl[wrapT])\n\n return texture\n}\n\n/**********************************************************************************/\n/* */\n/* Create Framebuffer */\n/* */\n/**********************************************************************************/\n\nconst FRAMEBUFFER_ATTACHMENT_MAP = {\n color: 'COLOR_ATTACHMENT0',\n depth: 'DEPTH_ATTACHMENT',\n stencil: 'STENCIL_ATTACHMENT',\n depthStencil: 'DEPTH_STENCIL_ATTACHMENT',\n} as const\n\nclass FramebufferError extends Error {\n constructor(gl: GL, status: number) {\n let errorMessage = `Framebuffer '${name}' not complete. Status: `\n switch (status) {\n case gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:\n errorMessage += 'FRAMEBUFFER_INCOMPLETE_ATTACHMENT'\n break\n case gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:\n errorMessage += 'FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT'\n break\n case gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:\n errorMessage += 'FRAMEBUFFER_INCOMPLETE_DIMENSIONS'\n break\n case gl.FRAMEBUFFER_UNSUPPORTED:\n errorMessage += 'FRAMEBUFFER_UNSUPPORTED'\n break\n default:\n errorMessage += `Unknown (${status})`\n }\n super(errorMessage)\n }\n}\n\nexport function createFramebuffer(\n gl: GL,\n { attachment, texture, ...options }: FramebufferDefinition,\n) {\n // Create texture for the framebuffer\n texture ??= createTexture(gl, options)\n\n // Create framebuffer\n const framebuffer = assertedNotNullish(\n gl.createFramebuffer(),\n `Failed to create framebuffer: ${name}`,\n )\n\n gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer)\n\n gl.framebufferTexture2D(\n gl.FRAMEBUFFER,\n // Determine attachment point based on attachment kind\n gl[FRAMEBUFFER_ATTACHMENT_MAP[attachment]],\n gl.TEXTURE_2D,\n texture,\n 0,\n )\n\n // Check framebuffer completeness\n const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER)\n if (status !== gl.FRAMEBUFFER_COMPLETE) {\n throw new FramebufferError(gl, status)\n }\n\n return {\n texture,\n framebuffer,\n }\n}\n\n/**********************************************************************************/\n/* */\n/* Create Upsert */\n/* */\n/**********************************************************************************/\n\ntype UpsertMapKind<T, U> = Map<T, U> | (T extends WeakKey ? WeakMap<T, U> : never)\n\nexport function createUpsertMap<T extends UpsertMapKind<any, any> = Map<any, any>>(\n constructor?: new () => T,\n) {\n const map = new (constructor ?? Map)() as T\n return Object.assign(map, {\n getOrInsert(\n key: T extends UpsertMapKind<infer U, any> ? U : never,\n value: T extends UpsertMapKind<any, infer U> ? () => U : never,\n ) {\n let result = map.get(key)\n if (result) {\n return result\n }\n result = value()\n map.set(key, result)\n return result\n },\n })\n}\n","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'\nexport * from './types'\n\n/**********************************************************************************/\n/* */\n/* To ID */\n/* */\n/**********************************************************************************/\n\nlet index = 0\nconst PREFIX = 'VIEW_GL_ALIAS'\nconst IS_FIREFOX = navigator.userAgent.toLowerCase().indexOf('firefox') >= 0\n\n// NOTE: using symbol as key for WeakMap is currently broken in firefox\n// see https://bugzilla.mozilla.org/show_bug.cgi?id=1710433\n// fallback to Map will currently cause a memory leak.\nconst SYMBOL_MAP = createUpsertMap(IS_FIREFOX ? Map<symbol, string> : 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 { Prettify } from './type-utils'\nimport type {\n AttributeDefinition,\n AttributeKind,\n AttributeTag,\n AttributeTagFn as AttributeTagMethod,\n CompileResult,\n GLSLSlot,\n GLSLTag,\n GLSLTagToSchema,\n InterleaveTag,\n UniformDefinition,\n UniformKind,\n UniformTagFn as UniformTagMethod,\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<UniformDefinition, 'kind'>) => ({\n type: 'uniform',\n key,\n kind: property,\n ...options,\n })\n },\n },\n)\n\nexport const attribute = new Proxy(\n {} as {\n [TKey in AttributeKind]: AttributeTagMethod<TKey>\n },\n {\n get(target, property) {\n // @ts-expect-error\n if (typeof property === 'symbol') return target[property]\n return (key: string, options?: Omit<AttributeDefinition, 'kind'>) => ({\n type: 'attribute',\n key,\n kind: property,\n ...options,\n })\n },\n },\n)\n\nexport function interleave<\n const TKey extends string | symbol,\n const TLayout extends Array<AttributeTag<string | symbol, AttributeKind, undefined>>,\n const TOptions extends Omit<AttributeDefinition, '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<AttributeDefinition, 'kind'>,\n>(key: TKey, layout: TLayout, { instanced, buffer }: Partial<TOptions> = {}) {\n return {\n type: 'interleavedAttribute',\n key,\n // remove instanced- and type-property\n layout: layout.map(({ key, kind }) => ({\n key,\n kind,\n })),\n instanced: !!instanced,\n buffer,\n } as unknown as InterleaveTag<TKey, TLayout, TOptions>\n}\n\n/**********************************************************************************/\n/* */\n/* Compile */\n/* */\n/**********************************************************************************/\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) as { template: string; schema: ViewSchema }\n const _fragment = resolveGLSLTag(fragment) as { template: string; schema: ViewSchema }\n\n const schema = {\n uniforms: {\n ..._vertex.schema.uniforms,\n ..._fragment.schema.uniforms,\n },\n attributes: {\n ..._vertex.schema.attributes,\n ..._fragment.schema.attributes,\n },\n interleavedAttributes: {\n ..._vertex.schema.interleavedAttributes,\n ..._fragment.schema.interleavedAttributes,\n },\n }\n\n 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 schemaKind[key] = {\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 Prettify<CompileResult<TVertex, TFragment, TOverride>>\n}\n\nfunction resolveGLSLTag<TTag extends GLSLTag>(tag: TTag) {\n return {\n template: compile.toString(tag),\n schema: compile.toSchema(tag),\n }\n}\n\ncompile.toSchema = function <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 } = compile.toSchema(slot)\n\n result.uniforms = {\n ...result.uniforms,\n ...uniforms,\n }\n result.attributes = {\n ...result.attributes,\n ...attributes,\n }\n result.interleavedAttributes = {\n ...result.interleavedAttributes,\n ...interleavedAttributes,\n }\n\n return\n }\n\n const { key: name, type, ...rest } = slot\n\n // @ts-expect-error\n result[`${type}s`][name] = rest\n }\n\n tag.slots.forEach(handleSlot)\n\n return result as unknown as Prettify<GLSLTagToSchema<TTag>>\n}\n\ncompile.toString = function <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 compile.toString(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","slot"]}
|
|
1
|
+
{"version":3,"sources":["../src/features.ts","../src/utils/object.ts","../src/utils/index.ts","../src/index.ts","../src/tag.ts"],"sourcesContent":["import { RemoveSuffix } from './type-utils'\nimport type { GL } 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 FramebufferDefinition,\n GL,\n KIND_TO_SIZE_MAP,\n KIND_TO_UNIFORM_FN_NAME_MAP,\n TextureDefinition,\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 }: TextureDefinition,\n data?: ArrayBufferView | null,\n): WebGLTexture {\n const texture = gl.createTexture()\n\n function getTextureConstant(name: string) {\n if (!(name in gl)) {\n throw new Error(`Attempted to create webgl2-only texture (${name}) in webgl1`)\n }\n return gl[name as keyof typeof gl] as any\n }\n\n gl.bindTexture(gl[target], texture)\n gl.texImage2D(\n gl[target],\n 0,\n getTextureConstant(internalFormat),\n width,\n height,\n 0,\n getTextureConstant(format),\n getTextureConstant(type),\n data ?? null,\n )\n\n console.log(minFilter)\n // Set texture parameters\n gl.texParameteri(gl[target], gl.TEXTURE_MIN_FILTER, gl[minFilter])\n gl.texParameteri(gl[target], gl.TEXTURE_MAG_FILTER, gl[magFilter])\n gl.texParameteri(gl[target], gl.TEXTURE_WRAP_S, gl[wrapS])\n gl.texParameteri(gl[target], gl.TEXTURE_WRAP_T, gl[wrapT])\n\n return texture\n}\n\n/**********************************************************************************/\n/* */\n/* Create Framebuffer */\n/* */\n/**********************************************************************************/\n\nconst FRAMEBUFFER_ATTACHMENT_MAP = {\n color: 'COLOR_ATTACHMENT0',\n depth: 'DEPTH_ATTACHMENT',\n stencil: 'STENCIL_ATTACHMENT',\n depthStencil: 'DEPTH_STENCIL_ATTACHMENT',\n} as const\n\nclass FramebufferError extends Error {\n constructor(gl: GL, status: number) {\n let errorMessage = `Framebuffer '${name}' not complete. Status: `\n switch (status) {\n case gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:\n errorMessage += 'FRAMEBUFFER_INCOMPLETE_ATTACHMENT'\n break\n case gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:\n errorMessage += 'FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT'\n break\n case gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:\n errorMessage += 'FRAMEBUFFER_INCOMPLETE_DIMENSIONS'\n break\n case gl.FRAMEBUFFER_UNSUPPORTED:\n errorMessage += 'FRAMEBUFFER_UNSUPPORTED'\n break\n default:\n errorMessage += `Unknown (${status})`\n }\n super(errorMessage)\n }\n}\n\nexport function createFramebuffer(\n gl: GL,\n { attachment, texture, ...options }: FramebufferDefinition,\n) {\n // Create texture for the framebuffer\n texture ??= createTexture(gl, options)\n\n // Create framebuffer\n const framebuffer = assertedNotNullish(\n gl.createFramebuffer(),\n `Failed to create framebuffer: ${name}`,\n )\n\n gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer)\n\n gl.framebufferTexture2D(\n gl.FRAMEBUFFER,\n // Determine attachment point based on attachment kind\n gl[FRAMEBUFFER_ATTACHMENT_MAP[attachment]],\n gl.TEXTURE_2D,\n texture,\n 0,\n )\n\n // Check framebuffer completeness\n const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER)\n if (status !== gl.FRAMEBUFFER_COMPLETE) {\n throw new FramebufferError(gl, status)\n }\n\n return {\n texture,\n framebuffer,\n }\n}\n\n/**********************************************************************************/\n/* */\n/* Create Upsert */\n/* */\n/**********************************************************************************/\n\ntype UpsertMapKind<T, U> = Map<T, U> | (T extends WeakKey ? WeakMap<T, U> : never)\n\nexport function createUpsertMap<T extends UpsertMapKind<any, any> = Map<any, any>>(\n constructor?: new () => T,\n) {\n const map = new (constructor ?? Map)() as T\n return Object.assign(map, {\n getOrInsert(\n key: T extends UpsertMapKind<infer U, any> ? U : never,\n value: T extends UpsertMapKind<any, infer U> ? () => U : never,\n ) {\n let result = map.get(key)\n if (result) {\n return result\n }\n result = value()\n map.set(key, result)\n return result\n },\n })\n}\n","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'\nexport * from './types'\n\n/**********************************************************************************/\n/* */\n/* To ID */\n/* */\n/**********************************************************************************/\n\nlet index = 0\nconst PREFIX = 'VIEW_GL_ALIAS'\nconst IS_FIREFOX = navigator.userAgent.toLowerCase().indexOf('firefox') >= 0\n\n// NOTE: using symbol as key for WeakMap is currently broken in firefox\n// see https://bugzilla.mozilla.org/show_bug.cgi?id=1710433\n// fallback to Map will currently cause a memory leak.\nconst SYMBOL_MAP = createUpsertMap(IS_FIREFOX ? Map<symbol, string> : 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 { Prettify } from './type-utils'\nimport type {\n AttributeDefinition,\n AttributeKind,\n AttributeTokenFn as AttributeTagMethod,\n AttributeToken,\n CompileResult,\n GLSL,\n GLSLSlot,\n GLSLToSchema,\n InterleaveToken,\n UniformDefinition,\n UniformKind,\n UniformTokenFn as UniformTagMethod,\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): GLSL<TSlots> {\n return { template, slots, type: 'glsl' }\n}\n\nexport const uniform = new Proxy(\n {} as {\n [TKey in UniformKind]: UniformTagMethod<TKey>\n },\n {\n get(target, property) {\n // @ts-expect-error\n if (typeof property === 'symbol') return target[property]\n return (key: string, options?: Omit<UniformDefinition, 'kind'>) => ({\n type: 'uniform',\n key,\n kind: property,\n ...options,\n })\n },\n },\n)\n\nexport const attribute = new Proxy(\n {} as {\n [TKey in AttributeKind]: AttributeTagMethod<TKey>\n },\n {\n get(target, property) {\n // @ts-expect-error\n if (typeof property === 'symbol') return target[property]\n return (key: string, options?: Omit<AttributeDefinition, 'kind'>) => ({\n type: 'attribute',\n key,\n kind: property,\n ...options,\n })\n },\n },\n)\n\nexport function interleave<\n const TKey extends string | symbol,\n const TLayout extends Array<AttributeToken<string | symbol, AttributeKind, undefined>>,\n const TOptions extends Omit<AttributeDefinition, 'kind'>,\n>(key: TKey, layout: TLayout, instanced: TOptions): InterleaveToken<TKey, TLayout, TOptions>\nexport function interleave<\n const TKey extends string | symbol,\n const TLayout extends Array<AttributeToken<string | symbol, AttributeKind, undefined>>,\n>(key: TKey, layout: TLayout): InterleaveToken<TKey, TLayout, { instanced: false }>\nexport function interleave<\n const TKey extends string | symbol,\n const TLayout extends Array<AttributeToken<string | symbol, AttributeKind, undefined>>,\n const TOptions extends Omit<AttributeDefinition, 'kind'>,\n>(key: TKey, layout: TLayout, { instanced, buffer }: Partial<TOptions> = {}) {\n return {\n type: 'interleavedAttribute',\n key,\n // remove instanced- and type-property\n layout: layout.map(({ key, kind }) => ({\n key,\n kind,\n })),\n instanced: !!instanced,\n buffer,\n } as unknown as InterleaveToken<TKey, TLayout, TOptions>\n}\n\n/**********************************************************************************/\n/* */\n/* Compile */\n/* */\n/**********************************************************************************/\n\nexport function compile<\n TVertex extends GLSL,\n TFragment extends GLSL,\n TOverride extends ViewSchemaPartial,\n>(gl: WebGLRenderingContext, vertex: TVertex, fragment: TFragment, overrideSchema?: TOverride) {\n const _vertex = resolveGLSLTag(vertex) as { template: string; schema: ViewSchema }\n const _fragment = resolveGLSLTag(fragment) as { template: string; schema: ViewSchema }\n\n const schema = {\n uniforms: {\n ..._vertex.schema.uniforms,\n ..._fragment.schema.uniforms,\n },\n attributes: {\n ..._vertex.schema.attributes,\n ..._fragment.schema.attributes,\n },\n interleavedAttributes: {\n ..._vertex.schema.interleavedAttributes,\n ..._fragment.schema.interleavedAttributes,\n },\n }\n\n 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 schemaKind[key] = {\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 vertex: _vertex.template,\n fragment: _fragment.template,\n } as unknown as Prettify<CompileResult<TVertex, TFragment, TOverride>>\n}\n\nfunction resolveGLSLTag<TTag extends GLSL>(tag: TTag) {\n return {\n template: compile.toString(tag),\n schema: compile.toSchema(tag),\n }\n}\n\ncompile.toSchema = function <TTag extends GLSL>(tag: TTag) {\n const result = {\n uniforms: {},\n attributes: {},\n interleavedAttributes: {},\n }\n\n 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 } = compile.toSchema(slot)\n\n result.uniforms = {\n ...result.uniforms,\n ...uniforms,\n }\n result.attributes = {\n ...result.attributes,\n ...attributes,\n }\n result.interleavedAttributes = {\n ...result.interleavedAttributes,\n ...interleavedAttributes,\n }\n\n return\n }\n\n const { key: name, type, ...rest } = slot\n\n // @ts-expect-error\n result[`${type}s`][name] = rest\n }\n\n tag.slots.forEach(handleSlot)\n\n return result as unknown as Prettify<GLSLToSchema<TTag>>\n}\n\ncompile.toString = function <TTag extends GLSL>({ 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 compile.toString(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":";;;;;;;AAGA,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;;;AC3DA;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;AA4I3E,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;;;ACnQA,IAAI,QAAQ;AACZ,IAAM,SAAS;AACf,IAAM,aAAa,UAAU,UAAU,YAAY,EAAE,QAAQ,SAAS,KAAK;AAK3E,IAAM,aAAa,gBAAgB,aAAa,MAAsB,OAAuB;AAEtF,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;;;AC/TO,SAAS,KACd,aACG,OACW;AACd,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,aAA+C;AAAA,QAClE,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,aAAiD;AAAA,QACpE,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;AAQO,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;AACpC,iBAAW,GAAG,IAAI;AAAA,QAChB,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,IAC9B,QAAQ,QAAQ;AAAA,IAChB,UAAU,UAAU;AAAA,EACtB;AACF;AAEA,SAAS,eAAkC,KAAW;AACpD,SAAO;AAAA,IACL,UAAU,QAAQ,SAAS,GAAG;AAAA,IAC9B,QAAQ,QAAQ,SAAS,GAAG;AAAA,EAC9B;AACF;AAEA,QAAQ,WAAW,SAA6B,KAAW;AACzD,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,QAAQ,SAAS,IAAI;AAE7E,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;AAEA,QAAQ,WAAW,SAA6B,EAAE,UAAU,CAAC,SAAS,GAAG,IAAI,GAAG,MAAM,GAAS;AAC7F,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,QAAQ,SAAS,IAAI;AAAA,EAC9B;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"]}
|
|
@@ -389,10 +389,10 @@ interface ViewSchemaPartial {
|
|
|
389
389
|
buffers?: Record<string | symbol, Partial<BufferDefinition>>;
|
|
390
390
|
}
|
|
391
391
|
type View<T extends ViewSchema = ViewSchema> = {
|
|
392
|
-
attributes: T['attributes'] extends AttributeSchema ? AttributeView<T['attributes']
|
|
393
|
-
interleavedAttributes: T['interleavedAttributes'] extends InterleavedAttributeSchema ? InterleavedAttributeView<T['interleavedAttributes']
|
|
394
|
-
buffers: T['buffers'] extends BufferSchema ? BufferView<T['buffers']
|
|
395
|
-
uniforms: T['uniforms'] extends UniformSchema ? UniformView<T['uniforms']
|
|
392
|
+
attributes: T['attributes'] extends AttributeSchema ? Prettify<AttributeView<T['attributes']>> : never;
|
|
393
|
+
interleavedAttributes: T['interleavedAttributes'] extends InterleavedAttributeSchema ? Prettify<InterleavedAttributeView<T['interleavedAttributes']>> : never;
|
|
394
|
+
buffers: T['buffers'] extends BufferSchema ? Prettify<BufferView<T['buffers']>> : never;
|
|
395
|
+
uniforms: T['uniforms'] extends UniformSchema ? Prettify<UniformView<T['uniforms']>> : never;
|
|
396
396
|
};
|
|
397
397
|
/**********************************************************************************/
|
|
398
398
|
/**********************************************************************************/
|
|
@@ -400,14 +400,14 @@ interface GLSLResult {
|
|
|
400
400
|
program: WebGLProgram;
|
|
401
401
|
schema: ViewSchema;
|
|
402
402
|
}
|
|
403
|
-
type GLSLSlotItem =
|
|
403
|
+
type GLSLSlotItem = GLSL | UniformToken | AttributeToken | InterleaveToken | string | number | symbol;
|
|
404
404
|
type GLSLSlot = GLSLSlotItem | Array<GLSLSlotItem>;
|
|
405
|
-
interface
|
|
405
|
+
interface GLSL<TSlots extends GLSLSlot[] = GLSLSlot[]> {
|
|
406
406
|
type: 'glsl';
|
|
407
407
|
template: TemplateStringsArray;
|
|
408
408
|
slots: TSlots;
|
|
409
409
|
}
|
|
410
|
-
type
|
|
410
|
+
type UniformToken<TKey extends string | symbol = string | symbol, TKind extends UniformKind = UniformKind, TDefinition extends Partial<UniformDefinition> = UniformDefinition> = TDefinition extends {
|
|
411
411
|
size: infer TSize;
|
|
412
412
|
} ? {
|
|
413
413
|
type: 'uniform';
|
|
@@ -419,41 +419,42 @@ type UniformTag<TKey extends string | symbol = string | symbol, TKind extends Un
|
|
|
419
419
|
kind: TKind;
|
|
420
420
|
key: TKey;
|
|
421
421
|
};
|
|
422
|
-
interface
|
|
423
|
-
<const TKey extends string | symbol, const TDefinition extends Omit<UniformDefinition, 'kind'>>(key: TKey, TDefinition: TDefinition): Prettify<
|
|
424
|
-
<const TName extends string | symbol>(key: TName): Prettify<
|
|
422
|
+
interface UniformTokenFn<TKind extends UniformKind> {
|
|
423
|
+
<const TKey extends string | symbol, const TDefinition extends Omit<UniformDefinition, 'kind'>>(key: TKey, TDefinition: TDefinition): Prettify<UniformToken<TKey, TKind, TDefinition>>;
|
|
424
|
+
<const TName extends string | symbol>(key: TName): Prettify<UniformToken<TName, TKind>>;
|
|
425
425
|
}
|
|
426
|
-
interface
|
|
426
|
+
interface AttributeToken<TKey extends string | symbol = string | symbol, TKind extends AttributeKind = AttributeKind, TInstanced extends boolean | undefined = boolean | undefined> {
|
|
427
427
|
type: 'attribute';
|
|
428
428
|
kind: TKind;
|
|
429
429
|
instanced: TInstanced;
|
|
430
430
|
key: TKey;
|
|
431
431
|
}
|
|
432
|
-
interface
|
|
433
|
-
<TName extends string | symbol, TDefinition extends Omit<AttributeDefinition, 'kind'>>(key: TName, options: TDefinition): Prettify<
|
|
434
|
-
<TName extends string | symbol>(key: TName): Prettify<
|
|
432
|
+
interface AttributeTokenFn<TKey extends AttributeKind> {
|
|
433
|
+
<TName extends string | symbol, TDefinition extends Omit<AttributeDefinition, 'kind'>>(key: TName, options: TDefinition): Prettify<AttributeToken<TName, TKey, TDefinition['instanced']>>;
|
|
434
|
+
<TName extends string | symbol>(key: TName): Prettify<AttributeToken<TName, TKey, undefined>>;
|
|
435
435
|
}
|
|
436
|
-
type
|
|
436
|
+
type InterleaveToken<TKey extends string | symbol = string | symbol, TLayout extends Array<AttributeToken<string | symbol, AttributeKind, undefined>> = Array<AttributeToken<string | symbol, AttributeKind, undefined>>, TDefinition extends Omit<AttributeDefinition, 'kind'> = Omit<AttributeDefinition, 'kind'>> = TDefinition & {
|
|
437
437
|
key: TKey;
|
|
438
438
|
type: 'interleavedAttribute';
|
|
439
439
|
layout: {
|
|
440
440
|
[TKey in keyof TLayout]: Prettify<Pick<TLayout[TKey], 'kind' | 'key'>>;
|
|
441
441
|
};
|
|
442
442
|
};
|
|
443
|
-
type
|
|
443
|
+
type GLSLToSchema<T extends GLSL> = FlattenSlots<T> extends infer TSlots ? TSlots extends Array<any> ? GLSLSlotsToSchema<TSlots> : never : never;
|
|
444
|
+
type GLSLToView<T extends GLSL> = View<GLSLToSchema<T>>;
|
|
444
445
|
type GLSLSlotsToSchema<TSlots extends Array<GLSLSlot>> = {
|
|
445
446
|
uniforms: {
|
|
446
|
-
[K in Extract<TSlots[number],
|
|
447
|
+
[K in Extract<TSlots[number], UniformToken> as K['key']]: Prettify<Omit<K, 'name' | 'type'>>;
|
|
447
448
|
};
|
|
448
449
|
attributes: {
|
|
449
|
-
[K in Extract<TSlots[number],
|
|
450
|
+
[K in Extract<TSlots[number], AttributeToken> as K['key']]: Prettify<Omit<K, 'name' | 'type'>>;
|
|
450
451
|
};
|
|
451
452
|
interleavedAttributes: {
|
|
452
|
-
[K in Extract<TSlots[number],
|
|
453
|
+
[K in Extract<TSlots[number], InterleaveToken> as K['key']]: Prettify<Omit<K, 'name' | 'type'>>;
|
|
453
454
|
};
|
|
454
455
|
};
|
|
455
|
-
type FlattenSlots<T> = T extends
|
|
456
|
-
type _FlattenSlots<T extends Array<GLSLSlot>> = T extends [infer First, ...infer Rest] ? First extends
|
|
456
|
+
type FlattenSlots<T> = T extends GLSL<infer TSlots> ? _FlattenSlots<TSlots> : T extends Array<GLSLSlot> ? _FlattenSlots<T> : never;
|
|
457
|
+
type _FlattenSlots<T extends Array<GLSLSlot>> = T extends [infer First, ...infer Rest] ? First extends GLSL ? [...FlattenSlots<First>, ...FlattenSlots<Rest>] : First extends unknown[] ? [...FlattenSlots<First>, ...FlattenSlots<Rest>] : [First, ...FlattenSlots<Rest>] : [];
|
|
457
458
|
type MergeGLSLSchema<TVertex extends ViewSchema, TFragment extends ViewSchema, TOverrides extends ViewSchemaPartial = {}> = {
|
|
458
459
|
uniforms: DeepMerge<[
|
|
459
460
|
ShallowMerge<[TVertex['uniforms'], TFragment['uniforms']]>,
|
|
@@ -468,10 +469,12 @@ type MergeGLSLSchema<TVertex extends ViewSchema, TFragment extends ViewSchema, T
|
|
|
468
469
|
TOverrides['interleavedAttributes']
|
|
469
470
|
]>;
|
|
470
471
|
};
|
|
471
|
-
type CompileResult<TVertex extends
|
|
472
|
+
type CompileResult<TVertex extends GLSL, TFragment extends GLSL, TOverrideSchema extends ViewSchemaPartial> = MergeGLSLSchema<GLSLToSchema<TVertex>, GLSLToSchema<TFragment>, TOverrideSchema> extends infer TSchema extends ViewSchema ? {
|
|
472
473
|
program: WebGLProgram;
|
|
473
474
|
schema: TSchema;
|
|
474
|
-
view: View<TSchema
|
|
475
|
+
view: Prettify<View<TSchema>>;
|
|
476
|
+
vertex: string;
|
|
477
|
+
fragment: string;
|
|
475
478
|
} : never;
|
|
476
479
|
|
|
477
|
-
export type {
|
|
480
|
+
export type { UniformToken as $, AttributeSchema as A, BufferSchema as B, BufferDefinition as C, BufferMethods as D, Framebuffer as E, FramebufferDefinition as F, GL as G, TextureTarget as H, InterleavedAttributeSchema as I, TextureSchema as J, KIND_TO_UNIFORM_FN_NAME_MAP as K, TextureMethods as L, TextureView as M, TextureParameterName as N, TextureParameterValue as O, TextureParameters as P, InternalFormat as Q, Format as R, PixelType as S, TextureDefinition as T, UniformSchema as U, ViewSchema as V, TexImage2DOptions as W, ViewSchemaPartial as X, GLSLResult as Y, GLSLSlot as Z, GLSL as _, ViewOptions as a, UniformTokenFn as a0, AttributeToken as a1, AttributeTokenFn as a2, InterleaveToken as a3, GLSLToSchema as a4, GLSLToView as a5, GLSLSlotsToSchema as a6, MergeGLSLSchema as a7, CompileResult as a8, Prettify as a9, View as b, UniformView as c, AttributeView as d, InterleavedAttributeView as e, BufferView as f, GLTarget as g, GLUsage as h, GLTextureTarget as i, GLTextureFormat as j, GLTextureType as k, GLTextureFilter as l, GLTextureWrap as m, KIND_TO_SIZE_MAP as n, UniformFnName as o, UniformKind as p, UniformDefinition as q, UniformSchemaPartial as r, UniformMethods as s, AttributeShortHand as t, AttributeKind as u, AttributeDefinition as v, AttributeMethods as w, InterleavedAttributeLayout as x, InterleavedAttributeDefinition as y, InterleavedAttributeMethods as z };
|
package/package.json
CHANGED
package/src/tag.ts
CHANGED
|
@@ -3,16 +3,16 @@ import type { Prettify } from './type-utils'
|
|
|
3
3
|
import type {
|
|
4
4
|
AttributeDefinition,
|
|
5
5
|
AttributeKind,
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
AttributeTokenFn as AttributeTagMethod,
|
|
7
|
+
AttributeToken,
|
|
8
8
|
CompileResult,
|
|
9
|
+
GLSL,
|
|
9
10
|
GLSLSlot,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
InterleaveTag,
|
|
11
|
+
GLSLToSchema,
|
|
12
|
+
InterleaveToken,
|
|
13
13
|
UniformDefinition,
|
|
14
14
|
UniformKind,
|
|
15
|
-
|
|
15
|
+
UniformTokenFn as UniformTagMethod,
|
|
16
16
|
ViewSchema,
|
|
17
17
|
ViewSchemaPartial,
|
|
18
18
|
} from './types'
|
|
@@ -21,7 +21,7 @@ import { createProgram } from './utils'
|
|
|
21
21
|
export function glsl<TSlot extends GLSLSlot, TSlots extends TSlot[]>(
|
|
22
22
|
template: TemplateStringsArray,
|
|
23
23
|
...slots: [...TSlots]
|
|
24
|
-
):
|
|
24
|
+
): GLSL<TSlots> {
|
|
25
25
|
return { template, slots, type: 'glsl' }
|
|
26
26
|
}
|
|
27
27
|
|
|
@@ -63,16 +63,16 @@ export const attribute = new Proxy(
|
|
|
63
63
|
|
|
64
64
|
export function interleave<
|
|
65
65
|
const TKey extends string | symbol,
|
|
66
|
-
const TLayout extends Array<
|
|
66
|
+
const TLayout extends Array<AttributeToken<string | symbol, AttributeKind, undefined>>,
|
|
67
67
|
const TOptions extends Omit<AttributeDefinition, 'kind'>,
|
|
68
|
-
>(key: TKey, layout: TLayout, instanced: TOptions):
|
|
68
|
+
>(key: TKey, layout: TLayout, instanced: TOptions): InterleaveToken<TKey, TLayout, TOptions>
|
|
69
69
|
export function interleave<
|
|
70
70
|
const TKey extends string | symbol,
|
|
71
|
-
const TLayout extends Array<
|
|
72
|
-
>(key: TKey, layout: TLayout):
|
|
71
|
+
const TLayout extends Array<AttributeToken<string | symbol, AttributeKind, undefined>>,
|
|
72
|
+
>(key: TKey, layout: TLayout): InterleaveToken<TKey, TLayout, { instanced: false }>
|
|
73
73
|
export function interleave<
|
|
74
74
|
const TKey extends string | symbol,
|
|
75
|
-
const TLayout extends Array<
|
|
75
|
+
const TLayout extends Array<AttributeToken<string | symbol, AttributeKind, undefined>>,
|
|
76
76
|
const TOptions extends Omit<AttributeDefinition, 'kind'>,
|
|
77
77
|
>(key: TKey, layout: TLayout, { instanced, buffer }: Partial<TOptions> = {}) {
|
|
78
78
|
return {
|
|
@@ -85,7 +85,7 @@ export function interleave<
|
|
|
85
85
|
})),
|
|
86
86
|
instanced: !!instanced,
|
|
87
87
|
buffer,
|
|
88
|
-
} as unknown as
|
|
88
|
+
} as unknown as InterleaveToken<TKey, TLayout, TOptions>
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
/**********************************************************************************/
|
|
@@ -95,8 +95,8 @@ export function interleave<
|
|
|
95
95
|
/**********************************************************************************/
|
|
96
96
|
|
|
97
97
|
export function compile<
|
|
98
|
-
TVertex extends
|
|
99
|
-
TFragment extends
|
|
98
|
+
TVertex extends GLSL,
|
|
99
|
+
TFragment extends GLSL,
|
|
100
100
|
TOverride extends ViewSchemaPartial,
|
|
101
101
|
>(gl: WebGLRenderingContext, vertex: TVertex, fragment: TFragment, overrideSchema?: TOverride) {
|
|
102
102
|
const _vertex = resolveGLSLTag(vertex) as { template: string; schema: ViewSchema }
|
|
@@ -135,17 +135,19 @@ export function compile<
|
|
|
135
135
|
program,
|
|
136
136
|
schema,
|
|
137
137
|
view: view(gl, program, schema),
|
|
138
|
-
|
|
138
|
+
vertex: _vertex.template,
|
|
139
|
+
fragment: _fragment.template,
|
|
140
|
+
} as unknown as Prettify<CompileResult<TVertex, TFragment, TOverride>>
|
|
139
141
|
}
|
|
140
142
|
|
|
141
|
-
function resolveGLSLTag<TTag extends
|
|
143
|
+
function resolveGLSLTag<TTag extends GLSL>(tag: TTag) {
|
|
142
144
|
return {
|
|
143
145
|
template: compile.toString(tag),
|
|
144
146
|
schema: compile.toSchema(tag),
|
|
145
147
|
}
|
|
146
148
|
}
|
|
147
149
|
|
|
148
|
-
compile.toSchema = function <TTag extends
|
|
150
|
+
compile.toSchema = function <TTag extends GLSL>(tag: TTag) {
|
|
149
151
|
const result = {
|
|
150
152
|
uniforms: {},
|
|
151
153
|
attributes: {},
|
|
@@ -189,10 +191,10 @@ compile.toSchema = function <TTag extends GLSLTag>(tag: TTag) {
|
|
|
189
191
|
|
|
190
192
|
tag.slots.forEach(handleSlot)
|
|
191
193
|
|
|
192
|
-
return result as unknown as Prettify<
|
|
194
|
+
return result as unknown as Prettify<GLSLToSchema<TTag>>
|
|
193
195
|
}
|
|
194
196
|
|
|
195
|
-
compile.toString = function <TTag extends
|
|
197
|
+
compile.toString = function <TTag extends GLSL>({ template: [initial, ...rest], slots }: TTag) {
|
|
196
198
|
const v300 = !!initial?.startsWith('#version 300 es')
|
|
197
199
|
|
|
198
200
|
let template = initial ?? ''
|
package/src/types.ts
CHANGED
|
@@ -633,12 +633,14 @@ export interface ViewSchemaPartial {
|
|
|
633
633
|
}
|
|
634
634
|
|
|
635
635
|
export type View<T extends ViewSchema = ViewSchema> = {
|
|
636
|
-
attributes: T['attributes'] extends AttributeSchema
|
|
636
|
+
attributes: T['attributes'] extends AttributeSchema
|
|
637
|
+
? Prettify<AttributeView<T['attributes']>>
|
|
638
|
+
: never
|
|
637
639
|
interleavedAttributes: T['interleavedAttributes'] extends InterleavedAttributeSchema
|
|
638
|
-
? InterleavedAttributeView<T['interleavedAttributes']
|
|
639
|
-
:
|
|
640
|
-
buffers: T['buffers'] extends BufferSchema ? BufferView<T['buffers']
|
|
641
|
-
uniforms: T['uniforms'] extends UniformSchema ? UniformView<T['uniforms']
|
|
640
|
+
? Prettify<InterleavedAttributeView<T['interleavedAttributes']>>
|
|
641
|
+
: never
|
|
642
|
+
buffers: T['buffers'] extends BufferSchema ? Prettify<BufferView<T['buffers']>> : never
|
|
643
|
+
uniforms: T['uniforms'] extends UniformSchema ? Prettify<UniformView<T['uniforms']>> : never
|
|
642
644
|
}
|
|
643
645
|
|
|
644
646
|
/**********************************************************************************/
|
|
@@ -652,17 +654,24 @@ export interface GLSLResult {
|
|
|
652
654
|
schema: ViewSchema
|
|
653
655
|
}
|
|
654
656
|
|
|
655
|
-
type GLSLSlotItem =
|
|
657
|
+
type GLSLSlotItem =
|
|
658
|
+
| GLSL
|
|
659
|
+
| UniformToken
|
|
660
|
+
| AttributeToken
|
|
661
|
+
| InterleaveToken
|
|
662
|
+
| string
|
|
663
|
+
| number
|
|
664
|
+
| symbol
|
|
656
665
|
|
|
657
666
|
export type GLSLSlot = GLSLSlotItem | Array<GLSLSlotItem>
|
|
658
667
|
|
|
659
|
-
export interface
|
|
668
|
+
export interface GLSL<TSlots extends GLSLSlot[] = GLSLSlot[]> {
|
|
660
669
|
type: 'glsl'
|
|
661
670
|
template: TemplateStringsArray
|
|
662
671
|
slots: TSlots
|
|
663
672
|
}
|
|
664
673
|
|
|
665
|
-
export type
|
|
674
|
+
export type UniformToken<
|
|
666
675
|
TKey extends string | symbol = string | symbol,
|
|
667
676
|
TKind extends UniformKind = UniformKind,
|
|
668
677
|
TDefinition extends Partial<UniformDefinition> = UniformDefinition,
|
|
@@ -679,15 +688,15 @@ export type UniformTag<
|
|
|
679
688
|
key: TKey
|
|
680
689
|
}
|
|
681
690
|
|
|
682
|
-
export interface
|
|
691
|
+
export interface UniformTokenFn<TKind extends UniformKind> {
|
|
683
692
|
<const TKey extends string | symbol, const TDefinition extends Omit<UniformDefinition, 'kind'>>(
|
|
684
693
|
key: TKey,
|
|
685
694
|
TDefinition: TDefinition,
|
|
686
|
-
): Prettify<
|
|
687
|
-
<const TName extends string | symbol>(key: TName): Prettify<
|
|
695
|
+
): Prettify<UniformToken<TKey, TKind, TDefinition>>
|
|
696
|
+
<const TName extends string | symbol>(key: TName): Prettify<UniformToken<TName, TKind>>
|
|
688
697
|
}
|
|
689
698
|
|
|
690
|
-
export interface
|
|
699
|
+
export interface AttributeToken<
|
|
691
700
|
TKey extends string | symbol = string | symbol,
|
|
692
701
|
TKind extends AttributeKind = AttributeKind,
|
|
693
702
|
TInstanced extends boolean | undefined = boolean | undefined,
|
|
@@ -698,18 +707,18 @@ export interface AttributeTag<
|
|
|
698
707
|
key: TKey
|
|
699
708
|
}
|
|
700
709
|
|
|
701
|
-
export interface
|
|
710
|
+
export interface AttributeTokenFn<TKey extends AttributeKind> {
|
|
702
711
|
<TName extends string | symbol, TDefinition extends Omit<AttributeDefinition, 'kind'>>(
|
|
703
712
|
key: TName,
|
|
704
713
|
options: TDefinition,
|
|
705
|
-
): Prettify<
|
|
706
|
-
<TName extends string | symbol>(key: TName): Prettify<
|
|
714
|
+
): Prettify<AttributeToken<TName, TKey, TDefinition['instanced']>>
|
|
715
|
+
<TName extends string | symbol>(key: TName): Prettify<AttributeToken<TName, TKey, undefined>>
|
|
707
716
|
}
|
|
708
717
|
|
|
709
|
-
export type
|
|
718
|
+
export type InterleaveToken<
|
|
710
719
|
TKey extends string | symbol = string | symbol,
|
|
711
|
-
TLayout extends Array<
|
|
712
|
-
|
|
720
|
+
TLayout extends Array<AttributeToken<string | symbol, AttributeKind, undefined>> = Array<
|
|
721
|
+
AttributeToken<string | symbol, AttributeKind, undefined>
|
|
713
722
|
>,
|
|
714
723
|
TDefinition extends Omit<AttributeDefinition, 'kind'> = Omit<AttributeDefinition, 'kind'>,
|
|
715
724
|
> = TDefinition & {
|
|
@@ -720,34 +729,36 @@ export type InterleaveTag<
|
|
|
720
729
|
}
|
|
721
730
|
}
|
|
722
731
|
|
|
723
|
-
export type
|
|
724
|
-
FlattenSlots<
|
|
732
|
+
export type GLSLToSchema<T extends GLSL> =
|
|
733
|
+
FlattenSlots<T> extends infer TSlots
|
|
725
734
|
? TSlots extends Array<any>
|
|
726
735
|
? GLSLSlotsToSchema<TSlots>
|
|
727
736
|
: never
|
|
728
737
|
: never
|
|
729
738
|
|
|
739
|
+
export type GLSLToView<T extends GLSL> = View<GLSLToSchema<T>>
|
|
740
|
+
|
|
730
741
|
export type GLSLSlotsToSchema<TSlots extends Array<GLSLSlot>> = {
|
|
731
742
|
uniforms: {
|
|
732
|
-
[K in Extract<TSlots[number],
|
|
743
|
+
[K in Extract<TSlots[number], UniformToken> as K['key']]: Prettify<Omit<K, 'name' | 'type'>>
|
|
733
744
|
}
|
|
734
745
|
attributes: {
|
|
735
|
-
[K in Extract<TSlots[number],
|
|
746
|
+
[K in Extract<TSlots[number], AttributeToken> as K['key']]: Prettify<Omit<K, 'name' | 'type'>>
|
|
736
747
|
}
|
|
737
748
|
interleavedAttributes: {
|
|
738
|
-
[K in Extract<TSlots[number],
|
|
749
|
+
[K in Extract<TSlots[number], InterleaveToken> as K['key']]: Prettify<Omit<K, 'name' | 'type'>>
|
|
739
750
|
}
|
|
740
751
|
}
|
|
741
752
|
|
|
742
753
|
type FlattenSlots<T> =
|
|
743
|
-
T extends
|
|
754
|
+
T extends GLSL<infer TSlots>
|
|
744
755
|
? _FlattenSlots<TSlots>
|
|
745
756
|
: T extends Array<GLSLSlot>
|
|
746
757
|
? _FlattenSlots<T>
|
|
747
758
|
: never
|
|
748
759
|
|
|
749
760
|
type _FlattenSlots<T extends Array<GLSLSlot>> = T extends [infer First, ...infer Rest]
|
|
750
|
-
? First extends
|
|
761
|
+
? First extends GLSL
|
|
751
762
|
? [...FlattenSlots<First>, ...FlattenSlots<Rest>]
|
|
752
763
|
: First extends unknown[]
|
|
753
764
|
? [...FlattenSlots<First>, ...FlattenSlots<Rest>]
|
|
@@ -774,18 +785,20 @@ export type MergeGLSLSchema<
|
|
|
774
785
|
}
|
|
775
786
|
|
|
776
787
|
export type CompileResult<
|
|
777
|
-
TVertex extends
|
|
778
|
-
TFragment extends
|
|
779
|
-
|
|
788
|
+
TVertex extends GLSL,
|
|
789
|
+
TFragment extends GLSL,
|
|
790
|
+
TOverrideSchema extends ViewSchemaPartial,
|
|
780
791
|
> =
|
|
781
792
|
MergeGLSLSchema<
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
793
|
+
GLSLToSchema<TVertex>,
|
|
794
|
+
GLSLToSchema<TFragment>,
|
|
795
|
+
TOverrideSchema
|
|
785
796
|
> extends infer TSchema extends ViewSchema
|
|
786
797
|
? {
|
|
787
798
|
program: WebGLProgram
|
|
788
799
|
schema: TSchema
|
|
789
|
-
view: View<TSchema
|
|
800
|
+
view: Prettify<View<TSchema>>
|
|
801
|
+
vertex: string
|
|
802
|
+
fragment: string
|
|
790
803
|
}
|
|
791
804
|
: never
|
package/test/tag.test.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
2
|
+
import { toID } from '../src'
|
|
2
3
|
import { attribute, compile, glsl, interleave, uniform } from '../src/tag'
|
|
3
4
|
import type { GL } from '../src/types'
|
|
4
5
|
import { createMockGL } from './mocks/webgl'
|
|
@@ -628,13 +629,15 @@ void main() { gl_FragColor = vec4(0.5); }`
|
|
|
628
629
|
|
|
629
630
|
compile(gl, glsl``, fragment)
|
|
630
631
|
|
|
631
|
-
|
|
632
|
+
const colorAlias = toID(color_symbol)
|
|
633
|
+
|
|
634
|
+
// Check that shaderSource was called with exact symbol alias
|
|
632
635
|
const fragmentShaderSource = (gl.shaderSource as any).mock.calls.find(
|
|
633
|
-
(call: any[]) => call[1].includes(
|
|
636
|
+
(call: any[]) => call[1].includes(`vec3 ${colorAlias}`)
|
|
634
637
|
)?.[1]
|
|
635
638
|
|
|
636
|
-
expect(fragmentShaderSource).
|
|
637
|
-
expect(fragmentShaderSource).
|
|
639
|
+
expect(fragmentShaderSource).toContain(`vec3 ${colorAlias} = vec3(1.0, 0.0, 0.0);`)
|
|
640
|
+
expect(fragmentShaderSource).toContain(`gl_FragColor = vec4(${colorAlias}, 1.0);`)
|
|
638
641
|
})
|
|
639
642
|
})
|
|
640
643
|
|
|
@@ -1485,6 +1488,231 @@ describe('compile', () => {
|
|
|
1485
1488
|
expect(schema.uniforms[u_vertex_only]).toEqual({ kind: 'vec2' })
|
|
1486
1489
|
expect(schema.uniforms[u_fragment_only]).toEqual({ kind: 'vec3' })
|
|
1487
1490
|
})
|
|
1491
|
+
|
|
1492
|
+
it('should return compiled vertex and fragment shader strings', () => {
|
|
1493
|
+
const vertex = glsl`
|
|
1494
|
+
${attribute.vec2('a_position')}
|
|
1495
|
+
${uniform.mat4('u_mvpMatrix')}
|
|
1496
|
+
|
|
1497
|
+
void main() {
|
|
1498
|
+
gl_Position = u_mvpMatrix * vec4(a_position, 0.0, 1.0);
|
|
1499
|
+
}
|
|
1500
|
+
`
|
|
1501
|
+
|
|
1502
|
+
const fragment = glsl`
|
|
1503
|
+
precision mediump float;
|
|
1504
|
+
${uniform.vec4('u_color')}
|
|
1505
|
+
|
|
1506
|
+
void main() {
|
|
1507
|
+
gl_FragColor = u_color;
|
|
1508
|
+
}
|
|
1509
|
+
`
|
|
1510
|
+
|
|
1511
|
+
const result = compile(gl, vertex, fragment)
|
|
1512
|
+
|
|
1513
|
+
// Check vertex shader string
|
|
1514
|
+
expect(result.vertex).toContain('attribute vec2 a_position;')
|
|
1515
|
+
expect(result.vertex).toContain('uniform mat4 u_mvpMatrix;')
|
|
1516
|
+
expect(result.vertex).toContain('gl_Position = u_mvpMatrix * vec4(a_position, 0.0, 1.0);')
|
|
1517
|
+
|
|
1518
|
+
// Check fragment shader string
|
|
1519
|
+
expect(result.fragment).toContain('precision mediump float;')
|
|
1520
|
+
expect(result.fragment).toContain('uniform vec4 u_color;')
|
|
1521
|
+
expect(result.fragment).toContain('gl_FragColor = u_color;')
|
|
1522
|
+
})
|
|
1523
|
+
|
|
1524
|
+
it('should return WebGL2 shader strings with proper syntax', () => {
|
|
1525
|
+
const vertex = glsl`#version 300 es
|
|
1526
|
+
${attribute.vec3('a_position')}
|
|
1527
|
+
${attribute.vec3('a_normal')}
|
|
1528
|
+
out vec3 v_normal;
|
|
1529
|
+
|
|
1530
|
+
void main() {
|
|
1531
|
+
v_normal = a_normal;
|
|
1532
|
+
gl_Position = vec4(a_position, 1.0);
|
|
1533
|
+
}
|
|
1534
|
+
`
|
|
1535
|
+
|
|
1536
|
+
const fragment = glsl`#version 300 es
|
|
1537
|
+
precision mediump float;
|
|
1538
|
+
${uniform.vec3('u_lightDir')}
|
|
1539
|
+
in vec3 v_normal;
|
|
1540
|
+
out vec4 fragColor;
|
|
1541
|
+
|
|
1542
|
+
void main() {
|
|
1543
|
+
float light = dot(v_normal, u_lightDir);
|
|
1544
|
+
fragColor = vec4(vec3(light), 1.0);
|
|
1545
|
+
}
|
|
1546
|
+
`
|
|
1547
|
+
|
|
1548
|
+
const result = compile(gl, vertex, fragment)
|
|
1549
|
+
|
|
1550
|
+
// Check vertex uses 'in' for attributes in WebGL2
|
|
1551
|
+
expect(result.vertex).toContain('in vec3 a_position;')
|
|
1552
|
+
expect(result.vertex).toContain('in vec3 a_normal;')
|
|
1553
|
+
expect(result.vertex).toContain('out vec3 v_normal;')
|
|
1554
|
+
|
|
1555
|
+
// Check fragment shader WebGL2 syntax
|
|
1556
|
+
expect(result.fragment).toContain('#version 300 es')
|
|
1557
|
+
expect(result.fragment).toContain('in vec3 v_normal;')
|
|
1558
|
+
expect(result.fragment).toContain('out vec4 fragColor;')
|
|
1559
|
+
})
|
|
1560
|
+
|
|
1561
|
+
it('should return shader strings with resolved symbols', () => {
|
|
1562
|
+
const u_time_symbol = Symbol('u_time')
|
|
1563
|
+
const a_pos_symbol = Symbol('a_position')
|
|
1564
|
+
|
|
1565
|
+
const vertex = glsl`
|
|
1566
|
+
${attribute.vec3(a_pos_symbol)}
|
|
1567
|
+
${uniform.float(u_time_symbol)}
|
|
1568
|
+
|
|
1569
|
+
void main() {
|
|
1570
|
+
gl_Position = vec4(${a_pos_symbol}, ${u_time_symbol});
|
|
1571
|
+
}
|
|
1572
|
+
`
|
|
1573
|
+
|
|
1574
|
+
const fragment = glsl`
|
|
1575
|
+
precision mediump float;
|
|
1576
|
+
${uniform.float(u_time_symbol)}
|
|
1577
|
+
|
|
1578
|
+
void main() {
|
|
1579
|
+
gl_FragColor = vec4(${u_time_symbol});
|
|
1580
|
+
}
|
|
1581
|
+
`
|
|
1582
|
+
|
|
1583
|
+
const result = compile(gl, vertex, fragment)
|
|
1584
|
+
|
|
1585
|
+
// Get exact symbol aliases
|
|
1586
|
+
const posAlias = toID(a_pos_symbol)
|
|
1587
|
+
const timeAlias = toID(u_time_symbol)
|
|
1588
|
+
|
|
1589
|
+
// Check vertex shader contains expected exact strings
|
|
1590
|
+
expect(result.vertex).toContain(`attribute vec3 ${posAlias};`)
|
|
1591
|
+
expect(result.vertex).toContain(`uniform float ${timeAlias};`)
|
|
1592
|
+
expect(result.vertex).toContain(`gl_Position = vec4(${posAlias}, ${timeAlias});`)
|
|
1593
|
+
|
|
1594
|
+
// Check fragment shader contains expected exact strings
|
|
1595
|
+
expect(result.fragment).toContain(`uniform float ${timeAlias};`)
|
|
1596
|
+
expect(result.fragment).toContain(`gl_FragColor = vec4(${timeAlias});`)
|
|
1597
|
+
expect(result.fragment).toContain('precision mediump float;')
|
|
1598
|
+
})
|
|
1599
|
+
|
|
1600
|
+
it('should return shader strings with interleaved attributes', () => {
|
|
1601
|
+
const vertex = glsl`
|
|
1602
|
+
${interleave('vertexData', [
|
|
1603
|
+
attribute.vec3('a_position'),
|
|
1604
|
+
attribute.vec2('a_uv'),
|
|
1605
|
+
attribute.vec3('a_normal')
|
|
1606
|
+
])}
|
|
1607
|
+
|
|
1608
|
+
void main() {
|
|
1609
|
+
gl_Position = vec4(a_position + a_normal, 0.0, 1.0);
|
|
1610
|
+
}
|
|
1611
|
+
`
|
|
1612
|
+
|
|
1613
|
+
const fragment = glsl`
|
|
1614
|
+
precision mediump float;
|
|
1615
|
+
|
|
1616
|
+
void main() {
|
|
1617
|
+
gl_FragColor = vec4(1.0);
|
|
1618
|
+
}
|
|
1619
|
+
`
|
|
1620
|
+
|
|
1621
|
+
const result = compile(gl, vertex, fragment)
|
|
1622
|
+
|
|
1623
|
+
// Check all interleaved attributes are expanded in vertex shader
|
|
1624
|
+
expect(result.vertex).toContain('attribute vec3 a_position;')
|
|
1625
|
+
expect(result.vertex).toContain('attribute vec2 a_uv;')
|
|
1626
|
+
expect(result.vertex).toContain('attribute vec3 a_normal;')
|
|
1627
|
+
expect(result.vertex).toContain('gl_Position = vec4(a_position + a_normal, 0.0, 1.0);')
|
|
1628
|
+
|
|
1629
|
+
// Fragment shader should be returned as-is
|
|
1630
|
+
expect(result.fragment).toContain('precision mediump float;')
|
|
1631
|
+
expect(result.fragment).toContain('gl_FragColor = vec4(1.0);')
|
|
1632
|
+
})
|
|
1633
|
+
|
|
1634
|
+
it('should return shader strings with composed GLSL fragments', () => {
|
|
1635
|
+
const sharedUniforms = glsl`
|
|
1636
|
+
${uniform.float('u_time')}
|
|
1637
|
+
${uniform.vec2('u_resolution')}
|
|
1638
|
+
`
|
|
1639
|
+
|
|
1640
|
+
const utils = glsl`
|
|
1641
|
+
float rand(vec2 co) {
|
|
1642
|
+
return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453);
|
|
1643
|
+
}
|
|
1644
|
+
`
|
|
1645
|
+
|
|
1646
|
+
const vertex = glsl`
|
|
1647
|
+
${sharedUniforms}
|
|
1648
|
+
${attribute.vec2('a_position')}
|
|
1649
|
+
|
|
1650
|
+
void main() {
|
|
1651
|
+
gl_Position = vec4(a_position * u_resolution, 0.0, 1.0);
|
|
1652
|
+
}
|
|
1653
|
+
`
|
|
1654
|
+
|
|
1655
|
+
const fragment = glsl`
|
|
1656
|
+
precision mediump float;
|
|
1657
|
+
${sharedUniforms}
|
|
1658
|
+
${utils}
|
|
1659
|
+
|
|
1660
|
+
void main() {
|
|
1661
|
+
float r = rand(gl_FragCoord.xy * u_time);
|
|
1662
|
+
gl_FragColor = vec4(r);
|
|
1663
|
+
}
|
|
1664
|
+
`
|
|
1665
|
+
|
|
1666
|
+
const result = compile(gl, vertex, fragment)
|
|
1667
|
+
|
|
1668
|
+
// Check vertex shader includes composed uniforms
|
|
1669
|
+
expect(result.vertex).toContain('uniform float u_time;')
|
|
1670
|
+
expect(result.vertex).toContain('uniform vec2 u_resolution;')
|
|
1671
|
+
expect(result.vertex).toContain('attribute vec2 a_position;')
|
|
1672
|
+
|
|
1673
|
+
// Check fragment shader includes both uniforms and utils
|
|
1674
|
+
expect(result.fragment).toContain('uniform float u_time;')
|
|
1675
|
+
expect(result.fragment).toContain('uniform vec2 u_resolution;')
|
|
1676
|
+
expect(result.fragment).toContain('float rand(vec2 co)')
|
|
1677
|
+
expect(result.fragment).toContain('return fract(sin(dot(co.xy')
|
|
1678
|
+
})
|
|
1679
|
+
|
|
1680
|
+
it('should return shader strings with array interpolations', () => {
|
|
1681
|
+
const vertex = glsl`
|
|
1682
|
+
${[
|
|
1683
|
+
uniform.mat4('u_model'),
|
|
1684
|
+
uniform.mat4('u_view'),
|
|
1685
|
+
uniform.mat4('u_projection')
|
|
1686
|
+
]}
|
|
1687
|
+
${[attribute.vec3('a_position'), attribute.vec3('a_normal')]}
|
|
1688
|
+
|
|
1689
|
+
void main() {
|
|
1690
|
+
gl_Position = u_projection * u_view * u_model * vec4(a_position, 1.0);
|
|
1691
|
+
}
|
|
1692
|
+
`
|
|
1693
|
+
|
|
1694
|
+
const fragment = glsl`
|
|
1695
|
+
precision mediump float;
|
|
1696
|
+
${[uniform.vec3('u_color'), uniform.float('u_alpha')]}
|
|
1697
|
+
|
|
1698
|
+
void main() {
|
|
1699
|
+
gl_FragColor = vec4(u_color, u_alpha);
|
|
1700
|
+
}
|
|
1701
|
+
`
|
|
1702
|
+
|
|
1703
|
+
const result = compile(gl, vertex, fragment)
|
|
1704
|
+
|
|
1705
|
+
// Check vertex shader has all uniforms and attributes from arrays
|
|
1706
|
+
expect(result.vertex).toContain('uniform mat4 u_model;')
|
|
1707
|
+
expect(result.vertex).toContain('uniform mat4 u_view;')
|
|
1708
|
+
expect(result.vertex).toContain('uniform mat4 u_projection;')
|
|
1709
|
+
expect(result.vertex).toContain('attribute vec3 a_position;')
|
|
1710
|
+
expect(result.vertex).toContain('attribute vec3 a_normal;')
|
|
1711
|
+
|
|
1712
|
+
// Check fragment shader
|
|
1713
|
+
expect(result.fragment).toContain('uniform vec3 u_color;')
|
|
1714
|
+
expect(result.fragment).toContain('uniform float u_alpha;')
|
|
1715
|
+
})
|
|
1488
1716
|
})
|
|
1489
1717
|
|
|
1490
1718
|
describe('compile.toString', () => {
|
|
@@ -1544,9 +1772,10 @@ describe('compile.toString', () => {
|
|
|
1544
1772
|
}`
|
|
1545
1773
|
|
|
1546
1774
|
const result = compile.toString(shader)
|
|
1775
|
+
const timeAlias = toID(u_time_symbol)
|
|
1547
1776
|
|
|
1548
|
-
expect(result).
|
|
1549
|
-
expect(result).
|
|
1777
|
+
expect(result).toContain(`uniform float ${timeAlias};`)
|
|
1778
|
+
expect(result).toContain(`gl_FragColor = vec4(${timeAlias});`)
|
|
1550
1779
|
})
|
|
1551
1780
|
|
|
1552
1781
|
it('should handle interleaved attributes', () => {
|