glre 0.26.0 → 0.27.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,5 +1,4 @@
1
- import { wgsl } from '../code/wgsl'
2
- import { X } from '../node'
1
+ import { fragment, vertex, X } from '../node'
3
2
  import { is } from './helpers'
4
3
  import type { GPUContext, GPUDevice, GPUPipeline } from '../types'
5
4
 
@@ -21,7 +20,7 @@ fn main(@builtin(position) position: vec4f) -> @location(0) vec4f {
21
20
  }
22
21
  `
23
22
 
24
- export const createDevive = async (c: GPUContext) => {
23
+ export const createDevice = async (c: GPUContext) => {
25
24
  const gpu = (navigator as any).gpu
26
25
  const format = gpu.getPreferredCanvasFormat()
27
26
  const adapter = await gpu.requestAdapter()
@@ -38,8 +37,8 @@ export const createPipeline = (
38
37
  vs: string | X = defaultVertexWGSL,
39
38
  fs: string | X = defaultFragmentWGSL
40
39
  ) => {
41
- if (is.obj(fs)) fs = wgsl(fs)
42
- if (is.obj(vs)) vs = wgsl(vs)
40
+ if (!is.str(fs)) fs = fragment(fs, { isWebGL: false })
41
+ if (!is.str(vs)) vs = vertex(vs, { isWebGL: false })
43
42
  const layout = device.createPipelineLayout({ bindGroupLayouts })
44
43
  return device.createRenderPipeline({
45
44
  vertex: {
@@ -1,5 +1,4 @@
1
- import { glsl } from '../code/glsl'
2
- import { X } from '../node'
1
+ import { fragment, vertex, X } from '../node'
3
2
  import { is } from './helpers'
4
3
 
5
4
  export const defaultVertexGLSL = /* cpp */ `
@@ -29,7 +28,7 @@ const createShader = (c: WebGLRenderingContext, source: string, type: number) =>
29
28
  if (c.getShaderParameter(shader, c.COMPILE_STATUS)) return shader
30
29
  const error = c.getShaderInfoLog(shader)
31
30
  c.deleteShader(shader)
32
- throw new Error(`Could not compile shader: ${error}`)
31
+ console.warn(`Could not compile shader: ${error}`)
33
32
  }
34
33
 
