glre 0.34.0 → 0.36.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.
@@ -1,8 +1,8 @@
1
- import { is } from '../utils/helpers'
2
- import { code } from './code'
1
+ import { code } from '.'
3
2
  import { infer } from './infer'
4
- import { formatConversions, addDependency } from './utils'
5
- import type { Constants, NodeContext, NodeProps, NodeProxy, X } from './types'
3
+ import { getConversions, addDependency } from './utils'
4
+ import { is } from '../../utils/helpers'
5
+ import type { Constants, NodeContext, NodeProps, NodeProxy, X } from '../types'
6
6
 
7
7
  export const parseArray = (children: X[], c: NodeContext) => {
8
8
  return children
@@ -54,48 +54,17 @@ export const parseDeclare = (c: NodeContext, x: X, y: X) => {
54
54
  const type = infer(x, c)
55
55
  const varName = (y as any)?.props?.id
56
56
  if (c.isWebGL) return `${type} ${varName} = ${code(x, c)};`
57
- const wgslType = formatConversions(type)
57
+ const wgslType = getConversions(type)
58
58
  return `var ${varName}: ${wgslType} = ${code(x, c)};`
59
59
  }
60
60
 
61
- export const parseDefine = (c: NodeContext, props: NodeProps, returnType: Constants) => {
62
- const { id, children = [], layout } = props
63
- const [x, ...args] = children
64
- const argParams: [name: string, type: string][] = []
65
- const params: string[] = []
66
- if (layout?.inputs)
67
- for (const input of layout.inputs) {
68
- argParams.push([input.name, input.type])
69
- }
70
- else
71
- for (let i = 0; i < args.length; i++) {
72
- argParams.push([`p${i}`, infer(args[i], c)])
73
- }
74
- const ret = []
75
- if (c?.isWebGL) {
76
- for (const [paramId, type] of argParams) {
77
- addDependency(c, id!, type)
78
- params.push(`${type} ${paramId}`)
79
- }
80
- addDependency(c, id!, returnType)
81
- ret.push(`${returnType} ${id}(${params}) {`)
82
- } else {
83
- for (const [paramId, type] of argParams) params.push(`${paramId}: ${formatConversions(type, c)}`)
84
- ret.push(`fn ${id}(${params}) -> ${formatConversions(returnType, c)} {`)
85
- }
86
- const scopeCode = code(x, c)
87
- if (scopeCode) ret.push(scopeCode)
88
- ret.push('}')
89
- return ret.join('\n')
90
- }
91
-
92
61
  export const parseStructHead = (c: NodeContext, id: string, fields: Record<string, NodeProxy> = {}) => {
93
62
  const lines: string[] = []
94
63
  for (const key in fields) {
95
64
  const fieldType = fields[key]
96
65
  const type = infer(fieldType, c)
97
66
  if (c.isWebGL) addDependency(c, id, type)
98
- lines.push(c.isWebGL ? `${type} ${key};` : `${key}: ${formatConversions(type, c)},`)
67
+ lines.push(c.isWebGL ? `${type} ${key};` : `${key}: ${getConversions(type, c)},`)
99
68
  }
100
69
  const ret = lines.join('\n ')
101
70
  return `struct ${id} {\n ${ret}\n};`
@@ -123,13 +92,47 @@ export const parseStruct = (
123
92
  }
124
93
  }
125
94
 
95
+ /**
96
+ * define
97
+ */
98
+ export const parseDefine = (c: NodeContext, props: NodeProps, returnType: Constants) => {
99
+ const { id, children = [], layout } = props
100
+ const [x, ...args] = children
101
+ const argParams: [name: string, type: string][] = []
102
+ const params: string[] = []
103
+ if (layout?.inputs)
104
+ for (const input of layout.inputs) {
105
+ argParams.push([input.name, input.type])
106
+ }
107
+ else
108
+ for (let i = 0; i < args.length; i++) {
109
+ argParams.push([`p${i}`, infer(args[i], c)])
110
+ }
111
+ const ret = []
112
+ if (c?.isWebGL) {
113
+ for (const [paramId, type] of argParams) {
114
+ addDependency(c, id!, type)
115
+ params.push(`${type} ${paramId}`)
116
+ }
117
+ addDependency(c, id!, returnType)
118
+ ret.push(`${returnType} ${id}(${params}) {`)
119
+ } else {
120
+ for (const [paramId, type] of argParams) params.push(`${paramId}: ${getConversions(type, c)}`)
121
+ ret.push(`fn ${id}(${params}) -> ${getConversions(returnType, c)} {`)
122
+ }
123
+ const scopeCode = code(x, c)
124
+ if (scopeCode) ret.push(scopeCode)
125
+ ret.push('}')
126
+ return ret.join('\n')
127
+ }
128
+
126
129
  /**
127
130
  * headers
128
131
  */
129
132
  export const parseVaryingHead = (c: NodeContext, id: string, type: string) => {
130
133
  return c.isWebGL
131
134
  ? `${type} ${id};`
132
- : `@location(${c.code?.vertVaryings?.size || 0}) ${id}: ${formatConversions(type, c)}`
135
+ : `@location(${c.code?.vertVaryings?.size || 0}) ${id}: ${getConversions(type, c)}`
133
136
  }
134
137
 
135
138
  export const parseUniformHead = (c: NodeContext, id: string, type: Constants) => {
@@ -146,17 +149,17 @@ export const parseUniformHead = (c: NodeContext, id: string, type: Constants) =>
146
149
  )
147
150
  }
