@luma.gl/shadertools 9.3.0-alpha.8 → 9.3.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/dist/dist.dev.js +1020 -191
- package/dist/dist.min.js +440 -145
- package/dist/index.cjs +915 -173
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +7 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/color/normalize-byte-colors.d.ts +23 -0
- package/dist/lib/color/normalize-byte-colors.d.ts.map +1 -0
- package/dist/lib/color/normalize-byte-colors.js +42 -0
- package/dist/lib/color/normalize-byte-colors.js.map +1 -0
- package/dist/lib/glsl-utils/shader-utils.js +4 -4
- package/dist/lib/glsl-utils/shader-utils.js.map +1 -1
- package/dist/lib/shader-assembly/assemble-shaders.d.ts.map +1 -1
- package/dist/lib/shader-assembly/assemble-shaders.js +102 -49
- package/dist/lib/shader-assembly/assemble-shaders.js.map +1 -1
- package/dist/lib/shader-assembly/wgsl-binding-debug.d.ts.map +1 -1
- package/dist/lib/shader-assembly/wgsl-binding-debug.js +7 -3
- package/dist/lib/shader-assembly/wgsl-binding-debug.js.map +1 -1
- package/dist/lib/shader-assembly/wgsl-binding-scan.d.ts +19 -0
- package/dist/lib/shader-assembly/wgsl-binding-scan.d.ts.map +1 -0
- package/dist/lib/shader-assembly/wgsl-binding-scan.js +151 -0
- package/dist/lib/shader-assembly/wgsl-binding-scan.js.map +1 -0
- package/dist/lib/shader-generator/glsl/generate-glsl.js +4 -4
- package/dist/lib/shader-generator/glsl/generate-glsl.js.map +1 -1
- package/dist/lib/shader-module/shader-module-uniform-layout.d.ts +69 -0
- package/dist/lib/shader-module/shader-module-uniform-layout.d.ts.map +1 -1
- package/dist/lib/shader-module/shader-module-uniform-layout.js +145 -4
- package/dist/lib/shader-module/shader-module-uniform-layout.js.map +1 -1
- package/dist/modules/color/float-colors.d.ts +26 -0
- package/dist/modules/color/float-colors.d.ts.map +1 -0
- package/dist/modules/color/float-colors.js +82 -0
- package/dist/modules/color/float-colors.js.map +1 -0
- package/dist/modules/engine/picking/picking.d.ts +8 -8
- package/dist/modules/engine/picking/picking.d.ts.map +1 -1
- package/dist/modules/engine/picking/picking.js +13 -15
- package/dist/modules/engine/picking/picking.js.map +1 -1
- package/dist/modules/engine/project/project.d.ts +1 -1
- package/dist/modules/engine/project/project.js +1 -1
- package/dist/modules/engine/skin/skin.d.ts +2 -2
- package/dist/modules/engine/skin/skin.d.ts.map +1 -1
- package/dist/modules/engine/skin/skin.js +1 -1
- package/dist/modules/lighting/gouraud-material/gouraud-material.d.ts +1 -0
- package/dist/modules/lighting/gouraud-material/gouraud-material.d.ts.map +1 -1
- package/dist/modules/lighting/gouraud-material/gouraud-material.js +6 -3
- package/dist/modules/lighting/gouraud-material/gouraud-material.js.map +1 -1
- package/dist/modules/lighting/lambert-material/lambert-shaders-glsl.d.ts +2 -2
- package/dist/modules/lighting/lambert-material/lambert-shaders-glsl.d.ts.map +1 -1
- package/dist/modules/lighting/lambert-material/lambert-shaders-glsl.js +2 -2
- package/dist/modules/lighting/lights/lighting-glsl.d.ts +1 -1
- package/dist/modules/lighting/lights/lighting-glsl.d.ts.map +1 -1
- package/dist/modules/lighting/lights/lighting-glsl.js +1 -1
- package/dist/modules/lighting/lights/lighting.d.ts +4 -2
- package/dist/modules/lighting/lights/lighting.d.ts.map +1 -1
- package/dist/modules/lighting/lights/lighting.js +17 -11
- package/dist/modules/lighting/lights/lighting.js.map +1 -1
- package/dist/modules/lighting/no-material/dirlight.d.ts +3 -3
- package/dist/modules/lighting/no-material/dirlight.d.ts.map +1 -1
- package/dist/modules/lighting/no-material/dirlight.js +2 -2
- package/dist/modules/lighting/pbr-material/pbr-material-glsl.d.ts +2 -2
- package/dist/modules/lighting/pbr-material/pbr-material-glsl.d.ts.map +1 -1
- package/dist/modules/lighting/pbr-material/pbr-material-glsl.js +138 -35
- package/dist/modules/lighting/pbr-material/pbr-material-glsl.js.map +1 -1
- package/dist/modules/lighting/pbr-material/pbr-material-wgsl.d.ts +1 -1
- package/dist/modules/lighting/pbr-material/pbr-material-wgsl.d.ts.map +1 -1
- package/dist/modules/lighting/pbr-material/pbr-material-wgsl.js +139 -35
- package/dist/modules/lighting/pbr-material/pbr-material-wgsl.js.map +1 -1
- package/dist/modules/lighting/pbr-material/pbr-material.d.ts +74 -6
- package/dist/modules/lighting/pbr-material/pbr-material.d.ts.map +1 -1
- package/dist/modules/lighting/pbr-material/pbr-material.js +70 -2
- package/dist/modules/lighting/pbr-material/pbr-material.js.map +1 -1
- package/dist/modules/lighting/pbr-material/pbr-projection.js +1 -1
- package/dist/modules/lighting/pbr-material/pbr-scene.d.ts +40 -0
- package/dist/modules/lighting/pbr-material/pbr-scene.d.ts.map +1 -0
- package/dist/modules/lighting/pbr-material/pbr-scene.js +67 -0
- package/dist/modules/lighting/pbr-material/pbr-scene.js.map +1 -0
- package/dist/modules/lighting/phong-material/phong-material.d.ts +1 -0
- package/dist/modules/lighting/phong-material/phong-material.d.ts.map +1 -1
- package/dist/modules/lighting/phong-material/phong-material.js +6 -3
- package/dist/modules/lighting/phong-material/phong-material.js.map +1 -1
- package/dist/modules/lighting/phong-material/phong-shaders-glsl.d.ts +2 -2
- package/dist/modules/lighting/phong-material/phong-shaders-glsl.d.ts.map +1 -1
- package/dist/modules/lighting/phong-material/phong-shaders-glsl.js +2 -2
- package/dist/modules/math/fp64/fp64-arithmetic-glsl.d.ts +1 -1
- package/dist/modules/math/fp64/fp64-arithmetic-glsl.d.ts.map +1 -1
- package/dist/modules/math/fp64/fp64-arithmetic-glsl.js +1 -1
- package/package.json +2 -2
- package/src/index.ts +17 -1
- package/src/lib/color/normalize-byte-colors.ts +57 -0
- package/src/lib/glsl-utils/shader-utils.ts +4 -4
- package/src/lib/shader-assembly/assemble-shaders.ts +197 -69
- package/src/lib/shader-assembly/wgsl-binding-debug.ts +14 -3
- package/src/lib/shader-assembly/wgsl-binding-scan.ts +228 -0
- package/src/lib/shader-generator/glsl/generate-glsl.ts +4 -4
- package/src/lib/shader-module/shader-module-uniform-layout.ts +236 -10
- package/src/modules/color/float-colors.ts +99 -0
- package/src/modules/engine/picking/picking.ts +17 -19
- package/src/modules/engine/project/project.ts +1 -1
- package/src/modules/engine/skin/skin.ts +1 -1
- package/src/modules/lighting/gouraud-material/gouraud-material.ts +10 -3
- package/src/modules/lighting/lambert-material/lambert-shaders-glsl.ts +2 -2
- package/src/modules/lighting/lights/lighting-glsl.ts +1 -1
- package/src/modules/lighting/lights/lighting.ts +20 -11
- package/src/modules/lighting/no-material/dirlight.ts +2 -2
- package/src/modules/lighting/pbr-material/pbr-material-glsl.ts +138 -35
- package/src/modules/lighting/pbr-material/pbr-material-wgsl.ts +139 -35
- package/src/modules/lighting/pbr-material/pbr-material.ts +110 -3
- package/src/modules/lighting/pbr-material/pbr-projection.ts +1 -1
- package/src/modules/lighting/pbr-material/pbr-scene.ts +91 -0
- package/src/modules/lighting/phong-material/phong-material.ts +10 -3
- package/src/modules/lighting/phong-material/phong-shaders-glsl.ts +2 -2
- package/src/modules/math/fp64/fp64-arithmetic-glsl.ts +1 -1
|
@@ -5,25 +5,81 @@
|
|
|
5
5
|
import type {ShaderModule} from './shader-module';
|
|
6
6
|
import {assert} from '../utils/assert';
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Shader stages supported by shader-module uniform-layout validation helpers.
|
|
10
|
+
*/
|
|
8
11
|
export type ShaderModuleUniformLayoutStage = 'vertex' | 'fragment' | 'wgsl';
|
|
9
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Describes the result of comparing declared `uniformTypes` with the fields
|
|
15
|
+
* found in a shader uniform block.
|
|
16
|
+
*/
|
|
10
17
|
export type ShaderModuleUniformLayoutValidationResult = {
|
|
18
|
+
/** Name of the shader module being validated. */
|
|
11
19
|
moduleName: string;
|
|
20
|
+
/** Expected block name derived from the shader module name. */
|
|
12
21
|
uniformBlockName: string;
|
|
22
|
+
/** Shader stage that was inspected. */
|
|
13
23
|
stage: ShaderModuleUniformLayoutStage;
|
|
24
|
+
/** Field names declared by the module metadata. */
|
|
14
25
|
expectedUniformNames: string[];
|
|
26
|
+
/** Field names parsed from the shader source. */
|
|
15
27
|
actualUniformNames: string[];
|
|
28
|
+
/** Whether the declared and parsed field lists match exactly. */
|
|
16
29
|
matches: boolean;
|
|
17
30
|
};
|
|
18
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Parsed information about one GLSL uniform block declaration.
|
|
34
|
+
*/
|
|
35
|
+
export type GLSLUniformBlockInfo = {
|
|
36
|
+
/** Declared block type name. */
|
|
37
|
+
blockName: string;
|
|
38
|
+
/** Optional instance name that follows the block declaration. */
|
|
39
|
+
instanceName: string | null;
|
|
40
|
+
/** Raw layout qualifier text, if present. */
|
|
41
|
+
layoutQualifier: string | null;
|
|
42
|
+
/** Whether any explicit layout qualifier was present. */
|
|
43
|
+
hasLayoutQualifier: boolean;
|
|
44
|
+
/** Whether the block explicitly declares `layout(std140)`. */
|
|
45
|
+
isStd140: boolean;
|
|
46
|
+
/** Raw source text inside the block braces. */
|
|
47
|
+
body: string;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Logging surface used by validation and warning helpers.
|
|
52
|
+
*/
|
|
19
53
|
type Logger = {
|
|
54
|
+
/** Error logger compatible with luma's deferred log API. */
|
|
20
55
|
error?: (...args: unknown[]) => () => unknown;
|
|
56
|
+
/** Warning logger compatible with luma's deferred log API. */
|
|
57
|
+
warn?: (...args: unknown[]) => () => unknown;
|
|
21
58
|
};
|
|
22
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Matches one field declaration inside a GLSL uniform block body.
|
|
62
|
+
*/
|
|
63
|
+
const GLSL_UNIFORM_BLOCK_FIELD_REGEXP =
|
|
64
|
+
/^(?:uniform\s+)?(?:(?:lowp|mediump|highp)\s+)?[A-Za-z0-9_]+(?:<[^>]+>)?\s+([A-Za-z0-9_]+)(?:\s*\[[^\]]+\])?\s*;/;
|
|
65
|
+
/**
|
|
66
|
+
* Matches full GLSL uniform block declarations, including optional layout qualifiers.
|
|
67
|
+
*/
|
|
68
|
+
const GLSL_UNIFORM_BLOCK_REGEXP =
|
|
69
|
+
/((?:layout\s*\([^)]*\)\s*)*)uniform\s+([A-Za-z_][A-Za-z0-9_]*)\s*\{([\s\S]*?)\}\s*([A-Za-z_][A-Za-z0-9_]*)?\s*;/g;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Returns the uniform block type name expected for the supplied shader module.
|
|
73
|
+
*/
|
|
23
74
|
export function getShaderModuleUniformBlockName(module: ShaderModule): string {
|
|
24
75
|
return `${module.name}Uniforms`;
|
|
25
76
|
}
|
|
26
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Returns the ordered field names parsed from a shader module's uniform block.
|
|
80
|
+
*
|
|
81
|
+
* @returns `null` when the stage has no source or the expected block is absent.
|
|
82
|
+
*/
|
|
27
83
|
export function getShaderModuleUniformBlockFields(
|
|
28
84
|
module: ShaderModule,
|
|
29
85
|
stage: ShaderModuleUniformLayoutStage
|
|
@@ -43,6 +99,12 @@ export function getShaderModuleUniformBlockFields(
|
|
|
43
99
|
);
|
|
44
100
|
}
|
|
45
101
|
|
|
102
|
+
/**
|
|
103
|
+
* Computes the validation result for a shader module's declared and parsed
|
|
104
|
+
* uniform-block field lists.
|
|
105
|
+
*
|
|
106
|
+
* @returns `null` when the module has no declared uniform types or no matching block.
|
|
107
|
+
*/
|
|
46
108
|
export function getShaderModuleUniformLayoutValidationResult(
|
|
47
109
|
module: ShaderModule,
|
|
48
110
|
stage: ShaderModuleUniformLayoutStage
|
|
@@ -67,6 +129,12 @@ export function getShaderModuleUniformLayoutValidationResult(
|
|
|
67
129
|
};
|
|
68
130
|
}
|
|
69
131
|
|
|
132
|
+
/**
|
|
133
|
+
* Validates that a shader module's parsed uniform block matches `uniformTypes`.
|
|
134
|
+
*
|
|
135
|
+
* When a mismatch is detected, the helper logs a formatted error and optionally
|
|
136
|
+
* throws via {@link assert}.
|
|
137
|
+
*/
|
|
70
138
|
export function validateShaderModuleUniformLayout(
|
|
71
139
|
module: ShaderModule,
|
|
72
140
|
stage: ShaderModuleUniformLayoutStage,
|
|
@@ -90,6 +158,67 @@ export function validateShaderModuleUniformLayout(
|
|
|
90
158
|
return validationResult;
|
|
91
159
|
}
|
|
92
160
|
|
|
161
|
+
/**
|
|
162
|
+
* Parses all GLSL uniform blocks in a shader source string.
|
|
163
|
+
*/
|
|
164
|
+
export function getGLSLUniformBlocks(shaderSource: string): GLSLUniformBlockInfo[] {
|
|
165
|
+
const blocks: GLSLUniformBlockInfo[] = [];
|
|
166
|
+
const uncommentedSource = stripShaderComments(shaderSource);
|
|
167
|
+
|
|
168
|
+
for (const sourceMatch of uncommentedSource.matchAll(GLSL_UNIFORM_BLOCK_REGEXP)) {
|
|
169
|
+
const layoutQualifier = sourceMatch[1]?.trim() || null;
|
|
170
|
+
blocks.push({
|
|
171
|
+
blockName: sourceMatch[2],
|
|
172
|
+
body: sourceMatch[3],
|
|
173
|
+
instanceName: sourceMatch[4] || null,
|
|
174
|
+
layoutQualifier,
|
|
175
|
+
hasLayoutQualifier: Boolean(layoutQualifier),
|
|
176
|
+
isStd140: Boolean(
|
|
177
|
+
layoutQualifier && /\blayout\s*\([^)]*\bstd140\b[^)]*\)/.exec(layoutQualifier)
|
|
178
|
+
)
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return blocks;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Emits warnings for GLSL uniform blocks that do not explicitly declare
|
|
187
|
+
* `layout(std140)`.
|
|
188
|
+
*
|
|
189
|
+
* @returns The list of parsed blocks that were considered non-compliant.
|
|
190
|
+
*/
|
|
191
|
+
export function warnIfGLSLUniformBlocksAreNotStd140(
|
|
192
|
+
shaderSource: string,
|
|
193
|
+
stage: Exclude<ShaderModuleUniformLayoutStage, 'wgsl'>,
|
|
194
|
+
log?: Logger,
|
|
195
|
+
context?: {label?: string}
|
|
196
|
+
): GLSLUniformBlockInfo[] {
|
|
197
|
+
const nonStd140Blocks = getGLSLUniformBlocks(shaderSource).filter(block => !block.isStd140);
|
|
198
|
+
const seenBlockNames = new Set<string>();
|
|
199
|
+
|
|
200
|
+
for (const block of nonStd140Blocks) {
|
|
201
|
+
if (seenBlockNames.has(block.blockName)) {
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
seenBlockNames.add(block.blockName);
|
|
205
|
+
|
|
206
|
+
const shaderLabel = context?.label ? `${context.label} ` : '';
|
|
207
|
+
const actualLayout = block.hasLayoutQualifier
|
|
208
|
+
? `declares ${normalizeWhitespace(block.layoutQualifier!)} instead of layout(std140)`
|
|
209
|
+
: 'does not declare layout(std140)';
|
|
210
|
+
const message = `${shaderLabel}${stage} shader uniform block ${
|
|
211
|
+
block.blockName
|
|
212
|
+
} ${actualLayout}. luma.gl host-side shader block packing assumes explicit layout(std140) for GLSL uniform blocks. Add \`layout(std140)\` to the block declaration.`;
|
|
213
|
+
log?.warn?.(message, block)();
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return nonStd140Blocks;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Extracts field names from the named GLSL or WGSL uniform block/struct.
|
|
221
|
+
*/
|
|
93
222
|
function extractShaderUniformBlockFieldNames(
|
|
94
223
|
shaderSource: string,
|
|
95
224
|
language: 'glsl' | 'wgsl',
|
|
@@ -115,9 +244,7 @@ function extractShaderUniformBlockFieldNames(
|
|
|
115
244
|
const fieldMatch =
|
|
116
245
|
language === 'wgsl'
|
|
117
246
|
? line.match(/^([A-Za-z0-9_]+)\s*:/)
|
|
118
|
-
: line.match(
|
|
119
|
-
/^(?:uniform\s+)?[A-Za-z0-9_]+(?:<[^>]+>)?\s+([A-Za-z0-9_]+)(?:\s*\[[^\]]+\])?\s*;/
|
|
120
|
-
);
|
|
247
|
+
: line.match(GLSL_UNIFORM_BLOCK_FIELD_REGEXP);
|
|
121
248
|
|
|
122
249
|
if (fieldMatch) {
|
|
123
250
|
fieldNames.push(fieldMatch[1]);
|
|
@@ -127,6 +254,9 @@ function extractShaderUniformBlockFieldNames(
|
|
|
127
254
|
return fieldNames;
|
|
128
255
|
}
|
|
129
256
|
|
|
257
|
+
/**
|
|
258
|
+
* Extracts the body of a WGSL struct with the supplied name.
|
|
259
|
+
*/
|
|
130
260
|
function extractWGSLStructBody(shaderSource: string, uniformBlockName: string): string | null {
|
|
131
261
|
const structMatch = new RegExp(`\\bstruct\\s+${uniformBlockName}\\b`, 'm').exec(shaderSource);
|
|
132
262
|
if (!structMatch) {
|
|
@@ -158,17 +288,22 @@ function extractWGSLStructBody(shaderSource: string, uniformBlockName: string):
|
|
|
158
288
|
return null;
|
|
159
289
|
}
|
|
160
290
|
|
|
291
|
+
/**
|
|
292
|
+
* Extracts the body of a named GLSL uniform block from shader source.
|
|
293
|
+
*/
|
|
161
294
|
function extractGLSLUniformBlockBody(
|
|
162
295
|
shaderSource: string,
|
|
163
296
|
uniformBlockName: string
|
|
164
297
|
): string | null {
|
|
165
|
-
const
|
|
166
|
-
|
|
298
|
+
const block = getGLSLUniformBlocks(shaderSource).find(
|
|
299
|
+
candidate => candidate.blockName === uniformBlockName
|
|
167
300
|
);
|
|
168
|
-
|
|
169
|
-
return sourceMatch?.[1] || null;
|
|
301
|
+
return block?.body || null;
|
|
170
302
|
}
|
|
171
303
|
|
|
304
|
+
/**
|
|
305
|
+
* Returns `true` when the two arrays contain the same strings in the same order.
|
|
306
|
+
*/
|
|
172
307
|
function areStringArraysEqual(leftValues: string[], rightValues: string[]): boolean {
|
|
173
308
|
if (leftValues.length !== rightValues.length) {
|
|
174
309
|
return false;
|
|
@@ -183,12 +318,103 @@ function areStringArraysEqual(leftValues: string[], rightValues: string[]): bool
|
|
|
183
318
|
return true;
|
|
184
319
|
}
|
|
185
320
|
|
|
321
|
+
/**
|
|
322
|
+
* Formats the standard validation error message for a shader-module layout mismatch.
|
|
323
|
+
*/
|
|
186
324
|
function formatShaderModuleUniformLayoutError(
|
|
187
325
|
validationResult: ShaderModuleUniformLayoutValidationResult
|
|
188
326
|
): string {
|
|
327
|
+
const {expectedUniformNames, actualUniformNames} = validationResult;
|
|
328
|
+
const missingUniformNames = expectedUniformNames.filter(
|
|
329
|
+
uniformName => !actualUniformNames.includes(uniformName)
|
|
330
|
+
);
|
|
331
|
+
const unexpectedUniformNames = actualUniformNames.filter(
|
|
332
|
+
uniformName => !expectedUniformNames.includes(uniformName)
|
|
333
|
+
);
|
|
334
|
+
const mismatchDetails = [
|
|
335
|
+
`Expected ${expectedUniformNames.length} fields, found ${actualUniformNames.length}.`
|
|
336
|
+
];
|
|
337
|
+
const firstMismatchDescription = getFirstUniformMismatchDescription(
|
|
338
|
+
expectedUniformNames,
|
|
339
|
+
actualUniformNames
|
|
340
|
+
);
|
|
341
|
+
if (firstMismatchDescription) {
|
|
342
|
+
mismatchDetails.push(firstMismatchDescription);
|
|
343
|
+
}
|
|
344
|
+
if (missingUniformNames.length) {
|
|
345
|
+
mismatchDetails.push(
|
|
346
|
+
`Missing from shader block (${missingUniformNames.length}): ${formatUniformNameList(
|
|
347
|
+
missingUniformNames
|
|
348
|
+
)}.`
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
if (unexpectedUniformNames.length) {
|
|
352
|
+
mismatchDetails.push(
|
|
353
|
+
`Unexpected in shader block (${unexpectedUniformNames.length}): ${formatUniformNameList(
|
|
354
|
+
unexpectedUniformNames
|
|
355
|
+
)}.`
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
if (
|
|
359
|
+
expectedUniformNames.length <= 12 &&
|
|
360
|
+
actualUniformNames.length <= 12 &&
|
|
361
|
+
(missingUniformNames.length || unexpectedUniformNames.length)
|
|
362
|
+
) {
|
|
363
|
+
mismatchDetails.push(`Expected: ${expectedUniformNames.join(', ')}.`);
|
|
364
|
+
mismatchDetails.push(`Actual: ${actualUniformNames.join(', ')}.`);
|
|
365
|
+
}
|
|
366
|
+
|
|
189
367
|
return `${validationResult.moduleName}: ${validationResult.stage} shader uniform block ${
|
|
190
368
|
validationResult.uniformBlockName
|
|
191
|
-
} does not match module.uniformTypes
|
|
192
|
-
|
|
193
|
-
|
|
369
|
+
} does not match module.uniformTypes. ${mismatchDetails.join(' ')}`;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Removes line and block comments from shader source before lightweight parsing.
|
|
374
|
+
*/
|
|
375
|
+
function stripShaderComments(shaderSource: string): string {
|
|
376
|
+
return shaderSource.replace(/\/\*[\s\S]*?\*\//g, '').replace(/\/\/.*$/gm, '');
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Collapses repeated whitespace in a layout qualifier for log-friendly output.
|
|
381
|
+
*/
|
|
382
|
+
function normalizeWhitespace(value: string): string {
|
|
383
|
+
return value.replace(/\s+/g, ' ').trim();
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function getFirstUniformMismatchDescription(
|
|
387
|
+
expectedUniformNames: string[],
|
|
388
|
+
actualUniformNames: string[]
|
|
389
|
+
): string | null {
|
|
390
|
+
const minimumLength = Math.min(expectedUniformNames.length, actualUniformNames.length);
|
|
391
|
+
for (let index = 0; index < minimumLength; index++) {
|
|
392
|
+
if (expectedUniformNames[index] !== actualUniformNames[index]) {
|
|
393
|
+
return `First mismatch at field ${index + 1}: expected ${
|
|
394
|
+
expectedUniformNames[index]
|
|
395
|
+
}, found ${actualUniformNames[index]}.`;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
if (expectedUniformNames.length > actualUniformNames.length) {
|
|
400
|
+
return `Shader block ends after field ${actualUniformNames.length}; expected next field ${
|
|
401
|
+
expectedUniformNames[actualUniformNames.length]
|
|
402
|
+
}.`;
|
|
403
|
+
}
|
|
404
|
+
if (actualUniformNames.length > expectedUniformNames.length) {
|
|
405
|
+
return `Shader block has extra field ${actualUniformNames.length}: ${
|
|
406
|
+
actualUniformNames[expectedUniformNames.length]
|
|
407
|
+
}.`;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
return null;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
function formatUniformNameList(uniformNames: string[], maxNames = 8): string {
|
|
414
|
+
if (uniformNames.length <= maxNames) {
|
|
415
|
+
return uniformNames.join(', ');
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
const remainingCount = uniformNames.length - maxNames;
|
|
419
|
+
return `${uniformNames.slice(0, maxNames).join(', ')}, ... (${remainingCount} more)`;
|
|
194
420
|
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// luma.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
import {ShaderModule} from '../../lib/shader-module/shader-module';
|
|
6
|
+
|
|
7
|
+
export type FloatColorsProps = {
|
|
8
|
+
/**
|
|
9
|
+
* When true, semantic colors are interpreted as 0-255 byte-style values and normalized in shader code.
|
|
10
|
+
* When false, semantic colors are interpreted directly as floats.
|
|
11
|
+
*/
|
|
12
|
+
useByteColors?: boolean;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export type FloatColorsUniforms = {
|
|
16
|
+
/** Controls whether shader helpers normalize semantic colors from byte space. */
|
|
17
|
+
useByteColors: boolean;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const GLSL_UNIFORMS = /* glsl */ `\
|
|
21
|
+
layout(std140) uniform floatColorsUniforms {
|
|
22
|
+
float useByteColors;
|
|
23
|
+
} floatColors;
|
|
24
|
+
|
|
25
|
+
vec3 floatColors_normalize(vec3 inputColor) {
|
|
26
|
+
return floatColors.useByteColors > 0.5 ? inputColor / 255.0 : inputColor;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
vec4 floatColors_normalize(vec4 inputColor) {
|
|
30
|
+
return floatColors.useByteColors > 0.5 ? inputColor / 255.0 : inputColor;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
vec4 floatColors_premultiplyAlpha(vec4 inputColor) {
|
|
34
|
+
return vec4(inputColor.rgb * inputColor.a, inputColor.a);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
vec4 floatColors_unpremultiplyAlpha(vec4 inputColor) {
|
|
38
|
+
return inputColor.a > 0.0 ? vec4(inputColor.rgb / inputColor.a, inputColor.a) : vec4(0.0);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
vec4 floatColors_premultiply_alpha(vec4 inputColor) {
|
|
42
|
+
return floatColors_premultiplyAlpha(inputColor);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
vec4 floatColors_unpremultiply_alpha(vec4 inputColor) {
|
|
46
|
+
return floatColors_unpremultiplyAlpha(inputColor);
|
|
47
|
+
}
|
|
48
|
+
`;
|
|
49
|
+
|
|
50
|
+
const WGSL_UNIFORMS = /* wgsl */ `\
|
|
51
|
+
struct floatColorsUniforms {
|
|
52
|
+
useByteColors: f32
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
@group(0) @binding(auto) var<uniform> floatColors : floatColorsUniforms;
|
|
56
|
+
|
|
57
|
+
fn floatColors_normalize(inputColor: vec3<f32>) -> vec3<f32> {
|
|
58
|
+
return select(inputColor, inputColor / 255.0, floatColors.useByteColors > 0.5);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
fn floatColors_normalize4(inputColor: vec4<f32>) -> vec4<f32> {
|
|
62
|
+
return select(inputColor, inputColor / 255.0, floatColors.useByteColors > 0.5);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
fn floatColors_premultiplyAlpha(inputColor: vec4<f32>) -> vec4<f32> {
|
|
66
|
+
return vec4<f32>(inputColor.rgb * inputColor.a, inputColor.a);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
fn floatColors_unpremultiplyAlpha(inputColor: vec4<f32>) -> vec4<f32> {
|
|
70
|
+
return select(
|
|
71
|
+
vec4<f32>(0.0),
|
|
72
|
+
vec4<f32>(inputColor.rgb / inputColor.a, inputColor.a),
|
|
73
|
+
inputColor.a > 0.0
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
fn floatColors_premultiply_alpha(inputColor: vec4<f32>) -> vec4<f32> {
|
|
78
|
+
return floatColors_premultiplyAlpha(inputColor);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
fn floatColors_unpremultiply_alpha(inputColor: vec4<f32>) -> vec4<f32> {
|
|
82
|
+
return floatColors_unpremultiplyAlpha(inputColor);
|
|
83
|
+
}
|
|
84
|
+
`;
|
|
85
|
+
|
|
86
|
+
export const floatColors = {
|
|
87
|
+
name: 'floatColors',
|
|
88
|
+
props: {} as FloatColorsProps,
|
|
89
|
+
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
|
+
}
|
|
99
|
+
} as const satisfies ShaderModule<FloatColorsProps, FloatColorsUniforms>;
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import {ShaderModule} from '../../../lib/shader-module/shader-module';
|
|
6
6
|
import type {NumberArray3, NumberArray4} from '@math.gl/core';
|
|
7
|
+
import {normalizeByteColor4, resolveUseByteColors} from '../../../lib/color/normalize-byte-colors';
|
|
7
8
|
|
|
8
9
|
// cyan color
|
|
9
10
|
const DEFAULT_HIGHLIGHT_COLOR: NumberArray4 = [0, 1, 1, 1];
|
|
@@ -22,8 +23,8 @@ export type PickingProps = {
|
|
|
22
23
|
highlightedObjectColor?: NumberArray3 | null;
|
|
23
24
|
/** Color of visual highlight of "selected" item */
|
|
24
25
|
highlightColor?: NumberArray3 | NumberArray4;
|
|
25
|
-
/**
|
|
26
|
-
|
|
26
|
+
/** Interpret highlight colors as byte-style 0-255 values. */
|
|
27
|
+
useByteColors?: boolean;
|
|
27
28
|
};
|
|
28
29
|
|
|
29
30
|
/**
|
|
@@ -39,8 +40,8 @@ export type PickingUniforms = {
|
|
|
39
40
|
isActive?: boolean;
|
|
40
41
|
/** Set to true when picking an attribute value instead of object index */
|
|
41
42
|
isAttribute?: boolean;
|
|
42
|
-
/**
|
|
43
|
-
|
|
43
|
+
/** Interpret highlight colors as byte-style 0-255 values. */
|
|
44
|
+
useByteColors?: boolean;
|
|
44
45
|
/** Do we have a highlighted item? */
|
|
45
46
|
isHighlightActive?: boolean;
|
|
46
47
|
/** Set to a picking color to visually highlight that item */
|
|
@@ -50,11 +51,11 @@ export type PickingUniforms = {
|
|
|
50
51
|
};
|
|
51
52
|
|
|
52
53
|
const vs = /* glsl */ `\
|
|
53
|
-
uniform pickingUniforms {
|
|
54
|
+
layout(std140) uniform pickingUniforms {
|
|
54
55
|
float isActive;
|
|
55
56
|
float isAttribute;
|
|
56
57
|
float isHighlightActive;
|
|
57
|
-
float
|
|
58
|
+
float useByteColors;
|
|
58
59
|
vec3 highlightedObjectColor;
|
|
59
60
|
vec4 highlightColor;
|
|
60
61
|
} picking;
|
|
@@ -63,12 +64,12 @@ out vec4 picking_vRGBcolor_Avalid;
|
|
|
63
64
|
|
|
64
65
|
// Normalize unsigned byte color to 0-1 range
|
|
65
66
|
vec3 picking_normalizeColor(vec3 color) {
|
|
66
|
-
return picking.
|
|
67
|
+
return picking.useByteColors > 0.5 ? color / 255.0 : color;
|
|
67
68
|
}
|
|
68
69
|
|
|
69
70
|
// Normalize unsigned byte color to 0-1 range
|
|
70
71
|
vec4 picking_normalizeColor(vec4 color) {
|
|
71
|
-
return picking.
|
|
72
|
+
return picking.useByteColors > 0.5 ? color / 255.0 : color;
|
|
72
73
|
}
|
|
73
74
|
|
|
74
75
|
bool picking_isColorZero(vec3 color) {
|
|
@@ -124,11 +125,11 @@ void picking_setPickingAttribute(vec3 value) {
|
|
|
124
125
|
`;
|
|
125
126
|
|
|
126
127
|
const fs = /* glsl */ `\
|
|
127
|
-
uniform pickingUniforms {
|
|
128
|
+
layout(std140) uniform pickingUniforms {
|
|
128
129
|
float isActive;
|
|
129
130
|
float isAttribute;
|
|
130
131
|
float isHighlightActive;
|
|
131
|
-
float
|
|
132
|
+
float useByteColors;
|
|
132
133
|
vec3 highlightedObjectColor;
|
|
133
134
|
vec4 highlightColor;
|
|
134
135
|
} picking;
|
|
@@ -202,7 +203,7 @@ export const picking = {
|
|
|
202
203
|
isActive: 'f32',
|
|
203
204
|
isAttribute: 'f32',
|
|
204
205
|
isHighlightActive: 'f32',
|
|
205
|
-
|
|
206
|
+
useByteColors: 'f32',
|
|
206
207
|
highlightedObjectColor: 'vec3<f32>',
|
|
207
208
|
highlightColor: 'vec4<f32>'
|
|
208
209
|
},
|
|
@@ -210,7 +211,7 @@ export const picking = {
|
|
|
210
211
|
isActive: false,
|
|
211
212
|
isAttribute: false,
|
|
212
213
|
isHighlightActive: false,
|
|
213
|
-
|
|
214
|
+
useByteColors: true,
|
|
214
215
|
highlightedObjectColor: [0, 0, 0],
|
|
215
216
|
highlightColor: DEFAULT_HIGHLIGHT_COLOR
|
|
216
217
|
},
|
|
@@ -222,6 +223,7 @@ export const picking = {
|
|
|
222
223
|
|
|
223
224
|
function getUniforms(opts: PickingProps = {}, prevUniforms?: PickingUniforms): PickingUniforms {
|
|
224
225
|
const uniforms = {} as PickingUniforms;
|
|
226
|
+
const useByteColors = resolveUseByteColors(opts.useByteColors, true);
|
|
225
227
|
|
|
226
228
|
if (opts.highlightedObjectColor === undefined) {
|
|
227
229
|
// Unless highlightedObjectColor explicitly null or set, do not update state
|
|
@@ -234,11 +236,7 @@ function getUniforms(opts: PickingProps = {}, prevUniforms?: PickingUniforms): P
|
|
|
234
236
|
}
|
|
235
237
|
|
|
236
238
|
if (opts.highlightColor) {
|
|
237
|
-
|
|
238
|
-
if (!Number.isFinite(color[3])) {
|
|
239
|
-
color[3] = 1;
|
|
240
|
-
}
|
|
241
|
-
uniforms.highlightColor = color as NumberArray4;
|
|
239
|
+
uniforms.highlightColor = normalizeByteColor4(opts.highlightColor, useByteColors);
|
|
242
240
|
}
|
|
243
241
|
|
|
244
242
|
if (opts.isActive !== undefined) {
|
|
@@ -246,8 +244,8 @@ function getUniforms(opts: PickingProps = {}, prevUniforms?: PickingUniforms): P
|
|
|
246
244
|
uniforms.isAttribute = Boolean(opts.isAttribute);
|
|
247
245
|
}
|
|
248
246
|
|
|
249
|
-
if (opts.
|
|
250
|
-
uniforms.
|
|
247
|
+
if (opts.useByteColors !== undefined) {
|
|
248
|
+
uniforms.useByteColors = Boolean(opts.useByteColors);
|
|
251
249
|
}
|
|
252
250
|
|
|
253
251
|
return uniforms;
|
|
@@ -7,6 +7,7 @@ import {ShaderModule} from '../../../lib/shader-module/shader-module';
|
|
|
7
7
|
import {lighting} from '../lights/lighting';
|
|
8
8
|
import {PHONG_VS, PHONG_FS} from '../phong-material/phong-shaders-glsl';
|
|
9
9
|
import {PHONG_WGSL} from '../phong-material/phong-shaders-wgsl';
|
|
10
|
+
import {normalizeByteColor3, resolveUseByteColors} from '../../../lib/color/normalize-byte-colors';
|
|
10
11
|
|
|
11
12
|
export type GouraudMaterialProps = {
|
|
12
13
|
unlit?: boolean;
|
|
@@ -15,6 +16,7 @@ export type GouraudMaterialProps = {
|
|
|
15
16
|
/** Specularity exponent */
|
|
16
17
|
shininess?: number;
|
|
17
18
|
specularColor?: [number, number, number];
|
|
19
|
+
useByteColors?: boolean;
|
|
18
20
|
};
|
|
19
21
|
|
|
20
22
|
/** In Gouraud shading, color is calculated for each triangle vertex normal, and then color is interpolated colors across the triangle */
|
|
@@ -36,20 +38,25 @@ export const gouraudMaterial: ShaderModule<GouraudMaterialProps> = {
|
|
|
36
38
|
ambient: 'f32',
|
|
37
39
|
diffuse: 'f32',
|
|
38
40
|
shininess: 'f32',
|
|
39
|
-
specularColor: 'vec3<f32>'
|
|
41
|
+
specularColor: 'vec3<f32>',
|
|
42
|
+
useByteColors: 'i32'
|
|
40
43
|
},
|
|
41
44
|
defaultUniforms: {
|
|
42
45
|
unlit: false,
|
|
43
46
|
ambient: 0.35,
|
|
44
47
|
diffuse: 0.6,
|
|
45
48
|
shininess: 32,
|
|
46
|
-
specularColor: [0.15, 0.15, 0.15]
|
|
49
|
+
specularColor: [0.15, 0.15, 0.15],
|
|
50
|
+
useByteColors: true
|
|
47
51
|
},
|
|
48
52
|
|
|
49
53
|
getUniforms(props: GouraudMaterialProps) {
|
|
50
54
|
const uniforms = {...props};
|
|
51
55
|
if (uniforms.specularColor) {
|
|
52
|
-
uniforms.specularColor =
|
|
56
|
+
uniforms.specularColor = normalizeByteColor3(
|
|
57
|
+
uniforms.specularColor,
|
|
58
|
+
resolveUseByteColors(uniforms.useByteColors, true)
|
|
59
|
+
) as NumberArray3;
|
|
53
60
|
}
|
|
54
61
|
return {...gouraudMaterial.defaultUniforms, ...uniforms};
|
|
55
62
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
5
|
export const LAMBERT_VS = /* glsl */ `\
|
|
6
|
-
uniform lambertMaterialUniforms {
|
|
6
|
+
layout(std140) uniform lambertMaterialUniforms {
|
|
7
7
|
uniform bool unlit;
|
|
8
8
|
uniform float ambient;
|
|
9
9
|
uniform float diffuse;
|
|
@@ -11,7 +11,7 @@ uniform lambertMaterialUniforms {
|
|
|
11
11
|
`;
|
|
12
12
|
|
|
13
13
|
export const LAMBERT_FS = /* glsl */ `\
|
|
14
|
-
uniform lambertMaterialUniforms {
|
|
14
|
+
layout(std140) uniform lambertMaterialUniforms {
|
|
15
15
|
uniform bool unlit;
|
|
16
16
|
uniform float ambient;
|
|
17
17
|
uniform float diffuse;
|