@react-three/fiber 10.0.0-canary.3f8df2b → 10.0.0-canary.42caa10
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.DH-VJXM_.d.ts → fiber.34TOMPo3.d.cts} +89 -464
- package/dist/shared/fiber.BFuGd7gN.d.cts +90 -0
- package/dist/shared/{fiber.khFlPHPf.cjs → fiber.BO8-26r8.cjs} +206 -62
- package/dist/shared/fiber.Bll9fqKA.d.mts +90 -0
- package/dist/shared/{fiber.BgxhptM_.mjs → fiber.BwymjkeO.mjs} +2067 -1497
- package/dist/shared/fiber.BzEJI6VE.cjs +14 -0
- package/dist/shared/{fiber.B0oukOFO.mjs → fiber.C-3TIsF8.mjs} +200 -64
- package/dist/shared/{fiber.EDf0d92E.cjs → fiber.C2WmwvFB.cjs} +2093 -1523
- package/dist/shared/fiber.C4Q4G0wZ.mjs +9 -0
- package/dist/shared/{fiber.cO-9hDzr.d.cts → fiber.CjMAAsJy.d.ts} +89 -464
- package/dist/shared/{fiber.Dh8K6RJr.d.cts → fiber.DQTSZ24m.d.cts} +481 -26
- package/dist/shared/{fiber.Dh8K6RJr.d.mts → fiber.DQTSZ24m.d.mts} +481 -26
- package/dist/shared/{fiber.Dh8K6RJr.d.ts → fiber.DQTSZ24m.d.ts} +481 -26
- package/dist/shared/fiber.DuA4F8L5.d.ts +90 -0
- package/dist/shared/{fiber.AN9kOS0N.d.mts → fiber.Dy7Uz273.d.mts} +89 -464
- 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.BIhZnMzg.d.ts +0 -48
- package/dist/shared/fiber.BcX0-yko.d.mts +0 -48
- package/dist/shared/fiber.BgP4izaL.d.cts +0 -48
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const jsxRuntime = require('react/jsx-runtime');
|
|
4
|
-
const
|
|
4
|
+
const textureStaging = require('./fiber.BO8-26r8.cjs');
|
|
5
5
|
const React = require('react');
|
|
6
6
|
const useMeasure = require('react-use-measure');
|
|
7
7
|
const itsFine = require('its-fine');
|
|
@@ -25,8 +25,8 @@ function _interopNamespaceCompat(e) {
|
|
|
25
25
|
return n;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
const React__default = /*#__PURE__*/_interopDefaultCompat(React);
|
|
29
28
|
const React__namespace = /*#__PURE__*/_interopNamespaceCompat(React);
|
|
29
|
+
const React__default = /*#__PURE__*/_interopDefaultCompat(React);
|
|
30
30
|
const useMeasure__default = /*#__PURE__*/_interopDefaultCompat(useMeasure);
|
|
31
31
|
const w1__default = /*#__PURE__*/_interopDefaultCompat(w1);
|
|
32
32
|
|
|
@@ -128,6 +128,20 @@ function updateFrustum(camera, frustum) {
|
|
|
128
128
|
target.setFromProjectionMatrix(frustumMatrix);
|
|
129
129
|
return target;
|
|
130
130
|
}
|
|
131
|
+
function computeInitialSize(canvas, size) {
|
|
132
|
+
if (!size && typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement && canvas.parentElement) {
|
|
133
|
+
const { width, height, top, left } = canvas.parentElement.getBoundingClientRect();
|
|
134
|
+
return { width, height, top, left };
|
|
135
|
+
} else if (!size && typeof OffscreenCanvas !== "undefined" && canvas instanceof OffscreenCanvas) {
|
|
136
|
+
return {
|
|
137
|
+
width: canvas.width,
|
|
138
|
+
height: canvas.height,
|
|
139
|
+
top: 0,
|
|
140
|
+
left: 0
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
return { width: 0, height: 0, top: 0, left: 0, ...size };
|
|
144
|
+
}
|
|
131
145
|
|
|
132
146
|
const REACT_INTERNAL_PROPS = ["children", "key", "ref"];
|
|
133
147
|
function findInitialRoot(instance) {
|
|
@@ -195,6 +209,7 @@ function prepare(target, root, type, props) {
|
|
|
195
209
|
object,
|
|
196
210
|
eventCount: 0,
|
|
197
211
|
handlers: {},
|
|
212
|
+
previousVisible: void 0,
|
|
198
213
|
isHidden: false
|
|
199
214
|
};
|
|
200
215
|
if (object) object.__r3f = instance;
|
|
@@ -422,7 +437,19 @@ function assertNodeMaterialSupported(state, value) {
|
|
|
422
437
|
const material = (Array.isArray(value) ? value : [value]).find((m) => m?.isNodeMaterial);
|
|
423
438
|
if (!material) return;
|
|
424
439
|
throw new Error(
|
|
425
|
-
`R3F: ${material.type ?? "Node material"} requires WebGPURenderer (it falls back to WebGL2 automatically).
|
|
440
|
+
`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.`
|
|
441
|
+
);
|
|
442
|
+
}
|
|
443
|
+
const warnedGLSL = /* @__PURE__ */ new Set();
|
|
444
|
+
function warnGLSLMaterialUnsupported(state, value) {
|
|
445
|
+
if (!state || state.isLegacy || state.internal?.support?.kind !== "webgpu" || !textureStaging.isDevelopment()) return;
|
|
446
|
+
const material = (Array.isArray(value) ? value : [value]).find((m) => m?.isShaderMaterial && !m.isNodeMaterial);
|
|
447
|
+
if (!material) return;
|
|
448
|
+
const type = material.type ?? "ShaderMaterial";
|
|
449
|
+
if (warnedGLSL.has(type)) return;
|
|
450
|
+
warnedGLSL.add(type);
|
|
451
|
+
console.warn(
|
|
452
|
+
`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).`
|
|
426
453
|
);
|
|
427
454
|
}
|
|
428
455
|
|
|
@@ -443,6 +470,28 @@ const VISIBILITY_EVENT_REGEX = /^on(Framed|Occluded|Visible)$/;
|
|
|
443
470
|
const INDEX_REGEX = /-\d+$/;
|
|
444
471
|
const MEMOIZED_PROTOTYPES = /* @__PURE__ */ new Map();
|
|
445
472
|
const colorMaps = ["map", "emissiveMap", "sheenColorMap", "specularColorMap", "envMap"];
|
|
473
|
+
const programProps = /* @__PURE__ */ new Set([
|
|
474
|
+
"transparent",
|
|
475
|
+
"vertexColors",
|
|
476
|
+
"flatShading",
|
|
477
|
+
"fog",
|
|
478
|
+
// Culling is live, but DOUBLE_SIDED / FLIP_SIDED normal flipping is compiled in
|
|
479
|
+
"side",
|
|
480
|
+
"alphaHash",
|
|
481
|
+
"premultipliedAlpha",
|
|
482
|
+
// Both feed the OPAQUE define when the material is not transparent
|
|
483
|
+
"blending",
|
|
484
|
+
"alphaToCoverage",
|
|
485
|
+
"dithering",
|
|
486
|
+
"sizeAttenuation",
|
|
487
|
+
"combine",
|
|
488
|
+
"normalMapType",
|
|
489
|
+
"depthPacking"
|
|
490
|
+
]);
|
|
491
|
+
function changesProgram(root, key, previous, next) {
|
|
492
|
+
if (!root?.isMaterial || previous === next) return false;
|
|
493
|
+
return programProps.has(key) || isTexture(previous) !== isTexture(next);
|
|
494
|
+
}
|
|
446
495
|
function resolve(root, key) {
|
|
447
496
|
if (!key.includes("-")) return { root, key, target: root[key] };
|
|
448
497
|
if (key in root) return { root, key, target: root[key] };
|
|
@@ -473,6 +522,7 @@ function attach(parent, child) {
|
|
|
473
522
|
const { root, key } = resolve(parent.object, child.props.attach);
|
|
474
523
|
child.previousAttach = root[key];
|
|
475
524
|
root[key] = child.object;
|
|
525
|
+
if (changesProgram(root, key, child.previousAttach, child.object)) root.needsUpdate = true;
|
|
476
526
|
} else if (is.fun(child.props.attach)) {
|
|
477
527
|
child.previousAttach = child.props.attach(parent.object, child.object);
|
|
478
528
|
}
|
|
@@ -483,6 +533,7 @@ function detach(parent, child) {
|
|
|
483
533
|
const previous = child.previousAttach;
|
|
484
534
|
if (previous === void 0) delete root[key];
|
|
485
535
|
else root[key] = previous;
|
|
536
|
+
if (changesProgram(root, key, child.object, previous)) root.needsUpdate = true;
|
|
486
537
|
} else {
|
|
487
538
|
child.previousAttach?.(parent.object, child.object);
|
|
488
539
|
}
|
|
@@ -527,7 +578,7 @@ function applyProps(object, props) {
|
|
|
527
578
|
const value = props[prop];
|
|
528
579
|
if (RESERVED_PROPS.includes(prop)) continue;
|
|
529
580
|
if (prop === "onUpdate") {
|
|
530
|
-
|
|
581
|
+
textureStaging.notifyDepreciated({
|
|
531
582
|
heading: "onUpdate is no longer an R3F prop",
|
|
532
583
|
body: "v10 removed the onUpdate hook: R3F no longer calls it after prop updates. The value is assigned to the object by name. On a Texture that sets three's Texture.onUpdate, which the renderer calls after a GPU upload, not after prop changes. On a node it replaces the Node.onUpdate() method. On other objects it is never called.\n\nUse an effect keyed on the props that change, read the object in useFrame, or use a ref callback.",
|
|
533
584
|
link: "https://docs.pmnd.rs/react-three-fiber/migration/v10#onupdate-removed"
|
|
@@ -562,6 +613,10 @@ function applyProps(object, props) {
|
|
|
562
613
|
}
|
|
563
614
|
continue;
|
|
564
615
|
}
|
|
616
|
+
if (prop === "visible" && instance?.isHidden && instance.previousVisible !== void 0) {
|
|
617
|
+
instance.previousVisible = value;
|
|
618
|
+
continue;
|
|
619
|
+
}
|
|
565
620
|
let { root, key, target } = resolve(object, prop);
|
|
566
621
|
if (target === void 0 && (typeof root !== "object" || root === null)) {
|
|
567
622
|
throw Error(`R3F: Cannot set "${prop}". Ensure it is an object before setting "${key}".`);
|
|
@@ -589,17 +644,24 @@ function applyProps(object, props) {
|
|
|
589
644
|
for (const name in nextUniforms) {
|
|
590
645
|
const uniform = nextUniforms[name];
|
|
591
646
|
const targetUniform = uniforms[name];
|
|
592
|
-
if (targetUniform)
|
|
593
|
-
|
|
647
|
+
if (targetUniform) {
|
|
648
|
+
Object.assign(targetUniform, uniform);
|
|
649
|
+
} else {
|
|
594
650
|
const nextUniform = isUniform(uniform) ? uniform.clone() : new (getThree()).Uniform(uniform.value);
|
|
595
651
|
uniforms[name] = nextUniform;
|
|
596
652
|
}
|
|
597
653
|
}
|
|
598
654
|
} else {
|
|
599
|
-
if (key === "material")
|
|
655
|
+
if (key === "material") {
|
|
656
|
+
assertNodeMaterialSupported(rootState, value);
|
|
657
|
+
warnGLSLMaterialUnsupported(rootState, value);
|
|
658
|
+
}
|
|
659
|
+
const previous = root[key];
|
|
600
660
|
root[key] = value;
|
|
601
661
|
if (key.endsWith("Node") && root.isMaterial) {
|
|
602
662
|
root.needsUpdate = true;
|
|
663
|
+
} else if (changesProgram(root, key, previous, value)) {
|
|
664
|
+
root.needsUpdate = true;
|
|
603
665
|
}
|
|
604
666
|
const three = rootState && getThree();
|
|
605
667
|
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
|
|
@@ -640,471 +702,393 @@ function applyProps(object, props) {
|
|
|
640
702
|
return object;
|
|
641
703
|
}
|
|
642
704
|
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
memoizedLoaders.set(Proto, loader);
|
|
651
|
-
}
|
|
652
|
-
return loader;
|
|
653
|
-
}
|
|
654
|
-
return Proto;
|
|
655
|
-
}
|
|
656
|
-
function loadingFn(extensions, onProgress) {
|
|
657
|
-
return function(Proto, input) {
|
|
658
|
-
const loader = getLoader(Proto);
|
|
659
|
-
if (extensions) extensions(loader);
|
|
660
|
-
if ("loadAsync" in loader && typeof loader.loadAsync === "function") {
|
|
661
|
-
return loader.loadAsync(input, onProgress).then((data) => {
|
|
662
|
-
if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
|
|
663
|
-
return data;
|
|
664
|
-
});
|
|
665
|
-
}
|
|
666
|
-
return new Promise(
|
|
667
|
-
(res, reject) => loader.load(
|
|
668
|
-
input,
|
|
669
|
-
(data) => {
|
|
670
|
-
if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
|
|
671
|
-
res(data);
|
|
672
|
-
},
|
|
673
|
-
onProgress,
|
|
674
|
-
(error) => reject(new Error(`Could not load ${input}: ${error?.message}`))
|
|
675
|
-
)
|
|
676
|
-
);
|
|
677
|
-
};
|
|
678
|
-
}
|
|
679
|
-
function useLoader(loader, input, extensions, onProgress, cacheKey) {
|
|
680
|
-
const inputs = Array.isArray(input) ? input : [input];
|
|
681
|
-
const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
|
|
682
|
-
const fn = loadingFn(extensions, onProgress);
|
|
683
|
-
const results = cacheKeys.map(
|
|
684
|
-
(key, index) => suspendReact.suspend(() => fn(loader, inputs[index]), [loader, key], { equal: is.equ })
|
|
685
|
-
);
|
|
686
|
-
const stableRef = React.useRef(null);
|
|
687
|
-
const previous = stableRef.current;
|
|
688
|
-
const stable = previous !== null && previous.length === results.length && previous.every((value, i) => value === results[i]) ? previous : results;
|
|
689
|
-
stableRef.current = stable;
|
|
690
|
-
return Array.isArray(input) ? stable : stable[0];
|
|
691
|
-
}
|
|
692
|
-
useLoader.preload = function(loader, input, extensions, onProgress, cacheKey) {
|
|
693
|
-
const inputs = Array.isArray(input) ? input : [input];
|
|
694
|
-
const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
|
|
695
|
-
cacheKeys.forEach(
|
|
696
|
-
(key, index) => suspendReact.preload(() => loadingFn(extensions, onProgress)(loader, inputs[index]), [loader, key])
|
|
697
|
-
);
|
|
698
|
-
};
|
|
699
|
-
useLoader.clear = function(loader, input, cacheKey) {
|
|
700
|
-
const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
|
|
701
|
-
cacheKeys.forEach((key) => suspendReact.clear([loader, key]));
|
|
702
|
-
};
|
|
703
|
-
useLoader.loader = getLoader;
|
|
704
|
-
|
|
705
|
-
const IsObject = (url) => url === Object(url) && !Array.isArray(url) && typeof url !== "function";
|
|
706
|
-
function getUrls(input) {
|
|
707
|
-
if (typeof input === "string") return [input];
|
|
708
|
-
if (Array.isArray(input)) return input;
|
|
709
|
-
return Object.values(input);
|
|
710
|
-
}
|
|
711
|
-
function inputSignature(input) {
|
|
712
|
-
if (typeof input === "string") return input;
|
|
713
|
-
if (Array.isArray(input)) return input.join("\0");
|
|
714
|
-
return Object.keys(input).sort().map((key) => `${key}\0${input[key]}`).join("");
|
|
715
|
-
}
|
|
716
|
-
function allUrlsCached(urls, textureCache) {
|
|
717
|
-
return urls.every((url) => textureCache.has(url));
|
|
705
|
+
function updateSize(state, size, imperative) {
|
|
706
|
+
state.set((current) => ({
|
|
707
|
+
size,
|
|
708
|
+
viewport: { ...current.viewport, ...current.viewport.getCurrentViewport(current.camera, void 0, size) },
|
|
709
|
+
_sizeImperative: imperative
|
|
710
|
+
}));
|
|
711
|
+
state.invalidate();
|
|
718
712
|
}
|
|
719
|
-
function
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
return input.map((url) => textureCache.get(url));
|
|
724
|
-
} else {
|
|
725
|
-
const result = {};
|
|
726
|
-
const objInput = input;
|
|
727
|
-
for (const key in objInput) {
|
|
728
|
-
result[key] = textureCache.get(objInput[key]);
|
|
729
|
-
}
|
|
730
|
-
return result;
|
|
731
|
-
}
|
|
713
|
+
function configureSize(store, size) {
|
|
714
|
+
const state = store.getState();
|
|
715
|
+
if (state._sizeImperative || is.equ(size, state.size, { objects: "shallow", strict: false })) return;
|
|
716
|
+
updateSize(state, size, false);
|
|
732
717
|
}
|
|
733
|
-
|
|
734
|
-
const
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
const keyed = {};
|
|
758
|
-
const textureArray = loadedTextures;
|
|
759
|
-
let i = 0;
|
|
760
|
-
for (const key in stableInput) keyed[key] = textureArray[i++];
|
|
761
|
-
return keyed;
|
|
762
|
-
} else {
|
|
763
|
-
return loadedTextures;
|
|
764
|
-
}
|
|
765
|
-
}, [stableInput, loadedTextures, cachedResult]);
|
|
766
|
-
React.useLayoutEffect(() => {
|
|
767
|
-
if (cachedResult) return;
|
|
768
|
-
if (onLoadCalledForRef.current === inputKey) return;
|
|
769
|
-
onLoadCalledForRef.current = inputKey;
|
|
770
|
-
onLoadRef.current?.(mappedTextures);
|
|
771
|
-
}, [cachedResult, mappedTextures, inputKey]);
|
|
772
|
-
React.useEffect(() => {
|
|
773
|
-
if (cachedResult) return;
|
|
774
|
-
if ("initTexture" in renderer) {
|
|
775
|
-
let textureArray = [];
|
|
776
|
-
if (Array.isArray(loadedTextures)) {
|
|
777
|
-
textureArray = loadedTextures;
|
|
778
|
-
} else if (loadedTextures.isTexture) {
|
|
779
|
-
textureArray = [loadedTextures];
|
|
780
|
-
} else if (IsObject(loadedTextures)) {
|
|
781
|
-
textureArray = Object.values(loadedTextures);
|
|
718
|
+
const createStore = (invalidate, advance) => {
|
|
719
|
+
const rootStore = traditional.createWithEqualityFn((rawSet, get, api) => {
|
|
720
|
+
const set = api.setState = textureStaging.preserveAccessors(rawSet, get);
|
|
721
|
+
let position;
|
|
722
|
+
let defaultTarget;
|
|
723
|
+
let tempTarget;
|
|
724
|
+
function getCurrentViewport(camera = get().camera, target = void 0, size = get().size) {
|
|
725
|
+
const { Vector3 } = getThree();
|
|
726
|
+
position ?? (position = new Vector3());
|
|
727
|
+
defaultTarget ?? (defaultTarget = new Vector3());
|
|
728
|
+
tempTarget ?? (tempTarget = new Vector3());
|
|
729
|
+
target ?? (target = defaultTarget);
|
|
730
|
+
const { width, height, top, left } = size;
|
|
731
|
+
const aspect = width / height;
|
|
732
|
+
if (target.isVector3) tempTarget.copy(target);
|
|
733
|
+
else tempTarget.set(...target);
|
|
734
|
+
const distance = camera.getWorldPosition(position).distanceTo(tempTarget);
|
|
735
|
+
if (isOrthographicCamera(camera)) {
|
|
736
|
+
return { width: width / camera.zoom, height: height / camera.zoom, top, left, factor: 1, distance, aspect };
|
|
737
|
+
} else {
|
|
738
|
+
const fov = camera.fov * Math.PI / 180;
|
|
739
|
+
const h = 2 * Math.tan(fov / 2) * distance;
|
|
740
|
+
const w = h * (width / height);
|
|
741
|
+
return { width: w, height: h, top, left, factor: width / w, distance, aspect };
|
|
782
742
|
}
|
|
783
|
-
textureArray.forEach((texture) => {
|
|
784
|
-
if (texture?.isTexture) {
|
|
785
|
-
renderer.initTexture(texture);
|
|
786
|
-
}
|
|
787
|
-
});
|
|
788
743
|
}
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
urlTextureMap.map(([url]) => url)
|
|
812
|
-
);
|
|
813
|
-
return () => store.setState((state) => {
|
|
814
|
-
const refs = new Map(state._textureRefs);
|
|
815
|
-
for (const [url] of urlTextureMap) {
|
|
816
|
-
const next = (refs.get(url) ?? 0) - 1;
|
|
817
|
-
if (next <= 0) refs.delete(url);
|
|
818
|
-
else refs.set(url, next);
|
|
819
|
-
}
|
|
820
|
-
return { _textureRefs: refs };
|
|
821
|
-
});
|
|
822
|
-
}, [cache, stableInput, mappedTextures, store]);
|
|
823
|
-
if (cache && !cachedResult) extensions.stageTextures(store, urlTextureEntries(stableInput, mappedTextures));
|
|
824
|
-
return mappedTextures;
|
|
825
|
-
}
|
|
826
|
-
function urlTextureEntries(input, textures) {
|
|
827
|
-
if (typeof input === "string") return [[input, textures]];
|
|
828
|
-
if (Array.isArray(input)) return input.map((url, i) => [url, textures[i]]);
|
|
829
|
-
const record = textures;
|
|
830
|
-
return Object.keys(input).map((key) => [input[key], record[key]]);
|
|
831
|
-
}
|
|
832
|
-
useTexture.preload = (url) => {
|
|
833
|
-
whenThree().then((three) => useLoader.preload(three.TextureLoader, url));
|
|
834
|
-
};
|
|
835
|
-
useTexture.clear = (input) => {
|
|
836
|
-
if (hasThree()) useLoader.clear(getThree().TextureLoader, input);
|
|
837
|
-
};
|
|
838
|
-
const Texture = ({
|
|
839
|
-
children,
|
|
840
|
-
input,
|
|
841
|
-
onLoad,
|
|
842
|
-
cache
|
|
843
|
-
}) => {
|
|
844
|
-
const options = typeof onLoad === "function" ? { onLoad, cache } : { ...onLoad, cache };
|
|
845
|
-
const ret = useTexture(input, options);
|
|
846
|
-
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: children?.(ret) });
|
|
847
|
-
};
|
|
848
|
-
|
|
849
|
-
function useTextures(selector) {
|
|
850
|
-
const store = extensions.useStore();
|
|
851
|
-
const registry = React.useMemo(() => {
|
|
852
|
-
const getState = store.getState;
|
|
853
|
-
const setState = store.setState;
|
|
854
|
-
const getOne = (key) => getState().textures.get(key);
|
|
855
|
-
return {
|
|
856
|
-
get all() {
|
|
857
|
-
return getState().textures;
|
|
858
|
-
},
|
|
859
|
-
get(input) {
|
|
860
|
-
if (typeof input === "string") return getOne(input);
|
|
861
|
-
if (Array.isArray(input)) return input.map(getOne);
|
|
862
|
-
const out = {};
|
|
863
|
-
for (const name in input) out[name] = getOne(input[name]);
|
|
864
|
-
return out;
|
|
865
|
-
},
|
|
866
|
-
has: (key) => getState().textures.has(key),
|
|
867
|
-
add(keyOrRecord, texture) {
|
|
868
|
-
setState((state) => {
|
|
869
|
-
const textures = new Map(state.textures);
|
|
870
|
-
if (typeof keyOrRecord === "string") {
|
|
871
|
-
textures.set(keyOrRecord, texture);
|
|
872
|
-
} else {
|
|
873
|
-
for (const key in keyOrRecord) textures.set(key, keyOrRecord[key]);
|
|
874
|
-
}
|
|
875
|
-
return { textures };
|
|
876
|
-
});
|
|
744
|
+
let performanceTimeout = void 0;
|
|
745
|
+
const setPerformanceCurrent = (current) => set((state2) => ({ performance: { ...state2.performance, current } }));
|
|
746
|
+
const rootState = {
|
|
747
|
+
set,
|
|
748
|
+
get,
|
|
749
|
+
// Mock objects that have to be configured
|
|
750
|
+
// primaryStore is set after store creation (self-reference for primary, primary's store for secondary)
|
|
751
|
+
primaryStore: null,
|
|
752
|
+
gl: null,
|
|
753
|
+
renderer: null,
|
|
754
|
+
camera: null,
|
|
755
|
+
// frustum, pointer and mouse are three objects; configure() creates them with the renderer
|
|
756
|
+
frustum: null,
|
|
757
|
+
autoUpdateFrustum: true,
|
|
758
|
+
raycaster: null,
|
|
759
|
+
events: {
|
|
760
|
+
priority: 1,
|
|
761
|
+
enabled: true,
|
|
762
|
+
connected: false,
|
|
763
|
+
frameTimedRaycasts: true,
|
|
764
|
+
alwaysFireOnScroll: true,
|
|
765
|
+
updateOnFrame: false
|
|
877
766
|
},
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
767
|
+
scene: null,
|
|
768
|
+
rootScene: null,
|
|
769
|
+
xr: null,
|
|
770
|
+
inspector: null,
|
|
771
|
+
invalidate: (frames = 1, stackFrames = false) => invalidate(get(), frames, stackFrames),
|
|
772
|
+
advance: (timestamp, runGlobalEffects) => advance(timestamp, runGlobalEffects, get()),
|
|
773
|
+
textureColorSpace: "srgb",
|
|
774
|
+
// THREE.SRGBColorSpace
|
|
775
|
+
isLegacy: false,
|
|
776
|
+
webGPUSupported: false,
|
|
777
|
+
isNative: false,
|
|
778
|
+
controls: null,
|
|
779
|
+
pointer: null,
|
|
780
|
+
mouse: null,
|
|
781
|
+
frameloop: "always",
|
|
782
|
+
onPointerMissed: void 0,
|
|
783
|
+
onDragOverMissed: void 0,
|
|
784
|
+
onDropMissed: void 0,
|
|
785
|
+
performance: {
|
|
786
|
+
current: 1,
|
|
787
|
+
min: 0.5,
|
|
788
|
+
max: 1,
|
|
789
|
+
debounce: 200,
|
|
790
|
+
regress: () => {
|
|
791
|
+
const state2 = get();
|
|
792
|
+
if (performanceTimeout) clearTimeout(performanceTimeout);
|
|
793
|
+
if (state2.performance.current !== state2.performance.min) setPerformanceCurrent(state2.performance.min);
|
|
794
|
+
performanceTimeout = setTimeout(
|
|
795
|
+
() => setPerformanceCurrent(get().performance.max),
|
|
796
|
+
state2.performance.debounce
|
|
884
797
|
);
|
|
885
|
-
return false;
|
|
886
798
|
}
|
|
887
|
-
state.textures.get(key)?.dispose();
|
|
888
|
-
setState((s) => {
|
|
889
|
-
const textures = new Map(s.textures);
|
|
890
|
-
textures.delete(key);
|
|
891
|
-
const nextRefs = new Map(s._textureRefs);
|
|
892
|
-
nextRefs.delete(key);
|
|
893
|
-
return { textures, _textureRefs: nextRefs };
|
|
894
|
-
});
|
|
895
|
-
return true;
|
|
896
799
|
},
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
800
|
+
size: { width: 0, height: 0, top: 0, left: 0 },
|
|
801
|
+
viewport: {
|
|
802
|
+
initialDpr: 0,
|
|
803
|
+
dpr: 0,
|
|
804
|
+
width: 0,
|
|
805
|
+
height: 0,
|
|
806
|
+
top: 0,
|
|
807
|
+
left: 0,
|
|
808
|
+
aspect: 0,
|
|
809
|
+
distance: 0,
|
|
810
|
+
factor: 0,
|
|
811
|
+
getCurrentViewport
|
|
812
|
+
},
|
|
813
|
+
setEvents: (events) => set((state2) => ({ events: { ...state2.events, ...events } })),
|
|
814
|
+
setSize: (width, height, top, left) => {
|
|
815
|
+
const state2 = get();
|
|
816
|
+
if (width === void 0) {
|
|
817
|
+
if (state2._sizeProps) {
|
|
818
|
+
const { width: propW, height: propH } = state2._sizeProps;
|
|
819
|
+
if (propW !== void 0 || propH !== void 0) {
|
|
820
|
+
const currentSize = state2.size;
|
|
821
|
+
const newSize = {
|
|
822
|
+
width: propW ?? currentSize.width,
|
|
823
|
+
height: propH ?? currentSize.height,
|
|
824
|
+
top: currentSize.top,
|
|
825
|
+
left: currentSize.left
|
|
826
|
+
};
|
|
827
|
+
updateSize(state2, newSize, false);
|
|
828
|
+
return;
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
set({ _sizeImperative: false });
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
834
|
+
const w = width;
|
|
835
|
+
const h = height ?? width;
|
|
836
|
+
const t = top ?? state2.size.top;
|
|
837
|
+
const l = left ?? state2.size.left;
|
|
838
|
+
const size = { width: w, height: h, top: t, left: l };
|
|
839
|
+
updateSize(state2, size, true);
|
|
840
|
+
},
|
|
841
|
+
setDpr: (dpr) => set((state2) => {
|
|
842
|
+
const resolved = calculateDpr(dpr);
|
|
843
|
+
return { viewport: { ...state2.viewport, dpr: resolved, initialDpr: state2.viewport.initialDpr || resolved } };
|
|
844
|
+
}),
|
|
845
|
+
setFrameloop: (frameloop = "always") => {
|
|
846
|
+
const rootId = get().internal.rootId;
|
|
847
|
+
if (rootId) scheduler.getScheduler().setRootFrameloop(rootId, frameloop);
|
|
848
|
+
set(() => ({ frameloop }));
|
|
849
|
+
},
|
|
850
|
+
setError: (error) => set(() => ({ error })),
|
|
851
|
+
error: null,
|
|
852
|
+
//* Texture registry (useTextures) ==============================
|
|
853
|
+
// TSL fields (uniforms, nodes, ..., renderPipeline) are added by @react-three/tsl's root extension.
|
|
854
|
+
textures: /* @__PURE__ */ new Map(),
|
|
855
|
+
_textureRefs: /* @__PURE__ */ new Map(),
|
|
856
|
+
_sizeImperative: false,
|
|
857
|
+
_sizeProps: null,
|
|
858
|
+
previousRoot: void 0,
|
|
859
|
+
internal: {
|
|
860
|
+
// Events
|
|
861
|
+
interaction: [],
|
|
862
|
+
subscribers: [],
|
|
863
|
+
// Per-pointer state (new unified structure)
|
|
864
|
+
pointerMap: /* @__PURE__ */ new Map(),
|
|
865
|
+
pointerDirty: /* @__PURE__ */ new Map(),
|
|
866
|
+
lastEvent: React__namespace.createRef(),
|
|
867
|
+
// Deprecated but kept for backwards compatibility
|
|
868
|
+
hovered: /* @__PURE__ */ new Map(),
|
|
869
|
+
initialClick: [0, 0],
|
|
870
|
+
initialHits: [],
|
|
871
|
+
capturedMap: /* @__PURE__ */ new Map(),
|
|
872
|
+
// Visibility tracking (onFramed, onOccluded, onVisible)
|
|
873
|
+
visibilityRegistry: /* @__PURE__ */ new Map(),
|
|
874
|
+
// Occlusion system (WebGPU only)
|
|
875
|
+
occlusionEnabled: false,
|
|
876
|
+
occlusionObserver: null,
|
|
877
|
+
occlusionCache: /* @__PURE__ */ new Map(),
|
|
878
|
+
helperGroup: null,
|
|
879
|
+
// Updates
|
|
880
|
+
active: false,
|
|
881
|
+
frames: 0,
|
|
882
|
+
priority: 0,
|
|
883
|
+
subscribe: (ref, priority, store) => {
|
|
884
|
+
const internal = get().internal;
|
|
885
|
+
internal.priority = internal.priority + (priority > 0 ? 1 : 0);
|
|
886
|
+
internal.subscribers.push({ ref, priority, store });
|
|
887
|
+
internal.subscribers = internal.subscribers.sort((a, b) => a.priority - b.priority);
|
|
888
|
+
return () => {
|
|
889
|
+
const internal2 = get().internal;
|
|
890
|
+
if (internal2?.subscribers) {
|
|
891
|
+
internal2.priority = internal2.priority - (priority > 0 ? 1 : 0);
|
|
892
|
+
internal2.subscribers = internal2.subscribers.filter((s) => s.ref !== ref);
|
|
893
|
+
}
|
|
894
|
+
};
|
|
895
|
+
},
|
|
896
|
+
// Renderer Storage (single source of truth)
|
|
897
|
+
actualRenderer: null,
|
|
898
|
+
// The renderer support configure() loads for this root
|
|
899
|
+
support: null,
|
|
900
|
+
// Scheduler for useFrameNext (initialized in loop.ts)
|
|
901
|
+
scheduler: null,
|
|
902
|
+
// Replaces the default render call when set (see setRenderOverride)
|
|
903
|
+
renderOverride: null
|
|
900
904
|
}
|
|
901
905
|
};
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
const
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
opts = widthOrOptions;
|
|
916
|
-
} else if (typeof widthOrOptions === "number") {
|
|
917
|
-
width = widthOrOptions;
|
|
918
|
-
if (typeof heightOrOptions === "object") {
|
|
919
|
-
height = widthOrOptions;
|
|
920
|
-
opts = heightOrOptions;
|
|
921
|
-
} else if (typeof heightOrOptions === "number") {
|
|
922
|
-
height = heightOrOptions;
|
|
923
|
-
opts = options;
|
|
924
|
-
} else {
|
|
925
|
-
height = widthOrOptions;
|
|
906
|
+
return rootState;
|
|
907
|
+
});
|
|
908
|
+
const state = rootStore.getState();
|
|
909
|
+
textureStaging.defineRendererAccessors(state);
|
|
910
|
+
let oldScene = state.scene;
|
|
911
|
+
rootStore.subscribe(() => {
|
|
912
|
+
const currentState = rootStore.getState();
|
|
913
|
+
const { scene, rootScene, set } = currentState;
|
|
914
|
+
if (scene !== oldScene) {
|
|
915
|
+
oldScene = scene;
|
|
916
|
+
if (scene?.isScene && scene !== rootScene) {
|
|
917
|
+
set({ rootScene: scene });
|
|
918
|
+
}
|
|
926
919
|
}
|
|
927
|
-
}
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
920
|
+
});
|
|
921
|
+
let oldSize = state.size;
|
|
922
|
+
let oldDpr = state.viewport.dpr;
|
|
923
|
+
let oldCamera = state.camera;
|
|
924
|
+
rootStore.subscribe(() => {
|
|
925
|
+
const { camera, size, viewport, set, internal } = rootStore.getState();
|
|
926
|
+
const actualRenderer = internal.actualRenderer;
|
|
927
|
+
const canvasTarget = internal.canvasTarget;
|
|
928
|
+
if (size.width !== oldSize.width || size.height !== oldSize.height || viewport.dpr !== oldDpr) {
|
|
929
|
+
oldSize = size;
|
|
930
|
+
oldDpr = viewport.dpr;
|
|
931
|
+
updateCamera(camera, size);
|
|
932
|
+
const resizeTarget = canvasTarget ?? actualRenderer;
|
|
933
|
+
if (viewport.dpr > 0) resizeTarget.setPixelRatio(viewport.dpr);
|
|
934
|
+
resizeTarget.setSize(size.width, size.height, false);
|
|
935
|
+
const activeTarget = actualRenderer.getCanvasTarget?.();
|
|
936
|
+
if (!canvasTarget || activeTarget !== canvasTarget) internal.canvasTargetSizeDirty = true;
|
|
937
|
+
}
|
|
938
|
+
if (camera !== oldCamera) {
|
|
939
|
+
oldCamera = camera;
|
|
940
|
+
const { rootScene } = rootStore.getState();
|
|
941
|
+
if (camera && rootScene && !camera.parent) {
|
|
942
|
+
rootScene.add(camera);
|
|
943
|
+
}
|
|
944
|
+
set((state2) => ({ viewport: { ...state2.viewport, ...state2.viewport.getCurrentViewport(camera) } }));
|
|
945
|
+
const currentState = rootStore.getState();
|
|
946
|
+
if (currentState.autoUpdateFrustum && camera) {
|
|
947
|
+
updateFrustum(camera, currentState.frustum);
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
});
|
|
951
|
+
rootStore.subscribe((state2) => {
|
|
952
|
+
if (state2.internal.active) invalidate(state2);
|
|
953
|
+
});
|
|
954
|
+
return rootStore;
|
|
947
955
|
};
|
|
948
956
|
|
|
949
|
-
const
|
|
950
|
-
|
|
951
|
-
const
|
|
952
|
-
const
|
|
953
|
-
const
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
957
|
+
const shallowLoose$1 = { objects: "shallow", strict: false };
|
|
958
|
+
function configureScheduler(store, canvasId, schedulerConfig, previous) {
|
|
959
|
+
const state = store.getState();
|
|
960
|
+
const scheduler$1 = scheduler.getScheduler();
|
|
961
|
+
const rootId = state.internal.rootId;
|
|
962
|
+
const ordersItself = schedulerConfig?.before !== void 0 || schedulerConfig?.after !== void 0;
|
|
963
|
+
const rootBefore = schedulerConfig?.before;
|
|
964
|
+
const rootAfter = ordersItself ? schedulerConfig?.after : state.internal.sharedAfter;
|
|
965
|
+
if (!rootId) {
|
|
966
|
+
const newRootId = state.internal.pendingRootId ?? canvasId ?? scheduler$1.generateRootId();
|
|
967
|
+
const unregisterRoot = scheduler$1.registerRoot(newRootId, {
|
|
968
|
+
// The scheduler spreads this into each frame state; see stateForScheduler
|
|
969
|
+
getState: () => textureStaging.stateForScheduler(store.getState()),
|
|
970
|
+
onError: (err) => store.getState().setError(err),
|
|
971
|
+
frameloop: store.getState().frameloop,
|
|
972
|
+
before: rootBefore,
|
|
973
|
+
after: rootAfter,
|
|
974
|
+
order: schedulerConfig?.order
|
|
975
|
+
});
|
|
976
|
+
const unregisterCanvasTarget = scheduler$1.register(
|
|
977
|
+
() => {
|
|
978
|
+
const state2 = store.getState();
|
|
979
|
+
const canvasTarget = state2.internal.canvasTarget;
|
|
980
|
+
if (canvasTarget) {
|
|
981
|
+
const renderer = state2.internal.actualRenderer;
|
|
982
|
+
if (renderer.getCanvasTarget() !== canvasTarget) renderer.setCanvasTarget(canvasTarget);
|
|
983
|
+
if (state2.internal.canvasTargetSizeDirty) {
|
|
984
|
+
state2.internal.canvasTargetSizeDirty = false;
|
|
985
|
+
renderer.backend?.updateSize?.();
|
|
986
|
+
}
|
|
987
|
+
}
|
|
961
988
|
},
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
989
|
+
{
|
|
990
|
+
id: `${newRootId}_canvasTarget`,
|
|
991
|
+
rootId: newRootId,
|
|
992
|
+
phase: "start",
|
|
993
|
+
system: true
|
|
965
994
|
}
|
|
966
995
|
);
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
}
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
}
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
loadLoader(format).then((loader) => {
|
|
1048
|
-
useLoader.preload(loader, input, (loader2) => {
|
|
1049
|
-
loader2.setPath?.(path);
|
|
1050
|
-
if (extensions) extensions(loader2);
|
|
1051
|
-
});
|
|
1052
|
-
});
|
|
1053
|
-
};
|
|
1054
|
-
const clearDefaultOptins = {
|
|
1055
|
-
files: defaultFiles,
|
|
1056
|
-
preset: void 0
|
|
1057
|
-
};
|
|
1058
|
-
useEnvironment.clear = (clearOptions) => {
|
|
1059
|
-
const options = { ...clearDefaultOptins, ...clearOptions };
|
|
1060
|
-
let { files } = options;
|
|
1061
|
-
const { preset } = options;
|
|
1062
|
-
if (preset) {
|
|
1063
|
-
validatePreset(preset);
|
|
1064
|
-
files = presetsObj[preset];
|
|
1065
|
-
}
|
|
1066
|
-
const { format } = getFormat(files);
|
|
1067
|
-
if (!format) throw new Error("useEnvironment: Unrecognized file extension: " + files);
|
|
1068
|
-
const input = isArray(files) ? [files] : files;
|
|
1069
|
-
const clear = (loader2) => useLoader.clear(loader2, input);
|
|
1070
|
-
const loader = loadedLoaders.get(format);
|
|
1071
|
-
if (loader) {
|
|
1072
|
-
clear(loader);
|
|
996
|
+
const unregisterEventsFlush = scheduler$1.register(
|
|
997
|
+
() => {
|
|
998
|
+
const state2 = store.getState();
|
|
999
|
+
state2.events.flush?.();
|
|
1000
|
+
},
|
|
1001
|
+
{
|
|
1002
|
+
id: `${newRootId}_events`,
|
|
1003
|
+
rootId: newRootId,
|
|
1004
|
+
phase: "input",
|
|
1005
|
+
system: true
|
|
1006
|
+
}
|
|
1007
|
+
);
|
|
1008
|
+
const unregisterFrustum = scheduler$1.register(
|
|
1009
|
+
() => {
|
|
1010
|
+
const state2 = store.getState();
|
|
1011
|
+
if (state2.autoUpdateFrustum && state2.camera) {
|
|
1012
|
+
updateFrustum(state2.camera, state2.frustum);
|
|
1013
|
+
}
|
|
1014
|
+
},
|
|
1015
|
+
{
|
|
1016
|
+
id: `${newRootId}_frustum`,
|
|
1017
|
+
rootId: newRootId,
|
|
1018
|
+
before: "render",
|
|
1019
|
+
system: true
|
|
1020
|
+
}
|
|
1021
|
+
);
|
|
1022
|
+
const unregisterVisibility = scheduler$1.register(
|
|
1023
|
+
() => {
|
|
1024
|
+
const state2 = store.getState();
|
|
1025
|
+
checkVisibility(state2);
|
|
1026
|
+
},
|
|
1027
|
+
{
|
|
1028
|
+
id: `${newRootId}_visibility`,
|
|
1029
|
+
rootId: newRootId,
|
|
1030
|
+
before: "render",
|
|
1031
|
+
system: true,
|
|
1032
|
+
after: `${newRootId}_frustum`
|
|
1033
|
+
}
|
|
1034
|
+
);
|
|
1035
|
+
const unregisterRender = scheduler$1.register(
|
|
1036
|
+
() => {
|
|
1037
|
+
const state2 = store.getState();
|
|
1038
|
+
const renderer = state2.internal.actualRenderer;
|
|
1039
|
+
const userHandlesRender = scheduler$1.hasUserJobsInPhase("render", newRootId);
|
|
1040
|
+
if (userHandlesRender || state2.internal.priority) return;
|
|
1041
|
+
try {
|
|
1042
|
+
const renderOverride = state2.internal.renderOverride;
|
|
1043
|
+
if (renderOverride) renderOverride();
|
|
1044
|
+
else if (renderer?.render) renderer.render(state2.scene, state2.camera);
|
|
1045
|
+
} catch (error) {
|
|
1046
|
+
state2.setError(error instanceof Error ? error : new Error(String(error)));
|
|
1047
|
+
}
|
|
1048
|
+
},
|
|
1049
|
+
{
|
|
1050
|
+
// Use canvas ID directly as job ID if available, otherwise use generated rootId
|
|
1051
|
+
id: canvasId || `${newRootId}_render`,
|
|
1052
|
+
rootId: newRootId,
|
|
1053
|
+
phase: "render",
|
|
1054
|
+
system: true,
|
|
1055
|
+
// Internal flag: this is a system job, not user-controlled
|
|
1056
|
+
// FPS throttles only the default render job; Canvas ordering belongs to the root.
|
|
1057
|
+
...schedulerConfig?.fps && { fps: schedulerConfig.fps }
|
|
1058
|
+
}
|
|
1059
|
+
);
|
|
1060
|
+
state.set((state2) => ({
|
|
1061
|
+
internal: {
|
|
1062
|
+
...state2.internal,
|
|
1063
|
+
rootId: newRootId,
|
|
1064
|
+
pendingRootId: void 0,
|
|
1065
|
+
unregisterRoot: () => {
|
|
1066
|
+
unregisterRoot();
|
|
1067
|
+
unregisterCanvasTarget();
|
|
1068
|
+
unregisterEventsFlush();
|
|
1069
|
+
unregisterFrustum();
|
|
1070
|
+
unregisterVisibility();
|
|
1071
|
+
unregisterRender();
|
|
1072
|
+
},
|
|
1073
|
+
scheduler: scheduler$1
|
|
1074
|
+
}
|
|
1075
|
+
}));
|
|
1073
1076
|
} else {
|
|
1074
|
-
const
|
|
1075
|
-
if (
|
|
1076
|
-
|
|
1077
|
+
const constraintsChanged = !is.equ(schedulerConfig?.before, previous?.before, shallowLoose$1) || !is.equ(schedulerConfig?.after, previous?.after, shallowLoose$1);
|
|
1078
|
+
if (constraintsChanged) {
|
|
1079
|
+
scheduler$1.setRootConstraints(rootId, {
|
|
1080
|
+
before: rootBefore,
|
|
1081
|
+
after: rootAfter
|
|
1082
|
+
});
|
|
1083
|
+
}
|
|
1084
|
+
if (schedulerConfig?.order !== previous?.order) {
|
|
1085
|
+
scheduler$1.setRootOrder(rootId, schedulerConfig?.order ?? 0);
|
|
1086
|
+
}
|
|
1077
1087
|
}
|
|
1078
|
-
};
|
|
1079
|
-
function validatePreset(preset) {
|
|
1080
|
-
if (!(preset in presetsObj)) throw new Error("Preset must be one of: " + Object.keys(presetsObj).join(", "));
|
|
1081
|
-
}
|
|
1082
|
-
function getFormat(files) {
|
|
1083
|
-
const isCubemap = isArray(files) && files.length === 6;
|
|
1084
|
-
const firstEntry = isArray(files) ? files[0] : files;
|
|
1085
|
-
const firstExtension = firstEntry.split(".").pop()?.split("?")?.shift()?.toLowerCase();
|
|
1086
|
-
let format;
|
|
1087
|
-
if (isCubemap) format = firstExtension === "hdr" ? "hdr-cube" : "cube";
|
|
1088
|
-
else if (firstEntry.startsWith("data:application/exr")) format = "exr";
|
|
1089
|
-
else if (firstEntry.startsWith("data:application/hdr")) format = "hdr";
|
|
1090
|
-
else if (firstEntry.startsWith("data:image/jpeg")) format = "jpg";
|
|
1091
|
-
else if (firstExtension === "hdr" || firstExtension === "exr") format = firstExtension;
|
|
1092
|
-
else if (firstExtension === "jpg" || firstExtension === "jpeg") format = "jpg";
|
|
1093
|
-
return { format, isCubemap };
|
|
1094
|
-
}
|
|
1095
|
-
|
|
1096
|
-
function useInstanceHandle(ref) {
|
|
1097
|
-
const instance = React.useRef(null);
|
|
1098
|
-
React.useImperativeHandle(instance, () => ref.current.__r3f, [ref]);
|
|
1099
|
-
return instance;
|
|
1100
|
-
}
|
|
1101
|
-
function useGraph(object) {
|
|
1102
|
-
return React.useMemo(() => buildGraph(object), [object]);
|
|
1103
1088
|
}
|
|
1104
|
-
|
|
1105
1089
|
let effectId = 0;
|
|
1106
1090
|
function addEffect(callback) {
|
|
1107
|
-
|
|
1091
|
+
textureStaging.notifyDepreciated({
|
|
1108
1092
|
heading: "addEffect is deprecated",
|
|
1109
1093
|
body: 'Use useFrame(callback, { phase: "start" }) instead.\naddEffect will be removed in a future version.',
|
|
1110
1094
|
link: "https://docs.pmnd.rs/react-three-fiber/api/hooks#useframe"
|
|
@@ -1113,7 +1097,7 @@ function addEffect(callback) {
|
|
|
1113
1097
|
return scheduler.getScheduler().registerGlobal("before", id, callback);
|
|
1114
1098
|
}
|
|
1115
1099
|
function addAfterEffect(callback) {
|
|
1116
|
-
|
|
1100
|
+
textureStaging.notifyDepreciated({
|
|
1117
1101
|
heading: "addAfterEffect is deprecated",
|
|
1118
1102
|
body: 'Use useFrame(callback, { phase: "finish" }) instead.\naddAfterEffect will be removed in a future version.',
|
|
1119
1103
|
link: "https://docs.pmnd.rs/react-three-fiber/api/hooks#useframe"
|
|
@@ -1122,7 +1106,7 @@ function addAfterEffect(callback) {
|
|
|
1122
1106
|
return scheduler.getScheduler().registerGlobal("after", id, callback);
|
|
1123
1107
|
}
|
|
1124
1108
|
function addTail(callback) {
|
|
1125
|
-
|
|
1109
|
+
textureStaging.notifyDepreciated({
|
|
1126
1110
|
heading: "addTail is deprecated",
|
|
1127
1111
|
body: "Use scheduler.onIdle(callback) instead.\naddTail will be removed in a future version.",
|
|
1128
1112
|
link: "https://docs.pmnd.rs/react-three-fiber/api/hooks#useframe"
|
|
@@ -1142,6 +1126,790 @@ function advance(timestamp, runGlobalEffects, state) {
|
|
|
1142
1126
|
else scheduler$1.step(timestamp);
|
|
1143
1127
|
}
|
|
1144
1128
|
|
|
1129
|
+
const isPromiseLike = (value) => typeof value?.then === "function";
|
|
1130
|
+
const fulfilled = (value) => Object.assign(Promise.resolve(value), { status: "fulfilled", value });
|
|
1131
|
+
const rejected = (reason) => {
|
|
1132
|
+
const promise = Promise.reject(reason);
|
|
1133
|
+
promise.catch(() => {
|
|
1134
|
+
});
|
|
1135
|
+
return Object.assign(promise, { status: "rejected", reason });
|
|
1136
|
+
};
|
|
1137
|
+
const deferred = () => {
|
|
1138
|
+
let resolve;
|
|
1139
|
+
let reject;
|
|
1140
|
+
const promise = new Promise((yes, no) => {
|
|
1141
|
+
resolve = (value) => {
|
|
1142
|
+
Object.assign(promise, { status: "fulfilled", value });
|
|
1143
|
+
yes(value);
|
|
1144
|
+
};
|
|
1145
|
+
reject = (reason) => {
|
|
1146
|
+
Object.assign(promise, { status: "rejected", reason });
|
|
1147
|
+
no(reason);
|
|
1148
|
+
};
|
|
1149
|
+
});
|
|
1150
|
+
promise.status = "pending";
|
|
1151
|
+
promise.catch(() => {
|
|
1152
|
+
});
|
|
1153
|
+
return { promise, resolve, reject };
|
|
1154
|
+
};
|
|
1155
|
+
function resolveThen(value, apply) {
|
|
1156
|
+
return isPromiseLike(value) ? Promise.resolve(value).then(apply) : apply(value);
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
const isRenderer = (def) => !!def?.render;
|
|
1160
|
+
function ensureStoreThreeObjects(store) {
|
|
1161
|
+
const state = store.getState();
|
|
1162
|
+
if (state.pointer) return;
|
|
1163
|
+
const { Vector2, Frustum } = getThree();
|
|
1164
|
+
const pointer = new Vector2();
|
|
1165
|
+
state.set({ pointer, mouse: pointer, frustum: new Frustum() });
|
|
1166
|
+
}
|
|
1167
|
+
const R3F_RENDERER_SETTINGS = ["textureColorSpace", "shadows"];
|
|
1168
|
+
const NON_APPLIED_RENDERER_PROPS = /* @__PURE__ */ new Set([
|
|
1169
|
+
...R3F_RENDERER_SETTINGS,
|
|
1170
|
+
"canvas",
|
|
1171
|
+
"antialias",
|
|
1172
|
+
"alpha",
|
|
1173
|
+
"samples",
|
|
1174
|
+
"powerPreference",
|
|
1175
|
+
"depth",
|
|
1176
|
+
"stencil",
|
|
1177
|
+
"logarithmicDepthBuffer",
|
|
1178
|
+
"reversedDepthBuffer",
|
|
1179
|
+
// WebGPURenderer only
|
|
1180
|
+
"forceWebGL",
|
|
1181
|
+
"outputBufferType",
|
|
1182
|
+
"multiview",
|
|
1183
|
+
"getFallback",
|
|
1184
|
+
"trackTimestamp"
|
|
1185
|
+
]);
|
|
1186
|
+
function settingsBag(config) {
|
|
1187
|
+
return is.obj(config) && !isRenderer(config) ? config : void 0;
|
|
1188
|
+
}
|
|
1189
|
+
function isInstanceOrFactory(config) {
|
|
1190
|
+
return is.fun(config) || isRenderer(config);
|
|
1191
|
+
}
|
|
1192
|
+
function assertNoRemovedConfig(props) {
|
|
1193
|
+
if (props.primaryCanvas !== void 0) {
|
|
1194
|
+
throw new Error(
|
|
1195
|
+
'R3F: `primaryCanvas` was removed: mark the owner <Canvas primary> and other canvases share it automatically (or use share="id")'
|
|
1196
|
+
);
|
|
1197
|
+
}
|
|
1198
|
+
if (props.shadows !== void 0) {
|
|
1199
|
+
throw new Error(
|
|
1200
|
+
"R3F: the `shadows` Canvas prop moved into the renderer settings: use `renderer={{ shadows }}` (or `gl={{ shadows }}` for WebGL and @react-three/fiber/legacy)"
|
|
1201
|
+
);
|
|
1202
|
+
}
|
|
1203
|
+
for (const name of ["renderer", "gl"]) {
|
|
1204
|
+
const bag = settingsBag(props[name]);
|
|
1205
|
+
if (!bag) continue;
|
|
1206
|
+
if ("primaryCanvas" in bag) {
|
|
1207
|
+
throw new Error(
|
|
1208
|
+
`R3F: \`${name}={{ primaryCanvas }}\` was removed: mark the owner <Canvas primary> and other canvases share it automatically (or use share="id")`
|
|
1209
|
+
);
|
|
1210
|
+
}
|
|
1211
|
+
if ("scheduler" in bag) {
|
|
1212
|
+
throw new Error(`R3F: \`${name}={{ scheduler }}\` moved to <Canvas scheduler>`);
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
function resolveRenderer(config, defaultProps, RendererClass) {
|
|
1217
|
+
if (typeof config === "function") {
|
|
1218
|
+
return resolveThen(config(defaultProps), (renderer) => ({
|
|
1219
|
+
renderer,
|
|
1220
|
+
owned: true
|
|
1221
|
+
}));
|
|
1222
|
+
}
|
|
1223
|
+
if (isRenderer(config)) return { renderer: config, owned: false };
|
|
1224
|
+
const params = { ...defaultProps };
|
|
1225
|
+
for (const key in settingsBag(config)) if (!R3F_RENDERER_SETTINGS.includes(key)) params[key] = config[key];
|
|
1226
|
+
return { renderer: new RendererClass(params), owned: true };
|
|
1227
|
+
}
|
|
1228
|
+
function createOwnedWebGPURenderer(rendererConfig, defaultGPUProps, canvas, propsSize, dpr, support) {
|
|
1229
|
+
return resolveThen(resolveRenderer(rendererConfig, defaultGPUProps, support.Renderer), (resolved) => {
|
|
1230
|
+
const renderer = resolved.renderer;
|
|
1231
|
+
if (!renderer.hasInitialized?.()) {
|
|
1232
|
+
const size = computeInitialSize(canvas, propsSize);
|
|
1233
|
+
if (size.width > 0 && size.height > 0) {
|
|
1234
|
+
renderer.setPixelRatio(calculateDpr(dpr));
|
|
1235
|
+
renderer.setSize(size.width, size.height, false);
|
|
1236
|
+
}
|
|
1237
|
+
return resolveThen(renderer.init(), () => ({ renderer, owned: resolved.owned }));
|
|
1238
|
+
}
|
|
1239
|
+
return { renderer, owned: resolved.owned };
|
|
1240
|
+
});
|
|
1241
|
+
}
|
|
1242
|
+
function initializeRenderer(canvas, provider, store, props) {
|
|
1243
|
+
const {
|
|
1244
|
+
id: canvasId,
|
|
1245
|
+
primary = false,
|
|
1246
|
+
share,
|
|
1247
|
+
gl: glConfig,
|
|
1248
|
+
renderer: rendererConfig,
|
|
1249
|
+
size: propsSize,
|
|
1250
|
+
dpr = [1, 2],
|
|
1251
|
+
_primaryToken
|
|
1252
|
+
} = props;
|
|
1253
|
+
assertNoRemovedConfig(props);
|
|
1254
|
+
const rendererBag = settingsBag(rendererConfig);
|
|
1255
|
+
const state = store.getState();
|
|
1256
|
+
const { webgl, webgpu } = provider;
|
|
1257
|
+
const defaultGLProps = {
|
|
1258
|
+
canvas,
|
|
1259
|
+
powerPreference: "high-performance",
|
|
1260
|
+
antialias: true,
|
|
1261
|
+
alpha: true
|
|
1262
|
+
};
|
|
1263
|
+
const defaultGPUProps = {
|
|
1264
|
+
canvas,
|
|
1265
|
+
antialias: true
|
|
1266
|
+
};
|
|
1267
|
+
if (glConfig && !webgl) {
|
|
1268
|
+
throw new Error(
|
|
1269
|
+
"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."
|
|
1270
|
+
);
|
|
1271
|
+
}
|
|
1272
|
+
if (rendererConfig && !webgpu) {
|
|
1273
|
+
throw new Error(
|
|
1274
|
+
"WebGPURenderer (renderer prop) is not available on this entry. Use @react-three/fiber or @react-three/fiber/webgpu instead."
|
|
1275
|
+
);
|
|
1276
|
+
}
|
|
1277
|
+
if (glConfig && rendererConfig) {
|
|
1278
|
+
throw new Error("Cannot use both gl and renderer props at the same time");
|
|
1279
|
+
}
|
|
1280
|
+
if (primary && !webgpu) {
|
|
1281
|
+
throw new Error(
|
|
1282
|
+
"R3F: <Canvas primary> shares a WebGPU renderer and is not available on this entry. Use @react-three/fiber or @react-three/fiber/webgpu instead."
|
|
1283
|
+
);
|
|
1284
|
+
}
|
|
1285
|
+
if (primary && glConfig) {
|
|
1286
|
+
throw new Error(
|
|
1287
|
+
"R3F: <Canvas primary> shares a WebGPU renderer and cannot be used with WebGL. Remove the `gl` prop or use the `renderer` prop."
|
|
1288
|
+
);
|
|
1289
|
+
}
|
|
1290
|
+
if (primary && is.str(share)) {
|
|
1291
|
+
throw new Error(`R3F: a <Canvas primary> owns its renderer; remove share="${share}" from it.`);
|
|
1292
|
+
}
|
|
1293
|
+
if (is.str(share)) {
|
|
1294
|
+
if (!webgpu || glConfig) {
|
|
1295
|
+
throw new Error(
|
|
1296
|
+
`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.`
|
|
1297
|
+
);
|
|
1298
|
+
}
|
|
1299
|
+
if (isInstanceOrFactory(rendererConfig)) {
|
|
1300
|
+
throw new Error(
|
|
1301
|
+
`R3F: share="${share}" borrows the primary's renderer, so it cannot be combined with a renderer instance or factory. Remove one of the two.`
|
|
1302
|
+
);
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
const primaryKey = canvasId || DEFAULT_PRIMARY;
|
|
1306
|
+
const primaryToken = _primaryToken ?? store;
|
|
1307
|
+
if (primary && !state.internal.actualRenderer) {
|
|
1308
|
+
announcePrimary(primaryKey, primaryToken);
|
|
1309
|
+
state.internal.unregisterPrimary = () => withdrawPrimary(primaryKey, primaryToken);
|
|
1310
|
+
if (primaryConflict(primaryKey, primaryToken)) {
|
|
1311
|
+
throw new Error(
|
|
1312
|
+
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\`.`
|
|
1313
|
+
);
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
let shareKey;
|
|
1317
|
+
if (!state.internal.actualRenderer && webgpu && !primary && !glConfig && !state.isLegacy) {
|
|
1318
|
+
if (is.str(share)) {
|
|
1319
|
+
shareKey = share;
|
|
1320
|
+
} else if (share !== false && !isInstanceOrFactory(rendererConfig)) {
|
|
1321
|
+
const live = livePrimaryKeys();
|
|
1322
|
+
if (live.length > 1) {
|
|
1323
|
+
throw new Error(
|
|
1324
|
+
`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.`
|
|
1325
|
+
);
|
|
1326
|
+
}
|
|
1327
|
+
shareKey = live[0];
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
const explicitShare = is.str(share);
|
|
1331
|
+
const wantsGL = !!webgl && (state.isLegacy || !!glConfig || !webgpu || !rendererConfig && !primary && shareKey === void 0);
|
|
1332
|
+
let renderer = state.internal.actualRenderer;
|
|
1333
|
+
if (!state.internal.actualRenderer) {
|
|
1334
|
+
return resolveThen(wantsGL ? webgl() : webgpu(), (support) => {
|
|
1335
|
+
registerThree(support.three);
|
|
1336
|
+
state.internal.support = support;
|
|
1337
|
+
ensureStoreThreeObjects(store);
|
|
1338
|
+
if (support.kind === "webgl") {
|
|
1339
|
+
return resolveThen(resolveRenderer(glConfig, defaultGLProps, support.Renderer), (resolved) => {
|
|
1340
|
+
renderer = resolved.renderer;
|
|
1341
|
+
state.internal.actualRenderer = renderer;
|
|
1342
|
+
state.internal.releaseRenderer = leaseRenderer(renderer, resolved.owned);
|
|
1343
|
+
state.set({ isLegacy: true, gl: renderer, renderer, primaryStore: store });
|
|
1344
|
+
});
|
|
1345
|
+
}
|
|
1346
|
+
const primaryReady = shareKey === void 0 ? null : explicitShare ? waitForPrimary(shareKey) : waitForAnnouncedPrimary(shareKey);
|
|
1347
|
+
return resolveThen(primaryReady, (primaryEntry) => {
|
|
1348
|
+
if (primaryEntry && primaryEntry.store.getState().webGPUSupported) {
|
|
1349
|
+
renderer = primaryEntry.renderer;
|
|
1350
|
+
state.internal.actualRenderer = renderer;
|
|
1351
|
+
state.internal.releaseRenderer = borrowRenderer(renderer);
|
|
1352
|
+
state.internal.sharedAfter = primaryEntry.rootId;
|
|
1353
|
+
const canvasTarget = new support.CanvasTarget(canvas);
|
|
1354
|
+
primaryEntry.store.setState((prev) => ({
|
|
1355
|
+
internal: { ...prev.internal, isMultiCanvas: true }
|
|
1356
|
+
}));
|
|
1357
|
+
state.set((prev) => ({
|
|
1358
|
+
webGPUSupported: primaryEntry.store.getState().webGPUSupported,
|
|
1359
|
+
renderer,
|
|
1360
|
+
primaryStore: primaryEntry.store,
|
|
1361
|
+
internal: {
|
|
1362
|
+
...prev.internal,
|
|
1363
|
+
canvasTarget,
|
|
1364
|
+
isMultiCanvas: true,
|
|
1365
|
+
isSecondary: true,
|
|
1366
|
+
targetId: shareKey === DEFAULT_PRIMARY ? void 0 : shareKey
|
|
1367
|
+
}
|
|
1368
|
+
}));
|
|
1369
|
+
return;
|
|
1370
|
+
}
|
|
1371
|
+
if (primaryEntry) {
|
|
1372
|
+
return resolveThen(
|
|
1373
|
+
createOwnedWebGPURenderer(
|
|
1374
|
+
{ ...rendererBag, forceWebGL: true },
|
|
1375
|
+
defaultGPUProps,
|
|
1376
|
+
canvas,
|
|
1377
|
+
propsSize,
|
|
1378
|
+
dpr,
|
|
1379
|
+
support
|
|
1380
|
+
),
|
|
1381
|
+
(resolved) => {
|
|
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((prev) => ({
|
|
1388
|
+
webGPUSupported: isWebGPUBackend,
|
|
1389
|
+
renderer,
|
|
1390
|
+
primaryStore: store,
|
|
1391
|
+
internal: {
|
|
1392
|
+
...prev.internal,
|
|
1393
|
+
canvasTarget: renderer.getCanvasTarget?.(),
|
|
1394
|
+
sharedRendererFallback: true
|
|
1395
|
+
}
|
|
1396
|
+
}));
|
|
1397
|
+
}
|
|
1398
|
+
);
|
|
1399
|
+
}
|
|
1400
|
+
return resolveThen(
|
|
1401
|
+
createOwnedWebGPURenderer(rendererConfig, defaultGPUProps, canvas, propsSize, dpr, support),
|
|
1402
|
+
(resolved) => {
|
|
1403
|
+
var _a;
|
|
1404
|
+
renderer = resolved.renderer;
|
|
1405
|
+
const backend = renderer.backend;
|
|
1406
|
+
const isWebGPUBackend = backend && "isWebGPUBackend" in backend;
|
|
1407
|
+
state.internal.actualRenderer = renderer;
|
|
1408
|
+
state.internal.releaseRenderer = leaseRenderer(renderer, resolved.owned);
|
|
1409
|
+
state.set({ webGPUSupported: isWebGPUBackend, renderer, primaryStore: store });
|
|
1410
|
+
if (primary) {
|
|
1411
|
+
const canvasTarget = renderer.getCanvasTarget?.();
|
|
1412
|
+
(_a = state.internal).pendingRootId ?? (_a.pendingRootId = canvasId || scheduler.getScheduler().generateRootId());
|
|
1413
|
+
registerPrimary(primaryKey, renderer, store, {
|
|
1414
|
+
token: primaryToken,
|
|
1415
|
+
rootId: state.internal.pendingRootId
|
|
1416
|
+
});
|
|
1417
|
+
state.set((prev) => ({ internal: { ...prev.internal, canvasTarget } }));
|
|
1418
|
+
} else if (share !== false && !isInstanceOrFactory(rendererConfig)) {
|
|
1419
|
+
state.internal.untrackStandalone = trackStandalone(store);
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
);
|
|
1423
|
+
});
|
|
1424
|
+
});
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
const records = /* @__PURE__ */ new WeakMap();
|
|
1428
|
+
function take(renderer, record) {
|
|
1429
|
+
record.leases++;
|
|
1430
|
+
let released = false;
|
|
1431
|
+
return () => {
|
|
1432
|
+
if (released) return;
|
|
1433
|
+
released = true;
|
|
1434
|
+
if (--record.leases > 0) return;
|
|
1435
|
+
records.delete(renderer);
|
|
1436
|
+
if (record.owned) return disposeRenderer(renderer);
|
|
1437
|
+
};
|
|
1438
|
+
}
|
|
1439
|
+
function leaseRenderer(renderer, owned) {
|
|
1440
|
+
let record = records.get(renderer);
|
|
1441
|
+
if (!record) records.set(renderer, record = { owned, leases: 0 });
|
|
1442
|
+
return take(renderer, record);
|
|
1443
|
+
}
|
|
1444
|
+
function borrowRenderer(renderer) {
|
|
1445
|
+
const record = records.get(renderer);
|
|
1446
|
+
if (!record) throw new Error("R3F: cannot share a renderer whose canvas has already unmounted");
|
|
1447
|
+
return take(renderer, record);
|
|
1448
|
+
}
|
|
1449
|
+
function disposeRenderer(renderer) {
|
|
1450
|
+
if (renderer.hasInitialized?.() === false) return;
|
|
1451
|
+
const warn = (error) => console.warn("[R3F] Error disposing renderer", error);
|
|
1452
|
+
const loseContext = () => {
|
|
1453
|
+
try {
|
|
1454
|
+
;
|
|
1455
|
+
renderer.forceContextLoss?.();
|
|
1456
|
+
} catch (error) {
|
|
1457
|
+
warn(error);
|
|
1458
|
+
}
|
|
1459
|
+
};
|
|
1460
|
+
let disposed;
|
|
1461
|
+
try {
|
|
1462
|
+
disposed = renderer.dispose ? renderer.dispose() : renderer.renderLists?.dispose?.();
|
|
1463
|
+
} catch (error) {
|
|
1464
|
+
warn(error);
|
|
1465
|
+
}
|
|
1466
|
+
if (typeof disposed?.then === "function") {
|
|
1467
|
+
return Promise.resolve(disposed).then(loseContext, (error) => {
|
|
1468
|
+
warn(error);
|
|
1469
|
+
loseContext();
|
|
1470
|
+
});
|
|
1471
|
+
}
|
|
1472
|
+
loseContext();
|
|
1473
|
+
}
|
|
1474
|
+
const DEFAULT_PRIMARY = "\0r3f:primary";
|
|
1475
|
+
const primaryRegistry = /* @__PURE__ */ new Map();
|
|
1476
|
+
const announcements = /* @__PURE__ */ new Map();
|
|
1477
|
+
const withdrawing = /* @__PURE__ */ new Set();
|
|
1478
|
+
const pendingSubscribers = /* @__PURE__ */ new Map();
|
|
1479
|
+
const standaloneRoots = /* @__PURE__ */ new Set();
|
|
1480
|
+
const warnedLatePrimary = /* @__PURE__ */ new WeakSet();
|
|
1481
|
+
function describePrimary(key) {
|
|
1482
|
+
return key === DEFAULT_PRIMARY ? "<Canvas primary>" : `<Canvas id="${key}" primary>`;
|
|
1483
|
+
}
|
|
1484
|
+
function notify(key, entry) {
|
|
1485
|
+
const subscribers = pendingSubscribers.get(key);
|
|
1486
|
+
if (!subscribers) return;
|
|
1487
|
+
pendingSubscribers.delete(key);
|
|
1488
|
+
subscribers.forEach((callback) => callback(entry));
|
|
1489
|
+
}
|
|
1490
|
+
function isLive(key) {
|
|
1491
|
+
const owners = announcements.get(key);
|
|
1492
|
+
if (owners) {
|
|
1493
|
+
for (const owner of owners) if (!withdrawing.has(owner)) return true;
|
|
1494
|
+
}
|
|
1495
|
+
const entry = primaryRegistry.get(key);
|
|
1496
|
+
return !!entry && !(entry.token && withdrawing.has(entry.token));
|
|
1497
|
+
}
|
|
1498
|
+
function announcePrimary(key, owner) {
|
|
1499
|
+
withdrawing.delete(owner);
|
|
1500
|
+
let owners = announcements.get(key);
|
|
1501
|
+
if (!owners) announcements.set(key, owners = /* @__PURE__ */ new Set());
|
|
1502
|
+
if (owners.has(owner)) return;
|
|
1503
|
+
owners.add(owner);
|
|
1504
|
+
if (standaloneRoots.size > 0 && !warnedLatePrimary.has(owner) && textureStaging.isDevelopment()) {
|
|
1505
|
+
warnedLatePrimary.add(owner);
|
|
1506
|
+
console.warn(
|
|
1507
|
+
`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.`
|
|
1508
|
+
);
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
function markWithdrawing(owner) {
|
|
1512
|
+
withdrawing.add(owner);
|
|
1513
|
+
}
|
|
1514
|
+
function withdrawPrimary(key, owner) {
|
|
1515
|
+
withdrawing.delete(owner);
|
|
1516
|
+
const owners = announcements.get(key);
|
|
1517
|
+
if (owners) {
|
|
1518
|
+
owners.delete(owner);
|
|
1519
|
+
if (owners.size === 0) announcements.delete(key);
|
|
1520
|
+
}
|
|
1521
|
+
const entry = primaryRegistry.get(key);
|
|
1522
|
+
if (entry?.token === owner) primaryRegistry.delete(key);
|
|
1523
|
+
if (!isLive(key)) notify(key, null);
|
|
1524
|
+
}
|
|
1525
|
+
function primaryConflict(key, owner) {
|
|
1526
|
+
const owners = announcements.get(key);
|
|
1527
|
+
if (owners) {
|
|
1528
|
+
for (const other of owners) {
|
|
1529
|
+
if (other === owner) break;
|
|
1530
|
+
if (!withdrawing.has(other)) return true;
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
const entry = primaryRegistry.get(key);
|
|
1534
|
+
return !!entry && entry.token !== owner && !(entry.token && withdrawing.has(entry.token));
|
|
1535
|
+
}
|
|
1536
|
+
function livePrimaryKeys() {
|
|
1537
|
+
const keys = /* @__PURE__ */ new Set([...announcements.keys(), ...primaryRegistry.keys()]);
|
|
1538
|
+
return [...keys].filter(isLive);
|
|
1539
|
+
}
|
|
1540
|
+
function trackStandalone(owner) {
|
|
1541
|
+
standaloneRoots.add(owner);
|
|
1542
|
+
return () => {
|
|
1543
|
+
standaloneRoots.delete(owner);
|
|
1544
|
+
};
|
|
1545
|
+
}
|
|
1546
|
+
function registerPrimary(id, renderer, store, options = {}) {
|
|
1547
|
+
if (options.token && !announcements.get(id)?.has(options.token)) return () => {
|
|
1548
|
+
};
|
|
1549
|
+
if (primaryRegistry.has(id)) {
|
|
1550
|
+
console.warn(`Canvas with id="${id}" already registered. Overwriting.`);
|
|
1551
|
+
}
|
|
1552
|
+
const entry = { renderer, store, rootId: options.rootId, token: options.token };
|
|
1553
|
+
primaryRegistry.set(id, entry);
|
|
1554
|
+
notify(id, entry);
|
|
1555
|
+
return () => {
|
|
1556
|
+
const currentEntry = primaryRegistry.get(id);
|
|
1557
|
+
if (currentEntry?.renderer === renderer) {
|
|
1558
|
+
primaryRegistry.delete(id);
|
|
1559
|
+
}
|
|
1560
|
+
};
|
|
1561
|
+
}
|
|
1562
|
+
function getPrimary(id) {
|
|
1563
|
+
return primaryRegistry.get(id);
|
|
1564
|
+
}
|
|
1565
|
+
function subscribe(id, callback) {
|
|
1566
|
+
if (!pendingSubscribers.has(id)) pendingSubscribers.set(id, []);
|
|
1567
|
+
pendingSubscribers.get(id).push(callback);
|
|
1568
|
+
return () => {
|
|
1569
|
+
const subscribers = pendingSubscribers.get(id);
|
|
1570
|
+
if (!subscribers) return;
|
|
1571
|
+
const index = subscribers.indexOf(callback);
|
|
1572
|
+
if (index !== -1) subscribers.splice(index, 1);
|
|
1573
|
+
if (subscribers.length === 0) pendingSubscribers.delete(id);
|
|
1574
|
+
};
|
|
1575
|
+
}
|
|
1576
|
+
function waitForPrimary(id, timeout = 5e3) {
|
|
1577
|
+
const existing = primaryRegistry.get(id);
|
|
1578
|
+
if (existing) {
|
|
1579
|
+
return Promise.resolve(existing);
|
|
1580
|
+
}
|
|
1581
|
+
return new Promise((resolve, reject) => {
|
|
1582
|
+
let unsubscribe = () => {
|
|
1583
|
+
};
|
|
1584
|
+
const timeoutId = setTimeout(() => {
|
|
1585
|
+
unsubscribe();
|
|
1586
|
+
reject(
|
|
1587
|
+
new Error(
|
|
1588
|
+
`Timeout waiting for canvas with id="${id}". Make sure a <Canvas id="${id}" primary> is mounted for share="${id}".`
|
|
1589
|
+
)
|
|
1590
|
+
);
|
|
1591
|
+
}, timeout);
|
|
1592
|
+
const callback = (entry) => {
|
|
1593
|
+
if (!entry) {
|
|
1594
|
+
unsubscribe = subscribe(id, callback);
|
|
1595
|
+
return;
|
|
1596
|
+
}
|
|
1597
|
+
clearTimeout(timeoutId);
|
|
1598
|
+
resolve(entry);
|
|
1599
|
+
};
|
|
1600
|
+
unsubscribe = subscribe(id, callback);
|
|
1601
|
+
});
|
|
1602
|
+
}
|
|
1603
|
+
function waitForAnnouncedPrimary(key, timeout = 5e3) {
|
|
1604
|
+
const existing = primaryRegistry.get(key);
|
|
1605
|
+
if (existing && isLive(key)) return Promise.resolve(existing);
|
|
1606
|
+
if (!isLive(key)) return Promise.resolve(null);
|
|
1607
|
+
return new Promise((resolve, reject) => {
|
|
1608
|
+
const timeoutId = setTimeout(() => {
|
|
1609
|
+
unsubscribe();
|
|
1610
|
+
reject(
|
|
1611
|
+
new Error(
|
|
1612
|
+
`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.`
|
|
1613
|
+
)
|
|
1614
|
+
);
|
|
1615
|
+
}, timeout);
|
|
1616
|
+
const unsubscribe = subscribe(key, (entry) => {
|
|
1617
|
+
clearTimeout(timeoutId);
|
|
1618
|
+
resolve(entry);
|
|
1619
|
+
});
|
|
1620
|
+
});
|
|
1621
|
+
}
|
|
1622
|
+
function hasPrimary(id) {
|
|
1623
|
+
return primaryRegistry.has(id);
|
|
1624
|
+
}
|
|
1625
|
+
function unregisterPrimary(id) {
|
|
1626
|
+
primaryRegistry.delete(id);
|
|
1627
|
+
}
|
|
1628
|
+
function getPrimaryIds() {
|
|
1629
|
+
return Array.from(primaryRegistry.keys());
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
const shallowLoose = { objects: "shallow", strict: false };
|
|
1633
|
+
function watchDpr(onChange) {
|
|
1634
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function" || !window.devicePixelRatio) {
|
|
1635
|
+
return () => {
|
|
1636
|
+
};
|
|
1637
|
+
}
|
|
1638
|
+
let watching = true;
|
|
1639
|
+
let query;
|
|
1640
|
+
const listen = () => {
|
|
1641
|
+
try {
|
|
1642
|
+
query = window.matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`);
|
|
1643
|
+
if (typeof query?.addEventListener === "function") query.addEventListener("change", handleChange);
|
|
1644
|
+
else query?.addListener?.(handleChange);
|
|
1645
|
+
} catch {
|
|
1646
|
+
query = void 0;
|
|
1647
|
+
}
|
|
1648
|
+
};
|
|
1649
|
+
const unlisten = () => {
|
|
1650
|
+
if (typeof query?.removeEventListener === "function") query.removeEventListener("change", handleChange);
|
|
1651
|
+
else query?.removeListener?.(handleChange);
|
|
1652
|
+
query = void 0;
|
|
1653
|
+
};
|
|
1654
|
+
const handleChange = () => {
|
|
1655
|
+
if (!watching) return;
|
|
1656
|
+
unlisten();
|
|
1657
|
+
listen();
|
|
1658
|
+
onChange();
|
|
1659
|
+
};
|
|
1660
|
+
listen();
|
|
1661
|
+
return () => {
|
|
1662
|
+
watching = false;
|
|
1663
|
+
unlisten();
|
|
1664
|
+
};
|
|
1665
|
+
}
|
|
1666
|
+
function createRootConfiguration(store, canvas) {
|
|
1667
|
+
let previous;
|
|
1668
|
+
let lastCamera;
|
|
1669
|
+
const lastConfiguredProps = {};
|
|
1670
|
+
let resolvedDpr = 0;
|
|
1671
|
+
let dprChangedInXR = false;
|
|
1672
|
+
let unwatchDpr;
|
|
1673
|
+
const resolveDpr = () => {
|
|
1674
|
+
const state = store.getState();
|
|
1675
|
+
const xr = state.internal.actualRenderer?.xr;
|
|
1676
|
+
if (xr?.isPresenting || xr?.getSession?.()) {
|
|
1677
|
+
dprChangedInXR = true;
|
|
1678
|
+
return;
|
|
1679
|
+
}
|
|
1680
|
+
dprChangedInXR = false;
|
|
1681
|
+
const dpr = lastConfiguredProps.dpr;
|
|
1682
|
+
if (dpr === void 0 || state.viewport.dpr !== resolvedDpr || calculateDpr(dpr) === resolvedDpr) return;
|
|
1683
|
+
state.setDpr(dpr);
|
|
1684
|
+
resolvedDpr = store.getState().viewport.dpr;
|
|
1685
|
+
};
|
|
1686
|
+
let warnedSharedSettings = false;
|
|
1687
|
+
let configured = false;
|
|
1688
|
+
return (props) => {
|
|
1689
|
+
const {
|
|
1690
|
+
gl: glConfig,
|
|
1691
|
+
renderer: rendererConfig,
|
|
1692
|
+
size: propsSize,
|
|
1693
|
+
scene: sceneOptions,
|
|
1694
|
+
events,
|
|
1695
|
+
orthographic = false,
|
|
1696
|
+
frameloop = "always",
|
|
1697
|
+
dpr = [1, 2],
|
|
1698
|
+
performance,
|
|
1699
|
+
raycaster: raycastOptions,
|
|
1700
|
+
camera: cameraOptions,
|
|
1701
|
+
onPointerMissed,
|
|
1702
|
+
onDragOverMissed,
|
|
1703
|
+
onDropMissed,
|
|
1704
|
+
autoUpdateFrustum = true,
|
|
1705
|
+
occlusion = false,
|
|
1706
|
+
_sizeProps,
|
|
1707
|
+
forceEven
|
|
1708
|
+
} = props;
|
|
1709
|
+
assertNoRemovedConfig(props);
|
|
1710
|
+
const rendererBag = settingsBag(rendererConfig);
|
|
1711
|
+
const settings = settingsBag(glConfig) ?? rendererBag;
|
|
1712
|
+
const requestedTextureColorSpace = settings?.textureColorSpace || void 0;
|
|
1713
|
+
const shadows = isInstanceOrFactory(glConfig ?? rendererConfig) ? void 0 : settings?.shadows ?? false;
|
|
1714
|
+
const next = { ...props, shadows, frameloop, autoUpdateFrustum, occlusion };
|
|
1715
|
+
const last = previous;
|
|
1716
|
+
const changed = (key) => !last || !is.equ(next[key], last[key], { objects: "shallow" });
|
|
1717
|
+
previous = void 0;
|
|
1718
|
+
const state = store.getState();
|
|
1719
|
+
const renderer = state.internal.actualRenderer;
|
|
1720
|
+
const three = getThree();
|
|
1721
|
+
const borrowsRenderer = state.internal.isSecondary === true;
|
|
1722
|
+
if (borrowsRenderer && !warnedSharedSettings && rendererBag && Object.keys(rendererBag).some((key) => key !== "textureColorSpace") && textureStaging.isDevelopment()) {
|
|
1723
|
+
warnedSharedSettings = true;
|
|
1724
|
+
console.warn(
|
|
1725
|
+
"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."
|
|
1726
|
+
);
|
|
1727
|
+
}
|
|
1728
|
+
let raycaster = state.raycaster;
|
|
1729
|
+
if (!raycaster) state.set({ raycaster: raycaster = new three.Raycaster() });
|
|
1730
|
+
if (changed("raycaster")) {
|
|
1731
|
+
const { params, ...options } = raycastOptions || {};
|
|
1732
|
+
if (!is.equ(options, raycaster, shallowLoose)) applyProps(raycaster, { ...options });
|
|
1733
|
+
if (!is.equ(params, raycaster.params, shallowLoose)) {
|
|
1734
|
+
applyProps(raycaster, { params: { ...raycaster.params, ...params } });
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
let tempCamera = state.camera;
|
|
1738
|
+
if (!state.camera || state.camera === lastCamera && changed("camera")) {
|
|
1739
|
+
lastCamera = cameraOptions;
|
|
1740
|
+
const isCamera = cameraOptions?.isCamera;
|
|
1741
|
+
const camera = isCamera ? cameraOptions : orthographic ? new three.OrthographicCamera(0, 0, 0, 0, 0.1, 1e3) : new three.PerspectiveCamera(50, 0, 0.1, 1e3);
|
|
1742
|
+
if (!isCamera) {
|
|
1743
|
+
camera.position.z = 5;
|
|
1744
|
+
if (cameraOptions) {
|
|
1745
|
+
applyProps(camera, cameraOptions);
|
|
1746
|
+
if (!camera.manual) {
|
|
1747
|
+
const projectionProps = ["aspect", "left", "right", "bottom", "top"];
|
|
1748
|
+
if (projectionProps.some((prop) => prop in cameraOptions)) {
|
|
1749
|
+
camera.manual = true;
|
|
1750
|
+
camera.updateProjectionMatrix();
|
|
1751
|
+
}
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
if (!state.camera && !cameraOptions?.rotation) camera.lookAt(0, 0, 0);
|
|
1755
|
+
}
|
|
1756
|
+
state.set({ camera });
|
|
1757
|
+
tempCamera = camera;
|
|
1758
|
+
raycaster.camera = camera;
|
|
1759
|
+
}
|
|
1760
|
+
if (!state.scene) {
|
|
1761
|
+
let scene;
|
|
1762
|
+
if (sceneOptions?.isScene) {
|
|
1763
|
+
scene = sceneOptions;
|
|
1764
|
+
prepare(scene, store, "", {});
|
|
1765
|
+
} else {
|
|
1766
|
+
scene = new three.Scene();
|
|
1767
|
+
prepare(scene, store, "", {});
|
|
1768
|
+
if (sceneOptions) applyProps(scene, sceneOptions);
|
|
1769
|
+
}
|
|
1770
|
+
state.set((prev) => ({
|
|
1771
|
+
scene,
|
|
1772
|
+
rootScene: scene,
|
|
1773
|
+
internal: { ...prev.internal, container: scene }
|
|
1774
|
+
}));
|
|
1775
|
+
const camera = tempCamera;
|
|
1776
|
+
if (camera && !camera.parent) scene.add(camera);
|
|
1777
|
+
}
|
|
1778
|
+
if (events && !state.events.handlers) {
|
|
1779
|
+
state.set({ events: events(store) });
|
|
1780
|
+
let wasEnabled = true;
|
|
1781
|
+
store.subscribe((state2) => {
|
|
1782
|
+
const { enabled } = state2.events;
|
|
1783
|
+
if (enabled && !wasEnabled) {
|
|
1784
|
+
state2.events.update?.();
|
|
1785
|
+
}
|
|
1786
|
+
wasEnabled = enabled;
|
|
1787
|
+
});
|
|
1788
|
+
}
|
|
1789
|
+
if (_sizeProps !== void 0 && changed("_sizeProps")) {
|
|
1790
|
+
state.set({ _sizeProps });
|
|
1791
|
+
}
|
|
1792
|
+
if (forceEven !== void 0 && state.internal.forceEven !== forceEven) {
|
|
1793
|
+
state.set((prev) => ({ internal: { ...prev.internal, forceEven } }));
|
|
1794
|
+
}
|
|
1795
|
+
configureSize(store, computeInitialSize(canvas, propsSize));
|
|
1796
|
+
if (dpr !== void 0 && (!last || !is.equ(dpr, lastConfiguredProps.dpr, shallowLoose))) {
|
|
1797
|
+
state.setDpr(dpr);
|
|
1798
|
+
lastConfiguredProps.dpr = dpr;
|
|
1799
|
+
resolvedDpr = store.getState().viewport.dpr;
|
|
1800
|
+
}
|
|
1801
|
+
const internal = store.getState().internal;
|
|
1802
|
+
if (Array.isArray(dpr) && (!unwatchDpr || internal.unwatchDpr !== unwatchDpr)) {
|
|
1803
|
+
internal.unwatchDpr?.();
|
|
1804
|
+
internal.unwatchDpr = unwatchDpr = watchDpr(resolveDpr);
|
|
1805
|
+
}
|
|
1806
|
+
resolveDpr();
|
|
1807
|
+
if (frameloop !== void 0 && changed("frameloop")) {
|
|
1808
|
+
state.setFrameloop(frameloop);
|
|
1809
|
+
}
|
|
1810
|
+
if (changed("onPointerMissed")) state.set({ onPointerMissed });
|
|
1811
|
+
if (changed("onDragOverMissed")) state.set({ onDragOverMissed });
|
|
1812
|
+
if (changed("onDropMissed")) state.set({ onDropMissed });
|
|
1813
|
+
if (changed("autoUpdateFrustum") && state.autoUpdateFrustum !== autoUpdateFrustum) {
|
|
1814
|
+
state.set({ autoUpdateFrustum });
|
|
1815
|
+
}
|
|
1816
|
+
if (occlusion && !state.internal.occlusionEnabled) {
|
|
1817
|
+
enableOcclusion(store);
|
|
1818
|
+
}
|
|
1819
|
+
if (performance && changed("performance")) {
|
|
1820
|
+
state.set((state2) => ({ performance: { ...state2.performance, ...performance } }));
|
|
1821
|
+
}
|
|
1822
|
+
if (!state.xr) {
|
|
1823
|
+
const handleXRFrame = (timestamp, _frame) => {
|
|
1824
|
+
const state2 = store.getState();
|
|
1825
|
+
if (state2.frameloop === "never") return;
|
|
1826
|
+
advance(timestamp, true, state2);
|
|
1827
|
+
};
|
|
1828
|
+
const actualRenderer = state.internal.actualRenderer;
|
|
1829
|
+
const handleSessionChange = () => {
|
|
1830
|
+
const state2 = store.getState();
|
|
1831
|
+
const renderer2 = state2.internal.actualRenderer;
|
|
1832
|
+
actualRenderer.xr.enabled = actualRenderer.xr.isPresenting;
|
|
1833
|
+
renderer2.xr.setAnimationLoop(renderer2.xr.isPresenting ? handleXRFrame : null);
|
|
1834
|
+
if (!renderer2.xr.isPresenting) {
|
|
1835
|
+
if (dprChangedInXR) resolveDpr();
|
|
1836
|
+
invalidate(state2);
|
|
1837
|
+
}
|
|
1838
|
+
};
|
|
1839
|
+
const xr = {
|
|
1840
|
+
connect() {
|
|
1841
|
+
const xrManager = store.getState().renderer.xr;
|
|
1842
|
+
xrManager.addEventListener("sessionstart", handleSessionChange);
|
|
1843
|
+
xrManager.addEventListener("sessionend", handleSessionChange);
|
|
1844
|
+
},
|
|
1845
|
+
disconnect() {
|
|
1846
|
+
const xrManager = store.getState().renderer.xr;
|
|
1847
|
+
xrManager.removeEventListener("sessionstart", handleSessionChange);
|
|
1848
|
+
xrManager.removeEventListener("sessionend", handleSessionChange);
|
|
1849
|
+
}
|
|
1850
|
+
};
|
|
1851
|
+
if (!borrowsRenderer && typeof renderer.xr?.addEventListener === "function") xr.connect();
|
|
1852
|
+
state.set({ xr });
|
|
1853
|
+
}
|
|
1854
|
+
if (!borrowsRenderer && shadows !== void 0 && renderer.shadowMap && changed("shadows")) {
|
|
1855
|
+
const oldEnabled = renderer.shadowMap.enabled;
|
|
1856
|
+
const oldType = renderer.shadowMap.type;
|
|
1857
|
+
renderer.shadowMap.enabled = !!shadows;
|
|
1858
|
+
if (is.boo(shadows)) {
|
|
1859
|
+
renderer.shadowMap.type = three.PCFShadowMap;
|
|
1860
|
+
} else if (is.str(shadows)) {
|
|
1861
|
+
if (shadows === "soft") {
|
|
1862
|
+
textureStaging.notifyDepreciated({
|
|
1863
|
+
heading: 'shadows="soft" is deprecated',
|
|
1864
|
+
body: "Three has depreciated soft and improved basic PCFShadows, we converted for you.",
|
|
1865
|
+
link: "https://github.com/mrdoob/three.js/wiki/Migration-Guide?utm_source=chatgpt.com#181--182"
|
|
1866
|
+
});
|
|
1867
|
+
}
|
|
1868
|
+
const types = {
|
|
1869
|
+
basic: three.BasicShadowMap,
|
|
1870
|
+
percentage: three.PCFShadowMap,
|
|
1871
|
+
soft: three.PCFShadowMap,
|
|
1872
|
+
variance: three.VSMShadowMap
|
|
1873
|
+
};
|
|
1874
|
+
renderer.shadowMap.type = types[shadows] ?? three.PCFShadowMap;
|
|
1875
|
+
} else if (is.obj(shadows)) {
|
|
1876
|
+
Object.assign(renderer.shadowMap, shadows);
|
|
1877
|
+
}
|
|
1878
|
+
if (oldEnabled !== renderer.shadowMap.enabled || oldType !== renderer.shadowMap.type) {
|
|
1879
|
+
renderer.shadowMap.needsUpdate = true;
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1882
|
+
if (!configured && !borrowsRenderer) {
|
|
1883
|
+
renderer.outputColorSpace = three.SRGBColorSpace;
|
|
1884
|
+
renderer.toneMapping = three.ACESFilmicToneMapping;
|
|
1885
|
+
}
|
|
1886
|
+
const textureColorSpace = requestedTextureColorSpace ?? three.SRGBColorSpace;
|
|
1887
|
+
if (textureColorSpace !== lastConfiguredProps.textureColorSpace) {
|
|
1888
|
+
if (state.textureColorSpace !== textureColorSpace) state.set(() => ({ textureColorSpace }));
|
|
1889
|
+
lastConfiguredProps.textureColorSpace = textureColorSpace;
|
|
1890
|
+
}
|
|
1891
|
+
if (glConfig && !is.fun(glConfig) && !isRenderer(glConfig) && changed("gl")) {
|
|
1892
|
+
const glProps = {};
|
|
1893
|
+
for (const key in glConfig) {
|
|
1894
|
+
if (!NON_APPLIED_RENDERER_PROPS.has(key)) glProps[key] = glConfig[key];
|
|
1895
|
+
}
|
|
1896
|
+
applyProps(renderer, glProps);
|
|
1897
|
+
}
|
|
1898
|
+
if (rendererConfig && !is.fun(rendererConfig) && !isRenderer(rendererConfig) && state.renderer && !borrowsRenderer) {
|
|
1899
|
+
const currentRenderer = state.renderer;
|
|
1900
|
+
if (changed("renderer")) {
|
|
1901
|
+
const rendererProps = {};
|
|
1902
|
+
for (const key in rendererConfig) {
|
|
1903
|
+
if (!NON_APPLIED_RENDERER_PROPS.has(key)) rendererProps[key] = rendererConfig[key];
|
|
1904
|
+
}
|
|
1905
|
+
applyProps(currentRenderer, rendererProps);
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
configured = true;
|
|
1909
|
+
previous = next;
|
|
1910
|
+
};
|
|
1911
|
+
}
|
|
1912
|
+
|
|
1145
1913
|
const version = "10.0.0-alpha.5";
|
|
1146
1914
|
const packageData = {
|
|
1147
1915
|
version: version};
|
|
@@ -13340,15 +14108,16 @@ function swapInteractivity(store, object, newObject) {
|
|
|
13340
14108
|
pointerState.hovered.set(makeId(next), next);
|
|
13341
14109
|
}
|
|
13342
14110
|
});
|
|
13343
|
-
const captureData
|
|
13344
|
-
|
|
13345
|
-
|
|
13346
|
-
pointerState.captured.
|
|
14111
|
+
for (const [key, captureData] of Array.from(pointerState.captured)) {
|
|
14112
|
+
const { intersection } = captureData;
|
|
14113
|
+
if (key !== object && intersection.object !== object && intersection.eventObject !== object) continue;
|
|
14114
|
+
if (key === object) pointerState.captured.delete(key);
|
|
14115
|
+
pointerState.captured.set(key === object ? newObject : key, {
|
|
13347
14116
|
...captureData,
|
|
13348
14117
|
intersection: {
|
|
13349
|
-
...
|
|
13350
|
-
object:
|
|
13351
|
-
eventObject:
|
|
14118
|
+
...intersection,
|
|
14119
|
+
object: intersection.object === object ? newObject : intersection.object,
|
|
14120
|
+
eventObject: intersection.eventObject === object ? newObject : intersection.eventObject
|
|
13352
14121
|
}
|
|
13353
14122
|
});
|
|
13354
14123
|
}
|
|
@@ -13877,10 +14646,11 @@ const catalogue = globalThis[R3F_CATALOGUE] ?? (globalThis[R3F_CATALOGUE] = {});
|
|
|
13877
14646
|
const R3F_EXTEND_ID = Symbol.for("@react-three/fiber.extendId");
|
|
13878
14647
|
const ids = globalThis;
|
|
13879
14648
|
const toPascalCase = (type) => `${type[0].toUpperCase()}${type.slice(1)}`;
|
|
13880
|
-
const isConstructor = (object) => typeof object === "function";
|
|
14649
|
+
const isConstructor$1 = (object) => typeof object === "function";
|
|
13881
14650
|
function extend(objects) {
|
|
13882
|
-
if (isConstructor(objects)) {
|
|
13883
|
-
|
|
14651
|
+
if (isConstructor$1(objects)) {
|
|
14652
|
+
let id = ids[R3F_EXTEND_ID] ?? 0;
|
|
14653
|
+
while (`${id}` in catalogue) id++;
|
|
13884
14654
|
ids[R3F_EXTEND_ID] = id + 1;
|
|
13885
14655
|
const Component = `${id}`;
|
|
13886
14656
|
catalogue[Component] = objects;
|
|
@@ -13888,15 +14658,14 @@ function extend(objects) {
|
|
|
13888
14658
|
} else {
|
|
13889
14659
|
for (const name in objects) {
|
|
13890
14660
|
const object = objects[name];
|
|
13891
|
-
if (isConstructor(object)) catalogue[name] = object;
|
|
14661
|
+
if (isConstructor$1(object)) catalogue[name] = object;
|
|
13892
14662
|
}
|
|
13893
14663
|
}
|
|
13894
14664
|
}
|
|
13895
|
-
|
|
13896
14665
|
function resolveConstructor(name, root) {
|
|
13897
14666
|
if (Object.prototype.hasOwnProperty.call(catalogue, name)) return catalogue[name];
|
|
13898
14667
|
const object = root.getState().internal.support?.three[name];
|
|
13899
|
-
return isConstructor(object) ? object : void 0;
|
|
14668
|
+
return isConstructor$1(object) ? object : void 0;
|
|
13900
14669
|
}
|
|
13901
14670
|
|
|
13902
14671
|
function createReconciler(config) {
|
|
@@ -13933,6 +14702,7 @@ function hideInstance(instance) {
|
|
|
13933
14702
|
if (instance.props.attach && instance.parent?.object) {
|
|
13934
14703
|
detach(instance.parent, instance);
|
|
13935
14704
|
} else if (isObject3D(instance.object)) {
|
|
14705
|
+
instance.previousVisible = instance.object.visible;
|
|
13936
14706
|
instance.object.visible = false;
|
|
13937
14707
|
}
|
|
13938
14708
|
instance.isHidden = true;
|
|
@@ -13943,9 +14713,10 @@ function unhideInstance(instance) {
|
|
|
13943
14713
|
if (instance.isHidden) {
|
|
13944
14714
|
if (instance.props.attach && instance.parent?.object) {
|
|
13945
14715
|
attach(instance.parent, instance);
|
|
13946
|
-
} else if (isObject3D(instance.object)
|
|
13947
|
-
instance.object.visible = true;
|
|
14716
|
+
} else if (isObject3D(instance.object)) {
|
|
14717
|
+
instance.object.visible = instance.previousVisible ?? true;
|
|
13948
14718
|
}
|
|
14719
|
+
instance.previousVisible = void 0;
|
|
13949
14720
|
instance.isHidden = false;
|
|
13950
14721
|
invalidateInstance(instance);
|
|
13951
14722
|
}
|
|
@@ -13958,6 +14729,7 @@ function handleContainerEffects(parent, child, beforeChild) {
|
|
|
13958
14729
|
child.object = child.props.object ?? new target(...child.props.args ?? []);
|
|
13959
14730
|
child.object.__r3f = child;
|
|
13960
14731
|
}
|
|
14732
|
+
warnGLSLMaterialUnsupported(state, child.object);
|
|
13961
14733
|
applyProps(child.object, child.props);
|
|
13962
14734
|
if (child.props.attach) {
|
|
13963
14735
|
attach(parent, child);
|
|
@@ -14450,945 +15222,738 @@ const reconciler = /* @__PURE__ */ createReconciler({
|
|
|
14450
15222
|
// https://github.com/facebook/react/pull/34522
|
|
14451
15223
|
getSuspendedCommitReason: (_state, _rootContainer) => null
|
|
14452
15224
|
});
|
|
14453
|
-
|
|
14454
|
-
|
|
14455
|
-
function isInternalRendererAccess(stack, callerDepth = 2) {
|
|
14456
|
-
if (!stack) return false;
|
|
14457
|
-
const caller = stack.split("\n")[callerDepth] ?? "";
|
|
14458
|
-
return INTERNAL_LIB_MARKERS.some((m) => caller.includes(m));
|
|
15225
|
+
function flushSync(fn) {
|
|
15226
|
+
return reconciler.flushSyncFromReconciler(fn);
|
|
14459
15227
|
}
|
|
14460
15228
|
|
|
14461
|
-
const
|
|
14462
|
-
|
|
14463
|
-
|
|
14464
|
-
|
|
14465
|
-
|
|
14466
|
-
|
|
14467
|
-
|
|
14468
|
-
|
|
14469
|
-
|
|
14470
|
-
|
|
14471
|
-
|
|
14472
|
-
|
|
14473
|
-
|
|
14474
|
-
|
|
14475
|
-
|
|
14476
|
-
|
|
14477
|
-
if (
|
|
14478
|
-
|
|
14479
|
-
|
|
14480
|
-
|
|
14481
|
-
const h = 2 * Math.tan(fov / 2) * distance;
|
|
14482
|
-
const w = h * (width / height);
|
|
14483
|
-
return { width: w, height: h, top, left, factor: width / w, distance, aspect };
|
|
14484
|
-
}
|
|
15229
|
+
const noop = () => {
|
|
15230
|
+
};
|
|
15231
|
+
const _roots = /* @__PURE__ */ new Map();
|
|
15232
|
+
function transitionRoot(root, event) {
|
|
15233
|
+
const state = root.state;
|
|
15234
|
+
switch (event.type) {
|
|
15235
|
+
case "use":
|
|
15236
|
+
if (state.status === "disposed") return false;
|
|
15237
|
+
if (state.status === "closing") {
|
|
15238
|
+
root.store.getState().internal.active = true;
|
|
15239
|
+
state.settle();
|
|
15240
|
+
}
|
|
15241
|
+
root.state = { status: "open" };
|
|
15242
|
+
return true;
|
|
15243
|
+
case "unmount": {
|
|
15244
|
+
if (state.status === "disposed") return false;
|
|
15245
|
+
if (state.status === "closing") state.settle();
|
|
15246
|
+
const { promise, resolve } = deferred();
|
|
15247
|
+
root.state = { status: "closing", token: event.token, settled: promise, settle: resolve };
|
|
15248
|
+
return true;
|
|
14485
15249
|
}
|
|
14486
|
-
|
|
14487
|
-
|
|
14488
|
-
|
|
14489
|
-
|
|
14490
|
-
|
|
14491
|
-
|
|
14492
|
-
|
|
14493
|
-
|
|
14494
|
-
|
|
14495
|
-
|
|
14496
|
-
|
|
14497
|
-
|
|
14498
|
-
|
|
14499
|
-
|
|
14500
|
-
|
|
14501
|
-
|
|
14502
|
-
|
|
14503
|
-
|
|
14504
|
-
|
|
14505
|
-
|
|
14506
|
-
|
|
14507
|
-
|
|
14508
|
-
|
|
14509
|
-
|
|
14510
|
-
|
|
14511
|
-
|
|
14512
|
-
|
|
14513
|
-
|
|
14514
|
-
|
|
14515
|
-
|
|
14516
|
-
|
|
14517
|
-
|
|
14518
|
-
|
|
14519
|
-
|
|
14520
|
-
|
|
14521
|
-
|
|
14522
|
-
|
|
14523
|
-
|
|
14524
|
-
|
|
14525
|
-
|
|
14526
|
-
|
|
14527
|
-
|
|
14528
|
-
|
|
14529
|
-
|
|
14530
|
-
|
|
14531
|
-
|
|
14532
|
-
|
|
14533
|
-
|
|
14534
|
-
|
|
14535
|
-
|
|
14536
|
-
|
|
14537
|
-
|
|
14538
|
-
|
|
14539
|
-
|
|
14540
|
-
|
|
14541
|
-
|
|
14542
|
-
size: { width: 0, height: 0, top: 0, left: 0 },
|
|
14543
|
-
viewport: {
|
|
14544
|
-
initialDpr: 0,
|
|
14545
|
-
dpr: 0,
|
|
14546
|
-
width: 0,
|
|
14547
|
-
height: 0,
|
|
14548
|
-
top: 0,
|
|
14549
|
-
left: 0,
|
|
14550
|
-
aspect: 0,
|
|
14551
|
-
distance: 0,
|
|
14552
|
-
factor: 0,
|
|
14553
|
-
getCurrentViewport
|
|
14554
|
-
},
|
|
14555
|
-
setEvents: (events) => set((state2) => ({ ...state2, events: { ...state2.events, ...events } })),
|
|
14556
|
-
setSize: (width, height, top, left) => {
|
|
14557
|
-
const state2 = get();
|
|
14558
|
-
if (width === void 0) {
|
|
14559
|
-
set({ _sizeImperative: false });
|
|
14560
|
-
if (state2._sizeProps) {
|
|
14561
|
-
const { width: propW, height: propH } = state2._sizeProps;
|
|
14562
|
-
if (propW !== void 0 || propH !== void 0) {
|
|
14563
|
-
const currentSize = state2.size;
|
|
14564
|
-
const newSize = {
|
|
14565
|
-
width: propW ?? currentSize.width,
|
|
14566
|
-
height: propH ?? currentSize.height,
|
|
14567
|
-
top: currentSize.top,
|
|
14568
|
-
left: currentSize.left
|
|
14569
|
-
};
|
|
14570
|
-
set((s) => ({
|
|
14571
|
-
size: newSize,
|
|
14572
|
-
viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, newSize) }
|
|
14573
|
-
}));
|
|
14574
|
-
get().invalidate();
|
|
14575
|
-
}
|
|
14576
|
-
}
|
|
14577
|
-
return;
|
|
14578
|
-
}
|
|
14579
|
-
const w = width;
|
|
14580
|
-
const h = height ?? width;
|
|
14581
|
-
const t = top ?? state2.size.top;
|
|
14582
|
-
const l = left ?? state2.size.left;
|
|
14583
|
-
const size = { width: w, height: h, top: t, left: l };
|
|
14584
|
-
set((s) => ({
|
|
14585
|
-
size,
|
|
14586
|
-
viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, size) },
|
|
14587
|
-
_sizeImperative: true
|
|
14588
|
-
}));
|
|
14589
|
-
get().invalidate();
|
|
14590
|
-
},
|
|
14591
|
-
setDpr: (dpr) => set((state2) => {
|
|
14592
|
-
const resolved = calculateDpr(dpr);
|
|
14593
|
-
return { viewport: { ...state2.viewport, dpr: resolved, initialDpr: state2.viewport.initialDpr || resolved } };
|
|
14594
|
-
}),
|
|
14595
|
-
setFrameloop: (frameloop = "always") => {
|
|
14596
|
-
const rootId = get().internal.rootId;
|
|
14597
|
-
if (rootId) scheduler.getScheduler().setRootFrameloop(rootId, frameloop);
|
|
14598
|
-
set(() => ({ frameloop }));
|
|
14599
|
-
},
|
|
14600
|
-
setError: (error) => set(() => ({ error })),
|
|
14601
|
-
error: null,
|
|
14602
|
-
//* Texture registry (useTextures) ==============================
|
|
14603
|
-
// TSL fields (uniforms, nodes, ..., renderPipeline) are added by @react-three/tsl's root extension.
|
|
14604
|
-
textures: /* @__PURE__ */ new Map(),
|
|
14605
|
-
_textureRefs: /* @__PURE__ */ new Map(),
|
|
14606
|
-
_sizeImperative: false,
|
|
14607
|
-
_sizeProps: null,
|
|
14608
|
-
previousRoot: void 0,
|
|
14609
|
-
internal: {
|
|
14610
|
-
// Events
|
|
14611
|
-
interaction: [],
|
|
14612
|
-
subscribers: [],
|
|
14613
|
-
// Per-pointer state (new unified structure)
|
|
14614
|
-
pointerMap: /* @__PURE__ */ new Map(),
|
|
14615
|
-
pointerDirty: /* @__PURE__ */ new Map(),
|
|
14616
|
-
lastEvent: React__namespace.createRef(),
|
|
14617
|
-
// Deprecated but kept for backwards compatibility
|
|
14618
|
-
hovered: /* @__PURE__ */ new Map(),
|
|
14619
|
-
initialClick: [0, 0],
|
|
14620
|
-
initialHits: [],
|
|
14621
|
-
capturedMap: /* @__PURE__ */ new Map(),
|
|
14622
|
-
// Visibility tracking (onFramed, onOccluded, onVisible)
|
|
14623
|
-
visibilityRegistry: /* @__PURE__ */ new Map(),
|
|
14624
|
-
// Occlusion system (WebGPU only)
|
|
14625
|
-
occlusionEnabled: false,
|
|
14626
|
-
occlusionObserver: null,
|
|
14627
|
-
occlusionCache: /* @__PURE__ */ new Map(),
|
|
14628
|
-
helperGroup: null,
|
|
14629
|
-
// Updates
|
|
14630
|
-
active: false,
|
|
14631
|
-
frames: 0,
|
|
14632
|
-
priority: 0,
|
|
14633
|
-
subscribe: (ref, priority, store) => {
|
|
14634
|
-
const internal = get().internal;
|
|
14635
|
-
internal.priority = internal.priority + (priority > 0 ? 1 : 0);
|
|
14636
|
-
internal.subscribers.push({ ref, priority, store });
|
|
14637
|
-
internal.subscribers = internal.subscribers.sort((a, b) => a.priority - b.priority);
|
|
14638
|
-
return () => {
|
|
14639
|
-
const internal2 = get().internal;
|
|
14640
|
-
if (internal2?.subscribers) {
|
|
14641
|
-
internal2.priority = internal2.priority - (priority > 0 ? 1 : 0);
|
|
14642
|
-
internal2.subscribers = internal2.subscribers.filter((s) => s.ref !== ref);
|
|
14643
|
-
}
|
|
14644
|
-
};
|
|
14645
|
-
},
|
|
14646
|
-
// Renderer Storage (single source of truth)
|
|
14647
|
-
actualRenderer: null,
|
|
14648
|
-
// The renderer support configure() loads for this root
|
|
14649
|
-
support: null,
|
|
14650
|
-
// Scheduler for useFrameNext (initialized in renderer.tsx)
|
|
14651
|
-
scheduler: null,
|
|
14652
|
-
// Replaces the default render call when set (see setRenderOverride)
|
|
14653
|
-
renderOverride: null
|
|
14654
|
-
}
|
|
14655
|
-
};
|
|
14656
|
-
return rootState;
|
|
14657
|
-
});
|
|
14658
|
-
const state = rootStore.getState();
|
|
14659
|
-
Object.defineProperty(state, "gl", {
|
|
14660
|
-
get() {
|
|
14661
|
-
const currentState = rootStore.getState();
|
|
14662
|
-
if (!currentState.isLegacy && currentState.internal.actualRenderer) {
|
|
14663
|
-
const stack = new Error().stack || "";
|
|
14664
|
-
if (!isInternalRendererAccess(stack)) {
|
|
14665
|
-
const cleanedStack = stack.split("\n").slice(2).join("\n") || "Stack trace unavailable";
|
|
14666
|
-
extensions.notifyDepreciated({
|
|
14667
|
-
heading: "Accessing state.gl in WebGPU mode",
|
|
14668
|
-
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
|
|
14669
|
-
});
|
|
14670
|
-
}
|
|
14671
|
-
}
|
|
14672
|
-
return currentState.internal.actualRenderer;
|
|
14673
|
-
},
|
|
14674
|
-
set(value) {
|
|
14675
|
-
rootStore.getState().internal.actualRenderer = value;
|
|
15250
|
+
case "dispose":
|
|
15251
|
+
if (state.status !== "closing" || state.token !== event.token) return false;
|
|
15252
|
+
root.state = { status: "disposed" };
|
|
15253
|
+
state.settle();
|
|
15254
|
+
return true;
|
|
15255
|
+
}
|
|
15256
|
+
}
|
|
15257
|
+
function createRoot(canvas, provider) {
|
|
15258
|
+
const prevRoot = _roots.get(canvas);
|
|
15259
|
+
const prevFiber = prevRoot?.fiber;
|
|
15260
|
+
const prevStore = prevRoot?.store;
|
|
15261
|
+
if (prevRoot) console.warn("R3F.createRoot should only be called once!");
|
|
15262
|
+
const logRecoverableError = typeof reportError === "function" ? (
|
|
15263
|
+
// In modern browsers, reportError will dispatch an error event,
|
|
15264
|
+
// emulating an uncaught JavaScript error.
|
|
15265
|
+
reportError
|
|
15266
|
+
) : (
|
|
15267
|
+
// In older browsers and test environments, fallback to console.error.
|
|
15268
|
+
console.error
|
|
15269
|
+
);
|
|
15270
|
+
const store = prevStore || createStore(invalidate, advance);
|
|
15271
|
+
const fiber = prevFiber || reconciler.createContainer(
|
|
15272
|
+
store,
|
|
15273
|
+
// container
|
|
15274
|
+
t,
|
|
15275
|
+
// tag
|
|
15276
|
+
null,
|
|
15277
|
+
// hydration callbacks
|
|
15278
|
+
false,
|
|
15279
|
+
// isStrictMode
|
|
15280
|
+
null,
|
|
15281
|
+
// concurrentUpdatesByDefaultOverride
|
|
15282
|
+
"",
|
|
15283
|
+
// identifierPrefix
|
|
15284
|
+
logRecoverableError,
|
|
15285
|
+
// onUncaughtError
|
|
15286
|
+
logRecoverableError,
|
|
15287
|
+
// onCaughtError
|
|
15288
|
+
logRecoverableError,
|
|
15289
|
+
// onRecoverableError
|
|
15290
|
+
null
|
|
15291
|
+
// transitionCallbacks
|
|
15292
|
+
);
|
|
15293
|
+
const root = prevRoot || {
|
|
15294
|
+
fiber,
|
|
15295
|
+
store,
|
|
15296
|
+
state: { status: "open" },
|
|
15297
|
+
ready: fulfilled(void 0),
|
|
15298
|
+
configuration: {}
|
|
15299
|
+
};
|
|
15300
|
+
if (!prevRoot) _roots.set(canvas, root);
|
|
15301
|
+
if (!prevRoot) root.configuration.apply = createRootConfiguration(store, canvas);
|
|
15302
|
+
let mounted = false;
|
|
15303
|
+
return {
|
|
15304
|
+
get ready() {
|
|
15305
|
+
return root.ready;
|
|
14676
15306
|
},
|
|
14677
|
-
|
|
14678
|
-
|
|
14679
|
-
|
|
14680
|
-
|
|
14681
|
-
|
|
14682
|
-
|
|
15307
|
+
configure(props = {}) {
|
|
15308
|
+
if (!transitionRoot(root, { type: "use" })) {
|
|
15309
|
+
return rejected(new Error("R3F: Cannot configure a root after it has unmounted (disposal has started)."));
|
|
15310
|
+
}
|
|
15311
|
+
const previous = root.ready;
|
|
15312
|
+
const { promise, resolve, reject } = deferred();
|
|
15313
|
+
root.ready = promise;
|
|
15314
|
+
const run = () => {
|
|
15315
|
+
try {
|
|
15316
|
+
const initialized = initializeRenderer(canvas, provider, store, props);
|
|
15317
|
+
const apply = () => {
|
|
15318
|
+
if (props.id) {
|
|
15319
|
+
for (const other of _roots.values()) {
|
|
15320
|
+
if (other !== root && other.state.status === "closing" && other.store.getState().internal.rootId === props.id) {
|
|
15321
|
+
other.state.settled.then(apply).catch(reject);
|
|
15322
|
+
return;
|
|
15323
|
+
}
|
|
15324
|
+
}
|
|
15325
|
+
}
|
|
15326
|
+
const previous2 = root.configuration.previous;
|
|
15327
|
+
root.configuration.apply(props);
|
|
15328
|
+
configureScheduler(store, props.id, props.scheduler, previous2?.scheduler);
|
|
15329
|
+
textureStaging.attachRootExtensions(store);
|
|
15330
|
+
root.configuration.previous = props;
|
|
15331
|
+
resolve(this);
|
|
15332
|
+
};
|
|
15333
|
+
if (isPromiseLike(initialized)) Promise.resolve(initialized).then(apply).catch(reject);
|
|
15334
|
+
else apply();
|
|
15335
|
+
} catch (error) {
|
|
15336
|
+
reject(error);
|
|
15337
|
+
}
|
|
15338
|
+
};
|
|
15339
|
+
if (previous.status === "pending") previous.then(run, reject);
|
|
15340
|
+
else run();
|
|
15341
|
+
return promise;
|
|
14683
15342
|
},
|
|
14684
|
-
|
|
14685
|
-
|
|
15343
|
+
render(children) {
|
|
15344
|
+
if (!transitionRoot(root, { type: "use" })) return store;
|
|
15345
|
+
if (!store.getState().internal.actualRenderer && root.ready.status === "fulfilled") this.configure();
|
|
15346
|
+
if (root.ready.status === "rejected") throw root.ready.reason;
|
|
15347
|
+
const commit = () => {
|
|
15348
|
+
if (root.state.status !== "open" || root.ready.status === "rejected") return;
|
|
15349
|
+
if (root.ready.status === "pending") {
|
|
15350
|
+
root.ready.then(commit, logRecoverableError);
|
|
15351
|
+
return;
|
|
15352
|
+
}
|
|
15353
|
+
const onCreated = root.configuration.previous?.onCreated;
|
|
15354
|
+
const element = /* @__PURE__ */ jsxRuntime.jsx(Provider, { store, children, onCreated, rootElement: canvas });
|
|
15355
|
+
if (mounted) {
|
|
15356
|
+
reconciler.updateContainer(element, fiber, null, noop);
|
|
15357
|
+
return;
|
|
15358
|
+
}
|
|
15359
|
+
mounted = true;
|
|
15360
|
+
reconciler.updateContainerSync(element, fiber, null, noop);
|
|
15361
|
+
reconciler.flushSyncWork();
|
|
15362
|
+
};
|
|
15363
|
+
commit();
|
|
15364
|
+
return store;
|
|
14686
15365
|
},
|
|
14687
|
-
|
|
14688
|
-
|
|
14689
|
-
});
|
|
14690
|
-
let oldScene = state.scene;
|
|
14691
|
-
rootStore.subscribe(() => {
|
|
14692
|
-
const currentState = rootStore.getState();
|
|
14693
|
-
const { scene, rootScene, set } = currentState;
|
|
14694
|
-
if (scene !== oldScene) {
|
|
14695
|
-
oldScene = scene;
|
|
14696
|
-
if (scene?.isScene && scene !== rootScene) {
|
|
14697
|
-
set({ rootScene: scene });
|
|
14698
|
-
}
|
|
15366
|
+
unmount() {
|
|
15367
|
+
if (_roots.get(canvas) === root) unmountComponentAtNode(canvas);
|
|
14699
15368
|
}
|
|
15369
|
+
};
|
|
15370
|
+
}
|
|
15371
|
+
function Provider({
|
|
15372
|
+
store,
|
|
15373
|
+
children,
|
|
15374
|
+
onCreated,
|
|
15375
|
+
rootElement
|
|
15376
|
+
}) {
|
|
15377
|
+
textureStaging.useIsomorphicLayoutEffect(() => {
|
|
15378
|
+
const state = store.getState();
|
|
15379
|
+
state.set((state2) => ({ internal: { ...state2.internal, active: true } }));
|
|
15380
|
+
if (onCreated) onCreated(state);
|
|
15381
|
+
if (!store.getState().events.connected) state.events.connect?.(rootElement);
|
|
15382
|
+
}, []);
|
|
15383
|
+
return /* @__PURE__ */ jsxRuntime.jsx(textureStaging.context.Provider, { value: store, children });
|
|
15384
|
+
}
|
|
15385
|
+
function unmountComponentAtNode(canvas, callback) {
|
|
15386
|
+
const claim = Symbol("unmount");
|
|
15387
|
+
const root = _roots.get(canvas);
|
|
15388
|
+
if (!root || !transitionRoot(root, { type: "unmount", token: claim })) return;
|
|
15389
|
+
root.store.getState().internal.active = false;
|
|
15390
|
+
reconciler.updateContainer(null, root.fiber, null, () => {
|
|
15391
|
+
if (root.state.status !== "closing" || root.state.token !== claim) return;
|
|
15392
|
+
reconciler.updateContainer(null, root.fiber, null, () => {
|
|
15393
|
+
if (root.state.status !== "closing" || root.state.token !== claim) return;
|
|
15394
|
+
if (root.ready.status === "pending") root.ready.then(teardown, teardown);
|
|
15395
|
+
else teardown();
|
|
15396
|
+
});
|
|
14700
15397
|
});
|
|
14701
|
-
|
|
14702
|
-
|
|
14703
|
-
|
|
14704
|
-
|
|
14705
|
-
const { camera, size, viewport, set, internal } = rootStore.getState();
|
|
14706
|
-
const actualRenderer = internal.actualRenderer;
|
|
14707
|
-
const canvasTarget = internal.canvasTarget;
|
|
14708
|
-
if (size.width !== oldSize.width || size.height !== oldSize.height || viewport.dpr !== oldDpr) {
|
|
14709
|
-
oldSize = size;
|
|
14710
|
-
oldDpr = viewport.dpr;
|
|
14711
|
-
updateCamera(camera, size);
|
|
14712
|
-
const resizeTarget = canvasTarget ?? actualRenderer;
|
|
14713
|
-
if (viewport.dpr > 0) resizeTarget.setPixelRatio(viewport.dpr);
|
|
14714
|
-
resizeTarget.setSize(size.width, size.height, false);
|
|
14715
|
-
const activeTarget = actualRenderer.getCanvasTarget?.();
|
|
14716
|
-
if (!canvasTarget || activeTarget !== canvasTarget) internal.canvasTargetSizeDirty = true;
|
|
15398
|
+
function teardown() {
|
|
15399
|
+
if (root.ready.status === "pending") {
|
|
15400
|
+
root.ready.then(teardown, teardown);
|
|
15401
|
+
return;
|
|
14717
15402
|
}
|
|
14718
|
-
if (
|
|
14719
|
-
|
|
14720
|
-
|
|
14721
|
-
|
|
14722
|
-
|
|
15403
|
+
if (!transitionRoot(root, { type: "dispose", token: claim })) return;
|
|
15404
|
+
_roots.delete(canvas);
|
|
15405
|
+
const state = root.store.getState();
|
|
15406
|
+
const internal = state.internal;
|
|
15407
|
+
internal.active = false;
|
|
15408
|
+
const attempt = (step) => {
|
|
15409
|
+
try {
|
|
15410
|
+
return step();
|
|
15411
|
+
} catch (error) {
|
|
15412
|
+
console.warn("[R3F] Error while unmounting root; teardown may be incomplete:", error);
|
|
14723
15413
|
}
|
|
14724
|
-
|
|
14725
|
-
|
|
14726
|
-
|
|
14727
|
-
|
|
15414
|
+
};
|
|
15415
|
+
attempt(() => internal.unwatchDpr?.());
|
|
15416
|
+
internal.unwatchDpr = void 0;
|
|
15417
|
+
attempt(() => internal.unregisterRoot?.());
|
|
15418
|
+
internal.unregisterRoot = void 0;
|
|
15419
|
+
attempt(() => textureStaging.detachRootExtensions(root.store));
|
|
15420
|
+
attempt(() => internal.unregisterPrimary?.());
|
|
15421
|
+
attempt(() => internal.untrackStandalone?.());
|
|
15422
|
+
attempt(() => state.events.disconnect?.());
|
|
15423
|
+
if (!internal.isSecondary && internal.actualRenderer?.xr && state.xr) attempt(() => state.xr.disconnect());
|
|
15424
|
+
attempt(() => cleanupHelperGroup(root.store));
|
|
15425
|
+
if (state.scene) attempt(() => dispose(state.scene));
|
|
15426
|
+
const canvasTarget = internal.canvasTarget;
|
|
15427
|
+
if (internal.isSecondary && canvasTarget?.dispose) attempt(() => canvasTarget.dispose());
|
|
15428
|
+
const released = attempt(() => internal.releaseRenderer?.());
|
|
15429
|
+
internal.releaseRenderer = void 0;
|
|
15430
|
+
if (callback) {
|
|
15431
|
+
if (released) {
|
|
15432
|
+
released.then(() => callback(canvas)).catch((error) => console.warn("[R3F] Error in unmount callback", error));
|
|
15433
|
+
} else {
|
|
15434
|
+
callback(canvas);
|
|
14728
15435
|
}
|
|
14729
15436
|
}
|
|
14730
|
-
});
|
|
14731
|
-
rootStore.subscribe((state2) => invalidate(state2));
|
|
14732
|
-
return rootStore;
|
|
14733
|
-
};
|
|
14734
|
-
|
|
14735
|
-
const primaryRegistry = /* @__PURE__ */ new Map();
|
|
14736
|
-
const pendingSubscribers = /* @__PURE__ */ new Map();
|
|
14737
|
-
function registerPrimary(id, renderer, store) {
|
|
14738
|
-
if (primaryRegistry.has(id)) {
|
|
14739
|
-
console.warn(`Canvas with id="${id}" already registered. Overwriting.`);
|
|
14740
15437
|
}
|
|
14741
|
-
|
|
14742
|
-
|
|
14743
|
-
|
|
14744
|
-
|
|
14745
|
-
|
|
14746
|
-
|
|
15438
|
+
}
|
|
15439
|
+
|
|
15440
|
+
const memoizedLoaders = /* @__PURE__ */ new WeakMap();
|
|
15441
|
+
const isConstructor = (value) => typeof value === "function" && value?.prototype?.constructor === value;
|
|
15442
|
+
function getLoader(Proto) {
|
|
15443
|
+
if (isConstructor(Proto)) {
|
|
15444
|
+
let loader = memoizedLoaders.get(Proto);
|
|
15445
|
+
if (!loader) {
|
|
15446
|
+
loader = new Proto();
|
|
15447
|
+
memoizedLoaders.set(Proto, loader);
|
|
15448
|
+
}
|
|
15449
|
+
return loader;
|
|
14747
15450
|
}
|
|
14748
|
-
return
|
|
14749
|
-
|
|
14750
|
-
|
|
14751
|
-
|
|
15451
|
+
return Proto;
|
|
15452
|
+
}
|
|
15453
|
+
function loadingFn(extensions, onProgress) {
|
|
15454
|
+
return function(Proto, input) {
|
|
15455
|
+
const loader = getLoader(Proto);
|
|
15456
|
+
if (extensions) extensions(loader);
|
|
15457
|
+
if ("loadAsync" in loader && typeof loader.loadAsync === "function") {
|
|
15458
|
+
return loader.loadAsync(input, onProgress).then((data) => {
|
|
15459
|
+
if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
|
|
15460
|
+
return data;
|
|
15461
|
+
});
|
|
14752
15462
|
}
|
|
15463
|
+
return new Promise(
|
|
15464
|
+
(res, reject) => loader.load(
|
|
15465
|
+
input,
|
|
15466
|
+
(data) => {
|
|
15467
|
+
if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
|
|
15468
|
+
res(data);
|
|
15469
|
+
},
|
|
15470
|
+
onProgress,
|
|
15471
|
+
(error) => reject(new Error(`Could not load ${input}: ${error?.message}`))
|
|
15472
|
+
)
|
|
15473
|
+
);
|
|
14753
15474
|
};
|
|
14754
15475
|
}
|
|
14755
|
-
function
|
|
14756
|
-
|
|
15476
|
+
function useLoader(loader, input, extensions, onProgress, cacheKey) {
|
|
15477
|
+
const inputs = Array.isArray(input) ? input : [input];
|
|
15478
|
+
const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
|
|
15479
|
+
const fn = loadingFn(extensions, onProgress);
|
|
15480
|
+
const results = cacheKeys.map(
|
|
15481
|
+
(key, index) => suspendReact.suspend(() => fn(loader, inputs[index]), [loader, key], { equal: is.equ })
|
|
15482
|
+
);
|
|
15483
|
+
const stableRef = React.useRef(null);
|
|
15484
|
+
const previous = stableRef.current;
|
|
15485
|
+
const stable = previous !== null && previous.length === results.length && previous.every((value, i) => value === results[i]) ? previous : results;
|
|
15486
|
+
stableRef.current = stable;
|
|
15487
|
+
return Array.isArray(input) ? stable : stable[0];
|
|
14757
15488
|
}
|
|
14758
|
-
function
|
|
14759
|
-
const
|
|
14760
|
-
|
|
14761
|
-
|
|
15489
|
+
useLoader.preload = function(loader, input, extensions, onProgress, cacheKey) {
|
|
15490
|
+
const inputs = Array.isArray(input) ? input : [input];
|
|
15491
|
+
const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
|
|
15492
|
+
cacheKeys.forEach(
|
|
15493
|
+
(key, index) => suspendReact.preload(() => loadingFn(extensions, onProgress)(loader, inputs[index]), [loader, key])
|
|
15494
|
+
);
|
|
15495
|
+
};
|
|
15496
|
+
useLoader.clear = function(loader, input, cacheKey) {
|
|
15497
|
+
const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
|
|
15498
|
+
cacheKeys.forEach((key) => suspendReact.clear([loader, key]));
|
|
15499
|
+
};
|
|
15500
|
+
useLoader.loader = getLoader;
|
|
15501
|
+
|
|
15502
|
+
const IsObject = (url) => url === Object(url) && !Array.isArray(url) && typeof url !== "function";
|
|
15503
|
+
function getUrls(input) {
|
|
15504
|
+
if (typeof input === "string") return [input];
|
|
15505
|
+
if (Array.isArray(input)) return input;
|
|
15506
|
+
return Object.values(input);
|
|
15507
|
+
}
|
|
15508
|
+
function inputSignature(input) {
|
|
15509
|
+
if (typeof input === "string") return input;
|
|
15510
|
+
if (Array.isArray(input)) return input.join("\0");
|
|
15511
|
+
return Object.keys(input).sort().map((key) => `${key}\0${input[key]}`).join("");
|
|
15512
|
+
}
|
|
15513
|
+
function allUrlsCached(urls, textureCache) {
|
|
15514
|
+
return urls.every((url) => textureCache.has(url));
|
|
15515
|
+
}
|
|
15516
|
+
function buildFromCache(input, textureCache) {
|
|
15517
|
+
if (typeof input === "string") {
|
|
15518
|
+
return textureCache.get(input);
|
|
15519
|
+
} else if (Array.isArray(input)) {
|
|
15520
|
+
return input.map((url) => textureCache.get(url));
|
|
15521
|
+
} else {
|
|
15522
|
+
const result = {};
|
|
15523
|
+
const objInput = input;
|
|
15524
|
+
for (const key in objInput) {
|
|
15525
|
+
result[key] = textureCache.get(objInput[key]);
|
|
15526
|
+
}
|
|
15527
|
+
return result;
|
|
14762
15528
|
}
|
|
14763
|
-
|
|
14764
|
-
|
|
14765
|
-
|
|
14766
|
-
|
|
14767
|
-
|
|
14768
|
-
|
|
14769
|
-
|
|
15529
|
+
}
|
|
15530
|
+
function useTexture(input, optionsOrOnLoad) {
|
|
15531
|
+
const renderer = textureStaging.useThree((state) => state.internal.actualRenderer);
|
|
15532
|
+
const store = textureStaging.useStore();
|
|
15533
|
+
const options = typeof optionsOrOnLoad === "function" ? { onLoad: optionsOrOnLoad } : optionsOrOnLoad ?? {};
|
|
15534
|
+
const { onLoad, cache = true } = options;
|
|
15535
|
+
const onLoadRef = React.useRef(onLoad);
|
|
15536
|
+
onLoadRef.current = onLoad;
|
|
15537
|
+
const onLoadCalledForRef = React.useRef(null);
|
|
15538
|
+
const inputKey = React.useMemo(() => inputSignature(input), [input]);
|
|
15539
|
+
const stableInput = React.useMemo(() => input, [inputKey]);
|
|
15540
|
+
const urls = React.useMemo(() => getUrls(stableInput), [stableInput]);
|
|
15541
|
+
const cachedResult = React.useMemo(() => {
|
|
15542
|
+
if (!cache) return null;
|
|
15543
|
+
const textures = store.getState().textures;
|
|
15544
|
+
if (!allUrlsCached(urls, textures)) return null;
|
|
15545
|
+
return buildFromCache(stableInput, textures);
|
|
15546
|
+
}, [cache, urls, stableInput, store]);
|
|
15547
|
+
const loadedTextures = useLoader(
|
|
15548
|
+
getThree().TextureLoader,
|
|
15549
|
+
IsObject(stableInput) ? Object.values(stableInput) : stableInput
|
|
15550
|
+
);
|
|
15551
|
+
const mappedTextures = React.useMemo(() => {
|
|
15552
|
+
if (cachedResult) return cachedResult;
|
|
15553
|
+
if (IsObject(stableInput)) {
|
|
15554
|
+
const keyed = {};
|
|
15555
|
+
const textureArray = loadedTextures;
|
|
15556
|
+
let i = 0;
|
|
15557
|
+
for (const key in stableInput) keyed[key] = textureArray[i++];
|
|
15558
|
+
return keyed;
|
|
15559
|
+
} else {
|
|
15560
|
+
return loadedTextures;
|
|
15561
|
+
}
|
|
15562
|
+
}, [stableInput, loadedTextures, cachedResult]);
|
|
15563
|
+
React.useLayoutEffect(() => {
|
|
15564
|
+
if (cachedResult) return;
|
|
15565
|
+
if (onLoadCalledForRef.current === inputKey) return;
|
|
15566
|
+
onLoadCalledForRef.current = inputKey;
|
|
15567
|
+
onLoadRef.current?.(mappedTextures);
|
|
15568
|
+
}, [cachedResult, mappedTextures, inputKey]);
|
|
15569
|
+
React.useEffect(() => {
|
|
15570
|
+
if (cachedResult) return;
|
|
15571
|
+
if ("initTexture" in renderer) {
|
|
15572
|
+
let textureArray = [];
|
|
15573
|
+
if (Array.isArray(loadedTextures)) {
|
|
15574
|
+
textureArray = loadedTextures;
|
|
15575
|
+
} else if (loadedTextures.isTexture) {
|
|
15576
|
+
textureArray = [loadedTextures];
|
|
15577
|
+
} else if (IsObject(loadedTextures)) {
|
|
15578
|
+
textureArray = Object.values(loadedTextures);
|
|
15579
|
+
}
|
|
15580
|
+
textureArray.forEach((texture) => {
|
|
15581
|
+
if (texture?.isTexture) {
|
|
15582
|
+
renderer.initTexture(texture);
|
|
15583
|
+
}
|
|
15584
|
+
});
|
|
15585
|
+
}
|
|
15586
|
+
}, [renderer, loadedTextures, cachedResult]);
|
|
15587
|
+
React.useEffect(() => {
|
|
15588
|
+
if (!cache) return;
|
|
15589
|
+
const urlTextureMap = urlTextureEntries(stableInput, mappedTextures);
|
|
15590
|
+
store.setState((state) => {
|
|
15591
|
+
const refs = new Map(state._textureRefs);
|
|
15592
|
+
let textures = state.textures;
|
|
15593
|
+
let added = false;
|
|
15594
|
+
for (const [url, texture] of urlTextureMap) {
|
|
15595
|
+
if (!textures.has(url)) {
|
|
15596
|
+
if (!added) {
|
|
15597
|
+
textures = new Map(textures);
|
|
15598
|
+
added = true;
|
|
15599
|
+
}
|
|
15600
|
+
textures.set(url, texture);
|
|
15601
|
+
}
|
|
15602
|
+
refs.set(url, (refs.get(url) ?? 0) + 1);
|
|
14770
15603
|
}
|
|
14771
|
-
|
|
14772
|
-
}
|
|
14773
|
-
|
|
14774
|
-
|
|
14775
|
-
|
|
14776
|
-
|
|
14777
|
-
|
|
14778
|
-
|
|
14779
|
-
|
|
14780
|
-
|
|
14781
|
-
|
|
14782
|
-
|
|
14783
|
-
|
|
14784
|
-
|
|
14785
|
-
}
|
|
14786
|
-
|
|
14787
|
-
|
|
15604
|
+
return added ? { textures, _textureRefs: refs } : { _textureRefs: refs };
|
|
15605
|
+
});
|
|
15606
|
+
textureStaging.unstageTextures(
|
|
15607
|
+
store,
|
|
15608
|
+
urlTextureMap.map(([url]) => url)
|
|
15609
|
+
);
|
|
15610
|
+
return () => store.setState((state) => {
|
|
15611
|
+
const refs = new Map(state._textureRefs);
|
|
15612
|
+
for (const [url] of urlTextureMap) {
|
|
15613
|
+
const next = (refs.get(url) ?? 0) - 1;
|
|
15614
|
+
if (next <= 0) refs.delete(url);
|
|
15615
|
+
else refs.set(url, next);
|
|
15616
|
+
}
|
|
15617
|
+
return { _textureRefs: refs };
|
|
15618
|
+
});
|
|
15619
|
+
}, [cache, stableInput, mappedTextures, store]);
|
|
15620
|
+
if (cache && !cachedResult) textureStaging.stageTextures(store, urlTextureEntries(stableInput, mappedTextures));
|
|
15621
|
+
return mappedTextures;
|
|
14788
15622
|
}
|
|
14789
|
-
function
|
|
14790
|
-
|
|
15623
|
+
function urlTextureEntries(input, textures) {
|
|
15624
|
+
if (typeof input === "string") return [[input, textures]];
|
|
15625
|
+
if (Array.isArray(input)) return input.map((url, i) => [url, textures[i]]);
|
|
15626
|
+
const record = textures;
|
|
15627
|
+
return Object.keys(input).map((key) => [input[key], record[key]]);
|
|
14791
15628
|
}
|
|
15629
|
+
useTexture.preload = (url) => {
|
|
15630
|
+
whenThree().then((three) => useLoader.preload(three.TextureLoader, url));
|
|
15631
|
+
};
|
|
15632
|
+
useTexture.clear = (input) => {
|
|
15633
|
+
if (hasThree()) useLoader.clear(getThree().TextureLoader, input);
|
|
15634
|
+
};
|
|
15635
|
+
const Texture = ({
|
|
15636
|
+
children,
|
|
15637
|
+
input,
|
|
15638
|
+
onLoad,
|
|
15639
|
+
cache
|
|
15640
|
+
}) => {
|
|
15641
|
+
const options = typeof onLoad === "function" ? { onLoad, cache } : { ...onLoad, cache };
|
|
15642
|
+
const ret = useTexture(input, options);
|
|
15643
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: children?.(ret) });
|
|
15644
|
+
};
|
|
14792
15645
|
|
|
14793
|
-
|
|
14794
|
-
const
|
|
14795
|
-
|
|
14796
|
-
|
|
14797
|
-
|
|
14798
|
-
|
|
14799
|
-
const pointer = new Vector2();
|
|
14800
|
-
state.set({ pointer, mouse: pointer, frustum: new Frustum() });
|
|
14801
|
-
}
|
|
14802
|
-
const shallowLoose = { objects: "shallow", strict: false };
|
|
14803
|
-
async function resolveRenderer(config, defaultProps, RendererClass) {
|
|
14804
|
-
if (typeof config === "function") return await config(defaultProps);
|
|
14805
|
-
if (isRenderer(config)) return config;
|
|
14806
|
-
return new RendererClass({ ...defaultProps, ...config });
|
|
14807
|
-
}
|
|
14808
|
-
function computeInitialSize(canvas, size) {
|
|
14809
|
-
if (!size && typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement && canvas.parentElement) {
|
|
14810
|
-
const { width, height, top, left } = canvas.parentElement.getBoundingClientRect();
|
|
14811
|
-
return { width, height, top, left };
|
|
14812
|
-
} else if (!size && typeof OffscreenCanvas !== "undefined" && canvas instanceof OffscreenCanvas) {
|
|
15646
|
+
function useTextures(selector) {
|
|
15647
|
+
const store = textureStaging.useStore();
|
|
15648
|
+
const registry = React.useMemo(() => {
|
|
15649
|
+
const getState = store.getState;
|
|
15650
|
+
const setState = store.setState;
|
|
15651
|
+
const getOne = (key) => getState().textures.get(key);
|
|
14813
15652
|
return {
|
|
14814
|
-
|
|
14815
|
-
|
|
14816
|
-
|
|
14817
|
-
|
|
15653
|
+
get all() {
|
|
15654
|
+
return getState().textures;
|
|
15655
|
+
},
|
|
15656
|
+
get(input) {
|
|
15657
|
+
if (typeof input === "string") return getOne(input);
|
|
15658
|
+
if (Array.isArray(input)) return input.map(getOne);
|
|
15659
|
+
const out = {};
|
|
15660
|
+
for (const name in input) out[name] = getOne(input[name]);
|
|
15661
|
+
return out;
|
|
15662
|
+
},
|
|
15663
|
+
has: (key) => getState().textures.has(key),
|
|
15664
|
+
add(keyOrRecord, texture) {
|
|
15665
|
+
setState((state) => {
|
|
15666
|
+
const textures = new Map(state.textures);
|
|
15667
|
+
if (typeof keyOrRecord === "string") {
|
|
15668
|
+
textures.set(keyOrRecord, texture);
|
|
15669
|
+
} else {
|
|
15670
|
+
for (const key in keyOrRecord) textures.set(key, keyOrRecord[key]);
|
|
15671
|
+
}
|
|
15672
|
+
return { textures };
|
|
15673
|
+
});
|
|
15674
|
+
},
|
|
15675
|
+
dispose(key, options) {
|
|
15676
|
+
const state = getState();
|
|
15677
|
+
const refs = state._textureRefs.get(key) ?? 0;
|
|
15678
|
+
if (refs > 0 && !options?.force) {
|
|
15679
|
+
console.warn(
|
|
15680
|
+
`[useTextures] "${key}" still has ${refs} active reference(s); skipping dispose. Pass { force: true } to override.`
|
|
15681
|
+
);
|
|
15682
|
+
return false;
|
|
15683
|
+
}
|
|
15684
|
+
state.textures.get(key)?.dispose();
|
|
15685
|
+
setState((s) => {
|
|
15686
|
+
const textures = new Map(s.textures);
|
|
15687
|
+
textures.delete(key);
|
|
15688
|
+
const nextRefs = new Map(s._textureRefs);
|
|
15689
|
+
nextRefs.delete(key);
|
|
15690
|
+
return { textures, _textureRefs: nextRefs };
|
|
15691
|
+
});
|
|
15692
|
+
return true;
|
|
15693
|
+
},
|
|
15694
|
+
disposeAll() {
|
|
15695
|
+
for (const texture of getState().textures.values()) texture.dispose();
|
|
15696
|
+
setState({ textures: /* @__PURE__ */ new Map(), _textureRefs: /* @__PURE__ */ new Map() });
|
|
15697
|
+
}
|
|
14818
15698
|
};
|
|
15699
|
+
}, [store]);
|
|
15700
|
+
const subscribe = selector ? () => selector(registry) : (state) => state.textures;
|
|
15701
|
+
const selected = textureStaging.useThree(subscribe);
|
|
15702
|
+
return selector ? selected : registry;
|
|
15703
|
+
}
|
|
15704
|
+
|
|
15705
|
+
function useRenderTarget(widthOrOptions, heightOrOptions, options) {
|
|
15706
|
+
const support = textureStaging.useThree((s) => s.internal.support);
|
|
15707
|
+
const size = textureStaging.useThree((s) => s.size);
|
|
15708
|
+
let width;
|
|
15709
|
+
let height;
|
|
15710
|
+
let opts;
|
|
15711
|
+
if (typeof widthOrOptions === "object") {
|
|
15712
|
+
opts = widthOrOptions;
|
|
15713
|
+
} else if (typeof widthOrOptions === "number") {
|
|
15714
|
+
width = widthOrOptions;
|
|
15715
|
+
if (typeof heightOrOptions === "object") {
|
|
15716
|
+
height = widthOrOptions;
|
|
15717
|
+
opts = heightOrOptions;
|
|
15718
|
+
} else if (typeof heightOrOptions === "number") {
|
|
15719
|
+
height = heightOrOptions;
|
|
15720
|
+
opts = options;
|
|
15721
|
+
} else {
|
|
15722
|
+
height = widthOrOptions;
|
|
15723
|
+
}
|
|
14819
15724
|
}
|
|
14820
|
-
return
|
|
15725
|
+
return React.useMemo(() => {
|
|
15726
|
+
const w = width ?? size.width;
|
|
15727
|
+
const h = height ?? size.height;
|
|
15728
|
+
const Target = support.RenderTarget;
|
|
15729
|
+
return new Target(w, h, opts);
|
|
15730
|
+
}, [width, height, size.width, size.height, opts, support]);
|
|
14821
15731
|
}
|
|
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
|
-
// onCaughtError
|
|
14853
|
-
logRecoverableError,
|
|
14854
|
-
// onRecoverableError
|
|
14855
|
-
null
|
|
14856
|
-
// transitionCallbacks
|
|
14857
|
-
);
|
|
14858
|
-
if (!prevRoot) _roots.set(canvas, { fiber, store });
|
|
14859
|
-
let onCreated;
|
|
14860
|
-
let lastCamera;
|
|
14861
|
-
const lastConfiguredProps = {};
|
|
14862
|
-
let configured = false;
|
|
14863
|
-
let pending = null;
|
|
14864
|
-
let rendererSetup = null;
|
|
14865
|
-
return {
|
|
14866
|
-
async configure(props = {}) {
|
|
14867
|
-
let resolve;
|
|
14868
|
-
pending = new Promise((_resolve) => resolve = _resolve);
|
|
14869
|
-
const {
|
|
14870
|
-
id: canvasId,
|
|
14871
|
-
primaryCanvas,
|
|
14872
|
-
scheduler: schedulerConfig,
|
|
14873
|
-
gl: glConfig,
|
|
14874
|
-
renderer: rendererConfig,
|
|
14875
|
-
size: propsSize,
|
|
14876
|
-
scene: sceneOptions,
|
|
14877
|
-
events,
|
|
14878
|
-
onCreated: onCreatedCallback,
|
|
14879
|
-
shadows = false,
|
|
14880
|
-
orthographic = false,
|
|
14881
|
-
frameloop = "always",
|
|
14882
|
-
dpr = [1, 2],
|
|
14883
|
-
performance,
|
|
14884
|
-
raycaster: raycastOptions,
|
|
14885
|
-
camera: cameraOptions,
|
|
14886
|
-
onPointerMissed,
|
|
14887
|
-
onDragOverMissed,
|
|
14888
|
-
onDropMissed,
|
|
14889
|
-
autoUpdateFrustum = true,
|
|
14890
|
-
occlusion = false,
|
|
14891
|
-
_sizeProps,
|
|
14892
|
-
forceEven
|
|
14893
|
-
} = props;
|
|
14894
|
-
const requestedTextureColorSpace = is.obj(glConfig) && !is.fun(glConfig) && !isRenderer(glConfig) && glConfig.textureColorSpace || is.obj(rendererConfig) && !is.fun(rendererConfig) && !isRenderer(rendererConfig) && rendererConfig.textureColorSpace || void 0;
|
|
14895
|
-
let state = store.getState();
|
|
14896
|
-
const { webgl, webgpu } = provider;
|
|
14897
|
-
const defaultGLProps = {
|
|
14898
|
-
canvas,
|
|
14899
|
-
powerPreference: "high-performance",
|
|
14900
|
-
antialias: true,
|
|
14901
|
-
alpha: true
|
|
14902
|
-
};
|
|
14903
|
-
const defaultGPUProps = {
|
|
14904
|
-
canvas,
|
|
14905
|
-
antialias: true
|
|
14906
|
-
};
|
|
14907
|
-
if (glConfig && !webgl) {
|
|
14908
|
-
throw new Error(
|
|
14909
|
-
"WebGLRenderer (gl prop) is not available on this entry. Use @react-three/fiber or @react-three/fiber/legacy instead."
|
|
14910
|
-
);
|
|
14911
|
-
}
|
|
14912
|
-
if (rendererConfig && !webgpu) {
|
|
14913
|
-
throw new Error(
|
|
14914
|
-
"WebGPURenderer (renderer prop) is not available on this entry. Use @react-three/fiber or @react-three/fiber/webgpu instead."
|
|
14915
|
-
);
|
|
14916
|
-
}
|
|
14917
|
-
const wantsGL = !!webgl && (state.isLegacy || !!glConfig || !webgpu || !rendererConfig);
|
|
14918
|
-
if (glConfig && rendererConfig) {
|
|
14919
|
-
throw new Error("Cannot use both gl and renderer props at the same time");
|
|
14920
|
-
}
|
|
14921
|
-
if (webgl && webgpu && !state.isLegacy && wantsGL) {
|
|
14922
|
-
extensions.notifyDepreciated({
|
|
14923
|
-
heading: "WebGlRenderer Usage",
|
|
14924
|
-
body: "WebGlRenderer usage is deprecated in favor of WebGPU. Import from /legacy directly or upgrade to WebGPU.",
|
|
14925
|
-
link: "https://docs.pmnd.rs/react-three-fiber/api/renderer"
|
|
14926
|
-
});
|
|
14927
|
-
}
|
|
14928
|
-
let renderer = state.internal.actualRenderer;
|
|
14929
|
-
if (primaryCanvas && !webgpu) {
|
|
14930
|
-
throw new Error(
|
|
14931
|
-
"The `primaryCanvas` prop for multi-canvas rendering is only available with WebGPU. Use @react-three/fiber/webgpu instead."
|
|
14932
|
-
);
|
|
14933
|
-
}
|
|
14934
|
-
if (primaryCanvas && wantsGL) {
|
|
14935
|
-
throw new Error(
|
|
14936
|
-
"The `primaryCanvas` prop for multi-canvas rendering cannot be used with WebGL. Remove the `gl` prop or use WebGPU."
|
|
14937
|
-
);
|
|
14938
|
-
}
|
|
14939
|
-
if (!state.internal.actualRenderer) {
|
|
14940
|
-
if (!rendererSetup) {
|
|
14941
|
-
rendererSetup = (async () => {
|
|
14942
|
-
const support = wantsGL ? await webgl() : await webgpu();
|
|
14943
|
-
registerThree(support.three);
|
|
14944
|
-
state.internal.support = support;
|
|
14945
|
-
ensureStoreThreeObjects(store);
|
|
14946
|
-
if (support.kind === "webgl") {
|
|
14947
|
-
renderer = await resolveRenderer(glConfig, defaultGLProps, support.Renderer);
|
|
14948
|
-
state.internal.actualRenderer = renderer;
|
|
14949
|
-
state.set({ isLegacy: true, gl: renderer, renderer, primaryStore: store });
|
|
14950
|
-
} else if (primaryCanvas) {
|
|
14951
|
-
const primary = await waitForPrimary(primaryCanvas);
|
|
14952
|
-
renderer = primary.renderer;
|
|
14953
|
-
state.internal.actualRenderer = renderer;
|
|
14954
|
-
const canvasTarget = new support.CanvasTarget(canvas);
|
|
14955
|
-
primary.store.setState((prev) => ({
|
|
14956
|
-
internal: { ...prev.internal, isMultiCanvas: true }
|
|
14957
|
-
}));
|
|
14958
|
-
state.set((prev) => ({
|
|
14959
|
-
webGPUSupported: primary.store.getState().webGPUSupported,
|
|
14960
|
-
renderer,
|
|
14961
|
-
primaryStore: primary.store,
|
|
14962
|
-
internal: {
|
|
14963
|
-
...prev.internal,
|
|
14964
|
-
canvasTarget,
|
|
14965
|
-
isMultiCanvas: true,
|
|
14966
|
-
isSecondary: true,
|
|
14967
|
-
targetId: primaryCanvas
|
|
14968
|
-
}
|
|
14969
|
-
}));
|
|
14970
|
-
} else {
|
|
14971
|
-
renderer = await resolveRenderer(rendererConfig, defaultGPUProps, support.Renderer);
|
|
14972
|
-
if (!renderer.hasInitialized?.()) {
|
|
14973
|
-
const size2 = computeInitialSize(canvas, propsSize);
|
|
14974
|
-
if (size2.width > 0 && size2.height > 0) {
|
|
14975
|
-
renderer.setPixelRatio(calculateDpr(dpr));
|
|
14976
|
-
renderer.setSize(size2.width, size2.height, false);
|
|
14977
|
-
}
|
|
14978
|
-
await renderer.init();
|
|
14979
|
-
}
|
|
14980
|
-
const backend = renderer.backend;
|
|
14981
|
-
const isWebGPUBackend = backend && "isWebGPUBackend" in backend;
|
|
14982
|
-
state.internal.actualRenderer = renderer;
|
|
14983
|
-
state.set({ webGPUSupported: isWebGPUBackend, renderer, primaryStore: store });
|
|
14984
|
-
if (canvasId && !state.internal.isSecondary) {
|
|
14985
|
-
const canvasTarget = renderer.getCanvasTarget?.();
|
|
14986
|
-
const unregisterPrimary = registerPrimary(canvasId, renderer, store);
|
|
14987
|
-
state.set((prev) => ({
|
|
14988
|
-
internal: {
|
|
14989
|
-
...prev.internal,
|
|
14990
|
-
canvasTarget,
|
|
14991
|
-
unregisterPrimary
|
|
14992
|
-
}
|
|
14993
|
-
}));
|
|
14994
|
-
}
|
|
14995
|
-
}
|
|
14996
|
-
})().catch((err) => {
|
|
14997
|
-
rendererSetup = null;
|
|
14998
|
-
throw err;
|
|
14999
|
-
});
|
|
15000
|
-
}
|
|
15001
|
-
await rendererSetup;
|
|
15002
|
-
state = store.getState();
|
|
15003
|
-
renderer = state.internal.actualRenderer;
|
|
15732
|
+
|
|
15733
|
+
const presetsObj = {
|
|
15734
|
+
apartment: "lebombo_1k.hdr",
|
|
15735
|
+
city: "potsdamer_platz_1k.hdr",
|
|
15736
|
+
dawn: "kiara_1_dawn_1k.hdr",
|
|
15737
|
+
forest: "forest_slope_1k.hdr",
|
|
15738
|
+
lobby: "st_fagans_interior_1k.hdr",
|
|
15739
|
+
night: "dikhololo_night_1k.hdr",
|
|
15740
|
+
park: "rooitou_park_1k.hdr",
|
|
15741
|
+
studio: "studio_small_03_1k.hdr",
|
|
15742
|
+
sunset: "venice_sunset_1k.hdr",
|
|
15743
|
+
warehouse: "empty_warehouse_01_1k.hdr"
|
|
15744
|
+
};
|
|
15745
|
+
|
|
15746
|
+
const CUBEMAP_ROOT = "https://raw.githack.com/pmndrs/drei-assets/456060a26bbeb8fdf79326f224b6d99b8bcce736/hdri/";
|
|
15747
|
+
const isArray = (arr) => Array.isArray(arr);
|
|
15748
|
+
const defaultFiles = ["/px.png", "/nx.png", "/py.png", "/ny.png", "/pz.png", "/nz.png"];
|
|
15749
|
+
const loadedLoaders = /* @__PURE__ */ new Map();
|
|
15750
|
+
const pendingLoaders = /* @__PURE__ */ new Map();
|
|
15751
|
+
function loadLoader(format) {
|
|
15752
|
+
let pending = pendingLoaders.get(format);
|
|
15753
|
+
if (!pending) {
|
|
15754
|
+
pending = importLoader(format).then(
|
|
15755
|
+
(loader) => {
|
|
15756
|
+
loadedLoaders.set(format, loader);
|
|
15757
|
+
return loader;
|
|
15758
|
+
},
|
|
15759
|
+
(error) => {
|
|
15760
|
+
pendingLoaders.delete(format);
|
|
15761
|
+
throw error;
|
|
15004
15762
|
}
|
|
15763
|
+
);
|
|
15764
|
+
pendingLoaders.set(format, pending);
|
|
15765
|
+
}
|
|
15766
|
+
return pending;
|
|
15767
|
+
}
|
|
15768
|
+
async function importLoader(format) {
|
|
15769
|
+
let loader;
|
|
15770
|
+
switch (format) {
|
|
15771
|
+
case "cube":
|
|
15772
|
+
loader = getThree().CubeTextureLoader;
|
|
15773
|
+
break;
|
|
15774
|
+
case "hdr-cube":
|
|
15775
|
+
loader = (await import('three/examples/jsm/loaders/HDRCubeTextureLoader.js')).HDRCubeTextureLoader;
|
|
15776
|
+
break;
|
|
15777
|
+
case "hdr":
|
|
15778
|
+
loader = (await import('three/examples/jsm/loaders/HDRLoader.js')).HDRLoader;
|
|
15779
|
+
break;
|
|
15780
|
+
case "exr":
|
|
15781
|
+
loader = (await import('three/examples/jsm/loaders/EXRLoader.js')).EXRLoader;
|
|
15782
|
+
break;
|
|
15783
|
+
case "jpg":
|
|
15784
|
+
loader = createJpegLoader((await import('three/examples/jsm/loaders/UltraHDRLoader.js')).UltraHDRLoader);
|
|
15785
|
+
break;
|
|
15786
|
+
case "ldr":
|
|
15787
|
+
loader = getThree().TextureLoader;
|
|
15788
|
+
break;
|
|
15789
|
+
}
|
|
15790
|
+
return loader;
|
|
15791
|
+
}
|
|
15792
|
+
function createJpegLoader(UltraHDR) {
|
|
15793
|
+
return class JpegEnvironmentLoader extends UltraHDR {
|
|
15794
|
+
// @ts-expect-error A plain JPEG resolves to a Texture, not the DataTexture UltraHDRLoader declares
|
|
15795
|
+
load(url, onLoad, onProgress, onError) {
|
|
15005
15796
|
const three = getThree();
|
|
15006
|
-
|
|
15007
|
-
|
|
15008
|
-
|
|
15009
|
-
|
|
15010
|
-
|
|
15011
|
-
|
|
15012
|
-
|
|
15013
|
-
|
|
15014
|
-
|
|
15015
|
-
|
|
15016
|
-
|
|
15017
|
-
|
|
15018
|
-
|
|
15019
|
-
|
|
15020
|
-
|
|
15021
|
-
|
|
15022
|
-
|
|
15023
|
-
|
|
15024
|
-
if (projectionProps.some((prop) => prop in cameraOptions)) {
|
|
15025
|
-
camera.manual = true;
|
|
15026
|
-
camera.updateProjectionMatrix();
|
|
15027
|
-
}
|
|
15028
|
-
}
|
|
15029
|
-
}
|
|
15030
|
-
if (!state.camera && !cameraOptions?.rotation) camera.lookAt(0, 0, 0);
|
|
15031
|
-
}
|
|
15032
|
-
state.set({ camera });
|
|
15033
|
-
tempCamera = camera;
|
|
15034
|
-
raycaster.camera = camera;
|
|
15035
|
-
}
|
|
15036
|
-
if (!state.scene) {
|
|
15037
|
-
let scene;
|
|
15038
|
-
if (sceneOptions?.isScene) {
|
|
15039
|
-
scene = sceneOptions;
|
|
15040
|
-
prepare(scene, store, "", {});
|
|
15041
|
-
} else {
|
|
15042
|
-
scene = new three.Scene();
|
|
15043
|
-
prepare(scene, store, "", {});
|
|
15044
|
-
if (sceneOptions) applyProps(scene, sceneOptions);
|
|
15045
|
-
}
|
|
15046
|
-
state.set((prev) => ({
|
|
15047
|
-
scene,
|
|
15048
|
-
rootScene: scene,
|
|
15049
|
-
internal: { ...prev.internal, container: scene }
|
|
15050
|
-
}));
|
|
15051
|
-
const camera = tempCamera;
|
|
15052
|
-
if (camera && !camera.parent) scene.add(camera);
|
|
15053
|
-
}
|
|
15054
|
-
if (events && !state.events.handlers) {
|
|
15055
|
-
state.set({ events: events(store) });
|
|
15056
|
-
let wasEnabled = true;
|
|
15057
|
-
store.subscribe((state2) => {
|
|
15058
|
-
const { enabled } = state2.events;
|
|
15059
|
-
if (enabled && !wasEnabled) {
|
|
15060
|
-
state2.events.update?.();
|
|
15061
|
-
}
|
|
15062
|
-
wasEnabled = enabled;
|
|
15063
|
-
});
|
|
15064
|
-
}
|
|
15065
|
-
if (_sizeProps !== void 0) {
|
|
15066
|
-
state.set({ _sizeProps });
|
|
15067
|
-
}
|
|
15068
|
-
if (forceEven !== void 0 && state.internal.forceEven !== forceEven) {
|
|
15069
|
-
state.set((prev) => ({ internal: { ...prev.internal, forceEven } }));
|
|
15070
|
-
}
|
|
15071
|
-
const size = computeInitialSize(canvas, propsSize);
|
|
15072
|
-
if (!state._sizeImperative && !is.equ(size, state.size, shallowLoose)) {
|
|
15073
|
-
const wasImperative = state._sizeImperative;
|
|
15074
|
-
state.setSize(size.width, size.height, size.top, size.left);
|
|
15075
|
-
if (!wasImperative) state.set({ _sizeImperative: false });
|
|
15076
|
-
}
|
|
15077
|
-
if (dpr !== void 0 && !is.equ(dpr, lastConfiguredProps.dpr, shallowLoose)) {
|
|
15078
|
-
state.setDpr(dpr);
|
|
15079
|
-
lastConfiguredProps.dpr = dpr;
|
|
15080
|
-
}
|
|
15081
|
-
if (frameloop !== void 0 && frameloop !== lastConfiguredProps.frameloop) {
|
|
15082
|
-
state.setFrameloop(frameloop);
|
|
15083
|
-
lastConfiguredProps.frameloop = frameloop;
|
|
15084
|
-
}
|
|
15085
|
-
if (!state.onPointerMissed) state.set({ onPointerMissed });
|
|
15086
|
-
if (!state.onDragOverMissed) state.set({ onDragOverMissed });
|
|
15087
|
-
if (!state.onDropMissed) state.set({ onDropMissed });
|
|
15088
|
-
if (state.autoUpdateFrustum !== autoUpdateFrustum) state.set({ autoUpdateFrustum });
|
|
15089
|
-
if (occlusion && !state.internal.occlusionEnabled) {
|
|
15090
|
-
enableOcclusion(store);
|
|
15091
|
-
}
|
|
15092
|
-
if (performance && !is.equ(performance, lastConfiguredProps.performance, shallowLoose)) {
|
|
15093
|
-
state.set((state2) => ({ performance: { ...state2.performance, ...performance } }));
|
|
15094
|
-
lastConfiguredProps.performance = performance;
|
|
15095
|
-
}
|
|
15096
|
-
if (!state.xr) {
|
|
15097
|
-
const handleXRFrame = (timestamp, _frame) => {
|
|
15098
|
-
const state2 = store.getState();
|
|
15099
|
-
if (state2.frameloop === "never") return;
|
|
15100
|
-
advance(timestamp, true, state2);
|
|
15101
|
-
};
|
|
15102
|
-
const actualRenderer = state.internal.actualRenderer;
|
|
15103
|
-
const handleSessionChange = () => {
|
|
15104
|
-
const state2 = store.getState();
|
|
15105
|
-
const renderer2 = state2.internal.actualRenderer;
|
|
15106
|
-
actualRenderer.xr.enabled = actualRenderer.xr.isPresenting;
|
|
15107
|
-
renderer2.xr.setAnimationLoop(renderer2.xr.isPresenting ? handleXRFrame : null);
|
|
15108
|
-
if (!renderer2.xr.isPresenting) invalidate(state2);
|
|
15109
|
-
};
|
|
15110
|
-
const xr = {
|
|
15111
|
-
connect() {
|
|
15112
|
-
const { gl, renderer: renderer2 } = store.getState();
|
|
15113
|
-
const xrManager = (renderer2 || gl).xr;
|
|
15114
|
-
xrManager.addEventListener("sessionstart", handleSessionChange);
|
|
15115
|
-
xrManager.addEventListener("sessionend", handleSessionChange);
|
|
15116
|
-
},
|
|
15117
|
-
disconnect() {
|
|
15118
|
-
const { gl, renderer: renderer2 } = store.getState();
|
|
15119
|
-
const xrManager = (renderer2 || gl).xr;
|
|
15120
|
-
xrManager.removeEventListener("sessionstart", handleSessionChange);
|
|
15121
|
-
xrManager.removeEventListener("sessionend", handleSessionChange);
|
|
15122
|
-
}
|
|
15123
|
-
};
|
|
15124
|
-
if (typeof renderer.xr?.addEventListener === "function") xr.connect();
|
|
15125
|
-
state.set({ xr });
|
|
15126
|
-
}
|
|
15127
|
-
if (renderer.shadowMap && !is.equ(shadows, lastConfiguredProps.shadows, shallowLoose)) {
|
|
15128
|
-
lastConfiguredProps.shadows = shadows;
|
|
15129
|
-
const oldEnabled = renderer.shadowMap.enabled;
|
|
15130
|
-
const oldType = renderer.shadowMap.type;
|
|
15131
|
-
renderer.shadowMap.enabled = !!shadows;
|
|
15132
|
-
if (is.boo(shadows)) {
|
|
15133
|
-
renderer.shadowMap.type = three.PCFShadowMap;
|
|
15134
|
-
} else if (is.str(shadows)) {
|
|
15135
|
-
if (shadows === "soft") {
|
|
15136
|
-
extensions.notifyDepreciated({
|
|
15137
|
-
heading: 'shadows="soft" is deprecated',
|
|
15138
|
-
body: "Three has depreciated soft and improved basic PCFShadows, we converted for you.",
|
|
15139
|
-
link: "https://github.com/mrdoob/three.js/wiki/Migration-Guide?utm_source=chatgpt.com#181--182"
|
|
15797
|
+
const file = new three.FileLoader(this.manager);
|
|
15798
|
+
file.setResponseType("arraybuffer");
|
|
15799
|
+
file.setRequestHeader(this.requestHeader);
|
|
15800
|
+
file.setPath(this.path);
|
|
15801
|
+
file.setWithCredentials(this.withCredentials);
|
|
15802
|
+
file.load(
|
|
15803
|
+
url,
|
|
15804
|
+
(buffer) => {
|
|
15805
|
+
try {
|
|
15806
|
+
this.parse(buffer, (texData) => {
|
|
15807
|
+
const { data } = texData;
|
|
15808
|
+
const texture = new three.DataTexture(data, texData.width, texData.height, three.RGBAFormat, texData.type);
|
|
15809
|
+
texture.minFilter = three.LinearMipMapLinearFilter;
|
|
15810
|
+
texture.magFilter = three.LinearFilter;
|
|
15811
|
+
texture.generateMipmaps = true;
|
|
15812
|
+
texture.flipY = true;
|
|
15813
|
+
texture.needsUpdate = true;
|
|
15814
|
+
onLoad?.(texture);
|
|
15140
15815
|
});
|
|
15141
|
-
}
|
|
15142
|
-
|
|
15143
|
-
|
|
15144
|
-
|
|
15145
|
-
|
|
15146
|
-
|
|
15147
|
-
|
|
15148
|
-
|
|
15149
|
-
|
|
15150
|
-
|
|
15151
|
-
|
|
15152
|
-
|
|
15153
|
-
|
|
15154
|
-
|
|
15155
|
-
|
|
15156
|
-
if (!configured) {
|
|
15157
|
-
renderer.outputColorSpace = three.SRGBColorSpace;
|
|
15158
|
-
renderer.toneMapping = three.ACESFilmicToneMapping;
|
|
15159
|
-
}
|
|
15160
|
-
const textureColorSpace = requestedTextureColorSpace ?? three.SRGBColorSpace;
|
|
15161
|
-
if (textureColorSpace !== lastConfiguredProps.textureColorSpace) {
|
|
15162
|
-
if (state.textureColorSpace !== textureColorSpace) state.set(() => ({ textureColorSpace }));
|
|
15163
|
-
lastConfiguredProps.textureColorSpace = textureColorSpace;
|
|
15164
|
-
}
|
|
15165
|
-
const r3fProps = ["textureColorSpace"];
|
|
15166
|
-
const constructorOnlyProps = ["samples", "antialias", "alpha", "canvas", "powerPreference"];
|
|
15167
|
-
const nonApplyProps = [...r3fProps, ...constructorOnlyProps];
|
|
15168
|
-
if (glConfig && !is.fun(glConfig) && !isRenderer(glConfig) && !is.equ(glConfig, renderer, shallowLoose)) {
|
|
15169
|
-
const glProps = {};
|
|
15170
|
-
for (const key in glConfig) {
|
|
15171
|
-
if (!nonApplyProps.includes(key)) glProps[key] = glConfig[key];
|
|
15172
|
-
}
|
|
15173
|
-
applyProps(renderer, glProps);
|
|
15174
|
-
}
|
|
15175
|
-
if (rendererConfig && !is.fun(rendererConfig) && !isRenderer(rendererConfig) && state.renderer) {
|
|
15176
|
-
const currentRenderer = state.renderer;
|
|
15177
|
-
if (!is.equ(rendererConfig, currentRenderer, shallowLoose)) {
|
|
15178
|
-
const rendererProps = {};
|
|
15179
|
-
for (const key in rendererConfig) {
|
|
15180
|
-
if (!nonApplyProps.includes(key)) rendererProps[key] = rendererConfig[key];
|
|
15181
|
-
}
|
|
15182
|
-
applyProps(currentRenderer, rendererProps);
|
|
15183
|
-
}
|
|
15184
|
-
}
|
|
15185
|
-
const scheduler$1 = scheduler.getScheduler();
|
|
15186
|
-
const rootId = state.internal.rootId;
|
|
15187
|
-
if (!rootId) {
|
|
15188
|
-
const newRootId = canvasId || scheduler$1.generateRootId();
|
|
15189
|
-
const unregisterRoot = scheduler$1.registerRoot(newRootId, {
|
|
15190
|
-
getState: () => store.getState(),
|
|
15191
|
-
onError: (err) => store.getState().setError(err),
|
|
15192
|
-
frameloop: store.getState().frameloop,
|
|
15193
|
-
before: schedulerConfig?.before,
|
|
15194
|
-
after: schedulerConfig?.after,
|
|
15195
|
-
order: schedulerConfig?.order
|
|
15196
|
-
});
|
|
15197
|
-
const unregisterCanvasTarget = scheduler$1.register(
|
|
15198
|
-
() => {
|
|
15199
|
-
const state2 = store.getState();
|
|
15200
|
-
const canvasTarget = state2.internal.canvasTarget;
|
|
15201
|
-
if (canvasTarget) {
|
|
15202
|
-
const renderer2 = state2.internal.actualRenderer;
|
|
15203
|
-
if (renderer2.getCanvasTarget() !== canvasTarget) renderer2.setCanvasTarget(canvasTarget);
|
|
15204
|
-
if (state2.internal.canvasTargetSizeDirty) {
|
|
15205
|
-
state2.internal.canvasTargetSizeDirty = false;
|
|
15206
|
-
renderer2.backend?.updateSize?.();
|
|
15816
|
+
} catch {
|
|
15817
|
+
const objectURL = URL.createObjectURL(new Blob([buffer], { type: "image/jpeg" }));
|
|
15818
|
+
const settle = () => URL.revokeObjectURL(objectURL);
|
|
15819
|
+
new three.ImageLoader().load(
|
|
15820
|
+
objectURL,
|
|
15821
|
+
(image) => {
|
|
15822
|
+
settle();
|
|
15823
|
+
const texture = new three.Texture(image);
|
|
15824
|
+
texture.needsUpdate = true;
|
|
15825
|
+
onLoad?.(texture);
|
|
15826
|
+
},
|
|
15827
|
+
void 0,
|
|
15828
|
+
(error) => {
|
|
15829
|
+
settle();
|
|
15830
|
+
onError?.(error);
|
|
15207
15831
|
}
|
|
15208
|
-
|
|
15209
|
-
},
|
|
15210
|
-
{
|
|
15211
|
-
id: `${newRootId}_canvasTarget`,
|
|
15212
|
-
rootId: newRootId,
|
|
15213
|
-
phase: "start",
|
|
15214
|
-
system: true
|
|
15215
|
-
}
|
|
15216
|
-
);
|
|
15217
|
-
const unregisterEventsFlush = scheduler$1.register(
|
|
15218
|
-
() => {
|
|
15219
|
-
const state2 = store.getState();
|
|
15220
|
-
state2.events.flush?.();
|
|
15221
|
-
},
|
|
15222
|
-
{
|
|
15223
|
-
id: `${newRootId}_events`,
|
|
15224
|
-
rootId: newRootId,
|
|
15225
|
-
phase: "input",
|
|
15226
|
-
system: true
|
|
15227
|
-
}
|
|
15228
|
-
);
|
|
15229
|
-
const unregisterFrustum = scheduler$1.register(
|
|
15230
|
-
() => {
|
|
15231
|
-
const state2 = store.getState();
|
|
15232
|
-
if (state2.autoUpdateFrustum && state2.camera) {
|
|
15233
|
-
updateFrustum(state2.camera, state2.frustum);
|
|
15234
|
-
}
|
|
15235
|
-
},
|
|
15236
|
-
{
|
|
15237
|
-
id: `${newRootId}_frustum`,
|
|
15238
|
-
rootId: newRootId,
|
|
15239
|
-
before: "render",
|
|
15240
|
-
system: true
|
|
15241
|
-
}
|
|
15242
|
-
);
|
|
15243
|
-
const unregisterVisibility = scheduler$1.register(
|
|
15244
|
-
() => {
|
|
15245
|
-
const state2 = store.getState();
|
|
15246
|
-
checkVisibility(state2);
|
|
15247
|
-
},
|
|
15248
|
-
{
|
|
15249
|
-
id: `${newRootId}_visibility`,
|
|
15250
|
-
rootId: newRootId,
|
|
15251
|
-
before: "render",
|
|
15252
|
-
system: true,
|
|
15253
|
-
after: `${newRootId}_frustum`
|
|
15254
|
-
}
|
|
15255
|
-
);
|
|
15256
|
-
const unregisterRender = scheduler$1.register(
|
|
15257
|
-
() => {
|
|
15258
|
-
const state2 = store.getState();
|
|
15259
|
-
const renderer2 = state2.internal.actualRenderer;
|
|
15260
|
-
const userHandlesRender = scheduler$1.hasUserJobsInPhase("render", newRootId);
|
|
15261
|
-
if (userHandlesRender || state2.internal.priority) return;
|
|
15262
|
-
try {
|
|
15263
|
-
const renderOverride = state2.internal.renderOverride;
|
|
15264
|
-
if (renderOverride) renderOverride();
|
|
15265
|
-
else if (renderer2?.render) renderer2.render(state2.scene, state2.camera);
|
|
15266
|
-
} catch (error) {
|
|
15267
|
-
state2.setError(error instanceof Error ? error : new Error(String(error)));
|
|
15268
|
-
}
|
|
15269
|
-
},
|
|
15270
|
-
{
|
|
15271
|
-
// Use canvas ID directly as job ID if available, otherwise use generated rootId
|
|
15272
|
-
id: canvasId || `${newRootId}_render`,
|
|
15273
|
-
rootId: newRootId,
|
|
15274
|
-
phase: "render",
|
|
15275
|
-
system: true,
|
|
15276
|
-
// Internal flag: this is a system job, not user-controlled
|
|
15277
|
-
// FPS throttles only the default render job; Canvas ordering belongs to the root.
|
|
15278
|
-
...schedulerConfig?.fps && { fps: schedulerConfig.fps }
|
|
15279
|
-
}
|
|
15280
|
-
);
|
|
15281
|
-
state.set((state2) => ({
|
|
15282
|
-
internal: {
|
|
15283
|
-
...state2.internal,
|
|
15284
|
-
rootId: newRootId,
|
|
15285
|
-
unregisterRoot: () => {
|
|
15286
|
-
unregisterRoot();
|
|
15287
|
-
unregisterCanvasTarget();
|
|
15288
|
-
unregisterEventsFlush();
|
|
15289
|
-
unregisterFrustum();
|
|
15290
|
-
unregisterVisibility();
|
|
15291
|
-
unregisterRender();
|
|
15292
|
-
},
|
|
15293
|
-
scheduler: scheduler$1
|
|
15832
|
+
);
|
|
15294
15833
|
}
|
|
15295
|
-
}
|
|
15296
|
-
|
|
15297
|
-
|
|
15298
|
-
|
|
15299
|
-
scheduler$1.setRootConstraints(rootId, {
|
|
15300
|
-
before: schedulerConfig?.before,
|
|
15301
|
-
after: schedulerConfig?.after
|
|
15302
|
-
});
|
|
15303
|
-
}
|
|
15304
|
-
if (schedulerConfig?.order !== lastConfiguredProps.schedulerOrder) {
|
|
15305
|
-
scheduler$1.setRootOrder(rootId, schedulerConfig?.order ?? 0);
|
|
15306
|
-
}
|
|
15307
|
-
}
|
|
15308
|
-
lastConfiguredProps.schedulerBefore = schedulerConfig?.before;
|
|
15309
|
-
lastConfiguredProps.schedulerAfter = schedulerConfig?.after;
|
|
15310
|
-
lastConfiguredProps.schedulerOrder = schedulerConfig?.order;
|
|
15311
|
-
extensions.attachRootExtensions(store);
|
|
15312
|
-
onCreated = onCreatedCallback;
|
|
15313
|
-
configured = true;
|
|
15314
|
-
resolve();
|
|
15315
|
-
return this;
|
|
15316
|
-
},
|
|
15317
|
-
render(children) {
|
|
15318
|
-
if (!configured && !pending) this.configure();
|
|
15319
|
-
pending.then(() => {
|
|
15320
|
-
reconciler.updateContainer(
|
|
15321
|
-
/* @__PURE__ */ jsxRuntime.jsx(Provider, { store, children, onCreated, rootElement: canvas }),
|
|
15322
|
-
fiber,
|
|
15323
|
-
null,
|
|
15324
|
-
() => void 0
|
|
15325
|
-
);
|
|
15326
|
-
});
|
|
15327
|
-
return store;
|
|
15328
|
-
},
|
|
15329
|
-
unmount() {
|
|
15330
|
-
unmountComponentAtNode(canvas);
|
|
15834
|
+
},
|
|
15835
|
+
onProgress,
|
|
15836
|
+
onError
|
|
15837
|
+
);
|
|
15331
15838
|
}
|
|
15332
15839
|
};
|
|
15333
15840
|
}
|
|
15334
|
-
|
|
15335
|
-
|
|
15336
|
-
|
|
15337
|
-
onCreated,
|
|
15338
|
-
rootElement
|
|
15339
|
-
}) {
|
|
15340
|
-
extensions.useIsomorphicLayoutEffect(() => {
|
|
15341
|
-
const state = store.getState();
|
|
15342
|
-
state.set((state2) => ({ internal: { ...state2.internal, active: true } }));
|
|
15343
|
-
if (onCreated) onCreated(state);
|
|
15344
|
-
if (!store.getState().events.connected) state.events.connect?.(rootElement);
|
|
15345
|
-
}, []);
|
|
15346
|
-
return /* @__PURE__ */ jsxRuntime.jsx(extensions.context.Provider, { value: store, children });
|
|
15841
|
+
const LOADER_KEY = Symbol("r3f-environment-loader");
|
|
15842
|
+
function useEnvironmentLoader(format) {
|
|
15843
|
+
return suspendReact.suspend(() => loadLoader(format), [LOADER_KEY, format]);
|
|
15347
15844
|
}
|
|
15348
|
-
function
|
|
15349
|
-
|
|
15350
|
-
|
|
15351
|
-
|
|
15352
|
-
|
|
15353
|
-
|
|
15354
|
-
|
|
15355
|
-
|
|
15356
|
-
|
|
15357
|
-
|
|
15358
|
-
|
|
15359
|
-
|
|
15845
|
+
function useEnvironment({
|
|
15846
|
+
files = defaultFiles,
|
|
15847
|
+
path = "",
|
|
15848
|
+
preset = void 0,
|
|
15849
|
+
colorSpace = void 0,
|
|
15850
|
+
extensions
|
|
15851
|
+
} = {}) {
|
|
15852
|
+
if (preset) {
|
|
15853
|
+
validatePreset(preset);
|
|
15854
|
+
files = presetsObj[preset];
|
|
15855
|
+
path = CUBEMAP_ROOT;
|
|
15856
|
+
}
|
|
15857
|
+
const multiFile = isArray(files);
|
|
15858
|
+
const { format, isCubemap } = getFormat(files);
|
|
15859
|
+
if (!format) throw new Error("useEnvironment: Unrecognized file extension: " + files);
|
|
15860
|
+
const loader = useEnvironmentLoader(format);
|
|
15861
|
+
const loaderResult = useLoader(
|
|
15862
|
+
loader,
|
|
15863
|
+
multiFile ? [files] : files,
|
|
15864
|
+
(loader2) => {
|
|
15865
|
+
loader2.setPath?.(path);
|
|
15866
|
+
if (extensions) extensions(loader2);
|
|
15360
15867
|
}
|
|
15361
|
-
|
|
15362
|
-
|
|
15363
|
-
|
|
15364
|
-
|
|
15365
|
-
|
|
15366
|
-
|
|
15367
|
-
|
|
15368
|
-
|
|
15369
|
-
|
|
15370
|
-
|
|
15371
|
-
|
|
15372
|
-
|
|
15373
|
-
|
|
15374
|
-
|
|
15375
|
-
|
|
15376
|
-
|
|
15377
|
-
|
|
15378
|
-
|
|
15379
|
-
|
|
15380
|
-
|
|
15381
|
-
|
|
15382
|
-
|
|
15383
|
-
|
|
15384
|
-
|
|
15385
|
-
|
|
15386
|
-
|
|
15387
|
-
|
|
15388
|
-
|
|
15868
|
+
);
|
|
15869
|
+
const texture = multiFile ? (
|
|
15870
|
+
// @ts-ignore
|
|
15871
|
+
loaderResult[0]
|
|
15872
|
+
) : loaderResult;
|
|
15873
|
+
const three = getThree();
|
|
15874
|
+
texture.mapping = isCubemap ? three.CubeReflectionMapping : three.EquirectangularReflectionMapping;
|
|
15875
|
+
const hdr = format === "hdr-cube" || texture.isDataTexture === true;
|
|
15876
|
+
texture.colorSpace = colorSpace ?? (hdr ? "srgb-linear" : "srgb");
|
|
15877
|
+
return texture;
|
|
15878
|
+
}
|
|
15879
|
+
const preloadDefaultOptions = {
|
|
15880
|
+
files: defaultFiles,
|
|
15881
|
+
path: "",
|
|
15882
|
+
preset: void 0,
|
|
15883
|
+
extensions: void 0
|
|
15884
|
+
};
|
|
15885
|
+
useEnvironment.preload = (preloadOptions) => {
|
|
15886
|
+
const options = { ...preloadDefaultOptions, ...preloadOptions };
|
|
15887
|
+
let { files, path = "" } = options;
|
|
15888
|
+
const { preset, extensions } = options;
|
|
15889
|
+
if (preset) {
|
|
15890
|
+
validatePreset(preset);
|
|
15891
|
+
files = presetsObj[preset];
|
|
15892
|
+
path = CUBEMAP_ROOT;
|
|
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
|
+
loadLoader(format).then((loader) => {
|
|
15898
|
+
useLoader.preload(loader, input, (loader2) => {
|
|
15899
|
+
loader2.setPath?.(path);
|
|
15900
|
+
if (extensions) extensions(loader2);
|
|
15901
|
+
});
|
|
15902
|
+
});
|
|
15903
|
+
};
|
|
15904
|
+
const clearDefaultOptins = {
|
|
15905
|
+
files: defaultFiles,
|
|
15906
|
+
preset: void 0
|
|
15907
|
+
};
|
|
15908
|
+
useEnvironment.clear = (clearOptions) => {
|
|
15909
|
+
const options = { ...clearDefaultOptins, ...clearOptions };
|
|
15910
|
+
let { files } = options;
|
|
15911
|
+
const { preset } = options;
|
|
15912
|
+
if (preset) {
|
|
15913
|
+
validatePreset(preset);
|
|
15914
|
+
files = presetsObj[preset];
|
|
15915
|
+
}
|
|
15916
|
+
const { format } = getFormat(files);
|
|
15917
|
+
if (!format) throw new Error("useEnvironment: Unrecognized file extension: " + files);
|
|
15918
|
+
const input = isArray(files) ? [files] : files;
|
|
15919
|
+
const clear = (loader2) => useLoader.clear(loader2, input);
|
|
15920
|
+
const loader = loadedLoaders.get(format);
|
|
15921
|
+
if (loader) {
|
|
15922
|
+
clear(loader);
|
|
15923
|
+
} else {
|
|
15924
|
+
const pending = pendingLoaders.get(format);
|
|
15925
|
+
if (pending) void pending.then(clear, () => {
|
|
15389
15926
|
});
|
|
15390
15927
|
}
|
|
15928
|
+
};
|
|
15929
|
+
function validatePreset(preset) {
|
|
15930
|
+
if (!(preset in presetsObj)) throw new Error("Preset must be one of: " + Object.keys(presetsObj).join(", "));
|
|
15931
|
+
}
|
|
15932
|
+
function getFormat(files) {
|
|
15933
|
+
const isCubemap = isArray(files) && files.length === 6;
|
|
15934
|
+
const firstEntry = isArray(files) ? files[0] : files;
|
|
15935
|
+
const firstExtension = firstEntry.split(/[?#]/)[0].split(".").pop()?.toLowerCase();
|
|
15936
|
+
let format;
|
|
15937
|
+
if (isCubemap) format = firstExtension === "hdr" ? "hdr-cube" : "cube";
|
|
15938
|
+
else if (firstEntry.startsWith("data:application/exr")) format = "exr";
|
|
15939
|
+
else if (firstEntry.startsWith("data:application/hdr")) format = "hdr";
|
|
15940
|
+
else if (firstEntry.startsWith("data:image/jpeg")) format = "jpg";
|
|
15941
|
+
else if (firstExtension === "hdr" || firstExtension === "exr") format = firstExtension;
|
|
15942
|
+
else if (firstExtension === "jpg" || firstExtension === "jpeg") format = "jpg";
|
|
15943
|
+
else if (/^data:image\/(png|webp|avif|gif)[;,]/.test(firstEntry)) format = "ldr";
|
|
15944
|
+
else if (["png", "webp", "avif", "gif"].includes(firstExtension)) format = "ldr";
|
|
15945
|
+
return { format, isCubemap };
|
|
15946
|
+
}
|
|
15947
|
+
|
|
15948
|
+
function useInstanceHandle(ref) {
|
|
15949
|
+
const instance = React.useRef(null);
|
|
15950
|
+
React.useImperativeHandle(instance, () => ref.current.__r3f, [ref]);
|
|
15951
|
+
return instance;
|
|
15952
|
+
}
|
|
15953
|
+
function useGraph(object) {
|
|
15954
|
+
return React.useMemo(() => buildGraph(object), [object]);
|
|
15391
15955
|
}
|
|
15956
|
+
|
|
15392
15957
|
function createPortal(children, container, state) {
|
|
15393
15958
|
return /* @__PURE__ */ jsxRuntime.jsx(Portal, { children, container, state });
|
|
15394
15959
|
}
|
|
@@ -15419,30 +15984,28 @@ function Portal({ children, container, state }) {
|
|
|
15419
15984
|
}
|
|
15420
15985
|
function PortalInner({ state = {}, children, container }) {
|
|
15421
15986
|
const { events, size, injectScene = true, ...rest } = state;
|
|
15422
|
-
const previousRoot =
|
|
15987
|
+
const previousRoot = textureStaging.useStore();
|
|
15423
15988
|
const [raycaster] = React.useState(() => new (getThree()).Raycaster());
|
|
15424
15989
|
const [pointer] = React.useState(() => new (getThree()).Vector2());
|
|
15425
15990
|
const [portalScene] = React.useState(() => {
|
|
15426
15991
|
if ("isScene" in container && container.isScene) return container;
|
|
15427
15992
|
if (!injectScene) return container;
|
|
15428
|
-
|
|
15429
|
-
container.add(scene);
|
|
15430
|
-
return scene;
|
|
15993
|
+
return new (getThree()).Scene();
|
|
15431
15994
|
});
|
|
15432
|
-
|
|
15995
|
+
textureStaging.useIsomorphicLayoutEffect(() => {
|
|
15996
|
+
if (portalScene === container || !injectScene) return;
|
|
15997
|
+
container.add(portalScene);
|
|
15433
15998
|
return () => {
|
|
15434
|
-
|
|
15435
|
-
container.remove(portalScene);
|
|
15436
|
-
dispose(portalScene);
|
|
15437
|
-
}
|
|
15999
|
+
container.remove(portalScene);
|
|
15438
16000
|
};
|
|
15439
16001
|
}, [portalScene, container, injectScene]);
|
|
15440
16002
|
const lastRootState = React.useRef(null);
|
|
15441
|
-
const inject =
|
|
16003
|
+
const inject = textureStaging.useMutableCallback((rootState, injectState) => {
|
|
15442
16004
|
const followed = {};
|
|
15443
16005
|
const lastRoot = lastRootState.current;
|
|
15444
16006
|
if (lastRoot) {
|
|
15445
16007
|
for (const key in rootState) {
|
|
16008
|
+
if (textureStaging.isAccessor(rootState, key)) continue;
|
|
15446
16009
|
const field = key;
|
|
15447
16010
|
const changed = rootState[field] !== lastRoot[field];
|
|
15448
16011
|
const inherited = !(key in rest) && injectState[field] === lastRoot[field];
|
|
@@ -15459,11 +16022,7 @@ function PortalInner({ state = {}, children, container }) {
|
|
|
15459
16022
|
if (camera !== rootState.camera) updateCamera(camera, resolvedSize);
|
|
15460
16023
|
}
|
|
15461
16024
|
const set = injectState.set;
|
|
15462
|
-
return {
|
|
15463
|
-
// The intersect consists of the previous root state
|
|
15464
|
-
...rootState,
|
|
15465
|
-
...injectState,
|
|
15466
|
-
...followed,
|
|
16025
|
+
return Object.assign(textureStaging.cloneState(rootState, injectState, followed), {
|
|
15467
16026
|
// Portals have their own scene - always a real THREE.Scene (injected if needed)
|
|
15468
16027
|
scene: portalScene,
|
|
15469
16028
|
// rootScene always points to the actual THREE.Scene, even inside portals
|
|
@@ -15478,18 +16037,24 @@ function PortalInner({ state = {}, children, container }) {
|
|
|
15478
16037
|
size: resolvedSize,
|
|
15479
16038
|
viewport: { ...rootState.viewport, ...viewport },
|
|
15480
16039
|
// Layers are allowed to override events
|
|
15481
|
-
setEvents: (events2) => set((state2) => ({
|
|
15482
|
-
// Container for child attachment - the portalScene (injected or container itself)
|
|
15483
|
-
|
|
15484
|
-
|
|
16040
|
+
setEvents: (events2) => set((state2) => ({ events: { ...state2.events, ...events2 } })),
|
|
16041
|
+
// Container for child attachment - the portalScene (injected or container itself). A portal
|
|
16042
|
+
// renders with its parent's renderer, which `renderer` / `gl` read from `actualRenderer`
|
|
16043
|
+
internal: {
|
|
16044
|
+
...rootState.internal,
|
|
16045
|
+
...injectState.internal,
|
|
16046
|
+
actualRenderer: rootState.internal.actualRenderer,
|
|
16047
|
+
container: portalScene
|
|
16048
|
+
}
|
|
16049
|
+
});
|
|
15485
16050
|
});
|
|
15486
16051
|
const usePortalStore = React.useMemo(() => {
|
|
15487
|
-
const store = traditional.createWithEqualityFn((set, get) => ({ ...rest, set, get }));
|
|
16052
|
+
const store = traditional.createWithEqualityFn(textureStaging.keepAccessors((set, get) => ({ ...rest, set, get })));
|
|
15488
16053
|
const onMutate = (prev) => store.setState((state2) => inject.current(prev, state2));
|
|
15489
16054
|
onMutate(previousRoot.getState());
|
|
15490
16055
|
return store;
|
|
15491
16056
|
}, [previousRoot, container]);
|
|
15492
|
-
|
|
16057
|
+
textureStaging.useIsomorphicLayoutEffect(() => {
|
|
15493
16058
|
const onMutate = (prev) => usePortalStore.setState((state2) => inject.current(prev, state2));
|
|
15494
16059
|
const unsubscribe = previousRoot.subscribe(onMutate);
|
|
15495
16060
|
return unsubscribe;
|
|
@@ -15497,15 +16062,12 @@ function PortalInner({ state = {}, children, container }) {
|
|
|
15497
16062
|
return (
|
|
15498
16063
|
// @ts-ignore, reconciler types are not maintained
|
|
15499
16064
|
/* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: reconciler.createPortal(
|
|
15500
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
16065
|
+
/* @__PURE__ */ jsxRuntime.jsx(textureStaging.context.Provider, { value: usePortalStore, children }),
|
|
15501
16066
|
usePortalStore,
|
|
15502
16067
|
null
|
|
15503
16068
|
) })
|
|
15504
16069
|
);
|
|
15505
16070
|
}
|
|
15506
|
-
function flushSync(fn) {
|
|
15507
|
-
return reconciler.flushSyncFromReconciler(fn);
|
|
15508
|
-
}
|
|
15509
16071
|
|
|
15510
16072
|
const isRef = (obj) => obj.current && obj.current.isScene;
|
|
15511
16073
|
const resolveScene = (scene) => isRef(scene) ? scene.current : scene;
|
|
@@ -15538,7 +16100,7 @@ function setEnvProps(background, scene, defaultScene, texture, sceneProps = {})
|
|
|
15538
16100
|
};
|
|
15539
16101
|
}
|
|
15540
16102
|
function EnvironmentMap({ scene, background = false, map, ...config }) {
|
|
15541
|
-
const defaultScene =
|
|
16103
|
+
const defaultScene = textureStaging.useThree((state) => state.scene);
|
|
15542
16104
|
React__namespace.useLayoutEffect(() => {
|
|
15543
16105
|
if (map) return setEnvProps(background, scene, defaultScene, map, config);
|
|
15544
16106
|
});
|
|
@@ -15556,7 +16118,7 @@ function EnvironmentCube({
|
|
|
15556
16118
|
...rest
|
|
15557
16119
|
}) {
|
|
15558
16120
|
const texture = useEnvironment(rest);
|
|
15559
|
-
const defaultScene =
|
|
16121
|
+
const defaultScene = textureStaging.useThree((state) => state.scene);
|
|
15560
16122
|
React__namespace.useLayoutEffect(() => {
|
|
15561
16123
|
return setEnvProps(background, scene, defaultScene, texture, {
|
|
15562
16124
|
backgroundBlurriness: blur ?? backgroundBlurriness,
|
|
@@ -15591,11 +16153,11 @@ function EnvironmentPortal({
|
|
|
15591
16153
|
files,
|
|
15592
16154
|
path,
|
|
15593
16155
|
preset = void 0,
|
|
15594
|
-
extensions
|
|
16156
|
+
extensions
|
|
15595
16157
|
}) {
|
|
15596
|
-
const renderer =
|
|
15597
|
-
const support =
|
|
15598
|
-
const defaultScene =
|
|
16158
|
+
const renderer = textureStaging.useThree((state) => state.renderer);
|
|
16159
|
+
const support = textureStaging.useThree((state) => state.internal.support);
|
|
16160
|
+
const defaultScene = textureStaging.useThree((state) => state.scene);
|
|
15599
16161
|
const camera = React__namespace.useRef(null);
|
|
15600
16162
|
const [virtualScene] = React__namespace.useState(() => new (getThree()).Scene());
|
|
15601
16163
|
const fbo = React__namespace.useMemo(() => {
|
|
@@ -15639,7 +16201,7 @@ function EnvironmentPortal({
|
|
|
15639
16201
|
environmentRotation
|
|
15640
16202
|
]);
|
|
15641
16203
|
let count = 1;
|
|
15642
|
-
|
|
16204
|
+
textureStaging.useFrame(() => {
|
|
15643
16205
|
if (frames === Infinity || count < frames) {
|
|
15644
16206
|
const autoClear = renderer.autoClear;
|
|
15645
16207
|
renderer.autoClear = true;
|
|
@@ -15652,7 +16214,7 @@ function EnvironmentPortal({
|
|
|
15652
16214
|
/* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
15653
16215
|
children,
|
|
15654
16216
|
/* @__PURE__ */ jsxRuntime.jsx("cubeCamera", { ref: camera, args: [near, far, fbo] }),
|
|
15655
|
-
files || preset ? /* @__PURE__ */ jsxRuntime.jsx(EnvironmentCube, { background: true, files, preset, path, extensions
|
|
16217
|
+
files || preset ? /* @__PURE__ */ jsxRuntime.jsx(EnvironmentCube, { background: true, files, preset, path, extensions }) : map ? /* @__PURE__ */ jsxRuntime.jsx(EnvironmentMap, { background: true, map, extensions }) : null
|
|
15656
16218
|
] }),
|
|
15657
16219
|
virtualScene
|
|
15658
16220
|
) });
|
|
@@ -15682,7 +16244,7 @@ function EnvironmentGround(props) {
|
|
|
15682
16244
|
] });
|
|
15683
16245
|
}
|
|
15684
16246
|
function EnvironmentColor({ color, scene }) {
|
|
15685
|
-
const defaultScene =
|
|
16247
|
+
const defaultScene = textureStaging.useThree((state) => state.scene);
|
|
15686
16248
|
React__namespace.useLayoutEffect(() => {
|
|
15687
16249
|
if (color === void 0) return;
|
|
15688
16250
|
const target = resolveScene(scene || defaultScene);
|
|
@@ -15697,12 +16259,12 @@ function EnvironmentColor({ color, scene }) {
|
|
|
15697
16259
|
function EnvironmentDualSource(props) {
|
|
15698
16260
|
const { backgroundFiles, ...envProps } = props;
|
|
15699
16261
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
15700
|
-
/* @__PURE__ */ jsxRuntime.jsx(EnvironmentCube, { ...envProps, background: false }),
|
|
15701
|
-
/* @__PURE__ */ jsxRuntime.jsx(EnvironmentCube, { ...props, files: backgroundFiles, background: "only" })
|
|
16262
|
+
(envProps.files || envProps.preset) && /* @__PURE__ */ jsxRuntime.jsx(EnvironmentCube, { ...envProps, background: false }),
|
|
16263
|
+
/* @__PURE__ */ jsxRuntime.jsx(EnvironmentCube, { ...props, files: backgroundFiles, preset: void 0, background: "only" })
|
|
15702
16264
|
] });
|
|
15703
16265
|
}
|
|
15704
16266
|
function Environment(props) {
|
|
15705
|
-
if (props.color && !props.files && !props.preset && !props.map) {
|
|
16267
|
+
if (props.color !== void 0 && !props.files && !props.preset && !props.map) {
|
|
15706
16268
|
return /* @__PURE__ */ jsxRuntime.jsx(EnvironmentColor, { ...props });
|
|
15707
16269
|
}
|
|
15708
16270
|
if (props.backgroundFiles && props.backgroundFiles !== props.files) {
|
|
@@ -15712,7 +16274,7 @@ function Environment(props) {
|
|
|
15712
16274
|
}
|
|
15713
16275
|
|
|
15714
16276
|
function parseBackground(background) {
|
|
15715
|
-
if (
|
|
16277
|
+
if (background === void 0 || background === null || background === "") return null;
|
|
15716
16278
|
if (typeof background === "object" && !background.isColor) {
|
|
15717
16279
|
const { backgroundMap, envMap, files, preset, ...rest } = background;
|
|
15718
16280
|
return {
|
|
@@ -15730,7 +16292,7 @@ function parseBackground(background) {
|
|
|
15730
16292
|
if (background in presetsObj) {
|
|
15731
16293
|
return { preset: background, background: true };
|
|
15732
16294
|
}
|
|
15733
|
-
if (/^(https
|
|
16295
|
+
if (/^(https?:\/\/|\/|\.\/|\.\.\/|data:)|\.(hdr|exr|jpg|jpeg|png|webp|avif|gif)([?#].*)?$/i.test(background)) {
|
|
15734
16296
|
return { files: background, background: true };
|
|
15735
16297
|
}
|
|
15736
16298
|
return { color: background, background: true };
|
|
@@ -15741,19 +16303,6 @@ function parseBackground(background) {
|
|
|
15741
16303
|
return null;
|
|
15742
16304
|
}
|
|
15743
16305
|
|
|
15744
|
-
function parseRendererConfig(rendererProp) {
|
|
15745
|
-
const isRendererConfig = typeof rendererProp === "object" && rendererProp !== null && !("render" in rendererProp) && ("primaryCanvas" in rendererProp || "scheduler" in rendererProp);
|
|
15746
|
-
if (isRendererConfig) {
|
|
15747
|
-
const { primaryCanvas: pc, scheduler: sc, ...rest } = rendererProp;
|
|
15748
|
-
return {
|
|
15749
|
-
primaryCanvas: pc,
|
|
15750
|
-
scheduler: sc,
|
|
15751
|
-
renderer: Object.keys(rest).length > 0 ? rest : rendererProp
|
|
15752
|
-
};
|
|
15753
|
-
}
|
|
15754
|
-
return { primaryCanvas: void 0, scheduler: void 0, renderer: rendererProp };
|
|
15755
|
-
}
|
|
15756
|
-
|
|
15757
16306
|
function CanvasImpl({
|
|
15758
16307
|
ref,
|
|
15759
16308
|
children,
|
|
@@ -15762,11 +16311,13 @@ function CanvasImpl({
|
|
|
15762
16311
|
style,
|
|
15763
16312
|
id,
|
|
15764
16313
|
gl,
|
|
15765
|
-
renderer
|
|
16314
|
+
renderer,
|
|
16315
|
+
primary,
|
|
16316
|
+
share,
|
|
16317
|
+
scheduler,
|
|
15766
16318
|
events = createPointerEvents,
|
|
15767
16319
|
eventSource,
|
|
15768
16320
|
eventPrefix,
|
|
15769
|
-
shadows,
|
|
15770
16321
|
orthographic,
|
|
15771
16322
|
frameloop,
|
|
15772
16323
|
dpr,
|
|
@@ -15788,8 +16339,12 @@ function CanvasImpl({
|
|
|
15788
16339
|
provider,
|
|
15789
16340
|
...props
|
|
15790
16341
|
}) {
|
|
15791
|
-
const {
|
|
15792
|
-
|
|
16342
|
+
const {
|
|
16343
|
+
shadows: removedShadows,
|
|
16344
|
+
primaryCanvas: removedPrimaryCanvas,
|
|
16345
|
+
...divProps
|
|
16346
|
+
} = props;
|
|
16347
|
+
const Bridge = textureStaging.useBridge();
|
|
15793
16348
|
const backgroundProps = React__namespace.useMemo(() => parseBackground(background), [background]);
|
|
15794
16349
|
const [hasInitialSize, setHasInitialSize] = React__namespace.useState(false);
|
|
15795
16350
|
const measureConfig = React__namespace.useMemo(() => {
|
|
@@ -15825,119 +16380,131 @@ function CanvasImpl({
|
|
|
15825
16380
|
const canvasRef = React__namespace.useRef(null);
|
|
15826
16381
|
const divRef = React__namespace.useRef(null);
|
|
15827
16382
|
React__namespace.useImperativeHandle(ref, () => canvasRef.current);
|
|
15828
|
-
const handlePointerMissed =
|
|
15829
|
-
const handleDragOverMissed =
|
|
15830
|
-
const handleDropMissed =
|
|
16383
|
+
const handlePointerMissed = textureStaging.useMutableCallback(onPointerMissed);
|
|
16384
|
+
const handleDragOverMissed = textureStaging.useMutableCallback(onDragOverMissed);
|
|
16385
|
+
const handleDropMissed = textureStaging.useMutableCallback(onDropMissed);
|
|
15831
16386
|
const [block, setBlock] = React__namespace.useState(false);
|
|
15832
16387
|
const [error, setError] = React__namespace.useState(false);
|
|
15833
16388
|
const [fallbackVisible, setFallbackVisible] = React__namespace.useState(false);
|
|
15834
16389
|
if (block) throw block;
|
|
15835
16390
|
if (error) throw error;
|
|
15836
16391
|
const root = React__namespace.useRef(null);
|
|
15837
|
-
const
|
|
15838
|
-
const
|
|
15839
|
-
|
|
15840
|
-
|
|
16392
|
+
const [gate, waitFor] = textureStaging.useGate();
|
|
16393
|
+
const rootState = React__namespace.useRef(null);
|
|
16394
|
+
const eventTarget = () => eventSource ? isRef$1(eventSource) ? eventSource.current : eventSource : divRef.current;
|
|
16395
|
+
const pointerMissed = React__namespace.useCallback(
|
|
16396
|
+
(...args) => handlePointerMissed.current?.(...args),
|
|
16397
|
+
[handlePointerMissed]
|
|
16398
|
+
);
|
|
16399
|
+
const dragOverMissed = React__namespace.useCallback(
|
|
16400
|
+
(...args) => handleDragOverMissed.current?.(...args),
|
|
16401
|
+
[handleDragOverMissed]
|
|
16402
|
+
);
|
|
16403
|
+
const dropMissed = React__namespace.useCallback(
|
|
16404
|
+
(...args) => handleDropMissed.current?.(...args),
|
|
16405
|
+
[handleDropMissed]
|
|
16406
|
+
);
|
|
16407
|
+
textureStaging.useIsomorphicLayoutEffect(() => {
|
|
15841
16408
|
if (fallbackVisible) return;
|
|
15842
16409
|
const canvas = canvasRef.current;
|
|
15843
16410
|
if (effectiveSize.width > 0 && effectiveSize.height > 0 && canvas) {
|
|
15844
16411
|
if (!root.current) {
|
|
15845
16412
|
root.current = createRoot(canvas, provider);
|
|
15846
|
-
|
|
16413
|
+
textureStaging.notifyAlpha({
|
|
15847
16414
|
message: "React Three Fiber v10 is in ALPHA - expect breaking changes",
|
|
15848
16415
|
link: "https://github.com/pmndrs/react-three-fiber/discussions"
|
|
15849
16416
|
});
|
|
15850
|
-
const rootEntry = _roots.get(canvas);
|
|
15851
|
-
if (rootEntry?.store) {
|
|
15852
|
-
if (unsubscribeErrorRef.current) unsubscribeErrorRef.current();
|
|
15853
|
-
unsubscribeErrorRef.current = rootEntry.store.subscribe((state) => {
|
|
15854
|
-
if (state.error && effectActiveRef.current) {
|
|
15855
|
-
setError(state.error);
|
|
15856
|
-
}
|
|
15857
|
-
});
|
|
15858
|
-
}
|
|
15859
16417
|
}
|
|
15860
|
-
|
|
15861
|
-
|
|
15862
|
-
|
|
15863
|
-
|
|
15864
|
-
|
|
15865
|
-
|
|
15866
|
-
|
|
15867
|
-
|
|
15868
|
-
|
|
15869
|
-
|
|
15870
|
-
|
|
15871
|
-
|
|
15872
|
-
|
|
15873
|
-
|
|
15874
|
-
|
|
15875
|
-
|
|
15876
|
-
|
|
15877
|
-
|
|
15878
|
-
|
|
15879
|
-
|
|
15880
|
-
|
|
15881
|
-
|
|
15882
|
-
|
|
15883
|
-
|
|
15884
|
-
|
|
15885
|
-
|
|
15886
|
-
|
|
15887
|
-
|
|
15888
|
-
|
|
15889
|
-
|
|
15890
|
-
|
|
15891
|
-
|
|
15892
|
-
|
|
15893
|
-
|
|
15894
|
-
|
|
15895
|
-
|
|
15896
|
-
|
|
15897
|
-
|
|
15898
|
-
|
|
15899
|
-
|
|
15900
|
-
}
|
|
15901
|
-
onCreated?.(state);
|
|
15902
|
-
}
|
|
15903
|
-
}).then(
|
|
15904
|
-
() => true,
|
|
15905
|
-
// Renderer setup failed (e.g. no WebGL/WebGPU support). The `fallback` prop lives
|
|
15906
|
-
// inside <canvas>, which browsers don't display, so surface it as visible DOM
|
|
15907
|
-
// instead; with no fallback, rethrow to an external error boundary. (#3757)
|
|
15908
|
-
(setupError) => {
|
|
15909
|
-
if (effectActiveRef.current) {
|
|
15910
|
-
if (fallback != null) setFallbackVisible(true);
|
|
15911
|
-
else setError(setupError);
|
|
15912
|
-
}
|
|
15913
|
-
return false;
|
|
16418
|
+
const current = root.current;
|
|
16419
|
+
current.configure({
|
|
16420
|
+
id,
|
|
16421
|
+
primary,
|
|
16422
|
+
share,
|
|
16423
|
+
scheduler,
|
|
16424
|
+
gl,
|
|
16425
|
+
renderer,
|
|
16426
|
+
scene,
|
|
16427
|
+
events,
|
|
16428
|
+
_primaryToken: primaryToken,
|
|
16429
|
+
...{ shadows: removedShadows, primaryCanvas: removedPrimaryCanvas },
|
|
16430
|
+
orthographic,
|
|
16431
|
+
frameloop,
|
|
16432
|
+
dpr,
|
|
16433
|
+
performance,
|
|
16434
|
+
raycaster,
|
|
16435
|
+
camera,
|
|
16436
|
+
autoUpdateFrustum,
|
|
16437
|
+
occlusion,
|
|
16438
|
+
size: effectiveSize,
|
|
16439
|
+
// Store size props for reset functionality
|
|
16440
|
+
_sizeProps: width !== void 0 || height !== void 0 ? { width, height } : null,
|
|
16441
|
+
forceEven,
|
|
16442
|
+
// Pass mutable reference to onPointerMissed so it's free to update
|
|
16443
|
+
onPointerMissed: pointerMissed,
|
|
16444
|
+
onDragOverMissed: dragOverMissed,
|
|
16445
|
+
onDropMissed: dropMissed,
|
|
16446
|
+
onCreated: (state) => {
|
|
16447
|
+
rootState.current = state;
|
|
16448
|
+
state.events.connect?.(eventTarget() ?? divRef.current);
|
|
16449
|
+
if (eventPrefix) {
|
|
16450
|
+
state.setEvents({
|
|
16451
|
+
compute: (event, state2) => {
|
|
16452
|
+
const x = event[eventPrefix + "X"];
|
|
16453
|
+
const y = event[eventPrefix + "Y"];
|
|
16454
|
+
state2.pointer.set(x / state2.size.width * 2 - 1, -(y / state2.size.height) * 2 + 1);
|
|
16455
|
+
state2.raycaster.setFromCamera(state2.pointer, state2.camera);
|
|
16456
|
+
}
|
|
16457
|
+
});
|
|
15914
16458
|
}
|
|
15915
|
-
|
|
15916
|
-
|
|
15917
|
-
|
|
15918
|
-
|
|
16459
|
+
onCreated?.(state);
|
|
16460
|
+
}
|
|
16461
|
+
}).catch((setupError) => {
|
|
16462
|
+
if (root.current !== current) return;
|
|
16463
|
+
if (fallback != null) setFallbackVisible(true);
|
|
16464
|
+
else setError(setupError);
|
|
16465
|
+
});
|
|
16466
|
+
if (current.ready.status === "fulfilled") {
|
|
16467
|
+
current.render(
|
|
16468
|
+
/* @__PURE__ */ jsxRuntime.jsx(Bridge, { children: /* @__PURE__ */ jsxRuntime.jsx(textureStaging.ErrorBoundary, { set: setError, children: /* @__PURE__ */ jsxRuntime.jsxs(React__namespace.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(textureStaging.Block, { set: setBlock }), children: [
|
|
15919
16469
|
backgroundProps && /* @__PURE__ */ jsxRuntime.jsx(Environment, { ...backgroundProps }),
|
|
15920
16470
|
children ?? null
|
|
15921
16471
|
] }) }) })
|
|
15922
16472
|
);
|
|
16473
|
+
} else if (current.ready.status === "pending") {
|
|
16474
|
+
waitFor(current.ready);
|
|
15923
16475
|
}
|
|
15924
|
-
run();
|
|
15925
16476
|
}
|
|
15926
|
-
|
|
15927
|
-
|
|
15928
|
-
|
|
15929
|
-
|
|
15930
|
-
|
|
15931
|
-
|
|
16477
|
+
});
|
|
16478
|
+
textureStaging.useIsomorphicLayoutEffect(() => {
|
|
16479
|
+
const store = canvasRef.current && _roots.get(canvasRef.current)?.store;
|
|
16480
|
+
if (!store) return;
|
|
16481
|
+
const report = () => {
|
|
16482
|
+
const error2 = store.getState().error;
|
|
16483
|
+
if (error2) setError(error2);
|
|
15932
16484
|
};
|
|
16485
|
+
report();
|
|
16486
|
+
return store.subscribe(report);
|
|
16487
|
+
});
|
|
16488
|
+
React__namespace.useEffect(() => {
|
|
16489
|
+
const state = rootState.current?.get();
|
|
16490
|
+
const target = eventTarget();
|
|
16491
|
+
if (state && target && state.events.connected !== target) state.events.connect?.(target);
|
|
15933
16492
|
});
|
|
15934
16493
|
const insertionMounted = React__namespace.useRef(false);
|
|
16494
|
+
const [primaryToken] = React__namespace.useState(() => ({}));
|
|
16495
|
+
const primaryKey = React__namespace.useRef(null);
|
|
15935
16496
|
React__namespace.useInsertionEffect(() => {
|
|
15936
16497
|
insertionMounted.current = true;
|
|
16498
|
+
if (primary && provider.webgpu) {
|
|
16499
|
+
primaryKey.current ?? (primaryKey.current = id || DEFAULT_PRIMARY);
|
|
16500
|
+
announcePrimary(primaryKey.current, primaryToken);
|
|
16501
|
+
}
|
|
15937
16502
|
return () => {
|
|
15938
16503
|
insertionMounted.current = false;
|
|
16504
|
+
if (primaryKey.current) markWithdrawing(primaryToken);
|
|
15939
16505
|
queueMicrotask(() => {
|
|
15940
16506
|
if (insertionMounted.current) return;
|
|
16507
|
+
if (primaryKey.current) withdrawPrimary(primaryKey.current, primaryToken);
|
|
15941
16508
|
const current = root.current;
|
|
15942
16509
|
root.current = null;
|
|
15943
16510
|
current?.unmount();
|
|
@@ -15962,10 +16529,10 @@ function CanvasImpl({
|
|
|
15962
16529
|
const handleHMR = () => {
|
|
15963
16530
|
queueMicrotask(() => {
|
|
15964
16531
|
const rootEntry = _roots.get(canvas);
|
|
15965
|
-
if (rootEntry?.store)
|
|
16532
|
+
if (rootEntry?.store) textureStaging.notifyRootExtensionsHmr(rootEntry.store);
|
|
15966
16533
|
});
|
|
15967
16534
|
};
|
|
15968
|
-
if (typeof ({ url: (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/fiber.
|
|
16535
|
+
if (typeof ({ url: (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/fiber.C2WmwvFB.cjs', document.baseURI).href)) }) !== "undefined" && undefined) {
|
|
15969
16536
|
const hot = undefined;
|
|
15970
16537
|
hot.on("vite:afterUpdate", handleHMR);
|
|
15971
16538
|
return () => hot.off?.("vite:afterUpdate", handleHMR);
|
|
@@ -15978,7 +16545,7 @@ function CanvasImpl({
|
|
|
15978
16545
|
}
|
|
15979
16546
|
}, [hmr]);
|
|
15980
16547
|
const pointerEvents = eventSource ? "none" : "auto";
|
|
15981
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
16548
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
15982
16549
|
"div",
|
|
15983
16550
|
{
|
|
15984
16551
|
ref: divRef,
|
|
@@ -15990,21 +16557,24 @@ function CanvasImpl({
|
|
|
15990
16557
|
pointerEvents,
|
|
15991
16558
|
...style
|
|
15992
16559
|
},
|
|
15993
|
-
...
|
|
15994
|
-
children:
|
|
15995
|
-
|
|
15996
|
-
|
|
15997
|
-
|
|
15998
|
-
|
|
15999
|
-
"canvas",
|
|
16000
|
-
|
|
16001
|
-
|
|
16002
|
-
|
|
16003
|
-
|
|
16004
|
-
|
|
16005
|
-
|
|
16006
|
-
|
|
16007
|
-
|
|
16560
|
+
...divProps,
|
|
16561
|
+
children: [
|
|
16562
|
+
fallbackVisible ? (
|
|
16563
|
+
// Renderer setup failed: render the fallback as visible DOM. Inside <canvas> (below)
|
|
16564
|
+
// it exists in the tree but browsers never paint it, which is the whole bug (#3757).
|
|
16565
|
+
fallback
|
|
16566
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, className: "r3f-canvas-container", style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
16567
|
+
"canvas",
|
|
16568
|
+
{
|
|
16569
|
+
ref: canvasRef,
|
|
16570
|
+
id,
|
|
16571
|
+
className: "r3f-canvas",
|
|
16572
|
+
style: { display: "block", width: "100%", height: "100%" },
|
|
16573
|
+
children: fallback
|
|
16574
|
+
}
|
|
16575
|
+
) }),
|
|
16576
|
+
gate
|
|
16577
|
+
]
|
|
16008
16578
|
}
|
|
16009
16579
|
);
|
|
16010
16580
|
}
|