@react-three/fiber 10.0.0-canary.2c50459 → 10.0.0-canary.4a21acb
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/index.cjs +214 -107
- package/dist/index.d.cts +49 -25
- package/dist/index.d.mts +49 -25
- package/dist/index.d.ts +49 -25
- package/dist/index.mjs +216 -109
- package/dist/legacy.cjs +169 -62
- package/dist/legacy.d.cts +49 -24
- package/dist/legacy.d.mts +49 -24
- package/dist/legacy.d.ts +49 -24
- package/dist/legacy.mjs +170 -63
- package/dist/webgpu/index.cjs +501 -635
- package/dist/webgpu/index.d.cts +83 -29
- package/dist/webgpu/index.d.mts +83 -29
- package/dist/webgpu/index.d.ts +83 -29
- package/dist/webgpu/index.mjs +503 -637
- package/package.json +3 -3
- package/readme.md +0 -1
package/dist/webgpu/index.cjs
CHANGED
|
@@ -63,13 +63,16 @@ const WebGLRenderer = class WebGLRenderer2 {
|
|
|
63
63
|
}
|
|
64
64
|
};
|
|
65
65
|
const WebGLRenderTarget = null;
|
|
66
|
+
const WebGLCubeRenderTarget = null;
|
|
66
67
|
|
|
67
68
|
const THREE = /*#__PURE__*/_mergeNamespaces({
|
|
68
69
|
__proto__: null,
|
|
70
|
+
CubeRenderTargetCompat: webgpu.CubeRenderTarget,
|
|
69
71
|
Inspector: Inspector_js.Inspector,
|
|
70
72
|
R3F_BUILD_LEGACY: R3F_BUILD_LEGACY,
|
|
71
73
|
R3F_BUILD_WEBGPU: R3F_BUILD_WEBGPU,
|
|
72
74
|
RenderTargetCompat: webgpu.RenderTarget,
|
|
75
|
+
WebGLCubeRenderTarget: WebGLCubeRenderTarget,
|
|
73
76
|
WebGLRenderTarget: WebGLRenderTarget,
|
|
74
77
|
WebGLRenderer: WebGLRenderer
|
|
75
78
|
}, [webgpu__namespace]);
|
|
@@ -343,15 +346,16 @@ function EnvironmentPortal({
|
|
|
343
346
|
preset = void 0,
|
|
344
347
|
extensions
|
|
345
348
|
}) {
|
|
346
|
-
const
|
|
349
|
+
const renderer = fiber.useThree((state) => state.renderer);
|
|
350
|
+
const isLegacy = fiber.useThree((state) => state.isLegacy);
|
|
347
351
|
const defaultScene = fiber.useThree((state) => state.scene);
|
|
348
352
|
const camera = React__namespace.useRef(null);
|
|
349
353
|
const [virtualScene] = React__namespace.useState(() => new webgpu.Scene());
|
|
350
354
|
const fbo = React__namespace.useMemo(() => {
|
|
351
|
-
const fbo2 = new webgpu.
|
|
355
|
+
const fbo2 = isLegacy ? new WebGLCubeRenderTarget(resolution) : new webgpu.CubeRenderTarget(resolution);
|
|
352
356
|
fbo2.texture.type = webgpu.HalfFloatType;
|
|
353
357
|
return fbo2;
|
|
354
|
-
}, [resolution]);
|
|
358
|
+
}, [resolution, isLegacy]);
|
|
355
359
|
React__namespace.useEffect(() => {
|
|
356
360
|
return () => {
|
|
357
361
|
fbo.dispose();
|
|
@@ -359,10 +363,10 @@ function EnvironmentPortal({
|
|
|
359
363
|
}, [fbo]);
|
|
360
364
|
React__namespace.useLayoutEffect(() => {
|
|
361
365
|
if (frames === 1) {
|
|
362
|
-
const autoClear =
|
|
363
|
-
|
|
364
|
-
camera.current.update(
|
|
365
|
-
|
|
366
|
+
const autoClear = renderer.autoClear;
|
|
367
|
+
renderer.autoClear = true;
|
|
368
|
+
camera.current.update(renderer, virtualScene);
|
|
369
|
+
renderer.autoClear = autoClear;
|
|
366
370
|
}
|
|
367
371
|
return setEnvProps(background, scene, defaultScene, fbo.texture, {
|
|
368
372
|
backgroundBlurriness: blur ?? backgroundBlurriness,
|
|
@@ -379,7 +383,7 @@ function EnvironmentPortal({
|
|
|
379
383
|
defaultScene,
|
|
380
384
|
background,
|
|
381
385
|
frames,
|
|
382
|
-
|
|
386
|
+
renderer,
|
|
383
387
|
blur,
|
|
384
388
|
backgroundBlurriness,
|
|
385
389
|
backgroundIntensity,
|
|
@@ -390,10 +394,10 @@ function EnvironmentPortal({
|
|
|
390
394
|
let count = 1;
|
|
391
395
|
fiber.useFrame(() => {
|
|
392
396
|
if (frames === Infinity || count < frames) {
|
|
393
|
-
const autoClear =
|
|
394
|
-
|
|
395
|
-
camera.current.update(
|
|
396
|
-
|
|
397
|
+
const autoClear = renderer.autoClear;
|
|
398
|
+
renderer.autoClear = true;
|
|
399
|
+
camera.current.update(renderer, virtualScene);
|
|
400
|
+
renderer.autoClear = autoClear;
|
|
397
401
|
count++;
|
|
398
402
|
}
|
|
399
403
|
});
|
|
@@ -636,8 +640,7 @@ function prepare(target, root, type, props) {
|
|
|
636
640
|
object,
|
|
637
641
|
eventCount: 0,
|
|
638
642
|
handlers: {},
|
|
639
|
-
isHidden: false
|
|
640
|
-
deferredRefs: []
|
|
643
|
+
isHidden: false
|
|
641
644
|
};
|
|
642
645
|
if (object) object.__r3f = instance;
|
|
643
646
|
}
|
|
@@ -794,6 +797,17 @@ function unregisterVisibility(store, object) {
|
|
|
794
797
|
internal.visibilityRegistry.delete(object.uuid);
|
|
795
798
|
internal.occlusionCache.delete(object);
|
|
796
799
|
}
|
|
800
|
+
function updateVisibilityHandlers(store, object, handlers) {
|
|
801
|
+
const { internal } = store.getState();
|
|
802
|
+
const entry = internal.visibilityRegistry.get(object.uuid);
|
|
803
|
+
if (!entry) return false;
|
|
804
|
+
entry.handlers = handlers;
|
|
805
|
+
if ((handlers.onOccluded || handlers.onVisible) && !internal.occlusionEnabled) {
|
|
806
|
+
object.occlusionTest = true;
|
|
807
|
+
enableOcclusion(store);
|
|
808
|
+
}
|
|
809
|
+
return true;
|
|
810
|
+
}
|
|
797
811
|
function checkVisibility(state) {
|
|
798
812
|
const { internal, camera } = state;
|
|
799
813
|
const registry = internal.visibilityRegistry;
|
|
@@ -981,10 +995,7 @@ function applyProps(object, props) {
|
|
|
981
995
|
continue;
|
|
982
996
|
}
|
|
983
997
|
if (value === void 0) continue;
|
|
984
|
-
if (isFromRef(value))
|
|
985
|
-
instance?.deferredRefs?.push({ prop, ref: value[FROM_REF] });
|
|
986
|
-
continue;
|
|
987
|
-
}
|
|
998
|
+
if (isFromRef(value)) continue;
|
|
988
999
|
if (isOnce(value)) {
|
|
989
1000
|
if (instance?.appliedOnce?.has(prop)) continue;
|
|
990
1001
|
if (instance) {
|
|
@@ -1020,6 +1031,19 @@ function applyProps(object, props) {
|
|
|
1020
1031
|
} else if (isVectorLike(target) && is.num(value)) {
|
|
1021
1032
|
if ("setScalar" in target && typeof target.setScalar === "function") target.setScalar(value);
|
|
1022
1033
|
else target.set(value);
|
|
1034
|
+
} else if (root instanceof webgpu.ShaderMaterial && key === "uniforms" && is.obj(value)) {
|
|
1035
|
+
if (!is.obj(root.uniforms)) root.uniforms = {};
|
|
1036
|
+
const uniforms = root.uniforms;
|
|
1037
|
+
const nextUniforms = value;
|
|
1038
|
+
for (const name in nextUniforms) {
|
|
1039
|
+
const uniform = nextUniforms[name];
|
|
1040
|
+
const targetUniform = uniforms[name];
|
|
1041
|
+
if (targetUniform) Object.assign(targetUniform, uniform);
|
|
1042
|
+
else {
|
|
1043
|
+
const nextUniform = uniform instanceof webgpu.Uniform ? uniform.clone() : new webgpu.Uniform(uniform.value);
|
|
1044
|
+
uniforms[name] = nextUniform;
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1023
1047
|
} else {
|
|
1024
1048
|
root[key] = value;
|
|
1025
1049
|
if (key.endsWith("Node") && root.isMaterial) {
|
|
@@ -1038,6 +1062,9 @@ function applyProps(object, props) {
|
|
|
1038
1062
|
if (instance.eventCount && object2.raycast !== null) {
|
|
1039
1063
|
rootState.internal.interaction.push(object2);
|
|
1040
1064
|
}
|
|
1065
|
+
}
|
|
1066
|
+
if (instance?.parent && rootState?.internal && instance.object?.isObject3D) {
|
|
1067
|
+
const object2 = instance.object;
|
|
1041
1068
|
const root = findInitialRoot(instance);
|
|
1042
1069
|
const visibilityHandlers = {
|
|
1043
1070
|
onFramed: instance.handlers.onFramed,
|
|
@@ -1045,7 +1072,9 @@ function applyProps(object, props) {
|
|
|
1045
1072
|
onVisible: instance.handlers.onVisible
|
|
1046
1073
|
};
|
|
1047
1074
|
if (hasVisibilityHandlers(visibilityHandlers)) {
|
|
1048
|
-
|
|
1075
|
+
if (!updateVisibilityHandlers(root, object2, visibilityHandlers)) {
|
|
1076
|
+
registerVisibility(root, object2, visibilityHandlers);
|
|
1077
|
+
}
|
|
1049
1078
|
} else {
|
|
1050
1079
|
unregisterVisibility(root, object2);
|
|
1051
1080
|
}
|
|
@@ -1573,6 +1602,7 @@ function createPointerEvents(store) {
|
|
|
1573
1602
|
set((state) => ({ events: { ...state.events, connected: void 0 } }));
|
|
1574
1603
|
}
|
|
1575
1604
|
},
|
|
1605
|
+
// PREVIEW (A8): the XR pointer registration API may change before stable.
|
|
1576
1606
|
registerPointer: (config) => {
|
|
1577
1607
|
const pointerId = nextXRPointerId++;
|
|
1578
1608
|
xrPointers.set(pointerId, config);
|
|
@@ -1659,6 +1689,13 @@ function notifyAlpha({ message, link }) {
|
|
|
1659
1689
|
}
|
|
1660
1690
|
}
|
|
1661
1691
|
|
|
1692
|
+
const INTERNAL_LIB_MARKERS = ["zustand", "setState", "Object.assign"];
|
|
1693
|
+
function isInternalRendererAccess(stack, callerDepth = 2) {
|
|
1694
|
+
if (!stack) return false;
|
|
1695
|
+
const caller = stack.split("\n")[callerDepth] ?? "";
|
|
1696
|
+
return INTERNAL_LIB_MARKERS.some((m) => caller.includes(m));
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1662
1699
|
const R3F_CONTEXT = Symbol.for("@react-three/fiber.context");
|
|
1663
1700
|
const context = globalThis[R3F_CONTEXT] ?? (globalThis[R3F_CONTEXT] = React__namespace.createContext(null));
|
|
1664
1701
|
const createStore = (invalidate, advance) => {
|
|
@@ -1791,6 +1828,7 @@ const createStore = (invalidate, advance) => {
|
|
|
1791
1828
|
}),
|
|
1792
1829
|
setFrameloop: (frameloop = "always") => {
|
|
1793
1830
|
set(() => ({ frameloop }));
|
|
1831
|
+
scheduler.getScheduler().frameloop = frameloop;
|
|
1794
1832
|
},
|
|
1795
1833
|
setError: (error) => set(() => ({ error })),
|
|
1796
1834
|
error: null,
|
|
@@ -1858,8 +1896,7 @@ const createStore = (invalidate, advance) => {
|
|
|
1858
1896
|
const currentState = rootStore.getState();
|
|
1859
1897
|
if (!currentState.isLegacy && currentState.internal.actualRenderer) {
|
|
1860
1898
|
const stack = new Error().stack || "";
|
|
1861
|
-
|
|
1862
|
-
if (!isInternalAccess) {
|
|
1899
|
+
if (!isInternalRendererAccess(stack)) {
|
|
1863
1900
|
const cleanedStack = stack.split("\n").slice(2).join("\n") || "Stack trace unavailable";
|
|
1864
1901
|
notifyDepreciated({
|
|
1865
1902
|
heading: "Accessing state.gl in WebGPU mode",
|
|
@@ -1972,19 +2009,25 @@ function loadingFn(extensions, onProgress) {
|
|
|
1972
2009
|
);
|
|
1973
2010
|
};
|
|
1974
2011
|
}
|
|
1975
|
-
function useLoader(loader, input, extensions, onProgress) {
|
|
1976
|
-
const
|
|
2012
|
+
function useLoader(loader, input, extensions, onProgress, cacheKey) {
|
|
2013
|
+
const inputs = Array.isArray(input) ? input : [input];
|
|
2014
|
+
const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
|
|
1977
2015
|
const fn = loadingFn(extensions, onProgress);
|
|
1978
|
-
const results =
|
|
2016
|
+
const results = cacheKeys.map(
|
|
2017
|
+
(key, index) => suspendReact.suspend(() => fn(loader, inputs[index]), [loader, key], { equal: is.equ })
|
|
2018
|
+
);
|
|
1979
2019
|
return Array.isArray(input) ? results : results[0];
|
|
1980
2020
|
}
|
|
1981
|
-
useLoader.preload = function(loader, input, extensions, onProgress) {
|
|
1982
|
-
const
|
|
1983
|
-
|
|
2021
|
+
useLoader.preload = function(loader, input, extensions, onProgress, cacheKey) {
|
|
2022
|
+
const inputs = Array.isArray(input) ? input : [input];
|
|
2023
|
+
const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
|
|
2024
|
+
cacheKeys.forEach(
|
|
2025
|
+
(key, index) => suspendReact.preload(() => loadingFn(extensions, onProgress)(loader, inputs[index]), [loader, key])
|
|
2026
|
+
);
|
|
1984
2027
|
};
|
|
1985
|
-
useLoader.clear = function(loader, input) {
|
|
1986
|
-
const
|
|
1987
|
-
|
|
2028
|
+
useLoader.clear = function(loader, input, cacheKey) {
|
|
2029
|
+
const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
|
|
2030
|
+
cacheKeys.forEach((key) => suspendReact.clear([loader, key]));
|
|
1988
2031
|
};
|
|
1989
2032
|
useLoader.loader = getLoader;
|
|
1990
2033
|
|
|
@@ -2404,7 +2447,7 @@ function advance(timestamp) {
|
|
|
2404
2447
|
scheduler.getScheduler().step(timestamp);
|
|
2405
2448
|
}
|
|
2406
2449
|
|
|
2407
|
-
const version = "10.0.0-alpha.
|
|
2450
|
+
const version = "10.0.0-alpha.3";
|
|
2408
2451
|
const packageData = {
|
|
2409
2452
|
version: version};
|
|
2410
2453
|
|
|
@@ -13843,6 +13886,7 @@ function swapInstances() {
|
|
|
13843
13886
|
}
|
|
13844
13887
|
}
|
|
13845
13888
|
if (instance.isHidden) unhideInstance(instance);
|
|
13889
|
+
if (isObject3D(instance.object)) removeInteractivity(findInitialRoot(instance), instance.object);
|
|
13846
13890
|
if (instance.object.__r3f) delete instance.object.__r3f;
|
|
13847
13891
|
if (instance.type !== "primitive") disposeOnIdle(instance.object);
|
|
13848
13892
|
}
|
|
@@ -13855,6 +13899,8 @@ function swapInstances() {
|
|
|
13855
13899
|
instance.object.__r3f = instance;
|
|
13856
13900
|
setFiberRef(fiber, instance.object);
|
|
13857
13901
|
delete instance.appliedOnce;
|
|
13902
|
+
instance.eventCount = 0;
|
|
13903
|
+
instance.handlers = {};
|
|
13858
13904
|
applyProps(instance.object, instance.props);
|
|
13859
13905
|
if (instance.props.attach) {
|
|
13860
13906
|
attach(parent, instance);
|
|
@@ -14070,11 +14116,15 @@ const reconciler = /* @__PURE__ */ createReconciler({
|
|
|
14070
14116
|
cloneMutableTextInstance(textInstance) {
|
|
14071
14117
|
return textInstance;
|
|
14072
14118
|
},
|
|
14119
|
+
// React 19.2 added these for root-level view transitions. They only run for hosts that opt into
|
|
14120
|
+
// view transitions by returning a container from cloneRootViewTransitionContainer; R3F renders
|
|
14121
|
+
// into a WebGL/WebGPU canvas, where cloning the root has no meaning, so we never opt in and
|
|
14122
|
+
// React never calls them. They stay as no-ops rather than throws: the host config is shared by
|
|
14123
|
+
// every root, and a throw here would turn a React-internal probe into a hard crash for users.
|
|
14124
|
+
// Guarded by a test asserting a full render + unmount never reaches them.
|
|
14073
14125
|
cloneRootViewTransitionContainer(_rootContainer) {
|
|
14074
|
-
throw new Error("Not implemented.");
|
|
14075
14126
|
},
|
|
14076
14127
|
removeRootViewTransitionClone(_rootContainer, _clone) {
|
|
14077
|
-
throw new Error("Not implemented.");
|
|
14078
14128
|
},
|
|
14079
14129
|
// https://github.com/facebook/react/pull/32465
|
|
14080
14130
|
createFragmentInstance: (_fiber) => null,
|
|
@@ -14159,6 +14209,7 @@ function createRoot(canvas) {
|
|
|
14159
14209
|
const lastConfiguredProps = {};
|
|
14160
14210
|
let configured = false;
|
|
14161
14211
|
let pending = null;
|
|
14212
|
+
let rendererSetup = null;
|
|
14162
14213
|
return {
|
|
14163
14214
|
async configure(props = {}) {
|
|
14164
14215
|
let resolve;
|
|
@@ -14189,7 +14240,7 @@ function createRoot(canvas) {
|
|
|
14189
14240
|
forceEven
|
|
14190
14241
|
} = props;
|
|
14191
14242
|
const textureColorSpace = is.obj(glConfig) && !is.fun(glConfig) && !isRenderer(glConfig) && glConfig.textureColorSpace || is.obj(rendererConfig) && !is.fun(rendererConfig) && !isRenderer(rendererConfig) && rendererConfig.textureColorSpace || webgpu.SRGBColorSpace;
|
|
14192
|
-
|
|
14243
|
+
let state = store.getState();
|
|
14193
14244
|
const defaultGPUProps = {
|
|
14194
14245
|
canvas,
|
|
14195
14246
|
antialias: true
|
|
@@ -14203,52 +14254,64 @@ function createRoot(canvas) {
|
|
|
14203
14254
|
throw new Error("Cannot use both gl and renderer props at the same time");
|
|
14204
14255
|
}
|
|
14205
14256
|
let renderer = state.internal.actualRenderer;
|
|
14206
|
-
if (
|
|
14207
|
-
|
|
14208
|
-
|
|
14209
|
-
|
|
14210
|
-
|
|
14211
|
-
|
|
14212
|
-
|
|
14213
|
-
|
|
14214
|
-
|
|
14215
|
-
|
|
14216
|
-
|
|
14217
|
-
|
|
14218
|
-
|
|
14219
|
-
|
|
14220
|
-
|
|
14221
|
-
|
|
14222
|
-
|
|
14223
|
-
|
|
14224
|
-
|
|
14225
|
-
|
|
14226
|
-
|
|
14227
|
-
|
|
14228
|
-
|
|
14229
|
-
|
|
14230
|
-
|
|
14231
|
-
|
|
14232
|
-
|
|
14233
|
-
|
|
14234
|
-
|
|
14235
|
-
|
|
14236
|
-
|
|
14237
|
-
|
|
14238
|
-
|
|
14239
|
-
|
|
14240
|
-
|
|
14241
|
-
|
|
14242
|
-
|
|
14243
|
-
|
|
14244
|
-
|
|
14245
|
-
|
|
14246
|
-
|
|
14247
|
-
|
|
14248
|
-
|
|
14257
|
+
if (!state.internal.actualRenderer) {
|
|
14258
|
+
if (!rendererSetup) {
|
|
14259
|
+
rendererSetup = (async () => {
|
|
14260
|
+
if (primaryCanvas) {
|
|
14261
|
+
const primary = await waitForPrimary(primaryCanvas);
|
|
14262
|
+
renderer = primary.renderer;
|
|
14263
|
+
state.internal.actualRenderer = renderer;
|
|
14264
|
+
const canvasTarget = new webgpu.CanvasTarget(canvas);
|
|
14265
|
+
primary.store.setState((prev) => ({
|
|
14266
|
+
internal: { ...prev.internal, isMultiCanvas: true }
|
|
14267
|
+
}));
|
|
14268
|
+
state.set((prev) => ({
|
|
14269
|
+
webGPUSupported: primary.store.getState().webGPUSupported,
|
|
14270
|
+
renderer,
|
|
14271
|
+
primaryStore: primary.store,
|
|
14272
|
+
internal: {
|
|
14273
|
+
...prev.internal,
|
|
14274
|
+
canvasTarget,
|
|
14275
|
+
isMultiCanvas: true,
|
|
14276
|
+
isSecondary: true,
|
|
14277
|
+
targetId: primaryCanvas
|
|
14278
|
+
}
|
|
14279
|
+
}));
|
|
14280
|
+
} else {
|
|
14281
|
+
renderer = await resolveRenderer(rendererConfig, defaultGPUProps, webgpu.WebGPURenderer);
|
|
14282
|
+
if (!renderer.hasInitialized?.()) {
|
|
14283
|
+
const size2 = computeInitialSize(canvas, propsSize);
|
|
14284
|
+
if (size2.width > 0 && size2.height > 0) {
|
|
14285
|
+
const pixelRatio = calculateDpr(dpr);
|
|
14286
|
+
canvas.width = size2.width * pixelRatio;
|
|
14287
|
+
canvas.height = size2.height * pixelRatio;
|
|
14288
|
+
}
|
|
14289
|
+
await renderer.init();
|
|
14290
|
+
}
|
|
14291
|
+
const backend = renderer.backend;
|
|
14292
|
+
const isWebGPUBackend = backend && "isWebGPUBackend" in backend;
|
|
14293
|
+
state.internal.actualRenderer = renderer;
|
|
14294
|
+
state.set({ webGPUSupported: isWebGPUBackend, renderer, primaryStore: store });
|
|
14295
|
+
if (canvasId && !state.internal.isSecondary) {
|
|
14296
|
+
const canvasTarget = new webgpu.CanvasTarget(canvas);
|
|
14297
|
+
const unregisterPrimary = registerPrimary(canvasId, renderer, store);
|
|
14298
|
+
state.set((prev) => ({
|
|
14299
|
+
internal: {
|
|
14300
|
+
...prev.internal,
|
|
14301
|
+
canvasTarget,
|
|
14302
|
+
unregisterPrimary
|
|
14303
|
+
}
|
|
14304
|
+
}));
|
|
14305
|
+
}
|
|
14249
14306
|
}
|
|
14250
|
-
}))
|
|
14307
|
+
})().catch((err) => {
|
|
14308
|
+
rendererSetup = null;
|
|
14309
|
+
throw err;
|
|
14310
|
+
});
|
|
14251
14311
|
}
|
|
14312
|
+
await rendererSetup;
|
|
14313
|
+
state = store.getState();
|
|
14314
|
+
renderer = state.internal.actualRenderer;
|
|
14252
14315
|
}
|
|
14253
14316
|
let raycaster = state.raycaster;
|
|
14254
14317
|
if (!raycaster) state.set({ raycaster: raycaster = new webgpu.Raycaster() });
|
|
@@ -14598,7 +14661,8 @@ function unmountComponentAtNode(canvas, callback) {
|
|
|
14598
14661
|
dispose(state.scene);
|
|
14599
14662
|
_roots.delete(canvas);
|
|
14600
14663
|
if (callback) callback(canvas);
|
|
14601
|
-
} catch {
|
|
14664
|
+
} catch (error) {
|
|
14665
|
+
console.warn("[R3F] Error while unmounting root; teardown may be incomplete:", error);
|
|
14602
14666
|
}
|
|
14603
14667
|
}, 500);
|
|
14604
14668
|
}
|
|
@@ -14661,6 +14725,7 @@ function PortalInner({ state = {}, children, container }) {
|
|
|
14661
14725
|
viewport = rootState.viewport.getCurrentViewport(camera, new webgpu.Vector3(), resolvedSize);
|
|
14662
14726
|
if (camera !== rootState.camera) updateCamera(camera, resolvedSize);
|
|
14663
14727
|
}
|
|
14728
|
+
const set = injectState.set;
|
|
14664
14729
|
return {
|
|
14665
14730
|
// The intersect consists of the previous root state
|
|
14666
14731
|
...rootState,
|
|
@@ -14679,7 +14744,7 @@ function PortalInner({ state = {}, children, container }) {
|
|
|
14679
14744
|
size: resolvedSize,
|
|
14680
14745
|
viewport: { ...rootState.viewport, ...viewport },
|
|
14681
14746
|
// Layers are allowed to override events
|
|
14682
|
-
setEvents: (events2) =>
|
|
14747
|
+
setEvents: (events2) => set((state2) => ({ ...state2, events: { ...state2.events, ...events2 } })),
|
|
14683
14748
|
// Container for child attachment - the portalScene (injected or container itself)
|
|
14684
14749
|
internal: { ...rootState.internal, ...injectState.internal, container: portalScene }
|
|
14685
14750
|
};
|
|
@@ -14738,14 +14803,146 @@ function parseBackground(background) {
|
|
|
14738
14803
|
return null;
|
|
14739
14804
|
}
|
|
14740
14805
|
|
|
14806
|
+
function parseRendererConfig(rendererProp) {
|
|
14807
|
+
const isRendererConfig = typeof rendererProp === "object" && rendererProp !== null && !("render" in rendererProp) && ("primaryCanvas" in rendererProp || "scheduler" in rendererProp);
|
|
14808
|
+
if (isRendererConfig) {
|
|
14809
|
+
const { primaryCanvas: pc, scheduler: sc, ...rest } = rendererProp;
|
|
14810
|
+
return {
|
|
14811
|
+
primaryCanvas: pc,
|
|
14812
|
+
scheduler: sc,
|
|
14813
|
+
renderer: Object.keys(rest).length > 0 ? rest : rendererProp
|
|
14814
|
+
};
|
|
14815
|
+
}
|
|
14816
|
+
return { primaryCanvas: void 0, scheduler: void 0, renderer: rendererProp };
|
|
14817
|
+
}
|
|
14818
|
+
|
|
14819
|
+
const RESOURCE_KINDS = ["nodes", "uniforms", "buffers", "gpuStorage"];
|
|
14820
|
+
const ROOT_SCOPE = "";
|
|
14821
|
+
const registries = /* @__PURE__ */ new WeakMap();
|
|
14822
|
+
function getKindRegistry(store, kind) {
|
|
14823
|
+
let registry = registries.get(store);
|
|
14824
|
+
if (!registry) {
|
|
14825
|
+
registry = {
|
|
14826
|
+
nodes: { valid: /* @__PURE__ */ new Set(), staged: /* @__PURE__ */ new Map() },
|
|
14827
|
+
uniforms: { valid: /* @__PURE__ */ new Set(), staged: /* @__PURE__ */ new Map() },
|
|
14828
|
+
buffers: { valid: /* @__PURE__ */ new Set(), staged: /* @__PURE__ */ new Map() },
|
|
14829
|
+
gpuStorage: { valid: /* @__PURE__ */ new Set(), staged: /* @__PURE__ */ new Map() }
|
|
14830
|
+
};
|
|
14831
|
+
registries.set(store, registry);
|
|
14832
|
+
}
|
|
14833
|
+
return registry[kind];
|
|
14834
|
+
}
|
|
14835
|
+
function resolvePrimary$1(store) {
|
|
14836
|
+
return store.getState().primaryStore ?? store;
|
|
14837
|
+
}
|
|
14838
|
+
function isScopeValid(store, kind, scopeKey) {
|
|
14839
|
+
return getKindRegistry(store, kind).valid.has(scopeKey);
|
|
14840
|
+
}
|
|
14841
|
+
function peekStaged(store, kind, scopeKey) {
|
|
14842
|
+
return getKindRegistry(store, kind).staged.get(scopeKey);
|
|
14843
|
+
}
|
|
14844
|
+
function stageEntries(store, kind, scopeKey, entries) {
|
|
14845
|
+
const { staged } = getKindRegistry(store, kind);
|
|
14846
|
+
const current = staged.get(scopeKey);
|
|
14847
|
+
if (current) Object.assign(current, entries);
|
|
14848
|
+
else staged.set(scopeKey, { ...entries });
|
|
14849
|
+
}
|
|
14850
|
+
function readCommittedScope(map, scopeKey, isLeaf) {
|
|
14851
|
+
if (scopeKey === ROOT_SCOPE) {
|
|
14852
|
+
const leaves = {};
|
|
14853
|
+
for (const [key, value] of Object.entries(map)) if (isLeaf(value)) leaves[key] = value;
|
|
14854
|
+
return leaves;
|
|
14855
|
+
}
|
|
14856
|
+
const scopeData = map[scopeKey];
|
|
14857
|
+
if (scopeData && typeof scopeData === "object" && !isLeaf(scopeData)) return scopeData;
|
|
14858
|
+
return {};
|
|
14859
|
+
}
|
|
14860
|
+
function withStagedOverlay(store, kind, committed) {
|
|
14861
|
+
const { staged } = getKindRegistry(store, kind);
|
|
14862
|
+
if (staged.size === 0) return committed;
|
|
14863
|
+
const view = { ...committed };
|
|
14864
|
+
for (const [scopeKey, entries] of staged) {
|
|
14865
|
+
if (scopeKey === ROOT_SCOPE) Object.assign(view, entries);
|
|
14866
|
+
else view[scopeKey] = { ...view[scopeKey], ...entries };
|
|
14867
|
+
}
|
|
14868
|
+
return view;
|
|
14869
|
+
}
|
|
14870
|
+
function flushStagedScope(store, kind, scopeKey, isLeaf) {
|
|
14871
|
+
const registry = getKindRegistry(store, kind);
|
|
14872
|
+
const staged = registry.staged.get(scopeKey);
|
|
14873
|
+
if (!staged) return;
|
|
14874
|
+
registry.staged.delete(scopeKey);
|
|
14875
|
+
const replace = !registry.valid.has(scopeKey);
|
|
14876
|
+
store.setState((state) => {
|
|
14877
|
+
const map = state[kind];
|
|
14878
|
+
if (scopeKey === ROOT_SCOPE) {
|
|
14879
|
+
if (!replace) return { [kind]: { ...map, ...staged } };
|
|
14880
|
+
const next = {};
|
|
14881
|
+
for (const [key, value] of Object.entries(map)) if (!isLeaf(value)) next[key] = value;
|
|
14882
|
+
return { [kind]: { ...next, ...staged } };
|
|
14883
|
+
}
|
|
14884
|
+
const current = replace ? {} : map[scopeKey] ?? {};
|
|
14885
|
+
return { [kind]: { ...map, [scopeKey]: { ...current, ...staged } } };
|
|
14886
|
+
});
|
|
14887
|
+
registry.valid.add(scopeKey);
|
|
14888
|
+
}
|
|
14889
|
+
function invalidateResource(store, kind, scopeKey) {
|
|
14890
|
+
const registry = getKindRegistry(store, kind);
|
|
14891
|
+
if (scopeKey === void 0) {
|
|
14892
|
+
registry.valid.clear();
|
|
14893
|
+
registry.staged.clear();
|
|
14894
|
+
} else {
|
|
14895
|
+
registry.valid.delete(scopeKey);
|
|
14896
|
+
registry.staged.delete(scopeKey);
|
|
14897
|
+
}
|
|
14898
|
+
}
|
|
14899
|
+
function rebuildResource(store, kind, userScope) {
|
|
14900
|
+
const primary = resolvePrimary$1(store);
|
|
14901
|
+
invalidateResource(primary, kind, userScope === "root" ? ROOT_SCOPE : userScope);
|
|
14902
|
+
primary.setState((state) => ({ _hmrVersion: state._hmrVersion + 1 }));
|
|
14903
|
+
}
|
|
14904
|
+
function invalidateAllResources(store) {
|
|
14905
|
+
for (const kind of RESOURCE_KINDS) invalidateResource(store, kind);
|
|
14906
|
+
}
|
|
14907
|
+
function removeResourceEntries(store, kind, names, scope, isLeaf) {
|
|
14908
|
+
const staged = peekStaged(store, kind, scope ?? ROOT_SCOPE);
|
|
14909
|
+
if (staged) for (const name of names) delete staged[name];
|
|
14910
|
+
store.setState((state) => {
|
|
14911
|
+
const map = state[kind];
|
|
14912
|
+
if (scope) {
|
|
14913
|
+
const currentScope = { ...map[scope] };
|
|
14914
|
+
for (const name of names) delete currentScope[name];
|
|
14915
|
+
return { [kind]: { ...map, [scope]: currentScope } };
|
|
14916
|
+
}
|
|
14917
|
+
const next = { ...map };
|
|
14918
|
+
for (const name of names) if (isLeaf(next[name])) delete next[name];
|
|
14919
|
+
return { [kind]: next };
|
|
14920
|
+
});
|
|
14921
|
+
}
|
|
14922
|
+
function clearResourceEntries(store, kind, scope, isLeaf) {
|
|
14923
|
+
const registry = getKindRegistry(store, kind);
|
|
14924
|
+
if (scope && scope !== "root") registry.staged.delete(scope);
|
|
14925
|
+
else if (scope === "root") registry.staged.delete(ROOT_SCOPE);
|
|
14926
|
+
else registry.staged.clear();
|
|
14927
|
+
store.setState((state) => {
|
|
14928
|
+
const map = state[kind];
|
|
14929
|
+
if (scope && scope !== "root") {
|
|
14930
|
+
const { [scope]: _, ...rest } = map;
|
|
14931
|
+
return { [kind]: rest };
|
|
14932
|
+
}
|
|
14933
|
+
if (scope === "root") {
|
|
14934
|
+
const next = {};
|
|
14935
|
+
for (const [key, value] of Object.entries(map)) if (!isLeaf(value)) next[key] = value;
|
|
14936
|
+
return { [kind]: next };
|
|
14937
|
+
}
|
|
14938
|
+
return { [kind]: {} };
|
|
14939
|
+
});
|
|
14940
|
+
}
|
|
14941
|
+
|
|
14741
14942
|
function clearHmrCaches(store) {
|
|
14742
|
-
store.
|
|
14743
|
-
|
|
14744
|
-
|
|
14745
|
-
buffers: {},
|
|
14746
|
-
gpuStorage: {},
|
|
14747
|
-
_hmrVersion: state._hmrVersion + 1
|
|
14748
|
-
}));
|
|
14943
|
+
const primary = store.getState().primaryStore ?? store;
|
|
14944
|
+
invalidateAllResources(primary);
|
|
14945
|
+
primary.setState((state) => ({ _hmrVersion: state._hmrVersion + 1 }));
|
|
14749
14946
|
}
|
|
14750
14947
|
|
|
14751
14948
|
function CanvasImpl({
|
|
@@ -14781,18 +14978,7 @@ function CanvasImpl({
|
|
|
14781
14978
|
forceEven,
|
|
14782
14979
|
...props
|
|
14783
14980
|
}) {
|
|
14784
|
-
const
|
|
14785
|
-
let primaryCanvas;
|
|
14786
|
-
let scheduler;
|
|
14787
|
-
let renderer;
|
|
14788
|
-
if (isRendererConfig) {
|
|
14789
|
-
const { primaryCanvas: pc, scheduler: sc, ...rest } = rendererProp;
|
|
14790
|
-
primaryCanvas = pc;
|
|
14791
|
-
scheduler = sc;
|
|
14792
|
-
renderer = Object.keys(rest).length > 0 ? rest : rendererProp;
|
|
14793
|
-
} else {
|
|
14794
|
-
renderer = rendererProp;
|
|
14795
|
-
}
|
|
14981
|
+
const { primaryCanvas, scheduler, renderer } = parseRendererConfig(rendererProp);
|
|
14796
14982
|
React__namespace.useMemo(() => extend(THREE), []);
|
|
14797
14983
|
const Bridge = useBridge();
|
|
14798
14984
|
const backgroundProps = React__namespace.useMemo(() => parseBackground(background), [background]);
|
|
@@ -14837,6 +15023,7 @@ function CanvasImpl({
|
|
|
14837
15023
|
const handleDropMissed = useMutableCallback(onDropMissed);
|
|
14838
15024
|
const [block, setBlock] = React__namespace.useState(false);
|
|
14839
15025
|
const [error, setError] = React__namespace.useState(false);
|
|
15026
|
+
const [fallbackVisible, setFallbackVisible] = React__namespace.useState(false);
|
|
14840
15027
|
if (block) throw block;
|
|
14841
15028
|
if (error) throw error;
|
|
14842
15029
|
const root = React__namespace.useRef(null);
|
|
@@ -14844,6 +15031,7 @@ function CanvasImpl({
|
|
|
14844
15031
|
const unsubscribeErrorRef = React__namespace.useRef(null);
|
|
14845
15032
|
useIsomorphicLayoutEffect(() => {
|
|
14846
15033
|
effectActiveRef.current = true;
|
|
15034
|
+
if (fallbackVisible) return;
|
|
14847
15035
|
const canvas = canvasRef.current;
|
|
14848
15036
|
if (effectiveSize.width > 0 && effectiveSize.height > 0 && canvas) {
|
|
14849
15037
|
if (!root.current) {
|
|
@@ -14864,7 +15052,7 @@ function CanvasImpl({
|
|
|
14864
15052
|
}
|
|
14865
15053
|
async function run() {
|
|
14866
15054
|
if (!effectActiveRef.current || !root.current) return;
|
|
14867
|
-
await root.current.configure({
|
|
15055
|
+
const configured = await root.current.configure({
|
|
14868
15056
|
id,
|
|
14869
15057
|
primaryCanvas,
|
|
14870
15058
|
scheduler,
|
|
@@ -14905,8 +15093,20 @@ function CanvasImpl({
|
|
|
14905
15093
|
}
|
|
14906
15094
|
onCreated?.(state);
|
|
14907
15095
|
}
|
|
14908
|
-
})
|
|
14909
|
-
|
|
15096
|
+
}).then(
|
|
15097
|
+
() => true,
|
|
15098
|
+
// Renderer setup failed (e.g. no WebGL/WebGPU support). The `fallback` prop lives
|
|
15099
|
+
// inside <canvas>, which browsers don't display, so surface it as visible DOM
|
|
15100
|
+
// instead; with no fallback, rethrow to an external error boundary. (#3757)
|
|
15101
|
+
(setupError) => {
|
|
15102
|
+
if (effectActiveRef.current) {
|
|
15103
|
+
if (fallback != null) setFallbackVisible(true);
|
|
15104
|
+
else setError(setupError);
|
|
15105
|
+
}
|
|
15106
|
+
return false;
|
|
15107
|
+
}
|
|
15108
|
+
);
|
|
15109
|
+
if (!configured || !effectActiveRef.current || !root.current) return;
|
|
14910
15110
|
root.current.render(
|
|
14911
15111
|
/* @__PURE__ */ jsxRuntime.jsx(Bridge, { children: /* @__PURE__ */ jsxRuntime.jsx(ErrorBoundary, { set: setError, children: /* @__PURE__ */ jsxRuntime.jsxs(React__namespace.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(Block, { set: setBlock }), children: [
|
|
14912
15112
|
backgroundProps && /* @__PURE__ */ jsxRuntime.jsx(Environment, { ...backgroundProps }),
|
|
@@ -14969,7 +15169,11 @@ function CanvasImpl({
|
|
|
14969
15169
|
...style
|
|
14970
15170
|
},
|
|
14971
15171
|
...props,
|
|
14972
|
-
children:
|
|
15172
|
+
children: fallbackVisible ? (
|
|
15173
|
+
// Renderer setup failed: render the fallback as visible DOM. Inside <canvas> (below)
|
|
15174
|
+
// it exists in the tree but browsers never paint it, which is the whole bug (#3757).
|
|
15175
|
+
fallback
|
|
15176
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, className: "r3f-canvas-container", style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
14973
15177
|
"canvas",
|
|
14974
15178
|
{
|
|
14975
15179
|
ref: canvasRef,
|
|
@@ -15051,30 +15255,31 @@ let ScopedStore = _ScopedStore;
|
|
|
15051
15255
|
function createScopedStore(data) {
|
|
15052
15256
|
return new ScopedStore(data);
|
|
15053
15257
|
}
|
|
15054
|
-
function createLazyCreatorState(state) {
|
|
15258
|
+
function createLazyCreatorState(state, store) {
|
|
15055
15259
|
let _uniforms = null;
|
|
15056
15260
|
let _nodes = null;
|
|
15057
15261
|
let _buffers = null;
|
|
15058
15262
|
let _gpuStorage = null;
|
|
15263
|
+
const view = (kind) => store ? withStagedOverlay(store, kind, state[kind]) : state[kind];
|
|
15059
15264
|
return Object.create(state, {
|
|
15060
15265
|
uniforms: {
|
|
15061
15266
|
get() {
|
|
15062
|
-
return _uniforms ?? (_uniforms = createScopedStore(
|
|
15267
|
+
return _uniforms ?? (_uniforms = createScopedStore(view("uniforms")));
|
|
15063
15268
|
}
|
|
15064
15269
|
},
|
|
15065
15270
|
nodes: {
|
|
15066
15271
|
get() {
|
|
15067
|
-
return _nodes ?? (_nodes = createScopedStore(
|
|
15272
|
+
return _nodes ?? (_nodes = createScopedStore(view("nodes")));
|
|
15068
15273
|
}
|
|
15069
15274
|
},
|
|
15070
15275
|
buffers: {
|
|
15071
15276
|
get() {
|
|
15072
|
-
return _buffers ?? (_buffers = createScopedStore(
|
|
15277
|
+
return _buffers ?? (_buffers = createScopedStore(view("buffers")));
|
|
15073
15278
|
}
|
|
15074
15279
|
},
|
|
15075
15280
|
gpuStorage: {
|
|
15076
15281
|
get() {
|
|
15077
|
-
return _gpuStorage ?? (_gpuStorage = createScopedStore(
|
|
15282
|
+
return _gpuStorage ?? (_gpuStorage = createScopedStore(view("gpuStorage")));
|
|
15078
15283
|
}
|
|
15079
15284
|
}
|
|
15080
15285
|
});
|
|
@@ -15197,65 +15402,56 @@ function useCompareMemoize(value, deep) {
|
|
|
15197
15402
|
return ref.current;
|
|
15198
15403
|
}
|
|
15199
15404
|
|
|
15405
|
+
function useScopedResource(options) {
|
|
15406
|
+
const { store, kind, scope, isLeaf, create, prepare, reconcile, input } = options;
|
|
15407
|
+
const scopeKey = scope ?? ROOT_SCOPE;
|
|
15408
|
+
const version = store((s) => s._hmrVersion);
|
|
15409
|
+
const entries = React.useMemo(() => {
|
|
15410
|
+
const staged = peekStaged(store, kind, scopeKey);
|
|
15411
|
+
const reusable = isScopeValid(store, kind, scopeKey);
|
|
15412
|
+
const map = store.getState()[kind];
|
|
15413
|
+
const committed = reusable ? readCommittedScope(map, scopeKey, isLeaf) : void 0;
|
|
15414
|
+
const result = {};
|
|
15415
|
+
let fresh = null;
|
|
15416
|
+
for (const [name, candidate] of Object.entries(create())) {
|
|
15417
|
+
const existing = staged?.[name] ?? committed?.[name];
|
|
15418
|
+
if (existing !== void 0) {
|
|
15419
|
+
result[name] = existing;
|
|
15420
|
+
reconcile?.(existing, candidate);
|
|
15421
|
+
} else {
|
|
15422
|
+
const value = prepare ? prepare(name, candidate) : candidate;
|
|
15423
|
+
result[name] = value;
|
|
15424
|
+
(fresh ?? (fresh = {}))[name] = value;
|
|
15425
|
+
}
|
|
15426
|
+
}
|
|
15427
|
+
if (fresh) stageEntries(store, kind, scopeKey, fresh);
|
|
15428
|
+
return result;
|
|
15429
|
+
}, [store, kind, scopeKey, version, input]);
|
|
15430
|
+
useIsomorphicLayoutEffect(() => {
|
|
15431
|
+
flushStagedScope(store, kind, scopeKey, isLeaf);
|
|
15432
|
+
});
|
|
15433
|
+
return entries;
|
|
15434
|
+
}
|
|
15435
|
+
|
|
15200
15436
|
const isUniformNode$1 = (value) => value !== null && typeof value === "object" && "value" in value && "uuid" in value;
|
|
15201
15437
|
function useUniforms(creatorOrScope, scope) {
|
|
15202
15438
|
const store = usePrimaryStore();
|
|
15203
15439
|
const removeUniforms2 = React.useCallback(
|
|
15204
|
-
(names, targetScope) =>
|
|
15205
|
-
const nameArray = Array.isArray(names) ? names : [names];
|
|
15206
|
-
store.setState((state) => {
|
|
15207
|
-
if (targetScope) {
|
|
15208
|
-
const currentScope = { ...state.uniforms[targetScope] };
|
|
15209
|
-
for (const name of nameArray) delete currentScope[name];
|
|
15210
|
-
return { uniforms: { ...state.uniforms, [targetScope]: currentScope } };
|
|
15211
|
-
}
|
|
15212
|
-
const uniforms2 = { ...state.uniforms };
|
|
15213
|
-
for (const name of nameArray) if (isUniformNode$1(uniforms2[name])) delete uniforms2[name];
|
|
15214
|
-
return { uniforms: uniforms2 };
|
|
15215
|
-
});
|
|
15216
|
-
},
|
|
15440
|
+
(names, targetScope) => removeResourceEntries(store, "uniforms", Array.isArray(names) ? names : [names], targetScope, isUniformNode$1),
|
|
15217
15441
|
[store]
|
|
15218
15442
|
);
|
|
15219
15443
|
const clearUniforms = React.useCallback(
|
|
15220
|
-
(targetScope) =>
|
|
15221
|
-
store.setState((state) => {
|
|
15222
|
-
if (targetScope && targetScope !== "root") {
|
|
15223
|
-
const { [targetScope]: _, ...rest } = state.uniforms;
|
|
15224
|
-
return { uniforms: rest };
|
|
15225
|
-
}
|
|
15226
|
-
if (targetScope === "root") {
|
|
15227
|
-
const uniforms2 = {};
|
|
15228
|
-
for (const [key, value] of Object.entries(state.uniforms)) {
|
|
15229
|
-
if (!isUniformNode$1(value)) uniforms2[key] = value;
|
|
15230
|
-
}
|
|
15231
|
-
return { uniforms: uniforms2 };
|
|
15232
|
-
}
|
|
15233
|
-
return { uniforms: {} };
|
|
15234
|
-
});
|
|
15235
|
-
},
|
|
15444
|
+
(targetScope) => clearResourceEntries(store, "uniforms", targetScope, isUniformNode$1),
|
|
15236
15445
|
[store]
|
|
15237
15446
|
);
|
|
15238
15447
|
const rebuildUniforms = React.useCallback(
|
|
15239
|
-
(targetScope) =>
|
|
15240
|
-
store.setState((state) => {
|
|
15241
|
-
let newUniforms = {};
|
|
15242
|
-
if (targetScope && targetScope !== "root") {
|
|
15243
|
-
const { [targetScope]: _, ...rest } = state.uniforms;
|
|
15244
|
-
newUniforms = rest;
|
|
15245
|
-
} else if (targetScope === "root") {
|
|
15246
|
-
for (const [key, value] of Object.entries(state.uniforms)) {
|
|
15247
|
-
if (!isUniformNode$1(value)) newUniforms[key] = value;
|
|
15248
|
-
}
|
|
15249
|
-
}
|
|
15250
|
-
return { uniforms: newUniforms, _hmrVersion: state._hmrVersion + 1 };
|
|
15251
|
-
});
|
|
15252
|
-
},
|
|
15448
|
+
(targetScope) => rebuildResource(store, "uniforms", targetScope),
|
|
15253
15449
|
[store]
|
|
15254
15450
|
);
|
|
15255
15451
|
const inputForMemoization = React.useMemo(() => {
|
|
15256
15452
|
let raw = creatorOrScope;
|
|
15257
15453
|
if (is.fun(creatorOrScope)) {
|
|
15258
|
-
const wrappedState = createLazyCreatorState(store.getState());
|
|
15454
|
+
const wrappedState = createLazyCreatorState(store.getState(), store);
|
|
15259
15455
|
raw = creatorOrScope(wrappedState);
|
|
15260
15456
|
}
|
|
15261
15457
|
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
|
|
@@ -15270,80 +15466,43 @@ function useUniforms(creatorOrScope, scope) {
|
|
|
15270
15466
|
const memoizedInput = useCompareMemoize(inputForMemoization);
|
|
15271
15467
|
const isReader = memoizedInput === void 0 || typeof memoizedInput === "string";
|
|
15272
15468
|
const storeUniforms = usePrimaryThree((s) => s.uniforms);
|
|
15273
|
-
const
|
|
15274
|
-
|
|
15275
|
-
|
|
15276
|
-
|
|
15277
|
-
|
|
15278
|
-
|
|
15279
|
-
|
|
15280
|
-
|
|
15281
|
-
|
|
15282
|
-
|
|
15283
|
-
|
|
15284
|
-
|
|
15285
|
-
|
|
15286
|
-
|
|
15287
|
-
|
|
15288
|
-
|
|
15289
|
-
|
|
15290
|
-
|
|
15291
|
-
|
|
15292
|
-
|
|
15293
|
-
|
|
15294
|
-
|
|
15295
|
-
if (!state.uniforms[scope]) state.uniforms[scope] = {};
|
|
15296
|
-
targetRecord = state.uniforms[scope];
|
|
15297
|
-
}
|
|
15298
|
-
for (const [name, node] of Object.entries(created)) {
|
|
15299
|
-
if (targetRecord[name]) {
|
|
15300
|
-
result[name] = targetRecord[name];
|
|
15301
|
-
const existingVal = result[name].value;
|
|
15302
|
-
const newVal = vectorize(node);
|
|
15303
|
-
let equals = newVal === existingVal;
|
|
15304
|
-
if (!equals && hasEqualsMethod(existingVal) && hasEqualsMethod(newVal)) {
|
|
15305
|
-
if (isThreeVector(existingVal) && isThreeVector(newVal)) {
|
|
15306
|
-
equals = vectorEquals(existingVal, newVal);
|
|
15307
|
-
} else if (isSameThreeType(existingVal, newVal)) {
|
|
15308
|
-
equals = existingVal.equals(newVal);
|
|
15309
|
-
}
|
|
15310
|
-
}
|
|
15311
|
-
if (!equals) result[name].value = newVal;
|
|
15312
|
-
} else {
|
|
15313
|
-
result[name] = createUniform(name, node, scope);
|
|
15314
|
-
hasNewUniforms = true;
|
|
15315
|
-
}
|
|
15316
|
-
}
|
|
15317
|
-
if (hasNewUniforms) {
|
|
15318
|
-
if (scope) {
|
|
15319
|
-
set((s) => ({
|
|
15320
|
-
uniforms: {
|
|
15321
|
-
...s.uniforms,
|
|
15322
|
-
[scope]: { ...s.uniforms[scope], ...result }
|
|
15323
|
-
}
|
|
15324
|
-
}));
|
|
15325
|
-
} else {
|
|
15326
|
-
set((s) => ({ uniforms: { ...s.uniforms, ...result } }));
|
|
15469
|
+
const created = useScopedResource({
|
|
15470
|
+
store,
|
|
15471
|
+
kind: "uniforms",
|
|
15472
|
+
scope: isReader ? void 0 : scope,
|
|
15473
|
+
isLeaf: isUniformNode$1,
|
|
15474
|
+
input: memoizedInput,
|
|
15475
|
+
create: () => {
|
|
15476
|
+
if (isReader) return {};
|
|
15477
|
+
if (typeof memoizedInput !== "object" || memoizedInput === null) throw new Error("Invalid uniform input");
|
|
15478
|
+
return memoizedInput;
|
|
15479
|
+
},
|
|
15480
|
+
prepare: (name, candidate) => createUniform(name, candidate, scope),
|
|
15481
|
+
reconcile: (existing, candidate) => {
|
|
15482
|
+
const existingVal = existing.value;
|
|
15483
|
+
const newVal = vectorize(candidate);
|
|
15484
|
+
let equals = newVal === existingVal;
|
|
15485
|
+
if (!equals && hasEqualsMethod(existingVal) && hasEqualsMethod(newVal)) {
|
|
15486
|
+
if (isThreeVector(existingVal) && isThreeVector(newVal)) {
|
|
15487
|
+
equals = vectorEquals(existingVal, newVal);
|
|
15488
|
+
} else if (isSameThreeType(existingVal, newVal)) {
|
|
15489
|
+
equals = existingVal.equals(newVal);
|
|
15490
|
+
}
|
|
15327
15491
|
}
|
|
15492
|
+
if (!equals) existing.value = newVal;
|
|
15328
15493
|
}
|
|
15329
|
-
|
|
15330
|
-
|
|
15494
|
+
});
|
|
15495
|
+
let uniforms = created;
|
|
15496
|
+
if (memoizedInput === void 0) {
|
|
15497
|
+
uniforms = storeUniforms;
|
|
15498
|
+
} else if (typeof memoizedInput === "string") {
|
|
15499
|
+
const scopeData = storeUniforms[memoizedInput];
|
|
15500
|
+
uniforms = scopeData && !isUniformNode$1(scopeData) ? scopeData : {};
|
|
15501
|
+
}
|
|
15331
15502
|
return { ...uniforms, removeUniforms: removeUniforms2, clearUniforms, rebuildUniforms };
|
|
15332
15503
|
}
|
|
15333
15504
|
function rebuildAllUniforms(store, scope) {
|
|
15334
|
-
store
|
|
15335
|
-
store.setState((state) => {
|
|
15336
|
-
let newUniforms = {};
|
|
15337
|
-
if (scope && scope !== "root") {
|
|
15338
|
-
const { [scope]: _, ...rest } = state.uniforms;
|
|
15339
|
-
newUniforms = rest;
|
|
15340
|
-
} else if (scope === "root") {
|
|
15341
|
-
for (const [key, value] of Object.entries(state.uniforms)) {
|
|
15342
|
-
if (!isUniformNode$1(value)) newUniforms[key] = value;
|
|
15343
|
-
}
|
|
15344
|
-
}
|
|
15345
|
-
return { uniforms: newUniforms, _hmrVersion: state._hmrVersion + 1 };
|
|
15346
|
-
});
|
|
15505
|
+
rebuildResource(store, "uniforms", scope);
|
|
15347
15506
|
}
|
|
15348
15507
|
function removeUniforms(set, names, scope) {
|
|
15349
15508
|
set((state) => {
|
|
@@ -15407,192 +15566,91 @@ function isSameThreeType(a, b) {
|
|
|
15407
15566
|
return obj_a.isColor && obj_b.isColor || obj_a.isMatrix3 && obj_b.isMatrix3 || obj_a.isMatrix4 && obj_b.isMatrix4 || obj_a.isEuler && obj_b.isEuler || obj_a.isQuaternion && obj_b.isQuaternion;
|
|
15408
15567
|
}
|
|
15409
15568
|
|
|
15569
|
+
const uniformOf = tsl.uniform;
|
|
15410
15570
|
const isUniformNode = (value) => value !== null && typeof value === "object" && "value" in value && "uuid" in value;
|
|
15411
15571
|
const isTSLNode$1 = (value) => value !== null && typeof value === "object" && "uuid" in value && "nodeType" in value;
|
|
15412
15572
|
function useUniform(name, value) {
|
|
15413
15573
|
const store = useStore();
|
|
15414
|
-
const
|
|
15415
|
-
|
|
15416
|
-
|
|
15417
|
-
|
|
15418
|
-
|
|
15419
|
-
|
|
15574
|
+
const registered = useScopedResource({
|
|
15575
|
+
store,
|
|
15576
|
+
kind: "uniforms",
|
|
15577
|
+
scope: void 0,
|
|
15578
|
+
isLeaf: isUniformNode,
|
|
15579
|
+
input: name,
|
|
15580
|
+
create: () => value === void 0 ? {} : { [name]: value },
|
|
15581
|
+
prepare: createNamedUniform,
|
|
15582
|
+
reconcile: (existing2) => {
|
|
15420
15583
|
if (value !== void 0 && !isTSLNode$1(value) && !isUniformNode(value)) {
|
|
15421
|
-
|
|
15584
|
+
existing2.value = typeof value === "string" ? new webgpu.Color(value) : value;
|
|
15422
15585
|
}
|
|
15423
|
-
return existing;
|
|
15424
|
-
}
|
|
15425
|
-
if (value === void 0) {
|
|
15426
|
-
throw new Error(
|
|
15427
|
-
`[useUniform] Uniform "${name}" not found. Create it first with: useUniform('${name}', initialValue)`
|
|
15428
|
-
);
|
|
15429
|
-
}
|
|
15430
|
-
if (isUniformNode(value)) {
|
|
15431
|
-
const node2 = value;
|
|
15432
|
-
if (typeof node2.setName === "function") {
|
|
15433
|
-
node2.setName(name);
|
|
15434
|
-
}
|
|
15435
|
-
set((s) => ({
|
|
15436
|
-
uniforms: { ...s.uniforms, [name]: node2 }
|
|
15437
|
-
}));
|
|
15438
|
-
return node2;
|
|
15439
15586
|
}
|
|
15440
|
-
|
|
15441
|
-
|
|
15442
|
-
|
|
15443
|
-
|
|
15444
|
-
|
|
15445
|
-
}
|
|
15446
|
-
|
|
15447
|
-
|
|
15448
|
-
|
|
15449
|
-
|
|
15450
|
-
|
|
15451
|
-
|
|
15452
|
-
|
|
15453
|
-
|
|
15454
|
-
|
|
15455
|
-
|
|
15456
|
-
|
|
15457
|
-
|
|
15458
|
-
}
|
|
15587
|
+
});
|
|
15588
|
+
if (registered[name]) return registered[name];
|
|
15589
|
+
const existing = peekStaged(store, "uniforms", ROOT_SCOPE)?.[name] ?? store.getState().uniforms[name];
|
|
15590
|
+
if (existing && isUniformNode(existing)) return existing;
|
|
15591
|
+
throw new Error(
|
|
15592
|
+
`[useUniform] Uniform "${name}" not found. Create it first with: useUniform('${name}', initialValue)`
|
|
15593
|
+
);
|
|
15594
|
+
}
|
|
15595
|
+
function createNamedUniform(name, value) {
|
|
15596
|
+
let node;
|
|
15597
|
+
if (isUniformNode(value)) {
|
|
15598
|
+
node = value;
|
|
15599
|
+
} else if (isTSLNode$1(value)) {
|
|
15600
|
+
node = uniformOf(value);
|
|
15601
|
+
} else if (typeof value === "string") {
|
|
15602
|
+
node = tsl.uniform(new webgpu.Color(value));
|
|
15603
|
+
} else {
|
|
15604
|
+
node = uniformOf(value);
|
|
15605
|
+
}
|
|
15606
|
+
if (typeof node.setName === "function") {
|
|
15607
|
+
node.setName(name);
|
|
15608
|
+
}
|
|
15609
|
+
return node;
|
|
15459
15610
|
}
|
|
15460
15611
|
|
|
15461
15612
|
const isTSLNode = (value) => value !== null && typeof value === "object" && ("uuid" in value || "nodeType" in value);
|
|
15462
15613
|
function useNodes(creatorOrScope, scope) {
|
|
15463
15614
|
const store = usePrimaryStore();
|
|
15464
15615
|
const removeNodes2 = React.useCallback(
|
|
15465
|
-
(names, targetScope) =>
|
|
15466
|
-
const nameArray = Array.isArray(names) ? names : [names];
|
|
15467
|
-
store.setState((state) => {
|
|
15468
|
-
if (targetScope) {
|
|
15469
|
-
const currentScope = { ...state.nodes[targetScope] };
|
|
15470
|
-
for (const name of nameArray) delete currentScope[name];
|
|
15471
|
-
return { nodes: { ...state.nodes, [targetScope]: currentScope } };
|
|
15472
|
-
}
|
|
15473
|
-
const nodes2 = { ...state.nodes };
|
|
15474
|
-
for (const name of nameArray) if (isTSLNode(nodes2[name])) delete nodes2[name];
|
|
15475
|
-
return { nodes: nodes2 };
|
|
15476
|
-
});
|
|
15477
|
-
},
|
|
15616
|
+
(names, targetScope) => removeResourceEntries(store, "nodes", Array.isArray(names) ? names : [names], targetScope, isTSLNode),
|
|
15478
15617
|
[store]
|
|
15479
15618
|
);
|
|
15480
15619
|
const clearNodes = React.useCallback(
|
|
15481
|
-
(targetScope) =>
|
|
15482
|
-
store.setState((state) => {
|
|
15483
|
-
if (targetScope && targetScope !== "root") {
|
|
15484
|
-
const { [targetScope]: _, ...rest } = state.nodes;
|
|
15485
|
-
return { nodes: rest };
|
|
15486
|
-
}
|
|
15487
|
-
if (targetScope === "root") {
|
|
15488
|
-
const nodes2 = {};
|
|
15489
|
-
for (const [key, value] of Object.entries(state.nodes)) {
|
|
15490
|
-
if (!isTSLNode(value)) nodes2[key] = value;
|
|
15491
|
-
}
|
|
15492
|
-
return { nodes: nodes2 };
|
|
15493
|
-
}
|
|
15494
|
-
return { nodes: {} };
|
|
15495
|
-
});
|
|
15496
|
-
},
|
|
15620
|
+
(targetScope) => clearResourceEntries(store, "nodes", targetScope, isTSLNode),
|
|
15497
15621
|
[store]
|
|
15498
15622
|
);
|
|
15499
15623
|
const rebuildNodes = React.useCallback(
|
|
15500
|
-
(targetScope) =>
|
|
15501
|
-
store.setState((state) => {
|
|
15502
|
-
let newNodes = state.nodes;
|
|
15503
|
-
if (targetScope && targetScope !== "root") {
|
|
15504
|
-
const { [targetScope]: _, ...rest } = state.nodes;
|
|
15505
|
-
newNodes = rest;
|
|
15506
|
-
} else if (targetScope === "root") {
|
|
15507
|
-
newNodes = {};
|
|
15508
|
-
for (const [key, value] of Object.entries(state.nodes)) {
|
|
15509
|
-
if (!isTSLNode(value)) newNodes[key] = value;
|
|
15510
|
-
}
|
|
15511
|
-
} else {
|
|
15512
|
-
newNodes = {};
|
|
15513
|
-
}
|
|
15514
|
-
return { nodes: newNodes, _hmrVersion: state._hmrVersion + 1 };
|
|
15515
|
-
});
|
|
15516
|
-
},
|
|
15624
|
+
(targetScope) => rebuildResource(store, "nodes", targetScope),
|
|
15517
15625
|
[store]
|
|
15518
15626
|
);
|
|
15519
15627
|
const isReader = creatorOrScope === void 0 || typeof creatorOrScope === "string";
|
|
15520
15628
|
const storeNodes = usePrimaryThree((s) => s.nodes);
|
|
15521
|
-
const
|
|
15522
|
-
|
|
15523
|
-
|
|
15524
|
-
|
|
15525
|
-
|
|
15526
|
-
|
|
15527
|
-
return
|
|
15528
|
-
|
|
15529
|
-
|
|
15530
|
-
|
|
15531
|
-
|
|
15532
|
-
return
|
|
15533
|
-
}
|
|
15534
|
-
const state = store.getState();
|
|
15535
|
-
const set = store.setState;
|
|
15536
|
-
const creator = creatorOrScope;
|
|
15537
|
-
const wrappedState = createLazyCreatorState(state);
|
|
15538
|
-
const created = creator(wrappedState);
|
|
15539
|
-
const result = {};
|
|
15540
|
-
let hasNewNodes = false;
|
|
15541
|
-
if (scope) {
|
|
15542
|
-
const currentScope = state.nodes[scope] ?? {};
|
|
15543
|
-
for (const [name, node] of Object.entries(created)) {
|
|
15544
|
-
if (currentScope[name]) {
|
|
15545
|
-
result[name] = currentScope[name];
|
|
15546
|
-
} else {
|
|
15547
|
-
node.setName?.(`${scope}.${name}`);
|
|
15548
|
-
result[name] = node;
|
|
15549
|
-
hasNewNodes = true;
|
|
15550
|
-
}
|
|
15551
|
-
}
|
|
15552
|
-
if (hasNewNodes) {
|
|
15553
|
-
set((s) => ({
|
|
15554
|
-
nodes: {
|
|
15555
|
-
...s.nodes,
|
|
15556
|
-
[scope]: { ...s.nodes[scope], ...result }
|
|
15557
|
-
}
|
|
15558
|
-
}));
|
|
15559
|
-
}
|
|
15560
|
-
return result;
|
|
15561
|
-
}
|
|
15562
|
-
for (const [name, node] of Object.entries(created)) {
|
|
15563
|
-
const existing = state.nodes[name];
|
|
15564
|
-
if (existing && isTSLNode(existing)) {
|
|
15565
|
-
result[name] = existing;
|
|
15566
|
-
} else {
|
|
15567
|
-
node.setName?.(name);
|
|
15568
|
-
result[name] = node;
|
|
15569
|
-
hasNewNodes = true;
|
|
15570
|
-
}
|
|
15571
|
-
}
|
|
15572
|
-
if (hasNewNodes) {
|
|
15573
|
-
set((s) => ({ nodes: { ...s.nodes, ...result } }));
|
|
15629
|
+
const created = useScopedResource({
|
|
15630
|
+
store,
|
|
15631
|
+
kind: "nodes",
|
|
15632
|
+
scope: isReader ? void 0 : scope,
|
|
15633
|
+
isLeaf: isTSLNode,
|
|
15634
|
+
create: () => {
|
|
15635
|
+
if (isReader) return {};
|
|
15636
|
+
return creatorOrScope(createLazyCreatorState(store.getState(), store));
|
|
15637
|
+
},
|
|
15638
|
+
prepare: (name, node) => {
|
|
15639
|
+
node.setName?.(scope ? `${scope}.${name}` : name);
|
|
15640
|
+
return node;
|
|
15574
15641
|
}
|
|
15575
|
-
|
|
15576
|
-
|
|
15642
|
+
});
|
|
15643
|
+
let nodes = created;
|
|
15644
|
+
if (creatorOrScope === void 0) {
|
|
15645
|
+
nodes = storeNodes;
|
|
15646
|
+
} else if (typeof creatorOrScope === "string") {
|
|
15647
|
+
const scopeData = storeNodes[creatorOrScope];
|
|
15648
|
+
nodes = scopeData && !isTSLNode(scopeData) ? scopeData : {};
|
|
15649
|
+
}
|
|
15577
15650
|
return { ...nodes, removeNodes: removeNodes2, clearNodes, rebuildNodes };
|
|
15578
15651
|
}
|
|
15579
15652
|
function rebuildAllNodes(store, scope) {
|
|
15580
|
-
store
|
|
15581
|
-
store.setState((state) => {
|
|
15582
|
-
let newNodes = state.nodes;
|
|
15583
|
-
if (scope && scope !== "root") {
|
|
15584
|
-
const { [scope]: _, ...rest } = state.nodes;
|
|
15585
|
-
newNodes = rest;
|
|
15586
|
-
} else if (scope === "root") {
|
|
15587
|
-
newNodes = {};
|
|
15588
|
-
for (const [key, value] of Object.entries(state.nodes)) {
|
|
15589
|
-
if (!isTSLNode(value)) newNodes[key] = value;
|
|
15590
|
-
}
|
|
15591
|
-
} else {
|
|
15592
|
-
newNodes = {};
|
|
15593
|
-
}
|
|
15594
|
-
return { nodes: newNodes, _hmrVersion: state._hmrVersion + 1 };
|
|
15595
|
-
});
|
|
15653
|
+
rebuildResource(store, "nodes", scope);
|
|
15596
15654
|
}
|
|
15597
15655
|
function removeNodes(set, names, scope) {
|
|
15598
15656
|
set((state) => {
|
|
@@ -15628,7 +15686,7 @@ function useLocalNodes(creator) {
|
|
|
15628
15686
|
const textures = usePrimaryThree((s) => s.textures);
|
|
15629
15687
|
const hmrVersion = usePrimaryThree((s) => s._hmrVersion);
|
|
15630
15688
|
return React.useMemo(() => {
|
|
15631
|
-
const wrappedState = createLazyCreatorState(store.getState());
|
|
15689
|
+
const wrappedState = createLazyCreatorState(store.getState(), store);
|
|
15632
15690
|
return creator(wrappedState);
|
|
15633
15691
|
}, [store, creator, uniforms, nodes, textures, hmrVersion]);
|
|
15634
15692
|
}
|
|
@@ -15649,58 +15707,15 @@ const disposeBuffer = (buffer) => {
|
|
|
15649
15707
|
function useBuffers(creatorOrScope, scope) {
|
|
15650
15708
|
const store = usePrimaryStore();
|
|
15651
15709
|
const removeBuffers = React.useCallback(
|
|
15652
|
-
(names, targetScope) =>
|
|
15653
|
-
const nameArray = Array.isArray(names) ? names : [names];
|
|
15654
|
-
store.setState((state) => {
|
|
15655
|
-
if (targetScope) {
|
|
15656
|
-
const currentScope = { ...state.buffers[targetScope] };
|
|
15657
|
-
for (const name of nameArray) delete currentScope[name];
|
|
15658
|
-
return { buffers: { ...state.buffers, [targetScope]: currentScope } };
|
|
15659
|
-
}
|
|
15660
|
-
const buffers2 = { ...state.buffers };
|
|
15661
|
-
for (const name of nameArray) if (isBufferLike(buffers2[name])) delete buffers2[name];
|
|
15662
|
-
return { buffers: buffers2 };
|
|
15663
|
-
});
|
|
15664
|
-
},
|
|
15710
|
+
(names, targetScope) => removeResourceEntries(store, "buffers", Array.isArray(names) ? names : [names], targetScope, isBufferLike),
|
|
15665
15711
|
[store]
|
|
15666
15712
|
);
|
|
15667
15713
|
const clearBuffers = React.useCallback(
|
|
15668
|
-
(targetScope) =>
|
|
15669
|
-
store.setState((state) => {
|
|
15670
|
-
if (targetScope && targetScope !== "root") {
|
|
15671
|
-
const { [targetScope]: _, ...rest } = state.buffers;
|
|
15672
|
-
return { buffers: rest };
|
|
15673
|
-
}
|
|
15674
|
-
if (targetScope === "root") {
|
|
15675
|
-
const buffers2 = {};
|
|
15676
|
-
for (const [key, value] of Object.entries(state.buffers)) {
|
|
15677
|
-
if (!isBufferLike(value)) buffers2[key] = value;
|
|
15678
|
-
}
|
|
15679
|
-
return { buffers: buffers2 };
|
|
15680
|
-
}
|
|
15681
|
-
return { buffers: {} };
|
|
15682
|
-
});
|
|
15683
|
-
},
|
|
15714
|
+
(targetScope) => clearResourceEntries(store, "buffers", targetScope, isBufferLike),
|
|
15684
15715
|
[store]
|
|
15685
15716
|
);
|
|
15686
15717
|
const rebuildBuffers = React.useCallback(
|
|
15687
|
-
(targetScope) =>
|
|
15688
|
-
store.setState((state) => {
|
|
15689
|
-
let newBuffers = state.buffers;
|
|
15690
|
-
if (targetScope && targetScope !== "root") {
|
|
15691
|
-
const { [targetScope]: _, ...rest } = state.buffers;
|
|
15692
|
-
newBuffers = rest;
|
|
15693
|
-
} else if (targetScope === "root") {
|
|
15694
|
-
newBuffers = {};
|
|
15695
|
-
for (const [key, value] of Object.entries(state.buffers)) {
|
|
15696
|
-
if (!isBufferLike(value)) newBuffers[key] = value;
|
|
15697
|
-
}
|
|
15698
|
-
} else {
|
|
15699
|
-
newBuffers = {};
|
|
15700
|
-
}
|
|
15701
|
-
return { buffers: newBuffers, _hmrVersion: state._hmrVersion + 1 };
|
|
15702
|
-
});
|
|
15703
|
-
},
|
|
15718
|
+
(targetScope) => rebuildResource(store, "buffers", targetScope),
|
|
15704
15719
|
[store]
|
|
15705
15720
|
);
|
|
15706
15721
|
const disposeBuffers = React.useCallback(
|
|
@@ -15719,85 +15734,33 @@ function useBuffers(creatorOrScope, scope) {
|
|
|
15719
15734
|
);
|
|
15720
15735
|
const isReader = creatorOrScope === void 0 || typeof creatorOrScope === "string";
|
|
15721
15736
|
const storeBuffers = usePrimaryThree((s) => s.buffers);
|
|
15722
|
-
const
|
|
15723
|
-
|
|
15724
|
-
|
|
15725
|
-
|
|
15726
|
-
|
|
15727
|
-
|
|
15728
|
-
return
|
|
15729
|
-
|
|
15730
|
-
|
|
15731
|
-
|
|
15732
|
-
if (
|
|
15733
|
-
|
|
15734
|
-
}
|
|
15735
|
-
const state = store.getState();
|
|
15736
|
-
const set = store.setState;
|
|
15737
|
-
const creator = creatorOrScope;
|
|
15738
|
-
const wrappedState = createLazyCreatorState(state);
|
|
15739
|
-
const created = creator(wrappedState);
|
|
15740
|
-
const result = {};
|
|
15741
|
-
let hasNewBuffers = false;
|
|
15742
|
-
if (scope) {
|
|
15743
|
-
const currentScope = state.buffers[scope] ?? {};
|
|
15744
|
-
for (const [name, buffer] of Object.entries(created)) {
|
|
15745
|
-
if (currentScope[name]) {
|
|
15746
|
-
result[name] = currentScope[name];
|
|
15747
|
-
} else {
|
|
15748
|
-
if ("setName" in buffer && typeof buffer.setName === "function") {
|
|
15749
|
-
buffer.setName(`${scope}.${name}`);
|
|
15750
|
-
}
|
|
15751
|
-
result[name] = buffer;
|
|
15752
|
-
hasNewBuffers = true;
|
|
15753
|
-
}
|
|
15754
|
-
}
|
|
15755
|
-
if (hasNewBuffers) {
|
|
15756
|
-
set((s) => ({
|
|
15757
|
-
buffers: {
|
|
15758
|
-
...s.buffers,
|
|
15759
|
-
[scope]: { ...s.buffers[scope], ...result }
|
|
15760
|
-
}
|
|
15761
|
-
}));
|
|
15762
|
-
}
|
|
15763
|
-
return result;
|
|
15764
|
-
}
|
|
15765
|
-
for (const [name, buffer] of Object.entries(created)) {
|
|
15766
|
-
const existing = state.buffers[name];
|
|
15767
|
-
if (existing && isBufferLike(existing)) {
|
|
15768
|
-
result[name] = existing;
|
|
15769
|
-
} else {
|
|
15770
|
-
if ("setName" in buffer && typeof buffer.setName === "function") {
|
|
15771
|
-
buffer.setName(name);
|
|
15772
|
-
}
|
|
15773
|
-
result[name] = buffer;
|
|
15774
|
-
hasNewBuffers = true;
|
|
15737
|
+
const created = useScopedResource({
|
|
15738
|
+
store,
|
|
15739
|
+
kind: "buffers",
|
|
15740
|
+
scope: isReader ? void 0 : scope,
|
|
15741
|
+
isLeaf: isBufferLike,
|
|
15742
|
+
create: () => {
|
|
15743
|
+
if (isReader) return {};
|
|
15744
|
+
return creatorOrScope(createLazyCreatorState(store.getState(), store));
|
|
15745
|
+
},
|
|
15746
|
+
prepare: (name, buffer) => {
|
|
15747
|
+
if ("setName" in buffer && typeof buffer.setName === "function") {
|
|
15748
|
+
buffer.setName(scope ? `${scope}.${name}` : name);
|
|
15775
15749
|
}
|
|
15750
|
+
return buffer;
|
|
15776
15751
|
}
|
|
15777
|
-
|
|
15778
|
-
|
|
15779
|
-
|
|
15780
|
-
|
|
15781
|
-
}
|
|
15752
|
+
});
|
|
15753
|
+
let buffers = created;
|
|
15754
|
+
if (creatorOrScope === void 0) {
|
|
15755
|
+
buffers = storeBuffers;
|
|
15756
|
+
} else if (typeof creatorOrScope === "string") {
|
|
15757
|
+
const scopeData = storeBuffers[creatorOrScope];
|
|
15758
|
+
buffers = scopeData && !isBufferLike(scopeData) ? scopeData : {};
|
|
15759
|
+
}
|
|
15782
15760
|
return { ...buffers, removeBuffers, clearBuffers, rebuildBuffers, disposeBuffers };
|
|
15783
15761
|
}
|
|
15784
15762
|
function rebuildAllBuffers(store, scope) {
|
|
15785
|
-
store
|
|
15786
|
-
store.setState((state) => {
|
|
15787
|
-
let newBuffers = state.buffers;
|
|
15788
|
-
if (scope && scope !== "root") {
|
|
15789
|
-
const { [scope]: _, ...rest } = state.buffers;
|
|
15790
|
-
newBuffers = rest;
|
|
15791
|
-
} else if (scope === "root") {
|
|
15792
|
-
newBuffers = {};
|
|
15793
|
-
for (const [key, value] of Object.entries(state.buffers)) {
|
|
15794
|
-
if (!isBufferLike(value)) newBuffers[key] = value;
|
|
15795
|
-
}
|
|
15796
|
-
} else {
|
|
15797
|
-
newBuffers = {};
|
|
15798
|
-
}
|
|
15799
|
-
return { buffers: newBuffers, _hmrVersion: state._hmrVersion + 1 };
|
|
15800
|
-
});
|
|
15763
|
+
rebuildResource(store, "buffers", scope);
|
|
15801
15764
|
}
|
|
15802
15765
|
|
|
15803
15766
|
const isStorageLike = (value) => {
|
|
@@ -15816,58 +15779,15 @@ const disposeStorage = (storage) => {
|
|
|
15816
15779
|
function useGPUStorage(creatorOrScope, scope) {
|
|
15817
15780
|
const store = usePrimaryStore();
|
|
15818
15781
|
const removeStorage = React.useCallback(
|
|
15819
|
-
(names, targetScope) =>
|
|
15820
|
-
const nameArray = Array.isArray(names) ? names : [names];
|
|
15821
|
-
store.setState((state) => {
|
|
15822
|
-
if (targetScope) {
|
|
15823
|
-
const currentScope = { ...state.gpuStorage[targetScope] };
|
|
15824
|
-
for (const name of nameArray) delete currentScope[name];
|
|
15825
|
-
return { gpuStorage: { ...state.gpuStorage, [targetScope]: currentScope } };
|
|
15826
|
-
}
|
|
15827
|
-
const gpuStorage2 = { ...state.gpuStorage };
|
|
15828
|
-
for (const name of nameArray) if (isStorageLike(gpuStorage2[name])) delete gpuStorage2[name];
|
|
15829
|
-
return { gpuStorage: gpuStorage2 };
|
|
15830
|
-
});
|
|
15831
|
-
},
|
|
15782
|
+
(names, targetScope) => removeResourceEntries(store, "gpuStorage", Array.isArray(names) ? names : [names], targetScope, isStorageLike),
|
|
15832
15783
|
[store]
|
|
15833
15784
|
);
|
|
15834
15785
|
const clearStorage = React.useCallback(
|
|
15835
|
-
(targetScope) =>
|
|
15836
|
-
store.setState((state) => {
|
|
15837
|
-
if (targetScope && targetScope !== "root") {
|
|
15838
|
-
const { [targetScope]: _, ...rest } = state.gpuStorage;
|
|
15839
|
-
return { gpuStorage: rest };
|
|
15840
|
-
}
|
|
15841
|
-
if (targetScope === "root") {
|
|
15842
|
-
const gpuStorage2 = {};
|
|
15843
|
-
for (const [key, value] of Object.entries(state.gpuStorage)) {
|
|
15844
|
-
if (!isStorageLike(value)) gpuStorage2[key] = value;
|
|
15845
|
-
}
|
|
15846
|
-
return { gpuStorage: gpuStorage2 };
|
|
15847
|
-
}
|
|
15848
|
-
return { gpuStorage: {} };
|
|
15849
|
-
});
|
|
15850
|
-
},
|
|
15786
|
+
(targetScope) => clearResourceEntries(store, "gpuStorage", targetScope, isStorageLike),
|
|
15851
15787
|
[store]
|
|
15852
15788
|
);
|
|
15853
15789
|
const rebuildStorage = React.useCallback(
|
|
15854
|
-
(targetScope) =>
|
|
15855
|
-
store.setState((state) => {
|
|
15856
|
-
let newStorage = state.gpuStorage;
|
|
15857
|
-
if (targetScope && targetScope !== "root") {
|
|
15858
|
-
const { [targetScope]: _, ...rest } = state.gpuStorage;
|
|
15859
|
-
newStorage = rest;
|
|
15860
|
-
} else if (targetScope === "root") {
|
|
15861
|
-
newStorage = {};
|
|
15862
|
-
for (const [key, value] of Object.entries(state.gpuStorage)) {
|
|
15863
|
-
if (!isStorageLike(value)) newStorage[key] = value;
|
|
15864
|
-
}
|
|
15865
|
-
} else {
|
|
15866
|
-
newStorage = {};
|
|
15867
|
-
}
|
|
15868
|
-
return { gpuStorage: newStorage, _hmrVersion: state._hmrVersion + 1 };
|
|
15869
|
-
});
|
|
15870
|
-
},
|
|
15790
|
+
(targetScope) => rebuildResource(store, "gpuStorage", targetScope),
|
|
15871
15791
|
[store]
|
|
15872
15792
|
);
|
|
15873
15793
|
const disposeStorageFn = React.useCallback(
|
|
@@ -15886,72 +15806,33 @@ function useGPUStorage(creatorOrScope, scope) {
|
|
|
15886
15806
|
);
|
|
15887
15807
|
const isReader = creatorOrScope === void 0 || typeof creatorOrScope === "string";
|
|
15888
15808
|
const storeStorage = usePrimaryThree((s) => s.gpuStorage);
|
|
15889
|
-
const
|
|
15890
|
-
|
|
15891
|
-
|
|
15892
|
-
|
|
15893
|
-
|
|
15894
|
-
|
|
15895
|
-
return
|
|
15896
|
-
|
|
15897
|
-
|
|
15898
|
-
|
|
15899
|
-
|
|
15900
|
-
|
|
15901
|
-
|
|
15902
|
-
const state = store.getState();
|
|
15903
|
-
const set = store.setState;
|
|
15904
|
-
const creator = creatorOrScope;
|
|
15905
|
-
const wrappedState = createLazyCreatorState(state);
|
|
15906
|
-
const created = creator(wrappedState);
|
|
15907
|
-
const result = {};
|
|
15908
|
-
let hasNewStorage = false;
|
|
15909
|
-
if (scope) {
|
|
15910
|
-
const currentScope = state.gpuStorage[scope] ?? {};
|
|
15911
|
-
for (const [name, storage] of Object.entries(created)) {
|
|
15912
|
-
if (currentScope[name]) {
|
|
15913
|
-
result[name] = currentScope[name];
|
|
15914
|
-
} else {
|
|
15915
|
-
if ("setName" in storage && typeof storage.setName === "function") {
|
|
15916
|
-
storage.setName(`${scope}.${name}`);
|
|
15917
|
-
}
|
|
15918
|
-
if ("name" in storage && typeof storage.name === "string") {
|
|
15919
|
-
storage.name = `${scope}.${name}`;
|
|
15920
|
-
}
|
|
15921
|
-
result[name] = storage;
|
|
15922
|
-
hasNewStorage = true;
|
|
15923
|
-
}
|
|
15924
|
-
}
|
|
15925
|
-
if (hasNewStorage) {
|
|
15926
|
-
set((s) => ({
|
|
15927
|
-
gpuStorage: {
|
|
15928
|
-
...s.gpuStorage,
|
|
15929
|
-
[scope]: { ...s.gpuStorage[scope], ...result }
|
|
15930
|
-
}
|
|
15931
|
-
}));
|
|
15809
|
+
const created = useScopedResource({
|
|
15810
|
+
store,
|
|
15811
|
+
kind: "gpuStorage",
|
|
15812
|
+
scope: isReader ? void 0 : scope,
|
|
15813
|
+
isLeaf: isStorageLike,
|
|
15814
|
+
create: () => {
|
|
15815
|
+
if (isReader) return {};
|
|
15816
|
+
return creatorOrScope(createLazyCreatorState(store.getState(), store));
|
|
15817
|
+
},
|
|
15818
|
+
prepare: (name, storage) => {
|
|
15819
|
+
const label = scope ? `${scope}.${name}` : name;
|
|
15820
|
+
if ("setName" in storage && typeof storage.setName === "function") {
|
|
15821
|
+
storage.setName(label);
|
|
15932
15822
|
}
|
|
15933
|
-
|
|
15934
|
-
|
|
15935
|
-
for (const [name, storage] of Object.entries(created)) {
|
|
15936
|
-
const existing = state.gpuStorage[name];
|
|
15937
|
-
if (existing && isStorageLike(existing)) {
|
|
15938
|
-
result[name] = existing;
|
|
15939
|
-
} else {
|
|
15940
|
-
if ("setName" in storage && typeof storage.setName === "function") {
|
|
15941
|
-
storage.setName(name);
|
|
15942
|
-
}
|
|
15943
|
-
if ("name" in storage && typeof storage.name === "string") {
|
|
15944
|
-
storage.name = name;
|
|
15945
|
-
}
|
|
15946
|
-
result[name] = storage;
|
|
15947
|
-
hasNewStorage = true;
|
|
15823
|
+
if ("name" in storage && typeof storage.name === "string") {
|
|
15824
|
+
storage.name = label;
|
|
15948
15825
|
}
|
|
15826
|
+
return storage;
|
|
15949
15827
|
}
|
|
15950
|
-
|
|
15951
|
-
|
|
15952
|
-
|
|
15953
|
-
|
|
15954
|
-
}
|
|
15828
|
+
});
|
|
15829
|
+
let gpuStorage = created;
|
|
15830
|
+
if (creatorOrScope === void 0) {
|
|
15831
|
+
gpuStorage = storeStorage;
|
|
15832
|
+
} else if (typeof creatorOrScope === "string") {
|
|
15833
|
+
const scopeData = storeStorage[creatorOrScope];
|
|
15834
|
+
gpuStorage = scopeData && !isStorageLike(scopeData) ? scopeData : {};
|
|
15835
|
+
}
|
|
15955
15836
|
return {
|
|
15956
15837
|
...gpuStorage,
|
|
15957
15838
|
removeStorage,
|
|
@@ -15961,22 +15842,7 @@ function useGPUStorage(creatorOrScope, scope) {
|
|
|
15961
15842
|
};
|
|
15962
15843
|
}
|
|
15963
15844
|
function rebuildAllStorage(store, scope) {
|
|
15964
|
-
store
|
|
15965
|
-
store.setState((state) => {
|
|
15966
|
-
let newStorage = state.gpuStorage;
|
|
15967
|
-
if (scope && scope !== "root") {
|
|
15968
|
-
const { [scope]: _, ...rest } = state.gpuStorage;
|
|
15969
|
-
newStorage = rest;
|
|
15970
|
-
} else if (scope === "root") {
|
|
15971
|
-
newStorage = {};
|
|
15972
|
-
for (const [key, value] of Object.entries(state.gpuStorage)) {
|
|
15973
|
-
if (!isStorageLike(value)) newStorage[key] = value;
|
|
15974
|
-
}
|
|
15975
|
-
} else {
|
|
15976
|
-
newStorage = {};
|
|
15977
|
-
}
|
|
15978
|
-
return { gpuStorage: newStorage, _hmrVersion: state._hmrVersion + 1 };
|
|
15979
|
-
});
|
|
15845
|
+
rebuildResource(store, "gpuStorage", scope);
|
|
15980
15846
|
}
|
|
15981
15847
|
|
|
15982
15848
|
function useRenderPipeline(mainCB, setupCB) {
|
|
@@ -16017,12 +15883,12 @@ function useRenderPipeline(mainCB, setupCB) {
|
|
|
16017
15883
|
const state = store.getState();
|
|
16018
15884
|
const set = store.setState;
|
|
16019
15885
|
try {
|
|
16020
|
-
let
|
|
15886
|
+
let pipeline = state.renderPipeline;
|
|
16021
15887
|
let currentPasses = { ...state.passes };
|
|
16022
|
-
let
|
|
16023
|
-
if (!
|
|
16024
|
-
|
|
16025
|
-
|
|
15888
|
+
let justCreatedPipeline = false;
|
|
15889
|
+
if (!pipeline) {
|
|
15890
|
+
pipeline = new webgpu.RenderPipeline(renderer);
|
|
15891
|
+
justCreatedPipeline = true;
|
|
16026
15892
|
}
|
|
16027
15893
|
const cacheValid = scenePassCacheRef.current && scenePassCacheRef.current.sceneUuid === scene.uuid && scenePassCacheRef.current.cameraUuid === camera.uuid;
|
|
16028
15894
|
let scenePass;
|
|
@@ -16033,9 +15899,9 @@ function useRenderPipeline(mainCB, setupCB) {
|
|
|
16033
15899
|
scenePassCacheRef.current = { sceneUuid: scene.uuid, cameraUuid: camera.uuid, scenePass };
|
|
16034
15900
|
}
|
|
16035
15901
|
currentPasses.scenePass = scenePass;
|
|
16036
|
-
if (!
|
|
16037
|
-
set({ renderPipeline:
|
|
16038
|
-
const shouldRunCallbacks =
|
|
15902
|
+
if (!pipeline.outputNode || justCreatedPipeline) pipeline.outputNode = scenePass;
|
|
15903
|
+
set({ renderPipeline: pipeline, passes: currentPasses });
|
|
15904
|
+
const shouldRunCallbacks = justCreatedPipeline || !callbacksRanRef.current || !cacheValid;
|
|
16039
15905
|
if (shouldRunCallbacks) {
|
|
16040
15906
|
if (setupCBRef.current) {
|
|
16041
15907
|
const freshState = store.getState();
|
|
@@ -16056,7 +15922,7 @@ function useRenderPipeline(mainCB, setupCB) {
|
|
|
16056
15922
|
callbacksRanRef.current = true;
|
|
16057
15923
|
}
|
|
16058
15924
|
} catch (error) {
|
|
16059
|
-
console.
|
|
15925
|
+
console.warn("[useRenderPipeline] Setup failed; the render pipeline was not configured:", error);
|
|
16060
15926
|
}
|
|
16061
15927
|
}, [store, renderer, scene, camera, isLegacy, rebuildVersion]);
|
|
16062
15928
|
const passes = useThree((s) => s.passes);
|