glre 0.39.0 → 0.40.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.
Files changed (281) hide show
  1. package/README.md +8 -4
  2. package/dist/addons.cjs +1 -1
  3. package/dist/addons.cjs.map +1 -1
  4. package/dist/addons.d.ts +849 -19
  5. package/dist/addons.js +1 -1
  6. package/dist/addons.js.map +1 -1
  7. package/dist/index.cjs +8 -8
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.d.ts +38 -20
  10. package/dist/index.js +8 -8
  11. package/dist/index.js.map +1 -1
  12. package/dist/native.d.ts +48 -22
  13. package/dist/node.cjs +59 -30
  14. package/dist/node.cjs.map +1 -1
  15. package/dist/node.d.ts +34 -22
  16. package/dist/node.js +59 -30
  17. package/dist/node.js.map +1 -1
  18. package/dist/react.d.ts +38 -20
  19. package/dist/solid.d.ts +38 -20
  20. package/package.json +24 -24
  21. package/src/addons/animation/easing/backIn.ts +10 -0
  22. package/src/addons/animation/easing/backInOut.ts +12 -0
  23. package/src/addons/animation/easing/backOut.ts +10 -0
  24. package/src/addons/animation/easing/bounceIn.ts +10 -0
  25. package/src/addons/animation/easing/bounceInOut.ts +13 -0
  26. package/src/addons/animation/easing/bounceOut.ts +30 -0
  27. package/src/addons/animation/easing/circularIn.ts +9 -0
  28. package/src/addons/animation/easing/circularInOut.ts +11 -0
  29. package/src/addons/animation/easing/circularOut.ts +9 -0
  30. package/src/addons/animation/easing/cubicIn.ts +9 -0
  31. package/src/addons/animation/easing/cubicInOut.ts +11 -0
  32. package/src/addons/animation/easing/cubicOut.ts +10 -0
  33. package/src/addons/animation/easing/elasticIn.ts +10 -0
  34. package/src/addons/animation/easing/elasticInOut.ts +21 -0
  35. package/src/addons/animation/easing/elasticOut.ts +12 -0
  36. package/src/addons/animation/easing/exponentialIn.ts +9 -0
  37. package/src/addons/animation/easing/exponentialInOut.ts +13 -0
  38. package/src/addons/animation/easing/exponentialOut.ts +9 -0
  39. package/src/addons/animation/easing/index.ts +33 -0
  40. package/src/addons/animation/easing/linearIn.ts +9 -0
  41. package/src/addons/animation/easing/linearInOut.ts +9 -0
  42. package/src/addons/animation/easing/linearOut.ts +9 -0
  43. package/src/addons/animation/easing/quadraticIn.ts +9 -0
  44. package/src/addons/animation/easing/quadraticInOut.ts +10 -0
  45. package/src/addons/animation/easing/quadraticOut.ts +9 -0
  46. package/src/addons/animation/easing/quarticIn.ts +9 -0
  47. package/src/addons/animation/easing/quarticInOut.ts +11 -0
  48. package/src/addons/animation/easing/quarticOut.ts +10 -0
  49. package/src/addons/animation/easing/quinticIn.ts +9 -0
  50. package/src/addons/animation/easing/quinticInOut.ts +11 -0
  51. package/src/addons/animation/easing/quinticOut.ts +9 -0
  52. package/src/addons/animation/easing/sineIn.ts +10 -0
  53. package/src/addons/animation/easing/sineInOut.ts +10 -0
  54. package/src/addons/animation/easing/sineOut.ts +10 -0
  55. package/src/addons/color/palette/macbeth.ts +42 -0
  56. package/src/addons/color/space/cmyk2rgb.ts +12 -0
  57. package/src/addons/color/space/gamma2linear.ts +19 -0
  58. package/src/addons/color/space/hsl2rgb.ts +20 -0
  59. package/src/addons/color/space/hsv2rgb.ts +18 -0
  60. package/src/addons/color/space/hue2rgb.ts +12 -0
  61. package/src/addons/color/space/index.ts +29 -0
  62. package/src/addons/color/space/lab2lch.ts +22 -0
  63. package/src/addons/color/space/lab2rgb.ts +19 -0
  64. package/src/addons/color/space/lab2xyz.ts +32 -0
  65. package/src/addons/color/space/lch2lab.ts +21 -0
  66. package/src/addons/color/space/lch2rgb.ts +22 -0
  67. package/src/addons/color/space/linear2gamma.ts +19 -0
  68. package/src/addons/color/space/oklab2rgb.ts +35 -0
  69. package/src/addons/color/space/rgb2cmyk.ts +13 -0
  70. package/src/addons/color/space/rgb2hcv.ts +29 -0
  71. package/src/addons/color/space/rgb2hsl.ts +23 -0
  72. package/src/addons/color/space/rgb2hsv.ts +36 -0
  73. package/src/addons/color/space/rgb2hue.ts +29 -0
  74. package/src/addons/color/space/rgb2lab.ts +19 -0
  75. package/src/addons/color/space/rgb2lch.ts +22 -0
  76. package/src/addons/color/space/rgb2oklab.ts +45 -0
  77. package/src/addons/color/space/rgb2srgb.ts +34 -0
  78. package/src/addons/color/space/rgb2xyz.ts +20 -0
  79. package/src/addons/color/space/rgb2yiq.ts +22 -0
  80. package/src/addons/color/space/rgb2yuv.ts +32 -0
  81. package/src/addons/color/space/srgb2rgb.ts +34 -0
  82. package/src/addons/color/space/xyz2lab.ts +27 -0
  83. package/src/addons/color/space/xyz2rgb.ts +30 -0
  84. package/src/addons/color/space/yiq2rgb.ts +22 -0
  85. package/src/addons/color/space/yuv2rgb.ts +32 -0
  86. package/src/addons/draw/arrows.ts +75 -0
  87. package/src/addons/draw/axis.ts +57 -0
  88. package/src/addons/draw/bridge.ts +81 -0
  89. package/src/addons/draw/char.ts +30 -0
  90. package/src/addons/draw/circle.ts +29 -0
  91. package/src/addons/draw/fill.ts +25 -0
  92. package/src/addons/draw/flip.ts +45 -0
  93. package/src/addons/draw/hex.ts +29 -0
  94. package/src/addons/draw/index.ts +13 -0
  95. package/src/addons/draw/line.ts +16 -0
  96. package/src/addons/draw/point.ts +30 -0
  97. package/src/addons/draw/rect.ts +52 -0
  98. package/src/addons/draw/stroke.ts +31 -0
  99. package/src/addons/draw/tri.ts +29 -0
  100. package/src/addons/generative/cnoise.ts +239 -0
  101. package/src/addons/generative/curl.ts +64 -0
  102. package/src/addons/generative/fbm.ts +69 -0
  103. package/src/addons/generative/gerstnerWave.ts +21 -0
  104. package/src/addons/generative/gnoise.ts +113 -0
  105. package/src/addons/generative/index.ts +15 -0
  106. package/src/addons/generative/noised.ts +139 -0
  107. package/src/addons/generative/pnoise.ts +249 -0
  108. package/src/addons/generative/psrdnoise.ts +277 -0
  109. package/src/addons/generative/random.ts +136 -0
  110. package/src/addons/generative/snoise.ts +199 -0
  111. package/src/addons/generative/srandom.ts +90 -0
  112. package/src/addons/generative/voronoi.ts +134 -0
  113. package/src/addons/generative/voronoise.ts +69 -0
  114. package/src/addons/generative/wavelet.ts +77 -0
  115. package/src/addons/generative/worley.ts +99 -0
  116. package/src/addons/geometry/aabb/aabb.ts +8 -0
  117. package/src/addons/geometry/aabb/centroid.ts +10 -0
  118. package/src/addons/geometry/aabb/contain.ts +19 -0
  119. package/src/addons/geometry/aabb/diagonal.ts +10 -0
  120. package/src/addons/geometry/aabb/expand.ts +16 -0
  121. package/src/addons/geometry/aabb/index.ts +7 -0
  122. package/src/addons/geometry/aabb/intersect.ts +20 -0
  123. package/src/addons/geometry/aabb/square.ts +17 -0
  124. package/src/addons/geometry/index.ts +2 -0
  125. package/src/addons/geometry/triangle/area.ts +10 -0
  126. package/src/addons/geometry/triangle/barycentric.ts +50 -0
  127. package/src/addons/geometry/triangle/centroid.ts +10 -0
  128. package/src/addons/geometry/triangle/closestPoint.ts +85 -0
  129. package/src/addons/geometry/triangle/contain.ts +19 -0
  130. package/src/addons/geometry/triangle/distanceSq.ts +38 -0
  131. package/src/addons/geometry/triangle/index.ts +10 -0
  132. package/src/addons/geometry/triangle/intersect.ts +49 -0
  133. package/src/addons/geometry/triangle/normal.ts +12 -0
  134. package/src/addons/geometry/triangle/signedDistance.ts +31 -0
  135. package/src/addons/geometry/triangle/triangle.ts +9 -0
  136. package/src/addons/index.ts +8 -6
  137. package/src/addons/lighting/ray.ts +8 -0
  138. package/src/addons/math/aafloor.ts +13 -0
  139. package/src/addons/math/aafract.ts +38 -0
  140. package/src/addons/math/aamirror.ts +12 -0
  141. package/src/addons/math/aastep.ts +14 -0
  142. package/src/addons/math/absi.ts +9 -0
  143. package/src/addons/math/adaptiveThreshold.ts +24 -0
  144. package/src/addons/math/bump.ts +20 -0
  145. package/src/addons/math/const.ts +19 -0
  146. package/src/addons/math/cubic.ts +101 -0
  147. package/src/addons/math/cubicMix.ts +49 -0
  148. package/src/addons/math/decimate.ts +12 -0
  149. package/src/addons/math/dist.ts +143 -0
  150. package/src/addons/math/fcos.ts +11 -0
  151. package/src/addons/math/frac.ts +9 -0
  152. package/src/addons/math/gain.ts +14 -0
  153. package/src/addons/math/gaussian.ts +14 -0
  154. package/src/addons/math/grad4.ts +19 -0
  155. package/src/addons/math/hammersley.ts +54 -0
  156. package/src/addons/math/highPass.ts +12 -0
  157. package/src/addons/math/index.ts +63 -0
  158. package/src/addons/math/inside.ts +68 -0
  159. package/src/addons/math/invCubic.ts +9 -0
  160. package/src/addons/math/invQuartic.ts +9 -0
  161. package/src/addons/math/inverse.ts +9 -0
  162. package/src/addons/math/lengthSq.ts +10 -0
  163. package/src/addons/math/map.ts +27 -0
  164. package/src/addons/math/mirror.ts +12 -0
  165. package/src/addons/math/mmax.ts +27 -0
  166. package/src/addons/math/mmin.ts +28 -0
  167. package/src/addons/math/mmix.ts +47 -0
  168. package/src/addons/math/mod2.ts +44 -0
  169. package/src/addons/math/mod289.ts +46 -0
  170. package/src/addons/math/modi.ts +15 -0
  171. package/src/addons/math/nyquist.ts +15 -0
  172. package/src/addons/math/pack.ts +15 -0
  173. package/src/addons/math/parabola.ts +12 -0
  174. package/src/addons/math/permute.ts +42 -0
  175. package/src/addons/math/pow2.ts +10 -0
  176. package/src/addons/math/pow3.ts +9 -0
  177. package/src/addons/math/pow5.ts +10 -0
  178. package/src/addons/math/pow7.ts +12 -0
  179. package/src/addons/math/powFast.ts +18 -0
  180. package/src/addons/math/quartic.ts +15 -0
  181. package/src/addons/math/quat/index.ts +14 -0
  182. package/src/addons/math/quat/quat2mat3.ts +28 -0
  183. package/src/addons/math/quat/quat2mat4.ts +16 -0
  184. package/src/addons/math/quat/quatAdd.ts +18 -0
  185. package/src/addons/math/quat/quatConj.ts +14 -0
  186. package/src/addons/math/quat/quatDiv.ts +18 -0
  187. package/src/addons/math/quat/quatIdentity.ts +9 -0
  188. package/src/addons/math/quat/quatInverse.ts +17 -0
  189. package/src/addons/math/quat/quatLength.ts +15 -0
  190. package/src/addons/math/quat/quatLengthSq.ts +14 -0
  191. package/src/addons/math/quat/quatLerp.ts +40 -0
  192. package/src/addons/math/quat/quatMul.ts +38 -0
  193. package/src/addons/math/quat/quatNeg.ts +14 -0
  194. package/src/addons/math/quat/quatNorm.ts +16 -0
  195. package/src/addons/math/quat/quatSub.ts +18 -0
  196. package/src/addons/math/quintic.ts +16 -0
  197. package/src/addons/math/rotate2d.ts +16 -0
  198. package/src/addons/math/rotate3d.ts +37 -0
  199. package/src/addons/math/rotate3dX.ts +20 -0
  200. package/src/addons/math/rotate3dY.ts +20 -0
  201. package/src/addons/math/rotate3dZ.ts +20 -0
  202. package/src/addons/math/rotate4d.ts +41 -0
  203. package/src/addons/math/rotate4dX.ts +21 -0
  204. package/src/addons/math/rotate4dY.ts +16 -0
  205. package/src/addons/math/rotate4dZ.ts +21 -0
  206. package/src/addons/math/saturateMediump.ts +11 -0
  207. package/src/addons/math/scale2d.ts +44 -0
  208. package/src/addons/math/scale3d.ts +17 -0
  209. package/src/addons/math/scale4d.ts +50 -0
  210. package/src/addons/math/smootherstep.ts +16 -0
  211. package/src/addons/math/taylorInvSqrt.ts +9 -0
  212. package/src/addons/math/toMat3.ts +14 -0
  213. package/src/addons/math/toMat4.ts +14 -0
  214. package/src/addons/math/translate4d.ts +31 -0
  215. package/src/addons/math/unpack.ts +88 -0
  216. package/src/addons/sdf/boxSDF.ts +24 -0
  217. package/src/addons/sdf/circleSDF.ts +20 -0
  218. package/src/addons/sdf/crossSDF.ts +17 -0
  219. package/src/addons/sdf/hexSDF.ts +18 -0
  220. package/src/addons/sdf/index.ts +7 -0
  221. package/src/addons/sdf/lineSDF.ts +33 -0
  222. package/src/addons/sdf/rectSDF.ts +46 -0
  223. package/src/addons/sdf/sphereSDF.ts +20 -0
  224. package/src/addons/sdf/triSDF.ts +14 -0
  225. package/src/addons/space/aspect.ts +14 -0
  226. package/src/addons/space/bracketing.ts +44 -0
  227. package/src/addons/space/brickTile.ts +44 -0
  228. package/src/addons/space/cart2polar.ts +20 -0
  229. package/src/addons/space/center.ts +32 -0
  230. package/src/addons/space/checkerTile.ts +41 -0
  231. package/src/addons/space/depth2viewZ.ts +43 -0
  232. package/src/addons/space/displace.ts +55 -0
  233. package/src/addons/space/equirect2xyz.ts +17 -0
  234. package/src/addons/space/eulerView.ts +19 -0
  235. package/src/addons/space/fisheye2xyz.ts +18 -0
  236. package/src/addons/space/flipY.ts +25 -0
  237. package/src/addons/space/hexTile.ts +18 -0
  238. package/src/addons/space/index.ts +38 -0
  239. package/src/addons/space/kaleidoscope.ts +48 -0
  240. package/src/addons/space/linearizeDepth.ts +17 -0
  241. package/src/addons/space/lookAt.ts +49 -0
  242. package/src/addons/space/lookAtView.ts +40 -0
  243. package/src/addons/space/mirrorTile.ts +73 -0
  244. package/src/addons/space/nearest.ts +13 -0
  245. package/src/addons/space/orthographic.ts +25 -0
  246. package/src/addons/space/parallaxMapping.ts +149 -0
  247. package/src/addons/space/perspective.ts +24 -0
  248. package/src/addons/space/polar2cart.ts +24 -0
  249. package/src/addons/space/ratio.ts +14 -0
  250. package/src/addons/space/rotate.ts +37 -0
  251. package/src/addons/space/rotateX.ts +54 -0
  252. package/src/addons/space/rotateY.ts +54 -0
  253. package/src/addons/space/rotateZ.ts +54 -0
  254. package/src/addons/space/scale.ts +13 -0
  255. package/src/addons/space/sprite.ts +16 -0
  256. package/src/addons/space/sqTile.ts +20 -0
  257. package/src/addons/space/tbn.ts +26 -0
  258. package/src/addons/space/translate.ts +12 -0
  259. package/src/addons/space/triTile.ts +32 -0
  260. package/src/addons/space/uncenter.ts +32 -0
  261. package/src/addons/space/unratio.ts +12 -0
  262. package/src/addons/space/viewZ2depth.ts +25 -0
  263. package/src/addons/space/windmillTile.ts +58 -0
  264. package/src/addons/space/xyz2equirect.ts +10 -0
  265. package/src/index.ts +5 -2
  266. package/src/node/build.ts +62 -52
  267. package/src/node/create.ts +3 -0
  268. package/src/node/index.ts +1 -2
  269. package/src/node/scope.ts +26 -25
  270. package/src/node/types.ts +15 -11
  271. package/src/node/utils/const.ts +12 -11
  272. package/src/node/utils/index.ts +14 -12
  273. package/src/node/utils/infer.ts +15 -5
  274. package/src/node/utils/parse.ts +37 -13
  275. package/src/node/utils/utils.ts +46 -23
  276. package/src/types.ts +9 -2
  277. package/src/utils/helpers.ts +56 -0
  278. package/src/utils/pipeline.ts +21 -5
  279. package/src/utils/program.ts +57 -38
  280. package/src/utils/webgl.ts +41 -35
  281. package/src/utils/webgpu.ts +19 -35
