@cosmos.gl/graph 2.6.2-rc.0 → 2.7.0-beta.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 (186) hide show
  1. package/.eslintrc +147 -0
  2. package/.github/SECURITY.md +13 -0
  3. package/.github/dco.yml +4 -0
  4. package/.github/workflows/github_pages.yml +54 -0
  5. package/.storybook/main.ts +26 -0
  6. package/.storybook/manager-head.html +1 -0
  7. package/.storybook/manager.ts +14 -0
  8. package/.storybook/preview.ts +29 -0
  9. package/.storybook/style.css +3 -0
  10. package/CHARTER.md +69 -0
  11. package/CODE_OF_CONDUCT.md +178 -0
  12. package/CONTRIBUTING.md +22 -0
  13. package/GOVERNANCE.md +21 -0
  14. package/cosmos-2-0-migration-notes.md +98 -0
  15. package/cosmos_awesome.md +96 -0
  16. package/dist/config.d.ts +5 -9
  17. package/dist/graph/utils/error-message.d.ts +1 -1
  18. package/dist/helper.d.ts +39 -2
  19. package/dist/index-FUIgayhu.js +19827 -0
  20. package/dist/index-FUIgayhu.js.map +1 -0
  21. package/dist/index.d.ts +17 -64
  22. package/dist/index.js +14 -14654
  23. package/dist/index.js.map +1 -1
  24. package/dist/index.min.js +1062 -475
  25. package/dist/index.min.js.map +1 -1
  26. package/dist/modules/Clusters/index.d.ts +11 -3
  27. package/dist/modules/ForceCenter/index.d.ts +10 -3
  28. package/dist/modules/ForceGravity/index.d.ts +5 -1
  29. package/dist/modules/ForceLink/index.d.ts +8 -5
  30. package/dist/modules/ForceManyBody/index.d.ts +16 -7
  31. package/dist/modules/ForceMouse/index.d.ts +5 -1
  32. package/dist/modules/GraphData/index.d.ts +0 -1
  33. package/dist/modules/Lines/index.d.ts +11 -5
  34. package/dist/modules/Points/index.d.ts +31 -13
  35. package/dist/modules/Store/index.d.ts +93 -0
  36. package/dist/modules/core-module.d.ts +3 -3
  37. package/dist/stories/beginners/basic-set-up/data-gen.d.ts +4 -0
  38. package/dist/stories/beginners/basic-set-up/index.d.ts +6 -0
  39. package/dist/stories/beginners/link-hovering/data-generator.d.ts +19 -0
  40. package/dist/stories/beginners/link-hovering/index.d.ts +6 -0
  41. package/dist/stories/beginners/point-labels/data.d.ts +13 -0
  42. package/dist/stories/beginners/point-labels/index.d.ts +10 -0
  43. package/dist/stories/beginners/point-labels/labels.d.ts +8 -0
  44. package/dist/stories/beginners/quick-start.d.ts +6 -0
  45. package/dist/stories/beginners/remove-points/config.d.ts +2 -0
  46. package/dist/stories/beginners/remove-points/data-gen.d.ts +4 -0
  47. package/dist/stories/beginners/remove-points/index.d.ts +6 -0
  48. package/dist/stories/beginners.stories.d.ts +10 -0
  49. package/dist/stories/clusters/polygon-selection/index.d.ts +6 -0
  50. package/dist/stories/clusters/polygon-selection/polygon.d.ts +20 -0
  51. package/dist/stories/clusters/radial.d.ts +6 -0
  52. package/dist/stories/clusters/with-labels.d.ts +6 -0
  53. package/dist/stories/clusters/worm.d.ts +6 -0
  54. package/dist/stories/clusters.stories.d.ts +9 -0
  55. package/dist/stories/create-cluster-labels.d.ts +4 -0
  56. package/dist/stories/create-cosmos.d.ts +17 -0
  57. package/dist/stories/create-story.d.ts +16 -0
  58. package/dist/stories/experiments/full-mesh.d.ts +6 -0
  59. package/dist/stories/experiments/mesh-with-holes.d.ts +6 -0
  60. package/dist/stories/experiments.stories.d.ts +7 -0
  61. package/dist/stories/generate-mesh-data.d.ts +12 -0
  62. package/dist/stories/geospatial/moscow-metro-stations/index.d.ts +16 -0
  63. package/dist/stories/geospatial/moscow-metro-stations/moscow-metro-coords.d.ts +1 -0
  64. package/dist/stories/geospatial/moscow-metro-stations/point-colors.d.ts +1 -0
  65. package/dist/stories/geospatial.stories.d.ts +6 -0
  66. package/dist/stories/shapes/all-shapes/index.d.ts +6 -0
  67. package/dist/stories/shapes/image-example/index.d.ts +6 -0
  68. package/dist/stories/shapes.stories.d.ts +7 -0
  69. package/dist/stories/test-luma-migration.d.ts +6 -0
  70. package/dist/stories/test.stories.d.ts +6 -0
  71. package/dist/webgl-device-B9ewDj5L.js +3923 -0
  72. package/dist/webgl-device-B9ewDj5L.js.map +1 -0
  73. package/logo.svg +3 -0
  74. package/package.json +5 -7
  75. package/rollup.config.js +70 -0
  76. package/src/config.ts +728 -0
  77. package/src/declaration.d.ts +12 -0
  78. package/src/graph/utils/error-message.ts +23 -0
  79. package/src/helper.ts +113 -0
  80. package/src/index.ts +1769 -0
  81. package/src/modules/Clusters/calculate-centermass.frag +12 -0
  82. package/src/modules/Clusters/calculate-centermass.vert +38 -0
  83. package/src/modules/Clusters/force-cluster.frag +55 -0
  84. package/src/modules/Clusters/index.ts +578 -0
  85. package/src/modules/Drag/index.ts +33 -0
  86. package/src/modules/FPSMonitor/css.ts +53 -0
  87. package/src/modules/FPSMonitor/index.ts +28 -0
  88. package/src/modules/ForceCenter/calculate-centermass.frag +9 -0
  89. package/src/modules/ForceCenter/calculate-centermass.vert +26 -0
  90. package/src/modules/ForceCenter/force-center.frag +37 -0
  91. package/src/modules/ForceCenter/index.ts +284 -0
  92. package/src/modules/ForceGravity/force-gravity.frag +40 -0
  93. package/src/modules/ForceGravity/index.ts +107 -0
  94. package/src/modules/ForceLink/force-spring.ts +89 -0
  95. package/src/modules/ForceLink/index.ts +293 -0
  96. package/src/modules/ForceManyBody/calculate-level.frag +9 -0
  97. package/src/modules/ForceManyBody/calculate-level.vert +37 -0
  98. package/src/modules/ForceManyBody/force-centermass.frag +61 -0
  99. package/src/modules/ForceManyBody/force-level.frag +138 -0
  100. package/src/modules/ForceManyBody/index.ts +525 -0
  101. package/src/modules/ForceManyBody/quadtree-frag-shader.ts +89 -0
  102. package/src/modules/ForceManyBodyQuadtree/calculate-level.frag +9 -0
  103. package/src/modules/ForceManyBodyQuadtree/calculate-level.vert +25 -0
  104. package/src/modules/ForceManyBodyQuadtree/index.ts +157 -0
  105. package/src/modules/ForceManyBodyQuadtree/quadtree-frag-shader.ts +93 -0
  106. package/src/modules/ForceMouse/force-mouse.frag +35 -0
  107. package/src/modules/ForceMouse/index.ts +102 -0
  108. package/src/modules/GraphData/index.ts +383 -0
  109. package/src/modules/Lines/draw-curve-line.frag +59 -0
  110. package/src/modules/Lines/draw-curve-line.vert +248 -0
  111. package/src/modules/Lines/geometry.ts +18 -0
  112. package/src/modules/Lines/hovered-line-index.frag +43 -0
  113. package/src/modules/Lines/hovered-line-index.vert +13 -0
  114. package/src/modules/Lines/index.ts +661 -0
  115. package/src/modules/Points/atlas-utils.ts +137 -0
  116. package/src/modules/Points/drag-point.frag +34 -0
  117. package/src/modules/Points/draw-highlighted.frag +44 -0
  118. package/src/modules/Points/draw-highlighted.vert +145 -0
  119. package/src/modules/Points/draw-points.frag +259 -0
  120. package/src/modules/Points/draw-points.vert +203 -0
  121. package/src/modules/Points/fill-sampled-points.frag +12 -0
  122. package/src/modules/Points/fill-sampled-points.vert +51 -0
  123. package/src/modules/Points/find-hovered-point.frag +15 -0
  124. package/src/modules/Points/find-hovered-point.vert +90 -0
  125. package/src/modules/Points/find-points-on-area-selection.frag +88 -0
  126. package/src/modules/Points/find-points-on-polygon-selection.frag +89 -0
  127. package/src/modules/Points/index.ts +2292 -0
  128. package/src/modules/Points/track-positions.frag +30 -0
  129. package/src/modules/Points/update-position.frag +39 -0
  130. package/src/modules/Shared/buffer.ts +39 -0
  131. package/src/modules/Shared/clear.frag +10 -0
  132. package/src/modules/Shared/quad.vert +13 -0
  133. package/src/modules/Store/index.ts +283 -0
  134. package/src/modules/Zoom/index.ts +148 -0
  135. package/src/modules/core-module.ts +28 -0
  136. package/src/stories/1. welcome.mdx +75 -0
  137. package/src/stories/2. configuration.mdx +111 -0
  138. package/src/stories/3. api-reference.mdx +591 -0
  139. package/src/stories/beginners/basic-set-up/data-gen.ts +33 -0
  140. package/src/stories/beginners/basic-set-up/index.ts +167 -0
  141. package/src/stories/beginners/basic-set-up/style.css +35 -0
  142. package/src/stories/beginners/link-hovering/data-generator.ts +198 -0
  143. package/src/stories/beginners/link-hovering/index.ts +65 -0
  144. package/src/stories/beginners/link-hovering/style.css +73 -0
  145. package/src/stories/beginners/point-labels/data.ts +73 -0
  146. package/src/stories/beginners/point-labels/index.ts +69 -0
  147. package/src/stories/beginners/point-labels/labels.ts +46 -0
  148. package/src/stories/beginners/point-labels/style.css +16 -0
  149. package/src/stories/beginners/quick-start.ts +54 -0
  150. package/src/stories/beginners/remove-points/config.ts +25 -0
  151. package/src/stories/beginners/remove-points/data-gen.ts +30 -0
  152. package/src/stories/beginners/remove-points/index.ts +96 -0
  153. package/src/stories/beginners/remove-points/style.css +31 -0
  154. package/src/stories/beginners.stories.ts +130 -0
  155. package/src/stories/clusters/polygon-selection/index.ts +52 -0
  156. package/src/stories/clusters/polygon-selection/polygon.ts +143 -0
  157. package/src/stories/clusters/polygon-selection/style.css +8 -0
  158. package/src/stories/clusters/radial.ts +24 -0
  159. package/src/stories/clusters/with-labels.ts +54 -0
  160. package/src/stories/clusters/worm.ts +40 -0
  161. package/src/stories/clusters.stories.ts +77 -0
  162. package/src/stories/create-cluster-labels.ts +50 -0
  163. package/src/stories/create-cosmos.ts +72 -0
  164. package/src/stories/create-story.ts +51 -0
  165. package/src/stories/experiments/full-mesh.ts +13 -0
  166. package/src/stories/experiments/mesh-with-holes.ts +13 -0
  167. package/src/stories/experiments.stories.ts +43 -0
  168. package/src/stories/generate-mesh-data.ts +125 -0
  169. package/src/stories/geospatial/moscow-metro-stations/index.ts +66 -0
  170. package/src/stories/geospatial/moscow-metro-stations/moscow-metro-coords.ts +1 -0
  171. package/src/stories/geospatial/moscow-metro-stations/point-colors.ts +46 -0
  172. package/src/stories/geospatial/moscow-metro-stations/style.css +30 -0
  173. package/src/stories/geospatial.stories.ts +30 -0
  174. package/src/stories/shapes/all-shapes/index.ts +73 -0
  175. package/src/stories/shapes/image-example/icons/box.png +0 -0
  176. package/src/stories/shapes/image-example/icons/lego.png +0 -0
  177. package/src/stories/shapes/image-example/icons/s.png +0 -0
  178. package/src/stories/shapes/image-example/icons/swift.png +0 -0
  179. package/src/stories/shapes/image-example/icons/toolbox.png +0 -0
  180. package/src/stories/shapes/image-example/index.ts +246 -0
  181. package/src/stories/shapes.stories.ts +37 -0
  182. package/src/stories/test-luma-migration.ts +195 -0
  183. package/src/stories/test.stories.ts +25 -0
  184. package/src/variables.ts +68 -0
  185. package/tsconfig.json +41 -0
  186. package/vite.config.ts +52 -0
