@react-three/fiber 10.0.0-alpha.2 → 10.0.0-canary.1b98c17
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/LICENSE +21 -21
- package/dist/index.cjs +1454 -618
- package/dist/index.d.cts +2130 -1285
- package/dist/index.d.mts +2130 -1285
- package/dist/index.d.ts +2130 -1285
- package/dist/index.mjs +1439 -622
- package/dist/legacy.cjs +1420 -608
- package/dist/legacy.d.cts +2131 -1286
- package/dist/legacy.d.mts +2131 -1286
- package/dist/legacy.d.ts +2131 -1286
- package/dist/legacy.mjs +1405 -612
- package/dist/webgpu/index.cjs +1841 -577
- package/dist/webgpu/index.d.cts +2310 -1312
- package/dist/webgpu/index.d.mts +2310 -1312
- package/dist/webgpu/index.d.ts +2310 -1312
- package/dist/webgpu/index.mjs +1821 -580
- package/package.json +3 -1
- package/readme.md +244 -318
package/dist/webgpu/index.cjs
CHANGED
|
@@ -6,6 +6,12 @@ const jsxRuntime = require('react/jsx-runtime');
|
|
|
6
6
|
const React = require('react');
|
|
7
7
|
const useMeasure = require('react-use-measure');
|
|
8
8
|
const itsFine = require('its-fine');
|
|
9
|
+
const fiber = require('@react-three/fiber');
|
|
10
|
+
const GroundedSkybox_js = require('three/examples/jsm/objects/GroundedSkybox.js');
|
|
11
|
+
const HDRLoader_js = require('three/examples/jsm/loaders/HDRLoader.js');
|
|
12
|
+
const EXRLoader_js = require('three/examples/jsm/loaders/EXRLoader.js');
|
|
13
|
+
const UltraHDRLoader_js = require('three/examples/jsm/loaders/UltraHDRLoader.js');
|
|
14
|
+
const gainmapJs = require('@monogrid/gainmap-js');
|
|
9
15
|
const Tb = require('scheduler');
|
|
10
16
|
const traditional = require('zustand/traditional');
|
|
11
17
|
const suspendReact = require('suspend-react');
|
|
@@ -67,6 +73,389 @@ const THREE = /*#__PURE__*/_mergeNamespaces({
|
|
|
67
73
|
WebGLRenderer: WebGLRenderer
|
|
68
74
|
}, [webgpu__namespace]);
|
|
69
75
|
|
|
76
|
+
const primaryRegistry = /* @__PURE__ */ new Map();
|
|
77
|
+
const pendingSubscribers = /* @__PURE__ */ new Map();
|
|
78
|
+
function registerPrimary(id, renderer, store) {
|
|
79
|
+
if (primaryRegistry.has(id)) {
|
|
80
|
+
console.warn(`Canvas with id="${id}" already registered. Overwriting.`);
|
|
81
|
+
}
|
|
82
|
+
const entry = { renderer, store };
|
|
83
|
+
primaryRegistry.set(id, entry);
|
|
84
|
+
const subscribers = pendingSubscribers.get(id);
|
|
85
|
+
if (subscribers) {
|
|
86
|
+
subscribers.forEach((callback) => callback(entry));
|
|
87
|
+
pendingSubscribers.delete(id);
|
|
88
|
+
}
|
|
89
|
+
return () => {
|
|
90
|
+
const currentEntry = primaryRegistry.get(id);
|
|
91
|
+
if (currentEntry?.renderer === renderer) {
|
|
92
|
+
primaryRegistry.delete(id);
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function getPrimary(id) {
|
|
97
|
+
return primaryRegistry.get(id);
|
|
98
|
+
}
|
|
99
|
+
function waitForPrimary(id, timeout = 5e3) {
|
|
100
|
+
const existing = primaryRegistry.get(id);
|
|
101
|
+
if (existing) {
|
|
102
|
+
return Promise.resolve(existing);
|
|
103
|
+
}
|
|
104
|
+
return new Promise((resolve, reject) => {
|
|
105
|
+
const timeoutId = setTimeout(() => {
|
|
106
|
+
const subscribers = pendingSubscribers.get(id);
|
|
107
|
+
if (subscribers) {
|
|
108
|
+
const index = subscribers.indexOf(callback);
|
|
109
|
+
if (index !== -1) subscribers.splice(index, 1);
|
|
110
|
+
if (subscribers.length === 0) pendingSubscribers.delete(id);
|
|
111
|
+
}
|
|
112
|
+
reject(new Error(`Timeout waiting for canvas with id="${id}". Make sure a <Canvas id="${id}"> is mounted.`));
|
|
113
|
+
}, timeout);
|
|
114
|
+
const callback = (entry) => {
|
|
115
|
+
clearTimeout(timeoutId);
|
|
116
|
+
resolve(entry);
|
|
117
|
+
};
|
|
118
|
+
if (!pendingSubscribers.has(id)) {
|
|
119
|
+
pendingSubscribers.set(id, []);
|
|
120
|
+
}
|
|
121
|
+
pendingSubscribers.get(id).push(callback);
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
function hasPrimary(id) {
|
|
125
|
+
return primaryRegistry.has(id);
|
|
126
|
+
}
|
|
127
|
+
function unregisterPrimary(id) {
|
|
128
|
+
primaryRegistry.delete(id);
|
|
129
|
+
}
|
|
130
|
+
function getPrimaryIds() {
|
|
131
|
+
return Array.from(primaryRegistry.keys());
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const presetsObj = {
|
|
135
|
+
apartment: "lebombo_1k.hdr",
|
|
136
|
+
city: "potsdamer_platz_1k.hdr",
|
|
137
|
+
dawn: "kiara_1_dawn_1k.hdr",
|
|
138
|
+
forest: "forest_slope_1k.hdr",
|
|
139
|
+
lobby: "st_fagans_interior_1k.hdr",
|
|
140
|
+
night: "dikhololo_night_1k.hdr",
|
|
141
|
+
park: "rooitou_park_1k.hdr",
|
|
142
|
+
studio: "studio_small_03_1k.hdr",
|
|
143
|
+
sunset: "venice_sunset_1k.hdr",
|
|
144
|
+
warehouse: "empty_warehouse_01_1k.hdr"
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const CUBEMAP_ROOT = "https://raw.githack.com/pmndrs/drei-assets/456060a26bbeb8fdf79326f224b6d99b8bcce736/hdri/";
|
|
148
|
+
const isArray = (arr) => Array.isArray(arr);
|
|
149
|
+
const defaultFiles = ["/px.png", "/nx.png", "/py.png", "/ny.png", "/pz.png", "/nz.png"];
|
|
150
|
+
function useEnvironment({
|
|
151
|
+
files = defaultFiles,
|
|
152
|
+
path = "",
|
|
153
|
+
preset = void 0,
|
|
154
|
+
colorSpace = void 0,
|
|
155
|
+
extensions
|
|
156
|
+
} = {}) {
|
|
157
|
+
if (preset) {
|
|
158
|
+
validatePreset(preset);
|
|
159
|
+
files = presetsObj[preset];
|
|
160
|
+
path = CUBEMAP_ROOT;
|
|
161
|
+
}
|
|
162
|
+
const multiFile = isArray(files);
|
|
163
|
+
const { extension, isCubemap } = getExtension(files);
|
|
164
|
+
const loader = getLoader$1(extension);
|
|
165
|
+
if (!loader) throw new Error("useEnvironment: Unrecognized file extension: " + files);
|
|
166
|
+
const renderer = fiber.useThree((state) => state.renderer);
|
|
167
|
+
React.useLayoutEffect(() => {
|
|
168
|
+
if (extension !== "webp" && extension !== "jpg" && extension !== "jpeg") return;
|
|
169
|
+
function clearGainmapTexture() {
|
|
170
|
+
fiber.useLoader.clear(loader, multiFile ? [files] : files);
|
|
171
|
+
}
|
|
172
|
+
renderer.domElement.addEventListener("webglcontextlost", clearGainmapTexture, { once: true });
|
|
173
|
+
}, [extension, files, loader, multiFile, renderer.domElement]);
|
|
174
|
+
const loaderResult = fiber.useLoader(
|
|
175
|
+
loader,
|
|
176
|
+
multiFile ? [files] : files,
|
|
177
|
+
(loader2) => {
|
|
178
|
+
if (extension === "webp" || extension === "jpg" || extension === "jpeg") {
|
|
179
|
+
loader2.setRenderer?.(renderer);
|
|
180
|
+
}
|
|
181
|
+
loader2.setPath?.(path);
|
|
182
|
+
if (extensions) extensions(loader2);
|
|
183
|
+
}
|
|
184
|
+
);
|
|
185
|
+
let texture = multiFile ? (
|
|
186
|
+
// @ts-ignore
|
|
187
|
+
loaderResult[0]
|
|
188
|
+
) : loaderResult;
|
|
189
|
+
if (extension === "jpg" || extension === "jpeg" || extension === "webp") {
|
|
190
|
+
texture = texture.renderTarget?.texture;
|
|
191
|
+
}
|
|
192
|
+
texture.mapping = isCubemap ? webgpu.CubeReflectionMapping : webgpu.EquirectangularReflectionMapping;
|
|
193
|
+
texture.colorSpace = colorSpace ?? (isCubemap ? "srgb" : "srgb-linear");
|
|
194
|
+
return texture;
|
|
195
|
+
}
|
|
196
|
+
const preloadDefaultOptions = {
|
|
197
|
+
files: defaultFiles,
|
|
198
|
+
path: "",
|
|
199
|
+
preset: void 0,
|
|
200
|
+
extensions: void 0
|
|
201
|
+
};
|
|
202
|
+
useEnvironment.preload = (preloadOptions) => {
|
|
203
|
+
const options = { ...preloadDefaultOptions, ...preloadOptions };
|
|
204
|
+
let { files, path = "" } = options;
|
|
205
|
+
const { preset, extensions } = options;
|
|
206
|
+
if (preset) {
|
|
207
|
+
validatePreset(preset);
|
|
208
|
+
files = presetsObj[preset];
|
|
209
|
+
path = CUBEMAP_ROOT;
|
|
210
|
+
}
|
|
211
|
+
const { extension } = getExtension(files);
|
|
212
|
+
if (extension === "webp" || extension === "jpg" || extension === "jpeg") {
|
|
213
|
+
throw new Error("useEnvironment: Preloading gainmaps is not supported");
|
|
214
|
+
}
|
|
215
|
+
const loader = getLoader$1(extension);
|
|
216
|
+
if (!loader) throw new Error("useEnvironment: Unrecognized file extension: " + files);
|
|
217
|
+
fiber.useLoader.preload(loader, isArray(files) ? [files] : files, (loader2) => {
|
|
218
|
+
loader2.setPath?.(path);
|
|
219
|
+
if (extensions) extensions(loader2);
|
|
220
|
+
});
|
|
221
|
+
};
|
|
222
|
+
const clearDefaultOptins = {
|
|
223
|
+
files: defaultFiles,
|
|
224
|
+
preset: void 0
|
|
225
|
+
};
|
|
226
|
+
useEnvironment.clear = (clearOptions) => {
|
|
227
|
+
const options = { ...clearDefaultOptins, ...clearOptions };
|
|
228
|
+
let { files } = options;
|
|
229
|
+
const { preset } = options;
|
|
230
|
+
if (preset) {
|
|
231
|
+
validatePreset(preset);
|
|
232
|
+
files = presetsObj[preset];
|
|
233
|
+
}
|
|
234
|
+
const { extension } = getExtension(files);
|
|
235
|
+
const loader = getLoader$1(extension);
|
|
236
|
+
if (!loader) throw new Error("useEnvironment: Unrecognized file extension: " + files);
|
|
237
|
+
fiber.useLoader.clear(loader, isArray(files) ? [files] : files);
|
|
238
|
+
};
|
|
239
|
+
function validatePreset(preset) {
|
|
240
|
+
if (!(preset in presetsObj)) throw new Error("Preset must be one of: " + Object.keys(presetsObj).join(", "));
|
|
241
|
+
}
|
|
242
|
+
function getExtension(files) {
|
|
243
|
+
const isCubemap = isArray(files) && files.length === 6;
|
|
244
|
+
const isGainmap = isArray(files) && files.length === 3 && files.some((file) => file.endsWith("json"));
|
|
245
|
+
const firstEntry = isArray(files) ? files[0] : files;
|
|
246
|
+
const extension = isCubemap ? "cube" : isGainmap ? "webp" : firstEntry.startsWith("data:application/exr") ? "exr" : firstEntry.startsWith("data:application/hdr") ? "hdr" : firstEntry.startsWith("data:image/jpeg") ? "jpg" : firstEntry.split(".").pop()?.split("?")?.shift()?.toLowerCase();
|
|
247
|
+
return { extension, isCubemap, isGainmap };
|
|
248
|
+
}
|
|
249
|
+
function getLoader$1(extension) {
|
|
250
|
+
const loader = extension === "cube" ? webgpu.CubeTextureLoader : extension === "hdr" ? HDRLoader_js.HDRLoader : extension === "exr" ? EXRLoader_js.EXRLoader : extension === "jpg" || extension === "jpeg" ? UltraHDRLoader_js.UltraHDRLoader : extension === "webp" ? gainmapJs.GainMapLoader : null;
|
|
251
|
+
return loader;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
const isRef$1 = (obj) => obj.current && obj.current.isScene;
|
|
255
|
+
const resolveScene = (scene) => isRef$1(scene) ? scene.current : scene;
|
|
256
|
+
function setEnvProps(background, scene, defaultScene, texture, sceneProps = {}) {
|
|
257
|
+
sceneProps = {
|
|
258
|
+
backgroundBlurriness: 0,
|
|
259
|
+
backgroundIntensity: 1,
|
|
260
|
+
backgroundRotation: [0, 0, 0],
|
|
261
|
+
environmentIntensity: 1,
|
|
262
|
+
environmentRotation: [0, 0, 0],
|
|
263
|
+
...sceneProps
|
|
264
|
+
};
|
|
265
|
+
const target = resolveScene(scene || defaultScene);
|
|
266
|
+
const oldbg = target.background;
|
|
267
|
+
const oldenv = target.environment;
|
|
268
|
+
const oldSceneProps = {
|
|
269
|
+
// @ts-ignore
|
|
270
|
+
backgroundBlurriness: target.backgroundBlurriness,
|
|
271
|
+
// @ts-ignore
|
|
272
|
+
backgroundIntensity: target.backgroundIntensity,
|
|
273
|
+
// @ts-ignore
|
|
274
|
+
backgroundRotation: target.backgroundRotation?.clone?.() ?? [0, 0, 0],
|
|
275
|
+
// @ts-ignore
|
|
276
|
+
environmentIntensity: target.environmentIntensity,
|
|
277
|
+
// @ts-ignore
|
|
278
|
+
environmentRotation: target.environmentRotation?.clone?.() ?? [0, 0, 0]
|
|
279
|
+
};
|
|
280
|
+
if (background !== "only") target.environment = texture;
|
|
281
|
+
if (background) target.background = texture;
|
|
282
|
+
fiber.applyProps(target, sceneProps);
|
|
283
|
+
return () => {
|
|
284
|
+
if (background !== "only") target.environment = oldenv;
|
|
285
|
+
if (background) target.background = oldbg;
|
|
286
|
+
fiber.applyProps(target, oldSceneProps);
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
function EnvironmentMap({ scene, background = false, map, ...config }) {
|
|
290
|
+
const defaultScene = fiber.useThree((state) => state.scene);
|
|
291
|
+
React__namespace.useLayoutEffect(() => {
|
|
292
|
+
if (map) return setEnvProps(background, scene, defaultScene, map, config);
|
|
293
|
+
});
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
function EnvironmentCube({
|
|
297
|
+
background = false,
|
|
298
|
+
scene,
|
|
299
|
+
blur,
|
|
300
|
+
backgroundBlurriness,
|
|
301
|
+
backgroundIntensity,
|
|
302
|
+
backgroundRotation,
|
|
303
|
+
environmentIntensity,
|
|
304
|
+
environmentRotation,
|
|
305
|
+
...rest
|
|
306
|
+
}) {
|
|
307
|
+
const texture = useEnvironment(rest);
|
|
308
|
+
const defaultScene = fiber.useThree((state) => state.scene);
|
|
309
|
+
React__namespace.useLayoutEffect(() => {
|
|
310
|
+
return setEnvProps(background, scene, defaultScene, texture, {
|
|
311
|
+
backgroundBlurriness: blur ?? backgroundBlurriness,
|
|
312
|
+
backgroundIntensity,
|
|
313
|
+
backgroundRotation,
|
|
314
|
+
environmentIntensity,
|
|
315
|
+
environmentRotation
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
React__namespace.useEffect(() => {
|
|
319
|
+
return () => {
|
|
320
|
+
texture.dispose();
|
|
321
|
+
};
|
|
322
|
+
}, [texture]);
|
|
323
|
+
return null;
|
|
324
|
+
}
|
|
325
|
+
function EnvironmentPortal({
|
|
326
|
+
children,
|
|
327
|
+
near = 0.1,
|
|
328
|
+
far = 1e3,
|
|
329
|
+
resolution = 256,
|
|
330
|
+
frames = 1,
|
|
331
|
+
map,
|
|
332
|
+
background = false,
|
|
333
|
+
blur,
|
|
334
|
+
backgroundBlurriness,
|
|
335
|
+
backgroundIntensity,
|
|
336
|
+
backgroundRotation,
|
|
337
|
+
environmentIntensity,
|
|
338
|
+
environmentRotation,
|
|
339
|
+
scene,
|
|
340
|
+
files,
|
|
341
|
+
path,
|
|
342
|
+
preset = void 0,
|
|
343
|
+
extensions
|
|
344
|
+
}) {
|
|
345
|
+
const gl = fiber.useThree((state) => state.gl);
|
|
346
|
+
const defaultScene = fiber.useThree((state) => state.scene);
|
|
347
|
+
const camera = React__namespace.useRef(null);
|
|
348
|
+
const [virtualScene] = React__namespace.useState(() => new webgpu.Scene());
|
|
349
|
+
const fbo = React__namespace.useMemo(() => {
|
|
350
|
+
const fbo2 = new webgpu.WebGLCubeRenderTarget(resolution);
|
|
351
|
+
fbo2.texture.type = webgpu.HalfFloatType;
|
|
352
|
+
return fbo2;
|
|
353
|
+
}, [resolution]);
|
|
354
|
+
React__namespace.useEffect(() => {
|
|
355
|
+
return () => {
|
|
356
|
+
fbo.dispose();
|
|
357
|
+
};
|
|
358
|
+
}, [fbo]);
|
|
359
|
+
React__namespace.useLayoutEffect(() => {
|
|
360
|
+
if (frames === 1) {
|
|
361
|
+
const autoClear = gl.autoClear;
|
|
362
|
+
gl.autoClear = true;
|
|
363
|
+
camera.current.update(gl, virtualScene);
|
|
364
|
+
gl.autoClear = autoClear;
|
|
365
|
+
}
|
|
366
|
+
return setEnvProps(background, scene, defaultScene, fbo.texture, {
|
|
367
|
+
backgroundBlurriness: blur ?? backgroundBlurriness,
|
|
368
|
+
backgroundIntensity,
|
|
369
|
+
backgroundRotation,
|
|
370
|
+
environmentIntensity,
|
|
371
|
+
environmentRotation
|
|
372
|
+
});
|
|
373
|
+
}, [
|
|
374
|
+
children,
|
|
375
|
+
virtualScene,
|
|
376
|
+
fbo.texture,
|
|
377
|
+
scene,
|
|
378
|
+
defaultScene,
|
|
379
|
+
background,
|
|
380
|
+
frames,
|
|
381
|
+
gl,
|
|
382
|
+
blur,
|
|
383
|
+
backgroundBlurriness,
|
|
384
|
+
backgroundIntensity,
|
|
385
|
+
backgroundRotation,
|
|
386
|
+
environmentIntensity,
|
|
387
|
+
environmentRotation
|
|
388
|
+
]);
|
|
389
|
+
let count = 1;
|
|
390
|
+
fiber.useFrame(() => {
|
|
391
|
+
if (frames === Infinity || count < frames) {
|
|
392
|
+
const autoClear = gl.autoClear;
|
|
393
|
+
gl.autoClear = true;
|
|
394
|
+
camera.current.update(gl, virtualScene);
|
|
395
|
+
gl.autoClear = autoClear;
|
|
396
|
+
count++;
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: fiber.createPortal(
|
|
400
|
+
/* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
401
|
+
children,
|
|
402
|
+
/* @__PURE__ */ jsxRuntime.jsx("cubeCamera", { ref: camera, args: [near, far, fbo] }),
|
|
403
|
+
files || preset ? /* @__PURE__ */ jsxRuntime.jsx(EnvironmentCube, { background: true, files, preset, path, extensions }) : map ? /* @__PURE__ */ jsxRuntime.jsx(EnvironmentMap, { background: true, map, extensions }) : null
|
|
404
|
+
] }),
|
|
405
|
+
virtualScene
|
|
406
|
+
) });
|
|
407
|
+
}
|
|
408
|
+
function EnvironmentGround(props) {
|
|
409
|
+
const textureDefault = useEnvironment(props);
|
|
410
|
+
const texture = props.map || textureDefault;
|
|
411
|
+
React__namespace.useMemo(() => fiber.extend({ GroundProjectedEnvImpl: GroundedSkybox_js.GroundedSkybox }), []);
|
|
412
|
+
React__namespace.useEffect(() => {
|
|
413
|
+
return () => {
|
|
414
|
+
textureDefault.dispose();
|
|
415
|
+
};
|
|
416
|
+
}, [textureDefault]);
|
|
417
|
+
const height = props.ground?.height ?? 15;
|
|
418
|
+
const radius = props.ground?.radius ?? 60;
|
|
419
|
+
const scale = props.ground?.scale ?? 1e3;
|
|
420
|
+
const args = React__namespace.useMemo(
|
|
421
|
+
() => [texture, height, radius],
|
|
422
|
+
[texture, height, radius]
|
|
423
|
+
);
|
|
424
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
425
|
+
/* @__PURE__ */ jsxRuntime.jsx(EnvironmentMap, { ...props, map: texture }),
|
|
426
|
+
/* @__PURE__ */ jsxRuntime.jsx("groundProjectedEnvImpl", { args, scale })
|
|
427
|
+
] });
|
|
428
|
+
}
|
|
429
|
+
function EnvironmentColor({ color, scene }) {
|
|
430
|
+
const defaultScene = fiber.useThree((state) => state.scene);
|
|
431
|
+
React__namespace.useLayoutEffect(() => {
|
|
432
|
+
if (color === void 0) return;
|
|
433
|
+
const target = resolveScene(scene || defaultScene);
|
|
434
|
+
const oldBg = target.background;
|
|
435
|
+
target.background = new webgpu.Color(color);
|
|
436
|
+
return () => {
|
|
437
|
+
target.background = oldBg;
|
|
438
|
+
};
|
|
439
|
+
});
|
|
440
|
+
return null;
|
|
441
|
+
}
|
|
442
|
+
function EnvironmentDualSource(props) {
|
|
443
|
+
const { backgroundFiles, ...envProps } = props;
|
|
444
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
445
|
+
/* @__PURE__ */ jsxRuntime.jsx(EnvironmentCube, { ...envProps, background: false }),
|
|
446
|
+
/* @__PURE__ */ jsxRuntime.jsx(EnvironmentCube, { ...props, files: backgroundFiles, background: "only" })
|
|
447
|
+
] });
|
|
448
|
+
}
|
|
449
|
+
function Environment(props) {
|
|
450
|
+
if (props.color && !props.files && !props.preset && !props.map) {
|
|
451
|
+
return /* @__PURE__ */ jsxRuntime.jsx(EnvironmentColor, { ...props });
|
|
452
|
+
}
|
|
453
|
+
if (props.backgroundFiles && props.backgroundFiles !== props.files) {
|
|
454
|
+
return /* @__PURE__ */ jsxRuntime.jsx(EnvironmentDualSource, { ...props });
|
|
455
|
+
}
|
|
456
|
+
return props.ground ? /* @__PURE__ */ jsxRuntime.jsx(EnvironmentGround, { ...props }) : props.map ? /* @__PURE__ */ jsxRuntime.jsx(EnvironmentMap, { ...props }) : props.children ? /* @__PURE__ */ jsxRuntime.jsx(EnvironmentPortal, { ...props }) : /* @__PURE__ */ jsxRuntime.jsx(EnvironmentCube, { ...props });
|
|
457
|
+
}
|
|
458
|
+
|
|
70
459
|
var __defProp$3 = Object.defineProperty;
|
|
71
460
|
var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
72
461
|
var __publicField$3 = (obj, key, value) => __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
@@ -246,7 +635,8 @@ function prepare(target, root, type, props) {
|
|
|
246
635
|
object,
|
|
247
636
|
eventCount: 0,
|
|
248
637
|
handlers: {},
|
|
249
|
-
isHidden: false
|
|
638
|
+
isHidden: false,
|
|
639
|
+
deferredRefs: []
|
|
250
640
|
};
|
|
251
641
|
if (object) object.__r3f = instance;
|
|
252
642
|
}
|
|
@@ -295,7 +685,7 @@ function createOcclusionObserverNode(store, uniform) {
|
|
|
295
685
|
let occlusionSetupPromise = null;
|
|
296
686
|
function enableOcclusion(store) {
|
|
297
687
|
const state = store.getState();
|
|
298
|
-
const { internal, renderer
|
|
688
|
+
const { internal, renderer } = state;
|
|
299
689
|
if (internal.occlusionEnabled || occlusionSetupPromise) return;
|
|
300
690
|
const hasOcclusionSupport = typeof renderer?.isOccluded === "function";
|
|
301
691
|
if (!hasOcclusionSupport) {
|
|
@@ -458,6 +848,22 @@ function hasVisibilityHandlers(handlers) {
|
|
|
458
848
|
return !!(handlers.onFramed || handlers.onOccluded || handlers.onVisible);
|
|
459
849
|
}
|
|
460
850
|
|
|
851
|
+
const FROM_REF = Symbol.for("@react-three/fiber.fromRef");
|
|
852
|
+
function fromRef(ref) {
|
|
853
|
+
return { [FROM_REF]: ref };
|
|
854
|
+
}
|
|
855
|
+
function isFromRef(value) {
|
|
856
|
+
return value !== null && typeof value === "object" && FROM_REF in value;
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
const ONCE = Symbol.for("@react-three/fiber.once");
|
|
860
|
+
function once(...args) {
|
|
861
|
+
return { [ONCE]: args.length ? args : true };
|
|
862
|
+
}
|
|
863
|
+
function isOnce(value) {
|
|
864
|
+
return value !== null && typeof value === "object" && ONCE in value;
|
|
865
|
+
}
|
|
866
|
+
|
|
461
867
|
const RESERVED_PROPS = [
|
|
462
868
|
"children",
|
|
463
869
|
"key",
|
|
@@ -528,7 +934,7 @@ function getMemoizedPrototype(root) {
|
|
|
528
934
|
ctor = new root.constructor();
|
|
529
935
|
MEMOIZED_PROTOTYPES.set(root.constructor, ctor);
|
|
530
936
|
}
|
|
531
|
-
} catch
|
|
937
|
+
} catch {
|
|
532
938
|
}
|
|
533
939
|
return ctor;
|
|
534
940
|
}
|
|
@@ -574,6 +980,25 @@ function applyProps(object, props) {
|
|
|
574
980
|
continue;
|
|
575
981
|
}
|
|
576
982
|
if (value === void 0) continue;
|
|
983
|
+
if (isFromRef(value)) {
|
|
984
|
+
instance?.deferredRefs?.push({ prop, ref: value[FROM_REF] });
|
|
985
|
+
continue;
|
|
986
|
+
}
|
|
987
|
+
if (isOnce(value)) {
|
|
988
|
+
if (instance?.appliedOnce?.has(prop)) continue;
|
|
989
|
+
if (instance) {
|
|
990
|
+
instance.appliedOnce ?? (instance.appliedOnce = /* @__PURE__ */ new Set());
|
|
991
|
+
instance.appliedOnce.add(prop);
|
|
992
|
+
}
|
|
993
|
+
const { root: targetRoot, key: targetKey } = resolve(object, prop);
|
|
994
|
+
const args = value[ONCE];
|
|
995
|
+
if (typeof targetRoot[targetKey] === "function") {
|
|
996
|
+
targetRoot[targetKey](...args === true ? [] : args);
|
|
997
|
+
} else if (args !== true && args.length > 0) {
|
|
998
|
+
targetRoot[targetKey] = args[0];
|
|
999
|
+
}
|
|
1000
|
+
continue;
|
|
1001
|
+
}
|
|
577
1002
|
let { root, key, target } = resolve(object, prop);
|
|
578
1003
|
if (target === void 0 && (typeof root !== "object" || root === null)) {
|
|
579
1004
|
throw Error(`R3F: Cannot set "${prop}". Ensure it is an object before setting "${key}".`);
|
|
@@ -596,7 +1021,10 @@ function applyProps(object, props) {
|
|
|
596
1021
|
else target.set(value);
|
|
597
1022
|
} else {
|
|
598
1023
|
root[key] = value;
|
|
599
|
-
if (
|
|
1024
|
+
if (key.endsWith("Node") && root.isMaterial) {
|
|
1025
|
+
root.needsUpdate = true;
|
|
1026
|
+
}
|
|
1027
|
+
if (rootState && rootState.renderer?.outputColorSpace === webgpu.SRGBColorSpace && colorMaps.includes(key) && isTexture(value) && root[key]?.isTexture && // sRGB textures must be RGBA8 since r137 https://github.com/mrdoob/three.js/pull/23129
|
|
600
1028
|
root[key].format === webgpu.RGBAFormat && root[key].type === webgpu.UnsignedByteType) {
|
|
601
1029
|
root[key].colorSpace = rootState.textureColorSpace;
|
|
602
1030
|
}
|
|
@@ -629,38 +1057,60 @@ function applyProps(object, props) {
|
|
|
629
1057
|
return object;
|
|
630
1058
|
}
|
|
631
1059
|
|
|
1060
|
+
const DEFAULT_POINTER_ID = 0;
|
|
1061
|
+
const XR_POINTER_ID_START = 1e3;
|
|
1062
|
+
function getPointerState(internal, pointerId) {
|
|
1063
|
+
let state = internal.pointerMap.get(pointerId);
|
|
1064
|
+
if (!state) {
|
|
1065
|
+
state = {
|
|
1066
|
+
hovered: /* @__PURE__ */ new Map(),
|
|
1067
|
+
captured: /* @__PURE__ */ new Map(),
|
|
1068
|
+
initialClick: [0, 0],
|
|
1069
|
+
initialHits: []
|
|
1070
|
+
};
|
|
1071
|
+
internal.pointerMap.set(pointerId, state);
|
|
1072
|
+
}
|
|
1073
|
+
return state;
|
|
1074
|
+
}
|
|
1075
|
+
function getPointerId(event) {
|
|
1076
|
+
return "pointerId" in event ? event.pointerId : DEFAULT_POINTER_ID;
|
|
1077
|
+
}
|
|
632
1078
|
function makeId(event) {
|
|
633
1079
|
return (event.eventObject || event.object).uuid + "/" + event.index + event.instanceId;
|
|
634
1080
|
}
|
|
635
|
-
function releaseInternalPointerCapture(
|
|
636
|
-
const
|
|
1081
|
+
function releaseInternalPointerCapture(internal, obj, pointerId) {
|
|
1082
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1083
|
+
if (!pointerState) return;
|
|
1084
|
+
const captureData = pointerState.captured.get(obj);
|
|
637
1085
|
if (captureData) {
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
capturedMap.delete(pointerId);
|
|
641
|
-
captureData.target.releasePointerCapture(pointerId);
|
|
642
|
-
}
|
|
1086
|
+
pointerState.captured.delete(obj);
|
|
1087
|
+
captureData.target.releasePointerCapture(pointerId);
|
|
643
1088
|
}
|
|
644
1089
|
}
|
|
645
1090
|
function removeInteractivity(store, object) {
|
|
646
1091
|
const { internal } = store.getState();
|
|
647
1092
|
internal.interaction = internal.interaction.filter((o) => o !== object);
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
1093
|
+
for (const [pointerId, pointerState] of internal.pointerMap) {
|
|
1094
|
+
pointerState.initialHits = pointerState.initialHits.filter((o) => o !== object);
|
|
1095
|
+
pointerState.hovered.forEach((value, key) => {
|
|
1096
|
+
if (value.eventObject === object || value.object === object) {
|
|
1097
|
+
pointerState.hovered.delete(key);
|
|
1098
|
+
}
|
|
1099
|
+
});
|
|
1100
|
+
if (pointerState.captured.has(object)) {
|
|
1101
|
+
releaseInternalPointerCapture(internal, object, pointerId);
|
|
652
1102
|
}
|
|
653
|
-
}
|
|
654
|
-
internal.capturedMap.forEach((captures, pointerId) => {
|
|
655
|
-
releaseInternalPointerCapture(internal.capturedMap, object, captures, pointerId);
|
|
656
|
-
});
|
|
1103
|
+
}
|
|
657
1104
|
unregisterVisibility(store, object);
|
|
658
1105
|
}
|
|
659
1106
|
function createEvents(store) {
|
|
660
|
-
function calculateDistance(event) {
|
|
1107
|
+
function calculateDistance(event, pointerId) {
|
|
661
1108
|
const { internal } = store.getState();
|
|
662
|
-
const
|
|
663
|
-
|
|
1109
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1110
|
+
if (!pointerState) return 0;
|
|
1111
|
+
const [initialX, initialY] = pointerState.initialClick;
|
|
1112
|
+
const dx = event.offsetX - initialX;
|
|
1113
|
+
const dy = event.offsetY - initialY;
|
|
664
1114
|
return Math.round(Math.sqrt(dx * dx + dy * dy));
|
|
665
1115
|
}
|
|
666
1116
|
function filterPointerEvents(objects) {
|
|
@@ -696,6 +1146,15 @@ function createEvents(store) {
|
|
|
696
1146
|
return state2.raycaster.camera ? state2.raycaster.intersectObject(obj, true) : [];
|
|
697
1147
|
}
|
|
698
1148
|
let hits = eventsObjects.flatMap(handleRaycast).sort((a, b) => {
|
|
1149
|
+
const aInteractivePriority = a.object.userData?.interactivePriority;
|
|
1150
|
+
const bInteractivePriority = b.object.userData?.interactivePriority;
|
|
1151
|
+
if (aInteractivePriority !== void 0 || bInteractivePriority !== void 0) {
|
|
1152
|
+
if (aInteractivePriority !== void 0 && bInteractivePriority === void 0) return -1;
|
|
1153
|
+
if (bInteractivePriority !== void 0 && aInteractivePriority === void 0) return 1;
|
|
1154
|
+
if (aInteractivePriority !== bInteractivePriority) {
|
|
1155
|
+
return (bInteractivePriority ?? 0) - (aInteractivePriority ?? 0);
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
699
1158
|
const aState = getRootState(a.object);
|
|
700
1159
|
const bState = getRootState(b.object);
|
|
701
1160
|
const aPriority = aState?.events?.priority ?? 1;
|
|
@@ -717,9 +1176,13 @@ function createEvents(store) {
|
|
|
717
1176
|
eventObject = eventObject.parent;
|
|
718
1177
|
}
|
|
719
1178
|
}
|
|
720
|
-
if ("pointerId" in event
|
|
721
|
-
|
|
722
|
-
|
|
1179
|
+
if ("pointerId" in event) {
|
|
1180
|
+
const pointerId = event.pointerId;
|
|
1181
|
+
const pointerState = state.internal.pointerMap.get(pointerId);
|
|
1182
|
+
if (pointerState?.captured.size) {
|
|
1183
|
+
for (const captureData of pointerState.captured.values()) {
|
|
1184
|
+
if (!duplicates.has(makeId(captureData.intersection))) intersections.push(captureData.intersection);
|
|
1185
|
+
}
|
|
723
1186
|
}
|
|
724
1187
|
}
|
|
725
1188
|
return intersections;
|
|
@@ -732,27 +1195,25 @@ function createEvents(store) {
|
|
|
732
1195
|
if (state) {
|
|
733
1196
|
const { raycaster, pointer, camera, internal } = state;
|
|
734
1197
|
const unprojectedPoint = new webgpu.Vector3(pointer.x, pointer.y, 0).unproject(camera);
|
|
735
|
-
const hasPointerCapture = (id) =>
|
|
1198
|
+
const hasPointerCapture = (id) => {
|
|
1199
|
+
const pointerState = internal.pointerMap.get(id);
|
|
1200
|
+
return pointerState?.captured.has(hit.eventObject) ?? false;
|
|
1201
|
+
};
|
|
736
1202
|
const setPointerCapture = (id) => {
|
|
737
1203
|
const captureData = { intersection: hit, target: event.target };
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
} else {
|
|
741
|
-
internal.capturedMap.set(id, /* @__PURE__ */ new Map([[hit.eventObject, captureData]]));
|
|
742
|
-
}
|
|
1204
|
+
const pointerState = getPointerState(internal, id);
|
|
1205
|
+
pointerState.captured.set(hit.eventObject, captureData);
|
|
743
1206
|
event.target.setPointerCapture(id);
|
|
744
1207
|
};
|
|
745
1208
|
const releasePointerCapture = (id) => {
|
|
746
|
-
|
|
747
|
-
if (captures) {
|
|
748
|
-
releaseInternalPointerCapture(internal.capturedMap, hit.eventObject, captures, id);
|
|
749
|
-
}
|
|
1209
|
+
releaseInternalPointerCapture(internal, hit.eventObject, id);
|
|
750
1210
|
};
|
|
751
1211
|
const extractEventProps = {};
|
|
752
1212
|
for (const prop in event) {
|
|
753
1213
|
const property = event[prop];
|
|
754
1214
|
if (typeof property !== "function") extractEventProps[prop] = property;
|
|
755
1215
|
}
|
|
1216
|
+
const eventPointerId = "pointerId" in event ? event.pointerId : void 0;
|
|
756
1217
|
const raycastEvent = {
|
|
757
1218
|
...hit,
|
|
758
1219
|
...extractEventProps,
|
|
@@ -763,18 +1224,19 @@ function createEvents(store) {
|
|
|
763
1224
|
unprojectedPoint,
|
|
764
1225
|
ray: raycaster.ray,
|
|
765
1226
|
camera,
|
|
1227
|
+
pointerId: eventPointerId,
|
|
766
1228
|
// Hijack stopPropagation, which just sets a flag
|
|
767
1229
|
stopPropagation() {
|
|
768
|
-
const
|
|
1230
|
+
const pointerState = eventPointerId !== void 0 ? internal.pointerMap.get(eventPointerId) : void 0;
|
|
769
1231
|
if (
|
|
770
1232
|
// ...if this pointer hasn't been captured
|
|
771
|
-
!
|
|
772
|
-
|
|
1233
|
+
!pointerState?.captured.size || // ... or if the hit object is capturing the pointer
|
|
1234
|
+
pointerState.captured.has(hit.eventObject)
|
|
773
1235
|
) {
|
|
774
1236
|
raycastEvent.stopped = localState.stopped = true;
|
|
775
|
-
if (
|
|
1237
|
+
if (pointerState?.hovered.size && Array.from(pointerState.hovered.values()).find((i) => i.eventObject === hit.eventObject)) {
|
|
776
1238
|
const higher = intersections.slice(0, intersections.indexOf(hit));
|
|
777
|
-
cancelPointer([...higher, hit]);
|
|
1239
|
+
cancelPointer([...higher, hit], eventPointerId);
|
|
778
1240
|
}
|
|
779
1241
|
}
|
|
780
1242
|
},
|
|
@@ -790,15 +1252,18 @@ function createEvents(store) {
|
|
|
790
1252
|
}
|
|
791
1253
|
return intersections;
|
|
792
1254
|
}
|
|
793
|
-
function cancelPointer(intersections) {
|
|
1255
|
+
function cancelPointer(intersections, pointerId) {
|
|
794
1256
|
const { internal } = store.getState();
|
|
795
|
-
|
|
1257
|
+
const pid = pointerId ?? DEFAULT_POINTER_ID;
|
|
1258
|
+
const pointerState = internal.pointerMap.get(pid);
|
|
1259
|
+
if (!pointerState) return;
|
|
1260
|
+
for (const [hoveredId, hoveredObj] of pointerState.hovered) {
|
|
796
1261
|
if (!intersections.length || !intersections.find(
|
|
797
1262
|
(hit) => hit.object === hoveredObj.object && hit.index === hoveredObj.index && hit.instanceId === hoveredObj.instanceId
|
|
798
1263
|
)) {
|
|
799
1264
|
const eventObject = hoveredObj.eventObject;
|
|
800
1265
|
const instance = eventObject.__r3f;
|
|
801
|
-
|
|
1266
|
+
pointerState.hovered.delete(hoveredId);
|
|
802
1267
|
if (instance?.eventCount) {
|
|
803
1268
|
const handlers = instance.handlers;
|
|
804
1269
|
const data = { ...hoveredObj, intersections };
|
|
@@ -827,41 +1292,118 @@ function createEvents(store) {
|
|
|
827
1292
|
instance?.handlers.onDropMissed?.(event);
|
|
828
1293
|
}
|
|
829
1294
|
}
|
|
1295
|
+
function cleanupPointer(pointerId) {
|
|
1296
|
+
const { internal } = store.getState();
|
|
1297
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1298
|
+
if (pointerState) {
|
|
1299
|
+
for (const [, hoveredObj] of pointerState.hovered) {
|
|
1300
|
+
const eventObject = hoveredObj.eventObject;
|
|
1301
|
+
const instance = eventObject.__r3f;
|
|
1302
|
+
if (instance?.eventCount) {
|
|
1303
|
+
const handlers = instance.handlers;
|
|
1304
|
+
const data = { ...hoveredObj, intersections: [] };
|
|
1305
|
+
handlers.onPointerOut?.(data);
|
|
1306
|
+
handlers.onPointerLeave?.(data);
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
internal.pointerMap.delete(pointerId);
|
|
1310
|
+
}
|
|
1311
|
+
internal.pointerDirty.delete(pointerId);
|
|
1312
|
+
}
|
|
1313
|
+
function processDeferredPointer(event, pointerId) {
|
|
1314
|
+
const state = store.getState();
|
|
1315
|
+
const { internal } = state;
|
|
1316
|
+
if (!state.events.enabled) return;
|
|
1317
|
+
const filter = filterPointerEvents;
|
|
1318
|
+
const hits = intersect(event, filter);
|
|
1319
|
+
cancelPointer(hits, pointerId);
|
|
1320
|
+
function onIntersect(data) {
|
|
1321
|
+
const eventObject = data.eventObject;
|
|
1322
|
+
const instance = eventObject.__r3f;
|
|
1323
|
+
if (!instance?.eventCount) return;
|
|
1324
|
+
const handlers = instance.handlers;
|
|
1325
|
+
if (handlers.onPointerOver || handlers.onPointerEnter || handlers.onPointerOut || handlers.onPointerLeave) {
|
|
1326
|
+
const id = makeId(data);
|
|
1327
|
+
const pointerState = getPointerState(internal, pointerId);
|
|
1328
|
+
const hoveredItem = pointerState.hovered.get(id);
|
|
1329
|
+
if (!hoveredItem) {
|
|
1330
|
+
pointerState.hovered.set(id, data);
|
|
1331
|
+
handlers.onPointerOver?.(data);
|
|
1332
|
+
handlers.onPointerEnter?.(data);
|
|
1333
|
+
} else if (hoveredItem.stopped) {
|
|
1334
|
+
data.stopPropagation();
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
handlers.onPointerMove?.(data);
|
|
1338
|
+
}
|
|
1339
|
+
handleIntersects(hits, event, 0, onIntersect);
|
|
1340
|
+
}
|
|
830
1341
|
function handlePointer(name) {
|
|
831
1342
|
switch (name) {
|
|
832
1343
|
case "onPointerLeave":
|
|
833
|
-
case "onPointerCancel":
|
|
834
1344
|
case "onDragLeave":
|
|
835
1345
|
return () => cancelPointer([]);
|
|
1346
|
+
// Global cancel of these events
|
|
1347
|
+
case "onPointerCancel":
|
|
1348
|
+
return (event) => {
|
|
1349
|
+
const pointerId = getPointerId(event);
|
|
1350
|
+
cleanupPointer(pointerId);
|
|
1351
|
+
};
|
|
836
1352
|
case "onLostPointerCapture":
|
|
837
1353
|
return (event) => {
|
|
838
1354
|
const { internal } = store.getState();
|
|
839
|
-
|
|
1355
|
+
const pointerId = getPointerId(event);
|
|
1356
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1357
|
+
if (pointerState?.captured.size) {
|
|
840
1358
|
requestAnimationFrame(() => {
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
1359
|
+
const pointerState2 = internal.pointerMap.get(pointerId);
|
|
1360
|
+
if (pointerState2?.captured.size) {
|
|
1361
|
+
pointerState2.captured.clear();
|
|
844
1362
|
}
|
|
1363
|
+
cancelPointer([], pointerId);
|
|
845
1364
|
});
|
|
846
1365
|
}
|
|
847
1366
|
};
|
|
848
1367
|
}
|
|
849
1368
|
return function handleEvent(event) {
|
|
850
1369
|
const state = store.getState();
|
|
851
|
-
const { onPointerMissed, onDragOverMissed, onDropMissed, internal } = state;
|
|
1370
|
+
const { onPointerMissed, onDragOverMissed, onDropMissed, internal, events } = state;
|
|
1371
|
+
const pointerId = getPointerId(event);
|
|
852
1372
|
internal.lastEvent.current = event;
|
|
853
|
-
if (!
|
|
1373
|
+
if (!events.enabled) return;
|
|
854
1374
|
const isPointerMove = name === "onPointerMove";
|
|
855
1375
|
const isDragOver = name === "onDragOver";
|
|
856
1376
|
const isDrop = name === "onDrop";
|
|
857
1377
|
const isClickEvent = name === "onClick" || name === "onContextMenu" || name === "onDoubleClick";
|
|
1378
|
+
const isPointerDown = name === "onPointerDown";
|
|
1379
|
+
const isPointerUp = name === "onPointerUp";
|
|
1380
|
+
const isWheel = name === "onWheel";
|
|
1381
|
+
const canDeferRaycasts = events.frameTimedRaycasts && state.frameloop === "always";
|
|
1382
|
+
if (isPointerMove && canDeferRaycasts) {
|
|
1383
|
+
events.compute?.(event, state);
|
|
1384
|
+
internal.pointerDirty.set(pointerId, event);
|
|
1385
|
+
return;
|
|
1386
|
+
}
|
|
1387
|
+
if (isWheel && canDeferRaycasts && !events.alwaysFireOnScroll) {
|
|
1388
|
+
events.compute?.(event, state);
|
|
1389
|
+
internal.pointerDirty.set(pointerId, event);
|
|
1390
|
+
return;
|
|
1391
|
+
}
|
|
1392
|
+
if ((isClickEvent || isPointerDown || isPointerUp) && internal.pointerDirty.has(pointerId)) {
|
|
1393
|
+
const deferredEvent = internal.pointerDirty.get(pointerId);
|
|
1394
|
+
internal.pointerDirty.delete(pointerId);
|
|
1395
|
+
processDeferredPointer(deferredEvent, pointerId);
|
|
1396
|
+
}
|
|
858
1397
|
const filter = isPointerMove || isDragOver || isDrop ? filterPointerEvents : void 0;
|
|
859
1398
|
const hits = intersect(event, filter);
|
|
860
|
-
const delta = isClickEvent ? calculateDistance(event) : 0;
|
|
861
|
-
if (
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
1399
|
+
const delta = isClickEvent ? calculateDistance(event, pointerId) : 0;
|
|
1400
|
+
if (isPointerDown) {
|
|
1401
|
+
const pointerState2 = getPointerState(internal, pointerId);
|
|
1402
|
+
pointerState2.initialClick = [event.offsetX, event.offsetY];
|
|
1403
|
+
pointerState2.initialHits = hits.map((hit) => hit.eventObject);
|
|
1404
|
+
}
|
|
1405
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1406
|
+
const initialHits = pointerState?.initialHits ?? [];
|
|
865
1407
|
if (isClickEvent && !hits.length) {
|
|
866
1408
|
if (delta <= 2) {
|
|
867
1409
|
pointerMissed(event, internal.interaction);
|
|
@@ -876,7 +1418,9 @@ function createEvents(store) {
|
|
|
876
1418
|
dropMissed(event, internal.interaction);
|
|
877
1419
|
if (onDropMissed) onDropMissed(event);
|
|
878
1420
|
}
|
|
879
|
-
if (isPointerMove || isDragOver)
|
|
1421
|
+
if (isPointerMove || isDragOver) {
|
|
1422
|
+
cancelPointer(hits, pointerId);
|
|
1423
|
+
}
|
|
880
1424
|
function onIntersect(data) {
|
|
881
1425
|
const eventObject = data.eventObject;
|
|
882
1426
|
const instance = eventObject.__r3f;
|
|
@@ -885,9 +1429,10 @@ function createEvents(store) {
|
|
|
885
1429
|
if (isPointerMove) {
|
|
886
1430
|
if (handlers.onPointerOver || handlers.onPointerEnter || handlers.onPointerOut || handlers.onPointerLeave) {
|
|
887
1431
|
const id = makeId(data);
|
|
888
|
-
const
|
|
1432
|
+
const pointerState2 = getPointerState(internal, pointerId);
|
|
1433
|
+
const hoveredItem = pointerState2.hovered.get(id);
|
|
889
1434
|
if (!hoveredItem) {
|
|
890
|
-
|
|
1435
|
+
pointerState2.hovered.set(id, data);
|
|
891
1436
|
handlers.onPointerOver?.(data);
|
|
892
1437
|
handlers.onPointerEnter?.(data);
|
|
893
1438
|
} else if (hoveredItem.stopped) {
|
|
@@ -897,9 +1442,10 @@ function createEvents(store) {
|
|
|
897
1442
|
handlers.onPointerMove?.(data);
|
|
898
1443
|
} else if (isDragOver) {
|
|
899
1444
|
const id = makeId(data);
|
|
900
|
-
const
|
|
1445
|
+
const pointerState2 = getPointerState(internal, pointerId);
|
|
1446
|
+
const hoveredItem = pointerState2.hovered.get(id);
|
|
901
1447
|
if (!hoveredItem) {
|
|
902
|
-
|
|
1448
|
+
pointerState2.hovered.set(id, data);
|
|
903
1449
|
handlers.onDragOverEnter?.(data);
|
|
904
1450
|
} else if (hoveredItem.stopped) {
|
|
905
1451
|
data.stopPropagation();
|
|
@@ -910,18 +1456,18 @@ function createEvents(store) {
|
|
|
910
1456
|
} else {
|
|
911
1457
|
const handler = handlers[name];
|
|
912
1458
|
if (handler) {
|
|
913
|
-
if (!isClickEvent ||
|
|
1459
|
+
if (!isClickEvent || initialHits.includes(eventObject)) {
|
|
914
1460
|
pointerMissed(
|
|
915
1461
|
event,
|
|
916
|
-
internal.interaction.filter((object) => !
|
|
1462
|
+
internal.interaction.filter((object) => !initialHits.includes(object))
|
|
917
1463
|
);
|
|
918
1464
|
handler(data);
|
|
919
1465
|
}
|
|
920
1466
|
} else {
|
|
921
|
-
if (isClickEvent &&
|
|
1467
|
+
if (isClickEvent && initialHits.includes(eventObject)) {
|
|
922
1468
|
pointerMissed(
|
|
923
1469
|
event,
|
|
924
|
-
internal.interaction.filter((object) => !
|
|
1470
|
+
internal.interaction.filter((object) => !initialHits.includes(object))
|
|
925
1471
|
);
|
|
926
1472
|
}
|
|
927
1473
|
}
|
|
@@ -930,7 +1476,15 @@ function createEvents(store) {
|
|
|
930
1476
|
handleIntersects(hits, event, delta, onIntersect);
|
|
931
1477
|
};
|
|
932
1478
|
}
|
|
933
|
-
|
|
1479
|
+
function flushDeferredPointers() {
|
|
1480
|
+
const { internal, events } = store.getState();
|
|
1481
|
+
if (!events.frameTimedRaycasts) return;
|
|
1482
|
+
for (const [pointerId, event] of internal.pointerDirty) {
|
|
1483
|
+
processDeferredPointer(event, pointerId);
|
|
1484
|
+
}
|
|
1485
|
+
internal.pointerDirty.clear();
|
|
1486
|
+
}
|
|
1487
|
+
return { handlePointer, flushDeferredPointers, processDeferredPointer };
|
|
934
1488
|
}
|
|
935
1489
|
const DOM_EVENTS = {
|
|
936
1490
|
onClick: ["click", false],
|
|
@@ -949,11 +1503,16 @@ const DOM_EVENTS = {
|
|
|
949
1503
|
onLostPointerCapture: ["lostpointercapture", true]
|
|
950
1504
|
};
|
|
951
1505
|
function createPointerEvents(store) {
|
|
952
|
-
const { handlePointer } = createEvents(store);
|
|
1506
|
+
const { handlePointer, flushDeferredPointers, processDeferredPointer } = createEvents(store);
|
|
1507
|
+
let nextXRPointerId = XR_POINTER_ID_START;
|
|
1508
|
+
const xrPointers = /* @__PURE__ */ new Map();
|
|
953
1509
|
return {
|
|
954
1510
|
priority: 1,
|
|
955
1511
|
enabled: true,
|
|
956
|
-
|
|
1512
|
+
frameTimedRaycasts: true,
|
|
1513
|
+
alwaysFireOnScroll: true,
|
|
1514
|
+
updateOnFrame: false,
|
|
1515
|
+
compute(event, state) {
|
|
957
1516
|
state.pointer.set(event.offsetX / state.size.width * 2 - 1, -(event.offsetY / state.size.height) * 2 + 1);
|
|
958
1517
|
state.raycaster.setFromCamera(state.pointer, state.camera);
|
|
959
1518
|
},
|
|
@@ -962,11 +1521,33 @@ function createPointerEvents(store) {
|
|
|
962
1521
|
(acc, key) => ({ ...acc, [key]: handlePointer(key) }),
|
|
963
1522
|
{}
|
|
964
1523
|
),
|
|
965
|
-
update: () => {
|
|
1524
|
+
update: (pointerId) => {
|
|
1525
|
+
const { events, internal } = store.getState();
|
|
1526
|
+
if (!events.handlers) return;
|
|
1527
|
+
if (pointerId !== void 0) {
|
|
1528
|
+
const event = internal.pointerDirty.get(pointerId);
|
|
1529
|
+
if (event) {
|
|
1530
|
+
internal.pointerDirty.delete(pointerId);
|
|
1531
|
+
processDeferredPointer(event, pointerId);
|
|
1532
|
+
} else if (internal.lastEvent?.current) {
|
|
1533
|
+
processDeferredPointer(internal.lastEvent.current, pointerId);
|
|
1534
|
+
}
|
|
1535
|
+
} else {
|
|
1536
|
+
flushDeferredPointers();
|
|
1537
|
+
if (internal.lastEvent?.current) {
|
|
1538
|
+
events.handlers.onPointerMove(internal.lastEvent.current);
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
},
|
|
1542
|
+
flush: () => {
|
|
966
1543
|
const { events, internal } = store.getState();
|
|
967
|
-
|
|
1544
|
+
flushDeferredPointers();
|
|
1545
|
+
if (events.updateOnFrame && internal.lastEvent?.current && events.handlers) {
|
|
1546
|
+
events.handlers.onPointerMove(internal.lastEvent.current);
|
|
1547
|
+
}
|
|
968
1548
|
},
|
|
969
1549
|
connect: (target) => {
|
|
1550
|
+
if (!target) return;
|
|
970
1551
|
const { set, events } = store.getState();
|
|
971
1552
|
events.disconnect?.();
|
|
972
1553
|
set((state) => ({ events: { ...state.events, connected: target } }));
|
|
@@ -990,6 +1571,32 @@ function createPointerEvents(store) {
|
|
|
990
1571
|
}
|
|
991
1572
|
set((state) => ({ events: { ...state.events, connected: void 0 } }));
|
|
992
1573
|
}
|
|
1574
|
+
},
|
|
1575
|
+
registerPointer: (config) => {
|
|
1576
|
+
const pointerId = nextXRPointerId++;
|
|
1577
|
+
xrPointers.set(pointerId, config);
|
|
1578
|
+
const { internal } = store.getState();
|
|
1579
|
+
getPointerState(internal, pointerId);
|
|
1580
|
+
return pointerId;
|
|
1581
|
+
},
|
|
1582
|
+
unregisterPointer: (pointerId) => {
|
|
1583
|
+
xrPointers.delete(pointerId);
|
|
1584
|
+
const { internal } = store.getState();
|
|
1585
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1586
|
+
if (pointerState) {
|
|
1587
|
+
for (const [, hoveredObj] of pointerState.hovered) {
|
|
1588
|
+
const eventObject = hoveredObj.eventObject;
|
|
1589
|
+
const instance = eventObject.__r3f;
|
|
1590
|
+
if (instance?.eventCount) {
|
|
1591
|
+
const handlers = instance.handlers;
|
|
1592
|
+
const data = { ...hoveredObj, intersections: [] };
|
|
1593
|
+
handlers.onPointerOut?.(data);
|
|
1594
|
+
handlers.onPointerLeave?.(data);
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
internal.pointerMap.delete(pointerId);
|
|
1598
|
+
}
|
|
1599
|
+
internal.pointerDirty.delete(pointerId);
|
|
993
1600
|
}
|
|
994
1601
|
};
|
|
995
1602
|
}
|
|
@@ -1051,331 +1658,26 @@ function notifyAlpha({ message, link }) {
|
|
|
1051
1658
|
}
|
|
1052
1659
|
}
|
|
1053
1660
|
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
}
|
|
1075
|
-
}
|
|
1076
|
-
let performanceTimeout = void 0;
|
|
1077
|
-
const setPerformanceCurrent = (current) => set((state2) => ({ performance: { ...state2.performance, current } }));
|
|
1078
|
-
const pointer = new webgpu.Vector2();
|
|
1079
|
-
const rootState = {
|
|
1080
|
-
set,
|
|
1081
|
-
get,
|
|
1082
|
-
// Mock objects that have to be configured
|
|
1083
|
-
gl: null,
|
|
1084
|
-
renderer: null,
|
|
1085
|
-
camera: null,
|
|
1086
|
-
frustum: new webgpu.Frustum(),
|
|
1087
|
-
autoUpdateFrustum: true,
|
|
1088
|
-
raycaster: null,
|
|
1089
|
-
events: { priority: 1, enabled: true, connected: false },
|
|
1090
|
-
scene: null,
|
|
1091
|
-
rootScene: null,
|
|
1092
|
-
xr: null,
|
|
1093
|
-
inspector: null,
|
|
1094
|
-
invalidate: (frames = 1, stackFrames = false) => invalidate(get(), frames, stackFrames),
|
|
1095
|
-
advance: (timestamp, runGlobalEffects) => advance(timestamp, runGlobalEffects, get()),
|
|
1096
|
-
legacy: false,
|
|
1097
|
-
linear: false,
|
|
1098
|
-
flat: false,
|
|
1099
|
-
textureColorSpace: "srgb",
|
|
1100
|
-
isLegacy: false,
|
|
1101
|
-
webGPUSupported: false,
|
|
1102
|
-
isNative: false,
|
|
1103
|
-
controls: null,
|
|
1104
|
-
pointer,
|
|
1105
|
-
mouse: pointer,
|
|
1106
|
-
frameloop: "always",
|
|
1107
|
-
onPointerMissed: void 0,
|
|
1108
|
-
onDragOverMissed: void 0,
|
|
1109
|
-
onDropMissed: void 0,
|
|
1110
|
-
performance: {
|
|
1111
|
-
current: 1,
|
|
1112
|
-
min: 0.5,
|
|
1113
|
-
max: 1,
|
|
1114
|
-
debounce: 200,
|
|
1115
|
-
regress: () => {
|
|
1116
|
-
const state2 = get();
|
|
1117
|
-
if (performanceTimeout) clearTimeout(performanceTimeout);
|
|
1118
|
-
if (state2.performance.current !== state2.performance.min) setPerformanceCurrent(state2.performance.min);
|
|
1119
|
-
performanceTimeout = setTimeout(
|
|
1120
|
-
() => setPerformanceCurrent(get().performance.max),
|
|
1121
|
-
state2.performance.debounce
|
|
1122
|
-
);
|
|
1123
|
-
}
|
|
1124
|
-
},
|
|
1125
|
-
size: { width: 0, height: 0, top: 0, left: 0 },
|
|
1126
|
-
viewport: {
|
|
1127
|
-
initialDpr: 0,
|
|
1128
|
-
dpr: 0,
|
|
1129
|
-
width: 0,
|
|
1130
|
-
height: 0,
|
|
1131
|
-
top: 0,
|
|
1132
|
-
left: 0,
|
|
1133
|
-
aspect: 0,
|
|
1134
|
-
distance: 0,
|
|
1135
|
-
factor: 0,
|
|
1136
|
-
getCurrentViewport
|
|
1137
|
-
},
|
|
1138
|
-
setEvents: (events) => set((state2) => ({ ...state2, events: { ...state2.events, ...events } })),
|
|
1139
|
-
setSize: (width, height, top, left) => {
|
|
1140
|
-
const state2 = get();
|
|
1141
|
-
if (width === void 0) {
|
|
1142
|
-
set({ _sizeImperative: false });
|
|
1143
|
-
if (state2._sizeProps) {
|
|
1144
|
-
const { width: propW, height: propH } = state2._sizeProps;
|
|
1145
|
-
if (propW !== void 0 || propH !== void 0) {
|
|
1146
|
-
const currentSize = state2.size;
|
|
1147
|
-
const newSize = {
|
|
1148
|
-
width: propW ?? currentSize.width,
|
|
1149
|
-
height: propH ?? currentSize.height,
|
|
1150
|
-
top: currentSize.top,
|
|
1151
|
-
left: currentSize.left
|
|
1152
|
-
};
|
|
1153
|
-
set((s) => ({
|
|
1154
|
-
size: newSize,
|
|
1155
|
-
viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, newSize) }
|
|
1156
|
-
}));
|
|
1157
|
-
}
|
|
1158
|
-
}
|
|
1159
|
-
return;
|
|
1160
|
-
}
|
|
1161
|
-
const w = width;
|
|
1162
|
-
const h = height ?? width;
|
|
1163
|
-
const t = top ?? state2.size.top;
|
|
1164
|
-
const l = left ?? state2.size.left;
|
|
1165
|
-
const size = { width: w, height: h, top: t, left: l };
|
|
1166
|
-
set((s) => ({
|
|
1167
|
-
size,
|
|
1168
|
-
viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, size) },
|
|
1169
|
-
_sizeImperative: true
|
|
1170
|
-
}));
|
|
1171
|
-
},
|
|
1172
|
-
setDpr: (dpr) => set((state2) => {
|
|
1173
|
-
const resolved = calculateDpr(dpr);
|
|
1174
|
-
return { viewport: { ...state2.viewport, dpr: resolved, initialDpr: state2.viewport.initialDpr || resolved } };
|
|
1175
|
-
}),
|
|
1176
|
-
setFrameloop: (frameloop = "always") => {
|
|
1177
|
-
set(() => ({ frameloop }));
|
|
1178
|
-
},
|
|
1179
|
-
setError: (error) => set(() => ({ error })),
|
|
1180
|
-
error: null,
|
|
1181
|
-
//* TSL State (managed via hooks: useUniforms, useNodes, useTextures, usePostProcessing) ==============================
|
|
1182
|
-
uniforms: {},
|
|
1183
|
-
nodes: {},
|
|
1184
|
-
textures: /* @__PURE__ */ new Map(),
|
|
1185
|
-
postProcessing: null,
|
|
1186
|
-
passes: {},
|
|
1187
|
-
_hmrVersion: 0,
|
|
1188
|
-
_sizeImperative: false,
|
|
1189
|
-
_sizeProps: null,
|
|
1190
|
-
previousRoot: void 0,
|
|
1191
|
-
internal: {
|
|
1192
|
-
// Events
|
|
1193
|
-
interaction: [],
|
|
1194
|
-
hovered: /* @__PURE__ */ new Map(),
|
|
1195
|
-
subscribers: [],
|
|
1196
|
-
initialClick: [0, 0],
|
|
1197
|
-
initialHits: [],
|
|
1198
|
-
capturedMap: /* @__PURE__ */ new Map(),
|
|
1199
|
-
lastEvent: React__namespace.createRef(),
|
|
1200
|
-
// Visibility tracking (onFramed, onOccluded, onVisible)
|
|
1201
|
-
visibilityRegistry: /* @__PURE__ */ new Map(),
|
|
1202
|
-
// Occlusion system (WebGPU only)
|
|
1203
|
-
occlusionEnabled: false,
|
|
1204
|
-
occlusionObserver: null,
|
|
1205
|
-
occlusionCache: /* @__PURE__ */ new Map(),
|
|
1206
|
-
helperGroup: null,
|
|
1207
|
-
// Updates
|
|
1208
|
-
active: false,
|
|
1209
|
-
frames: 0,
|
|
1210
|
-
priority: 0,
|
|
1211
|
-
subscribe: (ref, priority, store) => {
|
|
1212
|
-
const internal = get().internal;
|
|
1213
|
-
internal.priority = internal.priority + (priority > 0 ? 1 : 0);
|
|
1214
|
-
internal.subscribers.push({ ref, priority, store });
|
|
1215
|
-
internal.subscribers = internal.subscribers.sort((a, b) => a.priority - b.priority);
|
|
1216
|
-
return () => {
|
|
1217
|
-
const internal2 = get().internal;
|
|
1218
|
-
if (internal2?.subscribers) {
|
|
1219
|
-
internal2.priority = internal2.priority - (priority > 0 ? 1 : 0);
|
|
1220
|
-
internal2.subscribers = internal2.subscribers.filter((s) => s.ref !== ref);
|
|
1221
|
-
}
|
|
1222
|
-
};
|
|
1223
|
-
},
|
|
1224
|
-
// Renderer Storage (single source of truth)
|
|
1225
|
-
actualRenderer: null,
|
|
1226
|
-
// Scheduler for useFrameNext (initialized in renderer.tsx)
|
|
1227
|
-
scheduler: null
|
|
1228
|
-
}
|
|
1229
|
-
};
|
|
1230
|
-
return rootState;
|
|
1231
|
-
});
|
|
1232
|
-
const state = rootStore.getState();
|
|
1233
|
-
Object.defineProperty(state, "gl", {
|
|
1234
|
-
get() {
|
|
1235
|
-
const currentState = rootStore.getState();
|
|
1236
|
-
if (!currentState.isLegacy && currentState.internal.actualRenderer) {
|
|
1237
|
-
const stack = new Error().stack || "";
|
|
1238
|
-
const isInternalAccess = stack.includes("zustand") || stack.includes("setState") || stack.includes("Object.assign") || stack.includes("react-three-fiber/packages/fiber/src/core");
|
|
1239
|
-
if (!isInternalAccess) {
|
|
1240
|
-
const cleanedStack = stack.split("\n").slice(2).join("\n") || "Stack trace unavailable";
|
|
1241
|
-
notifyDepreciated({
|
|
1242
|
-
heading: "Accessing state.gl in WebGPU mode",
|
|
1243
|
-
body: "Please use state.renderer instead. state.gl is deprecated and will be removed in future versions.\n\nFor backwards compatibility, state.gl currently maps to state.renderer, but this may cause issues with libraries expecting WebGLRenderer.\n\nAccessed from:\n" + cleanedStack
|
|
1244
|
-
});
|
|
1245
|
-
}
|
|
1246
|
-
}
|
|
1247
|
-
return currentState.internal.actualRenderer;
|
|
1248
|
-
},
|
|
1249
|
-
set(value) {
|
|
1250
|
-
rootStore.getState().internal.actualRenderer = value;
|
|
1251
|
-
},
|
|
1252
|
-
enumerable: true,
|
|
1253
|
-
configurable: true
|
|
1254
|
-
});
|
|
1255
|
-
Object.defineProperty(state, "renderer", {
|
|
1256
|
-
get() {
|
|
1257
|
-
return rootStore.getState().internal.actualRenderer;
|
|
1258
|
-
},
|
|
1259
|
-
set(value) {
|
|
1260
|
-
rootStore.getState().internal.actualRenderer = value;
|
|
1261
|
-
},
|
|
1262
|
-
enumerable: true,
|
|
1263
|
-
configurable: true
|
|
1264
|
-
});
|
|
1265
|
-
let oldScene = state.scene;
|
|
1266
|
-
rootStore.subscribe(() => {
|
|
1267
|
-
const currentState = rootStore.getState();
|
|
1268
|
-
const { scene, rootScene, set } = currentState;
|
|
1269
|
-
if (scene !== oldScene) {
|
|
1270
|
-
oldScene = scene;
|
|
1271
|
-
if (scene?.isScene && scene !== rootScene) {
|
|
1272
|
-
set({ rootScene: scene });
|
|
1273
|
-
}
|
|
1274
|
-
}
|
|
1275
|
-
});
|
|
1276
|
-
let oldSize = state.size;
|
|
1277
|
-
let oldDpr = state.viewport.dpr;
|
|
1278
|
-
let oldCamera = state.camera;
|
|
1279
|
-
rootStore.subscribe(() => {
|
|
1280
|
-
const { camera, size, viewport, set, internal } = rootStore.getState();
|
|
1281
|
-
const actualRenderer = internal.actualRenderer;
|
|
1282
|
-
if (size.width !== oldSize.width || size.height !== oldSize.height || viewport.dpr !== oldDpr) {
|
|
1283
|
-
oldSize = size;
|
|
1284
|
-
oldDpr = viewport.dpr;
|
|
1285
|
-
updateCamera(camera, size);
|
|
1286
|
-
if (viewport.dpr > 0) actualRenderer.setPixelRatio(viewport.dpr);
|
|
1287
|
-
const updateStyle = typeof HTMLCanvasElement !== "undefined" && actualRenderer.domElement instanceof HTMLCanvasElement;
|
|
1288
|
-
actualRenderer.setSize(size.width, size.height, updateStyle);
|
|
1289
|
-
}
|
|
1290
|
-
if (camera !== oldCamera) {
|
|
1291
|
-
oldCamera = camera;
|
|
1292
|
-
const { rootScene } = rootStore.getState();
|
|
1293
|
-
if (camera && rootScene && !camera.parent) {
|
|
1294
|
-
rootScene.add(camera);
|
|
1295
|
-
}
|
|
1296
|
-
set((state2) => ({ viewport: { ...state2.viewport, ...state2.viewport.getCurrentViewport(camera) } }));
|
|
1297
|
-
const currentState = rootStore.getState();
|
|
1298
|
-
if (currentState.autoUpdateFrustum && camera) {
|
|
1299
|
-
updateFrustum(camera, currentState.frustum);
|
|
1300
|
-
}
|
|
1301
|
-
}
|
|
1302
|
-
});
|
|
1303
|
-
rootStore.subscribe((state2) => invalidate(state2));
|
|
1304
|
-
return rootStore;
|
|
1305
|
-
};
|
|
1306
|
-
|
|
1307
|
-
const memoizedLoaders = /* @__PURE__ */ new WeakMap();
|
|
1308
|
-
const isConstructor$1 = (value) => typeof value === "function" && value?.prototype?.constructor === value;
|
|
1309
|
-
function getLoader(Proto) {
|
|
1310
|
-
if (isConstructor$1(Proto)) {
|
|
1311
|
-
let loader = memoizedLoaders.get(Proto);
|
|
1312
|
-
if (!loader) {
|
|
1313
|
-
loader = new Proto();
|
|
1314
|
-
memoizedLoaders.set(Proto, loader);
|
|
1315
|
-
}
|
|
1316
|
-
return loader;
|
|
1317
|
-
}
|
|
1318
|
-
return Proto;
|
|
1319
|
-
}
|
|
1320
|
-
function loadingFn(extensions, onProgress) {
|
|
1321
|
-
return function(Proto, input) {
|
|
1322
|
-
const loader = getLoader(Proto);
|
|
1323
|
-
if (extensions) extensions(loader);
|
|
1324
|
-
if ("loadAsync" in loader && typeof loader.loadAsync === "function") {
|
|
1325
|
-
return loader.loadAsync(input, onProgress).then((data) => {
|
|
1326
|
-
if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
|
|
1327
|
-
return data;
|
|
1328
|
-
});
|
|
1329
|
-
}
|
|
1330
|
-
return new Promise(
|
|
1331
|
-
(res, reject) => loader.load(
|
|
1332
|
-
input,
|
|
1333
|
-
(data) => {
|
|
1334
|
-
if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
|
|
1335
|
-
res(data);
|
|
1336
|
-
},
|
|
1337
|
-
onProgress,
|
|
1338
|
-
(error) => reject(new Error(`Could not load ${input}: ${error?.message}`))
|
|
1339
|
-
)
|
|
1340
|
-
);
|
|
1341
|
-
};
|
|
1342
|
-
}
|
|
1343
|
-
function useLoader(loader, input, extensions, onProgress) {
|
|
1344
|
-
const keys = Array.isArray(input) ? input : [input];
|
|
1345
|
-
const fn = loadingFn(extensions, onProgress);
|
|
1346
|
-
const results = keys.map((key) => suspendReact.suspend(fn, [loader, key], { equal: is.equ }));
|
|
1347
|
-
return Array.isArray(input) ? results : results[0];
|
|
1348
|
-
}
|
|
1349
|
-
useLoader.preload = function(loader, input, extensions, onProgress) {
|
|
1350
|
-
const keys = Array.isArray(input) ? input : [input];
|
|
1351
|
-
keys.forEach((key) => suspendReact.preload(loadingFn(extensions, onProgress), [loader, key]));
|
|
1352
|
-
};
|
|
1353
|
-
useLoader.clear = function(loader, input) {
|
|
1354
|
-
const keys = Array.isArray(input) ? input : [input];
|
|
1355
|
-
keys.forEach((key) => suspendReact.clear([loader, key]));
|
|
1356
|
-
};
|
|
1357
|
-
useLoader.loader = getLoader;
|
|
1358
|
-
|
|
1359
|
-
var __defProp$2 = Object.defineProperty;
|
|
1360
|
-
var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
1361
|
-
var __publicField$2 = (obj, key, value) => __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1362
|
-
const DEFAULT_PHASES = ["start", "input", "physics", "update", "render", "finish"];
|
|
1363
|
-
class PhaseGraph {
|
|
1364
|
-
constructor() {
|
|
1365
|
-
/** Ordered list of phase nodes */
|
|
1366
|
-
__publicField$2(this, "phases", []);
|
|
1367
|
-
/** Quick lookup by name */
|
|
1368
|
-
__publicField$2(this, "phaseMap", /* @__PURE__ */ new Map());
|
|
1369
|
-
/** Cached ordered names (invalidated on changes) */
|
|
1370
|
-
__publicField$2(this, "orderedNamesCache", null);
|
|
1371
|
-
this.initializeDefaultPhases();
|
|
1372
|
-
}
|
|
1373
|
-
//* Initialization --------------------------------
|
|
1374
|
-
initializeDefaultPhases() {
|
|
1375
|
-
for (const name of DEFAULT_PHASES) {
|
|
1376
|
-
const node = { name, isAutoGenerated: false };
|
|
1377
|
-
this.phases.push(node);
|
|
1378
|
-
this.phaseMap.set(name, node);
|
|
1661
|
+
var __defProp$2 = Object.defineProperty;
|
|
1662
|
+
var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
1663
|
+
var __publicField$2 = (obj, key, value) => __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1664
|
+
const DEFAULT_PHASES = ["start", "input", "physics", "update", "render", "finish"];
|
|
1665
|
+
class PhaseGraph {
|
|
1666
|
+
constructor() {
|
|
1667
|
+
/** Ordered list of phase nodes */
|
|
1668
|
+
__publicField$2(this, "phases", []);
|
|
1669
|
+
/** Quick lookup by name */
|
|
1670
|
+
__publicField$2(this, "phaseMap", /* @__PURE__ */ new Map());
|
|
1671
|
+
/** Cached ordered names (invalidated on changes) */
|
|
1672
|
+
__publicField$2(this, "orderedNamesCache", null);
|
|
1673
|
+
this.initializeDefaultPhases();
|
|
1674
|
+
}
|
|
1675
|
+
//* Initialization --------------------------------
|
|
1676
|
+
initializeDefaultPhases() {
|
|
1677
|
+
for (const name of DEFAULT_PHASES) {
|
|
1678
|
+
const node = { name, isAutoGenerated: false };
|
|
1679
|
+
this.phases.push(node);
|
|
1680
|
+
this.phaseMap.set(name, node);
|
|
1379
1681
|
}
|
|
1380
1682
|
this.invalidateCache();
|
|
1381
1683
|
}
|
|
@@ -1608,7 +1910,7 @@ function shouldRun(job, now) {
|
|
|
1608
1910
|
const minInterval = 1e3 / job.fps;
|
|
1609
1911
|
const lastRun = job.lastRun ?? 0;
|
|
1610
1912
|
const elapsed = now - lastRun;
|
|
1611
|
-
if (elapsed < minInterval) return false;
|
|
1913
|
+
if (elapsed < minInterval - 1) return false;
|
|
1612
1914
|
if (job.drop) {
|
|
1613
1915
|
job.lastRun = now;
|
|
1614
1916
|
} else {
|
|
@@ -2388,36 +2690,364 @@ if (hmrData) {
|
|
|
2388
2690
|
hmrData.accept?.();
|
|
2389
2691
|
}
|
|
2390
2692
|
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
const
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2693
|
+
const R3F_CONTEXT = Symbol.for("@react-three/fiber.context");
|
|
2694
|
+
const context = globalThis[R3F_CONTEXT] ?? (globalThis[R3F_CONTEXT] = React__namespace.createContext(null));
|
|
2695
|
+
const createStore = (invalidate, advance) => {
|
|
2696
|
+
const rootStore = traditional.createWithEqualityFn((set, get) => {
|
|
2697
|
+
const position = new webgpu.Vector3();
|
|
2698
|
+
const defaultTarget = new webgpu.Vector3();
|
|
2699
|
+
const tempTarget = new webgpu.Vector3();
|
|
2700
|
+
function getCurrentViewport(camera = get().camera, target = defaultTarget, size = get().size) {
|
|
2701
|
+
const { width, height, top, left } = size;
|
|
2702
|
+
const aspect = width / height;
|
|
2703
|
+
if (target.isVector3) tempTarget.copy(target);
|
|
2704
|
+
else tempTarget.set(...target);
|
|
2705
|
+
const distance = camera.getWorldPosition(position).distanceTo(tempTarget);
|
|
2706
|
+
if (isOrthographicCamera(camera)) {
|
|
2707
|
+
return { width: width / camera.zoom, height: height / camera.zoom, top, left, factor: 1, distance, aspect };
|
|
2708
|
+
} else {
|
|
2709
|
+
const fov = camera.fov * Math.PI / 180;
|
|
2710
|
+
const h = 2 * Math.tan(fov / 2) * distance;
|
|
2711
|
+
const w = h * (width / height);
|
|
2712
|
+
return { width: w, height: h, top, left, factor: width / w, distance, aspect };
|
|
2713
|
+
}
|
|
2714
|
+
}
|
|
2715
|
+
let performanceTimeout = void 0;
|
|
2716
|
+
const setPerformanceCurrent = (current) => set((state2) => ({ performance: { ...state2.performance, current } }));
|
|
2717
|
+
const pointer = new webgpu.Vector2();
|
|
2718
|
+
const rootState = {
|
|
2719
|
+
set,
|
|
2720
|
+
get,
|
|
2721
|
+
// Mock objects that have to be configured
|
|
2722
|
+
// primaryStore is set after store creation (self-reference for primary, primary's store for secondary)
|
|
2723
|
+
primaryStore: null,
|
|
2724
|
+
gl: null,
|
|
2725
|
+
renderer: null,
|
|
2726
|
+
camera: null,
|
|
2727
|
+
frustum: new webgpu.Frustum(),
|
|
2728
|
+
autoUpdateFrustum: true,
|
|
2729
|
+
raycaster: null,
|
|
2730
|
+
events: {
|
|
2731
|
+
priority: 1,
|
|
2732
|
+
enabled: true,
|
|
2733
|
+
connected: false,
|
|
2734
|
+
frameTimedRaycasts: true,
|
|
2735
|
+
alwaysFireOnScroll: true,
|
|
2736
|
+
updateOnFrame: false
|
|
2737
|
+
},
|
|
2738
|
+
scene: null,
|
|
2739
|
+
rootScene: null,
|
|
2740
|
+
xr: null,
|
|
2741
|
+
inspector: null,
|
|
2742
|
+
invalidate: (frames = 1, stackFrames = false) => invalidate(get(), frames, stackFrames),
|
|
2743
|
+
advance: (timestamp, runGlobalEffects) => advance(timestamp, runGlobalEffects, get()),
|
|
2744
|
+
textureColorSpace: webgpu.SRGBColorSpace,
|
|
2745
|
+
isLegacy: false,
|
|
2746
|
+
webGPUSupported: false,
|
|
2747
|
+
isNative: false,
|
|
2748
|
+
controls: null,
|
|
2749
|
+
pointer,
|
|
2750
|
+
mouse: pointer,
|
|
2751
|
+
frameloop: "always",
|
|
2752
|
+
onPointerMissed: void 0,
|
|
2753
|
+
onDragOverMissed: void 0,
|
|
2754
|
+
onDropMissed: void 0,
|
|
2755
|
+
performance: {
|
|
2756
|
+
current: 1,
|
|
2757
|
+
min: 0.5,
|
|
2758
|
+
max: 1,
|
|
2759
|
+
debounce: 200,
|
|
2760
|
+
regress: () => {
|
|
2761
|
+
const state2 = get();
|
|
2762
|
+
if (performanceTimeout) clearTimeout(performanceTimeout);
|
|
2763
|
+
if (state2.performance.current !== state2.performance.min) setPerformanceCurrent(state2.performance.min);
|
|
2764
|
+
performanceTimeout = setTimeout(
|
|
2765
|
+
() => setPerformanceCurrent(get().performance.max),
|
|
2766
|
+
state2.performance.debounce
|
|
2767
|
+
);
|
|
2768
|
+
}
|
|
2769
|
+
},
|
|
2770
|
+
size: { width: 0, height: 0, top: 0, left: 0 },
|
|
2771
|
+
viewport: {
|
|
2772
|
+
initialDpr: 0,
|
|
2773
|
+
dpr: 0,
|
|
2774
|
+
width: 0,
|
|
2775
|
+
height: 0,
|
|
2776
|
+
top: 0,
|
|
2777
|
+
left: 0,
|
|
2778
|
+
aspect: 0,
|
|
2779
|
+
distance: 0,
|
|
2780
|
+
factor: 0,
|
|
2781
|
+
getCurrentViewport
|
|
2782
|
+
},
|
|
2783
|
+
setEvents: (events) => set((state2) => ({ ...state2, events: { ...state2.events, ...events } })),
|
|
2784
|
+
setSize: (width, height, top, left) => {
|
|
2785
|
+
const state2 = get();
|
|
2786
|
+
if (width === void 0) {
|
|
2787
|
+
set({ _sizeImperative: false });
|
|
2788
|
+
if (state2._sizeProps) {
|
|
2789
|
+
const { width: propW, height: propH } = state2._sizeProps;
|
|
2790
|
+
if (propW !== void 0 || propH !== void 0) {
|
|
2791
|
+
const currentSize = state2.size;
|
|
2792
|
+
const newSize = {
|
|
2793
|
+
width: propW ?? currentSize.width,
|
|
2794
|
+
height: propH ?? currentSize.height,
|
|
2795
|
+
top: currentSize.top,
|
|
2796
|
+
left: currentSize.left
|
|
2797
|
+
};
|
|
2798
|
+
set((s) => ({
|
|
2799
|
+
size: newSize,
|
|
2800
|
+
viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, newSize) }
|
|
2801
|
+
}));
|
|
2802
|
+
getScheduler().invalidate();
|
|
2803
|
+
}
|
|
2804
|
+
}
|
|
2805
|
+
return;
|
|
2806
|
+
}
|
|
2807
|
+
const w = width;
|
|
2808
|
+
const h = height ?? width;
|
|
2809
|
+
const t = top ?? state2.size.top;
|
|
2810
|
+
const l = left ?? state2.size.left;
|
|
2811
|
+
const size = { width: w, height: h, top: t, left: l };
|
|
2812
|
+
set((s) => ({
|
|
2813
|
+
size,
|
|
2814
|
+
viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, size) },
|
|
2815
|
+
_sizeImperative: true
|
|
2816
|
+
}));
|
|
2817
|
+
getScheduler().invalidate();
|
|
2818
|
+
},
|
|
2819
|
+
setDpr: (dpr) => set((state2) => {
|
|
2820
|
+
const resolved = calculateDpr(dpr);
|
|
2821
|
+
return { viewport: { ...state2.viewport, dpr: resolved, initialDpr: state2.viewport.initialDpr || resolved } };
|
|
2822
|
+
}),
|
|
2823
|
+
setFrameloop: (frameloop = "always") => {
|
|
2824
|
+
set(() => ({ frameloop }));
|
|
2825
|
+
},
|
|
2826
|
+
setError: (error) => set(() => ({ error })),
|
|
2827
|
+
error: null,
|
|
2828
|
+
//* TSL State (managed via hooks: useUniforms, useNodes, useBuffers, useGPUStorage, useTextures, useRenderPipeline) ==============================
|
|
2829
|
+
uniforms: {},
|
|
2830
|
+
nodes: {},
|
|
2831
|
+
buffers: {},
|
|
2832
|
+
gpuStorage: {},
|
|
2833
|
+
textures: /* @__PURE__ */ new Map(),
|
|
2834
|
+
renderPipeline: null,
|
|
2835
|
+
passes: {},
|
|
2836
|
+
_hmrVersion: 0,
|
|
2837
|
+
_sizeImperative: false,
|
|
2838
|
+
_sizeProps: null,
|
|
2839
|
+
previousRoot: void 0,
|
|
2840
|
+
internal: {
|
|
2841
|
+
// Events
|
|
2842
|
+
interaction: [],
|
|
2843
|
+
subscribers: [],
|
|
2844
|
+
// Per-pointer state (new unified structure)
|
|
2845
|
+
pointerMap: /* @__PURE__ */ new Map(),
|
|
2846
|
+
pointerDirty: /* @__PURE__ */ new Map(),
|
|
2847
|
+
lastEvent: React__namespace.createRef(),
|
|
2848
|
+
// Deprecated but kept for backwards compatibility
|
|
2849
|
+
hovered: /* @__PURE__ */ new Map(),
|
|
2850
|
+
initialClick: [0, 0],
|
|
2851
|
+
initialHits: [],
|
|
2852
|
+
capturedMap: /* @__PURE__ */ new Map(),
|
|
2853
|
+
// Visibility tracking (onFramed, onOccluded, onVisible)
|
|
2854
|
+
visibilityRegistry: /* @__PURE__ */ new Map(),
|
|
2855
|
+
// Occlusion system (WebGPU only)
|
|
2856
|
+
occlusionEnabled: false,
|
|
2857
|
+
occlusionObserver: null,
|
|
2858
|
+
occlusionCache: /* @__PURE__ */ new Map(),
|
|
2859
|
+
helperGroup: null,
|
|
2860
|
+
// Updates
|
|
2861
|
+
active: false,
|
|
2862
|
+
frames: 0,
|
|
2863
|
+
priority: 0,
|
|
2864
|
+
subscribe: (ref, priority, store) => {
|
|
2865
|
+
const internal = get().internal;
|
|
2866
|
+
internal.priority = internal.priority + (priority > 0 ? 1 : 0);
|
|
2867
|
+
internal.subscribers.push({ ref, priority, store });
|
|
2868
|
+
internal.subscribers = internal.subscribers.sort((a, b) => a.priority - b.priority);
|
|
2869
|
+
return () => {
|
|
2870
|
+
const internal2 = get().internal;
|
|
2871
|
+
if (internal2?.subscribers) {
|
|
2872
|
+
internal2.priority = internal2.priority - (priority > 0 ? 1 : 0);
|
|
2873
|
+
internal2.subscribers = internal2.subscribers.filter((s) => s.ref !== ref);
|
|
2874
|
+
}
|
|
2875
|
+
};
|
|
2876
|
+
},
|
|
2877
|
+
// Renderer Storage (single source of truth)
|
|
2878
|
+
actualRenderer: null,
|
|
2879
|
+
// Scheduler for useFrameNext (initialized in renderer.tsx)
|
|
2880
|
+
scheduler: null
|
|
2881
|
+
}
|
|
2882
|
+
};
|
|
2883
|
+
return rootState;
|
|
2884
|
+
});
|
|
2885
|
+
const state = rootStore.getState();
|
|
2886
|
+
Object.defineProperty(state, "gl", {
|
|
2887
|
+
get() {
|
|
2888
|
+
const currentState = rootStore.getState();
|
|
2889
|
+
if (!currentState.isLegacy && currentState.internal.actualRenderer) {
|
|
2890
|
+
const stack = new Error().stack || "";
|
|
2891
|
+
const isInternalAccess = stack.includes("zustand") || stack.includes("setState") || stack.includes("Object.assign") || stack.includes("react-three-fiber/packages/fiber/src/core");
|
|
2892
|
+
if (!isInternalAccess) {
|
|
2893
|
+
const cleanedStack = stack.split("\n").slice(2).join("\n") || "Stack trace unavailable";
|
|
2894
|
+
notifyDepreciated({
|
|
2895
|
+
heading: "Accessing state.gl in WebGPU mode",
|
|
2896
|
+
body: "Please use state.renderer instead. state.gl is deprecated and will be removed in future versions.\n\nFor backwards compatibility, state.gl currently maps to state.renderer, but this may cause issues with libraries expecting WebGLRenderer.\n\nAccessed from:\n" + cleanedStack
|
|
2897
|
+
});
|
|
2898
|
+
}
|
|
2899
|
+
}
|
|
2900
|
+
return currentState.internal.actualRenderer;
|
|
2901
|
+
},
|
|
2902
|
+
set(value) {
|
|
2903
|
+
rootStore.getState().internal.actualRenderer = value;
|
|
2904
|
+
},
|
|
2905
|
+
enumerable: true,
|
|
2906
|
+
configurable: true
|
|
2907
|
+
});
|
|
2908
|
+
Object.defineProperty(state, "renderer", {
|
|
2909
|
+
get() {
|
|
2910
|
+
return rootStore.getState().internal.actualRenderer;
|
|
2911
|
+
},
|
|
2912
|
+
set(value) {
|
|
2913
|
+
rootStore.getState().internal.actualRenderer = value;
|
|
2914
|
+
},
|
|
2915
|
+
enumerable: true,
|
|
2916
|
+
configurable: true
|
|
2917
|
+
});
|
|
2918
|
+
let oldScene = state.scene;
|
|
2919
|
+
rootStore.subscribe(() => {
|
|
2920
|
+
const currentState = rootStore.getState();
|
|
2921
|
+
const { scene, rootScene, set } = currentState;
|
|
2922
|
+
if (scene !== oldScene) {
|
|
2923
|
+
oldScene = scene;
|
|
2924
|
+
if (scene?.isScene && scene !== rootScene) {
|
|
2925
|
+
set({ rootScene: scene });
|
|
2926
|
+
}
|
|
2927
|
+
}
|
|
2928
|
+
});
|
|
2929
|
+
let oldSize = state.size;
|
|
2930
|
+
let oldDpr = state.viewport.dpr;
|
|
2931
|
+
let oldCamera = state.camera;
|
|
2932
|
+
rootStore.subscribe(() => {
|
|
2933
|
+
const { camera, size, viewport, set, internal } = rootStore.getState();
|
|
2934
|
+
const actualRenderer = internal.actualRenderer;
|
|
2935
|
+
const canvasTarget = internal.canvasTarget;
|
|
2936
|
+
if (size.width !== oldSize.width || size.height !== oldSize.height || viewport.dpr !== oldDpr) {
|
|
2937
|
+
oldSize = size;
|
|
2938
|
+
oldDpr = viewport.dpr;
|
|
2939
|
+
updateCamera(camera, size);
|
|
2940
|
+
if (internal.isSecondary && canvasTarget) {
|
|
2941
|
+
if (viewport.dpr > 0) canvasTarget.setPixelRatio(viewport.dpr);
|
|
2942
|
+
canvasTarget.setSize(size.width, size.height, false);
|
|
2943
|
+
} else {
|
|
2944
|
+
if (viewport.dpr > 0) actualRenderer.setPixelRatio(viewport.dpr);
|
|
2945
|
+
actualRenderer.setSize(size.width, size.height, false);
|
|
2946
|
+
if (canvasTarget) {
|
|
2947
|
+
if (viewport.dpr > 0) canvasTarget.setPixelRatio(viewport.dpr);
|
|
2948
|
+
canvasTarget.setSize(size.width, size.height, false);
|
|
2949
|
+
}
|
|
2950
|
+
}
|
|
2951
|
+
}
|
|
2952
|
+
if (camera !== oldCamera) {
|
|
2953
|
+
oldCamera = camera;
|
|
2954
|
+
const { rootScene } = rootStore.getState();
|
|
2955
|
+
if (camera && rootScene && !camera.parent) {
|
|
2956
|
+
rootScene.add(camera);
|
|
2957
|
+
}
|
|
2958
|
+
set((state2) => ({ viewport: { ...state2.viewport, ...state2.viewport.getCurrentViewport(camera) } }));
|
|
2959
|
+
const currentState = rootStore.getState();
|
|
2960
|
+
if (currentState.autoUpdateFrustum && camera) {
|
|
2961
|
+
updateFrustum(camera, currentState.frustum);
|
|
2962
|
+
}
|
|
2963
|
+
}
|
|
2964
|
+
});
|
|
2965
|
+
rootStore.subscribe((state2) => invalidate(state2));
|
|
2966
|
+
return rootStore;
|
|
2967
|
+
};
|
|
2968
|
+
|
|
2969
|
+
const memoizedLoaders = /* @__PURE__ */ new WeakMap();
|
|
2970
|
+
const isConstructor$1 = (value) => typeof value === "function" && value?.prototype?.constructor === value;
|
|
2971
|
+
function getLoader(Proto) {
|
|
2972
|
+
if (isConstructor$1(Proto)) {
|
|
2973
|
+
let loader = memoizedLoaders.get(Proto);
|
|
2974
|
+
if (!loader) {
|
|
2975
|
+
loader = new Proto();
|
|
2976
|
+
memoizedLoaders.set(Proto, loader);
|
|
2977
|
+
}
|
|
2978
|
+
return loader;
|
|
2979
|
+
}
|
|
2980
|
+
return Proto;
|
|
2981
|
+
}
|
|
2982
|
+
function loadingFn(extensions, onProgress) {
|
|
2983
|
+
return function(Proto, input) {
|
|
2984
|
+
const loader = getLoader(Proto);
|
|
2985
|
+
if (extensions) extensions(loader);
|
|
2986
|
+
if ("loadAsync" in loader && typeof loader.loadAsync === "function") {
|
|
2987
|
+
return loader.loadAsync(input, onProgress).then((data) => {
|
|
2988
|
+
if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
|
|
2989
|
+
return data;
|
|
2990
|
+
});
|
|
2991
|
+
}
|
|
2992
|
+
return new Promise(
|
|
2993
|
+
(res, reject) => loader.load(
|
|
2994
|
+
input,
|
|
2995
|
+
(data) => {
|
|
2996
|
+
if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
|
|
2997
|
+
res(data);
|
|
2998
|
+
},
|
|
2999
|
+
onProgress,
|
|
3000
|
+
(error) => reject(new Error(`Could not load ${input}: ${error?.message}`))
|
|
3001
|
+
)
|
|
3002
|
+
);
|
|
3003
|
+
};
|
|
3004
|
+
}
|
|
3005
|
+
function useLoader(loader, input, extensions, onProgress) {
|
|
3006
|
+
const keys = Array.isArray(input) ? input : [input];
|
|
3007
|
+
const fn = loadingFn(extensions, onProgress);
|
|
3008
|
+
const results = keys.map((key) => suspendReact.suspend(fn, [loader, key], { equal: is.equ }));
|
|
3009
|
+
return Array.isArray(input) ? results : results[0];
|
|
3010
|
+
}
|
|
3011
|
+
useLoader.preload = function(loader, input, extensions, onProgress) {
|
|
3012
|
+
const keys = Array.isArray(input) ? input : [input];
|
|
3013
|
+
keys.forEach((key) => suspendReact.preload(loadingFn(extensions, onProgress), [loader, key]));
|
|
3014
|
+
};
|
|
3015
|
+
useLoader.clear = function(loader, input) {
|
|
3016
|
+
const keys = Array.isArray(input) ? input : [input];
|
|
3017
|
+
keys.forEach((key) => suspendReact.clear([loader, key]));
|
|
3018
|
+
};
|
|
3019
|
+
useLoader.loader = getLoader;
|
|
3020
|
+
|
|
3021
|
+
function useFrame(callback, priorityOrOptions) {
|
|
3022
|
+
const store = React__namespace.useContext(context);
|
|
3023
|
+
const isInsideCanvas = store !== null;
|
|
3024
|
+
const scheduler = getScheduler();
|
|
3025
|
+
const optionsKey = typeof priorityOrOptions === "number" ? `p:${priorityOrOptions}` : priorityOrOptions ? JSON.stringify({
|
|
3026
|
+
id: priorityOrOptions.id,
|
|
3027
|
+
phase: priorityOrOptions.phase,
|
|
3028
|
+
priority: priorityOrOptions.priority,
|
|
3029
|
+
fps: priorityOrOptions.fps,
|
|
3030
|
+
drop: priorityOrOptions.drop,
|
|
3031
|
+
enabled: priorityOrOptions.enabled,
|
|
3032
|
+
before: priorityOrOptions.before,
|
|
3033
|
+
after: priorityOrOptions.after
|
|
3034
|
+
}) : "";
|
|
3035
|
+
const options = React__namespace.useMemo(() => {
|
|
3036
|
+
return typeof priorityOrOptions === "number" ? { priority: priorityOrOptions } : priorityOrOptions ?? {};
|
|
3037
|
+
}, [optionsKey]);
|
|
3038
|
+
const reactId = React__namespace.useId();
|
|
3039
|
+
const id = options.id ?? reactId;
|
|
3040
|
+
const callbackRef = useMutableCallback(callback);
|
|
3041
|
+
const isLegacyPriority = typeof priorityOrOptions === "number" && priorityOrOptions > 0;
|
|
3042
|
+
useIsomorphicLayoutEffect(() => {
|
|
3043
|
+
if (!callback) return;
|
|
3044
|
+
if (isInsideCanvas) {
|
|
3045
|
+
const state = store.getState();
|
|
3046
|
+
const rootId = state.internal.rootId;
|
|
3047
|
+
if (isLegacyPriority) {
|
|
3048
|
+
state.internal.priority++;
|
|
3049
|
+
let parentRoot = state.previousRoot;
|
|
3050
|
+
while (parentRoot) {
|
|
2421
3051
|
const parentState = parentRoot.getState();
|
|
2422
3052
|
if (parentState?.internal) parentState.internal.priority++;
|
|
2423
3053
|
parentRoot = parentState?.previousRoot;
|
|
@@ -2567,6 +3197,9 @@ function useTexture(input, optionsOrOnLoad) {
|
|
|
2567
3197
|
const textureCache = useThree((state) => state.textures);
|
|
2568
3198
|
const options = typeof optionsOrOnLoad === "function" ? { onLoad: optionsOrOnLoad } : optionsOrOnLoad ?? {};
|
|
2569
3199
|
const { onLoad, cache = false } = options;
|
|
3200
|
+
const onLoadRef = React.useRef(onLoad);
|
|
3201
|
+
onLoadRef.current = onLoad;
|
|
3202
|
+
const onLoadCalledForRef = React.useRef(null);
|
|
2570
3203
|
const urls = React.useMemo(() => getUrls(input), [input]);
|
|
2571
3204
|
const cachedResult = React.useMemo(() => {
|
|
2572
3205
|
if (!cache) return null;
|
|
@@ -2577,9 +3210,13 @@ function useTexture(input, optionsOrOnLoad) {
|
|
|
2577
3210
|
webgpu.TextureLoader,
|
|
2578
3211
|
IsObject(input) ? Object.values(input) : input
|
|
2579
3212
|
);
|
|
3213
|
+
const inputKey = urls.join("\0");
|
|
2580
3214
|
React.useLayoutEffect(() => {
|
|
2581
|
-
if (
|
|
2582
|
-
|
|
3215
|
+
if (cachedResult) return;
|
|
3216
|
+
if (onLoadCalledForRef.current === inputKey) return;
|
|
3217
|
+
onLoadCalledForRef.current = inputKey;
|
|
3218
|
+
onLoadRef.current?.(loadedTextures);
|
|
3219
|
+
}, [cachedResult, loadedTextures, inputKey]);
|
|
2583
3220
|
React.useEffect(() => {
|
|
2584
3221
|
if (cachedResult) return;
|
|
2585
3222
|
if ("initTexture" in renderer) {
|
|
@@ -2746,14 +3383,31 @@ function useTextures() {
|
|
|
2746
3383
|
}, [store]);
|
|
2747
3384
|
}
|
|
2748
3385
|
|
|
2749
|
-
function useRenderTarget(
|
|
3386
|
+
function useRenderTarget(widthOrOptions, heightOrOptions, options) {
|
|
2750
3387
|
const isLegacy = useThree((s) => s.isLegacy);
|
|
2751
3388
|
const size = useThree((s) => s.size);
|
|
3389
|
+
let width;
|
|
3390
|
+
let height;
|
|
3391
|
+
let opts;
|
|
3392
|
+
if (typeof widthOrOptions === "object") {
|
|
3393
|
+
opts = widthOrOptions;
|
|
3394
|
+
} else if (typeof widthOrOptions === "number") {
|
|
3395
|
+
width = widthOrOptions;
|
|
3396
|
+
if (typeof heightOrOptions === "object") {
|
|
3397
|
+
height = widthOrOptions;
|
|
3398
|
+
opts = heightOrOptions;
|
|
3399
|
+
} else if (typeof heightOrOptions === "number") {
|
|
3400
|
+
height = heightOrOptions;
|
|
3401
|
+
opts = options;
|
|
3402
|
+
} else {
|
|
3403
|
+
height = widthOrOptions;
|
|
3404
|
+
}
|
|
3405
|
+
}
|
|
2752
3406
|
return React.useMemo(() => {
|
|
2753
3407
|
const w = width ?? size.width;
|
|
2754
3408
|
const h = height ?? size.height;
|
|
2755
|
-
return new webgpu.RenderTarget(w, h,
|
|
2756
|
-
}, [width, height, size.width, size.height,
|
|
3409
|
+
return new webgpu.RenderTarget(w, h, opts);
|
|
3410
|
+
}, [width, height, size.width, size.height, opts, isLegacy]);
|
|
2757
3411
|
}
|
|
2758
3412
|
|
|
2759
3413
|
function useStore() {
|
|
@@ -2803,7 +3457,7 @@ function addTail(callback) {
|
|
|
2803
3457
|
function invalidate(state, frames = 1, stackFrames = false) {
|
|
2804
3458
|
getScheduler().invalidate(frames, stackFrames);
|
|
2805
3459
|
}
|
|
2806
|
-
function advance(timestamp
|
|
3460
|
+
function advance(timestamp) {
|
|
2807
3461
|
getScheduler().step(timestamp);
|
|
2808
3462
|
}
|
|
2809
3463
|
|
|
@@ -14257,6 +14911,7 @@ function swapInstances() {
|
|
|
14257
14911
|
instance.object = instance.props.object ?? new target(...instance.props.args ?? []);
|
|
14258
14912
|
instance.object.__r3f = instance;
|
|
14259
14913
|
setFiberRef(fiber, instance.object);
|
|
14914
|
+
delete instance.appliedOnce;
|
|
14260
14915
|
applyProps(instance.object, instance.props);
|
|
14261
14916
|
if (instance.props.attach) {
|
|
14262
14917
|
attach(parent, instance);
|
|
@@ -14330,8 +14985,22 @@ const reconciler = /* @__PURE__ */ createReconciler({
|
|
|
14330
14985
|
const isTailSibling = fiber.sibling === null || (fiber.flags & Update) === NoFlags;
|
|
14331
14986
|
if (isTailSibling) swapInstances();
|
|
14332
14987
|
},
|
|
14333
|
-
finalizeInitialChildren: () =>
|
|
14334
|
-
|
|
14988
|
+
finalizeInitialChildren: (instance) => {
|
|
14989
|
+
for (const prop in instance.props) {
|
|
14990
|
+
if (isFromRef(instance.props[prop])) return true;
|
|
14991
|
+
}
|
|
14992
|
+
return false;
|
|
14993
|
+
},
|
|
14994
|
+
commitMount(instance) {
|
|
14995
|
+
const resolved = {};
|
|
14996
|
+
for (const prop in instance.props) {
|
|
14997
|
+
const value = instance.props[prop];
|
|
14998
|
+
if (isFromRef(value)) {
|
|
14999
|
+
const ref = value[FROM_REF];
|
|
15000
|
+
if (ref.current != null) resolved[prop] = ref.current;
|
|
15001
|
+
}
|
|
15002
|
+
}
|
|
15003
|
+
if (Object.keys(resolved).length) applyProps(instance.object, resolved);
|
|
14335
15004
|
},
|
|
14336
15005
|
getPublicInstance: (instance) => instance?.object,
|
|
14337
15006
|
prepareForCommit: () => null,
|
|
@@ -14552,6 +15221,9 @@ function createRoot(canvas) {
|
|
|
14552
15221
|
let resolve;
|
|
14553
15222
|
pending = new Promise((_resolve) => resolve = _resolve);
|
|
14554
15223
|
const {
|
|
15224
|
+
id: canvasId,
|
|
15225
|
+
primaryCanvas,
|
|
15226
|
+
scheduler: schedulerConfig,
|
|
14555
15227
|
gl: glConfig,
|
|
14556
15228
|
renderer: rendererConfig,
|
|
14557
15229
|
size: propsSize,
|
|
@@ -14559,10 +15231,6 @@ function createRoot(canvas) {
|
|
|
14559
15231
|
events,
|
|
14560
15232
|
onCreated: onCreatedCallback,
|
|
14561
15233
|
shadows = false,
|
|
14562
|
-
linear = false,
|
|
14563
|
-
flat = false,
|
|
14564
|
-
textureColorSpace = webgpu.SRGBColorSpace,
|
|
14565
|
-
legacy = false,
|
|
14566
15234
|
orthographic = false,
|
|
14567
15235
|
frameloop = "always",
|
|
14568
15236
|
dpr = [1, 2],
|
|
@@ -14574,11 +15242,14 @@ function createRoot(canvas) {
|
|
|
14574
15242
|
onDropMissed,
|
|
14575
15243
|
autoUpdateFrustum = true,
|
|
14576
15244
|
occlusion = false,
|
|
14577
|
-
_sizeProps
|
|
15245
|
+
_sizeProps,
|
|
15246
|
+
forceEven
|
|
14578
15247
|
} = props;
|
|
15248
|
+
const textureColorSpace = is.obj(glConfig) && !is.fun(glConfig) && !isRenderer(glConfig) && glConfig.textureColorSpace || is.obj(rendererConfig) && !is.fun(rendererConfig) && !isRenderer(rendererConfig) && rendererConfig.textureColorSpace || webgpu.SRGBColorSpace;
|
|
14579
15249
|
const state = store.getState();
|
|
14580
15250
|
const defaultGPUProps = {
|
|
14581
|
-
canvas
|
|
15251
|
+
canvas,
|
|
15252
|
+
antialias: true
|
|
14582
15253
|
};
|
|
14583
15254
|
if (glConfig && !R3F_BUILD_LEGACY) {
|
|
14584
15255
|
throw new Error(
|
|
@@ -14589,15 +15260,52 @@ function createRoot(canvas) {
|
|
|
14589
15260
|
throw new Error("Cannot use both gl and renderer props at the same time");
|
|
14590
15261
|
}
|
|
14591
15262
|
let renderer = state.internal.actualRenderer;
|
|
14592
|
-
if (!state.internal.actualRenderer) {
|
|
15263
|
+
if (primaryCanvas && !state.internal.actualRenderer) {
|
|
15264
|
+
const primary = await waitForPrimary(primaryCanvas);
|
|
15265
|
+
renderer = primary.renderer;
|
|
15266
|
+
state.internal.actualRenderer = renderer;
|
|
15267
|
+
const canvasTarget = new webgpu.CanvasTarget(canvas);
|
|
15268
|
+
primary.store.setState((prev) => ({
|
|
15269
|
+
internal: { ...prev.internal, isMultiCanvas: true }
|
|
15270
|
+
}));
|
|
15271
|
+
state.set((prev) => ({
|
|
15272
|
+
webGPUSupported: primary.store.getState().webGPUSupported,
|
|
15273
|
+
renderer,
|
|
15274
|
+
primaryStore: primary.store,
|
|
15275
|
+
internal: {
|
|
15276
|
+
...prev.internal,
|
|
15277
|
+
canvasTarget,
|
|
15278
|
+
isMultiCanvas: true,
|
|
15279
|
+
isSecondary: true,
|
|
15280
|
+
targetId: primaryCanvas
|
|
15281
|
+
}
|
|
15282
|
+
}));
|
|
15283
|
+
} else if (!state.internal.actualRenderer) {
|
|
14593
15284
|
renderer = await resolveRenderer(rendererConfig, defaultGPUProps, webgpu.WebGPURenderer);
|
|
14594
15285
|
if (!renderer.hasInitialized?.()) {
|
|
15286
|
+
const size2 = computeInitialSize(canvas, propsSize);
|
|
15287
|
+
if (size2.width > 0 && size2.height > 0) {
|
|
15288
|
+
const pixelRatio = calculateDpr(dpr);
|
|
15289
|
+
canvas.width = size2.width * pixelRatio;
|
|
15290
|
+
canvas.height = size2.height * pixelRatio;
|
|
15291
|
+
}
|
|
14595
15292
|
await renderer.init();
|
|
14596
15293
|
}
|
|
14597
15294
|
const backend = renderer.backend;
|
|
14598
15295
|
const isWebGPUBackend = backend && "isWebGPUBackend" in backend;
|
|
14599
15296
|
state.internal.actualRenderer = renderer;
|
|
14600
|
-
state.set({ webGPUSupported: isWebGPUBackend, renderer });
|
|
15297
|
+
state.set({ webGPUSupported: isWebGPUBackend, renderer, primaryStore: store });
|
|
15298
|
+
if (canvasId && !state.internal.isSecondary) {
|
|
15299
|
+
const canvasTarget = new webgpu.CanvasTarget(canvas);
|
|
15300
|
+
const unregisterPrimary = registerPrimary(canvasId, renderer, store);
|
|
15301
|
+
state.set((prev) => ({
|
|
15302
|
+
internal: {
|
|
15303
|
+
...prev.internal,
|
|
15304
|
+
canvasTarget,
|
|
15305
|
+
unregisterPrimary
|
|
15306
|
+
}
|
|
15307
|
+
}));
|
|
15308
|
+
}
|
|
14601
15309
|
}
|
|
14602
15310
|
let raycaster = state.raycaster;
|
|
14603
15311
|
if (!raycaster) state.set({ raycaster: raycaster = new webgpu.Raycaster() });
|
|
@@ -14606,6 +15314,7 @@ function createRoot(canvas) {
|
|
|
14606
15314
|
if (!is.equ(params, raycaster.params, shallowLoose)) {
|
|
14607
15315
|
applyProps(raycaster, { params: { ...raycaster.params, ...params } });
|
|
14608
15316
|
}
|
|
15317
|
+
let tempCamera = state.camera;
|
|
14609
15318
|
if (!state.camera || state.camera === lastCamera && !is.equ(lastCamera, cameraOptions, shallowLoose)) {
|
|
14610
15319
|
lastCamera = cameraOptions;
|
|
14611
15320
|
const isCamera = cameraOptions?.isCamera;
|
|
@@ -14625,6 +15334,7 @@ function createRoot(canvas) {
|
|
|
14625
15334
|
if (!state.camera && !cameraOptions?.rotation) camera.lookAt(0, 0, 0);
|
|
14626
15335
|
}
|
|
14627
15336
|
state.set({ camera });
|
|
15337
|
+
tempCamera = camera;
|
|
14628
15338
|
raycaster.camera = camera;
|
|
14629
15339
|
}
|
|
14630
15340
|
if (!state.scene) {
|
|
@@ -14642,7 +15352,7 @@ function createRoot(canvas) {
|
|
|
14642
15352
|
rootScene: scene,
|
|
14643
15353
|
internal: { ...prev.internal, container: scene }
|
|
14644
15354
|
}));
|
|
14645
|
-
const camera =
|
|
15355
|
+
const camera = tempCamera;
|
|
14646
15356
|
if (camera && !camera.parent) scene.add(camera);
|
|
14647
15357
|
}
|
|
14648
15358
|
if (events && !state.events.handlers) {
|
|
@@ -14659,6 +15369,9 @@ function createRoot(canvas) {
|
|
|
14659
15369
|
if (_sizeProps !== void 0) {
|
|
14660
15370
|
state.set({ _sizeProps });
|
|
14661
15371
|
}
|
|
15372
|
+
if (forceEven !== void 0 && state.internal.forceEven !== forceEven) {
|
|
15373
|
+
state.set((prev) => ({ internal: { ...prev.internal, forceEven } }));
|
|
15374
|
+
}
|
|
14662
15375
|
const size = computeInitialSize(canvas, propsSize);
|
|
14663
15376
|
if (!state._sizeImperative && !is.equ(size, state.size, shallowLoose)) {
|
|
14664
15377
|
const wasImperative = state._sizeImperative;
|
|
@@ -14685,10 +15398,10 @@ function createRoot(canvas) {
|
|
|
14685
15398
|
lastConfiguredProps.performance = performance;
|
|
14686
15399
|
}
|
|
14687
15400
|
if (!state.xr) {
|
|
14688
|
-
const handleXRFrame = (timestamp,
|
|
15401
|
+
const handleXRFrame = (timestamp, _frame) => {
|
|
14689
15402
|
const state2 = store.getState();
|
|
14690
15403
|
if (state2.frameloop === "never") return;
|
|
14691
|
-
advance(timestamp
|
|
15404
|
+
advance(timestamp);
|
|
14692
15405
|
};
|
|
14693
15406
|
const actualRenderer = state.internal.actualRenderer;
|
|
14694
15407
|
const handleSessionChange = () => {
|
|
@@ -14700,16 +15413,16 @@ function createRoot(canvas) {
|
|
|
14700
15413
|
};
|
|
14701
15414
|
const xr = {
|
|
14702
15415
|
connect() {
|
|
14703
|
-
const { gl, renderer: renderer2
|
|
14704
|
-
const
|
|
14705
|
-
|
|
14706
|
-
|
|
15416
|
+
const { gl, renderer: renderer2 } = store.getState();
|
|
15417
|
+
const xrManager = (renderer2 || gl).xr;
|
|
15418
|
+
xrManager.addEventListener("sessionstart", handleSessionChange);
|
|
15419
|
+
xrManager.addEventListener("sessionend", handleSessionChange);
|
|
14707
15420
|
},
|
|
14708
15421
|
disconnect() {
|
|
14709
|
-
const { gl, renderer: renderer2
|
|
14710
|
-
const
|
|
14711
|
-
|
|
14712
|
-
|
|
15422
|
+
const { gl, renderer: renderer2 } = store.getState();
|
|
15423
|
+
const xrManager = (renderer2 || gl).xr;
|
|
15424
|
+
xrManager.removeEventListener("sessionstart", handleSessionChange);
|
|
15425
|
+
xrManager.removeEventListener("sessionend", handleSessionChange);
|
|
14713
15426
|
}
|
|
14714
15427
|
};
|
|
14715
15428
|
if (typeof renderer.xr?.addEventListener === "function") xr.connect();
|
|
@@ -14721,15 +15434,22 @@ function createRoot(canvas) {
|
|
|
14721
15434
|
const oldType = renderer.shadowMap.type;
|
|
14722
15435
|
renderer.shadowMap.enabled = !!shadows;
|
|
14723
15436
|
if (is.boo(shadows)) {
|
|
14724
|
-
renderer.shadowMap.type = webgpu.
|
|
15437
|
+
renderer.shadowMap.type = webgpu.PCFShadowMap;
|
|
14725
15438
|
} else if (is.str(shadows)) {
|
|
15439
|
+
if (shadows === "soft") {
|
|
15440
|
+
notifyDepreciated({
|
|
15441
|
+
heading: 'shadows="soft" is deprecated',
|
|
15442
|
+
body: "Three has depreciated soft and improved basic PCFShadows, we converted for you.",
|
|
15443
|
+
link: "https://github.com/mrdoob/three.js/wiki/Migration-Guide?utm_source=chatgpt.com#181--182"
|
|
15444
|
+
});
|
|
15445
|
+
}
|
|
14726
15446
|
const types = {
|
|
14727
15447
|
basic: webgpu.BasicShadowMap,
|
|
14728
15448
|
percentage: webgpu.PCFShadowMap,
|
|
14729
|
-
soft: webgpu.
|
|
15449
|
+
soft: webgpu.PCFShadowMap,
|
|
14730
15450
|
variance: webgpu.VSMShadowMap
|
|
14731
15451
|
};
|
|
14732
|
-
renderer.shadowMap.type = types[shadows] ?? webgpu.
|
|
15452
|
+
renderer.shadowMap.type = types[shadows] ?? webgpu.PCFShadowMap;
|
|
14733
15453
|
} else if (is.obj(shadows)) {
|
|
14734
15454
|
Object.assign(renderer.shadowMap, shadows);
|
|
14735
15455
|
}
|
|
@@ -14737,27 +15457,69 @@ function createRoot(canvas) {
|
|
|
14737
15457
|
renderer.shadowMap.needsUpdate = true;
|
|
14738
15458
|
}
|
|
14739
15459
|
}
|
|
15460
|
+
if (!configured) {
|
|
15461
|
+
renderer.outputColorSpace = webgpu.SRGBColorSpace;
|
|
15462
|
+
renderer.toneMapping = webgpu.ACESFilmicToneMapping;
|
|
15463
|
+
}
|
|
14740
15464
|
if (textureColorSpace !== lastConfiguredProps.textureColorSpace) {
|
|
14741
15465
|
if (state.textureColorSpace !== textureColorSpace) state.set(() => ({ textureColorSpace }));
|
|
14742
15466
|
lastConfiguredProps.textureColorSpace = textureColorSpace;
|
|
14743
15467
|
}
|
|
15468
|
+
const r3fProps = ["textureColorSpace"];
|
|
15469
|
+
const constructorOnlyProps = ["samples", "antialias", "alpha", "canvas", "powerPreference"];
|
|
15470
|
+
const nonApplyProps = [...r3fProps, ...constructorOnlyProps];
|
|
14744
15471
|
if (glConfig && !is.fun(glConfig) && !isRenderer(glConfig) && !is.equ(glConfig, renderer, shallowLoose)) {
|
|
14745
|
-
|
|
15472
|
+
const glProps = {};
|
|
15473
|
+
for (const key in glConfig) {
|
|
15474
|
+
if (!nonApplyProps.includes(key)) glProps[key] = glConfig[key];
|
|
15475
|
+
}
|
|
15476
|
+
applyProps(renderer, glProps);
|
|
14746
15477
|
}
|
|
14747
15478
|
if (rendererConfig && !is.fun(rendererConfig) && !isRenderer(rendererConfig) && state.renderer) {
|
|
14748
15479
|
const currentRenderer = state.renderer;
|
|
14749
15480
|
if (!is.equ(rendererConfig, currentRenderer, shallowLoose)) {
|
|
14750
|
-
|
|
15481
|
+
const rendererProps = {};
|
|
15482
|
+
for (const key in rendererConfig) {
|
|
15483
|
+
if (!nonApplyProps.includes(key)) rendererProps[key] = rendererConfig[key];
|
|
15484
|
+
}
|
|
15485
|
+
applyProps(currentRenderer, rendererProps);
|
|
14751
15486
|
}
|
|
14752
15487
|
}
|
|
14753
15488
|
const scheduler = getScheduler();
|
|
14754
15489
|
const rootId = state.internal.rootId;
|
|
14755
15490
|
if (!rootId) {
|
|
14756
|
-
const newRootId = scheduler.generateRootId();
|
|
15491
|
+
const newRootId = canvasId || scheduler.generateRootId();
|
|
14757
15492
|
const unregisterRoot = scheduler.registerRoot(newRootId, {
|
|
14758
15493
|
getState: () => store.getState(),
|
|
14759
15494
|
onError: (err) => store.getState().setError(err)
|
|
14760
15495
|
});
|
|
15496
|
+
const unregisterCanvasTarget = scheduler.register(
|
|
15497
|
+
() => {
|
|
15498
|
+
const state2 = store.getState();
|
|
15499
|
+
if (state2.internal.isMultiCanvas && state2.internal.canvasTarget) {
|
|
15500
|
+
const renderer2 = state2.internal.actualRenderer;
|
|
15501
|
+
renderer2.setCanvasTarget(state2.internal.canvasTarget);
|
|
15502
|
+
}
|
|
15503
|
+
},
|
|
15504
|
+
{
|
|
15505
|
+
id: `${newRootId}_canvasTarget`,
|
|
15506
|
+
rootId: newRootId,
|
|
15507
|
+
phase: "start",
|
|
15508
|
+
system: true
|
|
15509
|
+
}
|
|
15510
|
+
);
|
|
15511
|
+
const unregisterEventsFlush = scheduler.register(
|
|
15512
|
+
() => {
|
|
15513
|
+
const state2 = store.getState();
|
|
15514
|
+
state2.events.flush?.();
|
|
15515
|
+
},
|
|
15516
|
+
{
|
|
15517
|
+
id: `${newRootId}_events`,
|
|
15518
|
+
rootId: newRootId,
|
|
15519
|
+
phase: "input",
|
|
15520
|
+
system: true
|
|
15521
|
+
}
|
|
15522
|
+
);
|
|
14761
15523
|
const unregisterFrustum = scheduler.register(
|
|
14762
15524
|
() => {
|
|
14763
15525
|
const state2 = store.getState();
|
|
@@ -14792,18 +15554,22 @@ function createRoot(canvas) {
|
|
|
14792
15554
|
const userHandlesRender = scheduler.hasUserJobsInPhase("render", newRootId);
|
|
14793
15555
|
if (userHandlesRender || state2.internal.priority) return;
|
|
14794
15556
|
try {
|
|
14795
|
-
if (state2.
|
|
15557
|
+
if (state2.renderPipeline?.render) state2.renderPipeline.render();
|
|
14796
15558
|
else if (renderer2?.render) renderer2.render(state2.scene, state2.camera);
|
|
14797
15559
|
} catch (error) {
|
|
14798
15560
|
state2.setError(error instanceof Error ? error : new Error(String(error)));
|
|
14799
15561
|
}
|
|
14800
15562
|
},
|
|
14801
15563
|
{
|
|
14802
|
-
|
|
15564
|
+
// Use canvas ID directly as job ID if available, otherwise use generated rootId
|
|
15565
|
+
id: canvasId || `${newRootId}_render`,
|
|
14803
15566
|
rootId: newRootId,
|
|
14804
15567
|
phase: "render",
|
|
14805
|
-
system: true
|
|
15568
|
+
system: true,
|
|
14806
15569
|
// Internal flag: this is a system job, not user-controlled
|
|
15570
|
+
// Apply scheduler config for render ordering and rate limiting
|
|
15571
|
+
...schedulerConfig?.after && { after: schedulerConfig.after },
|
|
15572
|
+
...schedulerConfig?.fps && { fps: schedulerConfig.fps }
|
|
14807
15573
|
}
|
|
14808
15574
|
);
|
|
14809
15575
|
state.set((state2) => ({
|
|
@@ -14812,6 +15578,8 @@ function createRoot(canvas) {
|
|
|
14812
15578
|
rootId: newRootId,
|
|
14813
15579
|
unregisterRoot: () => {
|
|
14814
15580
|
unregisterRoot();
|
|
15581
|
+
unregisterCanvasTarget();
|
|
15582
|
+
unregisterEventsFlush();
|
|
14815
15583
|
unregisterFrustum();
|
|
14816
15584
|
unregisterVisibility();
|
|
14817
15585
|
unregisterRender();
|
|
@@ -14870,15 +15638,24 @@ function unmountComponentAtNode(canvas, callback) {
|
|
|
14870
15638
|
const renderer = state.internal.actualRenderer;
|
|
14871
15639
|
const unregisterRoot = state.internal.unregisterRoot;
|
|
14872
15640
|
if (unregisterRoot) unregisterRoot();
|
|
15641
|
+
const unregisterPrimary = state.internal.unregisterPrimary;
|
|
15642
|
+
if (unregisterPrimary) unregisterPrimary();
|
|
15643
|
+
const canvasTarget = state.internal.canvasTarget;
|
|
15644
|
+
if (canvasTarget?.dispose) canvasTarget.dispose();
|
|
14873
15645
|
state.events.disconnect?.();
|
|
14874
15646
|
cleanupHelperGroup(root.store);
|
|
14875
|
-
renderer
|
|
14876
|
-
|
|
14877
|
-
|
|
15647
|
+
if (state.isLegacy && renderer) {
|
|
15648
|
+
;
|
|
15649
|
+
renderer.renderLists?.dispose?.();
|
|
15650
|
+
renderer.forceContextLoss?.();
|
|
15651
|
+
}
|
|
15652
|
+
if (!state.internal.isSecondary) {
|
|
15653
|
+
if (renderer?.xr) state.xr.disconnect();
|
|
15654
|
+
}
|
|
14878
15655
|
dispose(state.scene);
|
|
14879
15656
|
_roots.delete(canvas);
|
|
14880
15657
|
if (callback) callback(canvas);
|
|
14881
|
-
} catch
|
|
15658
|
+
} catch {
|
|
14882
15659
|
}
|
|
14883
15660
|
}, 500);
|
|
14884
15661
|
}
|
|
@@ -14886,36 +15663,34 @@ function unmountComponentAtNode(canvas, callback) {
|
|
|
14886
15663
|
}
|
|
14887
15664
|
}
|
|
14888
15665
|
function createPortal(children, container, state) {
|
|
14889
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
15666
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Portal, { children, container, state });
|
|
14890
15667
|
}
|
|
14891
|
-
function
|
|
15668
|
+
function Portal({ children, container, state }) {
|
|
14892
15669
|
const isRef = React.useCallback((obj) => obj && "current" in obj, []);
|
|
14893
|
-
const [resolvedContainer,
|
|
15670
|
+
const [resolvedContainer, _setResolvedContainer] = React.useState(() => {
|
|
14894
15671
|
if (isRef(container)) return container.current ?? null;
|
|
14895
15672
|
return container;
|
|
14896
15673
|
});
|
|
15674
|
+
const setResolvedContainer = React.useCallback(
|
|
15675
|
+
(newContainer) => {
|
|
15676
|
+
if (!newContainer || newContainer === resolvedContainer) return;
|
|
15677
|
+
_setResolvedContainer(isRef(newContainer) ? newContainer.current : newContainer);
|
|
15678
|
+
},
|
|
15679
|
+
[resolvedContainer, _setResolvedContainer, isRef]
|
|
15680
|
+
);
|
|
14897
15681
|
React.useMemo(() => {
|
|
14898
|
-
if (isRef(container)) {
|
|
14899
|
-
|
|
14900
|
-
|
|
14901
|
-
|
|
14902
|
-
const updated = container.current;
|
|
14903
|
-
if (updated && updated !== resolvedContainer) {
|
|
14904
|
-
setResolvedContainer(updated);
|
|
14905
|
-
}
|
|
14906
|
-
});
|
|
14907
|
-
} else if (current !== resolvedContainer) {
|
|
14908
|
-
setResolvedContainer(current);
|
|
14909
|
-
}
|
|
14910
|
-
} else if (container !== resolvedContainer) {
|
|
14911
|
-
setResolvedContainer(container);
|
|
15682
|
+
if (isRef(container) && !container.current) {
|
|
15683
|
+
return queueMicrotask(() => {
|
|
15684
|
+
setResolvedContainer(container.current);
|
|
15685
|
+
});
|
|
14912
15686
|
}
|
|
14913
|
-
|
|
15687
|
+
setResolvedContainer(container);
|
|
15688
|
+
}, [container, isRef, setResolvedContainer]);
|
|
14914
15689
|
if (!resolvedContainer) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, {});
|
|
14915
15690
|
const portalKey = resolvedContainer.uuid ?? `portal-${resolvedContainer.id ?? "unknown"}`;
|
|
14916
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
15691
|
+
return /* @__PURE__ */ jsxRuntime.jsx(PortalInner, { children, container: resolvedContainer, state }, portalKey);
|
|
14917
15692
|
}
|
|
14918
|
-
function
|
|
15693
|
+
function PortalInner({ state = {}, children, container }) {
|
|
14919
15694
|
const { events, size, injectScene = true, ...rest } = state;
|
|
14920
15695
|
const previousRoot = useStore();
|
|
14921
15696
|
const [raycaster] = React.useState(() => new webgpu.Raycaster());
|
|
@@ -14936,11 +15711,12 @@ function Portal({ state = {}, children, container }) {
|
|
|
14936
15711
|
};
|
|
14937
15712
|
}, [portalScene, container, injectScene]);
|
|
14938
15713
|
const inject = useMutableCallback((rootState, injectState) => {
|
|
15714
|
+
const resolvedSize = { ...rootState.size, ...injectState.size, ...size };
|
|
14939
15715
|
let viewport = void 0;
|
|
14940
|
-
if (injectState.camera && size) {
|
|
15716
|
+
if (injectState.camera && (size || injectState.size)) {
|
|
14941
15717
|
const camera = injectState.camera;
|
|
14942
|
-
viewport = rootState.viewport.getCurrentViewport(camera, new webgpu.Vector3(),
|
|
14943
|
-
if (camera !== rootState.camera) updateCamera(camera,
|
|
15718
|
+
viewport = rootState.viewport.getCurrentViewport(camera, new webgpu.Vector3(), resolvedSize);
|
|
15719
|
+
if (camera !== rootState.camera) updateCamera(camera, resolvedSize);
|
|
14944
15720
|
}
|
|
14945
15721
|
return {
|
|
14946
15722
|
// The intersect consists of the previous root state
|
|
@@ -14957,7 +15733,7 @@ function Portal({ state = {}, children, container }) {
|
|
|
14957
15733
|
previousRoot,
|
|
14958
15734
|
// Events, size and viewport can be overridden by the inject layer
|
|
14959
15735
|
events: { ...rootState.events, ...injectState.events, ...events },
|
|
14960
|
-
size:
|
|
15736
|
+
size: resolvedSize,
|
|
14961
15737
|
viewport: { ...rootState.viewport, ...viewport },
|
|
14962
15738
|
// Layers are allowed to override events
|
|
14963
15739
|
setEvents: (events2) => injectState.set((state2) => ({ ...state2, events: { ...state2.events, ...events2 } })),
|
|
@@ -14969,9 +15745,13 @@ function Portal({ state = {}, children, container }) {
|
|
|
14969
15745
|
const store = traditional.createWithEqualityFn((set, get) => ({ ...rest, set, get }));
|
|
14970
15746
|
const onMutate = (prev) => store.setState((state2) => inject.current(prev, state2));
|
|
14971
15747
|
onMutate(previousRoot.getState());
|
|
14972
|
-
previousRoot.subscribe(onMutate);
|
|
14973
15748
|
return store;
|
|
14974
15749
|
}, [previousRoot, container]);
|
|
15750
|
+
useIsomorphicLayoutEffect(() => {
|
|
15751
|
+
const onMutate = (prev) => usePortalStore.setState((state2) => inject.current(prev, state2));
|
|
15752
|
+
const unsubscribe = previousRoot.subscribe(onMutate);
|
|
15753
|
+
return unsubscribe;
|
|
15754
|
+
}, [previousRoot, usePortalStore]);
|
|
14975
15755
|
return (
|
|
14976
15756
|
// @ts-ignore, reconciler types are not maintained
|
|
14977
15757
|
/* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: reconciler.createPortal(
|
|
@@ -14991,15 +15771,13 @@ function CanvasImpl({
|
|
|
14991
15771
|
fallback,
|
|
14992
15772
|
resize,
|
|
14993
15773
|
style,
|
|
15774
|
+
id,
|
|
14994
15775
|
gl,
|
|
14995
|
-
renderer,
|
|
15776
|
+
renderer: rendererProp,
|
|
14996
15777
|
events = createPointerEvents,
|
|
14997
15778
|
eventSource,
|
|
14998
15779
|
eventPrefix,
|
|
14999
15780
|
shadows,
|
|
15000
|
-
linear,
|
|
15001
|
-
flat,
|
|
15002
|
-
legacy,
|
|
15003
15781
|
orthographic,
|
|
15004
15782
|
frameloop,
|
|
15005
15783
|
dpr,
|
|
@@ -15014,10 +15792,53 @@ function CanvasImpl({
|
|
|
15014
15792
|
hmr,
|
|
15015
15793
|
width,
|
|
15016
15794
|
height,
|
|
15795
|
+
background,
|
|
15796
|
+
forceEven,
|
|
15017
15797
|
...props
|
|
15018
15798
|
}) {
|
|
15799
|
+
const isRendererConfig = typeof rendererProp === "object" && rendererProp !== null && !("render" in rendererProp) && ("primaryCanvas" in rendererProp || "scheduler" in rendererProp);
|
|
15800
|
+
let primaryCanvas;
|
|
15801
|
+
let scheduler;
|
|
15802
|
+
let renderer;
|
|
15803
|
+
if (isRendererConfig) {
|
|
15804
|
+
const { primaryCanvas: pc, scheduler: sc, ...rest } = rendererProp;
|
|
15805
|
+
primaryCanvas = pc;
|
|
15806
|
+
scheduler = sc;
|
|
15807
|
+
renderer = Object.keys(rest).length > 0 ? rest : rendererProp;
|
|
15808
|
+
} else {
|
|
15809
|
+
renderer = rendererProp;
|
|
15810
|
+
}
|
|
15019
15811
|
React__namespace.useMemo(() => extend(THREE), []);
|
|
15020
15812
|
const Bridge = useBridge();
|
|
15813
|
+
const backgroundProps = React__namespace.useMemo(() => {
|
|
15814
|
+
if (!background) return null;
|
|
15815
|
+
if (typeof background === "object" && !background.isColor) {
|
|
15816
|
+
const { backgroundMap, envMap, files, preset, ...rest } = background;
|
|
15817
|
+
return {
|
|
15818
|
+
...rest,
|
|
15819
|
+
preset,
|
|
15820
|
+
files: envMap || files,
|
|
15821
|
+
backgroundFiles: backgroundMap,
|
|
15822
|
+
background: true
|
|
15823
|
+
};
|
|
15824
|
+
}
|
|
15825
|
+
if (typeof background === "number") {
|
|
15826
|
+
return { color: background, background: true };
|
|
15827
|
+
}
|
|
15828
|
+
if (typeof background === "string") {
|
|
15829
|
+
if (background in presetsObj) {
|
|
15830
|
+
return { preset: background, background: true };
|
|
15831
|
+
}
|
|
15832
|
+
if (/^(https?:\/\/|\/|\.\/|\.\.\/)|\\.(hdr|exr|jpg|jpeg|png|webp|gif)$/i.test(background)) {
|
|
15833
|
+
return { files: background, background: true };
|
|
15834
|
+
}
|
|
15835
|
+
return { color: background, background: true };
|
|
15836
|
+
}
|
|
15837
|
+
if (background.isColor) {
|
|
15838
|
+
return { color: background, background: true };
|
|
15839
|
+
}
|
|
15840
|
+
return null;
|
|
15841
|
+
}, [background]);
|
|
15021
15842
|
const hasInitialSizeRef = React__namespace.useRef(false);
|
|
15022
15843
|
const measureConfig = React__namespace.useMemo(() => {
|
|
15023
15844
|
if (!hasInitialSizeRef.current) {
|
|
@@ -15034,15 +15855,20 @@ function CanvasImpl({
|
|
|
15034
15855
|
};
|
|
15035
15856
|
}, [resize, hasInitialSizeRef.current]);
|
|
15036
15857
|
const [containerRef, containerRect] = useMeasure__default(measureConfig);
|
|
15037
|
-
const effectiveSize = React__namespace.useMemo(
|
|
15038
|
-
|
|
15039
|
-
|
|
15040
|
-
|
|
15858
|
+
const effectiveSize = React__namespace.useMemo(() => {
|
|
15859
|
+
let w = width ?? containerRect.width;
|
|
15860
|
+
let h = height ?? containerRect.height;
|
|
15861
|
+
if (forceEven) {
|
|
15862
|
+
w = Math.ceil(w / 2) * 2;
|
|
15863
|
+
h = Math.ceil(h / 2) * 2;
|
|
15864
|
+
}
|
|
15865
|
+
return {
|
|
15866
|
+
width: w,
|
|
15867
|
+
height: h,
|
|
15041
15868
|
top: containerRect.top,
|
|
15042
15869
|
left: containerRect.left
|
|
15043
|
-
}
|
|
15044
|
-
|
|
15045
|
-
);
|
|
15870
|
+
};
|
|
15871
|
+
}, [width, height, containerRect, forceEven]);
|
|
15046
15872
|
if (!hasInitialSizeRef.current && effectiveSize.width > 0 && effectiveSize.height > 0) {
|
|
15047
15873
|
hasInitialSizeRef.current = true;
|
|
15048
15874
|
}
|
|
@@ -15082,14 +15908,14 @@ function CanvasImpl({
|
|
|
15082
15908
|
async function run() {
|
|
15083
15909
|
if (!effectActiveRef.current || !root.current) return;
|
|
15084
15910
|
await root.current.configure({
|
|
15911
|
+
id,
|
|
15912
|
+
primaryCanvas,
|
|
15913
|
+
scheduler,
|
|
15085
15914
|
gl,
|
|
15086
15915
|
renderer,
|
|
15087
15916
|
scene,
|
|
15088
15917
|
events,
|
|
15089
15918
|
shadows,
|
|
15090
|
-
linear,
|
|
15091
|
-
flat,
|
|
15092
|
-
legacy,
|
|
15093
15919
|
orthographic,
|
|
15094
15920
|
frameloop,
|
|
15095
15921
|
dpr,
|
|
@@ -15099,6 +15925,7 @@ function CanvasImpl({
|
|
|
15099
15925
|
size: effectiveSize,
|
|
15100
15926
|
// Store size props for reset functionality
|
|
15101
15927
|
_sizeProps: width !== void 0 || height !== void 0 ? { width, height } : null,
|
|
15928
|
+
forceEven,
|
|
15102
15929
|
// Pass mutable reference to onPointerMissed so it's free to update
|
|
15103
15930
|
onPointerMissed: (...args) => handlePointerMissed.current?.(...args),
|
|
15104
15931
|
onDragOverMissed: (...args) => handleDragOverMissed.current?.(...args),
|
|
@@ -15122,7 +15949,10 @@ function CanvasImpl({
|
|
|
15122
15949
|
});
|
|
15123
15950
|
if (!effectActiveRef.current || !root.current) return;
|
|
15124
15951
|
root.current.render(
|
|
15125
|
-
/* @__PURE__ */ jsxRuntime.jsx(Bridge, { children: /* @__PURE__ */ jsxRuntime.jsx(ErrorBoundary, { set: setError, children: /* @__PURE__ */ jsxRuntime.
|
|
15952
|
+
/* @__PURE__ */ jsxRuntime.jsx(Bridge, { children: /* @__PURE__ */ jsxRuntime.jsx(ErrorBoundary, { set: setError, children: /* @__PURE__ */ jsxRuntime.jsxs(React__namespace.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(Block, { set: setBlock }), children: [
|
|
15953
|
+
backgroundProps && /* @__PURE__ */ jsxRuntime.jsx(Environment, { ...backgroundProps }),
|
|
15954
|
+
children ?? null
|
|
15955
|
+
] }) }) })
|
|
15126
15956
|
);
|
|
15127
15957
|
}
|
|
15128
15958
|
run();
|
|
@@ -15149,20 +15979,22 @@ function CanvasImpl({
|
|
|
15149
15979
|
const canvas = canvasRef.current;
|
|
15150
15980
|
if (!canvas) return;
|
|
15151
15981
|
const handleHMR = () => {
|
|
15152
|
-
|
|
15153
|
-
|
|
15154
|
-
rootEntry
|
|
15155
|
-
nodes
|
|
15156
|
-
|
|
15157
|
-
|
|
15158
|
-
|
|
15159
|
-
|
|
15982
|
+
queueMicrotask(() => {
|
|
15983
|
+
const rootEntry = _roots.get(canvas);
|
|
15984
|
+
if (rootEntry?.store) {
|
|
15985
|
+
console.log("[R3F] HMR detected \u2014 rebuilding nodes/uniforms");
|
|
15986
|
+
rootEntry.store.setState((state) => ({
|
|
15987
|
+
nodes: {},
|
|
15988
|
+
uniforms: {},
|
|
15989
|
+
_hmrVersion: state._hmrVersion + 1
|
|
15990
|
+
}));
|
|
15991
|
+
}
|
|
15992
|
+
});
|
|
15160
15993
|
};
|
|
15161
15994
|
if (typeof ({ url: (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)) }) !== "undefined" && undefined) {
|
|
15162
15995
|
const hot = undefined;
|
|
15163
15996
|
hot.on("vite:afterUpdate", handleHMR);
|
|
15164
|
-
return () => hot.
|
|
15165
|
-
});
|
|
15997
|
+
return () => hot.off?.("vite:afterUpdate", handleHMR);
|
|
15166
15998
|
}
|
|
15167
15999
|
if (typeof module !== "undefined" && module.hot) {
|
|
15168
16000
|
const hot = module.hot;
|
|
@@ -15185,7 +16017,16 @@ function CanvasImpl({
|
|
|
15185
16017
|
...style
|
|
15186
16018
|
},
|
|
15187
16019
|
...props,
|
|
15188
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, className: "r3f-canvas-container", style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
16020
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, className: "r3f-canvas-container", style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
16021
|
+
"canvas",
|
|
16022
|
+
{
|
|
16023
|
+
ref: canvasRef,
|
|
16024
|
+
id,
|
|
16025
|
+
className: "r3f-canvas",
|
|
16026
|
+
style: { display: "block", width: "100%", height: "100%" },
|
|
16027
|
+
children: fallback
|
|
16028
|
+
}
|
|
16029
|
+
) })
|
|
15189
16030
|
}
|
|
15190
16031
|
);
|
|
15191
16032
|
}
|
|
@@ -15258,6 +16099,34 @@ let ScopedStore = _ScopedStore;
|
|
|
15258
16099
|
function createScopedStore(data) {
|
|
15259
16100
|
return new ScopedStore(data);
|
|
15260
16101
|
}
|
|
16102
|
+
function createLazyCreatorState(state) {
|
|
16103
|
+
let _uniforms = null;
|
|
16104
|
+
let _nodes = null;
|
|
16105
|
+
let _buffers = null;
|
|
16106
|
+
let _gpuStorage = null;
|
|
16107
|
+
return Object.create(state, {
|
|
16108
|
+
uniforms: {
|
|
16109
|
+
get() {
|
|
16110
|
+
return _uniforms ?? (_uniforms = createScopedStore(state.uniforms));
|
|
16111
|
+
}
|
|
16112
|
+
},
|
|
16113
|
+
nodes: {
|
|
16114
|
+
get() {
|
|
16115
|
+
return _nodes ?? (_nodes = createScopedStore(state.nodes));
|
|
16116
|
+
}
|
|
16117
|
+
},
|
|
16118
|
+
buffers: {
|
|
16119
|
+
get() {
|
|
16120
|
+
return _buffers ?? (_buffers = createScopedStore(state.buffers));
|
|
16121
|
+
}
|
|
16122
|
+
},
|
|
16123
|
+
gpuStorage: {
|
|
16124
|
+
get() {
|
|
16125
|
+
return _gpuStorage ?? (_gpuStorage = createScopedStore(state.gpuStorage));
|
|
16126
|
+
}
|
|
16127
|
+
}
|
|
16128
|
+
});
|
|
16129
|
+
}
|
|
15261
16130
|
|
|
15262
16131
|
function addTexture(set, key, value) {
|
|
15263
16132
|
set((state) => {
|
|
@@ -15298,6 +16167,27 @@ function createTextureOperations(set) {
|
|
|
15298
16167
|
removeMultiple: (keys) => removeTextures(set, keys)
|
|
15299
16168
|
};
|
|
15300
16169
|
}
|
|
16170
|
+
function extractTSLValue(value) {
|
|
16171
|
+
if (value === null || value === void 0) return value;
|
|
16172
|
+
if (typeof value !== "object") return value;
|
|
16173
|
+
const node = value;
|
|
16174
|
+
if (!node.isNode) return value;
|
|
16175
|
+
if (node.isConstNode) {
|
|
16176
|
+
return node.value;
|
|
16177
|
+
}
|
|
16178
|
+
if ("value" in node) {
|
|
16179
|
+
let extractedValue = node.value;
|
|
16180
|
+
if (typeof node.traverse === "function") {
|
|
16181
|
+
node.traverse((n) => {
|
|
16182
|
+
if (n.isConstNode) {
|
|
16183
|
+
extractedValue = n.value;
|
|
16184
|
+
}
|
|
16185
|
+
});
|
|
16186
|
+
}
|
|
16187
|
+
return extractedValue;
|
|
16188
|
+
}
|
|
16189
|
+
return value;
|
|
16190
|
+
}
|
|
15301
16191
|
function vectorize(inObject) {
|
|
15302
16192
|
if (inObject === null || inObject === void 0) return inObject;
|
|
15303
16193
|
if (typeof inObject === "string") {
|
|
@@ -15310,9 +16200,16 @@ function vectorize(inObject) {
|
|
|
15310
16200
|
}
|
|
15311
16201
|
if (typeof inObject !== "object") return inObject;
|
|
15312
16202
|
const obj = inObject;
|
|
16203
|
+
if (obj.isNode) {
|
|
16204
|
+
return extractTSLValue(inObject);
|
|
16205
|
+
}
|
|
15313
16206
|
if (obj.isVector2 || obj.isVector3 || obj.isVector4) return inObject;
|
|
15314
16207
|
if (obj.isMatrix3 || obj.isMatrix4) return inObject;
|
|
15315
16208
|
if (obj.isColor || obj.isEuler || obj.isQuaternion || obj.isSpherical) return inObject;
|
|
16209
|
+
if ("r" in obj && "g" in obj && "b" in obj && typeof obj.r === "number" && typeof obj.g === "number" && typeof obj.b === "number") {
|
|
16210
|
+
const scale = obj.r > 1 || obj.g > 1 || obj.b > 1 ? 1 / 255 : 1;
|
|
16211
|
+
return new webgpu.Color(obj.r * scale, obj.g * scale, obj.b * scale);
|
|
16212
|
+
}
|
|
15316
16213
|
if ("x" in obj && "y" in obj && typeof obj.x === "number" && typeof obj.y === "number") {
|
|
15317
16214
|
if ("w" in obj && typeof obj.w === "number" && "z" in obj && typeof obj.z === "number") {
|
|
15318
16215
|
return new webgpu.Vector4(obj.x, obj.y, obj.z, obj.w);
|
|
@@ -15375,17 +16272,14 @@ function useUniforms(creatorOrScope, scope) {
|
|
|
15375
16272
|
const rebuildUniforms = React.useCallback(
|
|
15376
16273
|
(targetScope) => {
|
|
15377
16274
|
store.setState((state) => {
|
|
15378
|
-
let newUniforms =
|
|
16275
|
+
let newUniforms = {};
|
|
15379
16276
|
if (targetScope && targetScope !== "root") {
|
|
15380
16277
|
const { [targetScope]: _, ...rest } = state.uniforms;
|
|
15381
16278
|
newUniforms = rest;
|
|
15382
16279
|
} else if (targetScope === "root") {
|
|
15383
|
-
newUniforms = {};
|
|
15384
16280
|
for (const [key, value] of Object.entries(state.uniforms)) {
|
|
15385
16281
|
if (!isUniformNode$1(value)) newUniforms[key] = value;
|
|
15386
16282
|
}
|
|
15387
|
-
} else {
|
|
15388
|
-
newUniforms = {};
|
|
15389
16283
|
}
|
|
15390
16284
|
return { uniforms: newUniforms, _hmrVersion: state._hmrVersion + 1 };
|
|
15391
16285
|
});
|
|
@@ -15393,20 +16287,26 @@ function useUniforms(creatorOrScope, scope) {
|
|
|
15393
16287
|
[store]
|
|
15394
16288
|
);
|
|
15395
16289
|
const inputForMemoization = React.useMemo(() => {
|
|
16290
|
+
let raw = creatorOrScope;
|
|
15396
16291
|
if (is.fun(creatorOrScope)) {
|
|
15397
|
-
const
|
|
15398
|
-
|
|
15399
|
-
|
|
15400
|
-
|
|
15401
|
-
|
|
15402
|
-
|
|
15403
|
-
|
|
16292
|
+
const wrappedState = createLazyCreatorState(store.getState());
|
|
16293
|
+
raw = creatorOrScope(wrappedState);
|
|
16294
|
+
}
|
|
16295
|
+
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
|
|
16296
|
+
const normalized = {};
|
|
16297
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
16298
|
+
normalized[key] = vectorize(value);
|
|
16299
|
+
}
|
|
16300
|
+
return normalized;
|
|
15404
16301
|
}
|
|
15405
|
-
return
|
|
16302
|
+
return raw;
|
|
15406
16303
|
}, [creatorOrScope, store]);
|
|
15407
16304
|
const memoizedInput = useCompareMemoize(inputForMemoization);
|
|
15408
16305
|
const isReader = memoizedInput === void 0 || typeof memoizedInput === "string";
|
|
15409
16306
|
const storeUniforms = useThree((s) => s.uniforms);
|
|
16307
|
+
const hmrVersion = useThree((s) => s._hmrVersion);
|
|
16308
|
+
const readerDep = isReader ? storeUniforms : null;
|
|
16309
|
+
const creatorDep = isReader ? null : hmrVersion;
|
|
15410
16310
|
const uniforms = React.useMemo(() => {
|
|
15411
16311
|
if (memoizedInput === void 0) {
|
|
15412
16312
|
return storeUniforms;
|
|
@@ -15461,28 +16361,19 @@ function useUniforms(creatorOrScope, scope) {
|
|
|
15461
16361
|
}
|
|
15462
16362
|
}
|
|
15463
16363
|
return result;
|
|
15464
|
-
}, [
|
|
15465
|
-
store,
|
|
15466
|
-
memoizedInput,
|
|
15467
|
-
scope,
|
|
15468
|
-
// Only include storeUniforms in deps for reader modes to enable reactivity
|
|
15469
|
-
isReader ? storeUniforms : null
|
|
15470
|
-
]);
|
|
16364
|
+
}, [store, memoizedInput, scope, readerDep, creatorDep]);
|
|
15471
16365
|
return { ...uniforms, removeUniforms: removeUniforms2, clearUniforms, rebuildUniforms };
|
|
15472
16366
|
}
|
|
15473
16367
|
function rebuildAllUniforms(store, scope) {
|
|
15474
16368
|
store.setState((state) => {
|
|
15475
|
-
let newUniforms =
|
|
16369
|
+
let newUniforms = {};
|
|
15476
16370
|
if (scope && scope !== "root") {
|
|
15477
16371
|
const { [scope]: _, ...rest } = state.uniforms;
|
|
15478
16372
|
newUniforms = rest;
|
|
15479
16373
|
} else if (scope === "root") {
|
|
15480
|
-
newUniforms = {};
|
|
15481
16374
|
for (const [key, value] of Object.entries(state.uniforms)) {
|
|
15482
16375
|
if (!isUniformNode$1(value)) newUniforms[key] = value;
|
|
15483
16376
|
}
|
|
15484
|
-
} else {
|
|
15485
|
-
newUniforms = {};
|
|
15486
16377
|
}
|
|
15487
16378
|
return { uniforms: newUniforms, _hmrVersion: state._hmrVersion + 1 };
|
|
15488
16379
|
});
|
|
@@ -15550,15 +16441,17 @@ function isSameThreeType(a, b) {
|
|
|
15550
16441
|
}
|
|
15551
16442
|
|
|
15552
16443
|
const isUniformNode = (value) => value !== null && typeof value === "object" && "value" in value && "uuid" in value;
|
|
16444
|
+
const isTSLNode$1 = (value) => value !== null && typeof value === "object" && "uuid" in value && "nodeType" in value;
|
|
15553
16445
|
function useUniform(name, value) {
|
|
15554
16446
|
const store = useStore();
|
|
16447
|
+
const hmrVersion = useThree((s) => s._hmrVersion);
|
|
15555
16448
|
return React.useMemo(() => {
|
|
15556
16449
|
const state = store.getState();
|
|
15557
16450
|
const set = store.setState;
|
|
15558
16451
|
const existing = state.uniforms[name];
|
|
15559
16452
|
if (existing && isUniformNode(existing)) {
|
|
15560
|
-
if (value !== void 0) {
|
|
15561
|
-
existing.value = value;
|
|
16453
|
+
if (value !== void 0 && !isTSLNode$1(value) && !isUniformNode(value)) {
|
|
16454
|
+
existing.value = typeof value === "string" ? new webgpu.Color(value) : value;
|
|
15562
16455
|
}
|
|
15563
16456
|
return existing;
|
|
15564
16457
|
}
|
|
@@ -15567,7 +16460,24 @@ function useUniform(name, value) {
|
|
|
15567
16460
|
`[useUniform] Uniform "${name}" not found. Create it first with: useUniform('${name}', initialValue)`
|
|
15568
16461
|
);
|
|
15569
16462
|
}
|
|
15570
|
-
|
|
16463
|
+
if (isUniformNode(value)) {
|
|
16464
|
+
const node2 = value;
|
|
16465
|
+
if (typeof node2.setName === "function") {
|
|
16466
|
+
node2.setName(name);
|
|
16467
|
+
}
|
|
16468
|
+
set((s) => ({
|
|
16469
|
+
uniforms: { ...s.uniforms, [name]: node2 }
|
|
16470
|
+
}));
|
|
16471
|
+
return node2;
|
|
16472
|
+
}
|
|
16473
|
+
let node;
|
|
16474
|
+
if (isTSLNode$1(value)) {
|
|
16475
|
+
node = tsl.uniform(value);
|
|
16476
|
+
} else if (typeof value === "string") {
|
|
16477
|
+
node = tsl.uniform(new webgpu.Color(value));
|
|
16478
|
+
} else {
|
|
16479
|
+
node = tsl.uniform(value);
|
|
16480
|
+
}
|
|
15571
16481
|
if (typeof node.setName === "function") {
|
|
15572
16482
|
node.setName(name);
|
|
15573
16483
|
}
|
|
@@ -15578,7 +16488,7 @@ function useUniform(name, value) {
|
|
|
15578
16488
|
}
|
|
15579
16489
|
}));
|
|
15580
16490
|
return node;
|
|
15581
|
-
}, [store, name]);
|
|
16491
|
+
}, [store, name, hmrVersion]);
|
|
15582
16492
|
}
|
|
15583
16493
|
|
|
15584
16494
|
const isTSLNode = (value) => value !== null && typeof value === "object" && ("uuid" in value || "nodeType" in value);
|
|
@@ -15642,6 +16552,9 @@ function useNodes(creatorOrScope, scope) {
|
|
|
15642
16552
|
const isReader = creatorOrScope === void 0 || typeof creatorOrScope === "string";
|
|
15643
16553
|
const storeNodes = useThree((s) => s.nodes);
|
|
15644
16554
|
const hmrVersion = useThree((s) => s._hmrVersion);
|
|
16555
|
+
const scopeDep = typeof creatorOrScope === "string" ? creatorOrScope : scope;
|
|
16556
|
+
const readerDep = isReader ? storeNodes : null;
|
|
16557
|
+
const creatorDep = isReader ? null : hmrVersion;
|
|
15645
16558
|
const nodes = React.useMemo(() => {
|
|
15646
16559
|
if (creatorOrScope === void 0) {
|
|
15647
16560
|
return storeNodes;
|
|
@@ -15654,11 +16567,7 @@ function useNodes(creatorOrScope, scope) {
|
|
|
15654
16567
|
const state = store.getState();
|
|
15655
16568
|
const set = store.setState;
|
|
15656
16569
|
const creator = creatorOrScope;
|
|
15657
|
-
const wrappedState =
|
|
15658
|
-
...state,
|
|
15659
|
-
uniforms: createScopedStore(state.uniforms),
|
|
15660
|
-
nodes: createScopedStore(state.nodes)
|
|
15661
|
-
};
|
|
16570
|
+
const wrappedState = createLazyCreatorState(state);
|
|
15662
16571
|
const created = creator(wrappedState);
|
|
15663
16572
|
const result = {};
|
|
15664
16573
|
let hasNewNodes = false;
|
|
@@ -15668,7 +16577,7 @@ function useNodes(creatorOrScope, scope) {
|
|
|
15668
16577
|
if (currentScope[name]) {
|
|
15669
16578
|
result[name] = currentScope[name];
|
|
15670
16579
|
} else {
|
|
15671
|
-
|
|
16580
|
+
node.setName?.(`${scope}.${name}`);
|
|
15672
16581
|
result[name] = node;
|
|
15673
16582
|
hasNewNodes = true;
|
|
15674
16583
|
}
|
|
@@ -15688,7 +16597,7 @@ function useNodes(creatorOrScope, scope) {
|
|
|
15688
16597
|
if (existing && isTSLNode(existing)) {
|
|
15689
16598
|
result[name] = existing;
|
|
15690
16599
|
} else {
|
|
15691
|
-
|
|
16600
|
+
node.setName?.(name);
|
|
15692
16601
|
result[name] = node;
|
|
15693
16602
|
hasNewNodes = true;
|
|
15694
16603
|
}
|
|
@@ -15697,15 +16606,7 @@ function useNodes(creatorOrScope, scope) {
|
|
|
15697
16606
|
set((s) => ({ nodes: { ...s.nodes, ...result } }));
|
|
15698
16607
|
}
|
|
15699
16608
|
return result;
|
|
15700
|
-
}, [
|
|
15701
|
-
store,
|
|
15702
|
-
typeof creatorOrScope === "string" ? creatorOrScope : scope,
|
|
15703
|
-
// Only include storeNodes in deps for reader modes to enable reactivity
|
|
15704
|
-
// Creator mode intentionally excludes it to avoid re-running creator on unrelated changes
|
|
15705
|
-
isReader ? storeNodes : null,
|
|
15706
|
-
// Include hmrVersion for creator modes to allow rebuildNodes() to bust the cache
|
|
15707
|
-
isReader ? null : hmrVersion
|
|
15708
|
-
]);
|
|
16609
|
+
}, [store, scopeDep, readerDep, creatorDep]);
|
|
15709
16610
|
return { ...nodes, removeNodes: removeNodes2, clearNodes, rebuildNodes };
|
|
15710
16611
|
}
|
|
15711
16612
|
function rebuildAllNodes(store, scope) {
|
|
@@ -15757,18 +16658,358 @@ function useLocalNodes(creator) {
|
|
|
15757
16658
|
const uniforms = useThree((s) => s.uniforms);
|
|
15758
16659
|
const nodes = useThree((s) => s.nodes);
|
|
15759
16660
|
const textures = useThree((s) => s.textures);
|
|
16661
|
+
const hmrVersion = useThree((s) => s._hmrVersion);
|
|
15760
16662
|
return React.useMemo(() => {
|
|
15761
|
-
const
|
|
15762
|
-
const wrappedState = {
|
|
15763
|
-
...state,
|
|
15764
|
-
uniforms: createScopedStore(state.uniforms),
|
|
15765
|
-
nodes: createScopedStore(state.nodes)
|
|
15766
|
-
};
|
|
16663
|
+
const wrappedState = createLazyCreatorState(store.getState());
|
|
15767
16664
|
return creator(wrappedState);
|
|
15768
|
-
}, [store, creator, uniforms, nodes, textures]);
|
|
16665
|
+
}, [store, creator, uniforms, nodes, textures, hmrVersion]);
|
|
16666
|
+
}
|
|
16667
|
+
|
|
16668
|
+
const isBufferLike = (value) => {
|
|
16669
|
+
if (value === null || typeof value !== "object") return false;
|
|
16670
|
+
if (ArrayBuffer.isView(value)) return true;
|
|
16671
|
+
if ("isBufferAttribute" in value) return true;
|
|
16672
|
+
if ("uuid" in value || "nodeType" in value) return true;
|
|
16673
|
+
return false;
|
|
16674
|
+
};
|
|
16675
|
+
const disposeBuffer = (buffer) => {
|
|
16676
|
+
if (buffer === null || typeof buffer !== "object") return;
|
|
16677
|
+
if ("dispose" in buffer && typeof buffer.dispose === "function") {
|
|
16678
|
+
buffer.dispose();
|
|
16679
|
+
}
|
|
16680
|
+
};
|
|
16681
|
+
function useBuffers(creatorOrScope, scope) {
|
|
16682
|
+
const store = useStore();
|
|
16683
|
+
const removeBuffers = React.useCallback(
|
|
16684
|
+
(names, targetScope) => {
|
|
16685
|
+
const nameArray = Array.isArray(names) ? names : [names];
|
|
16686
|
+
store.setState((state) => {
|
|
16687
|
+
if (targetScope) {
|
|
16688
|
+
const currentScope = { ...state.buffers[targetScope] };
|
|
16689
|
+
for (const name of nameArray) delete currentScope[name];
|
|
16690
|
+
return { buffers: { ...state.buffers, [targetScope]: currentScope } };
|
|
16691
|
+
}
|
|
16692
|
+
const buffers2 = { ...state.buffers };
|
|
16693
|
+
for (const name of nameArray) if (isBufferLike(buffers2[name])) delete buffers2[name];
|
|
16694
|
+
return { buffers: buffers2 };
|
|
16695
|
+
});
|
|
16696
|
+
},
|
|
16697
|
+
[store]
|
|
16698
|
+
);
|
|
16699
|
+
const clearBuffers = React.useCallback(
|
|
16700
|
+
(targetScope) => {
|
|
16701
|
+
store.setState((state) => {
|
|
16702
|
+
if (targetScope && targetScope !== "root") {
|
|
16703
|
+
const { [targetScope]: _, ...rest } = state.buffers;
|
|
16704
|
+
return { buffers: rest };
|
|
16705
|
+
}
|
|
16706
|
+
if (targetScope === "root") {
|
|
16707
|
+
const buffers2 = {};
|
|
16708
|
+
for (const [key, value] of Object.entries(state.buffers)) {
|
|
16709
|
+
if (!isBufferLike(value)) buffers2[key] = value;
|
|
16710
|
+
}
|
|
16711
|
+
return { buffers: buffers2 };
|
|
16712
|
+
}
|
|
16713
|
+
return { buffers: {} };
|
|
16714
|
+
});
|
|
16715
|
+
},
|
|
16716
|
+
[store]
|
|
16717
|
+
);
|
|
16718
|
+
const rebuildBuffers = React.useCallback(
|
|
16719
|
+
(targetScope) => {
|
|
16720
|
+
store.setState((state) => {
|
|
16721
|
+
let newBuffers = state.buffers;
|
|
16722
|
+
if (targetScope && targetScope !== "root") {
|
|
16723
|
+
const { [targetScope]: _, ...rest } = state.buffers;
|
|
16724
|
+
newBuffers = rest;
|
|
16725
|
+
} else if (targetScope === "root") {
|
|
16726
|
+
newBuffers = {};
|
|
16727
|
+
for (const [key, value] of Object.entries(state.buffers)) {
|
|
16728
|
+
if (!isBufferLike(value)) newBuffers[key] = value;
|
|
16729
|
+
}
|
|
16730
|
+
} else {
|
|
16731
|
+
newBuffers = {};
|
|
16732
|
+
}
|
|
16733
|
+
return { buffers: newBuffers, _hmrVersion: state._hmrVersion + 1 };
|
|
16734
|
+
});
|
|
16735
|
+
},
|
|
16736
|
+
[store]
|
|
16737
|
+
);
|
|
16738
|
+
const disposeBuffers = React.useCallback(
|
|
16739
|
+
(names, targetScope) => {
|
|
16740
|
+
const nameArray = Array.isArray(names) ? names : [names];
|
|
16741
|
+
const state = store.getState();
|
|
16742
|
+
for (const name of nameArray) {
|
|
16743
|
+
const buffer = targetScope ? state.buffers[targetScope]?.[name] : state.buffers[name];
|
|
16744
|
+
if (buffer && isBufferLike(buffer)) {
|
|
16745
|
+
disposeBuffer(buffer);
|
|
16746
|
+
}
|
|
16747
|
+
}
|
|
16748
|
+
removeBuffers(names, targetScope);
|
|
16749
|
+
},
|
|
16750
|
+
[store, removeBuffers]
|
|
16751
|
+
);
|
|
16752
|
+
const isReader = creatorOrScope === void 0 || typeof creatorOrScope === "string";
|
|
16753
|
+
const storeBuffers = useThree((s) => s.buffers);
|
|
16754
|
+
const hmrVersion = useThree((s) => s._hmrVersion);
|
|
16755
|
+
const scopeDep = typeof creatorOrScope === "string" ? creatorOrScope : scope;
|
|
16756
|
+
const readerDep = isReader ? storeBuffers : null;
|
|
16757
|
+
const creatorDep = isReader ? null : hmrVersion;
|
|
16758
|
+
const buffers = React.useMemo(() => {
|
|
16759
|
+
if (creatorOrScope === void 0) {
|
|
16760
|
+
return storeBuffers;
|
|
16761
|
+
}
|
|
16762
|
+
if (typeof creatorOrScope === "string") {
|
|
16763
|
+
const scopeData = storeBuffers[creatorOrScope];
|
|
16764
|
+
if (scopeData && !isBufferLike(scopeData)) return scopeData;
|
|
16765
|
+
return {};
|
|
16766
|
+
}
|
|
16767
|
+
const state = store.getState();
|
|
16768
|
+
const set = store.setState;
|
|
16769
|
+
const creator = creatorOrScope;
|
|
16770
|
+
const wrappedState = createLazyCreatorState(state);
|
|
16771
|
+
const created = creator(wrappedState);
|
|
16772
|
+
const result = {};
|
|
16773
|
+
let hasNewBuffers = false;
|
|
16774
|
+
if (scope) {
|
|
16775
|
+
const currentScope = state.buffers[scope] ?? {};
|
|
16776
|
+
for (const [name, buffer] of Object.entries(created)) {
|
|
16777
|
+
if (currentScope[name]) {
|
|
16778
|
+
result[name] = currentScope[name];
|
|
16779
|
+
} else {
|
|
16780
|
+
if ("setName" in buffer && typeof buffer.setName === "function") {
|
|
16781
|
+
buffer.setName(`${scope}.${name}`);
|
|
16782
|
+
}
|
|
16783
|
+
result[name] = buffer;
|
|
16784
|
+
hasNewBuffers = true;
|
|
16785
|
+
}
|
|
16786
|
+
}
|
|
16787
|
+
if (hasNewBuffers) {
|
|
16788
|
+
set((s) => ({
|
|
16789
|
+
buffers: {
|
|
16790
|
+
...s.buffers,
|
|
16791
|
+
[scope]: { ...s.buffers[scope], ...result }
|
|
16792
|
+
}
|
|
16793
|
+
}));
|
|
16794
|
+
}
|
|
16795
|
+
return result;
|
|
16796
|
+
}
|
|
16797
|
+
for (const [name, buffer] of Object.entries(created)) {
|
|
16798
|
+
const existing = state.buffers[name];
|
|
16799
|
+
if (existing && isBufferLike(existing)) {
|
|
16800
|
+
result[name] = existing;
|
|
16801
|
+
} else {
|
|
16802
|
+
if ("setName" in buffer && typeof buffer.setName === "function") {
|
|
16803
|
+
buffer.setName(name);
|
|
16804
|
+
}
|
|
16805
|
+
result[name] = buffer;
|
|
16806
|
+
hasNewBuffers = true;
|
|
16807
|
+
}
|
|
16808
|
+
}
|
|
16809
|
+
if (hasNewBuffers) {
|
|
16810
|
+
set((s) => ({ buffers: { ...s.buffers, ...result } }));
|
|
16811
|
+
}
|
|
16812
|
+
return result;
|
|
16813
|
+
}, [store, scopeDep, readerDep, creatorDep]);
|
|
16814
|
+
return { ...buffers, removeBuffers, clearBuffers, rebuildBuffers, disposeBuffers };
|
|
16815
|
+
}
|
|
16816
|
+
function rebuildAllBuffers(store, scope) {
|
|
16817
|
+
store.setState((state) => {
|
|
16818
|
+
let newBuffers = state.buffers;
|
|
16819
|
+
if (scope && scope !== "root") {
|
|
16820
|
+
const { [scope]: _, ...rest } = state.buffers;
|
|
16821
|
+
newBuffers = rest;
|
|
16822
|
+
} else if (scope === "root") {
|
|
16823
|
+
newBuffers = {};
|
|
16824
|
+
for (const [key, value] of Object.entries(state.buffers)) {
|
|
16825
|
+
if (!isBufferLike(value)) newBuffers[key] = value;
|
|
16826
|
+
}
|
|
16827
|
+
} else {
|
|
16828
|
+
newBuffers = {};
|
|
16829
|
+
}
|
|
16830
|
+
return { buffers: newBuffers, _hmrVersion: state._hmrVersion + 1 };
|
|
16831
|
+
});
|
|
16832
|
+
}
|
|
16833
|
+
|
|
16834
|
+
const isStorageLike = (value) => {
|
|
16835
|
+
if (value === null || typeof value !== "object") return false;
|
|
16836
|
+
if ("isTexture" in value) return true;
|
|
16837
|
+
if ("isData3DTexture" in value) return true;
|
|
16838
|
+
if ("uuid" in value || "nodeType" in value) return true;
|
|
16839
|
+
return false;
|
|
16840
|
+
};
|
|
16841
|
+
const disposeStorage = (storage) => {
|
|
16842
|
+
if (storage === null || typeof storage !== "object") return;
|
|
16843
|
+
if ("dispose" in storage && typeof storage.dispose === "function") {
|
|
16844
|
+
storage.dispose();
|
|
16845
|
+
}
|
|
16846
|
+
};
|
|
16847
|
+
function useGPUStorage(creatorOrScope, scope) {
|
|
16848
|
+
const store = useStore();
|
|
16849
|
+
const removeStorage = React.useCallback(
|
|
16850
|
+
(names, targetScope) => {
|
|
16851
|
+
const nameArray = Array.isArray(names) ? names : [names];
|
|
16852
|
+
store.setState((state) => {
|
|
16853
|
+
if (targetScope) {
|
|
16854
|
+
const currentScope = { ...state.gpuStorage[targetScope] };
|
|
16855
|
+
for (const name of nameArray) delete currentScope[name];
|
|
16856
|
+
return { gpuStorage: { ...state.gpuStorage, [targetScope]: currentScope } };
|
|
16857
|
+
}
|
|
16858
|
+
const gpuStorage2 = { ...state.gpuStorage };
|
|
16859
|
+
for (const name of nameArray) if (isStorageLike(gpuStorage2[name])) delete gpuStorage2[name];
|
|
16860
|
+
return { gpuStorage: gpuStorage2 };
|
|
16861
|
+
});
|
|
16862
|
+
},
|
|
16863
|
+
[store]
|
|
16864
|
+
);
|
|
16865
|
+
const clearStorage = React.useCallback(
|
|
16866
|
+
(targetScope) => {
|
|
16867
|
+
store.setState((state) => {
|
|
16868
|
+
if (targetScope && targetScope !== "root") {
|
|
16869
|
+
const { [targetScope]: _, ...rest } = state.gpuStorage;
|
|
16870
|
+
return { gpuStorage: rest };
|
|
16871
|
+
}
|
|
16872
|
+
if (targetScope === "root") {
|
|
16873
|
+
const gpuStorage2 = {};
|
|
16874
|
+
for (const [key, value] of Object.entries(state.gpuStorage)) {
|
|
16875
|
+
if (!isStorageLike(value)) gpuStorage2[key] = value;
|
|
16876
|
+
}
|
|
16877
|
+
return { gpuStorage: gpuStorage2 };
|
|
16878
|
+
}
|
|
16879
|
+
return { gpuStorage: {} };
|
|
16880
|
+
});
|
|
16881
|
+
},
|
|
16882
|
+
[store]
|
|
16883
|
+
);
|
|
16884
|
+
const rebuildStorage = React.useCallback(
|
|
16885
|
+
(targetScope) => {
|
|
16886
|
+
store.setState((state) => {
|
|
16887
|
+
let newStorage = state.gpuStorage;
|
|
16888
|
+
if (targetScope && targetScope !== "root") {
|
|
16889
|
+
const { [targetScope]: _, ...rest } = state.gpuStorage;
|
|
16890
|
+
newStorage = rest;
|
|
16891
|
+
} else if (targetScope === "root") {
|
|
16892
|
+
newStorage = {};
|
|
16893
|
+
for (const [key, value] of Object.entries(state.gpuStorage)) {
|
|
16894
|
+
if (!isStorageLike(value)) newStorage[key] = value;
|
|
16895
|
+
}
|
|
16896
|
+
} else {
|
|
16897
|
+
newStorage = {};
|
|
16898
|
+
}
|
|
16899
|
+
return { gpuStorage: newStorage, _hmrVersion: state._hmrVersion + 1 };
|
|
16900
|
+
});
|
|
16901
|
+
},
|
|
16902
|
+
[store]
|
|
16903
|
+
);
|
|
16904
|
+
const disposeStorageFn = React.useCallback(
|
|
16905
|
+
(names, targetScope) => {
|
|
16906
|
+
const nameArray = Array.isArray(names) ? names : [names];
|
|
16907
|
+
const state = store.getState();
|
|
16908
|
+
for (const name of nameArray) {
|
|
16909
|
+
const storage = targetScope ? state.gpuStorage[targetScope]?.[name] : state.gpuStorage[name];
|
|
16910
|
+
if (storage && isStorageLike(storage)) {
|
|
16911
|
+
disposeStorage(storage);
|
|
16912
|
+
}
|
|
16913
|
+
}
|
|
16914
|
+
removeStorage(names, targetScope);
|
|
16915
|
+
},
|
|
16916
|
+
[store, removeStorage]
|
|
16917
|
+
);
|
|
16918
|
+
const isReader = creatorOrScope === void 0 || typeof creatorOrScope === "string";
|
|
16919
|
+
const storeStorage = useThree((s) => s.gpuStorage);
|
|
16920
|
+
const hmrVersion = useThree((s) => s._hmrVersion);
|
|
16921
|
+
const scopeDep = typeof creatorOrScope === "string" ? creatorOrScope : scope;
|
|
16922
|
+
const readerDep = isReader ? storeStorage : null;
|
|
16923
|
+
const creatorDep = isReader ? null : hmrVersion;
|
|
16924
|
+
const gpuStorage = React.useMemo(() => {
|
|
16925
|
+
if (creatorOrScope === void 0) {
|
|
16926
|
+
return storeStorage;
|
|
16927
|
+
}
|
|
16928
|
+
if (typeof creatorOrScope === "string") {
|
|
16929
|
+
const scopeData = storeStorage[creatorOrScope];
|
|
16930
|
+
if (scopeData && !isStorageLike(scopeData)) return scopeData;
|
|
16931
|
+
return {};
|
|
16932
|
+
}
|
|
16933
|
+
const state = store.getState();
|
|
16934
|
+
const set = store.setState;
|
|
16935
|
+
const creator = creatorOrScope;
|
|
16936
|
+
const wrappedState = createLazyCreatorState(state);
|
|
16937
|
+
const created = creator(wrappedState);
|
|
16938
|
+
const result = {};
|
|
16939
|
+
let hasNewStorage = false;
|
|
16940
|
+
if (scope) {
|
|
16941
|
+
const currentScope = state.gpuStorage[scope] ?? {};
|
|
16942
|
+
for (const [name, storage] of Object.entries(created)) {
|
|
16943
|
+
if (currentScope[name]) {
|
|
16944
|
+
result[name] = currentScope[name];
|
|
16945
|
+
} else {
|
|
16946
|
+
if ("setName" in storage && typeof storage.setName === "function") {
|
|
16947
|
+
storage.setName(`${scope}.${name}`);
|
|
16948
|
+
}
|
|
16949
|
+
if ("name" in storage && typeof storage.name === "string") {
|
|
16950
|
+
storage.name = `${scope}.${name}`;
|
|
16951
|
+
}
|
|
16952
|
+
result[name] = storage;
|
|
16953
|
+
hasNewStorage = true;
|
|
16954
|
+
}
|
|
16955
|
+
}
|
|
16956
|
+
if (hasNewStorage) {
|
|
16957
|
+
set((s) => ({
|
|
16958
|
+
gpuStorage: {
|
|
16959
|
+
...s.gpuStorage,
|
|
16960
|
+
[scope]: { ...s.gpuStorage[scope], ...result }
|
|
16961
|
+
}
|
|
16962
|
+
}));
|
|
16963
|
+
}
|
|
16964
|
+
return result;
|
|
16965
|
+
}
|
|
16966
|
+
for (const [name, storage] of Object.entries(created)) {
|
|
16967
|
+
const existing = state.gpuStorage[name];
|
|
16968
|
+
if (existing && isStorageLike(existing)) {
|
|
16969
|
+
result[name] = existing;
|
|
16970
|
+
} else {
|
|
16971
|
+
if ("setName" in storage && typeof storage.setName === "function") {
|
|
16972
|
+
storage.setName(name);
|
|
16973
|
+
}
|
|
16974
|
+
if ("name" in storage && typeof storage.name === "string") {
|
|
16975
|
+
storage.name = name;
|
|
16976
|
+
}
|
|
16977
|
+
result[name] = storage;
|
|
16978
|
+
hasNewStorage = true;
|
|
16979
|
+
}
|
|
16980
|
+
}
|
|
16981
|
+
if (hasNewStorage) {
|
|
16982
|
+
set((s) => ({ gpuStorage: { ...s.gpuStorage, ...result } }));
|
|
16983
|
+
}
|
|
16984
|
+
return result;
|
|
16985
|
+
}, [store, scopeDep, readerDep, creatorDep]);
|
|
16986
|
+
return {
|
|
16987
|
+
...gpuStorage,
|
|
16988
|
+
removeStorage,
|
|
16989
|
+
clearStorage,
|
|
16990
|
+
rebuildStorage,
|
|
16991
|
+
disposeStorage: disposeStorageFn
|
|
16992
|
+
};
|
|
16993
|
+
}
|
|
16994
|
+
function rebuildAllStorage(store, scope) {
|
|
16995
|
+
store.setState((state) => {
|
|
16996
|
+
let newStorage = state.gpuStorage;
|
|
16997
|
+
if (scope && scope !== "root") {
|
|
16998
|
+
const { [scope]: _, ...rest } = state.gpuStorage;
|
|
16999
|
+
newStorage = rest;
|
|
17000
|
+
} else if (scope === "root") {
|
|
17001
|
+
newStorage = {};
|
|
17002
|
+
for (const [key, value] of Object.entries(state.gpuStorage)) {
|
|
17003
|
+
if (!isStorageLike(value)) newStorage[key] = value;
|
|
17004
|
+
}
|
|
17005
|
+
} else {
|
|
17006
|
+
newStorage = {};
|
|
17007
|
+
}
|
|
17008
|
+
return { gpuStorage: newStorage, _hmrVersion: state._hmrVersion + 1 };
|
|
17009
|
+
});
|
|
15769
17010
|
}
|
|
15770
17011
|
|
|
15771
|
-
function
|
|
17012
|
+
function useRenderPipeline(mainCB, setupCB) {
|
|
15772
17013
|
const store = useStore();
|
|
15773
17014
|
const { scene, camera, renderer, isLegacy } = useThree();
|
|
15774
17015
|
const callbacksRanRef = React.useRef(false);
|
|
@@ -15787,7 +17028,7 @@ function usePostProcessing(mainCB, setupCB) {
|
|
|
15787
17028
|
}, [store]);
|
|
15788
17029
|
const reset = React.useCallback(() => {
|
|
15789
17030
|
store.setState({
|
|
15790
|
-
|
|
17031
|
+
renderPipeline: null,
|
|
15791
17032
|
passes: {}
|
|
15792
17033
|
});
|
|
15793
17034
|
callbacksRanRef.current = false;
|
|
@@ -15800,13 +17041,13 @@ function usePostProcessing(mainCB, setupCB) {
|
|
|
15800
17041
|
}, []);
|
|
15801
17042
|
React.useLayoutEffect(() => {
|
|
15802
17043
|
if (isLegacy) {
|
|
15803
|
-
throw new Error("
|
|
17044
|
+
throw new Error("useRenderPipeline is only available with WebGPU renderer. Set renderer prop on Canvas.");
|
|
15804
17045
|
}
|
|
15805
17046
|
if (!renderer || !scene || !camera) return;
|
|
15806
17047
|
const state = store.getState();
|
|
15807
17048
|
const set = store.setState;
|
|
15808
17049
|
try {
|
|
15809
|
-
let pp = state.
|
|
17050
|
+
let pp = state.renderPipeline;
|
|
15810
17051
|
let currentPasses = { ...state.passes };
|
|
15811
17052
|
let justCreatedPP = false;
|
|
15812
17053
|
if (!pp) {
|
|
@@ -15823,7 +17064,7 @@ function usePostProcessing(mainCB, setupCB) {
|
|
|
15823
17064
|
}
|
|
15824
17065
|
currentPasses.scenePass = scenePass;
|
|
15825
17066
|
if (!pp.outputNode || justCreatedPP) pp.outputNode = scenePass;
|
|
15826
|
-
set({
|
|
17067
|
+
set({ renderPipeline: pp, passes: currentPasses });
|
|
15827
17068
|
const shouldRunCallbacks = justCreatedPP || !callbacksRanRef.current || !cacheValid;
|
|
15828
17069
|
if (shouldRunCallbacks) {
|
|
15829
17070
|
if (setupCBRef.current) {
|
|
@@ -15845,19 +17086,19 @@ function usePostProcessing(mainCB, setupCB) {
|
|
|
15845
17086
|
callbacksRanRef.current = true;
|
|
15846
17087
|
}
|
|
15847
17088
|
} catch (error) {
|
|
15848
|
-
console.error("[
|
|
17089
|
+
console.error("[useRenderPipeline] Setup error:", error);
|
|
15849
17090
|
}
|
|
15850
17091
|
}, [store, renderer, scene, camera, isLegacy, rebuildVersion]);
|
|
15851
17092
|
const passes = useThree((s) => s.passes);
|
|
15852
|
-
const
|
|
17093
|
+
const renderPipeline = useThree((s) => s.renderPipeline);
|
|
15853
17094
|
return {
|
|
15854
17095
|
passes,
|
|
15855
|
-
|
|
17096
|
+
renderPipeline,
|
|
15856
17097
|
clearPasses,
|
|
15857
17098
|
reset,
|
|
15858
17099
|
rebuild,
|
|
15859
|
-
// isReady indicates if
|
|
15860
|
-
isReady:
|
|
17100
|
+
// isReady indicates if RenderPipeline is configured and ready for rendering
|
|
17101
|
+
isReady: renderPipeline !== null
|
|
15861
17102
|
};
|
|
15862
17103
|
}
|
|
15863
17104
|
|
|
@@ -15865,8 +17106,15 @@ extend(THREE);
|
|
|
15865
17106
|
|
|
15866
17107
|
exports.Block = Block;
|
|
15867
17108
|
exports.Canvas = Canvas;
|
|
17109
|
+
exports.Environment = Environment;
|
|
17110
|
+
exports.EnvironmentCube = EnvironmentCube;
|
|
17111
|
+
exports.EnvironmentMap = EnvironmentMap;
|
|
17112
|
+
exports.EnvironmentPortal = EnvironmentPortal;
|
|
15868
17113
|
exports.ErrorBoundary = ErrorBoundary;
|
|
17114
|
+
exports.FROM_REF = FROM_REF;
|
|
15869
17115
|
exports.IsObject = IsObject;
|
|
17116
|
+
exports.ONCE = ONCE;
|
|
17117
|
+
exports.Portal = Portal;
|
|
15870
17118
|
exports.R3F_BUILD_LEGACY = R3F_BUILD_LEGACY;
|
|
15871
17119
|
exports.R3F_BUILD_WEBGPU = R3F_BUILD_WEBGPU;
|
|
15872
17120
|
exports.REACT_INTERNAL_PROPS = REACT_INTERNAL_PROPS;
|
|
@@ -15902,35 +17150,50 @@ exports.events = createPointerEvents;
|
|
|
15902
17150
|
exports.extend = extend;
|
|
15903
17151
|
exports.findInitialRoot = findInitialRoot;
|
|
15904
17152
|
exports.flushSync = flushSync;
|
|
17153
|
+
exports.fromRef = fromRef;
|
|
15905
17154
|
exports.getInstanceProps = getInstanceProps;
|
|
17155
|
+
exports.getPrimary = getPrimary;
|
|
17156
|
+
exports.getPrimaryIds = getPrimaryIds;
|
|
15906
17157
|
exports.getRootState = getRootState;
|
|
15907
17158
|
exports.getScheduler = getScheduler;
|
|
15908
17159
|
exports.getUuidPrefix = getUuidPrefix;
|
|
15909
17160
|
exports.hasConstructor = hasConstructor;
|
|
17161
|
+
exports.hasPrimary = hasPrimary;
|
|
15910
17162
|
exports.invalidate = invalidate;
|
|
15911
17163
|
exports.invalidateInstance = invalidateInstance;
|
|
15912
17164
|
exports.is = is;
|
|
15913
17165
|
exports.isColorRepresentation = isColorRepresentation;
|
|
15914
17166
|
exports.isCopyable = isCopyable;
|
|
17167
|
+
exports.isFromRef = isFromRef;
|
|
15915
17168
|
exports.isObject3D = isObject3D;
|
|
17169
|
+
exports.isOnce = isOnce;
|
|
15916
17170
|
exports.isOrthographicCamera = isOrthographicCamera;
|
|
15917
17171
|
exports.isRef = isRef;
|
|
15918
17172
|
exports.isRenderer = isRenderer;
|
|
15919
17173
|
exports.isTexture = isTexture;
|
|
15920
17174
|
exports.isVectorLike = isVectorLike;
|
|
17175
|
+
exports.once = once;
|
|
15921
17176
|
exports.prepare = prepare;
|
|
17177
|
+
exports.presetsObj = presetsObj;
|
|
17178
|
+
exports.rebuildAllBuffers = rebuildAllBuffers;
|
|
15922
17179
|
exports.rebuildAllNodes = rebuildAllNodes;
|
|
17180
|
+
exports.rebuildAllStorage = rebuildAllStorage;
|
|
15923
17181
|
exports.rebuildAllUniforms = rebuildAllUniforms;
|
|
15924
17182
|
exports.reconciler = reconciler;
|
|
17183
|
+
exports.registerPrimary = registerPrimary;
|
|
15925
17184
|
exports.removeInteractivity = removeInteractivity;
|
|
15926
17185
|
exports.removeNodes = removeNodes;
|
|
15927
17186
|
exports.removeUniforms = removeUniforms;
|
|
15928
17187
|
exports.resolve = resolve;
|
|
15929
17188
|
exports.unmountComponentAtNode = unmountComponentAtNode;
|
|
17189
|
+
exports.unregisterPrimary = unregisterPrimary;
|
|
15930
17190
|
exports.updateCamera = updateCamera;
|
|
15931
17191
|
exports.updateFrustum = updateFrustum;
|
|
15932
17192
|
exports.useBridge = useBridge;
|
|
17193
|
+
exports.useBuffers = useBuffers;
|
|
17194
|
+
exports.useEnvironment = useEnvironment;
|
|
15933
17195
|
exports.useFrame = useFrame;
|
|
17196
|
+
exports.useGPUStorage = useGPUStorage;
|
|
15934
17197
|
exports.useGraph = useGraph;
|
|
15935
17198
|
exports.useInstanceHandle = useInstanceHandle;
|
|
15936
17199
|
exports.useIsomorphicLayoutEffect = useIsomorphicLayoutEffect;
|
|
@@ -15938,7 +17201,7 @@ exports.useLoader = useLoader;
|
|
|
15938
17201
|
exports.useLocalNodes = useLocalNodes;
|
|
15939
17202
|
exports.useMutableCallback = useMutableCallback;
|
|
15940
17203
|
exports.useNodes = useNodes;
|
|
15941
|
-
exports.
|
|
17204
|
+
exports.useRenderPipeline = useRenderPipeline;
|
|
15942
17205
|
exports.useRenderTarget = useRenderTarget;
|
|
15943
17206
|
exports.useStore = useStore;
|
|
15944
17207
|
exports.useTexture = useTexture;
|
|
@@ -15946,3 +17209,4 @@ exports.useTextures = useTextures;
|
|
|
15946
17209
|
exports.useThree = useThree;
|
|
15947
17210
|
exports.useUniform = useUniform;
|
|
15948
17211
|
exports.useUniforms = useUniforms;
|
|
17212
|
+
exports.waitForPrimary = waitForPrimary;
|