148
151
  const { group = 0, binding = 0 } = c.gl?.webgpu?.uniforms.map.get(id) || {}
149
- const wgslType = formatConversions(type, c)
152
+ const wgslType = getConversions(type, c)
150
153
  return `@group(${group}) @binding(${binding}) var<uniform> ${id}: ${wgslType};`
151
154
  }
152
155
 
153
156
  export const parseAttribHead = (c: NodeContext, id: string, type: Constants) => {
154
157
  if (c.isWebGL) return `${type} ${id};`
155
158
  const { location = 0 } = c.gl?.webgpu?.attribs.map.get(id) || {}
156
- const wgslType = formatConversions(type, c)
159
+ const wgslType = getConversions(type, c)
157
160
  return `@location(${location}) ${id}: ${wgslType}`
158
161
  }
159
162
 
160
163
  export const parseConstantHead = (c: NodeContext, id: string, type: Constants, value: string) => {
161
- return c.isWebGL ? `const ${type} ${id} = ${value};` : `const ${id}: ${formatConversions(type, c)} = ${value};`
164
+ return c.isWebGL ? `const ${type} ${id} = ${value};` : `const ${id}: ${getConversions(type, c)} = ${value};`
162
165
  }
@@ -1,4 +1,3 @@
1
- import { is } from '../utils/helpers'
2
1
  import {
3
2
  CONSTANTS,
4
3
  CONVERSIONS,
@@ -8,7 +7,8 @@ import {
8
7
  TYPE_MAPPING,
9
8
  WGSL_TO_GLSL_BUILTIN,
10
9
  } from './const'
11
- import type { Constants, Conversions, Functions, NodeContext, NodeProxy, Operators, Swizzles, X } from './types'
10
+ import { is } from '../../utils/helpers'
11
+ import type { Constants, Conversions, Functions, NodeContext, NodeProxy, Operators, Swizzles, X } from '../types'
12
12
 
13
13
  export const isSwizzle = (key: unknown): key is Swizzles => {
14
14
  return is.str(key) && /^[xyzwrgbastpq]{1,4}$/.test(key)
@@ -46,9 +46,13 @@ export const hex2rgb = (hex: number) => {
46
46
 
47
47
  let count = 0
48
48
 
49
- export const getId = () => `i${count++}`
49
+ export const getId = () => `x${count++}`
50
50
 
51
- export const formatConversions = <T extends Constants>(x: X<T>, c?: NodeContext) => {
51
+ export const getBluiltin = (id: string) => {
52
+ return WGSL_TO_GLSL_BUILTIN[id as keyof typeof WGSL_TO_GLSL_BUILTIN]
53
+ }
54
+
55
+ export const getConversions = <T extends Constants>(x: X<T>, c?: NodeContext) => {
52
56
  if (!is.str(x)) return ''
53
57
  if (c?.isWebGL) return x
54
58
  return TYPE_MAPPING[x as keyof typeof TYPE_MAPPING] || x // for struct type
@@ -58,11 +62,7 @@ export const getOperator = (op: X<string>) => {
58
62
  return OPERATORS[op as keyof typeof OPERATORS] || op
59
63
  }
60
64
 
61
- export const getBluiltin = (id: string) => {
62
- return WGSL_TO_GLSL_BUILTIN[id as keyof typeof WGSL_TO_GLSL_BUILTIN]
63
- }
64
-
65
- export const conversionToConstant = (conversionKey: string): Constants => {
65
+ export const getConstant = (conversionKey: string): Constants => {
66
66
  const index = CONVERSIONS.indexOf(conversionKey as Conversions)
67
67
  return index !== -1 ? CONSTANTS[index] : 'float'
68
68
  }
@@ -79,7 +79,7 @@ export const getEventFun = (c: NodeContext, id: string, isAttribute = false, isT
79
79
  }
80
80
 
81
81
  export const safeEventCall = <T extends Constants>(x: X<T>, fun: (value: unknown) => void) => {
82
- if (!x) return
82
+ if (is.und(x)) return
83
83
  if (!isNodeProxy(x)) return fun(x) // for uniform(1)
84
84
  if (x.type !== 'conversion') return
85
85
  const value = x.props.children?.slice(1).filter(Boolean)
@@ -88,42 +88,26 @@ export const safeEventCall = <T extends Constants>(x: X<T>, fun: (value: unknown
88
88
  }
89
89
 
90
90
  export const initNodeContext = (c: NodeContext) => {
91
- if (!c.code) {
92
- c.code = {
93
- headers: new Map(),
94
- fragInputs: new Map(),
95
- vertInputs: new Map(),
96
- vertOutputs: new Map(),
97
- vertVaryings: new Map(),
98
- dependencies: new Map(),
99
- }
100
- if (!c.isWebGL) {
101
- c.code.fragInputs.set('position', '@builtin(position) position: vec4f')
102
- c.code.vertOutputs.set('position', '@builtin(position) position: vec4f')
103
- }
91
+ if (c.code) return c
92
+ c.code = {
93
+ headers: new Map(),
94
+ fragInputs: new Map(),
95
+ vertInputs: new Map(),
96
+ vertOutputs: new Map(),
97
+ vertVaryings: new Map(),
98
+ dependencies: new Map(),
104
99
  }
100
+ if (c.isWebGL) return c
101
+ c.code.fragInputs.set('position', '@builtin(position) position: vec4f')
102
+ c.code.vertOutputs.set('position', '@builtin(position) position: vec4f')
105
103
  return c
106
104
  }
107
105
 
106
+ export const isArrayAccess = (key: unknown): boolean => {
107
+ return is.num(key) || (is.str(key) && /^\d+$/.test(key))
108
+ }
109
+
108
110
  export const addDependency = (c: NodeContext, id = '', type: string) => {
109
111
  if (!c.code?.dependencies?.has(id)) c.code!.dependencies.set(id, new Set())
110
112
  if (!isConstants(type)) c.code!.dependencies.get(id)!.add(type)
111
113
  }
112
-
113
- export const sortHeadersByDependencies = (headers: Map<string, string>, dependencies: Map<string, Set<string>>) => {
114
- const sorted: [string, string][] = []
115
- const visited = new Set<string>()
116
- const visiting = new Set<string>()
117
- const visit = (id: string) => {
118
- if (visiting.has(id)) return
119
- if (visited.has(id)) return
120
- visiting.add(id)
121
- const deps = dependencies.get(id) || new Set()
122
- for (const dep of deps) if (headers.has(dep)) visit(dep)
123
- visiting.delete(id)
124
- visited.add(id)
125
- if (headers.has(id)) sorted.push([id, headers.get(id)!])
126
- }
127
- for (const [id] of headers) visit(id)
128
- return sorted
129
- }
package/src/types.ts CHANGED
@@ -2,56 +2,6 @@ import type { EventState, Nested } from 'reev'
2
2
  import type { Fun, Queue, Frame } from 'refr'
3
3
  import type { NodeProxy, Vec4 } from './node'
4
4
  export type { Fun, Queue, Frame }
5
- export type PrecisionMode = 'highp' | 'mediump' | 'lowp'
6
- export type GLClearMode = 'COLOR_BUFFER_BIT' | 'DEPTH_BUFFER_BIT' | 'STENCIL_BUFFER_BIT'
7
- export type GLDrawType = 'UNSIGNED_BYTE' | 'UNSIGNED_SHORT' | 'UNSIGNED_INT'
8
- export type GLDrawMode =
9
- | 'POINTS'
10
- | 'LINE_STRIP'
11
- | 'LINE_LOOP'
12
- | 'LINES'
13
- | 'TRIANGLE_STRIP'
14
- | 'TRIANGLE_FAN'
15
- | 'TRIANGLES'
16
-
17
- export interface UniformData {
18
- array: Float32Array
19
- buffer: GPUBuffer
20
- binding: number
21
- group: number
22
- }
23
-
24
- export interface TextureData {
25
- binding: number
26
- group: number
27
- texture: GPUTexture
28
- sampler: GPUSampler
29
- view: GPUTextureView
30
- }
31
-
32
- export interface AttribData {
33
- array: Float32Array
34
- buffer: GPUBuffer
35
- location: number
36
- stride: number
37
- }
38
-
39
- export interface WebGLState {
40
- context: WebGLRenderingContext
41
- program: WebGLProgram
42
- }
43
-
44
- export interface WebGPUState {
45
- device: GPUDevice
46
- uniforms: Nested<UniformData>
47
- textures: Nested<TextureData>
48
- attribs: Nested<AttribData>
49
- }
50
-
51
- export type Uniform = number | number[]
52
- export type Attribute = number[]
53
- export type Attributes = Record<string, Attribute>
54
- export type Uniforms = Record<string, Uniform>
55
5
 
56
6
  export type GL = EventState<{
57
7
  /**
@@ -59,20 +9,25 @@ export type GL = EventState<{
59
9
  */
60
10
  isNative: boolean
61
11
  isWebGL: boolean
12
+ isError: boolean
62
13
  isLoop: boolean
63
14
  isGL: true
64
- width: number
65
- height: number
15
+ width?: number
16
+ height?: number
66
17
  size: [number, number]
67
18
  mouse: [number, number]
68
19
  count: number
20
+ loading: number
69
21
  el: HTMLCanvasElement
70
- vs: string | Vec4
71
- fs: string | Vec4
72
- vert: string | Vec4
73
- frag: string | Vec4
74
- vertex: string | Vec4
75
- fragment: string | Vec4
22
+ vs?: string | Vec4
23
+ cs?: string | Vec4
24
+ fs?: string | Vec4
25
+ vert?: string | Vec4
26
+ comp?: string | Vec4
27
+ frag?: string | Vec4
28
+ vertex?: string | Vec4
29
+ compute?: string | Vec4
30
+ fragment?: string | Vec4
76
31
 
77
32
  /**
78
33
  * core state
@@ -86,13 +41,13 @@ export type GL = EventState<{
86
41
  * events
87
42
  */
88
43
  ref?: any
89
- init(): void
90
- loop(): void
91
44
  mount(): void
92
45
  clean(): void
46
+ error(e?: string): void
93
47
  render(): void
94
48
  resize(e?: Event): void
95
49
  mousemove(e: Event): void
50
+ loop(): void
96
51
 
97
52
  /**
98
53
  * setter
@@ -107,4 +62,59 @@ export type GL = EventState<{
107
62
  _attribute?(key: string, value: Attribute, iboValue?: Attribute): GL
108
63
  attribute(key: string, value: Attribute, iboValue?: Attribute): GL
109
64
  attribute(target: { [key: string]: Attribute }): GL
65
+ _storage?(key: string, value: Storage): GL
66
+ storage(key: string, value: Storage): GL
67
+ storage(target: { [key: string]: Storage }): GL
110
68
  }>
69
+
70
+ type Uniform = number | number[] | Float32Array
71
+ type Attribute = number[] | Float32Array
72
+ type Storage = number[] | Float32Array
73
+
74
+ /**
75
+ * for webgpu
76
+ */
77
+ export interface UniformData {
78
+ array: Float32Array
79
+ buffer: GPUBuffer
80
+ binding: number
81
+ group: number
82
+ }
83
+
84
+ export interface TextureData {
85
+ binding: number
86
+ group: number
87
+ texture: GPUTexture
88
+ sampler: GPUSampler
89
+ view: GPUTextureView
90
+ }
91
+
92
+ export interface AttribData {
93
+ array: Float32Array
94
+ buffer: GPUBuffer
95
+ location: number
96
+ stride: number
97
+ }
98
+
99
+ export interface StorageData {
100
+ array: Float32Array
101
+ buffer: GPUBuffer
102
+ binding: number
103
+ group: number
104
+ }
105
+
106
+ export interface WebGPUState {
107
+ device: GPUDevice
108
+ uniforms: Nested<UniformData>
109
+ textures: Nested<TextureData>
110
+ attribs: Nested<AttribData>
111
+ storages: Nested<StorageData>
112
+ }
113
+
114
+ /**
115
+ * for webgl
116
+ */
117
+ export interface WebGLState {
118
+ context: WebGLRenderingContext
119
+ program: WebGLProgram
120
+ }
@@ -1,3 +1,5 @@
1
+ import type { GL } from './../types'
2
+
1
3
  export const is = {
2
4
  arr: Array.isArray,
3
5
  bol: (a: unknown): a is boolean => typeof a === 'boolean',
@@ -42,3 +44,17 @@ export const sig = (value = 0, digit = -2) => {
42
44
  value /= digit
43
45
  return value
44
46
  }
47
+
48
+ export const isFloat32 = (value: unknown): value is Float32Array => {
49
+ return value instanceof Float32Array
50
+ }
51
+
52
+ export const loadingImage = (gl: GL, src: string, fun: (source: HTMLImageElement) => void) => {
53
+ gl.loading++
54
+ const source = new Image()
55
+ Object.assign(source, { src, crossOrigin: 'anonymous' })
56
+ source.decode().then(() => {
57
+ fun(source)
58
+ gl.loading--
59
+ })
60
+ }
@@ -1,13 +1,15 @@
1
- import type { AttribData, TextureData, UniformData } from '../types'
1
+ import { isFloat32 } from './helpers'
2
+ import type { AttribData, TextureData, UniformData, StorageData } from '../types'
2
3
 
3
4
  /**
4
5
  * initialize
5
6
  */
6
- export const createDevice = async (c: GPUCanvasContext) => {
7
+ export const createDevice = async (c: GPUCanvasContext, log = console.log) => {
7
8
  const gpu = navigator.gpu
8
9
  const format = gpu.getPreferredCanvasFormat()
9
10
  const adapter = await gpu.requestAdapter()
10
11
  const device = await adapter!.requestDevice()
12
+ device.onuncapturederror = (e) => log(e.error.message)
11
13
  c.configure({ device, format, alphaMode: 'opaque' })
12
14
  return { device, format }
13
15
  }
@@ -15,6 +17,7 @@ export const createDevice = async (c: GPUCanvasContext) => {
15
17
  export const createBindings = () => {
16
18
  let uniform = 0
17
19
  let texture = 0
20
+ let storage = 0
18
21
  let attrib = 0
19
22
  return {
20
23
  uniform: () => {
@@ -30,6 +33,13 @@ export const createBindings = () => {
30
33
  texture++
31
34
  return { group, binding }
32
35
  },
36
+ storage: () => {
37
+ const baseGroup = Math.floor(uniform / 12) + Math.floor(texture / 6) + 2
38
+ const group = baseGroup + Math.floor(storage / 12)
39
+ const binding = storage % 12
40
+ storage++
41
+ return { group, binding }
42
+ },
33
43
  attrib: () => {
34
44
  const location = attrib
35
45
  attrib++
@@ -70,7 +80,8 @@ export const createVertexBuffers = (attribs: Iterable<AttribData>) => {
70
80
  export const createBindGroup = (
71
81
  device: GPUDevice,
72
82
  uniforms: Iterable<UniformData>,
73
- textures: Iterable<TextureData>
83
+ textures: Iterable<TextureData>,
84
+ storages: Iterable<StorageData> = []
74
85
  ) => {
75
86
  const groups = new Map<number, { layouts: GPUBindGroupLayoutEntry[]; bindings: GPUBindGroupEntry[] }>()
76
87
  const ret = { bindGroups: [] as GPUBindGroup[], bindGroupLayouts: [] as GPUBindGroupLayout[] }
@@ -81,7 +92,10 @@ export const createBindGroup = (
81
92
  bindings.push(binding)
82
93
  }
83
94
  for (const { binding, buffer, group: i } of uniforms) {
84
- add(i, { binding, visibility: 3, buffer: { type: 'uniform' } }, { binding, resource: { buffer } })
95
+ add(i, { binding, visibility: 7, buffer: { type: 'uniform' } }, { binding, resource: { buffer } })
96
+ }
97
+ for (const { binding, buffer, group: i } of storages) {
98
+ add(i, { binding, visibility: 6, buffer: { type: 'storage' } }, { binding, resource: { buffer } })
85
99
  }
86
100
  for (const { binding: b, group: i, sampler, view } of textures) {
87
101
  add(i, { binding: b, visibility: 2, sampler: {} }, { binding: b, resource: sampler })
@@ -123,19 +137,34 @@ export const createPipeline = (
123
137
  })
124
138
  }
125
139
 
140
+ export const createComputePipeline = (device: GPUDevice, bindGroupLayouts: GPUBindGroupLayout[], cs: string) => {
141
+ return device.createComputePipeline({
142
+ compute: {
143
+ module: device.createShaderModule({ label: 'compute', code: cs }),
144
+ entryPoint: 'main',
145
+ },
146
+ layout: device.createPipelineLayout({ bindGroupLayouts }),
147
+ })
148
+ }
149
+
126
150
  /**
127
151
  * buffers
128
152
  */
129
- export const createUniformBuffer = (device: GPUDevice, value: number[]) => {
130
- const array = new Float32Array(value)
131
- const size = Math.ceil(array.byteLength / 256) * 256
132
- const buffer = device.createBuffer({ size, usage: 72 }) // 72 is GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
133
- return { array, buffer }
153
+ const bufferUsage = (type: 'uniform' | 'storage' | 'attrib') => {
154
+ if (type === 'uniform') return 72 // GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
155
+ if (type === 'attrib') return 40 // GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST
156
+ return 140 // GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST
134
157
  }
135
158
 
136
- export const createAttribBuffer = (device: GPUDevice, value: number[]) => {
137
- const array = new Float32Array(value)
138
- const buffer = device.createBuffer({ size: array.byteLength, usage: 40 }) // 40 is GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST
159
+ export const createArrayBuffer = (
160
+ device: GPUDevice,
161
+ array: number[] | Float32Array,
162
+ type: 'uniform' | 'storage' | 'attrib'
163
+ ) => {
164
+ if (!isFloat32(array)) array = new Float32Array(array)
165
+ const usage = bufferUsage(type)
166
+ const size = type === 'uniform' ? Math.ceil(array.byteLength / 256) * 256 : array.byteLength
167
+ const buffer = device.createBuffer({ size, usage })
139
168
  return { array, buffer }
140
169
  }
141
170
 
@@ -1,30 +1,38 @@
1
- const createShader = (c: WebGLRenderingContext, source: string, type: number) => {
1
+ import { fragment, vertex } from '../node'
2
+ import { is } from './helpers'
3
+ import type { X } from '../node'
4
+ import type { GL } from '../types'
5
+
6
+ const createShader = (c: WebGLRenderingContext, source: string, type: number, onError = console.warn) => {
2
7
  const shader = c.createShader(type)
3
- if (!shader) throw new Error('Failed to create shader')
8
+ if (!shader) return onError('Failed to create shader')
4
9
  c.shaderSource(shader, source.trim())
5
10
  c.compileShader(shader)
6
11
  if (c.getShaderParameter(shader, c.COMPILE_STATUS)) return shader
7
12
  const error = c.getShaderInfoLog(shader)
8
13
  c.deleteShader(shader)
9
- console.warn(`Could not compile shader: ${error}`)
14
+ onError(`Could not compile shader: ${error}`)
10
15
  }
11
16
 
12
- export const createProgram = (c: WebGLRenderingContext, vert: string, frag: string, onError = () => {}) => {
17
+ export const createProgram = (c: WebGLRenderingContext, vert: X, frag: X, gl: GL) => {
18
+ if (!vert || !frag) return
19
+ const config = { isWebGL: true, gl }
20
+ frag = fragment(frag, config) // needs to be before vertex
21
+ vert = vertex(vert, config)
13
22
  const pg = c.createProgram()
14
- const fs = createShader(c, frag, c.FRAGMENT_SHADER)
15
- const vs = createShader(c, vert, c.VERTEX_SHADER)
16
- if (!fs || !vs) return onError()
17
- c.attachShader(pg, vs)
18
- c.attachShader(pg, fs)
23
+ const vs = createShader(c, vert, c.VERTEX_SHADER, gl.error)
24
+ const fs = createShader(c, frag, c.FRAGMENT_SHADER, gl.error)
25
+ if (!fs || !vs) return
26
+ c.attachShader(pg, vs!)
27
+ c.attachShader(pg, fs!)
19
28
  c.linkProgram(pg)
20
29
  if (c.getProgramParameter(pg, c.LINK_STATUS)) return pg
21
30
  const error = c.getProgramInfoLog(pg)
22
31
  c.deleteProgram(pg)
23
- onError()
24
- console.warn(`Could not link program: ${error}`)
32
+ gl.error(`Could not link program: ${error}`)
25
33
  }
26
34
 
27
- export const createVbo = (c: WebGLRenderingContext, data: number[]) => {
35
+ const createVbo = (c: WebGLRenderingContext, data: number[]) => {
28
36
  const buffer = c.createBuffer()
29
37
  c.bindBuffer(c.ARRAY_BUFFER, buffer)
30
38
  c.bufferData(c.ARRAY_BUFFER, new Float32Array(data), c.STATIC_DRAW)
@@ -32,7 +40,7 @@ export const createVbo = (c: WebGLRenderingContext, data: number[]) => {
32
40
  return buffer
33
41
  }
34
42
 
35
- export const createIbo = (c: WebGLRenderingContext, data: number[]) => {
43
+ const createIbo = (c: WebGLRenderingContext, data: number[]) => {
36
44
  const buffer = c.createBuffer()
37
45
  c.bindBuffer(c.ELEMENT_ARRAY_BUFFER, buffer)
38
46
  c.bufferData(c.ELEMENT_ARRAY_BUFFER, new Int16Array(data), c.STATIC_DRAW)
@@ -40,7 +48,7 @@ export const createIbo = (c: WebGLRenderingContext, data: number[]) => {
40
48
  return buffer
41
49
  }
42
50
 
43
- export const getStride = (count: number, value: number[], iboValue?: number[]) => {
51
+ const getStride = (count: number, value: number[], iboValue?: number[]) => {
44
52
  if (iboValue) count = Math.max(...iboValue) + 1
45
53
  const stride = value.length / count
46
54
  return Math.floor(stride)
@@ -48,17 +56,28 @@ export const getStride = (count: number, value: number[], iboValue?: number[]) =
48
56
 
49
57
  export const createAttrib = (
50
58
  c: WebGLRenderingContext,
51
- stride: number,
52
- loc: any,
53
- vbo: WebGLBuffer,
54
- ibo?: WebGLBuffer
59
+ loc: number,
60
+ count: number,
61
+ value: number[],
62
+ iboValue: number[]
55
63
  ) => {
64
+ const vbo = createVbo(c, value)
65
+ const ibo = createIbo(c, iboValue)
66
+ const str = getStride(count, value, iboValue)
56
67
  c.bindBuffer(c.ARRAY_BUFFER, vbo)
57
68
  c.enableVertexAttribArray(loc)
58
- c.vertexAttribPointer(loc, stride, c.FLOAT, false, 0, 0)
69
+ c.vertexAttribPointer(loc, str, c.FLOAT, false, 0, 0)
59
70
  if (ibo) c.bindBuffer(c.ELEMENT_ARRAY_BUFFER, ibo)
60
71
  }
61
72
 
73
+ export const createUniform = (c: WebGLRenderingContext, loc: WebGLUniformLocation, value: number | number[]) => {
74
+ if (is.num(value)) return c.uniform1f(loc, value)
75
+ let l = value.length
76
+ if (l <= 4) return c[`uniform${l as 2}fv`](loc, value)
77
+ l = Math.sqrt(l) << 0
78
+ c[`uniformMatrix${l as 2}fv`](loc, false, value)
79
+ }
80
+
62
81
  export const createTexture = (c: WebGLRenderingContext, img: HTMLImageElement, loc: any, unit: number) => {
63
82
  const texture = c.createTexture()
64
83
  c.bindTexture(c.TEXTURE_2D, texture)
@@ -73,3 +92,21 @@ export const createTexture = (c: WebGLRenderingContext, img: HTMLImageElement, l
73
92
  c.activeTexture(c.TEXTURE0 + unit)
74
93
  c.bindTexture(c.TEXTURE_2D, texture)
75
94
  }
95
+
96
+ export const createStorage = (c: WebGL2RenderingContext, size: number, storage: any, array: any) => {
97
+ const data = new Float32Array(size * size * 4)
98
+ for (let i = 0; i < array.length; i++) data[i * 4] = array[i]
99
+ c.activeTexture(c.TEXTURE0 + storage.unit)
100
+ c.bindTexture(c.TEXTURE_2D, storage.a.texture)
101
+ c.texImage2D(c.TEXTURE_2D, 0, c.RGBA32F, size, size, 0, c.RGBA, c.FLOAT, data)
102
+ c.texParameteri(c.TEXTURE_2D, c.TEXTURE_MIN_FILTER, c.NEAREST)
103
+ c.texParameteri(c.TEXTURE_2D, c.TEXTURE_MAG_FILTER, c.NEAREST)
104
+ c.texParameteri(c.TEXTURE_2D, c.TEXTURE_WRAP_S, c.CLAMP_TO_EDGE)
105
+ c.texParameteri(c.TEXTURE_2D, c.TEXTURE_WRAP_T, c.CLAMP_TO_EDGE)
106
+ c.bindTexture(c.TEXTURE_2D, storage.b.texture)
107
+ c.texImage2D(c.TEXTURE_2D, 0, c.RGBA32F, size, size, 0, c.RGBA, c.FLOAT, null)
108
+ c.texParameteri(c.TEXTURE_2D, c.TEXTURE_MIN_FILTER, c.NEAREST)
109
+ c.texParameteri(c.TEXTURE_2D, c.TEXTURE_MAG_FILTER, c.NEAREST)
110
+ c.texParameteri(c.TEXTURE_2D, c.TEXTURE_WRAP_S, c.CLAMP_TO_EDGE)
111
+ c.texParameteri(c.TEXTURE_2D, c.TEXTURE_WRAP_T, c.CLAMP_TO_EDGE)
112
+ }