@bigmistqke/view.gl 0.1.1 → 0.1.2
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 +9 -0
- package/.github/ISSUE_TEMPLATE/bug-report.yml +31 -0
- package/.github/ISSUE_TEMPLATE/feature-request.yml +27 -0
- package/.github/workflows/codeql.yml +46 -0
- package/.github/workflows/deploy-page.yml +38 -0
- package/.github/workflows/format.yml +40 -0
- package/README.md +92 -35
- package/dev/404.html +19 -0
- package/dev/dist/404.html +19 -0
- package/dev/dist/assets/bezier-DuLTb2d1.js +294 -0
- package/dev/dist/assets/game_of_life-D7qHdFcv.js +202 -0
- package/dev/dist/assets/grid-Ie22U_9K.js +173 -0
- package/dev/dist/assets/index-0qrXMlfv.js +109 -0
- package/dev/dist/assets/index-C2N3u8wj.css +12 -0
- package/dev/dist/assets/main-BZ1N6pp6.js +32 -0
- package/dev/dist/assets/overview-DAxtMIw5.js +78 -0
- package/dev/dist/assets/pix_sim-DIhzM_vu.js +501 -0
- package/dev/dist/assets/symbol-BouRL-Ni.js +65 -0
- package/dev/dist/assets/tag-C_bg62fD.js +516 -0
- package/dev/dist/assets/tetris-IMnkSi9p.js +344 -0
- package/dev/dist/assets/utils-CvCgsM08.js +50 -0
- package/dev/dist/index.html +51 -0
- package/dev/index.html +39 -10
- package/dev/{bezier.ts → src/examples/bezier.ts} +1 -1
- package/dev/{grid.ts → src/examples/grid.ts} +1 -1
- package/dev/{pix_sim.ts → src/examples/pix_sim.ts} +112 -97
- package/dev/src/examples/symbol.ts +79 -0
- package/dev/{tetris.ts → src/examples/tetris.ts} +1 -0
- package/dev/src/index.css +12 -0
- package/dev/src/index.ts +69 -0
- package/dev/{utils.ts → src/utils.ts} +8 -2
- package/dev/vite.config.ts +9 -1
- package/dist/index.d.mts +3 -2
- package/dist/index.mjs +81 -27
- package/dist/index.mjs.map +1 -1
- package/dist/tag.d.mts +9 -9
- package/dist/tag.mjs +46 -17
- package/dist/tag.mjs.map +1 -1
- package/dist/{types-DxpS9Bae.d.mts → types-DoFAJoh-.d.mts} +18 -18
- package/package.json +20 -7
- package/src/index.ts +39 -17
- package/src/tag.ts +47 -39
- package/src/types.ts +24 -24
- package/src/{utils.ts → utils/index.ts} +39 -14
- package/src/utils/object.ts +27 -0
- package/test/index.test.ts +1017 -0
- package/test/mocks/webgl.ts +248 -0
- package/test/setup.ts +13 -0
- package/test/tag.test.ts +790 -0
- package/vitest.config.ts +15 -0
- /package/dev/{game_of_life.ts → src/examples/game_of_life.ts} +0 -0
- /package/dev/{index.ts → src/examples/overview.ts} +0 -0
|
@@ -2,6 +2,7 @@ import { FramebufferOptions } from 'src/types'
|
|
|
2
2
|
import { createFramebuffer } from 'src/utils'
|
|
3
3
|
import { view } from 'view.gl'
|
|
4
4
|
import { attribute, compile, glsl, uniform } from 'view.gl/tag'
|
|
5
|
+
import { createElement } from '../utils'
|
|
5
6
|
|
|
6
7
|
export const MATERIALS = {
|
|
7
8
|
SAND: {
|
|
@@ -21,126 +22,140 @@ export const MATERIALS = {
|
|
|
21
22
|
const MATERIAL_SIZE = Object.keys(MATERIALS).length
|
|
22
23
|
|
|
23
24
|
let playing = false
|
|
24
|
-
let currentMaterial = MATERIALS.SAND.id
|
|
25
|
-
|
|
26
|
-
const canvas = document.createElement('canvas')
|
|
27
|
-
const gl = canvas.getContext('webgl2', { antialias: false })!
|
|
28
|
-
if (!gl) {
|
|
29
|
-
throw new Error('WebGL not supported')
|
|
30
|
-
}
|
|
25
|
+
let currentMaterial: (typeof MATERIALS)[keyof typeof MATERIALS]['id'] = MATERIALS.SAND.id
|
|
31
26
|
|
|
32
27
|
// Create UI container
|
|
33
|
-
const container =
|
|
34
|
-
|
|
28
|
+
const container = createElement('div', {
|
|
29
|
+
style: 'display: flex; flex-direction: column; align-items: center; gap: 10px;',
|
|
30
|
+
parentElement: document.body,
|
|
31
|
+
})
|
|
35
32
|
|
|
36
33
|
// Create material buttons
|
|
37
|
-
const buttonContainer =
|
|
38
|
-
|
|
34
|
+
const buttonContainer = createElement('div', {
|
|
35
|
+
style: 'display: flex; gap: 10px; margin-bottom: 10px;',
|
|
36
|
+
parentElement: container,
|
|
37
|
+
})
|
|
39
38
|
|
|
40
39
|
Object.entries(MATERIALS).forEach(([name, material]) => {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
createElement('button', {
|
|
41
|
+
textContent: name.toLowerCase(),
|
|
42
|
+
'data-name': name,
|
|
43
|
+
'data-id': material.id.toString(),
|
|
44
|
+
style: `padding: 5px 10px;
|
|
45
45
|
font-size: 14px;
|
|
46
|
-
font-family:
|
|
46
|
+
font-family: arial;
|
|
47
47
|
cursor: pointer;
|
|
48
|
+
color: black;
|
|
48
49
|
background: ${
|
|
49
50
|
currentMaterial === material.id
|
|
50
51
|
? `rgb(${material.color.map(c => Math.floor(c * 255)).join(',')})`
|
|
51
|
-
: '
|
|
52
|
+
: `rgba(${material.color.map(c => Math.floor(c * 255)).join(',')}, 0.75)`
|
|
52
53
|
};
|
|
53
54
|
border-color: ${name === 'SAND' ? 'black' : 'white'};
|
|
54
55
|
border: 2px solid rgb(${material.color.map(c => Math.floor(c * 255)).join(',')});
|
|
55
56
|
border-radius: 2px;
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
57
|
+
`,
|
|
58
|
+
onclick() {
|
|
59
|
+
currentMaterial = material.id
|
|
60
|
+
// Update all button borders
|
|
61
|
+
buttonContainer.querySelectorAll('button').forEach(btn => {
|
|
62
|
+
const name = btn.getAttribute('data-name') as keyof typeof MATERIALS
|
|
63
|
+
const id = btn.getAttribute('data-id')
|
|
64
|
+
if (id === currentMaterial.toString()) {
|
|
65
|
+
btn.style.background = `rgb(${MATERIALS[name].color
|
|
66
|
+
.map(c => Math.floor(c * 255))
|
|
67
|
+
.join(',')})`
|
|
68
|
+
} else {
|
|
69
|
+
btn.style.background = `rgba(${MATERIALS[name].color
|
|
70
|
+
.map(c => Math.floor(c * 255))
|
|
71
|
+
.join(',')}, 0.75)`
|
|
72
|
+
}
|
|
73
|
+
})
|
|
74
|
+
},
|
|
75
|
+
parentElement: buttonContainer,
|
|
76
|
+
})
|
|
68
77
|
})
|
|
69
78
|
|
|
70
|
-
container.appendChild(canvas)
|
|
71
|
-
container.appendChild(buttonContainer)
|
|
72
|
-
document.body.append(container)
|
|
73
|
-
|
|
74
79
|
function spray() {
|
|
75
80
|
return Math.floor(Math.random() * 8) * (Math.random() < 0.5 ? 1 : -1)
|
|
76
81
|
}
|
|
77
82
|
|
|
78
|
-
canvas
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
83
|
+
const canvas = createElement('canvas', {
|
|
84
|
+
parentElement: container,
|
|
85
|
+
onmousedown() {
|
|
86
|
+
const rect = canvas.getBoundingClientRect()
|
|
87
|
+
const controller = new AbortController()
|
|
88
|
+
// playing = false
|
|
89
|
+
window.addEventListener(
|
|
90
|
+
'mousemove',
|
|
91
|
+
event => {
|
|
92
|
+
const x = Math.floor((event.clientX - rect.left + spray()) * (canvas.width / rect.width))
|
|
93
|
+
const y = Math.floor(
|
|
94
|
+
(rect.bottom - event.clientY + spray()) * (canvas.height / rect.height),
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
const dimensions = [8, 8] as const
|
|
98
|
+
|
|
99
|
+
// Encode selected material using bit encoding
|
|
100
|
+
const data = new Uint8Array(
|
|
101
|
+
(function* () {
|
|
102
|
+
for (let i = 0; i < dimensions[0] * dimensions[1]; i++) {
|
|
103
|
+
yield (currentMaterial & 1) * 255 // Red channel (bit 0)
|
|
104
|
+
yield ((currentMaterial >> 1) & 1) * 255 // Green channel (bit 1)
|
|
105
|
+
yield ((currentMaterial >> 2) & 1) * 255 // Blue channel (bit 2)
|
|
106
|
+
yield 255 // Alpha channel
|
|
107
|
+
}
|
|
108
|
+
})(),
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
// Update both read and write textures
|
|
112
|
+
gl.bindTexture(gl.TEXTURE_2D, read.texture)
|
|
113
|
+
gl.texSubImage2D(
|
|
114
|
+
gl.TEXTURE_2D,
|
|
115
|
+
0,
|
|
116
|
+
Math.max(0, Math.min(WIDTH - dimensions[0], x)),
|
|
117
|
+
Math.max(0, Math.min(HEIGHT - dimensions[1], y)),
|
|
118
|
+
dimensions[0],
|
|
119
|
+
dimensions[1],
|
|
120
|
+
gl.RGBA,
|
|
121
|
+
gl.UNSIGNED_BYTE,
|
|
122
|
+
data,
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
gl.bindTexture(gl.TEXTURE_2D, write.texture)
|
|
126
|
+
gl.texSubImage2D(
|
|
127
|
+
gl.TEXTURE_2D,
|
|
128
|
+
0,
|
|
129
|
+
Math.max(0, Math.min(WIDTH - dimensions[0], x)),
|
|
130
|
+
Math.max(0, Math.min(HEIGHT - dimensions[1], y)),
|
|
131
|
+
dimensions[0],
|
|
132
|
+
dimensions[1],
|
|
133
|
+
gl.RGBA,
|
|
134
|
+
gl.UNSIGNED_BYTE,
|
|
135
|
+
data,
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
render()
|
|
139
|
+
},
|
|
140
|
+
controller,
|
|
141
|
+
)
|
|
142
|
+
window.addEventListener(
|
|
143
|
+
'mouseup',
|
|
144
|
+
() => {
|
|
145
|
+
controller.abort()
|
|
146
|
+
// playing = true
|
|
147
|
+
// animate()
|
|
148
|
+
},
|
|
149
|
+
controller,
|
|
150
|
+
)
|
|
151
|
+
},
|
|
142
152
|
})
|
|
143
153
|
|
|
154
|
+
const gl = canvas.getContext('webgl2', { antialias: false })!
|
|
155
|
+
if (!gl) {
|
|
156
|
+
throw new Error('WebGL not supported')
|
|
157
|
+
}
|
|
158
|
+
|
|
144
159
|
canvas.width = 256 * 2
|
|
145
160
|
canvas.height = 256 * 2
|
|
146
161
|
const WIDTH = canvas.width
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { view } from 'view.gl'
|
|
2
|
+
import { attribute, compile, glsl, uniform } from 'view.gl/tag'
|
|
3
|
+
import { createElement } from '../utils'
|
|
4
|
+
|
|
5
|
+
const canvas = createElement('canvas', {
|
|
6
|
+
width: window.innerWidth,
|
|
7
|
+
height: window.innerHeight,
|
|
8
|
+
parentElement: document.body,
|
|
9
|
+
style: 'width: 100%; height: 100%',
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
new ResizeObserver(() => {
|
|
13
|
+
canvas.width = window.innerWidth
|
|
14
|
+
canvas.height = window.innerHeight
|
|
15
|
+
gl.viewport(0, 0, canvas.width, canvas.height)
|
|
16
|
+
draw(performance.now())
|
|
17
|
+
}).observe(canvas)
|
|
18
|
+
|
|
19
|
+
const gl = canvas.getContext('webgl2')!
|
|
20
|
+
gl.viewport(0, 0, canvas.width, canvas.height)
|
|
21
|
+
|
|
22
|
+
const vertex = glsl`
|
|
23
|
+
precision mediump float;
|
|
24
|
+
|
|
25
|
+
${attribute.vec2('a_vertex')}
|
|
26
|
+
${uniform.float('u_time')}
|
|
27
|
+
|
|
28
|
+
void main() {
|
|
29
|
+
float s = sin(u_time);
|
|
30
|
+
float c = cos(u_time);
|
|
31
|
+
mat2 rotation = mat2(
|
|
32
|
+
c, -s,
|
|
33
|
+
s, c
|
|
34
|
+
);
|
|
35
|
+
vec2 position = a_vertex * rotation;
|
|
36
|
+
gl_Position = vec4(position, 0.0, 1.0);
|
|
37
|
+
}`
|
|
38
|
+
|
|
39
|
+
const u_color = Symbol('color')
|
|
40
|
+
|
|
41
|
+
const fragment = glsl`
|
|
42
|
+
precision mediump float;
|
|
43
|
+
|
|
44
|
+
${uniform.vec3(u_color)}
|
|
45
|
+
|
|
46
|
+
void main() {
|
|
47
|
+
gl_FragColor = vec4(${u_color}, 1.0);
|
|
48
|
+
}`
|
|
49
|
+
|
|
50
|
+
const { program, schema } = compile(gl, vertex, fragment)
|
|
51
|
+
const { attributes, uniforms } = view(gl, program, schema)
|
|
52
|
+
|
|
53
|
+
gl.useProgram(program)
|
|
54
|
+
|
|
55
|
+
uniforms[u_color].set(0, 255, 0)
|
|
56
|
+
|
|
57
|
+
// Create triangle vertex buffer
|
|
58
|
+
attributes.a_vertex
|
|
59
|
+
.set(
|
|
60
|
+
new Float32Array([
|
|
61
|
+
// top
|
|
62
|
+
0.0, 1.0,
|
|
63
|
+
// bottom left
|
|
64
|
+
-1.0, -1.0,
|
|
65
|
+
// bottom right
|
|
66
|
+
1.0, -1.0,
|
|
67
|
+
]),
|
|
68
|
+
)
|
|
69
|
+
.bind()
|
|
70
|
+
|
|
71
|
+
function draw(delta: number) {
|
|
72
|
+
requestAnimationFrame(draw)
|
|
73
|
+
|
|
74
|
+
// Set uniform
|
|
75
|
+
uniforms.u_time.set(delta / 1_000)
|
|
76
|
+
|
|
77
|
+
gl.drawArraysInstanced(gl.TRIANGLES, 0, 3, 100)
|
|
78
|
+
}
|
|
79
|
+
requestAnimationFrame(draw)
|
package/dev/src/index.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import css from './index.css?url'
|
|
2
|
+
import { createElement } from './utils'
|
|
3
|
+
|
|
4
|
+
const iframe = document.querySelector('iframe')!
|
|
5
|
+
const nav = document.querySelector('nav')!
|
|
6
|
+
|
|
7
|
+
createElement('h3', { innerText: 'Examples', parentElement: nav })
|
|
8
|
+
|
|
9
|
+
const urls = Object.fromEntries(
|
|
10
|
+
Object.entries(import.meta.glob('./examples/*.ts', { eager: false })).map(([key, entry]) => {
|
|
11
|
+
const name = key.split('/').pop()!.replace('.ts', '')
|
|
12
|
+
const chunk = entry.toString().match(/import\(['"]([^'"]+)['"]/)![1]!
|
|
13
|
+
return [name, chunk] as const
|
|
14
|
+
}),
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
Object.entries(urls).forEach(([name, localUrl]) => {
|
|
18
|
+
createElement('button', {
|
|
19
|
+
onclick(event) {
|
|
20
|
+
event.preventDefault()
|
|
21
|
+
load(name, localUrl)
|
|
22
|
+
},
|
|
23
|
+
innerHTML: name,
|
|
24
|
+
parentElement: nav,
|
|
25
|
+
'data-route': name,
|
|
26
|
+
})
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
function load(name: string, url: string) {
|
|
30
|
+
// Use hash routing instead of pushState for GitHub Pages compatibility
|
|
31
|
+
window.location.hash = name
|
|
32
|
+
|
|
33
|
+
URL.revokeObjectURL(iframe.src)
|
|
34
|
+
|
|
35
|
+
nav.querySelectorAll('button').forEach(button => {
|
|
36
|
+
if (button.getAttribute('data-route') === name) {
|
|
37
|
+
button.classList.add('active')
|
|
38
|
+
} else {
|
|
39
|
+
button.classList.remove('active')
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
iframe.src = URL.createObjectURL(
|
|
44
|
+
new Blob(
|
|
45
|
+
[
|
|
46
|
+
`<head>
|
|
47
|
+
<link rel="stylesheet" href="${new URL(css, import.meta.url).href}"></link>
|
|
48
|
+
<script type="module" src="${new URL(url, import.meta.url).href}"></script></head>`,
|
|
49
|
+
],
|
|
50
|
+
{
|
|
51
|
+
type: 'text/html',
|
|
52
|
+
},
|
|
53
|
+
),
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Handle hash-based routing
|
|
58
|
+
const hash = window.location.hash.slice(1) // Remove #
|
|
59
|
+
if (hash && hash in urls) {
|
|
60
|
+
load(hash, urls[hash]!)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Listen for hash changes
|
|
64
|
+
window.addEventListener('hashchange', () => {
|
|
65
|
+
const hash = window.location.hash.slice(1)
|
|
66
|
+
if (hash && hash in urls) {
|
|
67
|
+
load(hash, urls[hash]!)
|
|
68
|
+
}
|
|
69
|
+
})
|
|
@@ -48,11 +48,17 @@ export function createElement<T extends keyof HTMLElementTagNameMap>(
|
|
|
48
48
|
{
|
|
49
49
|
parentElement,
|
|
50
50
|
...options
|
|
51
|
-
}: Partial<Omit<HTMLElementTagNameMap[T], 'style'> & { style: string }>
|
|
51
|
+
}: Partial<Omit<HTMLElementTagNameMap[T], 'style'> & { style: string }> &
|
|
52
|
+
Record<`data-${string}`, string> = {},
|
|
52
53
|
) {
|
|
53
54
|
const element = document.createElement(tag)
|
|
55
|
+
|
|
54
56
|
for (const key in options) {
|
|
55
|
-
|
|
57
|
+
if (key.startsWith('data-')) {
|
|
58
|
+
element.setAttribute(key, options[key])
|
|
59
|
+
} else {
|
|
60
|
+
element[key] = options[key]
|
|
61
|
+
}
|
|
56
62
|
}
|
|
57
63
|
|
|
58
64
|
;(parentElement ?? document.body).appendChild(element)
|
package/dev/vite.config.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { defineConfig } from 'vite'
|
|
|
2
2
|
import tsconfigPaths from 'vite-tsconfig-paths'
|
|
3
3
|
|
|
4
4
|
export default defineConfig({
|
|
5
|
-
base: '
|
|
5
|
+
base: process.env.GITHUB_ACTIONS ? 'https://bigmistqke.github.io/view.gl/' : undefined,
|
|
6
6
|
assetsInclude: ['assets/**/*'],
|
|
7
7
|
plugins: [
|
|
8
8
|
tsconfigPaths(),
|
|
@@ -38,5 +38,13 @@ export default defineConfig({
|
|
|
38
38
|
build: {
|
|
39
39
|
target: 'esnext',
|
|
40
40
|
minify: false,
|
|
41
|
+
rollupOptions: {
|
|
42
|
+
input: {
|
|
43
|
+
main: './dev/index.html',
|
|
44
|
+
index: './dev/src/index.ts', // Separate entry for index.ts
|
|
45
|
+
utils: './dev/src/utils.ts', // Separate entry for utils.ts
|
|
46
|
+
404: './dev/404.html',
|
|
47
|
+
},
|
|
48
|
+
},
|
|
41
49
|
},
|
|
42
50
|
})
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { V as ViewSchema, G as GL, a as ViewOptions, b as View, U as UniformSchema, c as UniformView, A as AttributeSchema, d as AttributeView, I as InterleavedAttributeSchema, e as InterleavedAttributeView, B as BufferSchema, f as BufferView } from './types-
|
|
1
|
+
import { V as ViewSchema, G as GL, a as ViewOptions, b as View, U as UniformSchema, c as UniformView, A as AttributeSchema, d as AttributeView, I as InterleavedAttributeSchema, e as InterleavedAttributeView, B as BufferSchema, f as BufferView } from './types-DoFAJoh-.mjs';
|
|
2
2
|
|
|
3
|
+
declare function toID(key: string | number | symbol): any;
|
|
3
4
|
/**********************************************************************************/
|
|
4
5
|
/**********************************************************************************/
|
|
5
6
|
declare function view<T extends ViewSchema>(gl: GL, program: WebGLProgram, schema: T, options?: ViewOptions): View<T>;
|
|
@@ -14,4 +15,4 @@ declare function interleavedAttributeView<T extends InterleavedAttributeSchema>(
|
|
|
14
15
|
/**********************************************************************************/
|
|
15
16
|
declare function bufferView<T extends BufferSchema>(gl: GL, schema: T, { signal }?: ViewOptions): BufferView<T>;
|
|
16
17
|
|
|
17
|
-
export { attributeView, bufferView, interleavedAttributeView, uniformView, view };
|
|
18
|
+
export { attributeView, bufferView, interleavedAttributeView, toID, uniformView, view };
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __export = (target, all) => {
|
|
3
|
+
for (var name2 in all)
|
|
4
|
+
__defProp(target, name2, { get: all[name2], enumerable: true });
|
|
5
|
+
};
|
|
6
|
+
|
|
1
7
|
// src/features.ts
|
|
2
8
|
var INSTANCED_ARRAYS_WRAPPER_MAP = /* @__PURE__ */ new WeakMap();
|
|
3
9
|
function getInstancedArrays(gl) {
|
|
@@ -30,12 +36,32 @@ function getVertexArrayObject(gl) {
|
|
|
30
36
|
return wrapper;
|
|
31
37
|
}
|
|
32
38
|
|
|
33
|
-
// src/utils.ts
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
)
|
|
39
|
+
// src/utils/object.ts
|
|
40
|
+
var object_exports = {};
|
|
41
|
+
__export(object_exports, {
|
|
42
|
+
forEach: () => forEach,
|
|
43
|
+
map: () => map
|
|
44
|
+
});
|
|
45
|
+
function forEach(value, callback) {
|
|
46
|
+
let index2 = 0;
|
|
47
|
+
for (const key in value) {
|
|
48
|
+
callback(value[key], key, index2);
|
|
49
|
+
index2++;
|
|
50
|
+
}
|
|
51
|
+
for (const key of Object.getOwnPropertySymbols(value)) {
|
|
52
|
+
callback(value[key], key, index2);
|
|
53
|
+
index2++;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function map(value, callback) {
|
|
57
|
+
const result = {};
|
|
58
|
+
forEach(value, (value2, key, index2) => {
|
|
59
|
+
result[key] = callback(value2, key, index2);
|
|
60
|
+
});
|
|
61
|
+
return result;
|
|
38
62
|
}
|
|
63
|
+
|
|
64
|
+
// src/utils/index.ts
|
|
39
65
|
function assertedNotNullish(value, message) {
|
|
40
66
|
if (value === void 0 || value === null) throw new Error(message);
|
|
41
67
|
return value;
|
|
@@ -71,17 +97,47 @@ var kindToSize = (kind) => {
|
|
|
71
97
|
switch (kind[0]) {
|
|
72
98
|
case "m":
|
|
73
99
|
const [a, b] = kind.match(/\d+/g).map(Number);
|
|
74
|
-
return a * (b
|
|
100
|
+
return a * (b ?? a);
|
|
75
101
|
case "v":
|
|
76
|
-
|
|
102
|
+
case "i":
|
|
103
|
+
case "b":
|
|
104
|
+
case "u":
|
|
105
|
+
const match = kind.match(/\d/);
|
|
106
|
+
return match ? +match[0] : 1;
|
|
77
107
|
default:
|
|
78
108
|
return 1;
|
|
79
109
|
}
|
|
80
110
|
};
|
|
81
111
|
var isMatKind = (kind) => kind.includes("mat");
|
|
82
112
|
var isSamplerKind = (kind) => kind.includes("sampler");
|
|
113
|
+
function createUpsertMap(constructor) {
|
|
114
|
+
const map2 = new (constructor ?? Map)();
|
|
115
|
+
return Object.assign(map2, {
|
|
116
|
+
getOrInsert(key, value) {
|
|
117
|
+
let result = map2.get(key);
|
|
118
|
+
if (result) {
|
|
119
|
+
return result;
|
|
120
|
+
}
|
|
121
|
+
result = value();
|
|
122
|
+
map2.set(key, result);
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
}
|
|
83
127
|
|
|
84
128
|
// src/index.ts
|
|
129
|
+
var index = 0;
|
|
130
|
+
var PREFIX = "VIEW_GL_ALIAS";
|
|
131
|
+
var SYMBOL_MAP = createUpsertMap(WeakMap);
|
|
132
|
+
function toID(key) {
|
|
133
|
+
if (typeof key === "string") {
|
|
134
|
+
return key;
|
|
135
|
+
}
|
|
136
|
+
if (typeof key === "symbol") {
|
|
137
|
+
return SYMBOL_MAP.getOrInsert(key, () => `${PREFIX}_${index++}`);
|
|
138
|
+
}
|
|
139
|
+
return key.toString();
|
|
140
|
+
}
|
|
85
141
|
function view(gl, program, schema, options) {
|
|
86
142
|
return {
|
|
87
143
|
uniforms: !schema.uniforms ? void 0 : uniformView(gl, program, schema.uniforms),
|
|
@@ -91,7 +147,8 @@ function view(gl, program, schema, options) {
|
|
|
91
147
|
};
|
|
92
148
|
}
|
|
93
149
|
function uniformView(gl, program, schema) {
|
|
94
|
-
return
|
|
150
|
+
return object_exports.map(schema, ({ kind, size }, key) => {
|
|
151
|
+
const name2 = toID(key);
|
|
95
152
|
const location = gl.getUniformLocation(program, name2);
|
|
96
153
|
if (isSamplerKind(kind)) {
|
|
97
154
|
return {
|
|
@@ -124,9 +181,10 @@ function handleAttribute(gl, location, size, stride, offset, type, instanced) {
|
|
|
124
181
|
}
|
|
125
182
|
}
|
|
126
183
|
function attributeView(gl, program, schema, { signal } = {}) {
|
|
127
|
-
const attributes =
|
|
184
|
+
const attributes = object_exports.map(
|
|
128
185
|
schema,
|
|
129
|
-
({ kind, instanced, buffer = assertedNotNullish(gl.createBuffer()) },
|
|
186
|
+
({ kind, instanced, buffer = assertedNotNullish(gl.createBuffer()) }, key) => {
|
|
187
|
+
const name2 = toID(key);
|
|
130
188
|
const location = gl.getAttribLocation(program, name2);
|
|
131
189
|
if (location < 0) {
|
|
132
190
|
throw new Error(`Attribute '${name2}' not found`);
|
|
@@ -151,27 +209,26 @@ function attributeView(gl, program, schema, { signal } = {}) {
|
|
|
151
209
|
}
|
|
152
210
|
);
|
|
153
211
|
signal?.addEventListener("abort", function dispose() {
|
|
154
|
-
|
|
155
|
-
attributes[name2].dispose();
|
|
156
|
-
}
|
|
212
|
+
object_exports.forEach(attributes, (value) => value.dispose());
|
|
157
213
|
});
|
|
158
214
|
return attributes;
|
|
159
215
|
}
|
|
160
216
|
function interleavedAttributeView(gl, program, schema, { signal } = {}) {
|
|
161
|
-
const interleavedAttributes =
|
|
162
|
-
let
|
|
217
|
+
const interleavedAttributes = object_exports.map(schema, ({ layout, instanced }) => {
|
|
218
|
+
let index2 = 0;
|
|
163
219
|
const handles = layout.map((layout2) => {
|
|
164
|
-
const
|
|
220
|
+
const name2 = toID(layout2.key);
|
|
221
|
+
const location = gl.getAttribLocation(program, name2);
|
|
165
222
|
if (location < 0) {
|
|
166
|
-
throw new Error(`Attribute '${
|
|
223
|
+
throw new Error(`Attribute '${name2}' not found`);
|
|
167
224
|
}
|
|
168
225
|
const size = kindToSize(layout2.kind);
|
|
169
|
-
const offset =
|
|
226
|
+
const offset = index2;
|
|
170
227
|
const type = layout2.kind.startsWith("i") ? "INT" : "FLOAT";
|
|
171
|
-
|
|
228
|
+
index2 += size * 4;
|
|
172
229
|
return () => handleAttribute(gl, location, size, stride, offset, type, instanced);
|
|
173
230
|
});
|
|
174
|
-
const stride =
|
|
231
|
+
const stride = index2;
|
|
175
232
|
const buffer = assertedNotNullish(gl.createBuffer());
|
|
176
233
|
let vao = void 0;
|
|
177
234
|
const feature = getVertexArrayObject(gl);
|
|
@@ -231,14 +288,12 @@ function interleavedAttributeView(gl, program, schema, { signal } = {}) {
|
|
|
231
288
|
};
|
|
232
289
|
});
|
|
233
290
|
signal?.addEventListener("abort", function dispose() {
|
|
234
|
-
|
|
235
|
-
interleavedAttributes[name2].dispose();
|
|
236
|
-
}
|
|
291
|
+
object_exports.forEach(interleavedAttributes, (value) => value.dispose());
|
|
237
292
|
});
|
|
238
293
|
return interleavedAttributes;
|
|
239
294
|
}
|
|
240
295
|
function bufferView(gl, schema, { signal } = {}) {
|
|
241
|
-
const buffers =
|
|
296
|
+
const buffers = object_exports.map(schema, ({ target = "ARRAY_BUFFER", usage = "STATIC_DRAW" }) => {
|
|
242
297
|
const buffer = assertedNotNullish(gl.createBuffer());
|
|
243
298
|
return {
|
|
244
299
|
bind() {
|
|
@@ -254,9 +309,7 @@ function bufferView(gl, schema, { signal } = {}) {
|
|
|
254
309
|
};
|
|
255
310
|
});
|
|
256
311
|
signal?.addEventListener("abort", function dispose() {
|
|
257
|
-
|
|
258
|
-
buffers[name2].dispose();
|
|
259
|
-
}
|
|
312
|
+
object_exports.forEach(buffers, (value) => value.dispose());
|
|
260
313
|
});
|
|
261
314
|
return buffers;
|
|
262
315
|
}
|
|
@@ -264,6 +317,7 @@ export {
|
|
|
264
317
|
attributeView,
|
|
265
318
|
bufferView,
|
|
266
319
|
interleavedAttributeView,
|
|
320
|
+
toID,
|
|
267
321
|
uniformView,
|
|
268
322
|
view
|
|
269
323
|
};
|