@@ -3,6 +3,7 @@ import { infer } from './infer'
3
3
  import { getConversions, addDependency } from './utils'
4
4
  import { is } from '../../utils/helpers'
5
5
  import type { Constants, NodeContext, NodeProps, StructFields, Y } from '../types'
6
+ import { storageSize } from '../../utils/program'
6
7
 
7
8
  export const parseArray = (children: Y[], c: NodeContext) => {
8
9
  return children
@@ -22,9 +23,9 @@ export const parseGather = (c: NodeContext, x: Y, y: Y, target: Y) => {
22
23
  throw new Error(`Unsupported storage scatter type: ${valueType}`)
23
24
  }
24
25
  const indexVar = code(y, c)
25
- const texSize = Math.floor(Math.sqrt(c.gl?.particles || 1024))
26
- const coordX = `int(${indexVar}) % ${texSize}`
27
- const coordY = `int(${indexVar}) / ${texSize}`
26
+ const size = storageSize(c.gl?.particleCount)
27
+ const coordX = `int(${indexVar}) % ${size.x}`
28
+ const coordY = `int(${indexVar}) / ${size.x}`
28
29
  return `texelFetch(${code(x, c)}, ivec2(${coordX}, ${coordY}), 0)${parseSwizzle()}`
29
30
  }
