glre 0.23.0 → 0.25.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "glre",
3
- "version": "0.23.0",
3
+ "version": "0.25.0",
4
4
  "author": "tseijp",
5
5
  "license": "MIT",
6
6
  "private": false,
package/src/index.ts CHANGED
@@ -20,6 +20,7 @@ export const isGL = (a: unknown): a is EventState<GL> => {
20
20
  if ('isGL' in a) return true
21
21
  return false
22
22
  }
23
+
23
24
  export const isServer = () => {
24
25
  return typeof window === 'undefined'
25
26
  }
@@ -29,9 +30,7 @@ export const isWebGPUSupported = () => {
29
30
  return 'gpu' in navigator
30
31
  }
31
32
 
32
- let iTime = performance.now(),
33
- iPrevTime = 0,
34
- iDeltaTime = 0
33
+ let iTime = performance.now()
35
34
 
36
35
  export const createGL = (props?: Partial<GL>) => {
37
36
  const gl = event<Partial<GL>>({
@@ -50,17 +49,21 @@ export const createGL = (props?: Partial<GL>) => {
50
49
  gl.frame = createFrame()
51
50
 
52
51
  gl.attribute = durable((k, v, i) => gl.queue(() => gl._attribute?.(k, v, i)))
53
- gl.uniform = durable((k, v, i) => gl.queue(() => gl._uniform?.(k, v, i)))
54
52
  gl.texture = durable((k, v) => gl.queue(() => gl._texture?.(k, v)))
53
+ gl.uniform = durable((k, v, i) => gl.queue(() => gl._uniform?.(k, v, i)))
54
+ gl.uniform({ iResolution: gl.size, iMouse: [0, 0], iTime })
55
55
 
56
56
  gl('mount', async () => {
57
+ gl.vs = gl.vs || gl.vert || gl.vertex
58
+ gl.fs = gl.fs || gl.frag || gl.fragment
57
59
  if (!isWebGPUSupported()) gl.isWebGL = true
58
60
  if (gl.isWebGL) {
59
- await webgl(gl)
60
- } else await webgpu(gl)
61
+ gl((await webgl(gl)) as GL)
62
+ } else gl((await webgpu(gl)) as GL)
61
63
  gl.resize()
62
64
  gl.frame(() => {
63
65
  gl.loop()
66
+ gl.queue.flush()
64
67
  gl.render()
65
68
  return gl.isLoop
66
69
  })
@@ -77,14 +80,6 @@ export const createGL = (props?: Partial<GL>) => {
77
80
  gl.el.removeEventListener('mousemove', gl.mousemove)
78
81
  })
79
82
 
80
- gl('loop', () => {
81
- iPrevTime = iTime
82
- iTime = performance.now() / 1000
83
- iDeltaTime = iTime - iPrevTime
84
- gl.uniform({ iPrevTime, iTime, iDeltaTime })
85
- // if (gl.fragmentNode) updateUniforms({ time: iTime }) // @TODO FIX
86
- })
87
-
88
83
  gl('resize', () => {
89
84
  const w = gl.width || window.innerWidth
90
85
  const h = gl.height || window.innerHeight
@@ -101,6 +96,11 @@ export const createGL = (props?: Partial<GL>) => {
101
96
  gl.uniform('iMouse', gl.mouse)
102
97
  })
103
98
 
99
+ gl('loop', () => {
100
+ iTime = performance.now() / 1000
101
+ gl.uniform('iTime', iTime)
102
+ })
103
+
104
104
  return gl(props)
105
105
  }
106
106
 
package/src/node/index.ts CHANGED
@@ -43,8 +43,8 @@ export const If = (condition: X, callback: () => void): ConditionalNode => {
43
43
  }
44
44
 
45
45
  // 組み込み変数
46
- export const gl_FragCoord = node('vec4', undefined)
47
- export const gl_Position = node('vec4', undefined)
46
+ export const fragCoord = node('vec4', undefined)
47
+ export const position = node('vec4', undefined)
48
48
  export const iTime = uniform(0.0)
49
49
  export const iResolution = uniform([1920, 1080])
50
50
  export const iMouse = uniform([0, 0])
package/src/types.ts CHANGED
@@ -6,6 +6,7 @@ export type GPUContext = any // GPUCanvasContext https://developer.mozilla.org/e
6
6
  export type GPUDevice = any //
7
7
  export type GPUBuffer = any //
8
8
  export type GPUPipeline = any //
9
+ export type GPUBindGroup = any
9
10
  export type Uniform = number | number[]
10
11
  export type Attribute = number[]
11
12
  export type Attributes = Record<string, Attribute>
@@ -28,9 +29,15 @@ export interface WebGLState {
28
29
  }
29
30
 
30
31
  export interface WebGPUState {
32
+ uniforms: any
33
+ textures: any
31
34
  device: GPUDevice
32
35
  context: GPUContext
36
+ groups: any[]
33
37
  pipeline: GPUPipeline
38
+ resources: any[]
39
+ loadingImg: number
40
+ needsUpdate: boolean
34
41
  }
35
42
 
36
43
  export type GL = EventState<{
@@ -1,17 +1,7 @@
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
- }
1
+ import { wgsl } from '../code/wgsl'
2
+ import { X } from '../node'
3
+ import { is } from './helpers'
4
+ import type { GPUContext, GPUDevice, GPUPipeline } from '../types'
15
5
 
16
6
  const defaultVertexWGSL = `
17
7
  @vertex
@@ -23,19 +13,34 @@ fn main(@builtin(vertex_index) vertex_index: u32) -> @builtin(position) vec4f {
23
13
  `
24
14
 
25
15
  const defaultFragmentWGSL = `
16
+ @group(0) @binding(0) var<uniform> iResolution: vec2f;
17
+
26
18
  @fragment
27
19
  fn main(@builtin(position) position: vec4f) -> @location(0) vec4f {
28
- return vec4f(position.xy / vec2f(1280, 800), 0.0, 1.0);
20
+ return vec4f(position.xy / iResolution, 0.0, 1.0);
29
21
  }
30
22
  `
31
23
 
32
- export const createRenderPipeline = (
24
+ export const createDevive = async (c: GPUContext) => {
25
+ const gpu = (navigator as any).gpu
26
+ const format = gpu.getPreferredCanvasFormat()
27
+ const adapter = await gpu.requestAdapter()
28
+ const device = await adapter.requestDevice()
29
+ c.configure({ device, format, alphaMode: 'opaque' })
30
+ return { device, format }
31
+ }
32
+
33
+ export const createPipeline = (
33
34
  device: GPUDevice,
34
35
  format: string,
35
- vs = defaultVertexWGSL,
36
- fs = defaultFragmentWGSL,
37
- buffers: any[]
36
+ buffers: any[],
37
+ layouts: any[],
38
+ vs: string | X = defaultVertexWGSL,
39
+ fs: string | X = defaultFragmentWGSL
38
40
  ) => {
41
+ if (is.obj(fs)) fs = wgsl(fs)
42
+ if (is.obj(vs)) vs = wgsl(vs)
43
+ const layout = device.createPipelineLayout({ bindGroupLayouts: layouts })
39
44
  return device.createRenderPipeline({
40
45
  vertex: {
41
46
  module: device.createShaderModule({ code: vs.trim() }),
@@ -47,11 +52,30 @@ export const createRenderPipeline = (
47
52
  entryPoint: 'main',
48
53
  targets: [{ format }],
49
54
  },
50
- layout: 'auto',
55
+ layout,
51
56
  primitive: { topology: 'triangle-list' },
52
57
  }) as GPUPipeline
53
58
  }
54
59
 
60
+ export const createBindGroup = (device: GPUDevice, resources: any[]) => {
61
+ const entries0 = [] as any[]
62
+ const entries1 = [] as any[]
63
+ resources.forEach((resource, binding) => {
64
+ if (!resource) return
65
+ const isUniform = 'buffer' in resource // @ts-ignore
66
+ const isTexture = resource instanceof GPUTextureView // @ts-ignore
67
+ const isSampler = resource instanceof GPUSampler // @ts-ignore
68
+ if (isUniform) entries0.push({ binding, visibility: 3, buffer: { type: 'uniform' } })
69
+ else if (isTexture) entries0.push({ binding, visibility: 2, texture: {} })
70
+ else if (isSampler) entries0.push({ binding, visibility: 2, sampler: {} })
71
+ else return
72
+ entries1.push({ binding, resource })
73
+ })
74
+ const layout = device.createBindGroupLayout({ entries: entries0 })
75
+ const bindGroup = device.createBindGroup({ layout, entries: entries1 })
76
+ return [layout, bindGroup]
77
+ }
78
+
55
79
  export const createDescriptor = (c: GPUContext) => {
56
80
  return {
57
81
  colorAttachments: [
@@ -64,65 +88,25 @@ export const createDescriptor = (c: GPUContext) => {
64
88
  ],
65
89
  }
66
90
  }
67
- export const alignTo256 = (size: number) => Math.ceil(size / 256) * 256
68
91
 
69
- export const createUniformBuffer = (device: GPUDevice, size: number) => {
70
- return device.createBuffer({ size: alignTo256(size), usage: 0x40 | 0x4 }) as Buffer
71
- }
92
+ export const alignTo256 = (size: number) => Math.ceil(size / 256) * 256
72
93
 
73
- export const createVertexBuffer = (device: GPUDevice, value: number[]) => {
94
+ export const createUniformBuffer = (device: GPUDevice, value: number[]) => {
74
95
  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)
96
+ const size = alignTo256(array.byteLength)
97
+ const buffer = device.createBuffer({ size, usage: 72 }) as Buffer // 72 === GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
98
+ return { array, buffer }
103
99
  }
104
100
 
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
- })
101
+ export const createTextureSampler = (device: GPUDevice, width = 1280, height = 800) => {
102
+ const texture = device.createTexture({ size: [width, height], format: 'rgba8unorm', usage: 22 })
103
+ const sampler = device.createSampler({ magFilter: 'linear', minFilter: 'linear' })
104
+ return [texture, sampler] as const
126
105
  }
127
106
 
128
- export const getDefaultVertices = () => new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1])
107
+ // export const createVertexBuffer = (device: GPUDevice, value: number[]) => {
108
+ // const array = new Float32Array(value)
109
+ // const buffer = device.createBuffer({ size: array.byteLength, usage: 0x20 | 0x4 })
110
+ // device.queue.writeBuffer(buffer, 0, array)
111
+ // return buffer as Buffer
112
+ // }
@@ -1,3 +1,7 @@
1
+ import { glsl } from '../code/glsl'
2
+ import { X } from '../node'
3
+ import { is } from './helpers'
4
+
1
5
  export const defaultVertexGLSL = /* cpp */ `
2
6
  #version 300 es
3
7
  void main() {
@@ -17,7 +21,7 @@ void main() {
17
21
  }
18
22
  `
19
23
 
20
- export const createShader = (c: WebGLRenderingContext, source: string, type: number) => {
24
+ const createShader = (c: WebGLRenderingContext, source: string, type: number) => {
21
25
  const shader = c.createShader(type)
22
26
  if (!shader) throw new Error('Failed to create shader')
23
27
  c.shaderSource(shader, source.trim())
@@ -28,7 +32,13 @@ export const createShader = (c: WebGLRenderingContext, source: string, type: num
28
32
  throw new Error(`Could not compile shader: ${error}`)
29
33
  }
30
34
 
31
- export const createProgram = (c: WebGLRenderingContext, vs = defaultVertexGLSL, fs = defaultFragmentGLSL) => {
35
+ export const createProgram = (
36
+ c: WebGLRenderingContext,
37
+ vs: string | X = defaultVertexGLSL,
38
+ fs: string | X = defaultFragmentGLSL
39
+ ) => {
40
+ if (is.obj(fs)) fs = glsl(fs as X)
41
+ if (is.obj(vs)) vs = glsl(vs as X)
32
42
  const pg = c.createProgram()
33
43
  c.attachShader(pg, createShader(c, vs, c.VERTEX_SHADER))
34
44
  c.attachShader(pg, createShader(c, fs, c.FRAGMENT_SHADER))
@@ -55,20 +65,26 @@ export const createIbo = (c: WebGLRenderingContext, data: number[]) => {
55
65
  return buffer
56
66
  }
57
67
 
68
+ export const getStride = (count: number, value: number[], iboValue?: number[]) => {
69
+ if (iboValue) count = Math.max(...iboValue) + 1
70
+ const stride = value.length / count
71
+ return Math.floor(stride)
72
+ }
73
+
58
74
  export const createAttrib = (
59
75
  c: WebGLRenderingContext,
60
76
  stride: number,
61
- location: any,
77
+ loc: any,
62
78
  vbo: WebGLBuffer,
63
79
  ibo?: WebGLBuffer
64
80
  ) => {
65
81
  c.bindBuffer(c.ARRAY_BUFFER, vbo)
66
- c.enableVertexAttribArray(location)
67
- c.vertexAttribPointer(location, stride, c.FLOAT, false, 0, 0)
82
+ c.enableVertexAttribArray(loc)
83
+ c.vertexAttribPointer(loc, stride, c.FLOAT, false, 0, 0)
68
84
  if (ibo) c.bindBuffer(c.ELEMENT_ARRAY_BUFFER, ibo)
69
85
  }
70
86
 
71
- export const createTexture = (c: WebGLRenderingContext, img: HTMLImageElement) => {
87
+ export const createTexture = (c: WebGLRenderingContext, img: HTMLImageElement, loc: any, unit: number) => {
72
88
  const texture = c.createTexture()
73
89
  c.bindTexture(c.TEXTURE_2D, texture)
74
90
  c.texImage2D(c.TEXTURE_2D, 0, c.RGBA, c.RGBA, c.UNSIGNED_BYTE, img)
@@ -78,17 +94,7 @@ export const createTexture = (c: WebGLRenderingContext, img: HTMLImageElement) =
78
94
  c.texParameteri(c.TEXTURE_2D, c.TEXTURE_WRAP_S, c.CLAMP_TO_EDGE)
79
95
  c.texParameteri(c.TEXTURE_2D, c.TEXTURE_WRAP_T, c.CLAMP_TO_EDGE)
80
96
  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)
97
+ c.uniform1i(loc, unit)
92
98
  c.activeTexture(c.TEXTURE0 + unit)
93
99
  c.bindTexture(c.TEXTURE_2D, texture)
94
100
  }
package/src/webgl.ts CHANGED
@@ -1,78 +1,54 @@
1
- import { nested } from 'reev'
2
- import { glsl } from './code/glsl'
1
+ import { nested as cached } from 'reev'
3
2
  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'
3
+ import { createAttrib, createIbo, createProgram, createTexture, createVbo, getStride } from './utils/program'
4
+ import type { GL, WebGLState } from './types'
7
5
 
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)
6
+ export const webgl = async (gl: Partial<GL>) => {
7
+ const c = gl.el!.getContext('webgl2')!
8
+ const pg = createProgram(c, gl.vs, gl.fs)
9
+ const state = { context: c, program: pg } as WebGLState
10
+ c.useProgram(pg)
15
11
 
16
12
  let _activeUnit = 0
17
- const activeUnits = nested(() => _activeUnit++)
13
+ const activeUnits = cached(() => _activeUnit++)
18
14
 
19
- const locations = nested((key, bool = false) => {
20
- if (bool) return c.getAttribLocation(pg, key)
21
- return c.getUniformLocation(pg, key) as WebGLUniformLocation
22
- })
15
+ const uniformLocations = cached((key) => c.getUniformLocation(pg, key))
16
+ const attribLocations = cached((key) => c.getAttribLocation(pg, key))
23
17
 
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
- })
18
+ const clean = () => c.deleteProgram(pg)
30
19
 
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()
20
+ const render = () => {
45
21
  c.clear(c.COLOR_BUFFER_BIT)
46
- c.viewport(0, 0, ...gl.size)
22
+ c.viewport(0, 0, ...gl.size!)
47
23
  c.drawArrays(c.TRIANGLES, 0, 3)
48
- })
24
+ }
49
25
 
50
- gl('_attribute', (key = '', value: number[], iboValue: number[]) => {
51
- const loc = locations(key, true)
26
+ const _attribute = (key = '', value: number[], iboValue: number[]) => {
27
+ const loc = attribLocations(key, true)
52
28
  const vbo = createVbo(c, value)
53
29
  const ibo = createIbo(c, iboValue)
54
- const str = strides(key, gl.count, value, iboValue)
30
+ const str = getStride(gl.count!, value, iboValue)
55
31
  createAttrib(c, str, loc, vbo, ibo)
56
- })
57
-
58
- gl('_uniform', (key: string, value: number | number[]) => {
59
- uniforms(key, value)(value)
60
- })
32
+ }
61
33
 
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)
34
+ const _uniform = (key: string, value: number | number[]) => {
35
+ const loc = uniformLocations(key)
36
+ if (is.num(value)) return c.uniform1f(loc, value)
37
+ let l = value.length
38
+ if (l <= 4) return c[`uniform${l as 2}fv`](loc, value)
39
+ l = Math.sqrt(l) << 0
40
+ c[`uniformMatrix${l as 2}fv`](loc, false, value)
67
41
  }
68
42
 
69
- gl('_texture', (alt: string, src: string) => {
43
+ const _texture = (alt: string, src: string) => {
70
44
  const image = new Image()
71
- image.addEventListener('load', _loadFn.bind(null, image), false)
72
45
  Object.assign(image, { src, alt, crossOrigin: 'anonymous' })
73
- })
74
-
75
- gl.webgl = { context: c, program: pg }
46
+ image.decode().then(() => {
47
+ const loc = uniformLocations(image.alt)
48
+ const unit = activeUnits(image.alt)
49
+ createTexture(c, image, loc, unit)
50
+ })
51
+ }
76
52
 
77
- return gl
53
+ return { webgl: state, render, clean, _attribute, _uniform, _texture }
78
54
  }
package/src/webgpu.ts CHANGED
@@ -1,70 +1,92 @@
1
- import { wgsl } from './code/wgsl'
2
1
  import { is } from './utils/helpers'
3
2
  import {
4
- createRenderPipeline,
3
+ createDevive,
4
+ createPipeline,
5
5
  createDescriptor,
6
- // createUniformBuffer,
7
- // updateBindGroup,
8
- // createVertexBuffer,
9
- // createUniform,
10
- // createDeviceTexture,
11
- // createSampler,
6
+ createUniformBuffer,
7
+ createBindGroup,
8
+ createTextureSampler,
12
9
  } from './utils/pipeline'
13
- import type { X } from './node'
14
- import type { GL, GPUPipeline } from './types'
10
+ import type { GL, WebGPUState } from './types'
15
11
 
16
- const quadVertexCount = 3
12
+ export const webgpu = async (gl: Partial<GL>) => {
13
+ const c = gl.el!.getContext('webgpu') as any
14
+ const { device, format } = await createDevive(c)
15
+ const state = {
16
+ device,
17
+ context: c,
18
+ uniforms: {},
19
+ textures: {},
20
+ resources: [[], []],
21
+ loadingImg: 0,
22
+ needsUpdate: true,
23
+ } as WebGPUState
17
24
 
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' })
25
+ const initUniform = (value: number[]) => {
26
+ const { array, buffer } = createUniformBuffer(device, value)
27
+ state.resources[0].push({ buffer })
28
+ state.needsUpdate = true
29
+ return { array, buffer }
30
+ }
29
31
 
30
- gl('clean', () => {})
32
+ const initTexutre = (source: HTMLImageElement) => {
33
+ const { width, height } = source
34
+ const [texture, sampler] = createTextureSampler(device, width, height)
35
+ state.resources[1].push(sampler, texture.createView())
36
+ state.needsUpdate = true
37
+ return { texture, width, height }
38
+ }
31
39
 
32
- let pipeline: GPUPipeline
40
+ const update = () => {
41
+ const layouts = [] as any
42
+ state.groups = []
43
+ state.resources.forEach((resource) => {
44
+ if (!resource.length) return
45
+ const [layout, group] = createBindGroup(device, resource)
46
+ layouts.push(layout)
47
+ state.groups.push(group)
48
+ })
49
+ state.pipeline = createPipeline(device, format, [], layouts, gl.vs, gl.fs)
50
+ }
33
51
 
34
- gl('render', () => {
35
- if (!pipeline) pipeline = createRenderPipeline(device, format, vs, fs, [])
52
+ const render = () => {
53
+ if (state.loadingImg) return // ignore if loading img
54
+ if (state.needsUpdate) update() // first rendering
55
+ state.needsUpdate = false
36
56
  const encoder = device.createCommandEncoder()
37
57
  const pass = encoder.beginRenderPass(createDescriptor(c))
38
- pass.setPipeline(pipeline)
39
- pass.draw(quadVertexCount, 1, 0, 0)
58
+ pass.setPipeline(state.pipeline)
59
+ state.groups.forEach((v, i) => pass.setBindGroup(i, v))
60
+ pass.draw(gl.count, 1, 0, 0)
40
61
  pass.end()
41
62
  device.queue.submit([encoder.finish()])
42
- })
63
+ }
43
64
 
44
- gl('_attribute', (key = '', value: number[]) => {
45
- // @TODO FIX
46
- // vertexBuffers(key, value)
47
- })
65
+ const clean = () => {}
48
66
 
49
- gl('_uniform', (key: string, value = 0) => {
67
+ const _attribute = (key = '', value: number[]) => {
50
68
  // @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
- })
69
+ // vertexBuffers(key, value)
70
+ }
56
71
 
57
- // const _loadFun = (image: HTMLImageElement, gl: GL) => {
58
- // const texture = createDeviceTexture(device, image)
59
- // // bindGroup = updateBindGroup(device, pipeline, uniformBuffer, textures, sampler)
60
- // }
72
+ const _uniform = (key: string, value: number | number[]) => {
73
+ if (is.num(value)) value = [value]
74
+ if (!state.uniforms[key]) state.uniforms[key] = initUniform(value)
75
+ const { array, buffer } = state.uniforms[key]
76
+ array.set(value)
77
+ device.queue.writeBuffer(buffer, 0, array)
78
+ }
61
79
 
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
- })
80
+ const _texture = (key: string, src: string) => {
81
+ state.loadingImg++
82
+ const source = Object.assign(new Image(), { src, crossOrigin: 'anonymous' })
83
+ source.decode().then(() => {
84
+ if (!state.textures[key]) state.textures[key] = initTexutre(source)
85
+ const { texture, width, height } = state.textures[key]
86
+ device.queue.copyExternalImageToTexture({ source }, { texture }, { width, height })
87
+ state.loadingImg--
88
+ })
89
+ }
68
90
 
69
- return gl
91
+ return { webgpu: state, render, clean, _attribute, _uniform, _texture }
70
92
  }