@react-three/fiber 10.0.0-canary.d202062 → 10.0.0-canary.d46ab63
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/extension.cjs +8 -8
- package/dist/extension.d.cts +50 -6
- package/dist/extension.d.mts +50 -6
- package/dist/extension.d.ts +50 -6
- package/dist/extension.mjs +1 -1
- package/dist/index.cjs +17 -19
- package/dist/index.d.cts +15 -47
- package/dist/index.d.mts +15 -47
- package/dist/index.d.ts +15 -47
- package/dist/index.mjs +7 -8
- package/dist/legacy.cjs +37 -15
- package/dist/legacy.d.cts +10 -7
- package/dist/legacy.d.mts +10 -7
- package/dist/legacy.d.ts +10 -7
- package/dist/legacy.mjs +13 -5
- package/dist/shared/{fiber.BY6Yf1h-.d.cts → fiber.34TOMPo3.d.cts} +157 -454
- package/dist/shared/fiber.BFuGd7gN.d.cts +90 -0
- package/dist/shared/{fiber.tsM9NKZ9.mjs → fiber.BSYBnw8x.mjs} +2177 -1575
- package/dist/shared/{fiber.B0oukOFO.mjs → fiber.Biz9olEe.mjs} +181 -64
- package/dist/shared/fiber.Bll9fqKA.d.mts +90 -0
- package/dist/shared/{fiber.Cu2hX1IM.d.mts → fiber.CjMAAsJy.d.ts} +157 -454
- package/dist/shared/{fiber.I5Q4dVvl.d.cts → fiber.DQTSZ24m.d.cts} +488 -26
- package/dist/shared/{fiber.I5Q4dVvl.d.mts → fiber.DQTSZ24m.d.mts} +488 -26
- package/dist/shared/{fiber.I5Q4dVvl.d.ts → fiber.DQTSZ24m.d.ts} +488 -26
- package/dist/shared/fiber.DUgKvaq-.mjs +9 -0
- package/dist/shared/{fiber.khFlPHPf.cjs → fiber.DfiCufha.cjs} +186 -62
- package/dist/shared/fiber.DuA4F8L5.d.ts +90 -0
- package/dist/shared/{fiber.DXw-SLsH.d.ts → fiber.Dy7Uz273.d.mts} +157 -454
- package/dist/shared/fiber.X4yI0DId.cjs +14 -0
- package/dist/shared/{fiber.oKEFddXj.cjs → fiber.nDnBf1np.cjs} +2222 -1620
- package/dist/webgpu/index.cjs +16 -18
- package/dist/webgpu/index.d.cts +17 -78
- package/dist/webgpu/index.d.mts +17 -78
- package/dist/webgpu/index.d.ts +17 -78
- package/dist/webgpu/index.mjs +7 -9
- package/package.json +3 -3
- package/dist/chunks/webgl.cjs +0 -27
- package/dist/chunks/webgl.mjs +0 -11
- package/dist/shared/fiber.BU0vBHc9.d.mts +0 -48
- package/dist/shared/fiber.Cx-UAmMb.d.ts +0 -48
- package/dist/shared/fiber.DAl4H27x.d.cts +0 -48
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
2
|
-
import {
|
|
2
|
+
import { i as isDevelopment, n as notifyDepreciated, p as preserveAccessors, h as defineRendererAccessors, j as detachRootExtensions, k as attachRootExtensions, d as useIsomorphicLayoutEffect, c as context, a as useThree, u as useStore, l as unstageTextures, m as stageTextures, e as useMutableCallback, o as isAccessor, q as cloneState, t as keepAccessors, b as useFrame, f as useBridge, v as useGate, w as notifyAlpha, E as ErrorBoundary, B as Block, x as notifyRootExtensionsHmr } from './fiber.Biz9olEe.mjs';
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
import React__default, { useRef, useMemo, useLayoutEffect, useEffect, useImperativeHandle, useCallback, useState } from 'react';
|
|
5
5
|
import useMeasure from 'react-use-measure';
|
|
@@ -107,6 +107,20 @@ function updateFrustum(camera, frustum) {
|
|
|
107
107
|
target.setFromProjectionMatrix(frustumMatrix);
|
|
108
108
|
return target;
|
|
109
109
|
}
|
|
110
|
+
function computeInitialSize(canvas, size) {
|
|
111
|
+
if (!size && typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement && canvas.parentElement) {
|
|
112
|
+
const { width, height, top, left } = canvas.parentElement.getBoundingClientRect();
|
|
113
|
+
return { width, height, top, left };
|
|
114
|
+
} else if (!size && typeof OffscreenCanvas !== "undefined" && canvas instanceof OffscreenCanvas) {
|
|
115
|
+
return {
|
|
116
|
+
width: canvas.width,
|
|
117
|
+
height: canvas.height,
|
|
118
|
+
top: 0,
|
|
119
|
+
left: 0
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
return { width: 0, height: 0, top: 0, left: 0, ...size };
|
|
123
|
+
}
|
|
110
124
|
|
|
111
125
|
const REACT_INTERNAL_PROPS = ["children", "key", "ref"];
|
|
112
126
|
function findInitialRoot(instance) {
|
|
@@ -174,6 +188,7 @@ function prepare(target, root, type, props) {
|
|
|
174
188
|
object,
|
|
175
189
|
eventCount: 0,
|
|
176
190
|
handlers: {},
|
|
191
|
+
previousVisible: void 0,
|
|
177
192
|
isHidden: false
|
|
178
193
|
};
|
|
179
194
|
if (object) object.__r3f = instance;
|
|
@@ -396,6 +411,27 @@ function isOnce(value) {
|
|
|
396
411
|
return value !== null && typeof value === "object" && ONCE in value;
|
|
397
412
|
}
|
|
398
413
|
|
|
414
|
+
function assertNodeMaterialSupported(state, value) {
|
|
415
|
+
if (!state?.isLegacy) return;
|
|
416
|
+
const material = (Array.isArray(value) ? value : [value]).find((m) => m?.isNodeMaterial);
|
|
417
|
+
if (!material) return;
|
|
418
|
+
throw new Error(
|
|
419
|
+
`R3F: ${material.type ?? "Node material"} requires WebGPURenderer (it falls back to WebGL2 automatically). Import Canvas from @react-three/fiber or @react-three/fiber/webgpu instead of @react-three/fiber/legacy.`
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
const warnedGLSL = /* @__PURE__ */ new Set();
|
|
423
|
+
function warnGLSLMaterialUnsupported(state, value) {
|
|
424
|
+
if (!state || state.isLegacy || state.internal?.support?.kind !== "webgpu" || !isDevelopment()) return;
|
|
425
|
+
const material = (Array.isArray(value) ? value : [value]).find((m) => m?.isShaderMaterial && !m.isNodeMaterial);
|
|
426
|
+
if (!material) return;
|
|
427
|
+
const type = material.type ?? "ShaderMaterial";
|
|
428
|
+
if (warnedGLSL.has(type)) return;
|
|
429
|
+
warnedGLSL.add(type);
|
|
430
|
+
console.warn(
|
|
431
|
+
`R3F: ${type} is a GLSL material, which WebGPURenderer cannot compile; three draws it with a blank default material. @react-three/fiber renders with WebGPU: import Canvas from @react-three/fiber/legacy to keep WebGLRenderer, or port the shader to a node material (TSL).`
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
|
|
399
435
|
const RESERVED_PROPS = [
|
|
400
436
|
"children",
|
|
401
437
|
"key",
|
|
@@ -413,6 +449,28 @@ const VISIBILITY_EVENT_REGEX = /^on(Framed|Occluded|Visible)$/;
|
|
|
413
449
|
const INDEX_REGEX = /-\d+$/;
|
|
414
450
|
const MEMOIZED_PROTOTYPES = /* @__PURE__ */ new Map();
|
|
415
451
|
const colorMaps = ["map", "emissiveMap", "sheenColorMap", "specularColorMap", "envMap"];
|
|
452
|
+
const programProps = /* @__PURE__ */ new Set([
|
|
453
|
+
"transparent",
|
|
454
|
+
"vertexColors",
|
|
455
|
+
"flatShading",
|
|
456
|
+
"fog",
|
|
457
|
+
// Culling is live, but DOUBLE_SIDED / FLIP_SIDED normal flipping is compiled in
|
|
458
|
+
"side",
|
|
459
|
+
"alphaHash",
|
|
460
|
+
"premultipliedAlpha",
|
|
461
|
+
// Both feed the OPAQUE define when the material is not transparent
|
|
462
|
+
"blending",
|
|
463
|
+
"alphaToCoverage",
|
|
464
|
+
"dithering",
|
|
465
|
+
"sizeAttenuation",
|
|
466
|
+
"combine",
|
|
467
|
+
"normalMapType",
|
|
468
|
+
"depthPacking"
|
|
469
|
+
]);
|
|
470
|
+
function changesProgram(root, key, previous, next) {
|
|
471
|
+
if (!root?.isMaterial || previous === next) return false;
|
|
472
|
+
return programProps.has(key) || isTexture(previous) !== isTexture(next);
|
|
473
|
+
}
|
|
416
474
|
function resolve(root, key) {
|
|
417
475
|
if (!key.includes("-")) return { root, key, target: root[key] };
|
|
418
476
|
if (key in root) return { root, key, target: root[key] };
|
|
@@ -443,6 +501,7 @@ function attach(parent, child) {
|
|
|
443
501
|
const { root, key } = resolve(parent.object, child.props.attach);
|
|
444
502
|
child.previousAttach = root[key];
|
|
445
503
|
root[key] = child.object;
|
|
504
|
+
if (changesProgram(root, key, child.previousAttach, child.object)) root.needsUpdate = true;
|
|
446
505
|
} else if (is.fun(child.props.attach)) {
|
|
447
506
|
child.previousAttach = child.props.attach(parent.object, child.object);
|
|
448
507
|
}
|
|
@@ -453,6 +512,7 @@ function detach(parent, child) {
|
|
|
453
512
|
const previous = child.previousAttach;
|
|
454
513
|
if (previous === void 0) delete root[key];
|
|
455
514
|
else root[key] = previous;
|
|
515
|
+
if (changesProgram(root, key, child.object, previous)) root.needsUpdate = true;
|
|
456
516
|
} else {
|
|
457
517
|
child.previousAttach?.(parent.object, child.object);
|
|
458
518
|
}
|
|
@@ -532,6 +592,10 @@ function applyProps(object, props) {
|
|
|
532
592
|
}
|
|
533
593
|
continue;
|
|
534
594
|
}
|
|
595
|
+
if (prop === "visible" && instance?.isHidden && instance.previousVisible !== void 0) {
|
|
596
|
+
instance.previousVisible = value;
|
|
597
|
+
continue;
|
|
598
|
+
}
|
|
535
599
|
let { root, key, target } = resolve(object, prop);
|
|
536
600
|
if (target === void 0 && (typeof root !== "object" || root === null)) {
|
|
537
601
|
throw Error(`R3F: Cannot set "${prop}". Ensure it is an object before setting "${key}".`);
|
|
@@ -559,16 +623,24 @@ function applyProps(object, props) {
|
|
|
559
623
|
for (const name in nextUniforms) {
|
|
560
624
|
const uniform = nextUniforms[name];
|
|
561
625
|
const targetUniform = uniforms[name];
|
|
562
|
-
if (targetUniform)
|
|
563
|
-
|
|
626
|
+
if (targetUniform) {
|
|
627
|
+
Object.assign(targetUniform, uniform);
|
|
628
|
+
} else {
|
|
564
629
|
const nextUniform = isUniform(uniform) ? uniform.clone() : new (getThree()).Uniform(uniform.value);
|
|
565
630
|
uniforms[name] = nextUniform;
|
|
566
631
|
}
|
|
567
632
|
}
|
|
568
633
|
} else {
|
|
634
|
+
if (key === "material") {
|
|
635
|
+
assertNodeMaterialSupported(rootState, value);
|
|
636
|
+
warnGLSLMaterialUnsupported(rootState, value);
|
|
637
|
+
}
|
|
638
|
+
const previous = root[key];
|
|
569
639
|
root[key] = value;
|
|
570
640
|
if (key.endsWith("Node") && root.isMaterial) {
|
|
571
641
|
root.needsUpdate = true;
|
|
642
|
+
} else if (changesProgram(root, key, previous, value)) {
|
|
643
|
+
root.needsUpdate = true;
|
|
572
644
|
}
|
|
573
645
|
const three = rootState && getThree();
|
|
574
646
|
if (three && rootState.renderer?.outputColorSpace === three.SRGBColorSpace && colorMaps.includes(key) && isTexture(value) && root[key]?.isTexture && // sRGB textures must be RGBA8 since r137 https://github.com/mrdoob/three.js/pull/23129
|
|
@@ -609,468 +681,389 @@ function applyProps(object, props) {
|
|
|
609
681
|
return object;
|
|
610
682
|
}
|
|
611
683
|
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
memoizedLoaders.set(Proto, loader);
|
|
620
|
-
}
|
|
621
|
-
return loader;
|
|
622
|
-
}
|
|
623
|
-
return Proto;
|
|
624
|
-
}
|
|
625
|
-
function loadingFn(extensions, onProgress) {
|
|
626
|
-
return function(Proto, input) {
|
|
627
|
-
const loader = getLoader(Proto);
|
|
628
|
-
if (extensions) extensions(loader);
|
|
629
|
-
if ("loadAsync" in loader && typeof loader.loadAsync === "function") {
|
|
630
|
-
return loader.loadAsync(input, onProgress).then((data) => {
|
|
631
|
-
if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
|
|
632
|
-
return data;
|
|
633
|
-
});
|
|
634
|
-
}
|
|
635
|
-
return new Promise(
|
|
636
|
-
(res, reject) => loader.load(
|
|
637
|
-
input,
|
|
638
|
-
(data) => {
|
|
639
|
-
if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
|
|
640
|
-
res(data);
|
|
641
|
-
},
|
|
642
|
-
onProgress,
|
|
643
|
-
(error) => reject(new Error(`Could not load ${input}: ${error?.message}`))
|
|
644
|
-
)
|
|
645
|
-
);
|
|
646
|
-
};
|
|
647
|
-
}
|
|
648
|
-
function useLoader(loader, input, extensions, onProgress, cacheKey) {
|
|
649
|
-
const inputs = Array.isArray(input) ? input : [input];
|
|
650
|
-
const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
|
|
651
|
-
const fn = loadingFn(extensions, onProgress);
|
|
652
|
-
const results = cacheKeys.map(
|
|
653
|
-
(key, index) => suspend(() => fn(loader, inputs[index]), [loader, key], { equal: is.equ })
|
|
654
|
-
);
|
|
655
|
-
const stableRef = useRef(null);
|
|
656
|
-
const previous = stableRef.current;
|
|
657
|
-
const stable = previous !== null && previous.length === results.length && previous.every((value, i) => value === results[i]) ? previous : results;
|
|
658
|
-
stableRef.current = stable;
|
|
659
|
-
return Array.isArray(input) ? stable : stable[0];
|
|
660
|
-
}
|
|
661
|
-
useLoader.preload = function(loader, input, extensions, onProgress, cacheKey) {
|
|
662
|
-
const inputs = Array.isArray(input) ? input : [input];
|
|
663
|
-
const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
|
|
664
|
-
cacheKeys.forEach(
|
|
665
|
-
(key, index) => preload(() => loadingFn(extensions, onProgress)(loader, inputs[index]), [loader, key])
|
|
666
|
-
);
|
|
667
|
-
};
|
|
668
|
-
useLoader.clear = function(loader, input, cacheKey) {
|
|
669
|
-
const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
|
|
670
|
-
cacheKeys.forEach((key) => clear([loader, key]));
|
|
671
|
-
};
|
|
672
|
-
useLoader.loader = getLoader;
|
|
673
|
-
|
|
674
|
-
const IsObject = (url) => url === Object(url) && !Array.isArray(url) && typeof url !== "function";
|
|
675
|
-
function getUrls(input) {
|
|
676
|
-
if (typeof input === "string") return [input];
|
|
677
|
-
if (Array.isArray(input)) return input;
|
|
678
|
-
return Object.values(input);
|
|
679
|
-
}
|
|
680
|
-
function inputSignature(input) {
|
|
681
|
-
if (typeof input === "string") return input;
|
|
682
|
-
if (Array.isArray(input)) return input.join("\0");
|
|
683
|
-
return Object.keys(input).sort().map((key) => `${key}\0${input[key]}`).join("");
|
|
684
|
-
}
|
|
685
|
-
function allUrlsCached(urls, textureCache) {
|
|
686
|
-
return urls.every((url) => textureCache.has(url));
|
|
684
|
+
function updateSize(state, size, imperative) {
|
|
685
|
+
state.set((current) => ({
|
|
686
|
+
size,
|
|
687
|
+
viewport: { ...current.viewport, ...current.viewport.getCurrentViewport(current.camera, void 0, size) },
|
|
688
|
+
_sizeImperative: imperative
|
|
689
|
+
}));
|
|
690
|
+
state.invalidate();
|
|
687
691
|
}
|
|
688
|
-
function
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
return input.map((url) => textureCache.get(url));
|
|
693
|
-
} else {
|
|
694
|
-
const result = {};
|
|
695
|
-
const objInput = input;
|
|
696
|
-
for (const key in objInput) {
|
|
697
|
-
result[key] = textureCache.get(objInput[key]);
|
|
698
|
-
}
|
|
699
|
-
return result;
|
|
700
|
-
}
|
|
692
|
+
function configureSize(store, size) {
|
|
693
|
+
const state = store.getState();
|
|
694
|
+
if (state._sizeImperative || is.equ(size, state.size, { objects: "shallow", strict: false })) return;
|
|
695
|
+
updateSize(state, size, false);
|
|
701
696
|
}
|
|
702
|
-
|
|
703
|
-
const
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
const keyed = {};
|
|
727
|
-
const textureArray = loadedTextures;
|
|
728
|
-
let i = 0;
|
|
729
|
-
for (const key in stableInput) keyed[key] = textureArray[i++];
|
|
730
|
-
return keyed;
|
|
731
|
-
} else {
|
|
732
|
-
return loadedTextures;
|
|
733
|
-
}
|
|
734
|
-
}, [stableInput, loadedTextures, cachedResult]);
|
|
735
|
-
useLayoutEffect(() => {
|
|
736
|
-
if (cachedResult) return;
|
|
737
|
-
if (onLoadCalledForRef.current === inputKey) return;
|
|
738
|
-
onLoadCalledForRef.current = inputKey;
|
|
739
|
-
onLoadRef.current?.(mappedTextures);
|
|
740
|
-
}, [cachedResult, mappedTextures, inputKey]);
|
|
741
|
-
useEffect(() => {
|
|
742
|
-
if (cachedResult) return;
|
|
743
|
-
if ("initTexture" in renderer) {
|
|
744
|
-
let textureArray = [];
|
|
745
|
-
if (Array.isArray(loadedTextures)) {
|
|
746
|
-
textureArray = loadedTextures;
|
|
747
|
-
} else if (loadedTextures.isTexture) {
|
|
748
|
-
textureArray = [loadedTextures];
|
|
749
|
-
} else if (IsObject(loadedTextures)) {
|
|
750
|
-
textureArray = Object.values(loadedTextures);
|
|
697
|
+
const createStore = (invalidate, advance) => {
|
|
698
|
+
const rootStore = createWithEqualityFn((rawSet, get, api) => {
|
|
699
|
+
const set = api.setState = preserveAccessors(rawSet, get);
|
|
700
|
+
let position;
|
|
701
|
+
let defaultTarget;
|
|
702
|
+
let tempTarget;
|
|
703
|
+
function getCurrentViewport(camera = get().camera, target = void 0, size = get().size) {
|
|
704
|
+
const { Vector3 } = getThree();
|
|
705
|
+
position ?? (position = new Vector3());
|
|
706
|
+
defaultTarget ?? (defaultTarget = new Vector3());
|
|
707
|
+
tempTarget ?? (tempTarget = new Vector3());
|
|
708
|
+
target ?? (target = defaultTarget);
|
|
709
|
+
const { width, height, top, left } = size;
|
|
710
|
+
const aspect = width / height;
|
|
711
|
+
if (target.isVector3) tempTarget.copy(target);
|
|
712
|
+
else tempTarget.set(...target);
|
|
713
|
+
const distance = camera.getWorldPosition(position).distanceTo(tempTarget);
|
|
714
|
+
if (isOrthographicCamera(camera)) {
|
|
715
|
+
return { width: width / camera.zoom, height: height / camera.zoom, top, left, factor: 1, distance, aspect };
|
|
716
|
+
} else {
|
|
717
|
+
const fov = camera.fov * Math.PI / 180;
|
|
718
|
+
const h = 2 * Math.tan(fov / 2) * distance;
|
|
719
|
+
const w = h * (width / height);
|
|
720
|
+
return { width: w, height: h, top, left, factor: width / w, distance, aspect };
|
|
751
721
|
}
|
|
752
|
-
textureArray.forEach((texture) => {
|
|
753
|
-
if (texture?.isTexture) {
|
|
754
|
-
renderer.initTexture(texture);
|
|
755
|
-
}
|
|
756
|
-
});
|
|
757
722
|
}
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
urlTextureMap.map(([url]) => url)
|
|
781
|
-
);
|
|
782
|
-
return () => store.setState((state) => {
|
|
783
|
-
const refs = new Map(state._textureRefs);
|
|
784
|
-
for (const [url] of urlTextureMap) {
|
|
785
|
-
const next = (refs.get(url) ?? 0) - 1;
|
|
786
|
-
if (next <= 0) refs.delete(url);
|
|
787
|
-
else refs.set(url, next);
|
|
788
|
-
}
|
|
789
|
-
return { _textureRefs: refs };
|
|
790
|
-
});
|
|
791
|
-
}, [cache, stableInput, mappedTextures, store]);
|
|
792
|
-
if (cache && !cachedResult) stageTextures(store, urlTextureEntries(stableInput, mappedTextures));
|
|
793
|
-
return mappedTextures;
|
|
794
|
-
}
|
|
795
|
-
function urlTextureEntries(input, textures) {
|
|
796
|
-
if (typeof input === "string") return [[input, textures]];
|
|
797
|
-
if (Array.isArray(input)) return input.map((url, i) => [url, textures[i]]);
|
|
798
|
-
const record = textures;
|
|
799
|
-
return Object.keys(input).map((key) => [input[key], record[key]]);
|
|
800
|
-
}
|
|
801
|
-
useTexture.preload = (url) => {
|
|
802
|
-
whenThree().then((three) => useLoader.preload(three.TextureLoader, url));
|
|
803
|
-
};
|
|
804
|
-
useTexture.clear = (input) => {
|
|
805
|
-
if (hasThree()) useLoader.clear(getThree().TextureLoader, input);
|
|
806
|
-
};
|
|
807
|
-
const Texture = ({
|
|
808
|
-
children,
|
|
809
|
-
input,
|
|
810
|
-
onLoad,
|
|
811
|
-
cache
|
|
812
|
-
}) => {
|
|
813
|
-
const options = typeof onLoad === "function" ? { onLoad, cache } : { ...onLoad, cache };
|
|
814
|
-
const ret = useTexture(input, options);
|
|
815
|
-
return /* @__PURE__ */ jsx(Fragment, { children: children?.(ret) });
|
|
816
|
-
};
|
|
817
|
-
|
|
818
|
-
function useTextures(selector) {
|
|
819
|
-
const store = useStore();
|
|
820
|
-
const registry = useMemo(() => {
|
|
821
|
-
const getState = store.getState;
|
|
822
|
-
const setState = store.setState;
|
|
823
|
-
const getOne = (key) => getState().textures.get(key);
|
|
824
|
-
return {
|
|
825
|
-
get all() {
|
|
826
|
-
return getState().textures;
|
|
723
|
+
let performanceTimeout = void 0;
|
|
724
|
+
const setPerformanceCurrent = (current) => set((state2) => ({ performance: { ...state2.performance, current } }));
|
|
725
|
+
const rootState = {
|
|
726
|
+
set,
|
|
727
|
+
get,
|
|
728
|
+
// Mock objects that have to be configured
|
|
729
|
+
// primaryStore is set after store creation (self-reference for primary, primary's store for secondary)
|
|
730
|
+
primaryStore: null,
|
|
731
|
+
gl: null,
|
|
732
|
+
renderer: null,
|
|
733
|
+
camera: null,
|
|
734
|
+
// frustum, pointer and mouse are three objects; configure() creates them with the renderer
|
|
735
|
+
frustum: null,
|
|
736
|
+
autoUpdateFrustum: true,
|
|
737
|
+
raycaster: null,
|
|
738
|
+
events: {
|
|
739
|
+
priority: 1,
|
|
740
|
+
enabled: true,
|
|
741
|
+
connected: false,
|
|
742
|
+
frameTimedRaycasts: true,
|
|
743
|
+
alwaysFireOnScroll: true,
|
|
744
|
+
updateOnFrame: false
|
|
827
745
|
},
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
746
|
+
scene: null,
|
|
747
|
+
rootScene: null,
|
|
748
|
+
xr: null,
|
|
749
|
+
inspector: null,
|
|
750
|
+
invalidate: (frames = 1, stackFrames = false) => invalidate(get(), frames, stackFrames),
|
|
751
|
+
advance: (timestamp, runGlobalEffects) => advance(timestamp, runGlobalEffects, get()),
|
|
752
|
+
textureColorSpace: "srgb",
|
|
753
|
+
// THREE.SRGBColorSpace
|
|
754
|
+
isLegacy: false,
|
|
755
|
+
webGPUSupported: false,
|
|
756
|
+
isNative: false,
|
|
757
|
+
controls: null,
|
|
758
|
+
pointer: null,
|
|
759
|
+
mouse: null,
|
|
760
|
+
frameloop: "always",
|
|
761
|
+
onPointerMissed: void 0,
|
|
762
|
+
onDragOverMissed: void 0,
|
|
763
|
+
onDropMissed: void 0,
|
|
764
|
+
performance: {
|
|
765
|
+
current: 1,
|
|
766
|
+
min: 0.5,
|
|
767
|
+
max: 1,
|
|
768
|
+
debounce: 200,
|
|
769
|
+
regress: () => {
|
|
770
|
+
const state2 = get();
|
|
771
|
+
if (performanceTimeout) clearTimeout(performanceTimeout);
|
|
772
|
+
if (state2.performance.current !== state2.performance.min) setPerformanceCurrent(state2.performance.min);
|
|
773
|
+
performanceTimeout = setTimeout(
|
|
774
|
+
() => setPerformanceCurrent(get().performance.max),
|
|
775
|
+
state2.performance.debounce
|
|
776
|
+
);
|
|
777
|
+
}
|
|
834
778
|
},
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
779
|
+
size: { width: 0, height: 0, top: 0, left: 0 },
|
|
780
|
+
viewport: {
|
|
781
|
+
initialDpr: 0,
|
|
782
|
+
dpr: 0,
|
|
783
|
+
width: 0,
|
|
784
|
+
height: 0,
|
|
785
|
+
top: 0,
|
|
786
|
+
left: 0,
|
|
787
|
+
aspect: 0,
|
|
788
|
+
distance: 0,
|
|
789
|
+
factor: 0,
|
|
790
|
+
getCurrentViewport
|
|
846
791
|
},
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
const
|
|
850
|
-
if (
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
792
|
+
setEvents: (events) => set((state2) => ({ events: { ...state2.events, ...events } })),
|
|
793
|
+
setSize: (width, height, top, left) => {
|
|
794
|
+
const state2 = get();
|
|
795
|
+
if (width === void 0) {
|
|
796
|
+
if (state2._sizeProps) {
|
|
797
|
+
const { width: propW, height: propH } = state2._sizeProps;
|
|
798
|
+
if (propW !== void 0 || propH !== void 0) {
|
|
799
|
+
const currentSize = state2.size;
|
|
800
|
+
const newSize = {
|
|
801
|
+
width: propW ?? currentSize.width,
|
|
802
|
+
height: propH ?? currentSize.height,
|
|
803
|
+
top: currentSize.top,
|
|
804
|
+
left: currentSize.left
|
|
805
|
+
};
|
|
806
|
+
updateSize(state2, newSize, false);
|
|
807
|
+
return;
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
set({ _sizeImperative: false });
|
|
811
|
+
return;
|
|
855
812
|
}
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
return { textures, _textureRefs: nextRefs };
|
|
863
|
-
});
|
|
864
|
-
return true;
|
|
813
|
+
const w = width;
|
|
814
|
+
const h = height ?? width;
|
|
815
|
+
const t = top ?? state2.size.top;
|
|
816
|
+
const l = left ?? state2.size.left;
|
|
817
|
+
const size = { width: w, height: h, top: t, left: l };
|
|
818
|
+
updateSize(state2, size, true);
|
|
865
819
|
},
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
820
|
+
setDpr: (dpr) => set((state2) => {
|
|
821
|
+
const resolved = calculateDpr(dpr);
|
|
822
|
+
return { viewport: { ...state2.viewport, dpr: resolved, initialDpr: state2.viewport.initialDpr || resolved } };
|
|
823
|
+
}),
|
|
824
|
+
setFrameloop: (frameloop = "always") => {
|
|
825
|
+
const rootId = get().internal.rootId;
|
|
826
|
+
if (rootId) getScheduler().setRootFrameloop(rootId, frameloop);
|
|
827
|
+
set(() => ({ frameloop }));
|
|
828
|
+
},
|
|
829
|
+
setError: (error) => set(() => ({ error })),
|
|
830
|
+
error: null,
|
|
831
|
+
//* Texture registry (useTextures) ==============================
|
|
832
|
+
// TSL fields (uniforms, nodes, ..., renderPipeline) are added by @react-three/tsl's root extension.
|
|
833
|
+
textures: /* @__PURE__ */ new Map(),
|
|
834
|
+
_textureRefs: /* @__PURE__ */ new Map(),
|
|
835
|
+
_sizeImperative: false,
|
|
836
|
+
_sizeProps: null,
|
|
837
|
+
previousRoot: void 0,
|
|
838
|
+
internal: {
|
|
839
|
+
// Events
|
|
840
|
+
interaction: [],
|
|
841
|
+
subscribers: [],
|
|
842
|
+
// Per-pointer state (new unified structure)
|
|
843
|
+
pointerMap: /* @__PURE__ */ new Map(),
|
|
844
|
+
pointerDirty: /* @__PURE__ */ new Map(),
|
|
845
|
+
lastEvent: React.createRef(),
|
|
846
|
+
// Deprecated but kept for backwards compatibility
|
|
847
|
+
hovered: /* @__PURE__ */ new Map(),
|
|
848
|
+
initialClick: [0, 0],
|
|
849
|
+
initialHits: [],
|
|
850
|
+
capturedMap: /* @__PURE__ */ new Map(),
|
|
851
|
+
// Visibility tracking (onFramed, onOccluded, onVisible)
|
|
852
|
+
visibilityRegistry: /* @__PURE__ */ new Map(),
|
|
853
|
+
// Occlusion system (WebGPU only)
|
|
854
|
+
occlusionEnabled: false,
|
|
855
|
+
occlusionObserver: null,
|
|
856
|
+
occlusionCache: /* @__PURE__ */ new Map(),
|
|
857
|
+
helperGroup: null,
|
|
858
|
+
// Updates
|
|
859
|
+
active: false,
|
|
860
|
+
frames: 0,
|
|
861
|
+
priority: 0,
|
|
862
|
+
subscribe: (ref, priority, store) => {
|
|
863
|
+
const internal = get().internal;
|
|
864
|
+
internal.priority = internal.priority + (priority > 0 ? 1 : 0);
|
|
865
|
+
internal.subscribers.push({ ref, priority, store });
|
|
866
|
+
internal.subscribers = internal.subscribers.sort((a, b) => a.priority - b.priority);
|
|
867
|
+
return () => {
|
|
868
|
+
const internal2 = get().internal;
|
|
869
|
+
if (internal2?.subscribers) {
|
|
870
|
+
internal2.priority = internal2.priority - (priority > 0 ? 1 : 0);
|
|
871
|
+
internal2.subscribers = internal2.subscribers.filter((s) => s.ref !== ref);
|
|
872
|
+
}
|
|
873
|
+
};
|
|
874
|
+
},
|
|
875
|
+
// Renderer Storage (single source of truth)
|
|
876
|
+
actualRenderer: null,
|
|
877
|
+
// The renderer support configure() loads for this root
|
|
878
|
+
support: null,
|
|
879
|
+
// Scheduler for useFrameNext (initialized in loop.ts)
|
|
880
|
+
scheduler: null,
|
|
881
|
+
// Replaces the default render call when set (see setRenderOverride)
|
|
882
|
+
renderOverride: null
|
|
869
883
|
}
|
|
870
884
|
};
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
const
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
opts = widthOrOptions;
|
|
885
|
-
} else if (typeof widthOrOptions === "number") {
|
|
886
|
-
width = widthOrOptions;
|
|
887
|
-
if (typeof heightOrOptions === "object") {
|
|
888
|
-
height = widthOrOptions;
|
|
889
|
-
opts = heightOrOptions;
|
|
890
|
-
} else if (typeof heightOrOptions === "number") {
|
|
891
|
-
height = heightOrOptions;
|
|
892
|
-
opts = options;
|
|
893
|
-
} else {
|
|
894
|
-
height = widthOrOptions;
|
|
885
|
+
return rootState;
|
|
886
|
+
});
|
|
887
|
+
const state = rootStore.getState();
|
|
888
|
+
defineRendererAccessors(state);
|
|
889
|
+
let oldScene = state.scene;
|
|
890
|
+
rootStore.subscribe(() => {
|
|
891
|
+
const currentState = rootStore.getState();
|
|
892
|
+
const { scene, rootScene, set } = currentState;
|
|
893
|
+
if (scene !== oldScene) {
|
|
894
|
+
oldScene = scene;
|
|
895
|
+
if (scene?.isScene && scene !== rootScene) {
|
|
896
|
+
set({ rootScene: scene });
|
|
897
|
+
}
|
|
895
898
|
}
|
|
896
|
-
}
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
};
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
const
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
let pending = pendingLoaders.get(format);
|
|
925
|
-
if (!pending) {
|
|
926
|
-
pending = importLoader(format).then(
|
|
927
|
-
(loader) => {
|
|
928
|
-
loadedLoaders.set(format, loader);
|
|
929
|
-
return loader;
|
|
930
|
-
},
|
|
931
|
-
(error) => {
|
|
932
|
-
pendingLoaders.delete(format);
|
|
933
|
-
throw error;
|
|
899
|
+
});
|
|
900
|
+
let oldSize = state.size;
|
|
901
|
+
let oldDpr = state.viewport.dpr;
|
|
902
|
+
let oldCamera = state.camera;
|
|
903
|
+
rootStore.subscribe(() => {
|
|
904
|
+
const { camera, size, viewport, set, internal } = rootStore.getState();
|
|
905
|
+
const actualRenderer = internal.actualRenderer;
|
|
906
|
+
const canvasTarget = internal.canvasTarget;
|
|
907
|
+
if (size.width !== oldSize.width || size.height !== oldSize.height || viewport.dpr !== oldDpr) {
|
|
908
|
+
oldSize = size;
|
|
909
|
+
oldDpr = viewport.dpr;
|
|
910
|
+
updateCamera(camera, size);
|
|
911
|
+
const resizeTarget = canvasTarget ?? actualRenderer;
|
|
912
|
+
if (viewport.dpr > 0) resizeTarget.setPixelRatio(viewport.dpr);
|
|
913
|
+
resizeTarget.setSize(size.width, size.height, false);
|
|
914
|
+
const activeTarget = actualRenderer.getCanvasTarget?.();
|
|
915
|
+
if (!canvasTarget || activeTarget !== canvasTarget) internal.canvasTargetSizeDirty = true;
|
|
916
|
+
}
|
|
917
|
+
if (camera !== oldCamera) {
|
|
918
|
+
oldCamera = camera;
|
|
919
|
+
const { rootScene } = rootStore.getState();
|
|
920
|
+
if (camera && rootScene && !camera.parent) {
|
|
921
|
+
rootScene.add(camera);
|
|
922
|
+
}
|
|
923
|
+
set((state2) => ({ viewport: { ...state2.viewport, ...state2.viewport.getCurrentViewport(camera) } }));
|
|
924
|
+
const currentState = rootStore.getState();
|
|
925
|
+
if (currentState.autoUpdateFrustum && camera) {
|
|
926
|
+
updateFrustum(camera, currentState.frustum);
|
|
934
927
|
}
|
|
935
|
-
);
|
|
936
|
-
pendingLoaders.set(format, pending);
|
|
937
|
-
}
|
|
938
|
-
return pending;
|
|
939
|
-
}
|
|
940
|
-
async function importLoader(format) {
|
|
941
|
-
let loader;
|
|
942
|
-
switch (format) {
|
|
943
|
-
case "cube":
|
|
944
|
-
loader = getThree().CubeTextureLoader;
|
|
945
|
-
break;
|
|
946
|
-
case "hdr-cube":
|
|
947
|
-
loader = (await import('three/examples/jsm/loaders/HDRCubeTextureLoader.js')).HDRCubeTextureLoader;
|
|
948
|
-
break;
|
|
949
|
-
case "hdr":
|
|
950
|
-
loader = (await import('three/examples/jsm/loaders/HDRLoader.js')).HDRLoader;
|
|
951
|
-
break;
|
|
952
|
-
case "exr":
|
|
953
|
-
loader = (await import('three/examples/jsm/loaders/EXRLoader.js')).EXRLoader;
|
|
954
|
-
break;
|
|
955
|
-
case "jpg":
|
|
956
|
-
loader = (await import('three/examples/jsm/loaders/UltraHDRLoader.js')).UltraHDRLoader;
|
|
957
|
-
break;
|
|
958
|
-
}
|
|
959
|
-
return loader;
|
|
960
|
-
}
|
|
961
|
-
const LOADER_KEY = Symbol("r3f-environment-loader");
|
|
962
|
-
function useEnvironmentLoader(format) {
|
|
963
|
-
return suspend(() => loadLoader(format), [LOADER_KEY, format]);
|
|
964
|
-
}
|
|
965
|
-
function useEnvironment({
|
|
966
|
-
files = defaultFiles,
|
|
967
|
-
path = "",
|
|
968
|
-
preset = void 0,
|
|
969
|
-
colorSpace = void 0,
|
|
970
|
-
extensions
|
|
971
|
-
} = {}) {
|
|
972
|
-
if (preset) {
|
|
973
|
-
validatePreset(preset);
|
|
974
|
-
files = presetsObj[preset];
|
|
975
|
-
path = CUBEMAP_ROOT;
|
|
976
|
-
}
|
|
977
|
-
const multiFile = isArray(files);
|
|
978
|
-
const { format, isCubemap } = getFormat(files);
|
|
979
|
-
if (!format) throw new Error("useEnvironment: Unrecognized file extension: " + files);
|
|
980
|
-
const loader = useEnvironmentLoader(format);
|
|
981
|
-
const loaderResult = useLoader(
|
|
982
|
-
loader,
|
|
983
|
-
multiFile ? [files] : files,
|
|
984
|
-
(loader2) => {
|
|
985
|
-
loader2.setPath?.(path);
|
|
986
|
-
if (extensions) extensions(loader2);
|
|
987
928
|
}
|
|
988
|
-
);
|
|
989
|
-
const texture = multiFile ? (
|
|
990
|
-
// @ts-ignore
|
|
991
|
-
loaderResult[0]
|
|
992
|
-
) : loaderResult;
|
|
993
|
-
const three = getThree();
|
|
994
|
-
texture.mapping = isCubemap ? three.CubeReflectionMapping : three.EquirectangularReflectionMapping;
|
|
995
|
-
texture.colorSpace = colorSpace ?? (isCubemap && format !== "hdr-cube" ? "srgb" : "srgb-linear");
|
|
996
|
-
return texture;
|
|
997
|
-
}
|
|
998
|
-
const preloadDefaultOptions = {
|
|
999
|
-
files: defaultFiles,
|
|
1000
|
-
path: "",
|
|
1001
|
-
preset: void 0,
|
|
1002
|
-
extensions: void 0
|
|
1003
|
-
};
|
|
1004
|
-
useEnvironment.preload = (preloadOptions) => {
|
|
1005
|
-
const options = { ...preloadDefaultOptions, ...preloadOptions };
|
|
1006
|
-
let { files, path = "" } = options;
|
|
1007
|
-
const { preset, extensions } = options;
|
|
1008
|
-
if (preset) {
|
|
1009
|
-
validatePreset(preset);
|
|
1010
|
-
files = presetsObj[preset];
|
|
1011
|
-
path = CUBEMAP_ROOT;
|
|
1012
|
-
}
|
|
1013
|
-
const { format } = getFormat(files);
|
|
1014
|
-
if (!format) throw new Error("useEnvironment: Unrecognized file extension: " + files);
|
|
1015
|
-
const input = isArray(files) ? [files] : files;
|
|
1016
|
-
loadLoader(format).then((loader) => {
|
|
1017
|
-
useLoader.preload(loader, input, (loader2) => {
|
|
1018
|
-
loader2.setPath?.(path);
|
|
1019
|
-
if (extensions) extensions(loader2);
|
|
1020
|
-
});
|
|
1021
929
|
});
|
|
930
|
+
rootStore.subscribe((state2) => {
|
|
931
|
+
if (state2.internal.active) invalidate(state2);
|
|
932
|
+
});
|
|
933
|
+
return rootStore;
|
|
1022
934
|
};
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
const
|
|
1029
|
-
|
|
1030
|
-
const
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
clear(loader);
|
|
1042
|
-
} else {
|
|
1043
|
-
const pending = pendingLoaders.get(format);
|
|
1044
|
-
if (pending) void pending.then(clear, () => {
|
|
935
|
+
|
|
936
|
+
const shallowLoose$1 = { objects: "shallow", strict: false };
|
|
937
|
+
function configureScheduler(store, canvasId, schedulerConfig, previous) {
|
|
938
|
+
const state = store.getState();
|
|
939
|
+
const scheduler = getScheduler();
|
|
940
|
+
const rootId = state.internal.rootId;
|
|
941
|
+
const ordersItself = schedulerConfig?.before !== void 0 || schedulerConfig?.after !== void 0;
|
|
942
|
+
const rootBefore = schedulerConfig?.before;
|
|
943
|
+
const rootAfter = ordersItself ? schedulerConfig?.after : state.internal.sharedAfter;
|
|
944
|
+
if (!rootId) {
|
|
945
|
+
const newRootId = state.internal.pendingRootId ?? canvasId ?? scheduler.generateRootId();
|
|
946
|
+
const unregisterRoot = scheduler.registerRoot(newRootId, {
|
|
947
|
+
getState: () => store.getState(),
|
|
948
|
+
onError: (err) => store.getState().setError(err),
|
|
949
|
+
frameloop: store.getState().frameloop,
|
|
950
|
+
before: rootBefore,
|
|
951
|
+
after: rootAfter,
|
|
952
|
+
order: schedulerConfig?.order
|
|
1045
953
|
});
|
|
954
|
+
const unregisterCanvasTarget = scheduler.register(
|
|
955
|
+
() => {
|
|
956
|
+
const state2 = store.getState();
|
|
957
|
+
const canvasTarget = state2.internal.canvasTarget;
|
|
958
|
+
if (canvasTarget) {
|
|
959
|
+
const renderer = state2.internal.actualRenderer;
|
|
960
|
+
if (renderer.getCanvasTarget() !== canvasTarget) renderer.setCanvasTarget(canvasTarget);
|
|
961
|
+
if (state2.internal.canvasTargetSizeDirty) {
|
|
962
|
+
state2.internal.canvasTargetSizeDirty = false;
|
|
963
|
+
renderer.backend?.updateSize?.();
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
},
|
|
967
|
+
{
|
|
968
|
+
id: `${newRootId}_canvasTarget`,
|
|
969
|
+
rootId: newRootId,
|
|
970
|
+
phase: "start",
|
|
971
|
+
system: true
|
|
972
|
+
}
|
|
973
|
+
);
|
|
974
|
+
const unregisterEventsFlush = scheduler.register(
|
|
975
|
+
() => {
|
|
976
|
+
const state2 = store.getState();
|
|
977
|
+
state2.events.flush?.();
|
|
978
|
+
},
|
|
979
|
+
{
|
|
980
|
+
id: `${newRootId}_events`,
|
|
981
|
+
rootId: newRootId,
|
|
982
|
+
phase: "input",
|
|
983
|
+
system: true
|
|
984
|
+
}
|
|
985
|
+
);
|
|
986
|
+
const unregisterFrustum = scheduler.register(
|
|
987
|
+
() => {
|
|
988
|
+
const state2 = store.getState();
|
|
989
|
+
if (state2.autoUpdateFrustum && state2.camera) {
|
|
990
|
+
updateFrustum(state2.camera, state2.frustum);
|
|
991
|
+
}
|
|
992
|
+
},
|
|
993
|
+
{
|
|
994
|
+
id: `${newRootId}_frustum`,
|
|
995
|
+
rootId: newRootId,
|
|
996
|
+
before: "render",
|
|
997
|
+
system: true
|
|
998
|
+
}
|
|
999
|
+
);
|
|
1000
|
+
const unregisterVisibility = scheduler.register(
|
|
1001
|
+
() => {
|
|
1002
|
+
const state2 = store.getState();
|
|
1003
|
+
checkVisibility(state2);
|
|
1004
|
+
},
|
|
1005
|
+
{
|
|
1006
|
+
id: `${newRootId}_visibility`,
|
|
1007
|
+
rootId: newRootId,
|
|
1008
|
+
before: "render",
|
|
1009
|
+
system: true,
|
|
1010
|
+
after: `${newRootId}_frustum`
|
|
1011
|
+
}
|
|
1012
|
+
);
|
|
1013
|
+
const unregisterRender = scheduler.register(
|
|
1014
|
+
() => {
|
|
1015
|
+
const state2 = store.getState();
|
|
1016
|
+
const renderer = state2.internal.actualRenderer;
|
|
1017
|
+
const userHandlesRender = scheduler.hasUserJobsInPhase("render", newRootId);
|
|
1018
|
+
if (userHandlesRender || state2.internal.priority) return;
|
|
1019
|
+
try {
|
|
1020
|
+
const renderOverride = state2.internal.renderOverride;
|
|
1021
|
+
if (renderOverride) renderOverride();
|
|
1022
|
+
else if (renderer?.render) renderer.render(state2.scene, state2.camera);
|
|
1023
|
+
} catch (error) {
|
|
1024
|
+
state2.setError(error instanceof Error ? error : new Error(String(error)));
|
|
1025
|
+
}
|
|
1026
|
+
},
|
|
1027
|
+
{
|
|
1028
|
+
// Use canvas ID directly as job ID if available, otherwise use generated rootId
|
|
1029
|
+
id: canvasId || `${newRootId}_render`,
|
|
1030
|
+
rootId: newRootId,
|
|
1031
|
+
phase: "render",
|
|
1032
|
+
system: true,
|
|
1033
|
+
// Internal flag: this is a system job, not user-controlled
|
|
1034
|
+
// FPS throttles only the default render job; Canvas ordering belongs to the root.
|
|
1035
|
+
...schedulerConfig?.fps && { fps: schedulerConfig.fps }
|
|
1036
|
+
}
|
|
1037
|
+
);
|
|
1038
|
+
state.set((state2) => ({
|
|
1039
|
+
internal: {
|
|
1040
|
+
...state2.internal,
|
|
1041
|
+
rootId: newRootId,
|
|
1042
|
+
pendingRootId: void 0,
|
|
1043
|
+
unregisterRoot: () => {
|
|
1044
|
+
unregisterRoot();
|
|
1045
|
+
unregisterCanvasTarget();
|
|
1046
|
+
unregisterEventsFlush();
|
|
1047
|
+
unregisterFrustum();
|
|
1048
|
+
unregisterVisibility();
|
|
1049
|
+
unregisterRender();
|
|
1050
|
+
},
|
|
1051
|
+
scheduler
|
|
1052
|
+
}
|
|
1053
|
+
}));
|
|
1054
|
+
} else {
|
|
1055
|
+
const constraintsChanged = !is.equ(schedulerConfig?.before, previous?.before, shallowLoose$1) || !is.equ(schedulerConfig?.after, previous?.after, shallowLoose$1);
|
|
1056
|
+
if (constraintsChanged) {
|
|
1057
|
+
scheduler.setRootConstraints(rootId, {
|
|
1058
|
+
before: rootBefore,
|
|
1059
|
+
after: rootAfter
|
|
1060
|
+
});
|
|
1061
|
+
}
|
|
1062
|
+
if (schedulerConfig?.order !== previous?.order) {
|
|
1063
|
+
scheduler.setRootOrder(rootId, schedulerConfig?.order ?? 0);
|
|
1064
|
+
}
|
|
1046
1065
|
}
|
|
1047
|
-
};
|
|
1048
|
-
function validatePreset(preset) {
|
|
1049
|
-
if (!(preset in presetsObj)) throw new Error("Preset must be one of: " + Object.keys(presetsObj).join(", "));
|
|
1050
|
-
}
|
|
1051
|
-
function getFormat(files) {
|
|
1052
|
-
const isCubemap = isArray(files) && files.length === 6;
|
|
1053
|
-
const firstEntry = isArray(files) ? files[0] : files;
|
|
1054
|
-
const firstExtension = firstEntry.split(".").pop()?.split("?")?.shift()?.toLowerCase();
|
|
1055
|
-
let format;
|
|
1056
|
-
if (isCubemap) format = firstExtension === "hdr" ? "hdr-cube" : "cube";
|
|
1057
|
-
else if (firstEntry.startsWith("data:application/exr")) format = "exr";
|
|
1058
|
-
else if (firstEntry.startsWith("data:application/hdr")) format = "hdr";
|
|
1059
|
-
else if (firstEntry.startsWith("data:image/jpeg")) format = "jpg";
|
|
1060
|
-
else if (firstExtension === "hdr" || firstExtension === "exr") format = firstExtension;
|
|
1061
|
-
else if (firstExtension === "jpg" || firstExtension === "jpeg") format = "jpg";
|
|
1062
|
-
return { format, isCubemap };
|
|
1063
|
-
}
|
|
1064
|
-
|
|
1065
|
-
function useInstanceHandle(ref) {
|
|
1066
|
-
const instance = useRef(null);
|
|
1067
|
-
useImperativeHandle(instance, () => ref.current.__r3f, [ref]);
|
|
1068
|
-
return instance;
|
|
1069
1066
|
}
|
|
1070
|
-
function useGraph(object) {
|
|
1071
|
-
return useMemo(() => buildGraph(object), [object]);
|
|
1072
|
-
}
|
|
1073
|
-
|
|
1074
1067
|
let effectId = 0;
|
|
1075
1068
|
function addEffect(callback) {
|
|
1076
1069
|
notifyDepreciated({
|
|
@@ -1111,33 +1104,817 @@ function advance(timestamp, runGlobalEffects, state) {
|
|
|
1111
1104
|
else scheduler.step(timestamp);
|
|
1112
1105
|
}
|
|
1113
1106
|
|
|
1114
|
-
const
|
|
1115
|
-
const
|
|
1116
|
-
|
|
1107
|
+
const isPromiseLike = (value) => typeof value?.then === "function";
|
|
1108
|
+
const fulfilled = (value) => Object.assign(Promise.resolve(value), { status: "fulfilled", value });
|
|
1109
|
+
const rejected = (reason) => {
|
|
1110
|
+
const promise = Promise.reject(reason);
|
|
1111
|
+
promise.catch(() => {
|
|
1112
|
+
});
|
|
1113
|
+
return Object.assign(promise, { status: "rejected", reason });
|
|
1114
|
+
};
|
|
1115
|
+
const deferred = () => {
|
|
1116
|
+
let resolve;
|
|
1117
|
+
let reject;
|
|
1118
|
+
const promise = new Promise((yes, no) => {
|
|
1119
|
+
resolve = (value) => {
|
|
1120
|
+
Object.assign(promise, { status: "fulfilled", value });
|
|
1121
|
+
yes(value);
|
|
1122
|
+
};
|
|
1123
|
+
reject = (reason) => {
|
|
1124
|
+
Object.assign(promise, { status: "rejected", reason });
|
|
1125
|
+
no(reason);
|
|
1126
|
+
};
|
|
1127
|
+
});
|
|
1128
|
+
promise.status = "pending";
|
|
1129
|
+
promise.catch(() => {
|
|
1130
|
+
});
|
|
1131
|
+
return { promise, resolve, reject };
|
|
1132
|
+
};
|
|
1133
|
+
function resolveThen(value, apply) {
|
|
1134
|
+
return isPromiseLike(value) ? Promise.resolve(value).then(apply) : apply(value);
|
|
1135
|
+
}
|
|
1117
1136
|
|
|
1118
|
-
|
|
1119
|
-
|
|
1137
|
+
const isRenderer = (def) => !!def?.render;
|
|
1138
|
+
function ensureStoreThreeObjects(store) {
|
|
1139
|
+
const state = store.getState();
|
|
1140
|
+
if (state.pointer) return;
|
|
1141
|
+
const { Vector2, Frustum } = getThree();
|
|
1142
|
+
const pointer = new Vector2();
|
|
1143
|
+
state.set({ pointer, mouse: pointer, frustum: new Frustum() });
|
|
1120
1144
|
}
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1145
|
+
const R3F_RENDERER_SETTINGS = ["textureColorSpace", "shadows"];
|
|
1146
|
+
const NON_APPLIED_RENDERER_PROPS = /* @__PURE__ */ new Set([
|
|
1147
|
+
...R3F_RENDERER_SETTINGS,
|
|
1148
|
+
"canvas",
|
|
1149
|
+
"antialias",
|
|
1150
|
+
"alpha",
|
|
1151
|
+
"samples",
|
|
1152
|
+
"powerPreference",
|
|
1153
|
+
"depth",
|
|
1154
|
+
"stencil",
|
|
1155
|
+
"logarithmicDepthBuffer",
|
|
1156
|
+
"reversedDepthBuffer",
|
|
1157
|
+
// WebGPURenderer only
|
|
1158
|
+
"forceWebGL",
|
|
1159
|
+
"outputBufferType",
|
|
1160
|
+
"multiview",
|
|
1161
|
+
"getFallback",
|
|
1162
|
+
"trackTimestamp"
|
|
1163
|
+
]);
|
|
1164
|
+
function settingsBag(config) {
|
|
1165
|
+
return is.obj(config) && !isRenderer(config) ? config : void 0;
|
|
1166
|
+
}
|
|
1167
|
+
function isInstanceOrFactory(config) {
|
|
1168
|
+
return is.fun(config) || isRenderer(config);
|
|
1169
|
+
}
|
|
1170
|
+
function assertNoRemovedConfig(props) {
|
|
1171
|
+
if (props.primaryCanvas !== void 0) {
|
|
1172
|
+
throw new Error(
|
|
1173
|
+
'R3F: `primaryCanvas` was removed: mark the owner <Canvas primary> and other canvases share it automatically (or use share="id")'
|
|
1174
|
+
);
|
|
1175
|
+
}
|
|
1176
|
+
if (props.shadows !== void 0) {
|
|
1177
|
+
throw new Error(
|
|
1178
|
+
"R3F: the `shadows` Canvas prop moved into the renderer settings: use `renderer={{ shadows }}` (or `gl={{ shadows }}` for WebGL and @react-three/fiber/legacy)"
|
|
1179
|
+
);
|
|
1180
|
+
}
|
|
1181
|
+
for (const name of ["renderer", "gl"]) {
|
|
1182
|
+
const bag = settingsBag(props[name]);
|
|
1183
|
+
if (!bag) continue;
|
|
1184
|
+
if ("primaryCanvas" in bag) {
|
|
1185
|
+
throw new Error(
|
|
1186
|
+
`R3F: \`${name}={{ primaryCanvas }}\` was removed: mark the owner <Canvas primary> and other canvases share it automatically (or use share="id")`
|
|
1187
|
+
);
|
|
1188
|
+
}
|
|
1189
|
+
if ("scheduler" in bag) {
|
|
1190
|
+
throw new Error(`R3F: \`${name}={{ scheduler }}\` moved to <Canvas scheduler>`);
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
function resolveRenderer(config, defaultProps, RendererClass) {
|
|
1195
|
+
if (typeof config === "function") {
|
|
1196
|
+
return resolveThen(config(defaultProps), (renderer) => ({
|
|
1197
|
+
renderer,
|
|
1198
|
+
owned: true
|
|
1199
|
+
}));
|
|
1200
|
+
}
|
|
1201
|
+
if (isRenderer(config)) return { renderer: config, owned: false };
|
|
1202
|
+
const params = { ...defaultProps };
|
|
1203
|
+
for (const key in settingsBag(config)) if (!R3F_RENDERER_SETTINGS.includes(key)) params[key] = config[key];
|
|
1204
|
+
return { renderer: new RendererClass(params), owned: true };
|
|
1205
|
+
}
|
|
1206
|
+
function createOwnedWebGPURenderer(rendererConfig, defaultGPUProps, canvas, propsSize, dpr, support) {
|
|
1207
|
+
return resolveThen(resolveRenderer(rendererConfig, defaultGPUProps, support.Renderer), (resolved) => {
|
|
1208
|
+
const renderer = resolved.renderer;
|
|
1209
|
+
if (!renderer.hasInitialized?.()) {
|
|
1210
|
+
const size = computeInitialSize(canvas, propsSize);
|
|
1211
|
+
if (size.width > 0 && size.height > 0) {
|
|
1212
|
+
renderer.setPixelRatio(calculateDpr(dpr));
|
|
1213
|
+
renderer.setSize(size.width, size.height, false);
|
|
1137
1214
|
}
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1215
|
+
return resolveThen(renderer.init(), () => ({ renderer, owned: resolved.owned }));
|
|
1216
|
+
}
|
|
1217
|
+
return { renderer, owned: resolved.owned };
|
|
1218
|
+
});
|
|
1219
|
+
}
|
|
1220
|
+
function initializeRenderer(canvas, provider, store, props) {
|
|
1221
|
+
const {
|
|
1222
|
+
id: canvasId,
|
|
1223
|
+
primary = false,
|
|
1224
|
+
share,
|
|
1225
|
+
gl: glConfig,
|
|
1226
|
+
renderer: rendererConfig,
|
|
1227
|
+
size: propsSize,
|
|
1228
|
+
dpr = [1, 2],
|
|
1229
|
+
_primaryToken
|
|
1230
|
+
} = props;
|
|
1231
|
+
assertNoRemovedConfig(props);
|
|
1232
|
+
const rendererBag = settingsBag(rendererConfig);
|
|
1233
|
+
const state = store.getState();
|
|
1234
|
+
const { webgl, webgpu } = provider;
|
|
1235
|
+
const defaultGLProps = {
|
|
1236
|
+
canvas,
|
|
1237
|
+
powerPreference: "high-performance",
|
|
1238
|
+
antialias: true,
|
|
1239
|
+
alpha: true
|
|
1240
|
+
};
|
|
1241
|
+
const defaultGPUProps = {
|
|
1242
|
+
canvas,
|
|
1243
|
+
antialias: true
|
|
1244
|
+
};
|
|
1245
|
+
if (glConfig && !webgl) {
|
|
1246
|
+
throw new Error(
|
|
1247
|
+
"R3F: the `gl` prop configures WebGLRenderer, which is only available on @react-three/fiber/legacy. Import Canvas from @react-three/fiber/legacy to keep WebGL, or move these settings to the `renderer` prop for WebGPU."
|
|
1248
|
+
);
|
|
1249
|
+
}
|
|
1250
|
+
if (rendererConfig && !webgpu) {
|
|
1251
|
+
throw new Error(
|
|
1252
|
+
"WebGPURenderer (renderer prop) is not available on this entry. Use @react-three/fiber or @react-three/fiber/webgpu instead."
|
|
1253
|
+
);
|
|
1254
|
+
}
|
|
1255
|
+
if (glConfig && rendererConfig) {
|
|
1256
|
+
throw new Error("Cannot use both gl and renderer props at the same time");
|
|
1257
|
+
}
|
|
1258
|
+
if (primary && !webgpu) {
|
|
1259
|
+
throw new Error(
|
|
1260
|
+
"R3F: <Canvas primary> shares a WebGPU renderer and is not available on this entry. Use @react-three/fiber or @react-three/fiber/webgpu instead."
|
|
1261
|
+
);
|
|
1262
|
+
}
|
|
1263
|
+
if (primary && glConfig) {
|
|
1264
|
+
throw new Error(
|
|
1265
|
+
"R3F: <Canvas primary> shares a WebGPU renderer and cannot be used with WebGL. Remove the `gl` prop or use the `renderer` prop."
|
|
1266
|
+
);
|
|
1267
|
+
}
|
|
1268
|
+
if (primary && is.str(share)) {
|
|
1269
|
+
throw new Error(`R3F: a <Canvas primary> owns its renderer; remove share="${share}" from it.`);
|
|
1270
|
+
}
|
|
1271
|
+
if (is.str(share)) {
|
|
1272
|
+
if (!webgpu || glConfig) {
|
|
1273
|
+
throw new Error(
|
|
1274
|
+
`R3F: share="${share}" borrows a WebGPU renderer and cannot be used with WebGL. Remove the \`gl\` prop, or use @react-three/fiber or @react-three/fiber/webgpu.`
|
|
1275
|
+
);
|
|
1276
|
+
}
|
|
1277
|
+
if (isInstanceOrFactory(rendererConfig)) {
|
|
1278
|
+
throw new Error(
|
|
1279
|
+
`R3F: share="${share}" borrows the primary's renderer, so it cannot be combined with a renderer instance or factory. Remove one of the two.`
|
|
1280
|
+
);
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
const primaryKey = canvasId || DEFAULT_PRIMARY;
|
|
1284
|
+
const primaryToken = _primaryToken ?? store;
|
|
1285
|
+
if (primary && !state.internal.actualRenderer) {
|
|
1286
|
+
announcePrimary(primaryKey, primaryToken);
|
|
1287
|
+
state.internal.unregisterPrimary = () => withdrawPrimary(primaryKey, primaryToken);
|
|
1288
|
+
if (primaryConflict(primaryKey, primaryToken)) {
|
|
1289
|
+
throw new Error(
|
|
1290
|
+
primaryKey === DEFAULT_PRIMARY ? 'R3F: two <Canvas primary> are mounted without ids. Give each primary a distinct `id`, and point the other canvases at one with share="id".' : `R3F: two <Canvas primary> use the id "${primaryKey}". Give each primary a distinct \`id\`.`
|
|
1291
|
+
);
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
let shareKey;
|
|
1295
|
+
if (!state.internal.actualRenderer && webgpu && !primary && !glConfig && !state.isLegacy) {
|
|
1296
|
+
if (is.str(share)) {
|
|
1297
|
+
shareKey = share;
|
|
1298
|
+
} else if (share !== false && !isInstanceOrFactory(rendererConfig)) {
|
|
1299
|
+
const live = livePrimaryKeys();
|
|
1300
|
+
if (live.length > 1) {
|
|
1301
|
+
throw new Error(
|
|
1302
|
+
`R3F: ${live.length} primaries are mounted (${live.map(describePrimary).join(", ")}), so this canvas cannot pick one to share. Pass share="id" to name one, or share={false} for its own renderer.`
|
|
1303
|
+
);
|
|
1304
|
+
}
|
|
1305
|
+
shareKey = live[0];
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
const explicitShare = is.str(share);
|
|
1309
|
+
const wantsGL = !!webgl && (state.isLegacy || !!glConfig || !webgpu || !rendererConfig && !primary && shareKey === void 0);
|
|
1310
|
+
let renderer = state.internal.actualRenderer;
|
|
1311
|
+
if (!state.internal.actualRenderer) {
|
|
1312
|
+
return resolveThen(wantsGL ? webgl() : webgpu(), (support) => {
|
|
1313
|
+
registerThree(support.three);
|
|
1314
|
+
state.internal.support = support;
|
|
1315
|
+
ensureStoreThreeObjects(store);
|
|
1316
|
+
if (support.kind === "webgl") {
|
|
1317
|
+
return resolveThen(resolveRenderer(glConfig, defaultGLProps, support.Renderer), (resolved) => {
|
|
1318
|
+
renderer = resolved.renderer;
|
|
1319
|
+
state.internal.actualRenderer = renderer;
|
|
1320
|
+
state.internal.releaseRenderer = leaseRenderer(renderer, resolved.owned);
|
|
1321
|
+
state.set({ isLegacy: true, gl: renderer, renderer, primaryStore: store });
|
|
1322
|
+
});
|
|
1323
|
+
}
|
|
1324
|
+
const primaryReady = shareKey === void 0 ? null : explicitShare ? waitForPrimary(shareKey) : waitForAnnouncedPrimary(shareKey);
|
|
1325
|
+
return resolveThen(primaryReady, (primaryEntry) => {
|
|
1326
|
+
if (primaryEntry && primaryEntry.store.getState().webGPUSupported) {
|
|
1327
|
+
renderer = primaryEntry.renderer;
|
|
1328
|
+
state.internal.actualRenderer = renderer;
|
|
1329
|
+
state.internal.releaseRenderer = borrowRenderer(renderer);
|
|
1330
|
+
state.internal.sharedAfter = primaryEntry.rootId;
|
|
1331
|
+
const canvasTarget = new support.CanvasTarget(canvas);
|
|
1332
|
+
primaryEntry.store.setState((prev) => ({
|
|
1333
|
+
internal: { ...prev.internal, isMultiCanvas: true }
|
|
1334
|
+
}));
|
|
1335
|
+
state.set((prev) => ({
|
|
1336
|
+
webGPUSupported: primaryEntry.store.getState().webGPUSupported,
|
|
1337
|
+
renderer,
|
|
1338
|
+
primaryStore: primaryEntry.store,
|
|
1339
|
+
internal: {
|
|
1340
|
+
...prev.internal,
|
|
1341
|
+
canvasTarget,
|
|
1342
|
+
isMultiCanvas: true,
|
|
1343
|
+
isSecondary: true,
|
|
1344
|
+
targetId: shareKey === DEFAULT_PRIMARY ? void 0 : shareKey
|
|
1345
|
+
}
|
|
1346
|
+
}));
|
|
1347
|
+
return;
|
|
1348
|
+
}
|
|
1349
|
+
if (primaryEntry) {
|
|
1350
|
+
return resolveThen(
|
|
1351
|
+
createOwnedWebGPURenderer(
|
|
1352
|
+
{ ...rendererBag, forceWebGL: true },
|
|
1353
|
+
defaultGPUProps,
|
|
1354
|
+
canvas,
|
|
1355
|
+
propsSize,
|
|
1356
|
+
dpr,
|
|
1357
|
+
support
|
|
1358
|
+
),
|
|
1359
|
+
(resolved) => {
|
|
1360
|
+
renderer = resolved.renderer;
|
|
1361
|
+
const backend = renderer.backend;
|
|
1362
|
+
const isWebGPUBackend = backend && "isWebGPUBackend" in backend;
|
|
1363
|
+
state.internal.actualRenderer = renderer;
|
|
1364
|
+
state.internal.releaseRenderer = leaseRenderer(renderer, resolved.owned);
|
|
1365
|
+
state.set((prev) => ({
|
|
1366
|
+
webGPUSupported: isWebGPUBackend,
|
|
1367
|
+
renderer,
|
|
1368
|
+
primaryStore: store,
|
|
1369
|
+
internal: {
|
|
1370
|
+
...prev.internal,
|
|
1371
|
+
canvasTarget: renderer.getCanvasTarget?.(),
|
|
1372
|
+
sharedRendererFallback: true
|
|
1373
|
+
}
|
|
1374
|
+
}));
|
|
1375
|
+
}
|
|
1376
|
+
);
|
|
1377
|
+
}
|
|
1378
|
+
return resolveThen(
|
|
1379
|
+
createOwnedWebGPURenderer(rendererConfig, defaultGPUProps, canvas, propsSize, dpr, support),
|
|
1380
|
+
(resolved) => {
|
|
1381
|
+
var _a;
|
|
1382
|
+
renderer = resolved.renderer;
|
|
1383
|
+
const backend = renderer.backend;
|
|
1384
|
+
const isWebGPUBackend = backend && "isWebGPUBackend" in backend;
|
|
1385
|
+
state.internal.actualRenderer = renderer;
|
|
1386
|
+
state.internal.releaseRenderer = leaseRenderer(renderer, resolved.owned);
|
|
1387
|
+
state.set({ webGPUSupported: isWebGPUBackend, renderer, primaryStore: store });
|
|
1388
|
+
if (primary) {
|
|
1389
|
+
const canvasTarget = renderer.getCanvasTarget?.();
|
|
1390
|
+
(_a = state.internal).pendingRootId ?? (_a.pendingRootId = canvasId || getScheduler().generateRootId());
|
|
1391
|
+
registerPrimary(primaryKey, renderer, store, {
|
|
1392
|
+
token: primaryToken,
|
|
1393
|
+
rootId: state.internal.pendingRootId
|
|
1394
|
+
});
|
|
1395
|
+
state.set((prev) => ({ internal: { ...prev.internal, canvasTarget } }));
|
|
1396
|
+
} else if (share !== false && !isInstanceOrFactory(rendererConfig)) {
|
|
1397
|
+
state.internal.untrackStandalone = trackStandalone(store);
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
);
|
|
1401
|
+
});
|
|
1402
|
+
});
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
const records = /* @__PURE__ */ new WeakMap();
|
|
1406
|
+
function take(renderer, record) {
|
|
1407
|
+
record.leases++;
|
|
1408
|
+
let released = false;
|
|
1409
|
+
return () => {
|
|
1410
|
+
if (released) return;
|
|
1411
|
+
released = true;
|
|
1412
|
+
if (--record.leases > 0) return;
|
|
1413
|
+
records.delete(renderer);
|
|
1414
|
+
if (record.owned) return disposeRenderer(renderer);
|
|
1415
|
+
};
|
|
1416
|
+
}
|
|
1417
|
+
function leaseRenderer(renderer, owned) {
|
|
1418
|
+
let record = records.get(renderer);
|
|
1419
|
+
if (!record) records.set(renderer, record = { owned, leases: 0 });
|
|
1420
|
+
return take(renderer, record);
|
|
1421
|
+
}
|
|
1422
|
+
function borrowRenderer(renderer) {
|
|
1423
|
+
const record = records.get(renderer);
|
|
1424
|
+
if (!record) throw new Error("R3F: cannot share a renderer whose canvas has already unmounted");
|
|
1425
|
+
return take(renderer, record);
|
|
1426
|
+
}
|
|
1427
|
+
function disposeRenderer(renderer) {
|
|
1428
|
+
if (renderer.hasInitialized?.() === false) return;
|
|
1429
|
+
const warn = (error) => console.warn("[R3F] Error disposing renderer", error);
|
|
1430
|
+
const loseContext = () => {
|
|
1431
|
+
try {
|
|
1432
|
+
;
|
|
1433
|
+
renderer.forceContextLoss?.();
|
|
1434
|
+
} catch (error) {
|
|
1435
|
+
warn(error);
|
|
1436
|
+
}
|
|
1437
|
+
};
|
|
1438
|
+
let disposed;
|
|
1439
|
+
try {
|
|
1440
|
+
disposed = renderer.dispose ? renderer.dispose() : renderer.renderLists?.dispose?.();
|
|
1441
|
+
} catch (error) {
|
|
1442
|
+
warn(error);
|
|
1443
|
+
}
|
|
1444
|
+
if (typeof disposed?.then === "function") {
|
|
1445
|
+
return Promise.resolve(disposed).then(loseContext, (error) => {
|
|
1446
|
+
warn(error);
|
|
1447
|
+
loseContext();
|
|
1448
|
+
});
|
|
1449
|
+
}
|
|
1450
|
+
loseContext();
|
|
1451
|
+
}
|
|
1452
|
+
const DEFAULT_PRIMARY = "\0r3f:primary";
|
|
1453
|
+
const primaryRegistry = /* @__PURE__ */ new Map();
|
|
1454
|
+
const announcements = /* @__PURE__ */ new Map();
|
|
1455
|
+
const withdrawing = /* @__PURE__ */ new Set();
|
|
1456
|
+
const pendingSubscribers = /* @__PURE__ */ new Map();
|
|
1457
|
+
const standaloneRoots = /* @__PURE__ */ new Set();
|
|
1458
|
+
const warnedLatePrimary = /* @__PURE__ */ new WeakSet();
|
|
1459
|
+
function describePrimary(key) {
|
|
1460
|
+
return key === DEFAULT_PRIMARY ? "<Canvas primary>" : `<Canvas id="${key}" primary>`;
|
|
1461
|
+
}
|
|
1462
|
+
function notify(key, entry) {
|
|
1463
|
+
const subscribers = pendingSubscribers.get(key);
|
|
1464
|
+
if (!subscribers) return;
|
|
1465
|
+
pendingSubscribers.delete(key);
|
|
1466
|
+
subscribers.forEach((callback) => callback(entry));
|
|
1467
|
+
}
|
|
1468
|
+
function isLive(key) {
|
|
1469
|
+
const owners = announcements.get(key);
|
|
1470
|
+
if (owners) {
|
|
1471
|
+
for (const owner of owners) if (!withdrawing.has(owner)) return true;
|
|
1472
|
+
}
|
|
1473
|
+
const entry = primaryRegistry.get(key);
|
|
1474
|
+
return !!entry && !(entry.token && withdrawing.has(entry.token));
|
|
1475
|
+
}
|
|
1476
|
+
function announcePrimary(key, owner) {
|
|
1477
|
+
withdrawing.delete(owner);
|
|
1478
|
+
let owners = announcements.get(key);
|
|
1479
|
+
if (!owners) announcements.set(key, owners = /* @__PURE__ */ new Set());
|
|
1480
|
+
if (owners.has(owner)) return;
|
|
1481
|
+
owners.add(owner);
|
|
1482
|
+
if (standaloneRoots.size > 0 && !warnedLatePrimary.has(owner) && isDevelopment()) {
|
|
1483
|
+
warnedLatePrimary.add(owner);
|
|
1484
|
+
console.warn(
|
|
1485
|
+
`R3F: ${describePrimary(key)} mounted after ${standaloneRoots.size} other WebGPU canvas(es) had already created their own renderer; those keep it and do not share the primary. Mount the primary with or before the canvases that share it, or give them share="id" so they wait for it.`
|
|
1486
|
+
);
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
function markWithdrawing(owner) {
|
|
1490
|
+
withdrawing.add(owner);
|
|
1491
|
+
}
|
|
1492
|
+
function withdrawPrimary(key, owner) {
|
|
1493
|
+
withdrawing.delete(owner);
|
|
1494
|
+
const owners = announcements.get(key);
|
|
1495
|
+
if (owners) {
|
|
1496
|
+
owners.delete(owner);
|
|
1497
|
+
if (owners.size === 0) announcements.delete(key);
|
|
1498
|
+
}
|
|
1499
|
+
const entry = primaryRegistry.get(key);
|
|
1500
|
+
if (entry?.token === owner) primaryRegistry.delete(key);
|
|
1501
|
+
if (!isLive(key)) notify(key, null);
|
|
1502
|
+
}
|
|
1503
|
+
function primaryConflict(key, owner) {
|
|
1504
|
+
const owners = announcements.get(key);
|
|
1505
|
+
if (owners) {
|
|
1506
|
+
for (const other of owners) {
|
|
1507
|
+
if (other === owner) break;
|
|
1508
|
+
if (!withdrawing.has(other)) return true;
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
const entry = primaryRegistry.get(key);
|
|
1512
|
+
return !!entry && entry.token !== owner && !(entry.token && withdrawing.has(entry.token));
|
|
1513
|
+
}
|
|
1514
|
+
function livePrimaryKeys() {
|
|
1515
|
+
const keys = /* @__PURE__ */ new Set([...announcements.keys(), ...primaryRegistry.keys()]);
|
|
1516
|
+
return [...keys].filter(isLive);
|
|
1517
|
+
}
|
|
1518
|
+
function trackStandalone(owner) {
|
|
1519
|
+
standaloneRoots.add(owner);
|
|
1520
|
+
return () => {
|
|
1521
|
+
standaloneRoots.delete(owner);
|
|
1522
|
+
};
|
|
1523
|
+
}
|
|
1524
|
+
function registerPrimary(id, renderer, store, options = {}) {
|
|
1525
|
+
if (options.token && !announcements.get(id)?.has(options.token)) return () => {
|
|
1526
|
+
};
|
|
1527
|
+
if (primaryRegistry.has(id)) {
|
|
1528
|
+
console.warn(`Canvas with id="${id}" already registered. Overwriting.`);
|
|
1529
|
+
}
|
|
1530
|
+
const entry = { renderer, store, rootId: options.rootId, token: options.token };
|
|
1531
|
+
primaryRegistry.set(id, entry);
|
|
1532
|
+
notify(id, entry);
|
|
1533
|
+
return () => {
|
|
1534
|
+
const currentEntry = primaryRegistry.get(id);
|
|
1535
|
+
if (currentEntry?.renderer === renderer) {
|
|
1536
|
+
primaryRegistry.delete(id);
|
|
1537
|
+
}
|
|
1538
|
+
};
|
|
1539
|
+
}
|
|
1540
|
+
function getPrimary(id) {
|
|
1541
|
+
return primaryRegistry.get(id);
|
|
1542
|
+
}
|
|
1543
|
+
function subscribe(id, callback) {
|
|
1544
|
+
if (!pendingSubscribers.has(id)) pendingSubscribers.set(id, []);
|
|
1545
|
+
pendingSubscribers.get(id).push(callback);
|
|
1546
|
+
return () => {
|
|
1547
|
+
const subscribers = pendingSubscribers.get(id);
|
|
1548
|
+
if (!subscribers) return;
|
|
1549
|
+
const index = subscribers.indexOf(callback);
|
|
1550
|
+
if (index !== -1) subscribers.splice(index, 1);
|
|
1551
|
+
if (subscribers.length === 0) pendingSubscribers.delete(id);
|
|
1552
|
+
};
|
|
1553
|
+
}
|
|
1554
|
+
function waitForPrimary(id, timeout = 5e3) {
|
|
1555
|
+
const existing = primaryRegistry.get(id);
|
|
1556
|
+
if (existing) {
|
|
1557
|
+
return Promise.resolve(existing);
|
|
1558
|
+
}
|
|
1559
|
+
return new Promise((resolve, reject) => {
|
|
1560
|
+
let unsubscribe = () => {
|
|
1561
|
+
};
|
|
1562
|
+
const timeoutId = setTimeout(() => {
|
|
1563
|
+
unsubscribe();
|
|
1564
|
+
reject(
|
|
1565
|
+
new Error(
|
|
1566
|
+
`Timeout waiting for canvas with id="${id}". Make sure a <Canvas id="${id}" primary> is mounted for share="${id}".`
|
|
1567
|
+
)
|
|
1568
|
+
);
|
|
1569
|
+
}, timeout);
|
|
1570
|
+
const callback = (entry) => {
|
|
1571
|
+
if (!entry) {
|
|
1572
|
+
unsubscribe = subscribe(id, callback);
|
|
1573
|
+
return;
|
|
1574
|
+
}
|
|
1575
|
+
clearTimeout(timeoutId);
|
|
1576
|
+
resolve(entry);
|
|
1577
|
+
};
|
|
1578
|
+
unsubscribe = subscribe(id, callback);
|
|
1579
|
+
});
|
|
1580
|
+
}
|
|
1581
|
+
function waitForAnnouncedPrimary(key, timeout = 5e3) {
|
|
1582
|
+
const existing = primaryRegistry.get(key);
|
|
1583
|
+
if (existing && isLive(key)) return Promise.resolve(existing);
|
|
1584
|
+
if (!isLive(key)) return Promise.resolve(null);
|
|
1585
|
+
return new Promise((resolve, reject) => {
|
|
1586
|
+
const timeoutId = setTimeout(() => {
|
|
1587
|
+
unsubscribe();
|
|
1588
|
+
reject(
|
|
1589
|
+
new Error(
|
|
1590
|
+
`Timeout waiting for ${describePrimary(key)} to create its renderer. A canvas mounted next to it shares its renderer automatically; pass share={false} to give it its own.`
|
|
1591
|
+
)
|
|
1592
|
+
);
|
|
1593
|
+
}, timeout);
|
|
1594
|
+
const unsubscribe = subscribe(key, (entry) => {
|
|
1595
|
+
clearTimeout(timeoutId);
|
|
1596
|
+
resolve(entry);
|
|
1597
|
+
});
|
|
1598
|
+
});
|
|
1599
|
+
}
|
|
1600
|
+
function hasPrimary(id) {
|
|
1601
|
+
return primaryRegistry.has(id);
|
|
1602
|
+
}
|
|
1603
|
+
function unregisterPrimary(id) {
|
|
1604
|
+
primaryRegistry.delete(id);
|
|
1605
|
+
}
|
|
1606
|
+
function getPrimaryIds() {
|
|
1607
|
+
return Array.from(primaryRegistry.keys());
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
const shallowLoose = { objects: "shallow", strict: false };
|
|
1611
|
+
function watchDpr(onChange) {
|
|
1612
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function" || !window.devicePixelRatio) {
|
|
1613
|
+
return () => {
|
|
1614
|
+
};
|
|
1615
|
+
}
|
|
1616
|
+
let watching = true;
|
|
1617
|
+
let query;
|
|
1618
|
+
const listen = () => {
|
|
1619
|
+
try {
|
|
1620
|
+
query = window.matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`);
|
|
1621
|
+
if (typeof query?.addEventListener === "function") query.addEventListener("change", handleChange);
|
|
1622
|
+
else query?.addListener?.(handleChange);
|
|
1623
|
+
} catch {
|
|
1624
|
+
query = void 0;
|
|
1625
|
+
}
|
|
1626
|
+
};
|
|
1627
|
+
const unlisten = () => {
|
|
1628
|
+
if (typeof query?.removeEventListener === "function") query.removeEventListener("change", handleChange);
|
|
1629
|
+
else query?.removeListener?.(handleChange);
|
|
1630
|
+
query = void 0;
|
|
1631
|
+
};
|
|
1632
|
+
const handleChange = () => {
|
|
1633
|
+
if (!watching) return;
|
|
1634
|
+
unlisten();
|
|
1635
|
+
listen();
|
|
1636
|
+
onChange();
|
|
1637
|
+
};
|
|
1638
|
+
listen();
|
|
1639
|
+
return () => {
|
|
1640
|
+
watching = false;
|
|
1641
|
+
unlisten();
|
|
1642
|
+
};
|
|
1643
|
+
}
|
|
1644
|
+
function createRootConfiguration(store, canvas) {
|
|
1645
|
+
let previous;
|
|
1646
|
+
let lastCamera;
|
|
1647
|
+
const lastConfiguredProps = {};
|
|
1648
|
+
let resolvedDpr = 0;
|
|
1649
|
+
let dprChangedInXR = false;
|
|
1650
|
+
let unwatchDpr;
|
|
1651
|
+
const resolveDpr = () => {
|
|
1652
|
+
const state = store.getState();
|
|
1653
|
+
const xr = state.internal.actualRenderer?.xr;
|
|
1654
|
+
if (xr?.isPresenting || xr?.getSession?.()) {
|
|
1655
|
+
dprChangedInXR = true;
|
|
1656
|
+
return;
|
|
1657
|
+
}
|
|
1658
|
+
dprChangedInXR = false;
|
|
1659
|
+
const dpr = lastConfiguredProps.dpr;
|
|
1660
|
+
if (dpr === void 0 || state.viewport.dpr !== resolvedDpr || calculateDpr(dpr) === resolvedDpr) return;
|
|
1661
|
+
state.setDpr(dpr);
|
|
1662
|
+
resolvedDpr = store.getState().viewport.dpr;
|
|
1663
|
+
};
|
|
1664
|
+
let warnedSharedSettings = false;
|
|
1665
|
+
let configured = false;
|
|
1666
|
+
return (props) => {
|
|
1667
|
+
const {
|
|
1668
|
+
gl: glConfig,
|
|
1669
|
+
renderer: rendererConfig,
|
|
1670
|
+
size: propsSize,
|
|
1671
|
+
scene: sceneOptions,
|
|
1672
|
+
events,
|
|
1673
|
+
orthographic = false,
|
|
1674
|
+
frameloop = "always",
|
|
1675
|
+
dpr = [1, 2],
|
|
1676
|
+
performance,
|
|
1677
|
+
raycaster: raycastOptions,
|
|
1678
|
+
camera: cameraOptions,
|
|
1679
|
+
onPointerMissed,
|
|
1680
|
+
onDragOverMissed,
|
|
1681
|
+
onDropMissed,
|
|
1682
|
+
autoUpdateFrustum = true,
|
|
1683
|
+
occlusion = false,
|
|
1684
|
+
_sizeProps,
|
|
1685
|
+
forceEven
|
|
1686
|
+
} = props;
|
|
1687
|
+
assertNoRemovedConfig(props);
|
|
1688
|
+
const rendererBag = settingsBag(rendererConfig);
|
|
1689
|
+
const settings = settingsBag(glConfig) ?? rendererBag;
|
|
1690
|
+
const requestedTextureColorSpace = settings?.textureColorSpace || void 0;
|
|
1691
|
+
const shadows = isInstanceOrFactory(glConfig ?? rendererConfig) ? void 0 : settings?.shadows ?? false;
|
|
1692
|
+
const next = { ...props, shadows, frameloop, autoUpdateFrustum, occlusion };
|
|
1693
|
+
const last = previous;
|
|
1694
|
+
const changed = (key) => !last || !is.equ(next[key], last[key], { objects: "shallow" });
|
|
1695
|
+
previous = void 0;
|
|
1696
|
+
const state = store.getState();
|
|
1697
|
+
const renderer = state.internal.actualRenderer;
|
|
1698
|
+
const three = getThree();
|
|
1699
|
+
const borrowsRenderer = state.internal.isSecondary === true;
|
|
1700
|
+
if (borrowsRenderer && !warnedSharedSettings && rendererBag && Object.keys(rendererBag).some((key) => key !== "textureColorSpace") && isDevelopment()) {
|
|
1701
|
+
warnedSharedSettings = true;
|
|
1702
|
+
console.warn(
|
|
1703
|
+
"R3F: renderer settings on a sharing canvas are ignored; set them on the <Canvas primary>. This canvas borrows the primary's renderer, so renderer-wide settings come from the primary. Pass share={false} to give this canvas its own renderer."
|
|
1704
|
+
);
|
|
1705
|
+
}
|
|
1706
|
+
let raycaster = state.raycaster;
|
|
1707
|
+
if (!raycaster) state.set({ raycaster: raycaster = new three.Raycaster() });
|
|
1708
|
+
if (changed("raycaster")) {
|
|
1709
|
+
const { params, ...options } = raycastOptions || {};
|
|
1710
|
+
if (!is.equ(options, raycaster, shallowLoose)) applyProps(raycaster, { ...options });
|
|
1711
|
+
if (!is.equ(params, raycaster.params, shallowLoose)) {
|
|
1712
|
+
applyProps(raycaster, { params: { ...raycaster.params, ...params } });
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
let tempCamera = state.camera;
|
|
1716
|
+
if (!state.camera || state.camera === lastCamera && changed("camera")) {
|
|
1717
|
+
lastCamera = cameraOptions;
|
|
1718
|
+
const isCamera = cameraOptions?.isCamera;
|
|
1719
|
+
const camera = isCamera ? cameraOptions : orthographic ? new three.OrthographicCamera(0, 0, 0, 0, 0.1, 1e3) : new three.PerspectiveCamera(50, 0, 0.1, 1e3);
|
|
1720
|
+
if (!isCamera) {
|
|
1721
|
+
camera.position.z = 5;
|
|
1722
|
+
if (cameraOptions) {
|
|
1723
|
+
applyProps(camera, cameraOptions);
|
|
1724
|
+
if (!camera.manual) {
|
|
1725
|
+
const projectionProps = ["aspect", "left", "right", "bottom", "top"];
|
|
1726
|
+
if (projectionProps.some((prop) => prop in cameraOptions)) {
|
|
1727
|
+
camera.manual = true;
|
|
1728
|
+
camera.updateProjectionMatrix();
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
if (!state.camera && !cameraOptions?.rotation) camera.lookAt(0, 0, 0);
|
|
1733
|
+
}
|
|
1734
|
+
state.set({ camera });
|
|
1735
|
+
tempCamera = camera;
|
|
1736
|
+
raycaster.camera = camera;
|
|
1737
|
+
}
|
|
1738
|
+
if (!state.scene) {
|
|
1739
|
+
let scene;
|
|
1740
|
+
if (sceneOptions?.isScene) {
|
|
1741
|
+
scene = sceneOptions;
|
|
1742
|
+
prepare(scene, store, "", {});
|
|
1743
|
+
} else {
|
|
1744
|
+
scene = new three.Scene();
|
|
1745
|
+
prepare(scene, store, "", {});
|
|
1746
|
+
if (sceneOptions) applyProps(scene, sceneOptions);
|
|
1747
|
+
}
|
|
1748
|
+
state.set((prev) => ({
|
|
1749
|
+
scene,
|
|
1750
|
+
rootScene: scene,
|
|
1751
|
+
internal: { ...prev.internal, container: scene }
|
|
1752
|
+
}));
|
|
1753
|
+
const camera = tempCamera;
|
|
1754
|
+
if (camera && !camera.parent) scene.add(camera);
|
|
1755
|
+
}
|
|
1756
|
+
if (events && !state.events.handlers) {
|
|
1757
|
+
state.set({ events: events(store) });
|
|
1758
|
+
let wasEnabled = true;
|
|
1759
|
+
store.subscribe((state2) => {
|
|
1760
|
+
const { enabled } = state2.events;
|
|
1761
|
+
if (enabled && !wasEnabled) {
|
|
1762
|
+
state2.events.update?.();
|
|
1763
|
+
}
|
|
1764
|
+
wasEnabled = enabled;
|
|
1765
|
+
});
|
|
1766
|
+
}
|
|
1767
|
+
if (_sizeProps !== void 0 && changed("_sizeProps")) {
|
|
1768
|
+
state.set({ _sizeProps });
|
|
1769
|
+
}
|
|
1770
|
+
if (forceEven !== void 0 && state.internal.forceEven !== forceEven) {
|
|
1771
|
+
state.set((prev) => ({ internal: { ...prev.internal, forceEven } }));
|
|
1772
|
+
}
|
|
1773
|
+
configureSize(store, computeInitialSize(canvas, propsSize));
|
|
1774
|
+
if (dpr !== void 0 && (!last || !is.equ(dpr, lastConfiguredProps.dpr, shallowLoose))) {
|
|
1775
|
+
state.setDpr(dpr);
|
|
1776
|
+
lastConfiguredProps.dpr = dpr;
|
|
1777
|
+
resolvedDpr = store.getState().viewport.dpr;
|
|
1778
|
+
}
|
|
1779
|
+
const internal = store.getState().internal;
|
|
1780
|
+
if (Array.isArray(dpr) && (!unwatchDpr || internal.unwatchDpr !== unwatchDpr)) {
|
|
1781
|
+
internal.unwatchDpr?.();
|
|
1782
|
+
internal.unwatchDpr = unwatchDpr = watchDpr(resolveDpr);
|
|
1783
|
+
}
|
|
1784
|
+
resolveDpr();
|
|
1785
|
+
if (frameloop !== void 0 && changed("frameloop")) {
|
|
1786
|
+
state.setFrameloop(frameloop);
|
|
1787
|
+
}
|
|
1788
|
+
if (changed("onPointerMissed")) state.set({ onPointerMissed });
|
|
1789
|
+
if (changed("onDragOverMissed")) state.set({ onDragOverMissed });
|
|
1790
|
+
if (changed("onDropMissed")) state.set({ onDropMissed });
|
|
1791
|
+
if (changed("autoUpdateFrustum") && state.autoUpdateFrustum !== autoUpdateFrustum) {
|
|
1792
|
+
state.set({ autoUpdateFrustum });
|
|
1793
|
+
}
|
|
1794
|
+
if (occlusion && !state.internal.occlusionEnabled) {
|
|
1795
|
+
enableOcclusion(store);
|
|
1796
|
+
}
|
|
1797
|
+
if (performance && changed("performance")) {
|
|
1798
|
+
state.set((state2) => ({ performance: { ...state2.performance, ...performance } }));
|
|
1799
|
+
}
|
|
1800
|
+
if (!state.xr) {
|
|
1801
|
+
const handleXRFrame = (timestamp, _frame) => {
|
|
1802
|
+
const state2 = store.getState();
|
|
1803
|
+
if (state2.frameloop === "never") return;
|
|
1804
|
+
advance(timestamp, true, state2);
|
|
1805
|
+
};
|
|
1806
|
+
const actualRenderer = state.internal.actualRenderer;
|
|
1807
|
+
const handleSessionChange = () => {
|
|
1808
|
+
const state2 = store.getState();
|
|
1809
|
+
const renderer2 = state2.internal.actualRenderer;
|
|
1810
|
+
actualRenderer.xr.enabled = actualRenderer.xr.isPresenting;
|
|
1811
|
+
renderer2.xr.setAnimationLoop(renderer2.xr.isPresenting ? handleXRFrame : null);
|
|
1812
|
+
if (!renderer2.xr.isPresenting) {
|
|
1813
|
+
if (dprChangedInXR) resolveDpr();
|
|
1814
|
+
invalidate(state2);
|
|
1815
|
+
}
|
|
1816
|
+
};
|
|
1817
|
+
const xr = {
|
|
1818
|
+
connect() {
|
|
1819
|
+
const xrManager = store.getState().renderer.xr;
|
|
1820
|
+
xrManager.addEventListener("sessionstart", handleSessionChange);
|
|
1821
|
+
xrManager.addEventListener("sessionend", handleSessionChange);
|
|
1822
|
+
},
|
|
1823
|
+
disconnect() {
|
|
1824
|
+
const xrManager = store.getState().renderer.xr;
|
|
1825
|
+
xrManager.removeEventListener("sessionstart", handleSessionChange);
|
|
1826
|
+
xrManager.removeEventListener("sessionend", handleSessionChange);
|
|
1827
|
+
}
|
|
1828
|
+
};
|
|
1829
|
+
if (!borrowsRenderer && typeof renderer.xr?.addEventListener === "function") xr.connect();
|
|
1830
|
+
state.set({ xr });
|
|
1831
|
+
}
|
|
1832
|
+
if (!borrowsRenderer && shadows !== void 0 && renderer.shadowMap && changed("shadows")) {
|
|
1833
|
+
const oldEnabled = renderer.shadowMap.enabled;
|
|
1834
|
+
const oldType = renderer.shadowMap.type;
|
|
1835
|
+
renderer.shadowMap.enabled = !!shadows;
|
|
1836
|
+
if (is.boo(shadows)) {
|
|
1837
|
+
renderer.shadowMap.type = three.PCFShadowMap;
|
|
1838
|
+
} else if (is.str(shadows)) {
|
|
1839
|
+
if (shadows === "soft") {
|
|
1840
|
+
notifyDepreciated({
|
|
1841
|
+
heading: 'shadows="soft" is deprecated',
|
|
1842
|
+
body: "Three has depreciated soft and improved basic PCFShadows, we converted for you.",
|
|
1843
|
+
link: "https://github.com/mrdoob/three.js/wiki/Migration-Guide?utm_source=chatgpt.com#181--182"
|
|
1844
|
+
});
|
|
1845
|
+
}
|
|
1846
|
+
const types = {
|
|
1847
|
+
basic: three.BasicShadowMap,
|
|
1848
|
+
percentage: three.PCFShadowMap,
|
|
1849
|
+
soft: three.PCFShadowMap,
|
|
1850
|
+
variance: three.VSMShadowMap
|
|
1851
|
+
};
|
|
1852
|
+
renderer.shadowMap.type = types[shadows] ?? three.PCFShadowMap;
|
|
1853
|
+
} else if (is.obj(shadows)) {
|
|
1854
|
+
Object.assign(renderer.shadowMap, shadows);
|
|
1855
|
+
}
|
|
1856
|
+
if (oldEnabled !== renderer.shadowMap.enabled || oldType !== renderer.shadowMap.type) {
|
|
1857
|
+
renderer.shadowMap.needsUpdate = true;
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
if (!configured && !borrowsRenderer) {
|
|
1861
|
+
renderer.outputColorSpace = three.SRGBColorSpace;
|
|
1862
|
+
renderer.toneMapping = three.ACESFilmicToneMapping;
|
|
1863
|
+
}
|
|
1864
|
+
const textureColorSpace = requestedTextureColorSpace ?? three.SRGBColorSpace;
|
|
1865
|
+
if (textureColorSpace !== lastConfiguredProps.textureColorSpace) {
|
|
1866
|
+
if (state.textureColorSpace !== textureColorSpace) state.set(() => ({ textureColorSpace }));
|
|
1867
|
+
lastConfiguredProps.textureColorSpace = textureColorSpace;
|
|
1868
|
+
}
|
|
1869
|
+
if (glConfig && !is.fun(glConfig) && !isRenderer(glConfig) && changed("gl")) {
|
|
1870
|
+
const glProps = {};
|
|
1871
|
+
for (const key in glConfig) {
|
|
1872
|
+
if (!NON_APPLIED_RENDERER_PROPS.has(key)) glProps[key] = glConfig[key];
|
|
1873
|
+
}
|
|
1874
|
+
applyProps(renderer, glProps);
|
|
1875
|
+
}
|
|
1876
|
+
if (rendererConfig && !is.fun(rendererConfig) && !isRenderer(rendererConfig) && state.renderer && !borrowsRenderer) {
|
|
1877
|
+
const currentRenderer = state.renderer;
|
|
1878
|
+
if (changed("renderer")) {
|
|
1879
|
+
const rendererProps = {};
|
|
1880
|
+
for (const key in rendererConfig) {
|
|
1881
|
+
if (!NON_APPLIED_RENDERER_PROPS.has(key)) rendererProps[key] = rendererConfig[key];
|
|
1882
|
+
}
|
|
1883
|
+
applyProps(currentRenderer, rendererProps);
|
|
1884
|
+
}
|
|
1885
|
+
}
|
|
1886
|
+
configured = true;
|
|
1887
|
+
previous = next;
|
|
1888
|
+
};
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1891
|
+
const version = "10.0.0-alpha.5";
|
|
1892
|
+
const packageData = {
|
|
1893
|
+
version: version};
|
|
1894
|
+
|
|
1895
|
+
function $1(Ut) {
|
|
1896
|
+
return Ut && Ut.__esModule && Object.prototype.hasOwnProperty.call(Ut, "default") ? Ut.default : Ut;
|
|
1897
|
+
}
|
|
1898
|
+
var S0 = { exports: {} }, Ob = { exports: {} }, P1;
|
|
1899
|
+
function Q1() {
|
|
1900
|
+
return P1 || (P1 = 1, (function(Ut) {
|
|
1901
|
+
Ut.exports = function(m) {
|
|
1902
|
+
function et(t, r, a, l) {
|
|
1903
|
+
return new Fe(t, r, a, l);
|
|
1904
|
+
}
|
|
1905
|
+
function zf() {
|
|
1906
|
+
}
|
|
1907
|
+
function F(t) {
|
|
1908
|
+
var r = "https://react.dev/errors/" + t;
|
|
1909
|
+
if (1 < arguments.length) {
|
|
1910
|
+
r += "?args[]=" + encodeURIComponent(arguments[1]);
|
|
1911
|
+
for (var a = 2; a < arguments.length; a++) r += "&args[]=" + encodeURIComponent(arguments[a]);
|
|
1912
|
+
}
|
|
1913
|
+
return "Minified React error #" + t + "; visit " + r + " for the full message or use the non-minified dev environment for full errors and additional helpful warnings.";
|
|
1914
|
+
}
|
|
1915
|
+
function Ef(t) {
|
|
1916
|
+
for (var r = t, a = r; a && !a.alternate; ) r = a, (r.flags & 4098) !== 0 && (t = r.return), a = r.return;
|
|
1917
|
+
for (; r.return; ) r = r.return;
|
|
1141
1918
|
return r.tag === 3 ? t : null;
|
|
1142
1919
|
}
|
|
1143
1920
|
function pc(t) {
|
|
@@ -13309,15 +14086,16 @@ function swapInteractivity(store, object, newObject) {
|
|
|
13309
14086
|
pointerState.hovered.set(makeId(next), next);
|
|
13310
14087
|
}
|
|
13311
14088
|
});
|
|
13312
|
-
const captureData
|
|
13313
|
-
|
|
13314
|
-
|
|
13315
|
-
pointerState.captured.
|
|
14089
|
+
for (const [key, captureData] of Array.from(pointerState.captured)) {
|
|
14090
|
+
const { intersection } = captureData;
|
|
14091
|
+
if (key !== object && intersection.object !== object && intersection.eventObject !== object) continue;
|
|
14092
|
+
if (key === object) pointerState.captured.delete(key);
|
|
14093
|
+
pointerState.captured.set(key === object ? newObject : key, {
|
|
13316
14094
|
...captureData,
|
|
13317
14095
|
intersection: {
|
|
13318
|
-
...
|
|
13319
|
-
object:
|
|
13320
|
-
eventObject:
|
|
14096
|
+
...intersection,
|
|
14097
|
+
object: intersection.object === object ? newObject : intersection.object,
|
|
14098
|
+
eventObject: intersection.eventObject === object ? newObject : intersection.eventObject
|
|
13321
14099
|
}
|
|
13322
14100
|
});
|
|
13323
14101
|
}
|
|
@@ -13846,10 +14624,11 @@ const catalogue = globalThis[R3F_CATALOGUE] ?? (globalThis[R3F_CATALOGUE] = {});
|
|
|
13846
14624
|
const R3F_EXTEND_ID = Symbol.for("@react-three/fiber.extendId");
|
|
13847
14625
|
const ids = globalThis;
|
|
13848
14626
|
const toPascalCase = (type) => `${type[0].toUpperCase()}${type.slice(1)}`;
|
|
13849
|
-
const isConstructor = (object) => typeof object === "function";
|
|
14627
|
+
const isConstructor$1 = (object) => typeof object === "function";
|
|
13850
14628
|
function extend(objects) {
|
|
13851
|
-
if (isConstructor(objects)) {
|
|
13852
|
-
|
|
14629
|
+
if (isConstructor$1(objects)) {
|
|
14630
|
+
let id = ids[R3F_EXTEND_ID] ?? 0;
|
|
14631
|
+
while (`${id}` in catalogue) id++;
|
|
13853
14632
|
ids[R3F_EXTEND_ID] = id + 1;
|
|
13854
14633
|
const Component = `${id}`;
|
|
13855
14634
|
catalogue[Component] = objects;
|
|
@@ -13857,15 +14636,14 @@ function extend(objects) {
|
|
|
13857
14636
|
} else {
|
|
13858
14637
|
for (const name in objects) {
|
|
13859
14638
|
const object = objects[name];
|
|
13860
|
-
if (isConstructor(object)) catalogue[name] = object;
|
|
14639
|
+
if (isConstructor$1(object)) catalogue[name] = object;
|
|
13861
14640
|
}
|
|
13862
14641
|
}
|
|
13863
14642
|
}
|
|
13864
|
-
|
|
13865
14643
|
function resolveConstructor(name, root) {
|
|
13866
14644
|
if (Object.prototype.hasOwnProperty.call(catalogue, name)) return catalogue[name];
|
|
13867
14645
|
const object = root.getState().internal.support?.three[name];
|
|
13868
|
-
return isConstructor(object) ? object : void 0;
|
|
14646
|
+
return isConstructor$1(object) ? object : void 0;
|
|
13869
14647
|
}
|
|
13870
14648
|
|
|
13871
14649
|
function createReconciler(config) {
|
|
@@ -13879,11 +14657,16 @@ function validateInstance(type, props, root) {
|
|
|
13879
14657
|
const name = toPascalCase(type);
|
|
13880
14658
|
const target = resolveConstructor(name, root);
|
|
13881
14659
|
if (type !== "primitive" && !target) {
|
|
14660
|
+
if (name.endsWith("NodeMaterial")) {
|
|
14661
|
+
assertNodeMaterialSupported(root.getState(), { isNodeMaterial: true, type: name });
|
|
14662
|
+
}
|
|
13882
14663
|
throw new Error(
|
|
13883
14664
|
`R3F: ${name} is not part of the THREE namespace! Did you forget to extend? See: https://docs.pmnd.rs/react-three-fiber/api/objects#using-3rd-party-objects-declaratively`
|
|
13884
14665
|
);
|
|
13885
14666
|
}
|
|
13886
14667
|
if (type === "primitive" && !props.object) throw new Error(`R3F: Primitives without 'object' are invalid!`);
|
|
14668
|
+
assertNodeMaterialSupported(root.getState(), props.object);
|
|
14669
|
+
assertNodeMaterialSupported(root.getState(), props.material);
|
|
13887
14670
|
if (props.args !== void 0 && !Array.isArray(props.args)) throw new Error("R3F: The args prop must be an array!");
|
|
13888
14671
|
}
|
|
13889
14672
|
function createInstance(type, props, root) {
|
|
@@ -13897,6 +14680,7 @@ function hideInstance(instance) {
|
|
|
13897
14680
|
if (instance.props.attach && instance.parent?.object) {
|
|
13898
14681
|
detach(instance.parent, instance);
|
|
13899
14682
|
} else if (isObject3D(instance.object)) {
|
|
14683
|
+
instance.previousVisible = instance.object.visible;
|
|
13900
14684
|
instance.object.visible = false;
|
|
13901
14685
|
}
|
|
13902
14686
|
instance.isHidden = true;
|
|
@@ -13907,9 +14691,10 @@ function unhideInstance(instance) {
|
|
|
13907
14691
|
if (instance.isHidden) {
|
|
13908
14692
|
if (instance.props.attach && instance.parent?.object) {
|
|
13909
14693
|
attach(instance.parent, instance);
|
|
13910
|
-
} else if (isObject3D(instance.object)
|
|
13911
|
-
instance.object.visible = true;
|
|
14694
|
+
} else if (isObject3D(instance.object)) {
|
|
14695
|
+
instance.object.visible = instance.previousVisible ?? true;
|
|
13912
14696
|
}
|
|
14697
|
+
instance.previousVisible = void 0;
|
|
13913
14698
|
instance.isHidden = false;
|
|
13914
14699
|
invalidateInstance(instance);
|
|
13915
14700
|
}
|
|
@@ -13922,6 +14707,7 @@ function handleContainerEffects(parent, child, beforeChild) {
|
|
|
13922
14707
|
child.object = child.props.object ?? new target(...child.props.args ?? []);
|
|
13923
14708
|
child.object.__r3f = child;
|
|
13924
14709
|
}
|
|
14710
|
+
warnGLSLMaterialUnsupported(state, child.object);
|
|
13925
14711
|
applyProps(child.object, child.props);
|
|
13926
14712
|
if (child.props.attach) {
|
|
13927
14713
|
attach(parent, child);
|
|
@@ -13982,6 +14768,7 @@ function disposeOnIdle(object) {
|
|
|
13982
14768
|
}
|
|
13983
14769
|
function removeChild(parent, child, dispose) {
|
|
13984
14770
|
if (!child) return;
|
|
14771
|
+
const wasLinked = !!child.parent;
|
|
13985
14772
|
child.parent = null;
|
|
13986
14773
|
const childIndex = parent.children.indexOf(child);
|
|
13987
14774
|
if (childIndex !== -1) parent.children.splice(childIndex, 1);
|
|
@@ -14001,7 +14788,10 @@ function removeChild(parent, child, dispose) {
|
|
|
14001
14788
|
if (shouldDispose && child.type !== "primitive" && child.object.type !== "Scene") {
|
|
14002
14789
|
disposeOnIdle(child.object);
|
|
14003
14790
|
}
|
|
14004
|
-
if (dispose === void 0)
|
|
14791
|
+
if (dispose === void 0 && wasLinked) {
|
|
14792
|
+
const state = findInitialRoot(child).getState();
|
|
14793
|
+
if (state.internal.active && state.internal.frames === 0) state.invalidate();
|
|
14794
|
+
}
|
|
14005
14795
|
}
|
|
14006
14796
|
function setFiberRef(fiber, publicInstance) {
|
|
14007
14797
|
for (const _fiber of [fiber, fiber.alternate]) {
|
|
@@ -14334,450 +15124,113 @@ const reconciler = /* @__PURE__ */ createReconciler({
|
|
|
14334
15124
|
},
|
|
14335
15125
|
restoreRootViewTransitionName(_rootContainer) {
|
|
14336
15126
|
},
|
|
14337
|
-
InstanceMeasurement: null,
|
|
14338
|
-
measureInstance: (_instance) => null,
|
|
14339
|
-
wasInstanceInViewport: (_measurement) => true,
|
|
14340
|
-
hasInstanceChanged: (_oldMeasurement, _newMeasurement) => false,
|
|
14341
|
-
hasInstanceAffectedParent: (_oldMeasurement, _newMeasurement) => false,
|
|
14342
|
-
// https://github.com/facebook/react/pull/32002
|
|
14343
|
-
// https://github.com/facebook/react/pull/34486
|
|
14344
|
-
suspendOnActiveViewTransition(_state, _container) {
|
|
14345
|
-
},
|
|
14346
|
-
// https://github.com/facebook/react/pull/32451
|
|
14347
|
-
// https://github.com/facebook/react/pull/32760
|
|
14348
|
-
// React hands the whole commit to the host when a transition touches a <ViewTransition> subtree.
|
|
14349
|
-
// three.js has nothing to animate between commits, so this mirrors the react-dom fallback for
|
|
14350
|
-
// browsers without document.startViewTransition and flushes the commit synchronously.
|
|
14351
|
-
startViewTransition(_suspendedState, _rootContainer, _transitionTypes, mutationCallback, layoutCallback, _afterMutationCallback, spawnedWorkCallback, _passiveCallback, _errorCallback, _blockedCallback, finishedAnimation) {
|
|
14352
|
-
mutationCallback();
|
|
14353
|
-
layoutCallback();
|
|
14354
|
-
finishedAnimation?.();
|
|
14355
|
-
spawnedWorkCallback();
|
|
14356
|
-
return null;
|
|
14357
|
-
},
|
|
14358
|
-
startGestureTransition(_suspendedState, _rootContainer, _timeline, _rangeStart, _rangeEnd, _transitionTypes, mutationCallback, animateCallback, _errorCallback, finishedAnimation) {
|
|
14359
|
-
mutationCallback();
|
|
14360
|
-
animateCallback();
|
|
14361
|
-
finishedAnimation?.();
|
|
14362
|
-
return null;
|
|
14363
|
-
},
|
|
14364
|
-
stopViewTransition(_transition) {
|
|
14365
|
-
},
|
|
14366
|
-
// https://github.com/facebook/react/pull/35564
|
|
14367
|
-
// Only reached with a non-null transition from startViewTransition, which never returns one here
|
|
14368
|
-
addViewTransitionFinishedListener(_transition, callback) {
|
|
14369
|
-
callback();
|
|
14370
|
-
},
|
|
14371
|
-
// https://github.com/facebook/react/pull/32038
|
|
14372
|
-
createViewTransitionInstance: (_name) => null,
|
|
14373
|
-
// https://github.com/facebook/react/pull/32379
|
|
14374
|
-
// https://github.com/facebook/react/pull/32786
|
|
14375
|
-
getCurrentGestureOffset(_provider) {
|
|
14376
|
-
throw new Error("startGestureTransition is not yet supported in react-three-fiber.");
|
|
14377
|
-
},
|
|
14378
|
-
// https://github.com/facebook/react/pull/32500
|
|
14379
|
-
cloneMutableInstance(instance, _keepChildren) {
|
|
14380
|
-
return instance;
|
|
14381
|
-
},
|
|
14382
|
-
cloneMutableTextInstance(textInstance) {
|
|
14383
|
-
return textInstance;
|
|
14384
|
-
},
|
|
14385
|
-
// React 19.2 added these for root-level view transitions. They only run for hosts that opt into
|
|
14386
|
-
// view transitions by returning a container from cloneRootViewTransitionContainer; R3F renders
|
|
14387
|
-
// into a WebGL/WebGPU canvas, where cloning the root has no meaning, so we never opt in and
|
|
14388
|
-
// React never calls them. They stay as no-ops rather than throws: the host config is shared by
|
|
14389
|
-
// every root, and a throw here would turn a React-internal probe into a hard crash for users.
|
|
14390
|
-
// Guarded by a test asserting a full render + unmount never reaches them.
|
|
14391
|
-
cloneRootViewTransitionContainer(_rootContainer) {
|
|
14392
|
-
},
|
|
14393
|
-
removeRootViewTransitionClone(_rootContainer, _clone) {
|
|
14394
|
-
},
|
|
14395
|
-
// https://github.com/facebook/react/pull/32465
|
|
14396
|
-
createFragmentInstance: (_fiber) => null,
|
|
14397
|
-
updateFragmentInstanceFiber(_fiber, _instance) {
|
|
14398
|
-
},
|
|
14399
|
-
commitNewChildToFragmentInstance(_child, _fragmentInstance) {
|
|
14400
|
-
},
|
|
14401
|
-
deleteChildFromFragmentInstance(_child, _fragmentInstance) {
|
|
14402
|
-
},
|
|
14403
|
-
// https://github.com/facebook/react/pull/32653
|
|
14404
|
-
measureClonedInstance: (_instance) => null,
|
|
14405
|
-
// https://github.com/facebook/react/pull/32819
|
|
14406
|
-
maySuspendCommitOnUpdate: (_type, _oldProps, _newProps) => false,
|
|
14407
|
-
maySuspendCommitInSyncRender: (_type, _props) => false,
|
|
14408
|
-
// https://github.com/facebook/react/pull/34486
|
|
14409
|
-
startSuspendingCommit: () => null,
|
|
14410
|
-
// https://github.com/facebook/react/pull/34522
|
|
14411
|
-
getSuspendedCommitReason: (_state, _rootContainer) => null
|
|
14412
|
-
});
|
|
14413
|
-
|
|
14414
|
-
|
|
14415
|
-
function isInternalRendererAccess(stack, callerDepth = 2) {
|
|
14416
|
-
if (!stack) return false;
|
|
14417
|
-
const caller = stack.split("\n")[callerDepth] ?? "";
|
|
14418
|
-
return INTERNAL_LIB_MARKERS.some((m) => caller.includes(m));
|
|
14419
|
-
}
|
|
14420
|
-
|
|
14421
|
-
const createStore = (invalidate, advance) => {
|
|
14422
|
-
const rootStore = createWithEqualityFn((set, get) => {
|
|
14423
|
-
let position;
|
|
14424
|
-
let defaultTarget;
|
|
14425
|
-
let tempTarget;
|
|
14426
|
-
function getCurrentViewport(camera = get().camera, target = void 0, size = get().size) {
|
|
14427
|
-
const { Vector3 } = getThree();
|
|
14428
|
-
position ?? (position = new Vector3());
|
|
14429
|
-
defaultTarget ?? (defaultTarget = new Vector3());
|
|
14430
|
-
tempTarget ?? (tempTarget = new Vector3());
|
|
14431
|
-
target ?? (target = defaultTarget);
|
|
14432
|
-
const { width, height, top, left } = size;
|
|
14433
|
-
const aspect = width / height;
|
|
14434
|
-
if (target.isVector3) tempTarget.copy(target);
|
|
14435
|
-
else tempTarget.set(...target);
|
|
14436
|
-
const distance = camera.getWorldPosition(position).distanceTo(tempTarget);
|
|
14437
|
-
if (isOrthographicCamera(camera)) {
|
|
14438
|
-
return { width: width / camera.zoom, height: height / camera.zoom, top, left, factor: 1, distance, aspect };
|
|
14439
|
-
} else {
|
|
14440
|
-
const fov = camera.fov * Math.PI / 180;
|
|
14441
|
-
const h = 2 * Math.tan(fov / 2) * distance;
|
|
14442
|
-
const w = h * (width / height);
|
|
14443
|
-
return { width: w, height: h, top, left, factor: width / w, distance, aspect };
|
|
14444
|
-
}
|
|
14445
|
-
}
|
|
14446
|
-
let performanceTimeout = void 0;
|
|
14447
|
-
const setPerformanceCurrent = (current) => set((state2) => ({ performance: { ...state2.performance, current } }));
|
|
14448
|
-
const rootState = {
|
|
14449
|
-
set,
|
|
14450
|
-
get,
|
|
14451
|
-
// Mock objects that have to be configured
|
|
14452
|
-
// primaryStore is set after store creation (self-reference for primary, primary's store for secondary)
|
|
14453
|
-
primaryStore: null,
|
|
14454
|
-
gl: null,
|
|
14455
|
-
renderer: null,
|
|
14456
|
-
camera: null,
|
|
14457
|
-
// frustum, pointer and mouse are three objects; configure() creates them with the renderer
|
|
14458
|
-
frustum: null,
|
|
14459
|
-
autoUpdateFrustum: true,
|
|
14460
|
-
raycaster: null,
|
|
14461
|
-
events: {
|
|
14462
|
-
priority: 1,
|
|
14463
|
-
enabled: true,
|
|
14464
|
-
connected: false,
|
|
14465
|
-
frameTimedRaycasts: true,
|
|
14466
|
-
alwaysFireOnScroll: true,
|
|
14467
|
-
updateOnFrame: false
|
|
14468
|
-
},
|
|
14469
|
-
scene: null,
|
|
14470
|
-
rootScene: null,
|
|
14471
|
-
xr: null,
|
|
14472
|
-
inspector: null,
|
|
14473
|
-
invalidate: (frames = 1, stackFrames = false) => invalidate(get(), frames, stackFrames),
|
|
14474
|
-
advance: (timestamp, runGlobalEffects) => advance(timestamp, runGlobalEffects, get()),
|
|
14475
|
-
textureColorSpace: "srgb",
|
|
14476
|
-
// THREE.SRGBColorSpace
|
|
14477
|
-
isLegacy: false,
|
|
14478
|
-
webGPUSupported: false,
|
|
14479
|
-
isNative: false,
|
|
14480
|
-
controls: null,
|
|
14481
|
-
pointer: null,
|
|
14482
|
-
mouse: null,
|
|
14483
|
-
frameloop: "always",
|
|
14484
|
-
onPointerMissed: void 0,
|
|
14485
|
-
onDragOverMissed: void 0,
|
|
14486
|
-
onDropMissed: void 0,
|
|
14487
|
-
performance: {
|
|
14488
|
-
current: 1,
|
|
14489
|
-
min: 0.5,
|
|
14490
|
-
max: 1,
|
|
14491
|
-
debounce: 200,
|
|
14492
|
-
regress: () => {
|
|
14493
|
-
const state2 = get();
|
|
14494
|
-
if (performanceTimeout) clearTimeout(performanceTimeout);
|
|
14495
|
-
if (state2.performance.current !== state2.performance.min) setPerformanceCurrent(state2.performance.min);
|
|
14496
|
-
performanceTimeout = setTimeout(
|
|
14497
|
-
() => setPerformanceCurrent(get().performance.max),
|
|
14498
|
-
state2.performance.debounce
|
|
14499
|
-
);
|
|
14500
|
-
}
|
|
14501
|
-
},
|
|
14502
|
-
size: { width: 0, height: 0, top: 0, left: 0 },
|
|
14503
|
-
viewport: {
|
|
14504
|
-
initialDpr: 0,
|
|
14505
|
-
dpr: 0,
|
|
14506
|
-
width: 0,
|
|
14507
|
-
height: 0,
|
|
14508
|
-
top: 0,
|
|
14509
|
-
left: 0,
|
|
14510
|
-
aspect: 0,
|
|
14511
|
-
distance: 0,
|
|
14512
|
-
factor: 0,
|
|
14513
|
-
getCurrentViewport
|
|
14514
|
-
},
|
|
14515
|
-
setEvents: (events) => set((state2) => ({ ...state2, events: { ...state2.events, ...events } })),
|
|
14516
|
-
setSize: (width, height, top, left) => {
|
|
14517
|
-
const state2 = get();
|
|
14518
|
-
if (width === void 0) {
|
|
14519
|
-
set({ _sizeImperative: false });
|
|
14520
|
-
if (state2._sizeProps) {
|
|
14521
|
-
const { width: propW, height: propH } = state2._sizeProps;
|
|
14522
|
-
if (propW !== void 0 || propH !== void 0) {
|
|
14523
|
-
const currentSize = state2.size;
|
|
14524
|
-
const newSize = {
|
|
14525
|
-
width: propW ?? currentSize.width,
|
|
14526
|
-
height: propH ?? currentSize.height,
|
|
14527
|
-
top: currentSize.top,
|
|
14528
|
-
left: currentSize.left
|
|
14529
|
-
};
|
|
14530
|
-
set((s) => ({
|
|
14531
|
-
size: newSize,
|
|
14532
|
-
viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, newSize) }
|
|
14533
|
-
}));
|
|
14534
|
-
get().invalidate();
|
|
14535
|
-
}
|
|
14536
|
-
}
|
|
14537
|
-
return;
|
|
14538
|
-
}
|
|
14539
|
-
const w = width;
|
|
14540
|
-
const h = height ?? width;
|
|
14541
|
-
const t = top ?? state2.size.top;
|
|
14542
|
-
const l = left ?? state2.size.left;
|
|
14543
|
-
const size = { width: w, height: h, top: t, left: l };
|
|
14544
|
-
set((s) => ({
|
|
14545
|
-
size,
|
|
14546
|
-
viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, size) },
|
|
14547
|
-
_sizeImperative: true
|
|
14548
|
-
}));
|
|
14549
|
-
get().invalidate();
|
|
14550
|
-
},
|
|
14551
|
-
setDpr: (dpr) => set((state2) => {
|
|
14552
|
-
const resolved = calculateDpr(dpr);
|
|
14553
|
-
return { viewport: { ...state2.viewport, dpr: resolved, initialDpr: state2.viewport.initialDpr || resolved } };
|
|
14554
|
-
}),
|
|
14555
|
-
setFrameloop: (frameloop = "always") => {
|
|
14556
|
-
const rootId = get().internal.rootId;
|
|
14557
|
-
if (rootId) getScheduler().setRootFrameloop(rootId, frameloop);
|
|
14558
|
-
set(() => ({ frameloop }));
|
|
14559
|
-
},
|
|
14560
|
-
setError: (error) => set(() => ({ error })),
|
|
14561
|
-
error: null,
|
|
14562
|
-
//* Texture registry (useTextures) ==============================
|
|
14563
|
-
// TSL fields (uniforms, nodes, ..., renderPipeline) are added by @react-three/tsl's root extension.
|
|
14564
|
-
textures: /* @__PURE__ */ new Map(),
|
|
14565
|
-
_textureRefs: /* @__PURE__ */ new Map(),
|
|
14566
|
-
_sizeImperative: false,
|
|
14567
|
-
_sizeProps: null,
|
|
14568
|
-
previousRoot: void 0,
|
|
14569
|
-
internal: {
|
|
14570
|
-
// Events
|
|
14571
|
-
interaction: [],
|
|
14572
|
-
subscribers: [],
|
|
14573
|
-
// Per-pointer state (new unified structure)
|
|
14574
|
-
pointerMap: /* @__PURE__ */ new Map(),
|
|
14575
|
-
pointerDirty: /* @__PURE__ */ new Map(),
|
|
14576
|
-
lastEvent: React.createRef(),
|
|
14577
|
-
// Deprecated but kept for backwards compatibility
|
|
14578
|
-
hovered: /* @__PURE__ */ new Map(),
|
|
14579
|
-
initialClick: [0, 0],
|
|
14580
|
-
initialHits: [],
|
|
14581
|
-
capturedMap: /* @__PURE__ */ new Map(),
|
|
14582
|
-
// Visibility tracking (onFramed, onOccluded, onVisible)
|
|
14583
|
-
visibilityRegistry: /* @__PURE__ */ new Map(),
|
|
14584
|
-
// Occlusion system (WebGPU only)
|
|
14585
|
-
occlusionEnabled: false,
|
|
14586
|
-
occlusionObserver: null,
|
|
14587
|
-
occlusionCache: /* @__PURE__ */ new Map(),
|
|
14588
|
-
helperGroup: null,
|
|
14589
|
-
// Updates
|
|
14590
|
-
active: false,
|
|
14591
|
-
frames: 0,
|
|
14592
|
-
priority: 0,
|
|
14593
|
-
subscribe: (ref, priority, store) => {
|
|
14594
|
-
const internal = get().internal;
|
|
14595
|
-
internal.priority = internal.priority + (priority > 0 ? 1 : 0);
|
|
14596
|
-
internal.subscribers.push({ ref, priority, store });
|
|
14597
|
-
internal.subscribers = internal.subscribers.sort((a, b) => a.priority - b.priority);
|
|
14598
|
-
return () => {
|
|
14599
|
-
const internal2 = get().internal;
|
|
14600
|
-
if (internal2?.subscribers) {
|
|
14601
|
-
internal2.priority = internal2.priority - (priority > 0 ? 1 : 0);
|
|
14602
|
-
internal2.subscribers = internal2.subscribers.filter((s) => s.ref !== ref);
|
|
14603
|
-
}
|
|
14604
|
-
};
|
|
14605
|
-
},
|
|
14606
|
-
// Renderer Storage (single source of truth)
|
|
14607
|
-
actualRenderer: null,
|
|
14608
|
-
// The renderer support configure() loads for this root
|
|
14609
|
-
support: null,
|
|
14610
|
-
// Scheduler for useFrameNext (initialized in renderer.tsx)
|
|
14611
|
-
scheduler: null,
|
|
14612
|
-
// Replaces the default render call when set (see setRenderOverride)
|
|
14613
|
-
renderOverride: null
|
|
14614
|
-
}
|
|
14615
|
-
};
|
|
14616
|
-
return rootState;
|
|
14617
|
-
});
|
|
14618
|
-
const state = rootStore.getState();
|
|
14619
|
-
Object.defineProperty(state, "gl", {
|
|
14620
|
-
get() {
|
|
14621
|
-
const currentState = rootStore.getState();
|
|
14622
|
-
if (!currentState.isLegacy && currentState.internal.actualRenderer) {
|
|
14623
|
-
const stack = new Error().stack || "";
|
|
14624
|
-
if (!isInternalRendererAccess(stack)) {
|
|
14625
|
-
const cleanedStack = stack.split("\n").slice(2).join("\n") || "Stack trace unavailable";
|
|
14626
|
-
notifyDepreciated({
|
|
14627
|
-
heading: "Accessing state.gl in WebGPU mode",
|
|
14628
|
-
body: "Please use state.renderer instead. state.gl is deprecated and will be removed in future versions.\n\nFor backwards compatibility, state.gl currently maps to state.renderer, but this may cause issues with libraries expecting WebGLRenderer.\n\nAccessed from:\n" + cleanedStack
|
|
14629
|
-
});
|
|
14630
|
-
}
|
|
14631
|
-
}
|
|
14632
|
-
return currentState.internal.actualRenderer;
|
|
14633
|
-
},
|
|
14634
|
-
set(value) {
|
|
14635
|
-
rootStore.getState().internal.actualRenderer = value;
|
|
14636
|
-
},
|
|
14637
|
-
enumerable: true,
|
|
14638
|
-
configurable: true
|
|
14639
|
-
});
|
|
14640
|
-
Object.defineProperty(state, "renderer", {
|
|
14641
|
-
get() {
|
|
14642
|
-
return rootStore.getState().internal.actualRenderer;
|
|
14643
|
-
},
|
|
14644
|
-
set(value) {
|
|
14645
|
-
rootStore.getState().internal.actualRenderer = value;
|
|
14646
|
-
},
|
|
14647
|
-
enumerable: true,
|
|
14648
|
-
configurable: true
|
|
14649
|
-
});
|
|
14650
|
-
let oldScene = state.scene;
|
|
14651
|
-
rootStore.subscribe(() => {
|
|
14652
|
-
const currentState = rootStore.getState();
|
|
14653
|
-
const { scene, rootScene, set } = currentState;
|
|
14654
|
-
if (scene !== oldScene) {
|
|
14655
|
-
oldScene = scene;
|
|
14656
|
-
if (scene?.isScene && scene !== rootScene) {
|
|
14657
|
-
set({ rootScene: scene });
|
|
14658
|
-
}
|
|
14659
|
-
}
|
|
14660
|
-
});
|
|
14661
|
-
let oldSize = state.size;
|
|
14662
|
-
let oldDpr = state.viewport.dpr;
|
|
14663
|
-
let oldCamera = state.camera;
|
|
14664
|
-
rootStore.subscribe(() => {
|
|
14665
|
-
const { camera, size, viewport, set, internal } = rootStore.getState();
|
|
14666
|
-
const actualRenderer = internal.actualRenderer;
|
|
14667
|
-
const canvasTarget = internal.canvasTarget;
|
|
14668
|
-
if (size.width !== oldSize.width || size.height !== oldSize.height || viewport.dpr !== oldDpr) {
|
|
14669
|
-
oldSize = size;
|
|
14670
|
-
oldDpr = viewport.dpr;
|
|
14671
|
-
updateCamera(camera, size);
|
|
14672
|
-
const resizeTarget = canvasTarget ?? actualRenderer;
|
|
14673
|
-
if (viewport.dpr > 0) resizeTarget.setPixelRatio(viewport.dpr);
|
|
14674
|
-
resizeTarget.setSize(size.width, size.height, false);
|
|
14675
|
-
const activeTarget = actualRenderer.getCanvasTarget?.();
|
|
14676
|
-
if (!canvasTarget || activeTarget !== canvasTarget) internal.canvasTargetSizeDirty = true;
|
|
14677
|
-
}
|
|
14678
|
-
if (camera !== oldCamera) {
|
|
14679
|
-
oldCamera = camera;
|
|
14680
|
-
const { rootScene } = rootStore.getState();
|
|
14681
|
-
if (camera && rootScene && !camera.parent) {
|
|
14682
|
-
rootScene.add(camera);
|
|
14683
|
-
}
|
|
14684
|
-
set((state2) => ({ viewport: { ...state2.viewport, ...state2.viewport.getCurrentViewport(camera) } }));
|
|
14685
|
-
const currentState = rootStore.getState();
|
|
14686
|
-
if (currentState.autoUpdateFrustum && camera) {
|
|
14687
|
-
updateFrustum(camera, currentState.frustum);
|
|
14688
|
-
}
|
|
14689
|
-
}
|
|
14690
|
-
});
|
|
14691
|
-
rootStore.subscribe((state2) => invalidate(state2));
|
|
14692
|
-
return rootStore;
|
|
14693
|
-
};
|
|
14694
|
-
|
|
14695
|
-
const primaryRegistry = /* @__PURE__ */ new Map();
|
|
14696
|
-
const pendingSubscribers = /* @__PURE__ */ new Map();
|
|
14697
|
-
function registerPrimary(id, renderer, store) {
|
|
14698
|
-
if (primaryRegistry.has(id)) {
|
|
14699
|
-
console.warn(`Canvas with id="${id}" already registered. Overwriting.`);
|
|
14700
|
-
}
|
|
14701
|
-
const entry = { renderer, store };
|
|
14702
|
-
primaryRegistry.set(id, entry);
|
|
14703
|
-
const subscribers = pendingSubscribers.get(id);
|
|
14704
|
-
if (subscribers) {
|
|
14705
|
-
subscribers.forEach((callback) => callback(entry));
|
|
14706
|
-
pendingSubscribers.delete(id);
|
|
14707
|
-
}
|
|
14708
|
-
return () => {
|
|
14709
|
-
const currentEntry = primaryRegistry.get(id);
|
|
14710
|
-
if (currentEntry?.renderer === renderer) {
|
|
14711
|
-
primaryRegistry.delete(id);
|
|
14712
|
-
}
|
|
14713
|
-
};
|
|
14714
|
-
}
|
|
14715
|
-
function getPrimary(id) {
|
|
14716
|
-
return primaryRegistry.get(id);
|
|
14717
|
-
}
|
|
14718
|
-
function waitForPrimary(id, timeout = 5e3) {
|
|
14719
|
-
const existing = primaryRegistry.get(id);
|
|
14720
|
-
if (existing) {
|
|
14721
|
-
return Promise.resolve(existing);
|
|
14722
|
-
}
|
|
14723
|
-
return new Promise((resolve, reject) => {
|
|
14724
|
-
const timeoutId = setTimeout(() => {
|
|
14725
|
-
const subscribers = pendingSubscribers.get(id);
|
|
14726
|
-
if (subscribers) {
|
|
14727
|
-
const index = subscribers.indexOf(callback);
|
|
14728
|
-
if (index !== -1) subscribers.splice(index, 1);
|
|
14729
|
-
if (subscribers.length === 0) pendingSubscribers.delete(id);
|
|
14730
|
-
}
|
|
14731
|
-
reject(new Error(`Timeout waiting for canvas with id="${id}". Make sure a <Canvas id="${id}"> is mounted.`));
|
|
14732
|
-
}, timeout);
|
|
14733
|
-
const callback = (entry) => {
|
|
14734
|
-
clearTimeout(timeoutId);
|
|
14735
|
-
resolve(entry);
|
|
14736
|
-
};
|
|
14737
|
-
if (!pendingSubscribers.has(id)) {
|
|
14738
|
-
pendingSubscribers.set(id, []);
|
|
14739
|
-
}
|
|
14740
|
-
pendingSubscribers.get(id).push(callback);
|
|
14741
|
-
});
|
|
14742
|
-
}
|
|
14743
|
-
function hasPrimary(id) {
|
|
14744
|
-
return primaryRegistry.has(id);
|
|
14745
|
-
}
|
|
14746
|
-
function unregisterPrimary(id) {
|
|
14747
|
-
primaryRegistry.delete(id);
|
|
14748
|
-
}
|
|
14749
|
-
function getPrimaryIds() {
|
|
14750
|
-
return Array.from(primaryRegistry.keys());
|
|
15127
|
+
InstanceMeasurement: null,
|
|
15128
|
+
measureInstance: (_instance) => null,
|
|
15129
|
+
wasInstanceInViewport: (_measurement) => true,
|
|
15130
|
+
hasInstanceChanged: (_oldMeasurement, _newMeasurement) => false,
|
|
15131
|
+
hasInstanceAffectedParent: (_oldMeasurement, _newMeasurement) => false,
|
|
15132
|
+
// https://github.com/facebook/react/pull/32002
|
|
15133
|
+
// https://github.com/facebook/react/pull/34486
|
|
15134
|
+
suspendOnActiveViewTransition(_state, _container) {
|
|
15135
|
+
},
|
|
15136
|
+
// https://github.com/facebook/react/pull/32451
|
|
15137
|
+
// https://github.com/facebook/react/pull/32760
|
|
15138
|
+
// React hands the whole commit to the host when a transition touches a <ViewTransition> subtree.
|
|
15139
|
+
// three.js has nothing to animate between commits, so this mirrors the react-dom fallback for
|
|
15140
|
+
// browsers without document.startViewTransition and flushes the commit synchronously.
|
|
15141
|
+
startViewTransition(_suspendedState, _rootContainer, _transitionTypes, mutationCallback, layoutCallback, _afterMutationCallback, spawnedWorkCallback, _passiveCallback, _errorCallback, _blockedCallback, finishedAnimation) {
|
|
15142
|
+
mutationCallback();
|
|
15143
|
+
layoutCallback();
|
|
15144
|
+
finishedAnimation?.();
|
|
15145
|
+
spawnedWorkCallback();
|
|
15146
|
+
return null;
|
|
15147
|
+
},
|
|
15148
|
+
startGestureTransition(_suspendedState, _rootContainer, _timeline, _rangeStart, _rangeEnd, _transitionTypes, mutationCallback, animateCallback, _errorCallback, finishedAnimation) {
|
|
15149
|
+
mutationCallback();
|
|
15150
|
+
animateCallback();
|
|
15151
|
+
finishedAnimation?.();
|
|
15152
|
+
return null;
|
|
15153
|
+
},
|
|
15154
|
+
stopViewTransition(_transition) {
|
|
15155
|
+
},
|
|
15156
|
+
// https://github.com/facebook/react/pull/35564
|
|
15157
|
+
// Only reached with a non-null transition from startViewTransition, which never returns one here
|
|
15158
|
+
addViewTransitionFinishedListener(_transition, callback) {
|
|
15159
|
+
callback();
|
|
15160
|
+
},
|
|
15161
|
+
// https://github.com/facebook/react/pull/32038
|
|
15162
|
+
createViewTransitionInstance: (_name) => null,
|
|
15163
|
+
// https://github.com/facebook/react/pull/32379
|
|
15164
|
+
// https://github.com/facebook/react/pull/32786
|
|
15165
|
+
getCurrentGestureOffset(_provider) {
|
|
15166
|
+
throw new Error("startGestureTransition is not yet supported in react-three-fiber.");
|
|
15167
|
+
},
|
|
15168
|
+
// https://github.com/facebook/react/pull/32500
|
|
15169
|
+
cloneMutableInstance(instance, _keepChildren) {
|
|
15170
|
+
return instance;
|
|
15171
|
+
},
|
|
15172
|
+
cloneMutableTextInstance(textInstance) {
|
|
15173
|
+
return textInstance;
|
|
15174
|
+
},
|
|
15175
|
+
// React 19.2 added these for root-level view transitions. They only run for hosts that opt into
|
|
15176
|
+
// view transitions by returning a container from cloneRootViewTransitionContainer; R3F renders
|
|
15177
|
+
// into a WebGL/WebGPU canvas, where cloning the root has no meaning, so we never opt in and
|
|
15178
|
+
// React never calls them. They stay as no-ops rather than throws: the host config is shared by
|
|
15179
|
+
// every root, and a throw here would turn a React-internal probe into a hard crash for users.
|
|
15180
|
+
// Guarded by a test asserting a full render + unmount never reaches them.
|
|
15181
|
+
cloneRootViewTransitionContainer(_rootContainer) {
|
|
15182
|
+
},
|
|
15183
|
+
removeRootViewTransitionClone(_rootContainer, _clone) {
|
|
15184
|
+
},
|
|
15185
|
+
// https://github.com/facebook/react/pull/32465
|
|
15186
|
+
createFragmentInstance: (_fiber) => null,
|
|
15187
|
+
updateFragmentInstanceFiber(_fiber, _instance) {
|
|
15188
|
+
},
|
|
15189
|
+
commitNewChildToFragmentInstance(_child, _fragmentInstance) {
|
|
15190
|
+
},
|
|
15191
|
+
deleteChildFromFragmentInstance(_child, _fragmentInstance) {
|
|
15192
|
+
},
|
|
15193
|
+
// https://github.com/facebook/react/pull/32653
|
|
15194
|
+
measureClonedInstance: (_instance) => null,
|
|
15195
|
+
// https://github.com/facebook/react/pull/32819
|
|
15196
|
+
maySuspendCommitOnUpdate: (_type, _oldProps, _newProps) => false,
|
|
15197
|
+
maySuspendCommitInSyncRender: (_type, _props) => false,
|
|
15198
|
+
// https://github.com/facebook/react/pull/34486
|
|
15199
|
+
startSuspendingCommit: () => null,
|
|
15200
|
+
// https://github.com/facebook/react/pull/34522
|
|
15201
|
+
getSuspendedCommitReason: (_state, _rootContainer) => null
|
|
15202
|
+
});
|
|
15203
|
+
function flushSync(fn) {
|
|
15204
|
+
return reconciler.flushSyncFromReconciler(fn);
|
|
14751
15205
|
}
|
|
14752
15206
|
|
|
14753
|
-
const
|
|
15207
|
+
const noop = () => {
|
|
15208
|
+
};
|
|
14754
15209
|
const _roots = /* @__PURE__ */ new Map();
|
|
14755
|
-
function
|
|
14756
|
-
const state =
|
|
14757
|
-
|
|
14758
|
-
|
|
14759
|
-
|
|
14760
|
-
|
|
14761
|
-
|
|
14762
|
-
|
|
14763
|
-
|
|
14764
|
-
|
|
14765
|
-
|
|
14766
|
-
|
|
14767
|
-
|
|
14768
|
-
|
|
14769
|
-
|
|
14770
|
-
|
|
14771
|
-
|
|
14772
|
-
|
|
14773
|
-
|
|
14774
|
-
|
|
14775
|
-
|
|
14776
|
-
|
|
14777
|
-
|
|
14778
|
-
};
|
|
15210
|
+
function transitionRoot(root, event) {
|
|
15211
|
+
const state = root.state;
|
|
15212
|
+
switch (event.type) {
|
|
15213
|
+
case "use":
|
|
15214
|
+
if (state.status === "disposed") return false;
|
|
15215
|
+
if (state.status === "closing") {
|
|
15216
|
+
root.store.getState().internal.active = true;
|
|
15217
|
+
state.settle();
|
|
15218
|
+
}
|
|
15219
|
+
root.state = { status: "open" };
|
|
15220
|
+
return true;
|
|
15221
|
+
case "unmount": {
|
|
15222
|
+
if (state.status === "disposed") return false;
|
|
15223
|
+
if (state.status === "closing") state.settle();
|
|
15224
|
+
const { promise, resolve } = deferred();
|
|
15225
|
+
root.state = { status: "closing", token: event.token, settled: promise, settle: resolve };
|
|
15226
|
+
return true;
|
|
15227
|
+
}
|
|
15228
|
+
case "dispose":
|
|
15229
|
+
if (state.status !== "closing" || state.token !== event.token) return false;
|
|
15230
|
+
root.state = { status: "disposed" };
|
|
15231
|
+
state.settle();
|
|
15232
|
+
return true;
|
|
14779
15233
|
}
|
|
14780
|
-
return { width: 0, height: 0, top: 0, left: 0, ...size };
|
|
14781
15234
|
}
|
|
14782
15235
|
function createRoot(canvas, provider) {
|
|
14783
15236
|
const prevRoot = _roots.get(canvas);
|
|
@@ -14815,540 +15268,670 @@ function createRoot(canvas, provider) {
|
|
|
14815
15268
|
null
|
|
14816
15269
|
// transitionCallbacks
|
|
14817
15270
|
);
|
|
14818
|
-
|
|
14819
|
-
|
|
14820
|
-
|
|
14821
|
-
|
|
14822
|
-
|
|
14823
|
-
|
|
14824
|
-
|
|
14825
|
-
|
|
14826
|
-
|
|
14827
|
-
|
|
14828
|
-
|
|
14829
|
-
|
|
14830
|
-
|
|
14831
|
-
|
|
14832
|
-
|
|
14833
|
-
|
|
14834
|
-
|
|
14835
|
-
|
|
14836
|
-
|
|
14837
|
-
|
|
14838
|
-
|
|
14839
|
-
|
|
14840
|
-
|
|
14841
|
-
|
|
14842
|
-
|
|
14843
|
-
|
|
14844
|
-
|
|
14845
|
-
|
|
14846
|
-
|
|
14847
|
-
|
|
14848
|
-
|
|
14849
|
-
|
|
14850
|
-
|
|
14851
|
-
|
|
14852
|
-
|
|
14853
|
-
|
|
14854
|
-
|
|
14855
|
-
|
|
14856
|
-
|
|
14857
|
-
|
|
14858
|
-
|
|
14859
|
-
|
|
14860
|
-
|
|
14861
|
-
|
|
14862
|
-
|
|
14863
|
-
|
|
14864
|
-
|
|
14865
|
-
|
|
14866
|
-
|
|
14867
|
-
|
|
14868
|
-
|
|
14869
|
-
|
|
14870
|
-
|
|
14871
|
-
|
|
14872
|
-
|
|
14873
|
-
|
|
14874
|
-
|
|
14875
|
-
|
|
14876
|
-
|
|
14877
|
-
|
|
14878
|
-
|
|
14879
|
-
|
|
14880
|
-
|
|
14881
|
-
|
|
14882
|
-
|
|
14883
|
-
|
|
14884
|
-
|
|
14885
|
-
|
|
14886
|
-
|
|
14887
|
-
}
|
|
14888
|
-
|
|
14889
|
-
|
|
14890
|
-
|
|
14891
|
-
|
|
14892
|
-
|
|
14893
|
-
|
|
14894
|
-
|
|
14895
|
-
|
|
14896
|
-
|
|
14897
|
-
|
|
15271
|
+
const root = prevRoot || {
|
|
15272
|
+
fiber,
|
|
15273
|
+
store,
|
|
15274
|
+
state: { status: "open" },
|
|
15275
|
+
ready: fulfilled(void 0),
|
|
15276
|
+
configuration: {}
|
|
15277
|
+
};
|
|
15278
|
+
if (!prevRoot) _roots.set(canvas, root);
|
|
15279
|
+
if (!prevRoot) root.configuration.apply = createRootConfiguration(store, canvas);
|
|
15280
|
+
let mounted = false;
|
|
15281
|
+
return {
|
|
15282
|
+
get ready() {
|
|
15283
|
+
return root.ready;
|
|
15284
|
+
},
|
|
15285
|
+
configure(props = {}) {
|
|
15286
|
+
if (!transitionRoot(root, { type: "use" })) {
|
|
15287
|
+
return rejected(new Error("R3F: Cannot configure a root after it has unmounted (disposal has started)."));
|
|
15288
|
+
}
|
|
15289
|
+
const previous = root.ready;
|
|
15290
|
+
const { promise, resolve, reject } = deferred();
|
|
15291
|
+
root.ready = promise;
|
|
15292
|
+
const run = () => {
|
|
15293
|
+
try {
|
|
15294
|
+
const initialized = initializeRenderer(canvas, provider, store, props);
|
|
15295
|
+
const apply = () => {
|
|
15296
|
+
if (props.id) {
|
|
15297
|
+
for (const other of _roots.values()) {
|
|
15298
|
+
if (other !== root && other.state.status === "closing" && other.store.getState().internal.rootId === props.id) {
|
|
15299
|
+
other.state.settled.then(apply).catch(reject);
|
|
15300
|
+
return;
|
|
15301
|
+
}
|
|
15302
|
+
}
|
|
15303
|
+
}
|
|
15304
|
+
const previous2 = root.configuration.previous;
|
|
15305
|
+
root.configuration.apply(props);
|
|
15306
|
+
configureScheduler(store, props.id, props.scheduler, previous2?.scheduler);
|
|
15307
|
+
attachRootExtensions(store);
|
|
15308
|
+
root.configuration.previous = props;
|
|
15309
|
+
resolve(this);
|
|
15310
|
+
};
|
|
15311
|
+
if (isPromiseLike(initialized)) Promise.resolve(initialized).then(apply).catch(reject);
|
|
15312
|
+
else apply();
|
|
15313
|
+
} catch (error) {
|
|
15314
|
+
reject(error);
|
|
15315
|
+
}
|
|
15316
|
+
};
|
|
15317
|
+
if (previous.status === "pending") previous.then(run, reject);
|
|
15318
|
+
else run();
|
|
15319
|
+
return promise;
|
|
15320
|
+
},
|
|
15321
|
+
render(children) {
|
|
15322
|
+
if (!transitionRoot(root, { type: "use" })) return store;
|
|
15323
|
+
if (!store.getState().internal.actualRenderer && root.ready.status === "fulfilled") this.configure();
|
|
15324
|
+
if (root.ready.status === "rejected") throw root.ready.reason;
|
|
15325
|
+
const commit = () => {
|
|
15326
|
+
if (root.state.status !== "open" || root.ready.status === "rejected") return;
|
|
15327
|
+
if (root.ready.status === "pending") {
|
|
15328
|
+
root.ready.then(commit, logRecoverableError);
|
|
15329
|
+
return;
|
|
15330
|
+
}
|
|
15331
|
+
const onCreated = root.configuration.previous?.onCreated;
|
|
15332
|
+
const element = /* @__PURE__ */ jsx(Provider, { store, children, onCreated, rootElement: canvas });
|
|
15333
|
+
if (mounted) {
|
|
15334
|
+
reconciler.updateContainer(element, fiber, null, noop);
|
|
15335
|
+
return;
|
|
15336
|
+
}
|
|
15337
|
+
mounted = true;
|
|
15338
|
+
reconciler.updateContainerSync(element, fiber, null, noop);
|
|
15339
|
+
reconciler.flushSyncWork();
|
|
15340
|
+
};
|
|
15341
|
+
commit();
|
|
15342
|
+
return store;
|
|
15343
|
+
},
|
|
15344
|
+
unmount() {
|
|
15345
|
+
if (_roots.get(canvas) === root) unmountComponentAtNode(canvas);
|
|
15346
|
+
}
|
|
15347
|
+
};
|
|
15348
|
+
}
|
|
15349
|
+
function Provider({
|
|
15350
|
+
store,
|
|
15351
|
+
children,
|
|
15352
|
+
onCreated,
|
|
15353
|
+
rootElement
|
|
15354
|
+
}) {
|
|
15355
|
+
useIsomorphicLayoutEffect(() => {
|
|
15356
|
+
const state = store.getState();
|
|
15357
|
+
state.set((state2) => ({ internal: { ...state2.internal, active: true } }));
|
|
15358
|
+
if (onCreated) onCreated(state);
|
|
15359
|
+
if (!store.getState().events.connected) state.events.connect?.(rootElement);
|
|
15360
|
+
}, []);
|
|
15361
|
+
return /* @__PURE__ */ jsx(context.Provider, { value: store, children });
|
|
15362
|
+
}
|
|
15363
|
+
function unmountComponentAtNode(canvas, callback) {
|
|
15364
|
+
const claim = Symbol("unmount");
|
|
15365
|
+
const root = _roots.get(canvas);
|
|
15366
|
+
if (!root || !transitionRoot(root, { type: "unmount", token: claim })) return;
|
|
15367
|
+
root.store.getState().internal.active = false;
|
|
15368
|
+
reconciler.updateContainer(null, root.fiber, null, () => {
|
|
15369
|
+
if (root.state.status !== "closing" || root.state.token !== claim) return;
|
|
15370
|
+
reconciler.updateContainer(null, root.fiber, null, () => {
|
|
15371
|
+
if (root.state.status !== "closing" || root.state.token !== claim) return;
|
|
15372
|
+
if (root.ready.status === "pending") root.ready.then(teardown, teardown);
|
|
15373
|
+
else teardown();
|
|
15374
|
+
});
|
|
15375
|
+
});
|
|
15376
|
+
function teardown() {
|
|
15377
|
+
if (root.ready.status === "pending") {
|
|
15378
|
+
root.ready.then(teardown, teardown);
|
|
15379
|
+
return;
|
|
15380
|
+
}
|
|
15381
|
+
if (!transitionRoot(root, { type: "dispose", token: claim })) return;
|
|
15382
|
+
_roots.delete(canvas);
|
|
15383
|
+
const state = root.store.getState();
|
|
15384
|
+
const internal = state.internal;
|
|
15385
|
+
internal.active = false;
|
|
15386
|
+
const attempt = (step) => {
|
|
15387
|
+
try {
|
|
15388
|
+
return step();
|
|
15389
|
+
} catch (error) {
|
|
15390
|
+
console.warn("[R3F] Error while unmounting root; teardown may be incomplete:", error);
|
|
15391
|
+
}
|
|
15392
|
+
};
|
|
15393
|
+
attempt(() => internal.unwatchDpr?.());
|
|
15394
|
+
internal.unwatchDpr = void 0;
|
|
15395
|
+
attempt(() => internal.unregisterRoot?.());
|
|
15396
|
+
internal.unregisterRoot = void 0;
|
|
15397
|
+
attempt(() => detachRootExtensions(root.store));
|
|
15398
|
+
attempt(() => internal.unregisterPrimary?.());
|
|
15399
|
+
attempt(() => internal.untrackStandalone?.());
|
|
15400
|
+
attempt(() => state.events.disconnect?.());
|
|
15401
|
+
if (!internal.isSecondary && internal.actualRenderer?.xr && state.xr) attempt(() => state.xr.disconnect());
|
|
15402
|
+
attempt(() => cleanupHelperGroup(root.store));
|
|
15403
|
+
if (state.scene) attempt(() => dispose(state.scene));
|
|
15404
|
+
const canvasTarget = internal.canvasTarget;
|
|
15405
|
+
if (internal.isSecondary && canvasTarget?.dispose) attempt(() => canvasTarget.dispose());
|
|
15406
|
+
const released = attempt(() => internal.releaseRenderer?.());
|
|
15407
|
+
internal.releaseRenderer = void 0;
|
|
15408
|
+
if (callback) {
|
|
15409
|
+
if (released) {
|
|
15410
|
+
released.then(() => callback(canvas)).catch((error) => console.warn("[R3F] Error in unmount callback", error));
|
|
15411
|
+
} else {
|
|
15412
|
+
callback(canvas);
|
|
15413
|
+
}
|
|
15414
|
+
}
|
|
15415
|
+
}
|
|
15416
|
+
}
|
|
15417
|
+
|
|
15418
|
+
const memoizedLoaders = /* @__PURE__ */ new WeakMap();
|
|
15419
|
+
const isConstructor = (value) => typeof value === "function" && value?.prototype?.constructor === value;
|
|
15420
|
+
function getLoader(Proto) {
|
|
15421
|
+
if (isConstructor(Proto)) {
|
|
15422
|
+
let loader = memoizedLoaders.get(Proto);
|
|
15423
|
+
if (!loader) {
|
|
15424
|
+
loader = new Proto();
|
|
15425
|
+
memoizedLoaders.set(Proto, loader);
|
|
15426
|
+
}
|
|
15427
|
+
return loader;
|
|
15428
|
+
}
|
|
15429
|
+
return Proto;
|
|
15430
|
+
}
|
|
15431
|
+
function loadingFn(extensions, onProgress) {
|
|
15432
|
+
return function(Proto, input) {
|
|
15433
|
+
const loader = getLoader(Proto);
|
|
15434
|
+
if (extensions) extensions(loader);
|
|
15435
|
+
if ("loadAsync" in loader && typeof loader.loadAsync === "function") {
|
|
15436
|
+
return loader.loadAsync(input, onProgress).then((data) => {
|
|
15437
|
+
if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
|
|
15438
|
+
return data;
|
|
15439
|
+
});
|
|
15440
|
+
}
|
|
15441
|
+
return new Promise(
|
|
15442
|
+
(res, reject) => loader.load(
|
|
15443
|
+
input,
|
|
15444
|
+
(data) => {
|
|
15445
|
+
if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
|
|
15446
|
+
res(data);
|
|
15447
|
+
},
|
|
15448
|
+
onProgress,
|
|
15449
|
+
(error) => reject(new Error(`Could not load ${input}: ${error?.message}`))
|
|
15450
|
+
)
|
|
15451
|
+
);
|
|
15452
|
+
};
|
|
15453
|
+
}
|
|
15454
|
+
function useLoader(loader, input, extensions, onProgress, cacheKey) {
|
|
15455
|
+
const inputs = Array.isArray(input) ? input : [input];
|
|
15456
|
+
const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
|
|
15457
|
+
const fn = loadingFn(extensions, onProgress);
|
|
15458
|
+
const results = cacheKeys.map(
|
|
15459
|
+
(key, index) => suspend(() => fn(loader, inputs[index]), [loader, key], { equal: is.equ })
|
|
15460
|
+
);
|
|
15461
|
+
const stableRef = useRef(null);
|
|
15462
|
+
const previous = stableRef.current;
|
|
15463
|
+
const stable = previous !== null && previous.length === results.length && previous.every((value, i) => value === results[i]) ? previous : results;
|
|
15464
|
+
stableRef.current = stable;
|
|
15465
|
+
return Array.isArray(input) ? stable : stable[0];
|
|
15466
|
+
}
|
|
15467
|
+
useLoader.preload = function(loader, input, extensions, onProgress, cacheKey) {
|
|
15468
|
+
const inputs = Array.isArray(input) ? input : [input];
|
|
15469
|
+
const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
|
|
15470
|
+
cacheKeys.forEach(
|
|
15471
|
+
(key, index) => preload(() => loadingFn(extensions, onProgress)(loader, inputs[index]), [loader, key])
|
|
15472
|
+
);
|
|
15473
|
+
};
|
|
15474
|
+
useLoader.clear = function(loader, input, cacheKey) {
|
|
15475
|
+
const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
|
|
15476
|
+
cacheKeys.forEach((key) => clear([loader, key]));
|
|
15477
|
+
};
|
|
15478
|
+
useLoader.loader = getLoader;
|
|
15479
|
+
|
|
15480
|
+
const IsObject = (url) => url === Object(url) && !Array.isArray(url) && typeof url !== "function";
|
|
15481
|
+
function getUrls(input) {
|
|
15482
|
+
if (typeof input === "string") return [input];
|
|
15483
|
+
if (Array.isArray(input)) return input;
|
|
15484
|
+
return Object.values(input);
|
|
15485
|
+
}
|
|
15486
|
+
function inputSignature(input) {
|
|
15487
|
+
if (typeof input === "string") return input;
|
|
15488
|
+
if (Array.isArray(input)) return input.join("\0");
|
|
15489
|
+
return Object.keys(input).sort().map((key) => `${key}\0${input[key]}`).join("");
|
|
15490
|
+
}
|
|
15491
|
+
function allUrlsCached(urls, textureCache) {
|
|
15492
|
+
return urls.every((url) => textureCache.has(url));
|
|
15493
|
+
}
|
|
15494
|
+
function buildFromCache(input, textureCache) {
|
|
15495
|
+
if (typeof input === "string") {
|
|
15496
|
+
return textureCache.get(input);
|
|
15497
|
+
} else if (Array.isArray(input)) {
|
|
15498
|
+
return input.map((url) => textureCache.get(url));
|
|
15499
|
+
} else {
|
|
15500
|
+
const result = {};
|
|
15501
|
+
const objInput = input;
|
|
15502
|
+
for (const key in objInput) {
|
|
15503
|
+
result[key] = textureCache.get(objInput[key]);
|
|
15504
|
+
}
|
|
15505
|
+
return result;
|
|
15506
|
+
}
|
|
15507
|
+
}
|
|
15508
|
+
function useTexture(input, optionsOrOnLoad) {
|
|
15509
|
+
const renderer = useThree((state) => state.internal.actualRenderer);
|
|
15510
|
+
const store = useStore();
|
|
15511
|
+
const options = typeof optionsOrOnLoad === "function" ? { onLoad: optionsOrOnLoad } : optionsOrOnLoad ?? {};
|
|
15512
|
+
const { onLoad, cache = true } = options;
|
|
15513
|
+
const onLoadRef = useRef(onLoad);
|
|
15514
|
+
onLoadRef.current = onLoad;
|
|
15515
|
+
const onLoadCalledForRef = useRef(null);
|
|
15516
|
+
const inputKey = useMemo(() => inputSignature(input), [input]);
|
|
15517
|
+
const stableInput = useMemo(() => input, [inputKey]);
|
|
15518
|
+
const urls = useMemo(() => getUrls(stableInput), [stableInput]);
|
|
15519
|
+
const cachedResult = useMemo(() => {
|
|
15520
|
+
if (!cache) return null;
|
|
15521
|
+
const textures = store.getState().textures;
|
|
15522
|
+
if (!allUrlsCached(urls, textures)) return null;
|
|
15523
|
+
return buildFromCache(stableInput, textures);
|
|
15524
|
+
}, [cache, urls, stableInput, store]);
|
|
15525
|
+
const loadedTextures = useLoader(
|
|
15526
|
+
getThree().TextureLoader,
|
|
15527
|
+
IsObject(stableInput) ? Object.values(stableInput) : stableInput
|
|
15528
|
+
);
|
|
15529
|
+
const mappedTextures = useMemo(() => {
|
|
15530
|
+
if (cachedResult) return cachedResult;
|
|
15531
|
+
if (IsObject(stableInput)) {
|
|
15532
|
+
const keyed = {};
|
|
15533
|
+
const textureArray = loadedTextures;
|
|
15534
|
+
let i = 0;
|
|
15535
|
+
for (const key in stableInput) keyed[key] = textureArray[i++];
|
|
15536
|
+
return keyed;
|
|
15537
|
+
} else {
|
|
15538
|
+
return loadedTextures;
|
|
15539
|
+
}
|
|
15540
|
+
}, [stableInput, loadedTextures, cachedResult]);
|
|
15541
|
+
useLayoutEffect(() => {
|
|
15542
|
+
if (cachedResult) return;
|
|
15543
|
+
if (onLoadCalledForRef.current === inputKey) return;
|
|
15544
|
+
onLoadCalledForRef.current = inputKey;
|
|
15545
|
+
onLoadRef.current?.(mappedTextures);
|
|
15546
|
+
}, [cachedResult, mappedTextures, inputKey]);
|
|
15547
|
+
useEffect(() => {
|
|
15548
|
+
if (cachedResult) return;
|
|
15549
|
+
if ("initTexture" in renderer) {
|
|
15550
|
+
let textureArray = [];
|
|
15551
|
+
if (Array.isArray(loadedTextures)) {
|
|
15552
|
+
textureArray = loadedTextures;
|
|
15553
|
+
} else if (loadedTextures.isTexture) {
|
|
15554
|
+
textureArray = [loadedTextures];
|
|
15555
|
+
} else if (IsObject(loadedTextures)) {
|
|
15556
|
+
textureArray = Object.values(loadedTextures);
|
|
14898
15557
|
}
|
|
14899
|
-
|
|
14900
|
-
if (
|
|
14901
|
-
|
|
14902
|
-
|
|
14903
|
-
|
|
14904
|
-
|
|
14905
|
-
|
|
14906
|
-
|
|
14907
|
-
|
|
14908
|
-
|
|
14909
|
-
|
|
14910
|
-
|
|
14911
|
-
|
|
14912
|
-
|
|
14913
|
-
|
|
14914
|
-
|
|
14915
|
-
|
|
14916
|
-
|
|
14917
|
-
|
|
14918
|
-
|
|
14919
|
-
|
|
14920
|
-
renderer,
|
|
14921
|
-
primaryStore: primary.store,
|
|
14922
|
-
internal: {
|
|
14923
|
-
...prev.internal,
|
|
14924
|
-
canvasTarget,
|
|
14925
|
-
isMultiCanvas: true,
|
|
14926
|
-
isSecondary: true,
|
|
14927
|
-
targetId: primaryCanvas
|
|
14928
|
-
}
|
|
14929
|
-
}));
|
|
14930
|
-
} else {
|
|
14931
|
-
renderer = await resolveRenderer(rendererConfig, defaultGPUProps, support.Renderer);
|
|
14932
|
-
if (!renderer.hasInitialized?.()) {
|
|
14933
|
-
const size2 = computeInitialSize(canvas, propsSize);
|
|
14934
|
-
if (size2.width > 0 && size2.height > 0) {
|
|
14935
|
-
renderer.setPixelRatio(calculateDpr(dpr));
|
|
14936
|
-
renderer.setSize(size2.width, size2.height, false);
|
|
14937
|
-
}
|
|
14938
|
-
await renderer.init();
|
|
14939
|
-
}
|
|
14940
|
-
const backend = renderer.backend;
|
|
14941
|
-
const isWebGPUBackend = backend && "isWebGPUBackend" in backend;
|
|
14942
|
-
state.internal.actualRenderer = renderer;
|
|
14943
|
-
state.set({ webGPUSupported: isWebGPUBackend, renderer, primaryStore: store });
|
|
14944
|
-
if (canvasId && !state.internal.isSecondary) {
|
|
14945
|
-
const canvasTarget = renderer.getCanvasTarget?.();
|
|
14946
|
-
const unregisterPrimary = registerPrimary(canvasId, renderer, store);
|
|
14947
|
-
state.set((prev) => ({
|
|
14948
|
-
internal: {
|
|
14949
|
-
...prev.internal,
|
|
14950
|
-
canvasTarget,
|
|
14951
|
-
unregisterPrimary
|
|
14952
|
-
}
|
|
14953
|
-
}));
|
|
14954
|
-
}
|
|
14955
|
-
}
|
|
14956
|
-
})().catch((err) => {
|
|
14957
|
-
rendererSetup = null;
|
|
14958
|
-
throw err;
|
|
14959
|
-
});
|
|
15558
|
+
textureArray.forEach((texture) => {
|
|
15559
|
+
if (texture?.isTexture) {
|
|
15560
|
+
renderer.initTexture(texture);
|
|
15561
|
+
}
|
|
15562
|
+
});
|
|
15563
|
+
}
|
|
15564
|
+
}, [renderer, loadedTextures, cachedResult]);
|
|
15565
|
+
useEffect(() => {
|
|
15566
|
+
if (!cache) return;
|
|
15567
|
+
const urlTextureMap = urlTextureEntries(stableInput, mappedTextures);
|
|
15568
|
+
store.setState((state) => {
|
|
15569
|
+
const refs = new Map(state._textureRefs);
|
|
15570
|
+
let textures = state.textures;
|
|
15571
|
+
let added = false;
|
|
15572
|
+
for (const [url, texture] of urlTextureMap) {
|
|
15573
|
+
if (!textures.has(url)) {
|
|
15574
|
+
if (!added) {
|
|
15575
|
+
textures = new Map(textures);
|
|
15576
|
+
added = true;
|
|
15577
|
+
}
|
|
15578
|
+
textures.set(url, texture);
|
|
14960
15579
|
}
|
|
14961
|
-
|
|
14962
|
-
state = store.getState();
|
|
14963
|
-
renderer = state.internal.actualRenderer;
|
|
15580
|
+
refs.set(url, (refs.get(url) ?? 0) + 1);
|
|
14964
15581
|
}
|
|
14965
|
-
|
|
14966
|
-
|
|
14967
|
-
|
|
14968
|
-
|
|
14969
|
-
|
|
14970
|
-
|
|
14971
|
-
|
|
15582
|
+
return added ? { textures, _textureRefs: refs } : { _textureRefs: refs };
|
|
15583
|
+
});
|
|
15584
|
+
unstageTextures(
|
|
15585
|
+
store,
|
|
15586
|
+
urlTextureMap.map(([url]) => url)
|
|
15587
|
+
);
|
|
15588
|
+
return () => store.setState((state) => {
|
|
15589
|
+
const refs = new Map(state._textureRefs);
|
|
15590
|
+
for (const [url] of urlTextureMap) {
|
|
15591
|
+
const next = (refs.get(url) ?? 0) - 1;
|
|
15592
|
+
if (next <= 0) refs.delete(url);
|
|
15593
|
+
else refs.set(url, next);
|
|
14972
15594
|
}
|
|
14973
|
-
|
|
14974
|
-
|
|
14975
|
-
|
|
14976
|
-
|
|
14977
|
-
|
|
14978
|
-
|
|
14979
|
-
|
|
14980
|
-
|
|
14981
|
-
|
|
14982
|
-
|
|
14983
|
-
|
|
14984
|
-
|
|
14985
|
-
|
|
14986
|
-
|
|
14987
|
-
|
|
14988
|
-
|
|
15595
|
+
return { _textureRefs: refs };
|
|
15596
|
+
});
|
|
15597
|
+
}, [cache, stableInput, mappedTextures, store]);
|
|
15598
|
+
if (cache && !cachedResult) stageTextures(store, urlTextureEntries(stableInput, mappedTextures));
|
|
15599
|
+
return mappedTextures;
|
|
15600
|
+
}
|
|
15601
|
+
function urlTextureEntries(input, textures) {
|
|
15602
|
+
if (typeof input === "string") return [[input, textures]];
|
|
15603
|
+
if (Array.isArray(input)) return input.map((url, i) => [url, textures[i]]);
|
|
15604
|
+
const record = textures;
|
|
15605
|
+
return Object.keys(input).map((key) => [input[key], record[key]]);
|
|
15606
|
+
}
|
|
15607
|
+
useTexture.preload = (url) => {
|
|
15608
|
+
whenThree().then((three) => useLoader.preload(three.TextureLoader, url));
|
|
15609
|
+
};
|
|
15610
|
+
useTexture.clear = (input) => {
|
|
15611
|
+
if (hasThree()) useLoader.clear(getThree().TextureLoader, input);
|
|
15612
|
+
};
|
|
15613
|
+
const Texture = ({
|
|
15614
|
+
children,
|
|
15615
|
+
input,
|
|
15616
|
+
onLoad,
|
|
15617
|
+
cache
|
|
15618
|
+
}) => {
|
|
15619
|
+
const options = typeof onLoad === "function" ? { onLoad, cache } : { ...onLoad, cache };
|
|
15620
|
+
const ret = useTexture(input, options);
|
|
15621
|
+
return /* @__PURE__ */ jsx(Fragment, { children: children?.(ret) });
|
|
15622
|
+
};
|
|
15623
|
+
|
|
15624
|
+
function useTextures(selector) {
|
|
15625
|
+
const store = useStore();
|
|
15626
|
+
const registry = useMemo(() => {
|
|
15627
|
+
const getState = store.getState;
|
|
15628
|
+
const setState = store.setState;
|
|
15629
|
+
const getOne = (key) => getState().textures.get(key);
|
|
15630
|
+
return {
|
|
15631
|
+
get all() {
|
|
15632
|
+
return getState().textures;
|
|
15633
|
+
},
|
|
15634
|
+
get(input) {
|
|
15635
|
+
if (typeof input === "string") return getOne(input);
|
|
15636
|
+
if (Array.isArray(input)) return input.map(getOne);
|
|
15637
|
+
const out = {};
|
|
15638
|
+
for (const name in input) out[name] = getOne(input[name]);
|
|
15639
|
+
return out;
|
|
15640
|
+
},
|
|
15641
|
+
has: (key) => getState().textures.has(key),
|
|
15642
|
+
add(keyOrRecord, texture) {
|
|
15643
|
+
setState((state) => {
|
|
15644
|
+
const textures = new Map(state.textures);
|
|
15645
|
+
if (typeof keyOrRecord === "string") {
|
|
15646
|
+
textures.set(keyOrRecord, texture);
|
|
15647
|
+
} else {
|
|
15648
|
+
for (const key in keyOrRecord) textures.set(key, keyOrRecord[key]);
|
|
14989
15649
|
}
|
|
14990
|
-
|
|
15650
|
+
return { textures };
|
|
15651
|
+
});
|
|
15652
|
+
},
|
|
15653
|
+
dispose(key, options) {
|
|
15654
|
+
const state = getState();
|
|
15655
|
+
const refs = state._textureRefs.get(key) ?? 0;
|
|
15656
|
+
if (refs > 0 && !options?.force) {
|
|
15657
|
+
console.warn(
|
|
15658
|
+
`[useTextures] "${key}" still has ${refs} active reference(s); skipping dispose. Pass { force: true } to override.`
|
|
15659
|
+
);
|
|
15660
|
+
return false;
|
|
14991
15661
|
}
|
|
14992
|
-
state.
|
|
14993
|
-
|
|
14994
|
-
|
|
14995
|
-
|
|
14996
|
-
|
|
14997
|
-
|
|
14998
|
-
|
|
14999
|
-
scene = sceneOptions;
|
|
15000
|
-
prepare(scene, store, "", {});
|
|
15001
|
-
} else {
|
|
15002
|
-
scene = new three.Scene();
|
|
15003
|
-
prepare(scene, store, "", {});
|
|
15004
|
-
if (sceneOptions) applyProps(scene, sceneOptions);
|
|
15005
|
-
}
|
|
15006
|
-
state.set((prev) => ({
|
|
15007
|
-
scene,
|
|
15008
|
-
rootScene: scene,
|
|
15009
|
-
internal: { ...prev.internal, container: scene }
|
|
15010
|
-
}));
|
|
15011
|
-
const camera = tempCamera;
|
|
15012
|
-
if (camera && !camera.parent) scene.add(camera);
|
|
15013
|
-
}
|
|
15014
|
-
if (events && !state.events.handlers) {
|
|
15015
|
-
state.set({ events: events(store) });
|
|
15016
|
-
let wasEnabled = true;
|
|
15017
|
-
store.subscribe((state2) => {
|
|
15018
|
-
const { enabled } = state2.events;
|
|
15019
|
-
if (enabled && !wasEnabled) {
|
|
15020
|
-
state2.events.update?.();
|
|
15021
|
-
}
|
|
15022
|
-
wasEnabled = enabled;
|
|
15662
|
+
state.textures.get(key)?.dispose();
|
|
15663
|
+
setState((s) => {
|
|
15664
|
+
const textures = new Map(s.textures);
|
|
15665
|
+
textures.delete(key);
|
|
15666
|
+
const nextRefs = new Map(s._textureRefs);
|
|
15667
|
+
nextRefs.delete(key);
|
|
15668
|
+
return { textures, _textureRefs: nextRefs };
|
|
15023
15669
|
});
|
|
15670
|
+
return true;
|
|
15671
|
+
},
|
|
15672
|
+
disposeAll() {
|
|
15673
|
+
for (const texture of getState().textures.values()) texture.dispose();
|
|
15674
|
+
setState({ textures: /* @__PURE__ */ new Map(), _textureRefs: /* @__PURE__ */ new Map() });
|
|
15024
15675
|
}
|
|
15025
|
-
|
|
15026
|
-
|
|
15027
|
-
|
|
15028
|
-
|
|
15029
|
-
|
|
15676
|
+
};
|
|
15677
|
+
}, [store]);
|
|
15678
|
+
const subscribe = selector ? () => selector(registry) : (state) => state.textures;
|
|
15679
|
+
const selected = useThree(subscribe);
|
|
15680
|
+
return selector ? selected : registry;
|
|
15681
|
+
}
|
|
15682
|
+
|
|
15683
|
+
function useRenderTarget(widthOrOptions, heightOrOptions, options) {
|
|
15684
|
+
const support = useThree((s) => s.internal.support);
|
|
15685
|
+
const size = useThree((s) => s.size);
|
|
15686
|
+
let width;
|
|
15687
|
+
let height;
|
|
15688
|
+
let opts;
|
|
15689
|
+
if (typeof widthOrOptions === "object") {
|
|
15690
|
+
opts = widthOrOptions;
|
|
15691
|
+
} else if (typeof widthOrOptions === "number") {
|
|
15692
|
+
width = widthOrOptions;
|
|
15693
|
+
if (typeof heightOrOptions === "object") {
|
|
15694
|
+
height = widthOrOptions;
|
|
15695
|
+
opts = heightOrOptions;
|
|
15696
|
+
} else if (typeof heightOrOptions === "number") {
|
|
15697
|
+
height = heightOrOptions;
|
|
15698
|
+
opts = options;
|
|
15699
|
+
} else {
|
|
15700
|
+
height = widthOrOptions;
|
|
15701
|
+
}
|
|
15702
|
+
}
|
|
15703
|
+
return useMemo(() => {
|
|
15704
|
+
const w = width ?? size.width;
|
|
15705
|
+
const h = height ?? size.height;
|
|
15706
|
+
const Target = support.RenderTarget;
|
|
15707
|
+
return new Target(w, h, opts);
|
|
15708
|
+
}, [width, height, size.width, size.height, opts, support]);
|
|
15709
|
+
}
|
|
15710
|
+
|
|
15711
|
+
const presetsObj = {
|
|
15712
|
+
apartment: "lebombo_1k.hdr",
|
|
15713
|
+
city: "potsdamer_platz_1k.hdr",
|
|
15714
|
+
dawn: "kiara_1_dawn_1k.hdr",
|
|
15715
|
+
forest: "forest_slope_1k.hdr",
|
|
15716
|
+
lobby: "st_fagans_interior_1k.hdr",
|
|
15717
|
+
night: "dikhololo_night_1k.hdr",
|
|
15718
|
+
park: "rooitou_park_1k.hdr",
|
|
15719
|
+
studio: "studio_small_03_1k.hdr",
|
|
15720
|
+
sunset: "venice_sunset_1k.hdr",
|
|
15721
|
+
warehouse: "empty_warehouse_01_1k.hdr"
|
|
15722
|
+
};
|
|
15723
|
+
|
|
15724
|
+
const CUBEMAP_ROOT = "https://raw.githack.com/pmndrs/drei-assets/456060a26bbeb8fdf79326f224b6d99b8bcce736/hdri/";
|
|
15725
|
+
const isArray = (arr) => Array.isArray(arr);
|
|
15726
|
+
const defaultFiles = ["/px.png", "/nx.png", "/py.png", "/ny.png", "/pz.png", "/nz.png"];
|
|
15727
|
+
const loadedLoaders = /* @__PURE__ */ new Map();
|
|
15728
|
+
const pendingLoaders = /* @__PURE__ */ new Map();
|
|
15729
|
+
function loadLoader(format) {
|
|
15730
|
+
let pending = pendingLoaders.get(format);
|
|
15731
|
+
if (!pending) {
|
|
15732
|
+
pending = importLoader(format).then(
|
|
15733
|
+
(loader) => {
|
|
15734
|
+
loadedLoaders.set(format, loader);
|
|
15735
|
+
return loader;
|
|
15736
|
+
},
|
|
15737
|
+
(error) => {
|
|
15738
|
+
pendingLoaders.delete(format);
|
|
15739
|
+
throw error;
|
|
15030
15740
|
}
|
|
15031
|
-
|
|
15032
|
-
|
|
15033
|
-
|
|
15034
|
-
|
|
15035
|
-
|
|
15036
|
-
|
|
15037
|
-
|
|
15038
|
-
|
|
15039
|
-
|
|
15040
|
-
|
|
15041
|
-
|
|
15042
|
-
|
|
15043
|
-
|
|
15044
|
-
|
|
15045
|
-
|
|
15046
|
-
|
|
15047
|
-
|
|
15048
|
-
|
|
15049
|
-
|
|
15050
|
-
|
|
15051
|
-
|
|
15052
|
-
|
|
15053
|
-
|
|
15054
|
-
|
|
15055
|
-
|
|
15056
|
-
|
|
15057
|
-
|
|
15058
|
-
|
|
15059
|
-
|
|
15060
|
-
|
|
15061
|
-
|
|
15062
|
-
|
|
15063
|
-
|
|
15064
|
-
|
|
15065
|
-
|
|
15066
|
-
|
|
15067
|
-
|
|
15068
|
-
|
|
15069
|
-
|
|
15070
|
-
|
|
15071
|
-
|
|
15072
|
-
|
|
15073
|
-
|
|
15074
|
-
|
|
15075
|
-
|
|
15076
|
-
|
|
15077
|
-
|
|
15078
|
-
|
|
15079
|
-
|
|
15080
|
-
|
|
15081
|
-
|
|
15082
|
-
|
|
15083
|
-
};
|
|
15084
|
-
if (typeof renderer.xr?.addEventListener === "function") xr.connect();
|
|
15085
|
-
state.set({ xr });
|
|
15086
|
-
}
|
|
15087
|
-
if (renderer.shadowMap && !is.equ(shadows, lastConfiguredProps.shadows, shallowLoose)) {
|
|
15088
|
-
lastConfiguredProps.shadows = shadows;
|
|
15089
|
-
const oldEnabled = renderer.shadowMap.enabled;
|
|
15090
|
-
const oldType = renderer.shadowMap.type;
|
|
15091
|
-
renderer.shadowMap.enabled = !!shadows;
|
|
15092
|
-
if (is.boo(shadows)) {
|
|
15093
|
-
renderer.shadowMap.type = three.PCFShadowMap;
|
|
15094
|
-
} else if (is.str(shadows)) {
|
|
15095
|
-
if (shadows === "soft") {
|
|
15096
|
-
notifyDepreciated({
|
|
15097
|
-
heading: 'shadows="soft" is deprecated',
|
|
15098
|
-
body: "Three has depreciated soft and improved basic PCFShadows, we converted for you.",
|
|
15099
|
-
link: "https://github.com/mrdoob/three.js/wiki/Migration-Guide?utm_source=chatgpt.com#181--182"
|
|
15741
|
+
);
|
|
15742
|
+
pendingLoaders.set(format, pending);
|
|
15743
|
+
}
|
|
15744
|
+
return pending;
|
|
15745
|
+
}
|
|
15746
|
+
async function importLoader(format) {
|
|
15747
|
+
let loader;
|
|
15748
|
+
switch (format) {
|
|
15749
|
+
case "cube":
|
|
15750
|
+
loader = getThree().CubeTextureLoader;
|
|
15751
|
+
break;
|
|
15752
|
+
case "hdr-cube":
|
|
15753
|
+
loader = (await import('three/examples/jsm/loaders/HDRCubeTextureLoader.js')).HDRCubeTextureLoader;
|
|
15754
|
+
break;
|
|
15755
|
+
case "hdr":
|
|
15756
|
+
loader = (await import('three/examples/jsm/loaders/HDRLoader.js')).HDRLoader;
|
|
15757
|
+
break;
|
|
15758
|
+
case "exr":
|
|
15759
|
+
loader = (await import('three/examples/jsm/loaders/EXRLoader.js')).EXRLoader;
|
|
15760
|
+
break;
|
|
15761
|
+
case "jpg":
|
|
15762
|
+
loader = createJpegLoader((await import('three/examples/jsm/loaders/UltraHDRLoader.js')).UltraHDRLoader);
|
|
15763
|
+
break;
|
|
15764
|
+
case "ldr":
|
|
15765
|
+
loader = getThree().TextureLoader;
|
|
15766
|
+
break;
|
|
15767
|
+
}
|
|
15768
|
+
return loader;
|
|
15769
|
+
}
|
|
15770
|
+
function createJpegLoader(UltraHDR) {
|
|
15771
|
+
return class JpegEnvironmentLoader extends UltraHDR {
|
|
15772
|
+
// @ts-expect-error A plain JPEG resolves to a Texture, not the DataTexture UltraHDRLoader declares
|
|
15773
|
+
load(url, onLoad, onProgress, onError) {
|
|
15774
|
+
const three = getThree();
|
|
15775
|
+
const file = new three.FileLoader(this.manager);
|
|
15776
|
+
file.setResponseType("arraybuffer");
|
|
15777
|
+
file.setRequestHeader(this.requestHeader);
|
|
15778
|
+
file.setPath(this.path);
|
|
15779
|
+
file.setWithCredentials(this.withCredentials);
|
|
15780
|
+
file.load(
|
|
15781
|
+
url,
|
|
15782
|
+
(buffer) => {
|
|
15783
|
+
try {
|
|
15784
|
+
this.parse(buffer, (texData) => {
|
|
15785
|
+
const { data } = texData;
|
|
15786
|
+
const texture = new three.DataTexture(data, texData.width, texData.height, three.RGBAFormat, texData.type);
|
|
15787
|
+
texture.minFilter = three.LinearMipMapLinearFilter;
|
|
15788
|
+
texture.magFilter = three.LinearFilter;
|
|
15789
|
+
texture.generateMipmaps = true;
|
|
15790
|
+
texture.flipY = true;
|
|
15791
|
+
texture.needsUpdate = true;
|
|
15792
|
+
onLoad?.(texture);
|
|
15100
15793
|
});
|
|
15101
|
-
}
|
|
15102
|
-
|
|
15103
|
-
|
|
15104
|
-
|
|
15105
|
-
|
|
15106
|
-
|
|
15107
|
-
|
|
15108
|
-
|
|
15109
|
-
|
|
15110
|
-
|
|
15111
|
-
|
|
15112
|
-
|
|
15113
|
-
|
|
15114
|
-
|
|
15115
|
-
|
|
15116
|
-
if (!configured) {
|
|
15117
|
-
renderer.outputColorSpace = three.SRGBColorSpace;
|
|
15118
|
-
renderer.toneMapping = three.ACESFilmicToneMapping;
|
|
15119
|
-
}
|
|
15120
|
-
const textureColorSpace = requestedTextureColorSpace ?? three.SRGBColorSpace;
|
|
15121
|
-
if (textureColorSpace !== lastConfiguredProps.textureColorSpace) {
|
|
15122
|
-
if (state.textureColorSpace !== textureColorSpace) state.set(() => ({ textureColorSpace }));
|
|
15123
|
-
lastConfiguredProps.textureColorSpace = textureColorSpace;
|
|
15124
|
-
}
|
|
15125
|
-
const r3fProps = ["textureColorSpace"];
|
|
15126
|
-
const constructorOnlyProps = ["samples", "antialias", "alpha", "canvas", "powerPreference"];
|
|
15127
|
-
const nonApplyProps = [...r3fProps, ...constructorOnlyProps];
|
|
15128
|
-
if (glConfig && !is.fun(glConfig) && !isRenderer(glConfig) && !is.equ(glConfig, renderer, shallowLoose)) {
|
|
15129
|
-
const glProps = {};
|
|
15130
|
-
for (const key in glConfig) {
|
|
15131
|
-
if (!nonApplyProps.includes(key)) glProps[key] = glConfig[key];
|
|
15132
|
-
}
|
|
15133
|
-
applyProps(renderer, glProps);
|
|
15134
|
-
}
|
|
15135
|
-
if (rendererConfig && !is.fun(rendererConfig) && !isRenderer(rendererConfig) && state.renderer) {
|
|
15136
|
-
const currentRenderer = state.renderer;
|
|
15137
|
-
if (!is.equ(rendererConfig, currentRenderer, shallowLoose)) {
|
|
15138
|
-
const rendererProps = {};
|
|
15139
|
-
for (const key in rendererConfig) {
|
|
15140
|
-
if (!nonApplyProps.includes(key)) rendererProps[key] = rendererConfig[key];
|
|
15141
|
-
}
|
|
15142
|
-
applyProps(currentRenderer, rendererProps);
|
|
15143
|
-
}
|
|
15144
|
-
}
|
|
15145
|
-
const scheduler = getScheduler();
|
|
15146
|
-
const rootId = state.internal.rootId;
|
|
15147
|
-
if (!rootId) {
|
|
15148
|
-
const newRootId = canvasId || scheduler.generateRootId();
|
|
15149
|
-
const unregisterRoot = scheduler.registerRoot(newRootId, {
|
|
15150
|
-
getState: () => store.getState(),
|
|
15151
|
-
onError: (err) => store.getState().setError(err),
|
|
15152
|
-
frameloop: store.getState().frameloop,
|
|
15153
|
-
before: schedulerConfig?.before,
|
|
15154
|
-
after: schedulerConfig?.after,
|
|
15155
|
-
order: schedulerConfig?.order
|
|
15156
|
-
});
|
|
15157
|
-
const unregisterCanvasTarget = scheduler.register(
|
|
15158
|
-
() => {
|
|
15159
|
-
const state2 = store.getState();
|
|
15160
|
-
const canvasTarget = state2.internal.canvasTarget;
|
|
15161
|
-
if (canvasTarget) {
|
|
15162
|
-
const renderer2 = state2.internal.actualRenderer;
|
|
15163
|
-
if (renderer2.getCanvasTarget() !== canvasTarget) renderer2.setCanvasTarget(canvasTarget);
|
|
15164
|
-
if (state2.internal.canvasTargetSizeDirty) {
|
|
15165
|
-
state2.internal.canvasTargetSizeDirty = false;
|
|
15166
|
-
renderer2.backend?.updateSize?.();
|
|
15794
|
+
} catch {
|
|
15795
|
+
const objectURL = URL.createObjectURL(new Blob([buffer], { type: "image/jpeg" }));
|
|
15796
|
+
const settle = () => URL.revokeObjectURL(objectURL);
|
|
15797
|
+
new three.ImageLoader().load(
|
|
15798
|
+
objectURL,
|
|
15799
|
+
(image) => {
|
|
15800
|
+
settle();
|
|
15801
|
+
const texture = new three.Texture(image);
|
|
15802
|
+
texture.needsUpdate = true;
|
|
15803
|
+
onLoad?.(texture);
|
|
15804
|
+
},
|
|
15805
|
+
void 0,
|
|
15806
|
+
(error) => {
|
|
15807
|
+
settle();
|
|
15808
|
+
onError?.(error);
|
|
15167
15809
|
}
|
|
15168
|
-
|
|
15169
|
-
},
|
|
15170
|
-
{
|
|
15171
|
-
id: `${newRootId}_canvasTarget`,
|
|
15172
|
-
rootId: newRootId,
|
|
15173
|
-
phase: "start",
|
|
15174
|
-
system: true
|
|
15175
|
-
}
|
|
15176
|
-
);
|
|
15177
|
-
const unregisterEventsFlush = scheduler.register(
|
|
15178
|
-
() => {
|
|
15179
|
-
const state2 = store.getState();
|
|
15180
|
-
state2.events.flush?.();
|
|
15181
|
-
},
|
|
15182
|
-
{
|
|
15183
|
-
id: `${newRootId}_events`,
|
|
15184
|
-
rootId: newRootId,
|
|
15185
|
-
phase: "input",
|
|
15186
|
-
system: true
|
|
15187
|
-
}
|
|
15188
|
-
);
|
|
15189
|
-
const unregisterFrustum = scheduler.register(
|
|
15190
|
-
() => {
|
|
15191
|
-
const state2 = store.getState();
|
|
15192
|
-
if (state2.autoUpdateFrustum && state2.camera) {
|
|
15193
|
-
updateFrustum(state2.camera, state2.frustum);
|
|
15194
|
-
}
|
|
15195
|
-
},
|
|
15196
|
-
{
|
|
15197
|
-
id: `${newRootId}_frustum`,
|
|
15198
|
-
rootId: newRootId,
|
|
15199
|
-
before: "render",
|
|
15200
|
-
system: true
|
|
15201
|
-
}
|
|
15202
|
-
);
|
|
15203
|
-
const unregisterVisibility = scheduler.register(
|
|
15204
|
-
() => {
|
|
15205
|
-
const state2 = store.getState();
|
|
15206
|
-
checkVisibility(state2);
|
|
15207
|
-
},
|
|
15208
|
-
{
|
|
15209
|
-
id: `${newRootId}_visibility`,
|
|
15210
|
-
rootId: newRootId,
|
|
15211
|
-
before: "render",
|
|
15212
|
-
system: true,
|
|
15213
|
-
after: `${newRootId}_frustum`
|
|
15214
|
-
}
|
|
15215
|
-
);
|
|
15216
|
-
const unregisterRender = scheduler.register(
|
|
15217
|
-
() => {
|
|
15218
|
-
const state2 = store.getState();
|
|
15219
|
-
const renderer2 = state2.internal.actualRenderer;
|
|
15220
|
-
const userHandlesRender = scheduler.hasUserJobsInPhase("render", newRootId);
|
|
15221
|
-
if (userHandlesRender || state2.internal.priority) return;
|
|
15222
|
-
try {
|
|
15223
|
-
const renderOverride = state2.internal.renderOverride;
|
|
15224
|
-
if (renderOverride) renderOverride();
|
|
15225
|
-
else if (renderer2?.render) renderer2.render(state2.scene, state2.camera);
|
|
15226
|
-
} catch (error) {
|
|
15227
|
-
state2.setError(error instanceof Error ? error : new Error(String(error)));
|
|
15228
|
-
}
|
|
15229
|
-
},
|
|
15230
|
-
{
|
|
15231
|
-
// Use canvas ID directly as job ID if available, otherwise use generated rootId
|
|
15232
|
-
id: canvasId || `${newRootId}_render`,
|
|
15233
|
-
rootId: newRootId,
|
|
15234
|
-
phase: "render",
|
|
15235
|
-
system: true,
|
|
15236
|
-
// Internal flag: this is a system job, not user-controlled
|
|
15237
|
-
// FPS throttles only the default render job; Canvas ordering belongs to the root.
|
|
15238
|
-
...schedulerConfig?.fps && { fps: schedulerConfig.fps }
|
|
15239
|
-
}
|
|
15240
|
-
);
|
|
15241
|
-
state.set((state2) => ({
|
|
15242
|
-
internal: {
|
|
15243
|
-
...state2.internal,
|
|
15244
|
-
rootId: newRootId,
|
|
15245
|
-
unregisterRoot: () => {
|
|
15246
|
-
unregisterRoot();
|
|
15247
|
-
unregisterCanvasTarget();
|
|
15248
|
-
unregisterEventsFlush();
|
|
15249
|
-
unregisterFrustum();
|
|
15250
|
-
unregisterVisibility();
|
|
15251
|
-
unregisterRender();
|
|
15252
|
-
},
|
|
15253
|
-
scheduler
|
|
15810
|
+
);
|
|
15254
15811
|
}
|
|
15255
|
-
}
|
|
15256
|
-
|
|
15257
|
-
|
|
15258
|
-
|
|
15259
|
-
scheduler.setRootConstraints(rootId, {
|
|
15260
|
-
before: schedulerConfig?.before,
|
|
15261
|
-
after: schedulerConfig?.after
|
|
15262
|
-
});
|
|
15263
|
-
}
|
|
15264
|
-
if (schedulerConfig?.order !== lastConfiguredProps.schedulerOrder) {
|
|
15265
|
-
scheduler.setRootOrder(rootId, schedulerConfig?.order ?? 0);
|
|
15266
|
-
}
|
|
15267
|
-
}
|
|
15268
|
-
lastConfiguredProps.schedulerBefore = schedulerConfig?.before;
|
|
15269
|
-
lastConfiguredProps.schedulerAfter = schedulerConfig?.after;
|
|
15270
|
-
lastConfiguredProps.schedulerOrder = schedulerConfig?.order;
|
|
15271
|
-
attachRootExtensions(store);
|
|
15272
|
-
onCreated = onCreatedCallback;
|
|
15273
|
-
configured = true;
|
|
15274
|
-
resolve();
|
|
15275
|
-
return this;
|
|
15276
|
-
},
|
|
15277
|
-
render(children) {
|
|
15278
|
-
if (!configured && !pending) this.configure();
|
|
15279
|
-
pending.then(() => {
|
|
15280
|
-
reconciler.updateContainer(
|
|
15281
|
-
/* @__PURE__ */ jsx(Provider, { store, children, onCreated, rootElement: canvas }),
|
|
15282
|
-
fiber,
|
|
15283
|
-
null,
|
|
15284
|
-
() => void 0
|
|
15285
|
-
);
|
|
15286
|
-
});
|
|
15287
|
-
return store;
|
|
15288
|
-
},
|
|
15289
|
-
unmount() {
|
|
15290
|
-
unmountComponentAtNode(canvas);
|
|
15812
|
+
},
|
|
15813
|
+
onProgress,
|
|
15814
|
+
onError
|
|
15815
|
+
);
|
|
15291
15816
|
}
|
|
15292
15817
|
};
|
|
15293
15818
|
}
|
|
15294
|
-
|
|
15295
|
-
|
|
15296
|
-
|
|
15297
|
-
onCreated,
|
|
15298
|
-
rootElement
|
|
15299
|
-
}) {
|
|
15300
|
-
useIsomorphicLayoutEffect(() => {
|
|
15301
|
-
const state = store.getState();
|
|
15302
|
-
state.set((state2) => ({ internal: { ...state2.internal, active: true } }));
|
|
15303
|
-
if (onCreated) onCreated(state);
|
|
15304
|
-
if (!store.getState().events.connected) state.events.connect?.(rootElement);
|
|
15305
|
-
}, []);
|
|
15306
|
-
return /* @__PURE__ */ jsx(context.Provider, { value: store, children });
|
|
15819
|
+
const LOADER_KEY = Symbol("r3f-environment-loader");
|
|
15820
|
+
function useEnvironmentLoader(format) {
|
|
15821
|
+
return suspend(() => loadLoader(format), [LOADER_KEY, format]);
|
|
15307
15822
|
}
|
|
15308
|
-
function
|
|
15309
|
-
|
|
15310
|
-
|
|
15311
|
-
|
|
15312
|
-
|
|
15313
|
-
|
|
15314
|
-
|
|
15315
|
-
|
|
15316
|
-
|
|
15317
|
-
|
|
15318
|
-
|
|
15319
|
-
|
|
15823
|
+
function useEnvironment({
|
|
15824
|
+
files = defaultFiles,
|
|
15825
|
+
path = "",
|
|
15826
|
+
preset = void 0,
|
|
15827
|
+
colorSpace = void 0,
|
|
15828
|
+
extensions
|
|
15829
|
+
} = {}) {
|
|
15830
|
+
if (preset) {
|
|
15831
|
+
validatePreset(preset);
|
|
15832
|
+
files = presetsObj[preset];
|
|
15833
|
+
path = CUBEMAP_ROOT;
|
|
15834
|
+
}
|
|
15835
|
+
const multiFile = isArray(files);
|
|
15836
|
+
const { format, isCubemap } = getFormat(files);
|
|
15837
|
+
if (!format) throw new Error("useEnvironment: Unrecognized file extension: " + files);
|
|
15838
|
+
const loader = useEnvironmentLoader(format);
|
|
15839
|
+
const loaderResult = useLoader(
|
|
15840
|
+
loader,
|
|
15841
|
+
multiFile ? [files] : files,
|
|
15842
|
+
(loader2) => {
|
|
15843
|
+
loader2.setPath?.(path);
|
|
15844
|
+
if (extensions) extensions(loader2);
|
|
15320
15845
|
}
|
|
15321
|
-
|
|
15322
|
-
|
|
15323
|
-
|
|
15324
|
-
|
|
15325
|
-
|
|
15326
|
-
|
|
15327
|
-
|
|
15328
|
-
|
|
15329
|
-
|
|
15330
|
-
|
|
15331
|
-
|
|
15332
|
-
|
|
15333
|
-
|
|
15334
|
-
|
|
15335
|
-
|
|
15336
|
-
|
|
15337
|
-
|
|
15338
|
-
|
|
15339
|
-
|
|
15340
|
-
|
|
15341
|
-
|
|
15342
|
-
|
|
15343
|
-
|
|
15344
|
-
|
|
15345
|
-
|
|
15346
|
-
|
|
15347
|
-
|
|
15348
|
-
|
|
15846
|
+
);
|
|
15847
|
+
const texture = multiFile ? (
|
|
15848
|
+
// @ts-ignore
|
|
15849
|
+
loaderResult[0]
|
|
15850
|
+
) : loaderResult;
|
|
15851
|
+
const three = getThree();
|
|
15852
|
+
texture.mapping = isCubemap ? three.CubeReflectionMapping : three.EquirectangularReflectionMapping;
|
|
15853
|
+
const hdr = format === "hdr-cube" || texture.isDataTexture === true;
|
|
15854
|
+
texture.colorSpace = colorSpace ?? (hdr ? "srgb-linear" : "srgb");
|
|
15855
|
+
return texture;
|
|
15856
|
+
}
|
|
15857
|
+
const preloadDefaultOptions = {
|
|
15858
|
+
files: defaultFiles,
|
|
15859
|
+
path: "",
|
|
15860
|
+
preset: void 0,
|
|
15861
|
+
extensions: void 0
|
|
15862
|
+
};
|
|
15863
|
+
useEnvironment.preload = (preloadOptions) => {
|
|
15864
|
+
const options = { ...preloadDefaultOptions, ...preloadOptions };
|
|
15865
|
+
let { files, path = "" } = options;
|
|
15866
|
+
const { preset, extensions } = options;
|
|
15867
|
+
if (preset) {
|
|
15868
|
+
validatePreset(preset);
|
|
15869
|
+
files = presetsObj[preset];
|
|
15870
|
+
path = CUBEMAP_ROOT;
|
|
15871
|
+
}
|
|
15872
|
+
const { format } = getFormat(files);
|
|
15873
|
+
if (!format) throw new Error("useEnvironment: Unrecognized file extension: " + files);
|
|
15874
|
+
const input = isArray(files) ? [files] : files;
|
|
15875
|
+
loadLoader(format).then((loader) => {
|
|
15876
|
+
useLoader.preload(loader, input, (loader2) => {
|
|
15877
|
+
loader2.setPath?.(path);
|
|
15878
|
+
if (extensions) extensions(loader2);
|
|
15879
|
+
});
|
|
15880
|
+
});
|
|
15881
|
+
};
|
|
15882
|
+
const clearDefaultOptins = {
|
|
15883
|
+
files: defaultFiles,
|
|
15884
|
+
preset: void 0
|
|
15885
|
+
};
|
|
15886
|
+
useEnvironment.clear = (clearOptions) => {
|
|
15887
|
+
const options = { ...clearDefaultOptins, ...clearOptions };
|
|
15888
|
+
let { files } = options;
|
|
15889
|
+
const { preset } = options;
|
|
15890
|
+
if (preset) {
|
|
15891
|
+
validatePreset(preset);
|
|
15892
|
+
files = presetsObj[preset];
|
|
15893
|
+
}
|
|
15894
|
+
const { format } = getFormat(files);
|
|
15895
|
+
if (!format) throw new Error("useEnvironment: Unrecognized file extension: " + files);
|
|
15896
|
+
const input = isArray(files) ? [files] : files;
|
|
15897
|
+
const clear = (loader2) => useLoader.clear(loader2, input);
|
|
15898
|
+
const loader = loadedLoaders.get(format);
|
|
15899
|
+
if (loader) {
|
|
15900
|
+
clear(loader);
|
|
15901
|
+
} else {
|
|
15902
|
+
const pending = pendingLoaders.get(format);
|
|
15903
|
+
if (pending) void pending.then(clear, () => {
|
|
15349
15904
|
});
|
|
15350
15905
|
}
|
|
15906
|
+
};
|
|
15907
|
+
function validatePreset(preset) {
|
|
15908
|
+
if (!(preset in presetsObj)) throw new Error("Preset must be one of: " + Object.keys(presetsObj).join(", "));
|
|
15909
|
+
}
|
|
15910
|
+
function getFormat(files) {
|
|
15911
|
+
const isCubemap = isArray(files) && files.length === 6;
|
|
15912
|
+
const firstEntry = isArray(files) ? files[0] : files;
|
|
15913
|
+
const firstExtension = firstEntry.split(/[?#]/)[0].split(".").pop()?.toLowerCase();
|
|
15914
|
+
let format;
|
|
15915
|
+
if (isCubemap) format = firstExtension === "hdr" ? "hdr-cube" : "cube";
|
|
15916
|
+
else if (firstEntry.startsWith("data:application/exr")) format = "exr";
|
|
15917
|
+
else if (firstEntry.startsWith("data:application/hdr")) format = "hdr";
|
|
15918
|
+
else if (firstEntry.startsWith("data:image/jpeg")) format = "jpg";
|
|
15919
|
+
else if (firstExtension === "hdr" || firstExtension === "exr") format = firstExtension;
|
|
15920
|
+
else if (firstExtension === "jpg" || firstExtension === "jpeg") format = "jpg";
|
|
15921
|
+
else if (/^data:image\/(png|webp|avif|gif)[;,]/.test(firstEntry)) format = "ldr";
|
|
15922
|
+
else if (["png", "webp", "avif", "gif"].includes(firstExtension)) format = "ldr";
|
|
15923
|
+
return { format, isCubemap };
|
|
15924
|
+
}
|
|
15925
|
+
|
|
15926
|
+
function useInstanceHandle(ref) {
|
|
15927
|
+
const instance = useRef(null);
|
|
15928
|
+
useImperativeHandle(instance, () => ref.current.__r3f, [ref]);
|
|
15929
|
+
return instance;
|
|
15930
|
+
}
|
|
15931
|
+
function useGraph(object) {
|
|
15932
|
+
return useMemo(() => buildGraph(object), [object]);
|
|
15351
15933
|
}
|
|
15934
|
+
|
|
15352
15935
|
function createPortal(children, container, state) {
|
|
15353
15936
|
return /* @__PURE__ */ jsx(Portal, { children, container, state });
|
|
15354
15937
|
}
|
|
@@ -15385,16 +15968,13 @@ function PortalInner({ state = {}, children, container }) {
|
|
|
15385
15968
|
const [portalScene] = useState(() => {
|
|
15386
15969
|
if ("isScene" in container && container.isScene) return container;
|
|
15387
15970
|
if (!injectScene) return container;
|
|
15388
|
-
|
|
15389
|
-
container.add(scene);
|
|
15390
|
-
return scene;
|
|
15971
|
+
return new (getThree()).Scene();
|
|
15391
15972
|
});
|
|
15392
15973
|
useIsomorphicLayoutEffect(() => {
|
|
15974
|
+
if (portalScene === container || !injectScene) return;
|
|
15975
|
+
container.add(portalScene);
|
|
15393
15976
|
return () => {
|
|
15394
|
-
|
|
15395
|
-
container.remove(portalScene);
|
|
15396
|
-
dispose(portalScene);
|
|
15397
|
-
}
|
|
15977
|
+
container.remove(portalScene);
|
|
15398
15978
|
};
|
|
15399
15979
|
}, [portalScene, container, injectScene]);
|
|
15400
15980
|
const lastRootState = useRef(null);
|
|
@@ -15403,6 +15983,7 @@ function PortalInner({ state = {}, children, container }) {
|
|
|
15403
15983
|
const lastRoot = lastRootState.current;
|
|
15404
15984
|
if (lastRoot) {
|
|
15405
15985
|
for (const key in rootState) {
|
|
15986
|
+
if (isAccessor(rootState, key)) continue;
|
|
15406
15987
|
const field = key;
|
|
15407
15988
|
const changed = rootState[field] !== lastRoot[field];
|
|
15408
15989
|
const inherited = !(key in rest) && injectState[field] === lastRoot[field];
|
|
@@ -15419,11 +16000,7 @@ function PortalInner({ state = {}, children, container }) {
|
|
|
15419
16000
|
if (camera !== rootState.camera) updateCamera(camera, resolvedSize);
|
|
15420
16001
|
}
|
|
15421
16002
|
const set = injectState.set;
|
|
15422
|
-
return {
|
|
15423
|
-
// The intersect consists of the previous root state
|
|
15424
|
-
...rootState,
|
|
15425
|
-
...injectState,
|
|
15426
|
-
...followed,
|
|
16003
|
+
return Object.assign(cloneState(rootState, injectState, followed), {
|
|
15427
16004
|
// Portals have their own scene - always a real THREE.Scene (injected if needed)
|
|
15428
16005
|
scene: portalScene,
|
|
15429
16006
|
// rootScene always points to the actual THREE.Scene, even inside portals
|
|
@@ -15438,13 +16015,19 @@ function PortalInner({ state = {}, children, container }) {
|
|
|
15438
16015
|
size: resolvedSize,
|
|
15439
16016
|
viewport: { ...rootState.viewport, ...viewport },
|
|
15440
16017
|
// Layers are allowed to override events
|
|
15441
|
-
setEvents: (events2) => set((state2) => ({
|
|
15442
|
-
// Container for child attachment - the portalScene (injected or container itself)
|
|
15443
|
-
|
|
15444
|
-
|
|
16018
|
+
setEvents: (events2) => set((state2) => ({ events: { ...state2.events, ...events2 } })),
|
|
16019
|
+
// Container for child attachment - the portalScene (injected or container itself). A portal
|
|
16020
|
+
// renders with its parent's renderer, which `renderer` / `gl` read from `actualRenderer`
|
|
16021
|
+
internal: {
|
|
16022
|
+
...rootState.internal,
|
|
16023
|
+
...injectState.internal,
|
|
16024
|
+
actualRenderer: rootState.internal.actualRenderer,
|
|
16025
|
+
container: portalScene
|
|
16026
|
+
}
|
|
16027
|
+
});
|
|
15445
16028
|
});
|
|
15446
16029
|
const usePortalStore = useMemo(() => {
|
|
15447
|
-
const store = createWithEqualityFn((set, get) => ({ ...rest, set, get }));
|
|
16030
|
+
const store = createWithEqualityFn(keepAccessors((set, get) => ({ ...rest, set, get })));
|
|
15448
16031
|
const onMutate = (prev) => store.setState((state2) => inject.current(prev, state2));
|
|
15449
16032
|
onMutate(previousRoot.getState());
|
|
15450
16033
|
return store;
|
|
@@ -15463,9 +16046,6 @@ function PortalInner({ state = {}, children, container }) {
|
|
|
15463
16046
|
) })
|
|
15464
16047
|
);
|
|
15465
16048
|
}
|
|
15466
|
-
function flushSync(fn) {
|
|
15467
|
-
return reconciler.flushSyncFromReconciler(fn);
|
|
15468
|
-
}
|
|
15469
16049
|
|
|
15470
16050
|
const isRef = (obj) => obj.current && obj.current.isScene;
|
|
15471
16051
|
const resolveScene = (scene) => isRef(scene) ? scene.current : scene;
|
|
@@ -15657,12 +16237,12 @@ function EnvironmentColor({ color, scene }) {
|
|
|
15657
16237
|
function EnvironmentDualSource(props) {
|
|
15658
16238
|
const { backgroundFiles, ...envProps } = props;
|
|
15659
16239
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
15660
|
-
/* @__PURE__ */ jsx(EnvironmentCube, { ...envProps, background: false }),
|
|
15661
|
-
/* @__PURE__ */ jsx(EnvironmentCube, { ...props, files: backgroundFiles, background: "only" })
|
|
16240
|
+
(envProps.files || envProps.preset) && /* @__PURE__ */ jsx(EnvironmentCube, { ...envProps, background: false }),
|
|
16241
|
+
/* @__PURE__ */ jsx(EnvironmentCube, { ...props, files: backgroundFiles, preset: void 0, background: "only" })
|
|
15662
16242
|
] });
|
|
15663
16243
|
}
|
|
15664
16244
|
function Environment(props) {
|
|
15665
|
-
if (props.color && !props.files && !props.preset && !props.map) {
|
|
16245
|
+
if (props.color !== void 0 && !props.files && !props.preset && !props.map) {
|
|
15666
16246
|
return /* @__PURE__ */ jsx(EnvironmentColor, { ...props });
|
|
15667
16247
|
}
|
|
15668
16248
|
if (props.backgroundFiles && props.backgroundFiles !== props.files) {
|
|
@@ -15672,7 +16252,7 @@ function Environment(props) {
|
|
|
15672
16252
|
}
|
|
15673
16253
|
|
|
15674
16254
|
function parseBackground(background) {
|
|
15675
|
-
if (
|
|
16255
|
+
if (background === void 0 || background === null || background === "") return null;
|
|
15676
16256
|
if (typeof background === "object" && !background.isColor) {
|
|
15677
16257
|
const { backgroundMap, envMap, files, preset, ...rest } = background;
|
|
15678
16258
|
return {
|
|
@@ -15690,7 +16270,7 @@ function parseBackground(background) {
|
|
|
15690
16270
|
if (background in presetsObj) {
|
|
15691
16271
|
return { preset: background, background: true };
|
|
15692
16272
|
}
|
|
15693
|
-
if (/^(https
|
|
16273
|
+
if (/^(https?:\/\/|\/|\.\/|\.\.\/|data:)|\.(hdr|exr|jpg|jpeg|png|webp|avif|gif)([?#].*)?$/i.test(background)) {
|
|
15694
16274
|
return { files: background, background: true };
|
|
15695
16275
|
}
|
|
15696
16276
|
return { color: background, background: true };
|
|
@@ -15701,19 +16281,6 @@ function parseBackground(background) {
|
|
|
15701
16281
|
return null;
|
|
15702
16282
|
}
|
|
15703
16283
|
|
|
15704
|
-
function parseRendererConfig(rendererProp) {
|
|
15705
|
-
const isRendererConfig = typeof rendererProp === "object" && rendererProp !== null && !("render" in rendererProp) && ("primaryCanvas" in rendererProp || "scheduler" in rendererProp);
|
|
15706
|
-
if (isRendererConfig) {
|
|
15707
|
-
const { primaryCanvas: pc, scheduler: sc, ...rest } = rendererProp;
|
|
15708
|
-
return {
|
|
15709
|
-
primaryCanvas: pc,
|
|
15710
|
-
scheduler: sc,
|
|
15711
|
-
renderer: Object.keys(rest).length > 0 ? rest : rendererProp
|
|
15712
|
-
};
|
|
15713
|
-
}
|
|
15714
|
-
return { primaryCanvas: void 0, scheduler: void 0, renderer: rendererProp };
|
|
15715
|
-
}
|
|
15716
|
-
|
|
15717
16284
|
function CanvasImpl({
|
|
15718
16285
|
ref,
|
|
15719
16286
|
children,
|
|
@@ -15722,11 +16289,13 @@ function CanvasImpl({
|
|
|
15722
16289
|
style,
|
|
15723
16290
|
id,
|
|
15724
16291
|
gl,
|
|
15725
|
-
renderer
|
|
16292
|
+
renderer,
|
|
16293
|
+
primary,
|
|
16294
|
+
share,
|
|
16295
|
+
scheduler,
|
|
15726
16296
|
events = createPointerEvents,
|
|
15727
16297
|
eventSource,
|
|
15728
16298
|
eventPrefix,
|
|
15729
|
-
shadows,
|
|
15730
16299
|
orthographic,
|
|
15731
16300
|
frameloop,
|
|
15732
16301
|
dpr,
|
|
@@ -15748,7 +16317,11 @@ function CanvasImpl({
|
|
|
15748
16317
|
provider,
|
|
15749
16318
|
...props
|
|
15750
16319
|
}) {
|
|
15751
|
-
const {
|
|
16320
|
+
const {
|
|
16321
|
+
shadows: removedShadows,
|
|
16322
|
+
primaryCanvas: removedPrimaryCanvas,
|
|
16323
|
+
...divProps
|
|
16324
|
+
} = props;
|
|
15752
16325
|
const Bridge = useBridge();
|
|
15753
16326
|
const backgroundProps = React.useMemo(() => parseBackground(background), [background]);
|
|
15754
16327
|
const [hasInitialSize, setHasInitialSize] = React.useState(false);
|
|
@@ -15794,10 +16367,22 @@ function CanvasImpl({
|
|
|
15794
16367
|
if (block) throw block;
|
|
15795
16368
|
if (error) throw error;
|
|
15796
16369
|
const root = React.useRef(null);
|
|
15797
|
-
const
|
|
15798
|
-
const
|
|
16370
|
+
const [gate, waitFor] = useGate();
|
|
16371
|
+
const rootState = React.useRef(null);
|
|
16372
|
+
const eventTarget = () => eventSource ? isRef$1(eventSource) ? eventSource.current : eventSource : divRef.current;
|
|
16373
|
+
const pointerMissed = React.useCallback(
|
|
16374
|
+
(...args) => handlePointerMissed.current?.(...args),
|
|
16375
|
+
[handlePointerMissed]
|
|
16376
|
+
);
|
|
16377
|
+
const dragOverMissed = React.useCallback(
|
|
16378
|
+
(...args) => handleDragOverMissed.current?.(...args),
|
|
16379
|
+
[handleDragOverMissed]
|
|
16380
|
+
);
|
|
16381
|
+
const dropMissed = React.useCallback(
|
|
16382
|
+
(...args) => handleDropMissed.current?.(...args),
|
|
16383
|
+
[handleDropMissed]
|
|
16384
|
+
);
|
|
15799
16385
|
useIsomorphicLayoutEffect(() => {
|
|
15800
|
-
effectActiveRef.current = true;
|
|
15801
16386
|
if (fallbackVisible) return;
|
|
15802
16387
|
const canvas = canvasRef.current;
|
|
15803
16388
|
if (effectiveSize.width > 0 && effectiveSize.height > 0 && canvas) {
|
|
@@ -15807,97 +16392,111 @@ function CanvasImpl({
|
|
|
15807
16392
|
message: "React Three Fiber v10 is in ALPHA - expect breaking changes",
|
|
15808
16393
|
link: "https://github.com/pmndrs/react-three-fiber/discussions"
|
|
15809
16394
|
});
|
|
15810
|
-
const rootEntry = _roots.get(canvas);
|
|
15811
|
-
if (rootEntry?.store) {
|
|
15812
|
-
if (unsubscribeErrorRef.current) unsubscribeErrorRef.current();
|
|
15813
|
-
unsubscribeErrorRef.current = rootEntry.store.subscribe((state) => {
|
|
15814
|
-
if (state.error && effectActiveRef.current) {
|
|
15815
|
-
setError(state.error);
|
|
15816
|
-
}
|
|
15817
|
-
});
|
|
15818
|
-
}
|
|
15819
16395
|
}
|
|
15820
|
-
|
|
15821
|
-
|
|
15822
|
-
|
|
15823
|
-
|
|
15824
|
-
|
|
15825
|
-
|
|
15826
|
-
|
|
15827
|
-
|
|
15828
|
-
|
|
15829
|
-
|
|
15830
|
-
|
|
15831
|
-
|
|
15832
|
-
|
|
15833
|
-
|
|
15834
|
-
|
|
15835
|
-
|
|
15836
|
-
|
|
15837
|
-
|
|
15838
|
-
|
|
15839
|
-
|
|
15840
|
-
|
|
15841
|
-
|
|
15842
|
-
|
|
15843
|
-
|
|
15844
|
-
|
|
15845
|
-
|
|
15846
|
-
|
|
15847
|
-
|
|
15848
|
-
|
|
15849
|
-
|
|
15850
|
-
|
|
15851
|
-
|
|
15852
|
-
|
|
15853
|
-
|
|
15854
|
-
|
|
15855
|
-
|
|
15856
|
-
|
|
15857
|
-
|
|
15858
|
-
|
|
15859
|
-
|
|
15860
|
-
}
|
|
15861
|
-
onCreated?.(state);
|
|
15862
|
-
}
|
|
15863
|
-
}).then(
|
|
15864
|
-
() => true,
|
|
15865
|
-
// Renderer setup failed (e.g. no WebGL/WebGPU support). The `fallback` prop lives
|
|
15866
|
-
// inside <canvas>, which browsers don't display, so surface it as visible DOM
|
|
15867
|
-
// instead; with no fallback, rethrow to an external error boundary. (#3757)
|
|
15868
|
-
(setupError) => {
|
|
15869
|
-
if (effectActiveRef.current) {
|
|
15870
|
-
if (fallback != null) setFallbackVisible(true);
|
|
15871
|
-
else setError(setupError);
|
|
15872
|
-
}
|
|
15873
|
-
return false;
|
|
16396
|
+
const current = root.current;
|
|
16397
|
+
current.configure({
|
|
16398
|
+
id,
|
|
16399
|
+
primary,
|
|
16400
|
+
share,
|
|
16401
|
+
scheduler,
|
|
16402
|
+
gl,
|
|
16403
|
+
renderer,
|
|
16404
|
+
scene,
|
|
16405
|
+
events,
|
|
16406
|
+
_primaryToken: primaryToken,
|
|
16407
|
+
...{ shadows: removedShadows, primaryCanvas: removedPrimaryCanvas },
|
|
16408
|
+
orthographic,
|
|
16409
|
+
frameloop,
|
|
16410
|
+
dpr,
|
|
16411
|
+
performance,
|
|
16412
|
+
raycaster,
|
|
16413
|
+
camera,
|
|
16414
|
+
autoUpdateFrustum,
|
|
16415
|
+
occlusion,
|
|
16416
|
+
size: effectiveSize,
|
|
16417
|
+
// Store size props for reset functionality
|
|
16418
|
+
_sizeProps: width !== void 0 || height !== void 0 ? { width, height } : null,
|
|
16419
|
+
forceEven,
|
|
16420
|
+
// Pass mutable reference to onPointerMissed so it's free to update
|
|
16421
|
+
onPointerMissed: pointerMissed,
|
|
16422
|
+
onDragOverMissed: dragOverMissed,
|
|
16423
|
+
onDropMissed: dropMissed,
|
|
16424
|
+
onCreated: (state) => {
|
|
16425
|
+
rootState.current = state;
|
|
16426
|
+
state.events.connect?.(eventTarget() ?? divRef.current);
|
|
16427
|
+
if (eventPrefix) {
|
|
16428
|
+
state.setEvents({
|
|
16429
|
+
compute: (event, state2) => {
|
|
16430
|
+
const x = event[eventPrefix + "X"];
|
|
16431
|
+
const y = event[eventPrefix + "Y"];
|
|
16432
|
+
state2.pointer.set(x / state2.size.width * 2 - 1, -(y / state2.size.height) * 2 + 1);
|
|
16433
|
+
state2.raycaster.setFromCamera(state2.pointer, state2.camera);
|
|
16434
|
+
}
|
|
16435
|
+
});
|
|
15874
16436
|
}
|
|
15875
|
-
|
|
15876
|
-
|
|
15877
|
-
|
|
16437
|
+
onCreated?.(state);
|
|
16438
|
+
}
|
|
16439
|
+
}).catch((setupError) => {
|
|
16440
|
+
if (root.current !== current) return;
|
|
16441
|
+
if (fallback != null) setFallbackVisible(true);
|
|
16442
|
+
else setError(setupError);
|
|
16443
|
+
});
|
|
16444
|
+
if (current.ready.status === "fulfilled") {
|
|
16445
|
+
current.render(
|
|
15878
16446
|
/* @__PURE__ */ jsx(Bridge, { children: /* @__PURE__ */ jsx(ErrorBoundary, { set: setError, children: /* @__PURE__ */ jsxs(React.Suspense, { fallback: /* @__PURE__ */ jsx(Block, { set: setBlock }), children: [
|
|
15879
16447
|
backgroundProps && /* @__PURE__ */ jsx(Environment, { ...backgroundProps }),
|
|
15880
16448
|
children ?? null
|
|
15881
16449
|
] }) }) })
|
|
15882
16450
|
);
|
|
16451
|
+
} else if (current.ready.status === "pending") {
|
|
16452
|
+
waitFor(current.ready);
|
|
15883
16453
|
}
|
|
15884
|
-
run();
|
|
15885
16454
|
}
|
|
15886
|
-
|
|
15887
|
-
|
|
15888
|
-
|
|
15889
|
-
|
|
15890
|
-
|
|
15891
|
-
|
|
16455
|
+
});
|
|
16456
|
+
useIsomorphicLayoutEffect(() => {
|
|
16457
|
+
const store = canvasRef.current && _roots.get(canvasRef.current)?.store;
|
|
16458
|
+
if (!store) return;
|
|
16459
|
+
const report = () => {
|
|
16460
|
+
const error2 = store.getState().error;
|
|
16461
|
+
if (error2) setError(error2);
|
|
15892
16462
|
};
|
|
16463
|
+
report();
|
|
16464
|
+
return store.subscribe(report);
|
|
16465
|
+
});
|
|
16466
|
+
React.useEffect(() => {
|
|
16467
|
+
const state = rootState.current?.get();
|
|
16468
|
+
const target = eventTarget();
|
|
16469
|
+
if (state && target && state.events.connected !== target) state.events.connect?.(target);
|
|
15893
16470
|
});
|
|
16471
|
+
const insertionMounted = React.useRef(false);
|
|
16472
|
+
const [primaryToken] = React.useState(() => ({}));
|
|
16473
|
+
const primaryKey = React.useRef(null);
|
|
16474
|
+
React.useInsertionEffect(() => {
|
|
16475
|
+
insertionMounted.current = true;
|
|
16476
|
+
if (primary && provider.webgpu) {
|
|
16477
|
+
primaryKey.current ?? (primaryKey.current = id || DEFAULT_PRIMARY);
|
|
16478
|
+
announcePrimary(primaryKey.current, primaryToken);
|
|
16479
|
+
}
|
|
16480
|
+
return () => {
|
|
16481
|
+
insertionMounted.current = false;
|
|
16482
|
+
if (primaryKey.current) markWithdrawing(primaryToken);
|
|
16483
|
+
queueMicrotask(() => {
|
|
16484
|
+
if (insertionMounted.current) return;
|
|
16485
|
+
if (primaryKey.current) withdrawPrimary(primaryKey.current, primaryToken);
|
|
16486
|
+
const current = root.current;
|
|
16487
|
+
root.current = null;
|
|
16488
|
+
current?.unmount();
|
|
16489
|
+
});
|
|
16490
|
+
};
|
|
16491
|
+
}, []);
|
|
15894
16492
|
React.useEffect(() => {
|
|
15895
16493
|
const canvas = canvasRef.current;
|
|
15896
16494
|
if (canvas) {
|
|
15897
16495
|
return () => {
|
|
15898
16496
|
if (canvas.isConnected) return;
|
|
15899
|
-
|
|
16497
|
+
const current = root.current;
|
|
15900
16498
|
root.current = null;
|
|
16499
|
+
current?.unmount();
|
|
15901
16500
|
};
|
|
15902
16501
|
}
|
|
15903
16502
|
}, []);
|
|
@@ -15924,7 +16523,7 @@ function CanvasImpl({
|
|
|
15924
16523
|
}
|
|
15925
16524
|
}, [hmr]);
|
|
15926
16525
|
const pointerEvents = eventSource ? "none" : "auto";
|
|
15927
|
-
return /* @__PURE__ */
|
|
16526
|
+
return /* @__PURE__ */ jsxs(
|
|
15928
16527
|
"div",
|
|
15929
16528
|
{
|
|
15930
16529
|
ref: divRef,
|
|
@@ -15936,21 +16535,24 @@ function CanvasImpl({
|
|
|
15936
16535
|
pointerEvents,
|
|
15937
16536
|
...style
|
|
15938
16537
|
},
|
|
15939
|
-
...
|
|
15940
|
-
children:
|
|
15941
|
-
|
|
15942
|
-
|
|
15943
|
-
|
|
15944
|
-
|
|
15945
|
-
"canvas",
|
|
15946
|
-
|
|
15947
|
-
|
|
15948
|
-
|
|
15949
|
-
|
|
15950
|
-
|
|
15951
|
-
|
|
15952
|
-
|
|
15953
|
-
|
|
16538
|
+
...divProps,
|
|
16539
|
+
children: [
|
|
16540
|
+
fallbackVisible ? (
|
|
16541
|
+
// Renderer setup failed: render the fallback as visible DOM. Inside <canvas> (below)
|
|
16542
|
+
// it exists in the tree but browsers never paint it, which is the whole bug (#3757).
|
|
16543
|
+
fallback
|
|
16544
|
+
) : /* @__PURE__ */ jsx("div", { ref: containerRef, className: "r3f-canvas-container", style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ jsx(
|
|
16545
|
+
"canvas",
|
|
16546
|
+
{
|
|
16547
|
+
ref: canvasRef,
|
|
16548
|
+
id,
|
|
16549
|
+
className: "r3f-canvas",
|
|
16550
|
+
style: { display: "block", width: "100%", height: "100%" },
|
|
16551
|
+
children: fallback
|
|
16552
|
+
}
|
|
16553
|
+
) }),
|
|
16554
|
+
gate
|
|
16555
|
+
]
|
|
15954
16556
|
}
|
|
15955
16557
|
);
|
|
15956
16558
|
}
|
|
@@ -15958,4 +16560,4 @@ function Canvas(props) {
|
|
|
15958
16560
|
return /* @__PURE__ */ jsx(FiberProvider, { children: /* @__PURE__ */ jsx(CanvasImpl, { ...props }) });
|
|
15959
16561
|
}
|
|
15960
16562
|
|
|
15961
|
-
export {
|
|
16563
|
+
export { invalidateInstance as $, useGraph as A, useLoader as B, Canvas as C, useTexture as D, EnvironmentMap as E, useTextures as F, useEnvironment as G, extend as H, IsObject as I, reconciler as J, flushSync as K, unmountComponentAtNode as L, createPortal as M, calculateDpr as N, getUuidPrefix as O, Portal as P, updateCamera as Q, updateFrustum as R, REACT_INTERNAL_PROPS as S, Texture as T, findInitialRoot as U, getRootState as V, buildGraph as W, dispose as X, getInstanceProps as Y, prepare as Z, _roots as _, createPointerEvents as a, RESERVED_PROPS as a0, resolve as a1, attach as a2, detach as a3, diffProps as a4, applyProps as a5, is as a6, isOrthographicCamera as a7, isRef$1 as a8, isColorRepresentation as a9, isObject3D as aa, isTexture as ab, isLayers as ac, isUniform as ad, isVectorLike as ae, isCopyable as af, hasConstructor as ag, FROM_REF as ah, fromRef as ai, isFromRef as aj, ONCE as ak, once as al, isOnce as am, useRenderTarget as an, addEffect as b, createRoot as c, addAfterEffect as d, addTail as e, advance as f, isRenderer as g, getPrimary as h, invalidate as i, hasPrimary as j, getPrimaryIds as k, createStore as l, getThree as m, hasThree as n, whenThree as o, EnvironmentCube as p, EnvironmentPortal as q, registerPrimary as r, Environment as s, presetsObj as t, unregisterPrimary as u, swapInteractivity as v, waitForPrimary as w, removeInteractivity as x, createEvents as y, useInstanceHandle as z };
|