@motion-core/motion-gpu 0.4.1 → 0.5.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/README.md +99 -0
- package/dist/advanced.d.ts +1 -0
- package/dist/advanced.d.ts.map +1 -0
- package/dist/advanced.js +14 -6
- package/dist/core/advanced.d.ts +1 -0
- package/dist/core/advanced.d.ts.map +1 -0
- package/dist/core/advanced.js +14 -5
- package/dist/core/compute-shader.d.ts +87 -0
- package/dist/core/compute-shader.d.ts.map +1 -0
- package/dist/core/compute-shader.js +205 -0
- package/dist/core/compute-shader.js.map +1 -0
- 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 +2 -1
- package/dist/core/error-report.d.ts.map +1 -0
- package/dist/core/error-report.js +247 -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 +6 -2
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +13 -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 +131 -152
- package/dist/core/material-preprocess.js.map +1 -0
- package/dist/core/material.d.ts +23 -6
- package/dist/core/material.d.ts.map +1 -0
- package/dist/core/material.js +290 -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 +8 -3
- package/dist/core/render-graph.d.ts.map +1 -0
- package/dist/core/render-graph.js +77 -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 +1337 -1081
- package/dist/core/renderer.js.map +1 -0
- package/dist/core/runtime-loop.d.ts +3 -2
- package/dist/core/runtime-loop.d.ts.map +1 -0
- package/dist/core/runtime-loop.js +353 -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 +10 -1
- package/dist/core/shader.d.ts.map +1 -0
- package/dist/core/shader.js +109 -115
- package/dist/core/shader.js.map +1 -0
- package/dist/core/storage-buffers.d.ts +37 -0
- package/dist/core/storage-buffers.d.ts.map +1 -0
- package/dist/core/storage-buffers.js +95 -0
- package/dist/core/storage-buffers.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 +209 -273
- package/dist/core/texture-loader.js.map +1 -0
- package/dist/core/textures.d.ts +13 -0
- package/dist/core/textures.d.ts.map +1 -0
- package/dist/core/textures.js +111 -116
- package/dist/core/textures.js.map +1 -0
- package/dist/core/types.d.ts +147 -4
- 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 +13 -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/ComputePass.d.ts +83 -0
- package/dist/passes/ComputePass.d.ts.map +1 -0
- package/dist/passes/ComputePass.js +92 -0
- package/dist/passes/ComputePass.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/PingPongComputePass.d.ts +104 -0
- package/dist/passes/PingPongComputePass.d.ts.map +1 -0
- package/dist/passes/PingPongComputePass.js +132 -0
- package/dist/passes/PingPongComputePass.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 +41 -37
- package/dist/passes/ShaderPass.js.map +1 -0
- package/dist/passes/index.d.ts +3 -0
- package/dist/passes/index.d.ts.map +1 -0
- package/dist/passes/index.js +6 -3
- package/dist/react/FragCanvas.d.ts +3 -2
- 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 +200 -14
- 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 +14 -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 +6 -2
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +12 -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 +2 -2
- package/dist/svelte/FragCanvas.svelte.d.ts +3 -2
- package/dist/svelte/FragCanvas.svelte.d.ts.map +1 -0
- package/dist/svelte/MotionGPUErrorOverlay.svelte +137 -7
- 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 +13 -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 +6 -2
- package/dist/svelte/index.d.ts.map +1 -0
- package/dist/svelte/index.js +12 -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/compute-shader.ts +326 -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 +535 -0
- package/src/lib/core/frame-registry.ts +1190 -0
- package/src/lib/core/index.ts +94 -0
- package/src/lib/core/material-preprocess.ts +295 -0
- package/src/lib/core/material.ts +748 -0
- package/src/lib/core/recompile-policy.ts +31 -0
- package/src/lib/core/render-graph.ts +173 -0
- package/src/lib/core/render-targets.ts +107 -0
- package/src/lib/core/renderer.ts +2161 -0
- package/src/lib/core/runtime-loop.ts +537 -0
- package/src/lib/core/scheduler-helpers.ts +136 -0
- package/src/lib/core/shader.ts +301 -0
- package/src/lib/core/storage-buffers.ts +142 -0
- package/src/lib/core/texture-loader.ts +482 -0
- package/src/lib/core/textures.ts +257 -0
- package/src/lib/core/types.ts +743 -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/ComputePass.ts +136 -0
- package/src/lib/passes/CopyPass.ts +80 -0
- package/src/lib/passes/FullscreenPass.ts +173 -0
- package/src/lib/passes/PingPongComputePass.ts +180 -0
- package/src/lib/passes/ShaderPass.ts +89 -0
- package/src/lib/passes/index.ts +9 -0
- package/src/lib/react/FragCanvas.tsx +345 -0
- package/src/lib/react/MotionGPUErrorOverlay.tsx +524 -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 +68 -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 +512 -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 +68 -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
package/dist/core/material.js
CHANGED
|
@@ -1,365 +1,338 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { normalizeDefines, normalizeIncludes, preprocessMaterialFragment, toDefineLine } from
|
|
1
|
+
import { assertUniformName, assertUniformValueForType, inferUniformType, resolveUniformLayout } from "./uniforms.js";
|
|
2
|
+
import { normalizeTextureDefinition } from "./textures.js";
|
|
3
|
+
import { normalizeDefines, normalizeIncludes, preprocessMaterialFragment, toDefineLine } from "./material-preprocess.js";
|
|
4
|
+
import { assertStorageBufferDefinition, assertStorageTextureFormat } from "./storage-buffers.js";
|
|
5
|
+
//#region src/lib/core/material.ts
|
|
4
6
|
/**
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
* Strict fragment contract used by MotionGPU.
|
|
8
|
+
*/
|
|
9
|
+
var FRAGMENT_FUNCTION_SIGNATURE_PATTERN = /\bfn\s+frag\s*\(\s*([^)]*?)\s*\)\s*->\s*([A-Za-z_][A-Za-z0-9_<>\s]*)\s*(?:\{|$)/m;
|
|
10
|
+
var FRAGMENT_FUNCTION_NAME_PATTERN = /\bfn\s+([A-Za-z_][A-Za-z0-9_]*)\s*\(/g;
|
|
11
|
+
var resolvedMaterialCache = /* @__PURE__ */ new WeakMap();
|
|
12
|
+
var preprocessedFragmentCache = /* @__PURE__ */ new WeakMap();
|
|
13
|
+
var materialSourceMetadataCache = /* @__PURE__ */ new WeakMap();
|
|
12
14
|
function getCachedResolvedMaterial(material) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
// Invariant: the cache key is the same material object used to produce this resolved payload.
|
|
18
|
-
return cached;
|
|
15
|
+
const cached = resolvedMaterialCache.get(material);
|
|
16
|
+
if (!cached) return null;
|
|
17
|
+
return cached;
|
|
19
18
|
}
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
var STACK_TRACE_CHROME_PATTERN = /^\s*at\s+(?:(.*?)\s+\()?(.+?):(\d+):(\d+)\)?$/;
|
|
20
|
+
var STACK_TRACE_FIREFOX_PATTERN = /^(.*?)@(.+?):(\d+):(\d+)$/;
|
|
22
21
|
function getPathBasename(path) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
return last && last.length > 0 ? last : path;
|
|
22
|
+
const parts = (path.split(/[?#]/)[0] ?? path).split(/[\\/]/);
|
|
23
|
+
const last = parts[parts.length - 1];
|
|
24
|
+
return last && last.length > 0 ? last : path;
|
|
27
25
|
}
|
|
28
26
|
function normalizeSignaturePart(value) {
|
|
29
|
-
|
|
27
|
+
return value.replace(/\s+/g, " ").trim();
|
|
30
28
|
}
|
|
31
29
|
function listFunctionNames(fragment) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
return Array.from(names);
|
|
30
|
+
const names = /* @__PURE__ */ new Set();
|
|
31
|
+
for (const match of fragment.matchAll(FRAGMENT_FUNCTION_NAME_PATTERN)) {
|
|
32
|
+
const name = match[1];
|
|
33
|
+
if (!name) continue;
|
|
34
|
+
names.add(name);
|
|
35
|
+
}
|
|
36
|
+
return Array.from(names);
|
|
41
37
|
}
|
|
42
38
|
function captureMaterialSourceFromStack() {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
return {
|
|
71
|
-
component: getPathBasename(file),
|
|
72
|
-
file,
|
|
73
|
-
line: parsedLine,
|
|
74
|
-
column: parsedColumn,
|
|
75
|
-
...(functionName ? { functionName } : {})
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
return null;
|
|
39
|
+
const stack = (/* @__PURE__ */ new Error()).stack;
|
|
40
|
+
if (!stack) return null;
|
|
41
|
+
const stackLines = stack.split("\n").slice(1);
|
|
42
|
+
for (const rawLine of stackLines) {
|
|
43
|
+
const line = rawLine.trim();
|
|
44
|
+
if (line.length === 0) continue;
|
|
45
|
+
const chromeMatch = line.match(STACK_TRACE_CHROME_PATTERN);
|
|
46
|
+
const firefoxMatch = line.match(STACK_TRACE_FIREFOX_PATTERN);
|
|
47
|
+
const functionName = chromeMatch?.[1] ?? firefoxMatch?.[1] ?? void 0;
|
|
48
|
+
const file = chromeMatch?.[2] ?? firefoxMatch?.[2];
|
|
49
|
+
const lineValue = chromeMatch?.[3] ?? firefoxMatch?.[3];
|
|
50
|
+
const columnValue = chromeMatch?.[4] ?? firefoxMatch?.[4];
|
|
51
|
+
if (!file || !lineValue || !columnValue) continue;
|
|
52
|
+
if (file.includes("/core/material") || file.includes("\\core\\material")) continue;
|
|
53
|
+
const parsedLine = Number.parseInt(lineValue, 10);
|
|
54
|
+
const parsedColumn = Number.parseInt(columnValue, 10);
|
|
55
|
+
if (!Number.isFinite(parsedLine) || !Number.isFinite(parsedColumn)) continue;
|
|
56
|
+
return {
|
|
57
|
+
component: getPathBasename(file),
|
|
58
|
+
file,
|
|
59
|
+
line: parsedLine,
|
|
60
|
+
column: parsedColumn,
|
|
61
|
+
...functionName ? { functionName } : {}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
return null;
|
|
79
65
|
}
|
|
80
66
|
function resolveSourceMetadata(source) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
...(component !== undefined ? { component } : {}),
|
|
96
|
-
...(file !== undefined ? { file } : {}),
|
|
97
|
-
...(line !== undefined ? { line } : {}),
|
|
98
|
-
...(column !== undefined ? { column } : {}),
|
|
99
|
-
...(functionName !== undefined ? { functionName } : {})
|
|
100
|
-
};
|
|
67
|
+
const captured = captureMaterialSourceFromStack();
|
|
68
|
+
const component = source?.component ?? captured?.component;
|
|
69
|
+
const file = source?.file ?? captured?.file;
|
|
70
|
+
const line = source?.line ?? captured?.line;
|
|
71
|
+
const column = source?.column ?? captured?.column;
|
|
72
|
+
const functionName = source?.functionName ?? captured?.functionName;
|
|
73
|
+
if (component === void 0 && file === void 0 && line === void 0 && column === void 0 && functionName === void 0) return null;
|
|
74
|
+
return {
|
|
75
|
+
...component !== void 0 ? { component } : {},
|
|
76
|
+
...file !== void 0 ? { file } : {},
|
|
77
|
+
...line !== void 0 ? { line } : {},
|
|
78
|
+
...column !== void 0 ? { column } : {},
|
|
79
|
+
...functionName !== void 0 ? { functionName } : {}
|
|
80
|
+
};
|
|
101
81
|
}
|
|
102
82
|
/**
|
|
103
|
-
|
|
104
|
-
|
|
83
|
+
* Asserts that material has been normalized by {@link defineMaterial}.
|
|
84
|
+
*/
|
|
105
85
|
function assertDefinedMaterial(material) {
|
|
106
|
-
|
|
107
|
-
!material.uniforms ||
|
|
108
|
-
!material.textures ||
|
|
109
|
-
!material.defines ||
|
|
110
|
-
!material.includes) {
|
|
111
|
-
throw new Error('Invalid material instance. Create materials with defineMaterial(...) before passing them to <FragCanvas>.');
|
|
112
|
-
}
|
|
86
|
+
if (!Object.isFrozen(material) || !material.uniforms || !material.textures || !material.defines || !material.includes) throw new Error("Invalid material instance. Create materials with defineMaterial(...) before passing them to <FragCanvas>.");
|
|
113
87
|
}
|
|
114
88
|
/**
|
|
115
|
-
|
|
116
|
-
|
|
89
|
+
* Clones uniform value input to decouple material instances from external objects.
|
|
90
|
+
*/
|
|
117
91
|
function cloneUniformValue(value) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
clonedTypedValue = Object.freeze([...typedValue]);
|
|
133
|
-
}
|
|
134
|
-
return Object.freeze({
|
|
135
|
-
type: typed.type,
|
|
136
|
-
value: clonedTypedValue
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
return value;
|
|
92
|
+
if (typeof value === "number") return value;
|
|
93
|
+
if (Array.isArray(value)) return Object.freeze([...value]);
|
|
94
|
+
if (typeof value === "object" && value !== null && "type" in value && "value" in value) {
|
|
95
|
+
const typed = value;
|
|
96
|
+
const typedValue = typed.value;
|
|
97
|
+
let clonedTypedValue = typedValue;
|
|
98
|
+
if (typedValue instanceof Float32Array) clonedTypedValue = new Float32Array(typedValue);
|
|
99
|
+
else if (Array.isArray(typedValue)) clonedTypedValue = Object.freeze([...typedValue]);
|
|
100
|
+
return Object.freeze({
|
|
101
|
+
type: typed.type,
|
|
102
|
+
value: clonedTypedValue
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
return value;
|
|
140
106
|
}
|
|
141
107
|
/**
|
|
142
|
-
|
|
143
|
-
|
|
108
|
+
* Clones optional texture value payload.
|
|
109
|
+
*/
|
|
144
110
|
function cloneTextureValue(value) {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
...(data.update !== undefined ? { update: data.update } : {})
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
return value;
|
|
111
|
+
if (value === void 0 || value === null) return null;
|
|
112
|
+
if (typeof value === "object" && "source" in value) {
|
|
113
|
+
const data = value;
|
|
114
|
+
return {
|
|
115
|
+
source: data.source,
|
|
116
|
+
...data.width !== void 0 ? { width: data.width } : {},
|
|
117
|
+
...data.height !== void 0 ? { height: data.height } : {},
|
|
118
|
+
...data.colorSpace !== void 0 ? { colorSpace: data.colorSpace } : {},
|
|
119
|
+
...data.flipY !== void 0 ? { flipY: data.flipY } : {},
|
|
120
|
+
...data.premultipliedAlpha !== void 0 ? { premultipliedAlpha: data.premultipliedAlpha } : {},
|
|
121
|
+
...data.generateMipmaps !== void 0 ? { generateMipmaps: data.generateMipmaps } : {},
|
|
122
|
+
...data.update !== void 0 ? { update: data.update } : {}
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
return value;
|
|
164
126
|
}
|
|
165
127
|
/**
|
|
166
|
-
|
|
167
|
-
|
|
128
|
+
* Clones and validates fragment source contract.
|
|
129
|
+
*/
|
|
168
130
|
function resolveFragment(fragment) {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
const returnType = normalizeSignaturePart(signature[2] ?? '');
|
|
182
|
-
if (params !== 'uv: vec2f') {
|
|
183
|
-
throw new Error(`Material fragment contract mismatch for \`frag\`: expected parameter list \`(uv: vec2f)\`, received \`(${params || '...'})\`.`);
|
|
184
|
-
}
|
|
185
|
-
if (returnType !== 'vec4f') {
|
|
186
|
-
throw new Error(`Material fragment contract mismatch for \`frag\`: expected return type \`vec4f\`, received \`${returnType}\`.`);
|
|
187
|
-
}
|
|
188
|
-
return fragment;
|
|
131
|
+
if (typeof fragment !== "string" || fragment.trim().length === 0) throw new Error("Material fragment shader must be a non-empty WGSL string.");
|
|
132
|
+
const signature = fragment.match(FRAGMENT_FUNCTION_SIGNATURE_PATTERN);
|
|
133
|
+
if (!signature) {
|
|
134
|
+
const discoveredFunctions = listFunctionNames(fragment).slice(0, 4);
|
|
135
|
+
const discoveredLabel = discoveredFunctions.length > 0 ? `Found: ${discoveredFunctions.map((name) => `\`${name}(...)\``).join(", ")}.` : "No WGSL function declarations were found.";
|
|
136
|
+
throw new Error(`Material fragment contract mismatch: missing entrypoint \`fn frag(uv: vec2f) -> vec4f\`. ${discoveredLabel}`);
|
|
137
|
+
}
|
|
138
|
+
const params = normalizeSignaturePart(signature[1] ?? "");
|
|
139
|
+
const returnType = normalizeSignaturePart(signature[2] ?? "");
|
|
140
|
+
if (params !== "uv: vec2f") throw new Error(`Material fragment contract mismatch for \`frag\`: expected parameter list \`(uv: vec2f)\`, received \`(${params || "..."})\`.`);
|
|
141
|
+
if (returnType !== "vec4f") throw new Error(`Material fragment contract mismatch for \`frag\`: expected return type \`vec4f\`, received \`${returnType}\`.`);
|
|
142
|
+
return fragment;
|
|
189
143
|
}
|
|
190
144
|
/**
|
|
191
|
-
|
|
192
|
-
|
|
145
|
+
* Clones and validates uniform declarations.
|
|
146
|
+
*/
|
|
193
147
|
function resolveUniforms(uniforms) {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
return resolved;
|
|
148
|
+
const resolved = {};
|
|
149
|
+
for (const [name, value] of Object.entries(uniforms ?? {})) {
|
|
150
|
+
assertUniformName(name);
|
|
151
|
+
const clonedValue = cloneUniformValue(value);
|
|
152
|
+
assertUniformValueForType(inferUniformType(clonedValue), clonedValue);
|
|
153
|
+
resolved[name] = clonedValue;
|
|
154
|
+
}
|
|
155
|
+
resolveUniformLayout(resolved);
|
|
156
|
+
return resolved;
|
|
204
157
|
}
|
|
205
158
|
/**
|
|
206
|
-
|
|
207
|
-
|
|
159
|
+
* Clones and validates texture declarations.
|
|
160
|
+
*/
|
|
208
161
|
function resolveTextures(textures) {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
162
|
+
const resolved = {};
|
|
163
|
+
for (const [name, definition] of Object.entries(textures ?? {})) {
|
|
164
|
+
assertUniformName(name);
|
|
165
|
+
const source = definition?.source;
|
|
166
|
+
const normalizedSource = cloneTextureValue(source);
|
|
167
|
+
const clonedDefinition = {
|
|
168
|
+
...definition ?? {},
|
|
169
|
+
...source !== void 0 ? { source: normalizedSource } : {}
|
|
170
|
+
};
|
|
171
|
+
resolved[name] = Object.freeze(clonedDefinition);
|
|
172
|
+
}
|
|
173
|
+
return resolved;
|
|
221
174
|
}
|
|
222
175
|
/**
|
|
223
|
-
|
|
224
|
-
|
|
176
|
+
* Clones and validates define declarations.
|
|
177
|
+
*/
|
|
225
178
|
function resolveDefines(defines) {
|
|
226
|
-
|
|
179
|
+
return normalizeDefines(defines);
|
|
227
180
|
}
|
|
228
181
|
/**
|
|
229
|
-
|
|
230
|
-
|
|
182
|
+
* Clones and validates include declarations.
|
|
183
|
+
*/
|
|
231
184
|
function resolveIncludes(includes) {
|
|
232
|
-
|
|
185
|
+
return normalizeIncludes(includes);
|
|
233
186
|
}
|
|
234
187
|
/**
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
188
|
+
* Builds a deterministic texture-config signature map used in material cache signatures.
|
|
189
|
+
*
|
|
190
|
+
* @param textures - Raw texture definitions from material input.
|
|
191
|
+
* @param textureKeys - Sorted texture keys.
|
|
192
|
+
* @returns Compact signature entries describing effective texture config per key.
|
|
193
|
+
*/
|
|
241
194
|
function buildTextureConfigSignature(textures, textureKeys) {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
195
|
+
const signature = {};
|
|
196
|
+
for (const key of textureKeys) {
|
|
197
|
+
const normalized = normalizeTextureDefinition(textures[key]);
|
|
198
|
+
signature[key] = [
|
|
199
|
+
normalized.colorSpace,
|
|
200
|
+
normalized.flipY ? "1" : "0",
|
|
201
|
+
normalized.generateMipmaps ? "1" : "0",
|
|
202
|
+
normalized.premultipliedAlpha ? "1" : "0",
|
|
203
|
+
normalized.anisotropy,
|
|
204
|
+
normalized.filter,
|
|
205
|
+
normalized.addressModeU,
|
|
206
|
+
normalized.addressModeV
|
|
207
|
+
].join(":");
|
|
208
|
+
}
|
|
209
|
+
return signature;
|
|
257
210
|
}
|
|
258
211
|
/**
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
.map(([key, value]) => {
|
|
272
|
-
assertUniformName(key);
|
|
273
|
-
return toDefineLine(key, value);
|
|
274
|
-
})
|
|
275
|
-
.join('\n');
|
|
212
|
+
* Creates a stable WGSL define block from the provided map.
|
|
213
|
+
*
|
|
214
|
+
* @param defines - Optional material defines.
|
|
215
|
+
* @returns Joined WGSL const declarations ordered by key.
|
|
216
|
+
*/
|
|
217
|
+
function buildDefinesBlock(defines) {
|
|
218
|
+
const normalizedDefines = normalizeDefines(defines);
|
|
219
|
+
if (Object.keys(normalizedDefines).length === 0) return "";
|
|
220
|
+
return Object.entries(normalizedDefines).sort(([a], [b]) => a.localeCompare(b)).map(([key, value]) => {
|
|
221
|
+
assertUniformName(key);
|
|
222
|
+
return toDefineLine(key, value);
|
|
223
|
+
}).join("\n");
|
|
276
224
|
}
|
|
277
225
|
/**
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
}
|
|
289
|
-
return `${defineBlock}\n\n${fragment}`;
|
|
226
|
+
* Prepends resolved defines to a fragment shader.
|
|
227
|
+
*
|
|
228
|
+
* @param fragment - Raw WGSL fragment source.
|
|
229
|
+
* @param defines - Optional define map.
|
|
230
|
+
* @returns Fragment source with a leading define block when defines are present.
|
|
231
|
+
*/
|
|
232
|
+
function applyMaterialDefines(fragment, defines) {
|
|
233
|
+
const defineBlock = buildDefinesBlock(defines);
|
|
234
|
+
if (defineBlock.length === 0) return fragment;
|
|
235
|
+
return `${defineBlock}\n\n${fragment}`;
|
|
290
236
|
}
|
|
291
237
|
/**
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
238
|
+
* Creates an immutable material object with validated shader/uniform/texture contracts.
|
|
239
|
+
*
|
|
240
|
+
* @param input - User material declaration.
|
|
241
|
+
* @returns Frozen material object safe to share and cache.
|
|
242
|
+
*/
|
|
243
|
+
function defineMaterial(input) {
|
|
244
|
+
const fragment = resolveFragment(input.fragment);
|
|
245
|
+
const uniforms = Object.freeze(resolveUniforms(input.uniforms));
|
|
246
|
+
const textures = Object.freeze(resolveTextures(input.textures));
|
|
247
|
+
const defines = Object.freeze(resolveDefines(input.defines));
|
|
248
|
+
const includes = Object.freeze(resolveIncludes(input.includes));
|
|
249
|
+
const source = Object.freeze(resolveSourceMetadata(void 0));
|
|
250
|
+
const rawStorageBuffers = input.storageBuffers ?? {};
|
|
251
|
+
for (const [name, definition] of Object.entries(rawStorageBuffers)) assertStorageBufferDefinition(name, definition);
|
|
252
|
+
const storageBuffers = Object.freeze(Object.fromEntries(Object.entries(rawStorageBuffers).map(([name, definition]) => {
|
|
253
|
+
const def = definition;
|
|
254
|
+
const cloned = {
|
|
255
|
+
size: def.size,
|
|
256
|
+
type: def.type,
|
|
257
|
+
...def.access !== void 0 ? { access: def.access } : {},
|
|
258
|
+
...def.initialData !== void 0 ? { initialData: def.initialData.slice() } : {}
|
|
259
|
+
};
|
|
260
|
+
return [name, Object.freeze(cloned)];
|
|
261
|
+
})));
|
|
262
|
+
for (const [name, definition] of Object.entries(textures)) if (definition?.storage) {
|
|
263
|
+
if (!definition.format) throw new Error(`Texture "${name}" with storage:true requires a \`format\` field.`);
|
|
264
|
+
assertStorageTextureFormat(name, definition.format);
|
|
265
|
+
}
|
|
266
|
+
const preprocessed = preprocessMaterialFragment({
|
|
267
|
+
fragment,
|
|
268
|
+
defines,
|
|
269
|
+
includes
|
|
270
|
+
});
|
|
271
|
+
const material = Object.freeze({
|
|
272
|
+
fragment,
|
|
273
|
+
uniforms,
|
|
274
|
+
textures,
|
|
275
|
+
defines,
|
|
276
|
+
includes,
|
|
277
|
+
storageBuffers
|
|
278
|
+
});
|
|
279
|
+
preprocessedFragmentCache.set(material, preprocessed);
|
|
280
|
+
materialSourceMetadataCache.set(material, source);
|
|
281
|
+
return material;
|
|
319
282
|
}
|
|
320
283
|
/**
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
284
|
+
* Resolves a material to renderer-ready data and a deterministic signature.
|
|
285
|
+
*
|
|
286
|
+
* @param material - Material input created via {@link defineMaterial}.
|
|
287
|
+
* @returns Resolved material with packed uniform layout, sorted texture keys and cache signature.
|
|
288
|
+
*/
|
|
289
|
+
function resolveMaterial(material) {
|
|
290
|
+
assertDefinedMaterial(material);
|
|
291
|
+
const cached = getCachedResolvedMaterial(material);
|
|
292
|
+
if (cached) return cached;
|
|
293
|
+
const uniforms = material.uniforms;
|
|
294
|
+
const textures = material.textures;
|
|
295
|
+
const uniformLayout = resolveUniformLayout(uniforms);
|
|
296
|
+
const textureKeys = Object.keys(textures).sort();
|
|
297
|
+
const preprocessed = preprocessedFragmentCache.get(material) ?? preprocessMaterialFragment({
|
|
298
|
+
fragment: material.fragment,
|
|
299
|
+
defines: material.defines,
|
|
300
|
+
includes: material.includes
|
|
301
|
+
});
|
|
302
|
+
const fragmentWgsl = preprocessed.fragment;
|
|
303
|
+
const textureConfig = buildTextureConfigSignature(textures, textureKeys);
|
|
304
|
+
const storageBufferKeys = Object.keys(material.storageBuffers ?? {}).sort();
|
|
305
|
+
const storageTextureKeys = textureKeys.filter((key) => textures[key]?.storage === true);
|
|
306
|
+
const signature = JSON.stringify({
|
|
307
|
+
fragmentWgsl,
|
|
308
|
+
uniforms: uniformLayout.entries.map((entry) => `${entry.name}:${entry.type}`),
|
|
309
|
+
textureKeys,
|
|
310
|
+
textureConfig,
|
|
311
|
+
storageBufferKeys: storageBufferKeys.map((key) => {
|
|
312
|
+
const def = material.storageBuffers[key];
|
|
313
|
+
return `${key}:${def?.type ?? "?"}:${def?.size ?? 0}:${def?.access ?? "read-write"}`;
|
|
314
|
+
}),
|
|
315
|
+
storageTextureKeys
|
|
316
|
+
});
|
|
317
|
+
const resolved = {
|
|
318
|
+
fragmentWgsl,
|
|
319
|
+
fragmentLineMap: preprocessed.lineMap,
|
|
320
|
+
uniforms,
|
|
321
|
+
textures,
|
|
322
|
+
uniformLayout,
|
|
323
|
+
textureKeys,
|
|
324
|
+
signature,
|
|
325
|
+
fragmentSource: material.fragment,
|
|
326
|
+
includeSources: material.includes,
|
|
327
|
+
defineBlockSource: preprocessed.defineBlockSource,
|
|
328
|
+
source: materialSourceMetadataCache.get(material) ?? null,
|
|
329
|
+
storageBufferKeys,
|
|
330
|
+
storageTextureKeys
|
|
331
|
+
};
|
|
332
|
+
resolvedMaterialCache.set(material, resolved);
|
|
333
|
+
return resolved;
|
|
365
334
|
}
|
|
335
|
+
//#endregion
|
|
336
|
+
export { applyMaterialDefines, buildDefinesBlock, defineMaterial, resolveMaterial };
|
|
337
|
+
|
|
338
|
+
//# sourceMappingURL=material.js.map
|