@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.mjs
CHANGED
|
@@ -985,6 +985,9 @@ function applyProps(object, props) {
|
|
|
985
985
|
else target.set(value);
|
|
986
986
|
} else {
|
|
987
987
|
root[key] = value;
|
|
988
|
+
if (key.endsWith("Node") && root.isMaterial) {
|
|
989
|
+
root.needsUpdate = true;
|
|
990
|
+
}
|
|
988
991
|
if (rootState && rootState.renderer?.outputColorSpace === SRGBColorSpace && colorMaps.includes(key) && isTexture(value) && root[key]?.isTexture && // sRGB textures must be RGBA8 since r137 https://github.com/mrdoob/three.js/pull/23129
|
|
989
992
|
root[key].format === RGBAFormat && root[key].type === UnsignedByteType) {
|
|
990
993
|
root[key].colorSpace = rootState.textureColorSpace;
|
|
@@ -1018,38 +1021,60 @@ function applyProps(object, props) {
|
|
|
1018
1021
|
return object;
|
|
1019
1022
|
}
|
|
1020
1023
|
|
|
1024
|
+
const DEFAULT_POINTER_ID = 0;
|
|
1025
|
+
const XR_POINTER_ID_START = 1e3;
|
|
1026
|
+
function getPointerState(internal, pointerId) {
|
|
1027
|
+
let state = internal.pointerMap.get(pointerId);
|
|
1028
|
+
if (!state) {
|
|
1029
|
+
state = {
|
|
1030
|
+
hovered: /* @__PURE__ */ new Map(),
|
|
1031
|
+
captured: /* @__PURE__ */ new Map(),
|
|
1032
|
+
initialClick: [0, 0],
|
|
1033
|
+
initialHits: []
|
|
1034
|
+
};
|
|
1035
|
+
internal.pointerMap.set(pointerId, state);
|
|
1036
|
+
}
|
|
1037
|
+
return state;
|
|
1038
|
+
}
|
|
1039
|
+
function getPointerId(event) {
|
|
1040
|
+
return "pointerId" in event ? event.pointerId : DEFAULT_POINTER_ID;
|
|
1041
|
+
}
|
|
1021
1042
|
function makeId(event) {
|
|
1022
1043
|
return (event.eventObject || event.object).uuid + "/" + event.index + event.instanceId;
|
|
1023
1044
|
}
|
|
1024
|
-
function releaseInternalPointerCapture(
|
|
1025
|
-
const
|
|
1045
|
+
function releaseInternalPointerCapture(internal, obj, pointerId) {
|
|
1046
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1047
|
+
if (!pointerState) return;
|
|
1048
|
+
const captureData = pointerState.captured.get(obj);
|
|
1026
1049
|
if (captureData) {
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
capturedMap.delete(pointerId);
|
|
1030
|
-
captureData.target.releasePointerCapture(pointerId);
|
|
1031
|
-
}
|
|
1050
|
+
pointerState.captured.delete(obj);
|
|
1051
|
+
captureData.target.releasePointerCapture(pointerId);
|
|
1032
1052
|
}
|
|
1033
1053
|
}
|
|
1034
1054
|
function removeInteractivity(store, object) {
|
|
1035
1055
|
const { internal } = store.getState();
|
|
1036
1056
|
internal.interaction = internal.interaction.filter((o) => o !== object);
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1057
|
+
for (const [pointerId, pointerState] of internal.pointerMap) {
|
|
1058
|
+
pointerState.initialHits = pointerState.initialHits.filter((o) => o !== object);
|
|
1059
|
+
pointerState.hovered.forEach((value, key) => {
|
|
1060
|
+
if (value.eventObject === object || value.object === object) {
|
|
1061
|
+
pointerState.hovered.delete(key);
|
|
1062
|
+
}
|
|
1063
|
+
});
|
|
1064
|
+
if (pointerState.captured.has(object)) {
|
|
1065
|
+
releaseInternalPointerCapture(internal, object, pointerId);
|
|
1041
1066
|
}
|
|
1042
|
-
}
|
|
1043
|
-
internal.capturedMap.forEach((captures, pointerId) => {
|
|
1044
|
-
releaseInternalPointerCapture(internal.capturedMap, object, captures, pointerId);
|
|
1045
|
-
});
|
|
1067
|
+
}
|
|
1046
1068
|
unregisterVisibility(store, object);
|
|
1047
1069
|
}
|
|
1048
1070
|
function createEvents(store) {
|
|
1049
|
-
function calculateDistance(event) {
|
|
1071
|
+
function calculateDistance(event, pointerId) {
|
|
1050
1072
|
const { internal } = store.getState();
|
|
1051
|
-
const
|
|
1052
|
-
|
|
1073
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1074
|
+
if (!pointerState) return 0;
|
|
1075
|
+
const [initialX, initialY] = pointerState.initialClick;
|
|
1076
|
+
const dx = event.offsetX - initialX;
|
|
1077
|
+
const dy = event.offsetY - initialY;
|
|
1053
1078
|
return Math.round(Math.sqrt(dx * dx + dy * dy));
|
|
1054
1079
|
}
|
|
1055
1080
|
function filterPointerEvents(objects) {
|
|
@@ -1085,6 +1110,15 @@ function createEvents(store) {
|
|
|
1085
1110
|
return state2.raycaster.camera ? state2.raycaster.intersectObject(obj, true) : [];
|
|
1086
1111
|
}
|
|
1087
1112
|
let hits = eventsObjects.flatMap(handleRaycast).sort((a, b) => {
|
|
1113
|
+
const aInteractivePriority = a.object.userData?.interactivePriority;
|
|
1114
|
+
const bInteractivePriority = b.object.userData?.interactivePriority;
|
|
1115
|
+
if (aInteractivePriority !== void 0 || bInteractivePriority !== void 0) {
|
|
1116
|
+
if (aInteractivePriority !== void 0 && bInteractivePriority === void 0) return -1;
|
|
1117
|
+
if (bInteractivePriority !== void 0 && aInteractivePriority === void 0) return 1;
|
|
1118
|
+
if (aInteractivePriority !== bInteractivePriority) {
|
|
1119
|
+
return (bInteractivePriority ?? 0) - (aInteractivePriority ?? 0);
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1088
1122
|
const aState = getRootState(a.object);
|
|
1089
1123
|
const bState = getRootState(b.object);
|
|
1090
1124
|
const aPriority = aState?.events?.priority ?? 1;
|
|
@@ -1106,9 +1140,13 @@ function createEvents(store) {
|
|
|
1106
1140
|
eventObject = eventObject.parent;
|
|
1107
1141
|
}
|
|
1108
1142
|
}
|
|
1109
|
-
if ("pointerId" in event
|
|
1110
|
-
|
|
1111
|
-
|
|
1143
|
+
if ("pointerId" in event) {
|
|
1144
|
+
const pointerId = event.pointerId;
|
|
1145
|
+
const pointerState = state.internal.pointerMap.get(pointerId);
|
|
1146
|
+
if (pointerState?.captured.size) {
|
|
1147
|
+
for (const captureData of pointerState.captured.values()) {
|
|
1148
|
+
if (!duplicates.has(makeId(captureData.intersection))) intersections.push(captureData.intersection);
|
|
1149
|
+
}
|
|
1112
1150
|
}
|
|
1113
1151
|
}
|
|
1114
1152
|
return intersections;
|
|
@@ -1121,27 +1159,25 @@ function createEvents(store) {
|
|
|
1121
1159
|
if (state) {
|
|
1122
1160
|
const { raycaster, pointer, camera, internal } = state;
|
|
1123
1161
|
const unprojectedPoint = new Vector3(pointer.x, pointer.y, 0).unproject(camera);
|
|
1124
|
-
const hasPointerCapture = (id) =>
|
|
1162
|
+
const hasPointerCapture = (id) => {
|
|
1163
|
+
const pointerState = internal.pointerMap.get(id);
|
|
1164
|
+
return pointerState?.captured.has(hit.eventObject) ?? false;
|
|
1165
|
+
};
|
|
1125
1166
|
const setPointerCapture = (id) => {
|
|
1126
1167
|
const captureData = { intersection: hit, target: event.target };
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
} else {
|
|
1130
|
-
internal.capturedMap.set(id, /* @__PURE__ */ new Map([[hit.eventObject, captureData]]));
|
|
1131
|
-
}
|
|
1168
|
+
const pointerState = getPointerState(internal, id);
|
|
1169
|
+
pointerState.captured.set(hit.eventObject, captureData);
|
|
1132
1170
|
event.target.setPointerCapture(id);
|
|
1133
1171
|
};
|
|
1134
1172
|
const releasePointerCapture = (id) => {
|
|
1135
|
-
|
|
1136
|
-
if (captures) {
|
|
1137
|
-
releaseInternalPointerCapture(internal.capturedMap, hit.eventObject, captures, id);
|
|
1138
|
-
}
|
|
1173
|
+
releaseInternalPointerCapture(internal, hit.eventObject, id);
|
|
1139
1174
|
};
|
|
1140
1175
|
const extractEventProps = {};
|
|
1141
1176
|
for (const prop in event) {
|
|
1142
1177
|
const property = event[prop];
|
|
1143
1178
|
if (typeof property !== "function") extractEventProps[prop] = property;
|
|
1144
1179
|
}
|
|
1180
|
+
const eventPointerId = "pointerId" in event ? event.pointerId : void 0;
|
|
1145
1181
|
const raycastEvent = {
|
|
1146
1182
|
...hit,
|
|
1147
1183
|
...extractEventProps,
|
|
@@ -1152,18 +1188,19 @@ function createEvents(store) {
|
|
|
1152
1188
|
unprojectedPoint,
|
|
1153
1189
|
ray: raycaster.ray,
|
|
1154
1190
|
camera,
|
|
1191
|
+
pointerId: eventPointerId,
|
|
1155
1192
|
// Hijack stopPropagation, which just sets a flag
|
|
1156
1193
|
stopPropagation() {
|
|
1157
|
-
const
|
|
1194
|
+
const pointerState = eventPointerId !== void 0 ? internal.pointerMap.get(eventPointerId) : void 0;
|
|
1158
1195
|
if (
|
|
1159
1196
|
// ...if this pointer hasn't been captured
|
|
1160
|
-
!
|
|
1161
|
-
|
|
1197
|
+
!pointerState?.captured.size || // ... or if the hit object is capturing the pointer
|
|
1198
|
+
pointerState.captured.has(hit.eventObject)
|
|
1162
1199
|
) {
|
|
1163
1200
|
raycastEvent.stopped = localState.stopped = true;
|
|
1164
|
-
if (
|
|
1201
|
+
if (pointerState?.hovered.size && Array.from(pointerState.hovered.values()).find((i) => i.eventObject === hit.eventObject)) {
|
|
1165
1202
|
const higher = intersections.slice(0, intersections.indexOf(hit));
|
|
1166
|
-
cancelPointer([...higher, hit]);
|
|
1203
|
+
cancelPointer([...higher, hit], eventPointerId);
|
|
1167
1204
|
}
|
|
1168
1205
|
}
|
|
1169
1206
|
},
|
|
@@ -1179,15 +1216,18 @@ function createEvents(store) {
|
|
|
1179
1216
|
}
|
|
1180
1217
|
return intersections;
|
|
1181
1218
|
}
|
|
1182
|
-
function cancelPointer(intersections) {
|
|
1219
|
+
function cancelPointer(intersections, pointerId) {
|
|
1183
1220
|
const { internal } = store.getState();
|
|
1184
|
-
|
|
1221
|
+
const pid = pointerId ?? DEFAULT_POINTER_ID;
|
|
1222
|
+
const pointerState = internal.pointerMap.get(pid);
|
|
1223
|
+
if (!pointerState) return;
|
|
1224
|
+
for (const [hoveredId, hoveredObj] of pointerState.hovered) {
|
|
1185
1225
|
if (!intersections.length || !intersections.find(
|
|
1186
1226
|
(hit) => hit.object === hoveredObj.object && hit.index === hoveredObj.index && hit.instanceId === hoveredObj.instanceId
|
|
1187
1227
|
)) {
|
|
1188
1228
|
const eventObject = hoveredObj.eventObject;
|
|
1189
1229
|
const instance = eventObject.__r3f;
|
|
1190
|
-
|
|
1230
|
+
pointerState.hovered.delete(hoveredId);
|
|
1191
1231
|
if (instance?.eventCount) {
|
|
1192
1232
|
const handlers = instance.handlers;
|
|
1193
1233
|
const data = { ...hoveredObj, intersections };
|
|
@@ -1216,41 +1256,118 @@ function createEvents(store) {
|
|
|
1216
1256
|
instance?.handlers.onDropMissed?.(event);
|
|
1217
1257
|
}
|
|
1218
1258
|
}
|
|
1259
|
+
function cleanupPointer(pointerId) {
|
|
1260
|
+
const { internal } = store.getState();
|
|
1261
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1262
|
+
if (pointerState) {
|
|
1263
|
+
for (const [, hoveredObj] of pointerState.hovered) {
|
|
1264
|
+
const eventObject = hoveredObj.eventObject;
|
|
1265
|
+
const instance = eventObject.__r3f;
|
|
1266
|
+
if (instance?.eventCount) {
|
|
1267
|
+
const handlers = instance.handlers;
|
|
1268
|
+
const data = { ...hoveredObj, intersections: [] };
|
|
1269
|
+
handlers.onPointerOut?.(data);
|
|
1270
|
+
handlers.onPointerLeave?.(data);
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
internal.pointerMap.delete(pointerId);
|
|
1274
|
+
}
|
|
1275
|
+
internal.pointerDirty.delete(pointerId);
|
|
1276
|
+
}
|
|
1277
|
+
function processDeferredPointer(event, pointerId) {
|
|
1278
|
+
const state = store.getState();
|
|
1279
|
+
const { onPointerMissed, onDragOverMissed, internal } = state;
|
|
1280
|
+
if (!state.events.enabled) return;
|
|
1281
|
+
const filter = filterPointerEvents;
|
|
1282
|
+
const hits = intersect(event, filter);
|
|
1283
|
+
cancelPointer(hits, pointerId);
|
|
1284
|
+
function onIntersect(data) {
|
|
1285
|
+
const eventObject = data.eventObject;
|
|
1286
|
+
const instance = eventObject.__r3f;
|
|
1287
|
+
if (!instance?.eventCount) return;
|
|
1288
|
+
const handlers = instance.handlers;
|
|
1289
|
+
if (handlers.onPointerOver || handlers.onPointerEnter || handlers.onPointerOut || handlers.onPointerLeave) {
|
|
1290
|
+
const id = makeId(data);
|
|
1291
|
+
const pointerState = getPointerState(internal, pointerId);
|
|
1292
|
+
const hoveredItem = pointerState.hovered.get(id);
|
|
1293
|
+
if (!hoveredItem) {
|
|
1294
|
+
pointerState.hovered.set(id, data);
|
|
1295
|
+
handlers.onPointerOver?.(data);
|
|
1296
|
+
handlers.onPointerEnter?.(data);
|
|
1297
|
+
} else if (hoveredItem.stopped) {
|
|
1298
|
+
data.stopPropagation();
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
handlers.onPointerMove?.(data);
|
|
1302
|
+
}
|
|
1303
|
+
handleIntersects(hits, event, 0, onIntersect);
|
|
1304
|
+
}
|
|
1219
1305
|
function handlePointer(name) {
|
|
1220
1306
|
switch (name) {
|
|
1221
1307
|
case "onPointerLeave":
|
|
1222
|
-
case "onPointerCancel":
|
|
1223
1308
|
case "onDragLeave":
|
|
1224
1309
|
return () => cancelPointer([]);
|
|
1310
|
+
// Global cancel of these events
|
|
1311
|
+
case "onPointerCancel":
|
|
1312
|
+
return (event) => {
|
|
1313
|
+
const pointerId = getPointerId(event);
|
|
1314
|
+
cleanupPointer(pointerId);
|
|
1315
|
+
};
|
|
1225
1316
|
case "onLostPointerCapture":
|
|
1226
1317
|
return (event) => {
|
|
1227
1318
|
const { internal } = store.getState();
|
|
1228
|
-
|
|
1319
|
+
const pointerId = getPointerId(event);
|
|
1320
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1321
|
+
if (pointerState?.captured.size) {
|
|
1229
1322
|
requestAnimationFrame(() => {
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1323
|
+
const pointerState2 = internal.pointerMap.get(pointerId);
|
|
1324
|
+
if (pointerState2?.captured.size) {
|
|
1325
|
+
pointerState2.captured.clear();
|
|
1233
1326
|
}
|
|
1327
|
+
cancelPointer([], pointerId);
|
|
1234
1328
|
});
|
|
1235
1329
|
}
|
|
1236
1330
|
};
|
|
1237
1331
|
}
|
|
1238
1332
|
return function handleEvent(event) {
|
|
1239
1333
|
const state = store.getState();
|
|
1240
|
-
const { onPointerMissed, onDragOverMissed, onDropMissed, internal } = state;
|
|
1334
|
+
const { onPointerMissed, onDragOverMissed, onDropMissed, internal, events } = state;
|
|
1335
|
+
const pointerId = getPointerId(event);
|
|
1241
1336
|
internal.lastEvent.current = event;
|
|
1242
|
-
if (!
|
|
1337
|
+
if (!events.enabled) return;
|
|
1243
1338
|
const isPointerMove = name === "onPointerMove";
|
|
1244
1339
|
const isDragOver = name === "onDragOver";
|
|
1245
1340
|
const isDrop = name === "onDrop";
|
|
1246
1341
|
const isClickEvent = name === "onClick" || name === "onContextMenu" || name === "onDoubleClick";
|
|
1342
|
+
const isPointerDown = name === "onPointerDown";
|
|
1343
|
+
const isPointerUp = name === "onPointerUp";
|
|
1344
|
+
const isWheel = name === "onWheel";
|
|
1345
|
+
const canDeferRaycasts = events.frameTimedRaycasts && state.frameloop === "always";
|
|
1346
|
+
if (isPointerMove && canDeferRaycasts) {
|
|
1347
|
+
events.compute?.(event, state);
|
|
1348
|
+
internal.pointerDirty.set(pointerId, event);
|
|
1349
|
+
return;
|
|
1350
|
+
}
|
|
1351
|
+
if (isWheel && canDeferRaycasts && !events.alwaysFireOnScroll) {
|
|
1352
|
+
events.compute?.(event, state);
|
|
1353
|
+
internal.pointerDirty.set(pointerId, event);
|
|
1354
|
+
return;
|
|
1355
|
+
}
|
|
1356
|
+
if ((isClickEvent || isPointerDown || isPointerUp) && internal.pointerDirty.has(pointerId)) {
|
|
1357
|
+
const deferredEvent = internal.pointerDirty.get(pointerId);
|
|
1358
|
+
internal.pointerDirty.delete(pointerId);
|
|
1359
|
+
processDeferredPointer(deferredEvent, pointerId);
|
|
1360
|
+
}
|
|
1247
1361
|
const filter = isPointerMove || isDragOver || isDrop ? filterPointerEvents : void 0;
|
|
1248
1362
|
const hits = intersect(event, filter);
|
|
1249
|
-
const delta = isClickEvent ? calculateDistance(event) : 0;
|
|
1250
|
-
if (
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1363
|
+
const delta = isClickEvent ? calculateDistance(event, pointerId) : 0;
|
|
1364
|
+
if (isPointerDown) {
|
|
1365
|
+
const pointerState2 = getPointerState(internal, pointerId);
|
|
1366
|
+
pointerState2.initialClick = [event.offsetX, event.offsetY];
|
|
1367
|
+
pointerState2.initialHits = hits.map((hit) => hit.eventObject);
|
|
1368
|
+
}
|
|
1369
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1370
|
+
const initialHits = pointerState?.initialHits ?? [];
|
|
1254
1371
|
if (isClickEvent && !hits.length) {
|
|
1255
1372
|
if (delta <= 2) {
|
|
1256
1373
|
pointerMissed(event, internal.interaction);
|
|
@@ -1265,7 +1382,9 @@ function createEvents(store) {
|
|
|
1265
1382
|
dropMissed(event, internal.interaction);
|
|
1266
1383
|
if (onDropMissed) onDropMissed(event);
|
|
1267
1384
|
}
|
|
1268
|
-
if (isPointerMove || isDragOver)
|
|
1385
|
+
if (isPointerMove || isDragOver) {
|
|
1386
|
+
cancelPointer(hits, pointerId);
|
|
1387
|
+
}
|
|
1269
1388
|
function onIntersect(data) {
|
|
1270
1389
|
const eventObject = data.eventObject;
|
|
1271
1390
|
const instance = eventObject.__r3f;
|
|
@@ -1274,9 +1393,10 @@ function createEvents(store) {
|
|
|
1274
1393
|
if (isPointerMove) {
|
|
1275
1394
|
if (handlers.onPointerOver || handlers.onPointerEnter || handlers.onPointerOut || handlers.onPointerLeave) {
|
|
1276
1395
|
const id = makeId(data);
|
|
1277
|
-
const
|
|
1396
|
+
const pointerState2 = getPointerState(internal, pointerId);
|
|
1397
|
+
const hoveredItem = pointerState2.hovered.get(id);
|
|
1278
1398
|
if (!hoveredItem) {
|
|
1279
|
-
|
|
1399
|
+
pointerState2.hovered.set(id, data);
|
|
1280
1400
|
handlers.onPointerOver?.(data);
|
|
1281
1401
|
handlers.onPointerEnter?.(data);
|
|
1282
1402
|
} else if (hoveredItem.stopped) {
|
|
@@ -1286,9 +1406,10 @@ function createEvents(store) {
|
|
|
1286
1406
|
handlers.onPointerMove?.(data);
|
|
1287
1407
|
} else if (isDragOver) {
|
|
1288
1408
|
const id = makeId(data);
|
|
1289
|
-
const
|
|
1409
|
+
const pointerState2 = getPointerState(internal, pointerId);
|
|
1410
|
+
const hoveredItem = pointerState2.hovered.get(id);
|
|
1290
1411
|
if (!hoveredItem) {
|
|
1291
|
-
|
|
1412
|
+
pointerState2.hovered.set(id, data);
|
|
1292
1413
|
handlers.onDragOverEnter?.(data);
|
|
1293
1414
|
} else if (hoveredItem.stopped) {
|
|
1294
1415
|
data.stopPropagation();
|
|
@@ -1299,18 +1420,18 @@ function createEvents(store) {
|
|
|
1299
1420
|
} else {
|
|
1300
1421
|
const handler = handlers[name];
|
|
1301
1422
|
if (handler) {
|
|
1302
|
-
if (!isClickEvent ||
|
|
1423
|
+
if (!isClickEvent || initialHits.includes(eventObject)) {
|
|
1303
1424
|
pointerMissed(
|
|
1304
1425
|
event,
|
|
1305
|
-
internal.interaction.filter((object) => !
|
|
1426
|
+
internal.interaction.filter((object) => !initialHits.includes(object))
|
|
1306
1427
|
);
|
|
1307
1428
|
handler(data);
|
|
1308
1429
|
}
|
|
1309
1430
|
} else {
|
|
1310
|
-
if (isClickEvent &&
|
|
1431
|
+
if (isClickEvent && initialHits.includes(eventObject)) {
|
|
1311
1432
|
pointerMissed(
|
|
1312
1433
|
event,
|
|
1313
|
-
internal.interaction.filter((object) => !
|
|
1434
|
+
internal.interaction.filter((object) => !initialHits.includes(object))
|
|
1314
1435
|
);
|
|
1315
1436
|
}
|
|
1316
1437
|
}
|
|
@@ -1319,7 +1440,15 @@ function createEvents(store) {
|
|
|
1319
1440
|
handleIntersects(hits, event, delta, onIntersect);
|
|
1320
1441
|
};
|
|
1321
1442
|
}
|
|
1322
|
-
|
|
1443
|
+
function flushDeferredPointers() {
|
|
1444
|
+
const { internal, events } = store.getState();
|
|
1445
|
+
if (!events.frameTimedRaycasts) return;
|
|
1446
|
+
for (const [pointerId, event] of internal.pointerDirty) {
|
|
1447
|
+
processDeferredPointer(event, pointerId);
|
|
1448
|
+
}
|
|
1449
|
+
internal.pointerDirty.clear();
|
|
1450
|
+
}
|
|
1451
|
+
return { handlePointer, flushDeferredPointers, processDeferredPointer };
|
|
1323
1452
|
}
|
|
1324
1453
|
const DOM_EVENTS = {
|
|
1325
1454
|
onClick: ["click", false],
|
|
@@ -1338,10 +1467,15 @@ const DOM_EVENTS = {
|
|
|
1338
1467
|
onLostPointerCapture: ["lostpointercapture", true]
|
|
1339
1468
|
};
|
|
1340
1469
|
function createPointerEvents(store) {
|
|
1341
|
-
const { handlePointer } = createEvents(store);
|
|
1470
|
+
const { handlePointer, flushDeferredPointers, processDeferredPointer } = createEvents(store);
|
|
1471
|
+
let nextXRPointerId = XR_POINTER_ID_START;
|
|
1472
|
+
const xrPointers = /* @__PURE__ */ new Map();
|
|
1342
1473
|
return {
|
|
1343
1474
|
priority: 1,
|
|
1344
1475
|
enabled: true,
|
|
1476
|
+
frameTimedRaycasts: true,
|
|
1477
|
+
alwaysFireOnScroll: true,
|
|
1478
|
+
updateOnFrame: false,
|
|
1345
1479
|
compute(event, state) {
|
|
1346
1480
|
state.pointer.set(event.offsetX / state.size.width * 2 - 1, -(event.offsetY / state.size.height) * 2 + 1);
|
|
1347
1481
|
state.raycaster.setFromCamera(state.pointer, state.camera);
|
|
@@ -1351,9 +1485,30 @@ function createPointerEvents(store) {
|
|
|
1351
1485
|
(acc, key) => ({ ...acc, [key]: handlePointer(key) }),
|
|
1352
1486
|
{}
|
|
1353
1487
|
),
|
|
1354
|
-
update: () => {
|
|
1488
|
+
update: (pointerId) => {
|
|
1489
|
+
const { events, internal } = store.getState();
|
|
1490
|
+
if (!events.handlers) return;
|
|
1491
|
+
if (pointerId !== void 0) {
|
|
1492
|
+
const event = internal.pointerDirty.get(pointerId);
|
|
1493
|
+
if (event) {
|
|
1494
|
+
internal.pointerDirty.delete(pointerId);
|
|
1495
|
+
processDeferredPointer(event, pointerId);
|
|
1496
|
+
} else if (internal.lastEvent?.current) {
|
|
1497
|
+
processDeferredPointer(internal.lastEvent.current, pointerId);
|
|
1498
|
+
}
|
|
1499
|
+
} else {
|
|
1500
|
+
flushDeferredPointers();
|
|
1501
|
+
if (internal.lastEvent?.current) {
|
|
1502
|
+
events.handlers.onPointerMove(internal.lastEvent.current);
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
},
|
|
1506
|
+
flush: () => {
|
|
1355
1507
|
const { events, internal } = store.getState();
|
|
1356
|
-
|
|
1508
|
+
flushDeferredPointers();
|
|
1509
|
+
if (events.updateOnFrame && internal.lastEvent?.current && events.handlers) {
|
|
1510
|
+
events.handlers.onPointerMove(internal.lastEvent.current);
|
|
1511
|
+
}
|
|
1357
1512
|
},
|
|
1358
1513
|
connect: (target) => {
|
|
1359
1514
|
const { set, events } = store.getState();
|
|
@@ -1379,6 +1534,32 @@ function createPointerEvents(store) {
|
|
|
1379
1534
|
}
|
|
1380
1535
|
set((state) => ({ events: { ...state.events, connected: void 0 } }));
|
|
1381
1536
|
}
|
|
1537
|
+
},
|
|
1538
|
+
registerPointer: (config) => {
|
|
1539
|
+
const pointerId = nextXRPointerId++;
|
|
1540
|
+
xrPointers.set(pointerId, config);
|
|
1541
|
+
const { internal } = store.getState();
|
|
1542
|
+
getPointerState(internal, pointerId);
|
|
1543
|
+
return pointerId;
|
|
1544
|
+
},
|
|
1545
|
+
unregisterPointer: (pointerId) => {
|
|
1546
|
+
xrPointers.delete(pointerId);
|
|
1547
|
+
const { internal } = store.getState();
|
|
1548
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1549
|
+
if (pointerState) {
|
|
1550
|
+
for (const [, hoveredObj] of pointerState.hovered) {
|
|
1551
|
+
const eventObject = hoveredObj.eventObject;
|
|
1552
|
+
const instance = eventObject.__r3f;
|
|
1553
|
+
if (instance?.eventCount) {
|
|
1554
|
+
const handlers = instance.handlers;
|
|
1555
|
+
const data = { ...hoveredObj, intersections: [] };
|
|
1556
|
+
handlers.onPointerOut?.(data);
|
|
1557
|
+
handlers.onPointerLeave?.(data);
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
internal.pointerMap.delete(pointerId);
|
|
1561
|
+
}
|
|
1562
|
+
internal.pointerDirty.delete(pointerId);
|
|
1382
1563
|
}
|
|
1383
1564
|
};
|
|
1384
1565
|
}
|
|
@@ -2509,7 +2690,14 @@ const createStore = (invalidate, advance) => {
|
|
|
2509
2690
|
frustum: new Frustum(),
|
|
2510
2691
|
autoUpdateFrustum: true,
|
|
2511
2692
|
raycaster: null,
|
|
2512
|
-
events: {
|
|
2693
|
+
events: {
|
|
2694
|
+
priority: 1,
|
|
2695
|
+
enabled: true,
|
|
2696
|
+
connected: false,
|
|
2697
|
+
frameTimedRaycasts: true,
|
|
2698
|
+
alwaysFireOnScroll: true,
|
|
2699
|
+
updateOnFrame: false
|
|
2700
|
+
},
|
|
2513
2701
|
scene: null,
|
|
2514
2702
|
rootScene: null,
|
|
2515
2703
|
xr: null,
|
|
@@ -2600,11 +2788,13 @@ const createStore = (invalidate, advance) => {
|
|
|
2600
2788
|
},
|
|
2601
2789
|
setError: (error) => set(() => ({ error })),
|
|
2602
2790
|
error: null,
|
|
2603
|
-
//* TSL State (managed via hooks: useUniforms, useNodes, useTextures,
|
|
2791
|
+
//* TSL State (managed via hooks: useUniforms, useNodes, useBuffers, useGPUStorage, useTextures, useRenderPipeline) ==============================
|
|
2604
2792
|
uniforms: {},
|
|
2605
2793
|
nodes: {},
|
|
2794
|
+
buffers: {},
|
|
2795
|
+
gpuStorage: {},
|
|
2606
2796
|
textures: /* @__PURE__ */ new Map(),
|
|
2607
|
-
|
|
2797
|
+
renderPipeline: null,
|
|
2608
2798
|
passes: {},
|
|
2609
2799
|
_hmrVersion: 0,
|
|
2610
2800
|
_sizeImperative: false,
|
|
@@ -2613,12 +2803,16 @@ const createStore = (invalidate, advance) => {
|
|
|
2613
2803
|
internal: {
|
|
2614
2804
|
// Events
|
|
2615
2805
|
interaction: [],
|
|
2616
|
-
hovered: /* @__PURE__ */ new Map(),
|
|
2617
2806
|
subscribers: [],
|
|
2807
|
+
// Per-pointer state (new unified structure)
|
|
2808
|
+
pointerMap: /* @__PURE__ */ new Map(),
|
|
2809
|
+
pointerDirty: /* @__PURE__ */ new Map(),
|
|
2810
|
+
lastEvent: React.createRef(),
|
|
2811
|
+
// Deprecated but kept for backwards compatibility
|
|
2812
|
+
hovered: /* @__PURE__ */ new Map(),
|
|
2618
2813
|
initialClick: [0, 0],
|
|
2619
2814
|
initialHits: [],
|
|
2620
2815
|
capturedMap: /* @__PURE__ */ new Map(),
|
|
2621
|
-
lastEvent: React.createRef(),
|
|
2622
2816
|
// Visibility tracking (onFramed, onOccluded, onVisible)
|
|
2623
2817
|
visibilityRegistry: /* @__PURE__ */ new Map(),
|
|
2624
2818
|
// Occlusion system (WebGPU only)
|
|
@@ -15050,6 +15244,12 @@ function createRoot(canvas) {
|
|
|
15050
15244
|
} else if (!state.internal.actualRenderer) {
|
|
15051
15245
|
renderer = await resolveRenderer(rendererConfig, defaultGPUProps, WebGPURenderer);
|
|
15052
15246
|
if (!renderer.hasInitialized?.()) {
|
|
15247
|
+
const size2 = computeInitialSize(canvas, propsSize);
|
|
15248
|
+
if (size2.width > 0 && size2.height > 0) {
|
|
15249
|
+
const pixelRatio = calculateDpr(dpr);
|
|
15250
|
+
canvas.width = size2.width * pixelRatio;
|
|
15251
|
+
canvas.height = size2.height * pixelRatio;
|
|
15252
|
+
}
|
|
15053
15253
|
await renderer.init();
|
|
15054
15254
|
}
|
|
15055
15255
|
const backend = renderer.backend;
|
|
@@ -15251,6 +15451,18 @@ function createRoot(canvas) {
|
|
|
15251
15451
|
system: true
|
|
15252
15452
|
}
|
|
15253
15453
|
);
|
|
15454
|
+
const unregisterEventsFlush = scheduler.register(
|
|
15455
|
+
() => {
|
|
15456
|
+
const state2 = store.getState();
|
|
15457
|
+
state2.events.flush?.();
|
|
15458
|
+
},
|
|
15459
|
+
{
|
|
15460
|
+
id: `${newRootId}_events`,
|
|
15461
|
+
rootId: newRootId,
|
|
15462
|
+
phase: "input",
|
|
15463
|
+
system: true
|
|
15464
|
+
}
|
|
15465
|
+
);
|
|
15254
15466
|
const unregisterFrustum = scheduler.register(
|
|
15255
15467
|
() => {
|
|
15256
15468
|
const state2 = store.getState();
|
|
@@ -15285,7 +15497,7 @@ function createRoot(canvas) {
|
|
|
15285
15497
|
const userHandlesRender = scheduler.hasUserJobsInPhase("render", newRootId);
|
|
15286
15498
|
if (userHandlesRender || state2.internal.priority) return;
|
|
15287
15499
|
try {
|
|
15288
|
-
if (state2.
|
|
15500
|
+
if (state2.renderPipeline?.render) state2.renderPipeline.render();
|
|
15289
15501
|
else if (renderer2?.render) renderer2.render(state2.scene, state2.camera);
|
|
15290
15502
|
} catch (error) {
|
|
15291
15503
|
state2.setError(error instanceof Error ? error : new Error(String(error)));
|
|
@@ -15310,6 +15522,7 @@ function createRoot(canvas) {
|
|
|
15310
15522
|
unregisterRoot: () => {
|
|
15311
15523
|
unregisterRoot();
|
|
15312
15524
|
unregisterCanvasTarget();
|
|
15525
|
+
unregisterEventsFlush();
|
|
15313
15526
|
unregisterFrustum();
|
|
15314
15527
|
unregisterVisibility();
|
|
15315
15528
|
unregisterRender();
|
|
@@ -15475,9 +15688,13 @@ function PortalInner({ state = {}, children, container }) {
|
|
|
15475
15688
|
const store = createWithEqualityFn((set, get) => ({ ...rest, set, get }));
|
|
15476
15689
|
const onMutate = (prev) => store.setState((state2) => inject.current(prev, state2));
|
|
15477
15690
|
onMutate(previousRoot.getState());
|
|
15478
|
-
previousRoot.subscribe(onMutate);
|
|
15479
15691
|
return store;
|
|
15480
15692
|
}, [previousRoot, container]);
|
|
15693
|
+
useIsomorphicLayoutEffect(() => {
|
|
15694
|
+
const onMutate = (prev) => usePortalStore.setState((state2) => inject.current(prev, state2));
|
|
15695
|
+
const unsubscribe = previousRoot.subscribe(onMutate);
|
|
15696
|
+
return unsubscribe;
|
|
15697
|
+
}, [previousRoot, usePortalStore]);
|
|
15481
15698
|
return (
|
|
15482
15699
|
// @ts-ignore, reconciler types are not maintained
|
|
15483
15700
|
/* @__PURE__ */ jsx(Fragment, { children: reconciler.createPortal(
|
|
@@ -15698,6 +15915,7 @@ function CanvasImpl({
|
|
|
15698
15915
|
queueMicrotask(() => {
|
|
15699
15916
|
const rootEntry = _roots.get(canvas);
|
|
15700
15917
|
if (rootEntry?.store) {
|
|
15918
|
+
console.log("[R3F] HMR detected \u2014 rebuilding nodes/uniforms");
|
|
15701
15919
|
rootEntry.store.setState((state) => ({
|
|
15702
15920
|
nodes: {},
|
|
15703
15921
|
uniforms: {},
|
|
@@ -15709,8 +15927,7 @@ function CanvasImpl({
|
|
|
15709
15927
|
if (typeof import.meta !== "undefined" && import.meta.hot) {
|
|
15710
15928
|
const hot = import.meta.hot;
|
|
15711
15929
|
hot.on("vite:afterUpdate", handleHMR);
|
|
15712
|
-
return () => hot.
|
|
15713
|
-
});
|
|
15930
|
+
return () => hot.off?.("vite:afterUpdate", handleHMR);
|
|
15714
15931
|
}
|
|
15715
15932
|
if (typeof module !== "undefined" && module.hot) {
|
|
15716
15933
|
const hot = module.hot;
|
|
@@ -15809,6 +16026,8 @@ function createScopedStore(data) {
|
|
|
15809
16026
|
function createLazyCreatorState(state) {
|
|
15810
16027
|
let _uniforms = null;
|
|
15811
16028
|
let _nodes = null;
|
|
16029
|
+
let _buffers = null;
|
|
16030
|
+
let _gpuStorage = null;
|
|
15812
16031
|
return Object.create(state, {
|
|
15813
16032
|
uniforms: {
|
|
15814
16033
|
get() {
|
|
@@ -15819,6 +16038,16 @@ function createLazyCreatorState(state) {
|
|
|
15819
16038
|
get() {
|
|
15820
16039
|
return _nodes ?? (_nodes = createScopedStore(state.nodes));
|
|
15821
16040
|
}
|
|
16041
|
+
},
|
|
16042
|
+
buffers: {
|
|
16043
|
+
get() {
|
|
16044
|
+
return _buffers ?? (_buffers = createScopedStore(state.buffers));
|
|
16045
|
+
}
|
|
16046
|
+
},
|
|
16047
|
+
gpuStorage: {
|
|
16048
|
+
get() {
|
|
16049
|
+
return _gpuStorage ?? (_gpuStorage = createScopedStore(state.gpuStorage));
|
|
16050
|
+
}
|
|
15822
16051
|
}
|
|
15823
16052
|
});
|
|
15824
16053
|
}
|
|
@@ -15901,6 +16130,10 @@ function vectorize(inObject) {
|
|
|
15901
16130
|
if (obj.isVector2 || obj.isVector3 || obj.isVector4) return inObject;
|
|
15902
16131
|
if (obj.isMatrix3 || obj.isMatrix4) return inObject;
|
|
15903
16132
|
if (obj.isColor || obj.isEuler || obj.isQuaternion || obj.isSpherical) return inObject;
|
|
16133
|
+
if ("r" in obj && "g" in obj && "b" in obj && typeof obj.r === "number" && typeof obj.g === "number" && typeof obj.b === "number") {
|
|
16134
|
+
const scale = obj.r > 1 || obj.g > 1 || obj.b > 1 ? 1 / 255 : 1;
|
|
16135
|
+
return new Color(obj.r * scale, obj.g * scale, obj.b * scale);
|
|
16136
|
+
}
|
|
15904
16137
|
if ("x" in obj && "y" in obj && typeof obj.x === "number" && typeof obj.y === "number") {
|
|
15905
16138
|
if ("w" in obj && typeof obj.w === "number" && "z" in obj && typeof obj.z === "number") {
|
|
15906
16139
|
return new Vector4(obj.x, obj.y, obj.z, obj.w);
|
|
@@ -16356,7 +16589,351 @@ function useLocalNodes(creator) {
|
|
|
16356
16589
|
}, [store, creator, uniforms, nodes, textures, hmrVersion]);
|
|
16357
16590
|
}
|
|
16358
16591
|
|
|
16359
|
-
|
|
16592
|
+
const isBufferLike = (value) => {
|
|
16593
|
+
if (value === null || typeof value !== "object") return false;
|
|
16594
|
+
if (ArrayBuffer.isView(value)) return true;
|
|
16595
|
+
if ("isBufferAttribute" in value) return true;
|
|
16596
|
+
if ("uuid" in value || "nodeType" in value) return true;
|
|
16597
|
+
return false;
|
|
16598
|
+
};
|
|
16599
|
+
const disposeBuffer = (buffer) => {
|
|
16600
|
+
if (buffer === null || typeof buffer !== "object") return;
|
|
16601
|
+
if ("dispose" in buffer && typeof buffer.dispose === "function") {
|
|
16602
|
+
buffer.dispose();
|
|
16603
|
+
}
|
|
16604
|
+
};
|
|
16605
|
+
function useBuffers(creatorOrScope, scope) {
|
|
16606
|
+
const store = useStore();
|
|
16607
|
+
const removeBuffers = useCallback(
|
|
16608
|
+
(names, targetScope) => {
|
|
16609
|
+
const nameArray = Array.isArray(names) ? names : [names];
|
|
16610
|
+
store.setState((state) => {
|
|
16611
|
+
if (targetScope) {
|
|
16612
|
+
const currentScope = { ...state.buffers[targetScope] };
|
|
16613
|
+
for (const name of nameArray) delete currentScope[name];
|
|
16614
|
+
return { buffers: { ...state.buffers, [targetScope]: currentScope } };
|
|
16615
|
+
}
|
|
16616
|
+
const buffers2 = { ...state.buffers };
|
|
16617
|
+
for (const name of nameArray) if (isBufferLike(buffers2[name])) delete buffers2[name];
|
|
16618
|
+
return { buffers: buffers2 };
|
|
16619
|
+
});
|
|
16620
|
+
},
|
|
16621
|
+
[store]
|
|
16622
|
+
);
|
|
16623
|
+
const clearBuffers = useCallback(
|
|
16624
|
+
(targetScope) => {
|
|
16625
|
+
store.setState((state) => {
|
|
16626
|
+
if (targetScope && targetScope !== "root") {
|
|
16627
|
+
const { [targetScope]: _, ...rest } = state.buffers;
|
|
16628
|
+
return { buffers: rest };
|
|
16629
|
+
}
|
|
16630
|
+
if (targetScope === "root") {
|
|
16631
|
+
const buffers2 = {};
|
|
16632
|
+
for (const [key, value] of Object.entries(state.buffers)) {
|
|
16633
|
+
if (!isBufferLike(value)) buffers2[key] = value;
|
|
16634
|
+
}
|
|
16635
|
+
return { buffers: buffers2 };
|
|
16636
|
+
}
|
|
16637
|
+
return { buffers: {} };
|
|
16638
|
+
});
|
|
16639
|
+
},
|
|
16640
|
+
[store]
|
|
16641
|
+
);
|
|
16642
|
+
const rebuildBuffers = useCallback(
|
|
16643
|
+
(targetScope) => {
|
|
16644
|
+
store.setState((state) => {
|
|
16645
|
+
let newBuffers = state.buffers;
|
|
16646
|
+
if (targetScope && targetScope !== "root") {
|
|
16647
|
+
const { [targetScope]: _, ...rest } = state.buffers;
|
|
16648
|
+
newBuffers = rest;
|
|
16649
|
+
} else if (targetScope === "root") {
|
|
16650
|
+
newBuffers = {};
|
|
16651
|
+
for (const [key, value] of Object.entries(state.buffers)) {
|
|
16652
|
+
if (!isBufferLike(value)) newBuffers[key] = value;
|
|
16653
|
+
}
|
|
16654
|
+
} else {
|
|
16655
|
+
newBuffers = {};
|
|
16656
|
+
}
|
|
16657
|
+
return { buffers: newBuffers, _hmrVersion: state._hmrVersion + 1 };
|
|
16658
|
+
});
|
|
16659
|
+
},
|
|
16660
|
+
[store]
|
|
16661
|
+
);
|
|
16662
|
+
const disposeBuffers = useCallback(
|
|
16663
|
+
(names, targetScope) => {
|
|
16664
|
+
const nameArray = Array.isArray(names) ? names : [names];
|
|
16665
|
+
const state = store.getState();
|
|
16666
|
+
for (const name of nameArray) {
|
|
16667
|
+
const buffer = targetScope ? state.buffers[targetScope]?.[name] : state.buffers[name];
|
|
16668
|
+
if (buffer && isBufferLike(buffer)) {
|
|
16669
|
+
disposeBuffer(buffer);
|
|
16670
|
+
}
|
|
16671
|
+
}
|
|
16672
|
+
removeBuffers(names, targetScope);
|
|
16673
|
+
},
|
|
16674
|
+
[store, removeBuffers]
|
|
16675
|
+
);
|
|
16676
|
+
const isReader = creatorOrScope === void 0 || typeof creatorOrScope === "string";
|
|
16677
|
+
const storeBuffers = useThree((s) => s.buffers);
|
|
16678
|
+
const hmrVersion = useThree((s) => s._hmrVersion);
|
|
16679
|
+
const scopeDep = typeof creatorOrScope === "string" ? creatorOrScope : scope;
|
|
16680
|
+
const readerDep = isReader ? storeBuffers : null;
|
|
16681
|
+
const creatorDep = isReader ? null : hmrVersion;
|
|
16682
|
+
const buffers = useMemo(() => {
|
|
16683
|
+
if (creatorOrScope === void 0) {
|
|
16684
|
+
return storeBuffers;
|
|
16685
|
+
}
|
|
16686
|
+
if (typeof creatorOrScope === "string") {
|
|
16687
|
+
const scopeData = storeBuffers[creatorOrScope];
|
|
16688
|
+
if (scopeData && !isBufferLike(scopeData)) return scopeData;
|
|
16689
|
+
return {};
|
|
16690
|
+
}
|
|
16691
|
+
const state = store.getState();
|
|
16692
|
+
const set = store.setState;
|
|
16693
|
+
const creator = creatorOrScope;
|
|
16694
|
+
const wrappedState = createLazyCreatorState(state);
|
|
16695
|
+
const created = creator(wrappedState);
|
|
16696
|
+
const result = {};
|
|
16697
|
+
let hasNewBuffers = false;
|
|
16698
|
+
if (scope) {
|
|
16699
|
+
const currentScope = state.buffers[scope] ?? {};
|
|
16700
|
+
for (const [name, buffer] of Object.entries(created)) {
|
|
16701
|
+
if (currentScope[name]) {
|
|
16702
|
+
result[name] = currentScope[name];
|
|
16703
|
+
} else {
|
|
16704
|
+
if ("setName" in buffer && typeof buffer.setName === "function") {
|
|
16705
|
+
buffer.setName(`${scope}.${name}`);
|
|
16706
|
+
}
|
|
16707
|
+
result[name] = buffer;
|
|
16708
|
+
hasNewBuffers = true;
|
|
16709
|
+
}
|
|
16710
|
+
}
|
|
16711
|
+
if (hasNewBuffers) {
|
|
16712
|
+
set((s) => ({
|
|
16713
|
+
buffers: {
|
|
16714
|
+
...s.buffers,
|
|
16715
|
+
[scope]: { ...s.buffers[scope], ...result }
|
|
16716
|
+
}
|
|
16717
|
+
}));
|
|
16718
|
+
}
|
|
16719
|
+
return result;
|
|
16720
|
+
}
|
|
16721
|
+
for (const [name, buffer] of Object.entries(created)) {
|
|
16722
|
+
const existing = state.buffers[name];
|
|
16723
|
+
if (existing && isBufferLike(existing)) {
|
|
16724
|
+
result[name] = existing;
|
|
16725
|
+
} else {
|
|
16726
|
+
if ("setName" in buffer && typeof buffer.setName === "function") {
|
|
16727
|
+
buffer.setName(name);
|
|
16728
|
+
}
|
|
16729
|
+
result[name] = buffer;
|
|
16730
|
+
hasNewBuffers = true;
|
|
16731
|
+
}
|
|
16732
|
+
}
|
|
16733
|
+
if (hasNewBuffers) {
|
|
16734
|
+
set((s) => ({ buffers: { ...s.buffers, ...result } }));
|
|
16735
|
+
}
|
|
16736
|
+
return result;
|
|
16737
|
+
}, [store, scopeDep, readerDep, creatorDep]);
|
|
16738
|
+
return { ...buffers, removeBuffers, clearBuffers, rebuildBuffers, disposeBuffers };
|
|
16739
|
+
}
|
|
16740
|
+
function rebuildAllBuffers(store, scope) {
|
|
16741
|
+
store.setState((state) => {
|
|
16742
|
+
let newBuffers = state.buffers;
|
|
16743
|
+
if (scope && scope !== "root") {
|
|
16744
|
+
const { [scope]: _, ...rest } = state.buffers;
|
|
16745
|
+
newBuffers = rest;
|
|
16746
|
+
} else if (scope === "root") {
|
|
16747
|
+
newBuffers = {};
|
|
16748
|
+
for (const [key, value] of Object.entries(state.buffers)) {
|
|
16749
|
+
if (!isBufferLike(value)) newBuffers[key] = value;
|
|
16750
|
+
}
|
|
16751
|
+
} else {
|
|
16752
|
+
newBuffers = {};
|
|
16753
|
+
}
|
|
16754
|
+
return { buffers: newBuffers, _hmrVersion: state._hmrVersion + 1 };
|
|
16755
|
+
});
|
|
16756
|
+
}
|
|
16757
|
+
|
|
16758
|
+
const isStorageLike = (value) => {
|
|
16759
|
+
if (value === null || typeof value !== "object") return false;
|
|
16760
|
+
if ("isTexture" in value) return true;
|
|
16761
|
+
if ("isData3DTexture" in value) return true;
|
|
16762
|
+
if ("uuid" in value || "nodeType" in value) return true;
|
|
16763
|
+
return false;
|
|
16764
|
+
};
|
|
16765
|
+
const disposeStorage = (storage) => {
|
|
16766
|
+
if (storage === null || typeof storage !== "object") return;
|
|
16767
|
+
if ("dispose" in storage && typeof storage.dispose === "function") {
|
|
16768
|
+
storage.dispose();
|
|
16769
|
+
}
|
|
16770
|
+
};
|
|
16771
|
+
function useGPUStorage(creatorOrScope, scope) {
|
|
16772
|
+
const store = useStore();
|
|
16773
|
+
const removeStorage = useCallback(
|
|
16774
|
+
(names, targetScope) => {
|
|
16775
|
+
const nameArray = Array.isArray(names) ? names : [names];
|
|
16776
|
+
store.setState((state) => {
|
|
16777
|
+
if (targetScope) {
|
|
16778
|
+
const currentScope = { ...state.gpuStorage[targetScope] };
|
|
16779
|
+
for (const name of nameArray) delete currentScope[name];
|
|
16780
|
+
return { gpuStorage: { ...state.gpuStorage, [targetScope]: currentScope } };
|
|
16781
|
+
}
|
|
16782
|
+
const gpuStorage2 = { ...state.gpuStorage };
|
|
16783
|
+
for (const name of nameArray) if (isStorageLike(gpuStorage2[name])) delete gpuStorage2[name];
|
|
16784
|
+
return { gpuStorage: gpuStorage2 };
|
|
16785
|
+
});
|
|
16786
|
+
},
|
|
16787
|
+
[store]
|
|
16788
|
+
);
|
|
16789
|
+
const clearStorage = useCallback(
|
|
16790
|
+
(targetScope) => {
|
|
16791
|
+
store.setState((state) => {
|
|
16792
|
+
if (targetScope && targetScope !== "root") {
|
|
16793
|
+
const { [targetScope]: _, ...rest } = state.gpuStorage;
|
|
16794
|
+
return { gpuStorage: rest };
|
|
16795
|
+
}
|
|
16796
|
+
if (targetScope === "root") {
|
|
16797
|
+
const gpuStorage2 = {};
|
|
16798
|
+
for (const [key, value] of Object.entries(state.gpuStorage)) {
|
|
16799
|
+
if (!isStorageLike(value)) gpuStorage2[key] = value;
|
|
16800
|
+
}
|
|
16801
|
+
return { gpuStorage: gpuStorage2 };
|
|
16802
|
+
}
|
|
16803
|
+
return { gpuStorage: {} };
|
|
16804
|
+
});
|
|
16805
|
+
},
|
|
16806
|
+
[store]
|
|
16807
|
+
);
|
|
16808
|
+
const rebuildStorage = useCallback(
|
|
16809
|
+
(targetScope) => {
|
|
16810
|
+
store.setState((state) => {
|
|
16811
|
+
let newStorage = state.gpuStorage;
|
|
16812
|
+
if (targetScope && targetScope !== "root") {
|
|
16813
|
+
const { [targetScope]: _, ...rest } = state.gpuStorage;
|
|
16814
|
+
newStorage = rest;
|
|
16815
|
+
} else if (targetScope === "root") {
|
|
16816
|
+
newStorage = {};
|
|
16817
|
+
for (const [key, value] of Object.entries(state.gpuStorage)) {
|
|
16818
|
+
if (!isStorageLike(value)) newStorage[key] = value;
|
|
16819
|
+
}
|
|
16820
|
+
} else {
|
|
16821
|
+
newStorage = {};
|
|
16822
|
+
}
|
|
16823
|
+
return { gpuStorage: newStorage, _hmrVersion: state._hmrVersion + 1 };
|
|
16824
|
+
});
|
|
16825
|
+
},
|
|
16826
|
+
[store]
|
|
16827
|
+
);
|
|
16828
|
+
const disposeStorageFn = useCallback(
|
|
16829
|
+
(names, targetScope) => {
|
|
16830
|
+
const nameArray = Array.isArray(names) ? names : [names];
|
|
16831
|
+
const state = store.getState();
|
|
16832
|
+
for (const name of nameArray) {
|
|
16833
|
+
const storage = targetScope ? state.gpuStorage[targetScope]?.[name] : state.gpuStorage[name];
|
|
16834
|
+
if (storage && isStorageLike(storage)) {
|
|
16835
|
+
disposeStorage(storage);
|
|
16836
|
+
}
|
|
16837
|
+
}
|
|
16838
|
+
removeStorage(names, targetScope);
|
|
16839
|
+
},
|
|
16840
|
+
[store, removeStorage]
|
|
16841
|
+
);
|
|
16842
|
+
const isReader = creatorOrScope === void 0 || typeof creatorOrScope === "string";
|
|
16843
|
+
const storeStorage = useThree((s) => s.gpuStorage);
|
|
16844
|
+
const hmrVersion = useThree((s) => s._hmrVersion);
|
|
16845
|
+
const scopeDep = typeof creatorOrScope === "string" ? creatorOrScope : scope;
|
|
16846
|
+
const readerDep = isReader ? storeStorage : null;
|
|
16847
|
+
const creatorDep = isReader ? null : hmrVersion;
|
|
16848
|
+
const gpuStorage = useMemo(() => {
|
|
16849
|
+
if (creatorOrScope === void 0) {
|
|
16850
|
+
return storeStorage;
|
|
16851
|
+
}
|
|
16852
|
+
if (typeof creatorOrScope === "string") {
|
|
16853
|
+
const scopeData = storeStorage[creatorOrScope];
|
|
16854
|
+
if (scopeData && !isStorageLike(scopeData)) return scopeData;
|
|
16855
|
+
return {};
|
|
16856
|
+
}
|
|
16857
|
+
const state = store.getState();
|
|
16858
|
+
const set = store.setState;
|
|
16859
|
+
const creator = creatorOrScope;
|
|
16860
|
+
const wrappedState = createLazyCreatorState(state);
|
|
16861
|
+
const created = creator(wrappedState);
|
|
16862
|
+
const result = {};
|
|
16863
|
+
let hasNewStorage = false;
|
|
16864
|
+
if (scope) {
|
|
16865
|
+
const currentScope = state.gpuStorage[scope] ?? {};
|
|
16866
|
+
for (const [name, storage] of Object.entries(created)) {
|
|
16867
|
+
if (currentScope[name]) {
|
|
16868
|
+
result[name] = currentScope[name];
|
|
16869
|
+
} else {
|
|
16870
|
+
if ("setName" in storage && typeof storage.setName === "function") {
|
|
16871
|
+
storage.setName(`${scope}.${name}`);
|
|
16872
|
+
}
|
|
16873
|
+
if ("name" in storage && typeof storage.name === "string") {
|
|
16874
|
+
storage.name = `${scope}.${name}`;
|
|
16875
|
+
}
|
|
16876
|
+
result[name] = storage;
|
|
16877
|
+
hasNewStorage = true;
|
|
16878
|
+
}
|
|
16879
|
+
}
|
|
16880
|
+
if (hasNewStorage) {
|
|
16881
|
+
set((s) => ({
|
|
16882
|
+
gpuStorage: {
|
|
16883
|
+
...s.gpuStorage,
|
|
16884
|
+
[scope]: { ...s.gpuStorage[scope], ...result }
|
|
16885
|
+
}
|
|
16886
|
+
}));
|
|
16887
|
+
}
|
|
16888
|
+
return result;
|
|
16889
|
+
}
|
|
16890
|
+
for (const [name, storage] of Object.entries(created)) {
|
|
16891
|
+
const existing = state.gpuStorage[name];
|
|
16892
|
+
if (existing && isStorageLike(existing)) {
|
|
16893
|
+
result[name] = existing;
|
|
16894
|
+
} else {
|
|
16895
|
+
if ("setName" in storage && typeof storage.setName === "function") {
|
|
16896
|
+
storage.setName(name);
|
|
16897
|
+
}
|
|
16898
|
+
if ("name" in storage && typeof storage.name === "string") {
|
|
16899
|
+
storage.name = name;
|
|
16900
|
+
}
|
|
16901
|
+
result[name] = storage;
|
|
16902
|
+
hasNewStorage = true;
|
|
16903
|
+
}
|
|
16904
|
+
}
|
|
16905
|
+
if (hasNewStorage) {
|
|
16906
|
+
set((s) => ({ gpuStorage: { ...s.gpuStorage, ...result } }));
|
|
16907
|
+
}
|
|
16908
|
+
return result;
|
|
16909
|
+
}, [store, scopeDep, readerDep, creatorDep]);
|
|
16910
|
+
return {
|
|
16911
|
+
...gpuStorage,
|
|
16912
|
+
removeStorage,
|
|
16913
|
+
clearStorage,
|
|
16914
|
+
rebuildStorage,
|
|
16915
|
+
disposeStorage: disposeStorageFn
|
|
16916
|
+
};
|
|
16917
|
+
}
|
|
16918
|
+
function rebuildAllStorage(store, scope) {
|
|
16919
|
+
store.setState((state) => {
|
|
16920
|
+
let newStorage = state.gpuStorage;
|
|
16921
|
+
if (scope && scope !== "root") {
|
|
16922
|
+
const { [scope]: _, ...rest } = state.gpuStorage;
|
|
16923
|
+
newStorage = rest;
|
|
16924
|
+
} else if (scope === "root") {
|
|
16925
|
+
newStorage = {};
|
|
16926
|
+
for (const [key, value] of Object.entries(state.gpuStorage)) {
|
|
16927
|
+
if (!isStorageLike(value)) newStorage[key] = value;
|
|
16928
|
+
}
|
|
16929
|
+
} else {
|
|
16930
|
+
newStorage = {};
|
|
16931
|
+
}
|
|
16932
|
+
return { gpuStorage: newStorage, _hmrVersion: state._hmrVersion + 1 };
|
|
16933
|
+
});
|
|
16934
|
+
}
|
|
16935
|
+
|
|
16936
|
+
function useRenderPipeline(mainCB, setupCB) {
|
|
16360
16937
|
const store = useStore();
|
|
16361
16938
|
const { scene, camera, renderer, isLegacy } = useThree();
|
|
16362
16939
|
const callbacksRanRef = useRef(false);
|
|
@@ -16375,7 +16952,7 @@ function usePostProcessing(mainCB, setupCB) {
|
|
|
16375
16952
|
}, [store]);
|
|
16376
16953
|
const reset = useCallback(() => {
|
|
16377
16954
|
store.setState({
|
|
16378
|
-
|
|
16955
|
+
renderPipeline: null,
|
|
16379
16956
|
passes: {}
|
|
16380
16957
|
});
|
|
16381
16958
|
callbacksRanRef.current = false;
|
|
@@ -16388,13 +16965,13 @@ function usePostProcessing(mainCB, setupCB) {
|
|
|
16388
16965
|
}, []);
|
|
16389
16966
|
useLayoutEffect(() => {
|
|
16390
16967
|
if (isLegacy) {
|
|
16391
|
-
throw new Error("
|
|
16968
|
+
throw new Error("useRenderPipeline is only available with WebGPU renderer. Set renderer prop on Canvas.");
|
|
16392
16969
|
}
|
|
16393
16970
|
if (!renderer || !scene || !camera) return;
|
|
16394
16971
|
const state = store.getState();
|
|
16395
16972
|
const set = store.setState;
|
|
16396
16973
|
try {
|
|
16397
|
-
let pp = state.
|
|
16974
|
+
let pp = state.renderPipeline;
|
|
16398
16975
|
let currentPasses = { ...state.passes };
|
|
16399
16976
|
let justCreatedPP = false;
|
|
16400
16977
|
if (!pp) {
|
|
@@ -16411,7 +16988,7 @@ function usePostProcessing(mainCB, setupCB) {
|
|
|
16411
16988
|
}
|
|
16412
16989
|
currentPasses.scenePass = scenePass;
|
|
16413
16990
|
if (!pp.outputNode || justCreatedPP) pp.outputNode = scenePass;
|
|
16414
|
-
set({
|
|
16991
|
+
set({ renderPipeline: pp, passes: currentPasses });
|
|
16415
16992
|
const shouldRunCallbacks = justCreatedPP || !callbacksRanRef.current || !cacheValid;
|
|
16416
16993
|
if (shouldRunCallbacks) {
|
|
16417
16994
|
if (setupCBRef.current) {
|
|
@@ -16433,22 +17010,22 @@ function usePostProcessing(mainCB, setupCB) {
|
|
|
16433
17010
|
callbacksRanRef.current = true;
|
|
16434
17011
|
}
|
|
16435
17012
|
} catch (error) {
|
|
16436
|
-
console.error("[
|
|
17013
|
+
console.error("[useRenderPipeline] Setup error:", error);
|
|
16437
17014
|
}
|
|
16438
17015
|
}, [store, renderer, scene, camera, isLegacy, rebuildVersion]);
|
|
16439
17016
|
const passes = useThree((s) => s.passes);
|
|
16440
|
-
const
|
|
17017
|
+
const renderPipeline = useThree((s) => s.renderPipeline);
|
|
16441
17018
|
return {
|
|
16442
17019
|
passes,
|
|
16443
|
-
|
|
17020
|
+
renderPipeline,
|
|
16444
17021
|
clearPasses,
|
|
16445
17022
|
reset,
|
|
16446
17023
|
rebuild,
|
|
16447
|
-
// isReady indicates if
|
|
16448
|
-
isReady:
|
|
17024
|
+
// isReady indicates if RenderPipeline is configured and ready for rendering
|
|
17025
|
+
isReady: renderPipeline !== null
|
|
16449
17026
|
};
|
|
16450
17027
|
}
|
|
16451
17028
|
|
|
16452
17029
|
extend(THREE);
|
|
16453
17030
|
|
|
16454
|
-
export { Block, Canvas, Environment, EnvironmentCube, EnvironmentMap, EnvironmentPortal, ErrorBoundary, FROM_REF, IsObject, ONCE, Portal, R3F_BUILD_LEGACY, R3F_BUILD_WEBGPU, REACT_INTERNAL_PROPS, RESERVED_PROPS, Scheduler, Texture, _roots, act, addAfterEffect, addEffect, addTail, advance, applyProps, attach, buildGraph, calculateDpr, clearNodeScope, clearRootNodes, clearRootUniforms, clearScope, context, createEvents, createPointerEvents, createPortal, createRoot, createScopedStore, createStore, createTextureOperations, detach, diffProps, dispose, createPointerEvents as events, extend, findInitialRoot, flushSync, fromRef, getInstanceProps, getPrimary, getPrimaryIds, getRootState, getScheduler, getUuidPrefix, hasConstructor, hasPrimary, invalidate, invalidateInstance, is, isColorRepresentation, isCopyable, isFromRef, isObject3D, isOnce, isOrthographicCamera, isRef, isRenderer, isTexture, isVectorLike, once, prepare, presetsObj, rebuildAllNodes, rebuildAllUniforms, reconciler, registerPrimary, removeInteractivity, removeNodes, removeUniforms, resolve, unmountComponentAtNode, unregisterPrimary, updateCamera, updateFrustum, useBridge, useEnvironment, useFrame, useGraph, useInstanceHandle, useIsomorphicLayoutEffect, useLoader, useLocalNodes, useMutableCallback, useNodes,
|
|
17031
|
+
export { Block, Canvas, Environment, EnvironmentCube, EnvironmentMap, EnvironmentPortal, ErrorBoundary, FROM_REF, IsObject, ONCE, Portal, R3F_BUILD_LEGACY, R3F_BUILD_WEBGPU, REACT_INTERNAL_PROPS, RESERVED_PROPS, Scheduler, Texture, _roots, act, addAfterEffect, addEffect, addTail, advance, applyProps, attach, buildGraph, calculateDpr, clearNodeScope, clearRootNodes, clearRootUniforms, clearScope, context, createEvents, createPointerEvents, createPortal, createRoot, createScopedStore, createStore, createTextureOperations, detach, diffProps, dispose, createPointerEvents as events, extend, findInitialRoot, flushSync, fromRef, getInstanceProps, getPrimary, getPrimaryIds, getRootState, getScheduler, getUuidPrefix, hasConstructor, hasPrimary, invalidate, invalidateInstance, is, isColorRepresentation, isCopyable, isFromRef, isObject3D, isOnce, isOrthographicCamera, isRef, isRenderer, isTexture, isVectorLike, once, prepare, presetsObj, rebuildAllBuffers, rebuildAllNodes, rebuildAllStorage, rebuildAllUniforms, reconciler, registerPrimary, removeInteractivity, removeNodes, removeUniforms, resolve, unmountComponentAtNode, unregisterPrimary, updateCamera, updateFrustum, useBridge, useBuffers, useEnvironment, useFrame, useGPUStorage, useGraph, useInstanceHandle, useIsomorphicLayoutEffect, useLoader, useLocalNodes, useMutableCallback, useNodes, useRenderPipeline, useRenderTarget, useStore, useTexture, useTextures, useThree, useUniform, useUniforms, waitForPrimary };
|