@luma.gl/shadertools 9.3.5 → 9.4.0-alpha.1

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 (113) hide show
  1. package/dist/dist.dev.js +6555 -2373
  2. package/dist/dist.min.js +2984 -237
  3. package/dist/index.cjs +4356 -268
  4. package/dist/index.cjs.map +4 -4
  5. package/dist/index.d.ts +13 -3
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +6 -1
  8. package/dist/index.js.map +1 -1
  9. package/dist/lib/preprocessor/preprocessor.d.ts +11 -1
  10. package/dist/lib/preprocessor/preprocessor.d.ts.map +1 -1
  11. package/dist/lib/preprocessor/preprocessor.js +47 -2
  12. package/dist/lib/preprocessor/preprocessor.js.map +1 -1
  13. package/dist/lib/shader-assembler.d.ts +10 -10
  14. package/dist/lib/shader-assembler.d.ts.map +1 -1
  15. package/dist/lib/shader-assembler.js +36 -20
  16. package/dist/lib/shader-assembler.js.map +1 -1
  17. package/dist/lib/shader-assembly/assemble-shaders.d.ts +28 -7
  18. package/dist/lib/shader-assembly/assemble-shaders.d.ts.map +1 -1
  19. package/dist/lib/shader-assembly/assemble-shaders.js +133 -15
  20. package/dist/lib/shader-assembly/assemble-shaders.js.map +1 -1
  21. package/dist/lib/shader-assembly/platform-info.d.ts +2 -0
  22. package/dist/lib/shader-assembly/platform-info.d.ts.map +1 -1
  23. package/dist/lib/shader-assembly/shader-hooks.d.ts +1 -1
  24. package/dist/lib/shader-assembly/shader-hooks.d.ts.map +1 -1
  25. package/dist/lib/shader-assembly/shader-hooks.js +6 -3
  26. package/dist/lib/shader-assembly/shader-hooks.js.map +1 -1
  27. package/dist/lib/shader-assembly/shader-injections.d.ts +4 -1
  28. package/dist/lib/shader-assembly/shader-injections.d.ts.map +1 -1
  29. package/dist/lib/shader-assembly/shader-injections.js +68 -11
  30. package/dist/lib/shader-assembly/shader-injections.js.map +1 -1
  31. package/dist/lib/shader-assembly/shader-plugin-varyings.d.ts +15 -0
  32. package/dist/lib/shader-assembly/shader-plugin-varyings.d.ts.map +1 -0
  33. package/dist/lib/shader-assembly/shader-plugin-varyings.js +412 -0
  34. package/dist/lib/shader-assembly/shader-plugin-varyings.js.map +1 -0
  35. package/dist/lib/shader-assembly/shader-plugin-vertex-inputs.d.ts +12 -0
  36. package/dist/lib/shader-assembly/shader-plugin-vertex-inputs.d.ts.map +1 -0
  37. package/dist/lib/shader-assembly/shader-plugin-vertex-inputs.js +237 -0
  38. package/dist/lib/shader-assembly/shader-plugin-vertex-inputs.js.map +1 -0
  39. package/dist/lib/shader-module/shader-module.d.ts +3 -0
  40. package/dist/lib/shader-module/shader-module.d.ts.map +1 -1
  41. package/dist/lib/shader-module/shader-module.js.map +1 -1
  42. package/dist/lib/shader-module/shader-pass-pipeline.d.ts +14 -0
  43. package/dist/lib/shader-module/shader-pass-pipeline.d.ts.map +1 -0
  44. package/dist/lib/shader-module/shader-pass-pipeline.js +5 -0
  45. package/dist/lib/shader-module/shader-pass-pipeline.js.map +1 -0
  46. package/dist/lib/shader-module/shader-pass.d.ts +21 -4
  47. package/dist/lib/shader-module/shader-pass.d.ts.map +1 -1
  48. package/dist/lib/shader-plugin.d.ts +68 -0
  49. package/dist/lib/shader-plugin.d.ts.map +1 -0
  50. package/dist/lib/shader-plugin.js +98 -0
  51. package/dist/lib/shader-plugin.js.map +1 -0
  52. package/dist/lib/utils/assert.js +1 -1
  53. package/dist/lib/utils/assert.js.map +1 -1
  54. package/dist/modules/color/float-colors.d.ts +111 -5
  55. package/dist/modules/color/float-colors.d.ts.map +1 -1
  56. package/dist/modules/color/float-colors.js +200 -34
  57. package/dist/modules/color/float-colors.js.map +1 -1
  58. package/dist/modules/engine/clip/clip.d.ts +12 -0
  59. package/dist/modules/engine/clip/clip.d.ts.map +1 -0
  60. package/dist/modules/engine/clip/clip.js +129 -0
  61. package/dist/modules/engine/clip/clip.js.map +1 -0
  62. package/dist/modules/engine/filter/filter.d.ts +12 -0
  63. package/dist/modules/engine/filter/filter.d.ts.map +1 -0
  64. package/dist/modules/engine/filter/filter.js +88 -0
  65. package/dist/modules/engine/filter/filter.js.map +1 -0
  66. package/dist/modules/geospatial/dggs/dggs-wgsl.d.ts +3 -0
  67. package/dist/modules/geospatial/dggs/dggs-wgsl.d.ts.map +1 -0
  68. package/dist/modules/geospatial/dggs/dggs-wgsl.js +1892 -0
  69. package/dist/modules/geospatial/dggs/dggs-wgsl.js.map +1 -0
  70. package/dist/modules/geospatial/dggs/dggs.d.ts +6 -0
  71. package/dist/modules/geospatial/dggs/dggs.d.ts.map +1 -0
  72. package/dist/modules/geospatial/dggs/dggs.js +10 -0
  73. package/dist/modules/geospatial/dggs/dggs.js.map +1 -0
  74. package/dist/modules/lighting/water-material/water-material.d.ts +28 -0
  75. package/dist/modules/lighting/water-material/water-material.d.ts.map +1 -0
  76. package/dist/modules/lighting/water-material/water-material.js +179 -0
  77. package/dist/modules/lighting/water-material/water-material.js.map +1 -0
  78. package/dist/modules/lighting/water-material/water-shaders-glsl.d.ts +3 -0
  79. package/dist/modules/lighting/water-material/water-shaders-glsl.d.ts.map +1 -0
  80. package/dist/modules/lighting/water-material/water-shaders-glsl.js +232 -0
  81. package/dist/modules/lighting/water-material/water-shaders-glsl.js.map +1 -0
  82. package/dist/modules/lighting/water-material/water-shaders-wgsl.d.ts +2 -0
  83. package/dist/modules/lighting/water-material/water-shaders-wgsl.d.ts.map +1 -0
  84. package/dist/modules/lighting/water-material/water-shaders-wgsl.js +230 -0
  85. package/dist/modules/lighting/water-material/water-shaders-wgsl.js.map +1 -0
  86. package/dist/modules/math/fp64/fp64-arithmetic-wgsl.d.ts +2 -1
  87. package/dist/modules/math/fp64/fp64-arithmetic-wgsl.d.ts.map +1 -1
  88. package/dist/modules/math/fp64/fp64-arithmetic-wgsl.js +268 -0
  89. package/dist/modules/math/fp64/fp64-arithmetic-wgsl.js.map +1 -1
  90. package/package.json +2 -2
  91. package/src/index.ts +50 -3
  92. package/src/lib/preprocessor/preprocessor.ts +68 -3
  93. package/src/lib/shader-assembler.ts +49 -20
  94. package/src/lib/shader-assembly/assemble-shaders.ts +242 -30
  95. package/src/lib/shader-assembly/platform-info.ts +2 -0
  96. package/src/lib/shader-assembly/shader-hooks.ts +7 -3
  97. package/src/lib/shader-assembly/shader-injections.ts +96 -11
  98. package/src/lib/shader-assembly/shader-plugin-varyings.ts +524 -0
  99. package/src/lib/shader-assembly/shader-plugin-vertex-inputs.ts +279 -0
  100. package/src/lib/shader-module/shader-module.ts +3 -0
  101. package/src/lib/shader-module/shader-pass-pipeline.ts +19 -0
  102. package/src/lib/shader-module/shader-pass.ts +29 -4
  103. package/src/lib/shader-plugin.ts +214 -0
  104. package/src/lib/utils/assert.ts +1 -1
  105. package/src/modules/color/float-colors.ts +272 -37
  106. package/src/modules/engine/clip/clip.ts +149 -0
  107. package/src/modules/engine/filter/filter.ts +107 -0
  108. package/src/modules/geospatial/dggs/dggs-wgsl.ts +1892 -0
  109. package/src/modules/geospatial/dggs/dggs.ts +12 -0
  110. package/src/modules/lighting/water-material/water-material.ts +234 -0
  111. package/src/modules/lighting/water-material/water-shaders-glsl.ts +233 -0
  112. package/src/modules/lighting/water-material/water-shaders-wgsl.ts +230 -0
  113. package/src/modules/math/fp64/fp64-arithmetic-wgsl.ts +268 -0
