@luma.gl/shaders 10.0.0-alpha.7 → 10.0.0-alpha.9
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 +233 -249
- package/dist/dist.min.js +124 -124
- package/dist/glsl.cjs.map +2 -2
- package/dist/index.cjs.map +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/shader-assembler-base.cjs +3 -4
- package/dist/lib/shader-assembler-base.d.ts +4 -5
- package/dist/lib/shader-assembler-base.d.ts.map +1 -1
- package/dist/lib/shader-assembler-base.js +3 -4
- package/dist/lib/shader-assembler-base.js.map +1 -1
- package/dist/lib/shader-assembly/assemble-glsl-shaders.cjs +6 -17
- package/dist/lib/shader-assembly/assemble-glsl-shaders.d.ts +5 -4
- package/dist/lib/shader-assembly/assemble-glsl-shaders.d.ts.map +1 -1
- package/dist/lib/shader-assembly/assemble-glsl-shaders.js +14 -19
- package/dist/lib/shader-assembly/assemble-glsl-shaders.js.map +1 -1
- package/dist/lib/shader-assembly/assemble-wgsl-shaders.cjs +6 -25
- package/dist/lib/shader-assembly/assemble-wgsl-shaders.d.ts +5 -6
- package/dist/lib/shader-assembly/assemble-wgsl-shaders.d.ts.map +1 -1
- package/dist/lib/shader-assembly/assemble-wgsl-shaders.js +14 -27
- package/dist/lib/shader-assembly/assemble-wgsl-shaders.js.map +1 -1
- package/dist/lib/shader-assembly/shader-assembly-shared.d.ts +2 -2
- package/dist/lib/shader-assembly/shader-assembly-shared.d.ts.map +1 -1
- package/dist/lib/shader-assembly/shader-assembly-shared.js.map +1 -1
- package/dist/lib/shader-assembly/shader-assembly-types.d.ts +11 -7
- package/dist/lib/shader-assembly/shader-assembly-types.d.ts.map +1 -1
- package/dist/lib/shader-assembly/shader-hooks.cjs +26 -29
- package/dist/lib/shader-assembly/shader-hooks.d.ts +34 -32
- package/dist/lib/shader-assembly/shader-hooks.d.ts.map +1 -1
- package/dist/lib/shader-assembly/shader-hooks.js +29 -33
- package/dist/lib/shader-assembly/shader-hooks.js.map +1 -1
- package/dist/lib/shader-assembly/shader-injections.cjs +26 -2
- package/dist/lib/shader-assembly/shader-injections.d.ts +20 -7
- package/dist/lib/shader-assembly/shader-injections.d.ts.map +1 -1
- package/dist/lib/shader-assembly/shader-injections.js +24 -0
- package/dist/lib/shader-assembly/shader-injections.js.map +1 -1
- package/dist/lib/shader-module/shader-module.cjs +3 -9
- package/dist/lib/shader-module/shader-module.d.ts +4 -8
- package/dist/lib/shader-module/shader-module.d.ts.map +1 -1
- package/dist/lib/shader-module/shader-module.js +3 -6
- package/dist/lib/shader-module/shader-module.js.map +1 -1
- package/dist/lib/shader-plugin.cjs +38 -17
- package/dist/lib/shader-plugin.d.ts +9 -17
- package/dist/lib/shader-plugin.d.ts.map +1 -1
- package/dist/lib/shader-plugin.js +43 -16
- package/dist/lib/shader-plugin.js.map +1 -1
- package/dist/modules/engine/clip/clip.cjs +4 -2
- package/dist/modules/engine/clip/clip.d.ts.map +1 -1
- package/dist/modules/engine/clip/clip.js +4 -2
- package/dist/modules/engine/clip/clip.js.map +1 -1
- package/dist/modules/engine/filter/filter.cjs +2 -1
- package/dist/modules/engine/filter/filter.d.ts.map +1 -1
- package/dist/modules/engine/filter/filter.js +2 -1
- package/dist/modules/engine/filter/filter.js.map +1 -1
- package/dist/modules/lighting/lights/lighting.d.ts +1 -1
- package/dist/modules/lighting/lights/lighting.d.ts.map +1 -1
- package/dist/modules/lighting/pbr-material/pbr-material-glsl.cjs +2 -2
- package/dist/modules/lighting/pbr-material/pbr-material-glsl.d.ts +1 -1
- package/dist/modules/lighting/pbr-material/pbr-material-glsl.d.ts.map +1 -1
- package/dist/modules/lighting/pbr-material/pbr-material-glsl.js +2 -2
- package/dist/modules/lighting/pbr-material/pbr-material-wgsl.cjs +2 -2
- 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 +2 -2
- package/dist/modules/lighting/pbr-material/pbr-material.d.ts +2 -2
- package/dist/types/texture-formats.d.ts +1 -1
- package/dist/types/texture-formats.d.ts.map +1 -1
- package/dist/wgsl.cjs.map +2 -2
- package/package.json +3 -3
- package/src/index.ts +5 -4
- package/src/lib/shader-assembler-base.ts +5 -6
- package/src/lib/shader-assembly/assemble-glsl-shaders.ts +27 -26
- package/src/lib/shader-assembly/assemble-wgsl-shaders.ts +28 -43
- package/src/lib/shader-assembly/shader-assembly-shared.ts +5 -5
- package/src/lib/shader-assembly/shader-assembly-types.ts +11 -7
- package/src/lib/shader-assembly/shader-hooks.ts +65 -68
- package/src/lib/shader-assembly/shader-injections.ts +52 -8
- package/src/lib/shader-module/shader-module.ts +7 -14
- package/src/lib/shader-plugin.ts +59 -48
- package/src/modules/engine/clip/clip.ts +4 -2
- package/src/modules/engine/filter/filter.ts +2 -1
- package/src/modules/lighting/lights/lighting.ts +1 -1
- package/src/modules/lighting/pbr-material/pbr-material-glsl.ts +2 -2
- package/src/modules/lighting/pbr-material/pbr-material-wgsl.ts +2 -2
- package/src/types/texture-formats.ts +2 -0
|
@@ -27,13 +27,12 @@ import {assert} from '../utils/assert';
|
|
|
27
27
|
import {preprocess} from '../preprocessor/preprocessor';
|
|
28
28
|
import {assembleShaderPluginVertexInputsWGSL} from './shader-plugin-vertex-inputs';
|
|
29
29
|
import {assembleShaderPluginInterStageVariablesWGSL} from './shader-plugin-varyings';
|
|
30
|
+
import {normalizeShaderHooks, validateShaderHookInjections, getShaderHooks} from './shader-hooks';
|
|
30
31
|
import {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
} from './shader-hooks';
|
|
36
|
-
import {type ShaderInjection, injectShader} from './shader-injections';
|
|
32
|
+
type ResolvedShaderInjection,
|
|
33
|
+
injectShader,
|
|
34
|
+
resolveShaderInjections
|
|
35
|
+
} from './shader-injections';
|
|
37
36
|
import {checkShaderModuleDeprecations, type ShaderModule} from '../shader-module/shader-module';
|
|
38
37
|
import {
|
|
39
38
|
getWGSLBindingDeclarationMatches,
|
|
@@ -159,18 +158,27 @@ export function assembleShaderWGSL(
|
|
|
159
158
|
// `
|
|
160
159
|
// `;
|
|
161
160
|
|
|
162
|
-
const hookFunctionMap = normalizeShaderHooks(hookFunctions);
|
|
161
|
+
const hookFunctionMap = normalizeShaderHooks(hookFunctions, options.pluginHooks, 'wgsl');
|
|
163
162
|
|
|
164
163
|
// Add source of dependent modules in resolved order
|
|
165
|
-
const hookInjections: Record<string,
|
|
166
|
-
const declInjections: Record<string,
|
|
167
|
-
const mainInjections: Record<string,
|
|
164
|
+
const hookInjections: Record<string, ResolvedShaderInjection[]> = {};
|
|
165
|
+
const declInjections: Record<string, ResolvedShaderInjection[]> = {};
|
|
166
|
+
const mainInjections: Record<string, ResolvedShaderInjection[]> = {};
|
|
168
167
|
|
|
169
168
|
appendInjections(pluginInjections, hookInjections, declInjections, mainInjections);
|
|
170
169
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
170
|
+
const applicationInjections = Array.isArray(inject)
|
|
171
|
+
? resolveShaderInjections(inject, 'wgsl')
|
|
172
|
+
: {};
|
|
173
|
+
appendInjections(applicationInjections, hookInjections, declInjections, mainInjections);
|
|
174
|
+
const injectionMap = Array.isArray(inject)
|
|
175
|
+
? {}
|
|
176
|
+
: (inject as Record<string, string | ResolvedShaderInjection>);
|
|
177
|
+
for (const key in injectionMap) {
|
|
178
|
+
const injection: ResolvedShaderInjection =
|
|
179
|
+
typeof injectionMap[key] === 'string'
|
|
180
|
+
? {injection: injectionMap[key], order: 0}
|
|
181
|
+
: injectionMap[key];
|
|
174
182
|
const match = /^(v|f)s:(#)?([\w-]+)$/.exec(key);
|
|
175
183
|
if (match) {
|
|
176
184
|
const hash = match[2];
|
|
@@ -232,22 +240,6 @@ export function assembleShaderWGSL(
|
|
|
232
240
|
checkShaderModuleDeprecations(module, coreSource, log);
|
|
233
241
|
}
|
|
234
242
|
assembledSource += moduleSource;
|
|
235
|
-
|
|
236
|
-
const injections = getWGSLModuleInjections(module);
|
|
237
|
-
for (const key in injections) {
|
|
238
|
-
const match = /^(v|f)s:#([\w-]+)$/.exec(key);
|
|
239
|
-
if (match) {
|
|
240
|
-
const name = match[2];
|
|
241
|
-
const injectionType = name === 'decl' ? declInjections : mainInjections;
|
|
242
|
-
injectionType[key] = injectionType[key] || [];
|
|
243
|
-
injectionType[key].push(injections[key]);
|
|
244
|
-
} else if (isShaderHookRegistered(hookFunctionMap, key)) {
|
|
245
|
-
// `ShaderModule.inject` is not language-specific and often carries GLSL-only hook
|
|
246
|
-
// injections, so WGSL silently skips module injections into hooks it has not declared.
|
|
247
|
-
hookInjections[key] = hookInjections[key] || [];
|
|
248
|
-
hookInjections[key].push(injections[key]);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
243
|
}
|
|
252
244
|
|
|
253
245
|
// For injectShader
|
|
@@ -282,8 +274,8 @@ export function assembleShaderWGSL(
|
|
|
282
274
|
export function appendGeneratedVertexInputInjections(
|
|
283
275
|
declarations: string,
|
|
284
276
|
initialization: string,
|
|
285
|
-
declarationInjections: Record<string,
|
|
286
|
-
mainInjections: Record<string,
|
|
277
|
+
declarationInjections: Record<string, ResolvedShaderInjection[]>,
|
|
278
|
+
mainInjections: Record<string, ResolvedShaderInjection[]>
|
|
287
279
|
): void {
|
|
288
280
|
if (declarations) {
|
|
289
281
|
declarationInjections['vs:#decl'] = declarationInjections['vs:#decl'] || [];
|
|
@@ -307,8 +299,8 @@ export function appendGeneratedVaryingInjections(
|
|
|
307
299
|
vertexInitialization: string;
|
|
308
300
|
fragmentInitialization: string;
|
|
309
301
|
},
|
|
310
|
-
declarationInjections: Record<string,
|
|
311
|
-
mainInjections: Record<string,
|
|
302
|
+
declarationInjections: Record<string, ResolvedShaderInjection[]>,
|
|
303
|
+
mainInjections: Record<string, ResolvedShaderInjection[]>
|
|
312
304
|
): void {
|
|
313
305
|
if (assembly.declarations) {
|
|
314
306
|
declarationInjections['vs:#decl'] = declarationInjections['vs:#decl'] || [];
|
|
@@ -333,16 +325,9 @@ export function appendGeneratedVaryingInjections(
|
|
|
333
325
|
}
|
|
334
326
|
}
|
|
335
327
|
|
|
336
|
-
export function getWGSLModuleInjections(module: ShaderModule): Record<string, ShaderInjection> {
|
|
337
|
-
return {
|
|
338
|
-
...(module.instance?.normalizedInjections.vertex || {}),
|
|
339
|
-
...(module.instance?.normalizedInjections.fragment || {})
|
|
340
|
-
};
|
|
341
|
-
}
|
|
342
|
-
|
|
343
328
|
export function getWGSLDeclarationInjections(
|
|
344
|
-
declarationInjections: Record<string,
|
|
345
|
-
): Record<string,
|
|
329
|
+
declarationInjections: Record<string, ResolvedShaderInjection[]>
|
|
330
|
+
): Record<string, ResolvedShaderInjection[]> {
|
|
346
331
|
const unifiedDeclarations = [
|
|
347
332
|
...(declarationInjections['vs:#decl'] || []),
|
|
348
333
|
...(declarationInjections['fs:#decl'] || [])
|
|
@@ -353,7 +338,7 @@ export function getWGSLDeclarationInjections(
|
|
|
353
338
|
|
|
354
339
|
export function getWGSLShaderHooks(
|
|
355
340
|
hookFunctionMap: ReturnType<typeof normalizeShaderHooks>,
|
|
356
|
-
hookInjections: Record<string,
|
|
341
|
+
hookInjections: Record<string, ResolvedShaderInjection[]>
|
|
357
342
|
): string {
|
|
358
343
|
return (
|
|
359
344
|
getShaderHooks(hookFunctionMap.vertex, hookInjections, 'wgsl') +
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
3
|
// SPDX-FileCopyrightText: Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
|
-
import {DECLARATION_INJECT_MARKER, type
|
|
5
|
+
import {DECLARATION_INJECT_MARKER, type ResolvedShaderInjection} from './shader-injections';
|
|
6
6
|
import {type ShaderModule} from '../shader-module/shader-module';
|
|
7
7
|
import {assert} from '../utils/assert';
|
|
8
8
|
import {validateShaderModuleUniformLayout} from '../shader-module/shader-module-uniform-layout';
|
|
@@ -31,10 +31,10 @@ export function assembleGetUniforms(modules: ShaderModule[]) {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
export function appendInjections(
|
|
34
|
-
injections: Record<string,
|
|
35
|
-
hookInjections: Record<string,
|
|
36
|
-
declInjections: Record<string,
|
|
37
|
-
mainInjections: Record<string,
|
|
34
|
+
injections: Record<string, ResolvedShaderInjection[]>,
|
|
35
|
+
hookInjections: Record<string, ResolvedShaderInjection[]>,
|
|
36
|
+
declInjections: Record<string, ResolvedShaderInjection[]>,
|
|
37
|
+
mainInjections: Record<string, ResolvedShaderInjection[]>
|
|
38
38
|
): void {
|
|
39
39
|
for (const key in injections) {
|
|
40
40
|
const match = /^(v|f)s:(#)?([\w-]+)$/.exec(key);
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import {type PlatformInfo} from './platform-info';
|
|
6
6
|
import {type ShaderModule} from '../shader-module/shader-module';
|
|
7
7
|
import {type ShaderHook} from './shader-hooks';
|
|
8
|
-
import {type ShaderInjection} from './shader-injections';
|
|
8
|
+
import {type ShaderInjection, type ResolvedShaderInjection} from './shader-injections';
|
|
9
9
|
import {type AttributeShaderType} from '../../types';
|
|
10
10
|
import {type ResolvedShaderPluginInterStageVariable} from '../shader-plugin';
|
|
11
11
|
|
|
@@ -45,11 +45,13 @@ export type AssembleShaderOptions = {
|
|
|
45
45
|
/** GLSL only: Overrides to be injected. In WGSL these are supplied during Pipeline creation time */
|
|
46
46
|
constants?: Record<string, number>;
|
|
47
47
|
/** Per-call hooks, appended after registered assembler hooks; matching names override for this call. */
|
|
48
|
-
hookFunctions?: readonly
|
|
48
|
+
hookFunctions?: readonly ShaderHook[];
|
|
49
|
+
/** Hook declarations contributed by resolved plugins. */
|
|
50
|
+
pluginHooks?: readonly ShaderHook[];
|
|
49
51
|
/** Code injections */
|
|
50
|
-
inject?: Record<string, string |
|
|
52
|
+
inject?: readonly ShaderInjection[] | Record<string, string | ResolvedShaderInjection>;
|
|
51
53
|
/** Ordered code injections contributed by ShaderPlugin descriptors. */
|
|
52
|
-
pluginInjections?: Record<string,
|
|
54
|
+
pluginInjections?: Record<string, ResolvedShaderInjection[]>;
|
|
53
55
|
/** Vertex inputs contributed by ShaderPlugin descriptors. */
|
|
54
56
|
pluginVertexInputs?: Record<string, AttributeShaderType>;
|
|
55
57
|
/** Inter-stage variables contributed by ShaderPlugin descriptors. */
|
|
@@ -79,11 +81,13 @@ export type AssembleStageOptions = {
|
|
|
79
81
|
/** GLSL only: Overrides to be injected. In WGSL these are supplied during Pipeline creation time */
|
|
80
82
|
constants?: Record<string, number>;
|
|
81
83
|
/** Per-call hooks, appended after registered assembler hooks; matching names override for this call. */
|
|
82
|
-
hookFunctions?: readonly
|
|
84
|
+
hookFunctions?: readonly ShaderHook[];
|
|
85
|
+
/** Hook declarations contributed by resolved plugins. */
|
|
86
|
+
pluginHooks?: readonly ShaderHook[];
|
|
83
87
|
/** Code injections */
|
|
84
|
-
inject?: Record<string, string |
|
|
88
|
+
inject?: readonly ShaderInjection[] | Record<string, string | ResolvedShaderInjection>;
|
|
85
89
|
/** Ordered code injections contributed by ShaderPlugin descriptors. */
|
|
86
|
-
pluginInjections?: Record<string,
|
|
90
|
+
pluginInjections?: Record<string, ResolvedShaderInjection[]>;
|
|
87
91
|
/** Vertex inputs contributed by ShaderPlugin descriptors. */
|
|
88
92
|
pluginVertexInputs?: Record<string, AttributeShaderType>;
|
|
89
93
|
/** Inter-stage variables contributed by ShaderPlugin descriptors. */
|
|
@@ -2,51 +2,57 @@
|
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
3
|
// SPDX-FileCopyrightText: Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
|
-
import type {
|
|
5
|
+
import type {ResolvedShaderInjection} from './shader-injections';
|
|
6
6
|
|
|
7
|
-
/**
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
*
|
|
15
|
-
* If a shader module injects code it will be executed upon the hook
|
|
16
|
-
* function call.
|
|
17
|
-
*/
|
|
18
|
-
export type ShaderHook = {
|
|
19
|
-
/** `vs:` or `fs:` followed by the name and arguments of the function, e.g. `vs:MYHOOK_func(inout vec4 value)`. Hook name without arguments
|
|
20
|
-
will also be used as the name of the shader hook */
|
|
21
|
-
hook: string;
|
|
22
|
-
/** Code always included at the beginning of a hook function */
|
|
7
|
+
/** Language-specific source for a callable shader hook. */
|
|
8
|
+
export type ShaderHookImplementation = {
|
|
9
|
+
/** Function parameters in the selected shader language, without parentheses. */
|
|
10
|
+
parameters: string;
|
|
11
|
+
/** Return type in this language. Omit for a hook that returns no value. */
|
|
12
|
+
returnType?: string;
|
|
13
|
+
/** Source included before injected code. */
|
|
23
14
|
header?: string;
|
|
24
|
-
/**
|
|
15
|
+
/** Source included after injected code. */
|
|
25
16
|
footer?: string;
|
|
26
|
-
/** To Be Documented */
|
|
27
|
-
signature?: string;
|
|
28
17
|
};
|
|
29
18
|
|
|
30
|
-
/**
|
|
31
|
-
export type
|
|
19
|
+
/** One logical extension point with independent GLSL and WGSL syntax. */
|
|
20
|
+
export type ShaderHook = {
|
|
21
|
+
/** Function name shared by both shader languages. */
|
|
22
|
+
name: string;
|
|
23
|
+
/** Shader stage that owns the hook. */
|
|
24
|
+
stage: 'vertex' | 'fragment';
|
|
25
|
+
/** GLSL implementation. Omit to skip this hook during GLSL assembly. */
|
|
26
|
+
glsl?: ShaderHookImplementation;
|
|
27
|
+
/** WGSL implementation. Omit to skip this hook during WGSL assembly. */
|
|
28
|
+
wgsl?: ShaderHookImplementation;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/** Language-selected hook ready for source generation. */
|
|
32
|
+
type ResolvedShaderHook = ShaderHookImplementation & {signature: string};
|
|
32
33
|
|
|
33
|
-
/**
|
|
34
|
+
/** Normalized shader hooks per shader */
|
|
34
35
|
export type ShaderHookRegistry = {
|
|
35
|
-
vertex
|
|
36
|
-
|
|
36
|
+
/** Normalized shader hooks for vertex shader */
|
|
37
|
+
vertex: Record<string, ResolvedShaderHook>;
|
|
38
|
+
/** Normalized shader hooks for fragment shader */
|
|
39
|
+
fragment: Record<string, ResolvedShaderHook>;
|
|
37
40
|
};
|
|
38
41
|
|
|
39
42
|
/** Generate hook source code */
|
|
40
43
|
export function getShaderHooks(
|
|
41
|
-
hookFunctions: Record<string,
|
|
42
|
-
hookInjections: Record<string,
|
|
44
|
+
hookFunctions: Record<string, ResolvedShaderHook>,
|
|
45
|
+
hookInjections: Record<string, ResolvedShaderInjection[]>,
|
|
43
46
|
shaderLanguage: 'glsl' | 'wgsl' = 'glsl'
|
|
44
47
|
): string {
|
|
45
48
|
let result = '';
|
|
46
49
|
for (const hookName in hookFunctions) {
|
|
47
50
|
const hookFunction = hookFunctions[hookName];
|
|
48
|
-
const
|
|
49
|
-
|
|
51
|
+
const returnType = hookFunction.returnType || 'void';
|
|
52
|
+
const functionPrefix = shaderLanguage === 'wgsl' ? 'fn' : returnType;
|
|
53
|
+
const returnSuffix =
|
|
54
|
+
shaderLanguage === 'wgsl' && returnType !== 'void' ? ` -> ${returnType}` : '';
|
|
55
|
+
result += `${functionPrefix} ${hookFunction.signature}${returnSuffix} {\n`;
|
|
50
56
|
if (hookFunction.header) {
|
|
51
57
|
result += ` ${hookFunction.header}`;
|
|
52
58
|
}
|
|
@@ -66,19 +72,39 @@ export function getShaderHooks(
|
|
|
66
72
|
return result;
|
|
67
73
|
}
|
|
68
74
|
|
|
69
|
-
/**
|
|
70
|
-
* Parse string based hook functions and split them per shader stage.
|
|
71
|
-
* A later declaration of the same stage-prefixed hook name replaces an earlier one.
|
|
72
|
-
*/
|
|
75
|
+
/** Select language syntax and merge compatible plugin declarations without mutating descriptors. */
|
|
73
76
|
export function normalizeShaderHooks(
|
|
74
|
-
hookFunctions: readonly
|
|
77
|
+
hookFunctions: readonly ShaderHook[],
|
|
78
|
+
pluginHooks: readonly ShaderHook[] = [],
|
|
79
|
+
language: 'glsl' | 'wgsl' = 'glsl'
|
|
75
80
|
): ShaderHookRegistry {
|
|
76
81
|
const result: ShaderHookRegistry = {vertex: {}, fragment: {}};
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
82
|
+
for (const hook of hookFunctions) {
|
|
83
|
+
const implementation = hook[language];
|
|
84
|
+
if (implementation) {
|
|
85
|
+
const prefix = hook.stage === 'vertex' ? 'vs' : 'fs';
|
|
86
|
+
result[hook.stage][`${prefix}:${hook.name}`] = {
|
|
87
|
+
...implementation,
|
|
88
|
+
signature: `${hook.name}(${implementation.parameters})`
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
for (const hook of pluginHooks) {
|
|
93
|
+
const selected = normalizeShaderHooks([hook], [], language);
|
|
94
|
+
for (const stage of ['vertex', 'fragment'] as const) {
|
|
95
|
+
for (const [name, declaration] of Object.entries(selected[stage])) {
|
|
96
|
+
const existing = result[stage][name];
|
|
97
|
+
if (
|
|
98
|
+
existing &&
|
|
99
|
+
(existing.signature !== declaration.signature ||
|
|
100
|
+
(existing.returnType || 'void') !== (declaration.returnType || 'void'))
|
|
101
|
+
) {
|
|
102
|
+
throw new Error(`Conflicting ShaderPlugin hook ${name}`);
|
|
103
|
+
}
|
|
104
|
+
result[stage][name] = existing || declaration;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
80
107
|
}
|
|
81
|
-
|
|
82
108
|
return result;
|
|
83
109
|
}
|
|
84
110
|
|
|
@@ -94,7 +120,7 @@ export function isShaderHookRegistered(registry: ShaderHookRegistry, hookName: s
|
|
|
94
120
|
*/
|
|
95
121
|
export function validateShaderHookInjections(
|
|
96
122
|
registry: ShaderHookRegistry,
|
|
97
|
-
hookInjections: Record<string,
|
|
123
|
+
hookInjections: Record<string, ResolvedShaderInjection[]>,
|
|
98
124
|
stage?: 'vertex' | 'fragment'
|
|
99
125
|
): void {
|
|
100
126
|
const stagePrefix = stage === 'vertex' ? 'vs:' : stage === 'fragment' ? 'fs:' : null;
|
|
@@ -115,32 +141,3 @@ export function validateShaderHookInjections(
|
|
|
115
141
|
}
|
|
116
142
|
}
|
|
117
143
|
}
|
|
118
|
-
|
|
119
|
-
function addShaderHookToRegistry(
|
|
120
|
-
registry: ShaderHookRegistry,
|
|
121
|
-
hookFunction: ShaderHook | string
|
|
122
|
-
): void {
|
|
123
|
-
const options: ShaderHookOptions = typeof hookFunction === 'string' ? {} : hookFunction;
|
|
124
|
-
const hook = (typeof hookFunction === 'string' ? hookFunction : hookFunction.hook).trim();
|
|
125
|
-
const stageSeparatorIndex = hook.indexOf(':');
|
|
126
|
-
const shaderStage = hook.slice(0, stageSeparatorIndex);
|
|
127
|
-
const signature = hook.slice(stageSeparatorIndex + 1);
|
|
128
|
-
const name = hook.replace(/\(.+/, '');
|
|
129
|
-
const normalizedHook: Required<ShaderHook> = {
|
|
130
|
-
hook: name,
|
|
131
|
-
signature,
|
|
132
|
-
header: options.header || '',
|
|
133
|
-
footer: options.footer || ''
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
switch (shaderStage) {
|
|
137
|
-
case 'vs':
|
|
138
|
-
registry.vertex[name] = normalizedHook;
|
|
139
|
-
break;
|
|
140
|
-
case 'fs':
|
|
141
|
-
registry.fragment[name] = normalizedHook;
|
|
142
|
-
break;
|
|
143
|
-
default:
|
|
144
|
-
throw new Error(shaderStage);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
@@ -17,29 +17,71 @@ const fragments: string[] = [];
|
|
|
17
17
|
|
|
18
18
|
export const DECLARATION_INJECT_MARKER = '__LUMA_INJECT_DECLARATIONS__';
|
|
19
19
|
|
|
20
|
-
/**
|
|
21
|
-
*
|
|
22
|
-
*/
|
|
20
|
+
/** Language-specific source inserted at a named shader anchor or hook. */
|
|
23
21
|
export type ShaderInjection = {
|
|
22
|
+
/** Shader stage receiving the injection. */
|
|
23
|
+
stage: 'vertex' | 'fragment';
|
|
24
|
+
/** Unqualified hook name or structural anchor such as #main-start. */
|
|
25
|
+
target: string;
|
|
26
|
+
/** GLSL source. Omit to skip this injection for GLSL assembly. */
|
|
27
|
+
glsl?: string;
|
|
28
|
+
/** WGSL source. Omit to skip this injection for WGSL assembly. */
|
|
29
|
+
wgsl?: string;
|
|
30
|
+
/** Relative order at the target; defaults to zero. */
|
|
31
|
+
order?: number;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/** Language-selected source and ordering used internally during shader assembly. */
|
|
35
|
+
export type ResolvedShaderInjection = {
|
|
24
36
|
/** Plugin responsible for this injection, when supplied by a ShaderPlugin. */
|
|
25
37
|
pluginName?: string;
|
|
26
38
|
injection: string;
|
|
27
39
|
order: number;
|
|
28
40
|
};
|
|
29
41
|
|
|
42
|
+
/** Select language-specific injections while retaining repeated targets and declaration order. */
|
|
43
|
+
export function resolveShaderInjections(
|
|
44
|
+
declarations: readonly ShaderInjection[],
|
|
45
|
+
language: 'glsl' | 'wgsl',
|
|
46
|
+
pluginName?: string
|
|
47
|
+
): Record<string, ResolvedShaderInjection[]> {
|
|
48
|
+
const resolved: Record<string, ResolvedShaderInjection[]> = {};
|
|
49
|
+
for (const declaration of declarations) {
|
|
50
|
+
const source = declaration[language];
|
|
51
|
+
if (source === undefined) continue;
|
|
52
|
+
if (
|
|
53
|
+
(declaration.stage !== 'vertex' && declaration.stage !== 'fragment') ||
|
|
54
|
+
declaration.target.includes(':')
|
|
55
|
+
) {
|
|
56
|
+
throw new Error('Shader injection targets require an explicit stage and unqualified target');
|
|
57
|
+
}
|
|
58
|
+
const target = `${declaration.stage === 'vertex' ? 'vs' : 'fs'}:${declaration.target}`;
|
|
59
|
+
if (!/^(vs|fs):(?:#(?:decl|main-start|main-end)|[A-Za-z_][A-Za-z0-9_]*)$/.test(target)) {
|
|
60
|
+
throw new Error(`Shader injection target "${target}" must be a named shader anchor or hook`);
|
|
61
|
+
}
|
|
62
|
+
resolved[target] ||= [];
|
|
63
|
+
resolved[target].push({
|
|
64
|
+
injection: source,
|
|
65
|
+
order: declaration.order ?? 0,
|
|
66
|
+
...(pluginName ? {pluginName} : {})
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
return resolved;
|
|
70
|
+
}
|
|
71
|
+
|
|
30
72
|
/**
|
|
31
73
|
* ShaderInjections, parsed and split per shader
|
|
32
74
|
*/
|
|
33
75
|
export type ShaderInjections = {
|
|
34
|
-
vertex: Record<string,
|
|
35
|
-
fragment: Record<string,
|
|
76
|
+
vertex: Record<string, ResolvedShaderInjection>;
|
|
77
|
+
fragment: Record<string, ResolvedShaderInjection>;
|
|
36
78
|
};
|
|
37
79
|
|
|
38
80
|
/**
|
|
39
81
|
*
|
|
40
82
|
*/
|
|
41
83
|
export function normalizeInjections(
|
|
42
|
-
injections: Record<string, string |
|
|
84
|
+
injections: Record<string, string | ResolvedShaderInjection>
|
|
43
85
|
): ShaderInjections {
|
|
44
86
|
const result: ShaderInjections = {vertex: {}, fragment: {}};
|
|
45
87
|
|
|
@@ -84,7 +126,7 @@ function getHookStage(hook: string): 'vertex' | 'fragment' {
|
|
|
84
126
|
export function injectShader(
|
|
85
127
|
source: string,
|
|
86
128
|
stage: 'vertex' | 'fragment',
|
|
87
|
-
inject: Record<string,
|
|
129
|
+
inject: Record<string, ResolvedShaderInjection[]>,
|
|
88
130
|
injectStandardStubs = false,
|
|
89
131
|
language: 'glsl' | 'wgsl' = 'glsl',
|
|
90
132
|
entryPoints: {vertex?: string; fragment?: string} = {}
|
|
@@ -93,7 +135,9 @@ export function injectShader(
|
|
|
93
135
|
|
|
94
136
|
for (const key in inject) {
|
|
95
137
|
const fragmentData = inject[key];
|
|
96
|
-
fragmentData.sort(
|
|
138
|
+
fragmentData.sort(
|
|
139
|
+
(a: ResolvedShaderInjection, b: ResolvedShaderInjection): number => a.order - b.order
|
|
140
|
+
);
|
|
97
141
|
fragments.length = fragmentData.length;
|
|
98
142
|
for (let i = 0, len = fragmentData.length; i < len; ++i) {
|
|
99
143
|
fragments[i] = fragmentData[i].injection;
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
getValidatedProperties
|
|
11
11
|
} from '../filters/prop-types';
|
|
12
12
|
import type {ShaderModuleUniformValue, UniformTypes, UniformValue} from '../utils/uniform-types';
|
|
13
|
-
import {
|
|
13
|
+
import type {ResolvedShaderInjection} from '../shader-assembly/shader-injections';
|
|
14
14
|
|
|
15
15
|
import type {ShaderBinding as Binding} from '../../types';
|
|
16
16
|
|
|
@@ -83,8 +83,6 @@ export type ShaderModule<
|
|
|
83
83
|
|
|
84
84
|
/** Boolean or numeric preprocessor defines contributed by this shader module. */
|
|
85
85
|
defines?: Record<string, boolean | number>;
|
|
86
|
-
/** Injections */
|
|
87
|
-
inject?: Record<string, string | {injection: string; order: number}>;
|
|
88
86
|
dependencies?: ShaderModule<any, any>[];
|
|
89
87
|
/** Information on deprecated properties */
|
|
90
88
|
deprecations?: ShaderModuleDeprecation[];
|
|
@@ -93,10 +91,10 @@ export type ShaderModule<
|
|
|
93
91
|
instance?: {
|
|
94
92
|
propValidators?: Record<string, PropValidator>;
|
|
95
93
|
parsedDeprecations: ShaderModuleDeprecation[];
|
|
96
|
-
|
|
94
|
+
/** Empty compatibility value for consumers using older shadertools assembly. */
|
|
97
95
|
normalizedInjections: {
|
|
98
|
-
vertex: Record<string,
|
|
99
|
-
fragment: Record<string,
|
|
96
|
+
vertex: Record<string, ResolvedShaderInjection>;
|
|
97
|
+
fragment: Record<string, ResolvedShaderInjection>;
|
|
100
98
|
};
|
|
101
99
|
};
|
|
102
100
|
};
|
|
@@ -123,16 +121,11 @@ export function initializeShaderModule(module: ShaderModule): void {
|
|
|
123
121
|
|
|
124
122
|
initializeShaderModules(module.dependencies || []);
|
|
125
123
|
|
|
126
|
-
const {
|
|
127
|
-
propTypes = {},
|
|
128
|
-
deprecations = [],
|
|
129
|
-
// defines = {},
|
|
130
|
-
inject = {}
|
|
131
|
-
} = module;
|
|
124
|
+
const {propTypes = {}, deprecations = []} = module;
|
|
132
125
|
|
|
133
126
|
const instance: Required<ShaderModule>['instance'] = {
|
|
134
|
-
|
|
135
|
-
|
|
127
|
+
parsedDeprecations: parseDeprecationDefinitions(deprecations),
|
|
128
|
+
normalizedInjections: {vertex: {}, fragment: {}}
|
|
136
129
|
};
|
|
137
130
|
|
|
138
131
|
if (propTypes) {
|