@react-three/fiber 8.9.2 → 8.10.1
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/CHANGELOG.md +12 -0
- package/dist/declarations/src/core/events.d.ts +70 -70
- package/dist/declarations/src/core/hooks.d.ts +28 -28
- package/dist/declarations/src/core/index.d.ts +55 -55
- package/dist/declarations/src/core/loop.d.ts +14 -14
- package/dist/declarations/src/core/renderer.d.ts +52 -52
- package/dist/declarations/src/core/store.d.ts +95 -95
- package/dist/declarations/src/core/utils.d.ts +83 -83
- package/dist/declarations/src/index.d.ts +12 -12
- package/dist/declarations/src/native/Canvas.d.ts +8 -8
- package/dist/declarations/src/native/events.d.ts +4 -4
- package/dist/declarations/src/native/polyfills.d.ts +1 -1
- package/dist/declarations/src/native.d.ts +12 -12
- package/dist/declarations/src/three-types.d.ts +335 -335
- package/dist/declarations/src/web/Canvas.d.ts +11 -11
- package/dist/declarations/src/web/events.d.ts +4 -4
- package/dist/{index-25dfa84d.cjs.prod.js → index-5d1efa67.cjs.prod.js} +425 -508
- package/dist/{index-79f9c7e9.esm.js → index-adfddf12.esm.js} +425 -508
- package/dist/{index-efc69a1d.cjs.dev.js → index-f2e97578.cjs.dev.js} +425 -508
- package/dist/react-three-fiber.cjs.dev.js +20 -23
- package/dist/react-three-fiber.cjs.prod.js +20 -23
- package/dist/react-three-fiber.esm.js +21 -24
- package/native/dist/react-three-fiber-native.cjs.dev.js +36 -44
- package/native/dist/react-three-fiber-native.cjs.prod.js +36 -44
- package/native/dist/react-three-fiber-native.esm.js +37 -45
- package/package.json +1 -1
|
@@ -13,6 +13,7 @@ var threeTypes = /*#__PURE__*/Object.freeze({
|
|
|
13
13
|
var _window$document, _window$navigator;
|
|
14
14
|
const isOrthographicCamera = def => def && def.isOrthographicCamera;
|
|
15
15
|
const isRef = obj => obj && obj.hasOwnProperty('current');
|
|
16
|
+
|
|
16
17
|
/**
|
|
17
18
|
* An SSR-friendly useLayoutEffect.
|
|
18
19
|
*
|
|
@@ -22,7 +23,6 @@ const isRef = obj => obj && obj.hasOwnProperty('current');
|
|
|
22
23
|
*
|
|
23
24
|
* @see https://github.com/facebook/react/issues/14927
|
|
24
25
|
*/
|
|
25
|
-
|
|
26
26
|
const useIsomorphicLayoutEffect = typeof window !== 'undefined' && ((_window$document = window.document) != null && _window$document.createElement || ((_window$navigator = window.navigator) == null ? void 0 : _window$navigator.product) === 'ReactNative') ? React.useLayoutEffect : React.useEffect;
|
|
27
27
|
function useMutableCallback(fn) {
|
|
28
28
|
const ref = React.useRef(fn);
|
|
@@ -39,40 +39,31 @@ function Block({
|
|
|
39
39
|
return null;
|
|
40
40
|
}
|
|
41
41
|
class ErrorBoundary extends React.Component {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
|
|
42
|
+
state = {
|
|
43
|
+
error: false
|
|
44
|
+
};
|
|
45
|
+
static getDerivedStateFromError = () => ({
|
|
46
|
+
error: true
|
|
47
|
+
});
|
|
49
48
|
componentDidCatch(err) {
|
|
50
49
|
this.props.set(err);
|
|
51
50
|
}
|
|
52
|
-
|
|
53
51
|
render() {
|
|
54
52
|
return this.state.error ? null : this.props.children;
|
|
55
53
|
}
|
|
56
|
-
|
|
57
54
|
}
|
|
58
|
-
|
|
59
|
-
ErrorBoundary.getDerivedStateFromError = () => ({
|
|
60
|
-
error: true
|
|
61
|
-
});
|
|
62
|
-
|
|
63
55
|
const DEFAULT = '__default';
|
|
64
56
|
const isDiffSet = def => def && !!def.memoized && !!def.changes;
|
|
65
57
|
function calculateDpr(dpr) {
|
|
66
58
|
const target = typeof window !== 'undefined' ? window.devicePixelRatio : 1;
|
|
67
59
|
return Array.isArray(dpr) ? Math.min(Math.max(dpr[0], target), dpr[1]) : dpr;
|
|
68
60
|
}
|
|
61
|
+
|
|
69
62
|
/**
|
|
70
63
|
* Returns instance root state
|
|
71
64
|
*/
|
|
72
|
-
|
|
73
65
|
const getRootState = obj => {
|
|
74
66
|
var _r3f;
|
|
75
|
-
|
|
76
67
|
return (_r3f = obj.__r3f) == null ? void 0 : _r3f.root.getState();
|
|
77
68
|
};
|
|
78
69
|
// A collection of compare functions
|
|
@@ -84,68 +75,61 @@ const is = {
|
|
|
84
75
|
boo: a => typeof a === 'boolean',
|
|
85
76
|
und: a => a === void 0,
|
|
86
77
|
arr: a => Array.isArray(a),
|
|
87
|
-
|
|
88
78
|
equ(a, b, {
|
|
89
79
|
arrays = 'shallow',
|
|
90
80
|
objects = 'reference',
|
|
91
81
|
strict = true
|
|
92
82
|
} = {}) {
|
|
93
83
|
// Wrong type or one of the two undefined, doesn't match
|
|
94
|
-
if (typeof a !== typeof b || !!a !== !!b) return false;
|
|
95
|
-
|
|
84
|
+
if (typeof a !== typeof b || !!a !== !!b) return false;
|
|
85
|
+
// Atomic, just compare a against b
|
|
96
86
|
if (is.str(a) || is.num(a)) return a === b;
|
|
97
87
|
const isObj = is.obj(a);
|
|
98
88
|
if (isObj && objects === 'reference') return a === b;
|
|
99
89
|
const isArr = is.arr(a);
|
|
100
|
-
if (isArr && arrays === 'reference') return a === b;
|
|
101
|
-
|
|
102
|
-
if ((isArr || isObj) && a === b) return true;
|
|
103
|
-
|
|
90
|
+
if (isArr && arrays === 'reference') return a === b;
|
|
91
|
+
// Array or Object, shallow compare first to see if it's a match
|
|
92
|
+
if ((isArr || isObj) && a === b) return true;
|
|
93
|
+
// Last resort, go through keys
|
|
104
94
|
let i;
|
|
105
|
-
|
|
106
95
|
for (i in a) if (!(i in b)) return false;
|
|
107
|
-
|
|
108
96
|
for (i in strict ? b : a) if (a[i] !== b[i]) return false;
|
|
109
|
-
|
|
110
97
|
if (is.und(i)) {
|
|
111
98
|
if (isArr && a.length === 0 && b.length === 0) return true;
|
|
112
99
|
if (isObj && Object.keys(a).length === 0 && Object.keys(b).length === 0) return true;
|
|
113
100
|
if (a !== b) return false;
|
|
114
101
|
}
|
|
115
|
-
|
|
116
102
|
return true;
|
|
117
103
|
}
|
|
104
|
+
};
|
|
118
105
|
|
|
119
|
-
|
|
120
|
-
|
|
106
|
+
// Collects nodes and materials from a THREE.Object3D
|
|
121
107
|
function buildGraph(object) {
|
|
122
108
|
const data = {
|
|
123
109
|
nodes: {},
|
|
124
110
|
materials: {}
|
|
125
111
|
};
|
|
126
|
-
|
|
127
112
|
if (object) {
|
|
128
113
|
object.traverse(obj => {
|
|
129
114
|
if (obj.name) data.nodes[obj.name] = obj;
|
|
130
115
|
if (obj.material && !data.materials[obj.material.name]) data.materials[obj.material.name] = obj.material;
|
|
131
116
|
});
|
|
132
117
|
}
|
|
133
|
-
|
|
134
118
|
return data;
|
|
135
|
-
}
|
|
119
|
+
}
|
|
136
120
|
|
|
121
|
+
// Disposes an object and all its properties
|
|
137
122
|
function dispose(obj) {
|
|
138
123
|
if (obj.dispose && obj.type !== 'Scene') obj.dispose();
|
|
139
|
-
|
|
140
124
|
for (const p in obj) {
|
|
141
125
|
p.dispose == null ? void 0 : p.dispose();
|
|
142
126
|
delete obj[p];
|
|
143
127
|
}
|
|
144
|
-
}
|
|
128
|
+
}
|
|
145
129
|
|
|
130
|
+
// Each object in the scene carries a small LocalState descriptor
|
|
146
131
|
function prepare(object, state) {
|
|
147
132
|
const instance = object;
|
|
148
|
-
|
|
149
133
|
if (state != null && state.primitive || !instance.__r3f) {
|
|
150
134
|
instance.__r3f = {
|
|
151
135
|
type: '',
|
|
@@ -159,13 +143,10 @@ function prepare(object, state) {
|
|
|
159
143
|
...state
|
|
160
144
|
};
|
|
161
145
|
}
|
|
162
|
-
|
|
163
146
|
return object;
|
|
164
147
|
}
|
|
165
|
-
|
|
166
148
|
function resolve(instance, key) {
|
|
167
149
|
let target = instance;
|
|
168
|
-
|
|
169
150
|
if (key.includes('-')) {
|
|
170
151
|
const entries = key.split('-');
|
|
171
152
|
const last = entries.pop();
|
|
@@ -178,9 +159,9 @@ function resolve(instance, key) {
|
|
|
178
159
|
target,
|
|
179
160
|
key
|
|
180
161
|
};
|
|
181
|
-
}
|
|
182
|
-
|
|
162
|
+
}
|
|
183
163
|
|
|
164
|
+
// Checks if a dash-cased string ends with an integer
|
|
184
165
|
const INDEX_REGEX = /-\d+$/;
|
|
185
166
|
function attach(parent, child, type) {
|
|
186
167
|
if (is.str(type)) {
|
|
@@ -193,7 +174,6 @@ function attach(parent, child, type) {
|
|
|
193
174
|
} = resolve(parent, root);
|
|
194
175
|
if (!Array.isArray(target[key])) target[key] = [];
|
|
195
176
|
}
|
|
196
|
-
|
|
197
177
|
const {
|
|
198
178
|
target,
|
|
199
179
|
key
|
|
@@ -204,21 +184,21 @@ function attach(parent, child, type) {
|
|
|
204
184
|
}
|
|
205
185
|
function detach(parent, child, type) {
|
|
206
186
|
var _child$__r3f, _child$__r3f2;
|
|
207
|
-
|
|
208
187
|
if (is.str(type)) {
|
|
209
188
|
const {
|
|
210
189
|
target,
|
|
211
190
|
key
|
|
212
191
|
} = resolve(parent, type);
|
|
213
|
-
const previous = child.__r3f.previousAttach;
|
|
214
|
-
|
|
215
|
-
if (previous === undefined) delete target[key];
|
|
192
|
+
const previous = child.__r3f.previousAttach;
|
|
193
|
+
// When the previous value was undefined, it means the value was never set to begin with
|
|
194
|
+
if (previous === undefined) delete target[key];
|
|
195
|
+
// Otherwise set the previous value
|
|
216
196
|
else target[key] = previous;
|
|
217
197
|
} else (_child$__r3f = child.__r3f) == null ? void 0 : _child$__r3f.previousAttach == null ? void 0 : _child$__r3f.previousAttach(parent, child);
|
|
218
|
-
|
|
219
198
|
(_child$__r3f2 = child.__r3f) == null ? true : delete _child$__r3f2.previousAttach;
|
|
220
|
-
}
|
|
199
|
+
}
|
|
221
200
|
|
|
201
|
+
// This function prepares a set of changes to be applied to the instance
|
|
222
202
|
function diffProps(instance, {
|
|
223
203
|
children: cN,
|
|
224
204
|
key: kN,
|
|
@@ -231,39 +211,38 @@ function diffProps(instance, {
|
|
|
231
211
|
...previous
|
|
232
212
|
} = {}, remove = false) {
|
|
233
213
|
var _instance$__r3f;
|
|
234
|
-
|
|
235
214
|
const localState = (_instance$__r3f = instance == null ? void 0 : instance.__r3f) != null ? _instance$__r3f : {};
|
|
236
215
|
const entries = Object.entries(props);
|
|
237
|
-
const changes = [];
|
|
216
|
+
const changes = [];
|
|
238
217
|
|
|
218
|
+
// Catch removed props, prepend them so they can be reset or removed
|
|
239
219
|
if (remove) {
|
|
240
220
|
const previousKeys = Object.keys(previous);
|
|
241
|
-
|
|
242
221
|
for (let i = 0; i < previousKeys.length; i++) {
|
|
243
222
|
if (!props.hasOwnProperty(previousKeys[i])) entries.unshift([previousKeys[i], DEFAULT + 'remove']);
|
|
244
223
|
}
|
|
245
224
|
}
|
|
246
|
-
|
|
247
225
|
entries.forEach(([key, value]) => {
|
|
248
226
|
var _instance$__r3f2;
|
|
249
|
-
|
|
250
227
|
// Bail out on primitive object
|
|
251
|
-
if ((_instance$__r3f2 = instance.__r3f) != null && _instance$__r3f2.primitive && key === 'object') return;
|
|
252
|
-
|
|
253
|
-
if (is.equ(value, previous[key])) return;
|
|
254
|
-
|
|
255
|
-
if (/^on(Pointer|Click|DoubleClick|ContextMenu|Wheel)/.test(key)) return changes.push([key, value, true, []]);
|
|
256
|
-
|
|
228
|
+
if ((_instance$__r3f2 = instance.__r3f) != null && _instance$__r3f2.primitive && key === 'object') return;
|
|
229
|
+
// When props match bail out
|
|
230
|
+
if (is.equ(value, previous[key])) return;
|
|
231
|
+
// Collect handlers and bail out
|
|
232
|
+
if (/^on(Pointer|Click|DoubleClick|ContextMenu|Wheel)/.test(key)) return changes.push([key, value, true, []]);
|
|
233
|
+
// Split dashed props
|
|
257
234
|
let entries = [];
|
|
258
235
|
if (key.includes('-')) entries = key.split('-');
|
|
259
|
-
changes.push([key, value, false, entries]);
|
|
236
|
+
changes.push([key, value, false, entries]);
|
|
260
237
|
|
|
238
|
+
// Reset pierced props
|
|
261
239
|
for (const prop in props) {
|
|
262
240
|
const value = props[prop];
|
|
263
241
|
if (prop.startsWith(`${key}-`)) changes.push([prop, value, false, prop.split('-')]);
|
|
264
242
|
}
|
|
265
243
|
});
|
|
266
|
-
const memoized = {
|
|
244
|
+
const memoized = {
|
|
245
|
+
...props
|
|
267
246
|
};
|
|
268
247
|
if (localState.memoizedProps && localState.memoizedProps.args) memoized.args = localState.memoizedProps.args;
|
|
269
248
|
if (localState.memoizedProps && localState.memoizedProps.attach) memoized.attach = localState.memoizedProps.attach;
|
|
@@ -271,11 +250,11 @@ function diffProps(instance, {
|
|
|
271
250
|
memoized,
|
|
272
251
|
changes
|
|
273
252
|
};
|
|
274
|
-
}
|
|
253
|
+
}
|
|
275
254
|
|
|
255
|
+
// This function applies a set of changes to the instance
|
|
276
256
|
function applyProps$1(instance, data) {
|
|
277
257
|
var _instance$__r3f3, _root$getState, _instance$__r3f4;
|
|
278
|
-
|
|
279
258
|
// Filter equals, events and reserved props
|
|
280
259
|
const localState = (_instance$__r3f3 = instance.__r3f) != null ? _instance$__r3f3 : {};
|
|
281
260
|
const root = localState.root;
|
|
@@ -284,104 +263,102 @@ function applyProps$1(instance, data) {
|
|
|
284
263
|
memoized,
|
|
285
264
|
changes
|
|
286
265
|
} = isDiffSet(data) ? data : diffProps(instance, data);
|
|
287
|
-
const prevHandlers = localState.eventCount;
|
|
266
|
+
const prevHandlers = localState.eventCount;
|
|
288
267
|
|
|
268
|
+
// Prepare memoized props
|
|
289
269
|
if (instance.__r3f) instance.__r3f.memoizedProps = memoized;
|
|
290
|
-
|
|
291
270
|
for (let i = 0; i < changes.length; i++) {
|
|
292
271
|
let [key, value, isEvent, keys] = changes[i];
|
|
293
272
|
let currentInstance = instance;
|
|
294
|
-
let targetProp = currentInstance[key];
|
|
273
|
+
let targetProp = currentInstance[key];
|
|
295
274
|
|
|
275
|
+
// Revolve dashed props
|
|
296
276
|
if (keys.length) {
|
|
297
|
-
targetProp = keys.reduce((acc, key) => acc[key], instance);
|
|
298
|
-
|
|
277
|
+
targetProp = keys.reduce((acc, key) => acc[key], instance);
|
|
278
|
+
// If the target is atomic, it forces us to switch the root
|
|
299
279
|
if (!(targetProp && targetProp.set)) {
|
|
300
280
|
const [name, ...reverseEntries] = keys.reverse();
|
|
301
281
|
currentInstance = reverseEntries.reverse().reduce((acc, key) => acc[key], instance);
|
|
302
282
|
key = name;
|
|
303
283
|
}
|
|
304
|
-
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// https://github.com/mrdoob/three.js/issues/21209
|
|
305
287
|
// HMR/fast-refresh relies on the ability to cancel out props, but threejs
|
|
306
288
|
// has no means to do this. Hence we curate a small collection of value-classes
|
|
307
289
|
// with their respective constructor/set arguments
|
|
308
290
|
// For removed props, try to set default values, if possible
|
|
309
|
-
|
|
310
|
-
|
|
311
291
|
if (value === DEFAULT + 'remove') {
|
|
312
|
-
if (
|
|
313
|
-
var _memoized$args;
|
|
314
|
-
|
|
315
|
-
// use the prop constructor to find the default it should be
|
|
316
|
-
value = new targetProp.constructor(...((_memoized$args = memoized.args) != null ? _memoized$args : []));
|
|
317
|
-
} else if (currentInstance.constructor) {
|
|
292
|
+
if (currentInstance.constructor) {
|
|
318
293
|
var _currentInstance$__r;
|
|
319
|
-
|
|
320
294
|
// create a blank slate of the instance and copy the particular parameter.
|
|
321
295
|
// @ts-ignore
|
|
322
296
|
const defaultClassCall = new currentInstance.constructor(...((_currentInstance$__r = currentInstance.__r3f.memoizedProps.args) != null ? _currentInstance$__r : []));
|
|
323
|
-
value = defaultClassCall[
|
|
324
|
-
|
|
325
|
-
if (defaultClassCall.dispose) defaultClassCall.dispose();
|
|
297
|
+
value = defaultClassCall[key];
|
|
298
|
+
// destroy the instance
|
|
299
|
+
if (defaultClassCall.dispose) defaultClassCall.dispose();
|
|
326
300
|
} else {
|
|
301
|
+
// instance does not have constructor, just set it to 0
|
|
327
302
|
value = 0;
|
|
328
303
|
}
|
|
329
|
-
}
|
|
330
|
-
|
|
304
|
+
}
|
|
331
305
|
|
|
306
|
+
// Deal with pointer events ...
|
|
332
307
|
if (isEvent) {
|
|
333
308
|
if (value) localState.handlers[key] = value;else delete localState.handlers[key];
|
|
334
309
|
localState.eventCount = Object.keys(localState.handlers).length;
|
|
335
|
-
}
|
|
310
|
+
}
|
|
311
|
+
// Special treatment for objects with support for set/copy, and layers
|
|
336
312
|
else if (targetProp && targetProp.set && (targetProp.copy || targetProp instanceof THREE.Layers)) {
|
|
337
313
|
// If value is an array
|
|
338
314
|
if (Array.isArray(value)) {
|
|
339
315
|
if (targetProp.fromArray) targetProp.fromArray(value);else targetProp.set(...value);
|
|
340
|
-
}
|
|
316
|
+
}
|
|
317
|
+
// Test again target.copy(class) next ...
|
|
341
318
|
else if (targetProp.copy && value && value.constructor && targetProp.constructor.name === value.constructor.name) {
|
|
342
319
|
targetProp.copy(value);
|
|
343
|
-
}
|
|
320
|
+
}
|
|
321
|
+
// If nothing else fits, just set the single value, ignore undefined
|
|
344
322
|
// https://github.com/pmndrs/react-three-fiber/issues/274
|
|
345
323
|
else if (value !== undefined) {
|
|
346
|
-
const isColor = targetProp instanceof THREE.Color;
|
|
347
|
-
|
|
348
|
-
if (!isColor && targetProp.setScalar) targetProp.setScalar(value);
|
|
349
|
-
|
|
350
|
-
else targetProp
|
|
324
|
+
const isColor = targetProp instanceof THREE.Color;
|
|
325
|
+
// Allow setting array scalars
|
|
326
|
+
if (!isColor && targetProp.setScalar) targetProp.setScalar(value);
|
|
327
|
+
// Layers have no copy function, we must therefore copy the mask property
|
|
328
|
+
else if (targetProp instanceof THREE.Layers && value instanceof THREE.Layers) targetProp.mask = value.mask;
|
|
329
|
+
// Otherwise just set ...
|
|
330
|
+
else targetProp.set(value);
|
|
331
|
+
// For versions of three which don't support THREE.ColorManagement,
|
|
351
332
|
// Auto-convert sRGB colors
|
|
352
333
|
// https://github.com/pmndrs/react-three-fiber/issues/344
|
|
353
|
-
|
|
354
334
|
const supportsColorManagement = ('ColorManagement' in THREE);
|
|
355
335
|
if (!supportsColorManagement && !rootState.linear && isColor) targetProp.convertSRGBToLinear();
|
|
356
|
-
}
|
|
357
|
-
|
|
336
|
+
}
|
|
337
|
+
// Else, just overwrite the value
|
|
358
338
|
} else {
|
|
359
|
-
currentInstance[key] = value;
|
|
339
|
+
currentInstance[key] = value;
|
|
340
|
+
// Auto-convert sRGB textures, for now ...
|
|
360
341
|
// https://github.com/pmndrs/react-three-fiber/issues/344
|
|
361
|
-
|
|
362
342
|
if (!rootState.linear && currentInstance[key] instanceof THREE.Texture) {
|
|
363
343
|
currentInstance[key].encoding = THREE.sRGBEncoding;
|
|
364
344
|
}
|
|
365
345
|
}
|
|
366
|
-
|
|
367
346
|
invalidateInstance(instance);
|
|
368
347
|
}
|
|
369
|
-
|
|
370
348
|
if (localState.parent && rootState.internal && instance.raycast && prevHandlers !== localState.eventCount) {
|
|
371
349
|
// Pre-emptively remove the instance from the interaction manager
|
|
372
350
|
const index = rootState.internal.interaction.indexOf(instance);
|
|
373
|
-
if (index > -1) rootState.internal.interaction.splice(index, 1);
|
|
374
|
-
|
|
351
|
+
if (index > -1) rootState.internal.interaction.splice(index, 1);
|
|
352
|
+
// Add the instance to the interaction manager only when it has handlers
|
|
375
353
|
if (localState.eventCount) rootState.internal.interaction.push(instance);
|
|
376
|
-
}
|
|
377
|
-
|
|
354
|
+
}
|
|
378
355
|
|
|
356
|
+
// Call the update lifecycle when it is being updated, but only when it is part of the scene
|
|
379
357
|
if (changes.length && (_instance$__r3f4 = instance.__r3f) != null && _instance$__r3f4.parent) updateInstance(instance);
|
|
380
358
|
return instance;
|
|
381
359
|
}
|
|
382
360
|
function invalidateInstance(instance) {
|
|
383
361
|
var _instance$__r3f5, _instance$__r3f5$root;
|
|
384
|
-
|
|
385
362
|
const state = (_instance$__r3f5 = instance.__r3f) == null ? void 0 : (_instance$__r3f5$root = _instance$__r3f5.root) == null ? void 0 : _instance$__r3f5$root.getState == null ? void 0 : _instance$__r3f5$root.getState();
|
|
386
363
|
if (state && state.internal.frames === 0) state.invalidate();
|
|
387
364
|
}
|
|
@@ -400,17 +377,16 @@ function updateCamera(camera, size) {
|
|
|
400
377
|
} else {
|
|
401
378
|
camera.aspect = size.width / size.height;
|
|
402
379
|
}
|
|
403
|
-
|
|
404
|
-
|
|
380
|
+
camera.updateProjectionMatrix();
|
|
381
|
+
// https://github.com/pmndrs/react-three-fiber/issues/178
|
|
405
382
|
// Update matrix world since the renderer is a frame late
|
|
406
|
-
|
|
407
383
|
camera.updateMatrixWorld();
|
|
408
384
|
}
|
|
409
385
|
}
|
|
386
|
+
|
|
410
387
|
/**
|
|
411
388
|
* Safely sets a deeply-nested value on an object.
|
|
412
389
|
*/
|
|
413
|
-
|
|
414
390
|
function setDeep(obj, value, keys) {
|
|
415
391
|
const key = keys.pop();
|
|
416
392
|
const target = keys.reduce((acc, key) => acc[key], obj);
|
|
@@ -419,19 +395,17 @@ function setDeep(obj, value, keys) {
|
|
|
419
395
|
|
|
420
396
|
function makeId(event) {
|
|
421
397
|
return (event.eventObject || event.object).uuid + '/' + event.index + event.instanceId;
|
|
422
|
-
}
|
|
423
|
-
// Gives React a clue as to how import the current interaction is
|
|
424
|
-
|
|
398
|
+
}
|
|
425
399
|
|
|
400
|
+
// https://github.com/facebook/react/tree/main/packages/react-reconciler#getcurrenteventpriority
|
|
401
|
+
// Gives React a clue as to how import the current interaction is
|
|
426
402
|
function getEventPriority() {
|
|
427
403
|
var _globalScope$event;
|
|
428
|
-
|
|
429
404
|
// Get a handle to the current global scope in window and worker contexts if able
|
|
430
405
|
// https://github.com/pmndrs/react-three-fiber/pull/2493
|
|
431
406
|
const globalScope = typeof self !== 'undefined' && self || typeof window !== 'undefined' && window;
|
|
432
407
|
if (!globalScope) return DefaultEventPriority;
|
|
433
408
|
const name = (_globalScope$event = globalScope.event) == null ? void 0 : _globalScope$event.type;
|
|
434
|
-
|
|
435
409
|
switch (name) {
|
|
436
410
|
case 'click':
|
|
437
411
|
case 'contextmenu':
|
|
@@ -440,7 +414,6 @@ function getEventPriority() {
|
|
|
440
414
|
case 'pointerdown':
|
|
441
415
|
case 'pointerup':
|
|
442
416
|
return DiscreteEventPriority;
|
|
443
|
-
|
|
444
417
|
case 'pointermove':
|
|
445
418
|
case 'pointerout':
|
|
446
419
|
case 'pointerover':
|
|
@@ -448,34 +421,31 @@ function getEventPriority() {
|
|
|
448
421
|
case 'pointerleave':
|
|
449
422
|
case 'wheel':
|
|
450
423
|
return ContinuousEventPriority;
|
|
451
|
-
|
|
452
424
|
default:
|
|
453
425
|
return DefaultEventPriority;
|
|
454
426
|
}
|
|
455
427
|
}
|
|
428
|
+
|
|
456
429
|
/**
|
|
457
430
|
* Release pointer captures.
|
|
458
431
|
* This is called by releasePointerCapture in the API, and when an object is removed.
|
|
459
432
|
*/
|
|
460
|
-
|
|
461
433
|
function releaseInternalPointerCapture(capturedMap, obj, captures, pointerId) {
|
|
462
434
|
const captureData = captures.get(obj);
|
|
463
|
-
|
|
464
435
|
if (captureData) {
|
|
465
|
-
captures.delete(obj);
|
|
466
|
-
|
|
436
|
+
captures.delete(obj);
|
|
437
|
+
// If this was the last capturing object for this pointer
|
|
467
438
|
if (captures.size === 0) {
|
|
468
439
|
capturedMap.delete(pointerId);
|
|
469
440
|
captureData.target.releasePointerCapture(pointerId);
|
|
470
441
|
}
|
|
471
442
|
}
|
|
472
443
|
}
|
|
473
|
-
|
|
474
444
|
function removeInteractivity(store, object) {
|
|
475
445
|
const {
|
|
476
446
|
internal
|
|
477
|
-
} = store.getState();
|
|
478
|
-
|
|
447
|
+
} = store.getState();
|
|
448
|
+
// Removes every trace of an object from the data store
|
|
479
449
|
internal.interaction = internal.interaction.filter(o => o !== object);
|
|
480
450
|
internal.initialHits = internal.initialHits.filter(o => o !== object);
|
|
481
451
|
internal.hovered.forEach((value, key) => {
|
|
@@ -498,106 +468,102 @@ function createEvents(store) {
|
|
|
498
468
|
const dy = event.offsetY - internal.initialClick[1];
|
|
499
469
|
return Math.round(Math.sqrt(dx * dx + dy * dy));
|
|
500
470
|
}
|
|
501
|
-
/** Returns true if an instance has a valid pointer-event registered, this excludes scroll, clicks etc */
|
|
502
|
-
|
|
503
471
|
|
|
472
|
+
/** Returns true if an instance has a valid pointer-event registered, this excludes scroll, clicks etc */
|
|
504
473
|
function filterPointerEvents(objects) {
|
|
505
474
|
return objects.filter(obj => ['Move', 'Over', 'Enter', 'Out', 'Leave'].some(name => {
|
|
506
475
|
var _r3f;
|
|
507
|
-
|
|
508
476
|
return (_r3f = obj.__r3f) == null ? void 0 : _r3f.handlers['onPointer' + name];
|
|
509
477
|
}));
|
|
510
478
|
}
|
|
511
|
-
|
|
512
479
|
function intersect(event, filter) {
|
|
513
480
|
const state = store.getState();
|
|
514
481
|
const duplicates = new Set();
|
|
515
|
-
const intersections = [];
|
|
516
|
-
|
|
517
|
-
const eventsObjects = filter ? filter(state.internal.interaction) : state.internal.interaction;
|
|
518
|
-
|
|
482
|
+
const intersections = [];
|
|
483
|
+
// Allow callers to eliminate event objects
|
|
484
|
+
const eventsObjects = filter ? filter(state.internal.interaction) : state.internal.interaction;
|
|
485
|
+
// Reset all raycaster cameras to undefined
|
|
519
486
|
for (let i = 0; i < eventsObjects.length; i++) {
|
|
520
487
|
const state = getRootState(eventsObjects[i]);
|
|
521
|
-
|
|
522
488
|
if (state) {
|
|
523
489
|
state.raycaster.camera = undefined;
|
|
524
490
|
}
|
|
525
491
|
}
|
|
526
|
-
|
|
527
492
|
if (!state.previousRoot) {
|
|
528
493
|
// Make sure root-level pointer and ray are set up
|
|
529
494
|
state.events.compute == null ? void 0 : state.events.compute(event, state);
|
|
530
495
|
}
|
|
531
|
-
|
|
532
496
|
function handleRaycast(obj) {
|
|
533
|
-
const state = getRootState(obj);
|
|
534
|
-
|
|
535
|
-
if (!state || !state.events.enabled || state.raycaster.camera === null) return [];
|
|
497
|
+
const state = getRootState(obj);
|
|
498
|
+
// Skip event handling when noEvents is set, or when the raycasters camera is null
|
|
499
|
+
if (!state || !state.events.enabled || state.raycaster.camera === null) return [];
|
|
536
500
|
|
|
501
|
+
// When the camera is undefined we have to call the event layers update function
|
|
537
502
|
if (state.raycaster.camera === undefined) {
|
|
538
503
|
var _state$previousRoot;
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
504
|
+
state.events.compute == null ? void 0 : state.events.compute(event, state, (_state$previousRoot = state.previousRoot) == null ? void 0 : _state$previousRoot.getState());
|
|
505
|
+
// If the camera is still undefined we have to skip this layer entirely
|
|
542
506
|
if (state.raycaster.camera === undefined) state.raycaster.camera = null;
|
|
543
|
-
}
|
|
544
|
-
|
|
507
|
+
}
|
|
545
508
|
|
|
509
|
+
// Intersect object by object
|
|
546
510
|
return state.raycaster.camera ? state.raycaster.intersectObject(obj, true) : [];
|
|
547
|
-
}
|
|
548
|
-
|
|
511
|
+
}
|
|
549
512
|
|
|
550
|
-
|
|
551
|
-
|
|
513
|
+
// Collect events
|
|
514
|
+
let hits = eventsObjects
|
|
515
|
+
// Intersect objects
|
|
516
|
+
.flatMap(handleRaycast)
|
|
517
|
+
// Sort by event priority and distance
|
|
552
518
|
.sort((a, b) => {
|
|
553
519
|
const aState = getRootState(a.object);
|
|
554
520
|
const bState = getRootState(b.object);
|
|
555
521
|
if (!aState || !bState) return a.distance - b.distance;
|
|
556
522
|
return bState.events.priority - aState.events.priority || a.distance - b.distance;
|
|
557
|
-
})
|
|
523
|
+
})
|
|
524
|
+
// Filter out duplicates
|
|
558
525
|
.filter(item => {
|
|
559
526
|
const id = makeId(item);
|
|
560
527
|
if (duplicates.has(id)) return false;
|
|
561
528
|
duplicates.add(id);
|
|
562
529
|
return true;
|
|
563
|
-
});
|
|
564
|
-
// Allow custom userland intersect sort order, this likely only makes sense on the root filter
|
|
530
|
+
});
|
|
565
531
|
|
|
566
|
-
|
|
532
|
+
// https://github.com/mrdoob/three.js/issues/16031
|
|
533
|
+
// Allow custom userland intersect sort order, this likely only makes sense on the root filter
|
|
534
|
+
if (state.events.filter) hits = state.events.filter(hits, state);
|
|
567
535
|
|
|
536
|
+
// Bubble up the events, find the event source (eventObject)
|
|
568
537
|
for (const hit of hits) {
|
|
569
|
-
let eventObject = hit.object;
|
|
570
|
-
|
|
538
|
+
let eventObject = hit.object;
|
|
539
|
+
// Bubble event up
|
|
571
540
|
while (eventObject) {
|
|
572
541
|
var _r3f2;
|
|
573
|
-
|
|
574
|
-
|
|
542
|
+
if ((_r3f2 = eventObject.__r3f) != null && _r3f2.eventCount) intersections.push({
|
|
543
|
+
...hit,
|
|
575
544
|
eventObject
|
|
576
545
|
});
|
|
577
546
|
eventObject = eventObject.parent;
|
|
578
547
|
}
|
|
579
|
-
}
|
|
580
|
-
|
|
548
|
+
}
|
|
581
549
|
|
|
550
|
+
// If the interaction is captured, make all capturing targets part of the intersect.
|
|
582
551
|
if ('pointerId' in event && state.internal.capturedMap.has(event.pointerId)) {
|
|
583
552
|
for (let captureData of state.internal.capturedMap.get(event.pointerId).values()) {
|
|
584
553
|
if (!duplicates.has(makeId(captureData.intersection))) intersections.push(captureData.intersection);
|
|
585
554
|
}
|
|
586
555
|
}
|
|
587
|
-
|
|
588
556
|
return intersections;
|
|
589
557
|
}
|
|
590
|
-
/** Handles intersections by forwarding them to handlers */
|
|
591
|
-
|
|
592
558
|
|
|
559
|
+
/** Handles intersections by forwarding them to handlers */
|
|
593
560
|
function handleIntersects(intersections, event, delta, callback) {
|
|
594
|
-
const rootState = store.getState();
|
|
595
|
-
|
|
561
|
+
const rootState = store.getState();
|
|
562
|
+
// If anything has been found, forward it to the event listeners
|
|
596
563
|
if (intersections.length) {
|
|
597
564
|
const localState = {
|
|
598
565
|
stopped: false
|
|
599
566
|
};
|
|
600
|
-
|
|
601
567
|
for (const hit of intersections) {
|
|
602
568
|
const state = getRootState(hit.object) || rootState;
|
|
603
569
|
const {
|
|
@@ -607,19 +573,15 @@ function createEvents(store) {
|
|
|
607
573
|
internal
|
|
608
574
|
} = state;
|
|
609
575
|
const unprojectedPoint = new THREE.Vector3(pointer.x, pointer.y, 0).unproject(camera);
|
|
610
|
-
|
|
611
576
|
const hasPointerCapture = id => {
|
|
612
577
|
var _internal$capturedMap, _internal$capturedMap2;
|
|
613
|
-
|
|
614
578
|
return (_internal$capturedMap = (_internal$capturedMap2 = internal.capturedMap.get(id)) == null ? void 0 : _internal$capturedMap2.has(hit.eventObject)) != null ? _internal$capturedMap : false;
|
|
615
579
|
};
|
|
616
|
-
|
|
617
580
|
const setPointerCapture = id => {
|
|
618
581
|
const captureData = {
|
|
619
582
|
intersection: hit,
|
|
620
583
|
target: event.target
|
|
621
584
|
};
|
|
622
|
-
|
|
623
585
|
if (internal.capturedMap.has(id)) {
|
|
624
586
|
// if the pointerId was previously captured, we add the hit to the
|
|
625
587
|
// event capturedMap.
|
|
@@ -629,29 +591,27 @@ function createEvents(store) {
|
|
|
629
591
|
// containing the hitObject, and the hit. hitObject is used for
|
|
630
592
|
// faster access.
|
|
631
593
|
internal.capturedMap.set(id, new Map([[hit.eventObject, captureData]]));
|
|
632
|
-
}
|
|
594
|
+
}
|
|
633
595
|
event.target.setPointerCapture(id);
|
|
634
596
|
};
|
|
635
|
-
|
|
636
597
|
const releasePointerCapture = id => {
|
|
637
598
|
const captures = internal.capturedMap.get(id);
|
|
638
|
-
|
|
639
599
|
if (captures) {
|
|
640
600
|
releaseInternalPointerCapture(internal.capturedMap, hit.eventObject, captures, id);
|
|
641
601
|
}
|
|
642
|
-
};
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
let extractEventProps = {}; // This iterates over the event's properties including the inherited ones. Native PointerEvents have most of their props as getters which are inherited, but polyfilled PointerEvents have them all as their own properties (i.e. not inherited). We can't use Object.keys() or Object.entries() as they only return "own" properties; nor Object.getPrototypeOf(event) as that *doesn't* return "own" properties, only inherited ones.
|
|
602
|
+
};
|
|
646
603
|
|
|
604
|
+
// Add native event props
|
|
605
|
+
let extractEventProps = {};
|
|
606
|
+
// This iterates over the event's properties including the inherited ones. Native PointerEvents have most of their props as getters which are inherited, but polyfilled PointerEvents have them all as their own properties (i.e. not inherited). We can't use Object.keys() or Object.entries() as they only return "own" properties; nor Object.getPrototypeOf(event) as that *doesn't* return "own" properties, only inherited ones.
|
|
647
607
|
for (let prop in event) {
|
|
648
|
-
let property = event[prop];
|
|
608
|
+
let property = event[prop];
|
|
609
|
+
// Only copy over atomics, leave functions alone as these should be
|
|
649
610
|
// called as event.nativeEvent.fn()
|
|
650
|
-
|
|
651
611
|
if (typeof property !== 'function') extractEventProps[prop] = property;
|
|
652
612
|
}
|
|
653
|
-
|
|
654
|
-
|
|
613
|
+
let raycastEvent = {
|
|
614
|
+
...hit,
|
|
655
615
|
...extractEventProps,
|
|
656
616
|
pointer,
|
|
657
617
|
intersections,
|
|
@@ -660,19 +620,21 @@ function createEvents(store) {
|
|
|
660
620
|
unprojectedPoint,
|
|
661
621
|
ray: raycaster.ray,
|
|
662
622
|
camera: camera,
|
|
663
|
-
|
|
664
623
|
// Hijack stopPropagation, which just sets a flag
|
|
665
624
|
stopPropagation() {
|
|
666
625
|
// https://github.com/pmndrs/react-three-fiber/issues/596
|
|
667
626
|
// Events are not allowed to stop propagation if the pointer has been captured
|
|
668
|
-
const capturesForPointer = 'pointerId' in event && internal.capturedMap.get(event.pointerId);
|
|
627
|
+
const capturesForPointer = 'pointerId' in event && internal.capturedMap.get(event.pointerId);
|
|
669
628
|
|
|
670
|
-
|
|
671
|
-
|
|
629
|
+
// We only authorize stopPropagation...
|
|
630
|
+
if (
|
|
631
|
+
// ...if this pointer hasn't been captured
|
|
632
|
+
!capturesForPointer ||
|
|
633
|
+
// ... or if the hit object is capturing the pointer
|
|
672
634
|
capturesForPointer.has(hit.eventObject)) {
|
|
673
|
-
raycastEvent.stopped = localState.stopped = true;
|
|
635
|
+
raycastEvent.stopped = localState.stopped = true;
|
|
636
|
+
// Propagation is stopped, remove all other hover records
|
|
674
637
|
// An event handler is only allowed to flush other handlers if it is hovered itself
|
|
675
|
-
|
|
676
638
|
if (internal.hovered.size && Array.from(internal.hovered.values()).find(i => i.eventObject === hit.eventObject)) {
|
|
677
639
|
// Objects cannot flush out higher up objects that have already caught the event
|
|
678
640
|
const higher = intersections.slice(0, intersections.indexOf(hit));
|
|
@@ -680,7 +642,6 @@ function createEvents(store) {
|
|
|
680
642
|
}
|
|
681
643
|
}
|
|
682
644
|
},
|
|
683
|
-
|
|
684
645
|
// there should be a distinction between target and currentTarget
|
|
685
646
|
target: {
|
|
686
647
|
hasPointerCapture,
|
|
@@ -693,22 +654,20 @@ function createEvents(store) {
|
|
|
693
654
|
releasePointerCapture
|
|
694
655
|
},
|
|
695
656
|
nativeEvent: event
|
|
696
|
-
};
|
|
697
|
-
|
|
698
|
-
callback(raycastEvent); // Event bubbling may be interrupted by stopPropagation
|
|
657
|
+
};
|
|
699
658
|
|
|
659
|
+
// Call subscribers
|
|
660
|
+
callback(raycastEvent);
|
|
661
|
+
// Event bubbling may be interrupted by stopPropagation
|
|
700
662
|
if (localState.stopped === true) break;
|
|
701
663
|
}
|
|
702
664
|
}
|
|
703
|
-
|
|
704
665
|
return intersections;
|
|
705
666
|
}
|
|
706
|
-
|
|
707
667
|
function cancelPointer(intersections) {
|
|
708
668
|
const {
|
|
709
669
|
internal
|
|
710
670
|
} = store.getState();
|
|
711
|
-
|
|
712
671
|
for (const hoveredObj of internal.hovered.values()) {
|
|
713
672
|
// When no objects were hit or the the hovered object wasn't found underneath the cursor
|
|
714
673
|
// we call onPointerOut and delete the object from the hovered-elements map
|
|
@@ -717,10 +676,10 @@ function createEvents(store) {
|
|
|
717
676
|
const instance = eventObject.__r3f;
|
|
718
677
|
const handlers = instance == null ? void 0 : instance.handlers;
|
|
719
678
|
internal.hovered.delete(makeId(hoveredObj));
|
|
720
|
-
|
|
721
679
|
if (instance != null && instance.eventCount) {
|
|
722
680
|
// Clear out intersects, they are outdated by now
|
|
723
|
-
const data = {
|
|
681
|
+
const data = {
|
|
682
|
+
...hoveredObj,
|
|
724
683
|
intersections
|
|
725
684
|
};
|
|
726
685
|
handlers.onPointerOut == null ? void 0 : handlers.onPointerOut(data);
|
|
@@ -729,27 +688,23 @@ function createEvents(store) {
|
|
|
729
688
|
}
|
|
730
689
|
}
|
|
731
690
|
}
|
|
732
|
-
|
|
733
691
|
function pointerMissed(event, objects) {
|
|
734
692
|
for (let i = 0; i < objects.length; i++) {
|
|
735
693
|
const instance = objects[i].__r3f;
|
|
736
694
|
instance == null ? void 0 : instance.handlers.onPointerMissed == null ? void 0 : instance.handlers.onPointerMissed(event);
|
|
737
695
|
}
|
|
738
696
|
}
|
|
739
|
-
|
|
740
697
|
function handlePointer(name) {
|
|
741
698
|
// Deal with cancelation
|
|
742
699
|
switch (name) {
|
|
743
700
|
case 'onPointerLeave':
|
|
744
701
|
case 'onPointerCancel':
|
|
745
702
|
return () => cancelPointer([]);
|
|
746
|
-
|
|
747
703
|
case 'onLostPointerCapture':
|
|
748
704
|
return event => {
|
|
749
705
|
const {
|
|
750
706
|
internal
|
|
751
707
|
} = store.getState();
|
|
752
|
-
|
|
753
708
|
if ('pointerId' in event && internal.capturedMap.has(event.pointerId)) {
|
|
754
709
|
// If the object event interface had onLostPointerCapture, we'd call it here on every
|
|
755
710
|
// object that's getting removed.
|
|
@@ -757,55 +712,54 @@ function createEvents(store) {
|
|
|
757
712
|
cancelPointer([]);
|
|
758
713
|
}
|
|
759
714
|
};
|
|
760
|
-
}
|
|
761
|
-
|
|
715
|
+
}
|
|
762
716
|
|
|
717
|
+
// Any other pointer goes here ...
|
|
763
718
|
return function handleEvent(event) {
|
|
764
719
|
const {
|
|
765
720
|
onPointerMissed,
|
|
766
721
|
internal
|
|
767
|
-
} = store.getState();
|
|
722
|
+
} = store.getState();
|
|
768
723
|
|
|
769
|
-
|
|
724
|
+
// prepareRay(event)
|
|
725
|
+
internal.lastEvent.current = event;
|
|
770
726
|
|
|
727
|
+
// Get fresh intersects
|
|
771
728
|
const isPointerMove = name === 'onPointerMove';
|
|
772
729
|
const isClickEvent = name === 'onClick' || name === 'onContextMenu' || name === 'onDoubleClick';
|
|
773
|
-
const filter = isPointerMove ? filterPointerEvents : undefined;
|
|
774
|
-
|
|
730
|
+
const filter = isPointerMove ? filterPointerEvents : undefined;
|
|
731
|
+
// const hits = patchIntersects(intersect(filter), event)
|
|
775
732
|
const hits = intersect(event, filter);
|
|
776
|
-
const delta = isClickEvent ? calculateDistance(event) : 0;
|
|
733
|
+
const delta = isClickEvent ? calculateDistance(event) : 0;
|
|
777
734
|
|
|
735
|
+
// Save initial coordinates on pointer-down
|
|
778
736
|
if (name === 'onPointerDown') {
|
|
779
737
|
internal.initialClick = [event.offsetX, event.offsetY];
|
|
780
738
|
internal.initialHits = hits.map(hit => hit.eventObject);
|
|
781
|
-
}
|
|
782
|
-
// Missed events have to come first in order to establish user-land side-effect clean up
|
|
783
|
-
|
|
739
|
+
}
|
|
784
740
|
|
|
741
|
+
// If a click yields no results, pass it back to the user as a miss
|
|
742
|
+
// Missed events have to come first in order to establish user-land side-effect clean up
|
|
785
743
|
if (isClickEvent && !hits.length) {
|
|
786
744
|
if (delta <= 2) {
|
|
787
745
|
pointerMissed(event, internal.interaction);
|
|
788
746
|
if (onPointerMissed) onPointerMissed(event);
|
|
789
747
|
}
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
|
|
748
|
+
}
|
|
749
|
+
// Take care of unhover
|
|
793
750
|
if (isPointerMove) cancelPointer(hits);
|
|
794
|
-
|
|
795
751
|
function onIntersect(data) {
|
|
796
752
|
const eventObject = data.eventObject;
|
|
797
753
|
const instance = eventObject.__r3f;
|
|
798
|
-
const handlers = instance == null ? void 0 : instance.handlers;
|
|
799
|
-
|
|
754
|
+
const handlers = instance == null ? void 0 : instance.handlers;
|
|
755
|
+
// Check presence of handlers
|
|
800
756
|
if (!(instance != null && instance.eventCount)) return;
|
|
801
|
-
|
|
802
757
|
if (isPointerMove) {
|
|
803
758
|
// Move event ...
|
|
804
759
|
if (handlers.onPointerOver || handlers.onPointerEnter || handlers.onPointerOut || handlers.onPointerLeave) {
|
|
805
760
|
// When enter or out is present take care of hover-state
|
|
806
761
|
const id = makeId(data);
|
|
807
762
|
const hoveredItem = internal.hovered.get(id);
|
|
808
|
-
|
|
809
763
|
if (!hoveredItem) {
|
|
810
764
|
// If the object wasn't previously hovered, book it and call its handler
|
|
811
765
|
internal.hovered.set(id, data);
|
|
@@ -815,21 +769,19 @@ function createEvents(store) {
|
|
|
815
769
|
// If the object was previously hovered and stopped, we shouldn't allow other items to proceed
|
|
816
770
|
data.stopPropagation();
|
|
817
771
|
}
|
|
818
|
-
}
|
|
819
|
-
|
|
820
|
-
|
|
772
|
+
}
|
|
773
|
+
// Call mouse move
|
|
821
774
|
handlers.onPointerMove == null ? void 0 : handlers.onPointerMove(data);
|
|
822
775
|
} else {
|
|
823
776
|
// All other events ...
|
|
824
777
|
const handler = handlers[name];
|
|
825
|
-
|
|
826
778
|
if (handler) {
|
|
827
779
|
// Forward all events back to their respective handlers with the exception of click events,
|
|
828
780
|
// which must use the initial target
|
|
829
781
|
if (!isClickEvent || internal.initialHits.includes(eventObject)) {
|
|
830
782
|
// Missed events have to come first
|
|
831
|
-
pointerMissed(event, internal.interaction.filter(object => !internal.initialHits.includes(object)));
|
|
832
|
-
|
|
783
|
+
pointerMissed(event, internal.interaction.filter(object => !internal.initialHits.includes(object)));
|
|
784
|
+
// Now call the handler
|
|
833
785
|
handler(data);
|
|
834
786
|
}
|
|
835
787
|
} else {
|
|
@@ -840,22 +792,19 @@ function createEvents(store) {
|
|
|
840
792
|
}
|
|
841
793
|
}
|
|
842
794
|
}
|
|
843
|
-
|
|
844
795
|
handleIntersects(hits, event, delta, onIntersect);
|
|
845
796
|
};
|
|
846
797
|
}
|
|
847
|
-
|
|
848
798
|
return {
|
|
849
799
|
handlePointer
|
|
850
800
|
};
|
|
851
801
|
}
|
|
852
802
|
|
|
853
803
|
let catalogue = {};
|
|
854
|
-
|
|
855
|
-
|
|
804
|
+
let extend = objects => void (catalogue = {
|
|
805
|
+
...catalogue,
|
|
856
806
|
...objects
|
|
857
807
|
});
|
|
858
|
-
|
|
859
808
|
function createRenderer(_roots, _getEventPriority) {
|
|
860
809
|
function createInstance(type, {
|
|
861
810
|
args = [],
|
|
@@ -864,7 +813,6 @@ function createRenderer(_roots, _getEventPriority) {
|
|
|
864
813
|
}, root) {
|
|
865
814
|
let name = `${type[0].toUpperCase()}${type.slice(1)}`;
|
|
866
815
|
let instance;
|
|
867
|
-
|
|
868
816
|
if (type === 'primitive') {
|
|
869
817
|
if (props.object === undefined) throw new Error("R3F: Primitives without 'object' are invalid!");
|
|
870
818
|
const object = props.object;
|
|
@@ -876,15 +824,15 @@ function createRenderer(_roots, _getEventPriority) {
|
|
|
876
824
|
});
|
|
877
825
|
} else {
|
|
878
826
|
const target = catalogue[name];
|
|
879
|
-
|
|
880
827
|
if (!target) {
|
|
881
828
|
throw new Error(`R3F: ${name} is not part of the THREE namespace! Did you forget to extend? See: https://docs.pmnd.rs/react-three-fiber/api/objects#using-3rd-party-objects-declaratively`);
|
|
882
|
-
}
|
|
829
|
+
}
|
|
883
830
|
|
|
831
|
+
// Throw if an object or literal was passed for args
|
|
832
|
+
if (!Array.isArray(args)) throw new Error('R3F: The args prop must be an array!');
|
|
884
833
|
|
|
885
|
-
|
|
834
|
+
// Instanciate new object, link it to the root
|
|
886
835
|
// Append memoized props with args so it's not forgotten
|
|
887
|
-
|
|
888
836
|
instance = prepare(new target(...args), {
|
|
889
837
|
type,
|
|
890
838
|
root,
|
|
@@ -894,27 +842,24 @@ function createRenderer(_roots, _getEventPriority) {
|
|
|
894
842
|
args
|
|
895
843
|
}
|
|
896
844
|
});
|
|
897
|
-
}
|
|
898
|
-
|
|
845
|
+
}
|
|
899
846
|
|
|
847
|
+
// Auto-attach geometries and materials
|
|
900
848
|
if (instance.__r3f.attach === undefined) {
|
|
901
849
|
if (instance instanceof THREE.BufferGeometry) instance.__r3f.attach = 'geometry';else if (instance instanceof THREE.Material) instance.__r3f.attach = 'material';
|
|
902
|
-
}
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
// It should NOT call onUpdate on object instanciation, because it hasn't been added to the
|
|
903
853
|
// view yet. If the callback relies on references for instance, they won't be ready yet, this is
|
|
904
854
|
// why it passes "true" here
|
|
905
855
|
// There is no reason to apply props to injects
|
|
906
|
-
|
|
907
|
-
|
|
908
856
|
if (name !== 'inject') applyProps$1(instance, props);
|
|
909
857
|
return instance;
|
|
910
858
|
}
|
|
911
|
-
|
|
912
859
|
function appendChild(parentInstance, child) {
|
|
913
860
|
let added = false;
|
|
914
|
-
|
|
915
861
|
if (child) {
|
|
916
862
|
var _child$__r3f, _parentInstance$__r3f;
|
|
917
|
-
|
|
918
863
|
// The attach attribute implies that the object attaches itself on the parent
|
|
919
864
|
if ((_child$__r3f = child.__r3f) != null && _child$__r3f.attach) {
|
|
920
865
|
attach(parentInstance, child, child.__r3f.attach);
|
|
@@ -922,10 +867,9 @@ function createRenderer(_roots, _getEventPriority) {
|
|
|
922
867
|
// add in the usual parent-child way
|
|
923
868
|
parentInstance.add(child);
|
|
924
869
|
added = true;
|
|
925
|
-
}
|
|
870
|
+
}
|
|
871
|
+
// This is for anything that used attach, and for non-Object3Ds that don't get attached to props;
|
|
926
872
|
// that is, anything that's a child in React but not a child in the scenegraph.
|
|
927
|
-
|
|
928
|
-
|
|
929
873
|
if (!added) (_parentInstance$__r3f = parentInstance.__r3f) == null ? void 0 : _parentInstance$__r3f.objects.push(child);
|
|
930
874
|
if (!child.__r3f) prepare(child, {});
|
|
931
875
|
child.__r3f.parent = parentInstance;
|
|
@@ -933,13 +877,10 @@ function createRenderer(_roots, _getEventPriority) {
|
|
|
933
877
|
invalidateInstance(child);
|
|
934
878
|
}
|
|
935
879
|
}
|
|
936
|
-
|
|
937
880
|
function insertBefore(parentInstance, child, beforeChild) {
|
|
938
881
|
let added = false;
|
|
939
|
-
|
|
940
882
|
if (child) {
|
|
941
883
|
var _child$__r3f2, _parentInstance$__r3f2;
|
|
942
|
-
|
|
943
884
|
if ((_child$__r3f2 = child.__r3f) != null && _child$__r3f2.attach) {
|
|
944
885
|
attach(parentInstance, child, child.__r3f.attach);
|
|
945
886
|
} else if (child.isObject3D && parentInstance.isObject3D) {
|
|
@@ -952,7 +893,6 @@ function createRenderer(_roots, _getEventPriority) {
|
|
|
952
893
|
parentInstance.children = [...restSiblings.slice(0, index), child, ...restSiblings.slice(index)];
|
|
953
894
|
added = true;
|
|
954
895
|
}
|
|
955
|
-
|
|
956
896
|
if (!added) (_parentInstance$__r3f2 = parentInstance.__r3f) == null ? void 0 : _parentInstance$__r3f2.objects.push(child);
|
|
957
897
|
if (!child.__r3f) prepare(child, {});
|
|
958
898
|
child.__r3f.parent = parentInstance;
|
|
@@ -960,31 +900,29 @@ function createRenderer(_roots, _getEventPriority) {
|
|
|
960
900
|
invalidateInstance(child);
|
|
961
901
|
}
|
|
962
902
|
}
|
|
963
|
-
|
|
964
903
|
function removeRecursive(array, parent, dispose = false) {
|
|
965
904
|
if (array) [...array].forEach(child => removeChild(parent, child, dispose));
|
|
966
905
|
}
|
|
967
|
-
|
|
968
906
|
function removeChild(parentInstance, child, dispose) {
|
|
969
907
|
if (child) {
|
|
970
908
|
var _parentInstance$__r3f3, _child$__r3f3, _child$__r3f5;
|
|
971
|
-
|
|
972
909
|
// Clear the parent reference
|
|
973
|
-
if (child.__r3f) child.__r3f.parent = null;
|
|
974
|
-
|
|
975
|
-
if ((_parentInstance$__r3f3 = parentInstance.__r3f) != null && _parentInstance$__r3f3.objects) parentInstance.__r3f.objects = parentInstance.__r3f.objects.filter(x => x !== child);
|
|
976
|
-
|
|
910
|
+
if (child.__r3f) child.__r3f.parent = null;
|
|
911
|
+
// Remove child from the parents objects
|
|
912
|
+
if ((_parentInstance$__r3f3 = parentInstance.__r3f) != null && _parentInstance$__r3f3.objects) parentInstance.__r3f.objects = parentInstance.__r3f.objects.filter(x => x !== child);
|
|
913
|
+
// Remove attachment
|
|
977
914
|
if ((_child$__r3f3 = child.__r3f) != null && _child$__r3f3.attach) {
|
|
978
915
|
detach(parentInstance, child, child.__r3f.attach);
|
|
979
916
|
} else if (child.isObject3D && parentInstance.isObject3D) {
|
|
980
917
|
var _child$__r3f4;
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
918
|
+
parentInstance.remove(child);
|
|
919
|
+
// Remove interactivity
|
|
984
920
|
if ((_child$__r3f4 = child.__r3f) != null && _child$__r3f4.root) {
|
|
985
921
|
removeInteractivity(child.__r3f.root, child);
|
|
986
922
|
}
|
|
987
|
-
}
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
// Allow objects to bail out of recursive dispose altogether by passing dispose={null}
|
|
988
926
|
// Never dispose of primitives because their state may be kept outside of React!
|
|
989
927
|
// In order for an object to be able to dispose it has to have
|
|
990
928
|
// - a dispose method,
|
|
@@ -993,29 +931,27 @@ function createRenderer(_roots, _getEventPriority) {
|
|
|
993
931
|
//
|
|
994
932
|
// Since disposal is recursive, we can check the optional dispose arg, which will be undefined
|
|
995
933
|
// when the reconciler calls it, but then carry our own check recursively
|
|
996
|
-
|
|
997
|
-
|
|
998
934
|
const isPrimitive = (_child$__r3f5 = child.__r3f) == null ? void 0 : _child$__r3f5.primitive;
|
|
999
|
-
const shouldDispose = dispose === undefined ? child.dispose !== null && !isPrimitive : dispose;
|
|
1000
|
-
// attached to them declaratively ...
|
|
935
|
+
const shouldDispose = dispose === undefined ? child.dispose !== null && !isPrimitive : dispose;
|
|
1001
936
|
|
|
937
|
+
// Remove nested child objects. Primitives should not have objects and children that are
|
|
938
|
+
// attached to them declaratively ...
|
|
1002
939
|
if (!isPrimitive) {
|
|
1003
940
|
var _child$__r3f6;
|
|
1004
|
-
|
|
1005
941
|
removeRecursive((_child$__r3f6 = child.__r3f) == null ? void 0 : _child$__r3f6.objects, child, shouldDispose);
|
|
1006
942
|
removeRecursive(child.children, child, shouldDispose);
|
|
1007
|
-
}
|
|
1008
|
-
|
|
943
|
+
}
|
|
1009
944
|
|
|
945
|
+
// Remove references
|
|
1010
946
|
if (child.__r3f) {
|
|
1011
947
|
delete child.__r3f.root;
|
|
1012
948
|
delete child.__r3f.objects;
|
|
1013
949
|
delete child.__r3f.handlers;
|
|
1014
950
|
delete child.__r3f.memoizedProps;
|
|
1015
951
|
if (!isPrimitive) delete child.__r3f;
|
|
1016
|
-
}
|
|
1017
|
-
|
|
952
|
+
}
|
|
1018
953
|
|
|
954
|
+
// Dispose item whenever the reconciler feels like it
|
|
1019
955
|
if (shouldDispose && child.dispose && child.type !== 'Scene') {
|
|
1020
956
|
unstable_scheduleCallback(unstable_IdlePriority, () => {
|
|
1021
957
|
try {
|
|
@@ -1025,61 +961,51 @@ function createRenderer(_roots, _getEventPriority) {
|
|
|
1025
961
|
}
|
|
1026
962
|
});
|
|
1027
963
|
}
|
|
1028
|
-
|
|
1029
964
|
invalidateInstance(parentInstance);
|
|
1030
965
|
}
|
|
1031
966
|
}
|
|
1032
|
-
|
|
1033
967
|
function switchInstance(instance, type, newProps, fiber) {
|
|
1034
968
|
var _instance$__r3f;
|
|
1035
|
-
|
|
1036
969
|
const parent = (_instance$__r3f = instance.__r3f) == null ? void 0 : _instance$__r3f.parent;
|
|
1037
970
|
if (!parent) return;
|
|
1038
|
-
const newInstance = createInstance(type, newProps, instance.__r3f.root);
|
|
971
|
+
const newInstance = createInstance(type, newProps, instance.__r3f.root);
|
|
972
|
+
|
|
973
|
+
// https://github.com/pmndrs/react-three-fiber/issues/1348
|
|
1039
974
|
// When args change the instance has to be re-constructed, which then
|
|
1040
975
|
// forces r3f to re-parent the children and non-scene objects
|
|
1041
|
-
|
|
1042
976
|
if (instance.children) {
|
|
1043
977
|
for (const child of instance.children) {
|
|
1044
978
|
if (child.__r3f) appendChild(newInstance, child);
|
|
1045
979
|
}
|
|
1046
|
-
|
|
1047
980
|
instance.children = instance.children.filter(child => !child.__r3f);
|
|
1048
981
|
}
|
|
1049
|
-
|
|
1050
982
|
instance.__r3f.objects.forEach(child => appendChild(newInstance, child));
|
|
1051
|
-
|
|
1052
983
|
instance.__r3f.objects = [];
|
|
1053
|
-
|
|
1054
984
|
if (!instance.__r3f.autoRemovedBeforeAppend) {
|
|
1055
985
|
removeChild(parent, instance);
|
|
1056
986
|
}
|
|
1057
|
-
|
|
1058
987
|
if (newInstance.parent) {
|
|
1059
988
|
newInstance.__r3f.autoRemovedBeforeAppend = true;
|
|
1060
989
|
}
|
|
990
|
+
appendChild(parent, newInstance);
|
|
1061
991
|
|
|
1062
|
-
|
|
1063
|
-
|
|
992
|
+
// Re-bind event handlers
|
|
1064
993
|
if (newInstance.raycast && newInstance.__r3f.eventCount) {
|
|
1065
994
|
const rootState = newInstance.__r3f.root.getState();
|
|
1066
|
-
|
|
1067
995
|
rootState.internal.interaction.push(newInstance);
|
|
1068
|
-
}
|
|
996
|
+
}
|
|
1069
997
|
[fiber, fiber.alternate].forEach(fiber => {
|
|
1070
998
|
if (fiber !== null) {
|
|
1071
999
|
fiber.stateNode = newInstance;
|
|
1072
|
-
|
|
1073
1000
|
if (fiber.ref) {
|
|
1074
1001
|
if (typeof fiber.ref === 'function') fiber.ref(newInstance);else fiber.ref.current = newInstance;
|
|
1075
1002
|
}
|
|
1076
1003
|
}
|
|
1077
1004
|
});
|
|
1078
|
-
}
|
|
1079
|
-
|
|
1005
|
+
}
|
|
1080
1006
|
|
|
1007
|
+
// Don't handle text instances, warn on undefined behavior
|
|
1081
1008
|
const handleTextInstance = () => console.warn('Text is not allowed in the R3F tree! This could be stray whitespace or characters.');
|
|
1082
|
-
|
|
1083
1009
|
const reconciler = Reconciler({
|
|
1084
1010
|
createInstance,
|
|
1085
1011
|
removeChild,
|
|
@@ -1092,11 +1018,13 @@ function createRenderer(_roots, _getEventPriority) {
|
|
|
1092
1018
|
supportsHydration: false,
|
|
1093
1019
|
noTimeout: -1,
|
|
1094
1020
|
appendChildToContainer: (container, child) => {
|
|
1095
|
-
if (!child) return;
|
|
1021
|
+
if (!child) return;
|
|
1096
1022
|
|
|
1023
|
+
// Don't append to unmounted container
|
|
1097
1024
|
const scene = container.getState().scene;
|
|
1098
|
-
if (!scene.__r3f) return;
|
|
1025
|
+
if (!scene.__r3f) return;
|
|
1099
1026
|
|
|
1027
|
+
// Link current root to the default scene
|
|
1100
1028
|
scene.__r3f.root = container;
|
|
1101
1029
|
appendChild(scene, child);
|
|
1102
1030
|
},
|
|
@@ -1105,24 +1033,22 @@ function createRenderer(_roots, _getEventPriority) {
|
|
|
1105
1033
|
removeChild(container.getState().scene, child);
|
|
1106
1034
|
},
|
|
1107
1035
|
insertInContainerBefore: (container, child, beforeChild) => {
|
|
1108
|
-
if (!child || !beforeChild) return;
|
|
1036
|
+
if (!child || !beforeChild) return;
|
|
1109
1037
|
|
|
1038
|
+
// Don't append to unmounted container
|
|
1110
1039
|
const scene = container.getState().scene;
|
|
1111
1040
|
if (!scene.__r3f) return;
|
|
1112
1041
|
insertBefore(scene, child, beforeChild);
|
|
1113
1042
|
},
|
|
1114
1043
|
getRootHostContext: () => null,
|
|
1115
1044
|
getChildHostContext: parentHostContext => parentHostContext,
|
|
1116
|
-
|
|
1117
1045
|
finalizeInitialChildren(instance) {
|
|
1118
1046
|
var _instance$__r3f2;
|
|
1119
|
-
|
|
1120
|
-
|
|
1047
|
+
const localState = (_instance$__r3f2 = instance == null ? void 0 : instance.__r3f) != null ? _instance$__r3f2 : {};
|
|
1048
|
+
// https://github.com/facebook/react/issues/20271
|
|
1121
1049
|
// Returning true will trigger commitMount
|
|
1122
|
-
|
|
1123
1050
|
return Boolean(localState.handlers);
|
|
1124
1051
|
},
|
|
1125
|
-
|
|
1126
1052
|
prepareUpdate(instance, _type, oldProps, newProps) {
|
|
1127
1053
|
// Create diff-sets
|
|
1128
1054
|
if (instance.__r3f.primitive && newProps.object && newProps.object !== instance) {
|
|
@@ -1138,47 +1064,44 @@ function createRenderer(_roots, _getEventPriority) {
|
|
|
1138
1064
|
args: argsOld = [],
|
|
1139
1065
|
children: cO,
|
|
1140
1066
|
...restOld
|
|
1141
|
-
} = oldProps;
|
|
1067
|
+
} = oldProps;
|
|
1142
1068
|
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
if (argsNew.some((value, index) => value !== argsOld[index])) return [true]; // Create a diff-set, flag if there are any changes
|
|
1069
|
+
// Throw if an object or literal was passed for args
|
|
1070
|
+
if (!Array.isArray(argsNew)) throw new Error('R3F: the args prop must be an array!');
|
|
1146
1071
|
|
|
1072
|
+
// If it has new props or arguments, then it needs to be re-instantiated
|
|
1073
|
+
if (argsNew.some((value, index) => value !== argsOld[index])) return [true];
|
|
1074
|
+
// Create a diff-set, flag if there are any changes
|
|
1147
1075
|
const diff = diffProps(instance, restNew, restOld, true);
|
|
1148
|
-
if (diff.changes.length) return [false, diff];
|
|
1076
|
+
if (diff.changes.length) return [false, diff];
|
|
1149
1077
|
|
|
1078
|
+
// Otherwise do not touch the instance
|
|
1150
1079
|
return null;
|
|
1151
1080
|
}
|
|
1152
1081
|
},
|
|
1153
|
-
|
|
1154
1082
|
commitUpdate(instance, [reconstruct, diff], type, _oldProps, newProps, fiber) {
|
|
1155
1083
|
// Reconstruct when args or <primitive object={...} have changes
|
|
1156
|
-
if (reconstruct) switchInstance(instance, type, newProps, fiber);
|
|
1084
|
+
if (reconstruct) switchInstance(instance, type, newProps, fiber);
|
|
1085
|
+
// Otherwise just overwrite props
|
|
1157
1086
|
else applyProps$1(instance, diff);
|
|
1158
1087
|
},
|
|
1159
|
-
|
|
1160
1088
|
commitMount(instance, _type, _props, _int) {
|
|
1161
1089
|
var _instance$__r3f3;
|
|
1162
|
-
|
|
1163
1090
|
// https://github.com/facebook/react/issues/20271
|
|
1164
1091
|
// This will make sure events are only added once to the central container
|
|
1165
1092
|
const localState = (_instance$__r3f3 = instance.__r3f) != null ? _instance$__r3f3 : {};
|
|
1166
|
-
|
|
1167
1093
|
if (instance.raycast && localState.handlers && localState.eventCount) {
|
|
1168
1094
|
instance.__r3f.root.getState().internal.interaction.push(instance);
|
|
1169
1095
|
}
|
|
1170
1096
|
},
|
|
1171
|
-
|
|
1172
1097
|
getPublicInstance: instance => instance,
|
|
1173
1098
|
prepareForCommit: () => null,
|
|
1174
1099
|
preparePortalMount: container => prepare(container.getState().scene),
|
|
1175
1100
|
resetAfterCommit: () => {},
|
|
1176
1101
|
shouldSetTextContent: () => false,
|
|
1177
1102
|
clearContainer: () => false,
|
|
1178
|
-
|
|
1179
1103
|
hideInstance(instance) {
|
|
1180
1104
|
var _instance$__r3f4;
|
|
1181
|
-
|
|
1182
1105
|
// Detach while the instance is hidden
|
|
1183
1106
|
const {
|
|
1184
1107
|
attach: type,
|
|
@@ -1188,10 +1111,8 @@ function createRenderer(_roots, _getEventPriority) {
|
|
|
1188
1111
|
if (instance.isObject3D) instance.visible = false;
|
|
1189
1112
|
invalidateInstance(instance);
|
|
1190
1113
|
},
|
|
1191
|
-
|
|
1192
1114
|
unhideInstance(instance, props) {
|
|
1193
1115
|
var _instance$__r3f5;
|
|
1194
|
-
|
|
1195
1116
|
// Re-attach when the instance is unhidden
|
|
1196
1117
|
const {
|
|
1197
1118
|
attach: type,
|
|
@@ -1201,7 +1122,6 @@ function createRenderer(_roots, _getEventPriority) {
|
|
|
1201
1122
|
if (instance.isObject3D && props.visible == null || props.visible) instance.visible = true;
|
|
1202
1123
|
invalidateInstance(instance);
|
|
1203
1124
|
},
|
|
1204
|
-
|
|
1205
1125
|
createTextInstance: handleTextInstance,
|
|
1206
1126
|
hideTextInstance: handleTextInstance,
|
|
1207
1127
|
unhideTextInstance: handleTextInstance,
|
|
@@ -1222,16 +1142,15 @@ function createRenderer(_roots, _getEventPriority) {
|
|
|
1222
1142
|
};
|
|
1223
1143
|
}
|
|
1224
1144
|
|
|
1145
|
+
// Keys that shouldn't be copied between R3F stores
|
|
1225
1146
|
const privateKeys = ['set', 'get', 'setSize', 'setFrameloop', 'setDpr', 'events', 'invalidate', 'advance', 'size', 'viewport'];
|
|
1226
1147
|
const isRenderer = def => !!(def != null && def.render);
|
|
1227
1148
|
const context = /*#__PURE__*/React.createContext(null);
|
|
1228
|
-
|
|
1229
1149
|
const createStore = (invalidate, advance) => {
|
|
1230
1150
|
const rootState = create((set, get) => {
|
|
1231
1151
|
const position = new THREE.Vector3();
|
|
1232
1152
|
const defaultTarget = new THREE.Vector3();
|
|
1233
1153
|
const tempTarget = new THREE.Vector3();
|
|
1234
|
-
|
|
1235
1154
|
function getCurrentViewport(camera = get().camera, target = defaultTarget, size = get().size) {
|
|
1236
1155
|
const {
|
|
1237
1156
|
width,
|
|
@@ -1242,7 +1161,6 @@ const createStore = (invalidate, advance) => {
|
|
|
1242
1161
|
const aspect = width / height;
|
|
1243
1162
|
if (target instanceof THREE.Vector3) tempTarget.copy(target);else tempTarget.set(...target);
|
|
1244
1163
|
const distance = camera.getWorldPosition(position).distanceTo(tempTarget);
|
|
1245
|
-
|
|
1246
1164
|
if (isOrthographicCamera(camera)) {
|
|
1247
1165
|
return {
|
|
1248
1166
|
width: width / camera.zoom,
|
|
@@ -1255,9 +1173,7 @@ const createStore = (invalidate, advance) => {
|
|
|
1255
1173
|
};
|
|
1256
1174
|
} else {
|
|
1257
1175
|
const fov = camera.fov * Math.PI / 180; // convert vertical fov to radians
|
|
1258
|
-
|
|
1259
1176
|
const h = 2 * Math.tan(fov / 2) * distance; // visible height
|
|
1260
|
-
|
|
1261
1177
|
const w = h * (width / height);
|
|
1262
1178
|
return {
|
|
1263
1179
|
width: w,
|
|
@@ -1270,15 +1186,13 @@ const createStore = (invalidate, advance) => {
|
|
|
1270
1186
|
};
|
|
1271
1187
|
}
|
|
1272
1188
|
}
|
|
1273
|
-
|
|
1274
1189
|
let performanceTimeout = undefined;
|
|
1275
|
-
|
|
1276
1190
|
const setPerformanceCurrent = current => set(state => ({
|
|
1277
|
-
performance: {
|
|
1191
|
+
performance: {
|
|
1192
|
+
...state.performance,
|
|
1278
1193
|
current
|
|
1279
1194
|
}
|
|
1280
1195
|
}));
|
|
1281
|
-
|
|
1282
1196
|
const pointer = new THREE.Vector2();
|
|
1283
1197
|
const rootState = {
|
|
1284
1198
|
set,
|
|
@@ -1311,12 +1225,12 @@ const createStore = (invalidate, advance) => {
|
|
|
1311
1225
|
max: 1,
|
|
1312
1226
|
debounce: 200,
|
|
1313
1227
|
regress: () => {
|
|
1314
|
-
const state = get();
|
|
1315
|
-
|
|
1316
|
-
if (performanceTimeout) clearTimeout(performanceTimeout);
|
|
1317
|
-
|
|
1318
|
-
if (state.performance.current !== state.performance.min) setPerformanceCurrent(state.performance.min);
|
|
1319
|
-
|
|
1228
|
+
const state = get();
|
|
1229
|
+
// Clear timeout
|
|
1230
|
+
if (performanceTimeout) clearTimeout(performanceTimeout);
|
|
1231
|
+
// Set lower bound performance
|
|
1232
|
+
if (state.performance.current !== state.performance.min) setPerformanceCurrent(state.performance.min);
|
|
1233
|
+
// Go back to upper bound performance after a while unless something regresses meanwhile
|
|
1320
1234
|
performanceTimeout = setTimeout(() => setPerformanceCurrent(get().performance.max), state.performance.debounce);
|
|
1321
1235
|
}
|
|
1322
1236
|
},
|
|
@@ -1339,8 +1253,10 @@ const createStore = (invalidate, advance) => {
|
|
|
1339
1253
|
factor: 0,
|
|
1340
1254
|
getCurrentViewport
|
|
1341
1255
|
},
|
|
1342
|
-
setEvents: events => set(state => ({
|
|
1343
|
-
|
|
1256
|
+
setEvents: events => set(state => ({
|
|
1257
|
+
...state,
|
|
1258
|
+
events: {
|
|
1259
|
+
...state.events,
|
|
1344
1260
|
...events
|
|
1345
1261
|
}
|
|
1346
1262
|
})),
|
|
@@ -1355,7 +1271,8 @@ const createStore = (invalidate, advance) => {
|
|
|
1355
1271
|
};
|
|
1356
1272
|
set(state => ({
|
|
1357
1273
|
size,
|
|
1358
|
-
viewport: {
|
|
1274
|
+
viewport: {
|
|
1275
|
+
...state.viewport,
|
|
1359
1276
|
...getCurrentViewport(camera, defaultTarget, size)
|
|
1360
1277
|
}
|
|
1361
1278
|
}));
|
|
@@ -1363,23 +1280,23 @@ const createStore = (invalidate, advance) => {
|
|
|
1363
1280
|
setDpr: dpr => set(state => {
|
|
1364
1281
|
const resolved = calculateDpr(dpr);
|
|
1365
1282
|
return {
|
|
1366
|
-
viewport: {
|
|
1283
|
+
viewport: {
|
|
1284
|
+
...state.viewport,
|
|
1367
1285
|
dpr: resolved,
|
|
1368
1286
|
initialDpr: state.viewport.initialDpr || resolved
|
|
1369
1287
|
}
|
|
1370
1288
|
};
|
|
1371
1289
|
}),
|
|
1372
1290
|
setFrameloop: (frameloop = 'always') => {
|
|
1373
|
-
const clock = get().clock;
|
|
1291
|
+
const clock = get().clock;
|
|
1374
1292
|
|
|
1293
|
+
// if frameloop === "never" clock.elapsedTime is updated using advance(timestamp)
|
|
1375
1294
|
clock.stop();
|
|
1376
1295
|
clock.elapsedTime = 0;
|
|
1377
|
-
|
|
1378
1296
|
if (frameloop !== 'never') {
|
|
1379
1297
|
clock.start();
|
|
1380
1298
|
clock.elapsedTime = 0;
|
|
1381
1299
|
}
|
|
1382
|
-
|
|
1383
1300
|
set(() => ({
|
|
1384
1301
|
frameloop
|
|
1385
1302
|
}));
|
|
@@ -1397,27 +1314,26 @@ const createStore = (invalidate, advance) => {
|
|
|
1397
1314
|
initialHits: [],
|
|
1398
1315
|
capturedMap: new Map(),
|
|
1399
1316
|
subscribe: (ref, priority, store) => {
|
|
1400
|
-
const internal = get().internal;
|
|
1317
|
+
const internal = get().internal;
|
|
1318
|
+
// If this subscription was given a priority, it takes rendering into its own hands
|
|
1401
1319
|
// For that reason we switch off automatic rendering and increase the manual flag
|
|
1402
1320
|
// As long as this flag is positive there can be no internal rendering at all
|
|
1403
1321
|
// because there could be multiple render subscriptions
|
|
1404
|
-
|
|
1405
1322
|
internal.priority = internal.priority + (priority > 0 ? 1 : 0);
|
|
1406
1323
|
internal.subscribers.push({
|
|
1407
1324
|
ref,
|
|
1408
1325
|
priority,
|
|
1409
1326
|
store
|
|
1410
|
-
});
|
|
1327
|
+
});
|
|
1328
|
+
// Register subscriber and sort layers from lowest to highest, meaning,
|
|
1411
1329
|
// highest priority renders last (on top of the other frames)
|
|
1412
|
-
|
|
1413
1330
|
internal.subscribers = internal.subscribers.sort((a, b) => a.priority - b.priority);
|
|
1414
1331
|
return () => {
|
|
1415
1332
|
const internal = get().internal;
|
|
1416
|
-
|
|
1417
1333
|
if (internal != null && internal.subscribers) {
|
|
1418
1334
|
// Decrease manual flag if this subscription had a priority
|
|
1419
|
-
internal.priority = internal.priority - (priority > 0 ? 1 : 0);
|
|
1420
|
-
|
|
1335
|
+
internal.priority = internal.priority - (priority > 0 ? 1 : 0);
|
|
1336
|
+
// Remove subscriber from list
|
|
1421
1337
|
internal.subscribers = internal.subscribers.filter(s => s.ref !== ref);
|
|
1422
1338
|
}
|
|
1423
1339
|
};
|
|
@@ -1437,31 +1353,35 @@ const createStore = (invalidate, advance) => {
|
|
|
1437
1353
|
viewport,
|
|
1438
1354
|
gl,
|
|
1439
1355
|
set
|
|
1440
|
-
} = rootState.getState();
|
|
1356
|
+
} = rootState.getState();
|
|
1441
1357
|
|
|
1358
|
+
// Resize camera and renderer on changes to size and pixelratio
|
|
1442
1359
|
if (size !== oldSize || viewport.dpr !== oldDpr) {
|
|
1443
1360
|
oldSize = size;
|
|
1444
|
-
oldDpr = viewport.dpr;
|
|
1445
|
-
|
|
1361
|
+
oldDpr = viewport.dpr;
|
|
1362
|
+
// Update camera & renderer
|
|
1446
1363
|
updateCamera(camera, size);
|
|
1447
1364
|
gl.setPixelRatio(viewport.dpr);
|
|
1448
1365
|
gl.setSize(size.width, size.height, size.updateStyle);
|
|
1449
|
-
}
|
|
1450
|
-
|
|
1366
|
+
}
|
|
1451
1367
|
|
|
1368
|
+
// Update viewport once the camera changes
|
|
1452
1369
|
if (camera !== oldCamera) {
|
|
1453
|
-
oldCamera = camera;
|
|
1454
|
-
|
|
1370
|
+
oldCamera = camera;
|
|
1371
|
+
// Update viewport
|
|
1455
1372
|
set(state => ({
|
|
1456
|
-
viewport: {
|
|
1373
|
+
viewport: {
|
|
1374
|
+
...state.viewport,
|
|
1457
1375
|
...state.viewport.getCurrentViewport(camera)
|
|
1458
1376
|
}
|
|
1459
1377
|
}));
|
|
1460
1378
|
}
|
|
1461
|
-
});
|
|
1379
|
+
});
|
|
1462
1380
|
|
|
1463
|
-
|
|
1381
|
+
// Invalidate on any change
|
|
1382
|
+
rootState.subscribe(state => invalidate(state));
|
|
1464
1383
|
|
|
1384
|
+
// Return root state
|
|
1465
1385
|
return rootState;
|
|
1466
1386
|
};
|
|
1467
1387
|
|
|
@@ -1472,144 +1392,129 @@ function createSubs(callback, subs) {
|
|
|
1472
1392
|
subs.add(sub);
|
|
1473
1393
|
return () => void subs.delete(sub);
|
|
1474
1394
|
}
|
|
1475
|
-
|
|
1476
1395
|
let i;
|
|
1477
1396
|
let globalEffects = new Set();
|
|
1478
1397
|
let globalAfterEffects = new Set();
|
|
1479
1398
|
let globalTailEffects = new Set();
|
|
1399
|
+
|
|
1480
1400
|
/**
|
|
1481
1401
|
* Adds a global render callback which is called each frame.
|
|
1482
1402
|
* @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#addEffect
|
|
1483
1403
|
*/
|
|
1484
|
-
|
|
1485
1404
|
const addEffect = callback => createSubs(callback, globalEffects);
|
|
1405
|
+
|
|
1486
1406
|
/**
|
|
1487
1407
|
* Adds a global after-render callback which is called each frame.
|
|
1488
1408
|
* @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#addAfterEffect
|
|
1489
1409
|
*/
|
|
1490
|
-
|
|
1491
1410
|
const addAfterEffect = callback => createSubs(callback, globalAfterEffects);
|
|
1411
|
+
|
|
1492
1412
|
/**
|
|
1493
1413
|
* Adds a global callback which is called when rendering stops.
|
|
1494
1414
|
* @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#addTail
|
|
1495
1415
|
*/
|
|
1496
|
-
|
|
1497
1416
|
const addTail = callback => createSubs(callback, globalTailEffects);
|
|
1498
|
-
|
|
1499
1417
|
function run(effects, timestamp) {
|
|
1500
1418
|
if (!effects.size) return;
|
|
1501
|
-
|
|
1502
1419
|
for (const {
|
|
1503
1420
|
callback
|
|
1504
1421
|
} of effects.values()) {
|
|
1505
1422
|
callback(timestamp);
|
|
1506
1423
|
}
|
|
1507
1424
|
}
|
|
1508
|
-
|
|
1509
1425
|
function flushGlobalEffects(type, timestamp) {
|
|
1510
1426
|
switch (type) {
|
|
1511
1427
|
case 'before':
|
|
1512
1428
|
return run(globalEffects, timestamp);
|
|
1513
|
-
|
|
1514
1429
|
case 'after':
|
|
1515
1430
|
return run(globalAfterEffects, timestamp);
|
|
1516
|
-
|
|
1517
1431
|
case 'tail':
|
|
1518
1432
|
return run(globalTailEffects, timestamp);
|
|
1519
1433
|
}
|
|
1520
1434
|
}
|
|
1521
1435
|
let subscribers;
|
|
1522
1436
|
let subscription;
|
|
1523
|
-
|
|
1524
1437
|
function render$1(timestamp, state, frame) {
|
|
1525
1438
|
// Run local effects
|
|
1526
|
-
let delta = state.clock.getDelta();
|
|
1527
|
-
|
|
1439
|
+
let delta = state.clock.getDelta();
|
|
1440
|
+
// In frameloop='never' mode, clock times are updated using the provided timestamp
|
|
1528
1441
|
if (state.frameloop === 'never' && typeof timestamp === 'number') {
|
|
1529
1442
|
delta = timestamp - state.clock.elapsedTime;
|
|
1530
1443
|
state.clock.oldTime = state.clock.elapsedTime;
|
|
1531
1444
|
state.clock.elapsedTime = timestamp;
|
|
1532
|
-
}
|
|
1533
|
-
|
|
1534
|
-
|
|
1445
|
+
}
|
|
1446
|
+
// Call subscribers (useFrame)
|
|
1535
1447
|
subscribers = state.internal.subscribers;
|
|
1536
|
-
|
|
1537
1448
|
for (i = 0; i < subscribers.length; i++) {
|
|
1538
1449
|
subscription = subscribers[i];
|
|
1539
1450
|
subscription.ref.current(subscription.store.getState(), delta, frame);
|
|
1540
|
-
}
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1451
|
+
}
|
|
1452
|
+
// Render content
|
|
1453
|
+
if (!state.internal.priority && state.gl.render) state.gl.render(state.scene, state.camera);
|
|
1454
|
+
// Decrease frame count
|
|
1545
1455
|
state.internal.frames = Math.max(0, state.internal.frames - 1);
|
|
1546
1456
|
return state.frameloop === 'always' ? 1 : state.internal.frames;
|
|
1547
1457
|
}
|
|
1548
|
-
|
|
1549
1458
|
function createLoop(roots) {
|
|
1550
1459
|
let running = false;
|
|
1551
1460
|
let repeat;
|
|
1552
1461
|
let frame;
|
|
1553
1462
|
let state;
|
|
1554
|
-
|
|
1555
1463
|
function loop(timestamp) {
|
|
1556
1464
|
frame = requestAnimationFrame(loop);
|
|
1557
1465
|
running = true;
|
|
1558
|
-
repeat = 0;
|
|
1466
|
+
repeat = 0;
|
|
1559
1467
|
|
|
1560
|
-
|
|
1468
|
+
// Run effects
|
|
1469
|
+
flushGlobalEffects('before', timestamp);
|
|
1561
1470
|
|
|
1471
|
+
// Render all roots
|
|
1562
1472
|
for (const root of roots.values()) {
|
|
1563
1473
|
var _state$gl$xr;
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1474
|
+
state = root.store.getState();
|
|
1475
|
+
// If the frameloop is invalidated, do not run another frame
|
|
1567
1476
|
if (state.internal.active && (state.frameloop === 'always' || state.internal.frames > 0) && !((_state$gl$xr = state.gl.xr) != null && _state$gl$xr.isPresenting)) {
|
|
1568
1477
|
repeat += render$1(timestamp, state);
|
|
1569
1478
|
}
|
|
1570
|
-
}
|
|
1571
|
-
|
|
1479
|
+
}
|
|
1572
1480
|
|
|
1573
|
-
|
|
1481
|
+
// Run after-effects
|
|
1482
|
+
flushGlobalEffects('after', timestamp);
|
|
1574
1483
|
|
|
1484
|
+
// Stop the loop if nothing invalidates it
|
|
1575
1485
|
if (repeat === 0) {
|
|
1576
1486
|
// Tail call effects, they are called when rendering stops
|
|
1577
|
-
flushGlobalEffects('tail', timestamp);
|
|
1487
|
+
flushGlobalEffects('tail', timestamp);
|
|
1578
1488
|
|
|
1489
|
+
// Flag end of operation
|
|
1579
1490
|
running = false;
|
|
1580
1491
|
return cancelAnimationFrame(frame);
|
|
1581
1492
|
}
|
|
1582
1493
|
}
|
|
1583
|
-
|
|
1584
1494
|
function invalidate(state, frames = 1) {
|
|
1585
1495
|
var _state$gl$xr2;
|
|
1586
|
-
|
|
1587
1496
|
if (!state) return roots.forEach(root => invalidate(root.store.getState()), frames);
|
|
1588
|
-
if ((_state$gl$xr2 = state.gl.xr) != null && _state$gl$xr2.isPresenting || !state.internal.active || state.frameloop === 'never') return;
|
|
1589
|
-
|
|
1590
|
-
state.internal.frames = Math.min(60, state.internal.frames + frames);
|
|
1591
|
-
|
|
1497
|
+
if ((_state$gl$xr2 = state.gl.xr) != null && _state$gl$xr2.isPresenting || !state.internal.active || state.frameloop === 'never') return;
|
|
1498
|
+
// Increase frames, do not go higher than 60
|
|
1499
|
+
state.internal.frames = Math.min(60, state.internal.frames + frames);
|
|
1500
|
+
// If the render-loop isn't active, start it
|
|
1592
1501
|
if (!running) {
|
|
1593
1502
|
running = true;
|
|
1594
1503
|
requestAnimationFrame(loop);
|
|
1595
1504
|
}
|
|
1596
1505
|
}
|
|
1597
|
-
|
|
1598
1506
|
function advance(timestamp, runGlobalEffects = true, state, frame) {
|
|
1599
1507
|
if (runGlobalEffects) flushGlobalEffects('before', timestamp);
|
|
1600
1508
|
if (!state) for (const root of roots.values()) render$1(timestamp, root.store.getState());else render$1(timestamp, state, frame);
|
|
1601
1509
|
if (runGlobalEffects) flushGlobalEffects('after', timestamp);
|
|
1602
1510
|
}
|
|
1603
|
-
|
|
1604
1511
|
return {
|
|
1605
1512
|
loop,
|
|
1606
|
-
|
|
1607
1513
|
/**
|
|
1608
1514
|
* Invalidates the view, requesting a frame to be rendered. Will globally invalidate unless passed a root's state.
|
|
1609
1515
|
* @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#invalidate
|
|
1610
1516
|
*/
|
|
1611
1517
|
invalidate,
|
|
1612
|
-
|
|
1613
1518
|
/**
|
|
1614
1519
|
* Advances the frameloop and runs render effects, useful for when manually rendering via `frameloop="never"`.
|
|
1615
1520
|
* @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#advance
|
|
@@ -1634,80 +1539,77 @@ function useStore() {
|
|
|
1634
1539
|
if (!store) throw new Error('R3F: Hooks can only be used within the Canvas component!');
|
|
1635
1540
|
return store;
|
|
1636
1541
|
}
|
|
1542
|
+
|
|
1637
1543
|
/**
|
|
1638
1544
|
* Accesses R3F's internal state, containing renderer, canvas, scene, etc.
|
|
1639
1545
|
* @see https://docs.pmnd.rs/react-three-fiber/api/hooks#usethree
|
|
1640
1546
|
*/
|
|
1641
|
-
|
|
1642
1547
|
function useThree(selector = state => state, equalityFn) {
|
|
1643
1548
|
return useStore()(selector, equalityFn);
|
|
1644
1549
|
}
|
|
1550
|
+
|
|
1645
1551
|
/**
|
|
1646
1552
|
* Executes a callback before render in a shared frame loop.
|
|
1647
1553
|
* Can order effects with render priority or manually render with a positive priority.
|
|
1648
1554
|
* @see https://docs.pmnd.rs/react-three-fiber/api/hooks#useframe
|
|
1649
1555
|
*/
|
|
1650
|
-
|
|
1651
1556
|
function useFrame(callback, renderPriority = 0) {
|
|
1652
1557
|
const store = useStore();
|
|
1653
|
-
const subscribe = store.getState().internal.subscribe;
|
|
1654
|
-
|
|
1655
|
-
const ref = useMutableCallback(callback);
|
|
1656
|
-
|
|
1558
|
+
const subscribe = store.getState().internal.subscribe;
|
|
1559
|
+
// Memoize ref
|
|
1560
|
+
const ref = useMutableCallback(callback);
|
|
1561
|
+
// Subscribe on mount, unsubscribe on unmount
|
|
1657
1562
|
useIsomorphicLayoutEffect(() => subscribe(ref, renderPriority, store), [renderPriority, subscribe, store]);
|
|
1658
1563
|
return null;
|
|
1659
1564
|
}
|
|
1565
|
+
|
|
1660
1566
|
/**
|
|
1661
1567
|
* Returns a node graph of an object with named nodes & materials.
|
|
1662
1568
|
* @see https://docs.pmnd.rs/react-three-fiber/api/hooks#usegraph
|
|
1663
1569
|
*/
|
|
1664
|
-
|
|
1665
1570
|
function useGraph(object) {
|
|
1666
1571
|
return React.useMemo(() => buildGraph(object), [object]);
|
|
1667
1572
|
}
|
|
1668
|
-
|
|
1669
1573
|
function loadingFn(extensions, onProgress) {
|
|
1670
1574
|
return function (Proto, ...input) {
|
|
1671
1575
|
// Construct new loader and run extensions
|
|
1672
1576
|
const loader = new Proto();
|
|
1673
|
-
if (extensions) extensions(loader);
|
|
1674
|
-
|
|
1577
|
+
if (extensions) extensions(loader);
|
|
1578
|
+
// Go through the urls and load them
|
|
1675
1579
|
return Promise.all(input.map(input => new Promise((res, reject) => loader.load(input, data => {
|
|
1676
1580
|
if (data.scene) Object.assign(data, buildGraph(data.scene));
|
|
1677
1581
|
res(data);
|
|
1678
1582
|
}, onProgress, error => reject(new Error(`Could not load ${input}: ${error.message})`))))));
|
|
1679
1583
|
};
|
|
1680
1584
|
}
|
|
1585
|
+
|
|
1681
1586
|
/**
|
|
1682
1587
|
* Synchronously loads and caches assets with a three loader.
|
|
1683
1588
|
*
|
|
1684
1589
|
* Note: this hook's caller must be wrapped with `React.Suspense`
|
|
1685
1590
|
* @see https://docs.pmnd.rs/react-three-fiber/api/hooks#useloader
|
|
1686
1591
|
*/
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
1592
|
function useLoader(Proto, input, extensions, onProgress) {
|
|
1690
1593
|
// Use suspense to load async assets
|
|
1691
1594
|
const keys = Array.isArray(input) ? input : [input];
|
|
1692
1595
|
const results = suspend(loadingFn(extensions, onProgress), [Proto, ...keys], {
|
|
1693
1596
|
equal: is.equ
|
|
1694
|
-
});
|
|
1695
|
-
|
|
1597
|
+
});
|
|
1598
|
+
// Return the object/s
|
|
1696
1599
|
return Array.isArray(input) ? results : results[0];
|
|
1697
1600
|
}
|
|
1601
|
+
|
|
1698
1602
|
/**
|
|
1699
1603
|
* Preloads an asset into cache as a side-effect.
|
|
1700
1604
|
*/
|
|
1701
|
-
|
|
1702
1605
|
useLoader.preload = function (Proto, input, extensions) {
|
|
1703
1606
|
const keys = Array.isArray(input) ? input : [input];
|
|
1704
1607
|
return preload(loadingFn(extensions), [Proto, ...keys]);
|
|
1705
1608
|
};
|
|
1609
|
+
|
|
1706
1610
|
/**
|
|
1707
1611
|
* Removes a loaded asset from cache.
|
|
1708
1612
|
*/
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
1613
|
useLoader.clear = function (Proto, input) {
|
|
1712
1614
|
const keys = Array.isArray(input) ? input : [input];
|
|
1713
1615
|
return clear([Proto, ...keys]);
|
|
@@ -1726,7 +1628,6 @@ const shallowLoose = {
|
|
|
1726
1628
|
objects: 'shallow',
|
|
1727
1629
|
strict: false
|
|
1728
1630
|
};
|
|
1729
|
-
|
|
1730
1631
|
const createRendererInstance = (gl, canvas) => {
|
|
1731
1632
|
const customRenderer = typeof gl === 'function' ? gl(canvas) : gl;
|
|
1732
1633
|
if (isRenderer(customRenderer)) return customRenderer;else return new THREE.WebGLRenderer({
|
|
@@ -1737,16 +1638,13 @@ const createRendererInstance = (gl, canvas) => {
|
|
|
1737
1638
|
...gl
|
|
1738
1639
|
});
|
|
1739
1640
|
};
|
|
1740
|
-
|
|
1741
1641
|
function isCanvas(maybeCanvas) {
|
|
1742
1642
|
return maybeCanvas instanceof HTMLCanvasElement;
|
|
1743
1643
|
}
|
|
1744
|
-
|
|
1745
1644
|
function computeInitialSize(canvas, defaultSize) {
|
|
1746
1645
|
if (defaultSize) {
|
|
1747
1646
|
return defaultSize;
|
|
1748
1647
|
}
|
|
1749
|
-
|
|
1750
1648
|
if (isCanvas(canvas) && canvas.parentElement) {
|
|
1751
1649
|
const {
|
|
1752
1650
|
width,
|
|
@@ -1761,7 +1659,6 @@ function computeInitialSize(canvas, defaultSize) {
|
|
|
1761
1659
|
left
|
|
1762
1660
|
};
|
|
1763
1661
|
}
|
|
1764
|
-
|
|
1765
1662
|
return {
|
|
1766
1663
|
width: 0,
|
|
1767
1664
|
height: 0,
|
|
@@ -1769,29 +1666,33 @@ function computeInitialSize(canvas, defaultSize) {
|
|
|
1769
1666
|
left: 0
|
|
1770
1667
|
};
|
|
1771
1668
|
}
|
|
1772
|
-
|
|
1773
1669
|
function createRoot(canvas) {
|
|
1774
1670
|
// Check against mistaken use of createRoot
|
|
1775
1671
|
const prevRoot = roots.get(canvas);
|
|
1776
1672
|
const prevFiber = prevRoot == null ? void 0 : prevRoot.fiber;
|
|
1777
1673
|
const prevStore = prevRoot == null ? void 0 : prevRoot.store;
|
|
1778
|
-
if (prevRoot) console.warn('R3F.createRoot should only be called once!');
|
|
1779
|
-
// https://github.com/pmndrs/react-three-fiber/pull/2261
|
|
1674
|
+
if (prevRoot) console.warn('R3F.createRoot should only be called once!');
|
|
1780
1675
|
|
|
1781
|
-
|
|
1676
|
+
// Report when an error was detected in a previous render
|
|
1677
|
+
// https://github.com/pmndrs/react-three-fiber/pull/2261
|
|
1678
|
+
const logRecoverableError = typeof reportError === 'function' ?
|
|
1679
|
+
// In modern browsers, reportError will dispatch an error event,
|
|
1782
1680
|
// emulating an uncaught JavaScript error.
|
|
1783
|
-
reportError :
|
|
1784
|
-
console.error
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
const
|
|
1789
|
-
|
|
1681
|
+
reportError :
|
|
1682
|
+
// In older browsers and test environments, fallback to console.error.
|
|
1683
|
+
console.error;
|
|
1684
|
+
|
|
1685
|
+
// Create store
|
|
1686
|
+
const store = prevStore || createStore(invalidate, advance);
|
|
1687
|
+
// Create renderer
|
|
1688
|
+
const fiber = prevFiber || reconciler.createContainer(store, ConcurrentRoot, null, false, null, '', logRecoverableError, null);
|
|
1689
|
+
// Map it
|
|
1790
1690
|
if (!prevRoot) roots.set(canvas, {
|
|
1791
1691
|
fiber,
|
|
1792
1692
|
store
|
|
1793
|
-
});
|
|
1693
|
+
});
|
|
1794
1694
|
|
|
1695
|
+
// Locals
|
|
1795
1696
|
let onCreated;
|
|
1796
1697
|
let configured = false;
|
|
1797
1698
|
return {
|
|
@@ -1813,108 +1714,121 @@ function createRoot(canvas) {
|
|
|
1813
1714
|
camera: cameraOptions,
|
|
1814
1715
|
onPointerMissed
|
|
1815
1716
|
} = props;
|
|
1816
|
-
let state = store.getState();
|
|
1717
|
+
let state = store.getState();
|
|
1817
1718
|
|
|
1719
|
+
// Set up renderer (one time only!)
|
|
1818
1720
|
let gl = state.gl;
|
|
1819
1721
|
if (!state.gl) state.set({
|
|
1820
1722
|
gl: gl = createRendererInstance(glConfig, canvas)
|
|
1821
|
-
});
|
|
1723
|
+
});
|
|
1822
1724
|
|
|
1725
|
+
// Set up raycaster (one time only!)
|
|
1823
1726
|
let raycaster = state.raycaster;
|
|
1824
1727
|
if (!raycaster) state.set({
|
|
1825
1728
|
raycaster: raycaster = new THREE.Raycaster()
|
|
1826
|
-
});
|
|
1729
|
+
});
|
|
1827
1730
|
|
|
1731
|
+
// Set raycaster options
|
|
1828
1732
|
const {
|
|
1829
1733
|
params,
|
|
1830
1734
|
...options
|
|
1831
1735
|
} = raycastOptions || {};
|
|
1832
|
-
if (!is.equ(options, raycaster, shallowLoose)) applyProps(raycaster, {
|
|
1736
|
+
if (!is.equ(options, raycaster, shallowLoose)) applyProps(raycaster, {
|
|
1737
|
+
...options
|
|
1833
1738
|
});
|
|
1834
1739
|
if (!is.equ(params, raycaster.params, shallowLoose)) applyProps(raycaster, {
|
|
1835
|
-
params: {
|
|
1740
|
+
params: {
|
|
1741
|
+
...raycaster.params,
|
|
1836
1742
|
...params
|
|
1837
1743
|
}
|
|
1838
|
-
});
|
|
1744
|
+
});
|
|
1839
1745
|
|
|
1746
|
+
// Create default camera (one time only!)
|
|
1840
1747
|
if (!state.camera) {
|
|
1841
1748
|
const isCamera = cameraOptions instanceof THREE.Camera;
|
|
1842
1749
|
const camera = isCamera ? cameraOptions : orthographic ? new THREE.OrthographicCamera(0, 0, 0, 0, 0.1, 1000) : new THREE.PerspectiveCamera(75, 0, 0.1, 1000);
|
|
1843
|
-
|
|
1844
1750
|
if (!isCamera) {
|
|
1845
1751
|
camera.position.z = 5;
|
|
1846
|
-
if (cameraOptions) applyProps(camera, cameraOptions);
|
|
1847
|
-
|
|
1752
|
+
if (cameraOptions) applyProps(camera, cameraOptions);
|
|
1753
|
+
// Always look at center by default
|
|
1848
1754
|
if (!(cameraOptions != null && cameraOptions.rotation)) camera.lookAt(0, 0, 0);
|
|
1849
1755
|
}
|
|
1850
|
-
|
|
1851
1756
|
state.set({
|
|
1852
1757
|
camera
|
|
1853
1758
|
});
|
|
1854
|
-
}
|
|
1855
|
-
|
|
1759
|
+
}
|
|
1856
1760
|
|
|
1761
|
+
// Set up XR (one time only!)
|
|
1857
1762
|
if (!state.xr) {
|
|
1858
1763
|
// Handle frame behavior in WebXR
|
|
1859
1764
|
const handleXRFrame = (timestamp, frame) => {
|
|
1860
1765
|
const state = store.getState();
|
|
1861
1766
|
if (state.frameloop === 'never') return;
|
|
1862
1767
|
advance(timestamp, true, state, frame);
|
|
1863
|
-
};
|
|
1864
|
-
|
|
1768
|
+
};
|
|
1865
1769
|
|
|
1770
|
+
// Toggle render switching on session
|
|
1866
1771
|
const handleSessionChange = () => {
|
|
1867
1772
|
const state = store.getState();
|
|
1868
1773
|
state.gl.xr.enabled = state.gl.xr.isPresenting;
|
|
1869
1774
|
state.gl.xr.setAnimationLoop(state.gl.xr.isPresenting ? handleXRFrame : null);
|
|
1870
1775
|
if (!state.gl.xr.isPresenting) invalidate(state);
|
|
1871
|
-
};
|
|
1872
|
-
|
|
1776
|
+
};
|
|
1873
1777
|
|
|
1778
|
+
// WebXR session manager
|
|
1874
1779
|
const xr = {
|
|
1875
1780
|
connect() {
|
|
1876
1781
|
const gl = store.getState().gl;
|
|
1877
1782
|
gl.xr.addEventListener('sessionstart', handleSessionChange);
|
|
1878
1783
|
gl.xr.addEventListener('sessionend', handleSessionChange);
|
|
1879
1784
|
},
|
|
1880
|
-
|
|
1881
1785
|
disconnect() {
|
|
1882
1786
|
const gl = store.getState().gl;
|
|
1883
1787
|
gl.xr.removeEventListener('sessionstart', handleSessionChange);
|
|
1884
1788
|
gl.xr.removeEventListener('sessionend', handleSessionChange);
|
|
1885
1789
|
}
|
|
1790
|
+
};
|
|
1886
1791
|
|
|
1887
|
-
|
|
1888
|
-
|
|
1792
|
+
// Subscribe to WebXR session events
|
|
1889
1793
|
if (gl.xr) xr.connect();
|
|
1890
1794
|
state.set({
|
|
1891
1795
|
xr
|
|
1892
1796
|
});
|
|
1893
|
-
}
|
|
1894
|
-
|
|
1797
|
+
}
|
|
1895
1798
|
|
|
1799
|
+
// Set shadowmap
|
|
1896
1800
|
if (gl.shadowMap) {
|
|
1897
|
-
const
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
gl.shadowMap.
|
|
1902
|
-
|
|
1903
|
-
|
|
1801
|
+
const oldEnabled = gl.shadowMap.enabled;
|
|
1802
|
+
const oldType = gl.shadowMap.type;
|
|
1803
|
+
gl.shadowMap.enabled = !!shadows;
|
|
1804
|
+
if (is.boo(shadows)) {
|
|
1805
|
+
gl.shadowMap.type = THREE.PCFSoftShadowMap;
|
|
1806
|
+
} else if (is.str(shadows)) {
|
|
1807
|
+
var _types$shadows;
|
|
1808
|
+
const types = {
|
|
1809
|
+
basic: THREE.BasicShadowMap,
|
|
1810
|
+
percentage: THREE.PCFShadowMap,
|
|
1811
|
+
soft: THREE.PCFSoftShadowMap,
|
|
1812
|
+
variance: THREE.VSMShadowMap
|
|
1813
|
+
};
|
|
1814
|
+
gl.shadowMap.type = (_types$shadows = types[shadows]) != null ? _types$shadows : THREE.PCFSoftShadowMap;
|
|
1815
|
+
} else if (is.obj(shadows)) {
|
|
1816
|
+
Object.assign(gl.shadowMap, shadows);
|
|
1904
1817
|
}
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1818
|
+
if (oldEnabled !== gl.shadowMap.enabled || oldType !== gl.shadowMap.type) gl.shadowMap.needsUpdate = true;
|
|
1819
|
+
}
|
|
1908
1820
|
|
|
1821
|
+
// Safely set color management if available.
|
|
1822
|
+
// Avoid accessing THREE.ColorManagement to play nice with older versions
|
|
1909
1823
|
if ('ColorManagement' in THREE) {
|
|
1910
1824
|
setDeep(THREE, legacy, ['ColorManagement', 'legacyMode']);
|
|
1911
1825
|
}
|
|
1912
|
-
|
|
1913
1826
|
const outputEncoding = linear ? THREE.LinearEncoding : THREE.sRGBEncoding;
|
|
1914
1827
|
const toneMapping = flat ? THREE.NoToneMapping : THREE.ACESFilmicToneMapping;
|
|
1915
1828
|
if (gl.outputEncoding !== outputEncoding) gl.outputEncoding = outputEncoding;
|
|
1916
|
-
if (gl.toneMapping !== toneMapping) gl.toneMapping = toneMapping;
|
|
1829
|
+
if (gl.toneMapping !== toneMapping) gl.toneMapping = toneMapping;
|
|
1917
1830
|
|
|
1831
|
+
// Update color management state
|
|
1918
1832
|
if (state.legacy !== legacy) state.set(() => ({
|
|
1919
1833
|
legacy
|
|
1920
1834
|
}));
|
|
@@ -1923,40 +1837,40 @@ function createRoot(canvas) {
|
|
|
1923
1837
|
}));
|
|
1924
1838
|
if (state.flat !== flat) state.set(() => ({
|
|
1925
1839
|
flat
|
|
1926
|
-
}));
|
|
1927
|
-
|
|
1928
|
-
if (glConfig && !is.fun(glConfig) && !isRenderer(glConfig) && !is.equ(glConfig, gl, shallowLoose)) applyProps(gl, glConfig); // Store events internally
|
|
1840
|
+
}));
|
|
1929
1841
|
|
|
1842
|
+
// Set gl props
|
|
1843
|
+
if (glConfig && !is.fun(glConfig) && !isRenderer(glConfig) && !is.equ(glConfig, gl, shallowLoose)) applyProps(gl, glConfig);
|
|
1844
|
+
// Store events internally
|
|
1930
1845
|
if (events && !state.events.handlers) state.set({
|
|
1931
1846
|
events: events(store)
|
|
1932
|
-
});
|
|
1933
|
-
|
|
1934
|
-
if (dpr && state.viewport.dpr !== calculateDpr(dpr)) state.setDpr(dpr);
|
|
1935
|
-
|
|
1847
|
+
});
|
|
1848
|
+
// Check pixelratio
|
|
1849
|
+
if (dpr && state.viewport.dpr !== calculateDpr(dpr)) state.setDpr(dpr);
|
|
1850
|
+
// Check size, allow it to take on container bounds initially
|
|
1936
1851
|
const size = computeInitialSize(canvas, propsSize);
|
|
1937
|
-
|
|
1938
1852
|
if (!is.equ(size, state.size, shallowLoose)) {
|
|
1939
1853
|
state.setSize(size.width, size.height, size.updateStyle, size.top, size.left);
|
|
1940
|
-
}
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1854
|
+
}
|
|
1855
|
+
// Check frameloop
|
|
1856
|
+
if (state.frameloop !== frameloop) state.setFrameloop(frameloop);
|
|
1857
|
+
// Check pointer missed
|
|
1945
1858
|
if (!state.onPointerMissed) state.set({
|
|
1946
1859
|
onPointerMissed
|
|
1947
|
-
});
|
|
1948
|
-
|
|
1860
|
+
});
|
|
1861
|
+
// Check performance
|
|
1949
1862
|
if (performance && !is.equ(performance, state.performance, shallowLoose)) state.set(state => ({
|
|
1950
|
-
performance: {
|
|
1863
|
+
performance: {
|
|
1864
|
+
...state.performance,
|
|
1951
1865
|
...performance
|
|
1952
1866
|
}
|
|
1953
|
-
}));
|
|
1867
|
+
}));
|
|
1954
1868
|
|
|
1869
|
+
// Set locals
|
|
1955
1870
|
onCreated = onCreatedCallback;
|
|
1956
1871
|
configured = true;
|
|
1957
1872
|
return this;
|
|
1958
1873
|
},
|
|
1959
|
-
|
|
1960
1874
|
render(children) {
|
|
1961
1875
|
// The root has to be configured before it can be rendered
|
|
1962
1876
|
if (!configured) this.configure();
|
|
@@ -1968,21 +1882,17 @@ function createRoot(canvas) {
|
|
|
1968
1882
|
}), fiber, null, () => undefined);
|
|
1969
1883
|
return store;
|
|
1970
1884
|
},
|
|
1971
|
-
|
|
1972
1885
|
unmount() {
|
|
1973
1886
|
unmountComponentAtNode(canvas);
|
|
1974
1887
|
}
|
|
1975
|
-
|
|
1976
1888
|
};
|
|
1977
1889
|
}
|
|
1978
|
-
|
|
1979
1890
|
function render(children, canvas, config) {
|
|
1980
1891
|
console.warn('R3F.render is no longer supported in React 18. Use createRoot instead!');
|
|
1981
1892
|
const root = createRoot(canvas);
|
|
1982
1893
|
root.configure(config);
|
|
1983
1894
|
return root.render(children);
|
|
1984
1895
|
}
|
|
1985
|
-
|
|
1986
1896
|
function Provider({
|
|
1987
1897
|
store,
|
|
1988
1898
|
children,
|
|
@@ -1990,28 +1900,28 @@ function Provider({
|
|
|
1990
1900
|
rootElement
|
|
1991
1901
|
}) {
|
|
1992
1902
|
useIsomorphicLayoutEffect(() => {
|
|
1993
|
-
const state = store.getState();
|
|
1994
|
-
|
|
1903
|
+
const state = store.getState();
|
|
1904
|
+
// Flag the canvas active, rendering will now begin
|
|
1995
1905
|
state.set(state => ({
|
|
1996
|
-
internal: {
|
|
1906
|
+
internal: {
|
|
1907
|
+
...state.internal,
|
|
1997
1908
|
active: true
|
|
1998
1909
|
}
|
|
1999
|
-
}));
|
|
2000
|
-
|
|
2001
|
-
if (onCreated) onCreated(state);
|
|
1910
|
+
}));
|
|
1911
|
+
// Notifiy that init is completed, the scene graph exists, but nothing has yet rendered
|
|
1912
|
+
if (onCreated) onCreated(state);
|
|
1913
|
+
// Connect events to the targets parent, this is done to ensure events are registered on
|
|
2002
1914
|
// a shared target, and not on the canvas itself
|
|
2003
|
-
|
|
2004
|
-
|
|
1915
|
+
if (!store.getState().events.connected) state.events.connect == null ? void 0 : state.events.connect(rootElement);
|
|
1916
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2005
1917
|
}, []);
|
|
2006
1918
|
return /*#__PURE__*/React.createElement(context.Provider, {
|
|
2007
1919
|
value: store
|
|
2008
1920
|
}, children);
|
|
2009
1921
|
}
|
|
2010
|
-
|
|
2011
1922
|
function unmountComponentAtNode(canvas, callback) {
|
|
2012
1923
|
const root = roots.get(canvas);
|
|
2013
1924
|
const fiber = root == null ? void 0 : root.fiber;
|
|
2014
|
-
|
|
2015
1925
|
if (fiber) {
|
|
2016
1926
|
const state = root == null ? void 0 : root.store.getState();
|
|
2017
1927
|
if (state) state.internal.active = false;
|
|
@@ -2020,7 +1930,6 @@ function unmountComponentAtNode(canvas, callback) {
|
|
|
2020
1930
|
setTimeout(() => {
|
|
2021
1931
|
try {
|
|
2022
1932
|
var _state$gl, _state$gl$renderLists, _state$gl2, _state$gl3;
|
|
2023
|
-
|
|
2024
1933
|
state.events.disconnect == null ? void 0 : state.events.disconnect();
|
|
2025
1934
|
(_state$gl = state.gl) == null ? void 0 : (_state$gl$renderLists = _state$gl.renderLists) == null ? void 0 : _state$gl$renderLists.dispose == null ? void 0 : _state$gl$renderLists.dispose();
|
|
2026
1935
|
(_state$gl2 = state.gl) == null ? void 0 : _state$gl2.forceContextLoss == null ? void 0 : _state$gl2.forceContextLoss();
|
|
@@ -2036,7 +1945,6 @@ function unmountComponentAtNode(canvas, callback) {
|
|
|
2036
1945
|
});
|
|
2037
1946
|
}
|
|
2038
1947
|
}
|
|
2039
|
-
|
|
2040
1948
|
function createPortal(children, container, state) {
|
|
2041
1949
|
return /*#__PURE__*/React.createElement(Portal, {
|
|
2042
1950
|
key: container.uuid,
|
|
@@ -2045,7 +1953,6 @@ function createPortal(children, container, state) {
|
|
|
2045
1953
|
state: state
|
|
2046
1954
|
});
|
|
2047
1955
|
}
|
|
2048
|
-
|
|
2049
1956
|
function Portal({
|
|
2050
1957
|
state = {},
|
|
2051
1958
|
children,
|
|
@@ -2056,6 +1963,7 @@ function Portal({
|
|
|
2056
1963
|
* the "R3F hooks can only be used within the Canvas component!" warning:
|
|
2057
1964
|
* <Canvas>
|
|
2058
1965
|
* {createPortal(...)} */
|
|
1966
|
+
|
|
2059
1967
|
const {
|
|
2060
1968
|
events,
|
|
2061
1969
|
size,
|
|
@@ -2065,30 +1973,32 @@ function Portal({
|
|
|
2065
1973
|
const [raycaster] = React.useState(() => new THREE.Raycaster());
|
|
2066
1974
|
const [pointer] = React.useState(() => new THREE.Vector2());
|
|
2067
1975
|
const inject = React.useCallback((rootState, injectState) => {
|
|
2068
|
-
const intersect = {
|
|
1976
|
+
const intersect = {
|
|
1977
|
+
...rootState
|
|
2069
1978
|
}; // all prev state props
|
|
1979
|
+
|
|
2070
1980
|
// Only the fields of "rootState" that do not differ from injectState
|
|
2071
1981
|
// Some props should be off-limits
|
|
2072
1982
|
// Otherwise filter out the props that are different and let the inject layer take precedence
|
|
2073
|
-
|
|
2074
1983
|
Object.keys(rootState).forEach(key => {
|
|
2075
|
-
if (
|
|
2076
|
-
|
|
1984
|
+
if (
|
|
1985
|
+
// Some props should be off-limits
|
|
1986
|
+
privateKeys.includes(key) ||
|
|
1987
|
+
// Otherwise filter out the props that are different and let the inject layer take precedence
|
|
2077
1988
|
rootState[key] !== injectState[key]) {
|
|
2078
1989
|
delete intersect[key];
|
|
2079
1990
|
}
|
|
2080
1991
|
});
|
|
2081
1992
|
let viewport = undefined;
|
|
2082
|
-
|
|
2083
1993
|
if (injectState && size) {
|
|
2084
|
-
const camera = injectState.camera;
|
|
2085
|
-
|
|
2086
|
-
viewport = rootState.viewport.getCurrentViewport(camera, new THREE.Vector3(), size);
|
|
2087
|
-
|
|
1994
|
+
const camera = injectState.camera;
|
|
1995
|
+
// Calculate the override viewport, if present
|
|
1996
|
+
viewport = rootState.viewport.getCurrentViewport(camera, new THREE.Vector3(), size);
|
|
1997
|
+
// Update the portal camera, if it differs from the previous layer
|
|
2088
1998
|
if (camera !== rootState.camera) updateCamera(camera, size);
|
|
2089
1999
|
}
|
|
2090
|
-
|
|
2091
|
-
|
|
2000
|
+
return {
|
|
2001
|
+
// The intersect consists of the previous root state
|
|
2092
2002
|
...intersect,
|
|
2093
2003
|
// Portals have their own scene, which forms the root, a raycaster and a pointer
|
|
2094
2004
|
scene: container,
|
|
@@ -2098,14 +2008,17 @@ function Portal({
|
|
|
2098
2008
|
// Their previous root is the layer before it
|
|
2099
2009
|
previousRoot,
|
|
2100
2010
|
// Events, size and viewport can be overridden by the inject layer
|
|
2101
|
-
events: {
|
|
2011
|
+
events: {
|
|
2012
|
+
...rootState.events,
|
|
2102
2013
|
...(injectState == null ? void 0 : injectState.events),
|
|
2103
2014
|
...events
|
|
2104
2015
|
},
|
|
2105
|
-
size: {
|
|
2016
|
+
size: {
|
|
2017
|
+
...rootState.size,
|
|
2106
2018
|
...size
|
|
2107
2019
|
},
|
|
2108
|
-
viewport: {
|
|
2020
|
+
viewport: {
|
|
2021
|
+
...rootState.viewport,
|
|
2109
2022
|
...viewport
|
|
2110
2023
|
},
|
|
2111
2024
|
...rest
|
|
@@ -2114,16 +2027,19 @@ function Portal({
|
|
|
2114
2027
|
const [usePortalStore] = React.useState(() => {
|
|
2115
2028
|
// Create a mirrored store, based on the previous root with a few overrides ...
|
|
2116
2029
|
const previousState = previousRoot.getState();
|
|
2117
|
-
const store = create((set, get) => ({
|
|
2030
|
+
const store = create((set, get) => ({
|
|
2031
|
+
...previousState,
|
|
2118
2032
|
scene: container,
|
|
2119
2033
|
raycaster,
|
|
2120
2034
|
pointer,
|
|
2121
2035
|
mouse: pointer,
|
|
2122
2036
|
previousRoot,
|
|
2123
|
-
events: {
|
|
2037
|
+
events: {
|
|
2038
|
+
...previousState.events,
|
|
2124
2039
|
...events
|
|
2125
2040
|
},
|
|
2126
|
-
size: {
|
|
2041
|
+
size: {
|
|
2042
|
+
...previousState.size,
|
|
2127
2043
|
...size
|
|
2128
2044
|
},
|
|
2129
2045
|
...rest,
|
|
@@ -2131,8 +2047,10 @@ function Portal({
|
|
|
2131
2047
|
set,
|
|
2132
2048
|
get,
|
|
2133
2049
|
// Layers are allowed to override events
|
|
2134
|
-
setEvents: events => set(state => ({
|
|
2135
|
-
|
|
2050
|
+
setEvents: events => set(state => ({
|
|
2051
|
+
...state,
|
|
2052
|
+
events: {
|
|
2053
|
+
...state.events,
|
|
2136
2054
|
...events
|
|
2137
2055
|
}
|
|
2138
2056
|
}))
|
|
@@ -2154,7 +2072,6 @@ function Portal({
|
|
|
2154
2072
|
value: usePortalStore
|
|
2155
2073
|
}, children), usePortalStore, null));
|
|
2156
2074
|
}
|
|
2157
|
-
|
|
2158
2075
|
reconciler.injectIntoDevTools({
|
|
2159
2076
|
bundleType: process.env.NODE_ENV === 'production' ? 0 : 1,
|
|
2160
2077
|
rendererPackageName: '@react-three/fiber',
|