@motion-core/motion-gpu 0.4.1 → 0.4.2
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/advanced.d.ts +1 -0
- package/dist/advanced.d.ts.map +1 -0
- package/dist/advanced.js +12 -6
- package/dist/core/advanced.d.ts +1 -0
- package/dist/core/advanced.d.ts.map +1 -0
- package/dist/core/advanced.js +12 -5
- package/dist/core/current-value.d.ts +1 -0
- package/dist/core/current-value.d.ts.map +1 -0
- package/dist/core/current-value.js +35 -34
- package/dist/core/current-value.js.map +1 -0
- package/dist/core/error-diagnostics.d.ts +1 -0
- package/dist/core/error-diagnostics.d.ts.map +1 -0
- package/dist/core/error-diagnostics.js +70 -137
- package/dist/core/error-diagnostics.js.map +1 -0
- package/dist/core/error-report.d.ts +1 -0
- package/dist/core/error-report.d.ts.map +1 -0
- package/dist/core/error-report.js +184 -233
- package/dist/core/error-report.js.map +1 -0
- package/dist/core/frame-registry.d.ts +1 -0
- package/dist/core/frame-registry.d.ts.map +1 -0
- package/dist/core/frame-registry.js +546 -662
- package/dist/core/frame-registry.js.map +1 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +11 -12
- package/dist/core/material-preprocess.d.ts +1 -0
- package/dist/core/material-preprocess.d.ts.map +1 -0
- package/dist/core/material-preprocess.js +128 -151
- package/dist/core/material-preprocess.js.map +1 -0
- package/dist/core/material.d.ts +1 -0
- package/dist/core/material.d.ts.map +1 -0
- package/dist/core/material.js +263 -317
- package/dist/core/material.js.map +1 -0
- package/dist/core/recompile-policy.d.ts +1 -0
- package/dist/core/recompile-policy.d.ts.map +1 -0
- package/dist/core/recompile-policy.js +18 -13
- package/dist/core/recompile-policy.js.map +1 -0
- package/dist/core/render-graph.d.ts +1 -0
- package/dist/core/render-graph.d.ts.map +1 -0
- package/dist/core/render-graph.js +61 -68
- package/dist/core/render-graph.js.map +1 -0
- package/dist/core/render-targets.d.ts +1 -0
- package/dist/core/render-targets.d.ts.map +1 -0
- package/dist/core/render-targets.js +52 -53
- package/dist/core/render-targets.js.map +1 -0
- package/dist/core/renderer.d.ts +1 -0
- package/dist/core/renderer.d.ts.map +1 -0
- package/dist/core/renderer.js +942 -1081
- package/dist/core/renderer.js.map +1 -0
- package/dist/core/runtime-loop.d.ts +1 -0
- package/dist/core/runtime-loop.d.ts.map +1 -0
- package/dist/core/runtime-loop.js +305 -362
- package/dist/core/runtime-loop.js.map +1 -0
- package/dist/core/scheduler-helpers.d.ts +1 -0
- package/dist/core/scheduler-helpers.d.ts.map +1 -0
- package/dist/core/scheduler-helpers.js +52 -51
- package/dist/core/scheduler-helpers.js.map +1 -0
- package/dist/core/shader.d.ts +1 -0
- package/dist/core/shader.d.ts.map +1 -0
- package/dist/core/shader.js +92 -117
- package/dist/core/shader.js.map +1 -0
- package/dist/core/texture-loader.d.ts +1 -0
- package/dist/core/texture-loader.d.ts.map +1 -0
- package/dist/core/texture-loader.js +205 -273
- package/dist/core/texture-loader.js.map +1 -0
- package/dist/core/textures.d.ts +1 -0
- package/dist/core/textures.d.ts.map +1 -0
- package/dist/core/textures.js +106 -116
- package/dist/core/textures.js.map +1 -0
- package/dist/core/types.d.ts +1 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +0 -4
- package/dist/core/uniforms.d.ts +1 -0
- package/dist/core/uniforms.d.ts.map +1 -0
- package/dist/core/uniforms.js +170 -191
- package/dist/core/uniforms.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -6
- package/dist/passes/BlitPass.d.ts +1 -0
- package/dist/passes/BlitPass.d.ts.map +1 -0
- package/dist/passes/BlitPass.js +23 -18
- package/dist/passes/BlitPass.js.map +1 -0
- package/dist/passes/CopyPass.d.ts +1 -0
- package/dist/passes/CopyPass.d.ts.map +1 -0
- package/dist/passes/CopyPass.js +58 -52
- package/dist/passes/CopyPass.js.map +1 -0
- package/dist/passes/FullscreenPass.d.ts +1 -0
- package/dist/passes/FullscreenPass.d.ts.map +1 -0
- package/dist/passes/FullscreenPass.js +127 -130
- package/dist/passes/FullscreenPass.js.map +1 -0
- package/dist/passes/ShaderPass.d.ts +1 -0
- package/dist/passes/ShaderPass.d.ts.map +1 -0
- package/dist/passes/ShaderPass.js +40 -37
- package/dist/passes/ShaderPass.js.map +1 -0
- package/dist/passes/index.d.ts +1 -0
- package/dist/passes/index.d.ts.map +1 -0
- package/dist/passes/index.js +4 -3
- package/dist/react/FragCanvas.d.ts +1 -0
- package/dist/react/FragCanvas.d.ts.map +1 -0
- package/dist/react/FragCanvas.js +234 -211
- package/dist/react/FragCanvas.js.map +1 -0
- package/dist/react/MotionGPUErrorOverlay.d.ts +1 -0
- package/dist/react/MotionGPUErrorOverlay.d.ts.map +1 -0
- package/dist/react/MotionGPUErrorOverlay.js +96 -13
- package/dist/react/MotionGPUErrorOverlay.js.map +1 -0
- package/dist/react/Portal.d.ts +1 -0
- package/dist/react/Portal.d.ts.map +1 -0
- package/dist/react/Portal.js +18 -21
- package/dist/react/Portal.js.map +1 -0
- package/dist/react/advanced.d.ts +1 -0
- package/dist/react/advanced.d.ts.map +1 -0
- package/dist/react/advanced.js +12 -6
- package/dist/react/frame-context.d.ts +1 -0
- package/dist/react/frame-context.d.ts.map +1 -0
- package/dist/react/frame-context.js +88 -94
- package/dist/react/frame-context.js.map +1 -0
- package/dist/react/index.d.ts +1 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +10 -9
- package/dist/react/motiongpu-context.d.ts +1 -0
- package/dist/react/motiongpu-context.d.ts.map +1 -0
- package/dist/react/motiongpu-context.js +18 -15
- package/dist/react/motiongpu-context.js.map +1 -0
- package/dist/react/use-motiongpu-user-context.d.ts +1 -0
- package/dist/react/use-motiongpu-user-context.d.ts.map +1 -0
- package/dist/react/use-motiongpu-user-context.js +83 -82
- package/dist/react/use-motiongpu-user-context.js.map +1 -0
- package/dist/react/use-texture.d.ts +1 -0
- package/dist/react/use-texture.d.ts.map +1 -0
- package/dist/react/use-texture.js +132 -152
- package/dist/react/use-texture.js.map +1 -0
- package/dist/svelte/FragCanvas.svelte.d.ts +1 -0
- package/dist/svelte/FragCanvas.svelte.d.ts.map +1 -0
- package/dist/svelte/MotionGPUErrorOverlay.svelte.d.ts +1 -0
- package/dist/svelte/MotionGPUErrorOverlay.svelte.d.ts.map +1 -0
- package/dist/svelte/Portal.svelte.d.ts +1 -0
- package/dist/svelte/Portal.svelte.d.ts.map +1 -0
- package/dist/svelte/advanced.d.ts +1 -0
- package/dist/svelte/advanced.d.ts.map +1 -0
- package/dist/svelte/advanced.js +11 -6
- package/dist/svelte/frame-context.d.ts +1 -0
- package/dist/svelte/frame-context.d.ts.map +1 -0
- package/dist/svelte/frame-context.js +27 -27
- package/dist/svelte/frame-context.js.map +1 -0
- package/dist/svelte/index.d.ts +1 -0
- package/dist/svelte/index.d.ts.map +1 -0
- package/dist/svelte/index.js +10 -9
- package/dist/svelte/motiongpu-context.d.ts +1 -0
- package/dist/svelte/motiongpu-context.d.ts.map +1 -0
- package/dist/svelte/motiongpu-context.js +24 -21
- package/dist/svelte/motiongpu-context.js.map +1 -0
- package/dist/svelte/use-motiongpu-user-context.d.ts +1 -0
- package/dist/svelte/use-motiongpu-user-context.d.ts.map +1 -0
- package/dist/svelte/use-motiongpu-user-context.js +69 -70
- package/dist/svelte/use-motiongpu-user-context.js.map +1 -0
- package/dist/svelte/use-texture.d.ts +1 -0
- package/dist/svelte/use-texture.d.ts.map +1 -0
- package/dist/svelte/use-texture.js +125 -147
- package/dist/svelte/use-texture.js.map +1 -0
- package/package.json +12 -7
- package/src/lib/advanced.ts +6 -0
- package/src/lib/core/advanced.ts +12 -0
- package/src/lib/core/current-value.ts +64 -0
- package/src/lib/core/error-diagnostics.ts +236 -0
- package/src/lib/core/error-report.ts +406 -0
- package/src/lib/core/frame-registry.ts +1189 -0
- package/src/lib/core/index.ts +77 -0
- package/src/lib/core/material-preprocess.ts +284 -0
- package/src/lib/core/material.ts +667 -0
- package/src/lib/core/recompile-policy.ts +31 -0
- package/src/lib/core/render-graph.ts +143 -0
- package/src/lib/core/render-targets.ts +107 -0
- package/src/lib/core/renderer.ts +1547 -0
- package/src/lib/core/runtime-loop.ts +458 -0
- package/src/lib/core/scheduler-helpers.ts +136 -0
- package/src/lib/core/shader.ts +258 -0
- package/src/lib/core/texture-loader.ts +476 -0
- package/src/lib/core/textures.ts +235 -0
- package/src/lib/core/types.ts +582 -0
- package/src/lib/core/uniforms.ts +282 -0
- package/src/lib/index.ts +6 -0
- package/src/lib/passes/BlitPass.ts +54 -0
- package/src/lib/passes/CopyPass.ts +80 -0
- package/src/lib/passes/FullscreenPass.ts +173 -0
- package/src/lib/passes/ShaderPass.ts +88 -0
- package/src/lib/passes/index.ts +3 -0
- package/src/lib/react/FragCanvas.tsx +345 -0
- package/src/lib/react/MotionGPUErrorOverlay.tsx +392 -0
- package/src/lib/react/Portal.tsx +34 -0
- package/src/lib/react/advanced.ts +36 -0
- package/src/lib/react/frame-context.ts +169 -0
- package/src/lib/react/index.ts +51 -0
- package/src/lib/react/motiongpu-context.ts +88 -0
- package/src/lib/react/use-motiongpu-user-context.ts +186 -0
- package/src/lib/react/use-texture.ts +233 -0
- package/src/lib/svelte/FragCanvas.svelte +249 -0
- package/src/lib/svelte/MotionGPUErrorOverlay.svelte +382 -0
- package/src/lib/svelte/Portal.svelte +31 -0
- package/src/lib/svelte/advanced.ts +32 -0
- package/src/lib/svelte/frame-context.ts +87 -0
- package/src/lib/svelte/index.ts +51 -0
- package/src/lib/svelte/motiongpu-context.ts +97 -0
- package/src/lib/svelte/use-motiongpu-user-context.ts +145 -0
- package/src/lib/svelte/use-texture.ts +232 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Framework-agnostic MotionGPU core entrypoint.
|
|
3
|
+
*
|
|
4
|
+
* This surface is intended for building framework adapters (Svelte/React/Vue).
|
|
5
|
+
*/
|
|
6
|
+
export { defineMaterial, resolveMaterial } from './material.js';
|
|
7
|
+
export { toMotionGPUErrorReport } from './error-report.js';
|
|
8
|
+
export { createCurrentWritable } from './current-value.js';
|
|
9
|
+
export { createFrameRegistry } from './frame-registry.js';
|
|
10
|
+
export { createMotionGPURuntimeLoop } from './runtime-loop.js';
|
|
11
|
+
export { loadTexturesFromUrls } from './texture-loader.js';
|
|
12
|
+
export { BlitPass, CopyPass, ShaderPass } from '../passes/index.js';
|
|
13
|
+
export type { CurrentReadable, CurrentWritable, Subscribable } from './current-value.js';
|
|
14
|
+
export type {
|
|
15
|
+
MotionGPUErrorCode,
|
|
16
|
+
MotionGPUErrorContext,
|
|
17
|
+
MotionGPUErrorPhase,
|
|
18
|
+
MotionGPUErrorReport,
|
|
19
|
+
MotionGPUErrorSeverity,
|
|
20
|
+
MotionGPUErrorSource,
|
|
21
|
+
MotionGPUErrorSourceLine
|
|
22
|
+
} from './error-report.js';
|
|
23
|
+
export type {
|
|
24
|
+
FrameCallback,
|
|
25
|
+
FrameKey,
|
|
26
|
+
FrameProfilingSnapshot,
|
|
27
|
+
FrameRegistry,
|
|
28
|
+
FrameRunTimings,
|
|
29
|
+
FrameScheduleSnapshot,
|
|
30
|
+
FrameStage,
|
|
31
|
+
FrameStageCallback,
|
|
32
|
+
FrameTask,
|
|
33
|
+
FrameTaskInvalidation,
|
|
34
|
+
FrameTaskInvalidationToken,
|
|
35
|
+
FrameTimingStats,
|
|
36
|
+
UseFrameOptions,
|
|
37
|
+
UseFrameResult
|
|
38
|
+
} from './frame-registry.js';
|
|
39
|
+
export type {
|
|
40
|
+
FragMaterial,
|
|
41
|
+
FragMaterialInput,
|
|
42
|
+
MaterialDefineValue,
|
|
43
|
+
MaterialDefines,
|
|
44
|
+
MaterialIncludes,
|
|
45
|
+
ResolvedMaterial,
|
|
46
|
+
TypedMaterialDefineValue
|
|
47
|
+
} from './material.js';
|
|
48
|
+
export type { MotionGPURuntimeLoop, MotionGPURuntimeLoopOptions } from './runtime-loop.js';
|
|
49
|
+
export type { LoadedTexture, TextureDecodeOptions, TextureLoadOptions } from './texture-loader.js';
|
|
50
|
+
export type {
|
|
51
|
+
FrameInvalidationToken,
|
|
52
|
+
FrameState,
|
|
53
|
+
OutputColorSpace,
|
|
54
|
+
RenderPass,
|
|
55
|
+
RenderPassContext,
|
|
56
|
+
RenderPassFlags,
|
|
57
|
+
RenderPassInputSlot,
|
|
58
|
+
RenderPassOutputSlot,
|
|
59
|
+
RenderMode,
|
|
60
|
+
RenderTarget,
|
|
61
|
+
RenderTargetDefinition,
|
|
62
|
+
RenderTargetDefinitionMap,
|
|
63
|
+
TextureData,
|
|
64
|
+
TextureDefinition,
|
|
65
|
+
TextureDefinitionMap,
|
|
66
|
+
TextureMap,
|
|
67
|
+
TextureSource,
|
|
68
|
+
TextureUpdateMode,
|
|
69
|
+
TextureValue,
|
|
70
|
+
TypedUniform,
|
|
71
|
+
UniformLayout,
|
|
72
|
+
UniformLayoutEntry,
|
|
73
|
+
UniformMap,
|
|
74
|
+
UniformMat4Value,
|
|
75
|
+
UniformType,
|
|
76
|
+
UniformValue
|
|
77
|
+
} from './types.js';
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import { assertUniformName } from './uniforms.js';
|
|
2
|
+
import type {
|
|
3
|
+
MaterialDefineValue,
|
|
4
|
+
MaterialDefines,
|
|
5
|
+
MaterialIncludes,
|
|
6
|
+
TypedMaterialDefineValue
|
|
7
|
+
} from './material.js';
|
|
8
|
+
|
|
9
|
+
const INCLUDE_DIRECTIVE_PATTERN = /^\s*#include\s+<([A-Za-z_][A-Za-z0-9_]*)>\s*$/;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Source location metadata for one generated fragment line.
|
|
13
|
+
*/
|
|
14
|
+
export interface MaterialSourceLocation {
|
|
15
|
+
/**
|
|
16
|
+
* Origin category for this generated line.
|
|
17
|
+
*/
|
|
18
|
+
kind: 'fragment' | 'include' | 'define';
|
|
19
|
+
/**
|
|
20
|
+
* 1-based line in the origin source.
|
|
21
|
+
*/
|
|
22
|
+
line: number;
|
|
23
|
+
/**
|
|
24
|
+
* Include chunk identifier when `kind === "include"`.
|
|
25
|
+
*/
|
|
26
|
+
include?: string;
|
|
27
|
+
/**
|
|
28
|
+
* Define identifier when `kind === "define"`.
|
|
29
|
+
*/
|
|
30
|
+
define?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 1-based line map from generated fragment WGSL to user source locations.
|
|
35
|
+
*/
|
|
36
|
+
export type MaterialLineMap = Array<MaterialSourceLocation | null>;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Preprocess output used by material resolution and diagnostics mapping.
|
|
40
|
+
*/
|
|
41
|
+
export interface PreprocessedMaterialFragment {
|
|
42
|
+
/**
|
|
43
|
+
* Final fragment source after defines/include expansion.
|
|
44
|
+
*/
|
|
45
|
+
fragment: string;
|
|
46
|
+
/**
|
|
47
|
+
* 1-based generated-line source map.
|
|
48
|
+
*/
|
|
49
|
+
lineMap: MaterialLineMap;
|
|
50
|
+
/**
|
|
51
|
+
* Deterministic WGSL define block used to build the final fragment source.
|
|
52
|
+
*/
|
|
53
|
+
defineBlockSource: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function normalizeTypedDefine(
|
|
57
|
+
name: string,
|
|
58
|
+
define: TypedMaterialDefineValue
|
|
59
|
+
): TypedMaterialDefineValue {
|
|
60
|
+
const value = define.value;
|
|
61
|
+
|
|
62
|
+
if (define.type === 'bool') {
|
|
63
|
+
if (typeof value !== 'boolean') {
|
|
64
|
+
throw new Error(`Invalid define value for "${name}". bool define requires boolean value.`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
type: 'bool',
|
|
69
|
+
value
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (typeof value !== 'number' || !Number.isFinite(value)) {
|
|
74
|
+
throw new Error(`Invalid define value for "${name}". Numeric define must be finite.`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if ((define.type === 'i32' || define.type === 'u32') && !Number.isInteger(value)) {
|
|
78
|
+
throw new Error(`Invalid define value for "${name}". ${define.type} define requires integer.`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (define.type === 'u32' && value < 0) {
|
|
82
|
+
throw new Error(`Invalid define value for "${name}". u32 define must be >= 0.`);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
type: define.type,
|
|
87
|
+
value
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Validates and normalizes define entries.
|
|
93
|
+
*/
|
|
94
|
+
export function normalizeDefines<TDefineKey extends string>(
|
|
95
|
+
defines: MaterialDefines<TDefineKey> | undefined
|
|
96
|
+
): MaterialDefines<TDefineKey> {
|
|
97
|
+
const resolved: MaterialDefines<TDefineKey> = {} as MaterialDefines<TDefineKey>;
|
|
98
|
+
|
|
99
|
+
for (const [name, value] of Object.entries(defines ?? {}) as Array<
|
|
100
|
+
[TDefineKey, MaterialDefineValue]
|
|
101
|
+
>) {
|
|
102
|
+
assertUniformName(name);
|
|
103
|
+
|
|
104
|
+
if (typeof value === 'boolean') {
|
|
105
|
+
resolved[name] = value;
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (typeof value === 'number') {
|
|
110
|
+
if (!Number.isFinite(value)) {
|
|
111
|
+
throw new Error(`Invalid define value for "${name}". Define numbers must be finite.`);
|
|
112
|
+
}
|
|
113
|
+
resolved[name] = value;
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const normalized = normalizeTypedDefine(name, value);
|
|
118
|
+
resolved[name] = Object.freeze(normalized);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return resolved;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Validates include map identifiers and source chunks.
|
|
126
|
+
*/
|
|
127
|
+
export function normalizeIncludes<TIncludeKey extends string>(
|
|
128
|
+
includes: MaterialIncludes<TIncludeKey> | undefined
|
|
129
|
+
): MaterialIncludes<TIncludeKey> {
|
|
130
|
+
const resolved: MaterialIncludes<TIncludeKey> = {} as MaterialIncludes<TIncludeKey>;
|
|
131
|
+
|
|
132
|
+
for (const [name, source] of Object.entries(includes ?? {}) as Array<[TIncludeKey, string]>) {
|
|
133
|
+
assertUniformName(name);
|
|
134
|
+
if (typeof source !== 'string' || source.trim().length === 0) {
|
|
135
|
+
throw new Error(`Invalid include "${name}". Include source must be a non-empty WGSL string.`);
|
|
136
|
+
}
|
|
137
|
+
resolved[name] = source;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return resolved;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Converts one define declaration to WGSL `const`.
|
|
145
|
+
*/
|
|
146
|
+
export function toDefineLine(key: string, value: MaterialDefineValue): string {
|
|
147
|
+
if (typeof value === 'boolean') {
|
|
148
|
+
return `const ${key}: bool = ${value ? 'true' : 'false'};`;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (typeof value === 'number') {
|
|
152
|
+
const valueLiteral = Number.isInteger(value) ? `${value}.0` : `${value}`;
|
|
153
|
+
return `const ${key}: f32 = ${valueLiteral};`;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (value.type === 'bool') {
|
|
157
|
+
return `const ${key}: bool = ${value.value ? 'true' : 'false'};`;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (value.type === 'f32') {
|
|
161
|
+
const numberValue = value.value as number;
|
|
162
|
+
const valueLiteral = Number.isInteger(numberValue) ? `${numberValue}.0` : `${numberValue}`;
|
|
163
|
+
return `const ${key}: f32 = ${valueLiteral};`;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (value.type === 'i32') {
|
|
167
|
+
return `const ${key}: i32 = ${value.value};`;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return `const ${key}: u32 = ${value.value}u;`;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function expandChunk(
|
|
174
|
+
source: string,
|
|
175
|
+
kind: 'fragment' | 'include',
|
|
176
|
+
includeName: string | undefined,
|
|
177
|
+
includes: Record<string, string>,
|
|
178
|
+
stack: string[]
|
|
179
|
+
): { lines: string[]; mapEntries: MaterialSourceLocation[] } {
|
|
180
|
+
const sourceLines = source.split('\n');
|
|
181
|
+
const lines: string[] = [];
|
|
182
|
+
const mapEntries: MaterialSourceLocation[] = [];
|
|
183
|
+
|
|
184
|
+
for (let index = 0; index < sourceLines.length; index += 1) {
|
|
185
|
+
const sourceLine = sourceLines[index];
|
|
186
|
+
if (sourceLine === undefined) {
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const includeMatch = sourceLine.match(INCLUDE_DIRECTIVE_PATTERN);
|
|
191
|
+
if (!includeMatch) {
|
|
192
|
+
lines.push(sourceLine);
|
|
193
|
+
mapEntries.push({
|
|
194
|
+
kind,
|
|
195
|
+
line: index + 1,
|
|
196
|
+
...(kind === 'include' && includeName ? { include: includeName } : {})
|
|
197
|
+
});
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const includeKey = includeMatch[1];
|
|
202
|
+
if (!includeKey) {
|
|
203
|
+
throw new Error('Invalid include directive in fragment shader.');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
assertUniformName(includeKey);
|
|
207
|
+
const includeSource = includes[includeKey];
|
|
208
|
+
if (!includeSource) {
|
|
209
|
+
throw new Error(`Unknown include "${includeKey}" referenced in fragment shader.`);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (stack.includes(includeKey)) {
|
|
213
|
+
throw new Error(
|
|
214
|
+
`Circular include detected for "${includeKey}". Include stack: ${[...stack, includeKey].join(' -> ')}.`
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const nested = expandChunk(includeSource, 'include', includeKey, includes, [
|
|
219
|
+
...stack,
|
|
220
|
+
includeKey
|
|
221
|
+
]);
|
|
222
|
+
lines.push(...nested.lines);
|
|
223
|
+
mapEntries.push(...nested.mapEntries);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return { lines, mapEntries };
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Preprocesses material fragment with deterministic define/include expansion and line mapping.
|
|
231
|
+
*/
|
|
232
|
+
export function preprocessMaterialFragment<
|
|
233
|
+
TDefineKey extends string,
|
|
234
|
+
TIncludeKey extends string
|
|
235
|
+
>(input: {
|
|
236
|
+
fragment: string;
|
|
237
|
+
defines?: MaterialDefines<TDefineKey>;
|
|
238
|
+
includes?: MaterialIncludes<TIncludeKey>;
|
|
239
|
+
}): PreprocessedMaterialFragment {
|
|
240
|
+
const normalizedDefines = normalizeDefines(input.defines);
|
|
241
|
+
const normalizedIncludes = normalizeIncludes(input.includes);
|
|
242
|
+
|
|
243
|
+
const fragmentExpanded = expandChunk(
|
|
244
|
+
input.fragment,
|
|
245
|
+
'fragment',
|
|
246
|
+
undefined,
|
|
247
|
+
normalizedIncludes,
|
|
248
|
+
[]
|
|
249
|
+
);
|
|
250
|
+
const defineEntries = (
|
|
251
|
+
Object.entries(normalizedDefines) as Array<[TDefineKey, MaterialDefineValue]>
|
|
252
|
+
).sort(([a], [b]) => a.localeCompare(b));
|
|
253
|
+
const lines: string[] = [];
|
|
254
|
+
const defineLines: string[] = [];
|
|
255
|
+
const mapEntries: Array<MaterialSourceLocation | null> = [];
|
|
256
|
+
|
|
257
|
+
for (let index = 0; index < defineEntries.length; index += 1) {
|
|
258
|
+
const entry = defineEntries[index];
|
|
259
|
+
if (!entry) {
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const [name, value] = entry;
|
|
264
|
+
const defineLine = toDefineLine(name, value);
|
|
265
|
+
lines.push(defineLine);
|
|
266
|
+
defineLines.push(defineLine);
|
|
267
|
+
mapEntries.push({ kind: 'define', line: index + 1, define: name });
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (defineEntries.length > 0) {
|
|
271
|
+
lines.push('');
|
|
272
|
+
mapEntries.push(null);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
lines.push(...fragmentExpanded.lines);
|
|
276
|
+
mapEntries.push(...fragmentExpanded.mapEntries);
|
|
277
|
+
|
|
278
|
+
const lineMap: MaterialLineMap = [null, ...mapEntries];
|
|
279
|
+
return {
|
|
280
|
+
fragment: lines.join('\n'),
|
|
281
|
+
lineMap,
|
|
282
|
+
defineBlockSource: defineLines.join('\n')
|
|
283
|
+
};
|
|
284
|
+
}
|