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;