@luma.gl/shaders 10.0.0-alpha.5 → 10.0.0-alpha.7

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 (92) hide show
  1. package/LICENSE +38 -0
  2. package/dist/dist.dev.js +159 -127
  3. package/dist/dist.min.js +110 -105
  4. package/dist/glsl.cjs.map +1 -1
  5. package/dist/index.cjs.map +2 -2
  6. package/dist/index.d.ts +1 -1
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js.map +1 -1
  9. package/dist/lib/glsl-shader-assembler.cjs +1 -1
  10. package/dist/lib/glsl-shader-assembler.js +1 -1
  11. package/dist/lib/glsl-shader-assembler.js.map +1 -1
  12. package/dist/lib/preprocessor/preprocessor.cjs +21 -0
  13. package/dist/lib/preprocessor/preprocessor.js +21 -0
  14. package/dist/lib/preprocessor/preprocessor.js.map +1 -1
  15. package/dist/lib/shader-assembly/assemble-glsl-shaders.cjs +11 -19
  16. package/dist/lib/shader-assembly/assemble-glsl-shaders.d.ts +2 -2
  17. package/dist/lib/shader-assembly/assemble-glsl-shaders.d.ts.map +1 -1
  18. package/dist/lib/shader-assembly/assemble-glsl-shaders.js +12 -20
  19. package/dist/lib/shader-assembly/assemble-glsl-shaders.js.map +1 -1
  20. package/dist/lib/shader-assembly/assemble-wgsl-shaders.cjs +6 -6
  21. package/dist/lib/shader-assembly/assemble-wgsl-shaders.js +7 -7
  22. package/dist/lib/shader-assembly/assemble-wgsl-shaders.js.map +1 -1
  23. package/dist/lib/shader-assembly/shader-assembly-types.d.ts +7 -7
  24. package/dist/lib/shader-assembly/shader-assembly-types.d.ts.map +1 -1
  25. package/dist/lib/shader-assembly/shader-hooks.cjs +4 -1
  26. package/dist/lib/shader-assembly/shader-hooks.d.ts.map +1 -1
  27. package/dist/lib/shader-assembly/shader-hooks.js +4 -1
  28. package/dist/lib/shader-assembly/shader-hooks.js.map +1 -1
  29. package/dist/lib/shader-assembly/shader-injections.d.ts +2 -0
  30. package/dist/lib/shader-assembly/shader-injections.d.ts.map +1 -1
  31. package/dist/lib/shader-assembly/shader-injections.js.map +1 -1
  32. package/dist/lib/shader-assembly/shader-plugin-varyings.cjs +39 -22
  33. package/dist/lib/shader-assembly/shader-plugin-varyings.d.ts +5 -5
  34. package/dist/lib/shader-assembly/shader-plugin-varyings.d.ts.map +1 -1
  35. package/dist/lib/shader-assembly/shader-plugin-varyings.js +45 -19
  36. package/dist/lib/shader-assembly/shader-plugin-varyings.js.map +1 -1
  37. package/dist/lib/shader-generator/glsl/generate-glsl.d.ts +1 -1
  38. package/dist/lib/shader-generator/glsl/generate-glsl.d.ts.map +1 -1
  39. package/dist/lib/shader-generator/wgsl/generate-wgsl.d.ts +1 -1
  40. package/dist/lib/shader-generator/wgsl/generate-wgsl.d.ts.map +1 -1
  41. package/dist/lib/shader-plugin.cjs +44 -30
  42. package/dist/lib/shader-plugin.d.ts +33 -32
  43. package/dist/lib/shader-plugin.d.ts.map +1 -1
  44. package/dist/lib/shader-plugin.js +49 -31
  45. package/dist/lib/shader-plugin.js.map +1 -1
  46. package/dist/lib/wgsl-shader-assembler.cjs +1 -1
  47. package/dist/lib/wgsl-shader-assembler.js +1 -1
  48. package/dist/lib/wgsl-shader-assembler.js.map +1 -1
  49. package/dist/modules/engine/clip/clip.cjs +18 -30
  50. package/dist/modules/engine/clip/clip.d.ts.map +1 -1
  51. package/dist/modules/engine/clip/clip.js +19 -31
  52. package/dist/modules/engine/clip/clip.js.map +1 -1
  53. package/dist/modules/engine/filter/filter.cjs +9 -18
  54. package/dist/modules/engine/filter/filter.d.ts.map +1 -1
  55. package/dist/modules/engine/filter/filter.js +9 -18
  56. package/dist/modules/engine/filter/filter.js.map +1 -1
  57. package/dist/modules/math/fp64/fp64.cjs +1 -1
  58. package/dist/modules/math/fp64/fp64.d.ts +1 -1
  59. package/dist/modules/math/fp64/fp64.d.ts.map +1 -1
  60. package/dist/modules/math/fp64/fp64.js +1 -1
  61. package/dist/modules/math/fp64/fp64.js.map +1 -1
  62. package/dist/types.cjs +27 -16
  63. package/dist/types.d.ts +7 -7
  64. package/dist/types.d.ts.map +1 -1
  65. package/dist/types.js +2 -7
  66. package/dist/types.js.map +1 -1
  67. package/dist/wgsl.cjs +20 -4
  68. package/dist/wgsl.cjs.map +1 -1
  69. package/dist/wgsl.d.ts +1 -1
  70. package/dist/wgsl.d.ts.map +1 -1
  71. package/dist/wgsl.js +1 -1
  72. package/dist/wgsl.js.map +1 -1
  73. package/package.json +3 -3
  74. package/src/index.ts +3 -4
  75. package/src/lib/glsl-shader-assembler.ts +1 -1
  76. package/src/lib/preprocessor/preprocessor.ts +25 -0
  77. package/src/lib/shader-assembly/assemble-glsl-shaders.ts +17 -22
  78. package/src/lib/shader-assembly/assemble-wgsl-shaders.ts +8 -8
  79. package/src/lib/shader-assembly/shader-assembly-types.ts +7 -7
  80. package/src/lib/shader-assembly/shader-hooks.ts +6 -1
  81. package/src/lib/shader-assembly/shader-injections.ts +2 -0
  82. package/src/lib/shader-assembly/shader-plugin-varyings.ts +58 -27
  83. package/src/lib/shader-generator/glsl/generate-glsl.ts +1 -1
  84. package/src/lib/shader-generator/wgsl/generate-wgsl.ts +1 -1
  85. package/src/lib/shader-module/shader-module-dependencies.ts +1 -1
  86. package/src/lib/shader-plugin.ts +75 -68
  87. package/src/lib/wgsl-shader-assembler.ts +1 -1
  88. package/src/modules/engine/clip/clip.ts +19 -31
  89. package/src/modules/engine/filter/filter.ts +9 -18
  90. package/src/modules/math/fp64/fp64.ts +1 -1
  91. package/src/types.ts +75 -7
  92. package/src/wgsl.ts +12 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@luma.gl/shaders",