35
34
  export const createProgram = (
@@ -37,16 +36,19 @@ export const createProgram = (
37
36
  vs: string | X = defaultVertexGLSL,
38
37
  fs: string | X = defaultFragmentGLSL
39
38
  ) => {
40
- if (is.obj(fs)) fs = glsl(fs as X)
41
- if (is.obj(vs)) vs = glsl(vs as X)
39
+ if (!is.str(fs)) fs = fragment(fs, { isWebGL: true })
40
+ if (!is.str(vs)) vs = vertex(fs, { isWebGL: true })
42
41
  const pg = c.createProgram()
43
- c.attachShader(pg, createShader(c, vs, c.VERTEX_SHADER))
44
- c.attachShader(pg, createShader(c, fs, c.FRAGMENT_SHADER))
42
+ const _vs = createShader(c, vs, c.VERTEX_SHADER)
43
+ const _fs = createShader(c, fs, c.FRAGMENT_SHADER)
44
+ if (!_vs || !_fs) return
45
+ c.attachShader(pg, _vs)
46
+ c.attachShader(pg, _fs)
45
47
  c.linkProgram(pg)
46
48
  if (c.getProgramParameter(pg, c.LINK_STATUS)) return pg
47
49
  const error = c.getProgramInfoLog(pg)
48
50
  c.deleteProgram(pg)
49
- throw new Error(`Could not link pg: ${error}`)
51
+ console.warn(`Could not link pg: ${error}`)
50
52
  }
51
53
 
52
54
  export const createVbo = (c: WebGLRenderingContext, data: number[]) => {
package/src/webgl.ts CHANGED
@@ -5,7 +5,7 @@ import type { GL, WebGLState } from './types'
5
5
 
6
6
  export const webgl = async (gl: Partial<GL>) => {
7
7
  const c = gl.el!.getContext('webgl2')!
8
- const pg = createProgram(c, gl.vs, gl.fs)
8
+ const pg = createProgram(c, gl.vs, gl.fs)!
9
9
  const state = { context: c, program: pg } as WebGLState
10
10
  c.useProgram(pg)
11
11
 
package/src/webgpu.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { nested as cached } from 'reev'
2
2
  import { is } from './utils/helpers'
3
3
  import {
4
- createDevive,
4
+ createDevice,
5
5
  createPipeline,
6
6
  createDescriptor,
7
7
  createUniformBuffer,
@@ -14,7 +14,7 @@ import type { GL, WebGPUState } from './types'
14
14
 
15
15
  export const webgpu = async (gl: Partial<GL>) => {
16
16
  const c = gl.el!.getContext('webgpu') as any
17
- const { device, format } = await createDevive(c)
17
+ const { device, format } = await createDevice(c)
18
18
  const state = {
19
19
  device,
20
20
  context: c,
package/src/code/glsl.ts DELETED
@@ -1,148 +0,0 @@
1
- import { is } from './../utils/helpers'
2
- import type { Node, NodeType, X, ConversionContext } from '../node'
3
-
4
- // GLSLコード生成コンテキスト
5
- interface GLSLContext extends ConversionContext {
6
- target: 'webgl'
7
- precision: 'lowp' | 'mediump' | 'highp'
8
- version: '100' | '300 es'
9
- }
10
-
11
- // ノードからGLSLコードを生成
12
- export const nodeToGLSL = (nodeProxy: X, context?: Partial<GLSLContext>): string => {
13
- const ctx: GLSLContext = {
14
- target: 'webgl',
15
- precision: 'mediump',
16
- version: '300 es',
17
- nodes: new Map(),
18
- variables: new Map(),
19
- functions: new Map(),
20
- ...context,
21
- }
22
-
23
- return generateGLSLExpression(nodeProxy as any, ctx)
24
- }
25
-
26
- // GLSL式を生成
27
- const generateGLSLExpression = (node: Node, context: GLSLContext): string => {
28
- if (!node) return '0.0'
29
- // 値ノード
30
- if (!is.und(node.value)) return formatGLSLValue(node.value, node.type)
31
- // プロパティアクセス(スウィズル)
32
- if (node.property && node.parent) {
33
- const parentExpr = generateGLSLExpression(node.parent, context)
34
- return `${parentExpr}.${node.property}`
35
- }
36
- // 演算子ノード
37
- if (node.operator && node.children && node.children.length >= 2) return generateGLSLOperator(node, context)
38
- // 数学関数ノード
39
- if (node.mathFunction && node.children && node.children.length >= 1)
40
- return generateGLSLMathFunction(node, context)
41
- return '0.0'
42
- }
43
-
44
- // GLSL値をフォーマット
45
- const formatGLSLValue = (value: any, type: NodeType): string => {
46
- if (type === 'float') {
47
- const num = Number(value)
48
- return num % 1 === 0 ? `${num}.0` : `${num}`
49
- }
50
- if (type === 'int') return `${Math.floor(Number(value))}`
51
- if (type === 'bool') return Boolean(value) ? 'true' : 'false'
52
- if (is.arr(value)) {
53
- const values = value
54
- .map((v) => {
55
- const num = Number(v)
56
- return num % 1 === 0 ? `${num}.0` : `${num}`
57
- })
58
- .join(', ')
59
- if (type === 'vec2') return `vec2(${values})`
60
- if (type === 'vec3') return `vec3(${values})`
61
- if (type === 'vec4') return `vec4(${values})`
62
- if (type === 'color') return `vec3(${values})`
63
- }
64
- return '0.0'
65
- }
66
-
67
- // GLSL演算子を生成
68
- const generateGLSLOperator = (node: Node, context: GLSLContext): string => {
69
- if (!node.children || node.children.length < 2) return '0.0'
70
- const left = generateGLSLExpression(node.children[0], context)
71
- const right = generateGLSLExpression(node.children[1], context)
72
- if (node.operator === 'add') return `(${left} + ${right})`
73
- if (node.operator === 'sub') return `(${left} - ${right})`
74
- if (node.operator === 'mul') return `(${left} * ${right})`
75
- if (node.operator === 'div') return `(${left} / ${right})`
76
- if (node.operator === 'mod') return `mod(${left}, ${right})`
77
- if (node.operator === 'equal') return `(${left} == ${right})`
78
- if (node.operator === 'notEqual') return `(${left} != ${right})`
79
- if (node.operator === 'lessThan') return `(${left} < ${right})`
80
- if (node.operator === 'lessThanEqual') return `(${left} <= ${right})`
81
- if (node.operator === 'greaterThan') return `(${left} > ${right})`
82
- if (node.operator === 'greaterThanEqual') return `(${left} >= ${right})`
83
- if (node.operator === 'and') return `(${left} && ${right})`
84
- if (node.operator === 'or') return `(${left} || ${right})`
85
- return `(${left} + ${right})`
86
- }
87
-
88
- // GLSL数学関数を生成
89
- const generateGLSLMathFunction = (node: Node, context: GLSLContext): string => {
90
- if (!node.children || node.children.length < 1) return '0.0'
91
- const fun = node.mathFunction
92
- const args = node.children.map((child) => {
93
- return generateGLSLExpression(child, context)
94
- })
95
- const [x, y, z] = args
96
- // @TODO FIX
97
- // if (fun === 'toVar') return x // toVarは変数化のヒントなので、そのまま返す
98
- if (args.length === 1) return `${fun}(${x})`
99
- if (args.length === 2) return `${fun}(${x}, ${y})`
100
- if (args.length === 3) return `${fun}(${x}, ${y}, ${z})`
101
- return x || '0.0'
102
- }
103
-
104
- // 値からGLSL型を推定
105
- const inferGLSLType = (value: unknown): string => {
106
- if (is.num(value)) return 'float'
107
- if (is.bol(value)) return 'bool'
108
- if (is.arr(value)) {
109
- const len = value.length
110
- if (len === 2) return 'vec2'
111
- if (len === 3) return 'vec3'
112
- if (len === 4) return 'vec4'
113
- }
114
- return 'float'
115
- }
116
-
117
- // 完全なGLSLシェーダーを生成
118
- export const glsl = (
119
- fragmentNode: X,
120
- options?: {
121
- precision?: 'lowp' | 'mediump' | 'highp'
122
- version?: '100' | '300 es'
123
- uniforms?: Record<string, any>
124
- }
125
- ) => {
126
- const precision = options?.precision || 'mediump'
127
- const version = options?.version || '300 es'
128
- const is300ES = version === '300 es'
129
- const fragment = nodeToGLSL(fragmentNode)
130
- let shader = ''
131
- if (is300ES) shader += '#version 300 es\n'
132
- shader += `precision ${precision} float;\n\n`
133
- // ユニフォーム変数の追加
134
- if (options?.uniforms) {
135
- Object.entries(options.uniforms).forEach(([name, value]) => {
136
- const type = inferGLSLType(value)
137
- shader += `uniform ${type} ${name};\n`
138
- })
139
- shader += '\n'
140
- }
141
- // 出力変数
142
- if (is300ES) shader += 'out vec4 fragColor;\n\n'
143
- shader += 'void main() {\n'
144
- shader += is300ES ? ` fragColor = ${fragment};\n` : ` gl_FragColor = ${fragment};\n`
145
- shader += '}\n'
146
-
147
- return shader
148
- }
package/src/code/wgsl.ts DELETED
@@ -1,134 +0,0 @@
1
- import { is } from '../utils/helpers'
2
- import type { Node, NodeType, ConversionContext, X } from '../node'
3
-
4
- // WGSLコード生成コンテキスト
5
- interface WGSLContext extends ConversionContext {
6
- target: 'webgpu'
7
- }
8
-
9
- // ノードからWGSLコードを生成
10
- export const nodeToWGSL = (nodeProxy: X, context?: Partial<WGSLContext>): string => {
11
- const ctx: WGSLContext = {
12
- target: 'webgpu',
13
- nodes: new Map(),
14
- variables: new Map(),
15
- functions: new Map(),
16
- ...context,
17
- }
18
- return generateWGSLExpression(nodeProxy as any, ctx)
19
- }
20
-
21
- // WGSL式を生成
22
- const generateWGSLExpression = (node: Node, context: WGSLContext): string => {
23
- if (!node) return '0.0'
24
- // 値ノード
25
- if (node.value !== undefined) return formatWGSLValue(node.value, node.type)
26
- // プロパティアクセス(スウィズル)
27
- if (node.property && node.parent) {
28
- const parentExpr = generateWGSLExpression(node.parent, context)
29
- return `${parentExpr}.${node.property}`
30
- }
31
- // 演算子ノード
32
- if (node.operator && node.children && node.children.length >= 2) return generateWGSLOperator(node, context)
33
- // 数学関数ノード
34
- if (node.mathFunction && node.children && node.children.length >= 1)
35
- return generateWGSLMathFunction(node, context)
36
- return '0.0'
37
- }
38
-
39
- // WGSL値をフォーマット
40
- const formatWGSLValue = (value: any, type: NodeType): string => {
41
- if (type === 'float') {
42
- const num = Number(value)
43
- return num % 1 === 0 ? `${num}.0` : `${num}`
44
- }
45
- if (type === 'int') return `${Math.floor(Number(value))}`
46
- if (type === 'bool') return Boolean(value) ? 'true' : 'false'
47
- if (is.arr(value)) {
48
- const values = value
49
- .map((v) => {
50
- const num = Number(v)
51
- return num % 1 === 0 ? `${num}.0` : `${num}`
52
- })
53
- .join(', ')
54
- if (type === 'vec2') return `vec2<f32>(${values})`
55
- if (type === 'vec3') return `vec3<f32>(${values})`
56
- if (type === 'vec4') return `vec4<f32>(${values})`
57
- if (type === 'color') return `vec3<f32>(${values})`
58
- }
59
-
60
- return '0.0'
61
- }
62
-
63
- // WGSL演算子を生成
64
- const generateWGSLOperator = (node: Node, context: WGSLContext): string => {
65
- if (!node.children || node.children.length < 2) return '0.0'
66
- const left = generateWGSLExpression(node.children[0], context)
67
- const right = generateWGSLExpression(node.children[1], context)
68
- if (node.operator === 'add') return `(${left} + ${right})`
69
- if (node.operator === 'sub') return `(${left} - ${right})`
70
- if (node.operator === 'mul') return `(${left} * ${right})`
71
- if (node.operator === 'div') return `(${left} / ${right})`
72
- if (node.operator === 'mod') return `(${left} % ${right})`
73
- if (node.operator === 'equal') return `(${left} == ${right})`
74
- if (node.operator === 'notEqual') return `(${left} != ${right})`
75
- if (node.operator === 'lessThan') return `(${left} < ${right})`
76
- if (node.operator === 'lessThanEqual') return `(${left} <= ${right})`
77
- if (node.operator === 'greaterThan') return `(${left} > ${right})`
78
- if (node.operator === 'greaterThanEqual') return `(${left} >= ${right})`
79
- if (node.operator === 'and') return `(${left} && ${right})`
80
- if (node.operator === 'or') return `(${left} || ${right})`
81
- return `(${left} + ${right})`
82
- }
83
-
84
- // WGSL数学関数を生成
85
- const generateWGSLMathFunction = (node: Node, context: WGSLContext): string => {
86
- if (!node.children || node.children.length < 1) return '0.0'
87
- const fun = node.mathFunction
88
- const args = node.children.map((child) => generateWGSLExpression(child, context))
89
- const [x, y, z] = args
90
- // @TODO FIX
91
- // if (fun === 'toVar') return x // toVarは変数化のヒントなので、そのまま返す
92
- if (args.length === 1) return `${fun}(${x})`
93
- if (args.length === 2) return `${fun}(${x}, ${y})`
94
- if (args.length === 3) return `${fun}(${x}, ${y}, ${z})`
95
- return x || '0.0'
96
- }
97
-
98
- // 完全なWGSLシェーダーを生成
99
- export const wgsl = (
100
- fragmentNode: X,
101
- options?: {
102
- uniforms?: Record<string, any>
103
- }
104
- ) => {
105
- let shader = ''
106
- // ユニフォーム変数の追加
107
- if (options?.uniforms) {
108
- Object.entries(options.uniforms).forEach(([name, value]) => {
109
- const type = inferWGSLType(value)
110
- shader += `@group(0) @binding(0) var<uniform> ${name}: ${type};\n`
111
- })
112
- shader += '\n'
113
- }
114
- shader += '@fragment\n'
115
- shader += 'fn main() -> @location(0) vec4<f32> {\n'
116
- const fragmentExpr = nodeToWGSL(fragmentNode)
117
- shader += ` return ${fragmentExpr};\n`
118
- shader += '}\n'
119
-
120
- return shader
121
- }
122
-
123
- // 値からWGSL型を推定
124
- const inferWGSLType = (value: any): string => {
125
- if (is.num(value)) return 'f32'
126
- if (is.bol(value)) return 'bool'
127
- if (is.arr(value)) {
128
- const len = value.length
129
- if (len === 2) return 'vec2<f32>'
130
- if (len === 3) return 'vec3<f32>'
131
- if (len === 4) return 'vec4<f32>'
132
- }
133
- return 'f32'
134
- }
package/src/node/cache.ts DELETED
@@ -1,60 +0,0 @@
1
- import { CACHE_BOOLS, CACHE_INTS, CACHE_FLOATS } from './const'
2
- import { node } from '.'
3
- import type { X } from './types'
4
-
5
- const boolCache = new Map<boolean, X>()
6
- const intCache = new Map<number, X>()
7
- const floatCache = new Map<number, X>()
8
-
9
- const initializeCache = () => {
10
- CACHE_BOOLS.forEach((value) => {
11
- boolCache.set(value, node('bool', value))
12
- })
13
- CACHE_INTS.forEach((value) => {
14
- intCache.set(value, node('int', value))
15
- })
16
- CACHE_FLOATS.forEach((value) => {
17
- floatCache.set(value, node('float', value))
18
- })
19
- }
20
-
21
- export const getCachedBool = (x: boolean): X => {
22
- if (!boolCache.has(x)) initializeCache()
23
- return boolCache.get(x) || node('bool', x)
24
- }
25
-
26
- // キャッシュされたintノードを取得
27
- export const getCachedInt = (x: number): X => {
28
- if (intCache.has(x)) return intCache.get(x)!
29
- return node('int', x)
30
- }
31
-
32
- // キャッシュされたfloatノードを取得
33
- export const getCachedFloat = (x: number): X => {
34
- if (floatCache.has(x)) return floatCache.get(x)!
35
- return node('float', x)
36
- }
37
-
38
- // ノードの重複を検出
39
- export const findDuplicateNodes = (nodes: X[]): Map<string, X[]> => {
40
- const duplicates = new Map<string, X[]>()
41
- const signatures = new Map<string, X>()
42
-
43
- nodes.forEach((nodeProxy) => {
44
- const signature = generateNodeSignature(nodeProxy)
45
- if (signatures.has(signature)) {
46
- if (!duplicates.has(signature)) duplicates.set(signature, [signatures.get(signature)!])
47
- duplicates.get(signature)!.push(nodeProxy)
48
- } else signatures.set(signature, nodeProxy)
49
- })
50
- return duplicates
51
- }
52
-
53
- // ノードのシグネチャを生成
54
- const generateNodeSignature = (nodeProxy: X): string => {
55
- const parts = [nodeProxy.type, `${nodeProxy.value}`, nodeProxy.property || '']
56
- return parts.join('|')
57
- }
58
-
59
- // 初期化を実行
60
- // initializeCache()
package/src/node/conv.ts DELETED
@@ -1,111 +0,0 @@
1
- import { node } from '.'
2
- import { getCachedBool, getCachedInt, getCachedFloat } from './cache'
3
- import { is } from '../utils/helpers'
4
- import type { X } from './types'
5
-
6
- // JavaScript値をノードに変換
7
- export const convertToNode = (x: unknown): X => {
8
- if (is.bol(x)) return getCachedBool(x)
9
- if (is.num(x)) {
10
- if (is.int(x)) return getCachedInt(x)
11
- return getCachedFloat(x)
12
- }
13
- if (is.arr(x)) return convertArrayToNode(x)
14
- if (is.obj(x)) return convertObjectToNode(x)
15
- return node('float', 0)
16
- }
17
-
18
- // 配列をベクトル/行列ノードに変換
19
- const convertArrayToNode = (array: number[]): X => {
20
- const len = array.length
21
- if (len === 2) return node('vec2', array)
22
- if (len === 3) return node('vec3', array)
23
- if (len === 4) return node('vec4', array)
24
- if (len === 9) return node('mat3', array)
25
- if (len === 16) return node('mat4', array)
26
- return node('float', array[0])
27
- }
28
-
29
- // オブジェクトをノードに変換
30
- const convertObjectToNode = (obj: any): X => {
31
- // カラーオブジェクトの検出
32
- if ('r' in obj && 'g' in obj && 'b' in obj) {
33
- const arr = [obj.r, obj.g, obj.b]
34
- if ('a' in obj) arr.push(obj.a)
35
- return node('color', arr)
36
- }
37
- // ベクトルライクオブジェクトの検出
38
- if ('x' in obj && 'y' in obj) {
39
- const arr = [obj.x, obj.y]
40
- if ('z' in obj) arr.push(obj.z)
41
- if ('w' in obj) arr.push(obj.w)
42
- return convertArrayToNode(arr)
43
- }
44
- return node('float', 0)
45
- }
46
-
47
- // 型変換関数
48
- export const float = (x: unknown): X => {
49
- if (is.num(x)) return getCachedFloat(x)
50
- return node('float', Number(x))
51
- }
52
-
53
- export const int = (x: unknown): X => {
54
- if (is.num(x) && Number.isInteger(x)) return getCachedInt(x)
55
- return node('int', Math.floor(Number(x)))
56
- }
57
-
58
- export const bool = (x: unknown): X => {
59
- return getCachedBool(Boolean(x))
60
- }
61
-
62
- export const vec2 = (x?: any, y?: any): X => {
63
- if (is.und(x)) return node('vec2', [0, 0])
64
- if (is.und(y)) {
65
- if (is.arr(x)) return node('vec2', x.slice(0, 2))
66
- if (is.obj(x) && 'x' in x && 'y' in x) return node('vec2', [x.x, x.y])
67
- return node('vec2', [Number(x), Number(x)])
68
- }
69
- return node('vec2', [Number(x), Number(y)])
70
- }
71
-
72
- export const vec3 = (x?: any, y?: any, z?: any): X => {
73
- if (is.und(x)) return node('vec3', [0, 0, 0])
74
- if (is.und(y)) {
75
- if (is.arr(x)) return node('vec3', x.slice(0, 3))
76
- if (is.obj(x) && 'x' in x && 'y' in x && 'z' in x) return node('vec3', [x.x, x.y, x.z])
77
- return node('vec3', [Number(x), Number(x), Number(x)])
78
- }
79
- if (z === undefined) {
80
- return node('vec3', [Number(x), Number(y), 0])
81
- }
82
- return node('vec3', [Number(x), Number(y), Number(z)])
83
- }
84
-
85
- export const vec4 = (x?: any, y?: any, z?: any, w?: any): X => {
86
- if (is.und(x)) return node('vec4', [0, 0, 0, 1])
87
- if (is.und(y)) {
88
- if (is.arr(x)) return node('vec4', x.slice(0, 4))
89
- if (is.obj(x) && 'x' in x && 'y' in x && 'z' in x && 'w' in x) return node('vec4', [x.x, x.y, x.z, x.w])
90
- return node('vec4', [Number(x), Number(x), Number(x), 1])
91
- }
92
- return node('vec4', [Number(x), Number(y), Number(z), Number(w)])
93
- }
94
-
95
- export const color = (r?: any, g?: any, b?: any): X => {
96
- if (r === undefined) return node('color', [1, 1, 1])
97
-
98
- // 16進数カラーの処理
99
- if (is.str(r) && r.startsWith('#')) {
100
- const hex = r.slice(1)
101
- const num = parseInt(hex, 16)
102
- return node('color', [((num >> 16) & 255) / 255, ((num >> 8) & 255) / 255, (num & 255) / 255])
103
- }
104
-
105
- // 数値カラーの処理
106
- if (is.num(r) && g === undefined && b === undefined) {
107
- return node('color', [((r >> 16) & 255) / 255, ((r >> 8) & 255) / 255, (r & 255) / 255])
108
- }
109
-
110
- return vec3(r, g, b)
111
- }
@@ -1,92 +0,0 @@
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
- }