import * as React from "react"; import { UnsupportedReason } from "../useAugmentedReality"; import { StartComponentProps, StandardProps, StandardAugmentedRealityProps, UnsupportedReasonProps } from "./propTypes"; import { GltfImage, XRSessionOptions } from "../types"; import { Gltf2Node } from "../immersive-web/render/nodes/gltf2"; import { Node } from "../immersive-web/render/core/node"; import { useAugmentedReality } from ".."; import { startSession, endSession, enableStats, addImage, removeImage } from "../augmentedRealitySession"; type UnsupportedMessageProps = StandardProps & UnsupportedReasonProps; const UnsupportedMessage = (props: UnsupportedMessageProps) => { const { reason, ...otherProps } = props; const getMessage = () => { switch (reason) { case UnsupportedReason.NotInitialised: return "Initialising augmented reality"; case UnsupportedReason.InsecureConnection: return "Augmented reality is not available on an insecure connection"; case UnsupportedReason.NotSupportedInBrowser: return "Augmented reality is not supported in this browser"; } }; return
{getMessage()}
; }; const StartStopButton = ({ onStartSelected }: StartComponentProps) => ( ); type AugmentedRealityProps = StandardProps & StandardAugmentedRealityProps & { options?: XRSessionOptions; onSelect?: () => void; onHitTest?: (matrix: Float32Array | null) => void; }; type SceneImage = { key: string; node: Node | Gltf2Node; }; const AugmentedReality = (props: AugmentedRealityProps) => { const [session, setSession] = React.useState(); const { support } = useAugmentedReality(); const { startStopComponent, unsupportedComponent, showStats = true, images, onHitTest, onSelect, options, ...otherProps } = props; const imagesInView = React.useRef([]); const updateImages = (images?: GltfImage[]) => { const toRemove = imagesInView.current.filter(({ key }) => !Boolean(images?.find(image => image.key === key))); const toAdd = images?.filter(({ key }) => !Boolean(imagesInView.current.find(image => image.key === key))); for (const image of toRemove) { removeImage(image.node); } for (const image of toAdd || []) { const { src, matrix } = image; const newImage = new Gltf2Node({ url: src }); const node = addImage(newImage, image.includeShadow); if (!node) return; if (matrix) { node.matrix = matrix; } imagesInView.current.push({ node, key: image.key }); } }; React.useEffect(() => { if (session) { enableStats(showStats); } }, [showStats, support, session]); React.useEffect(() => { if (session) { updateImages(images); } }, [images, updateImages, session]); React.useEffect(() => { if (onSelect) { session?.addEventListener("select", onSelect); } return () => session?.removeEventListener("select", onSelect); }); if (!support.isSupported) { const Unsupported = unsupportedComponent || UnsupportedMessage; return ; } const onStartSelected = async () => { const allOptions = onHitTest ? { ...options, hitTestOptions: options?.hitTestOptions ? { ...options?.hitTestOptions, onHitTest } : undefined, } : options; setSession(await startSession({ ...allOptions })); }; const onStopSelected = () => { endSession(); }; const StartStop = startStopComponent || StartStopButton; return (
); }; export default AugmentedReality;