UNPKG

@threlte/xr

Version:

Tools to more easily create VR and AR experiences with Threlte

81 lines (80 loc) 3.3 kB
import { Raycaster, Vector3 } from 'three'; import { currentWritable, observe } from '@threlte/core'; import { defaultComputeFunction } from './compute.js'; import { injectPointerControlsPlugin } from './plugin.svelte.js'; import { setupPointerControls } from './setup.svelte.js'; import { getControlsContext, getHandContext, setControlsContext, setHandContext, setInternalContext } from './context.js'; import { pointerIntersection, pointerState } from '../../internal/state.svelte.js'; const aggregateStates = new Map(); export const pointerControls = (handedness, options) => { if (getControlsContext() === undefined) { injectPointerControlsPlugin(); setInternalContext(); setControlsContext({ interactiveObjects: [] }); } const context = getControlsContext(); const aggregateState = aggregateStates.get(handedness) ?? (() => { const state = { enabled: currentWritable(options?.enabled ?? true), hovered: new Map() }; aggregateStates.set(handedness, state); return state; })(); const { enabled, hovered } = aggregateState; let controllerContext = getHandContext(handedness, 'controller'); let handContext = getHandContext(handedness, 'hand'); const syncSharedState = () => { hovered.clear(); for (const [id, event] of controllerContext.hovered) { hovered.set(`controller:${id}`, event); } for (const [id, event] of handContext.hovered) { hovered.set(`hand:${id}`, event); } // Shared handedness-level pointer visuals are currently controller-only: // <Controller /> renders the cursor/ray from these globals, while hand // pointer events are dispatched independently without a matching visual. pointerState[handedness].hovering = controllerContext.pointerOverTarget.current; pointerIntersection[handedness] = controllerContext.currentIntersection; }; const createContext = (sourceType) => ({ hand: handedness, sourceType, enabled, pointer: currentWritable(new Vector3()), pointerOverTarget: currentWritable(false), lastEvent: undefined, initialClick: [0, 0, 0], initialHits: [], hovered: new Map(), currentIntersection: undefined, raycaster: new Raycaster(), syncSharedState, compute: options?.compute ?? defaultComputeFunction, filter: options?.filter }); const setupContexts = []; if (controllerContext === undefined) { controllerContext = createContext('controller'); setHandContext(handedness, 'controller', controllerContext); setupContexts.push(controllerContext); } if (handContext === undefined) { handContext = createContext('hand'); setHandContext(handedness, 'hand', handContext); setupContexts.push(handContext); } for (const setupContext of setupContexts) { setupPointerControls(context, setupContext, options?.fixedStep); } observe.pre(() => [enabled], ([nextEnabled]) => { pointerState[handedness].enabled = nextEnabled; }); syncSharedState(); return { enabled, hovered }; };