@react-three/fiber 10.0.0-canary.2b511a5 → 10.0.0-canary.aecbafb
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 +290 -73
- package/dist/index.d.cts +138 -21
- package/dist/index.d.mts +138 -21
- package/dist/index.d.ts +138 -21
- package/dist/index.mjs +290 -73
- package/dist/legacy.cjs +284 -73
- package/dist/legacy.d.cts +138 -21
- package/dist/legacy.d.mts +138 -21
- package/dist/legacy.d.ts +138 -21
- package/dist/legacy.mjs +284 -73
- package/dist/webgpu/index.cjs +665 -84
- package/dist/webgpu/index.d.cts +223 -34
- package/dist/webgpu/index.d.mts +223 -34
- package/dist/webgpu/index.d.ts +223 -34
- package/dist/webgpu/index.mjs +661 -84
- package/package.json +1 -1
package/dist/webgpu/index.cjs
CHANGED
|
@@ -1006,6 +1006,9 @@ function applyProps(object, props) {
|
|
|
1006
1006
|
else target.set(value);
|
|
1007
1007
|
} else {
|
|
1008
1008
|
root[key] = value;
|
|
1009
|
+
if (key.endsWith("Node") && root.isMaterial) {
|
|
1010
|
+
root.needsUpdate = true;
|
|
1011
|
+
}
|
|
1009
1012
|
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
|
|
1010
1013
|
root[key].format === webgpu.RGBAFormat && root[key].type === webgpu.UnsignedByteType) {
|
|
1011
1014
|
root[key].colorSpace = rootState.textureColorSpace;
|
|
@@ -1039,38 +1042,60 @@ function applyProps(object, props) {
|
|
|
1039
1042
|
return object;
|
|
1040
1043
|
}
|
|
1041
1044
|
|
|
1045
|
+
const DEFAULT_POINTER_ID = 0;
|
|
1046
|
+
const XR_POINTER_ID_START = 1e3;
|
|
1047
|
+
function getPointerState(internal, pointerId) {
|
|
1048
|
+
let state = internal.pointerMap.get(pointerId);
|
|
1049
|
+
if (!state) {
|
|
1050
|
+
state = {
|
|
1051
|
+
hovered: /* @__PURE__ */ new Map(),
|
|
1052
|
+
captured: /* @__PURE__ */ new Map(),
|
|
1053
|
+
initialClick: [0, 0],
|
|
1054
|
+
initialHits: []
|
|
1055
|
+
};
|
|
1056
|
+
internal.pointerMap.set(pointerId, state);
|
|
1057
|
+
}
|
|
1058
|
+
return state;
|
|
1059
|
+
}
|
|
1060
|
+
function getPointerId(event) {
|
|
1061
|
+
return "pointerId" in event ? event.pointerId : DEFAULT_POINTER_ID;
|
|
1062
|
+
}
|
|
1042
1063
|
function makeId(event) {
|
|
1043
1064
|
return (event.eventObject || event.object).uuid + "/" + event.index + event.instanceId;
|
|
1044
1065
|
}
|
|
1045
|
-
function releaseInternalPointerCapture(
|
|
1046
|
-
const
|
|
1066
|
+
function releaseInternalPointerCapture(internal, obj, pointerId) {
|
|
1067
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1068
|
+
if (!pointerState) return;
|
|
1069
|
+
const captureData = pointerState.captured.get(obj);
|
|
1047
1070
|
if (captureData) {
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
capturedMap.delete(pointerId);
|
|
1051
|
-
captureData.target.releasePointerCapture(pointerId);
|
|
1052
|
-
}
|
|
1071
|
+
pointerState.captured.delete(obj);
|
|
1072
|
+
captureData.target.releasePointerCapture(pointerId);
|
|
1053
1073
|
}
|
|
1054
1074
|
}
|
|
1055
1075
|
function removeInteractivity(store, object) {
|
|
1056
1076
|
const { internal } = store.getState();
|
|
1057
1077
|
internal.interaction = internal.interaction.filter((o) => o !== object);
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1078
|
+
for (const [pointerId, pointerState] of internal.pointerMap) {
|
|
1079
|
+
pointerState.initialHits = pointerState.initialHits.filter((o) => o !== object);
|
|
1080
|
+
pointerState.hovered.forEach((value, key) => {
|
|
1081
|
+
if (value.eventObject === object || value.object === object) {
|
|
1082
|
+
pointerState.hovered.delete(key);
|
|
1083
|
+
}
|
|
1084
|
+
});
|
|
1085
|
+
if (pointerState.captured.has(object)) {
|
|
1086
|
+
releaseInternalPointerCapture(internal, object, pointerId);
|
|
1062
1087
|
}
|
|
1063
|
-
}
|
|
1064
|
-
internal.capturedMap.forEach((captures, pointerId) => {
|
|
1065
|
-
releaseInternalPointerCapture(internal.capturedMap, object, captures, pointerId);
|
|
1066
|
-
});
|
|
1088
|
+
}
|
|
1067
1089
|
unregisterVisibility(store, object);
|
|
1068
1090
|
}
|
|
1069
1091
|
function createEvents(store) {
|
|
1070
|
-
function calculateDistance(event) {
|
|
1092
|
+
function calculateDistance(event, pointerId) {
|
|
1071
1093
|
const { internal } = store.getState();
|
|
1072
|
-
const
|
|
1073
|
-
|
|
1094
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1095
|
+
if (!pointerState) return 0;
|
|
1096
|
+
const [initialX, initialY] = pointerState.initialClick;
|
|
1097
|
+
const dx = event.offsetX - initialX;
|
|
1098
|
+
const dy = event.offsetY - initialY;
|
|
1074
1099
|
return Math.round(Math.sqrt(dx * dx + dy * dy));
|
|
1075
1100
|
}
|
|
1076
1101
|
function filterPointerEvents(objects) {
|
|
@@ -1106,6 +1131,15 @@ function createEvents(store) {
|
|
|
1106
1131
|
return state2.raycaster.camera ? state2.raycaster.intersectObject(obj, true) : [];
|
|
1107
1132
|
}
|
|
1108
1133
|
let hits = eventsObjects.flatMap(handleRaycast).sort((a, b) => {
|
|
1134
|
+
const aInteractivePriority = a.object.userData?.interactivePriority;
|
|
1135
|
+
const bInteractivePriority = b.object.userData?.interactivePriority;
|
|
1136
|
+
if (aInteractivePriority !== void 0 || bInteractivePriority !== void 0) {
|
|
1137
|
+
if (aInteractivePriority !== void 0 && bInteractivePriority === void 0) return -1;
|
|
1138
|
+
if (bInteractivePriority !== void 0 && aInteractivePriority === void 0) return 1;
|
|
1139
|
+
if (aInteractivePriority !== bInteractivePriority) {
|
|
1140
|
+
return (bInteractivePriority ?? 0) - (aInteractivePriority ?? 0);
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1109
1143
|
const aState = getRootState(a.object);
|
|
1110
1144
|
const bState = getRootState(b.object);
|
|
1111
1145
|
const aPriority = aState?.events?.priority ?? 1;
|
|
@@ -1127,9 +1161,13 @@ function createEvents(store) {
|
|
|
1127
1161
|
eventObject = eventObject.parent;
|
|
1128
1162
|
}
|
|
1129
1163
|
}
|
|
1130
|
-
if ("pointerId" in event
|
|
1131
|
-
|
|
1132
|
-
|
|
1164
|
+
if ("pointerId" in event) {
|
|
1165
|
+
const pointerId = event.pointerId;
|
|
1166
|
+
const pointerState = state.internal.pointerMap.get(pointerId);
|
|
1167
|
+
if (pointerState?.captured.size) {
|
|
1168
|
+
for (const captureData of pointerState.captured.values()) {
|
|
1169
|
+
if (!duplicates.has(makeId(captureData.intersection))) intersections.push(captureData.intersection);
|
|
1170
|
+
}
|
|
1133
1171
|
}
|
|
1134
1172
|
}
|
|
1135
1173
|
return intersections;
|
|
@@ -1142,27 +1180,25 @@ function createEvents(store) {
|
|
|
1142
1180
|
if (state) {
|
|
1143
1181
|
const { raycaster, pointer, camera, internal } = state;
|
|
1144
1182
|
const unprojectedPoint = new webgpu.Vector3(pointer.x, pointer.y, 0).unproject(camera);
|
|
1145
|
-
const hasPointerCapture = (id) =>
|
|
1183
|
+
const hasPointerCapture = (id) => {
|
|
1184
|
+
const pointerState = internal.pointerMap.get(id);
|
|
1185
|
+
return pointerState?.captured.has(hit.eventObject) ?? false;
|
|
1186
|
+
};
|
|
1146
1187
|
const setPointerCapture = (id) => {
|
|
1147
1188
|
const captureData = { intersection: hit, target: event.target };
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
} else {
|
|
1151
|
-
internal.capturedMap.set(id, /* @__PURE__ */ new Map([[hit.eventObject, captureData]]));
|
|
1152
|
-
}
|
|
1189
|
+
const pointerState = getPointerState(internal, id);
|
|
1190
|
+
pointerState.captured.set(hit.eventObject, captureData);
|
|
1153
1191
|
event.target.setPointerCapture(id);
|
|
1154
1192
|
};
|
|
1155
1193
|
const releasePointerCapture = (id) => {
|
|
1156
|
-
|
|
1157
|
-
if (captures) {
|
|
1158
|
-
releaseInternalPointerCapture(internal.capturedMap, hit.eventObject, captures, id);
|
|
1159
|
-
}
|
|
1194
|
+
releaseInternalPointerCapture(internal, hit.eventObject, id);
|
|
1160
1195
|
};
|
|
1161
1196
|
const extractEventProps = {};
|
|
1162
1197
|
for (const prop in event) {
|
|
1163
1198
|
const property = event[prop];
|
|
1164
1199
|
if (typeof property !== "function") extractEventProps[prop] = property;
|
|
1165
1200
|
}
|
|
1201
|
+
const eventPointerId = "pointerId" in event ? event.pointerId : void 0;
|
|
1166
1202
|
const raycastEvent = {
|
|
1167
1203
|
...hit,
|
|
1168
1204
|
...extractEventProps,
|
|
@@ -1173,18 +1209,19 @@ function createEvents(store) {
|
|
|
1173
1209
|
unprojectedPoint,
|
|
1174
1210
|
ray: raycaster.ray,
|
|
1175
1211
|
camera,
|
|
1212
|
+
pointerId: eventPointerId,
|
|
1176
1213
|
// Hijack stopPropagation, which just sets a flag
|
|
1177
1214
|
stopPropagation() {
|
|
1178
|
-
const
|
|
1215
|
+
const pointerState = eventPointerId !== void 0 ? internal.pointerMap.get(eventPointerId) : void 0;
|
|
1179
1216
|
if (
|
|
1180
1217
|
// ...if this pointer hasn't been captured
|
|
1181
|
-
!
|
|
1182
|
-
|
|
1218
|
+
!pointerState?.captured.size || // ... or if the hit object is capturing the pointer
|
|
1219
|
+
pointerState.captured.has(hit.eventObject)
|
|
1183
1220
|
) {
|
|
1184
1221
|
raycastEvent.stopped = localState.stopped = true;
|
|
1185
|
-
if (
|
|
1222
|
+
if (pointerState?.hovered.size && Array.from(pointerState.hovered.values()).find((i) => i.eventObject === hit.eventObject)) {
|
|
1186
1223
|
const higher = intersections.slice(0, intersections.indexOf(hit));
|
|
1187
|
-
cancelPointer([...higher, hit]);
|
|
1224
|
+
cancelPointer([...higher, hit], eventPointerId);
|
|
1188
1225
|
}
|
|
1189
1226
|
}
|
|
1190
1227
|
},
|
|
@@ -1200,15 +1237,18 @@ function createEvents(store) {
|
|
|
1200
1237
|
}
|
|
1201
1238
|
return intersections;
|
|
1202
1239
|
}
|
|
1203
|
-
function cancelPointer(intersections) {
|
|
1240
|
+
function cancelPointer(intersections, pointerId) {
|
|
1204
1241
|
const { internal } = store.getState();
|
|
1205
|
-
|
|
1242
|
+
const pid = pointerId ?? DEFAULT_POINTER_ID;
|
|
1243
|
+
const pointerState = internal.pointerMap.get(pid);
|
|
1244
|
+
if (!pointerState) return;
|
|
1245
|
+
for (const [hoveredId, hoveredObj] of pointerState.hovered) {
|
|
1206
1246
|
if (!intersections.length || !intersections.find(
|
|
1207
1247
|
(hit) => hit.object === hoveredObj.object && hit.index === hoveredObj.index && hit.instanceId === hoveredObj.instanceId
|
|
1208
1248
|
)) {
|
|
1209
1249
|
const eventObject = hoveredObj.eventObject;
|
|
1210
1250
|
const instance = eventObject.__r3f;
|
|
1211
|
-
|
|
1251
|
+
pointerState.hovered.delete(hoveredId);
|
|
1212
1252
|
if (instance?.eventCount) {
|
|
1213
1253
|
const handlers = instance.handlers;
|
|
1214
1254
|
const data = { ...hoveredObj, intersections };
|
|
@@ -1237,41 +1277,118 @@ function createEvents(store) {
|
|
|
1237
1277
|
instance?.handlers.onDropMissed?.(event);
|
|
1238
1278
|
}
|
|
1239
1279
|
}
|
|
1280
|
+
function cleanupPointer(pointerId) {
|
|
1281
|
+
const { internal } = store.getState();
|
|
1282
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1283
|
+
if (pointerState) {
|
|
1284
|
+
for (const [, hoveredObj] of pointerState.hovered) {
|
|
1285
|
+
const eventObject = hoveredObj.eventObject;
|
|
1286
|
+
const instance = eventObject.__r3f;
|
|
1287
|
+
if (instance?.eventCount) {
|
|
1288
|
+
const handlers = instance.handlers;
|
|
1289
|
+
const data = { ...hoveredObj, intersections: [] };
|
|
1290
|
+
handlers.onPointerOut?.(data);
|
|
1291
|
+
handlers.onPointerLeave?.(data);
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
internal.pointerMap.delete(pointerId);
|
|
1295
|
+
}
|
|
1296
|
+
internal.pointerDirty.delete(pointerId);
|
|
1297
|
+
}
|
|
1298
|
+
function processDeferredPointer(event, pointerId) {
|
|
1299
|
+
const state = store.getState();
|
|
1300
|
+
const { onPointerMissed, onDragOverMissed, internal } = state;
|
|
1301
|
+
if (!state.events.enabled) return;
|
|
1302
|
+
const filter = filterPointerEvents;
|
|
1303
|
+
const hits = intersect(event, filter);
|
|
1304
|
+
cancelPointer(hits, pointerId);
|
|
1305
|
+
function onIntersect(data) {
|
|
1306
|
+
const eventObject = data.eventObject;
|
|
1307
|
+
const instance = eventObject.__r3f;
|
|
1308
|
+
if (!instance?.eventCount) return;
|
|
1309
|
+
const handlers = instance.handlers;
|
|
1310
|
+
if (handlers.onPointerOver || handlers.onPointerEnter || handlers.onPointerOut || handlers.onPointerLeave) {
|
|
1311
|
+
const id = makeId(data);
|
|
1312
|
+
const pointerState = getPointerState(internal, pointerId);
|
|
1313
|
+
const hoveredItem = pointerState.hovered.get(id);
|
|
1314
|
+
if (!hoveredItem) {
|
|
1315
|
+
pointerState.hovered.set(id, data);
|
|
1316
|
+
handlers.onPointerOver?.(data);
|
|
1317
|
+
handlers.onPointerEnter?.(data);
|
|
1318
|
+
} else if (hoveredItem.stopped) {
|
|
1319
|
+
data.stopPropagation();
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
handlers.onPointerMove?.(data);
|
|
1323
|
+
}
|
|
1324
|
+
handleIntersects(hits, event, 0, onIntersect);
|
|
1325
|
+
}
|
|
1240
1326
|
function handlePointer(name) {
|
|
1241
1327
|
switch (name) {
|
|
1242
1328
|
case "onPointerLeave":
|
|
1243
|
-
case "onPointerCancel":
|
|
1244
1329
|
case "onDragLeave":
|
|
1245
1330
|
return () => cancelPointer([]);
|
|
1331
|
+
// Global cancel of these events
|
|
1332
|
+
case "onPointerCancel":
|
|
1333
|
+
return (event) => {
|
|
1334
|
+
const pointerId = getPointerId(event);
|
|
1335
|
+
cleanupPointer(pointerId);
|
|
1336
|
+
};
|
|
1246
1337
|
case "onLostPointerCapture":
|
|
1247
1338
|
return (event) => {
|
|
1248
1339
|
const { internal } = store.getState();
|
|
1249
|
-
|
|
1340
|
+
const pointerId = getPointerId(event);
|
|
1341
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1342
|
+
if (pointerState?.captured.size) {
|
|
1250
1343
|
requestAnimationFrame(() => {
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1344
|
+
const pointerState2 = internal.pointerMap.get(pointerId);
|
|
1345
|
+
if (pointerState2?.captured.size) {
|
|
1346
|
+
pointerState2.captured.clear();
|
|
1254
1347
|
}
|
|
1348
|
+
cancelPointer([], pointerId);
|
|
1255
1349
|
});
|
|
1256
1350
|
}
|
|
1257
1351
|
};
|
|
1258
1352
|
}
|
|
1259
1353
|
return function handleEvent(event) {
|
|
1260
1354
|
const state = store.getState();
|
|
1261
|
-
const { onPointerMissed, onDragOverMissed, onDropMissed, internal } = state;
|
|
1355
|
+
const { onPointerMissed, onDragOverMissed, onDropMissed, internal, events } = state;
|
|
1356
|
+
const pointerId = getPointerId(event);
|
|
1262
1357
|
internal.lastEvent.current = event;
|
|
1263
|
-
if (!
|
|
1358
|
+
if (!events.enabled) return;
|
|
1264
1359
|
const isPointerMove = name === "onPointerMove";
|
|
1265
1360
|
const isDragOver = name === "onDragOver";
|
|
1266
1361
|
const isDrop = name === "onDrop";
|
|
1267
1362
|
const isClickEvent = name === "onClick" || name === "onContextMenu" || name === "onDoubleClick";
|
|
1363
|
+
const isPointerDown = name === "onPointerDown";
|
|
1364
|
+
const isPointerUp = name === "onPointerUp";
|
|
1365
|
+
const isWheel = name === "onWheel";
|
|
1366
|
+
const canDeferRaycasts = events.frameTimedRaycasts && state.frameloop === "always";
|
|
1367
|
+
if (isPointerMove && canDeferRaycasts) {
|
|
1368
|
+
events.compute?.(event, state);
|
|
1369
|
+
internal.pointerDirty.set(pointerId, event);
|
|
1370
|
+
return;
|
|
1371
|
+
}
|
|
1372
|
+
if (isWheel && canDeferRaycasts && !events.alwaysFireOnScroll) {
|
|
1373
|
+
events.compute?.(event, state);
|
|
1374
|
+
internal.pointerDirty.set(pointerId, event);
|
|
1375
|
+
return;
|
|
1376
|
+
}
|
|
1377
|
+
if ((isClickEvent || isPointerDown || isPointerUp) && internal.pointerDirty.has(pointerId)) {
|
|
1378
|
+
const deferredEvent = internal.pointerDirty.get(pointerId);
|
|
1379
|
+
internal.pointerDirty.delete(pointerId);
|
|
1380
|
+
processDeferredPointer(deferredEvent, pointerId);
|
|
1381
|
+
}
|
|
1268
1382
|
const filter = isPointerMove || isDragOver || isDrop ? filterPointerEvents : void 0;
|
|
1269
1383
|
const hits = intersect(event, filter);
|
|
1270
|
-
const delta = isClickEvent ? calculateDistance(event) : 0;
|
|
1271
|
-
if (
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1384
|
+
const delta = isClickEvent ? calculateDistance(event, pointerId) : 0;
|
|
1385
|
+
if (isPointerDown) {
|
|
1386
|
+
const pointerState2 = getPointerState(internal, pointerId);
|
|
1387
|
+
pointerState2.initialClick = [event.offsetX, event.offsetY];
|
|
1388
|
+
pointerState2.initialHits = hits.map((hit) => hit.eventObject);
|
|
1389
|
+
}
|
|
1390
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1391
|
+
const initialHits = pointerState?.initialHits ?? [];
|
|
1275
1392
|
if (isClickEvent && !hits.length) {
|
|
1276
1393
|
if (delta <= 2) {
|
|
1277
1394
|
pointerMissed(event, internal.interaction);
|
|
@@ -1286,7 +1403,9 @@ function createEvents(store) {
|
|
|
1286
1403
|
dropMissed(event, internal.interaction);
|
|
1287
1404
|
if (onDropMissed) onDropMissed(event);
|
|
1288
1405
|
}
|
|
1289
|
-
if (isPointerMove || isDragOver)
|
|
1406
|
+
if (isPointerMove || isDragOver) {
|
|
1407
|
+
cancelPointer(hits, pointerId);
|
|
1408
|
+
}
|
|
1290
1409
|
function onIntersect(data) {
|
|
1291
1410
|
const eventObject = data.eventObject;
|
|
1292
1411
|
const instance = eventObject.__r3f;
|
|
@@ -1295,9 +1414,10 @@ function createEvents(store) {
|
|
|
1295
1414
|
if (isPointerMove) {
|
|
1296
1415
|
if (handlers.onPointerOver || handlers.onPointerEnter || handlers.onPointerOut || handlers.onPointerLeave) {
|
|
1297
1416
|
const id = makeId(data);
|
|
1298
|
-
const
|
|
1417
|
+
const pointerState2 = getPointerState(internal, pointerId);
|
|
1418
|
+
const hoveredItem = pointerState2.hovered.get(id);
|
|
1299
1419
|
if (!hoveredItem) {
|
|
1300
|
-
|
|
1420
|
+
pointerState2.hovered.set(id, data);
|
|
1301
1421
|
handlers.onPointerOver?.(data);
|
|
1302
1422
|
handlers.onPointerEnter?.(data);
|
|
1303
1423
|
} else if (hoveredItem.stopped) {
|
|
@@ -1307,9 +1427,10 @@ function createEvents(store) {
|
|
|
1307
1427
|
handlers.onPointerMove?.(data);
|
|
1308
1428
|
} else if (isDragOver) {
|
|
1309
1429
|
const id = makeId(data);
|
|
1310
|
-
const
|
|
1430
|
+
const pointerState2 = getPointerState(internal, pointerId);
|
|
1431
|
+
const hoveredItem = pointerState2.hovered.get(id);
|
|
1311
1432
|
if (!hoveredItem) {
|
|
1312
|
-
|
|
1433
|
+
pointerState2.hovered.set(id, data);
|
|
1313
1434
|
handlers.onDragOverEnter?.(data);
|
|
1314
1435
|
} else if (hoveredItem.stopped) {
|
|
1315
1436
|
data.stopPropagation();
|
|
@@ -1320,18 +1441,18 @@ function createEvents(store) {
|
|
|
1320
1441
|
} else {
|
|
1321
1442
|
const handler = handlers[name];
|
|
1322
1443
|
if (handler) {
|
|
1323
|
-
if (!isClickEvent ||
|
|
1444
|
+
if (!isClickEvent || initialHits.includes(eventObject)) {
|
|
1324
1445
|
pointerMissed(
|
|
1325
1446
|
event,
|
|
1326
|
-
internal.interaction.filter((object) => !
|
|
1447
|
+
internal.interaction.filter((object) => !initialHits.includes(object))
|
|
1327
1448
|
);
|
|
1328
1449
|
handler(data);
|
|
1329
1450
|
}
|
|
1330
1451
|
} else {
|
|
1331
|
-
if (isClickEvent &&
|
|
1452
|
+
if (isClickEvent && initialHits.includes(eventObject)) {
|
|
1332
1453
|
pointerMissed(
|
|
1333
1454
|
event,
|
|
1334
|
-
internal.interaction.filter((object) => !
|
|
1455
|
+
internal.interaction.filter((object) => !initialHits.includes(object))
|
|
1335
1456
|
);
|
|
1336
1457
|
}
|
|
1337
1458
|
}
|
|
@@ -1340,7 +1461,15 @@ function createEvents(store) {
|
|
|
1340
1461
|
handleIntersects(hits, event, delta, onIntersect);
|
|
1341
1462
|
};
|
|
1342
1463
|
}
|
|
1343
|
-
|
|
1464
|
+
function flushDeferredPointers() {
|
|
1465
|
+
const { internal, events } = store.getState();
|
|
1466
|
+
if (!events.frameTimedRaycasts) return;
|
|
1467
|
+
for (const [pointerId, event] of internal.pointerDirty) {
|
|
1468
|
+
processDeferredPointer(event, pointerId);
|
|
1469
|
+
}
|
|
1470
|
+
internal.pointerDirty.clear();
|
|
1471
|
+
}
|
|
1472
|
+
return { handlePointer, flushDeferredPointers, processDeferredPointer };
|
|
1344
1473
|
}
|
|
1345
1474
|
const DOM_EVENTS = {
|
|
1346
1475
|
onClick: ["click", false],
|
|
@@ -1359,10 +1488,15 @@ const DOM_EVENTS = {
|
|
|
1359
1488
|
onLostPointerCapture: ["lostpointercapture", true]
|
|
1360
1489
|
};
|
|
1361
1490
|
function createPointerEvents(store) {
|
|
1362
|
-
const { handlePointer } = createEvents(store);
|
|
1491
|
+
const { handlePointer, flushDeferredPointers, processDeferredPointer } = createEvents(store);
|
|
1492
|
+
let nextXRPointerId = XR_POINTER_ID_START;
|
|
1493
|
+
const xrPointers = /* @__PURE__ */ new Map();
|
|
1363
1494
|
return {
|
|
1364
1495
|
priority: 1,
|
|
1365
1496
|
enabled: true,
|
|
1497
|
+
frameTimedRaycasts: true,
|
|
1498
|
+
alwaysFireOnScroll: true,
|
|
1499
|
+
updateOnFrame: false,
|
|
1366
1500
|
compute(event, state) {
|
|
1367
1501
|
state.pointer.set(event.offsetX / state.size.width * 2 - 1, -(event.offsetY / state.size.height) * 2 + 1);
|
|
1368
1502
|
state.raycaster.setFromCamera(state.pointer, state.camera);
|
|
@@ -1372,9 +1506,30 @@ function createPointerEvents(store) {
|
|
|
1372
1506
|
(acc, key) => ({ ...acc, [key]: handlePointer(key) }),
|
|
1373
1507
|
{}
|
|
1374
1508
|
),
|
|
1375
|
-
update: () => {
|
|
1509
|
+
update: (pointerId) => {
|
|
1510
|
+
const { events, internal } = store.getState();
|
|
1511
|
+
if (!events.handlers) return;
|
|
1512
|
+
if (pointerId !== void 0) {
|
|
1513
|
+
const event = internal.pointerDirty.get(pointerId);
|
|
1514
|
+
if (event) {
|
|
1515
|
+
internal.pointerDirty.delete(pointerId);
|
|
1516
|
+
processDeferredPointer(event, pointerId);
|
|
1517
|
+
} else if (internal.lastEvent?.current) {
|
|
1518
|
+
processDeferredPointer(internal.lastEvent.current, pointerId);
|
|
1519
|
+
}
|
|
1520
|
+
} else {
|
|
1521
|
+
flushDeferredPointers();
|
|
1522
|
+
if (internal.lastEvent?.current) {
|
|
1523
|
+
events.handlers.onPointerMove(internal.lastEvent.current);
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
},
|
|
1527
|
+
flush: () => {
|
|
1376
1528
|
const { events, internal } = store.getState();
|
|
1377
|
-
|
|
1529
|
+
flushDeferredPointers();
|
|
1530
|
+
if (events.updateOnFrame && internal.lastEvent?.current && events.handlers) {
|
|
1531
|
+
events.handlers.onPointerMove(internal.lastEvent.current);
|
|
1532
|
+
}
|
|
1378
1533
|
},
|
|
1379
1534
|
connect: (target) => {
|
|
1380
1535
|
const { set, events } = store.getState();
|
|
@@ -1400,6 +1555,32 @@ function createPointerEvents(store) {
|
|
|
1400
1555
|
}
|
|
1401
1556
|
set((state) => ({ events: { ...state.events, connected: void 0 } }));
|
|
1402
1557
|
}
|
|
1558
|
+
},
|
|
1559
|
+
registerPointer: (config) => {
|
|
1560
|
+
const pointerId = nextXRPointerId++;
|
|
1561
|
+
xrPointers.set(pointerId, config);
|
|
1562
|
+
const { internal } = store.getState();
|
|
1563
|
+
getPointerState(internal, pointerId);
|
|
1564
|
+
return pointerId;
|
|
1565
|
+
},
|
|
1566
|
+
unregisterPointer: (pointerId) => {
|
|
1567
|
+
xrPointers.delete(pointerId);
|
|
1568
|
+
const { internal } = store.getState();
|
|
1569
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1570
|
+
if (pointerState) {
|
|
1571
|
+
for (const [, hoveredObj] of pointerState.hovered) {
|
|
1572
|
+
const eventObject = hoveredObj.eventObject;
|
|
1573
|
+
const instance = eventObject.__r3f;
|
|
1574
|
+
if (instance?.eventCount) {
|
|
1575
|
+
const handlers = instance.handlers;
|
|
1576
|
+
const data = { ...hoveredObj, intersections: [] };
|
|
1577
|
+
handlers.onPointerOut?.(data);
|
|
1578
|
+
handlers.onPointerLeave?.(data);
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
internal.pointerMap.delete(pointerId);
|
|
1582
|
+
}
|
|
1583
|
+
internal.pointerDirty.delete(pointerId);
|
|
1403
1584
|
}
|
|
1404
1585
|
};
|
|
1405
1586
|
}
|
|
@@ -2530,7 +2711,14 @@ const createStore = (invalidate, advance) => {
|
|
|
2530
2711
|
frustum: new webgpu.Frustum(),
|
|
2531
2712
|
autoUpdateFrustum: true,
|
|
2532
2713
|
raycaster: null,
|
|
2533
|
-
events: {
|
|
2714
|
+
events: {
|
|
2715
|
+
priority: 1,
|
|
2716
|
+
enabled: true,
|
|
2717
|
+
connected: false,
|
|
2718
|
+
frameTimedRaycasts: true,
|
|
2719
|
+
alwaysFireOnScroll: true,
|
|
2720
|
+
updateOnFrame: false
|
|
2721
|
+
},
|
|
2534
2722
|
scene: null,
|
|
2535
2723
|
rootScene: null,
|
|
2536
2724
|
xr: null,
|
|
@@ -2621,11 +2809,13 @@ const createStore = (invalidate, advance) => {
|
|
|
2621
2809
|
},
|
|
2622
2810
|
setError: (error) => set(() => ({ error })),
|
|
2623
2811
|
error: null,
|
|
2624
|
-
//* TSL State (managed via hooks: useUniforms, useNodes, useTextures,
|
|
2812
|
+
//* TSL State (managed via hooks: useUniforms, useNodes, useBuffers, useGPUStorage, useTextures, useRenderPipeline) ==============================
|
|
2625
2813
|
uniforms: {},
|
|
2626
2814
|
nodes: {},
|
|
2815
|
+
buffers: {},
|
|
2816
|
+
gpuStorage: {},
|
|
2627
2817
|
textures: /* @__PURE__ */ new Map(),
|
|
2628
|
-
|
|
2818
|
+
renderPipeline: null,
|
|
2629
2819
|
passes: {},
|
|
2630
2820
|
_hmrVersion: 0,
|
|
2631
2821
|
_sizeImperative: false,
|
|
@@ -2634,12 +2824,16 @@ const createStore = (invalidate, advance) => {
|
|
|
2634
2824
|
internal: {
|
|
2635
2825
|
// Events
|
|
2636
2826
|
interaction: [],
|
|
2637
|
-
hovered: /* @__PURE__ */ new Map(),
|
|
2638
2827
|
subscribers: [],
|
|
2828
|
+
// Per-pointer state (new unified structure)
|
|
2829
|
+
pointerMap: /* @__PURE__ */ new Map(),
|
|
2830
|
+
pointerDirty: /* @__PURE__ */ new Map(),
|
|
2831
|
+
lastEvent: React__namespace.createRef(),
|
|
2832
|
+
// Deprecated but kept for backwards compatibility
|
|
2833
|
+
hovered: /* @__PURE__ */ new Map(),
|
|
2639
2834
|
initialClick: [0, 0],
|
|
2640
2835
|
initialHits: [],
|
|
2641
2836
|
capturedMap: /* @__PURE__ */ new Map(),
|
|
2642
|
-
lastEvent: React__namespace.createRef(),
|
|
2643
2837
|
// Visibility tracking (onFramed, onOccluded, onVisible)
|
|
2644
2838
|
visibilityRegistry: /* @__PURE__ */ new Map(),
|
|
2645
2839
|
// Occlusion system (WebGPU only)
|
|
@@ -15071,6 +15265,12 @@ function createRoot(canvas) {
|
|
|
15071
15265
|
} else if (!state.internal.actualRenderer) {
|
|
15072
15266
|
renderer = await resolveRenderer(rendererConfig, defaultGPUProps, webgpu.WebGPURenderer);
|
|
15073
15267
|
if (!renderer.hasInitialized?.()) {
|
|
15268
|
+
const size2 = computeInitialSize(canvas, propsSize);
|
|
15269
|
+
if (size2.width > 0 && size2.height > 0) {
|
|
15270
|
+
const pixelRatio = calculateDpr(dpr);
|
|
15271
|
+
canvas.width = size2.width * pixelRatio;
|
|
15272
|
+
canvas.height = size2.height * pixelRatio;
|
|
15273
|
+
}
|
|
15074
15274
|
await renderer.init();
|
|
15075
15275
|
}
|
|
15076
15276
|
const backend = renderer.backend;
|
|
@@ -15272,6 +15472,18 @@ function createRoot(canvas) {
|
|
|
15272
15472
|
system: true
|
|
15273
15473
|
}
|
|
15274
15474
|
);
|
|
15475
|
+
const unregisterEventsFlush = scheduler.register(
|
|
15476
|
+
() => {
|
|
15477
|
+
const state2 = store.getState();
|
|
15478
|
+
state2.events.flush?.();
|
|
15479
|
+
},
|
|
15480
|
+
{
|
|
15481
|
+
id: `${newRootId}_events`,
|
|
15482
|
+
rootId: newRootId,
|
|
15483
|
+
phase: "input",
|
|
15484
|
+
system: true
|
|
15485
|
+
}
|
|
15486
|
+
);
|
|
15275
15487
|
const unregisterFrustum = scheduler.register(
|
|
15276
15488
|
() => {
|
|
15277
15489
|
const state2 = store.getState();
|
|
@@ -15306,7 +15518,7 @@ function createRoot(canvas) {
|
|
|
15306
15518
|
const userHandlesRender = scheduler.hasUserJobsInPhase("render", newRootId);
|
|
15307
15519
|
if (userHandlesRender || state2.internal.priority) return;
|
|
15308
15520
|
try {
|
|
15309
|
-
if (state2.
|
|
15521
|
+
if (state2.renderPipeline?.render) state2.renderPipeline.render();
|
|
15310
15522
|
else if (renderer2?.render) renderer2.render(state2.scene, state2.camera);
|
|
15311
15523
|
} catch (error) {
|
|
15312
15524
|
state2.setError(error instanceof Error ? error : new Error(String(error)));
|
|
@@ -15331,6 +15543,7 @@ function createRoot(canvas) {
|
|
|
15331
15543
|
unregisterRoot: () => {
|
|
15332
15544
|
unregisterRoot();
|
|
15333
15545
|
unregisterCanvasTarget();
|
|
15546
|
+
unregisterEventsFlush();
|
|
15334
15547
|
unregisterFrustum();
|
|
15335
15548
|
unregisterVisibility();
|
|
15336
15549
|
unregisterRender();
|
|
@@ -15496,9 +15709,13 @@ function PortalInner({ state = {}, children, container }) {
|
|
|
15496
15709
|
const store = traditional.createWithEqualityFn((set, get) => ({ ...rest, set, get }));
|
|
15497
15710
|
const onMutate = (prev) => store.setState((state2) => inject.current(prev, state2));
|
|
15498
15711
|
onMutate(previousRoot.getState());
|
|
15499
|
-
previousRoot.subscribe(onMutate);
|
|
15500
15712
|
return store;
|
|
15501
15713
|
}, [previousRoot, container]);
|
|
15714
|
+
useIsomorphicLayoutEffect(() => {
|
|
15715
|
+
const onMutate = (prev) => usePortalStore.setState((state2) => inject.current(prev, state2));
|
|
15716
|
+
const unsubscribe = previousRoot.subscribe(onMutate);
|
|
15717
|
+
return unsubscribe;
|
|
15718
|
+
}, [previousRoot, usePortalStore]);
|
|
15502
15719
|
return (
|
|
15503
15720
|
// @ts-ignore, reconciler types are not maintained
|
|
15504
15721
|
/* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: reconciler.createPortal(
|
|
@@ -15719,6 +15936,7 @@ function CanvasImpl({
|
|
|
15719
15936
|
queueMicrotask(() => {
|
|
15720
15937
|
const rootEntry = _roots.get(canvas);
|
|
15721
15938
|
if (rootEntry?.store) {
|
|
15939
|
+
console.log("[R3F] HMR detected \u2014 rebuilding nodes/uniforms");
|
|
15722
15940
|
rootEntry.store.setState((state) => ({
|
|
15723
15941
|
nodes: {},
|
|
15724
15942
|
uniforms: {},
|
|
@@ -15730,8 +15948,7 @@ function CanvasImpl({
|
|
|
15730
15948
|
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) {
|
|
15731
15949
|
const hot = undefined;
|
|
15732
15950
|
hot.on("vite:afterUpdate", handleHMR);
|
|
15733
|
-
return () => hot.
|
|
15734
|
-
});
|
|
15951
|
+
return () => hot.off?.("vite:afterUpdate", handleHMR);
|
|
15735
15952
|
}
|
|
15736
15953
|
if (typeof module !== "undefined" && module.hot) {
|
|
15737
15954
|
const hot = module.hot;
|
|
@@ -15830,6 +16047,8 @@ function createScopedStore(data) {
|
|
|
15830
16047
|
function createLazyCreatorState(state) {
|
|
15831
16048
|
let _uniforms = null;
|
|
15832
16049
|
let _nodes = null;
|
|
16050
|
+
let _buffers = null;
|
|
16051
|
+
let _gpuStorage = null;
|
|
15833
16052
|
return Object.create(state, {
|
|
15834
16053
|
uniforms: {
|
|
15835
16054
|
get() {
|
|
@@ -15840,6 +16059,16 @@ function createLazyCreatorState(state) {
|
|
|
15840
16059
|
get() {
|
|
15841
16060
|
return _nodes ?? (_nodes = createScopedStore(state.nodes));
|
|
15842
16061
|
}
|
|
16062
|
+
},
|
|
16063
|
+
buffers: {
|
|
16064
|
+
get() {
|
|
16065
|
+
return _buffers ?? (_buffers = createScopedStore(state.buffers));
|
|
16066
|
+
}
|
|
16067
|
+
},
|
|
16068
|
+
gpuStorage: {
|
|
16069
|
+
get() {
|
|
16070
|
+
return _gpuStorage ?? (_gpuStorage = createScopedStore(state.gpuStorage));
|
|
16071
|
+
}
|
|
15843
16072
|
}
|
|
15844
16073
|
});
|
|
15845
16074
|
}
|
|
@@ -15922,6 +16151,10 @@ function vectorize(inObject) {
|
|
|
15922
16151
|
if (obj.isVector2 || obj.isVector3 || obj.isVector4) return inObject;
|
|
15923
16152
|
if (obj.isMatrix3 || obj.isMatrix4) return inObject;
|
|
15924
16153
|
if (obj.isColor || obj.isEuler || obj.isQuaternion || obj.isSpherical) return inObject;
|
|
16154
|
+
if ("r" in obj && "g" in obj && "b" in obj && typeof obj.r === "number" && typeof obj.g === "number" && typeof obj.b === "number") {
|
|
16155
|
+
const scale = obj.r > 1 || obj.g > 1 || obj.b > 1 ? 1 / 255 : 1;
|
|
16156
|
+
return new webgpu.Color(obj.r * scale, obj.g * scale, obj.b * scale);
|
|
16157
|
+
}
|
|
15925
16158
|
if ("x" in obj && "y" in obj && typeof obj.x === "number" && typeof obj.y === "number") {
|
|
15926
16159
|
if ("w" in obj && typeof obj.w === "number" && "z" in obj && typeof obj.z === "number") {
|
|
15927
16160
|
return new webgpu.Vector4(obj.x, obj.y, obj.z, obj.w);
|
|
@@ -16377,7 +16610,351 @@ function useLocalNodes(creator) {
|
|
|
16377
16610
|
}, [store, creator, uniforms, nodes, textures, hmrVersion]);
|
|
16378
16611
|
}
|
|
16379
16612
|
|
|
16380
|
-
|
|
16613
|
+
const isBufferLike = (value) => {
|
|
16614
|
+
if (value === null || typeof value !== "object") return false;
|
|
16615
|
+
if (ArrayBuffer.isView(value)) return true;
|
|
16616
|
+
if ("isBufferAttribute" in value) return true;
|
|
16617
|
+
if ("uuid" in value || "nodeType" in value) return true;
|
|
16618
|
+
return false;
|
|
16619
|
+
};
|
|
16620
|
+
const disposeBuffer = (buffer) => {
|
|
16621
|
+
if (buffer === null || typeof buffer !== "object") return;
|
|
16622
|
+
if ("dispose" in buffer && typeof buffer.dispose === "function") {
|
|
16623
|
+
buffer.dispose();
|
|
16624
|
+
}
|
|
16625
|
+
};
|
|
16626
|
+
function useBuffers(creatorOrScope, scope) {
|
|
16627
|
+
const store = useStore();
|
|
16628
|
+
const removeBuffers = React.useCallback(
|
|
16629
|
+
(names, targetScope) => {
|
|
16630
|
+
const nameArray = Array.isArray(names) ? names : [names];
|
|
16631
|
+
store.setState((state) => {
|
|
16632
|
+
if (targetScope) {
|
|
16633
|
+
const currentScope = { ...state.buffers[targetScope] };
|
|
16634
|
+
for (const name of nameArray) delete currentScope[name];
|
|
16635
|
+
return { buffers: { ...state.buffers, [targetScope]: currentScope } };
|
|
16636
|
+
}
|
|
16637
|
+
const buffers2 = { ...state.buffers };
|
|
16638
|
+
for (const name of nameArray) if (isBufferLike(buffers2[name])) delete buffers2[name];
|
|
16639
|
+
return { buffers: buffers2 };
|
|
16640
|
+
});
|
|
16641
|
+
},
|
|
16642
|
+
[store]
|
|
16643
|
+
);
|
|
16644
|
+
const clearBuffers = React.useCallback(
|
|
16645
|
+
(targetScope) => {
|
|
16646
|
+
store.setState((state) => {
|
|
16647
|
+
if (targetScope && targetScope !== "root") {
|
|
16648
|
+
const { [targetScope]: _, ...rest } = state.buffers;
|
|
16649
|
+
return { buffers: rest };
|
|
16650
|
+
}
|
|
16651
|
+
if (targetScope === "root") {
|
|
16652
|
+
const buffers2 = {};
|
|
16653
|
+
for (const [key, value] of Object.entries(state.buffers)) {
|
|
16654
|
+
if (!isBufferLike(value)) buffers2[key] = value;
|
|
16655
|
+
}
|
|
16656
|
+
return { buffers: buffers2 };
|
|
16657
|
+
}
|
|
16658
|
+
return { buffers: {} };
|
|
16659
|
+
});
|
|
16660
|
+
},
|
|
16661
|
+
[store]
|
|
16662
|
+
);
|
|
16663
|
+
const rebuildBuffers = React.useCallback(
|
|
16664
|
+
(targetScope) => {
|
|
16665
|
+
store.setState((state) => {
|
|
16666
|
+
let newBuffers = state.buffers;
|
|
16667
|
+
if (targetScope && targetScope !== "root") {
|
|
16668
|
+
const { [targetScope]: _, ...rest } = state.buffers;
|
|
16669
|
+
newBuffers = rest;
|
|
16670
|
+
} else if (targetScope === "root") {
|
|
16671
|
+
newBuffers = {};
|
|
16672
|
+
for (const [key, value] of Object.entries(state.buffers)) {
|
|
16673
|
+
if (!isBufferLike(value)) newBuffers[key] = value;
|
|
16674
|
+
}
|
|
16675
|
+
} else {
|
|
16676
|
+
newBuffers = {};
|
|
16677
|
+
}
|
|
16678
|
+
return { buffers: newBuffers, _hmrVersion: state._hmrVersion + 1 };
|
|
16679
|
+
});
|
|
16680
|
+
},
|
|
16681
|
+
[store]
|
|
16682
|
+
);
|
|
16683
|
+
const disposeBuffers = React.useCallback(
|
|
16684
|
+
(names, targetScope) => {
|
|
16685
|
+
const nameArray = Array.isArray(names) ? names : [names];
|
|
16686
|
+
const state = store.getState();
|
|
16687
|
+
for (const name of nameArray) {
|
|
16688
|
+
const buffer = targetScope ? state.buffers[targetScope]?.[name] : state.buffers[name];
|
|
16689
|
+
if (buffer && isBufferLike(buffer)) {
|
|
16690
|
+
disposeBuffer(buffer);
|
|
16691
|
+
}
|
|
16692
|
+
}
|
|
16693
|
+
removeBuffers(names, targetScope);
|
|
16694
|
+
},
|
|
16695
|
+
[store, removeBuffers]
|
|
16696
|
+
);
|
|
16697
|
+
const isReader = creatorOrScope === void 0 || typeof creatorOrScope === "string";
|
|
16698
|
+
const storeBuffers = useThree((s) => s.buffers);
|
|
16699
|
+
const hmrVersion = useThree((s) => s._hmrVersion);
|
|
16700
|
+
const scopeDep = typeof creatorOrScope === "string" ? creatorOrScope : scope;
|
|
16701
|
+
const readerDep = isReader ? storeBuffers : null;
|
|
16702
|
+
const creatorDep = isReader ? null : hmrVersion;
|
|
16703
|
+
const buffers = React.useMemo(() => {
|
|
16704
|
+
if (creatorOrScope === void 0) {
|
|
16705
|
+
return storeBuffers;
|
|
16706
|
+
}
|
|
16707
|
+
if (typeof creatorOrScope === "string") {
|
|
16708
|
+
const scopeData = storeBuffers[creatorOrScope];
|
|
16709
|
+
if (scopeData && !isBufferLike(scopeData)) return scopeData;
|
|
16710
|
+
return {};
|
|
16711
|
+
}
|
|
16712
|
+
const state = store.getState();
|
|
16713
|
+
const set = store.setState;
|
|
16714
|
+
const creator = creatorOrScope;
|
|
16715
|
+
const wrappedState = createLazyCreatorState(state);
|
|
16716
|
+
const created = creator(wrappedState);
|
|
16717
|
+
const result = {};
|
|
16718
|
+
let hasNewBuffers = false;
|
|
16719
|
+
if (scope) {
|
|
16720
|
+
const currentScope = state.buffers[scope] ?? {};
|
|
16721
|
+
for (const [name, buffer] of Object.entries(created)) {
|
|
16722
|
+
if (currentScope[name]) {
|
|
16723
|
+
result[name] = currentScope[name];
|
|
16724
|
+
} else {
|
|
16725
|
+
if ("setName" in buffer && typeof buffer.setName === "function") {
|
|
16726
|
+
buffer.setName(`${scope}.${name}`);
|
|
16727
|
+
}
|
|
16728
|
+
result[name] = buffer;
|
|
16729
|
+
hasNewBuffers = true;
|
|
16730
|
+
}
|
|
16731
|
+
}
|
|
16732
|
+
if (hasNewBuffers) {
|
|
16733
|
+
set((s) => ({
|
|
16734
|
+
buffers: {
|
|
16735
|
+
...s.buffers,
|
|
16736
|
+
[scope]: { ...s.buffers[scope], ...result }
|
|
16737
|
+
}
|
|
16738
|
+
}));
|
|
16739
|
+
}
|
|
16740
|
+
return result;
|
|
16741
|
+
}
|
|
16742
|
+
for (const [name, buffer] of Object.entries(created)) {
|
|
16743
|
+
const existing = state.buffers[name];
|
|
16744
|
+
if (existing && isBufferLike(existing)) {
|
|
16745
|
+
result[name] = existing;
|
|
16746
|
+
} else {
|
|
16747
|
+
if ("setName" in buffer && typeof buffer.setName === "function") {
|
|
16748
|
+
buffer.setName(name);
|
|
16749
|
+
}
|
|
16750
|
+
result[name] = buffer;
|
|
16751
|
+
hasNewBuffers = true;
|
|
16752
|
+
}
|
|
16753
|
+
}
|
|
16754
|
+
if (hasNewBuffers) {
|
|
16755
|
+
set((s) => ({ buffers: { ...s.buffers, ...result } }));
|
|
16756
|
+
}
|
|
16757
|
+
return result;
|
|
16758
|
+
}, [store, scopeDep, readerDep, creatorDep]);
|
|
16759
|
+
return { ...buffers, removeBuffers, clearBuffers, rebuildBuffers, disposeBuffers };
|
|
16760
|
+
}
|
|
16761
|
+
function rebuildAllBuffers(store, scope) {
|
|
16762
|
+
store.setState((state) => {
|
|
16763
|
+
let newBuffers = state.buffers;
|
|
16764
|
+
if (scope && scope !== "root") {
|
|
16765
|
+
const { [scope]: _, ...rest } = state.buffers;
|
|
16766
|
+
newBuffers = rest;
|
|
16767
|
+
} else if (scope === "root") {
|
|
16768
|
+
newBuffers = {};
|
|
16769
|
+
for (const [key, value] of Object.entries(state.buffers)) {
|
|
16770
|
+
if (!isBufferLike(value)) newBuffers[key] = value;
|
|
16771
|
+
}
|
|
16772
|
+
} else {
|
|
16773
|
+
newBuffers = {};
|
|
16774
|
+
}
|
|
16775
|
+
return { buffers: newBuffers, _hmrVersion: state._hmrVersion + 1 };
|
|
16776
|
+
});
|
|
16777
|
+
}
|
|
16778
|
+
|
|
16779
|
+
const isStorageLike = (value) => {
|
|
16780
|
+
if (value === null || typeof value !== "object") return false;
|
|
16781
|
+
if ("isTexture" in value) return true;
|
|
16782
|
+
if ("isData3DTexture" in value) return true;
|
|
16783
|
+
if ("uuid" in value || "nodeType" in value) return true;
|
|
16784
|
+
return false;
|
|
16785
|
+
};
|
|
16786
|
+
const disposeStorage = (storage) => {
|
|
16787
|
+
if (storage === null || typeof storage !== "object") return;
|
|
16788
|
+
if ("dispose" in storage && typeof storage.dispose === "function") {
|
|
16789
|
+
storage.dispose();
|
|
16790
|
+
}
|
|
16791
|
+
};
|
|
16792
|
+
function useGPUStorage(creatorOrScope, scope) {
|
|
16793
|
+
const store = useStore();
|
|
16794
|
+
const removeStorage = React.useCallback(
|
|
16795
|
+
(names, targetScope) => {
|
|
16796
|
+
const nameArray = Array.isArray(names) ? names : [names];
|
|
16797
|
+
store.setState((state) => {
|
|
16798
|
+
if (targetScope) {
|
|
16799
|
+
const currentScope = { ...state.gpuStorage[targetScope] };
|
|
16800
|
+
for (const name of nameArray) delete currentScope[name];
|
|
16801
|
+
return { gpuStorage: { ...state.gpuStorage, [targetScope]: currentScope } };
|
|
16802
|
+
}
|
|
16803
|
+
const gpuStorage2 = { ...state.gpuStorage };
|
|
16804
|
+
for (const name of nameArray) if (isStorageLike(gpuStorage2[name])) delete gpuStorage2[name];
|
|
16805
|
+
return { gpuStorage: gpuStorage2 };
|
|
16806
|
+
});
|
|
16807
|
+
},
|
|
16808
|
+
[store]
|
|
16809
|
+
);
|
|
16810
|
+
const clearStorage = React.useCallback(
|
|
16811
|
+
(targetScope) => {
|
|
16812
|
+
store.setState((state) => {
|
|
16813
|
+
if (targetScope && targetScope !== "root") {
|
|
16814
|
+
const { [targetScope]: _, ...rest } = state.gpuStorage;
|
|
16815
|
+
return { gpuStorage: rest };
|
|
16816
|
+
}
|
|
16817
|
+
if (targetScope === "root") {
|
|
16818
|
+
const gpuStorage2 = {};
|
|
16819
|
+
for (const [key, value] of Object.entries(state.gpuStorage)) {
|
|
16820
|
+
if (!isStorageLike(value)) gpuStorage2[key] = value;
|
|
16821
|
+
}
|
|
16822
|
+
return { gpuStorage: gpuStorage2 };
|
|
16823
|
+
}
|
|
16824
|
+
return { gpuStorage: {} };
|
|
16825
|
+
});
|
|
16826
|
+
},
|
|
16827
|
+
[store]
|
|
16828
|
+
);
|
|
16829
|
+
const rebuildStorage = React.useCallback(
|
|
16830
|
+
(targetScope) => {
|
|
16831
|
+
store.setState((state) => {
|
|
16832
|
+
let newStorage = state.gpuStorage;
|
|
16833
|
+
if (targetScope && targetScope !== "root") {
|
|
16834
|
+
const { [targetScope]: _, ...rest } = state.gpuStorage;
|
|
16835
|
+
newStorage = rest;
|
|
16836
|
+
} else if (targetScope === "root") {
|
|
16837
|
+
newStorage = {};
|
|
16838
|
+
for (const [key, value] of Object.entries(state.gpuStorage)) {
|
|
16839
|
+
if (!isStorageLike(value)) newStorage[key] = value;
|
|
16840
|
+
}
|
|
16841
|
+
} else {
|
|
16842
|
+
newStorage = {};
|
|
16843
|
+
}
|
|
16844
|
+
return { gpuStorage: newStorage, _hmrVersion: state._hmrVersion + 1 };
|
|
16845
|
+
});
|
|
16846
|
+
},
|
|
16847
|
+
[store]
|
|
16848
|
+
);
|
|
16849
|
+
const disposeStorageFn = React.useCallback(
|
|
16850
|
+
(names, targetScope) => {
|
|
16851
|
+
const nameArray = Array.isArray(names) ? names : [names];
|
|
16852
|
+
const state = store.getState();
|
|
16853
|
+
for (const name of nameArray) {
|
|
16854
|
+
const storage = targetScope ? state.gpuStorage[targetScope]?.[name] : state.gpuStorage[name];
|
|
16855
|
+
if (storage && isStorageLike(storage)) {
|
|
16856
|
+
disposeStorage(storage);
|
|
16857
|
+
}
|
|
16858
|
+
}
|
|
16859
|
+
removeStorage(names, targetScope);
|
|
16860
|
+
},
|
|
16861
|
+
[store, removeStorage]
|
|
16862
|
+
);
|
|
16863
|
+
const isReader = creatorOrScope === void 0 || typeof creatorOrScope === "string";
|
|
16864
|
+
const storeStorage = useThree((s) => s.gpuStorage);
|
|
16865
|
+
const hmrVersion = useThree((s) => s._hmrVersion);
|
|
16866
|
+
const scopeDep = typeof creatorOrScope === "string" ? creatorOrScope : scope;
|
|
16867
|
+
const readerDep = isReader ? storeStorage : null;
|
|
16868
|
+
const creatorDep = isReader ? null : hmrVersion;
|
|
16869
|
+
const gpuStorage = React.useMemo(() => {
|
|
16870
|
+
if (creatorOrScope === void 0) {
|
|
16871
|
+
return storeStorage;
|
|
16872
|
+
}
|
|
16873
|
+
if (typeof creatorOrScope === "string") {
|
|
16874
|
+
const scopeData = storeStorage[creatorOrScope];
|
|
16875
|
+
if (scopeData && !isStorageLike(scopeData)) return scopeData;
|
|
16876
|
+
return {};
|
|
16877
|
+
}
|
|
16878
|
+
const state = store.getState();
|
|
16879
|
+
const set = store.setState;
|
|
16880
|
+
const creator = creatorOrScope;
|
|
16881
|
+
const wrappedState = createLazyCreatorState(state);
|
|
16882
|
+
const created = creator(wrappedState);
|
|
16883
|
+
const result = {};
|
|
16884
|
+
let hasNewStorage = false;
|
|
16885
|
+
if (scope) {
|
|
16886
|
+
const currentScope = state.gpuStorage[scope] ?? {};
|
|
16887
|
+
for (const [name, storage] of Object.entries(created)) {
|
|
16888
|
+
if (currentScope[name]) {
|
|
16889
|
+
result[name] = currentScope[name];
|
|
16890
|
+
} else {
|
|
16891
|
+
if ("setName" in storage && typeof storage.setName === "function") {
|
|
16892
|
+
storage.setName(`${scope}.${name}`);
|
|
16893
|
+
}
|
|
16894
|
+
if ("name" in storage && typeof storage.name === "string") {
|
|
16895
|
+
storage.name = `${scope}.${name}`;
|
|
16896
|
+
}
|
|
16897
|
+
result[name] = storage;
|
|
16898
|
+
hasNewStorage = true;
|
|
16899
|
+
}
|
|
16900
|
+
}
|
|
16901
|
+
if (hasNewStorage) {
|
|
16902
|
+
set((s) => ({
|
|
16903
|
+
gpuStorage: {
|
|
16904
|
+
...s.gpuStorage,
|
|
16905
|
+
[scope]: { ...s.gpuStorage[scope], ...result }
|
|
16906
|
+
}
|
|
16907
|
+
}));
|
|
16908
|
+
}
|
|
16909
|
+
return result;
|
|
16910
|
+
}
|
|
16911
|
+
for (const [name, storage] of Object.entries(created)) {
|
|
16912
|
+
const existing = state.gpuStorage[name];
|
|
16913
|
+
if (existing && isStorageLike(existing)) {
|
|
16914
|
+
result[name] = existing;
|
|
16915
|
+
} else {
|
|
16916
|
+
if ("setName" in storage && typeof storage.setName === "function") {
|
|
16917
|
+
storage.setName(name);
|
|
16918
|
+
}
|
|
16919
|
+
if ("name" in storage && typeof storage.name === "string") {
|
|
16920
|
+
storage.name = name;
|
|
16921
|
+
}
|
|
16922
|
+
result[name] = storage;
|
|
16923
|
+
hasNewStorage = true;
|
|
16924
|
+
}
|
|
16925
|
+
}
|
|
16926
|
+
if (hasNewStorage) {
|
|
16927
|
+
set((s) => ({ gpuStorage: { ...s.gpuStorage, ...result } }));
|
|
16928
|
+
}
|
|
16929
|
+
return result;
|
|
16930
|
+
}, [store, scopeDep, readerDep, creatorDep]);
|
|
16931
|
+
return {
|
|
16932
|
+
...gpuStorage,
|
|
16933
|
+
removeStorage,
|
|
16934
|
+
clearStorage,
|
|
16935
|
+
rebuildStorage,
|
|
16936
|
+
disposeStorage: disposeStorageFn
|
|
16937
|
+
};
|
|
16938
|
+
}
|
|
16939
|
+
function rebuildAllStorage(store, scope) {
|
|
16940
|
+
store.setState((state) => {
|
|
16941
|
+
let newStorage = state.gpuStorage;
|
|
16942
|
+
if (scope && scope !== "root") {
|
|
16943
|
+
const { [scope]: _, ...rest } = state.gpuStorage;
|
|
16944
|
+
newStorage = rest;
|
|
16945
|
+
} else if (scope === "root") {
|
|
16946
|
+
newStorage = {};
|
|
16947
|
+
for (const [key, value] of Object.entries(state.gpuStorage)) {
|
|
16948
|
+
if (!isStorageLike(value)) newStorage[key] = value;
|
|
16949
|
+
}
|
|
16950
|
+
} else {
|
|
16951
|
+
newStorage = {};
|
|
16952
|
+
}
|
|
16953
|
+
return { gpuStorage: newStorage, _hmrVersion: state._hmrVersion + 1 };
|
|
16954
|
+
});
|
|
16955
|
+
}
|
|
16956
|
+
|
|
16957
|
+
function useRenderPipeline(mainCB, setupCB) {
|
|
16381
16958
|
const store = useStore();
|
|
16382
16959
|
const { scene, camera, renderer, isLegacy } = useThree();
|
|
16383
16960
|
const callbacksRanRef = React.useRef(false);
|
|
@@ -16396,7 +16973,7 @@ function usePostProcessing(mainCB, setupCB) {
|
|
|
16396
16973
|
}, [store]);
|
|
16397
16974
|
const reset = React.useCallback(() => {
|
|
16398
16975
|
store.setState({
|
|
16399
|
-
|
|
16976
|
+
renderPipeline: null,
|
|
16400
16977
|
passes: {}
|
|
16401
16978
|
});
|
|
16402
16979
|
callbacksRanRef.current = false;
|
|
@@ -16409,13 +16986,13 @@ function usePostProcessing(mainCB, setupCB) {
|
|
|
16409
16986
|
}, []);
|
|
16410
16987
|
React.useLayoutEffect(() => {
|
|
16411
16988
|
if (isLegacy) {
|
|
16412
|
-
throw new Error("
|
|
16989
|
+
throw new Error("useRenderPipeline is only available with WebGPU renderer. Set renderer prop on Canvas.");
|
|
16413
16990
|
}
|
|
16414
16991
|
if (!renderer || !scene || !camera) return;
|
|
16415
16992
|
const state = store.getState();
|
|
16416
16993
|
const set = store.setState;
|
|
16417
16994
|
try {
|
|
16418
|
-
let pp = state.
|
|
16995
|
+
let pp = state.renderPipeline;
|
|
16419
16996
|
let currentPasses = { ...state.passes };
|
|
16420
16997
|
let justCreatedPP = false;
|
|
16421
16998
|
if (!pp) {
|
|
@@ -16432,7 +17009,7 @@ function usePostProcessing(mainCB, setupCB) {
|
|
|
16432
17009
|
}
|
|
16433
17010
|
currentPasses.scenePass = scenePass;
|
|
16434
17011
|
if (!pp.outputNode || justCreatedPP) pp.outputNode = scenePass;
|
|
16435
|
-
set({
|
|
17012
|
+
set({ renderPipeline: pp, passes: currentPasses });
|
|
16436
17013
|
const shouldRunCallbacks = justCreatedPP || !callbacksRanRef.current || !cacheValid;
|
|
16437
17014
|
if (shouldRunCallbacks) {
|
|
16438
17015
|
if (setupCBRef.current) {
|
|
@@ -16454,19 +17031,19 @@ function usePostProcessing(mainCB, setupCB) {
|
|
|
16454
17031
|
callbacksRanRef.current = true;
|
|
16455
17032
|
}
|
|
16456
17033
|
} catch (error) {
|
|
16457
|
-
console.error("[
|
|
17034
|
+
console.error("[useRenderPipeline] Setup error:", error);
|
|
16458
17035
|
}
|
|
16459
17036
|
}, [store, renderer, scene, camera, isLegacy, rebuildVersion]);
|
|
16460
17037
|
const passes = useThree((s) => s.passes);
|
|
16461
|
-
const
|
|
17038
|
+
const renderPipeline = useThree((s) => s.renderPipeline);
|
|
16462
17039
|
return {
|
|
16463
17040
|
passes,
|
|
16464
|
-
|
|
17041
|
+
renderPipeline,
|
|
16465
17042
|
clearPasses,
|
|
16466
17043
|
reset,
|
|
16467
17044
|
rebuild,
|
|
16468
|
-
// isReady indicates if
|
|
16469
|
-
isReady:
|
|
17045
|
+
// isReady indicates if RenderPipeline is configured and ready for rendering
|
|
17046
|
+
isReady: renderPipeline !== null
|
|
16470
17047
|
};
|
|
16471
17048
|
}
|
|
16472
17049
|
|
|
@@ -16543,7 +17120,9 @@ exports.isVectorLike = isVectorLike;
|
|
|
16543
17120
|
exports.once = once;
|
|
16544
17121
|
exports.prepare = prepare;
|
|
16545
17122
|
exports.presetsObj = presetsObj;
|
|
17123
|
+
exports.rebuildAllBuffers = rebuildAllBuffers;
|
|
16546
17124
|
exports.rebuildAllNodes = rebuildAllNodes;
|
|
17125
|
+
exports.rebuildAllStorage = rebuildAllStorage;
|
|
16547
17126
|
exports.rebuildAllUniforms = rebuildAllUniforms;
|
|
16548
17127
|
exports.reconciler = reconciler;
|
|
16549
17128
|
exports.registerPrimary = registerPrimary;
|
|
@@ -16556,8 +17135,10 @@ exports.unregisterPrimary = unregisterPrimary;
|
|
|
16556
17135
|
exports.updateCamera = updateCamera;
|
|
16557
17136
|
exports.updateFrustum = updateFrustum;
|
|
16558
17137
|
exports.useBridge = useBridge;
|
|
17138
|
+
exports.useBuffers = useBuffers;
|
|
16559
17139
|
exports.useEnvironment = useEnvironment;
|
|
16560
17140
|
exports.useFrame = useFrame;
|
|
17141
|
+
exports.useGPUStorage = useGPUStorage;
|
|
16561
17142
|
exports.useGraph = useGraph;
|
|
16562
17143
|
exports.useInstanceHandle = useInstanceHandle;
|
|
16563
17144
|
exports.useIsomorphicLayoutEffect = useIsomorphicLayoutEffect;
|
|
@@ -16565,7 +17146,7 @@ exports.useLoader = useLoader;
|
|
|
16565
17146
|
exports.useLocalNodes = useLocalNodes;
|
|
16566
17147
|
exports.useMutableCallback = useMutableCallback;
|
|
16567
17148
|
exports.useNodes = useNodes;
|
|
16568
|
-
exports.
|
|
17149
|
+
exports.useRenderPipeline = useRenderPipeline;
|
|
16569
17150
|
exports.useRenderTarget = useRenderTarget;
|
|
16570
17151
|
exports.useStore = useStore;
|
|
16571
17152
|
exports.useTexture = useTexture;
|