@@ -2,9 +2,11 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
+ import type {Binding} from '@luma.gl/core';
5
6
  import {ShaderModule} from '../../lib/shader-module/shader-module';
6
7
 
7
- export type FloatColorsProps = {
8
+ /** Props for semantic color normalization helpers. */
9
+ export type ColorsProps = {
8
10
  /**
9
11
  * When true, semantic colors are interpreted as 0-255 byte-style values and normalized in shader code.
10
12
  * When false, semantic colors are interpreted directly as floats.
@@ -12,61 +14,214 @@ export type FloatColorsProps = {
12
14
  useByteColors?: boolean;
13
15
  };
14
16
 
15
- export type FloatColorsUniforms = {
17
+ /** Uniforms consumed by semantic color normalization helpers. */
18
+ export type ColorsUniforms = {
16
19
  /** Controls whether shader helpers normalize semantic colors from byte space. */
17
20
  useByteColors: boolean;
18
21
  };
19
22
 
20
- const GLSL_UNIFORMS = /* glsl */ `\
21
- layout(std140) uniform floatColorsUniforms {
23
+ /** Backward-compatible props alias for shaders that import `floatColors`. */
24
+ export type FloatColorsProps = ColorsProps;
25
+ /** Backward-compatible uniform alias for shaders that import `floatColors`. */
26
+ export type FloatColorsUniforms = ColorsUniforms;
27
+
28
+ /** Packed storage color formats decoded by `storageColors`. */
29
+ export type StorageColorFormat = 'rgba8unorm' | 'rgba16float' | 'rgba32float';
30
+
31
+ /** Numeric WGSL tags written to `storageColors.format`. */
32
+ export const STORAGE_COLOR_FORMAT = {
33
+ RGBA8UNORM: 0,
34
+ RGBA16FLOAT: 1,
35
+ RGBA32FLOAT: 2
36
+ } as const;
37
+
38
+ /** Numeric WGSL tag for one packed storage color format. */
39
+ export type StorageColorFormatValue =
40
+ (typeof STORAGE_COLOR_FORMAT)[keyof typeof STORAGE_COLOR_FORMAT];
41
+
42
+ /** Bytes occupied by one tightly packed storage color row. */
43
+ export const STORAGE_COLOR_FORMAT_BYTE_LENGTHS: Record<StorageColorFormat, number> = {
44
+ rgba8unorm: 4,
45
+ rgba16float: 8,
46
+ rgba32float: 16
47
+ };
48
+
49
+ /** Default byte stride for one tightly packed storage color row. */
50
+ export const STORAGE_COLOR_DEFAULT_BYTE_STRIDES: Record<StorageColorFormat, number> = {
51
+ ...STORAGE_COLOR_FORMAT_BYTE_LENGTHS
52
+ };
53
+
54
+ /** Props for reading packed color rows from a read-only storage buffer. */
55
+ export type StorageColorsProps = {
56
+ /** Storage buffer containing raw packed color words. */
57
+ colorBuffer?: Binding;
58
+ /** Per-row storage color representation. Defaults to `rgba8unorm`. */
59
+ format?: StorageColorFormat | StorageColorFormatValue;
60
+ /** Byte offset to the first color. Must be 4-byte aligned. Defaults to `0`. */
61
+ byteOffset?: number;
62
+ /** Bytes between color rows. Must be 4-byte aligned. Defaults to the packed format size. */
63
+ byteStride?: number;
64
+ };
65
+
66
+ /** Uniforms consumed by the packed storage color reader. */
67
+ export type StorageColorsUniforms = {
68
+ /** Numeric `STORAGE_COLOR_FORMAT` tag used by WGSL. */
69
+ format: StorageColorFormatValue;
70
+ /** Uint32 words between storage color rows. */
71
+ wordStride: number;
72
+ /** Uint32 word offset to the first storage color row. */
73
+ wordOffset: number;
74
+ /** Reserved field retaining a 16-byte uniform block. */
75
+ _padding: number;
76
+ };
77
+
78
+ /** Bindings consumed by the packed storage color reader. */
79
+ export type StorageColorsBindings = {
80
+ /** Raw packed storage color buffer exposed as `array<u32>`. */
81
+ storageColorsBuffer?: Binding;
82
+ };
83
+
84
+ const STORAGE_COLOR_FORMAT_BY_NAME: Record<StorageColorFormat, StorageColorFormatValue> = {
85
+ rgba8unorm: STORAGE_COLOR_FORMAT.RGBA8UNORM,
86
+ rgba16float: STORAGE_COLOR_FORMAT.RGBA16FLOAT,
87
+ rgba32float: STORAGE_COLOR_FORMAT.RGBA32FLOAT
88
+ };
89
+
90
+ const STORAGE_COLOR_FORMAT_NAME_BY_VALUE: Record<StorageColorFormatValue, StorageColorFormat> = {
91
+ [STORAGE_COLOR_FORMAT.RGBA8UNORM]: 'rgba8unorm',
92
+ [STORAGE_COLOR_FORMAT.RGBA16FLOAT]: 'rgba16float',
93
+ [STORAGE_COLOR_FORMAT.RGBA32FLOAT]: 'rgba32float'
94
+ };
95
+
96
+ const COLORS_UNIFORM_TYPES = {
97
+ useByteColors: 'f32'
98
+ } as const;
99
+
100
+ const COLORS_DEFAULT_UNIFORMS = {
101
+ useByteColors: true
102
+ } as const;
103
+
104
+ const STORAGE_COLORS_UNIFORM_TYPES = {
105
+ format: 'u32',
106
+ wordStride: 'u32',
107
+ wordOffset: 'u32',
108
+ _padding: 'u32'
109
+ } as const;
110
+
111
+ const STORAGE_COLORS_DEFAULT_UNIFORMS = {
112
+ format: STORAGE_COLOR_FORMAT.RGBA8UNORM,
113
+ wordStride: STORAGE_COLOR_DEFAULT_BYTE_STRIDES.rgba8unorm / Uint32Array.BYTES_PER_ELEMENT,
114
+ wordOffset: 0,
115
+ _padding: 0
116
+ } as const satisfies StorageColorsUniforms;
117
+
118
+ const COLORS_GLSL = buildGLSLColorModuleSource('colors');
119
+ const FLOAT_COLORS_GLSL = buildGLSLColorModuleSource('floatColors');
120
+ const COLORS_WGSL = buildWGSLColorModuleSource('colors');
121
+ const FLOAT_COLORS_WGSL = buildWGSLColorModuleSource('floatColors');
122
+
123
+ const STORAGE_COLORS_WGSL = /* wgsl */ `\
124
+ struct storageColorsUniforms {
125
+ format: u32,
126
+ wordStride: u32,
127
+ wordOffset: u32,
128
+ _padding: u32
129
+ };
130
+
131
+ @group(0) @binding(auto) var<uniform> storageColors : storageColorsUniforms;
132
+ @group(0) @binding(auto) var<storage, read> storageColorsBuffer : array<u32>;
133
+
134
+ const STORAGE_COLOR_FORMAT_RGBA8UNORM : u32 = ${STORAGE_COLOR_FORMAT.RGBA8UNORM}u;
135
+ const STORAGE_COLOR_FORMAT_RGBA16FLOAT : u32 = ${STORAGE_COLOR_FORMAT.RGBA16FLOAT}u;
136
+
137
+ fn storageColors_getWordIndex(rowIndex: u32) -> u32 {
138
+ return storageColors.wordOffset + rowIndex * storageColors.wordStride;
139
+ }
140
+
141
+ fn storageColors_readRgba8UnormColor(wordIndex: u32) -> vec4<f32> {
142
+ return unpack4x8unorm(storageColorsBuffer[wordIndex]);
143
+ }
144
+
145
+ fn storageColors_readRgba16FloatColor(wordIndex: u32) -> vec4<f32> {
146
+ let redGreen = unpack2x16float(storageColorsBuffer[wordIndex]);
147
+ let blueAlpha = unpack2x16float(storageColorsBuffer[wordIndex + 1u]);
148
+ return vec4<f32>(redGreen.x, redGreen.y, blueAlpha.x, blueAlpha.y);
149
+ }
150
+
151
+ fn storageColors_readRgba32FloatColor(wordIndex: u32) -> vec4<f32> {
152
+ return vec4<f32>(
153
+ bitcast<f32>(storageColorsBuffer[wordIndex]),
154
+ bitcast<f32>(storageColorsBuffer[wordIndex + 1u]),
155
+ bitcast<f32>(storageColorsBuffer[wordIndex + 2u]),
156
+ bitcast<f32>(storageColorsBuffer[wordIndex + 3u])
157
+ );
158
+ }
159
+
160
+ fn storageColors_readColor(rowIndex: u32) -> vec4<f32> {
161
+ let wordIndex = storageColors_getWordIndex(rowIndex);
162
+ if (storageColors.format == STORAGE_COLOR_FORMAT_RGBA8UNORM) {
163
+ return storageColors_readRgba8UnormColor(wordIndex);
164
+ }
165
+ if (storageColors.format == STORAGE_COLOR_FORMAT_RGBA16FLOAT) {
166
+ return storageColors_readRgba16FloatColor(wordIndex);
167
+ }
168
+ return storageColors_readRgba32FloatColor(wordIndex);
169
+ }
170
+ `;
171
+
172
+ function buildGLSLColorModuleSource(primaryPrefix: string): string {
173
+ return /* glsl */ `\
174
+ layout(std140) uniform ${primaryPrefix}Uniforms {
22
175
  float useByteColors;
23
- } floatColors;
176
+ } ${primaryPrefix};
24
177
 
25
- vec3 floatColors_normalize(vec3 inputColor) {
26
- return floatColors.useByteColors > 0.5 ? inputColor / 255.0 : inputColor;
178
+ vec3 ${primaryPrefix}_normalize(vec3 inputColor) {
179
+ return ${primaryPrefix}.useByteColors > 0.5 ? inputColor / 255.0 : inputColor;
27
180
  }
28
181
 
29
- vec4 floatColors_normalize(vec4 inputColor) {
30
- return floatColors.useByteColors > 0.5 ? inputColor / 255.0 : inputColor;
182
+ vec4 ${primaryPrefix}_normalize(vec4 inputColor) {
183
+ return ${primaryPrefix}.useByteColors > 0.5 ? inputColor / 255.0 : inputColor;
31
184
  }
32
185
 
33
- vec4 floatColors_premultiplyAlpha(vec4 inputColor) {
186
+ vec4 ${primaryPrefix}_premultiplyAlpha(vec4 inputColor) {
34
187
  return vec4(inputColor.rgb * inputColor.a, inputColor.a);
35
188
  }
36
189
 
37
- vec4 floatColors_unpremultiplyAlpha(vec4 inputColor) {
190
+ vec4 ${primaryPrefix}_unpremultiplyAlpha(vec4 inputColor) {
38
191
  return inputColor.a > 0.0 ? vec4(inputColor.rgb / inputColor.a, inputColor.a) : vec4(0.0);
39
192
  }
40
193
 
41
- vec4 floatColors_premultiply_alpha(vec4 inputColor) {
42
- return floatColors_premultiplyAlpha(inputColor);
194
+ vec4 ${primaryPrefix}_premultiply_alpha(vec4 inputColor) {
195
+ return ${primaryPrefix}_premultiplyAlpha(inputColor);
43
196
  }
44
197
 
45
- vec4 floatColors_unpremultiply_alpha(vec4 inputColor) {
46
- return floatColors_unpremultiplyAlpha(inputColor);
198
+ vec4 ${primaryPrefix}_unpremultiply_alpha(vec4 inputColor) {
199
+ return ${primaryPrefix}_unpremultiplyAlpha(inputColor);
47
200
  }
48
201
  `;
202
+ }
49
203
 
50
- const WGSL_UNIFORMS = /* wgsl */ `\
51
- struct floatColorsUniforms {
204
+ function buildWGSLColorModuleSource(primaryPrefix: string): string {
205
+ return /* wgsl */ `\
206
+ struct ${primaryPrefix}Uniforms {
52
207
  useByteColors: f32
53
208
  };
54
209
 
55
- @group(0) @binding(auto) var<uniform> floatColors : floatColorsUniforms;
210
+ @group(0) @binding(auto) var<uniform> ${primaryPrefix} : ${primaryPrefix}Uniforms;
56
211
 
57
- fn floatColors_normalize(inputColor: vec3<f32>) -> vec3<f32> {
58
- return select(inputColor, inputColor / 255.0, floatColors.useByteColors > 0.5);
212
+ fn ${primaryPrefix}_normalize(inputColor: vec3<f32>) -> vec3<f32> {
213
+ return select(inputColor, inputColor / 255.0, ${primaryPrefix}.useByteColors > 0.5);
59
214
  }
60
215
 
61
- fn floatColors_normalize4(inputColor: vec4<f32>) -> vec4<f32> {
62
- return select(inputColor, inputColor / 255.0, floatColors.useByteColors > 0.5);
216
+ fn ${primaryPrefix}_normalize4(inputColor: vec4<f32>) -> vec4<f32> {
217
+ return select(inputColor, inputColor / 255.0, ${primaryPrefix}.useByteColors > 0.5);
63
218
  }
64
219
 
65
- fn floatColors_premultiplyAlpha(inputColor: vec4<f32>) -> vec4<f32> {
220
+ fn ${primaryPrefix}_premultiplyAlpha(inputColor: vec4<f32>) -> vec4<f32> {
66
221
  return vec4<f32>(inputColor.rgb * inputColor.a, inputColor.a);
67
222
  }
68
223
 
69
- fn floatColors_unpremultiplyAlpha(inputColor: vec4<f32>) -> vec4<f32> {
224
+ fn ${primaryPrefix}_unpremultiplyAlpha(inputColor: vec4<f32>) -> vec4<f32> {
70
225
  return select(
71
226
  vec4<f32>(0.0),
72
227
  vec4<f32>(inputColor.rgb / inputColor.a, inputColor.a),
@@ -74,26 +229,106 @@ fn floatColors_unpremultiplyAlpha(inputColor: vec4<f32>) -> vec4<f32> {
74
229
  );
75
230
  }
76
231
 
77
- fn floatColors_premultiply_alpha(inputColor: vec4<f32>) -> vec4<f32> {
78
- return floatColors_premultiplyAlpha(inputColor);
232
+ fn ${primaryPrefix}_premultiply_alpha(inputColor: vec4<f32>) -> vec4<f32> {
233
+ return ${primaryPrefix}_premultiplyAlpha(inputColor);
79
234
  }
80
235
 
81
- fn floatColors_unpremultiply_alpha(inputColor: vec4<f32>) -> vec4<f32> {
82
- return floatColors_unpremultiplyAlpha(inputColor);
236
+ fn ${primaryPrefix}_unpremultiply_alpha(inputColor: vec4<f32>) -> vec4<f32> {
237
+ return ${primaryPrefix}_unpremultiplyAlpha(inputColor);
83
238
  }
84
239
  `;
240
+ }
241
+
242
+ function getStorageColorsUniforms(props: StorageColorsProps = {}): StorageColorsUniforms {
243
+ const format = resolveStorageColorFormat(props.format);
244
+ const formatName = STORAGE_COLOR_FORMAT_NAME_BY_VALUE[format];
245
+ const byteStride = props.byteStride ?? STORAGE_COLOR_DEFAULT_BYTE_STRIDES[formatName];
246
+ const byteOffset = props.byteOffset ?? 0;
247
+ const minimumByteStride = STORAGE_COLOR_FORMAT_BYTE_LENGTHS[formatName];
248
+
249
+ validateStorageColorByteAlignment('byteStride', byteStride);
250
+ validateStorageColorByteAlignment('byteOffset', byteOffset);
251
+ if (byteStride < minimumByteStride) {
252
+ throw new Error(
253
+ `storageColors byteStride must be at least ${minimumByteStride} for ${formatName}`
254
+ );
255
+ }
256
+
257
+ return {
258
+ format,
259
+ wordStride: byteStride / Uint32Array.BYTES_PER_ELEMENT,
260
+ wordOffset: byteOffset / Uint32Array.BYTES_PER_ELEMENT,
261
+ _padding: 0
262
+ };
263
+ }
264
+
265
+ function resolveStorageColorFormat(
266
+ format: StorageColorsProps['format'] = 'rgba8unorm'
267
+ ): StorageColorFormatValue {
268
+ if (typeof format === 'number') {
269
+ if (format in STORAGE_COLOR_FORMAT_NAME_BY_VALUE) {
270
+ return format as StorageColorFormatValue;
271
+ }
272
+ } else if (format in STORAGE_COLOR_FORMAT_BY_NAME) {
273
+ return STORAGE_COLOR_FORMAT_BY_NAME[format];
274
+ }
275
+
276
+ throw new Error(
277
+ `storageColors format must be one of ${Object.keys(STORAGE_COLOR_FORMAT_BY_NAME).join(', ')}`
278
+ );
279
+ }
85
280
 
281
+ function validateStorageColorByteAlignment(name: string, value: number): void {
282
+ if (!Number.isInteger(value) || value < 0 || value % Uint32Array.BYTES_PER_ELEMENT !== 0) {
283
+ throw new Error(`storageColors ${name} must be a non-negative 4-byte aligned integer`);
284
+ }
285
+ }
286
+
287
+ /** Semantic color normalization helpers named `colors_*`. */
288
+ export const colors = {
289
+ name: 'colors',
290
+ props: {} as ColorsProps,
291
+ uniforms: {} as ColorsUniforms,
292
+ vs: COLORS_GLSL,
293
+ fs: COLORS_GLSL,
294
+ source: COLORS_WGSL,
295
+ uniformTypes: COLORS_UNIFORM_TYPES,
296
+ defaultUniforms: COLORS_DEFAULT_UNIFORMS
297
+ } as const satisfies ShaderModule<ColorsProps, ColorsUniforms>;
298
+
299
+ /** Legacy semantic color normalization helpers named `floatColors_*`. */
86
300
  export const floatColors = {
87
301
  name: 'floatColors',
88
302
  props: {} as FloatColorsProps,
89
303
  uniforms: {} as FloatColorsUniforms,
90
- vs: GLSL_UNIFORMS,
91
- fs: GLSL_UNIFORMS,
92
- source: WGSL_UNIFORMS,
93
- uniformTypes: {
94
- useByteColors: 'f32'
95
- },
96
- defaultUniforms: {
97
- useByteColors: true
98
- }
304
+ vs: FLOAT_COLORS_GLSL,
305
+ fs: FLOAT_COLORS_GLSL,
306
+ source: FLOAT_COLORS_WGSL,
307
+ uniformTypes: COLORS_UNIFORM_TYPES,
308
+ defaultUniforms: COLORS_DEFAULT_UNIFORMS
99
309
  } as const satisfies ShaderModule<FloatColorsProps, FloatColorsUniforms>;
310
+
311
+ /**
312
+ * WGSL reader for packed RGBA storage rows.
313
+ *
314
+ * Include {@link colors} separately when semantic color normalization helpers are also needed.
315
+ */
316
+ export const storageColors = {
317
+ name: 'storageColors',
318
+ props: {} as StorageColorsProps,
319
+ uniforms: {} as StorageColorsUniforms,
320
+ bindings: {} as StorageColorsBindings,
321
+ source: STORAGE_COLORS_WGSL,
322
+ uniformTypes: STORAGE_COLORS_UNIFORM_TYPES,
323
+ defaultUniforms: STORAGE_COLORS_DEFAULT_UNIFORMS,
324
+ bindingLayout: [
325
+ {name: 'storageColors', group: 0},
326
+ {name: 'storageColorsBuffer', group: 0}
327
+ ],
328
+ getUniforms(props: StorageColorsProps = {}) {
329
+ return {
330
+ ...getStorageColorsUniforms(props),
331
+ ...(props.colorBuffer ? {storageColorsBuffer: props.colorBuffer} : {})
332
+ };
333
+ }
334
+ } as const satisfies ShaderModule<StorageColorsProps, StorageColorsUniforms, StorageColorsBindings>;
@@ -0,0 +1,149 @@
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import type {ShaderModule} from '../../../lib/shader-module/shader-module';
6
+ import type {ShaderPlugin} from '../../../lib/shader-plugin';
7
+
8
+ export type ClipShaderPluginProps = {
9
+ /** Enables clipping. Defaults to true. */
10
+ enabled?: boolean;
11
+ /** Inclusive lower and exclusive upper bounds. Defaults to [0, 0, 1, 1]. */
12
+ bounds?: readonly [number, number, number, number];
13
+ /** Clips whole instances by their anchor or individual fragments. Defaults to geometry. */
14
+ mode?: 'instance' | 'geometry';
15
+ };
16
+
17
+ type ClipUniforms = {
18
+ enabled: number;
19
+ mode: number;
20
+ bounds: readonly [number, number, number, number];
21
+ };
22
+
23
+ const CLIP_MODE_GEOMETRY = 0;
24
+ const CLIP_MODE_INSTANCE = 1;
25
+
26
+ const clipShaderModule = {
27
+ name: 'clip',
28
+ props: {} as ClipShaderPluginProps,
29
+ uniforms: {} as ClipUniforms,
30
+ bindingLayout: [{name: 'clip', group: 2}],
31
+ uniformTypes: {
32
+ enabled: 'i32',
33
+ mode: 'i32',
34
+ bounds: 'vec4<f32>'
35
+ },
36
+ defaultUniforms: {
37
+ enabled: 1,
38
+ mode: CLIP_MODE_GEOMETRY,
39
+ bounds: [0, 0, 1, 1]
40
+ },
41
+ vs: /* glsl */ `\
42
+ layout(std140) uniform clipUniforms {
43
+ highp int enabled;
44
+ highp int mode;
45
+ highp vec4 bounds;
46
+ } clipState;
47
+
48
+ bool clip_isInBounds(vec2 coordinates) {
49
+ return coordinates.x >= clipState.bounds.x &&
50
+ coordinates.y >= clipState.bounds.y &&
51
+ coordinates.x < clipState.bounds.z &&
52
+ coordinates.y < clipState.bounds.w;
53
+ }
54
+ `,
55
+ fs: /* glsl */ `\
56
+ layout(std140) uniform clipUniforms {
57
+ highp int enabled;
58
+ highp int mode;
59
+ highp vec4 bounds;
60
+ } clipState;
61
+
62
+ bool clip_isInBounds(vec2 coordinates) {
63
+ return coordinates.x >= clipState.bounds.x &&
64
+ coordinates.y >= clipState.bounds.y &&
65
+ coordinates.x < clipState.bounds.z &&
66
+ coordinates.y < clipState.bounds.w;
67
+ }
68
+ `,
69
+ source: /* wgsl */ `\
70
+ struct ClipUniforms {
71
+ enabled: i32,
72
+ mode: i32,
73
+ bounds: vec4<f32>,
74
+ };
75
+
76
+ @group(2) @binding(auto) var<uniform> clipUniforms: ClipUniforms;
77
+
78
+ fn clip_isInBounds(coordinates: vec2<f32>) -> bool {
79
+ return coordinates.x >= clipUniforms.bounds.x &&
80
+ coordinates.y >= clipUniforms.bounds.y &&
81
+ coordinates.x < clipUniforms.bounds.z &&
82
+ coordinates.y < clipUniforms.bounds.w;
83
+ }
84
+ `,
85
+ getUniforms(props: ClipShaderPluginProps = {}): Partial<ClipUniforms> {
86
+ const uniforms: Partial<ClipUniforms> = {};
87
+ if (props.enabled !== undefined) {
88
+ uniforms.enabled = Number(props.enabled);
89
+ }
90
+ if (props.mode !== undefined) {
91
+ uniforms.mode = props.mode === 'instance' ? CLIP_MODE_INSTANCE : CLIP_MODE_GEOMETRY;
92
+ }
93
+ if (props.bounds !== undefined) {
94
+ uniforms.bounds = props.bounds;
95
+ }
96
+ return uniforms;
97
+ }
98
+ } as const satisfies ShaderModule<ClipShaderPluginProps, ClipUniforms, {}>;
99
+
100
+ /** Coordinate-system-neutral instance and geometry clipping. */
101
+ export const clipShaderPlugin: ShaderPlugin = {
102
+ name: 'clip',
103
+ modules: [clipShaderModule],
104
+ varyings: {
105
+ clipCoordinates: {type: 'vec2<f32>', interpolation: 'smooth'}
106
+ },
107
+ glsl: {
108
+ injections: [
109
+ {
110
+ target: 'vs:CLIP_POSITION',
111
+ injection: `\
112
+ clipCoordinates = geometryCoordinates;
113
+ if (clipState.enabled != 0 && clipState.mode == ${CLIP_MODE_INSTANCE} &&
114
+ !clip_isInBounds(instanceCoordinates)) {
115
+ position = vec4(2.0, 2.0, 2.0, 1.0);
116
+ }`
117
+ },
118
+ {
119
+ target: 'fs:CLIP_COLOR',
120
+ injection: `\
121
+ if (clipState.enabled != 0 && clipState.mode == ${CLIP_MODE_GEOMETRY} &&
122
+ !clip_isInBounds(clipCoordinates)) {
123
+ discard;
124
+ }`
125
+ }
126
+ ]
127
+ },
128
+ wgsl: {
129
+ injections: [
130
+ {
131
+ target: 'vs:CLIP_POSITION',
132
+ injection: `\
133
+ clipCoordinates = geometryCoordinates;
134
+ if (clipUniforms.enabled != 0 && clipUniforms.mode == ${CLIP_MODE_INSTANCE} &&
135
+ !clip_isInBounds(instanceCoordinates)) {
136
+ *position = vec4<f32>(2.0, 2.0, 2.0, 1.0);
137
+ }`
138
+ },
139
+ {
140
+ target: 'fs:CLIP_COLOR',
141
+ injection: `\
142
+ if (clipUniforms.enabled != 0 && clipUniforms.mode == ${CLIP_MODE_GEOMETRY} &&
143
+ !clip_isInBounds(clipCoordinates)) {
144
+ discard;
145
+ }`
146
+ }
147
+ ]
148
+ }
149
+ };
@@ -0,0 +1,107 @@
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import type {ShaderModule} from '../../../lib/shader-module/shader-module';
6
+ import type {ShaderPlugin} from '../../../lib/shader-plugin';
7
+
8
+ export type FilterShaderPluginProps = {
9
+ /** Enables range filtering. Defaults to true. */
10
+ enabled?: boolean;
11
+ /** Inclusive minimum accepted value. Defaults to 0. */
12
+ min?: number;
13
+ /** Inclusive maximum accepted value. Defaults to 1. */
14
+ max?: number;
15
+ };
16
+
17
+ type FilterUniforms = {
18
+ enabled: number;
19
+ min: number;
20
+ max: number;
21
+ };
22
+
23
+ const filterShaderModule = {
24
+ name: 'filter',
25
+ props: {} as FilterShaderPluginProps,
26
+ uniforms: {} as FilterUniforms,
27
+ bindingLayout: [{name: 'filter', group: 2}],
28
+ uniformTypes: {
29
+ enabled: 'i32',
30
+ min: 'f32',
31
+ max: 'f32'
32
+ },
33
+ defaultUniforms: {
34
+ enabled: 1,
35
+ min: 0,
36
+ max: 1
37
+ },
38
+ vs: /* glsl */ `\
39
+ layout(std140) uniform filterUniforms {
40
+ int enabled;
41
+ float min;
42
+ float max;
43
+ } filterState;
44
+
45
+ bool filter_isVisible(float value) {
46
+ return filterState.enabled == 0 || (value >= filterState.min && value <= filterState.max);
47
+ }
48
+ `,
49
+ source: /* wgsl */ `\
50
+ struct FilterUniforms {
51
+ enabled: i32,
52
+ min: f32,
53
+ max: f32,
54
+ };
55
+
56
+ @group(2) @binding(auto) var<uniform> filterUniforms: FilterUniforms;
57
+
58
+ fn filter_isVisible(value: f32) -> bool {
59
+ return filterUniforms.enabled == 0 ||
60
+ (value >= filterUniforms.min && value <= filterUniforms.max);
61
+ }
62
+ `,
63
+ getUniforms(props: FilterShaderPluginProps = {}): Partial<FilterUniforms> {
64
+ const uniforms: Partial<FilterUniforms> = {};
65
+ if (props.enabled !== undefined) {
66
+ uniforms.enabled = Number(props.enabled);
67
+ }
68
+ if (props.min !== undefined) {
69
+ uniforms.min = props.min;
70
+ }
71
+ if (props.max !== undefined) {
72
+ uniforms.max = props.max;
73
+ }
74
+ return uniforms;
75
+ }
76
+ } as const satisfies ShaderModule<FilterShaderPluginProps, FilterUniforms>;
77
+
78
+ /** Scalar inclusive-range filtering for shaders that expose the `FILTER_POSITION` vertex hook. */
79
+ export const filterShaderPlugin: ShaderPlugin = {
80
+ name: 'filter',
81
+ modules: [filterShaderModule],
82
+ vertexInputs: {
83
+ filterValues: 'f32'
84
+ },
85
+ glsl: {
86
+ injections: [
87
+ {
88
+ target: 'vs:FILTER_POSITION',
89
+ injection: `\
90
+ if (!filter_isVisible(filterValues)) {
91
+ position = vec4(2.0, 2.0, 2.0, 1.0);
92
+ }`
93
+ }
94
+ ]
95
+ },
96
+ wgsl: {
97
+ injections: [
98
+ {
99
+ target: 'vs:FILTER_POSITION',
100
+ injection: `\
101
+ if (!filter_isVisible(filterValues)) {
102
+ *position = vec4<f32>(2.0, 2.0, 2.0, 1.0);
103
+ }`
104
+ }
105
+ ]
106
+ }
107
+ };