@cosmos.gl/graph 2.3.1-beta.1 → 2.4.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 +61 -0
- package/CHARTER.md +69 -0
- package/GOVERNANCE.md +21 -0
- package/dist/index.d.ts +46 -15
- package/dist/index.js +2986 -2701
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +180 -62
- package/dist/index.min.js.map +1 -1
- package/dist/modules/GraphData/index.d.ts +18 -2
- package/dist/modules/Points/atlas-utils.d.ts +24 -0
- package/dist/modules/Points/index.d.ts +21 -2
- package/dist/modules/Store/index.d.ts +6 -1
- package/dist/stories/create-story.d.ts +5 -1
- package/dist/stories/shapes/image-example/index.d.ts +5 -0
- package/dist/stories/shapes.stories.d.ts +1 -0
- package/package.json +4 -4
- package/src/config.ts +1 -0
- package/src/declaration.d.ts +5 -0
- package/src/index.ts +119 -67
- package/src/modules/GraphData/index.ts +68 -6
- package/src/modules/Points/atlas-utils.ts +137 -0
- package/src/modules/Points/draw-highlighted.vert +3 -3
- package/src/modules/Points/draw-points.frag +106 -14
- package/src/modules/Points/draw-points.vert +51 -25
- package/src/modules/Points/find-points-on-area-selection.frag +6 -5
- package/src/modules/Points/index.ts +121 -13
- package/src/modules/Store/index.ts +11 -3
- package/src/stories/3. api-reference.mdx +48 -1
- package/src/stories/create-story.ts +32 -5
- 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 +239 -0
- package/src/stories/shapes.stories.ts +12 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a texture atlas from an array of ImageData objects.
|
|
3
|
+
*
|
|
4
|
+
* A texture atlas is a single large texture that contains multiple smaller images.
|
|
5
|
+
* This allows efficient rendering by reducing the number of texture bindings needed.
|
|
6
|
+
*
|
|
7
|
+
* The atlas uses a grid layout where each image gets a square region sized to
|
|
8
|
+
* accommodate the largest image dimension. Images are placed left-to-right, top-to-bottom.
|
|
9
|
+
*
|
|
10
|
+
* @param imageDataArray - Array of ImageData objects to pack into the atlas
|
|
11
|
+
* @param webglMaxTextureSize - WebGL maximum texture size limit (default: 16384)
|
|
12
|
+
* @returns Atlas data object containing:
|
|
13
|
+
* - atlasData: RGBA pixel data as Uint8Array
|
|
14
|
+
* - atlasSize: Total atlas texture size in pixels
|
|
15
|
+
* - atlasCoords: UV coordinates for each image as Float32Array
|
|
16
|
+
* - atlasCoordsSize: Grid size (number of rows/columns)
|
|
17
|
+
* Returns null if creation fails or no valid images provided
|
|
18
|
+
*/
|
|
19
|
+
export function createAtlasDataFromImageData (
|
|
20
|
+
imageDataArray: ImageData[],
|
|
21
|
+
webglMaxTextureSize = 16384
|
|
22
|
+
): {
|
|
23
|
+
atlasData: Uint8Array;
|
|
24
|
+
atlasSize: number;
|
|
25
|
+
atlasCoords: Float32Array;
|
|
26
|
+
atlasCoordsSize: number;
|
|
27
|
+
} | null {
|
|
28
|
+
// Step 1: Validate input - ensure we have images to process
|
|
29
|
+
if (!imageDataArray?.length) {
|
|
30
|
+
return null
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Step 2: Find the maximum dimension across all images
|
|
34
|
+
// The max dimension determines the size of each grid cell in the atlas
|
|
35
|
+
let maxDimension = 0
|
|
36
|
+
for (const imageData of imageDataArray) {
|
|
37
|
+
const dimension = Math.max(imageData.width, imageData.height)
|
|
38
|
+
if (dimension > maxDimension) {
|
|
39
|
+
maxDimension = dimension
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Step 3: Validate that we found valid image dimensions
|
|
44
|
+
if (maxDimension === 0) {
|
|
45
|
+
console.warn('Invalid image dimensions: all images have zero width or height')
|
|
46
|
+
return null
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const originalMaxDimension = maxDimension
|
|
50
|
+
|
|
51
|
+
// Step 4: Calculate optimal atlas grid size
|
|
52
|
+
const atlasCoordsSize = Math.ceil(Math.sqrt(imageDataArray.length))
|
|
53
|
+
let atlasSize = atlasCoordsSize * maxDimension
|
|
54
|
+
|
|
55
|
+
// Step 5: Apply WebGL size limit scaling if necessary
|
|
56
|
+
let scalingFactor = 1.0
|
|
57
|
+
|
|
58
|
+
if (atlasSize > webglMaxTextureSize) {
|
|
59
|
+
// Calculate required scale to fit within WebGL limits
|
|
60
|
+
scalingFactor = webglMaxTextureSize / atlasSize
|
|
61
|
+
|
|
62
|
+
// Apply scaling to both the individual image dimensions and atlas size
|
|
63
|
+
maxDimension = Math.max(1, Math.floor(maxDimension * scalingFactor))
|
|
64
|
+
atlasSize = Math.max(1, Math.floor(atlasSize * scalingFactor))
|
|
65
|
+
|
|
66
|
+
console.warn(
|
|
67
|
+
'🖼️ Atlas scaling required: Original size ' +
|
|
68
|
+
`${(originalMaxDimension * atlasCoordsSize).toLocaleString()}px exceeds WebGL limit ` +
|
|
69
|
+
`${webglMaxTextureSize.toLocaleString()}px. Scaling down to ${atlasSize.toLocaleString()}px ` +
|
|
70
|
+
`(${Math.round(scalingFactor * 100)}% of original quality)`
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Step 6: Create buffers for atlas data
|
|
75
|
+
const atlasData = new Uint8Array(atlasSize * atlasSize * 4).fill(0)
|
|
76
|
+
const atlasCoords = new Float32Array(atlasCoordsSize * atlasCoordsSize * 4).fill(-1)
|
|
77
|
+
|
|
78
|
+
// Step 7: Pack each image into the atlas grid
|
|
79
|
+
for (const [index, imageData] of imageDataArray.entries()) {
|
|
80
|
+
const originalWidth = imageData.width
|
|
81
|
+
const originalHeight = imageData.height
|
|
82
|
+
if (originalWidth === 0 || originalHeight === 0) {
|
|
83
|
+
// leave coords at -1 for this index and continue
|
|
84
|
+
continue
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Calculate individual scale for this image based on maxDimension
|
|
88
|
+
// This ensures each image fits optimally within its grid cell
|
|
89
|
+
const individualScale = Math.min(1.0, maxDimension / Math.max(originalWidth, originalHeight))
|
|
90
|
+
|
|
91
|
+
const scaledWidth = Math.floor(originalWidth * individualScale)
|
|
92
|
+
const scaledHeight = Math.floor(originalHeight * individualScale)
|
|
93
|
+
|
|
94
|
+
// Calculate grid position (row, column) for this image
|
|
95
|
+
const row = Math.floor(index / atlasCoordsSize)
|
|
96
|
+
const col = index % atlasCoordsSize
|
|
97
|
+
|
|
98
|
+
// Calculate pixel position in the atlas texture
|
|
99
|
+
const atlasX = col * maxDimension
|
|
100
|
+
const atlasY = row * maxDimension
|
|
101
|
+
|
|
102
|
+
// Calculate and store UV coordinates for this image
|
|
103
|
+
atlasCoords[index * 4] = atlasX / atlasSize // minU
|
|
104
|
+
atlasCoords[index * 4 + 1] = atlasY / atlasSize // minV
|
|
105
|
+
atlasCoords[index * 4 + 2] = (atlasX + scaledWidth) / atlasSize // maxU
|
|
106
|
+
atlasCoords[index * 4 + 3] = (atlasY + scaledHeight) / atlasSize // maxV
|
|
107
|
+
|
|
108
|
+
// Copy image pixel data into the atlas texture
|
|
109
|
+
for (let y = 0; y < scaledHeight; y++) {
|
|
110
|
+
for (let x = 0; x < scaledWidth; x++) {
|
|
111
|
+
// Calculate source pixel coordinates (with scaling)
|
|
112
|
+
const srcX = Math.floor(x * (originalWidth / scaledWidth))
|
|
113
|
+
const srcY = Math.floor(y * (originalHeight / scaledHeight))
|
|
114
|
+
|
|
115
|
+
// Calculate source pixel index in the original image
|
|
116
|
+
const srcIndex = (srcY * originalWidth + srcX) * 4
|
|
117
|
+
|
|
118
|
+
// Calculate target pixel index in the atlas texture
|
|
119
|
+
const atlasIndex = ((atlasY + y) * atlasSize + (atlasX + x)) * 4
|
|
120
|
+
|
|
121
|
+
// Copy RGBA values from source to atlas
|
|
122
|
+
atlasData[atlasIndex] = imageData.data[srcIndex] ?? 0 // Red channel
|
|
123
|
+
atlasData[atlasIndex + 1] = imageData.data[srcIndex + 1] ?? 0 // Green channel
|
|
124
|
+
atlasData[atlasIndex + 2] = imageData.data[srcIndex + 2] ?? 0 // Blue channel
|
|
125
|
+
atlasData[atlasIndex + 3] = imageData.data[srcIndex + 3] ?? 255 // Alpha channel
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Return the complete atlas data
|
|
131
|
+
return {
|
|
132
|
+
atlasData,
|
|
133
|
+
atlasSize,
|
|
134
|
+
atlasCoords,
|
|
135
|
+
atlasCoordsSize,
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -16,7 +16,7 @@ uniform float maxPointSize;
|
|
|
16
16
|
uniform vec4 color;
|
|
17
17
|
uniform float universalPointOpacity;
|
|
18
18
|
uniform float greyoutOpacity;
|
|
19
|
-
uniform bool
|
|
19
|
+
uniform bool isDarkenGreyout;
|
|
20
20
|
uniform vec4 backgroundColor;
|
|
21
21
|
uniform vec4 greyoutColor;
|
|
22
22
|
varying vec2 vertexPosition;
|
|
@@ -49,10 +49,10 @@ void main () {
|
|
|
49
49
|
rgbColor = greyoutColor.rgb;
|
|
50
50
|
pointOpacity = greyoutColor.a;
|
|
51
51
|
} else {
|
|
52
|
-
// If greyoutColor is not set, make color lighter or darker based on
|
|
52
|
+
// If greyoutColor is not set, make color lighter or darker based on isDarkenGreyout
|
|
53
53
|
float blendFactor = 0.65; // Controls how much to modify (0.0 = original, 1.0 = target color)
|
|
54
54
|
|
|
55
|
-
if (
|
|
55
|
+
if (isDarkenGreyout) {
|
|
56
56
|
// Darken the color
|
|
57
57
|
rgbColor = mix(rgbColor, vec3(0.2), blendFactor);
|
|
58
58
|
} else {
|
|
@@ -4,10 +4,20 @@
|
|
|
4
4
|
precision highp float;
|
|
5
5
|
#endif
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
uniform float greyoutOpacity;
|
|
8
|
+
uniform float pointOpacity;
|
|
9
|
+
uniform sampler2D imageAtlasTexture;
|
|
10
|
+
uniform bool isDarkenGreyout;
|
|
11
|
+
uniform vec4 backgroundColor;
|
|
12
|
+
|
|
13
|
+
|
|
10
14
|
varying float pointShape;
|
|
15
|
+
varying float isGreyedOut;
|
|
16
|
+
varying vec4 shapeColor;
|
|
17
|
+
varying vec4 imageAtlasUV;
|
|
18
|
+
varying float shapeSize;
|
|
19
|
+
varying float imageSizeVarying;
|
|
20
|
+
varying float overallSize;
|
|
11
21
|
|
|
12
22
|
// Smoothing controls the smoothness of the point's edge
|
|
13
23
|
const float smoothing = 0.9;
|
|
@@ -21,12 +31,31 @@ const float PENTAGON = 4.0;
|
|
|
21
31
|
const float HEXAGON = 5.0;
|
|
22
32
|
const float STAR = 6.0;
|
|
23
33
|
const float CROSS = 7.0;
|
|
34
|
+
const float NONE = 8.0;
|
|
24
35
|
|
|
25
36
|
// Distance functions for different shapes
|
|
26
37
|
float circleDistance(vec2 p) {
|
|
27
38
|
return dot(p, p);
|
|
28
39
|
}
|
|
29
40
|
|
|
41
|
+
// Function to apply greyout logic to image colors
|
|
42
|
+
vec4 applyGreyoutToImage(vec4 imageColor) {
|
|
43
|
+
vec3 finalColor = imageColor.rgb;
|
|
44
|
+
float finalAlpha = imageColor.a;
|
|
45
|
+
|
|
46
|
+
if (isGreyedOut > 0.0) {
|
|
47
|
+
float blendFactor = 0.65; // Controls how much to modify (0.0 = original, 1.0 = target color)
|
|
48
|
+
|
|
49
|
+
if (isDarkenGreyout) {
|
|
50
|
+
finalColor = mix(finalColor, vec3(0.2), blendFactor);
|
|
51
|
+
} else {
|
|
52
|
+
finalColor = mix(finalColor, max(backgroundColor.rgb, vec3(0.8)), blendFactor);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return vec4(finalColor, finalAlpha);
|
|
57
|
+
}
|
|
58
|
+
|
|
30
59
|
float squareDistance(vec2 p) {
|
|
31
60
|
vec2 d = abs(p) - vec2(0.8);
|
|
32
61
|
return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0);
|
|
@@ -130,22 +159,85 @@ float getShapeDistance(vec2 p, float shape) {
|
|
|
130
159
|
}
|
|
131
160
|
|
|
132
161
|
void main() {
|
|
133
|
-
// Discard the fragment if the point is fully transparent
|
|
134
|
-
if (
|
|
162
|
+
// Discard the fragment if the point is fully transparent and has no image
|
|
163
|
+
if (shapeColor.a == 0.0 && imageAtlasUV.x == -1.0) {
|
|
164
|
+
discard;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Discard the fragment if the point has no shape and no image
|
|
168
|
+
if (pointShape == NONE && imageAtlasUV.x == -1.0) {
|
|
169
|
+
discard;
|
|
170
|
+
}
|
|
135
171
|
|
|
136
172
|
// Calculate coordinates within the point
|
|
137
173
|
vec2 pointCoord = 2.0 * gl_PointCoord - 1.0;
|
|
174
|
+
|
|
175
|
+
vec4 finalShapeColor = vec4(0.0);
|
|
176
|
+
vec4 finalImageColor = vec4(0.0);
|
|
138
177
|
|
|
139
|
-
|
|
140
|
-
if (pointShape
|
|
141
|
-
//
|
|
142
|
-
|
|
143
|
-
|
|
178
|
+
// Handle shape rendering with centering logic
|
|
179
|
+
if (pointShape != NONE) {
|
|
180
|
+
// Calculate shape coordinates with centering
|
|
181
|
+
vec2 shapeCoord = pointCoord;
|
|
182
|
+
if (overallSize > shapeSize && shapeSize > 0.0) {
|
|
183
|
+
// Shape is smaller than overall size, center it
|
|
184
|
+
float scale = shapeSize / overallSize;
|
|
185
|
+
shapeCoord = pointCoord / scale;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
float opacity;
|
|
189
|
+
if (pointShape == CIRCLE) {
|
|
190
|
+
// For circles, use the original distance calculation
|
|
191
|
+
float pointCenterDistance = dot(shapeCoord, shapeCoord);
|
|
192
|
+
opacity = 1.0 - smoothstep(smoothing, 1.0, pointCenterDistance);
|
|
193
|
+
} else {
|
|
194
|
+
// For other shapes, use the shape distance function
|
|
195
|
+
float shapeDistance = getShapeDistance(shapeCoord, pointShape);
|
|
196
|
+
opacity = 1.0 - smoothstep(-0.01, 0.01, shapeDistance);
|
|
197
|
+
}
|
|
198
|
+
opacity *= shapeColor.a;
|
|
199
|
+
|
|
200
|
+
finalShapeColor = vec4(shapeColor.rgb, opacity);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Handle image rendering with centering logic
|
|
204
|
+
if (imageAtlasUV.x != -1.0) {
|
|
205
|
+
// Calculate image coordinates with centering
|
|
206
|
+
vec2 imageCoord = pointCoord;
|
|
207
|
+
if (overallSize > imageSizeVarying && imageSizeVarying > 0.0) {
|
|
208
|
+
// Image is smaller than overall size, center it
|
|
209
|
+
float scale = imageSizeVarying / overallSize;
|
|
210
|
+
imageCoord = pointCoord / scale;
|
|
211
|
+
|
|
212
|
+
// Check if we're outside the valid image area
|
|
213
|
+
if (abs(imageCoord.x) > 1.0 || abs(imageCoord.y) > 1.0) {
|
|
214
|
+
// We're outside the image bounds, don't render the image
|
|
215
|
+
finalImageColor = vec4(0.0);
|
|
216
|
+
} else {
|
|
217
|
+
// Sample from texture atlas
|
|
218
|
+
vec2 atlasUV = mix(imageAtlasUV.xy, imageAtlasUV.zw, (imageCoord + 1.0) * 0.5);
|
|
219
|
+
vec4 imageColor = texture2D(imageAtlasTexture, atlasUV);
|
|
220
|
+
finalImageColor = applyGreyoutToImage(imageColor);
|
|
221
|
+
}
|
|
222
|
+
} else {
|
|
223
|
+
// Image is same size or larger than overall size, no scaling needed
|
|
224
|
+
// Sample from texture atlas
|
|
225
|
+
vec2 atlasUV = mix(imageAtlasUV.xy, imageAtlasUV.zw, (imageCoord + 1.0) * 0.5);
|
|
226
|
+
vec4 imageColor = texture2D(imageAtlasTexture, atlasUV);
|
|
227
|
+
finalImageColor = applyGreyoutToImage(imageColor);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
float finalPointAlpha = max(finalShapeColor.a, finalImageColor.a);
|
|
232
|
+
if (isGreyedOut > 0.0 && greyoutOpacity != -1.0) {
|
|
233
|
+
finalPointAlpha *= greyoutOpacity;
|
|
144
234
|
} else {
|
|
145
|
-
|
|
146
|
-
float shapeDistance = getShapeDistance(pointCoord, pointShape);
|
|
147
|
-
opacity = alpha * (1.0 - smoothstep(-0.01, 0.01, shapeDistance));
|
|
235
|
+
finalPointAlpha *= pointOpacity;
|
|
148
236
|
}
|
|
149
237
|
|
|
150
|
-
|
|
238
|
+
// Blend image color above point color
|
|
239
|
+
gl_FragColor = vec4(
|
|
240
|
+
mix(finalShapeColor.rgb, finalImageColor.rgb, finalImageColor.a),
|
|
241
|
+
finalPointAlpha
|
|
242
|
+
);
|
|
151
243
|
}
|
|
@@ -6,29 +6,37 @@ attribute vec2 pointIndices;
|
|
|
6
6
|
attribute float size;
|
|
7
7
|
attribute vec4 color;
|
|
8
8
|
attribute float shape;
|
|
9
|
+
attribute float imageIndex;
|
|
10
|
+
attribute float imageSize;
|
|
9
11
|
|
|
10
12
|
uniform sampler2D positionsTexture;
|
|
11
13
|
uniform sampler2D pointGreyoutStatus;
|
|
14
|
+
uniform sampler2D imageAtlasCoords;
|
|
12
15
|
uniform float ratio;
|
|
13
16
|
uniform mat3 transformationMatrix;
|
|
14
17
|
uniform float pointsTextureSize;
|
|
15
18
|
uniform float sizeScale;
|
|
16
19
|
uniform float spaceSize;
|
|
17
20
|
uniform vec2 screenSize;
|
|
18
|
-
|
|
19
|
-
uniform float pointOpacity;
|
|
21
|
+
|
|
20
22
|
uniform vec4 greyoutColor;
|
|
21
23
|
uniform vec4 backgroundColor;
|
|
22
24
|
uniform bool scalePointsOnZoom;
|
|
23
25
|
uniform float maxPointSize;
|
|
24
|
-
uniform bool
|
|
26
|
+
uniform bool isDarkenGreyout;
|
|
25
27
|
uniform bool skipSelected;
|
|
26
28
|
uniform bool skipUnselected;
|
|
29
|
+
uniform bool hasImages;
|
|
30
|
+
uniform float imageCount;
|
|
31
|
+
uniform float imageAtlasCoordsTextureSize;
|
|
27
32
|
|
|
28
|
-
varying vec2 textureCoords;
|
|
29
|
-
varying vec3 rgbColor;
|
|
30
|
-
varying float alpha;
|
|
31
33
|
varying float pointShape;
|
|
34
|
+
varying float isGreyedOut;
|
|
35
|
+
varying vec4 shapeColor;
|
|
36
|
+
varying vec4 imageAtlasUV;
|
|
37
|
+
varying float shapeSize;
|
|
38
|
+
varying float imageSizeVarying;
|
|
39
|
+
varying float overallSize;
|
|
32
40
|
|
|
33
41
|
float calculatePointSize(float size) {
|
|
34
42
|
float pSize;
|
|
@@ -41,11 +49,10 @@ float calculatePointSize(float size) {
|
|
|
41
49
|
return min(pSize, maxPointSize * ratio);
|
|
42
50
|
}
|
|
43
51
|
|
|
44
|
-
void main() {
|
|
45
|
-
textureCoords = pointIndices;
|
|
46
|
-
|
|
52
|
+
void main() {
|
|
47
53
|
// Check greyout status for selective rendering
|
|
48
|
-
vec4 greyoutStatus = texture2D(pointGreyoutStatus, (
|
|
54
|
+
vec4 greyoutStatus = texture2D(pointGreyoutStatus, (pointIndices + 0.5) / pointsTextureSize);
|
|
55
|
+
isGreyedOut = greyoutStatus.r;
|
|
49
56
|
bool isSelected = greyoutStatus.r == 0.0;
|
|
50
57
|
|
|
51
58
|
// Discard point based on rendering mode
|
|
@@ -61,7 +68,7 @@ void main() {
|
|
|
61
68
|
}
|
|
62
69
|
|
|
63
70
|
// Position
|
|
64
|
-
vec4 pointPosition = texture2D(positionsTexture, (
|
|
71
|
+
vec4 pointPosition = texture2D(positionsTexture, (pointIndices + 0.5) / pointsTextureSize);
|
|
65
72
|
vec2 point = pointPosition.rg;
|
|
66
73
|
|
|
67
74
|
// Transform point position to normalized device coordinates
|
|
@@ -70,32 +77,51 @@ void main() {
|
|
|
70
77
|
vec3 finalPosition = transformationMatrix * vec3(normalizedPosition, 1);
|
|
71
78
|
gl_Position = vec4(finalPosition.rg, 0, 1);
|
|
72
79
|
|
|
73
|
-
|
|
80
|
+
// Calculate sizes for shape and image
|
|
81
|
+
float shapeSizeValue = calculatePointSize(size * sizeScale);
|
|
82
|
+
float imageSizeValue = calculatePointSize(imageSize * sizeScale);
|
|
83
|
+
|
|
84
|
+
// Use the larger of the two sizes for the overall point size
|
|
85
|
+
float overallSizeValue = max(shapeSizeValue, imageSizeValue);
|
|
86
|
+
gl_PointSize = overallSizeValue;
|
|
87
|
+
|
|
88
|
+
// Pass size information to fragment shader
|
|
89
|
+
shapeSize = shapeSizeValue;
|
|
90
|
+
imageSizeVarying = imageSizeValue;
|
|
91
|
+
overallSize = overallSizeValue;
|
|
74
92
|
|
|
75
|
-
|
|
76
|
-
alpha = color.a * pointOpacity;
|
|
93
|
+
shapeColor = color;
|
|
77
94
|
pointShape = shape;
|
|
78
95
|
|
|
79
96
|
// Adjust alpha of selected points
|
|
80
|
-
if (
|
|
97
|
+
if (isGreyedOut > 0.0) {
|
|
81
98
|
if (greyoutColor[0] != -1.0) {
|
|
82
|
-
|
|
83
|
-
alpha = greyoutColor.a;
|
|
99
|
+
shapeColor = greyoutColor;
|
|
84
100
|
} else {
|
|
85
|
-
// If greyoutColor is not set, make color lighter or darker based on
|
|
101
|
+
// If greyoutColor is not set, make color lighter or darker based on isDarkenGreyout
|
|
86
102
|
float blendFactor = 0.65; // Controls how much to modify (0.0 = original, 1.0 = target color)
|
|
87
103
|
|
|
88
|
-
if (
|
|
104
|
+
if (isDarkenGreyout) {
|
|
89
105
|
// Darken the color
|
|
90
|
-
|
|
106
|
+
shapeColor.rgb = mix(shapeColor.rgb, vec3(0.2), blendFactor);
|
|
91
107
|
} else {
|
|
92
108
|
// Lighten the color
|
|
93
|
-
|
|
109
|
+
shapeColor.rgb = mix(shapeColor.rgb, max(backgroundColor.rgb, vec3(0.8)), blendFactor);
|
|
94
110
|
}
|
|
95
111
|
}
|
|
112
|
+
}
|
|
96
113
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
114
|
+
if (!hasImages || imageIndex < 0.0 || imageIndex >= imageCount) {
|
|
115
|
+
imageAtlasUV = vec4(-1.0);
|
|
116
|
+
return;
|
|
100
117
|
}
|
|
101
|
-
|
|
118
|
+
// Calculate image atlas UV coordinates based on imageIndex
|
|
119
|
+
float atlasCoordIndex = imageIndex;
|
|
120
|
+
// Calculate the position in the texture grid
|
|
121
|
+
float texX = mod(atlasCoordIndex, imageAtlasCoordsTextureSize);
|
|
122
|
+
float texY = floor(atlasCoordIndex / imageAtlasCoordsTextureSize);
|
|
123
|
+
// Convert to texture coordinates (0.0 to 1.0)
|
|
124
|
+
vec2 atlasCoordTexCoord = (vec2(texX, texY) + 0.5) / imageAtlasCoordsTextureSize;
|
|
125
|
+
vec4 atlasCoords = texture2D(imageAtlasCoords, atlasCoordTexCoord);
|
|
126
|
+
imageAtlasUV = atlasCoords;
|
|
127
|
+
}
|
|
@@ -9,7 +9,8 @@ uniform float spaceSize;
|
|
|
9
9
|
uniform vec2 screenSize;
|
|
10
10
|
uniform float ratio;
|
|
11
11
|
uniform mat3 transformationMatrix;
|
|
12
|
-
uniform vec2
|
|
12
|
+
uniform vec2 selection0;
|
|
13
|
+
uniform vec2 selection1;
|
|
13
14
|
uniform bool scalePointsOnZoom;
|
|
14
15
|
uniform float maxPointSize;
|
|
15
16
|
|
|
@@ -34,10 +35,10 @@ void main() {
|
|
|
34
35
|
vec4 pSize = texture2D(pointSize, textureCoords);
|
|
35
36
|
float size = pSize.r * sizeScale;
|
|
36
37
|
|
|
37
|
-
float left = 2.0 * (
|
|
38
|
-
float right = 2.0 * (
|
|
39
|
-
float top = 2.0 * (
|
|
40
|
-
float bottom = 2.0 * (
|
|
38
|
+
float left = 2.0 * (selection0.x - 0.5 * pointSizeF(size)) / screenSize.x - 1.0;
|
|
39
|
+
float right = 2.0 * (selection1.x + 0.5 * pointSizeF(size)) / screenSize.x - 1.0;
|
|
40
|
+
float top = 2.0 * (selection0.y - 0.5 * pointSizeF(size)) / screenSize.y - 1.0;
|
|
41
|
+
float bottom = 2.0 * (selection1.y + 0.5 * pointSizeF(size)) / screenSize.y - 1.0;
|
|
41
42
|
|
|
42
43
|
gl_FragColor = vec4(0.0, 0.0, pointPosition.rg);
|
|
43
44
|
if (final.x >= left && final.x <= right && final.y >= top && final.y <= bottom) {
|