@react-three/fiber 10.0.0-canary.604355a → 10.0.0-canary.9806389
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 +487 -226
- 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 +488 -227
- package/dist/legacy.cjs +481 -226
- 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 +482 -227
- package/dist/webgpu/index.cjs +891 -248
- 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 +888 -249
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -160,7 +160,7 @@ function useEnvironment({
|
|
|
160
160
|
fiber.useLoader.clear(loader, multiFile ? [files] : files);
|
|
161
161
|
}
|
|
162
162
|
renderer.domElement.addEventListener("webglcontextlost", clearGainmapTexture, { once: true });
|
|
163
|
-
}, [files, renderer.domElement]);
|
|
163
|
+
}, [extension, files, loader, multiFile, renderer.domElement]);
|
|
164
164
|
const loaderResult = fiber.useLoader(
|
|
165
165
|
loader,
|
|
166
166
|
multiFile ? [files] : files,
|
|
@@ -360,7 +360,22 @@ function EnvironmentPortal({
|
|
|
360
360
|
environmentIntensity,
|
|
361
361
|
environmentRotation
|
|
362
362
|
});
|
|
363
|
-
}, [
|
|
363
|
+
}, [
|
|
364
|
+
children,
|
|
365
|
+
virtualScene,
|
|
366
|
+
fbo.texture,
|
|
367
|
+
scene,
|
|
368
|
+
defaultScene,
|
|
369
|
+
background,
|
|
370
|
+
frames,
|
|
371
|
+
gl,
|
|
372
|
+
blur,
|
|
373
|
+
backgroundBlurriness,
|
|
374
|
+
backgroundIntensity,
|
|
375
|
+
backgroundRotation,
|
|
376
|
+
environmentIntensity,
|
|
377
|
+
environmentRotation
|
|
378
|
+
]);
|
|
364
379
|
let count = 1;
|
|
365
380
|
fiber.useFrame(() => {
|
|
366
381
|
if (frames === Infinity || count < frames) {
|
|
@@ -996,6 +1011,9 @@ function applyProps(object, props) {
|
|
|
996
1011
|
else target.set(value);
|
|
997
1012
|
} else {
|
|
998
1013
|
root[key] = value;
|
|
1014
|
+
if (key.endsWith("Node") && root.isMaterial) {
|
|
1015
|
+
root.needsUpdate = true;
|
|
1016
|
+
}
|
|
999
1017
|
if (rootState && rootState.renderer?.outputColorSpace === webgpu.SRGBColorSpace && colorMaps.includes(key) && isTexture(value) && root[key]?.isTexture && // sRGB textures must be RGBA8 since r137 https://github.com/mrdoob/three.js/pull/23129
|
|
1000
1018
|
root[key].format === webgpu.RGBAFormat && root[key].type === webgpu.UnsignedByteType) {
|
|
1001
1019
|
root[key].colorSpace = rootState.textureColorSpace;
|
|
@@ -1029,38 +1047,60 @@ function applyProps(object, props) {
|
|
|
1029
1047
|
return object;
|
|
1030
1048
|
}
|
|
1031
1049
|
|
|
1050
|
+
const DEFAULT_POINTER_ID = 0;
|
|
1051
|
+
const XR_POINTER_ID_START = 1e3;
|
|
1052
|
+
function getPointerState(internal, pointerId) {
|
|
1053
|
+
let state = internal.pointerMap.get(pointerId);
|
|
1054
|
+
if (!state) {
|
|
1055
|
+
state = {
|
|
1056
|
+
hovered: /* @__PURE__ */ new Map(),
|
|
1057
|
+
captured: /* @__PURE__ */ new Map(),
|
|
1058
|
+
initialClick: [0, 0],
|
|
1059
|
+
initialHits: []
|
|
1060
|
+
};
|
|
1061
|
+
internal.pointerMap.set(pointerId, state);
|
|
1062
|
+
}
|
|
1063
|
+
return state;
|
|
1064
|
+
}
|
|
1065
|
+
function getPointerId(event) {
|
|
1066
|
+
return "pointerId" in event ? event.pointerId : DEFAULT_POINTER_ID;
|
|
1067
|
+
}
|
|
1032
1068
|
function makeId(event) {
|
|
1033
1069
|
return (event.eventObject || event.object).uuid + "/" + event.index + event.instanceId;
|
|
1034
1070
|
}
|
|
1035
|
-
function releaseInternalPointerCapture(
|
|
1036
|
-
const
|
|
1071
|
+
function releaseInternalPointerCapture(internal, obj, pointerId) {
|
|
1072
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1073
|
+
if (!pointerState) return;
|
|
1074
|
+
const captureData = pointerState.captured.get(obj);
|
|
1037
1075
|
if (captureData) {
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
capturedMap.delete(pointerId);
|
|
1041
|
-
captureData.target.releasePointerCapture(pointerId);
|
|
1042
|
-
}
|
|
1076
|
+
pointerState.captured.delete(obj);
|
|
1077
|
+
captureData.target.releasePointerCapture(pointerId);
|
|
1043
1078
|
}
|
|
1044
1079
|
}
|
|
1045
1080
|
function removeInteractivity(store, object) {
|
|
1046
1081
|
const { internal } = store.getState();
|
|
1047
1082
|
internal.interaction = internal.interaction.filter((o) => o !== object);
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1083
|
+
for (const [pointerId, pointerState] of internal.pointerMap) {
|
|
1084
|
+
pointerState.initialHits = pointerState.initialHits.filter((o) => o !== object);
|
|
1085
|
+
pointerState.hovered.forEach((value, key) => {
|
|
1086
|
+
if (value.eventObject === object || value.object === object) {
|
|
1087
|
+
pointerState.hovered.delete(key);
|
|
1088
|
+
}
|
|
1089
|
+
});
|
|
1090
|
+
if (pointerState.captured.has(object)) {
|
|
1091
|
+
releaseInternalPointerCapture(internal, object, pointerId);
|
|
1052
1092
|
}
|
|
1053
|
-
}
|
|
1054
|
-
internal.capturedMap.forEach((captures, pointerId) => {
|
|
1055
|
-
releaseInternalPointerCapture(internal.capturedMap, object, captures, pointerId);
|
|
1056
|
-
});
|
|
1093
|
+
}
|
|
1057
1094
|
unregisterVisibility(store, object);
|
|
1058
1095
|
}
|
|
1059
1096
|
function createEvents(store) {
|
|
1060
|
-
function calculateDistance(event) {
|
|
1097
|
+
function calculateDistance(event, pointerId) {
|
|
1061
1098
|
const { internal } = store.getState();
|
|
1062
|
-
const
|
|
1063
|
-
|
|
1099
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1100
|
+
if (!pointerState) return 0;
|
|
1101
|
+
const [initialX, initialY] = pointerState.initialClick;
|
|
1102
|
+
const dx = event.offsetX - initialX;
|
|
1103
|
+
const dy = event.offsetY - initialY;
|
|
1064
1104
|
return Math.round(Math.sqrt(dx * dx + dy * dy));
|
|
1065
1105
|
}
|
|
1066
1106
|
function filterPointerEvents(objects) {
|
|
@@ -1096,6 +1136,15 @@ function createEvents(store) {
|
|
|
1096
1136
|
return state2.raycaster.camera ? state2.raycaster.intersectObject(obj, true) : [];
|
|
1097
1137
|
}
|
|
1098
1138
|
let hits = eventsObjects.flatMap(handleRaycast).sort((a, b) => {
|
|
1139
|
+
const aInteractivePriority = a.object.userData?.interactivePriority;
|
|
1140
|
+
const bInteractivePriority = b.object.userData?.interactivePriority;
|
|
1141
|
+
if (aInteractivePriority !== void 0 || bInteractivePriority !== void 0) {
|
|
1142
|
+
if (aInteractivePriority !== void 0 && bInteractivePriority === void 0) return -1;
|
|
1143
|
+
if (bInteractivePriority !== void 0 && aInteractivePriority === void 0) return 1;
|
|
1144
|
+
if (aInteractivePriority !== bInteractivePriority) {
|
|
1145
|
+
return (bInteractivePriority ?? 0) - (aInteractivePriority ?? 0);
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1099
1148
|
const aState = getRootState(a.object);
|
|
1100
1149
|
const bState = getRootState(b.object);
|
|
1101
1150
|
const aPriority = aState?.events?.priority ?? 1;
|
|
@@ -1117,9 +1166,13 @@ function createEvents(store) {
|
|
|
1117
1166
|
eventObject = eventObject.parent;
|
|
1118
1167
|
}
|
|
1119
1168
|
}
|
|
1120
|
-
if ("pointerId" in event
|
|
1121
|
-
|
|
1122
|
-
|
|
1169
|
+
if ("pointerId" in event) {
|
|
1170
|
+
const pointerId = event.pointerId;
|
|
1171
|
+
const pointerState = state.internal.pointerMap.get(pointerId);
|
|
1172
|
+
if (pointerState?.captured.size) {
|
|
1173
|
+
for (const captureData of pointerState.captured.values()) {
|
|
1174
|
+
if (!duplicates.has(makeId(captureData.intersection))) intersections.push(captureData.intersection);
|
|
1175
|
+
}
|
|
1123
1176
|
}
|
|
1124
1177
|
}
|
|
1125
1178
|
return intersections;
|
|
@@ -1132,27 +1185,25 @@ function createEvents(store) {
|
|
|
1132
1185
|
if (state) {
|
|
1133
1186
|
const { raycaster, pointer, camera, internal } = state;
|
|
1134
1187
|
const unprojectedPoint = new webgpu.Vector3(pointer.x, pointer.y, 0).unproject(camera);
|
|
1135
|
-
const hasPointerCapture = (id) =>
|
|
1188
|
+
const hasPointerCapture = (id) => {
|
|
1189
|
+
const pointerState = internal.pointerMap.get(id);
|
|
1190
|
+
return pointerState?.captured.has(hit.eventObject) ?? false;
|
|
1191
|
+
};
|
|
1136
1192
|
const setPointerCapture = (id) => {
|
|
1137
1193
|
const captureData = { intersection: hit, target: event.target };
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
} else {
|
|
1141
|
-
internal.capturedMap.set(id, /* @__PURE__ */ new Map([[hit.eventObject, captureData]]));
|
|
1142
|
-
}
|
|
1194
|
+
const pointerState = getPointerState(internal, id);
|
|
1195
|
+
pointerState.captured.set(hit.eventObject, captureData);
|
|
1143
1196
|
event.target.setPointerCapture(id);
|
|
1144
1197
|
};
|
|
1145
1198
|
const releasePointerCapture = (id) => {
|
|
1146
|
-
|
|
1147
|
-
if (captures) {
|
|
1148
|
-
releaseInternalPointerCapture(internal.capturedMap, hit.eventObject, captures, id);
|
|
1149
|
-
}
|
|
1199
|
+
releaseInternalPointerCapture(internal, hit.eventObject, id);
|
|
1150
1200
|
};
|
|
1151
1201
|
const extractEventProps = {};
|
|
1152
1202
|
for (const prop in event) {
|
|
1153
1203
|
const property = event[prop];
|
|
1154
1204
|
if (typeof property !== "function") extractEventProps[prop] = property;
|
|
1155
1205
|
}
|
|
1206
|
+
const eventPointerId = "pointerId" in event ? event.pointerId : void 0;
|
|
1156
1207
|
const raycastEvent = {
|
|
1157
1208
|
...hit,
|
|
1158
1209
|
...extractEventProps,
|
|
@@ -1163,18 +1214,19 @@ function createEvents(store) {
|
|
|
1163
1214
|
unprojectedPoint,
|
|
1164
1215
|
ray: raycaster.ray,
|
|
1165
1216
|
camera,
|
|
1217
|
+
pointerId: eventPointerId,
|
|
1166
1218
|
// Hijack stopPropagation, which just sets a flag
|
|
1167
1219
|
stopPropagation() {
|
|
1168
|
-
const
|
|
1220
|
+
const pointerState = eventPointerId !== void 0 ? internal.pointerMap.get(eventPointerId) : void 0;
|
|
1169
1221
|
if (
|
|
1170
1222
|
// ...if this pointer hasn't been captured
|
|
1171
|
-
!
|
|
1172
|
-
|
|
1223
|
+
!pointerState?.captured.size || // ... or if the hit object is capturing the pointer
|
|
1224
|
+
pointerState.captured.has(hit.eventObject)
|
|
1173
1225
|
) {
|
|
1174
1226
|
raycastEvent.stopped = localState.stopped = true;
|
|
1175
|
-
if (
|
|
1227
|
+
if (pointerState?.hovered.size && Array.from(pointerState.hovered.values()).find((i) => i.eventObject === hit.eventObject)) {
|
|
1176
1228
|
const higher = intersections.slice(0, intersections.indexOf(hit));
|
|
1177
|
-
cancelPointer([...higher, hit]);
|
|
1229
|
+
cancelPointer([...higher, hit], eventPointerId);
|
|
1178
1230
|
}
|
|
1179
1231
|
}
|
|
1180
1232
|
},
|
|
@@ -1190,15 +1242,18 @@ function createEvents(store) {
|
|
|
1190
1242
|
}
|
|
1191
1243
|
return intersections;
|
|
1192
1244
|
}
|
|
1193
|
-
function cancelPointer(intersections) {
|
|
1245
|
+
function cancelPointer(intersections, pointerId) {
|
|
1194
1246
|
const { internal } = store.getState();
|
|
1195
|
-
|
|
1247
|
+
const pid = pointerId ?? DEFAULT_POINTER_ID;
|
|
1248
|
+
const pointerState = internal.pointerMap.get(pid);
|
|
1249
|
+
if (!pointerState) return;
|
|
1250
|
+
for (const [hoveredId, hoveredObj] of pointerState.hovered) {
|
|
1196
1251
|
if (!intersections.length || !intersections.find(
|
|
1197
1252
|
(hit) => hit.object === hoveredObj.object && hit.index === hoveredObj.index && hit.instanceId === hoveredObj.instanceId
|
|
1198
1253
|
)) {
|
|
1199
1254
|
const eventObject = hoveredObj.eventObject;
|
|
1200
1255
|
const instance = eventObject.__r3f;
|
|
1201
|
-
|
|
1256
|
+
pointerState.hovered.delete(hoveredId);
|
|
1202
1257
|
if (instance?.eventCount) {
|
|
1203
1258
|
const handlers = instance.handlers;
|
|
1204
1259
|
const data = { ...hoveredObj, intersections };
|
|
@@ -1227,41 +1282,118 @@ function createEvents(store) {
|
|
|
1227
1282
|
instance?.handlers.onDropMissed?.(event);
|
|
1228
1283
|
}
|
|
1229
1284
|
}
|
|
1285
|
+
function cleanupPointer(pointerId) {
|
|
1286
|
+
const { internal } = store.getState();
|
|
1287
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1288
|
+
if (pointerState) {
|
|
1289
|
+
for (const [, hoveredObj] of pointerState.hovered) {
|
|
1290
|
+
const eventObject = hoveredObj.eventObject;
|
|
1291
|
+
const instance = eventObject.__r3f;
|
|
1292
|
+
if (instance?.eventCount) {
|
|
1293
|
+
const handlers = instance.handlers;
|
|
1294
|
+
const data = { ...hoveredObj, intersections: [] };
|
|
1295
|
+
handlers.onPointerOut?.(data);
|
|
1296
|
+
handlers.onPointerLeave?.(data);
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
internal.pointerMap.delete(pointerId);
|
|
1300
|
+
}
|
|
1301
|
+
internal.pointerDirty.delete(pointerId);
|
|
1302
|
+
}
|
|
1303
|
+
function processDeferredPointer(event, pointerId) {
|
|
1304
|
+
const state = store.getState();
|
|
1305
|
+
const { internal } = state;
|
|
1306
|
+
if (!state.events.enabled) return;
|
|
1307
|
+
const filter = filterPointerEvents;
|
|
1308
|
+
const hits = intersect(event, filter);
|
|
1309
|
+
cancelPointer(hits, pointerId);
|
|
1310
|
+
function onIntersect(data) {
|
|
1311
|
+
const eventObject = data.eventObject;
|
|
1312
|
+
const instance = eventObject.__r3f;
|
|
1313
|
+
if (!instance?.eventCount) return;
|
|
1314
|
+
const handlers = instance.handlers;
|
|
1315
|
+
if (handlers.onPointerOver || handlers.onPointerEnter || handlers.onPointerOut || handlers.onPointerLeave) {
|
|
1316
|
+
const id = makeId(data);
|
|
1317
|
+
const pointerState = getPointerState(internal, pointerId);
|
|
1318
|
+
const hoveredItem = pointerState.hovered.get(id);
|
|
1319
|
+
if (!hoveredItem) {
|
|
1320
|
+
pointerState.hovered.set(id, data);
|
|
1321
|
+
handlers.onPointerOver?.(data);
|
|
1322
|
+
handlers.onPointerEnter?.(data);
|
|
1323
|
+
} else if (hoveredItem.stopped) {
|
|
1324
|
+
data.stopPropagation();
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
handlers.onPointerMove?.(data);
|
|
1328
|
+
}
|
|
1329
|
+
handleIntersects(hits, event, 0, onIntersect);
|
|
1330
|
+
}
|
|
1230
1331
|
function handlePointer(name) {
|
|
1231
1332
|
switch (name) {
|
|
1232
1333
|
case "onPointerLeave":
|
|
1233
|
-
case "onPointerCancel":
|
|
1234
1334
|
case "onDragLeave":
|
|
1235
1335
|
return () => cancelPointer([]);
|
|
1336
|
+
// Global cancel of these events
|
|
1337
|
+
case "onPointerCancel":
|
|
1338
|
+
return (event) => {
|
|
1339
|
+
const pointerId = getPointerId(event);
|
|
1340
|
+
cleanupPointer(pointerId);
|
|
1341
|
+
};
|
|
1236
1342
|
case "onLostPointerCapture":
|
|
1237
1343
|
return (event) => {
|
|
1238
1344
|
const { internal } = store.getState();
|
|
1239
|
-
|
|
1345
|
+
const pointerId = getPointerId(event);
|
|
1346
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1347
|
+
if (pointerState?.captured.size) {
|
|
1240
1348
|
requestAnimationFrame(() => {
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1349
|
+
const pointerState2 = internal.pointerMap.get(pointerId);
|
|
1350
|
+
if (pointerState2?.captured.size) {
|
|
1351
|
+
pointerState2.captured.clear();
|
|
1244
1352
|
}
|
|
1353
|
+
cancelPointer([], pointerId);
|
|
1245
1354
|
});
|
|
1246
1355
|
}
|
|
1247
1356
|
};
|
|
1248
1357
|
}
|
|
1249
1358
|
return function handleEvent(event) {
|
|
1250
1359
|
const state = store.getState();
|
|
1251
|
-
const { onPointerMissed, onDragOverMissed, onDropMissed, internal } = state;
|
|
1360
|
+
const { onPointerMissed, onDragOverMissed, onDropMissed, internal, events } = state;
|
|
1361
|
+
const pointerId = getPointerId(event);
|
|
1252
1362
|
internal.lastEvent.current = event;
|
|
1253
|
-
if (!
|
|
1363
|
+
if (!events.enabled) return;
|
|
1254
1364
|
const isPointerMove = name === "onPointerMove";
|
|
1255
1365
|
const isDragOver = name === "onDragOver";
|
|
1256
1366
|
const isDrop = name === "onDrop";
|
|
1257
1367
|
const isClickEvent = name === "onClick" || name === "onContextMenu" || name === "onDoubleClick";
|
|
1368
|
+
const isPointerDown = name === "onPointerDown";
|
|
1369
|
+
const isPointerUp = name === "onPointerUp";
|
|
1370
|
+
const isWheel = name === "onWheel";
|
|
1371
|
+
const canDeferRaycasts = events.frameTimedRaycasts && state.frameloop === "always";
|
|
1372
|
+
if (isPointerMove && canDeferRaycasts) {
|
|
1373
|
+
events.compute?.(event, state);
|
|
1374
|
+
internal.pointerDirty.set(pointerId, event);
|
|
1375
|
+
return;
|
|
1376
|
+
}
|
|
1377
|
+
if (isWheel && canDeferRaycasts && !events.alwaysFireOnScroll) {
|
|
1378
|
+
events.compute?.(event, state);
|
|
1379
|
+
internal.pointerDirty.set(pointerId, event);
|
|
1380
|
+
return;
|
|
1381
|
+
}
|
|
1382
|
+
if ((isClickEvent || isPointerDown || isPointerUp) && internal.pointerDirty.has(pointerId)) {
|
|
1383
|
+
const deferredEvent = internal.pointerDirty.get(pointerId);
|
|
1384
|
+
internal.pointerDirty.delete(pointerId);
|
|
1385
|
+
processDeferredPointer(deferredEvent, pointerId);
|
|
1386
|
+
}
|
|
1258
1387
|
const filter = isPointerMove || isDragOver || isDrop ? filterPointerEvents : void 0;
|
|
1259
1388
|
const hits = intersect(event, filter);
|
|
1260
|
-
const delta = isClickEvent ? calculateDistance(event) : 0;
|
|
1261
|
-
if (
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1389
|
+
const delta = isClickEvent ? calculateDistance(event, pointerId) : 0;
|
|
1390
|
+
if (isPointerDown) {
|
|
1391
|
+
const pointerState2 = getPointerState(internal, pointerId);
|
|
1392
|
+
pointerState2.initialClick = [event.offsetX, event.offsetY];
|
|
1393
|
+
pointerState2.initialHits = hits.map((hit) => hit.eventObject);
|
|
1394
|
+
}
|
|
1395
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1396
|
+
const initialHits = pointerState?.initialHits ?? [];
|
|
1265
1397
|
if (isClickEvent && !hits.length) {
|
|
1266
1398
|
if (delta <= 2) {
|
|
1267
1399
|
pointerMissed(event, internal.interaction);
|
|
@@ -1276,7 +1408,9 @@ function createEvents(store) {
|
|
|
1276
1408
|
dropMissed(event, internal.interaction);
|
|
1277
1409
|
if (onDropMissed) onDropMissed(event);
|
|
1278
1410
|
}
|
|
1279
|
-
if (isPointerMove || isDragOver)
|
|
1411
|
+
if (isPointerMove || isDragOver) {
|
|
1412
|
+
cancelPointer(hits, pointerId);
|
|
1413
|
+
}
|
|
1280
1414
|
function onIntersect(data) {
|
|
1281
1415
|
const eventObject = data.eventObject;
|
|
1282
1416
|
const instance = eventObject.__r3f;
|
|
@@ -1285,9 +1419,10 @@ function createEvents(store) {
|
|
|
1285
1419
|
if (isPointerMove) {
|
|
1286
1420
|
if (handlers.onPointerOver || handlers.onPointerEnter || handlers.onPointerOut || handlers.onPointerLeave) {
|
|
1287
1421
|
const id = makeId(data);
|
|
1288
|
-
const
|
|
1422
|
+
const pointerState2 = getPointerState(internal, pointerId);
|
|
1423
|
+
const hoveredItem = pointerState2.hovered.get(id);
|
|
1289
1424
|
if (!hoveredItem) {
|
|
1290
|
-
|
|
1425
|
+
pointerState2.hovered.set(id, data);
|
|
1291
1426
|
handlers.onPointerOver?.(data);
|
|
1292
1427
|
handlers.onPointerEnter?.(data);
|
|
1293
1428
|
} else if (hoveredItem.stopped) {
|
|
@@ -1297,9 +1432,10 @@ function createEvents(store) {
|
|
|
1297
1432
|
handlers.onPointerMove?.(data);
|
|
1298
1433
|
} else if (isDragOver) {
|
|
1299
1434
|
const id = makeId(data);
|
|
1300
|
-
const
|
|
1435
|
+
const pointerState2 = getPointerState(internal, pointerId);
|
|
1436
|
+
const hoveredItem = pointerState2.hovered.get(id);
|
|
1301
1437
|
if (!hoveredItem) {
|
|
1302
|
-
|
|
1438
|
+
pointerState2.hovered.set(id, data);
|
|
1303
1439
|
handlers.onDragOverEnter?.(data);
|
|
1304
1440
|
} else if (hoveredItem.stopped) {
|
|
1305
1441
|
data.stopPropagation();
|
|
@@ -1310,18 +1446,18 @@ function createEvents(store) {
|
|
|
1310
1446
|
} else {
|
|
1311
1447
|
const handler = handlers[name];
|
|
1312
1448
|
if (handler) {
|
|
1313
|
-
if (!isClickEvent ||
|
|
1449
|
+
if (!isClickEvent || initialHits.includes(eventObject)) {
|
|
1314
1450
|
pointerMissed(
|
|
1315
1451
|
event,
|
|
1316
|
-
internal.interaction.filter((object) => !
|
|
1452
|
+
internal.interaction.filter((object) => !initialHits.includes(object))
|
|
1317
1453
|
);
|
|
1318
1454
|
handler(data);
|
|
1319
1455
|
}
|
|
1320
1456
|
} else {
|
|
1321
|
-
if (isClickEvent &&
|
|
1457
|
+
if (isClickEvent && initialHits.includes(eventObject)) {
|
|
1322
1458
|
pointerMissed(
|
|
1323
1459
|
event,
|
|
1324
|
-
internal.interaction.filter((object) => !
|
|
1460
|
+
internal.interaction.filter((object) => !initialHits.includes(object))
|
|
1325
1461
|
);
|
|
1326
1462
|
}
|
|
1327
1463
|
}
|
|
@@ -1330,7 +1466,15 @@ function createEvents(store) {
|
|
|
1330
1466
|
handleIntersects(hits, event, delta, onIntersect);
|
|
1331
1467
|
};
|
|
1332
1468
|
}
|
|
1333
|
-
|
|
1469
|
+
function flushDeferredPointers() {
|
|
1470
|
+
const { internal, events } = store.getState();
|
|
1471
|
+
if (!events.frameTimedRaycasts) return;
|
|
1472
|
+
for (const [pointerId, event] of internal.pointerDirty) {
|
|
1473
|
+
processDeferredPointer(event, pointerId);
|
|
1474
|
+
}
|
|
1475
|
+
internal.pointerDirty.clear();
|
|
1476
|
+
}
|
|
1477
|
+
return { handlePointer, flushDeferredPointers, processDeferredPointer };
|
|
1334
1478
|
}
|
|
1335
1479
|
const DOM_EVENTS = {
|
|
1336
1480
|
onClick: ["click", false],
|
|
@@ -1349,10 +1493,15 @@ const DOM_EVENTS = {
|
|
|
1349
1493
|
onLostPointerCapture: ["lostpointercapture", true]
|
|
1350
1494
|
};
|
|
1351
1495
|
function createPointerEvents(store) {
|
|
1352
|
-
const { handlePointer } = createEvents(store);
|
|
1496
|
+
const { handlePointer, flushDeferredPointers, processDeferredPointer } = createEvents(store);
|
|
1497
|
+
let nextXRPointerId = XR_POINTER_ID_START;
|
|
1498
|
+
const xrPointers = /* @__PURE__ */ new Map();
|
|
1353
1499
|
return {
|
|
1354
1500
|
priority: 1,
|
|
1355
1501
|
enabled: true,
|
|
1502
|
+
frameTimedRaycasts: true,
|
|
1503
|
+
alwaysFireOnScroll: true,
|
|
1504
|
+
updateOnFrame: false,
|
|
1356
1505
|
compute(event, state) {
|
|
1357
1506
|
state.pointer.set(event.offsetX / state.size.width * 2 - 1, -(event.offsetY / state.size.height) * 2 + 1);
|
|
1358
1507
|
state.raycaster.setFromCamera(state.pointer, state.camera);
|
|
@@ -1362,11 +1511,33 @@ function createPointerEvents(store) {
|
|
|
1362
1511
|
(acc, key) => ({ ...acc, [key]: handlePointer(key) }),
|
|
1363
1512
|
{}
|
|
1364
1513
|
),
|
|
1365
|
-
update: () => {
|
|
1514
|
+
update: (pointerId) => {
|
|
1366
1515
|
const { events, internal } = store.getState();
|
|
1367
|
-
if (
|
|
1516
|
+
if (!events.handlers) return;
|
|
1517
|
+
if (pointerId !== void 0) {
|
|
1518
|
+
const event = internal.pointerDirty.get(pointerId);
|
|
1519
|
+
if (event) {
|
|
1520
|
+
internal.pointerDirty.delete(pointerId);
|
|
1521
|
+
processDeferredPointer(event, pointerId);
|
|
1522
|
+
} else if (internal.lastEvent?.current) {
|
|
1523
|
+
processDeferredPointer(internal.lastEvent.current, pointerId);
|
|
1524
|
+
}
|
|
1525
|
+
} else {
|
|
1526
|
+
flushDeferredPointers();
|
|
1527
|
+
if (internal.lastEvent?.current) {
|
|
1528
|
+
events.handlers.onPointerMove(internal.lastEvent.current);
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
},
|
|
1532
|
+
flush: () => {
|
|
1533
|
+
const { events, internal } = store.getState();
|
|
1534
|
+
flushDeferredPointers();
|
|
1535
|
+
if (events.updateOnFrame && internal.lastEvent?.current && events.handlers) {
|
|
1536
|
+
events.handlers.onPointerMove(internal.lastEvent.current);
|
|
1537
|
+
}
|
|
1368
1538
|
},
|
|
1369
1539
|
connect: (target) => {
|
|
1540
|
+
if (!target) return;
|
|
1370
1541
|
const { set, events } = store.getState();
|
|
1371
1542
|
events.disconnect?.();
|
|
1372
1543
|
set((state) => ({ events: { ...state.events, connected: target } }));
|
|
@@ -1390,6 +1561,32 @@ function createPointerEvents(store) {
|
|
|
1390
1561
|
}
|
|
1391
1562
|
set((state) => ({ events: { ...state.events, connected: void 0 } }));
|
|
1392
1563
|
}
|
|
1564
|
+
},
|
|
1565
|
+
registerPointer: (config) => {
|
|
1566
|
+
const pointerId = nextXRPointerId++;
|
|
1567
|
+
xrPointers.set(pointerId, config);
|
|
1568
|
+
const { internal } = store.getState();
|
|
1569
|
+
getPointerState(internal, pointerId);
|
|
1570
|
+
return pointerId;
|
|
1571
|
+
},
|
|
1572
|
+
unregisterPointer: (pointerId) => {
|
|
1573
|
+
xrPointers.delete(pointerId);
|
|
1574
|
+
const { internal } = store.getState();
|
|
1575
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1576
|
+
if (pointerState) {
|
|
1577
|
+
for (const [, hoveredObj] of pointerState.hovered) {
|
|
1578
|
+
const eventObject = hoveredObj.eventObject;
|
|
1579
|
+
const instance = eventObject.__r3f;
|
|
1580
|
+
if (instance?.eventCount) {
|
|
1581
|
+
const handlers = instance.handlers;
|
|
1582
|
+
const data = { ...hoveredObj, intersections: [] };
|
|
1583
|
+
handlers.onPointerOut?.(data);
|
|
1584
|
+
handlers.onPointerLeave?.(data);
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
internal.pointerMap.delete(pointerId);
|
|
1588
|
+
}
|
|
1589
|
+
internal.pointerDirty.delete(pointerId);
|
|
1393
1590
|
}
|
|
1394
1591
|
};
|
|
1395
1592
|
}
|
|
@@ -1703,7 +1900,7 @@ function shouldRun(job, now) {
|
|
|
1703
1900
|
const minInterval = 1e3 / job.fps;
|
|
1704
1901
|
const lastRun = job.lastRun ?? 0;
|
|
1705
1902
|
const elapsed = now - lastRun;
|
|
1706
|
-
if (elapsed < minInterval) return false;
|
|
1903
|
+
if (elapsed < minInterval - 1) return false;
|
|
1707
1904
|
if (job.drop) {
|
|
1708
1905
|
job.lastRun = now;
|
|
1709
1906
|
} else {
|
|
@@ -2520,7 +2717,14 @@ const createStore = (invalidate, advance) => {
|
|
|
2520
2717
|
frustum: new webgpu.Frustum(),
|
|
2521
2718
|
autoUpdateFrustum: true,
|
|
2522
2719
|
raycaster: null,
|
|
2523
|
-
events: {
|
|
2720
|
+
events: {
|
|
2721
|
+
priority: 1,
|
|
2722
|
+
enabled: true,
|
|
2723
|
+
connected: false,
|
|
2724
|
+
frameTimedRaycasts: true,
|
|
2725
|
+
alwaysFireOnScroll: true,
|
|
2726
|
+
updateOnFrame: false
|
|
2727
|
+
},
|
|
2524
2728
|
scene: null,
|
|
2525
2729
|
rootScene: null,
|
|
2526
2730
|
xr: null,
|
|
@@ -2611,11 +2815,14 @@ const createStore = (invalidate, advance) => {
|
|
|
2611
2815
|
},
|
|
2612
2816
|
setError: (error) => set(() => ({ error })),
|
|
2613
2817
|
error: null,
|
|
2614
|
-
//* TSL State (managed via hooks: useUniforms, useNodes, useTextures,
|
|
2818
|
+
//* TSL State (managed via hooks: useUniforms, useNodes, useBuffers, useGPUStorage, useTextures, useRenderPipeline) ==============================
|
|
2615
2819
|
uniforms: {},
|
|
2616
2820
|
nodes: {},
|
|
2821
|
+
buffers: {},
|
|
2822
|
+
gpuStorage: {},
|
|
2617
2823
|
textures: /* @__PURE__ */ new Map(),
|
|
2618
|
-
|
|
2824
|
+
_textureRefs: /* @__PURE__ */ new Map(),
|
|
2825
|
+
renderPipeline: null,
|
|
2619
2826
|
passes: {},
|
|
2620
2827
|
_hmrVersion: 0,
|
|
2621
2828
|
_sizeImperative: false,
|
|
@@ -2624,12 +2831,16 @@ const createStore = (invalidate, advance) => {
|
|
|
2624
2831
|
internal: {
|
|
2625
2832
|
// Events
|
|
2626
2833
|
interaction: [],
|
|
2627
|
-
hovered: /* @__PURE__ */ new Map(),
|
|
2628
2834
|
subscribers: [],
|
|
2835
|
+
// Per-pointer state (new unified structure)
|
|
2836
|
+
pointerMap: /* @__PURE__ */ new Map(),
|
|
2837
|
+
pointerDirty: /* @__PURE__ */ new Map(),
|
|
2838
|
+
lastEvent: React__namespace.createRef(),
|
|
2839
|
+
// Deprecated but kept for backwards compatibility
|
|
2840
|
+
hovered: /* @__PURE__ */ new Map(),
|
|
2629
2841
|
initialClick: [0, 0],
|
|
2630
2842
|
initialHits: [],
|
|
2631
2843
|
capturedMap: /* @__PURE__ */ new Map(),
|
|
2632
|
-
lastEvent: React__namespace.createRef(),
|
|
2633
2844
|
// Visibility tracking (onFramed, onOccluded, onVisible)
|
|
2634
2845
|
visibilityRegistry: /* @__PURE__ */ new Map(),
|
|
2635
2846
|
// Occlusion system (WebGPU only)
|
|
@@ -2717,14 +2928,16 @@ const createStore = (invalidate, advance) => {
|
|
|
2717
2928
|
oldSize = size;
|
|
2718
2929
|
oldDpr = viewport.dpr;
|
|
2719
2930
|
updateCamera(camera, size);
|
|
2720
|
-
if (canvasTarget) {
|
|
2931
|
+
if (internal.isSecondary && canvasTarget) {
|
|
2721
2932
|
if (viewport.dpr > 0) canvasTarget.setPixelRatio(viewport.dpr);
|
|
2722
|
-
|
|
2723
|
-
canvasTarget.setSize(size.width, size.height, updateStyle);
|
|
2933
|
+
canvasTarget.setSize(size.width, size.height, false);
|
|
2724
2934
|
} else {
|
|
2725
2935
|
if (viewport.dpr > 0) actualRenderer.setPixelRatio(viewport.dpr);
|
|
2726
|
-
|
|
2727
|
-
|
|
2936
|
+
actualRenderer.setSize(size.width, size.height, false);
|
|
2937
|
+
if (canvasTarget) {
|
|
2938
|
+
if (viewport.dpr > 0) canvasTarget.setPixelRatio(viewport.dpr);
|
|
2939
|
+
canvasTarget.setSize(size.width, size.height, false);
|
|
2940
|
+
}
|
|
2728
2941
|
}
|
|
2729
2942
|
}
|
|
2730
2943
|
if (camera !== oldCamera) {
|
|
@@ -2972,18 +3185,18 @@ function buildFromCache(input, textureCache) {
|
|
|
2972
3185
|
function useTexture(input, optionsOrOnLoad) {
|
|
2973
3186
|
const renderer = useThree((state) => state.internal.actualRenderer);
|
|
2974
3187
|
const store = useStore();
|
|
2975
|
-
const textureCache = useThree((state) => state.textures);
|
|
2976
3188
|
const options = typeof optionsOrOnLoad === "function" ? { onLoad: optionsOrOnLoad } : optionsOrOnLoad ?? {};
|
|
2977
|
-
const { onLoad, cache =
|
|
3189
|
+
const { onLoad, cache = true } = options;
|
|
2978
3190
|
const onLoadRef = React.useRef(onLoad);
|
|
2979
3191
|
onLoadRef.current = onLoad;
|
|
2980
3192
|
const onLoadCalledForRef = React.useRef(null);
|
|
2981
3193
|
const urls = React.useMemo(() => getUrls(input), [input]);
|
|
2982
3194
|
const cachedResult = React.useMemo(() => {
|
|
2983
3195
|
if (!cache) return null;
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
3196
|
+
const textures = store.getState().textures;
|
|
3197
|
+
if (!allUrlsCached(urls, textures)) return null;
|
|
3198
|
+
return buildFromCache(input, textures);
|
|
3199
|
+
}, [cache, urls, input, store]);
|
|
2987
3200
|
const loadedTextures = useLoader(
|
|
2988
3201
|
webgpu.TextureLoader,
|
|
2989
3202
|
IsObject(input) ? Object.values(input) : input
|
|
@@ -3027,8 +3240,6 @@ function useTexture(input, optionsOrOnLoad) {
|
|
|
3027
3240
|
}, [input, loadedTextures, cachedResult]);
|
|
3028
3241
|
React.useEffect(() => {
|
|
3029
3242
|
if (!cache) return;
|
|
3030
|
-
if (cachedResult) return;
|
|
3031
|
-
const set = store.setState;
|
|
3032
3243
|
const urlTextureMap = [];
|
|
3033
3244
|
if (typeof input === "string") {
|
|
3034
3245
|
urlTextureMap.push([input, mappedTextures]);
|
|
@@ -3042,18 +3253,32 @@ function useTexture(input, optionsOrOnLoad) {
|
|
|
3042
3253
|
urlTextureMap.push([url, textureRecord[key]]);
|
|
3043
3254
|
}
|
|
3044
3255
|
}
|
|
3045
|
-
|
|
3046
|
-
const
|
|
3047
|
-
let
|
|
3256
|
+
store.setState((state) => {
|
|
3257
|
+
const refs = new Map(state._textureRefs);
|
|
3258
|
+
let textures = state.textures;
|
|
3259
|
+
let added = false;
|
|
3048
3260
|
for (const [url, texture] of urlTextureMap) {
|
|
3049
|
-
if (!
|
|
3050
|
-
|
|
3051
|
-
|
|
3261
|
+
if (!textures.has(url)) {
|
|
3262
|
+
if (!added) {
|
|
3263
|
+
textures = new Map(textures);
|
|
3264
|
+
added = true;
|
|
3265
|
+
}
|
|
3266
|
+
textures.set(url, texture);
|
|
3052
3267
|
}
|
|
3268
|
+
refs.set(url, (refs.get(url) ?? 0) + 1);
|
|
3053
3269
|
}
|
|
3054
|
-
return
|
|
3270
|
+
return added ? { textures, _textureRefs: refs } : { _textureRefs: refs };
|
|
3271
|
+
});
|
|
3272
|
+
return () => store.setState((state) => {
|
|
3273
|
+
const refs = new Map(state._textureRefs);
|
|
3274
|
+
for (const [url] of urlTextureMap) {
|
|
3275
|
+
const next = (refs.get(url) ?? 0) - 1;
|
|
3276
|
+
if (next <= 0) refs.delete(url);
|
|
3277
|
+
else refs.set(url, next);
|
|
3278
|
+
}
|
|
3279
|
+
return { _textureRefs: refs };
|
|
3055
3280
|
});
|
|
3056
|
-
}, [cache, input, mappedTextures, store
|
|
3281
|
+
}, [cache, input, mappedTextures, store]);
|
|
3057
3282
|
return mappedTextures;
|
|
3058
3283
|
}
|
|
3059
3284
|
useTexture.preload = (url) => useLoader.preload(webgpu.TextureLoader, url);
|
|
@@ -3069,96 +3294,63 @@ const Texture = ({
|
|
|
3069
3294
|
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: children?.(ret) });
|
|
3070
3295
|
};
|
|
3071
3296
|
|
|
3072
|
-
function
|
|
3073
|
-
if (entry instanceof webgpu.Texture) return entry;
|
|
3074
|
-
if (entry && typeof entry === "object" && "value" in entry && entry.value instanceof webgpu.Texture) {
|
|
3075
|
-
return entry.value;
|
|
3076
|
-
}
|
|
3077
|
-
return null;
|
|
3078
|
-
}
|
|
3079
|
-
function useTextures() {
|
|
3297
|
+
function useTextures(selector) {
|
|
3080
3298
|
const store = useStore();
|
|
3081
|
-
|
|
3082
|
-
const set = store.setState;
|
|
3299
|
+
const registry = React.useMemo(() => {
|
|
3083
3300
|
const getState = store.getState;
|
|
3084
|
-
const
|
|
3085
|
-
|
|
3086
|
-
const newMap = new Map(state.textures);
|
|
3087
|
-
newMap.set(key, value);
|
|
3088
|
-
return { textures: newMap };
|
|
3089
|
-
});
|
|
3090
|
-
};
|
|
3091
|
-
const addMultiple = (items) => {
|
|
3092
|
-
set((state) => {
|
|
3093
|
-
const newMap = new Map(state.textures);
|
|
3094
|
-
const entries = items instanceof Map ? items.entries() : Object.entries(items);
|
|
3095
|
-
for (const [key, value] of entries) {
|
|
3096
|
-
newMap.set(key, value);
|
|
3097
|
-
}
|
|
3098
|
-
return { textures: newMap };
|
|
3099
|
-
});
|
|
3100
|
-
};
|
|
3101
|
-
const remove = (key) => {
|
|
3102
|
-
set((state) => {
|
|
3103
|
-
const newMap = new Map(state.textures);
|
|
3104
|
-
newMap.delete(key);
|
|
3105
|
-
return { textures: newMap };
|
|
3106
|
-
});
|
|
3107
|
-
};
|
|
3108
|
-
const removeMultiple = (keys) => {
|
|
3109
|
-
set((state) => {
|
|
3110
|
-
const newMap = new Map(state.textures);
|
|
3111
|
-
for (const key of keys) newMap.delete(key);
|
|
3112
|
-
return { textures: newMap };
|
|
3113
|
-
});
|
|
3114
|
-
};
|
|
3115
|
-
const dispose = (key) => {
|
|
3116
|
-
const entry = getState().textures.get(key);
|
|
3117
|
-
if (entry) {
|
|
3118
|
-
const tex = getTextureValue(entry);
|
|
3119
|
-
tex?.dispose();
|
|
3120
|
-
}
|
|
3121
|
-
remove(key);
|
|
3122
|
-
};
|
|
3123
|
-
const disposeMultiple = (keys) => {
|
|
3124
|
-
const textures = getState().textures;
|
|
3125
|
-
for (const key of keys) {
|
|
3126
|
-
const entry = textures.get(key);
|
|
3127
|
-
if (entry) {
|
|
3128
|
-
const tex = getTextureValue(entry);
|
|
3129
|
-
tex?.dispose();
|
|
3130
|
-
}
|
|
3131
|
-
}
|
|
3132
|
-
removeMultiple(keys);
|
|
3133
|
-
};
|
|
3134
|
-
const disposeAll = () => {
|
|
3135
|
-
const textures = getState().textures;
|
|
3136
|
-
for (const entry of textures.values()) {
|
|
3137
|
-
const tex = getTextureValue(entry);
|
|
3138
|
-
tex?.dispose();
|
|
3139
|
-
}
|
|
3140
|
-
set({ textures: /* @__PURE__ */ new Map() });
|
|
3141
|
-
};
|
|
3301
|
+
const setState = store.setState;
|
|
3302
|
+
const getOne = (key) => getState().textures.get(key);
|
|
3142
3303
|
return {
|
|
3143
|
-
|
|
3144
|
-
get textures() {
|
|
3304
|
+
get all() {
|
|
3145
3305
|
return getState().textures;
|
|
3146
3306
|
},
|
|
3147
|
-
|
|
3148
|
-
|
|
3307
|
+
get(input) {
|
|
3308
|
+
if (typeof input === "string") return getOne(input);
|
|
3309
|
+
if (Array.isArray(input)) return input.map(getOne);
|
|
3310
|
+
const out = {};
|
|
3311
|
+
for (const name in input) out[name] = getOne(input[name]);
|
|
3312
|
+
return out;
|
|
3313
|
+
},
|
|
3149
3314
|
has: (key) => getState().textures.has(key),
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3315
|
+
add(keyOrRecord, texture) {
|
|
3316
|
+
setState((state) => {
|
|
3317
|
+
const textures = new Map(state.textures);
|
|
3318
|
+
if (typeof keyOrRecord === "string") {
|
|
3319
|
+
textures.set(keyOrRecord, texture);
|
|
3320
|
+
} else {
|
|
3321
|
+
for (const key in keyOrRecord) textures.set(key, keyOrRecord[key]);
|
|
3322
|
+
}
|
|
3323
|
+
return { textures };
|
|
3324
|
+
});
|
|
3325
|
+
},
|
|
3326
|
+
dispose(key, options) {
|
|
3327
|
+
const state = getState();
|
|
3328
|
+
const refs = state._textureRefs.get(key) ?? 0;
|
|
3329
|
+
if (refs > 0 && !options?.force) {
|
|
3330
|
+
console.warn(
|
|
3331
|
+
`[useTextures] "${key}" still has ${refs} active reference(s); skipping dispose. Pass { force: true } to override.`
|
|
3332
|
+
);
|
|
3333
|
+
return false;
|
|
3334
|
+
}
|
|
3335
|
+
state.textures.get(key)?.dispose();
|
|
3336
|
+
setState((s) => {
|
|
3337
|
+
const textures = new Map(s.textures);
|
|
3338
|
+
textures.delete(key);
|
|
3339
|
+
const nextRefs = new Map(s._textureRefs);
|
|
3340
|
+
nextRefs.delete(key);
|
|
3341
|
+
return { textures, _textureRefs: nextRefs };
|
|
3342
|
+
});
|
|
3343
|
+
return true;
|
|
3344
|
+
},
|
|
3345
|
+
disposeAll() {
|
|
3346
|
+
for (const texture of getState().textures.values()) texture.dispose();
|
|
3347
|
+
setState({ textures: /* @__PURE__ */ new Map(), _textureRefs: /* @__PURE__ */ new Map() });
|
|
3348
|
+
}
|
|
3160
3349
|
};
|
|
3161
3350
|
}, [store]);
|
|
3351
|
+
const subscribe = selector ? () => selector(registry) : (state) => state.textures;
|
|
3352
|
+
const selected = useThree(subscribe);
|
|
3353
|
+
return selector ? selected : registry;
|
|
3162
3354
|
}
|
|
3163
3355
|
|
|
3164
3356
|
function useRenderTarget(widthOrOptions, heightOrOptions, options) {
|
|
@@ -15011,7 +15203,6 @@ function createRoot(canvas) {
|
|
|
15011
15203
|
events,
|
|
15012
15204
|
onCreated: onCreatedCallback,
|
|
15013
15205
|
shadows = false,
|
|
15014
|
-
textureColorSpace = webgpu.SRGBColorSpace,
|
|
15015
15206
|
orthographic = false,
|
|
15016
15207
|
frameloop = "always",
|
|
15017
15208
|
dpr = [1, 2],
|
|
@@ -15026,6 +15217,7 @@ function createRoot(canvas) {
|
|
|
15026
15217
|
_sizeProps,
|
|
15027
15218
|
forceEven
|
|
15028
15219
|
} = props;
|
|
15220
|
+
const textureColorSpace = is.obj(glConfig) && !is.fun(glConfig) && !isRenderer(glConfig) && glConfig.textureColorSpace || is.obj(rendererConfig) && !is.fun(rendererConfig) && !isRenderer(rendererConfig) && rendererConfig.textureColorSpace || webgpu.SRGBColorSpace;
|
|
15029
15221
|
const state = store.getState();
|
|
15030
15222
|
const defaultGLProps = {
|
|
15031
15223
|
canvas,
|
|
@@ -15081,6 +15273,12 @@ function createRoot(canvas) {
|
|
|
15081
15273
|
} else if (!wantsGL && !state.internal.actualRenderer) {
|
|
15082
15274
|
renderer = await resolveRenderer(rendererConfig, defaultGPUProps, webgpu.WebGPURenderer);
|
|
15083
15275
|
if (!renderer.hasInitialized?.()) {
|
|
15276
|
+
const size2 = computeInitialSize(canvas, propsSize);
|
|
15277
|
+
if (size2.width > 0 && size2.height > 0) {
|
|
15278
|
+
const pixelRatio = calculateDpr(dpr);
|
|
15279
|
+
canvas.width = size2.width * pixelRatio;
|
|
15280
|
+
canvas.height = size2.height * pixelRatio;
|
|
15281
|
+
}
|
|
15084
15282
|
await renderer.init();
|
|
15085
15283
|
}
|
|
15086
15284
|
const backend = renderer.backend;
|
|
@@ -15190,7 +15388,7 @@ function createRoot(canvas) {
|
|
|
15190
15388
|
lastConfiguredProps.performance = performance;
|
|
15191
15389
|
}
|
|
15192
15390
|
if (!state.xr) {
|
|
15193
|
-
const handleXRFrame = (timestamp,
|
|
15391
|
+
const handleXRFrame = (timestamp, _frame) => {
|
|
15194
15392
|
const state2 = store.getState();
|
|
15195
15393
|
if (state2.frameloop === "never") return;
|
|
15196
15394
|
advance(timestamp);
|
|
@@ -15226,15 +15424,22 @@ function createRoot(canvas) {
|
|
|
15226
15424
|
const oldType = renderer.shadowMap.type;
|
|
15227
15425
|
renderer.shadowMap.enabled = !!shadows;
|
|
15228
15426
|
if (is.boo(shadows)) {
|
|
15229
|
-
renderer.shadowMap.type = webgpu.
|
|
15427
|
+
renderer.shadowMap.type = webgpu.PCFShadowMap;
|
|
15230
15428
|
} else if (is.str(shadows)) {
|
|
15429
|
+
if (shadows === "soft") {
|
|
15430
|
+
notifyDepreciated({
|
|
15431
|
+
heading: 'shadows="soft" is deprecated',
|
|
15432
|
+
body: "Three has depreciated soft and improved basic PCFShadows, we converted for you.",
|
|
15433
|
+
link: "https://github.com/mrdoob/three.js/wiki/Migration-Guide?utm_source=chatgpt.com#181--182"
|
|
15434
|
+
});
|
|
15435
|
+
}
|
|
15231
15436
|
const types = {
|
|
15232
15437
|
basic: webgpu.BasicShadowMap,
|
|
15233
15438
|
percentage: webgpu.PCFShadowMap,
|
|
15234
|
-
soft: webgpu.
|
|
15439
|
+
soft: webgpu.PCFShadowMap,
|
|
15235
15440
|
variance: webgpu.VSMShadowMap
|
|
15236
15441
|
};
|
|
15237
|
-
renderer.shadowMap.type = types[shadows] ?? webgpu.
|
|
15442
|
+
renderer.shadowMap.type = types[shadows] ?? webgpu.PCFShadowMap;
|
|
15238
15443
|
} else if (is.obj(shadows)) {
|
|
15239
15444
|
Object.assign(renderer.shadowMap, shadows);
|
|
15240
15445
|
}
|
|
@@ -15250,13 +15455,24 @@ function createRoot(canvas) {
|
|
|
15250
15455
|
if (state.textureColorSpace !== textureColorSpace) state.set(() => ({ textureColorSpace }));
|
|
15251
15456
|
lastConfiguredProps.textureColorSpace = textureColorSpace;
|
|
15252
15457
|
}
|
|
15458
|
+
const r3fProps = ["textureColorSpace"];
|
|
15459
|
+
const constructorOnlyProps = ["samples", "antialias", "alpha", "canvas", "powerPreference"];
|
|
15460
|
+
const nonApplyProps = [...r3fProps, ...constructorOnlyProps];
|
|
15253
15461
|
if (glConfig && !is.fun(glConfig) && !isRenderer(glConfig) && !is.equ(glConfig, renderer, shallowLoose)) {
|
|
15254
|
-
|
|
15462
|
+
const glProps = {};
|
|
15463
|
+
for (const key in glConfig) {
|
|
15464
|
+
if (!nonApplyProps.includes(key)) glProps[key] = glConfig[key];
|
|
15465
|
+
}
|
|
15466
|
+
applyProps(renderer, glProps);
|
|
15255
15467
|
}
|
|
15256
15468
|
if (rendererConfig && !is.fun(rendererConfig) && !isRenderer(rendererConfig) && state.renderer) {
|
|
15257
15469
|
const currentRenderer = state.renderer;
|
|
15258
15470
|
if (!is.equ(rendererConfig, currentRenderer, shallowLoose)) {
|
|
15259
|
-
|
|
15471
|
+
const rendererProps = {};
|
|
15472
|
+
for (const key in rendererConfig) {
|
|
15473
|
+
if (!nonApplyProps.includes(key)) rendererProps[key] = rendererConfig[key];
|
|
15474
|
+
}
|
|
15475
|
+
applyProps(currentRenderer, rendererProps);
|
|
15260
15476
|
}
|
|
15261
15477
|
}
|
|
15262
15478
|
const scheduler = getScheduler();
|
|
@@ -15282,6 +15498,18 @@ function createRoot(canvas) {
|
|
|
15282
15498
|
system: true
|
|
15283
15499
|
}
|
|
15284
15500
|
);
|
|
15501
|
+
const unregisterEventsFlush = scheduler.register(
|
|
15502
|
+
() => {
|
|
15503
|
+
const state2 = store.getState();
|
|
15504
|
+
state2.events.flush?.();
|
|
15505
|
+
},
|
|
15506
|
+
{
|
|
15507
|
+
id: `${newRootId}_events`,
|
|
15508
|
+
rootId: newRootId,
|
|
15509
|
+
phase: "input",
|
|
15510
|
+
system: true
|
|
15511
|
+
}
|
|
15512
|
+
);
|
|
15285
15513
|
const unregisterFrustum = scheduler.register(
|
|
15286
15514
|
() => {
|
|
15287
15515
|
const state2 = store.getState();
|
|
@@ -15292,7 +15520,7 @@ function createRoot(canvas) {
|
|
|
15292
15520
|
{
|
|
15293
15521
|
id: `${newRootId}_frustum`,
|
|
15294
15522
|
rootId: newRootId,
|
|
15295
|
-
|
|
15523
|
+
before: "render",
|
|
15296
15524
|
system: true
|
|
15297
15525
|
}
|
|
15298
15526
|
);
|
|
@@ -15304,7 +15532,7 @@ function createRoot(canvas) {
|
|
|
15304
15532
|
{
|
|
15305
15533
|
id: `${newRootId}_visibility`,
|
|
15306
15534
|
rootId: newRootId,
|
|
15307
|
-
|
|
15535
|
+
before: "render",
|
|
15308
15536
|
system: true,
|
|
15309
15537
|
after: `${newRootId}_frustum`
|
|
15310
15538
|
}
|
|
@@ -15316,7 +15544,7 @@ function createRoot(canvas) {
|
|
|
15316
15544
|
const userHandlesRender = scheduler.hasUserJobsInPhase("render", newRootId);
|
|
15317
15545
|
if (userHandlesRender || state2.internal.priority) return;
|
|
15318
15546
|
try {
|
|
15319
|
-
if (state2.
|
|
15547
|
+
if (state2.renderPipeline?.render) state2.renderPipeline.render();
|
|
15320
15548
|
else if (renderer2?.render) renderer2.render(state2.scene, state2.camera);
|
|
15321
15549
|
} catch (error) {
|
|
15322
15550
|
state2.setError(error instanceof Error ? error : new Error(String(error)));
|
|
@@ -15341,6 +15569,7 @@ function createRoot(canvas) {
|
|
|
15341
15569
|
unregisterRoot: () => {
|
|
15342
15570
|
unregisterRoot();
|
|
15343
15571
|
unregisterCanvasTarget();
|
|
15572
|
+
unregisterEventsFlush();
|
|
15344
15573
|
unregisterFrustum();
|
|
15345
15574
|
unregisterVisibility();
|
|
15346
15575
|
unregisterRender();
|
|
@@ -15506,9 +15735,13 @@ function PortalInner({ state = {}, children, container }) {
|
|
|
15506
15735
|
const store = traditional.createWithEqualityFn((set, get) => ({ ...rest, set, get }));
|
|
15507
15736
|
const onMutate = (prev) => store.setState((state2) => inject.current(prev, state2));
|
|
15508
15737
|
onMutate(previousRoot.getState());
|
|
15509
|
-
previousRoot.subscribe(onMutate);
|
|
15510
15738
|
return store;
|
|
15511
15739
|
}, [previousRoot, container]);
|
|
15740
|
+
useIsomorphicLayoutEffect(() => {
|
|
15741
|
+
const onMutate = (prev) => usePortalStore.setState((state2) => inject.current(prev, state2));
|
|
15742
|
+
const unsubscribe = previousRoot.subscribe(onMutate);
|
|
15743
|
+
return unsubscribe;
|
|
15744
|
+
}, [previousRoot, usePortalStore]);
|
|
15512
15745
|
return (
|
|
15513
15746
|
// @ts-ignore, reconciler types are not maintained
|
|
15514
15747
|
/* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: reconciler.createPortal(
|
|
@@ -15522,6 +15755,46 @@ function flushSync(fn) {
|
|
|
15522
15755
|
return reconciler.flushSyncFromReconciler(fn);
|
|
15523
15756
|
}
|
|
15524
15757
|
|
|
15758
|
+
function parseBackground(background) {
|
|
15759
|
+
if (!background) return null;
|
|
15760
|
+
if (typeof background === "object" && !background.isColor) {
|
|
15761
|
+
const { backgroundMap, envMap, files, preset, ...rest } = background;
|
|
15762
|
+
return {
|
|
15763
|
+
...rest,
|
|
15764
|
+
preset,
|
|
15765
|
+
files: envMap || files,
|
|
15766
|
+
backgroundFiles: backgroundMap,
|
|
15767
|
+
background: true
|
|
15768
|
+
};
|
|
15769
|
+
}
|
|
15770
|
+
if (typeof background === "number") {
|
|
15771
|
+
return { color: background, background: true };
|
|
15772
|
+
}
|
|
15773
|
+
if (typeof background === "string") {
|
|
15774
|
+
if (background in presetsObj) {
|
|
15775
|
+
return { preset: background, background: true };
|
|
15776
|
+
}
|
|
15777
|
+
if (/^(https?:\/\/|\/|\.\/|\.\.\/)|\.(hdr|exr|jpg|jpeg|png|webp|gif)$/i.test(background)) {
|
|
15778
|
+
return { files: background, background: true };
|
|
15779
|
+
}
|
|
15780
|
+
return { color: background, background: true };
|
|
15781
|
+
}
|
|
15782
|
+
if (background.isColor) {
|
|
15783
|
+
return { color: background, background: true };
|
|
15784
|
+
}
|
|
15785
|
+
return null;
|
|
15786
|
+
}
|
|
15787
|
+
|
|
15788
|
+
function clearHmrCaches(store) {
|
|
15789
|
+
store.setState((state) => ({
|
|
15790
|
+
nodes: {},
|
|
15791
|
+
uniforms: {},
|
|
15792
|
+
buffers: {},
|
|
15793
|
+
gpuStorage: {},
|
|
15794
|
+
_hmrVersion: state._hmrVersion + 1
|
|
15795
|
+
}));
|
|
15796
|
+
}
|
|
15797
|
+
|
|
15525
15798
|
function CanvasImpl({
|
|
15526
15799
|
ref,
|
|
15527
15800
|
children,
|
|
@@ -15542,6 +15815,8 @@ function CanvasImpl({
|
|
|
15542
15815
|
raycaster,
|
|
15543
15816
|
camera,
|
|
15544
15817
|
scene,
|
|
15818
|
+
autoUpdateFrustum,
|
|
15819
|
+
occlusion,
|
|
15545
15820
|
onPointerMissed,
|
|
15546
15821
|
onDragOverMissed,
|
|
15547
15822
|
onDropMissed,
|
|
@@ -15553,39 +15828,21 @@ function CanvasImpl({
|
|
|
15553
15828
|
forceEven,
|
|
15554
15829
|
...props
|
|
15555
15830
|
}) {
|
|
15556
|
-
const
|
|
15557
|
-
|
|
15831
|
+
const isRendererConfig = typeof rendererProp === "object" && rendererProp !== null && !("render" in rendererProp) && ("primaryCanvas" in rendererProp || "scheduler" in rendererProp);
|
|
15832
|
+
let primaryCanvas;
|
|
15833
|
+
let scheduler;
|
|
15834
|
+
let renderer;
|
|
15835
|
+
if (isRendererConfig) {
|
|
15836
|
+
const { primaryCanvas: pc, scheduler: sc, ...rest } = rendererProp;
|
|
15837
|
+
primaryCanvas = pc;
|
|
15838
|
+
scheduler = sc;
|
|
15839
|
+
renderer = Object.keys(rest).length > 0 ? rest : rendererProp;
|
|
15840
|
+
} else {
|
|
15841
|
+
renderer = rendererProp;
|
|
15842
|
+
}
|
|
15558
15843
|
React__namespace.useMemo(() => extend(THREE), []);
|
|
15559
15844
|
const Bridge = useBridge();
|
|
15560
|
-
const backgroundProps = React__namespace.useMemo(() =>
|
|
15561
|
-
if (!background) return null;
|
|
15562
|
-
if (typeof background === "object" && !background.isColor) {
|
|
15563
|
-
const { backgroundMap, envMap, files, preset, ...rest } = background;
|
|
15564
|
-
return {
|
|
15565
|
-
...rest,
|
|
15566
|
-
preset,
|
|
15567
|
-
files: envMap || files,
|
|
15568
|
-
backgroundFiles: backgroundMap,
|
|
15569
|
-
background: true
|
|
15570
|
-
};
|
|
15571
|
-
}
|
|
15572
|
-
if (typeof background === "number") {
|
|
15573
|
-
return { color: background, background: true };
|
|
15574
|
-
}
|
|
15575
|
-
if (typeof background === "string") {
|
|
15576
|
-
if (background in presetsObj) {
|
|
15577
|
-
return { preset: background, background: true };
|
|
15578
|
-
}
|
|
15579
|
-
if (/^(https?:\/\/|\/|\.\/|\.\.\/)|\\.(hdr|exr|jpg|jpeg|png|webp|gif)$/i.test(background)) {
|
|
15580
|
-
return { files: background, background: true };
|
|
15581
|
-
}
|
|
15582
|
-
return { color: background, background: true };
|
|
15583
|
-
}
|
|
15584
|
-
if (background.isColor) {
|
|
15585
|
-
return { color: background, background: true };
|
|
15586
|
-
}
|
|
15587
|
-
return null;
|
|
15588
|
-
}, [background]);
|
|
15845
|
+
const backgroundProps = React__namespace.useMemo(() => parseBackground(background), [background]);
|
|
15589
15846
|
const hasInitialSizeRef = React__namespace.useRef(false);
|
|
15590
15847
|
const measureConfig = React__namespace.useMemo(() => {
|
|
15591
15848
|
if (!hasInitialSizeRef.current) {
|
|
@@ -15669,6 +15926,8 @@ function CanvasImpl({
|
|
|
15669
15926
|
performance,
|
|
15670
15927
|
raycaster,
|
|
15671
15928
|
camera,
|
|
15929
|
+
autoUpdateFrustum,
|
|
15930
|
+
occlusion,
|
|
15672
15931
|
size: effectiveSize,
|
|
15673
15932
|
// Store size props for reset functionality
|
|
15674
15933
|
_sizeProps: width !== void 0 || height !== void 0 ? { width, height } : null,
|
|
@@ -15728,20 +15987,13 @@ function CanvasImpl({
|
|
|
15728
15987
|
const handleHMR = () => {
|
|
15729
15988
|
queueMicrotask(() => {
|
|
15730
15989
|
const rootEntry = _roots.get(canvas);
|
|
15731
|
-
if (rootEntry?.store)
|
|
15732
|
-
rootEntry.store.setState((state) => ({
|
|
15733
|
-
nodes: {},
|
|
15734
|
-
uniforms: {},
|
|
15735
|
-
_hmrVersion: state._hmrVersion + 1
|
|
15736
|
-
}));
|
|
15737
|
-
}
|
|
15990
|
+
if (rootEntry?.store) clearHmrCaches(rootEntry.store);
|
|
15738
15991
|
});
|
|
15739
15992
|
};
|
|
15740
15993
|
if (typeof ({ url: (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)) }) !== "undefined" && undefined) {
|
|
15741
15994
|
const hot = undefined;
|
|
15742
15995
|
hot.on("vite:afterUpdate", handleHMR);
|
|
15743
|
-
return () => hot.
|
|
15744
|
-
});
|
|
15996
|
+
return () => hot.off?.("vite:afterUpdate", handleHMR);
|
|
15745
15997
|
}
|
|
15746
15998
|
if (typeof module !== "undefined" && module.hot) {
|
|
15747
15999
|
const hot = module.hot;
|
|
@@ -15764,7 +16016,16 @@ function CanvasImpl({
|
|
|
15764
16016
|
...style
|
|
15765
16017
|
},
|
|
15766
16018
|
...props,
|
|
15767
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, className: "r3f-canvas-container", style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
16019
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, className: "r3f-canvas-container", style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
16020
|
+
"canvas",
|
|
16021
|
+
{
|
|
16022
|
+
ref: canvasRef,
|
|
16023
|
+
id,
|
|
16024
|
+
className: "r3f-canvas",
|
|
16025
|
+
style: { display: "block", width: "100%", height: "100%" },
|
|
16026
|
+
children: fallback
|
|
16027
|
+
}
|
|
16028
|
+
) })
|
|
15768
16029
|
}
|
|
15769
16030
|
);
|
|
15770
16031
|
}
|