@cosmos.gl/graph 2.6.2 → 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.
- package/.eslintrc +147 -0
- package/.github/SECURITY.md +13 -0
- package/.github/dco.yml +4 -0
- package/.github/workflows/github_pages.yml +54 -0
- package/.storybook/main.ts +26 -0
- package/.storybook/manager-head.html +1 -0
- package/.storybook/manager.ts +14 -0
- package/.storybook/preview.ts +29 -0
- package/.storybook/style.css +3 -0
- package/CHARTER.md +69 -0
- package/CODE_OF_CONDUCT.md +178 -0
- package/CONTRIBUTING.md +22 -0
- package/GOVERNANCE.md +21 -0
- package/cosmos-2-0-migration-notes.md +98 -0
- package/cosmos_awesome.md +96 -0
- package/dist/config.d.ts +5 -18
- package/dist/graph/utils/error-message.d.ts +1 -1
- package/dist/helper.d.ts +39 -2
- package/dist/index-FUIgayhu.js +19827 -0
- package/dist/index-FUIgayhu.js.map +1 -0
- package/dist/index.d.ts +17 -64
- package/dist/index.js +14 -14658
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1062 -475
- package/dist/index.min.js.map +1 -1
- package/dist/modules/Clusters/index.d.ts +11 -3
- package/dist/modules/ForceCenter/index.d.ts +10 -3
- package/dist/modules/ForceGravity/index.d.ts +5 -1
- package/dist/modules/ForceLink/index.d.ts +8 -5
- package/dist/modules/ForceManyBody/index.d.ts +16 -7
- package/dist/modules/ForceMouse/index.d.ts +5 -1
- package/dist/modules/GraphData/index.d.ts +0 -1
- package/dist/modules/Lines/index.d.ts +11 -5
- package/dist/modules/Points/index.d.ts +31 -13
- package/dist/modules/Store/index.d.ts +93 -0
- package/dist/modules/core-module.d.ts +3 -3
- package/dist/stories/beginners/basic-set-up/data-gen.d.ts +4 -0
- package/dist/stories/beginners/basic-set-up/index.d.ts +6 -0
- package/dist/stories/beginners/link-hovering/data-generator.d.ts +19 -0
- package/dist/stories/beginners/link-hovering/index.d.ts +6 -0
- package/dist/stories/beginners/point-labels/data.d.ts +13 -0
- package/dist/stories/beginners/point-labels/index.d.ts +10 -0
- package/dist/stories/beginners/point-labels/labels.d.ts +8 -0
- package/dist/stories/beginners/quick-start.d.ts +6 -0
- package/dist/stories/beginners/remove-points/config.d.ts +2 -0
- package/dist/stories/beginners/remove-points/data-gen.d.ts +4 -0
- package/dist/stories/beginners/remove-points/index.d.ts +6 -0
- package/dist/stories/beginners.stories.d.ts +10 -0
- package/dist/stories/clusters/polygon-selection/index.d.ts +6 -0
- package/dist/stories/clusters/polygon-selection/polygon.d.ts +20 -0
- package/dist/stories/clusters/radial.d.ts +6 -0
- package/dist/stories/clusters/with-labels.d.ts +6 -0
- package/dist/stories/clusters/worm.d.ts +6 -0
- package/dist/stories/clusters.stories.d.ts +9 -0
- package/dist/stories/create-cluster-labels.d.ts +4 -0
- package/dist/stories/create-cosmos.d.ts +17 -0
- package/dist/stories/create-story.d.ts +16 -0
- package/dist/stories/experiments/full-mesh.d.ts +6 -0
- package/dist/stories/experiments/mesh-with-holes.d.ts +6 -0
- package/dist/stories/experiments.stories.d.ts +7 -0
- package/dist/stories/generate-mesh-data.d.ts +12 -0
- package/dist/stories/geospatial/moscow-metro-stations/index.d.ts +16 -0
- package/dist/stories/geospatial/moscow-metro-stations/moscow-metro-coords.d.ts +1 -0
- package/dist/stories/geospatial/moscow-metro-stations/point-colors.d.ts +1 -0
- package/dist/stories/geospatial.stories.d.ts +6 -0
- package/dist/stories/shapes/all-shapes/index.d.ts +6 -0
- package/dist/stories/shapes/image-example/index.d.ts +6 -0
- package/dist/stories/shapes.stories.d.ts +7 -0
- package/dist/stories/test-luma-migration.d.ts +6 -0
- package/dist/stories/test.stories.d.ts +6 -0
- package/dist/webgl-device-B9ewDj5L.js +3923 -0
- package/dist/webgl-device-B9ewDj5L.js.map +1 -0
- package/logo.svg +3 -0
- package/package.json +5 -7
- package/rollup.config.js +70 -0
- package/src/config.ts +728 -0
- package/src/declaration.d.ts +12 -0
- package/src/graph/utils/error-message.ts +23 -0
- package/src/helper.ts +113 -0
- package/src/index.ts +1769 -0
- package/src/modules/Clusters/calculate-centermass.frag +12 -0
- package/src/modules/Clusters/calculate-centermass.vert +38 -0
- package/src/modules/Clusters/force-cluster.frag +55 -0
- package/src/modules/Clusters/index.ts +578 -0
- package/src/modules/Drag/index.ts +33 -0
- package/src/modules/FPSMonitor/css.ts +53 -0
- package/src/modules/FPSMonitor/index.ts +28 -0
- package/src/modules/ForceCenter/calculate-centermass.frag +9 -0
- package/src/modules/ForceCenter/calculate-centermass.vert +26 -0
- package/src/modules/ForceCenter/force-center.frag +37 -0
- package/src/modules/ForceCenter/index.ts +284 -0
- package/src/modules/ForceGravity/force-gravity.frag +40 -0
- package/src/modules/ForceGravity/index.ts +107 -0
- package/src/modules/ForceLink/force-spring.ts +89 -0
- package/src/modules/ForceLink/index.ts +293 -0
- package/src/modules/ForceManyBody/calculate-level.frag +9 -0
- package/src/modules/ForceManyBody/calculate-level.vert +37 -0
- package/src/modules/ForceManyBody/force-centermass.frag +61 -0
- package/src/modules/ForceManyBody/force-level.frag +138 -0
- package/src/modules/ForceManyBody/index.ts +525 -0
- package/src/modules/ForceManyBody/quadtree-frag-shader.ts +89 -0
- package/src/modules/ForceManyBodyQuadtree/calculate-level.frag +9 -0
- package/src/modules/ForceManyBodyQuadtree/calculate-level.vert +25 -0
- package/src/modules/ForceManyBodyQuadtree/index.ts +157 -0
- package/src/modules/ForceManyBodyQuadtree/quadtree-frag-shader.ts +93 -0
- package/src/modules/ForceMouse/force-mouse.frag +35 -0
- package/src/modules/ForceMouse/index.ts +102 -0
- package/src/modules/GraphData/index.ts +383 -0
- package/src/modules/Lines/draw-curve-line.frag +59 -0
- package/src/modules/Lines/draw-curve-line.vert +248 -0
- package/src/modules/Lines/geometry.ts +18 -0
- package/src/modules/Lines/hovered-line-index.frag +43 -0
- package/src/modules/Lines/hovered-line-index.vert +13 -0
- package/src/modules/Lines/index.ts +661 -0
- package/src/modules/Points/atlas-utils.ts +137 -0
- package/src/modules/Points/drag-point.frag +34 -0
- package/src/modules/Points/draw-highlighted.frag +44 -0
- package/src/modules/Points/draw-highlighted.vert +145 -0
- package/src/modules/Points/draw-points.frag +259 -0
- package/src/modules/Points/draw-points.vert +203 -0
- package/src/modules/Points/fill-sampled-points.frag +12 -0
- package/src/modules/Points/fill-sampled-points.vert +51 -0
- package/src/modules/Points/find-hovered-point.frag +15 -0
- package/src/modules/Points/find-hovered-point.vert +90 -0
- package/src/modules/Points/find-points-on-area-selection.frag +88 -0
- package/src/modules/Points/find-points-on-polygon-selection.frag +89 -0
- package/src/modules/Points/index.ts +2292 -0
- package/src/modules/Points/track-positions.frag +30 -0
- package/src/modules/Points/update-position.frag +39 -0
- package/src/modules/Shared/buffer.ts +39 -0
- package/src/modules/Shared/clear.frag +10 -0
- package/src/modules/Shared/quad.vert +13 -0
- package/src/modules/Store/index.ts +283 -0
- package/src/modules/Zoom/index.ts +148 -0
- package/src/modules/core-module.ts +28 -0
- package/src/stories/1. welcome.mdx +75 -0
- package/src/stories/2. configuration.mdx +111 -0
- package/src/stories/3. api-reference.mdx +591 -0
- package/src/stories/beginners/basic-set-up/data-gen.ts +33 -0
- package/src/stories/beginners/basic-set-up/index.ts +167 -0
- package/src/stories/beginners/basic-set-up/style.css +35 -0
- package/src/stories/beginners/link-hovering/data-generator.ts +198 -0
- package/src/stories/beginners/link-hovering/index.ts +65 -0
- package/src/stories/beginners/link-hovering/style.css +73 -0
- package/src/stories/beginners/point-labels/data.ts +73 -0
- package/src/stories/beginners/point-labels/index.ts +69 -0
- package/src/stories/beginners/point-labels/labels.ts +46 -0
- package/src/stories/beginners/point-labels/style.css +16 -0
- package/src/stories/beginners/quick-start.ts +54 -0
- package/src/stories/beginners/remove-points/config.ts +25 -0
- package/src/stories/beginners/remove-points/data-gen.ts +30 -0
- package/src/stories/beginners/remove-points/index.ts +96 -0
- package/src/stories/beginners/remove-points/style.css +31 -0
- package/src/stories/beginners.stories.ts +130 -0
- package/src/stories/clusters/polygon-selection/index.ts +52 -0
- package/src/stories/clusters/polygon-selection/polygon.ts +143 -0
- package/src/stories/clusters/polygon-selection/style.css +8 -0
- package/src/stories/clusters/radial.ts +24 -0
- package/src/stories/clusters/with-labels.ts +54 -0
- package/src/stories/clusters/worm.ts +40 -0
- package/src/stories/clusters.stories.ts +77 -0
- package/src/stories/create-cluster-labels.ts +50 -0
- package/src/stories/create-cosmos.ts +72 -0
- package/src/stories/create-story.ts +51 -0
- package/src/stories/experiments/full-mesh.ts +13 -0
- package/src/stories/experiments/mesh-with-holes.ts +13 -0
- package/src/stories/experiments.stories.ts +43 -0
- package/src/stories/generate-mesh-data.ts +125 -0
- package/src/stories/geospatial/moscow-metro-stations/index.ts +66 -0
- package/src/stories/geospatial/moscow-metro-stations/moscow-metro-coords.ts +1 -0
- package/src/stories/geospatial/moscow-metro-stations/point-colors.ts +46 -0
- package/src/stories/geospatial/moscow-metro-stations/style.css +30 -0
- package/src/stories/geospatial.stories.ts +30 -0
- package/src/stories/shapes/all-shapes/index.ts +73 -0
- package/src/stories/shapes/image-example/icons/box.png +0 -0
- package/src/stories/shapes/image-example/icons/lego.png +0 -0
- package/src/stories/shapes/image-example/icons/s.png +0 -0
- package/src/stories/shapes/image-example/icons/swift.png +0 -0
- package/src/stories/shapes/image-example/icons/toolbox.png +0 -0
- package/src/stories/shapes/image-example/index.ts +246 -0
- package/src/stories/shapes.stories.ts +37 -0
- package/src/stories/test-luma-migration.ts +195 -0
- package/src/stories/test.stories.ts +25 -0
- package/src/variables.ts +68 -0
- package/tsconfig.json +41 -0
- package/vite.config.ts +52 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#version 300 es
|
|
2
|
+
#ifdef GL_ES
|
|
3
|
+
precision highp float;
|
|
4
|
+
#endif
|
|
5
|
+
|
|
6
|
+
uniform sampler2D positionsTexture;
|
|
7
|
+
uniform sampler2D clusterTexture;
|
|
8
|
+
|
|
9
|
+
#ifdef USE_UNIFORM_BUFFERS
|
|
10
|
+
layout(std140) uniform calculateCentermassUniforms {
|
|
11
|
+
float pointsTextureSize;
|
|
12
|
+
float clustersTextureSize;
|
|
13
|
+
} calculateCentermass;
|
|
14
|
+
|
|
15
|
+
#define pointsTextureSize calculateCentermass.pointsTextureSize
|
|
16
|
+
#define clustersTextureSize calculateCentermass.clustersTextureSize
|
|
17
|
+
#else
|
|
18
|
+
uniform float pointsTextureSize;
|
|
19
|
+
uniform float clustersTextureSize;
|
|
20
|
+
#endif
|
|
21
|
+
|
|
22
|
+
in vec2 pointIndices;
|
|
23
|
+
|
|
24
|
+
out vec4 rgba;
|
|
25
|
+
|
|
26
|
+
void main() {
|
|
27
|
+
vec4 pointPosition = texture(positionsTexture, pointIndices / pointsTextureSize);
|
|
28
|
+
rgba = vec4(pointPosition.xy, 1.0, 0.0);
|
|
29
|
+
|
|
30
|
+
vec4 pointClusterIndices = texture(clusterTexture, pointIndices / pointsTextureSize);
|
|
31
|
+
vec2 xy = vec2(0.0);
|
|
32
|
+
if (pointClusterIndices.x >= 0.0 && pointClusterIndices.y >= 0.0) {
|
|
33
|
+
xy = 2.0 * (pointClusterIndices.xy + 0.5) / clustersTextureSize - 1.0;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
gl_Position = vec4(xy, 0.0, 1.0);
|
|
37
|
+
gl_PointSize = 1.0;
|
|
38
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#version 300 es
|
|
2
|
+
#ifdef GL_ES
|
|
3
|
+
precision highp float;
|
|
4
|
+
#endif
|
|
5
|
+
|
|
6
|
+
uniform sampler2D positionsTexture;
|
|
7
|
+
uniform sampler2D centermassTexture;
|
|
8
|
+
uniform sampler2D clusterTexture;
|
|
9
|
+
uniform sampler2D clusterPositionsTexture;
|
|
10
|
+
uniform sampler2D clusterForceCoefficient;
|
|
11
|
+
|
|
12
|
+
#ifdef USE_UNIFORM_BUFFERS
|
|
13
|
+
layout(std140) uniform applyForcesUniforms {
|
|
14
|
+
float alpha;
|
|
15
|
+
float clustersTextureSize;
|
|
16
|
+
float clusterCoefficient;
|
|
17
|
+
} applyForces;
|
|
18
|
+
|
|
19
|
+
#define alpha applyForces.alpha
|
|
20
|
+
#define clustersTextureSize applyForces.clustersTextureSize
|
|
21
|
+
#define clusterCoefficient applyForces.clusterCoefficient
|
|
22
|
+
#else
|
|
23
|
+
uniform float alpha;
|
|
24
|
+
uniform float clustersTextureSize;
|
|
25
|
+
uniform float clusterCoefficient;
|
|
26
|
+
#endif
|
|
27
|
+
|
|
28
|
+
in vec2 textureCoords;
|
|
29
|
+
|
|
30
|
+
out vec4 fragColor;
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
void main() {
|
|
34
|
+
vec4 pointPosition = texture(positionsTexture, textureCoords);
|
|
35
|
+
vec4 velocity = vec4(0.0);
|
|
36
|
+
vec4 pointClusterIndices = texture(clusterTexture, textureCoords);
|
|
37
|
+
// no cluster, so no forces
|
|
38
|
+
if (pointClusterIndices.x >= 0.0 && pointClusterIndices.y >= 0.0) {
|
|
39
|
+
// positioning points to custom cluster position or either to the center of mass
|
|
40
|
+
vec2 clusterPositions = texture(clusterPositionsTexture, pointClusterIndices.xy / clustersTextureSize).xy;
|
|
41
|
+
if (clusterPositions.x < 0.0 || clusterPositions.y < 0.0) {
|
|
42
|
+
vec4 centermassValues = texture(centermassTexture, pointClusterIndices.xy / clustersTextureSize);
|
|
43
|
+
clusterPositions = centermassValues.xy / centermassValues.b;
|
|
44
|
+
}
|
|
45
|
+
vec4 clusterCustomCoeff = texture(clusterForceCoefficient, textureCoords);
|
|
46
|
+
vec2 distVector = clusterPositions.xy - pointPosition.xy;
|
|
47
|
+
float dist = length(distVector);
|
|
48
|
+
if (dist > 0.0) {
|
|
49
|
+
float addV = alpha * dist * clusterCoefficient * clusterCustomCoeff.r;
|
|
50
|
+
velocity.rg += addV * normalize(distVector);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
fragColor = velocity;
|
|
55
|
+
}
|
|
@@ -0,0 +1,578 @@
|
|
|
1
|
+
import { Framebuffer, Buffer, Texture, UniformStore, RenderPass } from '@luma.gl/core'
|
|
2
|
+
import { Model } from '@luma.gl/engine'
|
|
3
|
+
import { CoreModule } from '@/graph/modules/core-module'
|
|
4
|
+
import calculateCentermassFrag from '@/graph/modules/Clusters/calculate-centermass.frag?raw'
|
|
5
|
+
import calculateCentermassVert from '@/graph/modules/Clusters/calculate-centermass.vert?raw'
|
|
6
|
+
import forceFrag from '@/graph/modules/Clusters/force-cluster.frag?raw'
|
|
7
|
+
import { createIndexesForBuffer } from '@/graph/modules/Shared/buffer'
|
|
8
|
+
import clearFrag from '@/graph/modules/Shared/clear.frag?raw'
|
|
9
|
+
import updateVert from '@/graph/modules/Shared/quad.vert?raw'
|
|
10
|
+
|
|
11
|
+
export class Clusters extends CoreModule {
|
|
12
|
+
public centermassFbo: Framebuffer | undefined
|
|
13
|
+
public clusterCount: number | undefined
|
|
14
|
+
|
|
15
|
+
private clusterFbo: Framebuffer | undefined
|
|
16
|
+
private clusterPositionsFbo: Framebuffer | undefined
|
|
17
|
+
private clusterForceCoefficientFbo: Framebuffer | undefined
|
|
18
|
+
private clearCentermassCommand: Model | undefined
|
|
19
|
+
private calculateCentermassCommand: Model | undefined
|
|
20
|
+
private applyForcesCommand: Model | undefined
|
|
21
|
+
private clusterTexture: Texture | undefined
|
|
22
|
+
private clusterPositionsTexture: Texture | undefined
|
|
23
|
+
private clusterForceCoefficientTexture: Texture | undefined
|
|
24
|
+
private centermassTexture: Texture | undefined
|
|
25
|
+
private pointIndices: Buffer | undefined
|
|
26
|
+
private clustersTextureSize: number | undefined
|
|
27
|
+
|
|
28
|
+
// Attribute buffers that need manual cleanup (Model doesn't destroy them)
|
|
29
|
+
private clearCentermassVertexCoordBuffer: Buffer | undefined
|
|
30
|
+
private applyForcesVertexCoordBuffer: Buffer | undefined
|
|
31
|
+
|
|
32
|
+
// Track previous sizes to detect changes
|
|
33
|
+
private previousPointsTextureSize: number | undefined
|
|
34
|
+
private previousClustersTextureSize: number | undefined
|
|
35
|
+
private previousClusterCount: number | undefined
|
|
36
|
+
|
|
37
|
+
// Uniform stores for scalar uniforms
|
|
38
|
+
private calculateCentermassUniformStore: UniformStore<{
|
|
39
|
+
calculateCentermassUniforms: {
|
|
40
|
+
pointsTextureSize: number;
|
|
41
|
+
clustersTextureSize: number;
|
|
42
|
+
};
|
|
43
|
+
}> | undefined
|
|
44
|
+
|
|
45
|
+
private applyForcesUniformStore: UniformStore<{
|
|
46
|
+
applyForcesUniforms: {
|
|
47
|
+
alpha: number;
|
|
48
|
+
clustersTextureSize: number;
|
|
49
|
+
clusterCoefficient: number;
|
|
50
|
+
};
|
|
51
|
+
}> | undefined
|
|
52
|
+
|
|
53
|
+
public create (): void {
|
|
54
|
+
const { device, store, data } = this
|
|
55
|
+
const { pointsTextureSize } = store
|
|
56
|
+
if (data.pointsNumber === undefined || (!data.pointClusters && !data.clusterPositions)) return
|
|
57
|
+
|
|
58
|
+
// Find the highest cluster index in the array and add 1 (since cluster indices start at 0).
|
|
59
|
+
this.clusterCount = (data.pointClusters ?? []).reduce<number>((max, clusterIndex) => {
|
|
60
|
+
if (clusterIndex === undefined || clusterIndex < 0) return max
|
|
61
|
+
return Math.max(max, clusterIndex)
|
|
62
|
+
}, 0) + 1
|
|
63
|
+
|
|
64
|
+
this.clustersTextureSize = Math.ceil(Math.sqrt(this.clusterCount))
|
|
65
|
+
|
|
66
|
+
// Check if sizes have changed - if so, we need to recreate textures/framebuffers
|
|
67
|
+
const sizesChanged =
|
|
68
|
+
this.previousPointsTextureSize !== pointsTextureSize ||
|
|
69
|
+
this.previousClustersTextureSize !== this.clustersTextureSize ||
|
|
70
|
+
this.previousClusterCount !== this.clusterCount
|
|
71
|
+
|
|
72
|
+
const pointsTextureDataSize = pointsTextureSize * pointsTextureSize * 4
|
|
73
|
+
const clustersTextureDataSize = this.clustersTextureSize * this.clustersTextureSize * 4
|
|
74
|
+
|
|
75
|
+
const clusterState = new Float32Array(pointsTextureDataSize)
|
|
76
|
+
const clusterPositions = new Float32Array(clustersTextureDataSize).fill(-1)
|
|
77
|
+
const clusterForceCoefficient = new Float32Array(pointsTextureDataSize).fill(1)
|
|
78
|
+
if (data.clusterPositions) {
|
|
79
|
+
for (let cluster = 0; cluster < this.clusterCount; ++cluster) {
|
|
80
|
+
clusterPositions[cluster * 4 + 0] = data.clusterPositions[cluster * 2 + 0] ?? -1
|
|
81
|
+
clusterPositions[cluster * 4 + 1] = data.clusterPositions[cluster * 2 + 1] ?? -1
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
for (let i = 0; i < data.pointsNumber; ++i) {
|
|
86
|
+
const clusterIndex = data.pointClusters?.[i]
|
|
87
|
+
if (clusterIndex === undefined) {
|
|
88
|
+
// no cluster, so no forces
|
|
89
|
+
clusterState[i * 4 + 0] = -1
|
|
90
|
+
clusterState[i * 4 + 1] = -1
|
|
91
|
+
} else {
|
|
92
|
+
clusterState[i * 4 + 0] = clusterIndex % this.clustersTextureSize
|
|
93
|
+
clusterState[i * 4 + 1] = Math.floor(clusterIndex / this.clustersTextureSize)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (data.clusterStrength) clusterForceCoefficient[i * 4 + 0] = data.clusterStrength[i] ?? 1
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Handle clusterTexture - recreate if size changed, update data if size same
|
|
100
|
+
if (!this.clusterTexture || sizesChanged) {
|
|
101
|
+
// Destroy framebuffer FIRST (before texture)
|
|
102
|
+
if (this.clusterFbo && !this.clusterFbo.destroyed) {
|
|
103
|
+
this.clusterFbo.destroy()
|
|
104
|
+
}
|
|
105
|
+
// Then destroy texture
|
|
106
|
+
if (this.clusterTexture && !this.clusterTexture.destroyed) {
|
|
107
|
+
this.clusterTexture.destroy()
|
|
108
|
+
}
|
|
109
|
+
// Create new texture
|
|
110
|
+
this.clusterTexture = device.createTexture({
|
|
111
|
+
width: pointsTextureSize,
|
|
112
|
+
height: pointsTextureSize,
|
|
113
|
+
format: 'rgba32float',
|
|
114
|
+
usage: Texture.SAMPLE | Texture.RENDER | Texture.COPY_DST,
|
|
115
|
+
})
|
|
116
|
+
this.clusterTexture.copyImageData({
|
|
117
|
+
data: clusterState,
|
|
118
|
+
bytesPerRow: pointsTextureSize,
|
|
119
|
+
mipLevel: 0,
|
|
120
|
+
x: 0,
|
|
121
|
+
y: 0,
|
|
122
|
+
})
|
|
123
|
+
// Create new framebuffer with explicit dimensions
|
|
124
|
+
this.clusterFbo = device.createFramebuffer({
|
|
125
|
+
width: pointsTextureSize,
|
|
126
|
+
height: pointsTextureSize,
|
|
127
|
+
colorAttachments: [this.clusterTexture],
|
|
128
|
+
})
|
|
129
|
+
} else {
|
|
130
|
+
// Size hasn't changed, just update the data
|
|
131
|
+
this.clusterTexture.copyImageData({
|
|
132
|
+
data: clusterState,
|
|
133
|
+
bytesPerRow: pointsTextureSize,
|
|
134
|
+
mipLevel: 0,
|
|
135
|
+
x: 0,
|
|
136
|
+
y: 0,
|
|
137
|
+
})
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Handle clusterPositionsTexture
|
|
141
|
+
if (!this.clusterPositionsTexture || sizesChanged) {
|
|
142
|
+
// Destroy framebuffer FIRST
|
|
143
|
+
if (this.clusterPositionsFbo && !this.clusterPositionsFbo.destroyed) {
|
|
144
|
+
this.clusterPositionsFbo.destroy()
|
|
145
|
+
}
|
|
146
|
+
// Then destroy texture
|
|
147
|
+
if (this.clusterPositionsTexture && !this.clusterPositionsTexture.destroyed) {
|
|
148
|
+
this.clusterPositionsTexture.destroy()
|
|
149
|
+
}
|
|
150
|
+
// Create new texture
|
|
151
|
+
this.clusterPositionsTexture = device.createTexture({
|
|
152
|
+
width: this.clustersTextureSize,
|
|
153
|
+
height: this.clustersTextureSize,
|
|
154
|
+
format: 'rgba32float',
|
|
155
|
+
usage: Texture.SAMPLE | Texture.RENDER | Texture.COPY_DST,
|
|
156
|
+
})
|
|
157
|
+
this.clusterPositionsTexture.copyImageData({
|
|
158
|
+
data: clusterPositions,
|
|
159
|
+
bytesPerRow: this.clustersTextureSize,
|
|
160
|
+
mipLevel: 0,
|
|
161
|
+
x: 0,
|
|
162
|
+
y: 0,
|
|
163
|
+
})
|
|
164
|
+
// Create new framebuffer with explicit dimensions
|
|
165
|
+
this.clusterPositionsFbo = device.createFramebuffer({
|
|
166
|
+
width: this.clustersTextureSize,
|
|
167
|
+
height: this.clustersTextureSize,
|
|
168
|
+
colorAttachments: [this.clusterPositionsTexture],
|
|
169
|
+
})
|
|
170
|
+
} else {
|
|
171
|
+
// Update data
|
|
172
|
+
this.clusterPositionsTexture.copyImageData({
|
|
173
|
+
data: clusterPositions,
|
|
174
|
+
bytesPerRow: this.clustersTextureSize,
|
|
175
|
+
mipLevel: 0,
|
|
176
|
+
x: 0,
|
|
177
|
+
y: 0,
|
|
178
|
+
})
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Handle clusterForceCoefficientTexture
|
|
182
|
+
if (!this.clusterForceCoefficientTexture || sizesChanged) {
|
|
183
|
+
// Destroy framebuffer FIRST
|
|
184
|
+
if (this.clusterForceCoefficientFbo && !this.clusterForceCoefficientFbo.destroyed) {
|
|
185
|
+
this.clusterForceCoefficientFbo.destroy()
|
|
186
|
+
}
|
|
187
|
+
// Then destroy texture
|
|
188
|
+
if (this.clusterForceCoefficientTexture && !this.clusterForceCoefficientTexture.destroyed) {
|
|
189
|
+
this.clusterForceCoefficientTexture.destroy()
|
|
190
|
+
}
|
|
191
|
+
// Create new texture
|
|
192
|
+
this.clusterForceCoefficientTexture = device.createTexture({
|
|
193
|
+
width: pointsTextureSize,
|
|
194
|
+
height: pointsTextureSize,
|
|
195
|
+
format: 'rgba32float',
|
|
196
|
+
usage: Texture.SAMPLE | Texture.RENDER | Texture.COPY_DST,
|
|
197
|
+
})
|
|
198
|
+
this.clusterForceCoefficientTexture.copyImageData({
|
|
199
|
+
data: clusterForceCoefficient,
|
|
200
|
+
bytesPerRow: pointsTextureSize,
|
|
201
|
+
mipLevel: 0,
|
|
202
|
+
x: 0,
|
|
203
|
+
y: 0,
|
|
204
|
+
})
|
|
205
|
+
// Create new framebuffer with explicit dimensions
|
|
206
|
+
this.clusterForceCoefficientFbo = device.createFramebuffer({
|
|
207
|
+
width: pointsTextureSize,
|
|
208
|
+
height: pointsTextureSize,
|
|
209
|
+
colorAttachments: [this.clusterForceCoefficientTexture],
|
|
210
|
+
})
|
|
211
|
+
} else {
|
|
212
|
+
// Update data
|
|
213
|
+
this.clusterForceCoefficientTexture.copyImageData({
|
|
214
|
+
data: clusterForceCoefficient,
|
|
215
|
+
bytesPerRow: pointsTextureSize,
|
|
216
|
+
mipLevel: 0,
|
|
217
|
+
x: 0,
|
|
218
|
+
y: 0,
|
|
219
|
+
})
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Handle centermassTexture - only size depends on clustersTextureSize
|
|
223
|
+
if (!this.centermassTexture || this.previousClustersTextureSize !== this.clustersTextureSize) {
|
|
224
|
+
// Destroy framebuffer FIRST
|
|
225
|
+
if (this.centermassFbo && !this.centermassFbo.destroyed) {
|
|
226
|
+
this.centermassFbo.destroy()
|
|
227
|
+
}
|
|
228
|
+
// Then destroy texture
|
|
229
|
+
if (this.centermassTexture && !this.centermassTexture.destroyed) {
|
|
230
|
+
this.centermassTexture.destroy()
|
|
231
|
+
}
|
|
232
|
+
// Create new texture
|
|
233
|
+
this.centermassTexture = device.createTexture({
|
|
234
|
+
width: this.clustersTextureSize,
|
|
235
|
+
height: this.clustersTextureSize,
|
|
236
|
+
format: 'rgba32float',
|
|
237
|
+
usage: Texture.SAMPLE | Texture.RENDER | Texture.COPY_DST,
|
|
238
|
+
})
|
|
239
|
+
this.centermassTexture.copyImageData({
|
|
240
|
+
data: new Float32Array(clustersTextureDataSize).fill(0),
|
|
241
|
+
bytesPerRow: this.clustersTextureSize,
|
|
242
|
+
mipLevel: 0,
|
|
243
|
+
x: 0,
|
|
244
|
+
y: 0,
|
|
245
|
+
})
|
|
246
|
+
// Create new framebuffer with explicit dimensions
|
|
247
|
+
this.centermassFbo = device.createFramebuffer({
|
|
248
|
+
width: this.clustersTextureSize,
|
|
249
|
+
height: this.clustersTextureSize,
|
|
250
|
+
colorAttachments: [this.centermassTexture],
|
|
251
|
+
})
|
|
252
|
+
} else {
|
|
253
|
+
// Clear the centermass texture (fill with zeros)
|
|
254
|
+
this.centermassTexture.copyImageData({
|
|
255
|
+
data: new Float32Array(clustersTextureDataSize).fill(0),
|
|
256
|
+
bytesPerRow: this.clustersTextureSize,
|
|
257
|
+
mipLevel: 0,
|
|
258
|
+
x: 0,
|
|
259
|
+
y: 0,
|
|
260
|
+
})
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Update pointIndices buffer if pointsTextureSize changed
|
|
264
|
+
if (!this.pointIndices || this.previousPointsTextureSize !== pointsTextureSize) {
|
|
265
|
+
if (this.pointIndices && !this.pointIndices.destroyed) {
|
|
266
|
+
this.pointIndices.destroy()
|
|
267
|
+
}
|
|
268
|
+
const indexData = createIndexesForBuffer(store.pointsTextureSize)
|
|
269
|
+
this.pointIndices = device.createBuffer({
|
|
270
|
+
data: indexData,
|
|
271
|
+
usage: Buffer.VERTEX | Buffer.COPY_DST,
|
|
272
|
+
})
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Update tracked sizes
|
|
276
|
+
this.previousPointsTextureSize = pointsTextureSize
|
|
277
|
+
this.previousClustersTextureSize = this.clustersTextureSize
|
|
278
|
+
this.previousClusterCount = this.clusterCount
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
public initPrograms (): void {
|
|
282
|
+
const { device, store, data, points } = this
|
|
283
|
+
// Use same check as create() and run() for consistency
|
|
284
|
+
if (!data.pointClusters && !data.clusterPositions) return
|
|
285
|
+
|
|
286
|
+
if (!this.clearCentermassCommand) {
|
|
287
|
+
// Create and track vertexCoord buffer
|
|
288
|
+
if (!this.clearCentermassVertexCoordBuffer) {
|
|
289
|
+
this.clearCentermassVertexCoordBuffer = device.createBuffer({
|
|
290
|
+
data: new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]),
|
|
291
|
+
})
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
this.clearCentermassCommand = new Model(device, {
|
|
295
|
+
fs: clearFrag,
|
|
296
|
+
vs: updateVert,
|
|
297
|
+
topology: 'triangle-strip',
|
|
298
|
+
vertexCount: 4,
|
|
299
|
+
attributes: {
|
|
300
|
+
vertexCoord: this.clearCentermassVertexCoordBuffer,
|
|
301
|
+
},
|
|
302
|
+
bufferLayout: [
|
|
303
|
+
{ name: 'vertexCoord', format: 'float32x2' }, // 2 floats per vertex
|
|
304
|
+
],
|
|
305
|
+
})
|
|
306
|
+
}
|
|
307
|
+
if (!this.calculateCentermassCommand) {
|
|
308
|
+
// Ensure pointIndices buffer exists
|
|
309
|
+
if (!this.pointIndices) {
|
|
310
|
+
const indexData = createIndexesForBuffer(store.pointsTextureSize)
|
|
311
|
+
this.pointIndices = device.createBuffer({
|
|
312
|
+
data: indexData,
|
|
313
|
+
usage: Buffer.VERTEX | Buffer.COPY_DST,
|
|
314
|
+
})
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Create UniformStore for calculateCentermass uniforms
|
|
318
|
+
if (!this.calculateCentermassUniformStore) {
|
|
319
|
+
this.calculateCentermassUniformStore = new UniformStore({
|
|
320
|
+
calculateCentermassUniforms: {
|
|
321
|
+
uniformTypes: {
|
|
322
|
+
pointsTextureSize: 'f32',
|
|
323
|
+
clustersTextureSize: 'f32',
|
|
324
|
+
},
|
|
325
|
+
defaultUniforms: {
|
|
326
|
+
pointsTextureSize: store.pointsTextureSize,
|
|
327
|
+
clustersTextureSize: (this.clustersTextureSize ?? 0),
|
|
328
|
+
},
|
|
329
|
+
},
|
|
330
|
+
})
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
this.calculateCentermassCommand = new Model(device, {
|
|
334
|
+
fs: calculateCentermassFrag,
|
|
335
|
+
vs: calculateCentermassVert,
|
|
336
|
+
topology: 'point-list',
|
|
337
|
+
vertexCount: data.pointsNumber ?? 0,
|
|
338
|
+
attributes: {
|
|
339
|
+
pointIndices: this.pointIndices,
|
|
340
|
+
},
|
|
341
|
+
bufferLayout: [
|
|
342
|
+
{ name: 'pointIndices', format: 'float32x2' }, // 2 floats per vertex
|
|
343
|
+
],
|
|
344
|
+
defines: {
|
|
345
|
+
USE_UNIFORM_BUFFERS: true, // Enable uniform buffers
|
|
346
|
+
},
|
|
347
|
+
bindings: {
|
|
348
|
+
// Uniform buffer via UniformStore (WebGPU-compatible)
|
|
349
|
+
calculateCentermassUniforms: this.calculateCentermassUniformStore.getManagedUniformBuffer(device, 'calculateCentermassUniforms'),
|
|
350
|
+
...(this.clusterTexture && { clusterTexture: this.clusterTexture }),
|
|
351
|
+
...(points?.previousPositionTexture && { positionsTexture: points.previousPositionTexture }),
|
|
352
|
+
},
|
|
353
|
+
parameters: {
|
|
354
|
+
blend: true,
|
|
355
|
+
blendColorOperation: 'add',
|
|
356
|
+
blendColorSrcFactor: 'one',
|
|
357
|
+
blendColorDstFactor: 'one',
|
|
358
|
+
blendAlphaOperation: 'add',
|
|
359
|
+
blendAlphaSrcFactor: 'one',
|
|
360
|
+
blendAlphaDstFactor: 'one',
|
|
361
|
+
depthWriteEnabled: false,
|
|
362
|
+
depthCompare: 'always',
|
|
363
|
+
},
|
|
364
|
+
})
|
|
365
|
+
}
|
|
366
|
+
if (!this.applyForcesCommand) {
|
|
367
|
+
// Create UniformStore for applyForces uniforms
|
|
368
|
+
if (!this.applyForcesUniformStore) {
|
|
369
|
+
this.applyForcesUniformStore = new UniformStore({
|
|
370
|
+
applyForcesUniforms: {
|
|
371
|
+
uniformTypes: {
|
|
372
|
+
alpha: 'f32',
|
|
373
|
+
clustersTextureSize: 'f32',
|
|
374
|
+
clusterCoefficient: 'f32',
|
|
375
|
+
},
|
|
376
|
+
defaultUniforms: {
|
|
377
|
+
alpha: store.alpha,
|
|
378
|
+
clustersTextureSize: (this.clustersTextureSize ?? 0),
|
|
379
|
+
clusterCoefficient: (this.config.simulationCluster ?? 0),
|
|
380
|
+
},
|
|
381
|
+
},
|
|
382
|
+
})
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// Create and track vertexCoord buffer
|
|
386
|
+
if (!this.applyForcesVertexCoordBuffer) {
|
|
387
|
+
this.applyForcesVertexCoordBuffer = device.createBuffer({
|
|
388
|
+
data: new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]),
|
|
389
|
+
})
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
this.applyForcesCommand = new Model(device, {
|
|
393
|
+
fs: forceFrag,
|
|
394
|
+
vs: updateVert,
|
|
395
|
+
topology: 'triangle-strip',
|
|
396
|
+
vertexCount: 4,
|
|
397
|
+
attributes: {
|
|
398
|
+
vertexCoord: this.applyForcesVertexCoordBuffer,
|
|
399
|
+
},
|
|
400
|
+
bufferLayout: [
|
|
401
|
+
{ name: 'vertexCoord', format: 'float32x2' }, // 2 floats per vertex
|
|
402
|
+
],
|
|
403
|
+
defines: {
|
|
404
|
+
USE_UNIFORM_BUFFERS: true, // Enable uniform buffers
|
|
405
|
+
},
|
|
406
|
+
bindings: {
|
|
407
|
+
// Uniform buffer via UniformStore (WebGPU-compatible)
|
|
408
|
+
applyForcesUniforms: this.applyForcesUniformStore.getManagedUniformBuffer(device, 'applyForcesUniforms'),
|
|
409
|
+
...(this.clusterTexture && { clusterTexture: this.clusterTexture }),
|
|
410
|
+
...(this.centermassTexture && { centermassTexture: this.centermassTexture }),
|
|
411
|
+
...(this.clusterPositionsTexture && { clusterPositionsTexture: this.clusterPositionsTexture }),
|
|
412
|
+
...(this.clusterForceCoefficientTexture && { clusterForceCoefficient: this.clusterForceCoefficientTexture }),
|
|
413
|
+
...(points?.previousPositionTexture && { positionsTexture: points.previousPositionTexture }),
|
|
414
|
+
},
|
|
415
|
+
})
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
public calculateCentermass (): void {
|
|
420
|
+
// Add safety check
|
|
421
|
+
if (!this.calculateCentermassCommand || !this.calculateCentermassUniformStore) {
|
|
422
|
+
return
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
if (!this.centermassFbo || this.centermassFbo.destroyed) return
|
|
426
|
+
if (!this.clusterTexture || this.clusterTexture.destroyed) return
|
|
427
|
+
if (!this.points?.previousPositionTexture || this.points.previousPositionTexture.destroyed) return
|
|
428
|
+
|
|
429
|
+
// Update vertex count dynamically (using same fallback logic as initialization)
|
|
430
|
+
this.calculateCentermassCommand.setVertexCount(this.data.pointsNumber ?? 0)
|
|
431
|
+
|
|
432
|
+
// Update UniformStore with current values
|
|
433
|
+
this.calculateCentermassUniformStore.setUniforms({
|
|
434
|
+
calculateCentermassUniforms: {
|
|
435
|
+
pointsTextureSize: this.store.pointsTextureSize,
|
|
436
|
+
clustersTextureSize: (this.clustersTextureSize ?? 0),
|
|
437
|
+
},
|
|
438
|
+
})
|
|
439
|
+
|
|
440
|
+
// Update bindings dynamically
|
|
441
|
+
this.calculateCentermassCommand.setBindings({
|
|
442
|
+
calculateCentermassUniforms: this.calculateCentermassUniformStore.getManagedUniformBuffer(this.device, 'calculateCentermassUniforms'),
|
|
443
|
+
clusterTexture: this.clusterTexture,
|
|
444
|
+
positionsTexture: this.points.previousPositionTexture,
|
|
445
|
+
})
|
|
446
|
+
|
|
447
|
+
// Create a RenderPass for the centermass framebuffer
|
|
448
|
+
const centermassPass = this.device.beginRenderPass({
|
|
449
|
+
framebuffer: this.centermassFbo,
|
|
450
|
+
})
|
|
451
|
+
|
|
452
|
+
this.clearCentermassCommand?.draw(centermassPass)
|
|
453
|
+
this.calculateCentermassCommand.draw(centermassPass)
|
|
454
|
+
|
|
455
|
+
centermassPass.end()
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
public run (renderPass?: RenderPass): void {
|
|
459
|
+
if (!this.data.pointClusters && !this.data.clusterPositions) return
|
|
460
|
+
|
|
461
|
+
// Calculate centermass (creates its own RenderPass - different framebuffer)
|
|
462
|
+
this.calculateCentermass()
|
|
463
|
+
|
|
464
|
+
// Add safety check
|
|
465
|
+
if (!this.applyForcesCommand || !this.applyForcesUniformStore) {
|
|
466
|
+
return
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// Add destroyed checks for resources before use
|
|
470
|
+
if (!this.clusterTexture || this.clusterTexture.destroyed) return
|
|
471
|
+
if (!this.centermassTexture || this.centermassTexture.destroyed) return
|
|
472
|
+
if (!this.clusterPositionsTexture || this.clusterPositionsTexture.destroyed) return
|
|
473
|
+
if (!this.clusterForceCoefficientTexture || this.clusterForceCoefficientTexture.destroyed) return
|
|
474
|
+
if (!this.points?.previousPositionTexture || this.points.previousPositionTexture.destroyed) return
|
|
475
|
+
if (!this.points?.velocityFbo || this.points.velocityFbo.destroyed) return
|
|
476
|
+
|
|
477
|
+
// Update UniformStore with current values
|
|
478
|
+
this.applyForcesUniformStore.setUniforms({
|
|
479
|
+
applyForcesUniforms: {
|
|
480
|
+
alpha: this.store.alpha,
|
|
481
|
+
clustersTextureSize: (this.clustersTextureSize ?? 0),
|
|
482
|
+
clusterCoefficient: this.config.simulationCluster ?? 0,
|
|
483
|
+
},
|
|
484
|
+
})
|
|
485
|
+
|
|
486
|
+
// Update bindings dynamically
|
|
487
|
+
this.applyForcesCommand.setBindings({
|
|
488
|
+
applyForcesUniforms: this.applyForcesUniformStore.getManagedUniformBuffer(this.device, 'applyForcesUniforms'),
|
|
489
|
+
clusterTexture: this.clusterTexture,
|
|
490
|
+
centermassTexture: this.centermassTexture,
|
|
491
|
+
clusterPositionsTexture: this.clusterPositionsTexture,
|
|
492
|
+
clusterForceCoefficient: this.clusterForceCoefficientTexture,
|
|
493
|
+
positionsTexture: this.points.previousPositionTexture,
|
|
494
|
+
})
|
|
495
|
+
|
|
496
|
+
// Use provided render pass or create one if not provided (backward compatibility)
|
|
497
|
+
if (renderPass) {
|
|
498
|
+
// Use the provided render pass (created in simulation loop)
|
|
499
|
+
this.applyForcesCommand.draw(renderPass)
|
|
500
|
+
} else {
|
|
501
|
+
// Create a RenderPass for the velocity framebuffer (fallback for backward compatibility)
|
|
502
|
+
const velocityPass = this.device.beginRenderPass({
|
|
503
|
+
framebuffer: this.points.velocityFbo,
|
|
504
|
+
})
|
|
505
|
+
|
|
506
|
+
this.applyForcesCommand.draw(velocityPass)
|
|
507
|
+
|
|
508
|
+
velocityPass.end()
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
public destroy (): void {
|
|
513
|
+
// Destroy UniformStore
|
|
514
|
+
this.calculateCentermassUniformStore?.destroy()
|
|
515
|
+
this.calculateCentermassUniformStore = undefined
|
|
516
|
+
this.applyForcesUniformStore?.destroy()
|
|
517
|
+
this.applyForcesUniformStore = undefined
|
|
518
|
+
|
|
519
|
+
// Destroy Models
|
|
520
|
+
this.clearCentermassCommand?.destroy()
|
|
521
|
+
this.clearCentermassCommand = undefined
|
|
522
|
+
this.calculateCentermassCommand?.destroy()
|
|
523
|
+
this.calculateCentermassCommand = undefined
|
|
524
|
+
this.applyForcesCommand?.destroy()
|
|
525
|
+
this.applyForcesCommand = undefined
|
|
526
|
+
|
|
527
|
+
// Destroy Framebuffers (destroy before textures they reference)
|
|
528
|
+
if (this.centermassFbo && !this.centermassFbo.destroyed) {
|
|
529
|
+
this.centermassFbo.destroy()
|
|
530
|
+
}
|
|
531
|
+
this.centermassFbo = undefined
|
|
532
|
+
if (this.clusterFbo && !this.clusterFbo.destroyed) {
|
|
533
|
+
this.clusterFbo.destroy()
|
|
534
|
+
}
|
|
535
|
+
this.clusterFbo = undefined
|
|
536
|
+
if (this.clusterPositionsFbo && !this.clusterPositionsFbo.destroyed) {
|
|
537
|
+
this.clusterPositionsFbo.destroy()
|
|
538
|
+
}
|
|
539
|
+
this.clusterPositionsFbo = undefined
|
|
540
|
+
if (this.clusterForceCoefficientFbo && !this.clusterForceCoefficientFbo.destroyed) {
|
|
541
|
+
this.clusterForceCoefficientFbo.destroy()
|
|
542
|
+
}
|
|
543
|
+
this.clusterForceCoefficientFbo = undefined
|
|
544
|
+
|
|
545
|
+
// Destroy Textures
|
|
546
|
+
if (this.clusterTexture && !this.clusterTexture.destroyed) {
|
|
547
|
+
this.clusterTexture.destroy()
|
|
548
|
+
}
|
|
549
|
+
this.clusterTexture = undefined
|
|
550
|
+
if (this.clusterPositionsTexture && !this.clusterPositionsTexture.destroyed) {
|
|
551
|
+
this.clusterPositionsTexture.destroy()
|
|
552
|
+
}
|
|
553
|
+
this.clusterPositionsTexture = undefined
|
|
554
|
+
if (this.clusterForceCoefficientTexture && !this.clusterForceCoefficientTexture.destroyed) {
|
|
555
|
+
this.clusterForceCoefficientTexture.destroy()
|
|
556
|
+
}
|
|
557
|
+
this.clusterForceCoefficientTexture = undefined
|
|
558
|
+
if (this.centermassTexture && !this.centermassTexture.destroyed) {
|
|
559
|
+
this.centermassTexture.destroy()
|
|
560
|
+
}
|
|
561
|
+
this.centermassTexture = undefined
|
|
562
|
+
|
|
563
|
+
// Destroy Buffers
|
|
564
|
+
if (this.pointIndices && !this.pointIndices.destroyed) {
|
|
565
|
+
this.pointIndices.destroy()
|
|
566
|
+
}
|
|
567
|
+
this.pointIndices = undefined
|
|
568
|
+
// Destroy attribute buffers (Model doesn't destroy them automatically)
|
|
569
|
+
if (this.clearCentermassVertexCoordBuffer && !this.clearCentermassVertexCoordBuffer.destroyed) {
|
|
570
|
+
this.clearCentermassVertexCoordBuffer.destroy()
|
|
571
|
+
}
|
|
572
|
+
this.clearCentermassVertexCoordBuffer = undefined
|
|
573
|
+
if (this.applyForcesVertexCoordBuffer && !this.applyForcesVertexCoordBuffer.destroyed) {
|
|
574
|
+
this.applyForcesVertexCoordBuffer.destroy()
|
|
575
|
+
}
|
|
576
|
+
this.applyForcesVertexCoordBuffer = undefined
|
|
577
|
+
}
|
|
578
|
+
}
|