3
- "version": "10.0.0-alpha.5",
3
+ "version": "10.0.0-alpha.7",
4
4
  "description": "Shader module system for luma.gl",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -61,7 +61,7 @@
61
61
  "prepublishOnly": "npm run build-minified-bundle && npm run build-dev-bundle"
62
62
  },
63
63
  "dependencies": {
64
- "@math.gl/core": "~5.0.0-beta.1"
64
+ "@math.gl/core": "~5.0.0-beta.2"
65
65
  },
66
- "gitHead": "c636c34b8f1581eed163e94543a8eb1f4382ba8e"
66
+ "gitHead": "e3979f06848a6d04547ac7a26f844212ba569806"
67
67
  }
package/src/index.ts CHANGED
@@ -20,13 +20,12 @@ export {
20
20
  export type {ShaderModule} from './lib/shader-module/shader-module';
21
21
  export type {
22
22
  ResolvedShaderPlugins,
23
- ResolvedShaderPluginVarying,
23
+ ResolvedShaderPluginInterStageVariable,
24
24
  ShaderPlugin,
25
25
  ShaderPluginInjection,
26
26
  ShaderPluginInjectionTarget,
27
- ShaderPluginVarying,
28
- ShaderPluginVaryingInterpolation,
29
- ShaderPluginVariant
27
+ ShaderPluginInterStageVariable,
28
+ ShaderPluginInterStageVariableInterpolation
30
29
  } from './lib/shader-plugin';
31
30
  export type {
32
31
  ShaderPass,
@@ -23,7 +23,7 @@ export class GLSLShaderAssembler extends ShaderAssembler {
23
23
  modules: ShaderModule[];
24
24
  } {
25
25
  const modules = this._getModuleList(props.modules); // Combine with default modules
26
- const hookFunctions = this._hookFunctions; // TODO - combine with default hook functions
26
+ const hookFunctions = [...this._hookFunctions, ...(props.hookFunctions || [])];
27
27
  const vertex = this._transpileShader(props, modules, props.vs, 'vertex');
28
28
  const fragment = this._transpileShader(props, modules, props.fs, 'fragment');
29
29
  const assembled = assembleGLSLShaderPair({
@@ -104,6 +104,31 @@ function evaluateIfExpression(
104
104
  return false;
105
105
  }
106
106
 
107
+ const operandPattern = '(?:[A-Za-z_][A-Za-z0-9_]*|[+-]?\\d+(?:\\.\\d+)?)';
108
+ const comparison = trimmedExpression.match(
109
+ new RegExp(`^(${operandPattern})\\s*(==|!=|<=|>=|<|>)\\s*(${operandPattern})$`)
110
+ );
111
+ if (comparison) {
112
+ const resolveOperand = (operand: string) =>
113
+ /^[A-Za-z_]/.test(operand) ? Number(defines[operand] ?? 0) : Number(operand);
114
+ const left = resolveOperand(comparison[1]);
115
+ const right = resolveOperand(comparison[3]);
116
+ switch (comparison[2]) {
117
+ case '==':
118
+ return left === right;
119
+ case '!=':
120
+ return left !== right;
121
+ case '<=':
122
+ return left <= right;
123
+ case '>=':
124
+ return left >= right;
125
+ case '<':
126
+ return left < right;
127
+ case '>':
128
+ return left > right;
129
+ }
130
+ }
131
+
107
132
  const negatedDefineMatch = trimmedExpression.match(new RegExp(`^!\\s*${DEFINE_NAME_PATTERN}$`));
108
133
  if (negatedDefineMatch) {
109
134
  return !Boolean(defines[negatedDefineMatch[1]]);
@@ -24,12 +24,12 @@ import {
24
24
  } from './shader-hooks';
25
25
  import {type ShaderInjection, injectShader} from './shader-injections';
26
26
  import {type AttributeShaderType} from '../../types';
27
- import {type ResolvedShaderPluginVarying} from '../shader-plugin';
27
+ import {type ResolvedShaderPluginInterStageVariable} from '../shader-plugin';
28
28
  import {assert} from '../utils/assert';
29
29
  import {getShaderInfo} from '../glsl-utils/get-shader-info';
30
30
  import {getPlatformShaderDefines} from './platform-defines';
31
31
  import {getShaderPluginVertexInputDeclarationsGLSL} from './shader-plugin-vertex-inputs';
32
- import {assembleShaderPluginVaryingsGLSL} from './shader-plugin-varyings';
32
+ import {assembleShaderPluginInterStageVariablesGLSL} from './shader-plugin-varyings';
33
33
  import {transpileGLSLShader} from '../shader-transpiler/transpile-glsl-shader';
34
34
  import {warnIfGLSLUniformBlocksAreNotStd140} from '../shader-module/shader-module-uniform-layout';
35
35
 
@@ -97,7 +97,7 @@ export function assembleShaderGLSL(
97
97
  inject?: Record<string, string | ShaderInjection>;
98
98
  pluginInjections?: Record<string, ShaderInjection[]>;
99
99
  pluginVertexInputs?: Record<string, AttributeShaderType>;
100
- pluginVaryings?: Record<string, ResolvedShaderPluginVarying>;
100
+ pluginInterStageVariables?: Record<string, ResolvedShaderPluginInterStageVariable>;
101
101
  prologue?: boolean;
102
102
  log?: ShaderAssemblyLog;
103
103
  }
@@ -112,7 +112,7 @@ export function assembleShaderGLSL(
112
112
  inject = {},
113
113
  pluginInjections = {},
114
114
  pluginVertexInputs = {},
115
- pluginVaryings = {},
115
+ pluginInterStageVariables = {},
116
116
  prologue = true,
117
117
  log
118
118
  } = options;
@@ -181,36 +181,31 @@ ${getApplicationDefines(allDefines)}
181
181
  const name = match[3];
182
182
  if (hash) {
183
183
  if (name === 'decl') {
184
- declInjections[key] = [injection];
184
+ declInjections[key] = [...(declInjections[key] || []), injection];
185
185
  } else {
186
- mainInjections[key] = [injection];
186
+ mainInjections[key] = [...(mainInjections[key] || []), injection];
187
187
  }
188
188
  } else {
189
- hookInjections[key] = [injection];
189
+ hookInjections[key] = [...(hookInjections[key] || []), injection];
190
190
  }
191
191
  } else {
192
192
  // Regex injection
193
- mainInjections[key] = [injection];
193
+ mainInjections[key] = [...(mainInjections[key] || []), injection];
194
194
  }
195
195
  }
196
+ // Module helpers may access plugin inputs and varyings. GLSL requires these
197
+ // interface declarations before the helpers, unlike ordinary #decl injections.
196
198
  if (stage === 'vertex') {
197
199
  const declarations = getShaderPluginVertexInputDeclarationsGLSL(coreSource, pluginVertexInputs);
198
- if (declarations) {
199
- declInjections['vs:#decl'] = declInjections['vs:#decl'] || [];
200
- declInjections['vs:#decl'].push({
201
- injection: declarations,
202
- order: Number.MIN_SAFE_INTEGER
203
- });
204
- }
200
+ if (declarations) assembledSource += `${declarations}\n`;
205
201
  }
206
- const pluginVaryingAssembly = assembleShaderPluginVaryingsGLSL(coreSource, stage, pluginVaryings);
202
+ const pluginVaryingAssembly = assembleShaderPluginInterStageVariablesGLSL(
203
+ coreSource,
204
+ stage,
205
+ pluginInterStageVariables
206
+ );
207
207
  if (pluginVaryingAssembly.declarations) {
208
- const declarationTarget = stage === 'vertex' ? 'vs:#decl' : 'fs:#decl';
209
- declInjections[declarationTarget] = declInjections[declarationTarget] || [];
210
- declInjections[declarationTarget].push({
211
- injection: pluginVaryingAssembly.declarations,
212
- order: Number.MIN_SAFE_INTEGER
213
- });
208
+ assembledSource += `${pluginVaryingAssembly.declarations}\n`;
214
209
  }
215
210
  if (pluginVaryingAssembly.initialization) {
216
211
  mainInjections['vs:#main-start'] = mainInjections['vs:#main-start'] || [];
@@ -26,7 +26,7 @@ import {PlatformInfo} from './platform-info';
26
26
  import {assert} from '../utils/assert';
27
27
  import {preprocess} from '../preprocessor/preprocessor';
28
28
  import {assembleShaderPluginVertexInputsWGSL} from './shader-plugin-vertex-inputs';
29
- import {assembleShaderPluginVaryingsWGSL} from './shader-plugin-varyings';
29
+ import {assembleShaderPluginInterStageVariablesWGSL} from './shader-plugin-varyings';
30
30
  import {
31
31
  normalizeShaderHooks,
32
32
  validateShaderHookInjections,
@@ -113,7 +113,7 @@ export function assembleShaderWGSL(
113
113
  inject = {},
114
114
  pluginInjections = {},
115
115
  pluginVertexInputs = {},
116
- pluginVaryings = {},
116
+ pluginInterStageVariables = {},
117
117
  vertexEntryPoint = 'vertexMain',
118
118
  fragmentEntryPoint = 'fragmentMain',
119
119
  log
@@ -130,11 +130,11 @@ export function assembleShaderWGSL(
130
130
  vertexEntryPoint,
131
131
  pluginVertexInputs
132
132
  );
133
- const pluginVaryingAssembly = assembleShaderPluginVaryingsWGSL(
133
+ const pluginVaryingAssembly = assembleShaderPluginInterStageVariablesWGSL(
134
134
  pluginVertexInputAssembly.source,
135
135
  vertexEntryPoint,
136
136
  fragmentEntryPoint,
137
- pluginVaryings
137
+ pluginInterStageVariables
138
138
  );
139
139
  const coreSource = pluginVaryingAssembly.source;
140
140
 
@@ -177,16 +177,16 @@ export function assembleShaderWGSL(
177
177
  const name = match[3];
178
178
  if (hash) {
179
179
  if (name === 'decl') {
180
- declInjections[key] = [injection];
180
+ declInjections[key] = [...(declInjections[key] || []), injection];
181
181
  } else {
182
- mainInjections[key] = [injection];
182
+ mainInjections[key] = [...(mainInjections[key] || []), injection];
183
183
  }
184
184
  } else {
185
- hookInjections[key] = [injection];
185
+ hookInjections[key] = [...(hookInjections[key] || []), injection];
186
186
  }
187
187
  } else {
188
188
  // Regex injection
189
- mainInjections[key] = [injection];
189
+ mainInjections[key] = [...(mainInjections[key] || []), injection];
190
190
  }
191
191
  }
192
192
  appendGeneratedVertexInputInjections(
@@ -7,7 +7,7 @@ import {type ShaderModule} from '../shader-module/shader-module';
7
7
  import {type ShaderHook} from './shader-hooks';
8
8
  import {type ShaderInjection} from './shader-injections';
9
9
  import {type AttributeShaderType} from '../../types';
10
- import {type ResolvedShaderPluginVarying} from '../shader-plugin';
10
+ import {type ResolvedShaderPluginInterStageVariable} from '../shader-plugin';
11
11
 
12
12
  export type ShaderAssemblyLog = {
13
13
  deprecated?: (...args: unknown[]) => () => unknown;
@@ -44,7 +44,7 @@ export type AssembleShaderOptions = {
44
44
  defines?: Record<string, boolean | number>;
45
45
  /** GLSL only: Overrides to be injected. In WGSL these are supplied during Pipeline creation time */
46
46
  constants?: Record<string, number>;
47
- /** Hook functions */
47
+ /** Per-call hooks, appended after registered assembler hooks; matching names override for this call. */
48
48
  hookFunctions?: readonly (ShaderHook | string)[];
49
49
  /** Code injections */
50
50
  inject?: Record<string, string | ShaderInjection>;
@@ -52,8 +52,8 @@ export type AssembleShaderOptions = {
52
52
  pluginInjections?: Record<string, ShaderInjection[]>;
53
53
  /** Vertex inputs contributed by ShaderPlugin descriptors. */
54
54
  pluginVertexInputs?: Record<string, AttributeShaderType>;
55
- /** Cross-stage varyings contributed by ShaderPlugin descriptors. */
56
- pluginVaryings?: Record<string, ResolvedShaderPluginVarying>;
55
+ /** Inter-stage variables contributed by ShaderPlugin descriptors. */
56
+ pluginInterStageVariables?: Record<string, ResolvedShaderPluginInterStageVariable>;
57
57
  /** WGSL vertex entry point selected by the render pipeline. */
58
58
  vertexEntryPoint?: string;
59
59
  /** Whether WGSL interface scanning should include vertex attributes. */
@@ -78,7 +78,7 @@ export type AssembleStageOptions = {
78
78
  defines?: Record<string, boolean | number>;
79
79
  /** GLSL only: Overrides to be injected. In WGSL these are supplied during Pipeline creation time */
80
80
  constants?: Record<string, number>;
81
- /** Hook functions */
81
+ /** Per-call hooks, appended after registered assembler hooks; matching names override for this call. */
82
82
  hookFunctions?: readonly (ShaderHook | string)[];
83
83
  /** Code injections */
84
84
  inject?: Record<string, string | ShaderInjection>;
@@ -86,8 +86,8 @@ export type AssembleStageOptions = {
86
86
  pluginInjections?: Record<string, ShaderInjection[]>;
87
87
  /** Vertex inputs contributed by ShaderPlugin descriptors. */
88
88
  pluginVertexInputs?: Record<string, AttributeShaderType>;
89
- /** Cross-stage varyings contributed by ShaderPlugin descriptors. */
90
- pluginVaryings?: Record<string, ResolvedShaderPluginVarying>;
89
+ /** Inter-stage variables contributed by ShaderPlugin descriptors. */
90
+ pluginInterStageVariables?: Record<string, ResolvedShaderPluginInterStageVariable>;
91
91
  /** WGSL vertex entry point selected by the render pipeline. */
92
92
  vertexEntryPoint?: string;
93
93
  /** WGSL fragment entry point selected by the render pipeline. */
@@ -106,7 +106,12 @@ export function validateShaderHookInjections(
106
106
 
107
107
  if (!isShaderHookRegistered(registry, hookName)) {
108
108
  // The injection targets a hook that was not declared for this stage.
109
- throw new Error(`Unknown shader hook ${hookName}`);
109
+ const pluginNames = [
110
+ ...new Set(hookInjections[hookName].map(injection => injection.pluginName).filter(Boolean))
111
+ ];
112
+ throw new Error(
113
+ `Unknown shader hook ${hookName}${pluginNames.length ? ` (plugins: ${pluginNames.join(', ')})` : ''}`
114
+ );
110
115
  }
111
116
  }
112
117
  }
@@ -21,6 +21,8 @@ export const DECLARATION_INJECT_MARKER = '__LUMA_INJECT_DECLARATIONS__';
21
21
  *
22
22
  */
23
23
  export type ShaderInjection = {
24
+ /** Plugin responsible for this injection, when supplied by a ShaderPlugin. */
25
+ pluginName?: string;
24
26
  injection: string;
25
27
  order: number;
26
28
  };
@@ -3,10 +3,11 @@
3
3
  // SPDX-FileCopyrightText: Copyright (c) vis.gl contributors
4
4
 
5
5
  import {shaderTypeDecoder} from '../../types';
6
- import type {ResolvedShaderPluginVarying} from '../shader-plugin';
6
+ import type {ResolvedShaderPluginInterStageVariable} from '../shader-plugin';
7
7
  import {getGLSLAttributeType} from './shader-plugin-vertex-inputs';
8
+ import {maskWGSLComments} from './wgsl-binding-scan';
8
9
 
9
- export type ShaderPluginVaryingAssembly = {
10
+ export type ShaderPluginInterStageVariableAssembly = {
10
11
  source: string;
11
12
  declarations: string;
12
13
  vertexInitialization: string;
@@ -14,14 +15,14 @@ export type ShaderPluginVaryingAssembly = {
14
15
  };
15
16
 
16
17
  /** Generate one stage of the GLSL interface contributed by shader plugins. */
17
- export function assembleShaderPluginVaryingsGLSL(
18
+ export function assembleShaderPluginInterStageVariablesGLSL(
18
19
  source: string,
19
20
  stage: 'vertex' | 'fragment',
20
- varyings: Record<string, ResolvedShaderPluginVarying>
21
+ interStageVariables: Record<string, ResolvedShaderPluginInterStageVariable>
21
22
  ): {declarations: string; initialization: string} {
22
23
  const declarations: string[] = [];
23
24
  const initialization: string[] = [];
24
- for (const [name, varying] of Object.entries(varyings)) {
25
+ for (const [name, varying] of Object.entries(interStageVariables)) {
25
26
  assertGLSLVaryingIsNew(source, name);
26
27
  const qualifier = varying.interpolation === 'flat' ? 'flat ' : '';
27
28
  const direction = stage === 'vertex' ? 'out' : 'in';
@@ -33,14 +34,14 @@ export function assembleShaderPluginVaryingsGLSL(
33
34
  return {declarations: declarations.join('\n'), initialization: initialization.join('\n')};
34
35
  }
35
36
 
36
- /** Add plugin varyings to selected WGSL vertex and fragment entry points. */
37
- export function assembleShaderPluginVaryingsWGSL(
37
+ /** Add plugin interStageVariables to selected WGSL vertex and fragment entry points. */
38
+ export function assembleShaderPluginInterStageVariablesWGSL(
38
39
  source: string,
39
40
  vertexEntryPoint: string,
40
41
  fragmentEntryPoint: string,
41
- varyings: Record<string, ResolvedShaderPluginVarying>
42
- ): ShaderPluginVaryingAssembly {
43
- const entries = Object.entries(varyings);
42
+ interStageVariables: Record<string, ResolvedShaderPluginInterStageVariable>
43
+ ): ShaderPluginInterStageVariableAssembly {
44
+ const entries = Object.entries(interStageVariables);
44
45
  if (entries.length === 0) {
45
46
  return {
46
47
  source,
@@ -56,19 +57,23 @@ export function assembleShaderPluginVaryingsWGSL(
56
57
  let fragmentFunction = getWGSLFunctionRange(transformedSource, fragmentEntryPoint, 'fragment');
57
58
  const fragmentInput = getWGSLFragmentStructInput(transformedSource, fragmentFunction);
58
59
  const vertexOutputStruct = getWGSLStructRange(transformedSource, vertexOutputType);
59
- const fragmentInputStruct = getWGSLStructRange(transformedSource, fragmentInput.type);
60
+ const fragmentInputStruct = fragmentInput
61
+ ? getWGSLStructRange(transformedSource, fragmentInput.type)
62
+ : null;
60
63
 
61
64
  const interfaceNames = new Set([
62
65
  ...getWGSLDeclaredNames(vertexFunction.parameters),
63
66
  ...getWGSLDeclaredNames(vertexOutputStruct.body),
64
67
  ...getWGSLDeclaredNames(fragmentFunction.parameters),
65
- ...getWGSLDeclaredNames(fragmentInputStruct.body)
68
+ ...getWGSLDeclaredNames(fragmentInputStruct?.body || '')
66
69
  ]);
67
70
  const usedLocations = new Set([
68
71
  ...getWGSLLocations(vertexOutputStruct.body),
69
- ...getWGSLLocations(fragmentInputStruct.body)
72
+ ...getWGSLLocations(fragmentInputStruct?.body || ''),
73
+ ...getWGSLLocations(fragmentFunction.parameters)
70
74
  ]);
71
75
  const fields: string[] = [];
76
+ const fragmentParameters: string[] = [];
72
77
  const declarations: string[] = [];
73
78
  const vertexInitialization: string[] = [];
74
79
  const fragmentInitialization: string[] = [];
@@ -85,7 +90,20 @@ export function assembleShaderPluginVaryingsWGSL(
85
90
  fields.push(` @location(${location})${interpolation} ${name}: ${varying.type},`);
86
91
  declarations.push(`var<private> ${name}: ${varying.type};`);
87
92
  vertexInitialization.push(`${name} = ${getWGSLZeroValue(varying.type)};`);
88
- fragmentInitialization.push(`${name} = ${fragmentInput.name}.${name};`);
93
+ if (fragmentInput) {
94
+ fragmentInitialization.push(`${name} = ${fragmentInput.name}.${name};`);
95
+ } else {
96
+ const parameterName = `_luma_${name}`;
97
+ if (interfaceNames.has(parameterName)) {
98
+ throw new Error(
99
+ `ShaderPlugin varying "${name}" conflicts with a generated fragment parameter`
100
+ );
101
+ }
102
+ fragmentParameters.push(
103
+ `@location(${location})${interpolation} ${parameterName}: ${varying.type}`
104
+ );
105
+ fragmentInitialization.push(`${name} = ${parameterName};`);
106
+ }
89
107
  }
90
108
 
91
109
  assertWGSLStructConstructorsAreLocal(
@@ -108,7 +126,7 @@ export function assembleShaderPluginVaryingsWGSL(
108
126
  );
109
127
 
110
128
  const structNames =
111
- vertexOutputType === fragmentInput.type
129
+ !fragmentInput || vertexOutputType === fragmentInput.type
112
130
  ? [vertexOutputType]
113
131
  : [vertexOutputType, fragmentInput.type];
114
132
  const structInsertions = structNames
@@ -122,9 +140,20 @@ export function assembleShaderPluginVaryingsWGSL(
122
140
  }
123
141
 
124
142
  fragmentFunction = getWGSLFunctionRange(transformedSource, fragmentEntryPoint, 'fragment');
125
- const fragmentInputPattern = new RegExp(`\\b${escapeRegExp(fragmentInput.name)}\\s*:`);
126
- if (!fragmentInputPattern.test(fragmentFunction.parameters)) {
127
- throw new Error(`Unable to preserve WGSL fragment input "${fragmentInput.name}"`);
143
+ if (fragmentParameters.length) {
144
+ let parameters = fragmentFunction.parameters;
145
+ const parameterTokens = maskWGSLComments(parameters).trimEnd();
146
+ if (parameterTokens.trim() && !parameterTokens.endsWith(',')) {
147
+ const insertionIndex = parameterTokens.length;
148
+ parameters = `${parameters.slice(0, insertionIndex)},${parameters.slice(insertionIndex)}`;
149
+ }
150
+ transformedSource =
151
+ transformedSource.slice(0, fragmentFunction.openParenthesis + 1) +
152
+ parameters +
153
+ '\n ' +
154
+ fragmentParameters.join(',\n ') +
155
+ '\n' +
156
+ transformedSource.slice(fragmentFunction.closeParenthesis);
128
157
  }
129
158
 
130
159
  return {
@@ -157,7 +186,9 @@ function getWGSLFunctionRange(
157
186
  const functionPattern = new RegExp(`\\bfn\\s+${escapeRegExp(entryPoint)}\\s*\\(`, 'g');
158
187
  const match = functionPattern.exec(source);
159
188
  if (!match) {
160
- throw new Error(`ShaderPlugin varyings require WGSL ${stage} entry point "${entryPoint}"`);
189
+ throw new Error(
190
+ `ShaderPlugin interStageVariables require WGSL ${stage} entry point "${entryPoint}"`
191
+ );
161
192
  }
162
193
  const openParenthesis = source.indexOf('(', match.index);
163
194
  const closeParenthesis = findMatchingDelimiter(source, openParenthesis, '(', ')');
@@ -180,7 +211,7 @@ function getWGSLNamedReturnType(source: string, functionRange: WGSLFunctionRange
180
211
  const match = /->\s*([A-Za-z_][\w]*)\s*$/.exec(resultSource.trim());
181
212
  if (!match || getWGSLStructRangeOrNull(source, match[1]) === null) {
182
213
  throw new Error(
183
- 'ShaderPlugin varyings require the WGSL vertex entry point to return a named struct'
214
+ 'ShaderPlugin interStageVariables require the WGSL vertex entry point to return a named struct'
184
215
  );
185
216
  }
186
217
  return match[1];
@@ -189,9 +220,9 @@ function getWGSLNamedReturnType(source: string, functionRange: WGSLFunctionRange
189
220
  function getWGSLFragmentStructInput(
190
221
  source: string,
191
222
  functionRange: WGSLFunctionRange
192
- ): {name: string; type: string} {
223
+ ): {name: string; type: string} | null {
193
224
  const candidates: {name: string; type: string}[] = [];
194
- for (const parameter of splitTopLevel(functionRange.parameters, ',')) {
225
+ for (const parameter of splitTopLevel(maskWGSLComments(functionRange.parameters), ',')) {
195
226
  const match =
196
227
  /(?:@[A-Za-z_][\w]*(?:\([^)]*\))?\s*)*([A-Za-z_][\w]*)\s*:\s*([A-Za-z_][\w]*)\s*$/.exec(
197
228
  parameter.trim()
@@ -200,12 +231,12 @@ function getWGSLFragmentStructInput(
200
231
  candidates.push({name: match[1], type: match[2]});
201
232
  }
202
233
  }
203
- if (candidates.length !== 1) {
234
+ if (candidates.length > 1) {
204
235
  throw new Error(
205
- `ShaderPlugin varyings require exactly one named WGSL fragment input struct; found ${candidates.length}`
236
+ `ShaderPlugin interStageVariables require exactly one named WGSL fragment input struct; found ${candidates.length}`
206
237
  );
207
238
  }
208
- return candidates[0];
239
+ return candidates[0] || null;
209
240
  }
210
241
 
211
242
  function getWGSLStructRange(source: string, structName: string): WGSLStructRange {
@@ -440,13 +471,13 @@ function getFirstUnusedLocation(usedLocations: Set<number>): number {
440
471
  return location;
441
472
  }
442
473
 
443
- function getGLSLZeroValue(type: ResolvedShaderPluginVarying['type']): string {
474
+ function getGLSLZeroValue(type: ResolvedShaderPluginInterStageVariable['type']): string {
444
475
  const {primitiveType, components} = shaderTypeDecoder.getAttributeShaderTypeInfo(type);
445
476
  const scalar = primitiveType === 'u32' ? '0u' : primitiveType === 'i32' ? '0' : '0.0';
446
477
  return components === 1 ? scalar : `${getGLSLAttributeType(type)}(${scalar})`;
447
478
  }
448
479
 
449
- function getWGSLZeroValue(type: ResolvedShaderPluginVarying['type']): string {
480
+ function getWGSLZeroValue(type: ResolvedShaderPluginInterStageVariable['type']): string {
450
481
  const {primitiveType, components} = shaderTypeDecoder.getAttributeShaderTypeInfo(type);
451
482
  const scalar = `${primitiveType}(0)`;
452
483
  return components === 1 ? scalar : `${type}(${scalar})`;
@@ -3,7 +3,7 @@
3
3
  // SPDX-FileCopyrightText: Copyright (c) vis.gl contributors
4
4
 
5
5
  import {UniformFormat} from '../../../types';
6
- import {ShaderModule} from '../../../lib/shader-module/shader-module';
6
+ import {ShaderModule} from '../../shader-module/shader-module';
7
7
  import {capitalize} from '../utils/capitalize';
8
8
 
9
9
  export type GLSLGenerationOptions = {
@@ -2,7 +2,7 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // SPDX-FileCopyrightText: Copyright (c) vis.gl contributors
4
4
 
5
- import {ShaderModule} from '../../../lib/shader-module/shader-module';
5
+ import {ShaderModule} from '../../shader-module/shader-module';
6
6
  import {capitalize} from '../utils/capitalize';
7
7
 
8
8
  export type WGSLGenerationOptions = {
@@ -5,7 +5,7 @@
5
5
  import {ShaderModule, initializeShaderModules} from './shader-module';
6
6
  import {assert} from '../utils/assert';
7
7
 
8
- // import type {ShaderModule} from '../shader-module/shader-module';
8
+ // import type {ShaderModule} from './shader-module';
9
9
 
10
10
  type AbstractModule = {
11
11
  name: string;