glre 0.22.0 → 0.23.0
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 +11 -18
- package/dist/index.d.ts +60 -220
- package/dist/index.js +35 -37
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +35 -37
- package/dist/index.mjs.map +1 -1
- package/dist/native.d.ts +49 -5
- package/dist/native.js +35 -37
- package/dist/native.js.map +1 -1
- package/dist/native.mjs +35 -37
- package/dist/native.mjs.map +1 -1
- package/dist/react.d.ts +1 -2
- package/dist/react.js +35 -37
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +35 -37
- package/dist/react.mjs.map +1 -1
- package/dist/solid.d.ts +1 -2
- package/dist/solid.js +35 -37
- package/dist/solid.js.map +1 -1
- package/dist/solid.mjs +35 -37
- package/dist/solid.mjs.map +1 -1
- package/package.json +5 -1
- package/src/code/glsl.ts +7 -45
- package/src/code/wgsl.ts +10 -46
- package/src/index.ts +31 -29
- package/src/native.ts +9 -4
- package/src/node/cache.ts +3 -10
- package/src/node/const.ts +2 -19
- package/src/node/conv.ts +6 -17
- package/src/node/index.ts +3 -6
- package/src/node/node.ts +8 -22
- package/src/node/uniform.ts +6 -13
- package/src/react.ts +0 -1
- package/src/solid.ts +0 -1
- package/src/types.ts +20 -21
- package/src/{utils.ts → utils/helpers.ts} +0 -9
- package/src/utils/pipeline.ts +128 -0
- package/src/utils/program.ts +94 -0
- package/src/webgl.ts +78 -0
- package/src/webgpu.ts +70 -0
- package/src/webgl/buffer.ts +0 -78
- package/src/webgl/index.ts +0 -79
- package/src/webgl/program.ts +0 -61
- package/src/webgl/shader.ts +0 -60
- package/src/webgl/texture.ts +0 -93
- package/src/webgpu/buffer.ts +0 -96
- package/src/webgpu/device.ts +0 -91
- package/src/webgpu/index.ts +0 -40
- package/src/webgpu/pipeline.ts +0 -94
- package/src/webgpu/texture.ts +0 -139
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { GPUContext, GPUDevice, GPUPipeline } from '../types'
|
|
2
|
+
|
|
3
|
+
export const initWebGPUDevice = async (el: HTMLCanvasElement) => {
|
|
4
|
+
const gpu = (navigator as any).gpu
|
|
5
|
+
if (!gpu) return null
|
|
6
|
+
const adapter = await gpu.requestAdapter()
|
|
7
|
+
if (!adapter) return null
|
|
8
|
+
const device = await adapter.requestDevice()
|
|
9
|
+
const context = el.getContext('webgpu') as GPUContext
|
|
10
|
+
if (!context) return null
|
|
11
|
+
const format = gpu.getPreferredCanvasFormat()
|
|
12
|
+
context.configure({ device, format })
|
|
13
|
+
return { device, context, format }
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const defaultVertexWGSL = `
|
|
17
|
+
@vertex
|
|
18
|
+
fn main(@builtin(vertex_index) vertex_index: u32) -> @builtin(position) vec4f {
|
|
19
|
+
let x = f32(vertex_index % 2u) * 4.0 - 1.0;
|
|
20
|
+
let y = f32(vertex_index / 2u) * 4.0 - 1.0;
|
|
21
|
+
return vec4f(x, y, 0.0, 1.0);
|
|
22
|
+
}
|
|
23
|
+
`
|
|
24
|
+
|
|
25
|
+
const defaultFragmentWGSL = `
|
|
26
|
+
@fragment
|
|
27
|
+
fn main(@builtin(position) position: vec4f) -> @location(0) vec4f {
|
|
28
|
+
return vec4f(position.xy / vec2f(1280, 800), 0.0, 1.0);
|
|
29
|
+
}
|
|
30
|
+
`
|
|
31
|
+
|
|
32
|
+
export const createRenderPipeline = (
|
|
33
|
+
device: GPUDevice,
|
|
34
|
+
format: string,
|
|
35
|
+
vs = defaultVertexWGSL,
|
|
36
|
+
fs = defaultFragmentWGSL,
|
|
37
|
+
buffers: any[]
|
|
38
|
+
) => {
|
|
39
|
+
return device.createRenderPipeline({
|
|
40
|
+
vertex: {
|
|
41
|
+
module: device.createShaderModule({ code: vs.trim() }),
|
|
42
|
+
entryPoint: 'main',
|
|
43
|
+
buffers,
|
|
44
|
+
},
|
|
45
|
+
fragment: {
|
|
46
|
+
module: device.createShaderModule({ code: fs.trim() }),
|
|
47
|
+
entryPoint: 'main',
|
|
48
|
+
targets: [{ format }],
|
|
49
|
+
},
|
|
50
|
+
layout: 'auto',
|
|
51
|
+
primitive: { topology: 'triangle-list' },
|
|
52
|
+
}) as GPUPipeline
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export const createDescriptor = (c: GPUContext) => {
|
|
56
|
+
return {
|
|
57
|
+
colorAttachments: [
|
|
58
|
+
{
|
|
59
|
+
view: c.getCurrentTexture().createView(),
|
|
60
|
+
clearValue: { r: 0, g: 0, b: 0, a: 1 },
|
|
61
|
+
loadOp: 'clear',
|
|
62
|
+
storeOp: 'store',
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
export const alignTo256 = (size: number) => Math.ceil(size / 256) * 256
|
|
68
|
+
|
|
69
|
+
export const createUniformBuffer = (device: GPUDevice, size: number) => {
|
|
70
|
+
return device.createBuffer({ size: alignTo256(size), usage: 0x40 | 0x4 }) as Buffer
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export const createVertexBuffer = (device: GPUDevice, value: number[]) => {
|
|
74
|
+
const array = new Float32Array(value)
|
|
75
|
+
const buffer = device.createBuffer({ size: array.byteLength, usage: 0x20 | 0x4 })
|
|
76
|
+
device.queue.writeBuffer(buffer, 0, array)
|
|
77
|
+
return buffer as Buffer
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export const createBindGroup = (device: GPUDevice, pipeline: GPUPipeline, entries: any[]) => {
|
|
81
|
+
const layout = pipeline.getBindGroupLayout(0)
|
|
82
|
+
return device.createBindGroup({ layout, entries })
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export const updateBindGroup = (
|
|
86
|
+
device: GPUDevice,
|
|
87
|
+
pipeline: GPUPipeline,
|
|
88
|
+
uniformBuffer: Buffer,
|
|
89
|
+
textures: any = {},
|
|
90
|
+
sampler: any = null
|
|
91
|
+
) => {
|
|
92
|
+
const entries = [{ binding: 0, resource: { buffer: uniformBuffer } }]
|
|
93
|
+
let binding = 1
|
|
94
|
+
Object.values(textures).forEach((texture: any) => {
|
|
95
|
+
entries.push({ binding: binding++, resource: texture.createView() })
|
|
96
|
+
})
|
|
97
|
+
if (sampler && Object.keys(textures).length > 0) entries.push({ binding: binding++, resource: sampler })
|
|
98
|
+
return createBindGroup(device, pipeline, entries)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export const createUniform = (device: GPUDevice, buffer: any, data: Float32Array, offset = 0) => {
|
|
102
|
+
device.queue.writeBuffer(buffer, offset, data)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export const createDeviceTexture = (device: GPUDevice, image: HTMLImageElement) => {
|
|
106
|
+
const texture = device.createTexture({
|
|
107
|
+
size: { width: image.width, height: image.height },
|
|
108
|
+
format: 'rgba8unorm',
|
|
109
|
+
usage: 0x4 | 0x2,
|
|
110
|
+
})
|
|
111
|
+
device.queue.copyExternalImageToTexture(
|
|
112
|
+
{ source: image },
|
|
113
|
+
{ texture },
|
|
114
|
+
{ width: image.width, height: image.height }
|
|
115
|
+
)
|
|
116
|
+
return texture
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export const createSampler = (device: GPUDevice) => {
|
|
120
|
+
return device.createSampler({
|
|
121
|
+
magFilter: 'linear',
|
|
122
|
+
minFilter: 'linear',
|
|
123
|
+
addressModeU: 'clamp-to-edge',
|
|
124
|
+
addressModeV: 'clamp-to-edge',
|
|
125
|
+
})
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export const getDefaultVertices = () => new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1])
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
export const defaultVertexGLSL = /* cpp */ `
|
|
2
|
+
#version 300 es
|
|
3
|
+
void main() {
|
|
4
|
+
float x = float(gl_VertexID % 2) * 4.0 - 1.0;
|
|
5
|
+
float y = float(gl_VertexID / 2) * 4.0 - 1.0;
|
|
6
|
+
gl_Position = vec4(x, y, 0.0, 1.0);
|
|
7
|
+
}
|
|
8
|
+
`
|
|
9
|
+
|
|
10
|
+
export const defaultFragmentGLSL = /* cpp */ `
|
|
11
|
+
#version 300 es
|
|
12
|
+
precision mediump float;
|
|
13
|
+
uniform vec2 iResolution;
|
|
14
|
+
out vec4 fragColor;
|
|
15
|
+
void main() {
|
|
16
|
+
fragColor = vec4(fract(gl_FragCoord.xy / iResolution), 0, 1);
|
|
17
|
+
}
|
|
18
|
+
`
|
|
19
|
+
|
|
20
|
+
export const createShader = (c: WebGLRenderingContext, source: string, type: number) => {
|
|
21
|
+
const shader = c.createShader(type)
|
|
22
|
+
if (!shader) throw new Error('Failed to create shader')
|
|
23
|
+
c.shaderSource(shader, source.trim())
|
|
24
|
+
c.compileShader(shader)
|
|
25
|
+
if (c.getShaderParameter(shader, c.COMPILE_STATUS)) return shader
|
|
26
|
+
const error = c.getShaderInfoLog(shader)
|
|
27
|
+
c.deleteShader(shader)
|
|
28
|
+
throw new Error(`Could not compile shader: ${error}`)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const createProgram = (c: WebGLRenderingContext, vs = defaultVertexGLSL, fs = defaultFragmentGLSL) => {
|
|
32
|
+
const pg = c.createProgram()
|
|
33
|
+
c.attachShader(pg, createShader(c, vs, c.VERTEX_SHADER))
|
|
34
|
+
c.attachShader(pg, createShader(c, fs, c.FRAGMENT_SHADER))
|
|
35
|
+
c.linkProgram(pg)
|
|
36
|
+
if (c.getProgramParameter(pg, c.LINK_STATUS)) return pg
|
|
37
|
+
const error = c.getProgramInfoLog(pg)
|
|
38
|
+
c.deleteProgram(pg)
|
|
39
|
+
throw new Error(`Could not link pg: ${error}`)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const createVbo = (c: WebGLRenderingContext, data: number[]) => {
|
|
43
|
+
const buffer = c.createBuffer()
|
|
44
|
+
c.bindBuffer(c.ARRAY_BUFFER, buffer)
|
|
45
|
+
c.bufferData(c.ARRAY_BUFFER, new Float32Array(data), c.STATIC_DRAW)
|
|
46
|
+
c.bindBuffer(c.ARRAY_BUFFER, null)
|
|
47
|
+
return buffer
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export const createIbo = (c: WebGLRenderingContext, data: number[]) => {
|
|
51
|
+
const buffer = c.createBuffer()
|
|
52
|
+
c.bindBuffer(c.ELEMENT_ARRAY_BUFFER, buffer)
|
|
53
|
+
c.bufferData(c.ELEMENT_ARRAY_BUFFER, new Int16Array(data), c.STATIC_DRAW)
|
|
54
|
+
c.bindBuffer(c.ELEMENT_ARRAY_BUFFER, null)
|
|
55
|
+
return buffer
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export const createAttrib = (
|
|
59
|
+
c: WebGLRenderingContext,
|
|
60
|
+
stride: number,
|
|
61
|
+
location: any,
|
|
62
|
+
vbo: WebGLBuffer,
|
|
63
|
+
ibo?: WebGLBuffer
|
|
64
|
+
) => {
|
|
65
|
+
c.bindBuffer(c.ARRAY_BUFFER, vbo)
|
|
66
|
+
c.enableVertexAttribArray(location)
|
|
67
|
+
c.vertexAttribPointer(location, stride, c.FLOAT, false, 0, 0)
|
|
68
|
+
if (ibo) c.bindBuffer(c.ELEMENT_ARRAY_BUFFER, ibo)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export const createTexture = (c: WebGLRenderingContext, img: HTMLImageElement) => {
|
|
72
|
+
const texture = c.createTexture()
|
|
73
|
+
c.bindTexture(c.TEXTURE_2D, texture)
|
|
74
|
+
c.texImage2D(c.TEXTURE_2D, 0, c.RGBA, c.RGBA, c.UNSIGNED_BYTE, img)
|
|
75
|
+
c.generateMipmap(c.TEXTURE_2D)
|
|
76
|
+
c.texParameteri(c.TEXTURE_2D, c.TEXTURE_MIN_FILTER, c.LINEAR)
|
|
77
|
+
c.texParameteri(c.TEXTURE_2D, c.TEXTURE_MAG_FILTER, c.LINEAR)
|
|
78
|
+
c.texParameteri(c.TEXTURE_2D, c.TEXTURE_WRAP_S, c.CLAMP_TO_EDGE)
|
|
79
|
+
c.texParameteri(c.TEXTURE_2D, c.TEXTURE_WRAP_T, c.CLAMP_TO_EDGE)
|
|
80
|
+
c.bindTexture(c.TEXTURE_2D, null)
|
|
81
|
+
return texture
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export const activeTexture = (
|
|
85
|
+
c: WebGLRenderingContext,
|
|
86
|
+
location: WebGLUniformLocation | null,
|
|
87
|
+
unit: number,
|
|
88
|
+
texture: WebGLTexture
|
|
89
|
+
) => {
|
|
90
|
+
if (!location) return
|
|
91
|
+
c.uniform1i(location, unit)
|
|
92
|
+
c.activeTexture(c.TEXTURE0 + unit)
|
|
93
|
+
c.bindTexture(c.TEXTURE_2D, texture)
|
|
94
|
+
}
|
package/src/webgl.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { nested } from 'reev'
|
|
2
|
+
import { glsl } from './code/glsl'
|
|
3
|
+
import { is } from './utils/helpers'
|
|
4
|
+
import type { X } from './node'
|
|
5
|
+
import type { GL } from './types'
|
|
6
|
+
import { activeTexture, createAttrib, createIbo, createProgram, createTexture, createVbo } from './utils/program'
|
|
7
|
+
|
|
8
|
+
export const webgl = async (gl: GL) => {
|
|
9
|
+
let vs = gl.vs || gl.vert || gl.vertex
|
|
10
|
+
let fs = gl.fs || gl.frag || gl.fragment
|
|
11
|
+
if (is.obj(fs)) fs = glsl(fs as X)
|
|
12
|
+
if (is.obj(vs)) vs = glsl(vs as X)
|
|
13
|
+
const c = gl.el.getContext('webgl2')!
|
|
14
|
+
const pg = createProgram(c, vs, fs)
|
|
15
|
+
|
|
16
|
+
let _activeUnit = 0
|
|
17
|
+
const activeUnits = nested(() => _activeUnit++)
|
|
18
|
+
|
|
19
|
+
const locations = nested((key, bool = false) => {
|
|
20
|
+
if (bool) return c.getAttribLocation(pg, key)
|
|
21
|
+
return c.getUniformLocation(pg, key) as WebGLUniformLocation
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
const strides = nested((_, count: number, value: number[], iboValue?: number[]) => {
|
|
25
|
+
if (iboValue) count = Math.max(...iboValue) + 1
|
|
26
|
+
const stride = value.length / count
|
|
27
|
+
if (stride !== Math.floor(stride)) console.warn(`Vertex Stride Error: count ${count} is mismatch`)
|
|
28
|
+
return Math.floor(stride)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
const uniforms = nested((key, value: number | number[]) => {
|
|
32
|
+
const loc = locations(key)
|
|
33
|
+
if (is.num(value)) return (value: any) => c.uniform1f(loc, value)
|
|
34
|
+
let l = value.length as 3
|
|
35
|
+
if (l <= 4) return (value: any) => c[`uniform${l}fv`](loc, value)
|
|
36
|
+
l = (Math.sqrt(l) << 0) as 3
|
|
37
|
+
return (value: any) => c[`uniformMatrix${l}fv`](loc, false, value)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
gl('clean', () => c.deleteProgram(pg))
|
|
41
|
+
|
|
42
|
+
gl('render', () => {
|
|
43
|
+
c.useProgram(pg)
|
|
44
|
+
gl.queue.flush()
|
|
45
|
+
c.clear(c.COLOR_BUFFER_BIT)
|
|
46
|
+
c.viewport(0, 0, ...gl.size)
|
|
47
|
+
c.drawArrays(c.TRIANGLES, 0, 3)
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
gl('_attribute', (key = '', value: number[], iboValue: number[]) => {
|
|
51
|
+
const loc = locations(key, true)
|
|
52
|
+
const vbo = createVbo(c, value)
|
|
53
|
+
const ibo = createIbo(c, iboValue)
|
|
54
|
+
const str = strides(key, gl.count, value, iboValue)
|
|
55
|
+
createAttrib(c, str, loc, vbo, ibo)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
gl('_uniform', (key: string, value: number | number[]) => {
|
|
59
|
+
uniforms(key, value)(value)
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
const _loadFn = (image: HTMLImageElement) => {
|
|
63
|
+
const loc = locations(image.alt)
|
|
64
|
+
const unit = activeUnits(image.alt)
|
|
65
|
+
const tex = createTexture(c, image)
|
|
66
|
+
activeTexture(c, loc, unit, tex)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
gl('_texture', (alt: string, src: string) => {
|
|
70
|
+
const image = new Image()
|
|
71
|
+
image.addEventListener('load', _loadFn.bind(null, image), false)
|
|
72
|
+
Object.assign(image, { src, alt, crossOrigin: 'anonymous' })
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
gl.webgl = { context: c, program: pg }
|
|
76
|
+
|
|
77
|
+
return gl
|
|
78
|
+
}
|
package/src/webgpu.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { wgsl } from './code/wgsl'
|
|
2
|
+
import { is } from './utils/helpers'
|
|
3
|
+
import {
|
|
4
|
+
createRenderPipeline,
|
|
5
|
+
createDescriptor,
|
|
6
|
+
// createUniformBuffer,
|
|
7
|
+
// updateBindGroup,
|
|
8
|
+
// createVertexBuffer,
|
|
9
|
+
// createUniform,
|
|
10
|
+
// createDeviceTexture,
|
|
11
|
+
// createSampler,
|
|
12
|
+
} from './utils/pipeline'
|
|
13
|
+
import type { X } from './node'
|
|
14
|
+
import type { GL, GPUPipeline } from './types'
|
|
15
|
+
|
|
16
|
+
const quadVertexCount = 3
|
|
17
|
+
|
|
18
|
+
export const webgpu = async (gl: GL) => {
|
|
19
|
+
let vs = gl.vs || gl.vert || gl.vertex
|
|
20
|
+
let fs = gl.fs || gl.frag || gl.fragment
|
|
21
|
+
if (is.obj(vs)) vs = wgsl(vs as X)
|
|
22
|
+
if (is.obj(fs)) fs = wgsl(fs as X)
|
|
23
|
+
const c = gl.el.getContext('webgpu') as any
|
|
24
|
+
const gpu = (navigator as any).gpu
|
|
25
|
+
const adapter = await gpu.requestAdapter()
|
|
26
|
+
const device = await adapter.requestDevice()
|
|
27
|
+
const format = gpu.getPreferredCanvasFormat()
|
|
28
|
+
c.configure({ device, format, alphaMode: 'opaque' })
|
|
29
|
+
|
|
30
|
+
gl('clean', () => {})
|
|
31
|
+
|
|
32
|
+
let pipeline: GPUPipeline
|
|
33
|
+
|
|
34
|
+
gl('render', () => {
|
|
35
|
+
if (!pipeline) pipeline = createRenderPipeline(device, format, vs, fs, [])
|
|
36
|
+
const encoder = device.createCommandEncoder()
|
|
37
|
+
const pass = encoder.beginRenderPass(createDescriptor(c))
|
|
38
|
+
pass.setPipeline(pipeline)
|
|
39
|
+
pass.draw(quadVertexCount, 1, 0, 0)
|
|
40
|
+
pass.end()
|
|
41
|
+
device.queue.submit([encoder.finish()])
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
gl('_attribute', (key = '', value: number[]) => {
|
|
45
|
+
// @TODO FIX
|
|
46
|
+
// vertexBuffers(key, value)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
gl('_uniform', (key: string, value = 0) => {
|
|
50
|
+
// @TODO FIX
|
|
51
|
+
// if (!device || !uniformBuffer) return
|
|
52
|
+
// uniforms[key] = value
|
|
53
|
+
// const uniformData = new Float32Array(Object.values(uniforms))
|
|
54
|
+
// createUniform(device, uniformBuffer, uniformData)
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
// const _loadFun = (image: HTMLImageElement, gl: GL) => {
|
|
58
|
+
// const texture = createDeviceTexture(device, image)
|
|
59
|
+
// // bindGroup = updateBindGroup(device, pipeline, uniformBuffer, textures, sampler)
|
|
60
|
+
// }
|
|
61
|
+
|
|
62
|
+
gl('_texture', (alt: string, src: string) => {
|
|
63
|
+
// @TODO FIX
|
|
64
|
+
// const image = new Image()
|
|
65
|
+
// image.addEventListener('load', _loadFun.bind(null, image, gl), false)
|
|
66
|
+
// Object.assign(image, { src, alt, crossOrigin: 'anonymous' })
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
return gl
|
|
70
|
+
}
|
package/src/webgl/buffer.ts
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
// WebGLバッファー作成と管理
|
|
2
|
-
export const createVbo = (c: WebGLRenderingContext, data: number[]) => {
|
|
3
|
-
const buffer = c.createBuffer()
|
|
4
|
-
if (!buffer) throw new Error('Failed to create VBO')
|
|
5
|
-
c.bindBuffer(c.ARRAY_BUFFER, buffer)
|
|
6
|
-
c.bufferData(c.ARRAY_BUFFER, new Float32Array(data), c.STATIC_DRAW)
|
|
7
|
-
c.bindBuffer(c.ARRAY_BUFFER, null)
|
|
8
|
-
return buffer
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
// インデックスバッファーオブジェクト作成
|
|
12
|
-
export const createIbo = (c: WebGLRenderingContext, data: number[]) => {
|
|
13
|
-
const buffer = c.createBuffer()
|
|
14
|
-
if (!buffer) throw new Error('Failed to create IBO')
|
|
15
|
-
c.bindBuffer(c.ELEMENT_ARRAY_BUFFER, buffer)
|
|
16
|
-
c.bufferData(
|
|
17
|
-
c.ELEMENT_ARRAY_BUFFER,
|
|
18
|
-
new Int16Array(data),
|
|
19
|
-
c.STATIC_DRAW
|
|
20
|
-
)
|
|
21
|
-
c.bindBuffer(c.ELEMENT_ARRAY_BUFFER, null)
|
|
22
|
-
return buffer
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// アトリビュート設定
|
|
26
|
-
export const createAttribute = (
|
|
27
|
-
c: WebGLRenderingContext,
|
|
28
|
-
stride: number,
|
|
29
|
-
location: number,
|
|
30
|
-
vbo: WebGLBuffer,
|
|
31
|
-
ibo?: WebGLBuffer
|
|
32
|
-
) => {
|
|
33
|
-
c.bindBuffer(c.ARRAY_BUFFER, vbo)
|
|
34
|
-
c.enableVertexAttribArray(location)
|
|
35
|
-
c.vertexAttribPointer(location, stride, c.FLOAT, false, 0, 0)
|
|
36
|
-
if (ibo) c.bindBuffer(c.ELEMENT_ARRAY_BUFFER, ibo)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// バッファーの削除
|
|
40
|
-
export const deleteBuffer = (c: WebGLRenderingContext, buffer: WebGLBuffer) => {
|
|
41
|
-
c.deleteBuffer(buffer)
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// 頂点ストライドを計算
|
|
45
|
-
export const vertexStride = (
|
|
46
|
-
count: number,
|
|
47
|
-
value: number[],
|
|
48
|
-
iboValue?: number[]
|
|
49
|
-
) => {
|
|
50
|
-
if (iboValue) count = Math.max(...iboValue) + 1
|
|
51
|
-
const stride = value.length / count
|
|
52
|
-
if (stride !== Math.floor(stride))
|
|
53
|
-
console.warn(`Vertex Stride Error: count ${count} is mismatch`)
|
|
54
|
-
return Math.floor(stride)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// バッファーデータの更新
|
|
58
|
-
export const updateVbo = (
|
|
59
|
-
c: WebGLRenderingContext,
|
|
60
|
-
buffer: WebGLBuffer,
|
|
61
|
-
data: number[],
|
|
62
|
-
usage = c.STATIC_DRAW
|
|
63
|
-
) => {
|
|
64
|
-
c.bindBuffer(c.ARRAY_BUFFER, buffer)
|
|
65
|
-
c.bufferData(c.ARRAY_BUFFER, new Float32Array(data), usage)
|
|
66
|
-
c.bindBuffer(c.ARRAY_BUFFER, null)
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export const updateIbo = (
|
|
70
|
-
c: WebGLRenderingContext,
|
|
71
|
-
buffer: WebGLBuffer,
|
|
72
|
-
data: number[],
|
|
73
|
-
usage = c.STATIC_DRAW
|
|
74
|
-
) => {
|
|
75
|
-
c.bindBuffer(c.ELEMENT_ARRAY_BUFFER, buffer)
|
|
76
|
-
c.bufferData(c.ELEMENT_ARRAY_BUFFER, new Int16Array(data), usage)
|
|
77
|
-
c.bindBuffer(c.ELEMENT_ARRAY_BUFFER, null)
|
|
78
|
-
}
|
package/src/webgl/index.ts
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { nested } from 'reev'
|
|
2
|
-
import { createAttribute, createIbo, createVbo, vertexStride } from './buffer'
|
|
3
|
-
import { createProgram, deleteProgram, getUniformType } from './program'
|
|
4
|
-
import { createFragmentShader, createVertexShader } from './shader'
|
|
5
|
-
import { activeTexture, createTexture } from './texture'
|
|
6
|
-
import { glsl } from '../code/glsl'
|
|
7
|
-
import { is } from '../utils'
|
|
8
|
-
import type { X } from '../node'
|
|
9
|
-
import type { GL } from '../types'
|
|
10
|
-
export * from './buffer'
|
|
11
|
-
export * from './program'
|
|
12
|
-
export * from './shader'
|
|
13
|
-
export * from './texture'
|
|
14
|
-
|
|
15
|
-
const a_position = [-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]
|
|
16
|
-
|
|
17
|
-
export const webgl = (gl: GL) => {
|
|
18
|
-
gl('init', () => {
|
|
19
|
-
const c = gl.gl
|
|
20
|
-
let vs = gl.vs || gl.vert || gl.vertex
|
|
21
|
-
let fs = gl.fs || gl.frag || gl.fragment
|
|
22
|
-
if (is.obj(fs)) fs = glsl(fs as X)
|
|
23
|
-
if (is.obj(vs)) vs = glsl(vs as X)
|
|
24
|
-
if (gl.count === 6) gl.attribute({ a_position })
|
|
25
|
-
gl.pg = createProgram(c, createVertexShader(c, vs), createFragmentShader(c, fs))
|
|
26
|
-
gl.location = nested((key, isAttribute = false) => {
|
|
27
|
-
return isAttribute ? c.getAttribLocation(gl.pg, key) : c.getUniformLocation(gl.pg, key)
|
|
28
|
-
})
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
gl('clean', () => {
|
|
32
|
-
const c = gl.gl
|
|
33
|
-
deleteProgram(c, gl.pg)
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
gl('render', () => {
|
|
37
|
-
const c = gl.gl
|
|
38
|
-
c.useProgram(gl.pg)
|
|
39
|
-
gl.queue.flush()
|
|
40
|
-
c.clear(c.COLOR_BUFFER_BIT)
|
|
41
|
-
c.viewport(0, 0, ...gl.size)
|
|
42
|
-
c.drawArrays(c.TRIANGLES, 0, gl.count)
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
gl('_attribute', (key = '', value: number[], iboValue: number[]) => {
|
|
46
|
-
const c = gl.gl
|
|
47
|
-
const n = gl.count
|
|
48
|
-
const loc = gl.location(key, true)
|
|
49
|
-
const vbo = createVbo(c, value)
|
|
50
|
-
const ibo = createIbo(c, iboValue)
|
|
51
|
-
const stride = vertexStride(n, value, iboValue)
|
|
52
|
-
createAttribute(c, stride, loc, vbo, ibo)
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
gl('_uniform', (key: string, value = 0, isMatrix = false) => {
|
|
56
|
-
const type = getUniformType(value, isMatrix)
|
|
57
|
-
const c = gl.gl
|
|
58
|
-
const loc = gl.location(key)
|
|
59
|
-
if (isMatrix) c[type](loc, false, value)
|
|
60
|
-
else c[type](loc, value)
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
const _loadFn = (image: HTMLImageElement) => {
|
|
64
|
-
const loc = gl.location(image.alt)
|
|
65
|
-
const unit = gl.activeUnit(image.alt)
|
|
66
|
-
const tex = createTexture(gl.gl, image)
|
|
67
|
-
activeTexture(gl.gl, loc, unit, tex)
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
gl('_texture', (alt: string, src: string) => {
|
|
71
|
-
const image = new Image()
|
|
72
|
-
image.addEventListener('load', _loadFn.bind(null, image), false)
|
|
73
|
-
Object.assign(image, { src, alt, crossOrigin: 'anonymous' })
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
let _activeUnit = 0
|
|
77
|
-
gl.activeUnit = nested(() => _activeUnit++)
|
|
78
|
-
return gl
|
|
79
|
-
}
|
package/src/webgl/program.ts
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
// WebGLプログラム作成と管理
|
|
2
|
-
export const createProgram = (
|
|
3
|
-
c: WebGLRenderingContext,
|
|
4
|
-
vs: WebGLShader,
|
|
5
|
-
fs: WebGLShader
|
|
6
|
-
) => {
|
|
7
|
-
const pg = c.createProgram()
|
|
8
|
-
if (!pg) throw new Error('Failed to create pg')
|
|
9
|
-
c.attachShader(pg, vs)
|
|
10
|
-
c.attachShader(pg, fs)
|
|
11
|
-
c.linkProgram(pg)
|
|
12
|
-
if (c.getProgramParameter(pg, c.LINK_STATUS)) return pg
|
|
13
|
-
const error = c.getProgramInfoLog(pg)
|
|
14
|
-
c.deleteProgram(pg)
|
|
15
|
-
throw new Error(`Could not link pg: ${error}`)
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// プログラムの削除
|
|
19
|
-
export const deleteProgram = (c: WebGLRenderingContext, pg: WebGLProgram) => {
|
|
20
|
-
c.deleteProgram(pg)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// プログラムの情報を取得
|
|
24
|
-
export const getProgramInfo = (c: WebGLRenderingContext, pg: WebGLProgram) => {
|
|
25
|
-
return {
|
|
26
|
-
linked: c.getProgramParameter(pg, c.LINK_STATUS),
|
|
27
|
-
log: c.getProgramInfoLog(pg),
|
|
28
|
-
activeAttributes: c.getProgramParameter(
|
|
29
|
-
pg,
|
|
30
|
-
c.ACTIVE_ATTRIBUTES
|
|
31
|
-
),
|
|
32
|
-
activeUniforms: c.getProgramParameter(pg, c.ACTIVE_UNIFORMS),
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// ユニフォームタイプの取得
|
|
37
|
-
export const getUniformType = (value: number | number[], isMatrix = false) => {
|
|
38
|
-
let length = typeof value === 'number' ? 0 : value?.length
|
|
39
|
-
if (!length) return `uniform1f`
|
|
40
|
-
if (!isMatrix) return `uniform${length}fv`
|
|
41
|
-
length = Math.sqrt(length) << 0
|
|
42
|
-
return `uniformMatrix${length}fv`
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// ユニフォーム位置を取得
|
|
46
|
-
export const getUniformLocation = (
|
|
47
|
-
c: WebGLRenderingContext,
|
|
48
|
-
pg: WebGLProgram,
|
|
49
|
-
name: string
|
|
50
|
-
) => {
|
|
51
|
-
return c.getUniformLocation(pg, name)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// アトリビュート位置を取得
|
|
55
|
-
export const getAttribLocation = (
|
|
56
|
-
c: WebGLRenderingContext,
|
|
57
|
-
pg: WebGLProgram,
|
|
58
|
-
name: string
|
|
59
|
-
) => {
|
|
60
|
-
return c.getAttribLocation(pg, name)
|
|
61
|
-
}
|
package/src/webgl/shader.ts
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
const defaultVertexShader = /* cpp */ `
|
|
2
|
-
attribute vec4 a_position;
|
|
3
|
-
void main() {
|
|
4
|
-
gl_Position = a_position;
|
|
5
|
-
}
|
|
6
|
-
`
|
|
7
|
-
|
|
8
|
-
const defaultFragmentShader = /* cpp */ `
|
|
9
|
-
precision mediump float;
|
|
10
|
-
uniform vec2 iResolution;
|
|
11
|
-
void main() {
|
|
12
|
-
gl_FragColor = vec4(fract(gl_FragCoord.xy / iResolution), 0, 1);
|
|
13
|
-
}
|
|
14
|
-
`
|
|
15
|
-
|
|
16
|
-
export const deleteShader = (c: WebGLRenderingContext, shader: WebGLShader) => {
|
|
17
|
-
c.deleteShader(shader)
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// WebGLシェーダー作成と管理
|
|
21
|
-
const createShader = (
|
|
22
|
-
c: WebGLRenderingContext,
|
|
23
|
-
source: string,
|
|
24
|
-
type: number
|
|
25
|
-
) => {
|
|
26
|
-
const shader = c.createShader(type)
|
|
27
|
-
if (!shader) throw new Error('Failed to create shader')
|
|
28
|
-
c.shaderSource(shader, source)
|
|
29
|
-
c.compileShader(shader)
|
|
30
|
-
if (c.getShaderParameter(shader, c.COMPILE_STATUS)) return shader
|
|
31
|
-
const error = c.getShaderInfoLog(shader)
|
|
32
|
-
deleteShader(c, shader)
|
|
33
|
-
throw new Error(`Could not compile shader: ${error}`)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export const createVertexShader = (
|
|
37
|
-
c: WebGLRenderingContext,
|
|
38
|
-
source = defaultVertexShader
|
|
39
|
-
) => {
|
|
40
|
-
return createShader(c, source, c.VERTEX_SHADER)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export const createFragmentShader = (
|
|
44
|
-
c: WebGLRenderingContext,
|
|
45
|
-
source = defaultFragmentShader
|
|
46
|
-
) => {
|
|
47
|
-
return createShader(c, source, c.FRAGMENT_SHADER)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// シェーダーの情報を取得
|
|
51
|
-
export const getShaderInfo = (
|
|
52
|
-
c: WebGLRenderingContext,
|
|
53
|
-
shader: WebGLShader
|
|
54
|
-
) => {
|
|
55
|
-
return {
|
|
56
|
-
compiled: c.getShaderParameter(shader, c.COMPILE_STATUS),
|
|
57
|
-
log: c.getShaderInfoLog(shader),
|
|
58
|
-
source: c.getShaderSource(shader),
|
|
59
|
-
}
|
|
60
|
-
}
|