@react-three/fiber 10.0.0-canary.6eb9584 → 10.0.0-canary.7a50545
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +94 -43
- package/dist/index.d.cts +40 -11
- package/dist/index.d.mts +40 -11
- package/dist/index.d.ts +40 -11
- package/dist/index.mjs +94 -43
- package/dist/legacy.cjs +94 -43
- package/dist/legacy.d.cts +40 -11
- package/dist/legacy.d.mts +40 -11
- package/dist/legacy.d.ts +40 -11
- package/dist/legacy.mjs +94 -43
- package/dist/webgpu/index.cjs +119 -49
- package/dist/webgpu/index.d.cts +43 -10
- package/dist/webgpu/index.d.mts +43 -10
- package/dist/webgpu/index.d.ts +43 -10
- package/dist/webgpu/index.mjs +119 -49
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -905,7 +905,7 @@ const createStore = (invalidate, advance) => {
|
|
|
905
905
|
size: newSize,
|
|
906
906
|
viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, newSize) }
|
|
907
907
|
}));
|
|
908
|
-
|
|
908
|
+
get().invalidate();
|
|
909
909
|
}
|
|
910
910
|
}
|
|
911
911
|
return;
|
|
@@ -920,15 +920,16 @@ const createStore = (invalidate, advance) => {
|
|
|
920
920
|
viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, size) },
|
|
921
921
|
_sizeImperative: true
|
|
922
922
|
}));
|
|
923
|
-
|
|
923
|
+
get().invalidate();
|
|
924
924
|
},
|
|
925
925
|
setDpr: (dpr) => set((state2) => {
|
|
926
926
|
const resolved = calculateDpr(dpr);
|
|
927
927
|
return { viewport: { ...state2.viewport, dpr: resolved, initialDpr: state2.viewport.initialDpr || resolved } };
|
|
928
928
|
}),
|
|
929
929
|
setFrameloop: (frameloop = "always") => {
|
|
930
|
+
const rootId = get().internal.rootId;
|
|
931
|
+
if (rootId) getScheduler().setRootFrameloop(rootId, frameloop);
|
|
930
932
|
set(() => ({ frameloop }));
|
|
931
|
-
getScheduler().frameloop = frameloop;
|
|
932
933
|
},
|
|
933
934
|
setError: (error) => set(() => ({ error })),
|
|
934
935
|
error: null,
|
|
@@ -1044,17 +1045,10 @@ const createStore = (invalidate, advance) => {
|
|
|
1044
1045
|
oldSize = size;
|
|
1045
1046
|
oldDpr = viewport.dpr;
|
|
1046
1047
|
updateCamera(camera, size);
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
if (viewport.dpr > 0) actualRenderer.setPixelRatio(viewport.dpr);
|
|
1052
|
-
actualRenderer.setSize(size.width, size.height, false);
|
|
1053
|
-
if (canvasTarget) {
|
|
1054
|
-
if (viewport.dpr > 0) canvasTarget.setPixelRatio(viewport.dpr);
|
|
1055
|
-
canvasTarget.setSize(size.width, size.height, false);
|
|
1056
|
-
}
|
|
1057
|
-
}
|
|
1048
|
+
const resizeTarget = canvasTarget ?? actualRenderer;
|
|
1049
|
+
if (viewport.dpr > 0) resizeTarget.setPixelRatio(viewport.dpr);
|
|
1050
|
+
resizeTarget.setSize(size.width, size.height, false);
|
|
1051
|
+
internal.canvasTargetSizeDirty = true;
|
|
1058
1052
|
}
|
|
1059
1053
|
if (camera !== oldCamera) {
|
|
1060
1054
|
oldCamera = camera;
|
|
@@ -1116,7 +1110,11 @@ function useLoader(loader, input, extensions, onProgress, cacheKey) {
|
|
|
1116
1110
|
const results = cacheKeys.map(
|
|
1117
1111
|
(key, index) => suspend(() => fn(loader, inputs[index]), [loader, key], { equal: is.equ })
|
|
1118
1112
|
);
|
|
1119
|
-
|
|
1113
|
+
const stableRef = useRef(null);
|
|
1114
|
+
const previous = stableRef.current;
|
|
1115
|
+
const stable = previous !== null && previous.length === results.length && previous.every((value, i) => value === results[i]) ? previous : results;
|
|
1116
|
+
stableRef.current = stable;
|
|
1117
|
+
return Array.isArray(input) ? stable : stable[0];
|
|
1120
1118
|
}
|
|
1121
1119
|
useLoader.preload = function(loader, input, extensions, onProgress, cacheKey) {
|
|
1122
1120
|
const inputs = Array.isArray(input) ? input : [input];
|
|
@@ -1236,6 +1234,13 @@ function useFrame(callback, priorityOrOptions) {
|
|
|
1236
1234
|
* Use for controlling the entire frame loop, adding phases, etc.
|
|
1237
1235
|
*/
|
|
1238
1236
|
scheduler: scheduler2,
|
|
1237
|
+
/**
|
|
1238
|
+
* The root that currently owns this job. Resolve on access because ambient
|
|
1239
|
+
* jobs can be adopted by a Canvas after the controls object is created.
|
|
1240
|
+
*/
|
|
1241
|
+
get rootId() {
|
|
1242
|
+
return getScheduler().getJobRootId(id);
|
|
1243
|
+
},
|
|
1239
1244
|
/**
|
|
1240
1245
|
* Manually step this job only.
|
|
1241
1246
|
* Bypasses FPS limiting - always runs.
|
|
@@ -1252,6 +1257,14 @@ function useFrame(callback, priorityOrOptions) {
|
|
|
1252
1257
|
stepAll: (timestamp) => {
|
|
1253
1258
|
getScheduler().step(timestamp);
|
|
1254
1259
|
},
|
|
1260
|
+
/**
|
|
1261
|
+
* Request frames for this job's owning root without waking sibling roots.
|
|
1262
|
+
*/
|
|
1263
|
+
invalidate: (frames, stackFrames) => {
|
|
1264
|
+
const scheduler3 = getScheduler();
|
|
1265
|
+
const rootId = scheduler3.getJobRootId(id);
|
|
1266
|
+
if (rootId) scheduler3.invalidateRoot(rootId, frames, stackFrames);
|
|
1267
|
+
},
|
|
1255
1268
|
/**
|
|
1256
1269
|
* Pause this job (set enabled=false).
|
|
1257
1270
|
* Job remains registered but won't run.
|
|
@@ -1281,6 +1294,11 @@ function getUrls(input) {
|
|
|
1281
1294
|
if (Array.isArray(input)) return input;
|
|
1282
1295
|
return Object.values(input);
|
|
1283
1296
|
}
|
|
1297
|
+
function inputSignature(input) {
|
|
1298
|
+
if (typeof input === "string") return input;
|
|
1299
|
+
if (Array.isArray(input)) return input.join("\0");
|
|
1300
|
+
return Object.keys(input).sort().map((key) => `${key}\0${input[key]}`).join("");
|
|
1301
|
+
}
|
|
1284
1302
|
function allUrlsCached(urls, textureCache) {
|
|
1285
1303
|
return urls.every((url) => textureCache.has(url));
|
|
1286
1304
|
}
|
|
@@ -1306,18 +1324,19 @@ function useTexture(input, optionsOrOnLoad) {
|
|
|
1306
1324
|
const onLoadRef = useRef(onLoad);
|
|
1307
1325
|
onLoadRef.current = onLoad;
|
|
1308
1326
|
const onLoadCalledForRef = useRef(null);
|
|
1309
|
-
const
|
|
1327
|
+
const inputKey = useMemo(() => inputSignature(input), [input]);
|
|
1328
|
+
const stableInput = useMemo(() => input, [inputKey]);
|
|
1329
|
+
const urls = useMemo(() => getUrls(stableInput), [stableInput]);
|
|
1310
1330
|
const cachedResult = useMemo(() => {
|
|
1311
1331
|
if (!cache) return null;
|
|
1312
1332
|
const textures = store.getState().textures;
|
|
1313
1333
|
if (!allUrlsCached(urls, textures)) return null;
|
|
1314
|
-
return buildFromCache(
|
|
1315
|
-
}, [cache, urls,
|
|
1334
|
+
return buildFromCache(stableInput, textures);
|
|
1335
|
+
}, [cache, urls, stableInput, store]);
|
|
1316
1336
|
const loadedTextures = useLoader(
|
|
1317
1337
|
TextureLoader,
|
|
1318
|
-
IsObject(
|
|
1338
|
+
IsObject(stableInput) ? Object.values(stableInput) : stableInput
|
|
1319
1339
|
);
|
|
1320
|
-
const inputKey = urls.join("\0");
|
|
1321
1340
|
useLayoutEffect(() => {
|
|
1322
1341
|
if (cachedResult) return;
|
|
1323
1342
|
if (onLoadCalledForRef.current === inputKey) return;
|
|
@@ -1344,28 +1363,28 @@ function useTexture(input, optionsOrOnLoad) {
|
|
|
1344
1363
|
}, [renderer, loadedTextures, cachedResult]);
|
|
1345
1364
|
const mappedTextures = useMemo(() => {
|
|
1346
1365
|
if (cachedResult) return cachedResult;
|
|
1347
|
-
if (IsObject(
|
|
1366
|
+
if (IsObject(stableInput)) {
|
|
1348
1367
|
const keyed = {};
|
|
1349
1368
|
const textureArray = loadedTextures;
|
|
1350
1369
|
let i = 0;
|
|
1351
|
-
for (const key in
|
|
1370
|
+
for (const key in stableInput) keyed[key] = textureArray[i++];
|
|
1352
1371
|
return keyed;
|
|
1353
1372
|
} else {
|
|
1354
1373
|
return loadedTextures;
|
|
1355
1374
|
}
|
|
1356
|
-
}, [
|
|
1375
|
+
}, [stableInput, loadedTextures, cachedResult]);
|
|
1357
1376
|
useEffect(() => {
|
|
1358
1377
|
if (!cache) return;
|
|
1359
1378
|
const urlTextureMap = [];
|
|
1360
|
-
if (typeof
|
|
1361
|
-
urlTextureMap.push([
|
|
1362
|
-
} else if (Array.isArray(
|
|
1379
|
+
if (typeof stableInput === "string") {
|
|
1380
|
+
urlTextureMap.push([stableInput, mappedTextures]);
|
|
1381
|
+
} else if (Array.isArray(stableInput)) {
|
|
1363
1382
|
const textureArray = mappedTextures;
|
|
1364
|
-
|
|
1365
|
-
} else if (IsObject(
|
|
1383
|
+
stableInput.forEach((url, i) => urlTextureMap.push([url, textureArray[i]]));
|
|
1384
|
+
} else if (IsObject(stableInput)) {
|
|
1366
1385
|
const textureRecord = mappedTextures;
|
|
1367
|
-
for (const key in
|
|
1368
|
-
const url =
|
|
1386
|
+
for (const key in stableInput) {
|
|
1387
|
+
const url = stableInput[key];
|
|
1369
1388
|
urlTextureMap.push([url, textureRecord[key]]);
|
|
1370
1389
|
}
|
|
1371
1390
|
}
|
|
@@ -1394,7 +1413,7 @@ function useTexture(input, optionsOrOnLoad) {
|
|
|
1394
1413
|
}
|
|
1395
1414
|
return { _textureRefs: refs };
|
|
1396
1415
|
});
|
|
1397
|
-
}, [cache,
|
|
1416
|
+
}, [cache, stableInput, mappedTextures, store]);
|
|
1398
1417
|
return mappedTextures;
|
|
1399
1418
|
}
|
|
1400
1419
|
useTexture.preload = (url) => useLoader.preload(TextureLoader, url);
|
|
@@ -1665,10 +1684,16 @@ function addTail(callback) {
|
|
|
1665
1684
|
return getScheduler().onIdle(callback);
|
|
1666
1685
|
}
|
|
1667
1686
|
function invalidate(state, frames = 1, stackFrames = false) {
|
|
1668
|
-
|
|
1687
|
+
const rootId = state?.internal?.rootId;
|
|
1688
|
+
const scheduler = getScheduler();
|
|
1689
|
+
if (rootId) scheduler.invalidateRoot(rootId, frames, stackFrames);
|
|
1690
|
+
else scheduler.invalidate(frames, stackFrames);
|
|
1669
1691
|
}
|
|
1670
|
-
function advance(timestamp) {
|
|
1671
|
-
|
|
1692
|
+
function advance(timestamp, runGlobalEffects, state) {
|
|
1693
|
+
const rootId = state?.internal?.rootId;
|
|
1694
|
+
const scheduler = getScheduler();
|
|
1695
|
+
if (rootId) scheduler.stepRoot(rootId, timestamp);
|
|
1696
|
+
else scheduler.step(timestamp);
|
|
1672
1697
|
}
|
|
1673
1698
|
|
|
1674
1699
|
const version = "10.0.0-alpha.3";
|
|
@@ -14330,7 +14355,7 @@ function createRoot(canvas) {
|
|
|
14330
14355
|
const handleXRFrame = (timestamp, _frame) => {
|
|
14331
14356
|
const state2 = store.getState();
|
|
14332
14357
|
if (state2.frameloop === "never") return;
|
|
14333
|
-
advance(timestamp);
|
|
14358
|
+
advance(timestamp, true, state2);
|
|
14334
14359
|
};
|
|
14335
14360
|
const actualRenderer = state.internal.actualRenderer;
|
|
14336
14361
|
const handleSessionChange = () => {
|
|
@@ -14338,7 +14363,7 @@ function createRoot(canvas) {
|
|
|
14338
14363
|
const renderer2 = state2.internal.actualRenderer;
|
|
14339
14364
|
actualRenderer.xr.enabled = actualRenderer.xr.isPresenting;
|
|
14340
14365
|
renderer2.xr.setAnimationLoop(renderer2.xr.isPresenting ? handleXRFrame : null);
|
|
14341
|
-
if (!renderer2.xr.isPresenting) invalidate();
|
|
14366
|
+
if (!renderer2.xr.isPresenting) invalidate(state2);
|
|
14342
14367
|
};
|
|
14343
14368
|
const xr = {
|
|
14344
14369
|
connect() {
|
|
@@ -14420,7 +14445,11 @@ function createRoot(canvas) {
|
|
|
14420
14445
|
const newRootId = canvasId || scheduler.generateRootId();
|
|
14421
14446
|
const unregisterRoot = scheduler.registerRoot(newRootId, {
|
|
14422
14447
|
getState: () => store.getState(),
|
|
14423
|
-
onError: (err) => store.getState().setError(err)
|
|
14448
|
+
onError: (err) => store.getState().setError(err),
|
|
14449
|
+
frameloop: store.getState().frameloop,
|
|
14450
|
+
before: schedulerConfig?.before,
|
|
14451
|
+
after: schedulerConfig?.after,
|
|
14452
|
+
order: schedulerConfig?.order
|
|
14424
14453
|
});
|
|
14425
14454
|
const unregisterCanvasTarget = scheduler.register(
|
|
14426
14455
|
() => {
|
|
@@ -14428,6 +14457,10 @@ function createRoot(canvas) {
|
|
|
14428
14457
|
if (state2.internal.isMultiCanvas && state2.internal.canvasTarget) {
|
|
14429
14458
|
const renderer2 = state2.internal.actualRenderer;
|
|
14430
14459
|
renderer2.setCanvasTarget(state2.internal.canvasTarget);
|
|
14460
|
+
if (state2.internal.canvasTargetSizeDirty) {
|
|
14461
|
+
state2.internal.canvasTargetSizeDirty = false;
|
|
14462
|
+
renderer2.backend?.updateSize?.();
|
|
14463
|
+
}
|
|
14431
14464
|
}
|
|
14432
14465
|
},
|
|
14433
14466
|
{
|
|
@@ -14496,8 +14529,7 @@ function createRoot(canvas) {
|
|
|
14496
14529
|
phase: "render",
|
|
14497
14530
|
system: true,
|
|
14498
14531
|
// Internal flag: this is a system job, not user-controlled
|
|
14499
|
-
//
|
|
14500
|
-
...schedulerConfig?.after && { after: schedulerConfig.after },
|
|
14532
|
+
// FPS throttles only the default render job; Canvas ordering belongs to the root.
|
|
14501
14533
|
...schedulerConfig?.fps && { fps: schedulerConfig.fps }
|
|
14502
14534
|
}
|
|
14503
14535
|
);
|
|
@@ -14516,8 +14548,21 @@ function createRoot(canvas) {
|
|
|
14516
14548
|
scheduler
|
|
14517
14549
|
}
|
|
14518
14550
|
}));
|
|
14551
|
+
} else {
|
|
14552
|
+
const constraintsChanged = !is.equ(schedulerConfig?.before, lastConfiguredProps.schedulerBefore, shallowLoose) || !is.equ(schedulerConfig?.after, lastConfiguredProps.schedulerAfter, shallowLoose);
|
|
14553
|
+
if (constraintsChanged) {
|
|
14554
|
+
scheduler.setRootConstraints(rootId, {
|
|
14555
|
+
before: schedulerConfig?.before,
|
|
14556
|
+
after: schedulerConfig?.after
|
|
14557
|
+
});
|
|
14558
|
+
}
|
|
14559
|
+
if (schedulerConfig?.order !== lastConfiguredProps.schedulerOrder) {
|
|
14560
|
+
scheduler.setRootOrder(rootId, schedulerConfig?.order ?? 0);
|
|
14561
|
+
}
|
|
14519
14562
|
}
|
|
14520
|
-
|
|
14563
|
+
lastConfiguredProps.schedulerBefore = schedulerConfig?.before;
|
|
14564
|
+
lastConfiguredProps.schedulerAfter = schedulerConfig?.after;
|
|
14565
|
+
lastConfiguredProps.schedulerOrder = schedulerConfig?.order;
|
|
14521
14566
|
onCreated = onCreatedCallback;
|
|
14522
14567
|
configured = true;
|
|
14523
14568
|
resolve();
|
|
@@ -14559,14 +14604,19 @@ function unmountComponentAtNode(canvas, callback) {
|
|
|
14559
14604
|
const fiber = root?.fiber;
|
|
14560
14605
|
if (fiber) {
|
|
14561
14606
|
const state = root?.store.getState();
|
|
14562
|
-
if (state)
|
|
14607
|
+
if (state) {
|
|
14608
|
+
state.internal.active = false;
|
|
14609
|
+
const unregisterRoot = state.internal.unregisterRoot;
|
|
14610
|
+
if (unregisterRoot) {
|
|
14611
|
+
unregisterRoot();
|
|
14612
|
+
state.internal.unregisterRoot = void 0;
|
|
14613
|
+
}
|
|
14614
|
+
}
|
|
14563
14615
|
reconciler.updateContainer(null, fiber, null, () => {
|
|
14564
14616
|
if (state) {
|
|
14565
14617
|
setTimeout(() => {
|
|
14566
14618
|
try {
|
|
14567
14619
|
const renderer = state.internal.actualRenderer;
|
|
14568
|
-
const unregisterRoot = state.internal.unregisterRoot;
|
|
14569
|
-
if (unregisterRoot) unregisterRoot();
|
|
14570
14620
|
const unregisterPrimary = state.internal.unregisterPrimary;
|
|
14571
14621
|
if (unregisterPrimary) unregisterPrimary();
|
|
14572
14622
|
const canvasTarget = state.internal.canvasTarget;
|
|
@@ -15160,6 +15210,7 @@ function CanvasImpl({
|
|
|
15160
15210
|
const canvas = canvasRef.current;
|
|
15161
15211
|
if (canvas) {
|
|
15162
15212
|
return () => {
|
|
15213
|
+
if (canvas.isConnected) return;
|
|
15163
15214
|
unmountComponentAtNode(canvas);
|
|
15164
15215
|
root.current = null;
|
|
15165
15216
|
};
|
package/dist/legacy.cjs
CHANGED
|
@@ -929,7 +929,7 @@ const createStore = (invalidate, advance) => {
|
|
|
929
929
|
size: newSize,
|
|
930
930
|
viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, newSize) }
|
|
931
931
|
}));
|
|
932
|
-
|
|
932
|
+
get().invalidate();
|
|
933
933
|
}
|
|
934
934
|
}
|
|
935
935
|
return;
|
|
@@ -944,15 +944,16 @@ const createStore = (invalidate, advance) => {
|
|
|
944
944
|
viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, size) },
|
|
945
945
|
_sizeImperative: true
|
|
946
946
|
}));
|
|
947
|
-
|
|
947
|
+
get().invalidate();
|
|
948
948
|
},
|
|
949
949
|
setDpr: (dpr) => set((state2) => {
|
|
950
950
|
const resolved = calculateDpr(dpr);
|
|
951
951
|
return { viewport: { ...state2.viewport, dpr: resolved, initialDpr: state2.viewport.initialDpr || resolved } };
|
|
952
952
|
}),
|
|
953
953
|
setFrameloop: (frameloop = "always") => {
|
|
954
|
+
const rootId = get().internal.rootId;
|
|
955
|
+
if (rootId) scheduler.getScheduler().setRootFrameloop(rootId, frameloop);
|
|
954
956
|
set(() => ({ frameloop }));
|
|
955
|
-
scheduler.getScheduler().frameloop = frameloop;
|
|
956
957
|
},
|
|
957
958
|
setError: (error) => set(() => ({ error })),
|
|
958
959
|
error: null,
|
|
@@ -1068,17 +1069,10 @@ const createStore = (invalidate, advance) => {
|
|
|
1068
1069
|
oldSize = size;
|
|
1069
1070
|
oldDpr = viewport.dpr;
|
|
1070
1071
|
updateCamera(camera, size);
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
if (viewport.dpr > 0) actualRenderer.setPixelRatio(viewport.dpr);
|
|
1076
|
-
actualRenderer.setSize(size.width, size.height, false);
|
|
1077
|
-
if (canvasTarget) {
|
|
1078
|
-
if (viewport.dpr > 0) canvasTarget.setPixelRatio(viewport.dpr);
|
|
1079
|
-
canvasTarget.setSize(size.width, size.height, false);
|
|
1080
|
-
}
|
|
1081
|
-
}
|
|
1072
|
+
const resizeTarget = canvasTarget ?? actualRenderer;
|
|
1073
|
+
if (viewport.dpr > 0) resizeTarget.setPixelRatio(viewport.dpr);
|
|
1074
|
+
resizeTarget.setSize(size.width, size.height, false);
|
|
1075
|
+
internal.canvasTargetSizeDirty = true;
|
|
1082
1076
|
}
|
|
1083
1077
|
if (camera !== oldCamera) {
|
|
1084
1078
|
oldCamera = camera;
|
|
@@ -1140,7 +1134,11 @@ function useLoader(loader, input, extensions, onProgress, cacheKey) {
|
|
|
1140
1134
|
const results = cacheKeys.map(
|
|
1141
1135
|
(key, index) => suspendReact.suspend(() => fn(loader, inputs[index]), [loader, key], { equal: is.equ })
|
|
1142
1136
|
);
|
|
1143
|
-
|
|
1137
|
+
const stableRef = React.useRef(null);
|
|
1138
|
+
const previous = stableRef.current;
|
|
1139
|
+
const stable = previous !== null && previous.length === results.length && previous.every((value, i) => value === results[i]) ? previous : results;
|
|
1140
|
+
stableRef.current = stable;
|
|
1141
|
+
return Array.isArray(input) ? stable : stable[0];
|
|
1144
1142
|
}
|
|
1145
1143
|
useLoader.preload = function(loader, input, extensions, onProgress, cacheKey) {
|
|
1146
1144
|
const inputs = Array.isArray(input) ? input : [input];
|
|
@@ -1260,6 +1258,13 @@ function useFrame(callback, priorityOrOptions) {
|
|
|
1260
1258
|
* Use for controlling the entire frame loop, adding phases, etc.
|
|
1261
1259
|
*/
|
|
1262
1260
|
scheduler: scheduler2,
|
|
1261
|
+
/**
|
|
1262
|
+
* The root that currently owns this job. Resolve on access because ambient
|
|
1263
|
+
* jobs can be adopted by a Canvas after the controls object is created.
|
|
1264
|
+
*/
|
|
1265
|
+
get rootId() {
|
|
1266
|
+
return scheduler.getScheduler().getJobRootId(id);
|
|
1267
|
+
},
|
|
1263
1268
|
/**
|
|
1264
1269
|
* Manually step this job only.
|
|
1265
1270
|
* Bypasses FPS limiting - always runs.
|
|
@@ -1276,6 +1281,14 @@ function useFrame(callback, priorityOrOptions) {
|
|
|
1276
1281
|
stepAll: (timestamp) => {
|
|
1277
1282
|
scheduler.getScheduler().step(timestamp);
|
|
1278
1283
|
},
|
|
1284
|
+
/**
|
|
1285
|
+
* Request frames for this job's owning root without waking sibling roots.
|
|
1286
|
+
*/
|
|
1287
|
+
invalidate: (frames, stackFrames) => {
|
|
1288
|
+
const scheduler3 = scheduler.getScheduler();
|
|
1289
|
+
const rootId = scheduler3.getJobRootId(id);
|
|
1290
|
+
if (rootId) scheduler3.invalidateRoot(rootId, frames, stackFrames);
|
|
1291
|
+
},
|
|
1279
1292
|
/**
|
|
1280
1293
|
* Pause this job (set enabled=false).
|
|
1281
1294
|
* Job remains registered but won't run.
|
|
@@ -1305,6 +1318,11 @@ function getUrls(input) {
|
|
|
1305
1318
|
if (Array.isArray(input)) return input;
|
|
1306
1319
|
return Object.values(input);
|
|
1307
1320
|
}
|
|
1321
|
+
function inputSignature(input) {
|
|
1322
|
+
if (typeof input === "string") return input;
|
|
1323
|
+
if (Array.isArray(input)) return input.join("\0");
|
|
1324
|
+
return Object.keys(input).sort().map((key) => `${key}\0${input[key]}`).join("");
|
|
1325
|
+
}
|
|
1308
1326
|
function allUrlsCached(urls, textureCache) {
|
|
1309
1327
|
return urls.every((url) => textureCache.has(url));
|
|
1310
1328
|
}
|
|
@@ -1330,18 +1348,19 @@ function useTexture(input, optionsOrOnLoad) {
|
|
|
1330
1348
|
const onLoadRef = React.useRef(onLoad);
|
|
1331
1349
|
onLoadRef.current = onLoad;
|
|
1332
1350
|
const onLoadCalledForRef = React.useRef(null);
|
|
1333
|
-
const
|
|
1351
|
+
const inputKey = React.useMemo(() => inputSignature(input), [input]);
|
|
1352
|
+
const stableInput = React.useMemo(() => input, [inputKey]);
|
|
1353
|
+
const urls = React.useMemo(() => getUrls(stableInput), [stableInput]);
|
|
1334
1354
|
const cachedResult = React.useMemo(() => {
|
|
1335
1355
|
if (!cache) return null;
|
|
1336
1356
|
const textures = store.getState().textures;
|
|
1337
1357
|
if (!allUrlsCached(urls, textures)) return null;
|
|
1338
|
-
return buildFromCache(
|
|
1339
|
-
}, [cache, urls,
|
|
1358
|
+
return buildFromCache(stableInput, textures);
|
|
1359
|
+
}, [cache, urls, stableInput, store]);
|
|
1340
1360
|
const loadedTextures = useLoader(
|
|
1341
1361
|
three.TextureLoader,
|
|
1342
|
-
IsObject(
|
|
1362
|
+
IsObject(stableInput) ? Object.values(stableInput) : stableInput
|
|
1343
1363
|
);
|
|
1344
|
-
const inputKey = urls.join("\0");
|
|
1345
1364
|
React.useLayoutEffect(() => {
|
|
1346
1365
|
if (cachedResult) return;
|
|
1347
1366
|
if (onLoadCalledForRef.current === inputKey) return;
|
|
@@ -1368,28 +1387,28 @@ function useTexture(input, optionsOrOnLoad) {
|
|
|
1368
1387
|
}, [renderer, loadedTextures, cachedResult]);
|
|
1369
1388
|
const mappedTextures = React.useMemo(() => {
|
|
1370
1389
|
if (cachedResult) return cachedResult;
|
|
1371
|
-
if (IsObject(
|
|
1390
|
+
if (IsObject(stableInput)) {
|
|
1372
1391
|
const keyed = {};
|
|
1373
1392
|
const textureArray = loadedTextures;
|
|
1374
1393
|
let i = 0;
|
|
1375
|
-
for (const key in
|
|
1394
|
+
for (const key in stableInput) keyed[key] = textureArray[i++];
|
|
1376
1395
|
return keyed;
|
|
1377
1396
|
} else {
|
|
1378
1397
|
return loadedTextures;
|
|
1379
1398
|
}
|
|
1380
|
-
}, [
|
|
1399
|
+
}, [stableInput, loadedTextures, cachedResult]);
|
|
1381
1400
|
React.useEffect(() => {
|
|
1382
1401
|
if (!cache) return;
|
|
1383
1402
|
const urlTextureMap = [];
|
|
1384
|
-
if (typeof
|
|
1385
|
-
urlTextureMap.push([
|
|
1386
|
-
} else if (Array.isArray(
|
|
1403
|
+
if (typeof stableInput === "string") {
|
|
1404
|
+
urlTextureMap.push([stableInput, mappedTextures]);
|
|
1405
|
+
} else if (Array.isArray(stableInput)) {
|
|
1387
1406
|
const textureArray = mappedTextures;
|
|
1388
|
-
|
|
1389
|
-
} else if (IsObject(
|
|
1407
|
+
stableInput.forEach((url, i) => urlTextureMap.push([url, textureArray[i]]));
|
|
1408
|
+
} else if (IsObject(stableInput)) {
|
|
1390
1409
|
const textureRecord = mappedTextures;
|
|
1391
|
-
for (const key in
|
|
1392
|
-
const url =
|
|
1410
|
+
for (const key in stableInput) {
|
|
1411
|
+
const url = stableInput[key];
|
|
1393
1412
|
urlTextureMap.push([url, textureRecord[key]]);
|
|
1394
1413
|
}
|
|
1395
1414
|
}
|
|
@@ -1418,7 +1437,7 @@ function useTexture(input, optionsOrOnLoad) {
|
|
|
1418
1437
|
}
|
|
1419
1438
|
return { _textureRefs: refs };
|
|
1420
1439
|
});
|
|
1421
|
-
}, [cache,
|
|
1440
|
+
}, [cache, stableInput, mappedTextures, store]);
|
|
1422
1441
|
return mappedTextures;
|
|
1423
1442
|
}
|
|
1424
1443
|
useTexture.preload = (url) => useLoader.preload(three.TextureLoader, url);
|
|
@@ -1687,10 +1706,16 @@ function addTail(callback) {
|
|
|
1687
1706
|
return scheduler.getScheduler().onIdle(callback);
|
|
1688
1707
|
}
|
|
1689
1708
|
function invalidate(state, frames = 1, stackFrames = false) {
|
|
1690
|
-
|
|
1709
|
+
const rootId = state?.internal?.rootId;
|
|
1710
|
+
const scheduler$1 = scheduler.getScheduler();
|
|
1711
|
+
if (rootId) scheduler$1.invalidateRoot(rootId, frames, stackFrames);
|
|
1712
|
+
else scheduler$1.invalidate(frames, stackFrames);
|
|
1691
1713
|
}
|
|
1692
|
-
function advance(timestamp) {
|
|
1693
|
-
|
|
1714
|
+
function advance(timestamp, runGlobalEffects, state) {
|
|
1715
|
+
const rootId = state?.internal?.rootId;
|
|
1716
|
+
const scheduler$1 = scheduler.getScheduler();
|
|
1717
|
+
if (rootId) scheduler$1.stepRoot(rootId, timestamp);
|
|
1718
|
+
else scheduler$1.step(timestamp);
|
|
1694
1719
|
}
|
|
1695
1720
|
|
|
1696
1721
|
const version = "10.0.0-alpha.3";
|
|
@@ -14305,7 +14330,7 @@ function createRoot(canvas) {
|
|
|
14305
14330
|
const handleXRFrame = (timestamp, _frame) => {
|
|
14306
14331
|
const state2 = store.getState();
|
|
14307
14332
|
if (state2.frameloop === "never") return;
|
|
14308
|
-
advance(timestamp);
|
|
14333
|
+
advance(timestamp, true, state2);
|
|
14309
14334
|
};
|
|
14310
14335
|
const actualRenderer = state.internal.actualRenderer;
|
|
14311
14336
|
const handleSessionChange = () => {
|
|
@@ -14313,7 +14338,7 @@ function createRoot(canvas) {
|
|
|
14313
14338
|
const renderer2 = state2.internal.actualRenderer;
|
|
14314
14339
|
actualRenderer.xr.enabled = actualRenderer.xr.isPresenting;
|
|
14315
14340
|
renderer2.xr.setAnimationLoop(renderer2.xr.isPresenting ? handleXRFrame : null);
|
|
14316
|
-
if (!renderer2.xr.isPresenting) invalidate();
|
|
14341
|
+
if (!renderer2.xr.isPresenting) invalidate(state2);
|
|
14317
14342
|
};
|
|
14318
14343
|
const xr = {
|
|
14319
14344
|
connect() {
|
|
@@ -14395,7 +14420,11 @@ function createRoot(canvas) {
|
|
|
14395
14420
|
const newRootId = canvasId || scheduler$1.generateRootId();
|
|
14396
14421
|
const unregisterRoot = scheduler$1.registerRoot(newRootId, {
|
|
14397
14422
|
getState: () => store.getState(),
|
|
14398
|
-
onError: (err) => store.getState().setError(err)
|
|
14423
|
+
onError: (err) => store.getState().setError(err),
|
|
14424
|
+
frameloop: store.getState().frameloop,
|
|
14425
|
+
before: schedulerConfig?.before,
|
|
14426
|
+
after: schedulerConfig?.after,
|
|
14427
|
+
order: schedulerConfig?.order
|
|
14399
14428
|
});
|
|
14400
14429
|
const unregisterCanvasTarget = scheduler$1.register(
|
|
14401
14430
|
() => {
|
|
@@ -14403,6 +14432,10 @@ function createRoot(canvas) {
|
|
|
14403
14432
|
if (state2.internal.isMultiCanvas && state2.internal.canvasTarget) {
|
|
14404
14433
|
const renderer2 = state2.internal.actualRenderer;
|
|
14405
14434
|
renderer2.setCanvasTarget(state2.internal.canvasTarget);
|
|
14435
|
+
if (state2.internal.canvasTargetSizeDirty) {
|
|
14436
|
+
state2.internal.canvasTargetSizeDirty = false;
|
|
14437
|
+
renderer2.backend?.updateSize?.();
|
|
14438
|
+
}
|
|
14406
14439
|
}
|
|
14407
14440
|
},
|
|
14408
14441
|
{
|
|
@@ -14471,8 +14504,7 @@ function createRoot(canvas) {
|
|
|
14471
14504
|
phase: "render",
|
|
14472
14505
|
system: true,
|
|
14473
14506
|
// Internal flag: this is a system job, not user-controlled
|
|
14474
|
-
//
|
|
14475
|
-
...schedulerConfig?.after && { after: schedulerConfig.after },
|
|
14507
|
+
// FPS throttles only the default render job; Canvas ordering belongs to the root.
|
|
14476
14508
|
...schedulerConfig?.fps && { fps: schedulerConfig.fps }
|
|
14477
14509
|
}
|
|
14478
14510
|
);
|
|
@@ -14491,8 +14523,21 @@ function createRoot(canvas) {
|
|
|
14491
14523
|
scheduler: scheduler$1
|
|
14492
14524
|
}
|
|
14493
14525
|
}));
|
|
14526
|
+
} else {
|
|
14527
|
+
const constraintsChanged = !is.equ(schedulerConfig?.before, lastConfiguredProps.schedulerBefore, shallowLoose) || !is.equ(schedulerConfig?.after, lastConfiguredProps.schedulerAfter, shallowLoose);
|
|
14528
|
+
if (constraintsChanged) {
|
|
14529
|
+
scheduler$1.setRootConstraints(rootId, {
|
|
14530
|
+
before: schedulerConfig?.before,
|
|
14531
|
+
after: schedulerConfig?.after
|
|
14532
|
+
});
|
|
14533
|
+
}
|
|
14534
|
+
if (schedulerConfig?.order !== lastConfiguredProps.schedulerOrder) {
|
|
14535
|
+
scheduler$1.setRootOrder(rootId, schedulerConfig?.order ?? 0);
|
|
14536
|
+
}
|
|
14494
14537
|
}
|
|
14495
|
-
|
|
14538
|
+
lastConfiguredProps.schedulerBefore = schedulerConfig?.before;
|
|
14539
|
+
lastConfiguredProps.schedulerAfter = schedulerConfig?.after;
|
|
14540
|
+
lastConfiguredProps.schedulerOrder = schedulerConfig?.order;
|
|
14496
14541
|
onCreated = onCreatedCallback;
|
|
14497
14542
|
configured = true;
|
|
14498
14543
|
resolve();
|
|
@@ -14534,14 +14579,19 @@ function unmountComponentAtNode(canvas, callback) {
|
|
|
14534
14579
|
const fiber = root?.fiber;
|
|
14535
14580
|
if (fiber) {
|
|
14536
14581
|
const state = root?.store.getState();
|
|
14537
|
-
if (state)
|
|
14582
|
+
if (state) {
|
|
14583
|
+
state.internal.active = false;
|
|
14584
|
+
const unregisterRoot = state.internal.unregisterRoot;
|
|
14585
|
+
if (unregisterRoot) {
|
|
14586
|
+
unregisterRoot();
|
|
14587
|
+
state.internal.unregisterRoot = void 0;
|
|
14588
|
+
}
|
|
14589
|
+
}
|
|
14538
14590
|
reconciler.updateContainer(null, fiber, null, () => {
|
|
14539
14591
|
if (state) {
|
|
14540
14592
|
setTimeout(() => {
|
|
14541
14593
|
try {
|
|
14542
14594
|
const renderer = state.internal.actualRenderer;
|
|
14543
|
-
const unregisterRoot = state.internal.unregisterRoot;
|
|
14544
|
-
if (unregisterRoot) unregisterRoot();
|
|
14545
14595
|
const unregisterPrimary = state.internal.unregisterPrimary;
|
|
14546
14596
|
if (unregisterPrimary) unregisterPrimary();
|
|
14547
14597
|
const canvasTarget = state.internal.canvasTarget;
|
|
@@ -15135,6 +15185,7 @@ function CanvasImpl({
|
|
|
15135
15185
|
const canvas = canvasRef.current;
|
|
15136
15186
|
if (canvas) {
|
|
15137
15187
|
return () => {
|
|
15188
|
+
if (canvas.isConnected) return;
|
|
15138
15189
|
unmountComponentAtNode(canvas);
|
|
15139
15190
|
root.current = null;
|
|
15140
15191
|
};
|