@bigmistqke/view.gl 0.1.8 → 0.1.9
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 +2 -1
- package/README.md +30 -0
- package/dev/src/examples/bezier.ts +3 -2
- package/dev/src/examples/game-of-life.ts +13 -30
- package/dev/src/examples/glsl-composition.ts +3 -3
- package/dev/src/examples/grid.ts +20 -14
- package/dev/src/examples/pix-sim.ts +29 -22
- package/dev/src/examples/ray-casting.ts +455 -0
- package/dev/src/examples/sdf.ts +98 -0
- package/dev/src/examples/symbol.ts +2 -2
- package/dev/src/index.ts +12 -11
- package/dev/src/utils.ts +18 -4
- package/dist/index.d.mts +2 -2
- package/dist/tag.d.mts +21 -4
- package/dist/tag.mjs +78 -39
- package/dist/tag.mjs.map +1 -1
- package/dist/{types-Bp9VAVe3.d.mts → types-DaV9McmR.d.mts} +18 -14
- package/package.json +1 -1
- package/src/tag.ts +111 -44
- package/src/types.ts +36 -22
- package/test/tag.test.ts +462 -0
package/src/tag.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
AttributeTokenFn as AttributeTagMethod,
|
|
7
7
|
AttributeToken,
|
|
8
8
|
CompileResult,
|
|
9
|
+
GL,
|
|
9
10
|
GLSL,
|
|
10
11
|
GLSLSlot,
|
|
11
12
|
GLSLToSchema,
|
|
@@ -16,7 +17,7 @@ import type {
|
|
|
16
17
|
ViewSchema,
|
|
17
18
|
ViewSchemaPartial,
|
|
18
19
|
} from './types'
|
|
19
|
-
import { createProgram } from './utils'
|
|
20
|
+
import { createProgram, createUpsertMap } from './utils'
|
|
20
21
|
|
|
21
22
|
export function glsl<TSlot extends GLSLSlot, TSlots extends TSlot[]>(
|
|
22
23
|
template: TemplateStringsArray,
|
|
@@ -94,13 +95,23 @@ export function interleave<
|
|
|
94
95
|
/* */
|
|
95
96
|
/**********************************************************************************/
|
|
96
97
|
|
|
98
|
+
export interface CompileOptions<TSchema extends ViewSchemaPartial> {
|
|
99
|
+
schema?: TSchema
|
|
100
|
+
webgl2?: boolean
|
|
101
|
+
}
|
|
102
|
+
|
|
97
103
|
export function compile<
|
|
98
104
|
TVertex extends GLSL,
|
|
99
105
|
TFragment extends GLSL,
|
|
100
|
-
|
|
101
|
-
>(
|
|
102
|
-
|
|
103
|
-
|
|
106
|
+
TSchema extends ViewSchemaPartial,
|
|
107
|
+
>(
|
|
108
|
+
gl: WebGLRenderingContext,
|
|
109
|
+
vertex: TVertex,
|
|
110
|
+
fragment: TFragment,
|
|
111
|
+
options?: CompileOptions<TSchema> | undefined,
|
|
112
|
+
) {
|
|
113
|
+
const _vertex = resolveGLSLTag(vertex, options) as { template: string; schema: ViewSchema }
|
|
114
|
+
const _fragment = resolveGLSLTag(fragment, options) as { template: string; schema: ViewSchema }
|
|
104
115
|
|
|
105
116
|
const schema = {
|
|
106
117
|
uniforms: {
|
|
@@ -117,32 +128,40 @@ export function compile<
|
|
|
117
128
|
},
|
|
118
129
|
}
|
|
119
130
|
|
|
120
|
-
|
|
131
|
+
// Deep merge options.schema with generated schema
|
|
132
|
+
for (const kind in options?.schema) {
|
|
121
133
|
const schemaKind = schema[kind as keyof typeof schema]
|
|
122
|
-
const
|
|
134
|
+
const configSchemaKind = options?.schema[kind]
|
|
123
135
|
|
|
124
|
-
for (const key in
|
|
136
|
+
for (const key in configSchemaKind) {
|
|
125
137
|
schemaKind[key] = {
|
|
126
138
|
...schemaKind[key],
|
|
127
|
-
...
|
|
139
|
+
...configSchemaKind[key],
|
|
128
140
|
}
|
|
129
141
|
}
|
|
130
142
|
}
|
|
131
143
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
144
|
+
try {
|
|
145
|
+
const program = createProgram(gl, _vertex.template, _fragment.template)
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
program,
|
|
149
|
+
schema,
|
|
150
|
+
view: view(gl, program, schema),
|
|
151
|
+
vertex: _vertex.template,
|
|
152
|
+
fragment: _fragment.template,
|
|
153
|
+
} as unknown as Prettify<CompileResult<TVertex, TFragment, TSchema>>
|
|
154
|
+
} catch (error) {
|
|
155
|
+
console.error('Error while creating WebGLProgram - vertex\n\n', _vertex.template)
|
|
156
|
+
console.error('Error while creating WebGLProgram - fragment\n\n', _fragment.template)
|
|
157
|
+
|
|
158
|
+
throw error
|
|
159
|
+
}
|
|
141
160
|
}
|
|
142
161
|
|
|
143
|
-
function resolveGLSLTag<TTag extends GLSL>(tag: TTag) {
|
|
162
|
+
function resolveGLSLTag<TTag extends GLSL>(tag: TTag, options?: { webgl2?: boolean }) {
|
|
144
163
|
return {
|
|
145
|
-
template: compile.toString(tag),
|
|
164
|
+
template: compile.toString(tag, options),
|
|
146
165
|
schema: compile.toSchema(tag),
|
|
147
166
|
}
|
|
148
167
|
}
|
|
@@ -154,13 +173,13 @@ compile.toSchema = function <TTag extends GLSL>(tag: TTag) {
|
|
|
154
173
|
interleavedAttributes: {},
|
|
155
174
|
}
|
|
156
175
|
|
|
157
|
-
function handleSlot(slot: GLSLSlot) {
|
|
158
|
-
if (
|
|
159
|
-
slot.forEach(handleSlot)
|
|
176
|
+
tag.slots.forEach(function handleSlot(slot: GLSLSlot) {
|
|
177
|
+
if (typeof slot !== 'object') {
|
|
160
178
|
return
|
|
161
179
|
}
|
|
162
180
|
|
|
163
|
-
if (
|
|
181
|
+
if (Array.isArray(slot)) {
|
|
182
|
+
slot.forEach(handleSlot)
|
|
164
183
|
return
|
|
165
184
|
}
|
|
166
185
|
|
|
@@ -187,49 +206,97 @@ compile.toSchema = function <TTag extends GLSL>(tag: TTag) {
|
|
|
187
206
|
|
|
188
207
|
// @ts-expect-error
|
|
189
208
|
result[`${type}s`][name] = rest
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
tag.slots.forEach(handleSlot)
|
|
209
|
+
})
|
|
193
210
|
|
|
194
211
|
return result as unknown as Prettify<GLSLToSchema<TTag>>
|
|
195
212
|
}
|
|
196
213
|
|
|
197
|
-
compile.toString = function <TTag extends GLSL>(
|
|
198
|
-
|
|
214
|
+
compile.toString = function <TTag extends GLSL>(
|
|
215
|
+
{ template: [initial, ...rest], slots }: TTag,
|
|
216
|
+
config?: { webgl2?: boolean },
|
|
217
|
+
) {
|
|
218
|
+
const v300 = config?.webgl2 ?? !!initial?.startsWith('#version 300 es')
|
|
199
219
|
|
|
200
220
|
let template = initial ?? ''
|
|
201
221
|
|
|
202
222
|
for (let i = 0; i < rest.length; i++) {
|
|
203
|
-
template += `${
|
|
223
|
+
template += `${resolveGlslSlotToString(slots[i]!, v300)}${rest[i]}`
|
|
204
224
|
}
|
|
205
225
|
|
|
206
226
|
return template
|
|
207
227
|
}
|
|
208
228
|
|
|
209
|
-
function
|
|
229
|
+
function resolveGlslSlotToString(slot: GLSLSlot, v300: boolean): string {
|
|
210
230
|
if (typeof slot !== 'object') {
|
|
211
231
|
return toID(slot)
|
|
212
232
|
}
|
|
213
233
|
|
|
214
234
|
if (Array.isArray(slot)) {
|
|
215
|
-
return slot.map(slot =>
|
|
235
|
+
return slot.map(slot => resolveGlslSlotToString(slot, v300)).join('')
|
|
216
236
|
}
|
|
217
237
|
|
|
218
|
-
|
|
219
|
-
|
|
238
|
+
switch (slot.type) {
|
|
239
|
+
case 'glsl':
|
|
240
|
+
return compile.toString(slot)
|
|
241
|
+
case 'interleavedAttribute':
|
|
242
|
+
return slot.layout.reduce(
|
|
243
|
+
(a, v) =>
|
|
244
|
+
v300 ? `${a}in ${v.kind} ${toID(v.key)};\n` : `${a}attribute ${v.kind} ${toID(v.key)};\n`,
|
|
245
|
+
'',
|
|
246
|
+
)
|
|
247
|
+
case 'uniform':
|
|
248
|
+
if ('size' in slot) {
|
|
249
|
+
return `${slot.type} ${slot.kind} ${toID(slot.key)}[${slot.size}];`
|
|
250
|
+
}
|
|
251
|
+
return `${slot.type} ${slot.kind} ${toID(slot.key)};`
|
|
220
252
|
}
|
|
221
253
|
|
|
222
|
-
if (slot.type === '
|
|
223
|
-
return slot.
|
|
224
|
-
(a, v) =>
|
|
225
|
-
v300 ? `${a}in ${v.kind} ${toID(v.key)};\n` : `${a}attribute ${v.kind} ${toID(v.key)};\n`,
|
|
226
|
-
'',
|
|
227
|
-
)
|
|
254
|
+
if (slot.type === 'attribute') {
|
|
255
|
+
return `${v300 ? 'in' : slot.type} ${slot.kind} ${toID(slot.key)};`
|
|
228
256
|
}
|
|
229
257
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
258
|
+
throw new Error(`Unexpected slot: ${JSON.stringify(slot)}`)
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const QUAD_FLOAT_ARRAY = new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1])
|
|
262
|
+
const QUAD_BUFFER_MAP = createUpsertMap(WeakMap<GL, WebGLBuffer>)
|
|
263
|
+
|
|
264
|
+
compile.toQuad = function <TFragment extends GLSL, TSchema extends ViewSchemaPartial>(
|
|
265
|
+
gl: GL,
|
|
266
|
+
fragment: TFragment,
|
|
267
|
+
options?: CompileOptions<TSchema>,
|
|
268
|
+
) {
|
|
269
|
+
const buffer = QUAD_BUFFER_MAP.getOrInsert(gl, gl.createBuffer.bind(gl))
|
|
270
|
+
|
|
271
|
+
const webgl2 = options?.webgl2 ?? fragment.template[0]?.startsWith('#version 300 es')
|
|
272
|
+
|
|
273
|
+
const vertex = webgl2
|
|
274
|
+
? glsl`#version 300 es
|
|
275
|
+
precision mediump float;
|
|
276
|
+
|
|
277
|
+
${attribute.vec2('a_quad', { buffer })}
|
|
278
|
+
|
|
279
|
+
out vec2 v_uv;
|
|
280
|
+
|
|
281
|
+
void main() {
|
|
282
|
+
v_uv = a_quad;
|
|
283
|
+
gl_Position = vec4(v_uv, 0.0, 1.0);
|
|
284
|
+
}`
|
|
285
|
+
: glsl`precision mediump float;
|
|
286
|
+
|
|
287
|
+
${attribute.vec2('a_quad', { buffer })}
|
|
288
|
+
|
|
289
|
+
varying vec2 v_uv;
|
|
290
|
+
|
|
291
|
+
void main() {
|
|
292
|
+
v_uv = a_quad;
|
|
293
|
+
gl_Position = vec4(v_uv, 0.0, 1.0);
|
|
294
|
+
}`
|
|
295
|
+
|
|
296
|
+
const result = compile(gl, vertex, fragment, options)
|
|
297
|
+
|
|
298
|
+
// @ts-expect-error
|
|
299
|
+
result.view.attributes.a_quad.set(QUAD_FLOAT_ARRAY)
|
|
233
300
|
|
|
234
|
-
return
|
|
301
|
+
return result
|
|
235
302
|
}
|
package/src/types.ts
CHANGED
|
@@ -416,7 +416,7 @@ export interface AttributeMethods<T = AttributeKind> {
|
|
|
416
416
|
}
|
|
417
417
|
|
|
418
418
|
export type AttributeView<T extends AttributeSchema> = {
|
|
419
|
-
[K in keyof T]: AttributeMethods<T[K]['kind']
|
|
419
|
+
[K in keyof T]: Prettify<AttributeMethods<T[K]['kind']>>
|
|
420
420
|
}
|
|
421
421
|
|
|
422
422
|
/**********************************************************************************/
|
|
@@ -635,12 +635,12 @@ export interface ViewSchemaPartial {
|
|
|
635
635
|
export type View<T extends ViewSchema = ViewSchema> = {
|
|
636
636
|
attributes: T['attributes'] extends AttributeSchema
|
|
637
637
|
? Prettify<AttributeView<T['attributes']>>
|
|
638
|
-
:
|
|
638
|
+
: {}
|
|
639
639
|
interleavedAttributes: T['interleavedAttributes'] extends InterleavedAttributeSchema
|
|
640
640
|
? Prettify<InterleavedAttributeView<T['interleavedAttributes']>>
|
|
641
|
-
:
|
|
642
|
-
buffers: T['buffers'] extends BufferSchema ? Prettify<BufferView<T['buffers']>> :
|
|
643
|
-
uniforms: T['uniforms'] extends UniformSchema ? Prettify<UniformView<T['uniforms']>> :
|
|
641
|
+
: {}
|
|
642
|
+
buffers: T['buffers'] extends BufferSchema ? Prettify<BufferView<T['buffers']>> : {}
|
|
643
|
+
uniforms: T['uniforms'] extends UniformSchema ? Prettify<UniformView<T['uniforms']>> : {}
|
|
644
644
|
}
|
|
645
645
|
|
|
646
646
|
/**********************************************************************************/
|
|
@@ -703,7 +703,7 @@ export interface AttributeToken<
|
|
|
703
703
|
> {
|
|
704
704
|
type: 'attribute'
|
|
705
705
|
kind: TKind
|
|
706
|
-
instanced: TInstanced
|
|
706
|
+
instanced: TInstanced extends boolean ? boolean : false
|
|
707
707
|
key: TKey
|
|
708
708
|
}
|
|
709
709
|
|
|
@@ -768,26 +768,40 @@ type _FlattenSlots<T extends Array<GLSLSlot>> = T extends [infer First, ...infer
|
|
|
768
768
|
export type MergeGLSLSchema<
|
|
769
769
|
TVertex extends ViewSchema,
|
|
770
770
|
TFragment extends ViewSchema,
|
|
771
|
-
TOverrides extends ViewSchemaPartial = {},
|
|
772
|
-
> =
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
771
|
+
TOverrides extends ViewSchemaPartial | undefined = {},
|
|
772
|
+
> = TOverrides extends ViewSchemaPartial
|
|
773
|
+
? {
|
|
774
|
+
uniforms: Prettify<
|
|
775
|
+
DeepMerge<
|
|
776
|
+
[ShallowMerge<[TVertex['uniforms'], TFragment['uniforms']]>, TOverrides['uniforms']]
|
|
777
|
+
>
|
|
778
|
+
>
|
|
779
|
+
attributes: Prettify<
|
|
780
|
+
DeepMerge<
|
|
781
|
+
[ShallowMerge<[TVertex['attributes'], TFragment['attributes']]>, TOverrides['attributes']]
|
|
782
|
+
>
|
|
783
|
+
>
|
|
784
|
+
interleavedAttributes: Prettify<
|
|
785
|
+
DeepMerge<
|
|
786
|
+
[
|
|
787
|
+
ShallowMerge<[TVertex['interleavedAttributes'], TFragment['interleavedAttributes']]>,
|
|
788
|
+
TOverrides['interleavedAttributes'],
|
|
789
|
+
]
|
|
790
|
+
>
|
|
791
|
+
>
|
|
792
|
+
}
|
|
793
|
+
: {
|
|
794
|
+
uniforms: Prettify<ShallowMerge<[TVertex['uniforms'], TFragment['uniforms']]>>
|
|
795
|
+
attributes: Prettify<ShallowMerge<[TVertex['attributes'], TFragment['attributes']]>>
|
|
796
|
+
interleavedAttributes: Prettify<
|
|
797
|
+
ShallowMerge<[TVertex['interleavedAttributes'], TFragment['interleavedAttributes']]>
|
|
798
|
+
>
|
|
799
|
+
}
|
|
786
800
|
|
|
787
801
|
export type CompileResult<
|
|
788
802
|
TVertex extends GLSL,
|
|
789
803
|
TFragment extends GLSL,
|
|
790
|
-
TOverrideSchema extends ViewSchemaPartial,
|
|
804
|
+
TOverrideSchema extends ViewSchemaPartial | undefined,
|
|
791
805
|
> =
|
|
792
806
|
MergeGLSLSchema<
|
|
793
807
|
GLSLToSchema<TVertex>,
|