@bigmistqke/view.gl 0.1.3 → 0.1.4
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/.claude/settings.local.json +4 -1
- package/README.md +430 -177
- package/dev/src/examples/bezier.ts +3 -9
- package/dev/src/examples/{game_of_life.ts → game-of-life.ts} +2 -9
- package/dev/src/examples/glsl-composition.ts +131 -0
- package/dev/src/examples/grid.ts +4 -3
- package/dev/src/examples/overview.ts +7 -6
- package/dev/src/examples/{pix_sim.ts → pix-sim.ts} +3 -14
- package/dev/src/examples/symbol.ts +4 -3
- package/dev/src/index.ts +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs.map +1 -1
- package/dist/tag.d.mts +39 -21
- package/dist/tag.mjs +387 -47
- package/dist/tag.mjs.map +1 -1
- package/dist/{types-DoFAJoh-.d.mts → types-CGTxl3Eq.d.mts} +33 -11
- package/package.json +3 -2
- package/src/index.ts +4 -4
- package/src/tag.ts +205 -110
- package/src/types.ts +70 -5
- package/src/utils/index.ts +9 -9
- package/test/tag.test.ts +531 -82
|
@@ -1,10 +1,24 @@
|
|
|
1
|
-
type Merge<A, B> = {
|
|
2
|
-
[K in keyof A | keyof B]: K extends keyof A ? K extends keyof B ? A[K] | B[K] : A[K] : K extends keyof B ? B[K] : never;
|
|
3
|
-
};
|
|
4
1
|
type Prettify<T> = {
|
|
5
2
|
[K in keyof T]: T[K];
|
|
6
3
|
} & {};
|
|
7
4
|
type GL = WebGLRenderingContext | WebGL2RenderingContext;
|
|
5
|
+
type DeepMerge<A extends readonly [...any]> = A extends [infer L, ...infer R] ? DeepMergeTwo<L, DeepMerge<R>> : unknown;
|
|
6
|
+
type DeepMergeTwo<TBase, TOverride> = {
|
|
7
|
+
[K in keyof TBase | keyof TOverride]: K extends keyof TOverride ? K extends keyof TBase ? ShallowMerge<[TBase[K], TOverride[K]]> : TOverride[K] : K extends keyof TBase ? TBase[K] : never;
|
|
8
|
+
};
|
|
9
|
+
type ShallowMerge<A extends readonly [...any]> = A extends [infer L, ...infer R] ? ShallowMergeTwo<L, ShallowMerge<R>> : unknown;
|
|
10
|
+
type OptionalPropertyNames<T> = {
|
|
11
|
+
[K in keyof T]-?: {} extends {
|
|
12
|
+
[P in K]: T[K];
|
|
13
|
+
} ? K : never;
|
|
14
|
+
}[keyof T];
|
|
15
|
+
type SpreadProperties<L, R, K extends keyof L & keyof R> = {
|
|
16
|
+
[P in K]: L[P] | Exclude<R[P], undefined>;
|
|
17
|
+
};
|
|
18
|
+
type Id<T> = T extends infer U ? {
|
|
19
|
+
[K in keyof U]: U[K];
|
|
20
|
+
} : never;
|
|
21
|
+
type ShallowMergeTwo<L, R> = Id<Pick<L, Exclude<keyof L, keyof R>> & Pick<R, Exclude<keyof R, OptionalPropertyNames<R>>> & Pick<R, Exclude<OptionalPropertyNames<R>, keyof L>> & SpreadProperties<L, R, OptionalPropertyNames<R> & keyof L>>;
|
|
8
22
|
/**********************************************************************************/
|
|
9
23
|
/**********************************************************************************/
|
|
10
24
|
type GLTarget = 'ARRAY_BUFFER' | 'ELEMENT_ARRAY_BUFFER';
|
|
@@ -219,19 +233,23 @@ interface ViewSchema {
|
|
|
219
233
|
interleavedAttributes?: InterleavedAttributeSchema;
|
|
220
234
|
buffers?: BufferSchema;
|
|
221
235
|
}
|
|
236
|
+
interface ViewSchemaPartial {
|
|
237
|
+
uniforms?: Record<string | symbol, Partial<UniformOptions>>;
|
|
238
|
+
attributes?: Record<string | symbol, Partial<AttributeOptions>>;
|
|
239
|
+
interleavedAttributes?: Record<string | symbol, Partial<InterleavedAttributeOptions>>;
|
|
240
|
+
buffers?: Record<string | symbol, Partial<BufferOptions>>;
|
|
241
|
+
}
|
|
222
242
|
type View<T extends ViewSchema = ViewSchema> = {
|
|
223
243
|
attributes: T['attributes'] extends AttributeSchema ? AttributeView<T['attributes']> : undefined;
|
|
224
244
|
interleavedAttributes: T['interleavedAttributes'] extends InterleavedAttributeSchema ? InterleavedAttributeView<T['interleavedAttributes']> : undefined;
|
|
225
245
|
buffers: T['buffers'] extends BufferSchema ? BufferView<T['buffers']> : undefined;
|
|
226
246
|
uniforms: T['uniforms'] extends UniformSchema ? UniformView<T['uniforms']> : never;
|
|
227
247
|
};
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
template:
|
|
232
|
-
|
|
233
|
-
attributes: Record<string | symbol, AttributeOptions>;
|
|
234
|
-
interleavedAttributes: Record<string | symbol, InterleavedAttributeOptions>;
|
|
248
|
+
type GLSLSlot = GLSLTag | UniformTag | AttributeTag | InterleaveTag | string | number | symbol;
|
|
249
|
+
interface GLSLTag<TSlots extends GLSLSlot[] = GLSLSlot[]> {
|
|
250
|
+
type: 'glsl';
|
|
251
|
+
template: TemplateStringsArray;
|
|
252
|
+
slots: TSlots;
|
|
235
253
|
}
|
|
236
254
|
type UniformTag<TKey extends string | symbol = string | symbol, TKind extends UniformKind = UniformKind, TOptions extends Partial<UniformOptions> = UniformOptions> = TOptions extends {
|
|
237
255
|
size: infer TSize;
|
|
@@ -245,6 +263,10 @@ type UniformTag<TKey extends string | symbol = string | symbol, TKind extends Un
|
|
|
245
263
|
kind: TKind;
|
|
246
264
|
key: TKey;
|
|
247
265
|
};
|
|
266
|
+
interface UniformTagFn<TKind extends UniformKind> {
|
|
267
|
+
<const TKey extends string | symbol, const TOptions extends Omit<UniformOptions, 'kind'>>(key: TKey, TOptions: TOptions): Prettify<UniformTag<TKey, TKind, TOptions>>;
|
|
268
|
+
<const TName extends string | symbol>(key: TName): Prettify<UniformTag<TName, TKind>>;
|
|
269
|
+
}
|
|
248
270
|
interface AttributeTag<TKey extends string | symbol = string | symbol, TKind extends AttributeKind = AttributeKind, TInstanced extends boolean | undefined = boolean | undefined> {
|
|
249
271
|
type: 'attribute';
|
|
250
272
|
kind: TKind;
|
|
@@ -263,4 +285,4 @@ type InterleaveTag<TKey extends string | symbol = string | symbol, TLayout exten
|
|
|
263
285
|
};
|
|
264
286
|
};
|
|
265
287
|
|
|
266
|
-
export type { AttributeSchema as A, BufferSchema as B, GL as G, InterleavedAttributeSchema as I,
|
|
288
|
+
export type { AttributeSchema as A, BufferSchema as B, DeepMerge as D, GL as G, InterleavedAttributeSchema as I, Prettify as P, ShallowMerge as S, UniformSchema as U, ViewSchema as V, ViewOptions as a, View as b, UniformView as c, AttributeView as d, InterleavedAttributeView as e, BufferView as f, GLSLSlot as g, GLSLTag as h, UniformTagFn as i, AttributeTagFn as j, AttributeTag as k, AttributeKind as l, AttributeOptions as m, InterleaveTag as n, ViewSchemaPartial as o, UniformTag as p };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bigmistqke/view.gl",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "🪟 Utilities for managing WebGL resources.",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
"prepublish": "pnpm build",
|
|
39
39
|
"test": "vitest --run",
|
|
40
40
|
"test:coverage": "vitest run --coverage",
|
|
41
|
-
"test:ui": "vitest --ui"
|
|
41
|
+
"test:ui": "vitest --ui",
|
|
42
|
+
"lint:types": "tsc --noEmit"
|
|
42
43
|
}
|
|
43
44
|
}
|
package/src/index.ts
CHANGED
|
@@ -52,12 +52,12 @@ export function toID(key: string | number | symbol) {
|
|
|
52
52
|
/* */
|
|
53
53
|
/**********************************************************************************/
|
|
54
54
|
|
|
55
|
-
export function view<
|
|
55
|
+
export function view<TSchema extends ViewSchema>(
|
|
56
56
|
gl: GL,
|
|
57
57
|
program: WebGLProgram,
|
|
58
|
-
schema:
|
|
58
|
+
schema: TSchema,
|
|
59
59
|
options?: ViewOptions,
|
|
60
|
-
): View<
|
|
60
|
+
): View<TSchema> {
|
|
61
61
|
return {
|
|
62
62
|
uniforms: !schema.uniforms ? undefined : uniformView(gl, program, schema.uniforms),
|
|
63
63
|
attributes: !schema.attributes
|
|
@@ -67,7 +67,7 @@ export function view<T extends ViewSchema>(
|
|
|
67
67
|
? undefined
|
|
68
68
|
: interleavedAttributeView(gl, program, schema.interleavedAttributes, options),
|
|
69
69
|
buffers: !schema.buffers ? undefined : bufferView(gl, schema.buffers),
|
|
70
|
-
} as View<
|
|
70
|
+
} as View<TSchema>
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
/**********************************************************************************/
|
package/src/tag.ts
CHANGED
|
@@ -1,36 +1,35 @@
|
|
|
1
|
-
import { toID } from '.'
|
|
1
|
+
import { toID, view } from '.'
|
|
2
2
|
import type {
|
|
3
3
|
AttributeKind,
|
|
4
4
|
AttributeOptions,
|
|
5
5
|
AttributeTag,
|
|
6
|
-
AttributeTagFn,
|
|
7
|
-
|
|
6
|
+
AttributeTagFn as AttributeTagMethod,
|
|
7
|
+
DeepMerge,
|
|
8
|
+
GLSLSlot,
|
|
9
|
+
GLSLTag,
|
|
8
10
|
InterleaveTag,
|
|
9
|
-
Merge,
|
|
10
11
|
Prettify,
|
|
12
|
+
ShallowMerge,
|
|
11
13
|
UniformKind,
|
|
12
14
|
UniformOptions,
|
|
13
15
|
UniformTag,
|
|
16
|
+
UniformTagFn as UniformTagMethod,
|
|
17
|
+
View,
|
|
18
|
+
ViewSchema,
|
|
19
|
+
ViewSchemaPartial,
|
|
14
20
|
} from './types'
|
|
15
21
|
import { createProgram } from './utils'
|
|
16
22
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
interface UniformTagFn<TKind extends UniformKind> {
|
|
24
|
-
<const TKey extends string | symbol, const TOptions extends Omit<UniformOptions, 'kind'>>(
|
|
25
|
-
key: TKey,
|
|
26
|
-
TOptions: TOptions,
|
|
27
|
-
): Prettify<UniformTag<TKey, TKind, TOptions>>
|
|
28
|
-
<const TName extends string | symbol>(key: TName): Prettify<UniformTag<TName, TKind>>
|
|
23
|
+
export function glsl<TSlot extends GLSLSlot, TSlots extends TSlot[]>(
|
|
24
|
+
template: TemplateStringsArray,
|
|
25
|
+
...slots: [...TSlots]
|
|
26
|
+
): GLSLTag<TSlots> {
|
|
27
|
+
return { template, slots, type: 'glsl' }
|
|
29
28
|
}
|
|
30
29
|
|
|
31
30
|
export const uniform = new Proxy(
|
|
32
31
|
{} as {
|
|
33
|
-
[TKey in UniformKind]:
|
|
32
|
+
[TKey in UniformKind]: UniformTagMethod<TKey>
|
|
34
33
|
},
|
|
35
34
|
{
|
|
36
35
|
get(target, property) {
|
|
@@ -48,7 +47,7 @@ export const uniform = new Proxy(
|
|
|
48
47
|
|
|
49
48
|
export const attribute = new Proxy(
|
|
50
49
|
{} as {
|
|
51
|
-
[TKey in AttributeKind]:
|
|
50
|
+
[TKey in AttributeKind]: AttributeTagMethod<TKey>
|
|
52
51
|
},
|
|
53
52
|
{
|
|
54
53
|
get(target, property) {
|
|
@@ -93,109 +92,205 @@ export function interleave<
|
|
|
93
92
|
|
|
94
93
|
/**********************************************************************************/
|
|
95
94
|
/* */
|
|
96
|
-
/*
|
|
95
|
+
/* Compile */
|
|
97
96
|
/* */
|
|
98
97
|
/**********************************************************************************/
|
|
99
98
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
99
|
+
type glslTagToSchema<TTag extends GLSLTag> =
|
|
100
|
+
FlattenSlots<TTag> extends infer TSlots
|
|
101
|
+
? TSlots extends Array<any>
|
|
102
|
+
? GLSLSlotsToSchema<TSlots>
|
|
103
|
+
: never
|
|
104
|
+
: never
|
|
105
|
+
|
|
106
|
+
type GLSLSlotsToSchema<TSlots extends Array<GLSLSlot>> = {
|
|
107
|
+
uniforms: {
|
|
108
|
+
[K in Extract<TSlots[number], UniformTag> as K['key']]: Prettify<Omit<K, 'name' | 'type'>>
|
|
109
|
+
}
|
|
110
|
+
attributes: {
|
|
111
|
+
[K in Extract<TSlots[number], AttributeTag> as K['key']]: Prettify<Omit<K, 'name' | 'type'>>
|
|
112
|
+
}
|
|
113
|
+
interleavedAttributes: {
|
|
114
|
+
[K in Extract<TSlots[number], InterleaveTag> as K['key']]: Prettify<Omit<K, 'name' | 'type'>>
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
type FlattenSlots<T> =
|
|
119
|
+
T extends GLSLTag<infer TSlots>
|
|
120
|
+
? _FlattenSlots<TSlots>
|
|
121
|
+
: T extends Array<GLSLSlot>
|
|
122
|
+
? _FlattenSlots<T>
|
|
123
|
+
: never
|
|
124
|
+
|
|
125
|
+
type _FlattenSlots<T extends Array<GLSLSlot>> = T extends [infer First, ...infer Rest]
|
|
126
|
+
? First extends GLSLTag
|
|
127
|
+
? [...FlattenSlots<First>, ...FlattenSlots<Rest>]
|
|
128
|
+
: First extends unknown[]
|
|
129
|
+
? [...FlattenSlots<First>, ...FlattenSlots<Rest>]
|
|
130
|
+
: [First, ...FlattenSlots<Rest>]
|
|
131
|
+
: []
|
|
132
|
+
|
|
133
|
+
type MergeGLSLSchema<
|
|
134
|
+
TVertex extends ViewSchema,
|
|
135
|
+
TFragment extends ViewSchema,
|
|
136
|
+
TOverrides extends ViewSchemaPartial,
|
|
137
|
+
> = {
|
|
138
|
+
uniforms: DeepMerge<
|
|
139
|
+
[ShallowMerge<[TVertex['uniforms'], TFragment['uniforms']]>, TOverrides['uniforms']]
|
|
140
|
+
>
|
|
141
|
+
attributes: DeepMerge<
|
|
142
|
+
[ShallowMerge<[TVertex['attributes'], TFragment['attributes']]>, TOverrides['attributes']]
|
|
143
|
+
>
|
|
144
|
+
interleavedAttributes: DeepMerge<
|
|
145
|
+
[
|
|
146
|
+
ShallowMerge<[TVertex['interleavedAttributes'], TFragment['interleavedAttributes']]>,
|
|
147
|
+
TOverrides['interleavedAttributes'],
|
|
148
|
+
]
|
|
149
|
+
>
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
type CompileResult<
|
|
153
|
+
TVertex extends GLSLTag,
|
|
154
|
+
TFragment extends GLSLTag,
|
|
155
|
+
TOverrides extends ViewSchemaPartial,
|
|
156
|
+
> =
|
|
157
|
+
MergeGLSLSchema<
|
|
158
|
+
glslTagToSchema<TVertex>,
|
|
159
|
+
glslTagToSchema<TFragment>,
|
|
160
|
+
TOverrides
|
|
161
|
+
> extends infer TSchema extends ViewSchema
|
|
162
|
+
? {
|
|
163
|
+
program: WebGLProgram
|
|
164
|
+
schema: TSchema
|
|
165
|
+
view: View<TSchema>
|
|
135
166
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
167
|
+
: never
|
|
168
|
+
|
|
169
|
+
export function compile<
|
|
170
|
+
TVertex extends GLSLTag,
|
|
171
|
+
TFragment extends GLSLTag,
|
|
172
|
+
TOverride extends ViewSchemaPartial,
|
|
173
|
+
>(gl: WebGLRenderingContext, vertex: TVertex, fragment: TFragment, overrideSchema?: TOverride) {
|
|
174
|
+
const _vertex = resolveGLSLTag(vertex)
|
|
175
|
+
const _fragment = resolveGLSLTag(fragment)
|
|
176
|
+
|
|
177
|
+
const schema = {
|
|
178
|
+
uniforms: {
|
|
179
|
+
..._vertex.schema.uniforms,
|
|
180
|
+
..._fragment.schema.uniforms,
|
|
141
181
|
},
|
|
142
|
-
{
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
attributes: {},
|
|
146
|
-
interleavedAttributes: {},
|
|
147
|
-
} as {
|
|
148
|
-
template: string
|
|
149
|
-
uniforms: {
|
|
150
|
-
[K in Extract<Holes[number], UniformTag> as K['key']]: Prettify<Omit<K, 'name' | 'type'>>
|
|
151
|
-
}
|
|
152
|
-
attributes: {
|
|
153
|
-
[K in Extract<Holes[number], AttributeTag> as K['key']]: Prettify<Omit<K, 'name' | 'type'>>
|
|
154
|
-
}
|
|
155
|
-
interleavedAttributes: {
|
|
156
|
-
[K in Extract<Holes[number], InterleaveTag> as K['key']]: Prettify<Omit<K, 'name' | 'type'>>
|
|
157
|
-
}
|
|
182
|
+
attributes: {
|
|
183
|
+
..._vertex.schema.attributes,
|
|
184
|
+
..._fragment.schema.attributes,
|
|
158
185
|
},
|
|
159
|
-
|
|
160
|
-
|
|
186
|
+
interleavedAttributes: {
|
|
187
|
+
..._vertex.schema.interleavedAttributes,
|
|
188
|
+
..._fragment.schema.interleavedAttributes,
|
|
189
|
+
},
|
|
190
|
+
}
|
|
161
191
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
192
|
+
for (const kind in overrideSchema) {
|
|
193
|
+
const schemaKind = schema[kind as keyof typeof schema]
|
|
194
|
+
const overrideSchemaKind = overrideSchema[kind]
|
|
195
|
+
|
|
196
|
+
for (const key in overrideSchemaKind) {
|
|
197
|
+
// @ts-expect-error
|
|
198
|
+
schemaKind[key] = {
|
|
199
|
+
// @ts-expect-error
|
|
200
|
+
...schemaKind[key],
|
|
201
|
+
...overrideSchemaKind[key],
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
167
205
|
|
|
168
|
-
|
|
169
|
-
gl: WebGLRenderingContext,
|
|
170
|
-
vertex: TVertex,
|
|
171
|
-
fragment: TFragment,
|
|
172
|
-
) {
|
|
173
|
-
const program = createProgram(gl, vertex.template, fragment.template)
|
|
206
|
+
const program = createProgram(gl, _vertex.template, _fragment.template)
|
|
174
207
|
|
|
175
208
|
return {
|
|
176
209
|
program,
|
|
177
|
-
schema
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
210
|
+
schema,
|
|
211
|
+
view: view(gl, program, schema),
|
|
212
|
+
} as CompileResult<TVertex, TFragment, TOverride>
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function resolveGLSLTag<TTag extends GLSLTag>(tag: TTag) {
|
|
216
|
+
return {
|
|
217
|
+
template: glslTagToString(tag),
|
|
218
|
+
schema: glslTagToSchema(tag),
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function glslTagToSchema<TTag extends GLSLTag>(tag: TTag) {
|
|
223
|
+
const result = {
|
|
224
|
+
uniforms: {},
|
|
225
|
+
attributes: {},
|
|
226
|
+
interleavedAttributes: {},
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
for (const slot of tag.slots) {
|
|
230
|
+
if (typeof slot !== 'object') {
|
|
231
|
+
continue
|
|
199
232
|
}
|
|
233
|
+
|
|
234
|
+
if (slot.type === 'glsl') {
|
|
235
|
+
const { uniforms, attributes, interleavedAttributes } = glslTagToSchema(slot)
|
|
236
|
+
|
|
237
|
+
result.uniforms = {
|
|
238
|
+
...result.uniforms,
|
|
239
|
+
...uniforms,
|
|
240
|
+
}
|
|
241
|
+
result.attributes = {
|
|
242
|
+
...result.attributes,
|
|
243
|
+
...attributes,
|
|
244
|
+
}
|
|
245
|
+
result.interleavedAttributes = {
|
|
246
|
+
...result.interleavedAttributes,
|
|
247
|
+
...interleavedAttributes,
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
continue
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const { key: name, type, ...rest } = slot
|
|
254
|
+
|
|
255
|
+
// @ts-expect-error
|
|
256
|
+
result[`${type}s`][name] = rest
|
|
200
257
|
}
|
|
258
|
+
|
|
259
|
+
return result
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function glslTagToString<TTag extends GLSLTag>({ template: [initial, ...rest], slots }: TTag) {
|
|
263
|
+
const v300 = !!initial?.startsWith('#version 300 es')
|
|
264
|
+
|
|
265
|
+
let template = initial ?? ''
|
|
266
|
+
|
|
267
|
+
for (let i = 0; i < rest.length; i++) {
|
|
268
|
+
template += `${glslSlotToString(slots[i]!, v300)}${rest[i]}`
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return template
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function glslSlotToString(slot: GLSLSlot, v300: boolean) {
|
|
275
|
+
if (typeof slot !== 'object') {
|
|
276
|
+
return toID(slot)
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (slot.type === 'glsl') {
|
|
280
|
+
return glslTagToString(slot)
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (slot.type === 'interleavedAttribute') {
|
|
284
|
+
return slot.layout.reduce(
|
|
285
|
+
(a, v) =>
|
|
286
|
+
v300 ? `${a}in ${v.kind} ${toID(v.key)};\n` : `${a}attribute ${v.kind} ${toID(v.key)};\n`,
|
|
287
|
+
'',
|
|
288
|
+
)
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (slot.type === 'uniform' && 'size' in slot) {
|
|
292
|
+
return `${slot.type} ${slot.kind} ${toID(slot.key)}[${slot.size}];`
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return `${slot.type === 'attribute' && v300 ? 'in' : slot.type} ${slot.kind} ${toID(slot.key)};`
|
|
201
296
|
}
|
package/src/types.ts
CHANGED
|
@@ -18,6 +18,42 @@ export type RemoveSuffix<T, S extends string> = {
|
|
|
18
18
|
|
|
19
19
|
export type GL = WebGLRenderingContext | WebGL2RenderingContext
|
|
20
20
|
|
|
21
|
+
export type DeepMerge<A extends readonly [...any]> = A extends [infer L, ...infer R]
|
|
22
|
+
? DeepMergeTwo<L, DeepMerge<R>>
|
|
23
|
+
: unknown
|
|
24
|
+
|
|
25
|
+
type DeepMergeTwo<TBase, TOverride> = {
|
|
26
|
+
[K in keyof TBase | keyof TOverride]: K extends keyof TOverride
|
|
27
|
+
? K extends keyof TBase
|
|
28
|
+
? ShallowMerge<[TBase[K], TOverride[K]]>
|
|
29
|
+
: TOverride[K]
|
|
30
|
+
: K extends keyof TBase
|
|
31
|
+
? TBase[K]
|
|
32
|
+
: never
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// see https://stackoverflow.com/a/49683575
|
|
36
|
+
export type ShallowMerge<A extends readonly [...any]> = A extends [infer L, ...infer R]
|
|
37
|
+
? ShallowMergeTwo<L, ShallowMerge<R>>
|
|
38
|
+
: unknown
|
|
39
|
+
|
|
40
|
+
type OptionalPropertyNames<T> = {
|
|
41
|
+
[K in keyof T]-?: {} extends { [P in K]: T[K] } ? K : never
|
|
42
|
+
}[keyof T]
|
|
43
|
+
|
|
44
|
+
type SpreadProperties<L, R, K extends keyof L & keyof R> = {
|
|
45
|
+
[P in K]: L[P] | Exclude<R[P], undefined>
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
type Id<T> = T extends infer U ? { [K in keyof U]: U[K] } : never
|
|
49
|
+
|
|
50
|
+
type ShallowMergeTwo<L, R> = Id<
|
|
51
|
+
Pick<L, Exclude<keyof L, keyof R>> &
|
|
52
|
+
Pick<R, Exclude<keyof R, OptionalPropertyNames<R>>> &
|
|
53
|
+
Pick<R, Exclude<OptionalPropertyNames<R>, keyof L>> &
|
|
54
|
+
SpreadProperties<L, R, OptionalPropertyNames<R> & keyof L>
|
|
55
|
+
>
|
|
56
|
+
|
|
21
57
|
/**********************************************************************************/
|
|
22
58
|
/* */
|
|
23
59
|
/* Constants */
|
|
@@ -359,6 +395,7 @@ export interface UniformOptions {
|
|
|
359
395
|
}
|
|
360
396
|
|
|
361
397
|
export type UniformSchema = Record<string | symbol, UniformOptions>
|
|
398
|
+
export type UniformSchemaPartial = Record<string | symbol, Partial<UniformOptions>>
|
|
362
399
|
|
|
363
400
|
export type UniformMethods<TOptions extends UniformOptions> = TOptions['size'] extends number
|
|
364
401
|
? {
|
|
@@ -645,6 +682,13 @@ export interface ViewSchema {
|
|
|
645
682
|
buffers?: BufferSchema
|
|
646
683
|
}
|
|
647
684
|
|
|
685
|
+
export interface ViewSchemaPartial {
|
|
686
|
+
uniforms?: Record<string | symbol, Partial<UniformOptions>>
|
|
687
|
+
attributes?: Record<string | symbol, Partial<AttributeOptions>>
|
|
688
|
+
interleavedAttributes?: Record<string | symbol, Partial<InterleavedAttributeOptions>>
|
|
689
|
+
buffers?: Record<string | symbol, Partial<BufferOptions>>
|
|
690
|
+
}
|
|
691
|
+
|
|
648
692
|
export type View<T extends ViewSchema = ViewSchema> = {
|
|
649
693
|
attributes: T['attributes'] extends AttributeSchema ? AttributeView<T['attributes']> : undefined
|
|
650
694
|
interleavedAttributes: T['interleavedAttributes'] extends InterleavedAttributeSchema
|
|
@@ -660,11 +704,24 @@ export type View<T extends ViewSchema = ViewSchema> = {
|
|
|
660
704
|
/* */
|
|
661
705
|
/**********************************************************************************/
|
|
662
706
|
|
|
663
|
-
export interface
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
707
|
+
export interface GLSLResult {
|
|
708
|
+
program: WebGLProgram
|
|
709
|
+
schema: ViewSchema
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
export type GLSLSlot =
|
|
713
|
+
| GLSLTag
|
|
714
|
+
| UniformTag
|
|
715
|
+
| AttributeTag
|
|
716
|
+
| InterleaveTag
|
|
717
|
+
| string
|
|
718
|
+
| number
|
|
719
|
+
| symbol
|
|
720
|
+
|
|
721
|
+
export interface GLSLTag<TSlots extends GLSLSlot[] = GLSLSlot[]> {
|
|
722
|
+
type: 'glsl'
|
|
723
|
+
template: TemplateStringsArray
|
|
724
|
+
slots: TSlots
|
|
668
725
|
}
|
|
669
726
|
|
|
670
727
|
export type UniformTag<
|
|
@@ -684,6 +741,14 @@ export type UniformTag<
|
|
|
684
741
|
key: TKey
|
|
685
742
|
}
|
|
686
743
|
|
|
744
|
+
export interface UniformTagFn<TKind extends UniformKind> {
|
|
745
|
+
<const TKey extends string | symbol, const TOptions extends Omit<UniformOptions, 'kind'>>(
|
|
746
|
+
key: TKey,
|
|
747
|
+
TOptions: TOptions,
|
|
748
|
+
): Prettify<UniformTag<TKey, TKind, TOptions>>
|
|
749
|
+
<const TName extends string | symbol>(key: TName): Prettify<UniformTag<TName, TKind>>
|
|
750
|
+
}
|
|
751
|
+
|
|
687
752
|
export interface AttributeTag<
|
|
688
753
|
TKey extends string | symbol = string | symbol,
|
|
689
754
|
TKind extends AttributeKind = AttributeKind,
|
package/src/utils/index.ts
CHANGED
|
@@ -71,26 +71,26 @@ export const kindToUniformFnName = <T extends UniformKind>(
|
|
|
71
71
|
switch (kind[0]) {
|
|
72
72
|
// mat
|
|
73
73
|
case 'm':
|
|
74
|
-
return 'Matrix' + kind.slice(3) + 'fv'
|
|
74
|
+
return ('Matrix' + kind.slice(3) + 'fv') as KIND_TO_UNIFORM_FN_NAME_MAP[T]
|
|
75
75
|
// sampler/booleans/integer
|
|
76
76
|
case 's':
|
|
77
77
|
case 'b':
|
|
78
78
|
case 'i':
|
|
79
|
-
return (kind.match(/\d/)?.[0] ?? '1') + 'i'
|
|
79
|
+
return ((kind.match(/\d/)?.[0] ?? '1') + 'i') as KIND_TO_UNIFORM_FN_NAME_MAP[T]
|
|
80
80
|
// unsigned integers
|
|
81
81
|
case 'u':
|
|
82
|
-
return (kind[4] || '1') + 'ui'
|
|
82
|
+
return ((kind[4] || '1') + 'ui') as KIND_TO_UNIFORM_FN_NAME_MAP[T]
|
|
83
83
|
// vec
|
|
84
84
|
case 'v':
|
|
85
|
-
return kind[3] + 'f'
|
|
85
|
+
return (kind[3] + 'f') as KIND_TO_UNIFORM_FN_NAME_MAP[T]
|
|
86
86
|
default:
|
|
87
87
|
switch (kind) {
|
|
88
88
|
case 'float':
|
|
89
|
-
return '1f'
|
|
89
|
+
return '1f' as KIND_TO_UNIFORM_FN_NAME_MAP[T]
|
|
90
90
|
case 'uint':
|
|
91
|
-
return '1ui'
|
|
91
|
+
return '1ui' as KIND_TO_UNIFORM_FN_NAME_MAP[T]
|
|
92
92
|
default:
|
|
93
|
-
return '1i'
|
|
93
|
+
return '1i' as KIND_TO_UNIFORM_FN_NAME_MAP[T]
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
96
|
}
|
|
@@ -167,7 +167,7 @@ export function createTexture(
|
|
|
167
167
|
if (!(name in gl)) {
|
|
168
168
|
throw new Error(`Attempted to create webgl2-only texture (${name}) in webgl1`)
|
|
169
169
|
}
|
|
170
|
-
return gl[name]
|
|
170
|
+
return gl[name as keyof typeof gl] as any
|
|
171
171
|
}
|
|
172
172
|
|
|
173
173
|
gl.bindTexture(gl[target], texture)
|
|
@@ -268,7 +268,7 @@ export function createFramebuffer(gl: GL, { attachment, texture, ...options }: F
|
|
|
268
268
|
/* */
|
|
269
269
|
/**********************************************************************************/
|
|
270
270
|
|
|
271
|
-
type UpsertMapKind<T, U> = Map<T, U> | WeakMap<T, U>
|
|
271
|
+
type UpsertMapKind<T, U> = Map<T, U> | (T extends WeakKey ? WeakMap<T, U> : never)
|
|
272
272
|
|
|
273
273
|
export function createUpsertMap<T extends UpsertMapKind<any, any> = Map<any, any>>(
|
|
274
274
|
constructor?: new () => T,
|