@@ -0,0 +1,89 @@
1
+ export function forceFrag (maxLinks: number): string {
2
+ return `#version 300 es
3
+ precision highp float;
4
+
5
+ uniform sampler2D positionsTexture;
6
+ uniform sampler2D linkInfoTexture; // Texture storing first link indices and amount
7
+ uniform sampler2D linkIndicesTexture;
8
+ uniform sampler2D linkPropertiesTexture; // Texture storing link bias and strength
9
+ uniform sampler2D linkRandomDistanceTexture;
10
+
11
+ #ifdef USE_UNIFORM_BUFFERS
12
+ layout(std140) uniform forceLinkUniforms {
13
+ float linkSpring;
14
+ float linkDistance;
15
+ vec2 linkDistRandomVariationRange;
16
+ float pointsTextureSize;
17
+ float linksTextureSize;
18
+ float alpha;
19
+ } forceLink;
20
+
21
+ #define linkSpring forceLink.linkSpring
22
+ #define linkDistance forceLink.linkDistance
23
+ #define linkDistRandomVariationRange forceLink.linkDistRandomVariationRange
24
+ #define pointsTextureSize forceLink.pointsTextureSize
25
+ #define linksTextureSize forceLink.linksTextureSize
26
+ #define alpha forceLink.alpha
27
+ #else
28
+ uniform float linkSpring;
29
+ uniform float linkDistance;
30
+ uniform vec2 linkDistRandomVariationRange;
31
+ uniform float pointsTextureSize;
32
+ uniform float linksTextureSize;
33
+ uniform float alpha;
34
+ #endif
35
+
36
+ in vec2 textureCoords;
37
+ out vec4 fragColor;
38
+
39
+ const float MAX_LINKS = ${maxLinks}.0;
40
+
41
+ void main() {
42
+ vec4 pointPosition = texture(positionsTexture, textureCoords);
43
+ vec4 velocity = vec4(0.0);
44
+
45
+ vec4 linkInfo = texture(linkInfoTexture, textureCoords);
46
+ float iCount = linkInfo.r;
47
+ float jCount = linkInfo.g;
48
+ float linkAmount = linkInfo.b;
49
+ if (linkAmount > 0.0) {
50
+ for (float i = 0.0; i < MAX_LINKS; i += 1.0) {
51
+ if (i < linkAmount) {
52
+ if (iCount >= linksTextureSize) {
53
+ iCount = 0.0;
54
+ jCount += 1.0;
55
+ }
56
+ vec2 linkTextureIndex = (vec2(iCount, jCount) + 0.5) / linksTextureSize;
57
+ vec4 connectedPointIndex = texture(linkIndicesTexture, linkTextureIndex);
58
+ vec4 biasAndStrength = texture(linkPropertiesTexture, linkTextureIndex);
59
+ vec4 randomMinDistance = texture(linkRandomDistanceTexture, linkTextureIndex);
60
+ float bias = biasAndStrength.r;
61
+ float strength = biasAndStrength.g;
62
+ float randomMinLinkDist = randomMinDistance.r * (linkDistRandomVariationRange.g - linkDistRandomVariationRange.r) + linkDistRandomVariationRange.r;
63
+ randomMinLinkDist *= linkDistance;
64
+
65
+ iCount += 1.0;
66
+
67
+ vec4 connectedPointPosition = texture(positionsTexture, (connectedPointIndex.rg + 0.5) / pointsTextureSize);
68
+ float x = connectedPointPosition.x - (pointPosition.x + velocity.x);
69
+ float y = connectedPointPosition.y - (pointPosition.y + velocity.y);
70
+ float l = sqrt(x * x + y * y);
71
+
72
+ // Apply the link force
73
+ l = max(l, randomMinLinkDist * 0.99);
74
+ l = (l - randomMinLinkDist) / l;
75
+ l *= linkSpring * alpha;
76
+ l *= strength;
77
+ l *= bias;
78
+ x *= l;
79
+ y *= l;
80
+ velocity.x += x;
81
+ velocity.y += y;
82
+ }
83
+ }
84
+ }
85
+
86
+ fragColor = vec4(velocity.rg, 0.0, 0.0);
87
+ }
88
+ `
89
+ }
@@ -0,0 +1,293 @@
1
+ import { Buffer, RenderPass, Texture, UniformStore } from '@luma.gl/core'
2
+ import { Model } from '@luma.gl/engine'
3
+ import { CoreModule } from '@/graph/modules/core-module'
4
+ import { forceFrag } from '@/graph/modules/ForceLink/force-spring'
5
+ import updateVert from '@/graph/modules/Shared/quad.vert?raw'
6
+
7
+ export enum LinkDirection {
8
+ OUTGOING = 'outgoing',
9
+ INCOMING = 'incoming'
10
+ }
11
+
12
+ export class ForceLink extends CoreModule {
13
+ private linkFirstIndicesAndAmount: Float32Array = new Float32Array()
14
+ private indices: Float32Array = new Float32Array()
15
+ private maxPointDegree = 0
16
+ private previousMaxPointDegree: number | undefined
17
+ private previousPointsTextureSize: number | undefined
18
+ private previousLinksTextureSize: number | undefined
19
+
20
+ private runCommand: Model | undefined
21
+ private vertexCoordBuffer: Buffer | undefined
22
+ private uniformStore: UniformStore<{
23
+ forceLinkUniforms: {
24
+ linkSpring: number;
25
+ linkDistance: number;
26
+ linkDistRandomVariationRange: [number, number];
27
+ pointsTextureSize: number;
28
+ linksTextureSize: number;
29
+ alpha: number;
30
+ };
31
+ }> | undefined
32
+
33
+ private linkFirstIndicesAndAmountTexture: Texture | undefined
34
+ private indicesTexture: Texture | undefined
35
+ private biasAndStrengthTexture: Texture | undefined
36
+ private randomDistanceTexture: Texture | undefined
37
+
38
+ public create (direction: LinkDirection): void {
39
+ const { device, store: { pointsTextureSize, linksTextureSize }, data } = this
40
+ if (!pointsTextureSize || !linksTextureSize) return
41
+
42
+ this.linkFirstIndicesAndAmount = new Float32Array(pointsTextureSize * pointsTextureSize * 4)
43
+ this.indices = new Float32Array(linksTextureSize * linksTextureSize * 4)
44
+ const linkBiasAndStrengthState = new Float32Array(linksTextureSize * linksTextureSize * 4)
45
+ const linkDistanceState = new Float32Array(linksTextureSize * linksTextureSize * 4)
46
+
47
+ const grouped = direction === LinkDirection.INCOMING ? data.sourceIndexToTargetIndices : data.targetIndexToSourceIndices
48
+ this.maxPointDegree = 0
49
+ let linkIndex = 0
50
+ grouped?.forEach((connectedPointIndices, pointIndex) => {
51
+ if (connectedPointIndices) {
52
+ this.linkFirstIndicesAndAmount[pointIndex * 4 + 0] = linkIndex % linksTextureSize
53
+ this.linkFirstIndicesAndAmount[pointIndex * 4 + 1] = Math.floor(linkIndex / linksTextureSize)
54
+ this.linkFirstIndicesAndAmount[pointIndex * 4 + 2] = connectedPointIndices.length ?? 0
55
+
56
+ connectedPointIndices.forEach(([connectedPointIndex, initialLinkIndex]) => {
57
+ this.indices[linkIndex * 4 + 0] = connectedPointIndex % pointsTextureSize
58
+ this.indices[linkIndex * 4 + 1] = Math.floor(connectedPointIndex / pointsTextureSize)
59
+ const degree = data.degree?.[connectedPointIndex] ?? 0
60
+ const connectedDegree = data.degree?.[pointIndex] ?? 0
61
+ const degreeSum = degree + connectedDegree
62
+ // Prevent division by zero
63
+ const bias = degreeSum !== 0 ? degree / degreeSum : 0.5
64
+ const minDegree = Math.min(degree, connectedDegree)
65
+ // Prevent division by zero
66
+ let strength = data.linkStrength?.[initialLinkIndex] ?? (1 / Math.max(minDegree, 1))
67
+ strength = Math.sqrt(strength)
68
+ linkBiasAndStrengthState[linkIndex * 4 + 0] = bias
69
+ linkBiasAndStrengthState[linkIndex * 4 + 1] = strength
70
+ linkDistanceState[linkIndex * 4] = this.store.getRandomFloat(0, 1)
71
+
72
+ linkIndex += 1
73
+ })
74
+
75
+ this.maxPointDegree = Math.max(this.maxPointDegree, connectedPointIndices.length ?? 0)
76
+ }
77
+ })
78
+
79
+ // Recreate textures if sizes changed
80
+ const recreatePointTextures =
81
+ !this.linkFirstIndicesAndAmountTexture ||
82
+ this.linkFirstIndicesAndAmountTexture.width !== pointsTextureSize ||
83
+ this.linkFirstIndicesAndAmountTexture.height !== pointsTextureSize
84
+
85
+ const recreateLinkTextures =
86
+ !this.indicesTexture ||
87
+ this.indicesTexture.width !== linksTextureSize ||
88
+ this.indicesTexture.height !== linksTextureSize
89
+
90
+ if (recreatePointTextures) {
91
+ if (this.linkFirstIndicesAndAmountTexture && !this.linkFirstIndicesAndAmountTexture.destroyed) {
92
+ this.linkFirstIndicesAndAmountTexture.destroy()
93
+ }
94
+ this.linkFirstIndicesAndAmountTexture = device.createTexture({
95
+ width: pointsTextureSize,
96
+ height: pointsTextureSize,
97
+ format: 'rgba32float',
98
+ usage: Texture.SAMPLE | Texture.COPY_DST,
99
+ })
100
+ }
101
+ this.linkFirstIndicesAndAmountTexture!.copyImageData({
102
+ data: this.linkFirstIndicesAndAmount,
103
+ bytesPerRow: pointsTextureSize,
104
+ mipLevel: 0,
105
+ x: 0,
106
+ y: 0,
107
+ })
108
+
109
+ if (recreateLinkTextures) {
110
+ if (this.indicesTexture && !this.indicesTexture.destroyed) this.indicesTexture.destroy()
111
+ if (this.biasAndStrengthTexture && !this.biasAndStrengthTexture.destroyed) this.biasAndStrengthTexture.destroy()
112
+ if (this.randomDistanceTexture && !this.randomDistanceTexture.destroyed) this.randomDistanceTexture.destroy()
113
+
114
+ this.indicesTexture = device.createTexture({
115
+ width: linksTextureSize,
116
+ height: linksTextureSize,
117
+ format: 'rgba32float',
118
+ usage: Texture.SAMPLE | Texture.COPY_DST,
119
+ })
120
+ this.biasAndStrengthTexture = device.createTexture({
121
+ width: linksTextureSize,
122
+ height: linksTextureSize,
123
+ format: 'rgba32float',
124
+ usage: Texture.SAMPLE | Texture.COPY_DST,
125
+ })
126
+ this.randomDistanceTexture = device.createTexture({
127
+ width: linksTextureSize,
128
+ height: linksTextureSize,
129
+ format: 'rgba32float',
130
+ usage: Texture.SAMPLE | Texture.COPY_DST,
131
+ })
132
+ }
133
+
134
+ this.indicesTexture!.copyImageData({
135
+ data: this.indices,
136
+ bytesPerRow: linksTextureSize,
137
+ mipLevel: 0,
138
+ x: 0,
139
+ y: 0,
140
+ })
141
+ this.biasAndStrengthTexture!.copyImageData({
142
+ data: linkBiasAndStrengthState,
143
+ bytesPerRow: linksTextureSize,
144
+ mipLevel: 0,
145
+ x: 0,
146
+ y: 0,
147
+ })
148
+ this.randomDistanceTexture!.copyImageData({
149
+ data: linkDistanceState,
150
+ bytesPerRow: linksTextureSize,
151
+ mipLevel: 0,
152
+ x: 0,
153
+ y: 0,
154
+ })
155
+
156
+ // Force shader rebuild if degree changed
157
+ if (this.previousMaxPointDegree !== undefined && this.previousMaxPointDegree !== this.maxPointDegree) {
158
+ this.runCommand?.destroy()
159
+ this.runCommand = undefined
160
+ }
161
+
162
+ this.previousMaxPointDegree = this.maxPointDegree
163
+ this.previousPointsTextureSize = pointsTextureSize
164
+ this.previousLinksTextureSize = linksTextureSize
165
+ }
166
+
167
+ public initPrograms (): void {
168
+ const { device, store, points } = this
169
+ if (!points || !store.pointsTextureSize || !store.linksTextureSize) return
170
+ if (!this.linkFirstIndicesAndAmountTexture || !this.indicesTexture || !this.biasAndStrengthTexture || !this.randomDistanceTexture) return
171
+
172
+ if (!this.vertexCoordBuffer || this.vertexCoordBuffer.destroyed) {
173
+ this.vertexCoordBuffer = device.createBuffer({
174
+ data: new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]),
175
+ })
176
+ }
177
+
178
+ if (!this.uniformStore) {
179
+ this.uniformStore = new UniformStore({
180
+ forceLinkUniforms: {
181
+ uniformTypes: {
182
+ linkSpring: 'f32',
183
+ linkDistance: 'f32',
184
+ linkDistRandomVariationRange: 'vec2<f32>',
185
+ pointsTextureSize: 'f32',
186
+ linksTextureSize: 'f32',
187
+ alpha: 'f32',
188
+ },
189
+ },
190
+ })
191
+ }
192
+
193
+ if (!this.runCommand) {
194
+ this.runCommand = new Model(device, {
195
+ fs: forceFrag(this.maxPointDegree),
196
+ vs: updateVert,
197
+ topology: 'triangle-strip',
198
+ vertexCount: 4,
199
+ attributes: {
200
+ vertexCoord: this.vertexCoordBuffer,
201
+ },
202
+ bufferLayout: [
203
+ { name: 'vertexCoord', format: 'float32x2' },
204
+ ],
205
+ defines: {
206
+ USE_UNIFORM_BUFFERS: true,
207
+ },
208
+ bindings: {
209
+ forceLinkUniforms: this.uniformStore.getManagedUniformBuffer(device, 'forceLinkUniforms'),
210
+ positionsTexture: points.previousPositionTexture!,
211
+ linkInfoTexture: this.linkFirstIndicesAndAmountTexture,
212
+ linkIndicesTexture: this.indicesTexture,
213
+ linkPropertiesTexture: this.biasAndStrengthTexture,
214
+ linkRandomDistanceTexture: this.randomDistanceTexture,
215
+ },
216
+ parameters: {
217
+ depthWriteEnabled: false,
218
+ depthCompare: 'always',
219
+ },
220
+ })
221
+ }
222
+ }
223
+
224
+ public run (renderPass?: RenderPass): void {
225
+ const { device, store, points } = this
226
+ if (!points || !this.runCommand || !this.uniformStore) return
227
+ if (!points.previousPositionTexture || points.previousPositionTexture.destroyed) return
228
+ if (!this.linkFirstIndicesAndAmountTexture || !this.indicesTexture || !this.biasAndStrengthTexture || !this.randomDistanceTexture) return
229
+ if (!renderPass && (!points.velocityFbo || points.velocityFbo.destroyed)) return
230
+
231
+ // Skip if sizes changed and create() wasn't called again
232
+ if (
233
+ store.pointsTextureSize !== this.previousPointsTextureSize ||
234
+ store.linksTextureSize !== this.previousLinksTextureSize
235
+ ) {
236
+ return
237
+ }
238
+
239
+ this.uniformStore.setUniforms({
240
+ forceLinkUniforms: {
241
+ linkSpring: this.config.simulationLinkSpring ?? 0,
242
+ linkDistance: this.config.simulationLinkDistance ?? 0,
243
+ linkDistRandomVariationRange: [
244
+ this.config.simulationLinkDistRandomVariationRange?.[0] ?? 0,
245
+ this.config.simulationLinkDistRandomVariationRange?.[1] ?? 0,
246
+ ],
247
+ pointsTextureSize: store.pointsTextureSize,
248
+ linksTextureSize: store.linksTextureSize,
249
+ alpha: store.alpha,
250
+ },
251
+ })
252
+
253
+ this.runCommand.setBindings({
254
+ forceLinkUniforms: this.uniformStore.getManagedUniformBuffer(device, 'forceLinkUniforms'),
255
+ positionsTexture: points.previousPositionTexture!,
256
+ linkInfoTexture: this.linkFirstIndicesAndAmountTexture,
257
+ linkIndicesTexture: this.indicesTexture,
258
+ linkPropertiesTexture: this.biasAndStrengthTexture,
259
+ linkRandomDistanceTexture: this.randomDistanceTexture,
260
+ })
261
+
262
+ const pass = renderPass ?? device.beginRenderPass({
263
+ framebuffer: points.velocityFbo,
264
+ })
265
+
266
+ this.runCommand.draw(pass)
267
+
268
+ if (!renderPass) pass.end()
269
+ }
270
+
271
+ public destroy (): void {
272
+ this.uniformStore?.destroy()
273
+ this.uniformStore = undefined
274
+
275
+ this.runCommand?.destroy()
276
+ this.runCommand = undefined
277
+
278
+ if (this.vertexCoordBuffer && !this.vertexCoordBuffer.destroyed) this.vertexCoordBuffer.destroy()
279
+ this.vertexCoordBuffer = undefined
280
+
281
+ if (this.linkFirstIndicesAndAmountTexture && !this.linkFirstIndicesAndAmountTexture.destroyed) this.linkFirstIndicesAndAmountTexture.destroy()
282
+ this.linkFirstIndicesAndAmountTexture = undefined
283
+
284
+ if (this.indicesTexture && !this.indicesTexture.destroyed) this.indicesTexture.destroy()
285
+ this.indicesTexture = undefined
286
+
287
+ if (this.biasAndStrengthTexture && !this.biasAndStrengthTexture.destroyed) this.biasAndStrengthTexture.destroy()
288
+ this.biasAndStrengthTexture = undefined
289
+
290
+ if (this.randomDistanceTexture && !this.randomDistanceTexture.destroyed) this.randomDistanceTexture.destroy()
291
+ this.randomDistanceTexture = undefined
292
+ }
293
+ }
@@ -0,0 +1,9 @@
1
+ #version 300 es
2
+ precision highp float;
3
+
4
+ in vec4 vColor;
5
+ out vec4 fragColor;
6
+
7
+ void main() {
8
+ fragColor = vColor;
9
+ }
@@ -0,0 +1,37 @@
1
+ #version 300 es
2
+ precision highp float;
3
+
4
+ uniform sampler2D positionsTexture;
5
+
6
+ #ifdef USE_UNIFORM_BUFFERS
7
+ layout(std140) uniform calculateLevelsUniforms {
8
+ float pointsTextureSize;
9
+ float levelTextureSize;
10
+ float cellSize;
11
+ } calculateLevels;
12
+
13
+ #define pointsTextureSize calculateLevels.pointsTextureSize
14
+ #define levelTextureSize calculateLevels.levelTextureSize
15
+ #define cellSize calculateLevels.cellSize
16
+ #else
17
+ uniform float pointsTextureSize;
18
+ uniform float levelTextureSize;
19
+ uniform float cellSize;
20
+ #endif
21
+
22
+ in vec2 pointIndices;
23
+
24
+ out vec4 vColor;
25
+
26
+ void main() {
27
+ vec4 pointPosition = texture(positionsTexture, pointIndices / pointsTextureSize);
28
+ vColor = vec4(pointPosition.rg, 1.0, 0.0);
29
+
30
+ float n = floor(pointPosition.x / cellSize);
31
+ float m = floor(pointPosition.y / cellSize);
32
+
33
+ vec2 levelPosition = 2.0 * (vec2(n, m) + 0.5) / levelTextureSize - 1.0;
34
+
35
+ gl_Position = vec4(levelPosition, 0.0, 1.0);
36
+ gl_PointSize = 1.0;
37
+ }
@@ -0,0 +1,61 @@
1
+ #version 300 es
2
+ precision highp float;
3
+
4
+ uniform sampler2D positionsTexture;
5
+ uniform sampler2D levelFbo;
6
+ uniform sampler2D randomValues;
7
+
8
+ #ifdef USE_UNIFORM_BUFFERS
9
+ layout(std140) uniform forceCenterUniforms {
10
+ float levelTextureSize;
11
+ float repulsion;
12
+ float alpha;
13
+ } forceCenter;
14
+
15
+ #define levelTextureSize forceCenter.levelTextureSize
16
+ #define repulsion forceCenter.repulsion
17
+ #define alpha forceCenter.alpha
18
+ #else
19
+ uniform float levelTextureSize;
20
+ uniform float repulsion;
21
+ uniform float alpha;
22
+ #endif
23
+
24
+ in vec2 textureCoords;
25
+ out vec4 fragColor;
26
+
27
+ // Calculate the additional velocity based on the center of mass
28
+ vec2 calculateAdditionalVelocity (vec2 ij, vec2 pp) {
29
+ vec2 add = vec2(0.0);
30
+ vec4 centermass = texture(levelFbo, ij);
31
+ if (centermass.r > 0.0 && centermass.g > 0.0 && centermass.b > 0.0) {
32
+ vec2 centermassPosition = vec2(centermass.rg / centermass.b);
33
+ vec2 distVector = pp - centermassPosition;
34
+ float l = dot(distVector, distVector);
35
+ float dist = sqrt(l);
36
+ if (l > 0.0) {
37
+ float angle = atan(distVector.y, distVector.x);
38
+ float c = alpha * repulsion * centermass.b;
39
+
40
+ float distanceMin2 = 1.0;
41
+ if (l < distanceMin2) l = sqrt(distanceMin2 * l);
42
+ float addV = c / sqrt(l);
43
+ add = addV * vec2(cos(angle), sin(angle));
44
+ }
45
+ }
46
+ return add;
47
+ }
48
+
49
+ void main() {
50
+ vec4 pointPosition = texture(positionsTexture, textureCoords);
51
+ vec4 random = texture(randomValues, textureCoords);
52
+
53
+ vec4 velocity = vec4(0.0);
54
+
55
+ // Calculate additional velocity based on the point position
56
+ velocity.xy += calculateAdditionalVelocity(pointPosition.xy / levelTextureSize, pointPosition.xy);
57
+ // Apply random factor to the velocity
58
+ velocity.xy += velocity.xy * random.rg;
59
+
60
+ fragColor = velocity;
61
+ }
@@ -0,0 +1,138 @@
1
+ #version 300 es
2
+ precision highp float;
3
+
4
+ uniform sampler2D positionsTexture;
5
+ uniform sampler2D levelFbo;
6
+
7
+ #ifdef USE_UNIFORM_BUFFERS
8
+ layout(std140) uniform forceUniforms {
9
+ float level;
10
+ float levels;
11
+ float levelTextureSize;
12
+ float repulsion;
13
+ float alpha;
14
+ float spaceSize;
15
+ float theta;
16
+ } force;
17
+
18
+ #define level force.level
19
+ #define levels force.levels
20
+ #define levelTextureSize force.levelTextureSize
21
+ #define repulsion force.repulsion
22
+ #define alpha force.alpha
23
+ #define spaceSize force.spaceSize
24
+ #define theta force.theta
25
+ #else
26
+ uniform float level;
27
+ uniform float levels;
28
+ uniform float levelTextureSize;
29
+ uniform float repulsion;
30
+ uniform float alpha;
31
+ uniform float spaceSize;
32
+ uniform float theta;
33
+ #endif
34
+
35
+ in vec2 textureCoords;
36
+ out vec4 fragColor;
37
+
38
+ const float MAX_LEVELS_NUM = 14.0;
39
+
40
+ vec2 calculateAdditionalVelocity (vec2 ij, vec2 pp) {
41
+ vec2 add = vec2(0.0);
42
+ vec4 centermass = texture(levelFbo, ij);
43
+ if (centermass.r > 0.0 && centermass.g > 0.0 && centermass.b > 0.0) {
44
+ vec2 centermassPosition = vec2(centermass.rg / centermass.b);
45
+ vec2 distVector = pp - centermassPosition;
46
+ float l = dot(distVector, distVector);
47
+ float dist = sqrt(l);
48
+ if (l > 0.0) {
49
+ float c = alpha * repulsion * centermass.b;
50
+
51
+ float distanceMin2 = 1.0;
52
+ if (l < distanceMin2) l = sqrt(distanceMin2 * l);
53
+ float addV = c / sqrt(l);
54
+ add = addV * normalize(distVector);
55
+ }
56
+ }
57
+ return add;
58
+ }
59
+
60
+ void main() {
61
+ vec4 pointPosition = texture(positionsTexture, textureCoords);
62
+ float x = pointPosition.x;
63
+ float y = pointPosition.y;
64
+
65
+ float left = 0.0;
66
+ float top = 0.0;
67
+ float right = spaceSize;
68
+ float bottom = spaceSize;
69
+
70
+ float n_left = 0.0;
71
+ float n_top = 0.0;
72
+ float n_right = 0.0;
73
+ float n_bottom = 0.0;
74
+
75
+ float cellSize = 0.0;
76
+
77
+ // Iterate over levels to adjust the boundaries based on the current level
78
+ for (float i = 0.0; i < MAX_LEVELS_NUM; i += 1.0) {
79
+ if (i <= level) {
80
+ left += cellSize * n_left;
81
+ top += cellSize * n_top;
82
+ right -= cellSize * n_right;
83
+ bottom -= cellSize * n_bottom;
84
+
85
+ cellSize = pow(2.0 , levels - i - 1.0);
86
+
87
+ float dist_left = x - left;
88
+ n_left = max(0.0, floor(dist_left / cellSize - theta));
89
+
90
+ float dist_top = y - top;
91
+ n_top = max(0.0, floor(dist_top / cellSize - theta));
92
+
93
+ float dist_right = right - x;
94
+ n_right = max(0.0, floor(dist_right / cellSize - theta));
95
+
96
+ float dist_bottom = bottom - y;
97
+ n_bottom = max(0.0, floor(dist_bottom / cellSize - theta));
98
+
99
+ }
100
+ }
101
+
102
+ vec4 velocity = vec4(vec2(0.0), 1.0, 0.0);
103
+
104
+ // Calculate the additional velocity based on neighboring cells
105
+ for (float i = 0.0; i < 12.0; i += 1.0) {
106
+ for (float j = 0.0; j < 4.0; j += 1.0) {
107
+ float n = left + cellSize * j;
108
+ float m = top + cellSize * n_top + cellSize * i;
109
+
110
+ if (n < (left + n_left * cellSize) && m < bottom) {
111
+ velocity.xy += calculateAdditionalVelocity(vec2(n / cellSize, m / cellSize) / levelTextureSize, pointPosition.xy);
112
+ }
113
+
114
+ n = left + cellSize * i;
115
+ m = top + cellSize * j;
116
+
117
+ if (n < (right - n_right * cellSize) && m < (top + n_top * cellSize)) {
118
+ velocity.xy += calculateAdditionalVelocity(vec2(n / cellSize, m / cellSize) / levelTextureSize, pointPosition.xy);
119
+ }
120
+
121
+ n = right - n_right * cellSize + cellSize * j;
122
+ m = top + cellSize * i;
123
+
124
+ if (n < right && m < (bottom - n_bottom * cellSize)) {
125
+ velocity.xy += calculateAdditionalVelocity(vec2(n / cellSize, m / cellSize) / levelTextureSize, pointPosition.xy);
126
+ }
127
+
128
+ n = left + n_left * cellSize + cellSize * i;
129
+ m = bottom - n_bottom * cellSize + cellSize * j;
130
+
131
+ if (n < right && m < bottom) {
132
+ velocity.xy += calculateAdditionalVelocity(vec2(n / cellSize, m / cellSize) / levelTextureSize, pointPosition.xy);
133
+ }
134
+ }
135
+ }
136
+
137
+ fragColor = velocity;
138
+ }