glre 0.21.0 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +150 -80
- package/dist/index.d.ts +524 -7
- package/dist/index.js +46 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +46 -13
- package/dist/index.mjs.map +1 -1
- package/dist/native.d.ts +6 -64
- package/dist/native.js +46 -13
- package/dist/native.js.map +1 -1
- package/dist/native.mjs +46 -13
- package/dist/native.mjs.map +1 -1
- package/dist/react.d.ts +7 -11
- package/dist/react.js +46 -13
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +46 -13
- package/dist/react.mjs.map +1 -1
- package/dist/solid.d.ts +6 -63
- package/dist/solid.js +46 -13
- package/dist/solid.js.map +1 -1
- package/dist/solid.mjs +46 -13
- package/dist/solid.mjs.map +1 -1
- package/package.json +25 -60
- package/src/code/glsl.ts +186 -0
- package/src/code/wgsl.ts +170 -0
- package/src/index.ts +105 -0
- package/src/native.ts +24 -0
- package/src/node/cache.ts +67 -0
- package/src/node/const.ts +147 -0
- package/src/node/conv.ts +122 -0
- package/src/node/index.ts +96 -0
- package/src/node/node.ts +114 -0
- package/src/node/types.ts +101 -0
- package/src/node/uniform.ts +99 -0
- package/src/react.ts +18 -0
- package/src/solid.ts +15 -0
- package/src/types.ts +90 -0
- package/src/utils.ts +53 -0
- package/src/webgl/buffer.ts +78 -0
- package/src/webgl/index.ts +79 -0
- package/src/webgl/program.ts +61 -0
- package/src/webgl/shader.ts +60 -0
- package/src/webgl/texture.ts +93 -0
- package/src/webgpu/buffer.ts +96 -0
- package/src/webgpu/device.ts +91 -0
- package/src/webgpu/index.ts +40 -0
- package/src/webgpu/pipeline.ts +94 -0
- package/src/webgpu/texture.ts +139 -0
- package/dist/types-f429c8b1.d.ts +0 -79
package/src/code/glsl.ts
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { is } from './../utils'
|
|
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 = (
|
|
13
|
+
nodeProxy: X,
|
|
14
|
+
context?: Partial<GLSLContext>
|
|
15
|
+
): string => {
|
|
16
|
+
const ctx: GLSLContext = {
|
|
17
|
+
target: 'webgl',
|
|
18
|
+
precision: 'mediump',
|
|
19
|
+
version: '300 es',
|
|
20
|
+
nodes: new Map(),
|
|
21
|
+
variables: new Map(),
|
|
22
|
+
functions: new Map(),
|
|
23
|
+
...context,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return generateGLSLExpression(nodeProxy as any, ctx)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// GLSL式を生成
|
|
30
|
+
const generateGLSLExpression = (node: Node, context: GLSLContext): string => {
|
|
31
|
+
if (!node) return '0.0'
|
|
32
|
+
// 値ノード
|
|
33
|
+
if (!is.und(node.value)) return formatGLSLValue(node.value, node.type)
|
|
34
|
+
// プロパティアクセス(スウィズル)
|
|
35
|
+
if (node.property && node.parent) {
|
|
36
|
+
const parentExpr = generateGLSLExpression(node.parent, context)
|
|
37
|
+
return `${parentExpr}.${node.property}`
|
|
38
|
+
}
|
|
39
|
+
// 演算子ノード
|
|
40
|
+
if (node.operator && node.children && node.children.length >= 2)
|
|
41
|
+
return generateGLSLOperator(node, context)
|
|
42
|
+
// 数学関数ノード
|
|
43
|
+
if (node.mathFunction && node.children && node.children.length >= 1)
|
|
44
|
+
return generateGLSLMathFunction(node, context)
|
|
45
|
+
return '0.0'
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// GLSL値をフォーマット
|
|
49
|
+
const formatGLSLValue = (value: any, type: NodeType): string => {
|
|
50
|
+
if (type === 'float') {
|
|
51
|
+
const num = Number(value)
|
|
52
|
+
return num % 1 === 0 ? `${num}.0` : `${num}`
|
|
53
|
+
}
|
|
54
|
+
if (type === 'int') return `${Math.floor(Number(value))}`
|
|
55
|
+
if (type === 'bool') return Boolean(value) ? 'true' : 'false'
|
|
56
|
+
if (is.arr(value)) {
|
|
57
|
+
const values = value
|
|
58
|
+
.map((v) => {
|
|
59
|
+
const num = Number(v)
|
|
60
|
+
return num % 1 === 0 ? `${num}.0` : `${num}`
|
|
61
|
+
})
|
|
62
|
+
.join(', ')
|
|
63
|
+
if (type === 'vec2') return `vec2(${values})`
|
|
64
|
+
if (type === 'vec3') return `vec3(${values})`
|
|
65
|
+
if (type === 'vec4') return `vec4(${values})`
|
|
66
|
+
if (type === 'color') return `vec3(${values})`
|
|
67
|
+
}
|
|
68
|
+
return '0.0'
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// GLSL演算子を生成
|
|
72
|
+
const generateGLSLOperator = (node: Node, context: GLSLContext): string => {
|
|
73
|
+
if (!node.children || node.children.length < 2) return '0.0'
|
|
74
|
+
const left = generateGLSLExpression(node.children[0], context)
|
|
75
|
+
const right = generateGLSLExpression(node.children[1], context)
|
|
76
|
+
if (node.operator === 'add') return `(${left} + ${right})`
|
|
77
|
+
if (node.operator === 'sub') return `(${left} - ${right})`
|
|
78
|
+
if (node.operator === 'mul') return `(${left} * ${right})`
|
|
79
|
+
if (node.operator === 'div') return `(${left} / ${right})`
|
|
80
|
+
if (node.operator === 'mod') return `mod(${left}, ${right})`
|
|
81
|
+
if (node.operator === 'equal') return `(${left} == ${right})`
|
|
82
|
+
if (node.operator === 'notEqual') return `(${left} != ${right})`
|
|
83
|
+
if (node.operator === 'lessThan') return `(${left} < ${right})`
|
|
84
|
+
if (node.operator === 'lessThanEqual') return `(${left} <= ${right})`
|
|
85
|
+
if (node.operator === 'greaterThan') return `(${left} > ${right})`
|
|
86
|
+
if (node.operator === 'greaterThanEqual') return `(${left} >= ${right})`
|
|
87
|
+
if (node.operator === 'and') return `(${left} && ${right})`
|
|
88
|
+
if (node.operator === 'or') return `(${left} || ${right})`
|
|
89
|
+
return `(${left} + ${right})`
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// GLSL数学関数を生成
|
|
93
|
+
const generateGLSLMathFunction = (node: Node, context: GLSLContext): string => {
|
|
94
|
+
if (!node.children || node.children.length < 1) return '0.0'
|
|
95
|
+
const fun = node.mathFunction
|
|
96
|
+
const args = node.children.map((child) => {
|
|
97
|
+
return generateGLSLExpression(child, context)
|
|
98
|
+
})
|
|
99
|
+
const [x, y, z] = args
|
|
100
|
+
// @TODO FIX
|
|
101
|
+
// if (fun === 'toVar') return x // toVarは変数化のヒントなので、そのまま返す
|
|
102
|
+
// 単項関数
|
|
103
|
+
if (args.length === 1) {
|
|
104
|
+
if (fun === 'abs') return `abs(${x})`
|
|
105
|
+
if (fun === 'acos') return `acos(${x})`
|
|
106
|
+
if (fun === 'asin') return `asin(${x})`
|
|
107
|
+
if (fun === 'atan') return `atan(${x})`
|
|
108
|
+
if (fun === 'ceil') return `ceil(${x})`
|
|
109
|
+
if (fun === 'cos') return `cos(${x})`
|
|
110
|
+
if (fun === 'floor') return `floor(${x})`
|
|
111
|
+
if (fun === 'fract') return `fract(${x})`
|
|
112
|
+
if (fun === 'length') return `length(${x})`
|
|
113
|
+
if (fun === 'normalize') return `normalize(${x})`
|
|
114
|
+
if (fun === 'sin') return `sin(${x})`
|
|
115
|
+
if (fun === 'sqrt') return `sqrt(${x})`
|
|
116
|
+
if (fun === 'tan') return `tan(${x})`
|
|
117
|
+
}
|
|
118
|
+
// 二項関数
|
|
119
|
+
if (args.length === 2) {
|
|
120
|
+
if (fun === 'atan2') return `atan(${x}, ${y})`
|
|
121
|
+
if (fun === 'pow') return `pow(${x}, ${y})`
|
|
122
|
+
if (fun === 'min') return `min(${x}, ${y})`
|
|
123
|
+
if (fun === 'max') return `max(${x}, ${y})`
|
|
124
|
+
if (fun === 'dot') return `dot(${x}, ${y})`
|
|
125
|
+
if (fun === 'cross') return `cross(${x}, ${y})`
|
|
126
|
+
if (fun === 'distance') return `distance(${x}, ${y})`
|
|
127
|
+
if (fun === 'reflect') return `reflect(${x}, ${y})`
|
|
128
|
+
}
|
|
129
|
+
// 三項関数
|
|
130
|
+
if (args.length === 3) {
|
|
131
|
+
if (fun === 'mix') return `mix(${x}, ${y}, ${z})`
|
|
132
|
+
if (fun === 'clamp') return `clamp(${x}, ${y}, ${z})`
|
|
133
|
+
if (fun === 'smoothstep') return `smoothstep(${x}, ${y}, ${z})`
|
|
134
|
+
if (fun === 'refract') return `refract(${x}, ${y}, ${z})`
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return x || '0.0'
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// 値からGLSL型を推定
|
|
141
|
+
const inferGLSLType = (value: unknown): string => {
|
|
142
|
+
if (is.num(value)) return 'float'
|
|
143
|
+
if (is.bol(value)) return 'bool'
|
|
144
|
+
if (is.arr(value)) {
|
|
145
|
+
const len = value.length
|
|
146
|
+
if (len === 2) return 'vec2'
|
|
147
|
+
if (len === 3) return 'vec3'
|
|
148
|
+
if (len === 4) return 'vec4'
|
|
149
|
+
}
|
|
150
|
+
return 'float'
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// 完全なGLSLシェーダーを生成
|
|
154
|
+
export const glsl = (
|
|
155
|
+
fragmentNode: X,
|
|
156
|
+
options?: {
|
|
157
|
+
precision?: 'lowp' | 'mediump' | 'highp'
|
|
158
|
+
version?: '100' | '300 es'
|
|
159
|
+
uniforms?: Record<string, any>
|
|
160
|
+
}
|
|
161
|
+
) => {
|
|
162
|
+
const precision = options?.precision || 'mediump'
|
|
163
|
+
const version = options?.version || '300 es'
|
|
164
|
+
const is300ES = version === '300 es'
|
|
165
|
+
const fragment = nodeToGLSL(fragmentNode)
|
|
166
|
+
let shader = ''
|
|
167
|
+
if (is300ES) shader += '#version 300 es\n'
|
|
168
|
+
shader += `precision ${precision} float;\n\n`
|
|
169
|
+
// ユニフォーム変数の追加
|
|
170
|
+
if (options?.uniforms) {
|
|
171
|
+
Object.entries(options.uniforms).forEach(([name, value]) => {
|
|
172
|
+
const type = inferGLSLType(value)
|
|
173
|
+
shader += `uniform ${type} ${name};\n`
|
|
174
|
+
})
|
|
175
|
+
shader += '\n'
|
|
176
|
+
}
|
|
177
|
+
// 出力変数
|
|
178
|
+
if (is300ES) shader += 'out vec4 fragColor;\n\n'
|
|
179
|
+
shader += 'void main() {\n'
|
|
180
|
+
shader += is300ES
|
|
181
|
+
? ` fragColor = ${fragment};\n`
|
|
182
|
+
: ` gl_FragColor = ${fragment};\n`
|
|
183
|
+
shader += '}\n'
|
|
184
|
+
|
|
185
|
+
return shader
|
|
186
|
+
}
|
package/src/code/wgsl.ts
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { is } from '../utils'
|
|
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 = (
|
|
11
|
+
nodeProxy: X,
|
|
12
|
+
context?: Partial<WGSLContext>
|
|
13
|
+
): string => {
|
|
14
|
+
const ctx: WGSLContext = {
|
|
15
|
+
target: 'webgpu',
|
|
16
|
+
nodes: new Map(),
|
|
17
|
+
variables: new Map(),
|
|
18
|
+
functions: new Map(),
|
|
19
|
+
...context,
|
|
20
|
+
}
|
|
21
|
+
return generateWGSLExpression(nodeProxy as any, ctx)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// WGSL式を生成
|
|
25
|
+
const generateWGSLExpression = (node: Node, context: WGSLContext): string => {
|
|
26
|
+
if (!node) return '0.0'
|
|
27
|
+
// 値ノード
|
|
28
|
+
if (node.value !== undefined)
|
|
29
|
+
return formatWGSLValue(node.value, node.type)
|
|
30
|
+
// プロパティアクセス(スウィズル)
|
|
31
|
+
if (node.property && node.parent) {
|
|
32
|
+
const parentExpr = generateWGSLExpression(node.parent, context)
|
|
33
|
+
return `${parentExpr}.${node.property}`
|
|
34
|
+
}
|
|
35
|
+
// 演算子ノード
|
|
36
|
+
if (node.operator && node.children && node.children.length >= 2)
|
|
37
|
+
return generateWGSLOperator(node, context)
|
|
38
|
+
// 数学関数ノード
|
|
39
|
+
if (node.mathFunction && node.children && node.children.length >= 1)
|
|
40
|
+
return generateWGSLMathFunction(node, context)
|
|
41
|
+
return '0.0'
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// WGSL値をフォーマット
|
|
45
|
+
const formatWGSLValue = (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<f32>(${values})`
|
|
60
|
+
if (type === 'vec3') return `vec3<f32>(${values})`
|
|
61
|
+
if (type === 'vec4') return `vec4<f32>(${values})`
|
|
62
|
+
if (type === 'color') return `vec3<f32>(${values})`
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return '0.0'
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// WGSL演算子を生成
|
|
69
|
+
const generateWGSLOperator = (node: Node, context: WGSLContext): string => {
|
|
70
|
+
if (!node.children || node.children.length < 2) return '0.0'
|
|
71
|
+
const left = generateWGSLExpression(node.children[0], context)
|
|
72
|
+
const right = generateWGSLExpression(node.children[1], context)
|
|
73
|
+
if (node.operator === 'add') return `(${left} + ${right})`
|
|
74
|
+
if (node.operator === 'sub') return `(${left} - ${right})`
|
|
75
|
+
if (node.operator === 'mul') return `(${left} * ${right})`
|
|
76
|
+
if (node.operator === 'div') return `(${left} / ${right})`
|
|
77
|
+
if (node.operator === 'mod') return `(${left} % ${right})`
|
|
78
|
+
if (node.operator === 'equal') return `(${left} == ${right})`
|
|
79
|
+
if (node.operator === 'notEqual') return `(${left} != ${right})`
|
|
80
|
+
if (node.operator === 'lessThan') return `(${left} < ${right})`
|
|
81
|
+
if (node.operator === 'lessThanEqual') return `(${left} <= ${right})`
|
|
82
|
+
if (node.operator === 'greaterThan') return `(${left} > ${right})`
|
|
83
|
+
if (node.operator === 'greaterThanEqual') return `(${left} >= ${right})`
|
|
84
|
+
if (node.operator === 'and') return `(${left} && ${right})`
|
|
85
|
+
if (node.operator === 'or') return `(${left} || ${right})`
|
|
86
|
+
return `(${left} + ${right})`
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// WGSL数学関数を生成
|
|
90
|
+
const generateWGSLMathFunction = (node: Node, context: WGSLContext): string => {
|
|
91
|
+
if (!node.children || node.children.length < 1) return '0.0'
|
|
92
|
+
const fun = node.mathFunction
|
|
93
|
+
const args = node.children.map((child) =>
|
|
94
|
+
generateWGSLExpression(child, context)
|
|
95
|
+
)
|
|
96
|
+
const [x, y, z] = args
|
|
97
|
+
// 単項関数
|
|
98
|
+
if (args.length === 1) {
|
|
99
|
+
if (fun === 'abs') return `abs(${x})`
|
|
100
|
+
if (fun === 'acos') return `acos(${x})`
|
|
101
|
+
if (fun === 'asin') return `asin(${x})`
|
|
102
|
+
if (fun === 'atan') return `atan(${x})`
|
|
103
|
+
if (fun === 'ceil') return `ceil(${x})`
|
|
104
|
+
if (fun === 'cos') return `cos(${x})`
|
|
105
|
+
if (fun === 'floor') return `floor(${x})`
|
|
106
|
+
if (fun === 'fract') return `fract(${x})`
|
|
107
|
+
if (fun === 'length') return `length(${x})`
|
|
108
|
+
if (fun === 'normalize') return `normalize(${x})`
|
|
109
|
+
if (fun === 'sin') return `sin(${x})`
|
|
110
|
+
if (fun === 'sqrt') return `sqrt(${x})`
|
|
111
|
+
if (fun === 'tan') return `tan(${x})`
|
|
112
|
+
}
|
|
113
|
+
// 二項関数
|
|
114
|
+
if (args.length === 2) {
|
|
115
|
+
if (fun === 'atan2') return `atan2(${x}, ${y})`
|
|
116
|
+
if (fun === 'pow') return `pow(${x}, ${y})`
|
|
117
|
+
if (fun === 'min') return `min(${x}, ${y})`
|
|
118
|
+
if (fun === 'max') return `max(${x}, ${y})`
|
|
119
|
+
if (fun === 'dot') return `dot(${x}, ${y})`
|
|
120
|
+
if (fun === 'cross') return `cross(${x}, ${y})`
|
|
121
|
+
if (fun === 'distance') return `distance(${x}, ${y})`
|
|
122
|
+
if (fun === 'reflect') return `reflect(${x}, ${y})`
|
|
123
|
+
}
|
|
124
|
+
// 三項関数
|
|
125
|
+
if (args.length === 3) {
|
|
126
|
+
if (fun === 'mix') return `mix(${x}, ${y}, ${z})`
|
|
127
|
+
if (fun === 'clamp') return `clamp(${x}, ${y}, ${z})`
|
|
128
|
+
if (fun === 'smoothstep') return `smoothstep(${x}, ${y}, ${z})`
|
|
129
|
+
return x
|
|
130
|
+
}
|
|
131
|
+
return x || '0.0'
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// 完全なWGSLシェーダーを生成
|
|
135
|
+
export const wgsl = (
|
|
136
|
+
fragmentNode: X,
|
|
137
|
+
options?: {
|
|
138
|
+
uniforms?: Record<string, any>
|
|
139
|
+
}
|
|
140
|
+
) => {
|
|
141
|
+
let shader = ''
|
|
142
|
+
// ユニフォーム変数の追加
|
|
143
|
+
if (options?.uniforms) {
|
|
144
|
+
Object.entries(options.uniforms).forEach(([name, value]) => {
|
|
145
|
+
const type = inferWGSLType(value)
|
|
146
|
+
shader += `@group(0) @binding(0) var<uniform> ${name}: ${type};\n`
|
|
147
|
+
})
|
|
148
|
+
shader += '\n'
|
|
149
|
+
}
|
|
150
|
+
shader += '@fragment\n'
|
|
151
|
+
shader += 'fn main() -> @location(0) vec4<f32> {\n'
|
|
152
|
+
const fragmentExpr = nodeToWGSL(fragmentNode)
|
|
153
|
+
shader += ` return ${fragmentExpr};\n`
|
|
154
|
+
shader += '}\n'
|
|
155
|
+
|
|
156
|
+
return shader
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// 値からWGSL型を推定
|
|
160
|
+
const inferWGSLType = (value: any): string => {
|
|
161
|
+
if (is.num(value)) return 'f32'
|
|
162
|
+
if (is.bol(value)) return 'bool'
|
|
163
|
+
if (is.arr(value)) {
|
|
164
|
+
const len = value.length
|
|
165
|
+
if (len === 2) return 'vec2<f32>'
|
|
166
|
+
if (len === 3) return 'vec3<f32>'
|
|
167
|
+
if (len === 4) return 'vec4<f32>'
|
|
168
|
+
}
|
|
169
|
+
return 'f32'
|
|
170
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { durable, event } from 'reev'
|
|
2
|
+
import { createFrame, createQueue } from 'refr'
|
|
3
|
+
import { webgl } from './webgl/index'
|
|
4
|
+
import { webgpu } from './webgpu/index'
|
|
5
|
+
import { is, isWebGPUSupported } from './utils'
|
|
6
|
+
import type { EventState } from 'reev'
|
|
7
|
+
import type { GL } from './types'
|
|
8
|
+
export * from './code/glsl'
|
|
9
|
+
export * from './code/wgsl'
|
|
10
|
+
export * from './node'
|
|
11
|
+
export * from './types'
|
|
12
|
+
export * from './utils'
|
|
13
|
+
export * from './webgl'
|
|
14
|
+
export * from './webgpu'
|
|
15
|
+
|
|
16
|
+
let iTime = performance.now(),
|
|
17
|
+
iPrevTime = 0,
|
|
18
|
+
iDeltaTime = 0
|
|
19
|
+
|
|
20
|
+
export const isGL = (a: unknown): a is EventState<GL> => {
|
|
21
|
+
if (!is.obj(a)) return false
|
|
22
|
+
if ('isGL' in a) return true
|
|
23
|
+
return false
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const createGL = (props?: Partial<GL>) => {
|
|
27
|
+
const gl = event<Partial<GL>>({
|
|
28
|
+
isNative: false,
|
|
29
|
+
isWebGL: true,
|
|
30
|
+
isLoop: true,
|
|
31
|
+
isGL: true,
|
|
32
|
+
size: [0, 0],
|
|
33
|
+
mouse: [0, 0],
|
|
34
|
+
count: 6,
|
|
35
|
+
counter: 0,
|
|
36
|
+
}) as EventState<GL>
|
|
37
|
+
|
|
38
|
+
gl('mount', () => {
|
|
39
|
+
if (!isWebGPUSupported()) gl.isWebGL = true
|
|
40
|
+
if (gl.isWebGL) {
|
|
41
|
+
webgl(gl)
|
|
42
|
+
} else webgpu(gl)
|
|
43
|
+
gl.init()
|
|
44
|
+
gl.resize()
|
|
45
|
+
gl.frame(() => {
|
|
46
|
+
gl.loop()
|
|
47
|
+
gl.render()
|
|
48
|
+
return gl.isLoop
|
|
49
|
+
})
|
|
50
|
+
if (gl.isNative) return
|
|
51
|
+
window.addEventListener('resize', gl.resize)
|
|
52
|
+
gl.el.addEventListener('mousemove', gl.mousemove)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
gl('clean', () => {
|
|
56
|
+
gl.frame.stop()
|
|
57
|
+
gl.frame.clean(gl.render)
|
|
58
|
+
if (gl.isNative) return
|
|
59
|
+
window.removeEventListener('resize', gl.resize)
|
|
60
|
+
gl.el.removeEventListener('mousemove', gl.mousemove)
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
gl('loop', () => {
|
|
64
|
+
iPrevTime = iTime
|
|
65
|
+
iTime = performance.now() / 1000
|
|
66
|
+
iDeltaTime = iTime - iPrevTime
|
|
67
|
+
gl.uniform({ iPrevTime, iTime, iDeltaTime })
|
|
68
|
+
// if (gl.fragmentNode) updateUniforms({ time: iTime }) // @TODO FIX
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
gl('resize', () => {
|
|
72
|
+
const w = gl.width || window.innerWidth
|
|
73
|
+
const h = gl.height || window.innerHeight
|
|
74
|
+
gl.size[0] = gl.el.width = w
|
|
75
|
+
gl.size[1] = gl.el.height = h
|
|
76
|
+
gl.uniform('iResolution', gl.size)
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
gl('mousemove', (_e: any, x = _e.clientX, y = _e.clientY) => {
|
|
80
|
+
const [w, h] = gl.size
|
|
81
|
+
const { top, left } = gl.el.getBoundingClientRect()
|
|
82
|
+
gl.mouse[0] = (x - top - w / 2) / (w / 2)
|
|
83
|
+
gl.mouse[1] = -(y - left - h / 2) / (h / 2)
|
|
84
|
+
gl.uniform('iMouse', gl.mouse)
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
gl.queue = createQueue()
|
|
88
|
+
gl.frame = createFrame()
|
|
89
|
+
|
|
90
|
+
gl.attribute = durable((key, value, iboValue) => {
|
|
91
|
+
gl.queue(() => void gl._attribute?.(key, value, iboValue))
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
gl.uniform = durable((key, value, isMatrix) => {
|
|
95
|
+
gl.queue(() => void gl._uniform?.(key, value, isMatrix))
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
gl.texture = durable((key, value) => {
|
|
99
|
+
gl.queue(() => void gl._texture?.(key, value))
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
return gl(props)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export default createGL
|
package/src/native.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { useState } from 'react'
|
|
2
|
+
import { Dimensions } from 'react-native'
|
|
3
|
+
import { createGL, isGL } from './index'
|
|
4
|
+
import type { GL } from './types'
|
|
5
|
+
export * from './index'
|
|
6
|
+
|
|
7
|
+
export const useGL = (props: Partial<GL> = {}) => {
|
|
8
|
+
return useState(() => {
|
|
9
|
+
const gl = isGL(props) ? props : createGL(props)
|
|
10
|
+
gl.ref = (ctx: any) => {
|
|
11
|
+
gl.el = {}
|
|
12
|
+
gl.gl = ctx
|
|
13
|
+
gl.mount()
|
|
14
|
+
const resize = () => {
|
|
15
|
+
gl.width = ctx.drawingBufferWidth
|
|
16
|
+
gl.height = ctx.drawingBufferHeight
|
|
17
|
+
gl.resize()
|
|
18
|
+
}
|
|
19
|
+
resize()
|
|
20
|
+
Dimensions.addEventListener('change', resize)
|
|
21
|
+
}
|
|
22
|
+
return gl
|
|
23
|
+
})[0]
|
|
24
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
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))
|
|
47
|
+
duplicates.set(signature, [
|
|
48
|
+
signatures.get(signature)!,
|
|
49
|
+
])
|
|
50
|
+
duplicates.get(signature)!.push(nodeProxy)
|
|
51
|
+
} else signatures.set(signature, nodeProxy)
|
|
52
|
+
})
|
|
53
|
+
return duplicates
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ノードのシグネチャを生成
|
|
57
|
+
const generateNodeSignature = (nodeProxy: X): string => {
|
|
58
|
+
const parts = [
|
|
59
|
+
nodeProxy.type,
|
|
60
|
+
`${nodeProxy.value}`,
|
|
61
|
+
nodeProxy.property || '',
|
|
62
|
+
]
|
|
63
|
+
return parts.join('|')
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// 初期化を実行
|
|
67
|
+
initializeCache()
|