@react-three/fiber 7.0.14 → 7.0.18
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 +24 -0
- package/dist/declarations/src/core/events.d.ts +4 -0
- package/dist/declarations/src/core/renderer.d.ts +3 -4
- package/dist/declarations/src/core/store.d.ts +6 -3
- package/dist/declarations/src/web/index.d.ts +7 -3
- package/dist/react-three-fiber.cjs.dev.js +87 -49
- package/dist/react-three-fiber.cjs.prod.js +87 -49
- package/dist/react-three-fiber.esm.js +87 -49
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# @react-three/fiber
|
|
2
2
|
|
|
3
|
+
## 7.0.18
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 6780f58: fix unmount pointer capture
|
|
8
|
+
|
|
9
|
+
## 7.0.17
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 894c550: fix: event count
|
|
14
|
+
|
|
15
|
+
## 7.0.16
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- c7a4220: patch: applyprops returns the same instance
|
|
20
|
+
|
|
21
|
+
## 7.0.15
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- c5645e8: fix primitve leftovers on switch
|
|
26
|
+
|
|
3
27
|
## 7.0.14
|
|
4
28
|
|
|
5
29
|
### Patch Changes
|
|
@@ -53,6 +53,10 @@ export interface EventManager<TTarget> {
|
|
|
53
53
|
connect?: (target: TTarget) => void;
|
|
54
54
|
disconnect?: () => void;
|
|
55
55
|
}
|
|
56
|
+
export interface PointerCaptureTarget {
|
|
57
|
+
intersection: Intersection;
|
|
58
|
+
target: Element;
|
|
59
|
+
}
|
|
56
60
|
export declare function removeInteractivity(store: UseStore<RootState>, object: THREE.Object3D): void;
|
|
57
61
|
export declare function createEvents(store: UseStore<RootState>): {
|
|
58
62
|
handlePointer: (name: string) => (event: DomEvent) => void;
|
|
@@ -12,9 +12,8 @@ export declare type LocalState = {
|
|
|
12
12
|
objects: Instance[];
|
|
13
13
|
parent: Instance | null;
|
|
14
14
|
primitive?: boolean;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
} & Partial<EventHandlers>;
|
|
15
|
+
eventCount: number;
|
|
16
|
+
handlers: Partial<EventHandlers>;
|
|
18
17
|
memoizedProps: {
|
|
19
18
|
[key: string]: any;
|
|
20
19
|
};
|
|
@@ -57,6 +56,6 @@ declare let extend: (objects: object) => void;
|
|
|
57
56
|
declare function prepare<T = THREE.Object3D>(object: T, state?: Partial<LocalState>): T;
|
|
58
57
|
declare function createRenderer<TCanvas>(roots: Map<TCanvas, Root>): {
|
|
59
58
|
reconciler: Reconciler.Reconciler<unknown, unknown, unknown, unknown, unknown>;
|
|
60
|
-
applyProps: (instance: Instance, data: InstanceProps | DiffSet) =>
|
|
59
|
+
applyProps: (instance: Instance, data: InstanceProps | DiffSet) => Instance;
|
|
61
60
|
};
|
|
62
61
|
export { prepare, createRenderer, extend };
|
|
@@ -3,7 +3,7 @@ import * as React from 'react';
|
|
|
3
3
|
import * as ReactThreeFiber from '../three-types';
|
|
4
4
|
import { GetState, SetState, UseStore } from 'zustand';
|
|
5
5
|
import { Instance, InstanceProps } from './renderer';
|
|
6
|
-
import { DomEvent, EventManager, ThreeEvent } from './events';
|
|
6
|
+
import { DomEvent, EventManager, PointerCaptureTarget, ThreeEvent } from './events';
|
|
7
7
|
export interface Intersection extends THREE.Intersection {
|
|
8
8
|
eventObject: THREE.Object3D;
|
|
9
9
|
}
|
|
@@ -37,7 +37,10 @@ export declare type Performance = {
|
|
|
37
37
|
debounce: number;
|
|
38
38
|
regress: () => void;
|
|
39
39
|
};
|
|
40
|
-
export declare
|
|
40
|
+
export declare type Renderer = {
|
|
41
|
+
render: (scene: THREE.Scene, camera: THREE.Camera) => any;
|
|
42
|
+
};
|
|
43
|
+
export declare const isRenderer: (def: Renderer) => boolean;
|
|
41
44
|
export declare const isOrthographicCamera: (def: THREE.Camera) => def is THREE.OrthographicCamera;
|
|
42
45
|
export declare type InternalState = {
|
|
43
46
|
active: boolean;
|
|
@@ -47,7 +50,7 @@ export declare type InternalState = {
|
|
|
47
50
|
interaction: THREE.Object3D[];
|
|
48
51
|
hovered: Map<string, DomEvent>;
|
|
49
52
|
subscribers: Subscription[];
|
|
50
|
-
capturedMap: Map<number, Map<THREE.Object3D,
|
|
53
|
+
capturedMap: Map<number, Map<THREE.Object3D, PointerCaptureTarget>>;
|
|
51
54
|
initialClick: [x: number, y: number];
|
|
52
55
|
initialHits: THREE.Object3D[];
|
|
53
56
|
subscribe: (callback: React.MutableRefObject<RenderCallback>, priority?: number) => () => void;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import * as THREE from 'three';
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
import { UseStore } from 'zustand';
|
|
5
|
-
import { StoreProps, context, RootState, Size } from '../core/store';
|
|
5
|
+
import { Renderer, StoreProps, context, RootState, Size } from '../core/store';
|
|
6
6
|
import { extend, Root } from '../core/renderer';
|
|
7
7
|
import { addEffect, addAfterEffect, addTail } from '../core/loop';
|
|
8
8
|
import { createPointerEvents as events } from './events';
|
|
@@ -11,9 +11,13 @@ import { EventManager } from '../core/events';
|
|
|
11
11
|
declare const roots: Map<Element, Root>;
|
|
12
12
|
declare const modes: readonly ["legacy", "blocking", "concurrent"];
|
|
13
13
|
declare const invalidate: (state?: RootState | undefined) => void, advance: (timestamp: number, runGlobalEffects?: boolean, state?: RootState | undefined) => void;
|
|
14
|
-
declare const reconciler: import("react-reconciler").Reconciler<unknown, unknown, unknown, unknown, unknown>, applyProps: (instance: import("../core/renderer").Instance, data: import("../core/renderer").InstanceProps | import("../core/renderer").DiffSet) =>
|
|
14
|
+
declare const reconciler: import("react-reconciler").Reconciler<unknown, unknown, unknown, unknown, unknown>, applyProps: (instance: import("../core/renderer").Instance, data: import("../core/renderer").InstanceProps | import("../core/renderer").DiffSet) => import("../core/renderer").Instance;
|
|
15
|
+
declare type Properties<T> = Pick<T, {
|
|
16
|
+
[K in keyof T]: T[K] extends (_: any) => any ? never : K;
|
|
17
|
+
}[keyof T]>;
|
|
18
|
+
declare type GLProps = Renderer | ((canvas: HTMLCanvasElement) => Renderer) | Partial<Properties<THREE.WebGLRenderer> | THREE.WebGLRendererParameters> | undefined;
|
|
15
19
|
export declare type RenderProps<TCanvas extends Element> = Omit<StoreProps, 'gl' | 'events' | 'size'> & {
|
|
16
|
-
gl?:
|
|
20
|
+
gl?: GLProps;
|
|
17
21
|
events?: (store: UseStore<RootState>) => EventManager<TCanvas>;
|
|
18
22
|
size?: Size;
|
|
19
23
|
mode?: typeof modes[number];
|
|
@@ -76,6 +76,23 @@ const is = {
|
|
|
76
76
|
function makeId(event) {
|
|
77
77
|
return (event.eventObject || event.object).uuid + '/' + event.index + event.instanceId;
|
|
78
78
|
}
|
|
79
|
+
/** Release pointer captures.
|
|
80
|
+
* This is called by releasePointerCapture in the API, and when an object is removed.
|
|
81
|
+
*/
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
function releaseInternalPointerCapture(capturedMap, obj, captures, pointerId) {
|
|
85
|
+
const captureData = captures.get(obj);
|
|
86
|
+
|
|
87
|
+
if (captureData) {
|
|
88
|
+
captures.delete(obj); // If this was the last capturing object for this pointer
|
|
89
|
+
|
|
90
|
+
if (captures.size === 0) {
|
|
91
|
+
capturedMap.delete(pointerId);
|
|
92
|
+
captureData.target.releasePointerCapture(pointerId);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
79
96
|
|
|
80
97
|
function removeInteractivity(store, object) {
|
|
81
98
|
const {
|
|
@@ -89,6 +106,9 @@ function removeInteractivity(store, object) {
|
|
|
89
106
|
internal.hovered.delete(key);
|
|
90
107
|
}
|
|
91
108
|
});
|
|
109
|
+
internal.capturedMap.forEach((captures, pointerId) => {
|
|
110
|
+
releaseInternalPointerCapture(internal.capturedMap, object, captures, pointerId);
|
|
111
|
+
});
|
|
92
112
|
}
|
|
93
113
|
function createEvents(store) {
|
|
94
114
|
const temp = new THREE__namespace.Vector3();
|
|
@@ -168,7 +188,7 @@ function createEvents(store) {
|
|
|
168
188
|
while (eventObject) {
|
|
169
189
|
var _r3f2;
|
|
170
190
|
|
|
171
|
-
if ((_r3f2 = eventObject.__r3f) != null && _r3f2.
|
|
191
|
+
if ((_r3f2 = eventObject.__r3f) != null && _r3f2.eventCount) intersections.push({ ...intersect,
|
|
172
192
|
eventObject
|
|
173
193
|
});
|
|
174
194
|
eventObject = eventObject.parent;
|
|
@@ -187,7 +207,9 @@ function createEvents(store) {
|
|
|
187
207
|
// intersect.
|
|
188
208
|
|
|
189
209
|
if ('pointerId' in event && internal.capturedMap.has(event.pointerId)) {
|
|
190
|
-
|
|
210
|
+
for (let captureData of internal.capturedMap.get(event.pointerId).values()) {
|
|
211
|
+
intersections.push(captureData.intersection);
|
|
212
|
+
}
|
|
191
213
|
}
|
|
192
214
|
|
|
193
215
|
return intersections;
|
|
@@ -205,9 +227,6 @@ function createEvents(store) {
|
|
|
205
227
|
|
|
206
228
|
if (intersections.length) {
|
|
207
229
|
const unprojectedPoint = temp.set(mouse.x, mouse.y, 0).unproject(camera);
|
|
208
|
-
|
|
209
|
-
const releasePointerCapture = id => event.target.releasePointerCapture(id);
|
|
210
|
-
|
|
211
230
|
const localState = {
|
|
212
231
|
stopped: false
|
|
213
232
|
};
|
|
@@ -220,23 +239,36 @@ function createEvents(store) {
|
|
|
220
239
|
};
|
|
221
240
|
|
|
222
241
|
const setPointerCapture = id => {
|
|
242
|
+
const captureData = {
|
|
243
|
+
intersection: hit,
|
|
244
|
+
target: event.target
|
|
245
|
+
};
|
|
246
|
+
|
|
223
247
|
if (internal.capturedMap.has(id)) {
|
|
224
248
|
// if the pointerId was previously captured, we add the hit to the
|
|
225
249
|
// event capturedMap.
|
|
226
|
-
internal.capturedMap.get(id).set(hit.eventObject,
|
|
250
|
+
internal.capturedMap.get(id).set(hit.eventObject, captureData);
|
|
227
251
|
} else {
|
|
228
252
|
// if the pointerId was not previously captured, we create a map
|
|
229
253
|
// containing the hitObject, and the hit. hitObject is used for
|
|
230
254
|
// faster access.
|
|
231
|
-
internal.capturedMap.set(id, new Map([[hit.eventObject,
|
|
255
|
+
internal.capturedMap.set(id, new Map([[hit.eventObject, captureData]]));
|
|
232
256
|
} // Call the original event now
|
|
233
257
|
event.target.setPointerCapture(id);
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
const releasePointerCapture = id => {
|
|
261
|
+
const captures = internal.capturedMap.get(id);
|
|
262
|
+
|
|
263
|
+
if (captures) {
|
|
264
|
+
releaseInternalPointerCapture(internal.capturedMap, hit.eventObject, captures, id);
|
|
265
|
+
}
|
|
234
266
|
}; // Add native event props
|
|
235
267
|
|
|
236
268
|
|
|
237
|
-
let extractEventProps = {};
|
|
269
|
+
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.
|
|
238
270
|
|
|
239
|
-
for (let prop in
|
|
271
|
+
for (let prop in event) {
|
|
240
272
|
let property = event[prop]; // Only copy over atomics, leave functions alone as these should be
|
|
241
273
|
// called as event.nativeEvent.fn()
|
|
242
274
|
|
|
@@ -305,13 +337,12 @@ function createEvents(store) {
|
|
|
305
337
|
// When no objects were hit or the the hovered object wasn't found underneath the cursor
|
|
306
338
|
// we call onPointerOut and delete the object from the hovered-elements map
|
|
307
339
|
if (!hits.length || !hits.find(hit => hit.object === hoveredObj.object && hit.index === hoveredObj.index && hit.instanceId === hoveredObj.instanceId)) {
|
|
308
|
-
var _r3f3;
|
|
309
|
-
|
|
310
340
|
const eventObject = hoveredObj.eventObject;
|
|
311
|
-
const
|
|
341
|
+
const instance = eventObject.__r3f;
|
|
342
|
+
const handlers = instance == null ? void 0 : instance.handlers;
|
|
312
343
|
internal.hovered.delete(makeId(hoveredObj));
|
|
313
344
|
|
|
314
|
-
if (
|
|
345
|
+
if (instance != null && instance.eventCount) {
|
|
315
346
|
// Clear out intersects, they are outdated by now
|
|
316
347
|
const data = { ...hoveredObj,
|
|
317
348
|
intersections: hits || []
|
|
@@ -333,9 +364,8 @@ function createEvents(store) {
|
|
|
333
364
|
case 'onLostPointerCapture':
|
|
334
365
|
return event => {
|
|
335
366
|
if ('pointerId' in event) {
|
|
336
|
-
//
|
|
337
|
-
//
|
|
338
|
-
// indifferently deletes all capturing references.
|
|
367
|
+
// If the object event interface had onLostPointerCapture, we'd call it here on every
|
|
368
|
+
// object that's getting removed.
|
|
339
369
|
store.getState().internal.capturedMap.delete(event.pointerId);
|
|
340
370
|
}
|
|
341
371
|
|
|
@@ -374,12 +404,11 @@ function createEvents(store) {
|
|
|
374
404
|
|
|
375
405
|
if (isPointerMove) cancelPointer(hits);
|
|
376
406
|
handleIntersects(hits, event, delta, data => {
|
|
377
|
-
var _r3f4;
|
|
378
|
-
|
|
379
407
|
const eventObject = data.eventObject;
|
|
380
|
-
const
|
|
408
|
+
const instance = eventObject.__r3f;
|
|
409
|
+
const handlers = instance == null ? void 0 : instance.handlers; // Check presence of handlers
|
|
381
410
|
|
|
382
|
-
if (!(
|
|
411
|
+
if (!(instance != null && instance.eventCount)) return;
|
|
383
412
|
|
|
384
413
|
if (isPointerMove) {
|
|
385
414
|
// Move event ...
|
|
@@ -422,9 +451,9 @@ function createEvents(store) {
|
|
|
422
451
|
|
|
423
452
|
function pointerMissed(event, objects) {
|
|
424
453
|
objects.forEach(object => {
|
|
425
|
-
var
|
|
454
|
+
var _r3f3;
|
|
426
455
|
|
|
427
|
-
return (
|
|
456
|
+
return (_r3f3 = object.__r3f) == null ? void 0 : _r3f3.handlers.onPointerMissed == null ? void 0 : _r3f3.handlers.onPointerMissed(event);
|
|
428
457
|
});
|
|
429
458
|
}
|
|
430
459
|
|
|
@@ -475,9 +504,8 @@ function prepare(object, state) {
|
|
|
475
504
|
instance.__r3f = {
|
|
476
505
|
root: null,
|
|
477
506
|
memoizedProps: {},
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
},
|
|
507
|
+
eventCount: 0,
|
|
508
|
+
handlers: {},
|
|
481
509
|
objects: [],
|
|
482
510
|
parent: null,
|
|
483
511
|
...state
|
|
@@ -538,7 +566,7 @@ function createRenderer(roots) {
|
|
|
538
566
|
}
|
|
539
567
|
|
|
540
568
|
function applyProps(instance, data) {
|
|
541
|
-
var _instance$__r3f3, _root$getState,
|
|
569
|
+
var _instance$__r3f3, _root$getState, _instance$__r3f4;
|
|
542
570
|
|
|
543
571
|
// Filter equals, events and reserved props
|
|
544
572
|
const localState = (_instance$__r3f3 = instance == null ? void 0 : instance.__r3f) != null ? _instance$__r3f3 : {};
|
|
@@ -548,7 +576,7 @@ function createRenderer(roots) {
|
|
|
548
576
|
memoized,
|
|
549
577
|
changes
|
|
550
578
|
} = isDiffSet(data) ? data : diffProps(instance, data);
|
|
551
|
-
const prevHandlers =
|
|
579
|
+
const prevHandlers = localState.eventCount; // Prepare memoized props
|
|
552
580
|
|
|
553
581
|
if (instance.__r3f) instance.__r3f.memoizedProps = memoized;
|
|
554
582
|
changes.forEach(([key, value, isEvent, keys]) => {
|
|
@@ -587,7 +615,7 @@ function createRenderer(roots) {
|
|
|
587
615
|
|
|
588
616
|
if (isEvent) {
|
|
589
617
|
if (value) localState.handlers[key] = value;else delete localState.handlers[key];
|
|
590
|
-
localState.
|
|
618
|
+
localState.eventCount = Object.keys(localState.handlers).length;
|
|
591
619
|
} // Special treatment for objects with support for set/copy, and layers
|
|
592
620
|
else if (targetProp && targetProp.set && (targetProp.copy || targetProp instanceof THREE__namespace.Layers)) {
|
|
593
621
|
// If value is an array
|
|
@@ -617,16 +645,17 @@ function createRenderer(roots) {
|
|
|
617
645
|
invalidateInstance(instance);
|
|
618
646
|
});
|
|
619
647
|
|
|
620
|
-
if (rootState.internal && instance.raycast && prevHandlers !==
|
|
648
|
+
if (rootState.internal && instance.raycast && prevHandlers !== localState.eventCount) {
|
|
621
649
|
// Pre-emptively remove the instance from the interaction manager
|
|
622
650
|
const index = rootState.internal.interaction.indexOf(instance);
|
|
623
651
|
if (index > -1) rootState.internal.interaction.splice(index, 1); // Add the instance to the interaction manager only when it has handlers
|
|
624
652
|
|
|
625
|
-
if (localState.
|
|
653
|
+
if (localState.eventCount) rootState.internal.interaction.push(instance);
|
|
626
654
|
} // Call the update lifecycle when it is being updated
|
|
627
655
|
|
|
628
656
|
|
|
629
657
|
if (changes.length && (_instance$__r3f4 = instance.__r3f) != null && _instance$__r3f4.parent) updateInstance(instance);
|
|
658
|
+
return instance;
|
|
630
659
|
}
|
|
631
660
|
|
|
632
661
|
function invalidateInstance(instance) {
|
|
@@ -669,14 +698,13 @@ function createRenderer(roots) {
|
|
|
669
698
|
});
|
|
670
699
|
} else {
|
|
671
700
|
const target = catalogue[name] || THREE__namespace[name];
|
|
672
|
-
if (!target) throw `${name} is not part of the THREE namespace! Did you forget to extend? See: https://github.com/pmndrs/react-three-fiber/blob/master/markdown/api.md#using-3rd-party-objects-declaratively`;
|
|
673
|
-
|
|
701
|
+
if (!target) throw `${name} is not part of the THREE namespace! Did you forget to extend? See: https://github.com/pmndrs/react-three-fiber/blob/master/markdown/api.md#using-3rd-party-objects-declaratively`; // Instanciate new object, link it to the root
|
|
702
|
+
// Append memoized props with args so it's not forgotten
|
|
674
703
|
|
|
675
|
-
instance = prepare(
|
|
704
|
+
instance = prepare(new target(...args), {
|
|
676
705
|
root,
|
|
677
|
-
// append memoized props with args so it's not forgotten
|
|
678
706
|
memoizedProps: {
|
|
679
|
-
args:
|
|
707
|
+
args: args.length === 0 ? null : args
|
|
680
708
|
}
|
|
681
709
|
});
|
|
682
710
|
} // Auto-attach geometries and materials
|
|
@@ -813,7 +841,7 @@ function createRenderer(roots) {
|
|
|
813
841
|
} else if (is.fun(detachFn)) {
|
|
814
842
|
detachFn(child, parentInstance);
|
|
815
843
|
}
|
|
816
|
-
} else if (child.isObject3D) {
|
|
844
|
+
} else if (child.isObject3D && parentInstance.isObject3D) {
|
|
817
845
|
var _child$__r3f;
|
|
818
846
|
|
|
819
847
|
parentInstance.remove(child); // Remove interactivity
|
|
@@ -875,8 +903,9 @@ function createRenderer(roots) {
|
|
|
875
903
|
const newInstance = createInstance(type, newProps, instance.__r3f.root); // https://github.com/pmndrs/react-three-fiber/issues/1348
|
|
876
904
|
// When args change the instance has to be re-constructed, which then
|
|
877
905
|
// forces r3f to re-parent the children and non-scene objects
|
|
906
|
+
// This can not include primitives, which should not have declarative children
|
|
878
907
|
|
|
879
|
-
if (instance.children) {
|
|
908
|
+
if (type !== 'primitive' && instance.children) {
|
|
880
909
|
instance.children.forEach(child => appendChild(newInstance, child));
|
|
881
910
|
instance.children = [];
|
|
882
911
|
}
|
|
@@ -955,7 +984,6 @@ function createRenderer(roots) {
|
|
|
955
984
|
},
|
|
956
985
|
|
|
957
986
|
commitUpdate(instance, [reconstruct, diff], type, oldProps, newProps, fiber) {
|
|
958
|
-
//console.log(type)
|
|
959
987
|
// Reconstruct when args or <primitive object={...} have changes
|
|
960
988
|
if (reconstruct) switchInstance(instance, type, newProps, fiber); // Otherwise just overwrite props
|
|
961
989
|
else applyProps(instance, diff);
|
|
@@ -1031,7 +1059,7 @@ function createRenderer(roots) {
|
|
|
1031
1059
|
};
|
|
1032
1060
|
}
|
|
1033
1061
|
|
|
1034
|
-
const isRenderer = def => def &&
|
|
1062
|
+
const isRenderer = def => !!(def != null && def.render);
|
|
1035
1063
|
const isOrthographicCamera = def => def && def.isOrthographicCamera;
|
|
1036
1064
|
function calculateDpr(dpr) {
|
|
1037
1065
|
return Array.isArray(dpr) ? Math.min(Math.max(dpr[0], window.devicePixelRatio), dpr[1]) : dpr;
|
|
@@ -1059,11 +1087,11 @@ const createStore = (applyProps, invalidate, advance, props) => {
|
|
|
1059
1087
|
if (shadows) {
|
|
1060
1088
|
gl.shadowMap.enabled = true;
|
|
1061
1089
|
if (typeof shadows === 'object') Object.assign(gl.shadowMap, shadows);else gl.shadowMap.type = THREE__namespace.PCFSoftShadowMap;
|
|
1062
|
-
} // Set color
|
|
1090
|
+
} // Set color preferences
|
|
1063
1091
|
|
|
1064
1092
|
|
|
1065
|
-
if (
|
|
1066
|
-
if (
|
|
1093
|
+
if (linear) gl.outputEncoding = THREE__namespace.LinearEncoding;
|
|
1094
|
+
if (flat) gl.toneMapping = THREE__namespace.NoToneMapping; // clock.elapsedTime is updated using advance(timestamp)
|
|
1067
1095
|
|
|
1068
1096
|
if (frameloop === 'never') {
|
|
1069
1097
|
clock.stop();
|
|
@@ -1638,13 +1666,23 @@ const {
|
|
|
1638
1666
|
applyProps
|
|
1639
1667
|
} = createRenderer();
|
|
1640
1668
|
|
|
1641
|
-
const createRendererInstance = (gl, canvas) =>
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1669
|
+
const createRendererInstance = (gl, canvas) => {
|
|
1670
|
+
const customRenderer = typeof gl === 'function' ? gl(canvas) : gl;
|
|
1671
|
+
if (isRenderer(customRenderer)) return customRenderer;
|
|
1672
|
+
const renderer = new THREE__namespace.WebGLRenderer({
|
|
1673
|
+
powerPreference: 'high-performance',
|
|
1674
|
+
canvas: canvas,
|
|
1675
|
+
antialias: true,
|
|
1676
|
+
alpha: true,
|
|
1677
|
+
...gl
|
|
1678
|
+
}); // Set color management
|
|
1679
|
+
|
|
1680
|
+
renderer.outputEncoding = THREE__namespace.sRGBEncoding;
|
|
1681
|
+
renderer.toneMapping = THREE__namespace.ACESFilmicToneMapping; // Set gl props
|
|
1682
|
+
|
|
1683
|
+
if (gl) applyProps(renderer, gl);
|
|
1684
|
+
return renderer;
|
|
1685
|
+
};
|
|
1648
1686
|
|
|
1649
1687
|
function render(element, canvas, {
|
|
1650
1688
|
gl,
|
|
@@ -76,6 +76,23 @@ const is = {
|
|
|
76
76
|
function makeId(event) {
|
|
77
77
|
return (event.eventObject || event.object).uuid + '/' + event.index + event.instanceId;
|
|
78
78
|
}
|
|
79
|
+
/** Release pointer captures.
|
|
80
|
+
* This is called by releasePointerCapture in the API, and when an object is removed.
|
|
81
|
+
*/
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
function releaseInternalPointerCapture(capturedMap, obj, captures, pointerId) {
|
|
85
|
+
const captureData = captures.get(obj);
|
|
86
|
+
|
|
87
|
+
if (captureData) {
|
|
88
|
+
captures.delete(obj); // If this was the last capturing object for this pointer
|
|
89
|
+
|
|
90
|
+
if (captures.size === 0) {
|
|
91
|
+
capturedMap.delete(pointerId);
|
|
92
|
+
captureData.target.releasePointerCapture(pointerId);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
79
96
|
|
|
80
97
|
function removeInteractivity(store, object) {
|
|
81
98
|
const {
|
|
@@ -89,6 +106,9 @@ function removeInteractivity(store, object) {
|
|
|
89
106
|
internal.hovered.delete(key);
|
|
90
107
|
}
|
|
91
108
|
});
|
|
109
|
+
internal.capturedMap.forEach((captures, pointerId) => {
|
|
110
|
+
releaseInternalPointerCapture(internal.capturedMap, object, captures, pointerId);
|
|
111
|
+
});
|
|
92
112
|
}
|
|
93
113
|
function createEvents(store) {
|
|
94
114
|
const temp = new THREE__namespace.Vector3();
|
|
@@ -168,7 +188,7 @@ function createEvents(store) {
|
|
|
168
188
|
while (eventObject) {
|
|
169
189
|
var _r3f2;
|
|
170
190
|
|
|
171
|
-
if ((_r3f2 = eventObject.__r3f) != null && _r3f2.
|
|
191
|
+
if ((_r3f2 = eventObject.__r3f) != null && _r3f2.eventCount) intersections.push({ ...intersect,
|
|
172
192
|
eventObject
|
|
173
193
|
});
|
|
174
194
|
eventObject = eventObject.parent;
|
|
@@ -187,7 +207,9 @@ function createEvents(store) {
|
|
|
187
207
|
// intersect.
|
|
188
208
|
|
|
189
209
|
if ('pointerId' in event && internal.capturedMap.has(event.pointerId)) {
|
|
190
|
-
|
|
210
|
+
for (let captureData of internal.capturedMap.get(event.pointerId).values()) {
|
|
211
|
+
intersections.push(captureData.intersection);
|
|
212
|
+
}
|
|
191
213
|
}
|
|
192
214
|
|
|
193
215
|
return intersections;
|
|
@@ -205,9 +227,6 @@ function createEvents(store) {
|
|
|
205
227
|
|
|
206
228
|
if (intersections.length) {
|
|
207
229
|
const unprojectedPoint = temp.set(mouse.x, mouse.y, 0).unproject(camera);
|
|
208
|
-
|
|
209
|
-
const releasePointerCapture = id => event.target.releasePointerCapture(id);
|
|
210
|
-
|
|
211
230
|
const localState = {
|
|
212
231
|
stopped: false
|
|
213
232
|
};
|
|
@@ -220,23 +239,36 @@ function createEvents(store) {
|
|
|
220
239
|
};
|
|
221
240
|
|
|
222
241
|
const setPointerCapture = id => {
|
|
242
|
+
const captureData = {
|
|
243
|
+
intersection: hit,
|
|
244
|
+
target: event.target
|
|
245
|
+
};
|
|
246
|
+
|
|
223
247
|
if (internal.capturedMap.has(id)) {
|
|
224
248
|
// if the pointerId was previously captured, we add the hit to the
|
|
225
249
|
// event capturedMap.
|
|
226
|
-
internal.capturedMap.get(id).set(hit.eventObject,
|
|
250
|
+
internal.capturedMap.get(id).set(hit.eventObject, captureData);
|
|
227
251
|
} else {
|
|
228
252
|
// if the pointerId was not previously captured, we create a map
|
|
229
253
|
// containing the hitObject, and the hit. hitObject is used for
|
|
230
254
|
// faster access.
|
|
231
|
-
internal.capturedMap.set(id, new Map([[hit.eventObject,
|
|
255
|
+
internal.capturedMap.set(id, new Map([[hit.eventObject, captureData]]));
|
|
232
256
|
} // Call the original event now
|
|
233
257
|
event.target.setPointerCapture(id);
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
const releasePointerCapture = id => {
|
|
261
|
+
const captures = internal.capturedMap.get(id);
|
|
262
|
+
|
|
263
|
+
if (captures) {
|
|
264
|
+
releaseInternalPointerCapture(internal.capturedMap, hit.eventObject, captures, id);
|
|
265
|
+
}
|
|
234
266
|
}; // Add native event props
|
|
235
267
|
|
|
236
268
|
|
|
237
|
-
let extractEventProps = {};
|
|
269
|
+
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.
|
|
238
270
|
|
|
239
|
-
for (let prop in
|
|
271
|
+
for (let prop in event) {
|
|
240
272
|
let property = event[prop]; // Only copy over atomics, leave functions alone as these should be
|
|
241
273
|
// called as event.nativeEvent.fn()
|
|
242
274
|
|
|
@@ -305,13 +337,12 @@ function createEvents(store) {
|
|
|
305
337
|
// When no objects were hit or the the hovered object wasn't found underneath the cursor
|
|
306
338
|
// we call onPointerOut and delete the object from the hovered-elements map
|
|
307
339
|
if (!hits.length || !hits.find(hit => hit.object === hoveredObj.object && hit.index === hoveredObj.index && hit.instanceId === hoveredObj.instanceId)) {
|
|
308
|
-
var _r3f3;
|
|
309
|
-
|
|
310
340
|
const eventObject = hoveredObj.eventObject;
|
|
311
|
-
const
|
|
341
|
+
const instance = eventObject.__r3f;
|
|
342
|
+
const handlers = instance == null ? void 0 : instance.handlers;
|
|
312
343
|
internal.hovered.delete(makeId(hoveredObj));
|
|
313
344
|
|
|
314
|
-
if (
|
|
345
|
+
if (instance != null && instance.eventCount) {
|
|
315
346
|
// Clear out intersects, they are outdated by now
|
|
316
347
|
const data = { ...hoveredObj,
|
|
317
348
|
intersections: hits || []
|
|
@@ -333,9 +364,8 @@ function createEvents(store) {
|
|
|
333
364
|
case 'onLostPointerCapture':
|
|
334
365
|
return event => {
|
|
335
366
|
if ('pointerId' in event) {
|
|
336
|
-
//
|
|
337
|
-
//
|
|
338
|
-
// indifferently deletes all capturing references.
|
|
367
|
+
// If the object event interface had onLostPointerCapture, we'd call it here on every
|
|
368
|
+
// object that's getting removed.
|
|
339
369
|
store.getState().internal.capturedMap.delete(event.pointerId);
|
|
340
370
|
}
|
|
341
371
|
|
|
@@ -374,12 +404,11 @@ function createEvents(store) {
|
|
|
374
404
|
|
|
375
405
|
if (isPointerMove) cancelPointer(hits);
|
|
376
406
|
handleIntersects(hits, event, delta, data => {
|
|
377
|
-
var _r3f4;
|
|
378
|
-
|
|
379
407
|
const eventObject = data.eventObject;
|
|
380
|
-
const
|
|
408
|
+
const instance = eventObject.__r3f;
|
|
409
|
+
const handlers = instance == null ? void 0 : instance.handlers; // Check presence of handlers
|
|
381
410
|
|
|
382
|
-
if (!(
|
|
411
|
+
if (!(instance != null && instance.eventCount)) return;
|
|
383
412
|
|
|
384
413
|
if (isPointerMove) {
|
|
385
414
|
// Move event ...
|
|
@@ -422,9 +451,9 @@ function createEvents(store) {
|
|
|
422
451
|
|
|
423
452
|
function pointerMissed(event, objects) {
|
|
424
453
|
objects.forEach(object => {
|
|
425
|
-
var
|
|
454
|
+
var _r3f3;
|
|
426
455
|
|
|
427
|
-
return (
|
|
456
|
+
return (_r3f3 = object.__r3f) == null ? void 0 : _r3f3.handlers.onPointerMissed == null ? void 0 : _r3f3.handlers.onPointerMissed(event);
|
|
428
457
|
});
|
|
429
458
|
}
|
|
430
459
|
|
|
@@ -475,9 +504,8 @@ function prepare(object, state) {
|
|
|
475
504
|
instance.__r3f = {
|
|
476
505
|
root: null,
|
|
477
506
|
memoizedProps: {},
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
},
|
|
507
|
+
eventCount: 0,
|
|
508
|
+
handlers: {},
|
|
481
509
|
objects: [],
|
|
482
510
|
parent: null,
|
|
483
511
|
...state
|
|
@@ -538,7 +566,7 @@ function createRenderer(roots) {
|
|
|
538
566
|
}
|
|
539
567
|
|
|
540
568
|
function applyProps(instance, data) {
|
|
541
|
-
var _instance$__r3f3, _root$getState,
|
|
569
|
+
var _instance$__r3f3, _root$getState, _instance$__r3f4;
|
|
542
570
|
|
|
543
571
|
// Filter equals, events and reserved props
|
|
544
572
|
const localState = (_instance$__r3f3 = instance == null ? void 0 : instance.__r3f) != null ? _instance$__r3f3 : {};
|
|
@@ -548,7 +576,7 @@ function createRenderer(roots) {
|
|
|
548
576
|
memoized,
|
|
549
577
|
changes
|
|
550
578
|
} = isDiffSet(data) ? data : diffProps(instance, data);
|
|
551
|
-
const prevHandlers =
|
|
579
|
+
const prevHandlers = localState.eventCount; // Prepare memoized props
|
|
552
580
|
|
|
553
581
|
if (instance.__r3f) instance.__r3f.memoizedProps = memoized;
|
|
554
582
|
changes.forEach(([key, value, isEvent, keys]) => {
|
|
@@ -587,7 +615,7 @@ function createRenderer(roots) {
|
|
|
587
615
|
|
|
588
616
|
if (isEvent) {
|
|
589
617
|
if (value) localState.handlers[key] = value;else delete localState.handlers[key];
|
|
590
|
-
localState.
|
|
618
|
+
localState.eventCount = Object.keys(localState.handlers).length;
|
|
591
619
|
} // Special treatment for objects with support for set/copy, and layers
|
|
592
620
|
else if (targetProp && targetProp.set && (targetProp.copy || targetProp instanceof THREE__namespace.Layers)) {
|
|
593
621
|
// If value is an array
|
|
@@ -617,16 +645,17 @@ function createRenderer(roots) {
|
|
|
617
645
|
invalidateInstance(instance);
|
|
618
646
|
});
|
|
619
647
|
|
|
620
|
-
if (rootState.internal && instance.raycast && prevHandlers !==
|
|
648
|
+
if (rootState.internal && instance.raycast && prevHandlers !== localState.eventCount) {
|
|
621
649
|
// Pre-emptively remove the instance from the interaction manager
|
|
622
650
|
const index = rootState.internal.interaction.indexOf(instance);
|
|
623
651
|
if (index > -1) rootState.internal.interaction.splice(index, 1); // Add the instance to the interaction manager only when it has handlers
|
|
624
652
|
|
|
625
|
-
if (localState.
|
|
653
|
+
if (localState.eventCount) rootState.internal.interaction.push(instance);
|
|
626
654
|
} // Call the update lifecycle when it is being updated
|
|
627
655
|
|
|
628
656
|
|
|
629
657
|
if (changes.length && (_instance$__r3f4 = instance.__r3f) != null && _instance$__r3f4.parent) updateInstance(instance);
|
|
658
|
+
return instance;
|
|
630
659
|
}
|
|
631
660
|
|
|
632
661
|
function invalidateInstance(instance) {
|
|
@@ -669,14 +698,13 @@ function createRenderer(roots) {
|
|
|
669
698
|
});
|
|
670
699
|
} else {
|
|
671
700
|
const target = catalogue[name] || THREE__namespace[name];
|
|
672
|
-
if (!target) throw `${name} is not part of the THREE namespace! Did you forget to extend? See: https://github.com/pmndrs/react-three-fiber/blob/master/markdown/api.md#using-3rd-party-objects-declaratively`;
|
|
673
|
-
|
|
701
|
+
if (!target) throw `${name} is not part of the THREE namespace! Did you forget to extend? See: https://github.com/pmndrs/react-three-fiber/blob/master/markdown/api.md#using-3rd-party-objects-declaratively`; // Instanciate new object, link it to the root
|
|
702
|
+
// Append memoized props with args so it's not forgotten
|
|
674
703
|
|
|
675
|
-
instance = prepare(
|
|
704
|
+
instance = prepare(new target(...args), {
|
|
676
705
|
root,
|
|
677
|
-
// append memoized props with args so it's not forgotten
|
|
678
706
|
memoizedProps: {
|
|
679
|
-
args:
|
|
707
|
+
args: args.length === 0 ? null : args
|
|
680
708
|
}
|
|
681
709
|
});
|
|
682
710
|
} // Auto-attach geometries and materials
|
|
@@ -813,7 +841,7 @@ function createRenderer(roots) {
|
|
|
813
841
|
} else if (is.fun(detachFn)) {
|
|
814
842
|
detachFn(child, parentInstance);
|
|
815
843
|
}
|
|
816
|
-
} else if (child.isObject3D) {
|
|
844
|
+
} else if (child.isObject3D && parentInstance.isObject3D) {
|
|
817
845
|
var _child$__r3f;
|
|
818
846
|
|
|
819
847
|
parentInstance.remove(child); // Remove interactivity
|
|
@@ -875,8 +903,9 @@ function createRenderer(roots) {
|
|
|
875
903
|
const newInstance = createInstance(type, newProps, instance.__r3f.root); // https://github.com/pmndrs/react-three-fiber/issues/1348
|
|
876
904
|
// When args change the instance has to be re-constructed, which then
|
|
877
905
|
// forces r3f to re-parent the children and non-scene objects
|
|
906
|
+
// This can not include primitives, which should not have declarative children
|
|
878
907
|
|
|
879
|
-
if (instance.children) {
|
|
908
|
+
if (type !== 'primitive' && instance.children) {
|
|
880
909
|
instance.children.forEach(child => appendChild(newInstance, child));
|
|
881
910
|
instance.children = [];
|
|
882
911
|
}
|
|
@@ -955,7 +984,6 @@ function createRenderer(roots) {
|
|
|
955
984
|
},
|
|
956
985
|
|
|
957
986
|
commitUpdate(instance, [reconstruct, diff], type, oldProps, newProps, fiber) {
|
|
958
|
-
//console.log(type)
|
|
959
987
|
// Reconstruct when args or <primitive object={...} have changes
|
|
960
988
|
if (reconstruct) switchInstance(instance, type, newProps, fiber); // Otherwise just overwrite props
|
|
961
989
|
else applyProps(instance, diff);
|
|
@@ -1031,7 +1059,7 @@ function createRenderer(roots) {
|
|
|
1031
1059
|
};
|
|
1032
1060
|
}
|
|
1033
1061
|
|
|
1034
|
-
const isRenderer = def => def &&
|
|
1062
|
+
const isRenderer = def => !!(def != null && def.render);
|
|
1035
1063
|
const isOrthographicCamera = def => def && def.isOrthographicCamera;
|
|
1036
1064
|
function calculateDpr(dpr) {
|
|
1037
1065
|
return Array.isArray(dpr) ? Math.min(Math.max(dpr[0], window.devicePixelRatio), dpr[1]) : dpr;
|
|
@@ -1059,11 +1087,11 @@ const createStore = (applyProps, invalidate, advance, props) => {
|
|
|
1059
1087
|
if (shadows) {
|
|
1060
1088
|
gl.shadowMap.enabled = true;
|
|
1061
1089
|
if (typeof shadows === 'object') Object.assign(gl.shadowMap, shadows);else gl.shadowMap.type = THREE__namespace.PCFSoftShadowMap;
|
|
1062
|
-
} // Set color
|
|
1090
|
+
} // Set color preferences
|
|
1063
1091
|
|
|
1064
1092
|
|
|
1065
|
-
if (
|
|
1066
|
-
if (
|
|
1093
|
+
if (linear) gl.outputEncoding = THREE__namespace.LinearEncoding;
|
|
1094
|
+
if (flat) gl.toneMapping = THREE__namespace.NoToneMapping; // clock.elapsedTime is updated using advance(timestamp)
|
|
1067
1095
|
|
|
1068
1096
|
if (frameloop === 'never') {
|
|
1069
1097
|
clock.stop();
|
|
@@ -1638,13 +1666,23 @@ const {
|
|
|
1638
1666
|
applyProps
|
|
1639
1667
|
} = createRenderer();
|
|
1640
1668
|
|
|
1641
|
-
const createRendererInstance = (gl, canvas) =>
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1669
|
+
const createRendererInstance = (gl, canvas) => {
|
|
1670
|
+
const customRenderer = typeof gl === 'function' ? gl(canvas) : gl;
|
|
1671
|
+
if (isRenderer(customRenderer)) return customRenderer;
|
|
1672
|
+
const renderer = new THREE__namespace.WebGLRenderer({
|
|
1673
|
+
powerPreference: 'high-performance',
|
|
1674
|
+
canvas: canvas,
|
|
1675
|
+
antialias: true,
|
|
1676
|
+
alpha: true,
|
|
1677
|
+
...gl
|
|
1678
|
+
}); // Set color management
|
|
1679
|
+
|
|
1680
|
+
renderer.outputEncoding = THREE__namespace.sRGBEncoding;
|
|
1681
|
+
renderer.toneMapping = THREE__namespace.ACESFilmicToneMapping; // Set gl props
|
|
1682
|
+
|
|
1683
|
+
if (gl) applyProps(renderer, gl);
|
|
1684
|
+
return renderer;
|
|
1685
|
+
};
|
|
1648
1686
|
|
|
1649
1687
|
function render(element, canvas, {
|
|
1650
1688
|
gl,
|
|
@@ -42,6 +42,23 @@ const is = {
|
|
|
42
42
|
function makeId(event) {
|
|
43
43
|
return (event.eventObject || event.object).uuid + '/' + event.index + event.instanceId;
|
|
44
44
|
}
|
|
45
|
+
/** Release pointer captures.
|
|
46
|
+
* This is called by releasePointerCapture in the API, and when an object is removed.
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
function releaseInternalPointerCapture(capturedMap, obj, captures, pointerId) {
|
|
51
|
+
const captureData = captures.get(obj);
|
|
52
|
+
|
|
53
|
+
if (captureData) {
|
|
54
|
+
captures.delete(obj); // If this was the last capturing object for this pointer
|
|
55
|
+
|
|
56
|
+
if (captures.size === 0) {
|
|
57
|
+
capturedMap.delete(pointerId);
|
|
58
|
+
captureData.target.releasePointerCapture(pointerId);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
45
62
|
|
|
46
63
|
function removeInteractivity(store, object) {
|
|
47
64
|
const {
|
|
@@ -55,6 +72,9 @@ function removeInteractivity(store, object) {
|
|
|
55
72
|
internal.hovered.delete(key);
|
|
56
73
|
}
|
|
57
74
|
});
|
|
75
|
+
internal.capturedMap.forEach((captures, pointerId) => {
|
|
76
|
+
releaseInternalPointerCapture(internal.capturedMap, object, captures, pointerId);
|
|
77
|
+
});
|
|
58
78
|
}
|
|
59
79
|
function createEvents(store) {
|
|
60
80
|
const temp = new THREE.Vector3();
|
|
@@ -134,7 +154,7 @@ function createEvents(store) {
|
|
|
134
154
|
while (eventObject) {
|
|
135
155
|
var _r3f2;
|
|
136
156
|
|
|
137
|
-
if ((_r3f2 = eventObject.__r3f) != null && _r3f2.
|
|
157
|
+
if ((_r3f2 = eventObject.__r3f) != null && _r3f2.eventCount) intersections.push({ ...intersect,
|
|
138
158
|
eventObject
|
|
139
159
|
});
|
|
140
160
|
eventObject = eventObject.parent;
|
|
@@ -153,7 +173,9 @@ function createEvents(store) {
|
|
|
153
173
|
// intersect.
|
|
154
174
|
|
|
155
175
|
if ('pointerId' in event && internal.capturedMap.has(event.pointerId)) {
|
|
156
|
-
|
|
176
|
+
for (let captureData of internal.capturedMap.get(event.pointerId).values()) {
|
|
177
|
+
intersections.push(captureData.intersection);
|
|
178
|
+
}
|
|
157
179
|
}
|
|
158
180
|
|
|
159
181
|
return intersections;
|
|
@@ -171,9 +193,6 @@ function createEvents(store) {
|
|
|
171
193
|
|
|
172
194
|
if (intersections.length) {
|
|
173
195
|
const unprojectedPoint = temp.set(mouse.x, mouse.y, 0).unproject(camera);
|
|
174
|
-
|
|
175
|
-
const releasePointerCapture = id => event.target.releasePointerCapture(id);
|
|
176
|
-
|
|
177
196
|
const localState = {
|
|
178
197
|
stopped: false
|
|
179
198
|
};
|
|
@@ -186,23 +205,36 @@ function createEvents(store) {
|
|
|
186
205
|
};
|
|
187
206
|
|
|
188
207
|
const setPointerCapture = id => {
|
|
208
|
+
const captureData = {
|
|
209
|
+
intersection: hit,
|
|
210
|
+
target: event.target
|
|
211
|
+
};
|
|
212
|
+
|
|
189
213
|
if (internal.capturedMap.has(id)) {
|
|
190
214
|
// if the pointerId was previously captured, we add the hit to the
|
|
191
215
|
// event capturedMap.
|
|
192
|
-
internal.capturedMap.get(id).set(hit.eventObject,
|
|
216
|
+
internal.capturedMap.get(id).set(hit.eventObject, captureData);
|
|
193
217
|
} else {
|
|
194
218
|
// if the pointerId was not previously captured, we create a map
|
|
195
219
|
// containing the hitObject, and the hit. hitObject is used for
|
|
196
220
|
// faster access.
|
|
197
|
-
internal.capturedMap.set(id, new Map([[hit.eventObject,
|
|
221
|
+
internal.capturedMap.set(id, new Map([[hit.eventObject, captureData]]));
|
|
198
222
|
} // Call the original event now
|
|
199
223
|
event.target.setPointerCapture(id);
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
const releasePointerCapture = id => {
|
|
227
|
+
const captures = internal.capturedMap.get(id);
|
|
228
|
+
|
|
229
|
+
if (captures) {
|
|
230
|
+
releaseInternalPointerCapture(internal.capturedMap, hit.eventObject, captures, id);
|
|
231
|
+
}
|
|
200
232
|
}; // Add native event props
|
|
201
233
|
|
|
202
234
|
|
|
203
|
-
let extractEventProps = {};
|
|
235
|
+
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.
|
|
204
236
|
|
|
205
|
-
for (let prop in
|
|
237
|
+
for (let prop in event) {
|
|
206
238
|
let property = event[prop]; // Only copy over atomics, leave functions alone as these should be
|
|
207
239
|
// called as event.nativeEvent.fn()
|
|
208
240
|
|
|
@@ -271,13 +303,12 @@ function createEvents(store) {
|
|
|
271
303
|
// When no objects were hit or the the hovered object wasn't found underneath the cursor
|
|
272
304
|
// we call onPointerOut and delete the object from the hovered-elements map
|
|
273
305
|
if (!hits.length || !hits.find(hit => hit.object === hoveredObj.object && hit.index === hoveredObj.index && hit.instanceId === hoveredObj.instanceId)) {
|
|
274
|
-
var _r3f3;
|
|
275
|
-
|
|
276
306
|
const eventObject = hoveredObj.eventObject;
|
|
277
|
-
const
|
|
307
|
+
const instance = eventObject.__r3f;
|
|
308
|
+
const handlers = instance == null ? void 0 : instance.handlers;
|
|
278
309
|
internal.hovered.delete(makeId(hoveredObj));
|
|
279
310
|
|
|
280
|
-
if (
|
|
311
|
+
if (instance != null && instance.eventCount) {
|
|
281
312
|
// Clear out intersects, they are outdated by now
|
|
282
313
|
const data = { ...hoveredObj,
|
|
283
314
|
intersections: hits || []
|
|
@@ -299,9 +330,8 @@ function createEvents(store) {
|
|
|
299
330
|
case 'onLostPointerCapture':
|
|
300
331
|
return event => {
|
|
301
332
|
if ('pointerId' in event) {
|
|
302
|
-
//
|
|
303
|
-
//
|
|
304
|
-
// indifferently deletes all capturing references.
|
|
333
|
+
// If the object event interface had onLostPointerCapture, we'd call it here on every
|
|
334
|
+
// object that's getting removed.
|
|
305
335
|
store.getState().internal.capturedMap.delete(event.pointerId);
|
|
306
336
|
}
|
|
307
337
|
|
|
@@ -340,12 +370,11 @@ function createEvents(store) {
|
|
|
340
370
|
|
|
341
371
|
if (isPointerMove) cancelPointer(hits);
|
|
342
372
|
handleIntersects(hits, event, delta, data => {
|
|
343
|
-
var _r3f4;
|
|
344
|
-
|
|
345
373
|
const eventObject = data.eventObject;
|
|
346
|
-
const
|
|
374
|
+
const instance = eventObject.__r3f;
|
|
375
|
+
const handlers = instance == null ? void 0 : instance.handlers; // Check presence of handlers
|
|
347
376
|
|
|
348
|
-
if (!(
|
|
377
|
+
if (!(instance != null && instance.eventCount)) return;
|
|
349
378
|
|
|
350
379
|
if (isPointerMove) {
|
|
351
380
|
// Move event ...
|
|
@@ -388,9 +417,9 @@ function createEvents(store) {
|
|
|
388
417
|
|
|
389
418
|
function pointerMissed(event, objects) {
|
|
390
419
|
objects.forEach(object => {
|
|
391
|
-
var
|
|
420
|
+
var _r3f3;
|
|
392
421
|
|
|
393
|
-
return (
|
|
422
|
+
return (_r3f3 = object.__r3f) == null ? void 0 : _r3f3.handlers.onPointerMissed == null ? void 0 : _r3f3.handlers.onPointerMissed(event);
|
|
394
423
|
});
|
|
395
424
|
}
|
|
396
425
|
|
|
@@ -441,9 +470,8 @@ function prepare(object, state) {
|
|
|
441
470
|
instance.__r3f = {
|
|
442
471
|
root: null,
|
|
443
472
|
memoizedProps: {},
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
},
|
|
473
|
+
eventCount: 0,
|
|
474
|
+
handlers: {},
|
|
447
475
|
objects: [],
|
|
448
476
|
parent: null,
|
|
449
477
|
...state
|
|
@@ -504,7 +532,7 @@ function createRenderer(roots) {
|
|
|
504
532
|
}
|
|
505
533
|
|
|
506
534
|
function applyProps(instance, data) {
|
|
507
|
-
var _instance$__r3f3, _root$getState,
|
|
535
|
+
var _instance$__r3f3, _root$getState, _instance$__r3f4;
|
|
508
536
|
|
|
509
537
|
// Filter equals, events and reserved props
|
|
510
538
|
const localState = (_instance$__r3f3 = instance == null ? void 0 : instance.__r3f) != null ? _instance$__r3f3 : {};
|
|
@@ -514,7 +542,7 @@ function createRenderer(roots) {
|
|
|
514
542
|
memoized,
|
|
515
543
|
changes
|
|
516
544
|
} = isDiffSet(data) ? data : diffProps(instance, data);
|
|
517
|
-
const prevHandlers =
|
|
545
|
+
const prevHandlers = localState.eventCount; // Prepare memoized props
|
|
518
546
|
|
|
519
547
|
if (instance.__r3f) instance.__r3f.memoizedProps = memoized;
|
|
520
548
|
changes.forEach(([key, value, isEvent, keys]) => {
|
|
@@ -553,7 +581,7 @@ function createRenderer(roots) {
|
|
|
553
581
|
|
|
554
582
|
if (isEvent) {
|
|
555
583
|
if (value) localState.handlers[key] = value;else delete localState.handlers[key];
|
|
556
|
-
localState.
|
|
584
|
+
localState.eventCount = Object.keys(localState.handlers).length;
|
|
557
585
|
} // Special treatment for objects with support for set/copy, and layers
|
|
558
586
|
else if (targetProp && targetProp.set && (targetProp.copy || targetProp instanceof THREE.Layers)) {
|
|
559
587
|
// If value is an array
|
|
@@ -583,16 +611,17 @@ function createRenderer(roots) {
|
|
|
583
611
|
invalidateInstance(instance);
|
|
584
612
|
});
|
|
585
613
|
|
|
586
|
-
if (rootState.internal && instance.raycast && prevHandlers !==
|
|
614
|
+
if (rootState.internal && instance.raycast && prevHandlers !== localState.eventCount) {
|
|
587
615
|
// Pre-emptively remove the instance from the interaction manager
|
|
588
616
|
const index = rootState.internal.interaction.indexOf(instance);
|
|
589
617
|
if (index > -1) rootState.internal.interaction.splice(index, 1); // Add the instance to the interaction manager only when it has handlers
|
|
590
618
|
|
|
591
|
-
if (localState.
|
|
619
|
+
if (localState.eventCount) rootState.internal.interaction.push(instance);
|
|
592
620
|
} // Call the update lifecycle when it is being updated
|
|
593
621
|
|
|
594
622
|
|
|
595
623
|
if (changes.length && (_instance$__r3f4 = instance.__r3f) != null && _instance$__r3f4.parent) updateInstance(instance);
|
|
624
|
+
return instance;
|
|
596
625
|
}
|
|
597
626
|
|
|
598
627
|
function invalidateInstance(instance) {
|
|
@@ -635,14 +664,13 @@ function createRenderer(roots) {
|
|
|
635
664
|
});
|
|
636
665
|
} else {
|
|
637
666
|
const target = catalogue[name] || THREE[name];
|
|
638
|
-
if (!target) throw `${name} is not part of the THREE namespace! Did you forget to extend? See: https://github.com/pmndrs/react-three-fiber/blob/master/markdown/api.md#using-3rd-party-objects-declaratively`;
|
|
639
|
-
|
|
667
|
+
if (!target) throw `${name} is not part of the THREE namespace! Did you forget to extend? See: https://github.com/pmndrs/react-three-fiber/blob/master/markdown/api.md#using-3rd-party-objects-declaratively`; // Instanciate new object, link it to the root
|
|
668
|
+
// Append memoized props with args so it's not forgotten
|
|
640
669
|
|
|
641
|
-
instance = prepare(
|
|
670
|
+
instance = prepare(new target(...args), {
|
|
642
671
|
root,
|
|
643
|
-
// append memoized props with args so it's not forgotten
|
|
644
672
|
memoizedProps: {
|
|
645
|
-
args:
|
|
673
|
+
args: args.length === 0 ? null : args
|
|
646
674
|
}
|
|
647
675
|
});
|
|
648
676
|
} // Auto-attach geometries and materials
|
|
@@ -779,7 +807,7 @@ function createRenderer(roots) {
|
|
|
779
807
|
} else if (is.fun(detachFn)) {
|
|
780
808
|
detachFn(child, parentInstance);
|
|
781
809
|
}
|
|
782
|
-
} else if (child.isObject3D) {
|
|
810
|
+
} else if (child.isObject3D && parentInstance.isObject3D) {
|
|
783
811
|
var _child$__r3f;
|
|
784
812
|
|
|
785
813
|
parentInstance.remove(child); // Remove interactivity
|
|
@@ -841,8 +869,9 @@ function createRenderer(roots) {
|
|
|
841
869
|
const newInstance = createInstance(type, newProps, instance.__r3f.root); // https://github.com/pmndrs/react-three-fiber/issues/1348
|
|
842
870
|
// When args change the instance has to be re-constructed, which then
|
|
843
871
|
// forces r3f to re-parent the children and non-scene objects
|
|
872
|
+
// This can not include primitives, which should not have declarative children
|
|
844
873
|
|
|
845
|
-
if (instance.children) {
|
|
874
|
+
if (type !== 'primitive' && instance.children) {
|
|
846
875
|
instance.children.forEach(child => appendChild(newInstance, child));
|
|
847
876
|
instance.children = [];
|
|
848
877
|
}
|
|
@@ -921,7 +950,6 @@ function createRenderer(roots) {
|
|
|
921
950
|
},
|
|
922
951
|
|
|
923
952
|
commitUpdate(instance, [reconstruct, diff], type, oldProps, newProps, fiber) {
|
|
924
|
-
//console.log(type)
|
|
925
953
|
// Reconstruct when args or <primitive object={...} have changes
|
|
926
954
|
if (reconstruct) switchInstance(instance, type, newProps, fiber); // Otherwise just overwrite props
|
|
927
955
|
else applyProps(instance, diff);
|
|
@@ -997,7 +1025,7 @@ function createRenderer(roots) {
|
|
|
997
1025
|
};
|
|
998
1026
|
}
|
|
999
1027
|
|
|
1000
|
-
const isRenderer = def => def &&
|
|
1028
|
+
const isRenderer = def => !!(def != null && def.render);
|
|
1001
1029
|
const isOrthographicCamera = def => def && def.isOrthographicCamera;
|
|
1002
1030
|
function calculateDpr(dpr) {
|
|
1003
1031
|
return Array.isArray(dpr) ? Math.min(Math.max(dpr[0], window.devicePixelRatio), dpr[1]) : dpr;
|
|
@@ -1025,11 +1053,11 @@ const createStore = (applyProps, invalidate, advance, props) => {
|
|
|
1025
1053
|
if (shadows) {
|
|
1026
1054
|
gl.shadowMap.enabled = true;
|
|
1027
1055
|
if (typeof shadows === 'object') Object.assign(gl.shadowMap, shadows);else gl.shadowMap.type = THREE.PCFSoftShadowMap;
|
|
1028
|
-
} // Set color
|
|
1056
|
+
} // Set color preferences
|
|
1029
1057
|
|
|
1030
1058
|
|
|
1031
|
-
if (
|
|
1032
|
-
if (
|
|
1059
|
+
if (linear) gl.outputEncoding = THREE.LinearEncoding;
|
|
1060
|
+
if (flat) gl.toneMapping = THREE.NoToneMapping; // clock.elapsedTime is updated using advance(timestamp)
|
|
1033
1061
|
|
|
1034
1062
|
if (frameloop === 'never') {
|
|
1035
1063
|
clock.stop();
|
|
@@ -1604,13 +1632,23 @@ const {
|
|
|
1604
1632
|
applyProps
|
|
1605
1633
|
} = createRenderer();
|
|
1606
1634
|
|
|
1607
|
-
const createRendererInstance = (gl, canvas) =>
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1635
|
+
const createRendererInstance = (gl, canvas) => {
|
|
1636
|
+
const customRenderer = typeof gl === 'function' ? gl(canvas) : gl;
|
|
1637
|
+
if (isRenderer(customRenderer)) return customRenderer;
|
|
1638
|
+
const renderer = new THREE.WebGLRenderer({
|
|
1639
|
+
powerPreference: 'high-performance',
|
|
1640
|
+
canvas: canvas,
|
|
1641
|
+
antialias: true,
|
|
1642
|
+
alpha: true,
|
|
1643
|
+
...gl
|
|
1644
|
+
}); // Set color management
|
|
1645
|
+
|
|
1646
|
+
renderer.outputEncoding = THREE.sRGBEncoding;
|
|
1647
|
+
renderer.toneMapping = THREE.ACESFilmicToneMapping; // Set gl props
|
|
1648
|
+
|
|
1649
|
+
if (gl) applyProps(renderer, gl);
|
|
1650
|
+
return renderer;
|
|
1651
|
+
};
|
|
1614
1652
|
|
|
1615
1653
|
function render(element, canvas, {
|
|
1616
1654
|
gl,
|