@react-three/fiber 10.0.0-canary.b0fafc8 → 10.0.0-canary.d6fdf72
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +440 -188
- package/dist/index.d.cts +236 -80
- package/dist/index.d.mts +236 -80
- package/dist/index.d.ts +236 -80
- package/dist/index.mjs +441 -189
- package/dist/legacy.cjs +434 -188
- package/dist/legacy.d.cts +236 -80
- package/dist/legacy.d.mts +236 -80
- package/dist/legacy.d.ts +236 -80
- package/dist/legacy.mjs +435 -189
- package/dist/webgpu/index.cjs +815 -199
- package/dist/webgpu/index.d.cts +321 -93
- package/dist/webgpu/index.d.mts +321 -93
- package/dist/webgpu/index.d.ts +321 -93
- package/dist/webgpu/index.mjs +812 -200
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as webgpu from 'three/webgpu';
|
|
2
|
-
import { RenderTarget, CubeReflectionMapping, EquirectangularReflectionMapping, CubeTextureLoader, Scene, WebGLCubeRenderTarget, HalfFloatType, Color, Frustum, Matrix4, Group, BoxGeometry, MeshBasicNodeMaterial, Mesh, Node, NodeUpdateType, Layers, SRGBColorSpace, RGBAFormat, UnsignedByteType, Vector3, Vector2, TextureLoader, Texture as Texture$1, CanvasTarget, Raycaster, OrthographicCamera, PerspectiveCamera,
|
|
2
|
+
import { RenderTarget, CubeReflectionMapping, EquirectangularReflectionMapping, CubeTextureLoader, Scene, WebGLCubeRenderTarget, HalfFloatType, Color, Frustum, Matrix4, Group, BoxGeometry, MeshBasicNodeMaterial, Mesh, Node, NodeUpdateType, Layers, SRGBColorSpace, RGBAFormat, UnsignedByteType, Vector3, Vector2, TextureLoader, Texture as Texture$1, CanvasTarget, Raycaster, OrthographicCamera, PerspectiveCamera, PCFShadowMap, VSMShadowMap, BasicShadowMap, ACESFilmicToneMapping, WebGPURenderer } from 'three/webgpu';
|
|
3
3
|
import { WebGLRenderTarget, WebGLRenderer } from 'three';
|
|
4
4
|
import { Inspector } from 'three/addons/inspector/Inspector.js';
|
|
5
5
|
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
@@ -139,7 +139,7 @@ function useEnvironment({
|
|
|
139
139
|
useLoader$1.clear(loader, multiFile ? [files] : files);
|
|
140
140
|
}
|
|
141
141
|
renderer.domElement.addEventListener("webglcontextlost", clearGainmapTexture, { once: true });
|
|
142
|
-
}, [files, renderer.domElement]);
|
|
142
|
+
}, [extension, files, loader, multiFile, renderer.domElement]);
|
|
143
143
|
const loaderResult = useLoader$1(
|
|
144
144
|
loader,
|
|
145
145
|
multiFile ? [files] : files,
|
|
@@ -339,7 +339,22 @@ function EnvironmentPortal({
|
|
|
339
339
|
environmentIntensity,
|
|
340
340
|
environmentRotation
|
|
341
341
|
});
|
|
342
|
-
}, [
|
|
342
|
+
}, [
|
|
343
|
+
children,
|
|
344
|
+
virtualScene,
|
|
345
|
+
fbo.texture,
|
|
346
|
+
scene,
|
|
347
|
+
defaultScene,
|
|
348
|
+
background,
|
|
349
|
+
frames,
|
|
350
|
+
gl,
|
|
351
|
+
blur,
|
|
352
|
+
backgroundBlurriness,
|
|
353
|
+
backgroundIntensity,
|
|
354
|
+
backgroundRotation,
|
|
355
|
+
environmentIntensity,
|
|
356
|
+
environmentRotation
|
|
357
|
+
]);
|
|
343
358
|
let count = 1;
|
|
344
359
|
useFrame$1(() => {
|
|
345
360
|
if (frames === Infinity || count < frames) {
|
|
@@ -975,6 +990,9 @@ function applyProps(object, props) {
|
|
|
975
990
|
else target.set(value);
|
|
976
991
|
} else {
|
|
977
992
|
root[key] = value;
|
|
993
|
+
if (key.endsWith("Node") && root.isMaterial) {
|
|
994
|
+
root.needsUpdate = true;
|
|
995
|
+
}
|
|
978
996
|
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
|
|
979
997
|
root[key].format === RGBAFormat && root[key].type === UnsignedByteType) {
|
|
980
998
|
root[key].colorSpace = rootState.textureColorSpace;
|
|
@@ -1008,38 +1026,60 @@ function applyProps(object, props) {
|
|
|
1008
1026
|
return object;
|
|
1009
1027
|
}
|
|
1010
1028
|
|
|
1029
|
+
const DEFAULT_POINTER_ID = 0;
|
|
1030
|
+
const XR_POINTER_ID_START = 1e3;
|
|
1031
|
+
function getPointerState(internal, pointerId) {
|
|
1032
|
+
let state = internal.pointerMap.get(pointerId);
|
|
1033
|
+
if (!state) {
|
|
1034
|
+
state = {
|
|
1035
|
+
hovered: /* @__PURE__ */ new Map(),
|
|
1036
|
+
captured: /* @__PURE__ */ new Map(),
|
|
1037
|
+
initialClick: [0, 0],
|
|
1038
|
+
initialHits: []
|
|
1039
|
+
};
|
|
1040
|
+
internal.pointerMap.set(pointerId, state);
|
|
1041
|
+
}
|
|
1042
|
+
return state;
|
|
1043
|
+
}
|
|
1044
|
+
function getPointerId(event) {
|
|
1045
|
+
return "pointerId" in event ? event.pointerId : DEFAULT_POINTER_ID;
|
|
1046
|
+
}
|
|
1011
1047
|
function makeId(event) {
|
|
1012
1048
|
return (event.eventObject || event.object).uuid + "/" + event.index + event.instanceId;
|
|
1013
1049
|
}
|
|
1014
|
-
function releaseInternalPointerCapture(
|
|
1015
|
-
const
|
|
1050
|
+
function releaseInternalPointerCapture(internal, obj, pointerId) {
|
|
1051
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1052
|
+
if (!pointerState) return;
|
|
1053
|
+
const captureData = pointerState.captured.get(obj);
|
|
1016
1054
|
if (captureData) {
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
capturedMap.delete(pointerId);
|
|
1020
|
-
captureData.target.releasePointerCapture(pointerId);
|
|
1021
|
-
}
|
|
1055
|
+
pointerState.captured.delete(obj);
|
|
1056
|
+
captureData.target.releasePointerCapture(pointerId);
|
|
1022
1057
|
}
|
|
1023
1058
|
}
|
|
1024
1059
|
function removeInteractivity(store, object) {
|
|
1025
1060
|
const { internal } = store.getState();
|
|
1026
1061
|
internal.interaction = internal.interaction.filter((o) => o !== object);
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1062
|
+
for (const [pointerId, pointerState] of internal.pointerMap) {
|
|
1063
|
+
pointerState.initialHits = pointerState.initialHits.filter((o) => o !== object);
|
|
1064
|
+
pointerState.hovered.forEach((value, key) => {
|
|
1065
|
+
if (value.eventObject === object || value.object === object) {
|
|
1066
|
+
pointerState.hovered.delete(key);
|
|
1067
|
+
}
|
|
1068
|
+
});
|
|
1069
|
+
if (pointerState.captured.has(object)) {
|
|
1070
|
+
releaseInternalPointerCapture(internal, object, pointerId);
|
|
1031
1071
|
}
|
|
1032
|
-
}
|
|
1033
|
-
internal.capturedMap.forEach((captures, pointerId) => {
|
|
1034
|
-
releaseInternalPointerCapture(internal.capturedMap, object, captures, pointerId);
|
|
1035
|
-
});
|
|
1072
|
+
}
|
|
1036
1073
|
unregisterVisibility(store, object);
|
|
1037
1074
|
}
|
|
1038
1075
|
function createEvents(store) {
|
|
1039
|
-
function calculateDistance(event) {
|
|
1076
|
+
function calculateDistance(event, pointerId) {
|
|
1040
1077
|
const { internal } = store.getState();
|
|
1041
|
-
const
|
|
1042
|
-
|
|
1078
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1079
|
+
if (!pointerState) return 0;
|
|
1080
|
+
const [initialX, initialY] = pointerState.initialClick;
|
|
1081
|
+
const dx = event.offsetX - initialX;
|
|
1082
|
+
const dy = event.offsetY - initialY;
|
|
1043
1083
|
return Math.round(Math.sqrt(dx * dx + dy * dy));
|
|
1044
1084
|
}
|
|
1045
1085
|
function filterPointerEvents(objects) {
|
|
@@ -1075,6 +1115,15 @@ function createEvents(store) {
|
|
|
1075
1115
|
return state2.raycaster.camera ? state2.raycaster.intersectObject(obj, true) : [];
|
|
1076
1116
|
}
|
|
1077
1117
|
let hits = eventsObjects.flatMap(handleRaycast).sort((a, b) => {
|
|
1118
|
+
const aInteractivePriority = a.object.userData?.interactivePriority;
|
|
1119
|
+
const bInteractivePriority = b.object.userData?.interactivePriority;
|
|
1120
|
+
if (aInteractivePriority !== void 0 || bInteractivePriority !== void 0) {
|
|
1121
|
+
if (aInteractivePriority !== void 0 && bInteractivePriority === void 0) return -1;
|
|
1122
|
+
if (bInteractivePriority !== void 0 && aInteractivePriority === void 0) return 1;
|
|
1123
|
+
if (aInteractivePriority !== bInteractivePriority) {
|
|
1124
|
+
return (bInteractivePriority ?? 0) - (aInteractivePriority ?? 0);
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1078
1127
|
const aState = getRootState(a.object);
|
|
1079
1128
|
const bState = getRootState(b.object);
|
|
1080
1129
|
const aPriority = aState?.events?.priority ?? 1;
|
|
@@ -1096,9 +1145,13 @@ function createEvents(store) {
|
|
|
1096
1145
|
eventObject = eventObject.parent;
|
|
1097
1146
|
}
|
|
1098
1147
|
}
|
|
1099
|
-
if ("pointerId" in event
|
|
1100
|
-
|
|
1101
|
-
|
|
1148
|
+
if ("pointerId" in event) {
|
|
1149
|
+
const pointerId = event.pointerId;
|
|
1150
|
+
const pointerState = state.internal.pointerMap.get(pointerId);
|
|
1151
|
+
if (pointerState?.captured.size) {
|
|
1152
|
+
for (const captureData of pointerState.captured.values()) {
|
|
1153
|
+
if (!duplicates.has(makeId(captureData.intersection))) intersections.push(captureData.intersection);
|
|
1154
|
+
}
|
|
1102
1155
|
}
|
|
1103
1156
|
}
|
|
1104
1157
|
return intersections;
|
|
@@ -1111,27 +1164,25 @@ function createEvents(store) {
|
|
|
1111
1164
|
if (state) {
|
|
1112
1165
|
const { raycaster, pointer, camera, internal } = state;
|
|
1113
1166
|
const unprojectedPoint = new Vector3(pointer.x, pointer.y, 0).unproject(camera);
|
|
1114
|
-
const hasPointerCapture = (id) =>
|
|
1167
|
+
const hasPointerCapture = (id) => {
|
|
1168
|
+
const pointerState = internal.pointerMap.get(id);
|
|
1169
|
+
return pointerState?.captured.has(hit.eventObject) ?? false;
|
|
1170
|
+
};
|
|
1115
1171
|
const setPointerCapture = (id) => {
|
|
1116
1172
|
const captureData = { intersection: hit, target: event.target };
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
} else {
|
|
1120
|
-
internal.capturedMap.set(id, /* @__PURE__ */ new Map([[hit.eventObject, captureData]]));
|
|
1121
|
-
}
|
|
1173
|
+
const pointerState = getPointerState(internal, id);
|
|
1174
|
+
pointerState.captured.set(hit.eventObject, captureData);
|
|
1122
1175
|
event.target.setPointerCapture(id);
|
|
1123
1176
|
};
|
|
1124
1177
|
const releasePointerCapture = (id) => {
|
|
1125
|
-
|
|
1126
|
-
if (captures) {
|
|
1127
|
-
releaseInternalPointerCapture(internal.capturedMap, hit.eventObject, captures, id);
|
|
1128
|
-
}
|
|
1178
|
+
releaseInternalPointerCapture(internal, hit.eventObject, id);
|
|
1129
1179
|
};
|
|
1130
1180
|
const extractEventProps = {};
|
|
1131
1181
|
for (const prop in event) {
|
|
1132
1182
|
const property = event[prop];
|
|
1133
1183
|
if (typeof property !== "function") extractEventProps[prop] = property;
|
|
1134
1184
|
}
|
|
1185
|
+
const eventPointerId = "pointerId" in event ? event.pointerId : void 0;
|
|
1135
1186
|
const raycastEvent = {
|
|
1136
1187
|
...hit,
|
|
1137
1188
|
...extractEventProps,
|
|
@@ -1142,18 +1193,19 @@ function createEvents(store) {
|
|
|
1142
1193
|
unprojectedPoint,
|
|
1143
1194
|
ray: raycaster.ray,
|
|
1144
1195
|
camera,
|
|
1196
|
+
pointerId: eventPointerId,
|
|
1145
1197
|
// Hijack stopPropagation, which just sets a flag
|
|
1146
1198
|
stopPropagation() {
|
|
1147
|
-
const
|
|
1199
|
+
const pointerState = eventPointerId !== void 0 ? internal.pointerMap.get(eventPointerId) : void 0;
|
|
1148
1200
|
if (
|
|
1149
1201
|
// ...if this pointer hasn't been captured
|
|
1150
|
-
!
|
|
1151
|
-
|
|
1202
|
+
!pointerState?.captured.size || // ... or if the hit object is capturing the pointer
|
|
1203
|
+
pointerState.captured.has(hit.eventObject)
|
|
1152
1204
|
) {
|
|
1153
1205
|
raycastEvent.stopped = localState.stopped = true;
|
|
1154
|
-
if (
|
|
1206
|
+
if (pointerState?.hovered.size && Array.from(pointerState.hovered.values()).find((i) => i.eventObject === hit.eventObject)) {
|
|
1155
1207
|
const higher = intersections.slice(0, intersections.indexOf(hit));
|
|
1156
|
-
cancelPointer([...higher, hit]);
|
|
1208
|
+
cancelPointer([...higher, hit], eventPointerId);
|
|
1157
1209
|
}
|
|
1158
1210
|
}
|
|
1159
1211
|
},
|
|
@@ -1169,15 +1221,18 @@ function createEvents(store) {
|
|
|
1169
1221
|
}
|
|
1170
1222
|
return intersections;
|
|
1171
1223
|
}
|
|
1172
|
-
function cancelPointer(intersections) {
|
|
1224
|
+
function cancelPointer(intersections, pointerId) {
|
|
1173
1225
|
const { internal } = store.getState();
|
|
1174
|
-
|
|
1226
|
+
const pid = pointerId ?? DEFAULT_POINTER_ID;
|
|
1227
|
+
const pointerState = internal.pointerMap.get(pid);
|
|
1228
|
+
if (!pointerState) return;
|
|
1229
|
+
for (const [hoveredId, hoveredObj] of pointerState.hovered) {
|
|
1175
1230
|
if (!intersections.length || !intersections.find(
|
|
1176
1231
|
(hit) => hit.object === hoveredObj.object && hit.index === hoveredObj.index && hit.instanceId === hoveredObj.instanceId
|
|
1177
1232
|
)) {
|
|
1178
1233
|
const eventObject = hoveredObj.eventObject;
|
|
1179
1234
|
const instance = eventObject.__r3f;
|
|
1180
|
-
|
|
1235
|
+
pointerState.hovered.delete(hoveredId);
|
|
1181
1236
|
if (instance?.eventCount) {
|
|
1182
1237
|
const handlers = instance.handlers;
|
|
1183
1238
|
const data = { ...hoveredObj, intersections };
|
|
@@ -1206,41 +1261,118 @@ function createEvents(store) {
|
|
|
1206
1261
|
instance?.handlers.onDropMissed?.(event);
|
|
1207
1262
|
}
|
|
1208
1263
|
}
|
|
1264
|
+
function cleanupPointer(pointerId) {
|
|
1265
|
+
const { internal } = store.getState();
|
|
1266
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1267
|
+
if (pointerState) {
|
|
1268
|
+
for (const [, hoveredObj] of pointerState.hovered) {
|
|
1269
|
+
const eventObject = hoveredObj.eventObject;
|
|
1270
|
+
const instance = eventObject.__r3f;
|
|
1271
|
+
if (instance?.eventCount) {
|
|
1272
|
+
const handlers = instance.handlers;
|
|
1273
|
+
const data = { ...hoveredObj, intersections: [] };
|
|
1274
|
+
handlers.onPointerOut?.(data);
|
|
1275
|
+
handlers.onPointerLeave?.(data);
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
internal.pointerMap.delete(pointerId);
|
|
1279
|
+
}
|
|
1280
|
+
internal.pointerDirty.delete(pointerId);
|
|
1281
|
+
}
|
|
1282
|
+
function processDeferredPointer(event, pointerId) {
|
|
1283
|
+
const state = store.getState();
|
|
1284
|
+
const { internal } = state;
|
|
1285
|
+
if (!state.events.enabled) return;
|
|
1286
|
+
const filter = filterPointerEvents;
|
|
1287
|
+
const hits = intersect(event, filter);
|
|
1288
|
+
cancelPointer(hits, pointerId);
|
|
1289
|
+
function onIntersect(data) {
|
|
1290
|
+
const eventObject = data.eventObject;
|
|
1291
|
+
const instance = eventObject.__r3f;
|
|
1292
|
+
if (!instance?.eventCount) return;
|
|
1293
|
+
const handlers = instance.handlers;
|
|
1294
|
+
if (handlers.onPointerOver || handlers.onPointerEnter || handlers.onPointerOut || handlers.onPointerLeave) {
|
|
1295
|
+
const id = makeId(data);
|
|
1296
|
+
const pointerState = getPointerState(internal, pointerId);
|
|
1297
|
+
const hoveredItem = pointerState.hovered.get(id);
|
|
1298
|
+
if (!hoveredItem) {
|
|
1299
|
+
pointerState.hovered.set(id, data);
|
|
1300
|
+
handlers.onPointerOver?.(data);
|
|
1301
|
+
handlers.onPointerEnter?.(data);
|
|
1302
|
+
} else if (hoveredItem.stopped) {
|
|
1303
|
+
data.stopPropagation();
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
handlers.onPointerMove?.(data);
|
|
1307
|
+
}
|
|
1308
|
+
handleIntersects(hits, event, 0, onIntersect);
|
|
1309
|
+
}
|
|
1209
1310
|
function handlePointer(name) {
|
|
1210
1311
|
switch (name) {
|
|
1211
1312
|
case "onPointerLeave":
|
|
1212
|
-
case "onPointerCancel":
|
|
1213
1313
|
case "onDragLeave":
|
|
1214
1314
|
return () => cancelPointer([]);
|
|
1315
|
+
// Global cancel of these events
|
|
1316
|
+
case "onPointerCancel":
|
|
1317
|
+
return (event) => {
|
|
1318
|
+
const pointerId = getPointerId(event);
|
|
1319
|
+
cleanupPointer(pointerId);
|
|
1320
|
+
};
|
|
1215
1321
|
case "onLostPointerCapture":
|
|
1216
1322
|
return (event) => {
|
|
1217
1323
|
const { internal } = store.getState();
|
|
1218
|
-
|
|
1324
|
+
const pointerId = getPointerId(event);
|
|
1325
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1326
|
+
if (pointerState?.captured.size) {
|
|
1219
1327
|
requestAnimationFrame(() => {
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1328
|
+
const pointerState2 = internal.pointerMap.get(pointerId);
|
|
1329
|
+
if (pointerState2?.captured.size) {
|
|
1330
|
+
pointerState2.captured.clear();
|
|
1223
1331
|
}
|
|
1332
|
+
cancelPointer([], pointerId);
|
|
1224
1333
|
});
|
|
1225
1334
|
}
|
|
1226
1335
|
};
|
|
1227
1336
|
}
|
|
1228
1337
|
return function handleEvent(event) {
|
|
1229
1338
|
const state = store.getState();
|
|
1230
|
-
const { onPointerMissed, onDragOverMissed, onDropMissed, internal } = state;
|
|
1339
|
+
const { onPointerMissed, onDragOverMissed, onDropMissed, internal, events } = state;
|
|
1340
|
+
const pointerId = getPointerId(event);
|
|
1231
1341
|
internal.lastEvent.current = event;
|
|
1232
|
-
if (!
|
|
1342
|
+
if (!events.enabled) return;
|
|
1233
1343
|
const isPointerMove = name === "onPointerMove";
|
|
1234
1344
|
const isDragOver = name === "onDragOver";
|
|
1235
1345
|
const isDrop = name === "onDrop";
|
|
1236
1346
|
const isClickEvent = name === "onClick" || name === "onContextMenu" || name === "onDoubleClick";
|
|
1347
|
+
const isPointerDown = name === "onPointerDown";
|
|
1348
|
+
const isPointerUp = name === "onPointerUp";
|
|
1349
|
+
const isWheel = name === "onWheel";
|
|
1350
|
+
const canDeferRaycasts = events.frameTimedRaycasts && state.frameloop === "always";
|
|
1351
|
+
if (isPointerMove && canDeferRaycasts) {
|
|
1352
|
+
events.compute?.(event, state);
|
|
1353
|
+
internal.pointerDirty.set(pointerId, event);
|
|
1354
|
+
return;
|
|
1355
|
+
}
|
|
1356
|
+
if (isWheel && canDeferRaycasts && !events.alwaysFireOnScroll) {
|
|
1357
|
+
events.compute?.(event, state);
|
|
1358
|
+
internal.pointerDirty.set(pointerId, event);
|
|
1359
|
+
return;
|
|
1360
|
+
}
|
|
1361
|
+
if ((isClickEvent || isPointerDown || isPointerUp) && internal.pointerDirty.has(pointerId)) {
|
|
1362
|
+
const deferredEvent = internal.pointerDirty.get(pointerId);
|
|
1363
|
+
internal.pointerDirty.delete(pointerId);
|
|
1364
|
+
processDeferredPointer(deferredEvent, pointerId);
|
|
1365
|
+
}
|
|
1237
1366
|
const filter = isPointerMove || isDragOver || isDrop ? filterPointerEvents : void 0;
|
|
1238
1367
|
const hits = intersect(event, filter);
|
|
1239
|
-
const delta = isClickEvent ? calculateDistance(event) : 0;
|
|
1240
|
-
if (
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1368
|
+
const delta = isClickEvent ? calculateDistance(event, pointerId) : 0;
|
|
1369
|
+
if (isPointerDown) {
|
|
1370
|
+
const pointerState2 = getPointerState(internal, pointerId);
|
|
1371
|
+
pointerState2.initialClick = [event.offsetX, event.offsetY];
|
|
1372
|
+
pointerState2.initialHits = hits.map((hit) => hit.eventObject);
|
|
1373
|
+
}
|
|
1374
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1375
|
+
const initialHits = pointerState?.initialHits ?? [];
|
|
1244
1376
|
if (isClickEvent && !hits.length) {
|
|
1245
1377
|
if (delta <= 2) {
|
|
1246
1378
|
pointerMissed(event, internal.interaction);
|
|
@@ -1255,7 +1387,9 @@ function createEvents(store) {
|
|
|
1255
1387
|
dropMissed(event, internal.interaction);
|
|
1256
1388
|
if (onDropMissed) onDropMissed(event);
|
|
1257
1389
|
}
|
|
1258
|
-
if (isPointerMove || isDragOver)
|
|
1390
|
+
if (isPointerMove || isDragOver) {
|
|
1391
|
+
cancelPointer(hits, pointerId);
|
|
1392
|
+
}
|
|
1259
1393
|
function onIntersect(data) {
|
|
1260
1394
|
const eventObject = data.eventObject;
|
|
1261
1395
|
const instance = eventObject.__r3f;
|
|
@@ -1264,9 +1398,10 @@ function createEvents(store) {
|
|
|
1264
1398
|
if (isPointerMove) {
|
|
1265
1399
|
if (handlers.onPointerOver || handlers.onPointerEnter || handlers.onPointerOut || handlers.onPointerLeave) {
|
|
1266
1400
|
const id = makeId(data);
|
|
1267
|
-
const
|
|
1401
|
+
const pointerState2 = getPointerState(internal, pointerId);
|
|
1402
|
+
const hoveredItem = pointerState2.hovered.get(id);
|
|
1268
1403
|
if (!hoveredItem) {
|
|
1269
|
-
|
|
1404
|
+
pointerState2.hovered.set(id, data);
|
|
1270
1405
|
handlers.onPointerOver?.(data);
|
|
1271
1406
|
handlers.onPointerEnter?.(data);
|
|
1272
1407
|
} else if (hoveredItem.stopped) {
|
|
@@ -1276,9 +1411,10 @@ function createEvents(store) {
|
|
|
1276
1411
|
handlers.onPointerMove?.(data);
|
|
1277
1412
|
} else if (isDragOver) {
|
|
1278
1413
|
const id = makeId(data);
|
|
1279
|
-
const
|
|
1414
|
+
const pointerState2 = getPointerState(internal, pointerId);
|
|
1415
|
+
const hoveredItem = pointerState2.hovered.get(id);
|
|
1280
1416
|
if (!hoveredItem) {
|
|
1281
|
-
|
|
1417
|
+
pointerState2.hovered.set(id, data);
|
|
1282
1418
|
handlers.onDragOverEnter?.(data);
|
|
1283
1419
|
} else if (hoveredItem.stopped) {
|
|
1284
1420
|
data.stopPropagation();
|
|
@@ -1289,18 +1425,18 @@ function createEvents(store) {
|
|
|
1289
1425
|
} else {
|
|
1290
1426
|
const handler = handlers[name];
|
|
1291
1427
|
if (handler) {
|
|
1292
|
-
if (!isClickEvent ||
|
|
1428
|
+
if (!isClickEvent || initialHits.includes(eventObject)) {
|
|
1293
1429
|
pointerMissed(
|
|
1294
1430
|
event,
|
|
1295
|
-
internal.interaction.filter((object) => !
|
|
1431
|
+
internal.interaction.filter((object) => !initialHits.includes(object))
|
|
1296
1432
|
);
|
|
1297
1433
|
handler(data);
|
|
1298
1434
|
}
|
|
1299
1435
|
} else {
|
|
1300
|
-
if (isClickEvent &&
|
|
1436
|
+
if (isClickEvent && initialHits.includes(eventObject)) {
|
|
1301
1437
|
pointerMissed(
|
|
1302
1438
|
event,
|
|
1303
|
-
internal.interaction.filter((object) => !
|
|
1439
|
+
internal.interaction.filter((object) => !initialHits.includes(object))
|
|
1304
1440
|
);
|
|
1305
1441
|
}
|
|
1306
1442
|
}
|
|
@@ -1309,7 +1445,15 @@ function createEvents(store) {
|
|
|
1309
1445
|
handleIntersects(hits, event, delta, onIntersect);
|
|
1310
1446
|
};
|
|
1311
1447
|
}
|
|
1312
|
-
|
|
1448
|
+
function flushDeferredPointers() {
|
|
1449
|
+
const { internal, events } = store.getState();
|
|
1450
|
+
if (!events.frameTimedRaycasts) return;
|
|
1451
|
+
for (const [pointerId, event] of internal.pointerDirty) {
|
|
1452
|
+
processDeferredPointer(event, pointerId);
|
|
1453
|
+
}
|
|
1454
|
+
internal.pointerDirty.clear();
|
|
1455
|
+
}
|
|
1456
|
+
return { handlePointer, flushDeferredPointers, processDeferredPointer };
|
|
1313
1457
|
}
|
|
1314
1458
|
const DOM_EVENTS = {
|
|
1315
1459
|
onClick: ["click", false],
|
|
@@ -1328,10 +1472,15 @@ const DOM_EVENTS = {
|
|
|
1328
1472
|
onLostPointerCapture: ["lostpointercapture", true]
|
|
1329
1473
|
};
|
|
1330
1474
|
function createPointerEvents(store) {
|
|
1331
|
-
const { handlePointer } = createEvents(store);
|
|
1475
|
+
const { handlePointer, flushDeferredPointers, processDeferredPointer } = createEvents(store);
|
|
1476
|
+
let nextXRPointerId = XR_POINTER_ID_START;
|
|
1477
|
+
const xrPointers = /* @__PURE__ */ new Map();
|
|
1332
1478
|
return {
|
|
1333
1479
|
priority: 1,
|
|
1334
1480
|
enabled: true,
|
|
1481
|
+
frameTimedRaycasts: true,
|
|
1482
|
+
alwaysFireOnScroll: true,
|
|
1483
|
+
updateOnFrame: false,
|
|
1335
1484
|
compute(event, state) {
|
|
1336
1485
|
state.pointer.set(event.offsetX / state.size.width * 2 - 1, -(event.offsetY / state.size.height) * 2 + 1);
|
|
1337
1486
|
state.raycaster.setFromCamera(state.pointer, state.camera);
|
|
@@ -1341,11 +1490,33 @@ function createPointerEvents(store) {
|
|
|
1341
1490
|
(acc, key) => ({ ...acc, [key]: handlePointer(key) }),
|
|
1342
1491
|
{}
|
|
1343
1492
|
),
|
|
1344
|
-
update: () => {
|
|
1493
|
+
update: (pointerId) => {
|
|
1345
1494
|
const { events, internal } = store.getState();
|
|
1346
|
-
if (
|
|
1495
|
+
if (!events.handlers) return;
|
|
1496
|
+
if (pointerId !== void 0) {
|
|
1497
|
+
const event = internal.pointerDirty.get(pointerId);
|
|
1498
|
+
if (event) {
|
|
1499
|
+
internal.pointerDirty.delete(pointerId);
|
|
1500
|
+
processDeferredPointer(event, pointerId);
|
|
1501
|
+
} else if (internal.lastEvent?.current) {
|
|
1502
|
+
processDeferredPointer(internal.lastEvent.current, pointerId);
|
|
1503
|
+
}
|
|
1504
|
+
} else {
|
|
1505
|
+
flushDeferredPointers();
|
|
1506
|
+
if (internal.lastEvent?.current) {
|
|
1507
|
+
events.handlers.onPointerMove(internal.lastEvent.current);
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
},
|
|
1511
|
+
flush: () => {
|
|
1512
|
+
const { events, internal } = store.getState();
|
|
1513
|
+
flushDeferredPointers();
|
|
1514
|
+
if (events.updateOnFrame && internal.lastEvent?.current && events.handlers) {
|
|
1515
|
+
events.handlers.onPointerMove(internal.lastEvent.current);
|
|
1516
|
+
}
|
|
1347
1517
|
},
|
|
1348
1518
|
connect: (target) => {
|
|
1519
|
+
if (!target) return;
|
|
1349
1520
|
const { set, events } = store.getState();
|
|
1350
1521
|
events.disconnect?.();
|
|
1351
1522
|
set((state) => ({ events: { ...state.events, connected: target } }));
|
|
@@ -1369,6 +1540,32 @@ function createPointerEvents(store) {
|
|
|
1369
1540
|
}
|
|
1370
1541
|
set((state) => ({ events: { ...state.events, connected: void 0 } }));
|
|
1371
1542
|
}
|
|
1543
|
+
},
|
|
1544
|
+
registerPointer: (config) => {
|
|
1545
|
+
const pointerId = nextXRPointerId++;
|
|
1546
|
+
xrPointers.set(pointerId, config);
|
|
1547
|
+
const { internal } = store.getState();
|
|
1548
|
+
getPointerState(internal, pointerId);
|
|
1549
|
+
return pointerId;
|
|
1550
|
+
},
|
|
1551
|
+
unregisterPointer: (pointerId) => {
|
|
1552
|
+
xrPointers.delete(pointerId);
|
|
1553
|
+
const { internal } = store.getState();
|
|
1554
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1555
|
+
if (pointerState) {
|
|
1556
|
+
for (const [, hoveredObj] of pointerState.hovered) {
|
|
1557
|
+
const eventObject = hoveredObj.eventObject;
|
|
1558
|
+
const instance = eventObject.__r3f;
|
|
1559
|
+
if (instance?.eventCount) {
|
|
1560
|
+
const handlers = instance.handlers;
|
|
1561
|
+
const data = { ...hoveredObj, intersections: [] };
|
|
1562
|
+
handlers.onPointerOut?.(data);
|
|
1563
|
+
handlers.onPointerLeave?.(data);
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
internal.pointerMap.delete(pointerId);
|
|
1567
|
+
}
|
|
1568
|
+
internal.pointerDirty.delete(pointerId);
|
|
1372
1569
|
}
|
|
1373
1570
|
};
|
|
1374
1571
|
}
|
|
@@ -1682,7 +1879,7 @@ function shouldRun(job, now) {
|
|
|
1682
1879
|
const minInterval = 1e3 / job.fps;
|
|
1683
1880
|
const lastRun = job.lastRun ?? 0;
|
|
1684
1881
|
const elapsed = now - lastRun;
|
|
1685
|
-
if (elapsed < minInterval) return false;
|
|
1882
|
+
if (elapsed < minInterval - 1) return false;
|
|
1686
1883
|
if (job.drop) {
|
|
1687
1884
|
job.lastRun = now;
|
|
1688
1885
|
} else {
|
|
@@ -2499,7 +2696,14 @@ const createStore = (invalidate, advance) => {
|
|
|
2499
2696
|
frustum: new Frustum(),
|
|
2500
2697
|
autoUpdateFrustum: true,
|
|
2501
2698
|
raycaster: null,
|
|
2502
|
-
events: {
|
|
2699
|
+
events: {
|
|
2700
|
+
priority: 1,
|
|
2701
|
+
enabled: true,
|
|
2702
|
+
connected: false,
|
|
2703
|
+
frameTimedRaycasts: true,
|
|
2704
|
+
alwaysFireOnScroll: true,
|
|
2705
|
+
updateOnFrame: false
|
|
2706
|
+
},
|
|
2503
2707
|
scene: null,
|
|
2504
2708
|
rootScene: null,
|
|
2505
2709
|
xr: null,
|
|
@@ -2590,11 +2794,14 @@ const createStore = (invalidate, advance) => {
|
|
|
2590
2794
|
},
|
|
2591
2795
|
setError: (error) => set(() => ({ error })),
|
|
2592
2796
|
error: null,
|
|
2593
|
-
//* TSL State (managed via hooks: useUniforms, useNodes, useTextures,
|
|
2797
|
+
//* TSL State (managed via hooks: useUniforms, useNodes, useBuffers, useGPUStorage, useTextures, useRenderPipeline) ==============================
|
|
2594
2798
|
uniforms: {},
|
|
2595
2799
|
nodes: {},
|
|
2800
|
+
buffers: {},
|
|
2801
|
+
gpuStorage: {},
|
|
2596
2802
|
textures: /* @__PURE__ */ new Map(),
|
|
2597
|
-
|
|
2803
|
+
_textureRefs: /* @__PURE__ */ new Map(),
|
|
2804
|
+
renderPipeline: null,
|
|
2598
2805
|
passes: {},
|
|
2599
2806
|
_hmrVersion: 0,
|
|
2600
2807
|
_sizeImperative: false,
|
|
@@ -2603,12 +2810,16 @@ const createStore = (invalidate, advance) => {
|
|
|
2603
2810
|
internal: {
|
|
2604
2811
|
// Events
|
|
2605
2812
|
interaction: [],
|
|
2606
|
-
hovered: /* @__PURE__ */ new Map(),
|
|
2607
2813
|
subscribers: [],
|
|
2814
|
+
// Per-pointer state (new unified structure)
|
|
2815
|
+
pointerMap: /* @__PURE__ */ new Map(),
|
|
2816
|
+
pointerDirty: /* @__PURE__ */ new Map(),
|
|
2817
|
+
lastEvent: React.createRef(),
|
|
2818
|
+
// Deprecated but kept for backwards compatibility
|
|
2819
|
+
hovered: /* @__PURE__ */ new Map(),
|
|
2608
2820
|
initialClick: [0, 0],
|
|
2609
2821
|
initialHits: [],
|
|
2610
2822
|
capturedMap: /* @__PURE__ */ new Map(),
|
|
2611
|
-
lastEvent: React.createRef(),
|
|
2612
2823
|
// Visibility tracking (onFramed, onOccluded, onVisible)
|
|
2613
2824
|
visibilityRegistry: /* @__PURE__ */ new Map(),
|
|
2614
2825
|
// Occlusion system (WebGPU only)
|
|
@@ -2696,14 +2907,16 @@ const createStore = (invalidate, advance) => {
|
|
|
2696
2907
|
oldSize = size;
|
|
2697
2908
|
oldDpr = viewport.dpr;
|
|
2698
2909
|
updateCamera(camera, size);
|
|
2699
|
-
if (canvasTarget) {
|
|
2910
|
+
if (internal.isSecondary && canvasTarget) {
|
|
2700
2911
|
if (viewport.dpr > 0) canvasTarget.setPixelRatio(viewport.dpr);
|
|
2701
|
-
|
|
2702
|
-
canvasTarget.setSize(size.width, size.height, updateStyle);
|
|
2912
|
+
canvasTarget.setSize(size.width, size.height, false);
|
|
2703
2913
|
} else {
|
|
2704
2914
|
if (viewport.dpr > 0) actualRenderer.setPixelRatio(viewport.dpr);
|
|
2705
|
-
|
|
2706
|
-
|
|
2915
|
+
actualRenderer.setSize(size.width, size.height, false);
|
|
2916
|
+
if (canvasTarget) {
|
|
2917
|
+
if (viewport.dpr > 0) canvasTarget.setPixelRatio(viewport.dpr);
|
|
2918
|
+
canvasTarget.setSize(size.width, size.height, false);
|
|
2919
|
+
}
|
|
2707
2920
|
}
|
|
2708
2921
|
}
|
|
2709
2922
|
if (camera !== oldCamera) {
|
|
@@ -2951,18 +3164,18 @@ function buildFromCache(input, textureCache) {
|
|
|
2951
3164
|
function useTexture(input, optionsOrOnLoad) {
|
|
2952
3165
|
const renderer = useThree((state) => state.internal.actualRenderer);
|
|
2953
3166
|
const store = useStore();
|
|
2954
|
-
const textureCache = useThree((state) => state.textures);
|
|
2955
3167
|
const options = typeof optionsOrOnLoad === "function" ? { onLoad: optionsOrOnLoad } : optionsOrOnLoad ?? {};
|
|
2956
|
-
const { onLoad, cache =
|
|
3168
|
+
const { onLoad, cache = true } = options;
|
|
2957
3169
|
const onLoadRef = useRef(onLoad);
|
|
2958
3170
|
onLoadRef.current = onLoad;
|
|
2959
3171
|
const onLoadCalledForRef = useRef(null);
|
|
2960
3172
|
const urls = useMemo(() => getUrls(input), [input]);
|
|
2961
3173
|
const cachedResult = useMemo(() => {
|
|
2962
3174
|
if (!cache) return null;
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
3175
|
+
const textures = store.getState().textures;
|
|
3176
|
+
if (!allUrlsCached(urls, textures)) return null;
|
|
3177
|
+
return buildFromCache(input, textures);
|
|
3178
|
+
}, [cache, urls, input, store]);
|
|
2966
3179
|
const loadedTextures = useLoader(
|
|
2967
3180
|
TextureLoader,
|
|
2968
3181
|
IsObject(input) ? Object.values(input) : input
|
|
@@ -3006,8 +3219,6 @@ function useTexture(input, optionsOrOnLoad) {
|
|
|
3006
3219
|
}, [input, loadedTextures, cachedResult]);
|
|
3007
3220
|
useEffect(() => {
|
|
3008
3221
|
if (!cache) return;
|
|
3009
|
-
if (cachedResult) return;
|
|
3010
|
-
const set = store.setState;
|
|
3011
3222
|
const urlTextureMap = [];
|
|
3012
3223
|
if (typeof input === "string") {
|
|
3013
3224
|
urlTextureMap.push([input, mappedTextures]);
|
|
@@ -3021,18 +3232,32 @@ function useTexture(input, optionsOrOnLoad) {
|
|
|
3021
3232
|
urlTextureMap.push([url, textureRecord[key]]);
|
|
3022
3233
|
}
|
|
3023
3234
|
}
|
|
3024
|
-
|
|
3025
|
-
const
|
|
3026
|
-
let
|
|
3235
|
+
store.setState((state) => {
|
|
3236
|
+
const refs = new Map(state._textureRefs);
|
|
3237
|
+
let textures = state.textures;
|
|
3238
|
+
let added = false;
|
|
3027
3239
|
for (const [url, texture] of urlTextureMap) {
|
|
3028
|
-
if (!
|
|
3029
|
-
|
|
3030
|
-
|
|
3240
|
+
if (!textures.has(url)) {
|
|
3241
|
+
if (!added) {
|
|
3242
|
+
textures = new Map(textures);
|
|
3243
|
+
added = true;
|
|
3244
|
+
}
|
|
3245
|
+
textures.set(url, texture);
|
|
3031
3246
|
}
|
|
3247
|
+
refs.set(url, (refs.get(url) ?? 0) + 1);
|
|
3032
3248
|
}
|
|
3033
|
-
return
|
|
3249
|
+
return added ? { textures, _textureRefs: refs } : { _textureRefs: refs };
|
|
3250
|
+
});
|
|
3251
|
+
return () => store.setState((state) => {
|
|
3252
|
+
const refs = new Map(state._textureRefs);
|
|
3253
|
+
for (const [url] of urlTextureMap) {
|
|
3254
|
+
const next = (refs.get(url) ?? 0) - 1;
|
|
3255
|
+
if (next <= 0) refs.delete(url);
|
|
3256
|
+
else refs.set(url, next);
|
|
3257
|
+
}
|
|
3258
|
+
return { _textureRefs: refs };
|
|
3034
3259
|
});
|
|
3035
|
-
}, [cache, input, mappedTextures, store
|
|
3260
|
+
}, [cache, input, mappedTextures, store]);
|
|
3036
3261
|
return mappedTextures;
|
|
3037
3262
|
}
|
|
3038
3263
|
useTexture.preload = (url) => useLoader.preload(TextureLoader, url);
|
|
@@ -3048,96 +3273,63 @@ const Texture = ({
|
|
|
3048
3273
|
return /* @__PURE__ */ jsx(Fragment, { children: children?.(ret) });
|
|
3049
3274
|
};
|
|
3050
3275
|
|
|
3051
|
-
function
|
|
3052
|
-
if (entry instanceof Texture$1) return entry;
|
|
3053
|
-
if (entry && typeof entry === "object" && "value" in entry && entry.value instanceof Texture$1) {
|
|
3054
|
-
return entry.value;
|
|
3055
|
-
}
|
|
3056
|
-
return null;
|
|
3057
|
-
}
|
|
3058
|
-
function useTextures() {
|
|
3276
|
+
function useTextures(selector) {
|
|
3059
3277
|
const store = useStore();
|
|
3060
|
-
|
|
3061
|
-
const set = store.setState;
|
|
3278
|
+
const registry = useMemo(() => {
|
|
3062
3279
|
const getState = store.getState;
|
|
3063
|
-
const
|
|
3064
|
-
|
|
3065
|
-
const newMap = new Map(state.textures);
|
|
3066
|
-
newMap.set(key, value);
|
|
3067
|
-
return { textures: newMap };
|
|
3068
|
-
});
|
|
3069
|
-
};
|
|
3070
|
-
const addMultiple = (items) => {
|
|
3071
|
-
set((state) => {
|
|
3072
|
-
const newMap = new Map(state.textures);
|
|
3073
|
-
const entries = items instanceof Map ? items.entries() : Object.entries(items);
|
|
3074
|
-
for (const [key, value] of entries) {
|
|
3075
|
-
newMap.set(key, value);
|
|
3076
|
-
}
|
|
3077
|
-
return { textures: newMap };
|
|
3078
|
-
});
|
|
3079
|
-
};
|
|
3080
|
-
const remove = (key) => {
|
|
3081
|
-
set((state) => {
|
|
3082
|
-
const newMap = new Map(state.textures);
|
|
3083
|
-
newMap.delete(key);
|
|
3084
|
-
return { textures: newMap };
|
|
3085
|
-
});
|
|
3086
|
-
};
|
|
3087
|
-
const removeMultiple = (keys) => {
|
|
3088
|
-
set((state) => {
|
|
3089
|
-
const newMap = new Map(state.textures);
|
|
3090
|
-
for (const key of keys) newMap.delete(key);
|
|
3091
|
-
return { textures: newMap };
|
|
3092
|
-
});
|
|
3093
|
-
};
|
|
3094
|
-
const dispose = (key) => {
|
|
3095
|
-
const entry = getState().textures.get(key);
|
|
3096
|
-
if (entry) {
|
|
3097
|
-
const tex = getTextureValue(entry);
|
|
3098
|
-
tex?.dispose();
|
|
3099
|
-
}
|
|
3100
|
-
remove(key);
|
|
3101
|
-
};
|
|
3102
|
-
const disposeMultiple = (keys) => {
|
|
3103
|
-
const textures = getState().textures;
|
|
3104
|
-
for (const key of keys) {
|
|
3105
|
-
const entry = textures.get(key);
|
|
3106
|
-
if (entry) {
|
|
3107
|
-
const tex = getTextureValue(entry);
|
|
3108
|
-
tex?.dispose();
|
|
3109
|
-
}
|
|
3110
|
-
}
|
|
3111
|
-
removeMultiple(keys);
|
|
3112
|
-
};
|
|
3113
|
-
const disposeAll = () => {
|
|
3114
|
-
const textures = getState().textures;
|
|
3115
|
-
for (const entry of textures.values()) {
|
|
3116
|
-
const tex = getTextureValue(entry);
|
|
3117
|
-
tex?.dispose();
|
|
3118
|
-
}
|
|
3119
|
-
set({ textures: /* @__PURE__ */ new Map() });
|
|
3120
|
-
};
|
|
3280
|
+
const setState = store.setState;
|
|
3281
|
+
const getOne = (key) => getState().textures.get(key);
|
|
3121
3282
|
return {
|
|
3122
|
-
|
|
3123
|
-
get textures() {
|
|
3283
|
+
get all() {
|
|
3124
3284
|
return getState().textures;
|
|
3125
3285
|
},
|
|
3126
|
-
|
|
3127
|
-
|
|
3286
|
+
get(input) {
|
|
3287
|
+
if (typeof input === "string") return getOne(input);
|
|
3288
|
+
if (Array.isArray(input)) return input.map(getOne);
|
|
3289
|
+
const out = {};
|
|
3290
|
+
for (const name in input) out[name] = getOne(input[name]);
|
|
3291
|
+
return out;
|
|
3292
|
+
},
|
|
3128
3293
|
has: (key) => getState().textures.has(key),
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3294
|
+
add(keyOrRecord, texture) {
|
|
3295
|
+
setState((state) => {
|
|
3296
|
+
const textures = new Map(state.textures);
|
|
3297
|
+
if (typeof keyOrRecord === "string") {
|
|
3298
|
+
textures.set(keyOrRecord, texture);
|
|
3299
|
+
} else {
|
|
3300
|
+
for (const key in keyOrRecord) textures.set(key, keyOrRecord[key]);
|
|
3301
|
+
}
|
|
3302
|
+
return { textures };
|
|
3303
|
+
});
|
|
3304
|
+
},
|
|
3305
|
+
dispose(key, options) {
|
|
3306
|
+
const state = getState();
|
|
3307
|
+
const refs = state._textureRefs.get(key) ?? 0;
|
|
3308
|
+
if (refs > 0 && !options?.force) {
|
|
3309
|
+
console.warn(
|
|
3310
|
+
`[useTextures] "${key}" still has ${refs} active reference(s); skipping dispose. Pass { force: true } to override.`
|
|
3311
|
+
);
|
|
3312
|
+
return false;
|
|
3313
|
+
}
|
|
3314
|
+
state.textures.get(key)?.dispose();
|
|
3315
|
+
setState((s) => {
|
|
3316
|
+
const textures = new Map(s.textures);
|
|
3317
|
+
textures.delete(key);
|
|
3318
|
+
const nextRefs = new Map(s._textureRefs);
|
|
3319
|
+
nextRefs.delete(key);
|
|
3320
|
+
return { textures, _textureRefs: nextRefs };
|
|
3321
|
+
});
|
|
3322
|
+
return true;
|
|
3323
|
+
},
|
|
3324
|
+
disposeAll() {
|
|
3325
|
+
for (const texture of getState().textures.values()) texture.dispose();
|
|
3326
|
+
setState({ textures: /* @__PURE__ */ new Map(), _textureRefs: /* @__PURE__ */ new Map() });
|
|
3327
|
+
}
|
|
3139
3328
|
};
|
|
3140
3329
|
}, [store]);
|
|
3330
|
+
const subscribe = selector ? () => selector(registry) : (state) => state.textures;
|
|
3331
|
+
const selected = useThree(subscribe);
|
|
3332
|
+
return selector ? selected : registry;
|
|
3141
3333
|
}
|
|
3142
3334
|
|
|
3143
3335
|
function useRenderTarget(widthOrOptions, heightOrOptions, options) {
|
|
@@ -14990,7 +15182,6 @@ function createRoot(canvas) {
|
|
|
14990
15182
|
events,
|
|
14991
15183
|
onCreated: onCreatedCallback,
|
|
14992
15184
|
shadows = false,
|
|
14993
|
-
textureColorSpace = SRGBColorSpace,
|
|
14994
15185
|
orthographic = false,
|
|
14995
15186
|
frameloop = "always",
|
|
14996
15187
|
dpr = [1, 2],
|
|
@@ -15005,6 +15196,7 @@ function createRoot(canvas) {
|
|
|
15005
15196
|
_sizeProps,
|
|
15006
15197
|
forceEven
|
|
15007
15198
|
} = props;
|
|
15199
|
+
const textureColorSpace = is.obj(glConfig) && !is.fun(glConfig) && !isRenderer(glConfig) && glConfig.textureColorSpace || is.obj(rendererConfig) && !is.fun(rendererConfig) && !isRenderer(rendererConfig) && rendererConfig.textureColorSpace || SRGBColorSpace;
|
|
15008
15200
|
const state = store.getState();
|
|
15009
15201
|
const defaultGLProps = {
|
|
15010
15202
|
canvas,
|
|
@@ -15060,6 +15252,12 @@ function createRoot(canvas) {
|
|
|
15060
15252
|
} else if (!wantsGL && !state.internal.actualRenderer) {
|
|
15061
15253
|
renderer = await resolveRenderer(rendererConfig, defaultGPUProps, WebGPURenderer);
|
|
15062
15254
|
if (!renderer.hasInitialized?.()) {
|
|
15255
|
+
const size2 = computeInitialSize(canvas, propsSize);
|
|
15256
|
+
if (size2.width > 0 && size2.height > 0) {
|
|
15257
|
+
const pixelRatio = calculateDpr(dpr);
|
|
15258
|
+
canvas.width = size2.width * pixelRatio;
|
|
15259
|
+
canvas.height = size2.height * pixelRatio;
|
|
15260
|
+
}
|
|
15063
15261
|
await renderer.init();
|
|
15064
15262
|
}
|
|
15065
15263
|
const backend = renderer.backend;
|
|
@@ -15169,7 +15367,7 @@ function createRoot(canvas) {
|
|
|
15169
15367
|
lastConfiguredProps.performance = performance;
|
|
15170
15368
|
}
|
|
15171
15369
|
if (!state.xr) {
|
|
15172
|
-
const handleXRFrame = (timestamp,
|
|
15370
|
+
const handleXRFrame = (timestamp, _frame) => {
|
|
15173
15371
|
const state2 = store.getState();
|
|
15174
15372
|
if (state2.frameloop === "never") return;
|
|
15175
15373
|
advance(timestamp);
|
|
@@ -15205,15 +15403,22 @@ function createRoot(canvas) {
|
|
|
15205
15403
|
const oldType = renderer.shadowMap.type;
|
|
15206
15404
|
renderer.shadowMap.enabled = !!shadows;
|
|
15207
15405
|
if (is.boo(shadows)) {
|
|
15208
|
-
renderer.shadowMap.type =
|
|
15406
|
+
renderer.shadowMap.type = PCFShadowMap;
|
|
15209
15407
|
} else if (is.str(shadows)) {
|
|
15408
|
+
if (shadows === "soft") {
|
|
15409
|
+
notifyDepreciated({
|
|
15410
|
+
heading: 'shadows="soft" is deprecated',
|
|
15411
|
+
body: "Three has depreciated soft and improved basic PCFShadows, we converted for you.",
|
|
15412
|
+
link: "https://github.com/mrdoob/three.js/wiki/Migration-Guide?utm_source=chatgpt.com#181--182"
|
|
15413
|
+
});
|
|
15414
|
+
}
|
|
15210
15415
|
const types = {
|
|
15211
15416
|
basic: BasicShadowMap,
|
|
15212
15417
|
percentage: PCFShadowMap,
|
|
15213
|
-
soft:
|
|
15418
|
+
soft: PCFShadowMap,
|
|
15214
15419
|
variance: VSMShadowMap
|
|
15215
15420
|
};
|
|
15216
|
-
renderer.shadowMap.type = types[shadows] ??
|
|
15421
|
+
renderer.shadowMap.type = types[shadows] ?? PCFShadowMap;
|
|
15217
15422
|
} else if (is.obj(shadows)) {
|
|
15218
15423
|
Object.assign(renderer.shadowMap, shadows);
|
|
15219
15424
|
}
|
|
@@ -15229,13 +15434,24 @@ function createRoot(canvas) {
|
|
|
15229
15434
|
if (state.textureColorSpace !== textureColorSpace) state.set(() => ({ textureColorSpace }));
|
|
15230
15435
|
lastConfiguredProps.textureColorSpace = textureColorSpace;
|
|
15231
15436
|
}
|
|
15437
|
+
const r3fProps = ["textureColorSpace"];
|
|
15438
|
+
const constructorOnlyProps = ["samples", "antialias", "alpha", "canvas", "powerPreference"];
|
|
15439
|
+
const nonApplyProps = [...r3fProps, ...constructorOnlyProps];
|
|
15232
15440
|
if (glConfig && !is.fun(glConfig) && !isRenderer(glConfig) && !is.equ(glConfig, renderer, shallowLoose)) {
|
|
15233
|
-
|
|
15441
|
+
const glProps = {};
|
|
15442
|
+
for (const key in glConfig) {
|
|
15443
|
+
if (!nonApplyProps.includes(key)) glProps[key] = glConfig[key];
|
|
15444
|
+
}
|
|
15445
|
+
applyProps(renderer, glProps);
|
|
15234
15446
|
}
|
|
15235
15447
|
if (rendererConfig && !is.fun(rendererConfig) && !isRenderer(rendererConfig) && state.renderer) {
|
|
15236
15448
|
const currentRenderer = state.renderer;
|
|
15237
15449
|
if (!is.equ(rendererConfig, currentRenderer, shallowLoose)) {
|
|
15238
|
-
|
|
15450
|
+
const rendererProps = {};
|
|
15451
|
+
for (const key in rendererConfig) {
|
|
15452
|
+
if (!nonApplyProps.includes(key)) rendererProps[key] = rendererConfig[key];
|
|
15453
|
+
}
|
|
15454
|
+
applyProps(currentRenderer, rendererProps);
|
|
15239
15455
|
}
|
|
15240
15456
|
}
|
|
15241
15457
|
const scheduler = getScheduler();
|
|
@@ -15261,6 +15477,18 @@ function createRoot(canvas) {
|
|
|
15261
15477
|
system: true
|
|
15262
15478
|
}
|
|
15263
15479
|
);
|
|
15480
|
+
const unregisterEventsFlush = scheduler.register(
|
|
15481
|
+
() => {
|
|
15482
|
+
const state2 = store.getState();
|
|
15483
|
+
state2.events.flush?.();
|
|
15484
|
+
},
|
|
15485
|
+
{
|
|
15486
|
+
id: `${newRootId}_events`,
|
|
15487
|
+
rootId: newRootId,
|
|
15488
|
+
phase: "input",
|
|
15489
|
+
system: true
|
|
15490
|
+
}
|
|
15491
|
+
);
|
|
15264
15492
|
const unregisterFrustum = scheduler.register(
|
|
15265
15493
|
() => {
|
|
15266
15494
|
const state2 = store.getState();
|
|
@@ -15295,7 +15523,7 @@ function createRoot(canvas) {
|
|
|
15295
15523
|
const userHandlesRender = scheduler.hasUserJobsInPhase("render", newRootId);
|
|
15296
15524
|
if (userHandlesRender || state2.internal.priority) return;
|
|
15297
15525
|
try {
|
|
15298
|
-
if (state2.
|
|
15526
|
+
if (state2.renderPipeline?.render) state2.renderPipeline.render();
|
|
15299
15527
|
else if (renderer2?.render) renderer2.render(state2.scene, state2.camera);
|
|
15300
15528
|
} catch (error) {
|
|
15301
15529
|
state2.setError(error instanceof Error ? error : new Error(String(error)));
|
|
@@ -15320,6 +15548,7 @@ function createRoot(canvas) {
|
|
|
15320
15548
|
unregisterRoot: () => {
|
|
15321
15549
|
unregisterRoot();
|
|
15322
15550
|
unregisterCanvasTarget();
|
|
15551
|
+
unregisterEventsFlush();
|
|
15323
15552
|
unregisterFrustum();
|
|
15324
15553
|
unregisterVisibility();
|
|
15325
15554
|
unregisterRender();
|
|
@@ -15485,9 +15714,13 @@ function PortalInner({ state = {}, children, container }) {
|
|
|
15485
15714
|
const store = createWithEqualityFn((set, get) => ({ ...rest, set, get }));
|
|
15486
15715
|
const onMutate = (prev) => store.setState((state2) => inject.current(prev, state2));
|
|
15487
15716
|
onMutate(previousRoot.getState());
|
|
15488
|
-
previousRoot.subscribe(onMutate);
|
|
15489
15717
|
return store;
|
|
15490
15718
|
}, [previousRoot, container]);
|
|
15719
|
+
useIsomorphicLayoutEffect(() => {
|
|
15720
|
+
const onMutate = (prev) => usePortalStore.setState((state2) => inject.current(prev, state2));
|
|
15721
|
+
const unsubscribe = previousRoot.subscribe(onMutate);
|
|
15722
|
+
return unsubscribe;
|
|
15723
|
+
}, [previousRoot, usePortalStore]);
|
|
15491
15724
|
return (
|
|
15492
15725
|
// @ts-ignore, reconciler types are not maintained
|
|
15493
15726
|
/* @__PURE__ */ jsx(Fragment, { children: reconciler.createPortal(
|
|
@@ -15532,8 +15765,18 @@ function CanvasImpl({
|
|
|
15532
15765
|
forceEven,
|
|
15533
15766
|
...props
|
|
15534
15767
|
}) {
|
|
15535
|
-
const
|
|
15536
|
-
|
|
15768
|
+
const isRendererConfig = typeof rendererProp === "object" && rendererProp !== null && !("render" in rendererProp) && ("primaryCanvas" in rendererProp || "scheduler" in rendererProp);
|
|
15769
|
+
let primaryCanvas;
|
|
15770
|
+
let scheduler;
|
|
15771
|
+
let renderer;
|
|
15772
|
+
if (isRendererConfig) {
|
|
15773
|
+
const { primaryCanvas: pc, scheduler: sc, ...rest } = rendererProp;
|
|
15774
|
+
primaryCanvas = pc;
|
|
15775
|
+
scheduler = sc;
|
|
15776
|
+
renderer = Object.keys(rest).length > 0 ? rest : rendererProp;
|
|
15777
|
+
} else {
|
|
15778
|
+
renderer = rendererProp;
|
|
15779
|
+
}
|
|
15537
15780
|
React.useMemo(() => extend(THREE), []);
|
|
15538
15781
|
const Bridge = useBridge();
|
|
15539
15782
|
const backgroundProps = React.useMemo(() => {
|
|
@@ -15708,6 +15951,7 @@ function CanvasImpl({
|
|
|
15708
15951
|
queueMicrotask(() => {
|
|
15709
15952
|
const rootEntry = _roots.get(canvas);
|
|
15710
15953
|
if (rootEntry?.store) {
|
|
15954
|
+
console.log("[R3F] HMR detected \u2014 rebuilding nodes/uniforms");
|
|
15711
15955
|
rootEntry.store.setState((state) => ({
|
|
15712
15956
|
nodes: {},
|
|
15713
15957
|
uniforms: {},
|
|
@@ -15719,8 +15963,7 @@ function CanvasImpl({
|
|
|
15719
15963
|
if (typeof import.meta !== "undefined" && import.meta.hot) {
|
|
15720
15964
|
const hot = import.meta.hot;
|
|
15721
15965
|
hot.on("vite:afterUpdate", handleHMR);
|
|
15722
|
-
return () => hot.
|
|
15723
|
-
});
|
|
15966
|
+
return () => hot.off?.("vite:afterUpdate", handleHMR);
|
|
15724
15967
|
}
|
|
15725
15968
|
if (typeof module !== "undefined" && module.hot) {
|
|
15726
15969
|
const hot = module.hot;
|
|
@@ -15743,7 +15986,16 @@ function CanvasImpl({
|
|
|
15743
15986
|
...style
|
|
15744
15987
|
},
|
|
15745
15988
|
...props,
|
|
15746
|
-
children: /* @__PURE__ */ jsx("div", { ref: containerRef, className: "r3f-canvas-container", style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ jsx(
|
|
15989
|
+
children: /* @__PURE__ */ jsx("div", { ref: containerRef, className: "r3f-canvas-container", style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ jsx(
|
|
15990
|
+
"canvas",
|
|
15991
|
+
{
|
|
15992
|
+
ref: canvasRef,
|
|
15993
|
+
id,
|
|
15994
|
+
className: "r3f-canvas",
|
|
15995
|
+
style: { display: "block", width: "100%", height: "100%" },
|
|
15996
|
+
children: fallback
|
|
15997
|
+
}
|
|
15998
|
+
) })
|
|
15747
15999
|
}
|
|
15748
16000
|
);
|
|
15749
16001
|
}
|