@threlte/xr 1.0.0-next.2 → 1.0.0-next.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/ARButton.svelte +2 -2
- package/dist/components/ARButton.svelte.d.ts +12 -2
- package/dist/components/Controller.svelte +25 -3
- package/dist/components/Controller.svelte.d.ts +9 -12
- package/dist/components/Hand.svelte +9 -2
- package/dist/components/Hand.svelte.d.ts +9 -15
- package/dist/components/VRButton.svelte +2 -2
- package/dist/components/VRButton.svelte.d.ts +12 -2
- package/dist/components/XR.svelte +17 -12
- package/dist/components/XR.svelte.d.ts +18 -25
- package/dist/components/XRButton.svelte +9 -7
- package/dist/components/XRButton.svelte.d.ts +12 -2
- package/dist/internal/stores.d.ts +5 -4
- package/dist/plugins/pointerControls/plugin.js +6 -2
- package/dist/plugins/pointerControls/setup.js +28 -27
- package/dist/plugins/pointerControls/types.d.ts +10 -10
- package/dist/plugins/pointerControls/types.js +9 -9
- package/dist/plugins/teleportControls/context.d.ts +9 -3
- package/dist/plugins/teleportControls/context.js +45 -2
- package/dist/plugins/teleportControls/index.js +4 -13
- package/dist/plugins/teleportControls/plugin.js +2 -2
- package/dist/plugins/teleportControls/setup.js +1 -1
- package/dist/types.d.ts +23 -7
- package/package.json +3 -3
- package/dist/plugins/teleportControls/hook.d.ts +0 -7
- package/dist/plugins/teleportControls/hook.js +0 -38
|
@@ -10,6 +10,16 @@ declare const __propDef: {
|
|
|
10
10
|
}) | undefined;
|
|
11
11
|
force?: "enter" | "exit" | undefined;
|
|
12
12
|
styled?: boolean | undefined;
|
|
13
|
+
children?: ((this: void, args_0: {
|
|
14
|
+
state: "blocked" | "unsupported" | "insecure" | "supported";
|
|
15
|
+
}) => typeof import("svelte").SnippetReturn & {
|
|
16
|
+
_: "functions passed to {@render ...} tags must use the `Snippet` type imported from \"svelte\"";
|
|
17
|
+
}) | undefined;
|
|
18
|
+
onclick?: ((event: {
|
|
19
|
+
state: "blocked" | "unsupported" | "insecure" | "supported";
|
|
20
|
+
nativeEvent: MouseEvent;
|
|
21
|
+
}) => void) | undefined;
|
|
22
|
+
onerror?: ((error: Error) => void) | undefined;
|
|
13
23
|
}, "mode" | "sessionInit"> & {
|
|
14
24
|
sessionInit?: (XRSessionInit & {
|
|
15
25
|
domOverlay?: {
|
|
@@ -30,8 +40,8 @@ export type ArButtonSlots = typeof __propDef.slots;
|
|
|
30
40
|
*
|
|
31
41
|
* ```svelte
|
|
32
42
|
* <ARButton
|
|
33
|
-
*
|
|
34
|
-
*
|
|
43
|
+
* onerror={(event) => {}}
|
|
44
|
+
* onclick={(event) => {}}
|
|
35
45
|
* />
|
|
36
46
|
* ```
|
|
37
47
|
*/
|
|
@@ -19,11 +19,33 @@ const stores = {
|
|
|
19
19
|
};
|
|
20
20
|
</script>
|
|
21
21
|
|
|
22
|
-
<script lang="ts">let {
|
|
22
|
+
<script lang="ts">let {
|
|
23
|
+
left,
|
|
24
|
+
right,
|
|
25
|
+
hand,
|
|
26
|
+
onconnected,
|
|
27
|
+
ondisconnected,
|
|
28
|
+
onselect,
|
|
29
|
+
onselectend,
|
|
30
|
+
onselectstart,
|
|
31
|
+
onsqueeze,
|
|
32
|
+
onsqueezeend,
|
|
33
|
+
onsqueezestart
|
|
34
|
+
} = $props();
|
|
23
35
|
const handedness = writable(left ? "left" : right ? "right" : hand);
|
|
24
36
|
$effect.pre(() => handedness.set(left ? "left" : right ? "right" : hand));
|
|
25
|
-
|
|
26
|
-
|
|
37
|
+
$effect.pre(
|
|
38
|
+
() => controllerEvents[$handedness].set({
|
|
39
|
+
onconnected,
|
|
40
|
+
ondisconnected,
|
|
41
|
+
onselect,
|
|
42
|
+
onselectend,
|
|
43
|
+
onselectstart,
|
|
44
|
+
onsqueeze,
|
|
45
|
+
onsqueezeend,
|
|
46
|
+
onsqueezestart
|
|
47
|
+
})
|
|
48
|
+
);
|
|
27
49
|
let store = $derived(stores[$handedness]);
|
|
28
50
|
let grip = $derived($store?.grip);
|
|
29
51
|
let targetRay = $derived($store?.targetRay);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SvelteComponent } from "svelte";
|
|
2
|
-
import type {
|
|
2
|
+
import type { XRControllerEvents } from '../types';
|
|
3
3
|
declare const __propDef: {
|
|
4
|
-
props: {
|
|
4
|
+
props: (XRControllerEvents & ({
|
|
5
5
|
/** Whether the controller should be matched with the left hand. */
|
|
6
6
|
left: true;
|
|
7
7
|
right?: undefined;
|
|
@@ -16,6 +16,13 @@ declare const __propDef: {
|
|
|
16
16
|
hand: 'left' | 'right';
|
|
17
17
|
left?: undefined;
|
|
18
18
|
right?: undefined;
|
|
19
|
+
})) & {
|
|
20
|
+
children?: ((this: void) => typeof import("svelte").SnippetReturn & {
|
|
21
|
+
_: "functions passed to {@render ...} tags must use the `Snippet` type imported from \"svelte\"";
|
|
22
|
+
}) | undefined;
|
|
23
|
+
};
|
|
24
|
+
events: {
|
|
25
|
+
[evt: string]: CustomEvent<any>;
|
|
19
26
|
};
|
|
20
27
|
slots: {
|
|
21
28
|
default: {};
|
|
@@ -26,16 +33,6 @@ declare const __propDef: {
|
|
|
26
33
|
'teleport-ray': {};
|
|
27
34
|
'teleport-cursor': {};
|
|
28
35
|
};
|
|
29
|
-
events: {
|
|
30
|
-
connected: XRControllerEvent<'connected'>;
|
|
31
|
-
disconnected: XRControllerEvent<'disconnected'>;
|
|
32
|
-
select: XRControllerEvent<'select'>;
|
|
33
|
-
selectstart: XRControllerEvent<'selectstart'>;
|
|
34
|
-
selectend: XRControllerEvent<'selectend'>;
|
|
35
|
-
squeeze: XRControllerEvent<'squeeze'>;
|
|
36
|
-
squeezeend: XRControllerEvent<'squeezeend'>;
|
|
37
|
-
squeezestart: XRControllerEvent<'squeezestart'>;
|
|
38
|
-
};
|
|
39
36
|
};
|
|
40
37
|
export type ControllerProps = typeof __propDef.props;
|
|
41
38
|
export type ControllerEvents = typeof __propDef.events;
|
|
@@ -13,12 +13,19 @@ const stores = {
|
|
|
13
13
|
};
|
|
14
14
|
</script>
|
|
15
15
|
|
|
16
|
-
<script lang="ts">let { left, right, hand,
|
|
16
|
+
<script lang="ts">let { left, right, hand, onconnected, ondisconnected, onpinchend, onpinchstart } = $props();
|
|
17
17
|
const { xr } = useThrelte().renderer;
|
|
18
18
|
const space = xr.getReferenceSpace();
|
|
19
19
|
const handedness = writable(left ? "left" : right ? "right" : hand);
|
|
20
20
|
$effect.pre(() => handedness.set(left ? "left" : right ? "right" : hand));
|
|
21
|
-
$effect.pre(
|
|
21
|
+
$effect.pre(
|
|
22
|
+
() => handEvents[$handedness].set({
|
|
23
|
+
onconnected,
|
|
24
|
+
ondisconnected,
|
|
25
|
+
onpinchend,
|
|
26
|
+
onpinchstart
|
|
27
|
+
})
|
|
28
|
+
);
|
|
22
29
|
let children = new Group();
|
|
23
30
|
const { start, stop } = useTask(
|
|
24
31
|
() => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SvelteComponent } from "svelte";
|
|
2
|
-
import type {
|
|
2
|
+
import type { XRHandEvents } from '../types';
|
|
3
3
|
declare const __propDef: {
|
|
4
|
-
props: ({
|
|
4
|
+
props: (XRHandEvents & ({
|
|
5
5
|
/** Whether the XRHand should be matched with the left hand. */
|
|
6
6
|
left: true;
|
|
7
7
|
right?: undefined;
|
|
@@ -16,25 +16,19 @@ declare const __propDef: {
|
|
|
16
16
|
hand: 'left' | 'right';
|
|
17
17
|
left?: undefined;
|
|
18
18
|
right?: undefined;
|
|
19
|
-
}) & {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
})) & {
|
|
20
|
+
children?: ((this: void) => typeof import("svelte").SnippetReturn & {
|
|
21
|
+
_: "functions passed to {@render ...} tags must use the `Snippet` type imported from \"svelte\"";
|
|
22
|
+
}) | undefined;
|
|
23
|
+
};
|
|
24
|
+
events: {
|
|
25
|
+
[evt: string]: CustomEvent<any>;
|
|
26
26
|
};
|
|
27
27
|
slots: {
|
|
28
28
|
'target-ray': {};
|
|
29
29
|
wrist: {};
|
|
30
30
|
default: {};
|
|
31
31
|
};
|
|
32
|
-
events: {
|
|
33
|
-
connected: XRHandEvent<'connected'>;
|
|
34
|
-
disconnected: XRHandEvent<'disconnected'>;
|
|
35
|
-
pinchstart: XRHandEvent<'pinchstart'>;
|
|
36
|
-
pinchend: XRHandEvent<'pinchend'>;
|
|
37
|
-
};
|
|
38
32
|
};
|
|
39
33
|
export type HandProps = typeof __propDef.props;
|
|
40
34
|
export type HandEvents = typeof __propDef.events;
|
|
@@ -10,6 +10,16 @@ declare const __propDef: {
|
|
|
10
10
|
}) | undefined;
|
|
11
11
|
force?: "enter" | "exit" | undefined;
|
|
12
12
|
styled?: boolean | undefined;
|
|
13
|
+
children?: ((this: void, args_0: {
|
|
14
|
+
state: "blocked" | "unsupported" | "insecure" | "supported";
|
|
15
|
+
}) => typeof import("svelte").SnippetReturn & {
|
|
16
|
+
_: "functions passed to {@render ...} tags must use the `Snippet` type imported from \"svelte\"";
|
|
17
|
+
}) | undefined;
|
|
18
|
+
onclick?: ((event: {
|
|
19
|
+
state: "blocked" | "unsupported" | "insecure" | "supported";
|
|
20
|
+
nativeEvent: MouseEvent;
|
|
21
|
+
}) => void) | undefined;
|
|
22
|
+
onerror?: ((error: Error) => void) | undefined;
|
|
13
23
|
}, "mode" | "sessionInit">;
|
|
14
24
|
events: {
|
|
15
25
|
[evt: string]: CustomEvent<any>;
|
|
@@ -24,8 +34,8 @@ export type VrButtonSlots = typeof __propDef.slots;
|
|
|
24
34
|
*
|
|
25
35
|
* ```svelte
|
|
26
36
|
* <VRButton
|
|
27
|
-
*
|
|
28
|
-
*
|
|
37
|
+
* onerror={(event) => {}}
|
|
38
|
+
* onclick={(event) => {}}
|
|
29
39
|
* />
|
|
30
40
|
* ```
|
|
31
41
|
*/
|
|
@@ -9,10 +9,10 @@ This should be placed within a Threlte `<Canvas />`.
|
|
|
9
9
|
foveation={1}
|
|
10
10
|
frameRate={90}
|
|
11
11
|
referenceSpace='local-floor'
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
onsessionstart={(event: XREvent<XRManagerEvent>) => {}}
|
|
13
|
+
onsessionend={(event: XREvent<XRManagerEvent>) => {}}
|
|
14
|
+
onvisibilitychange={(event: XREvent<XRSessionEvent>) => {}}
|
|
15
|
+
oninputsourceschange={(event: XREvent<XRSessionEvent>) => {}}
|
|
16
16
|
/>
|
|
17
17
|
```
|
|
18
18
|
|
|
@@ -34,7 +34,12 @@ let {
|
|
|
34
34
|
foveation = 1,
|
|
35
35
|
frameRate,
|
|
36
36
|
referenceSpace = "local-floor",
|
|
37
|
-
|
|
37
|
+
onsessionstart,
|
|
38
|
+
onsessionend,
|
|
39
|
+
onvisibilitychange,
|
|
40
|
+
oninputsourceschange,
|
|
41
|
+
fallback,
|
|
42
|
+
children
|
|
38
43
|
} = $props();
|
|
39
44
|
const { renderer, renderMode } = useThrelte();
|
|
40
45
|
const { xr } = renderer;
|
|
@@ -45,22 +50,22 @@ setupControllers();
|
|
|
45
50
|
setupHands();
|
|
46
51
|
const handleSessionStart = () => {
|
|
47
52
|
isPresenting.set(true);
|
|
48
|
-
|
|
53
|
+
onsessionstart?.({ type: "sessionstart", target: $session });
|
|
49
54
|
};
|
|
50
55
|
const handleSessionEnd = () => {
|
|
51
|
-
|
|
56
|
+
onsessionend?.({ type: "sessionend", target: $session });
|
|
52
57
|
isPresenting.set(false);
|
|
53
58
|
session.set(void 0);
|
|
54
59
|
};
|
|
55
60
|
const handleVisibilityChange = (event) => {
|
|
56
|
-
|
|
61
|
+
onvisibilitychange?.({ ...event, target: $session });
|
|
57
62
|
};
|
|
58
63
|
const handleInputSourcesChange = (event) => {
|
|
59
64
|
$isHandTracking = Object.values(event.session.inputSources).some((source) => source.hand);
|
|
60
|
-
|
|
65
|
+
oninputsourceschange?.({ ...event, target: $session });
|
|
61
66
|
};
|
|
62
67
|
const handleFramerateChange = (event) => {
|
|
63
|
-
|
|
68
|
+
onvisibilitychange?.({ ...event, target: $session });
|
|
64
69
|
};
|
|
65
70
|
const updateTargetFrameRate = (frameRate2) => {
|
|
66
71
|
if (frameRate2 === void 0)
|
|
@@ -113,7 +118,7 @@ $effect.pre(() => {
|
|
|
113
118
|
</script>
|
|
114
119
|
|
|
115
120
|
{#if $isPresenting}
|
|
116
|
-
|
|
121
|
+
{@render children?.()}
|
|
117
122
|
{:else}
|
|
118
|
-
|
|
123
|
+
{@render fallback?.()}
|
|
119
124
|
{/if}
|
|
@@ -22,32 +22,25 @@ declare const __propDef: {
|
|
|
22
22
|
frameRate?: number | undefined;
|
|
23
23
|
/** Type of WebXR reference space to use. Default is `local-floor` */
|
|
24
24
|
referenceSpace?: XRReferenceSpaceType | undefined;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
/** Called when an XRSession is hidden or unfocused. */
|
|
32
|
-
visibilitychange: (event: globalThis.XRSessionEvent) => void;
|
|
33
|
-
/** Called when available inputsources change */
|
|
34
|
-
inputsourceschange: (event: globalThis.XRSessionEvent) => void;
|
|
35
|
-
};
|
|
36
|
-
};
|
|
37
|
-
slots: {
|
|
38
|
-
default: {};
|
|
39
|
-
fallback: {};
|
|
40
|
-
};
|
|
41
|
-
events: {
|
|
25
|
+
fallback?: ((this: void) => typeof import("svelte").SnippetReturn & {
|
|
26
|
+
_: "functions passed to {@render ...} tags must use the `Snippet` type imported from \"svelte\"";
|
|
27
|
+
}) | undefined;
|
|
28
|
+
children?: ((this: void) => typeof import("svelte").SnippetReturn & {
|
|
29
|
+
_: "functions passed to {@render ...} tags must use the `Snippet` type imported from \"svelte\"";
|
|
30
|
+
}) | undefined;
|
|
42
31
|
/** Called as an XRSession is requested */
|
|
43
|
-
|
|
32
|
+
onsessionstart?: ((event: XRSessionEvent<'sessionstart'>) => void) | undefined;
|
|
44
33
|
/** Called after an XRSession is terminated */
|
|
45
|
-
|
|
34
|
+
onsessionend?: ((event: XRSessionEvent<'sessionend'>) => void) | undefined;
|
|
46
35
|
/** Called when an XRSession is hidden or unfocused. */
|
|
47
|
-
|
|
36
|
+
onvisibilitychange?: ((event: globalThis.XRSessionEvent) => void) | undefined;
|
|
48
37
|
/** Called when available inputsources change */
|
|
49
|
-
|
|
38
|
+
oninputsourceschange?: ((event: globalThis.XRSessionEvent) => void) | undefined;
|
|
39
|
+
};
|
|
40
|
+
events: {
|
|
41
|
+
[evt: string]: CustomEvent<any>;
|
|
50
42
|
};
|
|
43
|
+
slots: {};
|
|
51
44
|
};
|
|
52
45
|
export type XrProps = typeof __propDef.props;
|
|
53
46
|
export type XrEvents = typeof __propDef.events;
|
|
@@ -62,10 +55,10 @@ export type XrSlots = typeof __propDef.slots;
|
|
|
62
55
|
* foveation={1}
|
|
63
56
|
* frameRate={90}
|
|
64
57
|
* referenceSpace='local-floor'
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
58
|
+
* onsessionstart={(event: XREvent<XRManagerEvent>) => {}}
|
|
59
|
+
* onsessionend={(event: XREvent<XRManagerEvent>) => {}}
|
|
60
|
+
* onvisibilitychange={(event: XREvent<XRSessionEvent>) => {}}
|
|
61
|
+
* oninputsourceschange={(event: XREvent<XRSessionEvent>) => {}}
|
|
69
62
|
* />
|
|
70
63
|
* ```
|
|
71
64
|
*/
|
|
@@ -12,28 +12,28 @@ display info about your WebXR session. This is aliased by `ARButton` and
|
|
|
12
12
|
}}
|
|
13
13
|
force={'enter' | 'exit' | undefined}
|
|
14
14
|
styled={'true' | 'false'}
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
onerror={(event) => {}}
|
|
16
|
+
onclick={(event) => {}}
|
|
17
17
|
/>
|
|
18
18
|
```
|
|
19
19
|
-->
|
|
20
20
|
<script lang="ts">import { getXRSupportState } from "../lib/getXRSupportState";
|
|
21
21
|
import { toggleXRSession } from "../lib/toggleXRSession";
|
|
22
22
|
import { session, xr } from "../internal/stores";
|
|
23
|
-
let { mode, sessionInit, force, styled = true, ...props } = $props();
|
|
23
|
+
let { mode, sessionInit, force, styled = true, onclick, onerror, children, ...props } = $props();
|
|
24
24
|
const handleButtonClick = async (nativeEvent, state) => {
|
|
25
25
|
if (!$xr) {
|
|
26
26
|
throw new Error(
|
|
27
27
|
"The <XR> component was not created. This is required to start an XR session."
|
|
28
28
|
);
|
|
29
29
|
}
|
|
30
|
-
|
|
30
|
+
onclick?.({ state, nativeEvent });
|
|
31
31
|
if (state !== "supported")
|
|
32
32
|
return;
|
|
33
33
|
try {
|
|
34
34
|
await toggleXRSession(mode, sessionInit, force);
|
|
35
35
|
} catch (error) {
|
|
36
|
-
|
|
36
|
+
onerror?.(error);
|
|
37
37
|
}
|
|
38
38
|
};
|
|
39
39
|
let modeText = $derived(
|
|
@@ -62,13 +62,15 @@ let style = $derived(
|
|
|
62
62
|
|
|
63
63
|
{#await getXRSupportState(mode) then state}
|
|
64
64
|
<button
|
|
65
|
-
|
|
65
|
+
onclick={(event) => {
|
|
66
66
|
handleButtonClick(event, state)
|
|
67
67
|
}}
|
|
68
68
|
{...props}
|
|
69
69
|
{style}
|
|
70
70
|
>
|
|
71
|
-
{#if
|
|
71
|
+
{#if children}
|
|
72
|
+
{@render children?.({ state })}
|
|
73
|
+
{:else if state === 'unsupported'}
|
|
72
74
|
{modeText} unsupported
|
|
73
75
|
{:else if state === 'insecure'}
|
|
74
76
|
HTTPS needed
|
|
@@ -18,6 +18,16 @@ declare const __propDef: {
|
|
|
18
18
|
force?: "enter" | "exit" | undefined;
|
|
19
19
|
/** Whether to apply automatic styling to the button. Set false to apply custom styles. Default is true. */
|
|
20
20
|
styled?: boolean | undefined;
|
|
21
|
+
children?: ((this: void, args_0: {
|
|
22
|
+
state: "blocked" | "unsupported" | "insecure" | "supported";
|
|
23
|
+
}) => typeof import("svelte").SnippetReturn & {
|
|
24
|
+
_: "functions passed to {@render ...} tags must use the `Snippet` type imported from \"svelte\"";
|
|
25
|
+
}) | undefined;
|
|
26
|
+
onclick?: ((event: {
|
|
27
|
+
state: "blocked" | "unsupported" | "insecure" | "supported";
|
|
28
|
+
nativeEvent: MouseEvent;
|
|
29
|
+
}) => void) | undefined;
|
|
30
|
+
onerror?: ((error: Error) => void) | undefined;
|
|
21
31
|
};
|
|
22
32
|
events: {
|
|
23
33
|
[evt: string]: CustomEvent<any>;
|
|
@@ -40,8 +50,8 @@ export type XrButtonSlots = typeof __propDef.slots;
|
|
|
40
50
|
* }}
|
|
41
51
|
* force={'enter' | 'exit' | undefined}
|
|
42
52
|
* styled={'true' | 'false'}
|
|
43
|
-
*
|
|
44
|
-
*
|
|
53
|
+
* onerror={(event) => {}}
|
|
54
|
+
* onclick={(event) => {}}
|
|
45
55
|
* />
|
|
46
56
|
* ```
|
|
47
57
|
*/
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
/// <reference types="webxr" />
|
|
2
2
|
import type { WebXRManager, Intersection } from 'three';
|
|
3
|
+
import type { XRControllerEvents, XRHandEvents } from '../types';
|
|
3
4
|
export declare const isPresenting: import("@threlte/core").CurrentWritable<boolean>;
|
|
4
5
|
export declare const isHandTracking: import("@threlte/core").CurrentWritable<boolean>;
|
|
5
6
|
export declare const session: import("@threlte/core").CurrentWritable<XRSession | undefined>;
|
|
6
7
|
export declare const referenceSpaceType: import("@threlte/core").CurrentWritable<XRReferenceSpaceType | undefined>;
|
|
7
8
|
export declare const xr: import("@threlte/core").CurrentWritable<WebXRManager | undefined>;
|
|
8
9
|
export declare const controllerEvents: {
|
|
9
|
-
left: import("@threlte/core").CurrentWritable<
|
|
10
|
-
right: import("@threlte/core").CurrentWritable<
|
|
10
|
+
left: import("@threlte/core").CurrentWritable<XRControllerEvents | undefined>;
|
|
11
|
+
right: import("@threlte/core").CurrentWritable<XRControllerEvents | undefined>;
|
|
11
12
|
};
|
|
12
13
|
export declare const handEvents: {
|
|
13
|
-
left: import("@threlte/core").CurrentWritable<
|
|
14
|
-
right: import("@threlte/core").CurrentWritable<
|
|
14
|
+
left: import("@threlte/core").CurrentWritable<XRHandEvents | undefined>;
|
|
15
|
+
right: import("@threlte/core").CurrentWritable<XRHandEvents | undefined>;
|
|
15
16
|
};
|
|
16
17
|
export declare const teleportState: import("@threlte/core").CurrentWritable<{
|
|
17
18
|
left: {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { injectPlugin, watch } from '@threlte/core';
|
|
2
2
|
import { writable } from 'svelte/store';
|
|
3
3
|
import { usePointerControls } from './hook';
|
|
4
|
+
import { events } from './types';
|
|
4
5
|
export const injectPointerControlsPlugin = () => {
|
|
5
6
|
injectPlugin('threlte-pointer-controls', ({ ref, props }) => {
|
|
6
7
|
if (!ref.isObject3D)
|
|
@@ -8,9 +9,12 @@ export const injectPointerControlsPlugin = () => {
|
|
|
8
9
|
const { addInteractiveObject, removeInteractiveObject } = usePointerControls();
|
|
9
10
|
const refStore = writable(ref);
|
|
10
11
|
watch(refStore, ($refStore) => {
|
|
11
|
-
|
|
12
|
+
const hasEventHandlers = Object.entries(props).some(([key, value]) => {
|
|
13
|
+
return value !== undefined && events.includes(key);
|
|
14
|
+
});
|
|
15
|
+
if (!hasEventHandlers)
|
|
12
16
|
return;
|
|
13
|
-
addInteractiveObject($refStore, props
|
|
17
|
+
addInteractiveObject($refStore, props);
|
|
14
18
|
return () => removeInteractiveObject($refStore);
|
|
15
19
|
});
|
|
16
20
|
return {
|
|
@@ -24,10 +24,10 @@ export const setupPointerControls = (context, handContext, fixedStep = 1 / 40) =
|
|
|
24
24
|
return;
|
|
25
25
|
handContext.initialClick = [hit.point.x, hit.point.y, hit.point.z];
|
|
26
26
|
handContext.initialHits = hits.map((hit) => hit.eventObject);
|
|
27
|
-
handleEvent('
|
|
27
|
+
handleEvent('onpointerdown', event);
|
|
28
28
|
};
|
|
29
29
|
const handlePointerUp = (event) => {
|
|
30
|
-
handleEvent('
|
|
30
|
+
handleEvent('onpointerup', event);
|
|
31
31
|
};
|
|
32
32
|
const handleClick = (event) => {
|
|
33
33
|
// If a click yields no results, pass it back to the user as a miss
|
|
@@ -35,7 +35,7 @@ export const setupPointerControls = (context, handContext, fixedStep = 1 / 40) =
|
|
|
35
35
|
if (hits.length === 0) {
|
|
36
36
|
pointerMissed(context.interactiveObjects, event);
|
|
37
37
|
}
|
|
38
|
-
handleEvent('
|
|
38
|
+
handleEvent('onclick', event);
|
|
39
39
|
};
|
|
40
40
|
function cancelPointer(intersections) {
|
|
41
41
|
for (const [, hoveredObj] of handContext.hovered) {
|
|
@@ -51,8 +51,8 @@ export const setupPointerControls = (context, handContext, fixedStep = 1 / 40) =
|
|
|
51
51
|
if (events !== undefined) {
|
|
52
52
|
// Clear out intersects, they are outdated by now
|
|
53
53
|
const data = { ...hoveredObj, intersections };
|
|
54
|
-
events.
|
|
55
|
-
events.
|
|
54
|
+
events.onpointerout?.(data);
|
|
55
|
+
events.onpointerleave?.(data);
|
|
56
56
|
// Deal with cancelation
|
|
57
57
|
handContext.pointerOverTarget.set(false);
|
|
58
58
|
cancelPointer([]);
|
|
@@ -88,8 +88,8 @@ export const setupPointerControls = (context, handContext, fixedStep = 1 / 40) =
|
|
|
88
88
|
return getHits();
|
|
89
89
|
}
|
|
90
90
|
const handleEvent = (name, event) => {
|
|
91
|
-
const isPointerMove = name === '
|
|
92
|
-
const isClickEvent = name === '
|
|
91
|
+
const isPointerMove = name === 'onpointermove';
|
|
92
|
+
const isClickEvent = name === 'onclick' || name === 'oncontextmenu';
|
|
93
93
|
// Take care of unhover
|
|
94
94
|
if (isPointerMove)
|
|
95
95
|
cancelPointer(hits);
|
|
@@ -121,17 +121,17 @@ export const setupPointerControls = (context, handContext, fixedStep = 1 / 40) =
|
|
|
121
121
|
if (isPointerMove) {
|
|
122
122
|
// Move event ...
|
|
123
123
|
handContext.pointer.update((value) => value.copy(intersectionEvent.point));
|
|
124
|
-
if (events.
|
|
125
|
-
events.
|
|
126
|
-
events.
|
|
127
|
-
events.
|
|
124
|
+
if (events.onpointerover ||
|
|
125
|
+
events.onpointerenter ||
|
|
126
|
+
events.onpointerout ||
|
|
127
|
+
events.onpointerleave) {
|
|
128
128
|
const id = getIntersectionId(intersectionEvent);
|
|
129
129
|
const hoveredItem = handContext.hovered.get(id);
|
|
130
130
|
if (hoveredItem === undefined) {
|
|
131
131
|
// If the object wasn't previously hovered, book it and call its handler
|
|
132
132
|
handContext.hovered.set(id, intersectionEvent);
|
|
133
|
-
events.
|
|
134
|
-
events.
|
|
133
|
+
events.onpointerover?.(intersectionEvent);
|
|
134
|
+
events.onpointerenter?.(intersectionEvent);
|
|
135
135
|
handContext.pointerOverTarget.set(true);
|
|
136
136
|
}
|
|
137
137
|
else if (hoveredItem.stopped) {
|
|
@@ -140,10 +140,10 @@ export const setupPointerControls = (context, handContext, fixedStep = 1 / 40) =
|
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
142
|
// Call pointer move
|
|
143
|
-
events.
|
|
143
|
+
events.onpointermove?.(intersectionEvent);
|
|
144
144
|
}
|
|
145
145
|
else if ((!isClickEvent || handContext.initialHits.includes(hit.eventObject)) &&
|
|
146
|
-
events[name]) {
|
|
146
|
+
events[name] !== undefined) {
|
|
147
147
|
// Missed events have to come first
|
|
148
148
|
pointerMissed(context.interactiveObjects.filter((object) => !handContext.initialHits.includes(object)), event);
|
|
149
149
|
// Call the event
|
|
@@ -162,7 +162,7 @@ export const setupPointerControls = (context, handContext, fixedStep = 1 / 40) =
|
|
|
162
162
|
if (targetRay === undefined)
|
|
163
163
|
return;
|
|
164
164
|
if (targetRay.position.distanceTo(lastPosition) > EPSILON) {
|
|
165
|
-
handleEvent('
|
|
165
|
+
handleEvent('onpointermove');
|
|
166
166
|
}
|
|
167
167
|
lastPosition.copy(targetRay.position);
|
|
168
168
|
}, {
|
|
@@ -181,17 +181,18 @@ export const setupPointerControls = (context, handContext, fixedStep = 1 / 40) =
|
|
|
181
181
|
input.targetRay.removeEventListener('select', handleClick);
|
|
182
182
|
};
|
|
183
183
|
});
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
184
|
+
watch(hand, (input) => {
|
|
185
|
+
if (input === undefined)
|
|
186
|
+
return;
|
|
187
|
+
input.hand.addEventListener('pinchstart', handlePointerDown);
|
|
188
|
+
input.hand.addEventListener('pinchend', handlePointerUp);
|
|
189
|
+
input.hand.addEventListener('pinchend', handleClick);
|
|
190
|
+
return () => {
|
|
191
|
+
input.hand.removeEventListener('pinchstart', handlePointerDown);
|
|
192
|
+
input.hand.removeEventListener('pinchend', handlePointerUp);
|
|
193
|
+
input.hand.removeEventListener('pinchend', handleClick);
|
|
194
|
+
};
|
|
195
|
+
});
|
|
195
196
|
watch([useXR().isPresenting, handContext.enabled], ([isPresenting, enabled]) => {
|
|
196
197
|
if (isPresenting && enabled) {
|
|
197
198
|
start();
|
|
@@ -48,15 +48,15 @@ export interface PointerCaptureTarget {
|
|
|
48
48
|
target: Element;
|
|
49
49
|
}
|
|
50
50
|
export type ThrelteXREvents = {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
51
|
+
onclick: IntersectionEvent;
|
|
52
|
+
oncontextmenu: IntersectionEvent;
|
|
53
|
+
onpointerup: IntersectionEvent;
|
|
54
|
+
onpointerdown: IntersectionEvent;
|
|
55
|
+
onpointerover: IntersectionEvent;
|
|
56
|
+
onpointerout: IntersectionEvent;
|
|
57
|
+
onpointerenter: IntersectionEvent;
|
|
58
|
+
onpointerleave: IntersectionEvent;
|
|
59
|
+
onpointermove: IntersectionEvent;
|
|
60
|
+
onpointermissed: IntersectionEvent;
|
|
61
61
|
};
|
|
62
62
|
export declare const events: (keyof ThrelteXREvents)[];
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
export const events = [
|
|
2
|
-
'
|
|
3
|
-
'
|
|
4
|
-
'
|
|
5
|
-
'
|
|
6
|
-
'
|
|
7
|
-
'
|
|
8
|
-
'
|
|
9
|
-
'
|
|
10
|
-
'
|
|
2
|
+
'onclick',
|
|
3
|
+
'oncontextmenu',
|
|
4
|
+
'onpointerup',
|
|
5
|
+
'onpointerdown',
|
|
6
|
+
'onpointerover',
|
|
7
|
+
'onpointerout',
|
|
8
|
+
'onpointerenter',
|
|
9
|
+
'onpointerleave',
|
|
10
|
+
'onpointermove'
|
|
11
11
|
];
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Mesh, Raycaster, type Intersection } from 'three';
|
|
2
2
|
import type { CurrentWritable } from '@threlte/core';
|
|
3
|
+
import type { TeleportControlsOptions } from '.';
|
|
3
4
|
export type ComputeFunction = (context: Context, handContext: HandContext) => void;
|
|
5
|
+
export type TeleportEvents = {};
|
|
4
6
|
export interface Context {
|
|
5
7
|
interactiveObjects: Mesh[];
|
|
6
8
|
surfaces: Map<string, Mesh>;
|
|
@@ -8,6 +10,10 @@ export interface Context {
|
|
|
8
10
|
dispatchers: WeakMap<Mesh, Record<string, (arg: unknown) => void>>;
|
|
9
11
|
raycaster: Raycaster;
|
|
10
12
|
compute: ComputeFunction;
|
|
13
|
+
addBlocker: (mesh: Mesh) => void;
|
|
14
|
+
removeBlocker: (mesh: Mesh) => void;
|
|
15
|
+
addSurface: (mesh: Mesh, events: TeleportEvents) => void;
|
|
16
|
+
removeSurface: (mesh: Mesh) => void;
|
|
11
17
|
}
|
|
12
18
|
export interface HandContext {
|
|
13
19
|
hand: 'left' | 'right';
|
|
@@ -17,5 +23,5 @@ export interface HandContext {
|
|
|
17
23
|
}
|
|
18
24
|
export declare const getHandContext: (hand: 'left' | 'right') => HandContext;
|
|
19
25
|
export declare const setHandContext: (hand: 'left' | 'right', context: HandContext) => void;
|
|
20
|
-
export declare const
|
|
21
|
-
export declare const
|
|
26
|
+
export declare const useTeleportControls: () => Context;
|
|
27
|
+
export declare const createTeleportContext: (compute: TeleportControlsOptions['compute']) => Context;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { Raycaster } from 'three';
|
|
1
2
|
import { getContext, setContext } from 'svelte';
|
|
3
|
+
import { defaultComputeFunction } from './compute';
|
|
2
4
|
const handContextKeys = {
|
|
3
5
|
left: Symbol('teleport-controls-context-left-hand'),
|
|
4
6
|
right: Symbol('teleport-controls-context-right-hand')
|
|
@@ -10,9 +12,50 @@ export const getHandContext = (hand) => {
|
|
|
10
12
|
export const setHandContext = (hand, context) => {
|
|
11
13
|
setContext(handContextKeys[hand], context);
|
|
12
14
|
};
|
|
13
|
-
export const
|
|
15
|
+
export const useTeleportControls = () => {
|
|
14
16
|
return getContext(contextKey);
|
|
15
17
|
};
|
|
16
|
-
export const
|
|
18
|
+
export const createTeleportContext = (compute) => {
|
|
19
|
+
const addSurface = (mesh, events) => {
|
|
20
|
+
// check if the object is already in the list
|
|
21
|
+
if (context.interactiveObjects.indexOf(mesh) > -1) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
context.interactiveObjects.push(mesh);
|
|
25
|
+
context.surfaces.set(mesh.uuid, mesh);
|
|
26
|
+
context.dispatchers.set(mesh, events);
|
|
27
|
+
};
|
|
28
|
+
const removeSurface = (mesh) => {
|
|
29
|
+
const index = context.interactiveObjects.indexOf(mesh);
|
|
30
|
+
context.interactiveObjects.splice(index, 1);
|
|
31
|
+
context.surfaces.delete(mesh.uuid);
|
|
32
|
+
context.dispatchers.delete(mesh);
|
|
33
|
+
};
|
|
34
|
+
const addBlocker = (mesh) => {
|
|
35
|
+
// check if the object is already in the list
|
|
36
|
+
if (context.interactiveObjects.indexOf(mesh) > -1) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
context.interactiveObjects.push(mesh);
|
|
40
|
+
context.blockers.set(mesh.uuid, mesh);
|
|
41
|
+
};
|
|
42
|
+
const removeBlocker = (mesh) => {
|
|
43
|
+
const index = context.interactiveObjects.indexOf(mesh);
|
|
44
|
+
context.interactiveObjects.splice(index, 1);
|
|
45
|
+
context.blockers.delete(mesh.uuid);
|
|
46
|
+
};
|
|
47
|
+
const context = {
|
|
48
|
+
interactiveObjects: [],
|
|
49
|
+
surfaces: new Map(),
|
|
50
|
+
blockers: new Map(),
|
|
51
|
+
dispatchers: new WeakMap(),
|
|
52
|
+
raycaster: new Raycaster(),
|
|
53
|
+
compute: compute ?? defaultComputeFunction,
|
|
54
|
+
addBlocker,
|
|
55
|
+
removeBlocker,
|
|
56
|
+
addSurface,
|
|
57
|
+
removeSurface
|
|
58
|
+
};
|
|
17
59
|
setContext(contextKey, context);
|
|
60
|
+
return context;
|
|
18
61
|
};
|
|
@@ -1,25 +1,16 @@
|
|
|
1
|
-
import { Raycaster } from 'three';
|
|
2
1
|
import { currentWritable, watch } from '@threlte/core';
|
|
3
|
-
import {
|
|
2
|
+
import { createTeleportContext, useTeleportControls, getHandContext } from './context';
|
|
4
3
|
import { injectTeleportControlsPlugin } from './plugin';
|
|
5
|
-
import { defaultComputeFunction } from './compute';
|
|
6
4
|
import { setHandContext } from './context';
|
|
7
5
|
import { setupTeleportControls } from './setup';
|
|
8
6
|
import { teleportState } from '../../internal/stores';
|
|
9
7
|
let controlsCounter = 0;
|
|
10
8
|
export const teleportControls = (handedness, options) => {
|
|
11
|
-
if (
|
|
9
|
+
if (useTeleportControls() === undefined) {
|
|
12
10
|
injectTeleportControlsPlugin();
|
|
13
|
-
|
|
14
|
-
interactiveObjects: [],
|
|
15
|
-
surfaces: new Map(),
|
|
16
|
-
blockers: new Map(),
|
|
17
|
-
dispatchers: new WeakMap(),
|
|
18
|
-
raycaster: new Raycaster(),
|
|
19
|
-
compute: options?.compute ?? defaultComputeFunction
|
|
20
|
-
});
|
|
11
|
+
createTeleportContext(options?.compute);
|
|
21
12
|
}
|
|
22
|
-
const context =
|
|
13
|
+
const context = useTeleportControls();
|
|
23
14
|
if (getHandContext(handedness) === undefined) {
|
|
24
15
|
const enabled = options?.enabled ?? true;
|
|
25
16
|
controlsCounter += enabled ? 1 : -1;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { writable } from 'svelte/store';
|
|
2
2
|
import { watch } from '@threlte/core';
|
|
3
3
|
import { injectPlugin } from '@threlte/core';
|
|
4
|
-
import { useTeleportControls } from './
|
|
4
|
+
import { useTeleportControls } from './context';
|
|
5
5
|
/**
|
|
6
6
|
* Registers T components with "teleportSurface" or "teleportBlocker" attributes.
|
|
7
7
|
*/
|
|
@@ -24,7 +24,7 @@ export const injectTeleportControlsPlugin = () => {
|
|
|
24
24
|
return noop;
|
|
25
25
|
}
|
|
26
26
|
else {
|
|
27
|
-
addSurface($refStore, props
|
|
27
|
+
addSurface($refStore, props);
|
|
28
28
|
return () => removeSurface($refStore);
|
|
29
29
|
}
|
|
30
30
|
}
|
|
@@ -49,7 +49,7 @@ export const setupTeleportControls = (context, handContext, fixedStep = 1 / 40)
|
|
|
49
49
|
handContext.hovered.set(intersect);
|
|
50
50
|
}, {
|
|
51
51
|
fixedStep,
|
|
52
|
-
|
|
52
|
+
autoStart: false
|
|
53
53
|
});
|
|
54
54
|
watch([useXR().isPresenting, handContext.enabled], ([isPresenting, enabled]) => {
|
|
55
55
|
if (isPresenting && enabled) {
|
package/dist/types.d.ts
CHANGED
|
@@ -4,16 +4,26 @@ import type { XRControllerModel } from 'three/examples/jsm/webxr/XRControllerMod
|
|
|
4
4
|
import type { XRHandModel } from 'three/examples/jsm/webxr/XRHandModelFactory.js';
|
|
5
5
|
export type XRSessionEventType = 'sessionstart' | 'sessionend' | 'visibilitychange' | 'frameratechange';
|
|
6
6
|
export type XRControllerEventType = 'select' | 'selectstart' | 'selectend' | 'squeeze' | 'squeezeend' | 'squeezestart' | 'disconnected' | 'connected';
|
|
7
|
+
export type XRControllerEvents = {
|
|
8
|
+
onconnected?: XRControllerEvent<'connected'>;
|
|
9
|
+
ondisconnected?: XRControllerEvent<'disconnected'>;
|
|
10
|
+
onselect?: XRControllerEvent<'select'>;
|
|
11
|
+
onselectstart?: XRControllerEvent<'selectstart'>;
|
|
12
|
+
onselectend?: XRControllerEvent<'selectend'>;
|
|
13
|
+
onsqueeze?: XRControllerEvent<'squeeze'>;
|
|
14
|
+
onsqueezeend?: XRControllerEvent<'squeezeend'>;
|
|
15
|
+
onsqueezestart?: XRControllerEvent<'squeezestart'>;
|
|
16
|
+
};
|
|
7
17
|
export type XRHandEventType = 'pinchstart' | 'pinchend' | 'connected' | 'disconnected';
|
|
8
|
-
export type XRSessionEvent<Type = XRSessionEventType> = Event & {
|
|
18
|
+
export type XRSessionEvent<Type = XRSessionEventType> = (event: Event & {
|
|
9
19
|
type: Type;
|
|
10
20
|
target: XRSession;
|
|
11
|
-
};
|
|
12
|
-
export type XRControllerEvent<Type = XRControllerEventType> = Event & {
|
|
21
|
+
}) => void;
|
|
22
|
+
export type XRControllerEvent<Type = XRControllerEventType> = (event: Event & {
|
|
13
23
|
type: Type;
|
|
14
24
|
target: Group;
|
|
15
25
|
data: XRInputSource;
|
|
16
|
-
};
|
|
26
|
+
}) => void;
|
|
17
27
|
export type XRController = {
|
|
18
28
|
targetRay: XRTargetRaySpace;
|
|
19
29
|
grip: XRGripSpace;
|
|
@@ -26,12 +36,18 @@ export type XRHand = {
|
|
|
26
36
|
model?: XRHandModel;
|
|
27
37
|
inputSource: globalThis.XRHand;
|
|
28
38
|
};
|
|
29
|
-
export type
|
|
39
|
+
export type XRHandEvents = {
|
|
40
|
+
onconnected?: XRHandEvent<'connected'>;
|
|
41
|
+
ondisconnected?: XRHandEvent<'disconnected'>;
|
|
42
|
+
onpinchstart?: XRHandEvent<'pinchstart'>;
|
|
43
|
+
onpinchend?: XRHandEvent<'pinchend'>;
|
|
44
|
+
};
|
|
45
|
+
export type XRHandEvent<Type = XRHandEventType> = Type extends 'connected' | 'disconnected' ? (event: {
|
|
30
46
|
type: Type;
|
|
31
47
|
target: XRHandSpace;
|
|
32
48
|
data: XRInputSource;
|
|
33
|
-
} : Type extends 'pinchstart' | 'pinchend' ? {
|
|
49
|
+
}) => void : Type extends 'pinchstart' | 'pinchend' ? (event: {
|
|
34
50
|
type: Type;
|
|
35
51
|
handedness: 'left' | 'right';
|
|
36
52
|
target: null;
|
|
37
|
-
} : never;
|
|
53
|
+
}) => void : never;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@threlte/xr",
|
|
3
|
-
"version": "1.0.0-next.
|
|
3
|
+
"version": "1.0.0-next.3",
|
|
4
4
|
"author": "Micheal Parks <michealparks1989@gmail.com> (https://parks.lol)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"devDependencies": {
|
|
@@ -23,11 +23,11 @@
|
|
|
23
23
|
"tslib": "^2.6.2",
|
|
24
24
|
"vite": "^5.2.8",
|
|
25
25
|
"vite-plugin-mkcert": "^1.17.5",
|
|
26
|
-
"@threlte/core": "8.0.0-next.
|
|
26
|
+
"@threlte/core": "8.0.0-next.6"
|
|
27
27
|
},
|
|
28
28
|
"peerDependencies": {
|
|
29
29
|
"svelte": ">=5",
|
|
30
|
-
"three": ">=0.
|
|
30
|
+
"three": ">=0.155"
|
|
31
31
|
},
|
|
32
32
|
"type": "module",
|
|
33
33
|
"exports": {
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { Mesh } from 'three';
|
|
2
|
-
export declare const useTeleportControls: () => {
|
|
3
|
-
addSurface: (mesh: Mesh, events: Record<string, (arg: unknown) => void>) => void;
|
|
4
|
-
removeSurface: (mesh: Mesh) => void;
|
|
5
|
-
addBlocker: (mesh: Mesh) => void;
|
|
6
|
-
removeBlocker: (mesh: Mesh) => void;
|
|
7
|
-
};
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { getTeleportContext } from './context';
|
|
2
|
-
export const useTeleportControls = () => {
|
|
3
|
-
const context = getTeleportContext();
|
|
4
|
-
const addSurface = (mesh, events) => {
|
|
5
|
-
// check if the object is already in the list
|
|
6
|
-
if (context.interactiveObjects.indexOf(mesh) > -1) {
|
|
7
|
-
return;
|
|
8
|
-
}
|
|
9
|
-
context.interactiveObjects.push(mesh);
|
|
10
|
-
context.surfaces.set(mesh.uuid, mesh);
|
|
11
|
-
context.dispatchers.set(mesh, events);
|
|
12
|
-
};
|
|
13
|
-
const removeSurface = (mesh) => {
|
|
14
|
-
const index = context.interactiveObjects.indexOf(mesh);
|
|
15
|
-
context.interactiveObjects.splice(index, 1);
|
|
16
|
-
context.surfaces.delete(mesh.uuid);
|
|
17
|
-
context.dispatchers.delete(mesh);
|
|
18
|
-
};
|
|
19
|
-
const addBlocker = (mesh) => {
|
|
20
|
-
// check if the object is already in the list
|
|
21
|
-
if (context.interactiveObjects.indexOf(mesh) > -1) {
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
context.interactiveObjects.push(mesh);
|
|
25
|
-
context.blockers.set(mesh.uuid, mesh);
|
|
26
|
-
};
|
|
27
|
-
const removeBlocker = (mesh) => {
|
|
28
|
-
const index = context.interactiveObjects.indexOf(mesh);
|
|
29
|
-
context.interactiveObjects.splice(index, 1);
|
|
30
|
-
context.blockers.delete(mesh.uuid);
|
|
31
|
-
};
|
|
32
|
-
return {
|
|
33
|
-
addSurface,
|
|
34
|
-
removeSurface,
|
|
35
|
-
addBlocker,
|
|
36
|
-
removeBlocker
|
|
37
|
-
};
|
|
38
|
-
};
|