glre 0.38.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 (295) hide show
  1. package/README.md +8 -4
  2. package/dist/addons.cjs +2 -0
  3. package/dist/addons.cjs.map +1 -0
  4. package/dist/addons.d.ts +1287 -0
  5. package/dist/addons.js +2 -0
  6. package/dist/addons.js.map +1 -0
  7. package/dist/index.cjs +31 -43
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.d.ts +187 -323
  10. package/dist/index.js +31 -43
  11. package/dist/index.js.map +1 -1
  12. package/dist/native.cjs +1 -48
  13. package/dist/native.cjs.map +1 -1
  14. package/dist/native.d.ts +536 -10
  15. package/dist/native.js +1 -48
  16. package/dist/native.js.map +1 -1
  17. package/dist/node.cjs +69 -0
  18. package/dist/node.cjs.map +1 -0
  19. package/dist/node.d.ts +626 -0
  20. package/dist/node.js +69 -0
  21. package/dist/node.js.map +1 -0
  22. package/dist/react.cjs +1 -48
  23. package/dist/react.cjs.map +1 -1
  24. package/dist/react.d.ts +524 -4
  25. package/dist/react.js +1 -48
  26. package/dist/react.js.map +1 -1
  27. package/dist/solid.cjs +1 -48
  28. package/dist/solid.cjs.map +1 -1
  29. package/dist/solid.d.ts +524 -4
  30. package/dist/solid.js +1 -48
  31. package/dist/solid.js.map +1 -1
  32. package/package.json +64 -11
  33. package/src/addons/animation/easing/backIn.ts +10 -0
  34. package/src/addons/animation/easing/backInOut.ts +12 -0
  35. package/src/addons/animation/easing/backOut.ts +10 -0
  36. package/src/addons/animation/easing/bounceIn.ts +10 -0
  37. package/src/addons/animation/easing/bounceInOut.ts +13 -0
  38. package/src/addons/animation/easing/bounceOut.ts +30 -0
  39. package/src/addons/animation/easing/circularIn.ts +9 -0
  40. package/src/addons/animation/easing/circularInOut.ts +11 -0
  41. package/src/addons/animation/easing/circularOut.ts +9 -0
  42. package/src/addons/animation/easing/cubicIn.ts +9 -0
  43. package/src/addons/animation/easing/cubicInOut.ts +11 -0
  44. package/src/addons/animation/easing/cubicOut.ts +10 -0
  45. package/src/addons/animation/easing/elasticIn.ts +10 -0
  46. package/src/addons/animation/easing/elasticInOut.ts +21 -0
  47. package/src/addons/animation/easing/elasticOut.ts +12 -0
  48. package/src/addons/animation/easing/exponentialIn.ts +9 -0
  49. package/src/addons/animation/easing/exponentialInOut.ts +13 -0
  50. package/src/addons/animation/easing/exponentialOut.ts +9 -0
  51. package/src/addons/animation/easing/index.ts +33 -0
  52. package/src/addons/animation/easing/linearIn.ts +9 -0
  53. package/src/addons/animation/easing/linearInOut.ts +9 -0
  54. package/src/addons/animation/easing/linearOut.ts +9 -0
  55. package/src/addons/animation/easing/quadraticIn.ts +9 -0
  56. package/src/addons/animation/easing/quadraticInOut.ts +10 -0
  57. package/src/addons/animation/easing/quadraticOut.ts +9 -0
  58. package/src/addons/animation/easing/quarticIn.ts +9 -0
  59. package/src/addons/animation/easing/quarticInOut.ts +11 -0
  60. package/src/addons/animation/easing/quarticOut.ts +10 -0
  61. package/src/addons/animation/easing/quinticIn.ts +9 -0
  62. package/src/addons/animation/easing/quinticInOut.ts +11 -0
  63. package/src/addons/animation/easing/quinticOut.ts +9 -0
  64. package/src/addons/animation/easing/sineIn.ts +10 -0
  65. package/src/addons/animation/easing/sineInOut.ts +10 -0
  66. package/src/addons/animation/easing/sineOut.ts +10 -0
  67. package/src/addons/color/palette/macbeth.ts +42 -0
  68. package/src/addons/color/space/cmyk2rgb.ts +12 -0
  69. package/src/addons/color/space/gamma2linear.ts +19 -0
  70. package/src/addons/color/space/hsl2rgb.ts +20 -0
  71. package/src/addons/color/space/hsv2rgb.ts +18 -0
  72. package/src/addons/color/space/hue2rgb.ts +12 -0
  73. package/src/addons/color/space/index.ts +29 -0
  74. package/src/addons/color/space/lab2lch.ts +22 -0
  75. package/src/addons/color/space/lab2rgb.ts +19 -0
  76. package/src/addons/color/space/lab2xyz.ts +32 -0
  77. package/src/addons/color/space/lch2lab.ts +21 -0
  78. package/src/addons/color/space/lch2rgb.ts +22 -0
  79. package/src/addons/color/space/linear2gamma.ts +19 -0
  80. package/src/addons/color/space/oklab2rgb.ts +35 -0
  81. package/src/addons/color/space/rgb2cmyk.ts +13 -0
  82. package/src/addons/color/space/rgb2hcv.ts +29 -0
  83. package/src/addons/color/space/rgb2hsl.ts +23 -0
  84. package/src/addons/color/space/rgb2hsv.ts +36 -0
  85. package/src/addons/color/space/rgb2hue.ts +29 -0
  86. package/src/addons/color/space/rgb2lab.ts +19 -0
  87. package/src/addons/color/space/rgb2lch.ts +22 -0
  88. package/src/addons/color/space/rgb2oklab.ts +45 -0
  89. package/src/addons/color/space/rgb2srgb.ts +34 -0
  90. package/src/addons/color/space/rgb2xyz.ts +20 -0
  91. package/src/addons/color/space/rgb2yiq.ts +22 -0
  92. package/src/addons/color/space/rgb2yuv.ts +32 -0
  93. package/src/addons/color/space/srgb2rgb.ts +34 -0
  94. package/src/addons/color/space/xyz2lab.ts +27 -0
  95. package/src/addons/color/space/xyz2rgb.ts +30 -0
  96. package/src/addons/color/space/yiq2rgb.ts +22 -0
  97. package/src/addons/color/space/yuv2rgb.ts +32 -0
  98. package/src/addons/draw/arrows.ts +75 -0
  99. package/src/addons/draw/axis.ts +57 -0
  100. package/src/addons/draw/bridge.ts +81 -0
  101. package/src/addons/draw/char.ts +30 -0
  102. package/src/addons/draw/circle.ts +29 -0
  103. package/src/addons/draw/fill.ts +25 -0
  104. package/src/addons/draw/flip.ts +45 -0
  105. package/src/addons/draw/hex.ts +29 -0
  106. package/src/addons/draw/index.ts +13 -0
  107. package/src/addons/draw/line.ts +16 -0
  108. package/src/addons/draw/point.ts +30 -0
  109. package/src/addons/draw/rect.ts +52 -0
  110. package/src/addons/draw/stroke.ts +31 -0
  111. package/src/addons/draw/tri.ts +29 -0
  112. package/src/addons/generative/cnoise.ts +239 -0
  113. package/src/addons/generative/curl.ts +64 -0
  114. package/src/addons/generative/fbm.ts +69 -0
  115. package/src/addons/generative/gerstnerWave.ts +21 -0
  116. package/src/addons/generative/gnoise.ts +113 -0
  117. package/src/addons/generative/index.ts +15 -0
  118. package/src/addons/generative/noised.ts +139 -0
  119. package/src/addons/generative/pnoise.ts +249 -0
  120. package/src/addons/generative/psrdnoise.ts +277 -0
  121. package/src/addons/generative/random.ts +136 -0
  122. package/src/addons/generative/snoise.ts +199 -0
  123. package/src/addons/generative/srandom.ts +90 -0
  124. package/src/addons/generative/voronoi.ts +134 -0
  125. package/src/addons/generative/voronoise.ts +69 -0
  126. package/src/addons/generative/wavelet.ts +77 -0
  127. package/src/addons/generative/worley.ts +99 -0
  128. package/src/addons/geometry/aabb/aabb.ts +8 -0
  129. package/src/addons/geometry/aabb/centroid.ts +10 -0
  130. package/src/addons/geometry/aabb/contain.ts +19 -0
  131. package/src/addons/geometry/aabb/diagonal.ts +10 -0
  132. package/src/addons/geometry/aabb/expand.ts +16 -0
  133. package/src/addons/geometry/aabb/index.ts +7 -0
  134. package/src/addons/geometry/aabb/intersect.ts +20 -0
  135. package/src/addons/geometry/aabb/square.ts +17 -0
  136. package/src/addons/geometry/index.ts +2 -0
  137. package/src/addons/geometry/triangle/area.ts +10 -0
  138. package/src/addons/geometry/triangle/barycentric.ts +50 -0
  139. package/src/addons/geometry/triangle/centroid.ts +10 -0
  140. package/src/addons/geometry/triangle/closestPoint.ts +85 -0
  141. package/src/addons/geometry/triangle/contain.ts +19 -0
  142. package/src/addons/geometry/triangle/distanceSq.ts +38 -0
  143. package/src/addons/geometry/triangle/index.ts +10 -0
  144. package/src/addons/geometry/triangle/intersect.ts +49 -0
  145. package/src/addons/geometry/triangle/normal.ts +12 -0
  146. package/src/addons/geometry/triangle/signedDistance.ts +31 -0
  147. package/src/addons/geometry/triangle/triangle.ts +9 -0
  148. package/src/addons/index.ts +8 -0
  149. package/src/addons/lighting/ray.ts +8 -0
  150. package/src/addons/math/aafloor.ts +13 -0
  151. package/src/addons/math/aafract.ts +38 -0
  152. package/src/addons/math/aamirror.ts +12 -0
  153. package/src/addons/math/aastep.ts +14 -0
  154. package/src/addons/math/absi.ts +9 -0
  155. package/src/addons/math/adaptiveThreshold.ts +24 -0
  156. package/src/addons/math/bump.ts +20 -0
  157. package/src/addons/math/const.ts +19 -0
  158. package/src/addons/math/cubic.ts +101 -0
  159. package/src/addons/math/cubicMix.ts +49 -0
  160. package/src/addons/math/decimate.ts +12 -0
  161. package/src/addons/math/dist.ts +143 -0
  162. package/src/addons/math/fcos.ts +11 -0
  163. package/src/addons/math/frac.ts +9 -0
  164. package/src/addons/math/gain.ts +14 -0
  165. package/src/addons/math/gaussian.ts +14 -0
  166. package/src/addons/math/grad4.ts +19 -0
  167. package/src/addons/math/hammersley.ts +54 -0
  168. package/src/addons/math/highPass.ts +12 -0
  169. package/src/addons/math/index.ts +63 -0
  170. package/src/addons/math/inside.ts +68 -0
  171. package/src/addons/math/invCubic.ts +9 -0
  172. package/src/addons/math/invQuartic.ts +9 -0
  173. package/src/addons/math/inverse.ts +9 -0
  174. package/src/addons/math/lengthSq.ts +10 -0
  175. package/src/addons/math/map.ts +27 -0
  176. package/src/addons/math/mirror.ts +12 -0
  177. package/src/addons/math/mmax.ts +27 -0
  178. package/src/addons/math/mmin.ts +28 -0
  179. package/src/addons/math/mmix.ts +47 -0
  180. package/src/addons/math/mod2.ts +44 -0
  181. package/src/addons/math/mod289.ts +46 -0
  182. package/src/addons/math/modi.ts +15 -0
  183. package/src/addons/math/nyquist.ts +15 -0
  184. package/src/addons/math/pack.ts +15 -0
  185. package/src/addons/math/parabola.ts +12 -0
  186. package/src/addons/math/permute.ts +42 -0
  187. package/src/addons/math/pow2.ts +10 -0
  188. package/src/addons/math/pow3.ts +9 -0
  189. package/src/addons/math/pow5.ts +10 -0
  190. package/src/addons/math/pow7.ts +12 -0
  191. package/src/addons/math/powFast.ts +18 -0
  192. package/src/addons/math/quartic.ts +15 -0
  193. package/src/addons/math/quat/index.ts +14 -0
  194. package/src/addons/math/quat/quat2mat3.ts +28 -0
  195. package/src/addons/math/quat/quat2mat4.ts +16 -0
  196. package/src/addons/math/quat/quatAdd.ts +18 -0
  197. package/src/addons/math/quat/quatConj.ts +14 -0
  198. package/src/addons/math/quat/quatDiv.ts +18 -0
  199. package/src/addons/math/quat/quatIdentity.ts +9 -0
  200. package/src/addons/math/quat/quatInverse.ts +17 -0
  201. package/src/addons/math/quat/quatLength.ts +15 -0
  202. package/src/addons/math/quat/quatLengthSq.ts +14 -0
  203. package/src/addons/math/quat/quatLerp.ts +40 -0
  204. package/src/addons/math/quat/quatMul.ts +38 -0
  205. package/src/addons/math/quat/quatNeg.ts +14 -0
  206. package/src/addons/math/quat/quatNorm.ts +16 -0
  207. package/src/addons/math/quat/quatSub.ts +18 -0
  208. package/src/addons/math/quintic.ts +16 -0
  209. package/src/addons/math/rotate2d.ts +16 -0
  210. package/src/addons/math/rotate3d.ts +37 -0
  211. package/src/addons/math/rotate3dX.ts +20 -0
  212. package/src/addons/math/rotate3dY.ts +20 -0
  213. package/src/addons/math/rotate3dZ.ts +20 -0
  214. package/src/addons/math/rotate4d.ts +41 -0
  215. package/src/addons/math/rotate4dX.ts +21 -0
  216. package/src/addons/math/rotate4dY.ts +16 -0
  217. package/src/addons/math/rotate4dZ.ts +21 -0
  218. package/src/addons/math/saturateMediump.ts +11 -0
  219. package/src/addons/math/scale2d.ts +44 -0
  220. package/src/addons/math/scale3d.ts +17 -0
  221. package/src/addons/math/scale4d.ts +50 -0
  222. package/src/addons/math/smootherstep.ts +16 -0
  223. package/src/addons/math/taylorInvSqrt.ts +9 -0
  224. package/src/addons/math/toMat3.ts +14 -0
  225. package/src/addons/math/toMat4.ts +14 -0
  226. package/src/addons/math/translate4d.ts +31 -0
  227. package/src/addons/math/unpack.ts +88 -0
  228. package/src/addons/sdf/boxSDF.ts +24 -0
  229. package/src/addons/sdf/circleSDF.ts +20 -0
  230. package/src/addons/sdf/crossSDF.ts +17 -0
  231. package/src/addons/sdf/hexSDF.ts +18 -0
  232. package/src/addons/sdf/index.ts +7 -0
  233. package/src/addons/sdf/lineSDF.ts +33 -0
  234. package/src/addons/sdf/rectSDF.ts +46 -0
  235. package/src/addons/sdf/sphereSDF.ts +20 -0
  236. package/src/addons/sdf/triSDF.ts +14 -0
  237. package/src/addons/space/aspect.ts +14 -0
  238. package/src/addons/space/bracketing.ts +44 -0
  239. package/src/addons/space/brickTile.ts +44 -0
  240. package/src/addons/space/cart2polar.ts +20 -0
  241. package/src/addons/space/center.ts +32 -0
  242. package/src/addons/space/checkerTile.ts +41 -0
  243. package/src/addons/space/depth2viewZ.ts +43 -0
  244. package/src/addons/space/displace.ts +55 -0
  245. package/src/addons/space/equirect2xyz.ts +17 -0
  246. package/src/addons/space/eulerView.ts +19 -0
  247. package/src/addons/space/fisheye2xyz.ts +18 -0
  248. package/src/addons/space/flipY.ts +25 -0
  249. package/src/addons/space/hexTile.ts +18 -0
  250. package/src/addons/space/index.ts +38 -0
  251. package/src/addons/space/kaleidoscope.ts +48 -0
  252. package/src/addons/space/linearizeDepth.ts +17 -0
  253. package/src/addons/space/lookAt.ts +49 -0
  254. package/src/addons/space/lookAtView.ts +40 -0
  255. package/src/addons/space/mirrorTile.ts +73 -0
  256. package/src/addons/space/nearest.ts +13 -0
  257. package/src/addons/space/orthographic.ts +25 -0
  258. package/src/addons/space/parallaxMapping.ts +149 -0
  259. package/src/addons/space/perspective.ts +24 -0
  260. package/src/addons/space/polar2cart.ts +24 -0
  261. package/src/addons/space/ratio.ts +14 -0
  262. package/src/addons/space/rotate.ts +37 -0
  263. package/src/addons/space/rotateX.ts +54 -0
  264. package/src/addons/space/rotateY.ts +54 -0
  265. package/src/addons/space/rotateZ.ts +54 -0
  266. package/src/addons/space/scale.ts +13 -0
  267. package/src/addons/space/sprite.ts +16 -0
  268. package/src/addons/space/sqTile.ts +20 -0
  269. package/src/addons/space/tbn.ts +26 -0
  270. package/src/addons/space/translate.ts +12 -0
  271. package/src/addons/space/triTile.ts +32 -0
  272. package/src/addons/space/uncenter.ts +32 -0
  273. package/src/addons/space/unratio.ts +12 -0
  274. package/src/addons/space/viewZ2depth.ts +25 -0
  275. package/src/addons/space/windmillTile.ts +58 -0
  276. package/src/addons/space/xyz2equirect.ts +10 -0
  277. package/src/index.ts +10 -23
  278. package/src/node/build.ts +127 -0
  279. package/src/node/create.ts +76 -0
  280. package/src/node/index.ts +64 -49
  281. package/src/node/scope.ts +66 -62
  282. package/src/node/types.ts +221 -187
  283. package/src/node/utils/const.ts +74 -13
  284. package/src/node/utils/index.ts +19 -14
  285. package/src/node/utils/infer.ts +32 -34
  286. package/src/node/utils/parse.ts +48 -24
  287. package/src/node/utils/utils.ts +52 -29
  288. package/src/types.ts +11 -6
  289. package/src/utils/helpers.ts +56 -0
  290. package/src/utils/pipeline.ts +24 -8
  291. package/src/utils/program.ts +62 -38
  292. package/src/{webgl.ts → utils/webgl.ts} +46 -30
  293. package/src/{webgpu.ts → utils/webgpu.ts} +22 -17
  294. package/src/node/core.ts +0 -121
  295. package/src/node/node.ts +0 -65
