glre 0.21.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.
@@ -0,0 +1,100 @@
1
+ import { OPERATORS, FUNCTIONS, SWIZZLES } from './const'
2
+ import { is } from '../utils/helpers'
3
+ import type { NodeType } from './const'
4
+ import type { Node, ProxyCallback, X } from './types'
5
+
6
+ let nodeIdCounter = 0
7
+
8
+ // ノードIDを生成
9
+ const generateNodeId = () => `node_${++nodeIdCounter}`
10
+
11
+ // ノードを作成
12
+ export const createNode = (type: NodeType, value?: any, options?: Partial<Node>): Node => {
13
+ return {
14
+ id: generateNodeId(),
15
+ type,
16
+ value,
17
+ children: [],
18
+ ...options,
19
+ }
20
+ }
21
+
22
+ const isSwizzleProperty = (key = '') => SWIZZLES.includes(key as any)
23
+ const isOperatorMethod = (key = '') => OPERATORS.includes(key as any)
24
+ const isMathMethod = (key = '') => FUNCTIONS.includes(key as any)
25
+
26
+ // Proxyハンドラーを作成
27
+ const createNodeProxy = (node: Node, callback?: (info: ProxyCallback) => X) => {
28
+ const get = (_target: unknown, key: unknown) => {
29
+ if (!is.str(key) || key === 'then') return void 0
30
+
31
+ if (key === 'id') return node.id
32
+ if (key === 'type') return node.type
33
+ if (key === 'value') return node.value
34
+ if (key === 'property') return node.property
35
+
36
+ // swizzle prooerty
37
+ if (isSwizzleProperty(key))
38
+ return createNodeProxy(
39
+ createNode(getSwizzleType(key), undefined, {
40
+ parent: node,
41
+ property: key,
42
+ }),
43
+ callback
44
+ )
45
+
46
+ // 演算子メソッド
47
+ if (isOperatorMethod(key))
48
+ return (...args: any[]) => {
49
+ return createNodeProxy(
50
+ createNode(node.type, undefined, {
51
+ operator: key as any,
52
+ children: [node, ...args],
53
+ }),
54
+ callback
55
+ )
56
+ }
57
+
58
+ // 数学関数メソッド
59
+ if (isMathMethod(key))
60
+ return (...args: any[]) => {
61
+ return createNodeProxy(
62
+ createNode(getMathReturnType(key, node.type), undefined, {
63
+ mathFunction: key as any,
64
+ children: [node, ...args],
65
+ }),
66
+ callback
67
+ )
68
+ }
69
+
70
+ return callback?.({ path: [key], args: [] })
71
+ }
72
+ const apply = (_target: unknown, _thisArg: unknown, args: any) => {
73
+ return callback?.({ path: [], args })
74
+ }
75
+
76
+ return new Proxy(() => {}, { get, apply }) as X
77
+ }
78
+
79
+ // スウィズルの戻り値型を取得
80
+ const getSwizzleType = (swizzle: string): NodeType => {
81
+ if (swizzle.length === 1) return 'float'
82
+ if (swizzle.length === 2) return 'vec2'
83
+ if (swizzle.length === 3) return 'vec3'
84
+ if (swizzle.length === 4) return 'vec4'
85
+ return 'float'
86
+ }
87
+
88
+ // 数学関数の戻り値型を取得
89
+ const getMathReturnType = (func: string, inputType: NodeType): NodeType => {
90
+ if (func === 'length') return 'float'
91
+ if (func === 'normalize') return inputType
92
+ if (func === 'toVar') return inputType
93
+ return inputType
94
+ }
95
+
96
+ // 公開API
97
+ export const node = (type: NodeType, value?: any, options?: Partial<Node>) => {
98
+ const nodeInstance = createNode(type, value, options)
99
+ return createNodeProxy(nodeInstance)
100
+ }
@@ -0,0 +1,101 @@
1
+ import type { NodeType, Operator, MathFunction, Swillzes } from './const'
2
+
3
+ // ノードの基本インターフェース
4
+ export interface Node {
5
+ id: string
6
+ type: NodeType
7
+ value?: any
8
+ property?: string
9
+ parent?: Node
10
+ children?: Node[]
11
+ operator?: Operator
12
+ mathFunction?: MathFunction
13
+ }
14
+
15
+ // Proxyハンドラーのコールバック型
16
+ export interface ProxyCallback {
17
+ path: string[]
18
+ args: any[]
19
+ }
20
+
21
+ // ノード作成関数の型
22
+ export type NodeCreator = (value?: any) => X
23
+
24
+ // 演算子メソッドの型
25
+ export interface OperatorMethods {
26
+ add(x: X | number): X
27
+ sub(x: X | number): X
28
+ mul(x: X | number): X
29
+ div(x: X | number): X
30
+ mod(x: X | number): X
31
+ equal(x: X | number): X
32
+ notEqual(x: X | number): X
33
+ lessThan(x: X | number): X
34
+ lessThanEqual(x: X | number): X
35
+ greaterThan(x: X | number): X
36
+ greaterThanEqual(x: X | number): X
37
+ and(x: X): X
38
+ or(x: X): X
39
+ not(): X
40
+ }
41
+
42
+ // 数学関数メソッドの型
43
+ export interface MathMethods {
44
+ abs(): X
45
+ acos(): X
46
+ asin(): X
47
+ atan(): X
48
+ ceil(): X
49
+ cos(): X
50
+ floor(): X
51
+ fract(): X
52
+ length(): X
53
+ normalize(): X
54
+ sin(): X
55
+ sqrt(): X
56
+ tan(): X
57
+ toVar(): X
58
+ }
59
+
60
+ // 全てのswizzleパターンをまとめる型
61
+
62
+ // スウィズルプロパティの型
63
+ export type SwizzleProperties = {
64
+ [k in Swillzes]: X
65
+ }
66
+
67
+ // ノードProxy型
68
+ export interface X extends MathMethods, OperatorMethods, SwizzleProperties {
69
+ readonly id: string
70
+ readonly type: NodeType
71
+ readonly value: any
72
+ readonly property: string
73
+ (...args: any[]): X
74
+ }
75
+
76
+ // ユニフォーム変数の型
77
+ export interface UniformNode extends X {
78
+ set(value: any): void
79
+ onObjectUpdate(callback: (context: any) => any): UniformNode
80
+ onRenderUpdate(callback: (context: any) => any): UniformNode
81
+ }
82
+
83
+ // 関数定義の型
84
+ export interface FunctionNode {
85
+ (...args: any[]): X
86
+ call(x: X[]): X
87
+ }
88
+
89
+ // 条件分岐の型
90
+ export interface ConditionalNode {
91
+ ElseIf(condition: X, callback: () => void): ConditionalNode
92
+ Else(callback: () => void): void
93
+ }
94
+
95
+ // WebGL/WebGPU変換コンテキスト
96
+ export interface ConversionContext {
97
+ target: 'webgl' | 'webgpu'
98
+ nodes: Map<string, Node>
99
+ variables: Map<string, string>
100
+ functions: Map<string, string>
101
+ }
@@ -0,0 +1,92 @@
1
+ import { node } from './node'
2
+ import { is } from '../utils/helpers'
3
+ import type { UniformNode } from './types'
4
+ import type { NodeType } from './const'
5
+
6
+ // ユニフォーム更新コンテキスト
7
+ interface UpdateContext {
8
+ object?: any
9
+ camera?: any
10
+ renderer?: any
11
+ scene?: any
12
+ time?: number
13
+ }
14
+
15
+ // ユニフォーム値の型を推定
16
+ const inferUniformType = (value: any): NodeType => {
17
+ if (is.num(value)) return 'float'
18
+ if (is.bol(value)) return 'bool'
19
+ if (is.arr(value)) {
20
+ const len = value.length
21
+ if (len === 2) return 'vec2'
22
+ if (len === 3) return 'vec3'
23
+ if (len === 4) return 'vec4'
24
+ if (len === 9) return 'mat3'
25
+ if (len === 16) return 'mat4'
26
+ }
27
+ if (is.obj(value) && 'r' in value && 'g' in value && 'b' in value) return 'color'
28
+ return 'float'
29
+ }
30
+
31
+ // ユニフォーム変数を作成
32
+ export const uniform = (initialValue: any): UniformNode => {
33
+ const type = inferUniformType(initialValue)
34
+ let currentValue = initialValue
35
+ let objectUpdateCallback: ((context: UpdateContext) => any) | null = null
36
+ let renderUpdateCallback: ((context: UpdateContext) => any) | null = null
37
+
38
+ const baseNode = node(type, currentValue) as any
39
+
40
+ // 値を設定
41
+ const set = (value: any) => {
42
+ currentValue = value
43
+ baseNode.value = value
44
+ }
45
+ // オブジェクト更新時のコールバックを設定
46
+ const onObjectUpdate = (callback: (context: UpdateContext) => any): UniformNode => {
47
+ objectUpdateCallback = callback
48
+ return uniformNode
49
+ }
50
+ // レンダー更新時のコールバックを設定
51
+ const onRenderUpdate = (callback: (context: UpdateContext) => any): UniformNode => {
52
+ renderUpdateCallback = callback
53
+ return uniformNode
54
+ }
55
+ // 内部更新関数(外部から呼び出される)
56
+ const _updateFromContext = (context: UpdateContext) => {
57
+ if (objectUpdateCallback) {
58
+ const newValue = objectUpdateCallback(context)
59
+ if (newValue !== undefined) set(newValue)
60
+ }
61
+ if (renderUpdateCallback) {
62
+ const newValue = renderUpdateCallback(context)
63
+ if (newValue !== undefined) set(newValue)
64
+ }
65
+ }
66
+ // UniformNodeインターフェースを実装
67
+ const uniformNode = Object.create(baseNode)
68
+ uniformNode.set = set
69
+ uniformNode.onObjectUpdate = onObjectUpdate
70
+ uniformNode.onRenderUpdate = onRenderUpdate
71
+ uniformNode._updateFromContext = _updateFromContext
72
+ uniformNode.isUniform = true
73
+ return uniformNode as UniformNode
74
+ }
75
+
76
+ // 組み込みユニフォーム変数
77
+ export const iTime = uniform(0.0)
78
+ export const iPrevTime = uniform(0.0)
79
+ export const iDeltaTime = uniform(0.0)
80
+ export const iResolution = uniform([1920, 1080])
81
+ export const iMouse = uniform([0, 0])
82
+
83
+ // ユニフォーム変数の更新(レンダーループで呼び出される)
84
+ export const updateUniforms = (context: UpdateContext) => {
85
+ // 時間の更新
86
+ if (context.time !== undefined) {
87
+ const prevTime = iTime.value || 0
88
+ iTime.set(context.time)
89
+ iPrevTime.set(prevTime)
90
+ iDeltaTime.set(context.time - prevTime)
91
+ }
92
+ }
package/src/react.ts ADDED
@@ -0,0 +1,17 @@
1
+ import { useState } from 'react'
2
+ import { createGL, isGL } from './index'
3
+ import type { GL } from './types'
4
+ export * from './index'
5
+
6
+ export const useGL = (props: Partial<GL> = {}) => {
7
+ return useState(() => {
8
+ const gl = isGL(props) ? props : createGL(props)
9
+ gl.ref = (el: HTMLCanvasElement | null) => {
10
+ if (el) {
11
+ gl.el = el
12
+ gl.mount()
13
+ } else gl.clean()
14
+ }
15
+ return gl
16
+ })[0]
17
+ }
package/src/solid.ts ADDED
@@ -0,0 +1,14 @@
1
+ import { createGL, isGL } from './index'
2
+ import type { GL } from './types'
3
+ export * from './index'
4
+
5
+ export const onGL = (props?: Partial<GL>) => {
6
+ const gl = isGL(props) ? props : createGL(props)
7
+ gl.ref = (el: HTMLCanvasElement | null) => {
8
+ if (el) {
9
+ gl.el = el
10
+ gl.mount()
11
+ } else gl.clean()
12
+ }
13
+ return gl
14
+ }
package/src/types.ts ADDED
@@ -0,0 +1,89 @@
1
+ import { EventState } from 'reev'
2
+ import type { Fun, Queue, Frame } from 'refr'
3
+ import type { X } from './node'
4
+ export type { Fun, Queue, Frame }
5
+ export type GPUContext = any // GPUCanvasContext https://developer.mozilla.org/en-US/docs/Web/API/GPUCanvasContext
6
+ export type GPUDevice = any //
7
+ export type GPUBuffer = any //
8
+ export type GPUPipeline = any //
9
+ export type Uniform = number | number[]
10
+ export type Attribute = number[]
11
+ export type Attributes = Record<string, Attribute>
12
+ export type Uniforms = Record<string, Uniform>
13
+ export type PrecisionMode = 'highp' | 'mediump' | 'lowp'
14
+ export type GLClearMode = 'COLOR_BUFFER_BIT' | 'DEPTH_BUFFER_BIT' | 'STENCIL_BUFFER_BIT'
15
+ export type GLDrawType = 'UNSIGNED_BYTE' | 'UNSIGNED_SHORT' | 'UNSIGNED_INT'
16
+ export type GLDrawMode =
17
+ | 'POINTS'
18
+ | 'LINE_STRIP'
19
+ | 'LINE_LOOP'
20
+ | 'LINES'
21
+ | 'TRIANGLE_STRIP'
22
+ | 'TRIANGLE_FAN'
23
+ | 'TRIANGLES'
24
+
25
+ export interface WebGLState {
26
+ context: WebGLRenderingContext
27
+ program: WebGLProgram
28
+ }
29
+
30
+ export interface WebGPUState {
31
+ device: GPUDevice
32
+ context: GPUContext
33
+ pipeline: GPUPipeline
34
+ }
35
+
36
+ export type GL = EventState<{
37
+ /**
38
+ * initial value
39
+ */
40
+ isNative: boolean
41
+ isWebGL: boolean
42
+ isLoop: boolean
43
+ isGL: true
44
+ width: number
45
+ height: number
46
+ size: [number, number]
47
+ mouse: [number, number]
48
+ count: number
49
+ el: HTMLCanvasElement
50
+ vs: string | X
51
+ fs: string | X
52
+ vert: string | X
53
+ frag: string | X
54
+ vertex: string | X
55
+ fragment: string | X
56
+
57
+ /**
58
+ * core state
59
+ */
60
+ webgpu: WebGPUState
61
+ webgl: WebGLState
62
+ queue: Queue
63
+ frame: Frame
64
+
65
+ /**
66
+ * events
67
+ */
68
+ ref?: any
69
+ init(): void
70
+ loop(): void
71
+ mount(): void
72
+ clean(): void
73
+ render(): void
74
+ resize(e?: Event): void
75
+ mousemove(e: Event): void
76
+
77
+ /**
78
+ * setter
79
+ */
80
+ _uniform?(key: string, value: Uniform, isMatrix?: boolean): GL
81
+ uniform(key: string, value: Uniform, isMatrix?: boolean): GL
82
+ uniform(target: { [key: string]: Uniform }): GL
83
+ _texture?(key: string, value: string): GL
84
+ texture(key: string, value: string): GL
85
+ texture(target: { [key: string]: string }): GL
86
+ _attribute?(key: string, value: Attribute, iboValue?: Attribute): GL
87
+ attribute(key: string, value: Attribute, iboValue?: Attribute): GL
88
+ attribute(target: { [key: string]: Attribute }): GL
89
+ }>
@@ -0,0 +1,44 @@
1
+ export const is = {
2
+ arr: Array.isArray,
3
+ bol: (a: unknown): a is boolean => typeof a === 'boolean',
4
+ str: (a: unknown): a is string => typeof a === 'string',
5
+ num: (a: unknown): a is number => typeof a === 'number',
6
+ int: (a: unknown): a is number => Number.isInteger(a),
7
+ fun: (a: unknown): a is Function => typeof a === 'function',
8
+ und: (a: unknown): a is undefined => typeof a === 'undefined',
9
+ nul: (a: unknown): a is null => a === null,
10
+ set: (a: unknown): a is Set<unknown> => a instanceof Set,
11
+ map: (a: unknown): a is Map<unknown, unknown> => a instanceof Map,
12
+ obj: (a: unknown): a is object => !!a && a.constructor.name === 'Object',
13
+ nan: (a: unknown): a is number => typeof a === 'number' && Number.isNaN(a),
14
+ }
15
+
16
+ /**
17
+ * each
18
+ */
19
+ type EachFn<Value, Key, This> = (this: This, value: Value, key: Key) => void
20
+ type Eachable<Value = any, Key = any, This = any> = {
21
+ forEach(cb: EachFn<Value, Key, This>, ctx?: This): void
22
+ }
23
+
24
+ export const each = <Value, Key, This>(obj: Eachable<Value, Key, This>, fn: EachFn<Value, Key, This>) => obj.forEach(fn)
25
+
26
+ export const flush = <Value extends Function, Key, This>(obj: Eachable<Value, Key, This>, ...args: any[]) => {
27
+ each(obj, (f) => f(...args))
28
+ }
29
+
30
+ /**
31
+ * other
32
+ */
33
+ export const replace = (x = '', from = '_', to = '/') => x.split(from).join(to)
34
+ export const ext = (src = '.pdf') => src.split('.').pop()?.toLowerCase() ?? ''
35
+ export const fig = (x = 0) => `${x}`.split('.')[1]?.length ?? 0
36
+ export const dig = (x = 0) => `${x}`.split('.')[0]?.length - (x < 0 ? 1 : 0)
37
+ export const sig = (value = 0, digit = -2) => {
38
+ digit *= -1
39
+ digit = Math.pow(10, digit)
40
+ value *= digit
41
+ value = Math.round(value)
42
+ value /= digit
43
+ return value
44
+ }
@@ -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
+ }