30
31
 
@@ -123,16 +124,13 @@ export const parseStruct = (c: NodeContext, id: string, instanceId = '', initial
123
124
  export const parseDefine = (c: NodeContext, props: NodeProps, target: Y) => {
124
125
  const { id, children = [], layout } = props
125
126
  const [x, ...args] = children
126
- const argParams: [name: string, type: string][] = []
127
+ const argParams: [name: string, type: Constants][] = []
127
128
  const params: string[] = []
128
- if (layout?.inputs)
129
- for (const input of layout.inputs) {
130
- argParams.push([input.name, input.type])
131
- }
132
- else
133
- for (let i = 0; i < args.length; i++) {
134
- argParams.push([`p${i}`, infer(args[i], c)])
135
- }
129
+ for (let i = 0; i < args.length; i++) {
130
+ const input = layout?.inputs?.[i]
131
+ if (!input) argParams.push([`p${i}`, infer(args[i], c)])
132
+ else argParams.push([input.name, input.type === 'auto' ? infer(args[i], c) : input.type])
133
+ }
136
134
  const scopeCode = code(x, c) // build struct headers before inferring returnType
137
135
  const returnType = infer(target, c)
138
136
  const ret = []
@@ -158,7 +156,7 @@ export const parseDefine = (c: NodeContext, props: NodeProps, target: Y) => {
158
156
  /**
159
157
  * headers
160
158
  */
161
- export const parseVaryingHead = (c: NodeContext, id: string, type: string) => {
159
+ export const parseVaryingHead = (c: NodeContext, id: string, type: Constants) => {
162
160
  return c.isWebGL
163
161
  ? `${type} ${id};`
164
162
  : `@location(${c.code?.vertVaryings?.size || 0}) ${id}: ${getConversions(type, c)}`
@@ -201,6 +199,32 @@ export const parseStorageHead = (c: NodeContext, id: string, type: Constants) =>
201
199
  return `@group(${group}) @binding(${binding}) var<storage, read_write> ${id}: array<${wgslType}>;`
202
200
  }
203
201
 
202
+ export const parseLoop = (c: NodeContext, x: Y, y: Y, id: string) => {
203
+ const conditionType = infer(x, c)
204
+ const bodyCode = code(y, c)
205
+ const conditionCode = code(x, c)
206
+ if (c.isWebGL) {
207
+ if (conditionType === 'int')
208
+ return `for (int ${id} = 0; ${id} < ${conditionCode}; ${id} += 1) {\n${bodyCode}\n}`
209
+ if (conditionType === 'float')
210
+ return `for (float ${id} = 0.0; ${id} < ${conditionCode}; ${id} += 1.0) {\n${bodyCode}\n}`
211
+ if (conditionType === 'vec2')
212
+ return `for (vec2 ${id} = vec2(0.0); ${id}.x < ${conditionCode}.x && ${id}.y < ${conditionCode}.y; ${id} += vec2(1.0)) {\n${bodyCode}\n}`
213
+ if (conditionType === 'vec3')
214
+ return `for (vec3 ${id} = vec3(0.0); ${id}.x < ${conditionCode}.x && ${id}.y < ${conditionCode}.y && ${id}.z < ${conditionCode}.z; ${id} += vec3(1.0)) {\n${bodyCode}\n}`
215
+ return `for (int ${id} = 0; ${id} < ${conditionCode}; ${id} += 1) {\n${bodyCode}\n}`
216
+ }
217
+ if (conditionType === 'int')
218
+ return `for (var ${id}: i32 = 0; ${id} < ${conditionCode}; ${id}++) {\n${bodyCode}\n}`
219
+ if (conditionType === 'float')
220
+ return `for (var ${id}: f32 = 0.0; ${id} < ${conditionCode}; ${id} += 1.0) {\n${bodyCode}\n}`
221
+ if (conditionType === 'vec2')
222
+ return `for (var ${id}: vec2f = vec2f(0.0); ${id}.x < ${conditionCode}.x && ${id}.y < ${conditionCode}.y; ${id} += vec2f(1.0)) {\n${bodyCode}\n}`
223
+ if (conditionType === 'vec3')
224
+ return `for (var ${id}: vec3f = vec3f(0.0); ${id}.x < ${conditionCode}.x && ${id}.y < ${conditionCode}.y && ${id}.z < ${conditionCode}.z; ${id} += vec3f(1.0)) {\n${bodyCode}\n}`
225
+ return `for (var ${id}: i32 = 0; ${id} < ${conditionCode}; ${id}++) {\n${bodyCode}\n}`
226
+ }
227
+
204
228
  export const parseConstantHead = (c: NodeContext, id: string, type: Constants, value: string) => {
205
229
  return c.isWebGL ? `const ${type} ${id} = ${value};` : `const ${id}: ${getConversions(type, c)} = ${value};`
206
230
  }
@@ -8,7 +8,18 @@ import {
8
8
  WGSL_TO_GLSL_BUILTIN,
9
9
  } from './const'
10
10
  import { is } from '../../utils/helpers'
11
- import type { Constants as C, Conversions, Functions, NodeContext, Operators, Swizzles, X, Y } from '../types'
11
+ import type {
12
+ Constants as C,
13
+ Conversions,
14
+ Functions,
15
+ NodeContext,
16
+ NodeTypes,
17
+ Operators,
18
+ Swizzles,
19
+ X,
20
+ Y,
21
+ } from '../types'
22
+ import { storageSize } from '../../utils/program'
12
23
 
13
24
  export const isSwizzle = (key: unknown): key is Swizzles => {
14
25
  return is.str(key) && /^[xyzwrgbastpq]{1,4}$/.test(key)
@@ -50,8 +61,8 @@ export const getId = () => `x${count++}`
50
61
 
51
62
  export const getBluiltin = (c: NodeContext, id: string) => {
52
63
  if (id === 'global_invocation_id') {
53
- const size = Math.floor(Math.sqrt(c.gl?.particles || 1024))
54
- return `uvec3(uint(gl_FragCoord.y) * uint(${size}) + uint(gl_FragCoord.x), 0u, 0u)`
64
+ const size = storageSize(c.gl?.particleCount)
65
+ return `uvec3(uint(gl_FragCoord.y) * uint(${size.x}) + uint(gl_FragCoord.x), 0u, 0u)`
55
66
  }
56
67
  const ret = WGSL_TO_GLSL_BUILTIN[id as keyof typeof WGSL_TO_GLSL_BUILTIN]
57
68
  if (!ret) throw new Error(`Error: unknown builtin variable ${id}`)
@@ -73,26 +84,6 @@ export const getConstant = (conversionKey: string): C => {
73
84
  return index !== -1 ? CONSTANTS[index] : 'float'
74
85
  }
75
86
 
76
- export const getEventFun = (c: NodeContext, id: string, isAttribute = false, isTexture = false) => {
77
- if (c.isWebGL) {
78
- if (isAttribute) return (value: any) => c.gl?.attribute?.(id, value)
79
- if (isTexture) return (value: any) => c.gl?.texture?.(id, value)
80
- return (value: any) => c.gl?.uniform?.(id, value)
81
- }
82
- if (isAttribute) return (value: any) => c.gl?._attribute?.(id, value)
83
- if (isTexture) return (value: any) => c.gl?._texture?.(id, value)
84
- return (value: any) => c.gl?._uniform?.(id, value)
85
- }
86
-
87
- export const safeEventCall = <T extends C>(x: X<T>, fun: (value: unknown) => void) => {
88
- if (is.und(x)) return
89
- if (!isX(x)) return fun(x) // for uniform(0) or uniform([0, 1])
90
- if (x.type !== 'conversion') return
91
- const args = x.props.children?.slice(1)
92
- if (is.und(args?.[0])) return // ignore if uniform(vec2())
93
- fun(args.map((x) => x ?? args[0])) // for uniform(vec2(1)) or uniform(vec2(1, 1))
94
- }
95
-
96
87
  export const initNodeContext = (c: NodeContext) => {
97
88
  if (c.code) return c
98
89
  c.code = {
@@ -119,3 +110,35 @@ export const addDependency = (c: NodeContext, id = '', type: string) => {
119
110
  if (!c.code?.dependencies?.has(id)) c.code!.dependencies.set(id, new Set())
120
111
  if (!isConstants(type)) c.code!.dependencies.get(id)!.add(type)
121
112
  }
113
+
114
+ /**
115
+ * uniform ant attribute event listeners
116
+ */
117
+ const getEventFun = (c: NodeContext, id: string, type: string) => {
118
+ if (c.isWebGL) {
119
+ if (type === 'attribute') return (value: any) => c.gl?.attribute?.(id, value)
120
+ if (type === 'instance') return (value: any) => c.gl?.instance?.(id, value)
121
+ if (type === 'texture') return (value: any) => c.gl?.texture?.(id, value)
122
+ return (value: any) => c.gl?.uniform?.(id, value)
123
+ }
124
+ if (type === 'attribute') return (value: any) => c.gl?._attribute?.(id, value)
125
+ if (type === 'instance') return (value: any) => c.gl?._instance?.(id, value)
126
+ if (type === 'texture') return (value: any) => c.gl?._texture?.(id, value)
127
+ return (value: any) => c.gl?._uniform?.(id, value)
128
+ }
129
+
130
+ const safeEventCall = <T extends C>(x: X<T>, fun: (value: unknown) => void) => {
131
+ if (is.und(x)) return
132
+ if (!isX(x)) return fun(x) // for uniform(0) or uniform([0, 1])
133
+ if (x.type !== 'conversion') return
134
+ const args = x.props.children?.slice(1)
135
+ if (is.und(args?.[0])) return // ignore if uniform(vec2())
136
+ fun(args.map((x) => x ?? args[0])) // for uniform(vec2(1)) or uniform(vec2(1, 1))
137
+ }
138
+
139
+ export const setupEvent = (c: NodeContext, id: string, type: string, target: X, child: X) => {
140
+ const fun = getEventFun(c, id, type)
141
+ safeEventCall(child, fun)
142
+ target.listeners.add(fun)
143
+ return fun
144
+ }
package/src/types.ts CHANGED
@@ -10,14 +10,17 @@ export type GL = EventState<{
10
10
  isWebGL: boolean
11
11
  isError: boolean
12
12
  isLoop: boolean
13
+ isDebug: boolean
14
+ isDepth: boolean
13
15
  isGL: true
14
16
  width?: number
15
17
  height?: number
16
18
  size: [number, number]
17
19
  mouse: [number, number]
18
20
  count: number
21
+ instanceCount: number
22
+ particleCount: number | [number, number] | [number, number, number]
19
23
  loading: number
20
- particles: 64 | 256 | 576 | 1024 | 1600 | 2304 | 3136 | 4096 | 4096 | 5184 | 6400 // (8k)^2
21
24
  el: HTMLCanvasElement
22
25
  vs?: string | Vec4
23
26
  cs?: string | Void
@@ -46,7 +49,7 @@ export type GL = EventState<{
46
49
  error(e?: string): void
47
50
  render(): void
48
51
  resize(e?: Event): void
49
- mousemove(e: Event): void
52
+ mousemove(e: MouseEvent): void
50
53
  loop(): void
51
54
 
52
55
  /**
@@ -61,6 +64,9 @@ export type GL = EventState<{
61
64
  _attribute?(key: string, value: Attribute, iboValue?: Attribute): GL
62
65
  attribute(key: string, value: Attribute, iboValue?: Attribute): GL
63
66
  attribute(target: { [key: string]: Attribute }): GL
67
+ _instance?(key: string, value: Attribute, at?: number): GL
68
+ instance(key: string, value: Attribute, at?: number): GL
69
+ instance(target: { [key: string]: Attribute }): GL
64
70
  _storage?(key: string, value: Storage): GL
65
71
  storage(key: string, value: Storage): GL
66
72
  storage(target: { [key: string]: Storage }): GL
@@ -93,6 +99,7 @@ export interface AttribData {
93
99
  buffer: GPUBuffer
94
100
  location: number
95
101
  stride: number
102
+ isInstance?: boolean
96
103
  }
97
104
 
98
105
  export interface StorageData {
@@ -58,3 +58,59 @@ export const loadingImage = (gl: GL, src: string, fun: (source: HTMLImageElement
58
58
  gl.loading--
59
59
  })
60
60
  }
61
+
62
+ const isValidStride = (stride: number) => [1, 2, 3, 4, 9, 16].includes(stride)
63
+
64
+ const calcStride = (arrayLength: number, count = 3) => {
65
+ if (arrayLength % count === 0) return Math.floor(arrayLength / count)
66
+ return -1
67
+ }
68
+
69
+ export const getStride = (arrayLength: number, count = 1, error = console.warn) => {
70
+ const ret = calcStride(arrayLength, count)
71
+ if (!isValidStride(ret))
72
+ error(
73
+ `glre attribute error: Invalid attribute length ${arrayLength}. Must divide by vertex count (${count}) with valid stride (1,2,3,4,9,16)`
74
+ )
75
+ return ret
76
+ }
77
+
78
+ export const GLSL_FS = /* cpp */ `
79
+ #version 300 es
80
+ precision mediump float;
81
+ out vec4 fragColor;
82
+ uniform vec2 iResolution;
83
+ void main() {
84
+ fragColor = vec4(fract((gl_FragCoord.xy / iResolution)), 0.0, 1.0);
85
+ }
86
+ `
87
+
88
+ export const GLSL_VS = /* cpp */ `
89
+ #version 300 es
90
+ void main() {
91
+ float x = float(gl_VertexID % 2) * 4.0 - 1.0;
92
+ float y = float(gl_VertexID / 2) * 4.0 - 1.0;
93
+ gl_Position = vec4(x, y, 0.0, 1.0);
94
+ }`
95
+
96
+ export const WGSL_VS = /* rust */ `
97
+ struct In { @builtin(vertex_index) vertex_index: u32 }
98
+ struct Out { @builtin(position) position: vec4f }
99
+ @vertex
100
+ fn main(in: In) -> Out {
101
+ var out: Out;
102
+ var x = f32(in.vertex_index % 2) * 4.0 - 1.0;
103
+ var y = f32(in.vertex_index / 2) * 4.0 - 1.0;
104
+ out.position = vec4f(x, y, 0.0, 1.0);
105
+ return out;
106
+ }
107
+ `.trim()
108
+
109
+ export const WGSL_FS = /* rust */ `
110
+ struct Out { @builtin(position) position: vec4f }
111
+ @group(0) @binding(0) var<uniform> iResolution: vec2f;
112
+ @fragment
113
+ fn main(out: Out) -> @location(0) vec4f {
114
+ return vec4f(fract((out.position.xy / iResolution)), 0.0, 1.0);
115
+ }
116
+ `
@@ -1,4 +1,4 @@
1
- import { isFloat32 } from './helpers'
1
+ import { is, isFloat32 } from './helpers'
2
2
  import type { AttribData, TextureData, UniformData, StorageData } from '../types'
3
3
 
4
4
  /**
@@ -58,18 +58,21 @@ const getVertexFormat = (stride: number): GPUVertexFormat => {
58
58
  return 'float32'
59
59
  }
60
60
 
61
- export const createVertexBuffers = (attribs: Iterable<AttribData>) => {
61
+ export const createVertexBuffers = (attribs: Iterable<AttribData & { isInstance?: boolean }>) => {
62
62
  const vertexBuffers: GPUBuffer[] = []
63
63
  const bufferLayouts: GPUVertexBufferLayout[] = []
64
- for (const { buffer, location, stride } of attribs) {
64
+ for (const { buffer, location, stride, isInstance } of attribs) {
65
65
  vertexBuffers[location] = buffer
66
+ const componentSize = Math.min(Math.max(Math.floor(stride), 1), 4)
67
+ const arrayStride = Math.max(4, Math.ceil((componentSize * 4) / 4) * 4)
66
68
  bufferLayouts[location] = {
67
- arrayStride: stride * 4,
69
+ arrayStride,
70
+ stepMode: isInstance ? 'instance' : 'vertex',
68
71
  attributes: [
69
72
  {
70
73
  shaderLocation: location,
71
74
  offset: 0,
72
- format: getVertexFormat(stride),
75
+ format: getVertexFormat(componentSize),
73
76
  },
74
77
  ],
75
78
  }
@@ -203,3 +206,16 @@ export const createDepthTexture = (device: GPUDevice, width: number, height: num
203
206
  usage: GPUTextureUsage.RENDER_ATTACHMENT,
204
207
  })
205
208
  }
209
+
210
+ /**
211
+ * utils
212
+ */
213
+ export const workgroupCount = (particleCount: number | number[], workgroupSize = 32) => {
214
+ if (is.num(particleCount)) particleCount = [particleCount]
215
+ const [x, y = 1, z = 1] = particleCount
216
+ return {
217
+ x: Math.min((x * y * z) / workgroupSize, 65535),
218
+ y: 1,
219
+ z: 1,
220
+ }
221
+ }
@@ -1,7 +1,7 @@
1
1
  import { is } from './helpers'
2
2
  import type { GL } from '../types'
3
3
 
4
- const createShader = (c: WebGLRenderingContext, source: string, type: number, onError = console.warn) => {
4
+ const createShader = (c: WebGL2RenderingContext, source: string, type: number, onError = console.warn) => {
5
5
  const shader = c.createShader(type)
6
6
  if (!shader) return onError('Failed to create shader')
7
7
  c.shaderSource(shader, source.trim())
@@ -12,7 +12,7 @@ const createShader = (c: WebGLRenderingContext, source: string, type: number, on
12
12
  onError(`Could not compile shader: ${error}\n\n↓↓↓generated↓↓↓\n${source}`)
13
13
  }
14
14
 
15
- export const createProgram = (c: WebGLRenderingContext, frag: string, vert: string, gl: GL) => {
15
+ export const createProgram = (c: WebGL2RenderingContext, frag: string, vert: string, gl: GL) => {
16
16
  const pg = c.createProgram()
17
17
  const fs = createShader(c, frag, c.FRAGMENT_SHADER, gl.error)
18
18
  const vs = createShader(c, vert, c.VERTEX_SHADER, gl.error)
@@ -26,45 +26,38 @@ export const createProgram = (c: WebGLRenderingContext, frag: string, vert: stri
26
26
  gl.error(`Could not link program: ${error}`)
27
27
  }
28
28
 
29
- const createVbo = (c: WebGLRenderingContext, data: number[]) => {
29
+ export const createArrayBuffer = (c: WebGL2RenderingContext, data: number[]) => {
30
+ const array = new Float32Array(data)
30
31
  const buffer = c.createBuffer()
31
- c.bindBuffer(c.ARRAY_BUFFER, buffer)
32
- c.bufferData(c.ARRAY_BUFFER, new Float32Array(data), c.STATIC_DRAW)
33
- c.bindBuffer(c.ARRAY_BUFFER, null)
34
- return buffer
32
+ return { array, buffer }
35
33
  }
36
34
 
37
- const createIbo = (c: WebGLRenderingContext, data: number[]) => {
38
- const buffer = c.createBuffer()
39
- c.bindBuffer(c.ELEMENT_ARRAY_BUFFER, buffer)
40
- c.bufferData(c.ELEMENT_ARRAY_BUFFER, new Int16Array(data), c.STATIC_DRAW)
41
- c.bindBuffer(c.ELEMENT_ARRAY_BUFFER, null)
42
- return buffer
35
+ export const setArrayBuffer = (
36
+ c: WebGL2RenderingContext,
37
+ array: Float32Array,
38
+ buffer: WebGLBuffer,
39
+ value: number[]
40
+ ) => {
41
+ array.set(value)
42
+ c.bindBuffer(c.ARRAY_BUFFER, buffer)
43
+ c.bufferData(c.ARRAY_BUFFER, array, c.STATIC_DRAW)
44
+ c.bindBuffer(c.ARRAY_BUFFER, null)
43
45
  }
44
46
 
45
- const getStride = (count: number, value: number[], iboValue?: number[]) => {
46
- if (iboValue) count = Math.max(...iboValue) + 1
47
- const stride = value.length / count
48
- return Math.floor(stride)
47
+ export const updateAttrib = (c: WebGL2RenderingContext, loc: number, stride: number, buffer: WebGLBuffer) => {
48
+ c.bindBuffer(c.ARRAY_BUFFER, buffer)
49
+ c.enableVertexAttribArray(loc)
50
+ c.vertexAttribPointer(loc, stride, c.FLOAT, false, 0, 0)
49
51
  }
50
52
 
51
- export const createAttrib = (
52
- c: WebGLRenderingContext,
53
- loc: number,
54
- count: number,
55
- value: number[],
56
- iboValue: number[]
57
- ) => {
58
- const vbo = createVbo(c, value)
59
- const ibo = createIbo(c, iboValue)
60
- const str = getStride(count, value, iboValue)
61
- c.bindBuffer(c.ARRAY_BUFFER, vbo)
53
+ export const updateInstance = (c: WebGL2RenderingContext, loc: number, stride: number, buffer: WebGLBuffer) => {
54
+ c.bindBuffer(c.ARRAY_BUFFER, buffer)
62
55
  c.enableVertexAttribArray(loc)
63
- c.vertexAttribPointer(loc, str, c.FLOAT, false, 0, 0)
64
- if (ibo) c.bindBuffer(c.ELEMENT_ARRAY_BUFFER, ibo)
56
+ c.vertexAttribPointer(loc, stride, c.FLOAT, false, 0, 0)
57
+ c.vertexAttribDivisor(loc, 1) // divisor is 1
65
58
  }
66
59
 
67
- export const createUniform = (c: WebGLRenderingContext, loc: WebGLUniformLocation, value: number | number[]) => {
60
+ export const updateUniform = (c: WebGL2RenderingContext, loc: WebGLUniformLocation, value: number | number[]) => {
68
61
  if (is.num(value)) return c.uniform1f(loc, value)
69
62
  let l = value.length
70
63
  if (l <= 4) return c[`uniform${l as 2}fv`](loc, value)
@@ -73,7 +66,7 @@ export const createUniform = (c: WebGLRenderingContext, loc: WebGLUniformLocatio
73
66
  }
74
67
 
75
68
  export const createTexture = (
76
- c: WebGLRenderingContext,
69
+ c: WebGL2RenderingContext,
77
70
  img: HTMLImageElement,
78
71
  loc: WebGLUniformLocation,
79
72
  unit: number
@@ -103,28 +96,29 @@ interface TextureBuffer {
103
96
  export const createStorage = (
104
97
  c: WebGL2RenderingContext,
105
98
  value: number[],
106
- size: number,
99
+ width: number,
100
+ height: number,
107
101
  ping: TextureBuffer,
108
102
  pong: TextureBuffer,
109
103
  unit: number,
110
104
  array: Float32Array
111
105
  ) => {
112
- const particles = size * size
113
- const vectorSize = value.length / particles
114
- for (let i = 0; i < particles; i++) {
106
+ const particleCount = width * height
107
+ const vectorSize = value.length / particleCount
108
+ for (let i = 0; i < particleCount; i++) {
115
109
  for (let j = 0; j < Math.min(vectorSize, 4); j++) {
116
110
  array[4 * i + j] = value[i * vectorSize + j] || 0
117
111
  }
118
112
  }
119
113
  c.activeTexture(c.TEXTURE0 + unit)
120
114
  c.bindTexture(c.TEXTURE_2D, ping.texture)
121
- c.texImage2D(c.TEXTURE_2D, 0, c.RGBA32F, size, size, 0, c.RGBA, c.FLOAT, array)
115
+ c.texImage2D(c.TEXTURE_2D, 0, c.RGBA32F, width, height, 0, c.RGBA, c.FLOAT, array)
122
116
  c.texParameteri(c.TEXTURE_2D, c.TEXTURE_MIN_FILTER, c.NEAREST)
123
117
  c.texParameteri(c.TEXTURE_2D, c.TEXTURE_MAG_FILTER, c.NEAREST)
124
118
  c.texParameteri(c.TEXTURE_2D, c.TEXTURE_WRAP_S, c.CLAMP_TO_EDGE)
125
119
  c.texParameteri(c.TEXTURE_2D, c.TEXTURE_WRAP_T, c.CLAMP_TO_EDGE)
126
120
  c.bindTexture(c.TEXTURE_2D, pong.texture)
127
- c.texImage2D(c.TEXTURE_2D, 0, c.RGBA32F, size, size, 0, c.RGBA, c.FLOAT, array)
121
+ c.texImage2D(c.TEXTURE_2D, 0, c.RGBA32F, width, height, 0, c.RGBA, c.FLOAT, array)
128
122
  c.texParameteri(c.TEXTURE_2D, c.TEXTURE_MIN_FILTER, c.NEAREST)
129
123
  c.texParameteri(c.TEXTURE_2D, c.TEXTURE_MAG_FILTER, c.NEAREST)
130
124
  c.texParameteri(c.TEXTURE_2D, c.TEXTURE_WRAP_S, c.CLAMP_TO_EDGE)
@@ -159,3 +153,28 @@ export const createAttachment = (
159
153
  c.framebufferTexture2D(c.FRAMEBUFFER, attachment, c.TEXTURE_2D, o.texture, 0)
160
154
  return attachment
161
155
  }
156
+
157
+ /**
158
+ * utils
159
+ */
160
+ export const storageSize = (particleCount: number | number[] = 1024) => {
161
+ if (is.num(particleCount)) {
162
+ const sqrt = Math.sqrt(particleCount)
163
+ const size = Math.ceil(sqrt)
164
+ if (!Number.isInteger(sqrt)) {
165
+ console.warn(
166
+ `GLRE Storage Warning: particleCount (${particleCount}) is not a square. Using ${size}x${size} texture may waste GPU memory. Consider using [width, height] format for optimal storage.`
167
+ )
168
+ }
169
+ return { x: size, y: size }
170
+ }
171
+ const [x, y, z] = particleCount
172
+ if (z !== undefined) {
173
+ const yz = y * z
174
+ console.warn(
175
+ `GLRE Storage Warning: 3D particleCount [${x}, ${y}, ${z}] specified but WebGL storage textures only support 2D. Flattening to 2D by multiplying height=${y} * depth=${z} = ${yz}.`
176
+ )
177
+ return { x, y: yz }
178
+ }
179
+ return { x, y }
180
+ }
@@ -1,34 +1,20 @@
1
1
  import { nested as cached } from 'reev'
2
- import { is, loadingImage } from './helpers'
2
+ import { is, loadingImage, getStride, GLSL_VS, GLSL_FS } from './helpers'
3
3
  import {
4
+ createArrayBuffer,
4
5
  cleanStorage,
5
6
  createAttachment,
6
- createAttrib,
7
7
  createProgram,
8
8
  createStorage,
9
9
  createTexture,
10
- createUniform,
10
+ setArrayBuffer,
11
+ storageSize,
12
+ updateAttrib,
13
+ updateInstance,
14
+ updateUniform,
11
15
  } from './program'
12
16
  import type { GL, WebGLState } from '../types'
13
17
 
14
- const DEFAULT_FRAGMENT = /* cpp */ `
15
- #version 300 es
16
- precision mediump float;
17
- out vec4 fragColor;
18
- uniform vec2 iResolution;
19
- void main() {
20
- fragColor = vec4(fract((gl_FragCoord.xy / iResolution)), 0.0, 1.0);
21
- }
22
- `
23
-
24
- const DEFAULT_VERTEX = /* cpp */ `
25
- #version 300 es
26
- void main() {
27
- float x = float(gl_VertexID % 2) * 4.0 - 1.0;
28
- float y = float(gl_VertexID / 2) * 4.0 - 1.0;
29
- gl_Position = vec4(x, y, 0.0, 1.0);
30
- }`
31
-
32
18
  const computeProgram = (gl: GL, c: WebGL2RenderingContext) => {
33
19
  if (!gl.cs) return null // ignore if no compute shader
34
20
  c.getExtension('EXT_color_buffer_float')
@@ -38,12 +24,12 @@ const computeProgram = (gl: GL, c: WebGL2RenderingContext) => {
38
24
 
39
25
  const units = cached(() => activeUnit++)
40
26
  const cs = is.str(gl.cs) ? gl.cs : gl.cs!.compute({ isWebGL: true, gl, units })
41
- const pg = createProgram(c, cs, DEFAULT_VERTEX, gl)!
42
- const size = Math.ceil(Math.sqrt(gl.particles))
27
+ const pg = createProgram(c, cs, GLSL_VS, gl)!
28
+ const size = storageSize(gl.particleCount)
43
29
 
44
30
  const uniforms = cached((key) => c.getUniformLocation(pg, key)!)
45
31
  const storages = cached((key) => {
46
- const array = new Float32Array(size * size * 4) // RGBA texture data
32
+ const array = new Float32Array(size.x * size.y * 4) // RGBA texture data
47
33
  const ping = { texture: c.createTexture(), buffer: c.createFramebuffer() }
48
34
  const pong = { texture: c.createTexture(), buffer: c.createFramebuffer() }
49
35
  return { ping, pong, array, loc: uniforms(key), unit: units(key) }
@@ -51,12 +37,12 @@ const computeProgram = (gl: GL, c: WebGL2RenderingContext) => {
51
37
 
52
38
  const _uniform = (key: string, value: number | number[]) => {
53
39
  c.useProgram(pg)
54
- createUniform(c, uniforms(key), value)
40
+ updateUniform(c, uniforms(key), value)
55
41
  }
56
42
 
57
43
  const _storage = (key: string, value: number[]) => {
58
44
  const { ping, pong, unit, array } = storages(key)
59
- createStorage(c, value, size, ping, pong, unit, array)
45
+ createStorage(c, value, size.x, size.y, ping, pong, unit, array)
60
46
  }
61
47
 
62
48
  const clean = () => {
@@ -83,25 +69,38 @@ export const webgl = async (gl: GL) => {
83
69
  const config = { isWebGL: true, gl }
84
70
  const c = gl.el!.getContext('webgl2')!
85
71
  const cp = computeProgram(gl, c)
86
- const fs = gl.fs ? (is.str(gl.fs) ? gl.fs : gl.fs!.fragment(config)) : DEFAULT_FRAGMENT
87
- const vs = gl.vs ? (is.str(gl.vs) ? gl.vs : gl.vs!.vertex(config)) : DEFAULT_VERTEX
72
+ const fs = gl.fs ? (is.str(gl.fs) ? gl.fs : gl.fs!.fragment(config)) : GLSL_FS
73
+ const vs = gl.vs ? (is.str(gl.vs) ? gl.vs : gl.vs!.vertex(config)) : GLSL_VS
88
74
  const pg = createProgram(c, fs, vs, gl)!
89
75
  c.useProgram(pg)
90
76
 
91
77
  let activeUnit = 0 // for texture units
92
78
 
93
79
  const units = cached(() => activeUnit++)
94
- const attribs = cached((key) => c.getAttribLocation(pg, key))
95
80
  const uniforms = cached((key) => c.getUniformLocation(pg, key))
96
81
 
97
- const _attribute = (key = '', value: number[], iboValue: number[]) => {
98
- const loc = attribs(key, true)
99
- createAttrib(c, loc, gl.count, value, iboValue)
82
+ const attribs = cached((key, value: number[], isInstance = false) => {
83
+ const stride = getStride(value.length, isInstance ? gl.instanceCount : gl.count, gl.error)
84
+ const location = c.getAttribLocation(pg, key)
85
+ const { array, buffer } = createArrayBuffer(c, value)
86
+ return { array, buffer, location, stride }
87
+ })
88
+
89
+ const _attribute = (key = '', value: number[]) => {
90
+ const { array, buffer, location, stride } = attribs(key, value)
91
+ setArrayBuffer(c, array, buffer, value)
92
+ updateAttrib(c, location, stride, buffer)
93
+ }
94
+
95
+ const _instance = (key: string, value: number[]) => {
96
+ const { array, buffer, location, stride } = attribs(key, value, true)
97
+ setArrayBuffer(c, array, buffer, value)
98
+ updateInstance(c, location, stride, buffer)
100
99
  }
101
100
 
102
101
  const _uniform = (key: string, value: number | number[]) => {
103
102
  c.useProgram(pg)
104
- createUniform(c, uniforms(key)!, value)
103
+ updateUniform(c, uniforms(key)!, value)
105
104
  cp?._uniform(key, value)
106
105
  }
107
106
 
@@ -122,11 +121,18 @@ export const webgl = async (gl: GL) => {
122
121
  cp?.render()
123
122
  c.useProgram(pg)
124
123
  c.viewport(0, 0, ...gl.size)
125
- c.drawArrays(c.TRIANGLES, 0, gl.count)
124
+ if (gl.instanceCount > 1) {
125
+ c.drawArraysInstanced(c.TRIANGLES, 0, gl.count, gl.instanceCount)
126
+ } else c.drawArrays(c.TRIANGLES, 0, gl.count)
126
127
  c.bindFramebuffer(c.FRAMEBUFFER, null)
127
128
  }
128
129
 
130
+ if (gl.isDepth) {
131
+ c.depthFunc(c.LEQUAL)
132
+ c.enable(c.CULL_FACE)
133
+ }
134
+
129
135
  const webgl: WebGLState = { context: c, program: pg, storages: cp?.storages }
130
136
 
131
- return { webgl, render, clean, _attribute, _uniform, _texture, _storage: cp?._storage }
137
+ return { webgl, render, clean, _attribute, _instance, _uniform, _texture, _storage: cp?._storage }
132
138
  }