package/src/types.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import type { EventState, Nested } from 'reev'
2
- import type { Fun, Queue, Frame } from 'refr'
3
- import type { NodeProxy, Vec4, Void } from './node'
4
- export type { Fun, Queue, Frame }
2
+ import type { Queue, Frame } from 'refr'
3
+ import type { Vec4, Void } from './node'
5
4
 
6
5
  export type GL = EventState<{
7
6
  /**
@@ -11,14 +10,17 @@ export type GL = EventState<{
11
10
  isWebGL: boolean
12
11
  isError: boolean
13
12
  isLoop: boolean
13
+ isDebug: boolean
14
+ isDepth: boolean
14
15
  isGL: true
15
16
  width?: number
16
17
  height?: number
17
18
  size: [number, number]
18
19
  mouse: [number, number]
19
20
  count: number
21
+ instanceCount: number
22
+ particleCount: number | [number, number] | [number, number, number]
20
23
  loading: number
21
- particles: 64 | 256 | 576 | 1024 | 1600 | 2304 | 3136 | 4096 | 4096 | 5184 | 6400 // (8k)^2
22
24
  el: HTMLCanvasElement
23
25
  vs?: string | Vec4
24
26
  cs?: string | Void
@@ -47,7 +49,7 @@ export type GL = EventState<{
47
49
  error(e?: string): void
48
50
  render(): void
49
51
  resize(e?: Event): void
50
- mousemove(e: Event): void
52
+ mousemove(e: MouseEvent): void
51
53
  loop(): void
52
54
 
53
55
  /**
@@ -55,7 +57,6 @@ export type GL = EventState<{
55
57
  */
56
58
  _uniform?(key: string, value: Uniform, isMatrix?: boolean): GL
57
59
  uniform(key: string, value: Uniform, isMatrix?: boolean): GL
58
- uniform(node: NodeProxy): GL
59
60
  uniform(target: { [key: string]: Uniform }): GL
60
61
  _texture?(key: string, value: string): GL
61
62
  texture(key: string, value: string): GL
@@ -63,6 +64,9 @@ export type GL = EventState<{
63
64
  _attribute?(key: string, value: Attribute, iboValue?: Attribute): GL
64
65
  attribute(key: string, value: Attribute, iboValue?: Attribute): GL
65
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
66
70
  _storage?(key: string, value: Storage): GL
67
71
  storage(key: string, value: Storage): GL
68
72
  storage(target: { [key: string]: Storage }): GL
@@ -95,6 +99,7 @@ export interface AttribData {
95
99
  buffer: GPUBuffer
96
100
  location: number
97
101
  stride: number
102
+ isInstance?: boolean
98
103
  }
99
104
 
100
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
  }
@@ -118,12 +121,12 @@ export const createPipeline = (
118
121
  ) => {
119
122
  return device.createRenderPipeline({
120
123
  vertex: {
121
- module: device.createShaderModule({ label: 'vert', code: vs }),
124
+ module: device.createShaderModule({ label: 'vert', code: vs.trim() }),
122
125
  entryPoint: 'main',
123
126
  buffers: bufferLayouts,
124
127
  },
125
128
  fragment: {
126
- module: device.createShaderModule({ label: 'frag', code: fs }),
129
+ module: device.createShaderModule({ label: 'frag', code: fs.trim() }),
127
130
  entryPoint: 'main',
128
131
  targets: [{ format }],
129
132
  },
@@ -140,7 +143,7 @@ export const createPipeline = (
140
143
  export const createComputePipeline = (device: GPUDevice, bindGroupLayouts: GPUBindGroupLayout[], cs: string) => {
141
144
  return device.createComputePipeline({
142
145
  compute: {
143
- module: device.createShaderModule({ label: 'compute', code: cs }),
146
+ module: device.createShaderModule({ label: 'compute', code: cs.trim() }),
144
147
  entryPoint: 'main',
145
148
  },
146
149
  layout: device.createPipelineLayout({ bindGroupLayouts }),
@@ -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)
@@ -72,7 +65,12 @@ export const createUniform = (c: WebGLRenderingContext, loc: WebGLUniformLocatio
72
65
  c[`uniformMatrix${l as 2}fv`](loc, false, value)
73
66
  }
74
67
 
75
- export const createTexture = (c: WebGLRenderingContext, img: HTMLImageElement, loc: any, unit: number) => {
68
+ export const createTexture = (
69
+ c: WebGL2RenderingContext,
70
+ img: HTMLImageElement,
71
+ loc: WebGLUniformLocation,
72
+ unit: number
73
+ ) => {
76
74
  const texture = c.createTexture()
77
75
  c.bindTexture(c.TEXTURE_2D, texture)
78
76
  c.texImage2D(c.TEXTURE_2D, 0, c.RGBA, c.RGBA, c.UNSIGNED_BYTE, img)
@@ -98,28 +96,29 @@ interface TextureBuffer {
98
96
  export const createStorage = (
99
97
  c: WebGL2RenderingContext,
100
98
  value: number[],
101
- size: number,
99
+ width: number,
100
+ height: number,
102
101
  ping: TextureBuffer,
103
102
  pong: TextureBuffer,
104
103
  unit: number,
105
104
  array: Float32Array
106
105
  ) => {
107
- const particles = size * size
108
- const vectorSize = value.length / particles
109
- 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++) {
110
109
  for (let j = 0; j < Math.min(vectorSize, 4); j++) {
111
110
  array[4 * i + j] = value[i * vectorSize + j] || 0
112
111
  }
113
112
  }
114
113
  c.activeTexture(c.TEXTURE0 + unit)
115
114
  c.bindTexture(c.TEXTURE_2D, ping.texture)
116
- 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)
117
116
  c.texParameteri(c.TEXTURE_2D, c.TEXTURE_MIN_FILTER, c.NEAREST)
118
117
  c.texParameteri(c.TEXTURE_2D, c.TEXTURE_MAG_FILTER, c.NEAREST)
119
118
  c.texParameteri(c.TEXTURE_2D, c.TEXTURE_WRAP_S, c.CLAMP_TO_EDGE)
120
119
  c.texParameteri(c.TEXTURE_2D, c.TEXTURE_WRAP_T, c.CLAMP_TO_EDGE)
121
120
  c.bindTexture(c.TEXTURE_2D, pong.texture)
122
- 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)
123
122
  c.texParameteri(c.TEXTURE_2D, c.TEXTURE_MIN_FILTER, c.NEAREST)
124
123
  c.texParameteri(c.TEXTURE_2D, c.TEXTURE_MAG_FILTER, c.NEAREST)
125
124
  c.texParameteri(c.TEXTURE_2D, c.TEXTURE_WRAP_S, c.CLAMP_TO_EDGE)
@@ -154,3 +153,28 @@ export const createAttachment = (
154
153
  c.framebufferTexture2D(c.FRAMEBUFFER, attachment, c.TEXTURE_2D, o.texture, 0)
155
154
  return attachment
156
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,24 +1,19 @@
1
1
  import { nested as cached } from 'reev'
2
- import { loadingImage } from './utils/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,
11
- } from './utils/program'
12
- import { compute, fragment, vertex } from './node'
13
- import type { GL, WebGLState } from './types'
14
-
15
- const vert = /* cpp */ `
16
- #version 300 es
17
- void main() {
18
- float x = float(gl_VertexID % 2) * 4.0 - 1.0;
19
- float y = float(gl_VertexID / 2) * 4.0 - 1.0;
20
- gl_Position = vec4(x, y, 0.0, 1.0);
21
- }`.trim()
10
+ setArrayBuffer,
11
+ storageSize,
12
+ updateAttrib,
13
+ updateInstance,
14
+ updateUniform,
15
+ } from './program'
16
+ import type { GL, WebGLState } from '../types'
22
17
 
23
18
  const computeProgram = (gl: GL, c: WebGL2RenderingContext) => {
24
19
  if (!gl.cs) return null // ignore if no compute shader
@@ -28,14 +23,13 @@ const computeProgram = (gl: GL, c: WebGL2RenderingContext) => {
28
23
  let currentNum = 0 // for storage buffers
29
24
 
30
25
  const units = cached(() => activeUnit++)
31
- const config = { isWebGL: true, gl, units }
32
-
33
- const pg = createProgram(c, compute(gl.cs, config), vert, gl)!
34
- const size = Math.ceil(Math.sqrt(gl.particles))
26
+ const cs = is.str(gl.cs) ? gl.cs : gl.cs!.compute({ isWebGL: true, gl, units })
27
+ const pg = createProgram(c, cs, GLSL_VS, gl)!
28
+ const size = storageSize(gl.particleCount)
35
29
 
36
30
  const uniforms = cached((key) => c.getUniformLocation(pg, key)!)
37
31
  const storages = cached((key) => {
38
- const array = new Float32Array(size * size * 4) // RGBA texture data
32
+ const array = new Float32Array(size.x * size.y * 4) // RGBA texture data
39
33
  const ping = { texture: c.createTexture(), buffer: c.createFramebuffer() }
40
34
  const pong = { texture: c.createTexture(), buffer: c.createFramebuffer() }
41
35
  return { ping, pong, array, loc: uniforms(key), unit: units(key) }
@@ -43,12 +37,12 @@ const computeProgram = (gl: GL, c: WebGL2RenderingContext) => {
43
37
 
44
38
  const _uniform = (key: string, value: number | number[]) => {
45
39
  c.useProgram(pg)
46
- createUniform(c, uniforms(key), value)
40
+ updateUniform(c, uniforms(key), value)
47
41
  }
48
42
 
49
43
  const _storage = (key: string, value: number[]) => {
50
44
  const { ping, pong, unit, array } = storages(key)
51
- createStorage(c, value, size, ping, pong, unit, array)
45
+ createStorage(c, value, size.x, size.y, ping, pong, unit, array)
52
46
  }
53
47
 
54
48
  const clean = () => {
@@ -75,30 +69,45 @@ export const webgl = async (gl: GL) => {
75
69
  const config = { isWebGL: true, gl }
76
70
  const c = gl.el!.getContext('webgl2')!
77
71
  const cp = computeProgram(gl, c)
78
- const pg = createProgram(c, fragment(gl.fs, config), vertex(gl.vs, config), gl)!
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
74
+ const pg = createProgram(c, fs, vs, gl)!
79
75
  c.useProgram(pg)
80
76
 
81
77
  let activeUnit = 0 // for texture units
82
78
 
83
79
  const units = cached(() => activeUnit++)
84
- const attribs = cached((key) => c.getAttribLocation(pg, key))
85
80
  const uniforms = cached((key) => c.getUniformLocation(pg, key))
86
81
 
87
- const _attribute = (key = '', value: number[], iboValue: number[]) => {
88
- const loc = attribs(key, true)
89
- 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)
90
99
  }
91
100
 
92
101
  const _uniform = (key: string, value: number | number[]) => {
93
102
  c.useProgram(pg)
94
- createUniform(c, uniforms(key)!, value)
103
+ updateUniform(c, uniforms(key)!, value)
95
104
  cp?._uniform(key, value)
96
105
  }
97
106
 
98
107
  const _texture = (key: string, src: string) => {
99
108
  c.useProgram(pg)
100
109
  loadingImage(gl, src, (source) => {
101
- createTexture(c, source, uniforms(key), units(key))
110
+ createTexture(c, source, uniforms(key)!, units(key))
102
111
  })
103
112
  }
104
113
 
@@ -112,11 +121,18 @@ export const webgl = async (gl: GL) => {
112
121
  cp?.render()
113
122
  c.useProgram(pg)
114
123
  c.viewport(0, 0, ...gl.size)
115
- 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)
116
127
  c.bindFramebuffer(c.FRAMEBUFFER, null)
117
128
  }
118
129
 
130
+ if (gl.isDepth) {
131
+ c.depthFunc(c.LEQUAL)
132
+ c.enable(c.CULL_FACE)
133
+ }
134
+
119
135
  const webgl: WebGLState = { context: c, program: pg, storages: cp?.storages }
120
136
 
121
- return { webgl, render, clean, _attribute, _uniform, _texture, _storage: cp?._storage }
137
+ return { webgl, render, clean, _attribute, _instance, _uniform, _texture, _storage: cp?._storage }
122
138
  }
@@ -1,5 +1,5 @@
1
1
  import { nested as cached } from 'reev'
2
- import { is, loadingImage } from './utils/helpers'
2
+ import { is, loadingImage, getStride, WGSL_FS, WGSL_VS } from './helpers'
3
3
  import {
4
4
  createArrayBuffer,
5
5
  createBindGroup,
@@ -11,11 +11,9 @@ import {
11
11
  createPipeline,
12
12
  createTextureSampler,
13
13
  createVertexBuffers,
14
- } from './utils/pipeline'
15
- import type { GL, WebGPUState } from './types'
16
- import { compute, fragment, vertex } from './node'
17
-
18
- const WORKING_GROUP_SIZE = 32
14
+ workgroupCount,
15
+ } from './pipeline'
16
+ import type { GL, WebGPUState } from '../types'
19
17
 
20
18
  const computeProgram = (gl: GL, device: GPUDevice, bindings: any) => {
21
19
  let flush = (_pass: GPUComputePassEncoder) => {}
@@ -36,8 +34,8 @@ const computeProgram = (gl: GL, device: GPUDevice, bindings: any) => {
36
34
  flush = (pass) => {
37
35
  pass.setPipeline(pipeline)
38
36
  bindGroups.forEach((v, i) => pass.setBindGroup(i, v))
39
- const workgroupCount = Math.ceil(gl.particles / WORKING_GROUP_SIZE)
40
- pass.dispatchWorkgroups(workgroupCount, 1, 1)
37
+ const { x, y, z } = workgroupCount(gl.particleCount)
38
+ pass.dispatchWorkgroups(x, y, z)
41
39
  pass.end()
42
40
  }
43
41
  }
@@ -65,12 +63,12 @@ export const webgpu = async (gl: GL) => {
65
63
  let needsUpdate = true
66
64
  let depthTexture: GPUTexture
67
65
 
68
- const attribs = cached((_key, value: number[]) => {
66
+ const attribs = cached((_key, value: number[], isInstance = false) => {
69
67
  needsUpdate = true
70
- const stride = value.length / gl.count
68
+ const stride = getStride(value.length, isInstance ? gl.instanceCount : gl.count)
71
69
  const { location } = bindings.attrib()
72
70
  const { array, buffer } = createArrayBuffer(device, value, 'attrib')
73
- return { array, buffer, location, stride }
71
+ return { array, buffer, location, stride, isInstance }
74
72
  })
75
73
 
76
74
  const uniforms = cached((_key, value: number[]) => {
@@ -89,13 +87,20 @@ export const webgpu = async (gl: GL) => {
89
87
 
90
88
  const _attribute = (key = '', value: number[]) => {
91
89
  const { array, buffer } = attribs(key, value)
90
+ array.set(value)
91
+ device.queue.writeBuffer(buffer, 0, array as any)
92
+ }
93
+
94
+ const _instance = (key: string, value: number[]) => {
95
+ const { array, buffer } = attribs(key, value, true)
96
+ array.set(value)
92
97
  device.queue.writeBuffer(buffer, 0, array as any)
93
98
  }
94
99
 
95
100
  const _uniform = (key: string, value: number | number[]) => {
96
101
  if (is.num(value)) value = [value]
97
102
  const { array, buffer } = uniforms(key, value)
98
- array.set(value) // needs to set leatest value
103
+ array.set(value)
99
104
  device.queue.writeBuffer(buffer, 0, array as any)
100
105
  }
101
106
 
@@ -120,7 +125,7 @@ export const webgpu = async (gl: GL) => {
120
125
  pass.setPipeline(pipeline)
121
126
  bindGroups.forEach((v, i) => pass.setBindGroup(i, v))
122
127
  vertexBuffers.forEach((v, i) => pass.setVertexBuffer(i, v))
123
- pass.draw(gl.count, 1, 0, 0)
128
+ pass.draw(gl.count, gl.instanceCount, 0, 0)
124
129
  pass.end()
125
130
  }
126
131
  if (gl.cs) cp.update(bindGroups, bindGroupLayouts, comp)
@@ -129,9 +134,9 @@ export const webgpu = async (gl: GL) => {
129
134
  const render = () => {
130
135
  if (!frag || !vert) {
131
136
  const config = { isWebGL: false, gl }
132
- frag = fragment(gl.fs, config) // needs to be before vertex
133
- vert = vertex(gl.vs, config)
134
- comp = compute(gl.cs, config)
137
+ frag = gl.fs ? (is.str(gl.fs) ? gl.fs : gl.fs.fragment(config)) : WGSL_FS
138
+ vert = gl.vs ? (is.str(gl.vs) ? gl.vs : gl.vs.vertex(config)) : WGSL_VS
139
+ comp = gl.cs ? (is.str(gl.cs) ? gl.cs : gl.cs.compute(config)) : ''
135
140
  }
136
141
  if (gl.loading) return // MEMO: loading after build node
137
142
  if (needsUpdate) update()
@@ -161,5 +166,5 @@ export const webgpu = async (gl: GL) => {
161
166
 
162
167
  const webgpu = { device, uniforms, textures, attribs, storages: cp.storages } as WebGPUState
163
168
 
164
- return { webgpu, render, resize, clean, _attribute, _uniform, _texture, _storage: cp._storage }
169
+ return { webgpu, render, resize, clean, _attribute, _instance, _uniform, _texture, _storage: cp._storage }
165
170
  }