@react-three/fiber 10.0.0-canary.b0fafc8 → 10.0.0-canary.d6fdf72
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 +440 -188
- package/dist/index.d.cts +236 -80
- package/dist/index.d.mts +236 -80
- package/dist/index.d.ts +236 -80
- package/dist/index.mjs +441 -189
- package/dist/legacy.cjs +434 -188
- package/dist/legacy.d.cts +236 -80
- package/dist/legacy.d.mts +236 -80
- package/dist/legacy.d.ts +236 -80
- package/dist/legacy.mjs +435 -189
- package/dist/webgpu/index.cjs +815 -199
- package/dist/webgpu/index.d.cts +321 -93
- package/dist/webgpu/index.d.mts +321 -93
- package/dist/webgpu/index.d.ts +321 -93
- package/dist/webgpu/index.mjs +812 -200
- package/package.json +1 -1
package/dist/legacy.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as three from 'three';
|
|
2
|
-
import { WebGLRenderTarget, CubeReflectionMapping, EquirectangularReflectionMapping, CubeTextureLoader, Scene, WebGLCubeRenderTarget, HalfFloatType, Color, Frustum, Matrix4, Group, BoxGeometry, MeshBasicNodeMaterial, Mesh, Node, NodeUpdateType, Layers, SRGBColorSpace, RGBAFormat, UnsignedByteType, Vector3, Vector2, TextureLoader, Texture as Texture$1, Raycaster, OrthographicCamera, PerspectiveCamera,
|
|
2
|
+
import { WebGLRenderTarget, CubeReflectionMapping, EquirectangularReflectionMapping, CubeTextureLoader, Scene, WebGLCubeRenderTarget, HalfFloatType, Color, Frustum, Matrix4, Group, BoxGeometry, MeshBasicNodeMaterial, Mesh, Node, NodeUpdateType, Layers, SRGBColorSpace, RGBAFormat, UnsignedByteType, Vector3, Vector2, TextureLoader, Texture as Texture$1, Raycaster, OrthographicCamera, PerspectiveCamera, PCFShadowMap, VSMShadowMap, BasicShadowMap, ACESFilmicToneMapping, WebGLRenderer } from 'three';
|
|
3
3
|
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
4
4
|
import * as React from 'react';
|
|
5
5
|
import React__default, { useLayoutEffect, useRef, useMemo, useEffect, useContext, useImperativeHandle, useCallback, useState } from 'react';
|
|
@@ -148,7 +148,7 @@ function useEnvironment({
|
|
|
148
148
|
useLoader$1.clear(loader, multiFile ? [files] : files);
|
|
149
149
|
}
|
|
150
150
|
renderer.domElement.addEventListener("webglcontextlost", clearGainmapTexture, { once: true });
|
|
151
|
-
}, [files, renderer.domElement]);
|
|
151
|
+
}, [extension, files, loader, multiFile, renderer.domElement]);
|
|
152
152
|
const loaderResult = useLoader$1(
|
|
153
153
|
loader,
|
|
154
154
|
multiFile ? [files] : files,
|
|
@@ -348,7 +348,22 @@ function EnvironmentPortal({
|
|
|
348
348
|
environmentIntensity,
|
|
349
349
|
environmentRotation
|
|
350
350
|
});
|
|
351
|
-
}, [
|
|
351
|
+
}, [
|
|
352
|
+
children,
|
|
353
|
+
virtualScene,
|
|
354
|
+
fbo.texture,
|
|
355
|
+
scene,
|
|
356
|
+
defaultScene,
|
|
357
|
+
background,
|
|
358
|
+
frames,
|
|
359
|
+
gl,
|
|
360
|
+
blur,
|
|
361
|
+
backgroundBlurriness,
|
|
362
|
+
backgroundIntensity,
|
|
363
|
+
backgroundRotation,
|
|
364
|
+
environmentIntensity,
|
|
365
|
+
environmentRotation
|
|
366
|
+
]);
|
|
352
367
|
let count = 1;
|
|
353
368
|
useFrame$1(() => {
|
|
354
369
|
if (frames === Infinity || count < frames) {
|
|
@@ -984,6 +999,9 @@ function applyProps(object, props) {
|
|
|
984
999
|
else target.set(value);
|
|
985
1000
|
} else {
|
|
986
1001
|
root[key] = value;
|
|
1002
|
+
if (key.endsWith("Node") && root.isMaterial) {
|
|
1003
|
+
root.needsUpdate = true;
|
|
1004
|
+
}
|
|
987
1005
|
if (rootState && rootState.renderer?.outputColorSpace === SRGBColorSpace && colorMaps.includes(key) && isTexture(value) && root[key]?.isTexture && // sRGB textures must be RGBA8 since r137 https://github.com/mrdoob/three.js/pull/23129
|
|
988
1006
|
root[key].format === RGBAFormat && root[key].type === UnsignedByteType) {
|
|
989
1007
|
root[key].colorSpace = rootState.textureColorSpace;
|
|
@@ -1017,38 +1035,60 @@ function applyProps(object, props) {
|
|
|
1017
1035
|
return object;
|
|
1018
1036
|
}
|
|
1019
1037
|
|
|
1038
|
+
const DEFAULT_POINTER_ID = 0;
|
|
1039
|
+
const XR_POINTER_ID_START = 1e3;
|
|
1040
|
+
function getPointerState(internal, pointerId) {
|
|
1041
|
+
let state = internal.pointerMap.get(pointerId);
|
|
1042
|
+
if (!state) {
|
|
1043
|
+
state = {
|
|
1044
|
+
hovered: /* @__PURE__ */ new Map(),
|
|
1045
|
+
captured: /* @__PURE__ */ new Map(),
|
|
1046
|
+
initialClick: [0, 0],
|
|
1047
|
+
initialHits: []
|
|
1048
|
+
};
|
|
1049
|
+
internal.pointerMap.set(pointerId, state);
|
|
1050
|
+
}
|
|
1051
|
+
return state;
|
|
1052
|
+
}
|
|
1053
|
+
function getPointerId(event) {
|
|
1054
|
+
return "pointerId" in event ? event.pointerId : DEFAULT_POINTER_ID;
|
|
1055
|
+
}
|
|
1020
1056
|
function makeId(event) {
|
|
1021
1057
|
return (event.eventObject || event.object).uuid + "/" + event.index + event.instanceId;
|
|
1022
1058
|
}
|
|
1023
|
-
function releaseInternalPointerCapture(
|
|
1024
|
-
const
|
|
1059
|
+
function releaseInternalPointerCapture(internal, obj, pointerId) {
|
|
1060
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1061
|
+
if (!pointerState) return;
|
|
1062
|
+
const captureData = pointerState.captured.get(obj);
|
|
1025
1063
|
if (captureData) {
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
capturedMap.delete(pointerId);
|
|
1029
|
-
captureData.target.releasePointerCapture(pointerId);
|
|
1030
|
-
}
|
|
1064
|
+
pointerState.captured.delete(obj);
|
|
1065
|
+
captureData.target.releasePointerCapture(pointerId);
|
|
1031
1066
|
}
|
|
1032
1067
|
}
|
|
1033
1068
|
function removeInteractivity(store, object) {
|
|
1034
1069
|
const { internal } = store.getState();
|
|
1035
1070
|
internal.interaction = internal.interaction.filter((o) => o !== object);
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1071
|
+
for (const [pointerId, pointerState] of internal.pointerMap) {
|
|
1072
|
+
pointerState.initialHits = pointerState.initialHits.filter((o) => o !== object);
|
|
1073
|
+
pointerState.hovered.forEach((value, key) => {
|
|
1074
|
+
if (value.eventObject === object || value.object === object) {
|
|
1075
|
+
pointerState.hovered.delete(key);
|
|
1076
|
+
}
|
|
1077
|
+
});
|
|
1078
|
+
if (pointerState.captured.has(object)) {
|
|
1079
|
+
releaseInternalPointerCapture(internal, object, pointerId);
|
|
1040
1080
|
}
|
|
1041
|
-
}
|
|
1042
|
-
internal.capturedMap.forEach((captures, pointerId) => {
|
|
1043
|
-
releaseInternalPointerCapture(internal.capturedMap, object, captures, pointerId);
|
|
1044
|
-
});
|
|
1081
|
+
}
|
|
1045
1082
|
unregisterVisibility(store, object);
|
|
1046
1083
|
}
|
|
1047
1084
|
function createEvents(store) {
|
|
1048
|
-
function calculateDistance(event) {
|
|
1085
|
+
function calculateDistance(event, pointerId) {
|
|
1049
1086
|
const { internal } = store.getState();
|
|
1050
|
-
const
|
|
1051
|
-
|
|
1087
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1088
|
+
if (!pointerState) return 0;
|
|
1089
|
+
const [initialX, initialY] = pointerState.initialClick;
|
|
1090
|
+
const dx = event.offsetX - initialX;
|
|
1091
|
+
const dy = event.offsetY - initialY;
|
|
1052
1092
|
return Math.round(Math.sqrt(dx * dx + dy * dy));
|
|
1053
1093
|
}
|
|
1054
1094
|
function filterPointerEvents(objects) {
|
|
@@ -1084,6 +1124,15 @@ function createEvents(store) {
|
|
|
1084
1124
|
return state2.raycaster.camera ? state2.raycaster.intersectObject(obj, true) : [];
|
|
1085
1125
|
}
|
|
1086
1126
|
let hits = eventsObjects.flatMap(handleRaycast).sort((a, b) => {
|
|
1127
|
+
const aInteractivePriority = a.object.userData?.interactivePriority;
|
|
1128
|
+
const bInteractivePriority = b.object.userData?.interactivePriority;
|
|
1129
|
+
if (aInteractivePriority !== void 0 || bInteractivePriority !== void 0) {
|
|
1130
|
+
if (aInteractivePriority !== void 0 && bInteractivePriority === void 0) return -1;
|
|
1131
|
+
if (bInteractivePriority !== void 0 && aInteractivePriority === void 0) return 1;
|
|
1132
|
+
if (aInteractivePriority !== bInteractivePriority) {
|
|
1133
|
+
return (bInteractivePriority ?? 0) - (aInteractivePriority ?? 0);
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1087
1136
|
const aState = getRootState(a.object);
|
|
1088
1137
|
const bState = getRootState(b.object);
|
|
1089
1138
|
const aPriority = aState?.events?.priority ?? 1;
|
|
@@ -1105,9 +1154,13 @@ function createEvents(store) {
|
|
|
1105
1154
|
eventObject = eventObject.parent;
|
|
1106
1155
|
}
|
|
1107
1156
|
}
|
|
1108
|
-
if ("pointerId" in event
|
|
1109
|
-
|
|
1110
|
-
|
|
1157
|
+
if ("pointerId" in event) {
|
|
1158
|
+
const pointerId = event.pointerId;
|
|
1159
|
+
const pointerState = state.internal.pointerMap.get(pointerId);
|
|
1160
|
+
if (pointerState?.captured.size) {
|
|
1161
|
+
for (const captureData of pointerState.captured.values()) {
|
|
1162
|
+
if (!duplicates.has(makeId(captureData.intersection))) intersections.push(captureData.intersection);
|
|
1163
|
+
}
|
|
1111
1164
|
}
|
|
1112
1165
|
}
|
|
1113
1166
|
return intersections;
|
|
@@ -1120,27 +1173,25 @@ function createEvents(store) {
|
|
|
1120
1173
|
if (state) {
|
|
1121
1174
|
const { raycaster, pointer, camera, internal } = state;
|
|
1122
1175
|
const unprojectedPoint = new Vector3(pointer.x, pointer.y, 0).unproject(camera);
|
|
1123
|
-
const hasPointerCapture = (id) =>
|
|
1176
|
+
const hasPointerCapture = (id) => {
|
|
1177
|
+
const pointerState = internal.pointerMap.get(id);
|
|
1178
|
+
return pointerState?.captured.has(hit.eventObject) ?? false;
|
|
1179
|
+
};
|
|
1124
1180
|
const setPointerCapture = (id) => {
|
|
1125
1181
|
const captureData = { intersection: hit, target: event.target };
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
} else {
|
|
1129
|
-
internal.capturedMap.set(id, /* @__PURE__ */ new Map([[hit.eventObject, captureData]]));
|
|
1130
|
-
}
|
|
1182
|
+
const pointerState = getPointerState(internal, id);
|
|
1183
|
+
pointerState.captured.set(hit.eventObject, captureData);
|
|
1131
1184
|
event.target.setPointerCapture(id);
|
|
1132
1185
|
};
|
|
1133
1186
|
const releasePointerCapture = (id) => {
|
|
1134
|
-
|
|
1135
|
-
if (captures) {
|
|
1136
|
-
releaseInternalPointerCapture(internal.capturedMap, hit.eventObject, captures, id);
|
|
1137
|
-
}
|
|
1187
|
+
releaseInternalPointerCapture(internal, hit.eventObject, id);
|
|
1138
1188
|
};
|
|
1139
1189
|
const extractEventProps = {};
|
|
1140
1190
|
for (const prop in event) {
|
|
1141
1191
|
const property = event[prop];
|
|
1142
1192
|
if (typeof property !== "function") extractEventProps[prop] = property;
|
|
1143
1193
|
}
|
|
1194
|
+
const eventPointerId = "pointerId" in event ? event.pointerId : void 0;
|
|
1144
1195
|
const raycastEvent = {
|
|
1145
1196
|
...hit,
|
|
1146
1197
|
...extractEventProps,
|
|
@@ -1151,18 +1202,19 @@ function createEvents(store) {
|
|
|
1151
1202
|
unprojectedPoint,
|
|
1152
1203
|
ray: raycaster.ray,
|
|
1153
1204
|
camera,
|
|
1205
|
+
pointerId: eventPointerId,
|
|
1154
1206
|
// Hijack stopPropagation, which just sets a flag
|
|
1155
1207
|
stopPropagation() {
|
|
1156
|
-
const
|
|
1208
|
+
const pointerState = eventPointerId !== void 0 ? internal.pointerMap.get(eventPointerId) : void 0;
|
|
1157
1209
|
if (
|
|
1158
1210
|
// ...if this pointer hasn't been captured
|
|
1159
|
-
!
|
|
1160
|
-
|
|
1211
|
+
!pointerState?.captured.size || // ... or if the hit object is capturing the pointer
|
|
1212
|
+
pointerState.captured.has(hit.eventObject)
|
|
1161
1213
|
) {
|
|
1162
1214
|
raycastEvent.stopped = localState.stopped = true;
|
|
1163
|
-
if (
|
|
1215
|
+
if (pointerState?.hovered.size && Array.from(pointerState.hovered.values()).find((i) => i.eventObject === hit.eventObject)) {
|
|
1164
1216
|
const higher = intersections.slice(0, intersections.indexOf(hit));
|
|
1165
|
-
cancelPointer([...higher, hit]);
|
|
1217
|
+
cancelPointer([...higher, hit], eventPointerId);
|
|
1166
1218
|
}
|
|
1167
1219
|
}
|
|
1168
1220
|
},
|
|
@@ -1178,15 +1230,18 @@ function createEvents(store) {
|
|
|
1178
1230
|
}
|
|
1179
1231
|
return intersections;
|
|
1180
1232
|
}
|
|
1181
|
-
function cancelPointer(intersections) {
|
|
1233
|
+
function cancelPointer(intersections, pointerId) {
|
|
1182
1234
|
const { internal } = store.getState();
|
|
1183
|
-
|
|
1235
|
+
const pid = pointerId ?? DEFAULT_POINTER_ID;
|
|
1236
|
+
const pointerState = internal.pointerMap.get(pid);
|
|
1237
|
+
if (!pointerState) return;
|
|
1238
|
+
for (const [hoveredId, hoveredObj] of pointerState.hovered) {
|
|
1184
1239
|
if (!intersections.length || !intersections.find(
|
|
1185
1240
|
(hit) => hit.object === hoveredObj.object && hit.index === hoveredObj.index && hit.instanceId === hoveredObj.instanceId
|
|
1186
1241
|
)) {
|
|
1187
1242
|
const eventObject = hoveredObj.eventObject;
|
|
1188
1243
|
const instance = eventObject.__r3f;
|
|
1189
|
-
|
|
1244
|
+
pointerState.hovered.delete(hoveredId);
|
|
1190
1245
|
if (instance?.eventCount) {
|
|
1191
1246
|
const handlers = instance.handlers;
|
|
1192
1247
|
const data = { ...hoveredObj, intersections };
|
|
@@ -1215,41 +1270,118 @@ function createEvents(store) {
|
|
|
1215
1270
|
instance?.handlers.onDropMissed?.(event);
|
|
1216
1271
|
}
|
|
1217
1272
|
}
|
|
1273
|
+
function cleanupPointer(pointerId) {
|
|
1274
|
+
const { internal } = store.getState();
|
|
1275
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1276
|
+
if (pointerState) {
|
|
1277
|
+
for (const [, hoveredObj] of pointerState.hovered) {
|
|
1278
|
+
const eventObject = hoveredObj.eventObject;
|
|
1279
|
+
const instance = eventObject.__r3f;
|
|
1280
|
+
if (instance?.eventCount) {
|
|
1281
|
+
const handlers = instance.handlers;
|
|
1282
|
+
const data = { ...hoveredObj, intersections: [] };
|
|
1283
|
+
handlers.onPointerOut?.(data);
|
|
1284
|
+
handlers.onPointerLeave?.(data);
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
internal.pointerMap.delete(pointerId);
|
|
1288
|
+
}
|
|
1289
|
+
internal.pointerDirty.delete(pointerId);
|
|
1290
|
+
}
|
|
1291
|
+
function processDeferredPointer(event, pointerId) {
|
|
1292
|
+
const state = store.getState();
|
|
1293
|
+
const { internal } = state;
|
|
1294
|
+
if (!state.events.enabled) return;
|
|
1295
|
+
const filter = filterPointerEvents;
|
|
1296
|
+
const hits = intersect(event, filter);
|
|
1297
|
+
cancelPointer(hits, pointerId);
|
|
1298
|
+
function onIntersect(data) {
|
|
1299
|
+
const eventObject = data.eventObject;
|
|
1300
|
+
const instance = eventObject.__r3f;
|
|
1301
|
+
if (!instance?.eventCount) return;
|
|
1302
|
+
const handlers = instance.handlers;
|
|
1303
|
+
if (handlers.onPointerOver || handlers.onPointerEnter || handlers.onPointerOut || handlers.onPointerLeave) {
|
|
1304
|
+
const id = makeId(data);
|
|
1305
|
+
const pointerState = getPointerState(internal, pointerId);
|
|
1306
|
+
const hoveredItem = pointerState.hovered.get(id);
|
|
1307
|
+
if (!hoveredItem) {
|
|
1308
|
+
pointerState.hovered.set(id, data);
|
|
1309
|
+
handlers.onPointerOver?.(data);
|
|
1310
|
+
handlers.onPointerEnter?.(data);
|
|
1311
|
+
} else if (hoveredItem.stopped) {
|
|
1312
|
+
data.stopPropagation();
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
handlers.onPointerMove?.(data);
|
|
1316
|
+
}
|
|
1317
|
+
handleIntersects(hits, event, 0, onIntersect);
|
|
1318
|
+
}
|
|
1218
1319
|
function handlePointer(name) {
|
|
1219
1320
|
switch (name) {
|
|
1220
1321
|
case "onPointerLeave":
|
|
1221
|
-
case "onPointerCancel":
|
|
1222
1322
|
case "onDragLeave":
|
|
1223
1323
|
return () => cancelPointer([]);
|
|
1324
|
+
// Global cancel of these events
|
|
1325
|
+
case "onPointerCancel":
|
|
1326
|
+
return (event) => {
|
|
1327
|
+
const pointerId = getPointerId(event);
|
|
1328
|
+
cleanupPointer(pointerId);
|
|
1329
|
+
};
|
|
1224
1330
|
case "onLostPointerCapture":
|
|
1225
1331
|
return (event) => {
|
|
1226
1332
|
const { internal } = store.getState();
|
|
1227
|
-
|
|
1333
|
+
const pointerId = getPointerId(event);
|
|
1334
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1335
|
+
if (pointerState?.captured.size) {
|
|
1228
1336
|
requestAnimationFrame(() => {
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1337
|
+
const pointerState2 = internal.pointerMap.get(pointerId);
|
|
1338
|
+
if (pointerState2?.captured.size) {
|
|
1339
|
+
pointerState2.captured.clear();
|
|
1232
1340
|
}
|
|
1341
|
+
cancelPointer([], pointerId);
|
|
1233
1342
|
});
|
|
1234
1343
|
}
|
|
1235
1344
|
};
|
|
1236
1345
|
}
|
|
1237
1346
|
return function handleEvent(event) {
|
|
1238
1347
|
const state = store.getState();
|
|
1239
|
-
const { onPointerMissed, onDragOverMissed, onDropMissed, internal } = state;
|
|
1348
|
+
const { onPointerMissed, onDragOverMissed, onDropMissed, internal, events } = state;
|
|
1349
|
+
const pointerId = getPointerId(event);
|
|
1240
1350
|
internal.lastEvent.current = event;
|
|
1241
|
-
if (!
|
|
1351
|
+
if (!events.enabled) return;
|
|
1242
1352
|
const isPointerMove = name === "onPointerMove";
|
|
1243
1353
|
const isDragOver = name === "onDragOver";
|
|
1244
1354
|
const isDrop = name === "onDrop";
|
|
1245
1355
|
const isClickEvent = name === "onClick" || name === "onContextMenu" || name === "onDoubleClick";
|
|
1356
|
+
const isPointerDown = name === "onPointerDown";
|
|
1357
|
+
const isPointerUp = name === "onPointerUp";
|
|
1358
|
+
const isWheel = name === "onWheel";
|
|
1359
|
+
const canDeferRaycasts = events.frameTimedRaycasts && state.frameloop === "always";
|
|
1360
|
+
if (isPointerMove && canDeferRaycasts) {
|
|
1361
|
+
events.compute?.(event, state);
|
|
1362
|
+
internal.pointerDirty.set(pointerId, event);
|
|
1363
|
+
return;
|
|
1364
|
+
}
|
|
1365
|
+
if (isWheel && canDeferRaycasts && !events.alwaysFireOnScroll) {
|
|
1366
|
+
events.compute?.(event, state);
|
|
1367
|
+
internal.pointerDirty.set(pointerId, event);
|
|
1368
|
+
return;
|
|
1369
|
+
}
|
|
1370
|
+
if ((isClickEvent || isPointerDown || isPointerUp) && internal.pointerDirty.has(pointerId)) {
|
|
1371
|
+
const deferredEvent = internal.pointerDirty.get(pointerId);
|
|
1372
|
+
internal.pointerDirty.delete(pointerId);
|
|
1373
|
+
processDeferredPointer(deferredEvent, pointerId);
|
|
1374
|
+
}
|
|
1246
1375
|
const filter = isPointerMove || isDragOver || isDrop ? filterPointerEvents : void 0;
|
|
1247
1376
|
const hits = intersect(event, filter);
|
|
1248
|
-
const delta = isClickEvent ? calculateDistance(event) : 0;
|
|
1249
|
-
if (
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1377
|
+
const delta = isClickEvent ? calculateDistance(event, pointerId) : 0;
|
|
1378
|
+
if (isPointerDown) {
|
|
1379
|
+
const pointerState2 = getPointerState(internal, pointerId);
|
|
1380
|
+
pointerState2.initialClick = [event.offsetX, event.offsetY];
|
|
1381
|
+
pointerState2.initialHits = hits.map((hit) => hit.eventObject);
|
|
1382
|
+
}
|
|
1383
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1384
|
+
const initialHits = pointerState?.initialHits ?? [];
|
|
1253
1385
|
if (isClickEvent && !hits.length) {
|
|
1254
1386
|
if (delta <= 2) {
|
|
1255
1387
|
pointerMissed(event, internal.interaction);
|
|
@@ -1264,7 +1396,9 @@ function createEvents(store) {
|
|
|
1264
1396
|
dropMissed(event, internal.interaction);
|
|
1265
1397
|
if (onDropMissed) onDropMissed(event);
|
|
1266
1398
|
}
|
|
1267
|
-
if (isPointerMove || isDragOver)
|
|
1399
|
+
if (isPointerMove || isDragOver) {
|
|
1400
|
+
cancelPointer(hits, pointerId);
|
|
1401
|
+
}
|
|
1268
1402
|
function onIntersect(data) {
|
|
1269
1403
|
const eventObject = data.eventObject;
|
|
1270
1404
|
const instance = eventObject.__r3f;
|
|
@@ -1273,9 +1407,10 @@ function createEvents(store) {
|
|
|
1273
1407
|
if (isPointerMove) {
|
|
1274
1408
|
if (handlers.onPointerOver || handlers.onPointerEnter || handlers.onPointerOut || handlers.onPointerLeave) {
|
|
1275
1409
|
const id = makeId(data);
|
|
1276
|
-
const
|
|
1410
|
+
const pointerState2 = getPointerState(internal, pointerId);
|
|
1411
|
+
const hoveredItem = pointerState2.hovered.get(id);
|
|
1277
1412
|
if (!hoveredItem) {
|
|
1278
|
-
|
|
1413
|
+
pointerState2.hovered.set(id, data);
|
|
1279
1414
|
handlers.onPointerOver?.(data);
|
|
1280
1415
|
handlers.onPointerEnter?.(data);
|
|
1281
1416
|
} else if (hoveredItem.stopped) {
|
|
@@ -1285,9 +1420,10 @@ function createEvents(store) {
|
|
|
1285
1420
|
handlers.onPointerMove?.(data);
|
|
1286
1421
|
} else if (isDragOver) {
|
|
1287
1422
|
const id = makeId(data);
|
|
1288
|
-
const
|
|
1423
|
+
const pointerState2 = getPointerState(internal, pointerId);
|
|
1424
|
+
const hoveredItem = pointerState2.hovered.get(id);
|
|
1289
1425
|
if (!hoveredItem) {
|
|
1290
|
-
|
|
1426
|
+
pointerState2.hovered.set(id, data);
|
|
1291
1427
|
handlers.onDragOverEnter?.(data);
|
|
1292
1428
|
} else if (hoveredItem.stopped) {
|
|
1293
1429
|
data.stopPropagation();
|
|
@@ -1298,18 +1434,18 @@ function createEvents(store) {
|
|
|
1298
1434
|
} else {
|
|
1299
1435
|
const handler = handlers[name];
|
|
1300
1436
|
if (handler) {
|
|
1301
|
-
if (!isClickEvent ||
|
|
1437
|
+
if (!isClickEvent || initialHits.includes(eventObject)) {
|
|
1302
1438
|
pointerMissed(
|
|
1303
1439
|
event,
|
|
1304
|
-
internal.interaction.filter((object) => !
|
|
1440
|
+
internal.interaction.filter((object) => !initialHits.includes(object))
|
|
1305
1441
|
);
|
|
1306
1442
|
handler(data);
|
|
1307
1443
|
}
|
|
1308
1444
|
} else {
|
|
1309
|
-
if (isClickEvent &&
|
|
1445
|
+
if (isClickEvent && initialHits.includes(eventObject)) {
|
|
1310
1446
|
pointerMissed(
|
|
1311
1447
|
event,
|
|
1312
|
-
internal.interaction.filter((object) => !
|
|
1448
|
+
internal.interaction.filter((object) => !initialHits.includes(object))
|
|
1313
1449
|
);
|
|
1314
1450
|
}
|
|
1315
1451
|
}
|
|
@@ -1318,7 +1454,15 @@ function createEvents(store) {
|
|
|
1318
1454
|
handleIntersects(hits, event, delta, onIntersect);
|
|
1319
1455
|
};
|
|
1320
1456
|
}
|
|
1321
|
-
|
|
1457
|
+
function flushDeferredPointers() {
|
|
1458
|
+
const { internal, events } = store.getState();
|
|
1459
|
+
if (!events.frameTimedRaycasts) return;
|
|
1460
|
+
for (const [pointerId, event] of internal.pointerDirty) {
|
|
1461
|
+
processDeferredPointer(event, pointerId);
|
|
1462
|
+
}
|
|
1463
|
+
internal.pointerDirty.clear();
|
|
1464
|
+
}
|
|
1465
|
+
return { handlePointer, flushDeferredPointers, processDeferredPointer };
|
|
1322
1466
|
}
|
|
1323
1467
|
const DOM_EVENTS = {
|
|
1324
1468
|
onClick: ["click", false],
|
|
@@ -1337,10 +1481,15 @@ const DOM_EVENTS = {
|
|
|
1337
1481
|
onLostPointerCapture: ["lostpointercapture", true]
|
|
1338
1482
|
};
|
|
1339
1483
|
function createPointerEvents(store) {
|
|
1340
|
-
const { handlePointer } = createEvents(store);
|
|
1484
|
+
const { handlePointer, flushDeferredPointers, processDeferredPointer } = createEvents(store);
|
|
1485
|
+
let nextXRPointerId = XR_POINTER_ID_START;
|
|
1486
|
+
const xrPointers = /* @__PURE__ */ new Map();
|
|
1341
1487
|
return {
|
|
1342
1488
|
priority: 1,
|
|
1343
1489
|
enabled: true,
|
|
1490
|
+
frameTimedRaycasts: true,
|
|
1491
|
+
alwaysFireOnScroll: true,
|
|
1492
|
+
updateOnFrame: false,
|
|
1344
1493
|
compute(event, state) {
|
|
1345
1494
|
state.pointer.set(event.offsetX / state.size.width * 2 - 1, -(event.offsetY / state.size.height) * 2 + 1);
|
|
1346
1495
|
state.raycaster.setFromCamera(state.pointer, state.camera);
|
|
@@ -1350,11 +1499,33 @@ function createPointerEvents(store) {
|
|
|
1350
1499
|
(acc, key) => ({ ...acc, [key]: handlePointer(key) }),
|
|
1351
1500
|
{}
|
|
1352
1501
|
),
|
|
1353
|
-
update: () => {
|
|
1502
|
+
update: (pointerId) => {
|
|
1354
1503
|
const { events, internal } = store.getState();
|
|
1355
|
-
if (
|
|
1504
|
+
if (!events.handlers) return;
|
|
1505
|
+
if (pointerId !== void 0) {
|
|
1506
|
+
const event = internal.pointerDirty.get(pointerId);
|
|
1507
|
+
if (event) {
|
|
1508
|
+
internal.pointerDirty.delete(pointerId);
|
|
1509
|
+
processDeferredPointer(event, pointerId);
|
|
1510
|
+
} else if (internal.lastEvent?.current) {
|
|
1511
|
+
processDeferredPointer(internal.lastEvent.current, pointerId);
|
|
1512
|
+
}
|
|
1513
|
+
} else {
|
|
1514
|
+
flushDeferredPointers();
|
|
1515
|
+
if (internal.lastEvent?.current) {
|
|
1516
|
+
events.handlers.onPointerMove(internal.lastEvent.current);
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
},
|
|
1520
|
+
flush: () => {
|
|
1521
|
+
const { events, internal } = store.getState();
|
|
1522
|
+
flushDeferredPointers();
|
|
1523
|
+
if (events.updateOnFrame && internal.lastEvent?.current && events.handlers) {
|
|
1524
|
+
events.handlers.onPointerMove(internal.lastEvent.current);
|
|
1525
|
+
}
|
|
1356
1526
|
},
|
|
1357
1527
|
connect: (target) => {
|
|
1528
|
+
if (!target) return;
|
|
1358
1529
|
const { set, events } = store.getState();
|
|
1359
1530
|
events.disconnect?.();
|
|
1360
1531
|
set((state) => ({ events: { ...state.events, connected: target } }));
|
|
@@ -1378,6 +1549,32 @@ function createPointerEvents(store) {
|
|
|
1378
1549
|
}
|
|
1379
1550
|
set((state) => ({ events: { ...state.events, connected: void 0 } }));
|
|
1380
1551
|
}
|
|
1552
|
+
},
|
|
1553
|
+
registerPointer: (config) => {
|
|
1554
|
+
const pointerId = nextXRPointerId++;
|
|
1555
|
+
xrPointers.set(pointerId, config);
|
|
1556
|
+
const { internal } = store.getState();
|
|
1557
|
+
getPointerState(internal, pointerId);
|
|
1558
|
+
return pointerId;
|
|
1559
|
+
},
|
|
1560
|
+
unregisterPointer: (pointerId) => {
|
|
1561
|
+
xrPointers.delete(pointerId);
|
|
1562
|
+
const { internal } = store.getState();
|
|
1563
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1564
|
+
if (pointerState) {
|
|
1565
|
+
for (const [, hoveredObj] of pointerState.hovered) {
|
|
1566
|
+
const eventObject = hoveredObj.eventObject;
|
|
1567
|
+
const instance = eventObject.__r3f;
|
|
1568
|
+
if (instance?.eventCount) {
|
|
1569
|
+
const handlers = instance.handlers;
|
|
1570
|
+
const data = { ...hoveredObj, intersections: [] };
|
|
1571
|
+
handlers.onPointerOut?.(data);
|
|
1572
|
+
handlers.onPointerLeave?.(data);
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
internal.pointerMap.delete(pointerId);
|
|
1576
|
+
}
|
|
1577
|
+
internal.pointerDirty.delete(pointerId);
|
|
1381
1578
|
}
|
|
1382
1579
|
};
|
|
1383
1580
|
}
|
|
@@ -1691,7 +1888,7 @@ function shouldRun(job, now) {
|
|
|
1691
1888
|
const minInterval = 1e3 / job.fps;
|
|
1692
1889
|
const lastRun = job.lastRun ?? 0;
|
|
1693
1890
|
const elapsed = now - lastRun;
|
|
1694
|
-
if (elapsed < minInterval) return false;
|
|
1891
|
+
if (elapsed < minInterval - 1) return false;
|
|
1695
1892
|
if (job.drop) {
|
|
1696
1893
|
job.lastRun = now;
|
|
1697
1894
|
} else {
|
|
@@ -2508,7 +2705,14 @@ const createStore = (invalidate, advance) => {
|
|
|
2508
2705
|
frustum: new Frustum(),
|
|
2509
2706
|
autoUpdateFrustum: true,
|
|
2510
2707
|
raycaster: null,
|
|
2511
|
-
events: {
|
|
2708
|
+
events: {
|
|
2709
|
+
priority: 1,
|
|
2710
|
+
enabled: true,
|
|
2711
|
+
connected: false,
|
|
2712
|
+
frameTimedRaycasts: true,
|
|
2713
|
+
alwaysFireOnScroll: true,
|
|
2714
|
+
updateOnFrame: false
|
|
2715
|
+
},
|
|
2512
2716
|
scene: null,
|
|
2513
2717
|
rootScene: null,
|
|
2514
2718
|
xr: null,
|
|
@@ -2599,11 +2803,14 @@ const createStore = (invalidate, advance) => {
|
|
|
2599
2803
|
},
|
|
2600
2804
|
setError: (error) => set(() => ({ error })),
|
|
2601
2805
|
error: null,
|
|
2602
|
-
//* TSL State (managed via hooks: useUniforms, useNodes, useTextures,
|
|
2806
|
+
//* TSL State (managed via hooks: useUniforms, useNodes, useBuffers, useGPUStorage, useTextures, useRenderPipeline) ==============================
|
|
2603
2807
|
uniforms: {},
|
|
2604
2808
|
nodes: {},
|
|
2809
|
+
buffers: {},
|
|
2810
|
+
gpuStorage: {},
|
|
2605
2811
|
textures: /* @__PURE__ */ new Map(),
|
|
2606
|
-
|
|
2812
|
+
_textureRefs: /* @__PURE__ */ new Map(),
|
|
2813
|
+
renderPipeline: null,
|
|
2607
2814
|
passes: {},
|
|
2608
2815
|
_hmrVersion: 0,
|
|
2609
2816
|
_sizeImperative: false,
|
|
@@ -2612,12 +2819,16 @@ const createStore = (invalidate, advance) => {
|
|
|
2612
2819
|
internal: {
|
|
2613
2820
|
// Events
|
|
2614
2821
|
interaction: [],
|
|
2615
|
-
hovered: /* @__PURE__ */ new Map(),
|
|
2616
2822
|
subscribers: [],
|
|
2823
|
+
// Per-pointer state (new unified structure)
|
|
2824
|
+
pointerMap: /* @__PURE__ */ new Map(),
|
|
2825
|
+
pointerDirty: /* @__PURE__ */ new Map(),
|
|
2826
|
+
lastEvent: React.createRef(),
|
|
2827
|
+
// Deprecated but kept for backwards compatibility
|
|
2828
|
+
hovered: /* @__PURE__ */ new Map(),
|
|
2617
2829
|
initialClick: [0, 0],
|
|
2618
2830
|
initialHits: [],
|
|
2619
2831
|
capturedMap: /* @__PURE__ */ new Map(),
|
|
2620
|
-
lastEvent: React.createRef(),
|
|
2621
2832
|
// Visibility tracking (onFramed, onOccluded, onVisible)
|
|
2622
2833
|
visibilityRegistry: /* @__PURE__ */ new Map(),
|
|
2623
2834
|
// Occlusion system (WebGPU only)
|
|
@@ -2705,14 +2916,16 @@ const createStore = (invalidate, advance) => {
|
|
|
2705
2916
|
oldSize = size;
|
|
2706
2917
|
oldDpr = viewport.dpr;
|
|
2707
2918
|
updateCamera(camera, size);
|
|
2708
|
-
if (canvasTarget) {
|
|
2919
|
+
if (internal.isSecondary && canvasTarget) {
|
|
2709
2920
|
if (viewport.dpr > 0) canvasTarget.setPixelRatio(viewport.dpr);
|
|
2710
|
-
|
|
2711
|
-
canvasTarget.setSize(size.width, size.height, updateStyle);
|
|
2921
|
+
canvasTarget.setSize(size.width, size.height, false);
|
|
2712
2922
|
} else {
|
|
2713
2923
|
if (viewport.dpr > 0) actualRenderer.setPixelRatio(viewport.dpr);
|
|
2714
|
-
|
|
2715
|
-
|
|
2924
|
+
actualRenderer.setSize(size.width, size.height, false);
|
|
2925
|
+
if (canvasTarget) {
|
|
2926
|
+
if (viewport.dpr > 0) canvasTarget.setPixelRatio(viewport.dpr);
|
|
2927
|
+
canvasTarget.setSize(size.width, size.height, false);
|
|
2928
|
+
}
|
|
2716
2929
|
}
|
|
2717
2930
|
}
|
|
2718
2931
|
if (camera !== oldCamera) {
|
|
@@ -2960,18 +3173,18 @@ function buildFromCache(input, textureCache) {
|
|
|
2960
3173
|
function useTexture(input, optionsOrOnLoad) {
|
|
2961
3174
|
const renderer = useThree((state) => state.internal.actualRenderer);
|
|
2962
3175
|
const store = useStore();
|
|
2963
|
-
const textureCache = useThree((state) => state.textures);
|
|
2964
3176
|
const options = typeof optionsOrOnLoad === "function" ? { onLoad: optionsOrOnLoad } : optionsOrOnLoad ?? {};
|
|
2965
|
-
const { onLoad, cache =
|
|
3177
|
+
const { onLoad, cache = true } = options;
|
|
2966
3178
|
const onLoadRef = useRef(onLoad);
|
|
2967
3179
|
onLoadRef.current = onLoad;
|
|
2968
3180
|
const onLoadCalledForRef = useRef(null);
|
|
2969
3181
|
const urls = useMemo(() => getUrls(input), [input]);
|
|
2970
3182
|
const cachedResult = useMemo(() => {
|
|
2971
3183
|
if (!cache) return null;
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
3184
|
+
const textures = store.getState().textures;
|
|
3185
|
+
if (!allUrlsCached(urls, textures)) return null;
|
|
3186
|
+
return buildFromCache(input, textures);
|
|
3187
|
+
}, [cache, urls, input, store]);
|
|
2975
3188
|
const loadedTextures = useLoader(
|
|
2976
3189
|
TextureLoader,
|
|
2977
3190
|
IsObject(input) ? Object.values(input) : input
|
|
@@ -3015,8 +3228,6 @@ function useTexture(input, optionsOrOnLoad) {
|
|
|
3015
3228
|
}, [input, loadedTextures, cachedResult]);
|
|
3016
3229
|
useEffect(() => {
|
|
3017
3230
|
if (!cache) return;
|
|
3018
|
-
if (cachedResult) return;
|
|
3019
|
-
const set = store.setState;
|
|
3020
3231
|
const urlTextureMap = [];
|
|
3021
3232
|
if (typeof input === "string") {
|
|
3022
3233
|
urlTextureMap.push([input, mappedTextures]);
|
|
@@ -3030,18 +3241,32 @@ function useTexture(input, optionsOrOnLoad) {
|
|
|
3030
3241
|
urlTextureMap.push([url, textureRecord[key]]);
|
|
3031
3242
|
}
|
|
3032
3243
|
}
|
|
3033
|
-
|
|
3034
|
-
const
|
|
3035
|
-
let
|
|
3244
|
+
store.setState((state) => {
|
|
3245
|
+
const refs = new Map(state._textureRefs);
|
|
3246
|
+
let textures = state.textures;
|
|
3247
|
+
let added = false;
|
|
3036
3248
|
for (const [url, texture] of urlTextureMap) {
|
|
3037
|
-
if (!
|
|
3038
|
-
|
|
3039
|
-
|
|
3249
|
+
if (!textures.has(url)) {
|
|
3250
|
+
if (!added) {
|
|
3251
|
+
textures = new Map(textures);
|
|
3252
|
+
added = true;
|
|
3253
|
+
}
|
|
3254
|
+
textures.set(url, texture);
|
|
3040
3255
|
}
|
|
3256
|
+
refs.set(url, (refs.get(url) ?? 0) + 1);
|
|
3041
3257
|
}
|
|
3042
|
-
return
|
|
3258
|
+
return added ? { textures, _textureRefs: refs } : { _textureRefs: refs };
|
|
3043
3259
|
});
|
|
3044
|
-
|
|
3260
|
+
return () => store.setState((state) => {
|
|
3261
|
+
const refs = new Map(state._textureRefs);
|
|
3262
|
+
for (const [url] of urlTextureMap) {
|
|
3263
|
+
const next = (refs.get(url) ?? 0) - 1;
|
|
3264
|
+
if (next <= 0) refs.delete(url);
|
|
3265
|
+
else refs.set(url, next);
|
|
3266
|
+
}
|
|
3267
|
+
return { _textureRefs: refs };
|
|
3268
|
+
});
|
|
3269
|
+
}, [cache, input, mappedTextures, store]);
|
|
3045
3270
|
return mappedTextures;
|
|
3046
3271
|
}
|
|
3047
3272
|
useTexture.preload = (url) => useLoader.preload(TextureLoader, url);
|
|
@@ -3057,96 +3282,63 @@ const Texture = ({
|
|
|
3057
3282
|
return /* @__PURE__ */ jsx(Fragment, { children: children?.(ret) });
|
|
3058
3283
|
};
|
|
3059
3284
|
|
|
3060
|
-
function
|
|
3061
|
-
if (entry instanceof Texture$1) return entry;
|
|
3062
|
-
if (entry && typeof entry === "object" && "value" in entry && entry.value instanceof Texture$1) {
|
|
3063
|
-
return entry.value;
|
|
3064
|
-
}
|
|
3065
|
-
return null;
|
|
3066
|
-
}
|
|
3067
|
-
function useTextures() {
|
|
3285
|
+
function useTextures(selector) {
|
|
3068
3286
|
const store = useStore();
|
|
3069
|
-
|
|
3070
|
-
const set = store.setState;
|
|
3287
|
+
const registry = useMemo(() => {
|
|
3071
3288
|
const getState = store.getState;
|
|
3072
|
-
const
|
|
3073
|
-
|
|
3074
|
-
const newMap = new Map(state.textures);
|
|
3075
|
-
newMap.set(key, value);
|
|
3076
|
-
return { textures: newMap };
|
|
3077
|
-
});
|
|
3078
|
-
};
|
|
3079
|
-
const addMultiple = (items) => {
|
|
3080
|
-
set((state) => {
|
|
3081
|
-
const newMap = new Map(state.textures);
|
|
3082
|
-
const entries = items instanceof Map ? items.entries() : Object.entries(items);
|
|
3083
|
-
for (const [key, value] of entries) {
|
|
3084
|
-
newMap.set(key, value);
|
|
3085
|
-
}
|
|
3086
|
-
return { textures: newMap };
|
|
3087
|
-
});
|
|
3088
|
-
};
|
|
3089
|
-
const remove = (key) => {
|
|
3090
|
-
set((state) => {
|
|
3091
|
-
const newMap = new Map(state.textures);
|
|
3092
|
-
newMap.delete(key);
|
|
3093
|
-
return { textures: newMap };
|
|
3094
|
-
});
|
|
3095
|
-
};
|
|
3096
|
-
const removeMultiple = (keys) => {
|
|
3097
|
-
set((state) => {
|
|
3098
|
-
const newMap = new Map(state.textures);
|
|
3099
|
-
for (const key of keys) newMap.delete(key);
|
|
3100
|
-
return { textures: newMap };
|
|
3101
|
-
});
|
|
3102
|
-
};
|
|
3103
|
-
const dispose = (key) => {
|
|
3104
|
-
const entry = getState().textures.get(key);
|
|
3105
|
-
if (entry) {
|
|
3106
|
-
const tex = getTextureValue(entry);
|
|
3107
|
-
tex?.dispose();
|
|
3108
|
-
}
|
|
3109
|
-
remove(key);
|
|
3110
|
-
};
|
|
3111
|
-
const disposeMultiple = (keys) => {
|
|
3112
|
-
const textures = getState().textures;
|
|
3113
|
-
for (const key of keys) {
|
|
3114
|
-
const entry = textures.get(key);
|
|
3115
|
-
if (entry) {
|
|
3116
|
-
const tex = getTextureValue(entry);
|
|
3117
|
-
tex?.dispose();
|
|
3118
|
-
}
|
|
3119
|
-
}
|
|
3120
|
-
removeMultiple(keys);
|
|
3121
|
-
};
|
|
3122
|
-
const disposeAll = () => {
|
|
3123
|
-
const textures = getState().textures;
|
|
3124
|
-
for (const entry of textures.values()) {
|
|
3125
|
-
const tex = getTextureValue(entry);
|
|
3126
|
-
tex?.dispose();
|
|
3127
|
-
}
|
|
3128
|
-
set({ textures: /* @__PURE__ */ new Map() });
|
|
3129
|
-
};
|
|
3289
|
+
const setState = store.setState;
|
|
3290
|
+
const getOne = (key) => getState().textures.get(key);
|
|
3130
3291
|
return {
|
|
3131
|
-
|
|
3132
|
-
get textures() {
|
|
3292
|
+
get all() {
|
|
3133
3293
|
return getState().textures;
|
|
3134
3294
|
},
|
|
3135
|
-
|
|
3136
|
-
|
|
3295
|
+
get(input) {
|
|
3296
|
+
if (typeof input === "string") return getOne(input);
|
|
3297
|
+
if (Array.isArray(input)) return input.map(getOne);
|
|
3298
|
+
const out = {};
|
|
3299
|
+
for (const name in input) out[name] = getOne(input[name]);
|
|
3300
|
+
return out;
|
|
3301
|
+
},
|
|
3137
3302
|
has: (key) => getState().textures.has(key),
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3303
|
+
add(keyOrRecord, texture) {
|
|
3304
|
+
setState((state) => {
|
|
3305
|
+
const textures = new Map(state.textures);
|
|
3306
|
+
if (typeof keyOrRecord === "string") {
|
|
3307
|
+
textures.set(keyOrRecord, texture);
|
|
3308
|
+
} else {
|
|
3309
|
+
for (const key in keyOrRecord) textures.set(key, keyOrRecord[key]);
|
|
3310
|
+
}
|
|
3311
|
+
return { textures };
|
|
3312
|
+
});
|
|
3313
|
+
},
|
|
3314
|
+
dispose(key, options) {
|
|
3315
|
+
const state = getState();
|
|
3316
|
+
const refs = state._textureRefs.get(key) ?? 0;
|
|
3317
|
+
if (refs > 0 && !options?.force) {
|
|
3318
|
+
console.warn(
|
|
3319
|
+
`[useTextures] "${key}" still has ${refs} active reference(s); skipping dispose. Pass { force: true } to override.`
|
|
3320
|
+
);
|
|
3321
|
+
return false;
|
|
3322
|
+
}
|
|
3323
|
+
state.textures.get(key)?.dispose();
|
|
3324
|
+
setState((s) => {
|
|
3325
|
+
const textures = new Map(s.textures);
|
|
3326
|
+
textures.delete(key);
|
|
3327
|
+
const nextRefs = new Map(s._textureRefs);
|
|
3328
|
+
nextRefs.delete(key);
|
|
3329
|
+
return { textures, _textureRefs: nextRefs };
|
|
3330
|
+
});
|
|
3331
|
+
return true;
|
|
3332
|
+
},
|
|
3333
|
+
disposeAll() {
|
|
3334
|
+
for (const texture of getState().textures.values()) texture.dispose();
|
|
3335
|
+
setState({ textures: /* @__PURE__ */ new Map(), _textureRefs: /* @__PURE__ */ new Map() });
|
|
3336
|
+
}
|
|
3148
3337
|
};
|
|
3149
3338
|
}, [store]);
|
|
3339
|
+
const subscribe = selector ? () => selector(registry) : (state) => state.textures;
|
|
3340
|
+
const selected = useThree(subscribe);
|
|
3341
|
+
return selector ? selected : registry;
|
|
3150
3342
|
}
|
|
3151
3343
|
|
|
3152
3344
|
function useRenderTarget(widthOrOptions, heightOrOptions, options) {
|
|
@@ -14997,7 +15189,6 @@ function createRoot(canvas) {
|
|
|
14997
15189
|
events,
|
|
14998
15190
|
onCreated: onCreatedCallback,
|
|
14999
15191
|
shadows = false,
|
|
15000
|
-
textureColorSpace = SRGBColorSpace,
|
|
15001
15192
|
orthographic = false,
|
|
15002
15193
|
frameloop = "always",
|
|
15003
15194
|
dpr = [1, 2],
|
|
@@ -15012,6 +15203,7 @@ function createRoot(canvas) {
|
|
|
15012
15203
|
_sizeProps,
|
|
15013
15204
|
forceEven
|
|
15014
15205
|
} = props;
|
|
15206
|
+
const textureColorSpace = is.obj(glConfig) && !is.fun(glConfig) && !isRenderer(glConfig) && glConfig.textureColorSpace || is.obj(rendererConfig) && !is.fun(rendererConfig) && !isRenderer(rendererConfig) && rendererConfig.textureColorSpace || SRGBColorSpace;
|
|
15015
15207
|
const state = store.getState();
|
|
15016
15208
|
const defaultGLProps = {
|
|
15017
15209
|
canvas,
|
|
@@ -15135,7 +15327,7 @@ function createRoot(canvas) {
|
|
|
15135
15327
|
lastConfiguredProps.performance = performance;
|
|
15136
15328
|
}
|
|
15137
15329
|
if (!state.xr) {
|
|
15138
|
-
const handleXRFrame = (timestamp,
|
|
15330
|
+
const handleXRFrame = (timestamp, _frame) => {
|
|
15139
15331
|
const state2 = store.getState();
|
|
15140
15332
|
if (state2.frameloop === "never") return;
|
|
15141
15333
|
advance(timestamp);
|
|
@@ -15171,15 +15363,22 @@ function createRoot(canvas) {
|
|
|
15171
15363
|
const oldType = renderer.shadowMap.type;
|
|
15172
15364
|
renderer.shadowMap.enabled = !!shadows;
|
|
15173
15365
|
if (is.boo(shadows)) {
|
|
15174
|
-
renderer.shadowMap.type =
|
|
15366
|
+
renderer.shadowMap.type = PCFShadowMap;
|
|
15175
15367
|
} else if (is.str(shadows)) {
|
|
15368
|
+
if (shadows === "soft") {
|
|
15369
|
+
notifyDepreciated({
|
|
15370
|
+
heading: 'shadows="soft" is deprecated',
|
|
15371
|
+
body: "Three has depreciated soft and improved basic PCFShadows, we converted for you.",
|
|
15372
|
+
link: "https://github.com/mrdoob/three.js/wiki/Migration-Guide?utm_source=chatgpt.com#181--182"
|
|
15373
|
+
});
|
|
15374
|
+
}
|
|
15176
15375
|
const types = {
|
|
15177
15376
|
basic: BasicShadowMap,
|
|
15178
15377
|
percentage: PCFShadowMap,
|
|
15179
|
-
soft:
|
|
15378
|
+
soft: PCFShadowMap,
|
|
15180
15379
|
variance: VSMShadowMap
|
|
15181
15380
|
};
|
|
15182
|
-
renderer.shadowMap.type = types[shadows] ??
|
|
15381
|
+
renderer.shadowMap.type = types[shadows] ?? PCFShadowMap;
|
|
15183
15382
|
} else if (is.obj(shadows)) {
|
|
15184
15383
|
Object.assign(renderer.shadowMap, shadows);
|
|
15185
15384
|
}
|
|
@@ -15195,13 +15394,24 @@ function createRoot(canvas) {
|
|
|
15195
15394
|
if (state.textureColorSpace !== textureColorSpace) state.set(() => ({ textureColorSpace }));
|
|
15196
15395
|
lastConfiguredProps.textureColorSpace = textureColorSpace;
|
|
15197
15396
|
}
|
|
15397
|
+
const r3fProps = ["textureColorSpace"];
|
|
15398
|
+
const constructorOnlyProps = ["samples", "antialias", "alpha", "canvas", "powerPreference"];
|
|
15399
|
+
const nonApplyProps = [...r3fProps, ...constructorOnlyProps];
|
|
15198
15400
|
if (glConfig && !is.fun(glConfig) && !isRenderer(glConfig) && !is.equ(glConfig, renderer, shallowLoose)) {
|
|
15199
|
-
|
|
15401
|
+
const glProps = {};
|
|
15402
|
+
for (const key in glConfig) {
|
|
15403
|
+
if (!nonApplyProps.includes(key)) glProps[key] = glConfig[key];
|
|
15404
|
+
}
|
|
15405
|
+
applyProps(renderer, glProps);
|
|
15200
15406
|
}
|
|
15201
15407
|
if (rendererConfig && !is.fun(rendererConfig) && !isRenderer(rendererConfig) && state.renderer) {
|
|
15202
15408
|
const currentRenderer = state.renderer;
|
|
15203
15409
|
if (!is.equ(rendererConfig, currentRenderer, shallowLoose)) {
|
|
15204
|
-
|
|
15410
|
+
const rendererProps = {};
|
|
15411
|
+
for (const key in rendererConfig) {
|
|
15412
|
+
if (!nonApplyProps.includes(key)) rendererProps[key] = rendererConfig[key];
|
|
15413
|
+
}
|
|
15414
|
+
applyProps(currentRenderer, rendererProps);
|
|
15205
15415
|
}
|
|
15206
15416
|
}
|
|
15207
15417
|
const scheduler = getScheduler();
|
|
@@ -15227,6 +15437,18 @@ function createRoot(canvas) {
|
|
|
15227
15437
|
system: true
|
|
15228
15438
|
}
|
|
15229
15439
|
);
|
|
15440
|
+
const unregisterEventsFlush = scheduler.register(
|
|
15441
|
+
() => {
|
|
15442
|
+
const state2 = store.getState();
|
|
15443
|
+
state2.events.flush?.();
|
|
15444
|
+
},
|
|
15445
|
+
{
|
|
15446
|
+
id: `${newRootId}_events`,
|
|
15447
|
+
rootId: newRootId,
|
|
15448
|
+
phase: "input",
|
|
15449
|
+
system: true
|
|
15450
|
+
}
|
|
15451
|
+
);
|
|
15230
15452
|
const unregisterFrustum = scheduler.register(
|
|
15231
15453
|
() => {
|
|
15232
15454
|
const state2 = store.getState();
|
|
@@ -15261,7 +15483,7 @@ function createRoot(canvas) {
|
|
|
15261
15483
|
const userHandlesRender = scheduler.hasUserJobsInPhase("render", newRootId);
|
|
15262
15484
|
if (userHandlesRender || state2.internal.priority) return;
|
|
15263
15485
|
try {
|
|
15264
|
-
if (state2.
|
|
15486
|
+
if (state2.renderPipeline?.render) state2.renderPipeline.render();
|
|
15265
15487
|
else if (renderer2?.render) renderer2.render(state2.scene, state2.camera);
|
|
15266
15488
|
} catch (error) {
|
|
15267
15489
|
state2.setError(error instanceof Error ? error : new Error(String(error)));
|
|
@@ -15286,6 +15508,7 @@ function createRoot(canvas) {
|
|
|
15286
15508
|
unregisterRoot: () => {
|
|
15287
15509
|
unregisterRoot();
|
|
15288
15510
|
unregisterCanvasTarget();
|
|
15511
|
+
unregisterEventsFlush();
|
|
15289
15512
|
unregisterFrustum();
|
|
15290
15513
|
unregisterVisibility();
|
|
15291
15514
|
unregisterRender();
|
|
@@ -15451,9 +15674,13 @@ function PortalInner({ state = {}, children, container }) {
|
|
|
15451
15674
|
const store = createWithEqualityFn((set, get) => ({ ...rest, set, get }));
|
|
15452
15675
|
const onMutate = (prev) => store.setState((state2) => inject.current(prev, state2));
|
|
15453
15676
|
onMutate(previousRoot.getState());
|
|
15454
|
-
previousRoot.subscribe(onMutate);
|
|
15455
15677
|
return store;
|
|
15456
15678
|
}, [previousRoot, container]);
|
|
15679
|
+
useIsomorphicLayoutEffect(() => {
|
|
15680
|
+
const onMutate = (prev) => usePortalStore.setState((state2) => inject.current(prev, state2));
|
|
15681
|
+
const unsubscribe = previousRoot.subscribe(onMutate);
|
|
15682
|
+
return unsubscribe;
|
|
15683
|
+
}, [previousRoot, usePortalStore]);
|
|
15457
15684
|
return (
|
|
15458
15685
|
// @ts-ignore, reconciler types are not maintained
|
|
15459
15686
|
/* @__PURE__ */ jsx(Fragment, { children: reconciler.createPortal(
|
|
@@ -15498,8 +15725,18 @@ function CanvasImpl({
|
|
|
15498
15725
|
forceEven,
|
|
15499
15726
|
...props
|
|
15500
15727
|
}) {
|
|
15501
|
-
const
|
|
15502
|
-
|
|
15728
|
+
const isRendererConfig = typeof rendererProp === "object" && rendererProp !== null && !("render" in rendererProp) && ("primaryCanvas" in rendererProp || "scheduler" in rendererProp);
|
|
15729
|
+
let primaryCanvas;
|
|
15730
|
+
let scheduler;
|
|
15731
|
+
let renderer;
|
|
15732
|
+
if (isRendererConfig) {
|
|
15733
|
+
const { primaryCanvas: pc, scheduler: sc, ...rest } = rendererProp;
|
|
15734
|
+
primaryCanvas = pc;
|
|
15735
|
+
scheduler = sc;
|
|
15736
|
+
renderer = Object.keys(rest).length > 0 ? rest : rendererProp;
|
|
15737
|
+
} else {
|
|
15738
|
+
renderer = rendererProp;
|
|
15739
|
+
}
|
|
15503
15740
|
React.useMemo(() => extend(THREE), []);
|
|
15504
15741
|
const Bridge = useBridge();
|
|
15505
15742
|
const backgroundProps = React.useMemo(() => {
|
|
@@ -15674,6 +15911,7 @@ function CanvasImpl({
|
|
|
15674
15911
|
queueMicrotask(() => {
|
|
15675
15912
|
const rootEntry = _roots.get(canvas);
|
|
15676
15913
|
if (rootEntry?.store) {
|
|
15914
|
+
console.log("[R3F] HMR detected \u2014 rebuilding nodes/uniforms");
|
|
15677
15915
|
rootEntry.store.setState((state) => ({
|
|
15678
15916
|
nodes: {},
|
|
15679
15917
|
uniforms: {},
|
|
@@ -15685,8 +15923,7 @@ function CanvasImpl({
|
|
|
15685
15923
|
if (typeof import.meta !== "undefined" && import.meta.hot) {
|
|
15686
15924
|
const hot = import.meta.hot;
|
|
15687
15925
|
hot.on("vite:afterUpdate", handleHMR);
|
|
15688
|
-
return () => hot.
|
|
15689
|
-
});
|
|
15926
|
+
return () => hot.off?.("vite:afterUpdate", handleHMR);
|
|
15690
15927
|
}
|
|
15691
15928
|
if (typeof module !== "undefined" && module.hot) {
|
|
15692
15929
|
const hot = module.hot;
|
|
@@ -15709,7 +15946,16 @@ function CanvasImpl({
|
|
|
15709
15946
|
...style
|
|
15710
15947
|
},
|
|
15711
15948
|
...props,
|
|
15712
|
-
children: /* @__PURE__ */ jsx("div", { ref: containerRef, className: "r3f-canvas-container", style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ jsx(
|
|
15949
|
+
children: /* @__PURE__ */ jsx("div", { ref: containerRef, className: "r3f-canvas-container", style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ jsx(
|
|
15950
|
+
"canvas",
|
|
15951
|
+
{
|
|
15952
|
+
ref: canvasRef,
|
|
15953
|
+
id,
|
|
15954
|
+
className: "r3f-canvas",
|
|
15955
|
+
style: { display: "block", width: "100%", height: "100%" },
|
|
15956
|
+
children: fallback
|
|
15957
|
+
}
|
|
15958
|
+
) })
|
|
15713
15959
|
}
|
|
15714
15960
|
);
|
|
15715
15961
|
}
|